From 47d455dd55be855e4cc691c32f687f723d9247ee Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdegraphics@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- AUTHORS | 3 + COPYING | 347 + COPYING-DOCS | 397 + ChangeLog | 17 + INSTALL | 176 + Mainpage.dox | 16 + Makefile.am.in | 22 + Makefile.cvs | 16 + README | 97 + configure.in.in | 17 + doc/Makefile.am | 5 + doc/kamera/Makefile.am | 4 + doc/kamera/index.docbook | 78 + doc/kcoloredit/Makefile.am | 4 + doc/kcoloredit/index.docbook | 468 + doc/kdvi/KDVI-features.dvi | Bin 0 -> 737562 bytes doc/kdvi/KDVI-features.tex | 480 ++ doc/kdvi/Makefile.am | 4 + doc/kdvi/aboutkde.ps | 3351 ++++++++ doc/kdvi/index.docbook | 1072 +++ doc/kdvi/kdvi-search.el | 102 + doc/kdvi/optionrequester1.png | Bin 0 -> 14743 bytes doc/kdvi/optionrequester2.png | Bin 0 -> 17905 bytes doc/kdvi/srcltx.sty | 184 + doc/kdvi/srctex.sty | 146 + doc/kgamma/Makefile.am | 4 + doc/kgamma/index.docbook | 234 + doc/kghostview/Makefile.am | 4 + doc/kghostview/index.docbook | 755 ++ doc/kiconedit/Makefile.am | 4 + doc/kiconedit/index.docbook | 1083 +++ doc/kiconedit/kiconedit-configuration.png | Bin 0 -> 31231 bytes doc/kolourpaint/Makefile.am | 2 + doc/kolourpaint/brush_shapes.png | Bin 0 -> 475 bytes doc/kolourpaint/color_box.png | Bin 0 -> 2417 bytes doc/kolourpaint/eraser_shapes.png | Bin 0 -> 362 bytes doc/kolourpaint/fcc_std_text.png | Bin 0 -> 10072 bytes doc/kolourpaint/fcc_trans_text.png | Bin 0 -> 11702 bytes doc/kolourpaint/fill_color_similarity.png | Bin 0 -> 17540 bytes doc/kolourpaint/fill_style.png | Bin 0 -> 342 bytes doc/kolourpaint/image_balance.png | Bin 0 -> 35978 bytes doc/kolourpaint/image_emboss.png | Bin 0 -> 51537 bytes doc/kolourpaint/image_flatten.png | Bin 0 -> 25398 bytes doc/kolourpaint/image_flip.png | Bin 0 -> 10004 bytes doc/kolourpaint/image_invert.png | Bin 0 -> 27542 bytes doc/kolourpaint/image_reduce_colors.png | Bin 0 -> 25313 bytes doc/kolourpaint/image_resize_scale.png | Bin 0 -> 36298 bytes doc/kolourpaint/image_rotate.png | Bin 0 -> 32499 bytes doc/kolourpaint/image_skew.png | Bin 0 -> 25028 bytes doc/kolourpaint/image_soften_sharpen.png | Bin 0 -> 46238 bytes doc/kolourpaint/index.docbook | 1501 ++++ doc/kolourpaint/kolourpaint-main.png | Bin 0 -> 35385 bytes doc/kolourpaint/line_width.png | Bin 0 -> 307 bytes doc/kolourpaint/lines_30_45_deg.png | Bin 0 -> 1382 bytes doc/kolourpaint/lines_30_deg.png | Bin 0 -> 1062 bytes doc/kolourpaint/lines_45_deg.png | Bin 0 -> 853 bytes doc/kolourpaint/rotate_image_30.png | Bin 0 -> 2026 bytes doc/kolourpaint/rotate_selection_30.png | Bin 0 -> 2898 bytes doc/kolourpaint/selections_opaque_transparent.png | Bin 0 -> 1176 bytes doc/kolourpaint/spraycan_patterns.png | Bin 0 -> 829 bytes doc/kolourpaint/text_zoom_grid.png | Bin 0 -> 451 bytes doc/kolourpaint/tool_brush.png | Bin 0 -> 675 bytes doc/kolourpaint/tool_color_picker.png | Bin 0 -> 656 bytes doc/kolourpaint/tool_color_washer.png | Bin 0 -> 1010 bytes doc/kolourpaint/tool_curve.png | Bin 0 -> 483 bytes doc/kolourpaint/tool_ellipse.png | Bin 0 -> 837 bytes doc/kolourpaint/tool_elliptical_selection.png | Bin 0 -> 906 bytes doc/kolourpaint/tool_eraser.png | Bin 0 -> 806 bytes doc/kolourpaint/tool_flood_fill.png | Bin 0 -> 638 bytes doc/kolourpaint/tool_free_form_selection.png | Bin 0 -> 855 bytes doc/kolourpaint/tool_line.png | Bin 0 -> 439 bytes doc/kolourpaint/tool_pen.png | Bin 0 -> 579 bytes doc/kolourpaint/tool_polygon.png | Bin 0 -> 907 bytes doc/kolourpaint/tool_polyline.png | Bin 0 -> 543 bytes doc/kolourpaint/tool_polystar.png | Bin 0 -> 1365 bytes doc/kolourpaint/tool_rect_selection.png | Bin 0 -> 921 bytes doc/kolourpaint/tool_rectangle.png | Bin 0 -> 557 bytes doc/kolourpaint/tool_rectangles.png | Bin 0 -> 824 bytes doc/kolourpaint/tool_rounded_rectangle.png | Bin 0 -> 729 bytes doc/kolourpaint/tool_selections.png | Bin 0 -> 1831 bytes doc/kolourpaint/tool_spraycan.png | Bin 0 -> 784 bytes doc/kolourpaint/tool_text.png | Bin 0 -> 401 bytes doc/kolourpaint/view_thumbnails.png | Bin 0 -> 42197 bytes doc/kooka/Makefile.am | 4 + doc/kooka/index.docbook | 747 ++ doc/kooka/kooka_gocr.png | Bin 0 -> 12366 bytes doc/kooka/kooka_gocr_result.png | Bin 0 -> 12529 bytes doc/kooka/kooka_mainctrl.png | Bin 0 -> 414827 bytes doc/kooka/ocr-select.png | Bin 0 -> 899 bytes doc/kooka/shortcut0.png | Bin 0 -> 32037 bytes doc/kooka/shortcut1.png | Bin 0 -> 16028 bytes doc/kooka/toolbar.png | Bin 0 -> 54602 bytes doc/kooka/toolbar1.png | Bin 0 -> 6336 bytes doc/kooka/toolbar2.png | Bin 0 -> 7244 bytes doc/kpdf/Makefile.am | 4 + doc/kpdf/configure.png | Bin 0 -> 11240 bytes doc/kpdf/index.docbook | 932 ++ doc/kpovmodeler/Makefile.am | 4 + doc/kpovmodeler/cameraview.png | Bin 0 -> 7778 bytes doc/kpovmodeler/controlpoints.png | Bin 0 -> 5658 bytes doc/kpovmodeler/cr22-action-pmcamera.png | Bin 0 -> 525 bytes doc/kpovmodeler/cr22-action-pmcolorlist.png | Bin 0 -> 218 bytes doc/kpovmodeler/cr22-action-pmfinish.png | Bin 0 -> 299 bytes doc/kpovmodeler/cr22-action-pminterior.png | Bin 0 -> 277 bytes doc/kpovmodeler/cr22-action-pmlight.png | Bin 0 -> 438 bytes doc/kpovmodeler/cr22-action-pmpigment.png | Bin 0 -> 305 bytes doc/kpovmodeler/cr22-action-pmplane.png | Bin 0 -> 495 bytes doc/kpovmodeler/cr22-action-pmrender.png | Bin 0 -> 637 bytes doc/kpovmodeler/cr22-action-pmsolidcolor.png | Bin 0 -> 255 bytes doc/kpovmodeler/cr22-action-pmsphere.png | Bin 0 -> 592 bytes doc/kpovmodeler/defaultviewlayout.png | Bin 0 -> 20414 bytes doc/kpovmodeler/dockwidget.png | Bin 0 -> 629 bytes doc/kpovmodeler/dockwidgettab.png | Bin 0 -> 4534 bytes doc/kpovmodeler/index.docbook | 2100 +++++ doc/kpovmodeler/insertaspopup.png | Bin 0 -> 709 bytes doc/kpovmodeler/objectpropertiesview.png | Bin 0 -> 10272 bytes doc/kpovmodeler/objecttree.png | Bin 0 -> 5962 bytes doc/kpovmodeler/rendericon.png | Bin 0 -> 637 bytes doc/kpovmodeler/rendermodeoutput.png | Bin 0 -> 41312 bytes doc/kpovmodeler/rendermodequality.png | Bin 0 -> 40754 bytes doc/kpovmodeler/rendermodesize.png | Bin 0 -> 41223 bytes doc/kpovmodeler/rendermodesselection.png | Bin 0 -> 16508 bytes doc/kpovmodeler/rendermodestoolbar.png | Bin 0 -> 2355 bytes doc/kpovmodeler/rendersettingsicon.png | Bin 0 -> 693 bytes doc/kpovmodeler/renderwindow.png | Bin 0 -> 45098 bytes doc/kpovmodeler/texturepreview.png | Bin 0 -> 29483 bytes doc/kpovmodeler/topview.png | Bin 0 -> 4616 bytes doc/kpovmodeler/tutorial01-camera-dialog.png | Bin 0 -> 11691 bytes doc/kpovmodeler/tutorial01-camera-graphic.png | Bin 0 -> 1009 bytes doc/kpovmodeler/tutorial01-final-render.png | Bin 0 -> 40824 bytes doc/kpovmodeler/tutorial01-ground-color-list.png | Bin 0 -> 14585 bytes doc/kpovmodeler/tutorial01-ground-pigment.png | Bin 0 -> 24498 bytes doc/kpovmodeler/tutorial01-ground-render.png | Bin 0 -> 54913 bytes .../tutorial01-ground-solid-color-1.png | Bin 0 -> 15590 bytes .../tutorial01-ground-solid-color-2.png | Bin 0 -> 15887 bytes .../tutorial01-ground-wrong-colors-render.png | Bin 0 -> 42474 bytes doc/kpovmodeler/tutorial01-light-dialog.png | Bin 0 -> 11491 bytes doc/kpovmodeler/tutorial01-light-graphic.png | Bin 0 -> 989 bytes doc/kpovmodeler/tutorial01-plane-dialog.png | Bin 0 -> 5042 bytes doc/kpovmodeler/tutorial01-plane-graphic.png | Bin 0 -> 1289 bytes doc/kpovmodeler/tutorial01-plane-tree-expanded.png | Bin 0 -> 2358 bytes .../tutorial01-plane-tree-translate.png | Bin 0 -> 3068 bytes doc/kpovmodeler/tutorial01-sphere-dialog.png | Bin 0 -> 5641 bytes .../tutorial01-sphere-finish-dialog.png | Bin 0 -> 9855 bytes .../tutorial01-sphere-render-finish.png | Bin 0 -> 37390 bytes .../tutorial01-sphere-render-nocolor.png | Bin 0 -> 37263 bytes .../tutorial01-sphere-render-solidcolor.png | Bin 0 -> 37375 bytes doc/kpovmodeler/tutorial01-sphere-solid-color.png | Bin 0 -> 9346 bytes doc/kruler/Makefile.am | 4 + doc/kruler/index.docbook | 359 + doc/ksnapshot/Makefile.am | 4 + doc/ksnapshot/index.docbook | 535 ++ doc/ksnapshot/preview.png | Bin 0 -> 32987 bytes doc/ksnapshot/window.png | Bin 0 -> 43333 bytes doc/kuickshow/Makefile.am | 4 + doc/kuickshow/index.docbook | 1041 +++ doc/kuickshow/screenshot.png | Bin 0 -> 235434 bytes doc/kview/Makefile.am | 4 + doc/kview/index.docbook | 835 ++ doc/kview/kview-application-configuration.png | Bin 0 -> 31056 bytes doc/kview/kview-viewer-configuration.png | Bin 0 -> 45321 bytes kamera/AUTHORS | 4 + kamera/Makefile.am | 1 + kamera/README | 5 + kamera/configure.in.in | 182 + kamera/kcontrol/Makefile.am | 16 + kamera/kcontrol/kamera.cpp | 423 + kamera/kcontrol/kamera.desktop | 193 + kamera/kcontrol/kamera.h | 115 + kamera/kcontrol/kameraconfigdialog.cpp | 317 + kamera/kcontrol/kameraconfigdialog.h | 53 + kamera/kcontrol/kameradevice.cpp | 476 ++ kamera/kcontrol/kameradevice.h | 117 + kamera/kioslave/Makefile.am | 17 + kamera/kioslave/camera.protocol | 16 + kamera/kioslave/kamera.cpp | 1066 +++ kamera/kioslave/kamera.h | 81 + kamera/pics/Makefile.am | 1 + kamera/pics/cr16-action-camera_test.png | Bin 0 -> 661 bytes kamera/pics/cr16-app-camera.png | Bin 0 -> 747 bytes kamera/pics/cr16-device-camera.png | Bin 0 -> 747 bytes kamera/pics/cr22-device-camera.png | Bin 0 -> 953 bytes kamera/pics/cr22-filesys-camera.png | Bin 0 -> 953 bytes kamera/pics/cr32-device-camera.png | Bin 0 -> 1627 bytes kamera/pics/cr32-filesys-camera.png | Bin 0 -> 1627 bytes kcoloredit/Makefile.am | 35 + kcoloredit/color.cpp | 78 + kcoloredit/color.h | 81 + kcoloredit/colorselector.cpp | 212 + kcoloredit/colorselector.h | 96 + kcoloredit/editablestreamhistory.cpp | 18 + kcoloredit/editablestreamhistory.h | 107 + kcoloredit/gradientselection.cpp | 252 + kcoloredit/gradientselection.h | 106 + kcoloredit/hi16-app-kcolorchooser.png | Bin 0 -> 372 bytes kcoloredit/hi16-app-kcoloredit.png | Bin 0 -> 857 bytes kcoloredit/hi22-app-kcolorchooser.png | Bin 0 -> 317 bytes kcoloredit/hi32-app-kcoloredit.png | Bin 0 -> 2295 bytes kcoloredit/imageselection.cpp | 28 + kcoloredit/imageselection.h | 49 + kcoloredit/kcolorchooser.cpp | 70 + kcoloredit/kcolorchooser.desktop | 108 + kcoloredit/kcoloredit.cpp | 363 + kcoloredit/kcoloredit.desktop | 96 + kcoloredit/kcoloredit.h | 192 + kcoloredit/kcoloreditdoc.cpp | 293 + kcoloredit/kcoloreditdoc.h | 156 + kcoloredit/kcoloreditui.rc | 26 + kcoloredit/kcoloreditview.cpp | 282 + kcoloredit/kcoloreditview.h | 128 + kcoloredit/kxycolorselector.cpp | 186 + kcoloredit/kxycolorselector.h | 97 + kcoloredit/kzcolorselector.cpp | 170 + kcoloredit/kzcolorselector.h | 89 + kcoloredit/loadpalettedlg.cpp | 111 + kcoloredit/loadpalettedlg.h | 67 + kcoloredit/main.cpp | 74 + kcoloredit/main.h | 52 + kcoloredit/palette.cpp | 226 + kcoloredit/palette.h | 102 + kcoloredit/palettehistory.h | 26 + kcoloredit/paletteview.cpp | 75 + kcoloredit/paletteview.h | 64 + kcoloredit/paletteviewscrolledarea.cpp | 409 + kcoloredit/paletteviewscrolledarea.h | 162 + kcoloredit/resource.h | 35 + kcoloredit/texteditselection.cpp | 187 + kcoloredit/texteditselection.h | 89 + kcoloredit/textselection.cpp | 24 + kcoloredit/uninstall.desktop | 2 + kdegraphics.lsm | 11 + kdvi/AUTHORS | 39 + kdvi/ChangeLog | 9 + kdvi/Makefile.am | 66 + kdvi/TODO | 30 + kdvi/TeXFont.cpp | 9 + kdvi/TeXFont.h | 48 + kdvi/TeXFontDefinition.cpp | 250 + kdvi/TeXFontDefinition.h | 126 + kdvi/TeXFont_PFB.cpp | 294 + kdvi/TeXFont_PFB.h | 41 + kdvi/TeXFont_PK.cpp | 781 ++ kdvi/TeXFont_PK.h | 38 + kdvi/TeXFont_TFM.cpp | 163 + kdvi/TeXFont_TFM.h | 38 + kdvi/bigEndianByteReader.cpp | 111 + kdvi/bigEndianByteReader.h | 62 + kdvi/configure.in.in | 55 + kdvi/dvi.h | 68 + kdvi/dviFile.cpp | 406 + kdvi/dviFile.h | 150 + kdvi/dviPageCache.cpp | 42 + kdvi/dviPageCache.h | 40 + kdvi/dviRenderer.cpp | 839 ++ kdvi/dviRenderer.h | 300 + kdvi/dviRenderer_draw.cpp | 660 ++ kdvi/dviRenderer_export.cpp | 391 + kdvi/dviRenderer_prescan.cpp | 789 ++ kdvi/dviWidget.cpp | 123 + kdvi/dviWidget.h | 38 + kdvi/dvisourcesplitter.cpp | 95 + kdvi/dvisourcesplitter.h | 34 + kdvi/examples/BrokenDVI1.dvi | Bin 0 -> 146 bytes kdvi/examples/Font_not_found.dvi | Bin 0 -> 212 bytes kdvi/examples/dvistd0.dvi | Bin 0 -> 141240 bytes kdvi/fontEncoding.cpp | 87 + kdvi/fontEncoding.h | 86 + kdvi/fontEncodingPool.cpp | 37 + kdvi/fontEncodingPool.h | 29 + kdvi/fontMap.cpp | 159 + kdvi/fontMap.h | 118 + kdvi/fontpool.cpp | 597 ++ kdvi/fontpool.h | 215 + kdvi/fontprogress.cpp | 104 + kdvi/fontprogress.h | 64 + kdvi/glyph.cpp | 30 + kdvi/glyph.h | 37 + kdvi/infodialog.cpp | 134 + kdvi/infodialog.h | 58 + kdvi/kdvi.desktop | 90 + kdvi/kdvi.h | 17 + kdvi/kdvi.kcfg | 26 + kdvi/kdvi.lsm | 14 + kdvi/kdvi_multipage.cpp | 482 ++ kdvi/kdvi_multipage.h | 96 + kdvi/kdvi_multipage_texthandling.cpp | 70 + kdvi/kdvi_part.rc | 26 + kdvi/kdvimultipage.desktop | 18 + kdvi/kprinterwrapper.h | 24 + kdvi/main.cpp | 154 + kdvi/make/ChangeLog | 370 + kdvi/make/README | 3 + kdvi/make/common.make | 42 + kdvi/make/config.make | 39 + kdvi/make/dist.make | 33 + kdvi/make/library.make | 5 + kdvi/make/makevars.make | 20 + kdvi/make/misc.make | 31 + kdvi/make/paths.make | 99 + kdvi/make/programs.make | 13 + kdvi/make/rdepend.make | 15 + kdvi/make/texi.make | 13 + kdvi/make/tkpathsea.make | 9 + kdvi/optionDialogFontsWidget.cpp | 47 + kdvi/optionDialogFontsWidget.h | 24 + kdvi/optionDialogFontsWidget_base.ui | 64 + kdvi/optionDialogSpecialWidget.cpp | 135 + kdvi/optionDialogSpecialWidget.h | 36 + kdvi/optionDialogSpecialWidget_base.ui | 208 + kdvi/performanceMeasurement.h | 21 + kdvi/pix/Makefile.am | 2 + kdvi/pix/hi16-app-kdvi.png | Bin 0 -> 837 bytes kdvi/pix/hi22-app-kdvi.png | Bin 0 -> 1440 bytes kdvi/pix/hi32-app-kdvi.png | Bin 0 -> 2297 bytes kdvi/pix/hi48-app-kdvi.png | Bin 0 -> 4397 bytes kdvi/pix/hisc-app-kdvi.svgz | Bin 0 -> 31209 bytes kdvi/prebookmark.h | 50 + kdvi/prefs.kcfgc | 5 + kdvi/psgs.cpp | 340 + kdvi/psgs.h | 107 + kdvi/psheader.txt | 113 + kdvi/renderedDviPagePixmap.cpp | 44 + kdvi/renderedDviPagePixmap.h | 49 + kdvi/special.cpp | 727 ++ kdvi/squeeze.c | 190 + kdvi/tips | 42 + kdvi/util.cpp | 115 + kdvi/vf.cpp | 184 + kdvi/xdvi.h | 24 + kfax/AUTHORS | 3 + kfax/ChangeLog | 28 + kfax/Makefile.am | 32 + kfax/NOTES | 49 + kfax/README | 34 + kfax/TODO | 2 + kfax/examples/README | 22 + kfax/examples/README.kdeapps | 12 + kfax/examples/kde.g3 | Bin 0 -> 55571 bytes kfax/examples/nasty.tiff | Bin 0 -> 92354 bytes kfax/faxexpand.cpp | 732 ++ kfax/faxexpand.h | 160 + kfax/faxinit.cpp | 337 + kfax/faxinput.cpp | 479 ++ kfax/hi16-app-kfax.png | Bin 0 -> 787 bytes kfax/hi22-app-kfax.png | Bin 0 -> 1241 bytes kfax/hi32-app-kfax.png | Bin 0 -> 1928 bytes kfax/hi48-app-kfax.png | Bin 0 -> 3352 bytes kfax/hisc-app-kfax.svgz | Bin 0 -> 11876 bytes kfax/kfax.cpp | 1695 ++++ kfax/kfax.desktop | 86 + kfax/kfax.h | 159 + kfax/kfax.tif | Bin 0 -> 74703 bytes kfax/kfax_printsettings.cpp | 98 + kfax/kfax_printsettings.h | 47 + kfax/kfaxlogo.xpm | 134 + kfax/kfaxui.rc | 28 + kfax/options.cpp | 374 + kfax/options.h | 112 + kfax/version.h | 1 + kfax/viewfax.cpp | 770 ++ kfax/viewfax.h | 27 + kfaxview/Makefile.am | 38 + kfaxview/faxmultipage.cpp | 85 + kfaxview/faxmultipage.h | 120 + kfaxview/faxrenderer.cpp | 204 + kfaxview/faxrenderer.h | 90 + kfaxview/hi16-app-kfaxview.png | Bin 0 -> 787 bytes kfaxview/hi22-app-kfaxview.png | Bin 0 -> 1241 bytes kfaxview/hi32-app-kfaxview.png | Bin 0 -> 1928 bytes kfaxview/hi48-app-kfaxview.png | Bin 0 -> 3352 bytes kfaxview/hisc-app-kfaxview.svgz | Bin 0 -> 11876 bytes kfaxview/kfaxmultipage.desktop | 60 + kfaxview/kfaxmultipage_tiff.desktop | 57 + kfaxview/kfaxview.desktop | 82 + kfaxview/libkfaximage/Makefile.am | 14 + kfaxview/libkfaximage/faxexpand.cpp | 745 ++ kfaxview/libkfaximage/faxexpand.h | 126 + kfaxview/libkfaximage/faxinit.cpp | 345 + kfaxview/libkfaximage/kfaximage.cpp | 667 ++ kfaxview/libkfaximage/kfaximage.h | 162 + kfaxview/main.cpp | 174 + kfile-plugins/Makefile.am | 14 + kfile-plugins/RETURNED_ITEMS | 245 + kfile-plugins/bmp/Makefile.am | 22 + kfile-plugins/bmp/kfile_bmp.cpp | 174 + kfile-plugins/bmp/kfile_bmp.desktop | 66 + kfile-plugins/bmp/kfile_bmp.h | 37 + kfile-plugins/configure.in.bot | 32 + kfile-plugins/dds/Makefile.am | 22 + kfile-plugins/dds/kfile_dds.cpp | 317 + kfile-plugins/dds/kfile_dds.desktop | 53 + kfile-plugins/dds/kfile_dds.h | 37 + kfile-plugins/dvi/Makefile.am | 22 + kfile-plugins/dvi/kfile_dvi.cpp | 150 + kfile-plugins/dvi/kfile_dvi.desktop | 60 + kfile-plugins/dvi/kfile_dvi.h | 37 + kfile-plugins/exr/Makefile.am | 25 + kfile-plugins/exr/configure.in.in | 14 + kfile-plugins/exr/kfile_exr.cpp | 393 + kfile-plugins/exr/kfile_exr.desktop | 57 + kfile-plugins/exr/kfile_exr.h | 39 + kfile-plugins/gif/Makefile.am | 24 + kfile-plugins/gif/README | 10 + kfile-plugins/gif/gif-info.1 | 25 + kfile-plugins/gif/gif-info.c | 561 ++ kfile-plugins/gif/kfile_gif.cpp | 122 + kfile-plugins/gif/kfile_gif.desktop | 65 + kfile-plugins/gif/kfile_gif.h | 37 + kfile-plugins/ico/Makefile.am | 22 + kfile-plugins/ico/kfile_ico.cpp | 148 + kfile-plugins/ico/kfile_ico.desktop | 65 + kfile-plugins/ico/kfile_ico.h | 37 + kfile-plugins/jpeg/Makefile.am | 24 + kfile-plugins/jpeg/README | 35 + kfile-plugins/jpeg/exif.cpp | 961 +++ kfile-plugins/jpeg/exif.h | 127 + kfile-plugins/jpeg/kfile_jpeg.cpp | 531 ++ kfile-plugins/jpeg/kfile_jpeg.desktop | 64 + kfile-plugins/jpeg/kfile_jpeg.h | 43 + kfile-plugins/jpeg/kfile_setcomment.cpp | 536 ++ kfile-plugins/pcx/Makefile.am | 21 + kfile-plugins/pcx/kfile_pcx.cpp | 122 + kfile-plugins/pcx/kfile_pcx.desktop | 62 + kfile-plugins/pcx/kfile_pcx.h | 88 + kfile-plugins/pdf/Makefile.am | 22 + kfile-plugins/pdf/configure.in.in | 15 + kfile-plugins/pdf/kfile_pdf.cpp | 104 + kfile-plugins/pdf/kfile_pdf.desktop | 64 + kfile-plugins/pdf/kfile_pdf.h | 38 + kfile-plugins/png/Makefile.am | 22 + kfile-plugins/png/kfile_png.cpp | 315 + kfile-plugins/png/kfile_png.desktop | 65 + kfile-plugins/png/kfile_png.h | 39 + kfile-plugins/pnm/Makefile.am | 22 + kfile-plugins/pnm/kfile_pnm.cpp | 137 + kfile-plugins/pnm/kfile_pnm.desktop | 60 + kfile-plugins/pnm/kfile_pnm.h | 39 + kfile-plugins/ps/Makefile.am | 26 + kfile-plugins/ps/gscreator.cpp | 619 ++ kfile-plugins/ps/gscreator.h | 42 + kfile-plugins/ps/gsthumbnail.desktop | 60 + kfile-plugins/ps/kfile_ps.cpp | 124 + kfile-plugins/ps/kfile_ps.desktop | 66 + kfile-plugins/ps/kfile_ps.h | 50 + kfile-plugins/raw/Makefile.am | 19 + kfile-plugins/raw/kcamerarawplugin.cpp | 141 + kfile-plugins/raw/kcamerarawplugin.h | 38 + kfile-plugins/raw/kfile_raw.desktop | 53 + kfile-plugins/raw/parse.c | 1080 +++ kfile-plugins/rgb/Makefile.am | 22 + kfile-plugins/rgb/kfile_rgb.cpp | 208 + kfile-plugins/rgb/kfile_rgb.desktop | 61 + kfile-plugins/rgb/kfile_rgb.h | 41 + kfile-plugins/tga/Makefile.am | 22 + kfile-plugins/tga/kfile_tga.cpp | 165 + kfile-plugins/tga/kfile_tga.desktop | 64 + kfile-plugins/tga/kfile_tga.h | 37 + kfile-plugins/tiff/Makefile.am | 21 + kfile-plugins/tiff/configure.in.in | 3 + kfile-plugins/tiff/kfile_tiff.cpp | 299 + kfile-plugins/tiff/kfile_tiff.desktop | 67 + kfile-plugins/tiff/kfile_tiff.h | 42 + kfile-plugins/xbm/Makefile.am | 22 + kfile-plugins/xbm/kfile_xbm.cpp | 128 + kfile-plugins/xbm/kfile_xbm.desktop | 65 + kfile-plugins/xbm/kfile_xbm.h | 42 + kfile-plugins/xpm/Makefile.am | 21 + kfile-plugins/xpm/kfile_xpm.cpp | 71 + kfile-plugins/xpm/kfile_xpm.desktop | 53 + kfile-plugins/xpm/kfile_xpm.h | 45 + kgamma/AUTHORS | 1 + kgamma/ChangeLog | 54 + kgamma/Makefile.am | 2 + kgamma/TODO | 1 + kgamma/configure.in.in | 65 + kgamma/kcmkgamma/Makefile.am | 18 + kgamma/kcmkgamma/displaynumber.cpp | 61 + kgamma/kcmkgamma/displaynumber.h | 41 + kgamma/kcmkgamma/gammactrl.cpp | 138 + kgamma/kcmkgamma/gammactrl.h | 76 + kgamma/kcmkgamma/kgamma.cpp | 625 ++ kgamma/kcmkgamma/kgamma.desktop | 129 + kgamma/kcmkgamma/kgamma.h | 78 + kgamma/kcmkgamma/pics/Makefile.am | 7 + kgamma/kcmkgamma/pics/background.png | Bin 0 -> 167 bytes kgamma/kcmkgamma/pics/cmyscale.png | Bin 0 -> 1033 bytes kgamma/kcmkgamma/pics/darkgrey.png | Bin 0 -> 502 bytes kgamma/kcmkgamma/pics/greyscale.png | Bin 0 -> 428 bytes kgamma/kcmkgamma/pics/hi16-app-kgamma.png | Bin 0 -> 427 bytes kgamma/kcmkgamma/pics/hi32-app-kgamma.png | Bin 0 -> 1015 bytes kgamma/kcmkgamma/pics/hi48-app-kgamma.png | Bin 0 -> 1314 bytes kgamma/kcmkgamma/pics/lightgrey.png | Bin 0 -> 473 bytes kgamma/kcmkgamma/pics/midgrey.png | Bin 0 -> 509 bytes kgamma/kcmkgamma/pics/rgbscale.png | Bin 0 -> 752 bytes kgamma/kcmkgamma/xf86configpath.cpp | 56 + kgamma/kcmkgamma/xf86configpath.h | 42 + kgamma/kcmkgamma/xvidextwrap.cpp | 170 + kgamma/kcmkgamma/xvidextwrap.h | 59 + kgamma/xf86gammacfg/Makefile.am | 11 + kgamma/xf86gammacfg/xf86gammacfg.cpp | 138 + kghostview/AUTHORS | 9 + kghostview/ChangeLog | 40 + kghostview/Makefile.am | 69 + kghostview/README | 27 + kghostview/TODO | 41 + kghostview/configuration.kcfgc | 4 + kghostview/data/Makefile.am | 3 + kghostview/data/pdf_sec.ps | 386 + kghostview/displayoptions.cpp | 150 + kghostview/displayoptions.h | 112 + kghostview/dscparse.cpp | 3432 ++++++++ kghostview/dscparse.h | 473 ++ kghostview/dscparse_adapter.cpp | 420 + kghostview/dscparse_adapter.h | 386 + kghostview/fullscreenfilter.cpp | 54 + kghostview/fullscreenfilter.h | 44 + kghostview/generalsettingswidget.ui | 111 + kghostview/generalsettingswidget.ui.h | 9 + kghostview/gssettingswidget.ui | 158 + kghostview/gssettingswidget.ui.h | 14 + kghostview/hi128-app-kghostview.png | Bin 0 -> 15812 bytes kghostview/hi16-app-kghostview.png | Bin 0 -> 991 bytes kghostview/hi22-app-kghostview.png | Bin 0 -> 1247 bytes kghostview/hi32-app-kghostview.png | Bin 0 -> 2218 bytes kghostview/hi48-app-kghostview.png | Bin 0 -> 3910 bytes kghostview/hi64-app-kghostview.png | Bin 0 -> 6493 bytes kghostview/infodialog.cpp | 131 + kghostview/infodialog.h | 44 + kghostview/kdscerrordialog.cpp | 170 + kghostview/kdscerrordialog.h | 74 + kghostview/kghostview.desktop | 86 + kghostview/kghostview.kcfg | 77 + kghostview/kghostview.upd | 13 + kghostview/kghostview_part.desktop | 19 + kghostview/kghostviewui.rc | 43 + kghostview/kgv.h | 15 + kghostview/kgv_miniwidget.cpp | 573 ++ kghostview/kgv_miniwidget.h | 173 + kghostview/kgv_part.rc | 110 + kghostview/kgv_view.cpp | 1037 +++ kghostview/kgv_view.h | 268 + kghostview/kgvconfigdialog.cpp | 154 + kghostview/kgvconfigdialog.h | 32 + kghostview/kgvdocument.cpp | 864 ++ kghostview/kgvdocument.h | 195 + kghostview/kgvfactory.cpp | 105 + kghostview/kgvfactory.h | 50 + kghostview/kgvmainwidget.cpp | 50 + kghostview/kgvmainwidget.h | 45 + kghostview/kgvpagedecorator.cpp | 106 + kghostview/kgvpagedecorator.h | 81 + kghostview/kgvpageview.cpp | 254 + kghostview/kgvpageview.h | 105 + kghostview/kgvshell.cpp | 370 + kghostview/kgvshell.h | 92 + kghostview/kpswidget.cpp | 530 ++ kghostview/kpswidget.h | 387 + kghostview/logwindow.cpp | 76 + kghostview/logwindow.h | 55 + kghostview/main.cpp | 71 + kghostview/marklist.cpp | 242 + kghostview/marklist.h | 88 + kghostview/part_init.cpp | 22 + kghostview/ps.c | 188 + kghostview/ps.h | 44 + kghostview/scrollbox.cpp | 129 + kghostview/scrollbox.h | 60 + kghostview/thumbnailservice.cpp | 161 + kghostview/thumbnailservice.h | 92 + kghostview/update-to-xt-names.pl | 36 + kghostview/version.h | 4 + kghostview/viewcontrol.cpp | 194 + kghostview/viewcontrol.h | 44 + kiconedit/AUTHORS | 10 + kiconedit/Makefile.am | 26 + kiconedit/NEWS | 68 + kiconedit/kcolorgrid.cpp | 335 + kiconedit/kcolorgrid.h | 104 + kiconedit/kicon.cpp | 279 + kiconedit/kicon.h | 78 + kiconedit/kiconcolors.cpp | 170 + kiconedit/kiconcolors.h | 83 + kiconedit/kiconconfig.cpp | 589 ++ kiconedit/kiconconfig.h | 153 + kiconedit/kiconedit.cpp | 497 ++ kiconedit/kiconedit.desktop | 95 + kiconedit/kiconedit.h | 157 + kiconedit/kiconeditslots.cpp | 543 ++ kiconedit/kiconeditui.rc | 66 + kiconedit/kicongrid.cpp | 2263 +++++ kiconedit/kicongrid.h | 263 + kiconedit/knew.cpp | 326 + kiconedit/knew.h | 164 + kiconedit/kresize.cpp | 83 + kiconedit/kresize.h | 62 + kiconedit/main.cpp | 89 + kiconedit/palettetoolbar.cpp | 178 + kiconedit/palettetoolbar.h | 63 + kiconedit/pics/Makefile.am | 5 + kiconedit/pics/hi16-app-kiconedit.png | Bin 0 -> 406 bytes kiconedit/pics/hi22-app-kiconedit.png | Bin 0 -> 1101 bytes kiconedit/pics/hi32-app-kiconedit.png | Bin 0 -> 853 bytes kiconedit/pics/hi48-app-kiconedit.png | Bin 0 -> 1187 bytes kiconedit/pics/icons/Makefile.am | 5 + kiconedit/pics/icons/compressed.png | Bin 0 -> 530 bytes kiconedit/pics/icons/source.png | Bin 0 -> 473 bytes kiconedit/pics/icons/standard.png | Bin 0 -> 611 bytes kiconedit/pics/logo.xpm | 137 + kiconedit/pics/toolbar/Makefile.am | 28 + kiconedit/pics/toolbar/aim-cursor.xpm | 28 + kiconedit/pics/toolbar/aim.png | Bin 0 -> 303 bytes kiconedit/pics/toolbar/airbrush-cursor.xpm | 35 + kiconedit/pics/toolbar/areaselect.png | Bin 0 -> 290 bytes kiconedit/pics/toolbar/circle.png | Bin 0 -> 274 bytes kiconedit/pics/toolbar/colorpicker-cursor.xpm | 36 + kiconedit/pics/toolbar/ellipse.png | Bin 0 -> 257 bytes kiconedit/pics/toolbar/eraser-cursor.xpm | 32 + kiconedit/pics/toolbar/fileclose.png | Bin 0 -> 317 bytes kiconedit/pics/toolbar/fill-cursor.xpm | 36 + kiconedit/pics/toolbar/filledcircle.png | Bin 0 -> 279 bytes kiconedit/pics/toolbar/filledellipse.png | Bin 0 -> 262 bytes kiconedit/pics/toolbar/filledrectangle.png | Bin 0 -> 238 bytes kiconedit/pics/toolbar/flood-cursor.xpm | 32 + kiconedit/pics/toolbar/flood.png | Bin 0 -> 440 bytes kiconedit/pics/toolbar/grayscale.png | Bin 0 -> 449 bytes kiconedit/pics/toolbar/grid.png | Bin 0 -> 236 bytes kiconedit/pics/toolbar/kdepalette.png | Bin 0 -> 416 bytes kiconedit/pics/toolbar/line.png | Bin 0 -> 222 bytes kiconedit/pics/toolbar/paintbrush-cursor.xpm | 36 + kiconedit/pics/toolbar/paintbrush.png | Bin 0 -> 374 bytes kiconedit/pics/toolbar/pointer.png | Bin 0 -> 298 bytes kiconedit/pics/toolbar/rectangle.png | Bin 0 -> 246 bytes kiconedit/pics/toolbar/selectcircle.png | Bin 0 -> 274 bytes kiconedit/pics/toolbar/selectrect.png | Bin 0 -> 243 bytes kiconedit/pics/toolbar/spraycan-cursor.xpm | 30 + kiconedit/pics/toolbar/spraycan.png | Bin 0 -> 407 bytes kiconedit/pics/toolbar/transform.png | Bin 0 -> 409 bytes kiconedit/pics/toolbar/window_new.png | Bin 0 -> 799 bytes kiconedit/properties.cpp | 147 + kiconedit/properties.h | 82 + kiconedit/utils.cpp | 134 + kiconedit/utils.h | 73 + kiconedit/version.h | 36 + kmrml/AUTHORS | 1 + kmrml/ChangeLog | 28 + kmrml/Makefile.am | 1 + kmrml/README | 95 + kmrml/README.DEVELOPMENT | 41 + kmrml/TODO | 15 + kmrml/example-session.mrml | 142 + kmrml/kmrml.lsm | 27 + kmrml/kmrml.spec | 62 + kmrml/kmrml/Makefile.am | 41 + kmrml/kmrml/algorithmcombo.cpp | 66 + kmrml/kmrml/algorithmcombo.h | 54 + kmrml/kmrml/algorithmdialog.cpp | 132 + kmrml/kmrml/algorithmdialog.h | 60 + kmrml/kmrml/browser.cpp | 63 + kmrml/kmrml/browser.h | 48 + kmrml/kmrml/collectioncombo.cpp | 95 + kmrml/kmrml/collectioncombo.h | 57 + kmrml/kmrml/kcontrol/Makefile.am | 25 + kmrml/kmrml/kcontrol/indexcleaner.cpp | 96 + kmrml/kmrml/kcontrol/indexcleaner.h | 53 + kmrml/kmrml/kcontrol/indexer.cpp | 190 + kmrml/kmrml/kcontrol/indexer.h | 68 + kmrml/kmrml/kcontrol/indextest.cpp | 43 + kmrml/kmrml/kcontrol/indextest.h | 26 + kmrml/kmrml/kcontrol/kcmkmrml.cpp | 146 + kmrml/kmrml/kcontrol/kcmkmrml.desktop | 176 + kmrml/kmrml/kcontrol/kcmkmrml.h | 52 + kmrml/kmrml/kcontrol/mainpage.cpp | 501 ++ kmrml/kmrml/kcontrol/mainpage.h | 109 + kmrml/kmrml/kcontrol/serverconfigwidget.ui | 272 + kmrml/kmrml/lib/Makefile.am | 11 + kmrml/kmrml/lib/kmrml_config.cpp | 339 + kmrml/kmrml/lib/kmrml_config.h | 123 + kmrml/kmrml/lib/mrml_shared.cpp | 235 + kmrml/kmrml/lib/mrml_shared.h | 166 + kmrml/kmrml/lib/mrml_utils.cpp | 89 + kmrml/kmrml/lib/mrml_utils.h | 50 + kmrml/kmrml/lib/version.h | 6 + kmrml/kmrml/lib/watcher_stub.cpp | 95 + kmrml/kmrml/lib/watcher_stub.h | 36 + kmrml/kmrml/loader.cpp | 121 + kmrml/kmrml/loader.h | 72 + kmrml/kmrml/mrml-servicemenu.desktop | 67 + kmrml/kmrml/mrml.cpp | 267 + kmrml/kmrml/mrml.desktop | 60 + kmrml/kmrml/mrml.h | 84 + kmrml/kmrml/mrml.protocol | 10 + kmrml/kmrml/mrml_creator.cpp | 76 + kmrml/kmrml/mrml_creator.h | 49 + kmrml/kmrml/mrml_elements.cpp | 358 + kmrml/kmrml/mrml_elements.h | 255 + kmrml/kmrml/mrml_part.cpp | 857 ++ kmrml/kmrml/mrml_part.desktop | 67 + kmrml/kmrml/mrml_part.h | 175 + kmrml/kmrml/mrml_view.cpp | 480 ++ kmrml/kmrml/mrml_view.h | 180 + kmrml/kmrml/mrmlsearch.cpp | 74 + kmrml/kmrml/propertysheet.cpp | 206 + kmrml/kmrml/propertysheet.h | 113 + kmrml/kmrml/propertywidgets.cpp | 121 + kmrml/kmrml/propertywidgets.h | 108 + kmrml/kmrml/server/Makefile.am | 12 + kmrml/kmrml/server/daemonwatcher.desktop | 103 + kmrml/kmrml/server/watcher.cpp | 280 + kmrml/kmrml/server/watcher.h | 107 + kolourpaint/AUTHORS | 112 + kolourpaint/BUGS | 154 + kolourpaint/COPYING | 23 + kolourpaint/ChangeLog | 15 + kolourpaint/Makefile.am | 76 + kolourpaint/NEWS | 349 + kolourpaint/README | 102 + kolourpaint/VERSION | 1 + kolourpaint/cursors/Makefile.am | 11 + kolourpaint/cursors/kpcursorlightcross.cpp | 128 + kolourpaint/cursors/kpcursorlightcross.h | 38 + kolourpaint/cursors/kpcursorprovider.cpp | 49 + kolourpaint/cursors/kpcursorprovider.h | 43 + kolourpaint/kolourpaint.cpp | 229 + kolourpaint/kolourpaint.desktop | 92 + kolourpaint/kolourpaintui.rc | 169 + kolourpaint/kpcolor.cpp | 360 + kolourpaint/kpcolor.h | 101 + kolourpaint/kpcommandhistory.cpp | 939 +++ kolourpaint/kpcommandhistory.h | 255 + kolourpaint/kpdefs.h | 151 + kolourpaint/kpdocument.cpp | 1539 ++++ kolourpaint/kpdocument.h | 260 + kolourpaint/kpdocumentmetainfo.cpp | 186 + kolourpaint/kpdocumentmetainfo.h | 90 + kolourpaint/kpdocumentsaveoptions.cpp | 561 ++ kolourpaint/kpdocumentsaveoptions.h | 150 + kolourpaint/kpdocumentsaveoptionswidget.cpp | 951 +++ kolourpaint/kpdocumentsaveoptionswidget.h | 200 + kolourpaint/kpmainwindow.cpp | 1061 +++ kolourpaint/kpmainwindow.h | 739 ++ kolourpaint/kpmainwindow_edit.cpp | 1069 +++ kolourpaint/kpmainwindow_file.cpp | 1409 ++++ kolourpaint/kpmainwindow_help.cpp | 219 + kolourpaint/kpmainwindow_image.cpp | 474 ++ kolourpaint/kpmainwindow_p.h | 49 + kolourpaint/kpmainwindow_settings.cpp | 209 + kolourpaint/kpmainwindow_statusbar.cpp | 417 + kolourpaint/kpmainwindow_text.cpp | 395 + kolourpaint/kpmainwindow_tools.cpp | 646 ++ kolourpaint/kpmainwindow_view.cpp | 1151 +++ kolourpaint/kpselection.cpp | 1446 ++++ kolourpaint/kpselection.h | 237 + kolourpaint/kpselectiondrag.cpp | 294 + kolourpaint/kpselectiondrag.h | 71 + kolourpaint/kpselectiontransparency.cpp | 178 + kolourpaint/kpselectiontransparency.h | 80 + kolourpaint/kpsinglekeytriggersaction.cpp | 155 + kolourpaint/kpsinglekeytriggersaction.h | 82 + kolourpaint/kptemppixmap.cpp | 148 + kolourpaint/kptemppixmap.h | 90 + kolourpaint/kptextstyle.cpp | 279 + kolourpaint/kptextstyle.h | 108 + kolourpaint/kpthumbnail.cpp | 213 + kolourpaint/kpthumbnail.h | 68 + kolourpaint/kptool.cpp | 1666 ++++ kolourpaint/kptool.h | 422 + kolourpaint/kpview.cpp | 1910 +++++ kolourpaint/kpview.h | 535 ++ kolourpaint/kpviewmanager.cpp | 766 ++ kolourpaint/kpviewmanager.h | 220 + kolourpaint/kpviewscrollablecontainer.cpp | 1390 +++ kolourpaint/kpviewscrollablecontainer.h | 255 + kolourpaint/kpwidgetmapper.cpp | 76 + kolourpaint/kpwidgetmapper.h | 47 + .../patches/checkerboard-faster-render.diff | 141 + kolourpaint/patches/color_eraser_speedup.diff | 264 + kolourpaint/patches/doc_resize_no_flicker.diff | 614 ++ kolourpaint/pics/Makefile.am | 13 + kolourpaint/pics/cr16-action-tool_brush.png | Bin 0 -> 675 bytes kolourpaint/pics/cr16-action-tool_color_picker.png | Bin 0 -> 656 bytes kolourpaint/pics/cr16-action-tool_color_washer.png | Bin 0 -> 1010 bytes kolourpaint/pics/cr16-action-tool_curve.png | Bin 0 -> 483 bytes kolourpaint/pics/cr16-action-tool_ellipse.png | Bin 0 -> 837 bytes .../pics/cr16-action-tool_elliptical_selection.png | Bin 0 -> 906 bytes kolourpaint/pics/cr16-action-tool_eraser.png | Bin 0 -> 806 bytes kolourpaint/pics/cr16-action-tool_flood_fill.png | Bin 0 -> 638 bytes .../pics/cr16-action-tool_free_form_selection.png | Bin 0 -> 855 bytes kolourpaint/pics/cr16-action-tool_line.png | Bin 0 -> 439 bytes kolourpaint/pics/cr16-action-tool_pen.png | Bin 0 -> 579 bytes kolourpaint/pics/cr16-action-tool_polygon.png | Bin 0 -> 907 bytes kolourpaint/pics/cr16-action-tool_polyline.png | Bin 0 -> 543 bytes .../pics/cr16-action-tool_rect_selection.png | Bin 0 -> 921 bytes kolourpaint/pics/cr16-action-tool_rectangle.png | Bin 0 -> 557 bytes .../pics/cr16-action-tool_rounded_rectangle.png | Bin 0 -> 729 bytes kolourpaint/pics/cr16-action-tool_spraycan.png | Bin 0 -> 784 bytes kolourpaint/pics/cr16-action-tool_text.png | Bin 0 -> 401 bytes kolourpaint/pics/cr22-action-tool_brush.png | Bin 0 -> 981 bytes kolourpaint/pics/cr22-action-tool_color_picker.png | Bin 0 -> 981 bytes kolourpaint/pics/cr22-action-tool_color_washer.png | Bin 0 -> 1555 bytes kolourpaint/pics/cr22-action-tool_curve.png | Bin 0 -> 639 bytes kolourpaint/pics/cr22-action-tool_ellipse.png | Bin 0 -> 1206 bytes .../pics/cr22-action-tool_elliptical_selection.png | Bin 0 -> 1317 bytes kolourpaint/pics/cr22-action-tool_eraser.png | Bin 0 -> 1226 bytes kolourpaint/pics/cr22-action-tool_flood_fill.png | Bin 0 -> 865 bytes .../pics/cr22-action-tool_free_form_selection.png | Bin 0 -> 1259 bytes kolourpaint/pics/cr22-action-tool_line.png | Bin 0 -> 502 bytes kolourpaint/pics/cr22-action-tool_pen.png | Bin 0 -> 857 bytes kolourpaint/pics/cr22-action-tool_polygon.png | Bin 0 -> 1357 bytes kolourpaint/pics/cr22-action-tool_polyline.png | Bin 0 -> 776 bytes .../pics/cr22-action-tool_rect_selection.png | Bin 0 -> 1337 bytes kolourpaint/pics/cr22-action-tool_rectangle.png | Bin 0 -> 815 bytes .../pics/cr22-action-tool_rounded_rectangle.png | Bin 0 -> 1111 bytes kolourpaint/pics/cr22-action-tool_spraycan.png | Bin 0 -> 1158 bytes kolourpaint/pics/cr22-action-tool_text.png | Bin 0 -> 734 bytes kolourpaint/pics/cr32-action-tool_brush.png | Bin 0 -> 1601 bytes kolourpaint/pics/cr32-action-tool_color_picker.png | Bin 0 -> 1590 bytes kolourpaint/pics/cr32-action-tool_color_washer.png | Bin 0 -> 2612 bytes kolourpaint/pics/cr32-action-tool_curve.png | Bin 0 -> 947 bytes kolourpaint/pics/cr32-action-tool_ellipse.png | Bin 0 -> 1872 bytes .../pics/cr32-action-tool_elliptical_selection.png | Bin 0 -> 2179 bytes kolourpaint/pics/cr32-action-tool_eraser.png | Bin 0 -> 2047 bytes kolourpaint/pics/cr32-action-tool_flood_fill.png | Bin 0 -> 1275 bytes .../pics/cr32-action-tool_free_form_selection.png | Bin 0 -> 2078 bytes kolourpaint/pics/cr32-action-tool_line.png | Bin 0 -> 685 bytes kolourpaint/pics/cr32-action-tool_pen.png | Bin 0 -> 1307 bytes kolourpaint/pics/cr32-action-tool_polygon.png | Bin 0 -> 2036 bytes kolourpaint/pics/cr32-action-tool_polyline.png | Bin 0 -> 1101 bytes .../pics/cr32-action-tool_rect_selection.png | Bin 0 -> 2128 bytes kolourpaint/pics/cr32-action-tool_rectangle.png | Bin 0 -> 1002 bytes .../pics/cr32-action-tool_rounded_rectangle.png | Bin 0 -> 1683 bytes kolourpaint/pics/cr32-action-tool_spraycan.png | Bin 0 -> 1928 bytes kolourpaint/pics/cr32-action-tool_text.png | Bin 0 -> 1078 bytes kolourpaint/pics/cr48-action-tool_brush.png | Bin 0 -> 2792 bytes kolourpaint/pics/cr48-action-tool_color_picker.png | Bin 0 -> 2672 bytes kolourpaint/pics/cr48-action-tool_color_washer.png | Bin 0 -> 4572 bytes kolourpaint/pics/cr48-action-tool_curve.png | Bin 0 -> 1404 bytes kolourpaint/pics/cr48-action-tool_ellipse.png | Bin 0 -> 2873 bytes .../pics/cr48-action-tool_elliptical_selection.png | Bin 0 -> 3442 bytes kolourpaint/pics/cr48-action-tool_eraser.png | Bin 0 -> 3544 bytes kolourpaint/pics/cr48-action-tool_flood_fill.png | Bin 0 -> 2052 bytes .../pics/cr48-action-tool_free_form_selection.png | Bin 0 -> 3607 bytes kolourpaint/pics/cr48-action-tool_line.png | Bin 0 -> 981 bytes kolourpaint/pics/cr48-action-tool_pen.png | Bin 0 -> 2163 bytes kolourpaint/pics/cr48-action-tool_polygon.png | Bin 0 -> 3351 bytes kolourpaint/pics/cr48-action-tool_polyline.png | Bin 0 -> 1647 bytes .../pics/cr48-action-tool_rect_selection.png | Bin 0 -> 3658 bytes kolourpaint/pics/cr48-action-tool_rectangle.png | Bin 0 -> 1503 bytes .../pics/cr48-action-tool_rounded_rectangle.png | Bin 0 -> 2539 bytes kolourpaint/pics/cr48-action-tool_spraycan.png | Bin 0 -> 3341 bytes kolourpaint/pics/cr48-action-tool_text.png | Bin 0 -> 1539 bytes kolourpaint/pics/crsc-action-tool_brush.svgz | Bin 0 -> 9005 bytes .../pics/crsc-action-tool_color_picker.svgz | Bin 0 -> 12495 bytes .../pics/crsc-action-tool_color_washer.svgz | Bin 0 -> 8859 bytes kolourpaint/pics/crsc-action-tool_curve.svgz | Bin 0 -> 2442 bytes kolourpaint/pics/crsc-action-tool_ellipse.svgz | Bin 0 -> 2061 bytes .../crsc-action-tool_elliptical_selection.svgz | Bin 0 -> 3828 bytes kolourpaint/pics/crsc-action-tool_eraser.svgz | Bin 0 -> 7708 bytes kolourpaint/pics/crsc-action-tool_flood_fill.svgz | Bin 0 -> 2992 bytes .../pics/crsc-action-tool_free_form_selection.svgz | Bin 0 -> 5071 bytes kolourpaint/pics/crsc-action-tool_line.svgz | Bin 0 -> 1359 bytes kolourpaint/pics/crsc-action-tool_pen.svgz | Bin 0 -> 5120 bytes kolourpaint/pics/crsc-action-tool_polygon.svgz | Bin 0 -> 2360 bytes kolourpaint/pics/crsc-action-tool_polyline.svgz | Bin 0 -> 2139 bytes .../pics/crsc-action-tool_rect_selection.svgz | Bin 0 -> 4031 bytes kolourpaint/pics/crsc-action-tool_rectangle.svgz | Bin 0 -> 2021 bytes .../pics/crsc-action-tool_rounded_rectangle.svgz | Bin 0 -> 2294 bytes kolourpaint/pics/crsc-action-tool_spraycan.svgz | Bin 0 -> 9431 bytes kolourpaint/pics/crsc-action-tool_text.svgz | Bin 0 -> 2732 bytes kolourpaint/pics/custom/Makefile.am | 10 + .../pics/custom/color_transparent_26x26.png | Bin 0 -> 1055 bytes kolourpaint/pics/custom/colorbutton_swap_16x16.png | Bin 0 -> 166 bytes .../pics/custom/image_rotate_anticlockwise.png | Bin 0 -> 371 bytes kolourpaint/pics/custom/image_rotate_clockwise.png | Bin 0 -> 363 bytes kolourpaint/pics/custom/image_skew_horizontal.png | Bin 0 -> 347 bytes kolourpaint/pics/custom/image_skew_vertical.png | Bin 0 -> 424 bytes kolourpaint/pics/custom/option_opaque.png | Bin 0 -> 787 bytes kolourpaint/pics/custom/option_transparent.png | Bin 0 -> 888 bytes kolourpaint/pics/custom/resize.png | Bin 0 -> 4465 bytes kolourpaint/pics/custom/scale.png | Bin 0 -> 2222 bytes kolourpaint/pics/custom/smooth_scale.png | Bin 0 -> 5556 bytes kolourpaint/pics/custom/tool_spraycan_17x17.png | Bin 0 -> 188 bytes kolourpaint/pics/custom/tool_spraycan_29x29.png | Bin 0 -> 364 bytes kolourpaint/pics/custom/tool_spraycan_9x9.png | Bin 0 -> 121 bytes kolourpaint/pics/hi16-app-kolourpaint.png | Bin 0 -> 814 bytes kolourpaint/pics/hi22-app-kolourpaint.png | Bin 0 -> 1269 bytes kolourpaint/pics/hi32-app-kolourpaint.png | Bin 0 -> 2231 bytes kolourpaint/pics/hi48-app-kolourpaint.png | Bin 0 -> 4087 bytes kolourpaint/pics/hisc-app-kolourpaint.svgz | Bin 0 -> 14604 bytes kolourpaint/pixmapfx/Makefile.am | 19 + kolourpaint/pixmapfx/kpcoloreffect.cpp | 168 + kolourpaint/pixmapfx/kpcoloreffect.h | 111 + kolourpaint/pixmapfx/kpeffectbalance.cpp | 517 ++ kolourpaint/pixmapfx/kpeffectbalance.h | 116 + kolourpaint/pixmapfx/kpeffectblursharpen.cpp | 291 + kolourpaint/pixmapfx/kpeffectblursharpen.h | 105 + kolourpaint/pixmapfx/kpeffectemboss.cpp | 228 + kolourpaint/pixmapfx/kpeffectemboss.h | 93 + kolourpaint/pixmapfx/kpeffectflatten.cpp | 266 + kolourpaint/pixmapfx/kpeffectflatten.h | 115 + kolourpaint/pixmapfx/kpeffectinvert.cpp | 315 + kolourpaint/pixmapfx/kpeffectinvert.h | 130 + kolourpaint/pixmapfx/kpeffectreducecolors.cpp | 446 + kolourpaint/pixmapfx/kpeffectreducecolors.h | 110 + kolourpaint/pixmapfx/kpeffectsdialog.cpp | 369 + kolourpaint/pixmapfx/kpeffectsdialog.h | 90 + kolourpaint/pixmapfx/kpfloodfill.cpp | 362 + kolourpaint/pixmapfx/kpfloodfill.h | 106 + kolourpaint/pixmapfx/kppixmapfx.cpp | 1677 ++++ kolourpaint/pixmapfx/kppixmapfx.h | 450 + kolourpaint/tests/45deg_line.png | Bin 0 -> 106 bytes kolourpaint/tests/4x4-transparent.png | Bin 0 -> 98 bytes kolourpaint/tests/5x5.png | Bin 0 -> 109 bytes kolourpaint/tests/depth1.bmp | Bin 0 -> 462 bytes kolourpaint/tests/dither.png | Bin 0 -> 2894 bytes kolourpaint/tests/rotate.png | Bin 0 -> 84 bytes kolourpaint/tests/small16x16.png | Bin 0 -> 155 bytes kolourpaint/tests/tool_fill_xlimit.png | Bin 0 -> 173 bytes kolourpaint/tests/transparent.png | Bin 0 -> 212 bytes kolourpaint/tests/transparent_selection.png | Bin 0 -> 694 bytes kolourpaint/tools/Makefile.am | 53 + kolourpaint/tools/kptoolaction.cpp | 107 + kolourpaint/tools/kptoolaction.h | 78 + kolourpaint/tools/kptoolairspray.cpp | 376 + kolourpaint/tools/kptoolairspray.h | 110 + kolourpaint/tools/kptoolautocrop.cpp | 780 ++ kolourpaint/tools/kptoolautocrop.h | 127 + kolourpaint/tools/kptoolbrush.cpp | 45 + kolourpaint/tools/kptoolbrush.h | 43 + kolourpaint/tools/kptoolclear.cpp | 135 + kolourpaint/tools/kptoolclear.h | 68 + kolourpaint/tools/kptoolcolorpicker.cpp | 197 + kolourpaint/tools/kptoolcolorpicker.h | 95 + kolourpaint/tools/kptoolcolorwasher.cpp | 45 + kolourpaint/tools/kptoolcolorwasher.h | 43 + kolourpaint/tools/kptoolconverttograyscale.cpp | 106 + kolourpaint/tools/kptoolconverttograyscale.h | 57 + kolourpaint/tools/kptoolcrop.cpp | 335 + kolourpaint/tools/kptoolcrop.h | 39 + kolourpaint/tools/kptoolcurve.cpp | 47 + kolourpaint/tools/kptoolcurve.h | 45 + kolourpaint/tools/kptoolellipse.cpp | 45 + kolourpaint/tools/kptoolellipse.h | 45 + kolourpaint/tools/kptoolellipticalselection.cpp | 46 + kolourpaint/tools/kptoolellipticalselection.h | 43 + kolourpaint/tools/kptooleraser.cpp | 44 + kolourpaint/tools/kptooleraser.h | 43 + kolourpaint/tools/kptoolflip.cpp | 213 + kolourpaint/tools/kptoolflip.h | 88 + kolourpaint/tools/kptoolfloodfill.cpp | 261 + kolourpaint/tools/kptoolfloodfill.h | 94 + kolourpaint/tools/kptoolfreeformselection.cpp | 46 + kolourpaint/tools/kptoolfreeformselection.h | 43 + kolourpaint/tools/kptoolline.cpp | 47 + kolourpaint/tools/kptoolline.h | 45 + kolourpaint/tools/kptoolpen.cpp | 1145 +++ kolourpaint/tools/kptoolpen.h | 160 + kolourpaint/tools/kptoolpolygon.cpp | 895 ++ kolourpaint/tools/kptoolpolygon.h | 157 + kolourpaint/tools/kptoolpolyline.cpp | 47 + kolourpaint/tools/kptoolpolyline.h | 46 + kolourpaint/tools/kptoolpreviewdialog.cpp | 431 + kolourpaint/tools/kptoolpreviewdialog.h | 131 + kolourpaint/tools/kptoolrectangle.cpp | 638 ++ kolourpaint/tools/kptoolrectangle.h | 142 + kolourpaint/tools/kptoolrectselection.cpp | 46 + kolourpaint/tools/kptoolrectselection.h | 43 + kolourpaint/tools/kptoolresizescale.cpp | 1222 +++ kolourpaint/tools/kptoolresizescale.h | 196 + kolourpaint/tools/kptoolrotate.cpp | 500 ++ kolourpaint/tools/kptoolrotate.h | 129 + kolourpaint/tools/kptoolroundedrectangle.cpp | 45 + kolourpaint/tools/kptoolroundedrectangle.h | 45 + kolourpaint/tools/kptoolselection.cpp | 2371 ++++++ kolourpaint/tools/kptoolselection.h | 313 + kolourpaint/tools/kptoolskew.cpp | 449 + kolourpaint/tools/kptoolskew.h | 121 + kolourpaint/tools/kptooltext.cpp | 1394 +++ kolourpaint/tools/kptooltext.h | 203 + kolourpaint/views/Makefile.am | 14 + kolourpaint/views/kpthumbnailview.cpp | 98 + kolourpaint/views/kpthumbnailview.h | 90 + kolourpaint/views/kpunzoomedthumbnailview.cpp | 212 + kolourpaint/views/kpunzoomedthumbnailview.h | 106 + kolourpaint/views/kpzoomedthumbnailview.cpp | 140 + kolourpaint/views/kpzoomedthumbnailview.h | 95 + kolourpaint/views/kpzoomedview.cpp | 103 + kolourpaint/views/kpzoomedview.h | 96 + kolourpaint/widgets/Makefile.am | 21 + kolourpaint/widgets/kpcolorsimilaritycube.cpp | 348 + kolourpaint/widgets/kpcolorsimilaritycube.h | 72 + kolourpaint/widgets/kpcolorsimilaritydialog.cpp | 123 + kolourpaint/widgets/kpcolorsimilaritydialog.h | 62 + kolourpaint/widgets/kpcolortoolbar.cpp | 1112 +++ kolourpaint/widgets/kpcolortoolbar.h | 297 + kolourpaint/widgets/kpresizesignallinglabel.cpp | 67 + kolourpaint/widgets/kpresizesignallinglabel.h | 52 + kolourpaint/widgets/kpsqueezedtextlabel.cpp | 215 + kolourpaint/widgets/kpsqueezedtextlabel.h | 65 + kolourpaint/widgets/kptooltoolbar.cpp | 640 ++ kolourpaint/widgets/kptooltoolbar.h | 155 + kolourpaint/widgets/kptoolwidgetbase.cpp | 608 ++ kolourpaint/widgets/kptoolwidgetbase.h | 112 + kolourpaint/widgets/kptoolwidgetbrush.cpp | 184 + kolourpaint/widgets/kptoolwidgetbrush.h | 61 + kolourpaint/widgets/kptoolwidgeterasersize.cpp | 161 + kolourpaint/widgets/kptoolwidgeterasersize.h | 59 + kolourpaint/widgets/kptoolwidgetfillstyle.cpp | 222 + kolourpaint/widgets/kptoolwidgetfillstyle.h | 80 + kolourpaint/widgets/kptoolwidgetlinewidth.cpp | 97 + kolourpaint/widgets/kptoolwidgetlinewidth.h | 51 + .../widgets/kptoolwidgetopaqueortransparent.cpp | 100 + .../widgets/kptoolwidgetopaqueortransparent.h | 56 + kolourpaint/widgets/kptoolwidgetspraycansize.cpp | 119 + kolourpaint/widgets/kptoolwidgetspraycansize.h | 51 + kooka/AUTHORS | 2 + kooka/CHANGES | 158 + kooka/COPYING | 339 + kooka/CREDITS | 4 + kooka/INSTALL | 181 + kooka/Makefile.am | 46 + kooka/README | 66 + kooka/README.KADMOS | 73 + kooka/TODO | 26 + kooka/WARNING | 28 + kooka/configure.in.in | 33 + kooka/dwmenuaction.cpp | 72 + kooka/dwmenuaction.h | 62 + kooka/formathelp.h | 43 + kooka/imageselectline.cpp | 105 + kooka/imageselectline.h | 66 + kooka/img_saver.cpp | 897 ++ kooka/img_saver.h | 208 + kooka/imgnamecombo.cpp | 93 + kooka/imgnamecombo.h | 57 + kooka/imgprintdialog.cpp | 302 + kooka/imgprintdialog.h | 89 + kooka/kadmosocr.cpp | 432 + kooka/kadmosocr.h | 143 + kooka/kocrbase.cpp | 368 + kooka/kocrbase.h | 158 + kooka/kocrgocr.cpp | 201 + kooka/kocrgocr.h | 86 + kooka/kocrkadmos.cpp | 521 ++ kooka/kocrkadmos.h | 128 + kooka/kocrocrad.cpp | 263 + kooka/kocrocrad.h | 106 + kooka/kooka.cpp | 465 + kooka/kooka.desktop | 78 + kooka/kooka.h | 141 + kooka/kookaiface.h | 13 + kooka/kookaimage.cpp | 413 + kooka/kookaimage.h | 170 + kooka/kookaimagemeta.cpp | 51 + kooka/kookaimagemeta.h | 54 + kooka/kookapref.cpp | 547 ++ kooka/kookapref.h | 100 + kooka/kookaprint.cpp | 410 + kooka/kookaprint.h | 95 + kooka/kookarc | 121 + kooka/kookaui.rc | 62 + kooka/kookaview.cpp | 1083 +++ kooka/kookaview.h | 241 + kooka/ksaneocr.cpp | 1493 ++++ kooka/ksaneocr.h | 285 + kooka/main.cpp | 121 + kooka/ocrresedit.cpp | 148 + kooka/ocrresedit.h | 65 + kooka/ocrword.cpp | 157 + kooka/ocrword.h | 111 + kooka/pics/Makefile.am | 8 + kooka/pics/gocr.png | Bin 0 -> 5824 bytes kooka/pics/lockzoom.png | Bin 0 -> 1185 bytes kooka/pics/mirror-both.png | Bin 0 -> 471 bytes kooka/pics/mirror-horiz.png | Bin 0 -> 452 bytes kooka/pics/mirror-vert.png | Bin 0 -> 480 bytes kooka/pics/newfromselect.png | Bin 0 -> 287 bytes kooka/pics/ocr-select.png | Bin 0 -> 899 bytes kooka/pics/ocr.png | Bin 0 -> 950 bytes kooka/pics/ocrad.png | Bin 0 -> 244 bytes kooka/pics/scaleorig.png | Bin 0 -> 656 bytes kooka/pics/scaletoheight.png | Bin 0 -> 591 bytes kooka/pics/scaletowidth.png | Bin 0 -> 590 bytes kooka/pics/thumbviewtile.png | Bin 0 -> 16383 bytes kooka/resource.h | 94 + kooka/scanpackager.cpp | 1261 +++ kooka/scanpackager.h | 167 + kooka/thumbview.cpp | 494 ++ kooka/thumbview.h | 153 + kooka/thumbviewitem.cpp | 49 + kooka/thumbviewitem.h | 60 + kooka/version.h | 4 + kpdf/AUTHORS | 6 + kpdf/COPYING | 339 + kpdf/Makefile.am | 30 + kpdf/README.internals.png | Bin 0 -> 43015 bytes kpdf/TODO | 173 + kpdf/VERSION | 1 + kpdf/conf/Makefile.am | 13 + kpdf/conf/dlgaccessibility.ui | 576 ++ kpdf/conf/dlggeneral.ui | 171 + kpdf/conf/dlggeneral.ui.h | 26 + kpdf/conf/dlgperformance.ui | 278 + kpdf/conf/dlgperformance.ui.h | 38 + kpdf/conf/dlgpresentation.ui | 282 + kpdf/conf/kpdf.kcfg | 177 + kpdf/conf/preferencesdialog.cpp | 34 + kpdf/conf/preferencesdialog.h | 44 + kpdf/conf/settings.kcfgc | 4 + kpdf/configure.in.bot | 30 + kpdf/configure.in.in | 124 + kpdf/core/Makefile.am | 13 + kpdf/core/document.cpp | 1634 ++++ kpdf/core/document.h | 225 + kpdf/core/generator.h | 115 + kpdf/core/generator_kimgio/Makefile.am | 6 + kpdf/core/generator_kimgio/generator_kimgio.cpp | 72 + kpdf/core/generator_kimgio/generator_kimgio.h | 43 + kpdf/core/generator_pdf/Makefile.am | 10 + kpdf/core/generator_pdf/generator_pdf.cpp | 1258 +++ kpdf/core/generator_pdf/generator_pdf.h | 150 + kpdf/core/generator_pdf/gp_outputdev.cpp | 397 + kpdf/core/generator_pdf/gp_outputdev.h | 90 + kpdf/core/link.cpp | 65 + kpdf/core/link.h | 118 + kpdf/core/observer.h | 58 + kpdf/core/page.cpp | 327 + kpdf/core/page.h | 149 + kpdf/core/pagetransition.cpp | 28 + kpdf/core/pagetransition.h | 86 + kpdf/dcop.h | 35 + kpdf/error.cpp | 44 + kpdf/hi128-app-kpdf.png | Bin 0 -> 14500 bytes kpdf/hi16-app-kpdf.png | Bin 0 -> 766 bytes kpdf/hi22-app-kpdf.png | Bin 0 -> 1184 bytes kpdf/hi32-app-kpdf.png | Bin 0 -> 2101 bytes kpdf/hi48-app-kpdf.png | Bin 0 -> 3452 bytes kpdf/hi64-app-kpdf.png | Bin 0 -> 5842 bytes kpdf/hisc-app-kpdf.svgz | Bin 0 -> 11018 bytes kpdf/kpdf_part.desktop | 11 + kpdf/part.cpp | 1100 +++ kpdf/part.h | 212 + kpdf/part.rc | 64 + kpdf/shell/Makefile.am | 15 + kpdf/shell/kpdf.desktop | 82 + kpdf/shell/main.cpp | 82 + kpdf/shell/shell.cpp | 262 + kpdf/shell/shell.h | 112 + kpdf/shell/shell.rc | 21 + kpdf/ui/Makefile.am | 17 + kpdf/ui/minibar.cpp | 436 + kpdf/ui/minibar.h | 61 + kpdf/ui/pagepainter.cpp | 252 + kpdf/ui/pagepainter.h | 36 + kpdf/ui/pageview.cpp | 2114 +++++ kpdf/ui/pageview.h | 148 + kpdf/ui/pageviewutils.cpp | 207 + kpdf/ui/pageviewutils.h | 72 + kpdf/ui/presentationwidget.cpp | 1330 +++ kpdf/ui/presentationwidget.h | 108 + kpdf/ui/propertiesdialog.cpp | 94 + kpdf/ui/propertiesdialog.h | 23 + kpdf/ui/searchwidget.cpp | 135 + kpdf/ui/searchwidget.h | 50 + kpdf/ui/thumbnaillist.cpp | 575 ++ kpdf/ui/thumbnaillist.h | 121 + kpdf/ui/toc.cpp | 175 + kpdf/ui/toc.h | 43 + kpdf/xpdf/Makefile.am | 1 + kpdf/xpdf/README.xpdf | 405 + kpdf/xpdf/aconf.h | 17 + kpdf/xpdf/fofi/FoFiBase.cc | 156 + kpdf/xpdf/fofi/FoFiBase.h | 57 + kpdf/xpdf/fofi/FoFiEncodings.cc | 994 +++ kpdf/xpdf/fofi/FoFiEncodings.h | 36 + kpdf/xpdf/fofi/FoFiTrueType.cc | 2040 +++++ kpdf/xpdf/fofi/FoFiTrueType.h | 175 + kpdf/xpdf/fofi/FoFiType1.cc | 252 + kpdf/xpdf/fofi/FoFiType1.h | 59 + kpdf/xpdf/fofi/FoFiType1C.cc | 2603 ++++++ kpdf/xpdf/fofi/FoFiType1C.h | 233 + kpdf/xpdf/fofi/Makefile.am | 9 + kpdf/xpdf/goo/GHash.cc | 380 + kpdf/xpdf/goo/GHash.h | 78 + kpdf/xpdf/goo/GList.cc | 97 + kpdf/xpdf/goo/GList.h | 96 + kpdf/xpdf/goo/GMutex.h | 49 + kpdf/xpdf/goo/GString.cc | 718 ++ kpdf/xpdf/goo/GString.h | 136 + kpdf/xpdf/goo/Makefile.am | 5 + kpdf/xpdf/goo/gfile.cc | 731 ++ kpdf/xpdf/goo/gfile.h | 138 + kpdf/xpdf/goo/gmem.cc | 315 + kpdf/xpdf/goo/gmem.h | 80 + kpdf/xpdf/goo/gmempp.cc | 32 + kpdf/xpdf/goo/gtypes.h | 29 + kpdf/xpdf/splash/Makefile.am | 8 + kpdf/xpdf/splash/Splash.cc | 3335 ++++++++ kpdf/xpdf/splash/Splash.h | 293 + kpdf/xpdf/splash/SplashBitmap.cc | 188 + kpdf/xpdf/splash/SplashBitmap.h | 61 + kpdf/xpdf/splash/SplashClip.cc | 382 + kpdf/xpdf/splash/SplashClip.h | 107 + kpdf/xpdf/splash/SplashErrorCodes.h | 34 + kpdf/xpdf/splash/SplashFTFont.cc | 375 + kpdf/xpdf/splash/SplashFTFont.h | 58 + kpdf/xpdf/splash/SplashFTFontEngine.cc | 194 + kpdf/xpdf/splash/SplashFTFontEngine.h | 60 + kpdf/xpdf/splash/SplashFTFontFile.cc | 125 + kpdf/xpdf/splash/SplashFTFontFile.h | 72 + kpdf/xpdf/splash/SplashFont.cc | 201 + kpdf/xpdf/splash/SplashFont.h | 105 + kpdf/xpdf/splash/SplashFontEngine.cc | 295 + kpdf/xpdf/splash/SplashFontEngine.h | 86 + kpdf/xpdf/splash/SplashFontFile.cc | 108 + kpdf/xpdf/splash/SplashFontFile.h | 77 + kpdf/xpdf/splash/SplashFontFileID.cc | 23 + kpdf/xpdf/splash/SplashFontFileID.h | 30 + kpdf/xpdf/splash/SplashGlyphBitmap.h | 26 + kpdf/xpdf/splash/SplashMath.h | 89 + kpdf/xpdf/splash/SplashPath.cc | 184 + kpdf/xpdf/splash/SplashPath.h | 121 + kpdf/xpdf/splash/SplashPattern.cc | 40 + kpdf/xpdf/splash/SplashPattern.h | 65 + kpdf/xpdf/splash/SplashScreen.cc | 385 + kpdf/xpdf/splash/SplashScreen.h | 56 + kpdf/xpdf/splash/SplashState.cc | 165 + kpdf/xpdf/splash/SplashState.h | 103 + kpdf/xpdf/splash/SplashT1Font.cc | 292 + kpdf/xpdf/splash/SplashT1Font.h | 57 + kpdf/xpdf/splash/SplashT1FontEngine.cc | 122 + kpdf/xpdf/splash/SplashT1FontEngine.h | 53 + kpdf/xpdf/splash/SplashT1FontFile.cc | 117 + kpdf/xpdf/splash/SplashT1FontFile.h | 58 + kpdf/xpdf/splash/SplashTypes.h | 132 + kpdf/xpdf/splash/SplashXPath.cc | 443 + kpdf/xpdf/splash/SplashXPath.h | 100 + kpdf/xpdf/splash/SplashXPathScanner.cc | 429 + kpdf/xpdf/splash/SplashXPathScanner.h | 87 + kpdf/xpdf/xpdf/Annot.cc | 1556 ++++ kpdf/xpdf/xpdf/Annot.h | 143 + kpdf/xpdf/xpdf/Array.cc | 88 + kpdf/xpdf/xpdf/Array.h | 59 + kpdf/xpdf/xpdf/BuiltinFont.cc | 65 + kpdf/xpdf/xpdf/BuiltinFont.h | 57 + kpdf/xpdf/xpdf/BuiltinFontTables.cc | 4284 ++++++++++ kpdf/xpdf/xpdf/BuiltinFontTables.h | 23 + kpdf/xpdf/xpdf/CMap.cc | 408 + kpdf/xpdf/xpdf/CMap.h | 102 + kpdf/xpdf/xpdf/Catalog.cc | 443 + kpdf/xpdf/xpdf/Catalog.h | 137 + kpdf/xpdf/xpdf/CharCodeToUnicode.cc | 540 ++ kpdf/xpdf/xpdf/CharCodeToUnicode.h | 117 + kpdf/xpdf/xpdf/CharTypes.h | 24 + kpdf/xpdf/xpdf/CompactFontTables.h | 464 + kpdf/xpdf/xpdf/Decrypt.cc | 776 ++ kpdf/xpdf/xpdf/Decrypt.h | 95 + kpdf/xpdf/xpdf/Dict.cc | 95 + kpdf/xpdf/xpdf/Dict.h | 77 + kpdf/xpdf/xpdf/Error.h | 23 + kpdf/xpdf/xpdf/ErrorCodes.h | 36 + kpdf/xpdf/xpdf/FontEncodingTables.cc | 1824 ++++ kpdf/xpdf/xpdf/FontEncodingTables.h | 20 + kpdf/xpdf/xpdf/Function.cc | 1575 ++++ kpdf/xpdf/xpdf/Function.h | 229 + kpdf/xpdf/xpdf/Gfx.cc | 4187 +++++++++ kpdf/xpdf/xpdf/Gfx.h | 312 + kpdf/xpdf/xpdf/GfxFont.cc | 1616 ++++ kpdf/xpdf/xpdf/GfxFont.h | 322 + kpdf/xpdf/xpdf/GfxState.cc | 4137 +++++++++ kpdf/xpdf/xpdf/GfxState.h | 1244 +++ kpdf/xpdf/xpdf/GlobalParams.cc | 2989 +++++++ kpdf/xpdf/xpdf/GlobalParams.h | 464 + kpdf/xpdf/xpdf/JArithmeticDecoder.cc | 322 + kpdf/xpdf/xpdf/JArithmeticDecoder.h | 109 + kpdf/xpdf/xpdf/JBIG2Stream.cc | 3648 ++++++++ kpdf/xpdf/xpdf/JBIG2Stream.h | 149 + kpdf/xpdf/xpdf/JPXStream.cc | 3144 +++++++ kpdf/xpdf/xpdf/JPXStream.h | 351 + kpdf/xpdf/xpdf/Lexer.cc | 521 ++ kpdf/xpdf/xpdf/Lexer.h | 82 + kpdf/xpdf/xpdf/Link.cc | 784 ++ kpdf/xpdf/xpdf/Link.h | 369 + kpdf/xpdf/xpdf/Makefile.am | 19 + kpdf/xpdf/xpdf/NameToCharCode.cc | 116 + kpdf/xpdf/xpdf/NameToCharCode.h | 42 + kpdf/xpdf/xpdf/NameToUnicodeTable.h | 1097 +++ kpdf/xpdf/xpdf/Object.cc | 233 + kpdf/xpdf/xpdf/Object.h | 303 + kpdf/xpdf/xpdf/Outline.cc | 151 + kpdf/xpdf/xpdf/Outline.h | 76 + kpdf/xpdf/xpdf/OutputDev.cc | 131 + kpdf/xpdf/xpdf/OutputDev.h | 250 + kpdf/xpdf/xpdf/PDFDoc.cc | 433 + kpdf/xpdf/xpdf/PDFDoc.h | 183 + kpdf/xpdf/xpdf/PDFDocEncoding.cc | 44 + kpdf/xpdf/xpdf/PDFDocEncoding.h | 16 + kpdf/xpdf/xpdf/PSOutputDev.cc | 6307 ++++++++++++++ kpdf/xpdf/xpdf/PSOutputDev.h | 391 + kpdf/xpdf/xpdf/PSTokenizer.cc | 135 + kpdf/xpdf/xpdf/PSTokenizer.h | 41 + kpdf/xpdf/xpdf/Page.cc | 558 ++ kpdf/xpdf/xpdf/Page.h | 259 + kpdf/xpdf/xpdf/Parser.cc | 227 + kpdf/xpdf/xpdf/Parser.h | 59 + kpdf/xpdf/xpdf/PreScanOutputDev.cc | 257 + kpdf/xpdf/xpdf/PreScanOutputDev.h | 130 + kpdf/xpdf/xpdf/SecurityHandler.cc | 390 + kpdf/xpdf/xpdf/SecurityHandler.h | 160 + kpdf/xpdf/xpdf/SplashOutputDev.cc | 2851 +++++++ kpdf/xpdf/xpdf/SplashOutputDev.h | 247 + kpdf/xpdf/xpdf/Stream-CCITT.h | 462 + kpdf/xpdf/xpdf/Stream.cc | 4697 +++++++++++ kpdf/xpdf/xpdf/Stream.h | 860 ++ kpdf/xpdf/xpdf/TextOutputDev.cc | 4090 +++++++++ kpdf/xpdf/xpdf/TextOutputDev.h | 661 ++ kpdf/xpdf/xpdf/UTF8.h | 56 + kpdf/xpdf/xpdf/UnicodeMap.cc | 293 + kpdf/xpdf/xpdf/UnicodeMap.h | 123 + kpdf/xpdf/xpdf/UnicodeMapTables.h | 361 + kpdf/xpdf/xpdf/UnicodeTypeTable.cc | 949 +++ kpdf/xpdf/xpdf/UnicodeTypeTable.h | 20 + kpdf/xpdf/xpdf/XRef.cc | 917 ++ kpdf/xpdf/xpdf/XRef.h | 136 + kpdf/xpdf/xpdf/xpdf_config.h | 112 + kpovmodeler/AUTHORS | 13 + kpovmodeler/BUGS | 5 + kpovmodeler/COPYING | 341 + kpovmodeler/ChangeLog | 83 + kpovmodeler/INSTALL | 167 + kpovmodeler/Makefile.am | 251 + kpovmodeler/README | 3 + kpovmodeler/REQUIREMENTS | 19 + kpovmodeler/StyleConvention | 225 + kpovmodeler/TODO | 52 + kpovmodeler/baseinsertrules.xml | 1039 +++ kpovmodeler/configure.in.bot | 37 + kpovmodeler/configure.in.in | 60 + kpovmodeler/cr16-mime-kpovmodeler_doc.png | Bin 0 -> 684 bytes kpovmodeler/cr32-mime-kpovmodeler_doc.png | Bin 0 -> 1464 bytes kpovmodeler/cr48-mime-kpovmodeler_doc.png | Bin 0 -> 2258 bytes kpovmodeler/examples/Makefile.am | 1 + kpovmodeler/examples/includes/Makefile.am | 1 + kpovmodeler/examples/includes/inlined/Makefile.am | 4 + kpovmodeler/examples/includes/inlined/chars.kpm | Bin 0 -> 3354 bytes kpovmodeler/examples/includes/inlined/finish.kpm | Bin 0 -> 937 bytes kpovmodeler/examples/includes/inlined/glass.kpm | 141 + kpovmodeler/examples/includes/inlined/golds.kpm | Bin 0 -> 1140 bytes kpovmodeler/examples/includes/inlined/metals.kpm | Bin 0 -> 2748 bytes kpovmodeler/examples/includes/inlined/shapes.kpm | Bin 0 -> 1462 bytes kpovmodeler/examples/includes/inlined/shapes2.kpm | Bin 0 -> 1541 bytes kpovmodeler/examples/includes/inlined/shapesq.kpm | Bin 0 -> 3039 bytes kpovmodeler/examples/includes/inlined/skies.kpm | Bin 0 -> 2229 bytes kpovmodeler/examples/includes/inlined/stars.kpm | Bin 0 -> 1285 bytes kpovmodeler/examples/includes/inlined/stones1.kpm | Bin 0 -> 9383 bytes kpovmodeler/examples/includes/inlined/stones2.kpm | Bin 0 -> 3659 bytes kpovmodeler/examples/includes/inlined/textures.kpm | Bin 0 -> 7361 bytes kpovmodeler/examples/includes/inlined/woods.kpm | Bin 0 -> 7129 bytes kpovmodeler/examples/includes/original/Makefile.am | 4 + kpovmodeler/examples/includes/original/chars.kpm | Bin 0 -> 3083 bytes kpovmodeler/examples/includes/original/finish.kpm | Bin 0 -> 937 bytes kpovmodeler/examples/includes/original/glass.kpm | Bin 0 -> 1237 bytes kpovmodeler/examples/includes/original/golds.kpm | Bin 0 -> 1166 bytes kpovmodeler/examples/includes/original/metals.kpm | Bin 0 -> 3359 bytes kpovmodeler/examples/includes/original/shapes.kpm | Bin 0 -> 1462 bytes kpovmodeler/examples/includes/original/shapes2.kpm | Bin 0 -> 1541 bytes kpovmodeler/examples/includes/original/shapesq.kpm | Bin 0 -> 3045 bytes kpovmodeler/examples/includes/original/skies.kpm | Bin 0 -> 1981 bytes kpovmodeler/examples/includes/original/stars.kpm | Bin 0 -> 1285 bytes kpovmodeler/examples/includes/original/stones1.kpm | Bin 0 -> 7777 bytes kpovmodeler/examples/includes/original/stones2.kpm | Bin 0 -> 3659 bytes .../examples/includes/original/textures.kpm | Bin 0 -> 7317 bytes kpovmodeler/examples/includes/original/woods.kpm | Bin 0 -> 5539 bytes kpovmodeler/examples/scenes/Makefile.am | 1 + kpovmodeler/examples/scenes/advanced/Makefile.am | 2 + kpovmodeler/examples/scenes/advanced/ants.kpm | Bin 0 -> 5229 bytes kpovmodeler/examples/scenes/advanced/bee.kpm | Bin 0 -> 3052 bytes kpovmodeler/examples/scenes/advanced/ink.kpm | Bin 0 -> 3251 bytes kpovmodeler/examples/scenes/advanced/table.kpm | Bin 0 -> 4961 bytes kpovmodeler/examples/scenes/csg/Makefile.am | 2 + kpovmodeler/examples/scenes/csg/cheese.kpm | Bin 0 -> 2642 bytes kpovmodeler/examples/scenes/csg/emptybox.kpm | Bin 0 -> 1952 bytes kpovmodeler/examples/scenes/csg/heightfield.kpm | Bin 0 -> 1321 bytes kpovmodeler/examples/scenes/interior/Makefile.am | 2 + kpovmodeler/examples/scenes/interior/cubes.kpm | Bin 0 -> 1273 bytes kpovmodeler/examples/scenes/interior/media1.kpm | Bin 0 -> 1151 bytes kpovmodeler/examples/scenes/interior/media2.kpm | Bin 0 -> 1467 bytes kpovmodeler/examples/scenes/interior/media3.kpm | Bin 0 -> 1737 bytes kpovmodeler/examples/scenes/interior/spheres.kpm | Bin 0 -> 1247 bytes kpovmodeler/examples/scenes/lights/Makefile.am | 2 + kpovmodeler/examples/scenes/lights/arealight.kpm | Bin 0 -> 1142 bytes kpovmodeler/examples/scenes/lights/arealight2.kpm | Bin 0 -> 1148 bytes kpovmodeler/examples/scenes/lights/spotlight.kpm | Bin 0 -> 1117 bytes kpovmodeler/examples/scenes/objects/Makefile.am | 3 + kpovmodeler/examples/scenes/objects/allobjects.kpm | Bin 0 -> 2413 bytes kpovmodeler/examples/scenes/objects/fractals.kpm | Bin 0 -> 1143 bytes kpovmodeler/examples/scenes/objects/lathe.kpm | Bin 0 -> 1122 bytes kpovmodeler/examples/scenes/objects/prism.kpm | Bin 0 -> 1359 bytes kpovmodeler/examples/scenes/objects/sor.kpm | Bin 0 -> 1764 bytes .../examples/scenes/objects/superellipsoid.kpm | Bin 0 -> 1242 bytes kpovmodeler/examples/scenes/objects/text.kpm | Bin 0 -> 1124 bytes kpovmodeler/hi16-app-kpovmodeler.png | Bin 0 -> 815 bytes kpovmodeler/hi22-app-kpovmodeler.png | Bin 0 -> 1149 bytes kpovmodeler/hi32-app-kpovmodeler.png | Bin 0 -> 1891 bytes kpovmodeler/hi48-app-kpovmodeler.png | Bin 0 -> 3163 bytes kpovmodeler/kdoc.rules | 10 + kpovmodeler/kpovmodeler.desktop | 59 + kpovmodeler/kpovmodelerbrowser.rc | 21 + kpovmodeler/kpovmodelershell.rc | 58 + kpovmodeler/kpovmodelerui.rc | 303 + kpovmodeler/main.cpp | 69 + kpovmodeler/pics/Makefile.am | 1 + kpovmodeler/pics/crystalsvg/Makefile.am | 2 + .../pics/crystalsvg/cr16-action-pmaddpoint.png | Bin 0 -> 262 bytes .../crystalsvg/cr16-action-pmaddpointabove.png | Bin 0 -> 226 bytes .../pics/crystalsvg/cr16-action-pmaddsubprism.png | Bin 0 -> 260 bytes .../pics/crystalsvg/cr16-action-pmbicubicpatch.png | Bin 0 -> 398 bytes .../crystalsvg/cr16-action-pmblendmapmodifiers.png | Bin 0 -> 608 bytes kpovmodeler/pics/crystalsvg/cr16-action-pmblob.png | Bin 0 -> 514 bytes .../pics/crystalsvg/cr16-action-pmblobcylinder.png | Bin 0 -> 474 bytes .../pics/crystalsvg/cr16-action-pmblobsphere.png | Bin 0 -> 443 bytes .../pics/crystalsvg/cr16-action-pmboundedby.png | Bin 0 -> 398 bytes kpovmodeler/pics/crystalsvg/cr16-action-pmbox.png | Bin 0 -> 270 bytes .../pics/crystalsvg/cr16-action-pmbumpmap.png | Bin 0 -> 681 bytes .../pics/crystalsvg/cr16-action-pmcamera.png | Bin 0 -> 244 bytes .../pics/crystalsvg/cr16-action-pmclippedby.png | Bin 0 -> 387 bytes .../pics/crystalsvg/cr16-action-pmcolorlist.png | Bin 0 -> 169 bytes .../pics/crystalsvg/cr16-action-pmcolormap.png | Bin 0 -> 360 bytes .../crystalsvg/cr16-action-pmcolormapdeclare.png | Bin 0 -> 350 bytes .../pics/crystalsvg/cr16-action-pmcomment.png | Bin 0 -> 209 bytes kpovmodeler/pics/crystalsvg/cr16-action-pmcone.png | Bin 0 -> 374 bytes .../pics/crystalsvg/cr16-action-pmcylinder.png | Bin 0 -> 337 bytes .../pics/crystalsvg/cr16-action-pmdeclare.png | Bin 0 -> 451 bytes .../pics/crystalsvg/cr16-action-pmdensity.png | Bin 0 -> 530 bytes .../crystalsvg/cr16-action-pmdensitydeclare.png | Bin 0 -> 485 bytes .../pics/crystalsvg/cr16-action-pmdensitylist.png | Bin 0 -> 544 bytes .../pics/crystalsvg/cr16-action-pmdensitymap.png | Bin 0 -> 586 bytes .../crystalsvg/cr16-action-pmdensitymapdeclare.png | Bin 0 -> 519 bytes .../pics/crystalsvg/cr16-action-pmdialogview.png | Bin 0 -> 576 bytes .../pics/crystalsvg/cr16-action-pmdifference.png | Bin 0 -> 271 bytes kpovmodeler/pics/crystalsvg/cr16-action-pmdisc.png | Bin 0 -> 355 bytes kpovmodeler/pics/crystalsvg/cr16-action-pmdrag.png | Bin 0 -> 276 bytes .../pics/crystalsvg/cr16-action-pmfinish.png | Bin 0 -> 240 bytes .../crystalsvg/cr16-action-pmfinishdeclare.png | Bin 0 -> 265 bytes kpovmodeler/pics/crystalsvg/cr16-action-pmfog.png | Bin 0 -> 524 bytes .../pics/crystalsvg/cr16-action-pmfogdeclare.png | Bin 0 -> 477 bytes .../crystalsvg/cr16-action-pmglobalphotons.png | Bin 0 -> 589 bytes .../crystalsvg/cr16-action-pmglobalsettings.png | Bin 0 -> 736 bytes .../pics/crystalsvg/cr16-action-pmglview.png | Bin 0 -> 549 bytes .../pics/crystalsvg/cr16-action-pmheightfield.png | Bin 0 -> 385 bytes .../pics/crystalsvg/cr16-action-pmimagemap.png | Bin 0 -> 758 bytes .../pics/crystalsvg/cr16-action-pminserterrors.png | Bin 0 -> 246 bytes .../crystalsvg/cr16-action-pminsertfirstchild.png | Bin 0 -> 226 bytes .../crystalsvg/cr16-action-pminsertlastchild.png | Bin 0 -> 229 bytes .../crystalsvg/cr16-action-pminsertsibling.png | Bin 0 -> 233 bytes .../pics/crystalsvg/cr16-action-pminterior.png | Bin 0 -> 279 bytes .../crystalsvg/cr16-action-pminteriordeclare.png | Bin 0 -> 253 bytes .../crystalsvg/cr16-action-pminteriortexture.png | Bin 0 -> 449 bytes .../cr16-action-pminteriortexturedeclare.png | Bin 0 -> 376 bytes .../pics/crystalsvg/cr16-action-pmintersection.png | Bin 0 -> 269 bytes .../pics/crystalsvg/cr16-action-pmisosurface.png | Bin 0 -> 411 bytes .../pics/crystalsvg/cr16-action-pmjuliafractal.png | Bin 0 -> 468 bytes .../pics/crystalsvg/cr16-action-pmlathe.png | Bin 0 -> 445 bytes .../pics/crystalsvg/cr16-action-pmlight.png | Bin 0 -> 419 bytes .../pics/crystalsvg/cr16-action-pmlightgroup.png | Bin 0 -> 440 bytes .../pics/crystalsvg/cr16-action-pmlistpattern.png | Bin 0 -> 405 bytes .../pics/crystalsvg/cr16-action-pmlookslike.png | Bin 0 -> 385 bytes .../pics/crystalsvg/cr16-action-pmmaterial.png | Bin 0 -> 461 bytes .../crystalsvg/cr16-action-pmmaterialdeclare.png | Bin 0 -> 407 bytes .../pics/crystalsvg/cr16-action-pmmaterialmap.png | Bin 0 -> 699 bytes .../pics/crystalsvg/cr16-action-pmmatrix.png | Bin 0 -> 565 bytes .../pics/crystalsvg/cr16-action-pmmedia.png | Bin 0 -> 388 bytes .../pics/crystalsvg/cr16-action-pmmediadeclare.png | Bin 0 -> 376 bytes .../pics/crystalsvg/cr16-action-pmmerge.png | Bin 0 -> 281 bytes kpovmodeler/pics/crystalsvg/cr16-action-pmmesh.png | Bin 0 -> 360 bytes .../pics/crystalsvg/cr16-action-pmnormal.png | Bin 0 -> 539 bytes .../crystalsvg/cr16-action-pmnormaldeclare.png | Bin 0 -> 481 bytes .../pics/crystalsvg/cr16-action-pmnormallist.png | Bin 0 -> 556 bytes .../pics/crystalsvg/cr16-action-pmnormalmap.png | Bin 0 -> 516 bytes .../crystalsvg/cr16-action-pmnormalmapdeclare.png | Bin 0 -> 456 bytes .../crystalsvg/cr16-action-pmobjectdeclare.png | Bin 0 -> 420 bytes .../pics/crystalsvg/cr16-action-pmobjectlink.png | Bin 0 -> 476 bytes .../pics/crystalsvg/cr16-action-pmpattern.png | Bin 0 -> 710 bytes .../pics/crystalsvg/cr16-action-pmphotons.png | Bin 0 -> 513 bytes .../pics/crystalsvg/cr16-action-pmpigment.png | Bin 0 -> 334 bytes .../crystalsvg/cr16-action-pmpigmentdeclare.png | Bin 0 -> 361 bytes .../pics/crystalsvg/cr16-action-pmpigmentlist.png | Bin 0 -> 442 bytes .../pics/crystalsvg/cr16-action-pmpigmentmap.png | Bin 0 -> 487 bytes .../crystalsvg/cr16-action-pmpigmentmapdeclare.png | Bin 0 -> 454 bytes .../pics/crystalsvg/cr16-action-pmplane.png | Bin 0 -> 483 bytes .../pics/crystalsvg/cr16-action-pmpolynom.png | Bin 0 -> 371 bytes .../pics/crystalsvg/cr16-action-pmprism.png | Bin 0 -> 322 bytes .../crystalsvg/cr16-action-pmprojectedthrough.png | Bin 0 -> 422 bytes .../pics/crystalsvg/cr16-action-pmquickcolor.png | Bin 0 -> 220 bytes .../pics/crystalsvg/cr16-action-pmradiosity.png | Bin 0 -> 534 bytes .../pics/crystalsvg/cr16-action-pmrainbow.png | Bin 0 -> 318 bytes .../crystalsvg/cr16-action-pmrainbowdeclare.png | Bin 0 -> 307 bytes kpovmodeler/pics/crystalsvg/cr16-action-pmraw.png | Bin 0 -> 193 bytes .../pics/crystalsvg/cr16-action-pmremovepoint.png | Bin 0 -> 170 bytes .../pics/crystalsvg/cr16-action-pmrender.png | Bin 0 -> 442 bytes .../crystalsvg/cr16-action-pmrenderpreview.png | Bin 0 -> 451 bytes .../crystalsvg/cr16-action-pmrendersettings.png | Bin 0 -> 595 bytes .../pics/crystalsvg/cr16-action-pmrotate.png | Bin 0 -> 282 bytes .../pics/crystalsvg/cr16-action-pmscale.png | Bin 0 -> 209 bytes .../pics/crystalsvg/cr16-action-pmscene.png | Bin 0 -> 725 bytes .../pics/crystalsvg/cr16-action-pmskysphere.png | Bin 0 -> 614 bytes .../crystalsvg/cr16-action-pmskyspheredeclare.png | Bin 0 -> 560 bytes .../pics/crystalsvg/cr16-action-pmslope.png | Bin 0 -> 364 bytes .../pics/crystalsvg/cr16-action-pmslopemap.png | Bin 0 -> 396 bytes .../crystalsvg/cr16-action-pmslopemapdeclare.png | Bin 0 -> 342 bytes .../pics/crystalsvg/cr16-action-pmsolidcolor.png | Bin 0 -> 178 bytes kpovmodeler/pics/crystalsvg/cr16-action-pmsor.png | Bin 0 -> 425 bytes .../pics/crystalsvg/cr16-action-pmsphere.png | Bin 0 -> 467 bytes .../pics/crystalsvg/cr16-action-pmspheresweep.png | Bin 0 -> 540 bytes kpovmodeler/pics/crystalsvg/cr16-action-pmsqe.png | Bin 0 -> 495 bytes kpovmodeler/pics/crystalsvg/cr16-action-pmtext.png | Bin 0 -> 248 bytes .../pics/crystalsvg/cr16-action-pmtexture.png | Bin 0 -> 610 bytes .../crystalsvg/cr16-action-pmtexturedeclare.png | Bin 0 -> 544 bytes .../pics/crystalsvg/cr16-action-pmtexturelist.png | Bin 0 -> 617 bytes .../pics/crystalsvg/cr16-action-pmtexturemap.png | Bin 0 -> 603 bytes .../crystalsvg/cr16-action-pmtexturemapdeclare.png | Bin 0 -> 546 bytes .../pics/crystalsvg/cr16-action-pmtorus.png | Bin 0 -> 498 bytes .../pics/crystalsvg/cr16-action-pmtranslate.png | Bin 0 -> 231 bytes .../pics/crystalsvg/cr16-action-pmtreeview.png | Bin 0 -> 539 bytes .../pics/crystalsvg/cr16-action-pmtriangle.png | Bin 0 -> 252 bytes .../pics/crystalsvg/cr16-action-pmunion.png | Bin 0 -> 312 bytes kpovmodeler/pics/crystalsvg/cr16-action-pmwarp.png | Bin 0 -> 686 bytes .../pics/crystalsvg/cr22-action-pmbicubicpatch.png | Bin 0 -> 521 bytes .../crystalsvg/cr22-action-pmblendmapmodifiers.png | Bin 0 -> 975 bytes kpovmodeler/pics/crystalsvg/cr22-action-pmblob.png | Bin 0 -> 845 bytes .../pics/crystalsvg/cr22-action-pmblobcylinder.png | Bin 0 -> 796 bytes .../pics/crystalsvg/cr22-action-pmblobsphere.png | Bin 0 -> 617 bytes .../pics/crystalsvg/cr22-action-pmboundedby.png | Bin 0 -> 432 bytes kpovmodeler/pics/crystalsvg/cr22-action-pmbox.png | Bin 0 -> 302 bytes .../pics/crystalsvg/cr22-action-pmbumpmap.png | Bin 0 -> 1206 bytes .../pics/crystalsvg/cr22-action-pmcamera.png | Bin 0 -> 525 bytes .../pics/crystalsvg/cr22-action-pmclippedby.png | Bin 0 -> 477 bytes .../pics/crystalsvg/cr22-action-pmcolorlist.png | Bin 0 -> 218 bytes .../pics/crystalsvg/cr22-action-pmcolormap.png | Bin 0 -> 573 bytes .../crystalsvg/cr22-action-pmcolormapdeclare.png | Bin 0 -> 518 bytes .../pics/crystalsvg/cr22-action-pmcomment.png | Bin 0 -> 343 bytes kpovmodeler/pics/crystalsvg/cr22-action-pmcone.png | Bin 0 -> 396 bytes .../crystalsvg/cr22-action-pmconfigurecolors.png | Bin 0 -> 883 bytes .../cr22-action-pmconfiguredialogview.png | Bin 0 -> 392 bytes .../cr22-action-pmconfiguregraphicalview.png | Bin 0 -> 652 bytes .../crystalsvg/cr22-action-pmconfiguregrid.png | Bin 0 -> 553 bytes .../cr22-action-pmconfigureobjectlibrary.png | Bin 0 -> 500 bytes .../crystalsvg/cr22-action-pmconfigureobjects.png | Bin 0 -> 710 bytes .../crystalsvg/cr22-action-pmconfigureopengl.png | Bin 0 -> 519 bytes .../crystalsvg/cr22-action-pmconfigurepovray.png | Bin 0 -> 1080 bytes .../cr22-action-pmconfiguretexturepreview.png | Bin 0 -> 765 bytes .../cr22-action-pmconfigureviewlayout.png | Bin 0 -> 410 bytes .../pics/crystalsvg/cr22-action-pmcylinder.png | Bin 0 -> 384 bytes .../pics/crystalsvg/cr22-action-pmdeclare.png | Bin 0 -> 702 bytes .../pics/crystalsvg/cr22-action-pmdensity.png | Bin 0 -> 1147 bytes .../crystalsvg/cr22-action-pmdensitydeclare.png | Bin 0 -> 683 bytes .../pics/crystalsvg/cr22-action-pmdensitylist.png | Bin 0 -> 809 bytes .../pics/crystalsvg/cr22-action-pmdensitymap.png | Bin 0 -> 900 bytes .../crystalsvg/cr22-action-pmdensitymapdeclare.png | Bin 0 -> 764 bytes .../pics/crystalsvg/cr22-action-pmdifference.png | Bin 0 -> 430 bytes kpovmodeler/pics/crystalsvg/cr22-action-pmdisc.png | Bin 0 -> 527 bytes kpovmodeler/pics/crystalsvg/cr22-action-pmdrag.png | Bin 0 -> 369 bytes .../pics/crystalsvg/cr22-action-pmfinish.png | Bin 0 -> 299 bytes .../crystalsvg/cr22-action-pmfinishdeclare.png | Bin 0 -> 338 bytes kpovmodeler/pics/crystalsvg/cr22-action-pmfog.png | Bin 0 -> 827 bytes .../pics/crystalsvg/cr22-action-pmfogdeclare.png | Bin 0 -> 725 bytes .../crystalsvg/cr22-action-pmglobalphotons.png | Bin 0 -> 962 bytes .../crystalsvg/cr22-action-pmglobalsettings.png | Bin 0 -> 904 bytes .../pics/crystalsvg/cr22-action-pmheightfield.png | Bin 0 -> 487 bytes .../pics/crystalsvg/cr22-action-pmimagemap.png | Bin 0 -> 1344 bytes .../pics/crystalsvg/cr22-action-pminserterrors.png | Bin 0 -> 483 bytes .../pics/crystalsvg/cr22-action-pminterior.png | Bin 0 -> 277 bytes .../crystalsvg/cr22-action-pminteriordeclare.png | Bin 0 -> 255 bytes .../crystalsvg/cr22-action-pminteriortexture.png | Bin 0 -> 656 bytes .../cr22-action-pminteriortexturedeclare.png | Bin 0 -> 535 bytes .../pics/crystalsvg/cr22-action-pmintersection.png | Bin 0 -> 372 bytes .../pics/crystalsvg/cr22-action-pmisosurface.png | Bin 0 -> 730 bytes .../pics/crystalsvg/cr22-action-pmjuliafractal.png | Bin 0 -> 718 bytes .../pics/crystalsvg/cr22-action-pmlathe.png | Bin 0 -> 654 bytes .../pics/crystalsvg/cr22-action-pmlight.png | Bin 0 -> 438 bytes .../pics/crystalsvg/cr22-action-pmlightgroup.png | Bin 0 -> 709 bytes .../pics/crystalsvg/cr22-action-pmlistpattern.png | Bin 0 -> 367 bytes .../pics/crystalsvg/cr22-action-pmlookslike.png | Bin 0 -> 347 bytes .../pics/crystalsvg/cr22-action-pmmaterial.png | Bin 0 -> 675 bytes .../crystalsvg/cr22-action-pmmaterialdeclare.png | Bin 0 -> 563 bytes .../pics/crystalsvg/cr22-action-pmmaterialmap.png | Bin 0 -> 1243 bytes .../pics/crystalsvg/cr22-action-pmmatrix.png | Bin 0 -> 290 bytes .../pics/crystalsvg/cr22-action-pmmedia.png | Bin 0 -> 416 bytes .../pics/crystalsvg/cr22-action-pmmediadeclare.png | Bin 0 -> 405 bytes .../pics/crystalsvg/cr22-action-pmmerge.png | Bin 0 -> 489 bytes kpovmodeler/pics/crystalsvg/cr22-action-pmmesh.png | Bin 0 -> 576 bytes .../pics/crystalsvg/cr22-action-pmnormal.png | Bin 0 -> 844 bytes .../crystalsvg/cr22-action-pmnormaldeclare.png | Bin 0 -> 741 bytes .../pics/crystalsvg/cr22-action-pmnormallist.png | Bin 0 -> 845 bytes .../pics/crystalsvg/cr22-action-pmnormalmap.png | Bin 0 -> 804 bytes .../crystalsvg/cr22-action-pmnormalmapdeclare.png | Bin 0 -> 700 bytes .../crystalsvg/cr22-action-pmobjectdeclare.png | Bin 0 -> 643 bytes .../pics/crystalsvg/cr22-action-pmobjectlink.png | Bin 0 -> 806 bytes .../pics/crystalsvg/cr22-action-pmpattern.png | Bin 0 -> 1246 bytes .../pics/crystalsvg/cr22-action-pmphotons.png | Bin 0 -> 631 bytes .../pics/crystalsvg/cr22-action-pmpigment.png | Bin 0 -> 305 bytes .../crystalsvg/cr22-action-pmpigmentdeclare.png | Bin 0 -> 377 bytes .../pics/crystalsvg/cr22-action-pmpigmentlist.png | Bin 0 -> 492 bytes .../pics/crystalsvg/cr22-action-pmpigmentmap.png | Bin 0 -> 737 bytes .../crystalsvg/cr22-action-pmpigmentmapdeclare.png | Bin 0 -> 660 bytes .../pics/crystalsvg/cr22-action-pmplane.png | Bin 0 -> 495 bytes .../pics/crystalsvg/cr22-action-pmpolynom.png | Bin 0 -> 498 bytes .../pics/crystalsvg/cr22-action-pmprism.png | Bin 0 -> 423 bytes .../crystalsvg/cr22-action-pmprojectedthrough.png | Bin 0 -> 420 bytes .../pics/crystalsvg/cr22-action-pmquickcolor.png | Bin 0 -> 225 bytes .../pics/crystalsvg/cr22-action-pmradiosity.png | Bin 0 -> 428 bytes .../pics/crystalsvg/cr22-action-pmrainbow.png | Bin 0 -> 576 bytes .../crystalsvg/cr22-action-pmrainbowdeclare.png | Bin 0 -> 558 bytes kpovmodeler/pics/crystalsvg/cr22-action-pmraw.png | Bin 0 -> 271 bytes .../pics/crystalsvg/cr22-action-pmrender.png | Bin 0 -> 637 bytes .../crystalsvg/cr22-action-pmrenderpreview.png | Bin 0 -> 648 bytes .../crystalsvg/cr22-action-pmrendersettings.png | Bin 0 -> 693 bytes .../pics/crystalsvg/cr22-action-pmrotate.png | Bin 0 -> 272 bytes .../pics/crystalsvg/cr22-action-pmscale.png | Bin 0 -> 383 bytes .../pics/crystalsvg/cr22-action-pmscene.png | Bin 0 -> 791 bytes .../pics/crystalsvg/cr22-action-pmskysphere.png | Bin 0 -> 914 bytes .../crystalsvg/cr22-action-pmskyspheredeclare.png | Bin 0 -> 768 bytes .../pics/crystalsvg/cr22-action-pmslope.png | Bin 0 -> 312 bytes .../pics/crystalsvg/cr22-action-pmslopemap.png | Bin 0 -> 555 bytes .../crystalsvg/cr22-action-pmslopemapdeclare.png | Bin 0 -> 493 bytes .../pics/crystalsvg/cr22-action-pmsolidcolor.png | Bin 0 -> 255 bytes kpovmodeler/pics/crystalsvg/cr22-action-pmsor.png | Bin 0 -> 629 bytes .../pics/crystalsvg/cr22-action-pmsphere.png | Bin 0 -> 592 bytes .../pics/crystalsvg/cr22-action-pmspheresweep.png | Bin 0 -> 618 bytes kpovmodeler/pics/crystalsvg/cr22-action-pmsqe.png | Bin 0 -> 713 bytes kpovmodeler/pics/crystalsvg/cr22-action-pmtext.png | Bin 0 -> 284 bytes .../pics/crystalsvg/cr22-action-pmtexture.png | Bin 0 -> 977 bytes .../crystalsvg/cr22-action-pmtexturedeclare.png | Bin 0 -> 852 bytes .../pics/crystalsvg/cr22-action-pmtexturelist.png | Bin 0 -> 960 bytes .../pics/crystalsvg/cr22-action-pmtexturemap.png | Bin 0 -> 939 bytes .../crystalsvg/cr22-action-pmtexturemapdeclare.png | Bin 0 -> 800 bytes .../pics/crystalsvg/cr22-action-pmtorus.png | Bin 0 -> 677 bytes .../pics/crystalsvg/cr22-action-pmtranslate.png | Bin 0 -> 463 bytes .../pics/crystalsvg/cr22-action-pmtriangle.png | Bin 0 -> 455 bytes .../pics/crystalsvg/cr22-action-pmunion.png | Bin 0 -> 554 bytes kpovmodeler/pics/crystalsvg/cr22-action-pmwarp.png | Bin 0 -> 1011 bytes kpovmodeler/pics/locolor/Makefile.am | 2 + .../pics/locolor/lo16-action-pmaddpoint.png | Bin 0 -> 262 bytes .../pics/locolor/lo16-action-pmaddpointabove.png | Bin 0 -> 226 bytes .../pics/locolor/lo16-action-pmaddsubprism.png | Bin 0 -> 186 bytes .../pics/locolor/lo16-action-pmbicubicpatch.png | Bin 0 -> 373 bytes .../locolor/lo16-action-pmblendmapmodifiers.png | Bin 0 -> 520 bytes kpovmodeler/pics/locolor/lo16-action-pmblob.png | Bin 0 -> 396 bytes .../pics/locolor/lo16-action-pmblobcylinder.png | Bin 0 -> 212 bytes .../pics/locolor/lo16-action-pmblobsphere.png | Bin 0 -> 436 bytes .../pics/locolor/lo16-action-pmboundedby.png | Bin 0 -> 296 bytes kpovmodeler/pics/locolor/lo16-action-pmbox.png | Bin 0 -> 251 bytes kpovmodeler/pics/locolor/lo16-action-pmbumpmap.png | Bin 0 -> 299 bytes kpovmodeler/pics/locolor/lo16-action-pmcamera.png | Bin 0 -> 244 bytes .../pics/locolor/lo16-action-pmclippedby.png | Bin 0 -> 277 bytes kpovmodeler/pics/locolor/lo16-action-pmcomment.png | Bin 0 -> 209 bytes kpovmodeler/pics/locolor/lo16-action-pmcone.png | Bin 0 -> 466 bytes .../pics/locolor/lo16-action-pmcylinder.png | Bin 0 -> 341 bytes kpovmodeler/pics/locolor/lo16-action-pmdeclare.png | Bin 0 -> 327 bytes kpovmodeler/pics/locolor/lo16-action-pmdensity.png | Bin 0 -> 398 bytes .../pics/locolor/lo16-action-pmdensitydeclare.png | Bin 0 -> 354 bytes .../pics/locolor/lo16-action-pmdensitylist.png | Bin 0 -> 376 bytes .../pics/locolor/lo16-action-pmdensitymap.png | Bin 0 -> 379 bytes .../locolor/lo16-action-pmdensitymapdeclare.png | Bin 0 -> 373 bytes .../pics/locolor/lo16-action-pmdifference.png | Bin 0 -> 271 bytes kpovmodeler/pics/locolor/lo16-action-pmdisc.png | Bin 0 -> 394 bytes kpovmodeler/pics/locolor/lo16-action-pmdrag.png | Bin 0 -> 276 bytes kpovmodeler/pics/locolor/lo16-action-pmfog.png | Bin 0 -> 329 bytes .../pics/locolor/lo16-action-pmfogdeclare.png | Bin 0 -> 384 bytes .../pics/locolor/lo16-action-pmglobalsettings.png | Bin 0 -> 509 bytes .../pics/locolor/lo16-action-pmheightfield.png | Bin 0 -> 288 bytes .../pics/locolor/lo16-action-pmimagemap.png | Bin 0 -> 458 bytes .../pics/locolor/lo16-action-pminserterrors.png | Bin 0 -> 246 bytes .../locolor/lo16-action-pminsertfirstchild.png | Bin 0 -> 226 bytes .../pics/locolor/lo16-action-pminsertlastchild.png | Bin 0 -> 229 bytes .../pics/locolor/lo16-action-pminsertsibling.png | Bin 0 -> 233 bytes .../pics/locolor/lo16-action-pmintersection.png | Bin 0 -> 269 bytes .../pics/locolor/lo16-action-pmjuliafractal.png | Bin 0 -> 313 bytes kpovmodeler/pics/locolor/lo16-action-pmlathe.png | Bin 0 -> 237 bytes kpovmodeler/pics/locolor/lo16-action-pmlight.png | Bin 0 -> 297 bytes .../pics/locolor/lo16-action-pmlistpattern.png | Bin 0 -> 359 bytes .../pics/locolor/lo16-action-pmlookslike.png | Bin 0 -> 203 bytes .../pics/locolor/lo16-action-pmmaterialmap.png | Bin 0 -> 341 bytes kpovmodeler/pics/locolor/lo16-action-pmmatrix.png | Bin 0 -> 200 bytes kpovmodeler/pics/locolor/lo16-action-pmmerge.png | Bin 0 -> 281 bytes .../pics/locolor/lo16-action-pmobjectdeclare.png | Bin 0 -> 420 bytes .../pics/locolor/lo16-action-pmobjectlink.png | Bin 0 -> 476 bytes kpovmodeler/pics/locolor/lo16-action-pmpigment.png | Bin 0 -> 344 bytes .../pics/locolor/lo16-action-pmpigmentdeclare.png | Bin 0 -> 364 bytes kpovmodeler/pics/locolor/lo16-action-pmplane.png | Bin 0 -> 427 bytes kpovmodeler/pics/locolor/lo16-action-pmpolynom.png | Bin 0 -> 233 bytes kpovmodeler/pics/locolor/lo16-action-pmprism.png | Bin 0 -> 217 bytes .../pics/locolor/lo16-action-pmquickcolor.png | Bin 0 -> 205 bytes kpovmodeler/pics/locolor/lo16-action-pmrainbow.png | Bin 0 -> 354 bytes .../pics/locolor/lo16-action-pmrainbowdeclare.png | Bin 0 -> 337 bytes kpovmodeler/pics/locolor/lo16-action-pmraw.png | Bin 0 -> 193 bytes .../pics/locolor/lo16-action-pmremovepoint.png | Bin 0 -> 170 bytes kpovmodeler/pics/locolor/lo16-action-pmrender.png | Bin 0 -> 363 bytes .../pics/locolor/lo16-action-pmrenderpreview.png | Bin 0 -> 382 bytes .../pics/locolor/lo16-action-pmrendersettings.png | Bin 0 -> 501 bytes kpovmodeler/pics/locolor/lo16-action-pmrotate.png | Bin 0 -> 282 bytes kpovmodeler/pics/locolor/lo16-action-pmscale.png | Bin 0 -> 209 bytes kpovmodeler/pics/locolor/lo16-action-pmscene.png | Bin 0 -> 559 bytes .../pics/locolor/lo16-action-pmskysphere.png | Bin 0 -> 384 bytes .../locolor/lo16-action-pmskyspheredeclare.png | Bin 0 -> 368 bytes .../pics/locolor/lo16-action-pmsolidcolor.png | Bin 0 -> 382 bytes kpovmodeler/pics/locolor/lo16-action-pmsor.png | Bin 0 -> 311 bytes kpovmodeler/pics/locolor/lo16-action-pmsphere.png | Bin 0 -> 363 bytes kpovmodeler/pics/locolor/lo16-action-pmsqr.png | Bin 0 -> 289 bytes kpovmodeler/pics/locolor/lo16-action-pmtext.png | Bin 0 -> 208 bytes kpovmodeler/pics/locolor/lo16-action-pmtexture.png | Bin 0 -> 502 bytes .../pics/locolor/lo16-action-pmtexturedeclare.png | Bin 0 -> 464 bytes kpovmodeler/pics/locolor/lo16-action-pmtorus.png | Bin 0 -> 399 bytes .../pics/locolor/lo16-action-pmtranslate.png | Bin 0 -> 231 bytes .../pics/locolor/lo16-action-pmtriangle.png | Bin 0 -> 324 bytes kpovmodeler/pics/locolor/lo16-action-pmunion.png | Bin 0 -> 312 bytes kpovmodeler/pm2dcontrolpoint.cpp | 207 + kpovmodeler/pm2dcontrolpoint.h | 135 + kpovmodeler/pm3dcontrolpoint.cpp | 49 + kpovmodeler/pm3dcontrolpoint.h | 68 + kpovmodeler/pmactions.cpp | 254 + kpovmodeler/pmactions.h | 106 + kpovmodeler/pmaddcommand.cpp | 233 + kpovmodeler/pmaddcommand.h | 87 + kpovmodeler/pmallcommands.h | 27 + kpovmodeler/pmalledits.h | 25 + kpovmodeler/pmallobjects.h | 106 + kpovmodeler/pmbicubicpatch.cpp | 544 ++ kpovmodeler/pmbicubicpatch.h | 188 + kpovmodeler/pmbicubicpatchedit.cpp | 218 + kpovmodeler/pmbicubicpatchedit.h | 80 + kpovmodeler/pmblendmapmodifiers.cpp | 284 + kpovmodeler/pmblendmapmodifiers.h | 129 + kpovmodeler/pmblendmapmodifiersedit.cpp | 261 + kpovmodeler/pmblendmapmodifiersedit.h | 100 + kpovmodeler/pmblob.cpp | 175 + kpovmodeler/pmblob.h | 113 + kpovmodeler/pmblobcylinder.cpp | 468 + kpovmodeler/pmblobcylinder.h | 181 + kpovmodeler/pmblobcylinderedit.cpp | 114 + kpovmodeler/pmblobcylinderedit.h | 61 + kpovmodeler/pmblobedit.cpp | 96 + kpovmodeler/pmblobedit.h | 65 + kpovmodeler/pmblobsphere.cpp | 391 + kpovmodeler/pmblobsphere.h | 168 + kpovmodeler/pmblobsphereedit.cpp | 102 + kpovmodeler/pmblobsphereedit.h | 63 + kpovmodeler/pmboundedby.cpp | 114 + kpovmodeler/pmboundedby.h | 89 + kpovmodeler/pmboundedbyedit.cpp | 65 + kpovmodeler/pmboundedbyedit.h | 59 + kpovmodeler/pmbox.cpp | 276 + kpovmodeler/pmbox.h | 123 + kpovmodeler/pmboxedit.cpp | 86 + kpovmodeler/pmboxedit.h | 63 + kpovmodeler/pmbumpmap.cpp | 384 + kpovmodeler/pmbumpmap.h | 172 + kpovmodeler/pmbumpmapedit.cpp | 319 + kpovmodeler/pmbumpmapedit.h | 86 + kpovmodeler/pmcamera.cpp | 769 ++ kpovmodeler/pmcamera.h | 292 + kpovmodeler/pmcameraedit.cpp | 439 + kpovmodeler/pmcameraedit.h | 99 + kpovmodeler/pmclippedby.cpp | 114 + kpovmodeler/pmclippedby.h | 88 + kpovmodeler/pmclippedbyedit.cpp | 65 + kpovmodeler/pmclippedbyedit.h | 59 + kpovmodeler/pmcolor.cpp | 196 + kpovmodeler/pmcolor.h | 130 + kpovmodeler/pmcoloredit.cpp | 201 + kpovmodeler/pmcoloredit.h | 83 + kpovmodeler/pmcolorsettings.cpp | 163 + kpovmodeler/pmcolorsettings.h | 58 + kpovmodeler/pmcommand.h | 146 + kpovmodeler/pmcommandmanager.cpp | 99 + kpovmodeler/pmcommandmanager.h | 118 + kpovmodeler/pmcomment.cpp | 174 + kpovmodeler/pmcomment.h | 92 + kpovmodeler/pmcommentedit.cpp | 75 + kpovmodeler/pmcommentedit.h | 62 + kpovmodeler/pmcompositeobject.cpp | 396 + kpovmodeler/pmcompositeobject.h | 198 + kpovmodeler/pmcone.cpp | 451 + kpovmodeler/pmcone.h | 188 + kpovmodeler/pmconeedit.cpp | 119 + kpovmodeler/pmconeedit.h | 64 + kpovmodeler/pmcontrolpoint.cpp | 99 + kpovmodeler/pmcontrolpoint.h | 190 + kpovmodeler/pmcsg.cpp | 200 + kpovmodeler/pmcsg.h | 105 + kpovmodeler/pmcsgedit.cpp | 118 + kpovmodeler/pmcsgedit.h | 63 + kpovmodeler/pmcylinder.cpp | 407 + kpovmodeler/pmcylinder.h | 176 + kpovmodeler/pmcylinderedit.cpp | 113 + kpovmodeler/pmcylinderedit.h | 63 + kpovmodeler/pmdatachangecommand.cpp | 111 + kpovmodeler/pmdatachangecommand.h | 68 + kpovmodeler/pmdebug.h | 26 + kpovmodeler/pmdeclare.cpp | 238 + kpovmodeler/pmdeclare.h | 147 + kpovmodeler/pmdeclareedit.cpp | 206 + kpovmodeler/pmdeclareedit.h | 74 + kpovmodeler/pmdefaults.h | 131 + kpovmodeler/pmdeletecommand.cpp | 281 + kpovmodeler/pmdeletecommand.h | 126 + kpovmodeler/pmdensity.cpp | 76 + kpovmodeler/pmdensity.h | 76 + kpovmodeler/pmdensityedit.cpp | 44 + kpovmodeler/pmdensityedit.h | 58 + kpovmodeler/pmdetailobject.cpp | 151 + kpovmodeler/pmdetailobject.h | 115 + kpovmodeler/pmdetailobjectedit.cpp | 122 + kpovmodeler/pmdetailobjectedit.h | 68 + kpovmodeler/pmdialogeditbase.cpp | 558 ++ kpovmodeler/pmdialogeditbase.h | 356 + kpovmodeler/pmdialogview.cpp | 441 + kpovmodeler/pmdialogview.h | 163 + kpovmodeler/pmdisc.cpp | 440 + kpovmodeler/pmdisc.h | 180 + kpovmodeler/pmdiscedit.cpp | 147 + kpovmodeler/pmdiscedit.h | 67 + kpovmodeler/pmdistancecontrolpoint.cpp | 92 + kpovmodeler/pmdistancecontrolpoint.h | 110 + kpovmodeler/pmdockwidget.cpp | 2549 ++++++ kpovmodeler/pmdockwidget.h | 1478 ++++ kpovmodeler/pmdockwidget_private.cpp | 372 + kpovmodeler/pmdockwidget_private.h | 142 + kpovmodeler/pmdocumentationmap.cpp | 193 + kpovmodeler/pmdocumentationmap.h | 138 + kpovmodeler/pmdocumentformat.h | 26 + kpovmodeler/pmdragwidget.cpp | 49 + kpovmodeler/pmdragwidget.h | 51 + kpovmodeler/pmenumproperty.cpp | 57 + kpovmodeler/pmenumproperty.h | 110 + kpovmodeler/pmerrordialog.cpp | 136 + kpovmodeler/pmerrordialog.h | 73 + kpovmodeler/pmerrorflags.h | 31 + kpovmodeler/pmface.cpp | 119 + kpovmodeler/pmface.h | 130 + kpovmodeler/pmfactory.cpp | 102 + kpovmodeler/pmfactory.h | 48 + kpovmodeler/pmfiledialog.cpp | 104 + kpovmodeler/pmfiledialog.h | 60 + kpovmodeler/pmfinish.cpp | 765 ++ kpovmodeler/pmfinish.h | 208 + kpovmodeler/pmfinishedit.cpp | 474 ++ kpovmodeler/pmfinishedit.h | 122 + kpovmodeler/pmfog.cpp | 347 + kpovmodeler/pmfog.h | 129 + kpovmodeler/pmfogedit.cpp | 240 + kpovmodeler/pmfogedit.h | 95 + kpovmodeler/pmformulalabel.cpp | 190 + kpovmodeler/pmformulalabel.h | 69 + kpovmodeler/pmglobalphotons.cpp | 521 ++ kpovmodeler/pmglobalphotons.h | 284 + kpovmodeler/pmglobalphotonsedit.cpp | 328 + kpovmodeler/pmglobalphotonsedit.h | 98 + kpovmodeler/pmglobals.h | 29 + kpovmodeler/pmglobalsettings.cpp | 516 ++ kpovmodeler/pmglobalsettings.h | 268 + kpovmodeler/pmglobalsettingsedit.cpp | 317 + kpovmodeler/pmglobalsettingsedit.h | 93 + kpovmodeler/pmglview.cpp | 1853 ++++ kpovmodeler/pmglview.h | 589 ++ kpovmodeler/pmgraphicalobject.cpp | 248 + kpovmodeler/pmgraphicalobject.h | 141 + kpovmodeler/pmgraphicalobjectedit.cpp | 168 + kpovmodeler/pmgraphicalobjectedit.h | 78 + kpovmodeler/pmgridsettings.cpp | 155 + kpovmodeler/pmgridsettings.h | 60 + kpovmodeler/pmheightfield.cpp | 469 ++ kpovmodeler/pmheightfield.h | 180 + kpovmodeler/pmheightfieldedit.cpp | 201 + kpovmodeler/pmheightfieldedit.h | 87 + kpovmodeler/pmheightfieldroam.cpp | 422 + kpovmodeler/pmheightfieldroam.h | 283 + kpovmodeler/pmimagemap.cpp | 522 ++ kpovmodeler/pmimagemap.h | 209 + kpovmodeler/pmimagemapedit.cpp | 625 ++ kpovmodeler/pmimagemapedit.h | 121 + kpovmodeler/pminserterrordialog.cpp | 51 + kpovmodeler/pminserterrordialog.h | 54 + kpovmodeler/pminsertpopup.cpp | 90 + kpovmodeler/pminsertpopup.h | 81 + kpovmodeler/pminsertrules.dtd | 97 + kpovmodeler/pminsertrulesystem.cpp | 1061 +++ kpovmodeler/pminsertrulesystem.h | 678 ++ kpovmodeler/pminterior.cpp | 343 + kpovmodeler/pminterior.h | 128 + kpovmodeler/pminterioredit.cpp | 212 + kpovmodeler/pminterioredit.h | 85 + kpovmodeler/pminteriortexture.cpp | 75 + kpovmodeler/pminteriortexture.h | 71 + kpovmodeler/pminteriortextureedit.cpp | 44 + kpovmodeler/pminteriortextureedit.h | 58 + kpovmodeler/pmiomanager.cpp | 96 + kpovmodeler/pmiomanager.h | 184 + kpovmodeler/pmisosurface.cpp | 419 + kpovmodeler/pmisosurface.h | 234 + kpovmodeler/pmisosurfaceedit.cpp | 326 + kpovmodeler/pmisosurfaceedit.h | 92 + kpovmodeler/pmjuliafractal.cpp | 449 + kpovmodeler/pmjuliafractal.h | 174 + kpovmodeler/pmjuliafractaledit.cpp | 380 + kpovmodeler/pmjuliafractaledit.h | 79 + kpovmodeler/pmlathe.cpp | 948 +++ kpovmodeler/pmlathe.h | 193 + kpovmodeler/pmlatheedit.cpp | 333 + kpovmodeler/pmlatheedit.h | 89 + kpovmodeler/pmlayoutsettings.cpp | 774 ++ kpovmodeler/pmlayoutsettings.h | 174 + kpovmodeler/pmlibrarybrowser.cpp | 304 + kpovmodeler/pmlibrarybrowser.h | 119 + kpovmodeler/pmlibraryentrypreview.cpp | 344 + kpovmodeler/pmlibraryentrypreview.h | 119 + kpovmodeler/pmlibraryhandle.cpp | 395 + kpovmodeler/pmlibraryhandle.h | 210 + kpovmodeler/pmlibraryhandleedit.cpp | 131 + kpovmodeler/pmlibraryhandleedit.h | 66 + kpovmodeler/pmlibraryiconview.cpp | 328 + kpovmodeler/pmlibraryiconview.h | 123 + kpovmodeler/pmlibrarymanager.cpp | 121 + kpovmodeler/pmlibrarymanager.h | 97 + kpovmodeler/pmlibraryobject.cpp | 331 + kpovmodeler/pmlibraryobject.h | 136 + kpovmodeler/pmlibraryobjectsearch.cpp | 86 + kpovmodeler/pmlibraryobjectsearch.h | 55 + kpovmodeler/pmlight.cpp | 1064 +++ kpovmodeler/pmlight.h | 372 + kpovmodeler/pmlightedit.cpp | 450 + kpovmodeler/pmlightedit.h | 115 + kpovmodeler/pmlightgroup.cpp | 134 + kpovmodeler/pmlightgroup.h | 98 + kpovmodeler/pmlightgroupedit.cpp | 78 + kpovmodeler/pmlightgroupedit.h | 64 + kpovmodeler/pmline.cpp | 22 + kpovmodeler/pmline.h | 102 + kpovmodeler/pmlineedits.cpp | 229 + kpovmodeler/pmlineedits.h | 133 + kpovmodeler/pmlinkedit.cpp | 146 + kpovmodeler/pmlinkedit.h | 105 + kpovmodeler/pmlistpattern.cpp | 469 ++ kpovmodeler/pmlistpattern.h | 351 + kpovmodeler/pmlistpatternedit.cpp | 225 + kpovmodeler/pmlistpatternedit.h | 78 + kpovmodeler/pmlookslike.cpp | 92 + kpovmodeler/pmlookslike.h | 82 + kpovmodeler/pmmapmemento.cpp | 51 + kpovmodeler/pmmapmemento.h | 81 + kpovmodeler/pmmaterial.cpp | 75 + kpovmodeler/pmmaterial.h | 75 + kpovmodeler/pmmaterialedit.cpp | 44 + kpovmodeler/pmmaterialedit.h | 58 + kpovmodeler/pmmaterialmap.cpp | 338 + kpovmodeler/pmmaterialmap.h | 153 + kpovmodeler/pmmaterialmapedit.cpp | 299 + kpovmodeler/pmmaterialmapedit.h | 81 + kpovmodeler/pmmath.cpp | 67 + kpovmodeler/pmmath.h | 48 + kpovmodeler/pmmatrix.cpp | 442 + kpovmodeler/pmmatrix.h | 188 + kpovmodeler/pmmedia.cpp | 480 ++ kpovmodeler/pmmedia.h | 149 + kpovmodeler/pmmediaedit.cpp | 370 + kpovmodeler/pmmediaedit.h | 102 + kpovmodeler/pmmemento.cpp | 220 + kpovmodeler/pmmemento.h | 318 + kpovmodeler/pmmesh.cpp | 557 ++ kpovmodeler/pmmesh.h | 142 + kpovmodeler/pmmeshedit.cpp | 100 + kpovmodeler/pmmeshedit.h | 67 + kpovmodeler/pmmessage.cpp | 43 + kpovmodeler/pmmessage.h | 79 + kpovmodeler/pmmetaobject.cpp | 95 + kpovmodeler/pmmetaobject.h | 416 + kpovmodeler/pmmovecommand.cpp | 478 ++ kpovmodeler/pmmovecommand.h | 88 + kpovmodeler/pmnamedobject.cpp | 111 + kpovmodeler/pmnamedobject.h | 89 + kpovmodeler/pmnamedobjectedit.cpp | 81 + kpovmodeler/pmnamedobjectedit.h | 64 + kpovmodeler/pmnormal.cpp | 189 + kpovmodeler/pmnormal.h | 122 + kpovmodeler/pmnormaledit.cpp | 118 + kpovmodeler/pmnormaledit.h | 70 + kpovmodeler/pmobject.cpp | 283 + kpovmodeler/pmobject.h | 511 ++ kpovmodeler/pmobjectaction.h | 100 + kpovmodeler/pmobjectdrag.cpp | 230 + kpovmodeler/pmobjectdrag.h | 81 + kpovmodeler/pmobjectlibrarysettings.cpp | 189 + kpovmodeler/pmobjectlibrarysettings.h | 78 + kpovmodeler/pmobjectlink.cpp | 197 + kpovmodeler/pmobjectlink.h | 99 + kpovmodeler/pmobjectlinkedit.cpp | 74 + kpovmodeler/pmobjectlinkedit.h | 62 + kpovmodeler/pmobjectselect.cpp | 361 + kpovmodeler/pmobjectselect.h | 132 + kpovmodeler/pmobjectsettings.cpp | 550 ++ kpovmodeler/pmobjectsettings.h | 78 + kpovmodeler/pmopenglsettings.cpp | 59 + kpovmodeler/pmopenglsettings.h | 54 + kpovmodeler/pmoutputdevice.cpp | 203 + kpovmodeler/pmoutputdevice.h | 159 + kpovmodeler/pmpalettevalue.cpp | 81 + kpovmodeler/pmpalettevalue.h | 78 + kpovmodeler/pmpalettevalueedit.cpp | 99 + kpovmodeler/pmpalettevalueedit.h | 67 + kpovmodeler/pmpalettevaluememento.cpp | 84 + kpovmodeler/pmpalettevaluememento.h | 85 + kpovmodeler/pmparser.cpp | 433 + kpovmodeler/pmparser.h | 299 + kpovmodeler/pmpart.cpp | 2884 +++++++ kpovmodeler/pmpart.h | 1041 +++ kpovmodeler/pmpartiface.h | 119 + kpovmodeler/pmpattern.cpp | 1126 +++ kpovmodeler/pmpattern.h | 449 + kpovmodeler/pmpatternedit.cpp | 1073 +++ kpovmodeler/pmpatternedit.h | 164 + kpovmodeler/pmphotons.cpp | 240 + kpovmodeler/pmphotons.h | 160 + kpovmodeler/pmphotonsedit.cpp | 160 + kpovmodeler/pmphotonsedit.h | 79 + kpovmodeler/pmpigment.cpp | 124 + kpovmodeler/pmpigment.h | 95 + kpovmodeler/pmpigmentedit.cpp | 68 + kpovmodeler/pmpigmentedit.h | 60 + kpovmodeler/pmplane.cpp | 276 + kpovmodeler/pmplane.h | 148 + kpovmodeler/pmplaneedit.cpp | 124 + kpovmodeler/pmplaneedit.h | 66 + kpovmodeler/pmplanenormalcontrolpoint.cpp | 93 + kpovmodeler/pmplanenormalcontrolpoint.h | 92 + kpovmodeler/pmpluginmanager.cpp | 115 + kpovmodeler/pmpluginmanager.h | 113 + kpovmodeler/pmpluginsettings.cpp | 150 + kpovmodeler/pmpluginsettings.h | 62 + kpovmodeler/pmpoint.cpp | 98 + kpovmodeler/pmpoint.h | 122 + kpovmodeler/pmpolynom.cpp | 238 + kpovmodeler/pmpolynom.h | 105 + kpovmodeler/pmpolynomedit.cpp | 255 + kpovmodeler/pmpolynomedit.h | 80 + kpovmodeler/pmpolynomexponents.cpp | 71 + kpovmodeler/pmpolynomexponents.h | 129 + kpovmodeler/pmpovray31format.cpp | 153 + kpovmodeler/pmpovray31format.h | 64 + kpovmodeler/pmpovray31serialization.cpp | 2199 +++++ kpovmodeler/pmpovray31serialization.h | 103 + kpovmodeler/pmpovray35format.cpp | 100 + kpovmodeler/pmpovray35format.h | 64 + kpovmodeler/pmpovray35serialization.cpp | 1471 ++++ kpovmodeler/pmpovray35serialization.h | 49 + kpovmodeler/pmpovrayformat.cpp | 52 + kpovmodeler/pmpovrayformat.h | 94 + kpovmodeler/pmpovraymatrix.cpp | 152 + kpovmodeler/pmpovraymatrix.h | 97 + kpovmodeler/pmpovraymatrixedit.cpp | 102 + kpovmodeler/pmpovraymatrixedit.h | 62 + kpovmodeler/pmpovrayoutputwidget.cpp | 115 + kpovmodeler/pmpovrayoutputwidget.h | 77 + kpovmodeler/pmpovrayparser.cpp | 7213 ++++++++++++++++ kpovmodeler/pmpovrayparser.h | 534 ++ kpovmodeler/pmpovrayrenderwidget.cpp | 437 + kpovmodeler/pmpovrayrenderwidget.h | 177 + kpovmodeler/pmpovraysettings.cpp | 308 + kpovmodeler/pmpovraysettings.h | 98 + kpovmodeler/pmpovraywidget.cpp | 411 + kpovmodeler/pmpovraywidget.h | 103 + kpovmodeler/pmpreviewsettings.cpp | 207 + kpovmodeler/pmpreviewsettings.h | 69 + kpovmodeler/pmprism.cpp | 1187 +++ kpovmodeler/pmprism.h | 224 + kpovmodeler/pmprismedit.cpp | 696 ++ kpovmodeler/pmprismedit.h | 122 + kpovmodeler/pmprismmemento.cpp | 55 + kpovmodeler/pmprismmemento.h | 71 + kpovmodeler/pmprojectedthrough.cpp | 92 + kpovmodeler/pmprojectedthrough.h | 82 + kpovmodeler/pmprototypemanager.cpp | 243 + kpovmodeler/pmprototypemanager.h | 149 + kpovmodeler/pmquickcolor.cpp | 132 + kpovmodeler/pmquickcolor.h | 100 + kpovmodeler/pmquickcoloredit.cpp | 77 + kpovmodeler/pmquickcoloredit.h | 65 + kpovmodeler/pmradiosity.cpp | 428 + kpovmodeler/pmradiosity.h | 241 + kpovmodeler/pmradiosityedit.cpp | 233 + kpovmodeler/pmradiosityedit.h | 81 + kpovmodeler/pmrainbow.cpp | 422 + kpovmodeler/pmrainbow.h | 139 + kpovmodeler/pmrainbowedit.cpp | 278 + kpovmodeler/pmrainbowedit.h | 90 + kpovmodeler/pmraw.cpp | 135 + kpovmodeler/pmraw.h | 90 + kpovmodeler/pmrawedit.cpp | 79 + kpovmodeler/pmrawedit.h | 62 + kpovmodeler/pmrecursiveobjectiterator.cpp | 62 + kpovmodeler/pmrecursiveobjectiterator.h | 49 + kpovmodeler/pmrendermanager.cpp | 1647 ++++ kpovmodeler/pmrendermanager.h | 435 + kpovmodeler/pmrendermode.cpp | 220 + kpovmodeler/pmrendermode.h | 128 + kpovmodeler/pmrendermodesdialog.cpp | 611 ++ kpovmodeler/pmrendermodesdialog.h | 179 + kpovmodeler/pmresourcelocator.cpp | 103 + kpovmodeler/pmresourcelocator.h | 65 + kpovmodeler/pmrotate.cpp | 164 + kpovmodeler/pmrotate.h | 102 + kpovmodeler/pmrotatecontrolpoint.cpp | 78 + kpovmodeler/pmrotatecontrolpoint.h | 73 + kpovmodeler/pmrotateedit.cpp | 74 + kpovmodeler/pmrotateedit.h | 62 + kpovmodeler/pmscale.cpp | 163 + kpovmodeler/pmscale.h | 103 + kpovmodeler/pmscalecontrolpoint.cpp | 58 + kpovmodeler/pmscalecontrolpoint.h | 71 + kpovmodeler/pmscaleedit.cpp | 74 + kpovmodeler/pmscaleedit.h | 62 + kpovmodeler/pmscanner.cpp | 1353 +++ kpovmodeler/pmscanner.h | 191 + kpovmodeler/pmscene.cpp | 119 + kpovmodeler/pmscene.h | 92 + kpovmodeler/pmserializer.cpp | 93 + kpovmodeler/pmserializer.h | 179 + kpovmodeler/pmsettingsdialog.cpp | 263 + kpovmodeler/pmsettingsdialog.h | 187 + kpovmodeler/pmshell.cpp | 676 ++ kpovmodeler/pmshell.h | 172 + kpovmodeler/pmskysphere.cpp | 76 + kpovmodeler/pmskysphere.h | 75 + kpovmodeler/pmskysphereedit.cpp | 44 + kpovmodeler/pmskysphereedit.h | 58 + kpovmodeler/pmslope.cpp | 146 + kpovmodeler/pmslope.h | 94 + kpovmodeler/pmslopeedit.cpp | 95 + kpovmodeler/pmslopeedit.h | 68 + kpovmodeler/pmsolidcolor.cpp | 127 + kpovmodeler/pmsolidcolor.h | 97 + kpovmodeler/pmsolidcoloredit.cpp | 79 + kpovmodeler/pmsolidcoloredit.h | 62 + kpovmodeler/pmsolidobject.cpp | 140 + kpovmodeler/pmsolidobject.h | 94 + kpovmodeler/pmsolidobjectedit.cpp | 82 + kpovmodeler/pmsolidobjectedit.h | 63 + kpovmodeler/pmsor.cpp | 708 ++ kpovmodeler/pmsor.h | 191 + kpovmodeler/pmsorcontrolpoint.cpp | 228 + kpovmodeler/pmsorcontrolpoint.h | 99 + kpovmodeler/pmsoredit.cpp | 282 + kpovmodeler/pmsoredit.h | 86 + kpovmodeler/pmsorsegment.cpp | 97 + kpovmodeler/pmsorsegment.h | 77 + kpovmodeler/pmsphere.cpp | 411 + kpovmodeler/pmsphere.h | 165 + kpovmodeler/pmsphereedit.cpp | 95 + kpovmodeler/pmsphereedit.h | 64 + kpovmodeler/pmspheresweep.cpp | 894 ++ kpovmodeler/pmspheresweep.h | 245 + kpovmodeler/pmspheresweepedit.cpp | 354 + kpovmodeler/pmspheresweepedit.h | 90 + kpovmodeler/pmsplinememento.cpp | 58 + kpovmodeler/pmsplinememento.h | 68 + kpovmodeler/pmsplinesegment.cpp | 107 + kpovmodeler/pmsplinesegment.h | 122 + kpovmodeler/pmsqe.cpp | 413 + kpovmodeler/pmsqe.h | 155 + kpovmodeler/pmsqeedit.cpp | 93 + kpovmodeler/pmsqeedit.h | 63 + kpovmodeler/pmsymboltable.cpp | 121 + kpovmodeler/pmsymboltable.h | 128 + kpovmodeler/pmtext.cpp | 339 + kpovmodeler/pmtext.h | 147 + kpovmodeler/pmtextedit.cpp | 138 + kpovmodeler/pmtextedit.h | 74 + kpovmodeler/pmtexture.cpp | 124 + kpovmodeler/pmtexture.h | 95 + kpovmodeler/pmtexturebase.cpp | 180 + kpovmodeler/pmtexturebase.h | 96 + kpovmodeler/pmtexturebaseedit.cpp | 72 + kpovmodeler/pmtexturebaseedit.h | 64 + kpovmodeler/pmtextureedit.cpp | 67 + kpovmodeler/pmtextureedit.h | 60 + kpovmodeler/pmtexturemap.cpp | 601 ++ kpovmodeler/pmtexturemap.h | 368 + kpovmodeler/pmtexturemapedit.cpp | 152 + kpovmodeler/pmtexturemapedit.h | 70 + kpovmodeler/pmthreestate.h | 26 + kpovmodeler/pmtokens.h | 463 + kpovmodeler/pmtorus.cpp | 379 + kpovmodeler/pmtorus.h | 172 + kpovmodeler/pmtorusedit.cpp | 105 + kpovmodeler/pmtorusedit.h | 65 + kpovmodeler/pmtranslate.cpp | 162 + kpovmodeler/pmtranslate.h | 102 + kpovmodeler/pmtranslatecontrolpoint.cpp | 50 + kpovmodeler/pmtranslatecontrolpoint.h | 71 + kpovmodeler/pmtranslateedit.cpp | 74 + kpovmodeler/pmtranslateedit.h | 62 + kpovmodeler/pmtreeview.cpp | 820 ++ kpovmodeler/pmtreeview.h | 182 + kpovmodeler/pmtreeviewitem.cpp | 117 + kpovmodeler/pmtreeviewitem.h | 88 + kpovmodeler/pmtriangle.cpp | 621 ++ kpovmodeler/pmtriangle.h | 158 + kpovmodeler/pmtriangleedit.cpp | 273 + kpovmodeler/pmtriangleedit.h | 77 + kpovmodeler/pmtruetypecache.cpp | 395 + kpovmodeler/pmtruetypecache.h | 194 + kpovmodeler/pmunknownview.cpp | 37 + kpovmodeler/pmunknownview.h | 47 + kpovmodeler/pmvalue.h | 102 + kpovmodeler/pmvariant.cpp | 920 ++ kpovmodeler/pmvariant.h | 221 + kpovmodeler/pmvector.cpp | 593 ++ kpovmodeler/pmvector.h | 275 + kpovmodeler/pmvectorcontrolpoint.cpp | 89 + kpovmodeler/pmvectorcontrolpoint.h | 101 + kpovmodeler/pmvectoredit.cpp | 235 + kpovmodeler/pmvectoredit.h | 100 + kpovmodeler/pmvectorlistedit.cpp | 357 + kpovmodeler/pmvectorlistedit.h | 174 + kpovmodeler/pmview.cpp | 108 + kpovmodeler/pmview.h | 76 + kpovmodeler/pmviewbase.cpp | 20 + kpovmodeler/pmviewbase.h | 128 + kpovmodeler/pmviewfactory.cpp | 94 + kpovmodeler/pmviewfactory.h | 145 + kpovmodeler/pmviewlayoutmanager.cpp | 935 ++ kpovmodeler/pmviewlayoutmanager.h | 306 + kpovmodeler/pmviewstructure.cpp | 127 + kpovmodeler/pmviewstructure.h | 222 + kpovmodeler/pmwarp.cpp | 548 ++ kpovmodeler/pmwarp.h | 162 + kpovmodeler/pmwarpedit.cpp | 407 + kpovmodeler/pmwarpedit.h | 110 + kpovmodeler/pmxmlhelper.cpp | 160 + kpovmodeler/pmxmlhelper.h | 121 + kpovmodeler/pmxmlparser.cpp | 177 + kpovmodeler/pmxmlparser.h | 84 + kpovmodeler/povraydocmap.xml | 174 + kpovmodeler/questionmark.png | Bin 0 -> 12749 bytes kpovmodeler/version.h | 18 + kruler/Makefile.am | 25 + kruler/eventsrc | 192 + kruler/klineal.cpp | 746 ++ kruler/klineal.h | 106 + kruler/kruler.desktop | 90 + kruler/main.cpp | 48 + kruler/move.wav | Bin 0 -> 2656 bytes kruler/pics/Makefile.am | 5 + kruler/pics/hi16-app-kruler.png | Bin 0 -> 391 bytes kruler/pics/hi22-app-kruler.png | Bin 0 -> 310 bytes kruler/pics/hi32-app-kruler.png | Bin 0 -> 730 bytes kruler/pics/hi48-app-kruler.png | Bin 0 -> 932 bytes kruler/pics/kruler-east.png | Bin 0 -> 446 bytes kruler/pics/kruler-north.png | Bin 0 -> 310 bytes kruler/pics/kruler-south.png | Bin 0 -> 300 bytes kruler/pics/kruler-west.png | Bin 0 -> 439 bytes kruler/uninstall.desktop | 2 + ksnapshot/Makefile.am | 21 + ksnapshot/README | 29 + ksnapshot/configure.in.in | 6 + ksnapshot/hi16-app-ksnapshot.png | Bin 0 -> 852 bytes ksnapshot/hi22-app-ksnapshot.png | Bin 0 -> 1328 bytes ksnapshot/hi32-app-ksnapshot.png | Bin 0 -> 2056 bytes ksnapshot/hi48-app-ksnapshot.png | Bin 0 -> 3530 bytes ksnapshot/hisc-app-ksnapshot.svgz | Bin 0 -> 5445 bytes ksnapshot/ksnapshot.cpp | 510 ++ ksnapshot/ksnapshot.desktop | 92 + ksnapshot/ksnapshot.h | 150 + ksnapshot/ksnapshotiface.h | 65 + ksnapshot/ksnapshotwidget.ui | 361 + ksnapshot/ksnapshotwidget.ui.h | 138 + ksnapshot/main.cpp | 77 + ksnapshot/regiongrabber.cpp | 177 + ksnapshot/regiongrabber.h | 70 + ksnapshot/uninstall.desktop | 2 + ksnapshot/windowgrabber.cpp | 353 + ksnapshot/windowgrabber.h | 59 + ksvg/AUTHORS | 2 + ksvg/FAQ | 17 + ksvg/Makefile.am | 115 + ksvg/NEWS | 8 + ksvg/README | 9 + ksvg/RELEASE-TODO | 10 + ksvg/TODO | 10 + ksvg/VERSION | 1 + ksvg/configure.in.bot | 25 + ksvg/configure.in.in | 203 + ksvg/core/CanvasFactory.cpp | 176 + ksvg/core/CanvasFactory.h | 69 + ksvg/core/CanvasItem.h | 154 + ksvg/core/CanvasItems.cpp | 509 ++ ksvg/core/CanvasItems.h | 133 + ksvg/core/DocumentFactory.cpp | 110 + ksvg/core/DocumentFactory.h | 63 + ksvg/core/KSVGCanvas.cpp | 786 ++ ksvg/core/KSVGCanvas.h | 190 + ksvg/core/KSVGHelper.cpp | 92 + ksvg/core/KSVGHelper.h | 144 + ksvg/core/KSVGLoader.cpp | 449 + ksvg/core/KSVGLoader.h | 92 + ksvg/core/KSVGReader.cc | 500 ++ ksvg/core/KSVGReader.h | 67 + ksvg/core/KSVGTextChunk.cpp | 69 + ksvg/core/KSVGTextChunk.h | 54 + ksvg/core/Makefile.am | 16 + ksvg/core/ksvgrenderer.desktop | 56 + ksvg/data/SVGAElementImpl.lut.h | 20 + ksvg/data/SVGAngleImpl.lut.h | 77 + ksvg/data/SVGAnimatedAngleImpl.lut.h | 22 + ksvg/data/SVGAnimatedBooleanImpl.lut.h | 22 + ksvg/data/SVGAnimatedEnumerationImpl.lut.h | 22 + ksvg/data/SVGAnimatedIntegerImpl.lut.h | 22 + ksvg/data/SVGAnimatedLengthImpl.lut.h | 22 + ksvg/data/SVGAnimatedLengthListImpl.lut.h | 22 + ksvg/data/SVGAnimatedNumberImpl.lut.h | 22 + ksvg/data/SVGAnimatedNumberListImpl.lut.h | 22 + ksvg/data/SVGAnimatedPathDataImpl.lut.h | 28 + ksvg/data/SVGAnimatedPointsImpl.lut.h | 22 + ksvg/data/SVGAnimatedPreserveAspectRatioImpl.lut.h | 22 + ksvg/data/SVGAnimatedRectImpl.lut.h | 22 + ksvg/data/SVGAnimatedStringImpl.lut.h | 22 + ksvg/data/SVGAnimatedTransformListImpl.lut.h | 22 + ksvg/data/SVGAnimationElementImpl.lut.h | 94 + ksvg/data/SVGCircleElementImpl.lut.h | 26 + ksvg/data/SVGClipPathElementImpl.lut.h | 20 + ksvg/data/SVGColorImpl.lut.h | 76 + ksvg/data/SVGColorProfileElementImpl.lut.h | 26 + ksvg/data/SVGCursorElementImpl.lut.h | 22 + ksvg/data/SVGDocumentImpl.lut.h | 67 + ksvg/data/SVGEcma.lut.h | 396 + ksvg/data/SVGElementImpl.lut.h | 92 + ksvg/data/SVGEllipseElementImpl.lut.h | 28 + ksvg/data/SVGEventImpl.lut.h | 271 + ksvg/data/SVGExternalResourcesRequiredImpl.lut.h | 20 + ksvg/data/SVGFitToViewBoxImpl.lut.h | 22 + ksvg/data/SVGForeignObjectElementImpl.lut.h | 26 + ksvg/data/SVGGlyphElementImpl.lut.h | 39 + ksvg/data/SVGGlyphRefElementImpl.lut.h | 28 + ksvg/data/SVGGradientElementImpl.lut.h | 51 + ksvg/data/SVGICCColorImpl.lut.h | 23 + ksvg/data/SVGImageElementImpl.lut.h | 31 + ksvg/data/SVGLangSpaceImpl.lut.h | 24 + ksvg/data/SVGLengthImpl.lut.h | 87 + ksvg/data/SVGLengthListImpl.lut.h | 55 + ksvg/data/SVGLineElementImpl.lut.h | 27 + ksvg/data/SVGLinearGradientElementImpl.lut.h | 27 + ksvg/data/SVGLocatableImpl.lut.h | 49 + ksvg/data/SVGMarkerElementImpl.lut.h | 90 + ksvg/data/SVGMaskElementImpl.lut.h | 31 + ksvg/data/SVGMatrixImpl.lut.h | 74 + ksvg/data/SVGNumberImpl.lut.h | 20 + ksvg/data/SVGNumberListImpl.lut.h | 55 + ksvg/data/SVGPaintImpl.lut.h | 59 + ksvg/data/SVGPathElementImpl.lut.h | 87 + ksvg/data/SVGPathSegArcImpl.lut.h | 75 + ksvg/data/SVGPathSegCurvetoCubicImpl.lut.h | 65 + ksvg/data/SVGPathSegCurvetoCubicSmoothImpl.lut.h | 55 + ksvg/data/SVGPathSegCurvetoQuadraticImpl.lut.h | 53 + .../SVGPathSegCurvetoQuadraticSmoothImpl.lut.h | 43 + ksvg/data/SVGPathSegImpl.lut.h | 88 + ksvg/data/SVGPathSegLinetoHorizontalImpl.lut.h | 39 + ksvg/data/SVGPathSegLinetoImpl.lut.h | 43 + ksvg/data/SVGPathSegLinetoVerticalImpl.lut.h | 39 + ksvg/data/SVGPathSegListImpl.lut.h | 55 + ksvg/data/SVGPathSegMovetoImpl.lut.h | 43 + ksvg/data/SVGPatternElementImpl.lut.h | 37 + ksvg/data/SVGPointImpl.lut.h | 22 + ksvg/data/SVGPointListImpl.lut.h | 55 + ksvg/data/SVGPreserveAspectRatioImpl.lut.h | 73 + ksvg/data/SVGRadialGradientElementImpl.lut.h | 30 + ksvg/data/SVGRectElementImpl.lut.h | 29 + ksvg/data/SVGRectImpl.lut.h | 26 + ksvg/data/SVGSVGElementImpl.lut.h | 136 + ksvg/data/SVGScriptElementImpl.lut.h | 20 + ksvg/data/SVGStopElementImpl.lut.h | 22 + ksvg/data/SVGStringListImpl.lut.h | 74 + ksvg/data/SVGStylableImpl.lut.h | 143 + ksvg/data/SVGStyleElementImpl.lut.h | 27 + ksvg/data/SVGSymbolElementImpl.lut.h | 22 + ksvg/data/SVGTestsImpl.lut.h | 45 + ksvg/data/SVGTextContentElementImpl.lut.h | 84 + ksvg/data/SVGTextPathElementImpl.lut.h | 56 + ksvg/data/SVGTextPositioningElementImpl.lut.h | 28 + ksvg/data/SVGTransformImpl.lut.h | 89 + ksvg/data/SVGTransformListImpl.lut.h | 55 + ksvg/data/SVGTransformableImpl.lut.h | 20 + ksvg/data/SVGURIReferenceImpl.lut.h | 20 + ksvg/data/SVGUseElementImpl.lut.h | 36 + ksvg/data/SVGViewElementImpl.lut.h | 20 + ksvg/data/SVGZoomAndPanImpl.lut.h | 45 + ksvg/data/SVGZoomEventImpl.lut.h | 29 + ksvg/data/ksvg_window.lut.h | 98 + ksvg/dom/Makefile.am | 58 + ksvg/dom/SVGAElement.cc | 80 + ksvg/dom/SVGAElement.h | 64 + ksvg/dom/SVGAltGlyphDefElement.cc | 67 + ksvg/dom/SVGAltGlyphDefElement.h | 50 + ksvg/dom/SVGAltGlyphElement.cc | 80 + ksvg/dom/SVGAltGlyphElement.h | 55 + ksvg/dom/SVGAngle.cc | 120 + ksvg/dom/SVGAngle.h | 74 + ksvg/dom/SVGAnimateColorElement.cc | 67 + ksvg/dom/SVGAnimateColorElement.h | 50 + ksvg/dom/SVGAnimateElement.cc | 67 + ksvg/dom/SVGAnimateElement.h | 50 + ksvg/dom/SVGAnimateMotionElement.cc | 65 + ksvg/dom/SVGAnimateMotionElement.h | 47 + ksvg/dom/SVGAnimateTransformElement.cc | 67 + ksvg/dom/SVGAnimateTransformElement.h | 50 + ksvg/dom/SVGAnimatedAngle.cc | 79 + ksvg/dom/SVGAnimatedAngle.h | 52 + ksvg/dom/SVGAnimatedBoolean.cc | 84 + ksvg/dom/SVGAnimatedBoolean.h | 53 + ksvg/dom/SVGAnimatedEnumeration.cc | 84 + ksvg/dom/SVGAnimatedEnumeration.h | 53 + ksvg/dom/SVGAnimatedInteger.cc | 84 + ksvg/dom/SVGAnimatedInteger.h | 53 + ksvg/dom/SVGAnimatedLength.cc | 79 + ksvg/dom/SVGAnimatedLength.h | 52 + ksvg/dom/SVGAnimatedLengthList.cc | 78 + ksvg/dom/SVGAnimatedLengthList.h | 51 + ksvg/dom/SVGAnimatedNumber.cc | 84 + ksvg/dom/SVGAnimatedNumber.h | 53 + ksvg/dom/SVGAnimatedNumberList.cc | 78 + ksvg/dom/SVGAnimatedNumberList.h | 51 + ksvg/dom/SVGAnimatedPathData.cc | 91 + ksvg/dom/SVGAnimatedPathData.h | 54 + ksvg/dom/SVGAnimatedPoints.cc | 79 + ksvg/dom/SVGAnimatedPoints.h | 52 + ksvg/dom/SVGAnimatedPreserveAspectRatio.cc | 79 + ksvg/dom/SVGAnimatedPreserveAspectRatio.h | 52 + ksvg/dom/SVGAnimatedRect.cc | 79 + ksvg/dom/SVGAnimatedRect.h | 51 + ksvg/dom/SVGAnimatedString.cc | 84 + ksvg/dom/SVGAnimatedString.h | 55 + ksvg/dom/SVGAnimatedTransformList.cc | 79 + ksvg/dom/SVGAnimatedTransformList.h | 52 + ksvg/dom/SVGAnimationElement.cc | 93 + ksvg/dom/SVGAnimationElement.h | 60 + ksvg/dom/SVGCSSRule.cc | 66 + ksvg/dom/SVGCSSRule.h | 51 + ksvg/dom/SVGCircleElement.cc | 92 + ksvg/dom/SVGCircleElement.h | 117 + ksvg/dom/SVGClipPathElement.cc | 79 + ksvg/dom/SVGClipPathElement.h | 65 + ksvg/dom/SVGColor.cc | 105 + ksvg/dom/SVGColor.h | 69 + ksvg/dom/SVGColorProfileElement.cc | 105 + ksvg/dom/SVGColorProfileElement.h | 62 + ksvg/dom/SVGColorProfileRule.cc | 103 + ksvg/dom/SVGColorProfileRule.h | 57 + ksvg/dom/SVGComponentTransferFunctionElement.cc | 112 + ksvg/dom/SVGComponentTransferFunctionElement.h | 71 + ksvg/dom/SVGCursorElement.cc | 83 + ksvg/dom/SVGCursorElement.h | 60 + ksvg/dom/SVGDefinitionSrcElement.cc | 67 + ksvg/dom/SVGDefinitionSrcElement.h | 50 + ksvg/dom/SVGDefsElement.cc | 72 + ksvg/dom/SVGDefsElement.h | 78 + ksvg/dom/SVGDescElement.cc | 69 + ksvg/dom/SVGDescElement.h | 54 + ksvg/dom/SVGDocument.cc | 138 + ksvg/dom/SVGDocument.h | 70 + ksvg/dom/SVGElement.cc | 124 + ksvg/dom/SVGElement.h | 83 + ksvg/dom/SVGElementInstance.cc | 117 + ksvg/dom/SVGElementInstance.h | 60 + ksvg/dom/SVGElementInstanceList.cc | 79 + ksvg/dom/SVGElementInstanceList.h | 52 + ksvg/dom/SVGEllipseElement.cc | 98 + ksvg/dom/SVGEllipseElement.h | 131 + ksvg/dom/SVGEvent.cc | 187 + ksvg/dom/SVGEvent.h | 95 + ksvg/dom/SVGException.h | 51 + ksvg/dom/SVGExternalResourcesRequired.cc | 65 + ksvg/dom/SVGExternalResourcesRequired.h | 53 + ksvg/dom/SVGFEBlendElement.cc | 88 + ksvg/dom/SVGFEBlendElement.h | 68 + ksvg/dom/SVGFEColorMatrixElement.cc | 89 + ksvg/dom/SVGFEColorMatrixElement.h | 68 + ksvg/dom/SVGFEComponentTransferElement.cc | 75 + ksvg/dom/SVGFEComponentTransferElement.h | 55 + ksvg/dom/SVGFECompositeElement.cc | 113 + ksvg/dom/SVGFECompositeElement.h | 74 + ksvg/dom/SVGFEConvolveMatrixElement.cc | 140 + ksvg/dom/SVGFEConvolveMatrixElement.h | 78 + ksvg/dom/SVGFEDiffuseLightingElement.cc | 88 + ksvg/dom/SVGFEDiffuseLightingElement.h | 58 + ksvg/dom/SVGFEDisplacementMapElement.cc | 101 + ksvg/dom/SVGFEDisplacementMapElement.h | 69 + ksvg/dom/SVGFEDistantLightElement.cc | 80 + ksvg/dom/SVGFEDistantLightElement.h | 54 + ksvg/dom/SVGFEFloodElement.cc | 76 + ksvg/dom/SVGFEFloodElement.h | 57 + ksvg/dom/SVGFEFuncAElement.cc | 67 + ksvg/dom/SVGFEFuncAElement.h | 50 + ksvg/dom/SVGFEFuncBElement.cc | 67 + ksvg/dom/SVGFEFuncBElement.h | 50 + ksvg/dom/SVGFEFuncGElement.cc | 67 + ksvg/dom/SVGFEFuncGElement.h | 50 + ksvg/dom/SVGFEFuncRElement.cc | 67 + ksvg/dom/SVGFEFuncRElement.h | 50 + ksvg/dom/SVGFEGaussianBlurElement.cc | 94 + ksvg/dom/SVGFEGaussianBlurElement.h | 60 + ksvg/dom/SVGFEImageElement.cc | 72 + ksvg/dom/SVGFEImageElement.h | 60 + ksvg/dom/SVGFEMergeElement.cc | 68 + ksvg/dom/SVGFEMergeElement.h | 52 + ksvg/dom/SVGFEMergeNodeElement.cc | 74 + ksvg/dom/SVGFEMergeNodeElement.h | 53 + ksvg/dom/SVGFEMorphologyElement.cc | 95 + ksvg/dom/SVGFEMorphologyElement.h | 67 + ksvg/dom/SVGFEOffsetElement.cc | 88 + ksvg/dom/SVGFEOffsetElement.h | 58 + ksvg/dom/SVGFEPointLightElement.cc | 86 + ksvg/dom/SVGFEPointLightElement.h | 55 + ksvg/dom/SVGFESpecularLightingElement.cc | 94 + ksvg/dom/SVGFESpecularLightingElement.h | 59 + ksvg/dom/SVGFESpotLightElement.cc | 116 + ksvg/dom/SVGFESpotLightElement.h | 60 + ksvg/dom/SVGFETileElement.cc | 75 + ksvg/dom/SVGFETileElement.h | 55 + ksvg/dom/SVGFETurbulenceElement.cc | 107 + ksvg/dom/SVGFETurbulenceElement.h | 71 + ksvg/dom/SVGFilterElement.cc | 128 + ksvg/dom/SVGFilterElement.h | 74 + ksvg/dom/SVGFilterPrimitiveStandardAttributes.cc | 88 + ksvg/dom/SVGFilterPrimitiveStandardAttributes.h | 55 + ksvg/dom/SVGFitToViewBox.cc | 72 + ksvg/dom/SVGFitToViewBox.h | 55 + ksvg/dom/SVGFontElement.cc | 69 + ksvg/dom/SVGFontElement.h | 54 + ksvg/dom/SVGFontFaceElement.cc | 67 + ksvg/dom/SVGFontFaceElement.h | 50 + ksvg/dom/SVGFontFaceFormatElement.cc | 67 + ksvg/dom/SVGFontFaceFormatElement.h | 50 + ksvg/dom/SVGFontFaceNameElement.cc | 67 + ksvg/dom/SVGFontFaceNameElement.h | 50 + ksvg/dom/SVGFontFaceSrcElement.cc | 67 + ksvg/dom/SVGFontFaceSrcElement.h | 50 + ksvg/dom/SVGFontFaceUriElement.cc | 67 + ksvg/dom/SVGFontFaceUriElement.h | 50 + ksvg/dom/SVGForeignObjectElement.cc | 97 + ksvg/dom/SVGForeignObjectElement.h | 66 + ksvg/dom/SVGGElement.cc | 72 + ksvg/dom/SVGGElement.h | 83 + ksvg/dom/SVGGlyphElement.cc | 68 + ksvg/dom/SVGGlyphElement.h | 52 + ksvg/dom/SVGGlyphRefElement.cc | 81 + ksvg/dom/SVGGlyphRefElement.h | 57 + ksvg/dom/SVGGradientElement.cc | 80 + ksvg/dom/SVGGradientElement.h | 71 + ksvg/dom/SVGHKernElement.cc | 67 + ksvg/dom/SVGHKernElement.h | 50 + ksvg/dom/SVGICCColor.cc | 85 + ksvg/dom/SVGICCColor.h | 56 + ksvg/dom/SVGImageElement.cc | 106 + ksvg/dom/SVGImageElement.h | 70 + ksvg/dom/SVGLangSpace.cc | 82 + ksvg/dom/SVGLangSpace.h | 58 + ksvg/dom/SVGLength.cc | 135 + ksvg/dom/SVGLength.h | 81 + ksvg/dom/SVGLengthList.cc | 115 + ksvg/dom/SVGLengthList.h | 59 + ksvg/dom/SVGLineElement.cc | 98 + ksvg/dom/SVGLineElement.h | 126 + ksvg/dom/SVGLinearGradientElement.cc | 92 + ksvg/dom/SVGLinearGradientElement.h | 141 + ksvg/dom/SVGLocatable.cc | 97 + ksvg/dom/SVGLocatable.h | 122 + ksvg/dom/SVGMPathElement.cc | 69 + ksvg/dom/SVGMPathElement.h | 54 + ksvg/dom/SVGMarkerElement.cc | 129 + ksvg/dom/SVGMarkerElement.h | 87 + ksvg/dom/SVGMaskElement.cc | 109 + ksvg/dom/SVGMaskElement.h | 69 + ksvg/dom/SVGMatrix.cc | 210 + ksvg/dom/SVGMatrix.h | 79 + ksvg/dom/SVGMetadataElement.cc | 67 + ksvg/dom/SVGMetadataElement.h | 50 + ksvg/dom/SVGMissingGlyphElement.cc | 68 + ksvg/dom/SVGMissingGlyphElement.h | 52 + ksvg/dom/SVGNumber.cc | 78 + ksvg/dom/SVGNumber.h | 51 + ksvg/dom/SVGNumberList.cc | 115 + ksvg/dom/SVGNumberList.h | 58 + ksvg/dom/SVGPaint.cc | 93 + ksvg/dom/SVGPaint.h | 70 + ksvg/dom/SVGPathElement.cc | 200 + ksvg/dom/SVGPathElement.h | 107 + ksvg/dom/SVGPathSeg.cc | 69 + ksvg/dom/SVGPathSeg.h | 76 + ksvg/dom/SVGPathSegArc.cc | 238 + ksvg/dom/SVGPathSegArc.h | 109 + ksvg/dom/SVGPathSegClosePath.cc | 46 + ksvg/dom/SVGPathSegClosePath.h | 50 + ksvg/dom/SVGPathSegCurvetoCubic.cc | 214 + ksvg/dom/SVGPathSegCurvetoCubic.h | 103 + ksvg/dom/SVGPathSegCurvetoCubicSmooth.cc | 166 + ksvg/dom/SVGPathSegCurvetoCubicSmooth.h | 91 + ksvg/dom/SVGPathSegCurvetoQuadratic.cc | 166 + ksvg/dom/SVGPathSegCurvetoQuadratic.h | 91 + ksvg/dom/SVGPathSegCurvetoQuadraticSmooth.cc | 118 + ksvg/dom/SVGPathSegCurvetoQuadraticSmooth.h | 79 + ksvg/dom/SVGPathSegLineto.cc | 118 + ksvg/dom/SVGPathSegLineto.h | 79 + ksvg/dom/SVGPathSegLinetoHorizontal.cc | 94 + ksvg/dom/SVGPathSegLinetoHorizontal.h | 73 + ksvg/dom/SVGPathSegLinetoVertical.cc | 94 + ksvg/dom/SVGPathSegLinetoVertical.h | 73 + ksvg/dom/SVGPathSegList.cc | 114 + ksvg/dom/SVGPathSegList.h | 59 + ksvg/dom/SVGPathSegMoveto.cc | 118 + ksvg/dom/SVGPathSegMoveto.h | 79 + ksvg/dom/SVGPatternElement.cc | 117 + ksvg/dom/SVGPatternElement.h | 188 + ksvg/dom/SVGPoint.cc | 97 + ksvg/dom/SVGPoint.h | 57 + ksvg/dom/SVGPointList.cc | 114 + ksvg/dom/SVGPointList.h | 57 + ksvg/dom/SVGPolygonElement.cc | 84 + ksvg/dom/SVGPolygonElement.h | 106 + ksvg/dom/SVGPolylineElement.cc | 85 + ksvg/dom/SVGPolylineElement.h | 106 + ksvg/dom/SVGPreserveAspectRatio.cc | 81 + ksvg/dom/SVGPreserveAspectRatio.h | 76 + ksvg/dom/SVGRadialGradientElement.cc | 98 + ksvg/dom/SVGRadialGradientElement.h | 57 + ksvg/dom/SVGRect.cc | 114 + ksvg/dom/SVGRect.h | 87 + ksvg/dom/SVGRectElement.cc | 109 + ksvg/dom/SVGRectElement.h | 173 + ksvg/dom/SVGRenderingIntent.h | 41 + ksvg/dom/SVGSVGElement.cc | 337 + ksvg/dom/SVGSVGElement.h | 581 ++ ksvg/dom/SVGScriptElement.cc | 81 + ksvg/dom/SVGScriptElement.h | 58 + ksvg/dom/SVGSetElement.cc | 67 + ksvg/dom/SVGSetElement.h | 50 + ksvg/dom/SVGStopElement.cc | 75 + ksvg/dom/SVGStopElement.h | 81 + ksvg/dom/SVGStringList.cc | 115 + ksvg/dom/SVGStringList.h | 60 + ksvg/dom/SVGStylable.cc | 76 + ksvg/dom/SVGStylable.h | 56 + ksvg/dom/SVGStyleElement.cc | 115 + ksvg/dom/SVGStyleElement.h | 63 + ksvg/dom/SVGSwitchElement.cc | 72 + ksvg/dom/SVGSwitchElement.h | 60 + ksvg/dom/SVGSymbolElement.cc | 71 + ksvg/dom/SVGSymbolElement.h | 58 + ksvg/dom/SVGTRefElement.cc | 68 + ksvg/dom/SVGTRefElement.h | 52 + ksvg/dom/SVGTSpanElement.cc | 67 + ksvg/dom/SVGTSpanElement.h | 70 + ksvg/dom/SVGTests.cc | 83 + ksvg/dom/SVGTests.h | 59 + ksvg/dom/SVGTextContentElement.cc | 120 + ksvg/dom/SVGTextContentElement.h | 79 + ksvg/dom/SVGTextElement.cc | 68 + ksvg/dom/SVGTextElement.h | 115 + ksvg/dom/SVGTextPathElement.cc | 89 + ksvg/dom/SVGTextPathElement.h | 70 + ksvg/dom/SVGTextPositioningElement.cc | 85 + ksvg/dom/SVGTextPositioningElement.h | 60 + ksvg/dom/SVGTitleElement.cc | 69 + ksvg/dom/SVGTitleElement.h | 54 + ksvg/dom/SVGTransform.cc | 119 + ksvg/dom/SVGTransform.h | 71 + ksvg/dom/SVGTransformList.cc | 129 + ksvg/dom/SVGTransformList.h | 63 + ksvg/dom/SVGTransformable.cc | 67 + ksvg/dom/SVGTransformable.h | 55 + ksvg/dom/SVGURIReference.cc | 63 + ksvg/dom/SVGURIReference.h | 53 + ksvg/dom/SVGUnitTypes.h | 41 + ksvg/dom/SVGUseElement.cc | 111 + ksvg/dom/SVGUseElement.h | 71 + ksvg/dom/SVGVKernElement.cc | 67 + ksvg/dom/SVGVKernElement.h | 50 + ksvg/dom/SVGViewElement.cc | 77 + ksvg/dom/SVGViewElement.h | 59 + ksvg/dom/SVGViewSpec.cc | 107 + ksvg/dom/SVGViewSpec.h | 63 + ksvg/dom/SVGWindow.cc | 175 + ksvg/dom/SVGWindow.h | 127 + ksvg/dom/SVGZoomAndPan.cc | 70 + ksvg/dom/SVGZoomAndPan.h | 60 + ksvg/dom/SVGZoomEvent.cc | 99 + ksvg/dom/SVGZoomEvent.h | 58 + ksvg/ecma/Makefile.am | 7 + ksvg/ecma/ksvg_bridge.h | 103 + ksvg/ecma/ksvg_cacheimpl.h | 65 + ksvg/ecma/ksvg_ecma.cpp | 336 + ksvg/ecma/ksvg_ecma.h | 114 + ksvg/ecma/ksvg_ecmaeventlistener.cpp | 99 + ksvg/ecma/ksvg_ecmaeventlistener.h | 54 + ksvg/ecma/ksvg_helper.cpp | 68 + ksvg/ecma/ksvg_lookup.h | 318 + ksvg/ecma/ksvg_scriptinterpreter.cpp | 92 + ksvg/ecma/ksvg_scriptinterpreter.h | 71 + ksvg/ecma/ksvg_window.cpp | 578 ++ ksvg/ecma/ksvg_window.h | 122 + ksvg/impl/LRUCache.h | 169 + ksvg/impl/Makefile.am | 116 + ksvg/impl/SVGAElementImpl.cc | 117 + ksvg/impl/SVGAElementImpl.h | 79 + ksvg/impl/SVGAltGlyphDefElementImpl.cc | 33 + ksvg/impl/SVGAltGlyphDefElementImpl.h | 49 + ksvg/impl/SVGAltGlyphElementImpl.cc | 50 + ksvg/impl/SVGAltGlyphElementImpl.h | 55 + ksvg/impl/SVGAngleImpl.cc | 277 + ksvg/impl/SVGAngleImpl.h | 102 + ksvg/impl/SVGAnimateColorElementImpl.cc | 98 + ksvg/impl/SVGAnimateColorElementImpl.h | 60 + ksvg/impl/SVGAnimateElementImpl.cc | 191 + ksvg/impl/SVGAnimateElementImpl.h | 59 + ksvg/impl/SVGAnimateMotionElementImpl.cc | 102 + ksvg/impl/SVGAnimateMotionElementImpl.h | 56 + ksvg/impl/SVGAnimateTransformElementImpl.cc | 257 + ksvg/impl/SVGAnimateTransformElementImpl.h | 74 + ksvg/impl/SVGAnimatedAngleImpl.cc | 83 + ksvg/impl/SVGAnimatedAngleImpl.h | 61 + ksvg/impl/SVGAnimatedBooleanImpl.cc | 93 + ksvg/impl/SVGAnimatedBooleanImpl.h | 64 + ksvg/impl/SVGAnimatedEnumerationImpl.cc | 93 + ksvg/impl/SVGAnimatedEnumerationImpl.h | 64 + ksvg/impl/SVGAnimatedIntegerImpl.cc | 91 + ksvg/impl/SVGAnimatedIntegerImpl.h | 64 + ksvg/impl/SVGAnimatedLengthImpl.cc | 96 + ksvg/impl/SVGAnimatedLengthImpl.h | 65 + ksvg/impl/SVGAnimatedLengthListImpl.cc | 95 + ksvg/impl/SVGAnimatedLengthListImpl.h | 61 + ksvg/impl/SVGAnimatedNumberImpl.cc | 94 + ksvg/impl/SVGAnimatedNumberImpl.h | 63 + ksvg/impl/SVGAnimatedNumberListImpl.cc | 82 + ksvg/impl/SVGAnimatedNumberListImpl.h | 58 + ksvg/impl/SVGAnimatedPathDataImpl.cc | 108 + ksvg/impl/SVGAnimatedPathDataImpl.h | 67 + ksvg/impl/SVGAnimatedPointsImpl.cc | 139 + ksvg/impl/SVGAnimatedPointsImpl.h | 67 + ksvg/impl/SVGAnimatedPreserveAspectRatioImpl.cc | 83 + ksvg/impl/SVGAnimatedPreserveAspectRatioImpl.h | 61 + ksvg/impl/SVGAnimatedRectImpl.cc | 81 + ksvg/impl/SVGAnimatedRectImpl.h | 61 + ksvg/impl/SVGAnimatedStringImpl.cc | 90 + ksvg/impl/SVGAnimatedStringImpl.h | 65 + ksvg/impl/SVGAnimatedTransformListImpl.cc | 83 + ksvg/impl/SVGAnimatedTransformListImpl.h | 61 + ksvg/impl/SVGAnimationElementImpl.cc | 465 + ksvg/impl/SVGAnimationElementImpl.h | 149 + ksvg/impl/SVGBBoxTarget.cc | 55 + ksvg/impl/SVGBBoxTarget.h | 45 + ksvg/impl/SVGCSSRuleImpl.cc | 33 + ksvg/impl/SVGCSSRuleImpl.h | 42 + ksvg/impl/SVGCircleElementImpl.cc | 178 + ksvg/impl/SVGCircleElementImpl.h | 84 + ksvg/impl/SVGClipPathElementImpl.cc | 104 + ksvg/impl/SVGClipPathElementImpl.h | 80 + ksvg/impl/SVGColorImpl.cc | 540 ++ ksvg/impl/SVGColorImpl.h | 94 + ksvg/impl/SVGColorProfileElementImpl.cc | 271 + ksvg/impl/SVGColorProfileElementImpl.h | 100 + ksvg/impl/SVGColorProfileRuleImpl.cc | 63 + ksvg/impl/SVGColorProfileRuleImpl.h | 58 + .../SVGComponentTransferFunctionElementImpl.cc | 105 + .../impl/SVGComponentTransferFunctionElementImpl.h | 66 + ksvg/impl/SVGContainerImpl.cc | 135 + ksvg/impl/SVGContainerImpl.h | 58 + ksvg/impl/SVGCursorElementImpl.cc | 104 + ksvg/impl/SVGCursorElementImpl.h | 69 + ksvg/impl/SVGDefinitionSrcElementImpl.cc | 33 + ksvg/impl/SVGDefinitionSrcElementImpl.h | 46 + ksvg/impl/SVGDefsElementImpl.cc | 34 + ksvg/impl/SVGDefsElementImpl.h | 61 + ksvg/impl/SVGDescElementImpl.cc | 39 + ksvg/impl/SVGDescElementImpl.h | 55 + ksvg/impl/SVGDocumentImpl.cc | 705 ++ ksvg/impl/SVGDocumentImpl.h | 245 + ksvg/impl/SVGEcma.cc | 844 ++ ksvg/impl/SVGEcma.h | 250 + ksvg/impl/SVGElementImpl.cc | 713 ++ ksvg/impl/SVGElementImpl.h | 229 + ksvg/impl/SVGElementInstanceImpl.cc | 108 + ksvg/impl/SVGElementInstanceImpl.h | 70 + ksvg/impl/SVGElementInstanceListImpl.cc | 44 + ksvg/impl/SVGElementInstanceListImpl.h | 49 + ksvg/impl/SVGEllipseElementImpl.cc | 200 + ksvg/impl/SVGEllipseElementImpl.h | 86 + ksvg/impl/SVGEventImpl.cc | 992 +++ ksvg/impl/SVGEventImpl.h | 468 + ksvg/impl/SVGExternalResourcesRequiredImpl.cc | 88 + ksvg/impl/SVGExternalResourcesRequiredImpl.h | 59 + ksvg/impl/SVGFEBlendElementImpl.cc | 64 + ksvg/impl/SVGFEBlendElementImpl.h | 59 + ksvg/impl/SVGFEColorMatrixElementImpl.cc | 65 + ksvg/impl/SVGFEColorMatrixElementImpl.h | 60 + ksvg/impl/SVGFEComponentTransferElementImpl.cc | 43 + ksvg/impl/SVGFEComponentTransferElementImpl.h | 54 + ksvg/impl/SVGFECompositeElementImpl.cc | 105 + ksvg/impl/SVGFECompositeElementImpl.h | 68 + ksvg/impl/SVGFEConvolveMatrixElementImpl.cc | 149 + ksvg/impl/SVGFEConvolveMatrixElementImpl.h | 80 + ksvg/impl/SVGFEDiffuseLightingElementImpl.cc | 64 + ksvg/impl/SVGFEDiffuseLightingElementImpl.h | 59 + ksvg/impl/SVGFEDisplacementMapElementImpl.cc | 85 + ksvg/impl/SVGFEDisplacementMapElementImpl.h | 64 + ksvg/impl/SVGFEDistantLightElementImpl.cc | 53 + ksvg/impl/SVGFEDistantLightElementImpl.h | 54 + ksvg/impl/SVGFEFloodElementImpl.cc | 43 + ksvg/impl/SVGFEFloodElementImpl.h | 56 + ksvg/impl/SVGFEFuncAElementImpl.cc | 33 + ksvg/impl/SVGFEFuncAElementImpl.h | 46 + ksvg/impl/SVGFEFuncBElementImpl.cc | 33 + ksvg/impl/SVGFEFuncBElementImpl.h | 45 + ksvg/impl/SVGFEFuncGElementImpl.cc | 33 + ksvg/impl/SVGFEFuncGElementImpl.h | 46 + ksvg/impl/SVGFEFuncRElementImpl.cc | 33 + ksvg/impl/SVGFEFuncRElementImpl.h | 46 + ksvg/impl/SVGFEGaussianBlurElementImpl.cc | 68 + ksvg/impl/SVGFEGaussianBlurElementImpl.h | 60 + ksvg/impl/SVGFEImageElementImpl.cc | 33 + ksvg/impl/SVGFEImageElementImpl.h | 56 + ksvg/impl/SVGFEMergeElementImpl.cc | 33 + ksvg/impl/SVGFEMergeElementImpl.h | 48 + ksvg/impl/SVGFEMergeNodeElementImpl.cc | 43 + ksvg/impl/SVGFEMergeNodeElementImpl.h | 52 + ksvg/impl/SVGFEMorphologyElementImpl.cc | 75 + ksvg/impl/SVGFEMorphologyElementImpl.h | 62 + ksvg/impl/SVGFEOffsetElementImpl.cc | 64 + ksvg/impl/SVGFEOffsetElementImpl.h | 59 + ksvg/impl/SVGFEPointLightElementImpl.cc | 63 + ksvg/impl/SVGFEPointLightElementImpl.h | 56 + ksvg/impl/SVGFESpecularLightingElementImpl.cc | 74 + ksvg/impl/SVGFESpecularLightingElementImpl.h | 61 + ksvg/impl/SVGFESpotLightElementImpl.cc | 113 + ksvg/impl/SVGFESpotLightElementImpl.h | 65 + ksvg/impl/SVGFETileElementImpl.cc | 43 + ksvg/impl/SVGFETileElementImpl.h | 54 + ksvg/impl/SVGFETurbulenceElementImpl.cc | 100 + ksvg/impl/SVGFETurbulenceElementImpl.h | 65 + ksvg/impl/SVGFilterElementImpl.cc | 119 + ksvg/impl/SVGFilterElementImpl.h | 76 + .../SVGFilterPrimitiveStandardAttributesImpl.cc | 84 + .../SVGFilterPrimitiveStandardAttributesImpl.h | 55 + ksvg/impl/SVGFitToViewBoxImpl.cc | 141 + ksvg/impl/SVGFitToViewBoxImpl.h | 69 + ksvg/impl/SVGFontElementImpl.cc | 33 + ksvg/impl/SVGFontElementImpl.h | 49 + ksvg/impl/SVGFontFaceElementImpl.cc | 33 + ksvg/impl/SVGFontFaceElementImpl.h | 46 + ksvg/impl/SVGFontFaceFormatElementImpl.cc | 33 + ksvg/impl/SVGFontFaceFormatElementImpl.h | 46 + ksvg/impl/SVGFontFaceNameElementImpl.cc | 33 + ksvg/impl/SVGFontFaceNameElementImpl.h | 46 + ksvg/impl/SVGFontFaceSrcElementImpl.cc | 33 + ksvg/impl/SVGFontFaceSrcElementImpl.h | 45 + ksvg/impl/SVGFontFaceUriElementImpl.cc | 33 + ksvg/impl/SVGFontFaceUriElementImpl.h | 46 + ksvg/impl/SVGForeignObjectElementImpl.cc | 121 + ksvg/impl/SVGForeignObjectElementImpl.h | 78 + ksvg/impl/SVGGElementImpl.cc | 36 + ksvg/impl/SVGGElementImpl.h | 59 + ksvg/impl/SVGGlyphElementImpl.cc | 98 + ksvg/impl/SVGGlyphElementImpl.h | 66 + ksvg/impl/SVGGlyphRefElementImpl.cc | 134 + ksvg/impl/SVGGlyphRefElementImpl.h | 79 + ksvg/impl/SVGGradientElementImpl.cc | 264 + ksvg/impl/SVGGradientElementImpl.h | 110 + ksvg/impl/SVGHKernElementImpl.cc | 33 + ksvg/impl/SVGHKernElementImpl.h | 46 + ksvg/impl/SVGHelperImpl.cc | 230 + ksvg/impl/SVGHelperImpl.h | 88 + ksvg/impl/SVGICCColorImpl.cc | 107 + ksvg/impl/SVGICCColorImpl.h | 67 + ksvg/impl/SVGImageElementImpl.cc | 522 ++ ksvg/impl/SVGImageElementImpl.h | 140 + ksvg/impl/SVGLangSpaceImpl.cc | 130 + ksvg/impl/SVGLangSpaceImpl.h | 67 + ksvg/impl/SVGLengthImpl.cc | 510 ++ ksvg/impl/SVGLengthImpl.h | 136 + ksvg/impl/SVGLengthListImpl.cc | 64 + ksvg/impl/SVGLengthListImpl.h | 48 + ksvg/impl/SVGLineElementImpl.cc | 213 + ksvg/impl/SVGLineElementImpl.h | 86 + ksvg/impl/SVGLinearGradientElementImpl.cc | 201 + ksvg/impl/SVGLinearGradientElementImpl.h | 74 + ksvg/impl/SVGList.h | 174 + ksvg/impl/SVGLocatableImpl.cc | 208 + ksvg/impl/SVGLocatableImpl.h | 94 + ksvg/impl/SVGMPathElementImpl.cc | 33 + ksvg/impl/SVGMPathElementImpl.h | 50 + ksvg/impl/SVGMarkerElementImpl.cc | 424 + ksvg/impl/SVGMarkerElementImpl.h | 121 + ksvg/impl/SVGMaskElementImpl.cc | 542 ++ ksvg/impl/SVGMaskElementImpl.h | 158 + ksvg/impl/SVGMatrixImpl.cc | 460 + ksvg/impl/SVGMatrixImpl.h | 130 + ksvg/impl/SVGMetadataElementImpl.cc | 33 + ksvg/impl/SVGMetadataElementImpl.h | 46 + ksvg/impl/SVGMissingGlyphElementImpl.cc | 33 + ksvg/impl/SVGMissingGlyphElementImpl.h | 47 + ksvg/impl/SVGNumberImpl.cc | 83 + ksvg/impl/SVGNumberImpl.h | 61 + ksvg/impl/SVGNumberListImpl.cc | 64 + ksvg/impl/SVGNumberListImpl.h | 48 + ksvg/impl/SVGPaintImpl.cc | 175 + ksvg/impl/SVGPaintImpl.h | 85 + ksvg/impl/SVGPaintServerImpl.cc | 55 + ksvg/impl/SVGPaintServerImpl.h | 52 + ksvg/impl/SVGPathElementImpl.cc | 868 ++ ksvg/impl/SVGPathElementImpl.h | 194 + ksvg/impl/SVGPathSegArcImpl.cc | 495 ++ ksvg/impl/SVGPathSegArcImpl.h | 150 + ksvg/impl/SVGPathSegClosePathImpl.cc | 46 + ksvg/impl/SVGPathSegClosePathImpl.h | 61 + ksvg/impl/SVGPathSegCurvetoCubicImpl.cc | 325 + ksvg/impl/SVGPathSegCurvetoCubicImpl.h | 139 + ksvg/impl/SVGPathSegCurvetoCubicSmoothImpl.cc | 298 + ksvg/impl/SVGPathSegCurvetoCubicSmoothImpl.h | 139 + ksvg/impl/SVGPathSegCurvetoQuadraticImpl.cc | 260 + ksvg/impl/SVGPathSegCurvetoQuadraticImpl.h | 123 + ksvg/impl/SVGPathSegCurvetoQuadraticSmoothImpl.cc | 235 + ksvg/impl/SVGPathSegCurvetoQuadraticSmoothImpl.h | 123 + ksvg/impl/SVGPathSegImpl.cc | 107 + ksvg/impl/SVGPathSegImpl.h | 75 + ksvg/impl/SVGPathSegLinetoHorizontalImpl.cc | 167 + ksvg/impl/SVGPathSegLinetoHorizontalImpl.h | 99 + ksvg/impl/SVGPathSegLinetoImpl.cc | 196 + ksvg/impl/SVGPathSegLinetoImpl.h | 107 + ksvg/impl/SVGPathSegLinetoVerticalImpl.cc | 165 + ksvg/impl/SVGPathSegLinetoVerticalImpl.h | 99 + ksvg/impl/SVGPathSegListImpl.cc | 64 + ksvg/impl/SVGPathSegListImpl.h | 48 + ksvg/impl/SVGPathSegMovetoImpl.cc | 196 + ksvg/impl/SVGPathSegMovetoImpl.h | 107 + ksvg/impl/SVGPatternElementImpl.cc | 509 ++ ksvg/impl/SVGPatternElementImpl.h | 136 + ksvg/impl/SVGPointImpl.cc | 108 + ksvg/impl/SVGPointImpl.h | 66 + ksvg/impl/SVGPointListImpl.cc | 64 + ksvg/impl/SVGPointListImpl.h | 48 + ksvg/impl/SVGPolyElementImpl.cc | 141 + ksvg/impl/SVGPolyElementImpl.h | 70 + ksvg/impl/SVGPolygonElementImpl.cc | 88 + ksvg/impl/SVGPolygonElementImpl.h | 54 + ksvg/impl/SVGPolylineElementImpl.cc | 100 + ksvg/impl/SVGPolylineElementImpl.h | 54 + ksvg/impl/SVGPreserveAspectRatioImpl.cc | 217 + ksvg/impl/SVGPreserveAspectRatioImpl.h | 84 + ksvg/impl/SVGRadialGradientElementImpl.cc | 216 + ksvg/impl/SVGRadialGradientElementImpl.h | 76 + ksvg/impl/SVGRectElementImpl.cc | 244 + ksvg/impl/SVGRectElementImpl.h | 90 + ksvg/impl/SVGRectImpl.cc | 157 + ksvg/impl/SVGRectImpl.h | 80 + ksvg/impl/SVGSVGElementImpl.cc | 982 +++ ksvg/impl/SVGSVGElementImpl.h | 198 + ksvg/impl/SVGScriptElementImpl.cc | 185 + ksvg/impl/SVGScriptElementImpl.h | 90 + ksvg/impl/SVGSetElementImpl.cc | 48 + ksvg/impl/SVGSetElementImpl.h | 54 + ksvg/impl/SVGShapeImpl.cc | 162 + ksvg/impl/SVGShapeImpl.h | 73 + ksvg/impl/SVGStopElementImpl.cc | 125 + ksvg/impl/SVGStopElementImpl.h | 70 + ksvg/impl/SVGStringListImpl.cc | 93 + ksvg/impl/SVGStringListImpl.h | 82 + ksvg/impl/SVGStylableImpl.cc | 1309 +++ ksvg/impl/SVGStylableImpl.h | 327 + ksvg/impl/SVGStyleElementImpl.cc | 135 + ksvg/impl/SVGStyleElementImpl.h | 72 + ksvg/impl/SVGSwitchElementImpl.cc | 58 + ksvg/impl/SVGSwitchElementImpl.h | 62 + ksvg/impl/SVGSymbolElementImpl.cc | 106 + ksvg/impl/SVGSymbolElementImpl.h | 76 + ksvg/impl/SVGTRefElementImpl.cc | 76 + ksvg/impl/SVGTRefElementImpl.h | 52 + ksvg/impl/SVGTSpanElementImpl.cc | 64 + ksvg/impl/SVGTSpanElementImpl.h | 55 + ksvg/impl/SVGTestsImpl.cc | 178 + ksvg/impl/SVGTestsImpl.h | 77 + ksvg/impl/SVGTextContentElementImpl.cc | 285 + ksvg/impl/SVGTextContentElementImpl.h | 115 + ksvg/impl/SVGTextElementImpl.cc | 124 + ksvg/impl/SVGTextElementImpl.h | 65 + ksvg/impl/SVGTextPathElementImpl.cc | 240 + ksvg/impl/SVGTextPathElementImpl.h | 84 + ksvg/impl/SVGTextPositioningElementImpl.cc | 198 + ksvg/impl/SVGTextPositioningElementImpl.h | 83 + ksvg/impl/SVGTimeScheduler.cc | 234 + ksvg/impl/SVGTimeScheduler.h | 104 + ksvg/impl/SVGTitleElementImpl.cc | 39 + ksvg/impl/SVGTitleElementImpl.h | 55 + ksvg/impl/SVGTransformImpl.cc | 240 + ksvg/impl/SVGTransformImpl.h | 99 + ksvg/impl/SVGTransformListImpl.cc | 103 + ksvg/impl/SVGTransformListImpl.h | 53 + ksvg/impl/SVGTransformableImpl.cc | 169 + ksvg/impl/SVGTransformableImpl.h | 77 + ksvg/impl/SVGURIReferenceImpl.cc | 135 + ksvg/impl/SVGURIReferenceImpl.h | 64 + ksvg/impl/SVGUnitConverter.h | 100 + ksvg/impl/SVGUseElementImpl.cc | 409 + ksvg/impl/SVGUseElementImpl.h | 101 + ksvg/impl/SVGVKernElementImpl.cc | 33 + ksvg/impl/SVGVKernElementImpl.h | 46 + ksvg/impl/SVGViewElementImpl.cc | 94 + ksvg/impl/SVGViewElementImpl.h | 70 + ksvg/impl/SVGViewSpecImpl.cc | 98 + ksvg/impl/SVGViewSpecImpl.h | 69 + ksvg/impl/SVGWindowImpl.cc | 187 + ksvg/impl/SVGWindowImpl.h | 73 + ksvg/impl/SVGZoomAndPanImpl.cc | 112 + ksvg/impl/SVGZoomAndPanImpl.h | 76 + ksvg/impl/SVGZoomEventImpl.cc | 111 + ksvg/impl/SVGZoomEventImpl.h | 77 + ksvg/impl/TODO | 5 + ksvg/impl/generateddata.cpp | 8899 ++++++++++++++++++++ ksvg/impl/libs/Makefile.am | 1 + ksvg/impl/libs/art_support/Makefile.am | 4 + ksvg/impl/libs/art_support/art_misc.c | 1841 ++++ ksvg/impl/libs/art_support/art_misc.h | 79 + ksvg/impl/libs/art_support/art_render_misc.c | 774 ++ ksvg/impl/libs/art_support/art_render_misc.h | 90 + ksvg/impl/libs/art_support/art_rgba_svp.c | 659 ++ ksvg/impl/libs/art_support/art_rgba_svp.h | 57 + ksvg/impl/libs/libtext2path/AUTHORS | 1 + ksvg/impl/libs/libtext2path/COPYING | 339 + ksvg/impl/libs/libtext2path/ChangeLog | 2 + ksvg/impl/libs/libtext2path/INSTALL | 181 + ksvg/impl/libs/libtext2path/Makefile.am | 7 + ksvg/impl/libs/libtext2path/NEWS | 1 + ksvg/impl/libs/libtext2path/README | 4 + ksvg/impl/libs/libtext2path/VERSION | 1 + ksvg/impl/libs/libtext2path/configure.in.in | 41 + ksvg/impl/libs/libtext2path/libtext2path.lsm | 16 + ksvg/impl/libs/libtext2path/libtext2path.pc.in | 11 + ksvg/impl/libs/libtext2path/libtext2path.spec | 41 + ksvg/impl/libs/libtext2path/src/Affine.cpp | 174 + ksvg/impl/libs/libtext2path/src/Affine.h | 67 + ksvg/impl/libs/libtext2path/src/BezierPath.h | 56 + ksvg/impl/libs/libtext2path/src/Cache.h | 156 + ksvg/impl/libs/libtext2path/src/Converter.cpp | 505 ++ ksvg/impl/libs/libtext2path/src/Converter.h | 94 + ksvg/impl/libs/libtext2path/src/Font.cpp | 252 + ksvg/impl/libs/libtext2path/src/Font.h | 91 + ksvg/impl/libs/libtext2path/src/Glyph.cpp | 353 + ksvg/impl/libs/libtext2path/src/Glyph.h | 198 + ksvg/impl/libs/libtext2path/src/GlyphTracer.cpp | 76 + ksvg/impl/libs/libtext2path/src/GlyphTracer.h | 65 + ksvg/impl/libs/libtext2path/src/Makefile.am | 10 + ksvg/impl/libs/libtext2path/src/Point.h | 65 + ksvg/impl/libs/libtext2path/src/QtUnicode.cpp | 164 + ksvg/impl/libs/libtext2path/src/QtUnicode.h | 149 + ksvg/impl/libs/libtext2path/src/Rectangle.cpp | 102 + ksvg/impl/libs/libtext2path/src/Rectangle.h | 55 + ksvg/impl/libs/libtext2path/src/Tools.h | 85 + ksvg/impl/libs/libtext2path/src/myboost/assert.hpp | 24 + .../libtext2path/src/myboost/checked_delete.hpp | 61 + .../libtext2path/src/myboost/lightweight_mutex.hpp | 74 + .../libs/libtext2path/src/myboost/shared_count.hpp | 367 + .../libs/libtext2path/src/myboost/shared_ptr.hpp | 395 + .../libtext2path/src/myboost/throw_exception.hpp | 30 + ksvg/impl/libs/xrgbrender/Makefile.am | 5 + .../libs/xrgbrender/gdk-pixbuf-xlib-drawable.c | 1137 +++ .../impl/libs/xrgbrender/gdk-pixbuf-xlib-private.h | 30 + ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib.c | 46 + ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib.h | 78 + ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlibrgb.c | 3425 ++++++++ ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlibrgb.h | 145 + ksvg/impl/svgpathparser.cc | 564 ++ ksvg/impl/svgpathparser.h | 63 + ksvg/plugin/Makefile.am | 29 + ksvg/plugin/backends/Makefile.am | 1 + ksvg/plugin/backends/agg/AggCanvas.cpp | 130 + ksvg/plugin/backends/agg/AggCanvas.h | 77 + ksvg/plugin/backends/agg/AggCanvasFactory.cpp | 45 + ksvg/plugin/backends/agg/AggCanvasFactory.h | 45 + ksvg/plugin/backends/agg/AggCanvasItems.cpp | 1747 ++++ ksvg/plugin/backends/agg/AggCanvasItems.h | 500 ++ ksvg/plugin/backends/agg/BezierPathAgg.cpp | 126 + ksvg/plugin/backends/agg/BezierPathAgg.h | 83 + ksvg/plugin/backends/agg/GlyphTracerAgg.cpp | 113 + ksvg/plugin/backends/agg/GlyphTracerAgg.h | 49 + ksvg/plugin/backends/agg/Makefile.am | 15 + ksvg/plugin/backends/agg/ksvgaggcanvas.desktop | 101 + ksvg/plugin/backends/libart/BezierPathLibart.cpp | 160 + ksvg/plugin/backends/libart/BezierPathLibart.h | 52 + ksvg/plugin/backends/libart/GlyphTracerLibart.cpp | 177 + ksvg/plugin/backends/libart/GlyphTracerLibart.h | 50 + ksvg/plugin/backends/libart/LibartCanvas.cpp | 425 + ksvg/plugin/backends/libart/LibartCanvas.h | 84 + .../plugin/backends/libart/LibartCanvasFactory.cpp | 45 + ksvg/plugin/backends/libart/LibartCanvasFactory.h | 45 + ksvg/plugin/backends/libart/LibartCanvasItems.cpp | 2209 +++++ ksvg/plugin/backends/libart/LibartCanvasItems.h | 414 + ksvg/plugin/backends/libart/Makefile.am | 11 + .../backends/libart/ksvglibartcanvas.desktop | 101 + ksvg/plugin/ksvg_factory.cpp | 100 + ksvg/plugin/ksvg_factory.h | 58 + ksvg/plugin/ksvg_plugin.cpp | 417 + ksvg/plugin/ksvg_plugin.h | 87 + ksvg/plugin/ksvg_widget.cpp | 267 + ksvg/plugin/ksvg_widget.h | 68 + ksvg/plugin/ksvgplugin.desktop | 85 + ksvg/plugin/ksvgplugin.rc | 35 + ksvg/plugin/svgcreator.cpp | 92 + ksvg/plugin/svgcreator.h | 45 + ksvg/plugin/svgthumbnail.desktop | 52 + ksvg/scripts/COPYRIGHTS | 19 + ksvg/scripts/ECMACHECK | 25 + ksvg/scripts/OPENREF | 9 + ksvg/scripts/README | 16 + ksvg/scripts/add_static.pl | 42 + ksvg/scripts/check_hashtablesize.pl | 224 + ksvg/scripts/gen.sh | 51 + ksvg/scripts/generate.pl | 69 + ksvg/scripts/genimpl.sh | 49 + ksvg/scripts/getjs.php | 390 + ksvg/scripts/idl/svg.idl | 1756 ++++ ksvg/scripts/makecc | 211 + ksvg/scripts/makeheader | 164 + ksvg/scripts/makeimpl | 440 + ksvg/test/Makefile.am | 1 + ksvg/test/Units.svg | 43 + ksvg/test/W3C_TESTSUITE_1.1 | 227 + ksvg/test/ZVON-TEST-PASSED | 168 + ksvg/test/amflag.svg | 54 + ksvg/test/animskew.svg | 44 + ksvg/test/arabic.svg | 10 + ksvg/test/butterfly.svg | 11 + ksvg/test/chem1.svg | 189 + ksvg/test/colortest.svg | 18 + ksvg/test/dashes.svg | 32 + ksvg/test/ecma/bbox/bbox-circle.svg | 13 + ksvg/test/ecma/bbox/bbox-ellipse.svg | 14 + ksvg/test/ecma/bbox/bbox-line.svg | 35 + ksvg/test/ecma/bbox/bbox-path.svg | 15 + ksvg/test/ecma/bbox/bbox-path2.svg | 14 + ksvg/test/ecma/bbox/bbox-polygon.svg | 13 + ksvg/test/ecma/bbox/bbox-polyline.svg | 13 + ksvg/test/ecma/bbox/bbox-rect.svg | 15 + ksvg/test/ecma/bbox/bbox.js | 103 + ksvg/test/ecma/broken.svg | 30 + ksvg/test/ecma/circle.svg | 38 + ksvg/test/ecma/clock.svg | 66 + ksvg/test/ecma/dom01.svg | 40 + ksvg/test/external/Makefile.am | 13 + ksvg/test/external/SVGTestWidget.cc | 206 + ksvg/test/external/SVGTestWidget.h | 37 + ksvg/test/external/printnodetest.cpp | 63 + ksvg/test/external/printnodetest.h | 32 + ksvg/test/external/svgdisplay.cc | 32 + ksvg/test/fonttest.svg | 126 + ksvg/test/keytest.svg | 25 + ksvg/test/lion.svg | 160 + ksvg/test/opacity.svg | 41 + ksvg/test/physics-motor.svg | 43 + ksvg/test/poly.svg | 12 + ksvg/test/shapes-rect-trans.svg | 92 + ksvg/test/tiger.svg | 722 ++ ksvg/test/tiger2.svg | 725 ++ ksvg/test/tigert.svg | 388 + ksvg/test/tux.svg | 298 + ksvg/test/tux2.svg | 287 + ksvg/test/xlink.svg | 13 + kuickshow/AUTHORS | 1 + kuickshow/BUGS | 3 + kuickshow/COPYING | 339 + kuickshow/ChangeLog | 921 ++ kuickshow/Makefile.am | 8 + kuickshow/README | 8 + kuickshow/TODO | 24 + kuickshow/configure.in.bot | 9 + kuickshow/configure.in.in | 69 + kuickshow/kuickshow.lsm | 18 + kuickshow/kuickshow.spec | 69 + kuickshow/misc/Makefile.am | 2 + kuickshow/misc/im_palette.pal | 64 + kuickshow/pics/Makefile.am | 7 + kuickshow/pics/about.png | Bin 0 -> 257 bytes kuickshow/pics/arrows.png | Bin 0 -> 264 bytes kuickshow/pics/calibrate.png | Bin 0 -> 9161 bytes kuickshow/pics/handcursor.png | Bin 0 -> 359 bytes kuickshow/pics/imageviewer-medium.png | Bin 0 -> 1696 bytes kuickshow/pics/imageviewer-small.png | Bin 0 -> 618 bytes kuickshow/pics/ksslide.png | Bin 0 -> 246 bytes kuickshow/pics/kuickshow-day.jpg | Bin 0 -> 48857 bytes kuickshow/pics/kuickshow-night.jpg | Bin 0 -> 36800 bytes kuickshow/pics/logo.png | Bin 0 -> 2904 bytes kuickshow/src/Makefile.am | 31 + kuickshow/src/aboutwidget.cpp | 95 + kuickshow/src/aboutwidget.h | 43 + kuickshow/src/defaultswidget.cpp | 282 + kuickshow/src/defaultswidget.h | 73 + kuickshow/src/filecache.cpp | 83 + kuickshow/src/filecache.h | 47 + kuickshow/src/filefinder.cpp | 99 + kuickshow/src/filefinder.h | 54 + kuickshow/src/filewidget.cpp | 464 + kuickshow/src/filewidget.h | 98 + kuickshow/src/generalwidget.cpp | 163 + kuickshow/src/generalwidget.h | 62 + kuickshow/src/hi16-app-kuickshow.png | Bin 0 -> 396 bytes kuickshow/src/hi22-app-kuickshow.png | Bin 0 -> 1423 bytes kuickshow/src/hi32-app-kuickshow.png | Bin 0 -> 954 bytes kuickshow/src/imagewindow.cpp | 1251 +++ kuickshow/src/imagewindow.h | 176 + kuickshow/src/imdata.cpp | 92 + kuickshow/src/imdata.h | 57 + kuickshow/src/imlibwidget.cpp | 715 ++ kuickshow/src/imlibwidget.h | 187 + kuickshow/src/kuick.cpp | 4 + kuickshow/src/kuick.h | 70 + kuickshow/src/kuickconfigdlg.cpp | 99 + kuickshow/src/kuickconfigdlg.h | 58 + kuickshow/src/kuickdata.cpp | 177 + kuickshow/src/kuickdata.h | 86 + kuickshow/src/kuickfile.cpp | 194 + kuickshow/src/kuickfile.h | 99 + kuickshow/src/kuickglobals.h | 33 + kuickshow/src/kuickimage.cpp | 527 ++ kuickshow/src/kuickimage.h | 92 + kuickshow/src/kuickshow.cpp | 1443 ++++ kuickshow/src/kuickshow.desktop | 93 + kuickshow/src/kuickshow.h | 178 + kuickshow/src/kurlwidget.cpp | 42 + kuickshow/src/kurlwidget.h | 36 + kuickshow/src/main.cpp | 66 + kuickshow/src/mainwidget.cpp | 43 + kuickshow/src/mainwidget.h | 47 + kuickshow/src/printing.cpp | 338 + kuickshow/src/printing.h | 85 + kuickshow/src/slideshowwidget.cpp | 80 + kuickshow/src/slideshowwidget.h | 44 + kuickshow/src/version.h | 3 + kview/AUTHORS | 4 + kview/ChangeLog | 98 + kview/Makefile.am | 25 + kview/TODO | 73 + kview/config/Makefile.am | 21 + kview/config/kview.setdlg | 219 + kview/config/kviewconfmodules.cpp | 90 + kview/config/kviewconfmodules.h | 47 + kview/config/kviewgeneralconfig.desktop | 131 + kview/config/plugins/Makefile.am | 17 + kview/config/plugins/kviewpluginsconfig.cpp | 46 + kview/config/plugins/kviewpluginsconfig.desktop | 118 + kview/config/plugins/kviewpluginsconfig.h | 38 + kview/hi16-app-kview.png | Bin 0 -> 943 bytes kview/hi22-app-kview.png | Bin 0 -> 1506 bytes kview/hi32-app-kview.png | Bin 0 -> 2592 bytes kview/hi48-app-kview.png | Bin 0 -> 4918 bytes kview/kimageviewer/Makefile.am | 18 + kview/kimageviewer/canvas.cpp | 35 + kview/kimageviewer/canvas.h | 348 + kview/kimageviewer/kimageviewer.desktop | 63 + kview/kimageviewer/kimageviewercanvas.desktop | 60 + kview/kimageviewer/viewer.cpp | 36 + kview/kimageviewer/viewer.h | 99 + kview/kview.cpp | 698 ++ kview/kview.desktop | 95 + kview/kview.h | 124 + kview/kviewcanvas/ChangeLog | 18 + kview/kviewcanvas/Makefile.am | 18 + kview/kviewcanvas/config/Makefile.am | 16 + kview/kviewcanvas/config/confmodules.cpp | 145 + kview/kviewcanvas/config/confmodules.h | 51 + kview/kviewcanvas/config/defaults.h | 46 + kview/kviewcanvas/config/generalconfigwidget.ui | 300 + kview/kviewcanvas/config/kviewcanvasconfig.desktop | 118 + kview/kviewcanvas/kimagecanvas.cpp | 953 +++ kview/kviewcanvas/kimagecanvas.h | 366 + kview/kviewcanvas/kimageholder.cpp | 371 + kview/kviewcanvas/kimageholder.h | 105 + kview/kviewcanvas/kviewcanvas.desktop | 63 + kview/kviewcanvas/test/Makefile.am | 9 + kview/kviewcanvas/test/main.cpp | 51 + kview/kviewcanvas/test/test.cpp | 46 + kview/kviewcanvas/test/test.h | 25 + kview/kviewui.rc | 50 + kview/kviewviewer/ChangeLog | 68 + kview/kviewviewer/Makefile.am | 21 + kview/kviewviewer/config/Makefile.am | 17 + .../config/kviewviewerpluginsconfig.cpp | 48 + .../config/kviewviewerpluginsconfig.desktop | 118 + .../kviewviewer/config/kviewviewerpluginsconfig.h | 38 + kview/kviewviewer/imagesettings.cpp | 73 + kview/kviewviewer/imagesettings.h | 45 + kview/kviewviewer/kviewkonqextension.cpp | 105 + kview/kviewviewer/kviewkonqextension.h | 52 + kview/kviewviewer/kviewpopup.rc | 7 + kview/kviewviewer/kviewviewer.cpp | 883 ++ kview/kviewviewer/kviewviewer.desktop | 118 + kview/kviewviewer/kviewviewer.h | 145 + kview/kviewviewer/kviewviewer.rc | 36 + kview/kviewviewer/kviewviewer_ro.rc | 34 + kview/kviewviewer/kviewvieweriface.h | 30 + kview/kviewviewer/printimagesettings.ui | 190 + kview/kviewviewer/test/Makefile.am | 9 + kview/kviewviewer/test/main.cpp | 51 + kview/kviewviewer/test/test.cpp | 43 + kview/kviewviewer/test/test.h | 25 + kview/main.cpp | 70 + kview/modules/Makefile.am | 1 + kview/modules/NAMING | 4 + kview/modules/README | 52 + kview/modules/browser/Makefile.am | 15 + kview/modules/browser/kmyfileitemlist.cpp | 41 + kview/modules/browser/kmyfileitemlist.h | 39 + kview/modules/browser/kviewbrowser.cpp | 179 + kview/modules/browser/kviewbrowser.desktop | 130 + kview/modules/browser/kviewbrowser.h | 62 + kview/modules/browser/kviewbrowser.rc | 18 + kview/modules/effects/Makefile.am | 15 + kview/modules/effects/kvieweffects.cpp | 244 + kview/modules/effects/kvieweffects.desktop | 119 + kview/modules/effects/kvieweffects.h | 46 + kview/modules/effects/kvieweffects.rc | 10 + kview/modules/presenter/DESIGN | 42 + kview/modules/presenter/Makefile.am | 17 + kview/modules/presenter/config/Makefile.am | 17 + .../presenter/config/kviewpresenterconfig.cpp | 72 + .../presenter/config/kviewpresenterconfig.desktop | 120 + .../presenter/config/kviewpresenterconfig.h | 46 + kview/modules/presenter/imagelistdialog.ui | 289 + kview/modules/presenter/imagelistdialog.ui.h | 23 + kview/modules/presenter/imagelistitem.cpp | 82 + kview/modules/presenter/imagelistitem.h | 49 + kview/modules/presenter/kviewpresenter.cpp | 492 ++ kview/modules/presenter/kviewpresenter.desktop | 118 + kview/modules/presenter/kviewpresenter.h | 103 + kview/modules/presenter/kviewpresenter.rc | 20 + .../modules/presenter/kviewpresenterconfmodule.cpp | 60 + kview/modules/presenter/kviewpresenterconfmodule.h | 49 + kview/modules/scale/Makefile.am | 15 + kview/modules/scale/kfloatspinbox.cpp | 116 + kview/modules/scale/kfloatspinbox.h | 64 + kview/modules/scale/kview_scale.cpp | 180 + kview/modules/scale/kview_scale.desktop | 127 + kview/modules/scale/kview_scale.h | 48 + kview/modules/scale/kview_scale.rc | 14 + kview/modules/scale/scaledlg.cpp | 311 + kview/modules/scale/scaledlg.h | 78 + kview/modules/scanner/Makefile.am | 15 + kview/modules/scanner/kviewscanner.cpp | 96 + kview/modules/scanner/kviewscanner.desktop | 127 + kview/modules/scanner/kviewscanner.h | 50 + kview/modules/scanner/kviewscanner.rc | 12 + kview/modules/template/Makefile.am | 15 + kview/modules/template/kviewtemplate.cpp | 43 + kview/modules/template/kviewtemplate.desktop | 129 + kview/modules/template/kviewtemplate.h | 27 + kview/modules/template/kviewtemplate.rc | 11 + kview/photobook/Makefile.am | 19 + kview/photobook/cr16-app-photobook.png | Bin 0 -> 720 bytes kview/photobook/cr22-app-photobook.png | Bin 0 -> 922 bytes kview/photobook/photobook.cpp | 292 + kview/photobook/photobook.desktop | 131 + kview/photobook/photobook.h | 140 + kview/photobook/photobookui.rc | 14 + kview/version.h | 3 + kviewshell/DESIGN | 7 + kviewshell/Mainpage.dox | 92 + kviewshell/Makefile.am | 67 + kviewshell/TODO | 94 + kviewshell/anchor.h | 61 + kviewshell/bookmark.h | 107 + kviewshell/documentPageCache.cpp | 337 + kviewshell/documentPageCache.h | 143 + kviewshell/documentRenderer.cpp | 133 + kviewshell/documentRenderer.h | 478 ++ kviewshell/documentWidget.cpp | 764 ++ kviewshell/documentWidget.h | 193 + kviewshell/emptyRenderer.cpp | 29 + kviewshell/emptyRenderer.h | 41 + kviewshell/empty_multipage.cpp | 48 + kviewshell/empty_multipage.h | 51 + kviewshell/emptymultipage.desktop | 29 + kviewshell/history.cpp | 91 + kviewshell/history.h | 58 + kviewshell/hyperlink.h | 78 + kviewshell/kmultipage.cpp | 1976 +++++ kviewshell/kmultipage.desktop | 41 + kviewshell/kmultipage.h | 650 ++ kviewshell/kmultipageInterface.h | 18 + kviewshell/kprintDialogPage_pageoptions.cpp | 166 + kviewshell/kprintDialogPage_pageoptions.h | 43 + kviewshell/kviewerpart.rc | 91 + kviewshell/kviewpart.cpp | 1632 ++++ kviewshell/kviewpart.h | 252 + kviewshell/kviewpart_iface.cpp | 4 + kviewshell/kviewpart_iface.h | 35 + kviewshell/kviewshell.cpp | 384 + kviewshell/kviewshell.h | 89 + kviewshell/kviewshell.kcfg | 115 + kviewshell/kviewshell.rc | 37 + kviewshell/kvsprefs.kcfgc | 5 + kviewshell/length.h | 173 + kviewshell/main.cpp | 184 + kviewshell/marklist.cpp | 616 ++ kviewshell/marklist.h | 186 + kviewshell/optionDialogAccessibilityWidget.ui | 528 ++ kviewshell/optionDialogGUIWidget_base.ui | 148 + kviewshell/pageNumber.h | 65 + kviewshell/pageSize.cpp | 343 + kviewshell/pageSize.h | 280 + kviewshell/pageSizeDialog.cpp | 63 + kviewshell/pageSizeDialog.h | 52 + kviewshell/pageSizeWidget.cpp | 148 + kviewshell/pageSizeWidget.h | 52 + kviewshell/pageSizeWidget_base.ui | 260 + kviewshell/pageView.cpp | 593 ++ kviewshell/pageView.h | 175 + kviewshell/pics/Makefile.am | 3 + kviewshell/pics/cr16-app-kviewshell.png | Bin 0 -> 945 bytes kviewshell/pics/cr32-app-kviewshell.png | Bin 0 -> 2224 bytes kviewshell/pics/cr48-app-kviewshell.png | Bin 0 -> 3949 bytes kviewshell/pics/icons/Makefile.am | 3 + kviewshell/pics/icons/hi16-action-movetool.png | Bin 0 -> 433 bytes .../pics/icons/hi16-action-selectiontool.png | Bin 0 -> 483 bytes kviewshell/pics/icons/hi22-action-movetool.png | Bin 0 -> 826 bytes .../pics/icons/hi22-action-selectiontool.png | Bin 0 -> 404 bytes kviewshell/pics/icons/hi32-action-movetool.png | Bin 0 -> 1554 bytes kviewshell/pics/icons/hi48-action-movetool.png | Bin 0 -> 2874 bytes kviewshell/plugins/Makefile.am | 1 + kviewshell/plugins/djvu/Makefile.am | 33 + kviewshell/plugins/djvu/djvumultipage.cpp | 357 + kviewshell/plugins/djvu/djvumultipage.desktop | 57 + kviewshell/plugins/djvu/djvumultipage.h | 149 + kviewshell/plugins/djvu/djvumultipage.kcfg | 18 + kviewshell/plugins/djvu/djvumultipage.rc | 15 + kviewshell/plugins/djvu/djvurenderer.cpp | 719 ++ kviewshell/plugins/djvu/djvurenderer.h | 146 + .../kprintDialogPage_DJVUconversionoptions.cpp | 118 + .../djvu/kprintDialogPage_DJVUconversionoptions.h | 50 + ...tDialogPage_DJVUconversionoptions_basewidget.ui | 145 + .../djvu/kprintDialogPage_DJVUpageoptions.cpp | 119 + .../djvu/kprintDialogPage_DJVUpageoptions.h | 42 + kviewshell/plugins/djvu/libdjvu/Arrays.cpp | 305 + kviewshell/plugins/djvu/libdjvu/Arrays.h | 997 +++ kviewshell/plugins/djvu/libdjvu/BSByteStream.cpp | 465 + kviewshell/plugins/djvu/libdjvu/BSByteStream.h | 275 + .../plugins/djvu/libdjvu/BSEncodeByteStream.cpp | 1010 +++ kviewshell/plugins/djvu/libdjvu/ByteStream.cpp | 1445 ++++ kviewshell/plugins/djvu/libdjvu/ByteStream.h | 416 + kviewshell/plugins/djvu/libdjvu/DataPool.cpp | 1837 ++++ kviewshell/plugins/djvu/libdjvu/DataPool.h | 627 ++ kviewshell/plugins/djvu/libdjvu/DjVmDir.cpp | 839 ++ kviewshell/plugins/djvu/libdjvu/DjVmDir.h | 451 + kviewshell/plugins/djvu/libdjvu/DjVmDir0.cpp | 169 + kviewshell/plugins/djvu/libdjvu/DjVmDir0.h | 217 + kviewshell/plugins/djvu/libdjvu/DjVmDoc.cpp | 663 ++ kviewshell/plugins/djvu/libdjvu/DjVmDoc.h | 274 + kviewshell/plugins/djvu/libdjvu/DjVmNav.cpp | 338 + kviewshell/plugins/djvu/libdjvu/DjVmNav.h | 146 + kviewshell/plugins/djvu/libdjvu/DjVuAnno.cpp | 1514 ++++ kviewshell/plugins/djvu/libdjvu/DjVuAnno.h | 295 + kviewshell/plugins/djvu/libdjvu/DjVuDocEditor.cpp | 2193 +++++ kviewshell/plugins/djvu/libdjvu/DjVuDocEditor.h | 460 + kviewshell/plugins/djvu/libdjvu/DjVuDocument.cpp | 1845 ++++ kviewshell/plugins/djvu/libdjvu/DjVuDocument.h | 1071 +++ kviewshell/plugins/djvu/libdjvu/DjVuDumpHelper.cpp | 353 + kviewshell/plugins/djvu/libdjvu/DjVuDumpHelper.h | 126 + kviewshell/plugins/djvu/libdjvu/DjVuErrorList.cpp | 174 + kviewshell/plugins/djvu/libdjvu/DjVuErrorList.h | 194 + kviewshell/plugins/djvu/libdjvu/DjVuFile.cpp | 2831 +++++++ kviewshell/plugins/djvu/libdjvu/DjVuFile.h | 848 ++ kviewshell/plugins/djvu/libdjvu/DjVuFileCache.cpp | 272 + kviewshell/plugins/djvu/libdjvu/DjVuFileCache.h | 292 + kviewshell/plugins/djvu/libdjvu/DjVuGlobal.cpp | 255 + kviewshell/plugins/djvu/libdjvu/DjVuGlobal.h | 398 + .../plugins/djvu/libdjvu/DjVuGlobalMemory.cpp | 306 + kviewshell/plugins/djvu/libdjvu/DjVuImage.cpp | 1486 ++++ kviewshell/plugins/djvu/libdjvu/DjVuImage.h | 449 + kviewshell/plugins/djvu/libdjvu/DjVuInfo.cpp | 205 + kviewshell/plugins/djvu/libdjvu/DjVuInfo.h | 193 + kviewshell/plugins/djvu/libdjvu/DjVuMessage.cpp | 647 ++ kviewshell/plugins/djvu/libdjvu/DjVuMessage.h | 135 + .../plugins/djvu/libdjvu/DjVuMessageLite.cpp | 478 ++ kviewshell/plugins/djvu/libdjvu/DjVuMessageLite.h | 227 + kviewshell/plugins/djvu/libdjvu/DjVuNavDir.cpp | 237 + kviewshell/plugins/djvu/libdjvu/DjVuNavDir.h | 192 + kviewshell/plugins/djvu/libdjvu/DjVuPalette.cpp | 590 ++ kviewshell/plugins/djvu/libdjvu/DjVuPalette.h | 339 + kviewshell/plugins/djvu/libdjvu/DjVuPort.cpp | 710 ++ kviewshell/plugins/djvu/libdjvu/DjVuPort.h | 518 ++ kviewshell/plugins/djvu/libdjvu/DjVuText.cpp | 971 +++ kviewshell/plugins/djvu/libdjvu/DjVuText.h | 281 + kviewshell/plugins/djvu/libdjvu/DjVuToPS.cpp | 2582 ++++++ kviewshell/plugins/djvu/libdjvu/DjVuToPS.h | 425 + kviewshell/plugins/djvu/libdjvu/GBitmap.cpp | 1658 ++++ kviewshell/plugins/djvu/libdjvu/GBitmap.h | 673 ++ kviewshell/plugins/djvu/libdjvu/GContainer.cpp | 802 ++ kviewshell/plugins/djvu/libdjvu/GContainer.h | 1366 +++ kviewshell/plugins/djvu/libdjvu/GException.cpp | 284 + kviewshell/plugins/djvu/libdjvu/GException.h | 356 + kviewshell/plugins/djvu/libdjvu/GIFFManager.cpp | 663 ++ kviewshell/plugins/djvu/libdjvu/GIFFManager.h | 394 + kviewshell/plugins/djvu/libdjvu/GMapAreas.cpp | 1066 +++ kviewshell/plugins/djvu/libdjvu/GMapAreas.h | 565 ++ kviewshell/plugins/djvu/libdjvu/GOS.cpp | 370 + kviewshell/plugins/djvu/libdjvu/GOS.h | 161 + kviewshell/plugins/djvu/libdjvu/GPixmap.cpp | 1676 ++++ kviewshell/plugins/djvu/libdjvu/GPixmap.h | 531 ++ kviewshell/plugins/djvu/libdjvu/GRect.cpp | 458 + kviewshell/plugins/djvu/libdjvu/GRect.h | 407 + kviewshell/plugins/djvu/libdjvu/GScaler.cpp | 706 ++ kviewshell/plugins/djvu/libdjvu/GScaler.h | 321 + kviewshell/plugins/djvu/libdjvu/GSmartPointer.cpp | 256 + kviewshell/plugins/djvu/libdjvu/GSmartPointer.h | 489 ++ kviewshell/plugins/djvu/libdjvu/GString.cpp | 2811 +++++++ kviewshell/plugins/djvu/libdjvu/GString.h | 1676 ++++ kviewshell/plugins/djvu/libdjvu/GThreads.cpp | 1887 +++++ kviewshell/plugins/djvu/libdjvu/GThreads.h | 639 ++ kviewshell/plugins/djvu/libdjvu/GURL.cpp | 1965 +++++ kviewshell/plugins/djvu/libdjvu/GURL.h | 446 + kviewshell/plugins/djvu/libdjvu/GUnicode.cpp | 790 ++ kviewshell/plugins/djvu/libdjvu/IFFByteStream.cpp | 558 ++ kviewshell/plugins/djvu/libdjvu/IFFByteStream.h | 312 + .../plugins/djvu/libdjvu/IW44EncodeCodec.cpp | 1797 ++++ kviewshell/plugins/djvu/libdjvu/IW44Image.cpp | 1935 +++++ kviewshell/plugins/djvu/libdjvu/IW44Image.h | 761 ++ kviewshell/plugins/djvu/libdjvu/JB2EncodeCodec.cpp | 564 ++ kviewshell/plugins/djvu/libdjvu/JB2Image.cpp | 1427 ++++ kviewshell/plugins/djvu/libdjvu/JB2Image.h | 805 ++ kviewshell/plugins/djvu/libdjvu/JPEGDecoder.cpp | 413 + kviewshell/plugins/djvu/libdjvu/JPEGDecoder.h | 133 + kviewshell/plugins/djvu/libdjvu/MMRDecoder.cpp | 961 +++ kviewshell/plugins/djvu/libdjvu/MMRDecoder.h | 238 + kviewshell/plugins/djvu/libdjvu/MMX.cpp | 209 + kviewshell/plugins/djvu/libdjvu/MMX.h | 194 + kviewshell/plugins/djvu/libdjvu/Makefile.am | 18 + kviewshell/plugins/djvu/libdjvu/README.djvulibre | 85 + kviewshell/plugins/djvu/libdjvu/Template.h | 258 + .../plugins/djvu/libdjvu/UnicodeByteStream.cpp | 368 + .../plugins/djvu/libdjvu/UnicodeByteStream.h | 199 + kviewshell/plugins/djvu/libdjvu/XMLParser.cpp | 1128 +++ kviewshell/plugins/djvu/libdjvu/XMLParser.h | 123 + kviewshell/plugins/djvu/libdjvu/XMLTags.cpp | 417 + kviewshell/plugins/djvu/libdjvu/XMLTags.h | 242 + kviewshell/plugins/djvu/libdjvu/ZPCodec.cpp | 1292 +++ kviewshell/plugins/djvu/libdjvu/ZPCodec.h | 747 ++ kviewshell/plugins/djvu/libdjvu/configure.in.in | 674 ++ kviewshell/plugins/djvu/libdjvu/debug.cpp | 299 + kviewshell/plugins/djvu/libdjvu/debug.h | 304 + kviewshell/plugins/djvu/pageRangeWidget.cpp | 68 + kviewshell/plugins/djvu/pageRangeWidget.h | 45 + kviewshell/plugins/djvu/pageRangeWidget_base.ui | 75 + kviewshell/plugins/djvu/prefs.kcfgc | 5 + kviewshell/renderedDocumentPage.cpp | 375 + kviewshell/renderedDocumentPage.h | 241 + kviewshell/renderedDocumentPagePixmap.cpp | 122 + kviewshell/renderedDocumentPagePixmap.h | 59 + kviewshell/renderedDocumentPagePrinter.cpp | 53 + kviewshell/renderedDocumentPagePrinter.h | 46 + kviewshell/searchWidget.cpp | 141 + kviewshell/searchWidget.h | 73 + kviewshell/selection.cpp | 66 + kviewshell/selection.h | 86 + kviewshell/simplePageSize.cpp | 49 + kviewshell/simplePageSize.h | 164 + kviewshell/sizePreview.cpp | 134 + kviewshell/sizePreview.h | 47 + kviewshell/tableOfContents.cpp | 119 + kviewshell/tableOfContents.h | 69 + kviewshell/textBox.h | 65 + kviewshell/units.cpp | 83 + kviewshell/units.h | 34 + kviewshell/zoom.cpp | 156 + kviewshell/zoom.h | 55 + kviewshell/zoomlimits.h | 19 + libkscan/AUTHORS | 2 + libkscan/COPYING.LIB | 486 ++ libkscan/INSTALL | 167 + libkscan/Makefile.am | 32 + libkscan/README | 12 + libkscan/TODO | 59 + libkscan/configure.in.bot | 9 + libkscan/configure.in.in | 22 + libkscan/devselector.cpp | 183 + libkscan/devselector.h | 104 + libkscan/dispgamma.cpp | 85 + libkscan/dispgamma.h | 62 + libkscan/gammadialog.cpp | 114 + libkscan/gammadialog.h | 75 + libkscan/img_canvas.cpp | 1115 +++ libkscan/img_canvas.h | 221 + libkscan/imgscaledialog.cpp | 178 + libkscan/imgscaledialog.h | 62 + libkscan/imgscaninfo.cpp | 75 + libkscan/imgscaninfo.h | 52 + libkscan/kgammatable.cpp | 93 + libkscan/kgammatable.h | 71 + libkscan/kscandevice.cpp | 1541 ++++ libkscan/kscandevice.h | 459 + libkscan/kscandoc.h | 116 + libkscan/kscanoption.cpp | 1221 +++ libkscan/kscanoption.h | 260 + libkscan/kscanoptset.cpp | 221 + libkscan/kscanoptset.h | 113 + libkscan/kscanslider.cpp | 319 + libkscan/kscanslider.h | 244 + libkscan/massscandialog.cpp | 123 + libkscan/massscandialog.h | 67 + libkscan/pics/Makefile.am | 1 + libkscan/pics/cr16-action-palette_color.png | Bin 0 -> 227 bytes libkscan/pics/cr16-action-palette_gray.png | Bin 0 -> 176 bytes libkscan/pics/cr16-action-palette_halftone.png | Bin 0 -> 131 bytes libkscan/pics/cr16-action-palette_lineart.png | Bin 0 -> 131 bytes libkscan/previewer.cpp | 871 ++ libkscan/previewer.h | 120 + libkscan/scandialog.cpp | 380 + libkscan/scandialog.h | 83 + libkscan/scanparams.cpp | 1140 +++ libkscan/scanparams.h | 182 + libkscan/scanservice.desktop | 70 + libkscan/scansourcedialog.cpp | 211 + libkscan/scansourcedialog.h | 69 + libkscan/sizeindicator.cpp | 113 + libkscan/sizeindicator.h | 98 + 3625 files changed, 622724 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 COPYING-DOCS create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Mainpage.dox create mode 100644 Makefile.am.in create mode 100644 Makefile.cvs create mode 100644 README create mode 100644 configure.in.in create mode 100644 doc/Makefile.am create mode 100644 doc/kamera/Makefile.am create mode 100644 doc/kamera/index.docbook create mode 100644 doc/kcoloredit/Makefile.am create mode 100644 doc/kcoloredit/index.docbook create mode 100644 doc/kdvi/KDVI-features.dvi create mode 100644 doc/kdvi/KDVI-features.tex create mode 100644 doc/kdvi/Makefile.am create mode 100644 doc/kdvi/aboutkde.ps create mode 100644 doc/kdvi/index.docbook create mode 100644 doc/kdvi/kdvi-search.el create mode 100644 doc/kdvi/optionrequester1.png create mode 100644 doc/kdvi/optionrequester2.png create mode 100644 doc/kdvi/srcltx.sty create mode 100644 doc/kdvi/srctex.sty create mode 100644 doc/kgamma/Makefile.am create mode 100644 doc/kgamma/index.docbook create mode 100644 doc/kghostview/Makefile.am create mode 100644 doc/kghostview/index.docbook create mode 100644 doc/kiconedit/Makefile.am create mode 100644 doc/kiconedit/index.docbook create mode 100644 doc/kiconedit/kiconedit-configuration.png create mode 100644 doc/kolourpaint/Makefile.am create mode 100644 doc/kolourpaint/brush_shapes.png create mode 100644 doc/kolourpaint/color_box.png create mode 100644 doc/kolourpaint/eraser_shapes.png create mode 100644 doc/kolourpaint/fcc_std_text.png create mode 100644 doc/kolourpaint/fcc_trans_text.png create mode 100644 doc/kolourpaint/fill_color_similarity.png create mode 100644 doc/kolourpaint/fill_style.png create mode 100644 doc/kolourpaint/image_balance.png create mode 100644 doc/kolourpaint/image_emboss.png create mode 100644 doc/kolourpaint/image_flatten.png create mode 100644 doc/kolourpaint/image_flip.png create mode 100644 doc/kolourpaint/image_invert.png create mode 100644 doc/kolourpaint/image_reduce_colors.png create mode 100644 doc/kolourpaint/image_resize_scale.png create mode 100644 doc/kolourpaint/image_rotate.png create mode 100644 doc/kolourpaint/image_skew.png create mode 100644 doc/kolourpaint/image_soften_sharpen.png create mode 100644 doc/kolourpaint/index.docbook create mode 100644 doc/kolourpaint/kolourpaint-main.png create mode 100644 doc/kolourpaint/line_width.png create mode 100644 doc/kolourpaint/lines_30_45_deg.png create mode 100644 doc/kolourpaint/lines_30_deg.png create mode 100644 doc/kolourpaint/lines_45_deg.png create mode 100644 doc/kolourpaint/rotate_image_30.png create mode 100644 doc/kolourpaint/rotate_selection_30.png create mode 100644 doc/kolourpaint/selections_opaque_transparent.png create mode 100644 doc/kolourpaint/spraycan_patterns.png create mode 100644 doc/kolourpaint/text_zoom_grid.png create mode 100644 doc/kolourpaint/tool_brush.png create mode 100644 doc/kolourpaint/tool_color_picker.png create mode 100644 doc/kolourpaint/tool_color_washer.png create mode 100644 doc/kolourpaint/tool_curve.png create mode 100644 doc/kolourpaint/tool_ellipse.png create mode 100644 doc/kolourpaint/tool_elliptical_selection.png create mode 100644 doc/kolourpaint/tool_eraser.png create mode 100644 doc/kolourpaint/tool_flood_fill.png create mode 100644 doc/kolourpaint/tool_free_form_selection.png create mode 100644 doc/kolourpaint/tool_line.png create mode 100644 doc/kolourpaint/tool_pen.png create mode 100644 doc/kolourpaint/tool_polygon.png create mode 100644 doc/kolourpaint/tool_polyline.png create mode 100644 doc/kolourpaint/tool_polystar.png create mode 100644 doc/kolourpaint/tool_rect_selection.png create mode 100644 doc/kolourpaint/tool_rectangle.png create mode 100644 doc/kolourpaint/tool_rectangles.png create mode 100644 doc/kolourpaint/tool_rounded_rectangle.png create mode 100644 doc/kolourpaint/tool_selections.png create mode 100644 doc/kolourpaint/tool_spraycan.png create mode 100644 doc/kolourpaint/tool_text.png create mode 100644 doc/kolourpaint/view_thumbnails.png create mode 100644 doc/kooka/Makefile.am create mode 100644 doc/kooka/index.docbook create mode 100644 doc/kooka/kooka_gocr.png create mode 100644 doc/kooka/kooka_gocr_result.png create mode 100644 doc/kooka/kooka_mainctrl.png create mode 100644 doc/kooka/ocr-select.png create mode 100644 doc/kooka/shortcut0.png create mode 100644 doc/kooka/shortcut1.png create mode 100644 doc/kooka/toolbar.png create mode 100644 doc/kooka/toolbar1.png create mode 100644 doc/kooka/toolbar2.png create mode 100644 doc/kpdf/Makefile.am create mode 100644 doc/kpdf/configure.png create mode 100644 doc/kpdf/index.docbook create mode 100644 doc/kpovmodeler/Makefile.am create mode 100644 doc/kpovmodeler/cameraview.png create mode 100644 doc/kpovmodeler/controlpoints.png create mode 100644 doc/kpovmodeler/cr22-action-pmcamera.png create mode 100644 doc/kpovmodeler/cr22-action-pmcolorlist.png create mode 100644 doc/kpovmodeler/cr22-action-pmfinish.png create mode 100644 doc/kpovmodeler/cr22-action-pminterior.png create mode 100644 doc/kpovmodeler/cr22-action-pmlight.png create mode 100644 doc/kpovmodeler/cr22-action-pmpigment.png create mode 100644 doc/kpovmodeler/cr22-action-pmplane.png create mode 100644 doc/kpovmodeler/cr22-action-pmrender.png create mode 100644 doc/kpovmodeler/cr22-action-pmsolidcolor.png create mode 100644 doc/kpovmodeler/cr22-action-pmsphere.png create mode 100644 doc/kpovmodeler/defaultviewlayout.png create mode 100644 doc/kpovmodeler/dockwidget.png create mode 100644 doc/kpovmodeler/dockwidgettab.png create mode 100644 doc/kpovmodeler/index.docbook create mode 100644 doc/kpovmodeler/insertaspopup.png create mode 100644 doc/kpovmodeler/objectpropertiesview.png create mode 100644 doc/kpovmodeler/objecttree.png create mode 100644 doc/kpovmodeler/rendericon.png create mode 100644 doc/kpovmodeler/rendermodeoutput.png create mode 100644 doc/kpovmodeler/rendermodequality.png create mode 100644 doc/kpovmodeler/rendermodesize.png create mode 100644 doc/kpovmodeler/rendermodesselection.png create mode 100644 doc/kpovmodeler/rendermodestoolbar.png create mode 100644 doc/kpovmodeler/rendersettingsicon.png create mode 100644 doc/kpovmodeler/renderwindow.png create mode 100644 doc/kpovmodeler/texturepreview.png create mode 100644 doc/kpovmodeler/topview.png create mode 100644 doc/kpovmodeler/tutorial01-camera-dialog.png create mode 100644 doc/kpovmodeler/tutorial01-camera-graphic.png create mode 100644 doc/kpovmodeler/tutorial01-final-render.png create mode 100644 doc/kpovmodeler/tutorial01-ground-color-list.png create mode 100644 doc/kpovmodeler/tutorial01-ground-pigment.png create mode 100644 doc/kpovmodeler/tutorial01-ground-render.png create mode 100644 doc/kpovmodeler/tutorial01-ground-solid-color-1.png create mode 100644 doc/kpovmodeler/tutorial01-ground-solid-color-2.png create mode 100644 doc/kpovmodeler/tutorial01-ground-wrong-colors-render.png create mode 100644 doc/kpovmodeler/tutorial01-light-dialog.png create mode 100644 doc/kpovmodeler/tutorial01-light-graphic.png create mode 100644 doc/kpovmodeler/tutorial01-plane-dialog.png create mode 100644 doc/kpovmodeler/tutorial01-plane-graphic.png create mode 100644 doc/kpovmodeler/tutorial01-plane-tree-expanded.png create mode 100644 doc/kpovmodeler/tutorial01-plane-tree-translate.png create mode 100644 doc/kpovmodeler/tutorial01-sphere-dialog.png create mode 100644 doc/kpovmodeler/tutorial01-sphere-finish-dialog.png create mode 100644 doc/kpovmodeler/tutorial01-sphere-render-finish.png create mode 100644 doc/kpovmodeler/tutorial01-sphere-render-nocolor.png create mode 100644 doc/kpovmodeler/tutorial01-sphere-render-solidcolor.png create mode 100644 doc/kpovmodeler/tutorial01-sphere-solid-color.png create mode 100644 doc/kruler/Makefile.am create mode 100644 doc/kruler/index.docbook create mode 100644 doc/ksnapshot/Makefile.am create mode 100644 doc/ksnapshot/index.docbook create mode 100644 doc/ksnapshot/preview.png create mode 100644 doc/ksnapshot/window.png create mode 100644 doc/kuickshow/Makefile.am create mode 100644 doc/kuickshow/index.docbook create mode 100644 doc/kuickshow/screenshot.png create mode 100644 doc/kview/Makefile.am create mode 100644 doc/kview/index.docbook create mode 100644 doc/kview/kview-application-configuration.png create mode 100644 doc/kview/kview-viewer-configuration.png create mode 100644 kamera/AUTHORS create mode 100644 kamera/Makefile.am create mode 100644 kamera/README create mode 100644 kamera/configure.in.in create mode 100644 kamera/kcontrol/Makefile.am create mode 100644 kamera/kcontrol/kamera.cpp create mode 100644 kamera/kcontrol/kamera.desktop create mode 100644 kamera/kcontrol/kamera.h create mode 100644 kamera/kcontrol/kameraconfigdialog.cpp create mode 100644 kamera/kcontrol/kameraconfigdialog.h create mode 100644 kamera/kcontrol/kameradevice.cpp create mode 100644 kamera/kcontrol/kameradevice.h create mode 100644 kamera/kioslave/Makefile.am create mode 100644 kamera/kioslave/camera.protocol create mode 100644 kamera/kioslave/kamera.cpp create mode 100644 kamera/kioslave/kamera.h create mode 100644 kamera/pics/Makefile.am create mode 100644 kamera/pics/cr16-action-camera_test.png create mode 100644 kamera/pics/cr16-app-camera.png create mode 100644 kamera/pics/cr16-device-camera.png create mode 100644 kamera/pics/cr22-device-camera.png create mode 100644 kamera/pics/cr22-filesys-camera.png create mode 100644 kamera/pics/cr32-device-camera.png create mode 100644 kamera/pics/cr32-filesys-camera.png create mode 100644 kcoloredit/Makefile.am create mode 100644 kcoloredit/color.cpp create mode 100644 kcoloredit/color.h create mode 100644 kcoloredit/colorselector.cpp create mode 100644 kcoloredit/colorselector.h create mode 100644 kcoloredit/editablestreamhistory.cpp create mode 100644 kcoloredit/editablestreamhistory.h create mode 100644 kcoloredit/gradientselection.cpp create mode 100644 kcoloredit/gradientselection.h create mode 100644 kcoloredit/hi16-app-kcolorchooser.png create mode 100644 kcoloredit/hi16-app-kcoloredit.png create mode 100644 kcoloredit/hi22-app-kcolorchooser.png create mode 100644 kcoloredit/hi32-app-kcoloredit.png create mode 100644 kcoloredit/imageselection.cpp create mode 100644 kcoloredit/imageselection.h create mode 100644 kcoloredit/kcolorchooser.cpp create mode 100644 kcoloredit/kcolorchooser.desktop create mode 100644 kcoloredit/kcoloredit.cpp create mode 100644 kcoloredit/kcoloredit.desktop create mode 100644 kcoloredit/kcoloredit.h create mode 100644 kcoloredit/kcoloreditdoc.cpp create mode 100644 kcoloredit/kcoloreditdoc.h create mode 100644 kcoloredit/kcoloreditui.rc create mode 100644 kcoloredit/kcoloreditview.cpp create mode 100644 kcoloredit/kcoloreditview.h create mode 100644 kcoloredit/kxycolorselector.cpp create mode 100644 kcoloredit/kxycolorselector.h create mode 100644 kcoloredit/kzcolorselector.cpp create mode 100644 kcoloredit/kzcolorselector.h create mode 100644 kcoloredit/loadpalettedlg.cpp create mode 100644 kcoloredit/loadpalettedlg.h create mode 100644 kcoloredit/main.cpp create mode 100644 kcoloredit/main.h create mode 100644 kcoloredit/palette.cpp create mode 100644 kcoloredit/palette.h create mode 100644 kcoloredit/palettehistory.h create mode 100644 kcoloredit/paletteview.cpp create mode 100644 kcoloredit/paletteview.h create mode 100644 kcoloredit/paletteviewscrolledarea.cpp create mode 100644 kcoloredit/paletteviewscrolledarea.h create mode 100644 kcoloredit/resource.h create mode 100644 kcoloredit/texteditselection.cpp create mode 100644 kcoloredit/texteditselection.h create mode 100644 kcoloredit/textselection.cpp create mode 100644 kcoloredit/uninstall.desktop create mode 100644 kdegraphics.lsm create mode 100644 kdvi/AUTHORS create mode 100644 kdvi/ChangeLog create mode 100644 kdvi/Makefile.am create mode 100644 kdvi/TODO create mode 100644 kdvi/TeXFont.cpp create mode 100644 kdvi/TeXFont.h create mode 100644 kdvi/TeXFontDefinition.cpp create mode 100644 kdvi/TeXFontDefinition.h create mode 100644 kdvi/TeXFont_PFB.cpp create mode 100644 kdvi/TeXFont_PFB.h create mode 100644 kdvi/TeXFont_PK.cpp create mode 100644 kdvi/TeXFont_PK.h create mode 100644 kdvi/TeXFont_TFM.cpp create mode 100644 kdvi/TeXFont_TFM.h create mode 100644 kdvi/bigEndianByteReader.cpp create mode 100644 kdvi/bigEndianByteReader.h create mode 100644 kdvi/configure.in.in create mode 100644 kdvi/dvi.h create mode 100644 kdvi/dviFile.cpp create mode 100644 kdvi/dviFile.h create mode 100644 kdvi/dviPageCache.cpp create mode 100644 kdvi/dviPageCache.h create mode 100644 kdvi/dviRenderer.cpp create mode 100644 kdvi/dviRenderer.h create mode 100644 kdvi/dviRenderer_draw.cpp create mode 100644 kdvi/dviRenderer_export.cpp create mode 100644 kdvi/dviRenderer_prescan.cpp create mode 100644 kdvi/dviWidget.cpp create mode 100644 kdvi/dviWidget.h create mode 100644 kdvi/dvisourcesplitter.cpp create mode 100644 kdvi/dvisourcesplitter.h create mode 100644 kdvi/examples/BrokenDVI1.dvi create mode 100644 kdvi/examples/Font_not_found.dvi create mode 100644 kdvi/examples/dvistd0.dvi create mode 100644 kdvi/fontEncoding.cpp create mode 100644 kdvi/fontEncoding.h create mode 100644 kdvi/fontEncodingPool.cpp create mode 100644 kdvi/fontEncodingPool.h create mode 100644 kdvi/fontMap.cpp create mode 100644 kdvi/fontMap.h create mode 100644 kdvi/fontpool.cpp create mode 100644 kdvi/fontpool.h create mode 100644 kdvi/fontprogress.cpp create mode 100644 kdvi/fontprogress.h create mode 100644 kdvi/glyph.cpp create mode 100644 kdvi/glyph.h create mode 100644 kdvi/infodialog.cpp create mode 100644 kdvi/infodialog.h create mode 100644 kdvi/kdvi.desktop create mode 100644 kdvi/kdvi.h create mode 100644 kdvi/kdvi.kcfg create mode 100644 kdvi/kdvi.lsm create mode 100644 kdvi/kdvi_multipage.cpp create mode 100644 kdvi/kdvi_multipage.h create mode 100644 kdvi/kdvi_multipage_texthandling.cpp create mode 100644 kdvi/kdvi_part.rc create mode 100644 kdvi/kdvimultipage.desktop create mode 100644 kdvi/kprinterwrapper.h create mode 100644 kdvi/main.cpp create mode 100644 kdvi/make/ChangeLog create mode 100644 kdvi/make/README create mode 100644 kdvi/make/common.make create mode 100644 kdvi/make/config.make create mode 100644 kdvi/make/dist.make create mode 100644 kdvi/make/library.make create mode 100644 kdvi/make/makevars.make create mode 100644 kdvi/make/misc.make create mode 100644 kdvi/make/paths.make create mode 100644 kdvi/make/programs.make create mode 100644 kdvi/make/rdepend.make create mode 100644 kdvi/make/texi.make create mode 100644 kdvi/make/tkpathsea.make create mode 100644 kdvi/optionDialogFontsWidget.cpp create mode 100644 kdvi/optionDialogFontsWidget.h create mode 100644 kdvi/optionDialogFontsWidget_base.ui create mode 100644 kdvi/optionDialogSpecialWidget.cpp create mode 100644 kdvi/optionDialogSpecialWidget.h create mode 100644 kdvi/optionDialogSpecialWidget_base.ui create mode 100644 kdvi/performanceMeasurement.h create mode 100644 kdvi/pix/Makefile.am create mode 100644 kdvi/pix/hi16-app-kdvi.png create mode 100644 kdvi/pix/hi22-app-kdvi.png create mode 100644 kdvi/pix/hi32-app-kdvi.png create mode 100644 kdvi/pix/hi48-app-kdvi.png create mode 100644 kdvi/pix/hisc-app-kdvi.svgz create mode 100644 kdvi/prebookmark.h create mode 100644 kdvi/prefs.kcfgc create mode 100644 kdvi/psgs.cpp create mode 100644 kdvi/psgs.h create mode 100644 kdvi/psheader.txt create mode 100644 kdvi/renderedDviPagePixmap.cpp create mode 100644 kdvi/renderedDviPagePixmap.h create mode 100644 kdvi/special.cpp create mode 100644 kdvi/squeeze.c create mode 100644 kdvi/tips create mode 100644 kdvi/util.cpp create mode 100644 kdvi/vf.cpp create mode 100644 kdvi/xdvi.h create mode 100644 kfax/AUTHORS create mode 100644 kfax/ChangeLog create mode 100644 kfax/Makefile.am create mode 100644 kfax/NOTES create mode 100644 kfax/README create mode 100644 kfax/TODO create mode 100644 kfax/examples/README create mode 100644 kfax/examples/README.kdeapps create mode 100644 kfax/examples/kde.g3 create mode 100644 kfax/examples/nasty.tiff create mode 100644 kfax/faxexpand.cpp create mode 100644 kfax/faxexpand.h create mode 100644 kfax/faxinit.cpp create mode 100644 kfax/faxinput.cpp create mode 100644 kfax/hi16-app-kfax.png create mode 100644 kfax/hi22-app-kfax.png create mode 100644 kfax/hi32-app-kfax.png create mode 100644 kfax/hi48-app-kfax.png create mode 100644 kfax/hisc-app-kfax.svgz create mode 100644 kfax/kfax.cpp create mode 100644 kfax/kfax.desktop create mode 100644 kfax/kfax.h create mode 100644 kfax/kfax.tif create mode 100644 kfax/kfax_printsettings.cpp create mode 100644 kfax/kfax_printsettings.h create mode 100644 kfax/kfaxlogo.xpm create mode 100644 kfax/kfaxui.rc create mode 100644 kfax/options.cpp create mode 100644 kfax/options.h create mode 100644 kfax/version.h create mode 100644 kfax/viewfax.cpp create mode 100644 kfax/viewfax.h create mode 100644 kfaxview/Makefile.am create mode 100644 kfaxview/faxmultipage.cpp create mode 100644 kfaxview/faxmultipage.h create mode 100644 kfaxview/faxrenderer.cpp create mode 100644 kfaxview/faxrenderer.h create mode 100644 kfaxview/hi16-app-kfaxview.png create mode 100644 kfaxview/hi22-app-kfaxview.png create mode 100644 kfaxview/hi32-app-kfaxview.png create mode 100644 kfaxview/hi48-app-kfaxview.png create mode 100644 kfaxview/hisc-app-kfaxview.svgz create mode 100644 kfaxview/kfaxmultipage.desktop create mode 100644 kfaxview/kfaxmultipage_tiff.desktop create mode 100644 kfaxview/kfaxview.desktop create mode 100644 kfaxview/libkfaximage/Makefile.am create mode 100644 kfaxview/libkfaximage/faxexpand.cpp create mode 100644 kfaxview/libkfaximage/faxexpand.h create mode 100644 kfaxview/libkfaximage/faxinit.cpp create mode 100644 kfaxview/libkfaximage/kfaximage.cpp create mode 100644 kfaxview/libkfaximage/kfaximage.h create mode 100644 kfaxview/main.cpp create mode 100644 kfile-plugins/Makefile.am create mode 100644 kfile-plugins/RETURNED_ITEMS create mode 100644 kfile-plugins/bmp/Makefile.am create mode 100644 kfile-plugins/bmp/kfile_bmp.cpp create mode 100644 kfile-plugins/bmp/kfile_bmp.desktop create mode 100644 kfile-plugins/bmp/kfile_bmp.h create mode 100644 kfile-plugins/configure.in.bot create mode 100644 kfile-plugins/dds/Makefile.am create mode 100644 kfile-plugins/dds/kfile_dds.cpp create mode 100644 kfile-plugins/dds/kfile_dds.desktop create mode 100644 kfile-plugins/dds/kfile_dds.h create mode 100644 kfile-plugins/dvi/Makefile.am create mode 100644 kfile-plugins/dvi/kfile_dvi.cpp create mode 100644 kfile-plugins/dvi/kfile_dvi.desktop create mode 100644 kfile-plugins/dvi/kfile_dvi.h create mode 100644 kfile-plugins/exr/Makefile.am create mode 100644 kfile-plugins/exr/configure.in.in create mode 100644 kfile-plugins/exr/kfile_exr.cpp create mode 100644 kfile-plugins/exr/kfile_exr.desktop create mode 100644 kfile-plugins/exr/kfile_exr.h create mode 100644 kfile-plugins/gif/Makefile.am create mode 100644 kfile-plugins/gif/README create mode 100644 kfile-plugins/gif/gif-info.1 create mode 100644 kfile-plugins/gif/gif-info.c create mode 100644 kfile-plugins/gif/kfile_gif.cpp create mode 100644 kfile-plugins/gif/kfile_gif.desktop create mode 100644 kfile-plugins/gif/kfile_gif.h create mode 100644 kfile-plugins/ico/Makefile.am create mode 100644 kfile-plugins/ico/kfile_ico.cpp create mode 100644 kfile-plugins/ico/kfile_ico.desktop create mode 100644 kfile-plugins/ico/kfile_ico.h create mode 100644 kfile-plugins/jpeg/Makefile.am create mode 100644 kfile-plugins/jpeg/README create mode 100644 kfile-plugins/jpeg/exif.cpp create mode 100644 kfile-plugins/jpeg/exif.h create mode 100644 kfile-plugins/jpeg/kfile_jpeg.cpp create mode 100644 kfile-plugins/jpeg/kfile_jpeg.desktop create mode 100644 kfile-plugins/jpeg/kfile_jpeg.h create mode 100644 kfile-plugins/jpeg/kfile_setcomment.cpp create mode 100644 kfile-plugins/pcx/Makefile.am create mode 100644 kfile-plugins/pcx/kfile_pcx.cpp create mode 100644 kfile-plugins/pcx/kfile_pcx.desktop create mode 100644 kfile-plugins/pcx/kfile_pcx.h create mode 100644 kfile-plugins/pdf/Makefile.am create mode 100644 kfile-plugins/pdf/configure.in.in create mode 100644 kfile-plugins/pdf/kfile_pdf.cpp create mode 100644 kfile-plugins/pdf/kfile_pdf.desktop create mode 100644 kfile-plugins/pdf/kfile_pdf.h create mode 100644 kfile-plugins/png/Makefile.am create mode 100644 kfile-plugins/png/kfile_png.cpp create mode 100644 kfile-plugins/png/kfile_png.desktop create mode 100644 kfile-plugins/png/kfile_png.h create mode 100644 kfile-plugins/pnm/Makefile.am create mode 100644 kfile-plugins/pnm/kfile_pnm.cpp create mode 100644 kfile-plugins/pnm/kfile_pnm.desktop create mode 100644 kfile-plugins/pnm/kfile_pnm.h create mode 100644 kfile-plugins/ps/Makefile.am create mode 100644 kfile-plugins/ps/gscreator.cpp create mode 100644 kfile-plugins/ps/gscreator.h create mode 100644 kfile-plugins/ps/gsthumbnail.desktop create mode 100644 kfile-plugins/ps/kfile_ps.cpp create mode 100644 kfile-plugins/ps/kfile_ps.desktop create mode 100644 kfile-plugins/ps/kfile_ps.h create mode 100644 kfile-plugins/raw/Makefile.am create mode 100644 kfile-plugins/raw/kcamerarawplugin.cpp create mode 100644 kfile-plugins/raw/kcamerarawplugin.h create mode 100644 kfile-plugins/raw/kfile_raw.desktop create mode 100644 kfile-plugins/raw/parse.c create mode 100644 kfile-plugins/rgb/Makefile.am create mode 100644 kfile-plugins/rgb/kfile_rgb.cpp create mode 100644 kfile-plugins/rgb/kfile_rgb.desktop create mode 100644 kfile-plugins/rgb/kfile_rgb.h create mode 100644 kfile-plugins/tga/Makefile.am create mode 100644 kfile-plugins/tga/kfile_tga.cpp create mode 100644 kfile-plugins/tga/kfile_tga.desktop create mode 100644 kfile-plugins/tga/kfile_tga.h create mode 100644 kfile-plugins/tiff/Makefile.am create mode 100644 kfile-plugins/tiff/configure.in.in create mode 100644 kfile-plugins/tiff/kfile_tiff.cpp create mode 100644 kfile-plugins/tiff/kfile_tiff.desktop create mode 100644 kfile-plugins/tiff/kfile_tiff.h create mode 100644 kfile-plugins/xbm/Makefile.am create mode 100644 kfile-plugins/xbm/kfile_xbm.cpp create mode 100644 kfile-plugins/xbm/kfile_xbm.desktop create mode 100644 kfile-plugins/xbm/kfile_xbm.h create mode 100644 kfile-plugins/xpm/Makefile.am create mode 100644 kfile-plugins/xpm/kfile_xpm.cpp create mode 100644 kfile-plugins/xpm/kfile_xpm.desktop create mode 100644 kfile-plugins/xpm/kfile_xpm.h create mode 100644 kgamma/AUTHORS create mode 100644 kgamma/ChangeLog create mode 100644 kgamma/Makefile.am create mode 100644 kgamma/TODO create mode 100644 kgamma/configure.in.in create mode 100644 kgamma/kcmkgamma/Makefile.am create mode 100644 kgamma/kcmkgamma/displaynumber.cpp create mode 100644 kgamma/kcmkgamma/displaynumber.h create mode 100644 kgamma/kcmkgamma/gammactrl.cpp create mode 100644 kgamma/kcmkgamma/gammactrl.h create mode 100644 kgamma/kcmkgamma/kgamma.cpp create mode 100644 kgamma/kcmkgamma/kgamma.desktop create mode 100644 kgamma/kcmkgamma/kgamma.h create mode 100644 kgamma/kcmkgamma/pics/Makefile.am create mode 100644 kgamma/kcmkgamma/pics/background.png create mode 100644 kgamma/kcmkgamma/pics/cmyscale.png create mode 100644 kgamma/kcmkgamma/pics/darkgrey.png create mode 100644 kgamma/kcmkgamma/pics/greyscale.png create mode 100644 kgamma/kcmkgamma/pics/hi16-app-kgamma.png create mode 100644 kgamma/kcmkgamma/pics/hi32-app-kgamma.png create mode 100644 kgamma/kcmkgamma/pics/hi48-app-kgamma.png create mode 100644 kgamma/kcmkgamma/pics/lightgrey.png create mode 100644 kgamma/kcmkgamma/pics/midgrey.png create mode 100644 kgamma/kcmkgamma/pics/rgbscale.png create mode 100644 kgamma/kcmkgamma/xf86configpath.cpp create mode 100644 kgamma/kcmkgamma/xf86configpath.h create mode 100644 kgamma/kcmkgamma/xvidextwrap.cpp create mode 100644 kgamma/kcmkgamma/xvidextwrap.h create mode 100644 kgamma/xf86gammacfg/Makefile.am create mode 100644 kgamma/xf86gammacfg/xf86gammacfg.cpp create mode 100644 kghostview/AUTHORS create mode 100644 kghostview/ChangeLog create mode 100644 kghostview/Makefile.am create mode 100644 kghostview/README create mode 100644 kghostview/TODO create mode 100644 kghostview/configuration.kcfgc create mode 100644 kghostview/data/Makefile.am create mode 100644 kghostview/data/pdf_sec.ps create mode 100644 kghostview/displayoptions.cpp create mode 100644 kghostview/displayoptions.h create mode 100644 kghostview/dscparse.cpp create mode 100644 kghostview/dscparse.h create mode 100644 kghostview/dscparse_adapter.cpp create mode 100644 kghostview/dscparse_adapter.h create mode 100644 kghostview/fullscreenfilter.cpp create mode 100644 kghostview/fullscreenfilter.h create mode 100644 kghostview/generalsettingswidget.ui create mode 100644 kghostview/generalsettingswidget.ui.h create mode 100644 kghostview/gssettingswidget.ui create mode 100644 kghostview/gssettingswidget.ui.h create mode 100644 kghostview/hi128-app-kghostview.png create mode 100644 kghostview/hi16-app-kghostview.png create mode 100644 kghostview/hi22-app-kghostview.png create mode 100644 kghostview/hi32-app-kghostview.png create mode 100644 kghostview/hi48-app-kghostview.png create mode 100644 kghostview/hi64-app-kghostview.png create mode 100644 kghostview/infodialog.cpp create mode 100644 kghostview/infodialog.h create mode 100644 kghostview/kdscerrordialog.cpp create mode 100644 kghostview/kdscerrordialog.h create mode 100644 kghostview/kghostview.desktop create mode 100644 kghostview/kghostview.kcfg create mode 100644 kghostview/kghostview.upd create mode 100644 kghostview/kghostview_part.desktop create mode 100644 kghostview/kghostviewui.rc create mode 100644 kghostview/kgv.h create mode 100644 kghostview/kgv_miniwidget.cpp create mode 100644 kghostview/kgv_miniwidget.h create mode 100644 kghostview/kgv_part.rc create mode 100644 kghostview/kgv_view.cpp create mode 100644 kghostview/kgv_view.h create mode 100644 kghostview/kgvconfigdialog.cpp create mode 100644 kghostview/kgvconfigdialog.h create mode 100644 kghostview/kgvdocument.cpp create mode 100644 kghostview/kgvdocument.h create mode 100644 kghostview/kgvfactory.cpp create mode 100644 kghostview/kgvfactory.h create mode 100644 kghostview/kgvmainwidget.cpp create mode 100644 kghostview/kgvmainwidget.h create mode 100644 kghostview/kgvpagedecorator.cpp create mode 100644 kghostview/kgvpagedecorator.h create mode 100644 kghostview/kgvpageview.cpp create mode 100644 kghostview/kgvpageview.h create mode 100644 kghostview/kgvshell.cpp create mode 100644 kghostview/kgvshell.h create mode 100644 kghostview/kpswidget.cpp create mode 100644 kghostview/kpswidget.h create mode 100644 kghostview/logwindow.cpp create mode 100644 kghostview/logwindow.h create mode 100644 kghostview/main.cpp create mode 100644 kghostview/marklist.cpp create mode 100644 kghostview/marklist.h create mode 100644 kghostview/part_init.cpp create mode 100644 kghostview/ps.c create mode 100644 kghostview/ps.h create mode 100644 kghostview/scrollbox.cpp create mode 100644 kghostview/scrollbox.h create mode 100644 kghostview/thumbnailservice.cpp create mode 100644 kghostview/thumbnailservice.h create mode 100644 kghostview/update-to-xt-names.pl create mode 100644 kghostview/version.h create mode 100644 kghostview/viewcontrol.cpp create mode 100644 kghostview/viewcontrol.h create mode 100644 kiconedit/AUTHORS create mode 100644 kiconedit/Makefile.am create mode 100644 kiconedit/NEWS create mode 100644 kiconedit/kcolorgrid.cpp create mode 100644 kiconedit/kcolorgrid.h create mode 100644 kiconedit/kicon.cpp create mode 100644 kiconedit/kicon.h create mode 100644 kiconedit/kiconcolors.cpp create mode 100644 kiconedit/kiconcolors.h create mode 100644 kiconedit/kiconconfig.cpp create mode 100644 kiconedit/kiconconfig.h create mode 100644 kiconedit/kiconedit.cpp create mode 100644 kiconedit/kiconedit.desktop create mode 100644 kiconedit/kiconedit.h create mode 100644 kiconedit/kiconeditslots.cpp create mode 100644 kiconedit/kiconeditui.rc create mode 100644 kiconedit/kicongrid.cpp create mode 100644 kiconedit/kicongrid.h create mode 100644 kiconedit/knew.cpp create mode 100644 kiconedit/knew.h create mode 100644 kiconedit/kresize.cpp create mode 100644 kiconedit/kresize.h create mode 100644 kiconedit/main.cpp create mode 100644 kiconedit/palettetoolbar.cpp create mode 100644 kiconedit/palettetoolbar.h create mode 100644 kiconedit/pics/Makefile.am create mode 100644 kiconedit/pics/hi16-app-kiconedit.png create mode 100644 kiconedit/pics/hi22-app-kiconedit.png create mode 100644 kiconedit/pics/hi32-app-kiconedit.png create mode 100644 kiconedit/pics/hi48-app-kiconedit.png create mode 100644 kiconedit/pics/icons/Makefile.am create mode 100644 kiconedit/pics/icons/compressed.png create mode 100644 kiconedit/pics/icons/source.png create mode 100644 kiconedit/pics/icons/standard.png create mode 100644 kiconedit/pics/logo.xpm create mode 100644 kiconedit/pics/toolbar/Makefile.am create mode 100644 kiconedit/pics/toolbar/aim-cursor.xpm create mode 100644 kiconedit/pics/toolbar/aim.png create mode 100644 kiconedit/pics/toolbar/airbrush-cursor.xpm create mode 100644 kiconedit/pics/toolbar/areaselect.png create mode 100644 kiconedit/pics/toolbar/circle.png create mode 100644 kiconedit/pics/toolbar/colorpicker-cursor.xpm create mode 100644 kiconedit/pics/toolbar/ellipse.png create mode 100644 kiconedit/pics/toolbar/eraser-cursor.xpm create mode 100644 kiconedit/pics/toolbar/fileclose.png create mode 100644 kiconedit/pics/toolbar/fill-cursor.xpm create mode 100644 kiconedit/pics/toolbar/filledcircle.png create mode 100644 kiconedit/pics/toolbar/filledellipse.png create mode 100644 kiconedit/pics/toolbar/filledrectangle.png create mode 100644 kiconedit/pics/toolbar/flood-cursor.xpm create mode 100644 kiconedit/pics/toolbar/flood.png create mode 100644 kiconedit/pics/toolbar/grayscale.png create mode 100644 kiconedit/pics/toolbar/grid.png create mode 100644 kiconedit/pics/toolbar/kdepalette.png create mode 100644 kiconedit/pics/toolbar/line.png create mode 100644 kiconedit/pics/toolbar/paintbrush-cursor.xpm create mode 100644 kiconedit/pics/toolbar/paintbrush.png create mode 100644 kiconedit/pics/toolbar/pointer.png create mode 100644 kiconedit/pics/toolbar/rectangle.png create mode 100644 kiconedit/pics/toolbar/selectcircle.png create mode 100644 kiconedit/pics/toolbar/selectrect.png create mode 100644 kiconedit/pics/toolbar/spraycan-cursor.xpm create mode 100644 kiconedit/pics/toolbar/spraycan.png create mode 100644 kiconedit/pics/toolbar/transform.png create mode 100644 kiconedit/pics/toolbar/window_new.png create mode 100644 kiconedit/properties.cpp create mode 100644 kiconedit/properties.h create mode 100644 kiconedit/utils.cpp create mode 100644 kiconedit/utils.h create mode 100644 kiconedit/version.h create mode 100644 kmrml/AUTHORS create mode 100644 kmrml/ChangeLog create mode 100644 kmrml/Makefile.am create mode 100644 kmrml/README create mode 100644 kmrml/README.DEVELOPMENT create mode 100644 kmrml/TODO create mode 100644 kmrml/example-session.mrml create mode 100644 kmrml/kmrml.lsm create mode 100644 kmrml/kmrml.spec create mode 100644 kmrml/kmrml/Makefile.am create mode 100644 kmrml/kmrml/algorithmcombo.cpp create mode 100644 kmrml/kmrml/algorithmcombo.h create mode 100644 kmrml/kmrml/algorithmdialog.cpp create mode 100644 kmrml/kmrml/algorithmdialog.h create mode 100644 kmrml/kmrml/browser.cpp create mode 100644 kmrml/kmrml/browser.h create mode 100644 kmrml/kmrml/collectioncombo.cpp create mode 100644 kmrml/kmrml/collectioncombo.h create mode 100644 kmrml/kmrml/kcontrol/Makefile.am create mode 100644 kmrml/kmrml/kcontrol/indexcleaner.cpp create mode 100644 kmrml/kmrml/kcontrol/indexcleaner.h create mode 100644 kmrml/kmrml/kcontrol/indexer.cpp create mode 100644 kmrml/kmrml/kcontrol/indexer.h create mode 100644 kmrml/kmrml/kcontrol/indextest.cpp create mode 100644 kmrml/kmrml/kcontrol/indextest.h create mode 100644 kmrml/kmrml/kcontrol/kcmkmrml.cpp create mode 100644 kmrml/kmrml/kcontrol/kcmkmrml.desktop create mode 100644 kmrml/kmrml/kcontrol/kcmkmrml.h create mode 100644 kmrml/kmrml/kcontrol/mainpage.cpp create mode 100644 kmrml/kmrml/kcontrol/mainpage.h create mode 100644 kmrml/kmrml/kcontrol/serverconfigwidget.ui create mode 100644 kmrml/kmrml/lib/Makefile.am create mode 100644 kmrml/kmrml/lib/kmrml_config.cpp create mode 100644 kmrml/kmrml/lib/kmrml_config.h create mode 100644 kmrml/kmrml/lib/mrml_shared.cpp create mode 100644 kmrml/kmrml/lib/mrml_shared.h create mode 100644 kmrml/kmrml/lib/mrml_utils.cpp create mode 100644 kmrml/kmrml/lib/mrml_utils.h create mode 100644 kmrml/kmrml/lib/version.h create mode 100644 kmrml/kmrml/lib/watcher_stub.cpp create mode 100644 kmrml/kmrml/lib/watcher_stub.h create mode 100644 kmrml/kmrml/loader.cpp create mode 100644 kmrml/kmrml/loader.h create mode 100644 kmrml/kmrml/mrml-servicemenu.desktop create mode 100644 kmrml/kmrml/mrml.cpp create mode 100644 kmrml/kmrml/mrml.desktop create mode 100644 kmrml/kmrml/mrml.h create mode 100644 kmrml/kmrml/mrml.protocol create mode 100644 kmrml/kmrml/mrml_creator.cpp create mode 100644 kmrml/kmrml/mrml_creator.h create mode 100644 kmrml/kmrml/mrml_elements.cpp create mode 100644 kmrml/kmrml/mrml_elements.h create mode 100644 kmrml/kmrml/mrml_part.cpp create mode 100644 kmrml/kmrml/mrml_part.desktop create mode 100644 kmrml/kmrml/mrml_part.h create mode 100644 kmrml/kmrml/mrml_view.cpp create mode 100644 kmrml/kmrml/mrml_view.h create mode 100644 kmrml/kmrml/mrmlsearch.cpp create mode 100644 kmrml/kmrml/propertysheet.cpp create mode 100644 kmrml/kmrml/propertysheet.h create mode 100644 kmrml/kmrml/propertywidgets.cpp create mode 100644 kmrml/kmrml/propertywidgets.h create mode 100644 kmrml/kmrml/server/Makefile.am create mode 100644 kmrml/kmrml/server/daemonwatcher.desktop create mode 100644 kmrml/kmrml/server/watcher.cpp create mode 100644 kmrml/kmrml/server/watcher.h create mode 100644 kolourpaint/AUTHORS create mode 100644 kolourpaint/BUGS create mode 100644 kolourpaint/COPYING create mode 100644 kolourpaint/ChangeLog create mode 100644 kolourpaint/Makefile.am create mode 100644 kolourpaint/NEWS create mode 100644 kolourpaint/README create mode 100644 kolourpaint/VERSION create mode 100644 kolourpaint/cursors/Makefile.am create mode 100644 kolourpaint/cursors/kpcursorlightcross.cpp create mode 100644 kolourpaint/cursors/kpcursorlightcross.h create mode 100644 kolourpaint/cursors/kpcursorprovider.cpp create mode 100644 kolourpaint/cursors/kpcursorprovider.h create mode 100644 kolourpaint/kolourpaint.cpp create mode 100644 kolourpaint/kolourpaint.desktop create mode 100644 kolourpaint/kolourpaintui.rc create mode 100644 kolourpaint/kpcolor.cpp create mode 100644 kolourpaint/kpcolor.h create mode 100644 kolourpaint/kpcommandhistory.cpp create mode 100644 kolourpaint/kpcommandhistory.h create mode 100644 kolourpaint/kpdefs.h create mode 100644 kolourpaint/kpdocument.cpp create mode 100644 kolourpaint/kpdocument.h create mode 100644 kolourpaint/kpdocumentmetainfo.cpp create mode 100644 kolourpaint/kpdocumentmetainfo.h create mode 100644 kolourpaint/kpdocumentsaveoptions.cpp create mode 100644 kolourpaint/kpdocumentsaveoptions.h create mode 100644 kolourpaint/kpdocumentsaveoptionswidget.cpp create mode 100644 kolourpaint/kpdocumentsaveoptionswidget.h create mode 100644 kolourpaint/kpmainwindow.cpp create mode 100644 kolourpaint/kpmainwindow.h create mode 100644 kolourpaint/kpmainwindow_edit.cpp create mode 100644 kolourpaint/kpmainwindow_file.cpp create mode 100644 kolourpaint/kpmainwindow_help.cpp create mode 100644 kolourpaint/kpmainwindow_image.cpp create mode 100644 kolourpaint/kpmainwindow_p.h create mode 100644 kolourpaint/kpmainwindow_settings.cpp create mode 100644 kolourpaint/kpmainwindow_statusbar.cpp create mode 100644 kolourpaint/kpmainwindow_text.cpp create mode 100644 kolourpaint/kpmainwindow_tools.cpp create mode 100644 kolourpaint/kpmainwindow_view.cpp create mode 100644 kolourpaint/kpselection.cpp create mode 100644 kolourpaint/kpselection.h create mode 100644 kolourpaint/kpselectiondrag.cpp create mode 100644 kolourpaint/kpselectiondrag.h create mode 100644 kolourpaint/kpselectiontransparency.cpp create mode 100644 kolourpaint/kpselectiontransparency.h create mode 100644 kolourpaint/kpsinglekeytriggersaction.cpp create mode 100644 kolourpaint/kpsinglekeytriggersaction.h create mode 100644 kolourpaint/kptemppixmap.cpp create mode 100644 kolourpaint/kptemppixmap.h create mode 100644 kolourpaint/kptextstyle.cpp create mode 100644 kolourpaint/kptextstyle.h create mode 100644 kolourpaint/kpthumbnail.cpp create mode 100644 kolourpaint/kpthumbnail.h create mode 100644 kolourpaint/kptool.cpp create mode 100644 kolourpaint/kptool.h create mode 100644 kolourpaint/kpview.cpp create mode 100644 kolourpaint/kpview.h create mode 100644 kolourpaint/kpviewmanager.cpp create mode 100644 kolourpaint/kpviewmanager.h create mode 100644 kolourpaint/kpviewscrollablecontainer.cpp create mode 100644 kolourpaint/kpviewscrollablecontainer.h create mode 100644 kolourpaint/kpwidgetmapper.cpp create mode 100644 kolourpaint/kpwidgetmapper.h create mode 100644 kolourpaint/patches/checkerboard-faster-render.diff create mode 100644 kolourpaint/patches/color_eraser_speedup.diff create mode 100644 kolourpaint/patches/doc_resize_no_flicker.diff create mode 100644 kolourpaint/pics/Makefile.am create mode 100644 kolourpaint/pics/cr16-action-tool_brush.png create mode 100644 kolourpaint/pics/cr16-action-tool_color_picker.png create mode 100644 kolourpaint/pics/cr16-action-tool_color_washer.png create mode 100644 kolourpaint/pics/cr16-action-tool_curve.png create mode 100644 kolourpaint/pics/cr16-action-tool_ellipse.png create mode 100644 kolourpaint/pics/cr16-action-tool_elliptical_selection.png create mode 100644 kolourpaint/pics/cr16-action-tool_eraser.png create mode 100644 kolourpaint/pics/cr16-action-tool_flood_fill.png create mode 100644 kolourpaint/pics/cr16-action-tool_free_form_selection.png create mode 100644 kolourpaint/pics/cr16-action-tool_line.png create mode 100644 kolourpaint/pics/cr16-action-tool_pen.png create mode 100644 kolourpaint/pics/cr16-action-tool_polygon.png create mode 100644 kolourpaint/pics/cr16-action-tool_polyline.png create mode 100644 kolourpaint/pics/cr16-action-tool_rect_selection.png create mode 100644 kolourpaint/pics/cr16-action-tool_rectangle.png create mode 100644 kolourpaint/pics/cr16-action-tool_rounded_rectangle.png create mode 100644 kolourpaint/pics/cr16-action-tool_spraycan.png create mode 100644 kolourpaint/pics/cr16-action-tool_text.png create mode 100644 kolourpaint/pics/cr22-action-tool_brush.png create mode 100644 kolourpaint/pics/cr22-action-tool_color_picker.png create mode 100644 kolourpaint/pics/cr22-action-tool_color_washer.png create mode 100644 kolourpaint/pics/cr22-action-tool_curve.png create mode 100644 kolourpaint/pics/cr22-action-tool_ellipse.png create mode 100644 kolourpaint/pics/cr22-action-tool_elliptical_selection.png create mode 100644 kolourpaint/pics/cr22-action-tool_eraser.png create mode 100644 kolourpaint/pics/cr22-action-tool_flood_fill.png create mode 100644 kolourpaint/pics/cr22-action-tool_free_form_selection.png create mode 100644 kolourpaint/pics/cr22-action-tool_line.png create mode 100644 kolourpaint/pics/cr22-action-tool_pen.png create mode 100644 kolourpaint/pics/cr22-action-tool_polygon.png create mode 100644 kolourpaint/pics/cr22-action-tool_polyline.png create mode 100644 kolourpaint/pics/cr22-action-tool_rect_selection.png create mode 100644 kolourpaint/pics/cr22-action-tool_rectangle.png create mode 100644 kolourpaint/pics/cr22-action-tool_rounded_rectangle.png create mode 100644 kolourpaint/pics/cr22-action-tool_spraycan.png create mode 100644 kolourpaint/pics/cr22-action-tool_text.png create mode 100644 kolourpaint/pics/cr32-action-tool_brush.png create mode 100644 kolourpaint/pics/cr32-action-tool_color_picker.png create mode 100644 kolourpaint/pics/cr32-action-tool_color_washer.png create mode 100644 kolourpaint/pics/cr32-action-tool_curve.png create mode 100644 kolourpaint/pics/cr32-action-tool_ellipse.png create mode 100644 kolourpaint/pics/cr32-action-tool_elliptical_selection.png create mode 100644 kolourpaint/pics/cr32-action-tool_eraser.png create mode 100644 kolourpaint/pics/cr32-action-tool_flood_fill.png create mode 100644 kolourpaint/pics/cr32-action-tool_free_form_selection.png create mode 100644 kolourpaint/pics/cr32-action-tool_line.png create mode 100644 kolourpaint/pics/cr32-action-tool_pen.png create mode 100644 kolourpaint/pics/cr32-action-tool_polygon.png create mode 100644 kolourpaint/pics/cr32-action-tool_polyline.png create mode 100644 kolourpaint/pics/cr32-action-tool_rect_selection.png create mode 100644 kolourpaint/pics/cr32-action-tool_rectangle.png create mode 100644 kolourpaint/pics/cr32-action-tool_rounded_rectangle.png create mode 100644 kolourpaint/pics/cr32-action-tool_spraycan.png create mode 100644 kolourpaint/pics/cr32-action-tool_text.png create mode 100644 kolourpaint/pics/cr48-action-tool_brush.png create mode 100644 kolourpaint/pics/cr48-action-tool_color_picker.png create mode 100644 kolourpaint/pics/cr48-action-tool_color_washer.png create mode 100644 kolourpaint/pics/cr48-action-tool_curve.png create mode 100644 kolourpaint/pics/cr48-action-tool_ellipse.png create mode 100644 kolourpaint/pics/cr48-action-tool_elliptical_selection.png create mode 100644 kolourpaint/pics/cr48-action-tool_eraser.png create mode 100644 kolourpaint/pics/cr48-action-tool_flood_fill.png create mode 100644 kolourpaint/pics/cr48-action-tool_free_form_selection.png create mode 100644 kolourpaint/pics/cr48-action-tool_line.png create mode 100644 kolourpaint/pics/cr48-action-tool_pen.png create mode 100644 kolourpaint/pics/cr48-action-tool_polygon.png create mode 100644 kolourpaint/pics/cr48-action-tool_polyline.png create mode 100644 kolourpaint/pics/cr48-action-tool_rect_selection.png create mode 100644 kolourpaint/pics/cr48-action-tool_rectangle.png create mode 100644 kolourpaint/pics/cr48-action-tool_rounded_rectangle.png create mode 100644 kolourpaint/pics/cr48-action-tool_spraycan.png create mode 100644 kolourpaint/pics/cr48-action-tool_text.png create mode 100644 kolourpaint/pics/crsc-action-tool_brush.svgz create mode 100644 kolourpaint/pics/crsc-action-tool_color_picker.svgz create mode 100644 kolourpaint/pics/crsc-action-tool_color_washer.svgz create mode 100644 kolourpaint/pics/crsc-action-tool_curve.svgz create mode 100644 kolourpaint/pics/crsc-action-tool_ellipse.svgz create mode 100644 kolourpaint/pics/crsc-action-tool_elliptical_selection.svgz create mode 100644 kolourpaint/pics/crsc-action-tool_eraser.svgz create mode 100644 kolourpaint/pics/crsc-action-tool_flood_fill.svgz create mode 100644 kolourpaint/pics/crsc-action-tool_free_form_selection.svgz create mode 100644 kolourpaint/pics/crsc-action-tool_line.svgz create mode 100644 kolourpaint/pics/crsc-action-tool_pen.svgz create mode 100644 kolourpaint/pics/crsc-action-tool_polygon.svgz create mode 100644 kolourpaint/pics/crsc-action-tool_polyline.svgz create mode 100644 kolourpaint/pics/crsc-action-tool_rect_selection.svgz create mode 100644 kolourpaint/pics/crsc-action-tool_rectangle.svgz create mode 100644 kolourpaint/pics/crsc-action-tool_rounded_rectangle.svgz create mode 100644 kolourpaint/pics/crsc-action-tool_spraycan.svgz create mode 100644 kolourpaint/pics/crsc-action-tool_text.svgz create mode 100644 kolourpaint/pics/custom/Makefile.am create mode 100644 kolourpaint/pics/custom/color_transparent_26x26.png create mode 100644 kolourpaint/pics/custom/colorbutton_swap_16x16.png create mode 100644 kolourpaint/pics/custom/image_rotate_anticlockwise.png create mode 100644 kolourpaint/pics/custom/image_rotate_clockwise.png create mode 100644 kolourpaint/pics/custom/image_skew_horizontal.png create mode 100644 kolourpaint/pics/custom/image_skew_vertical.png create mode 100644 kolourpaint/pics/custom/option_opaque.png create mode 100644 kolourpaint/pics/custom/option_transparent.png create mode 100644 kolourpaint/pics/custom/resize.png create mode 100644 kolourpaint/pics/custom/scale.png create mode 100644 kolourpaint/pics/custom/smooth_scale.png create mode 100644 kolourpaint/pics/custom/tool_spraycan_17x17.png create mode 100644 kolourpaint/pics/custom/tool_spraycan_29x29.png create mode 100644 kolourpaint/pics/custom/tool_spraycan_9x9.png create mode 100644 kolourpaint/pics/hi16-app-kolourpaint.png create mode 100644 kolourpaint/pics/hi22-app-kolourpaint.png create mode 100644 kolourpaint/pics/hi32-app-kolourpaint.png create mode 100644 kolourpaint/pics/hi48-app-kolourpaint.png create mode 100644 kolourpaint/pics/hisc-app-kolourpaint.svgz create mode 100644 kolourpaint/pixmapfx/Makefile.am create mode 100644 kolourpaint/pixmapfx/kpcoloreffect.cpp create mode 100644 kolourpaint/pixmapfx/kpcoloreffect.h create mode 100644 kolourpaint/pixmapfx/kpeffectbalance.cpp create mode 100644 kolourpaint/pixmapfx/kpeffectbalance.h create mode 100644 kolourpaint/pixmapfx/kpeffectblursharpen.cpp create mode 100644 kolourpaint/pixmapfx/kpeffectblursharpen.h create mode 100644 kolourpaint/pixmapfx/kpeffectemboss.cpp create mode 100644 kolourpaint/pixmapfx/kpeffectemboss.h create mode 100644 kolourpaint/pixmapfx/kpeffectflatten.cpp create mode 100644 kolourpaint/pixmapfx/kpeffectflatten.h create mode 100644 kolourpaint/pixmapfx/kpeffectinvert.cpp create mode 100644 kolourpaint/pixmapfx/kpeffectinvert.h create mode 100644 kolourpaint/pixmapfx/kpeffectreducecolors.cpp create mode 100644 kolourpaint/pixmapfx/kpeffectreducecolors.h create mode 100644 kolourpaint/pixmapfx/kpeffectsdialog.cpp create mode 100644 kolourpaint/pixmapfx/kpeffectsdialog.h create mode 100644 kolourpaint/pixmapfx/kpfloodfill.cpp create mode 100644 kolourpaint/pixmapfx/kpfloodfill.h create mode 100644 kolourpaint/pixmapfx/kppixmapfx.cpp create mode 100644 kolourpaint/pixmapfx/kppixmapfx.h create mode 100644 kolourpaint/tests/45deg_line.png create mode 100644 kolourpaint/tests/4x4-transparent.png create mode 100644 kolourpaint/tests/5x5.png create mode 100644 kolourpaint/tests/depth1.bmp create mode 100644 kolourpaint/tests/dither.png create mode 100644 kolourpaint/tests/rotate.png create mode 100644 kolourpaint/tests/small16x16.png create mode 100644 kolourpaint/tests/tool_fill_xlimit.png create mode 100644 kolourpaint/tests/transparent.png create mode 100644 kolourpaint/tests/transparent_selection.png create mode 100644 kolourpaint/tools/Makefile.am create mode 100644 kolourpaint/tools/kptoolaction.cpp create mode 100644 kolourpaint/tools/kptoolaction.h create mode 100644 kolourpaint/tools/kptoolairspray.cpp create mode 100644 kolourpaint/tools/kptoolairspray.h create mode 100644 kolourpaint/tools/kptoolautocrop.cpp create mode 100644 kolourpaint/tools/kptoolautocrop.h create mode 100644 kolourpaint/tools/kptoolbrush.cpp create mode 100644 kolourpaint/tools/kptoolbrush.h create mode 100644 kolourpaint/tools/kptoolclear.cpp create mode 100644 kolourpaint/tools/kptoolclear.h create mode 100644 kolourpaint/tools/kptoolcolorpicker.cpp create mode 100644 kolourpaint/tools/kptoolcolorpicker.h create mode 100644 kolourpaint/tools/kptoolcolorwasher.cpp create mode 100644 kolourpaint/tools/kptoolcolorwasher.h create mode 100644 kolourpaint/tools/kptoolconverttograyscale.cpp create mode 100644 kolourpaint/tools/kptoolconverttograyscale.h create mode 100644 kolourpaint/tools/kptoolcrop.cpp create mode 100644 kolourpaint/tools/kptoolcrop.h create mode 100644 kolourpaint/tools/kptoolcurve.cpp create mode 100644 kolourpaint/tools/kptoolcurve.h create mode 100644 kolourpaint/tools/kptoolellipse.cpp create mode 100644 kolourpaint/tools/kptoolellipse.h create mode 100644 kolourpaint/tools/kptoolellipticalselection.cpp create mode 100644 kolourpaint/tools/kptoolellipticalselection.h create mode 100644 kolourpaint/tools/kptooleraser.cpp create mode 100644 kolourpaint/tools/kptooleraser.h create mode 100644 kolourpaint/tools/kptoolflip.cpp create mode 100644 kolourpaint/tools/kptoolflip.h create mode 100644 kolourpaint/tools/kptoolfloodfill.cpp create mode 100644 kolourpaint/tools/kptoolfloodfill.h create mode 100644 kolourpaint/tools/kptoolfreeformselection.cpp create mode 100644 kolourpaint/tools/kptoolfreeformselection.h create mode 100644 kolourpaint/tools/kptoolline.cpp create mode 100644 kolourpaint/tools/kptoolline.h create mode 100644 kolourpaint/tools/kptoolpen.cpp create mode 100644 kolourpaint/tools/kptoolpen.h create mode 100644 kolourpaint/tools/kptoolpolygon.cpp create mode 100644 kolourpaint/tools/kptoolpolygon.h create mode 100644 kolourpaint/tools/kptoolpolyline.cpp create mode 100644 kolourpaint/tools/kptoolpolyline.h create mode 100644 kolourpaint/tools/kptoolpreviewdialog.cpp create mode 100644 kolourpaint/tools/kptoolpreviewdialog.h create mode 100644 kolourpaint/tools/kptoolrectangle.cpp create mode 100644 kolourpaint/tools/kptoolrectangle.h create mode 100644 kolourpaint/tools/kptoolrectselection.cpp create mode 100644 kolourpaint/tools/kptoolrectselection.h create mode 100644 kolourpaint/tools/kptoolresizescale.cpp create mode 100644 kolourpaint/tools/kptoolresizescale.h create mode 100644 kolourpaint/tools/kptoolrotate.cpp create mode 100644 kolourpaint/tools/kptoolrotate.h create mode 100644 kolourpaint/tools/kptoolroundedrectangle.cpp create mode 100644 kolourpaint/tools/kptoolroundedrectangle.h create mode 100644 kolourpaint/tools/kptoolselection.cpp create mode 100644 kolourpaint/tools/kptoolselection.h create mode 100644 kolourpaint/tools/kptoolskew.cpp create mode 100644 kolourpaint/tools/kptoolskew.h create mode 100644 kolourpaint/tools/kptooltext.cpp create mode 100644 kolourpaint/tools/kptooltext.h create mode 100644 kolourpaint/views/Makefile.am create mode 100644 kolourpaint/views/kpthumbnailview.cpp create mode 100644 kolourpaint/views/kpthumbnailview.h create mode 100644 kolourpaint/views/kpunzoomedthumbnailview.cpp create mode 100644 kolourpaint/views/kpunzoomedthumbnailview.h create mode 100644 kolourpaint/views/kpzoomedthumbnailview.cpp create mode 100644 kolourpaint/views/kpzoomedthumbnailview.h create mode 100644 kolourpaint/views/kpzoomedview.cpp create mode 100644 kolourpaint/views/kpzoomedview.h create mode 100644 kolourpaint/widgets/Makefile.am create mode 100644 kolourpaint/widgets/kpcolorsimilaritycube.cpp create mode 100644 kolourpaint/widgets/kpcolorsimilaritycube.h create mode 100644 kolourpaint/widgets/kpcolorsimilaritydialog.cpp create mode 100644 kolourpaint/widgets/kpcolorsimilaritydialog.h create mode 100644 kolourpaint/widgets/kpcolortoolbar.cpp create mode 100644 kolourpaint/widgets/kpcolortoolbar.h create mode 100644 kolourpaint/widgets/kpresizesignallinglabel.cpp create mode 100644 kolourpaint/widgets/kpresizesignallinglabel.h create mode 100644 kolourpaint/widgets/kpsqueezedtextlabel.cpp create mode 100644 kolourpaint/widgets/kpsqueezedtextlabel.h create mode 100644 kolourpaint/widgets/kptooltoolbar.cpp create mode 100644 kolourpaint/widgets/kptooltoolbar.h create mode 100644 kolourpaint/widgets/kptoolwidgetbase.cpp create mode 100644 kolourpaint/widgets/kptoolwidgetbase.h create mode 100644 kolourpaint/widgets/kptoolwidgetbrush.cpp create mode 100644 kolourpaint/widgets/kptoolwidgetbrush.h create mode 100644 kolourpaint/widgets/kptoolwidgeterasersize.cpp create mode 100644 kolourpaint/widgets/kptoolwidgeterasersize.h create mode 100644 kolourpaint/widgets/kptoolwidgetfillstyle.cpp create mode 100644 kolourpaint/widgets/kptoolwidgetfillstyle.h create mode 100644 kolourpaint/widgets/kptoolwidgetlinewidth.cpp create mode 100644 kolourpaint/widgets/kptoolwidgetlinewidth.h create mode 100644 kolourpaint/widgets/kptoolwidgetopaqueortransparent.cpp create mode 100644 kolourpaint/widgets/kptoolwidgetopaqueortransparent.h create mode 100644 kolourpaint/widgets/kptoolwidgetspraycansize.cpp create mode 100644 kolourpaint/widgets/kptoolwidgetspraycansize.h create mode 100644 kooka/AUTHORS create mode 100644 kooka/CHANGES create mode 100644 kooka/COPYING create mode 100644 kooka/CREDITS create mode 100644 kooka/INSTALL create mode 100644 kooka/Makefile.am create mode 100644 kooka/README create mode 100644 kooka/README.KADMOS create mode 100644 kooka/TODO create mode 100644 kooka/WARNING create mode 100644 kooka/configure.in.in create mode 100644 kooka/dwmenuaction.cpp create mode 100644 kooka/dwmenuaction.h create mode 100644 kooka/formathelp.h create mode 100644 kooka/imageselectline.cpp create mode 100644 kooka/imageselectline.h create mode 100644 kooka/img_saver.cpp create mode 100644 kooka/img_saver.h create mode 100644 kooka/imgnamecombo.cpp create mode 100644 kooka/imgnamecombo.h create mode 100644 kooka/imgprintdialog.cpp create mode 100644 kooka/imgprintdialog.h create mode 100644 kooka/kadmosocr.cpp create mode 100644 kooka/kadmosocr.h create mode 100644 kooka/kocrbase.cpp create mode 100644 kooka/kocrbase.h create mode 100644 kooka/kocrgocr.cpp create mode 100644 kooka/kocrgocr.h create mode 100644 kooka/kocrkadmos.cpp create mode 100644 kooka/kocrkadmos.h create mode 100644 kooka/kocrocrad.cpp create mode 100644 kooka/kocrocrad.h create mode 100644 kooka/kooka.cpp create mode 100644 kooka/kooka.desktop create mode 100644 kooka/kooka.h create mode 100644 kooka/kookaiface.h create mode 100644 kooka/kookaimage.cpp create mode 100644 kooka/kookaimage.h create mode 100644 kooka/kookaimagemeta.cpp create mode 100644 kooka/kookaimagemeta.h create mode 100644 kooka/kookapref.cpp create mode 100644 kooka/kookapref.h create mode 100644 kooka/kookaprint.cpp create mode 100644 kooka/kookaprint.h create mode 100644 kooka/kookarc create mode 100644 kooka/kookaui.rc create mode 100644 kooka/kookaview.cpp create mode 100644 kooka/kookaview.h create mode 100644 kooka/ksaneocr.cpp create mode 100644 kooka/ksaneocr.h create mode 100644 kooka/main.cpp create mode 100644 kooka/ocrresedit.cpp create mode 100644 kooka/ocrresedit.h create mode 100644 kooka/ocrword.cpp create mode 100644 kooka/ocrword.h create mode 100644 kooka/pics/Makefile.am create mode 100644 kooka/pics/gocr.png create mode 100644 kooka/pics/lockzoom.png create mode 100644 kooka/pics/mirror-both.png create mode 100644 kooka/pics/mirror-horiz.png create mode 100644 kooka/pics/mirror-vert.png create mode 100644 kooka/pics/newfromselect.png create mode 100644 kooka/pics/ocr-select.png create mode 100644 kooka/pics/ocr.png create mode 100644 kooka/pics/ocrad.png create mode 100644 kooka/pics/scaleorig.png create mode 100644 kooka/pics/scaletoheight.png create mode 100644 kooka/pics/scaletowidth.png create mode 100644 kooka/pics/thumbviewtile.png create mode 100644 kooka/resource.h create mode 100644 kooka/scanpackager.cpp create mode 100644 kooka/scanpackager.h create mode 100644 kooka/thumbview.cpp create mode 100644 kooka/thumbview.h create mode 100644 kooka/thumbviewitem.cpp create mode 100644 kooka/thumbviewitem.h create mode 100644 kooka/version.h create mode 100644 kpdf/AUTHORS create mode 100644 kpdf/COPYING create mode 100644 kpdf/Makefile.am create mode 100644 kpdf/README.internals.png create mode 100644 kpdf/TODO create mode 100644 kpdf/VERSION create mode 100644 kpdf/conf/Makefile.am create mode 100644 kpdf/conf/dlgaccessibility.ui create mode 100644 kpdf/conf/dlggeneral.ui create mode 100644 kpdf/conf/dlggeneral.ui.h create mode 100644 kpdf/conf/dlgperformance.ui create mode 100644 kpdf/conf/dlgperformance.ui.h create mode 100644 kpdf/conf/dlgpresentation.ui create mode 100644 kpdf/conf/kpdf.kcfg create mode 100644 kpdf/conf/preferencesdialog.cpp create mode 100644 kpdf/conf/preferencesdialog.h create mode 100644 kpdf/conf/settings.kcfgc create mode 100644 kpdf/configure.in.bot create mode 100644 kpdf/configure.in.in create mode 100644 kpdf/core/Makefile.am create mode 100644 kpdf/core/document.cpp create mode 100644 kpdf/core/document.h create mode 100644 kpdf/core/generator.h create mode 100644 kpdf/core/generator_kimgio/Makefile.am create mode 100644 kpdf/core/generator_kimgio/generator_kimgio.cpp create mode 100644 kpdf/core/generator_kimgio/generator_kimgio.h create mode 100644 kpdf/core/generator_pdf/Makefile.am create mode 100644 kpdf/core/generator_pdf/generator_pdf.cpp create mode 100644 kpdf/core/generator_pdf/generator_pdf.h create mode 100644 kpdf/core/generator_pdf/gp_outputdev.cpp create mode 100644 kpdf/core/generator_pdf/gp_outputdev.h create mode 100644 kpdf/core/link.cpp create mode 100644 kpdf/core/link.h create mode 100644 kpdf/core/observer.h create mode 100644 kpdf/core/page.cpp create mode 100644 kpdf/core/page.h create mode 100644 kpdf/core/pagetransition.cpp create mode 100644 kpdf/core/pagetransition.h create mode 100644 kpdf/dcop.h create mode 100644 kpdf/error.cpp create mode 100644 kpdf/hi128-app-kpdf.png create mode 100644 kpdf/hi16-app-kpdf.png create mode 100644 kpdf/hi22-app-kpdf.png create mode 100644 kpdf/hi32-app-kpdf.png create mode 100644 kpdf/hi48-app-kpdf.png create mode 100644 kpdf/hi64-app-kpdf.png create mode 100644 kpdf/hisc-app-kpdf.svgz create mode 100644 kpdf/kpdf_part.desktop create mode 100644 kpdf/part.cpp create mode 100644 kpdf/part.h create mode 100644 kpdf/part.rc create mode 100644 kpdf/shell/Makefile.am create mode 100644 kpdf/shell/kpdf.desktop create mode 100644 kpdf/shell/main.cpp create mode 100644 kpdf/shell/shell.cpp create mode 100644 kpdf/shell/shell.h create mode 100644 kpdf/shell/shell.rc create mode 100644 kpdf/ui/Makefile.am create mode 100644 kpdf/ui/minibar.cpp create mode 100644 kpdf/ui/minibar.h create mode 100644 kpdf/ui/pagepainter.cpp create mode 100644 kpdf/ui/pagepainter.h create mode 100644 kpdf/ui/pageview.cpp create mode 100644 kpdf/ui/pageview.h create mode 100644 kpdf/ui/pageviewutils.cpp create mode 100644 kpdf/ui/pageviewutils.h create mode 100644 kpdf/ui/presentationwidget.cpp create mode 100644 kpdf/ui/presentationwidget.h create mode 100644 kpdf/ui/propertiesdialog.cpp create mode 100644 kpdf/ui/propertiesdialog.h create mode 100644 kpdf/ui/searchwidget.cpp create mode 100644 kpdf/ui/searchwidget.h create mode 100644 kpdf/ui/thumbnaillist.cpp create mode 100644 kpdf/ui/thumbnaillist.h create mode 100644 kpdf/ui/toc.cpp create mode 100644 kpdf/ui/toc.h create mode 100644 kpdf/xpdf/Makefile.am create mode 100644 kpdf/xpdf/README.xpdf create mode 100644 kpdf/xpdf/aconf.h create mode 100644 kpdf/xpdf/fofi/FoFiBase.cc create mode 100644 kpdf/xpdf/fofi/FoFiBase.h create mode 100644 kpdf/xpdf/fofi/FoFiEncodings.cc create mode 100644 kpdf/xpdf/fofi/FoFiEncodings.h create mode 100644 kpdf/xpdf/fofi/FoFiTrueType.cc create mode 100644 kpdf/xpdf/fofi/FoFiTrueType.h create mode 100644 kpdf/xpdf/fofi/FoFiType1.cc create mode 100644 kpdf/xpdf/fofi/FoFiType1.h create mode 100644 kpdf/xpdf/fofi/FoFiType1C.cc create mode 100644 kpdf/xpdf/fofi/FoFiType1C.h create mode 100644 kpdf/xpdf/fofi/Makefile.am create mode 100644 kpdf/xpdf/goo/GHash.cc create mode 100644 kpdf/xpdf/goo/GHash.h create mode 100644 kpdf/xpdf/goo/GList.cc create mode 100644 kpdf/xpdf/goo/GList.h create mode 100644 kpdf/xpdf/goo/GMutex.h create mode 100644 kpdf/xpdf/goo/GString.cc create mode 100644 kpdf/xpdf/goo/GString.h create mode 100644 kpdf/xpdf/goo/Makefile.am create mode 100644 kpdf/xpdf/goo/gfile.cc create mode 100644 kpdf/xpdf/goo/gfile.h create mode 100644 kpdf/xpdf/goo/gmem.cc create mode 100644 kpdf/xpdf/goo/gmem.h create mode 100644 kpdf/xpdf/goo/gmempp.cc create mode 100644 kpdf/xpdf/goo/gtypes.h create mode 100644 kpdf/xpdf/splash/Makefile.am create mode 100644 kpdf/xpdf/splash/Splash.cc create mode 100644 kpdf/xpdf/splash/Splash.h create mode 100644 kpdf/xpdf/splash/SplashBitmap.cc create mode 100644 kpdf/xpdf/splash/SplashBitmap.h create mode 100644 kpdf/xpdf/splash/SplashClip.cc create mode 100644 kpdf/xpdf/splash/SplashClip.h create mode 100644 kpdf/xpdf/splash/SplashErrorCodes.h create mode 100644 kpdf/xpdf/splash/SplashFTFont.cc create mode 100644 kpdf/xpdf/splash/SplashFTFont.h create mode 100644 kpdf/xpdf/splash/SplashFTFontEngine.cc create mode 100644 kpdf/xpdf/splash/SplashFTFontEngine.h create mode 100644 kpdf/xpdf/splash/SplashFTFontFile.cc create mode 100644 kpdf/xpdf/splash/SplashFTFontFile.h create mode 100644 kpdf/xpdf/splash/SplashFont.cc create mode 100644 kpdf/xpdf/splash/SplashFont.h create mode 100644 kpdf/xpdf/splash/SplashFontEngine.cc create mode 100644 kpdf/xpdf/splash/SplashFontEngine.h create mode 100644 kpdf/xpdf/splash/SplashFontFile.cc create mode 100644 kpdf/xpdf/splash/SplashFontFile.h create mode 100644 kpdf/xpdf/splash/SplashFontFileID.cc create mode 100644 kpdf/xpdf/splash/SplashFontFileID.h create mode 100644 kpdf/xpdf/splash/SplashGlyphBitmap.h create mode 100644 kpdf/xpdf/splash/SplashMath.h create mode 100644 kpdf/xpdf/splash/SplashPath.cc create mode 100644 kpdf/xpdf/splash/SplashPath.h create mode 100644 kpdf/xpdf/splash/SplashPattern.cc create mode 100644 kpdf/xpdf/splash/SplashPattern.h create mode 100644 kpdf/xpdf/splash/SplashScreen.cc create mode 100644 kpdf/xpdf/splash/SplashScreen.h create mode 100644 kpdf/xpdf/splash/SplashState.cc create mode 100644 kpdf/xpdf/splash/SplashState.h create mode 100644 kpdf/xpdf/splash/SplashT1Font.cc create mode 100644 kpdf/xpdf/splash/SplashT1Font.h create mode 100644 kpdf/xpdf/splash/SplashT1FontEngine.cc create mode 100644 kpdf/xpdf/splash/SplashT1FontEngine.h create mode 100644 kpdf/xpdf/splash/SplashT1FontFile.cc create mode 100644 kpdf/xpdf/splash/SplashT1FontFile.h create mode 100644 kpdf/xpdf/splash/SplashTypes.h create mode 100644 kpdf/xpdf/splash/SplashXPath.cc create mode 100644 kpdf/xpdf/splash/SplashXPath.h create mode 100644 kpdf/xpdf/splash/SplashXPathScanner.cc create mode 100644 kpdf/xpdf/splash/SplashXPathScanner.h create mode 100644 kpdf/xpdf/xpdf/Annot.cc create mode 100644 kpdf/xpdf/xpdf/Annot.h create mode 100644 kpdf/xpdf/xpdf/Array.cc create mode 100644 kpdf/xpdf/xpdf/Array.h create mode 100644 kpdf/xpdf/xpdf/BuiltinFont.cc create mode 100644 kpdf/xpdf/xpdf/BuiltinFont.h create mode 100644 kpdf/xpdf/xpdf/BuiltinFontTables.cc create mode 100644 kpdf/xpdf/xpdf/BuiltinFontTables.h create mode 100644 kpdf/xpdf/xpdf/CMap.cc create mode 100644 kpdf/xpdf/xpdf/CMap.h create mode 100644 kpdf/xpdf/xpdf/Catalog.cc create mode 100644 kpdf/xpdf/xpdf/Catalog.h create mode 100644 kpdf/xpdf/xpdf/CharCodeToUnicode.cc create mode 100644 kpdf/xpdf/xpdf/CharCodeToUnicode.h create mode 100644 kpdf/xpdf/xpdf/CharTypes.h create mode 100644 kpdf/xpdf/xpdf/CompactFontTables.h create mode 100644 kpdf/xpdf/xpdf/Decrypt.cc create mode 100644 kpdf/xpdf/xpdf/Decrypt.h create mode 100644 kpdf/xpdf/xpdf/Dict.cc create mode 100644 kpdf/xpdf/xpdf/Dict.h create mode 100644 kpdf/xpdf/xpdf/Error.h create mode 100644 kpdf/xpdf/xpdf/ErrorCodes.h create mode 100644 kpdf/xpdf/xpdf/FontEncodingTables.cc create mode 100644 kpdf/xpdf/xpdf/FontEncodingTables.h create mode 100644 kpdf/xpdf/xpdf/Function.cc create mode 100644 kpdf/xpdf/xpdf/Function.h create mode 100644 kpdf/xpdf/xpdf/Gfx.cc create mode 100644 kpdf/xpdf/xpdf/Gfx.h create mode 100644 kpdf/xpdf/xpdf/GfxFont.cc create mode 100644 kpdf/xpdf/xpdf/GfxFont.h create mode 100644 kpdf/xpdf/xpdf/GfxState.cc create mode 100644 kpdf/xpdf/xpdf/GfxState.h create mode 100644 kpdf/xpdf/xpdf/GlobalParams.cc create mode 100644 kpdf/xpdf/xpdf/GlobalParams.h create mode 100644 kpdf/xpdf/xpdf/JArithmeticDecoder.cc create mode 100644 kpdf/xpdf/xpdf/JArithmeticDecoder.h create mode 100644 kpdf/xpdf/xpdf/JBIG2Stream.cc create mode 100644 kpdf/xpdf/xpdf/JBIG2Stream.h create mode 100644 kpdf/xpdf/xpdf/JPXStream.cc create mode 100644 kpdf/xpdf/xpdf/JPXStream.h create mode 100644 kpdf/xpdf/xpdf/Lexer.cc create mode 100644 kpdf/xpdf/xpdf/Lexer.h create mode 100644 kpdf/xpdf/xpdf/Link.cc create mode 100644 kpdf/xpdf/xpdf/Link.h create mode 100644 kpdf/xpdf/xpdf/Makefile.am create mode 100644 kpdf/xpdf/xpdf/NameToCharCode.cc create mode 100644 kpdf/xpdf/xpdf/NameToCharCode.h create mode 100644 kpdf/xpdf/xpdf/NameToUnicodeTable.h create mode 100644 kpdf/xpdf/xpdf/Object.cc create mode 100644 kpdf/xpdf/xpdf/Object.h create mode 100644 kpdf/xpdf/xpdf/Outline.cc create mode 100644 kpdf/xpdf/xpdf/Outline.h create mode 100644 kpdf/xpdf/xpdf/OutputDev.cc create mode 100644 kpdf/xpdf/xpdf/OutputDev.h create mode 100644 kpdf/xpdf/xpdf/PDFDoc.cc create mode 100644 kpdf/xpdf/xpdf/PDFDoc.h create mode 100644 kpdf/xpdf/xpdf/PDFDocEncoding.cc create mode 100644 kpdf/xpdf/xpdf/PDFDocEncoding.h create mode 100644 kpdf/xpdf/xpdf/PSOutputDev.cc create mode 100644 kpdf/xpdf/xpdf/PSOutputDev.h create mode 100644 kpdf/xpdf/xpdf/PSTokenizer.cc create mode 100644 kpdf/xpdf/xpdf/PSTokenizer.h create mode 100644 kpdf/xpdf/xpdf/Page.cc create mode 100644 kpdf/xpdf/xpdf/Page.h create mode 100644 kpdf/xpdf/xpdf/Parser.cc create mode 100644 kpdf/xpdf/xpdf/Parser.h create mode 100644 kpdf/xpdf/xpdf/PreScanOutputDev.cc create mode 100644 kpdf/xpdf/xpdf/PreScanOutputDev.h create mode 100644 kpdf/xpdf/xpdf/SecurityHandler.cc create mode 100644 kpdf/xpdf/xpdf/SecurityHandler.h create mode 100644 kpdf/xpdf/xpdf/SplashOutputDev.cc create mode 100644 kpdf/xpdf/xpdf/SplashOutputDev.h create mode 100644 kpdf/xpdf/xpdf/Stream-CCITT.h create mode 100644 kpdf/xpdf/xpdf/Stream.cc create mode 100644 kpdf/xpdf/xpdf/Stream.h create mode 100644 kpdf/xpdf/xpdf/TextOutputDev.cc create mode 100644 kpdf/xpdf/xpdf/TextOutputDev.h create mode 100644 kpdf/xpdf/xpdf/UTF8.h create mode 100644 kpdf/xpdf/xpdf/UnicodeMap.cc create mode 100644 kpdf/xpdf/xpdf/UnicodeMap.h create mode 100644 kpdf/xpdf/xpdf/UnicodeMapTables.h create mode 100644 kpdf/xpdf/xpdf/UnicodeTypeTable.cc create mode 100644 kpdf/xpdf/xpdf/UnicodeTypeTable.h create mode 100644 kpdf/xpdf/xpdf/XRef.cc create mode 100644 kpdf/xpdf/xpdf/XRef.h create mode 100644 kpdf/xpdf/xpdf/xpdf_config.h create mode 100644 kpovmodeler/AUTHORS create mode 100644 kpovmodeler/BUGS create mode 100644 kpovmodeler/COPYING create mode 100644 kpovmodeler/ChangeLog create mode 100644 kpovmodeler/INSTALL create mode 100644 kpovmodeler/Makefile.am create mode 100644 kpovmodeler/README create mode 100644 kpovmodeler/REQUIREMENTS create mode 100644 kpovmodeler/StyleConvention create mode 100644 kpovmodeler/TODO create mode 100644 kpovmodeler/baseinsertrules.xml create mode 100644 kpovmodeler/configure.in.bot create mode 100644 kpovmodeler/configure.in.in create mode 100644 kpovmodeler/cr16-mime-kpovmodeler_doc.png create mode 100644 kpovmodeler/cr32-mime-kpovmodeler_doc.png create mode 100644 kpovmodeler/cr48-mime-kpovmodeler_doc.png create mode 100644 kpovmodeler/examples/Makefile.am create mode 100644 kpovmodeler/examples/includes/Makefile.am create mode 100644 kpovmodeler/examples/includes/inlined/Makefile.am create mode 100644 kpovmodeler/examples/includes/inlined/chars.kpm create mode 100644 kpovmodeler/examples/includes/inlined/finish.kpm create mode 100644 kpovmodeler/examples/includes/inlined/glass.kpm create mode 100644 kpovmodeler/examples/includes/inlined/golds.kpm create mode 100644 kpovmodeler/examples/includes/inlined/metals.kpm create mode 100644 kpovmodeler/examples/includes/inlined/shapes.kpm create mode 100644 kpovmodeler/examples/includes/inlined/shapes2.kpm create mode 100644 kpovmodeler/examples/includes/inlined/shapesq.kpm create mode 100644 kpovmodeler/examples/includes/inlined/skies.kpm create mode 100644 kpovmodeler/examples/includes/inlined/stars.kpm create mode 100644 kpovmodeler/examples/includes/inlined/stones1.kpm create mode 100644 kpovmodeler/examples/includes/inlined/stones2.kpm create mode 100644 kpovmodeler/examples/includes/inlined/textures.kpm create mode 100644 kpovmodeler/examples/includes/inlined/woods.kpm create mode 100644 kpovmodeler/examples/includes/original/Makefile.am create mode 100644 kpovmodeler/examples/includes/original/chars.kpm create mode 100644 kpovmodeler/examples/includes/original/finish.kpm create mode 100644 kpovmodeler/examples/includes/original/glass.kpm create mode 100644 kpovmodeler/examples/includes/original/golds.kpm create mode 100644 kpovmodeler/examples/includes/original/metals.kpm create mode 100644 kpovmodeler/examples/includes/original/shapes.kpm create mode 100644 kpovmodeler/examples/includes/original/shapes2.kpm create mode 100644 kpovmodeler/examples/includes/original/shapesq.kpm create mode 100644 kpovmodeler/examples/includes/original/skies.kpm create mode 100644 kpovmodeler/examples/includes/original/stars.kpm create mode 100644 kpovmodeler/examples/includes/original/stones1.kpm create mode 100644 kpovmodeler/examples/includes/original/stones2.kpm create mode 100644 kpovmodeler/examples/includes/original/textures.kpm create mode 100644 kpovmodeler/examples/includes/original/woods.kpm create mode 100644 kpovmodeler/examples/scenes/Makefile.am create mode 100644 kpovmodeler/examples/scenes/advanced/Makefile.am create mode 100644 kpovmodeler/examples/scenes/advanced/ants.kpm create mode 100644 kpovmodeler/examples/scenes/advanced/bee.kpm create mode 100644 kpovmodeler/examples/scenes/advanced/ink.kpm create mode 100644 kpovmodeler/examples/scenes/advanced/table.kpm create mode 100644 kpovmodeler/examples/scenes/csg/Makefile.am create mode 100644 kpovmodeler/examples/scenes/csg/cheese.kpm create mode 100644 kpovmodeler/examples/scenes/csg/emptybox.kpm create mode 100644 kpovmodeler/examples/scenes/csg/heightfield.kpm create mode 100644 kpovmodeler/examples/scenes/interior/Makefile.am create mode 100644 kpovmodeler/examples/scenes/interior/cubes.kpm create mode 100644 kpovmodeler/examples/scenes/interior/media1.kpm create mode 100644 kpovmodeler/examples/scenes/interior/media2.kpm create mode 100644 kpovmodeler/examples/scenes/interior/media3.kpm create mode 100644 kpovmodeler/examples/scenes/interior/spheres.kpm create mode 100644 kpovmodeler/examples/scenes/lights/Makefile.am create mode 100644 kpovmodeler/examples/scenes/lights/arealight.kpm create mode 100644 kpovmodeler/examples/scenes/lights/arealight2.kpm create mode 100644 kpovmodeler/examples/scenes/lights/spotlight.kpm create mode 100644 kpovmodeler/examples/scenes/objects/Makefile.am create mode 100644 kpovmodeler/examples/scenes/objects/allobjects.kpm create mode 100644 kpovmodeler/examples/scenes/objects/fractals.kpm create mode 100644 kpovmodeler/examples/scenes/objects/lathe.kpm create mode 100644 kpovmodeler/examples/scenes/objects/prism.kpm create mode 100644 kpovmodeler/examples/scenes/objects/sor.kpm create mode 100644 kpovmodeler/examples/scenes/objects/superellipsoid.kpm create mode 100644 kpovmodeler/examples/scenes/objects/text.kpm create mode 100644 kpovmodeler/hi16-app-kpovmodeler.png create mode 100644 kpovmodeler/hi22-app-kpovmodeler.png create mode 100644 kpovmodeler/hi32-app-kpovmodeler.png create mode 100644 kpovmodeler/hi48-app-kpovmodeler.png create mode 100644 kpovmodeler/kdoc.rules create mode 100644 kpovmodeler/kpovmodeler.desktop create mode 100644 kpovmodeler/kpovmodelerbrowser.rc create mode 100644 kpovmodeler/kpovmodelershell.rc create mode 100644 kpovmodeler/kpovmodelerui.rc create mode 100644 kpovmodeler/main.cpp create mode 100644 kpovmodeler/pics/Makefile.am create mode 100644 kpovmodeler/pics/crystalsvg/Makefile.am create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmaddpoint.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmaddpointabove.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmaddsubprism.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmbicubicpatch.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmblendmapmodifiers.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmblob.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmblobcylinder.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmblobsphere.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmboundedby.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmbox.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmbumpmap.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmcamera.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmclippedby.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmcolorlist.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmcolormap.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmcolormapdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmcomment.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmcone.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmcylinder.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmdensity.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmdensitydeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmdensitylist.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmdensitymap.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmdensitymapdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmdialogview.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmdifference.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmdisc.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmdrag.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmfinish.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmfinishdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmfog.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmfogdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmglobalphotons.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmglobalsettings.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmglview.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmheightfield.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmimagemap.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pminserterrors.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pminsertfirstchild.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pminsertlastchild.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pminsertsibling.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pminterior.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pminteriordeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pminteriortexture.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pminteriortexturedeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmintersection.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmisosurface.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmjuliafractal.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmlathe.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmlight.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmlightgroup.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmlistpattern.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmlookslike.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmmaterial.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmmaterialdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmmaterialmap.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmmatrix.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmmedia.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmmediadeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmmerge.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmmesh.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmnormal.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmnormaldeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmnormallist.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmnormalmap.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmnormalmapdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmobjectdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmobjectlink.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmpattern.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmphotons.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmpigment.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentlist.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentmap.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentmapdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmplane.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmpolynom.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmprism.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmprojectedthrough.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmquickcolor.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmradiosity.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmrainbow.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmrainbowdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmraw.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmremovepoint.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmrender.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmrenderpreview.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmrendersettings.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmrotate.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmscale.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmscene.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmskysphere.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmskyspheredeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmslope.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmslopemap.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmslopemapdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmsolidcolor.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmsor.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmsphere.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmspheresweep.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmsqe.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmtext.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmtexture.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmtexturedeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmtexturelist.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmtexturemap.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmtexturemapdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmtorus.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmtranslate.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmtreeview.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmtriangle.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmunion.png create mode 100644 kpovmodeler/pics/crystalsvg/cr16-action-pmwarp.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmbicubicpatch.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmblendmapmodifiers.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmblob.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmblobcylinder.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmblobsphere.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmboundedby.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmbox.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmbumpmap.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmcamera.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmclippedby.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmcolorlist.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmcolormap.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmcolormapdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmcomment.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmcone.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmconfigurecolors.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguredialogview.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguregraphicalview.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguregrid.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureobjectlibrary.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureobjects.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureopengl.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmconfigurepovray.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguretexturepreview.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureviewlayout.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmcylinder.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmdensity.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmdensitydeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmdensitylist.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmdensitymap.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmdensitymapdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmdifference.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmdisc.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmdrag.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmfinish.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmfinishdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmfog.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmfogdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmglobalphotons.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmglobalsettings.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmheightfield.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmimagemap.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pminserterrors.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pminterior.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pminteriordeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pminteriortexture.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pminteriortexturedeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmintersection.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmisosurface.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmjuliafractal.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmlathe.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmlight.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmlightgroup.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmlistpattern.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmlookslike.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmmaterial.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmmaterialdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmmaterialmap.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmmatrix.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmmedia.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmmediadeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmmerge.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmmesh.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmnormal.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmnormaldeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmnormallist.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmnormalmap.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmnormalmapdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmobjectdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmobjectlink.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmpattern.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmphotons.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmpigment.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentlist.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentmap.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentmapdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmplane.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmpolynom.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmprism.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmprojectedthrough.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmquickcolor.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmradiosity.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmrainbow.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmrainbowdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmraw.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmrender.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmrenderpreview.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmrendersettings.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmrotate.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmscale.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmscene.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmskysphere.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmskyspheredeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmslope.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmslopemap.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmslopemapdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmsolidcolor.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmsor.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmsphere.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmspheresweep.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmsqe.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmtext.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmtexture.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmtexturedeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmtexturelist.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmtexturemap.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmtexturemapdeclare.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmtorus.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmtranslate.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmtriangle.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmunion.png create mode 100644 kpovmodeler/pics/crystalsvg/cr22-action-pmwarp.png create mode 100644 kpovmodeler/pics/locolor/Makefile.am create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmaddpoint.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmaddpointabove.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmaddsubprism.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmbicubicpatch.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmblendmapmodifiers.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmblob.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmblobcylinder.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmblobsphere.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmboundedby.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmbox.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmbumpmap.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmcamera.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmclippedby.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmcomment.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmcone.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmcylinder.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmdeclare.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmdensity.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmdensitydeclare.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmdensitylist.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmdensitymap.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmdensitymapdeclare.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmdifference.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmdisc.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmdrag.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmfog.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmfogdeclare.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmglobalsettings.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmheightfield.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmimagemap.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pminserterrors.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pminsertfirstchild.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pminsertlastchild.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pminsertsibling.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmintersection.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmjuliafractal.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmlathe.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmlight.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmlistpattern.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmlookslike.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmmaterialmap.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmmatrix.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmmerge.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmobjectdeclare.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmobjectlink.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmpigment.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmpigmentdeclare.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmplane.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmpolynom.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmprism.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmquickcolor.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmrainbow.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmrainbowdeclare.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmraw.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmremovepoint.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmrender.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmrenderpreview.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmrendersettings.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmrotate.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmscale.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmscene.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmskysphere.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmskyspheredeclare.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmsolidcolor.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmsor.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmsphere.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmsqr.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmtext.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmtexture.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmtexturedeclare.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmtorus.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmtranslate.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmtriangle.png create mode 100644 kpovmodeler/pics/locolor/lo16-action-pmunion.png create mode 100644 kpovmodeler/pm2dcontrolpoint.cpp create mode 100644 kpovmodeler/pm2dcontrolpoint.h create mode 100644 kpovmodeler/pm3dcontrolpoint.cpp create mode 100644 kpovmodeler/pm3dcontrolpoint.h create mode 100644 kpovmodeler/pmactions.cpp create mode 100644 kpovmodeler/pmactions.h create mode 100644 kpovmodeler/pmaddcommand.cpp create mode 100644 kpovmodeler/pmaddcommand.h create mode 100644 kpovmodeler/pmallcommands.h create mode 100644 kpovmodeler/pmalledits.h create mode 100644 kpovmodeler/pmallobjects.h create mode 100644 kpovmodeler/pmbicubicpatch.cpp create mode 100644 kpovmodeler/pmbicubicpatch.h create mode 100644 kpovmodeler/pmbicubicpatchedit.cpp create mode 100644 kpovmodeler/pmbicubicpatchedit.h create mode 100644 kpovmodeler/pmblendmapmodifiers.cpp create mode 100644 kpovmodeler/pmblendmapmodifiers.h create mode 100644 kpovmodeler/pmblendmapmodifiersedit.cpp create mode 100644 kpovmodeler/pmblendmapmodifiersedit.h create mode 100644 kpovmodeler/pmblob.cpp create mode 100644 kpovmodeler/pmblob.h create mode 100644 kpovmodeler/pmblobcylinder.cpp create mode 100644 kpovmodeler/pmblobcylinder.h create mode 100644 kpovmodeler/pmblobcylinderedit.cpp create mode 100644 kpovmodeler/pmblobcylinderedit.h create mode 100644 kpovmodeler/pmblobedit.cpp create mode 100644 kpovmodeler/pmblobedit.h create mode 100644 kpovmodeler/pmblobsphere.cpp create mode 100644 kpovmodeler/pmblobsphere.h create mode 100644 kpovmodeler/pmblobsphereedit.cpp create mode 100644 kpovmodeler/pmblobsphereedit.h create mode 100644 kpovmodeler/pmboundedby.cpp create mode 100644 kpovmodeler/pmboundedby.h create mode 100644 kpovmodeler/pmboundedbyedit.cpp create mode 100644 kpovmodeler/pmboundedbyedit.h create mode 100644 kpovmodeler/pmbox.cpp create mode 100644 kpovmodeler/pmbox.h create mode 100644 kpovmodeler/pmboxedit.cpp create mode 100644 kpovmodeler/pmboxedit.h create mode 100644 kpovmodeler/pmbumpmap.cpp create mode 100644 kpovmodeler/pmbumpmap.h create mode 100644 kpovmodeler/pmbumpmapedit.cpp create mode 100644 kpovmodeler/pmbumpmapedit.h create mode 100644 kpovmodeler/pmcamera.cpp create mode 100644 kpovmodeler/pmcamera.h create mode 100644 kpovmodeler/pmcameraedit.cpp create mode 100644 kpovmodeler/pmcameraedit.h create mode 100644 kpovmodeler/pmclippedby.cpp create mode 100644 kpovmodeler/pmclippedby.h create mode 100644 kpovmodeler/pmclippedbyedit.cpp create mode 100644 kpovmodeler/pmclippedbyedit.h create mode 100644 kpovmodeler/pmcolor.cpp create mode 100644 kpovmodeler/pmcolor.h create mode 100644 kpovmodeler/pmcoloredit.cpp create mode 100644 kpovmodeler/pmcoloredit.h create mode 100644 kpovmodeler/pmcolorsettings.cpp create mode 100644 kpovmodeler/pmcolorsettings.h create mode 100644 kpovmodeler/pmcommand.h create mode 100644 kpovmodeler/pmcommandmanager.cpp create mode 100644 kpovmodeler/pmcommandmanager.h create mode 100644 kpovmodeler/pmcomment.cpp create mode 100644 kpovmodeler/pmcomment.h create mode 100644 kpovmodeler/pmcommentedit.cpp create mode 100644 kpovmodeler/pmcommentedit.h create mode 100644 kpovmodeler/pmcompositeobject.cpp create mode 100644 kpovmodeler/pmcompositeobject.h create mode 100644 kpovmodeler/pmcone.cpp create mode 100644 kpovmodeler/pmcone.h create mode 100644 kpovmodeler/pmconeedit.cpp create mode 100644 kpovmodeler/pmconeedit.h create mode 100644 kpovmodeler/pmcontrolpoint.cpp create mode 100644 kpovmodeler/pmcontrolpoint.h create mode 100644 kpovmodeler/pmcsg.cpp create mode 100644 kpovmodeler/pmcsg.h create mode 100644 kpovmodeler/pmcsgedit.cpp create mode 100644 kpovmodeler/pmcsgedit.h create mode 100644 kpovmodeler/pmcylinder.cpp create mode 100644 kpovmodeler/pmcylinder.h create mode 100644 kpovmodeler/pmcylinderedit.cpp create mode 100644 kpovmodeler/pmcylinderedit.h create mode 100644 kpovmodeler/pmdatachangecommand.cpp create mode 100644 kpovmodeler/pmdatachangecommand.h create mode 100644 kpovmodeler/pmdebug.h create mode 100644 kpovmodeler/pmdeclare.cpp create mode 100644 kpovmodeler/pmdeclare.h create mode 100644 kpovmodeler/pmdeclareedit.cpp create mode 100644 kpovmodeler/pmdeclareedit.h create mode 100644 kpovmodeler/pmdefaults.h create mode 100644 kpovmodeler/pmdeletecommand.cpp create mode 100644 kpovmodeler/pmdeletecommand.h create mode 100644 kpovmodeler/pmdensity.cpp create mode 100644 kpovmodeler/pmdensity.h create mode 100644 kpovmodeler/pmdensityedit.cpp create mode 100644 kpovmodeler/pmdensityedit.h create mode 100644 kpovmodeler/pmdetailobject.cpp create mode 100644 kpovmodeler/pmdetailobject.h create mode 100644 kpovmodeler/pmdetailobjectedit.cpp create mode 100644 kpovmodeler/pmdetailobjectedit.h create mode 100644 kpovmodeler/pmdialogeditbase.cpp create mode 100644 kpovmodeler/pmdialogeditbase.h create mode 100644 kpovmodeler/pmdialogview.cpp create mode 100644 kpovmodeler/pmdialogview.h create mode 100644 kpovmodeler/pmdisc.cpp create mode 100644 kpovmodeler/pmdisc.h create mode 100644 kpovmodeler/pmdiscedit.cpp create mode 100644 kpovmodeler/pmdiscedit.h create mode 100644 kpovmodeler/pmdistancecontrolpoint.cpp create mode 100644 kpovmodeler/pmdistancecontrolpoint.h create mode 100644 kpovmodeler/pmdockwidget.cpp create mode 100644 kpovmodeler/pmdockwidget.h create mode 100644 kpovmodeler/pmdockwidget_private.cpp create mode 100644 kpovmodeler/pmdockwidget_private.h create mode 100644 kpovmodeler/pmdocumentationmap.cpp create mode 100644 kpovmodeler/pmdocumentationmap.h create mode 100644 kpovmodeler/pmdocumentformat.h create mode 100644 kpovmodeler/pmdragwidget.cpp create mode 100644 kpovmodeler/pmdragwidget.h create mode 100644 kpovmodeler/pmenumproperty.cpp create mode 100644 kpovmodeler/pmenumproperty.h create mode 100644 kpovmodeler/pmerrordialog.cpp create mode 100644 kpovmodeler/pmerrordialog.h create mode 100644 kpovmodeler/pmerrorflags.h create mode 100644 kpovmodeler/pmface.cpp create mode 100644 kpovmodeler/pmface.h create mode 100644 kpovmodeler/pmfactory.cpp create mode 100644 kpovmodeler/pmfactory.h create mode 100644 kpovmodeler/pmfiledialog.cpp create mode 100644 kpovmodeler/pmfiledialog.h create mode 100644 kpovmodeler/pmfinish.cpp create mode 100644 kpovmodeler/pmfinish.h create mode 100644 kpovmodeler/pmfinishedit.cpp create mode 100644 kpovmodeler/pmfinishedit.h create mode 100644 kpovmodeler/pmfog.cpp create mode 100644 kpovmodeler/pmfog.h create mode 100644 kpovmodeler/pmfogedit.cpp create mode 100644 kpovmodeler/pmfogedit.h create mode 100644 kpovmodeler/pmformulalabel.cpp create mode 100644 kpovmodeler/pmformulalabel.h create mode 100644 kpovmodeler/pmglobalphotons.cpp create mode 100644 kpovmodeler/pmglobalphotons.h create mode 100644 kpovmodeler/pmglobalphotonsedit.cpp create mode 100644 kpovmodeler/pmglobalphotonsedit.h create mode 100644 kpovmodeler/pmglobals.h create mode 100644 kpovmodeler/pmglobalsettings.cpp create mode 100644 kpovmodeler/pmglobalsettings.h create mode 100644 kpovmodeler/pmglobalsettingsedit.cpp create mode 100644 kpovmodeler/pmglobalsettingsedit.h create mode 100644 kpovmodeler/pmglview.cpp create mode 100644 kpovmodeler/pmglview.h create mode 100644 kpovmodeler/pmgraphicalobject.cpp create mode 100644 kpovmodeler/pmgraphicalobject.h create mode 100644 kpovmodeler/pmgraphicalobjectedit.cpp create mode 100644 kpovmodeler/pmgraphicalobjectedit.h create mode 100644 kpovmodeler/pmgridsettings.cpp create mode 100644 kpovmodeler/pmgridsettings.h create mode 100644 kpovmodeler/pmheightfield.cpp create mode 100644 kpovmodeler/pmheightfield.h create mode 100644 kpovmodeler/pmheightfieldedit.cpp create mode 100644 kpovmodeler/pmheightfieldedit.h create mode 100644 kpovmodeler/pmheightfieldroam.cpp create mode 100644 kpovmodeler/pmheightfieldroam.h create mode 100644 kpovmodeler/pmimagemap.cpp create mode 100644 kpovmodeler/pmimagemap.h create mode 100644 kpovmodeler/pmimagemapedit.cpp create mode 100644 kpovmodeler/pmimagemapedit.h create mode 100644 kpovmodeler/pminserterrordialog.cpp create mode 100644 kpovmodeler/pminserterrordialog.h create mode 100644 kpovmodeler/pminsertpopup.cpp create mode 100644 kpovmodeler/pminsertpopup.h create mode 100644 kpovmodeler/pminsertrules.dtd create mode 100644 kpovmodeler/pminsertrulesystem.cpp create mode 100644 kpovmodeler/pminsertrulesystem.h create mode 100644 kpovmodeler/pminterior.cpp create mode 100644 kpovmodeler/pminterior.h create mode 100644 kpovmodeler/pminterioredit.cpp create mode 100644 kpovmodeler/pminterioredit.h create mode 100644 kpovmodeler/pminteriortexture.cpp create mode 100644 kpovmodeler/pminteriortexture.h create mode 100644 kpovmodeler/pminteriortextureedit.cpp create mode 100644 kpovmodeler/pminteriortextureedit.h create mode 100644 kpovmodeler/pmiomanager.cpp create mode 100644 kpovmodeler/pmiomanager.h create mode 100644 kpovmodeler/pmisosurface.cpp create mode 100644 kpovmodeler/pmisosurface.h create mode 100644 kpovmodeler/pmisosurfaceedit.cpp create mode 100644 kpovmodeler/pmisosurfaceedit.h create mode 100644 kpovmodeler/pmjuliafractal.cpp create mode 100644 kpovmodeler/pmjuliafractal.h create mode 100644 kpovmodeler/pmjuliafractaledit.cpp create mode 100644 kpovmodeler/pmjuliafractaledit.h create mode 100644 kpovmodeler/pmlathe.cpp create mode 100644 kpovmodeler/pmlathe.h create mode 100644 kpovmodeler/pmlatheedit.cpp create mode 100644 kpovmodeler/pmlatheedit.h create mode 100644 kpovmodeler/pmlayoutsettings.cpp create mode 100644 kpovmodeler/pmlayoutsettings.h create mode 100644 kpovmodeler/pmlibrarybrowser.cpp create mode 100644 kpovmodeler/pmlibrarybrowser.h create mode 100644 kpovmodeler/pmlibraryentrypreview.cpp create mode 100644 kpovmodeler/pmlibraryentrypreview.h create mode 100644 kpovmodeler/pmlibraryhandle.cpp create mode 100644 kpovmodeler/pmlibraryhandle.h create mode 100644 kpovmodeler/pmlibraryhandleedit.cpp create mode 100644 kpovmodeler/pmlibraryhandleedit.h create mode 100644 kpovmodeler/pmlibraryiconview.cpp create mode 100644 kpovmodeler/pmlibraryiconview.h create mode 100644 kpovmodeler/pmlibrarymanager.cpp create mode 100644 kpovmodeler/pmlibrarymanager.h create mode 100644 kpovmodeler/pmlibraryobject.cpp create mode 100644 kpovmodeler/pmlibraryobject.h create mode 100644 kpovmodeler/pmlibraryobjectsearch.cpp create mode 100644 kpovmodeler/pmlibraryobjectsearch.h create mode 100644 kpovmodeler/pmlight.cpp create mode 100644 kpovmodeler/pmlight.h create mode 100644 kpovmodeler/pmlightedit.cpp create mode 100644 kpovmodeler/pmlightedit.h create mode 100644 kpovmodeler/pmlightgroup.cpp create mode 100644 kpovmodeler/pmlightgroup.h create mode 100644 kpovmodeler/pmlightgroupedit.cpp create mode 100644 kpovmodeler/pmlightgroupedit.h create mode 100644 kpovmodeler/pmline.cpp create mode 100644 kpovmodeler/pmline.h create mode 100644 kpovmodeler/pmlineedits.cpp create mode 100644 kpovmodeler/pmlineedits.h create mode 100644 kpovmodeler/pmlinkedit.cpp create mode 100644 kpovmodeler/pmlinkedit.h create mode 100644 kpovmodeler/pmlistpattern.cpp create mode 100644 kpovmodeler/pmlistpattern.h create mode 100644 kpovmodeler/pmlistpatternedit.cpp create mode 100644 kpovmodeler/pmlistpatternedit.h create mode 100644 kpovmodeler/pmlookslike.cpp create mode 100644 kpovmodeler/pmlookslike.h create mode 100644 kpovmodeler/pmmapmemento.cpp create mode 100644 kpovmodeler/pmmapmemento.h create mode 100644 kpovmodeler/pmmaterial.cpp create mode 100644 kpovmodeler/pmmaterial.h create mode 100644 kpovmodeler/pmmaterialedit.cpp create mode 100644 kpovmodeler/pmmaterialedit.h create mode 100644 kpovmodeler/pmmaterialmap.cpp create mode 100644 kpovmodeler/pmmaterialmap.h create mode 100644 kpovmodeler/pmmaterialmapedit.cpp create mode 100644 kpovmodeler/pmmaterialmapedit.h create mode 100644 kpovmodeler/pmmath.cpp create mode 100644 kpovmodeler/pmmath.h create mode 100644 kpovmodeler/pmmatrix.cpp create mode 100644 kpovmodeler/pmmatrix.h create mode 100644 kpovmodeler/pmmedia.cpp create mode 100644 kpovmodeler/pmmedia.h create mode 100644 kpovmodeler/pmmediaedit.cpp create mode 100644 kpovmodeler/pmmediaedit.h create mode 100644 kpovmodeler/pmmemento.cpp create mode 100644 kpovmodeler/pmmemento.h create mode 100644 kpovmodeler/pmmesh.cpp create mode 100644 kpovmodeler/pmmesh.h create mode 100644 kpovmodeler/pmmeshedit.cpp create mode 100644 kpovmodeler/pmmeshedit.h create mode 100644 kpovmodeler/pmmessage.cpp create mode 100644 kpovmodeler/pmmessage.h create mode 100644 kpovmodeler/pmmetaobject.cpp create mode 100644 kpovmodeler/pmmetaobject.h create mode 100644 kpovmodeler/pmmovecommand.cpp create mode 100644 kpovmodeler/pmmovecommand.h create mode 100644 kpovmodeler/pmnamedobject.cpp create mode 100644 kpovmodeler/pmnamedobject.h create mode 100644 kpovmodeler/pmnamedobjectedit.cpp create mode 100644 kpovmodeler/pmnamedobjectedit.h create mode 100644 kpovmodeler/pmnormal.cpp create mode 100644 kpovmodeler/pmnormal.h create mode 100644 kpovmodeler/pmnormaledit.cpp create mode 100644 kpovmodeler/pmnormaledit.h create mode 100644 kpovmodeler/pmobject.cpp create mode 100644 kpovmodeler/pmobject.h create mode 100644 kpovmodeler/pmobjectaction.h create mode 100644 kpovmodeler/pmobjectdrag.cpp create mode 100644 kpovmodeler/pmobjectdrag.h create mode 100644 kpovmodeler/pmobjectlibrarysettings.cpp create mode 100644 kpovmodeler/pmobjectlibrarysettings.h create mode 100644 kpovmodeler/pmobjectlink.cpp create mode 100644 kpovmodeler/pmobjectlink.h create mode 100644 kpovmodeler/pmobjectlinkedit.cpp create mode 100644 kpovmodeler/pmobjectlinkedit.h create mode 100644 kpovmodeler/pmobjectselect.cpp create mode 100644 kpovmodeler/pmobjectselect.h create mode 100644 kpovmodeler/pmobjectsettings.cpp create mode 100644 kpovmodeler/pmobjectsettings.h create mode 100644 kpovmodeler/pmopenglsettings.cpp create mode 100644 kpovmodeler/pmopenglsettings.h create mode 100644 kpovmodeler/pmoutputdevice.cpp create mode 100644 kpovmodeler/pmoutputdevice.h create mode 100644 kpovmodeler/pmpalettevalue.cpp create mode 100644 kpovmodeler/pmpalettevalue.h create mode 100644 kpovmodeler/pmpalettevalueedit.cpp create mode 100644 kpovmodeler/pmpalettevalueedit.h create mode 100644 kpovmodeler/pmpalettevaluememento.cpp create mode 100644 kpovmodeler/pmpalettevaluememento.h create mode 100644 kpovmodeler/pmparser.cpp create mode 100644 kpovmodeler/pmparser.h create mode 100644 kpovmodeler/pmpart.cpp create mode 100644 kpovmodeler/pmpart.h create mode 100644 kpovmodeler/pmpartiface.h create mode 100644 kpovmodeler/pmpattern.cpp create mode 100644 kpovmodeler/pmpattern.h create mode 100644 kpovmodeler/pmpatternedit.cpp create mode 100644 kpovmodeler/pmpatternedit.h create mode 100644 kpovmodeler/pmphotons.cpp create mode 100644 kpovmodeler/pmphotons.h create mode 100644 kpovmodeler/pmphotonsedit.cpp create mode 100644 kpovmodeler/pmphotonsedit.h create mode 100644 kpovmodeler/pmpigment.cpp create mode 100644 kpovmodeler/pmpigment.h create mode 100644 kpovmodeler/pmpigmentedit.cpp create mode 100644 kpovmodeler/pmpigmentedit.h create mode 100644 kpovmodeler/pmplane.cpp create mode 100644 kpovmodeler/pmplane.h create mode 100644 kpovmodeler/pmplaneedit.cpp create mode 100644 kpovmodeler/pmplaneedit.h create mode 100644 kpovmodeler/pmplanenormalcontrolpoint.cpp create mode 100644 kpovmodeler/pmplanenormalcontrolpoint.h create mode 100644 kpovmodeler/pmpluginmanager.cpp create mode 100644 kpovmodeler/pmpluginmanager.h create mode 100644 kpovmodeler/pmpluginsettings.cpp create mode 100644 kpovmodeler/pmpluginsettings.h create mode 100644 kpovmodeler/pmpoint.cpp create mode 100644 kpovmodeler/pmpoint.h create mode 100644 kpovmodeler/pmpolynom.cpp create mode 100644 kpovmodeler/pmpolynom.h create mode 100644 kpovmodeler/pmpolynomedit.cpp create mode 100644 kpovmodeler/pmpolynomedit.h create mode 100644 kpovmodeler/pmpolynomexponents.cpp create mode 100644 kpovmodeler/pmpolynomexponents.h create mode 100644 kpovmodeler/pmpovray31format.cpp create mode 100644 kpovmodeler/pmpovray31format.h create mode 100644 kpovmodeler/pmpovray31serialization.cpp create mode 100644 kpovmodeler/pmpovray31serialization.h create mode 100644 kpovmodeler/pmpovray35format.cpp create mode 100644 kpovmodeler/pmpovray35format.h create mode 100644 kpovmodeler/pmpovray35serialization.cpp create mode 100644 kpovmodeler/pmpovray35serialization.h create mode 100644 kpovmodeler/pmpovrayformat.cpp create mode 100644 kpovmodeler/pmpovrayformat.h create mode 100644 kpovmodeler/pmpovraymatrix.cpp create mode 100644 kpovmodeler/pmpovraymatrix.h create mode 100644 kpovmodeler/pmpovraymatrixedit.cpp create mode 100644 kpovmodeler/pmpovraymatrixedit.h create mode 100644 kpovmodeler/pmpovrayoutputwidget.cpp create mode 100644 kpovmodeler/pmpovrayoutputwidget.h create mode 100644 kpovmodeler/pmpovrayparser.cpp create mode 100644 kpovmodeler/pmpovrayparser.h create mode 100644 kpovmodeler/pmpovrayrenderwidget.cpp create mode 100644 kpovmodeler/pmpovrayrenderwidget.h create mode 100644 kpovmodeler/pmpovraysettings.cpp create mode 100644 kpovmodeler/pmpovraysettings.h create mode 100644 kpovmodeler/pmpovraywidget.cpp create mode 100644 kpovmodeler/pmpovraywidget.h create mode 100644 kpovmodeler/pmpreviewsettings.cpp create mode 100644 kpovmodeler/pmpreviewsettings.h create mode 100644 kpovmodeler/pmprism.cpp create mode 100644 kpovmodeler/pmprism.h create mode 100644 kpovmodeler/pmprismedit.cpp create mode 100644 kpovmodeler/pmprismedit.h create mode 100644 kpovmodeler/pmprismmemento.cpp create mode 100644 kpovmodeler/pmprismmemento.h create mode 100644 kpovmodeler/pmprojectedthrough.cpp create mode 100644 kpovmodeler/pmprojectedthrough.h create mode 100644 kpovmodeler/pmprototypemanager.cpp create mode 100644 kpovmodeler/pmprototypemanager.h create mode 100644 kpovmodeler/pmquickcolor.cpp create mode 100644 kpovmodeler/pmquickcolor.h create mode 100644 kpovmodeler/pmquickcoloredit.cpp create mode 100644 kpovmodeler/pmquickcoloredit.h create mode 100644 kpovmodeler/pmradiosity.cpp create mode 100644 kpovmodeler/pmradiosity.h create mode 100644 kpovmodeler/pmradiosityedit.cpp create mode 100644 kpovmodeler/pmradiosityedit.h create mode 100644 kpovmodeler/pmrainbow.cpp create mode 100644 kpovmodeler/pmrainbow.h create mode 100644 kpovmodeler/pmrainbowedit.cpp create mode 100644 kpovmodeler/pmrainbowedit.h create mode 100644 kpovmodeler/pmraw.cpp create mode 100644 kpovmodeler/pmraw.h create mode 100644 kpovmodeler/pmrawedit.cpp create mode 100644 kpovmodeler/pmrawedit.h create mode 100644 kpovmodeler/pmrecursiveobjectiterator.cpp create mode 100644 kpovmodeler/pmrecursiveobjectiterator.h create mode 100644 kpovmodeler/pmrendermanager.cpp create mode 100644 kpovmodeler/pmrendermanager.h create mode 100644 kpovmodeler/pmrendermode.cpp create mode 100644 kpovmodeler/pmrendermode.h create mode 100644 kpovmodeler/pmrendermodesdialog.cpp create mode 100644 kpovmodeler/pmrendermodesdialog.h create mode 100644 kpovmodeler/pmresourcelocator.cpp create mode 100644 kpovmodeler/pmresourcelocator.h create mode 100644 kpovmodeler/pmrotate.cpp create mode 100644 kpovmodeler/pmrotate.h create mode 100644 kpovmodeler/pmrotatecontrolpoint.cpp create mode 100644 kpovmodeler/pmrotatecontrolpoint.h create mode 100644 kpovmodeler/pmrotateedit.cpp create mode 100644 kpovmodeler/pmrotateedit.h create mode 100644 kpovmodeler/pmscale.cpp create mode 100644 kpovmodeler/pmscale.h create mode 100644 kpovmodeler/pmscalecontrolpoint.cpp create mode 100644 kpovmodeler/pmscalecontrolpoint.h create mode 100644 kpovmodeler/pmscaleedit.cpp create mode 100644 kpovmodeler/pmscaleedit.h create mode 100644 kpovmodeler/pmscanner.cpp create mode 100644 kpovmodeler/pmscanner.h create mode 100644 kpovmodeler/pmscene.cpp create mode 100644 kpovmodeler/pmscene.h create mode 100644 kpovmodeler/pmserializer.cpp create mode 100644 kpovmodeler/pmserializer.h create mode 100644 kpovmodeler/pmsettingsdialog.cpp create mode 100644 kpovmodeler/pmsettingsdialog.h create mode 100644 kpovmodeler/pmshell.cpp create mode 100644 kpovmodeler/pmshell.h create mode 100644 kpovmodeler/pmskysphere.cpp create mode 100644 kpovmodeler/pmskysphere.h create mode 100644 kpovmodeler/pmskysphereedit.cpp create mode 100644 kpovmodeler/pmskysphereedit.h create mode 100644 kpovmodeler/pmslope.cpp create mode 100644 kpovmodeler/pmslope.h create mode 100644 kpovmodeler/pmslopeedit.cpp create mode 100644 kpovmodeler/pmslopeedit.h create mode 100644 kpovmodeler/pmsolidcolor.cpp create mode 100644 kpovmodeler/pmsolidcolor.h create mode 100644 kpovmodeler/pmsolidcoloredit.cpp create mode 100644 kpovmodeler/pmsolidcoloredit.h create mode 100644 kpovmodeler/pmsolidobject.cpp create mode 100644 kpovmodeler/pmsolidobject.h create mode 100644 kpovmodeler/pmsolidobjectedit.cpp create mode 100644 kpovmodeler/pmsolidobjectedit.h create mode 100644 kpovmodeler/pmsor.cpp create mode 100644 kpovmodeler/pmsor.h create mode 100644 kpovmodeler/pmsorcontrolpoint.cpp create mode 100644 kpovmodeler/pmsorcontrolpoint.h create mode 100644 kpovmodeler/pmsoredit.cpp create mode 100644 kpovmodeler/pmsoredit.h create mode 100644 kpovmodeler/pmsorsegment.cpp create mode 100644 kpovmodeler/pmsorsegment.h create mode 100644 kpovmodeler/pmsphere.cpp create mode 100644 kpovmodeler/pmsphere.h create mode 100644 kpovmodeler/pmsphereedit.cpp create mode 100644 kpovmodeler/pmsphereedit.h create mode 100644 kpovmodeler/pmspheresweep.cpp create mode 100644 kpovmodeler/pmspheresweep.h create mode 100644 kpovmodeler/pmspheresweepedit.cpp create mode 100644 kpovmodeler/pmspheresweepedit.h create mode 100644 kpovmodeler/pmsplinememento.cpp create mode 100644 kpovmodeler/pmsplinememento.h create mode 100644 kpovmodeler/pmsplinesegment.cpp create mode 100644 kpovmodeler/pmsplinesegment.h create mode 100644 kpovmodeler/pmsqe.cpp create mode 100644 kpovmodeler/pmsqe.h create mode 100644 kpovmodeler/pmsqeedit.cpp create mode 100644 kpovmodeler/pmsqeedit.h create mode 100644 kpovmodeler/pmsymboltable.cpp create mode 100644 kpovmodeler/pmsymboltable.h create mode 100644 kpovmodeler/pmtext.cpp create mode 100644 kpovmodeler/pmtext.h create mode 100644 kpovmodeler/pmtextedit.cpp create mode 100644 kpovmodeler/pmtextedit.h create mode 100644 kpovmodeler/pmtexture.cpp create mode 100644 kpovmodeler/pmtexture.h create mode 100644 kpovmodeler/pmtexturebase.cpp create mode 100644 kpovmodeler/pmtexturebase.h create mode 100644 kpovmodeler/pmtexturebaseedit.cpp create mode 100644 kpovmodeler/pmtexturebaseedit.h create mode 100644 kpovmodeler/pmtextureedit.cpp create mode 100644 kpovmodeler/pmtextureedit.h create mode 100644 kpovmodeler/pmtexturemap.cpp create mode 100644 kpovmodeler/pmtexturemap.h create mode 100644 kpovmodeler/pmtexturemapedit.cpp create mode 100644 kpovmodeler/pmtexturemapedit.h create mode 100644 kpovmodeler/pmthreestate.h create mode 100644 kpovmodeler/pmtokens.h create mode 100644 kpovmodeler/pmtorus.cpp create mode 100644 kpovmodeler/pmtorus.h create mode 100644 kpovmodeler/pmtorusedit.cpp create mode 100644 kpovmodeler/pmtorusedit.h create mode 100644 kpovmodeler/pmtranslate.cpp create mode 100644 kpovmodeler/pmtranslate.h create mode 100644 kpovmodeler/pmtranslatecontrolpoint.cpp create mode 100644 kpovmodeler/pmtranslatecontrolpoint.h create mode 100644 kpovmodeler/pmtranslateedit.cpp create mode 100644 kpovmodeler/pmtranslateedit.h create mode 100644 kpovmodeler/pmtreeview.cpp create mode 100644 kpovmodeler/pmtreeview.h create mode 100644 kpovmodeler/pmtreeviewitem.cpp create mode 100644 kpovmodeler/pmtreeviewitem.h create mode 100644 kpovmodeler/pmtriangle.cpp create mode 100644 kpovmodeler/pmtriangle.h create mode 100644 kpovmodeler/pmtriangleedit.cpp create mode 100644 kpovmodeler/pmtriangleedit.h create mode 100644 kpovmodeler/pmtruetypecache.cpp create mode 100644 kpovmodeler/pmtruetypecache.h create mode 100644 kpovmodeler/pmunknownview.cpp create mode 100644 kpovmodeler/pmunknownview.h create mode 100644 kpovmodeler/pmvalue.h create mode 100644 kpovmodeler/pmvariant.cpp create mode 100644 kpovmodeler/pmvariant.h create mode 100644 kpovmodeler/pmvector.cpp create mode 100644 kpovmodeler/pmvector.h create mode 100644 kpovmodeler/pmvectorcontrolpoint.cpp create mode 100644 kpovmodeler/pmvectorcontrolpoint.h create mode 100644 kpovmodeler/pmvectoredit.cpp create mode 100644 kpovmodeler/pmvectoredit.h create mode 100644 kpovmodeler/pmvectorlistedit.cpp create mode 100644 kpovmodeler/pmvectorlistedit.h create mode 100644 kpovmodeler/pmview.cpp create mode 100644 kpovmodeler/pmview.h create mode 100644 kpovmodeler/pmviewbase.cpp create mode 100644 kpovmodeler/pmviewbase.h create mode 100644 kpovmodeler/pmviewfactory.cpp create mode 100644 kpovmodeler/pmviewfactory.h create mode 100644 kpovmodeler/pmviewlayoutmanager.cpp create mode 100644 kpovmodeler/pmviewlayoutmanager.h create mode 100644 kpovmodeler/pmviewstructure.cpp create mode 100644 kpovmodeler/pmviewstructure.h create mode 100644 kpovmodeler/pmwarp.cpp create mode 100644 kpovmodeler/pmwarp.h create mode 100644 kpovmodeler/pmwarpedit.cpp create mode 100644 kpovmodeler/pmwarpedit.h create mode 100644 kpovmodeler/pmxmlhelper.cpp create mode 100644 kpovmodeler/pmxmlhelper.h create mode 100644 kpovmodeler/pmxmlparser.cpp create mode 100644 kpovmodeler/pmxmlparser.h create mode 100644 kpovmodeler/povraydocmap.xml create mode 100644 kpovmodeler/questionmark.png create mode 100644 kpovmodeler/version.h create mode 100644 kruler/Makefile.am create mode 100644 kruler/eventsrc create mode 100644 kruler/klineal.cpp create mode 100644 kruler/klineal.h create mode 100644 kruler/kruler.desktop create mode 100644 kruler/main.cpp create mode 100644 kruler/move.wav create mode 100644 kruler/pics/Makefile.am create mode 100644 kruler/pics/hi16-app-kruler.png create mode 100644 kruler/pics/hi22-app-kruler.png create mode 100644 kruler/pics/hi32-app-kruler.png create mode 100644 kruler/pics/hi48-app-kruler.png create mode 100644 kruler/pics/kruler-east.png create mode 100644 kruler/pics/kruler-north.png create mode 100644 kruler/pics/kruler-south.png create mode 100644 kruler/pics/kruler-west.png create mode 100644 kruler/uninstall.desktop create mode 100644 ksnapshot/Makefile.am create mode 100644 ksnapshot/README create mode 100644 ksnapshot/configure.in.in create mode 100644 ksnapshot/hi16-app-ksnapshot.png create mode 100644 ksnapshot/hi22-app-ksnapshot.png create mode 100644 ksnapshot/hi32-app-ksnapshot.png create mode 100644 ksnapshot/hi48-app-ksnapshot.png create mode 100644 ksnapshot/hisc-app-ksnapshot.svgz create mode 100644 ksnapshot/ksnapshot.cpp create mode 100644 ksnapshot/ksnapshot.desktop create mode 100644 ksnapshot/ksnapshot.h create mode 100644 ksnapshot/ksnapshotiface.h create mode 100644 ksnapshot/ksnapshotwidget.ui create mode 100644 ksnapshot/ksnapshotwidget.ui.h create mode 100644 ksnapshot/main.cpp create mode 100644 ksnapshot/regiongrabber.cpp create mode 100644 ksnapshot/regiongrabber.h create mode 100644 ksnapshot/uninstall.desktop create mode 100644 ksnapshot/windowgrabber.cpp create mode 100644 ksnapshot/windowgrabber.h create mode 100644 ksvg/AUTHORS create mode 100644 ksvg/FAQ create mode 100644 ksvg/Makefile.am create mode 100644 ksvg/NEWS create mode 100644 ksvg/README create mode 100644 ksvg/RELEASE-TODO create mode 100644 ksvg/TODO create mode 100644 ksvg/VERSION create mode 100644 ksvg/configure.in.bot create mode 100644 ksvg/configure.in.in create mode 100644 ksvg/core/CanvasFactory.cpp create mode 100644 ksvg/core/CanvasFactory.h create mode 100644 ksvg/core/CanvasItem.h create mode 100644 ksvg/core/CanvasItems.cpp create mode 100644 ksvg/core/CanvasItems.h create mode 100644 ksvg/core/DocumentFactory.cpp create mode 100644 ksvg/core/DocumentFactory.h create mode 100644 ksvg/core/KSVGCanvas.cpp create mode 100644 ksvg/core/KSVGCanvas.h create mode 100644 ksvg/core/KSVGHelper.cpp create mode 100644 ksvg/core/KSVGHelper.h create mode 100644 ksvg/core/KSVGLoader.cpp create mode 100644 ksvg/core/KSVGLoader.h create mode 100644 ksvg/core/KSVGReader.cc create mode 100644 ksvg/core/KSVGReader.h create mode 100644 ksvg/core/KSVGTextChunk.cpp create mode 100644 ksvg/core/KSVGTextChunk.h create mode 100644 ksvg/core/Makefile.am create mode 100644 ksvg/core/ksvgrenderer.desktop create mode 100644 ksvg/data/SVGAElementImpl.lut.h create mode 100644 ksvg/data/SVGAngleImpl.lut.h create mode 100644 ksvg/data/SVGAnimatedAngleImpl.lut.h create mode 100644 ksvg/data/SVGAnimatedBooleanImpl.lut.h create mode 100644 ksvg/data/SVGAnimatedEnumerationImpl.lut.h create mode 100644 ksvg/data/SVGAnimatedIntegerImpl.lut.h create mode 100644 ksvg/data/SVGAnimatedLengthImpl.lut.h create mode 100644 ksvg/data/SVGAnimatedLengthListImpl.lut.h create mode 100644 ksvg/data/SVGAnimatedNumberImpl.lut.h create mode 100644 ksvg/data/SVGAnimatedNumberListImpl.lut.h create mode 100644 ksvg/data/SVGAnimatedPathDataImpl.lut.h create mode 100644 ksvg/data/SVGAnimatedPointsImpl.lut.h create mode 100644 ksvg/data/SVGAnimatedPreserveAspectRatioImpl.lut.h create mode 100644 ksvg/data/SVGAnimatedRectImpl.lut.h create mode 100644 ksvg/data/SVGAnimatedStringImpl.lut.h create mode 100644 ksvg/data/SVGAnimatedTransformListImpl.lut.h create mode 100644 ksvg/data/SVGAnimationElementImpl.lut.h create mode 100644 ksvg/data/SVGCircleElementImpl.lut.h create mode 100644 ksvg/data/SVGClipPathElementImpl.lut.h create mode 100644 ksvg/data/SVGColorImpl.lut.h create mode 100644 ksvg/data/SVGColorProfileElementImpl.lut.h create mode 100644 ksvg/data/SVGCursorElementImpl.lut.h create mode 100644 ksvg/data/SVGDocumentImpl.lut.h create mode 100644 ksvg/data/SVGEcma.lut.h create mode 100644 ksvg/data/SVGElementImpl.lut.h create mode 100644 ksvg/data/SVGEllipseElementImpl.lut.h create mode 100644 ksvg/data/SVGEventImpl.lut.h create mode 100644 ksvg/data/SVGExternalResourcesRequiredImpl.lut.h create mode 100644 ksvg/data/SVGFitToViewBoxImpl.lut.h create mode 100644 ksvg/data/SVGForeignObjectElementImpl.lut.h create mode 100644 ksvg/data/SVGGlyphElementImpl.lut.h create mode 100644 ksvg/data/SVGGlyphRefElementImpl.lut.h create mode 100644 ksvg/data/SVGGradientElementImpl.lut.h create mode 100644 ksvg/data/SVGICCColorImpl.lut.h create mode 100644 ksvg/data/SVGImageElementImpl.lut.h create mode 100644 ksvg/data/SVGLangSpaceImpl.lut.h create mode 100644 ksvg/data/SVGLengthImpl.lut.h create mode 100644 ksvg/data/SVGLengthListImpl.lut.h create mode 100644 ksvg/data/SVGLineElementImpl.lut.h create mode 100644 ksvg/data/SVGLinearGradientElementImpl.lut.h create mode 100644 ksvg/data/SVGLocatableImpl.lut.h create mode 100644 ksvg/data/SVGMarkerElementImpl.lut.h create mode 100644 ksvg/data/SVGMaskElementImpl.lut.h create mode 100644 ksvg/data/SVGMatrixImpl.lut.h create mode 100644 ksvg/data/SVGNumberImpl.lut.h create mode 100644 ksvg/data/SVGNumberListImpl.lut.h create mode 100644 ksvg/data/SVGPaintImpl.lut.h create mode 100644 ksvg/data/SVGPathElementImpl.lut.h create mode 100644 ksvg/data/SVGPathSegArcImpl.lut.h create mode 100644 ksvg/data/SVGPathSegCurvetoCubicImpl.lut.h create mode 100644 ksvg/data/SVGPathSegCurvetoCubicSmoothImpl.lut.h create mode 100644 ksvg/data/SVGPathSegCurvetoQuadraticImpl.lut.h create mode 100644 ksvg/data/SVGPathSegCurvetoQuadraticSmoothImpl.lut.h create mode 100644 ksvg/data/SVGPathSegImpl.lut.h create mode 100644 ksvg/data/SVGPathSegLinetoHorizontalImpl.lut.h create mode 100644 ksvg/data/SVGPathSegLinetoImpl.lut.h create mode 100644 ksvg/data/SVGPathSegLinetoVerticalImpl.lut.h create mode 100644 ksvg/data/SVGPathSegListImpl.lut.h create mode 100644 ksvg/data/SVGPathSegMovetoImpl.lut.h create mode 100644 ksvg/data/SVGPatternElementImpl.lut.h create mode 100644 ksvg/data/SVGPointImpl.lut.h create mode 100644 ksvg/data/SVGPointListImpl.lut.h create mode 100644 ksvg/data/SVGPreserveAspectRatioImpl.lut.h create mode 100644 ksvg/data/SVGRadialGradientElementImpl.lut.h create mode 100644 ksvg/data/SVGRectElementImpl.lut.h create mode 100644 ksvg/data/SVGRectImpl.lut.h create mode 100644 ksvg/data/SVGSVGElementImpl.lut.h create mode 100644 ksvg/data/SVGScriptElementImpl.lut.h create mode 100644 ksvg/data/SVGStopElementImpl.lut.h create mode 100644 ksvg/data/SVGStringListImpl.lut.h create mode 100644 ksvg/data/SVGStylableImpl.lut.h create mode 100644 ksvg/data/SVGStyleElementImpl.lut.h create mode 100644 ksvg/data/SVGSymbolElementImpl.lut.h create mode 100644 ksvg/data/SVGTestsImpl.lut.h create mode 100644 ksvg/data/SVGTextContentElementImpl.lut.h create mode 100644 ksvg/data/SVGTextPathElementImpl.lut.h create mode 100644 ksvg/data/SVGTextPositioningElementImpl.lut.h create mode 100644 ksvg/data/SVGTransformImpl.lut.h create mode 100644 ksvg/data/SVGTransformListImpl.lut.h create mode 100644 ksvg/data/SVGTransformableImpl.lut.h create mode 100644 ksvg/data/SVGURIReferenceImpl.lut.h create mode 100644 ksvg/data/SVGUseElementImpl.lut.h create mode 100644 ksvg/data/SVGViewElementImpl.lut.h create mode 100644 ksvg/data/SVGZoomAndPanImpl.lut.h create mode 100644 ksvg/data/SVGZoomEventImpl.lut.h create mode 100644 ksvg/data/ksvg_window.lut.h create mode 100644 ksvg/dom/Makefile.am create mode 100644 ksvg/dom/SVGAElement.cc create mode 100644 ksvg/dom/SVGAElement.h create mode 100644 ksvg/dom/SVGAltGlyphDefElement.cc create mode 100644 ksvg/dom/SVGAltGlyphDefElement.h create mode 100644 ksvg/dom/SVGAltGlyphElement.cc create mode 100644 ksvg/dom/SVGAltGlyphElement.h create mode 100644 ksvg/dom/SVGAngle.cc create mode 100644 ksvg/dom/SVGAngle.h create mode 100644 ksvg/dom/SVGAnimateColorElement.cc create mode 100644 ksvg/dom/SVGAnimateColorElement.h create mode 100644 ksvg/dom/SVGAnimateElement.cc create mode 100644 ksvg/dom/SVGAnimateElement.h create mode 100644 ksvg/dom/SVGAnimateMotionElement.cc create mode 100644 ksvg/dom/SVGAnimateMotionElement.h create mode 100644 ksvg/dom/SVGAnimateTransformElement.cc create mode 100644 ksvg/dom/SVGAnimateTransformElement.h create mode 100644 ksvg/dom/SVGAnimatedAngle.cc create mode 100644 ksvg/dom/SVGAnimatedAngle.h create mode 100644 ksvg/dom/SVGAnimatedBoolean.cc create mode 100644 ksvg/dom/SVGAnimatedBoolean.h create mode 100644 ksvg/dom/SVGAnimatedEnumeration.cc create mode 100644 ksvg/dom/SVGAnimatedEnumeration.h create mode 100644 ksvg/dom/SVGAnimatedInteger.cc create mode 100644 ksvg/dom/SVGAnimatedInteger.h create mode 100644 ksvg/dom/SVGAnimatedLength.cc create mode 100644 ksvg/dom/SVGAnimatedLength.h create mode 100644 ksvg/dom/SVGAnimatedLengthList.cc create mode 100644 ksvg/dom/SVGAnimatedLengthList.h create mode 100644 ksvg/dom/SVGAnimatedNumber.cc create mode 100644 ksvg/dom/SVGAnimatedNumber.h create mode 100644 ksvg/dom/SVGAnimatedNumberList.cc create mode 100644 ksvg/dom/SVGAnimatedNumberList.h create mode 100644 ksvg/dom/SVGAnimatedPathData.cc create mode 100644 ksvg/dom/SVGAnimatedPathData.h create mode 100644 ksvg/dom/SVGAnimatedPoints.cc create mode 100644 ksvg/dom/SVGAnimatedPoints.h create mode 100644 ksvg/dom/SVGAnimatedPreserveAspectRatio.cc create mode 100644 ksvg/dom/SVGAnimatedPreserveAspectRatio.h create mode 100644 ksvg/dom/SVGAnimatedRect.cc create mode 100644 ksvg/dom/SVGAnimatedRect.h create mode 100644 ksvg/dom/SVGAnimatedString.cc create mode 100644 ksvg/dom/SVGAnimatedString.h create mode 100644 ksvg/dom/SVGAnimatedTransformList.cc create mode 100644 ksvg/dom/SVGAnimatedTransformList.h create mode 100644 ksvg/dom/SVGAnimationElement.cc create mode 100644 ksvg/dom/SVGAnimationElement.h create mode 100644 ksvg/dom/SVGCSSRule.cc create mode 100644 ksvg/dom/SVGCSSRule.h create mode 100644 ksvg/dom/SVGCircleElement.cc create mode 100644 ksvg/dom/SVGCircleElement.h create mode 100644 ksvg/dom/SVGClipPathElement.cc create mode 100644 ksvg/dom/SVGClipPathElement.h create mode 100644 ksvg/dom/SVGColor.cc create mode 100644 ksvg/dom/SVGColor.h create mode 100644 ksvg/dom/SVGColorProfileElement.cc create mode 100644 ksvg/dom/SVGColorProfileElement.h create mode 100644 ksvg/dom/SVGColorProfileRule.cc create mode 100644 ksvg/dom/SVGColorProfileRule.h create mode 100644 ksvg/dom/SVGComponentTransferFunctionElement.cc create mode 100644 ksvg/dom/SVGComponentTransferFunctionElement.h create mode 100644 ksvg/dom/SVGCursorElement.cc create mode 100644 ksvg/dom/SVGCursorElement.h create mode 100644 ksvg/dom/SVGDefinitionSrcElement.cc create mode 100644 ksvg/dom/SVGDefinitionSrcElement.h create mode 100644 ksvg/dom/SVGDefsElement.cc create mode 100644 ksvg/dom/SVGDefsElement.h create mode 100644 ksvg/dom/SVGDescElement.cc create mode 100644 ksvg/dom/SVGDescElement.h create mode 100644 ksvg/dom/SVGDocument.cc create mode 100644 ksvg/dom/SVGDocument.h create mode 100644 ksvg/dom/SVGElement.cc create mode 100644 ksvg/dom/SVGElement.h create mode 100644 ksvg/dom/SVGElementInstance.cc create mode 100644 ksvg/dom/SVGElementInstance.h create mode 100644 ksvg/dom/SVGElementInstanceList.cc create mode 100644 ksvg/dom/SVGElementInstanceList.h create mode 100644 ksvg/dom/SVGEllipseElement.cc create mode 100644 ksvg/dom/SVGEllipseElement.h create mode 100644 ksvg/dom/SVGEvent.cc create mode 100644 ksvg/dom/SVGEvent.h create mode 100644 ksvg/dom/SVGException.h create mode 100644 ksvg/dom/SVGExternalResourcesRequired.cc create mode 100644 ksvg/dom/SVGExternalResourcesRequired.h create mode 100644 ksvg/dom/SVGFEBlendElement.cc create mode 100644 ksvg/dom/SVGFEBlendElement.h create mode 100644 ksvg/dom/SVGFEColorMatrixElement.cc create mode 100644 ksvg/dom/SVGFEColorMatrixElement.h create mode 100644 ksvg/dom/SVGFEComponentTransferElement.cc create mode 100644 ksvg/dom/SVGFEComponentTransferElement.h create mode 100644 ksvg/dom/SVGFECompositeElement.cc create mode 100644 ksvg/dom/SVGFECompositeElement.h create mode 100644 ksvg/dom/SVGFEConvolveMatrixElement.cc create mode 100644 ksvg/dom/SVGFEConvolveMatrixElement.h create mode 100644 ksvg/dom/SVGFEDiffuseLightingElement.cc create mode 100644 ksvg/dom/SVGFEDiffuseLightingElement.h create mode 100644 ksvg/dom/SVGFEDisplacementMapElement.cc create mode 100644 ksvg/dom/SVGFEDisplacementMapElement.h create mode 100644 ksvg/dom/SVGFEDistantLightElement.cc create mode 100644 ksvg/dom/SVGFEDistantLightElement.h create mode 100644 ksvg/dom/SVGFEFloodElement.cc create mode 100644 ksvg/dom/SVGFEFloodElement.h create mode 100644 ksvg/dom/SVGFEFuncAElement.cc create mode 100644 ksvg/dom/SVGFEFuncAElement.h create mode 100644 ksvg/dom/SVGFEFuncBElement.cc create mode 100644 ksvg/dom/SVGFEFuncBElement.h create mode 100644 ksvg/dom/SVGFEFuncGElement.cc create mode 100644 ksvg/dom/SVGFEFuncGElement.h create mode 100644 ksvg/dom/SVGFEFuncRElement.cc create mode 100644 ksvg/dom/SVGFEFuncRElement.h create mode 100644 ksvg/dom/SVGFEGaussianBlurElement.cc create mode 100644 ksvg/dom/SVGFEGaussianBlurElement.h create mode 100644 ksvg/dom/SVGFEImageElement.cc create mode 100644 ksvg/dom/SVGFEImageElement.h create mode 100644 ksvg/dom/SVGFEMergeElement.cc create mode 100644 ksvg/dom/SVGFEMergeElement.h create mode 100644 ksvg/dom/SVGFEMergeNodeElement.cc create mode 100644 ksvg/dom/SVGFEMergeNodeElement.h create mode 100644 ksvg/dom/SVGFEMorphologyElement.cc create mode 100644 ksvg/dom/SVGFEMorphologyElement.h create mode 100644 ksvg/dom/SVGFEOffsetElement.cc create mode 100644 ksvg/dom/SVGFEOffsetElement.h create mode 100644 ksvg/dom/SVGFEPointLightElement.cc create mode 100644 ksvg/dom/SVGFEPointLightElement.h create mode 100644 ksvg/dom/SVGFESpecularLightingElement.cc create mode 100644 ksvg/dom/SVGFESpecularLightingElement.h create mode 100644 ksvg/dom/SVGFESpotLightElement.cc create mode 100644 ksvg/dom/SVGFESpotLightElement.h create mode 100644 ksvg/dom/SVGFETileElement.cc create mode 100644 ksvg/dom/SVGFETileElement.h create mode 100644 ksvg/dom/SVGFETurbulenceElement.cc create mode 100644 ksvg/dom/SVGFETurbulenceElement.h create mode 100644 ksvg/dom/SVGFilterElement.cc create mode 100644 ksvg/dom/SVGFilterElement.h create mode 100644 ksvg/dom/SVGFilterPrimitiveStandardAttributes.cc create mode 100644 ksvg/dom/SVGFilterPrimitiveStandardAttributes.h create mode 100644 ksvg/dom/SVGFitToViewBox.cc create mode 100644 ksvg/dom/SVGFitToViewBox.h create mode 100644 ksvg/dom/SVGFontElement.cc create mode 100644 ksvg/dom/SVGFontElement.h create mode 100644 ksvg/dom/SVGFontFaceElement.cc create mode 100644 ksvg/dom/SVGFontFaceElement.h create mode 100644 ksvg/dom/SVGFontFaceFormatElement.cc create mode 100644 ksvg/dom/SVGFontFaceFormatElement.h create mode 100644 ksvg/dom/SVGFontFaceNameElement.cc create mode 100644 ksvg/dom/SVGFontFaceNameElement.h create mode 100644 ksvg/dom/SVGFontFaceSrcElement.cc create mode 100644 ksvg/dom/SVGFontFaceSrcElement.h create mode 100644 ksvg/dom/SVGFontFaceUriElement.cc create mode 100644 ksvg/dom/SVGFontFaceUriElement.h create mode 100644 ksvg/dom/SVGForeignObjectElement.cc create mode 100644 ksvg/dom/SVGForeignObjectElement.h create mode 100644 ksvg/dom/SVGGElement.cc create mode 100644 ksvg/dom/SVGGElement.h create mode 100644 ksvg/dom/SVGGlyphElement.cc create mode 100644 ksvg/dom/SVGGlyphElement.h create mode 100644 ksvg/dom/SVGGlyphRefElement.cc create mode 100644 ksvg/dom/SVGGlyphRefElement.h create mode 100644 ksvg/dom/SVGGradientElement.cc create mode 100644 ksvg/dom/SVGGradientElement.h create mode 100644 ksvg/dom/SVGHKernElement.cc create mode 100644 ksvg/dom/SVGHKernElement.h create mode 100644 ksvg/dom/SVGICCColor.cc create mode 100644 ksvg/dom/SVGICCColor.h create mode 100644 ksvg/dom/SVGImageElement.cc create mode 100644 ksvg/dom/SVGImageElement.h create mode 100644 ksvg/dom/SVGLangSpace.cc create mode 100644 ksvg/dom/SVGLangSpace.h create mode 100644 ksvg/dom/SVGLength.cc create mode 100644 ksvg/dom/SVGLength.h create mode 100644 ksvg/dom/SVGLengthList.cc create mode 100644 ksvg/dom/SVGLengthList.h create mode 100644 ksvg/dom/SVGLineElement.cc create mode 100644 ksvg/dom/SVGLineElement.h create mode 100644 ksvg/dom/SVGLinearGradientElement.cc create mode 100644 ksvg/dom/SVGLinearGradientElement.h create mode 100644 ksvg/dom/SVGLocatable.cc create mode 100644 ksvg/dom/SVGLocatable.h create mode 100644 ksvg/dom/SVGMPathElement.cc create mode 100644 ksvg/dom/SVGMPathElement.h create mode 100644 ksvg/dom/SVGMarkerElement.cc create mode 100644 ksvg/dom/SVGMarkerElement.h create mode 100644 ksvg/dom/SVGMaskElement.cc create mode 100644 ksvg/dom/SVGMaskElement.h create mode 100644 ksvg/dom/SVGMatrix.cc create mode 100644 ksvg/dom/SVGMatrix.h create mode 100644 ksvg/dom/SVGMetadataElement.cc create mode 100644 ksvg/dom/SVGMetadataElement.h create mode 100644 ksvg/dom/SVGMissingGlyphElement.cc create mode 100644 ksvg/dom/SVGMissingGlyphElement.h create mode 100644 ksvg/dom/SVGNumber.cc create mode 100644 ksvg/dom/SVGNumber.h create mode 100644 ksvg/dom/SVGNumberList.cc create mode 100644 ksvg/dom/SVGNumberList.h create mode 100644 ksvg/dom/SVGPaint.cc create mode 100644 ksvg/dom/SVGPaint.h create mode 100644 ksvg/dom/SVGPathElement.cc create mode 100644 ksvg/dom/SVGPathElement.h create mode 100644 ksvg/dom/SVGPathSeg.cc create mode 100644 ksvg/dom/SVGPathSeg.h create mode 100644 ksvg/dom/SVGPathSegArc.cc create mode 100644 ksvg/dom/SVGPathSegArc.h create mode 100644 ksvg/dom/SVGPathSegClosePath.cc create mode 100644 ksvg/dom/SVGPathSegClosePath.h create mode 100644 ksvg/dom/SVGPathSegCurvetoCubic.cc create mode 100644 ksvg/dom/SVGPathSegCurvetoCubic.h create mode 100644 ksvg/dom/SVGPathSegCurvetoCubicSmooth.cc create mode 100644 ksvg/dom/SVGPathSegCurvetoCubicSmooth.h create mode 100644 ksvg/dom/SVGPathSegCurvetoQuadratic.cc create mode 100644 ksvg/dom/SVGPathSegCurvetoQuadratic.h create mode 100644 ksvg/dom/SVGPathSegCurvetoQuadraticSmooth.cc create mode 100644 ksvg/dom/SVGPathSegCurvetoQuadraticSmooth.h create mode 100644 ksvg/dom/SVGPathSegLineto.cc create mode 100644 ksvg/dom/SVGPathSegLineto.h create mode 100644 ksvg/dom/SVGPathSegLinetoHorizontal.cc create mode 100644 ksvg/dom/SVGPathSegLinetoHorizontal.h create mode 100644 ksvg/dom/SVGPathSegLinetoVertical.cc create mode 100644 ksvg/dom/SVGPathSegLinetoVertical.h create mode 100644 ksvg/dom/SVGPathSegList.cc create mode 100644 ksvg/dom/SVGPathSegList.h create mode 100644 ksvg/dom/SVGPathSegMoveto.cc create mode 100644 ksvg/dom/SVGPathSegMoveto.h create mode 100644 ksvg/dom/SVGPatternElement.cc create mode 100644 ksvg/dom/SVGPatternElement.h create mode 100644 ksvg/dom/SVGPoint.cc create mode 100644 ksvg/dom/SVGPoint.h create mode 100644 ksvg/dom/SVGPointList.cc create mode 100644 ksvg/dom/SVGPointList.h create mode 100644 ksvg/dom/SVGPolygonElement.cc create mode 100644 ksvg/dom/SVGPolygonElement.h create mode 100644 ksvg/dom/SVGPolylineElement.cc create mode 100644 ksvg/dom/SVGPolylineElement.h create mode 100644 ksvg/dom/SVGPreserveAspectRatio.cc create mode 100644 ksvg/dom/SVGPreserveAspectRatio.h create mode 100644 ksvg/dom/SVGRadialGradientElement.cc create mode 100644 ksvg/dom/SVGRadialGradientElement.h create mode 100644 ksvg/dom/SVGRect.cc create mode 100644 ksvg/dom/SVGRect.h create mode 100644 ksvg/dom/SVGRectElement.cc create mode 100644 ksvg/dom/SVGRectElement.h create mode 100644 ksvg/dom/SVGRenderingIntent.h create mode 100644 ksvg/dom/SVGSVGElement.cc create mode 100644 ksvg/dom/SVGSVGElement.h create mode 100644 ksvg/dom/SVGScriptElement.cc create mode 100644 ksvg/dom/SVGScriptElement.h create mode 100644 ksvg/dom/SVGSetElement.cc create mode 100644 ksvg/dom/SVGSetElement.h create mode 100644 ksvg/dom/SVGStopElement.cc create mode 100644 ksvg/dom/SVGStopElement.h create mode 100644 ksvg/dom/SVGStringList.cc create mode 100644 ksvg/dom/SVGStringList.h create mode 100644 ksvg/dom/SVGStylable.cc create mode 100644 ksvg/dom/SVGStylable.h create mode 100644 ksvg/dom/SVGStyleElement.cc create mode 100644 ksvg/dom/SVGStyleElement.h create mode 100644 ksvg/dom/SVGSwitchElement.cc create mode 100644 ksvg/dom/SVGSwitchElement.h create mode 100644 ksvg/dom/SVGSymbolElement.cc create mode 100644 ksvg/dom/SVGSymbolElement.h create mode 100644 ksvg/dom/SVGTRefElement.cc create mode 100644 ksvg/dom/SVGTRefElement.h create mode 100644 ksvg/dom/SVGTSpanElement.cc create mode 100644 ksvg/dom/SVGTSpanElement.h create mode 100644 ksvg/dom/SVGTests.cc create mode 100644 ksvg/dom/SVGTests.h create mode 100644 ksvg/dom/SVGTextContentElement.cc create mode 100644 ksvg/dom/SVGTextContentElement.h create mode 100644 ksvg/dom/SVGTextElement.cc create mode 100644 ksvg/dom/SVGTextElement.h create mode 100644 ksvg/dom/SVGTextPathElement.cc create mode 100644 ksvg/dom/SVGTextPathElement.h create mode 100644 ksvg/dom/SVGTextPositioningElement.cc create mode 100644 ksvg/dom/SVGTextPositioningElement.h create mode 100644 ksvg/dom/SVGTitleElement.cc create mode 100644 ksvg/dom/SVGTitleElement.h create mode 100644 ksvg/dom/SVGTransform.cc create mode 100644 ksvg/dom/SVGTransform.h create mode 100644 ksvg/dom/SVGTransformList.cc create mode 100644 ksvg/dom/SVGTransformList.h create mode 100644 ksvg/dom/SVGTransformable.cc create mode 100644 ksvg/dom/SVGTransformable.h create mode 100644 ksvg/dom/SVGURIReference.cc create mode 100644 ksvg/dom/SVGURIReference.h create mode 100644 ksvg/dom/SVGUnitTypes.h create mode 100644 ksvg/dom/SVGUseElement.cc create mode 100644 ksvg/dom/SVGUseElement.h create mode 100644 ksvg/dom/SVGVKernElement.cc create mode 100644 ksvg/dom/SVGVKernElement.h create mode 100644 ksvg/dom/SVGViewElement.cc create mode 100644 ksvg/dom/SVGViewElement.h create mode 100644 ksvg/dom/SVGViewSpec.cc create mode 100644 ksvg/dom/SVGViewSpec.h create mode 100644 ksvg/dom/SVGWindow.cc create mode 100644 ksvg/dom/SVGWindow.h create mode 100644 ksvg/dom/SVGZoomAndPan.cc create mode 100644 ksvg/dom/SVGZoomAndPan.h create mode 100644 ksvg/dom/SVGZoomEvent.cc create mode 100644 ksvg/dom/SVGZoomEvent.h create mode 100644 ksvg/ecma/Makefile.am create mode 100644 ksvg/ecma/ksvg_bridge.h create mode 100644 ksvg/ecma/ksvg_cacheimpl.h create mode 100644 ksvg/ecma/ksvg_ecma.cpp create mode 100644 ksvg/ecma/ksvg_ecma.h create mode 100644 ksvg/ecma/ksvg_ecmaeventlistener.cpp create mode 100644 ksvg/ecma/ksvg_ecmaeventlistener.h create mode 100644 ksvg/ecma/ksvg_helper.cpp create mode 100644 ksvg/ecma/ksvg_lookup.h create mode 100644 ksvg/ecma/ksvg_scriptinterpreter.cpp create mode 100644 ksvg/ecma/ksvg_scriptinterpreter.h create mode 100644 ksvg/ecma/ksvg_window.cpp create mode 100644 ksvg/ecma/ksvg_window.h create mode 100644 ksvg/impl/LRUCache.h create mode 100644 ksvg/impl/Makefile.am create mode 100644 ksvg/impl/SVGAElementImpl.cc create mode 100644 ksvg/impl/SVGAElementImpl.h create mode 100644 ksvg/impl/SVGAltGlyphDefElementImpl.cc create mode 100644 ksvg/impl/SVGAltGlyphDefElementImpl.h create mode 100644 ksvg/impl/SVGAltGlyphElementImpl.cc create mode 100644 ksvg/impl/SVGAltGlyphElementImpl.h create mode 100644 ksvg/impl/SVGAngleImpl.cc create mode 100644 ksvg/impl/SVGAngleImpl.h create mode 100644 ksvg/impl/SVGAnimateColorElementImpl.cc create mode 100644 ksvg/impl/SVGAnimateColorElementImpl.h create mode 100644 ksvg/impl/SVGAnimateElementImpl.cc create mode 100644 ksvg/impl/SVGAnimateElementImpl.h create mode 100644 ksvg/impl/SVGAnimateMotionElementImpl.cc create mode 100644 ksvg/impl/SVGAnimateMotionElementImpl.h create mode 100644 ksvg/impl/SVGAnimateTransformElementImpl.cc create mode 100644 ksvg/impl/SVGAnimateTransformElementImpl.h create mode 100644 ksvg/impl/SVGAnimatedAngleImpl.cc create mode 100644 ksvg/impl/SVGAnimatedAngleImpl.h create mode 100644 ksvg/impl/SVGAnimatedBooleanImpl.cc create mode 100644 ksvg/impl/SVGAnimatedBooleanImpl.h create mode 100644 ksvg/impl/SVGAnimatedEnumerationImpl.cc create mode 100644 ksvg/impl/SVGAnimatedEnumerationImpl.h create mode 100644 ksvg/impl/SVGAnimatedIntegerImpl.cc create mode 100644 ksvg/impl/SVGAnimatedIntegerImpl.h create mode 100644 ksvg/impl/SVGAnimatedLengthImpl.cc create mode 100644 ksvg/impl/SVGAnimatedLengthImpl.h create mode 100644 ksvg/impl/SVGAnimatedLengthListImpl.cc create mode 100644 ksvg/impl/SVGAnimatedLengthListImpl.h create mode 100644 ksvg/impl/SVGAnimatedNumberImpl.cc create mode 100644 ksvg/impl/SVGAnimatedNumberImpl.h create mode 100644 ksvg/impl/SVGAnimatedNumberListImpl.cc create mode 100644 ksvg/impl/SVGAnimatedNumberListImpl.h create mode 100644 ksvg/impl/SVGAnimatedPathDataImpl.cc create mode 100644 ksvg/impl/SVGAnimatedPathDataImpl.h create mode 100644 ksvg/impl/SVGAnimatedPointsImpl.cc create mode 100644 ksvg/impl/SVGAnimatedPointsImpl.h create mode 100644 ksvg/impl/SVGAnimatedPreserveAspectRatioImpl.cc create mode 100644 ksvg/impl/SVGAnimatedPreserveAspectRatioImpl.h create mode 100644 ksvg/impl/SVGAnimatedRectImpl.cc create mode 100644 ksvg/impl/SVGAnimatedRectImpl.h create mode 100644 ksvg/impl/SVGAnimatedStringImpl.cc create mode 100644 ksvg/impl/SVGAnimatedStringImpl.h create mode 100644 ksvg/impl/SVGAnimatedTransformListImpl.cc create mode 100644 ksvg/impl/SVGAnimatedTransformListImpl.h create mode 100644 ksvg/impl/SVGAnimationElementImpl.cc create mode 100644 ksvg/impl/SVGAnimationElementImpl.h create mode 100644 ksvg/impl/SVGBBoxTarget.cc create mode 100644 ksvg/impl/SVGBBoxTarget.h create mode 100644 ksvg/impl/SVGCSSRuleImpl.cc create mode 100644 ksvg/impl/SVGCSSRuleImpl.h create mode 100644 ksvg/impl/SVGCircleElementImpl.cc create mode 100644 ksvg/impl/SVGCircleElementImpl.h create mode 100644 ksvg/impl/SVGClipPathElementImpl.cc create mode 100644 ksvg/impl/SVGClipPathElementImpl.h create mode 100644 ksvg/impl/SVGColorImpl.cc create mode 100644 ksvg/impl/SVGColorImpl.h create mode 100644 ksvg/impl/SVGColorProfileElementImpl.cc create mode 100644 ksvg/impl/SVGColorProfileElementImpl.h create mode 100644 ksvg/impl/SVGColorProfileRuleImpl.cc create mode 100644 ksvg/impl/SVGColorProfileRuleImpl.h create mode 100644 ksvg/impl/SVGComponentTransferFunctionElementImpl.cc create mode 100644 ksvg/impl/SVGComponentTransferFunctionElementImpl.h create mode 100644 ksvg/impl/SVGContainerImpl.cc create mode 100644 ksvg/impl/SVGContainerImpl.h create mode 100644 ksvg/impl/SVGCursorElementImpl.cc create mode 100644 ksvg/impl/SVGCursorElementImpl.h create mode 100644 ksvg/impl/SVGDefinitionSrcElementImpl.cc create mode 100644 ksvg/impl/SVGDefinitionSrcElementImpl.h create mode 100644 ksvg/impl/SVGDefsElementImpl.cc create mode 100644 ksvg/impl/SVGDefsElementImpl.h create mode 100644 ksvg/impl/SVGDescElementImpl.cc create mode 100644 ksvg/impl/SVGDescElementImpl.h create mode 100644 ksvg/impl/SVGDocumentImpl.cc create mode 100644 ksvg/impl/SVGDocumentImpl.h create mode 100644 ksvg/impl/SVGEcma.cc create mode 100644 ksvg/impl/SVGEcma.h create mode 100644 ksvg/impl/SVGElementImpl.cc create mode 100644 ksvg/impl/SVGElementImpl.h create mode 100644 ksvg/impl/SVGElementInstanceImpl.cc create mode 100644 ksvg/impl/SVGElementInstanceImpl.h create mode 100644 ksvg/impl/SVGElementInstanceListImpl.cc create mode 100644 ksvg/impl/SVGElementInstanceListImpl.h create mode 100644 ksvg/impl/SVGEllipseElementImpl.cc create mode 100644 ksvg/impl/SVGEllipseElementImpl.h create mode 100644 ksvg/impl/SVGEventImpl.cc create mode 100644 ksvg/impl/SVGEventImpl.h create mode 100644 ksvg/impl/SVGExternalResourcesRequiredImpl.cc create mode 100644 ksvg/impl/SVGExternalResourcesRequiredImpl.h create mode 100644 ksvg/impl/SVGFEBlendElementImpl.cc create mode 100644 ksvg/impl/SVGFEBlendElementImpl.h create mode 100644 ksvg/impl/SVGFEColorMatrixElementImpl.cc create mode 100644 ksvg/impl/SVGFEColorMatrixElementImpl.h create mode 100644 ksvg/impl/SVGFEComponentTransferElementImpl.cc create mode 100644 ksvg/impl/SVGFEComponentTransferElementImpl.h create mode 100644 ksvg/impl/SVGFECompositeElementImpl.cc create mode 100644 ksvg/impl/SVGFECompositeElementImpl.h create mode 100644 ksvg/impl/SVGFEConvolveMatrixElementImpl.cc create mode 100644 ksvg/impl/SVGFEConvolveMatrixElementImpl.h create mode 100644 ksvg/impl/SVGFEDiffuseLightingElementImpl.cc create mode 100644 ksvg/impl/SVGFEDiffuseLightingElementImpl.h create mode 100644 ksvg/impl/SVGFEDisplacementMapElementImpl.cc create mode 100644 ksvg/impl/SVGFEDisplacementMapElementImpl.h create mode 100644 ksvg/impl/SVGFEDistantLightElementImpl.cc create mode 100644 ksvg/impl/SVGFEDistantLightElementImpl.h create mode 100644 ksvg/impl/SVGFEFloodElementImpl.cc create mode 100644 ksvg/impl/SVGFEFloodElementImpl.h create mode 100644 ksvg/impl/SVGFEFuncAElementImpl.cc create mode 100644 ksvg/impl/SVGFEFuncAElementImpl.h create mode 100644 ksvg/impl/SVGFEFuncBElementImpl.cc create mode 100644 ksvg/impl/SVGFEFuncBElementImpl.h create mode 100644 ksvg/impl/SVGFEFuncGElementImpl.cc create mode 100644 ksvg/impl/SVGFEFuncGElementImpl.h create mode 100644 ksvg/impl/SVGFEFuncRElementImpl.cc create mode 100644 ksvg/impl/SVGFEFuncRElementImpl.h create mode 100644 ksvg/impl/SVGFEGaussianBlurElementImpl.cc create mode 100644 ksvg/impl/SVGFEGaussianBlurElementImpl.h create mode 100644 ksvg/impl/SVGFEImageElementImpl.cc create mode 100644 ksvg/impl/SVGFEImageElementImpl.h create mode 100644 ksvg/impl/SVGFEMergeElementImpl.cc create mode 100644 ksvg/impl/SVGFEMergeElementImpl.h create mode 100644 ksvg/impl/SVGFEMergeNodeElementImpl.cc create mode 100644 ksvg/impl/SVGFEMergeNodeElementImpl.h create mode 100644 ksvg/impl/SVGFEMorphologyElementImpl.cc create mode 100644 ksvg/impl/SVGFEMorphologyElementImpl.h create mode 100644 ksvg/impl/SVGFEOffsetElementImpl.cc create mode 100644 ksvg/impl/SVGFEOffsetElementImpl.h create mode 100644 ksvg/impl/SVGFEPointLightElementImpl.cc create mode 100644 ksvg/impl/SVGFEPointLightElementImpl.h create mode 100644 ksvg/impl/SVGFESpecularLightingElementImpl.cc create mode 100644 ksvg/impl/SVGFESpecularLightingElementImpl.h create mode 100644 ksvg/impl/SVGFESpotLightElementImpl.cc create mode 100644 ksvg/impl/SVGFESpotLightElementImpl.h create mode 100644 ksvg/impl/SVGFETileElementImpl.cc create mode 100644 ksvg/impl/SVGFETileElementImpl.h create mode 100644 ksvg/impl/SVGFETurbulenceElementImpl.cc create mode 100644 ksvg/impl/SVGFETurbulenceElementImpl.h create mode 100644 ksvg/impl/SVGFilterElementImpl.cc create mode 100644 ksvg/impl/SVGFilterElementImpl.h create mode 100644 ksvg/impl/SVGFilterPrimitiveStandardAttributesImpl.cc create mode 100644 ksvg/impl/SVGFilterPrimitiveStandardAttributesImpl.h create mode 100644 ksvg/impl/SVGFitToViewBoxImpl.cc create mode 100644 ksvg/impl/SVGFitToViewBoxImpl.h create mode 100644 ksvg/impl/SVGFontElementImpl.cc create mode 100644 ksvg/impl/SVGFontElementImpl.h create mode 100644 ksvg/impl/SVGFontFaceElementImpl.cc create mode 100644 ksvg/impl/SVGFontFaceElementImpl.h create mode 100644 ksvg/impl/SVGFontFaceFormatElementImpl.cc create mode 100644 ksvg/impl/SVGFontFaceFormatElementImpl.h create mode 100644 ksvg/impl/SVGFontFaceNameElementImpl.cc create mode 100644 ksvg/impl/SVGFontFaceNameElementImpl.h create mode 100644 ksvg/impl/SVGFontFaceSrcElementImpl.cc create mode 100644 ksvg/impl/SVGFontFaceSrcElementImpl.h create mode 100644 ksvg/impl/SVGFontFaceUriElementImpl.cc create mode 100644 ksvg/impl/SVGFontFaceUriElementImpl.h create mode 100644 ksvg/impl/SVGForeignObjectElementImpl.cc create mode 100644 ksvg/impl/SVGForeignObjectElementImpl.h create mode 100644 ksvg/impl/SVGGElementImpl.cc create mode 100644 ksvg/impl/SVGGElementImpl.h create mode 100644 ksvg/impl/SVGGlyphElementImpl.cc create mode 100644 ksvg/impl/SVGGlyphElementImpl.h create mode 100644 ksvg/impl/SVGGlyphRefElementImpl.cc create mode 100644 ksvg/impl/SVGGlyphRefElementImpl.h create mode 100644 ksvg/impl/SVGGradientElementImpl.cc create mode 100644 ksvg/impl/SVGGradientElementImpl.h create mode 100644 ksvg/impl/SVGHKernElementImpl.cc create mode 100644 ksvg/impl/SVGHKernElementImpl.h create mode 100644 ksvg/impl/SVGHelperImpl.cc create mode 100644 ksvg/impl/SVGHelperImpl.h create mode 100644 ksvg/impl/SVGICCColorImpl.cc create mode 100644 ksvg/impl/SVGICCColorImpl.h create mode 100644 ksvg/impl/SVGImageElementImpl.cc create mode 100644 ksvg/impl/SVGImageElementImpl.h create mode 100644 ksvg/impl/SVGLangSpaceImpl.cc create mode 100644 ksvg/impl/SVGLangSpaceImpl.h create mode 100644 ksvg/impl/SVGLengthImpl.cc create mode 100644 ksvg/impl/SVGLengthImpl.h create mode 100644 ksvg/impl/SVGLengthListImpl.cc create mode 100644 ksvg/impl/SVGLengthListImpl.h create mode 100644 ksvg/impl/SVGLineElementImpl.cc create mode 100644 ksvg/impl/SVGLineElementImpl.h create mode 100644 ksvg/impl/SVGLinearGradientElementImpl.cc create mode 100644 ksvg/impl/SVGLinearGradientElementImpl.h create mode 100644 ksvg/impl/SVGList.h create mode 100644 ksvg/impl/SVGLocatableImpl.cc create mode 100644 ksvg/impl/SVGLocatableImpl.h create mode 100644 ksvg/impl/SVGMPathElementImpl.cc create mode 100644 ksvg/impl/SVGMPathElementImpl.h create mode 100644 ksvg/impl/SVGMarkerElementImpl.cc create mode 100644 ksvg/impl/SVGMarkerElementImpl.h create mode 100644 ksvg/impl/SVGMaskElementImpl.cc create mode 100644 ksvg/impl/SVGMaskElementImpl.h create mode 100644 ksvg/impl/SVGMatrixImpl.cc create mode 100644 ksvg/impl/SVGMatrixImpl.h create mode 100644 ksvg/impl/SVGMetadataElementImpl.cc create mode 100644 ksvg/impl/SVGMetadataElementImpl.h create mode 100644 ksvg/impl/SVGMissingGlyphElementImpl.cc create mode 100644 ksvg/impl/SVGMissingGlyphElementImpl.h create mode 100644 ksvg/impl/SVGNumberImpl.cc create mode 100644 ksvg/impl/SVGNumberImpl.h create mode 100644 ksvg/impl/SVGNumberListImpl.cc create mode 100644 ksvg/impl/SVGNumberListImpl.h create mode 100644 ksvg/impl/SVGPaintImpl.cc create mode 100644 ksvg/impl/SVGPaintImpl.h create mode 100644 ksvg/impl/SVGPaintServerImpl.cc create mode 100644 ksvg/impl/SVGPaintServerImpl.h create mode 100644 ksvg/impl/SVGPathElementImpl.cc create mode 100644 ksvg/impl/SVGPathElementImpl.h create mode 100644 ksvg/impl/SVGPathSegArcImpl.cc create mode 100644 ksvg/impl/SVGPathSegArcImpl.h create mode 100644 ksvg/impl/SVGPathSegClosePathImpl.cc create mode 100644 ksvg/impl/SVGPathSegClosePathImpl.h create mode 100644 ksvg/impl/SVGPathSegCurvetoCubicImpl.cc create mode 100644 ksvg/impl/SVGPathSegCurvetoCubicImpl.h create mode 100644 ksvg/impl/SVGPathSegCurvetoCubicSmoothImpl.cc create mode 100644 ksvg/impl/SVGPathSegCurvetoCubicSmoothImpl.h create mode 100644 ksvg/impl/SVGPathSegCurvetoQuadraticImpl.cc create mode 100644 ksvg/impl/SVGPathSegCurvetoQuadraticImpl.h create mode 100644 ksvg/impl/SVGPathSegCurvetoQuadraticSmoothImpl.cc create mode 100644 ksvg/impl/SVGPathSegCurvetoQuadraticSmoothImpl.h create mode 100644 ksvg/impl/SVGPathSegImpl.cc create mode 100644 ksvg/impl/SVGPathSegImpl.h create mode 100644 ksvg/impl/SVGPathSegLinetoHorizontalImpl.cc create mode 100644 ksvg/impl/SVGPathSegLinetoHorizontalImpl.h create mode 100644 ksvg/impl/SVGPathSegLinetoImpl.cc create mode 100644 ksvg/impl/SVGPathSegLinetoImpl.h create mode 100644 ksvg/impl/SVGPathSegLinetoVerticalImpl.cc create mode 100644 ksvg/impl/SVGPathSegLinetoVerticalImpl.h create mode 100644 ksvg/impl/SVGPathSegListImpl.cc create mode 100644 ksvg/impl/SVGPathSegListImpl.h create mode 100644 ksvg/impl/SVGPathSegMovetoImpl.cc create mode 100644 ksvg/impl/SVGPathSegMovetoImpl.h create mode 100644 ksvg/impl/SVGPatternElementImpl.cc create mode 100644 ksvg/impl/SVGPatternElementImpl.h create mode 100644 ksvg/impl/SVGPointImpl.cc create mode 100644 ksvg/impl/SVGPointImpl.h create mode 100644 ksvg/impl/SVGPointListImpl.cc create mode 100644 ksvg/impl/SVGPointListImpl.h create mode 100644 ksvg/impl/SVGPolyElementImpl.cc create mode 100644 ksvg/impl/SVGPolyElementImpl.h create mode 100644 ksvg/impl/SVGPolygonElementImpl.cc create mode 100644 ksvg/impl/SVGPolygonElementImpl.h create mode 100644 ksvg/impl/SVGPolylineElementImpl.cc create mode 100644 ksvg/impl/SVGPolylineElementImpl.h create mode 100644 ksvg/impl/SVGPreserveAspectRatioImpl.cc create mode 100644 ksvg/impl/SVGPreserveAspectRatioImpl.h create mode 100644 ksvg/impl/SVGRadialGradientElementImpl.cc create mode 100644 ksvg/impl/SVGRadialGradientElementImpl.h create mode 100644 ksvg/impl/SVGRectElementImpl.cc create mode 100644 ksvg/impl/SVGRectElementImpl.h create mode 100644 ksvg/impl/SVGRectImpl.cc create mode 100644 ksvg/impl/SVGRectImpl.h create mode 100644 ksvg/impl/SVGSVGElementImpl.cc create mode 100644 ksvg/impl/SVGSVGElementImpl.h create mode 100644 ksvg/impl/SVGScriptElementImpl.cc create mode 100644 ksvg/impl/SVGScriptElementImpl.h create mode 100644 ksvg/impl/SVGSetElementImpl.cc create mode 100644 ksvg/impl/SVGSetElementImpl.h create mode 100644 ksvg/impl/SVGShapeImpl.cc create mode 100644 ksvg/impl/SVGShapeImpl.h create mode 100644 ksvg/impl/SVGStopElementImpl.cc create mode 100644 ksvg/impl/SVGStopElementImpl.h create mode 100644 ksvg/impl/SVGStringListImpl.cc create mode 100644 ksvg/impl/SVGStringListImpl.h create mode 100644 ksvg/impl/SVGStylableImpl.cc create mode 100644 ksvg/impl/SVGStylableImpl.h create mode 100644 ksvg/impl/SVGStyleElementImpl.cc create mode 100644 ksvg/impl/SVGStyleElementImpl.h create mode 100644 ksvg/impl/SVGSwitchElementImpl.cc create mode 100644 ksvg/impl/SVGSwitchElementImpl.h create mode 100644 ksvg/impl/SVGSymbolElementImpl.cc create mode 100644 ksvg/impl/SVGSymbolElementImpl.h create mode 100644 ksvg/impl/SVGTRefElementImpl.cc create mode 100644 ksvg/impl/SVGTRefElementImpl.h create mode 100644 ksvg/impl/SVGTSpanElementImpl.cc create mode 100644 ksvg/impl/SVGTSpanElementImpl.h create mode 100644 ksvg/impl/SVGTestsImpl.cc create mode 100644 ksvg/impl/SVGTestsImpl.h create mode 100644 ksvg/impl/SVGTextContentElementImpl.cc create mode 100644 ksvg/impl/SVGTextContentElementImpl.h create mode 100644 ksvg/impl/SVGTextElementImpl.cc create mode 100644 ksvg/impl/SVGTextElementImpl.h create mode 100644 ksvg/impl/SVGTextPathElementImpl.cc create mode 100644 ksvg/impl/SVGTextPathElementImpl.h create mode 100644 ksvg/impl/SVGTextPositioningElementImpl.cc create mode 100644 ksvg/impl/SVGTextPositioningElementImpl.h create mode 100644 ksvg/impl/SVGTimeScheduler.cc create mode 100644 ksvg/impl/SVGTimeScheduler.h create mode 100644 ksvg/impl/SVGTitleElementImpl.cc create mode 100644 ksvg/impl/SVGTitleElementImpl.h create mode 100644 ksvg/impl/SVGTransformImpl.cc create mode 100644 ksvg/impl/SVGTransformImpl.h create mode 100644 ksvg/impl/SVGTransformListImpl.cc create mode 100644 ksvg/impl/SVGTransformListImpl.h create mode 100644 ksvg/impl/SVGTransformableImpl.cc create mode 100644 ksvg/impl/SVGTransformableImpl.h create mode 100644 ksvg/impl/SVGURIReferenceImpl.cc create mode 100644 ksvg/impl/SVGURIReferenceImpl.h create mode 100644 ksvg/impl/SVGUnitConverter.h create mode 100644 ksvg/impl/SVGUseElementImpl.cc create mode 100644 ksvg/impl/SVGUseElementImpl.h create mode 100644 ksvg/impl/SVGVKernElementImpl.cc create mode 100644 ksvg/impl/SVGVKernElementImpl.h create mode 100644 ksvg/impl/SVGViewElementImpl.cc create mode 100644 ksvg/impl/SVGViewElementImpl.h create mode 100644 ksvg/impl/SVGViewSpecImpl.cc create mode 100644 ksvg/impl/SVGViewSpecImpl.h create mode 100644 ksvg/impl/SVGWindowImpl.cc create mode 100644 ksvg/impl/SVGWindowImpl.h create mode 100644 ksvg/impl/SVGZoomAndPanImpl.cc create mode 100644 ksvg/impl/SVGZoomAndPanImpl.h create mode 100644 ksvg/impl/SVGZoomEventImpl.cc create mode 100644 ksvg/impl/SVGZoomEventImpl.h create mode 100644 ksvg/impl/TODO create mode 100644 ksvg/impl/generateddata.cpp create mode 100644 ksvg/impl/libs/Makefile.am create mode 100644 ksvg/impl/libs/art_support/Makefile.am create mode 100644 ksvg/impl/libs/art_support/art_misc.c create mode 100644 ksvg/impl/libs/art_support/art_misc.h create mode 100644 ksvg/impl/libs/art_support/art_render_misc.c create mode 100644 ksvg/impl/libs/art_support/art_render_misc.h create mode 100644 ksvg/impl/libs/art_support/art_rgba_svp.c create mode 100644 ksvg/impl/libs/art_support/art_rgba_svp.h create mode 100644 ksvg/impl/libs/libtext2path/AUTHORS create mode 100644 ksvg/impl/libs/libtext2path/COPYING create mode 100644 ksvg/impl/libs/libtext2path/ChangeLog create mode 100644 ksvg/impl/libs/libtext2path/INSTALL create mode 100644 ksvg/impl/libs/libtext2path/Makefile.am create mode 100644 ksvg/impl/libs/libtext2path/NEWS create mode 100644 ksvg/impl/libs/libtext2path/README create mode 100644 ksvg/impl/libs/libtext2path/VERSION create mode 100644 ksvg/impl/libs/libtext2path/configure.in.in create mode 100644 ksvg/impl/libs/libtext2path/libtext2path.lsm create mode 100644 ksvg/impl/libs/libtext2path/libtext2path.pc.in create mode 100644 ksvg/impl/libs/libtext2path/libtext2path.spec create mode 100644 ksvg/impl/libs/libtext2path/src/Affine.cpp create mode 100644 ksvg/impl/libs/libtext2path/src/Affine.h create mode 100644 ksvg/impl/libs/libtext2path/src/BezierPath.h create mode 100644 ksvg/impl/libs/libtext2path/src/Cache.h create mode 100644 ksvg/impl/libs/libtext2path/src/Converter.cpp create mode 100644 ksvg/impl/libs/libtext2path/src/Converter.h create mode 100644 ksvg/impl/libs/libtext2path/src/Font.cpp create mode 100644 ksvg/impl/libs/libtext2path/src/Font.h create mode 100644 ksvg/impl/libs/libtext2path/src/Glyph.cpp create mode 100644 ksvg/impl/libs/libtext2path/src/Glyph.h create mode 100644 ksvg/impl/libs/libtext2path/src/GlyphTracer.cpp create mode 100644 ksvg/impl/libs/libtext2path/src/GlyphTracer.h create mode 100644 ksvg/impl/libs/libtext2path/src/Makefile.am create mode 100644 ksvg/impl/libs/libtext2path/src/Point.h create mode 100644 ksvg/impl/libs/libtext2path/src/QtUnicode.cpp create mode 100644 ksvg/impl/libs/libtext2path/src/QtUnicode.h create mode 100644 ksvg/impl/libs/libtext2path/src/Rectangle.cpp create mode 100644 ksvg/impl/libs/libtext2path/src/Rectangle.h create mode 100644 ksvg/impl/libs/libtext2path/src/Tools.h create mode 100644 ksvg/impl/libs/libtext2path/src/myboost/assert.hpp create mode 100644 ksvg/impl/libs/libtext2path/src/myboost/checked_delete.hpp create mode 100644 ksvg/impl/libs/libtext2path/src/myboost/lightweight_mutex.hpp create mode 100644 ksvg/impl/libs/libtext2path/src/myboost/shared_count.hpp create mode 100644 ksvg/impl/libs/libtext2path/src/myboost/shared_ptr.hpp create mode 100644 ksvg/impl/libs/libtext2path/src/myboost/throw_exception.hpp create mode 100644 ksvg/impl/libs/xrgbrender/Makefile.am create mode 100644 ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib-drawable.c create mode 100644 ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib-private.h create mode 100644 ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib.c create mode 100644 ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib.h create mode 100644 ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlibrgb.c create mode 100644 ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlibrgb.h create mode 100644 ksvg/impl/svgpathparser.cc create mode 100644 ksvg/impl/svgpathparser.h create mode 100644 ksvg/plugin/Makefile.am create mode 100644 ksvg/plugin/backends/Makefile.am create mode 100644 ksvg/plugin/backends/agg/AggCanvas.cpp create mode 100644 ksvg/plugin/backends/agg/AggCanvas.h create mode 100644 ksvg/plugin/backends/agg/AggCanvasFactory.cpp create mode 100644 ksvg/plugin/backends/agg/AggCanvasFactory.h create mode 100644 ksvg/plugin/backends/agg/AggCanvasItems.cpp create mode 100644 ksvg/plugin/backends/agg/AggCanvasItems.h create mode 100644 ksvg/plugin/backends/agg/BezierPathAgg.cpp create mode 100644 ksvg/plugin/backends/agg/BezierPathAgg.h create mode 100644 ksvg/plugin/backends/agg/GlyphTracerAgg.cpp create mode 100644 ksvg/plugin/backends/agg/GlyphTracerAgg.h create mode 100644 ksvg/plugin/backends/agg/Makefile.am create mode 100644 ksvg/plugin/backends/agg/ksvgaggcanvas.desktop create mode 100644 ksvg/plugin/backends/libart/BezierPathLibart.cpp create mode 100644 ksvg/plugin/backends/libart/BezierPathLibart.h create mode 100644 ksvg/plugin/backends/libart/GlyphTracerLibart.cpp create mode 100644 ksvg/plugin/backends/libart/GlyphTracerLibart.h create mode 100644 ksvg/plugin/backends/libart/LibartCanvas.cpp create mode 100644 ksvg/plugin/backends/libart/LibartCanvas.h create mode 100644 ksvg/plugin/backends/libart/LibartCanvasFactory.cpp create mode 100644 ksvg/plugin/backends/libart/LibartCanvasFactory.h create mode 100644 ksvg/plugin/backends/libart/LibartCanvasItems.cpp create mode 100644 ksvg/plugin/backends/libart/LibartCanvasItems.h create mode 100644 ksvg/plugin/backends/libart/Makefile.am create mode 100644 ksvg/plugin/backends/libart/ksvglibartcanvas.desktop create mode 100644 ksvg/plugin/ksvg_factory.cpp create mode 100644 ksvg/plugin/ksvg_factory.h create mode 100644 ksvg/plugin/ksvg_plugin.cpp create mode 100644 ksvg/plugin/ksvg_plugin.h create mode 100644 ksvg/plugin/ksvg_widget.cpp create mode 100644 ksvg/plugin/ksvg_widget.h create mode 100644 ksvg/plugin/ksvgplugin.desktop create mode 100644 ksvg/plugin/ksvgplugin.rc create mode 100644 ksvg/plugin/svgcreator.cpp create mode 100644 ksvg/plugin/svgcreator.h create mode 100644 ksvg/plugin/svgthumbnail.desktop create mode 100644 ksvg/scripts/COPYRIGHTS create mode 100755 ksvg/scripts/ECMACHECK create mode 100755 ksvg/scripts/OPENREF create mode 100644 ksvg/scripts/README create mode 100644 ksvg/scripts/add_static.pl create mode 100755 ksvg/scripts/check_hashtablesize.pl create mode 100755 ksvg/scripts/gen.sh create mode 100755 ksvg/scripts/generate.pl create mode 100755 ksvg/scripts/genimpl.sh create mode 100755 ksvg/scripts/getjs.php create mode 100644 ksvg/scripts/idl/svg.idl create mode 100644 ksvg/scripts/makecc create mode 100644 ksvg/scripts/makeheader create mode 100644 ksvg/scripts/makeimpl create mode 100644 ksvg/test/Makefile.am create mode 100644 ksvg/test/Units.svg create mode 100644 ksvg/test/W3C_TESTSUITE_1.1 create mode 100644 ksvg/test/ZVON-TEST-PASSED create mode 100644 ksvg/test/amflag.svg create mode 100644 ksvg/test/animskew.svg create mode 100644 ksvg/test/arabic.svg create mode 100644 ksvg/test/butterfly.svg create mode 100644 ksvg/test/chem1.svg create mode 100644 ksvg/test/colortest.svg create mode 100644 ksvg/test/dashes.svg create mode 100644 ksvg/test/ecma/bbox/bbox-circle.svg create mode 100644 ksvg/test/ecma/bbox/bbox-ellipse.svg create mode 100644 ksvg/test/ecma/bbox/bbox-line.svg create mode 100644 ksvg/test/ecma/bbox/bbox-path.svg create mode 100644 ksvg/test/ecma/bbox/bbox-path2.svg create mode 100644 ksvg/test/ecma/bbox/bbox-polygon.svg create mode 100644 ksvg/test/ecma/bbox/bbox-polyline.svg create mode 100644 ksvg/test/ecma/bbox/bbox-rect.svg create mode 100644 ksvg/test/ecma/bbox/bbox.js create mode 100644 ksvg/test/ecma/broken.svg create mode 100644 ksvg/test/ecma/circle.svg create mode 100644 ksvg/test/ecma/clock.svg create mode 100644 ksvg/test/ecma/dom01.svg create mode 100644 ksvg/test/external/Makefile.am create mode 100644 ksvg/test/external/SVGTestWidget.cc create mode 100644 ksvg/test/external/SVGTestWidget.h create mode 100644 ksvg/test/external/printnodetest.cpp create mode 100644 ksvg/test/external/printnodetest.h create mode 100644 ksvg/test/external/svgdisplay.cc create mode 100644 ksvg/test/fonttest.svg create mode 100644 ksvg/test/keytest.svg create mode 100644 ksvg/test/lion.svg create mode 100644 ksvg/test/opacity.svg create mode 100644 ksvg/test/physics-motor.svg create mode 100644 ksvg/test/poly.svg create mode 100644 ksvg/test/shapes-rect-trans.svg create mode 100644 ksvg/test/tiger.svg create mode 100644 ksvg/test/tiger2.svg create mode 100644 ksvg/test/tigert.svg create mode 100644 ksvg/test/tux.svg create mode 100644 ksvg/test/tux2.svg create mode 100644 ksvg/test/xlink.svg create mode 100644 kuickshow/AUTHORS create mode 100644 kuickshow/BUGS create mode 100644 kuickshow/COPYING create mode 100644 kuickshow/ChangeLog create mode 100644 kuickshow/Makefile.am create mode 100644 kuickshow/README create mode 100644 kuickshow/TODO create mode 100644 kuickshow/configure.in.bot create mode 100644 kuickshow/configure.in.in create mode 100644 kuickshow/kuickshow.lsm create mode 100644 kuickshow/kuickshow.spec create mode 100644 kuickshow/misc/Makefile.am create mode 100644 kuickshow/misc/im_palette.pal create mode 100644 kuickshow/pics/Makefile.am create mode 100644 kuickshow/pics/about.png create mode 100644 kuickshow/pics/arrows.png create mode 100644 kuickshow/pics/calibrate.png create mode 100644 kuickshow/pics/handcursor.png create mode 100644 kuickshow/pics/imageviewer-medium.png create mode 100644 kuickshow/pics/imageviewer-small.png create mode 100644 kuickshow/pics/ksslide.png create mode 100644 kuickshow/pics/kuickshow-day.jpg create mode 100644 kuickshow/pics/kuickshow-night.jpg create mode 100644 kuickshow/pics/logo.png create mode 100644 kuickshow/src/Makefile.am create mode 100644 kuickshow/src/aboutwidget.cpp create mode 100644 kuickshow/src/aboutwidget.h create mode 100644 kuickshow/src/defaultswidget.cpp create mode 100644 kuickshow/src/defaultswidget.h create mode 100644 kuickshow/src/filecache.cpp create mode 100644 kuickshow/src/filecache.h create mode 100644 kuickshow/src/filefinder.cpp create mode 100644 kuickshow/src/filefinder.h create mode 100644 kuickshow/src/filewidget.cpp create mode 100644 kuickshow/src/filewidget.h create mode 100644 kuickshow/src/generalwidget.cpp create mode 100644 kuickshow/src/generalwidget.h create mode 100644 kuickshow/src/hi16-app-kuickshow.png create mode 100644 kuickshow/src/hi22-app-kuickshow.png create mode 100644 kuickshow/src/hi32-app-kuickshow.png create mode 100644 kuickshow/src/imagewindow.cpp create mode 100644 kuickshow/src/imagewindow.h create mode 100644 kuickshow/src/imdata.cpp create mode 100644 kuickshow/src/imdata.h create mode 100644 kuickshow/src/imlibwidget.cpp create mode 100644 kuickshow/src/imlibwidget.h create mode 100644 kuickshow/src/kuick.cpp create mode 100644 kuickshow/src/kuick.h create mode 100644 kuickshow/src/kuickconfigdlg.cpp create mode 100644 kuickshow/src/kuickconfigdlg.h create mode 100644 kuickshow/src/kuickdata.cpp create mode 100644 kuickshow/src/kuickdata.h create mode 100644 kuickshow/src/kuickfile.cpp create mode 100644 kuickshow/src/kuickfile.h create mode 100644 kuickshow/src/kuickglobals.h create mode 100644 kuickshow/src/kuickimage.cpp create mode 100644 kuickshow/src/kuickimage.h create mode 100644 kuickshow/src/kuickshow.cpp create mode 100644 kuickshow/src/kuickshow.desktop create mode 100644 kuickshow/src/kuickshow.h create mode 100644 kuickshow/src/kurlwidget.cpp create mode 100644 kuickshow/src/kurlwidget.h create mode 100644 kuickshow/src/main.cpp create mode 100644 kuickshow/src/mainwidget.cpp create mode 100644 kuickshow/src/mainwidget.h create mode 100644 kuickshow/src/printing.cpp create mode 100644 kuickshow/src/printing.h create mode 100644 kuickshow/src/slideshowwidget.cpp create mode 100644 kuickshow/src/slideshowwidget.h create mode 100644 kuickshow/src/version.h create mode 100644 kview/AUTHORS create mode 100644 kview/ChangeLog create mode 100644 kview/Makefile.am create mode 100644 kview/TODO create mode 100644 kview/config/Makefile.am create mode 100644 kview/config/kview.setdlg create mode 100644 kview/config/kviewconfmodules.cpp create mode 100644 kview/config/kviewconfmodules.h create mode 100644 kview/config/kviewgeneralconfig.desktop create mode 100644 kview/config/plugins/Makefile.am create mode 100644 kview/config/plugins/kviewpluginsconfig.cpp create mode 100644 kview/config/plugins/kviewpluginsconfig.desktop create mode 100644 kview/config/plugins/kviewpluginsconfig.h create mode 100644 kview/hi16-app-kview.png create mode 100644 kview/hi22-app-kview.png create mode 100644 kview/hi32-app-kview.png create mode 100644 kview/hi48-app-kview.png create mode 100644 kview/kimageviewer/Makefile.am create mode 100644 kview/kimageviewer/canvas.cpp create mode 100644 kview/kimageviewer/canvas.h create mode 100644 kview/kimageviewer/kimageviewer.desktop create mode 100644 kview/kimageviewer/kimageviewercanvas.desktop create mode 100644 kview/kimageviewer/viewer.cpp create mode 100644 kview/kimageviewer/viewer.h create mode 100644 kview/kview.cpp create mode 100644 kview/kview.desktop create mode 100644 kview/kview.h create mode 100644 kview/kviewcanvas/ChangeLog create mode 100644 kview/kviewcanvas/Makefile.am create mode 100644 kview/kviewcanvas/config/Makefile.am create mode 100644 kview/kviewcanvas/config/confmodules.cpp create mode 100644 kview/kviewcanvas/config/confmodules.h create mode 100644 kview/kviewcanvas/config/defaults.h create mode 100644 kview/kviewcanvas/config/generalconfigwidget.ui create mode 100644 kview/kviewcanvas/config/kviewcanvasconfig.desktop create mode 100644 kview/kviewcanvas/kimagecanvas.cpp create mode 100644 kview/kviewcanvas/kimagecanvas.h create mode 100644 kview/kviewcanvas/kimageholder.cpp create mode 100644 kview/kviewcanvas/kimageholder.h create mode 100644 kview/kviewcanvas/kviewcanvas.desktop create mode 100644 kview/kviewcanvas/test/Makefile.am create mode 100644 kview/kviewcanvas/test/main.cpp create mode 100644 kview/kviewcanvas/test/test.cpp create mode 100644 kview/kviewcanvas/test/test.h create mode 100644 kview/kviewui.rc create mode 100644 kview/kviewviewer/ChangeLog create mode 100644 kview/kviewviewer/Makefile.am create mode 100644 kview/kviewviewer/config/Makefile.am create mode 100644 kview/kviewviewer/config/kviewviewerpluginsconfig.cpp create mode 100644 kview/kviewviewer/config/kviewviewerpluginsconfig.desktop create mode 100644 kview/kviewviewer/config/kviewviewerpluginsconfig.h create mode 100644 kview/kviewviewer/imagesettings.cpp create mode 100644 kview/kviewviewer/imagesettings.h create mode 100644 kview/kviewviewer/kviewkonqextension.cpp create mode 100644 kview/kviewviewer/kviewkonqextension.h create mode 100644 kview/kviewviewer/kviewpopup.rc create mode 100644 kview/kviewviewer/kviewviewer.cpp create mode 100644 kview/kviewviewer/kviewviewer.desktop create mode 100644 kview/kviewviewer/kviewviewer.h create mode 100644 kview/kviewviewer/kviewviewer.rc create mode 100644 kview/kviewviewer/kviewviewer_ro.rc create mode 100644 kview/kviewviewer/kviewvieweriface.h create mode 100644 kview/kviewviewer/printimagesettings.ui create mode 100644 kview/kviewviewer/test/Makefile.am create mode 100644 kview/kviewviewer/test/main.cpp create mode 100644 kview/kviewviewer/test/test.cpp create mode 100644 kview/kviewviewer/test/test.h create mode 100644 kview/main.cpp create mode 100644 kview/modules/Makefile.am create mode 100644 kview/modules/NAMING create mode 100644 kview/modules/README create mode 100644 kview/modules/browser/Makefile.am create mode 100644 kview/modules/browser/kmyfileitemlist.cpp create mode 100644 kview/modules/browser/kmyfileitemlist.h create mode 100644 kview/modules/browser/kviewbrowser.cpp create mode 100644 kview/modules/browser/kviewbrowser.desktop create mode 100644 kview/modules/browser/kviewbrowser.h create mode 100644 kview/modules/browser/kviewbrowser.rc create mode 100644 kview/modules/effects/Makefile.am create mode 100644 kview/modules/effects/kvieweffects.cpp create mode 100644 kview/modules/effects/kvieweffects.desktop create mode 100644 kview/modules/effects/kvieweffects.h create mode 100644 kview/modules/effects/kvieweffects.rc create mode 100644 kview/modules/presenter/DESIGN create mode 100644 kview/modules/presenter/Makefile.am create mode 100644 kview/modules/presenter/config/Makefile.am create mode 100644 kview/modules/presenter/config/kviewpresenterconfig.cpp create mode 100644 kview/modules/presenter/config/kviewpresenterconfig.desktop create mode 100644 kview/modules/presenter/config/kviewpresenterconfig.h create mode 100644 kview/modules/presenter/imagelistdialog.ui create mode 100644 kview/modules/presenter/imagelistdialog.ui.h create mode 100644 kview/modules/presenter/imagelistitem.cpp create mode 100644 kview/modules/presenter/imagelistitem.h create mode 100644 kview/modules/presenter/kviewpresenter.cpp create mode 100644 kview/modules/presenter/kviewpresenter.desktop create mode 100644 kview/modules/presenter/kviewpresenter.h create mode 100644 kview/modules/presenter/kviewpresenter.rc create mode 100644 kview/modules/presenter/kviewpresenterconfmodule.cpp create mode 100644 kview/modules/presenter/kviewpresenterconfmodule.h create mode 100644 kview/modules/scale/Makefile.am create mode 100644 kview/modules/scale/kfloatspinbox.cpp create mode 100644 kview/modules/scale/kfloatspinbox.h create mode 100644 kview/modules/scale/kview_scale.cpp create mode 100644 kview/modules/scale/kview_scale.desktop create mode 100644 kview/modules/scale/kview_scale.h create mode 100644 kview/modules/scale/kview_scale.rc create mode 100644 kview/modules/scale/scaledlg.cpp create mode 100644 kview/modules/scale/scaledlg.h create mode 100644 kview/modules/scanner/Makefile.am create mode 100644 kview/modules/scanner/kviewscanner.cpp create mode 100644 kview/modules/scanner/kviewscanner.desktop create mode 100644 kview/modules/scanner/kviewscanner.h create mode 100644 kview/modules/scanner/kviewscanner.rc create mode 100644 kview/modules/template/Makefile.am create mode 100644 kview/modules/template/kviewtemplate.cpp create mode 100644 kview/modules/template/kviewtemplate.desktop create mode 100644 kview/modules/template/kviewtemplate.h create mode 100644 kview/modules/template/kviewtemplate.rc create mode 100644 kview/photobook/Makefile.am create mode 100644 kview/photobook/cr16-app-photobook.png create mode 100644 kview/photobook/cr22-app-photobook.png create mode 100644 kview/photobook/photobook.cpp create mode 100644 kview/photobook/photobook.desktop create mode 100644 kview/photobook/photobook.h create mode 100644 kview/photobook/photobookui.rc create mode 100644 kview/version.h create mode 100644 kviewshell/DESIGN create mode 100644 kviewshell/Mainpage.dox create mode 100644 kviewshell/Makefile.am create mode 100644 kviewshell/TODO create mode 100644 kviewshell/anchor.h create mode 100644 kviewshell/bookmark.h create mode 100644 kviewshell/documentPageCache.cpp create mode 100644 kviewshell/documentPageCache.h create mode 100644 kviewshell/documentRenderer.cpp create mode 100644 kviewshell/documentRenderer.h create mode 100644 kviewshell/documentWidget.cpp create mode 100644 kviewshell/documentWidget.h create mode 100644 kviewshell/emptyRenderer.cpp create mode 100644 kviewshell/emptyRenderer.h create mode 100644 kviewshell/empty_multipage.cpp create mode 100644 kviewshell/empty_multipage.h create mode 100644 kviewshell/emptymultipage.desktop create mode 100644 kviewshell/history.cpp create mode 100644 kviewshell/history.h create mode 100644 kviewshell/hyperlink.h create mode 100644 kviewshell/kmultipage.cpp create mode 100644 kviewshell/kmultipage.desktop create mode 100644 kviewshell/kmultipage.h create mode 100644 kviewshell/kmultipageInterface.h create mode 100644 kviewshell/kprintDialogPage_pageoptions.cpp create mode 100644 kviewshell/kprintDialogPage_pageoptions.h create mode 100644 kviewshell/kviewerpart.rc create mode 100644 kviewshell/kviewpart.cpp create mode 100644 kviewshell/kviewpart.h create mode 100644 kviewshell/kviewpart_iface.cpp create mode 100644 kviewshell/kviewpart_iface.h create mode 100644 kviewshell/kviewshell.cpp create mode 100644 kviewshell/kviewshell.h create mode 100644 kviewshell/kviewshell.kcfg create mode 100644 kviewshell/kviewshell.rc create mode 100644 kviewshell/kvsprefs.kcfgc create mode 100644 kviewshell/length.h create mode 100644 kviewshell/main.cpp create mode 100644 kviewshell/marklist.cpp create mode 100644 kviewshell/marklist.h create mode 100644 kviewshell/optionDialogAccessibilityWidget.ui create mode 100644 kviewshell/optionDialogGUIWidget_base.ui create mode 100644 kviewshell/pageNumber.h create mode 100644 kviewshell/pageSize.cpp create mode 100644 kviewshell/pageSize.h create mode 100644 kviewshell/pageSizeDialog.cpp create mode 100644 kviewshell/pageSizeDialog.h create mode 100644 kviewshell/pageSizeWidget.cpp create mode 100644 kviewshell/pageSizeWidget.h create mode 100644 kviewshell/pageSizeWidget_base.ui create mode 100644 kviewshell/pageView.cpp create mode 100644 kviewshell/pageView.h create mode 100644 kviewshell/pics/Makefile.am create mode 100644 kviewshell/pics/cr16-app-kviewshell.png create mode 100644 kviewshell/pics/cr32-app-kviewshell.png create mode 100644 kviewshell/pics/cr48-app-kviewshell.png create mode 100644 kviewshell/pics/icons/Makefile.am create mode 100644 kviewshell/pics/icons/hi16-action-movetool.png create mode 100644 kviewshell/pics/icons/hi16-action-selectiontool.png create mode 100644 kviewshell/pics/icons/hi22-action-movetool.png create mode 100644 kviewshell/pics/icons/hi22-action-selectiontool.png create mode 100644 kviewshell/pics/icons/hi32-action-movetool.png create mode 100644 kviewshell/pics/icons/hi48-action-movetool.png create mode 100644 kviewshell/plugins/Makefile.am create mode 100644 kviewshell/plugins/djvu/Makefile.am create mode 100644 kviewshell/plugins/djvu/djvumultipage.cpp create mode 100644 kviewshell/plugins/djvu/djvumultipage.desktop create mode 100644 kviewshell/plugins/djvu/djvumultipage.h create mode 100644 kviewshell/plugins/djvu/djvumultipage.kcfg create mode 100644 kviewshell/plugins/djvu/djvumultipage.rc create mode 100644 kviewshell/plugins/djvu/djvurenderer.cpp create mode 100644 kviewshell/plugins/djvu/djvurenderer.h create mode 100644 kviewshell/plugins/djvu/kprintDialogPage_DJVUconversionoptions.cpp create mode 100644 kviewshell/plugins/djvu/kprintDialogPage_DJVUconversionoptions.h create mode 100644 kviewshell/plugins/djvu/kprintDialogPage_DJVUconversionoptions_basewidget.ui create mode 100644 kviewshell/plugins/djvu/kprintDialogPage_DJVUpageoptions.cpp create mode 100644 kviewshell/plugins/djvu/kprintDialogPage_DJVUpageoptions.h create mode 100644 kviewshell/plugins/djvu/libdjvu/Arrays.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/Arrays.h create mode 100644 kviewshell/plugins/djvu/libdjvu/BSByteStream.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/BSByteStream.h create mode 100644 kviewshell/plugins/djvu/libdjvu/BSEncodeByteStream.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/ByteStream.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/ByteStream.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DataPool.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DataPool.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVmDir.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVmDir.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVmDir0.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVmDir0.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVmDoc.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVmDoc.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVmNav.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVmNav.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuAnno.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuAnno.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuDocEditor.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuDocEditor.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuDocument.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuDocument.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuDumpHelper.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuDumpHelper.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuErrorList.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuErrorList.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuFile.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuFile.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuFileCache.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuFileCache.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuGlobal.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuGlobal.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuGlobalMemory.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuImage.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuImage.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuInfo.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuInfo.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuMessage.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuMessage.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuMessageLite.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuMessageLite.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuNavDir.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuNavDir.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuPalette.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuPalette.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuPort.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuPort.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuText.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuText.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuToPS.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuToPS.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GBitmap.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GBitmap.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GContainer.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GContainer.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GException.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GException.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GIFFManager.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GIFFManager.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GMapAreas.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GMapAreas.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GOS.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GOS.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GPixmap.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GPixmap.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GRect.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GRect.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GScaler.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GScaler.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GSmartPointer.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GSmartPointer.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GString.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GString.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GThreads.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GThreads.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GURL.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GURL.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GUnicode.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/IFFByteStream.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/IFFByteStream.h create mode 100644 kviewshell/plugins/djvu/libdjvu/IW44EncodeCodec.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/IW44Image.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/IW44Image.h create mode 100644 kviewshell/plugins/djvu/libdjvu/JB2EncodeCodec.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/JB2Image.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/JB2Image.h create mode 100644 kviewshell/plugins/djvu/libdjvu/JPEGDecoder.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/JPEGDecoder.h create mode 100644 kviewshell/plugins/djvu/libdjvu/MMRDecoder.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/MMRDecoder.h create mode 100644 kviewshell/plugins/djvu/libdjvu/MMX.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/MMX.h create mode 100644 kviewshell/plugins/djvu/libdjvu/Makefile.am create mode 100644 kviewshell/plugins/djvu/libdjvu/README.djvulibre create mode 100644 kviewshell/plugins/djvu/libdjvu/Template.h create mode 100644 kviewshell/plugins/djvu/libdjvu/UnicodeByteStream.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/UnicodeByteStream.h create mode 100644 kviewshell/plugins/djvu/libdjvu/XMLParser.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/XMLParser.h create mode 100644 kviewshell/plugins/djvu/libdjvu/XMLTags.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/XMLTags.h create mode 100644 kviewshell/plugins/djvu/libdjvu/ZPCodec.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/ZPCodec.h create mode 100644 kviewshell/plugins/djvu/libdjvu/configure.in.in create mode 100644 kviewshell/plugins/djvu/libdjvu/debug.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/debug.h create mode 100644 kviewshell/plugins/djvu/pageRangeWidget.cpp create mode 100644 kviewshell/plugins/djvu/pageRangeWidget.h create mode 100644 kviewshell/plugins/djvu/pageRangeWidget_base.ui create mode 100644 kviewshell/plugins/djvu/prefs.kcfgc create mode 100644 kviewshell/renderedDocumentPage.cpp create mode 100644 kviewshell/renderedDocumentPage.h create mode 100644 kviewshell/renderedDocumentPagePixmap.cpp create mode 100644 kviewshell/renderedDocumentPagePixmap.h create mode 100644 kviewshell/renderedDocumentPagePrinter.cpp create mode 100644 kviewshell/renderedDocumentPagePrinter.h create mode 100644 kviewshell/searchWidget.cpp create mode 100644 kviewshell/searchWidget.h create mode 100644 kviewshell/selection.cpp create mode 100644 kviewshell/selection.h create mode 100644 kviewshell/simplePageSize.cpp create mode 100644 kviewshell/simplePageSize.h create mode 100644 kviewshell/sizePreview.cpp create mode 100644 kviewshell/sizePreview.h create mode 100644 kviewshell/tableOfContents.cpp create mode 100644 kviewshell/tableOfContents.h create mode 100644 kviewshell/textBox.h create mode 100644 kviewshell/units.cpp create mode 100644 kviewshell/units.h create mode 100644 kviewshell/zoom.cpp create mode 100644 kviewshell/zoom.h create mode 100644 kviewshell/zoomlimits.h create mode 100644 libkscan/AUTHORS create mode 100644 libkscan/COPYING.LIB create mode 100644 libkscan/INSTALL create mode 100644 libkscan/Makefile.am create mode 100644 libkscan/README create mode 100644 libkscan/TODO create mode 100644 libkscan/configure.in.bot create mode 100644 libkscan/configure.in.in create mode 100644 libkscan/devselector.cpp create mode 100644 libkscan/devselector.h create mode 100644 libkscan/dispgamma.cpp create mode 100644 libkscan/dispgamma.h create mode 100644 libkscan/gammadialog.cpp create mode 100644 libkscan/gammadialog.h create mode 100644 libkscan/img_canvas.cpp create mode 100644 libkscan/img_canvas.h create mode 100644 libkscan/imgscaledialog.cpp create mode 100644 libkscan/imgscaledialog.h create mode 100644 libkscan/imgscaninfo.cpp create mode 100644 libkscan/imgscaninfo.h create mode 100644 libkscan/kgammatable.cpp create mode 100644 libkscan/kgammatable.h create mode 100644 libkscan/kscandevice.cpp create mode 100644 libkscan/kscandevice.h create mode 100644 libkscan/kscandoc.h create mode 100644 libkscan/kscanoption.cpp create mode 100644 libkscan/kscanoption.h create mode 100644 libkscan/kscanoptset.cpp create mode 100644 libkscan/kscanoptset.h create mode 100644 libkscan/kscanslider.cpp create mode 100644 libkscan/kscanslider.h create mode 100644 libkscan/massscandialog.cpp create mode 100644 libkscan/massscandialog.h create mode 100644 libkscan/pics/Makefile.am create mode 100644 libkscan/pics/cr16-action-palette_color.png create mode 100644 libkscan/pics/cr16-action-palette_gray.png create mode 100644 libkscan/pics/cr16-action-palette_halftone.png create mode 100644 libkscan/pics/cr16-action-palette_lineart.png create mode 100644 libkscan/previewer.cpp create mode 100644 libkscan/previewer.h create mode 100644 libkscan/scandialog.cpp create mode 100644 libkscan/scandialog.h create mode 100644 libkscan/scanparams.cpp create mode 100644 libkscan/scanparams.h create mode 100644 libkscan/scanservice.desktop create mode 100644 libkscan/scansourcedialog.cpp create mode 100644 libkscan/scansourcedialog.h create mode 100644 libkscan/sizeindicator.cpp create mode 100644 libkscan/sizeindicator.h diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..74eb758b --- /dev/null +++ b/AUTHORS @@ -0,0 +1,3 @@ + +Look in the subdirs to get info about the authors. + diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..8900e10b --- /dev/null +++ b/COPYING @@ -0,0 +1,347 @@ +NOTE! The GPL below is copyrighted by the Free Software Foundation, but +the instance of code that it refers to (the kde programs) are copyrighted +by the authors who actually wrote it. + +--------------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +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 give any other recipients of the Program a copy of this License +along with the Program. + +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 Program or any portion +of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +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 Program, 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 Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) 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; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, 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 executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or 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 counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program 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. + + 5. 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 Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. 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 Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program 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 Program. + +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. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program 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. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 Program +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 Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, 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 + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/COPYING-DOCS b/COPYING-DOCS new file mode 100644 index 00000000..4a0fe1c8 --- /dev/null +++ b/COPYING-DOCS @@ -0,0 +1,397 @@ + GNU Free Documentation License + Version 1.2, November 2002 + + + Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. + 51 Franklin St, 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. + + +0. PREAMBLE + +The purpose of this License is to make a manual, textbook, or other +functional and useful document "free" in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, +with or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible +for modifications made by others. + +This License is a kind of "copyleft", which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft +license designed for free software. + +We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. + + +1. APPLICABILITY AND DEFINITIONS + +This License applies to any manual or other work, in any medium, that +contains a notice placed by the copyright holder saying it can be +distributed under the terms of this License. Such a notice grants a +world-wide, royalty-free license, unlimited in duration, to use that +work under the conditions stated herein. The "Document", below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as "you". You accept the license if you +copy, modify or distribute the work in a way requiring permission +under copyright law. + +A "Modified Version" of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. + +A "Secondary Section" is a named appendix or a front-matter section of +the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document's overall subject +(or to related matters) and contains nothing that could fall directly +within that overall subject. (Thus, if the Document is in part a +textbook of mathematics, a Secondary Section may not explain any +mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. + +The "Invariant Sections" are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. If a +section does not fit the above definition of Secondary then it is not +allowed to be designated as Invariant. The Document may contain zero +Invariant Sections. If the Document does not identify any Invariant +Sections then there are none. + +The "Cover Texts" are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. A Front-Cover Text may +be at most 5 words, and a Back-Cover Text may be at most 25 words. + +A "Transparent" copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, that is suitable for revising the document +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup, or absence of markup, has been arranged to thwart +or discourage subsequent modification by readers is not Transparent. +An image format is not Transparent if used for any substantial amount +of text. A copy that is not "Transparent" is called "Opaque". + +Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, LaTeX input format, SGML +or XML using a publicly available DTD, and standard-conforming simple +HTML, PostScript or PDF designed for human modification. Examples of +transparent image formats include PNG, XCF and JPG. Opaque formats +include proprietary formats that can be read and edited only by +proprietary word processors, SGML or XML for which the DTD and/or +processing tools are not generally available, and the +machine-generated HTML, PostScript or PDF produced by some word +processors for output purposes only. + +The "Title Page" means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, "Title Page" means +the text near the most prominent appearance of the work's title, +preceding the beginning of the body of the text. + +A section "Entitled XYZ" means a named subunit of the Document whose +title either is precisely XYZ or contains XYZ in parentheses following +text that translates XYZ in another language. (Here XYZ stands for a +specific section name mentioned below, such as "Acknowledgements", +"Dedications", "Endorsements", or "History".) To "Preserve the Title" +of such a section when you modify the Document means that it remains a +section "Entitled XYZ" according to this definition. + +The Document may include Warranty Disclaimers next to the notice which +states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this +License, but only as regards disclaiming warranties: any other +implication that these Warranty Disclaimers may have is void and has +no effect on the meaning of this License. + + +2. VERBATIM COPYING + +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. + +You may also lend copies, under the same conditions stated above, and +you may publicly display copies. + + +3. COPYING IN QUANTITY + +If you publish printed copies (or copies in media that commonly have +printed covers) of the Document, numbering more than 100, and the +Document's license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. + +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. + +If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a computer-network location from which the general network-using +public has access to download using public-standard network protocols +a complete Transparent copy of the Document, free of added material. +If you use the latter option, you must take reasonably prudent steps, +when you begin distribution of Opaque copies in quantity, to ensure +that this Transparent copy will remain thus accessible at the stated +location until at least one year after the last time you distribute an +Opaque copy (directly or through your agents or retailers) of that +edition to the public. + +It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to give +them a chance to provide you with an updated version of the Document. + + +4. MODIFICATIONS + +You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: + +A. Use in the Title Page (and on the covers, if any) a title distinct + from that of the Document, and from those of previous versions + (which should, if there were any, be listed in the History section + of the Document). You may use the same title as a previous version + if the original publisher of that version gives permission. +B. List on the Title Page, as authors, one or more persons or entities + responsible for authorship of the modifications in the Modified + Version, together with at least five of the principal authors of the + Document (all of its principal authors, if it has fewer than five), + unless they release you from this requirement. +C. State on the Title page the name of the publisher of the + Modified Version, as the publisher. +D. Preserve all the copyright notices of the Document. +E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. +F. Include, immediately after the copyright notices, a license notice + giving the public permission to use the Modified Version under the + terms of this License, in the form shown in the Addendum below. +G. Preserve in that license notice the full lists of Invariant Sections + and required Cover Texts given in the Document's license notice. +H. Include an unaltered copy of this License. +I. Preserve the section Entitled "History", Preserve its Title, and add + to it an item stating at least the title, year, new authors, and + publisher of the Modified Version as given on the Title Page. If + there is no section Entitled "History" in the Document, create one + stating the title, year, authors, and publisher of the Document as + given on its Title Page, then add an item describing the Modified + Version as stated in the previous sentence. +J. Preserve the network location, if any, given in the Document for + public access to a Transparent copy of the Document, and likewise + the network locations given in the Document for previous versions + it was based on. These may be placed in the "History" section. + You may omit a network location for a work that was published at + least four years before the Document itself, or if the original + publisher of the version it refers to gives permission. +K. For any section Entitled "Acknowledgements" or "Dedications", + Preserve the Title of the section, and preserve in the section all + the substance and tone of each of the contributor acknowledgements + and/or dedications given therein. +L. Preserve all the Invariant Sections of the Document, + unaltered in their text and in their titles. Section numbers + or the equivalent are not considered part of the section titles. +M. Delete any section Entitled "Endorsements". Such a section + may not be included in the Modified Version. +N. Do not retitle any existing section to be Entitled "Endorsements" + or to conflict in title with any Invariant Section. +O. Preserve any Warranty Disclaimers. + +If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. + +You may add a section Entitled "Endorsements", provided it contains +nothing but endorsements of your Modified Version by various +parties--for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. + +You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. + +The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. + + +5. COMBINING DOCUMENTS + +You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice, and that you preserve all their Warranty Disclaimers. + +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. + +In the combination, you must combine any sections Entitled "History" +in the various original documents, forming one section Entitled +"History"; likewise combine any sections Entitled "Acknowledgements", +and any sections Entitled "Dedications". You must delete all sections +Entitled "Endorsements". + + +6. COLLECTIONS OF DOCUMENTS + +You may make a collection consisting of the Document and other documents +released under this License, and replace the individual copies of this +License in the various documents with a single copy that is included in +the collection, provided that you follow the rules of this License for +verbatim copying of each of the documents in all other respects. + +You may extract a single document from such a collection, and distribute +it individually under this License, provided you insert a copy of this +License into the extracted document, and follow this License in all +other respects regarding verbatim copying of that document. + + +7. AGGREGATION WITH INDEPENDENT WORKS + +A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, is called an "aggregate" if the copyright +resulting from the compilation is not used to limit the legal rights +of the compilation's users beyond what the individual works permit. +When the Document is included in an aggregate, this License does not +apply to the other works in the aggregate which are not themselves +derivative works of the Document. + +If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document's Cover Texts may be placed on +covers that bracket the Document within the aggregate, or the +electronic equivalent of covers if the Document is in electronic form. +Otherwise they must appear on printed covers that bracket the whole +aggregate. + + +8. TRANSLATION + +Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between +the translation and the original version of this License or a notice +or disclaimer, the original version will prevail. + +If a section in the Document is Entitled "Acknowledgements", +"Dedications", or "History", the requirement (section 4) to Preserve +its Title (section 1) will typically require changing the actual +title. + + +9. TERMINATION + +You may not copy, modify, sublicense, or distribute the Document except +as expressly provided for under this License. Any other attempt to +copy, modify, sublicense or distribute the Document 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. + + +10. FUTURE REVISIONS OF THIS LICENSE + +The Free Software Foundation may publish new, revised versions +of the GNU Free Documentation 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. See +http://www.gnu.org/copyleft/. + +Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License "or any later version" applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. + + +ADDENDUM: How to use this License for your documents + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: + + Copyright (c) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.2 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + A copy of the license is included in the section entitled "GNU + Free Documentation License". + +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the "with...Texts." line with this: + + with the Invariant Sections being LIST THEIR TITLES, with the + Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. + +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, +to permit their use in free software. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 00000000..5036ba5e --- /dev/null +++ b/ChangeLog @@ -0,0 +1,17 @@ +1998-12-05 Alex Zepeda + + * README: Use a "new" style README. + +1998-11-13 Alex Zepeda + + * Makefile.cvs (all): Use an updated Makefile.cvs from kdenetwork that + tests for the admin directory. + + * configure.in.1: Remove comment about this being Alpha (quality) + software, and update version number (now it's at 1.1pre). Also, now + it uses the kde-common copy of the autoconf stuff. + +1998-11-08 Alex Zepeda + + * Makefile.cvs (all): Use the kde-common version of automoc. + diff --git a/INSTALL b/INSTALL new file mode 100644 index 00000000..f8bad0c1 --- /dev/null +++ b/INSTALL @@ -0,0 +1,176 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes a while. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/kde/bin', `/usr/local/kde/lib', etc. You can specify an +installation prefix other than `/usr/local/kde' by giving `configure' +the option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + diff --git a/Mainpage.dox b/Mainpage.dox new file mode 100644 index 00000000..668e62f5 --- /dev/null +++ b/Mainpage.dox @@ -0,0 +1,16 @@ +/** + * @mainpage The KDE Graphics API Reference + * + * This section contains the KDE online class reference for the current + * development version of the KDE graphics package. + * + * - kviewshell + * (classes)\n + * API for the implementation of kviewshell plugins. + * + * More information about the KDE architecture in form of + * tutorials, HOWTOs, + * and FAQs can be found at + * the KDE Developer's corner. + */ + diff --git a/Makefile.am.in b/Makefile.am.in new file mode 100644 index 00000000..f2467786 --- /dev/null +++ b/Makefile.am.in @@ -0,0 +1,22 @@ +## kdegraphics/Makefile.am $Id$ +## (C) 1997 Stephan Kulow + +AUTOMAKE_OPTIONS = foreign 1.6.1 + +COMPILE_BEFORE_kooka = libkscan +COMPILE_BEFORE_kfaxview = kfax +COMPILE_BEFORE_kfile-plugins = kghostview +COMPILE_AFTER_kviewshell = kdvi kfaxview + +DISTCLEANFILES = inst-apps + +EXTRA_DIST = admin debian kdebase.spec.in README.pam kde.pamd + +dist-hook: + cd $(top_distdir) && perl $(top_srcdir)/admin/am_edit -padmin + +MAINTAINERCLEANFILES = subdirs configure.in acinclude.m4 SUBDIRS + +include admin/Doxyfile.am +include admin/deps.am + diff --git a/Makefile.cvs b/Makefile.cvs new file mode 100644 index 00000000..b4752bd8 --- /dev/null +++ b/Makefile.cvs @@ -0,0 +1,16 @@ + +all: + @echo "This Makefile is only for the CVS repository" + @echo "This will be deleted before making the distribution" + @echo "" + @if test ! -d admin; then \ + echo "Please recheckout this module!" ;\ + echo "for cvs: use checkout once and after that update again" ;\ + echo "for cvsup: checkout kde-common from cvsup and" ;\ + echo " link kde-common/admin to ./admin" ;\ + exit 1 ;\ + fi + $(MAKE) -f admin/Makefile.common cvs + +.SILENT: + diff --git a/README b/README new file mode 100644 index 00000000..f0ea21a4 --- /dev/null +++ b/README @@ -0,0 +1,97 @@ +In this file: + +* About kdegraphics +* Common Mistakes +* Debugging +* More Info + + +About kdegraphics +----------------- +kdegraphics is a collection of graphic oriented applications: + +* debian + Files needed to create Debian packages. + +* doc + XML based documentation for the programs. + +* kamera + Digital camera io_slave for Konqueror. Together gPhoto this allows you + to access your camera's picture with the URL kamera:/ + +* kcoloredit + Contains two programs: a color value editor and also a color picker. + +* kdvi + Program (and embeddable KPart) to display *.DVI files from TeX. + +* kfax + A program to display raw and tiffed fax images (g3, g3-2d, g4). + +* kfaxview + An embeddable KPart to display tiffed fax images. + +* kfile-plugins + Provide meta information for graphic files. + +* kghostview + Program (and embeddable KPart) to display *.pdf and *.ps + +* kiconedit + An icon editor. + +* kmrml + Connects to a MRML server and find similar images + +* kooka + A raster image scan program, based on SANE and libkscan. + +* kolourpaint + An easy-to-use paint program designed for everyday tasks like drawing + simple diagrams/logos/icons and editing screenshots. + +* kpovmodeler + Program to enter scenes for the 3D rendering engine PovRay. + +* kruler + A ruler in inch, centimeter and pixel to check distances on the screen. + +* ksnapshot + Make snapshots of the screen contents. + +* kuickshow + Fast and comfortable imageviewer. + +* kview + Picture viewer, provided as standalone program and embeddable KPart. + +* kviewshell + Generic framework for viewer applications. + +* libkscan + Library to access scanners used by kooka (and koffice), needs SANE to be + used + + +Common Mistakes +--------------- +If configure claims Qt cannot be found, have a look at http://www.trolltech.com +to get a copy of latest Qt 3.3.x version. + + +Debugging +--------- +You can use --enable-debug with the configure script, if you want to have +debug code in your KDE apps and libs. This will ensure useful and more +verbose backtraces, but will require a lot more disk space. + + +More Info +--------- +Please direct any bug reports to our bug list by visiting +http://bugs.kde.org. + +General KDE discussions should go to the KDE mailing list (kde@kde.org). + + diff --git a/configure.in.in b/configure.in.in new file mode 100644 index 00000000..c0c74795 --- /dev/null +++ b/configure.in.in @@ -0,0 +1,17 @@ +#MIN_CONFIG +DO_NOT_COMPILE="$DO_NOT_COMPILE" + +dnl Checks for header files. +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_CHECK_HEADERS(fcntl.h sys/time.h unistd.h stdlib.h paths.h) +AC_CHECK_SETENV +AC_CHECK_UNSETENV +AC_CHECK_USLEEP +AC_CHECK_MKSTEMPS +dnl Checks for typedefs, structures, and compiler characteristics. +AC_HEADER_TIME + +CXXFLAGS="$CXXFLAGS $KDE_DEFAULT_CXXFLAGS" + +KDE_INIT_DOXYGEN([KDE Graphics API Reference], [Version $VERSION]) diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 00000000..6812bd2d --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,5 @@ + +KDE_LANG = en +KDE_DOCS = AUTO +SUBDIRS = $(AUTODIRS) + diff --git a/doc/kamera/Makefile.am b/doc/kamera/Makefile.am new file mode 100644 index 00000000..085981d9 --- /dev/null +++ b/doc/kamera/Makefile.am @@ -0,0 +1,4 @@ + +KDE_LANG = en +KDE_DOCS = AUTO + diff --git a/doc/kamera/index.docbook b/doc/kamera/index.docbook new file mode 100644 index 00000000..2579fe41 --- /dev/null +++ b/doc/kamera/index.docbook @@ -0,0 +1,78 @@ + + + + + +]> + + + + +The &kamera; Handbook + + + + + + + +
+
+
+ +
+ +&FDLNotice; + + + +2000-09-02 +0.00.00 + + + + + +&kamera; allows you to view and download images on a digital camera. + + + + + +KDE +Kapp + + +
+ + Introduction Sorry, but +the documentation for &kappname; was not finished when &kde; was installed on +this computer. If you need help, please check The &kde; Website for updates, or by +submitting your question to The +&kde; User Mailing list. The &kde; +Team + +&underFDL; + + + +&documentation.index; +
+ + diff --git a/doc/kcoloredit/Makefile.am b/doc/kcoloredit/Makefile.am new file mode 100644 index 00000000..085981d9 --- /dev/null +++ b/doc/kcoloredit/Makefile.am @@ -0,0 +1,4 @@ + +KDE_LANG = en +KDE_DOCS = AUTO + diff --git a/doc/kcoloredit/index.docbook b/doc/kcoloredit/index.docbook new file mode 100644 index 00000000..8599cdf4 --- /dev/null +++ b/doc/kcoloredit/index.docbook @@ -0,0 +1,468 @@ + +KColorEdit"> + + + + +] +> + + + + The &kcoloredit; Handbook + + +Artur +Rataj + +
&Artur.Rataj.mail;
+
+
+ + +
+ + +2000 +&Artur.Rataj; + + +&FDLNotice; + +2005-12-10 +3.5.0 + + +&kcoloredit; is a palette files editor. It can be used for editing +color palettes and for color choosing and naming. + + + +KDE +graphics +palette + +
+ + +Introduction + +&kcoloredit; is a palette files editor. It can be used for +editing color palettes and for color choosing and naming. + + + + +File operations + + +About palette files + + +The palette files installed by &kde; can be either system-wide or the +user ones. The latter are in you private &kde; configuration +folders, and they are named Custom Colors and +Recent Colors. + + + +In &kcoloredit;, you may open all of these palettes, as well as +palettes in arbitrary files. + + + + + +Opening a file + +In the Open File dialog, you may choose from a +list of installed palettes, or browse folders for files. + + + + + + +Editing + + +Cursor + +The cursor is visible as a line in the palette view. It can be +moved by clicking on an area beside a color. + +The cursor has the following functions: + + + + +It points to the color after it. The color, if any, is described below +the palette view. You may edit its name there. + + + + +It can be used to make a selection. A selection can be made by +clicking on an area beside a color, so to move the cursor there, and +by moving the mouse then with the left mouse button pressed. + + + +If the At cursor check-box near the +Add Color button is checked, a color from the +color chooser is put at the cursor. The color is either inserted +or it overwrites another one, depending on whether the +Overwrite mode is chosen. The mode can be chosen +by checking the Overwrite check-box, that is next +to the At cursor one. + + + + + + +Selection + +A selection, that can be made as it was written in the previous +section, can be used with the copy, cut and paste operations. + + + + +Clipboard format + +&kcoloredit; uses the following format for clipboard data: for each +color three numbers for red, green and blue components, respectively, +and an optional color name, followed by a new line character if there +is another color. Therefore, if for example three numbers are in the +clipboard, they can be pasted by &kcoloredit; as a color. + + + + + + +Selecting a color from an RGB space + + +A color can be selected from an RGB space in &kcoloredit; in the +following ways: + + + +By editing the HSV or RGB components. + + + + +By selecting a color from color gradient panels. In the left one, two +from HSV components can be selected, and in the right one, the third +one. The third component can be chosen by clicking on one of the +buttons labeled H:, S: and +V:. The one component panel display colors with +the other two components equal to these selected in the two components +panel. The two components panel may display colors with the third +component fixed, or, if the Variable check-box is +set, with a value equal to the one selected in the one component +panel. In the Replace mode, the color selected in +panels replaces the output one instantly, and in the +Change: mode it modifies the output color after +each click, or a mouse move while a mouse button is +pressed. Therefore, in the latter mode the color selected in the +gradient panels may be different from the output color. To synchronize +the colors, the Synchronize button can be used. + + + + + + + + + + +Drag and drop + +The palette colors and the color selection output color can be dragged +with a mouse. + + + + +Menu Reference + + +The <guimenu>File</guimenu> Menu + + + + +&Ctrl; +N +File +New + + +Start a new palette in the current window. + + + + + +File +New Window + + +Open a new window + + + + + +&Ctrl; +O +File +Open + + +Open a saved palette. + + + + + +File +Open Recent + + +Reopen a palette that you have recently been +editing. + + + + + +&Ctrl; +S +File +Save + + +Save the currently open palette. + + + + + +File +Save As... + + +Save the currently open palette with a new +name. + + + + + +&Ctrl; +W +File +Close + + +Close the current &kcoloredit; window + + + + + +&Ctrl; +Q +File +Quit + + +Quit &kcoloredit;. + + + + + + + +The <guimenu>Edit</guimenu> Menu + + + + +&Ctrl; +X +Edit +Cut + + +Cut the currently selected color to the +clipboard. + + + + + +&Ctrl; +C +Edit +Copy + + +Copy the currently selected color to the +clipboard. + + + + + +&Ctrl; +V +Edit +Paste + + +Paste a color from the clipboard. + + + + + + + +The <guimenu>Color</guimenu> Menu + + + + +Color +From Palette + + +Find the color currently selected in the palette, in the +color selector on the left. + + + + + +Color +From Screen + + +Pick a color from anywhere on the screen, and find it +in the color selector on the left. + + + + + + + +The <guimenu>Settings</guimenu> Menu + + + + +Settings +Hide/Show Toolbar + + +Toggle on and off the toolbar icons. + + + + + +Settings +Hide/Show Statusbar + + +Toggle on and off the status bar. + + + + + +Settings +Hide/Show Color Names + + +If the currently open palette has color name, display +them alongside the colors. + + + + + +Settings +Configure Shortcuts... + + +Configure the keyboard keys you use to access the +different actions. + + + + + +Settings +Configure Toolbars... + + +Configure the items you want to put in the toolbar + + + + + + + + + +The <guimenu>Help</guimenu> Menu + +&help.menu.documentation; + + + + + + +Credits and Licenses + +&kcoloredit; copyright 2000 &Artur.Rataj; + +Documentation copyright 2000 &Artur.Rataj; + + + +&underFDL; +&underGPL; + + + +Installation + +&install.intro.documentation; + +&install.compile.documentation; + + + +
+ + diff --git a/doc/kdvi/KDVI-features.dvi b/doc/kdvi/KDVI-features.dvi new file mode 100644 index 00000000..2bf4d014 Binary files /dev/null and b/doc/kdvi/KDVI-features.dvi differ diff --git a/doc/kdvi/KDVI-features.tex b/doc/kdvi/KDVI-features.tex new file mode 100644 index 00000000..66c3f9f5 --- /dev/null +++ b/doc/kdvi/KDVI-features.tex @@ -0,0 +1,480 @@ +\documentclass{article} + +\usepackage{amstext} +\usepackage{colordvi} +\usepackage{graphicx} +\usepackage{times} +\usepackage[arrow,matrix,curve,ps]{xy} +\xyoption{dvips} +\usepackage[active]{srcltx} +\usepackage[hypertex]{hyperref} +\sloppy + +\newcommand{\KDVI}{{\sf KDVI 1.1}} + +\begin{document} + +\title{Support for \TeX\ extensions in \KDVI} + +\author{Stefan Kebekus} + +\maketitle +\begin{abstract} + This document describes the extensions to the standard format of DVI + files which \KDVI\ implements in order to support PostScript + inclusion and hyperlinks. + + \KDVI\ is a program that displays DVI-files generated by the \TeX\ + typesetting system. If you don't know what \TeX\ is then you are + most likely not interested in this. If you would like to know how to + use special features of \KDVI, then you can find examples here. +\end{abstract} + +\tableofcontents + +\section{What's all this} + +The DVI-previewing program \KDVI\ is able to display standard +DVI-files as specified in \cite{Level0Std}. In order to support +graphics inclusion, hyperlinks and non-standard fonts, \KDVI\ +implements a number of features which extend \cite{Level0Std}. In +particular, \KDVI\ supports a number of \TeX 's $\backslash${\tt + special} commands. The aim of this document is to describe these +extensions and give examples of their use. + +Unfortunately, in spite of several attempts to find a sound standard +for the use of $\backslash${\tt special} commands, there is now a +wealth of competing and mutually incompatible definitions. + +\KDVI\ does not attempt to support all possible features. Instead, we +tried to implement those which are most useful and used most commonly. +In this, we have tried to be consistent with the {\sf dvips} program. +\KDVI\ does not support a number of outdated and unsane standards, nor +does it support features which impair the system security. + + +\section{Virtual fonts} + +\KDVI\ supports ``virtual fonts''. This enables \TeX\ to use +PostScript fonts. For more information, and a complete specification, +consult \cite{dvips}. + +\paragraph*{Example} + +This text uses the ``Times'' family of fonts instead of the ``Computer +Modern'' fonts which are usually used by \TeX. This was realized in +\LaTeX 2$\epsilon$ by including the line +\begin{verbatim} +\usepackage{times} +\end{verbatim} +in the header of this document. + + +\section{PostScript support} + +\KDVI\ implements basic facilities to include PostScript graphics in a +DVI file, which will enable the reader to conviently read most +scientific papers which use such features. + +\subsection{Literal PostScript} + +\KDVI\ supports the inclusion of PostScript into DVI-files by means of +the quote-special. The syntax follows the specification of +\cite{dvips}: +\begin{verbatim} +\special{" PostScript-commands} +\end{verbatim} +The PostScript-commands are not directly included, in fact they are +sandwiched between a {\tt save} and {\tt restore} pair. That way +\KDVI\ ensures that the command cannot affect PostScript-commands +which appear somewhere else in your file. + +\paragraph*{Example} + +Figure~\ref{quote-special} shows an example taken from \cite{dvips}. +The generating \TeX -code is +\begin{verbatim} +\vbox to 100bp{\vss +\special{" newpath 0 0 moveto 100 100 lineto + 300 0 lineto closepath gsave 0.8 setgray fill + grestore stroke}} +\end{verbatim} + +\begin{figure} +\vbox to 100bp{\vss +\special{" newpath 0 0 moveto 100 100 lineto 300 0 lineto closepath gsave 0.8 setgray fill grestore stroke}} +\caption{Graphic generated by literal PostScript inclusion\label{quote-special}} +\end{figure} + + +\subsection{Direct PostScript} + +\KDVI\ supports the inclusion of PostScript into DVI-files by means of +the direct-special. The syntax follows the specification of +\cite{dvips}: +\begin{verbatim} +\special{ps: Postscript-commands} +\end{verbatim} +The PostScript-commands are directly included, and there is no +protective {\tt save} and {\tt restore} pair. The use of this command +is not recommended, as it may have funny side effects on other +PostScript commands which appear later in your file. + +\KDVI\ also supports the following syntactical variants which are +explained in \cite{dvips}: +\begin{verbatim} +\special{ps: Postscript-commands} +\special{ps::[begin] Postscript-commands} +\special{ps:: Postscript-commands} +\special{ps::[end] Postscript-commands} +\end{verbatim} +The variant +\begin{verbatim} +\special{ps: plotfile filename} +\end{verbatim} +is not currently supported. + +\paragraph*{Example} + +The command +\begin{verbatim} +\includegraphics[height=3cm, angle=20]{aboutkde.ps} +\end{verbatim} +which is used in section~\ref{chap:eps} uses the direct-special +internally in order to set the rotation. + +\subsection{Literal headers} + +Literal headers work as described in \cite{dvips}. +\begin{verbatim} +\special{! PostScript-Header-commands} +\end{verbatim} + +\paragraph*{Example} +The following diagram, which was generated using the \Xy -pic macro +packages uses literal postscript inclusion which relies on literal +headers. +$$ +\xymatrix{ {\tilde X} + \ar@{-->}[rrd]_{\exists \alpha} \ar[rrrr]^{\eta}_{\txt{\tiny + normalization}} \ar@/_/ [rrdd]_ {\tilde \pi} & & & & {X} + \ar@/^/[lldd]^{\pi} \\ & & {X'} + \ar@{-->}[rru]_{\exists \beta} \ar@{-->}[d]_{\exists \pi'} & & \\ & & + {Y}& &} +$$ +Note that the actual headers are defined on the first page of the +document. This was a major source of trouble in earlier versions of +KDVI. + + + +\subsection{PostScript headers} + +PostScript headers work as described in \cite{dvips}. This command is +very similar to the literal header command, but expects the name of a +file which should be included. +\begin{verbatim} +\special{header=filename} +\end{verbatim} + + + + +\subsection{EPS inclusion}\label{chap:eps} + +A popular way to include PostScript-files into \TeX\ documents uses +the PSFile $\backslash${\tt special} command. Again this is explained +in detail in \cite{dvips}. Currently \KDVI\ supports the syntax +\begin{verbatim} +\special{psfile=File keyword=value keyword=value ...} +\end{verbatim} +Where keyword is one of the following +\begin{description} +\item[llx] lower left corner of the bounding box, $x$-coordinate +\item[lly] lower left corner of the bounding box, $y$-coordinate +\item[urx] upper right corner of the bounding box, $x$-coordinate +\item[ury] upper right corner of the bounding box, $y$-coordinate +\item[rwi] width of the bounding box. If $llx-urx \not = rwi$, then +the boundig box is scaled accordingly. +\item[rhi] height of the bounding box If $lly-ury \not = rhi$, then +the boundig box is scaled accordingly. +\item[angle] rotates the picture counterclockwise +\end{description} +Unknown keywords are silently ignored. The keywords {\tt llx}, {\tt + lly}, {\tt urx}, {\tt ury} and {\tt rwi} are usually generated by +the {\tt epsf} macros. The keywords {\tt hoffset}, {\tt voffset}, +{\tt hsize}, {\tt vsize}, {\tt hscale}, {\tt vscale}, {\tt angle} and +{\tt clip} are not currently implemented. The ``uncompression'' +feature of {\sf dvips} and {\sf xdvi} which allows to execute +arbitrary commands in via the syntactical variant +\begin{verbatim} +\special{psfile="'shell-command" keyword=value ...} +\end{verbatim} +is deliberately not implemented for security reasons. + +\paragraph*{Example} +Figure~\ref{epsf-special} shows an embedded postscript-file. +\begin{figure} + \begin{center} + \includegraphics[height=3cm]{aboutkde.ps} + \includegraphics[height=4cm]{aboutkde.ps} + \includegraphics[height=3cm, angle=20]{aboutkde.ps} + \end{center} +\caption{Embedded PostScript graphic\label{epsf-special}} +\end{figure} +This was easily realized by including the line +\begin{verbatim} +\usepackage{graphicx} +\end{verbatim} +into the header of this document, and the lines +\begin{verbatim} +\includegraphics[height=3cm]{aboutkde.ps} +\includegraphics[height=4cm]{aboutkde.ps} +\includegraphics[height=3cm, angle=20]{aboutkde.ps} +\end{verbatim} +at the place where the graphic should appear. It is strongly +recommended to use the {\tt graphicx} macro package for this purpose. +\begin{figure} + \begin{center} + \includegraphics[height=2cm, bb=0 0 150 50]{nonexistent.ps} + \end{center} +\caption{Reference to a non-existent PS-file\label{nonex-special}} +\end{figure} +Figure~\ref{nonex-special} shows how \KDVI\ warns you about +non-existent files. + + +\section{Hypertext support} + +\KDVI\ supports commands for hyperlink support which commands +establish links between sections of documents in a manner exactly +analogous to the HTML of the WWW. For a detailed specification we +refer to \cite{HFAQ99} or \cite{Rah98}. Note, however, that \KDVI\ +does currently not allow nested hyperlinks. + +\subsection{Hyper-Labels} + +The commands +\begin{verbatim} +\special{html:} +\special{html:} +\end{verbatim} +labels the current point of the text for later reference. + +\subsection{Hyper-References} + +The commands +\begin{verbatim} +\special{html:} +Text +\special{html:} +\end{verbatim} +makes {\tt Text} a link to {\tt hrefstring}, where {\tt hrefstring} is +an absolute or relative URL in the standard format used on the +internel. If {\tt hrefstring} is of the form {\tt \#label} then it +points to the section of the current document which is labeled using +the labeling command described above: +\begin{verbatim} +\special{html:} +\end{verbatim} + + + +\paragraph*{Example} +This document features a clickable table of contents, and also the +references can be clicked on. This has been achieved by using the {\tt + hyperref} macro package in \LaTeX\ by including the line +\begin{verbatim} +\usepackage[hypertex]{hyperref} +\end{verbatim} +into the document preamble. Everything else is automatic. + +Here is an external link which points to the \href{http://www.kde.org}{main + website of the KDE project}. For this, the command {\tt href} of the +{\tt hyperref} macro package was used: +\begin{verbatim} +\href{http://www.kde.org}{main + website of the KDE project} +\end{verbatim} + + +\paragraph{Warning.} On some installations, the {\tt + hyperref} macro package is configured to generate PostScript +hyperlinks for {\tt dvips} by default. On these systems, using the +line +\begin{verbatim} +\usepackage{hyperref} +\end{verbatim} +will generate DVI file whose hyperlinks are not visible in KDVI. +Worse, KDVI will call the {\tt ghostview} PostScript interpreter for +every page, which makes the display very slow. + + + +\section{Colored \Red{text} \Green{and} \Blue{background}} + +The DVI specials for colored text are supported as they are described +in \cite{dvips}. + +\paragraph*{Example} In this document, the following code was used to +generate the text below. +\begin{verbatim} +\usepackage{colordvi} + +... + +\textGreen This text is green but here we are +\Red{switching to red, \Blue{nesting blue}, +recovering the red} and back to original green. +\textCyan The text from here on will be cyan +unless \Yellow{locally changed to yellow}. Now +we are back to cyan. \textBlack +\end{verbatim} + +This gave the following output: +\begin{verse} + \textGreen This text is green but here +we are \Red{switching to red, \Blue{nesting blue}, recovering the red} +and back to original green. \textCyan The text from here on will be +cyan unless \Yellow{locally changed to yellow}. Now we are back to +cyan. \textBlack +\end{verse} + +To set the background color of the page, the command +\background{Lavender} +\begin{verbatim} +\background{Lavender} +\end{verbatim} +was used. To switch back to normal, the command +\begin{verbatim} +\background{White} +\end{verbatim} +was placed somewhere on the following page. As you see, the background +command does not fit well into \LaTeX's philosophy and should be +avoided. + +\section{Rotated Text} + +Rotated text can sometimes be useful, e.g. to fit large table onto a +single page. This is used, e.g.~in the style files of journals of the +American Astronomical Society. Here is one example. + +\begin{table}[h] + \centering +\begin{tabular}{l|ll} + & \rotatebox{90}{uses \TeX} & \rotatebox{90}{uses Linux} \\ \hline + Stefan & $\times$ & $\times$ \\ + Anke & & $\times$ \\ + Thomas & $\times$ &\\ +\end{tabular} +\end{table} + +This was easily realized by including the line +\begin{verbatim} +\usepackage{graphicx} +\end{verbatim} +into the header of this document. The table itself was then typeset by +{\footnotesize +\begin{verbatim} +\begin{tabular}{l|ll} + & \rotatebox{90}{uses \TeX} & \rotatebox{90}{uses Linux} \\ \hline + Stefan & $\times$ & $\times$ \\ + Anke & & $\times$ \\ + Thomas & $\times$ &\\ +\end{tabular} +\end{verbatim} +} + +\section{Source text specials} + +\KDVI\ is able to make use of source file information which is included +in the DVI file. To include source file information, a {\tt special} +command like to following should be included at the beginning of every +paragraph or every line: +\begin{verbatim} +\special{src:123text.tex} +\end{verbatim} +This tells \KDVI\ that the next paragraph should be associated with +line 123 in the source file text.tex. + +It is of course not practical to add these commands manually to the +beginning of every line ---see the \href{help:/kdvi}{Handbook of +\KDVI} to learn how to add the special commands automatically to your +DVI files. + +The main use of source file specials is the interaction between \KDVI\ +and your editor. Starting from version~1.0, both \emph{forward search} +and \emph{inverse search} are supported. + +\subsection{Forward search} + +Forward search is a feature that helps you find the place in the DVI +file that corresponds to a certain line in the source text. If source +file information is included, you can find the place in the DVI file +{\tt test.dvi} which corresponds to line 1234 in the source file {\tt +text.tex} by starting \KDVI\ like this: +\begin{verbatim} +kdvi file:test.dvi#1234text.tex +\end{verbatim} +In pracitse, this command line will be generated by a script that +communicates with your editor. Currently, scripts for Emacs and XEmacs +exist. As usual, the \href{help:/kdvi/forward-search.html}{Handbook of +\KDVI} explains how to set up your editor with thest scripts. + + +\subsection{Inverse search} + +\background{White} +Inverse search means that you can click into the document in \KDVI, +and your editor will open, load the source file and jump to the proper +place. \KDVI\ currently supports the editors Emacs, Kate, NEdit, VI +and XEmacs. Users who prefer a different editor can specify shell +commands which are to be used. Again we refer to the +\href{help:/kdvi/inverse-search.html}{Handbook of \KDVI} for a detailed explanation. + +\paragraph*{Example} +If you are viewing this document in \KDVI, you can click anywhere with +the middle mouse button (if your mouse has only two buttons, click +left and right simultaneously). An editor will pop up, load the +\LaTeX\ sourcefile and jump to the appropriate line in the +text. Source specials has been added using the {\tt srcltx} macro +package in \LaTeX\ by including the line +\begin{verbatim} +\usepackage[active]{srcltx} +\end{verbatim} +into the document preamble. Everything else is automatic. + + +\begin{thebibliography}{CM97} + +\bibitem[Bha99]{HFAQ99} +T.~Bhattacharya et al. +\newblock {\em Hyper\TeX\ FAQ} +\newblock available on the internet site of the preprint server of the + Los Alamos National Labatories at +\href{http://arXiv.org/hypertex}{\small \tt http://arXiv.org/hypertex} + +\bibitem[Rah98]{Rah98} +S.~Rahts +\newblock {\em Hypertext marks in \LaTeX: the {\sf hyperref} package} +\newblock included in the tetex distribution. A copy can be found on KDVI's +home page at \hfill \linebreak +\href{http://devel-home.kde.org/~kdvi/DVI/hyperref-manual.pdf}{\small \tt http://devel-home.kde.org/$\sim$kdvi/DVI/hyperref-manual.pdf} + +\bibitem[Rok00]{dvips} +T.~Rokicki +\newblock {\em DVIPS: A \TeX\ Driver} +\newblock included in the tetex distribution. A copy can be found on KDVI's +home page at \hfill \linebreak +\href{http://devel-home.kde.org/~kdvi/DVI/dvips.dvi}{\small \tt http://devel-home.kde.org/$\sim$kdvi/DVI/dvips.dvi} + +\bibitem[TUG0]{Level0Std} +The TUG DVI Driver Standards Committee +\newblock {\em The DVI Driver Standard, Level 0} +\newblock included in the tetex distribution. A copy can be found on KDVI's +home page at \hfill \linebreak +\href{http://devel-home.kde.org/~kdvi/DVI/dvistd0.dvi}{\small \tt http://devel-home.kde.org/$\sim$kdvi/DVI/dvistd0.dvi} + + +\end{thebibliography} +\end{document} diff --git a/doc/kdvi/Makefile.am b/doc/kdvi/Makefile.am new file mode 100644 index 00000000..085981d9 --- /dev/null +++ b/doc/kdvi/Makefile.am @@ -0,0 +1,4 @@ + +KDE_LANG = en +KDE_DOCS = AUTO + diff --git a/doc/kdvi/aboutkde.ps b/doc/kdvi/aboutkde.ps new file mode 100644 index 00000000..63200859 --- /dev/null +++ b/doc/kdvi/aboutkde.ps @@ -0,0 +1,3351 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: /home/devel/dvifiles/aboutkde.ps +%%Creator: XV Version 3.10a Rev: 12/29/94 (PNG patch 1.2) - by John Bradley +%%BoundingBox: 0 0 150 250 +%%Pages: 1 +%%DocumentFonts: +%%EndComments +%%EndProlog + +%%Page: 1 1 + +% remember original state +/origstate save def + +% build a temporary dictionary +20 dict begin + +% define string to hold a scanline's worth of data +/pix 450 string def + +% define space for color conversions +/grays 150 string def % space for gray scale line +/npixls 0 def +/rgbindx 0 def + +% lower left corner +0 0 translate + +% size of image (on paper, in 1/72inch coords) +149.97600 249.98400 scale + +% define 'colorimage' if it isn't defined +% ('colortogray' and 'mergeprocs' come from xwd2ps +% via xgrab) +/colorimage where % do we know about 'colorimage'? + { pop } % yes: pop off the 'dict' returned + { % no: define one + /colortogray { % define an RGB->I function + /rgbdata exch store % call input 'rgbdata' + rgbdata length 3 idiv + /npixls exch store + /rgbindx 0 store + 0 1 npixls 1 sub { + grays exch + rgbdata rgbindx get 20 mul % Red + rgbdata rgbindx 1 add get 32 mul % Green + rgbdata rgbindx 2 add get 12 mul % Blue + add add 64 idiv % I = .5G + .31R + .18B + put + /rgbindx rgbindx 3 add store + } for + grays 0 npixls getinterval + } bind def + + % Utility procedure for colorimage operator. + % This procedure takes two procedures off the + % stack and merges them into a single procedure. + + /mergeprocs { % def + dup length + 3 -1 roll + dup + length + dup + 5 1 roll + 3 -1 roll + add + array cvx + dup + 3 -1 roll + 0 exch + putinterval + dup + 4 2 roll + putinterval + } bind def + + /colorimage { % def + pop pop % remove 'false 3' operands + {colortogray} mergeprocs + image + } bind def + } ifelse % end of 'false' case + + + +150 250 8 % dimensions of data +[150 0 0 -250 0 250] % mapping matrix +{currentfile pix readhexstring pop} +false 3 colorimage + +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fcfffffffdfffefdfbfefffffffffff8fffff8fffffffcfbfefffbfeffffffffffffffff +fffefffefefffffffffefdfffdfdfde7e7e79797976767674444443a3a3a3333337f7f7f +fffefdfffdfffdfcfffffffbfefffffefefffefdfffffffafffffffffffffefefefefefe +fffffffefefefffffffefefeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fcfefdfdfdfdfffffffffffffefcfdfefffffbfffffffdfffefcfffffff8fefff9ffffff +fbfcf6fdfef9fffeffa3a2a74b4b4b1b1b1b1a1a1a2424243535352929292d2d2dc2c2c2 +fffefafffefffffffffffffd9799942c2e2d606165a0a1a5fffffffdfdfdfffffffafafa +fffffffffffffbfbfbffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfdfffefeffffdadada979a93fffdf6fffefbfefffffffffbfffefffffffffefefc +ffffffafb0a830322513121a1717172525252121211818181b1b1b676767f7f7f7ffffff +fefefefdfdfbfffff8fffffdc9cbca1517141b1c1e2a2b2f3e3e3ea3a3a3fefefeffffff +fcfcfcfffffffffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffafefffffffefffcfffd4a5c467e876cfbf5e5fffff6fffdfefffdfffbf9fffffeff +82837e181914161618161614131313151515404040838383eaeaeafffffffcfcfcffffff +fefffffefffffffff6fffefffefdff979a911618131315102727271e1e1e5f5f5fffffff +fdfdfdfefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffefbfdfcfffffdfffafff9759774567645838a60ddd9b6fffffbfbf9fefffdfffffffd +999a9556555d5c5a6571726aa9a9a9e1e1e1fffffffefefefffffffafafaffffffffffff +fbfffffefefffdfdfbfffdfffffffb979c7e888c7d55584f1616161515151717176b6b6b +fffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffefdfffefffffbfffefffbb2d4b167995e7a9858999f63cad092ffffeffffefffaf8f9 +fffefffffefffffffbfdfef8fcfcfcfffffffffffffdfdfdfdfdfdffffffffffffffffff +fbfff5fefefffcfafbfffffa7b7d589da367eaedd8fefefed2d2d27878783f3f3f696969 +fcfcfcfefefefffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fdfdfbfafefffffefffffafaf4ffee7db27c84be729ab669bac565d3dc8bfeffd9fffffa +fdfcf8fffffdfcfcfefefff8fffffffefefefffffffffffffcfcfcfffffffffffffdfdfd +fefff4fefdfffdfde386875bb1b46dd2d98cfffff1fffefffffffffefefefffffffdfdfd +fefefefffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fcfffdf9fffffbfffffffafffffef796c79a90da8da2d47dc3cc7be8f687f0fe8cfcffc2 +fffff7fffefffffffffefffffdfdfdfffffffffffffdfdfdfffffffffffffdfdfdffffff +fefffbe9e8e68b8f54b2b763fdffa4dde195fffcf3fffefffffffffefefefffffffdfdfd +fffffffbfbfbfdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffcfffbfffffcfdf8fffdfffff7ffd7f5d396ea95aef9a6bfeb9cd0ef78ffff9ffffd9a +fcffb0f9fffdfbfefffffef4fafefffffffdfffef8fffefbfdfdfffcfffdfcfffdfefeff +eeebe4828744bec55efdff9bfeffacdee48afffcfffffeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffbfffdfffefefffbfbfbfdfffdfff7fff0aae6a6b2ffafc1ffa9d5fda5f2ff94ffffab +ffffabffffb0feffddfafffff8fffdfbfffbfefefcfffdfffffefffffffafcfcf4fffcff +93935dc3c95ffcfc98fffdaffffeb3e9ee94fffdfefefffdffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffcfffffdfcfcfffbfafefdfffffffffffbdbf7d1acfea9d2ffc2dfffb8eeffa3fffdad +fffbbdb7c86a5176296f975bdbe4d1fcfffafcfcfff9fdfcfbfff1f9fefffefffd929a5f +bcca5bfbff95fffbbcfffccdffffb2eaf096fffdfffcfffbffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffdfffffefdf7fcf8fffffffdfffefbfafffcfff4b8f5afd5ffcbe9fde2fafdc6ffffad +99b0562b5620356e21366e173e641982ab6999ce748dd35974c13f6ab830589d1c508920 +6e8b3b849e3bb7c381fbfcd0fdffbdf6fea9fffff8fcfdffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fefefffffffdfefffdfffbfefefffff9fffffffffde1ffd2bcff9beefefbfcfffba3d16f +29680f386721375d24335f2068945597b774d1e09df3f9cbfbffdcd9fba7699e322c6812 +295e102d5717264412596e2bdbeb93f9ffb5fefbf4fffbffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fdfcfffefffdfefffdfff9fcfffefff9fffffcfefdfefff1c3fa9fe4ffdcbff0c1388330 +31821c346826254d07749a67c7e6bae6ffbbfaffcbfffedfffffedfffffdfbfff4a1b474 +3063202e5e143d651e728e53bbcc98f6fecbfefee6fffbf2ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffdfcfefffffdfffcfefffffffbfffffefcfcfffbfffdfff9fff8bff89953ac3e3a951e +3e902227701f6daa6ec5f8c0d9fdd1ebffdff3fedefeffeafffffdfefcfffffdfffdfdff +bed79d39511f667c56aec39ae0f2c0f7ffdcffffefffffeaffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffefafffffffcfffdf7fffffffbfffffbfaf9fff6fff9fffbfff9bdf5aa389d1143a72d +3c942463b455b9fec7befec1e5ffd2f0ffdcfeffebfffff3fefdfbfffffffbfdf8fefffd +fffbff92917c777e5fbbc79fe4f6baf8ffdffbfcf7fffffaffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffdfffbfff84c923042af22 +439d228ddd98b3ffc3caffcbe6ffdffafde8fffff3fafff7fffffdfffdfffffefffffcff +fefffdfcfcf489917ab0c59adef5c1fbffdcfffff3fdfdfffffffdfffffdfffffdfffefc +fcfcfafffffdfcfcfafffffdffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffefffffcfdff9ec691378426 +4a9b3eabfcc1b6ffc9cefed4e5fdddffffedfefff1f9fff6fcfcfafffefffcfdfffffeff +fcfefbfffffbd8e0cbb1c497e7fcc4f5ffdafefef2fefffffffefffffefffffdfeffffff +fffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffdfffafefafff8fff4527e4b +5aa564b4ffd3bcffced0fed9e8ffe0feffebfefff1f9fff8fffffdfffffffafffefeffff +fcfefdfffefffefff3acbf91dbf0b8fbffe1fffff8fbfdfcfffffffffffffefefefdfdfd +fffffffdfdfdfffffffefefeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffff8fffefff3f9eb3a5f34 +a1f0b7afffd1bafac6d1ffd7e1ffe0faffeddaded0808a81ababa9fefefefcfffffeffff +fefffffffdfffbfef3bccda0ddefbbfdffe9fdfcf8fefffdfefefefffffffffffffefefe +fffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffbf8f9fffa3f59363b6e35 +a8fccaabfed0c3fdd4cdffd8e6ffeca2af9d1820130d1810565654a5a1a2f4f6f5fffeff +fdfffefffcfffffffad8e6c2aebd94717463696866b9bbb6fefffffdfffefbfbfbffffff +fdfdfdfffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffb6b856a1a46113e813c +adffd9b4ffe1c4fcdfcbffe1c6edd2111e0d0f160e161f1a444245bdb8bcb3b4b6fffdfe +fdfffefffefffffffbd3ddc5222c13191911201e1f7e807bbbbdbcfdfffefefffffafafa +fffffffffffffdfbfcfffeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffaec6ac204816255c18438a3e +b4ffe0b3fce1c4fee6cbffe55b7b66151b11171813141a182422277d7b80bbc1c1e2e6e7 +fefffffffefffefdf97f857b0e140a181715282327636564bcc0bfcdd1d0f9fbfafeffff +fffffffdfdfdfffefffffeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff2f5e282e611c2f681958984a +bafddebfffe5bffbdfc8fddf384f3f13120d1e1a191317181c1a1f3b3a4097a3a3b6c0bf +fefffffffefbfffffb454a46161a1b171518201b1f3435379ea2a3acb0b1fefffffcfdff +fefefffffffffffdfffffeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffdfffffff7fcf8fbfffbfffdfffffbfff9fff6608657245b17397d283871204c8b3c +b1ffdbc3fff4c5faf0aaffce3443461d1f1c1b201c12151c1f16272b282f77807fa4a7ac +fcfffffefefcfffffa5e59531b16131b17181b191a2626247b84899aa0aefcfffffffffb +fefcfffffefffffffaffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fdfdfdfffffdfefffdfcfcfcfffdfffcfcfaacc3a6205016387824387c25377a1b306b1b +a2f9c2c8fff9c5fdf2aeffd6486b67202b271618131a1e1d1d181e2121234d5756848e8d +fefffffefffffffffa6f706a13131118181819191b202221495154797e84e0e4e3fefffd +fffefffefefefefff9feffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffefff7f9f6fffffffffcfffffcfff4fff02b582132702337841e3e892c39861c36701c +8de49fccfffacafffbb3fcdf65988f2b3d3d1b1d1c181d16111610202423262f2c888f87 +fefdfffefffffcfffb7b8079141915181c1d14181b1d1e22373c3f545857e6e8e3feffff +fffefffffffbfefff8fdfeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fefcfffefffbfffffffff9fffefffa577d4e276b183784243c90203d922d3b89232b6a0f +69b670cbfff4cbfeffc0fff27cb9a73e5656201f24171916171d1915191a171612bcbdab +fffdfffffefffdfff96c736b161c1a171c1f14151a1d1c213031353b3c36fdfef6fdfdff +fefefffffff2fefff2fffeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffefffcfefbfcfcfafffffda6ba9f255e172f801a3c922742982939942b3b8226246a0a +4f8b4fc6ffeaceffffc1fef7a8f1d331564e2828302218201412171a1a1c333327f8fedc +fffef9fffff7fdfff551564f171b1a1b1c201c1b201c1a1d1515175e6053fffff4fffffb +fffff4f9fce1fdfce8fffeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fefefefffffffcfef9f0ffea29541e347d23398f2241972844972b328f243c7d29397f26 +2f5e27a5eabbcafff3c3fff8adffd95a967c091c1620171a1511121d241c9aa78df0ffd6 +faffe8feffecfcffef454b411f21201e1f211c1c1c12110d151b11b6bea6f6fee6fbffee +fbffe1f4fad6fffff1fffeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fefffdfffdfffcfffa5e825624651536892146992d3a8d2145942b388f263b7d252e6b1d +376525387e3fbdfed6bffeebafffd8a6fccd669e793a503b495f4a8baa88d2edc4d8efc1 +eafdcff0ffd9d2dfc3333b2e1b1f1e171b1c10150f171d0f697c5ee9fed5ecffdaf1ffdb +eafcc8e1edc5fefff8fbfaffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fefffdfffdffced6cb2151173686253c922543942b49982f4392293c8d26347c19346925 +2e601726692263ad70c1ffe6baffde9dffc695edb09dd7a79cd4a398d2989bc08cbbcda5 +bfdda1c6e1ae90a4811c2717282e2c383e3c3f493e6f7c68abc898bddba5cceab8d3f0ba +d4eeafc5d7affafffefcfeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffefffffdfdfffffefffffffd +fdfdfbfffffffffdfffffcfffffdfcfffefffcfbfffffefffdfdfffdfdfbfffffdfffaff +fffdfef9fffdf7fffdeefbf1d7ded6d0d3ccd5dad4d4ddd8e5e7e4f4f9f5fefbfffff9ff +fffefff7fff8fbfffffffcfffffcfffffcfffefbfffcfefdfefffdfdfefffffefffffffb +fffafff8fff845713e2a6f1c36882241972a439a294299263c8f233b8c253e8a28337920 +35762428641a28611d6ca36286dba08de0a88ad7a380c2947bad887a9d7f83998297a490 +9cb0978d9f873d4a391017101c2021313534555b4d6f79607e98689dae8eb2c196b2c5a5 +9bb88289a269fdfffefffcfdf8fdfffbfffffcfffffefffffefdfffdfcfffffeffffffff +fffdfffefdfffbfcfffffffffffef9fffffaf9fdfcf7ffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffdfffefffdfdfffeffff +fcfffffbfffcfbfdfafffffdf7fffffffffafffdfafffffffcfffdfbfffff8fdfff9ffff +b2cda07da7684d8b383d82273a7d2038791f32771a2a7614366b1d306c1436631e4e6440 +717e6a9fac98b9c1aaadb397b4c5a5f6ffedfbfff7fffffbfdfbfefffefffffffffefffb +ffffffb0c3ad27591c347d233e9427439b2a3e9625439a294194283b8c233f8d28378024 +367a253b7a2b2d691f265f18235a17366d2a477b3b4e82425484485780465d8048678851 +678a5053753938551f2f491c2a3e221f31212f41354456485d6f5f78887e899c7e849d80 +53754262834ef8fffffef8fffffff8fffffdfffdfefffffdfffffbfffffbfffffffefdff +fffffbfefffdfbfffffdfefffefcfdfffefdfffffff9fdfcffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffefbfffffdfefffffbffff +fafefffcfffffefffafdfff5fffefbfefdfffcfffffcfdf5fafbf6edffe590c279418c25 +2c8614287e0f2d7c13357c1e377b243881273b8c263b93234d94363b9c1b419b2043852d +235a17133d0d254015304f14315a1840612ac5d6b6fffffafffcfffffcfffdfdfdfcffff +f8fff65272492b65193f8d27439c28449f2a429c2a429a2a4295293b8e243a8b24408c2a +3e8529377b243475212f6e1d3f681a3e681c3c681b416d20447325427121477423527f2c +4b7d1e4e801d53831f517f1d4f7923497226406923436c284e723553743b5c8036557f37 +3966115d833af7fff9fffefffffdfefffcfffffbfffffdfffffefcfffff7fffff8fefdf8 +fcfdf5fefffafcfffbfcfffffffefffffbfffffefdfffffaffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffcfdfcfcfafcfffdfcffff +fcfdfffffdfffffefffffffbfbfffafffff3fffdfdfbfffa91be7b3a881b2a78152e6c1f +285921325d27355e262f5a242958242a552a2d4a2b303f2a254923337e2340982842952b +3a9129357c2c335d2d284c1e345c1e2f5019374826fbfffafcf9fffffefffffffdfdfeff +c4e2be27571b3e8328449b28409e22419f2544a12e409c2d409629449a2d3f92283e8f28 +428e2a3b85243c832541882a3f7d273b7622366f1e396e204070243f6d22416d20467122 +41712741722344732242721c4879204b7e22497c1f5083264d8023477a1e497d1b52842d +44751c567935fbfffafffdfffdfefffefffffefffffefffffefefffcfbfffffefcfffff6 +fffefffffffdfefffbf8fcfbfefffffffdfffffcfdfffffaffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffdfffffffffcfffbfbfdf8 +fffdfffffbfffff9fffffcfffefffff8ffffa9d5a044902c1b631130602e306227357a29 +38742a3a7427397424397126376b2b2e5f282b55232f54213051243c7b2c448e2d439229 +429d283b89242b531e1c30152437192e3f1f16220cc0c6c2fefffffdfdfbfefefcfefdff +5f8f552d6a1c3c8b2246a22642a22444a22843a02d429e2f429a2a3f97273f95283f9226 +3e90244192294291283d8c2337892739852a377b28336b223364223963243a6023395d1f +3158232f561f3761224270284374254273224475244073243f6e1d3f701e3e6f1e3c6e27 +3d6e1f486f2cbdd2b3c7d4b8b5cba7a8be97a5bb94c7dabaf0ffecf9fffdfcfffffbfcff +fffcfffdfbfffffefffcfcfafefffffcfffffeffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffdfafffefffffcfffafdfef9 +fffcfffffbfffefcfdfbfffbf2fff87bae6c26661a235a202e6c213889223c8a25407b29 +4277313e7d2c3a7f243776253669273360293466273c762a459e2a419e2943a22e429c2b +3f97293d8e2530691c223b1421291c1d25162a3026fcfffffafefffcfffdfefffbfefffd +2c6a1d3a8327429a2941a12444a42643a1273f9c273b9825429a293b93223e9625409827 +409627409627409627449a2b3d8e2738822135751f376b233561223259202e551c2c531a +35581e3d6423406c1d4a7d1e568d25579027548c2b4b82274d79204b791f497827407326 +42771f386d1533621a33621436611a3664193665153c691445701e628543abc69df4fff1 +fcfffdfffffffffdfffffefffdfffafcfffbfcfffffeffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffefffcfefbf9fef8ffffff +fffbfffcfcfaf5ffefddffd54f9a352555193760244286213e931a4193253c8929338729 +3a832941843440793535672a326723377b243e972b43a8303a91282f841c389a213d9e2a +39852a3d892e3982282f561f2c3c2115200fb1b6b0fffffffffffff7fbfaf9fffaceddca +246d1337892348a5323ea02545a52a46a42c45a22d409d28429d2846a12c429d28409a28 +459f2d459f2d3f99273e982648972c3c842135731d35691f315d1e2c55192c581b305c1f +386021427028447823548e2768a93164a92c5b9f265b9e2d629d2f55942149861f50892b +4c86204b842347832b4582234d86274c88244e9022579d23569b1e4b8c144a841d4b8227 +cee7bdf8ffeffbfbfbfffefffffffdfefffafefffdfefdffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffcfbfefffbfcfffffffeff +fdfafff9fff6c7edbc407a2d245b1a327b1f42982941972a45932e3e892a428b3143852e +398a213879273269263273233e9223479e2b3c7e272a521d2437232e4821468729408e20 +295d152d671d387c27365b2524451034492afcfff8fffcfbfffcfffefffff4fff59eb797 +28751542982d41a02c43a52c44a32d45a22d429f2a43a129429d28449f2a3f9a25419e29 +44a12c429f2c429f2c3d9a273790243d8f2b3e822d336b222859182c5a1c316123316221 +3b6d1641761e4b862a52942a589f2560ac2862b02961ae2a5bb12a61b52964b13160a52e +65a3285e99255c972d5a98295fa02a61a72b62ad2c5dae2b58ab2961b23169b93261b023 +618c3de7ffd4fcfffdfffcfffffefffffff8fffffbfffdffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +f8fffcfcfffffffefffdfbfffffefffcfcfefefefffffefffefffdfbfffffffefffffefa +fbfff5b2dead236b15275c16378c27449b2a459a213c8d27438e33428d28408c2a418d2b +427a2f336b2a399027409b24347a24284e252f3e2b244319264a1c326b26429b2d2f601e +213919315724317f1c2e56222a3c12475d39fcfffbfdfefffefffdfafdf4fffbff619d55 +35831e469c2f44a12c42a1294aa43348a032459f2d43a22a459e2a449d29409b243f9d23 +40a32542a42942a12b419b2a3e932b3b862b326c202d5e1d2f5b1e336120386c24376d21 +3c711f437a1c538d274b8926569a2b65b12b66b92b63b72d66b9296bbe2e66b92967ba2c +6cbd3268b62f5ea92867af3162b32864b72b67ba2c6cbf3169be2d6abf2c70c5326dc531 +67bc2962a12cf2fff6fffdfffffefbfefdfbfefefffdfffcffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffafafcfffefffffefffffffffefffdfdfffcfefffdf8fbfffffcfffffffafbfffa +a5cd98235d112c5f264199284a9d354099213b9227479a32489430468d2d408b22337f27 +33751d479b2c3c792b254c172546172954292a602c335926315f2144952f2c6820203a1d +23431a3c60323883262a4c19293b15445737fcfff8fdfffefffffffcfffafffcfe3f802e +39932142a42943aa2744aa2a43a52a419e2941a0283c9e2344972d41972a439d2b46a32e +44a12c43a22c46a53141a02c3c8e28397f273166202e5c1c316220336b203871223a7326 +3b721f4881224a86224a88235ca02f63b12a63b6266abe326bbd2d68bb2b65b82869bc2c +67ba2c66b72c63b12961af2865b82a6abd2f6ec13171c6356dc22f69be2b6dc63071ca34 +77cd34569f1988b16ffbfffafffefbfffefffcfdfffeffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffdfffffefffffffdfcfdf8fafcf7fefffbfefffbfbfffafffefffffbfffefdf99ac88a +1b5e112f6b214ca12844a033449a2b419928439b2a41962e438f2b438b253b852639832a +4a8e29276319234920325d2836622539622a2d65242b6229408c28326f2a1e39162f4b25 +285326345230408029234719223215415436fffff8fffffffbfafffcfffdfefdfb398226 +409f2745aa2a42ac2643ad2943a72942a02845a029429d263a99233f9e2642a22747a72c +48a82d46a62b45a42c41a02a3885253473242d5d1f2e5f1e356f22367b203a7c243d7826 +3f79244a87284b89244f9028589e2a64b12d6abd2f68bd2e6ebf326cbf2f67bc296ec330 +6dc53172c7366fc43368bb2d69bc2c71c4346ec33267bc2964bd276ac32d72cb3374cd35 +74cc2c6ec72d5ea427d9f1cdfffffafffdfffefffbfcfdffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fff9fefffefdfdfffafefffbfefffdfefefefcfcfcfefefef9fdfefcfffb9dc68a246219 +30792047a52942a12d459e28409d2a439b2d499e2740912841912e3987223e842e468630 +2e5622264c23347028387527386f2b387027376b233c7d2b317f1c1f37272a491f3b6124 +2a552a2e552643812b1e3d1e1a291235482cfefff7fffefffffdfffafffefefffa418f29 +3e9b2649a92e46aa2c44a92944a729439e27449b2a45992a38a21e40a32547a52d4cac2e +47ae2746ae2548a82a409724367f252e681e2d5b1d356823397e253c8a243d87243d7d26 +44832a4787294687234e91275197235fac2a65b82c65ba2965b62b6dc03266bb2a68c02c +6bc52f6fc9336dc63065be2868bd2c6fc4336ec3306abf2c6dc63073cc3471cc336cc72e +6bc32371d5345ab6137ca85bfdfff7fffafefffffdfefffdffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffefffefffbfafffafcfffdfefdfffffcfffffdfffffffff8fff8a7d8971b6010377c1f +4ba62d3ea62b429d26479e2941a52b479e2b45912f428f253c8f2340913442842d2e611e +2553243a682a3f7e2d3270253c7b2c3778283e77303d85211c4412274626336526355a27 +32592a2e6722378223263724152012293823fffffafffdfefffdfffafffefffffd499732 +42a2274eae334aae3045aa2a3fa424409f27469c2d42932c35802340812f3d7a2a438f2b +49ae2e42b12641a124429128397a282e661d3366233d772a3a86243e912544932a418629 +4184274687294587254f94295ba22c62ae305eae276dc03261af276bbc316cbf316ac22e +67c02a6bc52f6fca316bc42c70c3336abf2e68bd2c6cc12e6fc7336dc6306ac32d6ec930 +70c62f6dd0376bcd2a4c8b19eefde8fffefffffcfffbfef3ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fdfdfdfbfffaf9fffbf8fcfdfffdfffffcfffcfcfcf9fff8bbe7aa1a611536831d4aa929 +45a72c429a2a46a52d499e2941a22142982d45903544902c3c8e2044922f28651824511a +3574253d7d27427530387b2b327d223579244687371e4f17293f1b3167292f6124375f2d +2b62282e622437851f243c1c1419121f2a1cfffefffffffffefdfffbfffcfffeff4d933b +41ab2345af2947ae2b42ac283da323419e2940912b2c721a2d4829223b1d12350b236116 +3e9a2b42aa2d3e9c2c378426306d202a6418337221397f2633811c37881f3f8e253d8724 +43862546892c478a294a8e215298245da6305da92b65b32b5fac2a62af2b6ebf3671c436 +61b62567bc2973c83571c63365b82c65b82c69bc2e6cc1326dc23169be2d66be2a6bc32f +6dc23369c5366fcc36539c17b2d1a5fffffdfffcfffefff6ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffdfffefffdfbfffdfdfefffffcfffefcfff8fff3d6f2ca1f6b103d7e224aac3142a924 +46a0254ba835469c2f48a428469b243d922d43992c47982f4a91312f6d181b4e153d6e2d +3f773036822036791839792330742b36802b306f1e20311e38622336712f32642737672b +26622434602b438b281b370f171813151c14efeef4fefffffefffdfcfffafff5fd6aa660 +3aa91c47b12948ad2d46a52d469e30408b303269261b411212240c1d3d14356c29499638 +3e9b293c992744993235802531692230711f3a85263d8e273a88223e8825418c273f8c24 +438a2444872a46892a478a204d9120589e2e66ad3764af2e64ae3159a62668b53170c039 +60b12863b42969ba2f6cba3064b42d66b62f69ba3163b52c61b42868bd2e6cc1326dc233 +66bd3065b62b65b82a61b2297eae64fefffafff9fffbfffeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffbfffffefffefffdfffefffef9fffefffae9ffdd416d303982284ba9314aa62747a72a +43a52c4299264da62e3d9d22428c2d439b2b3ea0273a921a46862f1a461535652b41792e +3a862b417c2c3b7e2e32762b3778244a7f2f1e3b0d2b522535782b356f25317522365e2a +3d662e346e243a862c22361a161513101612dedce7fbfffffcfffbfdfff5fff9ffb6e9ae +349f154db031459d2c358620367a252a5c1f1c3517191e17264f1547893147a72a40ac22 +46a9284397283c8824347e1d3166223478213e9127409629438f2b468b2e428a273d8c23 +3f862044872a44852752952b5ea2314c8f254f9523569e205fa92e4e981b58a52567b430 +63b12a62b0295da92362ae2863b02c5faf2a63b32c62b22b62b42b67b93065b82c62b529 +64bb2c6eb92b66b12352a320599234fafff6fffcfffcffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffcfffffdfffefefcfcfffafffff8fbfff55b8d522a92154dae2d4da92d48ab2a44a426 +459e2a47aa2c3ea025448e2f469d2a479e2d3b912642972f255718335427387e263b8926 +357f203f7b31387f233c752e338b23315d2221341e357b233d7b2e30791d36732e337023 +377125337b253a882522391d181818131313c8c8c8fffffffffffffdfdfdffffffffffff +58a04e2c851b307d17305d222c4619202a1116231923531943a22a43a92942a62a479f31 +439d2c3e9d2534851c3a73242d6c1b3a802744952e3f97273b95233e94253e8c263f8626 +398a2442892d437d30437b2056961c68ac315197235ea6285aa72367b43261af2559a51f +529c216eb93864b02c519a27589f2761a82e5ca42661a92964ad2a67af2f63ae2f5da72a +69b32868b4305caf2166ba304d8c19def6c4fffdfffefcffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +f9fff4f4fff7fbfffcfffbfff8fffb79b96b30931249ac2e42af1e49ad2947a22b419f27 +4dac344298294193274099254aa12e419a263e98273d7e2c2350173b702c3b7f2a3c8229 +3a81253e7e2a357e243f833037872623491a2a4b203a802a3a782b347d21397631387629 +3a74283479263c8826213a1d121212171717b8b8b8fdfdfdfffffffdfdfdfffffffefefe +e1fdd7446e3e2b56202a48241f331a112b082456174b9d3746a42a40a5253d9f24419929 +3f982a3d9a27358320356d223a8027438f2d43962c439d2b439d2b3e9425418e2841882a +3d89253f8223417824467a27447c17619f304e91205b9d2f64ac2f5ba22a64ab3367af31 +61a9295ba22c5da6335aa429539925579d2959a02a5fa62e5da42a5ca329579e265ba22a +62a82b59a02860b02d69ba3949871ab9d49ffefdfffffeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fbfefffffcfffff8fffefffbb1dda23c922344ab2642a6223da11b44ac234ba92f48a230 +47a62e46982c48932e47a8274aa32f3e9c2441992b335b262f57223e872d3c7d2b3d7c2b +3d812a3c812436822743912e3877281a3516376a253c812e3776273a81253976303b7c2a +3b782a3477273f8928223d1c1717171313139f9f9ffffffffffffffffffffffffffdfdfd +fffdfdf9f9fbf8fffbe8f6e99ba3a51b3a1a47942c3ba423449b28419c233c9a223e9628 +3e952a3f962b39862839752b41922b4b9e32409827429d2847a02c419428418d293f8427 +3d812c3a78233b6e1f3b68253a6b294c832f468123437d2853922957992b4e902657992b +599f2550942551942b579e265395294c8e22519528589c2f569a2d5296274f93225fa430 +5c9f2e4e902465ae3858a32d417b149eb984fcfdfffffffdffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fbfff6fffefafffef9dcf8d275a164e1ffd8f0fff3dafed88ec87b449f2a3da41f49a72b +469f29479e2b49a02d47a72a45a02943a1293f852c2b4c1f407233388525397a263e7b2b +40852c3c86253b8d293f952a2d5a1f1f381a3e842c3a7e2b3576243d842835752b3b8129 +3b7b27357626418b2a24441b1515151313138f8f8fffffffffffffffffffffffffffffff +fffbfffffbfffefefffafefde4deea213421397f1f399121408e283e8f26398c22388b23 +3d8f293e8e2b368124387c274098274aa5303e9c243c97204199284091283e88273b8025 +3b7f1c438023467b1f366514305f19447a24558f284078153f751d569029558f2b4f8a2c +518e2753932549881f519329508d264c88244c8a274d8b2a4d8b284d8e264e902456982a +45841957942d5b9e2d4d92273f78177a955efefffffefdfbffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffdfdfbfbfdf9fff8e3f0dffbfffdfbfbf9fffaf7fffafff5fff4bef2b047a72a44ac21 +449c21479f2748ab2c46a52d419f25469e2d306120305b25458936357b23377c2340822b +428c2b3d88293d95253a91282241182d4e213c8d2e367a25377b243f892a3376273a8727 +3b8027377528408a29254d1b141414161616656565fafafafefefefefefeffffffffffff +fdfffefffffaf8fcfdfefffdfff9ff1d23192d5b1b377124357b233e842e40862e3b842a +3c852b357b22307a1b3f8b2740a02546a62b42a0283a95203e92233f8d273c83253a7f24 +3d7f1e3871224c802e50802c33651c487d2f558d2c5b922c43751e3567104c8125487d23 +487e28508827508922578e314c812550872c4d832b497f274880254d8627508c284a871f +49871c59902b4e891f4987243f7619627e44fcfffdffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffbfffffefffffefffff8fffffcfffcfffbfbfef7fffcfffffcfff9fff8b7f1a43e9f1c +49a6244fa92e42a72743a92c43a129408a29254a17407a303d8a2a397a283b85263f892a +4395293b8b2a3f98243989281d3417376826368c293879253b8428418d29347c283c9227 +3c86273a792a3c8824285a1d1818181414142d2d2dfffffffbfbfbfffffffefefefefefe +fffefffcfdf5fefffdfffffdfffef82a302216360f3262242364142e6a22366f2a336f25 +3572252d671a307719469d2c44a92943a62844a22a3f97273e8f283c88263980243b8027 +346e242f60282a5520436c30406c2f2a581a36651d3e6d1d57882f3e6c24376618477721 +3e6c213d6b2046762244732245712245712442712148772748792740751d4b80264d8226 +548c294f81224a7d1e457d263c701b5c793ff8fdf7fffeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +f8fffff8fcfbfffefffffffffafaf2fffefdfffdfffffffbfffdfffffafff7ffef91cb7f +429d2644ab2647ac2847aa2b479f2e346c21295719468a353683233d862c3e8a2840912a +4098273e91293f9928387e262133193a7b29368b243a7b29408e2b42902a3781283c9926 +3d89253d7c2d3c89233168241616161313131b1b1bfcfcfcffffffffffffffffffffffff +fffdfffdfffcfefffbfffefffefffa4a55440c240a345f2a2f6e1f285b1926531a28581c +336327316123367a2347a62e47ab2d44a429439d2b42952b3c8a273982263a8027367a23 +3668212b57182f54202346103d64233e6721325b19375c193965164e79342a5412436c26 +37601e31571c395f22385f1e375d20315819375e1b3f6822406b233864193e6c2147752a +3c701e4a7526436e1e44762f39691d47642afcfffbfffeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffcf9fffffdf7fff4f8fff9fefefffffcfffffefffbfffffffffdfffffffffbfff4fff2 +55a74338b01b43ae2249a127489b2f2b571a377125428b313681263e902a3e8c27429529 +3a972243972740992f36752424371b38842a3b8e243a7b2b42932d4190273884293c9b25 +3a8b223e7d2e3b8a2139752b1d1d1d171717161616b0b0b0fffffffcfcfcfffffffcfcfc +fffefdf9fffffbfff9fefdfff9ffff737e70111f0e2c512540802c2f601f294f1c264e1a +274f1d264e1a31752245a83144a82a43a22a3f97273f9029378223377d243c822a2d711c +335c202c53142d4a1c2e48232e5014375a163c5d28334e232f59194f7b30335b1c335727 +3457212f521c2c4c1d2c4c1b30501f3455204063293960213a611e3b6420396321345e1e +386a25426928355d17325f242e5d17345119fafff8fefeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffefcf9fffdfcfffbfff6ff +b6e0b032a41949ad274aa12c42892d235d10458c303e8028408c2a3c97223f8d27449a2b +41922941972a3d9527346e24244018429430398b253b842a429a2c3e912939872242932d +3d9028398c223687213e892a202e171514191717155b615dfbfffbfffbf8fffdfffbfffa +fffffafefefffffefffbf8fff8ffff8cae7c10320f28421d4992362e871b2a5f192d5928 +2142172644222a521e3dae2a47aa2c3f9b2c3f912f41882c3983242f7b20327525316220 +245715274916293a182534171f371329481c30501e334f1c304e1c3f6029416829264f0d +3a62232b501a2d4c202f4b252c5012385c1e385c1f37581f33541d32501e3654222f4c1c +395a2130511c224411355d1f446c2637561de8f6ddfefeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffefff6fffafffffffffffd +ebffe847b03047a82549a22c387623306e1b479130418d2b43912b3b9124409128449a2b +3f90274197283f9729336d2128441c43952f398b253b8629439b2d41942a3a882342932d +4093293f92283c8d2744902e2c481f161618140f131f2521fcfffdfffefdfffdfffcfffb +fcfefdfefffffffbfffffefff9fdfcb9d1af22471c233819439229419c25327122376924 +26511c243f1624391a418a2e48b52847a22d3d8b263a8624357b223069223264252c611d +2f4e242c4a24223f202d4628253d1b1a300c233b172e4825233f0f2d4b17446629406522 +466b2831531732501c2d49193c5c2a2e4e1c2d4b192b48182d4a1c2e491e2843182d481d +37561a4464254b6e2a395e192b4f122b461de4efdeffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffefffbfffdfcfafdfbfff8 +ffffff81d16e40a12049a22c30661b40852a48963043992a45982c3f8d27429a2a439b2a +3d90264199294199292f6c1f2a491f42972f388d253d8829429a2a41942a398a2340912a +3f952a3f95283f902944922f2c611d1618171d111d131716c2c2c2fffdfefdfdfffefffd +fcfffffdfefffffdfbfdfffafffeffe0ebdb25571a2a401c3c88243d912232732131631e +2b621f27411a1d2a163055224aaf2b439f233a8e1f3f8b29326f22335e26325a26215019 +2e4920253e17253e1729461a3858293855271f330e29361823371c223a1a29431c2c491b +3754242b47172841172b411b2d472226401b2b452028401c263e1a28401c223a1628401e +304d212f4922304a23254216244415314925f9fff8fdfcffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffcfdfefffffbfdfcfbfff8 +fff7ffc9f9bd3e9f1c4299283466214896304298293fa224439b2a438d2c46a12c409b26 +3d9024429a29419b2a2d6a1c2d4c2043992e3a90233f8d2a419b293f95283b8c25409329 +3d93263f95283f92283e8c27368124182313190d1b141615646265fffdfffcfefbfeffff +fcfffffefffffffcfbf9fff9fffcfff5fbf9387a232b4913388125448a34317021274e22 +2d691f1a39171930131a331636752644962a39901f327822306424346224274e19274624 +213c1b20341922341a1c30151732111f3a191d2f1528312022302324352321331b1d3115 +24391a22351720331729391f21351924381c23371b2134181f3216223517243719213416 +1c35151a31171f321e2940241e3612586b4ffafff9fffeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfafffcfffbfefffa +fffafff2ffea45a9253b88223c7526489c2d409b2640a523409b2647912e47a22d3e9924 +3d9324439d2b429c2a2d6c1b2d4e1f429a2c3a922242902a449f2a3e96263f922844972d +3d95253f9727429529398a233b92271b39131c171d1515171d1b1cfffdfffefffdfcfdff +fdfdfdfefffbfffbfcf9fffffffdfff6ffff41892537611733861e49953a2b6c1a244621 +3064221e3d1b2a45221e32191b331b3668293c822a2f74232b641f376827274c19294225 +283b1b21381c162e181c2d1b212a192229171d2c151b311a1d29131e2c15202e15202e14 +1c2a101f2d14202e17202c161c2b141e2d161f2f1520301620301622321727371c25351a +243d162d421932441a32441e1e2e13849180f9fef7fffefcffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffbfdfcfffefffdfdfbfc +fffefffdfcf853b33531731b418b28459e2a42a22743a627409b2446982c469e2d3d9622 +419728429f2a409d2831721e2a4f1c439b2b3b952343942b419e293e96253f9528449a2d +3e96253e982642982b3b8c233b932530651f0d190d161417191816909092fffffdfcffff +fffdfefdfff7fffefffbfffffffcfff7fffb6ca755385f1e3a9820419a26347a22325b21 +21461a29451c293d2219251114181913241229511f2f6f21276617305c2128441b213c19 +253c122439181f331a253220232a18222a13212f151f3317252e1d242d1c212a191e2919 +1f2a1c20281b1f271c21291e1e2c151f2d1626341d202e171d2b12243219233319223218 +1d3115233316263319212b13263120e9f3e8fefffafffffbffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffdfcfafbfffdfffcfffffffb +fefffffffffd5bb2412e671a44a22846a12a45a82a48a62c429d2645a029489c2d3d9423 +439b2a42a028429f2a387a232a4f1b449e2c3d982345972b409e263f9927409627429829 +3f99273e98264298293e91273f902a3d8b28133210151014141510272928fffdfcfafffe +fffdfffcfff6fcfdfffffffbfffafffefffb97b38a1c2f11398322378a1e3c802b386927 +162f0f2440171f2e19171d0f1d1f1a1517121d2f152c581b32671f2d561e24431a27411c +23351d1d2c19152113192519182617202d1c21291e12171110170f141b14131915121615 +161a191218161016141319151824101c2814232f1b202d191c29151f2c1a1e2b19162512 +152616101b13151918222423c2c7c0fcfffafbfdfafffeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffefdf5fff8fff8fffafff7 +fcfffffcfff85eab4335692147b12947a52d47aa2b4aa32f449f2a43a6274a9c303c9223 +449c2b43a12942a1293d7f282a4f1b45a02b3d982145992a3f9e26429c2a419728409828 +429d283f9a2541992943962c3f8a2b3f9c272a55271e191d13160f121615736d6ffbffff +fffafffbfff5fbfffffffdf6fffbfffffdfa5e5f59131418325d253e7e3028641a2a5d24 +22391c1f3e1e1e301a1b23181a1e0f1e26172b3721394e25395c222c591e2b5122213615 +24221345523e5973582e492a27371a2d321c232719747973939b8e878f84888e84838881 +7e847a7c8278747c6d5c645525301f2732211e2919232e1e1c29181f2b1d4854465c6a5b +6374617c8874919584e8eadffcfefdfefffffffffffffefcffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffefffbfffdfff8fff9fffcfd +fbfffbfefff661904838822147b12b41a8253aa02036a01c34a017339f182f9518399a26 +469f2942a12947a2233d8e252b531e399d29469e23439821459c273b9a263c9b27358e1a +358e1a33921e399725439a273d94293e982641882c19350f17151a151219121713d4dad0 +fffdfefbfffffffbfffcfefbfbfffdd8bfc52e1018251214181f0d263a212a4526273c1d +1f32161c30171b2e1a14201215251b2030162f4c20355c27365422374e203a3e1b3e220d +601d0c7e4e387fd79b5b74563c3a23443923525d4cfffdffffffffffffffffffffffffff +ffffffffffffffffffffffff68905c3554422e32312e352535381d575b4cfffcfdf9ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffefffffefffefffffefff9fffffafffdfffffaffffffff +fffdfffffcfffefcfffffefffffefffefcfffefcfffcfefdfdfdfbfffffffffffffefefe +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffcfefbfffdfffefffffffeff +fdfcfafefdf8508d3d3d9b1f44a5224fa72f8dd073d0f9bfe3fdd8e0ffd5ade19764ac46 +3c992637a11946a2254093292c541f3d952d41992b489f2c33a11a3998204d9b3689ca76 +90cf7e77bd654a9c3633901e409925328f1c4a9c3a2b5d2015240d191514181119403a44 +fefffffefffdfffbfcfbfffdfbfffa8f585d50181b3517152212121a1a12151b11181911 +191911171a13181a171614150e1e14312a1a492b13622a137923147b1b0f871a179c131b +a31919a1352b86c78d557e563741263c3e26b5c2b0fffdffffffffffffffffffffffffff +ffffffffffffffffffffffff9bbf93477052353f343b402c35351dc5cbbdfffcfffbffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffcfffbfbf9fbfffffcfffffefbfffffbfffffffbfcfff8 +f9fdfcfcfffafcfff4fbfff9fbfffffcfffafdfff5fefffffffffdfffffffdfdfdfefefe +fffffffffffffefefefefeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffefffffffdfefefcfffffdff +fffbfffffffa398928399e1a79b764e7ffdcfbfffdfff9fffffafff9f8f6fcfffaf9fff8 +a4e798499b2d3a9f1f43a02d27481b3c8d2e429c38389e1e428c1da7d29cf5fffaf8fff8 +fffffffffefff1ffec9bc97e3a9520399322379024478d341b360d1e111a1e12200e1712 +818284fffffbfffefbfbfffffffdf18d2f3072121349161239161c2a16181f1315201418 +20131a1812161914181f141a231417400f126e16149e1a18b8181ab21619ad1416be151c +d7121cc51d1d99bf825c95603b452a525540fbfff6fffdffffffffffffffffffffffffff +ffffffffffffffffffffffffc5e3c1558a5e3e50383f432864614efbfffafffdfffbfbfb +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffcfdfffffafdfffcfefefffffefffffffbfefff7fefefe +fffefffcfbf9faf8fbfffff8f7f8d9eeecd5fff9fafffbfffefefcffffffffffffffffff +fefefefbfbfbfdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffefefffcfcfafffeffffffff +fffafff0ffe831861f7ac465fffffffefffafefff3fdfff4fffbfcfffbfffffafffffffd +f2fff4cde9c03c9e273ca31e324e263583203fa132319c1ac4e5b8f5fff1fafcfbfffdff +fffafffff9fffefcfff9fff3cefac54c9738309012499d2e3b6b2d1b2d170f160f131a12 +19141aafaba8fbfbf9fefffff1dad49315168e14116016133f1312321613271815241518 +1f13171814151615111a15111910113d14186b15149e1713b50f0fb11113b51b19bf1112 +da0f13d31614a5af705c9c5f3b3b239b9587fffffafefdffffffffffffffffffffffffff +ffffffffffffffffffffffffebfeea67a76a415b36373a1bc8c4b8f9fffdfffefffffeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffcfffffdfdfbfffdfffdf8fefdfffcfcfff8fffffdfffcff +f8fff9c5d1b9ebffb9daf58eb8ce7cadb989b8bda6fcfdf8fefefcfefefefdfdfdfefefe +fffffffffffffefefefefeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffdfafefdfefffdfefffa +fff9ffd2fac83f882cf4ffeafffcfffffefffdfdfffffffdfffff8fffff8fafff9f5fefd +fdfafffffcffa2de9630980d2b531f3e84243096179ad488f7fff9f8fff8f9fff8fdfff7 +fffffaf7fef7fbfffdfefffffefffdf4ffea6da858248b083ba12228641c182a14151611 +1c131815141297989afff8ffc48e8ea212129a16117218184c17133a17112b1613241415 +2115171b1a181819131a17101818163213186115159b1712ba1615ad1416a71313c11515 +d31715dc1a11af975b5a9f5c46412bede6dcfffefafcffffffffffffffffffffffffffff +fffffffffffffffffffffffff9fffa72ba6e3c572e68684cfffaf6fbfffdfcfbfffffbff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffefffdfbfcfefbfbfbfffffbfffefffffefffbfffcf4fff0 +4e883e3e7e1eb9faa09fdd945c9a4d5994405c943b7db44efffffdfffffffffffffdfdfd +fefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffdfffafcfdfffefffbfffffa +ffffffabe2a14e7c3efffafff9fffffffefffff9fffffcfffcfffffbfffffdfefffffdff +f9fefafffcfff8fff368bc4c2461142e6c1956af3bfffefbfffcfffffcfffffcfffff7ff +fffbfffffefffbfefffffefdfaf9f7fff9fffcfffa89ca7a2f95163b91243562291e311b +191c1112171013141872676d822b31af191a9b17127b161a59181c4214163113152b1218 +27141a1d14191814151d1415101d16271416581617941713af1112a91c25a8272cae1517 +cd1714e0130ebf764963a661666b55fffff8fefffdf9feffffffffffffffffffffffffff +fffffffffffffffffffffffffffffd90da853c522ecdccb7fffdfffefffdfffffffefeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffefdfcfffdf8fffafefffbfff9fffefbffcee9c8467f2e +3e9a1d52af3a5aba3c3e9f1454b1245db427479617377a19e9e9e7f7f7f7ffffffffffff +fffffffefefefdfdfdfefeffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffbfffcfffdfffffffdfcfcfa +fbfdf87daf729dac99fff7fffffefbfdfff9f9fff8fbfffafefdfbfffdfffffcfefdfcfa +f9fff8fffefffff7ffd1ffc92b7119205e13b4eda6fffafffffefffafafafffffdfffefd +fdf9f6fffffbfcfffdfbfffffffdfffbfffdfdfcfffffdffdaf6ce4f9d3842952d326723 +19371114211015131617140f8b1c22b61a1b9814107d14185914194412153414152d1418 +2714181d141918131720151b2824215a40497f3e4492211d961414bd5e64e49c9dc16860 +cb1b1be61211d25537669859aab29dfbfdf8fefffffdfeffffffffffffffffffffffffff +fffffffffffffffffffffffffffdff8fd87e6b7b61fdfbeffffefffffffafdfcfafeffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffefffefffdfbfdf8fcfcfafcfffdbcd7b63577203fa01d +4eae264bab2549a6244aa3254794243c792b305c2751783ffefefcfffffffffffffdfdfd +fefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffbfffffff7fffffefffffeff +fefff8557d4beee8f2fcfff8fcfffffefdfffffdfffffefffefdfbfefffdf9fffdfbffff +fffffdfff9fffffdfff2fff85a9b47185c11d3f0d4f4fff4fefff1fffdfffffcfffafff9 +fcfffbfffcfffffcfffefff3fefffffcfdfffffefffff9fffffeffeaffe4448a31349b14 +346a2e24381f201a1a181a0d94191bb21212a11b1880161657171843161133181128150f +2217131c1b17171715191516323c345b52559367687d20188a1d1ae4949dfbbec5ed9999 +c52321e91416d134234f7037e0e1d1fffefdfffefffffeffffffffffffffffffffffffff +fffffffffffffffffffffffffffafd599e43c9d5c1fffffafafafffffff8fffefbf8fdff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffff8fffffffefffffafffffdffe4fddd41822e3ea12343b426 +49a633429d283b91223c872c37702b2e571f264013c2cfb1fefefcfffffffffffffefefe +fffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfbfffffdfbfbf9 +fffffd979795fdfdfbfffffdffffffffffffffffffffffffffffffffffffffffffffffff +fcfffdfff9fffcfffaf8ffffbbd6ad115114aeb7a6fffbffffffffffffffffffffffffff +fffffffffffffffffffffffffffcfffdfefffbfffafffffdfffafffffffde8fddc598645 +34922032712028441b15321c321f198b18259b0f188718115b151d491217371412281914 +1f1a162213162211171b161c3636364e4a4b82646275292b90333becaeb3f8bdc1d26c77 +c71815e31311c6251b4a4734ffffeffefdf9fffdfefffefffffefffcfdf7fffff8fffefc +fffefffffffdfbfdfcfcffffebffdc829076fcfff6fefefefffefffffefffefefffdfffe +fffffffffffffffffffffffffffffffffffffffffffffffffffdfffbfdf8fcfffbfefcff +fffbfffffbfffffefffefefcfffcfdfcfcfefffefff5fff351953e389d1b44ab2843a628 +439b233a8c26357d27346c2131571e2235174c5244fffff6ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffefefcfffffdfffffdfffffd +fdfdfbfdfdfbfffffdfcfcfaffffffffffffffffffffffffffffffffffffffffffffffff +fbfffafffafff9fcf5fbfffdf4ffef1954128d928bfffdffffffffffffffffffffffffff +fffffffffffffffffffffffffefefcfefff8fefff6fdfcf8fffcfffbfafff7fff8e8ffe2 +4386372f751c3f7925336528144817452d138517186a0e0f5319184f14163d17162d1513 +2910132115171919191d14172928264a46477b6162894447c67079f3b6bbeea8aaba414a +c90e1fef1a14c0160967353efdf6fdfffefffefffaf8fffcfefffffefffffefffffeffff +fcfcfefffefffffffffbfef7deebd7e7f2e2fefffafffffffffefffdfbfefffffdfefffb +fffffffffffffffffffffffffffffffffffffffffffffffffffdfefffffdfbfdfaffffff +fffffffdfdfbfefffdfdfffcfefdf8fffcffefffee5a98453a85204a98353d922b3d9024 +3f8626387d24336d2328531e233e1f0d1b0cc1c7c5fefeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffdfffffdfcfcfafdfdfb +fffffdfffffdfffffdfffffdffffffffffffffffffffffffffffffffffffffffffffffff +fbfff9fffbfffdfef8fefffff9fff9508042747879fdfcfaffffffffffffffffffffffff +fffffffffffffffffffffffffefff6fcfef3fffff8fdfcfafffefffffefff9fdfefbfffd +fffdf357864f217216427d2b2e662521511f55321c851917581212461612391614341115 +2b10152216181c181718141323221e504a4a836a6e90575de79ea7efb3b5de8889b01d23 +d91521ee1617b7120c6c1921d3decdf9fffffffffffdfdfdfcfdfffefffffefffffdfeff +fefffffdfefffbfbf9fffff8fbfffafefffdfefefcfffefffffffdfffffdfefffbfefffb +fffffffffffffffffffffffffffffffffffffffffffffffffefffffdfdfffffffffdfffa +fbfffafcfffbfafcf9fffffffcffffd1e6c746862f3c9a20409128397b23387824306e23 +2e65222d5f1a284d17253e21101d13525952fdfffefefeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffefefeffffffffffffffffff +fffffffdfdfdfdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffff +fdfff9fffcfffffffbfefcfffffeffa0c4985c615dfffffbffffffffffffffffffffffff +fffffffffffffffffffffffffafefdfffffffffdfffffdfffefefefffffdfdfbfcfffdff +fff6fff8fffa5b8458265414323e181b27191926125f3016621616431610311410301315 +29161824141522141419151224241c4f46477d666cba8891eeafb8e6a8abb04e4db41114 +dc1512e21114ab1d1b73220f4580249bc289fdffedfff9fffffff4fffefffcf9ffffffff +fefff8fafff6fffffffffdfffffffffbfbfdfffefffffdfcfffffdfefefcfefffdfeffff +fffffffffffffffffffffffffffffffffffffffffffffffff9fffdfefcfffffdfffcfef9 +f6fdf5fefffffffefffefcffd0e8d22e761347a92041a0283b9229387f1f376d222d5d23 +295323214515253b15212d191b2117d9dcd3fffff8fffcf9ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffcfcfcfffffffefefe +fefefefffffffefefeffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffdfcfcfcfffefdfffcfffffaf8ecfff074786afdfffeffffffffffffffffffffffff +fffffffffffffffffffffffffdfefffffefffffafffffefffffffdfffffafffefdfffaff +f8fffff8ffff9bae9b0f330d2635201e171e101c1a2230195028204b19183815132b1716 +2a141626131521161422141329261f4b41427e676dc3969dedb0b8e8aaafae4e4faf1316 +d81415e1191b941411783d1564c92f56a41a89b057f6fff4fffefffffdfcfffcfdfffdff +fcfcfefcfff8fbfdf8fffdfffcfafdfffefffffefcfffffdfefdfbfefefefdfefffeffff +fffffffffffffffffffffffffffffffffffffffffffffffff7fffbfffefffffcfffffffb +fefffdfffcfffffafffefffa50963d43a62745ad24419f253e9a2b3884293870252d5f16 +28501e213f1922341a1b250d535a48fbfef7fffefdfffcfbffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffdfdfd +fffffff9f9f9fffffffefefeffffffffffffffffffffffffffffffffffffffffffffffff +fffcfffcfffbfdfcfafffefffffcfbf8ffffe9eddefeffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfefefefdfdfffffffffdfdfdfffefcfffffffffeff +fcfdff8591851a3b201c321b122311142b1b12140f1b171627291b3a1d194514183b1417 +2d15152617142416152113121b18135041448f7479ae7d81e3a0a9fcb9c2ea9598af3134 +c51518cc0d1596151a78531c62d02370d12c65b82072b951f2fff9fbfffafffbfafffdff +fffefffcfffffbfdfafffefffffffdfffefcfdfcfafffffdfefefefffffffffefffefdff +fffffffffffffffffffffffffffffffffffffffffffffffff8fffbfffdfffffdfffefffb +fffefffdf2fffcfffaafcea233a21545a02747a52d41a5293f962d3d882d3b7d252d6617 +30591d2b492521331d1e2e1347573af6fff2fffefffff8ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfdfdfdfffffffdfdfd +fcfcfcfffffffefefefafafaffffffffffffffffffffffffffffffffffffffffffffffff +fffcfffbfffdfffffbfdfefffff9fffbfffffffffbffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffbf8fefffbfcfffbfefffffffdfffffefffbfffff2fff8 +4d62591a261224371b1820111d1d131d2a18171b0d1a1112101d141d1c17391718411316 +3216132c17142a14161f13131e18185c4c4f947678b37d7db3686fefa9b3ffc4c9e18588 +ad1e1ac4151c9d17206355146dcd2e6ec33471d12963c9277dbb4ce6ffdcf7fffffefff9 +fefff3f9fdfcfffefffffefffafaf8fffffdfefffffafbfdfefffffdfdfffffffffefeff +fffffffffffffffffffffffffffffffffffffffffffffffffcfffdfffdfffffdfcfbfffa +fdfefffffdfff0ffe648922f3aa420469c2d499f32409f2b3f92283f8926367b20356e29 +2b511626421a24381f28421d2c4d1888a674f3ffedfeffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefeffffff +fdfdfdfffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffff +fff9fffbfffffefffafbfffdfffafffbfff7fffefffdfdfdffffffffffffffffffffffff +fffffffffffffffffffffffffffdfffdfffcf9fffbfcfffffffdfffffcfdb9c5b92b452a +14320e1b3a112435151c2b18171d19151419161f1e161616101a191419151f1a14331a15 +3f13143213112816162815171c1618635054a78886cc908f924046ca828efbc2c9ffbdc1 +d7625bb6180d9716115a602061b22f62a62d75c92971d03666c1265fa21eabcd81fbfff4 +fafdfffcfffffffffafffbfffefffff8faf9fefffffefffffcfdfffffffffcfcfafffffb +fffffffffffffffffffffffffffffffffffffffffffffffffffefffffcfffffffbf8fff8 +fafefffbffff8bbb7d329d1146972e369328388e293f8d2040941b38862037732b285f1c +2a4a1828411a29402327481b366517528328a8c78cf6fff2ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffcfdfefcfdfefffffeffff +fffefffffffbfcfffbf8fffbfdfffefffffffffdfffffefff8faf771806d102b08204416 +284c1e203f161c34141f2e191d2518181d16151a13151a131217131b1a15161e11242f1e +322618381c112f16112b171927140e6d5054b68c96d49ca5954a4e842b2ff9b1b5fbd4d5 +fd99a1ba2832851e0b5475264d912469b22f77c2345db7245ba63069c02364c41c80c260 +f1fff7fcfffffbfffffefdfffdfefffefffbfefffffefcfffffefffffffbfffefffdfeff +fffefffffdfffffcfffffcfffffefffdfef9fdfff9fefffafffffdf9fffbf7fffbfffdff +fffffab9dfb040912a3fa71c41942a3a8b243882213a7c243a7427376c262e611f245617 +2e41252c491b325c1c3d7126437e2a498b2958a42a69bd31b9e29cdffccef7fff4fcfdff +fffbfffffffdfcfffdf9fffffcfcfffffefffffcfcfffefafffffbfdfffcfffffdfffffb +fffefffbfffff8fffffffaf9fffffbf8fffd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffdfffefefefafffcf9fffb +fffffffffcfffffcfffffefffffafffffffdf4fff09ab3962c4b2912320d22401e243d1f +24431a233d1a21351a1e2b191a2217191e17181d17161b15121b1818171222261722351f +26321e321b13391213301317301712714a4dbd9097d5acaaad625f96141ed05a66ffd0cc +ffb8b8bb3d496f33115c923c4a872a477d1d53861d5da71e70c53272cc2f73c9286bc11e +75bd3de9ffd4fdf9f8fffff8fffff8fdfbfffffefffefef4fffffafffdfcfffef9fffffb +fbfffafcfffbfefffdfdfffefefffdfefffdfefffdfefefcfffbfffffefffffefffafffb +d7f5d13a7a2449a42d40a5253d9328388922337d1e32721c2e661b2e5f1e2d591e29541e +2b531f2e5f1d38721e427f224282244286214a972557ac2d52a52356a42d64a7407eb759 +9ecb76b3d78fc7e2afdaf0caf4ffeafafff6fefffffefffffbfffefbfffafffffffffcff +fffefff1fffbfffcfffffffdf6fffffffdff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffcfffefffffafff9fbfffb +fefffffffbfffffbfffff9fffffeffbec6b9435e3d1d49142c5e2324511a24481c1e3916 +1e37191f33181e2d1a1b2318171c16191b16191e18181d17151d1f15140f222f1b193819 +1b2e18271e17381a1a3d13153c1a1174363bcd8c92dda6a1b0514da00a13ae1c26e27878 +d25654a616207c5d1a64a434498627417b2659913a66c33663b2326bc62d73d02a6ecf20 +69cd1d68b032f1ffd9fffbfffffcfdfffdfffdfbfefffff8fbfdfcfffefffdfdfbfffefa +fbfffbfafffcfafffcfbfffffefffffdfcfffefcfffffdfffefbfffffafffffefdecffe4 +44883336941c3fa2233d9c2640952d3c8d2737802434742032671f326020335c22325924 +2a6219336e1e3d7c23437f273e7a243c7b22448b254f9d2d539d2e4e9d2a4da62855b628 +5bbe2355b41c4da4194e9d204e8e1e639c357bae5298c374c1e5a8e8fddcf8fefafefaff +fffef8fefefcfffefffffcf9f8fdf6f9ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffefffffcfefdfefffbfffffd +fffefffefdfffefffbfcfff36b86652040191a3f13254f1d3e6b3438632b244b14254a14 +1d2f19182615141e13161b15191b18181a17171c16181f181a1e1f1919111e3d1d174018 +1c240f1c211a24271e41181258130e7722259d41469a3334931614a91a16ad1313ba151b +c417139e0f09929e3074b6324f8c253f77203d64214f9429569a355faa2b6bc62d72d53c +6dce3167c6246dab40fafff5fefffffffff6fefffafefefff9fefffbfffffcfffffffeff +fffcfffffefffdfefffefdfffffdfffffdfffffdfffffdfff7fff3feffffbdccb7478230 +46a62841a52740992b3e91273b8b2a388525377d24357622356f22376c24376a25356624 +386e223770233a7025376a2732632135691e4181214e98294ea32151ac2955b93257c332 +59c62f5cc62e5dbe305ab62f4eb5254daf244fac2050aa144fa60a58a0168dc45edfffc1 +fbfffffffcfdfff7fffcf9fffbfff8fffdff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffcfffffdfdfffffcfffffcff +fcfcfef7fff8b7d3ad3e632d215e1033682234612615390b24431a2f4d2726451c224318 +1d281a192018151a14181a17191b18161b15151c14151f14181d161c20121e441d265423 +222b101d281a1a311d3832186f18117a131491181d9d1519a61816ab130eb61210c8181a +d81416a6311d89c23f7dbe3c5c9b33548b2e2f4312365021467f215b8c3067ad3369c830 +6bca2e67bd2868b62f7bbb4bfcfffafcfef1fffefdfbf8fffefffffcfffafdfef9fefbf6 +fffbfffffefffefffdfdfffcfefffffefffbf2fdece0f3d7a9d19f577b4f1e530f429926 +42aa213a97223b88283c83273a8329378027387e263b7d26397b243a7a24397b24377922 +3c7129366b253065212e611f2d601b326c183f86204f9e294eb0254db22851b52e55bb31 +57bc2e59bc2b5cbb2b5bb82954b83157bd2b5cc52a5ec92b61d0345ecb325cc12568c627 +a9ed80fdffeefdfff7fffdfffffffbf6faf9 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffbfffcfffefffffbfffefdfb +f5fff08aab7e295d15306e183b7f1c37731b32641f2b4f1f1a3115142515101b1317221c +191e171a1f191a1c19181a17171916151c14131f111422111c2b141e2c1520431b36682d +244413202e152034192d4e21664927881b14a011159b1514a91717af1412b61914c51515 +da1310af472281cf4571b433569b305d9f314368231b2b0e263d133c651f4a8022539321 +56a61f69ba3171c23748aa07cfe2b5fcfff8fffafffffbfffdfbfffbfdfcfffffbfffcff +fefff4e1ead9b6c5b08f9e8b6c7b684d644739602b31661e2a681d266b103e922347a72a +42a527439a27317b1a357926317520327621377824397b24377921357a21347b1f30791d +346d26306c223170213676203b7c203e851f4595264ba22d4ea7294da6264da8274eab27 +4eae284baf2949b02b46b02c4eab274ca62a50ab324cac3149ae2a56bd2e61c52f61c129 +60bb1e74c72de6ffc0fbfffffffafdfefff6 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffefffafdfbfcfffffdf5ffee +6c915d2c62143b7c20458829407c243b702230591f2c4621192815161d1617181c1a191f +161813181a17191917171916151a14131e101827141e301a28441b253c1f214118356e2a +2a611d223d14293f1b2c57214670307c4325971c1499140fa61615ab1715ac1210c31717 +d01b10ae401d76bb3e67a22a54902c5a942457912d2c3f111d1a21203d0f3e6522476b2b +5d943769b43563b6285fb92699c882f0fff3f8fffffeffffc7d2c19aae8972885a51623e +36462b233819162d1016291316271417320f295c1942892d418f2c4aa32f48a72943a129 +4ca73249a22c40932730791f2f701c306f1e327120367323367323367524357624337422 +346f1f357521397d263e8527428826428825418c2740912a41912e44972f469a2b439a29 +439a2943992a41972a3e94293f99283f952647972848972a408f24408d234b94294d9228 +4d93304b9f168dd06fe8fae0fffbf2f4fffb +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffafffffdf9fff858774e +2e64183a7e1b478b28448529376f282f5c231f3d1716230f1d2019191a151b1c16191a12 +171916151513141412181a15181d161621111d2f192e42272c511b2a44211841152f6f25 +3c762929541e3354293b5623326c224f6f2e7f351aac13159c1210a91b1ab91015b11614 +ca1317b728205e852c548122527c3057862a48972a44662912140f1d1d1330441f2b5817 +3d6e1d51901e66b52870c23263ba1d66a72f5276392f47272e4f1a2a55101c47121c411f +1f32141e32161e32191e2c1d1d271e1f361a2a5a1c377e22499d2b409d283b9823419825 +469f293b9d2445a42e3f93243d7d29377723357020346d20346c21376f26376f28356d26 +3971183876203a7b273a7b293979253977223a78233a7a243f85253c842138851f378822 +3b8926388125387d243c7c25308021367e2a3575273879273e8122377d1b367821337128 +396727305e13448833b9e8c8f6ffeefcffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffdfef8fffcffa5c99d245617 +39662143781c4672272a53191e261b1d241c1d221b1a1f19161b17131512101211161817 +19181e333736394039151c15181f17182615233e1b244c1a2e492818380f2f5a242d601e +3368203c71293c6e293c6a2940622f38712c5062267d311aa01413ae1613a9160fa61414 +b5161ba61e22384b1d405d2554722c5a8b32498b2748842037452c15150d2321221c2f13 +2a4f194c831d62ad2e6acd346bc12a55942b1c430c2b4623314e1e2c4815293a1821271b +1e26171926141b2a171d251a1f211c1e2b1a224819377029388d253d9527419c27469d2a +4296274194283c942444a12e489a2c37851f3079203272242f6d24316d25337022316f1c +30701a33711e367121346c21346921346722336621336621346b27366e27357225367524 +387824387925357521306f1e2f691f2f6d243272282d6b1e2d651e3060242a5122254a1f +25441b20391923362249564cbdc9bff4fff3 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb6f96612b5c1a +3c64253c681d3f5e23223b111318111217101a1f191315121416133739386d6d6da6a6a6 +f6f5fafafcfba8afa80f160f1c24191f2e1b29442129511f27461c20451238662830641c +356b1d42782a3d6f2641702a4b84254b761d3c71213f5c24752d1ea60f14ab1016a0171e +a2130d9a3a106f9e346792295f82246895385b943347761681a064a8acad201c1b121816 +1a31153a5b224f82265196225ba22c43772525441b31482c28421d1f3a111b2e121d271c +1e26191724121827141822171b201a1a251719371328551e3576223f8a2b42982b419928 +378d1e398a233b8924388621429124408d25387d2032721e336d20346d20346d1e366f1e +336b22336b22326a213166203063202e611f2a5a1c28561827541928581a2b5d1e2e611f +2d611f2c601e2c5f1d2d601e315f1f2b5c1a2b601a3166222f601e2a5617274e19204319 +182c110f1e093b453aa2a8a4fbfffcfbfffb +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffefefff8fff1406a2a2e6017 +385e213b5f2140522a29311a12141117191631333071716fcacacafcfcfcffffffffffff +fbfbfdfeffff5c5e5b10150e1f271c1f2e1927431d264c1b284d173760243d6c263c7123 +3d74213d72203d6d213b69204b822e4f86324a752e3c68293f61256d411c911e178c131c +941318995f16b8f653bff94f9ed44083ba3a68ad384f86214f842af4fff5e9e4ea4b454f +12161719251b22370c36502041701f36581c283c172f3f22243a14243f16243a161d2d13 +1d251a1724131726131723151c211b1b20191625101934132d541f3b702c357e25368824 +388a263a85283a7e273b7c28317a213379232e6e20316d25356c292f63252d5f242f6126 +325f262f5f232c5e1f2b5d1e2c5e1f305d222c5721274f1b26421924401722411824421c +24421e243f1c213c19213b18223d1c22401a1937111534121a3a151d3c131d36180d2213 +2a3129818680fffffdfffefffffefffcfafd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffff8fbffc9e0c32b5a12316417 +345f18365d1c30471b2f3626848484ccccccfbfbfbfffffffffffffefefffffffffefcff +fefffddfe1de1719161f221b1a22151a2912213b162d4e21325a1e3e6b2a38671f3b7020 +3c711f396c1d3f6f23406e25476f28587a30537e2f517e2b638d2b7baa388e98378f5317 +7b2914af9936ccff52c3fc3eb7f842a3e23c7ec93b529426397b1a92b478fffdfffffbfa +9d97a33737411619101312171d360e30411f212b10232d1428381d293e1f2b402126391b +1e231c192416162413142012191e181b1d1a171c151b23161a28112a46202b5b212a6721 +30702434742636752637762531752036772335752137722230661b295c192c5c1e29561d +294d1f294f1e27521c28551a2c591e2f5a242d5320284c1e2d3e1e25381c1d2f17192a17 +1b291a1c281a1d281a1f271a1a2b182e3c2d606e616674674c5d4d4d5b4c404644868690 +fefefffffffffdfbfefffdfffffbfffffdff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffcffff7da173275b11386b1e +3c701d3d6c1b2d511445553bfffdfffffefffffefffdfbfefefefefefefefffffffefefe +f8fff561665f11130e1a1d161c2415223218263e1a28441c2f561d335c2037662235671e +36691e4070263d6b23426f2a4f6d254d7628517329617b316c943375a92b90b935a8c449 +a19b3db3c245b5dc43afdf3ea3e637aee83b99db465c9a2b4589264d7f1ef3ffebfffefb +fffcfffdfeffb6b8b74a44521116191516181212101618130f160f121f161e2e23142417 +151a13161e13162214131f13161b151717171513141614151a1b150d180a13270e203d1e +2b50252d5c262d66212d6e1c306c262d661f2e681c376f2434672228591827541b244f1a +24431a26471c274b1b29511c2b541c2b531e284f1a24491626431726451b25431d223d1c +1f3a1b20371b21351c21331b1a320e2a39226f7a6cdde6d5f9ffedfcfff6fffefffffaff +fffefffffffffffefffffffdfffffdfffdfe +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffff8fffa3f723034681d45752b +4a7e294e832b39671e4d6740fffefffefcfffffefffcfcfcfffffffefefefcfcfafffffd +c9dac7121d0f1a1f181a20161c27161d2f15223718223a18264b172e551e3a6327376423 +35641e3b6a243b68253663203c6e27466e2556762b5c7c335c7d2c718c2f839f3981a13c +91ac37adbe4ba5ba45a2c841aeeb45bdfc4d93d3415a9930549628437d0f91b16efcffff +fffefff9fdfcfbfffffbfcf7cac8d39390978f8d909999998587866a6e6d515a553d473f +3f413c3e433d3e453e444b44565b57747474918f92a49fa3a6a4a5a2a2a2787d79394039 +192517142d10204718285c1c2c5529244f21214d1a25511c29541f234a1b1f441922441f +28441e29451d2a491f2b4c1f2a4e1e2b501d2c531e2f561f2a5f192f6720336b24326925 +3165232e602129591f24511a284e1d1f3a171b2a1322301968785de8f6dcfcfff4fffaff +fefffffcfefdfefffdfefffbfcfef9fefffd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffdef1de2d6d1739701c3d6620 +3664194170223c6c204f6d3bfffdfffdfdfffffffffefefefffffdfcfefbfefffbfbfdf8 +465f4210210e1820151f251b23301e1e30161b2e1225381c254516315321335920355d1f +38622233601d406d2a35621f355d21466f2152842557842763812b758a2f7f983389a23d +8ba13c98a2428da43c98c03ca5dd3aa1e63e7ebd3b589035609a2c54922748791eeffdec +fffffbfefffffbfffffffff4fffffbfefffafffffbfafbf6fefdf8fffffafcfdf8fefffb +fdfffcfffffffefffffdfffefafefdfdfffefffffffffefffcfcfefffffffffffffffeff +dad8d97577722f3d2c10290c1a3212203a1727431b203f152140142a491f29451d264019 +203e1a213c1b233c1c263f1f26421c26471a2b531e335e26357326377826397b24397b23 +387a223777233370222d691f2c5f272d561e27461a223c1f193c12395f22dffbcbf8fff8 +fffffffefefefefffffefffdfcfefbfafcf9 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffaec6ae29710e41781b476c27 +375f20345d1b3661194c6732fffffffffffffdfdfdfffffffbfdfafefffbfcfef9929790 +12310f1d301a1924161c241924311f1d2f1523351b28361f2946182d4a1a345721355b1e +3d652635621d3d6a253867213e54303e5b214e702453792e5680346c933887a83797b539 +98b0408e9f377ba1309ac844a9d6477ebb3065952f4e722a52852657992d3d751c8ba66f +fffefafffefffefefffffef9fffffbfbfdfcfefffffefdfffffdfffffcfefffdfffefbff +fffffdfffffffffdfffefdfffefffffcfffdfefffdfcfefbfefffffcfffdfcfef9fffffd +fffcfffffbfffffcffb4b4b65660572e3a2e212f1e1b2e1a152812172b12172911192b13 +112e0f132d10172e141c30171a331518380f1b46112353192a631e2f6c1f3676223a7b21 +38791f36741f347123356f25326f2a306610366217305a2a336624447e175d9034e1ffd9 +fffefffffefffdfdfffdfdfffefffffefefe +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffdfffbfffdfffffbfffcfffcfffffcfffffffdfefffeff76aa62397c1b408727478824 +4d8427417221345e14456131fffdfffefef6f8fff9dbe4df7f797dfffbffdbeed81e5b0d +25481e1b35101a2b191d291f2434171d321321351c263b1c2b4b1c29481c325324345721 +385f1e3d66203d6725315a1e3f6721385d29375e27406728476e2b6187327ea53298c137 +98b73f84ab3885b53b87ba37709c2d577630435e274865234d8321588f31568f283f6e12 +bfdaa7fbfffffefafffffffafafffbfffffdfffdfffffcfffffefffbfffafcfffffdfeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffefefef7f7f7e7e7e7d0d0d0b6b6b69d9d9d8d8d8d +747e736771665965594f5b4f495549455346414f423b493c1c3c17163b0f2350192b5f1d +316b1f397626377522357320326f21326d1d3d78283b76224380234a8b25498f1f62ab36 +fffff3fffbfffffdfffdfff9fdfff9fffdff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffdfffbfffdfffffdfffdfffbfffffefffffffefffeffff508e3b3d841e468c2a508e29 +4f87244e842c3f6b1c5b7649fffefffefffdb4beb31420141419153641334f75442a6b19 +24471d213b161a2b191a261a2434171c311023371e273b1f30502129481c2e4f2031541e +396021365f1b37611f345e1f3c5f1b3f621e385b25385a283e602446652956742c7a9a35 +82a330769629708f32556e2c384a20374c21496a2378a5407fb3345e9339528e2c4b8521 +426d1ecee5bbfcfffffdfcfffffefbfdfafffffefffffffbfefffbfafbfffefdfffffffb +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffdfdfd +fcfffbfbfffafbfffafcfffbfbfffbfbfffbfbfffbfbfffbdee5dda4b1a05a6e532c4c23 +1d48131f531329651d34722737782632732131701f39792539772237731b407d20468324 +aedaa7fbfff6fffcfff8fffdf8fffdfffcff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffefffcfffdfffffdfffcfefcfffffffffffffefff5fff43c88263f8b1f428524518b27 +4f8a20508c2c3867177f9870fffefff8fcff535d521b2817223724254c1d3471212f751f +2c5024213d171728151e2b1a2c3c1f1e331221351a2b3e222c4c1d2b4b1c30522031541e +3d6326315a18355f1d3a6425344f243a542d3d5a2a3e5d243957253550272d461e2d4718 +2b4021263919374b18657a2d728a2c84a635aee448baff37b2eb4479b23f4a8b274f9228 +3e7718477024bfd9acf6fff7fffbfffffafefffffdfefffbfefffafffffbfffdfefffdff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffefefeffffffffffffffffffffffffffffffffffffffffff +fefcfdfffdfefffefffffefffffffffefefefffffffefefefffcfffffcfffefefcf6fff5 +b5c8b45875562a50271944161e52102f6623346b283165252a5a1e29541c2b501d1e3e0d +6da86eebfae7fffafef8fffff8fffffffafe +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffefffcfffdfffefffffdfefcfffdfffefffffeffdff3d832881d4090214a8a2c538b28 +4c8a1d478a2330641296ae8afffdfffcffff7d877f1523122345203474263c8826377b24 +2e5423203e181e321922311a2c3f1f223814213617273a1e2a4a1b3151203557242f521c +3a60252c5415376121436d2d3a5729355226466623557b244e732344682046681e4f702b +52702a5a79296a8c2d7fa133a0c63fbfee48bdf740c1ff49bbf93c8ccc384f8d284b8d23 +4782283f711c4d7f1091bc74f8fffbfefff8fffefbfffbfcfefdfbfffff8fffefcfffcff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefe +fffdfffffdfffffdfffffdfffffefffffefffffefffffefffefffdfdfdfdfffefffffeff +fafafcfcfffdecf6ed99a5994d614520371a173213153011182f15132110192018626461 +90a892ecf2eefffefffefefcfefefcfffeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffefffefffbfffdfffffefffcfffbfffdffffffffbbdcb12f851a4292234a8b2f4b8423 +49881d4a8c283b70206f8966fffefffcfffbf2fcf42637252b5b213984273989282f711a +2b531e23431a2c4424233618253b17274018253e172034182a4a1933532233562030531d +3b61282c5418355f1f3e68264367273c611b456a24577e2f618a2e5f8a3065913076a62e +88b13b84ac2f92b63c8dab39b1cf4bddff5ec3f642c3fd53abef3a7fbd384d832d508626 +467a28467b2b62a61f4b931563904beaffe0fffffdfffbfffffdfffbfffffbfcfefffffd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffefefefdfdfdf8fff9fcfffbfdfdfdfffaff +fffbfffffdfffffefffffffdfffefdf4f5f0aaafa87279717a817aa5a7a6dcd7ddfff9ff +fffcfffffefffffffffffefbfffefbffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fefffffffffbfffdfffffffffcfff8fffcfffefffd90bb8333801a449222488e2b54932b +58972c50922e4177232443196c7572f8fff3c5d3c4304d2e326a213c872837812833731d +315f2123481c2f49222740182841192f4a1d2d481d1e36162e4e1d2e4e1c2a4d1732551f +3a5f292d541b355f1f39641f3d6823436c2a51783550792d4b7425517a2b648f366f9e34 +76a12b91b83b9dba3cacbe46c2d150cde64cc1ed42b9f14894cf4356873845722d4d7920 +527d2b4478265196296cc132559f2251832ed7edc9fbfdfcfffefffbfcfffcfffbfafdf2 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffdfdfdfdfdfdfefefeffffffffffffffffffffffffffffff +fdfffcfefffdfefffdfefffdfefffdfffffdfffffdfffffdfffffffffffffffefffffeff +fffffdfffffbfffff8fcfff4fffbfdfffefffefefcfafcf9fcfffdfcfffdfcfefdffffff +fffffffcfcfcfffffdfffffbfffffbfffffd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fdfefffffffbfffbfffffffffafff5fffcfffbfffc6a9d5a3c7e1c499720489525549925 +5a9a2a52902b50872c2c52191127103f523c26412026561c3b7f2a418a30357b23387a23 +356825254d1b2a491d304c1c324d22304e1c32501e223c1930501f30511c294c1432551d +3156222c531c3963233c67203c671f365e20487125567e25577c2e54792c5b832b5f872f +72983386ae2a95b4329db047a2b542b8da3db2e24086be39558026385d273b651d4f7923 +4d792444782344862560b12869b82954a01958972fccf1bef5fff7fffefffffefcfefffd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffefefefefefefefefefefefeffffffffffff +fcfefdfefffffdfffefcfefdfefefefefefefefefefffffffffcfffffdfffffefffffffd +fefffbfafff9f9fef8fefffbfefefcfffffffffffffefffffcfefdfcfefbfcfffbfafff8 +fcfffdfefffafffffbfefffdfefffdfffffb +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fbfffffffffbfff9fffffffffafff5fffbfffbfffc538b4047801f559f2653a32a539d22 +5d9e2a55922b4b812137601c25451c2943282147182f6c1c357f262a701842842a357b23 +2c61192852202c4e1c34521e324f212b4c17355621233e1b2949183556213558203e6129 +2f54202d541d3a642536611a396226375f23385b233c5b1f4c6b284c6a2e4c6c2b587b27 +71913c83a93c7da5327aa0318fb8389ccc3a75a83143772f334e19486924618c33507e26 +497827487d254f8e2371ba376eb72872cb3360bc29569a2bd1e9b9fffcfefffbfffafeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffefffffefffffdfffffefffffefffffffdfdfffafbfffa +fbfffcfefffffffdfffffafffefffffcfdfffffefffffdfffffdfffffefffffdfefffffd +fffdfffffffffefffdfefffffefffffefffd +f9fffdfffffffffdfffffcfffffdfffffffffbfffefcfffffffefffefcfffffefffffeff +fefcfffffefffffefffffefffbfffbfafff9fefffdfffffffffdfffffefffffdfffffeff +fff9fffdfffef9fffafffbfafcfffafdfcfffefffb3b881e46932359a42e5ba92260ad2b +59a1315191235083243b61242c56243056252b5e1c377d24357e223776273d7c2d337e1f +32581f2f4e2232501c34581a30581c2f571b355621273c1d2f4c1c2d4d1c305521315821 +335a212f551c385b23385b233a5d273b5c273654202f4b1a354f2237512436511e46612a +486e19557627566f2e5a712b5471213b57241836103d621f88ba358ec23285b53b5a822a +466f204d82284b921c71c82c6ac2306bc5286ac32d65ba275ca424c7efbaf6fdfffffbff +fefff8fefffffcfef9fffffdfffffbfffef9fffefffcfffdffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffdfdfdfefffdfdfffcfefffdfcfcfcfefefefffffffffffffcfcfc +fffffffffffffffffffffffffffdfffffdfffffefffffdfffffefffefcfffffefffefcfd +fffcfffefffffbfffcfffefcfbfdf8feffffcfe6c9368a184c9b2854a22b5cac2963b32e +5da92f5ba029568d28345c1d2b541c29511d2f63212c751c2e791a3c7d29357423387e25 +3457212b4a202c4d1835591b375f23375f21375821203814324f2132522130521f2f541e +33592030561d355820375a203a5d2533562033511f2b461d28401e2a4124233b1b1e3813 +1b301f2136231d341820371b1e341d415c2584aa33bbe845b3e5449ed03d81ac385f8629 +4f7925497c2f478b2672c7346ecc2e6ec72f77cb3870c63166b92958952ecde6befffeff +fffefff8f9f3fffffdfffefffffefcfffdfefdfdfdfefffdffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffdfefdfdfbfefffbfcfffbfcfffbfcfefbfffffdfffffdfefffdfdfffcfefffdfefffd +fcfefbfefffdfcfefbfefffdfffefffffefffffdfffffffffffffdfefffdfefffbfdfffa +fffffff9fdfcfffefffffffffffeffc4c9c384b7753c981c4ea22952a32b5cad2d62b42c +64b52c6ab32e58962934631b2a5617325e2339702c36812636841e3c83253574232a681d +2848192140172a4a18365d1c3b63253c64254165272f4c1e284316294616264615315320 +365b2530561d2b511832551b3355232d4f1c395a23415f293f5c2645632751702c5d7d32 +65812c6a883071913074952a89ab30b2d344c9e948c4e43bb9e64190ba30759c3264882e +4c741e477b28579c316ec72d6bcd2a73cb3777ca3470c72b6cca2e61b51f5a8e29efffe9 +fefafffffff6fffefffcfafffffffffffefffffffafefefcffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffefffffffdfefffdfdfdfffefcfffffdfffffefffcfdf8fdfffefefffffafcfbfeffff +fafcfbfefffffefffffefffffdfffcfefffdf9fef8fcfffbfcfffbfbfffafafff9fefffb +f3f7f6868887fff9fffcfcfec4bfc613200f3c882648a7274da32854a82f59ab2f5baf25 +6bc12c71c02f5598253e752241702831651d3c792b408c2a3f9122449129347324285e22 +29441b27431d3556214067263c642637601e3a621c2e5119314d1c3754242c4919264614 +2e501d3b5e28365c232c52172f521a2f531641642253742d5a7a2f5c7e285f83216a9126 +738e2f7c973696b042a4ba3bb5c642c3d04ccadc4cd0e646b7dc3f94ba337fa23c688b3b +456c1d467c1c65ad306cc52b70ce3072ca3672c92d71cd2e69ca2f72cf2963ae1e79ad58 +fefffbfcfcfafcf9fffffefffefdfffefffffdfef6fffeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fefffdfdfffcfefffffffcfffffafffff9fffffeff7c837bc9c9cbfefeffffffffffffff +ffffffaeaeb0fcfcfefffffffdfffefdfffc969b97535852fdfffcfffffffffdfffff8ff +747e761116108d888efcfffdb8b8ba27431d449d2949a5284ca72654aa2f55a92f57ae23 +6fc92c72c632519a24498726619a393f7c1d33751b3882213e9024408f26397b24336526 +2c442028421f31541e37601c355d1e365f1b406a203b64222b4c153758213d5e293c5c2a +31511f2e511b3659213b612837562c385827436229486628506f2961832f6c9030769d32 +89ac2c8da837abbb3ebbbd42c0b355ccc157e4ed54e3f94ebee2449cbd38779a325f8232 +4a73274d832562aa2c68c02e73ca2e6ec9306bca326dce336dcc3276d23374cb2f4ea113 +bfd89ff9fffffefdfffffffdfefdfffdfffcfcfcfafffeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fafffaeaf6eaf8fff6f9fff8fffefffffdff8c918d323e325c5c5cfefefeffffffffffff +e0e0e02626269e9e9efdfdfdfffefffcfcfe3c3e3d0f110e767875dfdde0cfc8cfaea4ad +3245321d2c191926142937281d2e1c31642147a5294fab2f52ad2c50a92b56aa305bb128 +6ec72d6ec334529d264e942466ad2d61a82e438b1f3a7f223a852637882240852834671c +233616243e1b34571f3b641e3b64223a631d3f6b1e3b69213a61203b6223395c2230511c +2d4d1b30501e375a2431541c2f4b23324f2345612e4b672d476424506f235f82286d912f +84a532a5be48a9b23dc6b953d4ba59d7c348f4f462c9d849b2d24186a52d6a8d275d812a +4e762d4e832761a9296bc12872c82967c2296dcc3e6bca3876d13477ce3274cf346ecf2a +6a9f33ebffecfbfffffcfbf7fffefffcfefbfffefffffdfeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +e9f0e9677b628dae8183a475748c6a76836f5e695b4b594a474c46747973858a84929791 +6b706a2d322c2f342e777c76797b78656c642632242536230f220c172a1417281512210e +1f3d1b2a461d21461323411f284f223b892451b0304aa62a52ad2c51aa2a59ad315cb22b +69c12d64ba35519e2a559f2460ae2665b62969b433529629428a2641942c40872b2e6218 +25361629411d365c1f3c661e3d66243b641e3f6b1c3d6d23416f243b661f355d1e2d5018 +3455202d4d1b34572132551f2c49132d490f3f5b1e506a2d516b2c506b2654732563852f +819b3a91ac2ba7b23cb3a84fccb356d5be54c3bb4cbac447a3c24185a72f80a639638932 +406925477e2164ad276ec42d6ec82b6fca2f6fcb386fc93368c22475ce3472cc366dcd2d +59a71d92c278f4fff1fffffdfffffafefefffffefffffffbffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fcfffb9ab59285b87381bc6a7ead69829d7273856d6f7d6c647064515d514753473f4b3f +3e4a3e404c403d493d2a362a23342222391f2c4a282d54272753202d5c2625541e305f29 +335a2b2f581e30681d37612f2f6a263ea0254aab284bab2d4faa2954ad2b5aae325ab02b +63ba2b5db2334e9d2a5ea92864b53461b62371bf2b72b532559e2b42952941893325571a +2736172a421e355b1e3b671c416a28416a24406f1f3d70233e7220437327426c2a2e5419 +3859242f4f1d325220284b152f4725324b24374e203d54204c6428546f285b7c25749637 +88a032a6c045b0c248b8b74bc5b34dc8b64acac44ad3db51a2c24396bc318ab3314f7623 +335a254e852a66af2c67b73a6bc8326fc82e74ca2b71c9296cc72a69c62f6fc93468c129 +64c12b4e8d1adff2d6fffefffffff8fefcfffefefffcfdf5ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fcfefdfcfffbe3eee0acbea698b28f90b1848db47f82ab717f9f767292696a8a61608057 +5a7a5158794e51724550714243693a3d67353a6730396d2d37732b377828367c26378027 +387d24337022397629378923367821469f274aa62752aa2f4baa2c53ac2a5caf295fb129 +62b52f53aa2750a72457ae2b64b12767b73263b93265be3065ba275daa2652902d265b13 +1c281a2b3b213751243b5e1e446e263b661e416c24416d204474284172234271233a651d +2f5718365921375725284515293c202e441d38501e39511d3f57234c66295d7a28749230 +97a939a2b935c3d54bc6c752cab758d0b854dbcc59c9c547a3be399cc541638c26344b1f +455c30497f1d58a52362b7286abe326dc53170cb3070ce306fcd2f6dcb2d70cc2d74d02d +79d03460bb205b8f3cfefffffffefffdfcfffffff6fffcffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffefffefefffcfffdf9fffaf3fff2c2d5c19cb49a95ae9192b68a8fb38786ac7d7aa472 +73a0696698595b904c59914a4e833f4a823b4480364180313e822d3a8329398425398724 +3984253b802740842d348c1e357e2249a72d4fae2e4aa5264cab2d53ac2a5caf295fb129 +5fb53054ab2852a9265bb12c66b52865b72f61b42e63ba2f66bb2c66b42c6ab13954962c +3251182542122c4f174169204976253d6b2243732940721d417522427322477827447229 +365f1d2e541931521d2f4f1d2e4121334922395121425b2449662654722a64812d6c8b2e +84a43595b435bad047bfc142c3b54ac4b250b4b148a5b23cadd13980a836284519374d26 +46651f52872f5ca2325ba52a60b22a64b92a68c1296ec92e6fcc336cc9306fca2f74d031 +78d7356ccb2f4e9120b9ceaffffffdfffffdfcfdf8feffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffdfffef9fdfffefffefefefcfefdfcfffff8fefcdfe5e3a4bb9e99b29290ae888bb084 +80ad7677ab6b70a96262a0535d9c4b5596424f933c4b9138448f303e8c293c8d2640912a +368822418f2a408c283c962436892146a82f4aab2a4fac2a4cab2d53ac2a5ab02b5caf29 +5db32e54ab2854ab285db32e64b72b62b42b5eb22963b72e65b72e61b4286fc1316fbe2d +5e98283e721d34641a4879204c7f224478234a812d4a86264c83264a8126487e28437627 +3c6a22396220385b2133541d31461d2d421b384e274058284d6a2763832e6c8f2b779c32 +92b7338ca736a3ab44b9b047bca547ac994aa0a144aabf469fc84439561e243b1f4b632f +466a224b81294d8e2653922756a62364b62d6dc22f69c22c68c22c6dc73172cc3675d035 +6fd12e6acc2b62b7267aa85dfbfff9fffffafcfffffbfff9ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffffbfffffbfffffbfefdfbfffffdfffefffffefffefcfdfefffaecf2e8bbc6b898a996 +88a1847999727096676e96646397555f9450558f454c893b478834458b333f882c358021 +3a8c283d8b26418e263e96253f9c2a44aa2d49ae2c4baa284baa2c50ab2a59af2a59af2a +59b02d50a92755ac295db32e5db32e5eb2295eb12564b62d66b8305eb2266cc22b73ce2b +73c63067ae344d8b2a4c8526518a23518f24539529579d2d529025528f284c8828457d22 +4175223f6d223c6322375a20334b1b31461f2b3e20354926425a26506f216d90287fa62f +85ac2d91af3d96a53ea1a1419b9138a19e41a9ba48a1c339415e261b2e0e4f622b4a6321 +39601d488122508f245d982a5aa4276bb93270c33369bf2a64be286bc52f70cb326fca2f +6ccd2e6fce2a6fcf2d569925f6ffeefffefdfcfffffafff6ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fcfefbfffffdfffffdfefefcfffffdfefdfbfffdfcfffefdfffdfffffdfffffefffefefe +e0e5dfbbc3b898a5947885735f785a526d4c49674143683c3c673237692c386f2c3c7530 +30752236772336781e3c88243ea0274cb23349ae2c47a6244baa2c50ab2a58af2c57ae2b +55ae2c4faa2954ad2b5bb12c5cb0345cb22b5db22362b52965b72f5fb22c66bf2f70cb32 +6cc82775ca395ea73152932d5c9c2e65ac2a63af295ead2e5ea428599e29529627509427 +528f284a7f253f6b20385f20344b1d283e17283b1d26351e2b3e22394f214c672470903b +97c942a8da45a5d23bb0d642bce040c0e64587ac3a34552017251850601f566426435c22 +426d1e4b81294e8821548f235ca12a62aa2a67b6296bbf296fc8306fca316dcb2f6dcb2d +72cf3872cd2865c52353a215b9d0a6fdf8fefffefffffffdffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fefffffcfdfffefffffffefffefefffefefffffffffdfdfdfdfcfafffefffffffffefeff +fffffffffffffbfdfafefffde4e6e5bdc2be959c9475817353665037503326442221411c +224d182c572227571b2e661d45a52a4cb12f42a5244fad314cab2d50ab2a58af2c55ae2c +53ae2d4faa2955ae2c5bb12c5cb0365bb02e5db1275db12561b42e5fb22e62b83168bf34 +65c22b6ec7315eae2b54992e5fa5336bb82a6cc02a63b72b69b72f65b5305fae2e5daa2a +60a82b5a982b487a2536601e364f273248222438152230171a2715121f0e1e2d1a304228 +5d7e2d6f942b7fa72c80a82d72952f57722b263d1314251246572363702a47551a425c2d +406724416c1d4372214b812b5594295a9f2862ae2769bb2970c62f71cc316fcd2f70ce2f +71c93571c9296ac52a63b52368904afefffffffdfffffeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fcfafffffefffefdfffaf9fefffffffefffffefffffdfefffefffbfdfffcfefffdfdfffe +fbfcfefffffffffffffefefefffefffffefffffffffdfffefbfffaf0f7efced6cba3ada2 +7a89725c6b58425a402f532545a0274dae294aab2847a52d4cab2d4faa2955ae2c53ac2a +50ac2d4eaa2b56af2d5ab02b59ae2d59ae2c5bb12c58ae295cb22d5fb22e62b52f66b830 +67bb2f68bb2b5aaa23509b245da92f62b3286bc12a69c12d69bf2a6ec6346ec63467bc29 +64b3245ea2274d84273b6823304b202d461f3a4b293c492b3843252e381f1722110d190d +1d26111920191a201e121912121818191c21262b174c531f5f75234e5a284a5d25375523 +2140162d460f3d5a2247712f4c8729589a2e62aa2d64b52a68bd2a6cc6306dcb2f6dcb2d +6fca2d75ce3675cb3464b7294a8622eafce6fffcfffffffdffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +fffefbfffbf8fffefbfffffdfdfdfbfcfefdfefffffefffffffdfefffdfefffefffffdff +fffefffffffffdfdfffffffffefffdfdfdfbfffffffffffffffdfefffdfefffefffffcff +fffdfafffffff9fffdd4ebcf49a22a4bab2549aa274da7354baa2c4da82753ac2a51ac2b +4eaa2b4da92a56af2d59af2a5cb02758ae2958ae2f52a82955aa2958ab255eaf2663b127 +64b42d67b82f5fad2656a32363b2335fb12b69c12f72cd3471cc316fca316ecc3071cd2e +70c52a64ad285089283c6e2534521e2b441c304023394422424e204d5a254752272f3a18 +1b2817212a172c311a363d1e4952275762285d69275f692a4d6029495a2441592533561c +27411a2c352233441a395d1d417824498724579c2763b02c6abf3069c33069c62f6dcb2f +71d02a6eca3777cc3165b72f3c8710a6c29afffcfffcfff8ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fcfffffdfffefffefff7fff349a42f4faf2954ad2d46a9284ba72a4da52a51a72c51aa2c +4faa2b4ca72652a7285aab2b56ab2a55ac2a54ab2955a72b55a02a569f295aa6285daf29 +61b12c63b63057b02e4ea72965bb3671c53262b42169bc306ed1266dca336cc33475cb32 +6cc63161b9274d8d2d4774232f4f2038502c32421d2d3b18323f23394a1e44561a4a5922 +445d26485c1f586321636325615c25605c2c5d5c2c55592647591d4e6328375019395522 +3b5828243f122640132e481b39641d4e8027609e2f62aa2a60b32769c12f71cc3170cc2d +6ece2c6ccb2f7acf3e68b7263d8306a0bf86fffffdfdfffcffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fefffffefefefffefff3ffef45a42c4eae2854ad2d49aa294ca62a4ca42950a62b50a82d +4faa2b4ca72852a72858a82b55a72954a92a53a72b52a12a4f99284d9525519c2554a525 +5cac295bb12c54ad2b4ea92a5fb63171c6336dc12d61b4266fc52c76cb3a68bc306bc42a +68c12960b32554932a49792339561e33481f33411d343d20303926303b1d3441153f4a20 +3e4a244d542b51522a544e2a554c2d504b2b4f512a4a52234e632b394c1e1d2c0d1a2713 +22311c2a3f1e3852223b5a1f396220437422508d255aa12760b02b6cc03470ca346fca2f +6fcd2f73d23668bd2a62b4225da52793b579fdfcfafefffdffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffefffffefcfffffdecffe742a6284eb02958ae3150ad2b4da72c4da2294da3284fa52a +4da72b4ca62a50a42a55a52c53a32a51a1284e9f274e9b294d942a4b8f284a9226499624 +56a2265aad2b52ad2a4eaa2b55af2967bf2d72c83367bc2d6cb83276c92f76cf296ac627 +71ca3269b6285d9d224a811c405f1c30461836421c303a182a311f2e3820313b18394021 +40451d41411b4b47244b44274944264545214048194b5a213647251f2b15141912141416 +181d19273420304a1d3153173b6126406e254d8426589c2b5fae2e66ba306ac2306ac42e +6ec72f6ecb3260b82474c83555a12383a66cfffffdffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffefdfffefcfefffde5fee040a9284cb02958ae3354ad2d50a82e4ea32a4ca0274ca128 +4ba3294aa2284da12851a029529c294b98244996244b92284b8d2b46862845882748902c +4e972455a72b4faa2b4ca82b52ad2a5db4256abf2c71c63766b72a6bbd2b78d3306ccd30 +6fca316eb82d5793224c8423334f1e293c2037442a353e1f2a331e29321f29331b2f3324 +34371c3c3c243a38213b39223c3a234245284953303c48201c231c151a16161817181818 +1a1d161924131b2e1028411a2c4f19335c1a3d711c488a1e539f215eb22868c02e6cc630 +6fc4336fca3170c63169be2f4d982174975dfffffbfffdffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffefbfffefffefffddffad73fab244aaf2b56a93351aa2a55ab3051a52b50a1294da128 +49a12749a1294c9f29509f2a5098284b9524499324498d26427e2439731f3b7924478730 +498d284b9a2748a02646a12851ac2d5ab2285db4256dc13570cf2b5daf2f66bc3571d13c +70cf376ab32d4d843047812c2a491d1f361c35452144551f44552138491d32411a323c21 +2f39212a321a343a20373e1f4348284b523130391a161f041a151b181619141611151d12 +1823131522101a271326331f304e1a3d6124497a2954932b60aa2f68bb2f67bf2b62bb23 +6abe3268c32a6ec22f5cac2740881a6c8c5afffefafffeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffafffefffeffffdbf5d040aa2248ab2a50a4324ba62756aa2e56a82c53a42b4fa329 +4aa22849a1294c9f2951a02b5199294b9524499123488a26417922356a1c32681d377023 +417f29448c26449b28429c2a49a22c56ad2a5db12865b93070d43460af20509a0f75d035 +68c63470c02d54932a4e92253a5e141d32131b28171e2a1227331b303f204151204b5a1f +47591d4a5b24414f1e3d4a1f333c1d1e221314151713131f191313181713141913172118 +1927181b291823301c232f1b243e0f32531c416c2549852559a02868b92e6fc5306ec72f +67b93061ba226dbc2d69b038317111617c4ffffefbffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffafffefffeffffd9f1cd42a92248ab2d4ca23349a52853a82955a72957a72c52a62c +4ba32949a1274c9f2952a12c529c294e98254a92224a8b27477d293d6c2433621e2a5d18 +356d243d82273f92283f962b4199294ba1265aad2961b22f64c1347dbe3091c25772bf23 +68c43364bb1e70bd315caa22324b24131f1f1b2026181b1010160c121615171c181b1b19 +1f231421241b1c211b121710181b121b1e1715151518171d151610171813181a171a1f1b +1822191b291822341c2135192137102c491b396123457d26559a2660b02969be2d6ec632 +67bb3268be2775bf365c9b3039701f647a54fffcf9fefffdffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fdfff9fefffffffeffd9efcb45ab2449ab304da33648a62a4ea32254a62857a72a55a72b +4ea42949a1274c9f2951a02b549e2b539e284f97274d8b284a7e2b44722a3966252f5d1c +295d1b3779223586203c932a43992e44972152a3235aab2b5ab126c5f190f4fff2a8e75a +5fba1d6ec83273c43b62b62c475f230f1a0c1b1b1d1d1d13191a151a191e1715181b1716 +1f1b121c181718151c16151b1414161415101617111514101016141216151717151a1b16 +1e2118192614172e141e3b1c2b3e1e2b451e2f561f3f74245195285aaa2760b42865bc2d +65b93064ba2363a924457f1b31631a7e9171fffefbfbfffaffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fefffafefffdfffbffceecc841b2264faa334ea53047a0284fa0274da52a4da72c51a62d +53a12a569f2a4d9c254ba3284c9d2454a0245395344f9123487c29365d1e3a55281d3714 +20362130632034801e3e8c2740912a3d942c43962c549e255aa526feffebfffafff7ff87 +6bc8216bc3315aa4316bbd2d4f86291a1f191b151710160c14181b1517161317161b1714 +1616161616163e3e3ebfbfbf7f7f7f2b2b2b151515151515151316151515121411141912 +1820151a25171c27171f2a1a2734162c401d345121446f2759932d5fa92c60b42b63bb31 +6acb2672c734549724497828304c1ba0ac94fdfff5fffffbffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fefffafefffdfffaffcbebc242b12752ad3450a7324aa32b4ca0274ba3294aa4294ea229 +539e28569f2a4f9f264da52a53a72d54a02451942b5190253e72202b51181e440b335c24 +2c60201c420f335d2b377a2a388a1e3d88293f832c418e1e499622c1ef95fffff8fdfcaa +6dc82d66c1286dc92668bc28508d252a381e1513141419131415171b1c1e151714181413 +1818186f6f6ffffffffdfdfdfffffffdfdfdadadad8080805b5b5d424242212121141613 +161b151a22171b26181b28171e2c1520321a213a1a274e193b711d51942163b12a6ec131 +6dbd364e951d457e1f3a631f1f3810cad5c4fefffbfffdffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffbfefffdfff9ffc3e9b843af2855ae3653a8334da42f4a9d2948a02848a0284e9f27 +559e295aa32d53a42b50aa2e52aa2f57a3255c9f2c4b88203c6d1e1c40143d6c2841822e +439229274d1c122217274c213b7c223b7b243c782e3678203c7c2564ab31f2ffcddbd299 +6bb92f6fc5306dcc3067b231549f2045652610151116151a1a181915151720221f767573 +e1e1e1fcfcfcfffffffffffffffffffcfcfcfffffffefefefefffffefefffdfbfe7f7d80 +1414141419131d271c1824161825131c2e16243c1830511a426e1f538a2557962454951d +548b2e3f7320305b162d4f1d32492cf7fff6fefffffffdffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffdfefffdfffbffb8e5ac46ad2a55ae3653a8334ea32e489a2b449826439a254d9e26 +58a12b5ca52f56a82c50ac2d51a92e57a3255fa328508d25406e237a977b467a3232851b +398b1d3d74300e2014131716264013386e23326e283263223a681d457a1e778959817d5a +66aa2f75c73e62b62c69ac2b6ec22f578b2749574668656e757170a2a0a3fdfef9fffdfe +fffffffffffffcfcfcfffffffefefefefefefffffffffffffafcfbfffffffefcfffffdff +2c2a2f101211111811172317191f1b1822191b29182135192b451e335226315223254919 +2846122f4c1c2d4a1e2c462351634df9fffafffefffff9ffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffefffdfffeffa9e19a49ac2d55af3454a7334fa2304b982e4094253f96234b9c26 +58a32c5ca62d55a72b50ab2c51aa2c5da8295ea5235598275b863fedfff35e8a4d257b0e +39832241872f1a3c171f15201d181420441822551a2c531a2a4e1e32471e20391b3b5621 +72ba306cc43270c52c6db52f6fca2f4d9215bed8b1fcfbfffffefffffefffffffdfefefe +fdfdfdfffffffffffffdfdfdfffffffefefefffffffdfdfdfefffffcfcfcfffeffefedf2 +1a181d141615151c151620171d2015181e14171c16141a18101916141f191b27191a2916 +1d2b1120301524341a1a29128a9786fbfffafdfdfdfffeffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fefefefefffdfffffd99d88752ae3258b03655a8344ea0314f9533429128419827499e27 +56a62b5ba72b58a82b54aa2b53a72b5ea92866af2c529c217ea765fbffffc0dab5236c12 +327b213e872b29561f1819141e1317202e1f294b262f551a153a182635144574264e8c2b +62b7286ece3663bb2761b6275cb71e62b32a86ad6cfefffbfffefff8faf9fffffdfefefe +fffffffffffffafafafffffffefefefffffffcfcfcfffffffefefefffffffbfdfa989a97 +111310131814171c18191e1a1a1d12191d0f1c20121c1f14171a111619101b1f111f2410 +262f1e232c1b263121262e1ff7fff4fcfffbfefefcfbfbfbffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fefefffefffdfefffa88cd7456af3759b13758a8354d9d2e498a2c408d27439b2b47a028 +53a72b59a82b5aa92a56a82a58a82d5da62365b23052a41e9bc384fef7fffcfff8417535 +30791f35802133672715220e1a17121c231b1b32183b57243a6629426a23659a3050932c +5dae3665bb3262b82f65be266abf3067be3356892dfcfff3fdfefffcfffbfffffdfdfdff +fffffffefefefffffffffffffafafafffffffffffffefefefffdfefffffdf8fdf6444e43 +0f190e10170f141915191b1a1a1f23181e1c181e14191f15181d171a1c191d1f1c1f211c +1722121c2719151b118e918afefffbfefefcfffffffeffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffdfffcfcfdf87cc56957ae3958b03557a73449992a3f7b213b8522439b2b43a127 +4ea72956a6295ba72955a42559a52b66ad295ead2e52a61ab7dfa1fff9fffff9ff84ab7e +296f163c8d27316d271d2f171416091726111e35192d3d19396122356d123a641a578f2c +65b12a66ae2869ba2d61b13661b32b63bb33487f17dae4cbfbfffffbfffafefefefffeff +fefefefffffffcfcfcfffffffffffffffffffdfdfdfffffffffefffbfcf7ebf3e6222f1e +1b2918101a0f1517141a1a1a152211152210162111151f16171d1d171d1d161d16171d0f +1523121b2618292e27fffffdfffdfffdfdfffffffffdfffeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffdffffffe9ffe468be4f5eae3f58af3a59a2374e93263f701f3e712e43a22e489f2c +48a72558a62c5ea52b53a32a5aaa3156a8226ab53457a920c8e9b0fefffbfffcfdd6e4d7 +26621a3484234090212a531b151a161c1a1b1a1e1d24301a2b451538611f4d882a519528 +498b274f8d285e9e2e5598275cb42c66b92b488715c7e7b8fbfffffff9fffffdfffeffff +fffffffdfdfdfffffffffffffefefefffffffefefefffffffcfefdfffffb9ab990174b0d +24441f202819181f17161a1d181d17192018141e15151f16181f18161b151518111f2219 +1d241c1217118c8e8bfffffffdfcfffefffffcfffffafefdffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffdfeffffffd3f1cd61b8475aad3b54ab36559e354d90264574262e5a1d48a231459c27 +47a62653a12957a12852a32a57a52d5bab2662ae2a5db125cdf0b6fcfefbfffbfff7fffa +5385481f680e3a8721315f21182416171c161d271c2434193c58274064243c692635681d +4376174b8121488025508e296ab63868af2f437917b3cca2fefffbfffefbfffffafdfeff +fdfdfdfcfcfcfffffffffffffefefefffffffefefefffffffffbfffcfdf869945e2a741d +2c63202b4a20182c111f29211c20121a20121c2216161c12171a131718121d1e16191c11 +13160b45463efffffafefaf7fffefdfffefbfefdf9fefff9ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffdfffeffffb4dfaa5bb44058ac3a54a934559934518f2a4a752d20421044972d47a02a +47a62851a02958a22953a42c569f295aaa2760ad2960b826cdf1b4fffffffff9fff8fffb +90bb862d6f183c8627376c261f38181220131f2e1915280c223c152d4a1c2b4c133b5e1e +4164243c641e3d6e1d49802c3f76184b7e22345818c7d6bffdfdfbfffff8fbfcf6fcffff +fffffffffffffffffffefefefefefefffffffefefefffffffffbfffcfff64a823b348b22 +337e23376f2626521723411f2837221724131920181719181b1c1e191a1c151918101511 +20221ff1f1f1fcfafbfffefffffdfffefcfdfffefffffffdffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffcfffcfffd94d08a58b33c5aad3953a634539533558e2d456e282036123a86244ba42e +42a0244f9c2a55a0294f9e29589e2a58a7275dad2859b31ecbefb2fffefffffafff3fff4 +65955b33751d3b86293a7a262a501f15271725351b1928111e32192b422535511e3f5e22 +2b491732551f3c63242e561a2f50191e3a0a485a40fbfffffffefffffffbfffffffafcff +fffffffffffffefefefefefefffffffffffffffffffffffffffefff3ffeb3b782a3b9229 +3e8b2b387d223678212155151b40151d3819162717141d18141a1a11171714191c13181b +b9bdbefbfffffcfffffcfffffefffffefffff8faf9feffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffdfff7fef67bc56c58b13d59a93a51a132519131558c2e3f6625303c26498e354aa32b +419f254e972c529b264b982655992856a5285aa92958b21ccef0b4fefdfffff9fdcce4ca +2a681b337d1a3789273681223161231c321b222e18212c1c1b28172033171d3714254715 +39611b44682a233f17263e1e304023182312c4c8c7fefdfffffefffcfdf8fefffffdfdff +fefefefefefefefefefffffffffffffefefefefefefefefefcfefdd7efcd337720348d1f +3b8c2637811e387f21346826234e1621401622311a1b2115151b111e231c565654d3ced2 +fdfffefefffffefffdfafcf9fcfef9fefffafffffbfcfdf8ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffdecf8ea68c1575aae3e57a239519c33539031538c2b355d1f4d50476dab58439e25 +43a1294e952f51972552972a51972552a02859a82b60b522c8e7acfefdfffffffb88b07e +2c7a173f90273e952c388a24336c252740221c28142633211520121d2c152e4624335523 +2a52163557242d4223202b1a1a231060635afffefffffefffffffbf9fcf3fefffafdfdfd +fffffffffffffffffffffffffefefefdfdfdfffffffffffffcfffb83a475398a23399d23 +3d93283c8a2431731b2f552426412023321d1b1e171c1b1714150fc9cac4fffefffffaff +fffcfffffdfffffefffffdfffffefffef9fffffcfffffcffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fefffadff0dd59bc4759a83d569a375299335390314f8b27285115736f6e87bf743a981e +3f9c274d912e4e9223509226529828529f2b5aa52e5db020b9d69cfefffff7fff1538c45 +3189193e932b439b2d368d242e6d1e2342161426101a311422311e1f2c1b1f2e0f2b411a +223b1d20391b3142221d26131a2217edeee9fdfcfafffffdfbfdf8fcfffbfdfef9fffefb +fefefefefefefefefefffffffefefefffffffffffffbfbfbcfe6c9386b2637921d3da125 +3a8b253b872333731f23431c1e2b2114181714141615171216230f87997ff9fff3fffffa +fefffdfcfefbfcfffbfbfffafcfffbfefffffefefffdfcffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fafff6d5e8d250b83d54a13b519234519532518e2f4b8a22214d12958f9390c87f3d9b21 +3c99244d8f2e4d8f214c8b22478f1f529f2d5aa52f57a81bb4d096fafeffccdec4367a23 +3c972042973243992a388f26397d2a355a242a41271c3c131f341528361f1e231c1c211a +23311722321523301c131c099ca2a2fcfdfffffefffffffffbfffffcfffffdfcfffffdff +fffffffffffffffffffffffffefefefffffffbfbfbe6e6e638682e3c81283c9c21369320 +40862e42892d30711d21481b1c2a1b151d121c221420311130531d38602156793f87a172 +97a886a7bb96aec49ea9c29bacc4a0cee3c2e1f1d6f4ffe9ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fcffffc1e1b057a93b4b973350913748943a4f8c2f4a7525263b14b8b7bd90ce7b369724 +419a2c4c892c43882b538723438b2757912b4da827559c189dc086fff8ff9cb490287c1a +419e293c8d2447932f3886203d8229325f24273f1f1729131b281628372221301918280e +25331c2a35241d23194a4c47ffffffffffffffffffffffffffffffffffffffffffffffff +fff9fffefffbf8fff8f5fcf5fffefbfffffdc7dac726561c24681337882140912b3f8731 +3d882d3f9226377c1f325e21293f192845192446142e531f32542134571f335b1c2d5811 +316513336d1935741b35721335710f336f0f3b7016406c17446a2d52733c68825b809f66 +91b875acd2a1d7f0d2fcfffffffbfffffdfffffdfefefffafcfef9fffcfffefffdf6fff9 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fbfff9b2d6a64fa13f46892844842e4595344e84304172172f3f22e2dfe69acb8a38931e +429720488b223c84214884243f85234e8a284aa02359a1218bb273fefdff6a9357349023 +41a02a3e91293a85262671122c6d1b264e1a1e32191a2819182313182513293622212e1a +25311d131b0c171c15d4d6d1fefefefefefeffffffffffffffffffffffffffffffffffff +fefffbfefdfbfffefffffefffcfffb9eab9a2a4a232d651e3f84293c8d24378b1c38831a +3a851c4592284285283c6b23374d262f4b1b2b4e182f521a33561c4064273e67233f6a22 +4574234a7f25477e234c802d4b7b2f3968203862202c52152d571538611532620c49831d +5b9e1d4e990960a92685c348f1ffe3fefffbfffdfffffefffdfef6fffef8fef6ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffdb2d5b5418d32abd08aa4cf7f438d2a4570283962203b4433fffdffb2d0ac3b8e22 +419023448b2b37782447853245882b4181214a9924519d1f82a966eaf5ed4083263a9b27 +369821449630479036397f272e67201e3e15162413192018131b0e192114152010151d0e +161e0f13190f797b76fffffdfefefefffffffffffffffffffffffffffffffffffffefefe +fbfff3fffcfffff9fff7fff86789681d441726571638752539792b357d273782233f8120 +38721b30651d2555191d4510293f182f4b1b3758213b5d21385a1e3d5f223a621c39671c +3b68233b66163d6816335c1630581c395c224064273b5e2435671e52842d589e2a50a129 +6bb92f74cc2a6ccf3467c9287ebe44f1ffecfdfafffffefffefffffcfdf7fffefbfffcff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffcf7cfe8d567ab56fbfff6faffcf47823238621a324c1f646462fffffdd2e5d241922b +4392273e872b2f60113364133e812442882847942249941e7da55fbbd3bb3b8f1d3d9c26 +3a99233886233778243a792a3163242a4323222a1f1719141c211a1c2218292f251e241a +171a13646661f6f6f4ffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffafffcffe8f5e44c7e41246b1d2e712131711a31751e3070222f7223327023346621 +2b4d1a233b19283c202e43242b3f1c344d23314f1d35541b304f162d4f123d6421406e25 +46752d4470214f7927456f233b62213a5e204068223d691c4a852959923161b2315dba2e +58a41e75c03070cf356bcf2e66c22194c363fefffdfffafff9fffff7fffffcfffffffffa +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fefffaf5fbf7aae79aecfff2f0fbc14f7d352b51182c3522c3bfc0fefffbe8f8ee519e38 +348d0d387f1556712a80965647822e368220418a1f4d922770995382a97c3d911f3d9628 +3d942334791e2e661b3063202048141a2c1220231a23241e1f211c1416111517121a1b16 +7b7b79fefefcfffffffefeffffffffffffffffffffffffffffffffffffffffffffffffff +fffdfff8fffa4373372b7c13368f2145983044962a3d942c419327448c293a7525315a22 +2a421e2633172b36182b3a191f32162a401c2e491e355023334f1f2d4b153a6122427028 +4b8423538b284f86215488244a7c232d5e0d437724558b2d518d1c56902964b5326bcd28 +60af225d9f2472c52f6ccb3166c426bff07affffdefffcfffcfffff8fffff9fdfffefffa +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fbfffffffbffc9fbc0b2f6abaed5845474311b331b696b68fffefdfbfdfaf8ffff6eaa60 +318b10508b39f8fee4fefef4b6de9f31781c4386254b87275a8442538f4537861d42982d +48922f366f22265217264c19203f16192614151811191c15141613191b18171715918f90 +fffefffffdfefafafcf8f8fafbfbfbfcfcfcfdfdfdffffffffffffffffffffffffffffff +fcfffd8eb5893580233c951f3f9625459c2b41a0283fa72a419f25428a272e5f1d1c3f17 +1f391c28381b2e3d1c283c192131171b3011263e1c28401c2e4720324f1f33591c427028 +518f225aa330559e285f9e2974b33e5ba22a549b25579322568a25457c21559d2d6ece2c +6fc9365396255fa51e63bf2e66b828bade84ffffbffffadafff9fdfffefffffffdfffdff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fefffafefcfdbbd9bd65a16573945f3c4a2915261ce0e0d8fdfdfbfffffffdfcff93b18b +217112a8d3a5fffefafffff4f9ffe64a84373974204675244c7a3944952f357f20399322 +3d7a2a29541c203e181f3a191f361c1a241b161815161b151517141f211eb1b1b1fffeff +fffefff8f6f9fffffffefffffafafafbfbfbfcfcfcfcfcfcfdfdfdfefefeffffffffffff +fbfffa477e3a3b94263b932347992b49a42f43a52a42a527378e2332652320371a172a14 +1c33191d311828372025381c2f3f221c2f112034181b2f13283d1c35502332591a407122 +518f245fb4336bc23d5ba12770b73375d13268c02c62a12f4877264e85314a8b2358ad1c +69c729b7f274afd86265a81b6bb8346d94399aa064f7f1d1ffffecfffff4fffdfffefcfd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffafff9ffffd6e4d5526551383a245d5958b7c7c4fffbfffcfffffcfafbfffdfad8e1cc +3f8636dbffd5f6fed7eeffadfffaee96c7852e62183f651c3d6e2d40a0254389313d9c26 +3064221d4115243b211f3520182919141a181516181218141116128a8c89fffffffdfbfe +fbf9fcfcfcfefbfdfcf7fbfafcfcfcfbfbfbfafafaf9f9f9fafafafbfbfbfdfdfdffffff +eff0ea3c762932931f338f22459b2c3e9e2345a22d469627347b1f26401b211c192a2b1b +2b3a191c2c12202c18202e142738162437172b3f23213319213617264114325916477924 +5e9b265fbc2563c62e5198205fa8236fd52966c32c437b22457a22468723589327579e28 +60b526b4db6effffc5bfdc805ab122598d2b495733747959d1d6b6fefef6fffffafbfffa +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffafafaf555555e7e7e7fffffffefefefcfef9fbfffefffdfffffdf9 +b1ccabb5fbb5b8ffadb7e994e1f091f7ffcb6a79402e4d1435772f479b29489d2439962c +2c59221f43171c2e16181a151914181a141819181617191410220ca0ac9efcfffffbf9ff +fbfafffdfff5f6fef1f5fefbfafcf7fafbf6fbfaf6fdfcfafffafefdf8fefef9fffdf8fc +fdfffc96ad912c601e1e6a0f33882142942e4b9838358021314d27192b13161e111c2218 +222d1d1825131b2616232b1e24311d1c2b1429391f2432192e3b212e481b396c1f4b922c +5cb32e66c02aaceb5284b93746892870d0316bcb2b46702837602848672355882352ad22 +5dbd2580ba41d4e3a2ffffe6c6df8c61a52a34501f282f1f484f2ea8a8a0f4fffcfffdfd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffefefefffffffffffffcfcfcfffffffdfdfdfffffffffffbf8fcfbfffefffffefb +f0ffe99ed89e94d38c8dbb739aaf6ad3e09b717d4d1d440d3f912d48a731429829358820 +396e262a551d1e39181321121620181924161f2f14283e182d4d1b5e774de3f0dcfdfeff +fffafffffbfffff8fefff9fffaf9fffdfcfffcfbfff9f9fbf8faf9f8fdf7fafff6f6fef1 +fcfbf7fffeffc1c6c25a715728551c24611328671629661920341b121d0d141510171715 +1b1e171820131820151c1f181c24171a251426361c1e36122c4f19316618408c2057b032 +50b72a7dd23feaff96e9fb8b638f2d62b92c68cc2e5b952e396d18385c1e406a2249912b +5bb62b78bc459bbc85cce3affcffefa5c878528c261f32141b1515262f1ef6f4f7fffcff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffcfcfcfdfdfdfffffffffffffbfbfbfffffffafafafffcf9fbfffefbfcfffffcfd +f8fff3aaceaa64905f658a56657b558a90545661362e652141a02c389d273c9227438629 +377124386b292a5122163412203b1a2d4c22365c233f6927325e0f4b74266e8c50bfcfb2 +e1e6dff7f7f5fffdfefef9fffffefffefdfffdfcfffffefffffefffffafffdf8fefffaff +fbfbfdf9f8f6fffefbfffefddadadc99a39b586e5726461f151c141214111914181b161c +18161717191611130e181a171719141e241a29382121461333711e3e90214bab265cc133 +5ec8347ac841d3da96ffffac9aaf5253932162c22d6fb8355da02c416d20375b1b3f7225 +529d1e72ba3c6c996087a26ddae3c8f8ffea41743195a88ae1d4deb1bab7fffdfffffff6 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffefefefffffffffffffcfcfcfffffffcfcfcfffffffffbfcfefffffbfffffffeff +fefefce6f7e7536d523851333a483b56523775895640842d38962839972739872131651d +255917346426355e24294e1832581f3c64263b6a24396b22305d2435631a34631239651a +507937547b3a678e4d6e95567899628fac7caac49dc2d5b7dce8d4f2f8eefefcfffffbff +fbfffdf6fffcf2f8f6fefcfffffafffffbfffffeffd7dcdf9f9f9f565457241f251a151b +1210131919191517141a1f1b1722141f2c1a2b45222d601d45962d4baf2b4db42759bb30 +65c22c6cb24094a072faf9b6dce5a2527823529c2160a528538f2d4c7c263f60193e6121 +4e871e60a6295580395b6751768661d1e0cbb9c4b6fffffdfffafffbfdfcf7fff2fffeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fbfbfbfffffffffffffafafafffffffffffffffffffefefefffcfefefffff8fcfdfffeff +fffdfffdfffeb5c1b72634251a1b1f282921547b383885253d8e3146932d3b8025356625 +2f5c21346023365e2232581b355c1b345d1736641b39691d38682e437627427b1c468222 +3b78193f7d183d7e163d7e18397f0f377c12397b1a3d791f487f2b5f8f437ba56699be8a +c5dccaeffbf1fffffbfffefffafafcf4f8f7fefffafefff5fdfbfeffffffd4d4d4727272 +2323231315141217112128201c3c15274c20356728367f2346a62b4db82c4fb52b55b230 +65bf2a5da341596e47c3ca9efaffdf798f4e477a1e437119284c1c3054143d5a20446328 +3b70204d95255a92312a38273d4039556d4dd6d2c9fefaf7fcfdfffffefff8fff0fffcff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffbfbfbfffffffffffffffffffbfbfbfffffffffffffffdfffffffffefffffcfcfe +fffefffbf9fefeffffced3cd635e64374e342d6b18358025377b24347416336d21366a22 +33611936631e3c66263e6627426b29416c244874254878243c7318437d19518d29478329 +3f7b25437e243e761d457b2744801c4a8a294f932e48922349971d4f9c1c49951b47901d +4b812367904aa3bc95e1ecdcfefffafefefcf6f4f7fcfbfffcfafdf8faf9fcfffbfcfffd +d0d2d1696b6a191e180f19101b47122f63233e822f358c233ca0224fb63152b330449e22 +57ba2b579c434857387f836cfbfff5a1b37f345619334a20313d252c411a2d461f395b1f +32671f3c8421599d263b622b1d140f101c10636a62fdfff2fbfff6fef9fdfffbfffeffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffefefefcfcfcfefefefefefefffffffdfdfdfffffffcfffffdfdfdfcfbf7fffffd +fffffffffefffffffffcfdf8fdfff952834b307d1f347b1f42822b33711c3670233a7521 +407821447b274378263f72234475264475234b7d284d7d2744782342791e4680293b7626 +407b27467f214a7f23437221436d21416f24497e2c51922e62a93166b32f5aa72557a327 +5da32659a521559b1f649a3aa5c18eeff5e9fffdfff8f4fffcf7fdf9f9f9f7fcf6f3f8f2 +fefefefffeffc9c9c9646963182c131d4115336c27388229368822409329499d2e429626 +4fa72c58993d42513c53594beff5e7cdd5ae243912151f141f23121c25101f2c1a283c17 +2e4b1b406a283a6b122a4d177171654545474a534efbfffffefffffdfef9fffcffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffefefefffffffffffffcfcfcfffffffefefef9fffffffffffffefafffffb +fcfffffefffffefcfdfffffbe4f2db3075252c821d478b2844842d3679293c7d2144832a +45862845872643842045831e47831f3e77183f751d447825487727487c293b752034721c +47892843851b458322477e2d4a7b22457924437e2442851e509a215ca92956a027549c2c +549a285ca92966ba276bc22661af2579af51c6d9b9fcf9fff7f0f8f4f4f4f1f6f0f0f2ef +f8f3f9f7f0f8fffdfffefefec9bbc8575f5413330a1c4e0f2f68213872263c7e273a8121 +4281195a9334354b3e334535aab499d1cdb02a341b1f2525141817131917101417161419 +1a17101f220d2b3421959d9ff0fffdfffcfffffefdfffffafffcfffefffffcfffbfffdfe +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffb6d4ae36722a388c1d4395263883243987243c872048892f +4a8e2744842446822a39731e437f27417c2240762042721e426d1e44761d417825417a2b +3f7b21418224448c294697214e952b54a02253a72d6caf3b529c235fa1256dbc2d5fa52b +497a2154922765af346ec42b6ed12969c9295b9f24a7c39deff1fdecf0f1eaedf6ecefe8 +eff3e4edeee8eeecf9f4f1fafff9f9fbf7f6abada8434d421b2e1a1b361522461a335926 +305d26456d2f2d4d1e1a2c1e67706fb5b9ababada0e6e4e7e0e0e0dcdcdccdcdcdc7c7c7 +c4c4c4d5d5d5fafafaffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffbbd2b8306f1e419928418d293f86283d93263d952448932a +428d24448a2835741b4180274686284684214d87234b811f4c86205492254b8c26428423 +4b9026519a2e53a63256b22b51b1295bb02f5ab92b71cf3d6dc93a4b9c1c65be2876ca36 +457b274078135fa52b5aa61f69c0316fcb2ab4f158b2ce60cad2abeef0efeff0f2eceaf7 +eeeeeceeeeeceff0eaecebf0eeeceff2f0f3fdfeffebeff0a1aaa54d5a501d2e1c10230d +1831131d330c1b2b0e101914424649a2a59adce0d2fcfdfffefefefffffffefefeffffff +fefefefcfcfcfffffffefefeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffedf4ed458232348e1d3c872a48902d409e263ea4254ba72b +499d2d3f8c2439811e478d2a42891f4b941f5aa12765a92e6bb63765b32b5cab2c56a12b +56a52855a7295cb9345bc2294fbc2353b32b6dc12d67c22575cf3153a4245eab2775d52d +5a9d364378204a8c2b4f8b275da82967bd28e7ffa9fafcd7d3de92e6e6dcf2f0f5f0f1eb +eeedf3efeef3eeeeeef0f2e5efefefeeeef0efeef3f2f1f7faf9fff9f8fdcfcfd1959595 +63656452564855574c37363b1d1c21797c73dee1d8f1f5f6ecececeeeeeef4f4f4fefefe +fffffffffffffffffffcfcfcffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffef9ff8ab57d2a7a173e932b459b2c40a32446b02c47ac28 +4ea930378e1b4c9e3053a63453ac2c5fba2f6bc53274ca356ec2366bc12a65b92d5bac2b +5aaa2752a7255cbc345fc92b56b92a53c03168bd2e73ca2e71c92963ba2d5b9a2f71c62d +6bbf33639d2d4e93264a7f274e90265fb12bc6dc8affffdaffffdfe9efafe2dedbf4f3f1 +edece8efeef4eaeaeceff2e9eaede4eef1eaeeeeecedebecf0eef1f3eef2f7f1f5fff9fb +fbf5fff2eeeffdf9f8d0ced32a2a2c5f605af6f8f3e8eceff3f3f3f4f4f4f9f9f9fdfdfd +fffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffaffdeefdc49853b348e1d3ea02741a42649ac2b48ac2e +48a7273e9a1d53af3353b43157be2e5fc92b6bd12f71d12f60b42a6ac02960b5245dae2b +63b23249992049a12664c63560c1364ac02c5dc6355dc12175c3396ccc2c4d972663a331 +6cca2c70b4295ba8244a7f254c87295aa32d8ca34bc4c67dfcfed9fefde9dee0b9e6e4e5 +f3f2eef1f2ecefeef6edefeaf2f3ededeee9eeefeaf1f1efececeaeaeae8eeeeecf1f2ed +ecebf1f7f7f5ebece7fbfbfbcccecdced0cbf9f9f7fefdfffcfcfcfefefeffffffffffff +fffffffffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffafffefdffa8c8a1307a1b3f9e2a4aa8304aa62946a52f +44a32347a62654b83451ba2c57c42b66d03069c92a6fc52c58a7276cc02d67bc2b69bb35 +69b5394b952643912459ad315cc2324fb82756bd2eadf36eedffa9a6e15152a41c3b731c +5db32a6eb63057a22b4e832b477c204c8a256578408b8b6fbdc491faf9f4fffefcccd1b3 +eff1e6eceaf5eeefe9ececececebf0ecebf0eeeef0eeeff1edeef0edf1f0ecf0efe7ebea +f0f2efe9eee8ebf0eaeaefebf2f4f1f8faf7f7f7f7fefcfffffffffffffffffffffdfdfd +fdfdfdfffffffefefeffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffbfdfafffdfffbfffa6f9564357c2040992545a329429f2c +48a62c46a92b50b7344bb62a52bc265fbd2974be33649f1e519b2273c53370c63167bb31 +5dac2d589f354e94324993245db7315aba255ab12ee4ffb6ffffc9f3ffa07ab535366d1a +468a236bb2325197234e8029406d1c3f6a2249612d515b39818867c3cba4fefffadbdecd +e0e2d4f1f2eaefeef6f0f1ecebeaeff0eff4eeedf2ededefefeff1ecedefeaebedeff0f2 +eeefeaededebeef0efebf0ecf0f2f1ecececf9f7f8fffefdfefefeffffffffffffffffff +fffffffffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffff9fffafcfcfafff9ffe6f0e74a7c33388f1c40a22b459f2d +3f9e2a46a82f4bb13149b42a51b62864b62ecbff8abbdf735ea52d76c83662bb215eb624 +58a9264d95293e8122458a1f579c2853bb1e66c14ae8fee7eafcc8ffffc8afcd69457d26 +4a802c5da225498c1b4d7f28496e293754243e57302c38244d5637717961c0cba3fbffe5 +c3c7b6fbfbfdf2f1f6efedeeefefedefefededeee9eeede9f0efedf0efedefedeeefedee +f1ebebf3eef2efedf2ededefecedefefeff1f4f2f3fffef9fffffffffffffefefeffffff +fefefefdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffafffefcfffffefffffeffffbdcebb41702c3e90223fa827 +46963544a92748b13044ac3148a92879cf62f4ffbdfdffac7ec13d66c13662b22d5ba72b +54992c517e2939691f3a722b418923509e2e79c44dcbffd9daffe0ffffd8f8fac8518322 +3a672248741d4165284266263b622123461052722f1c34102a3024464d3d636b56babfa9 +c5c9b8f5f6eef8f8f8f3f0f9eeeeeef0f0f0efefefedededeeeeeef5f5f5fbfbfbfdfdfd +fefefefefefefcfcfcfafafaf8f8f8f8f8f8fafafafcfcfcffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffdfffcfefdf9fef7fefffbfafff9aec6ac2e6720499f30 +3f9c2743a22a4dab314aa82c3fa1288de47ce0fec0fffcd691c6525eb02a599d2257942d +4c8429426a21315e1b30621b32701b40841f68ac45b7f6bfceffebe6fcd5fdffe966843a +2d4d1b254212162d1327411a32522319371146652a435e29191f13272d1f373e2e636758 +a6aa9ce6e7e1fffffff3f1f6f0f0f0efefefedededefefeff5f5f5fdfdfdffffffffffff +fffffffffffffffffffffffffefefefdfdfdfefefefefefeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffff7fffffefffcfff8fffff8fffafffffeffa4bea3407831 +439c2e499f3055ad354ea82d41a02c88d680cbfccdfffffa95b85a6ab131558d20436d25 +446c2d35561f274e193b5f21366521386f1b46832482c582b9fcd9c9fbd8f3fff9808d57 +2a3c14111e0a1f2a1934461c3c5420243e17253e16375019282d26151b111619102c2f26 +63645ed2d3cefdfdfbfdfdfdf5f5f5f2f2f2f0f0f0f3f3f3f9f9f9fefefefffffffefefe +fefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffdfbfffefffafbfdfffffffffdfffffbfffbfffbb7cab6 +477b3b43842a52a53949a13048a23172b268befcd7effff488a35669ad34558329304921 +314927294121243f2033461934572134611e467f1e4b87417bbf84a7e2c2d0f0db899361 +2431131216171417101a220b233016232f231f272a38413066686360625d1b1d1a151716 +131313a1a19ffefefcfffffbfefefefcfcfcfbfbfbfcfcfcfefefefefefeffffffffffff +fffffffffffffefefefefefeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffcfffdfefffdfffffffefbfffefefefafbf3fffffbfffdff +cddcc9557647407e3358a346499b3745813780bf90d3e6d07791525f9d384a722c243120 +233124202e211e2e242b301c263b1c2b4c1f37651a335f223b6b31659679a2c5af748656 +808d6fd1d5d4d7d7d5d0d0d2dadbdde9eaecfaf8fffffefbfefffdfeffffcacacc5e5e60 +464648cfcfcffcfcfafffffbffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffff9fffffbfdf8fffffbfffefffcfffffcfff8fffffafff9ff +fffffaeff8f789a3884e7a3f38732f467f385f9058aab4a9677c514476313147211d2321 +27302d292e2a1d22251c1b1719221d22341e254021314c213043253b574066847a5d6e4c +c0cbbafcfffffcfdf7fdfdfffffffdfefff5fffefffffdfafdfdfdfffffffffffffefeff +fffffff9f9f9fffffdfffffdfffffffefefefdfdfdfffffffffffffffffffefefeffffff +fffffffffffffffffffffffffffffffffffffffffffefefeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffbfffffefffdfffffbfbfbf9fefffffcfefdfcfefdffffff +fffef9fcfbfffcffffd2dec67a917561885c4c603d646a6a555e49536b51878882b9b7bc +d1d7d3d4d3d1afb0b28381864c4d5223241e161f1c192414191d0f0d190d1e2e2e696f63 +e8edf3f6f5fffffcfffffefffbfdfcfefffdfffefffff9fffffffffcfcfefffffffcfcfc +fffffffffffffffffffcfcfeffffffffffffffffffffffffffffffffffffffffffffffff +fefefefefefefffffffffffffffffffffffffefefefefefeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffbfffefffcfdfffffffdfffcf9fffdfffefffffbffff +fffdfffbfffffefffffffbfefffbfdebf6eedcd3d4c3ced0e5e1def2f7fbfff9fffffbff +fbfffafffefafffffdfcfdfff9f7f8dad0d1a9a7a87c8083797a6a84898399a29fd0c7ca +f7fbecf2f1eff6f1f7fdfdfdfcfffdfbfffffafefdfefffafffefffffefffffffdfefefc +fefefcfffffffffffffffefffffffffffffffffffffefefefefefefefefeffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +f3f3f3f2f2f2f3f3f3f7f7f7fcfcfcffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fdfdfdfcfcfcfbfbfbfcfcfcfefefefffffffffffffdfdfdffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffefefefefefefffffffffffffefefefefefeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fefefefefefefefefefefefeffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffefefefefefefefefeffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fefefefefefefffffffffffffefefefefefeffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff + +showpage + +% stop using temporary dictionary +end + +% restore original state +origstate restore + +%%Trailer diff --git a/doc/kdvi/index.docbook b/doc/kdvi/index.docbook new file mode 100644 index 00000000..cd60e640 --- /dev/null +++ b/doc/kdvi/index.docbook @@ -0,0 +1,1072 @@ + + + + + +]> + + + + The &kdvi; Handbook + + + Stefan + Kebekus + +
+ kebekus@kde.org +
+
+
+ +
+ + + 2001-2004 + Stefan Kebekus + + + &FDLNotice; + + 2004-02-27 + 1.11.00 + + + This document describes &kdvi; version 1.1 + + + + KDE + linux + TeX + DVI + + +
+ + + Introduction + + &kdvi; is a plugin for the &kviewshell; program which allows + &kviewshell; to display &DVI;-files (.dvi) which are produced by the TeX + typesetting system. &kdvi; supports many extensions of the &DVI; + standard, for instance the inclusion of &PostScript; graphics or + hyperlinks. More details, examples and all the technical + specifications can be found in the file + KDVI-features.dvi (or see + KDVI-features.tex for the TeX source of that + file). + + For up-to-date information, consult &kdvi;'s home page. + + + TeX is a high-end typesetting system geared towards + scientific, and in particular mathematical typesetting. More + information about TeX and &DVI; can be found on the homepage of the TeX user group or + the German German DANTE + e.V.. + + + + + + Starting &kdvi; + + Most of the time, &kdvi; will be started by just clicking + onto a .dvi file in the file + manager. For convenience there exists a command + kdvi which calls &kviewshell; with the &kdvi; + plugin preloaded. The viewer may thus be started using the command + kdvi + somepath/paper.dvi. The command + lines kdvi + somepath/paper or + kdvi + somepath/paper. will also + work. If you are connected to the internet, you can access files + which reside on other computers by giving a &URL; as a parameter, + like this: kdvi + http://somepath/paper.dvi + + + If you give a &URL; as a parameter, you can tell &kdvi; to + jump directly to certain place of the &DVI; file. + For example, kdvi + file:paper.dvi#43 will make + &kdvi; to open page 43. If you have included source file + information, a command like kdvi + file:paper.dvi#src:43paper.tex + will make &kdvi; search for the place in the &DVI; file which + corresponds to line 43 in the TeX file + paper.tex. You will hardly use this option + yourself — read the section on forward search to learn how to + set up your editor to start &kdvi; automatically. + + + Don't forget the file: + prefix or it will give unexpected results. For example, the command + kdvi + file:paper.dvi#43 will open + page 43 of the file paper.dvi. The command + kdvi + paper.dvi#43 will try to open + the file paper.dvi#43. + + + There is another option which you will most likely not need + to specify yourself. If you type + kdvi --unique + somepath/paper.dvi, &kdvi; will + load the file if there is no other instance running which has the + file already loaded. If there is, this instance of &kdvi; will pop + to the front. A command like kdvi + --unique + file:paper.dvi#43 can be used + in shell scripts to make a running instance of &kdvi; to jump to + page 43. + + The usual parameters handled by &Qt; and &kde; applications + also work: kdvi + windows + :0 + 400x400+0+0 + "DVI" + + + + + + Printing &DVI; Files + + &kdvi; can print your &DVI; files using the standard &kde; + printing interface. Internally, &kdvi; uses the program + dvips to generate &PostScript;, which is then + passed on to the printer. In particular, dvips + must be installed if you want to print with &kdvi;. The program + dvips uses its own configuration files and its + own settings, which are fine for most purposes. However, if you + care for optimal printing results, you should configure + dvips manually and make sure to set a default + MetaFont mode which fits your printer best — on many systems + you'll find a GNU-texinfo documentation + of dvips, and you might also want to + look for a file called dvips.dvi or + similar. + + + + Exporting the &DVI; file to other formats + + If you want to save your file as in &PostScript; or PDF + format, it is not recommended that you use the printing function + and redirect the printer output to a file. Instead, you can use + the export functions which produce better-quality output that + retains many of the special features of the dvi format and looks + better in many of the viewing applications, such as Adobe's + Acrobat Reader. You will find the + export functions in the File menu. + +
+ Exporting to &PostScript; + + As in printing, the external program + dvips is used to generate the &PostScript; + file. If the &DVI; file contains hyperlinks, these will also be + included in the &PostScript; file. If you are an expert, and if + you would like to generate output which is optimized for a + specific printer, you should probably start + dvips manually and choose the proper MetaFont + mode yourself. +
+ +
+ Exporting to <acronym>PDF</acronym> + + In order to produce PDF files of high + quality, &kdvi; converts &DVI; to PDF using + the external program dvipdfm. If you are + working on a machine where an older distribution of the TeX + typesetting system is installed, it may be that the program + dvipdfm is not installed. In that case, you + need to use the printing function to generate + PDF output. + + + + + + If you use an older TeX installation, and if are viewing + the generated file in Adobe's Acrobat + reader, you may well find that some of the + fonts look extremely poor although a printout is fine, + and although the document looks ok in + kghostview. This is a known issue with + the Acrobat Reader and bitmap + fonts. At the time of writing, the only practicable + workaround seems to be to avoid bitmap fonts, or to + upgrade to a more recent TeX installation. + + + + + While dvipdfm produces high-quality + PDF files, dvipdfm + currently currently ignores the &PostScript; that is + embedded into the &DVI; file. Embedded PostScript is + generated e.g. by the xy macro + package, or by the "Embed PostScript files" function + &kdvi; described below. + + + If you find that the generated PDF + file misses graphical data, use the print function of + &kdvi; instead. + + + + +
+ + +
+ Exporting to text files + + &kdvi; can also save your &DVI; files in text format. + + + + The &DVI; file standard was not designed with this kind of + functionality in mind. This function therefore only works + well with standard ASCII characters. It will not work with + non-European languages. Depending on the fonts used in the + files, there may also be problems with accented characters or + umlauts, and sometimes with ligatures. + + +
+
+ + + + Embedding PostScript files into the &DVI; + + The traditional way of using graphics with + TeX does not include the graphics data + directly in the &DVI; file. Instead, the &DVI; file contains only + a link to a graphics file which resides on the hard disk. The + advantage of this procedure is that the &DVI; file stays small, + and that the graphics file can be modified indepent of the + document's TeX source. The method, + however, becomes fairly inconvenient if you intend to archive the + &DVI; file, or if you wish to send it to someone else: rather than + handling a single file, you have to deal with a multitude of + files, which need to be kept in exactly the place specified in the + &DVI; file for everything to work. + + For that reason, &kdvi; allows you to embed external + &PostScript; files into your &DVI; file. To embed all &PostScript; + files into a &DVI; file, use the menu entry Edit/Embed + external PostScript files + + &DVI; files with embedded &PostScript; work fine + with most other &DVI; handling software, + e.g. xdvi, + dvips or + dvipdf. One notable exception is the + dvipdfm program, which currently + ignores the embedded &PostScript;. Since + dvipdfm is used internally by the + "Export to PDF" function of &kdvi;, expect + problems when you use that function. The same issue shows with + other software that uses embedded PostScript, e.g. the + TeX xy macro + package. + + + + + Using inverse search + + + Inverse search is a very useful feature when you are writing + a TeX document yourself. If everything is properly set up, you can + click into &kdvi;'s window with the + middle mouse button (on some systems, + when you don't have a three-button mouse, you can simultaneously + use the left and the + right button). After that, your + favorite editor will open, load the TeX source file and jump to + the proper paragraph. To use inverse search, do the + following: + + + + + Produce a &DVI; file that contains inverse search + information. This is explained in the section Producing TeX files for inverse + search below. If you just want to test the inverse + search feature, you can also use the example file + KDVI-features.dvi + + + Let &kdvi; know which editor you would like to + use. Choose an editor in the Preferences + dialog (this dialog can be reached by choosing + DVI Options in the + Settings menu). The next section of this + documentation, Rendering + Options, explains this dialog in more detail. + + + Some editors need to be started manually, or need + additional configuration. You will find a description of all + supported editors in the section Setting up your + editor for inverse search below. + + + Test your setup. Open your &DVI; file in &kdvi; and use + the middle mouse button to click + into &kdvi;. The editor should pop up and display the TeX + file. + + + + +
+ Producing TeX files for inverse search + There are essentially two ways to produce &DVI; files + which contain inverse search information: you can either use a + TeX/LaTeX binary which generates and includes the necessary + information automatically, or you can include an extra package + which is written in TeX/LaTeX. + + + A TeX binary which generates and includes the + necessary information automatically is certainly the + preferred method of including inverse search information. + If you use version 2 or greater of the TeTeX TeX + distribution, you can use the 'src-specials' command + line option of the tex or latex command, as follows. + +tex --src-specials myfile.tex + +or + +latex --src-specials myfile.tex + + + + + If you do not have a TeX binary which includes inverse + search information natively, copy the files + + srcltx.sty and + srctex.sty + to the folder where your TeX file resides (you + can do that by pressing the &Shift; key and &LMB; while the + mouse pointer is on a hyperlink.) If you use LaTeX, add the + line + +\usepackage[active]{srcltx} + + to the preamble of your LaTeX file. If you use plain TeX, the line + +\include{srctex} + + will do the trick. + + + + + While inverse search is extremely useful when you are + typing a document yourself, it might be a good idea to remove + the inverse search information before sending the &DVI; file to + someone else. + + +
+ +
+ + Setting up your editor for inverse search + + While inverse search works generally very well with most + editors, some of them require a bit of extra care. This section + explains how to configure your editor. + +
+ <application>Emacs</application> + + Emacs works well with + &kdvi;. The actual behavior of Emacs + depends largely on the configuration. As usual, you can + customize Emacs completely, if you + are willing to fight your way through Lisp code. + + &kdvi; uses the program emacsclient to + remote control Emacs. + + The program emacsclient requires that + Emacs is running, and that the + program Emacs Server is started inside + Emacs. Inverse search will not work + optimally unless you have started both + Emacs and the Emacs + Server. + + + To start the Emacs Server, you can do + one of the following: + + + In Emacs, start the + Emacs Server by typing + MX + server-start + + + Add the line + +(server-start) + + to your .emacs file. Restart + Emacs + + + + + + + + Make sure that Emacs is + installed. Try to start emacs from + the command line. + + + &kdvi; uses the command + emacsclient to remote control + Emacs. Make sure that + emacsclient is available on the + command line by trying the command + emacsclient + Name of a text + file. This should open a new + text in the Emacs + editor. + + + If emacsclient fails with an + error message like unable to connect to + local, make sure that + Emacs is + running. Furthermore, make sure that the + Emacs Server is started by typing + Mx + server-start. + + + If you want the frame to be auto-raised, add the + raise-frame function to + server-switch-hook (do + Mx + customize-variable + RET + server-switch-hook and + enter the function name into the text field. + + + If you have changed the buffer since your last + save, Emacs will ask you: + Revert buffer from file ...? (yes or + no). You will probably always want to + say no here, since reverting means + that the file is reread from disk, causing all + your changes since the last save to be + lost! + + gnuclient's behavior + of silently reloading the changed buffer is probably + preferable — add the following lines to your + .emacs file to emulate + gnuclient's behavior with + emacsclient: + + +(defadvice server-visit-files (around save-buffers last activate) + "Try to emulate gnuclient behavior with emacsclient. +Works only for visiting one buffer at a time." + (let* ((filen (car (car (ad-get-arg 0)))) + (buf (get-file-buffer filen)) + (this-buf-modified-p nil)) + ;;; the following is copied from server-visit-files, with + ;;; a modification for the `verify-visited-file-modtime' test + (if (and buf (set-buffer buf)) + (if (file-exists-p filen) + ;;; if the file has changed on disk, reload it + ;;; using `find-file-noselect' + (if (not (verify-visited-file-modtime buf)) + (progn + (find-file-noselect filen) + ;;; if user answered `no', reset modtime anyway + ;;; so that server-visit-files doesn't realize the + ;;; difference: + (set-visited-file-modtime))) + ;;; if file exists no longer, we let server-visit-files + ;;; deal with that + t) + (setq buf (find-file-noselect filen))) + (setq this-buf-modified-p (buffer-modified-p buf)) + (set-buffer buf) + (set-buffer-modified-p nil) + ad-do-it + (set-buffer-modified-p this-buf-modified-p))) + + + + +
+ + +
+ &kate; + + &kde;'s editor &kate; supports inverse search very well. + No extra setup is required.
+ + +
+ <application>Kile</application> + + The LaTeX-editor system Kile, + supports KDVI very well. No extra setup is + necessary. Further information about Kile can be found at + Kile's + homepage. + +
+ + +
+ <application>NEdit</application> + + NEdit generally works very well + indeed. Clicking into the &DVI; file should open a new + window. If the TeX file is already used in another window of + NEdit, the newly opened window + displays another view of the buffer. Otherwise, the TeX file is + loaded. After opening the window, + NEdit highlights the first line of + the appropriate paragraph. + + &kdvi; uses the command ncl to + remote control NEdit. Make sure + that ncl is available on the command line + by trying the command ncl + -noask. This should + open an instance of the NEdit + editor. If ncl is not available, you + might be using an older version of + NEdit. In that case, you should + either upgrade to a more recent version, or you have to use + the option User defined editor from the + Options dialog. + +
+ +
+ <application>XEmacs</application> + + XEmacs works well with + &kdvi;. The actual behavior of + XEmacs depends largely on the + configuration. As usual, you can customize + XEmacs completely, if you are willing + to fight your way through Lisp code. + + &kdvi; uses the program gnuclient to + remote control XEmacs. + + The program gnuclient requires that + XEmacs is running, and that the + program gnuserv is started inside + XEmacs. Inverse search will not + work unless you have started both + XEmacs and + gnuserv. + + + To start the gnuserv program, you can + do one of the following: + + + In XEmacs, start + gnuserv by typing +MX + gnuserv-start + + + Add the line + +(gnuserv-start) + + to your .xemacs file. If you use a + more recent version of XEmacs, + .xemacs will be a + folder. In that case, you should append the line to the + file .xemacs/init.el. Restart + XEmacs + + + + If you don't want to open a new frame for each editor + call, and want the frame to be auto-raised, set Gnuserv + Frame to Use selected frame, and add the + raise-frame function to Visit + Hook. Do Mx + customize-group RET + gnuserv to make these + settings. + + + + + Make sure that XEmacs + is installed. Try to start xemacs + from the command line. + + + &kdvi; uses the command gnuserv + to remote control + XEmacs. Make sure that + gnuclient is available on the command + line by trying the command + gnuclient Name + of a text file. This should open + a new frame in the XEmacs + editor. + + + If gnuserv fails with an error + message like unable to connect to + local, make sure that + XEmacs is + running. Furthermore, make sure that + gnuserv is started by typing + MX + gnuserv-start. + + + If you don't want to open a new frame for each + editor call, and want the frame to be auto-raised, set + Gnuserv Frame to Use selected + frame, and add the raise-frame + function to Visit Hook. Do + MX + customize-group RET + gnuserv to make these + settings. + + + +
+ +
+ <application>VI iMproved</application> / &GUI; + + The gvim variant of the + vi editor supports inverse search very well. + No extra setup is required. +
+
+
+ + + + Forward search + + The forward search functions allow you to jump from your + editor directly into the associated position of the &DVI; + file. Since forward search must be supported by your editor, only + Emacs and + XEmacs are currently supported. Other + editors will hopefully join in soon. + + To use forward search, you have to do the following: + + + Set up your editor — this is described below. + + + Add source file information to your &DVI; file, ⪚ by + using the package srcltx. This has been + described in the section Producing TeX files for inverse + search. + + + If you use Emacs and + everything is properly set up, you just press + &Ctrl;X &Ctrl;J + , and &kdvi; pops up and jumps to the + place which corresponds to the place of the TeX file which you + are currently editing. + + + +
+ Setting up your editor for forward search + +
+ <application>Emacs</application> + + In order to use forward search in + Emacs, follow these steps: + + + + Download the following + Emacs script, + + kdvi-search.el (press + &Shift; and &LMB; the filename to download) and store + it in a place where Emacs + can access it — we recommend a folder + emacs-scripts. + + + Add the lines + +(add-to-list 'load-path (expand-file-name "~/emacs-scripts/")) +(require 'kdvi-search) +(add-hook 'LaTeX-mode-hook (lambda () (local-set-key "\C-x\C-j" 'kdvi-jump-to-line))) +(add-hook 'tex-mode-hook (lambda () (local-set-key "\C-x\C-j" 'kdvi-jump-to-line))) + + to your .emacs file. Restart + Emacs. + + + + Open Emacs, load a + TeX file, produce the corresponding &DVI; file, and either + enter the command Mx + kdvi-jump-to-line + or press &Ctrl;X + &Ctrl;J + . + It may happen that Emacs asks + you for the name of a master file. This is + useful if you use a TeX file which includes other files: + the master file is the top-level file which includes the + others. Emacs will perhaps also + ask to save the name of the master file as a local + variable, &ie; as a comment at the very end of the + file. Type either yes or + no to continue. + + + + + + + Make sure that Emacs is + installed. Try to start emacs from + the command line. + + + If Emacs fails to start + &kdvi;, you can find its output in the Buffer + kdvi-output. + + + +
+ +
+ <application>Kile</application> + If you use Kile, no further setup is necessary. + +
+ +
+ <application>XEmacs</application> + + To set up XEmacs, follow the + steps for Emacs above, but modify + your .xemacs rather than your + .emacs file. If you use a very recent + version of XEmacs, .xemacs may be a folder. In + that case, append the lines to + .xemacs/init.el. + +
+ +
+ +
+ + + The <guilabel>Preferences</guilabel> dialog + + + The Preferences dialog can be reached + by choosing DVI Options in the + Settings menu. + + The dialog consists of two tabs, Fonts + and Rendering. + + + <guilabel>Fonts</guilabel> Options + + + Traditionally, the TeX typsetter uses fonts that are generated + by the MetaFont program. These fonts are + stored in the PK format. While a carefully configured + MetaFont system produces printouts of + highest quality, its configuration requires serious expertise, + MetaFont is not very good at producing fonts + suitable for computer displays, and there are only few + MetaFont fonts available for Asian + languages. + + + + To overcome these problems, newer TeX installations therefore + include fonts that are stored in the "PostScript Type 1" + format, which is a widely used font format in electronic + publishing. &kdvi; is able to use both font formats. + + + + The following picture shows the font options dialog of &kdvi; + that can be used to control &kdvi;'s use of the various font + formats. + + + + The Fonts tab + + + + + + The Fonts tab + + + + + + + Use font hinting for Type 1 fonts, if available + + + PostScript "Type 1" often contain "font hints", + i.e. additional information that is supposed to + help software produce better quality output on + computer screens. The quality of the font hints + varies from font to font, and you should experiment + to see if enabling this option gives better results. + + + + + + + + <guilabel>&DVI; specials</guilabel> Options + + + &kdvi; supports a large number of extensions to the original + &DVI; format, e.g. hyperlinks, graphic file inclusion or + embedded source file information. These extensions are known as + "&DVI; specials". A full account of specials supported by + &kdvi; can be found in this + document. + + + + The &DVI; specials dialog help you to configure support for + some specials. + + + The Rendering tab + + + + + + The Rendering tab + + + + + + + Show PostScript specials + + If this option is checked, &kdvi; will display + &PostScript; graphics which are embedded into the &DVI; + file. You probably want to set this option. + + If an external &PostScript; file could not be found, + &kdvi; will draw a red warning box in its + place. Unfortunately, rendering &PostScript; graphics is + very slow in the current version of &kdvi;. We will + improve on the speed in later versions. If this option is + off, &kdvi; will either draw a gray box as a placeholder + for the graphics, or it will leave the space blank. + + + There is no standard way to embed &PostScript; + graphics into a &DVI; file. It may therefore happen that + &kdvi; cannot properly display a graphic which works + fine with other programs. Older versions of + xdvi and dvips + support the execution of external commands. This is a + bad security risk and therefore deliberately not + implemented in &kdvi;. Technical information about + supported ways to include &PostScript; can be found in + the document + KDVI-features.dvi. + + + + + + + + Editor for inverse search + + If you intend to use inverse search, a + very useful feature if you write TeX documents yourself, + you have to specify which editor you are going to use, and + how this editor can be started by &kdvi;. In the example + shown, the user has opted for the + NEdit editor. If you use one of + the pre-configured editors from the + Editor combobox, then you don't have + to do anything else. If you whish to use a different + editor, chose User-defined editor + from the Editor combobox and enter + the command line which will be used to start your + editor. Use the placeholders %f and + %l which will be replaced with the name of + the TeX file, and the line of the TeX file, + respectively. + + If you use an editor which is not supported, please + send us an email at kebekus@kde.org and tell us + about the command line you use and how you have configured + your editor. + + + + + + + + + Frequently asked questions + + + + + What happens when &kdvi; displays the message + KDVI is currently generating bitmap + fonts, and why does + the procedure take so long? + + + Many of the fonts which are typically used in a TeX + document must be generated by the MetaFont system. Metafont + is a language similar to TeX (included in most TeX + distributions) which takes a description of the font + outline, and produces a rasterized version (.pk file) of the font which can + then be send to a printer or be used in a previewing program + like &kdvi;. Metafont goes out of its way to produce the + best possible output for your printer. For instance, it + knows that a pixel of an inkjet printer is a roundish blot, + and that nearby pixels tend to smear into each other. In + contrast, a pixel on a laser printer is rectangular, but an + isolated pixel is very often not rendered at all. + + Generating such highly optimized bitmap fonts is + naturally rather time-consuming, in particular since typical + TeX documents use a large number of different fonts. We can + only ask for your patience. To ease the matter somewhat, + most distributions of TeX store the .pk files for a limited time, + ⪚ 100 days. Therefore, if you access the same document + more than once, the .pk + files will be reused. + + + + + + What is a MetaFont Mode? + + + In order to produce bitmap fonts which are optimized + for your printer (see the answer to the first question), + Metafont comes with a database of printing engines — look + for a file called modes.mf. A Metafont + Mode is just the name of a database entry. For example, the + name ljfour refers to the entry in the + database that describes a &Hewlett-Packard; LaserJet 4 + printer. A MetaFont Mode is usually followed by a number, + the resolution. The LaserJet, for instance, can print in both + 300 and 600 dots per inch. Thus, ljfour/600 + would be a full description. + + + + + + + + + Credits and Licenses + + &kdvi; + + &kdvi; is based on based on the stand-alone-program &kdvi; + 0.4.3 by Markku Hihnala. That program is in turn based on + xdvi version 18f which has many + authors. + + Documentation is copyright 2001-2004, Stefan Kebekus + kebekus@kde.org + + + +&underGPL; +&underFDL; + + + +&documentation.index; + +
+ + diff --git a/doc/kdvi/kdvi-search.el b/doc/kdvi/kdvi-search.el new file mode 100644 index 00000000..d08dd07e --- /dev/null +++ b/doc/kdvi/kdvi-search.el @@ -0,0 +1,102 @@ +;;; (X)Emacs frontend to forward search with kdvi. See the section on +;;; FORWARD SEARCH in the kdvi manual for more information on forward +;;; search, and for an explanation how to use this script. This script +;;; is a modified version of the script "xdvi-search.el" by Stefan +;;; Ulrich , version 2000/03/13. The +;;; modifications were performed by Stefan Kebekus +;;; . Tested with Emacs 20.7.1 and Xemacs 21.4. +;;; +;;; 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. +;;; +;;; Please report bugs or improvements, etc. via the "Report bug"-Menu +;;; of kdvi. +;;; + +(defvar kdvi-script "kdvi" + "*Name of start script for kdvi.") + +(defun kdvi-jump-to-line () + "Call kdvi-script to perform a `forward search' for current file and line number. +See contents of kdvi-script for details. +If AucTeX is used, the value of TeX-master-file is used as filename +for the master .dvi file; else, the return value of kdvi-master-file-name +is used (which see)." + (interactive) + (save-excursion + (save-restriction + (widen) + (beginning-of-line 1) + (let* (;;; current line in file, as found in the documentation + ;;; of emacs. Slightly non-intuitive. + (current-line (format "%d" (+ 1 (count-lines (point-min) (point))))) + ;;; name of the `main' .tex file, which is also used as .dvi basename: + (master-file (expand-file-name (if (fboundp 'TeX-master-file) + (TeX-master-file t) + (kdvi-get-masterfile (kdvi-master-file-name))))) + ;;; .dvi file name: + (dvi-file (concat (file-name-sans-extension master-file) ".dvi")) + ;;; current source file name. + (filename (expand-file-name (buffer-file-name)))) + (start-process "kdvi" + "kdvi-output" "kdvi" ;;; src-args + ;;; args for -sourceposition: + "--unique" (concat "file:" dvi-file "#src:" current-line filename) + ))))) + +(defun kdvi-get-masterfile (file) + "Small helper function for AucTeX compatibility. +Converts the special value t that TeX-master might be set to +into a real file name." + (if (eq file t) + (buffer-file-name) + file)) + + +(defun kdvi-master-file-name () + "Emulate AucTeX's TeX-master-file function. +Partly copied from tex.el's TeX-master-file and TeX-add-local-master." + (if (boundp 'TeX-master) + TeX-master + (let ((master-file (read-file-name "Master file (default this file): "))) + (if (y-or-n-p "Save info as local variable? ") + (progn + (goto-char (point-max)) + (if (re-search-backward "^\\([^\n]+\\)Local Variables:" nil t) + (let* ((prefix (if (match-beginning 1) + (buffer-substring (match-beginning 1) (match-end 1)) + "")) + (start (point))) + (re-search-forward (regexp-quote (concat prefix "End:")) nil t) + (if (re-search-backward (regexp-quote (concat prefix "TeX-master")) start t) + ;;; if TeX-master line exists already, replace it + (progn + (beginning-of-line 1) + (kill-line 1)) + (beginning-of-line 1)) + (insert prefix "TeX-master: " (prin1-to-string master-file) "\n")) + (insert "\n%%% Local Variables: " +;;; mode is of little use without AucTeX ... +;;; "\n%%% mode: " (substring (symbol-name major-mode) 0 -5) + "\n%%% TeX-master: " (prin1-to-string master-file) + "\n%%% End: \n")) + (save-buffer) + (message "(local variables written.)")) + (message "(nothing written.)")) + (set (make-local-variable 'TeX-master) master-file)))) + + +(provide 'kdvi-search) + diff --git a/doc/kdvi/optionrequester1.png b/doc/kdvi/optionrequester1.png new file mode 100644 index 00000000..c03159f1 Binary files /dev/null and b/doc/kdvi/optionrequester1.png differ diff --git a/doc/kdvi/optionrequester2.png b/doc/kdvi/optionrequester2.png new file mode 100644 index 00000000..13d252e3 Binary files /dev/null and b/doc/kdvi/optionrequester2.png differ diff --git a/doc/kdvi/srcltx.sty b/doc/kdvi/srcltx.sty new file mode 100644 index 00000000..3e2d61a3 --- /dev/null +++ b/doc/kdvi/srcltx.sty @@ -0,0 +1,184 @@ + +% ------------------------------------------------------------------------ +% File: srcltx.sty +% ========== +% +% Version 1.002 1999 Sep 3 (modified to change \everypar) +% by David Carlisle +% +% Version 1.001 1998 Dec 23 (modified to change \output) +% by Berthold Horn +% +% This package was originally written by Aleksander Simonic (the +% author of WinEdt Shell) to implement a source file tracking and +% DVI "SRC" specials for LaTeX. +% +% This package comes with no guarantees and no reserved rights. +% You can use or modify this file at your own risk. +% ************************************************************************ +% NOTE: TeX commands are case sensitive. You have to use uppercase +% \Input to take advantage of this package +% +% This package supports nested \Input commands... +% File extension should be specified in \Input! +% +% This file should be placed in a directory where your LaTeX is +% looking for inputs (eg. ...\localtexmf\tex for MiKTeX). +% +% If you are writing a book with WinEdt and LaTeX simply +% include this file and use \include{mychapter} command... +% This way all the necessary specials for DVI Search and +% Inverse Search are inserted in your DVI File. +% +% WinEdt will be able to track Errors from your LOG file. +% +% ************************************************************************ +% +% Some TeX implementations (eg. MiKTeX 1.20 [or later]) can insert +% the SRC specials much better than any macro package. Consult your +% TeX documentation to see if it is better to leave the task to your +% TeX. You can still use the [inactive] version of this package to +% take advantage of the re-defined Input commands and thus allowing +% WinEdt to keep track of errors in included source files. +% +% MiKTeX inserts the SRC specials in the DVI file if you start +% [La]TeX with --src qualifier (see MiKTeX's Manual: +% ...\texmf\Doc\MiKTeX\MiKTeX.pdf for more info). +% +% ************************************************************************ +% +% * NOTE: Some TeX implementations add the file type to the "\jobname". +% In that case the definition of the "\MainFile" should be modified to: +% +% \def\MainFile{\jobname} instead of \def\MainFile{\jobname.tex}. +% +% ************************************************************************ +% +% *** Example - Your LaTeX thesis document may look like this: +% +%\documentclass[12pt]{report} +%\usepackage[centertags]{amstex} +%\usepackage{thesis,newlfont,amsthm} +%\usepackage[active]{srcltx} +%%No src specials are written when loading the package by +%%\usepackage[inactive]{srcltx} +% +% .... Preamble .... +% +%\begin{document} +% +% .... Title, Author etc. .... +% +%\WinEdt{?0000} % Do not process any Errors (Overful/Underful Boxes) +%\beforepreface +%\WinEdt{?1111} % Process All Types of Errors from here on +%\include{ABS} +%\include{ACK} +%\afterpreface +%\include{chapter0} +%\include{chapter1} +%\include{chapter2} +%\include{chapter3} +%\bibliographystyle{amsplain} +%\bibliography{xbib} +%\end{document} +% +% ------------------------------------------------------------------------ +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{srcltx}[1999/10/11 v1.002 DVI Search] +\newif\ifSRCOK \SRCOKtrue +\DeclareOption{active}{\SRCOKtrue} +\DeclareOption{inactive}{\SRCOKfalse} +\ExecuteOptions{inactive} +\ProcessOptions +% ------------------------------------------------------------------------ +\newcount\PAGETOP +\newcount\LASTLINE +\global\PAGETOP=1 +\global\LASTLINE=-1 +\gdef\MainFile{\jobname.tex}% ".tex" needed for MiKTeX +\gdef\CurrentInput{\MainFile} +\newcount\INPSP +\global\INPSP=0 +\def\EJECT{\SRC\eject} +\def\WinEdt#1{\typeout{:#1}}% WinEdt LOG MODE and INPUT +% ------------------------------------------------------------------------ +%If your are using DVIWIN remove the \space from the definitions below... +\def\SRC{\ifSRCOK% + \ifnum\inputlineno>\LASTLINE% + \ifnum\LASTLINE<0% + \global\PAGETOP=\inputlineno% + \fi% + \global\LASTLINE=\inputlineno% + \ifnum\INPSP=0% + \ifnum\inputlineno>\PAGETOP% + \special{src:\the\inputlineno\space\CurrentInput}% + \fi% + \else% + \special{src:\the\inputlineno\space\CurrentInput}% + \fi% + \fi% +\fi} +% ------------------------------------------------------------------------ +\def\PUSH#1{% +\SRC% +\ifnum\INPSP=0 \global\let\INPSTACKA=\CurrentInput \else% +\ifnum\INPSP=1 \global\let\INPSTACKB=\CurrentInput \else% +\ifnum\INPSP=2 \global\let\INPSTACKC=\CurrentInput \else% +\ifnum\INPSP=3 \global\let\INPSTACKD=\CurrentInput \else% +\ifnum\INPSP=4 \global\let\INPSTACKE=\CurrentInput \else% +\ifnum\INPSP=5 \global\let\INPSTACKF=\CurrentInput \else% + \global\let\INPSTACKX=\CurrentInput \fi\fi\fi\fi\fi\fi% +\gdef\CurrentInput{#1}% +\WinEdt{<+ \CurrentInput}% +\global\LASTLINE=0% +\ifSRCOK\special{src:1\CurrentInput}\fi% +\global\advance\INPSP by 1} +% +\def\POP{% +\ifnum\INPSP>0 \global\advance\INPSP by -1 \fi% +\ifnum\INPSP=0 \global\let\CurrentInput=\INPSTACKA \else% +\ifnum\INPSP=1 \global\let\CurrentInput=\INPSTACKB \else% +\ifnum\INPSP=2 \global\let\CurrentInput=\INPSTACKC \else% +\ifnum\INPSP=3 \global\let\CurrentInput=\INPSTACKD \else% +\ifnum\INPSP=4 \global\let\CurrentInput=\INPSTACKE \else% +\ifnum\INPSP=5 \global\let\CurrentInput=\INPSTACKF \else% + \global\let\CurrentInput=\INPSTACKX \fi\fi\fi\fi\fi\fi% +\WinEdt{<-}% +\global\LASTLINE=\inputlineno% +\global\advance\LASTLINE by -1% +\SRC} +% ------------------------------------------------------------------------ +% Dummy Input: can be used as \INPUT{.bbl} to collect \bibitems +\def\INPUT#1{\relax} +% ------------------------------------------------------------------------ +% Redefine the original \include command +\let\OldINCLUDE=\include +\def\include#1{%Always ".tex" file type! +\EJECT% +\PUSH{#1.tex}% +\OldINCLUDE{#1}% +\POP} +% ------------------------------------------------------------------------ +\def\Input#1{%Specify File Extension! +\PUSH{#1}% +\input #1% +\POP} +% ------------------------------------------------------------------------ +% Note that these have been defined to concatenate the \SRC with +% whatever those token lists did before, just in case they were not +% empty token lists. Of course, later definitions may undo all this... +\let\originalxxxeverypar\everypar +\newtoks\everypar +\originalxxxeverypar{\the\everypar\expandafter\SRC} +%\everypar\expandafter{\the\everypar\expandafter\SRC} +% ??? Remove the following line if you encounter problems: +\everymath\expandafter{\the\everymath\expandafter\SRC} +% ------------------------------------------------------------------------ +% Redefine the \bibliography command: +\let\zzzxxxbibliography=\bibliography +\def\bibliography#1{\PUSH{\jobname.bbl}\zzzxxxbibliography{#1}\POP} +%------------------------------------------------------------------------ +% Modification to output routine to turn off \SRC while \output is active +\output\expandafter{\expandafter\SRCOKfalse\the\output} +%------------------------------------------------------------------------ diff --git a/doc/kdvi/srctex.sty b/doc/kdvi/srctex.sty new file mode 100644 index 00000000..26ecd74b --- /dev/null +++ b/doc/kdvi/srctex.sty @@ -0,0 +1,146 @@ +% ------------------------------------------------------------------------ +% File: srctex.sty +% ========== +% +% Version 1.002 1999 Sep 3 (modified to change \everypar) +% by David Carlisle +% +% Version 1.001 1998 Dec 23 (modified to change \output) +% by Berthold Horn +% +% This package was originally written by Aleksander Simonic (the +% author of WinEdt Shell) to implement a source file tracking and +% DVI "SRC" specials for TeX. +% +% This package comes with no guarantees and no reserved rights. +% You can use or modify this file at your own risk. +% ************************************************************************ +% NOTE: TeX commands are case sensitive. You have to use uppercase +% \Input to take advantage of this package +% +% This package supports nested \Input commands... +% File extension should be specified in \Input! +% +% This file should be placed in a directory where your TeX is +% looking for inputs (eg. ...\localtexmf\tex for MiKTeX). +% +% ************************************************************************ +% +% Some TeX implementations (eg. MiKTeX 1.20 [or later]) can insert +% the SRC specials much better than any macro package. Consult your +% TeX documentation to see if it is better to leave the task to your +% TeX. You can still use the [inactive] version of this package to +% take advantage of the re-defined Input commands and thus allowing +% WinEdt to keep track of errors in included source files. +% +% MiKTeX inserts the SRC specials in the DVI file if you start +% TeX with --src qualifier (see MiKTeX's Manual: +% ...\texmf\Doc\MiKTeX\MiKTeX.pdf for more info). +% +% ************************************************************************ +% +% If you are writing a book with WinEdt Shell and TeX simply +% include this file and use "\Input{my_chapter}" instead of +% "\input my_chapter". This way all the necessary specials for +% DVI Search and Inverse Search are inserted in your DVI File. +% +% WinEdt will be able to track Errors from your LOG file. +% +% To remove SRC Specials from the dvi file compile the source +% after inserting \SRCOKfalse immediately after +% the \usepackage{srctex} directive... +% +% This package supports nested \Input commands... +% File extension should be specified in \Input! +% +% ************************************************************************ +% +% * NOTE: Some TeX implementations add the file type to the "\jobname". +% In that case the definition of the "\MainFile" should be modified to: +% +% \def\MainFile{\jobname} instead of \def\MainFile{\jobname.tex}. +% +% ************************************************************************ +\def\typeout#1{\message{^^J}\message{#1}\message{^^J}} +% +\newif\ifSRCOK \SRCOKtrue +\newcount\PAGETOP +\newcount\LASTLINE +\global\PAGETOP=1 +\global\LASTLINE=-1 +\def\EJECT{\SRC\eject} +\def\WinEdt#1{\typeout{:#1}}% WinEdt LOG MODE and INPUT +\gdef\MainFile{\jobname.tex}% ".tex" needed for MiKTeX +\gdef\CurrentInput{\MainFile} +\newcount\INPSP +\global\INPSP=0 +% ------------------------------------------------------------------------ +%If your are using DVIWIN remove the \space from the definitions below... +\def\SRC{\ifSRCOK% + \ifnum\inputlineno>\LASTLINE% + \ifnum\LASTLINE<0% + \global\PAGETOP=\inputlineno% + \fi% + \global\LASTLINE=\inputlineno% + \ifnum\INPSP=0% + \ifnum\inputlineno>\PAGETOP% + \special{src:\the\inputlineno\space\CurrentInput} + \fi% + \else% + \special{src:\the\inputlineno\space\CurrentInput} + \fi% + \fi% +\fi} +% ------------------------------------------------------------------------ +\def\PUSH#1{% +\SRC% +\ifnum\INPSP=0 \global\let\INPSTACKA=\CurrentInput \else% +\ifnum\INPSP=1 \global\let\INPSTACKB=\CurrentInput \else% +\ifnum\INPSP=2 \global\let\INPSTACKC=\CurrentInput \else% +\ifnum\INPSP=3 \global\let\INPSTACKD=\CurrentInput \else% +\ifnum\INPSP=4 \global\let\INPSTACKE=\CurrentInput \else% +\ifnum\INPSP=5 \global\let\INPSTACKF=\CurrentInput \else% + \global\let\INPSTACKX=\CurrentInput \fi\fi\fi\fi\fi\fi% +\gdef\CurrentInput{#1}% +\WinEdt{<+ \CurrentInput}% +\global\LASTLINE=0% +\ifSRCOK\special{src:1\CurrentInput}\fi% +\global\advance\INPSP by 1} +% +\def\POP{% +\ifnum\INPSP>0 \global\advance\INPSP by -1 \fi% +\ifnum\INPSP=0 \global\let\CurrentInput=\INPSTACKA \else% +\ifnum\INPSP=1 \global\let\CurrentInput=\INPSTACKB \else% +\ifnum\INPSP=2 \global\let\CurrentInput=\INPSTACKC \else% +\ifnum\INPSP=3 \global\let\CurrentInput=\INPSTACKD \else% +\ifnum\INPSP=4 \global\let\CurrentInput=\INPSTACKE \else% +\ifnum\INPSP=5 \global\let\CurrentInput=\INPSTACKF \else% + \global\let\CurrentInput=\INPSTACKX \fi\fi\fi\fi\fi\fi% +\WinEdt{<-}% +\global\LASTLINE=\inputlineno% +\global\advance\LASTLINE by -1% +\SRC} +% ------------------------------------------------------------------------ +% Dummy Input: can be used as \INPUT{.bbl} to collect \bibitems +\def\INPUT#1{\relax} +% ------------------------------------------------------------------------ +\def\Input#1{%Specify File Extension! +\SRC% +\PUSH{#1}% +\input #1% +\POP% +\SRC} +% ------------------------------------------------------------------------ +% Note that these have been defined to concatenate the \SRC with +% whatever those token lists did before, just in case they were not +% empty token lists. Of course, later definitions may undo all this... +\let\originalxxxeverypar\everypar +\newtoks\everypar +\originalxxxeverypar{\the\everypar\expandafter\SRC} +%\everypar\expandafter{\the\everypar\expandafter\SRC} +% ??? Remove the following line if you encounter problems: +\everymath\expandafter{\the\everymath\expandafter\SRC} +%------------------------------------------------------------------------ +% Modification to output routine to turn off \SRC while \output is active +\output\expandafter{\expandafter\SRCOKfalse\the\output} +%------------------------------------------------------------------------ diff --git a/doc/kgamma/Makefile.am b/doc/kgamma/Makefile.am new file mode 100644 index 00000000..085981d9 --- /dev/null +++ b/doc/kgamma/Makefile.am @@ -0,0 +1,4 @@ + +KDE_LANG = en +KDE_DOCS = AUTO + diff --git a/doc/kgamma/index.docbook b/doc/kgamma/index.docbook new file mode 100644 index 00000000..93be5949 --- /dev/null +++ b/doc/kgamma/index.docbook @@ -0,0 +1,234 @@ + +KGamma'> + + + + +]> + + + + + +The KGamma Handbook + + + + +Michael +v.Ostheim + +
ostheimm@users.berlios.de
+
+
+
+ + + +2001, 2002, 2003 +Michael v.Ostheim + + + +&FDLNotice; +28/08/2003 +1.00.20 + + + +&kgamma; is a simple tool for monitor gamma correction. + + + +KDE +KGamma +Monitor +Calibration +Gamma + + +
+ + +Introduction + +This document describes &kgamma; version 1.0.2 (KDE 3.2) +&kgamma; is a tool for monitor gamma correction. With proper gamma +settings, your display (websites, images, etc.) will look the same on your +monitor as on other monitors. +&kgamma; allows you to alter the monitor's gamma correction of +XFree86. But that's not all to do. For good results you have to set the +correct brightness, contrast and color balance of your monitor. This +may be difficult and you have to repeat every step several times. +For perfect results you need really good (and expensive) hardware. +This are system settings, please do not use &kgamma; to manipulate your +image files. + + + +Using KGamma + +Setting Gamma Correction +Use the four sliders to define the gamma correction either as a single +value, or separately for the red, green and blue components. The XFree86 +default setting for gamma is 1.00 (Mac 1.80, WinXX 2.20). The test images help +you to find proper settings. +To store the gamma settings system wide, enable the option 'Store +settings to XF86Config'. The system settings will be restored at next XFree86 +startup. You need root access to use this option. Use this if you want to +correct the gamma settings for all users and graphical environments on this +machine. +To store the gamma settings to your personal KDE configuration, do not +enable that option. The user settings will be restored at next KDE startup and +replace temporary the system gamma settings. The system settings are not removed by +that and will be restored at next XFree86 startup. +On multi head systems, select the screen you want to alter with the combo +box. This will also work with xinerama enabled. If you want to set all screens +to the same gamma values, enable the 'Sync screens' option. On systems with only +one screen this option will take no effect. + + + +Gray Scale Test Image +You should be able to see the following: + + + +A gray scale with 20 different sections + + +The darkest section pure black + + +The lightest section pure white + + +No hint of any color in the gray tones + + + +If you can't see all of the 20 sections, use your monitors contrast settings +or the "Gamma" slider of &kgamma; to correct this. If black is not pure black, +try to darken the monitor, if white is not pure white, try to lighten +it. If you see any colors in the gray tones alter the color balance settings of +your monitor or the "Red", "Green" and "Blue" slider of &kgamma;. + + + +RGB Scale Test Image + +You should be able to see three strips, each with 16 sections of red, +green or blue tones. The darkest sections should be pure black, the brightest +should be pure red, green or blue. If you don't see all sections of +a color strip, try to lighten or darken this color. + + + +CMY Scale Test Image + +You should be able to see three strips, each with 11 sections of cyan, +magenta or yellow tones. The brightest sections should be pure white, the darkest +should be pure cyan, magenta or yellow. + + + +If you can't see all cyan sections, try to lighten or darken red + + +If you can't see all magenta sections, try to lighten or darken green + + +If you can't see all yellow sections, try to lighten or darken blue + + + + + +Advanced Test Images + +The following three pictures shows you the abilities of your monitor at +three points of the gray spectrum. If you can't see all of the details, +don't be worry, or buy better hardware. + + +Dark Gray Test Image + +You should be able to see 10 different rectangles of dark gray within a +black box. The chart shows you 1% steps from black. + + + +Mid Gray Test Image + +This picture shows you 11 gray rectangles within a 50% gray box. You should be +able to see all of the rectangles except the middle one. The rectangles represent +the steps from 45% to 55% gray. + + + +Light Gray Test Image + +You should be able to see 10 different rectangles of light gray within a white box. +The chart shows you 1% steps from white. + + + + + + + +Credits and License + + +&kgamma; + + +Program copyright 2001, 2002, 3003 Michael v.Ostheim ostheimm@users.berlios.de + + + +Documentation copyright 2001, 2002, 2003 Michael v.Ostheim ostheimm@users.berlios.de + + + + +&underFDL; +&underGPL; + + + +Installation + +&kgamma;'s home site is +http://kgamma.berlios.de/index2.php + + + +Compilation and Installation + + +In order to compile and install &kgamma; on your system, type the following in the base +folder of the &kgamma; distribution: + +% ./configure +% make +% make install + + + + + + +&documentation.index; +
+ diff --git a/doc/kghostview/Makefile.am b/doc/kghostview/Makefile.am new file mode 100644 index 00000000..085981d9 --- /dev/null +++ b/doc/kghostview/Makefile.am @@ -0,0 +1,4 @@ + +KDE_LANG = en +KDE_DOCS = AUTO + diff --git a/doc/kghostview/index.docbook b/doc/kghostview/index.docbook new file mode 100644 index 00000000..41258728 --- /dev/null +++ b/doc/kghostview/index.docbook @@ -0,0 +1,755 @@ + + + + + +]> + + + +The &kghostview; Handbook + + +Pamela +Roberts + +
&Pamela.Roberts.mail;
+
+
+ + +
+ + +2001 2002 +&Pamela.Roberts; + + +&FDLNotice; + +2006-02-28 +0.20 + + +&kghostview; displays and prints &PostScript; (.ps, .eps) and Portable Document Format +(.pdf) files. +This document describes &kghostview; version 0.20 + + + +KDE +linux +postscript +ghostview + + +
+ + +Introduction + + +&kghostview; displays and prints &PostScript; (.ps, .eps) and Portable Document Format (.pdf) files. It is a port to &kde; of Tim +Theisen's Ghostview program which uses Alladin +Ghostscript to view documents prepared in +Adobe's &PostScript; page +description language. &PostScript; is the major page description language +for printing on &UNIX; systems and this application can be used to preview +material intended for printing or for reading documents online. + + + +You can use &kghostview; with all recent versions of +Ghostscript. Newer versions offer much +improved performance which you can take advantage of with &kghostview;. + + + +If a document does not conform to the Adobe document structuring convention the +functionality of the viewer is limited. For example, if there is no +table of contents, skipping around the document and marking pages is not +possible. + + + + + + +Fundamentals + + +This section describes what you see in the main &kghostview; window, the +actions of the Toolbar buttons and how to use the Page List. + + + +You can open multiple instances of &kghostview; to view multiple +documents. The titlebar at the top of a window shows you the name of +the document in that window. + + + +The main area displays a page of the current document. If the page is +too large to fit inside the window, scrollbars are automatically added +to the sides of the display, although these can be disabled with the +Settings menu. + + +Note that the Toolbar and the Page List can be hidden with the Settings menu options to give more space on +the screen for the content area. + + + +You can scroll up and down in a page with the Up +Arrow and Down Arrow keys, or use the +ViewRead Up +(PageUp) and View +Read Down +(PageDown) options to scroll through the entire document. + + +The +Read Up and Read Down +-Toolbar buttons do what they say, or you can go +immediately to any page with a &LMB; click on the appropriate entry in +the Page List. + + + +If selected in the Settings menu a Page List will be +displayed at the left side of the window. This list has two columns: the +first may contain a flag indicating that the page has been marked, the +second contains the page numbers. You can use this page list to navigate +through the document or to mark pages for printing. + + + +You can toggle the page marked flag for the currently +displayed page with &Ctrl;&Shift;M or for +any page by &LMB; clicking on it in the Page List. You can also clear or +change your page marks using the context menu that is activated by +&RMB; clicking anywhere in the Page List area or by selecting the Edit menu. + + + + + +The Menubar + + +The <guimenu>File</guimenu> Menu + + + + + +&Ctrl; +O +File +Open... + +Open a file. If a file +is currently being displayed it will be closed. + + + + + +File +Open Recent + +Open a file selected from a combo box of +recently opened files. If a file is currently being displayed it will be +closed. + + + + +File +Save As... + +Save the currently open file. + + + + + +&Ctrl; +P +File +Print... + +Print the currently displayed document. +The Print dialog box will let you choose to print all or selected +(marked) pages. + + + + +File +Document Info + +Display some basic information about +the document. + + + + +&Ctrl; +Q +File +Quit + +Close down &kghostview;. + + + + + + + + +The <guimenu>Edit</guimenu> Menu + + + +You can also get this menu by &RMB; clicking anywhere in the Page List +area. + + + + + + + +&Ctrl;&Shift; +M +Edit +Mark Current Page + +Toggle the page marked +flag for the current page. + + + + +Edit +Mark All Pages + +Set the page marked +flag for all pages of the document. + + + + +Edit +Mark Even Pages + +Set the page marked +flag for all even numbered pages in the document. Used in +conjunction with Mark Odd Pages or +Toggle Page Marks this provides a convenient way of +double-sided printing a document on a single sided printer + + + + +Edit +Mark Odd Pages + +Set the page marked +flag for all odd numbered pages in the document. + + + + +Edit +Toggle Page Marks + +Toggle the page marked +flags for all pages in the document. + + + + +Edit +Remove Page Marks + +Clear the page marked +flags for all pages in the document. + + + + + + + +The <guimenu>View</guimenu> Menu + + + + + + +F5 + +View +Reload + +Re-render the current document page. + + + + +M +View +Maximize + + +This option maximizes the &kghostview; window. + + + + +&Ctrl;&Shift; +F +View +Full Screen Mode + + +This option maximizes the &kghostview; window and the currently shown page. +Even the window decorations (titlebar &etc;) are temporarily removed. +To switch back to normal window mode, press the ESC key or +the shortcut &Ctrl;&Shift; +F again, or open the context menu with a &RMB; click +and select Exit Full Screen Mode. + + + + + + +View +Orientation + +Change the orientation of the +displayed page. You can choose between Auto, +Portrait, +Landscape, Upside +Down and Seascape which is like +Landscape but the other way up. + + + + +View +Paper Size + +Lets you view the document as if it +were printed on different paper sizes without changing the +scale. You should normally choose Auto. + + + + +&Ctrl;+ + +View +Zoom In + +Increase the magnification of the +document view. + + + +View +Zoom + + +Select a predefined zoom factor. + + + + + +&Ctrl; +- +View +Zoom Out + +Decrease the magnification of the +document view. + + + +View +Fit to Page Width + +Scale the display so a page width fits +exactly across the main display area. + + + +S +View +Fit to Screen + +Scale the display so the entire page fits +exactly across the main display area. + + + +&Ctrl; +PageUp +View +Previous Page + +View the previous page of the +document. + + + +&Ctrl; +PageDown +View +Next Page + +View the next page of the +document. + + + +&Ctrl; +Home +View +First Page + +Go to the first page of the +document. + + + +&Ctrl; +End +View +Last Page + +Go to the last page of the +document. + + + +View +Go to Page + +Go to a selected page of the +document. + + + +PageUp +View +Read Up + +Scroll backwards through the +document. + + + +PageDown +View +Read Down + +Scroll forwards through the +document. + + + + + + +The <guimenu>Settings</guimenu> Menu + + + + + +&Ctrl;M +Settings +Show/Hide Menubar + +Toggles the menubar on/off. + + + + +Settings +Show/Hide Toolbar + +Toggle the Toolbar display on +and off. + + + +Settings +Show/Hide Statusbar + +Toggle the Status bar display on +and off. + + +&Ctrl;&Shift; +F +Settings +Full Screen Mode + + +This option maximizes the &kghostview; window and the currently shown page. +Even the window decorations (titlebar &etc;) are temporarily removed. +To switch back to normal window mode, press the ESC key or +the shortcut &Ctrl;&Shift; +F again, or open the context menu with a &RMB; click +and select Exit Full Screen Mode. + + + + + + +Settings +Configure Shortcuts... + +Opens a dialog for changing the shortcuts. +Using this option you can change the standard key shortcut for &kghostview;'s commands +or create new ones. + + + + +Settings +Configure Toolbars... + +Opens a dialog for configuring the toolbar. You +can add and remove toolbuttons for &kghostview;'s commands with this +option. + + + + +Settings +Show/Hide Scrollbars + +Toggle the horizontal and vertical scrollbars +on and off. + + + +Settings +Show Page List + +Toggle the Page List +on and off. + + + +Settings +Show Page Labels + +If this is selected the name (if any) of the +current page is displayed in the Status Bar. + + + + +Settings +Watch File + +If this is selected the display will +automatically update if the document file +changes. + + + +Settings +No Flicker + + +If this is selected the display will start showing objects instantly as they are rendered, +otherwise the whole page is rendered off-screen and then displayed. + + + + +Settings +Configure &kghostview;... + +Brings up the &kghostview; +configuration dialog +box. + + + + + + +The <guimenu>Help</guimenu> Menu + +&help.menu.documentation; + + + + + +Configuration + + +The configuration dialog box is accessed with the +SettingsConfigure +&kghostview;... option. It has two pages; +General and Ghostscript +Configuration + + + +General Settings + + +You can select Enable anti-aliasing of fonts and +images to get smoothly rendered text, but note that +anti-aliasing is memory intensive and slower than straightforward +rendering of fonts. Early versions of +Ghostscript could not perform anti-aliasing. + + + +Select Use platform fonts if you wish to use your +native system fonts rather than those that come with +Ghostscript. + + + +Turn Show Ghostscript messages in a separate box +on if you want to be informed of any output or error messages +generated by the Ghostscript interpreter. + + + +You can choose whether &kghostview; uses a +Monochrome, Grayscale or +Color Palette for the display. + + + + + +<application>Ghostscript</application> Configuration + + +In this dialog box page you can set the name of the +Ghostscript Interpreter: +executable and the Non-antialiasing arguments: and +the Antialiasing arguments: passed to it. The +default settings should be suitable for most systems. + + + + + + + + +Credits and License + + +&kghostview; + + + +Program Copyright: +&Mark.Donohoe; &Mark.Donohoe.mail; (original author) 1998 + +&David.Sweet; &David.Sweet.mail; +Maintainer 1999-2000 + +&Wilco.Greven; &Wilco.Greven.mail; +Current maintainer + +&David.Faure; &David.Faure.mail; (basis for +shell) + +Daniel Duley mosfet@kde.org (port to +Kparts) + +&Espen.Sand; &Espen.Sand.mail; (dialog boxes) + + + + + +Documentation copyright 2001, 2002 &Pamela.Roberts; +&Pamela.Roberts.mail; + + + + + +&underFDL; + +&underGPL; + + + + + +Installation + + +&kghostview; is part of the &kde; 3 project, details of which can be found at +http://www.kde.org. + + + +To use &kghostview;, you must have the Ghostscript +program as well as &kde; 3 installed on your machine. The +Ghostscript home page is at +http://www.cs.wisc.edu/~ghost/ + + + +Most distributions will include &kghostview;, but if you want to roll your own +the source code can be found in the &package; package on &kde-ftp;, the main +ftp site of the &kde; project. + + + +&install.compile.documentation; + + + +&documentation.index; + +
+ + diff --git a/doc/kiconedit/Makefile.am b/doc/kiconedit/Makefile.am new file mode 100644 index 00000000..085981d9 --- /dev/null +++ b/doc/kiconedit/Makefile.am @@ -0,0 +1,4 @@ + +KDE_LANG = en +KDE_DOCS = AUTO + diff --git a/doc/kiconedit/index.docbook b/doc/kiconedit/index.docbook new file mode 100644 index 00000000..92bc8bc3 --- /dev/null +++ b/doc/kiconedit/index.docbook @@ -0,0 +1,1083 @@ + + + + + +]> + + + +The &kiconedit; Manual + + +Thomas +Tanghus + +
&Thomas.Tanghus.mail;
+
+
+ + + +
+ + +1997 +&Thomas.Tanghus; + + +20012003 +&Lauri.Watts; + + + +&FDLNotice; + + +2005-12-10 +3.5.0 + + + +&kiconedit; is designed to help create icons for &kde; using the +standard icon palette. + + + + +KDE +kdegraphics +KIconEdit +icon + +
+ + +Introduction + +
+&Thomas.Tanghus; +&Thomas.Tanghus.mail; + + +&kiconedit; is designed to help create icons for &kde; using the +standard icon palette. + + + +I hope you will find this program somehow useful and I would +appreciate any suggestions and comments. + + +
+ +
+ + +Onscreen Fundamentals + + +In this section will be briefly described the Icon Editor user +interface. + + + +The Icon Editor window is separated in five areas: main toolbar, tools +toolbar, statusbar, color palette and the grid, where you paint the icon. + + + +Main Toolbar + + + + +New + + +Create a new icon. If the current file has been +modified you will be asked if you want to save the changes. After that a +dialog will open where you can choose to create the icon from scratch or +from a template. + + + + + +Open + + +Open an existing icon file. + + + + + +Save + + +Save the currently open icon. + + + + + +Print + + +Print the icon. + + + + + +Undo +Undo the last action + + + +Redo +Redo the last action undone. If no actions have been +undone, this action is disabled. + + + +Cut + + +Cuts out the entire icon and put it onto the clipboard. + + + + + +Copy + + +Copies the entire icon to the clipboard. + + + + + +Paste + + +Paste the contents of the clipboard as a new image (if the +clipboard contains a valid icon). + + + + + +Zoom +Zoom In +Zoom Out + + +Zoom to predefined zoom factor, zoom in or zoom out. + + + + + +Resize + + +Resize icon to width X height. + + + + + +GrayScale + + +Gray scale the icon image. This may create colors not +conformant to the &kde; icon palette. + + + + + +Show Grid + + +Toggle grid on/off. + + + + + + + + +Tools Toolbar + + +This toolbar contains the tools you can use to manipulate the +icon. + + + + +Freehand + + +Draw free hand. + + + + + +Color Picker + + +Doesn't change the icon but changes the current drawcolor to the +color clicked on. + + + + + +Rectangle + + +Draw a rectangle. + + + + + +Filled Rectangle + + +Draw a filled rectangle. + + + + + +Circle + + +Draw a circle. + + + + + +Filled Circle + + +Draw a filled circle. + + + + + +Ellipse + + +Draw an ellipse + + + + + +Filled Ellipse + + +Draw a filled ellipse (almost the same thing as drawing +a circle.) + + + + + +Spray + + +Draws a randow dotted pattern like a spraycan. + + + + + +Flood Fill + + +Fill an area with the current color. + + + + + +Line + + +Draw a line. + + + + + +Eraser (Transparent) + + +Draw transparent (invisible). + + + + + +Rectangular Selection +Circular Selection + + +Select (mark) a part of the icon. + + + + + + + + +Grid + + +The grid is where you manipulate the icon contents. + + + + +Statusbar + + +The status bar keeps you informed of current operations. From left to +right, it tells you the x,y coordinates of the pixel you are working on, +the size of the current canvas, the zoom factor, and the current number +of colors in the icon. + + + + + + +The Menu Entries + + +The <guimenu>File</guimenu> Menu + + +The following functions are available from the File +menu: + + + + + + + +&Ctrl;N + +File +New + + + + +Lets you create a new icon, either from a template or +by specifying the size. + + + + + + + +File +New Window + + + + +Open a new Icon Editor window. + + + + + + + + +&Ctrl;O + +File +Open... + + + + +Open an existing icon file. + + + + + + + +File +Open Recent + + + + +Displays a list of recently opened icons to choose +from. + + + + + + + + +&Ctrl;S + +File +Save + + + + +Save the currently open icon. + + + + + + + +File +Save As... + + + + +Save the currently open icon under a new name. + + + + + + + + +&Ctrl;P + +File +Print... + + + + +Print the icon + + + + + + + + +&Ctrl;W + +File +Close + + + + +Close &kiconedit;. + + + + + + + + +The <guimenu>Edit</guimenu> Menu + + +The Edit menu contains the following entries: + + + + + +&Ctrl;Z +EditUndo + +Undo the last action + + + + +&Ctrl;&Shift;Z +EditRedo +Redo the last action undone. If no actions have been +undone, this action is disabled. + + + + + + +&Ctrl;X + +Edit +Cut + + + + +Cuts out the entire icon and put it onto the clipboard. + + + + + + + + +&Ctrl;C + +Edit +Copy + + + + +Copies the entire icon to the clipboard. + + + + + + + + +&Ctrl;V + +Edit +Paste + + + + +Paste the contents of the clipboard (if the clipboard contains a +valid icon). + + + + + + + +Edit +Paste as New + + + + +Paste the contents of the clipboard as a new image into a new Icon Editor window (if the +clipboard contains a valid icon). + + + + + + + +Edit +Clear + + + + +Clear the grid and fill it with transparent color. + + + + + + + + +&Ctrl;A + +Edit +Select All + + + + +Marks the entire icon as selected. + + + + + +EditResize... + + +Resize icon to width X height. + + + + + +EditGrayScale + +Gray scale the icon image. This may +create colors not conformant to the &kde; icon palette. + + + + + + + + +The <guimenu>View</guimenu> Menu + + + + + + +&Ctrl;+ +View +Zoom In + + + + +Magnify the view of the icon. + + + + + + + + +&Ctrl;- +View +Zoom Out + + + + +Shrink the view icon to a smaller screen size + + + + + + + +View +Zoom + + + +Zoom to a predefined zoom factor + + + + + + + +The <guimenu>Tools</guimenu> Menu + + + + + +Tools +Freehand + + + + +Draw free hand. + + + + + +ToolsColor +Picker +Select a color from the screen to use as the +foreground color. + + + + + +Tools +Rectangle + + + + +Draw a rectangle. + + + + + + + +Tools +Filled Rectangle + + + + +Draw a filled rectangle. + + + + + + + +Tools +Circle + + + + +Draw a circle. + + + + + + + +Tools +Filled Circle + + + + +Draw a filled circle. + + + + + + + +Tools +Ellipse + + + + +Draw an ellipse + + + + + + + +Tools +Filled Ellipse + + + + +Draw a filled ellipse (almost the same thing as drawing +a circle.) + + + + + + + +Tools +Spray + + + + +Draws a random dotted pattern like a spraycan. + + + + + + + +Tools +Flood Fill + + + + +Fill an area with the current color. + + + + + + + +Tools +Line + + + + +Draw a line. + + + + + + + +Tools +Eraser (Transparent) + + + +Draw transparent (invisible). + + + + +Tools +Rectangular Selection +Tools +Circular Selection +Select (mark) a part of the icon. + + + + + + + + + +The <guimenu>Settings</guimenu> Menu + + + + + + +Settings +Toolbars + + + + +Toggle on and off the display of the toolbars. + + + + + + +Settings +Show/Hide Statusbar + + + + +Toggle on and off the display of the status bar. + + + + + + +Settings +Show/Hide Grid + + + + +Toggle on and off the grid. + + + + +Settings +Configure Shortcuts... + +Opens a dialog where you can customize &kiconedit;'s +keyboard shortcuts. + + + + + +Settings +Configure &kiconedit;... + + + + +Opens the &kiconedit; configuration +dialog configuration dialog, described separately. + + + + + + + + + + +The <guimenu>Help</guimenu> Menu + +&help.menu.documentation; + + + + + +Configuration + + +Configuring &kiconedit; +Selecting the Settings +Configure &kiconedit;... menu item will +open a configuration dialog with the tree tabs Icon Templates, +Background and Icon Grid. + + +&kiconedit; configuration dialog + + +&kiconedit; configuration dialog + + + + +The <guilabel>Icon Templates</guilabel> Tab +Add..., Edit... and Remove +the templates for Standard File, Source File, +Compressed File &etc;. + + +The <guilabel>Background</guilabel> Tab +Select to Use color or to Use pixmap +as background. A Preview of your choice is displayed. + + +The <guilabel>Icon Grid</guilabel> Tab +Select to Paste transparent pixels or Show rulers +and set a Solid Color or a Checkerboard as +Transparency Display. +You can set the Checkerboard Size: to Small, +Medium or Large and choose Color 1: +and Color 2: of the checkerboard. + + + + + + +Credits and Licenses + + +&kiconedit; + + + +Program copyright &Thomas.Tanghus; tanghus@kde.org + + + +Contributors + + +John Califf jcaliff@compuzone.net + + + + +Laurent Montel lmontel@mandrakesoft.com + + +Aaron Seigo &Aaron.J.Seigo.mail; +Nadeem Hassan nhasan@nadmm.com - Rewrote UI to use +XMLGUI, Lots of fixes and cleanup +Adrian Page Adrian.Page@tesco.net - Bug Fixes and &GUI; tidy up. + + + + + + +&underFDL; +&underGPL; + + + + +Installation + + +How to obtain &kiconedit; + +&install.intro.documentation; + + + + +Compilation and Installation + +&install.compile.documentation; + + + + + + + +
+ + + diff --git a/doc/kiconedit/kiconedit-configuration.png b/doc/kiconedit/kiconedit-configuration.png new file mode 100644 index 00000000..100a68cb Binary files /dev/null and b/doc/kiconedit/kiconedit-configuration.png differ diff --git a/doc/kolourpaint/Makefile.am b/doc/kolourpaint/Makefile.am new file mode 100644 index 00000000..171f575c --- /dev/null +++ b/doc/kolourpaint/Makefile.am @@ -0,0 +1,2 @@ +KDE_LANG = en +KDE_DOCS = AUTO diff --git a/doc/kolourpaint/brush_shapes.png b/doc/kolourpaint/brush_shapes.png new file mode 100644 index 00000000..ee02cc21 Binary files /dev/null and b/doc/kolourpaint/brush_shapes.png differ diff --git a/doc/kolourpaint/color_box.png b/doc/kolourpaint/color_box.png new file mode 100644 index 00000000..97d7b458 Binary files /dev/null and b/doc/kolourpaint/color_box.png differ diff --git a/doc/kolourpaint/eraser_shapes.png b/doc/kolourpaint/eraser_shapes.png new file mode 100644 index 00000000..43c1f788 Binary files /dev/null and b/doc/kolourpaint/eraser_shapes.png differ diff --git a/doc/kolourpaint/fcc_std_text.png b/doc/kolourpaint/fcc_std_text.png new file mode 100644 index 00000000..6d74b00f Binary files /dev/null and b/doc/kolourpaint/fcc_std_text.png differ diff --git a/doc/kolourpaint/fcc_trans_text.png b/doc/kolourpaint/fcc_trans_text.png new file mode 100644 index 00000000..c85f07d6 Binary files /dev/null and b/doc/kolourpaint/fcc_trans_text.png differ diff --git a/doc/kolourpaint/fill_color_similarity.png b/doc/kolourpaint/fill_color_similarity.png new file mode 100644 index 00000000..2fce4156 Binary files /dev/null and b/doc/kolourpaint/fill_color_similarity.png differ diff --git a/doc/kolourpaint/fill_style.png b/doc/kolourpaint/fill_style.png new file mode 100644 index 00000000..6ced3249 Binary files /dev/null and b/doc/kolourpaint/fill_style.png differ diff --git a/doc/kolourpaint/image_balance.png b/doc/kolourpaint/image_balance.png new file mode 100644 index 00000000..96eadb9c Binary files /dev/null and b/doc/kolourpaint/image_balance.png differ diff --git a/doc/kolourpaint/image_emboss.png b/doc/kolourpaint/image_emboss.png new file mode 100644 index 00000000..093b25e3 Binary files /dev/null and b/doc/kolourpaint/image_emboss.png differ diff --git a/doc/kolourpaint/image_flatten.png b/doc/kolourpaint/image_flatten.png new file mode 100644 index 00000000..8095c62e Binary files /dev/null and b/doc/kolourpaint/image_flatten.png differ diff --git a/doc/kolourpaint/image_flip.png b/doc/kolourpaint/image_flip.png new file mode 100644 index 00000000..0e87243d Binary files /dev/null and b/doc/kolourpaint/image_flip.png differ diff --git a/doc/kolourpaint/image_invert.png b/doc/kolourpaint/image_invert.png new file mode 100644 index 00000000..64be7174 Binary files /dev/null and b/doc/kolourpaint/image_invert.png differ diff --git a/doc/kolourpaint/image_reduce_colors.png b/doc/kolourpaint/image_reduce_colors.png new file mode 100644 index 00000000..a8cd5884 Binary files /dev/null and b/doc/kolourpaint/image_reduce_colors.png differ diff --git a/doc/kolourpaint/image_resize_scale.png b/doc/kolourpaint/image_resize_scale.png new file mode 100644 index 00000000..43014039 Binary files /dev/null and b/doc/kolourpaint/image_resize_scale.png differ diff --git a/doc/kolourpaint/image_rotate.png b/doc/kolourpaint/image_rotate.png new file mode 100644 index 00000000..0db94613 Binary files /dev/null and b/doc/kolourpaint/image_rotate.png differ diff --git a/doc/kolourpaint/image_skew.png b/doc/kolourpaint/image_skew.png new file mode 100644 index 00000000..81f2afb4 Binary files /dev/null and b/doc/kolourpaint/image_skew.png differ diff --git a/doc/kolourpaint/image_soften_sharpen.png b/doc/kolourpaint/image_soften_sharpen.png new file mode 100644 index 00000000..ba7d94d7 Binary files /dev/null and b/doc/kolourpaint/image_soften_sharpen.png differ diff --git a/doc/kolourpaint/index.docbook b/doc/kolourpaint/index.docbook new file mode 100644 index 00000000..c80f7011 --- /dev/null +++ b/doc/kolourpaint/index.docbook @@ -0,0 +1,1501 @@ + + + ClarenceDang"> + dang@kde.org"> + ThurstonDang"> + thurston_dang@users.sourceforge.net"> + + + +]> + + + + +The &kolourpaint; Handbook + + + + +Thurston +Dang + +thurston_dang@users.sourceforge.net + + + + +Clarence +Dang + + + + +&Lauri.Watts; + + + + + +2004 +2005 +Thurston Dang + + + +&FDLNotice; + +2005-12-29 +1.4_relight + + + +&kolourpaint; is a free, easy-to-use paint program for &kde;. + + + + +kolourpaint +kdegraphics + + + + + +Introduction +&kolourpaint; is a free, easy-to-use paint program for &kde;. It's +perfect for everyday tasks such as: + + + +Painting - drawing diagrams and finger painting + + +Image Manipulation - editing screenshots and photos; applying +effects + + +Icon Editing - drawing clipart and logos with transparency + + + + + +Using &kolourpaint; + +Click on the following links to explore &kolourpaint;'s +capabilities: + + + +Tools + + +Working with Color + + +View Options + + +Image Effects + + + + + +Tools + + +Tool Reference + + +A quick way to select a tool in &kolourpaint; is to press the single key shortcut associated with it, +documented below and in the Tool Box tooltips. You can also hold +&Alt;&Shift; while pressing the key, which is necessary when you are +writing text (as the single key shortcuts will be disabled). For example, to select the brush, press +&Alt;&Shift;B or just B (when not writing text). + + + + + + + +Brush (B) + + + + + + + + +Color Eraser (O) + + + + + + + + + +Color Picker (C) + + + + + + + + + + + + +Connected Lines (N) + + + + + + + + + + + +Curve (V) + + + + + + + + + + + + +Ellipse (E) + + + + + + + + + + + + +Eraser (A) + + + + + + + + + + + + +Flood Fill (F) + + + + + + + + + + + + +Line (L) + + + + + + + + + + + + +Pen (P) + + + + + + + + + + + + +Polygon (G) + + + + + + + + + + + + +Rectangle (R) + + + + + + + + + + + + +Rounded Rectangle (U) + + + + + + + + + + + + +Selection (Elliptical) (I) + + + + + + + + + + + + +Selection (Free-Form) (M) + + + + + + + + + + + + +Selection (Rectangular) (S) + + + + + + + + + + + + +Spraycan (Y) + + + + + + + + + + + + +Text (T) + + + + + + + +Brush +<inlinemediaobject> +<imageobject> +<imagedata fileref="tool_brush.png" format="PNG"/> +</imageobject> +</inlinemediaobject> + + +Click or click and drag with the brush to draw. + + + + + + + + + + + + + + + + +Click on one of the shapes to select the brush shape. You can use a +circular, square, slash or backslash brush shape. + + + + + + +The &LMB; draws in the foreground color. The &RMB; draws in the +background color. + + + +Color Picker <inlinemediaobject> +<imageobject> +<imagedata fileref="tool_color_picker.png" format="PNG"/> +</imageobject> +</inlinemediaobject> + + +To set the foreground color, left click on +a pixel. To set the background color, right click on a pixel. +&kolourpaint; will then return to the previously selected tool. + + + + +Connected Lines and Polygon +<inlinemediaobject> +<imageobject> +<imagedata fileref="tool_polystar.png" format="PNG"/> +</imageobject> +</inlinemediaobject> + + +Click and drag to draw connected lines. The polygon tool is used in +the same way, however, the start and end points are automatically connected +to form a polygon. + +The &LMB; draws in the foreground color. The &RMB; draws in the +background color, and will also reverse the fill color for polygons. + +You can set the line width. For +polygons, you can also set the fill +style. + + + + +Curve <inlinemediaobject> +<imageobject> +<imagedata fileref="tool_curve.png" format="PNG"/> +</imageobject> +</inlinemediaobject> + + +Click and drag to draw a line - this sets the start and end +points. You can set up to two control points by dragging. To finish the +curve without using both or any control points, click the other mouse +button. The curve tool draws a Cubic Bezier. + +The &LMB; draws in the foreground color. The &RMB; draws in the +background color. + +You can also set the line +width. + + + + +Ellipse <inlinemediaobject> +<imageobject> +<imagedata fileref="tool_ellipse.png" format="PNG"/> +</imageobject> +</inlinemediaobject> + + +Click and drag to draw an ellipse. + +The &LMB; draws in the foreground color. The &RMB; draws in the +background color, and will reverse the fill color. + +You can also set the line width and fill +style. + +For additional functionality, use the modifier keys: + + + +Hold &Shift; and drag to draw a circle. + + +To draw an ellipse with a center point of your choice, hold &Ctrl;, +click on the center point, and drag until the ellipse is the correct size +and shape. + + +To draw a circle with a center point of your choice, hold &Ctrl; and +&Shift;, click on the center point, and drag until the circle is the correct +size. + + + + + + +Erasers + + +Eraser +<inlinemediaobject> +<imageobject> +<imagedata fileref="tool_eraser.png" format="PNG"/> +</imageobject> +</inlinemediaobject> + + +Click and drag with the eraser to rub out mistakes. + + +Unlike other tools, the erasers draw in the background color. To draw +in the foreground color, use the &RMB;. + + +The eraser only has square +shapes. To draw with other shapes such as circles use the Brush and the &RMB;. + + +Double-click on the Eraser icon to clear the entire image. This is +equivalent to using the Clear option on +the Image menu. + + + + + +Color Eraser +<inlinemediaobject> +<imageobject> +<imagedata fileref="tool_color_washer.png" format="PNG"/> +</imageobject> +</inlinemediaobject> + + +Click and drag to replace pixels of the foreground color with the +background color. To replace all pixels similar (but not necessarily exactly +equal) to the foreground color, such as in dithered images and photos, use a +Color Similarity setting other than +Exact. + + +Unlike other tools, the erasers draw in the background color. To +replace pixels of the background color with the foreground color, use the +&RMB;. + + +You can configure the eraser +size. + + +Double-click on the Color Eraser icon to apply it to the entire image. + + + + + + +Flood Fill +<inlinemediaobject> +<imageobject> +<imagedata fileref="tool_flood_fill.png" format="PNG"/> +</imageobject> +</inlinemediaobject> + + +Click to fill a region. To fill a dithered region, use a Color Similarity setting other than Exact. + +The &LMB; fills in the foreground color. The &RMB; fills in the +background color. + + + + +Line +<inlinemediaobject> +<imageobject> +<imagedata fileref="tool_line.png" format="PNG"/> +</imageobject> +</inlinemediaobject> + + +Click and drag to draw a line. + +The &LMB; draws in the foreground color. The &RMB; draws in the +background color. + +You can also set the line +width. + + + + + + + + + + + + + + + + + + + + + +Hold &Ctrl; to draw lines angled at the nearest multiple of 30 degrees +- these are the lines in the red diagram. + + +Hold &Shift; to draw lines angled at the nearest multiple of 45 +degrees - these are the lines in the blue diagram. + + +Hold &Ctrl; and &Shift; to draw lines angled at the nearest multiple +of 30 or 45 degrees - these are the lines in the green diagram. + + + + + + +Pen +<inlinemediaobject> +<imageobject> +<imagedata fileref="tool_pen.png" format="PNG"/> +</imageobject> +</inlinemediaobject> + + +Click to draw a dot or click and drag to draw a freehand line. + +The &LMB; draws in the foreground color. The &RMB; draws in the +background color. + + + + +Rectangles +<inlinemediaobject> +<imageobject> +<imagedata fileref="tool_rectangles.png" format="PNG"/> +</imageobject> +</inlinemediaobject> + + +Click and drag to draw a rectangle. The Rounded Rectangle is a Rectangle with rounded +corners. + +The &LMB; draws in the foreground color. The &RMB; draws in the background color, +and will reverse the fill color. + +You can also set the line width and fill +style. + + For additional functionality, use the modifier keys: + + + +Hold &Shift; and drag to draw a square. + + +To draw a rectangle with a center point of your choice, hold &Ctrl;, +click on the center point, and drag until the rectangle is the correct size +and shape. + + +To draw a square with a center point of your choice, hold &Ctrl; and &Shift;, +click on the center point, and drag until the square is the correct size. + + + + + + +Selections +<inlinemediaobject> +<imageobject> +<imagedata fileref="tool_selections.png" format="PNG"/> +</imageobject> +</inlinemediaobject> + + +Use the selection tools to draw out the boundary of a +selection. + +To move the selection, click and drag on it. The main view will scroll as required to allow you to move the selection to part of the image that is not currently displayed. + + +You can free-form Resize the entire image or +Smooth Scale the selection using the corresponding handles. +Hold &Shift; while free-form scaling the selection to maintain aspect ratio. +The &RMB; invokes a context menu with common Edit commands and Image Effects. + + + +You can use the cursor keys while drawing out the boundary of the +selection or while moving it. + + + +If you hold &Ctrl; before moving the selection, then you will move a +copy of it. The selection will be smeared when moving it while &Shift; is held. + + + + + + + + + + + + + + +There are two selection modes: Opaque (default) and Transparent. If +you use the Transparent selection mode, all pixels of the background color +will be transparent (background subtraction). This allows you to paste a +selection without the background. To perform background subtraction on a +dithered image, use a Color Similarity +setting other than Exact. + + + + + + +You can apply Image Effects to a selection - see the Image Effects section for more +information. + + + +Spraycan +<inlinemediaobject> +<imageobject> +<imagedata fileref="tool_spraycan.png" format="PNG"/> +</imageobject> +</inlinemediaobject> + + +Click and drag to spray graffiti. Hold down the mouse button for a +more concentrated spray. + + + + + + + + + + + + + +Click on one of the shapes to select the spray size. You can select +from spray sizes of 9x9, 17x17 and 29x29. + + + + + + +The &LMB; draws in the foreground color. The &RMB; draws in the +background color. + + + + +Text +<inlinemediaobject> +<imageobject> +<imagedata fileref="tool_text.png" format="PNG"/> +</imageobject> +</inlinemediaobject> + + + +Click and drag an area in which to write text. Click and drag +on the border to move it. You can resize the text box by dragging on the +handles or by using the Resize dialog. + + + +If you have deselected a text box you can use Undo to edit the text +again. + + + +Using the Transparent Color + + + + + + + + +The left picture shows the example image. The right picture shows the addition of text +with opaque foreground and background colors. + + + + + + + + + + +The left picture shows the addition of text with opaque foreground +colors and a transparent background color. The right picture shows the +addition of text with a transparent foreground color and opaque background +color. + + + + +Common Tool Options + + + + + + + + + + + + + +Click on one of the squares to select the eraser size. You can select +from squares of side length 2, 3, 5, 9, 17 and 29 pixels. + +The eraser size setting affects the Erasers. + + + + + + + + + + + +Click on one of the lines to select the line width. You can select +from line widths of 1, 2, 3, 5 and 8 pixel(s). + +The line width setting affects the Connected Lines, Curve, Ellipse, Line, Polygon, Rectangle and Rounded Rectangle tools. + + + + + + + + + + + +Click on one of the rectangles to select the fill style. You can +select from No Fill, Fill with Background Color and Fill with Foreground +Color. The fill style setting affects the Ellipse, Polygon, Rectangle and Rounded Rectangle tools. + + + + + + + + + + + +Working with Color + + +The Color Box + + + + + + + +Color Box + + + + +The Color Box has 3 main sections: the Color Tablet, the Color Palette +and the Color Similarity Selector. + +The Color Tablet shows the current foreground color as a square on top +of another square representing the current background color. When drawing +with the &LMB;, the foreground color is used, and when drawing with the +&RMB; the background color is used (except for the Erasers). You can click on the double-ended +arrow to swap the foreground and background colors. + +The Color Palette shows a selection of colors for you to choose +from. The translucent pyramid represents the transparent color. Left-click +on a color to set the foreground color and right-click on a color to set the +background color. You can also drag and drop any opaque color into the Color +Tablet squares. To edit a color in the Color Tablet or Palette, double-click +on it. The Color Picker tool allows +you to select a color from the image. + +Color Similarity allows you to work more effectively with dithered +images and photos, in a comparable manner to the Magic Wand feature of other paint programs. It applies to transparent selections, as well as the +Flood Fill, Color Eraser and Autocrop / Remove Internal Border tools. Double-click on the Color +Similarity Selector to choose how similar colors must be to be considered +identical. When using selections in Transparent mode, any color in the +selection that is similar to the background color will also be made +transparent. + + + + + + + + + + +The left picture shows the example image. The right pictures demonstrate the use of a flood fill, with Color Similarity settings of 5%, 15% and 30%. In this example, with a Color Similarity setting of Exact, a flood fill at (80, 100) would only fill one pixel, as the surrounding pixels are similar but not identical. As Color Similarity is increased, more pixels that are similar in color are considered identical, hence the fill extends further. + + + + + + +View Options + + +View Options Reference + +Zoom incorporating the Grid +Thumbnail + + + + +Zoom incorporating the Grid +Increase the zoom level to edit images with more precision, or reduce it to see more of the image. + + + +At zoom levels that aren't multiples of 100%, parts of the image may appear to move when the user interacts with it. Other minor redraw glitches may also occur at such zoom levels. + + + +At zoom levels of 600% or greater that are also multiples of 100%, you can Show Grid to more accurately edit individual pixels. + + + + + + + + + + + + + + + +The first picture shows the Text tool icon, while the latter shows it at 600% zoom with the grid on. + + + +Another way of zooming when not drawing is to scroll the wheel while holding &Ctrl;. + + + + + + +Thumbnail + + + + + + + + +If Zoomed Thumbnail Mode is selected, the entire image is displayed, scaled as required to fit the thumbnail window (top-right picture). + + +Otherwise, the thumbnail displays as much of the image as possible, starting from the top-left of the main view (bottom-right picture). + + + + + + +Image Effects + + +Image Effects Reference +Autocrop / Remove Internal Border +Balance +Clear +Emboss +Flatten +Flip +Invert +Reduce Colors +Reduce to Grayscale +Reduce to Monochrome (Dithered) +Resize / Scale +Rotate +Set as Image (Crop) +Skew +Soften & Sharpen +More Effects +Notes + + + +Autocrop / Remove Internal Border + +This automatically removes the border of an image or selection. Use +Autocrop if you have a figure that does not fill the entire image or selection and you +wish to remove the excess whitespace. To use this feature with a dithered +image border, you will also need to use Color +Similarity. + + + + +Balance + + +This feature is accessible from the More Effects dialog. + + + + + + + + + +This allows you to set the brightness, contrast and gamma of the image or selection. + + + + +The more common measure of gamma (a decimal from 0.10 to 10.00) is located between the +Gamma spinbox and the Reset button. + + + + + +Clear + +This fills the entire image or selection with the background +color. + + +Double-click on the Eraser +icon to clear the entire image. + + + + + +Emboss + + +This feature is accessible from the More Effects dialog. + + + + + + + + + + +Check Enable to apply the Emboss effect. This emphasises the edges and gives the +image or selection an "engraved look". + + + + +Flatten + + +This feature is accessible from the More Effects dialog. + + + + + + + + + + +This recolors the image with varying shades of the two selected colors. + + + + +Flip + + + + + + + + + +This flips the entire image or selection horizontally or +vertically. + + + + +Invert + + +This feature is accessible from the More Effects dialog. + + + + + + + + + +This allows you to invert one or more RGB channels in the image or selection. Select All to change a photo into a negative and vice versa. This generally looks quite funny. + + +To quickly invert all channels, you do not need to use this dialog. You can instead +access the Invert Colors item in the Image or +Selection menu. + + + + + + +Reduce Colors + + +This feature is accessible from the More Effects dialog. + + + + + + + + + + +This reduces the number of colors used by the image or selection, with or without dithering. + + + +Dithering generally provides better quality results, however, you may wish to disable it for artistic effects; +e.g. using Monochrome instead of +Monochrome (Dithered) gives a silhouette effect. + + + +Another important distinction is that while Monochrome (Dithered) will always reduce the entire image or selection to black and white, Monochrome will do this only if the image or selection contains more than 2 colors. + + + +For a quick, dithered monochrome image or selection, use the Reduce to Monochrome (Dithered) item of the Image or Selection menu. + + + + + +Changing the number of colors here has no effect on the color depth of the file format. If you want to +change the color depth, you should select it in the file saving dialogs. Note that, confusingly, changing +the color depth also changes the number of colors. + + + + + +Reduce to Grayscale + + This reduces the entire image or selection to grayscale. + + + + +Reduce to Monochrome (Dithered) + +This reduces the entire image or selection to black and white. + + + +If you do not want the image or selection to be dithered, use the +Reduce Colors dialog. + + + + + +Resize / Scale + + + + + + + + + +Resizing the image changes the dimensions of the image without +applying a transformation to the existing contents. Scaling the image will +stretch the existing contents to the new dimensions. Smooth Scale +generally provides better quality results than Scaling, by blending neighbouring colors. + +You can express the new dimensions in pixels, or as a percentage of +the original size. If you select Keep aspect ratio, the +width and height will be scaled by the same percentage. + + + +You can free-form Resize the entire image or Smooth Scale the selection using the corresponding handles. + + + + +Only scaling is supported for selections, and only resizing is +supported for text boxes. See Notes for +additional details about applying these effects. + + + + +Rotate + + + + + + + + + +This rotates the image. You can specify the angle and direction of +rotation. + + +You can reverse the direction of rotation by specifying a negative +custom angle. + + + +See Notes for details about +applying this effect to a selection. + + + + + +Set as Image (Crop) + +This will set the selection as the image. + + +This is only available when you have an active selection. + + + + +Skew + + + + + + + + + +This skews the entire image or selection horizontally and/or +vertically. + + +See Notes for details about +applying this effect to a selection. + + + + +Soften & Sharpen + + +This feature is accessible from the More Effects dialog. + + + + + + + + + + +Use this effect to soften or sharpen the image. + + + + + +More Effects + + +This dialog contains the Balance, +Emboss, Flatten, +Invert, Reduce Colors +and Soften & Sharpen features. + + + + +Notes + +Resizing / Scaling, Rotating and Skewing may change the dimensions of the +image. You can view the new dimensions in the dialog. + +If you apply these effects to an image, the image will be resized if +necessary. However, if you apply these effects to a selection, the image +will not be resized, even if the transformed selection does not fit. + + + + + + + + + + +The left image has been rotated 30 degrees clockwise to form the right image. &kolourpaint; has +automatically enlarged the image to accommodate the larger contents. + + + + + + + + + + + +The left selection has been rotated 30 degrees clockwise to form the right +selection. The image size has remained the same, hence parts of the selection will not be visible +without Resizing the image. + + + + + + +Credits and License + +Carl Tucker + +It might not be concise documentation; it might not be complete documentation; but it is +honest documentation. + + + + +&kolourpaint; + +Program Copyright © 2003, 2004, 2005 &Clarence.Dang; &Clarence.Dang.mail; + + +&kolourpaint;-specific icons Copyright © 2004, 2005 +Kristof Borrey borrey@kde.org, +Nuno Pinheiro nf.pinheiro@gmail.com, +Danny Allen dannya40uk@yahoo.co.uk + + +Documentation and additional documentation artwork Copyright © 2004, 2005 +&Thurston.Dang; &Thurston.Dang.mail; + +Portions reproduced with permission from . + +&underFDL; + +This program is licensed as follows: + +Copyright © 2003, 2004, 2005 &Clarence.Dang; &Clarence.Dang.mail; + + +All rights reserved. + + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + + +Installation + +How to obtain &kolourpaint; + +&install.intro.documentation; + +More frequent releases with support for previous versions of &kde; are +available at http://kolourpaint.sourceforge.net/. + + + + +Requirements + + &kolourpaint; 1.4_relight requires &kde; 3.5. + + + +Compilation and Installation + + + +If you are reading this help in the &khelpcenter;, then &kolourpaint; has already been +installed on this system and you do not need to follow these generic instructions. + + + +&install.compile.documentation; + + + + +Configuration + +&kolourpaint; should run without any additional configuration. + + + + +&documentation.index; + + + diff --git a/doc/kolourpaint/kolourpaint-main.png b/doc/kolourpaint/kolourpaint-main.png new file mode 100644 index 00000000..abab73d8 Binary files /dev/null and b/doc/kolourpaint/kolourpaint-main.png differ diff --git a/doc/kolourpaint/line_width.png b/doc/kolourpaint/line_width.png new file mode 100644 index 00000000..0477b6e1 Binary files /dev/null and b/doc/kolourpaint/line_width.png differ diff --git a/doc/kolourpaint/lines_30_45_deg.png b/doc/kolourpaint/lines_30_45_deg.png new file mode 100644 index 00000000..315499e5 Binary files /dev/null and b/doc/kolourpaint/lines_30_45_deg.png differ diff --git a/doc/kolourpaint/lines_30_deg.png b/doc/kolourpaint/lines_30_deg.png new file mode 100644 index 00000000..9519df52 Binary files /dev/null and b/doc/kolourpaint/lines_30_deg.png differ diff --git a/doc/kolourpaint/lines_45_deg.png b/doc/kolourpaint/lines_45_deg.png new file mode 100644 index 00000000..870cd464 Binary files /dev/null and b/doc/kolourpaint/lines_45_deg.png differ diff --git a/doc/kolourpaint/rotate_image_30.png b/doc/kolourpaint/rotate_image_30.png new file mode 100644 index 00000000..ebf00431 Binary files /dev/null and b/doc/kolourpaint/rotate_image_30.png differ diff --git a/doc/kolourpaint/rotate_selection_30.png b/doc/kolourpaint/rotate_selection_30.png new file mode 100644 index 00000000..23567ef8 Binary files /dev/null and b/doc/kolourpaint/rotate_selection_30.png differ diff --git a/doc/kolourpaint/selections_opaque_transparent.png b/doc/kolourpaint/selections_opaque_transparent.png new file mode 100644 index 00000000..627e5fee Binary files /dev/null and b/doc/kolourpaint/selections_opaque_transparent.png differ diff --git a/doc/kolourpaint/spraycan_patterns.png b/doc/kolourpaint/spraycan_patterns.png new file mode 100644 index 00000000..6505311a Binary files /dev/null and b/doc/kolourpaint/spraycan_patterns.png differ diff --git a/doc/kolourpaint/text_zoom_grid.png b/doc/kolourpaint/text_zoom_grid.png new file mode 100644 index 00000000..4fa85435 Binary files /dev/null and b/doc/kolourpaint/text_zoom_grid.png differ diff --git a/doc/kolourpaint/tool_brush.png b/doc/kolourpaint/tool_brush.png new file mode 100644 index 00000000..32a23881 Binary files /dev/null and b/doc/kolourpaint/tool_brush.png differ diff --git a/doc/kolourpaint/tool_color_picker.png b/doc/kolourpaint/tool_color_picker.png new file mode 100644 index 00000000..569171e6 Binary files /dev/null and b/doc/kolourpaint/tool_color_picker.png differ diff --git a/doc/kolourpaint/tool_color_washer.png b/doc/kolourpaint/tool_color_washer.png new file mode 100644 index 00000000..97193458 Binary files /dev/null and b/doc/kolourpaint/tool_color_washer.png differ diff --git a/doc/kolourpaint/tool_curve.png b/doc/kolourpaint/tool_curve.png new file mode 100644 index 00000000..b86c96fb Binary files /dev/null and b/doc/kolourpaint/tool_curve.png differ diff --git a/doc/kolourpaint/tool_ellipse.png b/doc/kolourpaint/tool_ellipse.png new file mode 100644 index 00000000..608d40b7 Binary files /dev/null and b/doc/kolourpaint/tool_ellipse.png differ diff --git a/doc/kolourpaint/tool_elliptical_selection.png b/doc/kolourpaint/tool_elliptical_selection.png new file mode 100644 index 00000000..70edc438 Binary files /dev/null and b/doc/kolourpaint/tool_elliptical_selection.png differ diff --git a/doc/kolourpaint/tool_eraser.png b/doc/kolourpaint/tool_eraser.png new file mode 100644 index 00000000..459d28a2 Binary files /dev/null and b/doc/kolourpaint/tool_eraser.png differ diff --git a/doc/kolourpaint/tool_flood_fill.png b/doc/kolourpaint/tool_flood_fill.png new file mode 100644 index 00000000..746ede5b Binary files /dev/null and b/doc/kolourpaint/tool_flood_fill.png differ diff --git a/doc/kolourpaint/tool_free_form_selection.png b/doc/kolourpaint/tool_free_form_selection.png new file mode 100644 index 00000000..ed03ba39 Binary files /dev/null and b/doc/kolourpaint/tool_free_form_selection.png differ diff --git a/doc/kolourpaint/tool_line.png b/doc/kolourpaint/tool_line.png new file mode 100644 index 00000000..ce282923 Binary files /dev/null and b/doc/kolourpaint/tool_line.png differ diff --git a/doc/kolourpaint/tool_pen.png b/doc/kolourpaint/tool_pen.png new file mode 100644 index 00000000..ae64f5aa Binary files /dev/null and b/doc/kolourpaint/tool_pen.png differ diff --git a/doc/kolourpaint/tool_polygon.png b/doc/kolourpaint/tool_polygon.png new file mode 100644 index 00000000..a5500d94 Binary files /dev/null and b/doc/kolourpaint/tool_polygon.png differ diff --git a/doc/kolourpaint/tool_polyline.png b/doc/kolourpaint/tool_polyline.png new file mode 100644 index 00000000..1e23ccd9 Binary files /dev/null and b/doc/kolourpaint/tool_polyline.png differ diff --git a/doc/kolourpaint/tool_polystar.png b/doc/kolourpaint/tool_polystar.png new file mode 100644 index 00000000..8eadbcad Binary files /dev/null and b/doc/kolourpaint/tool_polystar.png differ diff --git a/doc/kolourpaint/tool_rect_selection.png b/doc/kolourpaint/tool_rect_selection.png new file mode 100644 index 00000000..a85ef3f8 Binary files /dev/null and b/doc/kolourpaint/tool_rect_selection.png differ diff --git a/doc/kolourpaint/tool_rectangle.png b/doc/kolourpaint/tool_rectangle.png new file mode 100644 index 00000000..a8455de0 Binary files /dev/null and b/doc/kolourpaint/tool_rectangle.png differ diff --git a/doc/kolourpaint/tool_rectangles.png b/doc/kolourpaint/tool_rectangles.png new file mode 100644 index 00000000..851faf71 Binary files /dev/null and b/doc/kolourpaint/tool_rectangles.png differ diff --git a/doc/kolourpaint/tool_rounded_rectangle.png b/doc/kolourpaint/tool_rounded_rectangle.png new file mode 100644 index 00000000..4b5a0617 Binary files /dev/null and b/doc/kolourpaint/tool_rounded_rectangle.png differ diff --git a/doc/kolourpaint/tool_selections.png b/doc/kolourpaint/tool_selections.png new file mode 100644 index 00000000..1b0d09bf Binary files /dev/null and b/doc/kolourpaint/tool_selections.png differ diff --git a/doc/kolourpaint/tool_spraycan.png b/doc/kolourpaint/tool_spraycan.png new file mode 100644 index 00000000..75b7f748 Binary files /dev/null and b/doc/kolourpaint/tool_spraycan.png differ diff --git a/doc/kolourpaint/tool_text.png b/doc/kolourpaint/tool_text.png new file mode 100644 index 00000000..ffaab637 Binary files /dev/null and b/doc/kolourpaint/tool_text.png differ diff --git a/doc/kolourpaint/view_thumbnails.png b/doc/kolourpaint/view_thumbnails.png new file mode 100644 index 00000000..069a0888 Binary files /dev/null and b/doc/kolourpaint/view_thumbnails.png differ diff --git a/doc/kooka/Makefile.am b/doc/kooka/Makefile.am new file mode 100644 index 00000000..085981d9 --- /dev/null +++ b/doc/kooka/Makefile.am @@ -0,0 +1,4 @@ + +KDE_LANG = en +KDE_DOCS = AUTO + diff --git a/doc/kooka/index.docbook b/doc/kooka/index.docbook new file mode 100644 index 00000000..c0140d7e --- /dev/null +++ b/doc/kooka/index.docbook @@ -0,0 +1,747 @@ + + + + + +]> + + + + +The &kooka; Manual + + + Martin +Sommer +
msommer@suse.de
+
+ +Klaas +Freitag + +
freitag@suse.de
+
+Developer +
+ + + +
+ + +2002 +Klaas Freitag, Martin Sommer + + +&FDLNotice; + +2002-02-04 +0.33.00 + +&kooka; is a very useful &kde; scanning +application. + + + +KDE +Scanner + + +
+ + +Introduction + +&kooka; is a &kde; application that enables easy scanning using +SANE libraries. Therefore,SANE +the package must be installed to use &kooka;. Clear and concise use +was the focus of its development. + +Character recognition is also provided by the built-in text +recognition program gocr. Install gocr to +use this functionality. After character recognition is complete, the +recognized material can be opened in the text editor &kate; with just +one click, where you can edit the contents. + + + + +Application Instructions + +The web site http://www.sane-project.org +has information about supported scanners. Refer to it before +purchasing a scanner, if possible. + + +The &kooka; Main Window + + +The &kooka; Main Window + + + + + + + +Start &kooka; from a console by simply entering +kooka. Create a link on the +&kde; desktop, which uses a scanner icon, if desired. + +The main window in &kooka; consists of three frames. At the top, +see both icon and a menu panels. Use the mouse to enlarge or reduce +the windows as needed. + + + +The navigation window consists of two tabs, which allow you to +switch between the Preview and the integrated +file browser called the Gallery. The working +folder is displayed in the lower part of the window along with the +folder where the scan will be saved. + + + +Make your scanner-dependent settings, which are dependent on the +scanner you have connected, in the lower left window. Usually, these +are settings for resolution, brightness and contrast, scanning mode +(⪚, color, gray, or binary), and for gamma values. + +Configure your settings here first. Afterwards, initiate the +preview scan with Preview. If the +Preview tab in the upper window is selected, see +the results there. + +Select the various formats in the preview image itself to define +the final dimensions. The User setting is +recommended for this, so you select the area to scan in the preview +display with the mouse. + +After this is done, click Scan to scan the +selection made in the preview. After scanning, you will be asked in +which format to save the image whether to make this your standard +format (without being prompted to confirm your selection in the +future). + +If you checked that you do not want to be asked about the +save format, the memory assistant will no longer appear. To change the +format some time in the future, select +Settings Configure +Kooka... Save Image +Always show memory assistant + + + + +The large window shows how the image appears after a final +scan. + + + + + + + + +Command References + + +The main &kooka; Toolbar + + + +The <guimenu>File</guimenu> Menu + + + + + + +&Ctrl;P + +File +Print + + +Prints the displayed image. + + + + + + +File +Create Folder... + + +Create a folder to hold your images. + + + + + + +File +Save Image + + +Save the image selected underneath the +Kooka Gallery. +See the Save +section for details. + + + + + + +File +Delete Image + + +Delete the image selected underneath the +Kooka Gallery. + + + + + + +File +Unload Image + + +Remove the image displayed in the Image +Viewer. + + + + + + + + +&Ctrl;Q + +File +Quit + + +Quit &kooka;. + + + + + + + +The <guimenu>Image</guimenu> Menu + + + + + + +&Ctrl;G + +Image +Open image in graphic application + + +Enter a graphics application for opening your scanned image +directly. Recommended applications include The +GIMP. + + + + + + +&Ctrl;O + +Image +OCR image... + + +Start the window for optical character recognition +(OCR). If you have gocr +installed, then the path to it should be in the path line. This +starts the character recognition for the preview image or for the +highlighted area. + + + + + + +&Ctrl;C + +Image +OCR on selection... + + +A window will reappear for the character recognition. Here, +however, the character recognition is only for the area highlighted in +the final scan. + + + + + + + +&Ctrl;I + +Image +Scale to Width + + +This proportionally scales the image in the large canvas to the +width of the display. + + + + + + +&Ctrl;H + +Image +Scale to Height + + +Proportionately scales the image to the height of the +display. + + + + + + +&Ctrl;S + +Image +Original Size + + +Restores the original scan size by reducing or enlarging the +image in the display. + +There are additional methods of scaling an image: +right click the image display. Redefine the +three named options and set the enlargement itself. This can also be +done in the Preview window. + + + + + + +&Ctrl;N + +Image +Create from selection + + +If the scanned image includes more than you want to appear in the final +image, use this tool to crop your image by marking your selection in +the larger image display to the right then selecting this tool. The +image is cropped according to your selection. You may already be +familiar with this function from The GIMP +crop tool. + + + + + + +&Ctrl;V + +Image +Mirror image vertically + + +Flip image vertically. + + + + + +&Ctrl;M + +Image +Mirror image horizontally + + + +Flip image horizontally. + + + + + +&Ctrl;B + +Image +Mirror both directions + + +Flip image both horizontally and vertically. + + + + + + +&Ctrl;R + +Image +Rotate image clockwise + + +Rotate the image ninety degrees clockwise. + + + + + + +&Ctrl;W + +Image +Rotate image counter-clockwise + + + +Rotate the image ninety degrees counterclockwise. + + + + + + +&Ctrl;D + +Image +Rotate image 180 degrees + + + +Rotates image 180 degrees. + + + + + + +The <guimenu>Settings</guimenu> Menu + + + + + +Settings +Show Toolbar + + + +Removes the top toolbar to give additional viewing area. + + + + + + +Settings +Show Statusbar + + + +Removes the bottom statusbar to give additional viewing area. + + + + + + +Configuring Shortcuts + +The +SettingsConfigure Shortcuts... +allows you to specify key bindings + + +Below is an example of how to configure a short cut for deleting +an image. + + +Picture of shortcut dialog + + + + + + + + + +Click on the custom button. + + + +Next click on the primary button. + + + +Do CTRLX +and the dialog should disappear. The keybinding is now entered. + + + + +Picture of keybinding dialog + + + + + + + +Pressing the keys CTRLX +now deletes the image selected underneath Kooka Gallery. + + + + +Configuring Toolbars +The +SettingsConfigure Toolbars... +Is used to add additional buttons to the toolbars. + + +Picture of toolbars dialog + + + + + + + + + + + +To add a button to the File toolbar, + + + +Picture of toolbars dialog + + + + + + + + make sure Main Toolbar is displayed in +the top combo box. + + + +Click on one of the items in the left hand pane. This item will now have a +blue background showing that it has been selected. + + + +Next click on the Right arrow button to place it in +the right pane. + + + +Click on Apply and then +click on OK + + + + +The new Item should be in the toolbar. + +Picture of toolbars dialog + + + + + + + + + + +Configuring Kooka +The +SettingsConfigure Kooka... + + + + + + + + +Kooka Startup Preferences + + + +You may want to uncheck Show the scanner selection box +on next startup, if you have only one scanner. If you +have only one computer you may also want to uncheck +Query network for available scanners. + + + + + + + +Thumbnail View + + + +Here the size and the shading of the thumbnails can be adjusted; +as well as the background. For example, you might want to reduce the +size of the thumbnails if you are scanning many pages from a book. + + + + + + + + + + + + + +Save +More on Saving Images + +The method for saving an image is somewhat different in &kooka; +than in many other applications. Click the +Gallery tab to open a small file browser. This is +the folder ~/.kde/share/apps/ScanImages/ In the +lower portion of the window, your current subfolder in the gallery +is shown. This is where all scanned images are first saved as +files. When starting &kooka; for the first time, you will only see the +ScanImages. Create +subfolders by right clicking this +folder. The selected folder, highlighted in blue, is the first save +location of the scanned images. The scans are labeled in ascending +numerical order as in kscan_0001 and +kscan_0002. + +To save an image permanently, left +click the name. Next, give a new name and the appropriate ending for +the image format chosen when scanning. If you enter a different +extension, you will get a message that it does not correspond to the +scanned format. Although you can still save the image under this name, +it will retain its original format. At present, +On-the-fly conversion is not offered.If you do not want to use this method of managing your images +in ~/.kde/share/apps/ScanImages/, you can, +of course, save them to another location. To do this, +right click the +image name and select Save. Choose any path +here. In addition, close or permanently delete images here. + +To incorporate other images in the gallery, add them in +&konqueror; by dragging and dropping. Open &konqueror; to the +folder containing the desired images. Then add them to the &kooka; +gallery by dragging them and dropping them into the gallery. + + + + +Character Recognition + +As already mentioned, the gocr must +be installed. Scan a preview of your document in grayscale or +color. You can only scan in binary mode if you have a pure white sheet +of paper with black print. Next, highlight the text to be recognized +in the preview window. Then, do your final scan in binary mode with +Scan. + +Now click the second icon from the left, + + + , + in the icon panel, +OCR on Selection..., or select +this item in the Image menu. For your +first try, do not change the default settings shown in the emerging +OCR window. These are usually appropriate and meet +most needs. Now click Start character +recognition. You will now see a window containing the +OCR results. The quality depends heavily on that of +the document itself. + + The gocr Window + + +The text can now be opened by clicking the button with the +&kate; editor. After the final scan, mark a selection in the image +display to the right to load just a part of the text or image to the +OCR. Next, in the icon panel, click the third +button from the right or click in the menu on +OCR on selection. Now +proceed as described in the previous section. + + +The Results of the OCR + + + + + + + + + +Credits and License + +&kooka; + + Copyright for the application 2001-2002 Klaas Freitag +freitag@suse.de + +Copyright for the documentation 2002 Martin Sommer +msommer@suse.de + + + +&underFDL; +&underGPL; + + + + +Installation + +&install.intro.documentation; + +&install.compile.documentation; + + + +
+ diff --git a/doc/kooka/kooka_gocr.png b/doc/kooka/kooka_gocr.png new file mode 100644 index 00000000..ab94f75e Binary files /dev/null and b/doc/kooka/kooka_gocr.png differ diff --git a/doc/kooka/kooka_gocr_result.png b/doc/kooka/kooka_gocr_result.png new file mode 100644 index 00000000..e96bbbed Binary files /dev/null and b/doc/kooka/kooka_gocr_result.png differ diff --git a/doc/kooka/kooka_mainctrl.png b/doc/kooka/kooka_mainctrl.png new file mode 100644 index 00000000..1e727089 Binary files /dev/null and b/doc/kooka/kooka_mainctrl.png differ diff --git a/doc/kooka/ocr-select.png b/doc/kooka/ocr-select.png new file mode 100644 index 00000000..db076898 Binary files /dev/null and b/doc/kooka/ocr-select.png differ diff --git a/doc/kooka/shortcut0.png b/doc/kooka/shortcut0.png new file mode 100644 index 00000000..0e2eff1f Binary files /dev/null and b/doc/kooka/shortcut0.png differ diff --git a/doc/kooka/shortcut1.png b/doc/kooka/shortcut1.png new file mode 100644 index 00000000..e93bc9b8 Binary files /dev/null and b/doc/kooka/shortcut1.png differ diff --git a/doc/kooka/toolbar.png b/doc/kooka/toolbar.png new file mode 100644 index 00000000..56675b0b Binary files /dev/null and b/doc/kooka/toolbar.png differ diff --git a/doc/kooka/toolbar1.png b/doc/kooka/toolbar1.png new file mode 100644 index 00000000..a446a475 Binary files /dev/null and b/doc/kooka/toolbar1.png differ diff --git a/doc/kooka/toolbar2.png b/doc/kooka/toolbar2.png new file mode 100644 index 00000000..5ec2f725 Binary files /dev/null and b/doc/kooka/toolbar2.png differ diff --git a/doc/kpdf/Makefile.am b/doc/kpdf/Makefile.am new file mode 100644 index 00000000..085981d9 --- /dev/null +++ b/doc/kpdf/Makefile.am @@ -0,0 +1,4 @@ + +KDE_LANG = en +KDE_DOCS = AUTO + diff --git a/doc/kpdf/configure.png b/doc/kpdf/configure.png new file mode 100644 index 00000000..bbe89d9f Binary files /dev/null and b/doc/kpdf/configure.png differ diff --git a/doc/kpdf/index.docbook b/doc/kpdf/index.docbook new file mode 100644 index 00000000..7da3ab5f --- /dev/null +++ b/doc/kpdf/index.docbook @@ -0,0 +1,932 @@ + +KPDF"> + + + + +]> + + + + The &kpdf; Handbook + + + Albert + Astals Cid + +
tsdgeos@yahoo.es
+
+
+ + Titus + Laska + +
titus.laska@gmx.de
+
+
+ +
+ &FDLNotice; + 2006-05-20 + 0.5 + + + &kpdf; is a &kde; PDF viewer based on xpdf code. + + + KDE + kpdf + pdf + +
+ + Introduction + &kpdf; is a &kde; PDF (Portable Document Format) viewer + based on the code of the xpdf application. Although being based on xpdf code, &kpdf; + has some unique features such as continuous mode and presentation support. + + + The PDF format is widely used for publishing documents that are + mostly not meant to be edited again. &kpdf; is only a viewer + for these files and therefore it doesn't provide any functionality + to edit or create PDF documents. + + + + Using &kpdf; + + Opening Files + + To view a PDF file in &kpdf;, select FileOpen... + , choose a PDF or PS file in the dialogue and click Open. + Your file should now be displayed in the main window. + + + If you have already opened files in &kpdf; before, you can quickly access them by selecting them in + the FileOpen Recent menu. + + + After having a file opened you probably want to read it and therefore navigate through it. Click + Next to learn more about this. + + + + Navigating + This section describes how you can navigate through a document in &kpdf;. + + There are multiple ways of scrolling the viewing area. One is to use the + Up Arrow and Down Arrow keys. You may also use + the scrollbar, your mousewheel or the Page Up and Page Down + keys. + + + Another way is to hold the &LMB; down at any place on the document while dragging the mouse in the + opposite direction of where you want to move. This procedure only works if the Browse Tool is + enabled, which you can select by choosing ToolsBrowse Tool + . + + + The navigation panel on the left side of the screen enables two more ways of navigating + through a document: + + + + + If you click on a page thumbnail the viewing area will be brought to + that page. + + + + + If the document has a table of contents, clicking on a table + of contents item will bring the document to to the page linked to that + item. + + + + + Some documents have links. In this case you can click on them and the view will + change to the page it links to. If the link is to a web page the default + browser will be invoked. + + + Additionally, you may use the following functionality to quickly move to specific places + in the document: + + + + + You can go to the first page of the document using + &Ctrl;Home or + using + + Go + First Page + . + + + + + You can go to the last page of the document using + &Ctrl;End or + using + + Go + Last Page + . + + + + + You can go to the next page of the document using + Space, the Next Page Toolbar + button or using + + Go + Next Page + . + + + + + You can go to the previous page of the document using + Backspace, the Previous Page Toolbar + button or using + + Go + Previous Page + . + + + + + + Presentation Mode + + The Presentation mode represents another way to view PDF documents in &kpdf;. It can be + enabled in + ViewPresentation. + It shows the document on a page per page basis. The pages are shown with + zoom to page, that means all the page is visible. + + + + PDF documents can even specify that they are always opened in presentation mode. + + + + To navigate between + pages you may use the &LMB; (next page) and the &RMB; (previous page), the mouse + wheel, the arrow icons that appear as soon as you move the mouse cursor to the top of the screen, + or the keys specified in the Navigating + section. + + + You can exit presentation mode at any time by pressing the ESC key or clicking + the Quit icon appearing if you move the mouse cursor to the top of the + screen. + + + Presentation mode has some configuration options, you can find their + description at Configuring &kpdf;. + + + + + + The Menubar + + + The <guimenu>File</guimenu> Menu + + + + + + &Ctrl;O + + File + Open... + + + + + Open a PDF or PS file. If there is already an opened file it will be closed. + For more information, see the section about Opening Files. + + + + + + + + File + Open Recent + + + + + Open a file which was used previously from a + submenu. If a file is currently being displayed it + will be closed. For more information, see the section about + Opening Files. + + + + + + + + File + Save As... + + + + Save the currently open file under a different name. + + + + + + + &Ctrl;P + File + Print... + + + + + Print the currently displayed document. + + + + + + + + File + Print Preview... + + + + + Show a preview of how the currently displayed + document would be printed with the default options. + + + + + + + + File + Properties + + + + Display some basic information about the document, such as + title, author, creation date, and details about the fonts used. + + + + + + + &Ctrl; Q + File + Quit + + + + Close &kpdf;. + + + + + + + The <guimenu>Edit</guimenu> Menu + + + + + &Ctrl; F + Edit + Find... + + + + Open a dialogue that allows you to search for a string in + the document. + + + + + + + F3 + Edit + Find Next + + + + Try to find the previous searched string again in the document. + + + + + + + The <guimenu>View</guimenu> Menu + + + + + &Ctrl;&Shift;P + View + Presentation + + + + Activates the Presentation Mode. For more information, see the + section about Presentation Mode. + + + + + + &Ctrl;+ + View + Zoom In + + + + Increase the magnification of the document view. + + + + + + + &Ctrl;- + View + Zoom Out + + + + Decrease the magnification of the document view. + + + + + + View + Fit to Page Width + + + + Change the magnification of the document + view to a value that makes the pages' width equal to the document + view's width. + + + + + + View + Fit to Page + + + + Change the magnification of the document view + to a value that makes at least one whole page visible. + + + + + + View + Continuous + + + + Enable the continuous page mode. In continuous mode, + all pages of the document are shown, and you can scroll through + them without having to use the Go + Previous Page and + GoNext Page + options. + + + + + + View + Two Pages + + + + Enable the two page mode, which shows two pages of + the document next to each other.. + + + + + + + The <guimenu>Go</guimenu> Menu + + + + + Backspace + Go + Previous Page + + + + View the previous page of the document. + + + + + + Space + Go + Next Page + + + + View the next page of the document. + + + + + + &Ctrl; Home + Go + First Page + + + + Go to the first page of the document. + + + + + + &Ctrl; End + Go + Last Page + + + + Go to the last page of the document. + + + + + + &Alt; Left + Go + Back + + + + Go back to the previous view of the document. + + + + + + &Alt;Right + Go + Forward + + + + Move forward to the next view of the document. This only works if you have already moved back before. + + + + + + &Ctrl;G + Go + Go to Page + + + + Open a dialog which allows you to go to any page of the document. + + + + + + + The <guimenu>Tools</guimenu> Menu + + + + + Tools + Browse Tool + + + + The mouse will have its normal behaviour, &LMB; for dragging the document and following links and &RMB; for adding bookmarks and fit to width. + + + + + + Tools + Zoom Tool + + + + The mouse will work as a zoom tool. Clicking &LMB; and dragging will zoom the view to the selected area, clicking &RMB; will bring the document back to the previous zoom. + + + + + + Tools + Select Tool + + + + The mouse will work as a select tool. In that mode clicking &LMB; and dragging will give the option of copying the text/image of current the selected area to the clipboard, speak a text or to save an image to a file. + + + + + + + The <guimenu>Settings</guimenu> Menu + + + + + &Ctrl;M + Settings + Show/Hide Menubar + + + + Toggle the Menubar display on and off. Once + hidden it can be made visible using the &RMB; menu. + + + + + + Settings + Show/Hide Toolbar + + + + Toggle the Toolbar display on and off. + + + + + + &Ctrl;L + Settings + Show/Hide Navigation Panel + + + + Toggle the navigation panel on and off. + + + + + + &Ctrl;&Shift;F + Settings + Full Screen Mode + + + + Enables the full screen mode. Note that + full screen mode is different from presentation mode insofar as the + only peculiarity of full screen mode is that it hides the window + decorations, the menubar and the toolbar. + + + + + + Settings + Configure Shortcuts... + + + + Opens a window that lets you configure the keyboard + shortcuts for many menu commands. + + + + + + Settings + Configure Toolbars... + + + + Opens a window that lets you choose which icons are visible + in the toolbar. + + + + + + Settings + Configure &kpdf;... + + + + Opens the Configure + window. + + + + + + + The <guimenu>Help</guimenu> Menu + &help.menu.documentation; + + + + + Configuring &kpdf; + + Overview + + You can configure &kpdf; by choosing Settings + Configure &kpdf;.... + The configuration dialogue is split into four sections. This chapter describes the available + options in detail. + + + + General + + + Accessibility + + + Performance + + + Presentation + + + + The configuration dialogue + + + + + + The configuration dialogue + + + + + + General + + + Show search bar in thumbnails list + + Whether to the show a search bar in the thumbnails view or not. That + search bar is useful for filtering pages that contain a given + string. + + + + Link thumbnails list with the page + + Whether the thumbnails view should always display the current + page or not. + + + + Show scrollbars + + Whether to show scrollbars for the document view. + + + + Show hints and info messages + + Whether to show some informative messages on startup, file + load, etc. + + + + Obey DRM limitations + + Whether &kpdf; should obey DRM (Digital Rights Management) restrictions. DRM limitations are used to make it impossible to perform certain actions with PDF documents, such as copying content to the clipboard. Note that in some configurations of &kpdf;, this option is not available. + + + + Watch file + + Whether opened files should be automatically checked for + changes and updated, if necessary. + + + + + + Accessibility + + + Draw border around images + + Whether to draw a border around images. + + + + Draw border around links + + Whether to draw a border around links. + + + + Change colors + + Enables the color changing options. + + + + Invert colors + + Inverts colors on the view, &ie; black objects will be shown white. + + + + Change paper color + + Changes the paper's color, &ie; the document's background. + + + + Change dark and light colors + + Changes the dark and light color to your preference, that means + black will not be rendered as black but as the selected dark color and white + will not be rendered as white but as the selected light color. + + + + Convert to black and white + + Converts the document to black and white. You can set the + threshold and the contrast. Setting the threshold to a higher value + will result in darker grays used. + + + + + + Performance + + + Enable transparency effects + + Draw selections and other special graphics using + transparency effects. Disable the option to draw them using + outline or opaque fill styles and increase speed on selections. + + + + Enable background generation + + Use a background thread to generate the pages. By disabling + this option the user interface will become less reactive (will be blocked + if necessary), but pages will be displayed a bit faster. + + + + Memory usage profiles + + &kpdf; can achieve best performance by tuning the memory usage, based on your system and your tastes. + The more memory you let it to use, the faster the program will behave. The Default profile is good + for every system, but you can prevent &kpdf; from using more memory than necessary by selecting the Low + profile, or let it get the most out of your system using Aggressive. + + + + + + Presentation + + + Advance every + + Enables automatic advancing of pages given a time period. + + + + Loop after last page + + When navigating on presentation mode and going past the last page the first page will appear. + + + + Background color + + The color that will fill the part of the screen not covered by the page when on presentation mode. + + + + Default transition + + The transition effect between page and page if the document does not specify one. Set this to Random + Transition to make &kpdf; randomly choose one of the available effects. + + + + Mouse cursor + + Whether the mouse should be always hidden, always shown or hidden after a small time of inactivity. + + + + Show progress indicator + + Whether to show a progress circle that shows the current page and the total number of pages on the upper + right corner of the presentation screen everytime you change the page. + + + + Show summary page + + Whether to show a summary page at the beginning of the presentation with the title, author and number of pages of the document. + + + + + + + Credits and License + + + Program Copyright: + Albert Astals Cidtsdgeos@yahoo.es Current maintainer + Christophe Devrieseoelewapperke@ulyssis.org + &Wilco.Greven; &Wilco.Greven.mail; Original author + Enrico Roseros.kde@email.it Refactoring for 3.4 + Laurent Montelmontel@kde.org + + + + Documentation Copyright: + Albert Astals Cidtsdgeos@yahoo.es Author + Titus Laskatitus.laska@gmx.de Some updates and additions + + + &underFDL; + &underGPL; + + + + Installation + + How to obtain &kpdf; + &install.intro.documentation; + + + Compilation and Installation + + + If you are reading this help in the &khelpcenter;, &kpdf; has already been + installed on this system and you do not need install it anymore. + + + &install.compile.documentation; + + + &documentation.index; +
+ + + diff --git a/doc/kpovmodeler/Makefile.am b/doc/kpovmodeler/Makefile.am new file mode 100644 index 00000000..085981d9 --- /dev/null +++ b/doc/kpovmodeler/Makefile.am @@ -0,0 +1,4 @@ + +KDE_LANG = en +KDE_DOCS = AUTO + diff --git a/doc/kpovmodeler/cameraview.png b/doc/kpovmodeler/cameraview.png new file mode 100644 index 00000000..0003ea84 Binary files /dev/null and b/doc/kpovmodeler/cameraview.png differ diff --git a/doc/kpovmodeler/controlpoints.png b/doc/kpovmodeler/controlpoints.png new file mode 100644 index 00000000..88cd490d Binary files /dev/null and b/doc/kpovmodeler/controlpoints.png differ diff --git a/doc/kpovmodeler/cr22-action-pmcamera.png b/doc/kpovmodeler/cr22-action-pmcamera.png new file mode 100644 index 00000000..51e3079a Binary files /dev/null and b/doc/kpovmodeler/cr22-action-pmcamera.png differ diff --git a/doc/kpovmodeler/cr22-action-pmcolorlist.png b/doc/kpovmodeler/cr22-action-pmcolorlist.png new file mode 100644 index 00000000..b94946d3 Binary files /dev/null and b/doc/kpovmodeler/cr22-action-pmcolorlist.png differ diff --git a/doc/kpovmodeler/cr22-action-pmfinish.png b/doc/kpovmodeler/cr22-action-pmfinish.png new file mode 100644 index 00000000..070f16d1 Binary files /dev/null and b/doc/kpovmodeler/cr22-action-pmfinish.png differ diff --git a/doc/kpovmodeler/cr22-action-pminterior.png b/doc/kpovmodeler/cr22-action-pminterior.png new file mode 100644 index 00000000..d3c3a66f Binary files /dev/null and b/doc/kpovmodeler/cr22-action-pminterior.png differ diff --git a/doc/kpovmodeler/cr22-action-pmlight.png b/doc/kpovmodeler/cr22-action-pmlight.png new file mode 100644 index 00000000..ebb36242 Binary files /dev/null and b/doc/kpovmodeler/cr22-action-pmlight.png differ diff --git a/doc/kpovmodeler/cr22-action-pmpigment.png b/doc/kpovmodeler/cr22-action-pmpigment.png new file mode 100644 index 00000000..6a2103d0 Binary files /dev/null and b/doc/kpovmodeler/cr22-action-pmpigment.png differ diff --git a/doc/kpovmodeler/cr22-action-pmplane.png b/doc/kpovmodeler/cr22-action-pmplane.png new file mode 100644 index 00000000..f5430a72 Binary files /dev/null and b/doc/kpovmodeler/cr22-action-pmplane.png differ diff --git a/doc/kpovmodeler/cr22-action-pmrender.png b/doc/kpovmodeler/cr22-action-pmrender.png new file mode 100644 index 00000000..6aa2b69f Binary files /dev/null and b/doc/kpovmodeler/cr22-action-pmrender.png differ diff --git a/doc/kpovmodeler/cr22-action-pmsolidcolor.png b/doc/kpovmodeler/cr22-action-pmsolidcolor.png new file mode 100644 index 00000000..e8cbfc51 Binary files /dev/null and b/doc/kpovmodeler/cr22-action-pmsolidcolor.png differ diff --git a/doc/kpovmodeler/cr22-action-pmsphere.png b/doc/kpovmodeler/cr22-action-pmsphere.png new file mode 100644 index 00000000..bb9b6f2d Binary files /dev/null and b/doc/kpovmodeler/cr22-action-pmsphere.png differ diff --git a/doc/kpovmodeler/defaultviewlayout.png b/doc/kpovmodeler/defaultviewlayout.png new file mode 100644 index 00000000..cb7f3af5 Binary files /dev/null and b/doc/kpovmodeler/defaultviewlayout.png differ diff --git a/doc/kpovmodeler/dockwidget.png b/doc/kpovmodeler/dockwidget.png new file mode 100644 index 00000000..aac95037 Binary files /dev/null and b/doc/kpovmodeler/dockwidget.png differ diff --git a/doc/kpovmodeler/dockwidgettab.png b/doc/kpovmodeler/dockwidgettab.png new file mode 100644 index 00000000..f0e76f91 Binary files /dev/null and b/doc/kpovmodeler/dockwidgettab.png differ diff --git a/doc/kpovmodeler/index.docbook b/doc/kpovmodeler/index.docbook new file mode 100644 index 00000000..f6551595 --- /dev/null +++ b/doc/kpovmodeler/index.docbook @@ -0,0 +1,2100 @@ + + + + POV-Ray"> + + +]> + + + + +The &kpovmodeler; Handbook + + + +Lauri +Watts + +
lauri@kde.org
+
+
+ + +Andreas +Zehender + +
zehender@kde.org
+
+
+ + +Olivier +Saraja + +
olivier@linuxgraphic.org
+
+
+ + +
+ +&FDLNotice; + +2002-09-07 +1.00.00 + + + +&kpovmodeler; is a graphical 3D modeler, which can generate scenes for +&Povray; + + + + +KDE +KPovModeler + + +
+ + +Introduction + +&kpovmodeler; is a 3D modeling application to generate &Povray; +scenes. + +While it is not necessary to fully understand the &Povray; +application in order to make good use of &kpovmodeler;, it is highly +recommended that you read and try to understand the &Povray; +documentation. + +To find out more about &Povray; go to +www.povray.org. + + + + +The &kpovmodeler; Interface + +When you start &kpovmodeler;, the default layout is as +follows: + + +The default view layout + + +The default view layout + + + + + +Menubars (1) + + +Toolbars (2) + + +The object tree (3) + + +The object properties +view (4) + + +The wireframe and camera views (5) + + + + +The Object Tree + +The object tree displays the objects inside the scene and their hierarchy. + + + +The object tree + + + + +Selecting Objects +In the object tree you can select objects. Once you select an object, its attributes +are displayed in the +properties view and rendered yellow in the +wireframe views. + +You can select multiple objects. However, you cannot select a child of an already +selected object, because all children are selected indirectly with the parent. + +If only one object is selected, it is referred to as the active object from now on. + + + +Adding new Objects + +To add a new object to the object tree, select the object where you want to +insert the new object and either click the icon in the toolbar or choose a menu entry +in the Insert menu. + +There are three possible positions for new objects: + +As the first child of the active object +As the last child of the active object +As a sibling of the active object + + +If there is more than one position possible, the following popup menu prompts +you to select the correct position: + + + + +The insert position popup + + + + + + +Removing Objects +To remove objects, select them and select Delete from +either the Edit menu or the &RMB; context menu. + + + +Moving Objects +To move objects, drag and drop the selected objects on to the object tree. +You can cut the object and insert it at the new position as well. + + + + + +The Properties View + +The properties view displays the attributes of the active object. + + + +The properties view + + + +If you changed some properties, click the Apply button to +make the changes permanent. If you entered invalid data, a message box will show up with +an error description. You can then adjust the properties and press +Apply again, or revert your changes with the +Cancel button. +If you set the path to your &Povray; user documentation in the +settings dialog, you can open the +&Povray; reference page for the displayed object with the Help +button. + + +You need the &Povray; 3.1g or 3.5 HTML user documentation in order to use this feature. +If your distribution does not contain this documentation you can download it +here. +The &Povray; 3.5 package contains the html user documentation. + + +If you edit a texture or a part of a texture, you can preview it inside the properties view. + + + + +The properties view, texture preview + + + +Press the Preview button inside the properties view and a +small sample scene with the selected texture will be rendered. By default the whole texture +will be rendered, even if not the top item is selected. If you want to render only a part of +the texture (for example a texture inside a texture map and not the whole texture map), check the +local check box. + + + + +The Wireframe Views + + +The Orthographic Views + +The orthographic wireframe views show the scene as an orthographic +projection on one of the coordinate planes. + + + + +The top wireframe view + + + +There are six types of orthographic wireframes views: + +Top +Bottom +Left +Right +Front +Back + + +Each type renders the scene from a different perspective. + + +Graphical Attribute Changes +In the orthographic views you can change object attribute +properties graphically with the mouse. + + + + +The control points of the camera object + + + +The above screenshot shows the control points of the camera. +You can drag the control points around to change the camera's position and direction. + +If a transformation is selected, the control points are removed and a small cross is +displayed in the wireframe view. The cross marks the center for scaling and rotation, +as well as the position for translations. You can change the transformation with the mouse +by dragging inside the whole view. + +Some objects like the bicubic patch support selection and modification of multiple +control points. + + + + + &LMB; + Selects one control point and deselects all others + + + &Ctrl;Left + Mouse Button + Selects or deselects one control point + + + &Shift;Left + Mouse Button + Drag a rectangle. All control points inside the rectangle are + selected, the others deselected + + + &Shift;&Ctrl;Left Mouse Button + Drag a rectangle. All control points inside the rectangle are selected + + + + + + + +Display Window Selection +You can zoom and translate the view to change the display window. + + + + &MMB; + Translates the view + + + wheel + Zooms the view around the mouse position + + + Left, Right, Up, Down + Translates the view + + + CtrlLeft, + CtrlRight + Zooms the view + + + + + + + + + +The Camera View + +The camera view displays the scene from the camera's point of view. + + + + +The camera view + + + +The blue box displays the field of view when the scene is rendered. + +You cannot change control points in the camera view. + + + + +Visibility Levels + +By default all objects are displayed in the wireframe views. +Each object with a wire frame has a visibility level. +You can specify a visibility level relative to the parent's visibility level +or an absolute value. Objects are only displayed if they are selected or their visibility +level is smaller or equal the chosen scene visibility level in the +toolbar. + + + + + + + +View Layouts + +&kpovmodeler; comes with a default view layout: The object tree and +the object properties view to the left and four graphical views to the right. + +If you don't like the default layout, or need another layout, you can freely +configure it. You can even save multiple view layouts and switch between them +on the fly. + + +Modifying the View Layout + +You can move the existing views by dragging the handle on top of the +views around. + + + + +The dock widget handle + + + +To dock a widget above or below an existing view, drag the handle to +the top or bottom of a view. A rectangle will indicate the new position. +To create a new column, drag the handle to the right or left side +of another view. The view will then dock to the left or right side of the +view and span the full height. +If you want multiple views sharing the same space, drag the handle to +the center of another view. You can then switch between the views by +clicking the corresponding tab on top of the views. + + + + +The tabbed view layout + + + +The last layout possibility are floating views: views that +are not docked into the main view. To undock a view, drag the handle to the +desktop or press the little arrow in the view handle that points to the +top left side. + +To close a view, click the little cross in the handle. To prevent closing, +click the little box between the arrow and the cross. + +You can add additional views to the main window. The View +menu contains entries for each type of view. New views will be created floating, +which you can dock wherever you like. + + + + +Saving a View Layout + +You can save the current view layout with + +View +Save View Layout... + A dialog opens that lets you select an existing layout +or create a new one. + +You can then fine-tune your view layout in the +settings dialog. + + + + + +Switching between View Layouts +You can switch to a saved view layout by selecting the entry in the +ViewView Layout +menu. + + + + + + + + + +&Povray; Interaction + + +Rendering the Scene + +Once you have created a scene, you will want to render it. &kpovmodeler; +uses &Povray; 3.1g to render the scene, so you need a correct installation of &Povray;. +At the time of writing &Povray; 3.5 was released. This version is not supported in +the &kpovmodeler; 1.0 version. +Go to www.povray.org +to get a version of &Povray; and for installation instructions. + +To render the current scene, press the render icon + + +The render icon + +in the toolbar, or select the +ViewRender +menu entry. + + +Render Modes + +A render mode is similar to &Povray;s ini file entries. It specifies the image size +and quality levels for rendering. If you would like to render your scene with different +qualities and sizes, you can add as many render modes as you need, from quick previews +to fullscreen high quality images. + + +Render Modes Configuration + +When you press the render settings icon + + +The render settings + +in the toolbar or select the +ViewRender Modes... +menu icon, the following dialog opens: + + + + +The render modes selection dialog + + + +This dialog shows the list of all available render modes. + + + +Add +Adds a default render mode to the list. + + + +Remove +Removes the selected render mode. + + + +Edit +Opens a dialog to edit the selected render mode. + + + +Up +Moves the selected render mode one position up. + + + +Down +Moves the selected render mode one position down. + + + + + +The Edit Button opens the following +configuration dialog: + + + + +The render modes size tab + + + +Each render mode has a description. You can enter any description, but it should reflect +the render mode's properties. + +In the Size tab you can enter the width and height of the rendered image. If +you want to render only a small part of the image, check the +Subselection check box and enter the part of the image +in the fields below. + + + + +The render modes quality tab + + + +In the Quality tab you can select various quality levels +for the rendered image. + +In the Quality combo box you can select the features +&Povray; uses while rendering. The possibilities range from a very simple coloring +and lighting model, to one which has complex diffuse inter-reflection lighting. +See the &Povray; user documentation +for a detailed description of the rendering features. + +If an image is rendered with only one sample per pixel, various errors can occur. +These images often have moiré or stepped effects in curves and lines, and +details can get lost if they are smaller in appearance then one pixel. +This effect is called aliasing. + +&Povray; uses a technique called anti-aliasing to reduce the impact +of these errors. In general images will look smoother with this feature. + +If you enable anti-aliasing, &Povray; will calculate and combine more then one +sample per pixel. This is called super-sampling. + +&Povray; supports two methods of super-sampling. The default +is an adaptive non-recursive method; adaptive +because the super-sampling +depends on the local neighborhood of the pixel. Not every +pixel is super-sampled with this method. The second method is an adaptive +recursive one; recursive because every pixel is divided and sub-divided +recursively, and adaptive because the recursion depth depends on the +computed color values. + +When you select the first method, povray traces one ray per pixel. If the +difference between its color value and that of its neighbor exceeds the given threshold, +both pixels are super-sampled by tracing a fixed number of additional rays. If you set +the depth value to 4, a 4x4 grid of additional points will be calculated, a depth +value of 5 will result in 5x5 (25) samples per pixel. + +The difference between two pixels is computed as follows: r1, +g1 and b1 are the +red, green and blue values of the first pixel; r2, +g2 and b2 are the red, +green and blue values of the second pixel. The difference is then: + +diff = abs(r1-r2) ++ abs(g1-g2) ++ abs(b1-b2) + +The recursive method starts with 4 samples per pixel. If the resulting color values +differ more than the given threshold, the pixel is sub-divided into 4 sub pixels that are +separately traced and tested for further subdivision. You can specify the maximum +recursive depth with the depth value. + +An additional method to reduce aliasing effects is to add noise to the +sampling process, called jittering. If you enable +jittering, &Povray; jitters the samples a tiny amount to reduce +regular patterns. + +The last quality setting is radiosity. Radiosity is an experimental +&Povray; feature that computes inter-diffuse light reflection. Be patient +when rendering a scene with this feature. + + + + +The render modes output tab + + + +In the last tab, you can configure whether or not the +alpha channel should be calculated by povray. +A pixel will then be transparent +if the corresponding ray did not hit a single object. + + + + +Choosing a render mode + +You can select the render mode in the combo box in the rendering toolbar. + + + + +The render modes toolbar + + + + + + + + +The Render Window + +When you started to render a scene, this window will open: + + + + +The render window + + + +It shows the rendered image, the progress and the current rendering +speed. + + + +Stop +Terminates &Povray;. + + + +Suspend +Suspends rendering. + + + +Resume +Resumes rendering. + + + +Povray Output... +Opens another window that displays the &Povray; +console output. If &Povray; exits abnormally, you can find the reason +in that window. + + + +Save... +Lets you save the image when it is rendered. + + + +Close +Closes the render window. + + + + + + + + + + +Exporting and Importing + + +Exporting and Importing a Whole Scene + +You can export a scene to &Povray; with the +FileExport Povray... +menu entry. +The file save dialog will allow you to choose a name and +location to save the file. +&kpovmodeler; will automatically add the +.pov extension. + +To import a &Povray; scene select the +FileImport Povray... +menu item and choose a file in the file open dialog. + +Not the full &Povray; syntax is supported by &kpovmodeler; at the moment. +If there are errors or warnings during importing, a dialog will show up that +lists all messages. + +If you want to import unsupported code to &kpovmodeler;, put +the source between the two special comments //*PMRawBegin +and //*PMRawEnd. + + + + +Exporting and Importing single Objects + +You can drag objects from the object tree to an editor +to export &Povray; code. This will insert the objects code into the current +text file in the editor. To import objects into the scene, simply select +the code in your editor and drag it on to the object tree. +You can use the copy and paste functionality of &kpovmodeler; +and your editor to exchange &Povray; code as well. + + + + + + + + + +Configuring &kpovmodeler; + + +The <guilabel>Povray</guilabel> Tab + + +<guilabel>Povray Command</guilabel> + +The povray command is called when &kpovmodeler; renders a scene. Common commands +are povray or x-povray. + + + + +<guilabel>Povray User Documentation</guilabel> + +If you press the Help button in the properties view, &kpovmodeler; +opens the &Povray; user documentation for the displayed object. Set here the path to your documentation +and your documentation version. Supported versions are 3.1g and 3.5. + + + + +<guilabel>Library Paths</guilabel> + +&Povray; searches for external files (height field data as example) in the &Povray; library paths. +If you refer to files not in the scene's folder, you have to add the folder to the list. If a file +exists in multiple library paths, that one in the first path is used. +You can change the order with the Up and +Down buttons. + + + + + + +The <guilabel>Graphical view</guilabel> Tab + + +<guilabel>Colors</guilabel> + +The color tab lets you configure the used colors for the graphical views. + + + + +Background: +The background color. + + + +Wire frame: +The colors for wire frames. The second color is used if the object +is selected. + + + +Control points: +The color for control points. The second color is used if the control point +is selected. + + + +Axes: +The colors for the x-, y- and z-axis. + + + +Field of view: +The color for the field of view rectangle in the camera view +and the view type labels. + + + + + + + +The Grid + +This page lets you configure the grid in the wire frame views. + + +<guilabel>Displayed Grid</guilabel> + + + + +Color: +The grid color. + + + +Distance: +The minimal distance of two grid lines. + + + + + + + +<guilabel>Control Point Grid</guilabel> + +You can snap control points to the grid with the context menu in +the wireframe views. You can configure the grid for translations, scales and rotations +separately here. + + + + + + +<guilabel>Objects</guilabel> + + +<guilabel>Subdivisions</guilabel> + +You can configure the detail levels for various objects here. + +Higher values lead to a finer wireframe and therefore to a better approximation for +the displayed objects, but slow down rendering. For some objects like the sphere you can +configure the detail level for two directions separately. + + + + +<guilabel>Sizes</guilabel> + +Lets you configure the sizes in which infinite objects are displayed in +the wireframe views. + + + + +<guilabel>Camera Views</guilabel> + +If you check the High detail for enhanced projections check box, +all wire frame lines are subdivided further if the camera uses an enhanced projection. Enhanced +projections are all projections except the perspective and orthographic projections. This feature +greatly improves the approximation of these projections but slows down rendering. + + + + + + + + +The <guilabel>Properties view</guilabel> Tab + + +<guilabel>Texture Preview</guilabel> + +This page lets you configure the texture preview in the properties view. + + + + +Size: +The preview image size. + + + +Gamma: +The gamma correction. + + + +Rendered Objects +Defines the small sample scene. At least one +object has to be selected. + + + +Wall +If the Enable wall check box is checked, a +wall will be rendered behind the objects. The wall is textured with a checker pattern with the +two configurable colors. + + + +Floor +If the Enable floor check box is checked, a +floor will be rendered below the objects. The floor is textured with a checker pattern with the +two configurable colors. + + + +Anti-Aliasing +If the Enable antialiasing check box is checked, +the non-recursive antialiasing method will be used for rendering the scene. You can configure the +depth and threshold values. See render modes section +for a detailed description of the parameters. + + + + + + + + + +The <guilabel>View Layout</guilabel> Tab + +In this page you can fine-tune existing view layouts or manually +create new ones. See section View Layouts +how to create and save view layouts. + + +The default View Layout + +The combo box Default view layout: +lists all available view layouts. &kpovmodeler; uses the selected +view layout at program start. + + + + +List of View Layouts + +The list Available View Layouts +shows all available view layouts. You can add a new layout with the +Add button and remove the selected layout +with the Remove button. +The selected view layout is displayed in the box +View Layout + + + +View Layout Details + +Each view layout is identified by its name. The name has to +be unique and must not be empty. + +The list below the name displays all views for the selected +view layout. You can add new views with the +Add button and remove the selected view +with the Remove button. + +The attributes of the views are: + + + +Type: + +The view type. See The &kpovmodeler; Interface +for a description of each view type. + + + + +3D view type: + +The projection for wire frame views. You can choose one of the six +orthographic projections or the camera mode. + + + + +Dock position: + +The position of the view. New Column will +create a new column to the right side of the previous views, +Below will dock the view below the previous view, +Tabbed will create a tabbed view together with the previous one +and Floating will not dock the view into the main +window but create a separate window. + + + + +Column width: + +The width of the column in percent of the main view width. + + + + +View height: + +The view height in percent of the main view height. + + + + +Width: and Height: + +The size in pixels for floating views. + + + + +Position x: and y: + +The position on the desktop for floating views. + + + + + + + + + + + + +Basic Tutorial: Creating your first Scene + +OK, that's it. You have just installed &Povray; and &kpovmodeler;, +and now you already want to start without much knowledge of any of the two +softwares. Here we go now: If you follow the steps of this tutorial, +you'll be able to set the ultimate simple scene, very widespread among +the newbies: A sphere over a plane. + + + + + + + + +At any time you can render your scene using one of the following methods: + +Using the menu: +DisplayRender +Using the toolbar: Click on the + + + icon + +But you should carefully consider the following warnings before complaining +if all you get is a black screen. If this is the very first time you use a 3D software, +you should be aware of these golden rules: + + +If you set no camera, no rules apply to the render engine which can't +render a proper picture, ending in a black picture. +If you set no light system, all your scene is in the dark, +ending in a black picture. +The objects for which no material has been set won't show on the +rendered picture, ever. + + + +Step 1: Start &kpovmodeler; + +If you got everything installed fine, once &kpovmodeler; +is loaded, you discover the following default windows setting: + + + + + + + +Take a few minutes to explore the menus and icons available. +If you have time, please read the documentation in order to get a +fair idea of what you can expect from this piece of software. + + + +Menubars (1) + + +Toolbars (2) + + +The object tree (3) + + +The object properties +view (4) + + +The wireframe and camera views (5) + + + +You will have to use each of them intensively from now on, so always keep them +and their use in mind. + +&kpovmodeler; starts with a simple scene. In order to follow this tutorial +you first have to remove all objects from the object tree. Select the scene +and choose the EditDelete menu +entry. You should now have an empty scene. + + + + +Step 2: Setting the Camera + +First of all, we will set a camera. In order to do so, two convenient ways are available: +Using the menu: InsertCamera +Using the toolbar: Click on the + + + icon + +The wireframe view shows how the camera is set regarding the whole scene we are creating. +In particular, we can now see something in the fourth wire frame view (right, bottom): +This is the view of the scene from the camera point of view. +This is what will be seen when you render the scene. + + + + + + + +The object tree now shows a new entry, reading camera. If you click on it, +it affects the content of the object properties view, where various parameters +pertaining to the camera can be found. +Referring to the &Povray;'s documentation to learn more about these could be helpful. + + + + + + + +We will change nothing to the basic settings of the camera, +this will be the scope of later tutorials, but please note that in the graphic view, +the camera has control points that let you control the point to which the camera points. +You just have to left-click on one handle and move it to an appropriate location. + + + + +Step 3: Setting a Light + +The same way we have set a camera, we will now set a light system: +Using the menu: +InsertLight +Using the toolbar: Click on the + + + icon + +A new entry features now in the object tree. If you click on the light entry, +you see that the properties view changes in order to show the parameters available +to the lighting system. We will change some parameters in order to set the +light higher above the horizon (y=3), slightly on the right +(x=1) and in the foreground (z=1). +We can also rename the light system (Name=Main Light). +Change the values in the object properties view as follows: + + + + + + +Once you press the Apply button (or hit Enter), +the wire frame view and the object tree immediately +change in order to comply to these settings, and here is what now should see the camera. + + + + + + + + + +Step 4: Creating the Ground +There are many ways to create a ground for our scene. +One method could have been to insert a box object +(InsertFinite Solid Primitives +Box) +and resize x to 100, y to 0 and z to 100, for example, but it's a cumbersome way to do this task. + +In fact, &kpovmodeler; offers you a convenient feature: You can create +a infinite plane that will feature the ground: + +Using the menu: +InsertInfinite Solid Primitives +Plane +Using the toolbar: Click on the + + icon. + +Take a good custom: Having the plane selected in the object tree, please change its name +in something that is convenient to you and then press the Apply button (or hit Enter). +The object tree will update the name of the entry. + + + + + + +The wire frame view also shows the plane now, even if it looks finite by now. +But don't worry, it will spread up to the horizon line when you'll render the scene! + +If you pay attention to the object tree, you will notice that the ground entry +can be expanded if you click on the plus icon standing just before the object. +Once done, you see various settings parented to the object. In this case, +there isn't much yet, apart from the standard options to any newly created object: +Scale, rotate, and translate. Selecting each of these will change the settings +available in the object properties view. + + + + + + +In this scene, we will arbitrary translate the ground one unit lower than the horizon line, +just for you to tweak some of these parameters. Select translate, and adjust the parameters as follow: + + + + + + +Your scene should now look like the following picture. + + + + + + + +Step 5: Setting a Material for the Ground + +Please select the ground prior to adding any material properties to it. +Many possibilities await us, but we will stay close to something quite easy for now. + +Using the menu: InsertTextures +Pigment +Using the toolbar: Click on the + + + icon. + + + + + + +In both cases, a popup window will prompt you to choose the way the object should be inserted. +Please choose First Child. The pigment now appears in the object tree. +You can change its name +in the properties view (Name=Ground Pigment), and click on the +Preview button +in order to see how the pigment looks like for now. + + + + + + +Of course, the preview of the pigment shows nothing but a black matte material, +because we need to refine the pigment settings. Anyway, keep in mind you always +can preview the look and feel of your materials using the Preview button. +We will now define the pigment colors. Again, many possibilities await us, +but we will choose one of the most straightforward for now. + +Using the menu: InsertTextures +Color List +Using the toolbar: Click on the + + + icon + +If no color shows on the box and the sphere of the preview, +click on the Apply button before calling for a preview. + + + + + + +The ground material has been successfully set! If you render your picture now, using the + + + render icon, you should get the following result: + + + + + + +Of course, these colors are not the ones you could have expected. +We still have to see how we can customize them. In the case of the color list, +you have to define two new sets of attributes, called Solid Color. +In the Object Tree, make sure the color list entry is selected. +Then go through this two times (you can't do it more, anyway, +as the checkers color list can only afford the use of two solid colors): + +Using the menu: InsertTextures +Solid Color + +Using the toolbar: Click on the + + + icon. + +One after another, in the object tree, select the two solid colors +and change their color attributes in the object properties view: + + + + + + +...these attributes are for the first solid color (press Apply!), + + + + + + +... and these attributes are for the second (press Apply again!). + +Of course, a new rendering of our scene will prove that everything has been +taken into account accordingly: + + + + + + + + + +Step 6: Creating the Sphere + +For this step, we should already be at ease, because we begin to understand +&kpovmodeler;'s general behavior. In the object tree, select the scene entry. +Creating the sphere is as easy as creating the ground: + +Using the menu: InsertFinite Solid Primitives +Sphere + +Using the toolbar: Click on the + + + icon. + + + + + + +As before, select First Child when asked for. + +The object properties view offers you immediately to change its settings, +which we'll do right now. By setting the Radius value to 1 +(don't forget to hit Enter or press Apply), +we make sure that the sphere will be in contact +with the ground. Otherwise, since we moved the ground one unit bottom, +the sphere will look like floating above the ground. + + + + + + +Of course, a rendering now will give a strange result: As already seen before, +the sphere appears with a black matte material. We will set a proper material in the following step. + + + + + + + + + +Step 7: Setting a Material for the Sphere + +With the sphere selected, you can now set a material for it. As we already did for the ground, +let's give to the sphere a pigment color: + +Using the menu: InsertTextures +Pigment + +Using the toolbar: Click on the + + icon + +Select First Child and rename to Sphere pigment, for example. +With the sphere pigment entry selected, insert a solid color and set the parameters as follow: + +Using the menu: InsertTextures +Solid Color + +Using the toolbar: Click on the + + icon + + + + + + +You already can render the scene and get a first poor result: + + + + + + +But there are more interesting effects to achieve if we take time to set some finish attributes: + +Using the menu: InsertTextures +Finish +Using the toolbar: Click on the + + + icon. + +Then change the values according to the following snapshot and press +Apply or hit Enter. + + + + + + +The Specular and Reflection +parameters give particularly good visual effects, +perfect for glass or chrome-like effects, even if Metallic +hasn't been chosen at this step: + + + + + + + + + +Conclusion + +You should now have a fair glimpse of what is possible with kpovmodeler. +Hopefully, you are already skilled enough to do simple but beautiful things. + + + + + +Basic Concepts + + +What is Raytracing? + +Raytracing is a method of rendering, that is, creating a 2D +image out of a 3D scene or model. + +When raytracing a scene, the renderer shoots a hypothetical ray +from the perspective of the viewer (that is, from the camera you are +rendering the scene from) through each pixel in the scene. It +calculates how this ray reflects and refracts from objects, the visual +effects of the light sources in the scene and how atmospheric effects such +as fog affect it. The scene is built up, pixel by pixel. + +As you may imagine, without a camera, you cannot see anything - +the camera is your eye into the scene. Furthermore, +without any light, you still won't see anything - it would just be +dark. Obviously, any scene intended for raytracing must include +some light, an object of some kind and at least one camera. + + + + + + +Objects Reference + +For a complete reference to all objects and attributes +see the &Povray; user documentation. + + + + +Menu Reference + + +The <guimenu>File</guimenu> Menu + + + + +&Ctrl;N + +File +New + + +Create a new scene. + + + + + +File +Import Povray... + + +Import a &Povray; scene created outside +&kpovmodeler;. +A normal file dialog will open, allowing you to choose your +file. Povray files usually have the extensions *.pov or *.inc. + + + + + +&Ctrl;O + +File +Open... + + +Open a file. The standard file dialog will +allow you to choose a file you have previously created with +&kpovmodeler; + + + + + +File +Open Recent + + +Open a file from a list of the files you have been +recently working on. +Whenever you open or create a new model, it is added to this +submenu, replacing the oldest entry in the list. + + + + + +&Ctrl;S +File +Save + + +Save the currently active scene. +If you have already saved this model, it will be saved with the +same name. If it is a new file, you will be asked to name it and +choose a location to save it. + + + + + +File +Save As... + + +Save the currently active scene with a new +name. + + + + + +File +Export Povray... + + +Export the scene as a &Povray; file. +The file save dialog will allow you to choose a name and +location to save the file. +&kpovmodeler; will automatically add the +.pov extension. + + + + + +File +Revert + + +Revert the scene to the state it was in the last time +you saved it. Changes you have made since the last save will +be lost. + + + + + +&Ctrl;P +File +Print... + + +Printing is not implemented yet. + + + + + +&Ctrl;W +File +Close + + +Close the current scene without closing +&kpovmodeler; + + + + + +&Ctrl;Q +File +Quit + + +Quit &kpovmodeler;. If you have any unsaved +changes, you will be given a chance to save them. + + + + + + + +The <guimenu>Edit</guimenu> Menu + + + + +&Ctrl;Z + +Edit +Undo + + +Undo the last action you performed. +This menu item is not available unless you have unsaved changes +to the current scene. + + + + + + +&Ctrl;&Shift;Z +Edit +Redo + + +Redo the last action you undid. This menu item +is not available unless you have used +Edit +Undo. + + + + + +&Ctrl;X +Edit +Cut + + +Cut the currently selected object(s) from the scene, +and store them on the clipboard. + + + + + +&Ctrl;C +Edit +Copy + + +Copy the currently selected object(s), and +store them on the clipboard. + + + + + +&Ctrl;V +Edit +Paste + + +Paste the contents of the clipboard. + + + + + +Edit +Delete + + +Delete the currently selected object(s) from +the scene. + + + + + + + + + +The <guimenu>View</guimenu> Menu + + + + +View +New Object Tree + + +Create a new Object Tree. + + + + + +View +New Properties View + + +Create a new Object Properties View. + + + + + +View +New Top View + + +Create a new +Orthographic Wireframe View +from the top perspective. + + + + +View +New Bottom View + + +Create a new +Orthographic Wireframe View +from the bottom perspective. + + + + +View +New Left View + + +Create a new +Orthographic Wireframe View +from the left perspective. + + + + +View +New Right View + + +Create a new +Orthographic Wireframe View +from the right perspective. + + + + +View +New Front View + + +Create a new +Orthographic Wireframe View +from the front perspective. + + + + +View +New Back View + + +Create a new +Orthographic Wireframe View +from the back perspective. + + + + +View +New Camera View + + +Create a new +Camera View. + + + + +View +View Layouts + + +Contains a list of all available view layouts. Switch to the +selected layout. + + + + +View +Save View Layout... + + +Save the current view layout. A dialog opens to choose a +name for a new layout or to overwrite an existing one. + + + + +View +Render Modes... + + +Open the +render modes configuration +dialog. + + + + +View +Render + + +Render the scene. + + + + +View +Render Window + + +Show the &Povray; render window. + + + + +View +Redisplay + + +Redisplay the wire frame views. + + + + + + + + +The <guimenu>Insert</guimenu> Menu + +Creation actions for all supported &Povray; objects. + + + + +The <guimenu>Settings</guimenu> Menu +This menu provides options for configuring &kpovmodeler;, changing its +appearance, shortcuts and standard behavior. + + + + + +Settings +Show Statusbar + +Toggles the statusbar on/off. + + + + +Settings +Show Path + +Show/hide the path in the caption. + + + + +Settings +Save settings + +Saves the current settings. + + + + +Settings +Configure Key Bindings... + +Opens a dialog for changing the key bindings. +Using this option you can change the standard key shortcut for &kpovmodeler;'s commands +or create new ones. + + + + +Settings +Configure Toolbars... + +Opens a dialog for configuring the toolbar. You +can add and remove toolbuttons for &kpovmodeler;'s commands with this +option. + + + + +Settings +Configure KPovModeler... + +Opens a dialog to configure &kpovmodeler;. + + + + + + + + + +The <guimenu>Help</guimenu> Menu + +&help.menu.documentation; + + + + + + +Credits and Licenses + +&kpovmodeler; copyright 2001,2002 the &kpovmodeler; +authors. + + +Authors + +Andreas Zehender zehender@kde.org + + +Luis Passos Carvalho +lpassos@mail.telepac.pt + + +Phillippe Van Hecke +lephiloux@tiscalinet.be + + +Leonardo Skorianez skorianez@bol.com.br + + + +Documentation copyright 2002 Lauri Watts +lauri@kde.org +Documentation copyright 2002 Andreas Zehender +zehender@kde.org +Documentation copyright 2002 Olivier Saraja +olivier@linuxgraphic.org + + + +&underFDL; +&underGPL; + + + + +Glossary + + +Bump Map + +A bump map is a way to simulate a rough surface, without having +to model every single bump on the surface, and without +changing the underlying geometric shape of the object itself. +It is common to use the same file as both a bump map and a texture map. + + + + +Primitives + +Primitives are the basic geometric shapes that you can use as +building blocks. Most complex 3d models are created +from many dozens, or even hundreds, of these primitives, which are +then edited and manipulated to give a more realistic +appearance. + + + + +Rendering + +Not yet written + + + + +Texture Map + +A texture map is a way of applying color to the surface of an +object on a pixel by pixel basis, by applying an image file as a color +map. +It is common to use the same image file as a bump map. + + + + + + + +&documentation.index; + + +Installation + +&install.intro.documentation; +&install.compile.documentation; + + + +
+ + diff --git a/doc/kpovmodeler/insertaspopup.png b/doc/kpovmodeler/insertaspopup.png new file mode 100644 index 00000000..523bd0cc Binary files /dev/null and b/doc/kpovmodeler/insertaspopup.png differ diff --git a/doc/kpovmodeler/objectpropertiesview.png b/doc/kpovmodeler/objectpropertiesview.png new file mode 100644 index 00000000..92d74a6f Binary files /dev/null and b/doc/kpovmodeler/objectpropertiesview.png differ diff --git a/doc/kpovmodeler/objecttree.png b/doc/kpovmodeler/objecttree.png new file mode 100644 index 00000000..1be38e65 Binary files /dev/null and b/doc/kpovmodeler/objecttree.png differ diff --git a/doc/kpovmodeler/rendericon.png b/doc/kpovmodeler/rendericon.png new file mode 100644 index 00000000..6aa2b69f Binary files /dev/null and b/doc/kpovmodeler/rendericon.png differ diff --git a/doc/kpovmodeler/rendermodeoutput.png b/doc/kpovmodeler/rendermodeoutput.png new file mode 100644 index 00000000..77146f2c Binary files /dev/null and b/doc/kpovmodeler/rendermodeoutput.png differ diff --git a/doc/kpovmodeler/rendermodequality.png b/doc/kpovmodeler/rendermodequality.png new file mode 100644 index 00000000..0b0fba3d Binary files /dev/null and b/doc/kpovmodeler/rendermodequality.png differ diff --git a/doc/kpovmodeler/rendermodesize.png b/doc/kpovmodeler/rendermodesize.png new file mode 100644 index 00000000..c593b1ed Binary files /dev/null and b/doc/kpovmodeler/rendermodesize.png differ diff --git a/doc/kpovmodeler/rendermodesselection.png b/doc/kpovmodeler/rendermodesselection.png new file mode 100644 index 00000000..4ea97325 Binary files /dev/null and b/doc/kpovmodeler/rendermodesselection.png differ diff --git a/doc/kpovmodeler/rendermodestoolbar.png b/doc/kpovmodeler/rendermodestoolbar.png new file mode 100644 index 00000000..8aee4f53 Binary files /dev/null and b/doc/kpovmodeler/rendermodestoolbar.png differ diff --git a/doc/kpovmodeler/rendersettingsicon.png b/doc/kpovmodeler/rendersettingsicon.png new file mode 100644 index 00000000..cb6b2e9a Binary files /dev/null and b/doc/kpovmodeler/rendersettingsicon.png differ diff --git a/doc/kpovmodeler/renderwindow.png b/doc/kpovmodeler/renderwindow.png new file mode 100644 index 00000000..25662a25 Binary files /dev/null and b/doc/kpovmodeler/renderwindow.png differ diff --git a/doc/kpovmodeler/texturepreview.png b/doc/kpovmodeler/texturepreview.png new file mode 100644 index 00000000..c9ca6060 Binary files /dev/null and b/doc/kpovmodeler/texturepreview.png differ diff --git a/doc/kpovmodeler/topview.png b/doc/kpovmodeler/topview.png new file mode 100644 index 00000000..faf76e20 Binary files /dev/null and b/doc/kpovmodeler/topview.png differ diff --git a/doc/kpovmodeler/tutorial01-camera-dialog.png b/doc/kpovmodeler/tutorial01-camera-dialog.png new file mode 100644 index 00000000..b3f9856f Binary files /dev/null and b/doc/kpovmodeler/tutorial01-camera-dialog.png differ diff --git a/doc/kpovmodeler/tutorial01-camera-graphic.png b/doc/kpovmodeler/tutorial01-camera-graphic.png new file mode 100644 index 00000000..12ca95bc Binary files /dev/null and b/doc/kpovmodeler/tutorial01-camera-graphic.png differ diff --git a/doc/kpovmodeler/tutorial01-final-render.png b/doc/kpovmodeler/tutorial01-final-render.png new file mode 100644 index 00000000..48a3a016 Binary files /dev/null and b/doc/kpovmodeler/tutorial01-final-render.png differ diff --git a/doc/kpovmodeler/tutorial01-ground-color-list.png b/doc/kpovmodeler/tutorial01-ground-color-list.png new file mode 100644 index 00000000..00166661 Binary files /dev/null and b/doc/kpovmodeler/tutorial01-ground-color-list.png differ diff --git a/doc/kpovmodeler/tutorial01-ground-pigment.png b/doc/kpovmodeler/tutorial01-ground-pigment.png new file mode 100644 index 00000000..33bc3206 Binary files /dev/null and b/doc/kpovmodeler/tutorial01-ground-pigment.png differ diff --git a/doc/kpovmodeler/tutorial01-ground-render.png b/doc/kpovmodeler/tutorial01-ground-render.png new file mode 100644 index 00000000..18a4816c Binary files /dev/null and b/doc/kpovmodeler/tutorial01-ground-render.png differ diff --git a/doc/kpovmodeler/tutorial01-ground-solid-color-1.png b/doc/kpovmodeler/tutorial01-ground-solid-color-1.png new file mode 100644 index 00000000..a805904a Binary files /dev/null and b/doc/kpovmodeler/tutorial01-ground-solid-color-1.png differ diff --git a/doc/kpovmodeler/tutorial01-ground-solid-color-2.png b/doc/kpovmodeler/tutorial01-ground-solid-color-2.png new file mode 100644 index 00000000..870fd8d4 Binary files /dev/null and b/doc/kpovmodeler/tutorial01-ground-solid-color-2.png differ diff --git a/doc/kpovmodeler/tutorial01-ground-wrong-colors-render.png b/doc/kpovmodeler/tutorial01-ground-wrong-colors-render.png new file mode 100644 index 00000000..36dfe296 Binary files /dev/null and b/doc/kpovmodeler/tutorial01-ground-wrong-colors-render.png differ diff --git a/doc/kpovmodeler/tutorial01-light-dialog.png b/doc/kpovmodeler/tutorial01-light-dialog.png new file mode 100644 index 00000000..cb9adeaf Binary files /dev/null and b/doc/kpovmodeler/tutorial01-light-dialog.png differ diff --git a/doc/kpovmodeler/tutorial01-light-graphic.png b/doc/kpovmodeler/tutorial01-light-graphic.png new file mode 100644 index 00000000..ede4b9c7 Binary files /dev/null and b/doc/kpovmodeler/tutorial01-light-graphic.png differ diff --git a/doc/kpovmodeler/tutorial01-plane-dialog.png b/doc/kpovmodeler/tutorial01-plane-dialog.png new file mode 100644 index 00000000..9a63936d Binary files /dev/null and b/doc/kpovmodeler/tutorial01-plane-dialog.png differ diff --git a/doc/kpovmodeler/tutorial01-plane-graphic.png b/doc/kpovmodeler/tutorial01-plane-graphic.png new file mode 100644 index 00000000..c2cf8163 Binary files /dev/null and b/doc/kpovmodeler/tutorial01-plane-graphic.png differ diff --git a/doc/kpovmodeler/tutorial01-plane-tree-expanded.png b/doc/kpovmodeler/tutorial01-plane-tree-expanded.png new file mode 100644 index 00000000..024c969c Binary files /dev/null and b/doc/kpovmodeler/tutorial01-plane-tree-expanded.png differ diff --git a/doc/kpovmodeler/tutorial01-plane-tree-translate.png b/doc/kpovmodeler/tutorial01-plane-tree-translate.png new file mode 100644 index 00000000..84d377b1 Binary files /dev/null and b/doc/kpovmodeler/tutorial01-plane-tree-translate.png differ diff --git a/doc/kpovmodeler/tutorial01-sphere-dialog.png b/doc/kpovmodeler/tutorial01-sphere-dialog.png new file mode 100644 index 00000000..2d17f4b6 Binary files /dev/null and b/doc/kpovmodeler/tutorial01-sphere-dialog.png differ diff --git a/doc/kpovmodeler/tutorial01-sphere-finish-dialog.png b/doc/kpovmodeler/tutorial01-sphere-finish-dialog.png new file mode 100644 index 00000000..e72b9aa6 Binary files /dev/null and b/doc/kpovmodeler/tutorial01-sphere-finish-dialog.png differ diff --git a/doc/kpovmodeler/tutorial01-sphere-render-finish.png b/doc/kpovmodeler/tutorial01-sphere-render-finish.png new file mode 100644 index 00000000..7861b608 Binary files /dev/null and b/doc/kpovmodeler/tutorial01-sphere-render-finish.png differ diff --git a/doc/kpovmodeler/tutorial01-sphere-render-nocolor.png b/doc/kpovmodeler/tutorial01-sphere-render-nocolor.png new file mode 100644 index 00000000..72dffddb Binary files /dev/null and b/doc/kpovmodeler/tutorial01-sphere-render-nocolor.png differ diff --git a/doc/kpovmodeler/tutorial01-sphere-render-solidcolor.png b/doc/kpovmodeler/tutorial01-sphere-render-solidcolor.png new file mode 100644 index 00000000..b96ab37f Binary files /dev/null and b/doc/kpovmodeler/tutorial01-sphere-render-solidcolor.png differ diff --git a/doc/kpovmodeler/tutorial01-sphere-solid-color.png b/doc/kpovmodeler/tutorial01-sphere-solid-color.png new file mode 100644 index 00000000..52b03ff7 Binary files /dev/null and b/doc/kpovmodeler/tutorial01-sphere-solid-color.png differ diff --git a/doc/kruler/Makefile.am b/doc/kruler/Makefile.am new file mode 100644 index 00000000..085981d9 --- /dev/null +++ b/doc/kruler/Makefile.am @@ -0,0 +1,4 @@ + +KDE_LANG = en +KDE_DOCS = AUTO + diff --git a/doc/kruler/index.docbook b/doc/kruler/index.docbook new file mode 100644 index 00000000..433b3cc9 --- /dev/null +++ b/doc/kruler/index.docbook @@ -0,0 +1,359 @@ + + + + + +]> + + + + +The &kruler; Handbook + + + +Lauri +Watts + +
&Lauri.Watts.mail;
+
+
+ + +
+ +&FDLNotice; + + +2001 +&Lauri.Watts; + + +2005-12-10 +3.5 + + + + + +&kruler; can be used to measure objects on the screen. + + + + +KDE +KRuler +kdegraphics + + +
+ + +Introduction + +&kruler; is a very simple application, with only one aim in life. To +measure distances on your screen. + +To start &kruler;, choose Graphics +More Applications +KDE Screen Ruler from your +K menu. + +Clicking with the &LMB; on the &kruler; will turn the cursor to a cross +with four arrows and enables you to drag &kruler; around the screen. + +When you move the mouse over &kruler;, your cursor will turn into an +elongated arrow, with a circle at one end. As you move the cursor, &kruler; will +display how far from the point marked 0 the circle on the +end of the cursor currently is. &kruler; will also display the +&HTML; color code of the color currently under the circle. +This is very useful for picking out colors from an image. If you move the +mouse far enough that the arrow cursor is no longer touching &kruler;, the +cursor will revert to normal, allowing you to carry on working with your other +applications. + +You can change the orientation using the context menu, described in the +next chapter. + + + + +Menu Reference + +Clicking with the &RMB; on the ruler will pop up a context menu, with the +following entries: + + + + + +Orientation + + + +This submenu contains entries that allow you to change the orientation of +&kruler; + + + + + + +N + +Orientation +North + + + +Turns &kruler; so the ruler is horizontal, and the measurements are on the +top (North) of the ruler + + + + + + +E + +Orientation +East + + + +Turns &kruler; so the ruler is vertical, and the measurements are on the +right (East) of the ruler + + + + + + +S + +Orientation +South + + + +Turns &kruler; so the ruler is horizontal, and the measurements are on the +bottom (South) of the ruler + + + + + + +W + +Orientation +West + + + +Turns &kruler; so the ruler is vertical, and the measurements are on the +left (West) of the ruler + + + + + + +R + +Orientation +Turn Right + + + +Turns the ruler 90 Degrees to the right. For example, if it is oriented +South, it will rotate to be oriented West. + + + + + + +L + +Orientation +Turn Left + + + +Turns the ruler 90 Degrees to the left. For example, if it is oriented +West, it will rotate to be oriented South. + + + + + + + + +Length + + + +This submenu contains entries that allow you to change the length of +&kruler; + + + + +&Ctrl; +S + +Length +Short + + + +Makes &kruler; short - about 385 pixels long. + + + + + + +&Ctrl;M + +Length +Medium + + + +Makes &kruler; a medium length - about 640 pixels long. + + + + + + +&Ctrl;T + +Length +Tall + + + +Makes &kruler; long - about 960 pixels in length. + + + + + + +&Ctrl;F + +Length +Full Screen Width + + + +Makes &kruler; the same size as your screen width. + + + + + + + + + +&Ctrl;C + +Choose Color... + + + +Displays the standard &kde; color picker dialog, where you can choose the +background color for &kruler;. + + + + + + + +F + +Choose Font... + + + +Displays the standard &kde; font dialog where you can choose the font for +&kruler;. + + + + + + +Help + + + +&help.menu.documentation; + + + + + + + + + +&Ctrl;Q + +Quit + + + +Quits &kruler; + + + + + + + +Credits and Licenses + +&kruler; + +Copyright 2000, 2001 Till Krech till@snafu.de + +Thanks to Gunnstein Lye gl@ez.no for the initial port to +&kde; 2 + +Documentation Copyright &Lauri.Watts; +&Lauri.Watts.mail; + + + +&underFDL; +&underGPL; + + + + +Installation + +&install.intro.documentation; + +&install.compile.documentation; + + + +&documentation.index; +
+ + diff --git a/doc/ksnapshot/Makefile.am b/doc/ksnapshot/Makefile.am new file mode 100644 index 00000000..085981d9 --- /dev/null +++ b/doc/ksnapshot/Makefile.am @@ -0,0 +1,4 @@ + +KDE_LANG = en +KDE_DOCS = AUTO + diff --git a/doc/ksnapshot/index.docbook b/doc/ksnapshot/index.docbook new file mode 100644 index 00000000..408ab80d --- /dev/null +++ b/doc/ksnapshot/index.docbook @@ -0,0 +1,535 @@ + + + + + +]> + + + + +The &ksnapshot; Handbook + + + +Richard +J. +Moore + +
&Richard.J.Moore.mail;
+
+
+ + +Robert +L. +McCormick + +
&Robert.L.McCormick.mail;
+
+
+ + +Brad +Hards + +
&Brad.Hards.mail;
+
+
+ + +Lauri +Watts + +
&Lauri.Watts.mail;
+
+Reviewer +
+ + +Richard +J +Moore + +
&Richard.J.Moore.mail;
+
+Developer +
+ + +Matthias +Ettrich + +
&Matthias.Ettrich.mail;
+
+Developer +
+ + +
+ + +1997-2000 +&Richard.J.Moore; + + + +2000 +&Matthias.Ettrich; + + +&FDLNotice; + +2006-07-05 +0.7 + + +&ksnapshot; is a simple applet for taking screenshots. It is capable +of capturing images of the whole desktop, a single window, a section of a window or a selected +region. The images can then be saved in a variety of formats. + + + +KDE +KSnapshot +kdegraphics +screen capture +screen grab + + +
+ + +Introduction + +&ksnapshot; is a simple applet for taking screenshots. It is capable +of capturing images of the whole desktop, a single window a section of a window or a selected +region. The images can then be saved in a variety of formats. + +Please report any problems or feature requests to the &kde; Bug Tracking System + + + + +Using &ksnapshot; + +This chapter describes the use of &ksnapshot; for capturing screen +images. + + +Starting &ksnapshot; + +&ksnapshot; may be started by one of several ways as described +below. + + + +You may start &ksnapshot; by selecting it from the +K-MenuGraphics +&ksnapshot; (Screen Capture Program). + + +You may start &ksnapshot; by entering the following at the command +prompt: + +% ksnapshot & + + +The mini command line (invoked with +&Alt;F2) may +also be used to start &ksnapshot; + + +Once &ksnapshot; starts, you will see a window like the following: + + + + +&ksnapshot; Preview Window + + + + + + + +Taking A Snapshot + + &ksnapshot; grabs an image of your entire desktop immediately after it is +started, but before it displays itself on screen. This allows you to quickly +create full-desktop screenshot images. + +The snapshot taken by &ksnapshot; is displayed in the preview window, +which is located in the upper left of the &ksnapshot; application window. +Below is an example of the preview window from &ksnapshot;. Your preview +will differ depending on what you have displayed on the desktop. + + + + + +&ksnapshot; Preview Window + + + +The snapshot can be saved by clicking on +the Save As... button. This opens the standard &kde; save dialog, +where you can choose the filename, the folder location, and the format that your snapshot +will be saved in. If multiple snapshots are taken, the +filename is automatically incremented to prevent you from overwriting previous +snapshots. You may however edit the filename to anything you wish, including the name +of a previously saved snapshot. + +To take a snapshot of a single window, select the Window +Under Cursor combo box entry (next to the Capture mode: +label), and then click on the New Snapshot button. + +Depending on your Snapshot delay: settings you +get either a cross as the mouse pointer (for No delay), +or a standard mouse cursor which you can use to work with a program until +the delay is over and a snapshot is taken. + +With No delay, the snapshot is taken immediately when you +click into a window. + +&ksnapshot; will display the new snapshot in the preview +area, at which time you can choose to save the new image (by pressing +Save As...) +or to grab a new one, by pressing the +New Snapshot button. + +To take a new snapshot of the entire desktop, select the +Full Screen combo box entry and then click on the +New Snapshot button. +&ksnapshot; will now capture the entire desktop if you press +New Snapshot. + +Similarly, to take a snapshot of a region, select the +Region combo box entry and set the +Snapshot delay to No delay, +and then click on the New Snapshot button. The +mouse cursor will then change into a cross, and you can then use the +mouse to select the region you want to capture. + +To take a new snapshot of a section of a window, select the +Section of Window combo box entry and then click on the +New Snapshot button. With No delay +you get a cross as the mouse pointer and you have to click once with the &LMB; into +the window. The section of the window under the mouse cursor is now highlighted +with a red border. Move the mouse to the wanted section and click the &LMB; +to capture the screenshot. + + + + + +Additional Features + + +Snapshot Delay + +The Snapshot Delay: box allows you to enter an +arbitrary time delay, in seconds, between the time that you press the +New Snapshot button and the time that the snapshot is +taken. + +When a delay time has been set, you do not have to click the mouse +button to capture a screenshot. This enables you to open a drop down menu, +and take a picture of it. + + + + +Exclude Window decorations + +Include window decorations is enabled by default. + +When you only want to capture the application itself without the surrounding +window decoration, disable this option and take a new snapshot. + + + + +Print + +When you want to print your snapshot from the preview, just click +Print... and you get the standard &kde; Print dialog, from +where you can directly print your snapshot. + + + +Copy to Clipboard + +When you want to edit your snapshot in a graphics application without saving +the snapshot, just click Copy to Clipboard and insert the image +into a viewer or graphics application. + + + + +Buttons + +There are two further buttons located at the bottom of the +&ksnapshot; window. There function is described below. + + + +Help +Gives you a menu where you can open the +&ksnapshot; Handbook, report a bug or +get some more information About &ksnapshot; +and About &kde;. + + + + +Quit +Quits the &ksnapshot; application. + + + + + + + + + +&DCOP; Interface + +&ksnapshot; can be scripted using its &DCOP; interface. This +chapter explains the various &DCOP; calls that you can use, and +provides some examples of how you can use them. + +As with all &DCOP; calls, you need to specify the application +you want to interface with, and the particular interface. With &ksnapshot; +you need to identify which particular application, which is +ksnapshot- followed by the process number. + +To start &ksnapshot; and obtain the right argument, use +dcopstart ksnapshot, which returns the +argument (such as ksnapshot-20594) on +standard output. + +You can get a list of the available &DCOP; interfaces, use +the right arguments, as shown in this example: + +$ dcop `dcopstart ksnapshot` interface +QCStringList interfaces() +QCStringList functions() +QString url() +void slotGrab() +void slotPrint() +void slotSave() +bool save(QString filename) +void slotSaveAs() +void slotCopy() +void setTime(int newTime) +int timeout() +void setURL(QString newURL) +void setGrabMode(int grab) +int grabMode() +void slotMovePointer(int x,int y) +void exit() + + + + + +In the examples following, the process is always +ksnapshot-23151. + + + + +&DCOP; Access to Settings + +For each of the settings that you can control with the +&GUI;, you can both obtain the current status of that setting, +and modify the setting, using &DCOP;. + + +You can obtain the current capture mode using +grabMode, as shown below: + +$ dcop ksnapshot-23151 interface grabMode + +This will return 0 for full-screen capture, +1 for window capture, and 2 +for region capture. + + +You can set the capture mode using setGrabMode, +which requires an argument to identify the mode required (as for grabMode). +So you can set window capture mode (1), using: + +$ dcop ksnapshot-23151 interface setGrabMode 1 + + + +You can obtain the current timeout setting (the Snapshot delay: +GUI item) using timeout, as shown below: + +$ dcop ksnapshot-23151 interface timeout + +This will return the timeout setting in seconds, or zero if there is no delay +(capture on click). + + +You can set the timeout using setTime, +which requires an argument to identify the timeout duration. So you can +set a delay of 4 seconds using: + +$ dcop ksnapshot-23151 interface setTime 4 + + + +You can obtain the path that the snapshot will be saved to using +url, as shown below: + +$dcop ksnapshot-23151 interface url + +This will return the filename, as a &URL; (eg as +file:///home/bradh/test2.png). + + +You can set the path using setURL, +which requires a string argument to identify the new path. So you can +set the path to file:///home/bradh/snapshot.jpg +using: + +$ dcop ksnapshot-23151 interface setURL file:///home/bradh/snapshot.jpg + + + + + + +Taking Screenshots with &DCOP; + + +The key to taking screenshots with &DCOP; is use of slotGrab, +as shown below: + +$ dcop ksnapshot-23151 interface slotGrab + + + + +This will take a snapshot using the current snapshot mode and timeout settings +(as described above). If you want to save the snapshot image, there are a +number of calls you can use. If you just want to save the image to the current +path (as returned by url or changed by +setURL), you can use slotSave, as shown +below: + +$ dcop ksnapshot-23151 interface slotSave + + + + +If you want the user to be able to specify a filename (and path), you can use +slotSaveAs, which will bring up a standard &kde; file +save dialog. + + +If you want to save the image to a different name (or path) without +changing the path with setURL, you can use +save, providing the &URL; to save to as an argument. So if you +want to save the snapshot to file:///tmp/tempshot.png, you +can do the following: + +$ dcop ksnapshot-23151 interface save file:///tmp/tempshot.png + +Note that this will return true if the snapshot was successfully saved, and false +otherwise. Also, you should be aware that if the file already exists, the user +will get a standard &kde; dialog that requires the user to decide whether to overwrite +or not. + + + +In addition to saving the snapshot, you can also copy it to the clipboard, using +slotCopy, as shown below: + +$ dcop ksnapshot-23151 interface slotCopy + + + + +If you need to select a window that may not be under the mouse cursor, you +can use slotMovePointer, passing the x position +(in screen pixels) and the y position (also in screen pixels) as arguments. +So to move the mouse to the top left hand corner of the screen (0,0), you +can do the following: + +$ dcop ksnapshot-23151 interface slotMoveMouse 0 0 + + + + + +Printing Screenshots with &DCOP; + + +You can print the current screenshot (which may or may not have been saved) +using printSlot, as shown below: + +$ dcop ksnapshot-23151 interface slotPrint + + + + +Note that this will bring up the normal &kde; print dialog, which may require +user interaction. + + + + + +&DCOP; Application control + + +You can cause &ksnapshot; to exit by using exit, +as shown below. + +$ dcop ksnapshot-23151 interface exit + + + + + + + + + +Credits and License + +Program copyright + +1997-2000 &Richard.J.Moore; &Richard.J.Moore.mail; +2000 &Matthias.Ettrich; &Matthias.Ettrich.mail; + + +Documentation based on the original, copyright 1997-2000 &Richard.J.Moore; +&Richard.J.Moore.mail; + + +&underFDL; +&underGPL; + + + +&documentation.index; +
+ + + + + + diff --git a/doc/ksnapshot/preview.png b/doc/ksnapshot/preview.png new file mode 100644 index 00000000..0ee37a41 Binary files /dev/null and b/doc/ksnapshot/preview.png differ diff --git a/doc/ksnapshot/window.png b/doc/ksnapshot/window.png new file mode 100644 index 00000000..c4e99de7 Binary files /dev/null and b/doc/ksnapshot/window.png differ diff --git a/doc/kuickshow/Makefile.am b/doc/kuickshow/Makefile.am new file mode 100644 index 00000000..085981d9 --- /dev/null +++ b/doc/kuickshow/Makefile.am @@ -0,0 +1,4 @@ + +KDE_LANG = en +KDE_DOCS = AUTO + diff --git a/doc/kuickshow/index.docbook b/doc/kuickshow/index.docbook new file mode 100644 index 00000000..e454e2bf --- /dev/null +++ b/doc/kuickshow/index.docbook @@ -0,0 +1,1041 @@ + + + + + +]> + + + + + +The &kuickshow; Handbook + + + +Carsten +Pfeiffer + +
&Carsten.Pfeiffer.mail;
+
+
+ +
+ + +2001 +&Carsten.Pfeiffer; + + +&FDLNotice; + +2005-12-29 +0.8.7 + + + + + +&kuickshow; is a comfortable image browser/viewer. + + + + +KDE +kdegraphics +kuickshow +image +viewer + + +
+ + +Introduction + + +&kuickshow; is a comfortable image browser/viewer. It displays a +filebrowser where you can select images which are then shown. + + + + +The following image formats are supported: + +jpg + +gif + +tiff + +png + +bmp + +psd + +xpm + +ppm + +pgm + +pbm + +pnm + +eim + +xcf + + + +Images can be displayed either in their own window, as large as +the image, or fullscreen. + + + + +Using &kuickshow; + +Using &kuickshow; is very simple. The file browser lists files, +which you can select with a &LMB; click or the Return +key. + + +Here's a screenshot of &kuickshow; + + + + + + + + + Screenshot + + + + + + +More &kuickshow; features + +The options dialog makes available more possibilities: + + +Images can be automatically shrunk to fit onto the +screen, if they are larger. + +You can configure whether images should show up in +their own window, or always use the same window. + +You can set the delay time for a slide show. + +You can tell the browser which file types to show. + +You can tweak the speed/quality +ratio + + +If you are looking for a certain file, just enter the first few +characters of it's filename in the browser. A small edit window will +pop up in the bottom right corner. When a matching file is found, it +is highlighted. You can leave the edit window by pressing +Return or &Esc;. + + + + + +The <guilabel>&kuickshow; Configuration</guilabel> +Dialog + +The &kuickshow; Configuration dialog +contains 5 tabs. Three of them, General, Modifications +and Slideshow +configure the operation of &kuickshow;, and the other two, +Viewer Shortcuts +and Browser Shortcuts +allow you to personalize the shortcuts for the +respective windows. + + +<guilabel>General</guilabel> Options + +The General contains the options to +configure and tune &kuickshow;. + + + +Fullscreen mode + +If this is selected, images open in full screen mode. If the +image is not large enough to fill the screen, the rest of the screen +is filled with the background color selected below. The default is +off. + + + + +Preload next image + +If this is selected, &kuickshow; will load the next image in the +folder, while you are looking at the current one. This reduces the +delay when you select the next image, and is especially useful for +slide shows. + + + + +Remember last folder + +If this is selected, &kuickshow; saves the name of the last folder on exit. +On next start &kuickshow; will open this folder in the browser window. + + + + +Background color: + +Click on the colored bar to select a background color. This is +used to fill the screen in fullscreen mode, or the window, if you have +resized it larger than the image. + + + + +Show only files with extension: + +You can configure &kuickshow; to only show you some of the file +types it is capable of. + + + + + + +<guilabel>Quality/Speed</guilabel> + +Fast rendering +Render things fast. + + + + +Dither in HiColor (15/16bit) modes + + + + + + +Dither in LowColor (<=8bit) modes + + + + + + +Use own color palette + + + + + + +Fast palette remapping + + + + + + +Maximum cache size (MB): + + + + + + + + + + +The <guilabel>Modifications</guilabel> Tab + +Check Apply default image modifications to open an image +with these modifications in &kuickshow;. + + +<guilabel>Scaling</guilabel> + +Shrink image to screen size, if larger + +If this is selected, large images are displayed in maximized window. The default is +on. + + + + +Shrink image to screen size, if smaler, up to factor: + +If this is selected, &kuickshow; increases the magnification of small images up to +the selected factor. + + + + + + +<guilabel>Geometry</guilabel> + +Flip vertically +Flips the image vertically. + + + + +Flip horizontally +Flips the image horizontally. + + + + +Rotate image +Rotates the image to 0, 90, 180 or 270 degrees. + + + + + + + +<guilabel>Adjustments</guilabel> + +Brightness: +Lightens/darkens the image. + + + + +Contrast: +Adds/Removes contrast. + + + +Gamma: +More/less gamma. + + + + + + +A Preview of the Original +and Modified image is displayed below this options. + + + + +The <guilabel>Slideshow</guilabel> Tab + + + + +Switch to full-screen + +Indicates if &kuickshow; should switch to full-screen mode +when starting the slideshow. + + + + +Start with current image + +Indicates if the slideshow should start with the first +image in the folder or with the image which is selected. + + + + +Delay between slides: + +The length of time between image changes during the slideshow. +You can use the slider, type a new value into the field, +or use the small arrows to increase or decrease the value. The +default is 3 seconds. + + + + +Iterations (0 = infinite): + +The amount of iterations. If set to 0 it will loop untill you +abort the slideshow. You can use the slider, type a new value into the +field, or use the small arrows to increase or decrease the value. The +default is 1. + + + + + + + +The <guimenu>Shortcuts</guimenu> Tabs +Change the shortcuts for the different modes of &kuickshow; +in the Viewer Shortcuts and the Browser Shortcuts tabs. + + + + + +Menu Reference + + +The <guimenu>File</guimenu> Menu + + + + + +&Ctrl;O + +File +Open + +Opens a new image in &kuickshow;. + + + + +File +Show Image + +Displays the selected image in a new image +window. + + + + +File +Show Image in Aktive Window + +Displays the selected image in the active image +window. + + + + +File +Show Image in Fullscreen Mode + +Displays the selected image in fullscreen mode. + + + + + +F2 +File +Start Slideshow + +Starts a slideshow of the images in the folder. + + + + +&Ctrl; +P +File +Print Image... + +Prints the image. + + + + +&Ctrl;Q +File +Quit + +Quits &kuickshow;. If you have several +images windows open, all of them are closed. + + + + + + + +The <guimenu>Edit</guimenu> Menu + + + + +F10 +Edit +New Folder... + + +Create a new folder. + + + + + +&Shift;Delete +Edit +Delete + +Deletes the current file. You will be asked to confirm the +action. + + + + + +&Alt;Return +Edit +Properties + +Displays the properties of the current image file. + + + + + + +The <guimenu>View</guimenu> Menu + + + + +F6 +View +Short View + +If this option is selected, only the names of the files and folders will be shown. +Compare this to detailed view. + + + + +F7 +View +Detailed View + +If this option is selected, the names, sizes, dates, permissions, file owners and group ownerships are shown. +Compare this to short view. + + + + +F8 +View +Show Hidden Files + +This will toggle between revealing and hiding normally hidden files. + + + + +F12 +View +Separate Folders + +Use this option to toggle between a 2 pane view of the file system (one pane for the folders +and one pane for the files) and a one pane view of the file system with folders and files. + + + + +View +Large Icons + +Display the image files in the folder with large icons. +This item is only available in Short View mode. + + + + +View +Small Icons + +Display the image files in the folder with small icons. +This item is only available in Short View mode. + + + + +View +Thumbnail Previews + +Display a preview of the images in the folder. This item is only available in Short View mode. + + + + +&Ctrl;- +View +Zoom Out + +Reduces the image size by ten percent. Again +this refers to the current size of the +image. + + + + +&Ctrl;+ +View +Zoom In + +Enlarges the image by ten percent. Notice that +this refers to the current size of the +picture. + + + + + + +The <guimenu>Settings</guimenu> Menu + + + + +Settings +Configure &kuickshow;... + +Opens a dialog for changing some options as +described in the section + + + + + + + +The <guimenu>Help</guimenu> Menu + + + + + + +F1 + +Help +&kappname; Handbook + + +Invokes the &kde; Help system starting at the +&kappname; help pages. (this document). + + + + +Help +Report Bug... + +Opens the Bug report dialog where you can +report a bug or request a wishlist feature. + + + + +Help +About &kappname; + +This will display version and author +information. + + + + +Help +About KDE + +This displays the &kde; version and other basic +information. + + + + + + + + +Command Reference + + +The Image Window + +All the shortcuts are configurable from the Configuration Dialog. + + +Image Window Keyboard Shortcuts + + + +Key +Action + + + + +Page Down +Load the next image + + +Page Up +Load the previous image + + +Home +Loads the first image + + +End +Loads the last image + + ++ +Zooms into the image + + +- +Zooms out of the image + + +* +Flips the image horizontally + + +/ +Flips the image vertically + + +7 +Rotates 270° clockwise (which is also 90° +counter-clockwise) + + +8 +Rotates 90° clockwise + + +9 +Rotates 180° clockwise + + +Arrow keys +Move the image (or rather, you, the viewer,) if it is larger +than the screen + + +Return +Toggles between fullscreen and window mode + + +Space +Toggles the display of the browser + + +&Esc; +Closes the image window. This will close &kuickshow; entirely, +if you don't have a browser window open. + + +B/&Shift;B +Lightens/darkens the image + + +C/&Shift;C +Adds/Removes contrast + + +G/&Shift;G +More/less gamma + + +O +Shows the image in original size. This is only useful when you +have enabled automatic scaling. + + +Enter +Redisplays the image with the default settings and +size. + + +&Ctrl;S +Opens the Save As dialog + + +Delete +Deletes the current image. You will be asked to confirm the +request. + + +&Shift;Delete +Deletes the current image without asking for +confirmation + + +&Alt;Return +Displays the properties of the image + + +F1 +Opens the online help (this file) + + +&Ctrl;W +Quits &kuickshow; + + + +
+ + +Image Window Mouse Usage + + + +Mouse button +Action + + + + +Right click +Opens the context menu, with several options + + +Left drag +Moves the image, if it doesn't fit in the window. + + +&Shift;Left + drag +Marks a rectangle you can zoom into. + + +Left double click +Closes the current image + + + +
+ +
+ + +The Browser Window + + +Browser Window Keybindings + + + +Keybinding +Action + + + + +Return +Enters a folder, or opens an image window, depending on the +item selected. + + +Page Down +Advances one page in the list of files + + +Page Up +Moves back up a page in the list of files + + +Home +Selects the first file or folder + + +End +Selects the last file or folder + + +Space +Toggles showing the browser, if an image window is open + + +any alpha-numeric character +Opens the edit field used for completion. Enter +the first characters of a filename to search for, and if found, the +file will be selected. + + +&Ctrl;G +Go to — lets you enter a folder to go +to. + + +Delete +Deletes the current file. You will be asked to confirm the +action. + + +&Shift;Delete +Deletes the current file without asking for +confirmation. + + +F1 +Opens the online help (this file) + + +&Ctrl;Q +Quits &kuickshow; + + + +
+ + +Browser Window Mouse Usage + + + +Mouse Usage +Action + + + + +Left click +Enter a folder, or select an image window. + + +Right click +Opens a context menu, with several options. + + +Double click +Loads the selected image or enters the selected +folder + + + + +
+ +
+
+ + + + + +Credits and License + + +&kuickshow; + + +Program copyright 1998-2002 &Carsten.Pfeiffer; &Carsten.Pfeiffer.mail; + + + +Documentation copyright 2001 &Carsten.Pfeiffer; &Carsten.Pfeiffer.mail; + +Converted to DocBook &XML; and extended by &Lauri.Watts; +&Lauri.Watts.mail; + + + +&underFDL; + +&underGPL; + + + + +Installation + + +How to obtain &kuickshow; + +&install.intro.documentation; + + + + +Requirements + +To be written + + + + + + +Compilation and Installation + +&install.compile.documentation; + + + + + +&documentation.index; +
+ + + diff --git a/doc/kuickshow/screenshot.png b/doc/kuickshow/screenshot.png new file mode 100644 index 00000000..a57bd4c7 Binary files /dev/null and b/doc/kuickshow/screenshot.png differ diff --git a/doc/kview/Makefile.am b/doc/kview/Makefile.am new file mode 100644 index 00000000..085981d9 --- /dev/null +++ b/doc/kview/Makefile.am @@ -0,0 +1,4 @@ + +KDE_LANG = en +KDE_DOCS = AUTO + diff --git a/doc/kview/index.docbook b/doc/kview/index.docbook new file mode 100644 index 00000000..e1ddbbdf --- /dev/null +++ b/doc/kview/index.docbook @@ -0,0 +1,835 @@ + + + + + +]> + + + + +The &kview; Handbook + + + +Hauke +Hildebrandt + +
&Hauke.Hildebrandt.mail;
+
+
+ + +Sirtaj +Singh +Kang +Developer + + + +Lauri +Watts +
&Lauri.Watts.mail;
+Reviewer +
+ +
+ + + +2001 +&Hauke.Hildebrandt; + + +&FDLNotice; + +2006-05-20 +3.5.2 + +&kview; is an image viewing program. It is small and fast and +has some simple image processing commands. You can work with many different +graphic file formats and convert your images to them. &kview; is not a +fully-fledged image processor but it is sufficient for many of your everyday +tasks. + + +KDE +kview +kdegraphics +image +graphic +viewer + + +
+ + +Introduction + +&kview; is an image viewer for the &kde; desktop. You can view +graphics of many different formats such as &PostScript;, +TIFF &etc; By saving your files in a different +format than the original you can easily convert images to other +graphics formats. In addition, &kview; provides some nice little +features for doing simple image processing, like stretching/shrinking, +rotation and applying effects. You can arrange your images in a little +slideshow. + + + + +Menu Reference + +When you start &kview; you see the typical application layout: a +workspace containing your documents (images in this case), a menubar that +provides access to the various commands, a toolbar with shortcut buttons for +some of them and a status bar at the bottom to display status messages. When +you have the loaded an image into &kview;, there is also an additional +context menu available which is displayed by clicking your right mouse +button over the image. Below, all menu entries are explained in the order +that they appear in the menubar. + + +The <guimenu>File</guimenu> Menu + + + + + +&Ctrl;O + +File +Open... + +Opens a new image in &kview;. The size of the +&kview; main window and the image after loading are determined by your +settings. If you open several images, only the last one is shown, but all of +them can be accessed using the image list. + + + + +File +Open Recent + +Displays a list of recently opened images. +Selecting one from this list reopens the image. + + + + +&Ctrl;S +File +Save + +Save the current image. + + + + +File +Save As + +Saves the image under a different name. By +choosing a new file format you can convert the image to a different graphics +type. + + + + +&Ctrl; +P +File +Print... + +Prints the image. In the standard &kde; print dialog +click the Options >> button, go to the tab Image +Settings. Select Fit image to page size or +Center image on page. + + + + +&Ctrl;W +File +Close + +Closes the currently displayed +image. + + + + +&Ctrl;Q +File +Quit + +Quits &kview;. If you have several &kview; +images open, all of them are closed. + + + + + + + +The <guimenu>Edit</guimenu> Menu + + + +&Ctrl; +C +Edit +Copy + + +Copies the entire image or the selection to the clipboard. + + + + +&Ctrl; +V +Edit +Paste + + +Paste the contents of the clipboard as a new image (only available, if the clipboard contains a valid image). + + + + +C +Edit +Crop + + +If you have selected any part of the image (by drawing a box around it +using your mouse) you can cut off all the rest around it by using this +option. Your image is effectively reduced to your selection. + + + + +F5 +Edit +Reload + +Reloads the image to its original state (right +after opening it). + + + + +&Shift;Delete +Edit +Delete + +Deletes the image. + + + +V +Edit +Flip +Vertical + +Flips the image along the +vertical. Mathematically, this does a reflection along the image's +horizontal center line. + + + +H +Edit +Flip +Horizontal + +Flips the image along the +horizontal. Mathematically, this does a reflection along the image's +vertical center line. + + + + +Edit +Rotate Counter-Clockwise + +Rotates the image by 90° in the counter-clockwise +direction. + + + + +Edit +Rotate Clockwise + +Rotates the image by 90° in the clockwise +direction. + + + + + + +The <guimenu>Effects</guimenu> Menu + +&kview; provides some functions for simple image processing: + +This menu item is only displayed in the menubar, if you choose the +application plugin effects in &kview;s configure dialog + + + + +Effects +Gamma Correction... + +Adjusts the gamma factor. + + + + +Effects +Blend Color... + +Blends the image to selected color and opacity + + + + +Effects +Change Intensity (Brightness)... + +Changes the brightness of the image. Enter the +new brightness in percent (with respect to the initial +value). + + + + + + +The <guimenu>View</guimenu> Menu + + + + +&Ctrl;+ +View +Zoom In + +Enlarges the image by ten percent. Notice that +this refers to the current size of the +picture. + + + + +View +Zoom... + +Opens a list to choose the zoom +factor. This value is given in percent and always refers to the +initial size of the picture. + + + + +&Ctrl;- +View +Zoom Out + +Reduces the image size by ten percent. Again +this refers to the current size of the +image. + + + + +ViewFit Image +to Window +Maximizes the image size. The image is scaled +to the window size, keeping the aspect +ratio. + + + + + + +The <guimenu>Go</guimenu> Menu + +This item is only displayed in the menubar, if you choose the +application plugin presenter in &kview;s configure dialog + + + + +Go +Image List... + +Displays a list of the currently loaded images. +You can flip through the images by either double-clicking on them or using the +Previous and Next +buttons. Shuffle rearranges the images in a random order. +Pressing +Start Slideshow will start the slideshow with the current +settings for the interval. In addition, you can save and load your image +list using the corresponding buttons. +Slideshow interval: +Here you can change the interval between the different slides for the slideshow. + + + +S +Go +Start/Stop Slideshow + +Starts or stops the +slideshow. + + + + +&Alt;Left Arrow +Go +Previous Image in List + +Switches to the previous image in the +list. + + + + +&Alt;Right Arrow +Go +Next Image in List +Switches to the next item in the +list. + + + + + + +The <guimenu>Tools</guimenu> Menu + + + + + +Tools +Scan Image... + +Opens images from your scanner into &kview;. +This menu item is only displayed in the menubar, if you choose the +application plugin scanner in &kview;s configure dialog + + + + + +&Shift;Left Arrow +Tools +Back + +Switches to the previous image in the current +folder. + + + + +&Shift;Right Arrow +Tools +Forward + +Switches to the next image in the current +folder. + + + + + + +The <guimenu>Settings</guimenu> Menu +This menu provides options for configuring &kview;, changing its +appearance, shortcuts and standard behavior. + + + + +&Ctrl;M +Settings +Show/Hide Menubar + +Toggles the menubar on/off. + + + +Settings +Toolbars +Main Toolbar (KView) + +Settings +Toolbars +Extra Toolbar (KView) + + +Toggles the main toolbar and the extra toolbar on and off +respectively + + + + + +Settings +Show/Hide Statusbar + +Toggles the status bar on/off. + + + + +Settings +Show/Hide Scrollbars + +Toggles the Scrollbars on/off. + + + +&Ctrl; +&Shift;F +Settings +Fullscreen Mode + + +This option maximizes the &kview; window and the currently shown image so +you can have a closer look at it. Even the window decorations (titlebar &etc;) are +temporarily removed. Selecting this option once again switches back to normal +mode. + + + + + +Settings +Configure Shortcuts... + +Opens a dialog for changing the key bindings. +Using this option you can change the standard key shortcut for &kview;'s commands +or create new ones. + + + + +Settings +Configure Toolbars... + +Opens a dialog for configuring the toolbar. You +can add and remove toolbuttons for &kview;'s commands with this +option. + + + + +Settings +Configure &kview;... + +Opens a dialog for changing some options as +described in the section + + + + + + +The <guimenu>Help</guimenu> Menu + +&help.menu.documentation; + + + + + +Command Line Options + +&kview; can be started directly from a terminal like &konsole; or +xterm. Several command line options are +available. + + + +kview +Lists the command line options (see below). + + +kview +Shows the options specific to &Qt; (the &GUI; +library that &kde; is based on). + + +kview +Shows the &kde;-specific options. + + +kview +Displays all command line options. + + +kview +You want to send your warm wishes and euphoric cheers to +someone? Here they are! + + +kview , + +Displays the version number of &kview; (and that of +&Qt;/&kde;). + + +kview +Shows under which licenses &kview; is being +published. + + + + + +&kview; Options + + +<guilabel>Viewer</guilabel> + +This is the configuration for the part of &kview; that can be reused +by other applications (meaning that the settings will also affect the &kview; +part that gets embedded into &konqueror; or other applications). + + +&kview; viewer configuration dialog + + +&kview; viewer configuration dialog + + + + +General configuration options for KViewCanvas + +Use smooth scaling (high quality but +slower) + +As the option suggests, use a very high quality but relatively slow +method of scaling images. + + + +Keep aspect ratio + +If this is checked &kview; will always try to keep the aspect +ratio. That means if the width is scaled with a factor x, the height is +scaled with the same factor. + + + + +Center image + +If checked, the opened image will be displayed centered to the &kview; +window. + + + + +Background Color + +Opens a normal &kde; color picker dialog, where you can choose the +background color for the image + + + + +Minimum width: + +The width of the image shown will not get smaller than the size you +enter here. A value of 10 would cause a 1x1 image to be stretched +horizontally by a factor of 10. + + + + +Maximum width: + +The width of the image shown will not get bigger than the size you +enter here. A value of 100 would cause a 1000x1000 image to be compressed +horizontally by a factor of 0.1. + + + + +Minimum height: + +The height of the image shown will not get smaller than the size you +enter here. A value of 10 would cause a 1x1 image to be stretched vertically +by a factor of 10. + + + + +Maximum height: + +The height of the image shown will not get bigger than the size you +enter here. A value of 100 would cause a 1000x1000 image to be compressed +vertically by a factor of 0.1. + + + + +Choose which blend effects should be used: + +Every effect selected may be used to create a transition effect +between the images. If you select multiple effects they will be chosen +randomly. + + + + + + +<guilabel>Chooose and Configure Your Plugins</guilabel> + +Browser + +Here you can enable/disable use of the browser &kview; plugin, which +enables you to browse through all the images in the current folder. + + + + + + + +<guilabel>Application</guilabel> + +Here you can set options that are special for the &kview; application +when running stand-alone. What you change in here will not affect other +applications. + + +&kview; application configuration dialog + + +&kview; application configuration dialog + + + + +<guilabel>Application</guilabel> + +Resizing +This option determines if the window and/or the image will be +resized after loading a new picture into &kview;. With Only resize +window enabled, the &kview; window will be resized so that it snuggly +fits around the loaded image. Notice that this can reduce the main window almost +to a vertical arrangement of menu entries if you load a small button pixmap (you +can resize the window afterwards in the usual way, of course). If your image is +pretty large (in terms of pixels), sometimes the &kview; window is resized in +such a way that the caption bar completely moves off your screen. Similarly, +Resize image to fit window resizes the image to fit into the &kview; +workspace (keeping its aspect ratio intact). And with Don't +resize anything as your choice, both &kview; and your image keep their +size. With Best fit +&kview; will resize the window to fit the image. The image will never be +scaled up but if it is too large for the screen the image will be scaled down. + + + + + +<guilabel>Plugins</guilabel> + +Effects + +Provides some image effects (and adds an Effects to +the menubar to give you access to them). + + + + +Presenter + +Creates an image list and enables you to create a slideshow. + + + + +Scanner + +Adds Scan Image... to the Tools +menu to open images from your scanner into &kview;. + + + + + + + + +Credits and License + +&kview; + +Program copyright 1997-2001 Sirtaj S. Kang +&Sirtaj.Singh.Kang.mail; +KParts integration by &Simon.Hausmann; +shaus@neuro2.med.uni-magdeburg.de +Maintainer: Matthias Kretz kretz@kde.org +Documentation copyright 2001 &Hauke.Hildebrandt; +&Hauke.Hildebrandt.mail; + + +Documentation substantially updated by Burkhard Lück +lueck@hube-lueck.de in 2005 for &kde; 3.5 + + +&underFDL; +&underGPL; + + + + +Installation + + +How to obtain &kview; + +&install.intro.documentation; + +&install.compile.documentation; + + + + +Requirements + +Since &kview; is part of the &kde; desktop you need a working &kde; +installation to use it. However, some additional libraries are needed by &kview; +to use the various graphics file formats. For example, to handle the +PNG format &kview; needs the corresponding library +libpng. &kview; uses the libraries that are registered by +kdelibs/kimgio. + + + + + +&documentation.index; +
+ diff --git a/doc/kview/kview-application-configuration.png b/doc/kview/kview-application-configuration.png new file mode 100644 index 00000000..0ba79356 Binary files /dev/null and b/doc/kview/kview-application-configuration.png differ diff --git a/doc/kview/kview-viewer-configuration.png b/doc/kview/kview-viewer-configuration.png new file mode 100644 index 00000000..f2e6d8c2 Binary files /dev/null and b/doc/kview/kview-viewer-configuration.png differ diff --git a/kamera/AUTHORS b/kamera/AUTHORS new file mode 100644 index 00000000..b278e9ce --- /dev/null +++ b/kamera/AUTHORS @@ -0,0 +1,4 @@ + Copyright (C) 2001 The Kompany + 2001-2003 Ilya Konstantinov + 2001-2007 Marcus Meissner + 2003 Nadeem Hasan diff --git a/kamera/Makefile.am b/kamera/Makefile.am new file mode 100644 index 00000000..f012f4a1 --- /dev/null +++ b/kamera/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = kcontrol kioslave pics diff --git a/kamera/README b/kamera/README new file mode 100644 index 00000000..592a84f4 --- /dev/null +++ b/kamera/README @@ -0,0 +1,5 @@ +Dependencies: + +You need libgphoto 2.0 final (or later). + +libgphoto2 2.3.1 or newer is recommended. diff --git a/kamera/configure.in.in b/kamera/configure.in.in new file mode 100644 index 00000000..3e2fd1c6 --- /dev/null +++ b/kamera/configure.in.in @@ -0,0 +1,182 @@ +dnl KDE_FIND_GPHOTO2 - Find gphoto2 libraries and include files +dnl +dnl Adapted from kdebase/nsplugins/configure.in.in + +AC_DEFUN([KDE_FIND_GPHOTO2], +[ + + + +# Clear working variables +gphoto2_includes= +gphoto2_libraries= + + + +# Process user input to configure +AC_ARG_WITH(kamera, +AC_HELP_STRING([--without-kamera],[do not build kamera (gphoto2 required)]), +[if test "$withval" = "no" ; then + gphoto2_includes=none + gphoto2_libraries=none +fi])dnl + +AC_ARG_WITH(gphoto2-includes, +AC_HELP_STRING([--with-gphoto2-includes=DIR],[gphoto2 include files are in DIR]), +gphoto2_includes="$withval") + +AC_ARG_WITH(gphoto2-libraries, +AC_HELP_STRING([--with-gphoto2-libraries=DIR],[gphoto2 libraries are in DIR]), +gphoto2_libraries="$withval") + +AC_MSG_CHECKING(for gPhoto2) +# the pkg-config way first, if user did not use --with- +AC_CHECK_PROG(gphoto2_config,gphoto2-config,gphoto2-config,no) +AC_CHECK_PROG(gphoto2_port_config,gphoto2-port-config,gphoto2-port-config,no) +if test "$gphoto2_includes" = "" -a "$gphoto2_libraries" = "" -a "$gphoto2_config" != "no" -a "$gphoto2_port_config" != "no" +then + with_kamera="yes" + GPHOTO2_INCS="`$gphoto2_config --cflags` `$gphoto2_port_config --cflags`" + GPHOTO2_LIBS="`$gphoto2_config --libs` `$gphoto2_port_config --libs`" +else +# +# Search for gphoto2 include files. +# + if test "$gphoto2_includes" = ""; then + AC_CACHE_VAL(ac_cv_gphoto2_includes, [ + ac_gphoto2_save_LIBS="$LIBS" + LIBS="-lgphoto2 $LIBS" + ac_cv_gphoto2_includes="none" + AC_TRY_COMPILE([#include ],[int a;], + [ + # gphoto2.h is in the standard search path. + ac_cv_gphoto2_includes= + ],[ + # gphoto2.h is not in the standard search path. + # Locate it and put its directory in `gphoto2_includes' + for dir in /usr/include /usr/local/include \ + /usr/include/gphoto2 /usr/local/include/gphoto2; do + if test -f "$dir/gphoto2.h"; then + ac_cv_gphoto2_includes="$dir" + break + fi + done + ]) + # + LIBS="$ac_gphoto2_save_LIBS" + ]) + gphoto2_includes="$ac_cv_gphoto2_includes" + fi + + # + # Search for libgphoto2 + # + if test "$gphoto2_libraries" = ""; then + AC_CACHE_VAL(ac_cv_gphoto2_libraries,[ + ac_gphoto2_save_LIBS="$LIBS" + LIBS="-lgphoto2_port -lgphoto2 $LIBS" + ac_cv_gphoto2_libraries="none" + AC_TRY_LINK([#include ],[gp_context_progress_start(0,0,0,0);], [ + # libgphoto2 is in the standard search path. + ac_cv_gphoto2_libraries= + ],[ + # libgphoto2 is not in the standard search path. + # Locate it and put its directory in `gphoto2_libraries' + for dir in /usr/lib /usr/local/lib; do + if test -d "$dir" && test "`ls $dir/libgphoto2.* 2> /dev/null`" != ""; then + ac_cv_gphoto2_libraries="$dir" + break + fi + done + ]) + # + LIBS="$ac_gphoto2_save_LIBS" + ]) + # + gphoto2_libraries="$ac_cv_gphoto2_libraries" + fi +# Initialise compiler and linker flag variables for export + if test "$gphoto2_includes" = "none" -o "$gphoto2_libraries" = "none" ; then + with_kamera="no" + else + with_kamera="yes" + + if test "$gphoto2_libraries" = "" -o "$gphoto2_libraries" = "none"; then + GPHOTO2_LIBS="-lgphoto2" + else + GPHOTO2_LIBS="-L$gphoto2_libraries -lgphoto2" + fi + if test "$gphoto2_includes" != "" -a "$gphoto2_includes" != "none"; then + GPHOTO2_INCS="-I$gphoto2_includes" + fi + fi +fi + +if test "$with_kamera" = "yes" ; then + # Check if it works. + ac_gphoto2_save_LIBS="$LIBS" + ac_gphoto2_save_CFLAGS="$CFLAGS" + LIBS="$LIBS $GPHOTO2_LIBS" + CFLAGS="$CFLAGS $GPHOTO2_INCS" + AC_TRY_LINK([#include ],[gp_context_progress_start(0,0,0,0);], [ + # It works. + AC_DEFINE(HAVE_GPHOTO2,1,[Define if you have gPhoto2 installed]) + ],[ + with_kamera="no" + ]) + LIBS="$ac_gphoto2_save_LIBS" + CFLAGS="$ac_gphoto2_save_CFLAGS" +fi +dnl **** Check for va_copy **** +AC_CACHE_CHECK([for va_copy], ac_cv_c_va_copy, + AC_TRY_LINK( + [#include ], + [va_list ap1, ap2; + va_copy(ap1,ap2); + ], + [ac_cv_c_va_copy="yes"], + [ac_cv_c_va_copy="no"]) + ) +if test "$ac_cv_c_va_copy" = "yes" +then + AC_DEFINE(HAVE_VA_COPY, 1, [Define if we have va_copy]) +fi +AC_CACHE_CHECK([for __va_copy], ac_cv_c___va_copy, + AC_TRY_LINK( + [#include ], + [va_list ap1, ap2; + __va_copy(ap1,ap2); + ], + [ac_cv_c___va_copy="yes"], + [ac_cv_c___va_copy="no"]) + ) +if test "$ac_cv_c___va_copy" = "yes" +then + AC_DEFINE(HAVE___VA_COPY, 1, [Define if we have __va_copy]) +fi + +# Export compiler and linker flags for replacement in Makefile +AC_SUBST(GPHOTO2_INCS) +AC_SUBST(GPHOTO2_LIBS) + + +# Display results of configuration +gphoto2_libraries_result="$gphoto2_libraries" +gphoto2_includes_result="$gphoto2_includes" + +test "$gphoto2_libraries" = "" && gphoto2_libraries_result="in default path" +test "$gphoto2_includes" = "" && gphoto2_includes_result="in default path" + +test "$gphoto2_libraries" = "none" && gphoto2_libraries_result="(none)" +test "$gphoto2_includes" = "none" && gphoto2_includes_result="(none)" + +AC_MSG_RESULT( + [gphoto2 libraries $gphoto2_libraries_result, gphoto2 headers $gphoto2_includes_result]) + +]) dnl end of KDE_FIND_GPHOTO2 definition + +KDE_FIND_GPHOTO2 +if test "$with_kamera" = "no"; then +dnl AC_MSG_WARN([You need to install gphoto 2.0 (or later), e.g. http://gphoto.net/dist/gphoto2-2.0.tar.gz if your distributor doesn't have a package]) + DO_NOT_COMPILE="$DO_NOT_COMPILE kamera" +fi diff --git a/kamera/kcontrol/Makefile.am b/kamera/kcontrol/Makefile.am new file mode 100644 index 00000000..9fd30f46 --- /dev/null +++ b/kamera/kcontrol/Makefile.am @@ -0,0 +1,16 @@ +kde_module_LTLIBRARIES = kcm_kamera.la + +kcm_kamera_la_SOURCES = kamera.cpp kameradevice.cpp kameraconfigdialog.cpp + +kcm_kamera_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kcm_kamera_la_LIBADD = $(LIB_KIO) $(GPHOTO2_LIBS) +INCLUDES= $(all_includes) $(GPHOTO2_INCS) + +kcm_kamera_la_METASOURCES = AUTO + +noinst_HEADERS = kamera.h kameradevice.h kameraconfigdialog.h + +messages: + $(XGETTEXT) $(kcm_kamera_la_SOURCES) -o $(podir)/kcmkamera.pot + +xdg_apps_DATA = kamera.desktop diff --git a/kamera/kcontrol/kamera.cpp b/kamera/kcontrol/kamera.cpp new file mode 100644 index 00000000..0fdc416a --- /dev/null +++ b/kamera/kcontrol/kamera.cpp @@ -0,0 +1,423 @@ +/* + + Copyright (C) 2001 The Kompany + 2002-2003 Ilya Konstantinov + 2002-2003 Marcus Meissner + 2003 Nadeem Hasan + + 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kameraconfigdialog.h" +#include "kameradevice.h" +#include "kamera.h" +#include "kamera.moc" + +typedef KGenericFactory KKameraConfigFactory; +K_EXPORT_COMPONENT_FACTORY( kcm_kamera, KKameraConfigFactory( "kcmkamera" ) ) + +// --------------- Camera control center module widget --- + +KKameraConfig *KKameraConfig::m_instance = NULL; + +KKameraConfig::KKameraConfig(QWidget *parent, const char *name, const QStringList &) + : KCModule(KKameraConfigFactory::instance(), parent, name) +{ + m_devicePopup = new KPopupMenu(this); + m_actions = new KActionCollection(this); + m_config = new KSimpleConfig(KProtocolInfo::config("camera")); + + m_context = gp_context_new(); + if (m_context) { + + // Register the callback functions + gp_context_set_cancel_func(m_context, cbGPCancel, this); + gp_context_set_idle_func(m_context, cbGPIdle, this); + + displayGPSuccessDialogue(); + + // load existing configuration + load(); + + } else { + + displayGPFailureDialogue(); + } + + // store instance for frontend_prompt + m_instance = this; +} + +KKameraConfig::~KKameraConfig() +{ + delete m_config; +} + +void KKameraConfig::defaults() +{ + load( true ); +} + +void KKameraConfig::displayGPFailureDialogue(void) +{ + new QLabel(i18n("Unable to initialize the gPhoto2 libraries."), this); +} + +void KKameraConfig::displayGPSuccessDialogue(void) +{ + // set the kcontrol module buttons + setButtons(Help | Apply | Cancel | Ok); + + // create a layout with two vertical boxes + QVBoxLayout *topLayout = new QVBoxLayout(this, 0, 0); + topLayout->setAutoAdd(true); + + m_toolbar = new KToolBar(this, "ToolBar"); + m_toolbar->setMovingEnabled(false); + + // create list of devices + m_deviceSel = new KIconView(this); + + connect(m_deviceSel, SIGNAL(rightButtonClicked(QIconViewItem *, const QPoint &)), + SLOT(slot_deviceMenu(QIconViewItem *, const QPoint &))); + connect(m_deviceSel, SIGNAL(doubleClicked(QIconViewItem *)), + SLOT(slot_configureCamera())); + connect(m_deviceSel, SIGNAL(selectionChanged(QIconViewItem *)), + SLOT(slot_deviceSelected(QIconViewItem *))); + + m_deviceSel->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); + + // create actions + KAction *act; + + act = new KAction(i18n("Add"), "camera", 0, this, SLOT(slot_addCamera()), m_actions, "camera_add"); + act->setWhatsThis(i18n("Click this button to add a new camera.")); + act->plug(m_toolbar); + m_toolbar->insertLineSeparator(); + act = new KAction(i18n("Test"), "camera_test", 0, this, SLOT(slot_testCamera()), m_actions, "camera_test"); + act->setWhatsThis(i18n("Click this button to remove the selected camera from the list.")); + act->plug(m_toolbar); + act = new KAction(i18n("Remove"), "edittrash", 0, this, SLOT(slot_removeCamera()), m_actions, "camera_remove"); + act->setWhatsThis(i18n("Click this button to remove the selected camera from the list.")); + act->plug(m_toolbar); + act = new KAction(i18n("Configure..."), "configure", 0, this, SLOT(slot_configureCamera()), m_actions, "camera_configure"); + act->setWhatsThis(i18n("Click this button to change the configuration of the selected camera.

The availability of this feature and the contents of the Configuration dialog depend on the camera model.")); + act->plug(m_toolbar); + act = new KAction(i18n("Information"), "hwinfo", 0, this, SLOT(slot_cameraSummary()), m_actions, "camera_summary"); + act->setWhatsThis(i18n("Click this button to view a summary of the current status of the selected camera.

The availability of this feature and the contents of the Configuration dialog depend on the camera model.")); + act->plug(m_toolbar); + m_toolbar->insertLineSeparator(); + act = new KAction(i18n("Cancel"), "stop", 0, this, SLOT(slot_cancelOperation()), m_actions, "camera_cancel"); + act->setWhatsThis(i18n("Click this button to cancel the current camera operation.")); + act->setEnabled(false); + act->plug(m_toolbar); +} + +void KKameraConfig::populateDeviceListView(void) +{ + m_deviceSel->clear(); + CameraDevicesMap::Iterator it; + for (it = m_devices.begin(); it != m_devices.end(); it++) { + if (it.data()) { + new QIconViewItem(m_deviceSel, it.key(), DesktopIcon("camera")); + } + } + slot_deviceSelected(m_deviceSel->currentItem()); +} + +void KKameraConfig::save(void) +{ + CameraDevicesMap::Iterator it; + + for (it = m_devices.begin(); it != m_devices.end(); it++) + { + it.data()->save(m_config); + } + m_config->sync(); +} + +void KKameraConfig::load(void) +{ + load( false ); +} + +void KKameraConfig::load(bool useDefaults ) +{ + m_config->setReadDefaults( useDefaults ); + QStringList groupList = m_config->groupList(); + QStringList::Iterator it; + int i, count; + CameraList *list; + CameraAbilitiesList *al; + GPPortInfoList *il; + const char *model, *value; + KCamera *kcamera; + + for (it = groupList.begin(); it != groupList.end(); it++) { + if (*it != "") { + m_config->setGroup(*it); + if (m_config->readEntry("Path").contains("usb:")) + continue; + + kcamera = new KCamera(*it,m_config->readEntry("Path")); + connect(kcamera, SIGNAL(error(const QString &)), SLOT(slot_error(const QString &))); + connect(kcamera, SIGNAL(error(const QString &, const QString &)), SLOT(slot_error(const QString &, const QString &))); + kcamera->load(m_config); + m_devices[*it] = kcamera; + } + } + m_cancelPending = false; + + gp_list_new (&list); + + gp_abilities_list_new (&al); + gp_abilities_list_load (al, m_context); + gp_port_info_list_new (&il); + gp_port_info_list_load (il); + gp_abilities_list_detect (al, il, list, m_context); + gp_abilities_list_free (al); + gp_port_info_list_free (il); + + count = gp_list_count (list); + + QMap ports, names; + + for (i = 0 ; i::iterator portit; + + for (portit = ports.begin() ; portit != ports.end(); portit++) { + /* kdDebug() << "Adding USB camera: " << portit.data() << " at " << portit.key() << endl; */ + + kcamera = new KCamera(portit.data(),portit.key()); + connect(kcamera, SIGNAL(error(const QString &)), SLOT(slot_error(const QString &))); + connect(kcamera, SIGNAL(error(const QString &, const QString &)), SLOT(slot_error(const QString &, const QString &))); + m_devices[portit.data()] = kcamera; + } + populateDeviceListView(); + + gp_list_free (list); + + emit changed( useDefaults ); +} + +void KKameraConfig::beforeCameraOperation(void) +{ + m_cancelPending = false; + + m_actions->action("camera_test")->setEnabled(false); + m_actions->action("camera_remove")->setEnabled(false); + m_actions->action("camera_configure")->setEnabled(false); + m_actions->action("camera_summary")->setEnabled(false); + + m_actions->action("camera_cancel")->setEnabled(true); +} + +void KKameraConfig::afterCameraOperation(void) +{ + m_actions->action("camera_cancel")->setEnabled(false); + + // if we're regaining control after a Cancel... + if (m_cancelPending) { + qApp->restoreOverrideCursor(); + m_cancelPending = false; + } + + // if any item was selected before the operation was run + // it makes sense for the relevant toolbar buttons to be enabled + slot_deviceSelected(m_deviceSel->currentItem()); +} + +QString KKameraConfig::suggestName(const QString &name) +{ + QString new_name = name; + new_name.replace("/", ""); // we cannot have a slash in a URI's host + + if (!m_devices.contains(new_name)) return new_name; + + // try new names with a number appended until we find a free one + int i = 1; + while (i++ < 0xffff) { + new_name = name + " (" + QString::number(i) + ")"; + if (!m_devices.contains(new_name)) return new_name; + } + + return QString::null; +} + +void KKameraConfig::slot_addCamera() +{ + KCamera *m_device = new KCamera(QString::null,QString::null); + connect(m_device, SIGNAL(error(const QString &)), SLOT(slot_error(const QString &))); + connect(m_device, SIGNAL(error(const QString &, const QString &)), SLOT(slot_error(const QString &, const QString &))); + KameraDeviceSelectDialog dialog(this, m_device); + if (dialog.exec() == QDialog::Accepted) { + dialog.save(); + m_device->setName(suggestName(m_device->model())); + m_devices.insert(m_device->name(), m_device); + populateDeviceListView(); + emit changed(true); + } else { + delete m_device; + } +} + +void KKameraConfig::slot_removeCamera() +{ + QString name = m_deviceSel->currentItem()->text(); + if (m_devices.contains(name)) { + KCamera *m_device = m_devices[name]; + m_devices.remove(name); + delete m_device; + m_config->deleteGroup(name, true); + populateDeviceListView(); + emit changed(true); + } +} + +void KKameraConfig::slot_testCamera() +{ + beforeCameraOperation(); + + QString name = m_deviceSel->currentItem()->text(); + if (m_devices.contains(name)) { + KCamera *m_device = m_devices[name]; + if (m_device->test()) + KMessageBox::information(this, i18n("Camera test was successful.")); + } + + afterCameraOperation(); +} + +void KKameraConfig::slot_configureCamera() +{ + QString name = m_deviceSel->currentItem()->text(); + if (m_devices.contains(name)) { + KCamera *m_device = m_devices[name]; + m_device->configure(); + } +} + +void KKameraConfig::slot_cameraSummary() +{ + QString summary; + QString name = m_deviceSel->currentItem()->text(); + if (m_devices.contains(name)) { + KCamera *m_device = m_devices[name]; + summary = m_device->summary(); + if (!summary.isNull()) { + KMessageBox::information(this, summary); + } + } +} + +void KKameraConfig::slot_cancelOperation() +{ + m_cancelPending = true; + // Prevent the user from keeping clicking Cancel + m_actions->action("camera_cancel")->setEnabled(false); + // and indicate that the click on Cancel did have some effect + qApp->setOverrideCursor(Qt::WaitCursor); +} + +void KKameraConfig::slot_deviceMenu(QIconViewItem *item, const QPoint &point) +{ + if (item) { + m_devicePopup->clear(); + m_actions->action("camera_test")->plug(m_devicePopup); + m_actions->action("camera_remove")->plug(m_devicePopup); + m_actions->action("camera_configure")->plug(m_devicePopup); + m_actions->action("camera_summary")->plug(m_devicePopup); + m_devicePopup->popup(point); + } +} + +void KKameraConfig::slot_deviceSelected(QIconViewItem *item) +{ + m_actions->action("camera_test")->setEnabled(item); + m_actions->action("camera_remove")->setEnabled(item); + m_actions->action("camera_configure")->setEnabled(item); + m_actions->action("camera_summary")->setEnabled(item); +} + +void KKameraConfig::cbGPIdle(GPContext * /*context*/, void * /*data*/) +{ + /*KKameraConfig *self( reinterpret_cast(data) );*/ + + qApp->processEvents(); +} + +GPContextFeedback KKameraConfig::cbGPCancel(GPContext * /*context*/, void *data) +{ + KKameraConfig *self( reinterpret_cast(data) ); + + // Since in practice no camera driver supports idle callbacks yet, + // we'll use the cancel callback as opportunity to process events + qApp->processEvents(); + + // If a cancel request is pending, ask gphoto to cancel + if (self->m_cancelPending) + return GP_CONTEXT_FEEDBACK_CANCEL; + else + return GP_CONTEXT_FEEDBACK_OK; +} + +QString KKameraConfig::quickHelp() const +{ + return i18n("

Digital Camera

\n" + "This module allows you to configure support for your digital camera.\n" + "You would need to select the camera's model and the port it is connected\n" + "to on your computer (e.g. USB, Serial, Firewire). If your camera doesn't\n" + "appear in the list of Supported Cameras, go to the\n" + "
GPhoto web site for a possible update.

\n" + "To view and download images from the digital camera, go to address\n" + "camera:/ in Konqueror and other KDE applications."); +} + +void KKameraConfig::slot_error(const QString &message) +{ + KMessageBox::error(this, message); +} + +void KKameraConfig::slot_error(const QString &message, const QString &details) +{ + KMessageBox::detailedError(this, message, details); +} + diff --git a/kamera/kcontrol/kamera.desktop b/kamera/kcontrol/kamera.desktop new file mode 100644 index 00000000..0fda1401 --- /dev/null +++ b/kamera/kcontrol/kamera.desktop @@ -0,0 +1,193 @@ +[Desktop Entry] +Comment=Configure Kamera +Comment[af]=Konfigureer Kamera +Comment[ar]=إعداد Kamera +Comment[az]=Kameranı Quraşdır +Comment[bg]=Настройване на цифров фотоапарат +Comment[br]=Kefluniañ Kamera +Comment[bs]=Podesi kameru +Comment[ca]=Configura Kamera +Comment[cs]=Nastavení Kamery +Comment[cy]=Ffurfweddu Kamera +Comment[da]=Indstil kamera +Comment[de]=Kamera einrichten +Comment[el]=Ρύθμιση Kamera +Comment[eo]=Agordu fotilon +Comment[es]=Configura Kamera +Comment[et]=Kaamera seadistamine +Comment[eu]=Konfiguratu Kamera +Comment[fa]=پیکربندی Kamera +Comment[fi]=Kameran asetukset +Comment[fr]=Configuration de Kamera +Comment[ga]=Cumraigh Kamera +Comment[gl]=Configurar Kamera +Comment[he]=שינוי הגדרות Kamera +Comment[hi]=कॉन्फ़िगर केमरा +Comment[hr]=Podesi Kameru +Comment[hu]=A digitális fényképezőgépek beállításai +Comment[id]=Konfigurasi kamera +Comment[is]=Stilla samskiptaforrit stafrænna myndavéla (Kamera) +Comment[it]=Configura Kamera +Comment[ja]=カメラの設定 +Comment[kk]=Kamera баптаулары +Comment[km]=កំណត់​រចនាសម្ព័ន្ធ Kamera +Comment[ko]=카메라 설정 +Comment[lt]=Konfigūruoti Kamera +Comment[mk]=Конфигурирајте ја Kamera +Comment[ms]=Konfigurasi Kamera +Comment[mt]=Ikkonfigura Kamera +Comment[nb]=Tilpass Kamera +Comment[nds]=Kamera instellen +Comment[ne]=क्यामेरा कन्फिगर गर्नुहोस् +Comment[nl]=Camera instellen +Comment[nn]=Set opp Kamera +Comment[nso]=Beakanya Kamera +Comment[pa]=ਕੈਮਰਾ ਸੰਰਚਨਾ +Comment[pl]=Konfiguracja Kamery +Comment[pt]=Configuração do Kamera +Comment[pt_BR]=Configurar Kamera +Comment[ro]=Configurează aparatul foto digital +Comment[ru]=Настройка камеры +Comment[se]=Heivet govvenapperáhta +Comment[sk]=Nastaviť program Kamera +Comment[sl]=Nastavitve fotoaparata +Comment[sr]=Подеси Kamera-у +Comment[sr@Latn]=Podesi Kamera-u +Comment[sv]=Anpassa kamera +Comment[ta]=காமிராவை அமை +Comment[tg]=Танзимоти камера +Comment[th]=ปรับแต่ง Kamera +Comment[tr]=Kamera'yı Yapılandır +Comment[uk]=Налаштувати Kamera +Comment[uz]=Fotoaparatni moslash +Comment[uz@cyrillic]=Фотоапаратни мослаш +Comment[ven]=Dzudzanya kamera +Comment[xh]=Qwalasela Umfoti +Comment[zh_CN]=配置 Kamera +Comment[zh_HK]=設定 Kamera +Comment[zh_TW]=設定照相機 +Comment[zu]=Hlanganisa ikhamera +Keywords=gphoto,camera,digicam,webcam,kamera +Keywords[ar]=gphoto,كاميرا,كاميرا رقمية,كاميرا ويب,kamera +Keywords[az]=gphoto,kamera,digicam,veb kamera,Kamera,webcam +Keywords[bg]=фото, апарат, фотоапарат, камера, цифров, цифрова, gphoto, camera, digicam, webcam, kamera +Keywords[br]=gphoto,kamera,digicam,webcam,kamera +Keywords[ca]=gphoto,càmera,digicam,webcam,kamera +Keywords[cs]=gphoto,Kamera,Digitální kamera,Webová kamera,Foto +Keywords[da]=gphoto,kamera,digicam,webcam +Keywords[de]=gphoto,Kamera,Digicam,Webcam,Digitalkamera +Keywords[el]=gphoto,κάμερα,digicam,webcam,kamera +Keywords[eo]=gphoto,kamerao,fotilo,cifereca fotilo,TTT-fotilo +Keywords[es]=gphoto,cámara,digicam,webcam,kamera +Keywords[et]=gphoto,kaamera,digitaalkaamera,veebikaamera,kamera +Keywords[eu]=gphoto,kamera,digicam,webcam,kamera +Keywords[fa]=gphoto، دوربین، دوربین رقمی، دوربین وب، kamera +Keywords[fi]=gphoto,kamera,digicam,webcam +Keywords[fr]=gphoto,camera,digicam,webcam,kamera,caméscope,caméra,appareil photo +Keywords[he]=gphoto,kamera,מצלמה,מצלמת רשת,מצלמה דיגיטלית, amera,digicam,webcam +Keywords[hi]=जीफोटो,केमरा,डिजिकेम,वेबकेम,केमरा +Keywords[hu]=gphoto,fényképezőgép,digitális fényképezőgép,webkamera,videókamera +Keywords[is]=gphoto,myndavél,stafræn myndavél,webcam,kamera +Keywords[it]=gphoto,fotocamera,macchina fotografica digitale,webcam,kamera +Keywords[ja]=gphoto,カメラ,デジカム,ウェブカム,kamera +Keywords[km]=gphoto,ម៉ាស៊ីន​ថត​រូប,digicam,ម៉ាស៊ីនថត​តាម​បណ្ដាញ,kamera +Keywords[ko]=gphoto,camera,digicam,webcam,kamera,사진,카메라,사진기,웹캠 +Keywords[lv]=gfoto,camera,digicam,webcam,kamera +Keywords[nb]=gphoto,kamera,digicam,webcam,webkamera +Keywords[nds]=gphoto,Kamera,Webcam,Kamera,Nettkamera +Keywords[ne]=जी फोटो, क्यामेरा, डिजिक्याम, वेबक्याम, कामेरा +Keywords[nl]=gphoto,camera,digicam,webcam,kamera,foto +Keywords[nn]=gphoto,fotoapparat,digitalt kamera,webkamera,vevkamera,kamera +Keywords[pl]=gphoto,kamera,kamera cyfrowa,kamera sieciowa +Keywords[pt]=gphoto,câmara,digicam,webcam,kamera +Keywords[pt_BR]=gphoto,câmera,câmera digital,webcam,kamera +Keywords[ro]=gphoto,aparat,foto,digicam,webcam,camera,kamera +Keywords[ru]=gphoto,camera,digicam,webcam,kamera,камера,фото +Keywords[sl]=gphoto,kamera,digicam,webcam,foto,fotoaparat,spletna kamera +Keywords[sr]=gphoto,camera,digicam,webcam,kamera,камера +Keywords[sr@Latn]=gphoto,camera,digicam,webcam,kamera,kamera +Keywords[sv]=gphoto,kamera,digital kamera,webbkamera,kamera +Keywords[ta]=ஜிபோட்டோ, காமிரா, டிஜிகேம்,வலைதள காமிரா, காமிரா +Keywords[tg]=gphoto,camera,digicam,webcam,kamera,камера,фото +Keywords[tr]=gphoto,kamera,digicam,web kamera,Kamera,webcam +Keywords[uk]=gphoto,камера,цифрова камера,камера Тенет,kamera +Keywords[ven]=Tshinepe tsha g,Tshaudzhia zwifanyiso,digicam,webcam,Tshaudzhiazwifanyiso +Keywords[xh]=gphoto,umfoti,digicam,webcam,umfoti +Keywords[zh_CN]=gphoto,camera,digicam,webcam,kamera,照相机,数码相机,摄像头 +Keywords[zh_TW]=gphoto,camera,digicam,webcam,kamera,照相機 +Keywords[zu]=gphoto,ikhamera,digicam,webcam,ikhamera +Name=Digital Camera +Name[af]=Digitaal Kamera +Name[ar]=كاميرا رقمية +Name[az]=Digital Kamera +Name[bg]=Фотоапарат +Name[br]=Kamera niverel +Name[bs]=Digitalna kamera +Name[ca]=Càmera digital +Name[cs]=Digitální fotoaparát +Name[cy]=Camera Digidol +Name[da]=Digitalt kamera +Name[de]=Digitalkamera +Name[el]=Ψηφιακή κάμερα +Name[eo]=Cifereca fotilo +Name[es]=Cámara digital +Name[et]=Digitaalkaamera +Name[eu]=Kamera digitala +Name[fa]=دوربین رقمی +Name[fi]=Digitaalikamera +Name[fr]=Appareil photo numérique +Name[ga]=Ceamara Digiteach +Name[gl]=Cámara dixital +Name[he]=מצלמה דיגיטלית +Name[hi]=डिजिटल कैमरा +Name[hr]=Digitalna kamera +Name[hu]=Digitális fényképezőgép +Name[is]=Stafræn myndavél +Name[it]=Macchina fotografica digitale +Name[ja]=デジタルカメラ +Name[kk]=Цифрлық камера +Name[km]=ម៉ាស៊ីន​ថតរូប​ឌីជីថល +Name[lt]=Skaitmeninė kamera +Name[lv]=Digitālā Kamera +Name[mk]=Дигитална камера +Name[ms]=Kamera Digital +Name[mt]=Kamera diġitali +Name[nb]=Digitalkamera +Name[nds]=Digitaalkamera +Name[ne]= डिजिटल क्यामेरा +Name[nl]=Digitale camera +Name[nn]=Digitalkamera +Name[nso]=Camera ya Digital +Name[pa]=ਡਿਜ਼ੀਟਲ ਕੈਮਰਾ +Name[pl]=Aparat cyfrowy +Name[pt]=Máquina Fotográfica Digital +Name[pt_BR]=Câmera Digital +Name[ro]=Aparat foto digital +Name[ru]=Цифровая камера +Name[se]=Digitalalaš govvenapperáhtta +Name[sk]=Digitálny fotoaparát +Name[sl]=Digitalni fotoaparat +Name[sr]=Дигитална камера +Name[sr@Latn]=Digitalna kamera +Name[sv]=Digitalkamera +Name[ta]= Digital Camera +Name[tg]=Камераи digital +Name[th]=กล้องดิจิตอล +Name[tr]=Sayısal Kamera +Name[uk]=Цифровий фотоапарат +Name[uz]=Fotoaparat +Name[uz@cyrillic]=Фотоапарат +Name[ven]=Tshau dzhia zwifanyiso tsha didzhithala +Name[xh]=Ikhamera Yesuntswana +Name[zh_CN]=数码相机 +Name[zh_HK]=數碼相機 +Name[zh_TW]=數位相機 +Name[zu]=Ikhamera ebonisa inani ngalinye +Terminal=false +Type=Application +X-KDE-Library=kamera +X-KDE-ModuleType=Library +Icon=camera +Exec=kcmshell kamera +DocPath=kamera/index.html +Categories=Qt;KDE;Settings;X-KDE-settings-hardware; diff --git a/kamera/kcontrol/kamera.h b/kamera/kcontrol/kamera.h new file mode 100644 index 00000000..35f93bc0 --- /dev/null +++ b/kamera/kcontrol/kamera.h @@ -0,0 +1,115 @@ +/* + + Copyright (C) 2001 The Kompany + 2002-2003 Ilya Konstantinov + 2002-2003 Marcus Meissner + 2003 Nadeem Hasan + + 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 __kamera_h__ +#define __kamera_h__ + +#include +#include + +class QWidget; +class QRadioButton; +class QPushButton; +class QComboBox; +class QVButtonGroup; +class QLineEdit; +class QWidgetStack; +class QCheckBox; +class QIconViewItem; + +class KCamera; +class KameraDeviceSelectDialog; +class KSimpleConfig; +class KIconView; +class KActionCollection; +class KToolBar; +class KPopupMenu; + +class KKameraConfig : public KCModule +{ + Q_OBJECT + friend class KameraDeviceSelectDialog; + +public: + KKameraConfig(QWidget *parent, const char *name, const QStringList &); + virtual ~KKameraConfig(); + + // KCModule interface methods + void load(); + void load(bool useDefaults); + void save(); + void defaults(); + int buttons(); + QString quickHelp() const; + +protected: + QString suggestName(const QString &name); + +protected slots: + void slot_deviceMenu(QIconViewItem *item, const QPoint &point); + void slot_deviceSelected(QIconViewItem *item); + void slot_addCamera(); + void slot_removeCamera(); + void slot_configureCamera(); + void slot_cameraSummary(); + void slot_testCamera(); + void slot_cancelOperation(); + void slot_error(const QString &message); + void slot_error(const QString &message, const QString &details); + +private: + void displayGPFailureDialogue(void); + void displayGPSuccessDialogue(void); + void displayCameraAbilities(const CameraAbilities &abilities); + void populateDeviceListView(void); + void beforeCameraOperation(void); + void afterCameraOperation(void); + + // gphoto callbacks + static void cbGPIdle(GPContext *context, void *data); + static GPContextFeedback cbGPCancel(GPContext *context, void *data); + +private: + typedef QMap CameraDevicesMap; + + KSimpleConfig *m_config; + CameraDevicesMap m_devices; + bool m_cancelPending; + + // gphoto members + GPContext *m_context; + + // widgets for the cameras listview + KIconView *m_deviceSel; + KActionCollection *m_actions; + QPushButton *m_addCamera, *m_removeCamera, *m_testCamera, *m_configureCamera; + KToolBar *m_toolbar; + KPopupMenu *m_devicePopup; + + // true if libgphoto2 was initialised successfully in + // the constructor + bool m_gpInitialised; + + static KKameraConfig *m_instance; +}; + +#endif diff --git a/kamera/kcontrol/kameraconfigdialog.cpp b/kamera/kcontrol/kameraconfigdialog.cpp new file mode 100644 index 00000000..5af0b33d --- /dev/null +++ b/kamera/kcontrol/kameraconfigdialog.cpp @@ -0,0 +1,317 @@ +/* + + Copyright (C) 2001 The Kompany + 2002-2003 Ilya Konstantinov + 2002-2003 Marcus Meissner + 2003 Nadeem Hasan + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "kameraconfigdialog.h" +#include "kameraconfigdialog.moc" + +KameraConfigDialog::KameraConfigDialog(Camera */*camera*/, + CameraWidget *widget, + QWidget *parent, + const char *name) : +KDialogBase(parent, name, true, QString::null, Ok|Cancel, Ok ), +m_widgetRoot(widget) +{ + QFrame *main = makeMainWidget(); + QVBoxLayout *topLayout = new QVBoxLayout(main, 0, spacingHint()); + topLayout->setAutoAdd(true); + + m_tabWidget = 0; + + appendWidget(main, widget); +} + +void KameraConfigDialog::appendWidget(QWidget *parent, CameraWidget *widget) +{ + QWidget *newParent = parent; + + CameraWidgetType widget_type; + const char *widget_name; + const char *widget_info; + const char *widget_label; + float widget_value_float; + int widget_value_int; + const char *widget_value_string; + gp_widget_get_type(widget, &widget_type); + gp_widget_get_label(widget, &widget_label); + gp_widget_get_info(widget, &widget_info); + gp_widget_get_name(widget, &widget_name); + + QString whats_this = QString::fromLocal8Bit(widget_info); // gphoto2 doesn't seem to have any standard for i18n + + // Add this widget to parent + switch(widget_type) { + case GP_WIDGET_WINDOW: + { + setCaption(widget_label); + + break; + } + case GP_WIDGET_SECTION: + { + if (!m_tabWidget) + m_tabWidget = new QTabWidget(parent); + QWidget *tab = new QWidget(m_tabWidget); + // widgets are to be aligned vertically in the tab + QVBoxLayout *tabLayout = new QVBoxLayout(tab, marginHint(), + spacingHint()); + m_tabWidget->insertTab(tab, widget_label); + QVBox *tabContainer = new QVBox(tab); + tabContainer->setSpacing(spacingHint()); + tabLayout->addWidget(tabContainer); + newParent = tabContainer; + + tabLayout->addStretch(); + + break; + } + case GP_WIDGET_TEXT: + { + gp_widget_get_value(widget, &widget_value_string); + + QGrid *grid = new QGrid(2, Horizontal, parent); + grid->setSpacing(spacingHint()); + new QLabel(QString::fromLocal8Bit( widget_label )+":", grid); + QLineEdit *lineEdit = new QLineEdit(widget_value_string, grid); + m_wmap.insert(widget, lineEdit); + + if (!whats_this.isEmpty()) + QWhatsThis::add(grid, whats_this); + + break; + } + case GP_WIDGET_RANGE: + { + float widget_low; + float widget_high; + float widget_increment; + gp_widget_get_range(widget, &widget_low, &widget_high, &widget_increment); + gp_widget_get_value(widget, &widget_value_float); + + QGroupBox *groupBox = new QVGroupBox(widget_label, parent); + QSlider *slider = new QSlider( + ( int )widget_low, + ( int )widget_high, + ( int )widget_increment, + ( int )widget_value_float, + QSlider::Horizontal, + groupBox ); + m_wmap.insert(widget, slider); + + if (!whats_this.isEmpty()) + QWhatsThis::add(groupBox, whats_this); + + break; + } + case GP_WIDGET_TOGGLE: + { + gp_widget_get_value(widget, &widget_value_int); + + QCheckBox *checkBox = new QCheckBox(widget_label, parent); + checkBox->setChecked(widget_value_int); + m_wmap.insert(widget, checkBox); + + if (!whats_this.isEmpty()) + QWhatsThis::add(checkBox, whats_this); + + break; + } + case GP_WIDGET_RADIO: + { + gp_widget_get_value(widget, &widget_value_string); + + int count = gp_widget_count_choices(widget); + + // for less than 5 options, align them horizontally + QButtonGroup *buttonGroup; + if (count > 4) + buttonGroup = new QVButtonGroup(widget_label, parent); + else + buttonGroup = new QHButtonGroup(widget_label, parent); + + for(int i = 0; i < count; ++i) { + const char *widget_choice; + gp_widget_get_choice(widget, i, &widget_choice); + + new QRadioButton(widget_choice, buttonGroup); + if(!strcmp(widget_value_string, widget_choice)) + buttonGroup->setButton(i); + } + m_wmap.insert(widget, buttonGroup); + + if (!whats_this.isEmpty()) + QWhatsThis::add(buttonGroup, whats_this); + + break; + } + case GP_WIDGET_MENU: + { + gp_widget_get_value(widget, &widget_value_string); + + QComboBox *comboBox = new QComboBox(FALSE, parent); + comboBox->clear(); + for(int i = 0; i < gp_widget_count_choices(widget); ++i) { + const char *widget_choice; + gp_widget_get_choice(widget, i, &widget_choice); + + comboBox->insertItem(widget_choice); + if(!strcmp(widget_value_string, widget_choice)) + comboBox->setCurrentItem(i); + } + m_wmap.insert(widget, comboBox); + + if (!whats_this.isEmpty()) + QWhatsThis::add(comboBox, whats_this); + + break; + } + case GP_WIDGET_BUTTON: + { + // TODO + // I can't see a way of implementing this. Since there is + // no way of telling which button sent you a signal, we + // can't map to the appropriate widget->callback + new QLabel(i18n("Button (not supported by KControl)"), parent); + + break; + } + case GP_WIDGET_DATE: + { + // TODO + new QLabel(i18n("Date (not supported by KControl)"), parent); + + break; + } + default: + return; + } + + // Append all this widgets children + for(int i = 0; i < gp_widget_count_children(widget); ++i) { + CameraWidget *widget_child; + gp_widget_get_child(widget, i, &widget_child); + appendWidget(newParent, widget_child); + } + + // Things that must be done after all children were added +/* + switch (widget_type) { + case GP_WIDGET_SECTION: + { + tabLayout->addItem( new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding) ); + break; + } + } +*/ +} + +void KameraConfigDialog::updateWidgetValue(CameraWidget *widget) +{ + CameraWidgetType widget_type; + gp_widget_get_type(widget, &widget_type); + + switch(widget_type) { + case GP_WIDGET_WINDOW: + // nothing to do + break; + case GP_WIDGET_SECTION: + // nothing to do + break; + case GP_WIDGET_TEXT: + { + QLineEdit *lineEdit = static_cast(m_wmap[widget]); + gp_widget_set_value(widget, (void *)lineEdit->text().local8Bit().data()); + + break; + } + case GP_WIDGET_RANGE: + { + QSlider *slider = static_cast(m_wmap[widget]); + float value_float = slider->value(); + gp_widget_set_value(widget, (void *)&value_float); + + break; + } + case GP_WIDGET_TOGGLE: + { + QCheckBox *checkBox = static_cast(m_wmap[widget]); + int value_int = checkBox->isChecked() ? 1 : 0; + gp_widget_set_value(widget, (void *)&value_int); + + break; + } + case GP_WIDGET_RADIO: + { + QButtonGroup *buttonGroup = static_cast(m_wmap[widget]); + gp_widget_set_value(widget, (void *)buttonGroup->selected()->text().local8Bit().data()); + + break; + } + case GP_WIDGET_MENU: + { + QComboBox *comboBox = static_cast(m_wmap[widget]); + gp_widget_set_value(widget, (void *)comboBox->currentText().local8Bit().data()); + + break; + } + case GP_WIDGET_BUTTON: + // nothing to do + break; + case GP_WIDGET_DATE: + { + // not implemented + break; + } + } + + // Copy child widget values + for(int i = 0; i < gp_widget_count_children(widget); ++i) { + CameraWidget *widget_child; + gp_widget_get_child(widget, i, &widget_child); + updateWidgetValue(widget_child); + } +} + +void KameraConfigDialog::slotOk() +{ + // Copy Qt widget values into CameraWidget hierarchy + updateWidgetValue(m_widgetRoot); + + // 'ok' dialog + accept(); +} diff --git a/kamera/kcontrol/kameraconfigdialog.h b/kamera/kcontrol/kameraconfigdialog.h new file mode 100644 index 00000000..73b2a012 --- /dev/null +++ b/kamera/kcontrol/kameraconfigdialog.h @@ -0,0 +1,53 @@ +/* + + Copyright (C) 2001 The Kompany + 2002-2003 Ilya Konstantinov + 2002-2003 Marcus Meissner + 2003 Nadeem Hasan + + 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 __kameraconfigdialog_h__ +#define __kameraconfigdialog_h__ + +#include +#include +#include + +extern "C" { + #include +} + +class KameraConfigDialog : public KDialogBase +{ + Q_OBJECT +public: + KameraConfigDialog(Camera *camera, CameraWidget *widget, + QWidget *parent = 0, const char *name = 0); + +private slots: + void slotOk(); + +private: + void appendWidget(QWidget *parent, CameraWidget *widget); + void updateWidgetValue(CameraWidget *widget); + + QMap m_wmap; + CameraWidget *m_widgetRoot; + QTabWidget *m_tabWidget; +}; + +#endif diff --git a/kamera/kcontrol/kameradevice.cpp b/kamera/kcontrol/kameradevice.cpp new file mode 100644 index 00000000..010bf694 --- /dev/null +++ b/kamera/kcontrol/kameradevice.cpp @@ -0,0 +1,476 @@ +/* + + Copyright (C) 2001 The Kompany + 2002-2003 Ilya Konstantinov + 2002-2003 Marcus Meissner + 2003 Nadeem Hasan + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern "C" { + #include +} + +#include "kamera.h" +#include "kameraconfigdialog.h" +#include "kameradevice.moc" + +// Define some parts of the old API +#define GP_PROMPT_OK 0 +#define GP_PROMPT_CANCEL -1 + +static const int INDEX_NONE= 0; +static const int INDEX_SERIAL = 1; +static const int INDEX_USB= 3; +static GPContext *glob_context = 0; + +KCamera::KCamera(const QString &name, const QString &path) +{ + m_name = name; + m_model = name; + m_path = path; + m_camera = NULL; +} + +KCamera::~KCamera() +{ + if(m_camera) + gp_camera_free(m_camera); + if(m_abilitylist) + gp_abilities_list_free(m_abilitylist); +} + +bool KCamera::initInformation() +{ + if (!m_model) + return false; + + if(gp_abilities_list_new(&m_abilitylist) != GP_OK) { + emit error(i18n("Could not allocate memory for abilities list.")); + return false; + } + if(gp_abilities_list_load(m_abilitylist, glob_context) != GP_OK) { + emit error(i18n("Could not load ability list.")); + return false; + } + int index = gp_abilities_list_lookup_model(m_abilitylist, m_model.local8Bit().data()); + if(index < 0) { + emit error(i18n("Description of abilities for camera %1 is not available." + " Configuration options may be incorrect.").arg(m_model)); + return false; + } + gp_abilities_list_get_abilities(m_abilitylist, index, &m_abilities); + return true; +} + +bool KCamera::initCamera() +{ + if (m_camera) + return m_camera; + else { + int result; + + initInformation(); + + if (!m_model || !m_path) + return false; + + result = gp_camera_new(&m_camera); + if (result != GP_OK) { + // m_camera is not initialized, so we cannot get result as string + emit error(i18n("Could not access driver. Check your gPhoto2 installation.")); + return false; + } + + // set the camera's model + GPPortInfo info; + GPPortInfoList *il; + gp_port_info_list_new(&il); + gp_port_info_list_load(il); + gp_port_info_list_get_info(il, gp_port_info_list_lookup_path(il, m_path.local8Bit().data()), &info); + gp_port_info_list_free(il); + gp_camera_set_abilities(m_camera, m_abilities); + gp_camera_set_port_info(m_camera, info); + + // this might take some time (esp. for non-existant camera) - better be done asynchronously + result = gp_camera_init(m_camera, glob_context); + if (result != GP_OK) { + gp_camera_free(m_camera); + m_camera = NULL; + emit error( + i18n("Unable to initialize camera. Check your port settings and camera connectivity and try again."), + gp_result_as_string(result)); + return false; + } + + return m_camera; + } +} + +Camera* KCamera::camera() +{ + initCamera(); + return m_camera; +} + +QString KCamera::summary() +{ + int result; + CameraText summary; + + initCamera(); + + result = gp_camera_get_summary(m_camera, &summary, glob_context); + if (result != GP_OK) + return i18n("No camera summary information is available.\n"); + return QString(summary.text); +} + +bool KCamera::configure() +{ + CameraWidget *window; + int result; + + initCamera(); + + result = gp_camera_get_config(m_camera, &window, glob_context); + if (result != GP_OK) { + emit error(i18n("Camera configuration failed."), gp_result_as_string(result)); + return false; + } + + KameraConfigDialog kcd(m_camera, window); + result = kcd.exec() ? GP_PROMPT_OK : GP_PROMPT_CANCEL; + + if (result == GP_PROMPT_OK) { + result = gp_camera_set_config(m_camera, window, glob_context); + if (result != GP_OK) { + emit error(i18n("Camera configuration failed."), gp_result_as_string(result)); + return false; + } + } + + return true; +} + +bool KCamera::test() +{ + // TODO: Make testing non-blocking (maybe via KIO?) + // Currently, a failed serial test times out at about 30 sec. + return camera() != 0; +} + +void KCamera::load(KConfig *config) +{ + config->setGroup(m_name); + if (m_model.isNull()) + m_model = config->readEntry("Model"); + if (m_path.isNull()) + m_path = config->readEntry("Path"); + invalidateCamera(); +} + +void KCamera::save(KConfig *config) +{ + config->setGroup(m_name); + config->writeEntry("Model", m_model); + config->writeEntry("Path", m_path); +} + +QString KCamera::portName() +{ + QString port = m_path.left(m_path.find(":")).lower(); + if (port == "serial") return i18n("Serial"); + if (port == "usb") return i18n("USB"); + return i18n("Unknown port"); +} + +void KCamera::setName(const QString &name) +{ + m_name = name; +} + +void KCamera::setModel(const QString &model) +{ + m_model = model; + invalidateCamera(); + initInformation(); +} + +void KCamera::setPath(const QString &path) +{ + m_path = path; + invalidateCamera(); +} + +void KCamera::invalidateCamera() +{ + if (m_camera) { + gp_camera_free(m_camera); + m_camera = NULL; + } +} + +bool KCamera::isTestable() const +{ + return true; +} + +bool KCamera::isConfigurable() +{ + initInformation(); + return m_abilities.operations & GP_OPERATION_CONFIG; +} + +QStringList KCamera::supportedPorts() +{ + initInformation(); + QStringList ports; + if (m_abilities.port & GP_PORT_SERIAL) + ports.append("serial"); + if (m_abilities.port & GP_PORT_USB) + ports.append("usb"); + return ports; +} + +CameraAbilities KCamera::abilities() +{ + return m_abilities; +} + +// ---------- KameraSelectCamera ------------ + +KameraDeviceSelectDialog::KameraDeviceSelectDialog(QWidget *parent, KCamera *device) + : KDialogBase(parent, "kkameradeviceselect", true, i18n("Select Camera Device"), Ok | Cancel, Ok, true) +{ + m_device = device; + connect(m_device, SIGNAL(error(const QString &)), + SLOT(slot_error(const QString &))); + connect(m_device, SIGNAL(error(const QString &, const QString &)), + SLOT(slot_error(const QString &, const QString &))); + + QWidget *page = new QWidget( this ); + setMainWidget(page); + + // a layout with vertical boxes + QHBoxLayout *topLayout = new QHBoxLayout(page, 0, KDialog::spacingHint()); + + // the models list + m_modelSel = new KListView(page); + topLayout->addWidget( m_modelSel ); + m_modelSel->addColumn(i18n("Supported Cameras")); + m_modelSel->setColumnWidthMode(0, QListView::Maximum); + connect(m_modelSel, SIGNAL(selectionChanged(QListViewItem *)), + SLOT(slot_setModel(QListViewItem *))); + // make sure listview only as wide as it needs to be + m_modelSel->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, + QSizePolicy::Preferred)); + + QVBoxLayout *rightLayout = new QVBoxLayout(0L, 0, KDialog::spacingHint()); + topLayout->addLayout( rightLayout ); + + m_portSelectGroup = new QVButtonGroup(i18n("Port"), page); + rightLayout->addWidget(m_portSelectGroup); + m_portSettingsGroup = new QVGroupBox(i18n("Port Settings"), page); + rightLayout->addWidget(m_portSettingsGroup); + + // Create port type selection radiobuttons. + m_serialRB = new QRadioButton(i18n("Serial"), m_portSelectGroup); + m_portSelectGroup->insert(m_serialRB, INDEX_SERIAL); + QWhatsThis::add(m_serialRB, i18n("If this option is checked, the camera would have to be connected one of the serial ports (known as COM in Microsoft Windows) in your computer.")); + m_USBRB = new QRadioButton(i18n("USB"), m_portSelectGroup); + m_portSelectGroup->insert(m_USBRB, INDEX_USB); + QWhatsThis::add(m_USBRB, i18n("If this option is checked, the camera would have to be connected to one of the USB slots in your computer or USB hub.")); + // Create port settings widget stack + m_settingsStack = new QWidgetStack(m_portSettingsGroup); + connect(m_portSelectGroup, SIGNAL(clicked(int)), + m_settingsStack, SLOT(raiseWidget(int))); + + // none tab + m_settingsStack->addWidget(new QLabel(i18n("No port type selected."), + m_settingsStack), INDEX_NONE); + + // serial tab + QGrid *grid = new QGrid(2, m_settingsStack); + grid->setSpacing(KDialog::spacingHint()); + new QLabel(i18n("Port:"), grid); + m_serialPortCombo = new QComboBox(TRUE, grid); + QWhatsThis::add(m_serialPortCombo, i18n("Here you should choose the serial port you connect the camera to.")); + m_settingsStack->addWidget(grid, INDEX_SERIAL); + + grid = new QGrid(2, m_settingsStack); + grid->setSpacing(KDialog::spacingHint()); + new QLabel(i18n("Port"), grid); + + m_settingsStack->addWidget(new + QLabel(i18n("No further configuration is required for USB."), + m_settingsStack), INDEX_USB); + + // query gphoto2 for existing serial ports + GPPortInfoList *list; + GPPortInfo info; + int gphoto_ports=0; + gp_port_info_list_new(&list); + if(gp_port_info_list_load(list) >= 0) { + gphoto_ports = gp_port_info_list_count(list); + } + for (int i = 0; i < gphoto_ports; i++) { + if (gp_port_info_list_get_info(list, i, &info) >= 0) { + if (strncmp(info.path, "serial:", 7) == 0) + m_serialPortCombo->insertItem(QString::fromLatin1(info.path).mid(7)); + } + } + gp_port_info_list_free(list); + + // add a spacer + rightLayout->addStretch(); + + populateCameraListView(); + load(); + + enableButtonOK(false ); + m_portSelectGroup->setEnabled( false ); + m_portSettingsGroup->setEnabled( false ); +} + +bool KameraDeviceSelectDialog::populateCameraListView() +{ + gp_abilities_list_new (&m_device->m_abilitylist); + gp_abilities_list_load(m_device->m_abilitylist, glob_context); + int numCams = gp_abilities_list_count(m_device->m_abilitylist); + CameraAbilities a; + + if(numCams < 0) { + // XXX libgphoto2 failed to get te camera list + return false; + } else { + for(int x = 0; x < numCams; ++x) { + if(gp_abilities_list_get_abilities(m_device->m_abilitylist, x, &a) == GP_OK) { + new QListViewItem(m_modelSel, a.model); + } + } + return true; + } +} + +void KameraDeviceSelectDialog::save() +{ + m_device->setModel(m_modelSel->currentItem()->text(0)); + + if (m_portSelectGroup->selected()) { + QString type = m_portSelectGroup->selected()->text(); + + if(type == i18n("Serial")) + m_device->setPath("serial:" + m_serialPortCombo->currentText()); + else if(type == i18n("USB")) + m_device->setPath("usb:"); + } else { + // This camera has no port type (e.g. "Directory Browse" camera). + // Do nothing. + } +} + +void KameraDeviceSelectDialog::load() +{ + QString path = m_device->path(); + QString port = path.left(path.find(":")).lower(); + + if (port == "serial") setPortType(INDEX_SERIAL); + if (port == "usb") setPortType(INDEX_USB); + + QListViewItem *modelItem = m_modelSel->firstChild(); + if( modelItem) + { + do { + if (modelItem->text(0) == m_device->model()) { + m_modelSel->setSelected(modelItem, true); + m_modelSel->ensureItemVisible(modelItem); + } + } while ( ( modelItem = modelItem->nextSibling() ) ); + } +} + +void KameraDeviceSelectDialog::slot_setModel(QListViewItem *item) +{ + enableButtonOK(true); + m_portSelectGroup->setEnabled(true); + m_portSettingsGroup->setEnabled(true); + + QString model = item->text(0); + + CameraAbilities abilities; + int index = gp_abilities_list_lookup_model(m_device->m_abilitylist, model.local8Bit().data()); + if(index < 0) { + slot_error(i18n("Description of abilities for camera %1 is not available." + " Configuration options may be incorrect.").arg(model)); + } + int result = gp_abilities_list_get_abilities(m_device->m_abilitylist, index, &abilities); + if (result == GP_OK) { + // enable radiobuttons for supported port types + m_serialRB->setEnabled(abilities.port & GP_PORT_SERIAL); + m_USBRB->setEnabled(abilities.port & GP_PORT_USB); + + // turn off any selected port + QButton *selected = m_portSelectGroup->selected(); + if(selected != NULL) + selected->toggle(); + + // if there's only one available port type, make sure it's selected + if (abilities.port == GP_PORT_SERIAL) + setPortType(INDEX_SERIAL); + if (abilities.port == GP_PORT_USB) + setPortType(INDEX_USB); + } else { + slot_error(i18n("Description of abilities for camera %1 is not available." + " Configuration options may be incorrect.").arg(model)); + } +} + +void KameraDeviceSelectDialog::setPortType(int type) +{ + // Enable the correct button + m_portSelectGroup->setButton(type); + + // Bring the right tab to the front + m_settingsStack->raiseWidget(type); +} + +void KameraDeviceSelectDialog::slot_error(const QString &message) +{ + KMessageBox::error(this, message); +} + +void KameraDeviceSelectDialog::slot_error(const QString &message, const QString &details) +{ + KMessageBox::detailedError(this, message, details); +} diff --git a/kamera/kcontrol/kameradevice.h b/kamera/kcontrol/kameradevice.h new file mode 100644 index 00000000..aae24e02 --- /dev/null +++ b/kamera/kcontrol/kameradevice.h @@ -0,0 +1,117 @@ +/* + + Copyright (C) 2001 The Kompany + 2002-2003 Ilya Konstantinov + 2002-2003 Marcus Meissner + 2003 Nadeem Hasan + + 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 __kameradevice_h__ +#define __kameradevice_h__ + +#include +#include +#include + +class KConfig; +class QString; +class KListView; +class QWidgetStack; +class QVButtonGroup; +class QVGroupBox; +class QComboBox; +class QLineEdit; +class QRadioButton; + +class KCamera : public QObject { + friend class KameraDeviceSelectDialog; + Q_OBJECT +public: + KCamera(const QString &name, const QString &path); + ~KCamera(); + void invalidateCamera(); + bool configure(); + void load(KConfig *m_config); + void save(KConfig *m_config); + bool test(); + QStringList supportedPorts(); + + Camera* camera(); + QString name() const { return m_name ; } + QString model() const { return m_model; } + QString path() const { return m_path; } + QString portName(); + + QString summary(); + CameraAbilities abilities(); + + void setName(const QString &name); + void setModel(const QString &model); + void setPath(const QString &path); + + bool isTestable() const; + bool isConfigurable(); + +signals: + void error(const QString &message); + void error(const QString &message, const QString &details); + +protected: + bool initInformation(); + bool initCamera(); +// void doConfigureCamera(Camera *camera, CameraWidget *widgets); +// int frontend_prompt(Camera *camera, CameraWidget *widgets); + + Camera *m_camera; +// KConfig *m_config; + QString m_name; // the camera's real name + QString m_model; + QString m_path; + CameraAbilities m_abilities; + CameraAbilitiesList *m_abilitylist; +}; + +class KameraDeviceSelectDialog : public KDialogBase +{ + Q_OBJECT +public: + KameraDeviceSelectDialog(QWidget *parent, KCamera *device); + void save(); + void load(); +protected slots: + void slot_setModel(QListViewItem *item); + void slot_error(const QString &message); + void slot_error(const QString &message, const QString &details); +protected: + KCamera *m_device; + + bool populateCameraListView(void); + void setPortType(int type); + + // port settings widgets + KListView *m_modelSel; + QLineEdit *m_nameEdit; + QWidgetStack *m_settingsStack; + QVButtonGroup *m_portSelectGroup; + QVGroupBox *m_portSettingsGroup; + QComboBox *m_serialPortCombo; + // port selection radio buttons + QRadioButton *m_serialRB; + QRadioButton *m_USBRB; +}; + +#endif diff --git a/kamera/kioslave/Makefile.am b/kamera/kioslave/Makefile.am new file mode 100644 index 00000000..4c6c148e --- /dev/null +++ b/kamera/kioslave/Makefile.am @@ -0,0 +1,17 @@ +# $Id$ +# Makefile for kdebase/kioslave/kamera + +INCLUDES= -I$(srcdir)/../.. -I$(srcdir)/.. $(all_includes) $(GPHOTO2_INCS) + +####### Files + +kde_module_LTLIBRARIES = kio_kamera.la + +kio_kamera_la_SOURCES = kamera.cpp +kio_kamera_la_LIBADD = $(LIB_KIO) -lgphoto2 +kio_kamera_la_LDFLAGS = $(all_libraries) $(GPHOTO2_LIBS) -module $(KDE_PLUGIN) + +noinst_HEADERS = kamera.h + +kde_services_DATA = camera.protocol + diff --git a/kamera/kioslave/camera.protocol b/kamera/kioslave/camera.protocol new file mode 100644 index 00000000..947d02b9 --- /dev/null +++ b/kamera/kioslave/camera.protocol @@ -0,0 +1,16 @@ +[Protocol] +exec=kio_kamera +protocol=camera +input=none +output=filesystem +listing=Name,Type +reading=true +writing=false +deleting=true +source=true +makedir=false +linking=false +moving=false +Icon=camera +maxInstances=1 +Class=:local diff --git a/kamera/kioslave/kamera.cpp b/kamera/kioslave/kamera.cpp new file mode 100644 index 00000000..ab4eb469 --- /dev/null +++ b/kamera/kioslave/kamera.cpp @@ -0,0 +1,1066 @@ +/* + + Copyright (C) 2001 The Kompany + 2001-2003 Ilya Konstantinov + 2001-2007 Marcus Meissner + + 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "kamera.h" + +#define MAXIDLETIME 30 /* seconds */ + +#define tocstr(x) ((x).local8Bit()) + +using namespace KIO; + +extern "C" +{ + KDE_EXPORT int kdemain(int argc, char **argv); + + static void frontendCameraStatus(GPContext *context, const char *format, va_list args, void *data); + static unsigned int frontendProgressStart( + GPContext *context, float totalsize, const char *format, + va_list args, void *data + ); + static void frontendProgressUpdate( + GPContext *context, unsigned int id, float current, void *data + ); +} + +int kdemain(int argc, char **argv) +{ + KInstance instance("kio_kamera"); + + if(argc != 4) { + kdDebug(7123) << "Usage: kio_kamera protocol " + "domain-socket1 domain-socket2" << endl; + exit(-1); + } + KameraProtocol slave(argv[2], argv[3]); + slave.dispatchLoop(); + return 0; +} + +KameraProtocol::KameraProtocol(const QCString &pool, const QCString &app) +: SlaveBase("camera", pool, app), +m_camera(NULL) +{ + // attempt to initialize libgphoto2 and chosen camera (requires locking) + // (will init m_camera, since the m_camera's configuration is empty) + m_camera = 0; + m_file = NULL; + m_config = new KSimpleConfig(KProtocolInfo::config("camera")); + m_context = gp_context_new(); + actiondone = true; + cameraopen = false; + m_lockfile = locateLocal("tmp", "kamera"); + idletime = 0; +} + +// This handler is getting called every second. We use it to do the +// delayed close of the camera. +// Logic is: +// - No more requests in the queue (signaled by actiondone) AND +// - We are MAXIDLETIME seconds idle OR +// - Another slave wants to have access to the camera. +// +// The existance of a lockfile is used to signify "please give up camera". +// +void KameraProtocol::special(const QByteArray&) { + kdDebug(7123) << "KameraProtocol::special() at " << getpid() << endl; + + if (!actiondone && cameraopen) { + struct stat stbuf; + if ((-1!=::stat(m_lockfile.utf8(),&stbuf)) || (idletime++ >= MAXIDLETIME)) { + kdDebug(7123) << "KameraProtocol::special() closing camera." << endl; + closeCamera(); + setTimeoutSpecialCommand(-1); + } else { + // continue to wait + setTimeoutSpecialCommand(1); + } + } else { + // We let it run until the slave gets no actions anymore. + setTimeoutSpecialCommand(1); + } + actiondone = false; +} + +KameraProtocol::~KameraProtocol() +{ + kdDebug(7123) << "KameraProtocol::~KameraProtocol()" << endl; + delete m_config; + if(m_camera) { + closeCamera(); + gp_camera_free(m_camera); + m_camera = NULL; + } +} + +// initializes the camera for usage - should be done before operations over the wire +bool KameraProtocol::openCamera(QString &str) { + idletime = 0; + actiondone = true; + if (!m_camera) { + reparseConfiguration(); + } else { + if (!cameraopen) { + int ret, tries = 15; + kdDebug(7123) << "KameraProtocol::openCamera at " << getpid() << endl; + while (tries--) { + ret = gp_camera_init(m_camera, m_context); + if ( (ret == GP_ERROR_IO_USB_CLAIM) || + (ret == GP_ERROR_IO_LOCK)) { + // just create / touch if not there + int fd = ::open(m_lockfile.utf8(),O_CREAT|O_WRONLY,0600); + if (fd != -1) ::close(fd); + ::sleep(1); + kdDebug(7123) << "openCamera at " << getpid() << "- busy, ret " << ret << ", trying again." << endl; + continue; + } + if (ret == GP_OK) break; + str = gp_result_as_string(ret); + return false; + } + ::unlink(m_lockfile.utf8()); + setTimeoutSpecialCommand(1); + kdDebug(7123) << "openCamera succeeded at " << getpid() << endl; + cameraopen = true; + } + } + return true; +} + +// should be done after operations over the wire +void KameraProtocol::closeCamera(void) +{ + int gpr; + + if (!m_camera) + return; + + kdDebug(7123) << "KameraProtocol::closeCamera at " << getpid() << endl; + if ((gpr=gp_camera_exit(m_camera,m_context))!=GP_OK) { + kdDebug(7123) << "closeCamera failed with " << gp_result_as_string(gpr) << endl; + } + // HACK: gp_camera_exit() in gp 2.0 does not close the port if there + // is no camera_exit function. + gp_port_close(m_camera->port); + cameraopen = false; + return; +} + +static QString fix_foldername(QString ofolder) { + QString folder = ofolder; + if (folder.length() > 1) { + while ((folder.length()>1) && (folder.right(1) == "/")) + folder = folder.left(folder.length()-1); + } + if (folder.length() == 0) + folder = "/"; + return folder; +} + +// The KIO slave "get" function (starts a download from the camera) +// The actual returning of the data is done in the frontend callback functions. +void KameraProtocol::get(const KURL &url) +{ + kdDebug(7123) << "KameraProtocol::get(" << url.path() << ")" << endl; + + CameraFileType fileType; + int gpr; + if (url.host().isEmpty()) { + error(KIO::ERR_DOES_NOT_EXIST, url.path()); + return; + } + + if(!openCamera()) { + error(KIO::ERR_DOES_NOT_EXIST, url.path()); + return; + } + + // fprintf(stderr,"get(%s)\n",url.path().latin1()); + +#define GPHOTO_TEXT_FILE(xx) \ + if (!url.path().compare("/" #xx ".txt")) { \ + CameraText xx; \ + gpr = gp_camera_get_##xx(m_camera, &xx, m_context); \ + if (gpr != GP_OK) { \ + error(KIO::ERR_DOES_NOT_EXIST, url.path()); \ + return; \ + } \ + QByteArray chunkDataBuffer; \ + chunkDataBuffer.setRawData(xx.text, strlen(xx.text)); \ + data(chunkDataBuffer); \ + processedSize(strlen(xx.text)); \ + chunkDataBuffer.resetRawData(xx.text, strlen(xx.text)); \ + finished(); \ + return; \ + } + + GPHOTO_TEXT_FILE(about); + GPHOTO_TEXT_FILE(manual); + GPHOTO_TEXT_FILE(summary); + +#undef GPHOTO_TEXT_FILE + // emit info message + infoMessage( i18n("Retrieving data from camera %1").arg(url.user()) ); + + // Note: There's no need to re-read directory for each get() anymore + gp_file_new(&m_file); + + // emit the total size (we must do it before sending data to allow preview) + CameraFileInfo info; + + gpr = gp_camera_file_get_info(m_camera, tocstr(fix_foldername(url.directory(false))), tocstr(url.fileName()), &info, m_context); + if (gpr != GP_OK) { + // fprintf(stderr,"Folder %s / File %s not found, gpr is %d\n",folder.latin1(), url.fileName().latin1(), gpr); + gp_file_unref(m_file); + if ((gpr == GP_ERROR_FILE_NOT_FOUND) || (gpr == GP_ERROR_DIRECTORY_NOT_FOUND)) + error(KIO::ERR_DOES_NOT_EXIST, url.path()); + else + error(KIO::ERR_UNKNOWN, gp_result_as_string(gpr)); + return; + } + + // at last, a proper API to determine whether a thumbnail was requested. + if(cameraSupportsPreview() && metaData("thumbnail") == "1") { + kdDebug(7123) << "get() retrieving the thumbnail" << endl; + fileType = GP_FILE_TYPE_PREVIEW; + if (info.preview.fields & GP_FILE_INFO_SIZE) + totalSize(info.preview.size); + if (info.preview.fields & GP_FILE_INFO_TYPE) + mimeType(info.preview.type); + } else { + kdDebug(7123) << "get() retrieving the full-scale photo" << endl; + fileType = GP_FILE_TYPE_NORMAL; + if (info.file.fields & GP_FILE_INFO_SIZE) + totalSize(info.file.size); + if (info.preview.fields & GP_FILE_INFO_TYPE) + mimeType(info.file.type); + } + + // fetch the data + m_fileSize = 0; + gpr = gp_camera_file_get(m_camera, tocstr(fix_foldername(url.directory(false))), tocstr(url.fileName()), fileType, m_file, m_context); + if ( (gpr == GP_ERROR_NOT_SUPPORTED) && + (fileType == GP_FILE_TYPE_PREVIEW) + ) { + // If we get here, the file info command information + // will either not be used, or still valid. + fileType = GP_FILE_TYPE_NORMAL; + gpr = gp_camera_file_get(m_camera, tocstr(fix_foldername(url.directory(false))), tocstr(url.fileName()), fileType, m_file, m_context); + } + switch(gpr) { + case GP_OK: + break; + case GP_ERROR_FILE_NOT_FOUND: + case GP_ERROR_DIRECTORY_NOT_FOUND: + gp_file_unref(m_file); + m_file = NULL; + error(KIO::ERR_DOES_NOT_EXIST, url.fileName()); + return ; + default: + gp_file_unref(m_file); + m_file = NULL; + error(KIO::ERR_UNKNOWN, gp_result_as_string(gpr)); + return; + } + // emit the mimetype + // NOTE: we must first get the file, so that CameraFile->name would be set + const char *fileMimeType; + gp_file_get_mime_type(m_file, &fileMimeType); + mimeType(fileMimeType); + + // We need to pass left over data here. Some camera drivers do not + // implement progress callbacks! + const char *fileData; + long unsigned int fileSize; + // This merely returns us a pointer to gphoto's internal data + // buffer -- there's no expensive memcpy + gpr = gp_file_get_data_and_size(m_file, &fileData, &fileSize); + if (gpr != GP_OK) { + kdDebug(7123) << "get():: get_data_and_size failed." << endl; + gp_file_free(m_file); + m_file = NULL; + error(KIO::ERR_UNKNOWN, gp_result_as_string(gpr)); + return; + } + // make sure we're not sending zero-sized chunks (=EOF) + // also make sure we send only if the progress did not send the data + // already. + if ((fileSize > 0) && (fileSize - m_fileSize)>0) { + unsigned long written = 0; + QByteArray chunkDataBuffer; + + // We need to split it up here. Someone considered it funny + // to discard any data() larger than 16MB. + // + // So nearly any Movie will just fail.... + while (written < fileSize-m_fileSize) { + unsigned long towrite = 1024*1024; // 1MB + + if (towrite > fileSize-m_fileSize-written) + towrite = fileSize-m_fileSize-written; + chunkDataBuffer.setRawData(fileData + m_fileSize + written, towrite); + processedSize(m_fileSize + written + towrite); + data(chunkDataBuffer); + chunkDataBuffer.resetRawData(fileData + m_fileSize + written, towrite); + written += towrite; + } + m_fileSize = fileSize; + setFileSize(fileSize); + } + + finished(); + gp_file_unref(m_file); /* just unref, might be stored in fs */ + m_file = NULL; +} + +// The KIO slave "stat" function. +void KameraProtocol::stat(const KURL &url) +{ + kdDebug(7123) << "stat(\"" << url.path() << "\")" << endl; + + if (url.path() == "") { + KURL rooturl(url); + + kdDebug(7123) << "redirecting to /" << endl; + rooturl.setPath("/"); + rooturl.setHost(url.host()); + rooturl.setUser(url.user()); + redirection(rooturl); + finished(); + return; + } + + if(url.path() == "/") + statRoot(); + else + statRegular(url); +} + +// Implements stat("/") -- which always returns the same value. +void KameraProtocol::statRoot(void) +{ + UDSEntry entry; + UDSAtom atom; + + atom.m_uds = UDS_NAME; + atom.m_str = "/"; + entry.append(atom); + + atom.m_uds = UDS_FILE_TYPE; + atom.m_long = S_IFDIR; + entry.append(atom); + + atom.m_uds = UDS_ACCESS; + atom.m_long = S_IRUSR | S_IRGRP | S_IROTH | + S_IWUSR | S_IWGRP | S_IWOTH; + entry.append(atom); + + statEntry(entry); + + finished(); + + // This call happens on autodetect by kdemm. So close the camera, but + // only if no more requests are pending. + idletime = MAXIDLETIME; +} + +// Implements a regular stat() of a file / directory, returning all we know about it +void KameraProtocol::statRegular(const KURL &url) +{ + UDSEntry entry; + int gpr; + + kdDebug(7123) << "statRegular(\"" << url.path() << "\")" << endl; + if (openCamera() == false) { + error(KIO::ERR_DOES_NOT_EXIST, url.path()); + return; + } + + // fprintf(stderr,"statRegular(%s)\n",url.path().latin1()); + + // Is "url" a directory? + CameraList *dirList; + gp_list_new(&dirList); + kdDebug(7123) << "statRegular() Requesting directories list for " << url.directory() << endl; + + gpr = gp_camera_folder_list_folders(m_camera, tocstr(fix_foldername(url.directory(false))), dirList, m_context); + if (gpr != GP_OK) { + if ((gpr == GP_ERROR_FILE_NOT_FOUND) || (gpr == GP_ERROR_DIRECTORY_NOT_FOUND)) + error(KIO::ERR_DOES_NOT_EXIST, url.path()); + else + error(KIO::ERR_UNKNOWN, gp_result_as_string(gpr)); + gp_list_free(dirList); + return; + } + +#define GPHOTO_TEXT_FILE(xx) \ + if (!url.path().compare("/"#xx".txt")) { \ + CameraText xx; \ + gpr = gp_camera_get_about(m_camera, &xx, m_context); \ + if (gpr != GP_OK) { \ + error(KIO::ERR_DOES_NOT_EXIST, url.fileName()); \ + return; \ + } \ + translateTextToUDS(entry,#xx".txt",xx.text); \ + statEntry(entry); \ + finished(); \ + return; \ + } + GPHOTO_TEXT_FILE(about); + GPHOTO_TEXT_FILE(manual); + GPHOTO_TEXT_FILE(summary); +#undef GPHOTO_TEXT_FILE + + const char *name; + for(int i = 0; i < gp_list_count(dirList); i++) { + gp_list_get_name(dirList, i, &name); + if (url.fileName().compare(name) == 0) { + gp_list_free(dirList); + UDSEntry entry; + translateDirectoryToUDS(entry, url.fileName()); + statEntry(entry); + finished(); + return; + } + } + gp_list_free(dirList); + + // Is "url" a file? + CameraFileInfo info; + gpr = gp_camera_file_get_info(m_camera, tocstr(fix_foldername(url.directory(false))), tocstr(url.fileName()), &info, m_context); + if (gpr != GP_OK) { + if ((gpr == GP_ERROR_FILE_NOT_FOUND) || (gpr == GP_ERROR_DIRECTORY_NOT_FOUND)) + error(KIO::ERR_DOES_NOT_EXIST, url.path()); + else + error(KIO::ERR_UNKNOWN, gp_result_as_string(gpr)); + return; + } + translateFileToUDS(entry, info, url.fileName()); + statEntry(entry); + finished(); +} + +// The KIO slave "del" function. +void KameraProtocol::del(const KURL &url, bool isFile) +{ + kdDebug(7123) << "KameraProtocol::del(" << url.path() << ")" << endl; + + if(!openCamera()) { + error(KIO::ERR_CANNOT_DELETE, url.fileName()); + return; + } + if (!cameraSupportsDel()) { + error(KIO::ERR_CANNOT_DELETE, url.fileName()); + return; + } + if(isFile){ + CameraList *list; + gp_list_new(&list); + int ret; + + ret = gp_camera_file_delete(m_camera, tocstr(fix_foldername(url.directory(false))), tocstr(url.fileName()), m_context); + + if(ret != GP_OK) { + error(KIO::ERR_CANNOT_DELETE, url.fileName()); + } else { + finished(); + } + } +} + +// The KIO slave "listDir" function. +void KameraProtocol::listDir(const KURL &url) +{ + kdDebug(7123) << "KameraProtocol::listDir(" << url.path() << ")" << endl; + + if (url.host().isEmpty()) { + KURL xurl; + // List the available cameras + QStringList groupList = m_config->groupList(); + kdDebug(7123) << "Found cameras: " << groupList.join(", ") << endl; + QStringList::Iterator it; + UDSEntry entry; + UDSAtom atom; + + + /* + * What we do: + * - Autodetect cameras and remember them with their ports. + * - List all saved and possible offline cameras. + * - List all autodetected and not yet printed cameras. + */ + QMap ports, names; + QMap modelcnt; + + /* Autodetect USB cameras ... */ + GPContext *glob_context = NULL; + int i, count; + CameraList *list; + CameraAbilitiesList *al; + GPPortInfoList *il; + + gp_list_new (&list); + gp_abilities_list_new (&al); + gp_abilities_list_load (al, glob_context); + gp_port_info_list_new (&il); + gp_port_info_list_load (il); + gp_abilities_list_detect (al, il, list, glob_context); + gp_abilities_list_free (al); + gp_port_info_list_free (il); + + count = gp_list_count (list); + + for (i = 0 ; isetGroup(model); + m_config->writeEntry("Model",model); + m_config->writeEntry("Path",value); + modelcnt[model]++; + } + gp_list_free (list); + + /* Avoid duplicated entry for usb: and usb:001,042 entries. */ + if (ports.contains("usb:") && names[ports["usb:"]]!="usb:") + ports.remove("usb:"); + + for (it = groupList.begin(); it != groupList.end(); it++) { + QString m_cfgPath; + if (*it == "") + continue; + + m_config->setGroup(*it); + m_cfgPath = m_config->readEntry("Path"); + + /* If autodetect by USB autodetect ... skip it here. + * We leave unattached USB cameras in here, because the user + * might plug them in later and does not want to press reload. + * We add them with port "usb:". + */ + if (modelcnt[*it] > 0) + continue; + + entry.clear(); + atom.m_uds = UDS_FILE_TYPE;atom.m_long = S_IFDIR;entry.append(atom); + atom.m_uds = UDS_NAME;atom.m_str = *it;entry.append(atom); + atom.m_uds = UDS_ACCESS; + atom.m_long = S_IRUSR | S_IRGRP | S_IROTH | + S_IWUSR | S_IWGRP | S_IWOTH; + entry.append(atom); + + atom.m_uds = UDS_URL; + + xurl.setProtocol("camera"); + xurl.setUser(*it); + /* Avoid setting usb:xxx,yyy. */ + if (m_cfgPath.contains("usb:")>0) { + names[*it] = "usb:"; + xurl.setHost("usb:"); + } else { + xurl.setHost(m_cfgPath); + } + xurl.setPath("/"); + atom.m_str = xurl.url(); + entry.append(atom); + + listEntry(entry, false); + } + + QMap::iterator portsit; + + for (portsit = ports.begin(); portsit != ports.end(); portsit++) { + entry.clear(); + atom.m_uds = UDS_FILE_TYPE;atom.m_long = S_IFDIR; entry.append(atom); + atom.m_uds = UDS_NAME;atom.m_str = portsit.data();entry.append(atom); + + atom.m_uds = UDS_ACCESS; + atom.m_long = S_IRUSR | S_IRGRP | S_IROTH | + S_IWUSR | S_IWGRP | S_IWOTH; + entry.append(atom); + + atom.m_uds = UDS_URL; + xurl.setProtocol("camera"); + xurl.setHost(portsit.key()); + xurl.setUser(portsit.data()); + xurl.setPath("/"); + atom.m_str = xurl.url(); + entry.append(atom); + + listEntry(entry, false); + } + listEntry(entry, true); + + finished(); + return; + } + + if (url.path() == "") { + KURL rooturl(url); + + kdDebug(7123) << "redirecting to /" << endl; + rooturl.setPath("/"); + rooturl.setHost(url.host()); + rooturl.setUser(url.user()); + redirection(rooturl); + finished(); + return; + } + + if (!openCamera()) { + error(KIO::ERR_COULD_NOT_READ,url.path()); + return; + } + + CameraList *dirList; + CameraList *fileList; + CameraList *specialList; + gp_list_new(&dirList); + gp_list_new(&fileList); + gp_list_new(&specialList); + int gpr; + + if (!url.path().compare("/")) { + CameraText text; + if (GP_OK == gp_camera_get_manual(m_camera, &text, m_context)) + gp_list_append(specialList,"manual.txt",NULL); + if (GP_OK == gp_camera_get_about(m_camera, &text, m_context)) + gp_list_append(specialList,"about.txt",NULL); + if (GP_OK == gp_camera_get_summary(m_camera, &text, m_context)) + gp_list_append(specialList,"summary.txt",NULL); + } + + gpr = readCameraFolder(url.path(), dirList, fileList); + if(gpr != GP_OK) { + kdDebug(7123) << "read Camera Folder failed:" << gp_result_as_string(gpr) <getFile()) + return; + gp_file_get_data_and_size(object->getFile(), &fileData, &fileSize); + // make sure we're not sending zero-sized chunks (=EOF) + if (fileSize > 0) { + // XXX using assign() here causes segfault, prolly because + // gp_file_free is called before chunkData goes out of scope + QByteArray chunkDataBuffer; + chunkDataBuffer.setRawData(fileData + object->getFileSize(), fileSize - object->getFileSize()); + // Note: this will fail with sizes > 16MB ... + object->data(chunkDataBuffer); + object->processedSize(fileSize); + chunkDataBuffer.resetRawData(fileData + object->getFileSize(), fileSize - object->getFileSize()); + object->setFileSize(fileSize); + } +} + +unsigned int frontendProgressStart( + GPContext * /*context*/, float totalsize, const char *format, va_list args, + void *data +) { + KameraProtocol *object = (KameraProtocol*)data; + char *status; + + /* We must copy the va_list to walk it twice, or all hell + * breaks loose on non-i386 platforms. + */ +#if defined(HAVE_VA_COPY) || defined(HAVE___VA_COPY) + va_list xvalist; +# ifdef HAVE_VA_COPY + va_copy(xvalist, args); +# elif HAVE___VA_COPY + __va_copy(xvalist, args); +# endif + int size=vsnprintf(NULL, 0, format, xvalist); + if(size<=0) + return GP_OK; // vsnprintf is broken, better don't do anything. + + status=new char[size+1]; +# ifdef HAVE_VA_COPY + va_copy(xvalist, args); +# elif HAVE___VA_COPY + __va_copy(xvalist, args); +# endif + vsnprintf(status, size+1, format, xvalist); +#else + /* We cannot copy the va_list, so make sure we + * walk it just _once_. + */ + status=new char[300]; + vsnprintf(status, 300, format, args); +#endif + + object->infoMessage(QString::fromLocal8Bit(status)); + delete [] status; + object->totalSize((int)totalsize); // hack: call slot directly + return GP_OK; +} + +// this callback function is activated on every status message from gphoto2 +static void frontendCameraStatus(GPContext * /*context*/, const char *format, va_list args, void *data) +{ + KameraProtocol *object = (KameraProtocol*)data; + char *status; + + /* We must copy the va_list to walk it twice, or all hell + * breaks loose on non-i386 platforms. + */ +#if defined(HAVE_VA_COPY) || defined(HAVE___VA_COPY) + va_list xvalist; +# ifdef HAVE_VA_COPY + va_copy(xvalist, args); +# elif HAVE___VA_COPY + __va_copy(xvalist, args); +# endif + int size=vsnprintf(NULL, 0, format, xvalist); + if(size<=0) + return; // vsnprintf is broken, better don't do anything. + + status=new char[size+1]; +# ifdef HAVE_VA_COPY + va_copy(xvalist, args); +# elif HAVE___VA_COPY + __va_copy(xvalist, args); +# endif + vsnprintf(status, size+1, format, xvalist); +#else + /* We cannot copy the va_list, so make sure we + * walk it just _once_. + */ + status=new char[300]; + vsnprintf(status, 300, format, args); +#endif + object->infoMessage(QString::fromLocal8Bit(status)); + delete [] status; +} diff --git a/kamera/kioslave/kamera.h b/kamera/kioslave/kamera.h new file mode 100644 index 00000000..765f6560 --- /dev/null +++ b/kamera/kioslave/kamera.h @@ -0,0 +1,81 @@ +/* + + Copyright (C) 2001 The Kompany + 2001-2003 Ilya Konstantinov + 2001-2007 Marcus Meissner + + 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 __kamera_h__ +#define __kamera_h__ + +#include +#include +#include + +class KSimpleConfig; + +class KameraProtocol : public KIO::SlaveBase +{ +public: + KameraProtocol(const QCString &pool, const QCString &app); + virtual ~KameraProtocol(); + + virtual void get(const KURL &url); + virtual void stat(const KURL &url); + virtual void del(const KURL &url, bool isFile); + virtual void setHost(const QString& host, int port, const QString& user, const QString& pass ); + virtual void listDir(const KURL &url); + virtual void special(const QByteArray &data); + + CameraFile *getFile() { return m_file; } + int getFileSize() { return m_fileSize; } + void setFileSize(int newfs) { m_fileSize = newfs; } + +private: + Camera *m_camera; + CameraAbilities m_abilities; + KSimpleConfig *m_config; + + GPContext *m_context; + + void reparseConfiguration(void); + bool openCamera(QString& str); + bool openCamera(void ) { + QString errstr; + return openCamera(errstr); + } + void closeCamera(void); + + void statRoot(void); + void statRegular(const KURL &url); + void translateTextToUDS(KIO::UDSEntry &udsEntry, const QString &info, const char *txt); + void translateFileToUDS(KIO::UDSEntry &udsEntry, const CameraFileInfo &info, QString name); + void translateDirectoryToUDS(KIO::UDSEntry &udsEntry, const QString &dirname); + bool cameraSupportsPreview(void); + bool cameraSupportsDel(void); + bool cameraSupportsPut(void); + int readCameraFolder(const QString &folder, CameraList *dirList, CameraList *fileList); + + QString m_lockfile; + int idletime; + + int m_fileSize; + CameraFile *m_file; + bool actiondone, cameraopen; +}; +#endif diff --git a/kamera/pics/Makefile.am b/kamera/pics/Makefile.am new file mode 100644 index 00000000..b74ac1ca --- /dev/null +++ b/kamera/pics/Makefile.am @@ -0,0 +1 @@ +KDE_ICON = camera camera_test diff --git a/kamera/pics/cr16-action-camera_test.png b/kamera/pics/cr16-action-camera_test.png new file mode 100644 index 00000000..543710fb Binary files /dev/null and b/kamera/pics/cr16-action-camera_test.png differ diff --git a/kamera/pics/cr16-app-camera.png b/kamera/pics/cr16-app-camera.png new file mode 100644 index 00000000..364167f0 Binary files /dev/null and b/kamera/pics/cr16-app-camera.png differ diff --git a/kamera/pics/cr16-device-camera.png b/kamera/pics/cr16-device-camera.png new file mode 100644 index 00000000..364167f0 Binary files /dev/null and b/kamera/pics/cr16-device-camera.png differ diff --git a/kamera/pics/cr22-device-camera.png b/kamera/pics/cr22-device-camera.png new file mode 100644 index 00000000..745affe7 Binary files /dev/null and b/kamera/pics/cr22-device-camera.png differ diff --git a/kamera/pics/cr22-filesys-camera.png b/kamera/pics/cr22-filesys-camera.png new file mode 100644 index 00000000..745affe7 Binary files /dev/null and b/kamera/pics/cr22-filesys-camera.png differ diff --git a/kamera/pics/cr32-device-camera.png b/kamera/pics/cr32-device-camera.png new file mode 100644 index 00000000..6876fa90 Binary files /dev/null and b/kamera/pics/cr32-device-camera.png differ diff --git a/kamera/pics/cr32-filesys-camera.png b/kamera/pics/cr32-filesys-camera.png new file mode 100644 index 00000000..6876fa90 Binary files /dev/null and b/kamera/pics/cr32-filesys-camera.png differ diff --git a/kcoloredit/Makefile.am b/kcoloredit/Makefile.am new file mode 100644 index 00000000..1f377635 --- /dev/null +++ b/kcoloredit/Makefile.am @@ -0,0 +1,35 @@ +INCLUDES = $(all_includes) + +kcoloredit_SOURCES = kzcolorselector.cpp imageselection.cpp \ + texteditselection.cpp gradientselection.cpp colorselector.cpp \ + kxycolorselector.cpp paletteview.cpp paletteviewscrolledarea.cpp \ + editablestreamhistory.cpp color.cpp palette.cpp loadpalettedlg.cpp \ + kcoloreditview.cpp kcoloreditdoc.cpp kcoloredit.cpp main.cpp +kcoloredit_METASOURCES = AUTO +kcoloredit_LDADD = $(LIB_KDEUI) $(LIB_KFILE) +kcoloredit_LDFLAGS = $(all_libraries) $(KDE_RPATH) + +rcdir = $(kde_datadir)/kcoloredit +rc_DATA = kcoloreditui.rc + +bin_PROGRAMS = kcoloredit kcolorchooser +kcolorchooser_SOURCES = kcolorchooser.cpp +kcolorchooser_LDADD = $(LIB_KDEUI) +kcolorchooser_LDFLAGS = $(all_libraries) $(KDE_RPATH) + +noinst_HEADERS = color.h colorselector.h editablestreamhistory.h \ + gradientselection.h imageselection.h kcoloredit.h kcoloreditdoc.h \ + kcoloreditview.h kxycolorselector.h kzcolorselector.h \ + loadpalettedlg.h main.h palette.h palettehistory.h paletteview.h \ + resource.h texteditselection.h + +xdg_apps_DATA = kcoloredit.desktop kcolorchooser.desktop + +KDE_ICON = kcoloredit kcolorchooser + +EXTRA_DIST = $(xdg_apps_DATA) + +messages: rc.cpp + $(EXTRACTRC) *.rc > rc.cpp + $(XGETTEXT) $(kcoloredit_SOURCES) rc.cpp resource.h -o $(podir)/kcoloredit.pot + diff --git a/kcoloredit/color.cpp b/kcoloredit/color.cpp new file mode 100644 index 00000000..db18a5a5 --- /dev/null +++ b/kcoloredit/color.cpp @@ -0,0 +1,78 @@ +/*************************************************************************** + color.cpp - description + ------------------- + begin : Sun Jul 9 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "color.h" + +Color::Color(){ + setComponents(0, 0, 0); + setName(""); +} +Color::Color(const int red, const int green, const int blue, const QString& name) { + setComponents(red, green, blue); + setName(name); +} +Color::~Color(){ +} + +void Color::setComponent(const int index, const int value) { + m_components[index] = value; +} + +void Color::setComponents(const int red, const int green, const int blue) { + setComponent(RED_INDEX, red); + setComponent(GREEN_INDEX, green); + setComponent(BLUE_INDEX, blue); +} + +void Color::setName(const QString& name) { + m_name = name; +} + +int Color::component(const int index) const { + return m_components[index]; +} + +const int* Color::components() const{ + return m_components; +} + +const QString& Color::name() const { + return m_name; +} + +bool Color::equals(const Color& color) { + return component(RED_INDEX) == color.component(RED_INDEX) && + component(GREEN_INDEX) == color.component(GREEN_INDEX) && + component(BLUE_INDEX) == color.component(BLUE_INDEX); +} + +void Color::modifyComponent(const int index, const int value, const double amount) { + int comp = component(index); + comp += (int)(value*amount + 0.5); + if(comp > RGB_MAX_COMPONENT_VALUE) + comp = RGB_MAX_COMPONENT_VALUE; + else if(comp < 0) + comp = 0; + setComponent(index, comp); +} + +void Color::modifyComponents(const int red, const int green, const int blue, const double amount) { + modifyComponent(RED_INDEX, red, amount); + modifyComponent(GREEN_INDEX, green, amount); + modifyComponent(BLUE_INDEX, blue, amount); +} + diff --git a/kcoloredit/color.h b/kcoloredit/color.h new file mode 100644 index 00000000..723ba2f0 --- /dev/null +++ b/kcoloredit/color.h @@ -0,0 +1,81 @@ +/*************************************************************************** + color.h - description + ------------------- + begin : Sun Jul 9 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef COLOR_H +#define COLOR_H + +#include "main.h" + +/**A color class, holds its components and name + *@author Artur Rataj + */ + +class Color { + public: + /** indices of components + */ + enum { RED_INDEX = 0, + GREEN_INDEX = 1, + BLUE_INDEX = 2, + COMPONENTS_NUM = 3 }; + + public: + /** constructs a color + */ + Color(); + /** constructs a color with given components and a name + */ + Color(const int red, const int green, const int blue, const QString& name); + ~Color(); + /** sets a component + */ + void setComponent(const int index, const int value); + /** sets components + */ + void setComponents(const int red, const int green, const int blue); + /** sets a name + */ + void setName(const QString& name); + /** @return a component + */ + int component(const int index) const; + /** @return components + */ + const int* components() const; + /** @return a color name + */ + const QString& name() const; + /** @return if is equal to color + */ + bool equals(const Color& color); + /** modifies a component, amount can be either positive or negative + */ + void modifyComponent(const int index, const int value, const double amount); + /** modifies components, amount can be either positive or negative + */ + void modifyComponents(const int red, const int green, const int blue, const double amount); + + protected: + /** components table + */ + int m_components[COMPONENTS_NUM]; + /** a color name + */ + QString m_name; +}; + +#endif diff --git a/kcoloredit/colorselector.cpp b/kcoloredit/colorselector.cpp new file mode 100644 index 00000000..2b0530d3 --- /dev/null +++ b/kcoloredit/colorselector.cpp @@ -0,0 +1,212 @@ +/*************************************************************************** + colorselector.cpp - description + ------------------- + begin : Sun Jul 9 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include + +#include +/* #include */ +#include +#include +#include +#include +#include + +#include "main.h" +#include "imageselection.h" +#include "texteditselection.h" +#include "colorselector.h" + +ColorSelector::ColorSelector(QWidget *parent, const char *name ) : QWidget(parent, name) { + fComponentsMode = false; + QVBoxLayout* topLayout = new QVBoxLayout(this, 4); + /* + QTabWidget* pages = new QTabWidget(this); + */ + gradientSelection = new GradientSelection(this); + connect(gradientSelection, SIGNAL( valueChanged(Color*) ), + SLOT( slotGradientSelectionChangeColor(Color*) )); + connect(gradientSelection, SIGNAL( synchronizeColor() ), + SLOT( slotGradientSelectionSynchronizeColor() )); + connect(this, SIGNAL( valueChanged(Color*) ), gradientSelection, SLOT( slotSetValue(Color*) )); + /* + pages->addTab(gradientSelection, i18n( "Gradient" )); + ImageSelection* imageSelection = new ImageSelection(this); + connect(imageSelection, SIGNAL( valueChanged(Color*) ), SLOT( slotSetColor(Color*) )); + connect(this, SIGNAL( valueChanged(Color*) ), imageSelection, SLOT( slotSetValue(Color*) )); + pages->addTab(imageSelection, i18n( "Image" )); + topLayout->addWidget(pages, 10); + */ + topLayout->addWidget(gradientSelection, 10); + KSeparator* hLine = new KSeparator(KSeparator::HLine, this); + topLayout->addWidget(hLine); + QHBoxLayout* layout = new QHBoxLayout(); + TextEditSelection* textEditSelection = new TextEditSelection(this); + connect(textEditSelection, SIGNAL( valueChanged(Color*) ), SLOT( slotSetColor(Color*) )); + connect(this, SIGNAL( valueChanged(Color*) ), textEditSelection, SLOT( slotSetValue(Color*) )); + QVBoxLayout* colorChangeLayout = new QVBoxLayout(); + colorChangeLayout->setMargin(2); + QRadioButton* replaceButton = new QRadioButton(i18n( "Replace" ), this); + connect(replaceButton, SIGNAL( clicked() ), SLOT( slotColorReplace() )); + replaceButton->setChecked(true); + colorChangeButtons.insert(replaceButton); + colorChangeLayout->addWidget(replaceButton); + QRadioButton* changeButton = new QRadioButton(i18n( "Change" ) + ":", this); + connect(changeButton, SIGNAL( clicked() ), SLOT( slotColorChange() )); + colorChangeButtons.insert(changeButton); + colorChangeLayout->addWidget(changeButton); + colorChangeValue = 0; + colorChangeSliderWidget = new QWidget(this); + QVBoxLayout* colorChangeSliderLayout = new QVBoxLayout(colorChangeSliderWidget, 1); + colorChangeSliderLayout->setMargin(0); + QSlider* colorChangeSlider = new QSlider(0, MAX_COLOR_CHANGE_VALUE, + MAX_COLOR_CHANGE_VALUE/4, colorChangeValue, QSlider::Horizontal, colorChangeSliderWidget); + colorChangeSlider->setTickInterval(colorChangeSlider->pageStep()); + colorChangeSlider->setTickmarks(QSlider::Above); + connect(colorChangeSlider, SIGNAL( valueChanged(int) ), SLOT( slotColorChangeValueChanged(int) )); + colorChangeSliderLayout->addWidget(colorChangeSlider); + QHBoxLayout* colorChangeSliderLabelsLayout = new QHBoxLayout(0); + QLabel* subtractLabel = new QLabel(i18n( "0" ), colorChangeSliderWidget); + colorChangeSliderLabelsLayout->addWidget(subtractLabel); + colorChangeSliderLabelsLayout->addStretch(10); + QLabel* addLabel = new QLabel(" " + i18n( "Replace" ), colorChangeSliderWidget); + colorChangeSliderLabelsLayout->addWidget(addLabel); + colorChangeSliderLayout->addLayout(colorChangeSliderLabelsLayout); + colorChangeLayout->addStretch(10); + colorChangeLayout->addWidget(colorChangeSliderWidget); + colorChangeLayout->addStretch(10); + layout->addLayout(colorChangeLayout, 10); + m_color.setComponents(RGB_MAX_COMPONENT_VALUE, RGB_MAX_COMPONENT_VALUE, RGB_MAX_COMPONENT_VALUE); + slotColorReplace(); + KSeparator* vLine = new KSeparator(KSeparator::VLine, this); + layout->addWidget(vLine); + layout->addWidget(textEditSelection, 1); + colorPatch = new KColorPatch(this); + connect(colorPatch, SIGNAL( colorChanged(const QColor&) ), SLOT( slotSetColor(const QColor&) )); + colorPatch->setMinimumSize(80, 64); + layout->addWidget(colorPatch, 10); + topLayout->addLayout(layout); +} +ColorSelector::~ColorSelector() { +} + +void ColorSelector::slotSetColor(Color color) { + m_color = color; + colorPatch->setColor(QColor( m_color.component(Color::RED_INDEX), + m_color.component(Color::GREEN_INDEX), + m_color.component(Color::BLUE_INDEX) )); + fComponentsMode = false; + emit valueChanged(&m_color); +} + +void ColorSelector::slotSetColor(Color* color) { + slotSetColor(*color); +} + +void ColorSelector::slotSetColor(const QColor& color) { + m_color.setComponent(Color::RED_INDEX, color.red()); + m_color.setComponent(Color::GREEN_INDEX, color.green()); + m_color.setComponent(Color::BLUE_INDEX, color.blue()); + fComponentsMode = false; + emit valueChanged(&m_color); +} + +void ColorSelector::scaledComponent(double* const component, const double componentDiff) { + double scaledComponentDiff = componentDiff* + pow(colorChangeValue*1.0/MAX_COLOR_CHANGE_VALUE, 2.0); + *component += scaledComponentDiff; + if(*component > RGB_MAX_COMPONENT_VALUE) + *component = RGB_MAX_COMPONENT_VALUE; + else if(*component < 0) + *component = 0; +} + +void ColorSelector::slotGradientSelectionChangeColor(Color* gradientSelectionColor) { + switch(colorChangeMode) { + case MODE_REPLACE: + slotSetColor(gradientSelectionColor); + break; + + case MODE_CHANGE: + gradientSelection->slotIgnoreSetValue(true); + double rComponent; + double gComponent; + double bComponent; + if(fComponentsMode) { + rComponent = fRComponent; + gComponent = fGComponent; + bComponent = fBComponent; + } else { + rComponent = m_color.component(Color::RED_INDEX); + gComponent = m_color.component(Color::GREEN_INDEX); + bComponent = m_color.component(Color::BLUE_INDEX); + } + double rDiff = gradientSelectionColor->component(Color::RED_INDEX) - rComponent; + double gDiff = gradientSelectionColor->component(Color::GREEN_INDEX) - gComponent; + double bDiff = gradientSelectionColor->component(Color::BLUE_INDEX) - bComponent; + /* + printf("base color = (%i %i %i) gradient color = (%i %i %i)\n", + rComponent, gComponent, bComponent, + gradientSelectionColor->getComponent(Color::RED_INDEX), + gradientSelectionColor->getComponent(Color::GREEN_INDEX), + gradientSelectionColor->getComponent(Color::BLUE_INDEX)); + */ + scaledComponent(&rComponent, rDiff); + scaledComponent(&gComponent, gDiff); + scaledComponent(&bComponent, bDiff); + Color newColor((int)( rComponent + 0.5 ), + (int)( gComponent + 0.5 ), (int)( bComponent + 0.5 ), ""); + slotSetColor(newColor); + fRComponent = rComponent; + fGComponent = gComponent; + fBComponent = bComponent; + fComponentsMode = true; + /* + printf("output color = (%i %i %i)\n", + rComponent, gComponent, bComponent); + */ + gradientSelection->slotIgnoreSetValue(false); + break; + } +} + +void ColorSelector::slotGradientSelectionSynchronizeColor() { + /** Notify the gradient selector to update its color */ + emit valueChanged(&m_color); +} + +const Color& ColorSelector::color() { + return m_color; +} + +void ColorSelector::slotColorReplace() { + colorChangeMode = MODE_REPLACE; + slotGradientSelectionSynchronizeColor(); + gradientSelection->enableSynchronizeColorButton(false); + colorChangeSliderWidget->setEnabled(false); +} + +void ColorSelector::slotColorChange() { + colorChangeMode = MODE_CHANGE; + gradientSelection->enableSynchronizeColorButton(true); + colorChangeSliderWidget->setEnabled(true); +} + +void ColorSelector::slotColorChangeValueChanged(int value) { + colorChangeValue = value; +} + +#include "colorselector.moc" diff --git a/kcoloredit/colorselector.h b/kcoloredit/colorselector.h new file mode 100644 index 00000000..21b5902b --- /dev/null +++ b/kcoloredit/colorselector.h @@ -0,0 +1,96 @@ +/*************************************************************************** + colorselector.h - description + ------------------- + begin : Sun Jul 9 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef COLORSELECTOR_H +#define COLORSELECTOR_H + +#include +#include +#include +#include + +#include "color.h" +#include "gradientselection.h" + +/** Color selector widget + * @author Artur Rataj + */ +class ColorSelector : public QWidget { + Q_OBJECT + +public: + /** constructs a color selector widget */ + ColorSelector(QWidget *parent=0, const char *name=0); + ~ColorSelector(); + /** @return the selected color */ + const Color& color(); + +signals: + /** A signal that a color value has changed */ + void valueChanged(Color*); + +public slots: + /** Called if a color changed */ + void slotSetColor(Color color); + /** Called if a color changed */ + void slotSetColor(Color* color); + /** called if a color changed in the color patch */ + void slotSetColor(const QColor& color); + /** Called by the gradient selection, to replace or modify a color */ + void slotGradientSelectionChangeColor(Color* gradientSelectionColor); + /** Called by the gradient selection, to synchronize its color */ + void slotGradientSelectionSynchronizeColor(); + /** Called if color replace mode is chosen */ + void slotColorReplace(); + /** called if color change mode is chosen */ + void slotColorChange(); + /** Called if a color change value changed */ + void slotColorChangeValueChanged(int value); + +private: + /** Color change mode constants */ + enum { MODE_REPLACE = 0, + MODE_CHANGE = 1, + /** Maximum color change value */ + MAX_COLOR_CHANGE_VALUE = 16 }; + + /** A color change slider widget */ + QWidget* colorChangeSliderWidget; + /** Color change buttons button group widget */ + QButtonGroup colorChangeButtons; + /** A color patch widget */ + KColorPatch* colorPatch; + /** A gradient selection widget */ + GradientSelection* gradientSelection; + /** The current color */ + Color m_color; + /** Color change mode */ + int colorChangeMode; + /** Current color change value */ + int colorChangeValue; + /** Floating--point precision RGB components, for color change mode */ + double fRComponent; + double fGComponent; + double fBComponent; + /** Whether in the floating-point precision components mode */ + bool fComponentsMode; + + /** Scales a component according to componentDiff and colorChangeValue */ + void scaledComponent(double* const component, const double componentDiff); +}; + +#endif diff --git a/kcoloredit/editablestreamhistory.cpp b/kcoloredit/editablestreamhistory.cpp new file mode 100644 index 00000000..c299ed7a --- /dev/null +++ b/kcoloredit/editablestreamhistory.cpp @@ -0,0 +1,18 @@ +/*************************************************************************** + editablestream.cpp - description + ------------------- + begin : Sun Jul 9 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "editablestreamhistory.h" diff --git a/kcoloredit/editablestreamhistory.h b/kcoloredit/editablestreamhistory.h new file mode 100644 index 00000000..9fe59d99 --- /dev/null +++ b/kcoloredit/editablestreamhistory.h @@ -0,0 +1,107 @@ +/*************************************************************************** + editablestreamhistory.h - description + ------------------- + begin : Sun Jul 9 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef EDITABLESTREAMHISTORY_H +#define EDITABLESTREAMHISTORY_H + +/** A template class adding undo/redo history for EDITABLE_STREAM paste and cut + * methods + * @author Artur Rataj + */ +template class EditableStreamHistory { +public: + /** Constructs the class with stream as an EDITABLE_STREAM and + * a given number of undo levels + */ + EditableStreamHistory(EDITABLE_STREAM* stream, const int undoLevels); + ~EditableStreamHistory(); + /** Cuts a stream at index, of length length. + * Uses undo/redo history. + * @return A stream that has been cut out + */ + EDITABLE_STREAM cut(const int index, const int length); + /** Pastes a stream at index. Uses undo/redo history */ + void paste(const int index, EDITABLE_STREAM& pasteStream); + /** Replaces a stream at index. Uses undo/redo history */ + void replace(const int index, EDITABLE_STREAM& replaceStream); + /** @return Whether undo possible */ + bool undoPossible(); + /** @return Whether redo possible */ + bool redoPossible(); + /** Undoes if possible */ + void undo(); + /** Redoes if possible */ + void redo(); + /** @return A pointer to editableStream */ + EDITABLE_STREAM* editableStream(); + +protected: + /** An editable stream */ + EDITABLE_STREAM* m_editableStream; + /** A number of undo levels */ + int m_undoLevels; +}; + +template EditableStreamHistory:: + EditableStreamHistory(EDITABLE_STREAM* stream, const int undoLevels) { + m_editableStream = stream; + m_undoLevels = undoLevels; +} +template EditableStreamHistory::~EditableStreamHistory() { +} + +template EDITABLE_STREAM + EditableStreamHistory::cut(const int index, const int length) { + EDITABLE_STREAM cut_stream = m_editableStream->cut(index, length); + return cut_stream; +} + +template void + EditableStreamHistory::paste(const int index, EDITABLE_STREAM& pasteStream) { + m_editableStream->paste(index, pasteStream); +} + +template void + EditableStreamHistory::replace(const int index, EDITABLE_STREAM& replaceStream) { + m_editableStream->cut(index, replaceStream.length()); + m_editableStream->paste(index, replaceStream); +} + +template bool + EditableStreamHistory::undoPossible() { + return false; +} + +template bool + EditableStreamHistory::redoPossible() { + return false; +} + +template void + EditableStreamHistory::undo() { +} + +template void + EditableStreamHistory::redo() { +} + +template EDITABLE_STREAM* + EditableStreamHistory::editableStream() { + return m_editableStream; +} + +#endif diff --git a/kcoloredit/gradientselection.cpp b/kcoloredit/gradientselection.cpp new file mode 100644 index 00000000..a8927c7d --- /dev/null +++ b/kcoloredit/gradientselection.cpp @@ -0,0 +1,252 @@ +/*************************************************************************** + gradientselection.cpp - description + ------------------- + begin : Wed Jul 12 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include + +#include "main.h" +#include "gradientselection.h" + +GradientSelection::GradientSelection(QWidget *parent, const char *name ) : QWidget(parent,name) { + QGridLayout* topLayout = new QGridLayout(this, 2, 2, 0); + QHBoxLayout* layout = new QHBoxLayout(0); + layout->setMargin(3); + xyColorSelector = new KXYColorSelector(this); + connect(xyColorSelector, SIGNAL( valueChanged(int, int) ), + SLOT( slotXyColorSelectorPosChanged(int, int) )); + layout->addWidget(xyColorSelector); + topLayout->addLayout(layout, 0, 0); + topLayout->setRowStretch(0, 10); + topLayout->setRowStretch(1, 0); + QVBoxLayout* xyColorSelectorLayout = new QVBoxLayout(); + QHBoxLayout* checkBoxLayout = new QHBoxLayout(); + checkBoxLayout->setMargin(0); + variableCheckBox = new QCheckBox(i18n( "Variable" ), this); + variableGlobalComponent = false; + connect(variableCheckBox, SIGNAL( toggled(bool) ), SLOT( slotSetVariableGlobalComponent(bool) )); + checkBoxLayout->addSpacing(2); + checkBoxLayout->addWidget(variableCheckBox); + xyColorSelectorLayout->addLayout(checkBoxLayout); + xyColorSelectorLayout->addStretch(10); + QHBoxLayout* buttonsLayout = new QHBoxLayout(); + synchronizeColorButton = new QPushButton(i18n( "Synchronize" ), this); + connect(synchronizeColorButton, SIGNAL( clicked() ), SLOT( slotSynchronizeColor() )); + buttonsLayout->addSpacing(2); + buttonsLayout->addWidget(synchronizeColorButton); + buttonsLayout->addStretch(10); + xyColorSelectorLayout->addLayout(buttonsLayout); + xyColorSelectorLayout->addSpacing(2); + topLayout->addLayout(xyColorSelectorLayout, 1, 0); + zColorSelector = new KZColorSelector(KZColorSelector::Vertical, this); + connect(zColorSelector, SIGNAL( valueChanged(int) ), + SLOT( slotZColorSelectorPosChanged(int) )); + zColorSelector->setFixedWidth(36); + topLayout->addWidget(zColorSelector, 0, 1); + QVBoxLayout* zColorSelectorLayout = new QVBoxLayout(0); + connect(&hsvButtons, SIGNAL( clicked(int) ), SLOT( slotSetColorSelectionMode(int) )); + QRadioButton* hRadioButton = new QRadioButton("H", this); + hsvButtons.insert(hRadioButton, H_COMPONENT); + zColorSelectorLayout->addWidget(hRadioButton); + QRadioButton* sRadioButton = new QRadioButton("S", this); + hsvButtons.insert(sRadioButton, S_COMPONENT); + zColorSelectorLayout->addWidget(sRadioButton); + QRadioButton* vRadioButton = new QRadioButton("V", this); + hsvButtons.insert(vRadioButton, V_COMPONENT); + vRadioButton->toggle(); + zColorSelectorLayout->addWidget(vRadioButton); + topLayout->addLayout(zColorSelectorLayout, 1, 1); + color.setComponents(RGB_MAX_COMPONENT_VALUE, RGB_MAX_COMPONENT_VALUE, RGB_MAX_COMPONENT_VALUE); + hComponent = -1; + sComponent = 0; + vComponent = HSV_MAX_V_VALUE; + slotIgnoreSetValue(false); + slotSetColorSelectionMode(V_COMPONENT); +} +GradientSelection::~GradientSelection(){ +} + +void GradientSelection::slotSetValue(Color* color) { + if(!ignoreSetValue && !color->equals( this->color )) { + this->color = *color; + int newHComponent; + int newSComponent; + int newVComponent; + QColor hsvColor(this->color.component(Color::RED_INDEX), + this->color.component(Color::GREEN_INDEX), + this->color.component(Color::BLUE_INDEX)); + hsvColor.hsv(&newHComponent, &newSComponent, &newVComponent); + hComponent = newHComponent; + sComponent = newSComponent; + vComponent = newVComponent; + updateXyColorSelector(false); + updateZColorSelector(); + } +} + +void GradientSelection::slotIgnoreSetValue(bool ignore) { + ignoreSetValue = ignore; +} + +void GradientSelection::updateXyColorSelector(const bool modeChanged) { + int xPos; + int yPos; + int component; + switch(zColorSelectorComponentIndex) { + case H_COMPONENT: + xPos = (int)(vComponent*( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 )/ + HSV_MAX_V_VALUE + 0.5); + yPos = (int)(sComponent*( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 )/ + HSV_MAX_S_VALUE + 0.5); + component = hComponent; + break; + + case S_COMPONENT: + xPos = (int)(hComponent*( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 )/ + HSV_MAX_H_VALUE + 0.5); + yPos = (int)(vComponent*( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 )/ + HSV_MAX_V_VALUE + 0.5); + if(variableGlobalComponent) + component = sComponent; + else + component = 240; + break; + + case V_COMPONENT: + xPos = (int)(hComponent*( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 )/ + HSV_MAX_H_VALUE + 0.5); + yPos = (int)(sComponent*( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 )/ + HSV_MAX_S_VALUE + 0.5); + if(variableGlobalComponent) + component = vComponent; + else + component = 192; + break; + + default: + xPos = 0; + yPos = 0; + component = 0; + break; + + } + if(xPos < 0) + xPos = 0; + if(yPos < 0) + yPos = 0; + if(modeChanged || xyColorSelector->globalComponent() != component) { + xyColorSelector->setGlobalComponent(component); + xyColorSelector->updateContents(); + } + xyColorSelector->setValues(xPos, yPos); +} + +void GradientSelection::updateZColorSelector() { + zColorSelector->setBaseColorHsv(hComponent, sComponent, vComponent); + zColorSelector->updatePointerPos(); + zColorSelector->updateContents(); +} + +void GradientSelection::slotSetColorSelectionMode(int mode) { + zColorSelectorComponentIndex = mode; + xyColorSelector->setType(zColorSelectorComponentIndex); + updateXyColorSelector(true); + switch(zColorSelectorComponentIndex) { + case H_COMPONENT: + zColorSelector->setType(KZColorSelector::TYPE_H); + variableCheckBox->setEnabled(false); + break; + + case S_COMPONENT: + zColorSelector->setType(KZColorSelector::TYPE_S); + variableCheckBox->setEnabled(true); + break; + + case V_COMPONENT: + zColorSelector->setType(KZColorSelector::TYPE_V); + variableCheckBox->setEnabled(true); + break; + + } + updateZColorSelector(); +} + +void GradientSelection::slotSetVariableGlobalComponent(bool variable) { + variableGlobalComponent = variable; + updateXyColorSelector(false); +} + +void GradientSelection::slotXyColorSelectorPosChanged(int x, int y) { + switch(zColorSelectorComponentIndex) { + case H_COMPONENT: + vComponent = (int)(x*1.0*HSV_MAX_V_VALUE/( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 ) + 0.5); + sComponent = (int)(y*1.0*HSV_MAX_S_VALUE/( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 ) + 0.5); + break; + + case S_COMPONENT: + hComponent = (int)(x*1.0*HSV_MAX_H_VALUE/( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 ) + 0.5); + vComponent = (int)(y*1.0*HSV_MAX_V_VALUE/( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 ) + 0.5); + break; + + case V_COMPONENT: + hComponent = (int)(x*1.0*HSV_MAX_H_VALUE/( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 ) + 0.5); + sComponent = (int)(y*1.0*HSV_MAX_S_VALUE/( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 ) + 0.5); + break; + + } + QColor rgbColor; + rgbColor.setHsv(hComponent, sComponent, vComponent); + color.setComponents(rgbColor.red(), rgbColor.green(), rgbColor.blue()); + updateZColorSelector(); + emit valueChanged(&color); +} + +void GradientSelection::slotZColorSelectorPosChanged(int y) { + bool repaintZColorSelector = false; + switch(zColorSelectorComponentIndex) { + case H_COMPONENT: + hComponent = y; + break; + + case S_COMPONENT: + sComponent = y; + break; + + case V_COMPONENT: + vComponent = y; + break; + + } + QColor rgbColor; + rgbColor.setHsv(hComponent, sComponent, vComponent); + color.setComponents(rgbColor.red(), rgbColor.green(), rgbColor.blue()); + updateXyColorSelector(false); + if(repaintZColorSelector) + updateZColorSelector(); + emit valueChanged(&color); +} + +void GradientSelection::slotSynchronizeColor() { + emit synchronizeColor(); +} + +void GradientSelection::enableSynchronizeColorButton(bool enable) { + synchronizeColorButton->setEnabled(enable); +} +#include "gradientselection.moc" diff --git a/kcoloredit/gradientselection.h b/kcoloredit/gradientselection.h new file mode 100644 index 00000000..24a3c5e1 --- /dev/null +++ b/kcoloredit/gradientselection.h @@ -0,0 +1,106 @@ +/*************************************************************************** + gradientselection.h - description + ------------------- + begin : Wed Jul 12 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef GRADIENTSELECTION_H +#define GRADIENTSELECTION_H + +#include +#include +#include +#include + +#include "kxycolorselector.h" +#include "kzcolorselector.h" +#include "color.h" + +/** A widget for selecting colors from gradients + * @author Artur Rataj + */ +class GradientSelection : public QWidget { + Q_OBJECT + +public: + /** Constructs the widget */ + GradientSelection(QWidget *parent=0, const char *name=0); + ~GradientSelection(); + /** Enables or disables the color synchronize button */ + void enableSynchronizeColorButton(bool enable); + +signals: + /** A signal that a color value has changed by edition */ + void valueChanged(Color*); + /** Synchronizes the widget color */ + void synchronizeColor(); + +public slots: + /** Sets a color */ + void slotSetValue(Color* color); + /** Whether to ignore the set value slot. Default is false. */ + void slotIgnoreSetValue(bool ignore); + +protected: + /** Components indices. If the gradient selector shows one of them, + * the two components selector should be in a mode indicated by a value + * of the appropriate index + */ + enum { H_COMPONENT = KXYColorSelector::TYPE_VS, + S_COMPONENT = KXYColorSelector::TYPE_HV, + V_COMPONENT = KXYColorSelector::TYPE_HS }; + + /** Variable global component checkbox */ + QCheckBox* variableCheckBox; + /** Synchronize color button */ + QPushButton* synchronizeColorButton; + /** HSV buttons button group widget */ + QButtonGroup hsvButtons; + /** The two components selector */ + KXYColorSelector* xyColorSelector; + /** The gradient selector */ + KZColorSelector* zColorSelector; + /** Whether the two component color selector global component is variable */ + bool variableGlobalComponent; + /** Whether to ignore the set value slot */ + bool ignoreSetValue; + /** The selected color */ + Color color; + /** The selected color H component */ + int hComponent; + /** The selected color S component */ + int sComponent; + /** The selected color V component */ + int vComponent; + /** The gradient selector component index */ + int zColorSelectorComponentIndex; + /** Updates two component selector colors */ + void updateXyColorSelector(const bool modeChanged); + /** Updates gradient selector colors */ + void updateZColorSelector(); + +protected slots: + /** Sets color selection mode */ + void slotSetColorSelectionMode(int mode); + /** Sets if the two component selector has a variable global component */ + void slotSetVariableGlobalComponent(bool variable); + /** Notifies that the two component color selector pointer position changed */ + void slotXyColorSelectorPosChanged(int x, int y); + /** Notifies that the gradient color selector pointer position changed */ + void slotZColorSelectorPosChanged(int y); + /** sends synchronizeColor signal */ + void slotSynchronizeColor(); +}; + +#endif diff --git a/kcoloredit/hi16-app-kcolorchooser.png b/kcoloredit/hi16-app-kcolorchooser.png new file mode 100644 index 00000000..eeb387b3 Binary files /dev/null and b/kcoloredit/hi16-app-kcolorchooser.png differ diff --git a/kcoloredit/hi16-app-kcoloredit.png b/kcoloredit/hi16-app-kcoloredit.png new file mode 100644 index 00000000..c0a67bb9 Binary files /dev/null and b/kcoloredit/hi16-app-kcoloredit.png differ diff --git a/kcoloredit/hi22-app-kcolorchooser.png b/kcoloredit/hi22-app-kcolorchooser.png new file mode 100644 index 00000000..faa5080f Binary files /dev/null and b/kcoloredit/hi22-app-kcolorchooser.png differ diff --git a/kcoloredit/hi32-app-kcoloredit.png b/kcoloredit/hi32-app-kcoloredit.png new file mode 100644 index 00000000..e5aa87cb Binary files /dev/null and b/kcoloredit/hi32-app-kcoloredit.png differ diff --git a/kcoloredit/imageselection.cpp b/kcoloredit/imageselection.cpp new file mode 100644 index 00000000..39a8f2f0 --- /dev/null +++ b/kcoloredit/imageselection.cpp @@ -0,0 +1,28 @@ +/*************************************************************************** + imageselection.cpp - description + ------------------- + begin : Wed Jul 12 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "imageselection.h" + +ImageSelection::ImageSelection(QWidget *parent, const char *name ) : QWidget(parent,name) { +} +ImageSelection::~ImageSelection(){ +} + +void ImageSelection::slotSetValue(Color* color) { + this->color = *color; +} +#include "imageselection.moc" diff --git a/kcoloredit/imageselection.h b/kcoloredit/imageselection.h new file mode 100644 index 00000000..3137fec7 --- /dev/null +++ b/kcoloredit/imageselection.h @@ -0,0 +1,49 @@ +/*************************************************************************** + imageselection.h - description + ------------------- + begin : Wed Jul 12 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef IMAGESELECTION_H +#define IMAGESELECTION_H + +#include + +#include "color.h" + +/** This is a widget for selecting colors from an image + * @author Artur Rataj + */ +class ImageSelection : public QWidget { + Q_OBJECT + +public: + /** constructs the widget */ + ImageSelection(QWidget *parent=0, const char *name=0); + ~ImageSelection(); + +signals: + /** A signal that a color value has changed by edition */ + void valueChanged(Color*); + +public slots: + /** Sets a color */ + void slotSetValue(Color* color); + +protected: + /** The selected color */ + Color color; +}; + +#endif diff --git a/kcoloredit/kcolorchooser.cpp b/kcoloredit/kcolorchooser.cpp new file mode 100644 index 00000000..bf1204fb --- /dev/null +++ b/kcoloredit/kcolorchooser.cpp @@ -0,0 +1,70 @@ +/* +This file is part of KDE + + Copyright (C) 1998-2000 Waldo Bastian (bastian@kde.org) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include + +#include +#include +#include +#include + +#include "kcolordialog.h" + +static const char description[] = + I18N_NOOP("KDE Color Chooser"); + +static const char version[] = "v1.0.1"; + +static KCmdLineOptions options[] = +{ + { "print", I18N_NOOP("Print the selected color to stdout"), 0 }, + KCmdLineLastOption +}; + +int main(int argc, char *argv[]) +{ + KLocale::setMainCatalogue("kdelibs"); + KAboutData aboutData( "kcolorchooser", I18N_NOOP("KColorChooser"), + version, description, KAboutData::License_BSD, + "(c) 2000, Waldo Bastian"); + aboutData.addAuthor("Waldo Bastian",0, "bastian@kde.org"); + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); + + KApplication app; + + KColorDialog dlg; + + dlg.setColor(Qt::blue); // Just a color + + app.connect(&dlg, SIGNAL(finished()), SLOT(quit())); + + dlg.show(); + app.exec(); + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + const QColor c = dlg.color(); + if ( args->isSet("print") && c.isValid() ) { + std::cout << c.name().utf8().data() << std::endl; + } +} diff --git a/kcoloredit/kcolorchooser.desktop b/kcoloredit/kcolorchooser.desktop new file mode 100644 index 00000000..37d7b075 --- /dev/null +++ b/kcoloredit/kcolorchooser.desktop @@ -0,0 +1,108 @@ +[Desktop Entry] +Type=Application +Exec=kcolorchooser %i %m +Icon=kcolorchooser +Path= +Terminal=false +DocPath=kcoloredit/index.html +GenericName=Color Chooser +GenericName[af]=Kleur Kieser +GenericName[ar]=برنامج اختيار الألوان +GenericName[bg]=Избор на цвят +GenericName[br]=Dibaber livioù +GenericName[bs]=Izbornik boja +GenericName[ca]=Elecció de colors +GenericName[cs]=Výběr barev +GenericName[cy]=Dewis Lliwiau +GenericName[da]=Farvevælger +GenericName[de]=Farbauswahl +GenericName[el]=Επιλογέας χρωμάτων +GenericName[en_GB]=Colour Chooser +GenericName[eo]=Ilo por elekti koloron +GenericName[es]=Selector de colores +GenericName[et]=Värvivalija +GenericName[eu]=Kolore hautatzailea +GenericName[fa]=انتخاب‌‌کنندۀ رنگ +GenericName[fi]=Värivalitsin +GenericName[fr]=Sélecteur de couleur +GenericName[gl]=Selecionador de cores +GenericName[he]=בוחר צבעים +GenericName[hi]=रंग चयनक +GenericName[hr]=Izbornik boja +GenericName[hu]=Színválasztó +GenericName[is]=Litavalstól +GenericName[it]=Selettore di colori +GenericName[ja]=色の選択 +GenericName[kk]=Түсті таңдау +GenericName[km]=កម្មវិធី​ជ្រើស​ពណ៌ +GenericName[lt]=Spalvų parinkiklis +GenericName[lv]=Krāsu Izvēlētājs +GenericName[mk]=Избирач на бои +GenericName[ms]=Pemilih Warna +GenericName[mt]=Agħżel Kulur +GenericName[nb]=Fargevelger +GenericName[nds]=Klöörutwahl +GenericName[ne]=रङ चयनकर्ता +GenericName[nl]=Kleurenkiezer +GenericName[nn]=Fargeveljar +GenericName[pa]=ਰੰਗ ਸੰਰਚਨਾ +GenericName[pl]=Wybór koloru +GenericName[pt]=Selector de Cores +GenericName[pt_BR]=Seletor de Cores +GenericName[ro]=Selector de culori +GenericName[ru]=Выбор цвета +GenericName[se]=Ivdneválljejeaddji +GenericName[sk]=Výber farieb +GenericName[sl]=Izbirnik barv +GenericName[sr]=Бирач боја +GenericName[sr@Latn]=Birač boja +GenericName[sv]=Färgväljare +GenericName[ta]=வண்ணத் தேர்வு +GenericName[tg]=Интихоби ранг +GenericName[th]=เครื่องมือเลือกสีของ KDE +GenericName[tr]=Renk Seçici +GenericName[uk]=Селектор кольорів +GenericName[uz]=Rang tanlovchi +GenericName[uz@cyrillic]=Ранг танловчи +GenericName[ven]=Munangi wa Muvhala +GenericName[wa]=Tchoezixheu di coleurs +GenericName[xh]=Mkhethi Wombala +GenericName[zh_CN]=颜色选择程序 +GenericName[zh_HK]=顏色選擇器 +GenericName[zh_TW]=顏色選擇程式 +GenericName[zu]=Umkhethi Wombala +Name=KColorChooser +Name[af]=K-kleur-kieser +Name[ar]=برنامج KColorChooser +Name[ca]=Elecció de colors +Name[cs]=Výběr barev +Name[cy]=KDewisLliw +Name[eo]=Kolorelektilo +Name[fi]=Värivalitsin +Name[hi]=के-कलर-चूसर +Name[hr]=Izbornik boja +Name[is]=Litaval +Name[lv]=KKrāsuIzvēlētājs +Name[nb]=Fargevelger +Name[ne]=केडीई रङ चयनकर्ता +Name[nn]=KDE-fargeveljar +Name[nso]=KMokgethi wa Mmala +Name[pa]=ਕੇਰੰਗਚੋਣਕਾਰ +Name[pl]=Wybór koloru +Name[pt_BR]=KSeletor de Cores +Name[ro]=Selector culori +Name[se]=KDE-ivdneválljejeaddji +Name[sv]=Kcolorchooser +Name[ta]=கேவண்ணத் தேர்வு +Name[th]=เครื่องมือเลือกสี - K +Name[tr]=K Renk Seçici +Name[uk]=Селектор кольорів +Name[uz]=Rang tanlovchi +Name[uz@cyrillic]=Ранг танловчи +Name[ven]=Tshinangi tsha muvhala tsha K +Name[xh]=Umkhethi Wombala i K +Name[zh_TW]=KColorChooser 顏色選擇器 +Name[zu]=Umkhethi Wombala ka K + +X-DCOP-ServiceType=Multi +Categories=Qt;KDE;Graphics;X-KDE-More; diff --git a/kcoloredit/kcoloredit.cpp b/kcoloredit/kcoloredit.cpp new file mode 100644 index 00000000..a5582436 --- /dev/null +++ b/kcoloredit/kcoloredit.cpp @@ -0,0 +1,363 @@ +/*************************************************************************** + kcoloredit.cpp - description + ------------------- + begin : Sat Jul 8 09:57:28 CEST 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +// include files for QT +#include +#include +#include + +// include files for KDE +#include +#include +#include +#include +#include +#include +#include +#include + +// application specific includes +#include "kcoloredit.h" +#include "kcoloreditview.h" +#include "kcoloreditdoc.h" +#include "loadpalettedlg.h" +#include "resource.h" +#include +#include + + +KColorEditApp::KColorEditApp() : KMainWindow(0) { + config=kapp->config(); + + /////////////////////////////////////////////////////////////////// + // call inits to invoke all other construction parts + initActions(); + initStatusBar(); + initDocument(); + initView(); + + resize(606,400); + setupGUI(); + + readOptions(); + + gettingColorFromScreen = false; +} + +KColorEditApp::~KColorEditApp() { +} + +void KColorEditApp::initActions() +{ + // File actiojns + KStdAction::openNew( this, SLOT( slotFileNew() ), actionCollection() ); + KStdAction::open( this, SLOT( slotFileOpen() ), actionCollection() ); + KStdAction::saveAs( this, SLOT( slotFileSaveAs() ), actionCollection() ); + KStdAction::close( this, SLOT( slotClose() ), actionCollection() ); + KStdAction::quit( this, SLOT( slotQuit() ), actionCollection() ); + m_actSave = KStdAction::save( this, SLOT( slotFileSave() ), + actionCollection() ); + m_actRecent = KStdAction::openRecent( this, + SLOT( slotFileOpenRecent( const KURL& ) ), actionCollection() ); + + ( void ) new KAction( i18n("New &Window"), kapp->miniIcon(), KShortcut(), + this, SLOT( slotFileNewWindow() ), actionCollection(), + "file_new_window" ); + + // Edit actions + m_actCut = KStdAction::cut( this, SLOT( slotEditCut() ), + actionCollection() ); + m_actCopy = KStdAction::copy( this, SLOT( slotEditCopy() ), + actionCollection() ); + m_actPaste = KStdAction::paste( this, SLOT( slotEditPaste() ), + actionCollection() ); + + m_actPaste->setEnabled( false ); + + // Color Menu + m_actNames = new KToggleAction( i18n("Show &Color Names"), KShortcut(), this, + SLOT( slotViewColorNames() ), actionCollection(), + "color_view_names" ); + m_actNames->setCheckedState(i18n("Hide &Color Names")); + m_actPalette = new KAction( i18n("From &Palette"), KShortcut(), this, + SLOT( slotColorFromPalette() ), actionCollection(), + "color_from_palette" ); + ( void ) new KAction( i18n("From &Screen"), KShortcut(), this, + SLOT( slotColorFromScreen() ), actionCollection(), + "color_from_screen" ); +} + +void KColorEditApp::initStatusBar() +{ + statusBar()->insertItem(i18n("Ready."), ID_STATUS_MSG, 1); + statusBar()->setItemAlignment( ID_STATUS_MSG, Qt::AlignLeft ); +} + +void KColorEditApp::initDocument() +{ + doc = new KColorEditDoc(this); + doc->newDocument(); + + connect( doc, SIGNAL( selectionChanged( int, int ) ), + SLOT( slotSelectionChanged( int, int ) ) ); + connect( doc, SIGNAL( clipboardChanged() ), + SLOT( slotClipboardChanged() ) ); + connect( doc, SIGNAL( modified( bool ) ), + SLOT( slotModified( bool ) ) ); + connect( doc, SIGNAL( paletteAvailable( bool ) ), + SLOT( slotPaletteAvailable( bool ) ) ); +} + +void KColorEditApp::initView() +{ + //////////////////////////////////////////////////////////////////// + // create the main widget here that is managed by KMainWindow's view-region + // and connect the widget to your document to display document contents. + + view = new KColorEditView(this); + doc->addView(view); + setCentralWidget(view); + setCaption(doc->title()); +} + +void KColorEditApp::openDocumentFile(const char* _cmdl) +{ + doc->openDocument(_cmdl); +} + + +KColorEditDoc *KColorEditApp::document() const +{ + return doc; +} + +void KColorEditApp::saveOptions() +{ + saveMainWindowSettings( config, "MainWindowSettings" ); + m_actRecent->saveEntries( config ); + + config->setGroup("KColorEdit Options"); + config->writeEntry("ColorNames", viewColorNames); +} + +void KColorEditApp::readOptions() +{ + applyMainWindowSettings( config, "MainWindowSettings" ); + m_actRecent->loadEntries( config ); + + config->setGroup("KColorEdit Options"); + + viewColorNames = config->readBoolEntry("ColorNames", false); + m_actNames->setChecked(viewColorNames); + doc->slotChangeViewMode(viewColorNames); +} + +bool KColorEditApp::queryClose() +{ + return doc->saveModified(); +} + +bool KColorEditApp::queryExit() +{ + saveOptions(); + return true; +} + +///////////////////////////////////////////////////////////////////// +// SLOT IMPLEMENTATION +///////////////////////////////////////////////////////////////////// + +void KColorEditApp::slotSelectionChanged( int begin, int end ) +{ + m_actCut->setEnabled( begin != end ); + m_actCopy->setEnabled( begin != end ); +} + +void KColorEditApp::slotClipboardChanged() +{ + m_actPaste->setEnabled( true ); +} + +void KColorEditApp::slotModified( bool b ) +{ + m_actSave->setEnabled( b ); +} + +void KColorEditApp::slotPaletteAvailable( bool b ) +{ + m_actPalette->setEnabled( b ); +} + +void KColorEditApp::slotFileNewWindow() +{ + KColorEditApp *new_window= new KColorEditApp(); + new_window->show(); +} + +void KColorEditApp::slotFileNew() +{ + if(doc->saveModified()) { + doc->newDocument(); + + setCaption(doc->title()); + } +} + +void KColorEditApp::slotFileOpen() { + if(doc->saveModified()) { + LoadPaletteDlg dialog(this); + if(dialog.exec()) { + QString fileToOpen = dialog.getFileName(); + if(!fileToOpen.isEmpty()) + { + if(!doc->openDocument( fileToOpen )) { + KMessageBox::sorry(0, doc->errorString()); + } else { + setCaption(doc->title()); + m_actRecent->addURL( KURL::fromPathOrURL( fileToOpen ) ); + } + } + } + } +} + +void KColorEditApp::slotFileOpenRecent( const KURL & url ) +{ + if(doc->saveModified()) { + doc->openDocument( url.path() ); + setCaption(doc->title()); + } +} + +void KColorEditApp::slotFileSave() +{ + if(!doc->saveDocument( doc->absFilePath() )) + slotFileSaveAs(); + //KMessageBox::sorry(0, doc->getErrorString()); +} + +bool KColorEditApp::slotFileSaveAs() +{ + bool result = true; + + while(result) { + QString newName=KFileDialog::getSaveFileName(lastSavePaletteAsFileDir, + "*|" + i18n("All Files"), this, i18n("Save As")); + if(newName.isEmpty()) + result = false; + else { + QFileInfo saveAsInfo(newName); + if(!saveAsInfo.exists() || + KMessageBox::questionYesNo( this, + i18n("A Document with this name already exists.\n" + "Do you want to overwrite it?"), + i18n("Warning"), i18n("Overwrite"), KStdGuiItem::cancel() ) == KMessageBox::Yes) { + if(!doc->saveDocument( newName )) { + KMessageBox::sorry(0, doc->errorString()); + result = false; + } else { + doc->setTitle(saveAsInfo.fileName()); + doc->setAbsFilePath(saveAsInfo.absFilePath()); + setCaption(doc->title()); + lastSavePaletteAsFileDir = saveAsInfo.absFilePath(); + m_actRecent->addURL( KURL( newName ) ); + break; + } + } + } + } + + return result; +} + +void KColorEditApp::slotClose() +{ + close(); +} + +void KColorEditApp::slotFilePrint() +{ + QPrinter printer; + if (printer.setup(this)) + { + view->print(&printer); + } +} + +void KColorEditApp::slotQuit() +{ + saveOptions(); + // close the first window, the list makes the next one the first again. + // This ensures that queryClose() is called on each window to ask for closing + KMainWindow* w; + if(memberList) + { + for(w=memberList->first(); w!=0; w=memberList->next()) + { + // only close the window if the closeEvent is accepted. If the user presses Cancel on the saveModified() dialog, + // the window and the application stay open. + if(!w->close()) + break; + } + } +} + +void KColorEditApp::slotEditCut() +{ + doc->cut(); +} + +void KColorEditApp::slotEditCopy() +{ + doc->copy(); +} + +void KColorEditApp::slotEditPaste() +{ + doc->paste(); +} + +void KColorEditApp::slotColorFromPalette() { + view->chooseColor(doc->paletteHistory()->editableStream()-> + color( doc->paletteCursorPos() )); +} + +void KColorEditApp::slotColorFromScreen() { + gettingColorFromScreen = true; + grabMouse(crossCursor); + grabKeyboard(); +} + +void KColorEditApp::slotViewColorNames() +{ + viewColorNames = m_actNames->isChecked(); + doc->slotChangeViewMode(viewColorNames); +} + +void KColorEditApp::mouseReleaseEvent(QMouseEvent* event) { + if(gettingColorFromScreen) { + gettingColorFromScreen = false; + releaseMouse(); + releaseKeyboard(); + QColor rgbColor = KColorDialog::grabColor(event->globalPos()); + color.setComponents(rgbColor.red(), rgbColor.green(), rgbColor.blue()); + view->chooseColor(&color); + } else + KMainWindow::mouseReleaseEvent(event); +} + +#include "kcoloredit.moc" diff --git a/kcoloredit/kcoloredit.desktop b/kcoloredit/kcoloredit.desktop new file mode 100644 index 00000000..8a27dce8 --- /dev/null +++ b/kcoloredit/kcoloredit.desktop @@ -0,0 +1,96 @@ +[Desktop Entry] +Type=Application +Exec=kcoloredit %i %m %U +Icon=kcoloredit +Path= +Terminal=false +DocPath=kcoloredit/index.html +GenericName=Color Palette Editor +GenericName[af]=Kleur Palet Redigeerder +GenericName[ar]=محرر لوحة الألوان +GenericName[bg]=Редактор на цветове +GenericName[br]=Aozer livaoueg +GenericName[bs]=Editor palete boja +GenericName[ca]=Editor de la paleta de colors +GenericName[cs]=Editor palety barev +GenericName[cy]=Golygydd Palet Lliwiau +GenericName[da]=Farvepaletredigering +GenericName[de]=Editor für Farbpaletten +GenericName[el]=Επεξεργαστής παλέτας χρωμάτων +GenericName[en_GB]=Colour Palette Editor +GenericName[eo]=Paletroredaktilo +GenericName[es]=Editor de paleta de color +GenericName[et]=Värvipaleti redaktor +GenericName[eu]=Koloreko paleta editorea +GenericName[fa]=ویرایشگر پالت رنگ +GenericName[fi]=Väripalettien muokkain +GenericName[fr]=Éditeur de palette de couleurs +GenericName[gl]=Editor de paletas de cores +GenericName[he]=עורך לוחות צבעים +GenericName[hi]=रंग पट्टिका संपादक +GenericName[hr]=Uređivač palete +GenericName[hu]=Palettaszerkesztő +GenericName[is]=Sýsla með litaspjöld +GenericName[it]=Editor di tavolozza +GenericName[ja]=カラーパレットエディタ +GenericName[kk]=Түстер палитрасын өңдеу +GenericName[km]=កម្មវិធី​និពន្ធ​ក្ដារ​លាយ​ពណ៌ +GenericName[lt]=Spalvų paletės redaktorius +GenericName[lv]=Krāsu Paletes Redaktors +GenericName[mk]=Уредувач на палета +GenericName[ms]=Editor Palet Warna +GenericName[mt]=Editur tal-palett ta' kului +GenericName[nb]=Palett-redigerer +GenericName[nds]=Klörensett-Editor +GenericName[ne]=रङदानी सम्पादक +GenericName[nl]=Kleurenpaletbewerker +GenericName[nn]=Palettredigering +GenericName[pa]=ਰੰਗ ਪੱਟੀ ਸੰਪਾਦਕ +GenericName[pl]=Edytor palety (kolorów) +GenericName[pt]=Editor de Paletas de Cores +GenericName[pt_BR]=Editor de Paleta de Cores +GenericName[ro]=Editor paletă de culori +GenericName[ru]=Редактор палитры +GenericName[se]=Ivdnepaleahta doaimmaheaddji +GenericName[sk]=Editor palety farieb +GenericName[sl]=Urejevalnik barvne palete +GenericName[sr]=Уређивач палете боја +GenericName[sr@Latn]=Uređivač palete boja +GenericName[sv]=Färgpaletteditor +GenericName[ta]=வண்ணகளஞ்சியம் +GenericName[tg]=Муҳаррири палитра +GenericName[th]=เครื่องมือแก้ไขจานสีของ KDE +GenericName[tr]=Renk Paleti Düzenleyici +GenericName[uk]=Редактор палітри кольорів +GenericName[ven]=Musengulusi wa phalete ya muvhala +GenericName[wa]=Aspougneu del palete di coleurs +GenericName[zh_CN]=调色板编辑器 +GenericName[zh_HK]=調色板編輯器 +GenericName[zh_TW]=調色板編輯器 +GenericName[zu]=Umhleli Wombala we Palette +Name=KColorEdit +Name[af]=K-kleur-redigeer +Name[ar]=برنامج KColorEdit +Name[cs]=Editor barev +Name[cy]=KGolyguLliw +Name[eo]=Kolorredaktilo +Name[hi]=के-कलर-एडिट +Name[hr]=Uređivač boja +Name[lv]=KKrāsuRedaktors +Name[ne]=केडीई रङ सम्पादन +Name[nso]=KPhetoso ya Mmala +Name[pa]=ਕੇਰੰਗ ਸੰਪਾਦਕ +Name[pl]=Edytor kolorów +Name[pt_BR]=KEditor de Cores +Name[ro]=Editor culori +Name[sv]=Kcoloredit +Name[ta]=கேவண்ணம் திருத்தம் +Name[th]=แก้ไขค่าสี - K +Name[tr]=K Renk Düzenleyici +Name[ven]=U sengulusa muvhala ha K +Name[xh]=Umhleli Wombala ye K +Name[zh_TW]=KColorEdit 顏色編輯器 +Name[zu]=Umhleli Wombala ka K + +X-DCOP-ServiceType=Multi +Categories=Qt;KDE;Graphics;X-KDE-More; diff --git a/kcoloredit/kcoloredit.h b/kcoloredit/kcoloredit.h new file mode 100644 index 00000000..cd69cdaf --- /dev/null +++ b/kcoloredit/kcoloredit.h @@ -0,0 +1,192 @@ +/*************************************************************************** + kcoloredit.h - description + ------------------- + begin : Sat Jul 8 09:57:28 CEST 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KCOLOREDIT_H +#define KCOLOREDIT_H + + +#include + +// include files for Qt +#include +#include + +// include files for KDE +#include +#include +#include + +// application specific includes +#include "color.h" + +class KColorEditDoc; +class KColorEditView; + +/** + * The base class for KColorEdit application windows. It sets up the main + * window and reads the config file as well as providing a menubar, toolbar + * and statusbar. An instance of KColorEditView creates your center view, which is connected + * to the window's Doc object. + * KColorEditApp reimplements the methods that KMainWindow provides for main window handling and supports + * full session management as well as keyboard accelerator configuration by using KAccel. + * @see KMainWindow + * @see KApplication + * @see KConfig + * @see KAccel + * + * @author Source Framework Automatically Generated by KDevelop, (c) The KDevelop Team. + * @version KDevelop version 0.4 code generation + */ +class KColorEditApp : public KMainWindow +{ + Q_OBJECT + + friend class KColorEditView; + + public: + /** construtor of KColorEditApp, calls all init functions to create the application. + * @see initMenuBar initToolBar + */ + KColorEditApp(); + ~KColorEditApp(); + + /** opens a file specified by commandline option + */ + void openDocumentFile(const char *_cmdl=0); + /** returns a pointer to the current document connected to the KMainWindow instance and is used by + * the View class to access the document object's methods + */ + KColorEditDoc *document() const; + + protected: + /** save general Options like all bar positions and status as well as the geometry and the recent file list to the configuration + * file + */ + void saveOptions(); + /** read general Options again and initialize all variables like the recent file list + */ + void readOptions(); + + void initActions(); + + /** initMenuBar creates the menubar and inserts the menupopups as well as creating the helpMenu. + * @see KApplication#getHelpMenu + */ + void initStatusBar(); + /** initializes the document object of the main window that is connected to the view in initView(). + * @see initView(); + */ + void initDocument(); + /** creates the centerwidget of the KMainWindow instance and sets it as the view + */ + void initView(); + /** queryClose is called by KMainWindow on each closeEvent of a window. Against the + * default implementation (only returns true), this calles saveModified() on the document object to ask if the document shall + * be saved if Modified; on cancel the closeEvent is rejected. + * @see KMainWindow#queryClose + * @see KMainWindow#closeEvent + */ + virtual bool queryClose(); + /** queryExit is called by KMainWindow when the last window of the application is going to be closed during the closeEvent(). + * Against the default implementation that just returns true, this calls saveOptions() to save the settings of the last window's + * properties. + * @see KMainWindow#queryExit + * @see KMainWindow#closeEvent + */ + virtual bool queryExit(); + + void mouseReleaseEvent(QMouseEvent* event); + + public slots: + + void slotFileNewWindow(); + /** clears the document in the actual view to reuse it as the new document */ + void slotFileNew(); + /** open a file and load it into the document*/ + void slotFileOpen(); + /** opens a file from the recent files menu */ + void slotFileOpenRecent( const KURL & ); + /** save a document */ + void slotFileSave(); + /** save a document by a new filename + * @return whether the file has been saved + */ + bool slotFileSaveAs(); + /** asks for saving if the file is modified, then closes the actual file and window*/ + void slotClose(); + /** print the actual file */ + void slotFilePrint(); + /** closes all open windows by calling close() on each memberList item until the list is empty, then quits the application. + * If queryClose() returns false because the user canceled the saveModified() dialog, the closing breaks. + */ + void slotQuit(); + /** put the marked text/object into the clipboard and remove + * it from the document + */ + void slotEditCut(); + /** put the marked text/object into the clipboard + */ + void slotEditCopy(); + /** paste the clipboard into the document + */ + void slotEditPaste(); + /** get a color from palette + */ + void slotColorFromPalette(); + /** get a color from screen + */ + void slotColorFromScreen(); + /** copies a color to clipboard + */ + void slotViewColorNames(); + /** changes the statusbar contents for the standard label permanently, used to indicate current actions. + * @param text the text that is displayed in the statusbar + */ + + void slotSelectionChanged( int, int ); + void slotClipboardChanged(); + void slotModified( bool ); + void slotPaletteAvailable( bool ); + + private: + + /** the configuration object of the application */ + KConfig *config; + + KAction *m_actSave, *m_actCut, *m_actCopy, *m_actPaste, *m_actPalette; + KToggleAction *m_actNames; + KRecentFilesAction *m_actRecent; + + /** view is the main widget which represents your working area. The View + * class should handle all events of the view widget. It is kept empty so + * you can create your view according to your application's needs by + * changing the view class. + */ + KColorEditView *view; + /** doc represents your actual document and is created only once. It keeps + * information such as filename and does the serialization of your files. + */ + KColorEditDoc *doc; + /** Whether in getting a color from screen */ + bool gettingColorFromScreen; + /** A color taken from screen */ + Color color; + /** Whether to view color names */ + bool viewColorNames; +}; + +#endif // KCOLOREDIT_H diff --git a/kcoloredit/kcoloreditdoc.cpp b/kcoloredit/kcoloreditdoc.cpp new file mode 100644 index 00000000..536300a5 --- /dev/null +++ b/kcoloredit/kcoloreditdoc.cpp @@ -0,0 +1,293 @@ +/*************************************************************************** + kcoloreditdoc.cpp - description + ------------------- + begin : Sat Jul 8 09:57:28 CEST 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +// include files for Qt +#include +#include +#include +#include + +// include files for KDE +#include +#include + +// application specific includes +#include "kcoloreditdoc.h" +#include "kcoloredit.h" +#include "kcoloreditview.h" +#include "resource.h" + +KColorEditDoc::KColorEditDoc(QWidget *parent, const char *name) : QObject(parent, name), + m_palette(), m_paletteHistory(&m_palette, 0) { + m_pViewList = new QPtrList(); + m_pViewList->setAutoDelete(true); +} + +KColorEditDoc::~KColorEditDoc() +{ +} + +void KColorEditDoc::addView(KColorEditView *view) +{ + m_pViewList->append(view); +} + +void KColorEditDoc::removeView(KColorEditView *view) +{ + m_pViewList->remove(view); +} + +void KColorEditDoc::setModified(bool b) { + m_modified = b; + + emit modified( b ); +} + +void KColorEditDoc::setAbsFilePath(const QString &filename) +{ + m_absFilePath=filename; +} + +const QString &KColorEditDoc::absFilePath() const +{ + return m_absFilePath; +} + +void KColorEditDoc::setTitle(const QString &_t) +{ + m_title=_t; +} + +const QString &KColorEditDoc::title() const +{ + return m_title; +} + +void KColorEditDoc::slotRedrawAllViews(KColorEditView *sender, bool newDocument) { + KColorEditView *w; + if(m_pViewList) + { + for(w=m_pViewList->first(); w!=0; w=m_pViewList->next()) + { + if(w!=sender) + w->redraw(newDocument); + } + } +} + +void KColorEditDoc::slotChangeViewMode(bool viewColorNames) { + KColorEditView *w; + if(m_pViewList) + { + for(w=m_pViewList->first(); w!=0; w=m_pViewList->next()) + { + w->slotViewColorNames(viewColorNames); + } + } +} + +bool KColorEditDoc::saveModified() +{ + bool completed=true; + + if(m_modified) + { + KColorEditApp *window=(KColorEditApp *) parent(); + int want_save = KMessageBox::warningYesNoCancel(window, + i18n("The current file has been modified.\n" + "Do you want to save it?"), QString::null, KStdGuiItem::save(), i18n("Do Not Save")); + switch(want_save) + { + case KMessageBox::Yes: + if (title() == i18n("Untitled")) + { + completed = window->slotFileSaveAs(); + } + else + { + completed = saveDocument(absFilePath()); + }; + if(!completed) + KMessageBox::sorry(0, errorString()); + break; + + case KMessageBox::No: + completed=true; + break; + + case KMessageBox::Cancel: + completed=false; + break; + + default: + completed=false; + break; + } + } + + return completed; +} + +void KColorEditDoc::closeDocument() +{ + deleteContents(); +} + +bool KColorEditDoc::newDocument() +{ + deleteContents(); + setModified(false); + setAbsFilePath( QDir::homeDirPath() ); + setTitle( i18n("Untitled") ); + setPaletteCursorPos(0); + setPaletteSelection(0, 0); + slotRedrawAllViews(0, true); + return true; +} + +bool KColorEditDoc::openDocument(const QString& filename) { + if(filename.isEmpty()) + return newDocument(); + else { + deleteContents(); + QFileInfo fileInfo(filename); + setAbsFilePath( fileInfo.absFilePath() ); + if(!m_palette.load( absFilePath() )) { + setErrorString(m_palette.errorString()); + return false; + } + setModified(false); + setTitle( fileInfo.fileName() ); + setPaletteCursorPos(m_palette.length()); + setPaletteSelection(0, 0); + slotRedrawAllViews(0, true); + KColorEditApp *window=(KColorEditApp*)parent(); + window->setCaption(m_title); + } + return true; +} + +bool KColorEditDoc::saveDocument(const QString& filename) { + if(!m_palette.save( filename )) { + setErrorString(m_palette.errorString()); + return false; + } + setModified(false); + return true; +} + +void KColorEditDoc::deleteContents() { + m_palette.deleteContents(); +} + +void KColorEditDoc::setErrorString(const QString& string) { + m_errorString = string; +} + +const QString& KColorEditDoc::errorString() const { + return m_errorString; +} + +PaletteHistory* KColorEditDoc::paletteHistory() { + return &m_paletteHistory; +} + +void KColorEditDoc::setPaletteCursorPos(const int pos) { + m_paletteCursorPos = pos; + + emit paletteAvailable( pos < m_palette.length() ); +} + +int KColorEditDoc::paletteCursorPos() { + return m_paletteCursorPos; +} + +void KColorEditDoc::setPaletteSelection(const int begin, const int end) { + m_paletteSelectionBegin = begin; + m_paletteSelectionEnd = end; + + emit selectionChanged( begin, end ); +} + +int KColorEditDoc::paletteSelectionBegin() const { + return m_paletteSelectionBegin; +} + +int KColorEditDoc::paletteSelectionEnd() const { + return m_paletteSelectionEnd; +} + +void KColorEditDoc::copyToClipboard(Palette& palette) { + QString text; + QTextOStream stream(&text); + palette.save(stream, 0, false); + KApplication::clipboard()->setText(text); + + emit clipboardChanged(); +} + +void KColorEditDoc::copy() { + Palette paletteCopy = m_palette.copy(paletteSelectionBegin(), + paletteSelectionEnd() - paletteSelectionBegin()); + copyToClipboard(paletteCopy); +} + +void KColorEditDoc::cut() { + Palette paletteCut = m_paletteHistory.cut(paletteSelectionBegin(), + paletteSelectionEnd() - paletteSelectionBegin()); + copyToClipboard(paletteCut); + setPaletteCursorPos(paletteSelectionBegin()); + setPaletteSelection(0, 0); + setModified(true); + slotRedrawAllViews(0); +} + +void KColorEditDoc::paste() { + Palette palettePaste; + QString text; + QTextIStream stream(&text); + text = KApplication::clipboard()->text(); + if(palettePaste.load( stream, false )) { + m_paletteHistory.paste(paletteCursorPos(), palettePaste); + setPaletteSelection(paletteCursorPos(), paletteCursorPos() + + palettePaste.length()); + setModified(true); + slotRedrawAllViews(0); + } +} + +void KColorEditDoc::insert(int index, const Color& color) { + Palette paletteInsert; + Color* insertColor = new Color(color); + paletteInsert.append(insertColor); + m_paletteHistory.paste(index, paletteInsert); + setPaletteCursorPos( index ); + setPaletteSelection(0, 0); + setModified(true); + slotRedrawAllViews(0); +} + +void KColorEditDoc::replace(int index, const Color& color) { + Palette paletteReplace; + Color* replaceColor = new Color(color); + paletteReplace.append(replaceColor); + m_paletteHistory.replace(index, paletteReplace); + setPaletteSelection(0, 0); + setModified(true); + slotRedrawAllViews(0); +} +#include "kcoloreditdoc.moc" diff --git a/kcoloredit/kcoloreditdoc.h b/kcoloredit/kcoloreditdoc.h new file mode 100644 index 00000000..1d209f46 --- /dev/null +++ b/kcoloredit/kcoloreditdoc.h @@ -0,0 +1,156 @@ +/*************************************************************************** + kcoloreditdoc.h - description + ------------------- + begin : Sat Jul 8 09:57:28 CEST 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KCOLOREDITDOC_H +#define KCOLOREDITDOC_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +// include files for QT +#include +#include +#include + +// application specific includes +#include "palette.h" +#include "palettehistory.h" + +// forward declaration of the KColorEdit classes +class KColorEditView; + +/** KColorEditDoc provides a document object for a document-view model. + * + * The KColorEditDoc class provides a document object that can be used in conjunction with the classes KColorEditApp and KColorEditView + * to create a document-view model for standard KDE applications based on KApplication and KMainWindow. Thereby, the document object + * is created by the KColorEditApp instance and contains the document structure with the according methods for manipulation of the document + * data by KColorEditView objects. Also, KColorEditDoc contains the methods for serialization of the document data from and to files. + * + * @author Source Framework Automatically Generated by KDevelop, (c) The KDevelop Team. + * @version KDevelop version 0.4 code generation + */ +class KColorEditDoc : public QObject +{ + Q_OBJECT + + public: + /** Constructor for the fileclass of the application */ + KColorEditDoc(QWidget *parent, const char *name=0); + /** Destructor for the fileclass of the application */ + ~KColorEditDoc(); + + /** adds a view to the document which represents the document contents. Usually this is your main view. */ + void addView(KColorEditView *view); + /** removes a view from the list of currently connected views */ + void removeView(KColorEditView *view); + /** sets the modified flag for the document after a modifying action on the view connected to the document.*/ + void setModified(bool modified); + /** returns if the document is modified or not. Use this to determine if your document needs saving by the user on closing.*/ + bool isModified() const { return m_modified; }; + /** "save modified" - asks the user for saving if the document is modified */ + bool saveModified(); + /** deletes the document's contents */ + void deleteContents(); + /** initializes the document generally */ + bool newDocument(); + /** closes the actual document */ + void closeDocument(); + /** loads the document */ + bool openDocument(const QString& filename); + /** saves the document */ + bool saveDocument(const QString& filename); + /** sets the path to the file connected with the document */ + void setAbsFilePath(const QString &filename); + /** returns the pathname of the current document file*/ + const QString& absFilePath() const; + /** sets the filename of the document */ + void setTitle(const QString &_t); + /** returns the title of the document */ + const QString& title() const; + /** @return a description of a possible unsuccessfull IO operation */ + const QString& errorString() const; + /** returns a pointer to paletteHistory */ + PaletteHistory* paletteHistory(); + /** sets a palette cursor position */ + void setPaletteCursorPos(const int pos); + /** @return a palette cursor position */ + int paletteCursorPos(); + /** Sets palette selection and enables or disables cut/paste + * depending on whether any colors are selected + */ + void setPaletteSelection(const int begin, const int end); + /** Gets lesser selection position or equal selection position + * if no colors are selected + */ + int paletteSelectionBegin() const; + /** Gets greater selection position or equal selection position + * if no colors are selected + */ + int paletteSelectionEnd() const; + /** Copies a selection into a clipboard */ + void copy(); + /** Cuts a selection into a clipboard */ + void cut(); + /** Pastes a selection from a clipboard */ + void paste(); + /** Inserts a color at index */ + void insert(int index, const Color& color); + /** Replaces a color at index */ + void replace(int index, const Color& color); + + protected: + /** Sets an error string if an IO operation was unsuccesfull */ + void setErrorString(const QString& string); + /** Copies a palette to clipboard */ + void copyToClipboard(Palette& palette); + + public slots: + /** Calls redraw() on all views connected to the document object, + * except for sender if sender is not null + */ + void slotRedrawAllViews(KColorEditView* sender, bool newDocument = false); + /** Sets a view mode */ + void slotChangeViewMode(bool viewColorNames); + + signals: + + void selectionChanged( int, int ); + void clipboardChanged(); + void modified( bool ); + void paletteAvailable( bool ); + + public: + /** the list of the views currently connected to the document */ + QPtrList *m_pViewList; + + private: + /** the modified flag of the current document */ + bool m_modified; + QString m_title; + QString m_absFilePath; + QString m_errorString; + + protected: + Palette m_palette; + PaletteHistory m_paletteHistory; + int m_paletteCursorPos; + int m_paletteSelectionBegin; + int m_paletteSelectionEnd; +}; + +#endif // KCOLOREDITDOC_H diff --git a/kcoloredit/kcoloreditui.rc b/kcoloredit/kcoloreditui.rc new file mode 100644 index 00000000..d2820c12 --- /dev/null +++ b/kcoloredit/kcoloreditui.rc @@ -0,0 +1,26 @@ + + + + + + + + + &File + + + &Color + + + + + + + +Main Toolbar + + + + + + diff --git a/kcoloredit/kcoloreditview.cpp b/kcoloredit/kcoloreditview.cpp new file mode 100644 index 00000000..fe22f136 --- /dev/null +++ b/kcoloredit/kcoloreditview.cpp @@ -0,0 +1,282 @@ +/*************************************************************************** + kcoloreditview.cpp - description + ------------------- + begin : Sat Jul 8 09:57:28 CEST 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +// include files for Qt +#include +#include +#include +#include +#include +#include +#include + +// include files for KDE +#include +#include + +// application specific includes +#include "main.h" +#include "kcoloreditview.h" +#include "kcoloreditdoc.h" +#include "kcoloredit.h" +#include "palette.h" + +KColorEditView::KColorEditView(QWidget *parent, const char *name) : QSplitter(parent, name) { + colorSelector = new ColorSelector(this); + colorSelector->slotSetColor( + Color( RGB_MAX_COMPONENT_VALUE, RGB_MAX_COMPONENT_VALUE, RGB_MAX_COMPONENT_VALUE, "" )); + QWidget* paletteViewArea = new QWidget(this); + QVBoxLayout* paletteLayout = new QVBoxLayout(paletteViewArea); + paletteView = new PaletteView(16, 16, 2, this, paletteViewArea); + paletteLayout->addWidget(paletteView, 10); + QHBoxLayout* layout = new QHBoxLayout(); + QVBoxLayout* addColorLayout = new QVBoxLayout(4); + addColorLayout->setMargin(8); + QHBoxLayout* buttonsLayout = new QHBoxLayout(4); + QPushButton* addColorButton = new QPushButton(i18n( "Add Color" ), paletteViewArea); + connect(addColorButton, SIGNAL( clicked() ), SLOT( slotAddColor() )); + buttonsLayout->addWidget(addColorButton); + buttonsLayout->addStretch(10); + addColorLayout->addLayout(buttonsLayout); + QCheckBox* atCursorCheckBox = new QCheckBox(i18n( "At cursor" ), paletteViewArea); + connect(atCursorCheckBox, SIGNAL( toggled(bool) ), SLOT( slotAddColorAtCursor(bool) )); + addColorLayout->addWidget(atCursorCheckBox); + overwriteCheckBox = new QCheckBox(i18n( "Overwrite" ), paletteViewArea); + connect(overwriteCheckBox, SIGNAL( toggled(bool) ), SLOT( slotAddColorOverwrite(bool) )); + slotAddColorAtCursor(false); + slotAddColorOverwrite(false); + addColorLayout->addWidget(overwriteCheckBox); + addColorLayout->addStretch(10); + //KSeparator* hLine = new KSeparator(KSeparator::HLine, paletteViewArea); + //addColorLayout->addWidget(hLine); + //addColorLayout->addStretch(10); + //QCheckBox* cursorFollowsChosenColor = new QCheckBox(i18n( "Cursor follows" ), paletteViewArea); + //addColorLayout->addWidget(cursorFollowsChosenColor); + //connect(cursorFollowsChosenColor, SIGNAL( toggled(bool) ), + // paletteView, SLOT( slotCursorFollowsChosenColor(bool) )); + //cursorFollowsChosenColor->toggle(); + paletteView->slotCursorFollowsChosenColor(true); + layout->addLayout(addColorLayout, 0); + QVGroupBox* colorAtCursorFrame = new QVGroupBox(i18n("Color at Cursor"), paletteViewArea); + QWidget* colorAtCursorFrameArea = new QWidget(colorAtCursorFrame); + QVBoxLayout* colorAtCursorLayout = new QVBoxLayout(colorAtCursorFrameArea, 4); + QHBoxLayout* colorNameLayout = new QHBoxLayout(0); + QLabel* nameLabel = new QLabel(i18n( "Name" ) + ": ", colorAtCursorFrameArea); + colorNameLayout->addWidget(nameLabel, 0); + colorName = new QLineEdit(colorAtCursorFrameArea); + connect(colorName, SIGNAL( textChanged(const QString&) ), SLOT( slotSetColorName(const QString&) )); + colorNameLayout->addWidget(colorName, 10); + colorAtCursorLayout->addLayout(colorNameLayout); + QGridLayout* colorAtCursorComponentsLayout = new QGridLayout(3, 6, 4); + colorAtCursorLayout->addLayout(colorAtCursorComponentsLayout); + colorAtCursorComponentsLayout->setColStretch(1, 10); + colorAtCursorComponentsLayout->addColSpacing(2, 8); + colorAtCursorComponentsLayout->setColStretch(4, 10); + colorAtCursorComponentsLayout->setColStretch(5, 10); + QLabel* hLabel = new QLabel("H: ", colorAtCursorFrameArea); + colorAtCursorComponentsLayout->addWidget(hLabel, 0, 0); + colorAtCursorHValueLabel = new QLabel("", colorAtCursorFrameArea); + setColorAtCursorComponentValueLabelSizes(colorAtCursorHValueLabel); + colorAtCursorComponentsLayout->addWidget(colorAtCursorHValueLabel, 0, 1); + QLabel* sLabel = new QLabel("S: ", colorAtCursorFrameArea); + colorAtCursorComponentsLayout->addWidget(sLabel, 1, 0); + colorAtCursorSValueLabel = new QLabel("", colorAtCursorFrameArea); + setColorAtCursorComponentValueLabelSizes(colorAtCursorSValueLabel); + colorAtCursorComponentsLayout->addWidget(colorAtCursorSValueLabel, 1, 1); + QLabel* vLabel = new QLabel("V: ", colorAtCursorFrameArea); + colorAtCursorComponentsLayout->addWidget(vLabel, 2, 0); + colorAtCursorVValueLabel = new QLabel("", colorAtCursorFrameArea); + setColorAtCursorComponentValueLabelSizes(colorAtCursorVValueLabel); + colorAtCursorComponentsLayout->addWidget(colorAtCursorVValueLabel, 2, 1); + QLabel* rLabel = new QLabel("R: ", colorAtCursorFrameArea); + colorAtCursorComponentsLayout->addWidget(rLabel, 0, 3); + colorAtCursorRValueLabel = new QLabel("", colorAtCursorFrameArea); + setColorAtCursorComponentValueLabelSizes(colorAtCursorRValueLabel); + colorAtCursorComponentsLayout->addWidget(colorAtCursorRValueLabel, 0, 4); + QLabel* gLabel = new QLabel("G: ", colorAtCursorFrameArea); + colorAtCursorComponentsLayout->addWidget(gLabel, 1, 3); + colorAtCursorGValueLabel = new QLabel("", colorAtCursorFrameArea); + setColorAtCursorComponentValueLabelSizes(colorAtCursorGValueLabel); + colorAtCursorComponentsLayout->addWidget(colorAtCursorGValueLabel, 1, 4); + QLabel* bLabel = new QLabel("B: ", colorAtCursorFrameArea); + colorAtCursorComponentsLayout->addWidget(bLabel, 2, 3); + colorAtCursorBValueLabel = new QLabel("", colorAtCursorFrameArea); + setColorAtCursorComponentValueLabelSizes(colorAtCursorBValueLabel); + colorAtCursorComponentsLayout->addWidget(colorAtCursorBValueLabel, 2, 4); + QHBoxLayout* colorAtCursorRgbStringLayout = new QHBoxLayout(); + QLabel* colorAtCursorRgbStringLabel = + new QLabel("RGB " + i18n( "hex." ) + ": ", colorAtCursorFrameArea); + colorAtCursorRgbStringLayout->addWidget(colorAtCursorRgbStringLabel); + colorAtCursorRgbStringValueLabel = new QLabel("", colorAtCursorFrameArea); + colorAtCursorRgbStringValueLabel->setFixedWidth( + colorAtCursorRgbStringValueLabel->fontMetrics().width( QString("8888888") )); + colorAtCursorRgbStringLayout->addWidget(colorAtCursorRgbStringValueLabel); + colorAtCursorRgbStringLayout->addStretch(); + colorAtCursorLayout->addLayout(colorAtCursorRgbStringLayout); + layout->addWidget(colorAtCursorFrame, 10); + layout->addSpacing(8); + paletteLayout->addSpacing(4); + paletteLayout->addLayout(layout); + paletteLayout->addSpacing(4); + inColorNameChanging = false; + doNotUpdateColorLabels = false; +} + +KColorEditView::~KColorEditView() { +} + +void KColorEditView::setColorAtCursorComponentValueLabelSizes(QLabel* const label) { + label->setMinimumWidth(label->fontMetrics().width( QString("888") )); + label->setMaximumWidth(label->fontMetrics().width( QString("88888") )); +} + +KColorEditDoc *KColorEditView::document() const { + KColorEditApp *theApp=(KColorEditApp *) parentWidget(); + + return theApp->document(); +} + +void KColorEditView::print(QPrinter *pPrinter) { + QPainter printpainter; + printpainter.begin(pPrinter); + + // TODO: add your printing code here + + printpainter.end(); +} + +void KColorEditView::chooseColor(Color* const color) { + colorSelector->slotSetColor(color); +} + +void KColorEditView::slotCursorPosChanged(int position) { + Palette* palette = document()->paletteHistory()->editableStream(); + if(position < palette->length()) { + Color* color = palette->color(position); + QString string; + inColorNameChanging = true; + colorName->setText(color->name()); + colorName->setEnabled(true); + inColorNameChanging = false; + int rComponent = color->component(Color::RED_INDEX); + int gComponent = color->component(Color::GREEN_INDEX); + int bComponent = color->component(Color::BLUE_INDEX); + colorAtCursorRValueLabel->setText(string.setNum( rComponent )); + colorAtCursorGValueLabel->setText(string.setNum( gComponent )); + colorAtCursorBValueLabel->setText(string.setNum( bComponent )); + QColor hsvColor(rComponent, gComponent, bComponent); + int hComponent; + int sComponent; + int vComponent; + hsvColor.hsv(&hComponent, &sComponent, &vComponent); + colorAtCursorHValueLabel->setText(string.setNum( hComponent )); + colorAtCursorSValueLabel->setText(string.setNum( sComponent )); + colorAtCursorVValueLabel->setText(string.setNum( vComponent )); + colorAtCursorRgbStringValueLabel->setText(string.sprintf( "%02x%02x%02x", + rComponent, gComponent, bComponent )); + } else { + colorName->setText(""); + colorName->setEnabled(false); + colorAtCursorHValueLabel->setText(""); + colorAtCursorSValueLabel->setText(""); + colorAtCursorVValueLabel->setText(""); + colorAtCursorRValueLabel->setText(""); + colorAtCursorGValueLabel->setText(""); + colorAtCursorBValueLabel->setText(""); + colorAtCursorRgbStringValueLabel->setText(""); + } +} + +void KColorEditView::slotViewColorNames(bool viewColorNames) { + paletteView->slotViewColorNames(viewColorNames); +} + +void KColorEditView::updateColorValueLabels() { + if(!doNotUpdateColorLabels) + slotCursorPosChanged(document()->paletteCursorPos()); +} + +void KColorEditView::redraw(bool newDocument) { + if(newDocument) + paletteView->setScrollBarValue(0); + paletteView->redraw(); + updateColorValueLabels(); +} + +void KColorEditView::slotAddColor() { + Color color = colorSelector->color(); + Palette* palette = document()->paletteHistory()->editableStream(); + color.setName(""); + int index; + if(addColorAtCursor) + index = document()->paletteCursorPos(); + else + index = palette->length(); + switch(addColorMode) + { + case INSERT_COLOR: + document()->insert(index, color); + break; + + case REPLACE_COLOR: + if(index < palette->length()) + document()->replace(index, color); + else + document()->insert(index, color); + break; + + } +} + +void KColorEditView::slotAddColorAtCursor(bool atCursor) { + addColorAtCursor = atCursor; + overwriteCheckBox->setEnabled(addColorAtCursor); +} + +void KColorEditView::slotAddColorOverwrite(bool overwrite) { + if(overwrite) + addColorMode = REPLACE_COLOR; + else + addColorMode = INSERT_COLOR; +} + +void KColorEditView::slotSetColorName(const QString& name) { + if(!inColorNameChanging) { + /* + Palette* palette = getDocument()->getPaletteHistory()->getEditableStream(); + int cursorPos = getDocument()->getPaletteCursorPos(); + if(cursorPos < palette->length()) { + palette->getColor(cursorPos)->setName(name); + getDocument()->setModified(true); + getDocument()->slotRedrawAllViews(this); + } + */ + Palette* palette = document()->paletteHistory()->editableStream(); + int cursorPos = document()->paletteCursorPos(); + if(cursorPos < palette->length()) { + Color newColor( + palette->color(cursorPos)->component(Color::RED_INDEX), + palette->color(cursorPos)->component(Color::GREEN_INDEX), + palette->color(cursorPos)->component(Color::BLUE_INDEX), + name); + doNotUpdateColorLabels = true; + document()->replace(cursorPos, newColor); + doNotUpdateColorLabels = false; + } + } +} +#include "kcoloreditview.moc" diff --git a/kcoloredit/kcoloreditview.h b/kcoloredit/kcoloreditview.h new file mode 100644 index 00000000..ec0ca17f --- /dev/null +++ b/kcoloredit/kcoloreditview.h @@ -0,0 +1,128 @@ +/*************************************************************************** + kcoloreditview.h - description + ------------------- + begin : Sat Jul 8 09:57:28 CEST 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KCOLOREDITVIEW_H +#define KCOLOREDITVIEW_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +// include files for Qt +#include +#include +#include + +// application specific includes +#include "colorselector.h" +#include "paletteview.h" + +class KColorEditDoc; + +/** The KColorEditView class provides the view widget for the KColorEditApp instance. + * The View instance inherits QWidget as a base class and represents the view object of a KMainWindow. As KColorEditView is part of the + * docuement-view model, it needs a reference to the document object connected with it by the KColorEditApp class to manipulate and display + * the document structure provided by the KColorEditDoc class. + * + * @author Source Framework Automatically Generated by KDevelop, (c) The KDevelop Team. + * @version KDevelop version 0.4 code generation + */ +class KColorEditView : public QSplitter { + Q_OBJECT + + public: + /** Constructor for the main view */ + KColorEditView(QWidget *parent = 0, const char *name = 0); + /** Destructor for the main view */ + ~KColorEditView(); + + /** returns a pointer to the document connected to the view instance. Mind that this method requires a KColorEditApp instance as a parent + * widget to get to the window document pointer by calling the KColorEditApp::getDocument() method. + * + * @see KColorEditApp#getDocument + */ + KColorEditDoc *document() const; + + /** Contains the implementation for printing functionality */ + void print(QPrinter *pPrinter); + /** Chooses a color to the color selector */ + void chooseColor(Color* const color); + /** Updates the view after the document has been changed */ + void redraw(bool newDocument); + + public slots: + /** Notifies that the cursor position changed */ + void slotCursorPosChanged(int position); + /** Whether to view color names */ + void slotViewColorNames(bool viewColorNames); + + protected: + ColorSelector* colorSelector; + PaletteView* paletteView; + + protected slots: + /** Adds a color from color selector at cursor position. It inserts or replaces a color, + * depending on addColorMode + */ + void slotAddColor(); + /** Sets if add a color at cursor */ + void slotAddColorAtCursor(bool atCursor); + /** Sets whether insert or replace a color */ + void slotAddColorOverwrite(bool overwrite); + /** Sets a color name */ + void slotSetColorName(const QString& name); + + protected: + /** Add color mode constants */ + enum { INSERT_COLOR = 0, + REPLACE_COLOR = 1 }; + + /** Color mode widget */ + QCheckBox* overwriteCheckBox; + /** Color name widget */ + QLineEdit* colorName; + /** H component value label of the color at cursor */ + QLabel* colorAtCursorHValueLabel; + /** S component value label of the color at cursor */ + QLabel* colorAtCursorSValueLabel; + /** V component value label of the color at cursor */ + QLabel* colorAtCursorVValueLabel; + /** R component value label of the color at cursor */ + QLabel* colorAtCursorRValueLabel; + /** G component value label of the color at cursor */ + QLabel* colorAtCursorGValueLabel; + /** B component value label of the color at cursor */ + QLabel* colorAtCursorBValueLabel; + /** RGB Hex string value label of the color at cursor */ + QLabel* colorAtCursorRgbStringValueLabel; + /** If add a color at cursor */ + bool addColorAtCursor; + /** Add color mode */ + int addColorMode; + /** If in color name changing */ + bool inColorNameChanging; + /** Whether not to update color labels */ + bool doNotUpdateColorLabels; + + protected: + /** Sets component value label of the color at cursor sizes */ + void setColorAtCursorComponentValueLabelSizes(QLabel* const label); + /** Updates color value labels */ + void updateColorValueLabels(); +}; + +#endif // KCOLOREDITVIEW_H diff --git a/kcoloredit/kxycolorselector.cpp b/kcoloredit/kxycolorselector.cpp new file mode 100644 index 00000000..e12f7987 --- /dev/null +++ b/kcoloredit/kxycolorselector.cpp @@ -0,0 +1,186 @@ +/*************************************************************************** + kxycolorselector.cpp - description + ------------------- + begin : Fri Jul 7 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include + +#include "kxycolorselector.h" + +KXYColorSelector::KXYColorSelector(QWidget *parent, const char *name) : KXYSelector(parent,name) { + setBackgroundMode(NoBackground); + setRange(0, 0, COMPONENT_SELECTION_RESOLUTION - 1, COMPONENT_SELECTION_RESOLUTION - 1); + setType(TYPE_NONE); + setGlobalComponent(0); + setMinimumSize(RGB_MAX_COMPONENT_VALUE/2 + 4, RGB_MAX_COMPONENT_VALUE/2 + 4); + setMaximumSize(512, 512); + updateContents(); +} +KXYColorSelector::~KXYColorSelector() { + +} + +void KXYColorSelector::setType(const int type) { + this->type = type; +} + +void KXYColorSelector::updateContents() { + drawPalette(&pixmap); + repaint(); +} + +void KXYColorSelector::resizeEvent(QResizeEvent*) { + setValues(xValue(), yValue()); + updateContents(); +} + +void KXYColorSelector::drawContents(QPainter* painter) { + painter->drawPixmap(contentsRect().x(), contentsRect().y(), pixmap); +} + +void KXYColorSelector::drawCursor(QPainter* painter, int x, int y) { + QColor color; + int colorX = x - contentsRect().x(); + int colorY = y - contentsRect().y(); + if(colorX < 0) + colorX = 0; + if(colorY < 0) + colorY = 0; + if(colorX > contentsRect().width() - 1) + colorX = contentsRect().width() - 1; + if(colorY > contentsRect().height() - 1) + colorY = contentsRect().height() - 1; + setColor(&color, colorX, colorY); + QColor cursorColor; + if(( 2*color.red() + 4*color.green() + 1*color.blue() )*1.0/ + ( 2*255 + 4*255 + 1*255 ) > 0.65) + cursorColor = Qt::black; + else + cursorColor = Qt::white; + painter->setPen(QPen( cursorColor )); + const int lineBegin = 2; + const int lineEnd = 6; + painter->drawLine(x + lineBegin, y - lineBegin, x + lineEnd, y - lineEnd); + painter->drawLine(x + lineBegin, y + lineBegin, x + lineEnd, y + lineEnd); + painter->drawLine(x - lineBegin, y + lineBegin, x - lineEnd, y + lineEnd); + painter->drawLine(x - lineBegin, y - lineBegin, x - lineEnd, y - lineEnd); +} + +void KXYColorSelector::setGlobalComponent(const int component) { + m_globalComponent = component; +} + +int KXYColorSelector::globalComponent() const{ + return m_globalComponent; +} + +void KXYColorSelector::setColor(QColor* const color, const int x, const int y) { + int xSize = contentsRect().width(); + int ySize = contentsRect().height(); + switch(type) { + case TYPE_HS: + color->setHsv(360*x/xSize, 256*( ySize - 1 - y )/ySize, + globalComponent()); + break; + + case TYPE_VS: + color->setHsv(globalComponent(), 256*( ySize - 1 - y )/ySize, + 256*x/xSize); + break; + + case TYPE_HV: + color->setHsv(360*x/xSize, globalComponent(), + 256*( ySize - 1 - y )/ySize); + break; + + case TYPE_RG: + color->setRgb(x/xSize, 256*( ySize - 1 - y )/ySize, + globalComponent()); + break; + + case TYPE_GB: + color->setRgb(globalComponent(), 256*x/xSize, + 256*( ySize - 1 - y )/ySize); + break; + + case TYPE_BR: + color->setRgb(256*( ySize - 1 - y )/ySize, globalComponent(), + 256*x/xSize); + break; + + case TYPE_NONE: + color->setRgb(192, 192, 192); + break; + + } +} + +QColor* KXYColorSelector::standardColorsPalette() { + QColor* palette = new QColor[STANDARD_PALETTE_SIZE]; + int i = 0; + palette[i++] = Qt::red; + palette[i++] = Qt::green; + palette[i++] = Qt::blue; + palette[i++] = Qt::cyan; + palette[i++] = Qt::magenta; + palette[i++] = Qt::yellow; + palette[i++] = Qt::darkRed; + palette[i++] = Qt::darkGreen; + palette[i++] = Qt::darkBlue; + palette[i++] = Qt::darkCyan; + palette[i++] = Qt::darkMagenta; + palette[i++] = Qt::darkYellow; + palette[i++] = Qt::white; + palette[i++] = Qt::lightGray; + palette[i++] = Qt::gray; + palette[i++] = Qt::darkGray; + palette[i++] = Qt::black; + return palette; +} + +void KXYColorSelector::drawPalette(QPixmap* pixmap) { + int xSize = contentsRect().width(); + int ySize = contentsRect().height(); + QImage image(xSize, ySize, 32); + QColor color; + int x; + int y; + + if(type != TYPE_NONE) { + for (y = 0; y < ySize; ++y) + { + unsigned int* p = (unsigned int*)image.scanLine(y); + for(x = 0; x < xSize; ++x) + { + setColor(&color, x, y); + *p = color.rgb(); + ++p; + } + } + if (QColor::numBitPlanes() <= 8) + { + QColor* standardPalette = standardColorsPalette(); + KImageEffect::dither(image, standardPalette, STANDARD_PALETTE_SIZE); + delete[] standardPalette; + } + } + pixmap->convertFromImage(image); +} + +#include "kxycolorselector.moc" diff --git a/kcoloredit/kxycolorselector.h b/kcoloredit/kxycolorselector.h new file mode 100644 index 00000000..3213c59c --- /dev/null +++ b/kcoloredit/kxycolorselector.h @@ -0,0 +1,97 @@ +/*************************************************************************** + kxycolorselector.h - description + ------------------- + begin : Fri Jul 7 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KXYCOLORSELECTOR_H +#define KXYCOLORSELECTOR_H + +#include +#include + +#include "main.h" + +/** A widget for selecting two of color components + * @author Artur Rataj + */ +class KXYColorSelector : public KXYSelector { + Q_OBJECT + +public: + /** The types of the selector. They specify a color component subset */ + enum { TYPE_NONE = 0, + TYPE_HS = 1, + TYPE_VS = 2, + TYPE_HV = 3, + TYPE_RG = 4, + TYPE_GB = 5, + TYPE_BR = 6, + TYPE_ = 7, + /** Component selection resolution */ + COMPONENT_SELECTION_RESOLUTION = 10000 }; + +public: + /** Constructs a two-dimensional color component selector widget, + * with a type TYPE_NONE and ranges 0 .. MAX_COLOR_COMPONENT_VALUE + */ + KXYColorSelector(QWidget *parent=0, const char *name=0); + ~KXYColorSelector(); + /** Set the type of the selector */ + void setType(const int type); + /** Update the pixmap */ + void updateContents(); + /** Set the global component */ + void setGlobalComponent(const int component); + /** @return The global component */ + int globalComponent() const; + +protected: + /** The number of colors that are used to dither the pixmap + * if number of color planes <= 8. The palette returned by + * getStandardColorsPalette() is of the size. + */ + enum { STANDARD_PALETTE_SIZE = 17 }; + + /** A type of the selector */ + int type; + /** The global component value */ + int m_globalComponent; + + /** Draws the contents of the widget on a pixmap, + * which is used for buffering. + */ + virtual void drawPalette( QPixmap *pixmap ); + /** @reimplemented */ + virtual void resizeEvent( QResizeEvent * ); + /** Reimplemented from KXYSelector. This drawing is + * buffered in a pixmap here. As real drawing + * routine, drawPalette() is used. + */ + virtual void drawContents( QPainter *painter ); + /** Draws the cursor */ + virtual void drawCursor(QPainter* painter, int x, int y); + /** set a color at a given coordinate */ + virtual void setColor(QColor* const color, const int x, const int y); + /** @return STANDARD_PALETTE_SIZE colors used to dither the + * pixmap if number of color planes <= 8 + */ + QColor* standardColorsPalette(); + +private: + /* The buffering pixmap */ + QPixmap pixmap; +}; + +#endif diff --git a/kcoloredit/kzcolorselector.cpp b/kcoloredit/kzcolorselector.cpp new file mode 100644 index 00000000..36953180 --- /dev/null +++ b/kcoloredit/kzcolorselector.cpp @@ -0,0 +1,170 @@ +/*************************************************************************** + kzcolorselector.cpp - description + ------------------- + begin : Fri Jul 14 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include + +#include "main.h" +#include "kzcolorselector.h" + +KZColorSelector::KZColorSelector(Orientation o, QWidget *parent, const char *name) : + KSelector(o, parent, name) { + baseColorH = -1; + baseColorS = 0; + baseColorV = 0; + pixmap.setOptimization( QPixmap::BestOptim ); +} +KZColorSelector::~KZColorSelector() { +} + +void KZColorSelector::setType(const int type) { + this->type = type; + switch(this->type) { + case TYPE_H: + setRange(0, HSV_MAX_H_VALUE); + break; + + case TYPE_S: + setRange(0, HSV_MAX_S_VALUE); + break; + + case TYPE_V: + setRange(0, HSV_MAX_V_VALUE); + break; + + } +} + +void KZColorSelector::updateContents() { + drawPalette(&pixmap); + repaint(false); +} + +void KZColorSelector::resizeEvent(QResizeEvent*) { + updateContents(); +} + +void KZColorSelector::drawContents(QPainter* painter) { + painter->drawPixmap(contentsRect().x(), contentsRect().y(), pixmap); +} + +void KZColorSelector::setBaseColor(const QColor& color) { + color.hsv(&baseColorH, &baseColorS, &baseColorV); +} + +void KZColorSelector::setBaseColorHsv(const int colorH, + const int colorS, const int colorV) { + baseColorH = colorH; + baseColorS = colorS; + baseColorV = colorV; +} + +void KZColorSelector::updatePointerPos() { + int pos; + switch(type) { + case TYPE_H: + pos = baseColorH; + if(pos < 0) + pos = 0; + break; + + case TYPE_S: + pos = baseColorS; + break; + + case TYPE_V: + pos = baseColorV; + break; + + default: + pos = 0; + break; + + } + setValue(pos); +} + +void KZColorSelector::setColor(QColor* const color, const int y) { + int ySize = contentsRect().height(); + switch(type) { + case TYPE_H: + color->setHsv(( ySize - 1 - y )*360/ySize, baseColorS, baseColorV); + break; + + case TYPE_S: + color->setHsv(baseColorH, ( ySize - 1 - y )*256/ySize, baseColorV); + break; + + case TYPE_V: + color->setHsv(baseColorH, baseColorS, ( ySize - 1 - y )*256/ySize); + break; + + } +} + +QColor* KZColorSelector::getStandardColorsPalette() { + QColor* palette = new QColor[( int )STANDARD_PALETTE_SIZE]; + int i = 0; + palette[i++] = Qt::red; + palette[i++] = Qt::green; + palette[i++] = Qt::blue; + palette[i++] = Qt::cyan; + palette[i++] = Qt::magenta; + palette[i++] = Qt::yellow; + palette[i++] = Qt::darkRed; + palette[i++] = Qt::darkGreen; + palette[i++] = Qt::darkBlue; + palette[i++] = Qt::darkCyan; + palette[i++] = Qt::darkMagenta; + palette[i++] = Qt::darkYellow; + palette[i++] = Qt::white; + palette[i++] = Qt::lightGray; + palette[i++] = Qt::gray; + palette[i++] = Qt::darkGray; + palette[i++] = Qt::black; + return palette; +} + +void KZColorSelector::drawPalette(QPixmap* pixmap) { + int xSize = contentsRect().width(); + int ySize = contentsRect().height(); + QImage image(xSize, ySize, 32); + QColor color; + int x; + int y; + + for (y = 0; y < ySize; ++y) + { + unsigned int* p = (unsigned int*)image.scanLine(y); + for(x = 0; x < xSize; ++x) + { + setColor(&color, y); + *p = color.rgb(); + ++p; + } + } + if (QColor::numBitPlanes() <= 8) + { + QColor* standardPalette = getStandardColorsPalette(); + KImageEffect::dither(image, standardPalette, STANDARD_PALETTE_SIZE); + delete[] standardPalette; + } + pixmap->convertFromImage(image); +} +#include "kzcolorselector.moc" diff --git a/kcoloredit/kzcolorselector.h b/kcoloredit/kzcolorselector.h new file mode 100644 index 00000000..cafdb254 --- /dev/null +++ b/kcoloredit/kzcolorselector.h @@ -0,0 +1,89 @@ +/*************************************************************************** + kzcolorselector.h - description + ------------------- + begin : Fri Jul 14 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KZCOLORSELECTOR_H +#define KZCOLORSELECTOR_H + +#include "qcolor.h" +#include "qpixmap.h" +#include "kselect.h" + +#include "color.h" + +/** A widget for selecting a color component + * @author Artur Rataj + */ +class KZColorSelector : public KSelector { + Q_OBJECT + +public: + /** Selector type constants */ + enum { TYPE_H = 0, + TYPE_S = 1, + TYPE_V = 2 }; + + /** Constructs the widget */ + KZColorSelector(Orientation o, QWidget *parent=0, const char *name=0); + ~KZColorSelector(); + /** Sets the selector type */ + void setType(const int type); + /** Update the pixmap */ + void updateContents(); + /** Set the global components */ + void setBaseColor(const QColor& color); + /** Set the global components using HSV components */ + void setBaseColorHsv(const int colorH, const int colorS, const int colorV); + /** Updates a pointer position due to the base color */ + void updatePointerPos(); + +protected: + /** The number of colors that are used to dither the pixmap + * if number of color planes <= 8. The palette returned by + * getStandardColorsPalette() is of the size. + */ + enum { STANDARD_PALETTE_SIZE = 17 }; + + /** A type of the selector */ + int type; + /** A base color H component */ + int baseColorH; + /** A base color S component */ + int baseColorS; + /** A base color V component */ + int baseColorV; + + /** Draws the contents of the widget on a pixmap, + * which is used for buffering. + */ + virtual void drawPalette( QPixmap *pixmap ); + /** @reimplemented */ + virtual void resizeEvent( QResizeEvent * ); + /** Draws a color gradient in the selector */ + virtual void drawContents( QPainter *painter ); + /** Sets a color at a given coordinate */ + virtual void setColor(QColor* const color, const int y); + /** @return STANDARD_PALETTE_SIZE colors used to dither the + * pixmap if number of color planes <= 8 + */ + QColor* getStandardColorsPalette(); + +private: + /* The buffering pixmap */ + QPixmap pixmap; +}; + +#endif diff --git a/kcoloredit/loadpalettedlg.cpp b/kcoloredit/loadpalettedlg.cpp new file mode 100644 index 00000000..b426a874 --- /dev/null +++ b/kcoloredit/loadpalettedlg.cpp @@ -0,0 +1,111 @@ +/*************************************************************************** + loadpalettedlg.cpp - description + ------------------- + begin : Sat Jul 8 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "main.h" +#include "palette.h" +#include "loadpalettedlg.h" + +LoadPaletteDlg::LoadPaletteDlg(QWidget *parent, const char *name) + : KDialogBase(parent, name, true, i18n( "Load Palette" ), + Ok|Cancel, Ok, true) { + fileName = ""; + QWidget *mainWidget = new QWidget( this ); + setMainWidget( mainWidget ); + QVBoxLayout* topLayout = new QVBoxLayout(mainWidget, 0, spacingHint()); + QLabel* label = new QLabel(i18n( "Select a palette:" ), mainWidget); + topLayout->addWidget(label); + paletteBox = new QComboBox(false, mainWidget); + browseFileNameInserted = false; + QStringList palettesList = Palette::kdePalettes(); + for(QStringList::Iterator palette = palettesList.begin(); + palette != palettesList.end(); ++palette) { + bool prepend = (*palette).contains( "colors/Custom_Colors" ); + QString fileName = locate("config", (*palette)); + if(prepend) { + palettesFileNames.prepend(fileName); + setFileName(&fileName); + } else { + palettesFileNames.append(fileName); + if(palette == palettesList.begin()) + setFileName(&fileName); + } + QString paletteName = (*palette).mid(palettesDir.length() + 1); + if(paletteName == "Custom_Colors") + paletteName = i18n("Custom Colors"); + else if(paletteName == "Recent_Colors") + paletteName = i18n("Recent Colors"); + if(prepend) + paletteBox->insertItem(paletteName, 0); + else + paletteBox->insertItem(paletteName); + } + connect(paletteBox, SIGNAL( activated(int) ), SLOT( setFileName(int) )); + topLayout->addWidget(paletteBox); + QHBoxLayout* browseLayout = new QHBoxLayout( mainWidget ); + QPushButton* browseButton = new QPushButton(i18n( "Browse..." ), + mainWidget); + connect(browseButton, SIGNAL( clicked() ), SLOT( browseFileNames() )); + browseLayout->addWidget(browseButton); + browseLayout->addStretch(10); + topLayout->addLayout(browseLayout); + topLayout->addStretch(10); + resize(300, 155); +} +LoadPaletteDlg::~LoadPaletteDlg() { +} + +void LoadPaletteDlg::setFileName(QString* fileName) { + this->fileName = *fileName; +} + +void LoadPaletteDlg::setFileName(int index) { + setFileName(&palettesFileNames[index]); +} + +void LoadPaletteDlg::browseFileNames() { + QString fileToOpen = KFileDialog::getOpenFileName(lastOpenPaletteFileDir, + i18n("*|All Files"), this, i18n("Open File")); + if(!fileToOpen.isEmpty()) { + fileName = fileToOpen; + if(browseFileNameInserted) { + paletteBox->removeItem(0); + palettesFileNames.remove(palettesFileNames.begin()); + } + paletteBox->insertItem(fileName, 0); + paletteBox->setCurrentItem(0); + palettesFileNames.prepend(fileName); + browseFileNameInserted = true; + lastOpenPaletteFileDir = fileName; + } +} + +QString LoadPaletteDlg::getFileName() { + return fileName; +} +#include "loadpalettedlg.moc" diff --git a/kcoloredit/loadpalettedlg.h b/kcoloredit/loadpalettedlg.h new file mode 100644 index 00000000..3168ed68 --- /dev/null +++ b/kcoloredit/loadpalettedlg.h @@ -0,0 +1,67 @@ +/*************************************************************************** + loadpalettedlg.h - description + ------------------- + begin : Sat Jul 8 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef LOADPALETTEDLG_H +#define LOADPALETTEDLG_H + +#include +#include + +/**A dialog showing a list of installed palettes, with a possibility + *of choosing a custom file + *@author Artur Rataj + */ +class LoadPaletteDlg : public KDialogBase { + Q_OBJECT + +public: + /** constructs the dialog + */ + LoadPaletteDlg(QWidget *parent = 0, const char *name = 0); + ~LoadPaletteDlg(); + /** @return the fetched file name + */ + QString getFileName(); + +protected slots: + /** sets fileName + */ + void setFileName(QString* fileName); + /** sets fileName to that at position index in palettesFileNames + */ + void setFileName(int index); + /** browses file names and if a file name fetched sets fileName + */ + void browseFileNames(); + +private: + /** A widget holding palettes names + */ + QComboBox* paletteBox; + /** A list of KDE palettes file names + */ + QStringList palettesFileNames; + /** A fetched palette file name + */ + QString fileName; + /** whether a browse file name hab already been inserted into + * palettesFilenames + */ + bool browseFileNameInserted; +}; + +#endif diff --git a/kcoloredit/main.cpp b/kcoloredit/main.cpp new file mode 100644 index 00000000..fcc2ac66 --- /dev/null +++ b/kcoloredit/main.cpp @@ -0,0 +1,74 @@ +/*************************************************************************** + main.cpp - description + ------------------- + begin : Sat Jul 8 09:57:28 CEST 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include + +#include "kcoloredit.h" + +static const char description[] = + I18N_NOOP("KColorEdit"); +// INSERT A DESCRIPTION FOR YOUR APPLICATION HERE + + +static KCmdLineOptions options[] = +{ + { "+[File]", I18N_NOOP("File to open"), 0 }, + KCmdLineLastOption + // INSERT YOUR COMMANDLINE OPTIONS HERE +}; + +int main(int argc, char *argv[]) +{ + + KAboutData aboutData( "kcoloredit", I18N_NOOP("KColorEdit"), + VERSION, description, KAboutData::License_GPL, + "(c) 2000, Artur Rataj"); + aboutData.addAuthor("Artur Rataj",0, "art@zeus.polsl.gliwice.pl"); + aboutData.addCredit( "Nadeem Hasan", I18N_NOOP( "Rewrote UI code " + "to be KDE standards compliant" ), "nhasan@kde.org" ); + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); // Add our own options. + + KApplication app; + + if (app.isRestored()) + { + RESTORE(KColorEditApp); + } + else + { + KColorEditApp *kcoloredit = new KColorEditApp(); + kcoloredit->show(); + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if (args->count()) + { + kcoloredit->openDocumentFile(args->arg(0)); + } + else + { + kcoloredit->openDocumentFile(); + } + args->clear(); + } + + return app.exec(); +} diff --git a/kcoloredit/main.h b/kcoloredit/main.h new file mode 100644 index 00000000..5e0b086a --- /dev/null +++ b/kcoloredit/main.h @@ -0,0 +1,52 @@ +/*************************************************************************** + main.h - description + ------------------- + begin : Sat Jul 8 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef __MAIN_H__ +#define __MAIN_H__ + +#include +#include + +/** The maximum red, green or blue component value in RGB scheme + */ +const int RGB_MAX_COMPONENT_VALUE = 255; + +/** The maximum hue in HSV scheme + */ +const int HSV_MAX_H_VALUE = 359; + +/** The maximum saturation in HSV scheme + */ +const int HSV_MAX_S_VALUE = 255; + +/** The maximum value in HSV scheme + */ +const int HSV_MAX_V_VALUE = 255; + +/** name of KDE config directories containing palette files + */ +static const QString palettesDir("colors"); + +/** last open file dialog path + */ +static QString lastOpenPaletteFileDir = QDir::homeDirPath(); + +/** last save file as dialog path + */ +static QString lastSavePaletteAsFileDir = QDir::homeDirPath(); + +#endif /* !defined( __MAIN_H__ ) */ diff --git a/kcoloredit/palette.cpp b/kcoloredit/palette.cpp new file mode 100644 index 00000000..1e11aa27 --- /dev/null +++ b/kcoloredit/palette.cpp @@ -0,0 +1,226 @@ +/*************************************************************************** + palette.cpp - description + ------------------- + begin : Sat Jul 8 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "main.h" +#include "color.h" +#include "palette.h" + +Palette::Palette() { + init(); +} +Palette::Palette(const Palette& palette) { + init(); + for(int colorIndex = 0; colorIndex < palette.length(); ++colorIndex) { + Color* color = new Color(*( (Palette&)palette ).color( colorIndex )); + append(color); + } + setName(palette.name()); +} +Palette::~Palette() { +} + +void Palette::init() { + colors.setAutoDelete(true); +} + +QStringList Palette::kdePalettes() { + QStringList paletteList; + KGlobal::dirs()->findAllResources("config", palettesDir + "/*", false, true, paletteList); + return paletteList; +} + +void Palette::setName(const QString& name) { + m_name = name; +} + +const QString& Palette::name() const { + return m_name; +} + +void Palette::insert(const int index, Color* const color) { + colors.insert(index, color); +} + +void Palette::append(Color* const color) { + colors.append(color); +} + +void Palette::remove(const int index) { + colors.remove(index); +} + +int Palette::length() const { + return (int)colors.count(); +} + +Color* Palette::color(const int index) { + return colors.at(index); +} + +Palette Palette::copy(const int index, const int length) { + Palette newPalette; + for(int colorIndex = index; colorIndex < index + length; ++colorIndex) + newPalette.append(new Color( *color(colorIndex) )); + newPalette.setName(name()); + return newPalette; +} + +Palette Palette::cut(const int index, const int length) { + Palette newPalette; + for(int colorNum = 0; colorNum < length; ++colorNum) { + newPalette.append(new Color( *color(index) )); + remove(index); + } + newPalette.setName(name()); + return newPalette; +} + +void Palette::paste(const int index, Palette& palette) { + for(int colorIndex = 0; colorIndex < palette.length(); ++colorIndex) + insert(index + colorIndex, new Color( *palette.color(colorIndex) )); +} + +bool Palette::load(QTextStream& stream, bool loadName /* = true */) { + bool result = true; + setName("KDE palette"); + int lineNum = 0; + while (!stream.atEnd()) { + QString string = stream.readLine().append(' '); + if(string.find( QRegExp("[^\\s]") ) == -1 || + string.stripWhiteSpace().at( 0 ) == '#' || + ( loadName && lineNum == 0 )) { + if(loadName && lineNum == 0) + setName(string.stripWhiteSpace()); + } else { + Color* newColor = new Color(); + int position = string.find(QRegExp( "[^\\s]" )); + for(int componentIndex = 0; componentIndex < Color::COMPONENTS_NUM; + ++componentIndex) { + if(position == -1) { + m_errorString = i18n("Invalid format"); + result = false; + break; + } + int endPosition = string.find(QRegExp( "\\s" ), position); + if(endPosition == -1) { + m_errorString = i18n("Invalid format"); + result = false; + break; + } + QString componentString = string.mid(position, endPosition - position); + int componentValue = componentString.toInt(&result); + if(!result || + componentValue < 0 || + componentValue > RGB_MAX_COMPONENT_VALUE) { + m_errorString = i18n("Invalid format"); + result = false; + break; + } + newColor->setComponent(componentIndex, componentValue); + position = string.find(QRegExp( "[^\\s]" ), endPosition); + } + if(!result) { + delete newColor; + break; + } + if(position != -1) + newColor->setName(string.mid( position ).stripWhiteSpace()); + colors.append(newColor); + } + ++lineNum; + } + if(!result) + deleteContents(); + return result; +} + +bool Palette::load(const QString& fileName) { + bool result = true; + QFile file(fileName); + if(!file.open( IO_ReadOnly )) { + m_errorString = i18n("Could not open file"); + result = false; + } else { + QTextStream stream(&file); + result = load(stream); + file.close(); + } + return result; +} + +bool Palette::save(QTextStream& stream, const QFile* file /* = 0 */, + bool saveName /* = true */) { + bool result = true; + if(saveName) + stream << name() + QString("\n"); + if(file && file->status() != IO_Ok) { + m_errorString = i18n("Write error"); + result = false; + } else + for(int colorIndex = 0; colorIndex < length(); ++colorIndex) { + Color* col = color(colorIndex); + QString redComponentString; + QString greenComponentString; + QString blueComponentString; + redComponentString.setNum(col->component( Color::RED_INDEX )); + greenComponentString.setNum(col->component( Color::GREEN_INDEX )); + blueComponentString.setNum(col->component( Color::BLUE_INDEX )); + QString nameString = col->name(); + if(!nameString.isEmpty()) + nameString.prepend(" "); + stream << redComponentString + QString(" ") + + greenComponentString + QString(" ") + + blueComponentString + + nameString + QString("\n"); + if(file && file->status() != IO_Ok) { + m_errorString = i18n("Write error"); + result = false; + break; + } + } + return result; +} + +bool Palette::save(const QString& fileName) { + bool result = true; + QFile file(fileName); + if(!file.open( IO_WriteOnly|IO_Truncate )) { + m_errorString = i18n("Could not open file for writing"); + result = false; + } else { + QTextStream stream(&file); + result = save(stream); + file.close(); + } + return result; +} + +void Palette::deleteContents() { + colors.clear(); +} + +const QString& Palette::errorString() const { + return m_errorString; +} diff --git a/kcoloredit/palette.h b/kcoloredit/palette.h new file mode 100644 index 00000000..7b763296 --- /dev/null +++ b/kcoloredit/palette.h @@ -0,0 +1,102 @@ +/*************************************************************************** + palette.h - description + ------------------- + begin : Sat Jul 8 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef PALETTE_H +#define PALETTE_H + +#include +#include +#include + +#include "color.h" + +/**This class holds a palette. + *@author Artur Rataj + */ +class Palette { +public: + /** Constructs an empty palette */ + Palette(); + /** The copy constructor */ + Palette(const Palette& palette); + ~Palette(); + /** @return A list of KDE palettes */ + static QStringList kdePalettes(); + /** sets palette name */ + void setName(const QString& name); + /** @return palette name */ + const QString& name() const; + /** inserts a color at a given position */ + void insert(const int index, Color* const color); + /** appends a color */ + void append(Color* const color); + /** removes a color at index */ + void remove(const int index); + /** @return the number of colors */ + int length() const; + /** @return color at index */ + Color* color(const int index); + /** @return a copy of palette at index, of length length */ + Palette copy(const int index, const int length); + /** cuts a palette at index, of length length + * @return a palette that has been cut out + */ + Palette cut(const int index, const int length); + /** pastes a palette at index */ + void paste(const int index, Palette& palette); + /** Loads a palette from a text stream + * @return whether the load was succesfull + */ + bool load(QTextStream& stream, bool loadName = true); + /** Loads a palette from a file. + * If loadName is true, palette name is expected. + * @return whether the load was succesfull + */ + bool load(const QString& fileName); + /** Saves a palette into a text stream. + * If file is given, it is checked for IO errors. + * If saveName is true, palette name is saved. + * @return whether save was succesfull + */ + bool save(QTextStream& stream, const QFile* file = 0, bool saveName = true); + /** Saves a palette to a file + * @return whether save was succesfull + */ + bool save(const QString& fileName); + /** Deletes contents of the palette */ + void deleteContents(); + /** @return A possible error description from the last unsuccessfull + * IO operation + */ + const QString& errorString() const; + +private: + /** The palette name */ + QString m_name; + +private: + /** Initialization method called by constructors */ + void init(); + +protected: + /** A list of palette colors */ + QPtrList colors; + /** An IO error description */ + QString m_errorString; +}; + +#endif diff --git a/kcoloredit/palettehistory.h b/kcoloredit/palettehistory.h new file mode 100644 index 00000000..8bb63643 --- /dev/null +++ b/kcoloredit/palettehistory.h @@ -0,0 +1,26 @@ +/*************************************************************************** + palettehistory.h - description + ------------------- + begin : Sun Jul 9 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef __PALETTE_HISTORY_H__ +#define __PALETTE_HISTORY_H__ + +#include "editablestreamhistory.h" + +/** Definition of PaletteHistory type */ +typedef EditableStreamHistory PaletteHistory; + +#endif /* !defined( __PALETTE_HISTORY_H__ ) */ diff --git a/kcoloredit/paletteview.cpp b/kcoloredit/paletteview.cpp new file mode 100644 index 00000000..8e05a2d7 --- /dev/null +++ b/kcoloredit/paletteview.cpp @@ -0,0 +1,75 @@ +/*************************************************************************** + paletteview.cpp - description + ------------------- + begin : Sun Jul 9 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include + +#include "kcoloreditview.h" +#include "paletteview.h" + +PaletteView::PaletteView(const int defaultCellWidth, const int defaultCellHeight, const int cellSpacing, + KColorEditView* view, QWidget *parent, const char *name) : + QFrame(parent, name, QWidget::WResizeNoErase*0) { + setFrameStyle(StyledPanel|Sunken); + setLineWidth(2); + QGridLayout* topLayout = new QGridLayout(this, 2, 2); + topLayout->setMargin(2); + topLayout->setRowStretch(0, 10); + topLayout->setRowStretch(1, 0); + topLayout->setColStretch(0, 10); + topLayout->setColStretch(1, 0); + scrollBar = new QScrollBar(this); + hScrollBar = new QScrollBar(0, 1, 1, 1, 0, QScrollBar::Horizontal, this); + scrolledArea = new PaletteViewScrolledArea(defaultCellWidth, + defaultCellHeight, cellSpacing, scrollBar, hScrollBar, view, this); + connect(scrollBar, SIGNAL( valueChanged(int) ), + SLOT( slotRepaintScrolledArea() )); + topLayout->addWidget(scrolledArea, 0, 0); + connect(hScrollBar, SIGNAL( valueChanged(int) ), + SLOT( slotRepaintScrolledArea() )); + QHBoxLayout* hScrollBarLayout = new QHBoxLayout(); + hScrollBarLayout->addWidget(hScrollBar, 10); + hScrollBarLayout->addWidget(new QWidget(this), 0); + topLayout->addLayout(hScrollBarLayout, 1, 0); + topLayout->addWidget(scrollBar, 0, 1); +} + +PaletteView::~PaletteView() { +} + +void PaletteView::redraw() { + slotRepaintScrolledArea(); +} + +void PaletteView::setScrollBarValue(const int value) { + scrollBar->setValue(value); + hScrollBar->setValue(0); +} + +void PaletteView::slotViewColorNames(bool viewColorNames) { + scrolledArea->slotViewColorNames(viewColorNames); + setScrollBarValue(0); + scrolledArea->redraw(); +} + +void PaletteView::slotCursorFollowsChosenColor(bool follows) { + scrolledArea->slotCursorFollowsChosenColor(follows); +} + +void PaletteView::slotRepaintScrolledArea() { + scrolledArea->redraw(); +} +#include "paletteview.moc" diff --git a/kcoloredit/paletteview.h b/kcoloredit/paletteview.h new file mode 100644 index 00000000..0032997f --- /dev/null +++ b/kcoloredit/paletteview.h @@ -0,0 +1,64 @@ +/*************************************************************************** + paletteview.h - description + ------------------- + begin : Sun Jul 9 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef PALETTEVIEW_H +#define PALETTEVIEW_H + +#include +#include + +#include "paletteviewscrolledarea.h" + +class KColorEditView; + +/** This is a Palette class view widget. + * Its parent is KColorEditView + * @author Artur Rataj + */ +class PaletteView : public QFrame { + Q_OBJECT + +public: + /** Constructs a palette view widget, with a default cells sizes and spacing. + * The effective cell sizes may be adjusted to fit the widget sizes. + */ + PaletteView(const int defaultCellWidth, const int defaultCellHeight, const int cellSpacing, + KColorEditView* view, QWidget *parent = 0, const char *name=0); + ~PaletteView(); + /** Calls redraw() in scrolledArea */ + void redraw(); + /** Sets a scroll bar value */ + void setScrollBarValue(const int value); + /** Sets whether to view color names */ + void slotViewColorNames(bool viewColorNames); + +public slots: + /** Sets if the cursor follows a chosen color */ + void slotCursorFollowsChosenColor(bool follows); + /** Repaints the scrolled area */ + void slotRepaintScrolledArea(); + +protected: + /** The scrolled area */ + PaletteViewScrolledArea* scrolledArea; + /** The scroll bar widget */ + QScrollBar* scrollBar; + /** The horizontal scroll bar widget */ + QScrollBar* hScrollBar; +}; + +#endif diff --git a/kcoloredit/paletteviewscrolledarea.cpp b/kcoloredit/paletteviewscrolledarea.cpp new file mode 100644 index 00000000..dafb4d10 --- /dev/null +++ b/kcoloredit/paletteviewscrolledarea.cpp @@ -0,0 +1,409 @@ +/*************************************************************************** + paletteviewscrolledarea.cpp + ------------------- + begin : Sun Jul 17 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "palette.h" +#include "palettehistory.h" +#include "kcoloreditdoc.h" +#include "kcoloreditview.h" +#include "paletteviewscrolledarea.h" +#include "paletteviewscrolledarea.moc" + +PaletteViewScrolledArea::PaletteViewScrolledArea(const int defaultCellWidth, + const int defaultCellHeight, const int cellSpacing, QScrollBar* scrollBar, + QScrollBar* hScrollBar, KColorEditView* view, QWidget* parent, const char* name) + : QFrame(parent, name) { + this->defaultCellWidth = defaultCellWidth; + this->defaultCellHeight = defaultCellHeight; + this->cellSpacing = cellSpacing; + this->scrollBar = scrollBar; + this->hScrollBar = hScrollBar; + this->view = view; + setBackgroundMode(NoBackground); + scrollTimeoutTimer = new QTimer(this); + connect(scrollTimeoutTimer, SIGNAL( timeout() ), SLOT( slotScrollTimeout() )); + scrollTimeout = true; + mousePressed = false; + cursorPositioning = false; + colorChosen = false; + setCellsSizes(); + slotCursorFollowsChosenColor(false); + this->scrollBar->setValue(0); + slotViewColorNames(false); + setMinimumSize(1, 1); +} + +PaletteViewScrolledArea::~PaletteViewScrolledArea() { +} + +void PaletteViewScrolledArea::slotCursorFollowsChosenColor(bool follows) { + cursorFollowsChosenColor = follows; +} + +void PaletteViewScrolledArea::slotViewColorNames(bool viewColorNames) { + this->viewColorNames = viewColorNames; +} + +void PaletteViewScrolledArea::redraw() { + //setCellsSizes(); + repaintPalette(); +} + +void PaletteViewScrolledArea::repaintPalette() { + repaint(false); +} + +void PaletteViewScrolledArea::checkSelectionAutoScroll(const int mousePosY) { + if(mousePosY < 0) + scrollPalette(-8, 50); + else if(mousePosY > height() - 1) + scrollPalette(8, 50); +} + +void PaletteViewScrolledArea::scrollPalette(const int amount, const int timeout) { + if(scrollTimeout) { + scrollBy(amount); + scrollTimeout = false; + scrollTimeoutTimer->start(timeout, true); + } +} + +void PaletteViewScrolledArea::slotScrollTimeout() { + scrollTimeout = true; + if(mousePressed) { + QPoint cursorPoint = mapFromGlobal(QCursor::pos()); + setCursorPos(cursorPoint.x(), cursorPoint.y()); + selectionEnd = cursorPos(); + if(selectionEnd >= selectionBegin) + setSelection(selectionBegin, selectionEnd); + else + setSelection(selectionEnd, selectionBegin); + checkSelectionAutoScroll(cursorPoint.y()); + repaintPalette(); + } +} + +void PaletteViewScrolledArea::setCursorPos(const int pos) { + int oldCursorPos = document()->paletteCursorPos(); + document()->setPaletteCursorPos(pos); + if(pos != oldCursorPos) + view->slotCursorPosChanged(pos); +} + +bool PaletteViewScrolledArea::setCursorPos(const int x, const int y) { + int shiftedY = y + scrollBar->value(); + int shiftedX = x + hScrollBar->value(); + int cursorColumn = (shiftedX + rowWidth/cellsInRow/2)*cellsInRow/rowWidth; + int cursorRow; + if(shiftedY >= 0) + cursorRow = (shiftedY + cellSpacing)/rowHeight; + else + cursorRow = -1; + bool atCursorLocation = abs(cursorColumn*rowWidth/cellsInRow - shiftedX) < cellSpacing + 1; + if(!atCursorLocation) { + atCursorLocation = abs(cursorRow*rowHeight - shiftedY) < cellSpacing + 1; + if(atCursorLocation) + cursorColumn = 0; + } + if(atCursorLocation || cursorPositioning) { + if(cursorColumn > cellsInRow - 1) { + cursorColumn = 0; + ++cursorRow; + } + int tmpCursorPos = cursorRow*cellsInRow + cursorColumn; + if(tmpCursorPos < 0) + tmpCursorPos = 0; + else if(tmpCursorPos >= palette()->length()) { + if(tmpCursorPos == palette()->length() && + cursorColumn == 0 && + selectionMin() == selectionMax()) + /* if cursor has been set after the last color and the color is + * also the last in a row, and there is no selection, scroll the + * palette to ensure the cursor is visible + */ + scrollBy(rowHeight*2); + if(tmpCursorPos > palette()->length()) + tmpCursorPos = palette()->length(); + } + setCursorPos(tmpCursorPos); + } + return atCursorLocation; +} + +void PaletteViewScrolledArea::setSelection(const int min, const int max) { + document()->setPaletteSelection(min, max); +} + +void PaletteViewScrolledArea::setCellsSizes() { + rowWidth = width(); + cellWidth = defaultCellWidth; + cellHeight = defaultCellHeight; + if(viewColorNames) { + QPainter painter; + painter.begin(this); + if(cellHeight < painter.fontMetrics().height()) { + int prevCellHeight = cellHeight; + cellHeight = painter.fontMetrics().height(); + cellWidth = cellHeight*cellWidth/prevCellHeight; + } + painter.end(); + } + if(viewColorNames) + cellsInRow = 1; + else + cellsInRow = rowWidth/(cellWidth + cellSpacing*2); + if(viewColorNames) + rowHeight = cellHeight + cellSpacing*2; + else + rowHeight = (int)(rowWidth*1.0/cellsInRow/ + ( cellWidth + cellSpacing*2 )*( cellHeight + cellSpacing*2 ) + 0.5); + cellHeight = rowHeight - cellSpacing*2; + rowsNum = (palette()->length() + cellsInRow - 1)/cellsInRow; + cellTableHeight = rowsNum*rowHeight; + int contentsHeight; + if(palette()->length() != 0 && + ( palette()->length()%cellsInRow ) == 0) + contentsHeight = cellTableHeight + rowHeight; + else + contentsHeight = cellTableHeight; + int scrollBarRange = contentsHeight - 1 - height(); + if(scrollBarRange < 0) + scrollBarRange = 0; + scrollBar->setRange(0, scrollBarRange); + scrollBar->setSteps(rowHeight, height()); +} + +Palette* PaletteViewScrolledArea::palette() const { + return document()->paletteHistory()->editableStream(); +} + +int PaletteViewScrolledArea::cursorPos() const { + return document()->paletteCursorPos(); +} + +int PaletteViewScrolledArea::selectionMin() const{ + return document()->paletteSelectionBegin(); +} + +int PaletteViewScrolledArea::selectionMax() const { + return document()->paletteSelectionEnd(); +} + +void PaletteViewScrolledArea::paintEvent(QPaintEvent* /*event*/) { + setCellsSizes(); + QPixmap pixmap(size()); + QPainter painter; + painter.begin(&pixmap, this); + QFontMetrics fontMetrics = painter.fontMetrics(); + int maxLineWidth; + if(viewColorNames) { + int maxTextLength = 0; + for(int index = 0; index < palette()->length(); ++index) { + int currTextLength = fontMetrics.width( + palette()->color(index)->name()); + if(currTextLength > maxTextLength) + maxTextLength = currTextLength; + } + maxLineWidth = cellWidth + cellSpacing*2 + + cellSpacing*3 + maxTextLength + 1; + } else + maxLineWidth = rowWidth; + int width = rowWidth; + if(maxLineWidth > width) { + hScrollBar->setRange(0, maxLineWidth - width); + hScrollBar->setSteps(8, width); + hScrollBar->show(); + } else { + hScrollBar->setValue(0); + hScrollBar->hide(); + } + int posY = scrollBar->value(); + int firstRow = posY/rowHeight; + int lastRow = (posY + height() - 1 + rowHeight - 1)/rowHeight; + if(viewColorNames) + painter.fillRect(0, 0, rowWidth, height(), + QBrush( QFrame::palette().active().base() )); + QBrush normalBackgroundBrush(QFrame::palette().active().background()); + QBrush selectedBackgroundBrush(QFrame::palette().active().highlight()); + QBrush foregroundBrush; + QBrush cursorBrush(QFrame::palette().active().foreground()); + QPen backgroundPen(QFrame::palette().active().foreground()); + int min = selectionMin(); + int max = selectionMax(); + int fontAscent = fontMetrics.ascent(); + int xBegin = -hScrollBar->value(); + for(int x = 0; x < cellsInRow; ++x) { + int xEnd = -hScrollBar->value(); + if(viewColorNames) + xEnd += cellWidth + cellSpacing*2; + else + xEnd += (x + 1)*(width - 1)/cellsInRow; + int cellWithSpacingWidth = xEnd - xBegin + 1; + int cellWidth = cellWithSpacingWidth - 2*cellSpacing; + for(int y = firstRow; y <= lastRow; ++y) { + int yBegin = y*rowHeight - posY; + int currCellNum = y*cellsInRow + x; + QBrush* backgroundBrush; + if(currCellNum >= min && currCellNum < max) + backgroundBrush = &selectedBackgroundBrush; + else + backgroundBrush = &normalBackgroundBrush; + if(currCellNum < palette()->length()) { + Color* color = palette()->color(currCellNum); + QBrush foregroundBrush(QColor( + color->component(Color::RED_INDEX), + color->component(Color::GREEN_INDEX), + color->component(Color::BLUE_INDEX) )); + painter.fillRect(xBegin, yBegin, cellWithSpacingWidth, cellSpacing, + *backgroundBrush); + painter.fillRect(xBegin, yBegin + rowHeight - cellSpacing, cellWithSpacingWidth, cellSpacing, + *backgroundBrush); + QBrush* backgroundOrCursorBrush; + if(cursorPos() == currCellNum) + backgroundOrCursorBrush = &cursorBrush; + else + backgroundOrCursorBrush = backgroundBrush; + painter.fillRect(xBegin, yBegin + cellSpacing, cellSpacing, cellHeight, + *backgroundOrCursorBrush); + painter.fillRect(xBegin + cellWithSpacingWidth - cellSpacing, yBegin + cellSpacing, + cellSpacing, cellHeight, + *backgroundBrush); + painter.fillRect(xBegin + cellSpacing, yBegin + cellSpacing, cellWidth, cellHeight, + foregroundBrush); + if(viewColorNames) { + painter.setPen(backgroundPen); + painter.drawText(xBegin + cellWithSpacingWidth + cellSpacing*3, + yBegin + rowHeight/2 + fontAscent/2, color->name()); + } + } else { + if(cursorPos() == currCellNum) { + painter.fillRect(xBegin, yBegin + cellSpacing, cellSpacing, cellHeight, + cursorBrush); + painter.fillRect(xBegin, yBegin, cellSpacing, cellSpacing, + *backgroundBrush); + painter.fillRect(xBegin, yBegin + rowHeight - cellSpacing, cellSpacing, cellSpacing, + *backgroundBrush); + painter.fillRect(xBegin + cellSpacing, yBegin, cellWithSpacingWidth - cellSpacing, rowHeight, + *backgroundBrush); + } else + painter.fillRect(xBegin, yBegin, cellWithSpacingWidth, rowHeight, + *backgroundBrush); + } + } + xBegin = xEnd + 1; + } + painter.end(); + painter.begin(this); + painter.drawPixmap(0, 0, pixmap); + painter.end(); +} + +int PaletteViewScrolledArea::colorIndex(const QPoint& point) const { + int colorColumn = point.x()*cellsInRow/rowWidth; + int colorRow = (point.y() + scrollBar->value())/rowHeight; + int colorIndex = colorRow*cellsInRow + colorColumn; + if(colorIndex > palette()->length() - 1 || + colorIndex < 0) + colorIndex = -1; + return colorIndex; +} + +QColor PaletteViewScrolledArea::color(const QPoint& point) const { + Color* color = palette()->color(colorIndex( point )); + return QColor(color->component( Color::RED_INDEX ), + color->component( Color::GREEN_INDEX ), + color->component( Color::BLUE_INDEX )); +} + +void PaletteViewScrolledArea::mousePressEvent(QMouseEvent* event) { + cursorPositioning = false; + if(( cursorPositioning = setCursorPos(event->x(), event->y()) )) { + selectionBegin = cursorPos(); + setSelection(selectionBegin, selectionBegin); + redraw(); + colorChosen = false; + } else { + colorDragPoint = event->pos(); + colorChosen = true; + } + mousePressed = true; +} + +void PaletteViewScrolledArea::mouseMoveEvent(QMouseEvent* event) { + if(cursorPositioning) { + setCursorPos(event->x(), event->y()); + selectionEnd = cursorPos(); + if(selectionEnd >= selectionBegin) + setSelection(selectionBegin, selectionEnd); + else + setSelection(selectionEnd, selectionBegin); + checkSelectionAutoScroll(event->y()); + redraw(); + } else { + /* check if it is a color drag */ + if(colorIndex( colorDragPoint ) != -1) { + if(abs( event->x() - colorDragPoint.x() ) > 2 || + abs( event->y() - colorDragPoint.y() ) > 2) { + QColor draggedColor = color(colorDragPoint); + KColorDrag* colorDrag = KColorDrag::makeDrag(draggedColor, this); + colorDrag->dragCopy(); + } else + colorChosen = true; + } + } +} + +void PaletteViewScrolledArea::mouseReleaseEvent(QMouseEvent* /*event*/) { + if(colorChosen) { + if(colorIndex( colorDragPoint ) != -1) { + int index = colorIndex(colorDragPoint); + chooseColor(palette()->color( index )); + if(cursorFollowsChosenColor) { + setCursorPos(index); + setSelection(cursorPos(), cursorPos()); + redraw(); + } + } + colorChosen = false; + } + mousePressed = false; +} + +void PaletteViewScrolledArea::chooseColor(Color* const color) { + view->chooseColor(color); +} + +KColorEditDoc* PaletteViewScrolledArea::document() const { + return view->document(); +} + +void PaletteViewScrolledArea::scrollBy(const int y) { + scrollBar->setValue(scrollBar->value() + y); +} diff --git a/kcoloredit/paletteviewscrolledarea.h b/kcoloredit/paletteviewscrolledarea.h new file mode 100644 index 00000000..18bbae2b --- /dev/null +++ b/kcoloredit/paletteviewscrolledarea.h @@ -0,0 +1,162 @@ +/*************************************************************************** + paletteviewscrolledarea.h + ------------------- + begin : Sun Jul 17 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef PALETTEVIEWSCROLLEDAREA_H +#define PALETTEVIEWSCROLLEDAREA_H + +#include +#include + +#include "palette.h" + +class KColorEditDoc; +class KColorEditView; +class QScrollBar; + +/** This widget draws the palette view scrolled area. + * It has paste and cut features. + * @author Artur Rataj + */ +class PaletteViewScrolledArea : public QFrame { + Q_OBJECT + +public: + /** Constructs the widget */ + PaletteViewScrolledArea(const int defaultCellWidth, const int defaultCellHeight, + const int cellSpacing, QScrollBar* scrollBar, + QScrollBar* hScrollBar, KColorEditView* view, + QWidget* parent = 0, const char* name = 0); + ~PaletteViewScrolledArea(); + /** Sets cells sizes and then calls repaintPalette() */ + void redraw(); + +public slots: + /** Sets if the cursor follows a chosen color */ + void slotCursorFollowsChosenColor(bool follows); + /** Sets whether to view color names */ + void slotViewColorNames(bool viewColorNames); + +protected: + /** The scrollbar widget */ + QScrollBar* scrollBar; + /** The horizontal scrollbar widget */ + QScrollBar* hScrollBar; + /** Pointer to the document view */ + KColorEditView* view; + /** Default cell width */ + int defaultCellWidth; + /** Default cell height */ + int defaultCellHeight; + /** Cell spacing */ + int cellSpacing; + /** Cell width */ + int cellWidth; + /** Cell height */ + int cellHeight; + /** The number of cells in a row */ + int cellsInRow; + /** The number of rows */ + int rowsNum; + /** A row width */ + int rowWidth; + /** A row height */ + int rowHeight; + /** Total height of cells table */ + int cellTableHeight; + /** A position at which selection started */ + int selectionBegin; + /** A position at which selection ended */ + int selectionEnd; + /** Auto scroll timeout timer */ + QTimer* scrollTimeoutTimer; + /** Whether there is auto scroll timeout */ + bool scrollTimeout; + /** Whether a mouse has been pressed over the palette and not yet released */ + bool mousePressed; + /** Whether the cursor is being positioned */ + bool cursorPositioning; + /** A color drag point */ + QPoint colorDragPoint; + /** Whether a color has been chosen and it is not dragged */ + bool colorChosen; + /** Whether the cursor follows a chosen color */ + bool cursorFollowsChosenColor; + /** Whether to view color names */ + bool viewColorNames; + + /** @return The viewed palette */ + Palette* palette() const; + /** Computes the size of cell, number of cells in a row and + * height of cells table, depending on colors number and + * visible area width + */ + void setCellsSizes(); + /** repaints the palette */ + void repaintPalette(); + /** @return A color index at a given position, -1 if none */ + int colorIndex(const QPoint& point) const; + /** @return A color at a given position */ + QColor color(const QPoint& point) const; + /** sets a palette cursor position */ + void setCursorPos(const int pos); + /** Sets a cursor position due to a mouse position. + * If not in cursor positioning, the cursor is set + * only if mouse points to a possible cursor location + * @return If the mouse points to a cursor location + */ + bool setCursorPos(const int x, const int y); + /** @return a palette cursor position */ + int cursorPos() const; + /** sets a palette selection */ + void setSelection(const int min, const int max); + /** @return a palette selection lesser position, or equal position + * if no colors are selected + */ + int selectionMin() const; + /** @return a palette selection greater position, or equal position + * if no colors are selected + */ + int selectionMax() const; + /** checks whether to scrolls the palette if a mouse position + * is outside it + */ + void checkSelectionAutoScroll(const int mousePosY); + /** The widget painting */ + void paintEvent(QPaintEvent* event); + /** Used to get mouse press events coordinates */ + void mousePressEvent(QMouseEvent* event); + /** Used to get mouse move events coordinates */ + void mouseMoveEvent(QMouseEvent* event); + /** Used to get mouse release events coordinates */ + void mouseReleaseEvent(QMouseEvent* event); + /** If there is a scroll timeout, scrolls palette, + * sets scrollTimeout to false and resets scroll timeout timer + */ + void scrollPalette(const int amount, const int timeout); + /** @return The viewed document */ + KColorEditDoc* document() const; + /** Chooses a color to the color selector */ + void chooseColor(Color* const color); + /** scrolls the scrolled area */ + void scrollBy(const int y); + +protected slots: + /** called if there is a scroll timeout, sets scrollTimeout to true */ + void slotScrollTimeout(); +}; + +#endif /* !defined( PALETTEVIEWSCROLLEDAREA_H ) */ diff --git a/kcoloredit/resource.h b/kcoloredit/resource.h new file mode 100644 index 00000000..c96576cc --- /dev/null +++ b/kcoloredit/resource.h @@ -0,0 +1,35 @@ +/*************************************************************************** + resource.h - description + ------------------- + begin : Sat Jul 8 09:57:28 CEST 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef RESOURCE_H +#define RESOURCE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +/////////////////////////////////////////////////////////////////// +// resource.h -- contains macros used for commands + + +/////////////////////////////////////////////////////////////////// +// General application values +#define ID_STATUS_MSG 1001 + +#define IDS_STATUS_DEFAULT I18N_NOOP("Ready.") + +#endif // RESOURCE_H diff --git a/kcoloredit/texteditselection.cpp b/kcoloredit/texteditselection.cpp new file mode 100644 index 00000000..65d4ecad --- /dev/null +++ b/kcoloredit/texteditselection.cpp @@ -0,0 +1,187 @@ +/*************************************************************************** + texteditselection.cpp - description + ------------------- + begin : Wed Jul 12 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include + +#include + +#include "main.h" +#include "texteditselection.h" + +TextEditSelection::TextEditSelection(QWidget *parent, const char *name ) : QWidget(parent,name) { + inChangingComponents = false; + QVBoxLayout* topLayout = new QVBoxLayout(this, 4); + QGridLayout* componentsLayout = new QGridLayout(3, 5, 2); + topLayout->addLayout(componentsLayout); + componentsLayout->setColStretch(1, 10); + componentsLayout->addColSpacing(2, 8); + componentsLayout->setColStretch(4, 10); + QLineEdit* lineEdit; + addComponent(H_INDEX, ( lineEdit = new QLineEdit(this) ), HSV_MAX_H_VALUE, "H:", 0, 0, componentsLayout); + connect(lineEdit, SIGNAL( textChanged(const QString&) ), SLOT( slotHsvComponentChanged() )); + addComponent(S_INDEX, ( lineEdit = new QLineEdit(this) ), HSV_MAX_S_VALUE, "S:", 1, 0, componentsLayout); + connect(lineEdit, SIGNAL( textChanged(const QString&) ), SLOT( slotHsvComponentChanged() )); + addComponent(V_INDEX, ( lineEdit = new QLineEdit(this) ), HSV_MAX_V_VALUE, "V:", 2, 0, componentsLayout); + connect(lineEdit, SIGNAL( textChanged(const QString&) ), SLOT( slotHsvComponentChanged() )); + addComponent(R_INDEX, ( lineEdit = new QLineEdit(this) ), RGB_MAX_COMPONENT_VALUE, "R:", 0, 1, componentsLayout); + connect(lineEdit, SIGNAL( textChanged(const QString&) ), SLOT( slotRgbComponentChanged() )); + addComponent(G_INDEX, ( lineEdit = new QLineEdit(this) ), RGB_MAX_COMPONENT_VALUE, "G:", 1, 1, componentsLayout); + connect(lineEdit, SIGNAL( textChanged(const QString&) ), SLOT( slotRgbComponentChanged() )); + addComponent(B_INDEX, ( lineEdit = new QLineEdit(this) ), RGB_MAX_COMPONENT_VALUE, "B:", 2, 1, componentsLayout); + connect(lineEdit, SIGNAL( textChanged(const QString&) ), SLOT( slotRgbComponentChanged() )); + QHBoxLayout* rgbStringLayout = new QHBoxLayout(2); + QLabel* rgbStringLabel = new QLabel("RGB " + i18n( "hex." ) + ": ", this); + rgbStringLayout->addWidget(rgbStringLabel); + rgbStringLineEdit = new QLineEdit(this); + rgbStringLineEdit->setMinimumWidth(lineEdit->fontMetrics().width( QString("8888888") )); + rgbStringLineEdit->setMaximumWidth(lineEdit->fontMetrics().width( QString("888888888") )); + connect(rgbStringLineEdit, SIGNAL( textChanged(const QString&) ), SLOT( slotRgbStringChanged() )); + rgbStringLayout->addWidget(rgbStringLineEdit); + topLayout->addLayout(rgbStringLayout); +} +TextEditSelection::~TextEditSelection(){ +} + +void TextEditSelection::addComponent(const int index, QLineEdit* lineEdit, const int maxValue, + const QString& labelString, const int row, const int column, QGridLayout* layout) { + QLabel* label = new QLabel(labelString, this); + lineEdit->setValidator(new QIntValidator( 0, maxValue, lineEdit )); + lineEditTable[index] = lineEdit; + lineEdit->setMinimumWidth(lineEdit->fontMetrics().width( QString("8888") )); + lineEdit->setMaximumWidth(lineEdit->fontMetrics().width( QString("8888888") )); + layout->addWidget(label, row, column*3); + layout->addWidget(lineEdit, row, column*3 + 1); +} + +void TextEditSelection::setRgbString(const int red, const int green, const int blue) { + QString string; + string.sprintf("%02x%02x%02x", red, green, blue); + rgbStringLineEdit->setText(string); +} + +void TextEditSelection::slotHsvComponentChanged() { + if(!inChangingComponents) { + inChangingComponents = true; + int hComponent = lineEditTable[H_INDEX]->text().toInt(); + int sComponent = lineEditTable[S_INDEX]->text().toInt(); + int vComponent = lineEditTable[V_INDEX]->text().toInt(); + QColor color; + color.setHsv(hComponent, sComponent, vComponent); + int rComponent = color.red(); + int gComponent = color.green(); + int bComponent = color.blue(); + QString string; + lineEditTable[R_INDEX]->setText(string.setNum( rComponent )); + lineEditTable[G_INDEX]->setText(string.setNum( gComponent )); + lineEditTable[B_INDEX]->setText(string.setNum( bComponent )); + Color oldColor = this->color; + this->color.setComponent(Color::RED_INDEX, rComponent); + this->color.setComponent(Color::GREEN_INDEX, gComponent); + this->color.setComponent(Color::BLUE_INDEX, bComponent); + if(!this->color.equals( oldColor )) + emit valueChanged(&this->color); + setRgbString(rComponent, gComponent, bComponent); + inChangingComponents = false; + } +} + +void TextEditSelection::slotRgbComponentChanged() { + if(!inChangingComponents) { + inChangingComponents = true; + int rComponent = lineEditTable[R_INDEX]->text().toInt(); + int gComponent = lineEditTable[G_INDEX]->text().toInt(); + int bComponent = lineEditTable[B_INDEX]->text().toInt(); + QColor color; + color.setRgb(rComponent, gComponent, bComponent); + int hComponent; + int sComponent; + int vComponent; + color.hsv(&hComponent, &sComponent, &vComponent); + QString string; + lineEditTable[H_INDEX]->setText(string.setNum( hComponent )); + lineEditTable[S_INDEX]->setText(string.setNum( sComponent )); + lineEditTable[V_INDEX]->setText(string.setNum( vComponent )); + Color oldColor = this->color; + this->color.setComponent(Color::RED_INDEX, rComponent); + this->color.setComponent(Color::GREEN_INDEX, gComponent); + this->color.setComponent(Color::BLUE_INDEX, bComponent); + if(!this->color.equals( oldColor )) + emit valueChanged(&this->color); + setRgbString(rComponent, gComponent, bComponent); + inChangingComponents = false; + } +} + +void TextEditSelection::slotRgbStringChanged() { + if(!inChangingComponents) { + inChangingComponents = true; + QString string = rgbStringLineEdit->text().stripWhiteSpace(); + bool result; + int value = string.toInt(&result, 16); + if(result) { + int rComponent = (value >> 16)&0xff; + int gComponent = (value >> 8)&0xff; + int bComponent = (value >> 0)&0xff; + lineEditTable[R_INDEX]->setText(string.setNum( rComponent )); + lineEditTable[G_INDEX]->setText(string.setNum( gComponent )); + lineEditTable[B_INDEX]->setText(string.setNum( bComponent )); + int hComponent; + int sComponent; + int vComponent; + QColor hsvColor; + hsvColor.hsv(&hComponent, &sComponent, &vComponent); + lineEditTable[H_INDEX]->setText(string.setNum( hComponent )); + lineEditTable[S_INDEX]->setText(string.setNum( sComponent )); + lineEditTable[V_INDEX]->setText(string.setNum( vComponent )); + Color oldColor = this->color; + this->color.setComponent(Color::RED_INDEX, rComponent); + this->color.setComponent(Color::GREEN_INDEX, gComponent); + this->color.setComponent(Color::BLUE_INDEX, bComponent); + if(!this->color.equals( oldColor )) + emit valueChanged(&this->color); + } + inChangingComponents = false; + } +} + +void TextEditSelection::slotSetValue(Color* color) { + if(!color->equals( this->color )) { + inChangingComponents = true; + this->color = *color; + QString string; + int rComponent = this->color.component(Color::RED_INDEX); + int gComponent = this->color.component(Color::GREEN_INDEX); + int bComponent = this->color.component(Color::BLUE_INDEX); + lineEditTable[R_INDEX]->setText(string.setNum( rComponent )); + lineEditTable[G_INDEX]->setText(string.setNum( gComponent )); + lineEditTable[B_INDEX]->setText(string.setNum( bComponent )); + QColor hsvColor(rComponent, gComponent, bComponent); + int hComponent; + int sComponent; + int vComponent; + hsvColor.hsv(&hComponent, &sComponent, &vComponent); + lineEditTable[H_INDEX]->setText(string.setNum( hComponent )); + lineEditTable[S_INDEX]->setText(string.setNum( sComponent )); + lineEditTable[V_INDEX]->setText(string.setNum( vComponent )); + setRgbString(rComponent, gComponent, bComponent); + inChangingComponents = false; + } +} + +#include "texteditselection.moc" diff --git a/kcoloredit/texteditselection.h b/kcoloredit/texteditselection.h new file mode 100644 index 00000000..c2166098 --- /dev/null +++ b/kcoloredit/texteditselection.h @@ -0,0 +1,89 @@ +/*************************************************************************** + texteditselection.h - description + ------------------- + begin : Wed Jul 12 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef TEXTEDITSELECTION_H +#define TEXTEDITSELECTION_H + +#include +#include +#include + +#include "color.h" + +/** Color selection widget using line edit. Either HSV or RGB components + * can be set. + * @author Artur Rataj + */ +class TextEditSelection : public QWidget { + Q_OBJECT + +public: + /** Constructs the widget */ + TextEditSelection(QWidget *parent=0, const char *name=0); + ~TextEditSelection(); + +signals: + /** A signal that a color value has changed by edition */ + void valueChanged(Color*); + +public slots: + /** sets a color */ + void slotSetValue(Color* color); + +protected: + /** Adds a component line edit */ + void addComponent(const int index, QLineEdit* lineEdit, const int maxValue, const QString& labelString, + const int row, const int column, QGridLayout* layout); + /** sets RGB string in rgbStringLineEdit */ + void setRgbString(const int red, const int green, const int blue); + +protected slots: + /** Called if one of HSV components has changed. In that case, RGB components are + * also changed to match the HSV ones + */ + void slotHsvComponentChanged(); + /** Called if one of RGB components has changed. In that case, HSV components are + * also changed to match the RGB ones + */ + void slotRgbComponentChanged(); + /** Called if the RGB string has changed. In that case, RGB and HSV components are + * also changed to match the RGB string + */ + void slotRgbStringChanged(); + +protected: + /** Indexes of components */ + enum { H_INDEX = 0, + S_INDEX = 1, + V_INDEX = 2, + R_INDEX = 3, + G_INDEX = 4, + B_INDEX = 5, + /** A total number of components */ + COMPONENTS_NUM = 6 }; + + /** Line edit widgets table */ + QLineEdit* lineEditTable[COMPONENTS_NUM]; + /** RGB hex string line edit widgets table */ + QLineEdit* rgbStringLineEdit; + /** The selected color */ + Color color; + /** A flag that components are matched */ + bool inChangingComponents; +}; + +#endif diff --git a/kcoloredit/textselection.cpp b/kcoloredit/textselection.cpp new file mode 100644 index 00000000..8a4225bc --- /dev/null +++ b/kcoloredit/textselection.cpp @@ -0,0 +1,24 @@ +/*************************************************************************** + textselection.cpp - description + ------------------- + begin : Wed Jul 12 2000 + copyright : (C) 2000 by Artur Rataj + email : art@zeus.polsl.gliwice.pl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "textselection.h" + +TextSelection::TextSelection(QWidget *parent, const char *name ) : QWidget(parent,name) { + +} +TextSelection::~TextSelection(){ +} diff --git a/kcoloredit/uninstall.desktop b/kcoloredit/uninstall.desktop new file mode 100644 index 00000000..e1e3e173 --- /dev/null +++ b/kcoloredit/uninstall.desktop @@ -0,0 +1,2 @@ +[Desktop Entry] +Hidden=true diff --git a/kdegraphics.lsm b/kdegraphics.lsm new file mode 100644 index 00000000..a3933ce8 --- /dev/null +++ b/kdegraphics.lsm @@ -0,0 +1,11 @@ +Begin4 +Title: kdegraphics +Version: 3.5.10 +Entered-date: 2008-08-26 +Description: Graphical Applications written for the K Desktop Environment (KDE) +Keywords: KDE X11 desktop Qt +Author: http://bugs.kde.org/ (KDE Bugtracking System) +Primary-site: http://www.kde.org/download/ +Platforms: Unix, Qt +Copying-policy: GPL, Artistic +End diff --git a/kdvi/AUTHORS b/kdvi/AUTHORS new file mode 100644 index 00000000..0d869c99 --- /dev/null +++ b/kdvi/AUTHORS @@ -0,0 +1,39 @@ +The programm KDVI is based on the dvi-previewer xdvik, See below. KDVI +was written by Markku Hihnala with the help of many +collaborators. Later KDVI became a plug-in to KViewShell and Stefan +Kebekus re-implemented parts of the program. The current version of +KDVI shares a substantial amount of code with xdvi, not not very much +with the first versions of KDVI. + +------------------------------------------------------------------------------ + + +AUTHORS OF xdvik +================ + +This program, xdvik, was modified by kb@cs.umb.edu from Paul Vojta's +xdvi distribution for common path searching, GNU-style configuration, +etc. Send bug reports to tex-k@cs.umb.edu, not to Paul. See the +README for more info. + +Here are the credits for the original xdvi program: + +This program is the combined work of many people, including but not restricted to: + Eric Cooper, CMU + Bob Scheifler, MIT LCS + Paal Kvamme, Norwegian Institute of Technology + H\aa vard Eidnes, Norwegian Institute of Technology + Mark Eichin, MIT SIPB + Paul Vojta, UC Berkeley + Jeffrey Lee, U of Toronto + Donald Richardson, Clarkson Univ. + +In addition to the various comp.sources.x archives, current versions +of this program (the original xdvi, not xdvik) can also be obtained +via anonymous ftp from the following location: + + export.lcs.mit.edu [18.30.0.212] file contrib/xdvi.tar.Z +To ease the load on expo, you may also check other X archives, for example: + gatekeeper.dec.com [16.1.0.2] file pub/X11/contrib/xdvi.shar.Z + +Paul Vojta is now the primary maintainer. diff --git a/kdvi/ChangeLog b/kdvi/ChangeLog new file mode 100644 index 00000000..8345a95e --- /dev/null +++ b/kdvi/ChangeLog @@ -0,0 +1,9 @@ +Mon Jun 29 08:43:45 1998 Bernd Johannes Wuebben + + * KDVI uses KFileDialog now. + +Version 0.4.2 + * [Robert Williams] Added version.h and ChangeLog + * [Robert Williams] Renamed Kdvi.kdelnk to kdvi.kdelnk + * [Robert Williams] Added -caption "%c" to kdvi.kdelnk + * [Robert Williams] Added getHelpMenu() diff --git a/kdvi/Makefile.am b/kdvi/Makefile.am new file mode 100644 index 00000000..dce4053a --- /dev/null +++ b/kdvi/Makefile.am @@ -0,0 +1,66 @@ +# set the include path for X, qt and KDE +INCLUDES= -I$(top_srcdir)/kviewshell \ + -I$(top_builddir)/kviewshell \ + $(all_includes) $(LIBFREETYPE_CFLAGS) +# claim, which subdirectories you want to install +SUBDIRS = . pix + +bin_PROGRAMS = kdvi + +# you can add here more. This one gets installed +kde_module_LTLIBRARIES= kdvipart.la +noinst_PROGRAMS = squeeze + +# just to make sure, automake makes them +METASOURCES = AUTO + +kdvipart_la_SOURCES = renderedDviPagePixmap.cpp dviPageCache.cpp \ + kdvi_multipage.cpp kdvi_multipage_texthandling.cpp \ + dviRenderer.cpp bigEndianByteReader.cpp infodialog.cpp \ + psheader.c dviRenderer_draw.cpp dviRenderer_prescan.cpp dviRenderer_export.cpp \ + dviFile.cpp fontpool.cpp fontprogress.cpp psgs.cpp \ + fontMap.cpp fontEncoding.cpp fontEncodingPool.cpp \ + special.cpp util.cpp vf.cpp glyph.cpp \ + optionDialogFontsWidget.cpp optionDialogFontsWidget_base.ui \ + optionDialogSpecialWidget.cpp optionDialogSpecialWidget_base.ui \ + TeXFont.cpp TeXFont_PK.cpp TeXFont_PFB.cpp TeXFont_TFM.cpp \ + TeXFontDefinition.cpp dviWidget.cpp dvisourcesplitter.cpp \ + prefs.kcfgc + +kde_kcfg_DATA = kdvi.kcfg + +kdvipart_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module +kdvipart_la_LIBADD = $(LIBFREETYPE_LIBS) -lkparts \ + $(top_builddir)/kviewshell/libkmultipage.la + +# Which sources should be compiled for squeeze. +squeeze_SOURCES = squeeze.c + +KDE_OPTIONS = nofinal + +kdvi_SOURCES = main.cpp +kdvi_LDFLAGS = $(all_libraries) $(KDE_RPATH) +kdvi_LDADD = ../kviewshell/libifaces.la ../kviewshell/libkviewshell.la -lkparts + +## this option you can leave out. Just, if you use "make dist", you need it +noinst_HEADERS = dvi.h dviRenderer.h xdvi.h + +messages: rc.cpp + $(PREPARETIPS) > tips.cpp + $(XGETTEXT) *.cpp -o $(podir)/kdvi.pot + rm -f tips.cpp + +xdg_apps_DATA = kdvi.desktop + +tip_DATA = tips +tipdir = $(kde_datadir)/kdvi + +partdir = $(kde_datadir)/kdvi +part_DATA = ../kviewshell/kviewshell.rc kdvi_part.rc + +kde_services_DATA = kdvimultipage.desktop + +psheader.c: psheader.txt squeeze + ./squeeze $(srcdir)/psheader.txt $@ + +CLEANFILES = psheader.c diff --git a/kdvi/TODO b/kdvi/TODO new file mode 100644 index 00000000..44a4433c --- /dev/null +++ b/kdvi/TODO @@ -0,0 +1,30 @@ +ToDo-List for kdvi + +URGENT / URGENT BUGFIXING + +o improve performance and perceived performance (see also under 'highly desirable') + +o do not render the same PS code more than once if all pages have the same PS code +o add "papersize" which does not display the margin +o get rid of useless README.kdvi +o Proper handling of the base-url +o add "tt.dvi.gz" to the list of recent files, not "/tmp/kviews....." +o If one presses PgDn for a while, kdvi spends minutes browsing through pages... + +HIGHLY DESIRABLE + +o Speedup, in particular for ghostscript and glyph enlarging. + +o Support papersize information given by the dvi-file on a page-by-page + basis. + +o asynchronous rendering of pages, so that browsing with pg up/down looks faster + + +NOT SO URGENT + +o Internal printing using QPrinter +o Magnifier window +o Two page view +o Support for even more TeX specials +o more robust Error handling with throw/catch; no need to abort just because a PK-file is bad. \ No newline at end of file diff --git a/kdvi/TeXFont.cpp b/kdvi/TeXFont.cpp new file mode 100644 index 00000000..829b00fb --- /dev/null +++ b/kdvi/TeXFont.cpp @@ -0,0 +1,9 @@ +#include + +#include "glyph.h" +#include "TeXFont.h" + +TeXFont::~TeXFont() +{ + ; +} diff --git a/kdvi/TeXFont.h b/kdvi/TeXFont.h new file mode 100644 index 00000000..8ff70499 --- /dev/null +++ b/kdvi/TeXFont.h @@ -0,0 +1,48 @@ +// -*- C++ -*- +// TeXFont.h +// +// Part of KDVI - A DVI previewer for the KDE desktop environemt +// +// (C) 2003 Stefan Kebekus +// Distributed under the GPL + +#ifndef _TEXFONT_H +#define _TEXFONT_H + +#include "TeXFontDefinition.h" +#include "glyph.h" + + +class TeXFont { + public: + TeXFont(TeXFontDefinition *_parent) + { + parent = _parent; + errorMessage = QString::null; + }; + + virtual ~TeXFont(); + + void setDisplayResolution() + { + for(unsigned int i=0; i + +#include +#include +#include + +#include "dviRenderer.h" +#include "fontpool.h" +#include "kdvi.h" +#ifdef HAVE_FREETYPE +#include "TeXFont_PFB.h" +#endif +#include "TeXFont_PK.h" +#include "TeXFont_TFM.h" +#include "TeXFontDefinition.h" +#include "xdvi.h" + +extern const int MFResolutions[]; + +#define PK_PRE 247 +#define PK_ID 89 +#define PK_MAGIC (PK_PRE << 8) + PK_ID +#define GF_PRE 247 +#define GF_ID 131 +#define GF_MAGIC (GF_PRE << 8) + GF_ID +#define VF_PRE 247 +#define VF_ID_BYTE 202 +#define VF_MAGIC (VF_PRE << 8) + VF_ID_BYTE + +// #define DEBUG_FONT + + +TeXFontDefinition::TeXFontDefinition(QString nfontname, double _displayResolution_in_dpi, Q_UINT32 chk, Q_INT32 _scaled_size_in_DVI_units, + class fontPool *pool, double _enlargement) +{ +#ifdef DEBUG_FONT + kdDebug(4300) << "TeXFontDefinition::TeXFontDefinition(...); fontname=" << nfontname << ", enlargement=" << _enlargement << endl; +#endif + + enlargement = _enlargement; + font_pool = pool; + fontname = nfontname; + font = 0; + displayResolution_in_dpi = _displayResolution_in_dpi; + checksum = chk; + flags = TeXFontDefinition::FONT_IN_USE; + file = 0; + filename = QString::null; + scaled_size_in_DVI_units = _scaled_size_in_DVI_units; + + macrotable = 0; + + // By default, this font contains only empty characters. After the + // font has been loaded, this function pointer will be replaced by + // another one. + set_char_p = &dviRenderer::set_empty_char; +} + + +TeXFontDefinition::~TeXFontDefinition() +{ +#ifdef DEBUG_FONT + kdDebug(4300) << "discarding font " << fontname << " at " << (int)(enlargement * MFResolutions[font_pool->getMetafontMode()] + 0.5) << " dpi" << endl; +#endif + + if (font != 0) { + delete font; + font = 0; + } + if (macrotable != 0) { + delete [] macrotable; + macrotable = 0; + } + + if (flags & FONT_LOADED) { + if (file != 0) { + fclose(file); + file = 0; + } + if (flags & FONT_VIRTUAL) + vf_table.clear(); + } +} + + +void TeXFontDefinition::fontNameReceiver(const QString& fname) +{ +#ifdef DEBUG_FONT + kdDebug(4300) << "void TeXFontDefinition::fontNameReceiver( " << fname << " )" << endl; +#endif + + flags |= TeXFontDefinition::FONT_LOADED; + filename = fname; +#ifdef HAVE_FREETYPE + fullFontName = QString::null; + fullEncodingName = QString::null; +#endif + + file = fopen(QFile::encodeName(filename), "r"); + // Check if the file could be opened. If not, try to find the file + // in the DVI file's directory. If that works, modify the filename + // accordingly and go on. + if (file == 0) { + QString filename_test(font_pool->getExtraSearchPath() + "/" + filename); + file = fopen( QFile::encodeName(filename_test), "r"); + if (file == 0) { + kdError(4300) << i18n("Cannot find font %1, file %2.").arg(fontname).arg(filename) << endl; + return; + } else + filename = filename_test; + } + + set_char_p = &dviRenderer::set_char; + int magic = two(file); + + if (fname.endsWith("pk")) + if (magic == PK_MAGIC) { + fclose(file); + file = 0; + font = new TeXFont_PK(this); + set_char_p = &dviRenderer::set_char; + if ((checksum != 0) && (checksum != font->checksum)) + kdWarning(4300) << i18n("Checksum mismatch for font file %1").arg(filename) << endl; + fontTypeName = "TeX PK"; + return; + } + + if (fname.endsWith(".vf")) + if (magic == VF_MAGIC) { + read_VF_index(); + set_char_p = &dviRenderer::set_vf_char; + fontTypeName = i18n("TeX virtual"); + return; + } + + if (fname.endsWith(".tfm")) { + fclose(file); + file = 0; + font = new TeXFont_TFM(this); + set_char_p = &dviRenderer::set_char; + fontTypeName = i18n("TeX Font Metric"); + return; + } + + // None of these known types? Then it should be one of the font + // formats that are handled by the FreeType library + fclose(file); + file = 0; +#ifdef HAVE_FREETYPE + // Find the encoding for that font + const QString &enc = font_pool->fontsByTeXName.findEncoding(fontname); + + if (enc.isEmpty() == false) { +#ifdef DEBUG_FONT + kdDebug(4300) << "Font " << fontname << " uses encoding " << enc << endl; +#endif + font = new TeXFont_PFB(this, font_pool->encodingPool.findByName(enc), font_pool->fontsByTeXName.findSlant(fontname) ); + } else { +#ifdef DEBUG_FONT + kdDebug(4300) << "Font " << fontname << " does not have an encoding." << endl; +#endif + font = new TeXFont_PFB(this); + } + + set_char_p = &dviRenderer::set_char; + fontTypeName = i18n("FreeType"); + return; +#else + // If we don't have the FreeType library, we should never have + // reached this point. Complain, and leave this font blank + kdError(4300) << i18n("Cannot recognize format for font file %1").arg(filename) << endl; +#endif +} + + +void TeXFontDefinition::reset() +{ + if (font != 0) { + delete font; + font = 0; + } + + if (macrotable != 0) { + delete [] macrotable; + macrotable = 0; + } + + if (flags & FONT_LOADED) { + if (file != 0) { + fclose(file); + file = 0; + } + if (flags & FONT_VIRTUAL) + vf_table.clear(); + } + + filename = QString::null; + flags = TeXFontDefinition::FONT_IN_USE; + set_char_p = &dviRenderer::set_empty_char; +} + + +void TeXFontDefinition::setDisplayResolution(double _displayResolution_in_dpi) +{ + displayResolution_in_dpi = _displayResolution_in_dpi; + if (font != 0) + font->setDisplayResolution(); +} + + +/** mark_as_used marks the font, and all the fonts it referrs to, as + used, i.e. their FONT_IN_USE-flag is set. */ + +void TeXFontDefinition::mark_as_used() +{ +#ifdef DEBUG_FONT + kdDebug(4300) << "TeXFontDefinition::mark_as_used()" << endl; +#endif + + if (flags & TeXFontDefinition::FONT_IN_USE) + return; + + flags |= TeXFontDefinition::FONT_IN_USE; + + // For virtual fonts, also go through the list of referred fonts + if (flags & TeXFontDefinition::FONT_VIRTUAL) { + QIntDictIterator it(vf_table); + while( it.current() ) { + it.current()->mark_as_used(); + ++it; + } + } +} + + +macro::macro() +{ + pos = 0; /* address of first byte of macro */ + end = 0; /* address of last+1 byte */ + dvi_advance_in_units_of_design_size_by_2e20 = 0; /* DVI units to move reference point */ + free_me = false; +} + + +macro::~macro() +{ + if ((pos != 0L) && (free_me == true)) + delete [] pos; +} diff --git a/kdvi/TeXFontDefinition.h b/kdvi/TeXFontDefinition.h new file mode 100644 index 00000000..e3effc2a --- /dev/null +++ b/kdvi/TeXFontDefinition.h @@ -0,0 +1,126 @@ +// -*- C++ -*- +/* + * The layout of a font information block. + * There is one of these for every loaded font or magnification thereof. + * Duplicates are eliminated: this is necessary because of possible recursion + * in virtual fonts. + * + * Also note the strange units. The design size is in 1/2^20 point + * units (also called micro-points), and the individual character widths + * are in the TFM file in 1/2^20 ems units, i.e., relative to the design size. + * + * We then change the sizes to SPELL units (unshrunk pixel / 2^16). + */ + +#ifndef _FONT_H +#define _FONT_H + +#include +#include + +#include + +class dviRenderer; +class TeXFont; + +typedef void (dviRenderer::*set_char_proc)(unsigned int, unsigned int); + + +// Per character information for virtual fonts + +class macro { + public: + macro(); + ~macro(); + + unsigned char *pos; /* address of first byte of macro */ + unsigned char *end; /* address of last+1 byte */ + Q_INT32 dvi_advance_in_units_of_design_size_by_2e20; /* DVI units to move reference point */ + bool free_me; // if memory at pos should be returned on destruction +}; + + +class TeXFontDefinition { + public: + // Currently, kdvi supports fonts with at most 256 characters to + // comply with "The DVI Driver Standard, Level 0". If you change + // this value here, make sure to go through all the source and + // ensure that character numbers are stored in ints rather than + // unsigned chars. + static const unsigned int max_num_of_chars_in_font = 256; + enum font_flags { + FONT_IN_USE = 1, // used for housekeeping + FONT_LOADED = 2, // if font file has been read + FONT_VIRTUAL = 4, // if font is virtual + FONT_KPSE_NAME = 8 // if kpathsea has already tried to find the font name + }; + + + TeXFontDefinition(QString nfontname, double _displayResolution_in_dpi, Q_UINT32 chk, Q_INT32 _scaled_size_in_DVI_units, + class fontPool *pool, double _enlargement); + ~TeXFontDefinition(); + + void reset(); + void fontNameReceiver(const QString&); + + // Members for character fonts + void setDisplayResolution(double _displayResolution_in_dpi); + + bool isLocated() const {return ((flags & FONT_KPSE_NAME) != 0);} + void markAsLocated() {flags |= FONT_KPSE_NAME;} + + void mark_as_used(); + class fontPool *font_pool; // Pointer to the pool that contains this font. + QString fontname; // name of font, such as "cmr10" + unsigned char flags; // flags byte (see values below) + double enlargement; + Q_INT32 scaled_size_in_DVI_units; // Scaled size from the font definition command; in DVI units + set_char_proc set_char_p; // proc used to set char + + // Resolution of the display device (resolution will usually be + // scaled, according to the zoom) + double displayResolution_in_dpi; + + FILE *file; // open font file or NULL + QString filename; // name of font file + + TeXFont *font; + macro *macrotable; // used by (loaded) virtual fonts + QIntDict vf_table; // used by (loaded) virtual fonts, list of fonts used by this vf, + // acessible by number + TeXFontDefinition *first_font; // used by (loaded) virtual fonts, list of fonts used by this vf + +#ifdef HAVE_FREETYPE + const QString &getFullFontName() const {return fullFontName;} + const QString &getFullEncodingName() const {return fullEncodingName;} +#endif + const QString &getFontTypeName() const {return fontTypeName;} + +#ifdef HAVE_FREETYPE + /** For FREETYPE fonts, which use a map file, this field will + contain the full name of the font (e.g. 'Computer Modern'). If + the name does not exist, or cannot be found, this field will be + QString::null. Only subclasses of TeXFont should write into this + field. */ + QString fullFontName; + + /** For FREETYPE fonts, which use a map file, this field will + contain the full name of the font encoding (e.g. 'TexBase1'). If + the encoding name does not exist, or cannot be found, this field + will be QString::null. Only subclasses of TeXFont should write + into this field. */ + QString fullEncodingName; +#endif + + private: + Q_UINT32 checksum; + + /** This will be set to a human-readable description of the font, + e.g. "virtual" or "TeX PK", or "Type 1" */ + QString fontTypeName; + + // Functions related to virtual fonts + void read_VF_index(void ); +}; + +#endif diff --git a/kdvi/TeXFont_PFB.cpp b/kdvi/TeXFont_PFB.cpp new file mode 100644 index 00000000..927c84bc --- /dev/null +++ b/kdvi/TeXFont_PFB.cpp @@ -0,0 +1,294 @@ +// TeXFont_PFB.cpp +// +// Part of KDVI - A DVI previewer for the KDE desktop environemt +// +// (C) 2003 Stefan Kebekus +// Distributed under the GPL + +// This file is compiled only if the FreeType library is present on +// the system + +// Add header files alphabetically + +#include + +#include +#include +#include + +#include "fontpool.h" + +#ifdef HAVE_FREETYPE + +#include "glyph.h" +#include "TeXFont_PFB.h" + +//#define DEBUG_PFB 1 + + +TeXFont_PFB::TeXFont_PFB(TeXFontDefinition *parent, fontEncoding *enc, double slant) + : TeXFont(parent) +{ +#ifdef DEBUG_PFB + if (enc != 0) + kdDebug(4300) << "TeXFont_PFB::TeXFont_PFB( parent=" << parent << ", encoding=" << enc->encodingFullName << " )" << endl; + else + kdDebug(4300) << "TeXFont_PFB::TeXFont_PFB( parent=" << parent << ", encoding=0 )" << endl; +#endif + + fatalErrorInFontLoading = false; + + int error = FT_New_Face( parent->font_pool->FreeType_library, parent->filename.local8Bit(), 0, &face ); + + if ( error == FT_Err_Unknown_File_Format ) { + errorMessage = i18n("The font file %1 could be opened and read, but its font format is unsupported.").arg(parent->filename); + kdError(4300) << errorMessage << endl; + fatalErrorInFontLoading = true; + return; + } else + if ( error ) { + errorMessage = i18n("The font file %1 is broken, or it could not be opened or read.").arg(parent->filename); + kdError(4300) << errorMessage << endl; + fatalErrorInFontLoading = true; + return; + } + + // Take care of slanting, and transform all characters in the font, if necessary. + if (slant != 0.0) { + // Construct a transformation matrix for vertical shear which will + // be used to transform the characters. + transformationMatrix.xx = 0x10000; + transformationMatrix.xy = (FT_Fixed)(slant * 0x10000); + transformationMatrix.yx = 0; + transformationMatrix.yy = 0x10000; + + FT_Set_Transform( face, &transformationMatrix, 0); + } + + if (face->family_name != 0) + parent->fullFontName = face->family_name; + + // Finally, we need to set up the charMap array, which maps TeX + // character codes to glyph indices in the font. (Remark: the + // charMap, and the font encoding procedure is necessary, because + // TeX is only able to address character codes 0-255 while + // e.g. Type1 fonts may contain several thousands of characters) + if (enc != 0) { + parent->fullEncodingName = enc->encodingFullName.remove(QString::fromLatin1( "Encoding" )); + parent->fullEncodingName = enc->encodingFullName.remove(QString::fromLatin1( "encoding" )); + + // An encoding vector is given for this font, i.e. an array of + // character names (such as: 'parenleft' or 'dotlessj'). We use + // the FreeType library function 'FT_Get_Name_Index()' to + // associate glyph indices to those names. +#ifdef DEBUG_PFB + kdDebug(4300) << "Trying to associate glyph indices to names from the encoding vector." << endl; +#endif + for(int i=0; i<256; i++) { + charMap[i] = FT_Get_Name_Index( face, (FT_String *)(enc->glyphNameVector[i].ascii()) ); +#ifdef DEBUG_PFB + kdDebug(4300) << i << ": " << enc->glyphNameVector[i] << ", GlyphIndex=" << charMap[i] << endl; +#endif + } + } else { + // If there is no encoding vector available, we check if the font + // itself contains a charmap that could be used. An admissible + // charMap will be stored under platform_id=7 and encoding_id=2. + FT_CharMap found = 0; + for (int n = 0; nnum_charmaps; n++ ) { + FT_CharMap charmap = face->charmaps[n]; + if ( charmap->platform_id == 7 && charmap->encoding_id == 2 ) { + found = charmap; + break; + } + } + + if ((found != 0) && (FT_Set_Charmap( face, found ) == 0)) { + // Feed the charMap array with the charmap data found in the + // previous step. +#ifdef DEBUG_PFB + kdDebug(4300) << "No encoding given: using charmap platform=7, encoding=2 that is contained in the font." << endl; +#endif + for(int i=0; i<256; i++) + charMap[i] = FT_Get_Char_Index( face, i ); + } else { + if ((found == 0) && (face->charmap != 0)) { +#ifdef DEBUG_PFB + kdDebug(4300) << "No encoding given: using charmap platform=" << face->charmap->platform_id << + ", encoding=" << face->charmap->encoding_id << " that is contained in the font." << endl; +#endif + for(int i=0; i<256; i++) + charMap[i] = FT_Get_Char_Index( face, i ); + } else { + // As a last resort, we use the identity map. +#ifdef DEBUG_PFB + kdDebug(4300) << "No encoding given, no suitable charmaps found in the font: using identity charmap." << endl; +#endif + for(int i=0; i<256; i++) + charMap[i] = i; + } + } + } +} + + +TeXFont_PFB::~TeXFont_PFB() +{ + FT_Done_Face( face ); +} + + +glyph *TeXFont_PFB::getGlyph(Q_UINT16 ch, bool generateCharacterPixmap, const QColor& color) +{ +#ifdef DEBUG_PFB + kdDebug(4300) << "TeXFont_PFB::getGlyph( ch=" << ch << ", '" << (char)(ch) << "', generateCharacterPixmap=" << generateCharacterPixmap << " )" << endl; +#endif + + // Paranoia checks + if (ch >= TeXFontDefinition::max_num_of_chars_in_font) { + kdError(4300) << "TeXFont_PFB::getGlyph(): Argument is too big." << endl; + return glyphtable; + } + + // This is the address of the glyph that will be returned. + struct glyph *g = glyphtable+ch; + + + if (fatalErrorInFontLoading == true) + return g; + + if ((generateCharacterPixmap == true) && ((g->shrunkenCharacter.isNull()) || (color != g->color)) ) { + int error; + unsigned int res = (unsigned int)(parent->displayResolution_in_dpi/parent->enlargement +0.5); + g->color = color; + + // Character height in 1/64th of points (reminder: 1 pt = 1/72 inch) + // Only approximate, may vary from file to file!!!! @@@@@ + + long int characterSize_in_printers_points_by_64 = (long int)((64.0*72.0*parent->scaled_size_in_DVI_units*parent->font_pool->getCMperDVIunit())/2.54 + 0.5 ); + error = FT_Set_Char_Size(face, 0, characterSize_in_printers_points_by_64, res, res ); + if (error) { + QString msg = i18n("FreeType reported an error when setting the character size for font file %1.").arg(parent->filename); + if (errorMessage.isEmpty()) + errorMessage = msg; + kdError(4300) << msg << endl; + g->shrunkenCharacter.resize(1,1); + g->shrunkenCharacter.fill(QColor(255, 255, 255)); + return g; + } + + // load glyph image into the slot and erase the previous one + if (parent->font_pool->getUseFontHints() == true) + error = FT_Load_Glyph(face, charMap[ch], FT_LOAD_DEFAULT ); + else + error = FT_Load_Glyph(face, charMap[ch], FT_LOAD_NO_HINTING ); + + if (error) { + QString msg = i18n("FreeType is unable to load glyph #%1 from font file %2.").arg(ch).arg(parent->filename); + if (errorMessage.isEmpty()) + errorMessage = msg; + kdError(4300) << msg << endl; + g->shrunkenCharacter.resize(1,1); + g->shrunkenCharacter.fill(QColor(255, 255, 255)); + return g; + } + + // convert to an anti-aliased bitmap + error = FT_Render_Glyph( face->glyph, ft_render_mode_normal ); + if (error) { + QString msg = i18n("FreeType is unable to render glyph #%1 from font file %2.").arg(ch).arg(parent->filename); + if (errorMessage.isEmpty()) + errorMessage = msg; + kdError(4300) << msg << endl; + g->shrunkenCharacter.resize(1,1); + g->shrunkenCharacter.fill(QColor(255, 255, 255)); + return g; + } + + FT_GlyphSlot slot = face->glyph; + + if ((slot->bitmap.width == 0) || (slot->bitmap.rows == 0)) { + if (errorMessage.isEmpty()) + errorMessage = i18n("Glyph #%1 is empty.").arg(ch); + kdError(4300) << i18n("Glyph #%1 from font file %2 is empty.").arg(ch).arg(parent->filename) << endl; + g->shrunkenCharacter.resize( 15, 15 ); + g->shrunkenCharacter.fill(QColor(255, 0, 0)); + g->x2 = 0; + g->y2 = 15; + } else { + QImage imgi(slot->bitmap.width, slot->bitmap.rows, 32); + imgi.setAlphaBuffer(true); + + // Do QPixmaps fully support the alpha channel? If yes, we use + // that. Otherwise, use other routines as a fallback + if (parent->font_pool->QPixmapSupportsAlpha) { + // If the alpha channel is properly supported, we set the + // character glyph to a colored rectangle, and define the + // character outline only using the alpha channel. That + // ensures good quality rendering for overlapping characters. + uchar *srcScanLine = slot->bitmap.buffer; + for(int row=0; rowbitmap.rows; row++) { + uchar *destScanLine = imgi.scanLine(row); + for(int col=0; colbitmap.width; col++) { + destScanLine[4*col+0] = color.blue(); + destScanLine[4*col+1] = color.green(); + destScanLine[4*col+2] = color.red(); + destScanLine[4*col+3] = srcScanLine[col]; + } + srcScanLine += slot->bitmap.pitch; + } + } else { + // If the alpha channel is not supported... QT seems to turn + // the alpha channel into a crude bitmap which is used to mask + // the resulting QPixmap. In this case, we define the + // character outline using the image data, and use the alpha + // channel only to store "maximally opaque" or "completely + // transparent" values. When characters are rendered, + // overlapping characters are no longer correctly drawn, but + // quality is still sufficient for most purposes. One notable + // exception is output from the gftodvi program, which will be + // partially unreadable. + Q_UINT16 rInv = 0xFF - color.red(); + Q_UINT16 gInv = 0xFF - color.green(); + Q_UINT16 bInv = 0xFF - color.blue(); + + for(Q_UINT16 y=0; ybitmap.rows; y++) { + Q_UINT8 *srcScanLine = slot->bitmap.buffer + y*slot->bitmap.pitch; + unsigned int *destScanLine = (unsigned int *)imgi.scanLine(y); + for(Q_UINT16 col=0; colbitmap.width; col++) { + Q_UINT16 data = *srcScanLine; + // The value stored in "data" now has the following meaning: + // data = 0 -> white; data = 0xff -> use "color" + *destScanLine = qRgba(0xFF - (rInv*data + 0x7F) / 0xFF, + 0xFF - (gInv*data + 0x7F) / 0xFF, + 0xFF - (bInv*data + 0x7F) / 0xFF, + (data > 0x03) ? 0xff : 0x00); + destScanLine++; + srcScanLine++; + } + } + } + + g->shrunkenCharacter.convertFromImage (imgi, 0); + g->x2 = -slot->bitmap_left; + g->y2 = slot->bitmap_top; + } + } + + // Load glyph width, if that hasn't been done yet. + if (g->dvi_advance_in_units_of_design_size_by_2e20 == 0) { + int error = FT_Load_Glyph(face, charMap[ch], FT_LOAD_NO_SCALE); + if (error) { + QString msg = i18n("FreeType is unable to load metric for glyph #%1 from font file %2.").arg(ch).arg(parent->filename); + if (errorMessage.isEmpty()) + errorMessage = msg; + kdError(4300) << msg << endl; + g->dvi_advance_in_units_of_design_size_by_2e20 = 1; + } + g->dvi_advance_in_units_of_design_size_by_2e20 = (Q_INT32)(((Q_INT64)(1<<20) * (Q_INT64)face->glyph->metrics.horiAdvance) / (Q_INT64)face->units_per_EM); + } + + return g; +} + +#endif // HAVE_FREETYPE diff --git a/kdvi/TeXFont_PFB.h b/kdvi/TeXFont_PFB.h new file mode 100644 index 00000000..68211cdb --- /dev/null +++ b/kdvi/TeXFont_PFB.h @@ -0,0 +1,41 @@ +// -*- C++ -*- +// TeXFont_PFB.cpp +// +// Part of KDVI - A DVI previewer for the KDE desktop environemt +// +// (C) 2003 Stefan Kebekus +// Distributed under the GPL + +// This file is compiled only if the FreeType library is present on +// the system + +#ifndef _TEXFONT_PFB_H +#define _TEXFONT_PFB_H + +#include "TeXFont.h" + +#include +#include FT_FREETYPE_H + +class fontEncoding; +class glyph; + + +class TeXFont_PFB : public TeXFont { + public: + TeXFont_PFB(TeXFontDefinition *parent, fontEncoding *enc=0, double slant=0.0 ); + ~TeXFont_PFB(); + + glyph* getGlyph(Q_UINT16 character, bool generateCharacterPixmap=false, const QColor& color=Qt::black); + + private: + FT_Face face; + bool fatalErrorInFontLoading; + Q_UINT16 charMap[256]; + + // This matrix is used internally to describes the slant, if + // nonzero. Otherwise, this is undefined. + FT_Matrix transformationMatrix; +}; + +#endif diff --git a/kdvi/TeXFont_PK.cpp b/kdvi/TeXFont_PK.cpp new file mode 100644 index 00000000..6a3c9b3a --- /dev/null +++ b/kdvi/TeXFont_PK.cpp @@ -0,0 +1,781 @@ +/* + * Copyright (c) 1994 Paul Vojta. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * NOTE: + * xdvi is based on prior work as noted in the modification history, below. + */ + +/* + * DVI previewer for X. + * + * Eric Cooper, CMU, September 1985. + * + * Code derived from dvi-imagen.c. + * + * Modification history: + * 1/1986 Modified for X.10 --Bob Scheifler, MIT LCS. + * 7/1988 Modified for X.11 --Mark Eichin, MIT + * 12/1988 Added 'R' option, toolkit, magnifying glass + * --Paul Vojta, UC Berkeley. + * 2/1989 Added tpic support --Jeffrey Lee, U of Toronto + * 4/1989 Modified for System V --Donald Richardson, Clarkson Univ. + * 3/1990 Added VMS support --Scott Allendorf, U of Iowa + * 7/1990 Added reflection mode --Michael Pak, Hebrew U of Jerusalem + * 1/1992 Added greyscale code --Till Brychcy, Techn. Univ. Muenchen + * and Lee Hetherington, MIT + * 4/1994 Added DPS support, bounding box + * --Ricardo Telichevesky + * and Luis Miguel Silveira, MIT RLE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fontpool.h" +#include "glyph.h" +#include "xdvi.h" +#include "TeXFontDefinition.h" +#include "TeXFont_PK.h" + + +//#define DEBUG_PK + +#define PK_PRE 247 +#define PK_ID 89 +#define PK_MAGIC (PK_PRE << 8) + PK_ID + + +extern void oops(QString message); + + + +TeXFont_PK::TeXFont_PK(TeXFontDefinition *parent) + : TeXFont(parent) +{ +#ifdef DEBUG_PK + kdDebug(4300) << "TeXFont_PK::TeXFont_PK( parent=" << parent << ")" << endl; +#endif + + for(unsigned int i=0; ifilename), "r"); + if (file == 0) + kdError(4300) << i18n("Cannot open font file %1.").arg(parent->filename) << endl; +#ifdef DEBUG_PK + else + kdDebug(4300) << "TeXFont_PK::TeXFont_PK(): file opened successfully" << endl; +#endif + + read_PK_index(); + +#ifdef DEBUG_PK + kdDebug(4300) << "TeXFont_PK::TeXFont_PK() ended" << endl; +#endif +} + + +TeXFont_PK::~TeXFont_PK() +{ + //@@@ Release bitmaps + + if (file != 0) { + fclose(file); + file = 0; + } +} + + +glyph* TeXFont_PK::getGlyph(Q_UINT16 ch, bool generateCharacterPixmap, const QColor& color) +{ +#ifdef DEBUG_PK + kdDebug(4300) << "TeXFont_PK::getGlyph( ch=" << ch << ", generateCharacterPixmap=" << generateCharacterPixmap << " )" << endl; +#endif + + // Paranoia checks + if (ch >= TeXFontDefinition::max_num_of_chars_in_font) { + kdError(4300) << "TeXFont_PK::getGlyph(): Argument is too big." << endl; + return glyphtable; + } + + // This is the address of the glyph that will be returned. + struct glyph *g = glyphtable+ch; + + // Check if the glyph is loaded. If not, load it now. + if (characterBitmaps[ch] == 0) { + // If the character is not defined in the PK file, mark the + // character as missing, and print an error message + if (g->addr == 0) { + kdError(4300) << i18n("TexFont_PK::operator[]: Character %1 not defined in font %2").arg(ch).arg(parent->filename) << endl; + g->addr = -1; + return g; + } + + // If the character has already been marked as missing, just + // return a pointer to the glyph (which will then be empty) + if (g->addr == -1) + return g; + + // Otherwise, try to load the character + fseek(file, g->addr, 0); + read_PK_char(ch); + // Check if the character could be loaded. If not, mark the + // character as 'missing', and return a pointer. + if (characterBitmaps[ch]->bits == 0) { + g->addr = -1; + return g; + } + } + + // At this point, g points to a properly loaded character. Generate + // a smoothly scaled QPixmap if the user asks for it. + if ((generateCharacterPixmap == true) && + ((g->shrunkenCharacter.isNull()) || (color != g->color)) && + (characterBitmaps[ch]->w != 0)) { + g->color = color; + double shrinkFactor = 1200 / parent->displayResolution_in_dpi; + + // All is fine? Then we rescale the bitmap in order to produce the + // required pixmap. Rescaling a character, however, is an art + // that requires some explanation... + // + // If we would just divide the size of the character and the + // coordinates by the shrink factor, then the result would look + // quite ugly: due to the ineviatable rounding errors in the + // integer arithmetic, the characters would be displaced by up to + // a pixel. That doesn't sound much, but on low-resolution + // devices, such as a notebook screen, the effect would be a + // "dancing line" of characters, which looks really bad. + + // Calculate the coordinates of the hot point in the shrunken + // bitmap. For simplicity, let us consider the x-coordinate + // first. In principle, the hot point should have an x-coordinate + // of (g->x/shrinkFactor). That, however, will generally NOT be an + // integral number. The cure is to translate the source image + // somewhat, so that the x-coordinate of the hot point falls onto + // the round-up of this number, i.e. + g->x2 = (int)ceil(g->x/shrinkFactor); + + // Translating and scaling then means that the pixel in the scaled + // image which covers the range [x,x+1) corresponds to the range + // [x*shrinkFactor+srcXTrans, (x+1)*shrinkFactor+srcXTrans), where + // srcXTrans is the following NEGATIVE number + double srcXTrans = shrinkFactor * (g->x/shrinkFactor - ceil(g->x/shrinkFactor)); + + // How big will the shrunken bitmap then become? If shrunk_width + // denotes that width of the scaled image, and + // characterBitmaps[ch]->w the width of the orininal image, we + // need to make sure that the following inequality holds: + // + // shrunk_width*shrinkFactor+srcXTrans >= characterBitmaps[ch]->w + // + // in other words, + int shrunk_width = (int)ceil( (characterBitmaps[ch]->w - srcXTrans)/shrinkFactor ); + + // Now do the same for the y-coordinate + g->y2 = (int)ceil(g->y/shrinkFactor); + double srcYTrans = shrinkFactor * (g->y/shrinkFactor - ceil(g->y/shrinkFactor )); + int shrunk_height = (int)ceil( (characterBitmaps[ch]->h - srcYTrans)/shrinkFactor ); + + // Turn the image into 8 bit + QByteArray translated(characterBitmaps[ch]->w * characterBitmaps[ch]->h); + Q_UINT8 *data = (Q_UINT8 *)translated.data(); + for(int x=0; xw; x++) + for(int y=0; yh; y++) { + Q_UINT8 bit = *(characterBitmaps[ch]->bits + characterBitmaps[ch]->bytes_wide*y + (x >> 3)); + bit = bit >> (x & 7); + bit = bit & 1; + data[characterBitmaps[ch]->w*y + x] = bit; + } + + // Now shrink the image. We shrink the X-direction first + QByteArray xshrunk(shrunk_width*characterBitmaps[ch]->h); + Q_UINT8 *xdata = (Q_UINT8 *)xshrunk.data(); + + // Do the shrinking. The pixel (x,y) that we want to calculate + // corresponds to the line segment from + // + // [shrinkFactor*x+srcXTrans, shrinkFactor*(x+1)+srcXTrans) + // + // The trouble is, these numbers are in general no integers. + + for(int y=0; yh; y++) + for(int x=0; x= 0) && (srcX < characterBitmaps[ch]->w)) + value += data[characterBitmaps[ch]->w*y + srcX] * 255; + + if (destStartX >= 0.0) + value += (Q_UINT32) (255.0*(ceil(destStartX)-destStartX) * data[characterBitmaps[ch]->w*y + (int)floor(destStartX)]); + if (floor(destEndX) < characterBitmaps[ch]->w) + value += (Q_UINT32) (255.0*(destEndX-floor(destEndX)) * data[characterBitmaps[ch]->w*y + (int)floor(destEndX)]); + + xdata[shrunk_width*y + x] = (int)(value/shrinkFactor + 0.5); + } + + // Now shrink the Y-direction + QByteArray xyshrunk(shrunk_width*shrunk_height); + Q_UINT8 *xydata = (Q_UINT8 *)xyshrunk.data(); + for(int x=0; x= 0) && (srcY < characterBitmaps[ch]->h)) + value += xdata[shrunk_width*srcY + x]; + + if (destStartY >= 0.0) + value += (Q_UINT32) ((ceil(destStartY)-destStartY) * xdata[shrunk_width*(int)floor(destStartY) + x]); + if (floor(destEndY) < characterBitmaps[ch]->h) + value += (Q_UINT32) ((destEndY-floor(destEndY)) * xdata[shrunk_width*(int)floor(destEndY) + x]); + + xydata[shrunk_width*y + x] = (int)(value/shrinkFactor); + } + + QImage im32(shrunk_width, shrunk_height, 32); + im32.setAlphaBuffer(true); + // Do QPixmaps fully support the alpha channel? If yes, we use + // that. Otherwise, use other routines as a fallback + if (parent->font_pool->QPixmapSupportsAlpha) { + // If the alpha channel is properly supported, we set the + // character glyph to a colored rectangle, and define the + // character outline only using the alpha channel. That ensures + // good quality rendering for overlapping characters. + im32.fill(qRgb(color.red(), color.green(), color.blue())); + for(Q_UINT16 y=0; y white; data = 0xff -> use "color" + *destScanLine = qRgba(0xFF - (rInv*data + 0x7F) / 0xFF, + 0xFF - (gInv*data + 0x7F) / 0xFF, + 0xFF - (bInv*data + 0x7F) / 0xFF, + (data > 0x03) ? 0xff : 0x00); + destScanLine++; + srcScanLine++; + } + } + } + + g->shrunkenCharacter.convertFromImage(im32,0); + g->shrunkenCharacter.setOptimization(QPixmap::BestOptim); + } + return g; +} + + + +#define ADD(a, b) ((Q_UINT32 *) (((char *) a) + b)) +#define SUB(a, b) ((Q_UINT32 *) (((char *) a) - b)) + + + +// This table is used for changing the bit order in a byte. The +// expression bitflp[byte] takes a byte in big endian and gives the +// little endian equivalent of that. +static const uchar bitflip[256] = { + 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, + 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, + 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, + 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, + 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, + 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, + 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, + 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, + 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, + 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, + 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, + 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, + 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, + 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, + 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, + 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 +}; + +static Q_UINT32 bit_masks[33] = { + 0x0, 0x1, 0x3, 0x7, + 0xf, 0x1f, 0x3f, 0x7f, + 0xff, 0x1ff, 0x3ff, 0x7ff, + 0xfff, 0x1fff, 0x3fff, 0x7fff, + 0xffff, 0x1ffff, 0x3ffff, 0x7ffff, + 0xfffff, 0x1fffff, 0x3fffff, 0x7fffff, + 0xffffff, 0x1ffffff, 0x3ffffff, 0x7ffffff, + 0xfffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, + 0xffffffff +}; + + +#define PK_ID 89 +#define PK_CMD_START 240 +#define PK_X1 240 +#define PK_X2 241 +#define PK_X3 242 +#define PK_X4 243 +#define PK_Y 244 +#define PK_POST 245 +#define PK_NOOP 246 +#define PK_PRE 247 + + +int TeXFont_PK::PK_get_nyb(FILE *fp) +{ +#ifdef DEBUG_PK + kdDebug(4300) << "PK_get_nyb" << endl; +#endif + + unsigned temp; + if (PK_bitpos < 0) { + PK_input_byte = one(fp); + PK_bitpos = 4; + } + temp = PK_input_byte >> PK_bitpos; + PK_bitpos -= 4; + return (temp & 0xf); +} + + +int TeXFont_PK::PK_packed_num(FILE *fp) +{ +#ifdef DEBUG_PK + kdDebug(4300) << "PK_packed_num" << endl; +#endif + + int i,j; + + if ((i = PK_get_nyb(fp)) == 0) { + do { + j = PK_get_nyb(fp); + ++i; + } + while (j == 0); + while (i > 0) { + j = (j << 4) | PK_get_nyb(fp); + --i; + } + return (j - 15 + ((13 - PK_dyn_f) << 4) + PK_dyn_f); + } + else { + if (i <= PK_dyn_f) return i; + if (i < 14) + return (((i - PK_dyn_f - 1) << 4) + PK_get_nyb(fp) + + PK_dyn_f + 1); + if (i == 14) PK_repeat_count = PK_packed_num(fp); + else PK_repeat_count = 1; + return PK_packed_num(fp); + } +} + + +void TeXFont_PK::PK_skip_specials() +{ +#ifdef DEBUG_PK + kdDebug(4300) << "TeXFont_PK::PK_skip_specials() called" << endl; +#endif + + int i,j; + register FILE *fp = file; + +#ifdef DEBUG_PK + if (fp == 0) + kdDebug(4300) << "TeXFont_PK::PK_skip_specials(): file == 0" << endl; +#endif + + do { + PK_flag_byte = one(fp); + if (PK_flag_byte >= PK_CMD_START) { + switch (PK_flag_byte) { + case PK_X1 : + case PK_X2 : + case PK_X3 : + case PK_X4 : + i = 0; + for (j = PK_CMD_START; j <= PK_flag_byte; ++j) + i = (i << 8) | one(fp); + while (i--) (void) one(fp); + break; + case PK_Y : + (void) four(fp); + case PK_POST : + case PK_NOOP : + break; + default : + oops(i18n("Unexpected %1 in PK file %2").arg(PK_flag_byte).arg(parent->filename) ); + break; + } + } + } + while (PK_flag_byte != PK_POST && PK_flag_byte >= PK_CMD_START); + +#ifdef DEBUG_PK + kdDebug(4300) << "TeXFont_PK::PK_skip_specials() ended" << endl; +#endif +} + + +void TeXFont_PK::read_PK_char(unsigned int ch) +{ +#ifdef DEBUG_PK + kdDebug(4300) << "read_PK_char" << endl; +#endif + + int i, j; + int n; + int row_bit_pos; + bool paint_switch; + Q_UINT32 *cp; + register struct glyph *g; + register FILE *fp = file; + long fpwidth; + Q_UINT32 word = 0; + int word_weight, bytes_wide; + int rows_left, h_bit, count; + + g = glyphtable + ch; + PK_flag_byte = g->x2; + PK_dyn_f = PK_flag_byte >> 4; + paint_switch = ((PK_flag_byte & 8) != 0); + PK_flag_byte &= 0x7; + if (PK_flag_byte == 7) + n = 4; + else + if (PK_flag_byte > 3) + n = 2; + else + n = 1; + +#ifdef DEBUG_PK + kdDebug(4300) << "loading pk char " << ch << ", char type " << n << endl; +#endif + + if (characterBitmaps[ch] == 0) + characterBitmaps[ch] = new bitmap(); + + /* + * now read rest of character preamble + */ + if (n != 4) + fpwidth = num(fp, 3); + else { + fpwidth = sfour(fp); + (void) four(fp); /* horizontal escapement */ + } + (void) num(fp, n); /* vertical escapement */ + { + unsigned long w, h; + + w = num(fp, n); + h = num(fp, n); + if (w > 0x7fff || h > 0x7fff) + oops(i18n("The character %1 is too large in file %2").arg(ch).arg(parent->filename)); + characterBitmaps[ch]->w = w; + characterBitmaps[ch]->h = h; + } + g->x = snum(fp, n); + g->y = snum(fp, n); + + g->dvi_advance_in_units_of_design_size_by_2e20 = fpwidth; + + { + /* width must be multiple of 16 bits for raster_op */ + characterBitmaps[ch]->bytes_wide = ROUNDUP((int) characterBitmaps[ch]->w, 32) * 4; + register unsigned int size = characterBitmaps[ch]->bytes_wide * characterBitmaps[ch]->h; + characterBitmaps[ch]->bits = new char[size != 0 ? size : 1]; + } + + cp = (Q_UINT32 *) characterBitmaps[ch]->bits; + + /* + * read character data into *cp + */ + bytes_wide = ROUNDUP((int) characterBitmaps[ch]->w, 32) * 4; + PK_bitpos = -1; + + // The routines which read the character depend on the bit + // ordering. In principle, the bit order should be detected at + // compile time and the proper routing chosen. For the moment, as + // autoconf is somewhat complicated for the author, we prefer a + // simpler -even if somewhat slower approach and detect the ordering + // at runtime. That should of course be changed in the future. + + int wordSize; + bool bigEndian; + qSysInfo (&wordSize, &bigEndian); + + if (bigEndian) { + // Routine for big Endian machines. Applies e.g. to Motorola and + // (Ultra-)Sparc processors. + +#ifdef DEBUG_PK + kdDebug(4300) << "big Endian byte ordering" << endl; +#endif + + if (PK_dyn_f == 14) { /* get raster by bits */ + memset(characterBitmaps[ch]->bits, 0, (int) characterBitmaps[ch]->h * bytes_wide); + for (i = 0; i < (int) characterBitmaps[ch]->h; i++) { /* get all rows */ + cp = ADD(characterBitmaps[ch]->bits, i * bytes_wide); + row_bit_pos = 32; + for (j = 0; j < (int) characterBitmaps[ch]->w; j++) { /* get one row */ + if (--PK_bitpos < 0) { + word = one(fp); + PK_bitpos = 7; + } + if (--row_bit_pos < 0) { + cp++; + row_bit_pos = 32 - 1; + } + if (word & (1 << PK_bitpos)) + *cp |= 1 << row_bit_pos; + } + } + } else { /* get packed raster */ + rows_left = characterBitmaps[ch]->h; + h_bit = characterBitmaps[ch]->w; + PK_repeat_count = 0; + word_weight = 32; + word = 0; + while (rows_left > 0) { + count = PK_packed_num(fp); + while (count > 0) { + if (count < word_weight && count < h_bit) { + h_bit -= count; + word_weight -= count; + if (paint_switch) + word |= bit_masks[count] << word_weight; + count = 0; + } else + if (count >= h_bit && h_bit <= word_weight) { + if (paint_switch) + word |= bit_masks[h_bit] << (word_weight - h_bit); + *cp++ = word; + /* "output" row(s) */ + for (i = PK_repeat_count * bytes_wide / 4; i > 0; --i) { + *cp = *SUB(cp, bytes_wide); + ++cp; + } + rows_left -= PK_repeat_count + 1; + PK_repeat_count = 0; + word = 0; + word_weight = 32; + count -= h_bit; + h_bit = characterBitmaps[ch]->w; + } else { + if (paint_switch) + word |= bit_masks[word_weight]; + *cp++ = word; + word = 0; + count -= word_weight; + h_bit -= word_weight; + word_weight = 32; + } + } + paint_switch = 1 - paint_switch; + } + if (cp != ((Q_UINT32 *) (characterBitmaps[ch]->bits + bytes_wide * characterBitmaps[ch]->h))) + oops(i18n("Wrong number of bits stored: char. %1, font %2").arg(ch).arg(parent->filename)); + if (rows_left != 0 || h_bit != characterBitmaps[ch]->w) + oops(i18n("Bad pk file (%1), too many bits").arg(parent->filename)); + } + + // The data in the bitmap is now in the processor's bit order, + // that is, big endian. Since XWindows needs little endian, we + // need to change the bit order now. + register unsigned char* bitmapData = (unsigned char*) characterBitmaps[ch]->bits; + register unsigned char* endOfData = bitmapData + characterBitmaps[ch]->bytes_wide*characterBitmaps[ch]->h; + while(bitmapData < endOfData) { + *bitmapData = bitflip[*bitmapData]; + bitmapData++; + } + + } else { + + // Routines for small Endian start here. This applies e.g. to + // Intel and Alpha processors. + +#ifdef DEBUG_PK + kdDebug(4300) << "small Endian byte ordering" << endl; +#endif + + if (PK_dyn_f == 14) { /* get raster by bits */ + memset(characterBitmaps[ch]->bits, 0, (int) characterBitmaps[ch]->h * bytes_wide); + for (i = 0; i < (int) characterBitmaps[ch]->h; i++) { /* get all rows */ + cp = ADD(characterBitmaps[ch]->bits, i * bytes_wide); + row_bit_pos = -1; + for (j = 0; j < (int) characterBitmaps[ch]->w; j++) { /* get one row */ + if (--PK_bitpos < 0) { + word = one(fp); + PK_bitpos = 7; + } + if (++row_bit_pos >= 32) { + cp++; + row_bit_pos = 0; + } + if (word & (1 << PK_bitpos)) + *cp |= 1 << row_bit_pos; + } + } + } else { /* get packed raster */ + rows_left = characterBitmaps[ch]->h; + h_bit = characterBitmaps[ch]->w; + PK_repeat_count = 0; + word_weight = 32; + word = 0; + while (rows_left > 0) { + count = PK_packed_num(fp); + while (count > 0) { + if (count < word_weight && count < h_bit) { + if (paint_switch) + word |= bit_masks[count] << (32 - word_weight); + h_bit -= count; + word_weight -= count; + count = 0; + } else + if (count >= h_bit && h_bit <= word_weight) { + if (paint_switch) + word |= bit_masks[h_bit] << (32 - word_weight); + *cp++ = word; + /* "output" row(s) */ + for (i = PK_repeat_count * bytes_wide / 4; i > 0; --i) { + *cp = *SUB(cp, bytes_wide); + ++cp; + } + rows_left -= PK_repeat_count + 1; + PK_repeat_count = 0; + word = 0; + word_weight = 32; + count -= h_bit; + h_bit = characterBitmaps[ch]->w; + } else { + if (paint_switch) + word |= bit_masks[word_weight] << (32 - word_weight); + *cp++ = word; + word = 0; + count -= word_weight; + h_bit -= word_weight; + word_weight = 32; + } + } + paint_switch = 1 - paint_switch; + } + if (cp != ((Q_UINT32 *) (characterBitmaps[ch]->bits + bytes_wide * characterBitmaps[ch]->h))) + oops(i18n("Wrong number of bits stored: char. %1, font %2").arg(ch).arg(parent->filename)); + if (rows_left != 0 || h_bit != characterBitmaps[ch]->w) + oops(i18n("Bad pk file (%1), too many bits").arg(parent->filename)); + } + } // endif: big or small Endian? +} + + +void TeXFont_PK::read_PK_index() +{ +#ifdef DEBUG_PK + kdDebug(4300) << "TeXFont_PK::read_PK_index() called" << endl; +#endif + + if (file == 0) { + kdError(4300) << "TeXFont_PK::read_PK_index(): file == 0" << endl; + return; + } + + int magic = two(file); + if (magic != PK_MAGIC) { + kdError(4300) << "TeXFont_PK::read_PK_index(): file is not a PK file" << endl; + return; + } + + fseek(file, (long) one(file), SEEK_CUR); /* skip comment */ + (void) four(file); /* skip design size */ + + checksum = four(file); + + int hppp = sfour(file); + int vppp = sfour(file); + if (hppp != vppp) + kdWarning(4300) << i18n("Font has non-square aspect ratio ") << vppp << ":" << hppp << endl; + + // Read glyph directory (really a whole pass over the file). + for (;;) { + int bytes_left, flag_low_bits; + unsigned int ch; + + PK_skip_specials(); + if (PK_flag_byte == PK_POST) + break; + flag_low_bits = PK_flag_byte & 0x7; + if (flag_low_bits == 7) { + bytes_left = four(file); + ch = four(file); + } else + if (flag_low_bits > 3) { + bytes_left = ((flag_low_bits - 4) << 16) + two(file); + ch = one(file); + } else { + bytes_left = (flag_low_bits << 8) + one(file); + ch = one(file); + } + + glyphtable[ch].addr = ftell(file); + glyphtable[ch].x2 = PK_flag_byte; + fseek(file, (long) bytes_left, SEEK_CUR); +#ifdef DEBUG_PK + kdDebug(4300) << "Scanning pk char " << ch << "at " << glyphtable[ch].addr << endl; +#endif + } +#ifdef DEBUG_PK + kdDebug(4300) << "TeXFont_PK::read_PK_index() called" << endl; +#endif +} diff --git a/kdvi/TeXFont_PK.h b/kdvi/TeXFont_PK.h new file mode 100644 index 00000000..b555934e --- /dev/null +++ b/kdvi/TeXFont_PK.h @@ -0,0 +1,38 @@ +// -*- C++ -*- + +#ifndef _TEXFONT_PK_H +#define _TEXFONT_PK_H + +#include "TeXFont.h" + +class glyph; + +class TeXFont_PK : public TeXFont { + public: + TeXFont_PK(TeXFontDefinition *parent); + ~TeXFont_PK(); + + glyph* getGlyph(Q_UINT16 character, bool generateCharacterPixmap=false, const QColor& color=Qt::black); + + private: + FILE *file; // open font file or NULL + class bitmap *characterBitmaps[TeXFontDefinition::max_num_of_chars_in_font]; + + // For use by PK-decryption routines. I don't understand what these + // are good for -- Stefan Kebekus + int PK_flag_byte; + unsigned PK_input_byte; + int PK_bitpos; + int PK_dyn_f; + int PK_repeat_count; + + // PK-internal routines which were taken from xdvi. Again, I do not + // really know what they are good for -- Stefan Kebekus + inline void read_PK_char(unsigned int ch); + inline int PK_get_nyb(FILE *fp); + inline int PK_packed_num(FILE *fp); + inline void read_PK_index(); + inline void PK_skip_specials(); +}; + +#endif diff --git a/kdvi/TeXFont_TFM.cpp b/kdvi/TeXFont_TFM.cpp new file mode 100644 index 00000000..54edd2fc --- /dev/null +++ b/kdvi/TeXFont_TFM.cpp @@ -0,0 +1,163 @@ +// TeXFont_TFM.cpp +// +// Part of KDVI - A DVI previewer for the KDE desktop environemt +// +// (C) 2003 Stefan Kebekus +// Distributed under the GPL + +// Add header files alphabetically + +#include + +#include +#include +#include +#include + +#include "glyph.h" +#include "TeXFont_TFM.h" +#include "TeXFontDefinition.h" + +//#define DEBUG_TFM + + +TeXFont_TFM::TeXFont_TFM(TeXFontDefinition *parent) + : TeXFont(parent) +{ +#ifdef DEBUG_TFM + kdDebug(4300) << "TeXFont_TFM::TeXFont_TFM( parent=" << parent << " )" << endl; +#endif + + QFile file( parent->filename ); + if ( !file.open( IO_ReadOnly ) ) { + kdError(4300) << "TeXFont_TFM::TeXFont_TFM(): Could not read TFM file" << endl; + return; + } + QDataStream stream( &file ); + + // Data from the very beginning of the TFM file, as specified in + // "The DVI Driver Standard, Level 0", section D.2.1 + Q_UINT16 lf, lh, bc, ec, nw, nh, nd; + stream >> lf >> lh >> bc >> ec >> nw >> nh >> nd; +#ifdef DEBUG_TFM + kdDebug(4300) << "lf= " << lf << endl + << "lh= " << lh << endl + << "bc= " << bc << endl + << "ec= " << ec << endl + << "nw= " << nw << endl + << "nh= " << nh << endl + << "nd= " << nd << endl; +#endif + if ((bc > ec) || (ec >= TeXFontDefinition::max_num_of_chars_in_font)) { + kdError(4300) << "TeXFont_TFM::TeXFont_TFM( filename=" << parent->filename << " ): The font has an invalid bc and ec entries." << endl; + file.close(); + return; + } + + // Data from the HEADER section of the TFM data. + file.at(24); + stream >> checksum >> design_size_in_TeX_points.value; +#ifdef DEBUG_TFM + kdDebug(4300) << "checksum = " << checksum << endl + << "design_size = " << design_size_in_TeX_points.toDouble() << " TeX Points" << endl + << " = " << design_size_in_TeX_points.toDouble()*254.0/7227.0 << " cm" << endl; +#endif + + // Width table + fix_word widthTable_in_units_of_design_size[TeXFontDefinition::max_num_of_chars_in_font]; + for(unsigned int i=0; i> widthTable_in_units_of_design_size[i].value; + // Some characters, which are used as parts of glyphs, have width + // 0 --the real width is caculated in a lig_kern program and + // depends on the preceding character. We cannot calculate the + // real width here and take 0.4 times the design size as an + // approximation. + if (widthTable_in_units_of_design_size[i].value == 0) + widthTable_in_units_of_design_size[i].fromDouble(0.4); + } + + // Height table + fix_word heightTable_in_units_of_design_size[16]; + for(unsigned int i=0; i<16; i++) + heightTable_in_units_of_design_size[i].value = 0; + for(unsigned int i=0; i> heightTable_in_units_of_design_size[i].value; + } + + // Char-Info table + file.at( 24 + 4*lh ); + for(unsigned int characterCode=bc; characterCode> byte; + if (byte >= nw) + kdError(4300) << "TeXFont_TFM::TeXFont_TFM( filename=" << parent->filename << " ): The font has an invalid Char-Info table." << endl; + else { + characterWidth_in_units_of_design_size[characterCode] = widthTable_in_units_of_design_size[byte]; + g->dvi_advance_in_units_of_design_size_by_2e20 = widthTable_in_units_of_design_size[byte].value; + } + + stream >> byte; + byte = byte >> 4; + if (byte >= nh) + kdError(4300) << "TeXFont_TFM::TeXFont_TFM( filename=" << parent->filename << " ): The font has an invalid Char-Info table." << endl; + else + characterHeight_in_units_of_design_size[characterCode] = heightTable_in_units_of_design_size[byte]; + + stream >> byte; + stream >> byte; + } + file.close(); +} + + +TeXFont_TFM::~TeXFont_TFM() +{ +} + + +glyph *TeXFont_TFM::getGlyph(Q_UINT16 characterCode, bool generateCharacterPixmap, const QColor& color) +{ +#ifdef DEBUG_TFM + kdDebug(4300) << "TeXFont_TFM::getGlyph( ch=" << ch << ", generateCharacterPixmap=" << generateCharacterPixmap << " )" << endl; +#endif + + // Paranoia checks + if (characterCode >= TeXFontDefinition::max_num_of_chars_in_font) { + kdError(4300) << "TeXFont_TFM::getGlyph(): Argument is too big." << endl; + return glyphtable; + } + + // This is the address of the glyph that will be returned. + struct glyph *g = glyphtable+characterCode; + + if ((generateCharacterPixmap == true) && ((g->shrunkenCharacter.isNull()) || (color != g->color)) ) { + g->color = color; + Q_UINT16 pixelWidth = (Q_UINT16)(parent->displayResolution_in_dpi * + design_size_in_TeX_points.toDouble() * + characterWidth_in_units_of_design_size[characterCode].toDouble() * 100.0/7227.0 + 0.5); + Q_UINT16 pixelHeight = (Q_UINT16)(parent->displayResolution_in_dpi * + design_size_in_TeX_points.toDouble() * + characterHeight_in_units_of_design_size[characterCode].toDouble() * 100.0/7227.0 + 0.5); + + // Just make sure that weired TFM files never lead to giant + // pixmaps that eat all system memory... + if (pixelWidth > 50) + pixelWidth = 50; + if (pixelHeight > 50) + pixelHeight = 50; + + g->shrunkenCharacter.resize( pixelWidth, pixelHeight ); + g->shrunkenCharacter.fill(color); + g->x2 = 0; + g->y2 = pixelHeight; + } + + return g; +} diff --git a/kdvi/TeXFont_TFM.h b/kdvi/TeXFont_TFM.h new file mode 100644 index 00000000..e68ba872 --- /dev/null +++ b/kdvi/TeXFont_TFM.h @@ -0,0 +1,38 @@ +// -*- C++ -*- +// TeXFont_TFM.h +// +// Part of KDVI - A DVI previewer for the KDE desktop environemt +// +// (C) 2003 Stefan Kebekus +// Distributed under the GPL + +#ifndef _TEXFONT_TFM_H +#define _TEXFONT_TFM_H + +#include "TeXFont.h" + + +class fix_word { + public: + void fromINT32(Q_INT32 val) {value = val;} + void fromDouble(double val) {value = (Q_INT32)(val * (1<<20) + 0.5);} + double toDouble() {return (double(value)) / (double(1<<20));} + + Q_INT32 value; +}; + +class TeXFont_TFM : public TeXFont { + public: + TeXFont_TFM(TeXFontDefinition *parent); + ~TeXFont_TFM(); + + glyph* getGlyph(Q_UINT16 character, bool generateCharacterPixmap=false, const QColor& color=Qt::black); + + private: + fix_word characterWidth_in_units_of_design_size[256]; + fix_word characterHeight_in_units_of_design_size[256]; + + fix_word design_size_in_TeX_points; +}; + +#endif diff --git a/kdvi/bigEndianByteReader.cpp b/kdvi/bigEndianByteReader.cpp new file mode 100644 index 00000000..63d11f83 --- /dev/null +++ b/kdvi/bigEndianByteReader.cpp @@ -0,0 +1,111 @@ +// bigEndianByteReader.cpp +// +// Part of KDVI - A DVI previewer for the KDE desktop environemt +// +// (C) 2003 Stefan Kebekus +// Distributed under the GPL + +#include + +#include + +#include "bigEndianByteReader.h" +#include "dvi.h" + +//#define DEBUG_ENDIANREADER + +Q_UINT8 bigEndianByteReader::readUINT8() +{ + // This check saveguards us against segmentation fault. It is also + // necessary for virtual fonts, which do not end whith EOP. + if (command_pointer >= end_pointer) { +#ifdef DEBUG_ENDIANREADER + kdError(4300) << "bigEndianByteReader::readUINT8() tried to read past end of data chunk" << endl; + kdError(4300) << "end_pointer = " << end_pointer << endl; + kdError(4300) << "command_pointer = " << command_pointer << endl; +#endif + return EOP; + } + + return *(command_pointer++); +} + +Q_UINT16 bigEndianByteReader::readUINT16() +{ + // This check saveguards us against segmentation fault. It is also + // necessary for virtual fonts, which do not end whith EOP. + if (command_pointer >= end_pointer) + return EOP; + + Q_UINT16 a; + a = *(command_pointer++); + a = (a << 8) | *(command_pointer++); + return a; +} + +Q_UINT32 bigEndianByteReader::readUINT32() +{ + // This check saveguards us against segmentation fault. It is also + // necessary for virtual fonts, which do not end whith EOP. + if (command_pointer >= end_pointer) + return EOP; + + Q_UINT32 a; + a = *(command_pointer++); + a = (a << 8) | *(command_pointer++); + a = (a << 8) | *(command_pointer++); + a = (a << 8) | *(command_pointer++); + return a; +} + +void bigEndianByteReader::writeUINT32(Q_UINT32 a) +{ + // This check saveguards us against segmentation fault. It is also + // necessary for virtual fonts, which do not end whith EOP. + if (command_pointer >= end_pointer) + return; + + command_pointer[3] = (Q_UINT8)(a & 0xFF); + a = a >> 8; + command_pointer[2] = (Q_UINT8)(a & 0xFF); + a = a >> 8; + command_pointer[1] = (Q_UINT8)(a & 0xFF); + a = a >> 8; + command_pointer[0] = (Q_UINT8)(a & 0xFF); + + command_pointer += 4; + return; +} + +Q_UINT32 bigEndianByteReader::readUINT(Q_UINT8 size) +{ + // This check saveguards us against segmentation fault. It is also + // necessary for virtual fonts, which do not end whith EOP. + if (command_pointer >= end_pointer) + return EOP; + + Q_UINT32 a = 0; + while (size > 0) { + a = (a << 8) + *(command_pointer++); + size--; + } + return a; +} + +Q_INT32 bigEndianByteReader::readINT(Q_UINT8 length) +{ + // This check saveguards us against segmentation fault. It is also + // necessary for virtual fonts, which do not end whith EOP. + if (command_pointer >= end_pointer) + return EOP; + + Q_INT32 a = *(command_pointer++); + + if (a & 0x80) + a -= 0x100; + + while ((--length) > 0) + a = (a << 8) | *(command_pointer++); + + return a; +} diff --git a/kdvi/bigEndianByteReader.h b/kdvi/bigEndianByteReader.h new file mode 100644 index 00000000..674ca1c1 --- /dev/null +++ b/kdvi/bigEndianByteReader.h @@ -0,0 +1,62 @@ +// -*- C++ -*- +/* This file is part of KDVI (C) 2001 by Stefan Kebekus (kebekus@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. +*/ + +/** + * Byte reading routines which read big endian numbers from memory and + * convert them to native integers. + * + * @author Stefan Kebekus (kebekus@kde.org) + * + **/ + +#ifndef _bigEndianByteReader_H +#define _bigEndianByteReader_H + +#include + +class bigEndianByteReader { + public: + /** Set this pointer to the location where the number resides which + you want to read. */ + Q_UINT8 * command_pointer; + + /** This pointer marks the end of the memory area where bytes can be + read. It should point to the first byte which CANNOT be + read. The idea is to have a safety net which protects us against + SEGFAULTs. This is also used in virtual fonts, where the macro + does not have an EOP command at the end of the macro. */ + Q_UINT8 * end_pointer; + + /** If command_pointer >= end_pointer, this method return EOP (=140) + and exists. Otherwise, the method returns the unsigned byte + and increases the command_pointer by one. */ + Q_UINT8 readUINT8(); + + /** Similar to the method above, only that the method reads a big + endian 2-byte word and increases the pointer by two. */ + Q_UINT16 readUINT16(); + + /** Similar to the method above, only that the method reads a big + endian 4-byte word and increases the pointer by four. */ + Q_UINT32 readUINT32(); + + void writeUINT32(Q_UINT32 a); + + /** Similar to the method above, only that the method reads a big + endian number of length size, where 1 <= size <= 4. Note that + the value 3 is allowed (and is acually used in DVI files)!!! */ + Q_UINT32 readUINT(Q_UINT8 size); + + /** Similar to the method above, only that the method reads a SIGNED + number */ + Q_INT32 readINT(Q_UINT8); + +}; + +#endif //ifndef _bigEndianByteReader_H diff --git a/kdvi/configure.in.in b/kdvi/configure.in.in new file mode 100644 index 00000000..ba3ee342 --- /dev/null +++ b/kdvi/configure.in.in @@ -0,0 +1,55 @@ + +dnl the following is just to fool the toplevel configure.in +LTLIBOBJS= +AC_SUBST(LTLIBOBJS) + +compile_kdvi=yes +for j in $DO_NOT_COMPILE; do + if test "kdvi" = $j; then + compile_kdvi=no + fi +done + +dnl AC_CONFIG_SUBDIRS has to be done before KDE_CREATE_SUBDIRSLIST +if test "$compile_kdvi" = "yes"; then + + KDE_FIND_PATH(kpsewhich, KPSEWHICH, [/usr/bin /bin /usr/sbin /opt/teTeX/bin /opt/local/bin /opt/bin /usr/local/bin], [ ]) + + have_kpsewhich=no + test_kpsewhich="`${KPSEWHICH-kpsewhich} -show-path cnf 2>/dev/null`" + test -n "${test_kpsewhich}" && have_kpsewhich=yes + +fi + +AC_CHECK_HEADERS(sys/types.h sys/params.h limits.h) + +# Check for freetype2 +KDE_FIND_PATH(freetype-config, FREETYPE_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin],) + +if test -n "$FREETYPE_CONFIG"; then + vers=`$FREETYPE_CONFIG --version 2>/dev/null | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'` + if test -n "$vers" && test "$vers" -ge 8000002 + then + LIBFREETYPE_LIBS="`$FREETYPE_CONFIG --libs`" + FREETYPE_RPATH= + for args in $LIBFREETYPE_LIBS; do + case $args in + -L*) + FREETYPE_RPATH="$FREETYPE_RPATH $args" + ;; + esac + done + FREETYPE_RPATH=`echo $FREETYPE_RPATH | sed -e "s/-L/-R/g"` + LIBFREETYPE_CFLAGS="`$FREETYPE_CONFIG --cflags`" + + AC_DEFINE_UNQUOTED(HAVE_FREETYPE, 1, [Defines if your system has the freetype library]) + fi +fi + +AC_SUBST(LIBFREETYPE_LIBS) +AC_SUBST(LIBFREETYPE_CFLAGS) +AC_SUBST(FREETYPE_RPATH) + +if test -z "$LIBFREETYPE_LIBS"; then + DO_NOT_COMPILE="$DO_NOT_COMPILE kdvi" +fi diff --git a/kdvi/dvi.h b/kdvi/dvi.h new file mode 100644 index 00000000..62178f49 --- /dev/null +++ b/kdvi/dvi.h @@ -0,0 +1,68 @@ +// -*- C++ -*- +/* + * Mnemonics for bytes in dvi file. + */ + +#ifndef DVI_H +#define DVI_H + +#define SETCHAR0 0 +#define SET1 128 +#define SETRULE 132 +#define PUT1 133 +#define PUTRULE 137 +#define NOP 138 +#define BOP 139 +#define EOP 140 +#define PUSH 141 +#define POP 142 +#define RIGHT1 143 +#define RIGHT2 144 +#define RIGHT3 145 +#define RIGHT4 146 +#define W0 147 +#define W1 148 +#define W2 149 +#define W3 150 +#define W4 151 +#define X0 152 +#define X1 153 +#define X2 154 +#define X3 155 +#define X4 156 +#define DOWN1 157 +#define DOWN2 158 +#define DOWN3 159 +#define DOWN4 160 +#define Y0 161 +#define Y1 162 +#define Y2 163 +#define Y3 164 +#define Y4 165 +#define Z0 166 +#define Z1 167 +#define Z2 168 +#define Z3 169 +#define Z4 170 +#define FNTNUM0 171 +#define FNT1 235 +#define FNT2 236 +#define FNT3 237 +#define FNT4 238 +#define XXX1 239 +#define XXX2 240 +#define XXX3 241 +#define XXX4 242 +#define FNTDEF1 243 +#define FNTDEF2 244 +#define FNTDEF3 245 +#define FNTDEF4 246 +#define PRE 247 +#define POST 248 +#define POSTPOST 249 +#define SREFL 250 +#define EREFL 251 + +#define TRAILER 223 /* Trailing bytes at end of file */ + +#endif diff --git a/kdvi/dviFile.cpp b/kdvi/dviFile.cpp new file mode 100644 index 00000000..521fb39f --- /dev/null +++ b/kdvi/dviFile.cpp @@ -0,0 +1,406 @@ +/* + * Copyright (c) 1994 Paul Vojta. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * NOTE: + * xdvi is based on prior work as noted in the modification history, below. + */ + +/* + * DVI previewer for X. + * + * Eric Cooper, CMU, September 1985. + * + * Code derived from dvi-imagen.c. + * + * Modification history: + * 1/1986 Modified for X.10 --Bob Scheifler, MIT LCS. + * 7/1988 Modified for X.11 --Mark Eichin, MIT + * 12/1988 Added 'R' option, toolkit, magnifying glass + * --Paul Vojta, UC Berkeley. + * 2/1989 Added tpic support --Jeffrey Lee, U of Toronto + * 4/1989 Modified for System V --Donald Richardson, Clarkson Univ. + * 3/1990 Added VMS support --Scott Allendorf, U of Iowa + * 7/1990 Added reflection mode --Michael Pak, Hebrew U of Jerusalem + * 1/1992 Added greyscale code --Till Brychcy, Techn. Univ. Muenchen + * and Lee Hetherington, MIT + * 4/1994 Added DPS support, bounding box + * --Ricardo Telichevesky + * and Luis Miguel Silveira, MIT RLE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +extern "C" { +#include "dvi.h" +} + +#include "../kviewshell/pageSize.h" +#include "dviFile.h" +#include "fontpool.h" +#include "xdvi.h" + + +dvifile::dvifile(const dvifile *old, fontPool *fp) +{ + errorMsg = QString::null; + errorCounter = 0; + page_offset = 0; + suggestedPageSize = 0; + numberOfExternalPSFiles = 0; + numberOfExternalNONPSFiles = 0; + sourceSpecialMarker = old->sourceSpecialMarker; + + dviData = old->dviData.copy(); + + filename = old->filename; + size_of_file = old->size_of_file; + end_pointer = dvi_Data()+size_of_file; + if (dvi_Data() == 0) { + kdError(4300) << "Not enough memory to copy the DVI-file." << endl; + return; + } + + font_pool = fp; + filename = old->filename; + generatorString = old->generatorString; + total_pages = old->total_pages; + + + tn_table.clear(); + process_preamble(); + find_postamble(); + read_postamble(); + prepare_pages(); +} + + +void dvifile::process_preamble() +{ + command_pointer = dvi_Data(); + + Q_UINT8 magic_number = readUINT8(); + if (magic_number != PRE) { + errorMsg = i18n("The DVI file does not start with the preamble."); + return; + } + magic_number = readUINT8(); + if (magic_number != 2) { + errorMsg = i18n("The DVI file contains the wrong version of DVI output for this program. " + "Hint: If you use the typesetting system Omega, you have to use a special " + "program, such as oxdvi."); + return; + } + + /** numerator, denominator and the magnification value that describe + how many centimeters there are in one TeX unit, as explained in + section A.3 of the DVI driver standard, Level 0, published by + the TUG DVI driver standards committee. */ + Q_UINT32 numerator = readUINT32(); + Q_UINT32 denominator = readUINT32(); + _magnification = readUINT32(); + + cmPerDVIunit = (double(numerator) / double(denominator)) * (double(_magnification) / 1000.0) * (1.0 / 1e5); + + + // Read the generatorString (such as "TeX output ..." from the + // DVI-File). The variable "magic_number" holds the length of the + // string. + char job_id[300]; + magic_number = readUINT8(); + strncpy(job_id, (char *)command_pointer, magic_number); + job_id[magic_number] = '\0'; + generatorString = job_id; +} + + +/** find_postamble locates the beginning of the postamble and leaves + the file ready to start reading at that location. */ + +void dvifile::find_postamble() +{ + // Move backwards through the TRAILER bytes + command_pointer = dvi_Data() + size_of_file - 1; + while((*command_pointer == TRAILER) && (command_pointer > dvi_Data())) + command_pointer--; + if (command_pointer == dvi_Data()) { + errorMsg = i18n("The DVI file is badly corrupted. KDVI was not able to find the postamble."); + return; + } + + // And this is finally the pointer to the beginning of the postamble + command_pointer -= 4; + beginning_of_postamble = readUINT32(); + command_pointer = dvi_Data() + beginning_of_postamble; +} + + +void dvifile::read_postamble() +{ + Q_UINT8 magic_byte = readUINT8(); + if (magic_byte != POST) { + errorMsg = i18n("The postamble does not begin with the POST command."); + return; + } + last_page_offset = readUINT32(); + + // Skip the numerator, denominator and magnification, the largest + // box height and width and the maximal depth of the stack. These + // are not used at the moment. + command_pointer += 4 + 4 + 4 + 4 + 4 + 2; + + // The number of pages is more interesting for us. + total_pages = readUINT16(); + + // As a next step, read the font definitions. + Q_UINT8 cmnd = readUINT8(); + while (cmnd >= FNTDEF1 && cmnd <= FNTDEF4) { + Q_UINT32 TeXnumber = readUINT(cmnd-FNTDEF1+1); + Q_UINT32 checksum = readUINT32(); // Checksum of the font, as found by TeX in the TFM file + + // Read scale and design factor, and the name of the font. All + // these are explained in section A.4 of the DVI driver standard, + // Level 0, published by the TUG DVI driver standards committee + Q_UINT32 scale = readUINT32(); + Q_UINT32 design = readUINT32(); + Q_UINT16 len = readUINT8() + readUINT8(); // Length of the font name, including the directory name + char *fontname = new char[len + 1]; + strncpy(fontname, (char *)command_pointer, len ); + fontname[len] = '\0'; + command_pointer += len; + +#ifdef DEBUG_FONTS + kdDebug(4300) << "Postamble: define font \"" << fontname << "\" scale=" << scale << " design=" << design << endl; +#endif + + // According to section A.4 of the DVI driver standard, this font + // shall be enlarged by the following factor before it is used. + double enlargement_factor = (double(scale) * double(_magnification))/(double(design) * 1000.0); + + if (font_pool != 0) { + TeXFontDefinition *fontp = font_pool->appendx(fontname, checksum, scale, enlargement_factor); + + // Insert font in dictionary and make sure the dictionary is big + // enough. + if (tn_table.size()-2 <= tn_table.count()) + // Not quite optimal. The size of the dictionary should be a + // prime for optimal performance. I don't care. + tn_table.resize(tn_table.size()*2); + tn_table.insert(TeXnumber, fontp); + } + + // Read the next command + cmnd = readUINT8(); + } + + if (cmnd != POSTPOST) { + errorMsg = i18n("The postamble contained a command other than FNTDEF."); + return; + } + + // Now we remove all those fonts from the memory which are no longer + // in use. + if (font_pool != 0) + font_pool->release_fonts(); +} + + +void dvifile::prepare_pages() +{ +#ifdef DEBUG_DVIFILE + kdDebug(4300) << "prepare_pages" << endl; +#endif + + if (page_offset.resize(total_pages+1) == false) { + kdError(4300) << "No memory for page list!" << endl; + return; + } + for(int i=0; i<=total_pages; i++) + page_offset[i] = 0; + + + page_offset[total_pages] = beginning_of_postamble; + Q_UINT16 i = total_pages-1; + page_offset[i] = last_page_offset; + + // Follow back pointers through pages in the DVI file, storing the + // offsets in the page_offset table. + while (i > 0) { + command_pointer = dvi_Data() + page_offset[i--]; + if (readUINT8() != BOP) { + errorMsg = i18n("The page %1 does not start with the BOP command.").arg(i+1); + return; + } + command_pointer += 10 * 4; + page_offset[i] = readUINT32(); + if ((dvi_Data()+page_offset[i] < dvi_Data())||(dvi_Data()+page_offset[i] > dvi_Data()+size_of_file)) + break; + } +} + + +dvifile::dvifile(const QString& fname, fontPool* pool) +{ +#ifdef DEBUG_DVIFILE + kdDebug(4300) << "init_dvi_file: " << fname << endl; +#endif + + errorMsg = QString::null; + errorCounter = 0; + page_offset = 0; + suggestedPageSize = 0; + numberOfExternalPSFiles = 0; + numberOfExternalNONPSFiles = 0; + font_pool = pool; + sourceSpecialMarker = true; + + QFile file(fname); + filename = file.name(); + file.open( IO_ReadOnly ); + size_of_file = file.size(); + dviData.resize(size_of_file); + // Sets the end pointer for the bigEndianByteReader so that the + // whole memory buffer is readable + end_pointer = dvi_Data()+size_of_file; + if (dvi_Data() == 0) { + kdError() << i18n("Not enough memory to load the DVI-file."); + return; + } + file.readBlock((char *)dvi_Data(), size_of_file); + file.close(); + if (file.status() != IO_Ok) { + kdError() << i18n("Could not load the DVI-file."); + return; + } + + tn_table.clear(); + + process_preamble(); + find_postamble(); + read_postamble(); + prepare_pages(); + + return; +} + + +dvifile::~dvifile() +{ +#ifdef DEBUG_DVIFILE + kdDebug(4300) << "destroy dvi-file" << endl; +#endif + + // Delete converted PDF files + QMap::Iterator it; + for ( it = convertedFiles.begin(); it != convertedFiles.end(); ++it ) + QFile::remove(it.data()); + + if (suggestedPageSize != 0) + delete suggestedPageSize; + if (font_pool != 0) + font_pool->mark_fonts_as_unused(); +} + + +void dvifile::renumber() +{ + dviData.detach(); + + // Write the page number to the file, taking good care of byte + // orderings. + int wordSize; + bool bigEndian; + qSysInfo (&wordSize, &bigEndian); + + for(Q_UINT32 i=1; i<=total_pages; i++) { + Q_UINT8 *ptr = dviData.data() + page_offset[i-1]+1; + Q_UINT8 *num = (Q_UINT8 *)&i; + for(Q_UINT8 j=0; j<4; j++) + if (bigEndian) { + *(ptr++) = num[0]; + *(ptr++) = num[1]; + *(ptr++) = num[2]; + *(ptr++) = num[3]; + } else { + *(ptr++) = num[3]; + *(ptr++) = num[2]; + *(ptr++) = num[1]; + *(ptr++) = num[0]; + } + } +} + + +QString dvifile::convertPDFtoPS(const QString &PDFFilename) +{ + // Check if the PDFFile is known + QMap::Iterator it = convertedFiles.find(PDFFilename); + if (it != convertedFiles.end()) { + // PDF-File is known. Good. + return it.data(); + } + + // Get the name of a temporary file + KTempFile tmpfile(QString::null, ".ps"); + QString convertedFileName = tmpfile.name(); + tmpfile.close(); + tmpfile.unlink(); + + // Use pdf2ps to do the conversion + KProcIO proc; + proc << "pdf2ps" << PDFFilename << convertedFileName; + if (proc.start(KProcess::Block) == false) + convertedFileName = QString::null; // Indicates that conversion failed, won't try again. + if (!QFile::exists(convertedFileName)) + convertedFileName = QString::null; // Indicates that conversion failed, won't try again. + + // Save name of converted file to buffer, so PDF file won't be + // converted again, and files can be deleted when *this is + // deconstructed. + convertedFiles[PDFFilename] = convertedFileName; + + return convertedFileName; +} + + +bool dvifile::saveAs(const QString &filename) +{ + if (dvi_Data() == 0) + return false; + + QFile out(filename); + if (out.open( IO_Raw|IO_WriteOnly ) == false) + return false; + if (out.writeBlock ( (char *)(dvi_Data()), size_of_file ) == -1) + return false; + out.close(); + return true; +} diff --git a/kdvi/dviFile.h b/kdvi/dviFile.h new file mode 100644 index 00000000..069ae6d9 --- /dev/null +++ b/kdvi/dviFile.h @@ -0,0 +1,150 @@ +// -*- C++ -*- +// +// Class: dviFile +// +// Class that represents a DVI file. Part of KDVI - A DVI previewing +// plugin for kviewshell. +// +// (C) 2004--2005 Stefan Kebekus. Distributed under the GPL. +// + +#ifndef _DVIFILE_H +#define _DVIFILE_H + +#include "bigEndianByteReader.h" + +#include +#include +#include +#include + +class fontPool; +class pageSize; +class TeXFontDefinition; + + +class dvifile : public bigEndianByteReader +{ + public: + /** Makes a deep copy of the old DVI file. */ + dvifile(const dvifile *old, fontPool *fp ); + dvifile(const QString& fname, class fontPool* pool); + + ~dvifile(); + + fontPool * font_pool; + QString filename; + QString generatorString; + Q_UINT16 total_pages; + QMemArray page_offset; + + /** Saves the DVI file. Returns true on success. */ + bool saveAs(const QString &filename); + + // Returns a pointer to the DVI file's data, or 0 if no data has yet + // been allocated. + Q_UINT8 * dvi_Data() {return dviData.data();} + + QIODevice::Offset size_of_file; + QString errorMsg; + + /** This field is set to zero when the DVI file is constructed, and + will be modified during the prescan phase (at this time the + prescan code still resides in the dviRenderer class) */ + Q_UINT16 numberOfExternalPSFiles; + + /** This field is set to zero when the DVI file is constructed, and + will be modified during the prescan phase (at this time the + prescan code still resides in the dviRenderer class) */ + Q_UINT16 numberOfExternalNONPSFiles; + + Q_UINT32 beginning_of_postamble; + + /** This flag is set to "true" during the construction of the + dvifile, and is never changed afterwards by the dvifile + class. It is used in kdvi in conjuction with source-specials: + the first time a page with source specials is rendered, KDVI + shows an info dialog, and the flag is set to false. That way + KDVI ensures that the user is only informed once. */ + bool sourceSpecialMarker; + + QIntDict tn_table; + + /** Returns the number of centimeters per DVI unit in this DVI + file. */ + double getCmPerDVIunit() const {return cmPerDVIunit;} + + /** Returns the magnification of the DVI file, as described in the + DVI Standard. */ + Q_UINT32 getMagnification() const {return _magnification;} + + /** This member is set to zero on construction and can be used by + other software to count error messages that were printed when + the DVI-file was processed. Suggested application: limit the + number of error messages to, say, 25. */ + Q_UINT8 errorCounter; + + /** Papersize information read from the dvi-File */ + pageSize *suggestedPageSize; + + /** Sets new DVI data; all old data is erased. EXPERIMENTAL, use + with care. */ + void setNewData(const QMemArray& newData) {dviData = newData;} + + /** Page numbers that appear in a DVI document need not be + ordered. Worse, page numbers need not be unique. This method + renumbers the pages. */ + void renumber(); + + /** PDF to PS file conversion + + This utility method takes the name of a PDF-file, and attempts to + convert it to a PS file. The dvifile internally keeps a list of + converted files, to do two thigs: + + - convert files only once. + + - delete all converted files on destruction + + @warning The internal buffer can lead to difficulties if filenames + of PDF-files are not unique: if the content of a PDF file is + changed and this method is called a second time with the same file + name, the method will then NOT convert the file, but simply return + the name from the buffer + + @returns The name of the PS file, or QString::null on failure. + */ + QString convertPDFtoPS(const QString &PDFFilename); + + private: + /** process_preamble reads the information in the preamble and + stores it into global variables for later use. */ + void process_preamble(); + void find_postamble(); + /** read_postamble reads the information in the postamble, storing + it into global variables. It also takes care of reading in all + of the pixel files for the fonts used in the job. */ + void read_postamble(); + void prepare_pages(); + + + /** Offset in DVI file of last page, set in read_postamble(). */ + Q_UINT32 last_page_offset; + Q_UINT32 _magnification; + + double cmPerDVIunit; + + QMemArray dviData; + + + /** Map of filenames for converted PDF files + + This map contains names of PDF files that were converted to + PostScript. The key is the name of the PDF file, the data the name + of the associated PS file, or QString::null, if the file could not + be converted. The PS files are deleted when the DVI-file is + destructed. */ + QMap convertedFiles; +}; + +#endif //ifndef _DVIFILE_H diff --git a/kdvi/dviPageCache.cpp b/kdvi/dviPageCache.cpp new file mode 100644 index 00000000..2a2b8a30 --- /dev/null +++ b/kdvi/dviPageCache.cpp @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2005 by Wilfried Huss * + * Wilfried.Huss@gmx.at * + * * + * 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 + +#include + +#include "dviPageCache.h" +#include "renderedDviPagePixmap.h" + +DVIPageCache::DVIPageCache() + : DocumentPageCache() +{ +} + +DVIPageCache::~DVIPageCache() +{ +} + +RenderedDocumentPagePixmap* DVIPageCache::createDocumentPagePixmap() const +{ + return new RenderedDviPagePixmap(); +} + +#include "dviPageCache.moc" diff --git a/kdvi/dviPageCache.h b/kdvi/dviPageCache.h new file mode 100644 index 00000000..a28052c5 --- /dev/null +++ b/kdvi/dviPageCache.h @@ -0,0 +1,40 @@ +// -*- C++ -*- +/*************************************************************************** + * Copyright (C) 2005 by Wilfried Huss * + * Wilfried.Huss@gmx.at * + * * + * 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 _DVIPAGECACHE_H_ +#define _DVIPAGECACHE_H_ + +#include "documentPageCache.h" + +class DVIPageCache : public DocumentPageCache +{ + Q_OBJECT + + public: + DVIPageCache(); + + virtual ~DVIPageCache(); + + private: + virtual RenderedDocumentPagePixmap* createDocumentPagePixmap() const; +}; + +#endif diff --git a/kdvi/dviRenderer.cpp b/kdvi/dviRenderer.cpp new file mode 100644 index 00000000..b9bf6256 --- /dev/null +++ b/kdvi/dviRenderer.cpp @@ -0,0 +1,839 @@ +// +// Class: dviRenderer +// +// Class for rendering TeX DVI files. +// Part of KDVI- A previewer for TeX DVI files. +// +// (C) 2001-2005 Stefan Kebekus +// Distributed under the GPL +// + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "documentWidget.h" +#include "dviFile.h" +#include "dviRenderer.h" +#include "fontpool.h" +#include "fontprogress.h" +#include "hyperlink.h" +#include "infodialog.h" +#include "kdvi_multipage.h" +#include "performanceMeasurement.h" +#include "prebookmark.h" +#include "psgs.h" +#include "xdvi.h" +#include "zoomlimits.h" +#include "dvisourcesplitter.h" +#include "renderedDviPagePixmap.h" + +//#define DEBUG_DVIRENDERER + +QPainter *foreGroundPainter; // QPainter used for text + + +//------ now comes the dviRenderer class implementation ---------- + +dviRenderer::dviRenderer(QWidget *par) + : DocumentRenderer(par), info(new infoDialog(par)) +{ +#ifdef DEBUG_DVIRENDERER + kdDebug(4300) << "dviRenderer( parent=" << par << " )" << endl; +#endif + + // initialize the dvi machinery + dviFile = 0; + + connect(&font_pool, SIGNAL( setStatusBarText( const QString& ) ), this, SIGNAL( setStatusBarText( const QString& ) ) ); + + parentWidget = par; + shrinkfactor = 3; + current_page = 0; + resolutionInDPI = 0.0; + + connect( &clearStatusBarTimer, SIGNAL(timeout()), this, SLOT(clearStatusBar()) ); + + currentlyDrawnPage = 0; + editorCommand = ""; + + PostScriptOutPutString = NULL; + HTML_href = NULL; + _postscript = 0; + + // Storage used for dvips and friends, i.e. for the "export" functions. + proc = 0; + progress = 0; + export_printer = 0; + export_fileName = ""; + export_tmpFileName = ""; + export_errorString = ""; + + PS_interface = new ghostscript_interface(); + // pass status bar messages through + connect(PS_interface, SIGNAL( setStatusBarText( const QString& ) ), this, SIGNAL( setStatusBarText( const QString& ) ) ); +} + + +dviRenderer::~dviRenderer() +{ +#ifdef DEBUG_DVIRENDERER + kdDebug(4300) << "~dviRenderer" << endl; +#endif + + mutex.lock(); + mutex.unlock(); + + delete PS_interface; + delete proc; + delete dviFile; + // Don't delete the export printer. This is owned by the + // kdvi_multipage. + export_printer = 0; +} + + +void dviRenderer::setPrefs(bool flag_showPS, const QString &str_editorCommand, bool useFontHints ) +{ + QMutexLocker locker(&mutex); + _postscript = flag_showPS; + editorCommand = str_editorCommand; + font_pool.setParameters( useFontHints ); + emit(documentIsChanged()); +} + + +void dviRenderer::showInfo() +{ + mutex.lock(); + info->setDVIData(dviFile); + info->show(); + mutex.unlock(); +} + + +//------ this function calls the dvi interpreter ---------- + + +void dviRenderer::drawPage(double resolution, RenderedDocumentPage *page) +{ +#ifdef DEBUG_DVIRENDERER + kdDebug(4300) << "dviRenderer::drawPage(documentPage *) called, page number " << page->getPageNumber() << endl; +#endif + + // Paranoid safety checks + if (page == 0) { + kdError(4300) << "dviRenderer::drawPage(documentPage *) called with argument == 0" << endl; + return; + } + if (page->getPageNumber() == 0) { + kdError(4300) << "dviRenderer::drawPage(documentPage *) called for a documentPage with page number 0" << endl; + return; + } + + mutex.lock(); + if ( dviFile == 0 ) { + kdError(4300) << "dviRenderer::drawPage(documentPage *) called, but no dviFile class allocated." << endl; + page->clear(); + mutex.unlock(); + return; + } + if (page->getPageNumber() > dviFile->total_pages) { + kdError(4300) << "dviRenderer::drawPage(documentPage *) called for a documentPage with page number " << page->getPageNumber() + << " but the current dviFile has only " << dviFile->total_pages << " pages." << endl; + mutex.unlock(); + return; + } + if ( dviFile->dvi_Data() == 0 ) { + kdError(4300) << "dviRenderer::drawPage(documentPage *) called, but no dviFile is loaded yet." << endl; + page->clear(); + mutex.unlock(); + return; + } + + if (resolution != resolutionInDPI) + setResolution(resolution); + + currentlyDrawnPage = page; + shrinkfactor = 1200/resolutionInDPI; + current_page = page->getPageNumber()-1; + + + // Reset colors + colorStack.clear(); + globalColor = Qt::black; + + QApplication::setOverrideCursor( waitCursor ); + foreGroundPainter = page->getPainter(); + if (foreGroundPainter != 0) { + errorMsg = QString::null; + draw_page(); + page->returnPainter(foreGroundPainter); + } + QApplication::restoreOverrideCursor(); + + page->isEmpty = false; + if (errorMsg.isEmpty() != true) { + KMessageBox::detailedError(parentWidget, + i18n("File corruption! KDVI had trouble interpreting your DVI file. Most " + "likely this means that the DVI file is broken."), + errorMsg, i18n("DVI File Error")); + errorMsg = QString::null; + currentlyDrawnPage = 0; + mutex.unlock(); + return; + } + + // Tell the user (once) if the DVI file contains source specials + // ... we don't want our great feature to go unnoticed. + RenderedDviPagePixmap* currentDVIPage = dynamic_cast(currentlyDrawnPage); + if (currentDVIPage) + { + if ((dviFile->sourceSpecialMarker == true) && (currentDVIPage->sourceHyperLinkList.size() > 0)) { + dviFile->sourceSpecialMarker = false; + // Show the dialog as soon as event processing is finished, and + // the program is idle + QTimer::singleShot( 0, this, SLOT(showThatSourceInformationIsPresent()) ); + } + } + + currentlyDrawnPage = 0; + mutex.unlock(); +} + + +void dviRenderer::getText(RenderedDocumentPage* page) +{ + bool postscriptBackup = _postscript; + // Disable postscript-specials temporarely to speed up text extraction. + _postscript = false; + + drawPage(100.0, page); + + _postscript = postscriptBackup; +} + + +void dviRenderer::showThatSourceInformationIsPresent() +{ + // In principle, we should use a KMessagebox here, but we want to + // add a button "Explain in more detail..." which opens the + // Helpcenter. Thus, we practically re-implement the KMessagebox + // here. Most of the code is stolen from there. + + // Check if the 'Don't show again' feature was used + KConfig *config = kapp->config(); + KConfigGroupSaver saver( config, "Notification Messages" ); + bool showMsg = config->readBoolEntry( "KDVI-info_on_source_specials", true); + + if (showMsg) { + KDialogBase *dialog= new KDialogBase(i18n("KDVI: Information"), KDialogBase::Yes, KDialogBase::Yes, KDialogBase::Yes, + parentWidget, "information", true, true,KStdGuiItem::ok() ); + + QVBox *topcontents = new QVBox (dialog); + topcontents->setSpacing(KDialog::spacingHint()*2); + topcontents->setMargin(KDialog::marginHint()*2); + + QWidget *contents = new QWidget(topcontents); + QHBoxLayout * lay = new QHBoxLayout(contents); + lay->setSpacing(KDialog::spacingHint()*2); + + lay->addStretch(1); + QLabel *label1 = new QLabel( contents); + label1->setPixmap(QMessageBox::standardIcon(QMessageBox::Information)); + lay->add( label1 ); + QLabel *label2 = new QLabel( i18n("This DVI file contains source file information. You may click into the text with the " + "middle mouse button, and an editor will open the TeX-source file immediately."), + contents); + label2->setMinimumSize(label2->sizeHint()); + lay->add( label2 ); + lay->addStretch(1); + QSize extraSize = QSize(50,30); + QCheckBox *checkbox = new QCheckBox(i18n("Do not show this message again"), topcontents); + extraSize = QSize(50,0); + dialog->setHelpLinkText(i18n("Explain in more detail...")); + dialog->setHelp("inverse-search", "kdvi"); + dialog->enableLinkedHelp(true); + dialog->setMainWidget(topcontents); + dialog->enableButtonSeparator(false); + dialog->incInitialSize( extraSize ); + dialog->exec(); + delete dialog; + + showMsg = !checkbox->isChecked(); + if (!showMsg) { + KConfigGroupSaver saver( config, "Notification Messages" ); + config->writeEntry( "KDVI-info_on_source_specials", showMsg); + } + config->sync(); + } +} + + +void dviRenderer::embedPostScript() +{ +#ifdef DEBUG_DVIRENDERER + kdDebug(4300) << "dviRenderer::embedPostScript()" << endl; +#endif + + if (!dviFile) + return; + + embedPS_progress = new KProgressDialog(parentWidget, "embedPSProgressDialog", + i18n("Embedding PostScript Files"), QString::null, true); + if (!embedPS_progress) + return; + embedPS_progress->setAllowCancel(false); + embedPS_progress->showCancelButton(false); + embedPS_progress->setMinimumDuration(400); + embedPS_progress->progressBar()->setTotalSteps(dviFile->numberOfExternalPSFiles); + embedPS_progress->progressBar()->setProgress(0); + embedPS_numOfProgressedFiles = 0; + + + Q_UINT16 currPageSav = current_page; + errorMsg = QString::null; + for(current_page=0; current_page < dviFile->total_pages; current_page++) { + if (current_page < dviFile->total_pages) { + command_pointer = dviFile->dvi_Data() + dviFile->page_offset[current_page]; + end_pointer = dviFile->dvi_Data() + dviFile->page_offset[current_page+1]; + } else + command_pointer = end_pointer = 0; + + memset((char *) &currinf.data, 0, sizeof(currinf.data)); + currinf.fonttable = &(dviFile->tn_table); + currinf._virtual = NULL; + prescan(&dviRenderer::prescan_embedPS); + } + + delete embedPS_progress; + + if (!errorMsg.isEmpty()) { + errorMsg = "" + errorMsg + ""; + KMessageBox::detailedError(parentWidget, "" + i18n("Not all PostScript files could be embedded into your document.") + "", errorMsg); + errorMsg = QString::null; + } else + KMessageBox::information(parentWidget, "" + i18n("All external PostScript files were embedded into your document. You " + "will probably want to save the DVI file now.") + "", + QString::null, "embeddingDone"); + + // Prescan phase starts here +#ifdef PERFORMANCE_MEASUREMENT + kdDebug(4300) << "Time elapsed till prescan phase starts " << performanceTimer.elapsed() << "ms" << endl; + QTime preScanTimer; + preScanTimer.start(); +#endif + dviFile->numberOfExternalPSFiles = 0; + prebookmarks.clear(); + for(current_page=0; current_page < dviFile->total_pages; current_page++) { + PostScriptOutPutString = new QString(); + + if (current_page < dviFile->total_pages) { + command_pointer = dviFile->dvi_Data() + dviFile->page_offset[current_page]; + end_pointer = dviFile->dvi_Data() + dviFile->page_offset[current_page+1]; + } else + command_pointer = end_pointer = 0; + + memset((char *) &currinf.data, 0, sizeof(currinf.data)); + currinf.fonttable = &(dviFile->tn_table); + currinf._virtual = NULL; + + prescan(&dviRenderer::prescan_parseSpecials); + + if (!PostScriptOutPutString->isEmpty()) + PS_interface->setPostScript(current_page, *PostScriptOutPutString); + delete PostScriptOutPutString; + } + PostScriptOutPutString = NULL; + + +#ifdef PERFORMANCE_MEASUREMENT + kdDebug(4300) << "Time required for prescan phase: " << preScanTimer.restart() << "ms" << endl; +#endif + current_page = currPageSav; + _isModified = true; +} + + +bool dviRenderer::isValidFile(const QString& filename) const +{ + QFile f(filename); + if (!f.open(IO_ReadOnly)) + return false; + + unsigned char test[4]; + if ( f.readBlock( (char *)test,2)<2 || test[0] != 247 || test[1] != 2 ) + return false; + + int n = f.size(); + if ( n < 134 ) // Too short for a dvi file + return false; + f.at( n-4 ); + + unsigned char trailer[4] = { 0xdf,0xdf,0xdf,0xdf }; + + if ( f.readBlock( (char *)test, 4 )<4 || strncmp( (char *)test, (char *) trailer, 4 ) ) + return false; + // We suppose now that the dvi file is complete and OK + return true; +} + + +bool dviRenderer::setFile(const QString &fname, const KURL &base) +{ +#ifdef DEBUG_DVIRENDERER + kdDebug(4300) << "dviRenderer::setFile( fname='" << fname << "', ref='" << ref << "', sourceMarker=" << sourceMarker << " )" << endl; +#endif + + QMutexLocker lock(&mutex); + + QFileInfo fi(fname); + QString filename = fi.absFilePath(); + + // If fname is the empty string, then this means: "close". Delete + // the dvifile and the pixmap. + if (fname.isEmpty()) { + // Delete DVI file + info->setDVIData(0); + delete dviFile; + dviFile = 0; + return true; + } + + + // Make sure the file actually exists. + if (!fi.exists() || fi.isDir()) { + KMessageBox::error( parentWidget, + i18n("File error. The specified file '%1' does not exist. " + "KDVI already tried to add the ending '.dvi'.").arg(filename), + i18n("File Error!")); + return false; + } + + // Check if we are really loading a DVI file, and complain about the + // mime type, if the file is not DVI. Perhaps we should move the + // procedure later to the kviewpart, instead of the implementaton in + // the multipage. + QString mimetype( KMimeMagic::self()->findFileType( fname )->mimeType() ); + if (mimetype != "application/x-dvi") { + KMessageBox::sorry( parentWidget, + i18n( "Could not open file %1 which has " + "type %2. KDVI can only load DVI (.dvi) files." ) + .arg( fname ) + .arg( mimetype ) ); + return false; + } + + // Check if the file is a valid DVI file. + if (!isValidFile(filename)) + { + KMessageBox::sorry( parentWidget, + i18n("File corruption! KDVI had trouble interpreting your DVI file. Most " + "likely this means that the DVI file is broken.") + .arg( fname ) ); + return false; + } + + QApplication::setOverrideCursor( waitCursor ); + dvifile *dviFile_new = new dvifile(filename, &font_pool); + + if ((dviFile == 0) || (dviFile->filename != filename)) + dviFile_new->sourceSpecialMarker = true; + else + dviFile_new->sourceSpecialMarker = false; + + if ((dviFile_new->dvi_Data() == NULL)||(dviFile_new->errorMsg.isEmpty() != true)) { + QApplication::restoreOverrideCursor(); + if (dviFile_new->errorMsg.isEmpty() != true) + KMessageBox::detailedError(parentWidget, + i18n("File corruption! KDVI had trouble interpreting your DVI file. Most " + "likely this means that the DVI file is broken."), + dviFile_new->errorMsg, i18n("DVI File Error")); + delete dviFile_new; + return false; + } + + delete dviFile; + dviFile = dviFile_new; + numPages = dviFile->total_pages; + info->setDVIData(dviFile); + _isModified = false; + baseURL = base; + + font_pool.setExtraSearchPath( fi.dirPath(true) ); + font_pool.setCMperDVIunit( dviFile->getCmPerDVIunit() ); + + // Extract PostScript from the DVI file, and store the PostScript + // specials in PostScriptDirectory, and the headers in the + // PostScriptHeaderString. + PS_interface->clear(); + + // If the DVI file comes from a remote URL (e.g. downloaded from a + // web server), we limit the PostScript files that can be accessed + // by this file to the download directory, in order to limit the + // possibilities of a denial of service attack. + QString includePath; + if (!baseURL.isLocalFile()) { + includePath = filename; + includePath.truncate(includePath.findRev('/')); + } + PS_interface->setIncludePath(includePath); + + // We will also generate a list of hyperlink-anchors and source-file + // anchors in the document. So declare the existing lists empty. + anchorList.clear(); + sourceHyperLinkAnchors.clear(); + bookmarks.clear(); + prebookmarks.clear(); + + if (dviFile->page_offset.isEmpty() == true) + return false; + + // Locate fonts. + font_pool.locateFonts(); + + // Update the list of fonts in the info window + if (info != 0) + info->setFontInfo(&font_pool); + + // We should pre-scan the document now (to extract embedded, + // PostScript, Hyperlinks, ets). + + // PRESCAN STARTS HERE +#ifdef PERFORMANCE_MEASUREMENT + kdDebug(4300) << "Time elapsed till prescan phase starts " << performanceTimer.elapsed() << "ms" << endl; + QTime preScanTimer; + preScanTimer.start(); +#endif + dviFile->numberOfExternalPSFiles = 0; + Q_UINT16 currPageSav = current_page; + prebookmarks.clear(); + + for(current_page=0; current_page < dviFile->total_pages; current_page++) { + PostScriptOutPutString = new QString(); + + if (current_page < dviFile->total_pages) { + command_pointer = dviFile->dvi_Data() + dviFile->page_offset[current_page]; + end_pointer = dviFile->dvi_Data() + dviFile->page_offset[current_page+1]; + } else + command_pointer = end_pointer = 0; + + memset((char *) &currinf.data, 0, sizeof(currinf.data)); + currinf.fonttable = &(dviFile->tn_table); + currinf._virtual = NULL; + prescan(&dviRenderer::prescan_parseSpecials); + + if (!PostScriptOutPutString->isEmpty()) + PS_interface->setPostScript(current_page, *PostScriptOutPutString); + delete PostScriptOutPutString; + } + PostScriptOutPutString = NULL; + + // Generate the list of bookmarks + bookmarks.clear(); + QPtrStack stack; + stack.setAutoDelete (false); + QValueVector::iterator it; + for( it = prebookmarks.begin(); it != prebookmarks.end(); ++it ) { + Bookmark *bmk = new Bookmark((*it).title, findAnchor((*it).anchorName)); + if (stack.isEmpty()) + bookmarks.append(bmk); + else { + stack.top()->subordinateBookmarks.append(bmk); + stack.remove(); + } + for(int i=0; i<(*it).noOfChildren; i++) + stack.push(bmk); + } + prebookmarks.clear(); + + +#ifdef PERFORMANCE_MEASUREMENT + kdDebug(4300) << "Time required for prescan phase: " << preScanTimer.restart() << "ms" << endl; +#endif + current_page = currPageSav; + // PRESCAN ENDS HERE + + + pageSizes.resize(0); + if (dviFile->suggestedPageSize != 0) { + // Fill the vector pageSizes with total_pages identical entries + pageSizes.resize(dviFile->total_pages, *(dviFile->suggestedPageSize)); + } + + QApplication::restoreOverrideCursor(); + return true; +} + + +Anchor dviRenderer::parseReference(const QString &reference) +{ + mutex.lock(); + +#ifdef DEBUG_DVIRENDERER + kdError(4300) << "dviRenderer::parseReference( " << reference << " ) called" << endl; +#endif + + if (dviFile == 0) { + mutex.unlock(); + return Anchor(); + } + + // case 1: The reference is a number, which we'll interpret as a + // page number. + bool ok; + int page = reference.toInt ( &ok ); + if (ok == true) { + if (page < 0) + page = 0; + if (page > dviFile->total_pages) + page = dviFile->total_pages; + + mutex.unlock(); + return Anchor(page, Length() ); + } + + // case 2: The reference is of form "src:1111Filename", where "1111" + // points to line number 1111 in the file "Filename". KDVI then + // looks for source specials of the form "src:xxxxFilename", and + // tries to find the special with the biggest xxxx + if (reference.find("src:",0,false) == 0) { + + // Extract the file name and the numeral part from the reference string + DVI_SourceFileSplitter splitter(reference, dviFile->filename); + Q_UINT32 refLineNumber = splitter.line(); + QString refFileName = splitter.filePath(); + + if (sourceHyperLinkAnchors.isEmpty()) { + KMessageBox::sorry(parentWidget, i18n("You have asked KDVI to locate the place in the DVI file which corresponds to " + "line %1 in the TeX-file %2. It seems, however, that the DVI file " + "does not contain the necessary source file information. " + "We refer to the manual of KDVI for a detailed explanation on how to include this " + "information. Press the F1 key to open the manual.").arg(refLineNumber).arg(refFileName), + i18n("Could Not Find Reference")); + mutex.unlock(); + return Anchor(); + } + + // Go through the list of source file anchors, and find the anchor + // whose line number is the biggest among those that are smaller + // than the refLineNumber. That way, the position in the DVI file + // which is highlighted is always a little further up than the + // position in the editor, e.g. if the DVI file contains + // positional information at the beginning of every paragraph, + // KDVI jumps to the beginning of the paragraph that the cursor is + // in, and never to the next paragraph. If source file anchors for + // the refFileName can be found, but none of their line numbers is + // smaller than the refLineNumber, the reason is most likely, that + // the cursor in the editor stands somewhere in the preamble of + // the LaTeX file. In that case, we jump to the beginning of the + // document. + bool anchorForRefFileFound = false; // Flag that is set if source file anchors for the refFileName could be found at all + + QValueVector::iterator bestMatch = sourceHyperLinkAnchors.end(); + QValueVector::iterator it; + for( it = sourceHyperLinkAnchors.begin(); it != sourceHyperLinkAnchors.end(); ++it ) + if (refFileName.stripWhiteSpace() == it->fileName.stripWhiteSpace() + || refFileName.stripWhiteSpace() == it->fileName.stripWhiteSpace() + ".tex" + ) { + anchorForRefFileFound = true; + + if ( (it->line <= refLineNumber) && + ( (bestMatch == sourceHyperLinkAnchors.end()) || (it->line > bestMatch->line) ) ) + bestMatch = it; + } + + if (bestMatch != sourceHyperLinkAnchors.end()) { + mutex.unlock(); + return Anchor(bestMatch->page, bestMatch->distance_from_top); + } else + if (anchorForRefFileFound == false) + KMessageBox::sorry(parentWidget, i18n("KDVI was not able to locate the place in the DVI file which corresponds to " + "line %1 in the TeX-file %2.").arg(refLineNumber).arg(refFileName), + i18n( "Could Not Find Reference" )); + else { + mutex.unlock(); + return Anchor(); + } + mutex.unlock(); + return Anchor(); + } + mutex.unlock(); + return Anchor(); +} + + +void dviRenderer::setResolution(double resolution_in_DPI) +{ + // Ignore minute changes. The difference to the current value would + // hardly be visible anyway. That saves a lot of re-painting, + // e.g. when the user resizes the window, and a flickery mouse + // changes the window size by 1 pixel all the time. + if (fabs(resolutionInDPI-resolution_in_DPI) < 1) + return; + + resolutionInDPI = resolution_in_DPI; + + // Pass the information on to the font pool. + font_pool.setDisplayResolution( resolutionInDPI ); + shrinkfactor = 1200/resolutionInDPI; + return; +} + + +void dviRenderer::clearStatusBar() +{ + emit setStatusBarText( QString::null ); +} + + +void dviRenderer::handleSRCLink(const QString &linkText, QMouseEvent *e, DocumentWidget *win) +{ +#ifdef DEBUG_SPECIAL + RenderedDviPagePixmap* currentDVIPage = dynamic_cast currentlyDrawnPage; + if (currentDVIPage) + { + kdDebug(4300) << "Source hyperlink to " << currentDVIPage->sourceHyperLinkList[i].linkText << endl; + } +#endif + + DVI_SourceFileSplitter splitter(linkText, dviFile->filename); + QString TeXfile = splitter.filePath(); + if ( ! splitter.fileExists() ) + { + KMessageBox::sorry(parentWidget, QString("") + + i18n("The DVI-file refers to the TeX-file " + "%1 which could not be found.").arg(KShellProcess::quote(TeXfile)) + + QString(""), + i18n( "Could Not Find File" )); + return; + } + + QString command = editorCommand; + if (command.isEmpty() == true) { + int r = KMessageBox::warningContinueCancel(parentWidget, QString("") + + i18n("You have not yet specified an editor for inverse search. " + "Please choose your favorite editor in the " + "DVI options dialog " + "which you will find in the Settings-menu.") + + QString(""), + i18n("Need to Specify Editor"), + i18n("Use KDE's Editor Kate for Now")); + if (r == KMessageBox::Continue) + command = "kate %f"; + else + return; + } + command = command.replace( "%l", QString::number(splitter.line()) ).replace( "%f", KShellProcess::quote(TeXfile) ); + +#ifdef DEBUG_SPECIAL + kdDebug(4300) << "Calling program: " << command << endl; +#endif + + // There may still be another program running. Since we don't + // want to mix the output of several programs, we will + // henceforth dimiss the output of the older programm. "If it + // hasn't failed until now, we don't care." + if (proc != 0) { + qApp->disconnect(proc, SIGNAL(receivedStderr(KProcess *, char *, int)), 0, 0); + qApp->disconnect(proc, SIGNAL(receivedStdout(KProcess *, char *, int)), 0, 0); + proc = 0; + } + + // Set up a shell process with the editor command. + proc = new KShellProcess(); + if (proc == 0) { + kdError(4300) << "Could not allocate ShellProcess for the editor command." << endl; + return; + } + qApp->connect(proc, SIGNAL(receivedStderr(KProcess *, char *, int)), this, SLOT(dvips_output_receiver(KProcess *, char *, int))); + qApp->connect(proc, SIGNAL(receivedStdout(KProcess *, char *, int)), this, SLOT(dvips_output_receiver(KProcess *, char *, int))); + qApp->connect(proc, SIGNAL(processExited(KProcess *)), this, SLOT(editorCommand_terminated(KProcess *))); + // Merge the editor-specific editor message here. + export_errorString = i18n("The external program

%1

which was used to call the editor " + "for inverse search, reported an error. You might wish to look at the document info " + "dialog which you will find in the File-Menu for a precise error report. The " + "manual for KDVI contains a detailed explanation how to set up your editor for use with KDVI, " + "and a list of common problems.
").arg(command); + + info->clear(i18n("Starting the editor...")); + + int flashOffset = e->y(); // Heuristic correction. Looks better. + win->flash(flashOffset); + + + proc->clearArguments(); + *proc << command; + proc->closeStdin(); + if (proc->start(KProcess::NotifyOnExit, KProcess::AllOutput) == false) { + kdError(4300) << "Editor failed to start" << endl; + return; + } +} + + +QString dviRenderer::PDFencodingToQString(const QString& _pdfstring) +{ + // This method locates special PDF characters in a string and + // replaces them by UTF8. See Section 3.2.3 of the PDF reference + // guide for information. + QString pdfstring = _pdfstring; + pdfstring = pdfstring.replace("\\n", "\n"); + pdfstring = pdfstring.replace("\\r", "\n"); + pdfstring = pdfstring.replace("\\t", "\t"); + pdfstring = pdfstring.replace("\\f", "\f"); + pdfstring = pdfstring.replace("\\(", "("); + pdfstring = pdfstring.replace("\\)", ")"); + pdfstring = pdfstring.replace("\\\\", "\\"); + + // Now replace octal character codes with the characters they encode + int pos; + QRegExp rx( "(\\\\)(\\d\\d\\d)" ); // matches "\xyz" where x,y,z are numbers + while((pos = rx.search( pdfstring )) != -1) { + pdfstring = pdfstring.replace(pos, 4, QChar(rx.cap(2).toInt(0,8))); + } + rx.setPattern( "(\\\\)(\\d\\d)" ); // matches "\xy" where x,y are numbers + while((pos = rx.search( pdfstring )) != -1) { + pdfstring = pdfstring.replace(pos, 3, QChar(rx.cap(2).toInt(0,8))); + } + rx.setPattern( "(\\\\)(\\d)" ); // matches "\x" where x is a number + while((pos = rx.search( pdfstring )) != -1) { + pdfstring = pdfstring.replace(pos, 4, QChar(rx.cap(2).toInt(0,8))); + } + return pdfstring; +} + + +#include "dviRenderer.moc" diff --git a/kdvi/dviRenderer.h b/kdvi/dviRenderer.h new file mode 100644 index 00000000..98f0f4bd --- /dev/null +++ b/kdvi/dviRenderer.h @@ -0,0 +1,300 @@ +// -*- C++ -*- +// +// Class: dviRenderer +// +// Class for rendering TeX DVI files. +// Part of KDVI- A previewer for TeX DVI files. +// +// (C) 2001-2005 Stefan Kebekus. Distributed under the GPL. + +#ifndef _dvirenderer_h_ +#define _dvirenderer_h_ + +#include "bigEndianByteReader.h" +#include "documentRenderer.h" +#include "fontpool.h" + +#include +#include +#include +#include +#include +#include + +class Anchor; +class DocumentWidget; +class dviRenderer; +class fontProgressDialog; +class ghostscript_interface; +class infoDialog; +class KAction; +class KDVIMultiPage; +class KPrinter; +class KProcess; +class KProgressDialog; +class KShellProcess; +class PreBookmark; +class TeXFontDefinition; + +extern const int MFResolutions[]; + +class DVI_SourceFileAnchor { + public: + DVI_SourceFileAnchor() {} + DVI_SourceFileAnchor(const QString& name, Q_UINT32 ln, Q_UINT32 pg, const Length& _distance_from_top) + : fileName(name), line(ln), page(pg), + distance_from_top(_distance_from_top) {} + + QString fileName; + Q_UINT32 line; + Q_UINT32 page; + Length distance_from_top; +}; + +/** Compound of registers, as defined in section 2.6.2 of the DVI + driver standard, Level 0, published by the TUG DVI driver + standards committee. */ + +struct framedata { + long dvi_h; + long dvi_v; + long w; + long x; + long y; + long z; + int pxl_v; +}; + + +/* this information is saved when using virtual fonts */ + +typedef void (dviRenderer::*set_char_proc)(unsigned int, unsigned int); +typedef void (dviRenderer::*parseSpecials)(char *, Q_UINT8 *); + +struct drawinf { + struct framedata data; + TeXFontDefinition *fontp; + set_char_proc set_char_p; + + QIntDict *fonttable; + TeXFontDefinition *_virtual; +}; + + + +class dviRenderer : public DocumentRenderer, bigEndianByteReader +{ + Q_OBJECT + +public: + dviRenderer(QWidget *parent); + ~dviRenderer(); + + virtual bool setFile(const QString &fname, const KURL &base); + + class dvifile *dviFile; + + void setPrefs(bool flag_showPS, const QString &editorCommand, bool useFontHints ); + + virtual bool supportsTextSearch() const {return true;} + + bool showPS() { return _postscript; } + int curr_page() { return current_page+1; } + virtual bool isValidFile(const QString& fileName) const; + + + /** This method will try to parse the reference part of the DVI + file's URL, (either a number, which is supposed to be a page + number, or src:) and see if a corresponding + section of the DVI file can be found. If so, it returns an + anchor to that section. If not, it returns an invalid anchor. */ + virtual Anchor parseReference(const QString &reference); + + // These should not be public... only for the moment + void read_postamble(); + void draw_part(double current_dimconv, bool is_vfmacro); + void set_vf_char(unsigned int cmd, unsigned int ch); + void set_char(unsigned int cmd, unsigned int ch); + void set_empty_char(unsigned int cmd, unsigned int ch); + void set_no_char(unsigned int cmd, unsigned int ch); + void applicationDoSpecial(char * cp); + + void special(long nbytes); + void printErrorMsgForSpecials(const QString& msg); + void color_special(const QString& cp); + void html_href_special(const QString& cp); + void html_anchor_end(); + void draw_page(); + +public slots: + void exportPS(const QString& fname = QString::null, const QString& options = QString::null, KPrinter* printer = 0); + void exportPDF(); + + void showInfo(); + void handleSRCLink(const QString &linkText, QMouseEvent *e, DocumentWidget *widget); + + void embedPostScript(); + void abortExternalProgramm(); + + /** simply emits "setStatusBarText( QString::null )". This is used + in dviRenderer::mouseMoveEvent(), see the explanation there. */ + void clearStatusBar(); + + virtual void drawPage(double res, RenderedDocumentPage *page); + virtual void getText(RenderedDocumentPage* page); + + /** Slots used in conjunction with external programs */ + void dvips_output_receiver(KProcess *, char *buffer, int buflen); + void dvips_terminated(KProcess *); + void editorCommand_terminated(KProcess *); + +signals: + /** Passed through to the top-level kpart. */ + // void setStatusBarText( const QString& ); + +private slots: + /** This method shows a dialog that tells the user that source + information is present, and gives the opportunity to open the + manual and learn more about forward and inverse search */ + void showThatSourceInformationIsPresent(); + +private: + /** URL to the DVI file + + This field is initialized by the setFile() method. See the + explanation there. */ + KURL baseURL; + + + /** This method parses a color specification of type "gray 0.5", "rgb + 0.5 0.7 1.0", "hsb ...", "cmyk .." or "PineGreen". See the source + code for details. */ + QColor parseColorSpecification(const QString& colorSpec); + + /** This map contains the colors which are known by name. This field + is initialized in the method parseColorSpecification() as soon as + it is needed. */ + QMap namedColors; + + /* This method locates special PDF characters in a string and + replaces them by UTF8. See Section 3.2.3 of the PDF reference + guide for information */ + QString PDFencodingToQString(const QString& pdfstring); + + void setResolution(double resolution_in_DPI); + + fontPool font_pool; + infoDialog *info; + + double resolutionInDPI; + + // @@@ explanation + void prescan(parseSpecials specialParser); + void prescan_embedPS(char *cp, Q_UINT8 *); + void prescan_removePageSizeInfo(char *cp, Q_UINT8 *); + void prescan_parseSpecials(char *cp, Q_UINT8 *); + void prescan_ParsePapersizeSpecial(const QString& cp); + void prescan_ParseBackgroundSpecial(const QString& cp); + void prescan_ParseHTMLAnchorSpecial(const QString& cp); + void prescan_ParsePSHeaderSpecial(const QString& cp); + void prescan_ParsePSBangSpecial(const QString& cp); + void prescan_ParsePSQuoteSpecial(const QString& cp); + void prescan_ParsePSSpecial(const QString& cp); + void prescan_ParsePSFileSpecial(const QString& cp); + void prescan_ParseSourceSpecial(const QString& cp); + void prescan_setChar(unsigned int ch); + + /* */ + QValueVector prebookmarks; + + + + /** Utility fields used by the embedPostScript method*/ + KProgressDialog *embedPS_progress; + Q_UINT16 embedPS_numOfProgressedFiles; + + /** Shrink factor. Units are not quite clear */ + double shrinkfactor; + + QString errorMsg; + + /** Methods which handle certain special commands. */ + void epsf_special(const QString& cp); + void source_special(const QString& cp); + + /** TPIC specials */ + void TPIC_setPen_special(const QString& cp); + void TPIC_addPath_special(const QString& cp); + void TPIC_flushPath_special(); + + /** This timer is used to delay clearing of the statusbar. Clearing + the statusbar is delayed to avoid awful flickering when the + mouse moves over a block of text that contains source + hyperlinks. The signal timeout() is connected to the method + clearStatusBar() of *this. */ + QTimer clearStatusBarTimer; + + // List of source-hyperlinks on all pages. This vector is generated + // when the DVI-file is first loaded, i.e. when draw_part is called + // with PostScriptOutPutString != NULL + QValueVector sourceHyperLinkAnchors; + + // If not NULL, the text currently drawn represents a source + // hyperlink to the (relative) URL given in the string; + QString *source_href; + + // If not NULL, the text currently drawn represents a hyperlink to + // the (relative) URL given in the string; + QString *HTML_href; + + QString editorCommand; + + /** Stack for register compounds, used for the DVI-commands PUSH/POP + as explained in section 2.5 and 2.6.2 of the DVI driver standard, + Level 0, published by the TUG DVI driver standards committee. */ + QValueStack stack; + + /** A stack where color are stored, according to the documentation of + DVIPS */ + QValueStack colorStack; + + /** The global color is to be used when the color stack is empty */ + QColor globalColor; + + /** If PostScriptOutPutFile is non-zero, then no rendering takes + place. Instead, the PostScript code which is generated by the + \special-commands is written to the PostScriptString */ + QString *PostScriptOutPutString; + + ghostscript_interface *PS_interface; + + /** true, if gs should be used, otherwise, only bounding boxes are + drawn. */ + bool _postscript; + + /** This flag is used when rendering a dvi-page. It is set to "true" + when any dvi-command other than "set" or "put" series of commands + is encountered. This is considered to mark the end of a word. */ + bool line_boundary_encountered; + bool word_boundary_encountered; + + unsigned int current_page; + + /** Used to run and to show the progress of dvips and friends. */ + fontProgressDialog *progress; + KShellProcess *proc; + KPrinter *export_printer; + QString export_fileName; + QString export_tmpFileName; + QString export_errorString; + + /** Data required for handling TPIC specials */ + float penWidth_in_mInch; + QPointArray TPIC_path; + Q_UINT16 number_of_elements_in_path; + + struct drawinf currinf; + RenderedDocumentPage* currentlyDrawnPage; +}; + +#endif diff --git a/kdvi/dviRenderer_draw.cpp b/kdvi/dviRenderer_draw.cpp new file mode 100644 index 00000000..d09caf6d --- /dev/null +++ b/kdvi/dviRenderer_draw.cpp @@ -0,0 +1,660 @@ +/* + * Copyright (c) 1994 Paul Vojta. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * NOTE: + * xdvi is based on prior work as noted in the modification history, below. + */ + +/* + * DVI previewer for X. + * + * Eric Cooper, CMU, September 1985. + * + * Code derived from dvi-imagen.c. + * + * Modification history: + * 1/1986 Modified for X.10 --Bob Scheifler, MIT LCS. + * 7/1988 Modified for X.11 --Mark Eichin, MIT + * 12/1988 Added 'R' option, toolkit, magnifying glass + * --Paul Vojta, UC Berkeley. + * 2/1989 Added tpic support --Jeffrey Lee, U of Toronto + * 4/1989 Modified for System V --Donald Richardson, Clarkson Univ. + * 3/1990 Added VMS support --Scott Allendorf, U of Iowa + * 7/1990 Added reflection mode --Michael Pak, Hebrew U of Jerusalem + * 1/1992 Added greyscale code --Till Brychcy, Techn. Univ. Muenchen + * and Lee Hetherington, MIT + * 4/1994 Added DPS support, bounding box + * --Ricardo Telichevesky + * and Luis Miguel Silveira, MIT RLE. + */ + +//#define DEBUG_RENDER 0 + +#include + +#include "dviRenderer.h" +#include "dvi.h" +#include "dviFile.h" +#include "fontpool.h" +#include "hyperlink.h" +#include "kdvi_multipage.h" +#include "performanceMeasurement.h" +#include "psgs.h" +#include "renderedDviPagePixmap.h" +#include "TeXFont.h" +#include "textBox.h" +#include "xdvi.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern QPainter *foreGroundPainter; + + +/** Routine to print characters. */ + +void dviRenderer::set_char(unsigned int cmd, unsigned int ch) +{ +#ifdef DEBUG_RENDER + kdDebug(4300) << "set_char #" << ch << endl; +#endif + + glyph *g; + if (colorStack.isEmpty()) + g = ((TeXFont *)(currinf.fontp->font))->getGlyph(ch, true, globalColor); + else + g = ((TeXFont *)(currinf.fontp->font))->getGlyph(ch, true, colorStack.top()); + if (g == NULL) + return; + + long dvi_h_sav = currinf.data.dvi_h; + + QPixmap pix = g->shrunkenCharacter; + int x = ((int) ((currinf.data.dvi_h) / (shrinkfactor * 65536))) - g->x2; + int y = currinf.data.pxl_v - g->y2; + + // Draw the character. + foreGroundPainter->drawPixmap(x, y, pix); + + // Are we drawing text for a hyperlink? And are hyperlinks + // enabled? + if (HTML_href != NULL) { + // Now set up a rectangle which is checked against every mouse + // event. + if (line_boundary_encountered == true) { + // Set up hyperlink + Hyperlink dhl; + dhl.baseline = currinf.data.pxl_v; + dhl.box.setRect(x, y, pix.width(), pix.height()); + dhl.linkText = *HTML_href; + currentlyDrawnPage->hyperLinkList.push_back(dhl); + } else { + QRect dshunion = currentlyDrawnPage->hyperLinkList[currentlyDrawnPage->hyperLinkList.size()-1].box.unite(QRect(x, y, pix.width(), pix.height())) ; + currentlyDrawnPage->hyperLinkList[currentlyDrawnPage->hyperLinkList.size()-1].box = dshunion; + } + } + + // Are we drawing text for a source hyperlink? And are source + // hyperlinks enabled? + // If we are printing source hyperlinks are irrelevant, otherwise we + // actually got a pointer to a RenderedDviPagePixmap. + RenderedDviPagePixmap* currentDVIPage = dynamic_cast(currentlyDrawnPage); + if (source_href != 0 && currentDVIPage) { + // Now set up a rectangle which is checked against every mouse + // event. + if (line_boundary_encountered == true) { + // Set up source hyperlinks + Hyperlink dhl; + dhl.baseline = currinf.data.pxl_v; + dhl.box.setRect(x, y, pix.width(), pix.height()); + if (source_href != NULL) + dhl.linkText = *source_href; + else + dhl.linkText = ""; + currentDVIPage->sourceHyperLinkList.push_back(dhl); + } else { + QRect dshunion = currentDVIPage->sourceHyperLinkList[currentDVIPage->sourceHyperLinkList.size()-1].box.unite(QRect(x, y, pix.width(), pix.height())) ; + currentDVIPage->sourceHyperLinkList[currentDVIPage->sourceHyperLinkList.size()-1].box = dshunion; + } + } + + // Code for DVI -> text functions (e.g. marking of text, full text + // search, etc.). Set up the currentlyDrawnPage->textBoxList. + TextBox link; + link.box.setRect(x, y, pix.width(), pix.height()); + link.text = ""; + currentlyDrawnPage->textBoxList.push_back(link); + + switch(ch) { + case 0x0b: + currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "ff"; + break; + case 0x0c: + currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "fi"; + break; + case 0x0d: + currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "fl"; + break; + case 0x0e: + currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "ffi"; + break; + case 0x0f: + currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "ffl"; + break; + + case 0x7b: + currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "-"; + break; + case 0x7c: + currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "---"; + break; + case 0x7d: + currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "\""; + break; + case 0x7e: + currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "~"; + break; + case 0x7f: + currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "@@"; // @@@ check! + break; + + default: + if ((ch >= 0x21) && (ch <= 0x7a)) + currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += QChar(ch); + else + currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "?"; + break; + } + + + if (cmd == PUT1) + currinf.data.dvi_h = dvi_h_sav; + else + currinf.data.dvi_h += (int)(currinf.fontp->scaled_size_in_DVI_units * dviFile->getCmPerDVIunit() * + (1200.0 / 2.54)/16.0 * g->dvi_advance_in_units_of_design_size_by_2e20 + 0.5); + + word_boundary_encountered = false; + line_boundary_encountered = false; +} + +void dviRenderer::set_empty_char(unsigned int, unsigned int) +{ + return; +} + +void dviRenderer::set_vf_char(unsigned int cmd, unsigned int ch) +{ +#ifdef DEBUG_RENDER + kdDebug(4300) << "dviRenderer::set_vf_char( cmd=" << cmd << ", ch=" << ch << " )" << endl; +#endif + + static unsigned char c; + macro *m = &currinf.fontp->macrotable[ch]; + if (m->pos == NULL) { + kdError(4300) << "Character " << ch << " not defined in font " << currinf.fontp->fontname << endl; + m->pos = m->end = &c; + return; + } + + long dvi_h_sav = currinf.data.dvi_h; + + struct drawinf oldinfo = currinf; + currinf.data.w = 0; + currinf.data.x = 0; + currinf.data.y = 0; + currinf.data.z = 0; + + currinf.fonttable = &(currinf.fontp->vf_table); + currinf._virtual = currinf.fontp; + Q_UINT8 *command_ptr_sav = command_pointer; + Q_UINT8 *end_ptr_sav = end_pointer; + command_pointer = m->pos; + end_pointer = m->end; + draw_part(currinf.fontp->scaled_size_in_DVI_units*(dviFile->getCmPerDVIunit() * 1200.0 / 2.54)/16.0, true); + command_pointer = command_ptr_sav; + end_pointer = end_ptr_sav; + currinf = oldinfo; + + if (cmd == PUT1) + currinf.data.dvi_h = dvi_h_sav; + else + currinf.data.dvi_h += (int)(currinf.fontp->scaled_size_in_DVI_units * dviFile->getCmPerDVIunit() * + (1200.0 / 2.54)/16.0 * m->dvi_advance_in_units_of_design_size_by_2e20 + 0.5); +} + + +void dviRenderer::set_no_char(unsigned int cmd, unsigned int ch) +{ +#ifdef DEBUG_RENDER + kdDebug(4300) << "dviRenderer::set_no_char( cmd=" << cmd << ", ch =" << ch << " )" << endl; +#endif + + if (currinf._virtual) { + currinf.fontp = currinf._virtual->first_font; + if (currinf.fontp != NULL) { + currinf.set_char_p = currinf.fontp->set_char_p; + (this->*currinf.set_char_p)(cmd, ch); + return; + } + } + + errorMsg = i18n("The DVI code set a character of an unknown font."); + return; +} + + +void dviRenderer::draw_part(double current_dimconv, bool is_vfmacro) +{ +#ifdef DEBUG_RENDER + kdDebug(4300) << "draw_part" << endl; +#endif + + Q_INT32 RRtmp=0, WWtmp=0, XXtmp=0, YYtmp=0, ZZtmp=0; + Q_UINT8 ch; + + currinf.fontp = NULL; + currinf.set_char_p = &dviRenderer::set_no_char; + + for (;;) { + ch = readUINT8(); + if (ch <= (unsigned char) (SETCHAR0 + 127)) { + (this->*currinf.set_char_p)(ch, ch); + } else + if (FNTNUM0 <= ch && ch <= (unsigned char) (FNTNUM0 + 63)) { + currinf.fontp = currinf.fonttable->find(ch - FNTNUM0); + if (currinf.fontp == NULL) { + errorMsg = i18n("The DVI code referred to font #%1, which was not previously defined.").arg(ch - FNTNUM0); + return; + } + currinf.set_char_p = currinf.fontp->set_char_p; + } else { + Q_INT32 a, b; + + switch (ch) { + case SET1: + case PUT1: + (this->*currinf.set_char_p)(ch, readUINT8()); + break; + + case SETRULE: + if (is_vfmacro == false) { + word_boundary_encountered = true; + line_boundary_encountered = true; + } + /* Be careful, dvicopy outputs rules with height = + 0x80000000. We don't want any SIGFPE here. */ + a = readUINT32(); + b = readUINT32(); + b = ((long) (b * current_dimconv)); + if (a > 0 && b > 0) { + int h = ((int) ROUNDUP(((long) (a * current_dimconv)), shrinkfactor * 65536)); + int w = ((int) ROUNDUP(b, shrinkfactor * 65536)); + + if (colorStack.isEmpty()) + foreGroundPainter->fillRect( ((int) ((currinf.data.dvi_h) / (shrinkfactor * 65536))), + currinf.data.pxl_v - h + 1, w?w:1, h?h:1, globalColor ); + else + foreGroundPainter->fillRect( ((int) ((currinf.data.dvi_h) / (shrinkfactor * 65536))), + currinf.data.pxl_v - h + 1, w?w:1, h?h:1, colorStack.top() ); + } + currinf.data.dvi_h += b; + break; + + case PUTRULE: + if (is_vfmacro == false) { + word_boundary_encountered = true; + line_boundary_encountered = true; + } + a = readUINT32(); + b = readUINT32(); + a = ((long) (a * current_dimconv)); + b = ((long) (b * current_dimconv)); + if (a > 0 && b > 0) { + int h = ((int) ROUNDUP(a, shrinkfactor * 65536)); + int w = ((int) ROUNDUP(b, shrinkfactor * 65536)); + if (colorStack.isEmpty()) + foreGroundPainter->fillRect( ((int) ((currinf.data.dvi_h) / (shrinkfactor * 65536))), + currinf.data.pxl_v - h + 1, w?w:1, h?h:1, globalColor ); + else + foreGroundPainter->fillRect( ((int) ((currinf.data.dvi_h) / (shrinkfactor * 65536))), + currinf.data.pxl_v - h + 1, w?w:1, h?h:1, colorStack.top() ); + } + break; + + case NOP: + break; + + case BOP: + if (is_vfmacro == false) { + word_boundary_encountered = true; + line_boundary_encountered = true; + } + command_pointer += 11 * 4; + currinf.data.dvi_h = 1200 << 16; // Reminder: DVI-coordinates start at (1",1") from top of page + currinf.data.dvi_v = 1200; + currinf.data.pxl_v = int(currinf.data.dvi_v/shrinkfactor); + currinf.data.w = currinf.data.x = currinf.data.y = currinf.data.z = 0; + break; + + case EOP: + // Check if we are just at the end of a virtual font macro. + if (is_vfmacro == false) { + // This is really the end of a page, and not just the end + // of a macro. Mark the end of the current word. + word_boundary_encountered = true; + line_boundary_encountered = true; + // Sanity check for the dvi-file: The DVI-standard asserts + // that at the end of a page, the stack should always be + // empty. + if (!stack.isEmpty()) { + kdDebug(4300) << "DRAW: The stack was not empty when the EOP command was encountered." << endl; + errorMsg = i18n("The stack was not empty when the EOP command was encountered."); + return; + } + } + return; + + case PUSH: + stack.push(currinf.data); + break; + + case POP: + if (stack.isEmpty()) { + errorMsg = i18n("The stack was empty when a POP command was encountered."); + return; + } else + currinf.data = stack.pop(); + word_boundary_encountered = true; + line_boundary_encountered = true; + break; + + case RIGHT1: + case RIGHT2: + case RIGHT3: + case RIGHT4: + RRtmp = readINT(ch - RIGHT1 + 1); + + // A horizontal motion in the range 4 * font space [f] < h < + // font space [f] will be treated as a kern that is not + // indicated in the printouts that DVItype produces between + // brackets. We allow a larger space in the negative + // direction than in the positive one, because TEX makes + // comparatively large backspaces when it positions + // accents. (comments stolen from the source of dvitype) + if ((is_vfmacro == false) && + (currinf.fontp != 0) && + ((RRtmp >= currinf.fontp->scaled_size_in_DVI_units/6) || (RRtmp <= -4*(currinf.fontp->scaled_size_in_DVI_units/6))) && + (currentlyDrawnPage->textBoxList.size() > 0)) + currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += ' '; + currinf.data.dvi_h += ((long) (RRtmp * current_dimconv)); + break; + + case W1: + case W2: + case W3: + case W4: + WWtmp = readINT(ch - W0); + currinf.data.w = ((long) (WWtmp * current_dimconv)); + case W0: + if ((is_vfmacro == false) && + (currinf.fontp != 0) && + ((WWtmp >= currinf.fontp->scaled_size_in_DVI_units/6) || (WWtmp <= -4*(currinf.fontp->scaled_size_in_DVI_units/6))) && + (currentlyDrawnPage->textBoxList.size() > 0) ) + currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += ' '; + currinf.data.dvi_h += currinf.data.w; + break; + + case X1: + case X2: + case X3: + case X4: + XXtmp = readINT(ch - X0); + currinf.data.x = ((long) (XXtmp * current_dimconv)); + case X0: + if ((is_vfmacro == false) && + (currinf.fontp != 0) && + ((XXtmp >= currinf.fontp->scaled_size_in_DVI_units/6) || (XXtmp <= -4*(currinf.fontp->scaled_size_in_DVI_units/6))) && + (currentlyDrawnPage->textBoxList.size() > 0)) + currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += ' '; + currinf.data.dvi_h += currinf.data.x; + break; + + case DOWN1: + case DOWN2: + case DOWN3: + case DOWN4: + { + Q_INT32 DDtmp = readINT(ch - DOWN1 + 1); + if ((is_vfmacro == false) && + (currinf.fontp != 0) && + (abs(DDtmp) >= 5*(currinf.fontp->scaled_size_in_DVI_units/6)) && + (currentlyDrawnPage->textBoxList.size() > 0)) { + word_boundary_encountered = true; + line_boundary_encountered = true; + if (abs(DDtmp) >= 10*(currinf.fontp->scaled_size_in_DVI_units/6)) + currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += '\n'; + } + currinf.data.dvi_v += ((long) (DDtmp * current_dimconv))/65536; + currinf.data.pxl_v = int(currinf.data.dvi_v/shrinkfactor); + } + break; + + case Y1: + case Y2: + case Y3: + case Y4: + YYtmp = readINT(ch - Y0); + currinf.data.y = ((long) (YYtmp * current_dimconv)); + case Y0: + if ((is_vfmacro == false) && + (currinf.fontp != 0) && + (abs(YYtmp) >= 5*(currinf.fontp->scaled_size_in_DVI_units/6)) && + (currentlyDrawnPage->textBoxList.size() > 0)) { + word_boundary_encountered = true; + line_boundary_encountered = true; + if (abs(YYtmp) >= 10*(currinf.fontp->scaled_size_in_DVI_units/6)) + currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += '\n'; + } + currinf.data.dvi_v += currinf.data.y/65536; + currinf.data.pxl_v = int(currinf.data.dvi_v/shrinkfactor); + break; + + case Z1: + case Z2: + case Z3: + case Z4: + ZZtmp = readINT(ch - Z0); + currinf.data.z = ((long) (ZZtmp * current_dimconv)); + case Z0: + if ((is_vfmacro == false) && + (currinf.fontp != 0) && + (abs(ZZtmp) >= 5*(currinf.fontp->scaled_size_in_DVI_units/6)) && + (currentlyDrawnPage->textBoxList.size() > 0)) { + word_boundary_encountered = true; + line_boundary_encountered = true; + if (abs(ZZtmp) >= 10*(currinf.fontp->scaled_size_in_DVI_units/6)) + currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += '\n'; + } + currinf.data.dvi_v += currinf.data.z/65536; + currinf.data.pxl_v = int(currinf.data.dvi_v/shrinkfactor); + break; + + case FNT1: + case FNT2: + case FNT3: + currinf.fontp = currinf.fonttable->find(readUINT(ch - FNT1 + 1)); + if (currinf.fontp == NULL) { + errorMsg = i18n("The DVI code referred to a font which was not previously defined."); + return; + } + currinf.set_char_p = currinf.fontp->set_char_p; + break; + + case FNT4: + currinf.fontp = currinf.fonttable->find(readINT(ch - FNT1 + 1)); + if (currinf.fontp == NULL) { + errorMsg = i18n("The DVI code referred to a font which was not previously defined."); + return; + } + currinf.set_char_p = currinf.fontp->set_char_p; + break; + + case XXX1: + case XXX2: + case XXX3: + case XXX4: + if (is_vfmacro == false) { + word_boundary_encountered = true; + line_boundary_encountered = true; + } + a = readUINT(ch - XXX1 + 1); + if (a > 0) { + char *cmd = new char[a+1]; + strncpy(cmd, (char *)command_pointer, a); + command_pointer += a; + cmd[a] = '\0'; + applicationDoSpecial(cmd); + delete [] cmd; + } + break; + + case FNTDEF1: + case FNTDEF2: + case FNTDEF3: + case FNTDEF4: + command_pointer += 12 + ch - FNTDEF1 + 1; + { + Q_UINT8 tempa = readUINT8(); + Q_UINT8 tempb = readUINT8(); + command_pointer += tempa + tempb; + } + break; + + case PRE: + case POST: + case POSTPOST: + errorMsg = i18n("An illegal command was encountered."); + return; + break; + + default: + errorMsg = i18n("The unknown op-code %1 was encountered.").arg(ch); + return; + } /* end switch*/ + } /* end else (ch not a SETCHAR or FNTNUM) */ + } /* end for */ +} + + +void dviRenderer::draw_page() +{ + // Reset a couple of variables + HTML_href = 0; + source_href = 0; + penWidth_in_mInch = 0.0; + + // Calling resize() here rather than clear() means that the memory + // taken up by the vector is not freed. This is faster than + // constantly allocating/freeing memory. + currentlyDrawnPage->textBoxList.resize(0); + + RenderedDviPagePixmap* currentDVIPage = dynamic_cast(currentlyDrawnPage); + if (currentDVIPage) + { + currentDVIPage->sourceHyperLinkList.resize(0); + } + +#ifdef PERFORMANCE_MEASUREMENT + // If this is the first time a page is drawn, take the time that is + // elapsed till the kdvi_multipage was constructed, and print + // it. Set the flag so that is message will not be printed again. + if (performanceFlag == 0) { + kdDebug(4300) << "Time elapsed till the first page is drawn: " << performanceTimer.restart() << "ms" << endl; + performanceFlag = 1; + } +#endif + + +#ifdef DEBUG_RENDER + kdDebug(4300) <<"draw_page" << endl; +#endif + + if (!accessibilityBackground) + { + foreGroundPainter->fillRect( foreGroundPainter->viewport(), PS_interface->getBackgroundColor(current_page) ); + } + else + { + // In accessiblity mode use the custom background color + foreGroundPainter->fillRect( foreGroundPainter->viewport(), accessibilityBackgroundColor ); + } + + // Render the PostScript background, if there is one. + if (_postscript) + { + // In accessiblity mode use the custom background color + if (accessibilityBackground) + { + // Flag permanent is set to false because otherwise we would not be able to restore + // the original background color. + PS_interface->setBackgroundColor(current_page, accessibilityBackgroundColor, false); + } + else + PS_interface->restoreBackgroundColor(current_page); + + PS_interface->graphics(current_page, resolutionInDPI, dviFile->getMagnification(), foreGroundPainter); + } + + // Now really write the text + if (dviFile->page_offset.isEmpty() == true) + return; + if (current_page < dviFile->total_pages) { + command_pointer = dviFile->dvi_Data() + dviFile->page_offset[current_page]; + end_pointer = dviFile->dvi_Data() + dviFile->page_offset[current_page+1]; + } else + command_pointer = end_pointer = 0; + + memset((char *) &currinf.data, 0, sizeof(currinf.data)); + currinf.fonttable = &(dviFile->tn_table); + currinf._virtual = 0; + + double fontPixelPerDVIunit = dviFile->getCmPerDVIunit() * 1200.0/2.54; + + draw_part(65536.0*fontPixelPerDVIunit, false); + if (HTML_href != 0) { + delete HTML_href; + HTML_href = 0; + } + if (source_href != 0) { + delete source_href; + source_href = 0; + } +} diff --git a/kdvi/dviRenderer_export.cpp b/kdvi/dviRenderer_export.cpp new file mode 100644 index 00000000..4745bf18 --- /dev/null +++ b/kdvi/dviRenderer_export.cpp @@ -0,0 +1,391 @@ +// +// Class: dviRenderer +// Author: Stefan Kebekus +// +// (C) 2001-2004, Stefan Kebekus. +// +// Previewer for TeX DVI files. +// +// 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. +// +// Please report bugs or improvements, etc. via the "Report bug"-Menu +// of kdvi. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dviRenderer.h" +#include "dviFile.h" +#include "fontprogress.h" +#include "infodialog.h" +#include "kdvi_multipage.h" + +extern QPainter foreGroundPaint; // QPainter used for text + + + +void dviRenderer::exportPDF() +{ + // It could perhaps happen that a kShellProcess, which runs an + // editor for inverse search, is still running. In that case, we + // ingore any further output of the editor by detaching the + // appropriate slots. The sigal "processExited", however, remains + // attached to the slow "exportCommand_terminated", which is smart + // enough to ignore the exit status of the editor if another command + // has been called meanwhile. See also the exportPS method. + if (proc != 0) { + // Make sure all further output of the programm is ignored + qApp->disconnect(proc, SIGNAL(receivedStderr(KProcess *, char *, int)), 0, 0); + qApp->disconnect(proc, SIGNAL(receivedStdout(KProcess *, char *, int)), 0, 0); + proc = 0; + } + + // That sould also not happen. + if (dviFile == NULL) + return; + + // Is the dvipdfm-Programm available ?? + QStringList texList = QStringList::split(":", QString::fromLocal8Bit(getenv("PATH"))); + bool found = false; + for (QStringList::Iterator it=texList.begin(); it!=texList.end(); ++it) { + QString temp = (*it) + "/" + "dvipdfm"; + if (QFile::exists(temp)) { + found = true; + break; + } + } + if (found == false) { + KMessageBox::sorry(0, i18n("KDVI could not locate the program 'dvipdfm' on your computer. That program is " + "essential for the export function to work. You can, however, convert " + "the DVI-file to PDF using the print function of KDVI, but that will often " + "produce documents which print ok, but are of inferior quality if viewed in the " + "Acrobat Reader. It may be wise to upgrade to a more recent version of your " + "TeX distribution which includes the 'dvipdfm' program.\n" + "Hint to the perplexed system administrator: KDVI uses the shell's PATH variable " + "when looking for programs.")); + return; + } + + // Generate a suggestion for a reasonable file name + QString suggestedName = dviFile->filename; + suggestedName = suggestedName.left(suggestedName.find(".")) + ".pdf"; + + QString fileName = KFileDialog::getSaveFileName(suggestedName, i18n("*.pdf|Portable Document Format (*.pdf)"), parentWidget, i18n("Export File As")); + if (fileName.isEmpty()) + return; + QFileInfo finfo(fileName); + if (finfo.exists()) { + int r = KMessageBox::warningContinueCancel (parentWidget, i18n("The file %1\nexists. Do you want to overwrite that file?").arg(fileName), + i18n("Overwrite File"), i18n("Overwrite")); + if (r == KMessageBox::Cancel) + return; + } + + // Initialize the progress dialog + progress = new fontProgressDialog( QString::null, + i18n("Using dvipdfm to export the file to PDF"), + QString::null, + i18n("KDVI is currently using the external program 'dvipdfm' to " + "convert your DVI-file to PDF. Sometimes that can take " + "a while because dvipdfm needs to generate its own bitmap fonts " + "Please be patient."), + i18n("Waiting for dvipdfm to finish..."), + parentWidget, i18n("dvipdfm progress dialog"), false ); + if (progress != 0) { + progress->TextLabel2->setText( i18n("Please be patient") ); + progress->setTotalSteps( dviFile->total_pages ); + qApp->connect(progress, SIGNAL(finished()), this, SLOT(abortExternalProgramm())); + } + + proc = new KShellProcess(); + if (proc == 0) { + kdError(4300) << "Could not allocate ShellProcess for the dvipdfm command." << endl; + return; + } + qApp->disconnect( this, SIGNAL(mySignal()), 0, 0 ); + + qApp->connect(proc, SIGNAL(receivedStderr(KProcess *, char *, int)), this, SLOT(dvips_output_receiver(KProcess *, char *, int))); + qApp->connect(proc, SIGNAL(receivedStdout(KProcess *, char *, int)), this, SLOT(dvips_output_receiver(KProcess *, char *, int))); + qApp->connect(proc, SIGNAL(processExited(KProcess *)), this, SLOT(dvips_terminated(KProcess *))); + + export_errorString = i18n("The external program 'dvipdf', which was used to export the file, reported an error. " + "You might wish to look at the document info dialog which you will " + "find in the File-Menu for a precise error report.") ; + info->clear(i18n("Export: %1 to PDF").arg(KShellProcess::quote(dviFile->filename))); + + proc->clearArguments(); + finfo.setFile(dviFile->filename); + *proc << QString("cd %1; dvipdfm").arg(KShellProcess::quote(finfo.dirPath(true))); + *proc << QString("-o %1").arg(KShellProcess::quote(fileName)); + *proc << KShellProcess::quote(dviFile->filename); + proc->closeStdin(); + if (proc->start(KProcess::NotifyOnExit, KProcess::AllOutput) == false) { + kdError(4300) << "dvipdfm failed to start" << endl; + return; + } + return; +} + + +void dviRenderer::exportPS(const QString& fname, const QString& options, KPrinter* printer) +{ + // Safety check. + if (dviFile->page_offset.isEmpty() == true) + return; + + // It could perhaps happen that a kShellProcess, which runs an + // editor for inverse search, is still running. In that case, we + // ingore any further output of the editor by detaching the + // appropriate slots. The sigal "processExited", however, remains + // attached to the slow "exportCommand_terminated", which is smart + // enough to ignore the exit status of the editor if another command + // has been called meanwhile. See also the exportPDF method. + if (proc != 0) { + qApp->disconnect(proc, SIGNAL(receivedStderr(KProcess *, char *, int)), 0, 0); + qApp->disconnect(proc, SIGNAL(receivedStdout(KProcess *, char *, int)), 0, 0); + proc = 0; + } + + // That sould also not happen. + if (dviFile == NULL) + return; + + if (dviFile->numberOfExternalNONPSFiles != 0) { + KMessageBox::sorry( parentWidget, + i18n("

This DVI file refers to external graphic files which are not in PostScript format, and cannot be handled by the " + "dvips program that KDVI uses interally to print or to export to PostScript. The functionality that " + "you require is therefore unavailable in this version of KDVI.

" + "

As a workaround, you can use the File/Export As-Menu to save this file in PDF format, and then use " + "a PDF viewer.

" + "

The author of KDVI apologizes for the inconvenience. If enough users complain, the missing functionality might later " + "be added.

") , + i18n("Functionality Unavailable")); + return; + } + + QString fileName; + if (fname.isEmpty()) { + // Generate a suggestion for a reasonable file name + QString suggestedName = dviFile->filename; + suggestedName = suggestedName.left(suggestedName.find(".")) + ".ps"; + + fileName = KFileDialog::getSaveFileName(suggestedName, i18n("*.ps|PostScript (*.ps)"), parentWidget, i18n("Export File As")); + if (fileName.isEmpty()) + return; + QFileInfo finfo(fileName); + if (finfo.exists()) { + int r = KMessageBox::warningYesNo (parentWidget, i18n("The file %1\nexists. Do you want to overwrite that file?").arg(fileName), + i18n("Overwrite File")); + if (r == KMessageBox::No) + return; + } + } else + fileName = fname; + export_fileName = fileName; + export_printer = printer; + + // Initialize the progress dialog + progress = new fontProgressDialog( QString::null, + i18n("Using dvips to export the file to PostScript"), + QString::null, + i18n("KDVI is currently using the external program 'dvips' to " + "convert your DVI-file to PostScript. Sometimes that can take " + "a while because dvips needs to generate its own bitmap fonts " + "Please be patient."), + i18n("Waiting for dvips to finish..."), + parentWidget, i18n("dvips progress dialog"), false ); + if (progress != 0) { + progress->TextLabel2->setText( i18n("Please be patient") ); + progress->setTotalSteps( dviFile->total_pages ); + qApp->connect(progress, SIGNAL(finished()), this, SLOT(abortExternalProgramm())); + } + + // There is a major problem with dvips, at least 5.86 and lower: the + // arguments of the option "-pp" refer to TeX-pages, not to + // sequentially numbered pages. For instance "-pp 7" may refer to 3 + // or more pages: one page "VII" in the table of contents, a page + // "7" in the text body, and any number of pages "7" in various + // appendices, indices, bibliographies, and so forth. KDVI currently + // uses the following disgusting workaround: if the "options" + // variable is used, the DVI-file is copied to a temporary file, and + // all the page numbers are changed into a sequential ordering + // (using UNIX files, and taking manually care of CPU byte + // ordering). Finally, dvips is then called with the new file, and + // the file is afterwards deleted. Isn't that great? + + // A similar problem occurs with DVI files that contain page size + // information. On these files, dvips pointblank refuses to change + // the page orientation or set another page size. Thus, if the + // DVI-file does contain page size information, we remove that + // information first. + + // Sourcefile is the name of the DVI which is used by dvips, either + // the original file, or a temporary file with a new numbering. + QString sourceFileName = dviFile->filename; + if ((options.isEmpty() == false) || (dviFile->suggestedPageSize != 0) ) { + // Get a name for a temporary file. + KTempFile export_tmpFile; + export_tmpFileName = export_tmpFile.name(); + export_tmpFile.unlink(); + + sourceFileName = export_tmpFileName; + + fontPool fp; + dvifile newFile(dviFile, &fp); + + // Renumber pages + newFile.renumber(); + + // Remove any page size information from the file + Q_UINT16 currPageSav = current_page; + dvifile *dvsav = dviFile; + dviFile = &newFile; + errorMsg = QString::null; + + + for(current_page=0; current_page < newFile.total_pages; current_page++) { + if (current_page < newFile.total_pages) { + command_pointer = dviFile->dvi_Data() + dviFile->page_offset[current_page]; + end_pointer = dviFile->dvi_Data() + dviFile->page_offset[current_page+1]; + } else + command_pointer = end_pointer = 0; + + memset((char *) &currinf.data, 0, sizeof(currinf.data)); + currinf.fonttable = &(dviFile->tn_table); + currinf._virtual = NULL; + prescan(&dviRenderer::prescan_removePageSizeInfo); + } + + current_page = currPageSav; + dviFile = dvsav; + newFile.saveAs(sourceFileName); + } + + // Allocate and initialize the shell process. + proc = new KShellProcess(); + if (proc == 0) { + kdError(4300) << "Could not allocate ShellProcess for the dvips command." << endl; + return; + } + + qApp->connect(proc, SIGNAL(receivedStderr(KProcess *, char *, int)), this, SLOT(dvips_output_receiver(KProcess *, char *, int))); + qApp->connect(proc, SIGNAL(receivedStdout(KProcess *, char *, int)), this, SLOT(dvips_output_receiver(KProcess *, char *, int))); + qApp->connect(proc, SIGNAL(processExited(KProcess *)), this, SLOT(dvips_terminated(KProcess *))); + export_errorString = i18n("The external program 'dvips', which was used to export the file, reported an error. " + "You might wish to look at the document info dialog which you will " + "find in the File-Menu for a precise error report.") ; + info->clear(i18n("Export: %1 to PostScript").arg(KShellProcess::quote(dviFile->filename))); + + proc->clearArguments(); + QFileInfo finfo(dviFile->filename); + *proc << QString("cd %1; dvips").arg(KShellProcess::quote(finfo.dirPath(true))); + if (printer == 0) + *proc << "-z"; // export Hyperlinks + if (options.isEmpty() == false) + *proc << options; + *proc << QString("%1").arg(KShellProcess::quote(sourceFileName)); + *proc << QString("-o %1").arg(KShellProcess::quote(fileName)); + proc->closeStdin(); + if (proc->start(KProcess::NotifyOnExit, KProcess::Stderr) == false) { + kdError(4300) << "dvips failed to start" << endl; + return; + } + return; +} + + +void dviRenderer::dvips_output_receiver(KProcess *, char *buffer, int buflen) +{ + // Paranoia. + if (buflen < 0) + return; + QString op = QString::fromLocal8Bit(buffer, buflen); + + info->outputReceiver(op); + if (progress != 0) + progress->show(); +} + + +void dviRenderer::dvips_terminated(KProcess *sproc) +{ + // Give an error message from the message string. However, if the + // sproc is not the "current external process of interest", i.e. not + // the LAST external program that was started by the user, then the + // export_errorString, does not correspond to sproc. In that case, + // we ingore the return status silently. + if ((proc == sproc) && (sproc->normalExit() == true) && (sproc->exitStatus() != 0)) + KMessageBox::error( parentWidget, export_errorString ); + + if (export_printer != 0) + export_printer->printFiles( QStringList(export_fileName), true ); + + // Kill and delete the remaining process, delete the printer, etc. + abortExternalProgramm(); +} + + +void dviRenderer::editorCommand_terminated(KProcess *sproc) +{ + // Give an error message from the message string. However, if the + // sproc is not the "current external process of interest", i.e. not + // the LAST external program that was started by the user, then the + // export_errorString, does not correspond to sproc. In that case, + // we ingore the return status silently. + if ((proc == sproc) && (sproc->normalExit() == true) && (sproc->exitStatus() != 0)) + KMessageBox::error( parentWidget, export_errorString ); + + // Let's hope that this is not all too nasty... killing a + // KShellProcess from a slot that was called from the KShellProcess + // itself. Until now, there weren't any problems. + + // Perhaps it was a bad idea, after all. + //@@@@ delete sproc; +} + + +void dviRenderer::abortExternalProgramm() +{ + delete proc; // Deleting the KProcess kills the child. + proc = 0; + + if (export_tmpFileName.isEmpty() != true) { + unlink(QFile::encodeName(export_tmpFileName)); // That should delete the file. + export_tmpFileName = ""; + } + + if (progress != 0) { + progress->hide(); + delete progress; + progress = 0; + } + + delete export_printer; + export_printer = 0; + export_fileName = ""; +} diff --git a/kdvi/dviRenderer_prescan.cpp b/kdvi/dviRenderer_prescan.cpp new file mode 100644 index 00000000..59bdeb25 --- /dev/null +++ b/kdvi/dviRenderer_prescan.cpp @@ -0,0 +1,789 @@ +// dviRenderer_prescan.cpp +// +// Part of KDVI - A DVI previewer for the KDE desktop environemt +// +// (C) 2003--2004 Stefan Kebekus +// Distributed under the GPL + +#include + +#include "dviRenderer.h" +#include "dvi.h" +#include "dviFile.h" +#include "fontpool.h" +#include "kdvi_multipage.h" +#include "performanceMeasurement.h" +#include "prebookmark.h" +#include "psgs.h" +#include "TeXFont.h" +#include "xdvi.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +extern QPainter foreGroundPaint; +extern void parse_special_argument(const QString& strg, const char* argument_name, int* variable); + + +//#define DEBUG_PRESCAN + + +void dviRenderer::prescan_embedPS(char *cp, Q_UINT8 *beginningOfSpecialCommand) +{ +#ifdef DEBUG_PRESCAN + kdDebug(4300) << "dviRenderer::prescan_embedPS( cp = " << cp << " ) " << endl; +#endif + + // Encapsulated Postscript File + if (strncasecmp(cp, "PSfile=", 7) != 0) + return; + + QString command(cp+7); + + QString include_command = command.simplifyWhiteSpace(); + + // The line is supposed to start with "..ile=", and then comes the + // filename. Figure out what the filename is and stow it away. Of + // course, this does not work if the filename contains spaces + // (already the simplifyWhiteSpace() above is wrong). If you have + // files like this, go away. + QString EPSfilename = include_command; + EPSfilename.truncate(EPSfilename.find(' ')); + + // Strip enclosing quotation marks which are included by some LaTeX + // macro packages (but not by others). This probably means that + // graphic files are no longer found if the filename really does + // contain quotes, but we don't really care that much. + if ((EPSfilename.at(0) == '\"') && (EPSfilename.at(EPSfilename.length()-1) == '\"')) + EPSfilename = EPSfilename.mid(1,EPSfilename.length()-2); + + // If the file is neither a PostScript not a PDF file, we exit here. + // The graphic file is later read when the page is rendered. + KMimeType::Ptr const mime_type = + KMimeType::findByFileContent(EPSfilename); + QString const & mime_type_name = mime_type->name(); + + bool const is_ps_file = (mime_type_name == "application/postscript" || + mime_type_name == "image/x-eps"); + bool const is_pdf_file = (!is_ps_file && + mime_type_name == "application/pdf"); + if (!(is_ps_file || is_pdf_file)) + return; + + QString originalFName = EPSfilename; + + embedPS_progress->setLabel(i18n("Embedding %1").arg(EPSfilename)); + qApp->processEvents(); + + + // Now locate the Gfx file on the hard disk... + EPSfilename = ghostscript_interface::locateEPSfile(EPSfilename, baseURL); + + // If the EPSfilename really points to a PDF file, convert that file now. + if (is_pdf_file) + EPSfilename = dviFile->convertPDFtoPS(EPSfilename); + + if (!QFile::exists(EPSfilename)) { + // Find the number of the page + Q_UINT32 currentOffset = beginningOfSpecialCommand - dviFile->dvi_Data(); + Q_UINT16 page; + for(page=0; page < dviFile->total_pages; page++) + if ((dviFile->page_offset[page] <= currentOffset) && (currentOffset <= dviFile->page_offset[page+1])) + break; + errorMsg += i18n("Page %1: The PostScript file %2 could not be found.
").arg(page+1).arg(originalFName); + embedPS_progress->progressBar()->advance(1); + qApp->processEvents(); + return; + } + + // Now parse the arguments. + int llx = 0; + int lly = 0; + int urx = 0; + int ury = 0; + int rwi = 0; + int rhi = 0; + int angle = 0; + + // just to avoid ambiguities; the filename could contain keywords + include_command = include_command.mid(include_command.find(' ')); + + parse_special_argument(include_command, "llx=", &llx); + parse_special_argument(include_command, "lly=", &lly); + parse_special_argument(include_command, "urx=", &urx); + parse_special_argument(include_command, "ury=", &ury); + parse_special_argument(include_command, "rwi=", &rwi); + parse_special_argument(include_command, "rhi=", &rhi); + parse_special_argument(include_command, "angle=", &angle); + + int clip=include_command.find(" clip"); // -1 if clip keyword is not present, >= 0 otherwise + + // Generate the PostScript commands to be included + QString PS = QString("ps: @beginspecial %1 @llx %2 @lly %3 @urx %4 @ury").arg(llx).arg(lly).arg(urx).arg(ury); + if (rwi != 0) + PS.append( QString(" %1 @rwi").arg(rwi) ); + if (rhi != 0) + PS.append( QString(" %1 @rhi").arg(rhi) ); + if (angle != 0) + PS.append( QString(" %1 @angle").arg(angle) ); + if (clip != -1) + PS.append(" @clip"); + PS.append( " @setspecial\n" ); + + QFile file( EPSfilename ); + if ( file.open( IO_ReadOnly ) ) { + QTextStream stream( &file ); + while ( !stream.atEnd() ) { + PS += stream.readLine().section( '%', 0, 0); + PS += "\n"; + } + file.close(); + } + PS.append( "@endspecial" ); + PS = PS.simplifyWhiteSpace(); + + + _isModified = true; + Q_UINT32 lengthOfOldSpecial = command_pointer - beginningOfSpecialCommand; + Q_UINT32 lengthOfNewSpecial = PS.length()+5; + + QMemArray newDVI(dviFile->size_of_file + lengthOfNewSpecial-lengthOfOldSpecial); + + Q_UINT8 *commandPtrSav = command_pointer; + Q_UINT8 *endPtrSav = end_pointer; + end_pointer = newDVI.data() + dviFile->size_of_file + lengthOfNewSpecial-lengthOfOldSpecial; + memcpy(newDVI.data(), dviFile->dvi_Data(), beginningOfSpecialCommand-dviFile->dvi_Data()); + command_pointer = newDVI.data()+(beginningOfSpecialCommand-dviFile->dvi_Data()); + command_pointer[0] = XXX4; + command_pointer++; + writeUINT32(PS.length()); + memcpy(newDVI.data()+(beginningOfSpecialCommand-dviFile->dvi_Data())+5, PS.latin1(), PS.length() ); + memcpy(newDVI.data()+(beginningOfSpecialCommand-dviFile->dvi_Data())+lengthOfNewSpecial, beginningOfSpecialCommand+lengthOfOldSpecial, + dviFile->size_of_file-(beginningOfSpecialCommand-dviFile->dvi_Data())-lengthOfOldSpecial ); + + // Adjust page pointers in the DVI file + dviFile->size_of_file = dviFile->size_of_file + lengthOfNewSpecial-lengthOfOldSpecial; + end_pointer = newDVI.data() + dviFile->size_of_file; + Q_UINT32 currentOffset = beginningOfSpecialCommand-dviFile->dvi_Data(); + for(Q_UINT16 i=0; i < dviFile->total_pages; i++) { + if (dviFile->page_offset[i] > currentOffset) { + dviFile->page_offset[i] = dviFile->page_offset[i] + lengthOfNewSpecial-lengthOfOldSpecial; + command_pointer = dviFile->page_offset[i] + newDVI.data() + 4*10 + 1; + Q_UINT32 a = readUINT32(); + if (a > currentOffset) { + a = a + lengthOfNewSpecial-lengthOfOldSpecial; + command_pointer = dviFile->page_offset[i] + newDVI.data() + 4*10 + 1; + writeUINT32(a); + } + } + } + + + dviFile->beginning_of_postamble = dviFile->beginning_of_postamble + lengthOfNewSpecial - lengthOfOldSpecial; + dviFile->page_offset[dviFile->total_pages] = dviFile->beginning_of_postamble; + + command_pointer = newDVI.data() + dviFile->beginning_of_postamble + 1; + Q_UINT32 a = readUINT32(); + if (a > currentOffset) { + a = a + lengthOfNewSpecial - lengthOfOldSpecial; + command_pointer = newDVI.data() + dviFile->beginning_of_postamble + 1; + writeUINT32(a); + } + + command_pointer = newDVI.data() + dviFile->size_of_file - 1; + while((*command_pointer == TRAILER) && (command_pointer > newDVI.data())) + command_pointer--; + command_pointer -= 4; + writeUINT32(dviFile->beginning_of_postamble); + command_pointer -= 4; + + command_pointer = commandPtrSav; + end_pointer = endPtrSav; + + // Modify all pointers to point to the newly allocated memory + command_pointer = newDVI.data() + (command_pointer - dviFile->dvi_Data()) + lengthOfNewSpecial-lengthOfOldSpecial; + end_pointer = newDVI.data() + (end_pointer - dviFile->dvi_Data()) + lengthOfNewSpecial-lengthOfOldSpecial; + + dviFile->setNewData(newDVI); + + embedPS_progress->progressBar()->advance(1); + qApp->processEvents(); + return; +} + + +void dviRenderer::prescan_removePageSizeInfo(char *cp, Q_UINT8 *beginningOfSpecialCommand) +{ +#ifdef DEBUG_PRESCAN + kdDebug(4300) << "dviRenderer::prescan_embedPS( cp = " << cp << " ) " << endl; +#endif + + // Encapsulated Postscript File + if (strncasecmp(cp, "papersize=", 10) != 0) + return; + + for (Q_UINT8 *ptr=beginningOfSpecialCommand; ptrtotal_pages; page++) + PS_interface->setBackgroundColor(page, col); + return; +} + + +void dviRenderer::prescan_ParseHTMLAnchorSpecial(const QString& _cp) +{ + QString cp = _cp; + cp.truncate(cp.find('"')); + Length l; + l.setLength_in_inch(currinf.data.dvi_v/(resolutionInDPI*shrinkfactor)); + anchorList[cp] = Anchor(current_page+1, l); +} + + +void dviRenderer::prescan_ParsePSHeaderSpecial(const QString& cp) +{ +#ifdef DEBUG_PRESCAN + kdDebug(4300) << "PostScript-special, header " << cp.latin1() << endl; +#endif + + QString _file = cp; + + // If the file is not found in the current directory, use kpsewhich + // to find it. + if (!QFile::exists(_file)) { + // Otherwise, use kpsewhich to find the eps file. + KProcIO proc; + proc << "kpsewhich" << cp; + proc.start(KProcess::Block); + proc.readln(_file); + } + + if (QFile::exists(_file)) + PS_interface->PostScriptHeaderString->append( QString(" (%1) run\n").arg(_file) ); +} + + +void dviRenderer::prescan_ParsePSBangSpecial(const QString& cp) +{ +#ifdef DEBUG_PRESCAN + kdDebug(4300) << "PostScript-special, literal header " << cp.latin1() << endl; +#endif + + PS_interface->PostScriptHeaderString->append( " @defspecial \n" ); + PS_interface->PostScriptHeaderString->append( cp ); + PS_interface->PostScriptHeaderString->append( " @fedspecial \n" ); +} + + +void dviRenderer::prescan_ParsePSQuoteSpecial(const QString& cp) +{ +#ifdef DEBUG_PRESCAN + kdError(4300) << "PostScript-special, literal PostScript " << cp.latin1() << endl; +#endif + + double PS_H = (currinf.data.dvi_h*300.0)/(65536*1200)-300; + double PS_V = (currinf.data.dvi_v*300.0)/1200 - 300; + PostScriptOutPutString->append( QString(" %1 %2 moveto\n").arg(PS_H).arg(PS_V) ); + PostScriptOutPutString->append( " @beginspecial @setspecial \n" ); + PostScriptOutPutString->append( cp ); + PostScriptOutPutString->append( " @endspecial \n" ); +} + + +void dviRenderer::prescan_ParsePSSpecial(const QString& cp) +{ +#ifdef DEBUG_PRESCAN + kdDebug(4300) << "PostScript-special, direct PostScript " << cp << endl; +#endif + + // Unfortunately, in some TeX distribution the hyperref package uses + // the dvips driver by default, rather than the hypertex driver. As + // a result, the DVI files produced are full of PostScript that + // specifies links and anchors, and KDVI would call the ghostscript + // interpreter for every page which makes it really slow. This is a + // major nuisance, so that we try to filter and interpret the + // hypertex generated PostScript here. + if (cp.startsWith("ps:SDict begin")) { + // We suspect this may be hyperref generated nonsense. Let's check + // for some known code that hyperref generates. + if (cp == "ps:SDict begin H.S end") + return; // start of hyperref rectangle + if (cp == "ps:SDict begin H.R end") + return; // end of hyperref rectangle + if (cp.endsWith("H.A end")) + return; // end of hyperref anchor + if (cp.endsWith("H.L end")) + return; // end of hyperref link + if (cp.startsWith("ps:SDict begin /product where{pop product(Distiller)")) + return; // hyperref tries to work around Distiller bug + if (cp.startsWith("ps:SDict begin [") && cp.endsWith(" pdfmark end")) { // hyperref definition of link/anchor/bookmark/etc + if (cp.contains("/DEST")) { // The PostScript code defines an anchor + QString anchorName = cp.section('(', 1, 1).section(')', 0, 0); + Length l; + l.setLength_in_inch(currinf.data.dvi_v/(resolutionInDPI*shrinkfactor)); + anchorList[anchorName] = Anchor(current_page+1, l); + } + // The PostScript code defines a bookmark + if (cp.contains("/Dest") && cp.contains("/Title")) + prebookmarks.append(PreBookmark(PDFencodingToQString(cp.section('(', 2, 2).section(')', 0, 0)), + cp.section('(', 1, 1).section(')', 0, 0), + cp.section('-', 1, 1).section(' ', 0, 0).toUInt() + )); + return; + } + } + + double PS_H = (currinf.data.dvi_h*300.0)/(65536*1200)-300; + double PS_V = (currinf.data.dvi_v*300.0)/1200 - 300; + + if (cp.find("ps::[begin]", 0, false) == 0) { + PostScriptOutPutString->append( QString(" %1 %2 moveto\n").arg(PS_H).arg(PS_V) ); + PostScriptOutPutString->append( QString(" %1\n").arg(cp.mid(11)) ); + } else { + if (cp.find("ps::[end]", 0, false) == 0) { + PostScriptOutPutString->append( QString(" %1\n").arg(cp.mid(9)) ); + } else { + if (cp.find("ps::", 0, false) == 0) { + PostScriptOutPutString->append( QString(" %1\n").arg(cp.mid(4)) ); + } else { + PostScriptOutPutString->append( QString(" %1 %2 moveto\n").arg(PS_H).arg(PS_V) ); + PostScriptOutPutString->append( QString(" %1\n").arg(cp.mid(3)) ); + } + } + } +} + + +void dviRenderer::prescan_ParsePSFileSpecial(const QString& cp) +{ +#ifdef DEBUG_PRESCAN + kdDebug(4300) << "epsf-special: psfile=" << cp <numberOfExternalNONPSFiles++; + return; + } + + // Now assume that the graphics file *is* a PostScript file + dviFile->numberOfExternalPSFiles++; + + // Now locate the Gfx file on the hard disk... + EPSfilename = ghostscript_interface::locateEPSfile(EPSfilename, baseURL); + + // If the EPSfilename really points to a PDF file, convert that file now. + if (ending == "pdf") + EPSfilename = dviFile->convertPDFtoPS(EPSfilename); + + // Now parse the arguments. + int llx = 0; + int lly = 0; + int urx = 0; + int ury = 0; + int rwi = 0; + int rhi = 0; + int angle = 0; + + // just to avoid ambiguities; the filename could contain keywords + include_command = include_command.mid(include_command.find(' ')); + + parse_special_argument(include_command, "llx=", &llx); + parse_special_argument(include_command, "lly=", &lly); + parse_special_argument(include_command, "urx=", &urx); + parse_special_argument(include_command, "ury=", &ury); + parse_special_argument(include_command, "rwi=", &rwi); + parse_special_argument(include_command, "rhi=", &rhi); + parse_special_argument(include_command, "angle=", &angle); + + int clip=include_command.find(" clip"); // -1 if clip keyword is not present, >= 0 otherwise + + if (QFile::exists(EPSfilename)) { + double PS_H = (currinf.data.dvi_h*300.0)/(65536*1200)-300; + double PS_V = (currinf.data.dvi_v*300.0)/1200 - 300; + PostScriptOutPutString->append( QString(" %1 %2 moveto\n").arg(PS_H).arg(PS_V) ); + PostScriptOutPutString->append( "@beginspecial " ); + PostScriptOutPutString->append( QString(" %1 @llx").arg(llx) ); + PostScriptOutPutString->append( QString(" %1 @lly").arg(lly) ); + PostScriptOutPutString->append( QString(" %1 @urx").arg(urx) ); + PostScriptOutPutString->append( QString(" %1 @ury").arg(ury) ); + if (rwi != 0) + PostScriptOutPutString->append( QString(" %1 @rwi").arg(rwi) ); + if (rhi != 0) + PostScriptOutPutString->append( QString(" %1 @rhi").arg(rhi) ); + if (angle != 0) + PostScriptOutPutString->append( QString(" %1 @angle").arg(angle) ); + if (clip != -1) + PostScriptOutPutString->append(" @clip"); + PostScriptOutPutString->append( " @setspecial \n" ); + PostScriptOutPutString->append( QString(" (%1) run\n").arg(EPSfilename) ); + PostScriptOutPutString->append( "@endspecial \n" ); + } + + return; +} + + +void dviRenderer::prescan_ParseSourceSpecial(const QString& cp) +{ + // if no rendering takes place, i.e. when the DVI file is first + // loaded, generate a DVI_SourceFileAnchor. These anchors are used + // in forward search, i.e. to relate references line + // "src:123file.tex" to positions in the DVI file + + // extract the file name and the numeral part from the string + Q_UINT32 j; + for(j=0;jfilename); + QString sourceFileName = QFileInfo(fi1.dir(), cp.mid(j).stripWhiteSpace()).absFilePath(); + Length l; + l.setLength_in_inch(currinf.data.dvi_v/(resolutionInDPI*shrinkfactor)); + DVI_SourceFileAnchor sfa(sourceFileName, sourceLineNumber, current_page+1, l); + sourceHyperLinkAnchors.push_back(sfa); +} + + +void dviRenderer::prescan_parseSpecials(char *cp, Q_UINT8 *) +{ + QString special_command(cp); + + // Now to those specials which are only interpreted during the + // prescan phase, and NOT during rendering. + + // PaperSize special + if (strncasecmp(cp, "papersize", 9) == 0) { + prescan_ParsePapersizeSpecial(special_command.mid(9)); + return; + } + + // color special for background color + if (strncasecmp(cp, "background", 10) == 0) { + prescan_ParseBackgroundSpecial(special_command.mid(10)); + return; + } + + // HTML anchor special + if (strncasecmp(cp, "html:", 9) == 0) { + html_anchor_end(); + return; + } + + return; +} + + +void dviRenderer::prescan_setChar(unsigned int ch) +{ + TeXFontDefinition *fontp = currinf.fontp; + if (fontp == NULL) + return; + + if (currinf.set_char_p == &dviRenderer::set_char) { + glyph *g = ((TeXFont *)(currinf.fontp->font))->getGlyph(ch, true, globalColor); + if (g == NULL) + return; + currinf.data.dvi_h += (int)(currinf.fontp->scaled_size_in_DVI_units * dviFile->getCmPerDVIunit() * + (1200.0 / 2.54)/16.0 * g->dvi_advance_in_units_of_design_size_by_2e20 + 0.5); + return; + } + + if (currinf.set_char_p == &dviRenderer::set_vf_char) { + macro *m = &currinf.fontp->macrotable[ch]; + if (m->pos == NULL) + return; + currinf.data.dvi_h += (int)(currinf.fontp->scaled_size_in_DVI_units * dviFile->getCmPerDVIunit() * + (1200.0 / 2.54)/16.0 * m->dvi_advance_in_units_of_design_size_by_2e20 + 0.5); + return; + } +} + + +void dviRenderer::prescan(parseSpecials specialParser) +{ +#ifdef DEBUG_PRESCAN + kdDebug(4300) << "dviRenderer::prescan( ... )" << endl; +#endif + + if (resolutionInDPI == 0.0) + setResolution(100); + + Q_INT32 RRtmp=0, WWtmp=0, XXtmp=0, YYtmp=0, ZZtmp=0; + Q_UINT8 ch; + double fontPixelPerDVIunit = dviFile->getCmPerDVIunit() * 1200.0/2.54; + + stack.clear(); + + currinf.fontp = NULL; + currinf.set_char_p = &dviRenderer::set_no_char; + + for (;;) { + ch = readUINT8(); + + if (ch <= (unsigned char) (SETCHAR0 + 127)) { + prescan_setChar(ch); + continue; + } + + if (FNTNUM0 <= ch && ch <= (unsigned char) (FNTNUM0 + 63)) { + currinf.fontp = currinf.fonttable->find(ch - FNTNUM0); + if (currinf.fontp == NULL) { + errorMsg = i18n("The DVI code referred to font #%1, which was not previously defined.").arg(ch - FNTNUM0); + return; + } + currinf.set_char_p = currinf.fontp->set_char_p; + continue; + } + + + Q_INT32 a, b; + + switch (ch) { + case SET1: + prescan_setChar(readUINT8()); + break; + + case SETRULE: + /* Be careful, dvicopy outputs rules with height = + 0x80000000. We don't want any SIGFPE here. */ + a = readUINT32(); + b = readUINT32(); + b = ((long) (b * 65536.0*fontPixelPerDVIunit)); + currinf.data.dvi_h += b; + break; + + case PUTRULE: + a = readUINT32(); + b = readUINT32(); + break; + + case PUT1: + case NOP: + break; + + case BOP: + command_pointer += 11 * 4; + currinf.data.dvi_h = 1200 << 16; // Reminder: DVI-coordinates start at (1",1") from top of page + currinf.data.dvi_v = 1200; + currinf.data.pxl_v = int(currinf.data.dvi_v/shrinkfactor); + currinf.data.w = currinf.data.x = currinf.data.y = currinf.data.z = 0; + break; + + case PUSH: + stack.push(currinf.data); + break; + + case POP: + if (stack.isEmpty()) + return; + else + currinf.data = stack.pop(); + break; + + case RIGHT1: + case RIGHT2: + case RIGHT3: + case RIGHT4: + RRtmp = readINT(ch - RIGHT1 + 1); + currinf.data.dvi_h += ((long) (RRtmp * 65536.0*fontPixelPerDVIunit)); + break; + + case W1: + case W2: + case W3: + case W4: + WWtmp = readINT(ch - W0); + currinf.data.w = ((long) (WWtmp * 65536.0*fontPixelPerDVIunit)); + case W0: + currinf.data.dvi_h += currinf.data.w; + break; + + case X1: + case X2: + case X3: + case X4: + XXtmp = readINT(ch - X0); + currinf.data.x = ((long) (XXtmp * 65536.0*fontPixelPerDVIunit)); + case X0: + currinf.data.dvi_h += currinf.data.x; + break; + + case DOWN1: + case DOWN2: + case DOWN3: + case DOWN4: + { + Q_INT32 DDtmp = readINT(ch - DOWN1 + 1); + currinf.data.dvi_v += ((long) (DDtmp * 65536.0*fontPixelPerDVIunit))/65536; + currinf.data.pxl_v = int(currinf.data.dvi_v/shrinkfactor); + } + break; + + case Y1: + case Y2: + case Y3: + case Y4: + YYtmp = readINT(ch - Y0); + currinf.data.y = ((long) (YYtmp * 65536.0*fontPixelPerDVIunit)); + case Y0: + currinf.data.dvi_v += currinf.data.y/65536; + currinf.data.pxl_v = int(currinf.data.dvi_v/shrinkfactor); + break; + + case Z1: + case Z2: + case Z3: + case Z4: + ZZtmp = readINT(ch - Z0); + currinf.data.z = ((long) (ZZtmp * 65536.0*fontPixelPerDVIunit)); + case Z0: + currinf.data.dvi_v += currinf.data.z/65536; + currinf.data.pxl_v = int(currinf.data.dvi_v/shrinkfactor); + break; + + case FNT1: + case FNT2: + case FNT3: + case FNT4: + currinf.fontp = currinf.fonttable->find(readUINT(ch - FNT1 + 1)); + if (currinf.fontp == NULL) + return; + currinf.set_char_p = currinf.fontp->set_char_p; + break; + + case XXX1: + case XXX2: + case XXX3: + case XXX4: + { + Q_UINT8 *beginningOfSpecialCommand = command_pointer-1; + a = readUINT(ch - XXX1 + 1); + if (a > 0) { + char *cmd = new char[a+1]; + strncpy(cmd, (char *)command_pointer, a); + command_pointer += a; + cmd[a] = '\0'; + (this->*specialParser)(cmd, beginningOfSpecialCommand); + delete [] cmd; + } + } + break; + + case FNTDEF1: + case FNTDEF2: + case FNTDEF3: + case FNTDEF4: + command_pointer += 12 + ch - FNTDEF1 + 1; + command_pointer += readUINT8() + readUINT8(); + break; + + default: + return; + } /* end switch */ + } /* end for */ +} diff --git a/kdvi/dviWidget.cpp b/kdvi/dviWidget.cpp new file mode 100644 index 00000000..8475af92 --- /dev/null +++ b/kdvi/dviWidget.cpp @@ -0,0 +1,123 @@ +// +// Class: DVIWidget +// +// Widget for displaying TeX DVI files. +// Part of KDVI- A previewer for TeX DVI files. +// +// (C) 2004 Wilfried Huss, Stefan Kebekus +// Distributed under the GPL +// + +#include + +#include +#include + +#include "dviWidget.h" + +#include "documentPageCache.h" +#include "documentWidget.h" +#include "hyperlink.h" +#include "pageView.h" +#include "renderedDviPagePixmap.h" +#include "selection.h" + +DVIWidget::DVIWidget(QWidget* parent, PageView* sv, DocumentPageCache* cache, const char* name) + : DocumentWidget(parent, sv, cache, name) +{ +} + + +void DVIWidget::mousePressEvent(QMouseEvent* e) +{ + // pageNr == 0 indicated an invalid page (e.g. page number not yet set) + if (pageNr == 0) + return; + + // Get a pointer to the page contents + RenderedDviPagePixmap* pageData = dynamic_cast(documentCache->getPage(pageNr)); + if (pageData == 0) + { + kdDebug(4300) << "DVIWidget::mousePressEvent(...) pageData for page #" << pageNr << " is empty" << endl; + return; + } + + // Check if the mouse is pressed on a source-hyperlink + // source hyperlinks can be invoked with the Middle Mousebutton or alternatively + // with Control+Left Mousebutton + if ((e->button() == MidButton || (e->button() == LeftButton && (e->state() & ControlButton))) + && (pageData->sourceHyperLinkList.size() > 0)) + { + int minIndex = 0; + int minimum = 0; + + for(unsigned int i=0; isourceHyperLinkList.size(); i++) + { + if (pageData->sourceHyperLinkList[i].box.contains(e->pos())) + { + emit(SRCLink(pageData->sourceHyperLinkList[i].linkText, e, this)); + e->accept(); + return; + } + // Remember the closest source link + QPoint center = pageData->sourceHyperLinkList[i].box.center(); + int dx = center.x() - e->pos().x(); + int dy = center.y() - e->pos().y(); + if (dx*dx + dy*dy < minimum || i == 0) + { + minIndex = i; + minimum = dx*dx + dy*dy; + } + } + // If the mouse pointer is not exactly inside a source link, jump to the closest target. + emit(SRCLink(pageData->sourceHyperLinkList[minIndex].linkText, e, this)); + e->accept(); + } + + // Call implementation from parent + DocumentWidget::mousePressEvent(e); +} + + +void DVIWidget::mouseMoveEvent(QMouseEvent* e) +{ + // pageNr == 0 indicated an invalid page (e.g. page number not yet set) + if (pageNr == 0) + return; + + // Call the standard implementation + DocumentWidget::mouseMoveEvent(e); + + // Analyze the mouse movement only if no mouse button was pressed + if ( e->state() == 0 ) { + // Get a pointer to the page contents + RenderedDviPagePixmap* pageData = dynamic_cast(documentCache->getPage(pageNr)); + if (pageData == 0) { + kdDebug(4300) << "DVIWidget::mouseMoveEvent(...) pageData for page #" << pageNr << " is empty" << endl; + return; + } + + // Check if the cursor hovers over a sourceHyperlink. + for(unsigned int i=0; isourceHyperLinkList.size(); i++) { + if (pageData->sourceHyperLinkList[i].box.contains(e->pos())) { + clearStatusBarTimer.stop(); + + // The macro-package srcltx gives a special like "src:99 test.tex" + // while MikTeX gives "src:99test.tex". KDVI tries + // to understand both. + QString cp = pageData->sourceHyperLinkList[i].linkText; + int max = cp.length(); + int i; + for(i=0; i, (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// + +#include + +#include +#include + +#include "dvisourcesplitter.h" + +//#define DEBUG_SOURCESPLITTER + + +DVI_SourceFileSplitter::DVI_SourceFileSplitter(const QString &srclink, const QString &dviFile) +{ + QString filepart = srclink, linepart; + bool possibleNumberMixUp = false; //if sourcefilename starts with a number + //then there could be a mix up, i.e. src:123file.tex + //line 123 and file.tex or line 12 and 3file.tex? + +#ifdef DEBUG_SOURCESPLITTER + kdDebug(4300) << "DVI_SourceSplitter: srclink " << srclink << endl; +#endif + + //remove src: if necessary + if ( filepart.left(4) == "src:" ) filepart = srclink.mid(4); + + //split first + Q_UINT32 max = filepart.length(), i = 0; + for(i=0; i, (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// + +#ifndef DVI_SOURCEFILESPLITTER_H +#define DVI_SOURCEFILESPLITTER_H + +#include + +class QString; + + +class DVI_SourceFileSplitter +{ +public: + DVI_SourceFileSplitter(const QString & scrlink, const QString & dviFile); + + QString fileName() { return m_fileInfo.fileName(); } + QString filePath() { return m_fileInfo.absFilePath(); } + bool fileExists() { return m_fileInfo.exists(); } + + Q_UINT32 line() { return m_line; } + +private: + QFileInfo m_fileInfo; + Q_UINT32 m_line; + bool m_exists; +}; +#endif diff --git a/kdvi/examples/BrokenDVI1.dvi b/kdvi/examples/BrokenDVI1.dvi new file mode 100644 index 00000000..4f189853 Binary files /dev/null and b/kdvi/examples/BrokenDVI1.dvi differ diff --git a/kdvi/examples/Font_not_found.dvi b/kdvi/examples/Font_not_found.dvi new file mode 100644 index 00000000..4ba6383f Binary files /dev/null and b/kdvi/examples/Font_not_found.dvi differ diff --git a/kdvi/examples/dvistd0.dvi b/kdvi/examples/dvistd0.dvi new file mode 100644 index 00000000..ef73e604 Binary files /dev/null and b/kdvi/examples/dvistd0.dvi differ diff --git a/kdvi/fontEncoding.cpp b/kdvi/fontEncoding.cpp new file mode 100644 index 00000000..0ca83372 --- /dev/null +++ b/kdvi/fontEncoding.cpp @@ -0,0 +1,87 @@ +// fontEncoding.cpp +// +// Part of KDVI - A DVI previewer for the KDE desktop environemt +// +// (C) 2003 Stefan Kebekus +// Distributed under the GPL + +#include +#ifdef HAVE_FREETYPE + +#include +#include +#include +#include + +#include "fontEncoding.h" + +//#define DEBUG_FONTENC + +fontEncoding::fontEncoding(const QString &encName) +{ +#ifdef DEBUG_FONTENC + kdDebug(4300) << "fontEncoding( " << encName << " )" << endl; +#endif + + _isValid = false; + // Use kpsewhich to find the encoding file. + KProcIO proc; + QString encFileName; + proc << "kpsewhich" << encName; + if (proc.start(KProcess::Block) == false) { + kdError(4300) << "fontEncoding::fontEncoding(...): kpsewhich could not be started." << endl; + return; + } + proc.readln(encFileName); + encFileName = encFileName.stripWhiteSpace(); + + if (encFileName.isEmpty()) { + kdError(4300) << QString("fontEncoding::fontEncoding(...): The file '%1' could not be found by kpsewhich.").arg(encName) << endl; + return; + } + +#ifdef DEBUG_FONTENC + kdDebug(4300) << "FileName of the encoding: " << encFileName << endl; +#endif + + QFile file( encFileName ); + if ( file.open( IO_ReadOnly ) ) { + // Read the file (excluding comments) into the QString variable + // 'fileContent' + QTextStream stream( &file ); + QString fileContent; + while ( !stream.atEnd() ) + fileContent += stream.readLine().section('%', 0, 0); // line of text excluding '\n' until first '%'-sign + file.close(); + + fileContent = fileContent.stripWhiteSpace(); + + // Find the name of the encoding + encodingFullName = fileContent.section('[', 0, 0).simplifyWhiteSpace().mid(1); +#ifdef DEBUG_FONTENC + kdDebug(4300) << "encodingFullName: " << encodingFullName << endl; +#endif + + fileContent = fileContent.section('[', 1, 1).section(']',0,0).simplifyWhiteSpace(); + QStringList glyphNameList = QStringList::split( '/', fileContent ); + + int i = 0; + for ( QStringList::Iterator it = glyphNameList.begin(); (it != glyphNameList.end())&&(i<256); ++it ) { + glyphNameVector[i] = (*it).simplifyWhiteSpace(); +#ifdef DEBUG_FONTENC + kdDebug(4300) << i << ": " << glyphNameVector[i] << endl; +#endif + i++; + } + for(; i<256; i++) + glyphNameVector[i] = ".notdef"; + } else { + kdError(4300) << QString("fontEncoding::fontEncoding(...): The file '%1' could not be opened.").arg(encFileName) << endl; + return; + } + + _isValid = true; +} + + +#endif // HAVE_FREETYPE diff --git a/kdvi/fontEncoding.h b/kdvi/fontEncoding.h new file mode 100644 index 00000000..b5ca1344 --- /dev/null +++ b/kdvi/fontEncoding.h @@ -0,0 +1,86 @@ +// -*- C++ -*- +// fontEncoding.h +// +// Part of KDVI - A DVI previewer for the KDE desktop environemt +// +// (C) 2003 Stefan Kebekus +// Distributed under the GPL + +#ifndef _FONTENCODING_H +#define _FONTENCODING_H + +#include + + +/** + * This class represents the contents of a font encoding file, + * e.g. "8r.enc" + * + * Explanation of font encodings: TeX was designed to only use + * MetaFont fonts. A DVI file referres to a MetaFont font by giving an + * at-most-8-character name, such as 'cmr10'. The DVI previewer would + * then locate the associated PK font file (e.g. cmr10.600pk), load + * it, and retrieve the character shaped. + * + * Today TeX is also used to access Type1 and TrueType fonts, which it + * was never designed to do. As in the case of MetaFont font, the DVI + * file specifies the name of a font, e.g. 'rpbkd', and the DVI + * previewer finds the associated font file 'ubkd8a.pfb' by means of a + * map file (see fontMap.h). The font map file also specifies an + * encoding (e.g. '8r', to be found in a file '8r.enc'). Font + * encodings are necessary because TeX can only use the first 256 + * characters of a font, while modern PostScript fonts often contain + * more. + * + * In a PostScript font, glyphs can often be accessed in two ways: + * + * (a) by an integer, the 'glyph index', which need not be + * positive. Glyph indices can be found in every font. + * + * (b) by the name of the glyph, such as 'A', 'plusminus' or + * 'ogonek'. Note: Not all fonts contain glyph names, and if a font + * contains glyph names, they are not always reliable. + * + * An encoding file is essentially a list of 256 names of glyphs that + * TeX wishes to use from a certain font. If the font contains more + * than 256 glyphs, TeX is still limited to use at most 256 glyphs. If + * more glyphs are required, TeX can probably use the same font under + * a different name and with a different encoding ---the map file + * (fontMap.h) can probably see to that. + * + * Summing up: this class contains 256 glyph names read from an + * encoding file during the construction of this class. + * + * @author Stefan Kebekus + * + **/ + +class fontEncoding { + public: + // The constructor takes the name of an encoding file, such as + // '8r.enc', locate the file on the hard disk using the 'kpsewhich' + // command, reads it in and parses it. If the file cannot be + // located, opened or parsed, errors are printed using the kdError() + // channel, and the array glyphNameVector will contain empty + // strings. + fontEncoding(const QString &encName); + + // Full name of the encoding, as read from the encoding file + QString encodingFullName; + + // List of 256 glyph names. The name can be '.notdef' to indicate + // that a certain position is left open, or empty, if the encoding + // file did not contain 256 characters or could not be properly read + QString glyphNameVector[256]; + + // Returns 'true' if the encoding file was found and could + // successfully be loaded. + bool isValid() {return _isValid;} + + private: + // Set by the constructor to 'true', if the encoding file was found + // and could be loaded successfully. + bool _isValid; +}; + +#endif diff --git a/kdvi/fontEncodingPool.cpp b/kdvi/fontEncodingPool.cpp new file mode 100644 index 00000000..0100ee90 --- /dev/null +++ b/kdvi/fontEncodingPool.cpp @@ -0,0 +1,37 @@ +// fontEncodingPool.cpp +// +// Part of KDVI - A DVI previewer for the KDE desktop environemt +// +// (C) 2003 Stefan Kebekus +// Distributed under the GPL + +#include +#ifdef HAVE_FREETYPE + + +#include "fontEncodingPool.h" + +fontEncodingPool::fontEncodingPool() +{ +} + + +fontEncoding *fontEncodingPool::findByName(const QString &name) +{ + fontEncoding *ptr = dictionary.find( name ); + + if (ptr == 0) { + ptr = new fontEncoding(name); + if (ptr->isValid()) + dictionary.insert(name, ptr ); + else { + delete ptr; + ptr = 0; + } + } + + return ptr; +} + + +#endif // HAVE_FREETYPE diff --git a/kdvi/fontEncodingPool.h b/kdvi/fontEncodingPool.h new file mode 100644 index 00000000..b875bf52 --- /dev/null +++ b/kdvi/fontEncodingPool.h @@ -0,0 +1,29 @@ +// -*- C++ -*- +// fontEncodingPool.h +// +// Part of KDVI - A DVI previewer for the KDE desktop environemt +// +// (C) 2003 Stefan Kebekus +// Distributed under the GPL + +#ifndef _FONTENCODINGPOOL_H +#define _FONTENCODINGPOOL_H + +#include "fontEncoding.h" + +#include + +class QString; + + +class fontEncodingPool { + public: + fontEncodingPool(); + + fontEncoding *findByName(const QString &name); + + private: + QDict dictionary; +}; + +#endif diff --git a/kdvi/fontMap.cpp b/kdvi/fontMap.cpp new file mode 100644 index 00000000..cf5fa841 --- /dev/null +++ b/kdvi/fontMap.cpp @@ -0,0 +1,159 @@ +// fontMap.cpp +// +// Part of KDVI - A DVI previewer for the KDE desktop environemt +// +// (C) 2003 Stefan Kebekus +// Distributed under the GPL + +#include +#ifdef HAVE_FREETYPE + +#include +#include +#include + +#include "fontMap.h" + +//#define DEBUG_FONTMAP + +fontMap::fontMap() +{ + // Read the map file of ps2pk which will provide us with a + // dictionary "TeX Font names" <-> "Name of font files, Font Names + // and Encodings" (example: the font "Times-Roman" is called + // "ptmr8y" in the DVI file, but the Type1 font file name is + // "utmr8a.pfb". We use the map file of "ps2pk" because that progam + // has, like kdvi (and unlike dvips), no built-in fonts. + + // Finding ps2pk.map is not easy. In teTeX < 3.0, the kpsewhich + // program REQUIRES the option "--format=dvips config". In teTeX = + // 3.0, the option "--format=map" MUST be used. Since there is no + // way to give both options at the same time, there is seemingly no + // other way than to try both options one after another. We use the + // teTeX 3.0 format first. + KProcIO proc; + proc << "kpsewhich" << "--format=map" << "ps2pk.map"; + if (proc.start(KProcess::Block) == false) { + kdError(4700) << "fontMap::fontMap(): kpsewhich could not be started." << endl; + return; + } + + QString map_fileName; + proc.readln(map_fileName); + map_fileName = map_fileName.stripWhiteSpace(); + if (map_fileName.isEmpty()) { + // Map file not found? Then we try the teTeX < 3.0 way of finding + // the file. + proc << "kpsewhich" << "--format=dvips config" << "ps2pk.map"; + if (proc.start(KProcess::Block) == false) { + kdError(4700) << "fontMap::fontMap(): kpsewhich could not be started." << endl; + return; + } + proc.readln(map_fileName); + map_fileName = map_fileName.stripWhiteSpace(); + + // If both versions fail, then there is nothing left to do. + if (map_fileName.isEmpty()) { + kdError(4700) << "fontMap::fontMap(): The file 'ps2pk.map' could not be found by kpsewhich." << endl; + return; + } + } + + QFile file( map_fileName ); + if ( file.open( IO_ReadOnly ) ) { + QTextStream stream( &file ); + QString line; + while ( !stream.atEnd() ) { + line = stream.readLine().simplifyWhiteSpace(); + if (line.at(0) == '%') + continue; + + QString TeXName = line.section(' ', 0, 0); + QString FullName = line.section(' ', 1, 1); + QString fontFileName = line.section('<', -1).stripWhiteSpace().section(' ', 0, 0); + QString encodingName = line.section('<', -2, -2).stripWhiteSpace().section(' ', 0, 0); + // It seems that sometimes the encoding is prepended by the + // letter '[', which we ignore + if ((!encodingName.isEmpty()) && (encodingName[0] == '[')) + encodingName = encodingName.mid(1); + + double slant = 0.0; + int i = line.find("SlantFont"); + if (i >= 0) { + bool ok; + slant = line.left(i).section(' ', -1, -1 ,QString::SectionSkipEmpty).toDouble(&ok); + if (ok == false) + slant = 0.0; + } + + fontMapEntry &entry = fontMapEntries[TeXName]; + + entry.slant = slant; + entry.fontFileName = fontFileName; + entry.fullFontName = FullName; + if (encodingName.endsWith(".enc")) + entry.fontEncoding = encodingName; + else + entry.fontEncoding = QString::null; + } + file.close(); + } else + kdError(4300) << QString("fontMap::fontMap(): The file '%1' could not be opened.").arg(map_fileName) << endl; + +#ifdef DEBUG_FONTMAP + kdDebug(4300) << "FontMap file parsed. Results:" << endl; + QMap::Iterator it; + for ( it = fontMapEntries.begin(); it != fontMapEntries.end(); ++it ) + kdDebug(4300) << "TeXName: " << it.key() + << ", FontFileName=" << it.data().fontFileName + << ", FullName=" << it.data().fullFontName + << ", Encoding=" << it.data().fontEncoding + << "." << endl;; +#endif +} + + +const QString &fontMap::findFileName(const QString &TeXName) +{ + QMap::Iterator it = fontMapEntries.find(TeXName); + + if (it != fontMapEntries.end()) + return it.data().fontFileName; + else + return QString::null; +} + + +const QString &fontMap::findFontName(const QString &TeXName) +{ + QMap::Iterator it = fontMapEntries.find(TeXName); + + if (it != fontMapEntries.end()) + return it.data().fullFontName; + else + return QString::null; +} + + +const QString &fontMap::findEncoding(const QString &TeXName) +{ + QMap::Iterator it = fontMapEntries.find(TeXName); + + if (it != fontMapEntries.end()) + return it.data().fontEncoding; + else + return QString::null; +} + + +double fontMap::findSlant(const QString &TeXName) +{ + QMap::Iterator it = fontMapEntries.find(TeXName); + + if (it != fontMapEntries.end()) + return it.data().slant; + else + return 0.0; +} + +#endif // HAVE_FREETYPE diff --git a/kdvi/fontMap.h b/kdvi/fontMap.h new file mode 100644 index 00000000..55e44082 --- /dev/null +++ b/kdvi/fontMap.h @@ -0,0 +1,118 @@ +// -*- C++ -*- +// fontMap.h +// +// Part of KDVI - A DVI previewer for the KDE desktop environemt +// +// (C) 2003 Stefan Kebekus +// Distributed under the GPL + +#ifndef _FONTMAP_H +#define _FONTMAP_H + +#include +#include + +/** + * This class represents one line of a font map file, and contains + * three pieces of information about a font: its file name, the full + * name of the font, and the encoding. + * + * @author Stefan Kebekus + **/ + +class fontMapEntry { + public: + // File name of the font WITHOUT the path. The full path name must + // be looked by using the kpathsea library, e.g. by means of the + // kpsewhich command. A valid entry would be 'ubkd8a.pfb' + QString fontFileName; + + // This string contains the full name of the font, + // e.g. 'URWBookmanL-DemiBold' + QString fullFontName; + + // If the font requires an encoding (see fontEncoding.h for an + // explanation), this string is not empty and contains the name of + // the encoding, e.g. '8r'. The path of the associated encoding file + // (on the author's machine: /usr/share/texmf/dvips/psnfss/8r.enc) + // must be looked up using the kpsewhich comman. + QString fontEncoding; + + // Some fonts need to be slanted, and the font map file defines by + // how much. This field is set to 0.0 if no slanting is specified in + // the map file. + double slant; +}; + + +/** + * This class represents the contents of the font map file "ps2pk.map" + * + * A font map file is part of the machinery that make it possible to + * access PostScript (and possibly also TrueType and OpenType) fonts + * from a DVI file. + * + * Long time ago, when TeX was only used with MetaFont fonts, the DVI + * file would specify a font by giving an 8-character name, such as + * 'cmr10'. The DVI previewer would then locate the associated PK font + * file, load it, and retrieve the character shaped. Happy times, they + * were. + * + * Today TeX is also used to access Type1 and TrueType fonts, which do + * not fit well into the TeX naming scheme. Like in earlier times, the + * DVI file specifies the name of a font, e.g. 'rpbkd', but nowadays + * the DVI previewer cannot just go and find a file 'rpbkd.pk'. No, + * no. Instead, the DVI previewr needs to look up the meaning of + * 'rpbkd' in a map-file. There it finds that 'rpbkd' refers to a font + * called 'URWBookmanL-DemiBold', to be found under the file name + * 'ubkd8a.pfb' whose glyphs are to be encoded using the '8a' encoding + * file (see the header file 'fontEncoding.h' for more information + * about encodings) + * + * Such map files exists for all dvi output drivers that are part of + * the TeX distribution that is installed on your + * computer. Unfortunately, KDVI is not part of a TeX distribution, + * and therefore does not have its own map file. As a workaround, KDVI + * uses the map file of the program ps2pk which is similar to KDVI in + * that the ps2pk driver does not have built-in fonts, unlike the + * PostScript printers for which dvips is used. + * + * @author Stefan Kebekus + * + **/ + +class fontMap { + public: + /** The default constructor will try to locate the file 'ps2pk.map', + and read its contents. If the file 'ps2pk.map' cannot be found + using the kpsewhich command, or if it cannot be read, or is + (partially) in an improper format, an error message is printed + to stderr using the kdDebug() stream. */ + fontMap( void ); + + /** find the name of a font file (e.g. 'ubkd8a.pfb') from a TeX font + name (e.g. 'rpbkd'). This method return a reference to + QString::null if the font could not be found. */ + const QString &findFileName(const QString &TeXName); + + /** find the name of a font (e.g. 'URWBookmanL-DemiBold') from a TeX + font name (e.g. 'rpbkd'). This method return a reference to + QString::null if the font could not be found. */ + const QString &findFontName(const QString &TeXName); + + /** find the name of an encoding file for a font (e.g. '8r') from a + TeX font name (e.g. 'rpbkd'). This method return a reference to + QString::null if the font could not be found. */ + const QString &findEncoding(const QString &TeXName); + + /** This method finds the slant of a font. Returns 0.0 if no slant + was defined. */ + double findSlant(const QString &TeXName); + + private: + /** This member maps TeX font names mapEntry classes that contain + the font's filenames, full font names and encodings. */ + QMap fontMapEntries; +}; + +#endif // ifndef _FONTMAP_H diff --git a/kdvi/fontpool.cpp b/kdvi/fontpool.cpp new file mode 100644 index 00000000..adec497b --- /dev/null +++ b/kdvi/fontpool.cpp @@ -0,0 +1,597 @@ +// +// fontpool.cpp +// +// (C) 2001-2004 Stefan Kebekus +// Distributed under the GPL + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fontpool.h" +#include "performanceMeasurement.h" +#include "prefs.h" +#include "TeXFont.h" + +//#define DEBUG_FONTPOOL + + + +// List of permissible MetaFontModes which are supported by kdvi. + +//const char *MFModes[] = { "cx", "ljfour", "lexmarks" }; +//const char *MFModenames[] = { "Canon CX", "LaserJet 4", "Lexmark S" }; +//const int MFResolutions[] = { 300, 600, 1200 }; + +#ifdef PERFORMANCE_MEASUREMENT +QTime fontPoolTimer; +bool fontPoolTimerFlag; +#endif + +//#define DEBUG_FONTPOOL + +fontPool::fontPool() + : progress( "fontgen", // Chapter in the documentation for help. + i18n( "KDVI is currently generating bitmap fonts..." ), + i18n( "Aborts the font generation. Don't do this." ), + i18n( "KDVI is currently generating bitmap fonts which are needed to display your document. " + "For this, KDVI uses a number of external programs, such as MetaFont. You can find " + "the output of these programs later in the document info dialog." ), + i18n( "KDVI is generating fonts. Please wait." ), + 0 ) +{ +#ifdef DEBUG_FONTPOOL + kdDebug(4300) << "fontPool::fontPool() called" << endl; +#endif + + setName("Font Pool"); + + displayResolution_in_dpi = 100.0; // A not-too-bad-default + useFontHints = true; + CMperDVIunit = 0; + extraSearchPath = QString::null; + fontList.setAutoDelete(true); + + +#ifdef HAVE_FREETYPE + // Initialize the Freetype Library + if ( FT_Init_FreeType( &FreeType_library ) != 0 ) { + kdError(4300) << "Cannot load the FreeType library. KDVI proceeds without FreeType support." << endl; + FreeType_could_be_loaded = false; + } else + FreeType_could_be_loaded = true; +#endif + + // Check if the QT library supports the alpha channel of + // pixmaps. Experiments show that --depending of the configuration + // of QT at compile and runtime or the availability of the XFt + // extension, alpha channels are either supported, or silently + // converted to 1-bit masks. + QImage start(1, 1, 32); // Generate a 1x1 image, black with alpha=0x10 + start.setAlphaBuffer(true); + Q_UINT32 *destScanLine = (Q_UINT32 *)start.scanLine(0); + *destScanLine = 0x80000000; + QPixmap intermediate(start); + QPixmap dest(1,1); + dest.fill(Qt::white); + QPainter paint( &dest ); + paint.drawPixmap(0, 0, intermediate); + paint.end(); + start = dest.convertToImage().convertDepth(32); + Q_UINT8 result = *(start.scanLine(0)) & 0xff; + + if ((result == 0xff) || (result == 0x00)) { +#ifdef DEBUG_FONTPOOL + kdDebug(4300) << "fontPool::fontPool(): QPixmap does not support the alpha channel" << endl; +#endif + QPixmapSupportsAlpha = false; + } else { +#ifdef DEBUG_FONTPOOL + kdDebug(4300) << "fontPool::fontPool(): QPixmap supports the alpha channel" << endl; +#endif + QPixmapSupportsAlpha = true; + } +} + + +fontPool::~fontPool() +{ +#ifdef DEBUG_FONTPOOL + kdDebug(4300) << "fontPool::~fontPool() called" << endl; +#endif + + // need to manually clear the fonts _before_ freetype gets unloaded + fontList.clear(); + +#ifdef HAVE_FREETYPE + if (FreeType_could_be_loaded == true) + FT_Done_FreeType( FreeType_library ); +#endif +} + + +void fontPool::setParameters( bool _useFontHints ) +{ + // Check if glyphs need to be cleared + if (_useFontHints != useFontHints) { + double displayResolution = displayResolution_in_dpi; + TeXFontDefinition *fontp = fontList.first(); + while(fontp != 0 ) { + fontp->setDisplayResolution(displayResolution * fontp->enlargement); + fontp=fontList.next(); + } + } + + useFontHints = _useFontHints; +} + + +TeXFontDefinition* fontPool::appendx(const QString& fontname, Q_UINT32 checksum, Q_UINT32 scale, double enlargement) +{ + // Reuse font if possible: check if a font with that name and + // natural resolution is already in the fontpool, and use that, if + // possible. + TeXFontDefinition *fontp = fontList.first(); + while( fontp != 0 ) { + if ((fontname == fontp->fontname) && ( (int)(enlargement*1000.0+0.5)) == (int)(fontp->enlargement*1000.0+0.5)) { + // if font is already in the list + fontp->mark_as_used(); + return fontp; + } + fontp=fontList.next(); + } + + // If font doesn't exist yet, we have to generate a new font. + + double displayResolution = displayResolution_in_dpi; + + fontp = new TeXFontDefinition(fontname, displayResolution*enlargement, checksum, scale, this, enlargement); + if (fontp == 0) { + kdError(4300) << i18n("Could not allocate memory for a font structure!") << endl; + exit(0); + } + fontList.append(fontp); + +#ifdef PERFORMANCE_MEASUREMENT + fontPoolTimer.start(); + fontPoolTimerFlag = false; +#endif + + // Now start kpsewhich/MetaFont, etc. if necessary + return fontp; +} + + +QString fontPool::status() +{ +#ifdef DEBUG_FONTPOOL + kdDebug(4300) << "fontPool::status() called" << endl; +#endif + + QString text; + QStringList tmp; + + if (fontList.isEmpty()) + return i18n("The fontlist is currently empty."); + + text.append(""); + text.append( QString("") + .arg(i18n("TeX Name")) + .arg(i18n("Family")) + .arg(i18n("Zoom")) + .arg(i18n("Type")) + .arg(i18n("Encoding")) + .arg(i18n("Comment")) ); + + TeXFontDefinition *fontp = fontList.first(); + while ( fontp != 0 ) { + QString errMsg, encoding; + + if (!(fontp->flags & TeXFontDefinition::FONT_VIRTUAL)) { +#ifdef HAVE_FREETYPE + encoding = fontp->getFullEncodingName(); +#endif + if (fontp->font != 0) + errMsg = fontp->font->errorMessage; + else + errMsg = i18n("Font file not found"); + } + +#ifdef HAVE_FREETYPE + tmp << QString ("") + .arg(fontp->fontname) + .arg(fontp->getFullFontName()) + .arg((int)(fontp->enlargement*100 + 0.5)) + .arg(fontp->getFontTypeName()) + .arg(encoding) + .arg(errMsg); +#endif + + fontp=fontList.next(); + } + + tmp.sort(); + text.append(tmp.join("\n")); + text.append("
%1 %2 %3 %4 %5 %6
%1 %2 %3% %4 %5 %6
"); + + return text; +} + + +bool fontPool::areFontsLocated() +{ +#ifdef DEBUG_FONTPOOL + kdDebug(4300) << "fontPool::areFontsLocated() called" << endl; +#endif + + // Is there a font whose name we did not try to find out yet? + TeXFontDefinition *fontp = fontList.first(); + while( fontp != 0 ) { + if ( !fontp->isLocated() ) + return false; + fontp=fontList.next(); + } + +#ifdef DEBUG_FONTPOOL + kdDebug(4300) << "... yes, all fonts are located (but not necessarily loaded)." << endl; +#endif + return true; // That says that all fonts are located. +} + + +void fontPool::locateFonts() +{ + kpsewhichOutput = QString::null; + + // First, we try and find those fonts which exist on disk + // already. If virtual fonts are found, they will add new fonts to + // the list of fonts whose font files need to be located, so that we + // repeat the lookup. + bool vffound; + do { + vffound = false; + locateFonts(false, false, &vffound); + } while(vffound); + + // If still not all fonts are found, look again, this time with + // on-demand generation of PK fonts enabled. + if (!areFontsLocated()) + locateFonts(true, false); + + // If still not all fonts are found, we look for TFM files as a last + // resort, so that we can at least draw filled rectangles for + // characters. + if (!areFontsLocated()) + locateFonts(false, true); + + // If still not all fonts are found, we give up. We mark all fonts + // as 'located', so that wee won't look for them any more, and + // present an error message to the user. + if (!areFontsLocated()) { + markFontsAsLocated(); + QString details = QString("

PATH: %1

%2
").arg(getenv("PATH")).arg(kpsewhichOutput); + KMessageBox::detailedError( 0, i18n("

KDVI was not able to locate all the font files " + "which are necessary to display the current DVI file. " + "Your document might be unreadable.

"), + details, + i18n("Not All Font Files Found") ); + } +} + + +void fontPool::locateFonts(bool makePK, bool locateTFMonly, bool *virtualFontsFound) +{ + // Set up the kpsewhich process. If pass == 0, look for vf-fonts and + // disable automatic font generation as vf-fonts can't be + // generated. If pass == 0, ennable font generation, if it was + // enabled globally. + emit setStatusBarText(i18n("Locating fonts...")); + + QStringList shellProcessCmdLine; + + KProcIO kpsewhichIO; + // If PK fonts are generated, the kpsewhich command will re-route + // the output of MetaFont into its stderr. Here we make sure this + // output is intercepted and parsed. + qApp->connect(&kpsewhichIO, SIGNAL(receivedStderr(KProcess *, char *, int)), + this, SLOT(mf_output_receiver(KProcess *, char *, int))); + + + kpsewhichIO.setUseShell(true); + + // Now generate the command line for the kpsewhich + // program. Unfortunately, this can be rather long and involved... + shellProcessCmdLine += "kpsewhich"; + shellProcessCmdLine += QString("--dpi 1200"); + shellProcessCmdLine += QString("--mode lexmarks"); + + // Disable automatic pk-font generation. + if (makePK == true) + shellProcessCmdLine += "--mktex pk"; + else + shellProcessCmdLine += "--no-mktex pk"; + + // Names of fonts that shall be located + Q_UINT16 numFontsInJob = 0; + TeXFontDefinition *fontp = fontList.first(); + while ( fontp != 0 ) { + if (!fontp->isLocated()) { + numFontsInJob++; + + if (locateTFMonly == true) + shellProcessCmdLine += KShellProcess::quote(QString("%1.tfm").arg(fontp->fontname)); + else { +#ifdef HAVE_FREETYPE + if (FreeType_could_be_loaded == true) { + const QString &filename = fontsByTeXName.findFileName(fontp->fontname); + if (!filename.isEmpty()) + shellProcessCmdLine += KShellProcess::quote(QString("%1").arg(filename)); + } +#endif + shellProcessCmdLine += KShellProcess::quote(QString("%1.vf").arg(fontp->fontname)); + shellProcessCmdLine += KShellProcess::quote(QString("%1.1200pk").arg(fontp->fontname)); + } + } + fontp=fontList.next(); + } + + if (numFontsInJob == 0) + return; + + progress.setTotalSteps(numFontsInJob, &kpsewhichIO); + + // Now run... kpsewhich. In case of error, kick up a fuss. + MetafontOutput = QString::null; + kpsewhichOutput += "

"+shellProcessCmdLine.join(" ")+"

"; + kpsewhichIO << shellProcessCmdLine; + QString importanceOfKPSEWHICH = i18n("

KDVI relies on the kpsewhich program to locate font files " + "on your hard disc and to generate PK fonts, if necessary.

"); + if (kpsewhichIO.start(KProcess::NotifyOnExit, false) == false) { + QString msg = i18n( "

The shell process for the kpsewhich program could not " + "be started. Consequently, some font files could not be found, " + "and your document might by unreadable. If this error is reproducable " + "please report the issue to the KDVI developers using the 'Help' menu.

" ); + QApplication::restoreOverrideCursor(); + KMessageBox::error( 0, QString("%1%2").arg(importanceOfKPSEWHICH).arg(msg), + i18n("Problem locating fonts - KDVI") ); + markFontsAsLocated(); + return; + } + + // We wait here while the kpsewhich program is concurrently + // running. Every second we call processEvents() to keep the GUI + // updated. This is important, e.g. for the progress dialog that is + // shown when PK fonts are generated by MetaFont. + while(kpsewhichIO.wait(1) == false) + qApp->processEvents(); + progress.hide(); + + // Handle fatal errors. + if (!kpsewhichIO.normalExit()) { + KMessageBox::sorry( 0, "

The font generation was aborted. As a result, " + "some font files could not be located, and your document might be unreadable.

", + i18n("Font generation aborted - KDVI") ); + + // This makes sure the we don't try to run kpsewhich again + if (makePK == false) + markFontsAsLocated(); + } else + if (kpsewhichIO.exitStatus() == 127) { + // An exit status of 127 means that the kpsewhich executable + // could not be found. We give extra explanation then. + QApplication::restoreOverrideCursor(); + QString msg = i18n( "

There were problems running kpsewhich. As a result, " + "some font files could not be located, and your document might be unreadable.

" + "

Possible reason: The kpsewhich program is perhaps not installed on your system, or it " + "cannot be found in the current search path.

" + "

What you can do: The kpsewhich program is normally contained in distributions of the TeX " + "typesetting system. If TeX is not installed on your system, you could install the TeTeX distribution (www.tetex.org). " + "If you are sure that TeX is installed, please try to use the kpsewhich program from the command line to check if it " + "really works.

"); + QString details = QString("

PATH: %1

%2
").arg(getenv("PATH")).arg(kpsewhichOutput); + + KMessageBox::detailedError( 0, QString("%1%2").arg(importanceOfKPSEWHICH).arg(msg), details, + i18n("Problem locating fonts - KDVI") ); + // This makes sure the we don't try to run kpsewhich again + markFontsAsLocated(); + return; + } + + // Create a list with all filenames found by the kpsewhich program. + QStringList fileNameList; + QString line; + while(kpsewhichIO.readln(line) >= 0) + fileNameList += line; + + // Now associate the file names found with the fonts + fontp=fontList.first(); + while ( fontp != 0 ) { + if (fontp->filename.isEmpty() == true) { + QStringList matchingFiles; +#ifdef HAVE_FREETYPE + const QString &fn = fontsByTeXName.findFileName(fontp->fontname); + if (!fn.isEmpty()) + matchingFiles = fileNameList.grep(fn); +#endif + if (matchingFiles.isEmpty() == true) + matchingFiles += fileNameList.grep(fontp->fontname+"."); + + if (matchingFiles.isEmpty() != true) { +#ifdef DEBUG_FONTPOOL + kdDebug(4300) << "Associated " << fontp->fontname << " to " << matchingFiles.first() << endl; +#endif + QString fname = matchingFiles.first(); + fontp->fontNameReceiver(fname); + fontp->flags |= TeXFontDefinition::FONT_KPSE_NAME; + if (fname.endsWith(".vf")) { + if (virtualFontsFound != 0) + *virtualFontsFound = true; + // Constructing a virtual font will most likely insert other + // fonts into the fontList. After that, fontList.next() will + // no longer work. It is therefore safer to start over. + fontp=fontList.first(); + continue; + } + } + } // of if (fontp->filename.isEmpty() == true) + fontp = fontList.next(); + } +} + + +void fontPool::setCMperDVIunit( double _CMperDVI ) +{ +#ifdef DEBUG_FONTPOOL + kdDebug(4300) << "fontPool::setCMperDVIunit( " << _CMperDVI << " )" << endl; +#endif + + if (CMperDVIunit == _CMperDVI) + return; + + CMperDVIunit = _CMperDVI; + + TeXFontDefinition *fontp = fontList.first(); + while(fontp != 0 ) { + fontp->setDisplayResolution(displayResolution_in_dpi * fontp->enlargement); + fontp=fontList.next(); + } +} + + +void fontPool::setDisplayResolution( double _displayResolution_in_dpi ) +{ +#ifdef DEBUG_FONTPOOL + kdDebug(4300) << "fontPool::setDisplayResolution( displayResolution_in_dpi=" << _displayResolution_in_dpi << " ) called" << endl; +#endif + + // Ignore minute changes by less than 2 DPI. The difference would + // hardly be visible anyway. That saves a lot of re-painting, + // e.g. when the user resizes the window, and a flickery mouse + // changes the window size by 1 pixel all the time. + if ( fabs(displayResolution_in_dpi - _displayResolution_in_dpi) <= 2.0 ) { +#ifdef DEBUG_FONTPOOL + kdDebug(4300) << "fontPool::setDisplayResolution(...): resolution wasn't changed. Aborting." << endl; +#endif + return; + } + + displayResolution_in_dpi = _displayResolution_in_dpi; + double displayResolution = displayResolution_in_dpi; + + TeXFontDefinition *fontp = fontList.first(); + while(fontp != 0 ) { + fontp->setDisplayResolution(displayResolution * fontp->enlargement); + fontp=fontList.next(); + } + + // Do something that causes re-rendering of the dvi-window + /*@@@@ + emit fonts_have_been_loaded(this); + */ +} + + +void fontPool::markFontsAsLocated() +{ + TeXFontDefinition *fontp=fontList.first(); + while ( fontp != 0 ) { + fontp->markAsLocated(); + fontp = fontList.next(); + } +} + + + +void fontPool::mark_fonts_as_unused() +{ +#ifdef DEBUG_FONTPOOL + kdDebug(4300) << "fontPool::mark_fonts_as_unused() called" << endl; +#endif + + TeXFontDefinition *fontp = fontList.first(); + while ( fontp != 0 ) { + fontp->flags &= ~TeXFontDefinition::FONT_IN_USE; + fontp=fontList.next(); + } +} + + +void fontPool::release_fonts() +{ +#ifdef DEBUG_FONTPOOL + kdDebug(4300) << "Release_fonts" << endl; +#endif + + TeXFontDefinition *fontp = fontList.first(); + while(fontp != 0) { + if ((fontp->flags & TeXFontDefinition::FONT_IN_USE) != TeXFontDefinition::FONT_IN_USE) { + fontList.removeRef(fontp); + fontp = fontList.first(); + } else + fontp = fontList.next(); + } +} + + +void fontPool::mf_output_receiver(KProcess *, char *buffer, int buflen) +{ + // Paranoia. + if (buflen < 0) + return; + + QString op = QString::fromLocal8Bit(buffer, buflen); + + kpsewhichOutput.append(op); + MetafontOutput.append(op); + + // We'd like to print only full lines of text. + int numleft; + bool show_prog = false; + while( (numleft = MetafontOutput.find('\n')) != -1) { + QString line = MetafontOutput.left(numleft+1); +#ifdef DEBUG_FONTPOOL + kdDebug(4300) << "MF OUTPUT RECEIVED: " << line; +#endif + // Search for a line which marks the beginning of a MetaFont run + // and show the progress dialog at the end of this method. + if (line.find("kpathsea:") == 0) + show_prog = true; + + // If the Output of the kpsewhich program contains a line starting + // with "kpathsea:", this means that a new MetaFont-run has been + // started. We filter these lines out and update the display + // accordingly. + int startlineindex = line.find("kpathsea:"); + if (startlineindex != -1) { + int endstartline = line.find("\n",startlineindex); + QString startLine = line.mid(startlineindex,endstartline-startlineindex); + + // The last word in the startline is the name of the font which we + // are generating. The second-to-last word is the resolution in + // dots per inch. Display this info in the text label below the + // progress bar. + int lastblank = startLine.findRev(' '); + QString fontName = startLine.mid(lastblank+1); + int secondblank = startLine.findRev(' ',lastblank-1); + QString dpi = startLine.mid(secondblank+1,lastblank-secondblank-1); + + progress.show(); + progress.increaseNumSteps( i18n("Currently generating %1 at %2 dpi").arg(fontName).arg(dpi) ); + } + MetafontOutput = MetafontOutput.remove(0,numleft+1); + } +} + + +#include "fontpool.moc" diff --git a/kdvi/fontpool.h b/kdvi/fontpool.h new file mode 100644 index 00000000..2e9d25da --- /dev/null +++ b/kdvi/fontpool.h @@ -0,0 +1,215 @@ +// -*- C++ -*- +// fontpool.h +// +// (C) 2001-2004 Stefan Kebekus +// Distributed under the GPL + +#ifndef _FONTPOOL_H +#define _FONTPOOL_H + +#include "fontEncodingPool.h" +#include "fontMap.h" +#include "fontprogress.h" +#include "TeXFontDefinition.h" + +#include +#include + +#ifdef HAVE_FREETYPE +#include +#include FT_FREETYPE_H +#endif + +class KProcess; +class KShellProcess; + + +/** + * A list of fonts and a compilation of utility functions + * + * This class holds a list of fonts and is able to perform a number of + * functions on each of the fonts. The main use of this class is that + * it is able to control a concurrently running "kpsewhich" programm + * which is used to locate and load the fonts. + * + * @author Stefan Kebekus + * + **/ + +class fontPool : public QObject { + Q_OBJECT + +public: + // Default constructor. + fontPool(); + + // Default destructor. + ~fontPool(); + + /** Method used to set the MetafontMode for the PK font files. This + data is used when loading fonts. Currently, a change here will be + applied only to those font which were not yet loaded ---expect + funny results when changing the data in the mid-work. */ + void setParameters( bool useFontHints ); + + /** Sets the DVI file's path. This information is used to set the + current working directory for the kpsewhich command, so that + kpsewhich will find fonts that are stored in the DVI file's + directory. */ + void setExtraSearchPath( const QString &path ) {extraSearchPath = path;} + + /** Returns the path that is set as the current working directory + for the kpsewhich command, so that kpsewhich will find fonts + that are stored in the DVI file's directory. */ + QString getExtraSearchPath( ) const {return extraSearchPath;} + + /** Sets the resolution of the output device. */ + void setDisplayResolution( double _displayResolution_in_dpi ); + + /** Sets the number of centimeters per DVI unit. */ + void setCMperDVIunit( double CMperDVI ); + double getCMperDVIunit() const {return CMperDVIunit;} + + // If return value is true, font hinting should be used if possible + bool getUseFontHints() const {return useFontHints;} + + // This method adds a font to the list. If the font is not currently + // loaded, it's file will be located and font::load_font will be + // called. Since this is done using a concurrently running process, + // there is no guarantee that the loading is already performed when + // the method returns. + TeXFontDefinition* appendx(const QString& fontname, Q_UINT32 checksum, Q_UINT32 scale, double enlargement); + + // Returns a string in a very basic HTML format which describes the + // fonts in the pool. + QString status(); + + // This is the list which actually holds pointers to the fonts + QPtrList fontList; + + // This method marks all fonts in the fontpool as "not in use". The + // fonts are, however, not removed from memory until the method + // release_fonts is called. The method is called when the dvi-file + // is closed. Because the next dvi-file which will be loaded is + // likely to use most of the fonts again, this method implements a + // convenient way of re-using fonts without loading them repeatedly. + void mark_fonts_as_unused(); + + /** This methods removes all fonts from the fontpool (and thus from + memory) which are labeled "not in use". For explanation, see the + mark_fonts_as_unused method. */ + void release_fonts(); + +#ifdef HAVE_FREETYPE + /** A handle to the FreeType library, which is used by TeXFont_PFM + font objects, if KDVI is compiled with FreeType support. */ + FT_Library FreeType_library; + + /** Simple marker. Set to 'true', if the FreeType library was loaded + successfully */ + bool FreeType_could_be_loaded; + + /** This maps TeX font names to font file names, full font names and + encodings. See the file 'fontMap.h' for a detailed + description. */ + fontMap fontsByTeXName; + + /** This is a list of known font encodings which can be conveniently + acessed by name. */ + fontEncodingPool encodingPool; +#endif + + /** This flag is set during the construction of the fontPool + object. It indicates if the QT library supports the alpha + channel of pixmaps. Experiments show that --depending of the + configuration of QT at compile and runtime or the availability + of the XFt extension, alpha channels are either supported, or + silently converted to 1-bit masks. The redering routines in the + TeXFont implementation use this flag to choose the apropriate + drawing routines for the different setups. */ + bool QPixmapSupportsAlpha; + +signals: + /** Passed through to the top-level kpart. */ + void setStatusBarText( const QString& ); + +public slots: + // Locates font files on the disk using the kpsewhich program. If + // 'locateTFMonly' is true, the method does not look for PFB- or + // PK-fonts. Instead, only TFM-files are searched. This option can be + // used as a 'last resort': if a found cannot be found, one can at + // least use the TFM file to draw filled rectangles for the + // characters. If not null, the bool pointed at by virtualFontsFound + // is set to true if one of the fonts found is a virtual font. If no + // virtual font is found, the variable remains untouched. + void locateFonts(); + +private: + // This method goes through the list of fonts, and marks each of them + // as 'located'. Used, e.g. after a fatal error in the font lookup + // process to ensure that the problematic kpsewhich is not used again + void markFontsAsLocated(); + + // Checks if all the fonts file names have been located, and returns + // true if that is so. + bool areFontsLocated(); + + // This flag is used by PFB fonts to determine if the FREETYPE engine + // should use hinted fonts or not + bool useFontHints; + + // Resolution of the output device. + double displayResolution_in_dpi; + + // Number of centimeters per DVI unit + double CMperDVIunit; + + + /** Members used for font location */ + + // Locates font files on the disk using the kpsewhich program. If + // 'locateTFMonly' is true, the method does not look for PFB- or + // PK-fonts. Instead, only TFM-files are searched. This option can be + // used as a 'last resort': if a found cannot be found, one can at + // least use the TFM file to draw filled rectangles for the + // characters. If not null, the bool pointed at by virtualFontsFound + // is set to true if one of the fonts found is a virtual font. If no + // virtual font is found, the variable remains untouched. + void locateFonts(bool makePK, bool locateTFMonly, bool *virtualFontsFound=0); + + // This QString is used internally by the mf_output_receiver() + // method. This string is set to QString::null in locateFonts(bool, + // bool, bool *). Values are set and read by the + // mf_output_receiver(...) method + QString MetafontOutput; + + // This QString is used to collect the output of kpsewhich and + // MetaFont. The string is set to QString::null in the + // locateFonts()-method, and content is gathered by the + // mf_output_receiver(). This string is used by locateFonts() and + // locateFonts(bool, bool, bool *) to display error messages. + QString kpsewhichOutput; + + // This string is set to the DVI file's path. It is used to set the + // current working directory for the kpsewhich command, so that + // kpsewhich will find fonts that are stored in the DVI file's + // directory. Used by the locateFonts() and the locateFonts(bool, + // bool, bool *) method. Values are set by the + // setExtraSearchPath(...) method + QString extraSearchPath; + + // FontProgress; the progress dialog used when generating fonts. + fontProgressDialog progress; + +private slots: + /** Members used for font location */ + + // For internal purposess only. This slot is called when MetaFont is + // run via the kpsewhich programm. The MetaFont output is + // transmitted to the fontpool via this slot. This method calles + // suitable methods in the fontProgres Dialog, and collects the + // output of MetaFontt int the "MetafontOutput" member + void mf_output_receiver(KProcess *, char *, int); +}; + +#endif //ifndef _FONTPOOL_H diff --git a/kdvi/fontprogress.cpp b/kdvi/fontprogress.cpp new file mode 100644 index 00000000..3935ceba --- /dev/null +++ b/kdvi/fontprogress.cpp @@ -0,0 +1,104 @@ +// fontprogress.cpp +// +// (C) 2001--2004 Stefan Kebekus +// Distributed under the GPL + +#include + +#include "fontprogress.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * Constructs a fontProgressDialog which is a child of 'parent', with the + * name 'name' and widget flags set to 'f' + */ +fontProgressDialog::fontProgressDialog(const QString& helpIndex, const QString& label, const QString& abortTip, const QString& whatsThis, const QString& ttip, QWidget* parent, const QString& name, bool progressbar) + : KDialogBase( parent, "Font Generation Progress Dialog", true, name, Cancel, Cancel, true ) +{ + setCursor( QCursor( 3 ) ); + + setButtonCancel(KGuiItem(i18n("Abort"), "stop", abortTip)); + + if (helpIndex.isEmpty() == false) { + setHelp(helpIndex, "kdvi"); + setHelpLinkText( i18n( "What's going on here?") ); + enableLinkedHelp(true); + } else + enableLinkedHelp(false); + + QVBox *page = makeVBoxMainWidget(); + + TextLabel1 = new QLabel( label, page, "TextLabel2" ); + TextLabel1->setAlignment( int( QLabel::AlignCenter ) ); + QWhatsThis::add( TextLabel1, whatsThis ); + QToolTip::add( TextLabel1, ttip ); + + if (progressbar) { + ProgressBar1 = new KProgress( page, "ProgressBar1" ); + ProgressBar1->setFormat(i18n("%v of %m")); + QWhatsThis::add( ProgressBar1, whatsThis ); + QToolTip::add( ProgressBar1, ttip ); + } else + ProgressBar1 = NULL; + + TextLabel2 = new QLabel( "", page, "TextLabel2" ); + TextLabel2->setAlignment( int( QLabel::AlignCenter ) ); + QWhatsThis::add( TextLabel2, whatsThis ); + QToolTip::add( TextLabel2, ttip ); + + progress = 0; + procIO = 0; + qApp->connect(this, SIGNAL(finished()), this, SLOT(killProcIO())); +} + + +/* + * Destroys the object and frees any allocated resources + */ + +fontProgressDialog::~fontProgressDialog() +{ + // no need to delete child widgets, Qt does it all for us +} + + +void fontProgressDialog::increaseNumSteps(const QString& explanation) +{ + if (ProgressBar1 != 0) + ProgressBar1->setProgress(progress++); + TextLabel2->setText( explanation ); +} + + +void fontProgressDialog::setTotalSteps(int steps, KProcIO *proc) +{ + procIO = proc; + if (ProgressBar1 != 0) { + ProgressBar1->setTotalSteps(steps); + ProgressBar1->setProgress(0); + } + progress = 0; +} + + +void fontProgressDialog::killProcIO() +{ + if (!procIO.isNull()) + procIO->kill(); +} + + +#include "fontprogress.moc" diff --git a/kdvi/fontprogress.h b/kdvi/fontprogress.h new file mode 100644 index 00000000..f9c7232b --- /dev/null +++ b/kdvi/fontprogress.h @@ -0,0 +1,64 @@ +// -*- C++ -*- +// +// fontprogress.h +// +// (C) 2001-2004 Stefan Kebekus +// Distributed under the GPL + +#ifndef FONT_GENERATION_H +#define FONT_GENERATION_H + +#include +#include + +class KProcIO; +class KProgress; +class QLabel; + + +/** + * A dialog to give feedback to the user when kpsewhich is generating fonts. + * + * This class implements a dialog which pops up, shows a progress bar + * and displays the MetaFont output. It contains three slots, + * outputReceiver, setTotalSteps and hideDialog which can be connected + * with the appropriate signals emitted by the fontpool class. + * + * @author Stefan Kebekus + * + * + **/ +class fontProgressDialog : public KDialogBase +{ + Q_OBJECT + +public: + fontProgressDialog( const QString& helpIndex, const QString& label, const QString& abortTip, const QString& whatsThis, const QString& ttip, + QWidget* parent = 0, const QString &name = 0, bool progressbar=true ); + ~fontProgressDialog(); + + /** The number of steps already done is increased, the text received + here is analyzed and presented to the user. */ + void increaseNumSteps(const QString& explanation); + + /** Used to initialize the progress bar. If the argument proc is + non-zero, the associated process will be killed when the "abort" + button is pressed. The FontProgress uses a QGuarderPtr + internally, so it is save to delete the KProcIO anytime. */ + void setTotalSteps(int, KProcIO *proc=0); + + QLabel* TextLabel2; + +private slots: + /** Calling this slot does nothing than to kill the process that is + pointed to be procIO, if procIO is not zero.*/ + void killProcIO(); + +private: + QLabel* TextLabel1; + KProgress* ProgressBar1; + int progress; + QGuardedPtr procIO; +}; + +#endif // FONT_GENERATION_H diff --git a/kdvi/glyph.cpp b/kdvi/glyph.cpp new file mode 100644 index 00000000..d495d096 --- /dev/null +++ b/kdvi/glyph.cpp @@ -0,0 +1,30 @@ + +/* glyph.cpp + * + * part of kdvi, a dvi-previewer for the KDE desktop environement + * + * written by Stefan Kebekus, originally based on code by Paul Vojta + * and a large number of co-authors */ + +#include + +#include + +#include "glyph.h" + +glyph::glyph() +{ +#ifdef DEBUG_GLYPH + kdDebug(4300) << "glyph::glyph()" << endl; +#endif + + addr = 0; + x = 0; + y = 0; + dvi_advance_in_units_of_design_size_by_2e20 = 0; +} + +glyph::~glyph() +{ + ; +} diff --git a/kdvi/glyph.h b/kdvi/glyph.h new file mode 100644 index 00000000..1cc41823 --- /dev/null +++ b/kdvi/glyph.h @@ -0,0 +1,37 @@ +// -*- C++ -*- + +#ifndef _GLYPH_H +#define _GLYPH_H + +#include +#include + + +struct bitmap { + Q_UINT16 w, h; /* width and height in pixels */ + Q_UINT16 bytes_wide; /* scan-line width in bytes */ + char *bits; /* pointer to the bits */ +}; + +class glyph { + public: + glyph(); + ~glyph(); + + // address of bitmap in font file + long addr; + + QColor color; + + // DVI units to move reference point + Q_INT32 dvi_advance_in_units_of_design_size_by_2e20; + + // x and y offset in pixels + short x, y; + + QPixmap shrunkenCharacter; + + short x2, y2; /* x and y offset in pixels (shrunken bitmap) */ +}; + +#endif //ifndef _GLYPH_H diff --git a/kdvi/infodialog.cpp b/kdvi/infodialog.cpp new file mode 100644 index 00000000..f645def8 --- /dev/null +++ b/kdvi/infodialog.cpp @@ -0,0 +1,134 @@ +// infodialog.cpp +// +// (C) 2001-2003 Stefan Kebekus +// Distributed under the GPL + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dviFile.h" +#include "fontpool.h" +#include "infodialog.h" + +infoDialog::infoDialog( QWidget* parent ) + : KDialogBase( Tabbed, i18n("Document Info"), Ok, Ok, parent, "Document Info", false, false) +{ + QFrame *page1 = addPage( i18n("DVI File") ); + QVBoxLayout *topLayout1 = new QVBoxLayout( page1, 0, 6 ); + TextLabel1 = new QTextView( page1, "TextLabel1" ); + QToolTip::add( TextLabel1, i18n("Information on the currently loaded DVI-file.") ); + topLayout1->addWidget( TextLabel1 ); + + QFrame *page2 = addPage( i18n("Fonts") ); + QVBoxLayout *topLayout2 = new QVBoxLayout( page2, 0, 6 ); + TextLabel2 = new QTextView( page2, "TextLabel1" ); + TextLabel2->setMinimumWidth(fontMetrics().maxWidth()*40); + TextLabel2->setMinimumHeight(fontMetrics().height()*10); + QToolTip::add( TextLabel2, i18n("Information on currently loaded fonts.") ); + QWhatsThis::add( TextLabel2, i18n("This text field shows detailed information about the currently loaded fonts. " + "This is useful for experts who want to locate problems in the setup of TeX or KDVI.") ); + topLayout2->addWidget( TextLabel2 ); + + QFrame *page3 = addPage( i18n("External Programs") ); + QVBoxLayout *topLayout3 = new QVBoxLayout( page3, 0, 6 ); + TextLabel3 = new QTextView( page3, "TextLabel1" ); + TextLabel3->setText( i18n("No output from any external program received.") ); + QToolTip::add( TextLabel3, i18n("Output of external programs.") ); + QWhatsThis::add( TextLabel3, i18n("KDVI uses external programs, such as MetaFont, dvipdfm or dvips. " + "This text field shows the output of these programs. " + "That is useful for experts who want to find problems in the setup of TeX or KDVI.") ); + topLayout3->addWidget( TextLabel3 ); + + MFOutputReceived = false; + headline = QString::null; + pool = QString::null; +} + + +void infoDialog::setDVIData(dvifile *dviFile) +{ + QString text = ""; + + if (dviFile == NULL) + text = i18n("There is no DVI file loaded at the moment."); + else { + text.append(""); + text.append(QString("").arg(i18n("Filename")).arg(dviFile->filename)); + + QFile file(dviFile->filename); + if (file.exists()) + text.append(QString("").arg(i18n("File Size")).arg(KIO::convertSize(file.size()))); + else + text.append(QString("").arg(i18n("The file does no longer exist."))); + + text.append(QString("")); + text.append(QString("").arg(i18n("#Pages")).arg(dviFile->total_pages)); + text.append(QString("").arg(i18n("Generator/Date")).arg(dviFile->generatorString)); + } // else (dviFile == NULL) + + TextLabel1->setText( text ); +} + + +void infoDialog::setFontInfo(fontPool *fp) +{ + TextLabel2->setText(fp->status()); +} + +void infoDialog::outputReceiver(const QString& _op) +{ + QString op = _op; + op = op.replace( QRegExp("<"), "<" ); + + if (MFOutputReceived == false) { + TextLabel3->setText(""+headline+"
"); + headline = QString::null; + } + + // It seems that the QTextView wants that we append only full lines. + // We see to that. + pool = pool+op; + int idx = pool.findRev("\n"); + + while(idx != -1) { + QString line = pool.left(idx); + pool = pool.mid(idx+1); + + // If the Output of the kpsewhich program contains a line starting + // with "kpathsea:", this means that a new MetaFont-run has been + // started. We filter these lines out and print them in boldface. + int startlineindex = line.find("kpathsea:"); + if (startlineindex != -1) { + int endstartline = line.find("\n",startlineindex); + QString startLine = line.mid(startlineindex,endstartline-startlineindex); + if (MFOutputReceived) + TextLabel3->append("
\n"+startLine+""); + else + TextLabel3->append(""+startLine+""); + TextLabel3->append(line.mid(endstartline)); + } else + TextLabel3->append(line); + idx = pool.findRev("\n"); + } + + MFOutputReceived = true; +} + +void infoDialog::clear(const QString& op) +{ + headline = op; + pool = QString::null; + MFOutputReceived = false; +} +#include "infodialog.moc" diff --git a/kdvi/infodialog.h b/kdvi/infodialog.h new file mode 100644 index 00000000..916d0d13 --- /dev/null +++ b/kdvi/infodialog.h @@ -0,0 +1,58 @@ +// -*- C++ -*- +// infodialog.h +// +// (C) 2001 Stefan Kebekus +// Distributed under the GPL + +#ifndef INFO_KDVI_H +#define INFO_KDVI_H + +#include + +#include + +class dvifile; +class fontPool; +class QTextView; +class QWidget; + + +class infoDialog : public KDialogBase +{ + Q_OBJECT + +public: + infoDialog( QWidget* parent = 0 ); + + /** This method is used to set the data coming from the DVI + file. Note that 0 is a permissible argument, that just means: + "no file loaded" */ + void setDVIData(dvifile *dviFile); + + QTextView* TextLabel1; + QTextView* TextLabel2; + QTextView* TextLabel3; + +public slots: + /** This slot is called when Output from the MetaFont programm + is received via the fontpool/kpsewhich */ + void outputReceiver(const QString&); + + /** This slot is called whenever anything in the fontpool has + changed. If the infoDialog is shown, the dialog could then + query the fontpool for more information. */ + void setFontInfo(fontPool *fp); + + /** Calling this slot clears the text view and stores the + headline. The next time output is received via the + outputReceiver, the headline is displayed in bold on top of + the text view. */ + void clear(const QString&); + +protected: + bool MFOutputReceived; + QString headline; + QString pool; +}; + +#endif // INFO_KDVI_H diff --git a/kdvi/kdvi.desktop b/kdvi/kdvi.desktop new file mode 100644 index 00000000..183bef33 --- /dev/null +++ b/kdvi/kdvi.desktop @@ -0,0 +1,90 @@ +[Desktop Entry] +GenericName=DVI Viewer +GenericName[af]=Dvi Aansig +GenericName[ar]=عارض ملفات DVI +GenericName[az]=DVI Nümayişçisi +GenericName[bg]=Преглед на документи DVI +GenericName[br]=Gweler DVI +GenericName[bs]=Preglednik DVI dokumenata +GenericName[ca]=Visualitzador de DVI +GenericName[cs]=Prohlížeč DVI souborů +GenericName[cy]=Gwelydd DVI +GenericName[da]=DVI-fremviser +GenericName[de]=DVI-Betrachter +GenericName[el]=Προβολέας DVI +GenericName[eo]=DVI-rigardilo +GenericName[es]=Visor de documentos DVI +GenericName[et]=DVI failide vaataja +GenericName[eu]=DVI ikustailea +GenericName[fa]=مشاهده‌گر DVI +GenericName[fi]=DVI-näytin +GenericName[fr]=Afficheur DVI +GenericName[ga]=Amharcán DVI +GenericName[gl]=Visor de DVI +GenericName[he]=מציג DVI +GenericName[hi]=डीवीआई प्रदर्शक +GenericName[hr]=Preglednik DVI dokumenata +GenericName[hu]=DVI-nézegető +GenericName[id]=Viewer DVI +GenericName[is]=DVI sjá +GenericName[it]=Visore DVI +GenericName[ja]=DVI ビューア +GenericName[kk]=DVI файлдарын қарау +GenericName[km]=កម្មវិធី​មើល DVI +GenericName[ko]=DVI 보기 +GenericName[lt]=DVI Žiūriklis +GenericName[lv]=DVI Skatītājs +GenericName[mk]=Прикажувач на DVI +GenericName[ms]=Pemapar DVI +GenericName[mt]=Werrej DVI +GenericName[nb]=DVI-fremviser +GenericName[nds]=DVI-Kieker +GenericName[ne]=DVI दर्शक +GenericName[nl]=DVI-weergaveprogramma +GenericName[nn]=DVI-lesar +GenericName[pa]=DVI ਦਰਸ਼ਕ +GenericName[pl]=Przeglądarka plików DVI +GenericName[pt]=Visualizador de DVIs +GenericName[pt_BR]=Visualizador de DVI +GenericName[ro]=Vizualizor DVI +GenericName[ru]=Просмотр файлов DVI +GenericName[rw]=Ikigaragaza DVI +GenericName[se]=DVI čájeheaddji +GenericName[sk]=Prehliadač DVI súborov +GenericName[sl]=Pregledovalnik datotek DVI +GenericName[sr]=DVI приказивач +GenericName[sr@Latn]=DVI prikazivač +GenericName[sv]=DVI-visare +GenericName[ta]=DVI காட்சி +GenericName[tg]=Намоиши файли DVI +GenericName[th]=ตัวแสดงผล DVI +GenericName[tr]=DVI Görüntüleyici +GenericName[uk]=Переглядач DVI +GenericName[uz]=DVI koʻruvchi +GenericName[uz@cyrillic]=DVI кўрувчи +GenericName[ven]=Muvhoni wa DVI +GenericName[wa]=Håyneu di fitchîs DVI +GenericName[xh]=Umboniseli we DVI +GenericName[zh_CN]=DVI 查看器 +GenericName[zh_HK]=DVI 檢視器 +GenericName[zh_TW]=DVI 檢視器 +GenericName[zu]=Umboniseli we DVI +Name=KDVI +Name[af]=Kdvi +Name[ar]=برنامج KDVI +Name[eo]=DVI-rigardilo +Name[hi]=के-डीवीआई +Name[zh_TW]=KDVI 檢視器 +MimeType=application/x-dvi;application/x-gzdvi;application/x-bz2dvi; +InitialPreference=6 +Exec=kdvi %f -caption "%c" %i %m +Icon=kdvi +Path= +Type=Application +Terminal=false +ServiceTypes=Browser/View +X-KDE-Library=kviewerpart +X-KDE-BrowserView-Args=dvi +DocPath=kdvi/index.html +X-KDE-StartupNotify=true +Categories=Qt;KDE;Graphics; diff --git a/kdvi/kdvi.h b/kdvi/kdvi.h new file mode 100644 index 00000000..c04fe189 --- /dev/null +++ b/kdvi/kdvi.h @@ -0,0 +1,17 @@ +// -*- C++ -*- +// kdvi.h +// +// global variables and definitions for kdvi. +// +// (C) 2000, Stefan Kebekus. Distributed under the GPL. + +#ifndef KDVI_H +#define KDVI_H + +// Define the following flags to generate debugging output + +// #define DEBUG_FONT 1 +// #define DEBUG_FONTPOOL 1 +// #define DEBUG_PK 1 + +#endif diff --git a/kdvi/kdvi.kcfg b/kdvi/kdvi.kcfg new file mode 100644 index 00000000..aa416757 --- /dev/null +++ b/kdvi/kdvi.kcfg @@ -0,0 +1,26 @@ + + + fontpool.h + + + + + Allows KDVI to use MetaFont to produce bitmap fonts. Unless you have a very specific reason, you probably want to enable this option. + true + + + + Some DVI files contain PostScript graphics. If enabled, KDVI will use the Ghostview PostScript interpreter to display these. You probably want to enable this option, unless you have a DVI-file whose PostScript part is broken, or too large for your machine. + true + + + + Many modern fonts contain "font hinting" information which can be used to improve the appearance of a font on low-resolution displays, such as a computer monitor, or a notebook screen. However, many people find the "improved" fonts quite ugly and prefer to have this option disabled. + false + + + + diff --git a/kdvi/kdvi.lsm b/kdvi/kdvi.lsm new file mode 100644 index 00000000..7c42cd2c --- /dev/null +++ b/kdvi/kdvi.lsm @@ -0,0 +1,14 @@ +Begin3 +Title: kdvi +Version: 0.4 +Entered-date: October 15, 1997 +Description: TeX DVI previewer for the K Desktop Environment +Keywords: KDE, TeX, DVI, X11, Qt +Author: Markku Hihnala +Maintained-by: Markku Hihnala +Primary-site: ftp://ftp.kde.org/pub/kde/ +Alternate-site: +Original-site: ftp://ftp.kde.org/pub/kde/ +Platforms: Unix, Qt +Copying-policy: GPL +End diff --git a/kdvi/kdvi_multipage.cpp b/kdvi/kdvi_multipage.cpp new file mode 100644 index 00000000..973e4d5f --- /dev/null +++ b/kdvi/kdvi_multipage.cpp @@ -0,0 +1,482 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "kdvi_multipage.h" +#include "documentWidget.h" +#include "dviFile.h" +#include "dviPageCache.h" +#include "dviWidget.h" +#include "fontpool.h" +#include "kprinterwrapper.h" +#include "kviewpart.h" +#include "marklist.h" +#include "optionDialogFontsWidget.h" +#include "optionDialogSpecialWidget.h" +#include "performanceMeasurement.h" +#include "prefs.h" +#include "renderedDocumentPagePixmap.h" + + +#include + +//#define KDVI_MULTIPAGE_DEBUG + +#ifdef PERFORMANCE_MEASUREMENT +// These objects are explained in the file "performanceMeasurement.h" +QTime performanceTimer; +int performanceFlag = 0; +#endif + +typedef KParts::GenericFactory KDVIMultiPageFactory; +K_EXPORT_COMPONENT_FACTORY(kdvipart, KDVIMultiPageFactory) + + + +KDVIMultiPage::KDVIMultiPage(QWidget *parentWidget, const char *widgetName, QObject *parent, + const char *name, const QStringList& args) + : KMultiPage(parentWidget, widgetName, parent, name), DVIRenderer(parentWidget) +{ + Q_UNUSED(args); +#ifdef PERFORMANCE_MEASUREMENT + performanceTimer.start(); +#endif + + searchUsed = false; + + setInstance(KDVIMultiPageFactory::instance()); + + // Points to the same object as renderer to avoid downcasting. + // FIXME: Remove when the API of the Renderer-class is finished. + DVIRenderer.setName("DVI renderer"); + setRenderer(&DVIRenderer); + + docInfoAction = new KAction(i18n("Document &Info"), "info", 0, &DVIRenderer, SLOT(showInfo()), actionCollection(), "info_dvi"); + embedPSAction = new KAction(i18n("Embed External PostScript Files..."), 0, this, SLOT(slotEmbedPostScript()), actionCollection(), "embed_postscript"); + new KAction(i18n("Enable All Warnings && Messages"), 0, this, SLOT(doEnableWarnings()), actionCollection(), "enable_msgs"); + exportPSAction = new KAction(i18n("PostScript..."), 0, &DVIRenderer, SLOT(exportPS()), actionCollection(), "export_postscript"); + exportPDFAction = new KAction(i18n("PDF..."), 0, &DVIRenderer, SLOT(exportPDF()), actionCollection(), "export_pdf"); + + KStdAction::tipOfDay(this, SLOT(showTip()), actionCollection(), "help_tipofday"); + + setXMLFile("kdvi_part.rc"); + + preferencesChanged(); + + enableActions(false); + // Show tip of the day, when the first main window is shown. + QTimer::singleShot(0,this,SLOT(showTipOnStart())); +} + + +KDVIMultiPage::~KDVIMultiPage() +{ + delete docInfoAction; + delete embedPSAction; + delete exportPSAction; + delete exportPDFAction; + + Prefs::writeConfig(); +} + + +KAboutData* KDVIMultiPage::createAboutData() +{ + KAboutData* about = new KAboutData("kdvi", I18N_NOOP("KDVI"), "1.3", + I18N_NOOP("A previewer for Device Independent files (DVI files) produced by the TeX typesetting system."), + KAboutData::License_GPL, + "Markku Hinhala, Stephan Kebekus", + I18N_NOOP("This program displays Device Independent (DVI) files which are produced by the TeX typesetting system.\n" + "KDVI 1.3 is based on original code from KDVI version 0.43 and xdvik.")); + + about->addAuthor ("Stefan Kebekus", + I18N_NOOP("Current Maintainer."), + "kebekus@kde.org", + "http://www.mi.uni-koeln.de/~kebekus"); + + about->addAuthor ("Markku Hinhala", I18N_NOOP("Author of kdvi 0.4.3")); + about->addAuthor ("Nicolai Langfeldt", I18N_NOOP("Maintainer of xdvik")); + about->addAuthor ("Paul Vojta", I18N_NOOP("Author of xdvi")); + about->addCredit ("Philipp Lehmann", I18N_NOOP("Testing and bug reporting.")); + about->addCredit ("Wilfried Huss", I18N_NOOP("Re-organisation of source code.")); + + return about; +} + + +void KDVIMultiPage::slotEmbedPostScript() +{ + DVIRenderer.embedPostScript(); + emit askingToCheckActions(); +} + + +void KDVIMultiPage::setEmbedPostScriptAction() +{ + if ((DVIRenderer.dviFile == 0) || (DVIRenderer.dviFile->numberOfExternalPSFiles == 0)) + embedPSAction->setEnabled(false); + else + embedPSAction->setEnabled(true); +} + + +void KDVIMultiPage::slotSave() +{ + // Try to guess the proper ending... + QString formats; + QString ending; + int rindex = m_file.findRev("."); + if (rindex == -1) { + ending = QString::null; + formats = QString::null; + } else { + ending = m_file.mid(rindex); // e.g. ".dvi" + formats = fileFormats().grep(ending).join("\n"); + } + + QString fileName = KFileDialog::getSaveFileName(QString::null, formats, 0, i18n("Save File As")); + + if (fileName.isEmpty()) + return; + + // Add the ending to the filename. I hope the user likes it that + // way. + if (!ending.isEmpty() && fileName.find(ending) == -1) + fileName = fileName+ending; + + if (QFile(fileName).exists()) { + int r = KMessageBox::warningContinueCancel (0, i18n("The file %1\nexists. Do you want to overwrite that file?").arg(fileName), + i18n("Overwrite File"), i18n("Overwrite")); + if (r == KMessageBox::Cancel) + return; + } + + // TODO: error handling... + if ((DVIRenderer.dviFile != 0) && (DVIRenderer.dviFile->dvi_Data() != 0)) + DVIRenderer.dviFile->saveAs(fileName); + + return; +} + + +void KDVIMultiPage::slotSave_defaultFilename() +{ + // TODO: error handling... + if (DVIRenderer.dviFile != 0) + DVIRenderer.dviFile->saveAs(m_file); + return; +} + + +void KDVIMultiPage::setFile(bool r) +{ + enableActions(r); +} + + +QStringList KDVIMultiPage::fileFormats() const +{ + QStringList r; + r << i18n("*.dvi *.DVI|TeX Device Independent Files (*.dvi)"); + return r; +} + + +void KDVIMultiPage::addConfigDialogs(KConfigDialog* configDialog) +{ + static optionDialogFontsWidget* fontConfigWidget = 0; + + fontConfigWidget = new optionDialogFontsWidget(scrollView()); + optionDialogSpecialWidget* specialConfigWidget = new optionDialogSpecialWidget(scrollView()); + + configDialog->addPage(fontConfigWidget, Prefs::self(), i18n("TeX Fonts"), "fonts"); + configDialog->addPage(specialConfigWidget, Prefs::self(), i18n("DVI Specials"), "dvi"); + configDialog->setHelp("preferences", "kdvi"); +} + + +void KDVIMultiPage::preferencesChanged() +{ + // Call method from parent class + KMultiPage::preferencesChanged(); +#ifdef KDVI_MULTIPAGE_DEBUG + kdDebug(4300) << "preferencesChanged" << endl; +#endif + + bool showPS = Prefs::showPS(); + bool useFontHints = Prefs::useFontHints(); + + DVIRenderer.setPrefs( showPS, Prefs::editorCommand(), useFontHints); +} + + +void KDVIMultiPage::print() +{ + // Obtain a fully initialized KPrinter structure, and disable all + // entries in the "Page Size & Placement" tab of the printer dialog. + KPrinter *printer = getPrinter(false); + // Abort with an error message if no KPrinter could be initialized + if (printer == 0) { + kdError(4300) << "KPrinter not available" << endl; + return; + } + + // Show the printer options dialog. Return immediately if the user + // aborts. + if (!printer->setup(parentWdg, i18n("Print %1").arg(m_file.section('/', -1)) )) + return; + + // This funny method call is necessary for the KPrinter to return + // proper results in printer->orientation() below. It seems that + // KPrinter does some options parsing in that method. + ((KDVIPrinterWrapper *)printer)->doPreparePrinting(); + if (printer->pageList().isEmpty()) { + KMessageBox::error( scrollView(), + i18n("The list of pages you selected was empty.\n" + "Maybe you made an error in selecting the pages, " + "e.g. by giving an invalid range like '7-2'.") ); + return; + } + + // Turn the results of the options requestor into a list arguments + // which are used by dvips. + QString dvips_options = QString::null; + // Print in reverse order. + if ( printer->pageOrder() == KPrinter::LastPageFirst ) + dvips_options += "-r "; + // Print only odd pages. + if ( printer->pageSet() == KPrinter::OddPages ) + dvips_options += "-A "; + // Print only even pages. + if ( printer->pageSet() == KPrinter::EvenPages ) + dvips_options += "-B "; + // We use the printer->pageSize() method to find the printer page + // size, and pass that information on to dvips. Unfortunately, dvips + // does not understand all of these; what exactly dvips understands, + // depends on its configuration files. Consequence: expect problems + // with unusual paper sizes. + switch( printer->pageSize() ) { + case KPrinter::A4: + dvips_options += "-t a4 "; + break; + case KPrinter::B5: + dvips_options += "-t b5 "; + break; + case KPrinter::Letter: + dvips_options += "-t letter "; + break; + case KPrinter::Legal: + dvips_options += "-t legal "; + break; + case KPrinter::Executive: + dvips_options += "-t executive "; + break; + case KPrinter::A0: + dvips_options += "-t a0 "; + break; + case KPrinter::A1: + dvips_options += "-t a1 "; + break; + case KPrinter::A2: + dvips_options += "-t a2 "; + break; + case KPrinter::A3: + dvips_options += "-t a3 "; + break; + case KPrinter::A5: + dvips_options += "-t a5 "; + break; + case KPrinter::A6: + dvips_options += "-t a6 "; + break; + case KPrinter::A7: + dvips_options += "-t a7 "; + break; + case KPrinter::A8: + dvips_options += "-t a8 "; + break; + case KPrinter::A9: + dvips_options += "-t a9 "; + break; + case KPrinter::B0: + dvips_options += "-t b0 "; + break; + case KPrinter::B1: + dvips_options += "-t b1 "; + break; + case KPrinter::B10: + dvips_options += "-t b10 "; + break; + case KPrinter::B2: + dvips_options += "-t b2 "; + break; + case KPrinter::B3: + dvips_options += "-t b3 "; + break; + case KPrinter::B4: + dvips_options += "-t b4 "; + break; + case KPrinter::B6: + dvips_options += "-t b6 "; + break; + case KPrinter::B7: + dvips_options += "-t b7 "; + break; + case KPrinter::B8: + dvips_options += "-t b8 "; + break; + case KPrinter::B9: + dvips_options += "-t b9 "; + break; + case KPrinter::C5E: + dvips_options += "-t c5e "; + break; + case KPrinter::Comm10E: + dvips_options += "-t comm10e "; + break; + case KPrinter::DLE: + dvips_options += "-t dle "; + break; + case KPrinter::Folio: + dvips_options += "-t folio "; + break; + case KPrinter::Ledger: + dvips_options += "-t ledger "; + break; + case KPrinter::Tabloid: + dvips_options += "-t tabloid "; + break; + default: + break; + } + // Orientation + if ( printer->orientation() == KPrinter::Landscape ) + dvips_options += "-t landscape "; + + + // List of pages to print. + QValueList pageList = printer->pageList(); + dvips_options += "-pp "; + int commaflag = 0; + for( QValueList::ConstIterator it = pageList.begin(); it != pageList.end(); ++it ) { + if (commaflag == 1) + dvips_options += QString(","); + else + commaflag = 1; + dvips_options += QString("%1").arg(*it); + } + + // Now print. For that, export the DVI-File to PostScript. Note that + // dvips will run concurrently to keep the GUI responsive, keep log + // of dvips and allow abort. Giving a non-zero printer argument + // means that the dvi-widget will print the file when dvips + // terminates, and then delete the output file. + KTempFile tf; + DVIRenderer.exportPS(tf.name(), dvips_options, printer); + + // "True" may be a bit euphemistic. However, since dvips runs + // concurrently, there is no way of telling the result of the + // printing command at this stage. + return; +} + + +void KDVIMultiPage::enableActions(bool b) +{ + KMultiPage::enableActions(b); + + docInfoAction->setEnabled(b); + exportPSAction->setEnabled(b); + exportPDFAction->setEnabled(b); + + setEmbedPostScriptAction(); +} + + +void KDVIMultiPage::doEnableWarnings() +{ + KMessageBox::information (scrollView(), i18n("All messages and warnings will now be shown.")); + KMessageBox::enableAllMessages(); + KTipDialog::setShowOnStart(true); +} + + +void KDVIMultiPage::showTip() +{ + KTipDialog::showTip(scrollView(), "kdvi/tips", true); +} + + +void KDVIMultiPage::showTipOnStart() +{ + KTipDialog::showTip(scrollView(), "kdvi/tips"); +} + + +DocumentWidget* KDVIMultiPage::createDocumentWidget() +{ + DVIWidget* documentWidget = new DVIWidget(scrollView()->viewport(), scrollView(), pageCache, + "singlePageWidget" ); + + // Lets not forget the connections we make in the KMultiPage + connect(documentWidget, SIGNAL(clearSelection()), this, SLOT(clearSelection())); + connect(this, SIGNAL(enableMoveTool(bool)), documentWidget, SLOT(slotEnableMoveTool(bool))); + + // Handle source links + connect(documentWidget, SIGNAL(SRCLink(const QString&, QMouseEvent*, DocumentWidget*)), getRenderer(), + SLOT(handleSRCLink(const QString& ,QMouseEvent*, DocumentWidget*))); + + return documentWidget; +} + + +void KDVIMultiPage::initializePageCache() +{ + pageCache = new DVIPageCache(); +} + + +void KDVIMultiPage::showFindTextDialog() +{ + if ((getRenderer().isNull()) || (getRenderer()->supportsTextSearch() == false)) + return; + + if (!searchUsed) + { + // WARNING: This text appears several times in the code. Change + // everywhere, or nowhere! + if (KMessageBox::warningContinueCancel( scrollView(), + i18n("This function searches the DVI file for plain text. Unfortunately, this version of " + "KDVI treats only plain ASCII characters properly. Symbols, ligatures, mathematical " + "formulae, accented characters, and non-English text, such as Russian or Korean, will " + "most likely be messed up completely. Continue anyway?"), + i18n("Function May Not Work as Expected"), + KStdGuiItem::cont(), + "warning_search_text_may_not_work") == KMessageBox::Cancel) + return; + + // Remember that we don't need to show the warning message again. + searchUsed = true; + } + + // Now really show the search widget + KMultiPage::showFindTextDialog(); +} + +#include "kdvi_multipage.moc" diff --git a/kdvi/kdvi_multipage.h b/kdvi/kdvi_multipage.h new file mode 100644 index 00000000..713afab7 --- /dev/null +++ b/kdvi/kdvi_multipage.h @@ -0,0 +1,96 @@ +// -*- C++ -*- +#ifndef KDVIMULTIPAGE_H +#define KDVIMULTIPAGE_H + +#include "kmultipage.h" +#include "dviRenderer.h" + +#include + +class KPrinter; + +class KDVIMultiPage : public KMultiPage +{ + Q_OBJECT + +public: + KDVIMultiPage(QWidget *parentWidget, const char *widgetName, QObject *parent, + const char *name, const QStringList& args = QStringList()); + virtual ~KDVIMultiPage(); + +// Interface definition start ------------------------------------------------ + + /// returns the list of supported file formats + virtual QStringList fileFormats() const; + + virtual void setFile(bool r); + + virtual void print(); + + /// KDVI offers read- and write functionality must re-implement this + /// method and return true here. + virtual bool isReadWrite() {return true;} + + virtual void addConfigDialogs(KConfigDialog* configDialog); + + static KAboutData* createAboutData(); + +private: + virtual DocumentWidget* createDocumentWidget(); + + virtual void initializePageCache(); + + /** Used to enable the export menu when a file is successfully + loaded. */ + virtual void enableActions(bool); + +public slots: + /** Opens a file requestor and saves. This really saves the content + of the DVI-file, and does not just start a copy job */ + virtual void slotSave(); + + /** Similar to slotSave, but does not ask for a filename. */ + virtual void slotSave_defaultFilename(); + + void setEmbedPostScriptAction(); + + void slotEmbedPostScript(); + + virtual void preferencesChanged(); + + /** Shows the "text search" dialog, if text search is supported by + the renderer. Otherwise, the method returns immediately. + We reimplement this slot to show a warning message that informs the + user about the currently limited search capabilities of KDVI. */ + virtual void showFindTextDialog(); + +protected slots: + void doExportText(); + void doEnableWarnings(); + + void showTip(); + void showTipOnStart(); + +private: + // Points to the same object as renderer to avoid downcasting. + // FIXME: Remove when the API of the Renderer-class is finished. + dviRenderer DVIRenderer; + + // Set to true if we used the search function atleast once. + // It is used to remember if we already have show the warning message. + bool searchUsed; + + /************************************************************* + * Methods and classes concerned with the find functionality * + *************************************************************/ + + /** Pointers to several actions which are disabled if no file is + loaded. */ + KAction *docInfoAction; + KAction *embedPSAction; + KAction *exportPDFAction; + KAction *exportPSAction; +}; + + +#endif diff --git a/kdvi/kdvi_multipage_texthandling.cpp b/kdvi/kdvi_multipage_texthandling.cpp new file mode 100644 index 00000000..c667584e --- /dev/null +++ b/kdvi/kdvi_multipage_texthandling.cpp @@ -0,0 +1,70 @@ +// +// Class: kdvi_multipage +// Author: Stefan Kebekus +// +// (C) 2001-2005, Stefan Kebekus. +// +// Previewer for TeX DVI files. +// +// 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. +// +// Please report bugs or improvements, etc. via the "Report bug"-Menu +// of kdvi. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kdvi_multipage.h" +#include "dviFile.h" +#include "documentWidget.h" +#include "renderedDocumentPagePixmap.h" + + +//#define KDVI_MULTIPAGE_DEBUG + + +void KDVIMultiPage::doExportText() +{ +#ifdef KDVI_MULTIPAGE_DEBUG + kdDebug(4300) << "KDVIMultiPage::doExportText() called" << endl; +#endif + + // Paranoid safety checks + if (DVIRenderer.dviFile == 0) + return; + if (DVIRenderer.dviFile->dvi_Data() == 0 ) + return; + + if (KMessageBox::warningContinueCancel( scrollView(), + i18n("This function exports the DVI file to a plain text. Unfortunately, this version of " + "KDVI treats only plain ASCII characters properly. Symbols, ligatures, mathematical " + "formulae, accented characters, and non-English text, such as Russian or Korean, will " + "most likely be messed up completely."), + i18n("Function May Not Work as Expected"), + i18n("Continue Anyway"), + "warning_export_to_text_may_not_work") == KMessageBox::Cancel) + return; + + KMultiPage::doExportText(); +} diff --git a/kdvi/kdvi_part.rc b/kdvi/kdvi_part.rc new file mode 100644 index 00000000..ded5f346 --- /dev/null +++ b/kdvi/kdvi_part.rc @@ -0,0 +1,26 @@ + + + + &File + + Export As + + + + + + &Edit + + + + + &Settings + + + + &Help + + + + + diff --git a/kdvi/kdvimultipage.desktop b/kdvi/kdvimultipage.desktop new file mode 100644 index 00000000..48a5e1fb --- /dev/null +++ b/kdvi/kdvimultipage.desktop @@ -0,0 +1,18 @@ +[Desktop Entry] +Type=Service +Comment=DVI +Name=KDVIMultiPage +Name[es]=KDVIMultiPágina +Name[fr]=Multi-page KDVI +Name[hu]=KDVITöbbOldalas +Name[nb]=KDVI Flerside +Name[ne]=केडीभीआई बहुपृष्ठ +Name[nl]=KDVIMultiPagina +Name[nn]=KDVI-fleirside +Name[pt]=KDVIMultiPágina +Name[ro]=KDVI Pagini Multiple +Name[sv]=KDVI flera sidor +ServiceTypes=KViewShell/MultiPage +X-KDE-Library=kdvipart +X-KDE-MimeTypes=application/x-dvi +X-KDE-MultiPageVersion=2 diff --git a/kdvi/kprinterwrapper.h b/kdvi/kprinterwrapper.h new file mode 100644 index 00000000..03959361 --- /dev/null +++ b/kdvi/kprinterwrapper.h @@ -0,0 +1,24 @@ +// -*- C++ -*- +// kprinterwrapper.h +// +// Part of KDVI - A DVI previewer for the KDE desktop environemt +// +// (C) 2003 Stefan Kebekus +// Distributed under the GPL + + +#ifndef _PRINTERWRAPPER_H +#define _PRINTERWRAPPER_H + +#include "kprinter.h" + + +class KDVIPrinterWrapper : public KPrinter +{ +public: + KDVIPrinterWrapper() : KPrinter(true, QPrinter::ScreenResolution) {; }; + + void doPreparePrinting() { preparePrinting(); }; +}; + +#endif diff --git a/kdvi/main.cpp b/kdvi/main.cpp new file mode 100644 index 00000000..4340f0e8 --- /dev/null +++ b/kdvi/main.cpp @@ -0,0 +1,154 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "kviewshell.h" + + +static KCmdLineOptions options[] = +{ + { "u", 0, 0 }, + { "unique", I18N_NOOP("Check if the file is loaded in another KDVI.\nIf it is, bring up the other KDVI. Otherwise, load the file."), 0 }, + { "g", 0, 0 }, + { "goto ", I18N_NOOP("Navigate to this page"), 0 }, + { "+file(s)", I18N_NOOP("Files to load"), 0 }, + KCmdLineLastOption +}; + + +static const char description[] = I18N_NOOP("A previewer for Device Independent files (DVI files) produced by the TeX typesetting system."); + + +int main(int argc, char** argv) +{ + KAboutData about ("kdvi", I18N_NOOP("KDVI"), "1.4", + description, KAboutData::License_GPL, + "Markku Hinhala, Stephan Kebekus", + I18N_NOOP("This program displays Device Independent (DVI) files which are produced by the TeX typesetting system.\n" + "This KDVI version is based on original code from KDVI version 0.43 and xdvik.")); + + about.addAuthor ("Stefan Kebekus", + I18N_NOOP("Current Maintainer."), + "kebekus@kde.org", + "http://www.mi.uni-koeln.de/~kebekus"); + + about.addAuthor ("Markku Hinhala", I18N_NOOP("Author of kdvi 0.4.3")); + about.addAuthor ("Nicolai Langfeldt", I18N_NOOP("Maintainer of xdvik")); + about.addAuthor ("Paul Vojta", I18N_NOOP("Author of xdvi")); + about.addCredit ("Philipp Lehmann", I18N_NOOP("Testing and bug reporting.")); + about.addCredit ("Wilfried Huss", I18N_NOOP("Re-organisation of source code.")); + + KCmdLineArgs::init(argc, argv, &about); + KCmdLineArgs::addCmdLineOptions(options); + KApplication app; + + // see if we are starting with session management + if (app.isRestored()) + { + RESTORE(KViewShell); + } + else + { + KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); + + if (args->isSet("unique")) + { + // With --unique, we need 2 arguments. + if (args->count() < 1) + { + args->usage(); + exit(-1); + } + + // Find the fully qualified file name of the file we are + // loading. Complain, if we are given a URL which does not point + // to a local file. + KURL url(args->url(0)); + + if (!url.isValid()) + { + kdError(4300) << QString(I18N_NOOP("The URL %1 is not well-formed.")).arg(args->arg(0)) << endl; + return -1; + } + + if (!url.isLocalFile()) + { + kdError(4300) << QString(I18N_NOOP("The URL %1 does not point to a local file. You can only specify local " + "files if you are using the '--unique' option.")).arg(args->arg(0)) << endl; + return -1; + } + + QString qualPath = QFileInfo(url.path()).absFilePath(); + + app.dcopClient()->attach(); + // We need to register as "kviewshell" to stay compatible with existing DCOP-skripts. + QCString id = app.dcopClient()->registerAs("unique-kviewshell"); + if (id.isNull()) + kdError(4300) << "There was an error using dcopClient()->registerAs()." << endl; + QCStringList apps = app.dcopClient()->registeredApplications(); + for ( QCStringList::Iterator it = apps.begin(); it != apps.end(); ++it ) + { + if ((*it).find("kviewshell") == 0) + { + QByteArray data, replyData; + QCString replyType; + QDataStream arg(data, IO_WriteOnly); + bool result; + arg << qualPath.stripWhiteSpace(); + if (!app.dcopClient()->call( *it, "kmultipage", "is_file_loaded(QString)", data, replyType, replyData)) + kdError(4300) << "There was an error using DCOP." << endl; + else + { + QDataStream reply(replyData, IO_ReadOnly); + if (replyType == "bool") + { + reply >> result; + if (result == true) + { + if (app.dcopClient()->send( *it, "kmultipage", "jumpToReference(QString)", url.ref()) == true) + { + app.dcopClient()->detach(); + return 0; + } + } + } + else + kdError(4300) << "The DCOP function 'doIt' returned an unexpected type of reply!"; + } + } + } + } + + // We need to register as "kviewshell" to stay compatible with existing DCOP-skripts. + app.dcopClient()->registerAs("kviewshell"); + KViewShell* shell = new KViewShell("application/x-dvi"); + shell->show(); + app.processEvents(); + + if (args->count() > 0) + { + KURL url = args->url(0); + if (!url.hasRef() && args->isSet("goto")) + { + // If the url doesn't already has a reference part, add the + // argument of --goto to the url as reference, to make the + // KViewShell jump to this page. + QString reference = args->getOption("goto"); + url.setHTMLRef(reference); + } + shell->openURL(url); + } + } + + return app.exec(); +} diff --git a/kdvi/make/ChangeLog b/kdvi/make/ChangeLog new file mode 100644 index 00000000..7f808ed6 --- /dev/null +++ b/kdvi/make/ChangeLog @@ -0,0 +1,370 @@ +Thu Apr 13 11:03:10 1995 Ulrik Vieth + + * paths.make: Add new variables for MetaPost directories: + mpinputdir, memdir, mppooldir. + + * makevars.make: Make sure that new variables for MetaPost + directories are passed on to sub-makes. + +Sun Jan 8 12:16:36 1995 Karl Berry + + * kpathsea 2.6/dviljk 2.5/dvipsk 5.58f/xdvik 18f. + +Wed Jan 4 12:41:25 1995 Karl Berry + + * tkpathsea.make (kpathsea): Don't depend on texmf.cnf, since it + doesn't exist at the first make. + +Tue Jan 3 13:43:12 1995 Karl Berry + + * rdepend.make (depend): paths.h is not in the srcdir. + + * config.make (autoconf): Add acsite.m4. + + * dist.make (top_files): FTP belongs here, not in ln_files. + +Sun Jan 1 14:02:42 1995 Karl Berry + + * makevars.make (makevars): Include web2cdir. + * paths.make (web2cdir): New directory. Suggested by Joachim. + +Sat Dec 31 14:35:29 1994 Karl Berry + + * tmtpk.make: Just incorporate this in kpathsea/Makefile.in now. + + * rdepend.make (depend): Depend on ourselves. + +Fri Dec 30 15:50:37 1994 Karl Berry + + * rdepend.make (depend): Use kpathsea_srcdir, not kpathsea_dir. + From Joachim. + +Wed Dec 28 14:16:50 1994 Karl Berry + + * dist.make (ln_files): Add FTP. + +Mon Dec 26 10:31:14 1994 Karl Berry + + * dist.make (dist): Copy aclocal.m4 from acsite.m4. + Suggested by interran@uluru.Stanford.EDU (John Interrante). + +Wed Dec 14 15:17:42 1994 Karl Berry + + * kpathsea 2.5/dviljk 2.4/dvipsk 5.58e/xdvik 18e. + +Sun Dec 11 13:23:12 1994 Karl Berry + + * rdepend.make (depend): Remove system include files that are + alone on a line. + +Fri Nov 25 09:21:02 1994 Karl Berry + + * tmtpk.make (MakeTeXPK): Depend on the new filename. + +Tue Nov 15 15:28:14 1994 Karl Berry + + * tkpathsea.make (makeargs): Change MAKEARGS to XMAKEARGS. + + * targets.make (makeargs): Don't bother to pass $(SHELL). + +Tue Nov 8 19:12:45 1994 Karl Berry + + * common.make (CFLAGS): Don't include -g, since now it's automatic. + +Sun Nov 6 15:53:36 1994 Karl Berry + + * paths.make (prefix, exec_prefix): These value are now @prefix@ + and @exec_prefix@. + + * common.make: Call @SET_MAKE@. + + * misc.make (distclean): Remove config.log and config.cache. + + * programs.make (LDFLAGS): Add @LDFLAGS@. + * common.make (CPPFLAGS): Add @CPPFLAGS@. + (CFLAGS): Add @CFLAGS@. + + * dist.make (top_files): Distribute install-sh, not install.sh, + for Autoconf 2.0. + +Sun Oct 30 16:15:34 1994 Karl Berry + + * config.make (ac_dir): This is now $(gnu)/share. + +Tue Oct 25 17:48:02 1994 Karl Berry + + * kpathsea 2.3/dviljk 2.3/dvipsk 5.58c/xdvik 18d. + +Sun Oct 23 17:33:56 1994 Karl Berry + + * targets.make (MakeTeXPK): Make sed substitutions global. + Reported by wfranzki@hlrserv.hlrz.kfa-juelich.de. + +Mon Oct 17 13:28:41 1994 Karl Berry + + * paths.make (mfpooldir): Doc fix. + +Fri Oct 14 10:31:35 1994 Karl Berry + + * kpathsea 2.2/dviljk 2.2/dvipsk 5.58b/xdvik 18c. + +Mon Oct 10 15:31:06 1994 Karl Berry + + * common.make (.SUFFIXES): Declare .c.o. + + * programs.make (LOADLIBES): Omit LEXLIB here. + +Sun Sep 25 15:54:36 1994 Karl Berry + + * rdepend.make: Doc fix. + + * library.make: New file. + + * makevars.make (makevars): Remove MAKEARGS from here. + + * programs.make (CCLD, link_command): New variables. + (LOADLIBES): Add proglib, LEXLIB. + +Mon Sep 12 11:06:14 1994 Karl Berry (karl@cs.umb.edu) + + * kpathsea 2.1/dviljk 2.1/dvipsk 5.58a/xdvik 18b. + +Sun Sep 11 14:44:21 1994 Karl Berry (karl@cs.umb.edu) + + * targets.make (install-MakeTeXPK): Install this if it didn't + exist, and mkdirchain $(scriptdir). + + * dist.make (top_files): Include aclocal.m4. + +Sat Sep 10 13:40:10 1994 Karl Berry (karl@cs.umb.edu) + + * texi.make (.texi.dvi): No -o option to texi2dvi. + +Thu Sep 8 14:31:59 1994 Karl Berry (karl@cs.umb.edu) + + * kpathsea 2.0, dviljk 2.0, dvipsk 5.55b, xdvik 18a. + +Tue Sep 6 11:39:06 1994 Karl Berry (karl@cs.umb.edu) + + * targets.make (MakeTeXPK): Use psheaderdir, not psconfigdir, and + depend on ourselves. + +Sat Sep 3 08:37:11 1994 Karl Berry (karl@cs.umb.edu) + + * paths.make (psconfigdir): Toss this. + + * misc.make (distclean): Add MakeTeXPK. + + * rdepend.make: Rename from depend.make. + +Fri Sep 2 13:29:14 1994 Karl Berry (karl@cs.umb.edu) + + * targets.make (makeargs, installargs): Declare these here. + + * makevars.make (makevars): No need for ??_fontdir or psmacrodir. + + * misc.make (TAGS): Omit -t, use -i, for Emacs 19.25's etags. + +Thu Sep 1 17:51:10 1994 Karl Berry (karl@cs.umb.edu) + + * dist.make (top_files): Add install.sh. + +Tue Aug 30 14:46:18 1994 Karl Berry (karl@cs.umb.edu) + + * dist.make (dist): Touch *.info* if they exist. + +Mon Aug 29 16:28:19 1994 Karl Berry (karl@cs.umb.edu) + + * paths.make (dcfontdir, sauterdir): Move these here, since + everyone has MakeTeXPK now. + +Sun Aug 28 17:09:09 1994 Karl Berry (karl@cs.umb.edu) + + * common.make (INSTALL_FONTS): New variable. + +Thu Aug 25 17:04:43 1994 Karl Berry (karl@cs.umb.edu) + + * kpathsea.make (kpathsea): Also depend on texmf.cnf.in. + + * paths.make (texmf_prefix): Rename to texmf; change uses. + +Sun Aug 21 11:03:48 1994 Karl Berry (karl@cs.umb.edu) + + * programs.make: New file for driver-specific stuff. + + * paths.make (fontnamedir): New definition. + (configdir, headerdir): Prepend with `ps'. + +Sat Aug 13 17:19:53 1994 Karl Berry (karl@cs.umb.edu) + + * misc.make (mostlyclean): Don't remove $(lib), since we've tossed + that. + +Sun Jul 31 14:18:28 1994 Karl Berry (karl@cs.umb.edu) + + * paths.make (DB_DIR, DB_NAME): Remove from here. + +Fri Jul 29 14:56:47 1994 Karl Berry (karl@cs.umb.edu) + + * depend.make (depend): Add dvilj4l.o to the special cases. + +Sun Jul 17 11:37:57 1994 Karl Berry (karl@cs.umb.edu) + + * paths.make (db_dir): Use $TEXMF. + +Mon Jun 27 17:32:47 1994 Karl Berry (karl@cs.umb.edu) + + * paths.make (db_dir): Use $TEXMFROOT. + +Tue Jun 14 12:41:33 1994 Karl Berry (karl@cs.umb.edu) + + * depend.make (depend): No need for depend_encies, I think. + +Mon May 30 13:50:34 1994 Karl Berry (karl@cs.umb.edu) + + * common.make (LDFLAGS): Don't include $(CFLAGS), for Linux's sake. + +Tue May 24 13:26:05 1994 Karl Berry (karl@cs.umb.edu) + + * config.make (stamp-auto, stamp-auto.in): New targets, to avoid + rerunning autoheader/autoconf even when they don't change the main + output files. + +Sun Apr 17 16:11:34 1994 Karl Berry (karl@ra.cs.umb.edu) + + * config.make (configure): Change ; to && in case the cd fails. + +Thu Mar 24 11:12:56 1994 Karl Berry (karl@cs.umb.edu) + + * dist.make (dist): Don't append kutil/ChangeLog to the source + ChangeLog. + + * misc.make (extraclean): Don't delete patch*, since that kills + patchlevel.h. + +Sat Mar 5 13:48:15 1994 Karl Berry (karl@cs.umb.edu) + + * common.make (LOADLIBES): Include XLOADLIBES. + +Fri Feb 25 14:21:17 1994 Karl Berry (karl@cs.umb.edu) + + * dist.make (dist): Append kutil/ChangeLog to the top level, not + the main program. + +Thu Feb 24 16:11:37 1994 Karl Berry (karl@cs.umb.edu) + + * misc.make (clean): Remove *.lj here. + + * paths.make ({bh,cg,mt}_fontdir, install_fonts): Add these. + +Mon Feb 21 14:04:26 1994 Karl Berry (karl@cs.umb.edu) + + * misc.make (distclean): remove pool files here. + +Wed Feb 16 15:18:13 1994 Karl Berry (karl@cs.umb.edu) + + * paths.make: Doc fix. + +Sun Jan 23 17:17:37 1994 Karl Berry (karl@cs.umb.edu) + + * dist.make (dist): Don't fake kpathsea/MACHINES any more, now we + have a real one. + +Fri Jan 14 14:53:12 1994 Karl Berry (karl@cs.umb.edu) + + * paths.make ({tex,mf}pooldir, fmtdir, basedir): Use + $(texmf_prefix)/ini for all these. + +Tue Dec 21 19:23:29 1993 Karl Berry (karl@cs.umb.edu) + + * common.make (LDFLAGS): Don't include $(x_lib_flags) here -- + winds up getting included twice for virmf + +Tue Dec 14 17:40:23 1993 Karl Berry (karl@cs.umb.edu) + + * dist.make (dist): Dist the top-level and kutil/ChangeLog. + + * paths.make (formatdir): Rename to fmtdir. + (texprefix): Rename to texmf_prefix, change uses accordingly. + +Fri Dec 10 17:50:39 1993 Karl Berry (karl@cs.umb.edu) + + * paths.make (dvipsprefix): Rename to dvips_prefix. + +Sun Nov 14 11:52:33 1993 Karl Berry (karl@cs.umb.edu) + + * dist.make (dist): Do not depend on depend.make and TAGS, since + web2c doesn't have them. + + * paths.make: Change defaults for new hierarchy. + +Thu Nov 11 11:07:22 1993 Karl Berry (karl@cs.umb.edu) + + * common.make (CPPFLAGS, LDFLAGS): xincludedir, xlibdir, wlibs + names have changed. + +Sun Nov 7 15:22:32 1993 Karl Berry (karl@cs.umb.edu) + + * paths.h: Give dire warning that editing Makefiles will not + rebuild paths.h. + +Fri Oct 29 14:01:57 1993 Karl Berry (karl@cs.umb.edu) + + * dist.make (dist): chmod a+rw. + +Thu Oct 28 17:48:01 1993 Karl Berry (karl@cs.umb.edu) + + * common.make (CPPFLAGS): Include -I. before -I$(srcdir). + +Fri Oct 22 13:08:19 1993 Karl Berry (karl@cs.umb.edu) + + * paths.make: Remove the paths, and add the dvips directories. + + * common.make (kpathsea_srcdir{,_parent}): Define. From + simon@lia.di.epfl.ch. + +Tue Oct 19 15:59:03 1993 Karl Berry (karl@cs.umb.edu) + + * config.make (stamp-c-auto): New target. + (c-auto.h): Depend on it. + +Sat Oct 9 07:04:45 1993 Karl Berry (karl@cs.umb.edu) + + * misc.make (mostlyclean): Remove programs. + +Sun Oct 3 12:44:04 1993 Karl Berry (karl@cs.umb.edu) + + * misc.make (extraclean): Also remove .blg and .bbl, .vf and .vpl. + (clean): Remove *.pool. + +Tue Sep 28 13:11:01 1993 Karl Berry (karl@cs.umb.edu) + + * common.make (CPPFLAGS): Add $(xincludedir) again; when did I + remove it? + +Fri Sep 24 07:53:45 1993 Karl Berry (karl@cs.umb.edu) + + * common.make (warn_more) [kpathsea]: Move to kpathsea's Makefile. + + * texi.make (.texi.dvi): New rule. + + * common.make (warn_more): Had -pointer-arith twice. + +Thu Sep 23 17:42:42 1993 Karl Berry (karl@cs.umb.edu) + + * common.make (autoconf): Toss aclocal.m4. + * dist.make (top_files): Ditto. + + * common.make (autoheader): New variable, split off from autoconf. + +Sun Aug 29 11:30:39 1993 Karl Berry (karl@cs.umb.edu) + + * dist.make (dist): Remove MACHINES in kpathsea. + + * common.make (CPPFLAGS): Remove the -I. Why did I put it there? + +Sat Aug 28 07:01:52 1993 Karl Berry (karl@cs.umb.edu) + + * unbackslsh.awk: New file. + + * common.make (CPPFLAGS): Add -I before $(xincludedir). diff --git a/kdvi/make/README b/kdvi/make/README new file mode 100644 index 00000000..f91b3d16 --- /dev/null +++ b/kdvi/make/README @@ -0,0 +1,3 @@ +make -- this subdirectory contains Makefile fragments. +configure substitutes them for ac_include lines in Makefile.in. +(This is an enhancement to standard Autoconf; see aclocal.m4.) diff --git a/kdvi/make/common.make b/kdvi/make/common.make new file mode 100644 index 00000000..9d9f822d --- /dev/null +++ b/kdvi/make/common.make @@ -0,0 +1,42 @@ +# common.make -- used by all Makefiles. +SHELL = /bin/sh +@SET_MAKE@ +top_srcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +CC = @CC@ +# CFLAGS is used for both compilation and linking. +CFLAGS = @CFLAGS@ $(XCFLAGS) + +# Do not override CPPFLAGS; change XCPPFLAGS, CFLAGS, XCFLAGS, or DEFS instead. +CPPFLAGS = $(XCPPFLAGS) -I. -I$(srcdir) \ + -I$(kpathsea_parent) -I$(kpathsea_srcdir_parent) \ + $(prog_cflags) @CPPFLAGS@ $(DEFS) +.c.o: + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< +.SUFFIXES: .c .o + +# Installation. +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +# This is used to recursively copy a fonts/ or tex/ directory to +# $(fontdir) or $(texinputdir). +# The first arg is `.', and the second is the target directory. +CP_R = cp -r + +# This is so kpathsea will get remade automatically if you change +# something in it and recompile from the package directory. +kpathsea_parent = .. +kpathsea_dir = $(kpathsea_parent)/kpathsea +kpathsea_srcdir_parent = $(top_srcdir)/.. +kpathsea_srcdir = $(kpathsea_srcdir_parent)/kpathsea +kpathsea = $(kpathsea_dir)/kpathsea.a + +##ifeq ($(CC), gcc) +##XDEFS = -Wall -Wpointer-arith $(warn_more) +##CFLAGS = -g $(XCFLAGS) +##endif +# End of common.make. diff --git a/kdvi/make/config.make b/kdvi/make/config.make new file mode 100644 index 00000000..c35cbebe --- /dev/null +++ b/kdvi/make/config.make @@ -0,0 +1,39 @@ +# config.make -- autoconf rules to remake the Makefile, c-auto.h, etc. + +##ifdef HOSTNAME +##ac_dir = $(gnu)/share/autoconf +##autoconf = $(ac_dir)/acspecific.m4 $(ac_dir)/acgeneral.m4 $(ac_dir)/acsite.m4 +##autoheader = $(ac_dir)/acconfig.h +## +### I define $(autoconf) to acgeneral.m4 and the other Autoconf files, so +### configure automatically gets remade in the sources with a new Autoconf +### release. But it would be bad for installers with Autoconf to remake +### configure (not to mention require Autoconf), so I take out the variable +### $(autoconf) definition before release. +##configure_in = $(srcdir)/configure.in $(kpathsea_srcdir)/common.ac +##$(srcdir)/configure: $(configure_in) $(autoconf) +## cd $(srcdir) && autoconf +##endif + +config.status: $(srcdir)/configure + $(SHELL) $(srcdir)/configure --no-create --verbose + +Makefile: $(srcdir)/Makefile.in config.status + $(SHELL) config.status + +# This rule isn't used for web2c or the top-level Makefile, but it +# doesn't hurt. We don't depend on config.status because configure +# always rewrites config.status, even when it doesn't change. Thus it +# might be newer than c-auto.h when we don't need to remake the latter. +c-auto.h: $(srcdir)/stamp-auto +$(srcdir)/stamp-auto: $(srcdir)/c-auto.h.in + $(SHELL) config.status + touch $(srcdir)/stamp-auto + +##ifdef HOSTNAME +### autoheader reads acconfig.h (and c-auto.h.top) automatically. +##$(srcdir)/c-auto.h.in: $(srcdir)/stamp-auto.in +##$(srcdir)/stamp-auto.in: $(configure_in) $(autoheader) $(srcdir)/acconfig.h +## cd $(srcdir) && autoheader +## touch $(srcdir)/stamp-auto.in +##endif diff --git a/kdvi/make/dist.make b/kdvi/make/dist.make new file mode 100644 index 00000000..39c619c7 --- /dev/null +++ b/kdvi/make/dist.make @@ -0,0 +1,33 @@ +# dist.make -- how to make the distribution tar file. + +top_distdir = $(distname)-$(version) +top_files = ChangeLog FTP Makefile.in configure configure.in README \ + $(HOME)/gnu/gnuorg/COPYING* $(HOME)/gnu/gnuorg/install-sh \ + $(HOME)/bin/mkdirchain \ + $(plain)/texinfo.tex +distdir = $(top_distdir)/$(distname) +kpathsea_distdir = ../$(distname)/$(top_distdir)/kpathsea +ln_files = AUTHORS ChangeLog INSTALL NEWS README TAGS *.in *.h *.c \ + configure *.make .gdbinit stamp-auto + +dist: depend.make TAGS pre-dist-$(distname) + rm -rf $(top_distdir)* + mkdir -p $(distdir) + cd ..; make Makefile ./configure + cd ..; cp -p $(top_files) $(distname)/$(top_distdir) + ln -s $(gnu)/share/autoconf/acsite.m4 $(top_distdir)/aclocal.m4 + -ln $(ln_files) $(distdir) + ln $(program_files) $(distdir) + cd $(kpathsea_dir); $(MAKE) distdir=$(kpathsea_distdir) \ + ln_files='$(ln_files)' distdir + cp -rp ../make $(top_distdir) + ungnumake $(distdir)/Makefile.in $(kpathsea_distdir)/Makefile.in \ + $(top_distdir)/Makefile.in $(top_distdir)/make/*.make +# Remove the extra files our patterns got us. + cd $(top_distdir); rm -f */depend.make */c-auto.h */Makefile + $(MAKE) post-dist-$(distname) + cd $(distdir); add-version $(version) $(version_files) + cd $(distdir); test ! -r *.info || touch *.info* + chmod -R a+rwX $(top_distdir) + GZIP=-9 tar chzf $(top_distdir).tar.gz $(top_distdir) + rm -rf $(top_distdir) diff --git a/kdvi/make/library.make b/kdvi/make/library.make new file mode 100644 index 00000000..c343bfd7 --- /dev/null +++ b/kdvi/make/library.make @@ -0,0 +1,5 @@ +# library.make -- stuff only useful for libraries. +AR = ar +ARFLAGS = cq +RANLIB = @RANLIB@ +# End of library.make. diff --git a/kdvi/make/makevars.make b/kdvi/make/makevars.make new file mode 100644 index 00000000..4b14f1be --- /dev/null +++ b/kdvi/make/makevars.make @@ -0,0 +1,20 @@ +# makevars.make -- the directory names we pass. +# It's important that none of these values contain [ @%], for the sake +# of kpathsea/texmf.sed. +makevars = prefix=$(prefix) exec_prefix=$(exec_prefix) \ + platform=$(platform) \ + bindir=$(bindir) scriptdir=$(scriptdir) libdir=$(libdir) \ + datadir=$(datadir) infodir=$(infodir) includedir=$(includedir) \ + manext=$(manext) mandir=$(mandir) \ + texmf=$(texmf) web2cdir=$(web2cdir) \ + texinputdir=$(texinputdir) mfinputdir=$(mfinputdir) \ + mpinputdir=$(mpinputdir) \ + fontdir=$(fontdir) \ + fmtdir=$(fmtdir) basedir=$(basedir) \ + memdir=$(memdir) \ + texpooldir=$(texpooldir) mfpooldir=$(mfpooldir) \ + mppooldir=$(mppooldir) \ + install_fonts=$(install_fonts) \ + dvipsdir=$(dvipsdir) psheaderdir=$(psheaderdir) \ + default_texsizes='$(default_texsizes)' +# End of makevars.make. diff --git a/kdvi/make/misc.make b/kdvi/make/misc.make new file mode 100644 index 00000000..7ee38cca --- /dev/null +++ b/kdvi/make/misc.make @@ -0,0 +1,31 @@ +# misc.make -- cleaning, etc. +TAGS: *.c *.h + if pwd | grep kpathsea >/dev/null; then \ + etags *.c *.h; else etags -i $(kpathsea_dir)/TAGS *.c *.h; fi + +mostlyclean:: + rm -f *.o $(program) $(programs) squeeze $(library).a + +clean:: mostlyclean + rm -f *.dvi *.lj + +distclean:: clean + rm -f Makefile MakeTeXPK *.pool + rm -f config.status config.log config.cache c-auto.h + +# Although we can remake configure and c-auto.h.in, we don't remove +# them, since many people may lack Autoconf. Use configclean for that. +realclean:: distclean + rm -f TAGS *.info* + +extraclean:: + rm -f *.aux *.bak *.bbl *.blg *.dvi *.log *.orig *.pl *.rej + rm -f *.i *.s *.tfm *.vf *.vpl *\#* *gf *pk *~ + rm -f CONTENTS.tex a.out core mfput.* texput.* + +configclean: + rm -f configure c-auto.h.in c-auto.h + +# Prevent GNU make 3.[59,63) from overflowing arg limit on system V. +.NOEXPORT: +# End of misc.make. diff --git a/kdvi/make/paths.make b/kdvi/make/paths.make new file mode 100644 index 00000000..529612cc --- /dev/null +++ b/kdvi/make/paths.make @@ -0,0 +1,99 @@ +# paths.make -- installation directories. +# +# The compile-time paths are defined in kpathsea/paths.h, which is built +# from kpathsea/paths.h.in and these definitions. See kpathsea/INSTALL +# for a description of how the various path-related files are used and +# created. + +# Do not change prefix and exec_prefix in Makefile.in! +# configure doesn't propagate the change to the other Makefiles. +# Instead, give the -prefix/-exec-prefix options to configure. +# (See kpathsea/INSTALL for more details.) This is arguably +# a bug, but it's not likely to change soon. +prefix = @prefix@ +exec_prefix = @exec_prefix@ +platform = $(shell $(srcdir)/config.guess | sed 's/-.*-/-/') + +# Architecture-dependent executables. +bindir = $(exec_prefix)/bin/$(platform) + +# Architecture-independent executables. +scriptdir = $(bindir) + +# Architecture-dependent files, such as lib*.a files. +libdir = $(exec_prefix)/lib + +# Architecture-independent files. +datadir = $(prefix)/lib + +# Header files. +includedir = $(prefix)/include + +# GNU .info* files. +infodir = $(prefix)/info + +# Unix man pages. +manext = 1 +mandir = $(prefix)/man/man$(manext) + +# TeX & MF-specific directories. Not all of the following are relevant +# for all programs, but it seems cleaner to collect everything in one place. + +# The default paths are now in kpathsea/paths.h.in. Passing all the +# paths to sub-makes can make the arg list too long on system V. + +# The root of the tree. +texmf = $(prefix)/texmf + +# TeX, MF, and MP source files. +texinputdir = $(texmf)/tex +mfinputdir = $(texmf)/mf +mpinputdir = $(texmf)/mp + +# MakeTeXPK.site, texmf.cnf, etc. +web2cdir = $(texmf)/web2c + +# The top-level font directory. +fontdir = $(texmf)/fonts + +# Memory dumps (.fmt, .base, and .mem). +fmtdir = $(texmf)/web2c +basedir = $(texmf)/web2c +memdir = $(texmf)/web2c + +# Pool files. +texpooldir = $(texmf)/web2c +mfpooldir = $(texmf)/web2c +mppooldir = $(texmf)/web2c + +# If install_fonts=true, the PostScript/LaserJet TFM and VF files for +# the builtin fonts get installed in subdirectories of this directory, +# named for the typeface families of these directories. If you don't +# have the default directory setup, you will want to set +# install_fonts=false. Ditto for install_macros. +install_fonts = false +install_macros = false + +# Where the .map files from fontname are installed. +fontnamedir = $(texmf)/fontname + +# Where the dvips configuration files get installed, and where +# psfonts.map is. +dvipsdir = $(texmf)/dvips +psheaderdir = $(dvipsdir) + +# MakeTeXPK will go here to create dc*. +dcfontdir = $(fontdir)/public/dc + +# MakeTeXPK will go here if it exists to create nonstandard CM fonts, +# e.g., cmr11. See ftp.cs.umb.edu:pub/tex/sauter.tar.gz. The Sauter +# files must be in your regular MFINPUTS. +sauterdir = $(fontdir)/public/sauter + +# If a font can't be found close enough to its stated size, we look for +# each of these sizes in the order given. This colon-separated list is +# overridden by the envvar TEXSIZES, and by a program-specific variable +# (e.g., XDVISIZES), and perhaps by a config file (e.g., in dvips). +default_texsizes = 300:600 + +# End of paths.make. diff --git a/kdvi/make/programs.make b/kdvi/make/programs.make new file mode 100644 index 00000000..e54b73b5 --- /dev/null +++ b/kdvi/make/programs.make @@ -0,0 +1,13 @@ +# programs.make -- used by Makefiles for executables only. +# Linking. Don't include $(CFLAGS), since ld -g under Linux forces +# static libraries, including libc.a and libX*.a +LDFLAGS = @LDFLAGS@ $(XLDFLAGS) +LIBS = @LIBS@ +# proglib is for web2c; +# XLOADLIBES is for the installer. +LOADLIBES= $(proglib) $(kpathsea) $(LIBS) -lm $(XLOADLIBES) + +# Why separate CCLD from CC? No particular reason. +CCLD = $(CXX) +link_command = $(CCLD) -o $@ $(LDFLAGS) +# End of programs.make. diff --git a/kdvi/make/rdepend.make b/kdvi/make/rdepend.make new file mode 100644 index 00000000..26ddeeb8 --- /dev/null +++ b/kdvi/make/rdepend.make @@ -0,0 +1,15 @@ +# rdepend.make -- rules for remaking the dependencies. +# Have to use -M, not -MM, since we use instead of +# "kpathsea/..." in the sources. But that means we have to remove the +# directory prefixes and all the system include files. +# And is generated, not part of the distribution. +depend depend.make:: c-auto.h $(top_srcdir)/../make/rdepend.make + $(CC) -M $(CPPFLAGS) *.c \ + | sed -e 's,\.\./kpathsea/,$$(kpathsea_srcdir)/,g' \ + -e 's,$$(kpathsea_srcdir)/paths.h,paths.h,g' \ + -e 's,/usr[^ ]* ,,g' \ + -e 's,/usr[^ ]*$$,,g' \ + -e 's,dvi2xx.o,dvilj.o dvilj2p.o dvilj4.o dvilj4l.o,' \ + | grep -v '^ *\\$$' \ + >depend.make +# End of rdepend.make. diff --git a/kdvi/make/texi.make b/kdvi/make/texi.make new file mode 100644 index 00000000..ff953cc7 --- /dev/null +++ b/kdvi/make/texi.make @@ -0,0 +1,13 @@ +# texi.make -- making .dvi and .info from .texi. + +MAKEINFO = makeinfo +MAKEINFO_FLAGS = --paragraph-indent=2 -I$(HOME)/gnu/gnuorg +# That -I is purely for my own benefit in doing `make dist'. It won't +# hurt anything for you (I hope). +TEXI2DVI = texi2dvi + +.SUFFIXES: .info .dvi .texi +.texi.info: + -$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@ +.texi.dvi: + -$(TEXI2DVI) $(TEXI2DVI_FLAGS) $< diff --git a/kdvi/make/tkpathsea.make b/kdvi/make/tkpathsea.make new file mode 100644 index 00000000..dd1b6d17 --- /dev/null +++ b/kdvi/make/tkpathsea.make @@ -0,0 +1,9 @@ +# tkpathsea.make -- remaking kpathsea. + +makeargs = $(MFLAGS) CC='$(CC)' CFLAGS='$(CFLAGS)' $(XMAKEARGS) + +$(kpathsea): $(kpathsea_srcdir)/*.c $(kpathsea_srcdir)/*.h \ + $(kpathsea_srcdir)/texmf.cnf.in $(top_srcdir)/../make/paths.make + cd $(kpathsea_dir); $(MAKE) $(makeargs) + +# End of tkpathsea.make. diff --git a/kdvi/optionDialogFontsWidget.cpp b/kdvi/optionDialogFontsWidget.cpp new file mode 100644 index 00000000..a3a76425 --- /dev/null +++ b/kdvi/optionDialogFontsWidget.cpp @@ -0,0 +1,47 @@ +// optionDiologWidget.cpp +// +// Part of KDVI - A DVI previewer for the KDE desktop environemt +// +// (C) 2003 Stefan Kebekus +// Distributed under the GPL + +// Add header files alphabetically + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "fontpool.h" +#include "optionDialogFontsWidget.h" + + +// Constructs a optionDialogWidget_base which is a child of 'parent', with +// the name 'name' and widget flags set to 'f'. +optionDialogFontsWidget::optionDialogFontsWidget( QWidget* parent, const char* name, WFlags fl ) + : optionDialogFontsWidget_base( parent, name, fl ) +{ +#ifndef HAVE_FREETYPE + kcfg_UseType1Fonts->setChecked(false); + kcfg_UseType1Fonts->setEnabled(false); + kcfg_UseFontHints->setEnabled(false); + kcfg_UseFontHints->setChecked(false); + QToolTip::add(PFB_ButtonGroup, i18n("This version of KDVI does not support type 1 fonts.")); + QWhatsThis::add(PFB_ButtonGroup, i18n("KDVI needs the FreeType library to access type 1 fonts. This library " + "was not present when KDVI was compiled. If you want to use type 1 " + "fonts, you must either install the FreeType library and recompile KDVI " + "yourself, or find a precompiled software package for your operating " + "system.")); +#endif +} + +optionDialogFontsWidget::~optionDialogFontsWidget() +{ +} + +#include "optionDialogFontsWidget.moc" diff --git a/kdvi/optionDialogFontsWidget.h b/kdvi/optionDialogFontsWidget.h new file mode 100644 index 00000000..63ce98cc --- /dev/null +++ b/kdvi/optionDialogFontsWidget.h @@ -0,0 +1,24 @@ +// -*- C++ -*- +// optionDialogFontsWidget.h +// +// Part of KDVI - A DVI previewer for the KDE desktop environemt +// +// (C) 2003 Stefan Kebekus +// Distributed under the GPL + +#ifndef OPTIONDIALOGFONTSWIDGET_H +#define OPTIONDIALOGFONTSWIDGET_H + +#include "optionDialogFontsWidget_base.h" + + +class optionDialogFontsWidget : public optionDialogFontsWidget_base +{ + Q_OBJECT + + public: + optionDialogFontsWidget( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 ); + ~optionDialogFontsWidget(); +}; + +#endif // OPTIONDIALOGFONTSWIDGET_H diff --git a/kdvi/optionDialogFontsWidget_base.ui b/kdvi/optionDialogFontsWidget_base.ui new file mode 100644 index 00000000..da4ca601 --- /dev/null +++ b/kdvi/optionDialogFontsWidget_base.ui @@ -0,0 +1,64 @@ + +optionDialogFontsWidget_base +Stefan Kebekus + + + optionDialogFontsWidget_base + + + + 0 + 0 + 325 + 54 + + + + + unnamed + + + 0 + + + + kcfg_UseFontHints + + + Use font hinting for Type 1 fonts, if available + + + You should enable this, if the use of font hinting improves readability on your machine. + + + Many modern fonts contain "font hinting" information which can be used to improve the appearance of a font on low-resolution displays, such as a computer monitor, or a notebook screen. However, many people find the "improved" fonts quite ugly and prefer to have this option disabled. + + + + + spacer11 + + + Vertical + + + Expanding + + + + 31 + 121 + + + + + + + kdialog.h + + + buttonGroup1_clicked(int) + + + + diff --git a/kdvi/optionDialogSpecialWidget.cpp b/kdvi/optionDialogSpecialWidget.cpp new file mode 100644 index 00000000..1e24f6cc --- /dev/null +++ b/kdvi/optionDialogSpecialWidget.cpp @@ -0,0 +1,135 @@ +// optionDialogSpecialWidget.cpp +// +// Part of KDVI - A DVI previewer for the KDE desktop environemt +// +// (C) 2003 Stefan Kebekus +// Distributed under the GPL + +// Add header files alphabetically + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "optionDialogSpecialWidget.h" +#include "prefs.h" + + +// Constructs a optionDialogWidget_base which is a child of 'parent', with +// the name 'name' and widget flags set to 'f'. +optionDialogSpecialWidget::optionDialogSpecialWidget( QWidget* parent, const char* name, WFlags fl ) + : optionDialogSpecialWidget_base( parent, name, fl ) +{ + // Set up the list of known and supported editors + editorNameString += i18n("User-Defined Editor"); + editorCommandString += ""; + editorDescriptionString += i18n("Enter the command line below."); + + editorNameString += "Emacs / emacsclient"; + editorCommandString += "emacsclient --no-wait +%l %f || emacs +%l %f"; + editorDescriptionString += i18n("Click 'Help' to learn how to set up Emacs."); + + editorNameString += "Kate"; + editorCommandString += "kate --use --line %l %f"; + editorDescriptionString += i18n("Kate perfectly supports inverse search."); + + editorNameString += "Kile"; + editorCommandString += "kile %f --line %l"; + editorDescriptionString += i18n("Kile works very well"); + + editorNameString += "NEdit"; + editorCommandString += "ncl -noask -line %l %f || nc -noask -line %l %f"; + editorDescriptionString += i18n("NEdit perfectly supports inverse search."); + + editorNameString += "VIM - Vi IMproved / GUI"; + editorCommandString += "gvim --servername KDVI --remote-silent +%l %f"; + editorDescriptionString += i18n("VIM version 6.0 or greater works just fine."); + + editorNameString += "XEmacs / gnuclient"; + editorCommandString += "gnuclient -q +%l %f || xemacs +%l %f"; + editorDescriptionString += i18n("Click 'Help' to learn how to set up XEmacs."); + + for(unsigned int i=0; iinsertItem(editorNameString[i]); + // Set the proper editor on the "Rendering-Page", try to recognize + // the editor command from the config-file. If the editor command is + // not recognized, switch to "User defined editor". That way, kdvi + // stays compatible even if the EditorCommands[] change between + // different versions of kdvi. + QString currentEditorCommand = Prefs::editorCommand(); + int i; + for(i = editorCommandString.count()-1; i>0; i--) + if (editorCommandString[i] == currentEditorCommand) + break; + if (i == 0) + usersEditorCommand = currentEditorCommand; + slotComboBox(i); + + connect(urll, SIGNAL(leftClickedURL(const QString&)), this, SLOT(slotExtraHelpButton(const QString&))); + connect(editorChoice, SIGNAL( activated( int ) ), this, SLOT( slotComboBox( int ) ) ); + + // Editor description strings (and their translations) vary in + // size. Find the longest description string available to make sure + // that the page is always large enough. + int maximumWidth = 0; + for ( QStringList::Iterator it = editorDescriptionString.begin(); it != editorDescriptionString.end(); ++it ) { + int width = editorDescription->fontMetrics().width(*it); + if (width > maximumWidth) + maximumWidth = width; + } + editorDescription->setMinimumWidth(maximumWidth+10); + + connect(kcfg_EditorCommand, SIGNAL( textChanged (const QString &) ), this, SLOT( slotUserDefdEditorCommand( const QString & ) ) ); +} + +optionDialogSpecialWidget::~optionDialogSpecialWidget() +{ +} + +void optionDialogSpecialWidget::slotUserDefdEditorCommand( const QString &text ) +{ + if (isUserDefdEditor == true) + EditorCommand = usersEditorCommand = text; +} + + +void optionDialogSpecialWidget::slotComboBox(int item) +{ + if (item != editorChoice->currentItem()) + editorChoice->setCurrentItem(item); + + editorDescription->setText(editorDescriptionString[item]); + + if (item != 0) { + isUserDefdEditor = false; + kcfg_EditorCommand->setText(editorCommandString[item]); + kcfg_EditorCommand->setReadOnly(true); + EditorCommand = editorCommandString[item]; + } else { + kcfg_EditorCommand->setText(usersEditorCommand); + kcfg_EditorCommand->setReadOnly(false); + EditorCommand = usersEditorCommand; + isUserDefdEditor = true; + } +} + +void optionDialogSpecialWidget::slotExtraHelpButton( const QString & ) +{ + kapp->invokeHelp( "inv-search", "kdvi" ); +} + +void optionDialogSpecialWidget::apply() +{ + Prefs::setEditorCommand(EditorCommand); +} + + +#include "optionDialogSpecialWidget.moc" diff --git a/kdvi/optionDialogSpecialWidget.h b/kdvi/optionDialogSpecialWidget.h new file mode 100644 index 00000000..cdd81100 --- /dev/null +++ b/kdvi/optionDialogSpecialWidget.h @@ -0,0 +1,36 @@ +// -*- C++ -*- +// optionDialogSpecialWidget.h +// +// Part of KDVI - A DVI previewer for the KDE desktop environemt +// +// (C) 2003 Stefan Kebekus +// Distributed under the GPL + +#ifndef OPTIONDIALOGSPECIALWIDGET_H +#define OPTIONDIALOGSPECIALWIDGET_H + +#include "optionDialogSpecialWidget_base.h" + + +class optionDialogSpecialWidget : public optionDialogSpecialWidget_base +{ + Q_OBJECT + + public: + optionDialogSpecialWidget( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 ); + ~optionDialogSpecialWidget(); + + public slots: + void apply(); + void slotComboBox(int item); + void slotUserDefdEditorCommand( const QString &text ); + void slotExtraHelpButton( const QString &anchor); + + private: + QStringList editorNameString, editorCommandString, editorDescriptionString; + QString EditorCommand; + bool isUserDefdEditor; + QString usersEditorCommand; +}; + +#endif // OPTIONDIALOGSPECIALWIDGET_H diff --git a/kdvi/optionDialogSpecialWidget_base.ui b/kdvi/optionDialogSpecialWidget_base.ui new file mode 100644 index 00000000..7aa36a26 --- /dev/null +++ b/kdvi/optionDialogSpecialWidget_base.ui @@ -0,0 +1,208 @@ + +optionDialogSpecialWidget_base + + + optionDialogSpecialWidget_base + + + + 0 + 0 + 519 + 201 + + + + + unnamed + + + 0 + + + + kcfg_ShowPS + + + Show PostScript specials + + + If in doubt, enable this option. + + + Some DVI files contain PostScript graphics. If enabled, KDVI will use the Ghostview PostScript interpreter to display these. You probably want to enable this option, unless you have a DVI-file whose PostScript part is broken, or too large for your machine. + + + + + buttonGroup3 + + + Editor for Inverse Search + + + + unnamed + + + + editorChoice + + + + 3 + 0 + 0 + 0 + + + + Choose an editor which is used in inverse search. + + + <p>Some DVI files contain 'inverse search' information. If such a DVI file is loaded, you can right-click into KDVI and an editor will open, load the TeX file and jump to the correct position. You can select your favorite editor here. If in doubt, 'nedit' is usually a good choice.</p> +<p>Check the KDVI manual to see how to prepare DVI files which support the inverse search.</p> + + + + + textLabel3 + + + + 4 + 5 + 0 + 0 + + + + Description: + + + + + textLabel4 + + + + 4 + 5 + 0 + 0 + + + + Shell command: + + + + + editorDescription + + + + 3 + 5 + 0 + 0 + + + + + + + Explains about the editor's capabilities in conjunction with inverse search. + + + <p>Not all editors are well suited for inverse search. For instance, many editors have no command like 'If the file is not yet loaded, load it. Otherwise, bring the window with the file to the front'. If you are using an editor like this, clicking into the DVI file will always open a new editor, even if the TeX file is already open. Likewise, many editors have no command line argument that would allow KDVI to specify the exact line which you wish to edit.</p> +<p>If you feel that KDVI's support for a certain editor is inadequate, please write to kebekus@kde.org.</p> + + + + + kcfg_EditorCommand + + + + 3 + 0 + 0 + 0 + + + + Shell-command line used to start the editor. + + + If you are using inverse search, KDVI uses this command line to start the editor. The field '%f' is replaced with the filename, and '%l' is replaced with the line number. + + + + + textLabel2 + + + + 4 + 5 + 0 + 0 + + + + Editor: + + + + + urll + + + + 4 + 5 + 0 + 0 + + + + What is 'inverse search'? + + + AlignVCenter|AlignRight + + + inv-search + + + + + spacer3 + + + Horizontal + + + Expanding + + + + 390 + 21 + + + + + + + + + + + + kcombobox.h + klineedit.h + kurllabel.h + + diff --git a/kdvi/performanceMeasurement.h b/kdvi/performanceMeasurement.h new file mode 100644 index 00000000..b6cb46c7 --- /dev/null +++ b/kdvi/performanceMeasurement.h @@ -0,0 +1,21 @@ +// -*- C++ -*- + +//#define PERFORMANCE_MEASUREMENT + +#ifdef PERFORMANCE_MEASUREMENT +#include + +// This is the central timer used for performance measurement. It is +// set to zero and started when the kdvi_multipage is +// constructed. This object is statically defined in +// kdvi_multipage.cpp. +extern QTime performanceTimer; + +// A flag that is set to true once the first page of the document was +// successfully drawn. This object is statically defined in +// kdvi_multipage.cpp. +// 0 = initial value +// 1 = first page was drawn +// 2 = last page was drawn +extern int performanceFlag; +#endif diff --git a/kdvi/pix/Makefile.am b/kdvi/pix/Makefile.am new file mode 100644 index 00000000..c43e4d48 --- /dev/null +++ b/kdvi/pix/Makefile.am @@ -0,0 +1,2 @@ +KDE_ICON = kdvi + diff --git a/kdvi/pix/hi16-app-kdvi.png b/kdvi/pix/hi16-app-kdvi.png new file mode 100644 index 00000000..dc4c71c6 Binary files /dev/null and b/kdvi/pix/hi16-app-kdvi.png differ diff --git a/kdvi/pix/hi22-app-kdvi.png b/kdvi/pix/hi22-app-kdvi.png new file mode 100644 index 00000000..0462047e Binary files /dev/null and b/kdvi/pix/hi22-app-kdvi.png differ diff --git a/kdvi/pix/hi32-app-kdvi.png b/kdvi/pix/hi32-app-kdvi.png new file mode 100644 index 00000000..848eb1c3 Binary files /dev/null and b/kdvi/pix/hi32-app-kdvi.png differ diff --git a/kdvi/pix/hi48-app-kdvi.png b/kdvi/pix/hi48-app-kdvi.png new file mode 100644 index 00000000..404462dc Binary files /dev/null and b/kdvi/pix/hi48-app-kdvi.png differ diff --git a/kdvi/pix/hisc-app-kdvi.svgz b/kdvi/pix/hisc-app-kdvi.svgz new file mode 100644 index 00000000..9e45007d Binary files /dev/null and b/kdvi/pix/hisc-app-kdvi.svgz differ diff --git a/kdvi/prebookmark.h b/kdvi/prebookmark.h new file mode 100644 index 00000000..141c8d6c --- /dev/null +++ b/kdvi/prebookmark.h @@ -0,0 +1,50 @@ +// -*- C++ -*- +/*************************************************************************** + * Copyright (C) 2005 by Stefan Kebekus * + * kebekus@kde.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 _PREBOOKMARK_H_ +#define _PREBOOKMARK_H_ + +#include + +/*! \brief Bookmark representation + +This class presents a bookmark in a format that is used internally by +the DVI prescan routines. +*/ + +class PreBookmark +{ + public: + PreBookmark(const QString& t, const QString& a, Q_UINT16 n) {title=t; anchorName=a; noOfChildren=n;} + PreBookmark() {title=QString::null; anchorName=QString::null; noOfChildren=0;} + + // Title of the bookmark + QString title; + + // Name of the anchor + QString anchorName; + + // Number of subordinate bookmarks + Q_UINT16 noOfChildren; +}; + +#endif diff --git a/kdvi/prefs.kcfgc b/kdvi/prefs.kcfgc new file mode 100644 index 00000000..7b77dce6 --- /dev/null +++ b/kdvi/prefs.kcfgc @@ -0,0 +1,5 @@ +# Code generation options for kconfig_compiler +File=kdvi.kcfg +ClassName=Prefs +Singleton=true +Mutators=true \ No newline at end of file diff --git a/kdvi/psgs.cpp b/kdvi/psgs.cpp new file mode 100644 index 00000000..9e23fcad --- /dev/null +++ b/kdvi/psgs.cpp @@ -0,0 +1,340 @@ +// +// ghostscript_interface +// +// Part of KDVI - A framework for multipage text/gfx viewers +// +// (C) 2004 Stefan Kebekus +// Distributed under the GPL + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "psgs.h" +#include "dviFile.h" +#include "pageNumber.h" + +extern const char psheader[]; + +//#define DEBUG_PSGS + + +pageInfo::pageInfo(const QString& _PostScriptString) { + PostScriptString = new QString(_PostScriptString); + background = Qt::white; + permanentBackground = Qt::white; +} + + +pageInfo::~pageInfo() { + if (PostScriptString != 0L) + delete PostScriptString; +} + + +// ====================================================== + +ghostscript_interface::ghostscript_interface() { + pageList.setAutoDelete(true); + + PostScriptHeaderString = new QString(); + + knownDevices.append("png256"); + knownDevices.append("jpeg"); + knownDevices.append("pnn"); + knownDevices.append("pnnraw"); + gsDevice = knownDevices.begin(); +} + +ghostscript_interface::~ghostscript_interface() { + if (PostScriptHeaderString != 0L) + delete PostScriptHeaderString; +} + + +void ghostscript_interface::setPostScript(const PageNumber& page, const QString& PostScript) { +#ifdef DEBUG_PSGS + kdDebug(4300) << "ghostscript_interface::setPostScript( " << page << ", ... )" << endl; +#endif + + if (pageList.find(page) == 0) { + pageInfo *info = new pageInfo(PostScript); + // Check if dict is big enough + if (pageList.count() > pageList.size() -2) + pageList.resize(pageList.size()*2); + pageList.insert(page, info); + } else + *(pageList.find(page)->PostScriptString) = PostScript; +} + + +void ghostscript_interface::setIncludePath(const QString &_includePath) { + if (_includePath.isEmpty()) + includePath = "*"; // Allow all files + else + includePath = _includePath+"/*"; +} + + +void ghostscript_interface::setBackgroundColor(const PageNumber& page, const QColor& background_color, bool permanent) { +#ifdef DEBUG_PSGS + kdDebug(4300) << "ghostscript_interface::setBackgroundColor( " << page << ", " << background_color << " )" << endl; +#endif + + if (pageList.find(page) == 0) { + pageInfo *info = new pageInfo(QString::null); + info->background = background_color; + if (permanent) + info->permanentBackground = background_color; + // Check if dict is big enough + if (pageList.count() > pageList.size() -2) + pageList.resize(pageList.size()*2); + pageList.insert(page, info); + } else { + pageList.find(page)->background = background_color; + if (permanent) + pageList.find(page)->permanentBackground = background_color; + } +} + +void ghostscript_interface::restoreBackgroundColor(const PageNumber& page) +{ +#ifdef DEBUG_PSGS + kdDebug(4300) << "ghostscript_interface::restoreBackgroundColor( " << page << " )" << endl; +#endif + if (pageList.find(page) == 0) + return; + + pageInfo *info = pageList.find(page); + info->background = info->permanentBackground; +} + +// Returns the background color for a certain page. This color is +// always guaranteed to be valid + +QColor ghostscript_interface::getBackgroundColor(const PageNumber& page) const { +#ifdef DEBUG_PSGS + kdDebug(4300) << "ghostscript_interface::getBackgroundColor( " << page << " )" << endl; +#endif + + if (pageList.find(page) == 0) + return Qt::white; + else + return pageList.find(page)->background; +} + + +void ghostscript_interface::clear() { + PostScriptHeaderString->truncate(0); + + // Deletes all items, removes temporary files, etc. + pageList.clear(); +} + + +void ghostscript_interface::gs_generate_graphics_file(const PageNumber& page, const QString& filename, long magnification) { +#ifdef DEBUG_PSGS + kdDebug(4300) << "ghostscript_interface::gs_generate_graphics_file( " << page << ", " << filename << " )" << endl; +#endif + + if (knownDevices.isEmpty()) { + kdError(4300) << "No known devices found" << endl; + return; + } + + emit(setStatusBarText(i18n("Generating PostScript graphics..."))); + + pageInfo *info = pageList.find(page); + + // Generate a PNG-file + // Step 1: Write the PostScriptString to a File + KTempFile PSfile(QString::null,".ps"); + + QTextStream& os = *PSfile.textStream(); + os << "%!PS-Adobe-2.0\n" + << "%%Creator: kdvi\n" + << "%%Title: KDVI temporary PostScript\n" + << "%%Pages: 1\n" + << "%%PageOrder: Ascend\n" + // HSize and VSize in 1/72 inch + << "%%BoundingBox: 0 0 " + << (Q_INT32)(72*(pixel_page_w/resolution)) << ' ' + << (Q_INT32)(72*(pixel_page_h/resolution)) << '\n' + << "%%EndComments\n" + << "%!\n" + << psheader + << "TeXDict begin " + // HSize in (1/(65781.76*72))inch + << (Q_INT32)(72*65781*(pixel_page_w/resolution)) << ' ' + // VSize in (1/(65781.76*72))inch + << (Q_INT32)(72*65781*(pixel_page_h/resolution)) << ' ' + // Magnification + << (Q_INT32)(magnification) + // dpi and vdpi + << " 300 300" + // Name + << " (test.dvi)" + << " @start end\n" + << "TeXDict begin\n" + // Start page + << "1 0 bop 0 0 a \n"; + + if (PostScriptHeaderString->latin1() != NULL) + os << PostScriptHeaderString->latin1(); + + if (info->background != Qt::white) { + QString colorCommand = QString("gsave %1 %2 %3 setrgbcolor clippath fill grestore\n"). + arg(info->background.red()/255.0). + arg(info->background.green()/255.0). + arg(info->background.blue()/255.0); + os << colorCommand.latin1(); + } + + if (info->PostScriptString->latin1() != NULL) + os << info->PostScriptString->latin1(); + + os << "end\n" + << "showpage \n"; + + PSfile.close(); + + // Step 2: Call GS with the File + QFile::remove(filename.ascii()); + KProcIO proc; + QStringList argus; + argus << "gs"; + argus << "-dSAFER" << "-dPARANOIDSAFER" << "-dDELAYSAFER" << "-dNOPAUSE" << "-dBATCH"; + argus << QString("-sDEVICE=%1").arg(*gsDevice); + argus << QString("-sOutputFile=%1").arg(filename); + argus << QString("-sExtraIncludePath=%1").arg(includePath); + argus << QString("-g%1x%2").arg(pixel_page_w).arg(pixel_page_h); // page size in pixels + argus << QString("-r%1").arg(resolution); // resolution in dpi + argus << "-c" << "<< /PermitFileReading [ ExtraIncludePath ] /PermitFileWriting [] /PermitFileControl [] >> setuserparams .locksafe"; + argus << "-f" << PSfile.name(); + +#ifdef DEBUG_PSGS + kdDebug(4300) << argus.join(" ") << endl; +#endif + + proc << argus; + if (proc.start(KProcess::Block) == false) { + // Starting ghostscript did not work. + // TODO: Issue error message, switch PS support off. + kdError(4300) << "ghostview could not be started" << endl; + } + PSfile.unlink(); + + // Check if gs has indeed produced a file. + if (QFile::exists(filename) == false) { + kdError(4300) << "GS did not produce output." << endl; + + // No. Check is the reason is that the device is not compiled into + // ghostscript. If so, try again with another device. + QString GSoutput; + while(proc.readln(GSoutput) != -1) { + if (GSoutput.contains("Unknown device")) { + kdDebug(4300) << QString("The version of ghostview installed on this computer does not support " + "the '%1' ghostview device driver.").arg(*gsDevice) << endl; + knownDevices.remove(gsDevice); + gsDevice = knownDevices.begin(); + if (knownDevices.isEmpty()) + // TODO: show a requestor of some sort. + KMessageBox::detailedError(0, + i18n("The version of Ghostview that is installed on this computer does not contain " + "any of the Ghostview device drivers that are known to KDVI. PostScript " + "support has therefore been turned off in KDVI."), + i18n("

The Ghostview program, which KDVI uses internally to display the " + "PostScript graphics that is included in this DVI file, is generally able to " + "write its output in a variety of formats. The sub-programs that Ghostview uses " + "for these tasks are called 'device drivers'; there is one device driver for " + "each format that Ghostview is able to write. Different versions of Ghostview " + "often have different sets of device drivers available. It seems that the " + "version of Ghostview that is installed on this computer does not contain " + "any of the device drivers that are known to KDVI.

" + "

It seems unlikely that a regular installation of Ghostview would not contain " + "these drivers. This error may therefore point to a serious misconfiguration of " + "the Ghostview installation on your computer.

" + "

If you want to fix the problems with Ghostview, you can use the command " + "gs --help to display the list of device drivers contained in " + "Ghostview. Among others, KDVI can use the 'png256', 'jpeg' and 'pnm' " + "drivers. Note that KDVI needs to be restarted to re-enable PostScript support." + "

")); + else { + kdDebug(4300) << QString("KDVI will now try to use the '%1' device driver.").arg(*gsDevice) << endl; + gs_generate_graphics_file(page, filename, magnification); + } + return; + } + } + } + emit(setStatusBarText(QString::null)); +} + + +void ghostscript_interface::graphics(const PageNumber& page, double dpi, long magnification, QPainter* paint) { +#ifdef DEBUG_PSGS + kdDebug(4300) << "ghostscript_interface::graphics( " << page << ", " << dpi << ", ... ) called." << endl; +#endif + + if (paint == 0) { + kdError(4300) << "ghostscript_interface::graphics(PageNumber page, double dpi, long magnification, QPainter *paint) called with paint == 0" << endl; + return; + } + + resolution = dpi; + + pixel_page_w = paint->viewport().width(); + pixel_page_h = paint->viewport().height(); + + pageInfo *info = pageList.find(page); + + // No PostScript? Then return immediately. + if ((info == 0) || (info->PostScriptString->isEmpty())) { +#ifdef DEBUG_PSGS + kdDebug(4300) << "No PostScript found. Not drawing anything." << endl; +#endif + return; + } + + KTempFile gfxFile(QString::null, ".png"); + gfxFile.setAutoDelete(1); + gfxFile.close(); // we are want the filename, not the file + + gs_generate_graphics_file(page, gfxFile.name(), magnification); + + QPixmap MemoryCopy(gfxFile.name()); + paint->drawPixmap(0, 0, MemoryCopy); + return; +} + + +QString ghostscript_interface::locateEPSfile(const QString &filename, const KURL &base) +{ + // If the base URL indicates that the DVI file is local, try to find + // the graphics file in the directory where the DVI file resides + if (base.isLocalFile()) { + QString path = base.path(); // -> "/bar/foo.dvi" + QFileInfo fi1(path); + QFileInfo fi2(fi1.dir(),filename); + if (fi2.exists()) + return fi2.absFilePath(); + } + + // Otherwise, use kpsewhich to find the eps file. + QString EPSfilename; + KProcIO proc; + proc << "kpsewhich" << filename; + proc.start(KProcess::Block); + proc.readln(EPSfilename); + + return EPSfilename.stripWhiteSpace(); +} + +#include "psgs.moc" diff --git a/kdvi/psgs.h b/kdvi/psgs.h new file mode 100644 index 00000000..0b6e679d --- /dev/null +++ b/kdvi/psgs.h @@ -0,0 +1,107 @@ +// -*- C++ -*- +// +// ghostscript_interface +// +// Part of KDVI - A framework for multipage text/gfx viewers +// +// (C) 2004 Stefan Kebekus +// Distributed under the GPL + +#ifndef _PSGS_H_ +#define _PSGS_H_ + +#include +#include +#include +#include + +class PageNumber; +class QPainter; + + +class pageInfo +{ +public: + pageInfo(const QString& _PostScriptString); + ~pageInfo(); + + QColor background; + QColor permanentBackground; + QString *PostScriptString; +}; + + +class ghostscript_interface : public QObject +{ + Q_OBJECT + +public: + ghostscript_interface(); + ~ghostscript_interface(); + + void clear(); + + // sets the PostScript which is used on a certain page + void setPostScript(const PageNumber& page, const QString& PostScript); + + // sets path from additional postscript files may be read + void setIncludePath(const QString &_includePath); + + // Sets the background color for a certain page. If permanent is false then the original + // background color can be restored by calling restoreBackground(page). + // The Option permanent = false is used when we want to display a different paper + // color as the one specified in the dvi file. + void setBackgroundColor(const PageNumber& page, const QColor& background_color, bool permanent = true); + + // Restore the background to the color which was specified by the last call to setBackgroundColor() + // With option permanent = true. + void restoreBackgroundColor(const PageNumber& page); + + // Draws the graphics of the page into the painter, if possible. If + // the page does not contain any graphics, nothing happens + void graphics(const PageNumber& page, double dpi, long magnification, QPainter* paint); + + // Returns the background color for a certain page. If no color was + // set, Qt::white is returned. + QColor getBackgroundColor(const PageNumber& page) const; + + QString *PostScriptHeaderString; + + /** This method tries to find the PostScript file 'filename' in the + DVI file's directory (if the base-URL indicates that the DVI file + is local), and, if that fails, uses kpsewhich to find the file. If + the file is found, the full path (including file name) is + returned. Otherwise, the method returns the first argument. TODO: + use the DVI file's baseURL, once this is implemented. + */ + static QString locateEPSfile(const QString &filename, const KURL &base); + +private: + void gs_generate_graphics_file(const PageNumber& page, const QString& filename, long magnification); + QIntDict pageList; + + double resolution; // in dots per inch + int pixel_page_w; // in pixels + int pixel_page_h; // in pixels + + QString includePath; + + // Output device that ghostscript is supposed tp use. Default is + // "png256". If that does not work, gs_generate_graphics_file will + // automatically try other known device drivers. If no known output + // device can be found, something is badly wrong. In that case, + // "gsDevice" is set to an empty string, and + // gs_generate_graphics_file will return immediately. + QValueListIterator gsDevice; + + // A list of known devices, set by the constructor. This includes + // "png256", "pnm". If a device is found to not work, its name is + // removed from the list, and another device name is tried. + QStringList knownDevices; + +signals: + /** Passed through to the top-level kpart. */ + void setStatusBarText( const QString& ); +}; + +#endif diff --git a/kdvi/psheader.txt b/kdvi/psheader.txt new file mode 100644 index 00000000..f5e543d1 --- /dev/null +++ b/kdvi/psheader.txt @@ -0,0 +1,113 @@ +% texc.pro +%! +/TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S +N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72 +mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0 +0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{ +landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize +mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[ +matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round +exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{ +statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0] +N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin +/FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array +/BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2 +array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N +df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A +definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get +}B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub} +B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr +1 add N}if}B/id 0 N/rw 0 N/rc 0 N/gp 0 N/cp 0 N/G 0 N/CharBuilder{save 3 +1 roll S A/base get 2 index get S/BitMaps get S get/Cd X pop/ctr 0 N Cdx +0 Cx Cy Ch sub Cx Cw add Cy setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx +sub Cy .1 sub]/id Ci N/rw Cw 7 add 8 idiv string N/rc 0 N/gp 0 N/cp 0 N{ +rc 0 ne{rc 1 sub/rc X rw}{G}ifelse}imagemask restore}B/G{{id gp get/gp +gp 1 add N A 18 mod S 18 idiv pl S get exec}loop}B/adv{cp add/cp X}B +/chg{rw cp id gp 4 index getinterval putinterval A gp add/gp X adv}B/nd{ +/cp 0 N rw exit}B/lsh{rw cp 2 copy get A 0 eq{pop 1}{A 255 eq{pop 254}{ +A A add 255 and S 1 and or}ifelse}ifelse put 1 adv}B/rsh{rw cp 2 copy +get A 0 eq{pop 128}{A 255 eq{pop 127}{A 2 idiv S 128 and or}ifelse} +ifelse put 1 adv}B/clr{rw cp 2 index string putinterval adv}B/set{rw cp +fillstr 0 4 index getinterval putinterval adv}B/fillstr 18 string 0 1 17 +{2 copy 255 put pop}for N/pl[{adv 1 chg}{adv 1 chg nd}{1 add chg}{1 add +chg nd}{adv lsh}{adv lsh nd}{adv rsh}{adv rsh nd}{1 add adv}{/rc X nd}{ +1 add set}{1 add clr}{adv 2 chg}{adv 2 chg nd}{pop nd}]A{bind pop} +forall N/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn +/BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put +}if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{ +bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A +mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{ +SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{ +userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X +1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4 +index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N +/p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{ +/Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT) +(LaserWriter 16/600)]{A length product length le{A length product exch 0 +exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse +end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask +grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot} +imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round +exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto +fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p +delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M} +B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{ +p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S +rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end + +% special.pro +%! +TeXDict begin/SDict 200 dict N SDict begin/@SpecialDefaults{/hs 612 N +/vs 792 N/ho 0 N/vo 0 N/hsc 1 N/vsc 1 N/ang 0 N/CLIP 0 N/rwiSeen false N +/rhiSeen false N/letter{}N/note{}N/a4{}N/legal{}N}B/@scaleunit 100 N +/@hscale{@scaleunit div/hsc X}B/@vscale{@scaleunit div/vsc X}B/@hsize{ +/hs X/CLIP 1 N}B/@vsize{/vs X/CLIP 1 N}B/@clip{/CLIP 2 N}B/@hoffset{/ho +X}B/@voffset{/vo X}B/@angle{/ang X}B/@rwi{10 div/rwi X/rwiSeen true N}B +/@rhi{10 div/rhi X/rhiSeen true N}B/@llx{/llx X}B/@lly{/lly X}B/@urx{ +/urx X}B/@ury{/ury X}B/magscale true def end/@MacSetUp{userdict/md known +{userdict/md get type/dicttype eq{userdict begin md length 10 add md +maxlength ge{/md md dup length 20 add dict copy def}if end md begin +/letter{}N/note{}N/legal{}N/od{txpose 1 0 mtx defaultmatrix dtransform S +atan/pa X newpath clippath mark{transform{itransform moveto}}{transform{ +itransform lineto}}{6 -2 roll transform 6 -2 roll transform 6 -2 roll +transform{itransform 6 2 roll itransform 6 2 roll itransform 6 2 roll +curveto}}{{closepath}}pathforall newpath counttomark array astore/gc xdf +pop ct 39 0 put 10 fz 0 fs 2 F/|______Courier fnt invertflag{PaintBlack} +if}N/txpose{pxs pys scale ppr aload pop por{noflips{pop S neg S TR pop 1 +-1 scale}if xflip yflip and{pop S neg S TR 180 rotate 1 -1 scale ppr 3 +get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg TR}if xflip +yflip not and{pop S neg S TR pop 180 rotate ppr 3 get ppr 1 get neg sub +neg 0 TR}if yflip xflip not and{ppr 1 get neg ppr 0 get neg TR}if}{ +noflips{TR pop pop 270 rotate 1 -1 scale}if xflip yflip and{TR pop pop +90 rotate 1 -1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get +neg sub neg TR}if xflip yflip not and{TR pop pop 90 rotate ppr 3 get ppr +1 get neg sub neg 0 TR}if yflip xflip not and{TR pop pop 270 rotate ppr +2 get ppr 0 get neg sub neg 0 S TR}if}ifelse scaleby96{ppr aload pop 4 +-1 roll add 2 div 3 1 roll add 2 div 2 copy TR .96 dup scale neg S neg S +TR}if}N/cp{pop pop showpage pm restore}N end}if}if}N/normalscale{ +Resolution 72 div VResolution 72 div neg scale magscale{DVImag dup scale +}if 0 setgray}N/psfts{S 65781.76 div N}N/startTexFig{/psf$SavedState +save N userdict maxlength dict begin/magscale true def normalscale +currentpoint TR/psf$ury psfts/psf$urx psfts/psf$lly psfts/psf$llx psfts +/psf$y psfts/psf$x psfts currentpoint/psf$cy X/psf$cx X/psf$sx psf$x +psf$urx psf$llx sub div N/psf$sy psf$y psf$ury psf$lly sub div N psf$sx +psf$sy scale psf$cx psf$sx div psf$llx sub psf$cy psf$sy div psf$ury sub +TR/showpage{}N/erasepage{}N/copypage{}N/p 3 def @MacSetUp}N/doclip{ +psf$llx psf$lly psf$urx psf$ury currentpoint 6 2 roll newpath 4 copy 4 2 +roll moveto 6 -1 roll S lineto S lineto S lineto closepath clip newpath +moveto}N/endTexFig{end psf$SavedState restore}N/@beginspecial{SDict +begin/SpecialSave save N gsave normalscale currentpoint TR +@SpecialDefaults count/ocount X/dcount countdictstack N}N/@setspecial{ +CLIP 1 eq{newpath 0 0 moveto hs 0 rlineto 0 vs rlineto hs neg 0 rlineto +closepath clip}if ho vo TR hsc vsc scale ang rotate rwiSeen{rwi urx llx +sub div rhiSeen{rhi ury lly sub div}{dup}ifelse scale llx neg lly neg TR +}{rhiSeen{rhi ury lly sub div dup scale llx neg lly neg TR}if}ifelse +CLIP 2 eq{newpath llx lly moveto urx lly lineto urx ury lineto llx ury +lineto closepath clip}if/showpage{}N/erasepage{}N/copypage{}N newpath}N +/@endspecial{count ocount sub{pop}repeat countdictstack dcount sub{end} +repeat grestore SpecialSave restore end}N/@defspecial{SDict begin}N +/@fedspecial{end}B/li{lineto}B/rl{rlineto}B/rc{rcurveto}B/np{/SaveX +currentpoint/SaveY X N 1 setlinecap newpath}N/st{stroke SaveX SaveY +moveto}N/fil{fill SaveX SaveY moveto}N/ellipse{/endangle X/startangle X +/yrad X/xrad X/savematrix matrix currentmatrix N TR xrad yrad scale 0 0 +1 startangle endangle arc savematrix setmatrix}N end diff --git a/kdvi/renderedDviPagePixmap.cpp b/kdvi/renderedDviPagePixmap.cpp new file mode 100644 index 00000000..3d123a24 --- /dev/null +++ b/kdvi/renderedDviPagePixmap.cpp @@ -0,0 +1,44 @@ +/*************************************************************************** + * Copyright (C) 2005 by Wilfried Huss * + * Wilfried.Huss@gmx.at * + * * + * 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 + +#include "renderedDviPagePixmap.h" +#include "hyperlink.h" + + +RenderedDviPagePixmap::RenderedDviPagePixmap() + : RenderedDocumentPagePixmap() +{ + sourceHyperLinkList.reserve(200); +} + +RenderedDviPagePixmap::~RenderedDviPagePixmap() +{ +} + +void RenderedDviPagePixmap::clear() +{ + RenderedDocumentPagePixmap::clear(); + + sourceHyperLinkList.clear(); +} + +#include "renderedDviPagePixmap.moc" diff --git a/kdvi/renderedDviPagePixmap.h b/kdvi/renderedDviPagePixmap.h new file mode 100644 index 00000000..3b0f7272 --- /dev/null +++ b/kdvi/renderedDviPagePixmap.h @@ -0,0 +1,49 @@ +// -*- C++ -*- +/*************************************************************************** + * Copyright (C) 2005 by Wilfried Huss * + * Wilfried.Huss@gmx.at * + * * + * 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 _RENDEREDDVIPAGEPIXMAP_H_ +#define _RENDEREDDVIPAGEPIXMAP_H_ + +#include "renderedDocumentPagePixmap.h" + +#include + + +class RenderedDviPagePixmap : public RenderedDocumentPagePixmap +{ + Q_OBJECT + + public: + RenderedDviPagePixmap(); + + virtual ~RenderedDviPagePixmap(); + + virtual void clear(); + + /** \brief List of source hyperlinks + + List of source-hyperlinks in the current page. This vector is + generated when the current page is drawn. + */ + QValueVector sourceHyperLinkList; +}; + +#endif diff --git a/kdvi/special.cpp b/kdvi/special.cpp new file mode 100644 index 00000000..23e58441 --- /dev/null +++ b/kdvi/special.cpp @@ -0,0 +1,727 @@ + +// special.cpp + +// Methods for dviRenderer which deal with "\special" commands found in the +// DVI file + +// Copyright 2000--2004, Stefan Kebekus (kebekus@kde.org). + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dviFile.h" +#include "dviRenderer.h" +#include "hyperlink.h" +#include "kdvi.h" +#include "kdvi_multipage.h" +#include "psgs.h" +#include "xdvi.h" + +//#define DEBUG_SPECIAL + +extern QPainter *foreGroundPainter; + +void dviRenderer::printErrorMsgForSpecials(const QString& msg) +{ + if (dviFile->errorCounter < 25) { + kdError(4300) << msg << endl; + dviFile->errorCounter++; + if (dviFile->errorCounter == 25) + kdError(4300) << i18n("That makes 25 errors. Further error messages will not be printed.") << endl; + } +} + +// Parses a color specification, as explained in the manual to +// dvips. If the spec could not be parsed, an invalid color will be +// returned. + +QColor dviRenderer::parseColorSpecification(const QString& colorSpec) +{ + // Initialize the map of known colors, if that is not done yet. + if (namedColors.isEmpty()) { + namedColors["Red"] = QColor( (int)(255.0*1), (int)(255.0*0), (int)(255.0*0)); + namedColors["Tan"] = QColor( (int)(255.0*0.86), (int)(255.0*0.58), (int)(255.0*0.44)); + namedColors["Blue"] = QColor( (int)(255.0*0), (int)(255.0*0), (int)(255.0*1)); + namedColors["Cyan"] = QColor( (int)(255.0*0), (int)(255.0*1), (int)(255.0*1)); + namedColors["Gray"] = QColor( (int)(255.0*0.5), (int)(255.0*0.5), (int)(255.0*0.5)); + namedColors["Plum"] = QColor( (int)(255.0*0.5), (int)(255.0*0), (int)(255.0*1)); + namedColors["Black"] = QColor( (int)(255.0*0), (int)(255.0*0), (int)(255.0*0)); + namedColors["Brown"] = QColor( (int)(255.0*0.4), (int)(255.0*0), (int)(255.0*0)); + namedColors["Green"] = QColor( (int)(255.0*0), (int)(255.0*1), (int)(255.0*0)); + namedColors["Melon"] = QColor( (int)(255.0*1), (int)(255.0*0.54), (int)(255.0*0.5)); + namedColors["Peach"] = QColor( (int)(255.0*1), (int)(255.0*0.5), (int)(255.0*0.3)); + namedColors["Sepia"] = QColor( (int)(255.0*0.3), (int)(255.0*0), (int)(255.0*0)); + namedColors["White"] = QColor( (int)(255.0*1), (int)(255.0*1), (int)(255.0*1)); + namedColors["Maroon"] = QColor( (int)(255.0*0.68), (int)(255.0*0), (int)(255.0*0)); + namedColors["Orange"] = QColor( (int)(255.0*1), (int)(255.0*0.39), (int)(255.0*0.13)); + namedColors["Orchid"] = QColor( (int)(255.0*0.68), (int)(255.0*0.36), (int)(255.0*1)); + namedColors["Purple"] = QColor( (int)(255.0*0.55), (int)(255.0*0.14), (int)(255.0*1)); + namedColors["Salmon"] = QColor( (int)(255.0*1), (int)(255.0*0.47), (int)(255.0*0.62)); + namedColors["Violet"] = QColor( (int)(255.0*0.21), (int)(255.0*0.12), (int)(255.0*1)); + namedColors["Yellow"] = QColor( (int)(255.0*1), (int)(255.0*1), (int)(255.0*0)); + namedColors["Apricot"] = QColor( (int)(255.0*1), (int)(255.0*0.68), (int)(255.0*0.48)); + namedColors["Emerald"] = QColor( (int)(255.0*0), (int)(255.0*1), (int)(255.0*0.5)); + namedColors["Fuchsia"] = QColor( (int)(255.0*0.45), (int)(255.0*0.01), (int)(255.0*0.92)); + namedColors["Magenta"] = QColor( (int)(255.0*1), (int)(255.0*0), (int)(255.0*1)); + namedColors["SkyBlue"] = QColor( (int)(255.0*0.38), (int)(255.0*1), (int)(255.0*0.88)); + namedColors["Thistle"] = QColor( (int)(255.0*0.88), (int)(255.0*0.41), (int)(255.0*1)); + namedColors["BrickRed"] = QColor( (int)(255.0*0.72), (int)(255.0*0), (int)(255.0*0)); + namedColors["Cerulean"] = QColor( (int)(255.0*0.06), (int)(255.0*0.89), (int)(255.0*1)); + namedColors["Lavender"] = QColor( (int)(255.0*1), (int)(255.0*0.52), (int)(255.0*1)); + namedColors["Mahogany"] = QColor( (int)(255.0*0.65), (int)(255.0*0), (int)(255.0*0)); + namedColors["Mulberry"] = QColor( (int)(255.0*0.64), (int)(255.0*0.08), (int)(255.0*0.98)); + namedColors["NavyBlue"] = QColor( (int)(255.0*0.06), (int)(255.0*0.46), (int)(255.0*1)); + namedColors["SeaGreen"] = QColor( (int)(255.0*0.31), (int)(255.0*1), (int)(255.0*0.5)); + namedColors["TealBlue"] = QColor( (int)(255.0*0.12), (int)(255.0*0.98), (int)(255.0*0.64)); + namedColors["BlueGreen"] = QColor( (int)(255.0*0.15), (int)(255.0*1), (int)(255.0*0.67)); + namedColors["CadetBlue"] = QColor( (int)(255.0*0.38), (int)(255.0*0.43), (int)(255.0*0.77)); + namedColors["Dandelion"] = QColor( (int)(255.0*1), (int)(255.0*0.71), (int)(255.0*0.16)); + namedColors["Goldenrod"] = QColor( (int)(255.0*1), (int)(255.0*0.9), (int)(255.0*0.16)); + namedColors["LimeGreen"] = QColor( (int)(255.0*0.5), (int)(255.0*1), (int)(255.0*0)); + namedColors["OrangeRed"] = QColor( (int)(255.0*1), (int)(255.0*0), (int)(255.0*0.5)); + namedColors["PineGreen"] = QColor( (int)(255.0*0), (int)(255.0*0.75), (int)(255.0*0.16)); + namedColors["RawSienna"] = QColor( (int)(255.0*0.55), (int)(255.0*0), (int)(255.0*0)); + namedColors["RedOrange"] = QColor( (int)(255.0*1), (int)(255.0*0.23), (int)(255.0*0.13)); + namedColors["RedViolet"] = QColor( (int)(255.0*0.59), (int)(255.0*0), (int)(255.0*0.66)); + namedColors["Rhodamine"] = QColor( (int)(255.0*1), (int)(255.0*0.18), (int)(255.0*1)); + namedColors["RoyalBlue"] = QColor( (int)(255.0*0), (int)(255.0*0.5), (int)(255.0*1)); + namedColors["RubineRed"] = QColor( (int)(255.0*1), (int)(255.0*0), (int)(255.0*0.87)); + namedColors["Turquoise"] = QColor( (int)(255.0*0.15), (int)(255.0*1), (int)(255.0*0.8)); + namedColors["VioletRed"] = QColor( (int)(255.0*1), (int)(255.0*0.19), (int)(255.0*1)); + namedColors["Aquamarine"] = QColor( (int)(255.0*0.18), (int)(255.0*1), (int)(255.0*0.7)); + namedColors["BlueViolet"] = QColor( (int)(255.0*0.1), (int)(255.0*0.05), (int)(255.0*0.96)); + namedColors["DarkOrchid"] = QColor( (int)(255.0*0.6), (int)(255.0*0.2), (int)(255.0*0.8)); + namedColors["OliveGreen"] = QColor( (int)(255.0*0), (int)(255.0*0.6), (int)(255.0*0)); + namedColors["Periwinkle"] = QColor( (int)(255.0*0.43), (int)(255.0*0.45), (int)(255.0*1)); + namedColors["Bittersweet"] = QColor( (int)(255.0*0.76), (int)(255.0*0.01), (int)(255.0*0)); + namedColors["BurntOrange"] = QColor( (int)(255.0*1), (int)(255.0*0.49), (int)(255.0*0)); + namedColors["ForestGreen"] = QColor( (int)(255.0*0), (int)(255.0*0.88), (int)(255.0*0)); + namedColors["GreenYellow"] = QColor( (int)(255.0*0.85), (int)(255.0*1), (int)(255.0*0.31)); + namedColors["JungleGreen"] = QColor( (int)(255.0*0.01), (int)(255.0*1), (int)(255.0*0.48)); + namedColors["ProcessBlue"] = QColor( (int)(255.0*0.04), (int)(255.0*1), (int)(255.0*1)); + namedColors["RoyalPurple"] = QColor( (int)(255.0*0.25), (int)(255.0*0.1), (int)(255.0*1)); + namedColors["SpringGreen"] = QColor( (int)(255.0*0.74), (int)(255.0*1), (int)(255.0*0.24)); + namedColors["YellowGreen"] = QColor( (int)(255.0*0.56), (int)(255.0*1), (int)(255.0*0.26)); + namedColors["MidnightBlue"] = QColor( (int)(255.0*0), (int)(255.0*0.44), (int)(255.0*0.57)); + namedColors["YellowOrange"] = QColor( (int)(255.0*1), (int)(255.0*0.58), (int)(255.0*0)); + namedColors["CarnationPink"] = QColor( (int)(255.0*1), (int)(255.0*0.37), (int)(255.0*1)); + namedColors["CornflowerBlue"] = QColor( (int)(255.0*0.35), (int)(255.0*0.87), (int)(255.0*1)); + namedColors["WildStrawberry"] = QColor( (int)(255.0*1), (int)(255.0*0.04), (int)(255.0*0.61)); + } + + QString specType = colorSpec.section(' ', 0, 0); + + if (specType.find("rgb", false) == 0) { + bool ok; + + double r = colorSpec.section(' ', 1, 1).toDouble(&ok); + if ((ok == false) || (r < 0.0) || (r > 1.0)) + return QColor(); + + double g = colorSpec.section(' ', 2, 2).toDouble(&ok); + if ((ok == false) || (g < 0.0) || (g > 1.0)) + return QColor(); + + double b = colorSpec.section(' ', 3, 3).toDouble(&ok); + if ((ok == false) || (b < 0.0) || (b > 1.0)) + return QColor(); + + return QColor((int)(r*255.0+0.5), (int)(g*255.0+0.5), (int)(b*255.0+0.5)); + } + + if (specType.find("hsb", false) == 0) { + bool ok; + + double h = colorSpec.section(' ', 1, 1).toDouble(&ok); + if ((ok == false) || (h < 0.0) || (h > 1.0)) + return QColor(); + + double s = colorSpec.section(' ', 2, 2).toDouble(&ok); + if ((ok == false) || (s < 0.0) || (s > 1.0)) + return QColor(); + + double b = colorSpec.section(' ', 3, 3).toDouble(&ok); + if ((ok == false) || (b < 0.0) || (b > 1.0)) + return QColor(); + + return QColor((int)(h*359.0+0.5), (int)(s*255.0+0.5), (int)(b*255.0+0.5), QColor::Hsv); + } + + if (specType.find("cmyk", false) == 0) { + bool ok; + + double c = colorSpec.section(' ', 1, 1).toDouble(&ok); + if ((ok == false) || (c < 0.0) || (c > 1.0)) + return QColor(); + + double m = colorSpec.section(' ', 2, 2).toDouble(&ok); + if ((ok == false) || (m < 0.0) || (m > 1.0)) + return QColor(); + + double y = colorSpec.section(' ', 3, 3).toDouble(&ok); + if ((ok == false) || (y < 0.0) || (y > 1.0)) + return QColor(); + + double k = colorSpec.section(' ', 3, 3).toDouble(&ok); + if ((ok == false) || (k < 0.0) || (k > 1.0)) + return QColor(); + + // Convert cmyk coordinates to rgb. + double r = 1.0 - c - k; + if (r < 0.0) + r = 0.0; + double g = 1.0 - m - k; + if (g < 0.0) + g = 0.0; + double b = 1.0 - y - k; + if (b < 0.0) + b = 0.0; + + return QColor((int)(r*255.0+0.5), (int)(g*255.0+0.5), (int)(b*255.0+0.5)); + } + + if (specType.find("gray", false) == 0) { + bool ok; + + double g = colorSpec.section(' ', 1, 1).toDouble(&ok); + if ((ok == false) || (g < 0.0) || (g > 1.0)) + return QColor(); + + return QColor((int)(g*255.0+0.5), (int)(g*255.0+0.5), (int)(g*255.0+0.5)); + } + + // Check if the color is one of the known named colors. + QMap::Iterator f = namedColors.find(specType); + if (f != namedColors.end()) + return *f; + + return QColor(specType); +} + + + + + + +void dviRenderer::color_special(const QString& _cp) +{ + QString const cp = _cp.stripWhiteSpace(); + + QString command = cp.section(' ', 0, 0); + + if (command == "pop") { + // Take color off the stack + if (colorStack.isEmpty()) + printErrorMsgForSpecials( i18n("Error in DVIfile '%1', page %2. Color pop command issued when the color stack is empty." ). + arg(dviFile->filename).arg(current_page)); + else + colorStack.pop(); + return; + } + + if (command == "push") { + // Get color specification + QColor const col = parseColorSpecification(cp.section(' ', 1)); + // Set color + if (col.isValid()) + colorStack.push(col); + else + colorStack.push(Qt::black); + return; + } + + // Get color specification and set the color for the rest of this + // page + QColor col = parseColorSpecification(cp); + // Set color + if (col.isValid()) + globalColor = col; + else + globalColor = Qt::black; + return; +} + + +void dviRenderer::html_href_special(const QString& _cp) +{ + QString cp = _cp; + cp.truncate(cp.find('"')); + +#ifdef DEBUG_SPECIAL + kdDebug(4300) << "HTML-special, href " << cp.latin1() << endl; +#endif + HTML_href = new QString(cp); +} + + +void dviRenderer::html_anchor_end() +{ +#ifdef DEBUG_SPECIAL + kdDebug(4300) << "HTML-special, anchor-end" << endl; +#endif + + if (HTML_href != NULL) { + delete HTML_href; + HTML_href = NULL; + } +} + + +void dviRenderer::source_special(const QString& cp) +{ + // only when rendering really takes place: set source_href to the + // current special string. When characters are rendered, the + // rendering routine will then generate a DVI_HyperLink and add it + // to the proper list. This DVI_HyperLink is used to match mouse + // positions with the hyperlinks for inverse search. + if (source_href) + *source_href = cp; + else + source_href = new QString(cp); +} + + +void parse_special_argument(const QString& strg, const char* argument_name, int* variable) +{ + int index = strg.find(argument_name); + if (index >= 0) { + QString tmp = strg.mid(index + strlen(argument_name)); + index = tmp.find(' '); + if (index >= 0) + tmp.truncate(index); + + bool OK; + float const tmp_float = tmp.toFloat(&OK); + + if (OK) + *variable = int(tmp_float+0.5); + else + // Maybe we should open a dialog here. + kdError(4300) << i18n("Malformed parameter in the epsf special command.\n" + "Expected a float to follow %1 in %2") + .arg(argument_name).arg(strg) << endl; + } +} + + +void dviRenderer::epsf_special(const QString& cp) +{ +#ifdef DEBUG_SPECIAL + kdDebug(4300) << "epsf-special: psfile=" << cp <getCmPerDVIunit() * 1200.0/2.54; + + bbox_width *= 0.1 * 65536.0*fontPixelPerDVIunit / shrinkfactor; + bbox_height *= 0.1 * 65536.0*fontPixelPerDVIunit / shrinkfactor; + + QImage image(EPSfilename); + image = image.smoothScale((int)(bbox_width), (int)(bbox_height)); + foreGroundPainter->drawImage( ((int) ((currinf.data.dvi_h) / (shrinkfactor * 65536))), currinf.data.pxl_v - (int)bbox_height, image); + return; + } + + if (!_postscript || !QFile::exists(EPSfilename)) { + // Don't show PostScript, just draw the bounding box. For this, + // calculate the size of the bounding box in Pixels. + double bbox_width = urx - llx; + double bbox_height = ury - lly; + + if ((rwi != 0)&&(bbox_width != 0)) { + bbox_height *= rwi/bbox_width; + bbox_width = rwi; + } + if ((rhi != 0)&&(bbox_height != 0)) { + bbox_width *= rhi/bbox_height; + bbox_height = rhi; + } + + double fontPixelPerDVIunit = dviFile->getCmPerDVIunit() * 1200.0/2.54; + + bbox_width *= 0.1 * 65536.0*fontPixelPerDVIunit / shrinkfactor; + bbox_height *= 0.1 * 65536.0*fontPixelPerDVIunit / shrinkfactor; + + QRect bbox(((int) ((currinf.data.dvi_h) / (shrinkfactor * 65536))), currinf.data.pxl_v - (int)bbox_height, + (int)bbox_width, (int)bbox_height); + + foreGroundPainter->save(); + + if (QFile::exists(EPSfilename)) + foreGroundPainter->setBrush(Qt::lightGray); + else + foreGroundPainter->setBrush(Qt::red); + foreGroundPainter->setPen(Qt::black); + foreGroundPainter->drawRoundRect(bbox, 2, 2); + QFont f = foreGroundPainter->font(); + f.setPointSize(8); + foreGroundPainter->setFont(f); + if (QFile::exists(EPSfilename)) + foreGroundPainter->drawText (bbox, (int)(Qt::AlignCenter), EPSfilename_orig, -1); + else + foreGroundPainter->drawText (bbox, (int)(Qt::AlignCenter), + i18n("File not found: \n %1").arg(EPSfilename_orig), -1); + foreGroundPainter->restore(); + } + + return; +} + + +void dviRenderer::TPIC_flushPath_special() +{ +#ifdef DEBUG_SPECIAL + kdDebug(4300) << "TPIC special flushPath" << endl; +#endif + + if (number_of_elements_in_path == 0) { + printErrorMsgForSpecials("TPIC special flushPath called when path was empty."); + return; + } + + QPen pen(Qt::black, (int)(penWidth_in_mInch*resolutionInDPI/1000.0 + 0.5)); // Sets the pen size in milli-inches + foreGroundPainter->setPen(pen); + foreGroundPainter->drawPolyline(TPIC_path, 0, number_of_elements_in_path); + number_of_elements_in_path = 0; +} + + +void dviRenderer::TPIC_addPath_special(const QString& cp) +{ +#ifdef DEBUG_SPECIAL + kdDebug(4300) << "TPIC special addPath: " << cp << endl; +#endif + + // Adds a point to the path list + QString cp_noWhiteSpace = cp.stripWhiteSpace(); + bool ok; + float xKoord = cp_noWhiteSpace.section(' ', 0, 0).toFloat(&ok); + if (ok == false) { + printErrorMsgForSpecials( QString("TPIC special; cannot parse first argument in 'pn %1'.").arg(cp) ); + return; + } + float yKoord = cp_noWhiteSpace.section(' ', 1, 1).toFloat(&ok); + if (ok == false) { + printErrorMsgForSpecials( QString("TPIC special; cannot parse second argument in 'pn %1'.").arg(cp) ); + return; + } + + float mag = dviFile->getMagnification()/1000.0; + + int x = (int)( currinf.data.dvi_h/(shrinkfactor*65536.0) + mag*xKoord*resolutionInDPI/1000.0 + 0.5 ); + int y = (int)( currinf.data.pxl_v + mag*yKoord*resolutionInDPI/1000.0 + 0.5 ); + + // Initialize the point array used to store the path + if (TPIC_path.size() == 0) + number_of_elements_in_path = 0; + if (TPIC_path.size() == number_of_elements_in_path) + TPIC_path.resize(number_of_elements_in_path+100); + TPIC_path.setPoint(number_of_elements_in_path++, x, y); +} + + +void dviRenderer::TPIC_setPen_special(const QString& cp) +{ +#ifdef DEBUG_SPECIAL + kdDebug(4300) << "TPIC special setPen: " << cp << endl; +#endif + + // Sets the pen size in milli-inches + bool ok; + penWidth_in_mInch = cp.stripWhiteSpace().toFloat(&ok); + if (ok == false) { + printErrorMsgForSpecials( QString("TPIC special; cannot parse argument in 'pn %1'.").arg(cp) ); + penWidth_in_mInch = 0.0; + return; + } +} + + +void dviRenderer::applicationDoSpecial(char *cp) +{ + QString special_command(cp); + + // First come specials which is only interpreted during rendering, + // and NOT during the prescan phase + + // font color specials + if (strncasecmp(cp, "color", 5) == 0) { + color_special(special_command.mid(5)); + return; + } + + // HTML reference + if (strncasecmp(cp, "html:", 9) == 0) { + html_anchor_end(); + return; + } + + // TPIC specials + if (strncasecmp(cp, "pn", 2) == 0) { + TPIC_setPen_special(special_command.mid(2)); + return; + } + if (strncasecmp(cp, "pa ", 3) == 0) { + TPIC_addPath_special(special_command.mid(3)); + return; + } + if (strncasecmp(cp, "fp", 2) == 0) { + TPIC_flushPath_special(); + return; + } + + // Encapsulated Postscript File + if (strncasecmp(cp, "PSfile=", 7) == 0) { + epsf_special(special_command.mid(7)); + return; + } + + // source special + if (strncasecmp(cp, "src:", 4) == 0) { + source_special(special_command.mid(4)); + return; + } + + // Unfortunately, in some TeX distribution the hyperref package uses + // the dvips driver by default, rather than the hypertex driver. As + // a result, the DVI files produced are full of PostScript that + // specifies links and anchors, and KDVI would call the ghostscript + // interpreter for every page which makes it really slow. This is a + // major nuisance, so that we try to filter and interpret the + // hypertex generated PostScript here. + if (special_command.startsWith("ps:SDict begin")) { + + // Hyperref: start of hyperref rectangle. At this stage it is not + // yet clear if the rectangle will conain a hyperlink, an anchor, + // or another type of object. We suspect that this rectangle will + // define a hyperlink, allocate a QString and set HTML_href to + // point to this string. The string contains the name of the + // destination which ---due to the nature of the PostScript + // language--- will be defined only after characters are drawn and + // the hyperref rectangle has been closed. We use "glopglyph" as a + // temporary name. Since the pointer HTML_href is not NULL, the + // chracter drawing routines will now underline all characters in + // blue to point out that they correspond to a hyperlink. Also, as + // soon as characters are drawn, the drawing routines will + // allocate a Hyperlink and add it to the top of the vector + // currentlyDrawnPage->hyperLinkList. + if (special_command == "ps:SDict begin H.S end") { + // At this stage, the vector 'hyperLinkList' should not contain + // links with unspecified destinations (i.e. destination set to + // 'glopglyph'). As a protection against bad DVI files, we make + // sure to remove all link rectangles which point to + // 'glopglyph'. + while (!currentlyDrawnPage->hyperLinkList.isEmpty()) + if (currentlyDrawnPage->hyperLinkList.last().linkText == "glopglyph") + currentlyDrawnPage->hyperLinkList.pop_back(); + else + break; + + HTML_href = new QString("glopglyph"); + return; + } + + // Hyperref: end of hyperref rectangle of unknown type or hyperref + // link rectangle. In these cases we set HTML_href to NULL, which + // causes the character drawing routines to stop drawing + // characters underlined in blue. Note that the name of the + // destination is still set to "glopglyph". In a well-formed DVI + // file, this special command is immediately followed by another + // special, where the destination is specified. This special is + // treated below. + if ((special_command == "ps:SDict begin H.R end") || special_command.endsWith("H.L end")) { + if (HTML_href != NULL) { + delete HTML_href; + HTML_href = NULL; + } + return; // end of hyperref rectangle + } + + // Hyperref: end of anchor rectangle. If this special is + // encountered, the rectangle, which was started with "ps:SDict + // begin H.S end" does not contain a link, but an anchor for a + // link. Anchors, however, have already been dealt with in the + // prescan phase and will not be considered here. Thus, we set + // HTML_href to NULL so that character drawing routines will no + // longer underline hyperlinks in blue, and remove the link from + // the hyperLinkList. NOTE: in a well-formed DVI file, the "H.A" + // special comes directly after the "H.S" special. A + // hyperlink-anchor rectangle therefore never contains characters, + // so no character will by accidentally underlined in blue. + if (special_command.endsWith("H.A end")) { + if (HTML_href != NULL) { + delete HTML_href; + HTML_href = NULL; + } + while (!currentlyDrawnPage->hyperLinkList.isEmpty()) + if (currentlyDrawnPage->hyperLinkList.last().linkText == "glopglyph") + currentlyDrawnPage->hyperLinkList.pop_back(); + else + break; + return; // end of hyperref anchor + } + + // Hyperref: specification of a hyperref link rectangle's + // destination. As mentioned above, the destination of a hyperlink + // is specified only AFTER the rectangle has been specified. We + // will therefore go through the list of rectangles stored in + // currentlyDrawnPage->hyperLinkList, find those whose destination + // is open and fill in the value found here. NOTE: the character + // drawing routines sometimes split a single hyperlink rectangle + // into several rectangles (e.g. if the font changes, or when a + // line break is encountered) + if (special_command.startsWith("ps:SDict begin [") && special_command.endsWith(" pdfmark end")) { + if (!currentlyDrawnPage->hyperLinkList.isEmpty()) { + // Parse the PostScript literal text string inside parentheses + // and store it into 'targetName'. The scanner works + // according to "PostScript language reference, third edition" + // - Sec. 3.2.2. The specification is implemented completely: + // balanced parentheses and all escape sequences are + // considered. + QString tmpTargetName = special_command.section('(', 1); + QString targetName; + int parencount = 1; + for(int i=0; i::iterator it; + for( it = currentlyDrawnPage->hyperLinkList.begin(); it != currentlyDrawnPage->hyperLinkList.end(); ++it ) + if (it->linkText == "glopglyph") + it->linkText = targetName; + } + return; // hyperref definition of link/anchor/bookmark/etc + } + } + + // Detect text rotation specials that are included by the graphicx + // package. If one of these specials is found, the state of the + // painter is saved, and the coordinate system is rotated + // accordingly + if (special_command.startsWith("ps: gsave currentpoint currentpoint translate ") && + special_command.endsWith(" neg rotate neg exch neg exch translate") ) { + bool ok; + double angle = special_command.section(' ', 5, 5).toDouble(&ok); + if (ok == true) { + int x = ((int) ((currinf.data.dvi_h) / (shrinkfactor * 65536))); + int y = currinf.data.pxl_v; + + foreGroundPainter->save(); + // Rotate about the current point + foreGroundPainter->translate(x,y); + foreGroundPainter->rotate(-angle); + foreGroundPainter->translate(-x,-y); + } else + printErrorMsgForSpecials( i18n("Error in DVIfile '%1', page %2. Could not interpret angle in text rotation special." ). + arg(dviFile->filename).arg(current_page)); + } + + // The graphicx package marks the end of rotated text with this + // special. The state of the painter is restored. + if (special_command == "ps: currentpoint grestore moveto") { + foreGroundPainter->restore(); + } + + // The following special commands are not used here; they are of + // interest only during the prescan phase. We recognize them here + // anyway, to make sure that KDVI doesn't complain about + // unrecognized special commands. + if ((cp[0] == '!') || + (cp[0] == '"') || + (strncasecmp(cp, "html: +#include +#define LINELENGTH (72) +#define BUFLENGTH (1000) +#undef putchar +#define putchar(a) (void)putc(a, out) ; +FILE *in, *out ; +static int linepos = 0 ; +static int lastspecial = 1 ; +static int stringlen = 0; + +void specialout(char); +void strout(char *); +void cmdout(char *); + +/* + * This next routine writes out a `special' character. In this case, + * we simply put it out, since any special character terminates the + * preceding token. + */ +void specialout(char c) +{ + if (linepos + 1 > LINELENGTH) { + (void)fputs("\\n\\\n", out); + stringlen += linepos + 1; + linepos = 0 ; + } + putchar(c) ; + linepos++ ; + lastspecial = 1 ; +} +void strout(s) +char *s ; +{ + if (linepos + strlen(s) > LINELENGTH) { + (void)fputs("\\n\\\n", out); + stringlen += linepos + 1; + linepos = 0 ; + } + linepos += strlen(s) ; + while (*s != 0) + putchar(*s++) ; + lastspecial = 1 ; +} +void cmdout(s) +char *s ; +{ + int l ; + + l = strlen(s) ; + if (linepos + l + 1 > LINELENGTH) { + (void)fputs("\\n\\\n", out); + stringlen += linepos + 1; + linepos = 0 ; + lastspecial = 1 ; + } + if (! lastspecial) { + putchar(' ') ; + linepos++ ; + } + while (*s != 0) { + putchar(*s++) ; + } + linepos += l ; + lastspecial = 0 ; +} +char buf[BUFLENGTH] ; + +int main(int argc, char *argv[]) +{ + int c ; + char *b ; + char seeking ; + extern void exit() ; + + if (argc > 3 || (in=(argc < 2 ? stdin : fopen(argv[1], "r")))==NULL || + (out=(argc < 3 ? stdout : fopen(argv[2], "w")))==NULL) { + (void)fprintf(stderr, "Usage: squeeze [infile [outfile]]\n") ; + exit(1) ; + } + (void)fputs("/*\n\ + * DO NOT EDIT THIS FILE!\n\ + * It was created by squeeze.c from another file (see the Makefile).\n\ + */\n\n\ +#ifndef _Xconst\n\ +#if __STDC__\n\ +#define _Xconst const\n\ +#else\n\ +#define _Xconst\n\ +#endif\n\ +#endif\n\n\ +_Xconst char psheader[] = \"\\\n", out); + while (1) { + c = getc(in) ; + if (c==EOF) + break ; + if (c=='%') { + while ((c=getc(in))!='\n') ; + } + if (c <= ' ') + continue ; + switch (c) { +case '{' : +case '}' : +case '[' : +case ']' : + specialout(c) ; + break ; +case '<' : +case '(' : + if (c=='(') + seeking = ')' ; + else + seeking = '>' ; + b = buf ; + *b++ = c ; + do { + c = getc(in) ; + if (b > buf + BUFLENGTH-2) { + (void)fprintf(stderr, "Overran buffer seeking %c", seeking) ; + exit(1) ; + } + *b++ = c ; + if (c=='\\') + *b++ = getc(in) ; + } while (c != seeking) ; + *b++ = 0 ; + strout(buf) ; + break ; +default: + b = buf ; + while ((c>='A'&&c<='Z')||(c>='a'&&c<='z')|| + (c>='0'&&c<='9')||(c=='/')||(c=='@')|| + (c=='!')||(c=='"')||(c=='&')||(c=='*')||(c==':')|| + (c==',')||(c==';')||(c=='?')||(c=='^')||(c=='~')|| + (c=='-')||(c=='.')||(c=='#')||(c=='|')||(c=='_')|| + (c=='=')||(c=='$')||(c=='+')) { + *b++ = c ; + c = getc(in) ; + } + if (b == buf) { + (void)fprintf(stderr, "Oops! Missed a case: %c.\n", c) ; + exit(1) ; + } + *b++ = 0 ; + (void)ungetc(c, in) ; + cmdout(buf) ; + } + } + (void)fprintf(out, "\\n\";\n\n\ +int\tpsheaderlen\t= %d;\n", stringlen + linepos + 1); + return (0) ; + /*NOTREACHED*/ +} diff --git a/kdvi/tips b/kdvi/tips new file mode 100644 index 00000000..399d4427 --- /dev/null +++ b/kdvi/tips @@ -0,0 +1,42 @@ + + +

...that KDVI can also load compressed DVI-files? + + + + + +

...that you can mark text with the right mouse button and paste it +into any application? + + + + + +

...that KDVI now supports inverse search? You can click into your DVI file +with the middle mouse button and your editor opens, loads the TeX file, and +jumps to the proper line! The +manual explains how to set up your editor for this. + + + + + +

...that KDVI supports forward search? If you use Emacs or XEmacs, you can +jump directly from the TeX file to the associated place in the DVI file. +The manual explains how to set up +your editor for this. + + + + + +

...that KDVI now offers full text search? + + + + + +

...that KDVI can save your DVI file as PostScript, PDF, and even plain text? + + diff --git a/kdvi/util.cpp b/kdvi/util.cpp new file mode 100644 index 00000000..d25b7e03 --- /dev/null +++ b/kdvi/util.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 1994 Paul Vojta. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * NOTE: + * xdvi is based on prior work as noted in the modification history, below. + */ + +/* + * DVI previewer for X. + * + * Eric Cooper, CMU, September 1985. + * + * Code derived from dvi-imagen.c. + * + * Modification history: + * 1/1986 Modified for X.10 --Bob Scheifler, MIT LCS. + * 7/1988 Modified for X.11 --Mark Eichin, MIT + * 12/1988 Added 'R' option, toolkit, magnifying glass + * --Paul Vojta, UC Berkeley. + * 2/1989 Added tpic support --Jeffrey Lee, U of Toronto + * 4/1989 Modified for System V --Donald Richardson, Clarkson Univ. + * 3/1990 Added VMS support --Scott Allendorf, U of Iowa + * 7/1990 Added reflection mode --Michael Pak, Hebrew U of Jerusalem + * 1/1992 Added greyscale code --Till Brychcy, Techn. Univ. Muenchen + * and Lee Hetherington, MIT + * 4/1994 Added DPS support, bounding box + * --Ricardo Telichevesky + * and Luis Miguel Silveira, MIT RLE. + */ + +#include + +#include +#include +#include + +#include "dviRenderer.h" +#include "xdvi.h" + + + +/* + * General utility routines. + */ + +/* + * Print error message and quit. + */ + +void oops(QString message) +{ + kdError() << i18n("Fatal Error! ") << message << endl; + + KMessageBox::error( NULL, + i18n("Fatal error.\n\n") + + message + + i18n("\n\n\ +This probably means that either you found a bug in KDVI,\n\ +or that the DVI file, or auxiliary files (such as font files, \n\ +or virtual font files) were really badly broken.\n\ +KDVI will abort after this message. If you believe that you \n\ +found a bug, or that KDVI should behave better in this situation\n\ +please report the problem.")); + exit(1); +} + +/* + * + * Read size bytes from the FILE fp, constructing them into a + * signed/unsigned integer. + * + */ + +unsigned long num(FILE *fp, int size) +{ + register long x = 0; + + while (size--) x = (x << 8) | one(fp); + return x; +} + +long snum(FILE *fp, int size) +{ + register long x; + +#ifdef __STDC__ + x = (signed char) getc(fp); +#else + x = (unsigned char) getc(fp); + if (x & 0x80) x -= 0x100; +#endif + while (--size) x = (x << 8) | one(fp); + return x; +} diff --git a/kdvi/vf.cpp b/kdvi/vf.cpp new file mode 100644 index 00000000..36cad0ba --- /dev/null +++ b/kdvi/vf.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (c) 1994 Paul Vojta. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include + +#include "dvi.h" +#include "dviRenderer.h" +#include "fontpool.h" +#include "xdvi.h" + +extern void oops(QString message); + +/*** + *** VF font reading routines. + *** Public routine is read_index---because virtual characters are presumed + *** to be short, we read the whole virtual font in at once, instead of + *** faulting in characters as needed. + ***/ + +#define LONG_CHAR 242 + +/* + * These are parameters which determine whether macros are combined for + * storage allocation purposes. Small macros ( <= VF_PARM_1 bytes) are + * combined into chunks of size VF_PARM_2. + */ + +#ifndef VF_PARM_1 +#define VF_PARM_1 20 +#endif +#ifndef VF_PARM_2 +#define VF_PARM_2 256 +#endif + +/* + * The main routine + */ + +void TeXFontDefinition::read_VF_index() +{ +#ifdef DEBUG_FONTS + kdDebug(4300) << "font::read_VF_index()" << endl; +#endif + FILE *VF_file = file; + unsigned char cmnd; + unsigned char *avail, *availend; /* available space for macros */ + + flags |= FONT_VIRTUAL; + set_char_p = &dviRenderer::set_vf_char; +#ifdef DEBUG_FONTS + kdDebug(4300) << "TeXFontDefinition::read_VF_index: reading VF pixel file " << filename << endl; +#endif + // Read preamble. + fseek(VF_file, (long) one(VF_file), 1); /* skip comment */ + Q_UINT32 file_checksum = four(VF_file); + + if (file_checksum && checksum && file_checksum != checksum) + kdError(4300) << i18n("Checksum mismatch") << "(dvi = " << checksum << "u, vf = " << file_checksum << + "u)" << i18n(" in font file ") << filename << endl; + (void) four(VF_file); /* skip design size */ + + // Read the fonts. + first_font = NULL; + while ((cmnd = one(VF_file)) >= FNTDEF1 && cmnd <= FNTDEF4) { + int TeXnumber = num(VF_file, (int) cmnd - FNTDEF1 + 1); + Q_UINT32 checksum = four(VF_file); + Q_UINT32 scale = four(VF_file); + Q_UINT32 design = four(VF_file); + Q_UNUSED(design); + Q_UINT16 len = one(VF_file) + one(VF_file); /* sequence point in the middle */ + char *fontname = new char[len + 1]; + fread(fontname, sizeof(char), len, VF_file); + fontname[len] = '\0'; + +#ifdef DEBUG_FONTS + kdDebug(4300) << "Virtual font defines subfont \"" << fontname << "\" scale=" << scale << " design=" << design << endl; +#endif + + // According to Knuth's documentation found in the web source code + // of the "vftovp" program (which seems to be the standard + // definition of virtual fonts), the "scale" is a fixed point + // number which describes extra enlargement that the virtual font + // imposes. One obtains the enlargement by dividing 2^20. + double enlargement_factor = double(scale)/(1<<20) * enlargement; + + // TeXFontDefinition *newfontp = font_pool->appendx(fontname, checksum, (Q_UINT32)(scaled_size_in_DVI_units*enlargement_factor), enlargement_factor); + TeXFontDefinition *newfontp = font_pool->appendx(fontname, checksum, (Q_UINT32)((double(scale)/(1<<20))*scaled_size_in_DVI_units), enlargement_factor); + + // Insert font in dictionary and make sure the dictionary is big + // enough. + if (vf_table.size()-2 <= vf_table.count()) + // Not quite optimal. The size of the dictionary should be a + // prime. I don't care. + vf_table.resize(vf_table.size()*2); + vf_table.insert(TeXnumber, newfontp); + + if (first_font == NULL) + first_font = newfontp; + } + + // Prepare macro array. + macrotable = new macro[max_num_of_chars_in_font]; + if (macrotable == 0) { + kdError() << i18n("Could not allocate memory for a macro table.") << endl; + exit(0); + } + + // Read macros. + avail = availend = NULL; + for (; cmnd <= LONG_CHAR; cmnd = one(VF_file)) { + macro *m; + int len; + unsigned long cc; + long width; + + if (cmnd == LONG_CHAR) { /* long form packet */ + len = four(VF_file); + cc = four(VF_file); + width = four(VF_file); + if (cc >= 256) { + kdError() << i18n("Virtual character ") << cc << i18n(" in font ") + << fontname << i18n(" ignored.") << endl; + fseek(VF_file, (long) len, 1); + continue; + } + } else { /* short form packet */ + len = cmnd; + cc = one(VF_file); + width = num(VF_file, 3); + } + m = ¯otable[cc]; + + m->dvi_advance_in_units_of_design_size_by_2e20 = width; + if (len > 0) { + if (len <= availend - avail) { + m->pos = avail; + avail += len; + } else { + m->free_me = true; + if (len <= VF_PARM_1) { + m->pos = avail = new unsigned char [VF_PARM_2]; + availend = avail + VF_PARM_2; + avail += len; + } else + m->pos = new unsigned char[len]; + } + fread((char *) m->pos, 1, len, VF_file); + m->end = m->pos + len; + } + } + if (cmnd != POST) + oops(i18n("Wrong command byte found in VF macro list: %1").arg(cmnd)); + + fclose (VF_file); + file = NULL; +} diff --git a/kdvi/xdvi.h b/kdvi/xdvi.h new file mode 100644 index 00000000..0770cd8b --- /dev/null +++ b/kdvi/xdvi.h @@ -0,0 +1,24 @@ +// -*- C++ -*- +#ifndef _xdvi_h +#define _xdvi_h + +#include + +/* + * Written by Eric C. Cooper, CMU + */ + +#define ROUNDUP(x,y) (((x)+(y)-1)/(y)) + +extern unsigned long num (FILE *, int); +extern long snum(FILE *, int); +extern struct WindowRec mane, currwin; + +#define one(fp) ((unsigned char) getc(fp)) +#define sone(fp) ((long) one(fp)) +#define two(fp) num (fp, 2) +#define stwo(fp) snum(fp, 2) +#define four(fp) num (fp, 4) +#define sfour(fp) snum(fp, 4) + +#endif /* _xdvi_h */ diff --git a/kfax/AUTHORS b/kfax/AUTHORS new file mode 100644 index 00000000..88b4ef2b --- /dev/null +++ b/kfax/AUTHORS @@ -0,0 +1,3 @@ +Bernd Johannes Wuebben +wuebben@math.cornell.edu +wuebben@kde.org diff --git a/kfax/ChangeLog b/kfax/ChangeLog new file mode 100644 index 00000000..39accef4 --- /dev/null +++ b/kfax/ChangeLog @@ -0,0 +1,28 @@ +1999-03-03 Harri Porten + + * viewfax.cpp: prefix getopt declarations with 'extern'. Bug reported + by Oliver Oster + +1999-02-08 Harri Porten + + * fixed segfault caused by infinite recursion in kfaxerror() + +Sun May 3 16:48:13 1998 Bernd Johannes Wuebben + + * fixed print dialog + adjusted layout for i18n + +Sun Oct 5 22:17:09 1997 Bernd Johannes Wuebben + + * added support for printing all fax formats at all printer page + sizes. + +Sun Aug 3 09:55:52 1997 Bernd Johannes Wuebben + + * Made kfax work with the new KToolBar etc. + +Thu Jul 24 20:44:33 1997 Bernd Johannes Wuebben + + * made the necessary changes so that kfax will compile with + the new libs. + diff --git a/kfax/Makefile.am b/kfax/Makefile.am new file mode 100644 index 00000000..fd3e478c --- /dev/null +++ b/kfax/Makefile.am @@ -0,0 +1,32 @@ +AM_LDFLAGS = $(all_libraries) $(KDE_RPATH) +LDADD = $(LIB_KFILE) $(LIB_KDEPRINT) -lm +INCLUDES = $(all_includes) + +####### Files +noinst_HEADERS = kfax.h faxexpand.h options.h + +kfax_SOURCES = options.cpp kfax.cpp faxexpand.cpp faxinit.cpp faxinput.cpp \ + viewfax.cpp kfax_printsettings.cpp + +METASOURCES = AUTO + +bin_PROGRAMS = kfax + +xdg_apps_DATA = kfax.desktop + +picsdir = $(kde_datadir)/kfax/pics +pics_DATA = kfax.tif kfaxlogo.xpm + +rcdir = $(kde_datadir)/kfax +rc_DATA = kfaxui.rc + +KDE_ICON = kfax + +EXTRA_DIST = $(xdg_apps_DATA) $(pics_DATA) + +messages: rc.cpp + $(XGETTEXT) $(kfax_SOURCES) -o $(podir)/kfax.pot + +####### Explicit dependencies + + diff --git a/kfax/NOTES b/kfax/NOTES new file mode 100644 index 00000000..9a3c70b6 --- /dev/null +++ b/kfax/NOTES @@ -0,0 +1,49 @@ + +Drag and Drop +Net Drag and Drop + +kfax can display all fax output modes of ghostscript: +raw: fag3 faxg32d faxg4 +tiff: tiffg3 tiffg32d tiffg4 + +By default raw fax files are interpreted as g3 files. If you want +to display faxg3-2d and faxg4 files you have to specifiy this on +the command line and in the case of raw g4 files also specify +the height in scan lines of the fax if it differs from the +default 2155. + +A raw file will have no pagignation information and will be displayed +as a whole in the fax window. +tiff files contain pagination information can be paged through in the +fax window + +kfax can not display image file formats which are not related to +faxing, such as an arbitrary tiff or gif file. + + +How to create fax file that sendfax /mgetty can accept and send: +gs -sDEVICE=faxg3 -sOutputFile=/tmp/fax.g3.%d yourdocument.ps + +Assume that you ps document yourdocumnet.ps contains three pages, +this will produce fax.g3.1 fax.g3.2 fax.g3.3 + + +HylaFAX: +http://info-sys.home.vix.com/flexfax/toc.html + +sendfax/mgetty: +http://www.leo.org/~doering/mgetty/ + +cat fax.g3 | g32pbm | pnmtops -noturn > output.ps + + + +How to print raw " no tiff " g3 fax data: + + + +fax2tiff -M viewfax.g3 -o viewfax.tiff +(M for: Treat input data as having bits filled from most + significant bit (MSB) to most least bit (LSB)) +This is what I need on my intel machine, I would presume this +might be different on a Sun station. diff --git a/kfax/README b/kfax/README new file mode 100644 index 00000000..23d3c6c2 --- /dev/null +++ b/kfax/README @@ -0,0 +1,34 @@ +KFax 0.3 + +Added printing for g32 and g4, so that kfax can now print all fax formats. +Added support for all pages sizes. + +Bernd +wuebben@kde.org + + +I am please to release KFax 0.2, the first public release of +KFax - a fax file viewer for the KDE project. + +Please peruse the accompanying html documentation for more information +about KFax + +Help wanted: +============ + +Much of my work was done "in vitro". Now it is time to go out into +the wilderness and test KFax: + +I need people to send me faxes from all sorts of programs and machines +in order to thoroughly test KFax and develop further ideas as to what needs +to be implemented. If you own a fax modem or a fax machine and you would +like to help, please write to me by email. I will then give you my phone +number and we will agree on which fax program I will used for reception. +You can then send me a fax from your favorite program or machine, stating +what machine/program you used, from where you sent the fax, what +the size of the fax is, the number of pages you transmitted etc. +This would be very helpful. Thanks for your coorporation. + +thanks, +Bernd Wuebben +wuebben@kde.org diff --git a/kfax/TODO b/kfax/TODO new file mode 100644 index 00000000..2e9d8464 --- /dev/null +++ b/kfax/TODO @@ -0,0 +1,2 @@ +o Page Marking +o Printing of only the Marked pages diff --git a/kfax/examples/README b/kfax/examples/README new file mode 100644 index 00000000..74631fe6 --- /dev/null +++ b/kfax/examples/README @@ -0,0 +1,22 @@ +If you have the kdeapps distributions, please also read README.kdeapps +thanks, +Bernd + +This directory contains a number of fax files which you can use to +test and play with KFax: + +kde.g3 a group 3 raw fax file +kde.g32d a group 3, 2-dim raw fax file +kde.g4 a group 4 raw fax file + +Note: the g32d and g4 raw fax files will not display correctly + unless you change the default raw fax file format on the + Fax Options dialog. + +kdefaq.tiff.g3 a tiff group 3 encoded fax file +kdefaq.tiff.g32d a tiff group 3, 2-dim, encoded fax file +kdefaq.tiff.g4 a tiff group 4 encoded fax file + +Note that the tiff file format is the superiour format. Each +of the above tiff fax files contains several pages. + diff --git a/kfax/examples/README.kdeapps b/kfax/examples/README.kdeapps new file mode 100644 index 00000000..6664690a --- /dev/null +++ b/kfax/examples/README.kdeapps @@ -0,0 +1,12 @@ +Note from the kdeapps maintainer: + +This directory used to contain several example fax files. Some of which are +raw fax files others tiff fax files. Since I need to keep the kdeapps +distributions small in size, I removed them with the permission of the author. +You will still find all example files in the original kfax distribution +at: + +ftp.kde.org//pub/kde/apps/graphics/ + +Stephan Kulow + diff --git a/kfax/examples/kde.g3 b/kfax/examples/kde.g3 new file mode 100644 index 00000000..a419e9af Binary files /dev/null and b/kfax/examples/kde.g3 differ diff --git a/kfax/examples/nasty.tiff b/kfax/examples/nasty.tiff new file mode 100644 index 00000000..e9edd50c Binary files /dev/null and b/kfax/examples/nasty.tiff differ diff --git a/kfax/faxexpand.cpp b/kfax/faxexpand.cpp new file mode 100644 index 00000000..93f1bc85 --- /dev/null +++ b/kfax/faxexpand.cpp @@ -0,0 +1,732 @@ +/* Expand one page of fax data + Copyright (C) 1990, 1995 Frank D. Cringle. + +This file is part of viewfax - g3/g4 fax processing software. + +viewfax 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 +#include +#include +#include "faxexpand.h" + +//Uncomment this for verbose debug output +//#define DEBUG_FAX + +/* Note that NeedBits() only works for n <= 16 */ +#define NeedBits(n) do { \ + if (BitsAvail < (n)) { \ + BitAcc |= *sp++ << BitsAvail; \ + BitsAvail += 16; \ + } \ +} while (0) +#define GetBits(n) (BitAcc & ((1<<(n))-1)) +#define ClrBits(n) do { \ + BitAcc >>= (n); \ + BitsAvail -= (n); \ +} while (0) + +#ifdef DEBUG_FAX +#define DEBUG_SHOW putchar(BitAcc & (1 << t) ? '1' : '0') +#define LOOKUP(wid,tab) do { \ + int t; \ + NeedBits(wid); \ + TabEnt = tab + GetBits(wid); \ + printf("%08lX/%d: %s%5d\t", BitAcc, BitsAvail, \ + StateNames[TabEnt->State], TabEnt->Param); \ + for (t = 0; t < TabEnt->Width; t++) \ + DEBUG_SHOW; \ + putchar('\n'); \ + fflush(stdout); \ + ClrBits(TabEnt->Width); \ +} while (0) + +#define SETVAL(x) do { \ + *pa++ = RunLength + (x); \ + printf("SETVAL: %d\t%d\n", RunLength + (x), a0); \ + a0 += x; \ + RunLength = 0; \ +} while (0) + +char *StateNames[] = { + "Null ", + "Pass ", + "Horiz ", + "V0 ", + "VR ", + "VL ", + "Ext ", + "TermW ", + "TermB ", + "MakeUpW", + "MakeUpB", + "MakeUp ", + "EOL ", +}; + +#else +#define LOOKUP(wid,tab) do { \ + NeedBits(wid); \ + TabEnt = tab + GetBits(wid); \ + ClrBits(TabEnt->Width); \ +} while (0) + +#define SETVAL(x) do { \ + *pa++ = RunLength + (x); \ + a0 += x; \ + RunLength = 0; \ +} while (0) +#endif + +#define dumpruns(runs) do { \ + printf("-------------------- %d\n", LineNum); \ + for (pa = runs, a0 = 0; a0 < lastx; a0 += *pa++) \ + printf("%4d %d\n", a0, *pa); \ +} while (0) + +#define EndOfData(pn) (sp >= pn->data + pn->length/sizeof(*pn->data)) + +/* This macro handles coding errors in G3 data. + We redefine it below for the G4 case */ +#define SKIP_EOL do { \ + while (!EndOfData(pn)) { \ + NeedBits(11); \ + if (GetBits(11) == 0) \ + break; \ + ClrBits(1); \ + } \ + ClrBits(11); \ + goto EOL; \ +} while (0) +#define eol2lab EOL2: + +/* the line expanders are written as macros so that they can be reused + (twice each) but still have direct access to the local variables of + the "calling" function */ +#define expand1d() do { \ + while (a0 < lastx) { \ + int done = 0; \ + while (!done) { /* white first */ \ + LOOKUP(12, WhiteTable); \ + switch (TabEnt->State) { \ + case S_EOL: \ + EOLcnt = 1; \ + goto EOL; \ + case S_TermW: \ + SETVAL(TabEnt->Param); \ + done = 1; \ + break; \ + case S_MakeUpW: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + case S_Ext: \ + unexpected("Extension code", LineNum); \ + SKIP_EOL; \ + break; \ + default: \ + unexpected("WhiteTable", LineNum); \ + SKIP_EOL; \ + break; \ + } \ + } \ + done = a0 >= lastx; \ + while (!done) { /* then black */ \ + LOOKUP(13, BlackTable); \ + switch (TabEnt->State) { \ + case S_EOL: \ + EOLcnt = 1; \ + goto EOL; \ + case S_TermB: \ + SETVAL(TabEnt->Param); \ + done = 1; \ + break; \ + case S_MakeUpB: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + case S_Ext: \ + unexpected("Extension code", LineNum); \ + SKIP_EOL; \ + break; \ + default: \ + unexpected("BlackTable", LineNum); \ + SKIP_EOL; \ + break; \ + } \ + } \ + } \ + EOL: ; \ +} while (0) + +#define CHECK_b1 do { \ + if (pa != thisrun) while (b1 <= a0 && b1 < lastx) { \ + b1 += pb[0] + pb[1]; \ + pb += 2; \ + } \ +} while (0) + +#define expand2d(eolab) do { \ + while (a0 < lastx) { \ + LOOKUP(7, MainTable); \ + switch (TabEnt->State) { \ + case S_Pass: \ + CHECK_b1; \ + b1 += *pb++; \ + RunLength += b1 - a0; \ + a0 = b1; \ + b1 += *pb++; \ + break; \ + case S_Horiz: \ + if ((pa-run0)&1) { \ + int done = 0; \ + while (!done) { /* black first */ \ + LOOKUP(13, BlackTable); \ + switch (TabEnt->State) { \ + case S_TermB: \ + SETVAL(TabEnt->Param); \ + done = 1; \ + break; \ + case S_MakeUpB: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + unexpected("BlackTable", LineNum); \ + SKIP_EOL; \ + break; \ + } \ + } \ + done = 0; \ + while (!done) { /* then white */ \ + LOOKUP(12, WhiteTable); \ + switch (TabEnt->State) { \ + case S_TermW: \ + SETVAL(TabEnt->Param); \ + done = 1; \ + break; \ + case S_MakeUpW: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + unexpected("WhiteTable", LineNum); \ + SKIP_EOL; \ + break; \ + } \ + } \ + } \ + else { \ + int done = 0; \ + while (!done) { /* white first */ \ + LOOKUP(12, WhiteTable); \ + switch (TabEnt->State) { \ + case S_TermW: \ + SETVAL(TabEnt->Param); \ + done = 1; \ + break; \ + case S_MakeUpW: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + unexpected("WhiteTable", LineNum); \ + SKIP_EOL; \ + break; \ + } \ + } \ + done = 0; \ + while (!done) { /* then black */ \ + LOOKUP(13, BlackTable); \ + switch (TabEnt->State) { \ + case S_TermB: \ + SETVAL(TabEnt->Param); \ + done = 1; \ + break; \ + case S_MakeUpB: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + unexpected("BlackTable", LineNum); \ + SKIP_EOL; \ + break; \ + } \ + } \ + } \ + CHECK_b1; \ + break; \ + case S_V0: \ + CHECK_b1; \ + SETVAL(b1 - a0); \ + b1 += *pb++; \ + break; \ + case S_VR: \ + CHECK_b1; \ + SETVAL(b1 - a0 + TabEnt->Param); \ + b1 += *pb++; \ + break; \ + case S_VL: \ + CHECK_b1; \ + SETVAL(b1 - a0 - TabEnt->Param); \ + b1 -= *--pb; \ + break; \ + case S_Ext: \ + *pa++ = lastx - a0; \ + if (verbose) \ + fprintf(stderr, "Line %d: extension code\n", LineNum); \ + SKIP_EOL; \ + break; \ + case S_EOL: \ + *pa++ = lastx - a0; \ + NeedBits(4); \ + if (GetBits(4) && verbose) /* already seen 7 zeros */ \ + fprintf(stderr, "Line %d: Bad EOL\n", LineNum); \ + ClrBits(4); \ + EOLcnt = 1; \ + goto eolab; \ + break; \ + default: \ + unexpected("MainTable", LineNum); \ + SKIP_EOL; \ + break; \ + } \ + } \ + if (RunLength) { \ + if (RunLength + a0 < lastx) { \ + /* expect a final V0 */ \ + NeedBits(1); \ + if (!GetBits(1)) { \ + unexpected("MainTable", LineNum); \ + SKIP_EOL; \ + } \ + ClrBits(1); \ + } \ + SETVAL(0); \ + } \ + eol2lab ; \ +} while (0) + +static void +unexpected(const char *what, int LineNum) +{ + if (verbose) + fprintf(stderr, "Line %d: Unexpected state in %s\n", + LineNum, what); +} + +/* Expand tiff modified huffman data (g3-1d without EOLs) */ +void +MHexpand(struct pagenode *pn, drawfunc df) +{ + int a0; /* reference element */ + int lastx = pn->width; /* copy line width to register */ + t32bits BitAcc; /* bit accumulator */ + int BitsAvail; /* # valid bits in BitAcc */ + int RunLength; /* Length of current run */ + t16bits *sp; /* pointer into compressed data */ + pixnum *pa; /* pointer into new line */ + int EOLcnt; /* number of consecutive EOLs */ + int LineNum; /* line number */ + pixnum *runs; /* list of run lengths */ + struct tabent *TabEnt; + + sp = pn->data; + BitAcc = 0; + BitsAvail = 0; + lastx = pn->width; + runs = (pixnum *) xmalloc(lastx * sizeof(pixnum)); + for (LineNum = 0; LineNum < pn->rowsperstrip; ) { +#ifdef DEBUG_FAX + printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %d\n", LineNum); + fflush(stdout); +#endif + RunLength = 0; + pa = runs; + a0 = 0; + EOLcnt = 0; + if (BitsAvail & 7) /* skip to byte boundary */ + ClrBits(BitsAvail & 7); + expand1d(); + if (RunLength) + SETVAL(0); + if (a0 != lastx) { + if (verbose) + fprintf(stderr, "Line %d: length is %d (expected %d)\n", LineNum, a0, lastx); + while (a0 > lastx) + a0 -= *--pa; + if (a0 < lastx) { + if ((pa - runs) & 1) + SETVAL(0); + SETVAL(lastx - a0); + } + } + (*df)(runs, LineNum++, pn); + } + free(runs); +} + +/* Expand group-3 1-dimensional data */ +void +g31expand(struct pagenode *pn, drawfunc df) +{ + int a0; /* reference element */ + int lastx = pn->width; /* copy line width to register */ + t32bits BitAcc; /* bit accumulator */ + int BitsAvail; /* # valid bits in BitAcc */ + int RunLength; /* Length of current run */ + t16bits *sp; /* pointer into compressed data */ + pixnum *pa; /* pointer into new line */ + int EOLcnt; /* number of consecutive EOLs */ + int LineNum; /* line number */ + pixnum *runs; /* list of run lengths */ + struct tabent *TabEnt; + + sp = pn->data; + BitAcc = 0; + BitsAvail = 0; + lastx = pn->width; + runs = (pixnum *) xmalloc(lastx * sizeof(pixnum)); + EOLcnt = 0; + for (LineNum = 0; LineNum < pn->rowsperstrip; ) { +#ifdef DEBUG_FAX + printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %d\n", LineNum); + fflush(stdout); +#endif + if (EOLcnt == 0) + while (!EndOfData(pn)) { + /* skip over garbage after a coding error */ + NeedBits(11); + if (GetBits(11) == 0) + break; + ClrBits(1); + } + for (EOLcnt = 1; !EndOfData(pn); EOLcnt++) { + /* we have seen 11 zeros, which implies EOL, + skip possible fill bits too */ + while (1) { + NeedBits(8); + if (GetBits(8)) + break; + ClrBits(8); + } + while (GetBits(1) == 0) + ClrBits(1); + ClrBits(1); /* the eol flag */ + NeedBits(11); + if (GetBits(11)) + break; + ClrBits(11); + } + if (EOLcnt > 1 && EOLcnt != 6 && verbose) + fprintf(stderr, "Line %d: bad RTC (%d EOLs)\n", LineNum, EOLcnt); + if (EOLcnt >= 6 || EndOfData(pn)) { + free(runs); + return; + } + RunLength = 0; + pa = runs; + a0 = 0; + EOLcnt = 0; + expand1d(); + if (RunLength) + SETVAL(0); + if (a0 != lastx) { + if (verbose) + fprintf(stderr, "Line %d: length is %d (expected %d)\n", LineNum, a0, lastx); + while (a0 > lastx) + a0 -= *--pa; + if (a0 < lastx) { + if ((pa - runs) & 1) + SETVAL(0); + SETVAL(lastx - a0); + } + } + (*df)(runs, LineNum++, pn); + } + free(runs); +} + +/* Expand group-3 2-dimensional data */ +void +g32expand(struct pagenode *pn, drawfunc df) +{ + int RunLength; /* Length of current run */ + int a0; /* reference element */ + int b1; /* next change on previous line */ + int lastx = pn->width; /* copy line width to register */ + pixnum *run0, *run1; /* run length arrays */ + pixnum *thisrun, *pa, *pb; /* pointers into runs */ + t16bits *sp; /* pointer into compressed data */ + t32bits BitAcc; /* bit accumulator */ + int BitsAvail; /* # valid bits in BitAcc */ + int EOLcnt; /* number of consecutive EOLs */ + int refline = 0; /* 1D encoded reference line */ + int LineNum; /* line number */ + struct tabent *TabEnt; + + sp = pn->data; + BitAcc = 0; + BitsAvail = 0; + /* allocate space for 2 runlength arrays */ + run0 = (pixnum *) xmalloc(2 * ((lastx+5)&~1) * sizeof(pixnum)); + run1 = run0 + ((lastx+5)&~1); + run1[0] = lastx; + run1[1] = 0; + EOLcnt = 0; + for (LineNum = 0; LineNum < pn->rowsperstrip; ) { +#ifdef DEBUG_FAX + printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %d\n", LineNum); + fflush(stdout); +#endif + if (EOLcnt == 0) + while (!EndOfData(pn)) { + /* skip over garbage after a coding error */ + NeedBits(11); + if (GetBits(11) == 0) + break; + ClrBits(1); + } + for (EOLcnt = 1; !EndOfData(pn); EOLcnt++) { + /* we have seen 11 zeros, which implies EOL, + skip possible fill bits too */ + while (1) { + NeedBits(8); + if (GetBits(8)) + break; + ClrBits(8); + } + while (GetBits(1) == 0) + ClrBits(1); + ClrBits(1); /* the eol flag */ + NeedBits(12); + refline = GetBits(1); /* 1D / 2D flag */ + ClrBits(1); + if (GetBits(11)) + break; + ClrBits(11); + } + if (EOLcnt > 1 && EOLcnt != 6 && verbose) + fprintf(stderr, "Line %d: bad RTC (%d EOLs)\n", LineNum, EOLcnt); + if (EOLcnt >= 6 || EndOfData(pn)) { + free(run0); + return; + } + if (LineNum == 0 && refline == 0 && verbose) + fprintf(stderr, "First line is 2-D encoded\n"); + RunLength = 0; + if (LineNum & 1) { + pa = run1; + pb = run0; + } + else { + pa = run0; + pb = run1; + } + thisrun = pa; + EOLcnt = 0; + a0 = 0; + b1 = *pb++; + + if (refline) { + expand1d(); + } + else { + expand2d(EOL2); + } + if (RunLength) + SETVAL(0); + if (a0 != lastx) { + if (verbose) + fprintf(stderr, "Line %d: length is %d (expected %d)\n", LineNum, a0, lastx); + while (a0 > lastx) + a0 -= *--pa; + if (a0 < lastx) { + if ((pa - run0) & 1) + SETVAL(0); + SETVAL(lastx - a0); + } + } + SETVAL(0); /* imaginary change at end of line for reference */ + (*df)(thisrun, LineNum++, pn); + } + free(run0); +} + +/* Redefine the "skip to eol" macro. We cannot recover from coding + errors in G4 data */ +#undef SKIP_EOL +#undef eol2lab +#define SKIP_EOL do { \ + if (verbose) \ + fprintf(stderr, "Line %d: G4 coding error\n", LineNum); \ + free(run0); \ + return; \ +} while (0) +#define eol2lab + +/* Expand group-4 data */ +void +g4expand(struct pagenode *pn, drawfunc df) +{ + int RunLength; /* Length of current run */ + int a0; /* reference element */ + int b1; /* next change on previous line */ + int lastx = pn->width; /* copy line width to register */ + pixnum *run0, *run1; /* run length arrays */ + pixnum *thisrun, *pa, *pb; /* pointers into runs */ + t16bits *sp; /* pointer into compressed data */ + t32bits BitAcc; /* bit accumulator */ + int BitsAvail; /* # valid bits in BitAcc */ + int LineNum; /* line number */ + int EOLcnt; + struct tabent *TabEnt; + + sp = pn->data; + BitAcc = 0; + BitsAvail = 0; + /* allocate space for 2 runlength arrays */ + run0 = (pixnum *) xmalloc(2 * ((lastx+5)&~1) * sizeof(pixnum)); + run1 = run0 + ((lastx+5)&~1); + run1[0] = lastx; /* initial reference line */ + run1[1] = 0; + + for (LineNum = 0; LineNum < pn->rowsperstrip; ) { +#ifdef DEBUG_FAX + printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %d\n", LineNum); + fflush(stdout); +#endif + RunLength = 0; + if (LineNum & 1) { + pa = run1; + pb = run0; + } + else { + pa = run0; + pb = run1; + } + thisrun = pa; + a0 = 0; + b1 = *pb++; + expand2d(EOFB); + if (a0 < lastx) { + if ((pa - run0) & 1) + SETVAL(0); + SETVAL(lastx - a0); + } + SETVAL(0); /* imaginary change at end of line for reference */ + (*df)(thisrun, LineNum++, pn); + continue; + EOFB: + NeedBits(13); + if (GetBits(13) != 0x1001 && verbose) + fputs("Bad RTC\n", stderr); + break; + } + free(run0); +} + +static unsigned char zerotab[256] = { + 0x88, 0x07, 0x16, 0x06, 0x25, 0x05, 0x15, 0x05, + 0x34, 0x04, 0x14, 0x04, 0x24, 0x04, 0x14, 0x04, + 0x43, 0x03, 0x13, 0x03, 0x23, 0x03, 0x13, 0x03, + 0x33, 0x03, 0x13, 0x03, 0x23, 0x03, 0x13, 0x03, + 0x52, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02, + 0x32, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02, + 0x42, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02, + 0x32, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02, + 0x61, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, + 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, + 0x41, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, + 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, + 0x51, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, + 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, + 0x41, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, + 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, + 0x70, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x50, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x60, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x50, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00 +}; + +#define check(v) do { \ + prezeros = zerotab[v]; \ + postzeros = prezeros & 15; \ + prezeros >>= 4; \ + if (prezeros == 8) { \ + zeros += 8; \ + continue; \ + } \ + if (zeros + prezeros < 11) { \ + empty = 0; \ + zeros = postzeros; \ + continue; \ + } \ + zeros = postzeros; \ + if (empty) \ + EOLcnt++; \ + lines++; \ + empty = 1; \ +} while (0) + +/* count fax lines */ +int +G3count(struct pagenode *pn, int twoD) +{ + t16bits *p = pn->data; + t16bits *end = p + pn->length/sizeof(*p); + int lines = 0; /* lines seen so far */ + int zeros = 0; /* number of consecutive zero bits seen */ + int EOLcnt = 0; /* number of consecutive EOLs seen */ + int empty = 1; /* empty line */ + int prezeros, postzeros; + + while (p < end && EOLcnt < 6) { + t16bits bits = *p++; + check(bits&255); + if (twoD && (prezeros + postzeros == 7)) { + if (postzeros || ((bits & 0x100) == 0)) + zeros--; + } + check(bits>>8); + if (twoD && (prezeros + postzeros == 7)) { + if (postzeros || ((p < end) && ((*p & 1) == 0))) + zeros--; + } + } + return lines - EOLcnt; /* don't count trailing EOLs */ +} diff --git a/kfax/faxexpand.h b/kfax/faxexpand.h new file mode 100644 index 00000000..a1be736f --- /dev/null +++ b/kfax/faxexpand.h @@ -0,0 +1,160 @@ +/* Include file for fax routines + Copyright (C) 1990, 1995 Frank D. Cringle. + +This file is part of viewfax - g3/g4 fax processing software. + +viewfax 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 _faxexpand_h_ +#define _faxexpand_h_ + +#include + +#if ULONG_MAX == 4294967295UL +typedef unsigned long t32bits; +#elif UINT_MAX == 4294967295UL +typedef unsigned int t32bits; +#else +#error need a 32-bit unsigned type +/* if you expirence the above error, and live to tell about it, + add an #elif case for your architecture + and tell wuebben@math.cornell.edu , wuebben@kde.org about it */ +#endif + +#if USHRT_MAX == 65535 +typedef unsigned short t16bits; +#elif UINT_MAX == 65535 +typedef unsigned int t16bits; +#else +#error need a 16-bit unsigned type +/* if you experience the above error, and live to tell about it, + add an #elif case for your architecture + and tell fdc@cliwe.ping.de about it */ +#endif +typedef t16bits pixnum; + +struct pagenode; + +/* drawfunc() points to a function which processes a line of the + expanded image described as a list of run lengths. + run is the base of an array of lengths, starting with a + (possibly empty) white run for line number linenum. + pn points to the page descriptor */ +typedef void (*drawfunc)(pixnum *run, int linenum, struct pagenode *pn); + +struct strip { /* tiff strip descriptor */ + off_t offset; /* offset in file */ + off_t size; /* size of this strip */ +}; + + +/* defines for the pagenode member: type */ +#define FAX_TIFF 1 +#define FAX_RAW 2 + +struct pagenode { /* compressed page descriptor */ + struct pagenode *prev, *next; /* list links */ + char *name; /* basename of file */ + char *pathname; /* full name of file */ + int nstrips; /* number of strips */ + int rowsperstrip; /* number of rows per strip */ + int stripnum; /* current strip while expanding */ + struct strip *strips; /* array of strips containing fax data in file */ + t16bits *data; /* in-memory copy of strip */ + size_t length; /* length of data */ + pixnum width; /* width of page in pixels */ + pixnum height; /* height of page in lines */ + int inverse; /* black <=> white */ + int lsbfirst; /* bit order is lsb first */ + int type; /* Bernd: tiff vs no tiff*/ + int orient; /* orientation - upsidedown, landscape, mirrored */ + int vres; /* vertical resolution: 1 = fine */ + int dpiX,dpiY; /* DPI horz/vert */ + void (*expander)(struct pagenode *, drawfunc); + void *extra; /* used for Ximage */ +}; +extern struct pagenode *firstpage, *lastpage, *thispage,* auxpage; +extern struct pagenode defaultpage; + +/* page orientation flags */ +#define TURN_U 1 +#define TURN_L 2 +#define TURN_M 4 + +extern const char *ProgName; + +/* fsm state codes */ +#define S_Null 0 +#define S_Pass 1 +#define S_Horiz 2 +#define S_V0 3 +#define S_VR 4 +#define S_VL 5 +#define S_Ext 6 +#define S_TermW 7 +#define S_TermB 8 +#define S_MakeUpW 9 +#define S_MakeUpB 10 +#define S_MakeUp 11 +#define S_EOL 12 + +/* state table entry */ +struct tabent { + unsigned char State; + unsigned char Width; /* width of code in bits */ + pixnum Param; /* run length */ +}; + +extern struct tabent MainTable[]; /* 2-D state table */ +extern struct tabent WhiteTable[]; /* White run lengths */ +extern struct tabent BlackTable[]; /* Black run lengths */ + +extern int verbose; + +void MHexpand(struct pagenode *pn, drawfunc df); +void g31expand(struct pagenode *pn, drawfunc df); +void g32expand(struct pagenode *pn, drawfunc df); +void g4expand(struct pagenode *pn, drawfunc df); + +unsigned char * getstrip(struct pagenode *pn, int strip); +struct pagenode *notefile(const char *name); +int notetiff(const char *name); + +/* initialise code tables */ +extern void faxinit(void); +/* count lines in image */ +extern int G3count(struct pagenode *pn, int twoD); + +/* get memory or abort if none available */ +extern char *xmalloc(unsigned int size); + +#ifdef __linux__ +#define _HAVE_USLEEP +#endif + +#if defined(BSD) || defined(__FreeBSD__) || defined(_BSD_SOURCE) +#define _HAVE_USLEEP +#ifndef rindex +#define rindex strrchr +#endif +#ifndef bcmp +#define memcmp bcmp +#endif +#define memclr(p,n) bzero(p,n) +#else /* not BSD */ +#define memclr(p,n) memset(p,0,n) +#endif + +#endif diff --git a/kfax/faxinit.cpp b/kfax/faxinit.cpp new file mode 100644 index 00000000..62ee0569 --- /dev/null +++ b/kfax/faxinit.cpp @@ -0,0 +1,337 @@ +/* Initialise fax decoder tables + Copyright (C) 1990, 1995 Frank D. Cringle. + +This file is part of viewfax - g3/g4 fax processing software. + +viewfax 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 +#include "faxexpand.h" + +struct tabent MainTable[128]; +struct tabent WhiteTable[4096]; +struct tabent BlackTable[8192]; + +struct proto { + t16bits code; /* right justified, lsb-first, zero filled */ + t16bits val; /* (pixel count)<<4 + code width */ +}; + +static struct proto Pass[] = { +{ 0x0008, 4 }, +{ 0, 0 } +}; + +static struct proto Horiz[] = { +{ 0x0004, 3 }, +{ 0, 0 } +}; + +static struct proto V0[] = { +{ 0x0001, 1 }, +{ 0, 0 } +}; + +static struct proto VR[] = { +{ 0x0006, (1<<4)+3 }, +{ 0x0030, (2<<4)+6 }, +{ 0x0060, (3<<4)+7 }, +{ 0, 0 } +}; + +static struct proto VL[] = { +{ 0x0002, (1<<4)+3 }, +{ 0x0010, (2<<4)+6 }, +{ 0x0020, (3<<4)+7 }, +{ 0, 0 } +}; + +static struct proto ExtV[] = { +{ 0x0040, 7 }, +{ 0, 0 } +}; + +static struct proto EOLV[] = { +{ 0x0000, 7 }, +{ 0, 0 } +}; + +static struct proto MakeUpW[] = { +{ 0x001b, 1029 }, +{ 0x0009, 2053 }, +{ 0x003a, 3078 }, +{ 0x0076, 4103 }, +{ 0x006c, 5128 }, +{ 0x00ec, 6152 }, +{ 0x0026, 7176 }, +{ 0x00a6, 8200 }, +{ 0x0016, 9224 }, +{ 0x00e6, 10248 }, +{ 0x0066, 11273 }, +{ 0x0166, 12297 }, +{ 0x0096, 13321 }, +{ 0x0196, 14345 }, +{ 0x0056, 15369 }, +{ 0x0156, 16393 }, +{ 0x00d6, 17417 }, +{ 0x01d6, 18441 }, +{ 0x0036, 19465 }, +{ 0x0136, 20489 }, +{ 0x00b6, 21513 }, +{ 0x01b6, 22537 }, +{ 0x0032, 23561 }, +{ 0x0132, 24585 }, +{ 0x00b2, 25609 }, +{ 0x0006, 26630 }, +{ 0x01b2, 27657 }, +{ 0, 0 } +}; + +static struct proto MakeUpB[] = { +{ 0x03c0, 1034 }, +{ 0x0130, 2060 }, +{ 0x0930, 3084 }, +{ 0x0da0, 4108 }, +{ 0x0cc0, 5132 }, +{ 0x02c0, 6156 }, +{ 0x0ac0, 7180 }, +{ 0x06c0, 8205 }, +{ 0x16c0, 9229 }, +{ 0x0a40, 10253 }, +{ 0x1a40, 11277 }, +{ 0x0640, 12301 }, +{ 0x1640, 13325 }, +{ 0x09c0, 14349 }, +{ 0x19c0, 15373 }, +{ 0x05c0, 16397 }, +{ 0x15c0, 17421 }, +{ 0x0dc0, 18445 }, +{ 0x1dc0, 19469 }, +{ 0x0940, 20493 }, +{ 0x1940, 21517 }, +{ 0x0540, 22541 }, +{ 0x1540, 23565 }, +{ 0x0b40, 24589 }, +{ 0x1b40, 25613 }, +{ 0x04c0, 26637 }, +{ 0x14c0, 27661 }, +{ 0, 0 } +}; + +static struct proto MakeUp[] = { +{ 0x0080, 28683 }, +{ 0x0180, 29707 }, +{ 0x0580, 30731 }, +{ 0x0480, 31756 }, +{ 0x0c80, 32780 }, +{ 0x0280, 33804 }, +{ 0x0a80, 34828 }, +{ 0x0680, 35852 }, +{ 0x0e80, 36876 }, +{ 0x0380, 37900 }, +{ 0x0b80, 38924 }, +{ 0x0780, 39948 }, +{ 0x0f80, 40972 }, +{ 0, 0 } +}; + +static struct proto TermW[] = { +{ 0x00ac, 8 }, +{ 0x0038, 22 }, +{ 0x000e, 36 }, +{ 0x0001, 52 }, +{ 0x000d, 68 }, +{ 0x0003, 84 }, +{ 0x0007, 100 }, +{ 0x000f, 116 }, +{ 0x0019, 133 }, +{ 0x0005, 149 }, +{ 0x001c, 165 }, +{ 0x0002, 181 }, +{ 0x0004, 198 }, +{ 0x0030, 214 }, +{ 0x000b, 230 }, +{ 0x002b, 246 }, +{ 0x0015, 262 }, +{ 0x0035, 278 }, +{ 0x0072, 295 }, +{ 0x0018, 311 }, +{ 0x0008, 327 }, +{ 0x0074, 343 }, +{ 0x0060, 359 }, +{ 0x0010, 375 }, +{ 0x000a, 391 }, +{ 0x006a, 407 }, +{ 0x0064, 423 }, +{ 0x0012, 439 }, +{ 0x000c, 455 }, +{ 0x0040, 472 }, +{ 0x00c0, 488 }, +{ 0x0058, 504 }, +{ 0x00d8, 520 }, +{ 0x0048, 536 }, +{ 0x00c8, 552 }, +{ 0x0028, 568 }, +{ 0x00a8, 584 }, +{ 0x0068, 600 }, +{ 0x00e8, 616 }, +{ 0x0014, 632 }, +{ 0x0094, 648 }, +{ 0x0054, 664 }, +{ 0x00d4, 680 }, +{ 0x0034, 696 }, +{ 0x00b4, 712 }, +{ 0x0020, 728 }, +{ 0x00a0, 744 }, +{ 0x0050, 760 }, +{ 0x00d0, 776 }, +{ 0x004a, 792 }, +{ 0x00ca, 808 }, +{ 0x002a, 824 }, +{ 0x00aa, 840 }, +{ 0x0024, 856 }, +{ 0x00a4, 872 }, +{ 0x001a, 888 }, +{ 0x009a, 904 }, +{ 0x005a, 920 }, +{ 0x00da, 936 }, +{ 0x0052, 952 }, +{ 0x00d2, 968 }, +{ 0x004c, 984 }, +{ 0x00cc, 1000 }, +{ 0x002c, 1016 }, +{ 0, 0 } +}; + +static struct proto TermB[] = { +{ 0x03b0, 10 }, +{ 0x0002, 19 }, +{ 0x0003, 34 }, +{ 0x0001, 50 }, +{ 0x0006, 67 }, +{ 0x000c, 84 }, +{ 0x0004, 100 }, +{ 0x0018, 117 }, +{ 0x0028, 134 }, +{ 0x0008, 150 }, +{ 0x0010, 167 }, +{ 0x0050, 183 }, +{ 0x0070, 199 }, +{ 0x0020, 216 }, +{ 0x00e0, 232 }, +{ 0x0030, 249 }, +{ 0x03a0, 266 }, +{ 0x0060, 282 }, +{ 0x0040, 298 }, +{ 0x0730, 315 }, +{ 0x00b0, 331 }, +{ 0x01b0, 347 }, +{ 0x0760, 363 }, +{ 0x00a0, 379 }, +{ 0x0740, 395 }, +{ 0x00c0, 411 }, +{ 0x0530, 428 }, +{ 0x0d30, 444 }, +{ 0x0330, 460 }, +{ 0x0b30, 476 }, +{ 0x0160, 492 }, +{ 0x0960, 508 }, +{ 0x0560, 524 }, +{ 0x0d60, 540 }, +{ 0x04b0, 556 }, +{ 0x0cb0, 572 }, +{ 0x02b0, 588 }, +{ 0x0ab0, 604 }, +{ 0x06b0, 620 }, +{ 0x0eb0, 636 }, +{ 0x0360, 652 }, +{ 0x0b60, 668 }, +{ 0x05b0, 684 }, +{ 0x0db0, 700 }, +{ 0x02a0, 716 }, +{ 0x0aa0, 732 }, +{ 0x06a0, 748 }, +{ 0x0ea0, 764 }, +{ 0x0260, 780 }, +{ 0x0a60, 796 }, +{ 0x04a0, 812 }, +{ 0x0ca0, 828 }, +{ 0x0240, 844 }, +{ 0x0ec0, 860 }, +{ 0x01c0, 876 }, +{ 0x0e40, 892 }, +{ 0x0140, 908 }, +{ 0x01a0, 924 }, +{ 0x09a0, 940 }, +{ 0x0d40, 956 }, +{ 0x0340, 972 }, +{ 0x05a0, 988 }, +{ 0x0660, 1004 }, +{ 0x0e60, 1020 }, +{ 0, 0 } +}; + +static struct proto ExtH[] = { +{ 0x0100, 9 }, +{ 0, 0 } +}; + +static struct proto EOLH[] = { +{ 0x0000, 11 }, +{ 0, 0 } +}; + +static void +FillTable(struct tabent *T, int Size, struct proto *P, int State) +{ + int limit = 1 << Size; + + while (P->val) { + int width = P->val & 15; + int param = P->val >> 4; + int incr = 1 << width; + int code; + for (code = P->code; code < limit; code += incr) { + struct tabent *E = T+code; + E->State = State; + E->Width = width; + E->Param = param; + } + P++; + } +} + +/* initialise the huffman code tables */ +void +faxinit(void) +{ + FillTable(MainTable, 7, Pass, S_Pass); + FillTable(MainTable, 7, Horiz, S_Horiz); + FillTable(MainTable, 7, V0, S_V0); + FillTable(MainTable, 7, VR, S_VR); + FillTable(MainTable, 7, VL, S_VL); + FillTable(MainTable, 7, ExtV, S_Ext); + FillTable(MainTable, 7, EOLV, S_EOL); + FillTable(WhiteTable, 12, MakeUpW, S_MakeUpW); + FillTable(WhiteTable, 12, MakeUp, S_MakeUp); + FillTable(WhiteTable, 12, TermW, S_TermW); + FillTable(WhiteTable, 12, ExtH, S_Ext); + FillTable(WhiteTable, 12, EOLH, S_EOL); + FillTable(BlackTable, 13, MakeUpB, S_MakeUpB); + FillTable(BlackTable, 13, MakeUp, S_MakeUp); + FillTable(BlackTable, 13, TermB, S_TermB); + FillTable(BlackTable, 13, ExtH, S_Ext); + FillTable(BlackTable, 13, EOLH, S_EOL); +} diff --git a/kfax/faxinput.cpp b/kfax/faxinput.cpp new file mode 100644 index 00000000..8ca7fe85 --- /dev/null +++ b/kfax/faxinput.cpp @@ -0,0 +1,479 @@ +/* Fax file input processing + Copyright (C) 1990, 1995 Frank D. Cringle. + +This file is part of viewfax - g3/g4 fax processing software. + +viewfax 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 +#include +#include +#include +#include +#include +#include +#include +#include "faxexpand.h" +#include +#include +#include +#include +#include + +void statusbarupdate(char* name,int width,int height,char* res); +extern void kfaxerror(const QString& title, const QString& error); + +#define FAXMAGIC "\000PC Research, Inc\000\000\000\000\000\000" + +/* Enter an argument in the linked list of pages */ +struct pagenode * +notefile(const char *name, int type) +{ + struct pagenode *newnode = (struct pagenode *) xmalloc(sizeof *newnode); + + *newnode = defaultpage; + if (firstpage == NULL){ + firstpage = newnode; + auxpage = firstpage; + } + newnode->prev = lastpage; + newnode->next = NULL; + if (lastpage != NULL) + lastpage->next = newnode; + lastpage = newnode; + + // kdDebug() << "Adding new node " << newnode << endl; + + newnode->pathname = (char*) malloc (strlen(name) +1); + if(!newnode->pathname){ + kfaxerror(i18n("Sorry"),i18n("Out of memory\n")); + exit(1); + } + + strcpy(newnode->pathname,name); + + newnode->type = type; + + + if ((newnode->name = strrchr(newnode->pathname, '/')) != NULL) + newnode->name++; + else + newnode->name = newnode->pathname; + + if (newnode->width == 0) + newnode->width = 1728; + if (newnode->vres < 0) + newnode->vres = !(newnode->name[0] == 'f' && newnode->name[1] == 'n'); + newnode->extra = NULL; + + return newnode; +} + +static t32bits +get4(unsigned char *p, int endian) +{ + return endian ? (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3] : + p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24); +} + +static int +get2(unsigned char *p, int endian) +{ + return endian ? (p[0]<<8)|p[1] : p[0]|(p[1]<<8); +} + +/* generate pagenodes for the images in a tiff file */ +int +notetiff(const char *name) +{ + + FILE *tf; + unsigned char header[8]; + static const char littleTIFF[5] = "\x49\x49\x2a\x00"; + static const char bigTIFF[5] = "\x4d\x4d\x00\x2a"; + int endian; + t32bits IFDoff; + struct pagenode *pn = NULL; + QString str; + + + if ((tf = fopen(name, "r")) == NULL) { + QString mesg = i18n("Unable to open:\n%1\n").arg(QFile::decodeName(name)); + kfaxerror(i18n("Sorry"), mesg); + return 0; + } + + if (fread(header, 8, 1, tf) == 0) { + nottiff: + fclose(tf); + (void) notefile(name,FAX_RAW); + return 0; + } + if (memcmp(header, &littleTIFF, 4) == 0) + endian = 0; + else if (memcmp(header, &bigTIFF, 4) == 0) + endian = 1; + else + goto nottiff; + IFDoff = get4(header+4, endian); + if (IFDoff & 1) + goto nottiff; + do { /* for each page */ + unsigned char buf[8]; + unsigned char *dir = NULL , *dp = NULL; + int ndirent; + pixnum iwidth = defaultpage.width ? defaultpage.width : 1728; + pixnum iheight = defaultpage.height ? defaultpage.height : 2339; + int inverse = defaultpage.inverse; + int lsbfirst = 0; + int t4opt = 0, comp = 0; + int orient = defaultpage.orient; + double yres = defaultpage.vres ? 196.0 : 98.0; + struct strip *strips = NULL; + unsigned long rowsperstrip = 0; + t32bits nstrips = 1; + + if (fseek(tf, IFDoff, SEEK_SET) < 0) { + realbad: + str = i18n("Invalid tiff file:\n%1\n").arg(QFile::decodeName(name)); + kfaxerror(i18n("Sorry"),str); + bad: + if (strips) + free(strips); + if (dir) + free(dir); + fclose(tf); + return 1; + } + if (fread(buf, 2, 1, tf) == 0) + goto realbad; + ndirent = get2(buf, endian); + dir = (unsigned char *) xmalloc(12*ndirent+4); + if (fread(dir, 12*ndirent+4, 1, tf) == 0) + goto realbad; + for (dp = dir; ndirent; ndirent--, dp += 12) { + /* for each directory entry */ + int tag, ftype; + t32bits count, value = 0; + tag = get2(dp, endian); + ftype = get2(dp+2, endian); + count = get4(dp+4, endian); + switch(ftype) { /* value is offset to list if count*size > 4 */ + case 3: /* short */ + value = get2(dp+8, endian); + break; + case 4: /* long */ + value = get4(dp+8, endian); + break; + case 5: /* offset to rational */ + value = get4(dp+8, endian); + break; + } + switch(tag) { + case 256: /* ImageWidth */ + iwidth = value; + break; + case 257: /* ImageLength */ + iheight = value; + break; + case 259: /* Compression */ + comp = value; + break; + case 262: /* PhotometricInterpretation */ + inverse ^= (value == 1); + break; + case 266: /* FillOrder */ + lsbfirst = (value == 2); + break; + case 273: /* StripOffsets */ + nstrips = count; + strips = (struct strip *) xmalloc(count * sizeof *strips); + if (count == 1 || (count == 2 && ftype == 3)) { + strips[0].offset = value; + if (count == 2) + strips[1].offset = get2(dp+10, endian); + break; + } + if (fseek(tf, value, SEEK_SET) < 0) + goto realbad; + for (count = 0; count < nstrips; count++) { + if (fread(buf, (ftype == 3) ? 2 : 4, 1, tf) == 0) + goto realbad; + strips[count].offset = (ftype == 3) ? + get2(buf, endian) : get4(buf, endian); + } + break; + case 274: /* Orientation */ + switch(value) { + default: /* row0 at top, col0 at left */ + orient = 0; + break; + case 2: /* row0 at top, col0 at right */ + orient = TURN_M; + break; + case 3: /* row0 at bottom, col0 at right */ + orient = TURN_U; + break; + case 4: /* row0 at bottom, col0 at left */ + orient = TURN_U|TURN_M; + break; + case 5: /* row0 at left, col0 at top */ + orient = TURN_M|TURN_L; + break; + case 6: /* row0 at right, col0 at top */ + orient = TURN_U|TURN_L; + break; + case 7: /* row0 at right, col0 at bottom */ + orient = TURN_U|TURN_M|TURN_L; + break; + case 8: /* row0 at left, col0 at bottom */ + orient = TURN_L; + break; + } + break; + case 278: /* RowsPerStrip */ + rowsperstrip = value; + break; + case 279: /* StripByteCounts */ + if (count != nstrips) { + str = i18n("In file %1\nStripsPerImage tag 273=%2,tag279=%3\n") + .arg(QFile::decodeName(name)).arg(nstrips).arg(count); + kfaxerror(i18n("Message"),str); + goto realbad; + } + if (count == 1 || (count == 2 && ftype == 3)) { + strips[0].size = value; + if (count == 2) + strips[1].size = get2(dp+10, endian); + break; + } + if (fseek(tf, value, SEEK_SET) < 0) + goto realbad; + for (count = 0; count < nstrips; count++) { + if (fread(buf, (ftype == 3) ? 2 : 4, 1, tf) == 0) + goto realbad; + strips[count].size = (ftype == 3) ? + get2(buf, endian) : get4(buf, endian); + } + break; + case 283: /* YResolution */ + if (fseek(tf, value, SEEK_SET) < 0 || + fread(buf, 8, 1, tf) == 0) + goto realbad; + yres = get4(buf, endian) / get4(buf+4, endian); + break; + case 292: /* T4Options */ + t4opt = value; + break; + case 293: /* T6Options */ + /* later */ + break; + case 296: /* ResolutionUnit */ + if (value == 3) + yres *= 2.54; + break; + } + } + IFDoff = get4(dp, endian); + free(dir); + dir = NULL; + if (comp == 5) { + // compression type 5 is LZW compression + kfaxerror(i18n("Sorry"),i18n("Due to patent reasons KFax can not handle LZW (Lempel-Ziv & Welch) " + "compressed Fax files.\n")); + goto bad; + } + if (comp < 2 || comp > 4) { + kfaxerror(i18n("Sorry"),i18n("This version can only handle Fax files\n")); + goto bad; + } + pn = notefile(name,FAX_TIFF); + pn->nstrips = nstrips; + pn->rowsperstrip = nstrips > 1 ? rowsperstrip : iheight; + pn->strips = strips; + pn->width = iwidth; + pn->height = iheight; + pn->inverse = inverse; + pn->lsbfirst = lsbfirst; + pn->orient = orient; + pn->vres = (yres > 150); /* arbitrary threshold for fine resolution */ + if (comp == 2) + pn->expander = MHexpand; + else if (comp == 3) + pn->expander = (t4opt & 1) ? g32expand : g31expand; + else + pn->expander = g4expand; + } while (IFDoff); + fclose(tf); + return 1; +} + +/* report error and remove bad file from the list */ +static void +badfile(struct pagenode *pn) +{ + struct pagenode *p; + + if (errno) + perror(pn->pathname); + if (pn == firstpage) { + if (pn->next == NULL){ + kfaxerror(i18n("Sorry"),i18n("Bad Fax File")); + return; + } + else{ + firstpage = thispage = firstpage->next; + firstpage->prev = NULL; + } + } + else + for (p = firstpage; p; p = p->next) + if (p->next == pn) { + thispage = p; + p->next = pn->next; + if (pn->next) + pn->next->prev = p; + break; + } + if (pn) free(pn); + pn = NULL; +} + +/* rearrange input bits into t16bits lsb-first chunks */ +static void +normalize(struct pagenode *pn, int revbits, int swapbytes, size_t length) +{ + t32bits *p = (t32bits *) pn->data; + + switch ((revbits<<1)|swapbytes) { + case 0: + break; + case 1: + for ( ; length; length -= 4) { + t32bits t = *p; + *p++ = ((t & 0xff00ff00) >> 8) | ((t & 0x00ff00ff) << 8); + } + break; + case 2: + for ( ; length; length -= 4) { + t32bits t = *p; + t = ((t & 0xf0f0f0f0) >> 4) | ((t & 0x0f0f0f0f) << 4); + t = ((t & 0xcccccccc) >> 2) | ((t & 0x33333333) << 2); + *p++ = ((t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1); + } + break; + case 3: + for ( ; length; length -= 4) { + t32bits t = *p; + t = ((t & 0xff00ff00) >> 8) | ((t & 0x00ff00ff) << 8); + t = ((t & 0xf0f0f0f0) >> 4) | ((t & 0x0f0f0f0f) << 4); + t = ((t & 0xcccccccc) >> 2) | ((t & 0x33333333) << 2); + *p++ = ((t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1); + } + } +} + + +/* get compressed data into memory */ +unsigned char * +getstrip(struct pagenode *pn, int strip) +{ + int fd; + size_t offset, roundup; + struct stat sbuf; + unsigned char *Data; + union { t16bits s; unsigned char b[2]; } so; + QString str; + +#define ShortOrder so.b[1] + + so.s = 1; + if ((fd = open(pn->pathname, O_RDONLY, 0)) < 0) { + badfile(pn); + return NULL; + } + + if (pn->strips == NULL) { + if (fstat(fd, &sbuf) != 0) { + close(fd); + badfile(pn); + return NULL; + } + offset = 0; + pn->length = sbuf.st_size; + } + else if (strip < pn->nstrips) { + offset = pn->strips[strip].offset; + pn->length = pn->strips[strip].size; + } + else { + str = i18n("Trying to expand too many strips\n%1%n").arg(QFile::decodeName(pn->pathname)); + kfaxerror(i18n("Warning"),str); + return NULL; + } + + /* round size to full boundary plus t32bits */ + roundup = (pn->length + 7) & ~3; + + Data = (unsigned char *) xmalloc(roundup); + /* clear the last 2 t32bits, to force the expander to terminate + even if the file ends in the middle of a fax line */ + *((t32bits *) Data + roundup/4 - 2) = 0; + *((t32bits *) Data + roundup/4 - 1) = 0; + + /* we expect to get it in one gulp... */ + if (lseek(fd, offset, SEEK_SET) < 0 || + (uint) read(fd, Data, pn->length) != pn->length) { + badfile(pn); + free(Data); + close(fd); + return NULL; + } + close(fd); + + pn->data = (t16bits *) Data; + if (pn->strips == NULL && memcmp(Data, FAXMAGIC, sizeof(FAXMAGIC)) == 0) { + /* handle ghostscript / PC Research fax file */ + if (Data[24] != 1 || Data[25] != 0){ + str = i18n("Only the first page of the PC Research multipage file\n%1\nwill be shown\n") + .arg(QFile::decodeName(pn->pathname)); + kfaxerror(i18n("Message"),str); + } + pn->length -= 64; + pn->vres = Data[29]; + pn->data += 32; + roundup -= 64; + } + + normalize(pn, !pn->lsbfirst, ShortOrder, roundup); + if (pn->height == 0) + pn->height = G3count(pn, pn->expander == g32expand); + if (pn->height == 0) { + + str = i18n("No fax found in file:\n%1\n").arg(QFile::decodeName(pn->pathname)); + kfaxerror(i18n("Sorry"),str); + errno = 0; + badfile(pn); + free(Data); + return NULL; + } + if (pn->strips == NULL) + pn->rowsperstrip = pn->height; + if (verbose && strip == 0) + kdWarning() << pn->name << "\n\twidth = " << pn->width << "\n\theight = " + << pn->height << "\n\tresolution = " << (pn->vres ? "fine" : "normal") << endl; +// statusbarupdate(pn->name,pn->width,pn->height,pn->vres ? "fine" : "normal"); + return Data; +} diff --git a/kfax/hi16-app-kfax.png b/kfax/hi16-app-kfax.png new file mode 100644 index 00000000..bb676f8b Binary files /dev/null and b/kfax/hi16-app-kfax.png differ diff --git a/kfax/hi22-app-kfax.png b/kfax/hi22-app-kfax.png new file mode 100644 index 00000000..90fc64b0 Binary files /dev/null and b/kfax/hi22-app-kfax.png differ diff --git a/kfax/hi32-app-kfax.png b/kfax/hi32-app-kfax.png new file mode 100644 index 00000000..7330eb41 Binary files /dev/null and b/kfax/hi32-app-kfax.png differ diff --git a/kfax/hi48-app-kfax.png b/kfax/hi48-app-kfax.png new file mode 100644 index 00000000..3f58c369 Binary files /dev/null and b/kfax/hi48-app-kfax.png differ diff --git a/kfax/hisc-app-kfax.svgz b/kfax/hisc-app-kfax.svgz new file mode 100644 index 00000000..f46fd440 Binary files /dev/null and b/kfax/hisc-app-kfax.svgz differ diff --git a/kfax/kfax.cpp b/kfax/kfax.cpp new file mode 100644 index 00000000..02661325 --- /dev/null +++ b/kfax/kfax.cpp @@ -0,0 +1,1695 @@ + /* + + $Id$ + + Copyright (C) 1997 Bernd Johannes Wuebben + wuebben@math.cornell.edu + + 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. + + */ + +#ifdef KDE_USE_FINAL +/* NewImage() in viewfax.cpp needs to fiddle with the Display structure */ +#define XLIB_ILLEGAL_ACCESS +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "faxexpand.h" +#include "kfax.h" +#include "version.h" +#include "viewfax.h" +#include "options.h" +#include "kfax_printsettings.h" + +#include +#include +#include +#include +#include +#include +#include + +// StatusBar field IDs +#define ID_LINE_COLUMN 1 +#define ID_INS_OVR 2 +#define ID_GENERAL 3 +#define ID_FNAME 4 +#define ID_TYPE 5 +#define ID_PAGE_NO 6 + + +TopLevel *toplevel; + +extern int GetImage(struct pagenode *pn); + +void TurnFollowing(int How, struct pagenode *pn); +void handle_X_event(XEvent event); +void ShowLoop(void); +void SetupDisplay(); +void mysighandler(int sig); +void setFaxDefaults(); + +void parse(char* buf, char** args); + +extern void g31expand(struct pagenode *pn, drawfunc df); +extern void g32expand(struct pagenode *pn, drawfunc df); +extern void g4expand(struct pagenode *pn, drawfunc df); + +#define PATIENCE 100000 + +static char KFAX_FILETYPES[] = "image/fax-g3 image/tiff"; + +int ExpectConfNotify = 1; + +GC PaintGC; +Cursor WorkCursor; +Cursor ReadyCursor; +Cursor MoveCursor; +Cursor LRCursor; +Cursor UDCursor; + +extern Time Lasttime; +extern bool have_cmd_opt; +extern struct pagenode *viewpage; + +extern XImage *FlipImage(XImage *xi); +extern XImage *MirrorImage(XImage *xi); +extern XImage *RotImage(XImage *Image); +extern XImage *ZoomImage(XImage *Big); +extern void FreeImage(XImage *Image); + +extern XImage *Image, *Images[MAXZOOM]; + +int xpos, ox; /* x, old x, offset x, new xpos*/ +int ypos, oy; /* y, old y, offset y, new y */ +int offx, offy; +int nx, ny; + +int oz, Resize, Refresh; /* old zoom, window size changed, + needs updating */ +int PaneWidth, PaneHeight; /* current size of our window */ +int AbsX, AbsY; /* absolute position of centre of window */ + +Display* qtdisplay; + +int startingup; +Window qtwin; // the qt window +Window Win; +int qwindow_height; +int qwindow_width; +bool have_no_fax = TRUE; +bool display_is_setup = FALSE; +struct optionsinfo fop; // contains the fax options + +extern struct pagenode *firstpage, *lastpage, *thispage; +extern struct pagenode* auxpage; + +extern struct pagenode defaultpage; + +bool buttondown; + +bool MyApp::x11EventFilter( XEvent * ev) +{ + if (KApplication::x11EventFilter(ev)) + return TRUE; + + if (ev->type == ButtonRelease){ + /* this is so that the cursor goes back to normal on leaving the fax window + and that the fax won't be moved when I reenter after I release the mouse*/ + + if (buttondown == true){ + buttondown = false; + XDefineCursor(qtdisplay, Win, ReadyCursor); + XFlush(qtdisplay); + } + } + if ( ev->xany.window == qtwin || + ev->xany.window == Win){ + + if(startingup || have_no_fax) + return FALSE; + + toplevel->handle_X_event(*ev); + ev->xany.window = qtwin; + + } + + return FALSE; + +} + +TopLevel::TopLevel (QWidget *, const char *name) + : KMainWindow (0, name) +{ + setMinimumSize (100, 100); + + buttondown = false; + + setupMenuBar(); + setupStatusBar(); + updateActions(); + + resize(550,400); + setupGUI(); + + readSettings(); + + faxqtwin = new QFrame(this); + + qtwin = faxqtwin->winId(); + faxqtwin->setFrameStyle(QFrame::Panel | QFrame::Sunken); + + // Create a Vertical scroll bar + + vsb = new QScrollBar( QScrollBar::Vertical,faxqtwin,"scrollBar" ); + vsb->hide(); + connect( vsb, SIGNAL(valueChanged(int)), SLOT(scrollVert(int)) ); + + // Create a Horizontal scroll bar + + hsb = new QScrollBar( QScrollBar::Horizontal,faxqtwin,"scrollBar" ); + connect( hsb, SIGNAL(valueChanged(int)), SLOT(scrollHorz(int)) ); + hsb->hide(); + + setCentralWidget(faxqtwin); + + setAcceptDrops(true); + + show(); +} + + +TopLevel::~TopLevel() +{ +} + +void TopLevel::setupMenuBar() +{ + // File menu + KStdAction::open( this, SLOT( faxOpen() ), actionCollection() ); + actRecent = KStdAction::openRecent( this, SLOT( faxOpen( const KURL & ) ), + actionCollection() ); + actSave = KStdAction::save( this, SLOT( faxSave() ), actionCollection() ); + actSaveAs = KStdAction::saveAs( this, SLOT( faxSaveAs() ), + actionCollection() ); + actPrint = KStdAction::print( this, SLOT( print() ), actionCollection() ); + KStdAction::quit( this, SLOT( close() ), actionCollection() ); + actAdd = new KAction( i18n( "A&dd..." ), "filenew", KShortcut(), this, + SLOT( faxAdd() ), actionCollection(), "file_add_fax" ); + + actRecent->setMaxItems( 5 ); + + // View Menu + actSize = KStdAction::actualSize( this, SLOT( actualSize() ), + actionCollection() ); + actZoomIn = KStdAction::zoomIn( this, SLOT( zoomin() ), actionCollection() ); + actZoomOut = KStdAction::zoomOut( this, SLOT( zoomout() ), + actionCollection() ); + + actRotate = new KAction( i18n( "&Rotate Page" ), "rotate", KShortcut(), this, + SLOT( rotatePage() ), actionCollection(), "view_rotate" ); + actMirror = new KAction( i18n( "Mirror Page" ), KShortcut(), this, + SLOT( mirrorPage() ), actionCollection(), "view_mirror" ); + actFlip = new KAction( i18n( "&Flip Page" ), KShortcut(), this, + SLOT( flipPage() ), actionCollection(), "view_flip" ); + + // Go menu + actNext = KStdAction::next( this, SLOT( nextPage() ), actionCollection() ); + actPrev = KStdAction::prior( this, SLOT( prevPage() ), actionCollection() ); + actFirst = KStdAction::firstPage( this, SLOT( firstPage() ), + actionCollection() ); + actLast = KStdAction::lastPage( this, SLOT( lastPage() ), + actionCollection() ); + + // Settings menu + KStdAction::preferences( this, SLOT( faxoptions() ), actionCollection() ); +} + +void TopLevel::setupStatusBar() +{ + statusbar = statusBar(); + + statusbar->insertFixedItem(i18n("w: 00000 h: 00000"), ID_INS_OVR); + statusbar->insertFixedItem(i18n("Res: XXXXX"), ID_GENERAL); + statusbar->insertFixedItem(i18n("Type: XXXXXXX"), ID_TYPE); + statusbar->insertFixedItem(i18n("Page: XX of XX"), ID_PAGE_NO); + statusbar->insertItem(QString::null, ID_FNAME, 1); + statusbar->setItemAlignment( ID_FNAME, AlignLeft ); + + statusbar->changeItem(QString::null, ID_INS_OVR); + statusbar->changeItem(QString::null, ID_GENERAL); + statusbar->changeItem(QString::null, ID_TYPE); + statusbar->changeItem(QString::null, ID_PAGE_NO); + statusbar->changeItem(QString::null, ID_FNAME); +} + +void TopLevel::readSettings() +{ + config = kapp->config(); + + applyMainWindowSettings( config, "MainWindowSettings" ); + + actRecent->loadEntries( config ); + + config->setGroup("General Options"); + + config->setGroup("Fax Options"); + + fop.width = config->readNumEntry("width", 1728); + fop.resauto = config->readNumEntry("resauto", 1); + fop.geomauto = config->readNumEntry("geomauto", 1); + fop.height = config->readNumEntry("height", 2339); + fop.fine = config->readNumEntry("resolution", 1); + fop.flip = config->readNumEntry("flip", 0); + fop.invert = config->readNumEntry("invert", 0); + fop.lsbfirst = config->readNumEntry("lsb", 0); + fop.raw = config->readNumEntry("raw", 3); + + setFaxDefaults(); +} + +void TopLevel::updateActions() +{ + actAdd->setEnabled( thispage ); + actSave->setEnabled( thispage ); + actSaveAs->setEnabled( thispage ); + actPrint->setEnabled( thispage ); + + actRotate->setEnabled( thispage ); + actFlip->setEnabled( thispage ); + actMirror->setEnabled( thispage ); + + updateGoActions(); + updateZoomActions(); +} + +void TopLevel::updateGoActions() +{ + actNext->setEnabled( thispage && thispage->next ); + actPrev->setEnabled( thispage && thispage->prev ); + actFirst->setEnabled( thispage && thispage->prev ); + actLast->setEnabled( thispage && thispage->next ); +} + +void TopLevel::updateZoomActions() +{ + actSize->setEnabled( Image && oz > 0 ); + actZoomIn->setEnabled( Image && oz > 0 ); + actZoomOut->setEnabled( Image && oz < MAXZOOM-1 && Image->width >= 256 ); +} + +bool TopLevel::queryClose() +{ + saveMainWindowSettings( config, "MainWindowSettings" ); + actRecent->saveEntries( config ); + + return true; +} + +void TopLevel::writeSettings() +{ + config = kapp->config(); + + config->setGroup("General Options"); + + config->setGroup("Fax Options"); + + config->writeEntry("resauto",fop.resauto); + config->writeEntry("geomauto",fop.geomauto); + config->writeEntry("width",fop.width); + config->writeEntry("height",fop.height); + config->writeEntry("resolution",fop.fine); + config->writeEntry("flip",fop.flip); + config->writeEntry("invert",fop.invert); + config->writeEntry("lsb",fop.lsbfirst); + config->writeEntry("raw",fop.raw); + + config->sync(); +} + +void TopLevel::faxOpen() +{ + KURL url = KFileDialog::getOpenURL(QString::null, KFAX_FILETYPES); + + faxOpen( url ); + + actRecent->addURL( fileURL ); +} + +void TopLevel::faxOpen( const KURL & url ) +{ + if (!url.isValid()) + return; + + faxClose(); + faxAdd( url ); + + fileURL = url; + + updateActions(); +} + +void TopLevel::faxAdd() +{ + KURL url = KFileDialog::getOpenURL(QString::null, KFAX_FILETYPES); + + faxAdd( url ); + + actRecent->addURL( fileURL ); +} + +void TopLevel::faxAdd( const KURL & url ) +{ + if (!url.isValid()) + return; + + openNetFile(url); + + updateGoActions(); +} + +void TopLevel::faxSave() +{ + saveNetFile(fileURL); +} + +void TopLevel::faxSaveAs() +{ + fileURL = KFileDialog::getSaveURL(QString::null, KFAX_FILETYPES); + + if (fileURL.isEmpty()) + return; + + faxSave(); + + actRecent->addURL( fileURL ); +} + + +static void freeImages() +{ + int i; + for (i = 1; i < MAXZOOM; i++) { + if (Images[i]) + FreeImage(Images[i]); + Images[i] = NULL; + } +} + +static XImage *generateZoomImages(int maxzoom) +{ + int i; + for (i = 1; i < MAXZOOM; i++){ + if (!Images[i-1]) + continue; + Image = Images[i] = ZoomImage(Images[i-1]); + if(Image == NULL){// out of memory + Image = Images[i -1]; + break; + } + } + + i = maxzoom; + while (!Images[i]) + i--; + return Images[i]; +} + + +void TopLevel::zoom( int factor ) +{ + if(!thispage || !Image || !faxqtwin || !display_is_setup) + return; + + Resize = Refresh = 1; + + Image = generateZoomImages(factor); + + PaneWidth = Image->width; + PaneHeight = Image->height; + + resizeView(); + putImage(); + + uiUpdate(); + + updateZoomActions(); +} + +void TopLevel::zoomin() +{ + if ( oz > 0 ) + { + oz--; + zoom( oz ); + } +} + +void TopLevel::zoomout() +{ + if (oz < MAXZOOM && Image->width >= 256) + { + ++oz; + zoom( oz ); + } +} + +void TopLevel::actualSize() +{ + oz = 0; + zoom( oz ); +} + +void loadfile(QString filename) +{ + // Typical FAX resolutions are: + // Standard: 203 dpi x 98 dpi + // Fine: 203 dpi x 196 lpi + // Super Fine: 203 dpi y 392 lpi, or + // 406 dpi x 392 lpi + QSize dpi(203,196); + + KFileMetaInfo metaInfo(filename); + if (metaInfo.isValid() && metaInfo.item("Resolution").isValid()) + { + QSize s = metaInfo.item("Resolution").value().toSize(); + if (s.width() >= 100 && s.height() >= 100) + dpi = s; + } + + (void) notetiff(QFile::encodeName(filename)); + + struct pagenode *pn; + for(pn = firstpage; pn; pn = pn->next) + if (!pn->dpiX) { + pn->dpiX = dpi.width(); + pn->dpiY = dpi.height(); + } +} + +void TopLevel::openadd(QString filename) +{ + auxpage = lastpage; + + loadfile(filename); + + if( firstpage != lastpage ) + { + if(auxpage->next) + auxpage = auxpage->next; + } + + // auxpage should now point to the first pagenode which was created for + // the newly added fax file. + have_no_fax = false; + thispage = auxpage; + newPage(); + resizeView(); + putImage(); +} + +void TopLevel::resizeEvent(QResizeEvent *e) +{ + KMainWindow::resizeEvent(e); + + resizeView(); +} + +void TopLevel::wheelEvent( QWheelEvent *e ) +{ + e->accept(); + + if ( e->state() & ShiftButton ) + { + if ( e->delta() < 0 ) + zoomin(); + else + zoomout(); + } + else + { + int offset = QApplication::wheelScrollLines()*vsb->lineStep(); + if ( e->state() & ControlButton ) + offset = vsb->pageStep(); + offset = -e->delta()*offset/120; + vsb->setValue( vsb->value() + offset ); + } +} + +void TopLevel::resizeView() +{ + if(!faxqtwin || !display_is_setup) + return; + +//printf("In resizeView() entered\n"); + + qwindow_width = faxqtwin->width(); + qwindow_height = faxqtwin->height(); + + if( hsb->isVisible()) + qwindow_height -= 16; + + if( vsb->isVisible()) + qwindow_width -= 16; + + if(Image){ + PaneWidth = Image->width; + PaneHeight = Image->height; + } + + // printf("faxw %d qtw %d\n", PaneWidth , faxqtwin->width()); + + if( (PaneHeight > qwindow_height ) && + (PaneWidth > qwindow_width)){ + + vsb->setGeometry(faxqtwin->width() - 16,0,16,faxqtwin->height()-16); + hsb->setGeometry(0,faxqtwin->height() - 16 ,faxqtwin->width()-16,16); + + qwindow_width = faxqtwin->width() -16; + qwindow_height = faxqtwin->height()-16; + + + vsb->raise(); + vsb->show(); + hsb->show(); + } + else{ + + if( PaneHeight > qwindow_height){ + vsb->setGeometry(faxqtwin->width() - 16,0,16,faxqtwin->height()); + + + qwindow_width = faxqtwin->width() -16 ; + qwindow_height = faxqtwin->height(); + + + vsb->show(); + hsb->hide(); + hsb->raise(); + } + else + vsb->hide(); + + if( PaneWidth > qwindow_width ){ + hsb->setGeometry(0,faxqtwin->height() - 16 ,faxqtwin->width(),16); + hsb->show(); + hsb->raise(); + vsb->hide(); + qwindow_width = faxqtwin->width() ; + qwindow_height = faxqtwin->height() -16; + + } + else + hsb->hide(); + + } + + if(Image){ + hsb->setRange(0,QMAX(0,Image->width - qwindow_width)); + hsb->setSteps(5,qwindow_width/2); + // printf("hsb range: %d\n",QMAX(0,Image->width - qwindow_width)); + vsb->setRange(0,QMAX(0,Image->height - qwindow_height)); + vsb->setSteps(5,qwindow_height/2); + // printf("vsb range: %d\n",QMAX(0,Image->height - qwindow_height)); + // printf("vsb QMIN %d vdb QMAX %d\n",vsb->QMINValue(),vsb->QMAXValue()); + } + + + Resize = 1; + uiUpdate(); + +} + +bool TopLevel::loadAllPages( int &numpages, int ¤tpage ) +{ + struct pagenode *pn; + + numpages = 0; + currentpage = 1; + + for(pn = firstpage; pn; pn = pn->next) { + ++numpages; + if (pn == thispage) + currentpage = numpages; + if (!Pimage(pn)) { + int k = -1; + while((k != 0) && (k != 3) && (k != 1)) + k = GetImage(pn); // fetch image if it is not available yet. + } + } + return (numpages != 0); +} + +void TopLevel::print(){ + if(!thispage || !firstpage) { + return KMessageBox::sorry(this, i18n("There is no document active.")); + } + + int pages, currentpage; + loadAllPages(pages, currentpage); + + KPrinter printer(true, QPrinter::HighResolution); + printer.setFullPage( true ); + printer.setUsePrinterResolution( true ); + printer.setCreator( i18n("KFax") + " " KFAXVERSION ); + printer.setDocName( QString("%1 - %2").arg(firstpage->name).arg(i18n("KFax"))); + printer.setDocFileName( firstpage->name ); + printer.setPageSelection( KPrinter::ApplicationSide ); + printer.setMinMax( 1, pages ); + printer.setCurrentPage( currentpage ); + printer.addDialogPage(new KFAXPrintSettings()); + if ( !printer.setup( this ) ) + return; + + QPainter painter; + painter.begin( &printer ); + printIt(printer, painter); + painter.end(); +} + + +void TopLevel::printIt( KPrinter &printer, QPainter &painter ) +{ + QPaintDeviceMetrics dm(painter.device()); + + QApplication::setOverrideCursor( waitCursor ); + kapp->processEvents(); + + const bool fullpage = printer.option(APP_KFAX_SCALE_FULLPAGE) == "true"; + const bool center_h = printer.option(APP_KFAX_CENTER_HORZ) == "true"; + const bool center_v = printer.option(APP_KFAX_CENTER_VERT) == "true"; + + int currentpage = 0; + bool first_page_printed = false; + struct pagenode *pn; + for(pn = firstpage; pn; pn = pn->next) { + + ++currentpage; + // should this page be printed ? + if (printer.pageList().findIndex(currentpage) < 0) + continue; + + XImage *Image = Pimage(pn); + if (!Image) + continue; + + // byte-swapping the image + QByteArray bytes( Image->height*Image->bytes_per_line ); + for (int y=Image->height-1; y>=0; --y) { + Q_UINT32 offset = y*Image->bytes_per_line; + Q_UINT32 *source = (Q_UINT32 *) (Image->data + offset); + Q_UINT32 *dest = (Q_UINT32 *) (bytes.data() + offset); + for (int x=(Image->bytes_per_line/4)-1; x>=0; --x) { + Q_UINT32 dv = 0, sv = *source; + for (int bit=32; bit>0; --bit) { + dv <<= 1; + dv |= sv&1; + sv >>= 1; + } + *dest = dv; + ++dest; + ++source; + } + } + + QImage image( (uchar *)bytes.data(), Image->bytes_per_line*8, Image->height, 1, NULL, 2, QImage::LittleEndian); + + if (first_page_printed) + printer.newPage(); + first_page_printed = true; + + const QSize printersize( dm.width(), dm.height() ); + kdDebug() << "Printersize = " << printersize << endl; + // print Image in original size if possible, else scale it. + + const QSize size( // logical size of the image + Image->width * dm.logicalDpiX() / pn->dpiX, + Image->height * dm.logicalDpiY() / pn->dpiY + ); + + kdDebug() << "Org image size = " << Image->width << "x" << Image->height + << " logical picture res = " << pn->dpiX << "x" << pn->dpiY << endl; + kdDebug() << "New image size = " << size + << " logical printer res = " << dm.logicalDpiX() << "x" << dm.logicalDpiY() << endl; + + uint top, left, bottom, right; + if (fullpage) + top = left = bottom = right = 0; + else + printer.margins( &top, &left, &bottom, &right ); + kdDebug() << "Margins = " << top << " " << left << " " << bottom << " " << right << endl; + + const QSize maxSize( printersize.width()-left-right, printersize.height()-top-bottom ); + QSize scaledImageSize = size; + if (size.width() > maxSize.width() || size.height() > maxSize.height() ) { + // Image does not fit - scale it and print centered + scaledImageSize.scale( maxSize, QSize::ScaleMin ); + kdDebug() << "Image does not fit - scaling to " << maxSize << endl; + } else { + // Image does fit - print it in original size, but centered + scaledImageSize.scale( size, QSize::ScaleMin ); + kdDebug() << "Image does fit - scaling to " << size << endl; + } + kdDebug() << "Final image size " << scaledImageSize << endl; + int x,y; + if (center_h) + x = (maxSize.width()-scaledImageSize.width())/2 + left; + else + x = left; + if (center_v) + y = (maxSize.height()-scaledImageSize.height())/2 + top; + else + y = top; + painter.drawImage( QRect(x,y,scaledImageSize.width(), scaledImageSize.height()), image ); + + } + + QApplication::restoreOverrideCursor(); +} + +void TopLevel::saveNetFile( const KURL& dest) +{ + if ( !dest.isValid() ) + { + KMessageBox::sorry(this, i18n("Malformed URL")); + return; + } + + statusbar->message( i18n( "Saving..." ) ); + + KURL source = KURL::fromPathOrURL(thispage->pathname); + bool ok = KIO::NetAccess::file_copy( source, dest, -1, true, false, this); + + statusbar->clear(); + + if (!ok) + KMessageBox::error(this, i18n("Failure in 'copy file()'\n" + "Could not save file!")); +} + +void TopLevel::openNetFile( const KURL &u) +{ + if ( !u.isValid() ) + { + KMessageBox::error(this, i18n("Malformed URL")); + return; + } + + if ( u.isLocalFile() ) + { + QString string = i18n("Loading '%1'").arg(u.path()); + statusbar->message(string); + openadd( u.path()); + statusbar->clear(); + } + else + { + statusbar->message(i18n("Downloading...")); + QString tmpFile = QString::null; + if ( KIO::NetAccess::download( u, tmpFile, this ) ) + { + openadd( tmpFile ); + setCaption( u.prettyURL() ); + } + statusbar->clear(); + KIO::NetAccess::removeTempFile( tmpFile ); + } +} + +void TopLevel::dragEnterEvent( QDragEnterEvent * event) +{ + event->accept(KURLDrag::canDecode(event)); +} + +void TopLevel::dropEvent( QDropEvent * event) +{ + + KURL::List list; + + if (KURLDrag::decode(event, list) && !list.isEmpty()) + { + // Load the first file in this window + const KURL &url = list.first(); + openNetFile( url ); + } +} + +void SetupDisplay(){ + + if(display_is_setup){ + return; + } + + display_is_setup = TRUE; + + xpos = ypos = ox = oy = 0; + ExpectConfNotify = 1; + + /* XSizeHints size_hints;*/ + + Win = XCreateSimpleWindow(qtdisplay,qtwin,1,1, + 1,1, + 0, + BlackPixel(qtdisplay,XDefaultScreen(qtdisplay)), + WhitePixel(qtdisplay,XDefaultScreen(qtdisplay))); + + PaintGC = XCreateGC(qtdisplay, Win, 0L, (XGCValues *) NULL); + XSetForeground(qtdisplay, PaintGC, BlackPixel(qtdisplay, XDefaultScreen(qtdisplay) )); + XSetBackground(qtdisplay, PaintGC, WhitePixel(qtdisplay, XDefaultScreen(qtdisplay) )); + XSetFunction(qtdisplay, PaintGC, GXcopy); + WorkCursor = XCreateFontCursor(qtdisplay, XC_watch); + //ReadyCursor = XCreateFontCursor(qtdisplay, XC_plus); + ReadyCursor = XCreateFontCursor(qtdisplay, XC_hand2); + MoveCursor = XCreateFontCursor(qtdisplay, XC_fleur); + LRCursor = XCreateFontCursor(qtdisplay, XC_sb_h_double_arrow); + UDCursor = XCreateFontCursor(qtdisplay, XC_sb_v_double_arrow); + + XSelectInput(qtdisplay, Win, Button2MotionMask | ButtonPressMask | + ButtonReleaseMask | ExposureMask | KeyPressMask | + SubstructureNotifyMask | LeaveWindowMask | OwnerGrabButtonMask | + StructureNotifyMask); + + XMapRaised(qtdisplay, Win); + + XDefineCursor(qtdisplay, Win, ReadyCursor); + XFlush(qtdisplay); + + memset(Images, 0, sizeof(Images)); + + // Start at half the Size + oz = 1; +} + +void TopLevel::handle_X_event(XEvent Event) +{ + if(!thispage || !Image || !faxqtwin || !display_is_setup) + return; + + bool putimage = false; // Do we actually have to write the image to the scree? + + do { + switch(Event.type) { + case MappingNotify: + XRefreshKeyboardMapping((XMappingEvent *)(&Event)); + break; + + case LeaveNotify: + /* buttondown = false; + XDefineCursor(qtdisplay, Win, ReadyCursor); + XFlush(qtdisplay);*/ + break; + case Expose: + { + + if(Event.xexpose.count != 0) + break; + + if(!Image) + break; + + putimage = TRUE; + } + break; + + case KeyPress: + if (ExpectConfNotify && + (Event.xkey.time < (Lasttime + PATIENCE))) + break; + Lasttime = Event.xkey.time; + ExpectConfNotify = 0; + switch(XKeycodeToKeysym(qtdisplay, Event.xkey.keycode, 0)) { + case XK_m: + mirrorPage(); + if (Event.xkey.state & ShiftMask) + TurnFollowing(TURN_M, thispage->next); + break; + case XK_o: + zoomout(); + break; + + case XK_i: + zoomin(); + break; + + case XK_Up: + ypos-= qwindow_height / 3; + putimage = TRUE; + break; + case XK_Down: + ypos+= qwindow_height / 3; + putimage = TRUE; + break; + case XK_Left: + xpos-= qwindow_width / 4; + putimage = TRUE; + break; + case XK_Right: + xpos+= qwindow_width / 4; + putimage = TRUE; + break; + case XK_Home: + case XK_R7: + if (Event.xkey.state & ShiftMask) { + thispage = firstpage; + newPage(); + resizeView(); + putImage(); + break; + } + xpos= 0; + ypos= 0; + putImage(); + break; + case XK_End: + case XK_R13: + if (Event.xkey.state & ShiftMask) { + thispage = lastpage; + newPage(); + resizeView(); + putImage(); + break; + } + xpos= Image->width; + ypos= Image->height; + putImage(); + break; + case XK_l: + case XK_r: + rotatePage(); + if (Event.xkey.state & ShiftMask) + TurnFollowing(TURN_L, thispage->next); + break; + case XK_p: + case XK_minus: + case XK_Prior: + case XK_R9: + case XK_BackSpace: + prevPage(); + break; + case XK_n: + case XK_plus: + case XK_space: + case XK_Next: + case XK_R15: + nextPage(); + break; + case XK_u: + flipPage(); + if (Event.xkey.state & ShiftMask) + TurnFollowing(TURN_U, thispage->next); + break; + + case XK_q: + if (viewpage) { + thispage = viewpage; + viewpage = NULL; + newPage(); + resizeView(); + putImage(); + } + + } + + break; + + case ButtonPress: + + if (ExpectConfNotify && (Event.xbutton.time < (Lasttime + PATIENCE))) + break; + + Lasttime = Event.xbutton.time; + ExpectConfNotify = 0; + + + switch (Event.xbutton.button) { + + case Button1: + buttondown = true; + + switch (((Image->width > qwindow_width)<<1) | + (Image->height > qwindow_height)) { + case 0: + break; + case 1: + XDefineCursor(qtdisplay, Win, UDCursor); + break; + case 2: + XDefineCursor(qtdisplay, Win, LRCursor); + break; + case 3: + XDefineCursor(qtdisplay, Win, MoveCursor); + } + + XFlush(qtdisplay); + offx = Event.xbutton.x; + offy = Event.xbutton.y; + break; + + } + + break; + + case MotionNotify: + if(!buttondown) + break; + do { + + nx = Event.xmotion.x; + ny = Event.xmotion.y; + + + } while (XCheckTypedEvent(qtdisplay, MotionNotify, &Event)); + + + xpos+= offx - nx; + ypos+= offy - ny; + + offx = nx; + offy = ny; + + putimage = TRUE; + + break; + + case ButtonRelease: + + if (Event.xbutton.button == Button1) { + + buttondown = false; + XDefineCursor(qtdisplay, Win, ReadyCursor); + XFlush(qtdisplay); + } + + } + + } while (XCheckWindowEvent(qtdisplay, Win, KeyPressMask|ButtonPressMask, &Event)); + + if(putimage == TRUE) { + Refresh = Resize = 1; + putImage(); + } +} + +void TopLevel::rotatePage() +{ + if(!thispage || !Image || !faxqtwin || !display_is_setup) + return; + + XDefineCursor(qtdisplay, Win, WorkCursor); + XFlush(qtdisplay); + + XImage *newrotimage = RotImage(Images[0]); + + XDefineCursor(qtdisplay, Win, ReadyCursor); + + if(newrotimage == NULL){ // out of memory + return; + } + + thispage->extra = Images[0] = newrotimage; + thispage->orient ^= TURN_L; + + freeImages(); + Image = generateZoomImages(oz); + + { int t = xpos ; xpos= ypos; ypos= t; } + + Refresh = Resize = 1; + + putImage(); +} + +void TopLevel::flipPage() +{ + if(!thispage || !Image || !faxqtwin || !display_is_setup) + return; + + XDefineCursor(qtdisplay, Win, WorkCursor); + XFlush(qtdisplay); + + XImage *newflipimage = FlipImage(Images[0]); + + XDefineCursor(qtdisplay, Win, ReadyCursor); + + if(newflipimage == NULL){ // out of memory + return; + } + + thispage->extra = Images[0] = newflipimage; + thispage->orient ^= TURN_U; + + freeImages(); + Image = generateZoomImages(oz); + + Refresh = Resize = 1; + putImage(); +} + +void TopLevel::mirrorPage() +{ + if(!thispage || !Image || !faxqtwin || !display_is_setup) + return; + + XDefineCursor(qtdisplay, Win, WorkCursor); + XFlush(qtdisplay); + + XImage *newmirror = MirrorImage(Images[0]); + + XDefineCursor(qtdisplay, Win, ReadyCursor); + + if(newmirror == NULL){ // out of memory + return; + } + thispage->extra = Images[0] = newmirror; + thispage->orient ^= TURN_M; + + freeImages(); + Image = generateZoomImages(oz); + + Refresh = Resize = 1; + putImage(); +} + +void TopLevel::scrollHorz(int){ + + if(!Image) + return; + + // printf("hsb value: %d\n",hsb->value()); + xpos= hsb->value() + qwindow_width/2; + + Refresh = 1; + putImage(); +} + +void TopLevel::scrollVert(int ){ + + if(!Image) + return; + + // printf("vsb value: %d\n",vsb->value()); + ypos= vsb->value() + qwindow_height/2; + + Refresh = 1; + putImage(); +} + +void TopLevel::lastPage() +{ + if(!thispage) + return; + + if ( thispage->next ) + { + while(thispage->next != NULL) + thispage = thispage->next; + + newPage(); + resizeView(); + putImage(); + } + + updateGoActions(); +} + +void TopLevel::firstPage() +{ + if(!thispage) + return; + + if ( thispage->prev ) + { + while(thispage->prev != NULL) + thispage = thispage->prev; + + newPage(); + resizeView(); + putImage(); + } + + updateGoActions(); +} + +void TopLevel::nextPage() +{ + if(!thispage) + return; + + if (thispage->next) + { + thispage = thispage->next; + + newPage(); + resizeView(); + putImage(); + } + + updateGoActions(); +} + +void TopLevel::prevPage() +{ + if(!thispage) + return; + + if (thispage->prev) + { + thispage = thispage->prev; + + newPage(); + resizeView(); + putImage(); + } + + updateGoActions(); +} + +void TopLevel::newPage(){ + + if(!display_is_setup) + SetupDisplay(); + + XDefineCursor(qtdisplay, Win, WorkCursor); + XFlush(qtdisplay); + + freeImages(); + + int k = -1; + + if(!thispage) { + XDefineCursor(qtdisplay, Win, ReadyCursor); + return; + } + + if (Pimage(thispage) == NULL){ + + while((k != 0) && (k != 3) && (k !=1)) + k = GetImage(thispage); + + } + + if (k == 3 ){ + + XDefineCursor(qtdisplay, Win, ReadyCursor); + FreeFax(); + /* KMessageBox::sorry(i18n("Bad fax file k=3"));*/ + return; + } + + if (k == 0 ){ + + XDefineCursor(qtdisplay, Win, ReadyCursor); + FreeFax(); + /* KMessageBox::sorry(i18n("Bad fax file k=0"));*/ + return; + } + + Image = Images[0] = Pimage(thispage); + + setCaption(QFile::decodeName(thispage->name)); + + Image = generateZoomImages(oz); + + PaneWidth = Image->width; + PaneHeight = Image->height; + Refresh = 1; + + XDefineCursor(qtdisplay, Win, ReadyCursor); + uiUpdate(); + +} + + +void TopLevel::faxClose() +{ + FreeFax(); + + setCaption(i18n("KFax")); + // TODO replace this with unmapping the window. + if(display_is_setup) + XResizeWindow(qtdisplay,Win,1,1); // we want a clear gray background. + + resizeView(); + vsb->hide(); + hsb->hide(); + + fileURL = QString::null; + + updateActions(); +} + +void TopLevel::FreeFax() +{ + if(display_is_setup) + XClearWindow(qtdisplay, Win); + + freeImages(); + + pagenode *pn; + for (pn = firstpage; pn; pn = pn->next){ + if(Pimage(pn)){ + FreeImage(Pimage(pn)); + pn->extra = NULL; + } + } + + Image = NULL; + + for (pn = firstpage; pn; pn = pn->next){ + if(pn->pathname){ + free(pn->pathname); + } + } + + + if(firstpage){ + for(pn = firstpage->next; pn; pn = pn->next){ + if(pn->prev){ + free(pn->prev); + } + } + } + + if(lastpage) + free(lastpage); + + firstpage = lastpage = viewpage = thispage = auxpage = NULL; + + uiUpdate(); +} + +void TopLevel::uiUpdate(){ + + if(thispage){ + + struct pagenode *pn ; + int pages = 0; + int currentpage = 0; + + for(pn = firstpage; pn ; pn = pn->next){ + pages ++; + if (thispage == pn) + currentpage = pages; + } + + QString pagestr = i18n("Page: %1 of %2").arg(currentpage).arg(pages); + + statusbar->changeItem(pagestr, ID_PAGE_NO); + + if(Image){ + QString wh = i18n("W: %1 H: %2").arg(Image->width).arg(Image->height); + statusbar->changeItem(wh, ID_INS_OVR); + } + + QString resolution = i18n("Res: %1").arg(thispage->vres?i18n("Fine"):i18n("Normal")); + // TODO: resolution += QString("%1x%2").arg(thispage->dpiX).arg(thispage->dpiY); + statusbar->changeItem(resolution, ID_GENERAL); + + statusbar->changeItem(thispage->name, ID_FNAME); + + QString typestring; + + if(thispage->type == FAX_TIFF){ + typestring = i18n("Type: Tiff "); + } + else if ( thispage->type == FAX_RAW){ + typestring = i18n("Type: Raw "); + } + + if ( thispage->expander == g31expand ) + typestring += "G3"; + + if ( thispage->expander == g32expand ) + typestring += "G3 2D"; + + if ( thispage->expander == g4expand ) + typestring += "G4"; + + statusbar->changeItem(typestring,ID_TYPE); + updateActions(); + } +} + +void kfaxerror(const QString& title, const QString& error){ + KMessageBox::error(toplevel, error, title); +} + +void TopLevel::putImage() +{ + + // TODO do I really need to set Refresh or Resize to 1 , is there + // really still someonce calling this with out haveing set Refresh or Resize to 1? + + if ( !Image || !display_is_setup || !thispage ) + return; + + if ( qwindow_width > Image->width){ + xpos= Image->width/2; + } + else{ + if(xpos< qwindow_width/2){ + xpos = qwindow_width/2; + } + else{ + if(xpos> Image->width - qwindow_width/2){ + xpos= Image->width - qwindow_width/2; + } + + } + } + + if ( qwindow_height > Image->height){ + ypos= Image->height/2; + } + else{ + if(ypos< qwindow_height/2){ + ypos = qwindow_height/2; + } + else{ + if(ypos> Image->height - qwindow_height/2){ + ypos= Image->height - qwindow_height/2; + } + + } + } + + if (xpos!= ox || ypos!= oy || Refresh || Resize){ + + /* In the following we use qwindow_height -1 etc since the main view + has a sunken frame and I need to offset by 1 pixel to the right and + one pixel down so that I don't paint my fax into the border of the frame*/ + + XResizeWindow(qtdisplay,Win,QMIN(qwindow_width -1,Image->width ), + QMIN(qwindow_height -1,Image->height )); + + XPutImage(qtdisplay, Win, PaintGC, Image, + QMAX(xpos - qwindow_width/2,0), QMAX(ypos - qwindow_height/2,0), + 0, 0, QMIN(qwindow_width -1,Image->width) , + QMIN(qwindow_height -1,Image->height) ); + + vsb->setValue(QMAX(ypos - qwindow_height/2,0)); + hsb->setValue(QMAX(xpos - qwindow_width/2,0)); + + XFlush(qtdisplay); + } + + ox = xpos; + oy = ypos; + + Resize = Refresh = 0; + +} + +void TopLevel::faxoptions(){ + + OptionsDialog * opd = new OptionsDialog(this, "options"); + opd->setWidgets(&fop); + + if(opd->exec()){ + + struct optionsinfo *newops; + newops = opd->getInfo(); + + fop.resauto = newops->resauto; + fop.geomauto = newops->geomauto; + fop.width = newops->width; + fop.height = newops->height; + fop.fine = newops->fine; + fop.landscape= newops->landscape; + fop.flip = newops->flip; + fop.invert = newops->invert; + fop.lsbfirst = newops->lsbfirst; + fop.raw = newops->raw; + + setFaxDefaults(); + + writeSettings(); + } + + delete opd; +} + +void setFaxDefaults(){ + + // fop is called in readSettings, so this can't be + // called after a TopLevel::readSettings() + + if(have_cmd_opt ) // we have commad line options all kfaxrc defaults are + return; // overridden + + if(fop.resauto == 1) + defaultpage.vres = -1; + else + defaultpage.vres = fop.fine; + + if(fop.geomauto == 1){ + defaultpage.width = defaultpage.height = 0; + } + else{ + defaultpage.width = fop.width; + defaultpage.height = fop.height; + } + + if(fop.landscape) + defaultpage.orient |= TURN_L; + + if(fop.flip) + defaultpage.orient |= TURN_U; + + defaultpage.inverse = fop.invert; + defaultpage.lsbfirst = fop.lsbfirst; + + switch (fop.raw) { + case 2: defaultpage.expander = g32expand; + break; + case 4: defaultpage.expander = g4expand; + break; + default:defaultpage.expander = g31expand; + } + +} + +static const char description[] = + I18N_NOOP("KDE G3/G4 Fax Viewer"); + +static KCmdLineOptions options[] = +{ + {"f", 0, 0 }, + {"fine", I18N_NOOP( "Fine resolution" ), 0 }, + {"n", 0, 0 }, + {"normal", I18N_NOOP( "Normal resolution" ), 0 }, + {"height", I18N_NOOP( "Height (number of fax lines)" ), 0 }, + {"w", 0, 0 }, + {"width", I18N_NOOP( "Width (dots per fax line)" ), 0 }, + {"l", 0, 0 }, + {"landscape", I18N_NOOP( "Turn image 90 degrees (landscape mode)" ), 0 }, + {"u", 0, 0 }, + {"upsidedown", I18N_NOOP( "Turn image upside down" ), 0 }, + {"i", 0, 0 }, + {"invert", I18N_NOOP( "Invert black and white" ), 0 }, + {"m", 0, 0 }, + {"mem ", I18N_NOOP( "Limit memory use to 'bytes'" ), "8M" }, + {"r", 0, 0 }, + {"reverse", I18N_NOOP( "Fax data is packed lsb first" ), 0 }, + {"2" , I18N_NOOP( "Raw files are g3-2d" ), 0 }, + {"4", I18N_NOOP( "Raw files are g4" ), 0 }, + {"+file(s)", I18N_NOOP( "Fax file(s) to show" ), 0 }, + KCmdLineLastOption +}; + +int main (int argc, char **argv) +{ + KAboutData aboutData( "kfax", I18N_NOOP("KFax"), + KFAXVERSION, description, KAboutData::License_GPL, + "(c) 1997-98 Bernd Johannes Wuebben"); + aboutData.addAuthor( "Bernd Johannes Wuebben", 0, "wuebben@kde.org" ); + aboutData.addCredit( "Nadeem Hasan", I18N_NOOP( "UI Rewrite, lots of code " + "cleanups and fixes" ), "nhasan@kde.org" ); + aboutData.addCredit( "Helge Deller", I18N_NOOP( "Printing Rewrite, lots of code " + "cleanups and fixes"), "deller@kde.org" ); + + KCmdLineArgs::init(argc, argv, &aboutData); + KCmdLineArgs::addCmdLineOptions( options ); + + MyApp a; + + qtdisplay = qt_xdisplay(); + + viewfaxmain(); + + toplevel = new TopLevel(); + toplevel->show(); + + startingup = 1; + a.processEvents(); + a.flushX(); + + startingup = 0; + + faxinit(); + if(!have_no_fax){ + + thispage = firstpage; + + toplevel->newPage(); + toplevel->resizeView(); + //TODO : I don't think I need this putImage(); + toplevel->putImage(); + } + + toplevel->uiUpdate(); + + return a.exec (); +} + + +#include "kfax.moc" diff --git a/kfax/kfax.desktop b/kfax/kfax.desktop new file mode 100644 index 00000000..eefd8b87 --- /dev/null +++ b/kfax/kfax.desktop @@ -0,0 +1,86 @@ +[Desktop Entry] +MimeType=image/fax-g3;image/tiff; +GenericName=Fax Viewer +GenericName[af]=Faks Aansig +GenericName[ar]=عارض الفاكس +GenericName[bg]=Преглед на факсове +GenericName[br]=Gweler faks +GenericName[bs]=Preglednik faxova +GenericName[ca]=Visualitzador de fax +GenericName[cs]=Prohlížeč faxů +GenericName[cy]=Gwelydd Ffacs +GenericName[da]=Fax-fremviser +GenericName[de]=Faxbetrachter +GenericName[el]=Προβολέας φαξ +GenericName[eo]=Faksrigardilo +GenericName[es]=Visor de faxes +GenericName[et]=Fakside vaataja +GenericName[eu]=Fax ikustailua +GenericName[fa]=مشاهده‌گر دورنگار +GenericName[fi]=Faksinäytin +GenericName[fr]=Afficheur de fax +GenericName[gl]=Visor de fax +GenericName[he]=מציג פקסים +GenericName[hi]=फ़ैक्स प्रदर्शक +GenericName[hr]=Preglednik faksova +GenericName[hu]=Faxnézegető +GenericName[is]=Fax sjá +GenericName[it]=Visore di fax +GenericName[ja]=ファクスビューア +GenericName[kk]=Факсты қарау +GenericName[km]=កម្មវិធី​មើល​ទូរសារ +GenericName[lt]=Faksų žiūriklis +GenericName[lv]=Faksu Skatītājs +GenericName[ms]=Pemapar Faks +GenericName[nb]=Faksfremviser +GenericName[nds]=Faxkieker +GenericName[ne]=फ्याक्स द्रष्टा +GenericName[nl]=Faxweergaveprogramma +GenericName[nn]=Faksvisar +GenericName[pa]=ਫੈਕਸ ਦਰਸ਼ਕ +GenericName[pl]=Przeglądarka faksów +GenericName[pt]=Visualizador de Faxes +GenericName[pt_BR]=Visualizador de Faxes +GenericName[ro]=Vizualizor FAX +GenericName[ru]=Просмотр факсов +GenericName[se]=Fáksačájeheaddji +GenericName[sk]=Prehliadač faxov +GenericName[sl]=Pregledovalnik faksov +GenericName[sr]=Приказивач факсова +GenericName[sr@Latn]=Prikazivač faksova +GenericName[sv]=Faxvisare +GenericName[ta]=ஃபாக்ஸ் காட்சி +GenericName[tg]=Хондани факс +GenericName[th]=เครื่องมือแสดงโทรสารของ KDE +GenericName[tr]=Faks Görüntüleyici +GenericName[uk]=Переглядач факсів +GenericName[uz]=Faks koʻruvchi +GenericName[uz@cyrillic]=Факс кўрувчи +GenericName[ven]=Muvhoni wa Fekisi +GenericName[wa]=Håyneu di facs +GenericName[xh]=Umboniseli Wefax +GenericName[zh_CN]=传真查看器 +GenericName[zh_HK]=傳真檢視器 +GenericName[zh_TW]=傳真檢視器 +GenericName[zu]=Umbonisi wefax +Name=KFax +Name[af]=K-faks +Name[ar]=برنامج KFax +Name[cy]=KFfacs +Name[eo]=Faksrigardilo +Name[hi]=के-फ़ैक्स +Name[lv]=KFakss +Name[ne]=केडीई फ्याक्स +Name[sv]=Kfax +Name[ta]=கேஃபாக்ஸ் +Name[ven]=Fekisi ya K +Name[wa]=KFacs +Name[zh_TW]=KFax 傳真檢視器 +Exec=kfax %f -caption "%c" %i %m +Icon=kfax +Path= +Type=Application +Terminal=false +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Multi +Categories=Qt;KDE;Graphics;X-KDE-More; diff --git a/kfax/kfax.h b/kfax/kfax.h new file mode 100644 index 00000000..506a1452 --- /dev/null +++ b/kfax/kfax.h @@ -0,0 +1,159 @@ + /* + + $Id$ + + Requires the Qt widget libraries, available at no cost at + http://www.troll.no + + Copyright (C) 1997 Bernd Johannes Wuebben + wuebben@math.cornell.edu + + + 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 _KFAX_H_ +#define _KFAX_H_ + +#include +#include +#include +#include + +#define Pimage(p) ((XImage *)(p)->extra) + +class QPopupMenu; +class KConfig; +class KStatusBar; +class KAction; +class KRecentFilesAction; +class KPrinter; +class QPainter; +class QScrollBar; + +typedef KToolBar::BarPosition BarPosition; + +class MyApp:public KApplication { +public: + virtual bool x11EventFilter( XEvent * ); +}; + +class TopLevel : public KMainWindow +{ + Q_OBJECT + + +public: + + TopLevel( QWidget *parent=0, const char *name=0 ); + ~TopLevel(); + + void openNetFile( const KURL& _url); + void saveNetFile( const KURL& _url ); + + static QPtrList windowList; + QPopupMenu *right_mouse_button, *colors; + + void handle_X_event(XEvent Event); + void putImage(); + +protected: + + void resizeEvent( QResizeEvent * ); + void wheelEvent( QWheelEvent * ); + void dragEnterEvent( QDragEnterEvent * event ); + void dropEvent( QDropEvent * event ); + + void updateActions(); + void updateGoActions(); + void updateZoomActions(); + + void zoom( int ); + + void readSettings(); + void writeSettings(); + void setupActions(); + void setupMenuBar(); + void setupToolBar(); + void setupEditWidget(); + void setupStatusBar(); + + bool queryClose(); + +private: + + QFrame *faxqtwin; + + int indentID; + QColor forecolor; + QColor backcolor; + + KURL fileURL; + KStatusBar *statusbar; + + KRecentFilesAction *actRecent; + KAction *actAdd, *actSave, *actSaveAs, *actPrint; + KAction *actSize, *actZoomIn, *actZoomOut, *actRotate, *actMirror; + KAction *actFlip, *actNext, *actPrev, *actFirst, *actLast; + + int open_mode; + + KConfig *config; + + QScrollBar *hsb; + QScrollBar *vsb; + QFrame* mainpane; + + void printIt( KPrinter &printer, QPainter &painter ); + bool loadAllPages( int &numpages, int ¤tpage ); + +public slots: + + void faxOpen( const KURL & ); + void faxOpen(); + void faxAdd(); + void faxAdd( const KURL & ); + void faxClose(); + void print(); + void zoomin(); + void zoomout(); + void actualSize(); + void resizeView(); + void faxSave(); + void faxSaveAs(); + + void faxoptions(); + void rotatePage(); + void mirrorPage(); + void flipPage(); + void nextPage(); + void prevPage(); + void newPage(); + void firstPage(); + void lastPage(); + void uiUpdate(); + + void openadd(QString filename); + void FreeFax(); + void scrollHorz(int); + void scrollVert(int); +}; + +void kfaxerror(const QString&, const QString&); +void loadfile(QString filename); + +#endif // _KFAX_H_ + diff --git a/kfax/kfax.tif b/kfax/kfax.tif new file mode 100644 index 00000000..85eec6bb Binary files /dev/null and b/kfax/kfax.tif differ diff --git a/kfax/kfax_printsettings.cpp b/kfax/kfax_printsettings.cpp new file mode 100644 index 00000000..02aa4050 --- /dev/null +++ b/kfax/kfax_printsettings.cpp @@ -0,0 +1,98 @@ +/* + * This file is part of the KDE libraries + * Copyright (c) 2005 Helge Deller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * 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 "kfax_printsettings.h" + +#include +#include +#include +#include + +KFAXPrintSettings::KFAXPrintSettings(QWidget *parent, const char *name) +: KPrintDialogPage(parent, name) +{ + QString whatsThisScaleFullPage = i18n( "" + "

'Ignore Paper Margins'

" + "

" + "If this checkbox is enabled, the paper margins will be ignored " + "and the fax will be printed on the full paper size." + "

" + "

" + "If this checkbox is disabled, KFax will respect the standard paper " + "margins and print the fax inside this printable area." + "

" + " " ); + QString whatsThisCenterHorz = i18n( "" + "

'Horizontal centered'

" + "

" + "If this checkbox is enabled, the fax will be centered horizontally " + "on the page." + "

" + "

" + "If this checkbox is disabled, the fax will be printed at the left " + "side of the page." + "

" + "
" ); + QString whatsThisCenterVert = i18n( "" + "

'Vertical centered'

" + "

" + "If this checkbox is enabled, the fax will be centered vertically " + "on the page." + "

" + "

" + "If this checkbox is disabled, the fax will be printed at the top " + "of the page." + "

" + "
" ); + + setTitle(i18n("&Layout")); + + m_scaleFullPage = new QCheckBox(i18n("Ignore paper margins"), this); + QWhatsThis::add(m_scaleFullPage, whatsThisScaleFullPage); + m_center_horz = new QCheckBox(i18n("Horizontal centered"), this); + QWhatsThis::add(m_center_horz, whatsThisCenterHorz); + m_center_vert = new QCheckBox(i18n("Vertical centered"), this); + QWhatsThis::add(m_center_vert, whatsThisCenterVert); + + QVBoxLayout *l0 = new QVBoxLayout(this, 0, 10); + l0->addWidget(m_scaleFullPage); + l0->addWidget(m_center_horz); + l0->addWidget(m_center_vert); + l0->addStretch(1); +} + +KFAXPrintSettings::~KFAXPrintSettings() +{ +} + +void KFAXPrintSettings::getOptions(QMap& opts, bool /*incldef*/) +{ + opts[APP_KFAX_SCALE_FULLPAGE] = (m_scaleFullPage->isChecked() ? "true" : "false"); + opts[APP_KFAX_CENTER_HORZ] = (m_center_horz->isChecked() ? "true" : "false"); + opts[APP_KFAX_CENTER_VERT] = (m_center_vert->isChecked() ? "true" : "false"); +} + +void KFAXPrintSettings::setOptions(const QMap& opts) +{ + m_scaleFullPage->setChecked(opts[APP_KFAX_SCALE_FULLPAGE] == "true"); + m_center_horz->setChecked(opts[APP_KFAX_CENTER_HORZ] != "false"); + m_center_vert->setChecked(opts[APP_KFAX_CENTER_VERT] == "true"); +} + +#include "kfax_printsettings.moc" diff --git a/kfax/kfax_printsettings.h b/kfax/kfax_printsettings.h new file mode 100644 index 00000000..e43e3530 --- /dev/null +++ b/kfax/kfax_printsettings.h @@ -0,0 +1,47 @@ +/* + * This file is part of the KDE libraries + * Copyright (c) 2005 Helge Deller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * 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 KFAX_PRINTSETTINGS_H +#define KFAX_PRINTSETTINGS_H + +#include + +class QCheckBox; + +#define APP_KFAX_SCALE_FULLPAGE "app-kfax-scalefullpage" +#define APP_KFAX_CENTER_HORZ "app-kfax-center-horz" +#define APP_KFAX_CENTER_VERT "app-kfax-center-vert" + +class KFAXPrintSettings : public KPrintDialogPage +{ + Q_OBJECT +public: + KFAXPrintSettings(QWidget *parent = 0, const char *name = 0); + ~KFAXPrintSettings(); + + void getOptions(QMap& opts, bool incldef = false); + void setOptions(const QMap& opts); + +private: + QCheckBox *m_scaleFullPage; + QCheckBox *m_center_horz; + QCheckBox *m_center_vert; +}; + +#endif diff --git a/kfax/kfaxlogo.xpm b/kfax/kfaxlogo.xpm new file mode 100644 index 00000000..8adb7087 --- /dev/null +++ b/kfax/kfaxlogo.xpm @@ -0,0 +1,134 @@ +/* XPM */ +static char *magick[] = { +/* columns rows colors chars-per-pixel */ +"90 120 8 1", +" c #ffffff", +". c #595959", +"X c #808080", +"o c #c0c0c0", +"O c #000000", +"+ c #dfdfdf", +"@ c #303030", +"# c #a0a0a4", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" .....X ...... o....o ", +" OOOOO. oOOOOOX +@OOOOOO@+ ", +" OOOOO. .OOOO@ +@OOOOOOOO@+ ", +" OOOOO. XOOOOO# @OOOOOOOOOO# ", +" OOOOO. @OOOO@ #OOOOOOOOO@+ ", +" OOOOO. XOOOOOo .OOOOO.@O. o...X+ o..... ..... ", +" OOOOO.+@OOOO. OOOOO. o #.OOOOOO. #OOOOO OOOOO ", +" OOOOO..OOOOO+ OOOOO. #OOOOOOOOO@+ #OOOOO OOOOO ", +" OOOOO@OOOOO. OOOOO. +OOOOOOOOOOO. #OOOOO OOOOO ", +" OOOOO@OOOOO# OOOOO@.o @OOOOOOOOOOOOo OOOOO++OOOOO ", +" OOOOO.@OOOO. OOOOOOO# OOOOOO..OOOOO. .OOOO@@OOOO. ", +" OOOOO.#OOOOOo OOOOOOO# #OOOOO# @OOOOO +.OOOOOOOO@+ ", +" OOOOO. OOOOO@ OOOOOOO# #OOOO. #OOOOO .OOOOOOOO. ", +" OOOOO. .OOOOOo OOOOOOO# oOOOO@ #OOOOO .OOOO@@OOOO. ", +" OOOOO. +OOOOO@ OOOOO.#+ OOOOO@###OOOOO OOOOO++OOOO@ ", +" OOOOO. @OOOOOo OOOOO. .OOOOOOO#OOOOO oOOOOO OOOOO ", +" OOOOO. #OOOOO@ OOOOO. +@OOOOOO#OOOOO #OOOOO OOOOO ", +" OOOOO. @OOOOOoOOOOO. o@OOOOO#OOOOO #OOOOO OOOOO ", +" OOOOO. .OOOOO.OOOOO. +@OOOO#OOOOO #OOOOO OOOOO ", +" #####o +####o######o o#.. ##### +##### ##### ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" " +}; diff --git a/kfax/kfaxui.rc b/kfax/kfaxui.rc new file mode 100644 index 00000000..35daf9f3 --- /dev/null +++ b/kfax/kfaxui.rc @@ -0,0 +1,28 @@ + + + + &File + + + &View + + + + + + + Main Toolbar + + + + + + + + + + + + + + diff --git a/kfax/options.cpp b/kfax/options.cpp new file mode 100644 index 00000000..b8bf8067 --- /dev/null +++ b/kfax/options.cpp @@ -0,0 +1,374 @@ +/* + $Id$ + + Requires the Qt widget libraries, available at no cost at + http://www.troll.no + + Copyright (C) 1996 Bernd Johannes Wuebben + wuebben@math.cornell.edu + + 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kfax.h" +#include "options.h" + +OptionsDialog::OptionsDialog( QWidget *parent, const char *name) + : KDialogBase( parent, name, true, i18n("Configure"), Ok|Cancel) +{ + QWidget *mainWidget = new QWidget(this); + setMainWidget(mainWidget); + + QVBoxLayout *mainLayout = new QVBoxLayout(mainWidget, 0, spacingHint()); + + bg = new QGroupBox(mainWidget,"bg"); + bg->setColumnLayout( 0, Qt::Horizontal ); + mainLayout->addWidget( bg ); + + QVBoxLayout *vbl = new QVBoxLayout(bg->layout()); + + QHBoxLayout *hbl1 = new QHBoxLayout(); + + vbl->addLayout( hbl1 ); + + displaylabel = new QLabel(i18n("Display options:"), bg,"displaylabel"); + displaylabel->setFixedSize( displaylabel->sizeHint() ); + hbl1->addWidget( displaylabel ); + + landscape = new QCheckBox(i18n("Landscape"), bg,"Landscape"); + landscape->setFixedSize( landscape->sizeHint() ); + hbl1->addSpacing( 10 ); + hbl1->addWidget( landscape ); + + flip = new QCheckBox(i18n("Upside down"), bg,"upsidedown"); + flip->setFixedSize( flip->sizeHint() ); + hbl1->addSpacing( 10 ); + hbl1->addWidget( flip ); + + invert = new QCheckBox(i18n("Invert"), bg,"invert"); + invert->setFixedSize( invert->sizeHint() ); + hbl1->addSpacing( 10 ); + hbl1->addWidget( invert ); + + vbl->addSpacing( 20 ); + + QHBoxLayout *hbl8 = new QHBoxLayout(); + vbl->addLayout( hbl8 ); + hbl8->addSpacing( 10 ); + + resgroup = new QButtonGroup(bg,"resgroup"); + resgroup->setFrameStyle(QFrame::NoFrame); + hbl8->addWidget( resgroup ); + + QHBoxLayout *hbl2 = new QHBoxLayout(resgroup); + + reslabel = new QLabel(i18n("Raw fax resolution:"),resgroup,"relabel"); + hbl2->addWidget( reslabel ); + + resauto = new QRadioButton(i18n("Auto"),resgroup,"resauto"); + hbl2->addSpacing( 20 ); + hbl2->addWidget( resauto ); + + fine = new QRadioButton(i18n("Fine"),resgroup,"fine"); + hbl2->addSpacing( 30 ); + hbl2->addWidget( fine ); + + normal = new QRadioButton(i18n("Normal"),resgroup,"normal"); + hbl2->addSpacing( 30 ); + hbl2->addWidget( normal ); + + vbl->addSpacing( 20 ); + + QHBoxLayout *hbl3 = new QHBoxLayout(); + vbl->addLayout( hbl3 ); + + lsblabel = new QLabel(i18n("Raw fax data are:"), bg,"lsblabel"); + hbl3->addSpacing( 10 ); + hbl3->addWidget( lsblabel ); + + lsb = new QCheckBox(i18n("LS-Bit first"), bg,"lsbitfirst"); + hbl3->addSpacing( 10 ); + hbl3->addWidget( lsb ); + + vbl->addSpacing( 15 ); + + QHBoxLayout *hbl9 = new QHBoxLayout(); + vbl->addLayout( hbl9 ); + hbl9->addSpacing( 10 ); + + rawgroup = new QButtonGroup(bg,"rawgroup"); + hbl9->addWidget( rawgroup ); + + QHBoxLayout *hbl4 = new QHBoxLayout( rawgroup ); + + rawgroup->setFrameStyle(QFrame::NoFrame); + + rawlabel = new QLabel(i18n("Raw fax format:"),rawgroup,"rawlabel"); + rawlabel->setFixedSize( rawlabel->sizeHint() ); + hbl4->addWidget( rawlabel ); + + g3 = new QRadioButton("G3",rawgroup,"g3"); + connect(g3,SIGNAL(clicked()), this, SLOT(g3toggled())); + hbl4->addSpacing( 20 ); + hbl4->addWidget( g3 ); + + g32d = new QRadioButton("G32d",rawgroup,"g32d"); + connect(g32d,SIGNAL(clicked()), this,SLOT(g32toggled())); + hbl4->addSpacing( 30 ); + hbl4->addWidget( g32d ); + + g4 = new QRadioButton("G4",rawgroup,"g4"); + connect(g4,SIGNAL(clicked()), this, SLOT(g4toggled())); + hbl4->addSpacing( 30 ); + hbl4->addWidget( g4 ); + + vbl->addSpacing( 20 ); + + QHBoxLayout *hbl5 = new QHBoxLayout(); + vbl->addLayout( hbl5 ); + + widthlabel = new QLabel(i18n("Raw fax width:"),bg,"widthlabel"); + hbl5->addSpacing( 10 ); + hbl5->addWidget( widthlabel ); + + widthedit = new KIntNumInput(1, bg); + widthedit->setRange(1, 10000, 1, false); + hbl5->addWidget( widthedit ); + + heightlabel = new QLabel(i18n("Height:"),bg,"heightlabel"); + hbl5->addSpacing( 10 ); + hbl5->addWidget( heightlabel ); + + heightedit = new KIntNumInput(1, bg); + heightedit->setRange(0, 100000, 1, false); + hbl5->addWidget( heightedit ); + + geomauto = new QCheckBox(i18n("Auto"),bg,"geomauto"); + connect(geomauto,SIGNAL(clicked()),this,SLOT(geomtoggled())); + hbl5->addSpacing( 10 ); + hbl5->addWidget( geomauto ); +} + + +struct optionsinfo * OptionsDialog::getInfo(){ + + if(resauto->isChecked()) + oi.resauto = 1; + + if(fine->isChecked()) + oi.fine = 1; + else + oi.fine = 0; + + if(landscape->isChecked()) + oi.landscape = 1; + else + oi.landscape = 0; + + if(flip->isChecked()) + oi.flip = 1; + else + oi.flip = 0; + + if(invert->isChecked()) + oi.invert = 1; + else + oi.invert = 0; + + if(lsb->isChecked()) + oi.lsbfirst = 1; + else + oi.lsbfirst = 0; + + if(geomauto->isChecked()) + oi.geomauto = 1; + + + if(g3->isChecked()){ + oi.raw = 3; + } + + if(g32d->isChecked()){ + oi.raw = 2; + oi.geomauto = 0; + + } + + if(g4->isChecked()){ + oi.raw = 4; + oi.geomauto = 0; + } + + oi.height = heightedit->value(); + oi.width = widthedit->value(); + + + + return &oi; + +} + +void OptionsDialog::setWidgets(struct optionsinfo* newoi ){ + + if(!newoi) + return; + + if(newoi->resauto == 1){ + resauto->setChecked(newoi->resauto); + fine->setChecked(!newoi->resauto); + normal->setChecked(!newoi->resauto); + } + else{ + if(newoi->fine == 1){ + resauto->setChecked(FALSE); + fine->setChecked(TRUE); + normal->setChecked(FALSE); + } + else{ + resauto->setChecked(FALSE); + fine->setChecked(FALSE); + normal->setChecked(TRUE); + } + } + + if(newoi->landscape == 1) + landscape->setChecked(TRUE); + else + landscape->setChecked(FALSE); + + if(newoi->flip == 1) + flip->setChecked(TRUE); + else + flip->setChecked(FALSE); + + if(newoi->invert == 1) + invert->setChecked(TRUE); + else + invert->setChecked(FALSE); + + if(newoi->lsbfirst == 1) + lsb->setChecked(TRUE); + else + lsb->setChecked(FALSE); + + if(newoi->raw == 3){ + geomauto->setEnabled(TRUE); + g3->setChecked(TRUE); + } + + if(newoi->raw == 2){ + geomauto->setEnabled(FALSE); + g32d->setChecked(TRUE); + } + + if(newoi->raw == 4){ + geomauto->setEnabled(FALSE); + g4->setChecked(TRUE); + } + widthedit->setValue(newoi->width); + heightedit->setValue(newoi->height); + + // auto height and width can only work with g3 faxes + if(newoi->geomauto == 1 && newoi->raw != 4 && newoi->raw != 2){ + geomauto->setChecked(TRUE); + widthedit->setEnabled(FALSE); + heightedit->setEnabled(FALSE); + } + else{ + geomauto->setChecked(FALSE); + widthedit->setEnabled(TRUE); + heightedit->setEnabled(TRUE); + + } + +} + + +void OptionsDialog::g32toggled(){ + + geomauto->setChecked(FALSE); + geomauto->setEnabled(FALSE); + widthedit->setEnabled(TRUE); + heightedit->setEnabled(TRUE); + +} + +void OptionsDialog::g4toggled(){ + + geomauto->setChecked(FALSE); + geomauto->setEnabled(FALSE); + widthedit->setEnabled(TRUE); + heightedit->setEnabled(TRUE); + + +} + + +void OptionsDialog::g3toggled(){ + + geomauto->setEnabled(TRUE); + geomauto->setChecked(TRUE); + widthedit->setEnabled(FALSE); + heightedit->setEnabled(FALSE); + + +} + +void OptionsDialog::geomtoggled(){ + + if(geomauto->isChecked()){ + + widthedit->setEnabled(FALSE); + heightedit->setEnabled(FALSE); + + } + else{ + + widthedit->setEnabled(TRUE); + heightedit->setEnabled(TRUE); + + } + +} + +void OptionsDialog::slotHelp(){ + kapp->invokeHelp(); +} + + +#include "options.moc" diff --git a/kfax/options.h b/kfax/options.h new file mode 100644 index 00000000..fa9c61c9 --- /dev/null +++ b/kfax/options.h @@ -0,0 +1,112 @@ +/* + $Id$ + + + Copyright (C) 1996 Bernd Johannes Wuebben + wuebben@math.cornell.edu + + 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 _OPTIONS_DIALOG_H_ +#define _OPTIONS_DIALOG_H_ + +#include +#include +#include +#include + +class QGroupBox; +class QLabel; +class QButtonGroup; +class QRadioButton; +class QCheckBox; +class QRadioButton; + + +struct optionsinfo { + int geomauto; + int resauto; + int width ; + int height; + int fine; + int landscape; + int flip; + int invert; + int lsbfirst; + int raw; +}; + +class KIntNumInput; + +class OptionsDialog : public KDialogBase { + + Q_OBJECT + +public: + OptionsDialog( QWidget *parent = 0, const char *name = 0); + + struct optionsinfo* getInfo(); + void setWidgets(struct optionsinfo *oi); + +signals: + +public slots: + void slotHelp(); + void geomtoggled(); + void g32toggled(); + void g4toggled(); + void g3toggled(); + +private: + + QGroupBox *bg; + QLabel *reslabel; + QButtonGroup *resgroup; + QRadioButton *fine; + QRadioButton *resauto; + QRadioButton *normal; + QLabel *displaylabel; + QButtonGroup *displaygroup; + QCheckBox *landscape; + QCheckBox *geomauto; + QCheckBox *flip; + QCheckBox *invert; + + QButtonGroup *lsbgroup; + QLabel *lsblabel; + QCheckBox *lsb; + QButtonGroup *rawgroup; + QRadioButton *g3; + QRadioButton *g32d; + QRadioButton *g4; + + QLabel *rawlabel; + + QLabel *widthlabel; + QLabel *heightlabel; + KIntNumInput *widthedit; + KIntNumInput *heightedit; + + struct optionsinfo oi; + +}; + + +#endif diff --git a/kfax/version.h b/kfax/version.h new file mode 100644 index 00000000..ca6653cf --- /dev/null +++ b/kfax/version.h @@ -0,0 +1 @@ +#define KFAXVERSION "3.3.6" diff --git a/kfax/viewfax.cpp b/kfax/viewfax.cpp new file mode 100644 index 00000000..fe1e4246 --- /dev/null +++ b/kfax/viewfax.cpp @@ -0,0 +1,770 @@ +/* + + KFax -- A G3/G4 Fax Viewer + + Copyrigh (C) 1997 Bernd Johannes Wuebben + wuebben@math.cornell.edu + wuebben@kde.org + + Based on: + + viewfax - g3/g4 fax processing software. + Copyright (C) 1990, 1995 Frank D. Cringle. + + This file is part of viewfax - g3/g4 fax processing software. + + viewfax 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "kfax.h" +#include "faxexpand.h" +#include "version.h" +#include "viewfax.h" + +/* NewImage() needs to fiddle with the Display structure */ +#define XLIB_ILLEGAL_ACCESS +#include +#include +#include +#include +#include +#include + + +#define VIEWFAXVERSION "2.3" + + +/* If moving the image around with the middle mouse button is jerky or + slow, try defining USE_MOTIONHINT. It may help (it may also make + things worse - it depends on the server implementation) */ +#undef USE_MOTIONHINT + + + +/* access the 'extra' field in a pagenode */ + +#define Pimage(p) ((XImage *)(p)->extra) + + +/* forward declarations */ + +XImage *FlipImage(XImage *xi); +XImage *MirrorImage(XImage *xi); +XImage *NewImage(int w, int h, char *data, int bit_order); +XImage *RotImage(XImage *Image); +XImage *ZoomImage(XImage *Big); + +void FreeImage(XImage *Image); + +static int release(int quit); + + +/* X variables */ + +extern Cursor WorkCursor; +extern Cursor ReadyCursor; +extern Cursor MoveCursor; +extern Cursor LRCursor; +extern Cursor UDCursor; + +extern bool have_no_fax; +extern Display* qtdisplay ; +extern Window qtwin; +extern Window Win; +extern int qwindow_width; +extern int qwindow_height; + +struct pagenode *firstpage, *lastpage, *thispage, *helppage, *auxpage; +struct pagenode defaultpage; + +Display *Disp; + +int Default_Screen; +int verbose = 0; + +int abell = 1; /* audio bell */ +int vbell = 0; /* visual bell */ +bool have_cmd_opt = FALSE; + +size_t Memused = 0; /* image memory usage */ +static size_t Memlimit = 8*1024*1024; /* try not to exceed */ + +#undef min +#undef max +#define min(a,b) ((a)<(b)?(a):(b)) +#define max(a,b) ((a)>(b)?(a):(b)) + +#ifndef EXIT_FAILURE +#define EXIT_FAILURE 1 +#endif + +/* OK, OK - this is a dreadful hack. But it adequately distinguishes + modern big- and little- endian hosts. We only need this to set the + byte order in XImage structures */ + +static union { t32bits i; unsigned char b[4]; } bo; +#define ByteOrder bo.b[3] + +static char Banner[] = +"KFax version " KFAXVERSION "\tCopyright (C) 1997, Bernd Johannes Wuebben\n"; + +/*"KFax is based on:\n" +"viewfax " VERSION ":\t\tCopyright (c) 1990, 1995 Frank D. Cringle.\n" +"libtiff v 3.4beta:\tCopyright (c) 1988 - 1955 Sam Leffler\n" +" \tCopyright (c) 1991 - 1995 Silicon Graphics, Inc.\n\n" +"KFax comes with ABSOLUTELY NO WARRANTY; for details see the\n" +"file \"COPYING\" in the distribution directory.\n";*/ + +XEvent Event; +XImage *Image, *Images[MAXZOOM]; +XSizeHints size_hints; + +Time Lasttime = 0; + +struct pagenode *viewpage = 0; + +int viewfaxmain() +{ + int banner = 0; + int have_height = 0; + + bo.i = 1; + defaultpage.vres = -1; + have_no_fax = TRUE; + + /* TODO Do I need to know this: */ + defaultpage.expander = g31expand; + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if (args->isSet("height")) + { + have_height = 1; + defaultpage.height = args->getOption("height").toInt(); + } + + if (args->isSet("2")) + { + defaultpage.expander = g32expand; + if(!have_height) + defaultpage.height = 2339; + } + + if (args->isSet("4")) + { + defaultpage.expander = g4expand; + if(!have_height) + defaultpage.height = 2155; + } + + if (args->isSet("invert")) + { + defaultpage.inverse = 1; + } + + if (args->isSet("landscape")) + { + defaultpage.orient |= TURN_L; + } + + if (args->isSet("fine")) + { + defaultpage.vres = 1; + } + + if (!args->isSet("rmal")) // "normal" is interpreted as "no"+"rmal" :-) + { + defaultpage.vres = 0; + } + + if (args->isSet("reverse")) + { + defaultpage.lsbfirst = 1; + } + + if (args->isSet("upsidedown")) + { + defaultpage.orient |= TURN_U; + } + + if (args->isSet("width")) + { + defaultpage.width = args->getOption("width").toInt(); + } + + QCString mem = args->getOption("mem"); + Memlimit = atoi(mem.data()); + switch(mem[mem.length()-1]) { + case 'M': + case 'm': + Memlimit *= 1024; + case 'K': + case 'k': + Memlimit *= 1024; + } + + if (defaultpage.expander == g4expand && defaultpage.height == 0) { + KCmdLineArgs::usage("--height value is required to interpret raw g4 faxes\n"); + } + + firstpage = lastpage = thispage = helppage = auxpage = 0; + + for (int i = 0; i < args->count(); i++){ + loadfile(QFile::decodeName(args->arg(i))); + } + args->clear(); + + if (banner ) { + fputs(Banner, stderr); + exit(1); + } + + have_no_fax = (firstpage == 0); + + Disp = qtdisplay; + Default_Screen = XDefaultScreen(qtdisplay); + + return 1; +} + + +/* Change orientation of all following pages */ +void TurnFollowing(int How, struct pagenode *pn) +{ + while (pn) { + if (Pimage(pn)) { + FreeImage(Pimage(pn)); + pn->extra = 0; + } + pn->orient ^= How; + pn = pn->next; + } +} + +static void +drawline(pixnum *run, int LineNum, struct pagenode *pn) +{ + t32bits *p, *p1; /* p - current line, p1 - low-res duplicate */ + pixnum *r; /* pointer to run-lengths */ + t32bits pix; /* current pixel value */ + t32bits acc; /* pixel accumulator */ + int nacc; /* number of valid bits in acc */ + int tot; /* total pixels in line */ + int n; + + LineNum += pn->stripnum * pn->rowsperstrip; + if (LineNum >= pn->height) { + if (verbose && LineNum == pn->height) + fputs("Height exceeded\n", stderr); + return; + } + + p = (t32bits *) (Pimage(pn)->data + LineNum*(2-pn->vres)*Pimage(pn)->bytes_per_line); + p1 =(t32bits *)( pn->vres ? 0 : p + Pimage(pn)->bytes_per_line/sizeof(*p)); + r = run; + acc = 0; + nacc = 0; + pix = pn->inverse ? ~0 : 0; + tot = 0; + while (tot < pn->width) { + n = *r++; + tot += n; + /* Watch out for buffer overruns, e.g. when n == 65535. */ + if (tot > pn->width) + break; + if (pix) + acc |= (~(t32bits)0 >> nacc); + else if (nacc) + acc &= (~(t32bits)0 << (32 - nacc)); + else + acc = 0; + if (nacc + n < 32) { + nacc += n; + pix = ~pix; + continue; + } + *p++ = acc; + if (p1) + *p1++ = acc; + n -= 32 - nacc; + while (n >= 32) { + n -= 32; + *p++ = pix; + if (p1) + *p1++ = pix; + } + acc = pix; + nacc = n; + pix = ~pix; + } + if (nacc) { + *p++ = acc; + if (p1) + *p1++ = acc; + } +} + +static int +GetPartImage(struct pagenode *pn, int n) +{ + unsigned char *Data = getstrip(pn, n); + + if (Data == 0) + return 3; + pn->stripnum = n; + (*pn->expander)(pn, drawline); + free(Data); + return 1; +} + +int GetImage(struct pagenode *pn){ + int i; + + if (pn->strips == 0) { + + /*printf("RAW fax file\n");*/ + + /* raw file; maybe we don't have the height yet */ + unsigned char *Data = getstrip(pn, 0); + if (Data == 0){ + + return 0; + } + pn->extra = NewImage(pn->width, pn->vres ? + pn->height : 2*pn->height, 0, 1); + +//printf("height = %d\n",pn->height); +//printf("setting height to %d\n", pn->vres ? pn->height : 2*pn->height); + + if(pn->extra == 0) + return 0; + + (*pn->expander)(pn, drawline); + } + else { + /* multi-strip tiff */ + /*printf("MULTI STRIP TIFF fax file\n");*/ + + pn->extra = NewImage(pn->width, pn->vres ? + pn->height : 2*pn->height, 0, 1); + + if(pn->extra == 0) + return 0; + pn->stripnum = 0; + for (i = 0; i < pn->nstrips; i++){ + + int k =GetPartImage(pn, i); + + if ( k == 3 ){ + FreeImage(Pimage(pn)); + return k; + } + + } + } + if (pn->orient & TURN_U) + pn->extra = FlipImage(Pimage(pn)); + if (pn->orient & TURN_M) + pn->extra = MirrorImage(Pimage(pn)); + if (pn->orient & TURN_L) + pn->extra = RotImage(Pimage(pn)); + if (verbose) printf("\tmemused = %d\n", Memused); + +/* +if(pn->extra) + printf("pn->extra !=0 %s\n",pn->name); +else + printf("pn->extra ==0 %s\n",pn->name); + */ + + return 1; +} + + + +/* run this region through perl to generate the zoom table: +$lim = 1; +@c = ("0", "1", "1", "2"); +print "static unsigned char Z[] = {\n"; +for ($i = 0; $i < 16; $i++) { + for ($j = 0; $j < 16; $j++) { + $b1 = ($c[$j&3]+$c[$i&3]) > $lim; + $b2 = ($c[($j>>2)&3]+$c[($i>>2)&3]) > $lim; + printf " %X,", ($b2 << 1) | $b1; + } + print "\n"; +} +print "};\n"; +*/ + +static unsigned char Z[] = { + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 3, + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 2, 3, 3, 3, + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 2, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, + 0, 0, 0, 1, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, + 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, + 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, + 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 0, 0, 0, 1, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, + 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, + 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, + 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, + 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, + 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +}; + +#define nib(n,w) (((w)>>((n)<<2))&15) +#define zak(a,b) Z[(a<<4)|b] + +/* 2 -> 1 zoom, 4 pixels -> 1 pixel + if #pixels <= $lim (see above), new pixel is white, + else black. +*/ + +XImage *ZoomImage(XImage *Big){ + + XImage *Small; + int w, h; + int i, j; + + XDefineCursor(Disp, Win, WorkCursor); + XFlush(Disp); + w = (Big->width+1) / 2; + h = (Big->height+1) / 2; + Small = NewImage(w, h, 0, Big->bitmap_bit_order); + if(Small == 0) + return 0; + + Small->xoffset = (Big->xoffset+1)/2; + for (i = 0; i < Big->height; i += 2) { + t32bits *pb0 = (t32bits *) (Big->data + i * Big->bytes_per_line); + t32bits *pb1 = pb0 + ((i == Big->height-1) ? 0 : Big->bytes_per_line/4); + t32bits *ps = (t32bits *) (Small->data + i * Small->bytes_per_line / 2); + for (j = 0; j < Big->bytes_per_line/8; j++) { + t32bits r1, r2; + t32bits t0 = *pb0++; + t32bits t1 = *pb1++; + r1 = (zak(nib(7,t0),nib(7,t1))<<14) | + (zak(nib(6,t0),nib(6,t1))<<12) | + (zak(nib(5,t0),nib(5,t1))<<10) | + (zak(nib(4,t0),nib(4,t1))<<8) | + (zak(nib(3,t0),nib(3,t1))<<6) | + (zak(nib(2,t0),nib(2,t1))<<4) | + (zak(nib(1,t0),nib(1,t1))<<2) | + (zak(nib(0,t0),nib(0,t1))); + t0 = *pb0++; + t1 = *pb1++; + r2 = (zak(nib(7,t0),nib(7,t1))<<14) | + (zak(nib(6,t0),nib(6,t1))<<12) | + (zak(nib(5,t0),nib(5,t1))<<10) | + (zak(nib(4,t0),nib(4,t1))<<8) | + (zak(nib(3,t0),nib(3,t1))<<6) | + (zak(nib(2,t0),nib(2,t1))<<4) | + (zak(nib(1,t0),nib(1,t1))<<2) | + (zak(nib(0,t0),nib(0,t1))); + *ps++ = (Big->bitmap_bit_order) ? + (r1<<16)|r2 : (r2<<16)|r1; + } + for ( ; j < Small->bytes_per_line/4; j++) { + t32bits r1; + t32bits t0 = *pb0++; + t32bits t1 = *pb1++; + r1 = (zak(nib(7,t0),nib(7,t1))<<14) | + (zak(nib(6,t0),nib(6,t1))<<12) | + (zak(nib(5,t0),nib(5,t1))<<10) | + (zak(nib(4,t0),nib(4,t1))<<8) | + (zak(nib(3,t0),nib(3,t1))<<6) | + (zak(nib(2,t0),nib(2,t1))<<4) | + (zak(nib(1,t0),nib(1,t1))<<2) | + (zak(nib(0,t0),nib(0,t1))); + *ps++ = (Big->bitmap_bit_order) ? + (r1<<16) : r1; + } + } + XDefineCursor(Disp, Win, ReadyCursor); + return Small; +} + +XImage *FlipImage(XImage *Image){ + + XImage *New = NewImage(Image->width, Image->height, + Image->data, !Image->bitmap_bit_order); + if(New == 0) + return 0; + + t32bits *p1 = (t32bits *) Image->data; + t32bits *p2 = (t32bits *) (Image->data + Image->height * + Image->bytes_per_line - 4); + + /* the first shall be last ... */ + while (p1 < p2) { + t32bits t = *p1; + *p1++ = *p2; + *p2-- = t; + } + + /* let Xlib twiddle the bits */ + New->xoffset = 32 - (Image->width & 31) - Image->xoffset; + New->xoffset &= 31; + + Image->data = 0; + FreeImage(Image); + return New; +} + +XImage *MirrorImage(XImage *Image){ + + int i; + XImage *New = NewImage(Image->width, Image->height, + Image->data, !Image->bitmap_bit_order); + if(New == 0) + return 0; + + /* reverse order of 32-bit words in each line */ + for (i = 0; i < Image->height; i++) { + t32bits *p1 = (t32bits *) (Image->data + Image->bytes_per_line * i); + t32bits *p2 = p1 + Image->bytes_per_line/4 - 1; + while (p1 < p2) { + t32bits t = *p1; + *p1++ = *p2; + *p2-- = t; + } + } + + /* let Xlib twiddle the bits */ + New->xoffset = 32 - (Image->width & 31) - Image->xoffset; + New->xoffset &= 31; + + Image->data = 0; + FreeImage(Image); + return New; +} + +XImage *RotImage(XImage *Image){ + + XImage *New; + int w = Image->height; + int h = Image->width; + int i, j, k, shift; + int order = Image->bitmap_bit_order; + int offs = h+Image->xoffset-1; + + New = NewImage(w, h, 0, 1); + if (New == 0) + return 0; + + k = (32 - Image->xoffset) & 3; + for (i = h - 1; i && k; i--, k--) { + t32bits *sp = (t32bits *) Image->data + (offs-i)/32; + t32bits *dp = (t32bits *) (New->data+i*New->bytes_per_line); + t32bits d0 =0; + shift = (offs-i)&31; + if (order) shift = 31-shift; + for (j = 0; j < w; j++) { + t32bits t = *sp; + sp += Image->bytes_per_line/4; + d0 |= ((t >> shift) & 1); + if ((j & 31) == 31) + *dp++ = d0; + d0 <<= 1;; + } + if (j & 31) + *dp++ = d0<<(31-j); + } + for ( ; i >= 3; i-=4) { + t32bits *sp = (t32bits *) Image->data + (offs-i)/32; + t32bits *dp0 = (t32bits *) (New->data+i*New->bytes_per_line); + t32bits *dp1 = dp0 - New->bytes_per_line/4; + t32bits *dp2 = dp1 - New->bytes_per_line/4; + t32bits *dp3 = dp2 - New->bytes_per_line/4; + t32bits d0=0 , d1=0, d2 =0, d3 =0; + shift = (offs-i)&31; + if (order) shift = 28-shift; + for (j = 0; j < w; j++) { + t32bits t = *sp >> shift; + sp += Image->bytes_per_line/4; + d0 |= t & 1; t >>= 1; + d1 |= t & 1; t >>= 1; + d2 |= t & 1; t >>= 1; + d3 |= t & 1; t >>= 1; + if ((j & 31) == 31) { + if (order) { + *dp0++ = d3; + *dp1++ = d2; + *dp2++ = d1; + *dp3++ = d0; + } + else { + *dp0++ = d0; + *dp1++ = d1; + *dp2++ = d2; + *dp3++ = d3; + } + } + d0 <<= 1; d1 <<= 1; d2 <<= 1; d3 <<= 1; + } + if (j & 31) { + if (order) { + *dp0++ = d3<<(31-j); + *dp1++ = d2<<(31-j); + *dp2++ = d1<<(31-j); + *dp3++ = d0<<(31-j); + } + else { + *dp0++ = d0<<(31-j); + *dp1++ = d1<<(31-j); + *dp2++ = d2<<(31-j); + *dp3++ = d3<<(31-j); + } + } + } + for (; i >= 0; i--) { + t32bits *sp = (t32bits *) Image->data + (offs-i)/32; + t32bits *dp = (t32bits *) (New->data+i*New->bytes_per_line); + t32bits d0=0; + shift = (offs-i)&31; + if (order) shift = 31-shift; + for (j = 0; j < w; j++) { + t32bits t = *sp; + sp += Image->bytes_per_line/4; + d0 |= ((t >> shift) & 1); + if ((j & 31) == 31) + *dp++ = d0; + d0 <<= 1;; + } + if (j & 31) + *dp++ = d0<<(31-j); + } + FreeImage(Image); + return New; +} + +/* release some non-essential memory or abort */ +#define Try(n) \ + if (n && n != thispage && n->extra) { \ + FreeImage((XImage*)n->extra); \ + n->extra = 0; \ + return 1; \ + } + +static int +release(int quit) +{ + (void) quit; + + struct pagenode *pn; + + if (thispage) { + /* first consider "uninteresting" pages */ + for (pn = firstpage->next; pn; pn = pn->next) + if (pn->extra && pn != thispage && pn != thispage->prev && + pn != thispage->next && pn != lastpage) { + FreeImage(Pimage(pn)); + pn->extra = 0; + return 1; + } + Try(lastpage); + Try(firstpage); + Try(thispage->prev); + Try(thispage->next); + } + + return 0; + +} + +XImage *NewImage(int w, int h, char *data, int bit_order){ + + XImage *newimage; + /* This idea is taken from xwud/xpr. Use a fake display with the + desired bit/byte order to get the image routines initialised + correctly */ + Display fake; + + fake = *Disp; + if (data == 0) + data = xmalloc(((w + 31) & ~31) * h / 8); + fake.byte_order = ByteOrder; + fake.bitmap_unit = 32; + fake.bitmap_bit_order = bit_order; + + int returncode = -1; + while ((newimage = XCreateImage(&fake, DefaultVisual(Disp, Default_Screen), + 1, XYBitmap, 0, data, w, h, 32, 0)) == 0 ){ + + returncode = release(1); + if (returncode == 0) + break; + } + + if (returncode == 0){ + kfaxerror("Sorry","Can not allocate Memory for a new Fax Image\n"); + return 0; + } + + Memused += newimage->bytes_per_line * newimage->height; + /*printf("allocating %d bytes for %ld\n", + newimage->bytes_per_line * newimage->height, + newimage);*/ + + + return newimage; +} + +void FreeImage(XImage *Image){ + + if (Image->data){ + Memused -= Image->bytes_per_line * Image->height; +/*printf("deallocating %d bytes for %ld\n", + Image->bytes_per_line * Image->height, + Image);*/ + } + XDestroyImage(Image); +} + +#ifndef xmalloc +char * +xmalloc(unsigned int size) +{ + char *p; + + while (Memused + size > Memlimit && release(0)) + ; + while ((p = (char*) malloc(size)) == 0) + (void) release(1); + return p; +} +#endif diff --git a/kfax/viewfax.h b/kfax/viewfax.h new file mode 100644 index 00000000..92ffbd70 --- /dev/null +++ b/kfax/viewfax.h @@ -0,0 +1,27 @@ +/* + This file is part of KFAX + Copyright (c) 1999 Waldo Bastian + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 _VIEWFAX_H_ +#define _VIEWFAX_H_ + +#define MAXZOOM 4 + +int viewfaxmain(); + +#endif diff --git a/kfaxview/Makefile.am b/kfaxview/Makefile.am new file mode 100644 index 00000000..669fcd9b --- /dev/null +++ b/kfaxview/Makefile.am @@ -0,0 +1,38 @@ +INCLUDES = -I$(top_srcdir)/kviewshell \ + -I$(top_builddir)/kviewshell \ + -I$(kde_includes)/kviewshell \ + -I$(srcdir)/libkfaximage \ + -I$(top_srcdir) $(all_includes) + +SUBDIRS = libkfaximage . + +KDE_ICON = kfaxview + +METASOURCES = AUTO + +bin_PROGRAMS = kfaxview +kfaxview_SOURCES = main.cpp +kfaxview_LDFLAGS = $(all_libraries) $(KDE_RPATH) +kfaxview_LDADD = ../kviewshell/libifaces.la ../kviewshell/libkviewshell.la -lkparts + +# this is where the desktop file will go +kde_services_DATA = kfaxmultipage.desktop kfaxmultipage_tiff.desktop + +# this is where the shell's XML-GUI resource file goes +shellrcdir = $(kde_datadir)/kfaxview + +kde_module_LTLIBRARIES = kfaxviewpart.la +kfaxviewpart_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module +kfaxviewpart_la_LIBADD = -lkdeprint -lkparts $(top_builddir)/kviewshell/libkmultipage.la libkfaximage/libkfaximage.la +kfaxviewpart_la_SOURCES = faxmultipage.cpp faxrenderer.cpp + +partdir = $(kde_datadir)/kfaxview +part_DATA = ../kviewshell/kviewshell.rc + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/kfaxview.pot + +xdg_apps_DATA = kfaxview.desktop + +# The next line switches the API documentation on +include ../admin/Doxyfile.am diff --git a/kfaxview/faxmultipage.cpp b/kfaxview/faxmultipage.cpp new file mode 100644 index 00000000..bbf4e566 --- /dev/null +++ b/kfaxview/faxmultipage.cpp @@ -0,0 +1,85 @@ +/*************************************************************************** + * Copyright (C) 2005 by Stefan Kebekus * + * kebekus@kde.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 + +#include +#include + +#include "faxmultipage.h" + + + +typedef KParts::GenericFactory FaxMultiPageFactory; +K_EXPORT_COMPONENT_FACTORY(kfaxviewpart, FaxMultiPageFactory) + + +FaxMultiPage::FaxMultiPage(QWidget *parentWidget, const char *widgetName, QObject *parent, + const char *name, const QStringList&) + : KMultiPage(parentWidget, widgetName, parent, name), faxRenderer(parentWidget) +{ + /* This is kparts wizardry that cannot be understood by man. Simply + change the names to match your implementation. */ + setInstance(FaxMultiPageFactory::instance()); + faxRenderer.setName("Fax renderer"); + + setXMLFile("kfaxview.rc"); + + /* It is very important that this method is called in the + constructor. Otherwise kmultipage does not know how to render + files, and crashes may result. */ + setRenderer(&faxRenderer); +} + + +FaxMultiPage::~FaxMultiPage() +{ + ; +} + + +KAboutData* FaxMultiPage::createAboutData() +{ + /* You obviously want to change this to match your setup */ + KAboutData* about = new KAboutData("kfaxview", I18N_NOOP("KFaxView"), "0.1", + I18N_NOOP("KViewshell Fax Plugin."), + KAboutData::License_GPL, + "Stefan Kebekus", + I18N_NOOP("This program previews fax (g3) files.")); + + about->addAuthor ("Stefan Kebekus", + I18N_NOOP("Current Maintainer."), + "kebekus@kde.org", + "http://www.mi.uni-koeln.de/~kebekus"); + return about; +} + + +QStringList FaxMultiPage::fileFormats() const +{ + /* This list is used in the file selection dialog when the file is + saved */ + QStringList r; + r << i18n("*.g3|Fax (g3) file (*.g3)"); + return r; +} + + +#include "faxmultipage.moc" diff --git a/kfaxview/faxmultipage.h b/kfaxview/faxmultipage.h new file mode 100644 index 00000000..1ea8b6c5 --- /dev/null +++ b/kfaxview/faxmultipage.h @@ -0,0 +1,120 @@ +/*************************************************************************** + * Copyright (C) 2005 by Stefan Kebekus * + * kebekus@kde.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 FAXMULTIPAGE_H +#define FAXMULTIPAGE_H + +#include + +#include "kmultipage.h" +#include "faxrenderer.h" + + + +/*! \mainpage FaxMultiPage + +\section intro_sec Introduction + +FaxMultiPage is a minimal, but well-documented reference +implementation of a kviewshell plugin that can serve as a starting +point for implementations. + +\section install_sec Usage + +When FaxMultiPage and the associated files are installed, the +kviewshell program can open TIFF-Fax anf G3 fax files, i.e. files of +mime types image/fax-g3 or image/tiff. + +\section content Content + +Only the two classes that are absolutely necessary for a working +plugin are implemented. The only other file that is installed are +desktop file, which tells kviewshell to use the plugin. + +- FaxMultiPage, an implementation of a KMultiPage. In a larger +application, this class would contain the GUI elements that the plugin +adds to the GUI of the kviewshell. For viewing FAXes, no special GUI +elements are required, and this plugin does only the minimal +initialization required. + +- FaxRenderer, an implementation of a DocumentRenderer. This class is +responsible for document loading and rendering. + +- kfaxmultipage.desktop and kfaxmultipage_tiff.desktop are desktop +entry files that associate the plugin wit image/fax-g3 or image/tiff +mime-types. Without these files installed, the file dialog in +kviewshell would not show FAX files, and the command line "kvieshell +test.g3" would fail with an error dialog "No plugin for image/fax-g3 +files installed". +*/ + + + + +/*! \brief Well-documented minimal implementation of a KMultiPage + +This class provides a well-documented reference implementation of a +KMultiPage, suitable as a starting point for a real-world +implementation. In a larger application, this class would contain the +GUI elements that the plugin adds to the GUI of the kviewshell. For +viewing FAXes, no special GUI elements are required, and this plugin +does only the minimal initialization required. +*/ + +class FaxMultiPage : public KMultiPage +{ + Q_OBJECT + +public: + /** Constructor + + The constructor needs to initialize several members of the + kmultipage. Please have a look at the constructor's source code to + see how to adjust this for your implementation. + */ + FaxMultiPage(QWidget *parentWidget, const char *widgetName, QObject *parent, + const char *name, const QStringList& args = QStringList()); + + /** Destructor + + This destructor does nothing. + */ + virtual ~FaxMultiPage(); + + /** List of file formats for file saving + + This method returns the list of supported file formats for saving + the file. + */ + virtual QStringList fileFormats() const; + + /** Author information + + This member returns a structure that contains information about the + authors of the implementation + */ + static KAboutData* createAboutData(); + + private: + /** This member holds the renderer which is used by the demo implementation */ + FaxRenderer faxRenderer; +}; + +#endif diff --git a/kfaxview/faxrenderer.cpp b/kfaxview/faxrenderer.cpp new file mode 100644 index 00000000..ec18d431 --- /dev/null +++ b/kfaxview/faxrenderer.cpp @@ -0,0 +1,204 @@ +/*************************************************************************** + * Copyright (C) 2005 by Stefan Kebekus * + * kebekus@kde.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 + +#include +#include +#include +#include +#include + +#include "documentWidget.h" +#include "faxrenderer.h" +#include "faxmultipage.h" + +//#define KF_DEBUG + +FaxRenderer::FaxRenderer(QWidget* par) + : DocumentRenderer(par) +{ +#ifdef KF_DEBUG + kdError() << "FaxRenderer( parent=" << par << " )" << endl; +#endif +} + + + +FaxRenderer::~FaxRenderer() +{ +#ifdef KF_DEBUG + kdDebug() << "~FaxRenderer" << endl; +#endif + + // Wait for all access to this documentRenderer to finish + mutex.lock(); + mutex.unlock(); +} + + +void FaxRenderer::drawPage(double resolution, RenderedDocumentPage* page) +{ +#ifdef KF_DEBUG + kdDebug() << "FaxRenderer::drawPage(documentPage*) called, page number " << page->getPageNumber() << endl; +#endif + + // Paranoid safety checks + if (page == 0) { + kdError() << "FaxRenderer::drawPage(documentPage*) called with argument == 0" << endl; + return; + } + if (page->getPageNumber() == 0) { + kdError() << "FaxRenderer::drawPage(documentPage*) called for a documentPage with page number 0" << endl; + return; + } + + // Wait for all access to this documentRenderer to finish + mutex.lock(); + + // more paranoid safety checks + if (page->getPageNumber() > numPages) { + kdError() << "FaxRenderer::drawPage(documentPage*) called for a documentPage with page number " << page->getPageNumber() + << " but the current fax file has only " << numPages << " pages." << endl; + mutex.unlock(); + return; + } + + QImage img = fax.page(page->getPageNumber() - 1); + + SimplePageSize psize = pageSizes[page->getPageNumber() - 1]; + if (psize.isValid()) { + QPainter *foreGroundPaint = page->getPainter(); + if (foreGroundPaint != 0) { + // Compute an image for the page. + + // WARNING: It may be tempting to compute the image size in + // pixel, using page->height() and page->width(). DON'T DO + // THAT. KViewShell uses transformations e.g. to rotate the + // page, and sets the argument 'resolution' accordingly. Similar + // problems occur if KViewShell required a shrunken version of + // the page, e.g. to print multiple pages on one sheet of paper. + + int width_in_pixel = qRound(resolution * psize.width().getLength_in_inch()); + int height_in_pixel = qRound(resolution * psize.height().getLength_in_inch()); + + img = img.smoothScale(width_in_pixel, height_in_pixel); + foreGroundPaint->drawImage(0, 0, img); + page->returnPainter(foreGroundPaint); + } + } else + kdError() << "FaxRenderer::drawPage() called, but page size for page " << page->getPageNumber() << " is invalid." << endl; + + // To indicate that the page was drawn, we set the appropriate flas in the page structure + page->isEmpty = false; + + mutex.unlock(); +} + + +bool FaxRenderer::setFile(const QString &fname, const KURL &) +{ +#ifdef KF_DEBUG + kdDebug() << "FaxRenderer::setFile(" << fname << ") called" << endl; +#endif + + // Wait for all access to this documentRenderer to finish + mutex.lock(); + + // If fname is the empty string, then this means: "close". + if (fname.isEmpty()) { + kdDebug() << "FaxRenderer::setFile( ... ) called with empty filename. Closing the file." << endl; + mutex.unlock(); + return true; + } + + // Paranoid saftey checks: make sure the file actually exists, and + // that it is a file, not a directory. Otherwise, show an error + // message and exit.. + QFileInfo fi(fname); + QString filename = fi.absFilePath(); + if (!fi.exists() || fi.isDir()) { + KMessageBox::error( parentWidget, + i18n("File error. The specified file '%1' does not exist.").arg(filename), + i18n("File Error")); + // the return value 'false' indicates that this operation was not successful. + mutex.unlock(); + return false; + } + + // Now we assume that the file is fine and load the file into the + // fax member. We abort on error and give an error message. + bool ok = fax.loadImage(filename); + + // It can happen that fax.loadImage() returns with 'ok == true', but + // still the file could NOT be loaded. This happens, e.g. for TIFF + // file that do NOT contain FAX, but other image formats. We handle + // that case here also. + if ( (!ok) || (fax.numPages() == 0)) { + // Unfortunately, it can happen that fax.loadImage() fails WITHOUT + // leaving an error message in fax.errorString(). We try to handle + // this case gracefully. + if (fax.errorString().isEmpty()) + KMessageBox::error( parentWidget, + i18n("File error. The specified file '%1' could not be loaded.").arg(filename), + i18n("File Error")); + else + KMessageBox::detailedError( parentWidget, + i18n("File error. The specified file '%1' could not be loaded.").arg(filename), + fax.errorString(), + i18n("File Error")); + clear(); + mutex.unlock(); + return false; + } + + // Set the number of pages page sizes + numPages = fax.numPages(); + + // Set the page size for the first page in the pageSizes array. + // The rest of the page sizes will be calculated on demand by the drawPage function. + pageSizes.resize(numPages); + Length w,h; + + if (numPages != 0) { + for(Q_UINT16 pg=0; pg < numPages; pg++) { + QSize pageSize = fax.page_size(pg); + QPoint dpi = fax.page_dpi(pg); + double dpix = dpi.x(); + double dpiy = dpi.y(); + + if (dpix*dpiy < 1.0) { + kdError() << "File invalid resolutions, dpi x = " << dpix << ", dpi y = " << dpiy << ". This information will be ignored and 75 DPI assumed." << endl; + dpix = dpiy = 75.0; + } + + w.setLength_in_inch(pageSize.width() / dpix); + h.setLength_in_inch(pageSize.height() / dpiy); + pageSizes[pg].setPageSize(w, h); + } + } + + // the return value 'true' indicates that this operation was not successful. + mutex.unlock(); + return true; +} + + +#include "faxrenderer.moc" diff --git a/kfaxview/faxrenderer.h b/kfaxview/faxrenderer.h new file mode 100644 index 00000000..d2b37657 --- /dev/null +++ b/kfaxview/faxrenderer.h @@ -0,0 +1,90 @@ +/*************************************************************************** + * Copyright (C) 2005 by Stefan Kebekus * + * kebekus@kde.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 _FAXRENDERER_H_ +#define _FAXRENDERER_H_ + + +#include "documentRenderer.h" +#include "kfaximage.h" + +class documentPage; + +/*! \brief Well-documented minimal implementation of a documentRenderer for reading FAX files + +This class provides a well-documented reference implementation of a +documentRenderer, suitable as a starting point for a real-world +implementation. This class is responsible for document loading and +rendering. Apart from the constructor and the descructor, it +implements only the necessary methods setFile() and drawPage(). +*/ + +class FaxRenderer : public DocumentRenderer +{ + Q_OBJECT + +public: + /** Default constructor + + This constructor simply prints a message (if debugging is + enabled) and calls the default constructor. + */ + FaxRenderer(QWidget* parent); + + /** Destructor + + The destructor simpley prints a message if debugging is + enabled. It uses the mutex to ensure that this class is not + destructed while another thread is currently using it. + */ + ~FaxRenderer(); + + /** Opening a file + + This implementation does the necessary consistency checks and + complains, e.g. if the file does not exist. It then uses the + member 'fax' to load the fax file and initializes the + appropriate data structures. The code for loading and rendering + is contained in the class "KFaxImage", to keep this reference + implementation short. + + @param fname the name of the file that should be opened. + */ + virtual bool setFile(const QString& fname, const KURL &); + + /** Rendering a page + + This implementation first checks if the arguments are in a + reasonable range, and error messages are printed if this is not + so. Secondly, the page is rendered by the KFaxImage class and + the drawn. + + @param res resolution at which drawing should take place + + @param page pointer to a page structur on which we should draw + */ + void drawPage(double res, RenderedDocumentPage* page); + +private: + /** This class holds the fax file */ + KFaxImage fax; +}; + +#endif diff --git a/kfaxview/hi16-app-kfaxview.png b/kfaxview/hi16-app-kfaxview.png new file mode 100644 index 00000000..bb676f8b Binary files /dev/null and b/kfaxview/hi16-app-kfaxview.png differ diff --git a/kfaxview/hi22-app-kfaxview.png b/kfaxview/hi22-app-kfaxview.png new file mode 100644 index 00000000..90fc64b0 Binary files /dev/null and b/kfaxview/hi22-app-kfaxview.png differ diff --git a/kfaxview/hi32-app-kfaxview.png b/kfaxview/hi32-app-kfaxview.png new file mode 100644 index 00000000..7330eb41 Binary files /dev/null and b/kfaxview/hi32-app-kfaxview.png differ diff --git a/kfaxview/hi48-app-kfaxview.png b/kfaxview/hi48-app-kfaxview.png new file mode 100644 index 00000000..3f58c369 Binary files /dev/null and b/kfaxview/hi48-app-kfaxview.png differ diff --git a/kfaxview/hisc-app-kfaxview.svgz b/kfaxview/hisc-app-kfaxview.svgz new file mode 100644 index 00000000..f46fd440 Binary files /dev/null and b/kfaxview/hisc-app-kfaxview.svgz differ diff --git a/kfaxview/kfaxmultipage.desktop b/kfaxview/kfaxmultipage.desktop new file mode 100644 index 00000000..1bfc9acc --- /dev/null +++ b/kfaxview/kfaxmultipage.desktop @@ -0,0 +1,60 @@ +[Desktop Entry] +Name=kfaxview +Name[hu]=KFaxView +Name[ja]=KfaxView +Name[nb]=Kfaxview +Name[ne]=केडीई फ्याक्स दृश्य +Name[ro]=KFaxiView +Name[sv]=Kfaxview +Name[zh_CN]=KFaxView +Icon=kfaxview +Type=Service +Comment=KViewShell plugin for fax files +Comment[bg]=Приставка за факс файлове +Comment[br]=Lugent KViewShell evit ar restroù faks +Comment[bs]=KViewShell dodatak za fax datoteke +Comment[ca]=Connector pel KViewShell per a fitxers de fax +Comment[cs]=KViewShell modul pro faxové soubory +Comment[da]=Kviewshell-plugin for telefaxfiler +Comment[de]=Ein Modul für KViewShell zum Betrachten von Faxdateien +Comment[el]=Πρόσθετο του KViewShell για αρχεία φαξ +Comment[eo]=KViewShell-kromaĵo for faksdosieroj +Comment[es]=Extensión KViewShell para archivos de fax +Comment[et]=KView faksifailide plugin +Comment[eu]=Fax fitxategientzatko KViewShell-en plugina +Comment[fa]=وصلۀ KViewShell برای پرونده‌های دورنگار +Comment[fi]=KViewShell sovelma faksitiedostoille +Comment[fr]=Module KViewShell pour les fichiers de fax +Comment[gl]=Extensión de KViewShell para ficheiros de fax +Comment[hu]=KViewShell-modul faxfájlokhoz +Comment[is]=KViewShell íforrit fyrir faxskrár +Comment[it]=Plugin KViewShell per file di fax +Comment[ja]=ファクスファイル用の KViewShell プラグイン +Comment[kk]=Факс файлдарын қарау плагин модулі +Comment[km]=កម្មវិធី​ជំនួយ KViewShell សម្រាប់​ឯកសារ​ទូរសារ +Comment[lt]=KViewShell priedas fakso byloms +Comment[ms]=Plugin KViewShell untuk fail faks +Comment[nb]=KViewShell programtillegg for faksfiler +Comment[nds]="KViewShell"-Moduul för Faxdateien +Comment[ne]=फ्याक्स फाइलका लागि केडीई दृश्य शेल प्लगइन +Comment[nl]=KViewShell-plugin voor faxbestanden +Comment[nn]=KViewShell-programtillegg for faksfiler +Comment[pl]=Wtyczka KViewShell do plików faksów +Comment[pt]='Plugin' do KViewShell para ficheiros de Fax +Comment[pt_BR]=Plugin KViewShell para arquivos de fax +Comment[ru]=Компонент просмотра факсов +Comment[sk]=KViewShell modul pre faxové súbory +Comment[sl]=Vstavek za KViewShell za fakse +Comment[sr]=KViewShell-ов прикључак за факс фајлове +Comment[sr@Latn]=KViewShell-ov priključak za faks fajlove +Comment[sv]=Kviewshell-insticksprogram för telefaxfiler +Comment[th]=ปลั๊กอินสำหรับแสดงแฟ้มโทรสารของ KViewShell +Comment[tr]=Faks dosyaları için KViewShell eklentisi +Comment[uk]=Втулок перегляду файлів факсів для KViewShell +Comment[zh_CN]=传真文件的 KViewShell 插件 +Comment[zh_HK]=傳真檔的 KViewShell 插件 +Comment[zh_TW]=KViewShell 傳真檔外掛程式 +ServiceTypes=KViewShell/MultiPage +X-KDE-MimeTypes=image/fax-g3 +X-KDE-Library=kfaxviewpart +X-KDE-MultiPageVersion=2 diff --git a/kfaxview/kfaxmultipage_tiff.desktop b/kfaxview/kfaxmultipage_tiff.desktop new file mode 100644 index 00000000..a1b33913 --- /dev/null +++ b/kfaxview/kfaxmultipage_tiff.desktop @@ -0,0 +1,57 @@ +[Desktop Entry] +Name=kfaxview_tiff +Name[da]=Kfaxview TIFF +Name[ne]=केडीई फ्याक्स दृश्य टिफ +Name[sv]=Kfaxview TIFF +Name[zh_CN]=KFaxView_tiff +Icon=kfaxview +Type=Service +Comment=KViewShell plugin for fax files +Comment[bg]=Приставка за факс файлове +Comment[br]=Lugent KViewShell evit ar restroù faks +Comment[bs]=KViewShell dodatak za fax datoteke +Comment[ca]=Connector pel KViewShell per a fitxers de fax +Comment[cs]=KViewShell modul pro faxové soubory +Comment[da]=Kviewshell-plugin for telefaxfiler +Comment[de]=Ein Modul für KViewShell zum Betrachten von Faxdateien +Comment[el]=Πρόσθετο του KViewShell για αρχεία φαξ +Comment[eo]=KViewShell-kromaĵo for faksdosieroj +Comment[es]=Extensión KViewShell para archivos de fax +Comment[et]=KView faksifailide plugin +Comment[eu]=Fax fitxategientzatko KViewShell-en plugina +Comment[fa]=وصلۀ KViewShell برای پرونده‌های دورنگار +Comment[fi]=KViewShell sovelma faksitiedostoille +Comment[fr]=Module KViewShell pour les fichiers de fax +Comment[gl]=Extensión de KViewShell para ficheiros de fax +Comment[hu]=KViewShell-modul faxfájlokhoz +Comment[is]=KViewShell íforrit fyrir faxskrár +Comment[it]=Plugin KViewShell per file di fax +Comment[ja]=ファクスファイル用の KViewShell プラグイン +Comment[kk]=Факс файлдарын қарау плагин модулі +Comment[km]=កម្មវិធី​ជំនួយ KViewShell សម្រាប់​ឯកសារ​ទូរសារ +Comment[lt]=KViewShell priedas fakso byloms +Comment[ms]=Plugin KViewShell untuk fail faks +Comment[nb]=KViewShell programtillegg for faksfiler +Comment[nds]="KViewShell"-Moduul för Faxdateien +Comment[ne]=फ्याक्स फाइलका लागि केडीई दृश्य शेल प्लगइन +Comment[nl]=KViewShell-plugin voor faxbestanden +Comment[nn]=KViewShell-programtillegg for faksfiler +Comment[pl]=Wtyczka KViewShell do plików faksów +Comment[pt]='Plugin' do KViewShell para ficheiros de Fax +Comment[pt_BR]=Plugin KViewShell para arquivos de fax +Comment[ru]=Компонент просмотра факсов +Comment[sk]=KViewShell modul pre faxové súbory +Comment[sl]=Vstavek za KViewShell za fakse +Comment[sr]=KViewShell-ов прикључак за факс фајлове +Comment[sr@Latn]=KViewShell-ov priključak za faks fajlove +Comment[sv]=Kviewshell-insticksprogram för telefaxfiler +Comment[th]=ปลั๊กอินสำหรับแสดงแฟ้มโทรสารของ KViewShell +Comment[tr]=Faks dosyaları için KViewShell eklentisi +Comment[uk]=Втулок перегляду файлів факсів для KViewShell +Comment[zh_CN]=传真文件的 KViewShell 插件 +Comment[zh_HK]=傳真檔的 KViewShell 插件 +Comment[zh_TW]=KViewShell 傳真檔外掛程式 +ServiceTypes=KViewShell/MultiPage +X-KDE-MimeTypes=image/tiff +X-KDE-Library=kfaxviewpart +X-KDE-MultiPageVersion=2 diff --git a/kfaxview/kfaxview.desktop b/kfaxview/kfaxview.desktop new file mode 100644 index 00000000..4dc74ff1 --- /dev/null +++ b/kfaxview/kfaxview.desktop @@ -0,0 +1,82 @@ +[Desktop Entry] +GenericName=Fax Viewer +GenericName[af]=Faks Aansig +GenericName[ar]=عارض الفاكس +GenericName[bg]=Преглед на факсове +GenericName[br]=Gweler faks +GenericName[bs]=Preglednik faxova +GenericName[ca]=Visualitzador de fax +GenericName[cs]=Prohlížeč faxů +GenericName[cy]=Gwelydd Ffacs +GenericName[da]=Fax-fremviser +GenericName[de]=Faxbetrachter +GenericName[el]=Προβολέας φαξ +GenericName[eo]=Faksrigardilo +GenericName[es]=Visor de faxes +GenericName[et]=Fakside vaataja +GenericName[eu]=Fax ikustailua +GenericName[fa]=مشاهده‌گر دورنگار +GenericName[fi]=Faksinäytin +GenericName[fr]=Afficheur de fax +GenericName[gl]=Visor de fax +GenericName[he]=מציג פקסים +GenericName[hi]=फ़ैक्स प्रदर्शक +GenericName[hr]=Preglednik faksova +GenericName[hu]=Faxnézegető +GenericName[is]=Fax sjá +GenericName[it]=Visore di fax +GenericName[ja]=ファクスビューア +GenericName[kk]=Факсты қарау +GenericName[km]=កម្មវិធី​មើល​ទូរសារ +GenericName[lt]=Faksų žiūriklis +GenericName[lv]=Faksu Skatītājs +GenericName[ms]=Pemapar Faks +GenericName[nb]=Faksfremviser +GenericName[nds]=Faxkieker +GenericName[ne]=फ्याक्स द्रष्टा +GenericName[nl]=Faxweergaveprogramma +GenericName[nn]=Faksvisar +GenericName[pa]=ਫੈਕਸ ਦਰਸ਼ਕ +GenericName[pl]=Przeglądarka faksów +GenericName[pt]=Visualizador de Faxes +GenericName[pt_BR]=Visualizador de Faxes +GenericName[ro]=Vizualizor FAX +GenericName[ru]=Просмотр факсов +GenericName[se]=Fáksačájeheaddji +GenericName[sk]=Prehliadač faxov +GenericName[sl]=Pregledovalnik faksov +GenericName[sr]=Приказивач факсова +GenericName[sr@Latn]=Prikazivač faksova +GenericName[sv]=Faxvisare +GenericName[ta]=ஃபாக்ஸ் காட்சி +GenericName[tg]=Хондани факс +GenericName[th]=เครื่องมือแสดงโทรสารของ KDE +GenericName[tr]=Faks Görüntüleyici +GenericName[uk]=Переглядач факсів +GenericName[uz]=Faks koʻruvchi +GenericName[uz@cyrillic]=Факс кўрувчи +GenericName[ven]=Muvhoni wa Fekisi +GenericName[wa]=Håyneu di facs +GenericName[xh]=Umboniseli Wefax +GenericName[zh_CN]=传真查看器 +GenericName[zh_HK]=傳真檢視器 +GenericName[zh_TW]=傳真檢視器 +GenericName[zu]=Umbonisi wefax +Name=KFaxView +Name[nb]=Kfaxview +Name[ne]=केडीई फ्याक्स दृश्य +Name[sv]=Kfaxview +Name[zh_TW]=KFaxView 傳真檢視 +MimeType=image/fax-g3; +InitialPreference=6 +Exec=kfaxview %f +Icon=kfaxview +Path= +Type=Application +Terminal=false +ServiceTypes=Browser/View +X-KDE-Library=kviewerpart +X-KDE-BrowserView-Args=fax +DocPath=kfaxview/index.html +X-KDE-StartupNotify=true +Categories=Qt;KDE;Graphics; diff --git a/kfaxview/libkfaximage/Makefile.am b/kfaxview/libkfaximage/Makefile.am new file mode 100644 index 00000000..616afb3c --- /dev/null +++ b/kfaxview/libkfaximage/Makefile.am @@ -0,0 +1,14 @@ +INCLUDES = -I$(top_srcdir) $(all_includes) + +lib_LTLIBRARIES = libkfaximage.la +libkfaximage_la_LDFLAGS = $(all_libraries) -no-undefined -avoid-version +libkfaximage_la_LIBADD = $(LIB_KDECORE) +libkfaximage_la_SOURCES = kfaximage.cpp faxexpand.cpp faxinit.cpp + +include_HEADERS = kfaximage.h +noinst_HEADERS = faxexpand.h + +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) $(libkfaximage_la_SOURCES) -o $(podir)/libkfaximgage.pot diff --git a/kfaxview/libkfaximage/faxexpand.cpp b/kfaxview/libkfaximage/faxexpand.cpp new file mode 100644 index 00000000..9c4b4082 --- /dev/null +++ b/kfaxview/libkfaximage/faxexpand.cpp @@ -0,0 +1,745 @@ +/* Expand one page of fax data + Copyright (C) 1990, 1995 Frank D. Cringle. + +This file is part of viewfax - g3/g4 fax processing software. + +viewfax 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 + +#include +#include +#include + +#include + +#include "faxexpand.h" + +//Uncomment this for verbose debug output +//#define DEBUG_FAX +#define verbose false + +pagenode::pagenode() +{ +} + +/* Note that NeedBits() only works for n <= 16 */ +#define NeedBits(n) do { \ + if (BitsAvail < (n)) { \ + BitAcc |= *sp++ << BitsAvail; \ + BitsAvail += 16; \ + } \ +} while (0) +#define GetBits(n) (BitAcc & ((1<<(n))-1)) +#define ClrBits(n) do { \ + BitAcc >>= (n); \ + BitsAvail -= (n); \ +} while (0) + +#ifdef DEBUG_FAX +#define DEBUG_SHOW putchar(BitAcc & (1 << t) ? '1' : '0') +#define LOOKUP(wid,tab) do { \ + int t; \ + NeedBits(wid); \ + TabEnt = tab + GetBits(wid); \ + printf("%08lX/%d: %s%5d\t", BitAcc, BitsAvail, \ + StateNames[TabEnt->State], TabEnt->Param); \ + for (t = 0; t < TabEnt->Width; t++) \ + DEBUG_SHOW; \ + putchar('\n'); \ + fflush(stdout); \ + ClrBits(TabEnt->Width); \ +} while (0) + +#define SETVAL(x) do { \ + *pa++ = RunLength + (x); \ + printf("SETVAL: %d\t%d\n", RunLength + (x), a0); \ + a0 += x; \ + RunLength = 0; \ +} while (0) + +const char *StateNames[] = { + "Null ", + "Pass ", + "Horiz ", + "V0 ", + "VR ", + "VL ", + "Ext ", + "TermW ", + "TermB ", + "MakeUpW", + "MakeUpB", + "MakeUp ", + "EOL ", +}; + +#else +#define LOOKUP(wid,tab) do { \ + NeedBits(wid); \ + TabEnt = tab + GetBits(wid); \ + ClrBits(TabEnt->Width); \ +} while (0) + +#define SETVAL(x) do { \ + *pa++ = RunLength + (x); \ + a0 += x; \ + RunLength = 0; \ +} while (0) +#endif + +#define dumpruns(runs) do { \ + printf("-------------------- %d\n", LineNum); \ + for (pa = runs, a0 = 0; a0 < lastx; a0 += *pa++) \ + printf("%4d %d\n", a0, *pa); \ +} while (0) + +#define EndOfData(pn) (sp >= pn->data + pn->length/sizeof(*pn->data)) + +/* This macro handles coding errors in G3 data. + We redefine it below for the G4 case */ +#define SKIP_EOL do { \ + while (!EndOfData(pn)) { \ + NeedBits(11); \ + if (GetBits(11) == 0) \ + break; \ + ClrBits(1); \ + } \ + ClrBits(11); \ + goto EOL; \ +} while (0) +#define eol2lab EOL2: + +/* the line expanders are written as macros so that they can be reused + (twice each) but still have direct access to the local variables of + the "calling" function */ +#define expand1d() do { \ + while (a0 < lastx) { \ + int done = 0; \ + while (!done) { /* white first */ \ + LOOKUP(12, WhiteTable); \ + switch (TabEnt->State) { \ + case S_EOL: \ + EOLcnt = 1; \ + goto EOL; \ + case S_TermW: \ + SETVAL(TabEnt->Param); \ + done = 1; \ + break; \ + case S_MakeUpW: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + case S_Ext: \ + unexpected("Extension code", LineNum); \ + SKIP_EOL; \ + break; \ + default: \ + unexpected("WhiteTable", LineNum); \ + SKIP_EOL; \ + break; \ + } \ + } \ + done = a0 >= lastx; \ + while (!done) { /* then black */ \ + LOOKUP(13, BlackTable); \ + switch (TabEnt->State) { \ + case S_EOL: \ + EOLcnt = 1; \ + goto EOL; \ + case S_TermB: \ + SETVAL(TabEnt->Param); \ + done = 1; \ + break; \ + case S_MakeUpB: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + case S_Ext: \ + unexpected("Extension code", LineNum); \ + SKIP_EOL; \ + break; \ + default: \ + unexpected("BlackTable", LineNum); \ + SKIP_EOL; \ + break; \ + } \ + } \ + } \ + EOL: ; \ +} while (0) + +#define CHECK_b1 do { \ + if (pa != thisrun) while (b1 <= a0 && b1 < lastx) { \ + b1 += pb[0] + pb[1]; \ + pb += 2; \ + } \ +} while (0) + +#define expand2d(eolab) do { \ + while (a0 < lastx) { \ + LOOKUP(7, MainTable); \ + switch (TabEnt->State) { \ + case S_Pass: \ + CHECK_b1; \ + b1 += *pb++; \ + RunLength += b1 - a0; \ + a0 = b1; \ + b1 += *pb++; \ + break; \ + case S_Horiz: \ + if ((pa-run0)&1) { \ + int done = 0; \ + while (!done) { /* black first */ \ + LOOKUP(13, BlackTable); \ + switch (TabEnt->State) { \ + case S_TermB: \ + SETVAL(TabEnt->Param); \ + done = 1; \ + break; \ + case S_MakeUpB: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + unexpected("BlackTable", LineNum); \ + SKIP_EOL; \ + break; \ + } \ + } \ + done = 0; \ + while (!done) { /* then white */ \ + LOOKUP(12, WhiteTable); \ + switch (TabEnt->State) { \ + case S_TermW: \ + SETVAL(TabEnt->Param); \ + done = 1; \ + break; \ + case S_MakeUpW: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + unexpected("WhiteTable", LineNum); \ + SKIP_EOL; \ + break; \ + } \ + } \ + } \ + else { \ + int done = 0; \ + while (!done) { /* white first */ \ + LOOKUP(12, WhiteTable); \ + switch (TabEnt->State) { \ + case S_TermW: \ + SETVAL(TabEnt->Param); \ + done = 1; \ + break; \ + case S_MakeUpW: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + unexpected("WhiteTable", LineNum); \ + SKIP_EOL; \ + break; \ + } \ + } \ + done = 0; \ + while (!done) { /* then black */ \ + LOOKUP(13, BlackTable); \ + switch (TabEnt->State) { \ + case S_TermB: \ + SETVAL(TabEnt->Param); \ + done = 1; \ + break; \ + case S_MakeUpB: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + unexpected("BlackTable", LineNum); \ + SKIP_EOL; \ + break; \ + } \ + } \ + } \ + CHECK_b1; \ + break; \ + case S_V0: \ + CHECK_b1; \ + SETVAL(b1 - a0); \ + b1 += *pb++; \ + break; \ + case S_VR: \ + CHECK_b1; \ + SETVAL(b1 - a0 + TabEnt->Param); \ + b1 += *pb++; \ + break; \ + case S_VL: \ + CHECK_b1; \ + SETVAL(b1 - a0 - TabEnt->Param); \ + b1 -= *--pb; \ + break; \ + case S_Ext: \ + *pa++ = lastx - a0; \ + if (verbose) \ + kdDebug() << "Line " << LineNum << ": extension code\n";\ + SKIP_EOL; \ + break; \ + case S_EOL: \ + *pa++ = lastx - a0; \ + NeedBits(4); \ + if (GetBits(4) && verbose) /* already seen 7 zeros */ \ + kdDebug() << "Line " << LineNum << ": Bad EOL\n"; \ + ClrBits(4); \ + EOLcnt = 1; \ + goto eolab; \ + break; \ + default: \ + unexpected("MainTable", LineNum); \ + SKIP_EOL; \ + break; \ + } \ + } \ + if (RunLength) { \ + if (RunLength + a0 < lastx) { \ + /* expect a final V0 */ \ + NeedBits(1); \ + if (!GetBits(1)) { \ + unexpected("MainTable", LineNum); \ + SKIP_EOL; \ + } \ + ClrBits(1); \ + } \ + SETVAL(0); \ + } \ + eol2lab ; \ +} while (0) + +static void +unexpected(const char *what, int LineNum) +{ + if (verbose) + kdError() << "Line " << LineNum << ": Unexpected state in " + << what << endl; +} + +/* Expand tiff modified huffman data (g3-1d without EOLs) */ +void +MHexpand(struct pagenode *pn, drawfunc df) +{ + int a0; /* reference element */ + int lastx; /* copy line width to register */ + t32bits BitAcc; /* bit accumulator */ + int BitsAvail; /* # valid bits in BitAcc */ + int RunLength; /* Length of current run */ + t16bits *sp; /* pointer into compressed data */ + pixnum *pa; /* pointer into new line */ + int EOLcnt; /* number of consecutive EOLs */ + int LineNum; /* line number */ + pixnum *runs; /* list of run lengths */ + struct tabent *TabEnt; + + sp = pn->data; + BitAcc = 0; + BitsAvail = 0; + lastx = pn->size.width(); + runs = (pixnum *) malloc(lastx * sizeof(pixnum)); + for (LineNum = 0; LineNum < pn->rowsperstrip; ) { +#ifdef DEBUG_FAX + printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %d\n", LineNum); + fflush(stdout); +#endif + RunLength = 0; + pa = runs; + a0 = 0; + EOLcnt = 0; + if (BitsAvail & 7) /* skip to byte boundary */ + ClrBits(BitsAvail & 7); + expand1d(); + if (RunLength) + SETVAL(0); + if (a0 != lastx) { + if (verbose) + kdWarning() << "Line " << LineNum << ": length is " + << a0 << " (expected "<< lastx << ")\n"; + while (a0 > lastx) + a0 -= *--pa; + if (a0 < lastx) { + if ((pa - runs) & 1) + SETVAL(0); + SETVAL(lastx - a0); + } + } + (*df)(runs, LineNum++, pn); + } + free(runs); +} + +/* Expand group-3 1-dimensional data */ +void +g31expand(struct pagenode *pn, drawfunc df) +{ + int a0; /* reference element */ + int lastx; /* copy line width to register */ + t32bits BitAcc; /* bit accumulator */ + int BitsAvail; /* # valid bits in BitAcc */ + int RunLength; /* Length of current run */ + t16bits *sp; /* pointer into compressed data */ + pixnum *pa; /* pointer into new line */ + int EOLcnt; /* number of consecutive EOLs */ + int LineNum; /* line number */ + pixnum *runs; /* list of run lengths */ + struct tabent *TabEnt; + + sp = pn->data; + BitAcc = 0; + BitsAvail = 0; + lastx = pn->size.width(); + runs = (pixnum *) malloc(lastx * sizeof(pixnum)); + EOLcnt = 0; + for (LineNum = 0; LineNum < pn->rowsperstrip; ) { +#ifdef DEBUG_FAX + printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %d\n", LineNum); + fflush(stdout); +#endif + if (EOLcnt == 0) + while (!EndOfData(pn)) { + /* skip over garbage after a coding error */ + NeedBits(11); + if (GetBits(11) == 0) + break; + ClrBits(1); + } + for (EOLcnt = 1; !EndOfData(pn); EOLcnt++) { + /* we have seen 11 zeros, which implies EOL, + skip possible fill bits too */ + while (1) { + NeedBits(8); + if (GetBits(8)) + break; + ClrBits(8); + } + while (GetBits(1) == 0) + ClrBits(1); + ClrBits(1); /* the eol flag */ + NeedBits(11); + if (GetBits(11)) + break; + ClrBits(11); + } + if (EOLcnt > 1 && EOLcnt != 6 && verbose) + kdError() << "Line " << LineNum << ": bad RTC (" << EOLcnt << " EOLs)\n"; + if (EOLcnt >= 6 || EndOfData(pn)) { + free(runs); + return; + } + RunLength = 0; + pa = runs; + a0 = 0; + EOLcnt = 0; + expand1d(); + if (RunLength) + SETVAL(0); + if (a0 != lastx) { + if (verbose) + kdWarning() << "Line " << LineNum << ": length is " + << a0 << " (expected "<< lastx << ")\n"; + while (a0 > lastx) + a0 -= *--pa; + if (a0 < lastx) { + if ((pa - runs) & 1) + SETVAL(0); + SETVAL(lastx - a0); + } + } + (*df)(runs, LineNum++, pn); + } + free(runs); +} + +/* Expand group-3 2-dimensional data */ +void +g32expand(struct pagenode *pn, drawfunc df) +{ + int RunLength; /* Length of current run */ + int a0; /* reference element */ + int b1; /* next change on previous line */ + int lastx = pn->size.width();/* copy line width to register */ + pixnum *run0, *run1; /* run length arrays */ + pixnum *thisrun, *pa, *pb; /* pointers into runs */ + t16bits *sp; /* pointer into compressed data */ + t32bits BitAcc; /* bit accumulator */ + int BitsAvail; /* # valid bits in BitAcc */ + int EOLcnt; /* number of consecutive EOLs */ + int refline = 0; /* 1D encoded reference line */ + int LineNum; /* line number */ + struct tabent *TabEnt; + + sp = pn->data; + BitAcc = 0; + BitsAvail = 0; + /* allocate space for 2 runlength arrays */ + run0 = (pixnum *) malloc(2 * ((lastx+5)&~1) * sizeof(pixnum)); + run1 = run0 + ((lastx+5)&~1); + run1[0] = lastx; + run1[1] = 0; + EOLcnt = 0; + for (LineNum = 0; LineNum < pn->rowsperstrip; ) { +#ifdef DEBUG_FAX + printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %d\n", LineNum); + fflush(stdout); +#endif + if (EOLcnt == 0) + while (!EndOfData(pn)) { + /* skip over garbage after a coding error */ + NeedBits(11); + if (GetBits(11) == 0) + break; + ClrBits(1); + } + for (EOLcnt = 1; !EndOfData(pn); EOLcnt++) { + /* we have seen 11 zeros, which implies EOL, + skip possible fill bits too */ + while (1) { + NeedBits(8); + if (GetBits(8)) + break; + ClrBits(8); + } + while (GetBits(1) == 0) + ClrBits(1); + ClrBits(1); /* the eol flag */ + NeedBits(12); + refline = GetBits(1); /* 1D / 2D flag */ + ClrBits(1); + if (GetBits(11)) + break; + ClrBits(11); + } + if (EOLcnt > 1 && EOLcnt != 6 && verbose) + kdError() << "Line " << LineNum << ": bad RTC (" << EOLcnt << " EOLs)\n"; + if (EOLcnt >= 6 || EndOfData(pn)) { + free(run0); + return; + } + if (LineNum == 0 && refline == 0 && verbose) + kdDebug() << "First line is 2-D encoded\n"; + RunLength = 0; + if (LineNum & 1) { + pa = run1; + pb = run0; + } + else { + pa = run0; + pb = run1; + } + thisrun = pa; + EOLcnt = 0; + a0 = 0; + b1 = *pb++; + + if (refline) { + expand1d(); + } + else { + expand2d(EOL2); + } + if (RunLength) + SETVAL(0); + if (a0 != lastx) { + if (verbose) + kdWarning() << "Line " << LineNum << ": length is " + << a0 << " (expected "<< lastx << ")\n"; + while (a0 > lastx) + a0 -= *--pa; + if (a0 < lastx) { + if ((pa - run0) & 1) + SETVAL(0); + SETVAL(lastx - a0); + } + } + SETVAL(0); /* imaginary change at end of line for reference */ + (*df)(thisrun, LineNum++, pn); + } + free(run0); +} + +/* Redefine the "skip to eol" macro. We cannot recover from coding + errors in G4 data */ +#undef SKIP_EOL +#undef eol2lab +#define SKIP_EOL do { \ + if (verbose) \ + kdError() << "Line " << LineNum << ": G4 coding error\n"; \ + free(run0); \ + return; \ +} while (0) +#define eol2lab + +/* Expand group-4 data */ +void +g4expand(struct pagenode *pn, drawfunc df) +{ + int RunLength; /* Length of current run */ + int a0; /* reference element */ + int b1; /* next change on previous line */ + int lastx = pn->size.width();/* copy line width to register */ + pixnum *run0, *run1; /* run length arrays */ + pixnum *thisrun, *pa, *pb; /* pointers into runs */ + t16bits *sp; /* pointer into compressed data */ + t32bits BitAcc; /* bit accumulator */ + int BitsAvail; /* # valid bits in BitAcc */ + int LineNum; /* line number */ + int EOLcnt; + struct tabent *TabEnt; + + sp = pn->data; + BitAcc = 0; + BitsAvail = 0; + /* allocate space for 2 runlength arrays */ + run0 = (pixnum *) malloc(2 * ((lastx+5)&~1) * sizeof(pixnum)); + run1 = run0 + ((lastx+5)&~1); + run1[0] = lastx; /* initial reference line */ + run1[1] = 0; + + for (LineNum = 0; LineNum < pn->rowsperstrip; ) { +#ifdef DEBUG_FAX + printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %d\n", LineNum); + fflush(stdout); +#endif + RunLength = 0; + if (LineNum & 1) { + pa = run1; + pb = run0; + } + else { + pa = run0; + pb = run1; + } + thisrun = pa; + a0 = 0; + b1 = *pb++; + expand2d(EOFB); + if (a0 < lastx) { + if ((pa - run0) & 1) + SETVAL(0); + SETVAL(lastx - a0); + } + SETVAL(0); /* imaginary change at end of line for reference */ + (*df)(thisrun, LineNum++, pn); + continue; + EOFB: + NeedBits(13); + if (GetBits(13) != 0x1001 && verbose) + kdError() << "Bad RTC\n"; + break; + } + free(run0); +} + +static const unsigned char zerotab[256] = { + 0x88, 0x07, 0x16, 0x06, 0x25, 0x05, 0x15, 0x05, + 0x34, 0x04, 0x14, 0x04, 0x24, 0x04, 0x14, 0x04, + 0x43, 0x03, 0x13, 0x03, 0x23, 0x03, 0x13, 0x03, + 0x33, 0x03, 0x13, 0x03, 0x23, 0x03, 0x13, 0x03, + 0x52, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02, + 0x32, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02, + 0x42, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02, + 0x32, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02, + 0x61, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, + 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, + 0x41, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, + 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, + 0x51, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, + 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, + 0x41, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, + 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, + 0x70, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x50, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x60, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x50, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00 +}; + +#define check(v) do { \ + prezeros = zerotab[v]; \ + postzeros = prezeros & 15; \ + prezeros >>= 4; \ + if (prezeros == 8) { \ + zeros += 8; \ + continue; \ + } \ + if (zeros + prezeros < 11) { \ + empty = 0; \ + zeros = postzeros; \ + continue; \ + } \ + zeros = postzeros; \ + if (empty) \ + EOLcnt++; \ + lines++; \ + empty = 1; \ +} while (0) + +/* count fax lines */ +int +G3count(struct pagenode *pn, int twoD) +{ + t16bits *p = pn->data; + t16bits *end = p + pn->length/sizeof(*p); + int lines = 0; /* lines seen so far */ + int zeros = 0; /* number of consecutive zero bits seen */ + int EOLcnt = 0; /* number of consecutive EOLs seen */ + int empty = 1; /* empty line */ + int prezeros, postzeros; + + while (p < end && EOLcnt < 6) { + t16bits bits = *p++; + check(bits&255); + if (twoD && (prezeros + postzeros == 7)) { + if (postzeros || ((bits & 0x100) == 0)) + zeros--; + } + check(bits>>8); + if (twoD && (prezeros + postzeros == 7)) { + if (postzeros || ((p < end) && ((*p & 1) == 0))) + zeros--; + } + } + return lines - EOLcnt; /* don't count trailing EOLs */ +} diff --git a/kfaxview/libkfaximage/faxexpand.h b/kfaxview/libkfaximage/faxexpand.h new file mode 100644 index 00000000..8da4e8bc --- /dev/null +++ b/kfaxview/libkfaximage/faxexpand.h @@ -0,0 +1,126 @@ +/* Include file for fax routines + Copyright (C) 1990, 1995 Frank D. Cringle. + Copyright (C) 2005 Helge Deller + +This file is part of viewfax - g3/g4 fax processing software. + +viewfax 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 _faxexpand_h_ +#define _faxexpand_h_ + +#include +#include + +#include +#include + +#define t32bits Q_UINT32 +#define t16bits Q_UINT16 + +typedef t16bits pixnum; + +class pagenode; + +/* drawfunc() points to a function which processes a line of the + expanded image described as a list of run lengths. + run is the base of an array of lengths, starting with a + (possibly empty) white run for line number linenum. + pn points to the page descriptor */ +typedef void (*drawfunc)(pixnum *run, int linenum, class pagenode *pn); + +struct strip { /* tiff strip descriptor */ + off_t offset; /* offset in file */ + off_t size; /* size of this strip */ +}; + + +/* defines for the pagenode member: type */ +#define FAX_TIFF 1 +#define FAX_RAW 2 + +class pagenode { /* compressed page descriptor */ + public: + pagenode(); + ~pagenode() { }; + int nstrips; /* number of strips */ + int rowsperstrip; /* number of rows per strip */ + int stripnum; /* current strip while expanding */ + struct strip *strips; /* array of strips containing fax data in file */ + t16bits *data; /* in-memory copy of strip */ + size_t length; /* length of data */ + QSize size; /* width & height of page in pixels */ + int inverse; /* black <=> white */ + int lsbfirst; /* bit order is lsb first */ + int type; /* Bernd: tiff vs no tiff*/ + int orient; /* orientation - upsidedown, landscape, mirrored */ + int vres; /* vertical resolution: 1 = fine */ + QPoint dpi; /* DPI horz/vert */ + void (*expander)(class pagenode *, drawfunc); + QImage image; + unsigned int bytes_per_line; +}; + +extern class pagenode *firstpage, *lastpage, *thispage; +extern class pagenode defaultpage; + +/* page orientation flags */ +#define TURN_NONE 0 +#define TURN_U 1 +#define TURN_L 2 +#define TURN_M 4 + +/* fsm state codes */ +#define S_Null 0 +#define S_Pass 1 +#define S_Horiz 2 +#define S_V0 3 +#define S_VR 4 +#define S_VL 5 +#define S_Ext 6 +#define S_TermW 7 +#define S_TermB 8 +#define S_MakeUpW 9 +#define S_MakeUpB 10 +#define S_MakeUp 11 +#define S_EOL 12 + +/* state table entry */ +struct tabent { + unsigned char State; + unsigned char Width; /* width of code in bits */ + pixnum Param; /* run length */ +}; + +extern struct tabent MainTable[]; /* 2-D state table */ +extern struct tabent WhiteTable[]; /* White run lengths */ +extern struct tabent BlackTable[]; /* Black run lengths */ + +void MHexpand(class pagenode *pn, drawfunc df); +void g31expand(class pagenode *pn, drawfunc df); +void g32expand(class pagenode *pn, drawfunc df); +void g4expand(class pagenode *pn, drawfunc df); + +unsigned char *getstrip(class pagenode *pn, int strip); +class pagenode *notefile(const char *name); +int notetiff(const char *name); + +/* initialise code tables */ +extern void fax_init_tables(void); + +/* count lines in image */ +extern int G3count(class pagenode *pn, int twoD); + +#endif diff --git a/kfaxview/libkfaximage/faxinit.cpp b/kfaxview/libkfaximage/faxinit.cpp new file mode 100644 index 00000000..aa6166aa --- /dev/null +++ b/kfaxview/libkfaximage/faxinit.cpp @@ -0,0 +1,345 @@ +/* Initialise fax decoder tables + Copyright (C) 1990, 1995 Frank D. Cringle. + +This file is part of viewfax - g3/g4 fax processing software. + +viewfax 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 + +#include +#include "faxexpand.h" + +struct tabent MainTable[128]; +struct tabent WhiteTable[4096]; +struct tabent BlackTable[8192]; + +struct proto { + t16bits code; /* right justified, lsb-first, zero filled */ + t16bits val; /* (pixel count)<<4 + code width */ +}; + +static const struct proto Pass[] = { +{ 0x0008, 4 }, +{ 0, 0 } +}; + +static const struct proto Horiz[] = { +{ 0x0004, 3 }, +{ 0, 0 } +}; + +static const struct proto V0[] = { +{ 0x0001, 1 }, +{ 0, 0 } +}; + +static const struct proto VR[] = { +{ 0x0006, (1<<4)+3 }, +{ 0x0030, (2<<4)+6 }, +{ 0x0060, (3<<4)+7 }, +{ 0, 0 } +}; + +static const struct proto VL[] = { +{ 0x0002, (1<<4)+3 }, +{ 0x0010, (2<<4)+6 }, +{ 0x0020, (3<<4)+7 }, +{ 0, 0 } +}; + +static const struct proto ExtV[] = { +{ 0x0040, 7 }, +{ 0, 0 } +}; + +static const struct proto EOLV[] = { +{ 0x0000, 7 }, +{ 0, 0 } +}; + +static const struct proto MakeUpW[] = { +{ 0x001b, 1029 }, +{ 0x0009, 2053 }, +{ 0x003a, 3078 }, +{ 0x0076, 4103 }, +{ 0x006c, 5128 }, +{ 0x00ec, 6152 }, +{ 0x0026, 7176 }, +{ 0x00a6, 8200 }, +{ 0x0016, 9224 }, +{ 0x00e6, 10248 }, +{ 0x0066, 11273 }, +{ 0x0166, 12297 }, +{ 0x0096, 13321 }, +{ 0x0196, 14345 }, +{ 0x0056, 15369 }, +{ 0x0156, 16393 }, +{ 0x00d6, 17417 }, +{ 0x01d6, 18441 }, +{ 0x0036, 19465 }, +{ 0x0136, 20489 }, +{ 0x00b6, 21513 }, +{ 0x01b6, 22537 }, +{ 0x0032, 23561 }, +{ 0x0132, 24585 }, +{ 0x00b2, 25609 }, +{ 0x0006, 26630 }, +{ 0x01b2, 27657 }, +{ 0, 0 } +}; + +static const struct proto MakeUpB[] = { +{ 0x03c0, 1034 }, +{ 0x0130, 2060 }, +{ 0x0930, 3084 }, +{ 0x0da0, 4108 }, +{ 0x0cc0, 5132 }, +{ 0x02c0, 6156 }, +{ 0x0ac0, 7180 }, +{ 0x06c0, 8205 }, +{ 0x16c0, 9229 }, +{ 0x0a40, 10253 }, +{ 0x1a40, 11277 }, +{ 0x0640, 12301 }, +{ 0x1640, 13325 }, +{ 0x09c0, 14349 }, +{ 0x19c0, 15373 }, +{ 0x05c0, 16397 }, +{ 0x15c0, 17421 }, +{ 0x0dc0, 18445 }, +{ 0x1dc0, 19469 }, +{ 0x0940, 20493 }, +{ 0x1940, 21517 }, +{ 0x0540, 22541 }, +{ 0x1540, 23565 }, +{ 0x0b40, 24589 }, +{ 0x1b40, 25613 }, +{ 0x04c0, 26637 }, +{ 0x14c0, 27661 }, +{ 0, 0 } +}; + +static const struct proto MakeUp[] = { +{ 0x0080, 28683 }, +{ 0x0180, 29707 }, +{ 0x0580, 30731 }, +{ 0x0480, 31756 }, +{ 0x0c80, 32780 }, +{ 0x0280, 33804 }, +{ 0x0a80, 34828 }, +{ 0x0680, 35852 }, +{ 0x0e80, 36876 }, +{ 0x0380, 37900 }, +{ 0x0b80, 38924 }, +{ 0x0780, 39948 }, +{ 0x0f80, 40972 }, +{ 0, 0 } +}; + +static const struct proto TermW[] = { +{ 0x00ac, 8 }, +{ 0x0038, 22 }, +{ 0x000e, 36 }, +{ 0x0001, 52 }, +{ 0x000d, 68 }, +{ 0x0003, 84 }, +{ 0x0007, 100 }, +{ 0x000f, 116 }, +{ 0x0019, 133 }, +{ 0x0005, 149 }, +{ 0x001c, 165 }, +{ 0x0002, 181 }, +{ 0x0004, 198 }, +{ 0x0030, 214 }, +{ 0x000b, 230 }, +{ 0x002b, 246 }, +{ 0x0015, 262 }, +{ 0x0035, 278 }, +{ 0x0072, 295 }, +{ 0x0018, 311 }, +{ 0x0008, 327 }, +{ 0x0074, 343 }, +{ 0x0060, 359 }, +{ 0x0010, 375 }, +{ 0x000a, 391 }, +{ 0x006a, 407 }, +{ 0x0064, 423 }, +{ 0x0012, 439 }, +{ 0x000c, 455 }, +{ 0x0040, 472 }, +{ 0x00c0, 488 }, +{ 0x0058, 504 }, +{ 0x00d8, 520 }, +{ 0x0048, 536 }, +{ 0x00c8, 552 }, +{ 0x0028, 568 }, +{ 0x00a8, 584 }, +{ 0x0068, 600 }, +{ 0x00e8, 616 }, +{ 0x0014, 632 }, +{ 0x0094, 648 }, +{ 0x0054, 664 }, +{ 0x00d4, 680 }, +{ 0x0034, 696 }, +{ 0x00b4, 712 }, +{ 0x0020, 728 }, +{ 0x00a0, 744 }, +{ 0x0050, 760 }, +{ 0x00d0, 776 }, +{ 0x004a, 792 }, +{ 0x00ca, 808 }, +{ 0x002a, 824 }, +{ 0x00aa, 840 }, +{ 0x0024, 856 }, +{ 0x00a4, 872 }, +{ 0x001a, 888 }, +{ 0x009a, 904 }, +{ 0x005a, 920 }, +{ 0x00da, 936 }, +{ 0x0052, 952 }, +{ 0x00d2, 968 }, +{ 0x004c, 984 }, +{ 0x00cc, 1000 }, +{ 0x002c, 1016 }, +{ 0, 0 } +}; + +static const struct proto TermB[] = { +{ 0x03b0, 10 }, +{ 0x0002, 19 }, +{ 0x0003, 34 }, +{ 0x0001, 50 }, +{ 0x0006, 67 }, +{ 0x000c, 84 }, +{ 0x0004, 100 }, +{ 0x0018, 117 }, +{ 0x0028, 134 }, +{ 0x0008, 150 }, +{ 0x0010, 167 }, +{ 0x0050, 183 }, +{ 0x0070, 199 }, +{ 0x0020, 216 }, +{ 0x00e0, 232 }, +{ 0x0030, 249 }, +{ 0x03a0, 266 }, +{ 0x0060, 282 }, +{ 0x0040, 298 }, +{ 0x0730, 315 }, +{ 0x00b0, 331 }, +{ 0x01b0, 347 }, +{ 0x0760, 363 }, +{ 0x00a0, 379 }, +{ 0x0740, 395 }, +{ 0x00c0, 411 }, +{ 0x0530, 428 }, +{ 0x0d30, 444 }, +{ 0x0330, 460 }, +{ 0x0b30, 476 }, +{ 0x0160, 492 }, +{ 0x0960, 508 }, +{ 0x0560, 524 }, +{ 0x0d60, 540 }, +{ 0x04b0, 556 }, +{ 0x0cb0, 572 }, +{ 0x02b0, 588 }, +{ 0x0ab0, 604 }, +{ 0x06b0, 620 }, +{ 0x0eb0, 636 }, +{ 0x0360, 652 }, +{ 0x0b60, 668 }, +{ 0x05b0, 684 }, +{ 0x0db0, 700 }, +{ 0x02a0, 716 }, +{ 0x0aa0, 732 }, +{ 0x06a0, 748 }, +{ 0x0ea0, 764 }, +{ 0x0260, 780 }, +{ 0x0a60, 796 }, +{ 0x04a0, 812 }, +{ 0x0ca0, 828 }, +{ 0x0240, 844 }, +{ 0x0ec0, 860 }, +{ 0x01c0, 876 }, +{ 0x0e40, 892 }, +{ 0x0140, 908 }, +{ 0x01a0, 924 }, +{ 0x09a0, 940 }, +{ 0x0d40, 956 }, +{ 0x0340, 972 }, +{ 0x05a0, 988 }, +{ 0x0660, 1004 }, +{ 0x0e60, 1020 }, +{ 0, 0 } +}; + +static const struct proto ExtH[] = { +{ 0x0100, 9 }, +{ 0, 0 } +}; + +static const struct proto EOLH[] = { +{ 0x0000, 11 }, +{ 0, 0 } +}; + +static void +FillTable(struct tabent *T, int Size, const struct proto *P, int State) +{ + int limit = 1 << Size; + + while (P->val) { + int width = P->val & 15; + int param = P->val >> 4; + int incr = 1 << width; + int code; + for (code = P->code; code < limit; code += incr) { + struct tabent *E = T+code; + E->State = State; + E->Width = width; + E->Param = param; + } + P++; + } +} + +/* initialise the huffman code tables */ +void +fax_init_tables(void) +{ + static bool already_initialized = 0; + if (already_initialized) + return; + + ++already_initialized; + + FillTable(MainTable, 7, Pass, S_Pass); + FillTable(MainTable, 7, Horiz, S_Horiz); + FillTable(MainTable, 7, V0, S_V0); + FillTable(MainTable, 7, VR, S_VR); + FillTable(MainTable, 7, VL, S_VL); + FillTable(MainTable, 7, ExtV, S_Ext); + FillTable(MainTable, 7, EOLV, S_EOL); + FillTable(WhiteTable, 12, MakeUpW, S_MakeUpW); + FillTable(WhiteTable, 12, MakeUp, S_MakeUp); + FillTable(WhiteTable, 12, TermW, S_TermW); + FillTable(WhiteTable, 12, ExtH, S_Ext); + FillTable(WhiteTable, 12, EOLH, S_EOL); + FillTable(BlackTable, 13, MakeUpB, S_MakeUpB); + FillTable(BlackTable, 13, MakeUp, S_MakeUp); + FillTable(BlackTable, 13, TermB, S_TermB); + FillTable(BlackTable, 13, ExtH, S_Ext); + FillTable(BlackTable, 13, EOLH, S_EOL); +} diff --git a/kfaxview/libkfaximage/kfaximage.cpp b/kfaxview/libkfaximage/kfaximage.cpp new file mode 100644 index 00000000..28744923 --- /dev/null +++ b/kfaxview/libkfaximage/kfaximage.cpp @@ -0,0 +1,667 @@ +/* + This file is part of KDE FAX image library + Copyright (c) 2005 Helge Deller + + based on Frank D. Cringle's viewfax package + Copyright (C) 1990, 1995 Frank D. Cringle. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include + +#include +#include + +#include +#include +#include + +#include "faxexpand.h" +#include "kfaximage.h" + +static const char FAXMAGIC[] = "\000PC Research, Inc\000\000\000\000\000\000"; +static const char littleTIFF[] = "\x49\x49\x2a\x00"; +static const char bigTIFF[] = "\x4d\x4d\x00\x2a"; + +KFaxImage::KFaxImage( const QString &filename, QObject *parent, const char *name ) + : QObject(parent,name) +{ + KGlobal::locale()->insertCatalogue( QString::fromLatin1("libkfaximage") ); + loadImage(filename); +} + +KFaxImage::~KFaxImage() +{ } + +bool KFaxImage::loadImage( const QString &filename ) +{ + reset(); + + m_filename = filename; + m_errorString = QString::null; + + if (m_filename.isEmpty()) + return false; + + int ok = notetiff(); + if (!ok) { + reset(); + } + return ok == 1; +} + +void KFaxImage::reset() +{ + fax_init_tables(); + m_pagenodes.setAutoDelete(true); + m_pagenodes.clear(); + // do not reset m_errorString and m_filename, since + // they may be needed by calling application +} + +QImage KFaxImage::page( unsigned int pageNr ) +{ + if (pageNr >= numPages()) { + kdDebug() << "KFaxImage::page() called with invalid page number\n"; + return QImage(); + } + pagenode *pn = m_pagenodes.at(pageNr); + GetImage(pn); + return pn->image; +} + +QPoint KFaxImage::page_dpi( unsigned int pageNr ) +{ + if (pageNr >= numPages()) { + kdDebug() << "KFaxImage::page_dpi() called with invalid page number\n"; + return QPoint(0,0); + } + pagenode *pn = m_pagenodes.at(pageNr); + GetImage(pn); + return pn->dpi; +} + +QSize KFaxImage::page_size( unsigned int pageNr ) +{ + if (pageNr >= numPages()) { + kdDebug() << "KFaxImage::page_size() called with invalid page number\n"; + return QSize(0,0); + } + pagenode *pn = m_pagenodes.at(pageNr); + GetImage(pn); + return pn->size; +} + + +pagenode *KFaxImage::AppendImageNode(int type) +{ + pagenode *pn = new pagenode(); + if (pn) { + pn->type = type; + pn->expander = g31expand; + pn->strips = NULL; + pn->size = QSize(1728,2339); + pn->vres = -1; + pn->dpi = KFAX_DPI_FINE; + m_pagenodes.append(pn); + } + return pn; +} + +bool KFaxImage::NewImage(pagenode *pn, int w, int h) +{ + pn->image = QImage( w, h, 1, 2, QImage::systemByteOrder() ); + pn->image.setColor(0, qRgb(255,255,255)); + pn->image.setColor(1, qRgb(0,0,0)); + pn->data = (Q_UINT16*) pn->image.bits(); + pn->bytes_per_line = pn->image.bytesPerLine(); + pn->dpi = KFAX_DPI_FINE; + + return !pn->image.isNull(); +} + +void KFaxImage::FreeImage(pagenode *pn) +{ + pn->image = QImage(); + pn->data = NULL; + pn->bytes_per_line = 0; +} + +void KFaxImage::kfaxerror(const QString& error) +{ + m_errorString = error; + kdError() << "kfaxerror: " << error << endl; +} + + +/* Enter an argument in the linked list of pages */ +pagenode * +KFaxImage::notefile(int type) +{ + pagenode *newnode = new pagenode(); + newnode->type = type; + newnode->size = QSize(1728,0); + return newnode; +} + +static t32bits +get4(unsigned char *p, QImage::Endian endian) +{ + return (endian == QImage::BigEndian) + ? (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3] : + p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24); +} + +static int +get2(unsigned char *p, QImage::Endian endian) +{ + return (endian == QImage::BigEndian) ? (p[0]<<8)|p[1] : p[0]|(p[1]<<8); +} + +/* generate pagenodes for the images in a tiff file */ +int +KFaxImage::notetiff() +{ +#define SC(x) (char *)(x) + unsigned char header[8]; + QImage::Endian endian; + t32bits IFDoff; + pagenode *pn = NULL; + QString str; + + QFile file(filename()); + if (!file.open(IO_ReadOnly)) { + kfaxerror(i18n("Unable to open file for reading.")); + return 0; + } + + if (file.readBlock(SC(header), 8) != 8) { + kfaxerror(i18n("Unable to read file header (file too short).")); + return 0; + } + if (memcmp(header, &littleTIFF, 4) == 0) + endian = QImage::LittleEndian; + else if (memcmp(header, &bigTIFF, 4) == 0) + endian = QImage::BigEndian; + else { + maybe_RAW_FAX: + kfaxerror(i18n("This is not a TIFF FAX file.")); + // AppendImageNode(FAX_RAW); + return 0; + } + IFDoff = get4(header+4, endian); + if (IFDoff & 1) { + goto maybe_RAW_FAX; + } + do { /* for each page */ + unsigned char buf[8]; + unsigned char *dir = NULL , *dp = NULL; + int ndirent; + pixnum iwidth = 1728; + pixnum iheight = 2339; + int inverse = false; + int lsbfirst = 0; + int t4opt = 0, comp = 0; + int orient = TURN_NONE; + int yres = 196; /* 98.0 */ + struct strip *strips = NULL; + unsigned int rowsperstrip = 0; + t32bits nstrips = 1; + + if (!file.at(IFDoff)) { + realbad: + kfaxerror( i18n("Invalid or incomplete TIFF file.") ); + bad: + if (strips) + free(strips); + if (dir) + free(dir); + file.close(); + return 1; + } + if (file.readBlock(SC(buf), 2) != 2) + goto realbad; + ndirent = get2(buf, endian); + int len = 12*ndirent+4; + dir = (unsigned char *) malloc(len); + if (file.readBlock(SC(dir), len) != len) + goto realbad; + for (dp = dir; ndirent; ndirent--, dp += 12) { + /* for each directory entry */ + int tag, ftype; + t32bits count, value = 0; + tag = get2(dp, endian); + ftype = get2(dp+2, endian); + count = get4(dp+4, endian); + switch(ftype) { /* value is offset to list if count*size > 4 */ + case 3: /* short */ + value = get2(dp+8, endian); + break; + case 4: /* long */ + value = get4(dp+8, endian); + break; + case 5: /* offset to rational */ + value = get4(dp+8, endian); + break; + } + switch(tag) { + case 256: /* ImageWidth */ + iwidth = value; + break; + case 257: /* ImageLength */ + iheight = value; + break; + case 259: /* Compression */ + comp = value; + break; + case 262: /* PhotometricInterpretation */ + inverse ^= (value == 1); + break; + case 266: /* FillOrder */ + lsbfirst = (value == 2); + break; + case 273: /* StripOffsets */ + nstrips = count; + strips = (struct strip *) malloc(count * sizeof *strips); + if (count == 1 || (count == 2 && ftype == 3)) { + strips[0].offset = value; + if (count == 2) + strips[1].offset = get2(dp+10, endian); + break; + } + if (!file.at(value)) + goto realbad; + for (count = 0; count < nstrips; count++) { + if (file.readBlock(SC(buf), (ftype == 3) ? 2 : 4) <= 0) + goto realbad; + strips[count].offset = (ftype == 3) ? + get2(buf, endian) : get4(buf, endian); + } + break; + case 274: /* Orientation */ + switch(value) { + default: /* row0 at top, col0 at left */ + orient = 0; + break; + case 2: /* row0 at top, col0 at right */ + orient = TURN_M; + break; + case 3: /* row0 at bottom, col0 at right */ + orient = TURN_U; + break; + case 4: /* row0 at bottom, col0 at left */ + orient = TURN_U|TURN_M; + break; + case 5: /* row0 at left, col0 at top */ + orient = TURN_M|TURN_L; + break; + case 6: /* row0 at right, col0 at top */ + orient = TURN_U|TURN_L; + break; + case 7: /* row0 at right, col0 at bottom */ + orient = TURN_U|TURN_M|TURN_L; + break; + case 8: /* row0 at left, col0 at bottom */ + orient = TURN_L; + break; + } + break; + case 278: /* RowsPerStrip */ + rowsperstrip = value; + break; + case 279: /* StripByteCounts */ + if (count != nstrips) { + str = i18n("In file %1\nStripsPerImage tag 273=%2,tag279=%3\n") + .arg(filename()).arg(nstrips).arg(count); + kfaxerror(str); + goto realbad; + } + if (count == 1 || (count == 2 && ftype == 3)) { + strips[0].size = value; + if (count == 2) + strips[1].size = get2(dp+10, endian); + break; + } + if (!file.at(value)) + goto realbad; + for (count = 0; count < nstrips; count++) { + if (file.readBlock(SC(buf), (ftype == 3) ? 2 : 4) <= 0) + goto realbad; + strips[count].size = (ftype == 3) ? + get2(buf, endian) : get4(buf, endian); + } + break; + case 283: /* YResolution */ + if (!file.at(value) || + file.readBlock(SC(buf), 8) != 8) + goto realbad; + yres = get4(buf, endian) / get4(buf+4, endian); + break; + case 292: /* T4Options */ + t4opt = value; + break; + case 293: /* T6Options */ + /* later */ + break; + case 296: /* ResolutionUnit */ + if (value == 3) + yres = (yres * 254) / 100; /* *2.54 */ + break; + } + } + IFDoff = get4(dp, endian); + free(dir); + dir = NULL; + if (comp == 5) { + // compression type 5 is LZW compression // XXX + kfaxerror(i18n("Due to patent reasons LZW (Lempel-Ziv & Welch) " + "compressed Fax files cannot be loaded yet.\n")); + goto bad; + } + if (comp < 2 || comp > 4) { + kfaxerror(i18n("This version can only handle Fax files\n")); + goto bad; + } + pn = AppendImageNode(FAX_TIFF); + pn->nstrips = nstrips; + pn->rowsperstrip = nstrips > 1 ? rowsperstrip : iheight; + pn->strips = strips; + pn->size = QSize(iwidth,iheight); + pn->inverse = inverse; + pn->lsbfirst = lsbfirst; + pn->orient = orient; + pn->dpi.setY(yres); + pn->vres = (yres > 150) ? 1:0; /* arbitrary threshold for fine resolution */ + if (comp == 2) + pn->expander = MHexpand; + else if (comp == 3) + pn->expander = (t4opt & 1) ? g32expand : g31expand; + else + pn->expander = g4expand; + } while (IFDoff); + file.close(); + return 1; +#undef UC +} + +/* report error and remove bad file from the list */ +void +KFaxImage::badfile(pagenode *pn) +{ + kfaxerror(i18n("%1: Bad Fax File").arg(filename())); + FreeImage(pn); +} + +/* rearrange input bits into t16bits lsb-first chunks */ +static void +normalize(pagenode *pn, int revbits, int swapbytes, size_t length) +{ + t32bits *p = (t32bits *) pn->data; + + kdDebug() << "normalize = " << ((revbits<<1)|swapbytes) << endl; + switch ((revbits<<1)|swapbytes) { + case 0: + break; + case 1: + for ( ; length; length -= 4) { + t32bits t = *p; + *p++ = ((t & 0xff00ff00) >> 8) | ((t & 0x00ff00ff) << 8); + } + break; + case 2: + for ( ; length; length -= 4) { + t32bits t = *p; + t = ((t & 0xf0f0f0f0) >> 4) | ((t & 0x0f0f0f0f) << 4); + t = ((t & 0xcccccccc) >> 2) | ((t & 0x33333333) << 2); + *p++ = ((t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1); + } + break; + case 3: + for ( ; length; length -= 4) { + t32bits t = *p; + t = ((t & 0xff00ff00) >> 8) | ((t & 0x00ff00ff) << 8); + t = ((t & 0xf0f0f0f0) >> 4) | ((t & 0x0f0f0f0f) << 4); + t = ((t & 0xcccccccc) >> 2) | ((t & 0x33333333) << 2); + *p++ = ((t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1); + } + } +} + + +/* get compressed data into memory */ +unsigned char * +KFaxImage::getstrip(pagenode *pn, int strip) +{ + size_t offset, roundup; + unsigned char *Data; + + union { t16bits s; unsigned char b[2]; } so; +#define ShortOrder so.b[1] + so.s = 1; /* XXX */ + + QFile file(filename()); + if (!file.open(IO_ReadOnly)) { + badfile(pn); + return NULL; + } + + if (pn->strips == NULL) { + offset = 0; + pn->length = file.size(); + } + else if (strip < pn->nstrips) { + offset = pn->strips[strip].offset; + pn->length = pn->strips[strip].size; + } + else { + kfaxerror( i18n("Trying to expand too many strips.") ); + return NULL; + } + + /* round size to full boundary plus t32bits */ + roundup = (pn->length + 7) & ~3; + + Data = (unsigned char *) malloc(roundup); + /* clear the last 2 t32bits, to force the expander to terminate + even if the file ends in the middle of a fax line */ + *((t32bits *) Data + roundup/4 - 2) = 0; + *((t32bits *) Data + roundup/4 - 1) = 0; + + /* we expect to get it in one gulp... */ + if (!file.at(offset) || + (size_t) file.readBlock((char *)Data, pn->length) != pn->length) { + badfile(pn); + free(Data); + return NULL; + } + file.close(); + + pn->data = (t16bits *) Data; + if (pn->strips == NULL && memcmp(Data, FAXMAGIC, sizeof(FAXMAGIC)-1) == 0) { + /* handle ghostscript / PC Research fax file */ + if (Data[24] != 1 || Data[25] != 0){ + kfaxerror( i18n("Only the first page of the PC Research multipage file will be shown.") ); + } + pn->length -= 64; + pn->vres = Data[29]; + pn->data += 32; + roundup -= 64; + } + + normalize(pn, !pn->lsbfirst, ShortOrder, roundup); + if (pn->size.height() == 0) + pn->size.setHeight( G3count(pn, pn->expander == g32expand) ); + if (pn->size.height() == 0) { + + kfaxerror( i18n("No fax found in file.") ); + badfile(pn); + free(Data); + return NULL; + } + if (pn->strips == NULL) + pn->rowsperstrip = pn->size.height(); + return Data; +} + + +static void +drawline(pixnum *run, int LineNum, pagenode *pn) +{ + t32bits *p, *p1; /* p - current line, p1 - low-res duplicate */ + pixnum *r; /* pointer to run-lengths */ + t32bits pix; /* current pixel value */ + t32bits acc; /* pixel accumulator */ + int nacc; /* number of valid bits in acc */ + int tot; /* total pixels in line */ + int n; + + LineNum += pn->stripnum * pn->rowsperstrip; + if (LineNum >= pn->size.height()) { + if (LineNum == pn->size.height()) + kdError() << "Height exceeded\n"; + return; + } + + p = (t32bits *) pn->image.scanLine(LineNum*(2-pn->vres)); + p1 =(t32bits *)( pn->vres ? 0 : pn->image.scanLine(1+LineNum*(2-pn->vres))); + r = run; + acc = 0; + nacc = 0; + pix = pn->inverse ? ~0 : 0; + tot = 0; + while (tot < pn->size.width()) { + n = *r++; + tot += n; + /* Watch out for buffer overruns, e.g. when n == 65535. */ + if (tot > pn->size.width()) + break; + if (pix) + acc |= (~(t32bits)0 >> nacc); + else if (nacc) + acc &= (~(t32bits)0 << (32 - nacc)); + else + acc = 0; + if (nacc + n < 32) { + nacc += n; + pix = ~pix; + continue; + } + *p++ = acc; + if (p1) + *p1++ = acc; + n -= 32 - nacc; + while (n >= 32) { + n -= 32; + *p++ = pix; + if (p1) + *p1++ = pix; + } + acc = pix; + nacc = n; + pix = ~pix; + } + if (nacc) { + *p++ = acc; + if (p1) + *p1++ = acc; + } +} + +int +KFaxImage::GetPartImage(pagenode *pn, int n) +{ + unsigned char *Data = getstrip(pn, n); + if (Data == 0) + return 3; + pn->stripnum = n; + (*pn->expander)(pn, drawline); + free(Data); + return 1; +} + +int +KFaxImage::GetImage(pagenode *pn) +{ + if (!pn->image.isNull()) + return 1; + + int i; + if (pn->strips == 0) { + + kdDebug() << "Loading RAW fax file " << m_filename << " size=" << pn->size << endl; + + /* raw file; maybe we don't have the height yet */ + unsigned char *Data = getstrip(pn, 0); + if (Data == 0){ + return 0; + } + if (!NewImage(pn, pn->size.width(), (pn->vres ? 1:2) * pn->size.height())) + return 0; + + (*pn->expander)(pn, drawline); + } + else { + /* multi-strip tiff */ + kdDebug() << "Loading MULTI STRIP TIFF fax file " << m_filename << endl; + + if (!NewImage(pn, pn->size.width(), (pn->vres ? 1:2) * pn->size.height())) + return 0; + pn->stripnum = 0; + kdDebug() << "has " << pn->nstrips << " strips.\n"; + for (i = 0; i < pn->nstrips; i++){ + + int k = GetPartImage(pn, i); + if ( k == 3 ){ + FreeImage(pn); + kfaxerror( i18n("Fax G3 format not yet supported.") ); + return k; + } + + } + } + + // byte-swapping the image on little endian machines +#if defined(Q_BYTE_ORDER) && (Q_BYTE_ORDER == Q_LITTLE_ENDIAN) + for (int y=pn->image.height()-1; y>=0; --y) { + Q_UINT32 *source = (Q_UINT32 *) pn->image.scanLine(y); + Q_UINT32 *dest = source; + for (int x=(pn->bytes_per_line/4)-1; x>=0; --x) { + Q_UINT32 dv = 0, sv = *source; + for (int bit=32; bit>0; --bit) { + dv <<= 1; + dv |= sv&1; + sv >>= 1; + } + *dest = dv; + ++dest; + ++source; + } + } +#endif + + kdDebug() << filename() + << "\n\tsize = " << pn->size + << "\n\tDPI = " << pn->dpi + << "\n\tresolution = " << (pn->vres ? "fine" : "normal") + << endl; + + return 1; +} + + +#include "kfaximage.moc" diff --git a/kfaxview/libkfaximage/kfaximage.h b/kfaxview/libkfaximage/kfaximage.h new file mode 100644 index 00000000..0ed2db90 --- /dev/null +++ b/kfaxview/libkfaximage/kfaximage.h @@ -0,0 +1,162 @@ +/* + This file is part of KDE FAX image loading library + Copyright (c) 2005 Helge Deller + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 _LIBKFAXIMAGE_H_ +#define _LIBKFAXIMAGE_H_ + +#include +#include +#include +#include +#include + +class pagenode; + + +/** + * This is KFaxImage, a class for loading FAX files under KDE + * + * @short KFaxImage + * @author Helge Deller + * @version 0.1 + * + * + * Standard fax dpi values: + * ------------------------ + * Standard: 203 dpi x 98 lpi + * Fine: 203 dpi x 196 lpi + * Super Fine: 203 dpi y 392 lpi, or + * 406 dpi x 392 lpi + */ + +#define KFAX_DPI_STANDARD QPoint(203,98) +#define KFAX_DPI_FINE QPoint(203,196) +#define KFAX_DPI_SUPERFINE QPoint(406,392) + + +class KDE_EXPORT KFaxImage : public QObject +{ + Q_OBJECT + +public: + + /** + * KFaxImage - the KDE FAX loader class + * constructor. + * @param filename: an optional FAX file which should be loaded. + * @see: numPages + */ + + KFaxImage( const QString &filename = QString::null, QObject *parent = 0, const char *name = 0 ); + + /** + * Destructor + * + * releases internal allocated memory. + */ + + virtual ~KFaxImage(); + + /** + * loads the FAX image and returns true when sucessful. + * @param filename: the file which should be loaded. + * @return boolean value on success or failure + * @see: numPages + * @see: errorString + */ + + bool loadImage( const QString &filename ); + + /** + * returns currently loaded image file name. + * @return FAX filename + */ + + QString filename() { return m_filename; }; + + /** + * returns number of pages which are stored in the FAX file + * @return page count + */ + + unsigned int numPages() const { return m_pagenodes.count(); }; + + /** + * returns a QImage which holds the contents of page pageNr + * @param pageNr: page number (starting with 0) + * @return QImage of the page pageNr + */ + + QImage page( unsigned int pageNr ); + + /** + * returns the DPI (dots per inch) of page pageNr + * @param pageNr: page number (starting with 0) + * @return a QPoint value with the DPIs in X- and Y-direction + */ + + QPoint page_dpi( unsigned int pageNr ); + + /** + * returns the physical pixels of page pageNr + * @param pageNr: page number (starting with 0) + * @return a QSize value with the width and height of the image + */ + + QSize page_size( unsigned int pageNr ); + + /** + * @return a user-visible, translated error string + */ + + const QString errorString() const { return m_errorString; }; + + + + private: + + /** + * private member variables + */ + + QString m_filename; + QString m_errorString; + + typedef QPtrList t_PageNodeList; + t_PageNodeList m_pagenodes; + + /** + * private member functions + */ + + void reset(); + void kfaxerror(const QString& error); + pagenode *AppendImageNode(int type); + bool NewImage(pagenode *pn, int w, int h); + void FreeImage(pagenode *pn); + unsigned char *getstrip(pagenode *pn, int strip); + int GetPartImage(pagenode *pn, int n); + int GetImage(pagenode *pn); + pagenode *notefile(int type); + int notetiff(); + void badfile(pagenode *pn); +}; + +#endif /* _LIBKFAXIMAGE_H_ */ + diff --git a/kfaxview/main.cpp b/kfaxview/main.cpp new file mode 100644 index 00000000..8e967a96 --- /dev/null +++ b/kfaxview/main.cpp @@ -0,0 +1,174 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "kviewshell.h" + + +static KCmdLineOptions options[] = +{ + { "unique", I18N_NOOP("Check if the file is loaded in another KFaxView instance.\nIf it is, bring up the other KFaxView. Otherwise, load the file."), 0 }, + { "g", 0, 0 }, + { "goto ", I18N_NOOP("Navigate to this page"), 0 }, + // The rest of the options are only for compability with the old KFax + { "f", 0, 0 }, + { "fine", I18N_NOOP("(obsolete)"), 0 }, + { "n", 0, 0 }, + { "normal", I18N_NOOP("(obsolete)"), 0 }, + { "height", I18N_NOOP("(obsolete)"), 0 }, + { "w", 0, 0 }, + { "width", I18N_NOOP("(obsolete)"), 0 }, + { "l", 0, 0 }, + { "landscape", I18N_NOOP("(obsolete)"), 0 }, + { "u", 0, 0 }, + { "upsidedown", I18N_NOOP("(obsolete)"), 0 }, + { "i", 0, 0 }, + { "invert", I18N_NOOP("(obsolete)"), 0 }, + { "m", 0, 0 }, + { "mem ", I18N_NOOP("(obsolete)"), 0 }, + { "r", 0, 0 }, + { "reverse", I18N_NOOP("(obsolete)"), 0 }, + { "2" , I18N_NOOP("(obsolete)"), 0 }, + { "4", I18N_NOOP("(obsolete)"), 0 }, + { "+file(s)", I18N_NOOP("Files to load"), 0 }, + KCmdLineLastOption +}; + + +static const char description[] = I18N_NOOP("A previewer for Fax files."); + + +int main(int argc, char** argv) +{ + KAboutData about ("kfaxview", I18N_NOOP("KFaxView"), "3.5", + description, KAboutData::License_GPL, + "Stephan Kebekus, Helge Deller", + I18N_NOOP("Fax-G3 plugin for the KViewShell document viewer framework.")); + + about.addAuthor ("Stefan Kebekus", + I18N_NOOP("KViewShell plugin"), + "kebekus@kde.org", + "http://www.mi.uni-koeln.de/~kebekus"); + + about.addAuthor ("Wilfried Huss", + I18N_NOOP("KViewShell maintainer"), + "Wilfried.Huss@gmx.at"); + + about.addAuthor ("Helge Deller", + I18N_NOOP("Fax file loading"), + "deller@gmx.de"); + + KCmdLineArgs::init(argc, argv, &about); + KCmdLineArgs::addCmdLineOptions(options); + KApplication app; + + // see if we are starting with session management + if (app.isRestored()) + { + RESTORE(KViewShell); + } + else + { + KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); + + if (args->isSet("unique")) + { + // With --unique, we need 2 arguments. + if (args->count() < 1) + { + args->usage(); + exit(-1); + } + + // Find the fully qualified file name of the file we are + // loading. Complain, if we are given a URL which does not point + // to a local file. + KURL url(args->url(0)); + + if (!url.isValid()) + { + kdError(4300) << QString(I18N_NOOP("The URL %1 is not well-formed.")).arg(args->arg(0)) << endl; + return -1; + } + + if (!url.isLocalFile()) + { + kdError(4300) << QString(I18N_NOOP("The URL %1 does not point to a local file. You can only specify local " + "files if you are using the '--unique' option.")).arg(args->arg(0)) << endl; + return -1; + } + + QString qualPath = QFileInfo(url.path()).absFilePath(); + + app.dcopClient()->attach(); + // We need to register as "kviewshell" to stay compatible with existing DCOP-skripts. + QCString id = app.dcopClient()->registerAs("unique-kviewshell"); + if (id.isNull()) + kdError(4300) << "There was an error using dcopClient()->registerAs()." << endl; + QCStringList apps = app.dcopClient()->registeredApplications(); + for ( QCStringList::Iterator it = apps.begin(); it != apps.end(); ++it ) + { + if ((*it).find("kviewshell") == 0) + { + QByteArray data, replyData; + QCString replyType; + QDataStream arg(data, IO_WriteOnly); + bool result; + arg << qualPath.stripWhiteSpace(); + if (!app.dcopClient()->call( *it, "kmultipage", "is_file_loaded(QString)", data, replyType, replyData)) + kdError(4300) << "There was an error using DCOP." << endl; + else + { + QDataStream reply(replyData, IO_ReadOnly); + if (replyType == "bool") + { + reply >> result; + if (result == true) + { + if (app.dcopClient()->send( *it, "kmultipage", "jumpToReference(QString)", url.ref()) == true) + { + app.dcopClient()->detach(); + return 0; + } + } + } + else + kdError(4300) << "The DCOP function 'doIt' returned an unexpected type of reply!"; + } + } + } + } + + // We need to register as "kviewshell" to stay compatible with existing DCOP-skripts. + app.dcopClient()->registerAs("kviewshell"); + KViewShell* shell = new KViewShell("image/fax-g3"); + shell->show(); + app.processEvents(); + + if (args->count() > 0) + { + KURL url = args->url(0); + if (!url.hasRef() && args->isSet("goto")) + { + // If the url doesn't already has a reference part, add the + // argument of --goto to the url as reference, to make the + // KViewShell jump to this page. + QString reference = args->getOption("goto"); + url.setHTMLRef(reference); + } + shell->openURL(url); + } + } + + return app.exec(); +} diff --git a/kfile-plugins/Makefile.am b/kfile-plugins/Makefile.am new file mode 100644 index 00000000..92a6e911 --- /dev/null +++ b/kfile-plugins/Makefile.am @@ -0,0 +1,14 @@ +if include_EXR_MODULES +KFILE_EXR_SUBDIR=exr +endif + +if include_TIFF +KFILE_TIFF_SUBDIR=tiff +endif + +if include_PDF +KFILE_PDF_SUBDIR=pdf +endif + +SUBDIRS=dvi png ps jpeg xbm xpm bmp tga rgb ico pcx $(KFILE_TIFF_SUBDIR) pnm \ + $(KFILE_EXR_SUBDIR) $(KFILE_PDF_SUBDIR) dds gif raw diff --git a/kfile-plugins/RETURNED_ITEMS b/kfile-plugins/RETURNED_ITEMS new file mode 100644 index 00000000..593d466a --- /dev/null +++ b/kfile-plugins/RETURNED_ITEMS @@ -0,0 +1,245 @@ +If you make a new plugin, please add the list of returned items to this list. + + +pdf plugin: +=========== + +Date Created +Date Modiified +Int Pages +Bool Encrypted +and everything else pdfinfo returns as string + + +png plugin: +=========== + +type key W/A details +------------------------------------------------------------------------ +Size Dimensions -/- +Int BitDepth -/- +String ColorMode -/- +String Compression -/- Compression type. Right now always "deflate" + +Other keys corresponding to the png comment keys are returned as non-editable +String. + +Common keys that are recommended in the png spec: +Title, Author, Description, Copyright, Creation Time, Software, Disclaimer, +Warning, Source, Comment + + +PostScript plugin: +================== + +String Title +String Creator +String CreationDate +String For +Int Pages + + + +Jpeg plugin: +============ +Note: number.number means precision of converted number + +type key Comment +----------------------------------------------------------------------------- +String Camera make +String Camera model +String Date/time +Size Dimensions Width x Height in pixels +int Orientation 1 - "The 0th row is at the visual top of the image, + and the 0th column is the visual left-hand side." + 2 - "The 0th row is at the visual top of the image, + and the 0th column is the visual right-hand side." + 3 - "The 0th row is at the visual bottom of the image, + and the 0th column is the visual right-hand side." + 4 - "The 0th row is at the visual bottom of the image, + and the 0th column is the visual left-hand side." + 5 - "The 0th row is the visual left-hand side of of the image, + and the 0th column is the visual top." + 6 - "The 0th row is the visual right-hand side of of the image, + and the 0th column is the visual top." + 7 - "The 0th row is the visual right-hand side of of the image, + and the 0th column is the visual bottom." + 8 - "The 0th row is the visual left-hand side of of the image, + and the 0th column is the visual bottom." +String ColorMode "Grayscale" "Color" +String Flash used "Yes" "No" +String Focal length 4.1 mm, 35mm equivalent +String Exposure time 6.3 (if < 0.5 also in 1/xx) sec +String Aperture "f/3.1" +String Focus dist. "Infinite" or 5.2 m +String CCD width 4.2 Postfix mm +String Exposure bias 4.2 +String Whitebalance 0 = unknown + 1 = Daylight + 2 = Fluorescent + 3 = Tungsten + 17 = Standard light A + 18 = Standard light B + 19 = Standard light C + 20 = D55 + 21 = D65 + 22 = D75 + 23 to 254 = reserved + 255 = other +String Metering mode 0 = unknown + 1 = Average + 2 = CenterWeightedAverage + 3 = Spot + 4 = MultiSpot + 5 = Pattern + 6 = Partial + 7 to 254 = reserved + 255 = other +String Exposure 0 = Not defined + 1 = Manual + 2 = Normal program + 3 = Aperture priority + 4 = Shutter priority + 5 = Creative program (biased toward depth of field) + 6 = Action program + (biased toward fast shutter speed) + 7 = Portrait mode + (for closeup photos with the background out of focus) + 8 = Landscape mode + (for landscape photos with the background in focus) + 9 to 255 = reserved +String ISO equiv. 2digits ??? +String JPG quality 1 - "basic" + 2 - "normal" + 4 - "fine" + default: unknown +String User comment +String Comment +QImage Thumbnail + + +gif plugin: +=========== + +type key Comment +----------------------------------------------------------------------------- +Size Dimensions Width x Height in pixels. +String Comment gif comment blocks, which we permit to be utf-8 encoded + in clear violation/extension of the specification which + calls for 7 bit ASCII. See: + http://www.geocities.co.jp/SiliconValley/3453/gif_info/index_en.html + + +TIFF plugin: +=========== + +:: Group: General :: + +type key Comment +------ -------------- ----------------------------------------------------- +String ColorMode Color Mode (Monochrome, RGB, RGBA etc) +Size Dimensions Width & height as a QSize object +Size Resolution x & y resolution in dpi as a QSize object +Int BitDepth No. of bits per pixel (e.g. 24 for 8-bit RGB) +String Compression Compression used (None, Deflate, LZW, JPEG etc.) +Int FaxPages No. of pages if this is fax +String Software Software used to produce this image +String Description Image description +String Copyright Copyright information +String DateTime Date and time of image creation +String Artist Name of the person who created this image + +:: Group: Scanner :: + +type key Comment +------ -------------- ----------------------------------------------------- +String Make Make of the scanner used +String Model Model of the scanner used + + + + + +xbm plugin: +=========== + +type key W/A details +------------------------------------------------------------------------ +QSize Dimensions -/- Dimensions in pixels + +xpm plugin: +=========== + +type key W/A details +------------------------------------------------------------------------ +QSize Dimensions -/- Dimensions in pixels +Int BitDepth -/- Bits per pixel + + +bmp plugin: +=========== + +type key W/A details +------------------------------------------------------------------------ +String Type -/- Bitmap type (Windows / OS/2) +QSize Dimensions -/- Dimensions in pixels +Int BitDepth -/- Bits per pixel +String Compression -/- Compression type + + +tga plugin: +=========== + +type key W/A details +------------------------------------------------------------------------ +QSize Dimensions -/- Dimensions in pixels +Int BitDepth -/- Bits per pixel +String ColorMode -/- Color mode (e.g. RGB) +String Compression -/- Compression type, if any + + +ico plugin: +=========== + +type key W/A details +------------------------------------------------------------------------ +Int Number -/- Number of icons in file +QSize Dimensions -/- Dimensions +QSize DimensionsM -/- Dimensions [of 1st icon] +Int Colors -/- Number of colors [in 1st icon] + +pcx plugin: +=========== + +type key W/A details +------------------------------------------------------------------------ +QSize Dimensions -/- Dimensions in pixels +Int BitDepth -/- Bits per pixel +QSize Resolution -/- Resolution in DPI +String Compression -/- Compression type, if any + + +rgb plugin: +=========== + +type key details +------------------------------------------------------------------------ +String ImageName Image name (or comment) +QSize Dimensions Dimensions in pixels +Int BitDepth Bits per pixel +String ColorMode Color Mode (Monochrome, RGB, RGBA etc) +String Compression Compression type +String SharedRows Percentage of shared rows + (amount of "aggression" -> see GIMP) +dds plugin: +=========== + +type key details +------------------------------------------------------------------------ +QSize Dimensions Dimensions in pixels +Int Depth Depth in pixels +Int BitDepth Bits per pixel +String ColorMode Color Mode (RGB, RGBA) +String Type 2D, volume or cube map +String Compression Compression type + diff --git a/kfile-plugins/bmp/Makefile.am b/kfile-plugins/bmp/Makefile.am new file mode 100644 index 00000000..dbaa8ff2 --- /dev/null +++ b/kfile-plugins/bmp/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for bmp file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_bmp.h + +kde_module_LTLIBRARIES = kfile_bmp.la + +kfile_bmp_la_SOURCES = kfile_bmp.cpp +kfile_bmp_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_bmp_la_LIBADD = $(LIB_KSYCOCA) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_bmp.cpp -o $(podir)/kfile_bmp.pot + +services_DATA = kfile_bmp.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/bmp/kfile_bmp.cpp b/kfile-plugins/bmp/kfile_bmp.cpp new file mode 100644 index 00000000..b9d6a7ad --- /dev/null +++ b/kfile-plugins/bmp/kfile_bmp.cpp @@ -0,0 +1,174 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Shane Wright + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include +#include "kfile_bmp.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if !defined(__osf__) +#include +#else +typedef unsigned long uint32_t; +typedef unsigned short uint16_t; +#endif + +typedef KGenericFactory BmpFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_bmp, BmpFactory( "kfile_bmp" )) + +KBmpPlugin::KBmpPlugin(QObject *parent, const char *name, + const QStringList &args) + + : KFilePlugin(parent, name, args) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-bmp" ); + + KFileMimeTypeInfo::GroupInfo* group = 0L; + + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + + KFileMimeTypeInfo::ItemInfo* item; + + item = addItemInfo(group, "Type", i18n("Type"), QVariant::String); + + item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size); + setHint( item, KFileMimeTypeInfo::Size ); + setUnit(item, KFileMimeTypeInfo::Pixels); + + item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::BitsPerPixel); + + item = addItemInfo(group, "Compression", i18n("Compression"), QVariant::String); + +} + + +bool KBmpPlugin::readInfo( KFileMetaInfo& info, uint what) +{ + const char * bmptype_bm = "BM"; + const char * bmptype_ba = "BA"; + const char * bmptype_ci = "CI"; + const char * bmptype_cp = "CP"; + const char * bmptype_ic = "IC"; + const char * bmptype_pt = "PT"; + + QFile file(info.path()); + + if (!file.open(IO_ReadOnly)) + { + kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl; + return false; + } + + QDataStream dstream(&file); + + // BMP files are little-endian + dstream.setByteOrder(QDataStream::LittleEndian); + + // create this now because we output image type early on + KFileMetaInfoGroup group = appendGroup(info, "Technical"); + + + // read the beginning of the file and make sure it looks ok + unsigned char * bmp_id = (unsigned char *) malloc(2); + file.readBlock((char *) bmp_id, 2); + + if (memcmp(bmp_id, bmptype_bm, 2) == 0) { + appendItem(group, "Type", i18n("Windows Bitmap")); + } else if (memcmp(bmp_id, bmptype_ba, 2) == 0) { + appendItem(group, "Type", i18n("OS/2 Bitmap Array")); + } else if (memcmp(bmp_id, bmptype_ci, 2) == 0) { + appendItem(group, "Type", i18n("OS/2 Color Icon")); + } else if (memcmp(bmp_id, bmptype_cp, 2) == 0) { + appendItem(group, "Type", i18n("OS/2 Color Pointer")); + } else if (memcmp(bmp_id, bmptype_ic, 2) == 0) { + appendItem(group, "Type", i18n("OS/2 Icon")); + } else if (memcmp(bmp_id, bmptype_pt, 2) == 0) { + appendItem(group, "Type", i18n("OS/2 Pointer")); + } else { + return false; + } + + free(bmp_id); + + + // read the next bits, we ignore them, but anyways... + uint32_t bmp_size; + uint16_t bmp_reserved1; + uint16_t bmp_reserved2; + uint32_t bmp_offbits; + + dstream >> bmp_size; + dstream >> bmp_reserved1; + dstream >> bmp_reserved2; + dstream >> bmp_offbits; + + + // we should now be at the file info structure + uint32_t bmpi_size; + uint32_t bmpi_width; + uint32_t bmpi_height; + uint16_t bmpi_planes; + uint16_t bmpi_bitcount; + uint32_t bmpi_compression; + + dstream >> bmpi_size; + dstream >> bmpi_width; + dstream >> bmpi_height; + dstream >> bmpi_planes; + dstream >> bmpi_bitcount; + dstream >> bmpi_compression; + + + // output the useful bits + appendItem(group, "Dimensions", QSize(bmpi_width, bmpi_height)); + appendItem(group, "BitDepth", bmpi_bitcount); + + switch (bmpi_compression) { + case 0 : + appendItem(group, "Compression", i18n("None")); + break; + case 1 : + appendItem(group, "Compression", i18n("RLE 8bit/pixel")); + break; + case 2 : + appendItem(group, "Compression", i18n("RLE 4bit/pixel")); + break; + case 3 : + appendItem(group, "Compression", i18n("Bitfields")); + break; + default : + appendItem(group, "Compression", i18n("Unknown")); + } + + return true; +} + +#include "kfile_bmp.moc" diff --git a/kfile-plugins/bmp/kfile_bmp.desktop b/kfile-plugins/bmp/kfile_bmp.desktop new file mode 100644 index 00000000..37b44b42 --- /dev/null +++ b/kfile-plugins/bmp/kfile_bmp.desktop @@ -0,0 +1,66 @@ +[Desktop Entry] +Type=Service +Name=BMP Info +Name[af]=Bmp Inligting +Name[ar]=معلومات BMP +Name[br]=Titouroù BMP +Name[ca]=Informació de BMP +Name[cs]=BMP info +Name[cy]=Gwybodaeth BMP +Name[da]=BMP-info +Name[de]=BMP-Info +Name[el]=Πληροφορίες BMP +Name[eo]=BMP-informo +Name[es]=Info BMP +Name[et]=BMP info +Name[fa]=اطلاعات BMP +Name[fi]=BMP-tiedot +Name[fr]=Informations BMP +Name[ga]=Eolas faoi BMP +Name[gl]=Inf. BMP +Name[he]=מידע BMP +Name[hi]=BMP जानकारी +Name[hr]=BMP informacije +Name[hu]=BMP-jellemzők +Name[is]=BMP upplýsingar +Name[it]=Informazioni BMP +Name[ja]=BMP 情報 +Name[kk]=BMP мәліметі +Name[km]=ព័ត៌មាន BMP +Name[lt]=BMP informacija +Name[ms]=Maklumat BMP +Name[nds]=BMP-Info +Name[ne]=BMP सूचना +Name[nl]=BMP-info +Name[nn]=BMP-info +Name[nso]=Tshedimoso ya BMP +Name[pa]=BMP ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku BMP +Name[pt]=Informação do BMP +Name[pt_BR]=Informação sobre BMP +Name[ro]=Informaţii BMP +Name[ru]=Информация о BMP +Name[se]=BMP-dieđut +Name[sl]=Podatki o BMP +Name[sr]=BMP информације +Name[sr@Latn]=BMP informacije +Name[sv]=BMP-information +Name[ta]=BMP தகவல் +Name[tg]=Иттилоот оиди BMP +Name[th]=ข้อมูลแฟ้ม BMP +Name[tr]=BMP Bilgisi +Name[uk]=Інформація по BMP +Name[uz]=BMP haqida maʼlumot +Name[uz@cyrillic]=BMP ҳақида маълумот +Name[ven]=Mafhungo BMP +Name[wa]=Informåcion sol imådje BMP +Name[xh]=Ulwazi lwe BMP +Name[zh_CN]=BMP 信息 +Name[zh_HK]=BMP 資訊 +Name[zh_TW]=BMP 資訊 +Name[zu]=Ulwazi lwe-BMP +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_bmp +MimeType=image/x-bmp +PreferredGroups=Technical +PreferredItems=Type,Resolution,Bitdepth,Compression diff --git a/kfile-plugins/bmp/kfile_bmp.h b/kfile-plugins/bmp/kfile_bmp.h new file mode 100644 index 00000000..b72ee16d --- /dev/null +++ b/kfile-plugins/bmp/kfile_bmp.h @@ -0,0 +1,37 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Shane Wright + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef __KFILE_BMP_H__ +#define __KFILE_BMP_H__ + +#include + +class QStringList; + +class KBmpPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KBmpPlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo( KFileMetaInfo& info, uint what); +}; + +#endif diff --git a/kfile-plugins/configure.in.bot b/kfile-plugins/configure.in.bot new file mode 100644 index 00000000..47308e8b --- /dev/null +++ b/kfile-plugins/configure.in.bot @@ -0,0 +1,32 @@ +if test -z "$LIBTIFF"; then + echo "" + echo "You're missing libtiff. The additional info plugin for TIFF images" + echo "files won't be compiled without libtiff." + echo "You can download it from http://www.libtiff.org" + echo "" + all_tests=bad +fi + +if test -z "$POPPLER_LIBS"; then + echo "" + echo "You're missing poppler. The additional info plugin for PDF files" + echo "files won't be compiled without poppler >= 0.3.1." + echo "You can download poppler from http://poppler.freedesktop.org/" + echo "" +fi + +if test "$EXRSTATUS" = "no"; then + echo "" + echo "No OpenEXR Libraries were found" + echo "Install the OpenEXR package (from http://www.openexr.org)" + echo "if you want EXR image format support" + echo "" +fi + +if test "$EXRSTATUS" = "old"; then + echo "" + echo "OpenEXR libraries were found, but at least version 1.1.0 is required" + echo "Install a newer OpenEXR package (from http://www.openexr.org)" + echo "if you want EXR image format support" + echo "" +fi diff --git a/kfile-plugins/dds/Makefile.am b/kfile-plugins/dds/Makefile.am new file mode 100644 index 00000000..c3e0382a --- /dev/null +++ b/kfile-plugins/dds/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for dds file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_dds.h + +kde_module_LTLIBRARIES = kfile_dds.la + +kfile_dds_la_SOURCES = kfile_dds.cpp +kfile_dds_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_dds_la_LIBADD = $(LIB_KSYCOCA) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_dds.cpp -o $(podir)/kfile_dds.pot + +services_DATA = kfile_dds.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/dds/kfile_dds.cpp b/kfile-plugins/dds/kfile_dds.cpp new file mode 100644 index 00000000..dd7f8f1e --- /dev/null +++ b/kfile-plugins/dds/kfile_dds.cpp @@ -0,0 +1,317 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Ignacio Castao + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include +#include "kfile_dds.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +typedef KGenericFactory DdsFactory; + +typedef Q_UINT32 uint; +typedef Q_UINT16 ushort; +typedef Q_UINT8 uchar; + +namespace { // Private. + +#if !defined(MAKEFOURCC) +# define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + (uint(uchar(ch0)) | (uint(uchar(ch1)) << 8) | \ + (uint(uchar(ch2)) << 16) | (uint(uchar(ch3)) << 24 )) +#endif + + static const uint FOURCC_DDS = MAKEFOURCC('D', 'D', 'S', ' '); + static const uint FOURCC_DXT1 = MAKEFOURCC('D', 'X', 'T', '1'); + static const uint FOURCC_DXT2 = MAKEFOURCC('D', 'X', 'T', '2'); + static const uint FOURCC_DXT3 = MAKEFOURCC('D', 'X', 'T', '3'); + static const uint FOURCC_DXT4 = MAKEFOURCC('D', 'X', 'T', '4'); + static const uint FOURCC_DXT5 = MAKEFOURCC('D', 'X', 'T', '5'); + static const uint FOURCC_RXGB = MAKEFOURCC('R', 'X', 'G', 'B'); + + static const uint DDSD_CAPS = 0x00000001l; + static const uint DDSD_PIXELFORMAT = 0x00001000l; + static const uint DDSD_WIDTH = 0x00000004l; + static const uint DDSD_HEIGHT = 0x00000002l; + static const uint DDSD_PITCH = 0x00000008l; + + static const uint DDSCAPS_TEXTURE = 0x00001000l; + static const uint DDSCAPS2_VOLUME = 0x00200000l; + static const uint DDSCAPS2_CUBEMAP = 0x00000200l; + + static const uint DDPF_RGB = 0x00000040l; + static const uint DDPF_FOURCC = 0x00000004l; + static const uint DDPF_ALPHAPIXELS = 0x00000001l; + + enum DDSType { + DDS_A8R8G8B8 = 0, + DDS_A1R5G5B5 = 1, + DDS_A4R4G4B4 = 2, + DDS_R8G8B8 = 3, + DDS_R5G6B5 = 4, + DDS_DXT1 = 5, + DDS_DXT2 = 6, + DDS_DXT3 = 7, + DDS_DXT4 = 8, + DDS_DXT5 = 9, + DDS_RXGB = 10, + DDS_UNKNOWN + }; + + + struct DDSPixelFormat { + uint size; + uint flags; + uint fourcc; + uint bitcount; + uint rmask; + uint gmask; + uint bmask; + uint amask; + }; + + QDataStream & operator>> ( QDataStream & s, DDSPixelFormat & pf ) + { + s >> pf.size; + s >> pf.flags; + s >> pf.fourcc; + s >> pf.bitcount; + s >> pf.rmask; + s >> pf.gmask; + s >> pf.bmask; + s >> pf.amask; + return s; + } + + struct DDSCaps { + uint caps1; + uint caps2; + uint caps3; + uint caps4; + }; + + QDataStream & operator>> ( QDataStream & s, DDSCaps & caps ) + { + s >> caps.caps1; + s >> caps.caps2; + s >> caps.caps3; + s >> caps.caps4; + return s; + } + + struct DDSHeader { + uint size; + uint flags; + uint height; + uint width; + uint pitch; + uint depth; + uint mipmapcount; + uint reserved[11]; + DDSPixelFormat pf; + DDSCaps caps; + uint notused; + }; + + QDataStream & operator>> ( QDataStream & s, DDSHeader & header ) + { + s >> header.size; + s >> header.flags; + s >> header.height; + s >> header.width; + s >> header.pitch; + s >> header.depth; + s >> header.mipmapcount; + for( int i = 0; i < 11; i++ ) { + s >> header.reserved[i]; + } + s >> header.pf; + s >> header.caps; + s >> header.notused; + return s; + } + + static bool IsValid( const DDSHeader & header ) + { + if( header.size != 124 ) { + return false; + } + const uint required = (DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|DDSD_PIXELFORMAT); + if( (header.flags & required) != required ) { + return false; + } + if( header.pf.size != 32 ) { + return false; + } + if( !(header.caps.caps1 & DDSCAPS_TEXTURE) ) { + return false; + } + return true; + } + +} // namespace + + + +K_EXPORT_COMPONENT_FACTORY(kfile_dds, DdsFactory( "kfile_dds" )) + +// Constructor, init mime type info. +KDdsPlugin::KDdsPlugin(QObject *parent, const char *name, const QStringList &args) : + KFilePlugin(parent, name, args) +{ + KFileMimeTypeInfo * info = addMimeTypeInfo( "image/x-dds" ); + + KFileMimeTypeInfo::GroupInfo * group = 0L; + + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + + KFileMimeTypeInfo::ItemInfo * item; + + item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size); + setHint(item, KFileMimeTypeInfo::Size); + setUnit(item, KFileMimeTypeInfo::Pixels); + + item = addItemInfo(group, "Depth", i18n("Depth"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::Pixels); + + item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::BitsPerPixel); + + addItemInfo(group, "MipmapCount", i18n("Mipmap Count"), QVariant::Int); + + addItemInfo(group, "Type", i18n("Type"), QVariant::String); + addItemInfo(group, "ColorMode", i18n("Color Mode"), QVariant::String); + addItemInfo(group, "Compression", i18n("Compression"), QVariant::String); +} + +// Read mime type info. +bool KDdsPlugin::readInfo( KFileMetaInfo& info, uint /*what*/) +{ + QFile file(info.path()); + + if (!file.open(IO_ReadOnly)) { + kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl; + return false; + } + + QDataStream s(&file); + s.setByteOrder(QDataStream::LittleEndian); + + // Validate header. + uint fourcc; + s >> fourcc; + if( fourcc != FOURCC_DDS ) { + kdDebug(7034) << QFile::encodeName(info.path()) << " is not a DDS file." << endl; + return false; + } + + // Read image header. + DDSHeader header; + s >> header; + + // Check image file format. + if( s.atEnd() || !IsValid( header ) ) { + kdDebug(7034) << QFile::encodeName(info.path()) << " is not a valid DDS file." << endl; + return false; + } + + // Set file info. + KFileMetaInfoGroup group = appendGroup(info, "Technical"); + appendItem(group, "Dimensions", QSize(header.width, header.height)); + appendItem(group, "MipmapCount", header.mipmapcount); + + // Set file type. + if( header.caps.caps2 & DDSCAPS2_CUBEMAP ) { + appendItem(group, "Type", i18n("Cube Map Texture")); + } + else if( header.caps.caps2 & DDSCAPS2_VOLUME ) { + appendItem(group, "Type", i18n("Volume Texture")); + appendItem(group, "Depth", header.depth); + } + else { + appendItem(group, "Type", i18n("2D Texture")); + } + + // Set file color depth and compression. + if( header.pf.flags & DDPF_RGB ) { + appendItem(group, "BitDepth", header.pf.bitcount); + appendItem(group, "Compression", i18n("Uncompressed")); + if( header.pf.flags & DDPF_ALPHAPIXELS ) { + appendItem(group, "ColorMode", "RGB/Alpha"); + } + else { + appendItem(group, "ColorMode", "RGB"); + } + } + else if( header.pf.flags & DDPF_FOURCC ) { + switch( header.pf.fourcc ) { + case FOURCC_DXT1: + appendItem(group, "BitDepth", 4); + appendItem(group, "Compression", "DXT1"); + appendItem(group, "ColorMode", "RGB"); + break; + case FOURCC_DXT2: + appendItem(group, "BitDepth", 16); + appendItem(group, "Compression", "DXT2"); + appendItem(group, "ColorMode", "RGB/Alpha"); + break; + case FOURCC_DXT3: + appendItem(group, "BitDepth", 16); + appendItem(group, "Compression", "DXT3"); + appendItem(group, "ColorMode", "RGB/Alpha"); + break; + case FOURCC_DXT4: + appendItem(group, "BitDepth", 16); + appendItem(group, "Compression", "DXT4"); + appendItem(group, "ColorMode", "RGB/Alpha"); + break; + case FOURCC_DXT5: + appendItem(group, "BitDepth", 16); + appendItem(group, "Compression", "DXT5"); + appendItem(group, "ColorMode", "RGB/Alpha"); + break; + case FOURCC_RXGB: + appendItem(group, "BitDepth", 16); + appendItem(group, "Compression", "RXGB"); + appendItem(group, "ColorMode", "RGB"); + break; + default: + appendItem(group, "Compression", "Unknown"); + break; + } + } + else { + appendItem(group, "Compression", "Unknown"); + } + + return true; +} + +#include "kfile_dds.moc" + diff --git a/kfile-plugins/dds/kfile_dds.desktop b/kfile-plugins/dds/kfile_dds.desktop new file mode 100644 index 00000000..f6b4ae02 --- /dev/null +++ b/kfile-plugins/dds/kfile_dds.desktop @@ -0,0 +1,53 @@ +[Desktop Entry] +Type=Service +Name=DirectDraw Surface Info +Name[ca]=Informació de superfície DirectDraw +Name[cs]=DirectDraw Surface info +Name[da]=DirectDraw overflade-info +Name[de]=DirectDraw Oberflächeninfo +Name[el]=Πληροφορίες επιφάνειας DirectDraw +Name[eo]=DirectDraw surfac-informo +Name[es]=Información de la primera vista de DirectDraw +Name[et]=DirectDraw Surface'i info +Name[eu]=DirectDraw Surface informazioa +Name[fa]=اطلاعات سطح DirectDraw +Name[fi]=DirectDraw pintatieto +Name[fr]=Informations de surface DirectDraw +Name[ga]=Eolas faoi DirectDraw Surface +Name[gl]=Información de Superficie de DirectDraw +Name[he]=מיגע אודות משטח DirectDraw +Name[hu]=DirectDraw felületinformáció +Name[is]=DirectDraw yfirborðs upplýsingar +Name[it]=Informazioni superficie DirectDraw +Name[ja]=DDS (DirectDraw Surface) 情報 +Name[kk]=DirectDraw бедерінің мәлметі +Name[km]=ព័ត៌មាន​ផ្ទៃ​ខាង​ក្រៅ​អំពី DirectDraw +Name[lt]=DirectDraw Surface informacija +Name[ms]=Maklumat Permukaan LukisTerus +Name[nb]=DirectDraw Overflate info +Name[nds]="DirectDraw"-Böversietinfo +Name[ne]=प्रत्यक्ष रेखाचित्र सतह सूचना +Name[nl]=DirectDraw Surface-info +Name[nn]=DirectDraw-overflateinfo +Name[pl]=Informacja o powierzchni DirectDraw +Name[pt]=Informação de Superfície DirectDraw +Name[pt_BR]=Informações Sobre Superfícies Direct Draw +Name[ro]=Informaţii Suprafaţă DirectDraw +Name[ru]=Сведения о поверхности DirectDraw +Name[sk]=DirectDraw informácie o povrchu +Name[sl]=Podatki o površini DirectDraw +Name[sr]=Информације о DirectDraw површини +Name[sr@Latn]=Informacije o DirectDraw površini +Name[sv]=Directdraw ytinformation +Name[ta]=நேரடி மேற்பரப்பு தகவல் +Name[th]=ข้อมูลแฟ้มพื้นผิว DirectDraw +Name[tr]=DirectDraw Yüzey Bilgisi +Name[uk]=Інформація про поверхню DirectDraw +Name[zh_CN]=DirectDraw 表面信息 +Name[zh_HK]=DirectDraw 表面資訊 +Name[zh_TW]=DirectDraw Surface 資訊 +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_dds +MimeType=image/x-dds +PreferredGroups=Technical +PreferredItems=Dimensions,Depth,BitDepth,Type,ColorMode,Compression diff --git a/kfile-plugins/dds/kfile_dds.h b/kfile-plugins/dds/kfile_dds.h new file mode 100644 index 00000000..342581bb --- /dev/null +++ b/kfile-plugins/dds/kfile_dds.h @@ -0,0 +1,37 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Ignacio Castao + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef __KFILE_DDS_H__ +#define __KFILE_DDS_H__ + +#include + +class QStringList; + +class KDdsPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KDdsPlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo( KFileMetaInfo& info, uint what); +}; + +#endif diff --git a/kfile-plugins/dvi/Makefile.am b/kfile-plugins/dvi/Makefile.am new file mode 100644 index 00000000..61791bdc --- /dev/null +++ b/kfile-plugins/dvi/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for the dvi file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_dvi.h + +kde_module_LTLIBRARIES = kfile_dvi.la + +kfile_dvi_la_SOURCES = kfile_dvi.cpp +kfile_dvi_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_dvi_la_LIBADD = $(LIB_KIO) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_dvi.pot + +services_DATA = kfile_dvi.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/dvi/kfile_dvi.cpp b/kfile-plugins/dvi/kfile_dvi.cpp new file mode 100644 index 00000000..4140b98b --- /dev/null +++ b/kfile-plugins/dvi/kfile_dvi.cpp @@ -0,0 +1,150 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Matthias Witzgall + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + + +/* further informations about the dvi file format could be downloaded from: http://www.rpi.edu/~sofkam/DVI/archive/standards/dvistd0.dvi */ + +#include "kfile_dvi.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +// preprocessormacro K_EXPORT_COMPONENT_FACTORY loads shared library 'kfile_dvi.so' dynamic if necessary +typedef KGenericFactory DviFactory; +K_EXPORT_COMPONENT_FACTORY(kfile_dvi, DviFactory("kfile_dvi")) + +KDviPlugin::KDviPlugin (QObject * parent, const char * name, const QStringList & preferredItems) + : KFilePlugin(parent, name, preferredItems) +{ + kdDebug(7034) << "dvi plugin" << endl; + + // set up our mime type + KFileMimeTypeInfo * info = this->addMimeTypeInfo("application/x-dvi"); + + + KFileMimeTypeInfo::GroupInfo * group = this->addGroupInfo(info, "General", "General"); + + this->addItemInfo(group, "3_Created", i18n("Created"), QVariant::String); + this->addItemInfo(group, "6_Comment", i18n("Comment"), QVariant::String); + this->addItemInfo(group, "7_Pages", i18n("Pages"), QVariant::UInt); +} + +bool KDviPlugin::readInfo (KFileMetaInfo & info, uint /* what (unused in this plugin) */) +{ + if ( info.path().isEmpty() ) + return false; + KFileMetaInfoGroup GeneralGroup = appendGroup(info, "General"); + QFile f(info.path()); + QFileInfo f_info; + Q_UINT16 bytes_to_read; + Q_UINT8 comment_length; + QString comment; + Q_UINT16 pages; + Q_UINT8 buffer[270]; // buffer for reading data; no data is read with more than 270 bytes + Q_UINT32 ptr; + int i; // running index + + // open file and try to get the comment + f.open(IO_ReadOnly); + + if ( f.isOpen() == false ){ + kdDebug(7034) << "cannot open file" << endl; + return false; + } + + f_info.setFile(f); // create fileinfoobject + bytes_to_read = QMIN(f_info.size(), 270); // check, if the file size is smaller than 270 bytes + // (if the comment is as large as possible, we don't have to + // read more than 270 bytes) + + if ( f.readBlock((char *)buffer, bytes_to_read) != bytes_to_read ){ // cast to (char *) is necessary + kdDebug(7034) << "read error (1)" << endl; + return false; + } + + if ( (buffer[0] != 247) || (buffer[1] != 2) ){ + // magic numbers are not right + kdDebug(7034) << "wrong file format" << endl;; + return false; + } + + comment_length = buffer[14]; // set up length of comment + comment.setLength(comment_length); // used to avoid permanent reallocation when extracting the comment from buffer + + for ( i = 15; i <= 14+comment_length; ++i ) // extract comment from buffer + comment[i-15] = (char)buffer[i]; + + appendItem(GeneralGroup, "6_Comment", comment.simplifyWhiteSpace() ); + + // comment is ok, now get total number of pages + f.at( f.size() - 13); + if ( f.readBlock((char *)buffer, 13) != 13 ){ + kdDebug(7034) << "read error (2)" << endl; + return false; + } + + i = 12; // reset running index i + while ( buffer[i] == 223 ){ --i; } // skip all trailing bytes + + if ( (buffer[i] != 2) || (i > 8) || (i < 5) ){ + kdDebug(7034) << "wrong file formatx" << endl; + return false; + } + + // now we know the position of the pointer to the beginning of the postamble and we can read it + ptr = buffer[i-4]; + ptr = (ptr << 8) | buffer[i-3]; + ptr = (ptr << 8) | buffer[i-2]; + ptr = (ptr << 8) | buffer[i-1]; + + // bytes for total number of pages have a offset of 27 to the beginning of the postamble + f.at(ptr + 27); + + // now read total number of pages from file + if ( f.readBlock((char *)buffer, 2) != 2 ){ + kdDebug(7034) << "read error (3)" << endl; + return false; + } + pages = buffer[0]; + pages = (pages << 8) | buffer[1]; + + appendItem(GeneralGroup, "7_Pages", QVariant(pages) ); + + f.close(); + + // now get and set up some basic informations about the file (same informations would be displayed, if there is no dvi-plugin) + appendItem(GeneralGroup, "1_Type", QVariant( i18n("TeX Device Independent file") ) ); // set up type of file + + appendItem(GeneralGroup, "4_Modified", QVariant(f_info.lastModified().toString("yyyy-MM-dd hh:mm")) ); + // ISO 8601 date format (without seconds) + + return true; +} + +#include "kfile_dvi.moc" diff --git a/kfile-plugins/dvi/kfile_dvi.desktop b/kfile-plugins/dvi/kfile_dvi.desktop new file mode 100644 index 00000000..ed640afb --- /dev/null +++ b/kfile-plugins/dvi/kfile_dvi.desktop @@ -0,0 +1,60 @@ +[Desktop Entry] +Icon= +MimeType=application/x-dvi +Name=DVI Info +Name[ar]=معلومات DVI +Name[br]=Titouroù DVI +Name[ca]=Informació de DVI +Name[cs]=DVI info +Name[cy]=Gwybodaeth DVI +Name[da]=DVI-info +Name[de]=DVI-Info +Name[el]=Πληροφορίες DVI +Name[eo]=DVI-informo +Name[es]=Info DVI +Name[et]=DVI info +Name[fa]=اطلاعات DVI +Name[fi]=DVI-tiedot +Name[fr]=Informations DVI +Name[ga]=Eolas faoi DVI +Name[gl]=Inf. DVI +Name[he]=מידע DVI +Name[hi]=DVI जानकारी +Name[hu]=DVI-jellemzők +Name[is]=DVI upplýsingar +Name[it]=Informazioni DVI +Name[ja]=DVI 情報 +Name[kk]=DVI мәліметі +Name[km]=ព័ត៌មាន DVI +Name[lt]=DVI informacija +Name[ms]=Maklumat DVI +Name[nds]=DVI-Info +Name[ne]=DVI सूचना +Name[nl]=DVI-info +Name[nn]=DVI-info +Name[pa]=DVI ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku DVI +Name[pt]=Informação do DVI +Name[pt_BR]=Informação sobre DVI +Name[ro]=Informaţii DVI +Name[ru]=Информация о DVI +Name[se]=DVI-dieđut +Name[sl]=Podatki o DVI +Name[sr]=DVI информације +Name[sr@Latn]=DVI informacije +Name[sv]=DVI-information +Name[ta]=DVI தகவல் +Name[tg]=Иттилоот оиди DVI +Name[th]=ข้อมูลแฟ้ม DVI +Name[tr]=DVI Bilgisi +Name[uk]=Інформація по DVI +Name[uz]=DVI haqida maʼlumot +Name[uz@cyrillic]=DVI ҳақида маълумот +Name[wa]=Informåcion sol documint DVI +Name[zh_CN]=DVI 信息 +Name[zh_HK]=DVI 資訊 +Name[zh_TW]=DVI 資訊 +ServiceTypes=KFilePlugin +Type=Service +X-KDE-Library=kfile_dvi +PreferredItems=Title,Author,Subject,Creator,Producer,CreationDate,ModDate,Keywords diff --git a/kfile-plugins/dvi/kfile_dvi.h b/kfile-plugins/dvi/kfile_dvi.h new file mode 100644 index 00000000..66e7b218 --- /dev/null +++ b/kfile-plugins/dvi/kfile_dvi.h @@ -0,0 +1,37 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Matthias Witzgall + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + + +#ifndef __KFILE_DVI_H__ +#define __KFILE_DVI_H__ + +#include + +class QStringList; + +class KDviPlugin : public KFilePlugin +{ + Q_OBJECT +public: + KDviPlugin ( QObject * parent, const char * name, const QStringList & preferredItems ); + + virtual bool readInfo (KFileMetaInfo & info, uint what); +}; + +#endif diff --git a/kfile-plugins/exr/Makefile.am b/kfile-plugins/exr/Makefile.am new file mode 100644 index 00000000..f337359c --- /dev/null +++ b/kfile-plugins/exr/Makefile.am @@ -0,0 +1,25 @@ +## Makefile.am for EXR file meta info plugin + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) + +# set the include path for X, qt and KDE +INCLUDES = -Drestrict= $(all_includes) $(EXR_FLAGS) +# INCLUDES = $(all_includes) $(EXR_FLAGS) + +# these are the headers for your project +noinst_HEADERS = kfile_exr.h + +kde_module_LTLIBRARIES = kfile_exr.la + +kfile_exr_la_SOURCES = kfile_exr.cpp +kfile_exr_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_exr_la_LIBADD = $(LIB_KIO) $(LIB_EXR) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_exr.pot + +services_DATA = kfile_exr.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/exr/configure.in.in b/kfile-plugins/exr/configure.in.in new file mode 100644 index 00000000..2a9ff5e5 --- /dev/null +++ b/kfile-plugins/exr/configure.in.in @@ -0,0 +1,14 @@ +AC_ARG_WITH([openexr], + [AC_HELP_STRING([--with-openexr], + [Enable support for OpenEXR @<:@default=check@:>@])], + [], with_openexr=check) + +if test "x$with_openexr" != xno; then + KDE_FIND_LIBEXR + + if test "x$with_openexr" != xcheck && test -z "$LIB_EXR"; then + AC_MSG_ERROR([--with-openexr was given, but test for OpenEXR failed]) + fi +fi + +AM_CONDITIONAL(include_EXR_MODULES, test -n "$LIB_EXR") diff --git a/kfile-plugins/exr/kfile_exr.cpp b/kfile-plugins/exr/kfile_exr.cpp new file mode 100644 index 00000000..2e995fc6 --- /dev/null +++ b/kfile-plugins/exr/kfile_exr.cpp @@ -0,0 +1,393 @@ +// -*- C++;indent-tabs-mode: t; tab-width: 4; c-basic-offset: 4; -*- +/* This file is part of the KDE project + * Copyright (C) 2003 + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#include "kfile_exr.h" +using namespace Imf; + +typedef KGenericFactory ExrFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_exr, ExrFactory("kfile_exr")) + +KExrPlugin::KExrPlugin(QObject *parent, const char *name, + const QStringList &args) + : KFilePlugin(parent, name, args) +{ + // set up our mime type + KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-exr" ); + + KFileMimeTypeInfo::GroupInfo* group = 0; + KFileMimeTypeInfo::ItemInfo* item; + + // info group + group = addGroupInfo( info, "Info", i18n("Information") ); + addItemInfo( group, "Version", i18n("Format Version"), QVariant::Int ); + addItemInfo( group, "Tiled image", i18n("Tiled Image"), QVariant::String ); + item = addItemInfo( group, "Dimensions", i18n("Dimensions"), QVariant::Size ); + setHint( item, KFileMimeTypeInfo::Size ); + setUnit( item, KFileMimeTypeInfo::Pixels ); + item = addItemInfo( group, "ThumbnailDimensions", + i18n("Thumbnail Dimensions"), QVariant::Size ); + setHint( item, KFileMimeTypeInfo::Size ); + setUnit( item, KFileMimeTypeInfo::Pixels ); + addItemInfo( group, "Comment", i18n("Comment"), QVariant::String ); + item = addItemInfo( group, "Thumbnail", i18n("Thumbnail"), QVariant::Image ); + setHint( item, KFileMimeTypeInfo::Thumbnail ); + + // standard attributes group + group = addGroupInfo( info, "Standard", i18n("Standard Attributes") ); + addItemInfo( group, "Owner", i18n("Owner"), QVariant::String ); + addItemInfo( group, "Comments", i18n("Comments"), QVariant::String ); + addItemInfo( group, "Capture Date", i18n("Capture Date"), QVariant::String ); + item = addItemInfo( group, "UTC Offset", i18n("UTC Offset"), QVariant::String ); + item = addItemInfo( group, "Exposure time", i18n("Exposure Time"), QVariant::Double); + setUnit( item, KFileMimeTypeInfo::Seconds ); + item = addItemInfo( group, "Focus", i18n("Focus"), QVariant::Double); + setSuffix( item, i18n("Metres", "m") ); + item = addItemInfo( group, "X Density", i18n("X Density"), QVariant::Double); + setSuffix( item, i18n("Pixels Per Inch", " ppi") ); + item = addItemInfo( group, "White luminance", i18n("White Luminance"), QVariant::Double); + setSuffix( item, i18n("Candelas per square metre", " Nits") ); + addItemInfo( group, "Longitude", i18n("Longitude"), QVariant::String ); + addItemInfo( group, "Latitude", i18n("Latitude"), QVariant::String ); + item = addItemInfo( group, "Altitude", i18n("Altitude"), QVariant::String ); + setSuffix( item, i18n("Metres", "m") ); + addItemInfo( group, "ISO speed", i18n("ISO Speed"), QVariant::Double ); + addItemInfo( group, "Aperture", i18n("Aperture"), QVariant::Double ); + + // channel group + group = addGroupInfo( info, "Channel", i18n("Channels") ); + addItemInfo( group, "A", i18n("A"), QVariant::String ); + addItemInfo( group, "R", i18n("R"), QVariant::String ); + addItemInfo( group, "G", i18n("G"), QVariant::String ); + addItemInfo( group, "B", i18n("B"), QVariant::String ); + addItemInfo( group, "Z", i18n("Z"), QVariant::String ); + addItemInfo( group, "NX", i18n("NX"), QVariant::String ); + addItemInfo( group, "NY", i18n("NY"), QVariant::String ); + addItemInfo( group, "NZ", i18n("NZ"), QVariant::String ); + addItemInfo( group, "R", i18n("R"), QVariant::String ); + addItemInfo( group, "U", i18n("U"), QVariant::String ); + addItemInfo( group, "V", i18n("V"), QVariant::String ); + addItemInfo( group, "materialID", i18n("materialID"), QVariant::String ); + addItemInfo( group, "objectID", i18n("objectID"), QVariant::String ); + addItemInfo( group, "renderID", i18n("renderID"), QVariant::String ); + addItemInfo( group, "pixelCover", i18n("pixelCover"), QVariant::String ); + addItemInfo( group, "velX", i18n("velX"), QVariant::String ); + addItemInfo( group, "velY", i18n("velY"), QVariant::String ); + addItemInfo( group, "packedRGBA", i18n("packedRGBA"), QVariant::String ); + + + // technical group + group = addGroupInfo( info, "Technical", i18n("Technical Details") ); + addItemInfo( group, "Compression", i18n("Compression"), QVariant::String ); + addItemInfo( group, "Line Order", i18n("Line Order"), QVariant::String ); + + // 3dsMax group + // This supports a special plugin for 3D Studio Max + group = addGroupInfo( info, "3dsMax", i18n("3dsMax Details") ); + addItemInfo( group, "Local time", i18n("Local Time"), QVariant::String ); + addItemInfo( group, "System time", i18n("System Time"), QVariant::String ); + addItemInfo( group, "Plugin version", i18n("Plugin Version"), QVariant::String ); + addItemInfo( group, "EXR version", i18n("EXR Version"), QVariant::String ); + addItemInfo( group, "Computer name", i18n("Computer Name"), QVariant::String ); +} + +QCString doType( PixelType pt ) +{ + switch (pt) + { + case UINT: + return QCString("32-bit unsigned integer"); + break; + case HALF: + return QCString("16-bit floating-point"); + break; + case FLOAT: + return QCString("32-bit floating-point"); + break; + default: + return QCString(); + break; + } +} + +bool KExrPlugin::readInfo( KFileMetaInfo& info, uint what) +{ + try + { + InputFile in ( info.path().ascii() ); + const Header &h = in.header(); + + KFileMetaInfoGroup infogroup = appendGroup(info, "Info"); + KFileMetaInfoGroup stdgroup = appendGroup(info, "Standard"); + KFileMetaInfoGroup channelgroup = appendGroup(info, "Channel"); + KFileMetaInfoGroup techgroup = appendGroup(info, "Technical"); + KFileMetaInfoGroup threedsmaxgroup = appendGroup(info, "3dsMax"); + + appendItem( infogroup, "Version", getVersion(in.version()) ); + if (isTiled(in.version())) { + appendItem( infogroup, "Tiled image", "yes" ); + } else { + appendItem( infogroup, "Tiled image", "no" ); + } + + Imath::Box2i dw = h.dataWindow(); + appendItem( infogroup, "Dimensions", QSize( (dw.max.x - dw.min.x + 1 ), + (dw.max.y - dw.min.y + 1 ) ) ); + + if ( h.hasPreviewImage() ) { + const PreviewImage &preview = in.header().previewImage(); + appendItem( infogroup, "ThumbnailDimensions", QSize(preview.width(), preview.height()) ); + QImage qpreview(preview.width(), preview.height(), 32, 0, QImage::BigEndian); + for ( unsigned int y=0; y < preview.height(); y++ ) { + for ( unsigned int x=0; x < preview.width(); x++ ) { + const PreviewRgba &q = preview.pixels()[x+(y*preview.width())]; + qpreview.setPixel( x, y, qRgba(q.r, q.g, q.b, q.a) ); + } + } + appendItem( infogroup, "Thumbnail", qpreview); + } + + const StringAttribute *commentSA = h.findTypedAttribute ("comment"); + if (commentSA) { + std::string commentString = commentSA->value(); + QString qcommentString(commentString.data()); + qcommentString.setLength(commentString.size()); + appendItem( infogroup, "Comment", qcommentString ); + } + + // Standard Attributes we are interested in and can + // meaningfully represent. + if ( hasComments(h) ) { + std::string commentsString = comments(h); + QString qcommentsString(commentsString.data()); + qcommentsString.setLength(commentsString.size()); + appendItem( stdgroup, "Comments", qcommentsString ); + } + if ( hasOwner(h) ) { + std::string ownerString = owner(h); + QString qownerString(ownerString.data()); + qownerString.setLength(ownerString.size()); + appendItem( stdgroup, "Owner", qownerString ); + } + if ( hasCapDate(h) ) { + std::string capDateString = capDate(h); + QString qcapDateString(capDateString.data()); + qcapDateString.setLength(capDateString.size()); + appendItem( stdgroup, "Capture Date", qcapDateString ); + } + // This define was introduced in EXR 1.6.0 +#ifndef IMF_B44_COMPRESSION + // This is the 1.4 and earlier version + if ( hasutcOffset(h) ) { +#else + // This is the 1.6.0 and later version + if ( hasUtcOffset(h) ) { +#endif + QString UTCOffset; + if (utcOffset(h)>0.0) { + UTCOffset.append(QString("%1").arg(utcOffset(h)/3600, 0, 'f', 1)); + UTCOffset.append(" hours behind UTC"); + } else { + UTCOffset.append(QString("%1").arg(-1.0*utcOffset(h)/3600, 0, 'f', 1)); + UTCOffset.append(" hours ahead of UTC"); + } + appendItem( stdgroup, "UTC Offset", UTCOffset); + } + if ( hasExpTime(h) ) { + double exposureTime = expTime(h); + appendItem( stdgroup, "Exposure time", exposureTime ); + } + if ( hasFocus(h) ) { + double focusDistance = focus(h); + appendItem( stdgroup, "Focus", focusDistance ); + } + if ( hasXDensity(h) ) { + double XDensity = xDensity(h); + appendItem( stdgroup, "X Density", XDensity ); + } + if ( hasWhiteLuminance(h) ) { + double WhiteLuminance = whiteLuminance(h); + appendItem( stdgroup, "White luminance", WhiteLuminance ); + } + if ( hasLongitude(h) ) { + QString Longitude; + if (longitude(h)<0.0) { + Longitude.append(QString("%1").arg(-1.0*longitude(h),0,'f',3)); + Longitude.append(" deg West"); + } else { + Longitude.append(QString("%1").arg(longitude(h),0,'f',3)); + Longitude.append(" deg East"); + } + appendItem( stdgroup, "Longitude", Longitude); + } + if ( hasLatitude(h) ) { + QString Latitude; + if (latitude(h)<0.0) { + Latitude.append(QString("%1").arg(-1.0*latitude(h),0,'f',3)); + Latitude.append(" deg South"); + } else { + Latitude.append(QString("%1").arg(latitude(h),0,'f',3)); + Latitude.append(" deg North"); + } + appendItem( stdgroup, "Latitude", Latitude ); + } + if ( hasAltitude(h) ) { + double Altitude = altitude(h); + appendItem( stdgroup, "Altitude", QString("%1").arg(Altitude,0,'f',1) ); + } + if ( hasIsoSpeed(h) ) { + double IsoSpeed = isoSpeed(h); + appendItem( stdgroup, "ISO speed", IsoSpeed ); + } + if ( hasAperture(h) ) { + double Aperture = aperture(h); + appendItem( stdgroup, "Aperture", Aperture ); + } + + for (Header::ConstIterator i = h.begin(); i != h.end(); ++i) { + const Attribute *a = &i.attribute(); + + if (const CompressionAttribute *ta = dynamic_cast (a)) { + switch ( ta->value() ) + { + case NO_COMPRESSION: + appendItem( techgroup, "Compression", i18n("No compression")); + break; + case RLE_COMPRESSION: + appendItem( techgroup, "Compression", i18n("Run Length Encoding")); + break; + case ZIPS_COMPRESSION: + appendItem( techgroup, "Compression", i18n("zip, individual scanlines")); + break; + case ZIP_COMPRESSION: + appendItem( techgroup, "Compression", i18n("zip, multi-scanline blocks")); + break; + case PIZ_COMPRESSION: + appendItem( techgroup, "Compression", i18n("piz compression")); + break; + default: + break; + } + } else if (const LineOrderAttribute *ta = dynamic_cast (a)) { + switch (ta->value()) + { + case INCREASING_Y: + appendItem( techgroup, "Line Order", i18n("increasing Y")); + break; + case DECREASING_Y: + appendItem( techgroup, "Line Order", i18n("decreasing Y")); + break; + default: + break; + }; + } else if (const ChannelListAttribute *ta = dynamic_cast (a)) { + + for (ChannelList::ConstIterator i = ta->value().begin(); i != ta->value().end(); ++i) + { + appendItem( channelgroup, i.name(), doType(i.channel().type) ); + } + } + } + + // This section deals with some special case stuff for a 3D Studio Max + // plugin from Splutterfish. The weird construction is an + // attempt to to deal with class conversion. C++ string handling + // without Qt is a pain... + const StringAttribute *ver3DSM = h.findTypedAttribute ("version3dsMax"); + if (ver3DSM) { + std::string ver3DSMstring = ver3DSM->value(); + QString qver3DSMstring(ver3DSMstring.data()); + qver3DSMstring.setLength(ver3DSMstring.size()); + appendItem( threedsmaxgroup, "Plugin version", qver3DSMstring ); + } + const StringAttribute *verEXR = h.findTypedAttribute ("versionEXR"); + if (verEXR) { + std::string verEXRstring = verEXR->value(); + QString qverEXRstring(verEXRstring.data()); + qverEXRstring.setLength(verEXRstring.size()); + appendItem( threedsmaxgroup, "EXR version", QString( verEXRstring.data() ) ); + } + const StringAttribute *localTime = h.findTypedAttribute ("localTime"); + if (localTime) { + std::string localTimeString = localTime->value(); + QString qlocalTimeString(localTimeString.data()); + qlocalTimeString.setLength(localTimeString.size()); + appendItem( threedsmaxgroup, "Local time", qlocalTimeString ); + } + const StringAttribute *systemTime = h.findTypedAttribute ("systemTime"); + if (systemTime) { + std::string systemTimeString = systemTime->value(); + QString qsystemTimeString(systemTimeString.data()); + qsystemTimeString.setLength(systemTimeString.size()); + appendItem( threedsmaxgroup, "System time", qsystemTimeString ); + } + const StringAttribute *computerName = h.findTypedAttribute ("computerName"); + if (computerName) { + std::string computerNameString = computerName->value(); + QString qcomputerNameString(computerNameString.data()); + qcomputerNameString.setLength(computerNameString.size()); + appendItem( threedsmaxgroup, "Computer name", qcomputerNameString ); + } + + return true; + } + catch (const std::exception &e) + { + kdDebug(0) << e.what() << endl; + return false; + } +} + +#include "kfile_exr.moc" diff --git a/kfile-plugins/exr/kfile_exr.desktop b/kfile-plugins/exr/kfile_exr.desktop new file mode 100644 index 00000000..b1b3a583 --- /dev/null +++ b/kfile-plugins/exr/kfile_exr.desktop @@ -0,0 +1,57 @@ +[Desktop Entry] +Type=Service +Name=EXR Info +Name[br]=Titouroù EXR +Name[ca]=Informació EXR +Name[cs]=EXR info +Name[cy]=Gwybodaeth EXR +Name[da]=EXR-Info +Name[de]=EXR-Info +Name[el]=Πληροφορίες EXR +Name[eo]=EXR-informo +Name[es]=Info EXR +Name[et]=EXR info +Name[fa]=اطلاعات EXR +Name[fi]=EXR-tiedot +Name[fr]=Informations EXR +Name[ga]=Eolas faoi EXR +Name[gl]=Inf. EXR +Name[he]=מידע EXR +Name[hu]=EXR-jellemzők +Name[is]=EXR upplýsingar +Name[it]=Informazioni EXR +Name[ja]=EXR 情報 +Name[kk]=EXR мәліметі +Name[km]=ព័ត៌មាន EXR +Name[lt]=EXR informacija +Name[ms]=Maklumat EXR +Name[nds]=EXR-Info +Name[ne]=EXR सूचना +Name[nl]=EXR-info +Name[nn]=EXR-info +Name[pa]=EXR ਜਾਣਕਾਰੀ +Name[pl]=Informacja EXR +Name[pt]=Informação do EXR +Name[pt_BR]=Informação sobre EXR +Name[ro]=Informaţii EXR +Name[ru]=Информация о EXR +Name[se]=EXR-dieđut +Name[sl]=Podatki o EXR +Name[sr]=EXR информације +Name[sr@Latn]=EXR informacije +Name[sv]=EXR-information +Name[ta]=EXR தகவல் +Name[tg]=Иттилоот оиди EXR +Name[th]=ข้อมูลแฟ้ม EXR +Name[tr]=EXR Bilgisi +Name[uk]=Інформація по EXR +Name[uz]=EXR haqida maʼlumot +Name[uz@cyrillic]=EXR ҳақида маълумот +Name[zh_CN]=EXR 信息 +Name[zh_HK]=EXR 資訊 +Name[zh_TW]=EXR 資訊 +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_exr +MimeType=image/x-exr +PreferredGroups=Info,Standard,Channels,Technical,3dsMax +PreferredItems=Dimensions,Thumbnail,ThumbnailDimensions,Version,Comments,Owner,Latitude,Longitude,Altitude,Capture Date,UTC Offset diff --git a/kfile-plugins/exr/kfile_exr.h b/kfile-plugins/exr/kfile_exr.h new file mode 100644 index 00000000..cb795ba5 --- /dev/null +++ b/kfile-plugins/exr/kfile_exr.h @@ -0,0 +1,39 @@ +/* This file is part of the KDE project + * Copyright (C) 2003 + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef __KFILE_EXR_H__ +#define __KFILE_EXR_H__ + +#include +#include + +class QStringList; + +class KExrPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KExrPlugin( QObject *parent, const char *name, const QStringList& preferredItems ); + + virtual bool readInfo( KFileMetaInfo& info, uint ); +}; + +#endif diff --git a/kfile-plugins/gif/Makefile.am b/kfile-plugins/gif/Makefile.am new file mode 100644 index 00000000..b847d002 --- /dev/null +++ b/kfile-plugins/gif/Makefile.am @@ -0,0 +1,24 @@ +## Makefile.am for gif file meta info plugin + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_gif.h + +kde_module_LTLIBRARIES = kfile_gif.la + +kfile_gif_la_SOURCES = kfile_gif.cpp +kfile_gif_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_gif_la_LIBADD = $(LIB_KIO) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_gif.pot + +services_DATA = kfile_gif.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/gif/README b/kfile-plugins/gif/README new file mode 100644 index 00000000..e81cc913 --- /dev/null +++ b/kfile-plugins/gif/README @@ -0,0 +1,10 @@ +The original README for this file read: + +Note: Development of this module has been suspended. +Please feel free to contact me, and pick it up. All I ask +is that you preserve both command line and kfile abilities. Thanks. +bryce@obviously.com + + +I contacted Bryce, but received no response. The command line code +is unchanged - I just fixed the kfile code to work, read only. diff --git a/kfile-plugins/gif/gif-info.1 b/kfile-plugins/gif/gif-info.1 new file mode 100644 index 00000000..6c36b1c4 --- /dev/null +++ b/kfile-plugins/gif/gif-info.1 @@ -0,0 +1,25 @@ +.TH gif-info 1 "April 2002" + +.SH NAME +gif-info \- reads gif image info or sets comment. + +.SH SYNOPSIS +.B gif-info +.RB +['Comment'] + +.SH DESCRIPTION +.LP +.B gif-info +displays information about the given gif (Graphic Interchange Format) image. If a comment is specified, the comment is set instead. +.PP +Write a empty comment ('') to delete the comment block. +.PP +The GIF standard allows any number of 256 byte comment blocks in an image file, but most implementations (including this one) restrict you to just one block. The GIF standard restricts comment blocks to "7 Bit ASCII", but this is widely ignored. You are welcome to store text in your own native language, and are especially encouraged to use comments in utf-8 unicode format. + +.SH "SEE ALSO" +.BR wrjpgcom (1) +.BR rdjpgcom (1) + +.SH AUTHOR +Bryce Nesbitt diff --git a/kfile-plugins/gif/gif-info.c b/kfile-plugins/gif/gif-info.c new file mode 100644 index 00000000..2f64a2f2 --- /dev/null +++ b/kfile-plugins/gif/gif-info.c @@ -0,0 +1,561 @@ +/* +** $Id$ +** +** Minimal GIF parser, for use in extracting and setting metadata. +** Modified for standalone & KDE calling by Bryce Nesbitt +** +** TODO: +** Support gif comments that span more than one comment block. +** Verify that Unicode utf-8 is fully unmolested by this code. +** Implement gif structure verifier. +** +** Based on: GIFtrans v1.12.2 +** Copyright (C) 24.2.94 by Andreas Ley +** +******************************************************************************* +** +** Original distribution site is +** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.c +** A man-page by knordlun@fltxa.helsinki.fi (Kai Nordlund) is at +** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.1 +** An online version by taylor@intuitive.com (Dave Taylor) is at +** http://www.intuitive.com/coolweb/Addons/giftrans-doc.html +** To compile for MS-DOS or OS/2, you need getopt: +** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/getopt.c +** MS-DOS executable can be found at +** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.exe +** OS/2 executable can be found at +** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.os2.exe +** A template rgb.txt for use with the MS-DOS version can be found at +** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/rgb.txt +** Additional info can be found on +** http://melmac.corp.harris.com/transparent_images.html +** +** The GIF file format is documented in +** ftp://ftp.uu.net/doc/literary/obi/Standards/Graphics/Formats/gif89a.doc.Z +** A good quick reference is at: +** http://www.goice.co.jp/member/mo/formats/gif.html +** +******************************************************************************* +** +** 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 +#include +#include +#include +#include +#include +#include + +#define STANDALONE_COMPILE + +extern int set_gif_comment( const char * original_filename, char * comment ); +extern void * get_gif_info( const char * original_filename ); +extern int validate_gif_structure( const char * original_filename ); +int giftrans( FILE * src, FILE * dest); + +#define WARNING_GARBAGE 1 /* Original file had some unspecified content */ +#define ERROR_NOT_A_JPEG 5 /* Original file not a proper jpeg (must be 1st) */ +#define ERROR_TEMP_FILE 6 /* Problem writing temporay file */ +#define ERROR_SCREWUP 7 /* Original file is now damaged. Ooops. */ +#define ERROR_PREMATURE_EOF 8 /* Unexpected end of file */ +#define ERROR_BAD_MARKER 9 /* Marker with illegal length */ +#define ERROR_MARKER_ORDER 10 /* File seems to be mixed up */ + +/*****************************************************************************/ +#ifndef FALSE +#define FALSE (0) /* This is the naked Truth */ +#define TRUE (1) /* and this is the Light */ +#endif + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#define WRITE_BINARY "w" +#else +#ifdef VMS /* VMS is very nonstandard */ +#define READ_BINARY "rb", "ctx=stm" +#define WRITE_BINARY "wb", "ctx=stm" +#else /* standard ANSI-compliant case */ +#define READ_BINARY "rb" +#define WRITE_BINARY "wb" +#endif +#endif + +#define SUCCESS (0) +#define FAILURE (1) + +static char skipcomment,list,verbose,output,debug; +char *global_comment; +static long int pos; + +static char true[] = "True"; +static char false[] = "False"; +static char id[] = "$Id$"; + +/*****************************************************************************/ + +#define readword(buffer) ((buffer)[0]+256*(buffer)[1]) +#define readflag(buffer) ((buffer)?true:false) +#define hex(c) ('a'<=(c)&&(c)<='z'?(c)-'a'+10:'A'<=(c)&&(c)<='Z'?(c)-'A'+10:(c)-'0') + +void dump(adr,data,len) +long int adr; +unsigned char *data; +size_t len; +{ + int i; + + while (len>0) { + (void)fprintf(stderr,"%08lx:%*s",adr,(int)((adr%16)*3+(adr%16>8?1:0)),""); + for (i=adr%16;i<16&&len>0;i++,adr++,data++,len--) + (void)fprintf(stderr,"%s%02x",i==8?" ":" ",*data); + (void)fprintf(stderr,"\n"); + } +} + +void writedata(dest,data,len) +FILE *dest; +unsigned char *data; +size_t len; +{ + unsigned char size; + + while (len) { + size=len<256?len:255; + (void)fwrite((void *)&size,1,1,dest); + (void)fwrite((void *)data,(size_t)size,1,dest); + data+=size; + len-=size; + } + size=0; + (void)fwrite((void *)&size,1,1,dest); +} + +void skipdata(src) +FILE *src; +{ + unsigned char size,buffer[256]; + + do { + pos=ftell(src); + (void)fread((void *)&size,1,1,src); + if (debug) + dump(pos,&size,1); + if (debug) { + pos=ftell(src); + (void)fread((void *)buffer,(size_t)size,1,src); + dump(pos,buffer,(size_t)size); + } + else + (void)fseek(src,(long int)size,SEEK_CUR); + } while (!feof(src)&&size>0); +} + +void transblock(src,dest) +FILE *src; +FILE *dest; +{ + unsigned char size,buffer[256]; + + pos=ftell(src); + (void)fread((void *)&size,1,1,src); + if (debug) + dump(pos,&size,1); + if (output) + (void)fwrite((void *)&size,1,1,dest); + pos=ftell(src); + (void)fread((void *)buffer,(size_t)size,1,src); + if (debug) + dump(pos,buffer,(size_t)size); + if (output) + (void)fwrite((void *)buffer,(size_t)size,1,dest); +} + +void dumpcomment(src) +FILE *src; +{ + unsigned char size,buffer[256]; + size_t i; + + pos=ftell(src); + (void)fread((void *)&size,1,1,src); + if (debug) + dump(pos,&size,1); + (void)fread((void *)buffer,(size_t)size,1,src); + if (debug) + dump(pos+1,buffer,(size_t)size); + for (i=0; i<(size_t)size; i++) + { + if ( buffer[i] >= 0x20 || buffer[i] == '\t' || + buffer[i] =='\r' || buffer[i] == '\n') + (void)putc(buffer[i],stderr); + else + (void)fprintf(stderr,"\\%03o",buffer[i]); + } + (void)fseek(src,(long int)pos,SEEK_SET); +} + +void transdata(src,dest) +FILE *src; +FILE *dest; +{ + unsigned char size,buffer[256]; + + do { + pos=ftell(src); + (void)fread((void *)&size,1,1,src); + if (debug) + dump(pos,&size,1); + if (output) + (void)fwrite((void *)&size,1,1,dest); + pos=ftell(src); + (void)fread((void *)buffer,(size_t)size,1,src); + if (debug) + dump(pos,buffer,(size_t)size); + if (output) + (void)fwrite((void *)buffer,(size_t)size,1,dest); + } while (!feof(src)&&size>0); +} + + +/*****************************************************************************/ + +int giftrans(src,dest) +FILE *src; +FILE *dest; +{ + unsigned char buffer[3*256],lsd[7],gct[3*256]; + unsigned int cnt,cols,size,gct_size; + + /* Header */ + pos=ftell(src); + (void)fread((void *)buffer,6,1,src); + if (strncmp((char *)buffer,"GIF",3)) { + (void)fprintf(stderr,"Not GIF file!\n"); + return(1); + } + if (verbose && debug) { + buffer[6]='\0'; + (void)fprintf(stderr,"Header: \"%s\"\n",buffer); + } + if (debug) + dump(pos,buffer,6); + if (output) { + (void)fwrite((void *)buffer,6,1,dest); + } + + /* Logical Screen Descriptor */ + pos=ftell(src); + (void)fread((void *)lsd,7,1,src); + if (verbose) { + //(void)fprintf(stderr,"Logical Screen Descriptor:\n"); + (void)fprintf(stderr,"Size : %dx%d pixels\n",readword(lsd), readword(lsd+2)); + //(void)fprintf(stderr,"Global Color Table Flag: %s\n",readflag(lsd[4]&0x80)); + (void)fprintf(stderr,"Depth : %d bits\n",(lsd[4]&0x70>>4)+1); + //if (lsd[4]&0x80) { + // (void)fprintf(stderr,"\tSort Flag: %s\n",readflag(lsd[4]&0x8)); + // (void)fprintf(stderr,"\tSize of Global Color Table: %d colors\n",2<<(lsd[4]&0x7)); + // (void)fprintf(stderr,"\tBackground Color Index: %d\n",lsd[5]); + //} + if (lsd[6]) + (void)fprintf(stderr,"Pixel Aspect Ratio: %d (Aspect Ratio %f)\n",lsd[6],((double)lsd[6]+15)/64); + } + if (debug) + dump(pos,lsd,7); + if (output) + (void)fwrite((void *)lsd,7,1,dest); + + /* Global Color Table */ + if (lsd[4]&0x80) { + gct_size=2<<(lsd[4]&0x7); + pos=ftell(src); + (void)fread((void *)gct,gct_size,3,src); + if (output) + (void)fwrite((void *)gct,gct_size,3,dest); + } + + do { + pos=ftell(src); + (void)fread((void *)buffer,1,1,src); + switch (buffer[0]) { + case 0x2c: /* Image Descriptor */ + if (verbose && debug) + (void)fprintf(stderr,"Image Descriptor:\n"); + (void)fread((void *)(buffer+1),9,1,src); + if (debug) + dump(pos,buffer,10); + if (output) + (void)fwrite((void *)buffer,10,1,dest); + /* Local Color Table */ + if (buffer[8]&0x80) { + size=2<<(buffer[8]&0x7); + pos=ftell(src); + (void)fread((void *)buffer,size,3,src); + if (verbose && debug) { + (void)fprintf(stderr,"Local Color Table:\n"); + for(cnt=0;cnt 3) { + fprintf(stderr, "Usage: %s [\"\"]\nReads gif image info or sets comment.\n", progname); + return(5); + } + filename = argv[1]; + comment = argv[2]; + + + /* Check if file is readable... */ + if ((fp = fopen(filename, READ_BINARY)) == NULL) { + fprintf(stderr, "Error: Can't open file '%s'\n", filename); + return(5); + } + fclose(fp); + + /* Check if we really have a commentable image file here... */ + if( validate_gif_structure( filename ) ) { + fprintf(stderr, "Error: error parsing file '%s' as a gif image\n", filename); + return(5); + } + + if( argc == 2 ) { + get_gif_info( filename ); + } + else { + set_gif_comment( filename, comment ); + } + + return( 0 ); +} +#endif + diff --git a/kfile-plugins/gif/kfile_gif.cpp b/kfile-plugins/gif/kfile_gif.cpp new file mode 100644 index 00000000..3c29f05f --- /dev/null +++ b/kfile-plugins/gif/kfile_gif.cpp @@ -0,0 +1,122 @@ +/* + * This file is part of the KDE project, added by Bryce Nesbitt + * + * This is a plugin for Konqeror/KFile which processes 'extra' information + * contained in a .gif image file (In particular the comment, and resolution). + * + ************************************** + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include +#include "kfile_gif.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +typedef KGenericFactory GifFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_gif, GifFactory("kfile_gif")) + +KGifPlugin::KGifPlugin(QObject *parent, const char *name, + const QStringList &args) + : KFilePlugin(parent, name, args) +{ + kdDebug(7034) << "gif KFileMetaInfo plugin\n"; + + KFileMimeTypeInfo* info = addMimeTypeInfo( "image/gif" ); + + KFileMimeTypeInfo::GroupInfo* group = 0L; + + group = addGroupInfo(info, "General", i18n("General")); + + KFileMimeTypeInfo::ItemInfo* item; + + item = addItemInfo(group, "Version", i18n("Version"), QVariant::String); + + item = addItemInfo( group, "Dimensions", i18n("Dimensions"), QVariant::Size ); + setHint( item, KFileMimeTypeInfo::Size ); + setUnit( item, KFileMimeTypeInfo::Pixels ); + + item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::BitsPerPixel); + +} + +bool KGifPlugin::readInfo( KFileMetaInfo& info, uint what ) +{ + Q_UNUSED( what ); + + kdDebug(7034) << "gif KFileMetaInfo readInfo\n"; + + QFile file(info.path()); + + if (!file.open(IO_ReadOnly)) { + kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl; + return false; + } + + QDataStream fstream(&file); + + bool isGIF87a = false; + char magic[7]; + Q_UINT16 width = 0; + Q_UINT16 height = 0; + Q_UINT8 miscInfo = 0; + + fstream.readRawBytes( magic, 6 ); + magic[6] = 0x00; // null terminate + + // I have special requirements... + fstream.setByteOrder( QDataStream::LittleEndian ); + fstream >> width; + fstream >> height; + fstream >> miscInfo; + + KFileMetaInfoGroup group = appendGroup(info, "General"); + + if ( 0 == strncmp( magic, "GIF89a", 6 ) ) { + appendItem( group, "Version", i18n("GIF Version 89a") ); + } else if ( 0 == strncmp( magic, "GIF87a", 6 ) ) { + appendItem( group, "Version", i18n("GIF Version 87a") ); + isGIF87a = true; + } else { + appendItem( group, "Version", i18n("Unknown") ); + } + + appendItem( group, "Dimensions", QSize(width, height) ); + + if ( isGIF87a ) { + appendItem( group, "BitDepth", ( (miscInfo & 0x07) + 1) ); + } + + file.close(); + + return true; +} + +#include "kfile_gif.moc" diff --git a/kfile-plugins/gif/kfile_gif.desktop b/kfile-plugins/gif/kfile_gif.desktop new file mode 100644 index 00000000..8188f60f --- /dev/null +++ b/kfile-plugins/gif/kfile_gif.desktop @@ -0,0 +1,65 @@ +[Desktop Entry] +Type=Service +Name=GIF Info +Name[af]=Gif Inligting +Name[ar]=معلومات GIF +Name[br]=Titouroù GIF +Name[ca]=Informació de GIF +Name[cs]=GIF info +Name[cy]=Gwybodaeth GIF +Name[da]=GIF-info +Name[de]=GIF-Info +Name[el]=Πληροφορίες GIF +Name[eo]=GIF-informo +Name[es]=Info GIF +Name[et]=GIF info +Name[fa]=اطلاعات GIF +Name[fi]=GIF-tiedot +Name[fr]=Informations GIF +Name[ga]=Eolas faoi GIF +Name[gl]=Inf. Gif +Name[he]=מידע GIF +Name[hi]=GIF जानकारी +Name[hr]=GIF Informacije +Name[hu]=GIF-jellemzők +Name[is]=GIF upplýsingar +Name[it]=Informazioni GIF +Name[ja]=GIF 情報 +Name[kk]=GIF мәліметі +Name[km]=ព័ត៌មាន GIF +Name[lt]=GIF informacija +Name[ms]=Maklumat GIF +Name[nds]=GIF-Info +Name[ne]=GIF सूचना +Name[nl]=GIF-info +Name[nn]=GIF-info +Name[nso]=Tshedimoso ya GIF +Name[pa]=GIF ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku GIF +Name[pt]=Informação do GIF +Name[pt_BR]=Informação sobre GIF +Name[ro]=Informaţii GIF +Name[ru]=Информация о GIF +Name[se]=GIF-dieđut +Name[sl]=Podatki o GIF +Name[sr]=GIF информације +Name[sr@Latn]=GIF informacije +Name[sv]=Gif-information +Name[ta]=GIF தகவல் +Name[tg]=Иттилоот оиди GIF +Name[th]=ข้อมูลแฟ้ม GIF +Name[tr]=GIF Bilgisi +Name[uk]=Інформація по GIF +Name[uz]=GIF haqida maʼlumot +Name[uz@cyrillic]=GIF ҳақида маълумот +Name[ven]=Mafhungo a GIF +Name[wa]=Informåcion sol imådje GIF +Name[xh]=Ulwazi lwe GIF +Name[zh_CN]=GIF 信息 +Name[zh_HK]=GIF 資訊 +Name[zh_TW]=GIF 資訊 +Name[zu]=Ulwazi lwe-GIF +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_gif +MimeType=image/gif +PreferredItems=Comment,Resolution diff --git a/kfile-plugins/gif/kfile_gif.h b/kfile-plugins/gif/kfile_gif.h new file mode 100644 index 00000000..6f932f37 --- /dev/null +++ b/kfile-plugins/gif/kfile_gif.h @@ -0,0 +1,37 @@ +/* This file is part of the KDE project + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef __KFILE_GIF_H__ +#define __KFILE_GIF_H__ + +#include +#include + +class QStringList; + +class KGifPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KGifPlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo ( KFileMetaInfo& info, uint what ); +}; + +#endif diff --git a/kfile-plugins/ico/Makefile.am b/kfile-plugins/ico/Makefile.am new file mode 100644 index 00000000..df3d65ca --- /dev/null +++ b/kfile-plugins/ico/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for ico file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_ico.h + +kde_module_LTLIBRARIES = kfile_ico.la + +kfile_ico_la_SOURCES = kfile_ico.cpp +kfile_ico_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_ico_la_LIBADD = $(LIB_KSYCOCA) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_ico.cpp -o $(podir)/kfile_ico.pot + +services_DATA = kfile_ico.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/ico/kfile_ico.cpp b/kfile-plugins/ico/kfile_ico.cpp new file mode 100644 index 00000000..01c5b65e --- /dev/null +++ b/kfile-plugins/ico/kfile_ico.cpp @@ -0,0 +1,148 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Shane Wright + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include +#include "kfile_ico.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if !defined(__osf__) +#include +#else +typedef unsigned long uint32_t; +typedef unsigned short uint16_t; +typedef unsigned char uint8_t; +#endif + +typedef KGenericFactory IcoFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_ico, IcoFactory( "kfile_ico" )) + +KIcoPlugin::KIcoPlugin(QObject *parent, const char *name, + const QStringList &args) + + : KFilePlugin(parent, name, args) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-ico" ); + + KFileMimeTypeInfo::GroupInfo* group = 0L; + + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + + KFileMimeTypeInfo::ItemInfo* item; + + item = addItemInfo(group, "Number", i18n("Number of Icons"), QVariant::Int); + + item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size); + item = addItemInfo(group, "Colors", i18n("Colors"), QVariant::Int); + + item = addItemInfo(group, "DimensionsM", i18n("Dimensions (1st icon)"), QVariant::Size); + item = addItemInfo(group, "ColorsM", i18n("Colors (1st icon)"), QVariant::Int); +} + + +bool KIcoPlugin::readInfo( KFileMetaInfo& info, uint what) +{ + + + QFile file(info.path()); + + if (!file.open(IO_ReadOnly)) + { + kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl; + return false; + } + + QDataStream dstream(&file); + + // ICO files are little-endian + dstream.setByteOrder(QDataStream::LittleEndian); + + + // read the beginning of the file and make sure it looks ok + uint16_t ico_reserved; + uint16_t ico_type; + uint16_t ico_count; + + dstream >> ico_reserved; + dstream >> ico_type; + dstream >> ico_count; + + if ((ico_reserved != 0) || (ico_type != 1) || (ico_count < 1)) + return false; + + + // now loop through each of the icon entries + uint8_t icoe_width; + uint8_t icoe_height; + uint8_t icoe_colorcount; + uint8_t icoe_reserved; + uint16_t icoe_planes; + uint16_t icoe_bitcount; + uint32_t icoe_bytesinres; + uint32_t icoe_imageoffset; + + // read the data on the 1st icon + dstream >> icoe_width; + dstream >> icoe_height; + dstream >> icoe_colorcount; + dstream >> icoe_reserved; + dstream >> icoe_planes; + dstream >> icoe_bitcount; + dstream >> icoe_bytesinres; + dstream >> icoe_imageoffset; + + + // output the useful bits + KFileMetaInfoGroup group = appendGroup(info, "Technical"); + appendItem(group, "Number", ico_count); + + if (ico_count == 1) { + appendItem(group, "Dimensions", QSize(icoe_width, icoe_height)); + + if (icoe_colorcount > 0) + appendItem(group, "Colors", icoe_colorcount); + else if (icoe_bitcount > 0) + appendItem(group, "Colors", 2 ^ icoe_bitcount); + + } else { + + appendItem(group, "DimensionsM", QSize(icoe_width, icoe_height)); + + if (icoe_colorcount > 0) + appendItem(group, "ColorsM", icoe_colorcount); + else if (icoe_bitcount > 0) + appendItem(group, "ColorsM", 2 ^ icoe_bitcount); + + } + + return true; +} + +#include "kfile_ico.moc" diff --git a/kfile-plugins/ico/kfile_ico.desktop b/kfile-plugins/ico/kfile_ico.desktop new file mode 100644 index 00000000..dcd98f50 --- /dev/null +++ b/kfile-plugins/ico/kfile_ico.desktop @@ -0,0 +1,65 @@ +[Desktop Entry] +Type=Service +Name=ICO Info +Name[af]=Ico Inligting +Name[ar]=معلومات ICO +Name[br]=Titouroù ICO +Name[ca]=Informació d'ICO +Name[cs]=ICO info +Name[cy]=Gwybodaeth ICO +Name[da]=ICO-info +Name[de]=ICO-Info +Name[el]=Πληροφορίες ICO +Name[eo]=ICO-informo +Name[es]=Info ICO +Name[et]=ICO info +Name[fa]=اطلاعات ICO +Name[fi]=ICO-tiedot +Name[fr]=Informations ICO +Name[gl]=Inf. ICO +Name[he]=מידע ICO +Name[hi]=ICO जानकारी +Name[hr]=ICO informacije +Name[hu]=ICO-jellemzők +Name[is]=ICO upplýsingar +Name[it]=Informazioni ICO +Name[ja]=ICO 情報 +Name[kk]=ICO мәліметі +Name[km]=ព័ត៌មាន ICO +Name[lt]=ICO informacija +Name[ms]= Maklumat ICO +Name[nds]=ICO-Info +Name[ne]=ICO सूचना +Name[nl]=ICO-info +Name[nn]=ICO-info +Name[nso]=Tshedimoso ya ICO +Name[pa]=ICO ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku ICO +Name[pt]=Informação do ICO +Name[pt_BR]=Informação sobre ICO +Name[ro]=Informaţii ICO +Name[ru]=Информация об ICO +Name[se]=ICO-dieđut +Name[sl]=Podatki o ICO +Name[sr]=ICO информације +Name[sr@Latn]=ICO informacije +Name[sv]=Ico-information +Name[ta]=ICO தகவல் +Name[tg]=Иттилоот оиди ICO +Name[th]=ข้อมูลแฟ้ม ICO +Name[tr]=ICO Bilgisi +Name[uk]=Інформація по ICO +Name[uz]=ICO haqida maʼlumot +Name[uz@cyrillic]=ICO ҳақида маълумот +Name[ven]=Mafhungo a ICO +Name[wa]=Informåcion sol imådjete ICO +Name[xh]=Ulwazi lwe ICO +Name[zh_CN]=ICO 信息 +Name[zh_HK]=ICO 資訊 +Name[zh_TW]=ICO 資訊 +Name[zu]=Ulwazi lwe-ICO +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_ico +MimeType=image/x-ico +PreferredGroups=Technical +PreferredItems=Number,Resolution,Colors,ResolutionM,ColorsM diff --git a/kfile-plugins/ico/kfile_ico.h b/kfile-plugins/ico/kfile_ico.h new file mode 100644 index 00000000..e06e8094 --- /dev/null +++ b/kfile-plugins/ico/kfile_ico.h @@ -0,0 +1,37 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Shane Wright + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef __KFILE_ICO_H__ +#define __KFILE_ICO_H__ + +#include + +class QStringList; + +class KIcoPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KIcoPlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo( KFileMetaInfo& info, uint what); +}; + +#endif diff --git a/kfile-plugins/jpeg/Makefile.am b/kfile-plugins/jpeg/Makefile.am new file mode 100644 index 00000000..fac3b392 --- /dev/null +++ b/kfile-plugins/jpeg/Makefile.am @@ -0,0 +1,24 @@ +## Makefile.am for jpeg file meta info plugin + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_jpeg.h exif.h + +kde_module_LTLIBRARIES = kfile_jpeg.la + +kfile_jpeg_la_SOURCES = kfile_jpeg.cpp exif.cpp kfile_setcomment.cpp +kfile_jpeg_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_jpeg_la_LIBADD = $(LIB_KIO) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_jpeg.pot + +services_DATA = kfile_jpeg.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/jpeg/README b/kfile-plugins/jpeg/README new file mode 100644 index 00000000..6b714426 --- /dev/null +++ b/kfile-plugins/jpeg/README @@ -0,0 +1,35 @@ +------------------------------------------------------------------------------- +Thanks to: +Matthias Wandel +jhead (http://www.sentex.net/~mwandel/jhead/) + +Groult Richard +showimg (http://ric.jalix.org/) + +Bryce Nesbitt for setcomment +based on wrjpgcom.c, Copyright (C) 1994-1997, Thomas G. Lane. + +Frank Pieczynski + +EXIF spec: +http://www.pima.net/standards/it10/PIMA15740/exif.htm +http://www.ba.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html + +------------------------------------------------------------------------------- +Bugs: + 0) Just showing the meta info can cause the file to be rewritten!!! + 1) utf-8 paths must be tested and supported. + 2) Display of EXIF comments need to be tested. + Both Unicode & ASCII need testing. + +New features needed: + 1) Should switch to a multi-line editor for comments. Support "\n". + 2) Should autodetect if the jpeg COM is in utf-8 format. + 3) Allow editing the EXIF "Orientation" flag (without rewriting the exif header). + 4) Extract and return the EXIF thumbnail, oriented properly, as an alternative + to the much slower process of generating a new thumbnail. + +Future features: + 1) Allow the user to erase or move comment in either the EXIF or jpeg COM. + 2) Play or return audio files associated with the exif. + diff --git a/kfile-plugins/jpeg/exif.cpp b/kfile-plugins/jpeg/exif.cpp new file mode 100644 index 00000000..f25e8a78 --- /dev/null +++ b/kfile-plugins/jpeg/exif.cpp @@ -0,0 +1,961 @@ +//-------------------------------------------------------------------------- +// Program to pull the information out of various types of EFIF digital +// camera files and show it in a reasonably consistent way +// +// This module parses the very complicated exif structures. +// +// Matthias Wandel, Dec 1999 - August 2000 +//-------------------------------------------------------------------------- + + +#include "exif.h" +#include +#include + + +static unsigned char * LastExifRefd; +static int ExifSettingsLength; +static double FocalplaneXRes; +static double FocalplaneUnits; +static int MotorolaOrder = 0; +static int SectionsRead; +//static int HaveAll; + +//-------------------------------------------------------------------------- +// Table of Jpeg encoding process names + +#define M_SOF0 0xC0 // Start Of Frame N +#define M_SOF1 0xC1 // N indicates which compression process +#define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use +#define M_SOF3 0xC3 +#define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers +#define M_SOF6 0xC6 +#define M_SOF7 0xC7 +#define M_SOF9 0xC9 +#define M_SOF10 0xCA +#define M_SOF11 0xCB +#define M_SOF13 0xCD +#define M_SOF14 0xCE +#define M_SOF15 0xCF +#define M_SOI 0xD8 // Start Of Image (beginning of datastream) +#define M_EOI 0xD9 // End Of Image (end of datastream) +#define M_SOS 0xDA // Start Of Scan (begins compressed data) +#define M_JFIF 0xE0 // Jfif marker +#define M_EXIF 0xE1 // Exif marker +#define M_COM 0xFE // COMment + + +TagTable_t ProcessTable[] = { + { M_SOF0, "Baseline"}, + { M_SOF1, "Extended sequential"}, + { M_SOF2, "Progressive"}, + { M_SOF3, "Lossless"}, + { M_SOF5, "Differential sequential"}, + { M_SOF6, "Differential progressive"}, + { M_SOF7, "Differential lossless"}, + { M_SOF9, "Extended sequential, arithmetic coding"}, + { M_SOF10, "Progressive, arithmetic coding"}, + { M_SOF11, "Lossless, arithmetic coding"}, + { M_SOF13, "Differential sequential, arithmetic coding"}, + { M_SOF14, "Differential progressive, arithmetic coding"}, + { M_SOF15, "Differential lossless, arithmetic coding"}, + { 0, "Unknown"} +}; + + + +//-------------------------------------------------------------------------- +// Describes format descriptor +static int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8}; +#define NUM_FORMATS 12 + +#define FMT_BYTE 1 +#define FMT_STRING 2 +#define FMT_USHORT 3 +#define FMT_ULONG 4 +#define FMT_URATIONAL 5 +#define FMT_SBYTE 6 +#define FMT_UNDEFINED 7 +#define FMT_SSHORT 8 +#define FMT_SLONG 9 +#define FMT_SRATIONAL 10 +#define FMT_SINGLE 11 +#define FMT_DOUBLE 12 + +//-------------------------------------------------------------------------- +// Describes tag values + +#define TAG_EXIF_OFFSET 0x8769 +#define TAG_INTEROP_OFFSET 0xa005 + +#define TAG_MAKE 0x010F +#define TAG_MODEL 0x0110 +#define TAG_ORIENTATION 0x0112 + +#define TAG_EXPOSURETIME 0x829A +#define TAG_FNUMBER 0x829D + +#define TAG_SHUTTERSPEED 0x9201 +#define TAG_APERTURE 0x9202 +#define TAG_MAXAPERTURE 0x9205 +#define TAG_FOCALLENGTH 0x920A + +#define TAG_DATETIME_ORIGINAL 0x9003 +#define TAG_USERCOMMENT 0x9286 + +#define TAG_SUBJECT_DISTANCE 0x9206 +#define TAG_FLASH 0x9209 + +#define TAG_FOCALPLANEXRES 0xa20E +#define TAG_FOCALPLANEUNITS 0xa210 +#define TAG_EXIF_IMAGEWIDTH 0xA002 +#define TAG_EXIF_IMAGELENGTH 0xA003 + +// the following is added 05-jan-2001 vcs +#define TAG_EXPOSURE_BIAS 0x9204 +#define TAG_WHITEBALANCE 0x9208 +#define TAG_METERING_MODE 0x9207 +#define TAG_EXPOSURE_PROGRAM 0x8822 +#define TAG_ISO_EQUIVALENT 0x8827 +#define TAG_COMPRESSION_LEVEL 0x9102 + +#define TAG_THUMBNAIL_OFFSET 0x0201 +#define TAG_THUMBNAIL_LENGTH 0x0202 + + +/*static TagTable_t TagTable[] = { + { 0x100, "ImageWidth"}, + { 0x101, "ImageLength"}, + { 0x102, "BitsPerSample"}, + { 0x103, "Compression"}, + { 0x106, "PhotometricInterpretation"}, + { 0x10A, "FillOrder"}, + { 0x10D, "DocumentName"}, + { 0x10E, "ImageDescription"}, + { 0x10F, "Make"}, + { 0x110, "Model"}, + { 0x111, "StripOffsets"}, + { 0x112, "Orientation"}, + { 0x115, "SamplesPerPixel"}, + { 0x116, "RowsPerStrip"}, + { 0x117, "StripByteCounts"}, + { 0x11A, "XResolution"}, + { 0x11B, "YResolution"}, + { 0x11C, "PlanarConfiguration"}, + { 0x128, "ResolutionUnit"}, + { 0x12D, "TransferFunction"}, + { 0x131, "Software"}, + { 0x132, "DateTime"}, + { 0x13B, "Artist"}, + { 0x13E, "WhitePoint"}, + { 0x13F, "PrimaryChromaticities"}, + { 0x156, "TransferRange"}, + { 0x200, "JPEGProc"}, + { 0x201, "ThumbnailOffset"}, + { 0x202, "ThumbnailLength"}, + { 0x211, "YCbCrCoefficients"}, + { 0x212, "YCbCrSubSampling"}, + { 0x213, "YCbCrPositioning"}, + { 0x214, "ReferenceBlackWhite"}, + { 0x828D, "CFARepeatPatternDim"}, + { 0x828E, "CFAPattern"}, + { 0x828F, "BatteryLevel"}, + { 0x8298, "Copyright"}, + { 0x829A, "ExposureTime"}, + { 0x829D, "FNumber"}, + { 0x83BB, "IPTC/NAA"}, + { 0x8769, "ExifOffset"}, + { 0x8773, "InterColorProfile"}, + { 0x8822, "ExposureProgram"}, + { 0x8824, "SpectralSensitivity"}, + { 0x8825, "GPSInfo"}, + { 0x8827, "ISOSpeedRatings"}, + { 0x8828, "OECF"}, + { 0x9000, "ExifVersion"}, + { 0x9003, "DateTimeOriginal"}, + { 0x9004, "DateTimeDigitized"}, + { 0x9101, "ComponentsConfiguration"}, + { 0x9102, "CompressedBitsPerPixel"}, + { 0x9201, "ShutterSpeedValue"}, + { 0x9202, "ApertureValue"}, + { 0x9203, "BrightnessValue"}, + { 0x9204, "ExposureBiasValue"}, + { 0x9205, "MaxApertureValue"}, + { 0x9206, "SubjectDistance"}, + { 0x9207, "MeteringMode"}, + { 0x9208, "LightSource"}, + { 0x9209, "Flash"}, + { 0x920A, "FocalLength"}, + { 0x927C, "MakerNote"}, + { 0x9286, "UserComment"}, + { 0x9290, "SubSecTime"}, + { 0x9291, "SubSecTimeOriginal"}, + { 0x9292, "SubSecTimeDigitized"}, + { 0xA000, "FlashPixVersion"}, + { 0xA001, "ColorSpace"}, + { 0xA002, "ExifImageWidth"}, + { 0xA003, "ExifImageLength"}, + { 0xA005, "InteroperabilityOffset"}, + { 0xA20B, "FlashEnergy"}, // 0x920B in TIFF/EP + { 0xA20C, "SpatialFrequencyResponse"}, // 0x920C - - + { 0xA20E, "FocalPlaneXResolution"}, // 0x920E - - + { 0xA20F, "FocalPlaneYResolution"}, // 0x920F - - + { 0xA210, "FocalPlaneResolutionUnit"}, // 0x9210 - - + { 0xA214, "SubjectLocation"}, // 0x9214 - - + { 0xA215, "ExposureIndex"}, // 0x9215 - - + { 0xA217, "SensingMethod"}, // 0x9217 - - + { 0xA300, "FileSource"}, + { 0xA301, "SceneType"}, + { 0, NULL} +} ; +*/ + + +//-------------------------------------------------------------------------- +// Parse the marker stream until SOS or EOI is seen; +//-------------------------------------------------------------------------- +int ExifData::ReadJpegSections (QFile & infile, ReadMode_t ReadMode) +{ + int a; + + a = infile.getch(); + + if (a != 0xff || infile.getch() != M_SOI) { + SectionsRead = 0; + return false; + } + for(SectionsRead = 0; SectionsRead < MAX_SECTIONS-1; ){ + int marker = 0; + int got; + unsigned int ll,lh; + unsigned int itemlen; + uchar * Data; + + for (a=0;a<7;a++){ + marker = infile.getch(); + if (marker != 0xff) break; + + if (a >= 6){ + + kdDebug(7034) << "too many padding bytes\n"; + return false; + + } + } + + if (marker == 0xff){ + // 0xff is legal padding, but if we get that many, something's wrong. + throw FatalError("too many padding bytes!"); + } + + Sections[SectionsRead].Type = marker; + + // Read the length of the section. + lh = (uchar) infile.getch(); + ll = (uchar) infile.getch(); + + itemlen = (lh << 8) | ll; + + if (itemlen < 2) { + throw FatalError("invalid marker"); + } + + Sections[SectionsRead].Size = itemlen; + + Data = (uchar *)malloc(itemlen+1); // Add 1 to allow sticking a 0 at the end. + Sections[SectionsRead].Data = Data; + + // Store first two pre-read bytes. + Data[0] = (uchar)lh; + Data[1] = (uchar)ll; + + got = infile.readBlock((char*)Data+2, itemlen-2); // Read the whole section. + if (( unsigned ) got != itemlen-2){ + throw FatalError("reading from file"); + } + SectionsRead++; + + switch(marker){ + + case M_SOS: // stop before hitting compressed data + // If reading entire image is requested, read the rest of the data. + if (ReadMode & READ_IMAGE){ + unsigned long size; + + size = kMax( 0ul, infile.size()-infile.at() ); + Data = (uchar *)malloc(size); + if (Data == NULL){ + throw FatalError("could not allocate data for entire image"); + } + + got = infile.readBlock((char*)Data, size); + if (( unsigned ) got != size){ + throw FatalError("could not read the rest of the image"); + } + + Sections[SectionsRead].Data = Data; + Sections[SectionsRead].Size = size; + Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER; + SectionsRead ++; + //HaveAll = 1; + } + return true; + + case M_EOI: // in case it's a tables-only JPEG stream + kdDebug(7034) << "No image in jpeg!\n"; + return false; + + case M_COM: // Comment section + // pieczy 2002-02-12 + // now the User comment goes to UserComment + // so we can store a Comment section also in READ_EXIF mode + process_COM(Data, itemlen); + break; + + case M_JFIF: + // Regular jpegs always have this tag, exif images have the exif + // marker instead, althogh ACDsee will write images with both markers. + // this program will re-create this marker on absence of exif marker. + // hence no need to keep the copy from the file. + free(Sections[--SectionsRead].Data); + break; + + case M_EXIF: + // Seen files from some 'U-lead' software with Vivitar scanner + // that uses marker 31 for non exif stuff. Thus make sure + // it says 'Exif' in the section before treating it as exif. + if ((ReadMode & READ_EXIF) && memcmp(Data+2, "Exif", 4) == 0){ + process_EXIF((uchar *)Data, itemlen); // FIXME: This call + // requires Data to be array of at least 8 bytes. Code + // above only checks for itemlen < 2. + }else{ + // Discard this section. + free(Sections[--SectionsRead].Data); + } + break; + + case M_SOF0: + case M_SOF1: + case M_SOF2: + case M_SOF3: + case M_SOF5: + case M_SOF6: + case M_SOF7: + case M_SOF9: + case M_SOF10: + case M_SOF11: + case M_SOF13: + case M_SOF14: + case M_SOF15: + process_SOFn(Data, marker); //FIXME: This call requires Data to + // be array of at least 8 bytes. Code above only checks for + // itemlen < 2. + break; + default: + break; + } + } + return true; +} + + +//-------------------------------------------------------------------------- +// Discard read data. +//-------------------------------------------------------------------------- +void ExifData::DiscardData(void) +{ + for (int a=0; a < SectionsRead; a++) + free(Sections[a].Data); + SectionsRead = 0; +} + +//-------------------------------------------------------------------------- +// Convert a 16 bit unsigned value from file's native byte order +//-------------------------------------------------------------------------- +int ExifData::Get16u(void * Short) +{ + if (MotorolaOrder){ + return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1]; + }else{ + return (((uchar *)Short)[1] << 8) | ((uchar *)Short)[0]; + } +} + +//-------------------------------------------------------------------------- +// Convert a 32 bit signed value from file's native byte order +//-------------------------------------------------------------------------- +int ExifData::Get32s(void * Long) +{ + if (MotorolaOrder){ + return ((( char *)Long)[0] << 24) | (((uchar *)Long)[1] << 16) + | (((uchar *)Long)[2] << 8 ) | (((uchar *)Long)[3] << 0 ); + }else{ + return ((( char *)Long)[3] << 24) | (((uchar *)Long)[2] << 16) + | (((uchar *)Long)[1] << 8 ) | (((uchar *)Long)[0] << 0 ); + } +} + +//-------------------------------------------------------------------------- +// Convert a 32 bit unsigned value from file's native byte order +//-------------------------------------------------------------------------- +unsigned ExifData::Get32u(void * Long) +{ + return (unsigned)Get32s(Long) & 0xffffffff; +} + +//-------------------------------------------------------------------------- +// Evaluate number, be it int, rational, or float from directory. +//-------------------------------------------------------------------------- +double ExifData::ConvertAnyFormat(void * ValuePtr, int Format) +{ + double Value; + Value = 0; + + switch(Format){ + case FMT_SBYTE: Value = *(signed char *)ValuePtr; break; + case FMT_BYTE: Value = *(uchar *)ValuePtr; break; + + case FMT_USHORT: Value = Get16u(ValuePtr); break; + + case FMT_ULONG: Value = Get32u(ValuePtr); break; + + case FMT_URATIONAL: + case FMT_SRATIONAL: + { + int Num,Den; + Num = Get32s(ValuePtr); + Den = Get32s(4+(char *)ValuePtr); + if (Den == 0){ + Value = 0; + }else{ + Value = (double)Num/Den; + } + break; + } + + case FMT_SSHORT: Value = (signed short)Get16u(ValuePtr); break; + case FMT_SLONG: Value = Get32s(ValuePtr); break; + + // Not sure if this is correct (never seen float used in Exif format) + case FMT_SINGLE: Value = (double)*(float *)ValuePtr; break; + case FMT_DOUBLE: Value = *(double *)ValuePtr; break; + } + return Value; +} + +//-------------------------------------------------------------------------- +// Process one of the nested EXIF directories. +//-------------------------------------------------------------------------- +void ExifData::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength, unsigned NestingLevel) +{ + int de; + int a; + int NumDirEntries; + unsigned ThumbnailOffset = 0; + unsigned ThumbnailSize = 0; + + if ( NestingLevel > 4) + throw FatalError("Maximum directory nesting exceeded (corrupt exif header)"); + + NumDirEntries = Get16u(DirStart); + #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry)) + + { + unsigned char * DirEnd; + DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries); + if (DirEnd+4 > (OffsetBase+ExifLength)){ + if (DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength){ + // Version 1.3 of jhead would truncate a bit too much. + // This also caught later on as well. + }else{ + // Note: Files that had thumbnails trimmed with jhead 1.3 or earlier + // might trigger this. + throw FatalError("Illegally sized directory"); + } + } + if (DirEnd < LastExifRefd) LastExifRefd = DirEnd; + } + + for (de=0;de= NUM_FORMATS) { + // (-1) catches illegal zero case as unsigned underflows to positive large. + throw FatalError("Illegal format code in EXIF dir"); + } + + if ((unsigned)Components > 0x10000) { + throw FatalError("Illegal number of components for tag"); + continue; + } + + ByteCount = Components * BytesPerFormat[Format]; + + if (ByteCount > 4){ + unsigned OffsetVal; + OffsetVal = Get32u(DirEntry+8); + // If its bigger than 4 bytes, the dir entry contains an offset. + if (OffsetVal+ByteCount > ExifLength){ + // Bogus pointer offset and / or bytecount value + //printf("Offset %d bytes %d ExifLen %d\n",OffsetVal, ByteCount, ExifLength); + + throw FatalError("Illegal pointer offset value in EXIF"); + } + ValuePtr = OffsetBase+OffsetVal; + }else{ + // 4 bytes or less and value is in the dir entry itself + ValuePtr = (unsigned char *)DirEntry+8; + } + + if (LastExifRefd < ValuePtr+ByteCount){ + // Keep track of last byte in the exif header that was actually referenced. + // That way, we know where the discardable thumbnail data begins. + LastExifRefd = ValuePtr+ByteCount; + } + + // Extract useful components of tag + switch(Tag){ + + case TAG_MAKE: + ExifData::CameraMake = QString::fromLatin1((const char*)ValuePtr, 31); + break; + + case TAG_MODEL: + ExifData::CameraModel = QString::fromLatin1((const char*)ValuePtr, 39); + break; + + case TAG_ORIENTATION: + Orientation = (int)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_DATETIME_ORIGINAL: + DateTime = QString::fromLatin1((const char*)ValuePtr, 19); + break; + + case TAG_USERCOMMENT: + // Olympus has this padded with trailing spaces. Remove these first. + for (a=ByteCount;;){ + a--; + if ((ValuePtr)[a] == ' '){ + (ValuePtr)[a] = '\0'; + }else{ + break; + } + if (a == 0) break; + } + + // Copy the comment + if (memcmp(ValuePtr, "ASCII",5) == 0){ + for (a=5;a<10;a++){ + int c; + c = (ValuePtr)[a]; + if (c != '\0' && c != ' '){ + UserComment = QString::fromLatin1((const char*)(a+ValuePtr), 199); + break; + } + } + }else{ + UserComment = QString::fromLatin1((const char*)ValuePtr, 199); + } + break; + + case TAG_FNUMBER: + // Simplest way of expressing aperture, so I trust it the most. + // (overwrite previously computd value if there is one) + ExifData::ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_APERTURE: + case TAG_MAXAPERTURE: + // More relevant info always comes earlier, so only use this field if we don't + // have appropriate aperture information yet. + if (ExifData::ApertureFNumber == 0){ + ExifData::ApertureFNumber + = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0)*0.5); + } + break; + + case TAG_FOCALLENGTH: + // Nice digital cameras actually save the focal length as a function + // of how far they are zoomed in. + ExifData::FocalLength = (float)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_SUBJECT_DISTANCE: + // Inidcates the distacne the autofocus camera is focused to. + // Tends to be less accurate as distance increases. + ExifData::Distance = (float)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_EXPOSURETIME: + // Simplest way of expressing exposure time, so I trust it most. + // (overwrite previously computd value if there is one) + ExifData::ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_SHUTTERSPEED: + // More complicated way of expressing exposure time, so only use + // this value if we don't already have it from somewhere else. + if (ExifData::ExposureTime == 0){ + ExifData::ExposureTime + = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0))); + } + break; + + case TAG_FLASH: + ExifData::FlashUsed = (int)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_EXIF_IMAGELENGTH: + ExifImageLength = (int)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_EXIF_IMAGEWIDTH: + ExifImageWidth = (int)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_FOCALPLANEXRES: + FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_FOCALPLANEUNITS: + switch((int)ConvertAnyFormat(ValuePtr, Format)){ + case 1: FocalplaneUnits = 25.4; break; // inch + case 2: + // According to the information I was using, 2 means meters. + // But looking at the Cannon powershot's files, inches is the only + // sensible value. + FocalplaneUnits = 25.4; + break; + + case 3: FocalplaneUnits = 10; break; // centimeter + case 4: FocalplaneUnits = 1; break; // milimeter + case 5: FocalplaneUnits = .001; break; // micrometer + } + break; + + // Remaining cases contributed by: Volker C. Schoech (schoech@gmx.de) + + case TAG_EXPOSURE_BIAS: + ExifData::ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_WHITEBALANCE: + ExifData::Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_METERING_MODE: + ExifData::MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_EXPOSURE_PROGRAM: + ExifData::ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_ISO_EQUIVALENT: + ExifData::ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format); + if ( ExifData::ISOequivalent < 50 ) ExifData::ISOequivalent *= 200; + break; + + case TAG_COMPRESSION_LEVEL: + ExifData::CompressionLevel = (int)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_THUMBNAIL_OFFSET: + ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_THUMBNAIL_LENGTH: + ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format); + break; + + } + + if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET){ + unsigned char * SubdirStart; + SubdirStart = OffsetBase + Get32u(ValuePtr); + if (SubdirStart <= OffsetBase || SubdirStart >= OffsetBase+ExifLength){ + throw FatalError("Illegal subdirectory link"); + } + ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1); + continue; + } + } + + { + // In addition to linking to subdirectories via exif tags, + // there's also a potential link to another directory at the end of each + // directory. this has got to be the result of a comitee! + unsigned char * SubdirStart; + unsigned Offset; + + if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength){ + Offset = Get32u(DIR_ENTRY_ADDR(DirStart, NumDirEntries)); + // There is at least one jpeg from an HP camera having an Offset of almost MAXUINT. + // Adding OffsetBase to it produces an overflow, so compare with ExifLength here. + // See http://bugs.kde.org/show_bug.cgi?id=54542 + if (Offset && Offset < ExifLength){ + SubdirStart = OffsetBase + Offset; + if (SubdirStart > OffsetBase+ExifLength){ + if (SubdirStart < OffsetBase+ExifLength+20){ + // Jhead 1.3 or earlier would crop the whole directory! + // As Jhead produces this form of format incorrectness, + // I'll just let it pass silently + kdDebug(7034) << "Thumbnail removed with Jhead 1.3 or earlier\n"; + }else{ + throw FatalError("Illegal subdirectory link 2"); + } + }else{ + if (SubdirStart <= OffsetBase+ExifLength){ + ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1); + } + } + } + }else{ + // The exif header ends before the last next directory pointer. + } + } + + if (ThumbnailSize && ThumbnailOffset){ + if (ThumbnailSize + ThumbnailOffset < ExifLength){ + // The thumbnail pointer appears to be valid. Store it. + Thumbnail.loadFromData(OffsetBase + ThumbnailOffset, ThumbnailSize, "JPEG"); + } + } +} + +//-------------------------------------------------------------------------- +// Process a COM marker. We want to leave the bytes unchanged. The +// progam that displays this text may decide to remove blanks, convert +// newlines, or otherwise modify the text. In particular we want to be +// safe for passing utf-8 text. +//-------------------------------------------------------------------------- +void ExifData::process_COM (const uchar * Data, int length) +{ + Comment = QString::fromUtf8((char *)Data+2, (length-2)); +} + + +//-------------------------------------------------------------------------- +// Process a SOFn marker. This is useful for the image dimensions +//-------------------------------------------------------------------------- +void ExifData::process_SOFn (const uchar * Data, int marker) +{ + int data_precision, num_components; + + data_precision = Data[2]; + ExifData::Height = Get16m(Data+3); + ExifData::Width = Get16m(Data+5); + num_components = Data[7]; + + if (num_components == 3){ + ExifData::IsColor = 1; + }else{ + ExifData::IsColor = 0; + } + + ExifData::Process = marker; + +} + +//-------------------------------------------------------------------------- +// Get 16 bits motorola order (always) for jpeg header stuff. +//-------------------------------------------------------------------------- +int ExifData::Get16m(const void * Short) +{ + return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1]; +} + + +//-------------------------------------------------------------------------- +// Process a EXIF marker +// Describes all the drivel that most digital cameras include... +//-------------------------------------------------------------------------- +void ExifData::process_EXIF(unsigned char * CharBuf, unsigned int length) +{ + ExifData::FlashUsed = 0; // If it s from a digicam, and it used flash, it says so. + + FocalplaneXRes = 0; + FocalplaneUnits = 0; + ExifImageWidth = 0; + ExifImageLength = 0; + + { // Check the EXIF header component + static const uchar ExifHeader[] = "Exif\0\0"; + if (memcmp(CharBuf+2, ExifHeader,6)){ + throw FatalError("Incorrect Exif header"); + } + } + + if (memcmp(CharBuf+8,"II",2) == 0){ + // printf("Exif section in Intel order\n"); + MotorolaOrder = 0; + }else{ + if (memcmp(CharBuf+8,"MM",2) == 0){ + // printf("Exif section in Motorola order\n"); + MotorolaOrder = 1; + }else{ + throw FatalError("Invalid Exif alignment marker."); + } + } + + // Check the next two values for correctness. + if (Get16u(CharBuf+10) != 0x2a){ + throw FatalError("Invalid Exif start (1)"); + } + + long IFDoffset = Get32u(CharBuf+12); + + LastExifRefd = CharBuf; + + // First directory starts 16 bytes in. Offsets start at 8 bytes in. + ProcessExifDir(&CharBuf[8+IFDoffset], CharBuf+8, length-6, 0); + + // This is how far the interesting (non thumbnail) part of the exif went. + ExifSettingsLength = LastExifRefd - CharBuf; + + // Compute the CCD width, in milimeters. + if (FocalplaneXRes != 0){ + kdDebug(7034) << "ExifImageWidth " << ExifImageWidth << " FocalplaneUnits " << FocalplaneUnits << " FocalplaneXRes " << FocalplaneXRes << endl; + ExifData::CCDWidth = (float)(ExifImageWidth * FocalplaneUnits / FocalplaneXRes); + } +} + +//-------------------------------------------------------------------------- +// Convert exif time to Unix time structure +//-------------------------------------------------------------------------- +int ExifData::Exif2tm(struct tm * timeptr, char * ExifTime) +{ + int a; + + timeptr->tm_wday = -1; + + // Check for format: YYYY:MM:DD HH:MM:SS format. + a = sscanf(ExifTime, "%d:%d:%d %d:%d:%d", + &timeptr->tm_year, &timeptr->tm_mon, &timeptr->tm_mday, + &timeptr->tm_hour, &timeptr->tm_min, &timeptr->tm_sec); + + if (a == 6){ + timeptr->tm_isdst = -1; + timeptr->tm_mon -= 1; // Adjust for unix zero-based months + timeptr->tm_year -= 1900; // Adjust for year starting at 1900 + return true; // worked. + } + + return false; // Wasn't in Exif date format. +} + +//-------------------------------------------------------------------------- +// Contructor for initialising +//-------------------------------------------------------------------------- +ExifData::ExifData() +{ + ExifData::Whitebalance = -1; + ExifData::MeteringMode = -1; + ExifData::FlashUsed = 0; + Orientation = 0; + Height = 0; + Width = 0; + IsColor = 0; + Process = 0; + FocalLength = 0; + ExposureTime = 0; + ApertureFNumber = 0; + Distance = 0; + CCDWidth = 0; + ExposureBias = 0; + ExposureProgram = 0; + ISOequivalent = 0; + CompressionLevel = 0; +} + +//-------------------------------------------------------------------------- +// process a EXIF jpeg file +//-------------------------------------------------------------------------- +bool ExifData::scan(const QString & path) +{ + int ret; + + QFile f(path); + if ( !f.open(IO_ReadOnly) ) + return false; + + try { + // Scan the JPEG headers. + ret = ReadJpegSections(f, READ_EXIF); + } + catch (FatalError& e) { + e.debug_print(); + f.close(); + return false; + } + + if (ret == false){ + kdDebug(7034) << "Not JPEG file!\n"; + DiscardData(); + f.close(); + return false; + } + f.close(); + DiscardData(); + + //now make the strings clean, + // for exmaple my Casio is a "QV-4000 " + CameraMake = CameraMake.stripWhiteSpace(); + CameraModel = CameraModel.stripWhiteSpace(); + UserComment = UserComment.stripWhiteSpace(); + Comment = Comment.stripWhiteSpace(); + return true; +} + +//-------------------------------------------------------------------------- +// Does the embedded thumbnail match the jpeg image? +//-------------------------------------------------------------------------- +#ifndef JPEG_TOL +#define JPEG_TOL 0.02 +#endif +bool ExifData::isThumbnailSane() { + if (Thumbnail.isNull()) return false; + + // check whether thumbnail dimensions match the image + // not foolproof, but catches some altered images (jpegtran -rotate) + if (ExifImageLength != 0 && ExifImageLength != Height) return false; + if (ExifImageWidth != 0 && ExifImageWidth != Width) return false; + if (Thumbnail.width() == 0 || Thumbnail.height() == 0) return false; + if (Height == 0 || Width == 0) return false; + double d = (double)Height/Width*Thumbnail.width()/Thumbnail.height(); + return (1-JPEG_TOL < d) && (d < 1+JPEG_TOL); +} + + +//-------------------------------------------------------------------------- +// return a thumbnail that respects the orientation flag +// only if it seems sane +//-------------------------------------------------------------------------- +QImage ExifData::getThumbnail() { + if (!isThumbnailSane()) return NULL; + if (!Orientation || Orientation == 1) return Thumbnail; + + // now fix orientation + QWMatrix M; + QWMatrix flip= QWMatrix(-1,0,0,1,0,0); + switch (Orientation) { // notice intentional fallthroughs + case 2: M = flip; break; + case 4: M = flip; + case 3: M.rotate(180); break; + case 5: M = flip; + case 6: M.rotate(90); break; + case 7: M = flip; + case 8: M.rotate(270); break; + default: break; // should never happen + } + return Thumbnail.xForm(M); +} diff --git a/kfile-plugins/jpeg/exif.h b/kfile-plugins/jpeg/exif.h new file mode 100644 index 00000000..2b4e5606 --- /dev/null +++ b/kfile-plugins/jpeg/exif.h @@ -0,0 +1,127 @@ +#ifndef __EXIF_H__ +#define __EXIF_H__ + +/** + exif.h +*/ + +#include +#include +#include +#include + +#include "qstring.h" +#include "qfile.h" +#include "qimage.h" +#include + +typedef enum { + READ_EXIF = 1, + READ_IMAGE = 2, + READ_ALL = 3 +}ReadMode_t; + +//-------------------------------------------------------------------------- +// This structure is used to store jpeg file sections in memory. +typedef struct { + uchar * Data; + int Type; + unsigned Size; +}Section_t; + +typedef unsigned char uchar; + +typedef struct { + unsigned short Tag; + const char*const Desc; +}TagTable_t; + +#define MAX_SECTIONS 20 +#define PSEUDO_IMAGE_MARKER 0x123; // Extra value. + +class ExifData { + Section_t Sections[MAX_SECTIONS]; + + QString CameraMake; + QString CameraModel; + QString DateTime; + int Orientation; + int Height, Width; + int ExifImageLength, ExifImageWidth; + int IsColor; + int Process; + int FlashUsed; + float FocalLength; + float ExposureTime; + float ApertureFNumber; + float Distance; + int Whitebalance; + int MeteringMode; + float CCDWidth; + float ExposureBias; + int ExposureProgram; + int ISOequivalent; + int CompressionLevel; + QString UserComment; + QString Comment; + QImage Thumbnail; + + int ReadJpegSections (QFile & infile, ReadMode_t ReadMode); + void DiscardData(void); + int Get16u(void * Short); + int Get32s(void * Long); + unsigned Get32u(void * Long); + double ConvertAnyFormat(void * ValuePtr, int Format); + void ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength, + unsigned NestingLevel); + void process_COM (const uchar * Data, int length); + void process_SOFn (const uchar * Data, int marker); + int Get16m(const void * Short); + void process_EXIF(unsigned char * CharBuf, unsigned int length); + int Exif2tm(struct tm * timeptr, char * ExifTime); + +public: + ExifData(); + bool scan(const QString &); + QString getCameraMake() { return CameraMake; } + QString getCameraModel() { return CameraModel; } + QString getDateTime() { return DateTime; } + int getOrientation() { return Orientation; } + int getHeight() { return Height; } + int getWidth() { return Width; } + int getIsColor() { return IsColor; } + int getProcess() { return Process; } + int getFlashUsed() { return FlashUsed; } + float getFocalLength() { return FocalLength; } + float getExposureTime() { return ExposureTime; } + float getApertureFNumber() { return ApertureFNumber; } + float getDistance() { return Distance; } + int getWhitebalance() { return Whitebalance; } + int getMeteringMode() { return MeteringMode; } + float getCCDWidth() { return CCDWidth; } + float getExposureBias() { return ExposureBias; } + int getExposureProgram() { return ExposureProgram; } + int getISOequivalent() { return ISOequivalent; } + int getCompressionLevel() { return CompressionLevel; } + QString getUserComment() { return UserComment; } + QString getComment() { return Comment; } + QImage getThumbnail(); + bool isThumbnailSane(); + bool isNullThumbnail() { return !isThumbnailSane(); } +}; + +class FatalError { + const char* ex; +public: + FatalError(const char* s) { ex = s; } + void debug_print() const { kdDebug(7034) << "exception: " << ex << endl; } +}; + +extern TagTable_t ProcessTable[]; + +//-------------------------------------------------------------------------- +// Define comment writing code, impelemented in setcomment.c +extern int safe_copy_and_modify( const char * original_filename, const char * comment ); + +#endif + diff --git a/kfile-plugins/jpeg/kfile_jpeg.cpp b/kfile-plugins/jpeg/kfile_jpeg.cpp new file mode 100644 index 00000000..d302cf65 --- /dev/null +++ b/kfile-plugins/jpeg/kfile_jpeg.cpp @@ -0,0 +1,531 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Frank Pieczynski , + * 2002 Carsten Pfeiffer + * based on the jhead tool of Matthias Wandel (see below) + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + + +#include +#include "kfile_jpeg.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "exif.h" + +#define EXIFGROUP "Jpeg EXIF Data" + +typedef KGenericFactory JpegFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_jpeg, JpegFactory("kfile_jpeg")) + +KJpegPlugin::KJpegPlugin(QObject *parent, const char *name, + const QStringList &args ) + : KFilePlugin(parent, name, args) +{ + kdDebug(7034) << "jpeg plugin\n"; + + // + // define all possible meta info items + // + KFileMimeTypeInfo *info = addMimeTypeInfo("image/jpeg"); + KFileMimeTypeInfo::GroupInfo *exifGroup = addGroupInfo( info, EXIFGROUP, + i18n("JPEG Exif") ); + KFileMimeTypeInfo::ItemInfo* item; + + item = addItemInfo( exifGroup, "Comment", i18n("Comment"), QVariant::String); + setAttributes( item, + KFileMimeTypeInfo::Modifiable | + KFileMimeTypeInfo::Addable | + KFileMimeTypeInfo::MultiLine ); + + item = addItemInfo( exifGroup, "Manufacturer", i18n("Camera Manufacturer"), + QVariant::String ); + + item = addItemInfo( exifGroup, "Model", i18n("Camera Model"), + QVariant::String ); + + item = addItemInfo( exifGroup, "Date/time", i18n("Date/Time"), + QVariant::DateTime ); + + item = addItemInfo( exifGroup, "CreationDate", i18n("Creation Date"), + QVariant::Date ); + + item = addItemInfo( exifGroup, "CreationTime", i18n("Creation Time"), + QVariant::Time ); + + item = addItemInfo( exifGroup, "Dimensions", i18n("Dimensions"), + QVariant::Size ); + setHint( item, KFileMimeTypeInfo::Size ); + setUnit( item, KFileMimeTypeInfo::Pixels ); + + item = addItemInfo( exifGroup, "Orientation", i18n("Orientation"), + QVariant::Int ); + + item = addItemInfo( exifGroup, "ColorMode", i18n("Color Mode"), + QVariant::String ); + + item = addItemInfo( exifGroup, "Flash used", i18n("Flash Used"), + QVariant::String ); + item = addItemInfo( exifGroup, "Focal length", i18n("Focal Length"), + QVariant::String ); + setUnit( item, KFileMimeTypeInfo::Millimeters ); + + item = addItemInfo( exifGroup, "35mm equivalent", i18n("35mm Equivalent"), + QVariant::Int ); + setUnit( item, KFileMimeTypeInfo::Millimeters ); + + item = addItemInfo( exifGroup, "CCD width", i18n("CCD Width"), + QVariant::String ); + setUnit( item, KFileMimeTypeInfo::Millimeters ); + + item = addItemInfo( exifGroup, "Exposure time", i18n("Exposure Time"), + QVariant::String ); + setHint( item, KFileMimeTypeInfo::Seconds ); + + item = addItemInfo( exifGroup, "Aperture", i18n("Aperture"), + QVariant::String ); + + item = addItemInfo( exifGroup, "Focus dist.", i18n("Focus Dist."), + QVariant::String ); + + item = addItemInfo( exifGroup, "Exposure bias", i18n("Exposure Bias"), + QVariant::String ); + + item = addItemInfo( exifGroup, "Whitebalance", i18n("Whitebalance"), + QVariant::String ); + + item = addItemInfo( exifGroup, "Metering mode", i18n("Metering Mode"), + QVariant::String ); + + item = addItemInfo( exifGroup, "Exposure", i18n("Exposure"), + QVariant::String ); + + item = addItemInfo( exifGroup, "ISO equiv.", i18n("ISO Equiv."), + QVariant::String ); + + item = addItemInfo( exifGroup, "JPEG quality", i18n("JPEG Quality"), + QVariant::String ); + + item = addItemInfo( exifGroup, "User comment", i18n("User Comment"), + QVariant::String ); + setHint(item, KFileMimeTypeInfo::Description); + + item = addItemInfo( exifGroup, "JPEG process", i18n("JPEG Process"), + QVariant::String ); + + item = addItemInfo( exifGroup, "Thumbnail", i18n("Thumbnail"), + QVariant::Image ); + setHint( item, KFileMimeTypeInfo::Thumbnail ); + +// ### +// exifGroup.setSupportsVariableKeys(true); +} + +QValidator* KJpegPlugin::createValidator(const KFileMetaInfoItem& /*item*/, + QObject */*parent*/, + const char */*name*/ ) const +{ + // no need to return a validator that validates everything as OK :) +// if (item.isEditable()) +// return new QRegExpValidator(QRegExp(".*"), parent, name); +// else + return 0L; +} + +bool KJpegPlugin::writeInfo( const KFileMetaInfo& info ) const +{ + QString comment = info[EXIFGROUP].value("Comment").toString(); + QString path = info.path(); + + kdDebug(7034) << "exif writeInfo: " << info.path() << " \"" << comment << "\"\n"; + + /* + Do a strictly safe insertion of the comment: + + Scan original to verify it's a proper jpeg + Open a unique temporary file in this directory + Write temporary, replacing all COM blocks with this one. + Scan temporary, to verify it's a proper jpeg + Rename original to another unique name + Rename temporary to original + Unlink original + */ + /* + The jpeg standard does not regulate the contents of the COM block. + I'm assuming the best thing to do here is write as unicode utf-8, + which is fully backwards compatible with readers expecting ascii. + Readers expecting a national character set are out of luck... + */ + if( safe_copy_and_modify( QFile::encodeName( path ), comment.utf8() ) ) { + return false; + } + return true; +} + +bool KJpegPlugin::readInfo( KFileMetaInfo& info, uint what ) +{ + const QString path( info.path() ); + if ( path.isEmpty() ) // remote file + return false; + + QString tag; + ExifData ImageInfo; + + // parse the jpeg file now + try { + if ( !ImageInfo.scan(info.path()) ) { + kdDebug(7034) << "Not a JPEG file!\n"; + return false; + } + } + catch (FatalError& e) { // malformed exif data? + kdDebug(7034) << "Exception caught while parsing Exif data of: " << info.path() << endl; + e.debug_print(); + return false; + } + + KFileMetaInfoGroup exifGroup = appendGroup( info, EXIFGROUP ); + + tag = ImageInfo.getComment(); + if ( tag.length() ) { + kdDebug(7034) << "exif inserting Comment: " << tag << "\n"; + appendItem( exifGroup, "Comment", tag ); + } else { + appendItem( exifGroup, "Comment", tag ); // So user can add new comment + } + + tag = ImageInfo.getCameraMake(); + if (tag.length()) + appendItem( exifGroup, "Manufacturer", tag ); + + tag = ImageInfo.getCameraModel(); + if (tag.length()) + appendItem( exifGroup, "Model", tag ); + + tag = ImageInfo.getDateTime(); + if (tag.length()){ + QDateTime dt = parseDateTime( tag.stripWhiteSpace() ); + if ( dt.isValid() ) { + appendItem( exifGroup, "Date/time", dt ); + appendItem( exifGroup, "CreationDate", dt.date() ); + appendItem( exifGroup, "CreationTime", dt.time() ); + } + } + + appendItem( exifGroup,"Dimensions", QSize( ImageInfo.getWidth(), + ImageInfo.getHeight() ) ); + + if ( ImageInfo.getOrientation() ) + appendItem( exifGroup, "Orientation", ImageInfo.getOrientation() ); + + appendItem( exifGroup, "ColorMode", ImageInfo.getIsColor() ? + i18n("Color") : i18n("Black and white") ); + + int flashUsed = ImageInfo.getFlashUsed(); // -1, + if ( flashUsed >= 0 ) { + QString flash = i18n("Flash", "(unknown)"); + switch ( flashUsed ) { + case 0: flash = i18n("Flash", "No"); + break; + case 1: + case 5: + case 7: + flash = i18n("Flash", "Fired"); + break; + case 9: + case 13: + case 15: + flash = i18n( "Flash", "Fill Fired" ); + break; + case 16: + flash = i18n( "Flash", "Off" ); + break; + case 24: + flash = i18n( "Flash", "Auto Off" ); + break; + case 25: + case 29: + case 31: + flash = i18n( "Flash", "Auto Fired" ); + break; + case 32: + flash = i18n( "Flash", "Not Available" ); + break; + default: + break; + } + appendItem( exifGroup, "Flash used", + flash ); + } + + if (ImageInfo.getFocalLength()){ + appendItem( exifGroup, "Focal length", + QString().sprintf("%4.1f", ImageInfo.getFocalLength()) ); + + if (ImageInfo.getCCDWidth()){ + appendItem( exifGroup, "35mm equivalent", + (int)(ImageInfo.getFocalLength()/ImageInfo.getCCDWidth()*35 + 0.5) ); + } + } + + if (ImageInfo.getCCDWidth()){ + appendItem( exifGroup, "CCD width", + QString().sprintf("%4.2f", ImageInfo.getCCDWidth()) ); + } + + if (ImageInfo.getExposureTime()){ + tag=QString().sprintf("%6.3f", ImageInfo.getExposureTime()); + float exposureTime = ImageInfo.getExposureTime(); + if (exposureTime > 0 && exposureTime <= 0.5){ + tag+=QString().sprintf(" (1/%d)", (int)(0.5 + 1/exposureTime) ); + } + appendItem( exifGroup, "Exposure time", tag ); + } + + if (ImageInfo.getApertureFNumber()){ + appendItem( exifGroup, "Aperture", + QString().sprintf("f/%3.1f", + (double)ImageInfo.getApertureFNumber())); + } + + if (ImageInfo.getDistance()){ + if (ImageInfo.getDistance() < 0){ + tag=i18n("Infinite"); + }else{ + tag=QString().sprintf("%5.2fm",(double)ImageInfo.getDistance()); + } + appendItem( exifGroup, "Focus dist.", tag ); + } + + if (ImageInfo.getExposureBias()){ + appendItem( exifGroup, "Exposure bias", + QString().sprintf("%4.2f", + (double)ImageInfo.getExposureBias()) ); + } + + if (ImageInfo.getWhitebalance() != -1){ + switch(ImageInfo.getWhitebalance()) { + case 0: + tag=i18n("Unknown"); + break; + case 1: + tag=i18n("Daylight"); + break; + case 2: + tag=i18n("Fluorescent"); + break; + case 3: + //tag=i18n("incandescent"); + tag=i18n("Tungsten"); + break; + case 17: + tag=i18n("Standard light A"); + break; + case 18: + tag=i18n("Standard light B"); + break; + case 19: + tag=i18n("Standard light C"); + break; + case 20: + tag=i18n("D55"); + break; + case 21: + tag=i18n("D65"); + break; + case 22: + tag=i18n("D75"); + break; + case 255: + tag=i18n("Other"); + break; + default: + //23 to 254 = reserved + tag=i18n("Unknown"); + } + appendItem( exifGroup, "Whitebalance", tag ); + } + + if (ImageInfo.getMeteringMode() != -1){ + switch(ImageInfo.getMeteringMode()) { + case 0: + tag=i18n("Unknown"); + break; + case 1: + tag=i18n("Average"); + break; + case 2: + tag=i18n("Center weighted average"); + break; + case 3: + tag=i18n("Spot"); + break; + case 4: + tag=i18n("MultiSpot"); + break; + case 5: + tag=i18n("Pattern"); + break; + case 6: + tag=i18n("Partial"); + break; + case 255: + tag=i18n("Other"); + break; + default: + // 7 to 254 = reserved + tag=i18n("Unknown"); + } + appendItem( exifGroup, "Metering mode", tag ); + } + + if (ImageInfo.getExposureProgram()){ + switch(ImageInfo.getExposureProgram()) { + case 0: + tag=i18n("Not defined"); + break; + case 1: + tag=i18n("Manual"); + break; + case 2: + tag=i18n("Normal program"); + break; + case 3: + tag=i18n("Aperture priority"); + break; + case 4: + tag=i18n("Shutter priority"); + break; + case 5: + tag=i18n("Creative program\n(biased toward fast shutter speed)"); + break; + case 6: + tag=i18n("Action program\n(biased toward fast shutter speed)"); + break; + case 7: + tag=i18n("Portrait mode\n(for closeup photos with the background out of focus)"); + break; + case 8: + tag=i18n("Landscape mode\n(for landscape photos with the background in focus)"); + break; + default: + // 9 to 255 = reserved + tag=i18n("Unknown"); + } + appendItem( exifGroup, "Exposure", tag ); + } + + if (ImageInfo.getISOequivalent()){ + appendItem( exifGroup, "ISO equiv.", + QString().sprintf("%2d", + (int)ImageInfo.getISOequivalent()) ); + } + + if (ImageInfo.getCompressionLevel()){ + switch(ImageInfo.getCompressionLevel()) { + case 1: + tag=i18n("Basic"); + break; + case 2: + tag=i18n("Normal"); + break; + case 4: + tag=i18n("Fine"); + break; + default: + tag=i18n("Unknown"); + } + appendItem( exifGroup, "JPEG quality", tag ); + } + + tag = ImageInfo.getUserComment(); + if (tag.length()){ + appendItem( exifGroup, "EXIF comment", tag ); + } + + int a; + for (a=0;;a++){ + if (ProcessTable[a].Tag == ImageInfo.getProcess() || ProcessTable[a].Tag == 0){ + appendItem( exifGroup, "JPEG process", + QString::fromUtf8( ProcessTable[a].Desc) ); + break; + } + } + + if ( what & KFileMetaInfo::Thumbnail && !ImageInfo.isNullThumbnail() ){ + appendItem( exifGroup, "Thumbnail", ImageInfo.getThumbnail() ); + } + + return true; +} + +// format of the string is: +// YYYY:MM:DD HH:MM:SS +QDateTime KJpegPlugin::parseDateTime( const QString& string ) +{ + QDateTime dt; + if ( string.length() != 19 ) + return dt; + + QString year = string.left( 4 ); + QString month = string.mid( 5, 2 ); + QString day = string.mid( 8, 2 ); + QString hour = string.mid( 11, 2 ); + QString minute = string.mid( 14, 2 ); + QString seconds = string.mid( 17, 2 ); + + bool ok; + bool allOk = true; + int y = year.toInt( &ok ); + allOk &= ok; + + int mo = month.toInt( &ok ); + allOk &= ok; + + int d = day.toInt( &ok ); + allOk &= ok; + + int h = hour.toInt( &ok ); + allOk &= ok; + + int mi = minute.toInt( &ok ); + allOk &= ok; + + int s = seconds.toInt( &ok ); + allOk &= ok; + + if ( allOk ) { + dt.setDate( QDate( y, mo, d ) ); + dt.setTime( QTime( h, mi, s ) ); + } + + return dt; +} + +#include "kfile_jpeg.moc" diff --git a/kfile-plugins/jpeg/kfile_jpeg.desktop b/kfile-plugins/jpeg/kfile_jpeg.desktop new file mode 100644 index 00000000..3ca5a011 --- /dev/null +++ b/kfile-plugins/jpeg/kfile_jpeg.desktop @@ -0,0 +1,64 @@ +[Desktop Entry] +Type=Service +Name=JPEG EXIF Info +Name[ar]=معلومات JPEG EXIF +Name[br]=Titouroù EXIF JPEG +Name[ca]=Informació de JPEG EXIF +Name[cs]=JPEG EXIF info +Name[cy]=Gwybodaeth JPEG EXIF +Name[da]=JPEG EXIF-info +Name[de]=JPEG EXIF-Info +Name[el]=Πληροφορίες JPEG EXIF +Name[eo]=JPEG-EXIF-informo +Name[es]=Info JPEG EXIF +Name[et]=JPEG EXIF info +Name[fa]=اطلاعات JPEG EXIF +Name[fi]=JPEG EXIF -tiedot +Name[fr]=Informations JPEG EXIF +Name[gl]=Inf. JPEG EXIF +Name[he]=מידע JPEG EXIF +Name[hi]=JPEG EXIF जानकारी +Name[hr]=JPEG EXIF Informacije +Name[hu]=JPEG EXIF-jellemzők +Name[is]=JPEG EXIF upplýsingar +Name[it]=Informazioni JPEG EXIF +Name[ja]=JPEG EXIF 情報 +Name[kk]=JPEG EXIF мәліметі +Name[km]=ព័ត៌មាន JPEG EXIF +Name[lt]=JPEG EXIF informacija +Name[ms]=Maklumat JPEG EXIF +Name[nds]=JPEG-EXIF-Info +Name[ne]=JPEG EXIF सूचना +Name[nl]=JPEG EXIF-info +Name[nn]=JPEG EXIF-info +Name[nso]=TshedimoJPEG EXIF Info +Name[pa]=JPEG EXIF ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku JPEG EXIF +Name[pt]=Informação do JPEG EXIF +Name[pt_BR]=Informação sobre JPEG EXIF +Name[ro]=Informaţii EXIF JPEG +Name[ru]=Информация о JPEG EXIF +Name[se]=JPEG EXIF-dieđut +Name[sl]=Podatki o JPEG EXIF +Name[sr]=JPEG EXIF информације +Name[sr@Latn]=JPEG EXIF informacije +Name[sv]=JPEG EXIF-information +Name[ta]=JPEG EXIF தகவல் +Name[tg]=Иттилоот оиди JPEG EXIF +Name[th]=ข้อมูลแฟ้ม JPEG EXIF +Name[tr]=JPEG EXIF Bilgisi +Name[uk]=Інформація про JPEG EXIF +Name[uz]=JPEG EXIF haqida maʼlumot +Name[uz@cyrillic]=JPEG EXIF ҳақида маълумот +Name[ven]=Mafhungo a JPEG EXIF +Name[wa]=Informåcion sol imådje JPEG EXIF +Name[xh]=Ulwazi lwe JPEG EXIF +Name[zh_CN]=JPEG EXIF 信息 +Name[zh_HK]=JPEG EXIF 資訊 +Name[zh_TW]=JPEG EXIF 資訊 +Name[zu]=Ulwazi lwe-JPEG EXIF +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_jpeg +MimeType=image/jpeg +PreferredItems=User comment,CreationDate,CreationTime,Dimensions,Exposure time,JPEG quality,Comment +SupportsThumbnail=true diff --git a/kfile-plugins/jpeg/kfile_jpeg.h b/kfile-plugins/jpeg/kfile_jpeg.h new file mode 100644 index 00000000..5c585fb0 --- /dev/null +++ b/kfile-plugins/jpeg/kfile_jpeg.h @@ -0,0 +1,43 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Frank Pieczynski + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef __KFILE_JPEG_H__ +#define __KFILE_JPEG_H__ + +#include +#include + +class KJpegPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KJpegPlugin( QObject *parent, const char *name, + const QStringList& args ); + + virtual bool readInfo ( KFileMetaInfo& info, uint what ); + virtual bool writeInfo( const KFileMetaInfo& info ) const; + virtual QValidator* createValidator( const KFileMetaInfoItem& item, + QObject* parent, const char* name) const; + +private: + QDateTime parseDateTime( const QString& string ); +}; + +#endif diff --git a/kfile-plugins/jpeg/kfile_setcomment.cpp b/kfile-plugins/jpeg/kfile_setcomment.cpp new file mode 100644 index 00000000..07dca273 --- /dev/null +++ b/kfile-plugins/jpeg/kfile_setcomment.cpp @@ -0,0 +1,536 @@ +/* + * setcomment.cpp + * + * Copyright 2002 Bryce Nesbitt + * + * Based on wrjpgcom.c, Copyright (C) 1994-1997, Thomas G. Lane. + * Part of the Independent JPEG Group's software release 6b of 27-Mar-1998 + * + * This file contains a very simple stand-alone application that inserts + * user-supplied text as a COM (comment) marker in a JPEG/JFIF file. + * This may be useful as an example of the minimum logic needed to parse + * JPEG markers. + * + * There can be an arbitrary number of COM blocks in each jpeg file, with + * up to 64K of data each. We, however, write just one COM and blow away + * the rest. + * + ***************** + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#undef STANDALONE_COMPILE + +#include +#include +#include +#include +#include +#include +#include "config.h" + +extern int safe_copy_and_modify( const char * original_filename, const char * comment ); + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#define WRITE_BINARY "w" +#else +#ifdef VMS /* VMS is very nonstandard */ +#define READ_BINARY "rb", "ctx=stm" +#define WRITE_BINARY "wb", "ctx=stm" +#else /* standard ANSI-compliant case */ +#define READ_BINARY "rb" +#define WRITE_BINARY "wb" +#endif +#endif + +#define WARNING_GARBAGE 1 /* Original file had some unspecified content */ +#define ERROR_NOT_A_JPEG 5 /* Original file not a proper jpeg (must be 1st) */ +#define ERROR_TEMP_FILE 6 /* Problem writing temporay file */ +#define ERROR_SCREWUP 7 /* Original file is now damaged. Ooops. */ +#define ERROR_PREMATURE_EOF 8 /* Unexpected end of file */ +#define ERROR_BAD_MARKER 9 /* Marker with illegal length */ +#define ERROR_MARKER_ORDER 10 /* File seems to be mixed up */ + +static int global_error; /* global error flag. Once set, we're dead. */ + +/****************************************************************************/ +/* + * These macros are used to read the input file and write the output file. + * To reuse this code in another application, you might need to change these. + */ +static FILE * infile; /* input JPEG file */ + +/* Return next input byte, or EOF if no more */ +#define NEXTBYTE() getc(infile) + +static FILE * outfile; /* output JPEG file */ + +/* Emit an output byte */ +#define PUTBYTE(x) putc((x), outfile) + + +/****************************************************************************/ +/* Read one byte, testing for EOF */ +static int +read_1_byte (void) +{ + int c; + + c = NEXTBYTE(); + if (c == EOF) { + global_error = ERROR_PREMATURE_EOF; + } + return c; +} + +/* Read 2 bytes, convert to unsigned int */ +/* All 2-byte quantities in JPEG markers are MSB first */ +static unsigned int +read_2_bytes (void) +{ + int c1, c2; + + c1 = NEXTBYTE(); + if (c1 == EOF) + global_error = ERROR_PREMATURE_EOF; + c2 = NEXTBYTE(); + if (c2 == EOF) + global_error = ERROR_PREMATURE_EOF; + return (((unsigned int) c1) << 8) + ((unsigned int) c2); +} + + +/****************************************************************************/ +/* Routines to write data to output file */ +static void +write_1_byte (int c) +{ + PUTBYTE(c); +} + +static void +write_2_bytes (unsigned int val) +{ + PUTBYTE((val >> 8) & 0xFF); + PUTBYTE(val & 0xFF); +} + +static void +write_marker (int marker) +{ + PUTBYTE(0xFF); + PUTBYTE(marker); +} + +static void +copy_rest_of_file (void) +{ + int c; + + while ((c = NEXTBYTE()) != EOF) + PUTBYTE(c); +} + + +/****************************************************************************/ +/* + * JPEG markers consist of one or more 0xFF bytes, followed by a marker + * code byte (which is not an FF). Here are the marker codes of interest + * in this program. (See jdmarker.c for a more complete list.) + */ + +#define M_SOF0 0xC0 /* Start Of Frame N */ +#define M_SOF1 0xC1 /* N indicates which compression process */ +#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */ +#define M_SOF3 0xC3 +#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */ +#define M_SOF6 0xC6 +#define M_SOF7 0xC7 +#define M_SOF9 0xC9 +#define M_SOF10 0xCA +#define M_SOF11 0xCB +#define M_SOF13 0xCD +#define M_SOF14 0xCE +#define M_SOF15 0xCF +#define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */ +#define M_EOI 0xD9 /* End Of Image (end of datastream) */ +#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */ +#define M_COM 0xFE /* COMment */ + + +/* + * Find the next JPEG marker and return its marker code. + * We expect at least one FF byte, possibly more if the compressor used FFs + * to pad the file. (Padding FFs will NOT be replicated in the output file.) + * There could also be non-FF garbage between markers. The treatment of such + * garbage is unspecified; we choose to skip over it but emit a warning msg. + * NB: this routine must not be used after seeing SOS marker, since it will + * not deal correctly with FF/00 sequences in the compressed image data... + */ +static int +next_marker (void) +{ + int c; + int discarded_bytes = 0; + + /* Find 0xFF byte; count and skip any non-FFs. */ + c = read_1_byte(); + while (c != 0xFF) { + discarded_bytes++; + c = read_1_byte(); + } + /* Get marker code byte, swallowing any duplicate FF bytes. Extra FFs + * are legal as pad bytes, so don't count them in discarded_bytes. + */ + do { + c = read_1_byte(); + } while (c == 0xFF); + + if (discarded_bytes != 0) { + global_error = WARNING_GARBAGE; + } + + return c; +} + + +/* + * Most types of marker are followed by a variable-length parameter segment. + * This routine skips over the parameters for any marker we don't otherwise + * want to process. + * Note that we MUST skip the parameter segment explicitly in order not to + * be fooled by 0xFF bytes that might appear within the parameter segment; + * such bytes do NOT introduce new markers. + */ +static void +copy_variable (void) +/* Copy an unknown or uninteresting variable-length marker */ +{ + unsigned int length; + + /* Get the marker parameter length count */ + length = read_2_bytes(); + write_2_bytes(length); + /* Length includes itself, so must be at least 2 */ + if (length < 2) { + global_error = ERROR_BAD_MARKER; + length = 2; + } + length -= 2; + /* Skip over the remaining bytes */ + while (length > 0) { + write_1_byte(read_1_byte()); + length--; + } +} + +static void +skip_variable (void) +/* Skip over an unknown or uninteresting variable-length marker */ +{ + unsigned int length; + + /* Get the marker parameter length count */ + length = read_2_bytes(); + /* Length includes itself, so must be at least 2 */ + if (length < 2) { + global_error = ERROR_BAD_MARKER; + length = 2; + } + length -= 2; + /* Skip over the remaining bytes */ + while (length > 0) { + (void) read_1_byte(); + length--; + } +} + + +static int +scan_JPEG_header (int keep_COM) +/* + * Parse & copy the marker stream until SOFn or EOI is seen; + * copy data to output, but discard COM markers unless keep_COM is true. + */ +{ + int c1, c2; + int marker; + + /* + * Read the initial marker, which should be SOI. + * For a JFIF file, the first two bytes of the file should be literally + * 0xFF M_SOI. To be more general, we could use next_marker, but if the + * input file weren't actually JPEG at all, next_marker might read the whole + * file and then return a misleading error message... + */ + c1 = NEXTBYTE(); + c2 = NEXTBYTE(); + if (c1 != 0xFF || c2 != M_SOI) { + global_error = ERROR_NOT_A_JPEG; + return EOF; + } + + write_marker(M_SOI); + + /* Scan miscellaneous markers until we reach SOFn. */ + for (;;) { + marker = next_marker(); + switch (marker) { + /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be, + * treated as SOFn. C4 in particular is actually DHT. + */ + case M_SOF0: /* Baseline */ + case M_SOF1: /* Extended sequential, Huffman */ + case M_SOF2: /* Progressive, Huffman */ + case M_SOF3: /* Lossless, Huffman */ + case M_SOF5: /* Differential sequential, Huffman */ + case M_SOF6: /* Differential progressive, Huffman */ + case M_SOF7: /* Differential lossless, Huffman */ + case M_SOF9: /* Extended sequential, arithmetic */ + case M_SOF10: /* Progressive, arithmetic */ + case M_SOF11: /* Lossless, arithmetic */ + case M_SOF13: /* Differential sequential, arithmetic */ + case M_SOF14: /* Differential progressive, arithmetic */ + case M_SOF15: /* Differential lossless, arithmetic */ + return marker; + + case M_SOS: /* should not see compressed data before SOF */ + global_error = ERROR_MARKER_ORDER; + break; + + case M_EOI: /* in case it's a tables-only JPEG stream */ + return marker; + + case M_COM: /* Existing COM: conditionally discard */ + if (keep_COM) { + write_marker(marker); + copy_variable(); + } else { + skip_variable(); + } + break; + + default: /* Anything else just gets copied */ + write_marker(marker); + copy_variable(); /* we assume it has a parameter count... */ + break; + } + } /* end loop */ +} + + +/****************************************************************************/ +/* + Verify we know how to set the comment on this type of file. + + TODO: The actual check! This should verify + the image size promised in the headers matches the file, + and that all markers are properly formatted. +*/ +static int validate_image_file( const char * filename ) +{ +int status = 1; +int c1, c2; + + if ( (infile = fopen(filename, READ_BINARY)) ) { + c1 = NEXTBYTE(); + c2 = NEXTBYTE(); + if (c1 != 0xFF || c2 != M_SOI) + status = ERROR_NOT_A_JPEG; + else + status = 0; + fclose( infile ); + } + return( status ); +} + + +/****************************************************************************/ +/* + Modify the file in place, but be paranoid and safe about it. + It's worth a few extra CPU cycles to make sure we never + destory an original image: + 1) Validate the input file. + 2) Open a temporary file. + 3) Copy the data, writing a new comment block. + 4) Validate the temporary file. + 5) Move the temporary file over the original. + + To be even more paranoid & safe we could: + 5) Rename the original to a different temporary name. + 6) Rename the temporary to the original. + 7) Delete the original. +*/ +extern int safe_copy_and_modify( const char * original_filename, const char * comment ) +{ +char * temp_filename; +int temp_filename_length; +int comment_length = 0; +int marker; +int i; +struct stat statbuf; + + global_error = 0; + + /* + * Make sure we're dealing with a proper input file. Safety first! + */ + if( validate_image_file( original_filename ) ) { + fprintf(stderr, "error validating original file %s\n", original_filename); + return(ERROR_NOT_A_JPEG); + } + + /* Get a unique temporary file in the same directory. Hopefully + * if things go wrong, this file will still be left for recovery purposes. + * + * NB: I hate these stupid string functions in C... the buffer length is too + * hard to manage... + */ + outfile = NULL; + temp_filename_length = strlen( original_filename) + 4; + temp_filename = (char *)calloc( temp_filename_length, 1 ); + for( i=0; i<10; i++ ) { + snprintf( temp_filename, temp_filename_length, "%s%d", original_filename, i ); + if( stat( temp_filename, &statbuf ) ) { + outfile = fopen(temp_filename, WRITE_BINARY); + break; + } + } + if( !outfile ) { + fprintf(stderr, "failed opening temporary file %s\n", temp_filename); + free(temp_filename); + return(ERROR_TEMP_FILE); + } + + + /* + * Let's rock and roll! + */ + if ((infile = fopen(original_filename, READ_BINARY)) == NULL) { + fprintf(stderr, "can't open input file %s\n", original_filename); + free(temp_filename); + return(ERROR_NOT_A_JPEG); + } + /* Copy JPEG headers until SOFn marker; + * we will insert the new comment marker just before SOFn. + * This (a) causes the new comment to appear after, rather than before, + * existing comments; and (b) ensures that comments come after any JFIF + * or JFXX markers, as required by the JFIF specification. + */ + marker = scan_JPEG_header(0); + /* Insert the new COM marker, but only if nonempty text has been supplied */ + if (comment) { + comment_length = strlen( comment ); + } + if (comment_length > 0) { + write_marker(M_COM); + write_2_bytes(comment_length + 2); + while (comment_length > 0) { + write_1_byte(*comment++); + comment_length--; + } + } + /* Duplicate the remainder of the source file. + * Note that any COM markers occurring after SOF will not be touched. + * + * :TODO: Discard COM markers occurring after SOF + */ + write_marker(marker); + copy_rest_of_file(); + fclose( infile ); + fsync( fileno( outfile) ); /* Make sure its really on disk first. !!!VERY IMPORTANT!!! */ + if ( fclose( outfile ) ) { + fprintf(stderr, "error in temporary file %s\n", temp_filename); + free(temp_filename); + return(ERROR_TEMP_FILE); + } + + + /* + * Make sure we did it right. We've already fsync()'ed the file. Safety first! + */ + if( validate_image_file( temp_filename ) ) { + fprintf(stderr, "error in temporary file %s\n", temp_filename); + free(temp_filename); + return(ERROR_TEMP_FILE); + } + + if( global_error >= ERROR_NOT_A_JPEG ) { + fprintf(stderr, "error %d processing %s\n", global_error, original_filename); + free(temp_filename); + return(ERROR_NOT_A_JPEG); + } + + if( rename( temp_filename, original_filename ) ) { + fprintf(stderr, "error renaming %s to %s\n", temp_filename, original_filename); + free(temp_filename); + return(ERROR_TEMP_FILE); + } + free(temp_filename); + + return(0); +} + + +#ifdef STANDALONE_COMPILE +int +main (int argc, char **argv) +{ + char * progname; /* program name for error messages */ + char * filename; + char * comment; + FILE * fp; + int error; + + /* Process command line arguments... */ + progname = argv[0]; + if (progname == NULL || progname[0] == 0) + progname = "writejpgcomment"; /* in case C library doesn't provide it */ + if( argc != 3) { + fprintf(stderr, "Usage: %s \"\"\nOverwrites the comment in a image file with the given comment.\n", progname); + return(5); + } + filename = argv[1]; + comment = argv[2]; + + + /* Check if file is readable... */ + if ((fp = fopen(filename, READ_BINARY)) == NULL) { + fprintf(stderr, "Error: Can't open file %s\n", filename); + fclose(fp); + return(5); + } + fclose(fp); + + /* Check if we really have a commentable image file here... */ + if( validate_image_file( filename ) ) { + fprintf(stderr, "Error: file %s is not of a supported type\n", filename); + return(5); + } + + /* Lets do it... modify the comment in place */ + if ((error = safe_copy_and_modify( filename, comment ) )) { + fprintf(stderr, "Error: %d setting jpg comment\n", error); + return(10); + } + + + /* TODO: Read comment back out of jpg and display it */ + return( 0 ); +} +#endif diff --git a/kfile-plugins/pcx/Makefile.am b/kfile-plugins/pcx/Makefile.am new file mode 100644 index 00000000..111b4c28 --- /dev/null +++ b/kfile-plugins/pcx/Makefile.am @@ -0,0 +1,21 @@ +## Makefile.am for PCX file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +noinst_HEADERS = kfile_pcx.h + +kde_module_LTLIBRARIES = kfile_pcx.la + +kfile_pcx_la_SOURCES = kfile_pcx.cpp +kfile_pcx_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_pcx_la_LIBADD = $(LIB_KIO) $(LIBTIFF) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_pcx.pot + +services_DATA = kfile_pcx.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/pcx/kfile_pcx.cpp b/kfile-plugins/pcx/kfile_pcx.cpp new file mode 100644 index 00000000..a7468a57 --- /dev/null +++ b/kfile-plugins/pcx/kfile_pcx.cpp @@ -0,0 +1,122 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Nadeem Hasan + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "kfile_pcx.h" + +#include +#include + +#include +#include + +typedef KGenericFactory PcxFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_pcx, PcxFactory("kfile_pcx")) + +QDataStream &operator>>( QDataStream &s, PALETTE &pal ) +{ + for ( int i=0; i<16; ++i ) + s >> pal.p[ i ].r >> pal.p[ i ].g >> pal.p[ i ].b; + + return s; +} + +QDataStream &operator>>( QDataStream &s, PCXHEADER &ph ) +{ + s >> ph.Manufacturer; + s >> ph.Version; + s >> ph.Encoding; + s >> ph.Bpp; + s >> ph.XMin >> ph.YMin >> ph.XMax >> ph.YMax; + s >> ph.HDpi >> ph.YDpi; + s >> ph.Palette; + s >> ph.Reserved; + s >> ph.NPlanes; + s >> ph.BytesPerLine; + s >> ph.PaletteInfo; + s >> ph.HScreenSize; + s >> ph.VScreenSize; + + return s; +} + +KPcxPlugin::KPcxPlugin( QObject *parent, const char *name, + const QStringList &args ) : KFilePlugin( parent, name, args ) +{ + kdDebug(7034) << "PCX file meta info plugin" << endl; + KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-pcx" ); + + KFileMimeTypeInfo::GroupInfo* group = + addGroupInfo( info, "General", i18n( "General" ) ); + + KFileMimeTypeInfo::ItemInfo* item; + item = addItemInfo( group, "Dimensions", i18n( "Dimensions" ), + QVariant::Size ); + setHint( item, KFileMimeTypeInfo::Size ); + setUnit( item, KFileMimeTypeInfo::Pixels ); + item = addItemInfo( group, "BitDepth", i18n( "Bit Depth" ), + QVariant::Int ); + setUnit( item, KFileMimeTypeInfo::BitsPerPixel ); + item = addItemInfo( group, "Resolution", i18n( "Resolution" ), + QVariant::Size ); + setUnit( item, KFileMimeTypeInfo::DotsPerInch ); + item = addItemInfo( group, "Compression", i18n( "Compression" ), + QVariant::String ); +} + +bool KPcxPlugin::readInfo( KFileMetaInfo& info, uint ) +{ + if ( info.path().isEmpty() ) + return false; + + struct PCXHEADER header; + + QFile f( info.path() ); + if ( !f.open( IO_ReadOnly ) ) + return false; + + QDataStream s( &f ); + s.setByteOrder( QDataStream::LittleEndian ); + + s >> header; + + int w = ( header.XMax-header.XMin ) + 1; + int h = ( header.YMax-header.YMin ) + 1; + int bpp = header.Bpp*header.NPlanes; + + KFileMetaInfoGroup group = appendGroup( info, "General" ); + + appendItem( group, "Dimensions", QSize( w, h ) ); + appendItem( group, "BitDepth", bpp ); + appendItem( group, "Resolution", QSize( header.HDpi, header.YDpi ) ); + if ( header.Encoding == 1 ) + appendItem( group, "Compression", i18n( "Yes (RLE)" ) ); + else + appendItem( group, "Compression", i18n( "None" ) ); + + f.close(); + + return true; +} + +#include "kfile_pcx.moc" + +/* vim: et sw=2 ts=2 +*/ + diff --git a/kfile-plugins/pcx/kfile_pcx.desktop b/kfile-plugins/pcx/kfile_pcx.desktop new file mode 100644 index 00000000..9a3f2090 --- /dev/null +++ b/kfile-plugins/pcx/kfile_pcx.desktop @@ -0,0 +1,62 @@ +[Desktop Entry] +Type=Service +Name=PCX File Meta Info +Name[ar]=معلومات ملف PCX +Name[br]=Meta-titouroù ar restr PCX +Name[bs]=PCX meta-podaci +Name[ca]=Metainformació de fitxer PCX +Name[cs]=Metainformace obrázku typu PCX +Name[cy]=Meta-wybodaeth Ffeil PCX +Name[da]=PCX Fil-meta-info +Name[de]=PCX Metainformation +Name[el]=Μετα-πληροφορίες αρχείου PCX +Name[eo]=PCX-dosiera metainformo +Name[es]=Info meta de archivos PCX +Name[et]=PCX faili metainfo +Name[eu]=PCX fitxategi meta info +Name[fa]=فرااطلاعات پروندۀ PCX +Name[fi]=PCX-tiedoston metatiedot +Name[fr]=Méta Informations sur les fichiers PCX +Name[gl]=Inf. metaficheiro PCX +Name[he]=מידע PCX +Name[hi]=PCX फ़ाइल मेटा जानकारी +Name[hu]=PCX-jellemzők +Name[is]=PCX File Meta upplýsingar +Name[it]=Informazioni PCX +Name[ja]=PCX ファイルメタ情報 +Name[kk]=PCX файлдың мета деректері +Name[km]=ព័ត៌មាន​មេតា​របស់​ឯកសារ PCX +Name[lt]=PCX bylos meta informacija +Name[ms]=Maklumat Meta Fail PCX +Name[nb]=PCX-filmetainfo +Name[nds]=PCX-Metainfo +Name[ne]=PCX फाइल मेटा सूचना +Name[nl]=PCX meta-info +Name[nn]=PCX-filmetainfo +Name[pl]=Informacja o pliku PCX +Name[pt]=Meta-Informação do Ficheiro PCX +Name[pt_BR]=Informação sobre Meta Arquivo PCX +Name[ro]=Metainformaţii PCX +Name[ru]=Информация о метафайле PCX +Name[se]=PCX-filla metadieđut +Name[sk]=Meta-info o súbore PCX +Name[sl]=Meta podatki o PCX +Name[sr]=Мета информације PCX фајла +Name[sr@Latn]=Meta informacije PCX fajla +Name[sv]=Metainformation om PCX-fil +Name[ta]=PCX File Meta தகவல் +Name[tg]=Иттилоот оиди метафайли PCX +Name[th]=ข้อมูลเมตาแฟ้ม PCX +Name[tr]=PCX Dosya Bilgisi +Name[uk]=Метаінформація про файл PCX +Name[uz]=PCX-faylining meta-maʼlumoti +Name[uz@cyrillic]=PCX-файлининг мета-маълумоти +Name[wa]=Informåcion sol imådje PCX +Name[zh_CN]=PCX 文件元信息 +Name[zh_HK]=PCX 檔案 Meta 資訊 +Name[zh_TW]=PCX 檔案 Meta 資訊 +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_pcx +MimeType=image/x-pcx +PreferredGroups=General +PreferredItems=Dimensions,Resolution,BitDepth,Compression diff --git a/kfile-plugins/pcx/kfile_pcx.h b/kfile-plugins/pcx/kfile_pcx.h new file mode 100644 index 00000000..434f89a3 --- /dev/null +++ b/kfile-plugins/pcx/kfile_pcx.h @@ -0,0 +1,88 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Nadeem Hasan + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef __KFILE_PCX_H_ +#define __KFILE_PCX_H_ + +#include + +struct PALETTE +{ + struct + { + Q_UINT8 r; + Q_UINT8 g; + Q_UINT8 b; + } p[ 16 ]; +}; + +struct PCXHEADER +{ + Q_UINT8 Manufacturer; // Constant Flag, 10 = ZSoft .pcx + Q_UINT8 Version; // Version information + // 0 = Version 2.5 of PC Paintbrush + // 2 = Version 2.8 w/palette information + // 3 = Version 2.8 w/o palette information + // 4 = PC Paintbrush for Windows(Plus for + // Windows uses Ver 5) + // 5 = Version 3.0 and > of PC Paintbrush + // and PC Paintbrush +, includes + // Publisher's Paintbrush . Includes + // 24-bit .PCX files + Q_UINT8 Encoding; // 1 = .PCX run length encoding + Q_UINT8 Bpp; // Number of bits to represent a pixel + // (per Plane) - 1, 2, 4, or 8 + Q_UINT16 XMin; + Q_UINT16 YMin; + Q_UINT16 XMax; + Q_UINT16 YMax; + Q_UINT16 HDpi; + Q_UINT16 YDpi; + struct PALETTE Palette; + Q_UINT8 Reserved; // Should be set to 0. + Q_UINT8 NPlanes; // Number of color planes + Q_UINT16 BytesPerLine; // Number of bytes to allocate for a scanline + // plane. MUST be an EVEN number. Do NOT + // calculate from Xmax-Xmin. + Q_UINT16 PaletteInfo; // How to interpret palette- 1 = Color/BW, + // 2 = Grayscale ( ignored in PB IV/ IV + ) + Q_UINT16 HScreenSize; // Horizontal screen size in pixels. New field + // found only in PB IV/IV Plus + Q_UINT16 VScreenSize; // Vertical screen size in pixels. New field + // found only in PB IV/IV Plus + Q_UINT8 Filler[ 54 ]; // Blank to fill out 128 byte header. Set all + // bytes to 0 +}; + +class KPcxPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KPcxPlugin(QObject *parent, const char *name, const QStringList& args); + virtual bool readInfo(KFileMetaInfo& info, uint what); + +private: +}; + +#endif + +/* vim: et sw=2 ts=2 +*/ + diff --git a/kfile-plugins/pdf/Makefile.am b/kfile-plugins/pdf/Makefile.am new file mode 100644 index 00000000..841d9980 --- /dev/null +++ b/kfile-plugins/pdf/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for the pdf file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) $(POPPLER_CFLAGS) + +# these are the headers for your project +noinst_HEADERS = kfile_pdf.h + +kde_module_LTLIBRARIES = kfile_pdf.la + +kfile_pdf_la_SOURCES = kfile_pdf.cpp +kfile_pdf_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_pdf_la_LIBADD = $(LIB_KIO) $(POPPLER_LIBS) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_pdf.pot + +services_DATA = kfile_pdf.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/pdf/configure.in.in b/kfile-plugins/pdf/configure.in.in new file mode 100644 index 00000000..926497a5 --- /dev/null +++ b/kfile-plugins/pdf/configure.in.in @@ -0,0 +1,15 @@ +AC_ARG_WITH([poppler], + [AC_HELP_STRING([--with-poppler], + [Enable PDF support through poppler @<:@default=check@:>@])], + [], with_poppler=check) + +# Compile the pdf meta info plugin only if Poppler is available +if test "x$with_poppler" != xno; then + PKG_CHECK_MODULES(POPPLER, poppler-qt >= 0.3.1, have_poppler=yes, have_poppler=no) + + if test "x$with_poppler" != xcheck && test "x$have_poppler" != xyes; then + AC_MSG_ERROR([--with-poppler was given, but test for poppler failed]) + fi +fi + +AM_CONDITIONAL(include_PDF, test "x$have_poppler" = xyes) diff --git a/kfile-plugins/pdf/kfile_pdf.cpp b/kfile-plugins/pdf/kfile_pdf.cpp new file mode 100644 index 00000000..d5beeb60 --- /dev/null +++ b/kfile-plugins/pdf/kfile_pdf.cpp @@ -0,0 +1,104 @@ +/* This file is part of the KDE project + * Copyright (C) 2001, 2002 Rolf Magnus + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "kfile_pdf.h" + +#include +#include + +typedef KGenericFactory PdfFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_pdf, PdfFactory("kfile_pdf")) + +KPdfPlugin::KPdfPlugin(QObject *parent, const char *name, const QStringList &preferredItems) + : KFilePlugin(parent, name, preferredItems) +{ + kdDebug(7034) << "pdf plugin\n"; + + // set up our mime type + KFileMimeTypeInfo* info = addMimeTypeInfo( "application/pdf" ); + + // general group + KFileMimeTypeInfo::GroupInfo* group = addGroupInfo(info, "General", i18n("General")); + + KFileMimeTypeInfo::ItemInfo* item; + + item = addItemInfo(group, "Title", i18n("Title"), QVariant::String); + setHint(item, KFileMimeTypeInfo::Name); + item = addItemInfo(group, "Subject", i18n("Subject"), QVariant::String); + setHint(item, KFileMimeTypeInfo::Description); + item = addItemInfo(group, "Author", i18n("Author"), QVariant::String); + setHint(item, KFileMimeTypeInfo::Author); + addItemInfo(group, "Keywords", i18n("Key Words"), QVariant::String); + addItemInfo(group, "Creator", i18n("Creator"), QVariant::String); + addItemInfo(group, "Producer", i18n("Producer"), QVariant::String); + addItemInfo(group, "CreationDate", i18n("Creation Date"), QVariant::DateTime); + addItemInfo(group, "ModificationDate", i18n("Modified"), QVariant::DateTime); + addItemInfo(group, "Pages", i18n("Pages"), QVariant::Int); + addItemInfo(group, "Protected", i18n("Protected"), QVariant::String); + addItemInfo(group, "Linearized", i18n("Linearized"), QVariant::String); + addItemInfo(group, "Version", i18n("Version"), QVariant::String); +} + +bool KPdfPlugin::readInfo( KFileMetaInfo& info, uint /* what */) +{ + Poppler::Document *doc = Poppler::Document::load(info.path()); + if (!doc || doc->isLocked()) + { + delete doc; + return false; + } + + KFileMetaInfoGroup generalGroup = appendGroup(info, "General"); + + appendItem(generalGroup, "Title", doc->getInfo("Title") ); + appendItem(generalGroup, "Subject", doc->getInfo("Subject") ); + appendItem(generalGroup, "Author", doc->getInfo("Author") ); + appendItem(generalGroup, "Keywords", doc->getInfo("Keywords") ); + appendItem(generalGroup, "Creator", doc->getInfo("Creator") ); + appendItem(generalGroup, "Producer", doc->getInfo("Producer") ); + + appendItem(generalGroup, "CreationDate", doc->getDate("CreationDate") ); + appendItem(generalGroup, "ModificationDate", doc->getDate("ModDate") ); + appendItem(generalGroup, "Pages", doc->getNumPages() ); + + QString enc; + if (doc->isEncrypted()) + { + enc = i18n("Yes (Can Print:%1 Can Copy:%2 Can Change:%3 Can Add notes:%4)") + .arg(doc->okToPrint() ? i18n("Yes") : i18n("No")) + .arg(doc->okToCopy() ? i18n("Yes") : i18n("No")) + .arg(doc->okToChange() ? i18n("Yes") : i18n("No")) + .arg(doc->okToAddNotes() ? i18n("Yes") : i18n("No")); + } + else enc = i18n("No"); + + appendItem(generalGroup, "Protected", enc ); + appendItem(generalGroup, "Linearized", doc->isLinearized() ? i18n("Yes") : i18n("No") ); + QString versionString = QString("%1").arg( doc->getPDFVersion(), 0, 'f', 1 ); + appendItem(generalGroup, "Version", versionString ); + + delete doc; + + return true; +} + +#include "kfile_pdf.moc" + diff --git a/kfile-plugins/pdf/kfile_pdf.desktop b/kfile-plugins/pdf/kfile_pdf.desktop new file mode 100644 index 00000000..cdc6a8e8 --- /dev/null +++ b/kfile-plugins/pdf/kfile_pdf.desktop @@ -0,0 +1,64 @@ +[Desktop Entry] +Type=Service +Name=PDF Info +Name[af]=Pdf Inligting +Name[ar]=معلومات PDF +Name[br]=Titouroù PDF +Name[ca]=Informació de PDF +Name[cs]=PDF info +Name[cy]=Gybodaeth PDF +Name[da]=PDF-info +Name[de]=PDF-Info +Name[el]=Πληροφορίες PDF +Name[eo]=PDF-informo +Name[es]=Info PDF +Name[et]=PDF info +Name[fa]=اطلاعات PDF +Name[fi]=PDF-tiedot +Name[fr]=Informations PDF +Name[gl]=Inf. PDF +Name[he]=מידע PDF +Name[hi]=PDF जानकारी +Name[hr]=PDF Informacije +Name[hu]=PDF-jellemzők +Name[is]=PDF upplýsingar +Name[it]=Informazioni PDF +Name[ja]=PDF 情報 +Name[kk]=PDF мәліметі +Name[km]=ព័ត៌មាន PDF +Name[lt]=PDF informacija +Name[ms]=Maklumat PDF +Name[nds]=PDF-Info +Name[ne]=PDF सूचना +Name[nl]=PDF-info +Name[nn]=PDF-info +Name[nso]=Tshedimoso ya PDF +Name[pa]=PDF ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku PDF +Name[pt]=Informação do PDF +Name[pt_BR]=Informação sobre PDF +Name[ro]=Informaţii PDF +Name[ru]=Информация о PDF +Name[se]=PDF-dieđut +Name[sl]=Podatki o PDF +Name[sr]=PDF информације +Name[sr@Latn]=PDF informacije +Name[sv]=PDF-information +Name[ta]=PDF தகவல் +Name[tg]=Иттилоот оиди PDF +Name[th]=ข้อมูลแฟ้ม PDF +Name[tr]=PDF Bilgisi +Name[uk]=Інформація про PDF +Name[uz]=PDF haqida maʼlumot +Name[uz@cyrillic]=PDF ҳақида маълумот +Name[ven]=Mafhungo a PDF +Name[wa]=Informåcion sol documint PDF +Name[xh]=PDF Ulwazi +Name[zh_CN]=PDF 信息 +Name[zh_HK]=PDF 資訊 +Name[zh_TW]=PDF 資訊 +Name[zu]=Ulwazi lwe-PDF +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_pdf +MimeType=application/pdf +PreferredItems=Title,Subject,Author,Keywords,Creator,Producer,CreationDate,ModificationDate,Pages,Protected,Linearized,Version diff --git a/kfile-plugins/pdf/kfile_pdf.h b/kfile-plugins/pdf/kfile_pdf.h new file mode 100644 index 00000000..b0214f54 --- /dev/null +++ b/kfile-plugins/pdf/kfile_pdf.h @@ -0,0 +1,38 @@ +/* This file is part of the KDE project + * Copyright (C) 2001, 2002 Rolf Magnus + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef __KFILE_PDF_H__ +#define __KFILE_PDF_H__ + +#include +#include + +class QStringList; + +class KPdfPlugin: public KFilePlugin +{ +Q_OBJECT +public: + KPdfPlugin( QObject *parent, const char *name, const QStringList& preferredItems ); + + virtual bool readInfo(KFileMetaInfo& info, uint what); +}; + +#endif diff --git a/kfile-plugins/png/Makefile.am b/kfile-plugins/png/Makefile.am new file mode 100644 index 00000000..9aa820b6 --- /dev/null +++ b/kfile-plugins/png/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for png file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_png.h + +kde_module_LTLIBRARIES = kfile_png.la + +kfile_png_la_SOURCES = kfile_png.cpp +kfile_png_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_png_la_LIBADD = $(LIB_KIO) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_png.pot + +services_DATA = kfile_png.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/png/kfile_png.cpp b/kfile-plugins/png/kfile_png.cpp new file mode 100644 index 00000000..c3e54b66 --- /dev/null +++ b/kfile-plugins/png/kfile_png.cpp @@ -0,0 +1,315 @@ +/* This file is part of the KDE project + * Copyright (C) 2001, 2002 Rolf Magnus + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include +#include "kfile_png.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +// some defines to make it easier +// don't tell me anything about preprocessor usage :) +#define CHUNK_SIZE(data, index) ((data[index ]<<24) + (data[index+1]<<16) + \ + (data[index+2]<< 8) + data[index+3]) +#define CHUNK_TYPE(data, index) &data[index+4] +#define CHUNK_HEADER_SIZE 12 +#define CHUNK_DATA(data, index, offset) data[8+index+offset] + +// known translations for common png keys +static const char* knownTranslations[] +#ifdef __GNUC__ +__attribute__((unused)) +#endif + = { + I18N_NOOP("Title"), + I18N_NOOP("Author"), + I18N_NOOP("Description"), + I18N_NOOP("Copyright"), + I18N_NOOP("Creation Time"), + I18N_NOOP("Software"), + I18N_NOOP("Disclaimer"), + I18N_NOOP("Warning"), + I18N_NOOP("Source"), + I18N_NOOP("Comment") +}; + +// and for the colors +static const char* colors[] = { + I18N_NOOP("Grayscale"), + I18N_NOOP("Unknown"), + I18N_NOOP("RGB"), + I18N_NOOP("Palette"), + I18N_NOOP("Grayscale/Alpha"), + I18N_NOOP("Unknown"), + I18N_NOOP("RGB/Alpha") +}; + + // and compressions +static const char* compressions[] = +{ + I18N_NOOP("Deflate") +}; + + // interlaced modes +static const char* interlaceModes[] = { + I18N_NOOP("None"), + I18N_NOOP("Adam7") +}; + +typedef KGenericFactory PngFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_png, PngFactory("kfile_png")) + +KPngPlugin::KPngPlugin(QObject *parent, const char *name, + const QStringList &args) + : KFilePlugin(parent, name, args) +{ + kdDebug(7034) << "png plugin\n"; + + // set up our mime type + KFileMimeTypeInfo* info = addMimeTypeInfo( "image/png" ); + + KFileMimeTypeInfo::GroupInfo* group = 0; + KFileMimeTypeInfo::ItemInfo* item = 0; + + // comment group + group = addGroupInfo(info, "Comment", i18n("Comment")); + addVariableInfo(group, QVariant::String, 0); + + // technical group + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + + item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size); + setHint( item, KFileMimeTypeInfo::Size ); + setUnit(item, KFileMimeTypeInfo::Pixels); + + item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::BitsPerPixel); + + addItemInfo(group, "ColorMode", i18n("Color Mode"), QVariant::String); + addItemInfo(group, "Compression", i18n("Compression"), QVariant::String); + addItemInfo(group, "InterlaceMode", i18n("Interlace Mode"),QVariant::String); +} + +bool KPngPlugin::readInfo( KFileMetaInfo& info, uint what) +{ + if ( info.path().isEmpty() ) // remote file + return false; + QFile f(info.path()); + if ( !f.open(IO_ReadOnly) ) + return false; + + QIODevice::Offset fileSize = f.size(); + + if (fileSize < 29) return false; + // the technical group will be read from the first 29 bytes. If the file + // is smaller, we can't even read this. + + bool readComments = false; + if (what & (KFileMetaInfo::Fastest | + KFileMetaInfo::DontCare | + KFileMetaInfo::ContentInfo)) readComments = true; + else + fileSize = 29; // No need to read more + + uchar *data = new uchar[fileSize+1]; + f.readBlock(reinterpret_cast(data), fileSize); + data[fileSize]='\n'; + + // find the start + if (data[0] == 137 && data[1] == 80 && data[2] == 78 && data[3] == 71 && + data[4] == 13 && data[5] == 10 && data[6] == 26 && data[7] == 10 ) + { + // ok + // the IHDR chunk should be the first + if (!strncmp((char*)&data[12], "IHDR", 4)) + { + // we found it, get the dimensions + ulong x,y; + x = (data[16]<<24) + (data[17]<<16) + (data[18]<<8) + data[19]; + y = (data[20]<<24) + (data[21]<<16) + (data[22]<<8) + data[23]; + + uint type = data[25]; + uint bpp = data[24]; + kdDebug(7034) << "dimensions " << x << "*" << y << endl; + + // the bpp are only per channel, so we need to multiply the with + // the channel count + switch (type) + { + case 0: break; // Grayscale + case 2: bpp *= 3; break; // RGB + case 3: break; // palette + case 4: bpp *= 2; break; // grayscale w. alpha + case 6: bpp *= 4; break; // RGBA + + default: // we don't get any sensible value here + bpp = 0; + } + + KFileMetaInfoGroup techgroup = appendGroup(info, "Technical"); + + appendItem(techgroup, "Dimensions", QSize(x, y)); + appendItem(techgroup, "BitDepth", bpp); + appendItem(techgroup, "ColorMode", + (type < sizeof(colors)/sizeof(colors[0])) + ? i18n(colors[data[25]]) : i18n("Unknown")); + + appendItem(techgroup, "Compression", + (data[26] < sizeof(compressions)/sizeof(compressions[0])) + ? i18n(compressions[data[26]]) : i18n("Unknown")); + + appendItem(techgroup, "InterlaceMode", + (data[28] < sizeof(interlaceModes)/sizeof(interlaceModes[0])) + ? i18n(interlaceModes[data[28]]) : i18n("Unknown")); + } + + // look for a tEXt chunk + if (readComments) + { + uint index = 8; + index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE; + KFileMetaInfoGroup commentGroup = appendGroup(info, "Comment"); + + while(index=fileSize) + goto end; + + QByteArray arr; + if(!strncmp((char*)CHUNK_TYPE(data,index), "zTXt", 4)) { + kdDebug(7034) << "We found a zTXt field\n"; + // we get the compression method after the key + uchar* compressionMethod = &CHUNK_DATA(data,index,keysize+1); + if ( *compressionMethod != 0x00 ) { + // then it isn't zlib compressed and we are sunk + kdDebug(7034) << "Non-standard compression method." << endl; + goto end; + } + // compressed string after the compression technique spec + uchar* compressedText = &CHUNK_DATA(data, index, keysize+2); + uint compressedTextSize = CHUNK_SIZE(data, index)-keysize-2; + + // security check, also considering overflow wraparound from the addition -- + // we may endup with a /smaller/ index if we wrap all the way around + uint firstIndex = (uint)(compressedText - data); + uint onePastLastIndex = firstIndex + compressedTextSize; + if ( onePastLastIndex > fileSize || onePastLastIndex <= firstIndex) + goto end; + + uLongf uncompressedLen = compressedTextSize * 2; // just a starting point + int zlibResult; + do { + arr.resize(uncompressedLen); + zlibResult = uncompress((Bytef*)arr.data(), &uncompressedLen, + compressedText, compressedTextSize); + if (Z_OK == zlibResult) { + // then it is all OK + arr.resize(uncompressedLen); + } else if (Z_BUF_ERROR == zlibResult) { + // the uncompressedArray needs to be larger + // kdDebug(7034) << "doubling size for decompression" << endl; + uncompressedLen *= 2; + + // DoS protection. can't be bigger than 64k + if ( uncompressedLen > 131072 ) + break; + } else { + // something bad happened + goto end; + } + } while (Z_BUF_ERROR == zlibResult); + + if (Z_OK != zlibResult) + goto end; + } else if (!strncmp((char*)CHUNK_TYPE(data,index), "tEXt", 4)) { + kdDebug(7034) << "We found a tEXt field\n"; + // the text comes after the key, but isn't null terminated + uchar* text = &CHUNK_DATA(data,index, keysize+1); + uint textsize = CHUNK_SIZE(data, index)-keysize-1; + + // security check, also considering overflow wraparound from the addition -- + // we may endup with a /smaller/ index if we wrap all the way around + uint firstIndex = (uint)(text - data); + uint onePastLastIndex = firstIndex + textsize; + + if ( onePastLastIndex > fileSize || onePastLastIndex <= firstIndex) + goto end; + + arr.resize(textsize); + arr = QByteArray(textsize).duplicate((const char*)text, + textsize); + + } else { + kdDebug(7034) << "We found a field, not expected though\n"; + goto end; + } + appendItem(commentGroup, + QString(reinterpret_cast(key)), + QString(arr)); + + kdDebug(7034) << "adding " << key << " / " + << QString(arr) << endl; + + index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE; + } + } + } + } +end: + delete[] data; + return true; +} + +#include "kfile_png.moc" diff --git a/kfile-plugins/png/kfile_png.desktop b/kfile-plugins/png/kfile_png.desktop new file mode 100644 index 00000000..b4819b8d --- /dev/null +++ b/kfile-plugins/png/kfile_png.desktop @@ -0,0 +1,65 @@ +[Desktop Entry] +Type=Service +Name=PNG Info +Name[af]=Png Inligting +Name[ar]=معلومات PNG +Name[br]=Titouroù PNG +Name[ca]=Informació de PNG +Name[cs]=PNG info +Name[cy]=Gybodaeth PNG +Name[da]=PNG-info +Name[de]=PNG-Info +Name[el]=Πληροφορίες PNG +Name[eo]=PNG-informo +Name[es]=Info PNG +Name[et]=PNG info +Name[fa]=اطلاعات PNG +Name[fi]=PNG-tiedot +Name[fr]=Informations PNG +Name[gl]=Inf. PNG +Name[he]=מידע PNG +Name[hi]=PNG जानकारी +Name[hr]=PNG Informacije +Name[hu]=PNG-jellemzők +Name[is]=PNG upplýsingar +Name[it]=Informazioni PNG +Name[ja]=PNG 情報 +Name[kk]=PNG мәліметі +Name[km]=ព័ត៌មាន PNG +Name[lt]=PNG informacija +Name[ms]=Maklumat PNG +Name[nds]=PNG-Info +Name[ne]=PNG सूचना +Name[nl]=PNG-Info +Name[nn]=PNG-info +Name[nso]=Tshedimoso ya PNG +Name[pa]=PNG ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku PNG +Name[pt]=Informação do PNG +Name[pt_BR]= Informação sobre PNG +Name[ro]=Informaţii PNG +Name[ru]=Информация о PNG +Name[se]=PNG-dieđut +Name[sl]=Podatki o PNG +Name[sr]=PNG информације +Name[sr@Latn]=PNG informacije +Name[sv]=PNG-information +Name[ta]=PNG தகவல் +Name[tg]=Иттилоот оиди PNG +Name[th]=ข้อมูลแฟ้ม PNG +Name[tr]=PNG Bilgisi +Name[uk]=Інформація про PNG +Name[uz]=PNG haqida maʼlumot +Name[uz@cyrillic]=PNG ҳақида маълумот +Name[ven]=Mafhungo a PNG +Name[wa]=Informåcion sol imådje PNG +Name[xh]=PNG Ulwazi +Name[zh_CN]=PNG 信息 +Name[zh_HK]=PNG 資訊 +Name[zh_TW]=PNG 資訊 +Name[zu]=Ulwazi lwe-PNG +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_png +MimeType=image/png +PreferredGroups=Comment,Technical +PreferredItems=Title,Author,Dimensions,BitDepth,ColorMode,Compression diff --git a/kfile-plugins/png/kfile_png.h b/kfile-plugins/png/kfile_png.h new file mode 100644 index 00000000..0873d55d --- /dev/null +++ b/kfile-plugins/png/kfile_png.h @@ -0,0 +1,39 @@ +/* This file is part of the KDE project + * Copyright (C) 2001, 2002 Rolf Magnus + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef __KFILE_PNG_H__ +#define __KFILE_PNG_H__ + +#include +#include + +class QStringList; + +class KPngPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KPngPlugin( QObject *parent, const char *name, const QStringList& preferredItems ); + + virtual bool readInfo( KFileMetaInfo& info, uint ); +}; + +#endif diff --git a/kfile-plugins/pnm/Makefile.am b/kfile-plugins/pnm/Makefile.am new file mode 100644 index 00000000..7148232a --- /dev/null +++ b/kfile-plugins/pnm/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for pnm file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_pnm.h + +kde_module_LTLIBRARIES = kfile_pnm.la + +kfile_pnm_la_SOURCES = kfile_pnm.cpp +kfile_pnm_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_pnm_la_LIBADD = $(LIB_KIO) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_pnm.pot + +services_DATA = kfile_pnm.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/pnm/kfile_pnm.cpp b/kfile-plugins/pnm/kfile_pnm.cpp new file mode 100644 index 00000000..b0a1dcca --- /dev/null +++ b/kfile-plugins/pnm/kfile_pnm.cpp @@ -0,0 +1,137 @@ +/* This file is part of the KDE project + * Copyright (C) 2003 Volker Krause + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "kfile_pnm.h" + +#include +#include +#include +#include + +static const char* formats[] = { + I18N_NOOP("plain"), + I18N_NOOP("raw") +}; + +typedef KGenericFactory PnmFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_pnm, PnmFactory("kfile_pnm")) + +KPnmPlugin::KPnmPlugin(QObject *parent, const char *name, const QStringList &args) : KFilePlugin(parent, name, args) +{ + makeMimeTypeInfo( "image/x-portable-bitmap" ); + makeMimeTypeInfo( "image/x-portable-greymap" ); + makeMimeTypeInfo( "image/x-portable-pixmap" ); +} + +void KPnmPlugin::makeMimeTypeInfo(const QString& mimetype) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo( mimetype ); + + KFileMimeTypeInfo::GroupInfo* group = 0; + KFileMimeTypeInfo::ItemInfo* item = 0; + + group = addGroupInfo(info, "General", i18n("General")); + + addItemInfo(group, "Format", i18n("Format"), QVariant::String); + + item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size); + setUnit(item, KFileMimeTypeInfo::Pixels); + + item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::BitsPerPixel); + + addItemInfo(group, "Comment", i18n("Comment"), QVariant::String); +} + + +bool KPnmPlugin::readInfo( KFileMetaInfo& info, uint /*what*/) +{ + QFile f(info.path()); + if(!f.open(IO_ReadOnly)) + return false; + if(f.size() <= 2) + return false; + QTextStream stream(&f); + + char c; + stream >> c; + if(c != 'P') + return false; + + // image format and type + int n; + stream >> n; + int format = (n - 1) / 3; + if(format != 0 && format != 1) + return false; + int type = (n - 1) % 3; + + QString comments, buffer; + while(!stream.atEnd()) { + stream >> c; + // comment + if( c == '#') { + buffer = stream.readLine(); + comments += buffer.stripWhiteSpace(); + comments += '\n'; + } + // image size + // unfortunately Qt doesn't have some kind of push-back method for + // QTextStream, so we need to manually decode the first part of the + // image size. + if( c >= '0' && c <= '9' ) { + buffer = ""; + QChar tmp(c); + while(!stream.atEnd() && tmp.isDigit()) { + buffer += tmp; + stream >> tmp; + } + break; + } + } + + // image size + int x, y, max; + x = buffer.toInt(); + stream >> y; + stream >> max; + + // bit depth + // PNM doesn't provide a conventional bit depth value, only the highest value + // per pixel. To have comparable values with other formats, we convert it to + // a normal bit depth value. + int bpp = 1; + if(type != 0) + bpp = (int)ceil(log((double)max) / log(2.0)); + if(type == 2) + bpp *= 3; + + KFileMetaInfoGroup group = appendGroup(info, "General"); + appendItem(group, "Format", formats[format]); + appendItem(group, "Dimensions", QSize(x, y)); + if(!comments.isEmpty()) + appendItem(group, "Comment", comments.stripWhiteSpace()); + appendItem(group, "BitDepth", bpp); + + f.close(); + return true; +} + +#include "kfile_pnm.moc" diff --git a/kfile-plugins/pnm/kfile_pnm.desktop b/kfile-plugins/pnm/kfile_pnm.desktop new file mode 100644 index 00000000..cfb475d2 --- /dev/null +++ b/kfile-plugins/pnm/kfile_pnm.desktop @@ -0,0 +1,60 @@ +[Desktop Entry] +Type=Service +Name=PNM Info +Name[ar]=معلومات PNM +Name[br]=Titouroù PNM +Name[ca]=Informació de PNM +Name[cs]=PNM info +Name[cy]=Gybodaeth PNM +Name[da]=PNG-info +Name[de]=PNM-Info +Name[el]=Πληροφορίες PNM +Name[eo]=PNM-informo +Name[es]=Info PNM +Name[et]=PNM info +Name[fa]=اطلاعات PNM +Name[fi]=PNM-tiedot +Name[fr]=Informations PNM +Name[gl]=Inf. PNM +Name[he]=מידע PNM +Name[hi]=PNM जानकारी +Name[hu]=PNM-jellemzők +Name[is]=PNM upplýsingar +Name[it]=Informazioni PNM +Name[ja]=PNM 情報 +Name[kk]=PNM мәліметі +Name[km]=ព័ត៌មាន PNM +Name[lt]=PNM informacija +Name[ms]=Maklumat PNM +Name[nb]=PNM-info +Name[nds]=PNM-Info +Name[ne]=PNM सूचना +Name[nl]=PNG-info +Name[nn]=PNM-info +Name[pa]=PNM ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku PNM +Name[pt]=Informação do PNM +Name[pt_BR]=Informação sobre PNG +Name[ro]=Informaţii PNM +Name[ru]=Информация о PNM +Name[se]=PNM-dieđut +Name[sl]=Podatki o PNM +Name[sr]=PNM информације +Name[sr@Latn]=PNM informacije +Name[sv]=PNM-information +Name[ta]=PNM தகவல் +Name[tg]=Иттилоот оиди PNM +Name[th]=ข้อมูลแฟ้ม PNM +Name[tr]=PNM Bilgisi +Name[uk]=Інформація про PNM +Name[uz]=PNM haqida maʼlumot +Name[uz@cyrillic]=PNM ҳақида маълумот +Name[wa]=Informåcion sol imådje PNM +Name[zh_CN]=PNM 信息 +Name[zh_HK]=PNM 資訊 +Name[zh_TW]=PNM 資訊 +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_pnm +MimeType=image/x-portable-bitmap;image/x-portable-greymap;image/x-portable-pixmap +PreferredGroups=General +PreferredItems=Format,Dimensions,BitDepth,Comment diff --git a/kfile-plugins/pnm/kfile_pnm.h b/kfile-plugins/pnm/kfile_pnm.h new file mode 100644 index 00000000..4f1043e5 --- /dev/null +++ b/kfile-plugins/pnm/kfile_pnm.h @@ -0,0 +1,39 @@ +/* This file is part of the KDE project + * Copyright (C) 2003 Volker Krause + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef __KFILE_PNM_H__ +#define __KFILE_PNM_H__ + +#include + +class QStringList; + +class KPnmPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KPnmPlugin( QObject *parent, const char *name, const QStringList& preferredItems ); + virtual bool readInfo( KFileMetaInfo& info, uint ); + +private: + void makeMimeTypeInfo( const QString&); +}; + +#endif diff --git a/kfile-plugins/ps/Makefile.am b/kfile-plugins/ps/Makefile.am new file mode 100644 index 00000000..9c5b20a3 --- /dev/null +++ b/kfile-plugins/ps/Makefile.am @@ -0,0 +1,26 @@ +## Makefile.am for the ps file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = -I$(top_srcdir)/kghostview $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_ps.h gscreator.h + +kde_module_LTLIBRARIES = kfile_ps.la gsthumbnail.la + +kfile_ps_la_SOURCES = kfile_ps.cpp +kfile_ps_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_ps_la_LIBADD = $(LIB_KIO) ../../kghostview/libdscparse.la + +gsthumbnail_la_SOURCES = gscreator.cpp +gsthumbnail_la_LIBADD = $(LIB_KDECORE) ../../kghostview/libdscparse.la +gsthumbnail_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_ps.pot + +services_DATA = kfile_ps.desktop gsthumbnail.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/ps/gscreator.cpp b/kfile-plugins/ps/gscreator.cpp new file mode 100644 index 00000000..33cbc141 --- /dev/null +++ b/kfile-plugins/ps/gscreator.cpp @@ -0,0 +1,619 @@ +/* This file is part of the KDE libraries + Copyright (C) 2001 Malte Starostik + + Handling of EPS previews Copyright (C) 2003 Philipp Hullmann + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 function gets a path of a DVI, EPS, PS or PDF file and + produces a PNG-Thumbnail which is stored as a QImage + + The program works as follows + + 1. Test if file is a DVI file + + 2. Create a child process (1), in which the + file is to be changed into a PNG + + 3. Child-process (1) : + + 4. If file is DVI continue with 6 + + 5. If file is no DVI continue with 9 + + 6. Create another child process (2), in which the DVI is + turned into PS using dvips + + 7. Parent process (2) : + Turn the recently created PS file into a PNG file using gs + + 8. continue with 10 + + 9. Turn the PS,PDF or EPS file into a PNG file using gs + + 10. Parent process (1) + store data in a QImage +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_SELECT_H +#include +#endif +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +#include "gscreator.h" +#include "dscparse_adapter.h" +#include "dscparse.h" + +extern "C" +{ + KDE_EXPORT ThumbCreator *new_creator() + { + return new GSCreator; + } +} + +// This PS snippet will be prepended to the actual file so that only +// the first page is output. +static const char *psprolog = + "%!PS-Adobe-3.0\n" + "/.showpage.orig /showpage load def\n" + "/.showpage.firstonly {\n" + " .showpage.orig\n" + " quit\n" + "} def\n" + "/showpage { .showpage.firstonly } def\n"; + +// This is the code recommended by Adobe tech note 5002 for including +// EPS files. +static const char *epsprolog = + "%!PS-Adobe-3.0\n" + "userdict begin /pagelevel save def /showpage { } def\n" + "0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin 10 setmiterlimit\n" + "[ ] 0 setdash newpath false setoverprint false setstrokeadjust\n"; + +static const char * gsargs_ps[] = { + "gs", + "-sDEVICE=png16m", + "-sOutputFile=-", + "-dSAFER", + "-dPARANOIDSAFER", + "-dNOPAUSE", + "-dFirstPage=1", + "-dLastPage=1", + "-q", + "-", + 0, // file name + "-c", + "showpage", + "-c", + "quit", + 0 +}; + +static const char * gsargs_eps[] = { + "gs", + "-sDEVICE=png16m", + "-sOutputFile=-", + "-dSAFER", + "-dPARANOIDSAFER", + "-dNOPAUSE", + 0, // page size + 0, // resolution + "-q", + "-", + 0, // file name + "-c", + "pagelevel", + "-c", + "restore", + "-c", + "end", + "-c", + "showpage", + "-c", + "quit", + 0 +}; + +static const char *dvipsargs[] = { + "dvips", + "-n", + "1", + "-q", + "-o", + "-", + 0, // file name + 0 +}; + +static bool correctDVI(const QString& filename); + + +namespace { + bool got_sig_term = false; + void handle_sigterm( int ) { + got_sig_term = true; + } +} + + +bool GSCreator::create(const QString &path, int width, int height, QImage &img) +{ +// The code in the loop (when testing whether got_sig_term got set) +// should read some variation of: +// parentJob()->wasKilled() +// +// Unfortunatelly, that's currently impossible without breaking BIC. +// So we need to catch the signal ourselves. +// Otherwise, on certain funny PS files (for example +// http://www.tjhsst.edu/~Eedanaher/pslife/life.ps ) +// gs would run forever after we were dead. +// #### Reconsider for KDE 4 ### +// (24/12/03 - luis_pedro) +// + typedef void ( *sighandler_t )( int ); + // according to linux's "man signal" the above typedef is a gnu extension + sighandler_t oldhandler = signal( SIGTERM, handle_sigterm ); + + int input[2]; + int output[2]; + int dvipipe[2]; + + QByteArray data(1024); + + bool ok = false; + + // Test if file is DVI + bool no_dvi =!correctDVI(path); + + if (pipe(input) == -1) { + return false; + } + if (pipe(output) == -1) { + close(input[0]); + close(input[1]); + return false; + } + + KDSC dsc; + endComments = false; + dsc.setCommentHandler(this); + + if (no_dvi) + { + FILE* fp = fopen(QFile::encodeName(path), "r"); + if (fp == 0) return false; + + char buf[4096]; + int count; + while ((count = fread(buf, sizeof(char), 4096, fp)) != 0 + && !endComments) { + dsc.scanData(buf, count); + } + fclose(fp); + + if (dsc.pjl() || dsc.ctrld()) { + // this file is a mess. + return false; + } + } + + const bool is_encapsulated = no_dvi && + (path.find(QRegExp("\\.epsi?$", false, false)) > 0) && + (dsc.bbox()->width() > 0) && (dsc.bbox()->height() > 0) && + (dsc.page_count() <= 1); + + char translation[64] = ""; + char pagesize[32] = ""; + char resopt[32] = ""; + std::auto_ptr bbox = dsc.bbox(); + if (is_encapsulated) { + // GhostScript's rendering at the extremely low resolutions + // required for thumbnails leaves something to be desired. To + // get nicer images, we render to four times the required + // resolution and let QImage scale the result. + const int hres = (width * 72) / bbox->width(); + const int vres = (height * 72) / bbox->height(); + const int resolution = (hres > vres ? vres : hres) * 4; + const int gswidth = ((bbox->urx() - bbox->llx()) * resolution) / 72; + const int gsheight = ((bbox->ury() - bbox->lly()) * resolution) / 72; + + snprintf(pagesize, 31, "-g%ix%i", gswidth, gsheight); + snprintf(resopt, 31, "-r%i", resolution); + snprintf(translation, 63, + " 0 %i sub 0 %i sub translate\n", bbox->llx(), + bbox->lly()); + } + + const CDSC_PREVIEW_TYPE previewType = + static_cast(dsc.preview()); + + switch (previewType) { + case CDSC_TIFF: + case CDSC_WMF: + case CDSC_PICT: + // FIXME: these should take precedence, since they can hold + // color previews, which EPSI can't (or can it?). + break; + case CDSC_EPSI: + { + const int xscale = bbox->width() / width; + const int yscale = bbox->height() / height; + const int scale = xscale < yscale ? xscale : yscale; + if (getEPSIPreview(path, + dsc.beginpreview(), + dsc.endpreview(), + img, + bbox->width() / scale, + bbox->height() / scale)) + return true; + // If the preview extraction routine fails, gs is used to + // create a thumbnail. + } + break; + case CDSC_NOPREVIEW: + default: + // need to run ghostscript in these cases + break; + } + + pid_t pid = fork(); + if (pid == 0) { + // Child process (1) + + // close(STDERR_FILENO); + + // find first zero entry in gsargs and put the filename + // or - (stdin) there, if DVI + const char **gsargs = gsargs_ps; + const char **arg = gsargs; + + if (no_dvi && is_encapsulated) { + gsargs = gsargs_eps; + arg = gsargs; + + // find first zero entry and put page size there + while (*arg) ++arg; + *arg = pagesize; + + // find second zero entry and put resolution there + while (*arg) ++arg; + *arg = resopt; + } + + // find next zero entry and put the filename there + QCString fname = QFile::encodeName( path ); + while (*arg) + ++arg; + if( no_dvi ) + *arg = fname.data(); + else + *arg = "-"; + + // find first zero entry in dvipsargs and put the filename there + arg = dvipsargs; + while (*arg) + ++arg; + *arg = fname.data(); + + if( !no_dvi ){ + pipe(dvipipe); + pid_t pid_two = fork(); + if( pid_two == 0 ){ + // Child process (2), reopen stdout on the pipe "dvipipe" and exec dvips + + close(input[0]); + close(input[1]); + close(output[0]); + close(output[1]); + close(dvipipe[0]); + + dup2( dvipipe[1], STDOUT_FILENO); + + execvp(dvipsargs[0], const_cast(dvipsargs)); + exit(1); + } + else if(pid_two != -1){ + close(input[1]); + close(output[0]); + close(dvipipe[1]); + + dup2( dvipipe[0], STDIN_FILENO); + dup2( output[1], STDOUT_FILENO); + + execvp(gsargs[0], const_cast(gsargs)); + exit(1); + } + else{ + // fork() (2) failed, close these + close(dvipipe[0]); + close(dvipipe[1]); + } + + } + else if( no_dvi ){ + // Reopen stdin/stdout on the pipes and exec gs + close(input[1]); + close(output[0]); + + dup2(input[0], STDIN_FILENO); + dup2(output[1], STDOUT_FILENO); + + execvp(gsargs[0], const_cast(gsargs)); + exit(1); + } + } + else if (pid != -1) { + // Parent process, write first-page-only-hack (the hack is not + // used if DVI) and read the png output + close(input[0]); + close(output[1]); + const char *prolog; + if (is_encapsulated) + prolog = epsprolog; + else + prolog = psprolog; + int count = write(input[1], prolog, strlen(prolog)); + if (is_encapsulated) + write(input[1], translation, strlen(translation)); + + close(input[1]); + if (count == static_cast(strlen(prolog))) { + int offset = 0; + while (!ok) { + fd_set fds; + FD_ZERO(&fds); + FD_SET(output[0], &fds); + struct timeval tv; + tv.tv_sec = 20; + tv.tv_usec = 0; + + got_sig_term = false; + if (select(output[0] + 1, &fds, 0, 0, &tv) <= 0) { + if ( ( errno == EINTR || errno == EAGAIN ) && !got_sig_term ) continue; + break; // error, timeout or master wants us to quit (SIGTERM) + } + if (FD_ISSET(output[0], &fds)) { + count = read(output[0], data.data() + offset, 1024); + if (count == -1) + break; + else + if (count) // prepare for next block + { + offset += count; + data.resize(offset + 1024); + } + else // got all data + { + data.resize(offset); + ok = true; + } + } + } + } + if (!ok) // error or timeout, gs probably didn't exit yet + { + kill(pid, SIGTERM); + } + + int status = 0; + if (waitpid(pid, &status, 0) != pid || (status != 0 && status != 256) ) + ok = false; + } + else { + // fork() (1) failed, close these + close(input[0]); + close(input[1]); + close(output[1]); + } + close(output[0]); + + int l = img.loadFromData( data ); + + if ( got_sig_term && + oldhandler != SIG_ERR && + oldhandler != SIG_DFL && + oldhandler != SIG_IGN ) { + oldhandler( SIGTERM ); // propagate the signal. Other things might rely on it + } + if ( oldhandler != SIG_ERR ) signal( SIGTERM, oldhandler ); + + return ok && l; +} + +ThumbCreator::Flags GSCreator::flags() const +{ + return static_cast(DrawFrame); +} + +void GSCreator::comment(Name name) +{ + switch (name) { + case EndPreview: + case BeginProlog: + case Page: + endComments = true; + break; + + default: + break; + } +} + +// Quick function to check if the filename corresponds to a valid DVI +// file. Returns true if is a DVI file, false otherwise. + +static bool correctDVI(const QString& filename) +{ + QFile f(filename); + if (!f.open(IO_ReadOnly)) + return FALSE; + + unsigned char test[4]; + if ( f.readBlock( (char *)test,2)<2 || test[0] != 247 || test[1] != 2 ) + return FALSE; + + int n = f.size(); + if ( n < 134 ) // Too short for a dvi file + return FALSE; + f.at( n-4 ); + + unsigned char trailer[4] = { 0xdf,0xdf,0xdf,0xdf }; + + if ( f.readBlock( (char *)test, 4 )<4 || strncmp( (char *)test, (char*) trailer, 4 ) ) + return FALSE; + // We suppose now that the dvi file is complete and OK + return TRUE; +} + +bool GSCreator::getEPSIPreview(const QString &path, long start, long + end, QImage &outimg, int imgwidth, int imgheight) +{ + FILE *fp; + fp = fopen(QFile::encodeName(path), "r"); + if (fp == 0) return false; + + const long previewsize = end - start + 1; + + char *buf = (char *) malloc(previewsize); + fseek(fp, start, SEEK_SET); + int count = fread(buf, sizeof(char), previewsize - 1, fp); + fclose(fp); + buf[previewsize - 1] = 0; + if (count != previewsize - 1) + { + free(buf); + return false; + } + + QString previewstr = QString::fromLatin1(buf); + free(buf); + + int offset = 0; + while ((offset < previewsize) && !(previewstr[offset].isDigit())) offset++; + int digits = 0; + while ((offset + digits < previewsize) && previewstr[offset + digits].isDigit()) digits++; + int width = previewstr.mid(offset, digits).toInt(); + offset += digits + 1; + while ((offset < previewsize) && !(previewstr[offset].isDigit())) offset++; + digits = 0; + while ((offset + digits < previewsize) && previewstr[offset + digits].isDigit()) digits++; + int height = previewstr.mid(offset, digits).toInt(); + offset += digits + 1; + while ((offset < previewsize) && !(previewstr[offset].isDigit())) offset++; + digits = 0; + while ((offset + digits < previewsize) && previewstr[offset + digits].isDigit()) digits++; + int depth = previewstr.mid(offset, digits).toInt(); + + // skip over the rest of the BeginPreview comment + while ((offset < previewsize) && + previewstr[offset] != '\n' && + previewstr[offset] != '\r') offset++; + while ((offset < previewsize) && previewstr[offset] != '%') offset++; + + unsigned int imagedepth; + switch (depth) { + case 1: + case 2: + case 4: + case 8: + imagedepth = 8; + break; + case 12: // valid, but not (yet) supported + default: // illegal value + return false; + } + + unsigned int colors = (1U << depth); + QImage img(width, height, imagedepth, colors); + img.setAlphaBuffer(false); + + if (imagedepth <= 8) { + for (unsigned int gray = 0; gray < colors; gray++) { + unsigned int grayvalue = (255U * (colors - 1 - gray)) / + (colors - 1); + img.setColor(gray, qRgb(grayvalue, grayvalue, grayvalue)); + } + } + + const unsigned int bits_per_scan_line = width * depth; + unsigned int bytes_per_scan_line = bits_per_scan_line / 8; + if (bits_per_scan_line % 8) bytes_per_scan_line++; + const unsigned int bindatabytes = height * bytes_per_scan_line; + QMemArray bindata(bindatabytes); + + for (unsigned int i = 0; i < bindatabytes; i++) { + if (offset >= previewsize) + return false; + + while (!isxdigit(previewstr[offset].latin1()) && + offset < previewsize) + offset++; + + bool ok = false; + bindata[i] = static_cast(previewstr.mid(offset, 2).toUInt(&ok, 16)); + if (!ok) + return false; + + offset += 2; + } + + for (int scanline = 0; scanline < height; scanline++) { + unsigned char *scanlineptr = img.scanLine(scanline); + + for (int pixelindex = 0; pixelindex < width; pixelindex++) { + unsigned char pixelvalue = 0; + const unsigned int bitoffset = + scanline * bytes_per_scan_line * 8U + pixelindex * depth; + for (int depthindex = 0; depthindex < depth; + depthindex++) { + const unsigned int byteindex = (bitoffset + depthindex) / 8U; + const unsigned int bitindex = + 7 - ((bitoffset + depthindex) % 8U); + const unsigned char bitvalue = + (bindata[byteindex] & static_cast(1U << bitindex)) >> bitindex; + pixelvalue |= (bitvalue << depthindex); + } + scanlineptr[pixelindex] = pixelvalue; + } + } + + outimg = img.convertDepth(32).smoothScale(imgwidth, imgheight); + + return true; +} diff --git a/kfile-plugins/ps/gscreator.h b/kfile-plugins/ps/gscreator.h new file mode 100644 index 00000000..b91fb0b0 --- /dev/null +++ b/kfile-plugins/ps/gscreator.h @@ -0,0 +1,42 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 Malte Starostik + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 _GSCREATOR_H_ +#define _GSCREATOR_H_ + +#include +#include "dscparse_adapter.h" + +class GSCreator : public ThumbCreator, public KDSCCommentHandler +{ +public: + GSCreator() {}; + virtual bool create(const QString &path, int, int, QImage &img); + virtual Flags flags() const; + void comment(Name name); + +private: + static bool getEPSIPreview(const QString &path, + long start, long end, + QImage &outimg, + int imgwidth, int imgheight); + bool endComments; +}; + +#endif diff --git a/kfile-plugins/ps/gsthumbnail.desktop b/kfile-plugins/ps/gsthumbnail.desktop new file mode 100644 index 00000000..0211020e --- /dev/null +++ b/kfile-plugins/ps/gsthumbnail.desktop @@ -0,0 +1,60 @@ +[Desktop Entry] +Type=Service +Name=PostScript, PDF and DVI Files +Name[ar]=ملفات الــ PostScript ، PDF و DVI +Name[br]=Restroù PostScript, PDF ha DVI +Name[bs]=Postscript, PDF i DVI datoteke +Name[ca]=Fitxers PostScript, PDF i DVI +Name[cs]=Postscriptové, PDF a DVI soubory +Name[cy]=Ffeiliau PostScript, PDF a DVI +Name[da]=PostScript, PDF- og DVI-filer +Name[de]=PostScript-, PDF- und DVI-Dateien +Name[el]=Αρχεία PostScript, PDF και DVI +Name[eo]=Postskriptaj, PDF- kaj DVI-dosieroj +Name[es]=Archivos PostScript, PDF y DVI +Name[et]=PostScript-, PDF- ja DVI-failid +Name[eu]=PostScript, PDF eta DVI fitxategiak +Name[fa]=پرونده‌های PostScript، PDF و DVI +Name[fi]=PostScript-, PDF- ja DVI-tiedostot +Name[fr]=Fichiers PostScript, PDF et DVI +Name[ga]=Comhaid PostScript, PDF agus DVI +Name[gl]=Ficheiros PostScript, PDF e DVI +Name[he]=קבצי PostScript, PDF ו־DVI +Name[hu]=PostScript-, PDF- és DVI-fájlok +Name[is]=PostScript PDF og DVI skrár +Name[it]=File PostScript, PDF e DVI +Name[ja]=Postscript,PDF,DVIファイル +Name[kk]=PostScript, PDF және DVI файлдары +Name[km]=ឯកសារ PostScript, PDF និង DVI +Name[lt]=Postscript, PDF ir DVI bylos +Name[ms]=PostScript, PDF dan Fail DVI +Name[nb]=PostScript, PDF og DVI filer +Name[nds]=PostScript-, PDF- un DVI-Dateien +Name[ne]=पोष्टस्क्रिप्ट, PDF र DVI फाइल +Name[nl]=PostScript-, DVI- en PDF-bestanden +Name[nn]=PostScript-, PDF- og DVI-filer +Name[pl]=Pliki PostScript, PDF i DVI +Name[pt]=Ficheiros PostScript, PDF e DVI +Name[pt_BR]=Arquivos PostScript, PDF e DVI +Name[ro]=Fişiere PostScript, PDF şi DVI +Name[ru]=Файлы PostScript, PDF и DVI +Name[se]=PostScript-, PDF- ja DVI-fiillat +Name[sk]=PostScript, PDF a DVI súbory +Name[sl]=Datoteke PostScript, PDF in DVI +Name[sr]=PostScript, PDF и DVI фајлови +Name[sr@Latn]=PostScript, PDF i DVI fajlovi +Name[sv]=Postscript, PDF och DVI-filer +Name[ta]= போஸ்ட்கிரிப்ட், பிடிஃப் மற்றும் டிவிஐ கோப்புகள் +Name[tg]=Файлҳои PostScript, PDF ва DVI +Name[th]=แฟ้ม PDF, DVI และ โพสต์สคริปต์ +Name[tr]=PostScript, PDF ve DVI Dosyaları +Name[uk]=Файли PostScript, PDF та DVI +Name[uz]=PostScript, PDF va DVI fayllari +Name[uz@cyrillic]=PostScript, PDF ва DVI файллари +Name[zh_CN]=PostScript、PDF 和 DVI 文件 +Name[zh_HK]=PostScript 、PDF 及 DVI 檔案 +Name[zh_TW]=PostScript,PDF 與 DVI 檔 +ServiceTypes=ThumbCreator +MimeTypes=application/x-dvi,application/postscript,application/pdf,image/x-eps +X-KDE-Library=gsthumbnail +CacheThumbnail=true diff --git a/kfile-plugins/ps/kfile_ps.cpp b/kfile-plugins/ps/kfile_ps.cpp new file mode 100644 index 00000000..6d3caa31 --- /dev/null +++ b/kfile-plugins/ps/kfile_ps.cpp @@ -0,0 +1,124 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Wilco Greven + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#include "kfile_ps.h" + +#include + +#include +#include +#include + +typedef KGenericFactory PSFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_ps, PSFactory("kfile_ps")) + +KPSPlugin::KPSPlugin(QObject *parent, const char *name, + const QStringList &preferredItems) : + KFilePlugin( parent, name, preferredItems ) +{ + kdDebug(7034) << "ps plugin\n"; + + // set up our mimetypes + makeMimeTypeInfo( "application/postscript" ); + makeMimeTypeInfo( "image/x-eps" ); +} + +void KPSPlugin::makeMimeTypeInfo( const char* mimeType ) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo( mimeType ); + + // general group + KFileMimeTypeInfo::GroupInfo* group = addGroupInfo(info, "General", i18n("General")); + addItemInfo(group, "Title", i18n("Title"), QVariant::String); + addItemInfo(group, "Creator", i18n("Creator"), QVariant::String); + addItemInfo(group, "CreationDate", i18n("Creation Date"), QVariant::String); + addItemInfo(group, "For", i18n("For"), QVariant::String); + addItemInfo(group, "Pages", i18n("Pages"), QVariant::UInt); +} + +bool KPSPlugin::readInfo( KFileMetaInfo& info, uint /* what */) +{ + _info = info; + _group = appendGroup(info, "General"); + _endComments = false; + _setData = 0; + + _dsc = new KDSC; + _dsc->setCommentHandler( this ); + FILE* fp = fopen( QFile::encodeName( info.path() ), "r" ); + if( fp == 0 ) + return false; + + char buf[4096]; + int count; + while( ( count = fread( buf, sizeof(char), sizeof( buf ), fp ) ) ) { + if ( !_dsc->scanData( buf, count ) ) break; + if ( _endComments || _setData == 5 ) break; // Change if new item scanned + } + fclose( fp ); + delete _dsc; + _dsc = 0; + + return _setData > 0; +} + +void KPSPlugin::comment( Name name ) +{ + switch( name ) + { + case Title: + appendItem(_group, "Title", _dsc->dsc_title()); + ++_setData; + break; + case Creator: + appendItem(_group, "Creator", _dsc->dsc_creator()); + ++_setData; + break; + case CreationDate: + appendItem(_group, "CreationDate", _dsc->dsc_date()); + ++_setData; + break; + case For: + appendItem(_group, "For", _dsc->dsc_for()); + ++_setData; + break; + case Pages: { + int pages = _dsc->page_pages(); + if (pages) + { + appendItem(_group, "Pages", pages); + ++_setData; + } + } + break; + + // Right now we watch for 5 elements: + // Title, Creator, CreationDate, For, Pages + // + // If you add another one(s), please update the 5 in "_setData == 5" above + // + case EndComments: _endComments = true; + default: ; // Ignore + } +} + +#include "kfile_ps.moc" + diff --git a/kfile-plugins/ps/kfile_ps.desktop b/kfile-plugins/ps/kfile_ps.desktop new file mode 100644 index 00000000..75b3e055 --- /dev/null +++ b/kfile-plugins/ps/kfile_ps.desktop @@ -0,0 +1,66 @@ +[Desktop Entry] +Type=Service +Name=PostScript Info +Name[af]=Postscript Inligting +Name[ar]=معلومات PostScript +Name[br]=Procinfo PostScript +Name[ca]=Informació de PostScript +Name[cs]=PostScript info +Name[cy]=Gwybodaeth PostScript +Name[da]=PostScript-info +Name[de]=PostScript-Info +Name[el]=Πληροφορίες PostScript +Name[eo]=Postskriptinformo +Name[es]=Info PostScript +Name[et]=PostScript info +Name[fa]=اطلاعات PostScript +Name[fi]=PostScript-tiedot +Name[fr]=Informations PostScript +Name[gl]=Inf. PostScript +Name[he]=מידע PostScript +Name[hi]=पोस्टस्क्रिप्ट जानकारी +Name[hr]=Postscript informacije +Name[hu]=PostScript-jellemzők +Name[is]=PostScript upplýsingar +Name[it]=Informazioni PostScript +Name[ja]=PostScript 情報 +Name[kk]=PostScript мәліметі +Name[km]=ព័ត៌មាន PostScript +Name[lt]=PostScript informacija +Name[lv]=Postscript Info +Name[ms]=Maklumat PostScript +Name[nb]=PostScript-info +Name[nds]=PostScript-Info +Name[ne]=पोष्टस्क्रिप्ट सूचना +Name[nl]=PostScript-info +Name[nn]=PostScript-info +Name[nso]=Tshedimoso ya PostScript +Name[pa]=PostScript ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku PostScriptu +Name[pt]=Informação do PostScript +Name[pt_BR]=Informação sobre PostScript +Name[ro]=Informaţii PostScript +Name[ru]=Информация о PostScript +Name[se]=PostScript-dieđut +Name[sl]=Podatki o PostScriptu +Name[sr]=PostScript информације +Name[sr@Latn]=PostScript informacije +Name[sv]=Postscript-information +Name[ta]=முன் எழுத்தாக்க தகவல் +Name[tg]=Иттилоот оиди PostScript +Name[th]=ข้อมูลโพสต์สคริปต์ +Name[tr]=PostScript Bilgisi +Name[uk]=Інформація про PostScript +Name[uz]=PostScript haqida maʼlumot +Name[uz@cyrillic]=PostScript ҳақида маълумот +Name[ven]=Mafhungo a mabammbiri a poso +Name[wa]=Informåcion sol documint PostScript +Name[xh]=Ulwazi Lwe PostScript +Name[zh_CN]=PostScript 信息 +Name[zh_HK]=PostScript 資訊 +Name[zh_TW]=PostScript 資訊 +Name[zu]=Ulwazi Lwesi-PostScript +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_ps +MimeType=application/postscript;image/x-eps +PreferredItems=Title,Creator,CreationDate,For,Pages diff --git a/kfile-plugins/ps/kfile_ps.h b/kfile-plugins/ps/kfile_ps.h new file mode 100644 index 00000000..339020d1 --- /dev/null +++ b/kfile-plugins/ps/kfile_ps.h @@ -0,0 +1,50 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Wilco Greven + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * $Id$ + */ + +#ifndef __KFILE_PS_H__ +#define __KFILE_PS_H__ + +#include + +#include "dscparse_adapter.h" + +class QStringList; + +class KPSPlugin: public KFilePlugin, public KDSCCommentHandler +{ + Q_OBJECT +public: + KPSPlugin( QObject *parent, const char *name, + const QStringList& preferredItems ); + + virtual bool readInfo( KFileMetaInfo& info, uint what); + + void comment( Name ); + void makeMimeTypeInfo( const char* mimeType ); + +private: + KFileMetaInfo _info; + KFileMetaInfoGroup _group; + KDSC* _dsc; + bool _endComments; + int _setData; +}; + +#endif diff --git a/kfile-plugins/raw/Makefile.am b/kfile-plugins/raw/Makefile.am new file mode 100644 index 00000000..c68309bc --- /dev/null +++ b/kfile-plugins/raw/Makefile.am @@ -0,0 +1,19 @@ +## Makefile.am for the raw thumbnail extration plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kcamerarawplugin.h + +kde_module_LTLIBRARIES = kfile_raw.la + +kfile_raw_la_SOURCES = kcamerarawplugin.cpp parse.c +kfile_raw_la_LIBADD = $(LIB_KIO) +kfile_raw_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +services_DATA = kfile_raw.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/raw/kcamerarawplugin.cpp b/kfile-plugins/raw/kcamerarawplugin.cpp new file mode 100644 index 00000000..525e53ae --- /dev/null +++ b/kfile-plugins/raw/kcamerarawplugin.cpp @@ -0,0 +1,141 @@ +/* This file is part of the KDE project + * Copyright (C) Steffen Hansen + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "kcamerarawplugin.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +typedef KGenericFactory RawFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_raw, RawFactory("kfile_raw")) + +#ifndef KDE_EXPORT +# define KDE_EXPORT +#endif + +/* Main entry point into raw parser */ +extern "C" { + int extract_thumbnail( FILE*, FILE*, int* ); + extern char make[]; + extern char model[]; +} + +bool KCameraRawPlugin::createPreview(const QString &path, QImage &img) +{ + /* Open file and extract thumbnail */ + FILE* input = fopen( QFile::encodeName(path), "rb" ); + if( !input ) return false; + KTempFile output; + output.setAutoDelete(true); + int orientation = 0; + if( extract_thumbnail( input, output.fstream(), &orientation ) ) { + fclose(input); + return false; + } + fclose(input); + output.close(); + if( !img.load( output.name() ) ) return false; + + if(orientation) { + QWMatrix M; + QWMatrix flip= QWMatrix(-1,0,0,1,0,0); + switch(orientation+1) { // notice intentional fallthroughs + case 2: M = flip; break; + case 4: M = flip; + case 3: M.rotate(180); break; + case 5: M = flip; + case 6: M.rotate(90); break; + case 7: M = flip; + case 8: M.rotate(270); break; + default: break; // should never happen + } + img = img.xForm(M); + } + return true; +} + +KCameraRawPlugin::KCameraRawPlugin(QObject *parent, const char *name, + const QStringList &args ) + : KFilePlugin(parent, name, args) +{ + kdDebug(7034) << "KCameraRawPlugin c'tor" << endl; + + // + // define all possible meta info items + // + KFileMimeTypeInfo *info = addMimeTypeInfo("image/x-raw"); + KFileMimeTypeInfo::GroupInfo *group = addGroupInfo( info, "Info", + i18n("Image Info") ); + KFileMimeTypeInfo::ItemInfo* item; + + item = addItemInfo( group, "Manufacturer", i18n("Camera Manufacturer"), + QVariant::String ); + item = addItemInfo( group, "Model", i18n("Camera Model"), + QVariant::String ); + item = addItemInfo( group, "Thumbnail", i18n("Thumbnail"), + QVariant::Image ); + setHint( item, KFileMimeTypeInfo::Thumbnail ); +} + +bool KCameraRawPlugin::readInfo( KFileMetaInfo& info, uint what ) +{ + kdDebug(7034) << "KCameraRawPlugin::readInfo()" << endl; + + const QString path( info.path() ); + if ( path.isEmpty() ) // remote file + return false; + + KFileMetaInfoGroup group = appendGroup( info, "Info" ); + if ( what & KFileMetaInfo::Thumbnail ){ + QImage img; + if( createPreview( path,img ) ) { + appendItem( group, "Thumbnail", img ); + kdDebug(7034) << "thumbnail " << path << " created" << endl; + } + } else { + // HACK: We have to extract thumbnail to get any info... + QImage img; + createPreview( path,img ); + } + kdDebug(7034) << "make=" << make << endl; + kdDebug(7034) << "model=" << model << endl; + if( make[0] ) { + appendItem( group, "Manufacturer", &make[0] ); + } + if( model[0] ) { + appendItem( group, "Model", &model[0] ); + } + + return true; +} + +#include "kcamerarawplugin.moc" diff --git a/kfile-plugins/raw/kcamerarawplugin.h b/kfile-plugins/raw/kcamerarawplugin.h new file mode 100644 index 00000000..5a097784 --- /dev/null +++ b/kfile-plugins/raw/kcamerarawplugin.h @@ -0,0 +1,38 @@ +/* This file is part of the KDE project + * Copyright (C) 2005 Steffen Hansen + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef KCAMERARAWPLUGIN_H +#define KCAMERARAWPLUGIN_H + +#include + +class QImage; + +class KCameraRawPlugin: public KFilePlugin { + Q_OBJECT + +public: + KCameraRawPlugin(QObject *parent, const char *name, const QStringList& args); + virtual bool readInfo(KFileMetaInfo& info, uint what); + +private: + bool createPreview(const QString &path, QImage &img); +}; + +#endif /* KCAMERARAWPLUGIN_H */ diff --git a/kfile-plugins/raw/kfile_raw.desktop b/kfile-plugins/raw/kfile_raw.desktop new file mode 100644 index 00000000..696d286e --- /dev/null +++ b/kfile-plugins/raw/kfile_raw.desktop @@ -0,0 +1,53 @@ +[Desktop Entry] +Type=Service +Name=RAW Camera Files +Name[br]=Restroù kamera kriz +Name[bs]=RAW kamera datoteke +Name[ca]=Fitxers RAW de càmera +Name[cs]=RAW soubory +Name[da]=RAW kamera-filer +Name[de]=RAW Kamera-Dateien +Name[el]=RAW αρχείο κάμερας +Name[es]=Archivos RAW de cámara +Name[et]=Toored kaamerafailid +Name[eu]=RAW kamera-fitxategiak +Name[fa]=پرونده‌های خام دوربین +Name[fi]=RAW-kuvatiedostot +Name[fr]=Fichiers RAW d'appareil photo numérique +Name[ga]=Comhaid Cheamara RAW +Name[gl]=Ficheiros RAW de Cámara +Name[he]=קבצי מצלמה דיגיטלית גולמיים +Name[hu]=RAW-fájlok +Name[is]=RAW myndavélaskrár +Name[it]=File grezzi fotocamera digitale +Name[ja]=RAW カメラファイル +Name[kk]=Камераның RAW пішімдегі файлдары +Name[km]=ឯកសារ​ចេញ​ពី​ម៉ាស៊ីន​ថត​រូប +Name[lt]=RAW fotoaparato bylos +Name[nb]=RAW-kamerafiler +Name[nds]=RAW-Kameradateien +Name[ne]=RAW क्यामेरा फाइल +Name[nl]=Rauwe camerabestanden +Name[nn]=RAW-kamerafiler +Name[pa]=RAW ਕੈਮਰਾ ਫਾਇਲਾਂ +Name[pl]=Pliki RAW z aparatów cyfrowych +Name[pt]=Ficheiros de Máquina Fotográfica Digital RAW +Name[pt_BR]=Arquivos de Câmeras +Name[ro]=Fişiere foto brute +Name[ru]=Необработанные Файлы с цифровой камеры (RAW) +Name[sk]=RAW súbory digitálneho fotoaparátu +Name[sl]=Surove datoteke s fotoaparata +Name[sr]=RAW фајлови слика +Name[sr@Latn]=RAW fajlovi slika +Name[sv]=Obehandlade kamerafiler +Name[th]=แฟ้มภาพ RAW จากกล้อง +Name[tr]=RAW Kamera Dosyaları +Name[uk]=Файли цифрової камери RAW +Name[zh_CN]=RAW 相机文件 +Name[zh_HK]=RAW 相機檔案 +Name[zh_TW]=原始相機檔 +ServiceTypes=KFilePlugin +MimeType=image/x-raw +X-KDE-Library=kfile_raw +CacheThumbnail=false +SupportsThumbnail=true diff --git a/kfile-plugins/raw/parse.c b/kfile-plugins/raw/parse.c new file mode 100644 index 00000000..1abbbfce --- /dev/null +++ b/kfile-plugins/raw/parse.c @@ -0,0 +1,1080 @@ +/* + Raw Photo Parser + Copyright 2004 by Dave Coffin, dcoffin a cybercom o net + + This program extracts thumbnail images (preferably JPEGs) + from any raw digital camera formats that have them, and + shows table contents. + + $Revision: 1.36 $ + $Date: 2005/05/10 21:43:10 $ + */ + +/* Hacked for thumbnail extraction in KDE by + Steffen Hansen + + Based on parse.c and parts of dcraw.c by Dave Coffin +*/ + +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +#include +typedef __int64 INT64; +#else +#include +typedef long long INT64; +#endif + +/* + TIFF and CIFF data blocks can be quite large. + Display only the first DLEN bytes. + */ +#ifndef DLEN +#define DLEN 768 +#endif + +typedef unsigned char uchar; +/*typedef unsigned short ushort;*/ + +FILE *ifp; +short order; +char *fname; +char make[128], model[128], model2[128], thumb_head[128]; +int width, height, offset, length, bps, is_dng; +int thumb_offset, thumb_length, thumb_layers; +float cam_mul[4], pre_mul[4], coeff[3][4]; +#define camera_red cam_mul[0] +#define camera_blue cam_mul[2] +/*float flash_used, canon_5814;*/ +time_t timestamp; +/*int data_offset, meta_offset*/ +int raw_height, raw_width, top_margin, left_margin; +static int flip = 0; + +struct decode { + struct decode *branch[2]; + int leaf; +} first_decode[640], *free_decode; + +#define CLASS + +#define FORC3 for (c=0; c < 3; c++) +#define FORC4 for (c=0; c < 4; c++) +#define FORCC for (c=0; c < colors; c++) + +/* + Get a 2-byte integer, making no assumptions about CPU byte order. + Nor should we assume that the compiler evaluates left-to-right. + */ +ushort get2() +{ + uchar a, b; + + a = fgetc(ifp); b = fgetc(ifp); + + if (order == 0x4949) /* "II" means little-endian */ + return a | b << 8; + else /* "MM" means big-endian */ + return a << 8 | b; +} + +/* + Same for a 4-byte integer. + */ +int get4() +{ + uchar a, b, c, d; + + a = fgetc(ifp); b = fgetc(ifp); + c = fgetc(ifp); d = fgetc(ifp); + + if (order == 0x4949) + return a | b << 8 | c << 16 | d << 24; + else + return a << 24 | b << 16 | c << 8 | d; +} + +void tiff_dump(int base, int tag, int type, int count, int level) +{ + int save, j, num, den; + uchar c; + int size[] = { 1,1,1,2,4,8,1,1,2,4,8,4,8 }; + + if (count * size[type < 13 ? type:0] > 4) + fseek (ifp, get4()+base, SEEK_SET); + save = ftell(ifp); + fseek (ifp, save, SEEK_SET); +} + +void nikon_decrypt (uchar ci, uchar cj, int tag, int i, int size, uchar *buf) +{ +} + +int parse_tiff_ifd (int base, int level); + +void nef_parse_makernote (base) +{ + int offset=0, entries, tag, type, count, val, save; + unsigned serial=0, key=0; + uchar buf91[630], buf97[608], buf98[31]; + short sorder; + char buf[10]; + +/* + The MakerNote might have its own TIFF header (possibly with + its own byte-order!), or it might just be a table. + */ + sorder = order; + fread (buf, 1, 10, ifp); + if (!strcmp (buf,"Nikon")) { /* starts with "Nikon\0\2\0\0\0" ? */ + base = ftell(ifp); + order = get2(); /* might differ from file-wide byteorder */ + val = get2(); /* should be 42 decimal */ + offset = get4(); + fseek (ifp, offset-8, SEEK_CUR); + } else if (!strncmp (buf,"FUJIFILM",8) || + !strcmp (buf,"Panasonic")) { + order = 0x4949; + fseek (ifp, 2, SEEK_CUR); + } else if (!strcmp (buf,"OLYMP") || + !strcmp (buf,"LEICA") || + !strcmp (buf,"EPSON")) + fseek (ifp, -2, SEEK_CUR); + else if (!strcmp (buf,"AOC")) + fseek (ifp, -4, SEEK_CUR); + else + fseek (ifp, -10, SEEK_CUR); + + entries = get2(); + if (entries > 100) return; + while (entries--) { + save = ftell(ifp); + tag = get2(); + type = get2(); + count= get4(); + tiff_dump (base, tag, type, count, 2); + if (tag == 0x1d) + fscanf (ifp, "%d", &serial); + if (tag == 0x91) + fread (buf91, sizeof buf91, 1, ifp); + if (tag == 0x97) + fread (buf97, sizeof buf97, 1, ifp); + if (tag == 0x98) + fread (buf98, sizeof buf98, 1, ifp); + if (tag == 0xa7) + key = fgetc(ifp)^fgetc(ifp)^fgetc(ifp)^fgetc(ifp); + + if (tag == 0x100 && type == 7 && !strncmp(make,"OLYMPUS",7)) { + thumb_offset = ftell(ifp); + thumb_length = count; + } + if (tag == 0x280 && type == 1) { /* EPSON */ + strncpy (thumb_head, "\xff", sizeof(thumb_head) ); + thumb_offset = ftell(ifp)+1; + thumb_length = count-1; + } + if (strstr(make,"Minolta") || strstr(make,"MINOLTA")) { + switch (tag) { + case 0x81: + thumb_offset = ftell(ifp); + thumb_length = count; + break; + case 0x88: + thumb_offset = get4() + base; + break; + case 0x89: + thumb_length = get4(); + } + } + if (!strcmp (buf,"OLYMP") && tag >> 8 == 0x20) + parse_tiff_ifd (base, 3); + fseek (ifp, save+12, SEEK_SET); + } + nikon_decrypt (serial, key, 0x91, 4, sizeof buf91, buf91); + nikon_decrypt (serial, key, 0x97, 284, sizeof buf97, buf97); + nikon_decrypt (serial, key, 0x98, 4, sizeof buf98, buf98); + order = sorder; +} + +void nef_parse_exif(int base) +{ + int entries, tag, type, count, save; + + entries = get2(); + while (entries--) { + save = ftell(ifp); + tag = get2(); + type = get2(); + count= get4(); + tiff_dump (base, tag, type, count, 1); + if (tag == 0x927c) + nef_parse_makernote (base); + fseek (ifp, save+12, SEEK_SET); + } +} + +int parse_tiff_ifd (int base, int level) +{ + int entries, tag, type, count, slen, save, save2, val, i; + int comp=0; + static const int flip_map[] = { 0,1,3,2,4,6,7,5 }; + + entries = get2(); + if (entries > 255) return 1; + while (entries--) { + save = ftell(ifp); + tag = get2(); + type = get2(); + count= get4(); + slen = count; + if (slen > 128) slen = 128; + + tiff_dump (base, tag, type, count, level); + + save2 = ftell(ifp); + if (type == 3) /* short int */ + val = get2(); + else + val = get4(); + fseek (ifp, save2, SEEK_SET); + + if (tag > 50700 && tag < 50800) + is_dng = 1; + + if (level == 3) { /* Olympus E-1 and E-300 */ + if (type == 4) { + if (tag == 0x101) + thumb_offset = val; + else if (tag == 0x102) + thumb_length = val; + } + goto cont; + } + switch (tag) { + case 0x100: /* ImageWidth */ + if (!width) width = val; + break; + case 0x101: /* ImageHeight */ + if (!height) height = val; + break; + case 0x102: /* Bits per sample */ + if (bps) break; + bps = val; + if (count == 1) + thumb_layers = 1; + break; + case 0x103: /* Compression */ + comp = val; + break; + case 0x10f: /* Make tag */ + fgets (make, slen, ifp); + break; + case 0x110: /* Model tag */ + fgets (model, slen, ifp); + break; + case 33405: /* Model2 tag */ + fgets (model2, slen, ifp); + break; + case 0x111: /* StripOffset */ + if (!offset || is_dng) offset = val; + break; + case 0x112: /* Orientation */ + flip = flip_map[(val-1) & 7]; + break; + case 0x117: /* StripByteCounts */ + if (!length || is_dng) length = val; + if (offset > val && !strncmp(make,"KODAK",5) && !is_dng) + offset -= val; + break; + case 0x14a: /* SubIFD tag */ + save2 = ftell(ifp); + for (i=0; i < count; i++) { + fseek (ifp, save2 + i*4, SEEK_SET); + fseek (ifp, get4()+base, SEEK_SET); + parse_tiff_ifd (base, level+1); + } + break; + case 0x201: + if (strncmp(make,"OLYMPUS",7) || !thumb_offset) + thumb_offset = val; + break; + case 0x202: + if (strncmp(make,"OLYMPUS",7) || !thumb_length) + thumb_length = val; + break; + case 34665: + fseek (ifp, get4()+base, SEEK_SET); + nef_parse_exif (base); + break; + case 50706: + is_dng = 1; + } +cont: + fseek (ifp, save+12, SEEK_SET); + } + if ((comp == 6 && !strcmp(make,"Canon")) || + (comp == 7 && is_dng)) { + thumb_offset = offset; + thumb_length = length; + } + return 0; +} + +/* + Parse a TIFF file looking for camera model and decompress offsets. + */ +void parse_tiff (int base) +{ + int doff, spp=3, ifd=0; + + width = height = offset = length = bps = is_dng = 0; + fseek (ifp, base, SEEK_SET); + order = get2(); + if (order != 0x4949 && order != 0x4d4d) return; + get2(); + while ((doff = get4())) { + fseek (ifp, doff+base, SEEK_SET); + printf ("IFD #%d:\n", ifd++); + if (parse_tiff_ifd (base, 0)) break; + } + if (is_dng) return; + + if (strncmp(make,"KODAK",5)) + thumb_layers = 0; + if (!strncmp(make,"Kodak",5)) { + fseek (ifp, 12+base, SEEK_SET); + puts ("\nSpecial Kodak image directory:"); + parse_tiff_ifd (base, 0); + } + if (!strncmp(model,"DCS460A",7)) { + spp = 1; + thumb_layers = 0; + } + if (!thumb_length && offset) { + thumb_offset = offset; + sprintf (thumb_head, "P%d %d %d %d\n", + spp > 1 ? 6:5, width, height, (1 << bps) - 1); + thumb_length = width * height * spp * ((bps+7)/8); + } +} + +void parse_minolta() +{ + int data_offset, save, tag, len; + + fseek (ifp, 4, SEEK_SET); + data_offset = get4() + 8; + while ((save=ftell(ifp)) < data_offset) { + tag = get4(); + len = get4(); + printf ("Tag %c%c%c offset %06x length %06x\n", + tag>>16, tag>>8, tag, save, len); + switch (tag) { + case 0x545457: /* TTW */ + parse_tiff (ftell(ifp)); + } + fseek (ifp, save+len+8, SEEK_SET); + } + strncpy (thumb_head, "\xff", sizeof(thumb_head) ); + thumb_offset++; + thumb_length--; +} + +/* + Parse a CIFF file, better known as Canon CRW format. + */ +void parse_ciff (int offset, int length, int level /*unused*/) +{ + int tboff, nrecs, i, c, type, len, roff, aoff, save, wbi=-1; + static const int remap[] = { 1,2,3,4,5,1 }; + static const int remap_10d[] = { 0,1,3,4,5,6,0,0,2,8 }; + static const int remap_s70[] = { 0,1,2,9,4,3,6,7,8,9,10,0,0,0,7,0,0,8 }; + ushort key[] = { 0x410, 0x45f3 }; + + if (strcmp(model,"Canon PowerShot G6") && + strcmp(model,"Canon PowerShot S60") && + strcmp(model,"Canon PowerShot S70") && + strcmp(model,"Canon PowerShot Pro1")) + key[0] = key[1] = 0; + fseek (ifp, offset+length-4, SEEK_SET); + tboff = get4() + offset; + fseek (ifp, tboff, SEEK_SET); + nrecs = get2(); + if (nrecs > 100) return; + for (i = 0; i < nrecs; i++) { + type = get2(); + len = get4(); + roff = get4(); + aoff = offset + roff; + save = ftell(ifp); + if (type == 0x080a) { /* Get the camera make and model */ + fseek (ifp, aoff, SEEK_SET); + fread (make, 64, 1, ifp); + fseek (ifp, aoff+strlen(make)+1, SEEK_SET); + fread (model, 64, 1, ifp); + } + if (type == 0x102a) { /* Find the White Balance index */ + fseek (ifp, aoff+14, SEEK_SET); /* 0=auto, 1=daylight, 2=cloudy ... */ + wbi = get2(); + if (((!strcmp(model,"Canon EOS DIGITAL REBEL") || + !strcmp(model,"Canon EOS 300D DIGITAL"))) && wbi == 6) + wbi++; + } + if (type == 0x102c) { /* Get white balance (G2) */ + if (!strcmp(model,"Canon PowerShot G1") || + !strcmp(model,"Canon PowerShot Pro90 IS")) { + fseek (ifp, aoff+120, SEEK_SET); + FORC4 cam_mul[c ^ 2] = get2(); + } else { + fseek (ifp, aoff+100, SEEK_SET); + goto common; + } + } + if (type == 0x0032) { /* Get white balance (D30 & G3) */ + if (!strcmp(model,"Canon EOS D30")) { + fseek (ifp, aoff+72, SEEK_SET); +common: + camera_red = get2() ^ key[0]; + camera_red =(get2() ^ key[1]) / camera_red; + camera_blue = get2() ^ key[0]; + camera_blue /= get2() ^ key[1]; + } else if (!strcmp(model,"Canon PowerShot G6") || + !strcmp(model,"Canon PowerShot S60") || + !strcmp(model,"Canon PowerShot S70")) { + fseek (ifp, aoff+96 + remap_s70[wbi]*8, SEEK_SET); + goto common; + } else if (!strcmp(model,"Canon PowerShot Pro1")) { + fseek (ifp, aoff+96 + wbi*8, SEEK_SET); + goto common; + } else { + fseek (ifp, aoff+80 + (wbi < 6 ? remap[wbi]*8 : 0), SEEK_SET); + if (!camera_red) + goto common; + } + } + if (type == 0x10a9) { /* Get white balance (D60) */ + if (!strcmp(model,"Canon EOS 10D")) + wbi = remap_10d[wbi]; + fseek (ifp, aoff+2 + wbi*8, SEEK_SET); + camera_red = get2(); + camera_red /= get2(); + camera_blue = get2(); + camera_blue = get2() / camera_blue; + } + /* Skip this for now /steffen */ +#if 0 + if (type == 0x1030 && (wbi == 6 || wbi == 15)) { + fseek (ifp, aoff, SEEK_SET); /* Get white sample */ + ciff_block_1030(); + } +#endif + if (type == 0x1031) { /* Get the raw width and height */ + fseek (ifp, aoff+2, SEEK_SET); + raw_width = get2(); + raw_height = get2(); + } + if (type == 0x180e) { /* Get the timestamp */ + fseek (ifp, aoff, SEEK_SET); + timestamp = get4(); + } + if (type == 0x580e) + timestamp = len; +#if 0 + if (type == 0x5813) + flash_used = *((float *) &len); + if (type == 0x5814) + canon_5814 = *((float *) &len); +#endif + if (type == 0x1810) { /* Get the rotation */ + fseek (ifp, aoff+12, SEEK_SET); + flip = get4(); + } + /* Skip this for now /steffen */ +#if 0 + if (type == 0x1835) { /* Get the decoder table */ + fseek (ifp, aoff, SEEK_SET); + crw_init_tables (get4()); + } +#endif + if (type == 0x2007) { /* Found the JPEG thumbnail */ + thumb_offset = aoff; + thumb_length = len; + } + if (type >> 8 == 0x28 || type >> 8 == 0x30) /* Get sub-tables */ + parse_ciff(aoff, len, level+1); + fseek (ifp, save, SEEK_SET); + } + if (wbi == 0 && !strcmp(model,"Canon EOS D30")) + camera_red = -1; /* Use my auto WB for this photo */ +} + + +void parse_mos(int level) +{ + uchar data[256]; + int i, j, skip, save; + char *cp; + + save = ftell(ifp); + while (1) { + fread (data, 1, 8, ifp); + if (strcmp(data,"PKTS")) break; + strcpy (model, "Valeo"); + fread (data, 1, 40, ifp); + skip = get4(); + if (!strcmp(data,"icc_camera_to_tone_matrix")) { + for (i=0; i < skip/4; i++) { + j = get4(); + } + continue; + } + if (!strcmp(data,"JPEG_preview_data")) { + thumb_head[0] = 0; + thumb_offset = ftell(ifp); + thumb_length = skip; + } + fread (data, 1, sizeof data, ifp); + fseek (ifp, -sizeof data, SEEK_CUR); + data[sizeof data - 1] = 0; + while ((cp=index(data,'\n'))) + *cp = ' '; + parse_mos(level+2); + fseek (ifp, skip, SEEK_CUR); + } + fseek (ifp, save, SEEK_SET); +} + +void parse_rollei() +{ + char line[128], *val; + + fseek (ifp, 0, SEEK_SET); + do { + fgets (line, 128, ifp); + fputs (line, stdout); + if ((val = strchr(line,'='))) + *val++ = 0; + else + val = line + strlen(line); + if (!strcmp(line,"HDR")) + thumb_offset = atoi(val); + if (!strcmp(line,"TX ")) + width = atoi(val); + if (!strcmp(line,"TY ")) + height = atoi(val); + } while (strncmp(line,"EOHD",4)); + strcpy (make, "Rollei"); + strcpy (model, "d530flex"); + thumb_length = width*height*2; +} + +void rollei_decode (FILE *tfp) +{ + ushort data; + int row, col; + + fseek (ifp, thumb_offset, SEEK_SET); + fprintf (tfp, "P6\n%d %d\n255\n", width, height); + for (row=0; row < height; row++) + for (col=0; col < width; col++) { + fread (&data, 2, 1, ifp); + data = ntohs(data); + putc (data << 3, tfp); + putc (data >> 5 << 2, tfp); + putc (data >> 11 << 3, tfp); + } +} + +void get_utf8 (int offset, char *buf, int len) +{ + ushort c; + char *cp; + + fseek (ifp, offset, SEEK_SET); + for (cp=buf; (c = get2()) && cp+3 < buf+len; ) { + if (c < 0x80) + *cp++ = c; + else if (c < 0x800) { + *cp++ = 0xc0 + (c >> 6); + *cp++ = 0x80 + (c & 0x3f); + } else { + *cp++ = 0xe0 + (c >> 12); + *cp++ = 0x80 + (c >> 6 & 0x3f); + *cp++ = 0x80 + (c & 0x3f); + } + } + *cp = 0; +} + +ushort sget2 (uchar *s) +{ + return s[0] + (s[1]<<8); +} + +int sget4 (uchar *s) +{ + return s[0] + (s[1]<<8) + (s[2]<<16) + (s[3]<<24); +} + +void parse_foveon() +{ + int entries, img=0, off, len, tag, save, i, j, k, pent, poff[256][2]; + char name[128], value[128], camf[0x20000], *pos, *cp, *dp; + unsigned val, key, type, num, ndim, dim[3]; + + order = 0x4949; /* Little-endian */ + fseek (ifp, -4, SEEK_END); + fseek (ifp, get4(), SEEK_SET); + if (get4() != 0x64434553) { /* SECd */ + printf ("Bad Section identifier at %6x\n", (int)ftell(ifp)-4); + return; + } + get4(); + entries = get4(); + while (entries--) { + off = get4(); + len = get4(); + tag = get4(); + save = ftell(ifp); + fseek (ifp, off, SEEK_SET); + if (get4() != (0x20434553 | (tag << 24))) { + printf ("Bad Section identifier at %6x\n", off); + goto next; + } + val = get4(); + switch (tag) { + case 0x32414d49: /* IMA2 */ + case 0x47414d49: /* IMAG */ + if (++img == 2) { /* second image */ + thumb_offset = off; + thumb_length = 1; + } + printf ("type %d, " , get4()); + printf ("format %2d, " , get4()); + printf ("columns %4d, " , get4()); + printf ("rows %4d, " , get4()); + printf ("rowsize %d\n" , get4()); + break; + case 0x464d4143: /* CAMF */ + printf ("type %d, ", get4()); + get4(); + for (i=0; i < 4; i++) + putchar(fgetc(ifp)); + val = get4(); + printf (" version %d.%d:\n",val >> 16, val & 0xffff); + key = get4(); + if ((len -= 28) > 0x20000) + len = 0x20000; + fread (camf, 1, len, ifp); + for (i=0; i < len; i++) { + key = (key * 1597 + 51749) % 244944; + val = key * (INT64) 301593171 >> 24; + camf[i] ^= ((((key << 8) - val) >> 1) + val) >> 17; + } + for (pos=camf; (unsigned) (pos-camf) < len; pos += sget4(pos+8)) { + if (strncmp (pos, "CMb", 3)) { + printf("Bad CAMF tag \"%.4s\"\n", pos); + break; + } + val = sget4(pos+4); + printf (" %4.4s version %d.%d: ", pos, val >> 16, val & 0xffff); + switch (pos[3]) { + case 'M': + cp = pos + sget4(pos+16); + type = sget4(cp); + ndim = sget4(cp+4); + dim[0] = dim[1] = dim[2] = 1; + printf ("%d-dimensonal array %s of type %d:\n Key: (", + ndim, pos+sget4(pos+12), sget4(cp)); + dp = pos + sget4(cp+8); + for (i=ndim; i--; ) { + cp += 12; + dim[i] = sget4(cp); + printf ("%s %d%s", pos+sget4(cp+4), dim[i], i ? ", ":")\n"); + } + for (i=0; i < dim[2]; i++) { + for (j=0; j < dim[1]; j++) { + printf (" "); + for (k=0; k < dim[0]; k++) + switch (type) { + case 0: + case 6: + printf ("%7d", sget2(dp)); + dp += 2; + break; + case 1: + case 2: + printf (" %d", sget4(dp)); + dp += 4; + break; + case 3: { + union { int ival; float fval; } __t; + __t.ival = sget4(dp); + printf (" %9f", __t.fval); + dp += 4; + } + } + printf ("\n"); + } + printf ("\n"); + } + break; + case 'P': + val = sget4(pos+16); + num = sget4(pos+val); + printf ("%s, %d parameters:\n", pos+sget4(pos+12), num); + cp = pos+val+8 + num*8; + for (i=0; i < num; i++) { + val += 8; + printf (" %s = %s\n", cp+sget4(pos+val), cp+sget4(pos+val+4)); + } + break; + case 'T': + cp = pos + sget4(pos+16); + printf ("%s = %.*s\n", pos+sget4(pos+12), sget4(cp), cp+4); + break; + default: + printf ("\n"); + } + } + break; + case 0x504f5250: /* PROP */ + printf ("entries %d, ", pent=get4()); + printf ("charset %d, ", get4()); + get4(); + printf ("nchars %d\n", get4()); + off += pent*8 + 24; + if (pent > 256) pent=256; + for (i=0; i < pent*2; i++) + poff[0][i] = off + get4()*2; + for (i=0; i < pent; i++) { + get_utf8 (poff[i][0], name, 128); + get_utf8 (poff[i][1], value, 128); + printf (" %s = %s\n", name, value); + if (!strcmp (name,"CAMMANUF")) + strncpy (make, value, sizeof(make)); + if (!strcmp (name,"CAMMODEL")) + strncpy (model, value, sizeof(value)); + } + } +next: + fseek (ifp, save, SEEK_SET); + } +} + +void foveon_tree (unsigned huff[1024], unsigned code) +{ + struct decode *cur; + int i, len; + + cur = free_decode++; + if (code) { + for (i=0; i < 1024; i++) + if (huff[i] == code) { + cur->leaf = i; + return; + } + } + if ((len = code >> 27) > 26) return; + code = (len+1) << 27 | (code & 0x3ffffff) << 1; + + cur->branch[0] = free_decode; + foveon_tree (huff, code); + cur->branch[1] = free_decode; + foveon_tree (huff, code+1); +} + +void foveon_decode (FILE *tfp) +{ + int bwide, row, col, bit=-1, c, i; + char *buf; + struct decode *dindex; + short pred[3]; + unsigned huff[1024], bitbuf=0; + + fseek (ifp, thumb_offset+16, SEEK_SET); + width = get4(); + height = get4(); + bwide = get4(); + fprintf (tfp, "P6\n%d %d\n255\n", width, height); + if (bwide > 0) { + buf = malloc(bwide); + for (row=0; row < height; row++) { + fread (buf, 1, bwide, ifp); + fwrite (buf, 3, width, tfp); + } + free (buf); + return; + } + for (i=0; i < 256; i++) + huff[i] = get4(); + memset (first_decode, 0, sizeof first_decode); + free_decode = first_decode; + foveon_tree (huff, 0); + + for (row=0; row < height; row++) { + memset (pred, 0, sizeof pred); + if (!bit) get4(); + for (col=bit=0; col < width; col++) { + for (c=0; c < 3; c++) { + for (dindex=first_decode; dindex->branch[0]; ) { + if ((bit = (bit-1) & 31) == 31) + for (i=0; i < 4; i++) + bitbuf = (bitbuf << 8) + fgetc(ifp); + dindex = dindex->branch[bitbuf >> bit & 1]; + } + pred[c] += dindex->leaf; + fputc (pred[c], tfp); + } + } + } +} + +void kodak_yuv_decode (FILE *tfp) +{ + uchar c, blen[384]; + unsigned row, col, len, bits=0; + INT64 bitbuf=0; + int i, li=0, si, diff, six[6], y[4], cb=0, cr=0, rgb[3]; + ushort *out, *op; + + fseek (ifp, thumb_offset, SEEK_SET); + width = (width+1) & -2; + height = (height+1) & -2; + fprintf (tfp, "P6\n%d %d\n65535\n", width, height); + out = malloc (width * 12); + if (!out) { + fprintf (stderr, "kodak_yuv_decode() malloc failed!\n"); + exit(1); + } + + for (row=0; row < height; row+=2) { + for (col=0; col < width; col+=2) { + if ((col & 127) == 0) { + len = (width - col + 1) * 3 & -4; + if (len > 384) len = 384; + for (i=0; i < len; ) { + c = fgetc(ifp); + blen[i++] = c & 15; + blen[i++] = c >> 4; + } + li = bitbuf = bits = y[1] = y[3] = cb = cr = 0; + if (len % 8 == 4) { + bitbuf = fgetc(ifp) << 8; + bitbuf += fgetc(ifp); + bits = 16; + } + } + for (si=0; si < 6; si++) { + len = blen[li++]; + if (bits < len) { + for (i=0; i < 32; i+=8) + bitbuf += (INT64) fgetc(ifp) << (bits+(i^8)); + bits += 32; + } + diff = bitbuf & (0xffff >> (16-len)); + bitbuf >>= len; + bits -= len; + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - 1; + six[si] = diff; + } + y[0] = six[0] + y[1]; + y[1] = six[1] + y[0]; + y[2] = six[2] + y[3]; + y[3] = six[3] + y[2]; + cb += six[4]; + cr += six[5]; + for (i=0; i < 4; i++) { + op = out + ((i >> 1)*width + col+(i & 1)) * 3; + rgb[0] = y[i] + 1.40200/2 * cr; + rgb[1] = y[i] - 0.34414/2 * cb - 0.71414/2 * cr; + rgb[2] = y[i] + 1.77200/2 * cb; + for (c=0; c < 3; c++) + if (rgb[c] > 0) op[c] = htons(rgb[c]); + } + } + fwrite (out, sizeof *out, width*6, tfp); + } + free(out); +} + +void parse_phase_one (int base) +{ + unsigned entries, tag, type, len, data, save; + char str[256]; + + fseek (ifp, base + 8, SEEK_SET); + fseek (ifp, base + get4(), SEEK_SET); + entries = get4(); + get4(); + while (entries--) { + tag = get4(); + type = get4(); + len = get4(); + data = get4(); + save = ftell(ifp); + printf ("Phase One tag=0x%x, type=%d, len=%2d, data = 0x%x\n", + tag, type, len, data); + if (type == 1 && len < 256) { + fseek (ifp, base + data, SEEK_SET); + fread (str, 256, 1, ifp); + puts (str); + } + if (tag == 0x110) { + thumb_offset = data + base; + thumb_length = len; + } + fseek (ifp, save, SEEK_SET); + } + strcpy (make, "Phase One"); + strcpy (model, "unknown"); +} + +void parse_jpeg (int offset) +{ + int len, save, hlen; + + fseek (ifp, offset, SEEK_SET); + if (fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) return; + + while (fgetc(ifp) == 0xff && fgetc(ifp) >> 4 != 0xd) { + order = 0x4d4d; + len = get2() - 2; + save = ftell(ifp); + order = get2(); + hlen = get4(); + if (get4() == 0x48454150) /* "HEAP" */ + parse_ciff (save+hlen, len-hlen, 0); + parse_tiff (save+6); + fseek (ifp, save+len, SEEK_SET); + } +} + +char *raw_memmem (char *haystack, size_t haystacklen, + char *needle, size_t needlelen) +{ + char *c; + for (c = haystack; c <= haystack + haystacklen - needlelen; c++) + if (!memcmp (c, needle, needlelen)) + return c; + return NULL; +} + +/* + Identify which camera created this file, and set global variables + accordingly. + Return nonzero if the file cannot be decoded or no thumbnail is found + */ +int identify(FILE* tfp) +{ + char head[32], *thumb, *rgb, *cp; + unsigned hlen, fsize, toff, tlen, lsize, i; + + make[0] = model[0] = model2[0] = is_dng = 0; + thumb_head[0] = thumb_offset = thumb_length = thumb_layers = 0; + order = get2(); + hlen = get4(); + fseek (ifp, 0, SEEK_SET); + fread (head, 1, 32, ifp); + fseek (ifp, 0, SEEK_END); + fsize = ftell(ifp); + if ((cp = raw_memmem (head, 32, "MMMMRawT", 8)) || + (cp = raw_memmem (head, 32, "IIIITwaR", 8))) + parse_phase_one (cp - head); + else if (order == 0x4949 || order == 0x4d4d) { + if (!memcmp(head+6,"HEAPCCDR",8)) { + parse_ciff (hlen, fsize - hlen, 0); + fseek (ifp, hlen, SEEK_SET); + } else + parse_tiff (0); + } else if (!memcmp (head, "\0MRM", 4)) + parse_minolta(); + else if (!memcmp (head, "\xff\xd8\xff\xe1", 4) && + !memcmp (head+6, "Exif", 4)) { + parse_tiff (12); + thumb_length = 0; + } else if (!memcmp (head, "FUJIFILM", 8)) { + fseek (ifp, 84, SEEK_SET); + toff = get4(); + tlen = get4(); + thumb_offset = toff; + thumb_length = tlen; + } else if (!memcmp (head, "DSC-Image", 9)) + parse_rollei(); + else if (!memcmp (head, "FOVb", 4)) + parse_foveon(); + fseek (ifp, 8, SEEK_SET); + parse_mos(0); + fseek (ifp, 3472, SEEK_SET); + parse_mos(0); + parse_jpeg(0); + + if (!thumb_length) { + fprintf (stderr, "Thumbnail image not found\n"); + return -1; + } + + if (is_dng) goto dng_skip; + if (!strncmp(model,"DCS Pro",7)) { + kodak_yuv_decode (tfp); + goto done; + } + if (!strcmp(make,"Rollei")) { + rollei_decode (tfp); + goto done; + } + if (!strcmp(make,"SIGMA")) { + foveon_decode (tfp); + goto done; + } +dng_skip: + thumb = (char *) malloc(thumb_length); + if (!thumb) { + fprintf (stderr, "Cannot allocate %d bytes!!\n", thumb_length); + exit(1); + } + fseek (ifp, thumb_offset, SEEK_SET); + fread (thumb, 1, thumb_length, ifp); + if (thumb_layers && !is_dng) { + rgb = (char *) malloc(thumb_length); + if (!rgb) { + fprintf (stderr, "Cannot allocate %d bytes!!\n", thumb_length); + return -1; + } + lsize = thumb_length/3; + for (i=0; i < thumb_length; i++) + rgb[(i%lsize)*3 + i/lsize] = thumb[i]; + free(thumb); + thumb = rgb; + } + fputs (thumb_head, tfp); + fwrite(thumb, 1, thumb_length, tfp); + free (thumb); +done: + fprintf (stderr, "Thumbnail image written, make=%s, model=%s\n",&(make[0]),&(model[0])); + return 0; +} + +int extract_thumbnail( FILE* input, FILE* output, int* orientation ) +{ + /* Coffin's code has different meaning for orientation + values than TIFF, so we map them to TIFF values */ + static const int flip_map[] = { 0,1,3,2,4,7,5,6 }; + int rc; + ifp = input; + rc = identify(output); + switch ((flip+3600) % 360) { + case 270: flip = 5; break; + case 180: flip = 3; break; + case 90: flip = 6; + } + if( orientation ) *orientation = flip_map[flip%7]; + return rc; +} diff --git a/kfile-plugins/rgb/Makefile.am b/kfile-plugins/rgb/Makefile.am new file mode 100644 index 00000000..8fc22e17 --- /dev/null +++ b/kfile-plugins/rgb/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for rgb file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_rgb.h + +kde_module_LTLIBRARIES = kfile_rgb.la + +kfile_rgb_la_SOURCES = kfile_rgb.cpp +kfile_rgb_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_rgb_la_LIBADD = $(LIB_KSYCOCA) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_rgb.cpp -o $(podir)/kfile_rgb.pot + +services_DATA = kfile_rgb.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/rgb/kfile_rgb.cpp b/kfile-plugins/rgb/kfile_rgb.cpp new file mode 100644 index 00000000..b7b55035 --- /dev/null +++ b/kfile-plugins/rgb/kfile_rgb.cpp @@ -0,0 +1,208 @@ +/* This file is part of the KDE project + * Copyright (C) 2004 Melchior FRANZ + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include +#include "kfile_rgb.h" + +#include +#include + +#include +#include + + +typedef KGenericFactory RgbFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_rgb, RgbFactory("kfile_rgb")) + + +KRgbPlugin::KRgbPlugin(QObject *parent, const char *name, const QStringList &args) : + KFilePlugin(parent, name, args) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo("image/x-rgb"); + + KFileMimeTypeInfo::GroupInfo* group = 0; + KFileMimeTypeInfo::ItemInfo* item; + + + group = addGroupInfo(info, "Comment", i18n("Comment")); + + item = addItemInfo(group, "ImageName", i18n("Name"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + setHint(item, KFileMimeTypeInfo::Description); + + + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + + item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size); + setHint(item, KFileMimeTypeInfo::Size); + setUnit(item, KFileMimeTypeInfo::Pixels); + + item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::BitsPerPixel); + + item = addItemInfo(group, "ColorMode", i18n("Color Mode"), QVariant::String); + item = addItemInfo(group, "Compression", i18n("Compression"), QVariant::String); + item = addItemInfo(group, "SharedRows", + i18n("percentage of avoided vertical redundancy (the higher the better)", + "Shared Rows"), QVariant::String); + +} + + +bool KRgbPlugin::readInfo(KFileMetaInfo& info, uint /*what*/) +{ + QFile file(info.path()); + + if (!file.open(IO_ReadOnly)) { + kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl; + return false; + } + + QDataStream dstream(&file); + + Q_UINT16 magic; + Q_UINT8 storage; + Q_UINT8 bpc; + Q_UINT16 dimension; + Q_UINT16 xsize; + Q_UINT16 ysize; + Q_UINT16 zsize; + Q_UINT32 pixmin; + Q_UINT32 pixmax; + Q_UINT32 dummy; + char imagename[80]; + Q_UINT32 colormap; + + dstream >> magic; + dstream >> storage; + dstream >> bpc; + dstream >> dimension; + dstream >> xsize; + dstream >> ysize; + dstream >> zsize; + dstream >> pixmin; + dstream >> pixmax; + dstream >> dummy; + dstream.readRawBytes(imagename, 80); + imagename[79] = '\0'; + dstream >> colormap; + Q_UINT8 u8; + for (uint i = 0; i < 404; i++) + dstream >> u8; + + if (magic != 474) + return false; + + KFileMetaInfoGroup group; + + group = appendGroup(info, "Technical"); + + if (dimension == 1) + ysize = 1; + appendItem(group, "Dimensions", QSize(xsize, ysize)); + appendItem(group, "BitDepth", zsize * 8 * bpc); + + if (zsize == 1) + appendItem(group, "ColorMode", i18n("Grayscale")); + else if (zsize == 2) + appendItem(group, "ColorMode", i18n("Grayscale/Alpha")); + else if (zsize == 3) + appendItem(group, "ColorMode", i18n("RGB")); + else if (zsize == 4) + appendItem(group, "ColorMode", i18n("RGB/Alpha")); + + if (!storage) + appendItem(group, "Compression", i18n("Uncompressed")); + else if (storage == 1) { + long compressed = file.size() - 512; + long verbatim = xsize * ysize * zsize; + appendItem(group, "Compression", i18n("Runlength Encoded") + + QString(", %1%").arg(compressed * 100.0 / verbatim, 0, 'f', 1)); + + long k; + Q_UINT32 offs; + QMap map; + QMap::Iterator it; + QMap::Iterator end = map.end(); + for (k = 0; k < (ysize * zsize); k++) { + dstream >> offs; + if ((it = map.find(offs)) != end) + map.replace(offs, it.data() + 1); + else + map[offs] = 0; + } + for (k = 0, it = map.begin(); it != end; ++it) + k += it.data(); + + if (k) + appendItem(group, "SharedRows", QString("%1%").arg(k * 100.0 + / (ysize * zsize), 0, 'f', 1)); + else + appendItem(group, "SharedRows", i18n("None")); + } else + appendItem(group, "Compression", i18n("Unknown")); + + + group = appendGroup(info, "Comment"); + appendItem(group, "ImageName", imagename); + + file.close(); + return true; +} + + +bool KRgbPlugin::writeInfo(const KFileMetaInfo& info) const +{ + QFile file(info.path()); + + if (!file.open(IO_WriteOnly|IO_Raw)) { + kdDebug(7034) << "couldn't open " << QFile::encodeName(info.path()) << endl; + return false; + } + + if (!file.at(24)) { + kdDebug(7034) << "couldn't set offset" << endl; + return false; + } + + QDataStream dstream(&file); + QString s = info["Comment"]["ImageName"].value().toString(); + s.truncate(79); + + unsigned i; + for (i = 0; i < s.length(); i++) + dstream << Q_UINT8(s.latin1()[i]); + for (; i < 80; i++) + dstream << Q_UINT8(0); + + file.close(); + return true; +} + + +// restrict to 79 ASCII characters +QValidator* KRgbPlugin::createValidator(const QString&, const QString &, + const QString &, QObject* parent, const char* name) const +{ + return new QRegExpValidator(QRegExp("[\x0020-\x007E]{79}"), parent, name); +} + + +#include "kfile_rgb.moc" diff --git a/kfile-plugins/rgb/kfile_rgb.desktop b/kfile-plugins/rgb/kfile_rgb.desktop new file mode 100644 index 00000000..3a02989d --- /dev/null +++ b/kfile-plugins/rgb/kfile_rgb.desktop @@ -0,0 +1,61 @@ +[Desktop Entry] +Type=Service +Name=SGI Image (RGB) +Name[br]=Skeudenn SGI (RGB) +Name[bs]=SGI slika (RGB) +Name[ca]=Imatge SGI (RGB) +Name[cs]=SGI obrázek (RGB) +Name[cy]=Delwedd SGI (RGB) +Name[da]=SGI-billede (RGB) +Name[de]=SGI-Bild (RGB) +Name[el]=Εικόνα SGI (RGB) +Name[es]=Imagen SGI (RGB) +Name[et]=SGI pildifail (RGB) +Name[eu]=SGI irudia RGB) +Name[fa]=تصویر SGI (RGB) +Name[fi]=SGI-kuva (RGB) +Name[fr]=Image SGI (RVB) +Name[ga]=Íomhá SGI (RGB) +Name[gl]=Imaxe SGI (RGB) +Name[he]=תמונת SGI (RGB) +Name[hr]=SGI slika (RGB) +Name[hu]=SGI-kép (RGB) +Name[is]=SGI mynd (TGB) +Name[it]=Immagine SGI (RGB) +Name[ja]=SGI 画像 (RGB) +Name[kk]=SGI кескіні (RGB) +Name[km]=រូបភាព SGI (RGB) +Name[lt]=SGI paveiksliukas (RGB) +Name[ms]=Imej SGI (RGB) +Name[nb]=Bildeindeks +Name[nds]=SGI-Bild (RGB) +Name[ne]=SGI छवि (RGB) +Name[nl]=SGI-afbeelding (RGB) +Name[nn]=SGI-bilete (RGB) +Name[pl]=Obrazek SGI (RGB) +Name[pt]=Imagem SGI (RGB) +Name[pt_BR]=Imagem SGI (RGB) +Name[ro]=Imagine SGI (RGB) +Name[ru]=Изображение SGI (RGB) +Name[rw]=SGI Ishusho (RGB) +Name[se]=SGI-govva (RGB) +Name[sk]=SGI obrázok (RGB) +Name[sl]=Slika SGI (RGB) +Name[sr]=SGI слика (RGB) +Name[sr@Latn]=SGI slika (RGB) +Name[sv]=SGI-bild (RGB) +Name[ta]=எஸ்ஜிஐ படிமம் (RGB) +Name[tg]=Тасвироти SGI (RGB) +Name[th]=ภาพ SGI (RGB) +Name[tr]=SGI Resmi(KYM) +Name[uk]=Зображення SGI (RGB) +Name[uz]=SGI-rasm (RGB) +Name[uz@cyrillic]=SGI-расм (RGB) +Name[zh_CN]=SGI 图像(RGB) +Name[zh_HK]=SGI 圖像 (RGB) +Name[zh_TW]=SGI 影像(RGB) +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_rgb +MimeType=image/x-rgb +PreferredGroups=Comment,Technical +PreferredItems=Dimensions,BitDepth,ColorMode,Compression,SharedRows,ImageName diff --git a/kfile-plugins/rgb/kfile_rgb.h b/kfile-plugins/rgb/kfile_rgb.h new file mode 100644 index 00000000..dbbfef0e --- /dev/null +++ b/kfile-plugins/rgb/kfile_rgb.h @@ -0,0 +1,41 @@ +/* This file is part of the KDE project + * Copyright (C) 2004 Melcrhio FRANZ + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef __KFILE_RGB_H__ +#define __KFILE_RGB_H__ + +#include + +class QStringList; + +class KRgbPlugin : public KFilePlugin +{ + Q_OBJECT + +public: + KRgbPlugin(QObject *parent, const char *name, const QStringList& args); + virtual bool readInfo(KFileMetaInfo& info, uint what); + virtual bool writeInfo(const KFileMetaInfo& info) const; + virtual QValidator* createValidator(const QString& mimetype, + const QString &group, const QString &key, + QObject* parent, const char* name) const; + +}; + +#endif diff --git a/kfile-plugins/tga/Makefile.am b/kfile-plugins/tga/Makefile.am new file mode 100644 index 00000000..3856c26f --- /dev/null +++ b/kfile-plugins/tga/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for tga file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_tga.h + +kde_module_LTLIBRARIES = kfile_tga.la + +kfile_tga_la_SOURCES = kfile_tga.cpp +kfile_tga_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_tga_la_LIBADD = $(LIB_KSYCOCA) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_tga.cpp -o $(podir)/kfile_tga.pot + +services_DATA = kfile_tga.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/tga/kfile_tga.cpp b/kfile-plugins/tga/kfile_tga.cpp new file mode 100644 index 00000000..9c2c24dc --- /dev/null +++ b/kfile-plugins/tga/kfile_tga.cpp @@ -0,0 +1,165 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Shane Wright + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include +#include "kfile_tga.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if !defined(__osf__) +#include +#else +typedef unsigned long uint32_t; +typedef unsigned short uint16_t; +typedef unsigned char uint8_t; +#endif + +typedef KGenericFactory TgaFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_tga, TgaFactory( "kfile_tga" )) + +KTgaPlugin::KTgaPlugin(QObject *parent, const char *name, + const QStringList &args) + + : KFilePlugin(parent, name, args) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-targa" ); + + KFileMimeTypeInfo::GroupInfo* group = 0L; + + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + + KFileMimeTypeInfo::ItemInfo* item; + + item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size); + setHint( item, KFileMimeTypeInfo::Size ); + setUnit(item, KFileMimeTypeInfo::Pixels); + + item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::BitsPerPixel); + + item = addItemInfo(group, "ColorMode", i18n("Color Mode"), QVariant::String); + item = addItemInfo(group, "Compression", i18n("Compression"), QVariant::String); + +} + +bool KTgaPlugin::readInfo( KFileMetaInfo& info, uint what) +{ + + + QFile file(info.path()); + + if (!file.open(IO_ReadOnly)) + { + kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl; + return false; + } + + QDataStream dstream(&file); + + // TGA files are little-endian + dstream.setByteOrder(QDataStream::LittleEndian); + + // the vars for the image data + uint8_t tga_idlength; + uint8_t tga_colormaptype; + uint8_t tga_imagetype; + uint16_t tga_colormap_fei; + uint16_t tga_colormap_length; + uint8_t tga_colormap_entrysize; + uint16_t tga_imagespec_origin_x; + uint16_t tga_imagespec_origin_y; + uint16_t tga_imagespec_width; + uint16_t tga_imagespec_height; + uint8_t tga_imagespec_depth; + uint8_t tga_imagespec_descriptor; + + // read the image data + dstream >> tga_idlength; + dstream >> tga_colormaptype; + dstream >> tga_imagetype; + dstream >> tga_colormap_fei; + dstream >> tga_colormap_length; + dstream >> tga_colormap_entrysize; + dstream >> tga_imagespec_origin_x; + dstream >> tga_imagespec_origin_y; + dstream >> tga_imagespec_width; + dstream >> tga_imagespec_height; + dstream >> tga_imagespec_depth; + dstream >> tga_imagespec_descriptor; + + // output the useful bits + KFileMetaInfoGroup group = appendGroup(info, "Technical"); + appendItem(group, "Dimensions", QSize(tga_imagespec_width, tga_imagespec_height)); + appendItem(group, "BitDepth", tga_imagespec_depth); + + switch (tga_imagetype) { + case 1 : + case 9 : + case 32 : + appendItem(group, "ColorMode", i18n("Color-Mapped")); + break; + case 2 : + case 10 : + case 33 : + appendItem(group, "ColorMode", i18n("RGB")); + break; + case 3 : + case 11 : + appendItem(group, "ColorMode", i18n("Black and White")); + break; + default : + appendItem(group, "ColorMode", i18n("Unknown")); + } + + switch (tga_imagetype) { + case 1 : + case 2 : + case 3 : + appendItem(group, "Compression", i18n("Uncompressed")); + break; + case 9 : + case 10 : + case 11 : + appendItem(group, "Compression", i18n("Runlength Encoded")); + break; + case 32 : + appendItem(group, "Compression", i18n("Huffman, Delta & RLE")); + break; + case 33 : + appendItem(group, "Compression", i18n("Huffman, Delta, RLE (4-pass quadtree)")); + break; + default : + appendItem(group, "Compression", i18n("Unknown")); + }; + + return true; +} + +#include "kfile_tga.moc" diff --git a/kfile-plugins/tga/kfile_tga.desktop b/kfile-plugins/tga/kfile_tga.desktop new file mode 100644 index 00000000..a4578368 --- /dev/null +++ b/kfile-plugins/tga/kfile_tga.desktop @@ -0,0 +1,64 @@ +[Desktop Entry] +Type=Service +Name=Truevision Targa Info +Name[ar]=معلومات Truevision Targa +Name[br]=Gorretaol Truevision Targa +Name[ca]=Informació de Targa Truevision +Name[cs]=Truevision Targa info +Name[cy]=Gwybodaeth Truevision Targa +Name[da]=Truevision Targa-info +Name[de]=Truevision Targa-Info +Name[el]=Πληροφορίες Truevision Targa +Name[eo]=TARGA-informo +Name[es]=Info de Targa visión verdadera +Name[et]=Truevision Targa info +Name[fa]=اطلاعات Truevision Targa +Name[fi]=Truevision Targa -tiedot +Name[fr]=Informations Truevision +Name[gl]=Inf. Truevision Targa +Name[he]=מידע Truevision Targa +Name[hi]=ट्रू-विज़न टाग्रा जानकारी +Name[hr]=Truevision Targa Infomacije +Name[hu]=Truevision/Targa-jellemzők +Name[is]=Truevision Targa upplýsingar +Name[it]=Informazioni Truevision Targa +Name[ja]=TGA (Truevision Targa) 情報 +Name[kk]=Truevision Targa мәліметі +Name[km]=ព័ត៌មាន Truevision Targa +Name[lt]=Truevision Targa informacija +Name[ms]=Maklumat Targa Truevision +Name[nb]=Truevision Targa-info +Name[nds]="Truevision Targa"-Info +Name[ne]=ट्रुभिजन टार्गा सूचना +Name[nl]=Truevision Targa-info +Name[nn]=Truevision Targa-info +Name[nso]=Tshedimoso ya Targa ya pono ya Nnete +Name[pl]=Informacja o pliku Truevision Targa +Name[pt]=Informação do Targa da Truevision +Name[pt_BR]=Informação sobre Truevision Targa +Name[ro]=Informaţii Targa Truevision +Name[ru]=Информация о Truevision Targa +Name[se]=Truevision Targa-dieđut +Name[sl]=Podatki o Truevision Targa +Name[sr]=Truevision Targa информације +Name[sr@Latn]=Truevision Targa informacije +Name[sv]=Information om Truevision Targa +Name[ta]=சரியான பார்வை தார்கா தகவல் +Name[tg]=Иттилоот оиди Truevision Targa +Name[th]=ข้อมูลแฟ้ม Truevision Targa +Name[tr]=Truevision Targa Bilgisi +Name[uk]=Інформація по Truevision Targa +Name[uz]=TGA haqida maʼlumot +Name[uz@cyrillic]=TGA ҳақида маълумот +Name[ven]=Mafhungo a Targa ya mbonalelo ya vhukuma +Name[wa]=Informåcion sol imådje Truevision Targa +Name[xh]=Ulwazi lwe Truevision Targa +Name[zh_CN]=Truevision Targa 信息 +Name[zh_HK]=Truevision Targa 資訊 +Name[zh_TW]=Truevision Targa 資訊 +Name[zu]=Ulwazi lwe-Truevision Targa +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_tga +MimeType=image/x-targa +PreferredGroups=Technical +PreferredItems=Dimensions,BitDepth,ColorMode,Compression diff --git a/kfile-plugins/tga/kfile_tga.h b/kfile-plugins/tga/kfile_tga.h new file mode 100644 index 00000000..cd224fdf --- /dev/null +++ b/kfile-plugins/tga/kfile_tga.h @@ -0,0 +1,37 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Shane Wright + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef __KFILE_TGA_H__ +#define __KFILE_TGA_H__ + +#include + +class QStringList; + +class KTgaPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KTgaPlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo( KFileMetaInfo& info, uint what); +}; + +#endif diff --git a/kfile-plugins/tiff/Makefile.am b/kfile-plugins/tiff/Makefile.am new file mode 100644 index 00000000..e1e74cde --- /dev/null +++ b/kfile-plugins/tiff/Makefile.am @@ -0,0 +1,21 @@ +## Makefile.am for Tiff file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +noinst_HEADERS = kfile_tiff.h + +kde_module_LTLIBRARIES = kfile_tiff.la + +kfile_tiff_la_SOURCES = kfile_tiff.cpp +kfile_tiff_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_tiff_la_LIBADD = $(LIB_KIO) $(LIBTIFF) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_tiff.pot + +services_DATA = kfile_tiff.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/tiff/configure.in.in b/kfile-plugins/tiff/configure.in.in new file mode 100644 index 00000000..e1a9730a --- /dev/null +++ b/kfile-plugins/tiff/configure.in.in @@ -0,0 +1,3 @@ +# Compile the tiff meta info plugin only if libtiff was detected +AC_FIND_TIFF +AM_CONDITIONAL(include_TIFF, test -n "$LIBTIFF") diff --git a/kfile-plugins/tiff/kfile_tiff.cpp b/kfile-plugins/tiff/kfile_tiff.cpp new file mode 100644 index 00000000..1e844d0d --- /dev/null +++ b/kfile-plugins/tiff/kfile_tiff.cpp @@ -0,0 +1,299 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Nadeem Hasan + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "kfile_tiff.h" + +#include +#include + +#include +#include +#include +#include + +#include +#include + +typedef KGenericFactory TiffFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_tiff, TiffFactory("kfile_tiff")) + +KTiffPlugin::KTiffPlugin(QObject *parent, const char *name, + const QStringList &args) : KFilePlugin(parent, name, args) +{ + kdDebug(7034) << "TIFF file meta info plugin" << endl; + KFileMimeTypeInfo* info = addMimeTypeInfo( "image/tiff" ); + + KFileMimeTypeInfo::GroupInfo* group = + addGroupInfo(info, "General", i18n("General")); + + KFileMimeTypeInfo::ItemInfo* item; + item = addItemInfo(group, "Description", i18n("Description"), + QVariant::String); + setHint(item, KFileMimeTypeInfo::Description); + item = addItemInfo(group, "Copyright", i18n("Copyright"), + QVariant::String); + item = addItemInfo(group, "ColorMode", i18n("Color Mode"), + QVariant::String); + item = addItemInfo(group, "Dimensions", i18n("Dimensions"), + QVariant::Size); + setHint(item, KFileMimeTypeInfo::Size); + setUnit(item, KFileMimeTypeInfo::Pixels); + item = addItemInfo(group, "Resolution", i18n("Resolution"), + QVariant::Size); + setUnit(item, KFileMimeTypeInfo::DotsPerInch); + item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), + QVariant::Int); + setUnit(item, KFileMimeTypeInfo::BitsPerPixel); + item = addItemInfo(group, "Compression", i18n("Compression"), + QVariant::String); + item = addItemInfo(group, "Software", i18n("Software"), + QVariant::String); + item = addItemInfo(group, "DateTime", i18n("Date/Time"), + QVariant::DateTime); + item = addItemInfo(group, "Artist", i18n("Artist"), + QVariant::String); + setHint(item, KFileMimeTypeInfo::Author); + item = addItemInfo(group, "FaxPages", i18n("Fax Pages"), + QVariant::Int); + + group = addGroupInfo(info, "Scanner", i18n("Scanner")); + + item = addItemInfo(group, "Make", i18n("Make"), QVariant::String); + item = addItemInfo(group, "Model", i18n("Model"), QVariant::String); + + m_colorMode.setAutoDelete(true); + m_imageCompression.setAutoDelete(true); + + m_colorMode.insert(PHOTOMETRIC_MINISWHITE, + new QString(I18N_NOOP("Monochrome"))); + m_colorMode.insert(PHOTOMETRIC_MINISBLACK, + new QString(I18N_NOOP("Monochrome"))); + m_colorMode.insert(PHOTOMETRIC_RGB, + new QString(I18N_NOOP("RGB"))); + m_colorMode.insert(PHOTOMETRIC_PALETTE, + new QString(I18N_NOOP("Palette color"))); + m_colorMode.insert(PHOTOMETRIC_MASK, + new QString(I18N_NOOP("Transparency mask"))); + m_colorMode.insert(PHOTOMETRIC_SEPARATED, + new QString(I18N_NOOP("Color separations"))); + m_colorMode.insert(PHOTOMETRIC_YCBCR, + new QString(I18N_NOOP("YCbCr"))); + m_colorMode.insert(PHOTOMETRIC_CIELAB, + new QString(I18N_NOOP("CIE Lab"))); +#ifdef PHOTOMETRIC_ITULAB + m_colorMode.insert(PHOTOMETRIC_ITULAB, + new QString(I18N_NOOP("ITU Lab"))); +#endif + m_colorMode.insert(PHOTOMETRIC_LOGL, + new QString(I18N_NOOP("LOGL"))); + m_colorMode.insert(PHOTOMETRIC_LOGLUV, + new QString(I18N_NOOP("LOGLUV"))); + + m_imageCompression.insert(COMPRESSION_NONE, + new QString(I18N_NOOP("None"))); + m_imageCompression.insert(COMPRESSION_CCITTRLE, + new QString(I18N_NOOP("RLE"))); + m_imageCompression.insert(COMPRESSION_CCITTFAX3, + new QString(I18N_NOOP("G3 Fax"))); + m_imageCompression.insert(COMPRESSION_CCITTFAX4, + new QString(I18N_NOOP("G4 Fax"))); + m_imageCompression.insert(COMPRESSION_LZW, + new QString(I18N_NOOP("LZW"))); + m_imageCompression.insert(COMPRESSION_OJPEG, + new QString(I18N_NOOP("JPEG"))); + m_imageCompression.insert(COMPRESSION_JPEG, + new QString(I18N_NOOP("JPEG DCT"))); +#ifdef COMPRESSION_ADOBE_DEFLATE + m_imageCompression.insert(COMPRESSION_ADOBE_DEFLATE, + new QString(I18N_NOOP("Adobe Deflate"))); +#endif + m_imageCompression.insert(COMPRESSION_NEXT, + new QString(I18N_NOOP("NeXT 2-bit RLE"))); + m_imageCompression.insert(COMPRESSION_CCITTRLEW, + new QString(I18N_NOOP("RLE Word"))); + m_imageCompression.insert(COMPRESSION_PACKBITS, + new QString(I18N_NOOP("Packbits"))); + m_imageCompression.insert(COMPRESSION_THUNDERSCAN, + new QString(I18N_NOOP("Thunderscan RLE"))); + m_imageCompression.insert(COMPRESSION_IT8CTPAD, + new QString(I18N_NOOP("IT8 CT w/padding"))); + m_imageCompression.insert(COMPRESSION_IT8LW, + new QString(I18N_NOOP("IT8 linework RLE"))); + m_imageCompression.insert(COMPRESSION_IT8MP, + new QString(I18N_NOOP("IT8 monochrome"))); + m_imageCompression.insert(COMPRESSION_IT8BL, + new QString(I18N_NOOP("IT8 binary lineart"))); + m_imageCompression.insert(COMPRESSION_PIXARFILM, + new QString(I18N_NOOP("Pixar 10-bit LZW"))); + m_imageCompression.insert(COMPRESSION_PIXARLOG, + new QString(I18N_NOOP("Pixar 11-bit ZIP"))); + m_imageCompression.insert(COMPRESSION_DEFLATE, + new QString(I18N_NOOP("Pixar deflate"))); + m_imageCompression.insert(COMPRESSION_DCS, + new QString(I18N_NOOP("Kodak DCS"))); + m_imageCompression.insert(COMPRESSION_JBIG, + new QString(I18N_NOOP("ISO JBIG"))); + m_imageCompression.insert(COMPRESSION_SGILOG, + new QString(I18N_NOOP("SGI log luminance RLE"))); + m_imageCompression.insert(COMPRESSION_SGILOG24, + new QString(I18N_NOOP("SGI log 24-bit packed"))); +} + +QDateTime KTiffPlugin::tiffDate(const QString& s) const +{ + QDateTime dt; + QRegExp rxDate("^([0-9]{4}):([0-9]{2}):([0-9]{2})\\s" + "([0-9]{2}):([0-9]{2}):([0-9]{2})$"); + + if (rxDate.search(s) != -1) + { + int year = rxDate.cap(1).toInt(); + int month = rxDate.cap(2).toInt(); + int day = rxDate.cap(3).toInt(); + int hour = rxDate.cap(4).toInt(); + int min = rxDate.cap(5).toInt(); + int sec = rxDate.cap(6).toInt(); + + QDate d = QDate(year, month, day); + QTime t = QTime(hour, min, sec); + + if (d.isValid() && t.isValid()) + { + dt.setDate(d); + dt.setTime(t); + } + } + + return dt; +} + +bool KTiffPlugin::readInfo(KFileMetaInfo& info, uint) +{ + TIFF *tiff = TIFFOpen(QFile::encodeName(info.path()), "r"); + if (!tiff) + return false; + + uint32 imageLength=0, imageWidth=0; + uint16 bitsPerSample=0, imageCompression=0, colorMode=0, samplesPerPixel=0, + imageAlpha=0, imageResUnit=0, dummy=0, faxPages=0; + float imageXResolution=0, imageYResolution=0; + char *description=0, *copyright=0, *software=0, *datetime=0, *artist=0, + *scannerMake=0, *scannerModel=0; + + TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &imageLength); + TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &imageWidth); + TIFFGetFieldDefaulted(tiff, TIFFTAG_BITSPERSAMPLE, &bitsPerSample); + TIFFGetFieldDefaulted(tiff, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel); + TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &colorMode); + TIFFGetFieldDefaulted(tiff, TIFFTAG_COMPRESSION, &imageCompression); + TIFFGetField(tiff, TIFFTAG_MATTEING, &imageAlpha); + TIFFGetField(tiff, TIFFTAG_XRESOLUTION, &imageXResolution); + TIFFGetField(tiff, TIFFTAG_YRESOLUTION, &imageYResolution); + TIFFGetFieldDefaulted(tiff, TIFFTAG_RESOLUTIONUNIT, &imageResUnit); + TIFFGetField(tiff, TIFFTAG_IMAGEDESCRIPTION, &description); + TIFFGetField(tiff, TIFFTAG_SOFTWARE, &software); + TIFFGetField(tiff, TIFFTAG_COPYRIGHT, ©right); + TIFFGetField(tiff, TIFFTAG_DATETIME, &datetime); + TIFFGetField(tiff, TIFFTAG_ARTIST, &artist); + TIFFGetField(tiff, TIFFTAG_PAGENUMBER, &dummy, &faxPages); + TIFFGetField(tiff, TIFFTAG_MAKE, &scannerMake); + TIFFGetField(tiff, TIFFTAG_MODEL, &scannerModel); + + kdDebug(7034) << "Description: " << description << endl; + kdDebug(7034) << "Width: " << imageWidth << endl; + kdDebug(7034) << "Height: " << imageLength << endl; + kdDebug(7034) << "BitDepth: " << bitsPerSample << endl; + kdDebug(7034) << "ColorMode: " << colorMode << endl; + kdDebug(7034) << "Compression: " << imageCompression << endl; + kdDebug(7034) << "SamplesPerPixel: " << samplesPerPixel << endl; + kdDebug(7034) << "ImageAlpha: " << imageAlpha << endl; + kdDebug(7034) << "XResolution: " << imageXResolution << endl; + kdDebug(7034) << "YResolution: " << imageYResolution << endl; + kdDebug(7034) << "ResolutionUnit: " << imageResUnit << endl; + kdDebug(7034) << "FaxPages: " << faxPages << endl; + kdDebug(7034) << "DateTime: " << datetime << endl; + kdDebug(7034) << "Copyright: " << copyright << endl; + kdDebug(7034) << "Software: " << software << endl; + kdDebug(7034) << "Artist: " << artist << endl; + kdDebug(7034) << "Make: " << scannerMake << endl; + kdDebug(7034) << "Model: " << scannerModel << endl; + + if (imageResUnit == RESUNIT_CENTIMETER) + { + imageXResolution *= 2.54; + imageYResolution *= 2.54; + } + else if (imageResUnit == RESUNIT_NONE) + { + imageXResolution = 0; + imageYResolution = 0; + } + + int imageBpp = bitsPerSample*samplesPerPixel; + if (imageAlpha && colorMode==PHOTOMETRIC_RGB) + m_colorMode.replace(PHOTOMETRIC_RGB, new QString(I18N_NOOP("RGBA"))); + + KFileMetaInfoGroup group = appendGroup(info, "General"); + if (description) + appendItem(group, "Description", QString(description)); + appendItem(group, "Dimensions", QSize(imageWidth, imageLength)); + appendItem(group, "BitDepth", imageBpp); + if (imageXResolution>0 && imageYResolution>0) + appendItem(group, "Resolution", QSize( + static_cast(imageXResolution), + static_cast(imageYResolution))); + if (m_colorMode[colorMode]) + appendItem(group, "ColorMode", *m_colorMode[colorMode]); + if (m_imageCompression[imageCompression]) + appendItem(group, "Compression", *m_imageCompression[imageCompression]); + if (datetime) + { + QDateTime dt = tiffDate(QString(datetime)); + if (dt.isValid()) + appendItem(group, "DateTime", dt); + } + if (copyright) + appendItem(group, "Copyright", QString(copyright)); + if (software) + appendItem(group, "Software", QString(software)); + if (artist) + appendItem(group, "Artist", QString(artist)); + + if (faxPages>0 && (imageCompression==COMPRESSION_CCITTFAX3 || + imageCompression==COMPRESSION_CCITTFAX4)) + { + appendItem(group, "FaxPages", faxPages); + } + + if (scannerMake || scannerModel) + { + group = appendGroup(info, "Scanner"); + if (scannerMake) + appendItem(group, "Make", QString(scannerMake)); + if (scannerModel) + appendItem(group, "Model", QString(scannerModel)); + } + + TIFFClose(tiff); + + return true; +} + +#include "kfile_tiff.moc" diff --git a/kfile-plugins/tiff/kfile_tiff.desktop b/kfile-plugins/tiff/kfile_tiff.desktop new file mode 100644 index 00000000..c7c7441e --- /dev/null +++ b/kfile-plugins/tiff/kfile_tiff.desktop @@ -0,0 +1,67 @@ +[Desktop Entry] +Type=Service +Name=TIFF File Meta Info +Name[af]=Tiff Lêer Meta Inligting +Name[ar]=معلومات ملف TIFF +Name[br]=Meta-titouroù ar restr TIFF +Name[ca]=Metainformació de fitxer TIFF +Name[cs]=Metainformace obrázku typu TIFF +Name[cy]=Meta-wybodaeth Ffeil TIFF +Name[da]=TIFF Fil-meta-info +Name[de]=TIFF-Metainformation +Name[el]=Μετα-πληροφορίες αρχείου TIFF +Name[eo]=TIFF-informo +Name[es]=Info meta de archivos TIFF +Name[et]=TIFF faili metainfo +Name[eu]=TIFF fitxategi meta info +Name[fa]=فرااطلاعات پروندۀ TIFF +Name[fi]=TIFF-metatiedot +Name[fr]=Méta Informations sur les fichiers TIFF +Name[gl]=Inf. metaficheiro TIFF +Name[he]=מידע TIFF +Name[hi]=TIFF फ़ाइल मेटा जानकारी +Name[hr]=TIFF meta informacije +Name[hu]=TIFF-metajellemzők +Name[is]=TIFF File Meta upplýsingar +Name[it]=Informazioni TIFF +Name[ja]=TIFF ファイルメタ情報 +Name[kk]=TIFF файлдың мета деректері +Name[km]=ព័ត៌មាន​មេតា​របស់​ឯកសារ TIFF +Name[lt]=TIFF bylos meta informacija +Name[ms]=TIFF Maklumat Meta Fail TIFF +Name[nb]=TIFF-filmetainfo +Name[nds]=TIFF-Metainfo +Name[ne]=TIFF फाइल मेटा सूचना +Name[nl]=TIFF File Meta-info +Name[nn]=TIFF-filmetainfo +Name[nso]=Tshedimoso ya Meta wa Faele ya TIFF +Name[pl]=Informacja o pliku TIFF +Name[pt]=Meta-Informação do Ficheiro TIFF +Name[pt_BR]=Informação sobre Meta Arquivo TIFF +Name[ro]=Metainformaţii TIFF +Name[ru]=Информация о метафайле TIFF +Name[se]=TIFF-filla metadieđut +Name[sk]=Meta-info o súbore TIFF +Name[sl]=Meta podatki o TIFF +Name[sr]=Мета информације TIFF фајла +Name[sr@Latn]=Meta informacije TIFF fajla +Name[sv]=Metainformation om TIFF-fil +Name[ta]=TIFF மீக்கோப்பு தகவல் +Name[tg]=Иттилоот оиди метафайли TIFF +Name[th]=ข้อมูลเมตาแฟ้ม TIFF +Name[tr]=TIFF Dosya Bilgisi +Name[uk]=Метаінформація про файл TIFF +Name[uz]=TIFF-faylining meta-maʼlumoti +Name[uz@cyrillic]=TIFF-файлининг мета-маълумоти +Name[ven]=Mafhungo a Meta faela ya TIFF +Name[wa]=Informåcion sol imådje TIFF +Name[xh]=Ulwazi lwe TIFF Ifayile Esembindini +Name[zh_CN]=TIFF 文件元信息 +Name[zh_HK]=TIFF 檔案 Meta 資訊 +Name[zh_TW]=TIFF 檔案 Meta 資訊 +Name[zu]=Ulwazi Lwefayela yemeta ye-TIFF +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_tiff +MimeType=image/tiff +PreferredGroups=General,Scanner +PreferredItems=Description,Copyright,Type,Dimensions,Resolution,BitDepth,Compression,Software,DateTime,Artist,FaxPages,Make,Model diff --git a/kfile-plugins/tiff/kfile_tiff.h b/kfile-plugins/tiff/kfile_tiff.h new file mode 100644 index 00000000..8985288d --- /dev/null +++ b/kfile-plugins/tiff/kfile_tiff.h @@ -0,0 +1,42 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Nadeem Hasan + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef __KFILE_TIFF_H_ +#define __KFILE_TIFF_H_ + +#include + +#include + +class KTiffPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KTiffPlugin(QObject *parent, const char *name, const QStringList& args); + virtual bool readInfo(KFileMetaInfo& info, uint what); + +private: + QDateTime tiffDate(const QString&) const; + + QIntDict m_colorMode; + QIntDict m_imageCompression; +}; + +#endif diff --git a/kfile-plugins/xbm/Makefile.am b/kfile-plugins/xbm/Makefile.am new file mode 100644 index 00000000..1b9d7ff9 --- /dev/null +++ b/kfile-plugins/xbm/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for xbm file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_xbm.h + +kde_module_LTLIBRARIES = kfile_xbm.la + +kfile_xbm_la_SOURCES = kfile_xbm.cpp +kfile_xbm_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_xbm_la_LIBADD = $(LIB_KSYCOCA) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_xbm.cpp -o $(podir)/kfile_xbm.pot + +services_DATA = kfile_xbm.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/xbm/kfile_xbm.cpp b/kfile-plugins/xbm/kfile_xbm.cpp new file mode 100644 index 00000000..d62471f5 --- /dev/null +++ b/kfile-plugins/xbm/kfile_xbm.cpp @@ -0,0 +1,128 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Shane Wright + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include +#include "kfile_xbm.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if !defined(__osf__) +#include +#else +typedef unsigned short uint32_t; +#endif + +typedef KGenericFactory XbmFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_xbm, XbmFactory( "kfile_xbm" )) + +KXbmPlugin::KXbmPlugin(QObject *parent, const char *name, + const QStringList &args) + + : KFilePlugin(parent, name, args) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-xbm" ); + + KFileMimeTypeInfo::GroupInfo* group = 0L; + + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + + KFileMimeTypeInfo::ItemInfo* item; + + item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size); + setHint( item, KFileMimeTypeInfo::Size ); + setUnit(item, KFileMimeTypeInfo::Pixels); +} + + +unsigned long KXbmPlugin::xbm_processLine(char * linebuf) +{ + const char * fsig = "#define "; + + // check it starts with #define + if (memcmp(linebuf, fsig, 8)) + return 0; + + // scan for the 2nd space and set up a pointer + uint32_t slen = strlen(linebuf); + bool done = false; + uint32_t spos = 0; + unsigned char spacecount = 0; + do { + + if (linebuf[spos] == 0x00) + return 0; + + if (linebuf[spos] == ' ') + ++spacecount; + + if (spacecount == 2) + done = true; + else + ++spos; + + } while (!done); + + return atoi(linebuf + spos); +} + + +bool KXbmPlugin::readInfo( KFileMetaInfo& info, uint what) +{ + + QFile file(info.path()); + + if (!file.open(IO_ReadOnly)) + { + kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl; + return false; + } + + // we need a buffer for lines + char linebuf[1000]; + + // read the first line + file.readLine(linebuf, sizeof( linebuf )); + uint32_t width = xbm_processLine(linebuf); + + // read the 2nd line + file.readLine(linebuf, sizeof( linebuf )); + uint32_t height = xbm_processLine(linebuf); + + if ((width > 0) && (height > 0)) { + // we have valid looking data + KFileMetaInfoGroup group = appendGroup(info, "Technical"); + appendItem(group, "Dimensions", QSize(width, height)); + return true; + } + + return false; +} + +#include "kfile_xbm.moc" diff --git a/kfile-plugins/xbm/kfile_xbm.desktop b/kfile-plugins/xbm/kfile_xbm.desktop new file mode 100644 index 00000000..c33407ac --- /dev/null +++ b/kfile-plugins/xbm/kfile_xbm.desktop @@ -0,0 +1,65 @@ +[Desktop Entry] +Type=Service +Name=XBM Info +Name[af]=Xbm Inligting +Name[ar]=معلومات XBM +Name[br]=Titouroù XBM +Name[ca]=Informació d'XBM +Name[cs]=XBM info +Name[cy]=Gwybodaeth XBM +Name[da]=XBM-info +Name[de]=XBM-Info +Name[el]=Πληροφορίες XBM +Name[eo]=XBM-informo +Name[es]=Info XBM +Name[et]=XBM info +Name[fa]=اطلاعات XBM +Name[fi]=XBM-tiedot +Name[fr]=Informations sur XBM +Name[gl]=Inf. XBM +Name[he]=מידע XBM +Name[hi]=XBM जानकारी +Name[hr]=XBM Infoformacije +Name[hu]=XBM-jellemzők +Name[is]=XBM upplýsingar +Name[it]=Informazioni XBM +Name[ja]=XBM 情報 +Name[kk]=XBM мәліметі +Name[km]=ព័ត៌មាន XBM +Name[lt]=XBM informacija +Name[ms]=Maklumat XBM +Name[nds]=XBM-Info +Name[ne]=XBM सूचना +Name[nl]=XBM-info +Name[nn]=XBM-info +Name[nso]=Tshedimoso ya XBM +Name[pa]=XBM ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku XBM +Name[pt]=Informação do XBM +Name[pt_BR]=Informação sobre XBM +Name[ro]=Informaţii XBM +Name[ru]=Информация о XBM +Name[se]=XBM-dieđut +Name[sl]=Podatki o XBM +Name[sr]=XBM информације +Name[sr@Latn]=XBM informacije +Name[sv]=XBM-information +Name[ta]=XBM தகவல் +Name[tg]=Иттилоот оиди XBM +Name[th]=ข้อมูลแฟ้ม XBM +Name[tr]=XBM Bilgisi +Name[uk]=Інформація по XBM +Name[uz]=XBM haqida maʼlumot +Name[uz@cyrillic]=XBM ҳақида маълумот +Name[ven]=Mafhungo a XBM +Name[wa]=Informåcion sol imådje XBM +Name[xh]=Ulwazi lwe XBM +Name[zh_CN]=XBM 信息 +Name[zh_HK]=XBM 資訊 +Name[zh_TW]=XBM 資訊 +Name[zu]=Ulwazi lwe-XBM +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_xbm +MimeType=image/x-xbm +PreferredGroups=Technical +PreferredItems=Resolution diff --git a/kfile-plugins/xbm/kfile_xbm.h b/kfile-plugins/xbm/kfile_xbm.h new file mode 100644 index 00000000..8cc571e1 --- /dev/null +++ b/kfile-plugins/xbm/kfile_xbm.h @@ -0,0 +1,42 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Shane Wright + * + * 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 version 2. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef __KFILE_XBM_H__ +#define __KFILE_XBM_H__ + +#include + +class QStringList; + +class KXbmPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KXbmPlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo( KFileMetaInfo& info, uint what); + +private: + + unsigned long xbm_processLine(char * linebuf); + +}; + +#endif diff --git a/kfile-plugins/xpm/Makefile.am b/kfile-plugins/xpm/Makefile.am new file mode 100644 index 00000000..5a1254b1 --- /dev/null +++ b/kfile-plugins/xpm/Makefile.am @@ -0,0 +1,21 @@ +## Makefile.am for xpm file meta info plugin + +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_xpm.h + +kde_module_LTLIBRARIES = kfile_xpm.la + +kfile_xpm_la_SOURCES = kfile_xpm.cpp +kfile_xpm_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_xpm_la_LIBADD = $(LIB_KIO) +kfile_xpm_la_METASOURCES = kfile_xpm.moc + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +kde_services_DATA = kfile_xpm.desktop + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_xpm.pot diff --git a/kfile-plugins/xpm/kfile_xpm.cpp b/kfile-plugins/xpm/kfile_xpm.cpp new file mode 100644 index 00000000..3fd188b7 --- /dev/null +++ b/kfile-plugins/xpm/kfile_xpm.cpp @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (C) 2004 by Martin Koller * + * m.koller@surfeu.at * + * * + * 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 +#include +#include "kfile_xpm.h" + +#include + +//-------------------------------------------------------------------------------- + +typedef KGenericFactory xpmFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_xpm, xpmFactory( "kfile_xpm" )) + +//-------------------------------------------------------------------------------- + +xpmPlugin::xpmPlugin(QObject *parent, const char *name, const QStringList &args) + : KFilePlugin(parent, name, args) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-xpm" ); + + // our new group + KFileMimeTypeInfo::GroupInfo* group = 0; + group = addGroupInfo(info, "xpmInfo", i18n("X PixMap File Information")); + + KFileMimeTypeInfo::ItemInfo* item; + + // our new items in the group + item = addItemInfo(group, "Dimension", i18n("Dimension"), QVariant::Size); + setHint(item, KFileMimeTypeInfo::Size); + setUnit(item, KFileMimeTypeInfo::Pixels); + + item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::BitsPerPixel); +} + +//-------------------------------------------------------------------------------- + +bool xpmPlugin::readInfo(KFileMetaInfo& info, uint /*what*/) +{ + QImage pix; + + if ( ! pix.load(info.path(), "XPM") ) return false; + + KFileMetaInfoGroup group = appendGroup(info, "xpmInfo"); + + appendItem(group, "Dimension", pix.size()); + appendItem(group, "BitDepth", pix.depth()); + + return true; +} + +#include "kfile_xpm.moc" diff --git a/kfile-plugins/xpm/kfile_xpm.desktop b/kfile-plugins/xpm/kfile_xpm.desktop new file mode 100644 index 00000000..612fb82e --- /dev/null +++ b/kfile-plugins/xpm/kfile_xpm.desktop @@ -0,0 +1,53 @@ +[Desktop Entry] +Type=Service +Name=XPM Info +Name[br]=Titouroù XPM +Name[ca]=Informació de XPM +Name[cs]=XPM info +Name[de]=XPM-Info +Name[el]=Πληροφορίες XPM +Name[eo]=XPM-informo +Name[es]=Información XPM +Name[et]=XPM info +Name[fa]=اطلاعات XPM +Name[fi]=XPM-tiedot +Name[fr]=Informations XPM +Name[gl]=Información XPM +Name[he]=מידע XPM +Name[hu]=XPM-jellemzők +Name[is]=XPM upplýsingar +Name[it]=Informazioni XPM +Name[ja]=XPM 情報 +Name[kk]=XPM мәліметі +Name[km]=ព័ត៌មាន XPM +Name[lt]=XPM informacija +Name[ms]=Maklumat XPM +Name[nb]=XPM-info +Name[nds]=XPM-Info +Name[ne]=XPM सूचना +Name[nl]=XPM-info +Name[nn]=XPM-info +Name[pa]=XPM ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku XPM +Name[pt]=Informação do XPM +Name[pt_BR]=Informações Sobre XPM +Name[ro]=Informaţii XPM +Name[ru]=Информация о XPM +Name[sl]=Podatki o XPM +Name[sr]=XPM информације +Name[sr@Latn]=XPM informacije +Name[sv]=XPM-information +Name[ta]=XPM தகவல் +Name[th]=ข้อมูลแฟ้ม XPM +Name[tr]=XPM Bilgisi +Name[uk]=Інформація про XPM +Name[uz]=XPM haqida maʼlumot +Name[uz@cyrillic]=XPM ҳақида маълумот +Name[zh_CN]=XPM 信息 +Name[zh_HK]=XPM 資訊 +Name[zh_TW]=XPM 資訊 +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_xpm +MimeType=image/x-xpm +PreferredGroups=xpmInfo +PreferredItems=Dimension diff --git a/kfile-plugins/xpm/kfile_xpm.h b/kfile-plugins/xpm/kfile_xpm.h new file mode 100644 index 00000000..c68ad4eb --- /dev/null +++ b/kfile-plugins/xpm/kfile_xpm.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2004 by Martin Koller * + * m.koller@surfeu.at * + * * + * This plugin provides information about the content of a * + * XPM image file. * + * * + * 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 KFILE_XPM_H +#define KFILE_XPM_H + +/** + * Note: For further information look into <$KDEDIR/include/kfilemetainfo.h> + */ +#include + +class QStringList; + +class xpmPlugin: public KFilePlugin +{ + Q_OBJECT + + public: + xpmPlugin(QObject *parent, const char *name, const QStringList& args); + + virtual bool readInfo(KFileMetaInfo& info, uint what); +}; + +#endif + diff --git a/kgamma/AUTHORS b/kgamma/AUTHORS new file mode 100644 index 00000000..3d67f1cb --- /dev/null +++ b/kgamma/AUTHORS @@ -0,0 +1 @@ +Michael v.Ostheim diff --git a/kgamma/ChangeLog b/kgamma/ChangeLog new file mode 100644 index 00000000..6ffc823e --- /dev/null +++ b/kgamma/ChangeLog @@ -0,0 +1,54 @@ +KGamma 0.9.9: + +* Add multi-head support (fix bug #321) +* Add screen selector +* Add screen synchronisation +* Change kgammarc format (old user settings are lost) +* Fix a localisation bug in class GammaCtrl +* Add class XF86ConfigPath +* Add Dutch translation (by Rinse de Vries) +* Add Czech translation (by Daniel Prynych) + +KGamma 0.9.2: + +* Fix compile errors with configure option --enable-final (again) +* Cancel the split into two parts (admin and user mode), add a + checkbox to choose where to store the settings (user config file + or XF86Config) + +KGamma 0.9.1: + +* Fix compile errors with configure option --enable-final +* French and spanish translation update +* Install script update + +KGamma 0.9: + +* Add admin mode (in this mode, gamma settings are stored to XF86Config) +* Add spec file for RPM based distributions (Dominik Seichter) +* Remove class RGBCtrl, handle the widgets in main widget +* Add check for XFree86-VidModeExtension to configure.in.in +* Add wrapper class XVidExtWrap to access XFree86-VidModeExtension directly, + KGamma no longer needs xgamma as a backend + +KGamma 0.2.3: + +* Minor install script changes, should compile with KDE2 and KDE3 now + +KGamma 0.2.2: + +* Ported to KDE3 + +KGamma 0.2.1: + +* Code clean up +* Converted all strings to QString to avoid copying between QString and char* +* Add french localisation (Pierre Jarillon) +* Add italian localization (Daniele Medri) + +KGamma 0.2: + +* Add spanish translation (Miguel Novas) +* Change behavior of "Use Defaults" button to be compliant with kcontrol standard +* Partial rewrite to make it a KDE control center plugin +* Create new logo diff --git a/kgamma/Makefile.am b/kgamma/Makefile.am new file mode 100644 index 00000000..1c0d4b6d --- /dev/null +++ b/kgamma/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = kcmkgamma xf86gammacfg + diff --git a/kgamma/TODO b/kgamma/TODO new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/kgamma/TODO @@ -0,0 +1 @@ + diff --git a/kgamma/configure.in.in b/kgamma/configure.in.in new file mode 100644 index 00000000..d4e1a9f4 --- /dev/null +++ b/kgamma/configure.in.in @@ -0,0 +1,65 @@ +#MIN_CONFIG(3) + +AM_INIT_AUTOMAKE(kgamma,1.0.2) + +dnl CXXFLAGS="$NOOPT_CXXFLAGS" dnl __kdevelop[noopt]__ +dnl CFLAGS="$NOOPT_CFLAGS" dnl __kdevelop[noopt]__ +dnl CXXFLAGS="$CXXFLAGS $USE_EXCEPTIONS" dnl __kdevelop[exc]__ + +dnl KDE_NEED_FLEX dnl __kdevelop__ +dnl AC_PROG_YACC dnl __kdevelop__ + +dnl This test is taken from the aktion configure.in.in +dnl Modified by Michael v.Ostheim +dnl Checking for XFree86 VidMode Extensions +AC_MSG_CHECKING([for XFree86-VidModeExtension]) + +AC_CACHE_VAL(ac_cv_lib_vm, + [ac_save_LIBS="$LIBS" + kgamma_save_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS $all_includes" + LIBS="-L$x_libraries -lXxf86vm -lXext -lX11" + AC_TRY_LINK( [ + #include + #include + #include + ], + [], + eval "ac_cv_lib_vm='-lXxf86vm'", + [AC_MSG_RESULT(no) + eval "ac_cv_lib_vm=no"]) + LIBS="$ac_save_LIBS" + CFLAGS=$kgamma_save_CFLAGS +]) + +if eval "test ! \"`echo $ac_cv_lib_vm`\" = no"; then + LIBVM="$ac_cv_lib_vm" + AC_SUBST(LIBVM) + AC_MSG_RESULT($ac_cv_lib_vm) + + AC_MSG_CHECKING([for gamma functions in XFree86-VidModeExtension]) + + AC_CACHE_VAL(ac_cv_lib_vmgamma, + [ac_save_LIBS="$LIBS" + kgamma_save_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS $all_includes" + LIBS="-L$x_libraries -lXxf86vm -lXext -lX11" + AC_TRY_LINK( [], + [XF86VidModeGetGamma();], + [AC_MSG_RESULT(yes) + eval "ac_cv_lib_vm='-lXxf86vm'"], + [AC_MSG_RESULT(no) + eval "ac_cv_lib_vm=no"]) + LIBS="$ac_save_LIBS" + CFLAGS=$kgamma_save_CFLAGS + ]) +fi + +if eval "test \"`echo $ac_cv_lib_vm`\" = no"; then + DO_NOT_COMPILE="$DO_NOT_COMPILE kgamma" +fi + +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +AC_CHECK_HEADERS(sstream) +AC_LANG_RESTORE diff --git a/kgamma/kcmkgamma/Makefile.am b/kgamma/kcmkgamma/Makefile.am new file mode 100644 index 00000000..6420ee92 --- /dev/null +++ b/kgamma/kcmkgamma/Makefile.am @@ -0,0 +1,18 @@ + +INCLUDES = $(all_includes) + +kde_module_LTLIBRARIES = kcm_kgamma.la +kcm_kgamma_la_METASOURCES=AUTO +kcm_kgamma_la_SOURCES = xf86configpath.cpp xvidextwrap.cpp displaynumber.cpp \ + gammactrl.cpp kgamma.cpp +kcm_kgamma_la_LIBADD = $(LIBVM) $(LIB_KDEUI) $(LIB_KDECORE) $(LIB_QT) +kcm_kgamma_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +SUBDIRS = pics + +xdg_apps_DATA = kgamma.desktop + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kgamma.pot + +KDE_OPTIONS = nofinal diff --git a/kgamma/kcmkgamma/displaynumber.cpp b/kgamma/kcmkgamma/displaynumber.cpp new file mode 100644 index 00000000..cb04f513 --- /dev/null +++ b/kgamma/kcmkgamma/displaynumber.cpp @@ -0,0 +1,61 @@ +/*************************************************************************** + displaynumber.cpp - description + ------------------- + begin : Sun Feb 23 2003 + copyright : (C) 2003 by Michael v.Ostheim + email : ostheimm@users.berlios.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include + +#include "displaynumber.h" + +DisplayNumber::DisplayNumber(QWidget *parent, int digits, \ + int prec, const char *name) : QLabel(parent,name) { + + setPrecision(prec); + setWidth(digits); + + setFrameStyle(QFrame::Panel | QFrame::Sunken); + setBackgroundMode(Qt::PaletteBase); + setAlignment(Qt::AlignCenter); + setFocusPolicy(NoFocus); +} + +DisplayNumber::~DisplayNumber(){ +} + +void DisplayNumber::setFont( const QFont & f ) { + QLabel::setFont(f); + setWidth(dg); +} + +void DisplayNumber::setWidth(int digits) { + QFontMetrics fm(font()); + QString s("0123456789.+-"); + int width = 0, charWidth=0; + + for (int i = 0; i < 11; i++, width = fm.width(s[i])) + charWidth = (width > charWidth) ? width : charWidth; + + dg = digits; + setMinimumWidth( dg * charWidth + charWidth/2 ); +} + +void DisplayNumber::setNum(double num) { + QString text; + setText(text.setNum(num, 'f', precision)); +} + + +#include "displaynumber.moc" diff --git a/kgamma/kcmkgamma/displaynumber.h b/kgamma/kcmkgamma/displaynumber.h new file mode 100644 index 00000000..e86d6d3a --- /dev/null +++ b/kgamma/kcmkgamma/displaynumber.h @@ -0,0 +1,41 @@ +/*************************************************************************** + displaynumber.h - description + ------------------- + begin : Sun Feb 23 2003 + copyright : (C) 2003 by Michael v.Ostheim + email : ostheimm@users.berlios.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef DISPLAYNUMBER_H +#define DISPLAYNUMBER_H + +#include + +/** + *@author Michael v.Ostheim + */ + +class DisplayNumber : public QLabel { + Q_OBJECT +public: + DisplayNumber(QWidget *parent=0, int digits=0, int prec=0, const char *name=0); + ~DisplayNumber(); + void setFont( const QFont & f ); + void setNum(double num); + void setWidth(int digits); + void setPrecision(int prec) { precision = prec; }; + +private: + int dg, precision; +}; + +#endif diff --git a/kgamma/kcmkgamma/gammactrl.cpp b/kgamma/kcmkgamma/gammactrl.cpp new file mode 100644 index 00000000..2052fd34 --- /dev/null +++ b/kgamma/kcmkgamma/gammactrl.cpp @@ -0,0 +1,138 @@ +/*************************************************************************** + gammactrl.cpp - description + ------------------- + begin : Sun Oct 7 2001 + copyright : (C) 2001 by Michael v.Ostheim + email : MvOstheim@web.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include + +#include + +#include "gammactrl.h" +#include "xvidextwrap.h" +#include "displaynumber.h" +#include "gammactrl.moc" + +GammaCtrl::GammaCtrl(QWidget *parent, XVidExtWrap *xvid, int channel, \ + const QString& mingamma, const QString& maxgamma, const QString& setgamma, \ + const char *name) : QHBox(parent, name) +{ + int maxslider = (int)( ( maxgamma.toDouble() - mingamma.toDouble() \ + + 0.0005 ) * 20 ); + int setslider = (int)( ( setgamma.toDouble() - mingamma.toDouble() \ + + 0.0005 ) * 20 ); + setslider = (setslider > maxslider) ? maxslider : setslider; + setslider = (setslider < 0) ? 0 : setslider; + + suspended = false; + changed=false; + ming = mingamma.toFloat(); + mgamma = mingamma; + oldpos = setslider; + gchannel = channel; + xv = xvid; + + setSpacing(KDialog::spacingHint()); + + slider = new QSlider(Horizontal, this); + slider->setFixedHeight(24); + slider->setTickmarks(QSlider::Below); + slider->setRange(0, maxslider); + slider->setTickInterval(2); + slider->setValue(setslider); + connect(slider, SIGNAL(valueChanged(int)), SLOT(setGamma(int))); + connect(slider, SIGNAL(sliderPressed()), SLOT(pressed())); + + textfield = new DisplayNumber(this, 4, 2); + textfield->setText(setgamma); + +} + +GammaCtrl::~GammaCtrl() +{ +} + +/** set gamma, slider and textfield */ +void GammaCtrl::setGamma(const QString& gamma){ + int sliderpos; + + sliderpos = (int)( ( gamma.toDouble() - mgamma.toDouble() + 0.0005 ) * 20 ); + changed=true; + slider->setValue(sliderpos); + + setGamma(sliderpos); + if (suspended) { + suspended=false; + textfield->setDisabled(false); + } +} + +/** set slider and textfield */ +void GammaCtrl::setControl(const QString& gamma){ + int sliderpos; + + sliderpos = (int)( ( gamma.toDouble() - mgamma.toDouble() + 0.0005 ) * 20 ); + setCtrl(sliderpos); +} + +/** Return the current gamma value with precision prec */ +QString GammaCtrl::gamma(int prec){ + QString gammatext; + gammatext.setNum(xv->getGamma(gchannel) + 0.0005, 'f', prec); + + return(gammatext); +} + +/** Slot: set gamma and textfield */ +void GammaCtrl::setGamma(int sliderpos){ + if (sliderpos != oldpos || changed) { + xv->setGamma(gchannel, ming+(float)(slider->value())*0.05); + textfield->setNum(xv->getGamma(gchannel)); + oldpos = sliderpos; + changed=false; + emit gammaChanged(sliderpos); + } +} + +/** Slot: set slider and textfield */ +void GammaCtrl::setCtrl(int sliderpos){ + if (suspended) { + suspended=false; + textfield->setDisabled(false); + } + oldpos = sliderpos; + slider->setValue(sliderpos); + textfield->setNum(xv->getGamma(gchannel)); +} + +/** Slot: disable textfield */ +void GammaCtrl::suspend(){ + if (!suspended) { + suspended = true; + textfield->setDisabled(true); + } +} + +/** Slot: Change status of GammaCtrl when pressed */ +void GammaCtrl::pressed(){ + if (suspended) { + suspended=false; + textfield->setDisabled(false); + changed=true; + setGamma(slider->value()); + } +} + diff --git a/kgamma/kcmkgamma/gammactrl.h b/kgamma/kcmkgamma/gammactrl.h new file mode 100644 index 00000000..0d6ea890 --- /dev/null +++ b/kgamma/kcmkgamma/gammactrl.h @@ -0,0 +1,76 @@ +/*************************************************************************** + gammactrl.h - description + ------------------- + begin : Sun Oct 7 2001 + copyright : (C) 2001 by Michael v.Ostheim + email : MvOstheim@web.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +/**A horizontal slider and a text field for the gamma value. + *@author Michael v.Ostheim + */ + +#ifndef GAMMACTRL_H +#define GAMMACTRL_H + +#include +#include + +class QString; +class DisplayNumber; +class XVidExtWrap; + +class GammaCtrl : public QHBox { + + Q_OBJECT + public: + /** construktor */ + GammaCtrl(QWidget *parent=0, XVidExtWrap *xvid=0, int channel=0, \ + const QString& mingamma="0.40", const QString& maxgamma="3.50", \ + const QString& setgamma="1.00", const char *name=0 ); + /** destruktor */ + ~GammaCtrl(); + /** Return the current gamma value with precision prec */ + QString gamma(int); + /** Set gamma, slider and textfield */ + void setGamma(const QString&); + /** Set slider and textfield */ + void setControl(const QString&); + /** Disable the slider */ + void disableSlider() { slider->setDisabled(true);}; + + private: + QString mgamma; + QSlider *slider; + DisplayNumber *textfield; + bool suspended, changed; + int gchannel, oldpos; + double ming; + XVidExtWrap *xv; + + public slots: + /** Disable textfield */ + void suspend(); + + protected slots: + /** Set slider and textfield */ + void setCtrl(int); + /** Set gamma and textfield */ + void setGamma(int); + /** Change status of GammaCtrl when pressed */ + void pressed(); + + signals: + /** Gamma change signal */ + void gammaChanged(int); +}; + +#endif diff --git a/kgamma/kcmkgamma/kgamma.cpp b/kgamma/kcmkgamma/kgamma.cpp new file mode 100644 index 00000000..427d01c4 --- /dev/null +++ b/kgamma/kcmkgamma/kgamma.cpp @@ -0,0 +1,625 @@ +/*************************************************************************** + kgamma.cpp - description + ------------------- + begin : Sun Dec 16 13:52:24 CET 2001 + copyright : (C) 2001 by Michael v.Ostheim + email : MvOstheim@web.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "xf86configpath.h" +#include "gammactrl.h" +#include "xvidextwrap.h" +#include "kgamma.h" +#include "kgamma.moc" + +typedef KGenericFactory KGammaFactory; +K_EXPORT_COMPONENT_FACTORY ( kcm_kgamma, KGammaFactory( "kgamma" ) ) + +extern "C" +{ + bool test_kgamma() + { + bool retval; + (void) new XVidExtWrap(&retval, NULL); + return retval; + } +} + +KGamma::KGamma(QWidget *parent, const char *name, const QStringList&) + :KCModule(parent,name) +{ + bool ok; + GammaCorrection = true; + xv = new XVidExtWrap(&ok, NULL); + if (ok) { /* KDE 4: Uneccessary test, when all KCM wrappers do conditional loading */ + xv->getGamma(XVidExtWrap::Red, &ok); + if (ok) { + ScreenCount = xv->_ScreenCount(); + currentScreen = xv->getScreen(); + xv->setGammaLimits(0.4, 3.5); + + for (int i = 0; i < ScreenCount; i++ ) { + assign << 0; + rgamma << ""; + ggamma << ""; + bgamma << ""; + + // Store the current gamma values + xv->setScreen(i); + rbak << xv->getGamma(XVidExtWrap::Red); + gbak << xv->getGamma(XVidExtWrap::Green); + bbak << xv->getGamma(XVidExtWrap::Blue); + } + xv->setScreen(currentScreen); + + rootProcess = new KProcess; + setupUI(); + saved = false; + + if (!loadSettings()) { //try to load gamma values from config file + // if failed, take current gamma values + for (int i = 0; i < ScreenCount; i++ ) { + rgamma[i].setNum(rbak[i], 'f', 2); + ggamma[i].setNum(gbak[i], 'f', 2); + bgamma[i].setNum(bbak[i], 'f', 2); + } + } + load(); + } + else { //something is wrong, show only error message + GammaCorrection = false; + setupUI(); + } + } +} + +KGamma::~KGamma() { + // Restore the old gamma settings, if the user has not saved + // and there is no valid kgammarc. + // Existing user settings overwrite system settings + if (GammaCorrection) { + if ( loadUserSettings() ) load(); + else if ( !saved ) + for (int i = 0; i < ScreenCount; i++ ) { + xv->setScreen(i); + xv->setGamma( XVidExtWrap::Red, rbak[i] ); + xv->setGamma( XVidExtWrap::Green, gbak[i] ); + xv->setGamma( XVidExtWrap::Blue, bbak[i] ); + } + delete rootProcess; + } + delete xv; +} + +/** User interface */ +void KGamma::setupUI() { + QBoxLayout *topLayout = new QVBoxLayout(this, 0, KDialog::spacingHint()); + + if (GammaCorrection) { + QHBoxLayout *hbox = new QHBoxLayout( topLayout ); + QLabel *label = new QLabel( i18n( "&Select test picture:" ) , this); + QComboBox *combo = new QComboBox( this ); + label->setBuddy( combo ); + + QStringList list; + list << i18n( "Gray Scale" ) + << i18n( "RGB Scale" ) + << i18n( "CMY Scale" ) + << i18n( "Dark Gray" ) + << i18n( "Mid Gray" ) + << i18n( "Light Gray" ); + combo->insertStringList( list ); + + hbox->addWidget( label ); + hbox->addWidget( combo ); + hbox->addStretch(); + + QWidgetStack *stack = new QWidgetStack( this ); + stack->setFrameStyle( QFrame::Box | QFrame::Raised ); + + connect( combo, SIGNAL( activated( int ) ), + stack, SLOT( raiseWidget( int ) ) ); + + QPixmap background; + background.load(locate("data", "kgamma/pics/background.png")); + + QLabel *pic1 = new QLabel(stack); + pic1->setMinimumSize(530, 171); + pic1->setBackgroundPixmap(background); + pic1->setPixmap(QPixmap(locate("data", "kgamma/pics/greyscale.png"))); + pic1->setAlignment(AlignCenter); + stack->addWidget( pic1, 0 ); + + QLabel *pic2 = new QLabel(stack); + pic2->setBackgroundPixmap(background); + pic2->setPixmap(QPixmap(locate("data", "kgamma/pics/rgbscale.png"))); + pic2->setAlignment(AlignCenter); + stack->addWidget( pic2, 1 ); + + QLabel *pic3 = new QLabel(stack); + pic3->setBackgroundPixmap(background); + pic3->setPixmap(QPixmap(locate("data", "kgamma/pics/cmyscale.png"))); + pic3->setAlignment(AlignCenter); + stack->addWidget( pic3, 2 ); + + QLabel *pic4 = new QLabel(stack); + pic4->setBackgroundPixmap(background); + pic4->setPixmap(QPixmap(locate("data", "kgamma/pics/darkgrey.png"))); + pic4->setAlignment(AlignCenter); + stack->addWidget( pic4, 3 ); + + QLabel *pic5 = new QLabel(stack); + pic5->setBackgroundPixmap(background); + pic5->setPixmap(QPixmap(locate("data", "kgamma/pics/midgrey.png"))); + pic5->setAlignment(AlignCenter); + stack->addWidget( pic5, 4 ); + + QLabel *pic6 = new QLabel(stack); + pic6->setBackgroundPixmap(background); + pic6->setPixmap(QPixmap(locate("data", "kgamma/pics/lightgrey.png"))); + pic6->setAlignment(AlignCenter); + stack->addWidget( pic6, 5 ); + + topLayout->addWidget(stack, 10); + + //Sliders for gamma correction + QFrame *frame1 = new QFrame(this); + frame1->setFrameStyle( QFrame::GroupBoxPanel | QFrame::Plain ); + + QFrame *frame2 = new QFrame(this); + frame2->setFrameStyle( QFrame::GroupBoxPanel | QFrame::Plain ); + + QLabel *gammalabel = new QLabel(this); + gammalabel->setText(i18n("Gamma:")); + + QLabel *redlabel = new QLabel(this); + redlabel->setText(i18n("Red:")); + + QLabel *greenlabel = new QLabel(this); + greenlabel->setText(i18n("Green:")); + + QLabel *bluelabel = new QLabel(this); + bluelabel->setText(i18n("Blue:")); + + gctrl = new GammaCtrl(this, xv); + connect(gctrl, SIGNAL(gammaChanged(int)), SLOT(Changed())); + connect(gctrl, SIGNAL(gammaChanged(int)), SLOT(SyncScreens())); + gammalabel->setBuddy( gctrl ); + + rgctrl = new GammaCtrl(this, xv, XVidExtWrap::Red); + connect(rgctrl, SIGNAL(gammaChanged(int)), SLOT(Changed())); + connect(rgctrl, SIGNAL(gammaChanged(int)), SLOT(SyncScreens())); + connect(gctrl, SIGNAL(gammaChanged(int)), rgctrl, SLOT(setCtrl(int))); + connect(rgctrl, SIGNAL(gammaChanged(int)), gctrl, SLOT(suspend())); + redlabel->setBuddy( rgctrl ); + + ggctrl = new GammaCtrl(this, xv, XVidExtWrap::Green); + connect(ggctrl, SIGNAL(gammaChanged(int)), SLOT(Changed())); + connect(ggctrl, SIGNAL(gammaChanged(int)), SLOT(SyncScreens())); + connect(gctrl, SIGNAL(gammaChanged(int)), ggctrl, SLOT(setCtrl(int))); + connect(ggctrl, SIGNAL(gammaChanged(int)), gctrl, SLOT(suspend())); + greenlabel->setBuddy( ggctrl ); + + bgctrl = new GammaCtrl(this, xv, XVidExtWrap::Blue); + connect(bgctrl, SIGNAL(gammaChanged(int)), SLOT(Changed())); + connect(bgctrl, SIGNAL(gammaChanged(int)), SLOT(SyncScreens())); + connect(gctrl, SIGNAL(gammaChanged(int)), bgctrl, SLOT(setCtrl(int))); + connect(bgctrl, SIGNAL(gammaChanged(int)), gctrl, SLOT(suspend())); + bluelabel->setBuddy( bgctrl ); + + QGridLayout *grid = new QGridLayout(4, 9); + grid->setSpacing(8); + grid->addMultiCellWidget(frame1, 0, 2, 0, 3); + grid->addMultiCellWidget(frame2, 4, 8, 0, 3); + grid->addWidget(gammalabel, 1, 1, Qt::AlignRight); + grid->addWidget(redlabel, 5, 1, Qt::AlignRight); + grid->addWidget(greenlabel, 6, 1, Qt::AlignRight); + grid->addWidget(bluelabel, 7, 1, Qt::AlignRight); + grid->addWidget(gctrl, 1, 2); + grid->addWidget(rgctrl, 5, 2); + grid->addWidget(ggctrl, 6, 2); + grid->addWidget(bgctrl, 7, 2); + + topLayout->addLayout(grid); + + //Options + QHBox *options = new QHBox(this); + + xf86cfgbox = new QCheckBox( i18n("Save settings to XF86Config"), options ); + connect(xf86cfgbox, SIGNAL(clicked()), SLOT(changeConfig())); + + syncbox = new QCheckBox( i18n("Sync screens"), options ); + connect(syncbox, SIGNAL(clicked()), SLOT(SyncScreens())); + connect(syncbox, SIGNAL(clicked()), SLOT(Changed())); + + screenselect = new QComboBox( options ); + for ( int i = 0; i < ScreenCount; i++ ) + screenselect->insertItem( i18n("Screen %1").arg(i+1) ); + screenselect->setCurrentItem(currentScreen); + connect(screenselect, SIGNAL(activated(int)), SLOT(changeScreen(int))); + + options->setSpacing( 10 ); + options->setStretchFactor( xf86cfgbox, 10 ); + options->setStretchFactor( syncbox, 1 ); + options->setStretchFactor( screenselect, 1 ); + + topLayout->addWidget(options); + } + else { + QLabel *error = new QLabel(this); + error->setText(i18n("Gamma correction is not supported by your" + " graphics hardware or driver.")); + error->setAlignment(AlignCenter); + topLayout->addWidget(error); + } +} + +void KGamma::load() { + load( false ); +} + +/** Restore latest saved gamma values */ +void KGamma::load(bool useDefaults) { + if (GammaCorrection) { + KConfig *config = new KConfig("kgammarc"); + + config->setReadDefaults( useDefaults ); + + config->setGroup("ConfigFile"); + + // save checkbox status + if ( xf86cfgbox->isChecked() ) config->writeEntry("use", "XF86Config"); + else config->writeEntry("use", "kgammarc"); + + // load syncbox status + config->setGroup("SyncBox"); + if ( config->readEntry("sync") == "yes" ) syncbox->setChecked(true); + else syncbox->setChecked(false); + + config->sync(); + delete config; + + for (int i = 0; i < ScreenCount; i++) { + xv->setScreen(i); + if (rgamma[i] == ggamma[i] && rgamma[i] == bgamma[i]) + if (i == currentScreen) gctrl->setGamma(rgamma[i]); + else xv->setGamma(XVidExtWrap::Value, rgamma[i].toFloat()); + else { + if (i == currentScreen) { + rgctrl->setGamma(rgamma[i]); + ggctrl->setGamma(ggamma[i]); + bgctrl->setGamma(bgamma[i]); + gctrl->suspend(); + } + else { + xv->setGamma(XVidExtWrap::Red, rgamma[i].toFloat()); + xv->setGamma(XVidExtWrap::Green, ggamma[i].toFloat()); + xv->setGamma(XVidExtWrap::Blue, bgamma[i].toFloat()); + } + } + } + xv->setScreen(currentScreen); + + emit changed(useDefaults); + } +} + +void KGamma::save() { + if (GammaCorrection) { + for (int i = 0; i < ScreenCount; i++) { + xv->setScreen(i); + rgamma[i] = rgctrl->gamma(2); + ggamma[i] = ggctrl->gamma(2); + bgamma[i] = bgctrl->gamma(2); + } + xv->setScreen(currentScreen); + + KConfig *config = new KConfig("kgammarc"); + config->setGroup("SyncBox"); + if ( syncbox->isChecked() ) config->writeEntry("sync", "yes"); + else config->writeEntry("sync", "no"); + + if ( !xf86cfgbox->isChecked() ) { //write gamma settings to the users config + for (int i = 0; i < ScreenCount; i++) { + config->setGroup( QString("Screen %1").arg(i) ); + config->writeEntry("rgamma", rgamma[i]); + config->writeEntry("ggamma", ggamma[i]); + config->writeEntry("bgamma", bgamma[i]); + } + config->setGroup("ConfigFile"); + config->writeEntry("use", "kgammarc"); + } + else { // write gamma settings to section "Monitor" of XF86Config + config->setGroup("ConfigFile"); + config->writeEntry("use", "XF86Config"); + + if ( !rootProcess->isRunning() ) { + QString Arguments = "xf86gammacfg "; + for (int i = 0; i < ScreenCount; i++) + Arguments += rgamma[assign[i]] + " " + ggamma[assign[i]] + " " + \ + bgamma[assign[i]] + " "; + rootProcess->clearArguments(); + *rootProcess << "kdesu" << Arguments; + rootProcess->start(); + } + } + config->sync(); + delete config; + saved = true; + emit changed(false); + } +} + +void KGamma::defaults() { + load( true ); +} + +bool KGamma::loadSettings() { + KConfig *config = new KConfig("kgammarc"); + config->setGroup("ConfigFile"); + QString ConfigFile( config->readEntry("use") ); + config->setGroup("SyncBox"); + if ( config->readEntry("sync") == "yes" ) syncbox->setChecked(true); + delete config; + + if ( ConfigFile == "XF86Config" ) { // parse XF86Config + xf86cfgbox->setChecked(true); + return( loadSystemSettings() ); + } + else { //get gamma settings from user config + return( loadUserSettings() ); + } +} + +bool KGamma::loadUserSettings() { + KConfig *config = new KConfig("kgammarc"); + + for (int i = 0; i < ScreenCount; i++) { + config->setGroup(QString( "Screen %1" ).arg(i) ); + rgamma[i] = config->readEntry("rgamma"); + ggamma[i] = config->readEntry("ggamma"); + bgamma[i] = config->readEntry("bgamma"); + } + delete config; + + return( validateGammaValues() ); +} + +bool KGamma::loadSystemSettings() { + QStringList Monitor, Screen, ScreenLayout, ScreenMonitor, Gamma; + QValueList ScreenNr; + QString Section; + XF86ConfigPath Path; + + QFile f( Path.get() ); + if ( f.open(IO_ReadOnly) ) { + QTextStream t( &f ); + QString s; + int sn = 0; + bool gm = false; + + // Analyse Screen<->Monitor assignments of multi-head configurations + while ( !t.eof() ) { + s = (t.readLine()).simplifyWhiteSpace(); + QStringList words = QStringList::split(' ', s); + + if ( !words.empty() ) { + if ( words[0] == "Section" && words.size() > 1 ) { + if ( (Section = words[1]) == "\"Monitor\"" ) gm = false; + } + else if ( words[0] == "EndSection" ) { + if ( Section == "\"Monitor\"" && !gm ) { + Gamma << ""; + gm = false; + } + Section = ""; + } + else if ( words[0] == "Identifier" && words.size() > 1 ) { + if ( Section == "\"Monitor\"" ) Monitor << words[1]; + else if ( Section == "\"Screen\"" ) Screen << words[1]; + } + else if ( words[0] == "Screen" && words.size() > 1 ) { + if ( Section == "\"ServerLayout\"" ) { + bool ok; + int i = words[1].toInt(&ok); + if ( ok && words.size() > 2 ) { + ScreenNr << i; + ScreenLayout << words[2]; + } + else { + ScreenNr << sn++; + ScreenLayout << words[1]; + } + } + } + else if ( words[0] == "Monitor" && words.size() > 1 ) { + if ( Section == "\"Screen\"" ) + ScreenMonitor << words[1]; + } + else if ( words[0] == "Gamma" ) { + if ( Section == "\"Monitor\"" ) { + Gamma << s; + gm = true; + } + } + } + } // End while + f.close(); + + for ( int i = 0; i < ScreenCount; i++ ) { + for ( int j = 0; j < ScreenCount; j++ ) { + if ( ScreenLayout[i] == Screen[j] ) { + for ( int k = 0; k < ScreenCount; k++ ) { + if ( Monitor[k] == ScreenMonitor[j] ) + assign[ScreenNr[i]] = k; + } + } + } + } + + // Extract gamma values + for ( int i = 0; i < ScreenCount; i++) { + rgamma[i] = ggamma[i] = bgamma[i] = ""; + + QStringList words = QStringList::split(' ', Gamma[assign[i]]); + QStringList::ConstIterator it = words.begin(); + if ( words.size() < 4 ) + rgamma[i] = ggamma[i] = bgamma[i] = *(++it); // single gamma value + else { + rgamma[i] = *(++it); // eventually rgb gamma values + ggamma[i] = *(++it); + bgamma[i] = *(++it); + } + } + + } + return( validateGammaValues() ); +} + +bool KGamma::validateGammaValues() { + bool rOk, gOk, bOk, result; + + result = true; + for (int i = 0; i < ScreenCount; i++ ) { + rgamma[i].toFloat( &rOk ); + ggamma[i].toFloat( &gOk ); + bgamma[i].toFloat( &bOk ); + + if ( !(rOk && gOk && bOk) ) { + if ( rOk ) ggamma[i] = bgamma[i] = rgamma[i]; + else result = false; + } + } + return(result); +} + +void KGamma::changeConfig() { + bool Ok = false; + + if ( xf86cfgbox->isChecked() ) Ok = loadSystemSettings(); + else Ok = loadUserSettings(); + + if ( !Ok ) { + for (int i = 0; i < ScreenCount; i++ ) { + xv->setScreen(i); + rgamma[i].setNum(xv->getGamma(XVidExtWrap::Red), 'f', 2); + ggamma[i].setNum(xv->getGamma(XVidExtWrap::Green), 'f', 2); + bgamma[i].setNum(xv->getGamma(XVidExtWrap::Blue), 'f', 2); + } + xv->setScreen(currentScreen); + } + load(); +} + +void KGamma::SyncScreens() { + if ( syncbox->isChecked() ) { + float rg = xv->getGamma(XVidExtWrap::Red); + float gg = xv->getGamma(XVidExtWrap::Green); + float bg = xv->getGamma(XVidExtWrap::Blue); + + for (int i = 0; i < ScreenCount; i++ ) { + if ( i != currentScreen ) { + xv->setScreen(i); + xv->setGamma(XVidExtWrap::Red, rg); + xv->setGamma(XVidExtWrap::Green, gg); + xv->setGamma(XVidExtWrap::Blue, bg); + } + } + xv->setScreen(currentScreen); + } +} + +void KGamma::changeScreen(int sn) { + QString red, green, blue; + + xv->setScreen(sn); + currentScreen = sn; + + red.setNum(xv->getGamma(XVidExtWrap::Red), 'f', 2); + green.setNum(xv->getGamma(XVidExtWrap::Green), 'f', 2); + blue.setNum(xv->getGamma(XVidExtWrap::Blue), 'f', 2); + + gctrl->setControl(red); + rgctrl->setControl(red); + ggctrl->setControl(green); + bgctrl->setControl(blue); + if (red != green || red != blue) gctrl->suspend(); +} + +int KGamma::buttons () { + return Default|Apply|Help; +} + +QString KGamma::quickHelp() const +{ + return i18n("

Monitor Gamma

This is a tool for changing monitor gamma" + " correction. Use the four sliders to define the gamma correction either" + " as a single value, or separately for the red, green and blue components." + " You may need to correct the brightness and contrast settings of your" + " monitor for good results. The test images help you to find proper" + " settings.
You can save them system-wide to XF86Config (root access" + " is required for that) or to your own KDE settings. On multi head" + " systems you can correct the gamma values separately for all screens."); +} + + +// ------------------------------------------------------------------------ + +extern "C" +{ + // Restore the user gamma settings + void init_kgamma() + { + bool ok; + XVidExtWrap xv(&ok); + + if (ok) { + xv.setGammaLimits(0.4, 3.5); + float rgamma, ggamma, bgamma; + KConfig *config = new KConfig("kgammarc"); + + for (int i = 0; i < xv._ScreenCount(); i++) { + xv.setScreen(i); + config->setGroup( QString("Screen %1").arg(i) ); + + if ((rgamma = config->readEntry("rgamma").toFloat())) + xv.setGamma(XVidExtWrap::Red, rgamma); + if ((ggamma = config->readEntry("ggamma").toFloat())) + xv.setGamma(XVidExtWrap::Green, ggamma); + if ((bgamma = config->readEntry("bgamma").toFloat())) + xv.setGamma(XVidExtWrap::Blue, bgamma); + } + delete config; + } + } +} diff --git a/kgamma/kcmkgamma/kgamma.desktop b/kgamma/kcmkgamma/kgamma.desktop new file mode 100644 index 00000000..5d4c3b05 --- /dev/null +++ b/kgamma/kcmkgamma/kgamma.desktop @@ -0,0 +1,129 @@ +[Desktop Entry] +Comment=A monitor calibration tool +Comment[ar]=أداة مراقبة وتعيير +Comment[bg]=Калибриране на монитора +Comment[bs]=Alat za kalibraciju monitora +Comment[ca]=Una eina de calibració del monitor +Comment[cs]=Nástroj pro kalibraci monitoru +Comment[cy]=Erfyn graddnodi dangosydd +Comment[da]=Et skærmkalibreringsværktøj +Comment[de]=Ein Kalibrierungswerkzeug für Monitore +Comment[el]=Ένα εργαλείο ρύθμισης της οθόνης +Comment[eo]=Ekrankalibrilo +Comment[es]=Una herramienta de calibración del monitor +Comment[et]=Monitori kalibreerija +Comment[eu]=Monitoreak kalibratzeko tresna +Comment[fa]=ابزار درجه‌بندی نمایشگر +Comment[fi]=Näytön asetustyökalu +Comment[fr]=Outil de calibrage de moniteur +Comment[gl]=Unha utilidade para calibrar o monitor +Comment[hi]=मॉनीटर केलिब्रेशन औज़ार +Comment[hu]=Monitorbeállító program +Comment[is]=Tól til að stilla skjáinn +Comment[it]=Calibrazione del monitor +Comment[ja]=モニタ測定ツール +Comment[kk]=Мониторды калибрлеу құралы +Comment[km]=ឧបករណ៍​ក្រិត​របស់​ម៉ូនីទ័រ +Comment[lt]=Monitoriaus kalibravimo įrankis +Comment[ms]=Alat tentukur monitor +Comment[nb]=Et verktøy for å kalibrere skjermen +Comment[nds]=En Afstimmwarktüüch för Monitoren +Comment[ne]=मोनिटर क्यालिब्रेसन उपकरण +Comment[nl]=Gereedschap om de kleurweergave goed in te stellen +Comment[nn]=Eit verktøy for å kalibrera skjermen +Comment[pl]=Narzędzie do kalibracji monitora +Comment[pt]=Ferramenta de calibração do monitor +Comment[pt_BR]=Uma ferramenta de calibragem de monitor +Comment[ro]=Un utilitar de calibrat monitorul +Comment[ru]=Утилита для калибровки монитора +Comment[sk]=Kalibračný nástroj pre monitor +Comment[sl]=Kalibracijsko orodje za monitorje +Comment[sr]=Алат за калибрацију монитора +Comment[sr@Latn]=Alat za kalibraciju monitora +Comment[sv]=Kalibreringsverktyg för skärmen +Comment[ta]=திரை நிலைக்கருவி +Comment[tg]=Утилита барои калибратсия кардани монитор +Comment[th]=เครื่องมือปรับความเที่ยงตรงของจอภาพ +Comment[tr]=Monitör kalibrasyon aracı +Comment[uk]=Засіб для калібрування монітора +Comment[zh_CN]=监视器校准工具 +Comment[zh_HK]=顯示器調校工具 +Comment[zh_TW]=監視器校準工具 + +Name=Gamma +Name[ar]=غاما +Name[az]=Qamma +Name[bg]=Гама +Name[cs]=Gama +Name[cy]=Gama +Name[el]=Γάμμα +Name[eo]=Gamo +Name[fa]=گاما +Name[ga]=Gáma +Name[gl]=Gama +Name[he]=גאמה +Name[hr]=Gama +Name[hu]=Gamma-korrekció +Name[is]=Litatíðni (gamma) +Name[kk]=Гамма +Name[km]=ហ្គាម៉ា +Name[ne]=गामा +Name[pa]=ਗ਼ਾਮਾ +Name[pt]=Gama +Name[ru]=Гамма +Name[sl]=Gama +Name[sr]=Гама +Name[sr@Latn]=Gama +Name[ta]=காமா +Name[tg]=Гамма +Name[th]=แกมมา +Name[uk]=Гама +Name[uz@cyrillic]=Гамма +Name[wa]=Gama +Name[xh]=Unobumba wesithathu konoobumba besiGrike +Name[zh_HK]=伽馬(Gamma) + +DocPath=kgamma +Exec=kcmshell kgamma +Icon=kgamma +Keywords=KGamma, kgamma, Gamma, gamma +Keywords[bg]=калибриране, гама, яркост, цвят, монитор, екран, KGamma, kgamma, Gamma, gamma +Keywords[cs]=KGamma, kgamma, gama +Keywords[de]=KGamma,kgamma,Gamma,gamma +Keywords[el]=KGamma, kgamma, Γάμμα, γάμμα +Keywords[ga]=KGamma, kgamma, Gamma, gamma, Gáma +Keywords[gl]=KGamma, kgamma, Gamma, gamma, gama +Keywords[he]=KGamma, kgamma, Gamma, gamma, גאמה +Keywords[hi]=के-गामा,केगामा,गामा,गामा +Keywords[hu]=KGamma,kgamma,gamma,gamma-korrekció +Keywords[it]=KGamma,gamma +Keywords[ja]=KGamma, kgamma, ガンマ, Gamma, gamma +Keywords[km]=KGamma, kgamma,ហ្គ៉ាម៉ា +Keywords[lt]=KGamma, kgamma, Gamma, gamma, gama +Keywords[nds]=KGamma,kgamma,Gamma,gamma +Keywords[ne]=के गामा, के गामा, गामा, गामा +Keywords[nl]=KGamma,kgamma,Gamma,gamma,kleurweergave +Keywords[nn]=KGamma,gamma +Keywords[pl]=KGamma, kgamma, Gamma, gamma, jasność,ciemność,rozjaśnienie +Keywords[pt]=kgamma, gama +Keywords[pt_BR]=KGama, kgama, Gama, gama +Keywords[ro]=KGamma,kgamma,gama,gamma +Keywords[ru]=KGamma,kgamma,Gamma,gamma,гамма,монитор +Keywords[sk]=KGamma, kgamma, gamma +Keywords[sl]=KGamma,kgamma,Gama,gama +Keywords[sr]=KGamma, kgamma, Gamma, gamma, гама +Keywords[sr@Latn]=KGamma, kgamma, Gamma, gamma, gama +Keywords[ta]=கேகாமா, கேகாமா, காமா, காமா +Keywords[tg]=KGamma,kgamma,Gamma,gamma,гамма,монитор +Keywords[uk]=KGamma, kgamma, Gamma, gamma, гама, яскравість +Keywords[uz@cyrillic]=KGamma, kgamma, Гамма, гамма +Keywords[wa]=KGamma, kgamma, Gama, gama +Keywords[zh_CN]=KGamma, kgamma, Gamma, gamma,伽玛 +Type=Application +X-KDE-Init=kgamma +X-KDE-FactoryName=kgamma +X-KDE-Library=kgamma +X-KDE-ModuleType=Library +X-KDE-Test-Module=true +NoDisplay=true +Categories=Qt;KDE;Settings;X-KDE-settings-peripherals; diff --git a/kgamma/kcmkgamma/kgamma.h b/kgamma/kcmkgamma/kgamma.h new file mode 100644 index 00000000..b347e2a1 --- /dev/null +++ b/kgamma/kcmkgamma/kgamma.h @@ -0,0 +1,78 @@ +/*************************************************************************** + kgamma.h - description + ------------------- + begin : Sun Dec 16 13:52:24 CET 2001 + copyright : (C) 2001 by Michael v.Ostheim + email : MvOstheim@web.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#ifndef KGAMMA_H_ +#define KGAMMA_H_ + +#include + +class GammaCtrl; +class QCheckBox; +class QComboBox; +class XVidExtWrap; +class KProcess; + +class KGamma: public KCModule +{ + Q_OBJECT + public: + KGamma(QWidget *parent, const char *name, const QStringList&); + virtual ~KGamma(); + + void load(); + void load(bool useDefaults); + void save(); + void defaults(); + int buttons(); + QString quickHelp() const; + + protected: // Protected methods + /** The user interface */ + void setupUI(); + /** Decides if to load settings from user or system config */ + bool loadSettings(); + /** Load settings from kgammarc */ + bool loadUserSettings(); + /** Load settings from XF86Config */ + bool loadSystemSettings(); + /** Validate the loaded gamma values */ + bool validateGammaValues(); + + private slots: + /** Called if the user changesd something */ + void Changed() { emit changed(true); } + /** Called if the user marked or unmarked the XF86Config checkbox */ + void changeConfig(); + /** Called if the user marked or unmarked the sync screen checkbox */ + void SyncScreens(); + /** Called if the user chooses a new screen */ + void changeScreen(int sn); + + private: + bool saved, GammaCorrection; + int ScreenCount, currentScreen; + QStringList rgamma, ggamma, bgamma; + QValueList assign; + QValueList rbak, gbak, bbak; + GammaCtrl *gctrl, *rgctrl, *ggctrl, *bgctrl; + QCheckBox *xf86cfgbox, *syncbox; + QComboBox *screenselect; + KProcess *rootProcess; + XVidExtWrap *xv; +}; + +#endif + diff --git a/kgamma/kcmkgamma/pics/Makefile.am b/kgamma/kcmkgamma/pics/Makefile.am new file mode 100644 index 00000000..14dd5857 --- /dev/null +++ b/kgamma/kcmkgamma/pics/Makefile.am @@ -0,0 +1,7 @@ + +img_DATA = background.png cmyscale.png darkgrey.png greyscale.png lightgrey.png midgrey.png \ + rgbscale.png +imgdir = $(kde_datadir)/kgamma/pics + +KDE_ICON = kgamma + diff --git a/kgamma/kcmkgamma/pics/background.png b/kgamma/kcmkgamma/pics/background.png new file mode 100644 index 00000000..01797213 Binary files /dev/null and b/kgamma/kcmkgamma/pics/background.png differ diff --git a/kgamma/kcmkgamma/pics/cmyscale.png b/kgamma/kcmkgamma/pics/cmyscale.png new file mode 100644 index 00000000..e30700bc Binary files /dev/null and b/kgamma/kcmkgamma/pics/cmyscale.png differ diff --git a/kgamma/kcmkgamma/pics/darkgrey.png b/kgamma/kcmkgamma/pics/darkgrey.png new file mode 100644 index 00000000..221d65e4 Binary files /dev/null and b/kgamma/kcmkgamma/pics/darkgrey.png differ diff --git a/kgamma/kcmkgamma/pics/greyscale.png b/kgamma/kcmkgamma/pics/greyscale.png new file mode 100644 index 00000000..8532c3ea Binary files /dev/null and b/kgamma/kcmkgamma/pics/greyscale.png differ diff --git a/kgamma/kcmkgamma/pics/hi16-app-kgamma.png b/kgamma/kcmkgamma/pics/hi16-app-kgamma.png new file mode 100644 index 00000000..de14649c Binary files /dev/null and b/kgamma/kcmkgamma/pics/hi16-app-kgamma.png differ diff --git a/kgamma/kcmkgamma/pics/hi32-app-kgamma.png b/kgamma/kcmkgamma/pics/hi32-app-kgamma.png new file mode 100644 index 00000000..c5f605df Binary files /dev/null and b/kgamma/kcmkgamma/pics/hi32-app-kgamma.png differ diff --git a/kgamma/kcmkgamma/pics/hi48-app-kgamma.png b/kgamma/kcmkgamma/pics/hi48-app-kgamma.png new file mode 100644 index 00000000..19fd51e7 Binary files /dev/null and b/kgamma/kcmkgamma/pics/hi48-app-kgamma.png differ diff --git a/kgamma/kcmkgamma/pics/lightgrey.png b/kgamma/kcmkgamma/pics/lightgrey.png new file mode 100644 index 00000000..650603c8 Binary files /dev/null and b/kgamma/kcmkgamma/pics/lightgrey.png differ diff --git a/kgamma/kcmkgamma/pics/midgrey.png b/kgamma/kcmkgamma/pics/midgrey.png new file mode 100644 index 00000000..5b22f4c5 Binary files /dev/null and b/kgamma/kcmkgamma/pics/midgrey.png differ diff --git a/kgamma/kcmkgamma/pics/rgbscale.png b/kgamma/kcmkgamma/pics/rgbscale.png new file mode 100644 index 00000000..5e9be6d9 Binary files /dev/null and b/kgamma/kcmkgamma/pics/rgbscale.png differ diff --git a/kgamma/kcmkgamma/xf86configpath.cpp b/kgamma/kcmkgamma/xf86configpath.cpp new file mode 100644 index 00000000..e6f7163b --- /dev/null +++ b/kgamma/kcmkgamma/xf86configpath.cpp @@ -0,0 +1,56 @@ +/*************************************************************************** + xf86configpath.cpp - description + ------------------- + begin : Mon Dec 30 2002 + copyright : (C) 2002 by Michael v.Ostheim + email : ostheimm@users.berlios.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include + +#include + +#include "xf86configpath.h" + +using namespace std; + +XF86ConfigPath::XF86ConfigPath(){ + vector searchPaths; + searchPaths.push_back("/etc/X11/XF86Config-4"); + searchPaths.push_back("/etc/X11/XF86Config"); + searchPaths.push_back("/etc/XF86Config"); + searchPaths.push_back("/usr/X11R6/etc/X11/XF86Config-4"); + searchPaths.push_back("/usr/X11R6/etc/X11/XF86Config"); + searchPaths.push_back("/usr/X11R6/lib/X11/XF86Config-4"); + searchPaths.push_back("/usr/X11R6/lib/X11/XF86Config"); + + searchPaths.push_back("/etc/X11/xorg.conf-4"); + searchPaths.push_back("/etc/X11/xorg.conf"); + searchPaths.push_back("/etc/xorg.conf"); + searchPaths.push_back("/usr/X11R6/etc/X11/xorg.conf-4"); + searchPaths.push_back("/usr/X11R6/etc/X11/xorg.conf"); + searchPaths.push_back("/usr/X11R6/lib/X11/xorg.conf-4"); + searchPaths.push_back("/usr/X11R6/lib/X11/xorg.conf"); + + vector::iterator it = searchPaths.begin(); + for (; it != searchPaths.end(); ++it ) + if ( !access( (Path = *it).c_str(), F_OK ) ) break; +} + +XF86ConfigPath::~XF86ConfigPath(){ +} + +/** Returns path */ +const char* XF86ConfigPath::get(){ + return( Path.c_str() ); +} diff --git a/kgamma/kcmkgamma/xf86configpath.h b/kgamma/kcmkgamma/xf86configpath.h new file mode 100644 index 00000000..88f7afa4 --- /dev/null +++ b/kgamma/kcmkgamma/xf86configpath.h @@ -0,0 +1,42 @@ +/*************************************************************************** + xf86configpath.h - description + ------------------- + begin : Mon Dec 30 2002 + copyright : (C) 2002 by Michael v.Ostheim + email : ostheimm@users.berlios.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef XF86CONFIGPATH_H +#define XF86CONFIGPATH_H + +#include + +/**Search for XF86Config or XF86Config-4 which can be located at different + places. + *@author Michael v.Ostheim + */ + +class XF86ConfigPath { + +public: + XF86ConfigPath(); + ~XF86ConfigPath(); + + /** Returns Path variable */ + const char* get(); + +private: // Private attributes + /** Contains the path of XF86Config file */ + std::string Path; +}; + +#endif diff --git a/kgamma/kcmkgamma/xvidextwrap.cpp b/kgamma/kcmkgamma/xvidextwrap.cpp new file mode 100644 index 00000000..9d8136d9 --- /dev/null +++ b/kgamma/kcmkgamma/xvidextwrap.cpp @@ -0,0 +1,170 @@ +/*************************************************************************** + xvidextwrap.cpp - description + ------------------- + begin : Sat Jan 5 2002 + copyright : (C) 2002 by Michael v.Ostheim + email : MvOstheim@web.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#ifdef HAVE_SSTREAM +#include +#else +#include +#define istringstream istrstream +#endif + +#include + +#include "xf86configpath.h" +#include "xvidextwrap.h" + +using namespace std; + + +XVidExtWrap::XVidExtWrap(bool* OK, const char* displayname) { + if ((dpy = XOpenDisplay(displayname))) { + screen = DefaultScreen(dpy); + setGammaLimits(0.1, 10.0); + *OK = true; + } + else { + kdDebug() << "KGamma: unable to open display " << displayname << endl; + *OK = false; + } +} + +XVidExtWrap::~XVidExtWrap() { + if (dpy) XCloseDisplay(dpy); +} + +int XVidExtWrap::_DefaultScreen() { + return DefaultScreen(dpy); +} + +/** We have to parse XF86Config to get the number of screens, because */ +/** ScreenCount() from X11/Xlib.h does not count correctly with xinerama */ +int XVidExtWrap::_ScreenCount() { + int count = 0; + bool section = false; + XF86ConfigPath Path; + + std::ifstream in( Path.get() ); + + if ( in.is_open() ) { + std::string s, buf; + std::vector words; + + while (getline(in, s,'\n')) { + words.clear(); + istringstream ss(s.c_str()); + while (ss >> buf) words.push_back(buf); // Split "s" into words + + if ( !words.empty() ) { + if ( words[0] == "Section" && words.size() > 1 ) { + if ( words[1] == "\"ServerLayout\"" ) section = true; + } + else if ( words[0] == "EndSection" ) + section = false; + if ( section && words[0] == "Screen" ) ++count; + } + } //end while + in.close(); + + } + + if ( !count ) count = 1; //If failed,fill count with a valid value; + + return( count ); +} + +const char* XVidExtWrap::DisplayName() { + return DisplayString(dpy); +} + +void XVidExtWrap::setGamma(int channel, float gam, bool* OK) { + XF86VidModeGamma gamma; + + if ( gam >= mingamma && gam <= maxgamma ) { + if (!XF86VidModeGetGamma(dpy, screen, &gamma)) { + kdDebug() << "KGamma: Unable to query gamma correction" << endl; + if ( OK ) *OK = false; + } + else { + switch (channel) { + case Value: + gamma.red = gam; + gamma.green = gam; + gamma.blue = gam; break; + case Red: + gamma.red = gam; break; + case Green: + gamma.green = gam; break; + case Blue: + gamma.blue = gam; + }; + if (!XF86VidModeSetGamma(dpy, screen, &gamma)) { + kdDebug() << "KGamma: Unable to set gamma correction" << endl; + if ( OK ) *OK = false; + } + else { + XFlush(dpy); + if ( OK ) *OK = true; + } + } + } +} + +float XVidExtWrap::getGamma(int channel, bool* OK) { + XF86VidModeGamma gamma; + float gam = 0; + + if (!XF86VidModeGetGamma(dpy, screen, &gamma)) { + kdDebug() << "KGamma: Unable to query gamma correction" << endl; + if ( OK ) *OK = false; + } + else { + switch (channel) { + case Value: + gam = gamma.red; break; + case Red: + gam = gamma.red; break; + case Green: + gam = gamma.green; break; + case Blue: + gam = gamma.blue; + }; + if ( OK ) *OK = true; + } + return(gam); +} + +void XVidExtWrap::setGammaLimits( float min, float max ) { + mingamma = (min < 0.1) ? 0.1 : min; + maxgamma = (max > 10.0) ? 10.0 : max; +} + +#ifdef istringstream +#undef istringstream +#endif diff --git a/kgamma/kcmkgamma/xvidextwrap.h b/kgamma/kcmkgamma/xvidextwrap.h new file mode 100644 index 00000000..20ae4310 --- /dev/null +++ b/kgamma/kcmkgamma/xvidextwrap.h @@ -0,0 +1,59 @@ +/*************************************************************************** + xvidextwrap.h - description + ------------------- + begin : Sat Jan 5 2002 + copyright : (C) 2002 by Michael v.Ostheim + email : MvOstheim@web.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef XVIDEXTWRAP_H +#define XVIDEXTWRAP_H + +struct _XDisplay; + +/**A wrapper for XF86VidMode Extension + *@author Michael v.Ostheim + */ + +class XVidExtWrap { + + public: + + enum GammaChannel { Value = 0, Red = 1, Green = 2, Blue = 3 }; + XVidExtWrap(bool *OK, const char* displayname = NULL); + ~XVidExtWrap(); + + /** Returns the default screen */ + int _DefaultScreen(); + /** Returns the number of screens (extracted from XF86Config) */ + int _ScreenCount(); + /** Returns the displayname */ + const char* DisplayName(); + /** Sets the screen actions are take effect */ + void setScreen( int scrn ) { screen = scrn; }; + /** Returns the current screen */ + int getScreen() { return screen; }; + /** Sets the gamma value on the current screen */ + void setGamma( int channel, float gam, bool *OK = NULL ); + /** Gets the gamma value of the current screen */ + float getGamma( int channel, bool *OK = NULL ); + /** Limits the possible gamma values (default 0.1-10.0) */ + void setGammaLimits( float min, float max ); + + private: + float mingamma, maxgamma; + int screen; + Display* dpy; +}; + +#endif + diff --git a/kgamma/xf86gammacfg/Makefile.am b/kgamma/xf86gammacfg/Makefile.am new file mode 100644 index 00000000..3c7c0154 --- /dev/null +++ b/kgamma/xf86gammacfg/Makefile.am @@ -0,0 +1,11 @@ + +INCLUDES= $(all_includes) + +bin_PROGRAMS = xf86gammacfg +xf86gammacfg_SOURCES = xf86gammacfg.cpp +xf86gammacfg_LDADD = +xf86gammacfg_METASOURCES = AUTO +noinst_HEADERS = + +EXTRA_DIST = xf86gammacfg.cpp + diff --git a/kgamma/xf86gammacfg/xf86gammacfg.cpp b/kgamma/xf86gammacfg/xf86gammacfg.cpp new file mode 100644 index 00000000..db98a8fb --- /dev/null +++ b/kgamma/xf86gammacfg/xf86gammacfg.cpp @@ -0,0 +1,138 @@ +/*************************************************************************** + main.cpp - description + ------------------- + begin : Wed Aug 7 18:11:19 CEST 2002 + copyright : (C) 2002 by Michael v.Ostheim + email : MvOstheim@web.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include + +#include + +#include +#include +#include +#include + +#include + +#ifdef HAVE_SSTREAM +#include +#else +#include +#define istringstream istrstream +#endif + +using namespace std; + +int main(int argc, char *argv[]) +{ + + bool cpyonly, secmon, success; + + cpyonly = secmon = success = false; + + if ( !((argc-1) % 3) ) { + int Screen = 0; + int ScreenCount = (argc-1) / 3; + + // First, search for XF86Config or xorg.conf + vector searchPaths; + searchPaths.push_back("/etc/X11/XF86Config-4"); + searchPaths.push_back("/etc/X11/XF86Config"); + searchPaths.push_back("/etc/XF86Config"); + searchPaths.push_back("/usr/X11R6/etc/X11/XF86Config-4"); + searchPaths.push_back("/usr/X11R6/etc/X11/XF86Config"); + searchPaths.push_back("/usr/X11R6/lib/X11/XF86Config-4"); + searchPaths.push_back("/usr/X11R6/lib/X11/XF86Config"); + + searchPaths.push_back("/etc/X11/xorg.conf-4"); + searchPaths.push_back("/etc/X11/xorg.conf"); + searchPaths.push_back("/etc/xorg.conf"); + searchPaths.push_back("/usr/X11R6/etc/X11/xorg.conf-4"); + searchPaths.push_back("/usr/X11R6/etc/X11/xorg.conf"); + searchPaths.push_back("/usr/X11R6/lib/X11/xorg.conf-4"); + searchPaths.push_back("/usr/X11R6/lib/X11/xorg.conf"); + + std::vector::iterator it = searchPaths.begin(); + for (; it != searchPaths.end(); ++it ) { + //Try to open file + std::ifstream in( (*it).c_str() ); + + if ( in.is_open() ) { + std::ofstream out( ( (*it) + ".tmp" ).c_str() ); + if ( out.is_open() ) { + std::string s, buf; + std::vector words; + + while (getline(in, s,'\n')) { + if (!cpyonly) { + words.clear(); + std::istringstream ss(s.c_str()); + while (ss >> buf) words.push_back(buf); + + if ( !words.empty() ) { + if ( words[0] == "Section" && words.size() > 1 ) { + if ( words[1] == "\"Monitor\"" ) { + secmon = true; + out << s << endl; + continue; + } + } + if ( secmon ) { + if ( words[0] == "Gamma" ) { + out << " Gamma " << argv[3*Screen+1] << " " << \ + argv[3*Screen+2]<< " " << argv[3*Screen+3]; + out << " # created by KGamma" << endl; + cpyonly = success = ( ++Screen == ScreenCount ); + secmon = false; + continue; + } + if ( words[0] == "EndSection" ) { + out << " Gamma " << argv[3*Screen+1] << " " << \ + argv[3*Screen+2]<< " " << argv[3*Screen+3]; + out << " # created by KGamma" << endl; + out << s << endl; + cpyonly = success = ( ++Screen == ScreenCount ); + secmon = false; + continue; + } + } + } + } + out << s << endl; + } //endwhile + + in.close(); + out.close(); + + if ( success ) { + rename( (*it).c_str(),(*it + ".kgammaorig").c_str() ); + rename( (*it + ".tmp").c_str(),(*it).c_str() ); + } + else remove( (*it + ".tmp").c_str() ); + break; + } + } + } + } + if ( !success ) + cerr << "Usage: xf86gammacfg RGAMMA GGAMMA " \ + "BGAMMA [RGAMMA GGAMMA BGAMMA [...]]" << endl; + + return success; +} + +#ifdef istringstream +#undef istringstream +#endif diff --git a/kghostview/AUTHORS b/kghostview/AUTHORS new file mode 100644 index 00000000..001afaa8 --- /dev/null +++ b/kghostview/AUTHORS @@ -0,0 +1,9 @@ +Copyright (C) 1997-1998 Mark Donohoe +Copyright (C) 2000 Daniel Duley +Copyright (C) 2000-2002 Wilco Greven +Copyright (C) 1997 Markkhu Hihnala +Copyright (C) 2000 Espen Sand +Copyright (C) 1999-2000 David Sweet +Copyright (C) 2002-2003 Luís-Pedro Coelho + +KGhostView is based on original work by Tim Theisen. diff --git a/kghostview/ChangeLog b/kghostview/ChangeLog new file mode 100644 index 00000000..3695036c --- /dev/null +++ b/kghostview/ChangeLog @@ -0,0 +1,40 @@ +Version 0.8: + * [Mario Weilguni] + Made it work with Qt 2.0 + Fixed a lot of layout problems + Fixed segfault caused by wrong accelerator in ::changeAccelerators() + There are still a few problems with changed color handling, + currently outcommented (look for "TODO" if you wish to fix it) + +Version 0.7: + * [Mark Donohoe] Patch from Jake Hamy which + incorporates code from Johanes Plass' GV. This adds + (1) Compressed file support, (2) PDF support + ( Currently limited by ghostscript's poor handling of + this format ) + * [Mark Donohoe] Fixed major performance bug which caused gs to be + repeatedly restarted + * [Mark Donohoe] Improved print dialog + - Print to file + - Print all, current, marked, or range of pages + - Setup spooler command, printer name + - Reverse order of printing + * [Mark Donohoe] Much better keyboard support + * [Mark Donohoe] Improved geometry management + * [Mark Donohoe] Improved warning and error dialogs + +Version 0.6.3: + * [Mark Donohoe] Session management + * [Mark Donohoe] Patch from Markus Duda for + pagelist. + ( Fixes a problem with documents that have named rather + than numbered pages I believe ) + * [Mark Donohoe] Imporvements to page list interface + * [Mark Donohoe] Fixed mix up of Magnification and Orientation on + View Control dialog + * [Mark Donohoe] Few geometry management fixes + * [Mark Donohoe] New icon + +Version 0.6.1: + * [Robert Williams] Added version.h and ChangeLog + * [Robert Williams] Added -caption "%c" to kghostview.kdelnk diff --git a/kghostview/Makefile.am b/kghostview/Makefile.am new file mode 100644 index 00000000..93209382 --- /dev/null +++ b/kghostview/Makefile.am @@ -0,0 +1,69 @@ +SUBDIRS = data + +INCLUDES= $(all_includes) + +####### Files + +bin_PROGRAMS = kghostview +lib_LTLIBRARIES = libkghostviewlib.la +kde_module_LTLIBRARIES = libkghostviewpart.la +noinst_LTLIBRARIES = libdscparse.la + +libkghostviewlib_la_LDFLAGS = $(all_libraries) +libkghostviewlib_la_LIBADD = $(LIB_KFILE) $(LIB_KPARTS) -lkdeprint libdscparse.la + +libkghostviewpart_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module +libkghostviewpart_la_LIBADD = libkghostviewlib.la + +# Check "make final" after making changes to the following line!! +libkghostviewlib_la_SOURCES = kgvshell.cpp kgvdocument.cpp kgv_miniwidget.cpp \ + marklist.cpp logwindow.cpp infodialog.cpp \ + kgvpageview.cpp ps.c kgv_view.cpp scrollbox.cpp kgvpagedecorator.cpp \ + kgvconfigdialog.cpp kgvmainwidget.cpp \ + kdscerrordialog.cpp displayoptions.cpp kpswidget.cpp \ + fullscreenfilter.cpp kgvfactory.cpp \ + generalsettingswidget.ui gssettingswidget.ui thumbnailservice.cpp \ + configuration.kcfgc + +libkghostviewpart_la_SOURCES = part_init.cpp + +kghostview_SOURCES = main.cpp +kghostview_LDFLAGS = $(all_libraries) $(KDE_RPATH) +kghostview_LDADD = libkghostviewlib.la + +libdscparse_la_LDFLAGS = $(all_libraries) -no-undefined +libdscparse_la_LIBADD = $(LIB_QT) +libdscparse_la_SOURCES = dscparse.cpp dscparse_adapter.cpp + +noinst_HEADERS = marklist.h logwindow.h infodialog.h kgvshell.h \ + kpswidget.h kgvpageview.h ps.h kgv_miniwidget.h kgv_view.h scrollbox.h \ + kgvpagedecorator.h kgvconfigdialog.h kgvmainwidget.h dscparse.h \ + dscparse_adapter.h kdscerrordialog.h kgvdocument.h displayoptions.h \ + fullscreenfilter.h kgvfactory.h thumbnailservice.h + +METASOURCES = AUTO +EXTRA_DIST = kghostview.desktop + +KDE_ICON = kghostview + +xdg_apps_DATA = kghostview.desktop +kde_kcfg_DATA = kghostview.kcfg + +partdir = $(kde_datadir)/kghostview +part_DATA = kgv_part.rc kghostviewui.rc + +partdesktopdir = $(kde_servicesdir) +partdesktop_DATA = kghostview_part.desktop + +messages: rc.cpp + $(XGETTEXT) *.cpp *.h -o $(podir)/kghostview.pot + + +updatedir = $(kde_datadir)/kconf_update +update_DATA = kghostview.upd +update_SCRIPTS = update-to-xt-names.pl + +# check_PROGRAMS = testdsc + +# testdsc_SOURCES = testdsc.cpp kdsc.cpp ps.c +# testdsc_LDADD = -lqt diff --git a/kghostview/README b/kghostview/README new file mode 100644 index 00000000..eb92b02b --- /dev/null +++ b/kghostview/README @@ -0,0 +1,27 @@ +KGHOSTVIEW for KDE 3.x + +This is Tim Theisen's Ghostview program ported to the K +Desktop Environment. Ghostscript is used to view PostScript +documents on Unix X11 systems. + +REQUIREMENTS + +1. GNU ghostscript +2. KDE 3.x + +If ghostscript works for you then so should KGhostview. ghostscript can be obtained +at http://www.cs.wisc.edu/~ghost/. + +Due to security reasons, kghostview works only with recent versions of ghostscript. +Versions greater or equal to than GNU version 6.53 or GNU version 7.05 should work. + +Other versions or implementation of ghostscript may or may not work. In the +configuration dialog, found under the Settings menu in the app, it +is possible to configure the interpreter to use. + +Send bugs via http://bugs.kde.org + +CURRENT MAINTANER + +Luís-Pedro Coelho + diff --git a/kghostview/TODO b/kghostview/TODO new file mode 100644 index 00000000..f747ff13 --- /dev/null +++ b/kghostview/TODO @@ -0,0 +1,41 @@ +- Port to KViewShell / KMultiPage + +- Progress bar(s) when loading/converting (the latter can be very slow). + +- Find dialog. + +- Different icons for Read Up and Read Down. + +- Use pdftops which comes with xpdf for pdf->ps conversion. It's output + is much better, and it allows the conversion of selected pages, which is + important when you want to print a small number of pages from a large + document. + I don't think I'll switch to pdftops. Ghostscript also has the possibility + to convert selected pages only. And for printing its output is fine. + +- Provide more information via statusbar messages. See gsview, for how it + should be. + +- Move the page navigation options from the View menu to the Go menu. + Currently Konqueror doesn't merge the Go menu, so that should be fixed first. + +- Fit page to view-width, auto-zoom on widget resize. + +- Better handling of Orientation and Paper Size choice. + +- Continuous and Continuous Facing viewing of pages, like Acroread. + +- Find a good solution which helps the user to keep his eyes focused when + scrolling (smooth scrolling or using helper lines like gv). + +- Fix all the bugs. + + +Done: +- Scrollbox should show a thumbnail (like kdvi). + +- New implementation for the marklist because QTableView won't be in Qt-3.0 + anymore. (I'll keep using QTableView, simply because there's no suitable + alternative in Qt3.) + +- Switch to the DSC parser provided by Ghostscript. diff --git a/kghostview/configuration.kcfgc b/kghostview/configuration.kcfgc new file mode 100644 index 00000000..5617f368 --- /dev/null +++ b/kghostview/configuration.kcfgc @@ -0,0 +1,4 @@ +File=kghostview.kcfg +ClassName=Configuration +Mutators=true +Singleton=true diff --git a/kghostview/data/Makefile.am b/kghostview/data/Makefile.am new file mode 100644 index 00000000..f6a27c16 --- /dev/null +++ b/kghostview/data/Makefile.am @@ -0,0 +1,3 @@ +ps_DATA = pdf_sec.ps +psdir = ${kde_datadir}/kghostview + diff --git a/kghostview/data/pdf_sec.ps b/kghostview/data/pdf_sec.ps new file mode 100644 index 00000000..5fe9598a --- /dev/null +++ b/kghostview/data/pdf_sec.ps @@ -0,0 +1,386 @@ +% Copyright (C) 1996-1998 Geoffrey Keating. +% This file may be freely distributed with or without modifications, +% so long as modified versions are marked as such and copyright notices are +% not removed. + +% pdf_sec.ps (version 1.0.4) +% Implementation of security hooks for PDF reader. + +% This file contains the procedures that have to take encryption into +% account when reading a PDF file. It replaces the stub version of this +% file that is shipped with GhostScript. It requires GhostScript version 4.02 +% or later. + +% Documentation for using this file is available at +% http://www.ozemail.com.au/%7Egeoffk/pdfencrypt/ + +/.setlanguagelevel where { pop 2 .setlanguagelevel } if +.currentglobal true .setglobal +/pdfdict where { pop } { /pdfdict 100 dict def } ifelse +pdfdict begin + +% Older ghostscript versions do not have .pdftoken, so we use 'token' instead. +/.pdftoken where { pop } { /.pdftoken /token load def } ifelse + +% An implementation of an algorithm compatible with the RSA Data Security +% Inc. RC4 stream encryption algorithm. + +% rc4setkey +/rc4setkey +{ + 6 dict begin + /k exch def + /a 256 string def + 0 1 255 { a exch dup put } for + /l k length def + /j 0 def + 0 1 255 + { + /i exch def + /j a i get k i l mod get add j add 255 and def + a i a j get a j a i get put put + } for + 3 dict dup begin + /a a def + /x 0 def + /y 0 def + end + end +} bind def + +% rc4 +/rc4 +{ + 1 index begin + dup dup length 1 sub 0 exch 1 exch + { + /x x 1 add 255 and def + /y a x get y add 255 and def + a x a y get a y a x get put put +% stack: string string index + 2 copy get + a dup x get a y get add 255 and get + xor put dup + } for + pop + end +} bind def + +% take a stream and rc4 decrypt it. +% rc4decodefilter +/rc4decodefilter { + currentglobal exch true setglobal + dup length string copy rc4setkey + exch setglobal + exch 512 string + % stack: + { readstring pop rc4 exch pop } aload pop + 8 array astore cvx 0 () /SubFileDecode filter +} bind def + +% MD5 derived from RFC 1321, "The MD5 Message-Digest Algorithm", +% R. Rivest, MIT, RSADSI; implemented in PostScript by Geoffrey Keating. + +% We construct the MD5 transform by a sort of inline expansion. +% this takes up quite a bit of memory (around 17k), but gives a +% factor-of-two speed increase. +% This also allows us to take advantage of interpreters with 64-bit +% wide integers. +% This will not run on interpreters with 16-bit wide integers, if such +% things exist. +20 dict begin + +/T [ +16#d76aa478 16#e8c7b756 16#242070db 16#c1bdceee +16#f57c0faf 16#4787c62a 16#a8304613 16#fd469501 +16#698098d8 16#8b44f7af 16#ffff5bb1 16#895cd7be +16#6b901122 16#fd987193 16#a679438e 16#49b40821 +16#f61e2562 16#c040b340 16#265e5a51 16#e9b6c7aa +16#d62f105d 16#02441453 16#d8a1e681 16#e7d3fbc8 +16#21e1cde6 16#c33707d6 16#f4d50d87 16#455a14ed +16#a9e3e905 16#fcefa3f8 16#676f02d9 16#8d2a4c8a +16#fffa3942 16#8771f681 16#6d9d6122 16#fde5380c +16#a4beea44 16#4bdecfa9 16#f6bb4b60 16#bebfbc70 +16#289b7ec6 16#eaa127fa 16#d4ef3085 16#04881d05 +16#d9d4d039 16#e6db99e5 16#1fa27cf8 16#c4ac5665 +16#f4292244 16#432aff97 16#ab9423a7 16#fc93a039 +16#655b59c3 16#8f0ccc92 16#ffeff47d 16#85845dd1 +16#6fa87e4f 16#fe2ce6e0 16#a3014314 16#4e0811a1 +16#f7537e82 16#bd3af235 16#2ad7d2bb 16#eb86d391 +] def +/F [ +{ c d /xor b /and d /xor } { b c /xor d /and c /xor } +{ b c /xor d /xor } { d /not b /or c /xor } +] def +/R [ +16#0007 16#010c 16#0211 16#0316 16#0407 16#050c 16#0611 16#0716 +16#0807 16#090c 16#0a11 16#0b16 16#0c07 16#0d0c 16#0e11 16#0f16 +16#0105 16#0609 16#0b0e 16#0014 16#0505 16#0a09 16#0f0e 16#0414 +16#0905 16#0e09 16#030e 16#0814 16#0d05 16#0209 16#070e 16#0c14 +16#0504 16#080b 16#0b10 16#0e17 16#0104 16#040b 16#0710 16#0a17 +16#0d04 16#000b 16#0310 16#0617 16#0904 16#0c0b 16#0f10 16#0217 +16#0006 16#070a 16#0e0f 16#0515 16#0c06 16#030a 16#0a0f 16#0115 +16#0806 16#0f0a 16#060f 16#0d15 16#0406 16#0b0a 16#020f 16#0915 +] def + +/W 1 31 bitshift 0 gt def +/A W { /add } { /md5add } ifelse def +/t W { 1744 } { 1616 } ifelse array def +/C 0 def + +0 1 63 { + /i exch def + /r R i get def + /a/b/c/d 4 i 3 and roll [ /d/c/b/a ] { exch def } forall + + t C [ + a F i -4 bitshift get exec + a A /x r -8 bitshift /get A T i get A + W { 1 32 bitshift 1 sub /and } if + /dup r 31 and /bitshift /exch r 31 and 32 sub /bitshift /or + b A + /def + ] dup length C add /C exch def putinterval +} for + +1 1 C 1 sub { + dup 1 sub t exch get /def cvx eq + {pop} + {t exch 2 copy get cvx put} + ifelse +} for + +% If we could put t into a _packed_ array, its memory requirements +% would go from about 13k to about 4k. Unfortunately, we'd need around +% 1600 stack positions, around 3 times what we can expect to have +% available---and if that kind of memory is available, we don't really +% need to pack t. Sigh. + +% In fact, it's worse than that. You can't even determine what t will +% be and write it in directly (something like +% { /a c d xor b and d xor a md5add x 0 get md5add -680876936 md5add dup 7 +% bitshift exch -25 bitshift or b md5add def /d b c xor a ... +% ) because the scanner uses the operand stack to accumulate procedures. +% So the only way to have md5transform as a single procedure is the above +% trick. + +W /md5transform t end cvx bind def + +% Unfortunately, PostScript & its imitators convert large +% integers to floating-point. Worse, the fp representation probably +% won't have 32 significant bits. +% This procedure accounts for about 35% of the total time on 32-bit +% machines. +not { + /md5add { + 2 copy xor 0 lt + % if one is positive and one is negative, can't overflow + { add } + % if both are positive or negative + { 16#80000000 xor add 16#80000000 xor } + % same as subtracting (or adding) 2^31 and then subtracting (or + % adding) it back. + ifelse + } bind def +} { + /md5add { + add 16#0FFFFFFFF and + } bind def +} ifelse + +/md5 { + 20 dict begin + + % initialise a,b,c,d,x + /a 16#67452301 def + /b 16#efcdab89 def + /c 16#98badcfe def + /d 16#10325476 def + /x 16 array def + + % parameters + /origs exch def + /oslen origs length def + + % pad string to multiple of 512 bits + /s oslen 72 add 64 idiv 64 mul dup /slen exch def string def + s 0 origs putinterval + s oslen 16#80 put + s slen 8 sub oslen 31 and 3 bitshift put + s slen 7 sub oslen -5 bitshift 255 and put + s slen 6 sub oslen -13 bitshift 255 and put + + 0 64 slen 64 sub { + dup 1 exch 63 add { s exch get } for + 15 -1 0 { x exch 6 2 roll 3 { 8 bitshift or } repeat put } for + a b c d + md5transform + d md5add /d exch def + c md5add /c exch def + b md5add /b exch def + a md5add /a exch def + } for + + 16 string + [ [ a b c d ] { 3 { dup -8 bitshift } repeat } forall ] + 0 1 15 { + 3 copy dup 3 1 roll get 255 and put pop + } for + pop + + end +} bind def + +% Pad a key out to 32 bytes. +/pdf_pad_key % pdf_pad_key + { dup length 32 gt { 0 32 getinterval } if + <28bf4e5e4e758a41 64004e56fffa0108 + 2e2e00b6d0683e80 2f0ca9fe6453697a> + 0 32 3 index length sub getinterval + concatstrings + } bind def + +% Try a user key for a PDF file. +/pdf_try_key % pdf_try_key true + % pdf_try_key false + { Trailer /Encrypt oget + dup /O oget exch + /P oget 4 string exch + 2 copy 255 and 0 exch put + 2 copy -8 bitshift 255 and 1 exch put + 2 copy -16 bitshift 255 and 2 exch put + 2 copy -24 bitshift 255 and 3 exch put pop + Trailer /ID oget 0 oget + 3 { concatstrings } repeat + md5 0 5 getinterval + dup + Trailer /Encrypt oget /U oget dup length string copy exch + rc4setkey exch rc4 exch pop + <28bf4e5e4e758a41 64004e56fffa0108 + 2e2e00b6d0683e80 2f0ca9fe6453697a> eq + dup not { exch pop } if + } bind def + +% Process the encryption information in the Trailer. +/pdf_process_Encrypt + { Trailer /Encrypt oget + /Filter oget /Standard eq not + { (****This file uses an unknown security handler.\n) print flush + /pdf_process_Encrypt cvx /undefined signalerror + } + if + () pdf_pad_key pdf_try_key + { /FileKey exch def } + { /PDFPassword where + { pop PDFPassword pdf_pad_key pdf_try_key + { true } + { PDFPassword pdf_pad_key md5 0 5 getinterval rc4setkey + Trailer /Encrypt oget /O oget dup length string copy + rc4 exch pop + pdf_try_key + } + ifelse + { /FileKey exch def } + { (****Password did not work.\n) print flush + /pdf_process_Encrypt cvx /invalidfileaccess signalerror + } + ifelse + } + { (****This file has a user password set.\n) print flush + /pdf_process_Encrypt cvx /invalidfileaccess signalerror + } + ifelse + } + ifelse + Trailer /Encrypt oget /P oget 4 and 0 eq #? and + { (****This owner of this file has requested you do not print it.\n) + print flush + /pdf_process_Encrypt cvx /invalidfileaccess signalerror + } + if + } bind def + +% Calculate the key used to decrypt an object (to pass to .decpdfrun or +% put into a stream dictionary). +/computeobjkey % computeobjkey +{ + exch + 10 string + dup 0 FileKey putinterval + exch + % stack: gen# string obj# + 2 copy 255 and 5 exch put + 2 copy -8 bitshift 255 and 6 exch put + 2 copy -16 bitshift 255 and 7 exch put + pop exch + 2 copy 255 and 8 exch put + 2 copy -8 bitshift 255 and 9 exch put + pop md5 0 10 getinterval +} bind def + +% As .pdfrun, but decrypt strings with key . +/.decpdfrun % .decpdfrun - + { % Construct a procedure with the file, opdict and key bound into it. + 2 index cvlit mark mark 5 2 roll + { .pdftoken not { (%%EOF) cvn cvx } if + dup xcheck + { DEBUG { dup == flush } if + 3 -1 roll pop + 2 copy .knownget + { exch pop exch pop exec } + { (%stderr) (w) file + dup (****************Unknown operator: ) writestring + dup 3 -1 roll .writecvs dup (\n) writestring flushfile + pop + } + ifelse + } + { exch pop DEBUG { dup ==only ( ) print flush } if + dup type /stringtype eq + { exch rc4setkey exch rc4 } + if + exch pop + } + ifelse + } + aload pop .packtomark cvx + /loop cvx 2 packedarray cvx + { stopped /PDFsource } aload pop + PDFsource + { store { stop } if } aload pop .packtomark cvx + /PDFsource 3 -1 roll store exec + } bind def + +% Run the code to resolve an object reference. +/pdf_run_resolve + { /FileKey where + { pop + 2 copy computeobjkey dup 4 1 roll + PDFfile exch resolveopdict .decpdfrun + dup dup dup 5 2 roll + % stack: object object key object object + xcheck exch type /dicttype eq and + { /StreamKey exch put } + { pop pop } + ifelse + } + { PDFfile resolveopdict .pdfrun } + ifelse + } bind def + +% Prefix a decryption filter to a stream if needed. +% Stack: readdata? dict parms file/string filternames +% (both before and after). +/pdf_decrypt_stream + { 3 index /StreamKey known + { + exch + % Stack: readdata? dict parms filternames file/string + 3 index /Length oget () /SubFileDecode filter + 3 index /StreamKey get rc4decodefilter + exch + } if + } bind def + +end % pdfdict +.setglobal diff --git a/kghostview/displayoptions.cpp b/kghostview/displayoptions.cpp new file mode 100644 index 00000000..48d45e7e --- /dev/null +++ b/kghostview/displayoptions.cpp @@ -0,0 +1,150 @@ +/** + * Copyright (C) 2003, Lus Pedro Coelho + * + * 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 "displayoptions.h" +#include +#include +#include +#include + +namespace { + const double allowedMagnifications[] = { + 0.125, + 0.25, + 0.3333, + 0.5, + 0.6667, + 0.75, + 1, + 1.25, + 1.50, + 2, + 3, + 4, + 6, + 8 + }; + const size_t numberOfMagnifications = ( sizeof( allowedMagnifications ) / sizeof( allowedMagnifications[ 0 ] ) ); +} + +DisplayOptions DisplayOptions::parse( KCmdLineArgs* args ) +{ + DisplayOptions res; +#define CHECK_ORIENTATION( tag, value ) \ + if ( args->isSet( tag ) ) res._overrideOrientation = value; \ + if ( args->getOption( "orientation" ) == tag ) res._overrideOrientation = value; + + CHECK_ORIENTATION( "landscape", CDSC_LANDSCAPE ); + CHECK_ORIENTATION( "seascape", CDSC_SEASCAPE ); + CHECK_ORIENTATION( "portrait", CDSC_PORTRAIT); + CHECK_ORIENTATION( "upsidedown", CDSC_UPSIDEDOWN); + + res.setMagnification( args->getOption( "scale" ).toFloat() ); + res.setPage( args->getOption( "page" ).toInt() - 1 ); // transform from 1-based into 0-based + //res._overridePageMedia = args->getOption( "paper" ); + kdDebug(4500 ) << "Parsed options: " << DisplayOptions::toString( res ) << endl; + return res; +} + +namespace { + const char* const rformat = ".page: (\\d+); .magnification: ([\\d\\.]+); .orientation = (\\d+); .media = ([^;]*);"; + const char* const qformat = ".page: %1; .magnification: %2; .orientation = %3; .media = %4;"; +} + +QString DisplayOptions::toString( const DisplayOptions& options ) +{ + return QString( qformat ) + .arg( options.page() ) + .arg( options.magnification() ) + .arg( options.overrideOrientation() ) + .arg( options.overridePageMedia().utf8() ); +} + +bool DisplayOptions::fromString( DisplayOptions& out, const QString& in ) +{ + QRegExp regex( QString::fromLatin1( rformat ) ); + if ( regex.search( in ) < 0 ) return false; + + out.reset(); + out.setPage( regex.cap( 1 ).toInt() ); + out.setMagnification( regex.cap( 2 ).toDouble() ); + out.setOverrideOrientation( static_cast( regex.cap( 3 ).toInt() ) ); + if ( !regex.cap( 4 ).isEmpty() ) out.setOverridePageMedia( regex.cap( 4 ) ); + return true; +} + + +bool DisplayOptions::canZoomIn() const +{ + return unsigned( closestIndex() ) < ( numberOfMagnifications - 1 ); +} + +bool DisplayOptions::zoomIn() +{ + if ( !canZoomIn() ) return false; + _magnification = allowedMagnifications[ closestIndex() + 1 ]; + return true; +} + +bool DisplayOptions::canZoomOut() const +{ + return closestIndex() > 0; +} + +bool DisplayOptions::zoomOut() +{ + if ( !canZoomOut() ) return false; + _magnification = allowedMagnifications[ closestIndex() - 1 ]; + return true; +} + +double DisplayOptions::magnification() const +{ + return _magnification; +} + + +void DisplayOptions::setMagnification( double newZoom ) { + _magnification = newZoom; +} + +unsigned DisplayOptions::closestIndex() const { + kdDebug(4500) << "DisplayOptions::closestIndex(" << _magnification << ")" << endl; + unsigned res = 0; + while ( res < numberOfMagnifications + && allowedMagnifications[ res ] < _magnification ) ++res; + if ( res >= ( numberOfMagnifications - 1 ) ) return numberOfMagnifications - 1; + if ( res == 0 ) return 0; + + if ( ( allowedMagnifications[ res ] - _magnification ) > ( _magnification - allowedMagnifications[ res - 1 ] ) ) { + --res; + } + kdDebug(4500) << "DisplayOptions::closestIndex(" << res << "): nearest allowed magnification: " + << allowedMagnifications[ res ] << endl; + return res; +} + +QValueList DisplayOptions::normalMagnificationValues() { + QValueList res; + for ( const double *first = allowedMagnifications, *last = allowedMagnifications + numberOfMagnifications; + first != last; + ++first ) { + res << *first; + } + return res; +} + diff --git a/kghostview/displayoptions.h b/kghostview/displayoptions.h new file mode 100644 index 00000000..e929d8b7 --- /dev/null +++ b/kghostview/displayoptions.h @@ -0,0 +1,112 @@ +/** + * Copyright (C) 2003, Lus Pedro Coelho + * + * 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 DISPLAYOPTIONS_H +#define DISPLAYOPTIONS_H +#include +#include +#include "dscparse_adapter.h" +#include +class KCmdLineArgs; +class KConfig; + +class KDE_EXPORT DisplayOptions +{ + public: + DisplayOptions(); + + // default generated DisplayOptions(const DisplayOptions&); + // default generated ~DisplayOptions(); + // default generated DisplayOptions& operator = (const DisplayOptions&); + + void reset() { *this = DisplayOptions(); } + + void restoreOverrideOrientation() { setOverrideOrientation( CDSC_ORIENT_UNKNOWN ); } + void setOverrideOrientation(CDSC_ORIENTATION_ENUM e) { _overrideOrientation = e; } + CDSC_ORIENTATION_ENUM overrideOrientation() const { return _overrideOrientation; } + + void restoreOverridePageMedia() { _overridePageMedia = QString::null; } + void setOverridePageMedia(const QString& newMedia) { _overridePageMedia = newMedia; } + const QString& overridePageMedia() const { return _overridePageMedia; } + + /** + * The current page. + * Note that the pages here are 0-based, although the user should see 1-based pages. + * + * In parsing cmdline-args, we transform --page=1 into setPage( 0 ); + */ + int page() const { return _page; } + void setPage( int newPage ) { _page = newPage; } + + double magnification() const; + void setMagnification( double ); + /** + * Goes to the next degree of magnification if possible. If we cannot zoom in any more, it returns false, + * leaving the magnification untouched. + */ + bool zoomIn(); + bool zoomOut(); + + bool canZoomIn() const; + bool canZoomOut() const; + + /** + * Parses command line options. + */ + static DisplayOptions parse ( KCmdLineArgs * ); + /** + * Transforms the object in a string representation. + * Useful for storing in config files, for example. + * + * \return string representation or null on error. + * + * \sa fromString + */ + static QString toString( const DisplayOptions& ); + /** + * Reads the display options from a string formatted by toString. + * + * \return true if the convertion succeeded. + */ + static bool fromString( DisplayOptions&, const QString& ); + + /** + * Returns a list of values that normally we can get through + * zoomIn() & zoomOut() + */ + static QValueList normalMagnificationValues(); + + private: + + unsigned closestIndex() const; + + CDSC_ORIENTATION_ENUM _overrideOrientation; + QString _overridePageMedia; + int _page; + double _magnification; +}; + +inline +DisplayOptions::DisplayOptions() + :_overrideOrientation( CDSC_ORIENT_UNKNOWN ), + _overridePageMedia ( QString::null ), + _page( 0 ) +{ + setMagnification( 1.0 ); +} + +#endif // DISPLAYOPTIONS_H diff --git a/kghostview/dscparse.cpp b/kghostview/dscparse.cpp new file mode 100644 index 00000000..b5d2c3a7 --- /dev/null +++ b/kghostview/dscparse.cpp @@ -0,0 +1,3432 @@ +/* Copyright (C) 2000-2001, Ghostgum Software Pty Ltd. All rights reserved. + + This file is part of GSview. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility + to anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer + to the GNU General Public Licence for full details. + + Everyone is granted permission to copy, modify and redistribute this + file, but only under the conditions described in the GNU General + Public Licence. A copy of this license is supposed to have been given + to you along with this file so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. +*/ + +/* $Id$ */ + +/* dscparse.c - DSC parser */ + +/* + * This is a DSC parser, based on the DSC 3.0 spec, + * with a few DSC 2.1 additions for page size. + * + * Current limitations: + * %%+ may be used after any comment in the comment or trailer, + * but is currently only supported by + * %%DocumentMedia + * + * DSC 2.1 additions (discontinued in DSC 3.0): + * %%DocumentPaperColors: + * %%DocumentPaperForms: + * %%DocumentPaperSizes: + * %%DocumentPaperWeights: + * %%PaperColor: (ignored) + * %%PaperForm: (ignored) + * %%PaperSize: + * %%PaperWeight: (ignored) + * + * Other additions for defaults or page section + % %%ViewingOrientation: xx xy yx yy +*/ + +#include /* for sprintf(), not file I/O */ +#include +#include +#include + +#define MAXSTR 256 + +#include "dscparse.h" + +/* Macros for comparing string literals + * For maximum speed, the length of the second macro argument is + * computed at compile time. + * THE SECOND MACRO ARGUMENT MUST BE A STRING LITERAL. + */ +#define COMPARE(p,str) (strncmp((const char *)(p), (str), sizeof(str)-1)==0) +#define IS_DSC(line, str) (COMPARE((line), (str))) + +/* Macros for comparing the first one or two characters */ +#define IS_WHITE(ch) (((ch)==' ') || ((ch)=='\t')) +#define IS_EOL(ch) (((ch)=='\r') || ((ch)=='\n')) +#define IS_WHITE_OR_EOL(ch) (IS_WHITE(ch) || IS_EOL(ch)) +#define IS_BLANK(str) (IS_EOL(str[0])) +#define NOT_DSC_LINE(str) (((str)[0]!='%') || ((str)[1]!='%')) + +/* Macros for document offset to start and end of line */ +#define DSC_START(dsc) ((dsc)->data_offset + (dsc)->data_index - (dsc)->line_length) +#define DSC_END(dsc) ((dsc)->data_offset + (dsc)->data_index) + +/* dsc_scan_SECTION() functions return one of + * CDSC_ERROR, CDSC_OK, CDSC_NOTDSC + * or one of the following + */ +/* The line should be passed on to the next section parser. */ +#define CDSC_PROPAGATE 10 + +/* If document is DOS EPS and we haven't read 30 bytes, ask for more. */ +#define CDSC_NEEDMORE 11 + +template +inline T min (T a, T b) { return a < b ? a : b; } + +/* local prototypes */ +dsc_private void * dsc_memalloc(P2(CDSC *dsc, size_t size)); +dsc_private void dsc_memfree(P2(CDSC*dsc, void *ptr)); +dsc_private CDSC * dsc_init2(P1(CDSC *dsc)); +dsc_private void dsc_reset(P1(CDSC *dsc)); +dsc_private void dsc_section_join(P3(unsigned long begin, unsigned long *pend, unsigned long **pplast)); +dsc_private int dsc_read_line(P1(CDSC *dsc)); +dsc_private int dsc_read_doseps(P1(CDSC *dsc)); +dsc_private char * dsc_alloc_string(P3(CDSC *dsc, const char *str, int len)); +dsc_private char * dsc_add_line(P3(CDSC *dsc, const char *line, unsigned int len)); +dsc_private char * dsc_copy_string(P5(char *str, unsigned int slen, + char *line, unsigned int len, unsigned int *offset)); +dsc_private GSDWORD dsc_get_dword(P1(const unsigned char *buf)); +dsc_private GSWORD dsc_get_word(P1(const unsigned char *buf)); +dsc_private int dsc_get_int(P3(const char *line, unsigned int len, unsigned int *offset)); +dsc_private float dsc_get_real(P3(const char *line, unsigned int len, + unsigned int *offset)); +dsc_private int dsc_stricmp(P2(const char *s, const char *t)); +dsc_private void dsc_unknown(P1(CDSC *dsc)); +dsc_private GSBOOL dsc_is_section(char *line); +dsc_private int dsc_parse_pages(P1(CDSC *dsc)); +dsc_private int dsc_parse_bounding_box(P3(CDSC *dsc, CDSCBBOX** pbbox, int offset)); +dsc_private int dsc_parse_float_bounding_box(P3(CDSC *dsc, CDSCFBBOX** pfbbox, int offset)); +dsc_private int dsc_parse_orientation(P3(CDSC *dsc, unsigned int *porientation, + int offset)); +dsc_private int dsc_parse_order(P1(CDSC *dsc)); +dsc_private int dsc_parse_media(P2(CDSC *dsc, const CDSCMEDIA **page_media)); +dsc_private int dsc_parse_document_media(P1(CDSC *dsc)); +dsc_private int dsc_parse_viewing_orientation(P2(CDSC *dsc, CDSCCTM **pctm)); +dsc_private int dsc_parse_page(P1(CDSC *dsc)); +dsc_private void dsc_save_line(P1(CDSC *dsc)); +dsc_private int dsc_scan_type(P1(CDSC *dsc)); +dsc_private int dsc_scan_comments(P1(CDSC *dsc)); +dsc_private int dsc_scan_preview(P1(CDSC *dsc)); +dsc_private int dsc_scan_defaults(P1(CDSC *dsc)); +dsc_private int dsc_scan_prolog(P1(CDSC *dsc)); +dsc_private int dsc_scan_setup(P1(CDSC *dsc)); +dsc_private int dsc_scan_page(P1(CDSC *dsc)); +dsc_private int dsc_scan_trailer(P1(CDSC *dsc)); +dsc_private int dsc_error(P4(CDSC *dsc, unsigned int explanation, + char *line, unsigned int line_len)); + +/* DSC error reporting */ +dsc_private const int dsc_severity[] = { + CDSC_ERROR_WARN, /* CDSC_MESSAGE_BBOX */ + CDSC_ERROR_WARN, /* CDSC_MESSAGE_EARLY_TRAILER */ + CDSC_ERROR_WARN, /* CDSC_MESSAGE_EARLY_EOF */ + CDSC_ERROR_ERROR, /* CDSC_MESSAGE_PAGE_IN_TRAILER */ + CDSC_ERROR_ERROR, /* CDSC_MESSAGE_PAGE_ORDINAL */ + CDSC_ERROR_ERROR, /* CDSC_MESSAGE_PAGES_WRONG */ + CDSC_ERROR_ERROR, /* CDSC_MESSAGE_EPS_NO_BBOX */ + CDSC_ERROR_ERROR, /* CDSC_MESSAGE_EPS_PAGES */ + CDSC_ERROR_WARN, /* CDSC_MESSAGE_NO_MEDIA */ + CDSC_ERROR_WARN, /* CDSC_MESSAGE_ATEND */ + CDSC_ERROR_INFORM, /* CDSC_MESSAGE_DUP_COMMENT */ + CDSC_ERROR_INFORM, /* CDSC_MESSAGE_DUP_TRAILER */ + CDSC_ERROR_WARN, /* CDSC_MESSAGE_BEGIN_END */ + CDSC_ERROR_INFORM, /* CDSC_MESSAGE_BAD_SECTION */ + CDSC_ERROR_INFORM, /* CDSC_MESSAGE_LONG_LINE */ + CDSC_ERROR_WARN, /* CDSC_MESSAGE_INCORRECT_USAGE */ + 0 +}; + +#define DSC_MAX_ERROR ((sizeof(dsc_severity) / sizeof(int))-2) + +const CDSCMEDIA dsc_known_media[CDSC_KNOWN_MEDIA] = { + /* These sizes taken from Ghostscript gs_statd.ps */ + {"11x17", 792, 1224, 0, NULL, NULL, NULL}, + {"A0", 2380, 3368, 0, NULL, NULL, NULL}, + {"A1", 1684, 2380, 0, NULL, NULL, NULL}, + {"A2", 1190, 1684, 0, NULL, NULL, NULL}, + {"A3", 842, 1190, 0, NULL, NULL, NULL}, + {"A4", 595, 842, 0, NULL, NULL, NULL}, + {"A5", 421, 595, 0, NULL, NULL, NULL}, + {"A6", 297, 421, 0, NULL, NULL, NULL}, + {"A7", 210, 297, 0, NULL, NULL, NULL}, + {"A8", 148, 210, 0, NULL, NULL, NULL}, + {"A9", 105, 148, 0, NULL, NULL, NULL}, + {"A10", 74, 105, 0, NULL, NULL, NULL}, + {"B0", 2836, 4008, 0, NULL, NULL, NULL}, + {"B1", 2004, 2836, 0, NULL, NULL, NULL}, + {"B2", 1418, 2004, 0, NULL, NULL, NULL}, + {"B3", 1002, 1418, 0, NULL, NULL, NULL}, + {"B4", 709, 1002, 0, NULL, NULL, NULL}, /* ISO, but not Adobe standard */ + {"B5", 501, 709, 0, NULL, NULL, NULL}, /* ISO, but not Adobe standard */ + {"B6", 354, 501, 0, NULL, NULL, NULL}, + {"C0", 2600, 3677, 0, NULL, NULL, NULL}, + {"C1", 1837, 2600, 0, NULL, NULL, NULL}, + {"C2", 1298, 1837, 0, NULL, NULL, NULL}, + {"C3", 918, 1298, 0, NULL, NULL, NULL}, + {"C4", 649, 918, 0, NULL, NULL, NULL}, + {"C5", 459, 649, 0, NULL, NULL, NULL}, + {"C6", 323, 459, 0, NULL, NULL, NULL}, + {"Ledger", 1224, 792, 0, NULL, NULL, NULL}, + {"Legal", 612, 1008, 0, NULL, NULL, NULL}, + {"Letter", 612, 792, 0, NULL, NULL, NULL}, + {"Note", 612, 792, 0, NULL, NULL, NULL}, +// ISO and JIS B sizes are different.... + {"jisb0", 2916, 4128, 0, NULL, NULL, NULL}, + {"jisb1", 2064, 2916, 0, NULL, NULL, NULL}, + {"jisb2", 1458, 2064, 0, NULL, NULL, NULL}, + {"jisb3", 1032, 1458, 0, NULL, NULL, NULL}, + {"jisb4", 729, 1032, 0, NULL, NULL, NULL}, + {"jisb5", 516, 729, 0, NULL, NULL, NULL}, + {"jisb6", 363, 516, 0, NULL, NULL, NULL}, +// U.S. CAD standard paper sizes + {"archE", 2592, 3456, 0, NULL, NULL, NULL}, + {"archD", 1728, 2592, 0, NULL, NULL, NULL}, + {"archC", 1296, 1728, 0, NULL, NULL, NULL}, + {"archB", 864, 1296, 0, NULL, NULL, NULL}, + {"archA", 648, 864, 0, NULL, NULL, NULL}, +// Other paper sizes + {"flsa", 612, 936, 0, NULL, NULL, NULL}, /* U.S. foolscap */ + {"flse", 612, 936, 0, NULL, NULL, NULL}, /* European foolscap */ + {"halfletter", 396, 612, 0, NULL, NULL, NULL}, + {NULL, 0, 0, 0, NULL, NULL, NULL} +}; + +/* parser state */ +enum CDSC_SCAN_SECTION { + scan_none = 0, + scan_comments = 1, + scan_pre_preview = 2, + scan_preview = 3, + scan_pre_defaults = 4, + scan_defaults = 5, + scan_pre_prolog = 6, + scan_prolog = 7, + scan_pre_setup = 8, + scan_setup = 9, + scan_pre_pages = 10, + scan_pages = 11, + scan_pre_trailer = 12, + scan_trailer = 13, + scan_eof = 14 +}; + +static const char * const dsc_scan_section_name[15] = { + "Type", "Comments", + "pre-Preview", "Preview", + "pre-Defaults", "Defaults", + "pre-Prolog", "Prolog", + "pre-Setup", "Setup", + "pre-Page", "Page", + "pre-Trailer", "Trailer", + "EOF" +}; + +/******************************************************************/ +/* Public functions */ +/******************************************************************/ + +/* constructor */ +CDSC * +dsc_init(void *caller_data) +{ + CDSC *dsc = (CDSC *)malloc(sizeof(CDSC)); + if (dsc == NULL) + return NULL; + memset(dsc, 0, sizeof(CDSC)); + dsc->caller_data = caller_data; + + return dsc_init2(dsc); +} + +/* constructor, with caller supplied memalloc */ +CDSC * +dsc_init_with_alloc( + void *caller_data, + void *(*memalloc)(size_t size, void *closure_data), + void (*memfree)(void *ptr, void *closure_data), + void *closure_data) +{ + CDSC *dsc = (CDSC *)memalloc(sizeof(CDSC), closure_data); + if (dsc == NULL) + return NULL; + memset(dsc, 0, sizeof(CDSC)); + dsc->caller_data = caller_data; + + dsc->memalloc = memalloc; + dsc->memfree = memfree; + dsc->mem_closure_data = closure_data; + + return dsc_init2(dsc); +} + + + +/* destructor */ +void +dsc_free(CDSC *dsc) +{ + if (dsc == NULL) + return; + dsc_reset(dsc); + dsc_memfree(dsc, dsc); +} + + +/* Tell DSC parser how long document will be, to allow ignoring + * of early %%Trailer and %%EOF. This is optional. + */ +void +dsc_set_length(CDSC *dsc, unsigned long len) +{ + dsc->file_length = len; +} + +/* Process a buffer containing DSC comments and PostScript */ +/* Return value is < 0 for error, >=0 for OK. + * CDSC_ERROR + * CDSC_OK + * CDSC_NOTDSC (DSC will be ignored) + * other values indicate the last DSC comment read + */ +int +dsc_scan_data(CDSC *dsc, const char *data, int length) +{ + int bytes_read; + int code = 0; + + if (dsc == NULL) + return CDSC_ERROR; + + if (dsc->id == CDSC_NOTDSC) + return CDSC_NOTDSC; + dsc->id = CDSC_OK; + if (dsc->eof) + return CDSC_OK; /* ignore */ + + if (length == 0) { + /* EOF, so process what remains */ + dsc->eof = TRUE; + } + + do { + if (dsc->id == CDSC_NOTDSC) + break; + + if (length != 0) { + /* move existing data if needed */ + if (dsc->data_length > CDSC_DATA_LENGTH/2) { + memmove(dsc->data, dsc->data + dsc->data_index, + dsc->data_length - dsc->data_index); + dsc->data_offset += dsc->data_index; + dsc->data_length -= dsc->data_index; + dsc->data_index = 0; + } + /* append to buffer */ + bytes_read = min(length, (int)(CDSC_DATA_LENGTH - dsc->data_length)); + memcpy(dsc->data + dsc->data_length, data, bytes_read); + dsc->data_length += bytes_read; + data += bytes_read; + length -= bytes_read; + } + if (dsc->scan_section == scan_none) { + code = dsc_scan_type(dsc); + if (code == CDSC_NEEDMORE) { + /* need more characters before we can identify type */ + code = CDSC_OK; + break; + } + dsc->id = code; + } + + if (code == CDSC_NOTDSC) { + dsc->id = CDSC_NOTDSC; + break; + } + + while ((code = dsc_read_line(dsc)) > 0) { + if (dsc->id == CDSC_NOTDSC) + break; + if (dsc->doseps_end && + (dsc->data_offset + dsc->data_index > dsc->doseps_end)) { + /* have read past end of DOS EPS PostScript section */ + return CDSC_OK; /* ignore */ + } + if (dsc->eof) + return CDSC_OK; + if (dsc->skip_document) + continue; /* embedded document */ + if (dsc->skip_lines) + continue; /* embedded lines */ + if (IS_DSC(dsc->line, "%%BeginData:")) + continue; + if (IS_DSC(dsc->line, "%%BeginBinary:")) + continue; + if (IS_DSC(dsc->line, "%%EndDocument")) + continue; + if (IS_DSC(dsc->line, "%%EndData")) + continue; + if (IS_DSC(dsc->line, "%%EndBinary")) + continue; + + do { + switch (dsc->scan_section) { + case scan_comments: + code = dsc_scan_comments(dsc); + break; + case scan_pre_preview: + case scan_preview: + code = dsc_scan_preview(dsc); + break; + case scan_pre_defaults: + case scan_defaults: + code = dsc_scan_defaults(dsc); + break; + case scan_pre_prolog: + case scan_prolog: + code = dsc_scan_prolog(dsc); + break; + case scan_pre_setup: + case scan_setup: + code = dsc_scan_setup(dsc); + break; + case scan_pre_pages: + case scan_pages: + code = dsc_scan_page(dsc); + break; + case scan_pre_trailer: + case scan_trailer: + code = dsc_scan_trailer(dsc); + break; + case scan_eof: + code = CDSC_OK; + break; + default: + /* invalid state */ + code = CDSC_ERROR; + } + /* repeat if line is start of next section */ + } while (code == CDSC_PROPAGATE); + + /* if DOS EPS header not complete, ask for more */ + if (code == CDSC_NEEDMORE) { + code = CDSC_OK; + break; + } + if (code == CDSC_NOTDSC) { + dsc->id = CDSC_NOTDSC; + break; + } + } + } while (length != 0); + + return (code < 0) ? code : dsc->id; +} + +/* Tidy up from incorrect DSC comments */ +int +dsc_fixup(CDSC *dsc) +{ + unsigned int i; + char buf[32]; + unsigned long *last; + + if (dsc->id == CDSC_NOTDSC) + return 0; + + /* flush last partial line */ + dsc_scan_data(dsc, NULL, 0); + + /* Fix DSC error: code between %%EndSetup and %%Page */ + if (dsc->page_count && (dsc->page[0].begin != dsc->endsetup) + && (dsc->endsetup != dsc->beginsetup)) { + dsc->endsetup = dsc->page[0].begin; + dsc_debug_print(dsc, "Warning: code included between setup and first page\n"); + } + + /* Last page contained a false trailer, */ + /* so extend last page to start of trailer */ + if (dsc->page_count && (dsc->begintrailer != 0) && + (dsc->page[dsc->page_count-1].end != dsc->begintrailer)) { + dsc_debug_print(dsc, "Ignoring earlier misplaced trailer\n"); + dsc_debug_print(dsc, "and extending last page to start of trailer\n"); + dsc->page[dsc->page_count-1].end = dsc->begintrailer; + } + + /* + * Join up all sections. + * There might be extra code between them, or we might have + * missed including the \n which followed \r. + */ + last = &dsc->endcomments; + dsc_section_join(dsc->beginpreview, &dsc->endpreview, &last); + dsc_section_join(dsc->begindefaults, &dsc->enddefaults, &last); + dsc_section_join(dsc->beginprolog, &dsc->endprolog, &last); + dsc_section_join(dsc->beginsetup, &dsc->endsetup, &last); + for (i=0; ipage_count; i++) + dsc_section_join(dsc->page[i].begin, &dsc->page[i].end, &last); + if (dsc->begintrailer) + *last = dsc->begintrailer; + + if ((dsc->page_pages == 0) && (dsc->page_count == 1)) { + /* don't flag an error if %%Pages absent but one %%Page found */ + /* adjust incorrect page count */ + dsc->page_pages = dsc->page_count; + } + + /* Warnings and Errors that we can now identify */ + if ((dsc->page_count != dsc->page_pages)) { + int rc = dsc_error(dsc, CDSC_MESSAGE_PAGES_WRONG, NULL, 0); + switch (rc) { + case CDSC_RESPONSE_OK: + /* adjust incorrect page count */ + dsc->page_pages = dsc->page_count; + break; + case CDSC_RESPONSE_CANCEL: + break;; + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + + if (dsc->epsf && (dsc->bbox == (CDSCBBOX *)NULL)) { + /* EPS files MUST include a BoundingBox */ + int rc = dsc_error(dsc, CDSC_MESSAGE_EPS_NO_BBOX, NULL, 0); + switch (rc) { + case CDSC_RESPONSE_OK: + /* Assume that it is EPS */ + break; + case CDSC_RESPONSE_CANCEL: + /* Is NOT an EPS file */ + dsc->epsf = FALSE; + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + + if (dsc->epsf && ((dsc->page_count > 1) || (dsc->page_pages > 1))) { + int rc = dsc_error(dsc, CDSC_MESSAGE_EPS_PAGES, NULL, 0); + switch (rc) { + case CDSC_RESPONSE_OK: + /* Is an EPS file */ + break; + case CDSC_RESPONSE_CANCEL: + /* Is NOT an EPS file */ + dsc->epsf = FALSE; + break; + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + + if ((dsc->media_count == 1) && (dsc->page_media == NULL)) { + /* if one only media was specified, and default page media */ + /* was not specified, assume that default is the only media. */ + dsc->page_media = dsc->media[0]; + } + + if ((dsc->media_count != 0) && (dsc->page_media == NULL)) { + int rc = dsc_error(dsc, CDSC_MESSAGE_NO_MEDIA, NULL, 0); + switch (rc) { + case CDSC_RESPONSE_OK: + /* default media is first listed */ + dsc->page_media = dsc->media[0]; + break; + case CDSC_RESPONSE_CANCEL: + /* No default media */ + break; + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + + /* make sure all pages have a label */ + for (i=0; ipage_count; i++) { + if (strlen(dsc->page[i].label) == 0) { + sprintf(buf, "%d", i+1); + if ((dsc->page[i].label = dsc_alloc_string(dsc, buf, strlen(buf))) + == (char *)NULL) + return CDSC_ERROR; /* no memory */ + } + } + return CDSC_OK; +} + +/* Install a function to be used for displaying messages about + * DSC errors and warnings, and to request advice from user. + * Installing an error function is optional. + */ +void +dsc_set_error_function(CDSC *dsc, + int (*fn)(P5(void *caller_data, CDSC *dsc, + unsigned int explanation, const char *line, unsigned int line_len))) +{ + dsc->dsc_error_fn = fn; +} + + +/* Install a function for printing debug messages */ +/* This is optional */ +void +dsc_set_debug_function(CDSC *dsc, + void (*debug_fn)(P2(void *caller_data, const char *str))) +{ + dsc->debug_print_fn = debug_fn; +} + +/* Doesn't need to be public for PostScript documents */ +/* Made public so GSview can add pages when processing PDF files */ +int +dsc_add_page(CDSC *dsc, int ordinal, char *label) +{ + dsc->page[dsc->page_count].ordinal = ordinal; + dsc->page[dsc->page_count].label = + dsc_alloc_string(dsc, label, strlen(label)+1); + dsc->page[dsc->page_count].begin = 0; + dsc->page[dsc->page_count].end = 0; + dsc->page[dsc->page_count].orientation = CDSC_ORIENT_UNKNOWN; + dsc->page[dsc->page_count].media = NULL; + dsc->page[dsc->page_count].bbox = NULL; + dsc->page[dsc->page_count].viewing_orientation = NULL; + + dsc->page_count++; + if (dsc->page_count >= dsc->page_chunk_length) { + CDSCPAGE *new_page = (CDSCPAGE *)dsc_memalloc(dsc, + (CDSC_PAGE_CHUNK+dsc->page_count) * sizeof(CDSCPAGE)); + if (new_page == NULL) + return CDSC_ERROR; /* out of memory */ + memcpy(new_page, dsc->page, + dsc->page_count * sizeof(CDSCPAGE)); + dsc_memfree(dsc, dsc->page); + dsc->page= new_page; + dsc->page_chunk_length = CDSC_PAGE_CHUNK+dsc->page_count; + } + return CDSC_OK; +} + +/* Doesn't need to be public for PostScript documents */ +/* Made public so GSview can store PDF MediaBox */ +int +dsc_add_media(CDSC *dsc, CDSCMEDIA *media) +{ + CDSCMEDIA **newmedia_array; + CDSCMEDIA *newmedia; + + /* extend media array */ + newmedia_array = (CDSCMEDIA **)dsc_memalloc(dsc, + (dsc->media_count + 1) * sizeof(CDSCMEDIA *)); + if (newmedia_array == NULL) + return CDSC_ERROR; /* out of memory */ + if (dsc->media != NULL) { + memcpy(newmedia_array, dsc->media, + dsc->media_count * sizeof(CDSCMEDIA *)); + dsc_memfree(dsc, dsc->media); + } + dsc->media = newmedia_array; + + /* allocate new media */ + newmedia = dsc->media[dsc->media_count] = + (CDSCMEDIA *)dsc_memalloc(dsc, sizeof(CDSCMEDIA)); + if (newmedia == NULL) + return CDSC_ERROR; /* out of memory */ + newmedia->name = NULL; + newmedia->width = 595.0; + newmedia->height = 842.0; + newmedia->weight = 80.0; + newmedia->colour = NULL; + newmedia->type = NULL; + newmedia->mediabox = NULL; + + dsc->media_count++; + + if (media->name) { + newmedia->name = dsc_alloc_string(dsc, media->name, + strlen(media->name)); + if (newmedia->name == NULL) + return CDSC_ERROR; /* no memory */ + } + newmedia->width = media->width; + newmedia->height = media->height; + newmedia->weight = media->weight; + if (media->colour) { + newmedia->colour = dsc_alloc_string(dsc, media->colour, + strlen(media->colour)); + if (newmedia->colour == NULL) + return CDSC_ERROR; /* no memory */ + } + if (media->type) { + newmedia->type = dsc_alloc_string(dsc, media->type, + strlen(media->type)); + if (newmedia->type == NULL) + return CDSC_ERROR; /* no memory */ + } + newmedia->mediabox = NULL; + + if (media->mediabox) { + newmedia->mediabox = (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX)); + if (newmedia->mediabox == NULL) + return CDSC_ERROR; /* no memory */ + *newmedia->mediabox = *media->mediabox; + } + return CDSC_OK; +} + +/* Doesn't need to be public for PostScript documents */ +/* Made public so GSview can store PDF CropBox */ +int +dsc_set_page_bbox(CDSC *dsc, unsigned int page_number, + int llx, int lly, int urx, int ury) +{ + CDSCBBOX *bbox; + if (page_number >= dsc->page_count) + return CDSC_ERROR; + bbox = dsc->page[page_number].bbox; + if (bbox == NULL) + dsc->page[page_number].bbox = bbox = + (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX)); + if (bbox == NULL) + return CDSC_ERROR; + bbox->llx = llx; + bbox->lly = lly; + bbox->urx = urx; + bbox->ury = ury; + return CDSC_OK; +} + + +/******************************************************************/ +/* Private functions below here. */ +/******************************************************************/ + +dsc_private void * +dsc_memalloc(CDSC *dsc, size_t size) +{ + if (dsc->memalloc) + return dsc->memalloc(size, dsc->mem_closure_data); + return malloc(size); +} + +dsc_private void +dsc_memfree(CDSC*dsc, void *ptr) +{ + if (dsc->memfree) + dsc->memfree(ptr, dsc->mem_closure_data); + else + free(ptr); +} + +/* private constructor */ +dsc_private CDSC * +dsc_init2(CDSC *dsc) +{ + dsc_reset(dsc); + + dsc->string_head = (CDSCSTRING *)dsc_memalloc(dsc, sizeof(CDSCSTRING)); + if (dsc->string_head == NULL) { + dsc_free(dsc); + return NULL; /* no memory */ + } + dsc->string = dsc->string_head; + dsc->string->next = NULL; + dsc->string->data = (char *)dsc_memalloc(dsc, CDSC_STRING_CHUNK); + if (dsc->string->data == NULL) { + dsc_free(dsc); + return NULL; /* no memory */ + } + dsc->string->index = 0; + dsc->string->length = CDSC_STRING_CHUNK; + + dsc->page = (CDSCPAGE *)dsc_memalloc(dsc, CDSC_PAGE_CHUNK * sizeof(CDSCPAGE)); + if (dsc->page == NULL) { + dsc_free(dsc); + return NULL; /* no memory */ + } + dsc->page_chunk_length = CDSC_PAGE_CHUNK; + dsc->page_count = 0; + + dsc->line = NULL; + dsc->data_length = 0; + dsc->data_index = dsc->data_length; + + return dsc; +} + + +dsc_private void +dsc_reset(CDSC *dsc) +{ + unsigned int i; + /* Clear public members */ + dsc->dsc = FALSE; + dsc->ctrld = FALSE; + dsc->pjl = FALSE; + dsc->epsf = FALSE; + dsc->pdf = FALSE; + dsc->epsf = FALSE; + dsc->preview = CDSC_NOPREVIEW; + dsc->dsc_version = NULL; /* stored in dsc->string */ + dsc->language_level = 0; + dsc->document_data = CDSC_DATA_UNKNOWN; + dsc->begincomments = 0; + dsc->endcomments = 0; + dsc->beginpreview = 0; + dsc->endpreview = 0; + dsc->begindefaults = 0; + dsc->enddefaults = 0; + dsc->beginprolog = 0; + dsc->endprolog = 0; + dsc->beginsetup = 0; + dsc->endsetup = 0; + dsc->begintrailer = 0; + dsc->endtrailer = 0; + + for (i=0; ipage_count; i++) { + /* page media is pointer to an element of media or dsc_known_media */ + /* do not free it. */ + + if (dsc->page[i].bbox) + dsc_memfree(dsc, dsc->page[i].bbox); + if (dsc->page[i].viewing_orientation) + dsc_memfree(dsc, dsc->page[i].viewing_orientation); + } + if (dsc->page) + dsc_memfree(dsc, dsc->page); + dsc->page = NULL; + + dsc->page_count = 0; + dsc->page_pages = 0; + dsc->page_order = CDSC_ORDER_UNKNOWN; + dsc->page_orientation = CDSC_ORIENT_UNKNOWN; + if (dsc->viewing_orientation) + dsc_memfree(dsc, dsc->viewing_orientation); + dsc->viewing_orientation = NULL; + + if (dsc->media) { + for (i=0; imedia_count; i++) { + if (dsc->media[i]) { + if (dsc->media[i]->mediabox) + dsc_memfree(dsc, dsc->media[i]->mediabox); + dsc_memfree(dsc, dsc->media[i]); + } + } + dsc_memfree(dsc, dsc->media); + } + dsc->media_count = 0; + dsc->media = NULL; + + /* page_media is pointer to an element of media or dsc_known_media */ + /* do not free it. */ + dsc->page_media = NULL; + + if (dsc->bbox) + dsc_memfree(dsc, dsc->bbox); + dsc->bbox = NULL; + if (dsc->page_bbox) + dsc_memfree(dsc, dsc->page_bbox); + dsc->page_bbox = NULL; + if (dsc->doseps) + dsc_memfree(dsc, dsc->doseps); + dsc->doseps = NULL; + + dsc->dsc_title = NULL; + dsc->dsc_creator = NULL; + dsc->dsc_date = NULL; + dsc->dsc_for = NULL; + + + dsc->max_error = DSC_MAX_ERROR; + dsc->severity = dsc_severity; + + /* Clear private members */ + /* Don't touch dsc->caller_data */ + dsc->id = CDSC_OK; + dsc->scan_section = scan_none; + dsc->doseps_end = 0; + dsc->page_chunk_length = 0; + dsc->file_length = 0; + dsc->skip_document = 0; + dsc->skip_bytes = 0; + dsc->skip_lines = 0; + dsc->skip_pjl = 0; + dsc->begin_font_count = 0; + dsc->begin_feature_count = 0; + dsc->begin_resource_count = 0; + dsc->begin_procset_count = 0; + + dsc->data_length = 0; + dsc->data_index = 0; + dsc->data_offset = 0; + + dsc->eof = 0; + + dsc->line = 0; + dsc->line_length = 0; + dsc->eol = 0; + dsc->last_cr = FALSE; + dsc->line_count = 1; + dsc->long_line = FALSE; + memset(dsc->last_line, 0, sizeof(dsc->last_line)); + + dsc->string = dsc->string_head; + while (dsc->string != (CDSCSTRING *)NULL) { + if (dsc->string->data) + dsc_memfree(dsc, dsc->string->data); + dsc->string_head = dsc->string; + dsc->string = dsc->string->next; + dsc_memfree(dsc, dsc->string_head); + } + dsc->string_head = NULL; + dsc->string = NULL; + + /* don't touch caller functions */ + + /* public data */ + if (dsc->hires_bbox) + dsc_memfree(dsc, dsc->hires_bbox); + dsc->hires_bbox = NULL; + if (dsc->crop_box) + dsc_memfree(dsc, dsc->crop_box); + dsc->crop_box = NULL; +} + +/* +* Join up all sections. +* There might be extra code between them, or we might have +* missed including the \n which followed \r. +* begin is the start of this section +* pend is a pointer to the end of this section +* pplast is a pointer to a pointer of the end of the previous section +*/ +dsc_private void +dsc_section_join(unsigned long begin, unsigned long *pend, unsigned long **pplast) +{ + if (begin) + **pplast = begin; + if (*pend > begin) + *pplast = pend; +} + + +/* return value is 0 if no line available, or length of line */ +dsc_private int +dsc_read_line(CDSC *dsc) +{ + char *p, *last; + dsc->line = NULL; + + if (dsc->eof) { + /* return all that remains, even if line incomplete */ + dsc->line = dsc->data + dsc->data_index; + dsc->line_length = dsc->data_length - dsc->data_index; + dsc->data_index = dsc->data_length; + return dsc->line_length; + } + + /* ignore embedded bytes */ + if (dsc->skip_bytes) { + int cnt = min(dsc->skip_bytes, + (int)(dsc->data_length - dsc->data_index)); + dsc->skip_bytes -= cnt; + dsc->data_index += cnt; + if (dsc->skip_bytes != 0) + return 0; + } + + do { + dsc->line = dsc->data + dsc->data_index; + last = dsc->data + dsc->data_length; + if (dsc->data_index == dsc->data_length) { + dsc->line_length = 0; + return 0; + } + if (dsc->eol) { + /* if previous line was complete, increment line count */ + dsc->line_count++; + if (dsc->skip_lines) + dsc->skip_lines--; + } + + /* skip over \n which followed \r */ + if (dsc->last_cr && dsc->line[0] == '\n') { + dsc->data_index++; + dsc->line++; + } + dsc->last_cr = FALSE; + + /* look for EOL */ + dsc->eol = FALSE; + for (p = dsc->line; p < last; p++) { + if (*p == '\r') { + p++; + if ((plast_cr = TRUE; /* we might need to skip \n */ + dsc->eol = TRUE; /* dsc->line is a complete line */ + break; + } + if (*p == '\n') { + p++; + dsc->eol = TRUE; /* dsc->line is a complete line */ + break; + } + if (*p == '\032') { /* MS-DOS Ctrl+Z */ + dsc->eol = TRUE; + } + } + if (dsc->eol == FALSE) { + /* we haven't got a complete line yet */ + if (dsc->data_length - dsc->data_index < sizeof(dsc->data)/2) { + /* buffer is less than half full, ask for some more */ + dsc->line_length = 0; + return 0; + } + } + dsc->data_index += dsc->line_length = (p - dsc->line); + } while (dsc->skip_lines && dsc->line_length); + + if (dsc->line_length == 0) + return 0; + + if ((dsc->line[0]=='%') && (dsc->line[1]=='%')) { + /* handle recursive %%BeginDocument */ + if ((dsc->skip_document) && dsc->line_length && + COMPARE(dsc->line, "%%EndDocument")) { + dsc->skip_document--; + } + + /* handle embedded lines or binary data */ + if (COMPARE(dsc->line, "%%BeginData:")) { + /* %%BeginData: [ [ ] ] + * ::= (Lines or physical bytes) + * ::= Hex | Binary | ASCII (Type of data) + * ::= Bytes | Lines (Read in bytes or lines) + */ + char begindata[MAXSTR+1]; + int cnt; + unsigned int num; + const char *numberof, *bytesorlines; + if ((num = dsc->line_length) >= sizeof(begindata)-1) + num = sizeof(begindata)-1; + + memcpy(begindata, dsc->line, num); + begindata[num] = '\0'; + numberof = strtok(begindata+12, " \r\n"); + strtok(NULL, " \r\n"); /* dump type */ + bytesorlines = strtok(NULL, " \r\n"); + if (bytesorlines == NULL) + bytesorlines = "Bytes"; + + if ( (numberof == NULL) || (bytesorlines == NULL) ) { + /* invalid usage of %%BeginData */ + /* ignore that we ever saw it */ + int rc = dsc_error(dsc, CDSC_MESSAGE_INCORRECT_USAGE, + dsc->line, dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + case CDSC_RESPONSE_CANCEL: + break; + case CDSC_RESPONSE_IGNORE_ALL: + return 0; + } + } + else { + cnt = atoi(numberof); + if (cnt) { + if (bytesorlines && (dsc_stricmp(bytesorlines, "Lines")==0)) { + /* skip cnt lines */ + if (dsc->skip_lines == 0) { + /* we are not already skipping lines */ + dsc->skip_lines = cnt+1; + } + } + else { + /* byte count doesn't includes \n or \r\n */ + /* or \r of %%BeginData: */ + /* skip cnt bytes */ + if (dsc->skip_bytes == 0) { + /* we are not already skipping lines */ + dsc->skip_bytes = cnt; + } + + } + } + } + } + else if (COMPARE(dsc->line, "%%BeginBinary:")) { + /* byte count doesn't includes \n or \r\n or \r of %%BeginBinary:*/ + unsigned long cnt = atoi(dsc->line + 14); + if (dsc->skip_bytes == 0) { + /* we are not already skipping lines */ + dsc->skip_bytes = cnt; + } + } + } + + if ((dsc->line[0]=='%') && (dsc->line[1]=='%') && + COMPARE(dsc->line, "%%BeginDocument:") ) { + /* Skip over embedded document, recursively */ + dsc->skip_document++; + } + + if (!dsc->long_line && (dsc->line_length > DSC_LINE_LENGTH)) { + dsc_error(dsc, CDSC_MESSAGE_LONG_LINE, dsc->line, dsc->line_length); + dsc->long_line = TRUE; + } + + return dsc->line_length; +} + + +/* Save last DSC line, for use with %%+ */ +dsc_private void +dsc_save_line(CDSC *dsc) +{ + int len = min((size_t) sizeof(dsc->last_line), (size_t) dsc->line_length); + memcpy(dsc->last_line, dsc->line, len); +} + +/* display unknown DSC line */ +dsc_private void +dsc_unknown(CDSC *dsc) +{ + if (dsc->debug_print_fn) { + char line[DSC_LINE_LENGTH]; + unsigned int length = min((unsigned)DSC_LINE_LENGTH-1, dsc->line_length); + sprintf(line, "Unknown in %s section at line %d:\n ", + dsc_scan_section_name[dsc->scan_section], dsc->line_count); + dsc_debug_print(dsc, line); + strncpy(line, dsc->line, length); + line[length] = '\0'; + dsc_debug_print(dsc, line); + } +} + + +dsc_private GSBOOL +dsc_is_section(char *line) +{ + if ( !((line[0]=='%') && (line[1]=='%')) ) + return FALSE; + if (IS_DSC(line, "%%BeginPreview")) + return TRUE; + if (IS_DSC(line, "%%BeginDefaults")) + return TRUE; + if (IS_DSC(line, "%%BeginProlog")) + return TRUE; + if (IS_DSC(line, "%%BeginSetup")) + return TRUE; + if (IS_DSC(line, "%%Page:")) + return TRUE; + if (IS_DSC(line, "%%Trailer")) + return TRUE; + if (IS_DSC(line, "%%EOF")) + return TRUE; + return FALSE; +} + + +dsc_private GSDWORD +dsc_get_dword(const unsigned char *buf) +{ + GSDWORD dw; + dw = (GSDWORD)buf[0]; + dw += ((GSDWORD)buf[1])<<8; + dw += ((GSDWORD)buf[2])<<16; + dw += ((GSDWORD)buf[3])<<24; + return dw; +} + +dsc_private GSWORD +dsc_get_word(const unsigned char *buf) +{ + GSWORD w; + w = (GSWORD)buf[0]; + w |= (GSWORD)(buf[1]<<8); + return w; +} + +dsc_private int +dsc_read_doseps(CDSC *dsc) +{ + unsigned char *line = (unsigned char *)dsc->line; + if ((dsc->doseps = (CDSCDOSEPS *)dsc_memalloc(dsc, sizeof(CDSCDOSEPS))) == NULL) + return CDSC_ERROR; /* no memory */ + + dsc->doseps->ps_begin = dsc_get_dword(line+4); + dsc->doseps->ps_length = dsc_get_dword(line+8); + dsc->doseps->wmf_begin = dsc_get_dword(line+12); + dsc->doseps->wmf_length = dsc_get_dword(line+16); + dsc->doseps->tiff_begin = dsc_get_dword(line+20); + dsc->doseps->tiff_length = dsc_get_dword(line+24); + dsc->doseps->checksum = dsc_get_word(line+28); + + dsc->doseps_end = dsc->doseps->ps_begin + dsc->doseps->ps_length; + + /* move data_index backwards to byte after doseps header */ + dsc->data_index -= dsc->line_length - 30; + /* we haven't read a line of PostScript code yet */ + dsc->line_count = 0; + /* skip from current position to start of PostScript section */ + dsc->skip_bytes = dsc->doseps->ps_begin - 30; + + if (dsc->doseps->tiff_begin) + dsc->preview = CDSC_TIFF; + if (dsc->doseps->wmf_begin) + dsc->preview = CDSC_WMF; + + return CDSC_OK; +} + + + +dsc_private int +dsc_parse_pages(CDSC *dsc) +{ + int ip, io; + unsigned int i; + char *p; + int n; + if ((dsc->page_pages != 0) && (dsc->scan_section == scan_comments)) { + int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, + dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + case CDSC_RESPONSE_CANCEL: + return CDSC_OK; /* ignore duplicate comments in header */ + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + if ((dsc->page_pages != 0) && (dsc->scan_section == scan_trailer)) { + int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line, + dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + case CDSC_RESPONSE_CANCEL: + break; /* use duplicate comments in header */ + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + + n = IS_DSC(dsc->line, "%%+") ? 3 : 8; + while (IS_WHITE(dsc->line[n])) + n++; + p = dsc->line + n; + if (COMPARE(p, "atend")) { + int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + /* assume (atend) */ + /* we should mark it as deferred */ + break; + case CDSC_RESPONSE_CANCEL: + /* ignore it */ + break; + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + else if (COMPARE(p, "(atend)")) { + /* do nothing */ + /* we should mark it as deferred */ + } + else { + ip = dsc_get_int(dsc->line+n, dsc->line_length-n, &i); + if (i) { + n+=i; + dsc->page_pages = ip; + io = dsc_get_int(dsc->line+n, dsc->line_length-n, &i); + if (i) { + /* DSC 2 uses extra integer to indicate page order */ + /* DSC 3 uses %%PageOrder: */ + if (dsc->page_order == CDSC_ORDER_UNKNOWN) + switch (io) { + case -1: + dsc->page_order = CDSC_DESCEND; + break; + case 0: + dsc->page_order = CDSC_SPECIAL; + break; + case 1: + dsc->page_order = CDSC_ASCEND; + break; + } + } + } + else { + int rc = dsc_error(dsc, CDSC_MESSAGE_INCORRECT_USAGE, dsc->line, + dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + case CDSC_RESPONSE_CANCEL: + /* ignore it */ + break; + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + } + return CDSC_OK; +} + +dsc_private int +dsc_parse_bounding_box(CDSC *dsc, CDSCBBOX** pbbox, int offset) +{ + unsigned int i, n; + int llx, lly, urx, ury; + float fllx, flly, furx, fury; + char *p; + /* Process first %%BoundingBox: in comments, and last in trailer */ + if ((*pbbox != NULL) && (dsc->scan_section == scan_comments)) { + int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, + dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + case CDSC_RESPONSE_CANCEL: + return CDSC_OK; /* ignore duplicate comments in header */ + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + if ((*pbbox != NULL) && (dsc->scan_section == scan_pages)) { + int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, + dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + case CDSC_RESPONSE_CANCEL: + return CDSC_OK; /* ignore duplicate comments in header */ + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + if ((*pbbox != NULL) && (dsc->scan_section == scan_trailer)) { + int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line, + dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + case CDSC_RESPONSE_CANCEL: + break; /* use duplicate comments in trailer */ + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + if (*pbbox != NULL) { + dsc_memfree(dsc, *pbbox); + *pbbox = NULL; + } + + /* should only process first %%BoundingBox: */ + + while (IS_WHITE(dsc->line[offset])) + offset++; + p = dsc->line + offset; + + if (COMPARE(p, "atend")) { + int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, + dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + /* assume (atend) */ + /* we should mark it as deferred */ + break; + case CDSC_RESPONSE_CANCEL: + /* ignore it */ + break; + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + else if (COMPARE(p, "(atend)")) { + /* do nothing */ + /* we should mark it as deferred */ + } + else { + /* llx = */ lly = urx = ury = 0; + n = offset; + llx = dsc_get_int(dsc->line+n, dsc->line_length-n, &i); + n += i; + if (i) + lly = dsc_get_int(dsc->line+n, dsc->line_length-n, &i); + n += i; + if (i) + urx = dsc_get_int(dsc->line+n, dsc->line_length-n, &i); + n += i; + if (i) + ury = dsc_get_int(dsc->line+n, dsc->line_length-n, &i); + if (i) { + *pbbox = (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX)); + if (*pbbox == NULL) + return CDSC_ERROR; /* no memory */ + (*pbbox)->llx = llx; + (*pbbox)->lly = lly; + (*pbbox)->urx = urx; + (*pbbox)->ury = ury; + } + else { + int rc = dsc_error(dsc, CDSC_MESSAGE_BBOX, dsc->line, + dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + /* fllx = */ flly = furx = fury = 0.0; + n = offset; + n += i; + fllx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); + n += i; + if (i) + flly = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); + n += i; + if (i) + furx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); + n += i; + if (i) + fury = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); + if (i) { + *pbbox = (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX)); + if (*pbbox == NULL) + return CDSC_ERROR; /* no memory */ + (*pbbox)->llx = (int)fllx; + (*pbbox)->lly = (int)flly; + (*pbbox)->urx = (int)(furx+0.999); + (*pbbox)->ury = (int)(fury+0.999); + } + return CDSC_OK; + case CDSC_RESPONSE_CANCEL: + return CDSC_OK; + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + } + return CDSC_OK; +} + +dsc_private int +dsc_parse_float_bounding_box(CDSC *dsc, CDSCFBBOX** pbbox, int offset) +{ + unsigned int i, n; + float fllx, flly, furx, fury; + char *p; + /* Process first %%HiResBoundingBox: or %%CropBox: in comments, + * and last in trailer. + */ + if ((*pbbox != NULL) && (dsc->scan_section == scan_comments)) { + int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, + dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + case CDSC_RESPONSE_CANCEL: + return CDSC_OK; /* ignore duplicate comments in header */ + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + if ((*pbbox != NULL) && (dsc->scan_section == scan_pages)) { + int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, + dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + case CDSC_RESPONSE_CANCEL: + return CDSC_OK; /* ignore duplicate comments in header */ + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + if ((*pbbox != NULL) && (dsc->scan_section == scan_trailer)) { + int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line, + dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + case CDSC_RESPONSE_CANCEL: + break; /* use duplicate comments in trailer */ + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + if (*pbbox != NULL) { + dsc_memfree(dsc, *pbbox); + *pbbox = NULL; + } + + /* should only process first %%BoundingBox: */ + + while (IS_WHITE(dsc->line[offset])) + offset++; + p = dsc->line + offset; + + if (COMPARE(p, "atend")) { + int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, + dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + /* assume (atend) */ + /* we should mark it as deferred */ + break; + case CDSC_RESPONSE_CANCEL: + /* ignore it */ + break; + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + else if (COMPARE(p, "(atend)")) { + /* do nothing */ + /* we should mark it as deferred */ + } + else { + /* fllx = */ flly = furx = fury = 0.0; + n = offset; + fllx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); + n += i; + if (i) + flly = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); + n += i; + if (i) + furx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); + n += i; + if (i) + fury = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); + if (i) { + *pbbox = (CDSCFBBOX *)dsc_memalloc(dsc, sizeof(CDSCFBBOX)); + if (*pbbox == NULL) + return CDSC_ERROR; /* no memory */ + (*pbbox)->fllx = fllx; + (*pbbox)->flly = flly; + (*pbbox)->furx = furx; + (*pbbox)->fury = fury; + } + } + return CDSC_OK; +} + +dsc_private int +dsc_parse_orientation(CDSC *dsc, unsigned int *porientation, int offset) +{ + char *p; + if ((dsc->page_orientation != CDSC_ORIENT_UNKNOWN) && + (dsc->scan_section == scan_comments)) { + int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, + dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + case CDSC_RESPONSE_CANCEL: + return CDSC_OK; /* ignore duplicate comments in header */ + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + if ((dsc->page_orientation != CDSC_ORIENT_UNKNOWN) && + (dsc->scan_section == scan_trailer)) { + int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line, + dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + case CDSC_RESPONSE_CANCEL: + break; /* use duplicate comments in header; */ + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + p = dsc->line + offset; + while (IS_WHITE(*p)) + p++; + if (COMPARE(p, "atend")) { + int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + /* assume (atend) */ + /* we should mark it as deferred */ + break; + case CDSC_RESPONSE_CANCEL: + /* ignore it */ + break; + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + else if (COMPARE(p, "(atend)")) { + /* do nothing */ + /* we should mark it as deferred */ + } + else if (COMPARE(p, "Portrait")) { + *porientation = CDSC_PORTRAIT; + } + else if (COMPARE(p, "Landscape")) { + *porientation = CDSC_LANDSCAPE; + } + else { + dsc_unknown(dsc); + } + return CDSC_OK; +} + +dsc_private int +dsc_parse_order(CDSC *dsc) +{ + char *p; + if ((dsc->page_order != CDSC_ORDER_UNKNOWN) && + (dsc->scan_section == scan_comments)) { + int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, + dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + case CDSC_RESPONSE_CANCEL: + return CDSC_OK; /* ignore duplicate comments in header */ + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + if ((dsc->page_order != CDSC_ORDER_UNKNOWN) && + (dsc->scan_section == scan_trailer)) { + int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line, + dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + case CDSC_RESPONSE_CANCEL: + break; /* use duplicate comments in trailer */ + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + + p = dsc->line + (IS_DSC(dsc->line, "%%+") ? 3 : 13); + while (IS_WHITE(*p)) + p++; + if (COMPARE(p, "atend")) { + int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, + dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + /* assume (atend) */ + /* we should mark it as deferred */ + break; + case CDSC_RESPONSE_CANCEL: + /* ignore it */ + break; + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + else if (COMPARE(p, "(atend)")) { + /* do nothing */ + /* we should mark it as deferred */ + } + else if (COMPARE(p, "Ascend")) { + dsc->page_order = CDSC_ASCEND; + } + else if (COMPARE(p, "Descend")) { + dsc->page_order = CDSC_DESCEND; + } + else if (COMPARE(p, "Special")) { + dsc->page_order = CDSC_SPECIAL; + } + else { + dsc_unknown(dsc); + } + return CDSC_OK; +} + + +dsc_private int +dsc_parse_media(CDSC *dsc, const CDSCMEDIA **page_media) +{ + char media_name[MAXSTR]; + int n = IS_DSC(dsc->line, "%%+") ? 3 : 12; /* %%PageMedia: */ + unsigned int i; + + if (dsc_copy_string(media_name, sizeof(media_name)-1, + dsc->line+n, dsc->line_length-n, NULL)) { + for (i=0; imedia_count; i++) { + if (dsc->media[i]->name && + (dsc_stricmp(media_name, dsc->media[i]->name) == 0)) { + *page_media = dsc->media[i]; + return CDSC_OK; + } + } + } + dsc_unknown(dsc); + + return CDSC_OK; +} + + +dsc_private int +dsc_parse_document_media(CDSC *dsc) +{ + unsigned int i, n; + CDSCMEDIA lmedia; + GSBOOL blank_line; + + if (IS_DSC(dsc->line, "%%DocumentMedia:")) + n = 16; + else if (IS_DSC(dsc->line, "%%+")) + n = 3; + else + return CDSC_ERROR; /* error */ + + /* check for blank remainder of line */ + blank_line = TRUE; + for (i=n; iline_length; i++) { + if (!IS_WHITE_OR_EOL(dsc->line[i])) { + blank_line = FALSE; + break; + } + } + + if (!blank_line) { + char name[MAXSTR]; + char colour[MAXSTR]; + char type[MAXSTR]; + lmedia.name = lmedia.colour = lmedia.type = (char *)NULL; + lmedia.width = lmedia.height = lmedia.weight = 0; + lmedia.mediabox = (CDSCBBOX *)NULL; + lmedia.name = dsc_copy_string(name, sizeof(name)-1, + dsc->line+n, dsc->line_length-n, &i); + n+=i; + if (i) + lmedia.width = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); + n+=i; + if (i) + lmedia.height = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); + n+=i; + if (i) + lmedia.weight = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); + n+=i; + if (i) + lmedia.colour = dsc_copy_string(colour, sizeof(colour)-1, + dsc->line+n, dsc->line_length-n, &i); + n+=i; + if (i) + lmedia.type = dsc_copy_string(type, sizeof(type)-1, + dsc->line+n, dsc->line_length-n, &i); + + if (i==0) + dsc_unknown(dsc); /* we didn't get all fields */ + else { + if (dsc_add_media(dsc, &lmedia)) + return CDSC_ERROR; /* out of memory */ + } + } + return CDSC_OK; +} + +/* viewing orientation is believed to be the first four elements of + * a CTM matrix + */ +dsc_private int +dsc_parse_viewing_orientation(CDSC *dsc, CDSCCTM **pctm) +{ + CDSCCTM ctm; + unsigned int i, n; + + if (*pctm != NULL) { + dsc_memfree(dsc, *pctm); + *pctm = NULL; + } + + n = IS_DSC(dsc->line, "%%+") ? 3 : 21; /* %%ViewingOrientation: */ + while (IS_WHITE(dsc->line[n])) + n++; + + /* ctm.xx = */ ctm.xy = ctm.yx = ctm.yy = 0.0; + ctm.xx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); + n += i; + if (i) + ctm.xy = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); + n += i; + if (i) + ctm.yx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); + n += i; + if (i) + ctm.yy = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); + if (i==0) { + dsc_unknown(dsc); /* we didn't get all fields */ + } + else { + *pctm = (CDSCCTM *)dsc_memalloc(dsc, sizeof(CDSCCTM)); + if (*pctm == NULL) + return CDSC_ERROR; /* no memory */ + **pctm = ctm; + } + return CDSC_OK; +} + + +/* This is called before dsc_read_line(), since we may + * need to skip a binary header which contains a new line + * character + */ +dsc_private int +dsc_scan_type(CDSC *dsc) +{ + unsigned char *p; + unsigned char *line = (unsigned char *)(dsc->data + dsc->data_index); + int length = dsc->data_length - dsc->data_index; + + /* Types that should be known: + * DSC + * EPSF + * PJL + any of above + * ^D + any of above + * DOS EPS + * PDF + * non-DSC + */ + + /* First process any non PostScript headers */ + /* At this stage we do not have a complete line */ + + if (length == 0) + return CDSC_NEEDMORE; + + if (dsc->skip_pjl) { + /* skip until first PostScript comment */ + while (length >= 2) { + while (length && !IS_EOL(line[0])) { + /* skip until EOL character */ + line++; + dsc->data_index++; + length--; + } + while ((length >= 2) && IS_EOL(line[0]) && IS_EOL(line[1])) { + /* skip until EOL followed by non-EOL */ + line++; + dsc->data_index++; + length--; + } + if (length < 2) + return CDSC_NEEDMORE; + + if (IS_EOL(line[0]) && line[1]=='%') { + line++; + dsc->data_index++; + length--; + dsc->skip_pjl = FALSE; + break; + } + else { + /* line++; */ + dsc->data_index++; + /* length--; */ + return CDSC_NEEDMORE; + } + } + if (dsc->skip_pjl) + return CDSC_NEEDMORE; + } + + if (length == 0) + return CDSC_NEEDMORE; + + if (line[0] == '\004') { + line++; + dsc->data_index++; + length--; + dsc->ctrld = TRUE; + } + + if (line[0] == '\033') { + /* possibly PJL */ + if (length < 9) + return CDSC_NEEDMORE; + if (COMPARE(line, "\033%-12345X")) { + dsc->skip_pjl = TRUE; /* skip until first PostScript comment */ + dsc->pjl = TRUE; + dsc->data_index += 9; + return dsc_scan_type(dsc); + } + } + + if ((line[0]==0xc5) && (length < 4)) + return CDSC_NEEDMORE; + if ((line[0]==0xc5) && (line[1]==0xd0) && + (line[2]==0xd3) && (line[3]==0xc6) ) { + /* id is "EPSF" with bit 7 set */ + /* read DOS EPS header, then ignore all bytes until the PS section */ + if (length < 30) + return CDSC_NEEDMORE; + dsc->line = (char *)line; + if (dsc_read_doseps(dsc)) + return CDSC_ERROR; + } + else { + if (length < 2) + return CDSC_NEEDMORE; + if ((line[0] == '%') && (line[1] == 'P')) { + if (length < 5) + return CDSC_NEEDMORE; + if (COMPARE(line, "%PDF-")) { + dsc->pdf = TRUE; + dsc->scan_section = scan_comments; + return CDSC_OK; + } + } + } + + /* Finally process PostScript headers */ + + if (dsc_read_line(dsc) <= 0) + return CDSC_NEEDMORE; + + dsc->dsc_version = dsc_add_line(dsc, dsc->line, dsc->line_length); + if (COMPARE(dsc->line, "%!PS-Adobe")) { + dsc->dsc = TRUE; + dsc->begincomments = DSC_START(dsc); + if (dsc->dsc_version == NULL) + return CDSC_ERROR; /* no memory */ + p = (unsigned char *)dsc->line + 14; + while (IS_WHITE(*p)) + p++; + if (COMPARE(p, "EPSF-")) + dsc->epsf = TRUE; + dsc->scan_section = scan_comments; + return CDSC_PSADOBE; + } + if (COMPARE(dsc->line, "%!")) { + dsc->scan_section = scan_comments; + return CDSC_NOTDSC; + } + + dsc->scan_section = scan_comments; + return CDSC_NOTDSC; /* unrecognised */ +} + + + +dsc_private int +dsc_scan_comments(CDSC *dsc) +{ + /* Comments section ends at */ + /* %%EndComments */ + /* another section */ + /* line that does not start with %% */ + /* Save a few important lines */ + + char *line = dsc->line; + GSBOOL continued = FALSE; + dsc->id = CDSC_OK; + if (IS_DSC(line, "%%EndComments")) { + dsc->id = CDSC_ENDCOMMENTS; + dsc->endcomments = DSC_END(dsc); + dsc->scan_section = scan_pre_preview; + return CDSC_OK; + } + else if (IS_DSC(line, "%%BeginComments")) { + /* ignore because we are in this section */ + dsc->id = CDSC_BEGINCOMMENTS; + } + else if (dsc_is_section(line)) { + dsc->endcomments = DSC_START(dsc); + dsc->scan_section = scan_pre_preview; + return CDSC_PROPAGATE; + } + else if (line[0] == '%' && IS_WHITE_OR_EOL(line[1])) { + dsc->endcomments = DSC_START(dsc); + dsc->scan_section = scan_pre_preview; + return CDSC_PROPAGATE; + } + else if (line[0] != '%') { + dsc->id = CDSC_OK; + dsc->endcomments = DSC_START(dsc); + dsc->scan_section = scan_pre_preview; + return CDSC_PROPAGATE; + } + else if (IS_DSC(line, "%%Begin")) { + dsc->endcomments = DSC_START(dsc); + dsc->scan_section = scan_pre_preview; + return CDSC_PROPAGATE; + } + + /* Handle continuation lines. + * To simply processing, we assume that contination lines + * will only occur if repeat parameters are allowed and that + * a complete set of these parameters appears on each line. + * This is more restrictive than the DSC specification, but + * is valid for the DSC comments understood by this parser + * for all documents that we have seen. + */ + if (IS_DSC(line, "%%+")) { + line = dsc->last_line; + continued = TRUE; + } + else + dsc_save_line(dsc); + + if (IS_DSC(line, "%%Pages:")) { + dsc->id = CDSC_PAGES; + if (dsc_parse_pages(dsc) != 0) + return CDSC_ERROR; + } + else if (IS_DSC(line, "%%Creator:")) { + dsc->id = CDSC_CREATOR; + dsc->dsc_creator = dsc_add_line(dsc, dsc->line+10, dsc->line_length-10); + if (dsc->dsc_creator==NULL) + return CDSC_ERROR; + } + else if (IS_DSC(line, "%%CreationDate:")) { + dsc->id = CDSC_CREATIONDATE; + dsc->dsc_date = dsc_add_line(dsc, dsc->line+15, dsc->line_length-15); + if (dsc->dsc_date==NULL) + return CDSC_ERROR; + } + else if (IS_DSC(line, "%%Title:")) { + dsc->id = CDSC_TITLE; + dsc->dsc_title = dsc_add_line(dsc, dsc->line+8, dsc->line_length-8); + if (dsc->dsc_title==NULL) + return CDSC_ERROR; + } + else if (IS_DSC(line, "%%For:")) { + dsc->id = CDSC_FOR; + dsc->dsc_for = dsc_add_line(dsc, dsc->line+6, dsc->line_length-6); + if (dsc->dsc_for==NULL) + return CDSC_ERROR; + } + else if (IS_DSC(line, "%%LanguageLevel:")) { + unsigned int n = continued ? 3 : 16; + unsigned int i; + int ll; + dsc->id = CDSC_LANGUAGELEVEL; + ll = dsc_get_int(dsc->line+n, dsc->line_length-n, &i); + if (i) { + if ( (ll==1) || (ll==2) || (ll==3) ) + dsc->language_level = ll; + else { + dsc_unknown(dsc); + } + } + else + dsc_unknown(dsc); + } + else if (IS_DSC(line, "%%BoundingBox:")) { + dsc->id = CDSC_BOUNDINGBOX; + if (dsc_parse_bounding_box(dsc, &(dsc->bbox), continued ? 3 : 14)) + return CDSC_ERROR; + } + else if (IS_DSC(line, "%%HiResBoundingBox:")) { + dsc->id = CDSC_HIRESBOUNDINGBOX; + if (dsc_parse_float_bounding_box(dsc, &(dsc->hires_bbox), + continued ? 3 : 19)) + return CDSC_ERROR; + } + else if (IS_DSC(line, "%%CropBox:")) { + dsc->id = CDSC_CROPBOX; + if (dsc_parse_float_bounding_box(dsc, &(dsc->crop_box), + continued ? 3 : 10)) + return CDSC_ERROR; + } + else if (IS_DSC(line, "%%Orientation:")) { + dsc->id = CDSC_ORIENTATION; + if (dsc_parse_orientation(dsc, &(dsc->page_orientation), + continued ? 3 : 14)) + return CDSC_ERROR; + } + else if (IS_DSC(line, "%%PageOrder:")) { + dsc->id = CDSC_PAGEORDER; + if (dsc_parse_order(dsc)) + return CDSC_ERROR; + } + else if (IS_DSC(line, "%%DocumentMedia:")) { + dsc->id = CDSC_DOCUMENTMEDIA; + if (dsc_parse_document_media(dsc)) + return CDSC_ERROR; + } + else if (IS_DSC(line, "%%DocumentPaperSizes:")) { + /* DSC 2.1 */ + unsigned int n = continued ? 3 : 21; + unsigned int count = 0; + unsigned int i = 1; + char name[MAXSTR]; + char *p; + dsc->id = CDSC_DOCUMENTPAPERSIZES; + while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) { + p = dsc_copy_string(name, sizeof(name)-1, + dsc->line+n, dsc->line_length-n, &i); + if (i && p) { + const CDSCMEDIA *m = dsc_known_media; + if (count >= dsc->media_count) { + /* set some default values */ + CDSCMEDIA lmedia; + lmedia.name = p; + lmedia.width = 595.0; + lmedia.height = 842.0; + lmedia.weight = 80.0; + lmedia.colour = NULL; + lmedia.type = NULL; + lmedia.mediabox = NULL; + if (dsc_add_media(dsc, &lmedia)) + return CDSC_ERROR; + } + else + dsc->media[count]->name = + dsc_alloc_string(dsc, p, strlen(p)); + /* find in list of known media */ + while (m && m->name) { + if (dsc_stricmp(p, m->name)==0) { + dsc->media[count]->width = m->width; + dsc->media[count]->height = m->height; + break; + } + m++; + } + } + n+=i; + count++; + } + } + else if (IS_DSC(line, "%%DocumentPaperForms:")) { + /* DSC 2.1 */ + unsigned int n = continued ? 3 : 21; + unsigned int count = 0; + unsigned int i = 1; + char type[MAXSTR]; + char *p; + dsc->id = CDSC_DOCUMENTPAPERFORMS; + while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) { + p = dsc_copy_string(type, sizeof(type)-1, + dsc->line+n, dsc->line_length-n, &i); + if (i && p) { + if (count >= dsc->media_count) { + /* set some default values */ + CDSCMEDIA lmedia; + lmedia.name = NULL; + lmedia.width = 595.0; + lmedia.height = 842.0; + lmedia.weight = 80.0; + lmedia.colour = NULL; + lmedia.type = p; + lmedia.mediabox = NULL; + if (dsc_add_media(dsc, &lmedia)) + return CDSC_ERROR; + } + else + dsc->media[count]->type = + dsc_alloc_string(dsc, p, strlen(p)); + } + n+=i; + count++; + } + } + else if (IS_DSC(line, "%%DocumentPaperColors:")) { + /* DSC 2.1 */ + unsigned int n = continued ? 3 : 22; + unsigned int count = 0; + unsigned int i = 1; + char colour[MAXSTR]; + char *p; + dsc->id = CDSC_DOCUMENTPAPERCOLORS; + while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) { + p = dsc_copy_string(colour, sizeof(colour)-1, + dsc->line+n, dsc->line_length-n, &i); + if (i && p) { + if (count >= dsc->media_count) { + /* set some default values */ + CDSCMEDIA lmedia; + lmedia.name = NULL; + lmedia.width = 595.0; + lmedia.height = 842.0; + lmedia.weight = 80.0; + lmedia.colour = p; + lmedia.type = NULL; + lmedia.mediabox = NULL; + if (dsc_add_media(dsc, &lmedia)) + return CDSC_ERROR; + } + else + dsc->media[count]->colour = + dsc_alloc_string(dsc, p, strlen(p)); + } + n+=i; + count++; + } + } + else if (IS_DSC(line, "%%DocumentPaperWeights:")) { + /* DSC 2.1 */ + unsigned int n = continued ? 3 : 23; + unsigned int count = 0; + unsigned int i = 1; + float w; + dsc->id = CDSC_DOCUMENTPAPERWEIGHTS; + while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) { + w = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); + if (i) { + if (count >= dsc->media_count) { + /* set some default values */ + CDSCMEDIA lmedia; + lmedia.name = NULL; + lmedia.width = 595.0; + lmedia.height = 842.0; + lmedia.weight = w; + lmedia.colour = NULL; + lmedia.type = NULL; + lmedia.mediabox = NULL; + if (dsc_add_media(dsc, &lmedia)) + return CDSC_ERROR; + } + else + dsc->media[count]->weight = w; + } + n+=i; + count++; + } + } + else if (IS_DSC(line, "%%DocumentData:")) { + unsigned int n = continued ? 3 : 15; + char *p = dsc->line + n; + while (IS_WHITE(*p)) + p++; + dsc->id = CDSC_DOCUMENTDATA; + if (COMPARE(p, "Clean7Bit")) + dsc->document_data = CDSC_CLEAN7BIT; + else if (COMPARE(p, "Clean8Bit")) + dsc->document_data = CDSC_CLEAN8BIT; + else if (COMPARE(p, "Binary")) + dsc->document_data = CDSC_BINARY; + else + dsc_unknown(dsc); + } + else if (IS_DSC(line, "%%Requirements:")) { + dsc->id = CDSC_REQUIREMENTS; + /* ignore */ + } + else if (IS_DSC(line, "%%DocumentNeededFonts:")) { + dsc->id = CDSC_DOCUMENTNEEDEDFONTS; + /* ignore */ + } + else if (IS_DSC(line, "%%DocumentSuppliedFonts:")) { + dsc->id = CDSC_DOCUMENTSUPPLIEDFONTS; + /* ignore */ + } + else if (dsc->line[0] == '%' && IS_WHITE_OR_EOL(dsc->line[1])) { + dsc->id = CDSC_OK; + /* ignore */ + } + else { + dsc->id = CDSC_UNKNOWNDSC; + dsc_unknown(dsc); + } + + dsc->endcomments = DSC_END(dsc); + return CDSC_OK; +} + + +dsc_private int +dsc_scan_preview(CDSC *dsc) +{ + /* Preview section ends at */ + /* %%EndPreview */ + /* another section */ + /* Preview section must start with %%BeginPreview */ + char *line = dsc->line; + dsc->id = CDSC_OK; + + if (dsc->scan_section == scan_pre_preview) { + if (IS_BLANK(line)) + return CDSC_OK; /* ignore blank lines before preview */ + else if (IS_DSC(line, "%%BeginPreview")) { + dsc->id = CDSC_BEGINPREVIEW; + dsc->beginpreview = DSC_START(dsc); + dsc->endpreview = DSC_END(dsc); + dsc->scan_section = scan_preview; + /* Don't mark the preview as EPSI if a DOS EPS header is present */ + if (dsc->preview == CDSC_NOPREVIEW) + dsc->preview = CDSC_EPSI; + return CDSC_OK; + } + else { + dsc->scan_section = scan_pre_defaults; + return CDSC_PROPAGATE; + } + } + + if (IS_DSC(line, "%%BeginPreview")) { + /* ignore because we are in this section */ + } + else if (dsc_is_section(line)) { + dsc->endpreview = DSC_START(dsc); + dsc->scan_section = scan_pre_defaults; + return CDSC_PROPAGATE; + } + else if (IS_DSC(line, "%%EndPreview")) { + dsc->id = CDSC_ENDPREVIEW; + dsc->endpreview = DSC_END(dsc); + dsc->scan_section = scan_pre_defaults; + return CDSC_OK; + } + else if (line[0] == '%' && line[1] != '%') { + /* Ordinary comments are OK */ + } + else { + dsc->id = CDSC_UNKNOWNDSC; + /* DSC comments should not occur in preview */ + dsc_unknown(dsc); + } + + dsc->endpreview = DSC_END(dsc); + return CDSC_OK; +} + +dsc_private int +dsc_scan_defaults(CDSC *dsc) +{ + /* Defaults section ends at */ + /* %%EndDefaults */ + /* another section */ + /* Defaults section must start with %%BeginDefaults */ + char *line = dsc->line; + dsc->id = CDSC_OK; + + if (dsc->scan_section == scan_pre_defaults) { + if (IS_BLANK(line)) + return CDSC_OK; /* ignore blank lines before defaults */ + else if (IS_DSC(line, "%%BeginDefaults")) { + dsc->id = CDSC_BEGINDEFAULTS; + dsc->begindefaults = DSC_START(dsc); + dsc->enddefaults = DSC_END(dsc); + dsc->scan_section = scan_defaults; + return CDSC_OK; + } + else { + dsc->scan_section = scan_pre_prolog; + return CDSC_PROPAGATE; + } + } + + if (NOT_DSC_LINE(line)) { + /* ignore */ + } + else if (IS_DSC(line, "%%BeginPreview")) { + /* ignore because we have already processed this section */ + } + else if (IS_DSC(line, "%%BeginDefaults")) { + /* ignore because we are in this section */ + } + else if (dsc_is_section(line)) { + dsc->enddefaults = DSC_START(dsc); + dsc->scan_section = scan_pre_prolog; + return CDSC_PROPAGATE; + } + else if (IS_DSC(line, "%%EndDefaults")) { + dsc->id = CDSC_ENDDEFAULTS; + dsc->enddefaults = DSC_END(dsc); + dsc->scan_section = scan_pre_prolog; + return CDSC_OK; + } + else if (IS_DSC(line, "%%PageMedia:")) { + dsc->id = CDSC_PAGEMEDIA; + dsc_parse_media(dsc, &dsc->page_media); + } + else if (IS_DSC(line, "%%PageOrientation:")) { + dsc->id = CDSC_PAGEORIENTATION; + /* This can override %%Orientation: */ + if (dsc_parse_orientation(dsc, &(dsc->page_orientation), 18)) + return CDSC_ERROR; + } + else if (IS_DSC(line, "%%PageBoundingBox:")) { + dsc->id = CDSC_PAGEBOUNDINGBOX; + if (dsc_parse_bounding_box(dsc, &(dsc->page_bbox), 18)) + return CDSC_ERROR; + } + else if (IS_DSC(line, "%%ViewingOrientation:")) { + dsc->id = CDSC_VIEWINGORIENTATION; + if (dsc_parse_viewing_orientation(dsc, &dsc->viewing_orientation)) + return CDSC_ERROR; + } + else { + dsc->id = CDSC_UNKNOWNDSC; + /* All other DSC comments are unknown, but not an error */ + dsc_unknown(dsc); + } + dsc->enddefaults = DSC_END(dsc); + return CDSC_OK; +} + +/* CDSC_RESPONSE_OK and CDSC_RESPONSE_CANCEL mean ignore the + * mismatch (default) */ +dsc_private int +dsc_check_match_prompt(CDSC *dsc, const char *str, int count) +{ + if (count != 0) { + char buf[MAXSTR+MAXSTR] = ""; + if (dsc->line_length < (unsigned int)(sizeof(buf)/2-1)) { + strncpy(buf, dsc->line, dsc->line_length); + buf[dsc->line_length] = '\0'; + } + sprintf(buf+strlen(buf), "\n%%%%Begin%.40s: / %%%%End%.40s\n", str, str); + return dsc_error(dsc, CDSC_MESSAGE_BEGIN_END, buf, strlen(buf)); + } + return CDSC_RESPONSE_CANCEL; +} + +dsc_private int +dsc_check_match_type(CDSC *dsc, const char *str, int count) +{ + if (dsc_check_match_prompt(dsc, str, count) == CDSC_RESPONSE_IGNORE_ALL) + return CDSC_NOTDSC; + return CDSC_OK; +} + +/* complain if Begin/End blocks didn't match */ +/* return non-zero if we should ignore all DSC */ +dsc_private int +dsc_check_match(CDSC *dsc) +{ + int rc = 0; + const char *font = "Font"; + const char *feature = "Feature"; + const char *resource = "Resource"; + const char *procset = "ProcSet"; + + if (!rc) + rc = dsc_check_match_type(dsc, font, dsc->begin_font_count); + if (!rc) + rc = dsc_check_match_type(dsc, feature, dsc->begin_feature_count); + if (!rc) + rc = dsc_check_match_type(dsc, resource, dsc->begin_resource_count); + if (!rc) + rc = dsc_check_match_type(dsc, procset, dsc->begin_procset_count); + + dsc->begin_font_count = 0; + dsc->begin_feature_count = 0; + dsc->begin_resource_count = 0; + dsc->begin_procset_count = 0; + return rc; +} + + +dsc_private int +dsc_scan_prolog(CDSC *dsc) +{ + /* Prolog section ends at */ + /* %%EndProlog */ + /* another section */ + /* Prolog section may start with %%BeginProlog or non-dsc line */ + char *line = dsc->line; + dsc->id = CDSC_OK; + + if (dsc->scan_section == scan_pre_prolog) { + if (dsc_is_section(line) && (!IS_DSC(line, "%%BeginProlog"))) { + dsc->scan_section = scan_pre_setup; + return CDSC_PROPAGATE; + } + dsc->id = CDSC_BEGINPROLOG; + dsc->beginprolog = DSC_START(dsc); + dsc->endprolog = DSC_END(dsc); + dsc->scan_section = scan_prolog; + if (IS_DSC(line, "%%BeginProlog")) + return CDSC_OK; + } + + if (NOT_DSC_LINE(line)) { + /* ignore */ + } + else if (IS_DSC(line, "%%BeginPreview")) { + /* ignore because we have already processed this section */ + } + else if (IS_DSC(line, "%%BeginDefaults")) { + /* ignore because we have already processed this section */ + } + else if (IS_DSC(line, "%%BeginProlog")) { + /* ignore because we are in this section */ + } + else if (dsc_is_section(line)) { + dsc->endprolog = DSC_START(dsc); + dsc->scan_section = scan_pre_setup; + if (dsc_check_match(dsc)) + return CDSC_NOTDSC; + return CDSC_PROPAGATE; + } + else if (IS_DSC(line, "%%EndProlog")) { + dsc->id = CDSC_ENDPROLOG; + dsc->endprolog = DSC_END(dsc); + dsc->scan_section = scan_pre_setup; + if (dsc_check_match(dsc)) + return CDSC_NOTDSC; + return CDSC_OK; + } + else if (IS_DSC(line, "%%BeginFont:")) { + dsc->id = CDSC_BEGINFONT; + /* ignore Begin/EndFont, apart form making sure */ + /* that they are matched. */ + dsc->begin_font_count++; + } + else if (IS_DSC(line, "%%EndFont")) { + dsc->id = CDSC_ENDFONT; + dsc->begin_font_count--; + } + else if (IS_DSC(line, "%%BeginFeature:")) { + dsc->id = CDSC_BEGINFEATURE; + /* ignore Begin/EndFeature, apart form making sure */ + /* that they are matched. */ + dsc->begin_feature_count++; + } + else if (IS_DSC(line, "%%EndFeature")) { + dsc->id = CDSC_ENDFEATURE; + dsc->begin_feature_count--; + } + else if (IS_DSC(line, "%%BeginResource:")) { + dsc->id = CDSC_BEGINRESOURCE; + /* ignore Begin/EndResource, apart form making sure */ + /* that they are matched. */ + dsc->begin_resource_count++; + } + else if (IS_DSC(line, "%%EndResource")) { + dsc->id = CDSC_ENDRESOURCE; + dsc->begin_resource_count--; + } + else if (IS_DSC(line, "%%BeginProcSet:")) { + dsc->id = CDSC_BEGINPROCSET; + /* ignore Begin/EndProcSet, apart form making sure */ + /* that they are matched. */ + dsc->begin_procset_count++; + } + else if (IS_DSC(line, "%%EndProcSet")) { + dsc->id = CDSC_ENDPROCSET; + dsc->begin_procset_count--; + } + else { + /* All other DSC comments are unknown, but not an error */ + dsc->id = CDSC_UNKNOWNDSC; + dsc_unknown(dsc); + } + + dsc->endprolog = DSC_END(dsc); + return CDSC_OK; +} + +dsc_private int +dsc_scan_setup(CDSC *dsc) +{ + /* Setup section ends at */ + /* %%EndSetup */ + /* another section */ + /* Setup section must start with %%BeginSetup */ + + char *line = dsc->line; + dsc->id = CDSC_OK; + + if (dsc->scan_section == scan_pre_setup) { + if (IS_BLANK(line)) + return CDSC_OK; /* ignore blank lines before setup */ + else if (IS_DSC(line, "%%BeginSetup")) { + dsc->id = CDSC_BEGINSETUP; + dsc->beginsetup = DSC_START(dsc); + dsc->endsetup = DSC_END(dsc); + dsc->scan_section = scan_setup; + return CDSC_OK; + } + else { + dsc->scan_section = scan_pre_pages; + return CDSC_PROPAGATE; + } + } + + if (NOT_DSC_LINE(line)) { + /* ignore */ + } + else if (IS_DSC(line, "%%BeginPreview")) { + /* ignore because we have already processed this section */ + } + else if (IS_DSC(line, "%%BeginDefaults")) { + /* ignore because we have already processed this section */ + } + else if (IS_DSC(line, "%%BeginProlog")) { + /* ignore because we have already processed this section */ + } + else if (IS_DSC(line, "%%BeginSetup")) { + /* ignore because we are in this section */ + } + else if (dsc_is_section(line)) { + dsc->endsetup = DSC_START(dsc); + dsc->scan_section = scan_pre_pages; + if (dsc_check_match(dsc)) + return CDSC_NOTDSC; + return CDSC_PROPAGATE; + } + else if (IS_DSC(line, "%%EndSetup")) { + dsc->id = CDSC_ENDSETUP; + dsc->endsetup = DSC_END(dsc); + dsc->scan_section = scan_pre_pages; + if (dsc_check_match(dsc)) + return CDSC_NOTDSC; + return CDSC_OK; + } + else if (IS_DSC(line, "%%BeginFeature:")) { + dsc->id = CDSC_BEGINFEATURE; + /* ignore Begin/EndFeature, apart form making sure */ + /* that they are matched. */ + dsc->begin_feature_count++; + } + else if (IS_DSC(line, "%%EndFeature")) { + dsc->id = CDSC_ENDFEATURE; + dsc->begin_feature_count--; + } + else if (IS_DSC(line, "%%Feature:")) { + dsc->id = CDSC_FEATURE; + /* ignore */ + } + else if (IS_DSC(line, "%%BeginResource:")) { + dsc->id = CDSC_BEGINRESOURCE; + /* ignore Begin/EndResource, apart form making sure */ + /* that they are matched. */ + dsc->begin_resource_count++; + } + else if (IS_DSC(line, "%%EndResource")) { + dsc->id = CDSC_ENDRESOURCE; + dsc->begin_resource_count--; + } + else if (IS_DSC(line, "%%PaperColor:")) { + dsc->id = CDSC_PAPERCOLOR; + /* ignore */ + } + else if (IS_DSC(line, "%%PaperForm:")) { + dsc->id = CDSC_PAPERFORM; + /* ignore */ + } + else if (IS_DSC(line, "%%PaperWeight:")) { + dsc->id = CDSC_PAPERWEIGHT; + /* ignore */ + } + else if (IS_DSC(line, "%%PaperSize:")) { + /* DSC 2.1 */ + GSBOOL found_media = FALSE; + int i; + int n = 12; + char buf[MAXSTR]; + buf[0] = '\0'; + dsc->id = CDSC_PAPERSIZE; + dsc_copy_string(buf, sizeof(buf)-1, dsc->line+n, dsc->line_length-n, + NULL); + for (i=0; i<(int)dsc->media_count; i++) { + if (dsc->media[i] && dsc->media[i]->name && + (dsc_stricmp(buf, dsc->media[i]->name)==0)) { + dsc->page_media = dsc->media[i]; + found_media = TRUE; + break; + } + } + if (!found_media) { + /* It didn't match %%DocumentPaperSizes: */ + /* Try our known media */ + const CDSCMEDIA *m = dsc_known_media; + while (m->name) { + if (dsc_stricmp(buf, m->name)==0) { + dsc->page_media = m; + break; + } + m++; + } + if (m->name == NULL) + dsc_unknown(dsc); + } + } + else { + /* All other DSC comments are unknown, but not an error */ + dsc->id = CDSC_UNKNOWNDSC; + dsc_unknown(dsc); + } + + dsc->endsetup = DSC_END(dsc); + return CDSC_OK; +} + +dsc_private int +dsc_scan_page(CDSC *dsc) +{ + /* Page section ends at */ + /* %%Page */ + /* %%Trailer */ + /* %%EOF */ + char *line = dsc->line; + dsc->id = CDSC_OK; + + if (dsc->scan_section == scan_pre_pages) { + if (IS_DSC(line, "%%Page:")) { + dsc->scan_section = scan_pages; + /* fall through */ + } + else { + /* %%Page: didn't follow %%EndSetup + * Keep reading until reach %%Page or %%Trailer + * and add it to previous section. + */ + unsigned long *last; + if (dsc->endsetup != 0) + last = &dsc->endsetup; + else if (dsc->endprolog != 0) + last = &dsc->endprolog; + else if (dsc->enddefaults != 0) + last = &dsc->enddefaults; + else if (dsc->endpreview != 0) + last = &dsc->endpreview; + else if (dsc->endcomments != 0) + last = &dsc->endcomments; + else + last = &dsc->begincomments; + *last = DSC_START(dsc); + if (IS_DSC(line, "%%Trailer") || IS_DSC(line, "%%EOF")) { + dsc->scan_section = scan_pre_trailer; + return CDSC_PROPAGATE; + } + return CDSC_OK; + } + } + + if (NOT_DSC_LINE(line)) { + /* ignore */ + } + else if (IS_DSC(line, "%%Page:")) { + dsc->id = CDSC_PAGE; + if (dsc->page_count) { + dsc->page[dsc->page_count-1].end = DSC_START(dsc); + if (dsc_check_match(dsc)) + return CDSC_NOTDSC; + } + + if (dsc_parse_page(dsc) != 0) + return CDSC_ERROR; + + return CDSC_OK; + } + else if (IS_DSC(line, "%%BeginPreview")) { + /* ignore because we have already processed this section */ + } + else if (IS_DSC(line, "%%BeginDefaults")) { + /* ignore because we have already processed this section */ + } + else if (IS_DSC(line, "%%BeginProlog")) { + /* ignore because we have already processed this section */ + } + else if (IS_DSC(line, "%%BeginSetup")) { + /* ignore because we have already processed this section */ + } + else if (dsc_is_section(line)) { + if (IS_DSC(line, "%%Trailer")) { + dsc->page[dsc->page_count-1].end = DSC_START(dsc); + if (dsc->file_length) { + if ((!dsc->doseps && + ((DSC_END(dsc) + 32768) < dsc->file_length)) || + ((dsc->doseps) && + ((DSC_END(dsc) + 32768) < dsc->doseps_end))) { + int rc = dsc_error(dsc, CDSC_MESSAGE_EARLY_TRAILER, + dsc->line, dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + /* ignore early trailer */ + break; + case CDSC_RESPONSE_CANCEL: + /* this is the trailer */ + dsc->scan_section = scan_pre_trailer; + if (dsc_check_match(dsc)) + return CDSC_NOTDSC; + return CDSC_PROPAGATE; + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + else { + dsc->scan_section = scan_pre_trailer; + if (dsc_check_match(dsc)) + return CDSC_NOTDSC; + return CDSC_PROPAGATE; + } + } + else { + dsc->scan_section = scan_pre_trailer; + if (dsc_check_match(dsc)) + return CDSC_NOTDSC; + return CDSC_PROPAGATE; + } + } + else if (IS_DSC(line, "%%EOF")) { + dsc->page[dsc->page_count-1].end = DSC_START(dsc); + if (dsc->file_length) { + if ((DSC_END(dsc)+100 < dsc->file_length) || + (dsc->doseps && (DSC_END(dsc) + 100 < dsc->doseps_end))) { + int rc = dsc_error(dsc, CDSC_MESSAGE_EARLY_EOF, + dsc->line, dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + /* %%EOF is wrong, ignore it */ + break; + case CDSC_RESPONSE_CANCEL: + /* %%EOF is correct */ + dsc->scan_section = scan_eof; + dsc->eof = TRUE; + if (dsc_check_match(dsc)) + return CDSC_NOTDSC; + return CDSC_PROPAGATE; + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + } + else { + /* ignore it */ + if (dsc_check_match(dsc)) + return CDSC_NOTDSC; + return CDSC_OK; + } + } + else { + /* Section comment, probably from a badly */ + /* encapsulated EPS file. */ + int rc = dsc_error(dsc, CDSC_MESSAGE_BAD_SECTION, + dsc->line, dsc->line_length); + if (rc == CDSC_RESPONSE_IGNORE_ALL) + return CDSC_NOTDSC; + } + } + else if (IS_DSC(line, "%%PageTrailer")) { + dsc->id = CDSC_PAGETRAILER; + /* ignore */ + } + else if (IS_DSC(line, "%%BeginPageSetup")) { + dsc->id = CDSC_BEGINPAGESETUP; + /* ignore */ + } + else if (IS_DSC(line, "%%EndPageSetup")) { + dsc->id = CDSC_ENDPAGESETUP; + /* ignore */ + } + else if (IS_DSC(line, "%%PageMedia:")) { + dsc->id = CDSC_PAGEMEDIA; + dsc_parse_media(dsc, &(dsc->page[dsc->page_count-1].media)); + } + else if (IS_DSC(line, "%%PaperColor:")) { + dsc->id = CDSC_PAPERCOLOR; + /* ignore */ + } + else if (IS_DSC(line, "%%PaperForm:")) { + dsc->id = CDSC_PAPERFORM; + /* ignore */ + } + else if (IS_DSC(line, "%%PaperWeight:")) { + dsc->id = CDSC_PAPERWEIGHT; + /* ignore */ + } + else if (IS_DSC(line, "%%PaperSize:")) { + /* DSC 2.1 */ + GSBOOL found_media = FALSE; + int i; + int n = 12; + char buf[MAXSTR]; + buf[0] = '\0'; + dsc_copy_string(buf, sizeof(buf)-1, dsc->line+n, + dsc->line_length-n, NULL); + for (i=0; i<(int)dsc->media_count; i++) { + if (dsc->media[i] && dsc->media[i]->name && + (dsc_stricmp(buf, dsc->media[i]->name)==0)) { + dsc->page_media = dsc->media[i]; + found_media = TRUE; + break; + } + } + if (!found_media) { + /* It didn't match %%DocumentPaperSizes: */ + /* Try our known media */ + const CDSCMEDIA *m = dsc_known_media; + while (m->name) { + if (dsc_stricmp(buf, m->name)==0) { + dsc->page[dsc->page_count-1].media = m; + break; + } + m++; + } + if (m->name == NULL) + dsc_unknown(dsc); + } + } + else if (IS_DSC(line, "%%PageOrientation:")) { + dsc->id = CDSC_PAGEORIENTATION; + if (dsc_parse_orientation(dsc, + &(dsc->page[dsc->page_count-1].orientation) ,18)) + return CDSC_NOTDSC; + } + else if (IS_DSC(line, "%%PageBoundingBox:")) { + dsc->id = CDSC_PAGEBOUNDINGBOX; + if (dsc_parse_bounding_box(dsc, &dsc->page[dsc->page_count-1].bbox, 18)) + return CDSC_NOTDSC; + } + else if (IS_DSC(line, "%%ViewingOrientation:")) { + dsc->id = CDSC_VIEWINGORIENTATION; + if (dsc_parse_viewing_orientation(dsc, + &dsc->page[dsc->page_count-1].viewing_orientation)) + return CDSC_ERROR; + } + else if (IS_DSC(line, "%%BeginFont:")) { + dsc->id = CDSC_BEGINFONT; + /* ignore Begin/EndFont, apart form making sure */ + /* that they are matched. */ + dsc->begin_font_count++; + } + else if (IS_DSC(line, "%%EndFont")) { + dsc->id = CDSC_BEGINFONT; + dsc->begin_font_count--; + } + else if (IS_DSC(line, "%%BeginFeature:")) { + dsc->id = CDSC_BEGINFEATURE; + /* ignore Begin/EndFeature, apart form making sure */ + /* that they are matched. */ + dsc->begin_feature_count++; + } + else if (IS_DSC(line, "%%EndFeature")) { + dsc->id = CDSC_ENDFEATURE; + dsc->begin_feature_count--; + } + else if (IS_DSC(line, "%%BeginResource:")) { + dsc->id = CDSC_BEGINRESOURCE; + /* ignore Begin/EndResource, apart form making sure */ + /* that they are matched. */ + dsc->begin_resource_count++; + } + else if (IS_DSC(line, "%%EndResource")) { + dsc->id = CDSC_ENDRESOURCE; + dsc->begin_resource_count--; + } + else if (IS_DSC(line, "%%BeginProcSet:")) { + dsc->id = CDSC_BEGINPROCSET; + /* ignore Begin/EndProcSet, apart form making sure */ + /* that they are matched. */ + dsc->begin_procset_count++; + } + else if (IS_DSC(line, "%%EndProcSet")) { + dsc->id = CDSC_ENDPROCSET; + dsc->begin_procset_count--; + } + else if (IS_DSC(line, "%%IncludeFont:")) { + dsc->id = CDSC_INCLUDEFONT; + /* ignore */ + } + else { + /* All other DSC comments are unknown, but not an error */ + dsc->id = CDSC_UNKNOWNDSC; + dsc_unknown(dsc); + } + + dsc->page[dsc->page_count-1].end = DSC_END(dsc); + return CDSC_OK; +} + +/* Valid Trailer comments are + * %%Trailer + * %%EOF + * or the following deferred with (atend) + * %%BoundingBox: + * %%DocumentCustomColors: + * %%DocumentFiles: + * %%DocumentFonts: + * %%DocumentNeededFiles: + * %%DocumentNeededFonts: + * %%DocumentNeededProcSets: + * %%DocumentNeededResources: + * %%DocumentProcSets: + * %%DocumentProcessColors: + * %%DocumentSuppliedFiles: + * %%DocumentSuppliedFonts: + * %%DocumentSuppliedProcSets: + * %%DocumentSuppliedResources: + * %%Orientation: + * %%Pages: + * %%PageOrder: + * + * Our supported subset is + * %%Trailer + * %%EOF + * %%BoundingBox: + * %%Orientation: + * %%Pages: + * %%PageOrder: + * In addition to these, we support + * %%DocumentMedia: + * + * A %%PageTrailer can have the following: + * %%PageBoundingBox: + * %%PageCustomColors: + * %%PageFiles: + * %%PageFonts: + * %%PageOrientation: + * %%PageProcessColors: + * %%PageResources: + */ + +dsc_private int +dsc_scan_trailer(CDSC *dsc) +{ + /* Trailer section start at */ + /* %%Trailer */ + /* and ends at */ + /* %%EOF */ + char *line = dsc->line; + GSBOOL continued = FALSE; + dsc->id = CDSC_OK; + + if (dsc->scan_section == scan_pre_trailer) { + if (IS_DSC(line, "%%Trailer")) { + dsc->id = CDSC_TRAILER; + dsc->begintrailer = DSC_START(dsc); + dsc->endtrailer = DSC_END(dsc); + dsc->scan_section = scan_trailer; + return CDSC_OK; + } + else if (IS_DSC(line, "%%EOF")) { + dsc->id = CDSC_EOF; + dsc->begintrailer = DSC_START(dsc); + dsc->endtrailer = DSC_END(dsc); + dsc->scan_section = scan_trailer; + /* Continue, in case we found %%EOF in an embedded document */ + return CDSC_OK; + } + else { + /* %%Page: didn't follow %%EndSetup + * Keep reading until reach %%Page or %%Trailer + * and add it to setup section + */ + /* append to previous section */ + if (dsc->beginsetup) + dsc->endsetup = DSC_END(dsc); + else if (dsc->beginprolog) + dsc->endprolog = DSC_END(dsc); + else { + /* horribly confused */ + } + return CDSC_OK; + } + } + + /* Handle continuation lines. + * See comment above about our restrictive processing of + * continuation lines + */ + if (IS_DSC(line, "%%+")) { + line = dsc->last_line; + continued = TRUE; + } + else + dsc_save_line(dsc); + + if (NOT_DSC_LINE(line)) { + /* ignore */ + } + else if (IS_DSC(dsc->line, "%%EOF")) { + /* Keep scanning, in case we have a false trailer */ + dsc->id = CDSC_EOF; + } + else if (IS_DSC(dsc->line, "%%Trailer")) { + /* Cope with no pages with code after setup and before trailer. */ + /* Last trailer is the correct one. */ + dsc->id = CDSC_TRAILER; + dsc->begintrailer = DSC_START(dsc); + } + else if (IS_DSC(line, "%%Pages:")) { + dsc->id = CDSC_PAGES; + if (dsc_parse_pages(dsc) != 0) + return CDSC_ERROR; + } + else if (IS_DSC(line, "%%BoundingBox:")) { + dsc->id = CDSC_BOUNDINGBOX; + if (dsc_parse_bounding_box(dsc, &(dsc->bbox), continued ? 3 : 14)) + return CDSC_ERROR; + } + else if (IS_DSC(line, "%%HiResBoundingBox:")) { + dsc->id = CDSC_HIRESBOUNDINGBOX; + if (dsc_parse_float_bounding_box(dsc, &(dsc->hires_bbox), + continued ? 3 : 19)) + return CDSC_ERROR; + } + else if (IS_DSC(line, "%%CropBox:")) { + dsc->id = CDSC_CROPBOX; + if (dsc_parse_float_bounding_box(dsc, &(dsc->crop_box), + continued ? 3 : 10)) + return CDSC_ERROR; + } + else if (IS_DSC(line, "%%Orientation:")) { + dsc->id = CDSC_ORIENTATION; + if (dsc_parse_orientation(dsc, &(dsc->page_orientation), continued ? 3 : 14)) + return CDSC_ERROR; + } + else if (IS_DSC(line, "%%PageOrder:")) { + dsc->id = CDSC_PAGEORDER; + if (dsc_parse_order(dsc)) + return CDSC_ERROR; + } + else if (IS_DSC(line, "%%DocumentMedia:")) { + dsc->id = CDSC_DOCUMENTMEDIA; + if (dsc_parse_document_media(dsc)) + return CDSC_ERROR; + } + else if (IS_DSC(dsc->line, "%%Page:")) { + /* This should not occur in the trailer, but we might see + * this if a document has been incorrectly embedded. + */ + int rc = dsc_error(dsc, CDSC_MESSAGE_PAGE_IN_TRAILER, + dsc->line, dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + /* Assume that we are really in the previous */ + /* page, not the trailer */ + dsc->scan_section = scan_pre_pages; + if (dsc->page_count) + dsc->page[dsc->page_count-1].end = DSC_START(dsc); + return CDSC_PROPAGATE; /* try again */ + case CDSC_RESPONSE_CANCEL: + /* ignore pages in trailer */ + break; + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + else if (IS_DSC(line, "%%DocumentNeededFonts:")) { + dsc->id = CDSC_DOCUMENTNEEDEDFONTS; + /* ignore */ + } + else if (IS_DSC(line, "%%DocumentSuppliedFonts:")) { + dsc->id = CDSC_DOCUMENTSUPPLIEDFONTS; + /* ignore */ + } + else { + /* All other DSC comments are unknown, but not an error */ + dsc->id = CDSC_UNKNOWNDSC; + dsc_unknown(dsc); + } + + dsc->endtrailer = DSC_END(dsc); + return CDSC_OK; +} + + +dsc_private char * +dsc_alloc_string(CDSC *dsc, const char *str, int len) +{ + char *p; + if (dsc->string_head == NULL) { + dsc->string_head = (CDSCSTRING *)dsc_memalloc(dsc, sizeof(CDSCSTRING)); + if (dsc->string_head == NULL) + return NULL; /* no memory */ + dsc->string = dsc->string_head; + dsc->string->next = NULL; + dsc->string->data = (char *)dsc_memalloc(dsc, CDSC_STRING_CHUNK); + if (dsc->string->data == NULL) { + dsc_reset(dsc); + return NULL; /* no memory */ + } + dsc->string->index = 0; + dsc->string->length = CDSC_STRING_CHUNK; + } + if ( dsc->string->index + len + 1 > dsc->string->length) { + /* allocate another string block */ + CDSCSTRING *newstring = (CDSCSTRING *)dsc_memalloc(dsc, sizeof(CDSCSTRING)); + if (newstring == NULL) { + dsc_debug_print(dsc, "Out of memory\n"); + return NULL; + } + newstring->next = NULL; + newstring->length = 0; + newstring->index = 0; + newstring->data = (char *)dsc_memalloc(dsc, CDSC_STRING_CHUNK); + if (newstring->data == NULL) { + dsc_memfree(dsc, newstring); + dsc_debug_print(dsc, "Out of memory\n"); + return NULL; /* no memory */ + } + newstring->length = CDSC_STRING_CHUNK; + dsc->string->next = newstring; + dsc->string = newstring; + } + if ( dsc->string->index + len + 1 > dsc->string->length) + return NULL; /* failed */ + p = dsc->string->data + dsc->string->index; + memcpy(p, str, len); + *(p+len) = '\0'; + dsc->string->index += len + 1; + return p; +} + +/* store line, ignoring leading spaces */ +dsc_private char * +dsc_add_line(CDSC *dsc, const char *line, unsigned int len) +{ + char *newline; + unsigned int i; + while (len && (IS_WHITE(*line))) { + len--; + line++; + } + newline = dsc_alloc_string(dsc, line, len); + if (newline == NULL) + return NULL; + + for (i=0; i slen) + len = slen-1; + while ( (i= '0') && (ch <= '9')) { + /* octal coded character */ + int j = 3; + ch = 0; + while (j && (i < len) && line[i]>='0' && line[i]<='7') { + ch = (unsigned char)((ch<<3) + (line[i]-'0')); + i++; + j--; + } + str[newlength] = ch; + } + else if (ch == '(') { + str[newlength] = ch; + i++; + } + else if (ch == ')') { + str[newlength] = ch; + i++; + } + else if (ch == 'b') { + str[newlength] = '\b'; + i++; + } + else if (ch == 'f') { + str[newlength] = '\b'; + i++; + } + else if (ch == 'n') { + str[newlength] = '\n'; + i++; + } + else if (ch == 'r') { + str[newlength] = '\r'; + i++; + } + else if (ch == 't') { + str[newlength] = '\t'; + i++; + } + else if (ch == '\\') { + str[newlength] = '\\'; + i++; + } + } + newlength++; + } + str[newlength] = '\0'; + if (offset != (unsigned int *)NULL) + *offset = i; + return str; +} + +dsc_private int +dsc_get_int(const char *line, unsigned int len, unsigned int *offset) +{ + char newline[MAXSTR]; + int newlength = 0; + unsigned int i = 0; + unsigned char ch; + + len = min((size_t) len, (size_t) sizeof(newline)-1); + while ((iline + 7; + pl = dsc_copy_string(page_label, sizeof(page_label)-1, p, dsc->line_length-7, &i); + if (pl == NULL) + return CDSC_ERROR; + p += i; + page_ordinal = atoi(p); + + if ( (page_ordinal == 0) || (strlen(page_label) == 0) || + (dsc->page_count && + (page_ordinal != dsc->page[dsc->page_count-1].ordinal+1)) ) { + int rc = dsc_error(dsc, CDSC_MESSAGE_PAGE_ORDINAL, dsc->line, + dsc->line_length); + switch (rc) { + case CDSC_RESPONSE_OK: + /* ignore this page */ + return CDSC_OK; + case CDSC_RESPONSE_CANCEL: + /* accept the page */ + break; + case CDSC_RESPONSE_IGNORE_ALL: + return CDSC_NOTDSC; + } + } + + page_number = dsc->page_count; + dsc_add_page(dsc, page_ordinal, page_label); + dsc->page[page_number].begin = DSC_START(dsc); + dsc->page[page_number].end = DSC_START(dsc); + + if (dsc->page[page_number].label == NULL) + return CDSC_ERROR; /* no memory */ + + return CDSC_OK; +} + + + +/* DSC error reporting */ + +void +dsc_debug_print(CDSC *dsc, const char *str) +{ + if (dsc->debug_print_fn) + dsc->debug_print_fn(dsc->caller_data, str); +} + + +/* Display a message about a problem with the DSC comments. + * + * explanation = an index to to a multiline explanation in dsc_message[] + * line = pointer to the offending DSC line (if any) + * return code = + * CDSC_RESPONSE_OK DSC was wrong, make a guess about what + * was really meant. + * CDSC_RESPONSE_CANCEL Assume DSC was correct, ignore if it + * is misplaced. + * CDSC_RESPONSE_IGNORE_ALL Ignore all DSC. + */ +/* Silent operation. Don't display errors. */ +dsc_private int +dsc_error(CDSC *dsc, unsigned int explanation, + char *line, unsigned int line_len) +{ + /* if error function provided, use it */ + if (dsc->dsc_error_fn) + return dsc->dsc_error_fn(dsc->caller_data, dsc, + explanation, line, line_len); + + /* treat DSC as being correct */ + return CDSC_RESPONSE_CANCEL; +} + + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/dscparse.h b/kghostview/dscparse.h new file mode 100644 index 00000000..10d2746c --- /dev/null +++ b/kghostview/dscparse.h @@ -0,0 +1,473 @@ +/* Copyright (C) 2000-2001, Ghostgum Software Pty Ltd. All rights reserved. + + This file is part of GSview. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility + to anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer + to the GNU General Public Licence for full details. + + Everyone is granted permission to copy, modify and redistribute this + file, but only under the conditions described in the GNU General + Public Licence. A copy of this license is supposed to have been given + to you along with this file so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. +*/ + +/* $Id$ */ + +/* dscparse.h */ +/* Interface for the DSC parser. */ + +#ifndef _DSCPARSE_H_ +#define _DSCPARSE_H_ + +/* Some local types that may need modification */ +typedef bool GSBOOL; +typedef unsigned long GSDWORD; /* must be at least 32 bits */ +typedef unsigned int GSWORD; /* must be at least 16 bits */ + +#ifndef FALSE +# define FALSE ((GSBOOL)0) +# define TRUE ((GSBOOL)(!FALSE)) +#endif + +#ifndef dsc_private +# ifdef private +# define dsc_private private +# else +# define dsc_private static +# endif +#endif + +/* macros to allow conversion of function declarations to K&R */ +#ifndef P0 +#define P0() void +#define P1(t1) t1 +#define P2(t1,t2) t1,t2 +#define P3(t1,t2,t3) t1,t2,t3 +#define P4(t1,t2,t3,t4) t1,t2,t3,t4 +#define P5(t1,t2,t3,t4,t5) t1,t2,t3,t4,t5 +#define P6(t1,t2,t3,t4,t5,t6) t1,t2,t3,t4,t5,t6 +#endif + +/* maximum legal length of lines in a DSC compliant file */ +#define DSC_LINE_LENGTH 255 + +/* memory for strings is allocated in chunks of this length */ +#define CDSC_STRING_CHUNK 4096 + +/* page array is allocated in chunks of this many pages */ +#define CDSC_PAGE_CHUNK 128 + +/* buffer length for storing lines passed to dsc_scan_data() */ +/* must be at least 2 * DSC_LINE_LENGTH */ +/* We choose 8192 as twice the length passed to us by GSview */ +#define CDSC_DATA_LENGTH 8192 + +/* Return codes from dsc_scan_data() + * < 0 = error + * >=0 = OK + * + * -1 = error, usually insufficient memory. + * 0-9 = normal + * 10-99 = internal codes, should not be seen. + * 100-999 = identifier of last DSC comment processed. + */ + +typedef enum { + CDSC_ERROR = -1, /* Fatal error, usually insufficient memory */ + + CDSC_OK = 0, /* OK, no DSC comment found */ + CDSC_NOTDSC = 1, /* Not DSC, or DSC is being ignored */ + +/* Any section */ + CDSC_UNKNOWNDSC = 100, /* DSC comment not recognised */ + +/* Header section */ + CDSC_PSADOBE = 200, /* %!PS-Adobe- */ + CDSC_BEGINCOMMENTS = 201, /* %%BeginComments */ + CDSC_ENDCOMMENTS = 202, /* %%EndComments */ + CDSC_PAGES = 203, /* %%Pages: */ + CDSC_CREATOR = 204, /* %%Creator: */ + CDSC_CREATIONDATE = 205, /* %%CreationDate: */ + CDSC_TITLE = 206, /* %%Title: */ + CDSC_FOR = 207, /* %%For: */ + CDSC_LANGUAGELEVEL = 208, /* %%LanguageLevel: */ + CDSC_BOUNDINGBOX = 209, /* %%BoundingBox: */ + CDSC_ORIENTATION = 210, /* %%Orientation: */ + CDSC_PAGEORDER = 211, /* %%PageOrder: */ + CDSC_DOCUMENTMEDIA = 212, /* %%DocumentMedia: */ + CDSC_DOCUMENTPAPERSIZES = 213, /* %%DocumentPaperSizes: */ + CDSC_DOCUMENTPAPERFORMS = 214, /* %%DocumentPaperForms: */ + CDSC_DOCUMENTPAPERCOLORS = 215, /* %%DocumentPaperColors: */ + CDSC_DOCUMENTPAPERWEIGHTS = 216, /* %%DocumentPaperWeights: */ + CDSC_DOCUMENTDATA = 217, /* %%DocumentData: */ + CDSC_REQUIREMENTS = 218, /* IGNORED %%Requirements: */ + CDSC_DOCUMENTNEEDEDFONTS = 219, /* IGNORED %%DocumentNeededFonts: */ + CDSC_DOCUMENTSUPPLIEDFONTS = 220, /* IGNORED %%DocumentSuppliedFonts: */ + CDSC_HIRESBOUNDINGBOX = 221, /* %%HiResBoundingBox: */ + CDSC_CROPBOX = 222, /* %%CropBox: */ + +/* Preview section */ + CDSC_BEGINPREVIEW = 301, /* %%BeginPreview */ + CDSC_ENDPREVIEW = 302, /* %%EndPreview */ + +/* Defaults section */ + CDSC_BEGINDEFAULTS = 401, /* %%BeginDefaults */ + CDSC_ENDDEFAULTS = 402, /* %%EndDefaults */ +/* also %%PageMedia, %%PageOrientation, %%PageBoundingBox */ + +/* Prolog section */ + CDSC_BEGINPROLOG = 501, /* %%BeginProlog */ + CDSC_ENDPROLOG = 502, /* %%EndProlog */ + CDSC_BEGINFONT = 503, /* IGNORED %%BeginFont */ + CDSC_ENDFONT = 504, /* IGNORED %%EndFont */ + CDSC_BEGINFEATURE = 505, /* IGNORED %%BeginFeature */ + CDSC_ENDFEATURE = 506, /* IGNORED %%EndFeature */ + CDSC_BEGINRESOURCE = 507, /* IGNORED %%BeginResource */ + CDSC_ENDRESOURCE = 508, /* IGNORED %%EndResource */ + CDSC_BEGINPROCSET = 509, /* IGNORED %%BeginProcSet */ + CDSC_ENDPROCSET = 510, /* IGNORED %%EndProcSet */ + +/* Setup section */ + CDSC_BEGINSETUP = 601, /* %%BeginSetup */ + CDSC_ENDSETUP = 602, /* %%EndSetup */ + CDSC_FEATURE = 603, /* IGNORED %%Feature: */ + CDSC_PAPERCOLOR = 604, /* IGNORED %%PaperColor: */ + CDSC_PAPERFORM = 605, /* IGNORED %%PaperForm: */ + CDSC_PAPERWEIGHT = 606, /* IGNORED %%PaperWeight: */ + CDSC_PAPERSIZE = 607, /* %%PaperSize: */ +/* also %%Begin/EndFeature, %%Begin/EndResource */ + +/* Page section */ + CDSC_PAGE = 700, /* %%Page: */ + CDSC_PAGETRAILER = 701, /* IGNORED %%PageTrailer */ + CDSC_BEGINPAGESETUP = 702, /* IGNORED %%BeginPageSetup */ + CDSC_ENDPAGESETUP = 703, /* IGNORED %%EndPageSetup */ + CDSC_PAGEMEDIA = 704, /* %%PageMedia: */ +/* also %%PaperColor, %%PaperForm, %%PaperWeight, %%PaperSize */ + CDSC_PAGEORIENTATION = 705, /* %%PageOrientation: */ + CDSC_PAGEBOUNDINGBOX = 706, /* %%PageBoundingBox: */ +/* also %%Begin/EndFont, %%Begin/EndFeature */ +/* also %%Begin/EndResource, %%Begin/EndProcSet */ + CDSC_INCLUDEFONT = 707, /* IGNORED %%IncludeFont: */ + CDSC_VIEWINGORIENTATION = 708, /* %%ViewingOrientation: */ + +/* Trailer section */ + CDSC_TRAILER = 800, /* %%Trailer */ +/* also %%Pages, %%BoundingBox, %%Orientation, %%PageOrder, %%DocumentMedia */ +/* %%Page is recognised as an error */ +/* also %%DocumentNeededFonts, %%DocumentSuppliedFonts */ + +/* End of File */ + CDSC_EOF = 900 /* %%EOF */ +} CDSC_RETURN_CODE; + + +/* stored in dsc->preview */ +typedef enum { + CDSC_NOPREVIEW = 0, + CDSC_EPSI = 1, + CDSC_TIFF = 2, + CDSC_WMF = 3, + CDSC_PICT = 4 +} CDSC_PREVIEW_TYPE; + +/* stored in dsc->page_order */ +typedef enum { + CDSC_ORDER_UNKNOWN = 0, + CDSC_ASCEND = 1, + CDSC_DESCEND = 2, + CDSC_SPECIAL = 3 +} CDSC_PAGE_ORDER; + +/* stored in dsc->page_orientation and dsc->page[pagenum-1].orientation */ +typedef enum { + CDSC_ORIENT_UNKNOWN = 0, + CDSC_PORTRAIT = 1, + CDSC_LANDSCAPE = 2, + CDSC_UPSIDEDOWN = 3, + CDSC_SEASCAPE = 4 +} CDSC_ORIENTATION_ENUM; + +/* stored in dsc->document_data */ +typedef enum { + CDSC_DATA_UNKNOWN = 0, + CDSC_CLEAN7BIT = 1, + CDSC_CLEAN8BIT = 2, + CDSC_BINARY = 3 +} CDSC_DOCUMENT_DATA ; + +typedef struct CDSCBBOX_S { + int llx; + int lly; + int urx; + int ury; +} CDSCBBOX; + +typedef struct CDSCFBBOX_S { + float fllx; + float flly; + float furx; + float fury; +} CDSCFBBOX; + +typedef struct CDSCMEDIA_S { + const char *name; + float width; /* PostScript points */ + float height; + float weight; /* GSM */ + const char *colour; + const char *type; + CDSCBBOX *mediabox; /* Used by GSview for PDF MediaBox */ +} CDSCMEDIA; + +#define CDSC_KNOWN_MEDIA 46 +extern const CDSCMEDIA dsc_known_media[CDSC_KNOWN_MEDIA]; + +typedef struct CDSCCTM_S { /* used for %%ViewingOrientation */ + float xx; + float xy; + float yx; + float yy; + /* float ty; */ + /* float ty; */ +} CDSCCTM; + +typedef struct CDSCPAGE_S { + int ordinal; + const char *label; + unsigned long begin; + unsigned long end; + unsigned int orientation; + const CDSCMEDIA *media; + CDSCBBOX *bbox; /* PageBoundingBox, also used by GSview for PDF CropBox */ + CDSCCTM *viewing_orientation; +} CDSCPAGE; + +/* binary DOS EPS header */ +typedef struct CDSCDOSEPS_S { + GSDWORD ps_begin; + GSDWORD ps_length; + GSDWORD wmf_begin; + GSDWORD wmf_length; + GSDWORD tiff_begin; + GSDWORD tiff_length; + GSWORD checksum; +} CDSCDOSEPS; + +/* rather than allocated every string with malloc, we allocate + * chunks of 4k and place the (usually) short strings in these + * chunks. + */ +typedef struct CDSCSTRING_S CDSCSTRING; +struct CDSCSTRING_S { + unsigned int index; + unsigned int length; + char *data; + CDSCSTRING *next; +}; + + +/* DSC error reporting */ + +typedef enum { + CDSC_MESSAGE_BBOX = 0, + CDSC_MESSAGE_EARLY_TRAILER = 1, + CDSC_MESSAGE_EARLY_EOF = 2, + CDSC_MESSAGE_PAGE_IN_TRAILER = 3, + CDSC_MESSAGE_PAGE_ORDINAL = 4, + CDSC_MESSAGE_PAGES_WRONG = 5, + CDSC_MESSAGE_EPS_NO_BBOX = 6, + CDSC_MESSAGE_EPS_PAGES = 7, + CDSC_MESSAGE_NO_MEDIA = 8, + CDSC_MESSAGE_ATEND = 9, + CDSC_MESSAGE_DUP_COMMENT = 10, + CDSC_MESSAGE_DUP_TRAILER = 11, + CDSC_MESSAGE_BEGIN_END = 12, + CDSC_MESSAGE_BAD_SECTION = 13, + CDSC_MESSAGE_LONG_LINE = 14, + CDSC_MESSAGE_INCORRECT_USAGE = 15 +} CDSC_MESSAGE_ERROR; + +/* severity */ +typedef enum { + CDSC_ERROR_INFORM = 0, /* Not an error */ + CDSC_ERROR_WARN = 1, /* Not a DSC error itself, */ + CDSC_ERROR_ERROR = 2 /* DSC error */ +} CDSC_MESSAGE_SEVERITY; + +/* response */ +typedef enum { + CDSC_RESPONSE_OK = 0, + CDSC_RESPONSE_CANCEL = 1, + CDSC_RESPONSE_IGNORE_ALL = 2 +} CDSC_RESPONSE; + +extern const char * const dsc_message[]; + +typedef struct CDSC_S CDSC; +struct CDSC_S { + /* public data */ + GSBOOL dsc; /* TRUE if DSC comments found */ + GSBOOL ctrld; /* TRUE if has CTRLD at start of stream */ + GSBOOL pjl; /* TRUE if has HP PJL at start of stream */ + GSBOOL epsf; /* TRUE if EPSF */ + GSBOOL pdf; /* TRUE if Portable Document Format */ + unsigned int preview; /* enum CDSC_PREVIEW_TYPE */ + char *dsc_version; /* first line of file */ + unsigned int language_level; + unsigned int document_data; /* Clean7Bit, Clean8Bit, Binary */ + /* enum CDSC_DOCUMENT_DATA */ + /* DSC sections */ + unsigned long begincomments; + unsigned long endcomments; + unsigned long beginpreview; + unsigned long endpreview; + unsigned long begindefaults; + unsigned long enddefaults; + unsigned long beginprolog; + unsigned long endprolog; + unsigned long beginsetup; + unsigned long endsetup; + unsigned long begintrailer; + unsigned long endtrailer; + CDSCPAGE *page; + unsigned int page_count; /* number of %%Page: pages in document */ + unsigned int page_pages; /* number of pages in document from %%Pages: */ + unsigned int page_order; /* enum CDSC_PAGE_ORDER */ + unsigned int page_orientation; /* the default page orientation */ + /* enum CDSC_ORIENTATION */ + CDSCCTM *viewing_orientation; + unsigned int media_count; /* number of media items */ + CDSCMEDIA **media; /* the array of media */ + const CDSCMEDIA *page_media;/* the default page media */ + CDSCBBOX *bbox; /* the document bounding box */ + CDSCBBOX *page_bbox; /* the default page bounding box */ + CDSCDOSEPS *doseps; /* DOS binary header */ + char *dsc_title; + char *dsc_creator; + char *dsc_date; + char *dsc_for; + + unsigned int max_error; /* highest error number that will be reported */ + const int *severity; /* array of severity values, one per error */ + + + /* private data */ + void *caller_data; /* pointer to be provided when calling */ + /* error and debug callbacks */ + int id; /* last DSC comment found */ + int scan_section; /* section currently being scanned */ + /* enum CDSC_SECTION */ + + unsigned long doseps_end; /* ps_begin+ps_length, otherwise 0 */ + unsigned int page_chunk_length; /* number of pages allocated */ + unsigned long file_length; /* length of document */ + /* If provided we try to recognise %%Trailer and %%EOF */ + /* incorrectly embedded inside document. */ + /* Can be left set to default value of 0 */ + int skip_document; /* recursion level of %%BeginDocument: */ + int skip_bytes; /* #bytes to ignore from BeginData: */ + /* or DOSEPS preview section */ + int skip_lines; /* #lines to ignore from BeginData: */ + GSBOOL skip_pjl; /* TRUE if skip PJL until first PS comment */ + int begin_font_count; /* recursion level of %%BeginFont */ + int begin_feature_count; /* recursion level of %%BeginFeature */ + int begin_resource_count; /* recursion level of %%BeginResource */ + int begin_procset_count; /* recursion level of %%BeginProcSet */ + + /* buffer for input */ + char data[CDSC_DATA_LENGTH];/* start of buffer */ + unsigned int data_length; /* length of data in buffer */ + unsigned int data_index; /* offset to next char in buffer */ + unsigned long data_offset; /* offset from start of document */ + /* to byte in data[0] */ + GSBOOL eof; /* TRUE if there is no more data */ + + /* information about DSC line */ + char *line; /* pointer to last read DSC line */ + /* not null terminated */ + unsigned int line_length; /* number of characters in line */ + GSBOOL eol; /* TRUE if dsc_line contains EOL */ + GSBOOL last_cr; /* TRUE if last line ended in \r */ + /* check next time for \n */ + unsigned int line_count; /* line number */ + GSBOOL long_line; /* TRUE if found a line longer than 255 characters */ + char last_line[256]; /* previous DSC line, used for %%+ */ + + /* more efficient string storage (for short strings) than malloc */ + CDSCSTRING *string_head; /* linked list head */ + CDSCSTRING *string; /* current list item */ + + /* memory allocation routines */ + void *(*memalloc)(P2(size_t size, void *closure_data)); + void (*memfree)(P2(void *ptr, void *closure_data)); + void *mem_closure_data; + + /* function for printing debug messages */ + void (*debug_print_fn)(P2(void *caller_data, const char *str)); + + /* function for reporting errors in DSC comments */ + int (*dsc_error_fn)(P5(void *caller_data, CDSC *dsc, + unsigned int explanation, const char *line, unsigned int line_len)); + + /* public data */ + /* Added 2001-10-01 */ + CDSCFBBOX *hires_bbox; /* the hires document bounding box */ + CDSCFBBOX *crop_box; /* the size of the trimmed page */ +}; + + +/* Public functions */ + +/* Create and initialise DSC parser */ +CDSC *dsc_init(P1(void *caller_data)); + +CDSC *dsc_init_with_alloc(P4( + void *caller_data, + void *(*memalloc)(size_t size, void *closure_data), + void (*memfree)(void *ptr, void *closure_data), + void *closure_data)); + +/* Free the DSC parser */ +void dsc_free(P1(CDSC *dsc)); + +/* Tell DSC parser how long document will be, to allow ignoring + * of early %%Trailer and %%EOF. This is optional. + */ +void dsc_set_length(P2(CDSC *dsc, unsigned long len)); + +/* Process a buffer containing DSC comments and PostScript */ +int dsc_scan_data(P3(CDSC *dsc, const char *data, int len)); + +/* All data has been processed, fixup any DSC errors */ +int dsc_fixup(P1(CDSC *dsc)); + +/* Install error query function */ +void dsc_set_error_function(P2(CDSC *dsc, + int (*dsc_error_fn)(P5(void *caller_data, CDSC *dsc, + unsigned int explanation, const char *line, unsigned int line_len)))); + +/* Install print function for debug messages */ +void dsc_set_debug_function(P2(CDSC *dsc, + void (*debug_fn)(P2(void *caller_data, const char *str)))); + +/* Print a message to debug output, if provided */ +void dsc_debug_print(P2(CDSC *dsc, const char *str)); + +/* should be internal only functions, but made available to + * GSview for handling PDF + */ +int dsc_add_page(P3(CDSC *dsc, int ordinal, char *label)); +int dsc_add_media(P2(CDSC *dsc, CDSCMEDIA *media)); +int dsc_set_page_bbox(P6(CDSC *dsc, unsigned int page_number, + int llx, int lly, int urx, int ury)); + +#endif + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/dscparse_adapter.cpp b/kghostview/dscparse_adapter.cpp new file mode 100644 index 00000000..4db450bb --- /dev/null +++ b/kghostview/dscparse_adapter.cpp @@ -0,0 +1,420 @@ +/** + * Copyright (C) 2001 the KGhostView authors. See file AUTHORS. + * + * 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 "dscparse_adapter.h" + +using namespace std; + +/*-- KDSCBBOX implementation -----------------------------------------------*/ + +KDSCBBOX::KDSCBBOX() : + _llx( 0 ), _lly( 0 ), + _urx( 0 ), _ury( 0 ) +{} + +KDSCBBOX::KDSCBBOX( const KDSCBBOX& b ) : + _llx( b._llx ), _lly( b._lly ), + _urx( b._urx ), _ury( b._ury ) +{} + +KDSCBBOX::KDSCBBOX( int llx, int lly, int urx, int ury ) : + _llx( llx ), _lly( lly ), + _urx( urx ), _ury( ury ) +{} + +KDSCBBOX::KDSCBBOX( const CDSCBBOX& bbox ) : + _llx( bbox.llx ), _lly( bbox.lly ), + _urx( bbox.urx ), _ury( bbox.ury ) +{} + +KDSCBBOX& KDSCBBOX::operator = ( const KDSCBBOX& b ) +{ + _llx = b._llx; _lly = b._lly; _urx = b._urx; _ury = b._ury; + return *this; +} + +bool KDSCBBOX::operator == ( const KDSCBBOX& b ) +{ + return ( _llx == b._llx && _lly == b._lly + && _urx == b._urx && _ury == b._ury ); +} + +bool KDSCBBOX::operator != ( const KDSCBBOX& b ) +{ + return !( *this == b ); +} + +int KDSCBBOX::llx() const { return _llx; } +int KDSCBBOX::lly() const { return _lly; } +int KDSCBBOX::urx() const { return _urx; } +int KDSCBBOX::ury() const { return _ury; } + +int KDSCBBOX::width() const { return _urx - _llx; } +int KDSCBBOX::height() const { return _ury - _lly; } + +QSize KDSCBBOX::size() const { return QSize( width(), height() ); } + +ostream& operator << ( ostream& os, const KDSCBBOX& source ) +{ + os << "{ llx: "<< source.llx() << ", lly: " << source.lly() + << " urx: "<< source.urx() << ", ury: " << source.ury() << " }"; + return os; +} + +/*-- KDSCError implementation ----------------------------------------------*/ + +KDSCError::KDSCError( Type type, Severity severity, const QCString& line, + unsigned int lineNumber ) : + _type( type ), + _severity( severity ), + _line( line ), + _lineNumber( lineNumber ) +{} + +KDSCError::Type KDSCError::type() const +{ + return _type; +} + +KDSCError::Severity KDSCError::severity() const +{ + return _severity; +} + +QCString KDSCError::line() const +{ + return _line; +} + +unsigned int KDSCError::lineNumber() const +{ + return _lineNumber; +} + +/*-- KDSCOkErrorHandler implementation -------------------------------------*/ + +KDSCErrorHandler::Response KDSCOkErrorHandler::error( const KDSCError& err ) +{ + cout << "KDSC: error in line " << err.lineNumber() << endl; + cout << err.line() << endl; + return Ok; +} + +/*-- KDSC implementation ---------------------------------------------------*/ + +KDSC::KDSC() : + _errorHandler( 0 ), + _commentHandler( 0 ) +{ + _cdsc = dsc_init( this ); + Q_ASSERT( _cdsc != 0 ); + _scanHandler = new KDSCScanHandler( _cdsc ); +} + +KDSC::~KDSC() +{ + dsc_free( _cdsc ); + delete _scanHandler; +} + +QString KDSC::dsc_version() const +{ + return QString( _cdsc->dsc_version ); +} + +bool KDSC::dsc() const +{ + return ( _cdsc->dsc == TRUE ); +} + +bool KDSC::ctrld() const +{ + return ( _cdsc->ctrld == TRUE ); +} + +bool KDSC::pjl() const +{ + return ( _cdsc->pjl == TRUE ); +} + +bool KDSC::epsf() const +{ + return ( _cdsc->epsf == TRUE ); +} + +bool KDSC::pdf() const +{ + return ( _cdsc->pdf == TRUE ); +} + +unsigned int KDSC::preview() const +{ + return _cdsc->preview; +} + +unsigned int KDSC::language_level() const +{ + return _cdsc->language_level; +} + +unsigned int KDSC::document_data() const +{ + return _cdsc->document_data; +} + +unsigned long KDSC::begincomments() const +{ + return _cdsc->begincomments; +} + +unsigned long KDSC::endcomments() const +{ + return _cdsc->endcomments; +} + +unsigned long KDSC::beginpreview() const +{ + return _cdsc->beginpreview; +} + +unsigned long KDSC::endpreview() const +{ + return _cdsc->endpreview; +} + +unsigned long KDSC::begindefaults() const +{ + return _cdsc->begindefaults; +} + +unsigned long KDSC::enddefaults() const +{ + return _cdsc->enddefaults; +} + +unsigned long KDSC::beginprolog() const +{ + return _cdsc->beginprolog; +} + +unsigned long KDSC::endprolog() const +{ + return _cdsc->endprolog; +} + +unsigned long KDSC::beginsetup() const +{ + return _cdsc->beginsetup; +} + +unsigned long KDSC::endsetup() const +{ + return _cdsc->endsetup; +} + +unsigned long KDSC::begintrailer() const +{ + return _cdsc->begintrailer; +} + +unsigned long KDSC::endtrailer() const +{ + return _cdsc->endtrailer; +} + +CDSCPAGE* KDSC::page() const +{ + return _cdsc->page; +} + +unsigned int KDSC::page_count() const +{ + return _cdsc->page_count; +} + +unsigned int KDSC::page_pages() const +{ + return _cdsc->page_pages; +} + +unsigned int KDSC::page_order() const +{ + return _cdsc->page_order; +} + +unsigned int KDSC::page_orientation() const +{ + return _cdsc->page_orientation; +} + +CDSCCTM* KDSC::viewing_orientation() const +{ + return _cdsc->viewing_orientation; +} + +unsigned int KDSC::media_count() const +{ + return _cdsc->media_count; +} + +CDSCMEDIA** KDSC::media() const +{ + return _cdsc->media; +} + +const CDSCMEDIA* KDSC::page_media() const +{ + return _cdsc->page_media; +} + +auto_ptr KDSC::bbox() const +{ + if( _cdsc->bbox == 0 ) + return auto_ptr( 0 ); + else + return auto_ptr( new KDSCBBOX( *_cdsc->bbox ) ); +} + +auto_ptr KDSC::page_bbox() const +{ + if( _cdsc->page_bbox == 0 ) + return auto_ptr( 0 ); + else + return auto_ptr( new KDSCBBOX( *_cdsc->page_bbox ) ); +} + +QString KDSC::dsc_title() const +{ + return QString( _cdsc->dsc_title ); +} + +QString KDSC::dsc_creator() const +{ + return QString( _cdsc->dsc_creator ); +} + +QString KDSC::dsc_date() const +{ + return QString( _cdsc->dsc_date ); +} + +QString KDSC::dsc_for() const +{ + return QString( _cdsc->dsc_for ); +} + +bool KDSC::scanData( char* buffer, unsigned int count ) +{ + return _scanHandler->scanData( buffer, count ); +} + +int KDSC::fixup() +{ + return dsc_fixup( _cdsc ); +} + +KDSCErrorHandler* KDSC::errorHandler() const +{ + return _errorHandler; +} + +void KDSC::setErrorHandler( KDSCErrorHandler* errorHandler ) +{ + _errorHandler = errorHandler; + if( errorHandler == 0 ) + dsc_set_error_function( _cdsc, 0 ); + else + dsc_set_error_function( _cdsc, &errorFunction ); +} + +KDSCCommentHandler* KDSC::commentHandler() const +{ + return _commentHandler; +} + +void KDSC::setCommentHandler( KDSCCommentHandler* commentHandler ) +{ + if( _commentHandler != 0 && commentHandler == 0 ) + { + delete _scanHandler; + _scanHandler = new KDSCScanHandler( _cdsc ); + } + else if( _commentHandler == 0 && commentHandler != 0 ) + { + delete _scanHandler; + _scanHandler = new KDSCScanHandlerByLine( _cdsc, commentHandler ); + } + _commentHandler = commentHandler; +} + +bool KDSC::isStructured() const +{ + return epsf() ? ( page_count() > 1 ) : ( page_count() > 0 ); +} + +CDSC* KDSC::cdsc() const +{ + return _cdsc; +} + +int KDSC::errorFunction( void* caller_data, CDSC* dsc, + unsigned int explanation, const char* line, unsigned int line_len ) +{ + KDSCError error( + static_cast< KDSCError::Type >( explanation ), + static_cast< KDSCError::Severity >( dsc->severity[explanation] ), + QCString( line, line_len + 1 ), + dsc->line_count + ); + + KDSC* kdsc = static_cast< KDSC* >( caller_data ); + Q_ASSERT( kdsc ); + + return kdsc->errorHandler()->error( error ); +} + +bool KDSCScanHandlerByLine::scanData( char* buf, unsigned int count ) +{ + char* lineStart = buf; + char* it = buf; + while( it < buf + count ) + { + if( *it++ == '\n' ) + { + int retval = dsc_scan_data( _cdsc, lineStart, it - lineStart ); + if( retval < 0 ) + return false; + else if( retval > 0 ) + { + _commentHandler->comment( + static_cast( retval ) ); + } + lineStart = it; + } + } + + if( it != lineStart ) + { + // Scan the remaining part of the string. + return ( dsc_scan_data( _cdsc, lineStart, it - lineStart ) < 0 ); + } + else + return true; +} + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/dscparse_adapter.h b/kghostview/dscparse_adapter.h new file mode 100644 index 00000000..9e41f3c2 --- /dev/null +++ b/kghostview/dscparse_adapter.h @@ -0,0 +1,386 @@ +/** + * Copyright (C) 2001 the KGhostView authors. See file AUTHORS. + * + * 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 DSCPARSE_ADAPTER_H +#define DSCPARSE_ADAPTER_H + +#include +#include +#include + +#include +#include + +#include "dscparse.h" + +#if defined(__GNUC__) +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 93) +/* + * We add a quick 'n' dirty inline implementation of auto_ptr for older + * releases of GCC, which don't include an auto_ptr implementation in + * . + */ + +template class auto_ptr { +private: + T* _ptr; + +public: + typedef T element_type; + explicit auto_ptr(T* p = 0) : _ptr(p) {} + auto_ptr(auto_ptr& a) : _ptr(a.release()) {} + template auto_ptr(auto_ptr& a) : _ptr(a.release()) {} + auto_ptr& operator=(auto_ptr& a) { + if (&a != this) { + delete _ptr; + _ptr = a.release(); + } + return *this; + } + template + auto_ptr& operator=(auto_ptr& a) { + if (a.get() != this->get()) { + delete _ptr; + _ptr = a.release(); + } + return *this; + } + ~auto_ptr() { delete _ptr; } + + T& operator*() const { return *_ptr; } + T* operator->() const { return _ptr; } + T* get() const { return _ptr; } + T* release() { T* tmp = _ptr; _ptr = 0; return tmp; } + void reset(T* p = 0) { delete _ptr; _ptr = p; } +}; + +#endif +#endif + + +class KDSCBBOX +{ +public: + KDSCBBOX(); + KDSCBBOX( const KDSCBBOX& b ); + KDSCBBOX( int llx, int lly, int urx, int ury ); + KDSCBBOX( const CDSCBBOX& bbox ); + + KDSCBBOX& operator = ( const KDSCBBOX& b ); + + bool operator == ( const KDSCBBOX& b ); + bool operator != ( const KDSCBBOX& b ); + + int llx() const; + int lly() const; + int urx() const; + int ury() const; + + int width() const; + int height() const; + + QSize size() const; + +private: + int _llx, _lly, _urx, _ury; +}; + +std::ostream& operator << ( std::ostream&, const KDSCBBOX& ); + + +class KDSCError +{ +public: + enum Type + { + BBox = CDSC_MESSAGE_BBOX, + EarlyTrailer = CDSC_MESSAGE_EARLY_TRAILER, + EarlyEOF = CDSC_MESSAGE_EARLY_EOF, + PageInTrailer = CDSC_MESSAGE_PAGE_IN_TRAILER, + PageOrdinal = CDSC_MESSAGE_PAGE_ORDINAL, + PagesWrong = CDSC_MESSAGE_PAGES_WRONG, + EPSNoBBox = CDSC_MESSAGE_EPS_NO_BBOX, + EPSPages = CDSC_MESSAGE_EPS_PAGES, + NoMedia = CDSC_MESSAGE_NO_MEDIA, + AtEnd = CDSC_MESSAGE_ATEND, + DuplicateComment = CDSC_MESSAGE_DUP_COMMENT, + DuplicateTrailer = CDSC_MESSAGE_DUP_TRAILER, + BeginEnd = CDSC_MESSAGE_BEGIN_END, + BadSection = CDSC_MESSAGE_BAD_SECTION, + LongLine = CDSC_MESSAGE_LONG_LINE, + IncorrectUsage = CDSC_MESSAGE_INCORRECT_USAGE + }; + + enum Severity + { + Information = CDSC_ERROR_INFORM, + Warning = CDSC_ERROR_WARN, + Error = CDSC_ERROR_ERROR + }; + + KDSCError( Type, Severity, const QCString& line, + unsigned int lineNumber ); + + Type type() const; + Severity severity() const; + QCString line() const; + unsigned int lineNumber() const; + +private: + Type _type; + Severity _severity; + QCString _line; + unsigned int _lineNumber; +}; + + +class KDSCErrorHandler +{ +public: + virtual ~KDSCErrorHandler() {} + enum Response + { + Ok = CDSC_RESPONSE_OK, + Cancel = CDSC_RESPONSE_CANCEL, + IgnoreAll = CDSC_RESPONSE_IGNORE_ALL + }; + + virtual Response error( const KDSCError& ) = 0; +}; + +class KDSCOkErrorHandler : public KDSCErrorHandler +{ + Response error( const KDSCError& ); +}; + +class KDSCCommentHandler +{ +public: + virtual ~KDSCCommentHandler() {} + enum Name + { + // Header section + PSAdobe = CDSC_PSADOBE, + BeginComments = CDSC_BEGINCOMMENTS, + EndComments = CDSC_ENDCOMMENTS, + Pages = CDSC_PAGES, + Creator = CDSC_CREATOR, + CreationDate = CDSC_CREATIONDATE, + Title = CDSC_TITLE, + For = CDSC_FOR, + LanguageLevel = CDSC_LANGUAGELEVEL, + BoundingBox = CDSC_BOUNDINGBOX, + Orientation = CDSC_ORIENTATION, + PageOrder = CDSC_PAGEORDER, + DocumentMedia = CDSC_DOCUMENTMEDIA, + DocumentPaperSizes = CDSC_DOCUMENTPAPERSIZES, + DocumentPaperForms = CDSC_DOCUMENTPAPERFORMS, + DocumentPaperColors = CDSC_DOCUMENTPAPERCOLORS, + DocumentPaperWeights = CDSC_DOCUMENTPAPERWEIGHTS, + DocumentData = CDSC_DOCUMENTDATA, + Requirements = CDSC_REQUIREMENTS, + DocumentNeededFonts = CDSC_DOCUMENTNEEDEDFONTS, + DocumentSuppliedFonts = CDSC_DOCUMENTSUPPLIEDFONTS, + HiResBoundingBox = CDSC_HIRESBOUNDINGBOX, + CropBox = CDSC_CROPBOX, + + // Preview section + BeginPreview = CDSC_BEGINPREVIEW, + EndPreview = CDSC_ENDPREVIEW, + + // Defaults section + BeginDefaults = CDSC_BEGINDEFAULTS, + EndDefaults = CDSC_ENDDEFAULTS, + // also %%PageMedia, %%PageOrientation, %%PageBoundingBox + + // Prolog section + BeginProlog = CDSC_BEGINPROLOG, + EndProlog = CDSC_ENDPROLOG, + BeginFont = CDSC_BEGINFONT, + EndFont = CDSC_ENDFONT, + BeginFeature = CDSC_BEGINFEATURE, + EndFeature = CDSC_ENDFEATURE, + BeginResource = CDSC_BEGINRESOURCE, + EndResource = CDSC_ENDRESOURCE, + BeginProcset = CDSC_BEGINPROCSET, + EndProcset = CDSC_ENDPROCSET, + + // Setup section + BeginSetup = CDSC_BEGINSETUP, + EndSetup = CDSC_ENDSETUP, + Feature = CDSC_FEATURE, + PaperColor = CDSC_PAPERCOLOR, + PaperForm = CDSC_PAPERFORM, + PaperWeight = CDSC_PAPERWEIGHT, + PaperSize = CDSC_PAPERSIZE, + // also %%Begin/EndFeature, %%Begin/EndResource + + // Page section + Page = CDSC_PAGE, + PageTrailer = CDSC_PAGETRAILER, + BeginPageSetup = CDSC_BEGINPAGESETUP, + EndPageSetup = CDSC_ENDPAGESETUP, + PageMedia = CDSC_PAGEMEDIA, + // also %%PaperColor, %%PaperForm, %%PaperWeight, %%PaperSize + PageOrientation = CDSC_PAGEORIENTATION, + PageBoundingBox = CDSC_PAGEBOUNDINGBOX, + // also %%Begin/EndFont, %%Begin/EndFeature + // also %%Begin/EndResource, %%Begin/EndProcSet + IncludeFont = CDSC_INCLUDEFONT, + ViewingOrientation = CDSC_VIEWINGORIENTATION, + + // Trailer section + Trailer = CDSC_TRAILER, + // also %%Pages, %%BoundingBox, %%Orientation, %%PageOrder, + // %%DocumentMedia + // %%Page is recognised as an error + // also %%DocumentNeededFonts, %%DocumentSuppliedFonts + + // End of File */ + Eof = CDSC_EOF + }; + + virtual void comment( Name name ) { std::cout << name << std::endl; } +}; + +class KDSCScanHandler; +class KDSC +{ +public: + KDSC(); + ~KDSC(); + + /*--- Adapter for CDSC ------------------------------------------------*/ + QString dsc_version() const; + + bool dsc() const; + bool ctrld() const; + bool pjl() const; + bool epsf() const; + bool pdf() const; + + unsigned int preview() const; + unsigned int language_level() const; + unsigned int document_data() const; + + unsigned long begincomments() const; + unsigned long endcomments() const; + unsigned long beginpreview() const; + unsigned long endpreview() const; + unsigned long begindefaults() const; + unsigned long enddefaults() const; + unsigned long beginprolog() const; + unsigned long endprolog() const; + unsigned long beginsetup() const; + unsigned long endsetup() const; + unsigned long begintrailer() const; + unsigned long endtrailer() const; + + CDSCPAGE* page() const; + + unsigned int page_count() const; + unsigned int page_pages() const; + unsigned int page_order() const; + unsigned int page_orientation() const; + + CDSCCTM* viewing_orientation() const; + + unsigned int media_count() const; + CDSCMEDIA** media() const; + const CDSCMEDIA* page_media() const; + +#if defined(__GNUC__) && (__GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 93)) + auto_ptr bbox() const; + auto_ptr page_bbox() const; +#else + std::auto_ptr bbox() const; + std::auto_ptr page_bbox() const; +#endif + + // CDSCDOSEPS *doseps; + + QString dsc_title() const; + QString dsc_creator() const; + QString dsc_date() const; + QString dsc_for() const; + + // unsigned int max_error + + bool scanData( char*, unsigned int ); + + /** + * Tidy up from incorrect DSC comments. + */ + int fixup(); + + KDSCErrorHandler* errorHandler() const; + void setErrorHandler( KDSCErrorHandler* ); + + KDSCCommentHandler* commentHandler() const; + void setCommentHandler( KDSCCommentHandler* ); + + /*--- Extra methods for convenience -----------------------------------*/ + bool isStructured() const; + + /*--- Temporary -------------------------------------------------------*/ + CDSC* cdsc() const; + +protected: + static int errorFunction( void* caller_data, CDSC* dsc, + unsigned int explanation, + const char* line, unsigned int line_len ); + +private: + CDSC* _cdsc; + KDSCErrorHandler* _errorHandler; + KDSCCommentHandler* _commentHandler; + KDSCScanHandler* _scanHandler; +}; + +class KDSCScanHandler +{ +public: + virtual ~KDSCScanHandler() {} + KDSCScanHandler( CDSC* cdsc ) : _cdsc( cdsc ) {} + + virtual bool scanData( char* buf, unsigned int count ) + { + return ( dsc_scan_data( _cdsc, buf, count ) >= 0 ); + } + +protected: + CDSC* _cdsc; +}; + +class KDSCScanHandlerByLine : public KDSCScanHandler +{ +public: + KDSCScanHandlerByLine( CDSC* cdsc, KDSCCommentHandler* commentHandler ) : + KDSCScanHandler( cdsc ), + _commentHandler( commentHandler ) + {} + + virtual bool scanData( char* buf, unsigned int count ); + +protected: + KDSCCommentHandler* _commentHandler; +}; + +#endif + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/fullscreenfilter.cpp b/kghostview/fullscreenfilter.cpp new file mode 100644 index 00000000..ec208169 --- /dev/null +++ b/kghostview/fullscreenfilter.cpp @@ -0,0 +1,54 @@ +/** + * Copyright (C) 2003, Lus Pedro Coelho + * + * 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 "fullscreenfilter.h" + +#include "kgvshell.h" +#include "kgv_view.h" +#include "kgv_miniwidget.h" +#include "kgvpageview.h" + +FullScreenFilter::FullScreenFilter( KGVShell& parent ) + :QObject( &parent, "full-screen-filter" ), + parent( parent ) +{ +} + +bool FullScreenFilter::eventFilter( QObject* /*object*/, QEvent* ev) { + if ( QKeyEvent* keyevent = dynamic_cast( ev ) ) { + if ( keyevent->key() == Key_Escape ) { + parent.setFullScreen( false ); + keyevent->accept(); + return true; + } + } + if ( QMouseEvent* mouseevent = dynamic_cast( ev ) ) { + if ( mouseevent->stateAfter() & mouseevent->button() & LeftButton ) { + // if ( The whole image is visible at once ) + if ( parent.m_gvpart->pageView()->contentsHeight() <= parent.m_gvpart->widget()->height() && + parent.m_gvpart->pageView()->contentsWidth() <= parent.m_gvpart->widget()->width() ) { + parent.m_gvpart->miniWidget()->nextPage(); + mouseevent->accept(); + return true; + } + } + } + return false; +} + +#include "fullscreenfilter.moc" + diff --git a/kghostview/fullscreenfilter.h b/kghostview/fullscreenfilter.h new file mode 100644 index 00000000..e60090a1 --- /dev/null +++ b/kghostview/fullscreenfilter.h @@ -0,0 +1,44 @@ +/** + * Copyright (C) 2003, Lus Pedro Coelho + * + * 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 DB_FULLSCREENFILTER_H1055977622_INCLUDE_GUARD_ +#define DB_FULLSCREENFILTER_H1055977622_INCLUDE_GUARD_ + +#include +class KGVShell; + +/* @class FullScreenFilter + * + * @short This class is to have in one place the special event all the special + * key/mouse handling related to full-screen mode without bloating further KGVPart + */ +class FullScreenFilter : public QObject { + Q_OBJECT + public: + FullScreenFilter( KGVShell& parent ); + + /** + * @reimplemented + */ + virtual bool eventFilter( QObject*, QEvent* ); + private: + KGVShell& parent; +}; + + + +#endif /* DB_FULLSCREENFILTER_H1055977622_INCLUDE_GUARD_ */ diff --git a/kghostview/generalsettingswidget.ui b/kghostview/generalsettingswidget.ui new file mode 100644 index 00000000..60ffbdf3 --- /dev/null +++ b/kghostview/generalsettingswidget.ui @@ -0,0 +1,111 @@ + +GeneralSettingsWidget +Nadeem Hasan <nhasan@kde.org> + + + GeneralSettingsWidget + + + + 0 + 0 + 397 + 143 + + + + + unnamed + + + 0 + + + + kcfg_Antialiasing + + + &Enable anti-aliasing of fonts and images + + + Anti-aliasing makes the result look better, but it makes the display take longer + + + + + kcfg_PlatformFonts + + + true + + + &Use platform fonts + + + + + kcfg_Messages + + + &Show Ghostscript messages in a separate box + + + Ghostscript is the basic renderer (the program which draws the picture)<br> +In case of problems you might want to see its error messages + + + + + kcfg_Palette + + + Palette + + + + unnamed + + + + Mono + + + &Monochrome + + + 2 + + + + + Gray + + + &Grayscale + + + 1 + + + + + Color + + + Co&lor + + + 0 + + + + + + + + kdialog.h + generalsettingswidget.ui.h + + + + diff --git a/kghostview/generalsettingswidget.ui.h b/kghostview/generalsettingswidget.ui.h new file mode 100644 index 00000000..8dd6920d --- /dev/null +++ b/kghostview/generalsettingswidget.ui.h @@ -0,0 +1,9 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + diff --git a/kghostview/gssettingswidget.ui b/kghostview/gssettingswidget.ui new file mode 100644 index 00000000..06779f3b --- /dev/null +++ b/kghostview/gssettingswidget.ui @@ -0,0 +1,158 @@ + +GSSettingsWidget +Nadeem Hasan <nhasan@kde.org> + + + GSSettingsWidget + + + + 0 + 0 + 395 + 243 + + + + + unnamed + + + 0 + + + + mConfigureButton + + + + 0 + 0 + 0 + 0 + + + + Auto Con&figure + + + + + spacer1 + + + Horizontal + + + Expanding + + + + 286 + 20 + + + + + + groupBox1 + + + Settings + + + + unnamed + + + + textLabel1 + + + &Interpreter: + + + kcfg_Interpreter + + + + + kcfg_Interpreter + + + Ghostscript is the basic renderer (i.e. the program which draws) + + + + + mDetectedVersion + + + (detected gs version: %1) + + + + + textLabel2 + + + &Non-antialiasing arguments: + + + kcfg_NonAntialiasingArguments + + + + + kcfg_NonAntialiasingArguments + + + Anti-aliasing makes the result look better, but it makes the display take longer + + + + + textLabel3 + + + An&tialiasing arguments: + + + kcfg_AntialiasingArguments + + + + + kcfg_AntialiasingArguments + + + Anti-aliasing makes the result look better, but it makes the display take longer + + + + + + + + + + kdialog.h + gssettingswidget.ui.h + + + configClicked() + + + setDetectedVersion( QString v ) + + + + + kpushbutton.h + kurlrequester.h + klineedit.h + kpushbutton.h + klineedit.h + klineedit.h + + diff --git a/kghostview/gssettingswidget.ui.h b/kghostview/gssettingswidget.ui.h new file mode 100644 index 00000000..87937c76 --- /dev/null +++ b/kghostview/gssettingswidget.ui.h @@ -0,0 +1,14 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + +void GSSettingsWidget::setDetectedVersion( QString v) +{ + mDetectedVersion->setText(mDetectedVersion->text().arg( v )); +} + diff --git a/kghostview/hi128-app-kghostview.png b/kghostview/hi128-app-kghostview.png new file mode 100644 index 00000000..82048b94 Binary files /dev/null and b/kghostview/hi128-app-kghostview.png differ diff --git a/kghostview/hi16-app-kghostview.png b/kghostview/hi16-app-kghostview.png new file mode 100644 index 00000000..9603332f Binary files /dev/null and b/kghostview/hi16-app-kghostview.png differ diff --git a/kghostview/hi22-app-kghostview.png b/kghostview/hi22-app-kghostview.png new file mode 100644 index 00000000..2109ade8 Binary files /dev/null and b/kghostview/hi22-app-kghostview.png differ diff --git a/kghostview/hi32-app-kghostview.png b/kghostview/hi32-app-kghostview.png new file mode 100644 index 00000000..4726452e Binary files /dev/null and b/kghostview/hi32-app-kghostview.png differ diff --git a/kghostview/hi48-app-kghostview.png b/kghostview/hi48-app-kghostview.png new file mode 100644 index 00000000..0289cea7 Binary files /dev/null and b/kghostview/hi48-app-kghostview.png differ diff --git a/kghostview/hi64-app-kghostview.png b/kghostview/hi64-app-kghostview.png new file mode 100644 index 00000000..e8bab3f4 Binary files /dev/null and b/kghostview/hi64-app-kghostview.png differ diff --git a/kghostview/infodialog.cpp b/kghostview/infodialog.cpp new file mode 100644 index 00000000..b9cc8a91 --- /dev/null +++ b/kghostview/infodialog.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2000 the KGhostView authors. See file AUTHORS. + * + * 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 +#include +#include +#include +#include + +#include +#include +#include + +#include "infodialog.h" + +// +// Using KDialogBase in message box mode (gives centered action button) +// +InfoDialog::InfoDialog( QWidget *parent, const char *name, bool modal ) + :KDialogBase( i18n("Document Information"), Yes, Yes, Yes, parent, + name, modal, true, KStdGuiItem::ok() ) +{ + QFrame *page = makeMainWidget(); + QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() ); + QGridLayout *glay = new QGridLayout( topLayout, 3, 2 ); + glay->setColStretch(1,1); + + QLabel *label = new QLabel( i18n("File name:" ), page ); + glay->addWidget( label, 0, 0, AlignRight|AlignVCenter ); + mFileLabel = new QLabel( page ); + glay->addWidget( mFileLabel, 0, 1 ); + + label = new QLabel( i18n("Document title:" ), page ); + glay->addWidget( label, 1, 0, AlignRight|AlignVCenter ); + mTitleLabel = new QLabel( page ); + glay->addWidget( mTitleLabel, 1, 1 ); + + label = new QLabel( i18n("Publication date:" ), page ); + glay->addWidget( label, 2, 0, AlignRight|AlignVCenter ); + mDateLabel = new QLabel( page ); + glay->addWidget( mDateLabel, 2, 1 ); + + topLayout->addStretch(1); +} + +namespace { + /* For PDF files, the dates are in a standard format. + * + * According to the spec at http://partners.adobe.com/asn/tech/pdf/specifications.jsp + * That format is "(D:YYYYMMDDHHmmSSOHH'mm')", where + * YYYY is year, + * MM month + * DD day + * HH hour + * mm minute + * SS second + * O is "+" or "-" + * HH is hour + * mm is minute + * + * OHH'mm' form together the desviation to UCT time ( the timezone ). + * Everything after the YYYY is optional. + * The D: is "highly recommended", but legally optional + * + * For PS files, there is no such standard and dates appear + * in any format they desire. + */ + QString parseDate( const QString& dateStr ) { + kdDebug( 4500 ) << "parseDate( \"" << dateStr << "\" )" << endl; + QRegExp exp( "\\((?:D:)?" + "(\\d\\d\\d\\d)" + "(\\d\\d)?(\\d\\d)?(\\d\\d)?.*" + "(\\d\\d)?(\\d\\d)?.*" + "(?:(\\+|\\-)(\\d\\d)\'?(\\d\\d)\'?)?" + "\\)" ); + if ( exp.exactMatch( dateStr ) ) { + QStringList list = exp.capturedTexts(); + QStringList::iterator iter = list.begin(); + ++iter; // whole string! +#undef GET +#define GET( variable, def ) \ + unsigned variable = def; \ + if ( iter != list.end() ) { \ + variable = ( *iter ).toUInt();\ + ++iter; \ + } + GET( year, 1 ) + GET( month, 1 ) + GET( day, 1 ) + GET( hour, 0 ) + GET( min, 0 ) + GET( sec, 0 ) +#undef GET + // FIXME: this ignores the timezone + QDate date( year, month, day ); + QTime time( hour, min, sec ); + KLocale locale( "kghostview" ); + return locale.formatDateTime( QDateTime( date, time ) ); + } + kdDebug( 4500 ) << "parseDate failed." << endl; + return dateStr; + } +} + +void InfoDialog::setup( const QString &fileName, const QString &documentTitle, + const QString &publicationDate ) +{ + mFileLabel->setText( fileName ); + mTitleLabel->setText( documentTitle ); + mDateLabel->setText( parseDate( publicationDate ) ); +} + +#include "infodialog.moc" + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/infodialog.h b/kghostview/infodialog.h new file mode 100644 index 00000000..1c857fc1 --- /dev/null +++ b/kghostview/infodialog.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2000 the KGhostView authors. See file AUTHORS. + * + * 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 _INFO_DIALOG_H_ +#define _INFO_DIALOG_H_ + +class QLabel; + +#include + +class InfoDialog : public KDialogBase +{ + Q_OBJECT + + public: + InfoDialog( QWidget *parent=0, const char *name=0, bool modal=true ); + void setup( const QString &fileName, const QString &documentTitle, + const QString &publicationDate ); + + private: + QLabel *mFileLabel; + QLabel *mTitleLabel; + QLabel *mDateLabel; +}; + +#endif + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/kdscerrordialog.cpp b/kghostview/kdscerrordialog.cpp new file mode 100644 index 00000000..601f5fc5 --- /dev/null +++ b/kghostview/kdscerrordialog.cpp @@ -0,0 +1,170 @@ +/** + * Copyright (C) 2001 the KGhostView authors. See file AUTHORS. + * + * 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 +#include +#include + +#include +#include +#include +#include +#include + +#include "kdscerrordialog.h" +#include "kdscerrordialog.moc" + +KDSCErrorThreshold::KDSCErrorThreshold( int threshold, + KDSCErrorHandler* errorHandler ) : + _threshold( threshold ), + _errorHandler( errorHandler ) +{} + +KDSCErrorHandler::Response KDSCErrorThreshold::error( const KDSCError& err ) +{ + if( _errorHandler != 0 && err.severity() >= _threshold ) + return _errorHandler->error( err ); + else + // Cancel is the default handling strategy for dsc_error_fn, so + // we keep it. This cancels error handling and *not* document + // parsing! + return Cancel; +} + +KDSCErrorDialog::KDSCErrorDialog( QWidget* parent ) : + KDialog( parent, "dscerrordialog", true ), + _response( Ok ) +{ + QVBoxLayout* vbox = new QVBoxLayout( this, marginHint(), spacingHint() ); + + _lineNumberLabel = new QLabel( this ); + vbox->addWidget( _lineNumberLabel ); + + _lineLabel = new QTextEdit( this ); + _lineLabel->setReadOnly( true ); + vbox->addWidget( _lineLabel ); + + _descriptionLabel = new QLabel( this ); + vbox->addWidget( _descriptionLabel ); + + KSeparator* sep = new KSeparator( KSeparator::HLine, this ); + vbox->addWidget( sep ); + + QHBoxLayout* hbox = new QHBoxLayout( vbox ); + + hbox->addStretch(); + + _okButton = new KPushButton( KStdGuiItem::ok(), this ); + hbox->addWidget( _okButton ); + _cancelButton = new KPushButton( KStdGuiItem::cancel(), this ); + hbox->addWidget( _cancelButton ); + _ignoreAllButton = new QPushButton( i18n("Ignore All"), this ); + hbox->addWidget( _ignoreAllButton ); + + connect( _okButton, SIGNAL( clicked() ), this, SLOT( slotOk() ) ); + connect( _cancelButton, SIGNAL( clicked() ), this, SLOT( slotCancel() ) ); + connect( _ignoreAllButton, SIGNAL( clicked() ), + this, SLOT( slotIgnoreAll() ) ); +} + +KDSCErrorHandler::Response KDSCErrorDialog::error( const KDSCError& err ) +{ + switch( err.severity() ) + { + case KDSCError::Information: + setCaption( i18n( "DSC Information" ) ); + break; + case KDSCError::Warning: + setCaption( i18n( "DSC Warning" ) ); + break; + case KDSCError::Error: + setCaption( i18n( "DSC Error" ) ); + break; + } + + _lineNumberLabel->setText( i18n( "On line %1:" ).arg( err.lineNumber() ) ); + _lineLabel->setText( err.line() ); + _descriptionLabel->setText( description( err.type() ) ); + + exec(); + + kdDebug(4500) << "KDSCErrorDialog: returning " << _response << endl; + + return _response; +} + +QString KDSCErrorDialog::description( KDSCError::Type type ) const +{ + switch( type ) + { + case KDSCError::BBox: + return "TODO"; + case KDSCError::EarlyTrailer: + return "TODO"; + case KDSCError::EarlyEOF: + return "TODO"; + case KDSCError::PageInTrailer: + return "TODO"; + case KDSCError::PageOrdinal: + return "TODO"; + case KDSCError::PagesWrong: + return "TODO"; + case KDSCError::EPSNoBBox: + return "TODO"; + case KDSCError::EPSPages: + return "TODO"; + case KDSCError::NoMedia: + return "TODO"; + case KDSCError::AtEnd: + return "TODO"; + case KDSCError::DuplicateComment: + return "TODO"; + case KDSCError::DuplicateTrailer: + return "TODO"; + case KDSCError::BeginEnd: + return "TODO"; + case KDSCError::BadSection: + return "TODO"; + case KDSCError::LongLine: + return i18n( "Lines in DSC documents must be shorter than 255 " + "characters." ); + case KDSCError::IncorrectUsage: + return "TODO"; + default: return "TODO"; + } +} + +void KDSCErrorDialog::slotOk() +{ + _response = Ok; + accept(); +} + +void KDSCErrorDialog::slotCancel() +{ + _response = Cancel; + accept(); +} + +void KDSCErrorDialog::slotIgnoreAll() +{ + _response = IgnoreAll; + accept(); +} + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/kdscerrordialog.h b/kghostview/kdscerrordialog.h new file mode 100644 index 00000000..0aee24d2 --- /dev/null +++ b/kghostview/kdscerrordialog.h @@ -0,0 +1,74 @@ +/** + * Copyright (C) 2001 the KGhostView authors. See file AUTHORS. + * + * 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 KDSCERRORDIALOG_H +#define KDSCERRORDIALOG_H + +#include + +#include "dscparse_adapter.h" + +class QLabel; +class QPushButton; +class QTextEdit; + +class KDSCErrorThreshold : public KDSCErrorHandler +{ +public: + KDSCErrorThreshold( int threshold, KDSCErrorHandler* ); + + Response error( const KDSCError& ); + +private: + int _threshold; + KDSCErrorHandler* _errorHandler; +}; + +class KDSCErrorDialog : public KDialog, public KDSCErrorHandler +{ + Q_OBJECT + +public: + KDSCErrorDialog( QWidget* parent = 0 ); + + Response error( const KDSCError& ); + +protected: + QString description( KDSCError::Type ) const; + +protected slots: + void slotOk(); + void slotCancel(); + void slotIgnoreAll(); + +private: + QLabel* _lineNumberLabel; + QTextEdit* _lineLabel; + QLabel* _descriptionLabel; + + QPushButton* _okButton; + QPushButton* _cancelButton; + QPushButton* _ignoreAllButton; + + Response _response; +}; + +#endif + + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/kghostview.desktop b/kghostview/kghostview.desktop new file mode 100644 index 00000000..66d3ee3f --- /dev/null +++ b/kghostview/kghostview.desktop @@ -0,0 +1,86 @@ +[Desktop Entry] +Name=KGhostView +Name[af]=Kghostview +Name[ar]=برنامج KGhostView +Name[eo]=Postskriptrigardilo +Name[hi]=के-घोस्ट-व्यू +Name[hu]=KGhostview +Name[ne]=केडीई घोस्ट दृश्य +Name[sv]=Kghostview +Name[ta]=கேமற்றொரு காட்சி +Name[tr]=GhostView +Name[ven]=Mbonalelo ya tshipuku tsha K +Name[xh]=Imboniselo yeKGhost +MimeType=application/pdf;application/postscript;image/x-eps;application/x-gzpostscript;application/illustrator; +InitialPreference=6 +Exec=kghostview %u -caption "%c" %i %m +Icon=kghostview +Type=Application +DocPath=kghostview/index.html +GenericName=PS/PDF Viewer +GenericName[af]=Ps/Pdf Aansig +GenericName[ar]=عارض PS/PDF +GenericName[bg]=Преглед на документи PS/PDF +GenericName[br]=Gweler PS/PDF +GenericName[bs]=Preglednik PS/PDF dokumenata +GenericName[ca]=Visualitzador de PS/PDF +GenericName[cs]=Prohlížeč PS/PDF souborů +GenericName[cy]=Gwelydd PS/PDF +GenericName[da]=PS/PDF-fremviser +GenericName[de]=PS/PDF-Betrachter +GenericName[el]=Προβολέας PS/PDF +GenericName[eo]=PS/PDF-rigardilo +GenericName[es]=Visor de documentos PS/PDF +GenericName[et]=PS/PDF-failide näitaja +GenericName[eu]=PS/PDF ikustailua +GenericName[fa]=مشاهده‌گر PS/PDF +GenericName[fi]=PS/PDF-näytin +GenericName[fr]=Afficheur PostScript et PDF +GenericName[ga]=Amharcán PS/PDF +GenericName[gl]=Visor PS/PDF +GenericName[he]=מציג PS/PDF +GenericName[hi]=PS/PDF प्रदर्शक +GenericName[hr]=Preglednik PS/PDF dokumenata +GenericName[hu]=PS/PDF-megjelenítő +GenericName[is]=PS/PDF sjá +GenericName[it]=Visore PS/PDF +GenericName[ja]=PS/PDF ビューア +GenericName[kk]=PS/PDF файлдарын қарау +GenericName[km]=កម្មវិធី​មើល PS/PDF +GenericName[lt]=PS/PDF žiūriklis +GenericName[lv]=PS/PDF Skatītājs +GenericName[ms]=Pemapar PS/PDF +GenericName[nb]=PS-/PDF-fremviser +GenericName[nds]=PostScript-/PDF-Kieker +GenericName[ne]=PS/PDF दर्शक +GenericName[nl]=PostScript/PDF-weergaveprogramma +GenericName[nn]=PS/PDF-lesar +GenericName[nso]=Molebeledi wa PS/PDF +GenericName[pa]=PS/PDF ਦਰਸ਼ਕ +GenericName[pl]=Przeglądarka plików PS/PDF +GenericName[pt]=Visualizador de PS/PDF +GenericName[pt_BR]=Visualizador PDF/PS +GenericName[ro]=Vizualizor PS/PDF +GenericName[ru]=Просмотр Postscript и PDF +GenericName[se]=PS/PDF-čájeheaddji +GenericName[sk]=Prehliadač PS/PDF +GenericName[sl]=Pregledovalnik datotek PS/PDF +GenericName[sr]=PS/PDF приказивач +GenericName[sr@Latn]=PS/PDF prikazivač +GenericName[sv]=PS/PDF-visare +GenericName[ta]=PS/PDF காட்சி +GenericName[tg]=Хондани PS/PDF +GenericName[th]=เครื่องมือแสดงแฟ้มโพสต์สคริปต์ PS/PDF +GenericName[tr]=PS/PDF Görüntüleyici +GenericName[uk]=Переглядач PDF/PS +GenericName[uz]=PS/PDF koʻruvchi +GenericName[uz@cyrillic]=PS/PDF кўрувчи +GenericName[ven]=Muvhoni wa PS/PDF +GenericName[wa]=Håyneu di documints PS/PDF +GenericName[xh]=Umboniseli we PS/PDF +GenericName[zh_CN]=PS/PDF 查看器 +GenericName[zh_HK]=PS/PDF 檢視器 +GenericName[zh_TW]=PS/PDF 檢視器 +GenericName[zu]=Umboniseli we PS/PDF +Terminal=false +Categories=Qt;KDE;Graphics; diff --git a/kghostview/kghostview.kcfg b/kghostview/kghostview.kcfg new file mode 100644 index 00000000..362191f3 --- /dev/null +++ b/kghostview/kghostview.kcfg @@ -0,0 +1,77 @@ + + + + + + + Anti-aliasing makes the result look better, specially regarding text, but it makes the display take longer + + + + + + + + + + + Whether to see a window with Ghostscript messages. This can give you additional information on the files you see. In case of an error, a window will popup regardless of this option. + false + + + + + true + + + + + true + + + + Sometimes information is available on page names which can be used in the list panner instead of just the numbers. Most often, these names are, in fact, another numbering. Often, the first few pages use roman numbering (i, ii, iii, iv ...) followed by arabic numbers from one (1, 2, 3...) when the real content starts. + true + + + + + true + + + + If this is on, then the file will be reloaded whenever it changes on disk + false + + + + + + Kghostview does not, itself, display the document: it relies on ghostscript, and therefore needs it to be available. Here you can define the ghostscript interpreter to use. + gs + + + + + -sDEVICE=x11 -dTextAlphaBits=4 -dGraphicsAlphaBits=2 -dMaxBitmap=10000000 + + + + + -sDEVICE=x11 + + + + This is the version of ghostscript you are running. Normally you will not need to change this since it gets detected automatically. + + + + + + + + + diff --git a/kghostview/kghostview.upd b/kghostview/kghostview.upd new file mode 100644 index 00000000..a61fffaf --- /dev/null +++ b/kghostview/kghostview.upd @@ -0,0 +1,13 @@ +Id=1changeToKConfigXT +File=kghostviewrc +Group=General +Key=Platform Fonts,PlatformFonts +Group=Ghostscript +Key=Antialiasing arguments,AntialiasingArguments +Key=Non-antialiasing arguments,NonAntialiasingArguments +Key=Redetection Counter,RedetectionCounter +# +Id=2changeToKConfigXT +File=kghostviewrc +Group=General +Script=update-to-xt-names.pl,perl diff --git a/kghostview/kghostview_part.desktop b/kghostview/kghostview_part.desktop new file mode 100644 index 00000000..a468fc02 --- /dev/null +++ b/kghostview/kghostview_part.desktop @@ -0,0 +1,19 @@ +[Desktop Entry] +Name=KGhostView +Name[af]=Kghostview +Name[ar]=برنامج KGhostView +Name[eo]=Postskriptrigardilo +Name[hi]=के-घोस्ट-व्यू +Name[hu]=KGhostview +Name[ne]=केडीई घोस्ट दृश्य +Name[sv]=Kghostview +Name[ta]=கேமற்றொரு காட்சி +Name[tr]=GhostView +Name[ven]=Mbonalelo ya tshipuku tsha K +Name[xh]=Imboniselo yeKGhost +MimeType=application/pdf;application/postscript;image/x-eps;application/x-gzpostscript;application/illustrator +InitialPreference=6 +Icon=kghostview +ServiceTypes=KParts/ReadOnlyPart,Browser/View +X-KDE-Library=libkghostviewpart +Type=Service diff --git a/kghostview/kghostviewui.rc b/kghostview/kghostviewui.rc new file mode 100644 index 00000000..3903a725 --- /dev/null +++ b/kghostview/kghostviewui.rc @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + &Main Toolbar + + + diff --git a/kghostview/kgv.h b/kghostview/kgv.h new file mode 100644 index 00000000..db7a1679 --- /dev/null +++ b/kghostview/kgv.h @@ -0,0 +1,15 @@ +#ifndef KGV_H +#define KGV_H + +#include + +namespace KGV +{ + +typedef QValueList PageList; + +} + +#endif + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/kgv_miniwidget.cpp b/kghostview/kgv_miniwidget.cpp new file mode 100644 index 00000000..33045b17 --- /dev/null +++ b/kghostview/kgv_miniwidget.cpp @@ -0,0 +1,573 @@ +/** + * Copyright (C) 1997-2003 the KGhostView authors. See file AUTHORS. + * + * 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 + +#include + +#include +#include +#include +#include +#include +#include +#include + +// KLineEditDlg is depricated as of 3.2. use KInputDialog instead +#if KDE_VERSION >= KDE_MAKE_VERSION(3,1,90) + #include +#else + #include + #include + #include +#endif + +#include +#include + +#include "infodialog.h" +#include "marklist.h" +#include "kgvdocument.h" +#include "kgv_view.h" +#include "version.h" +#include "scrollbox.h" + +#include "kgv_miniwidget.h" + +#include "kpswidget.h" + +using namespace KGV; + +KGVMiniWidget::KGVMiniWidget( KGVPart* part, const char* name ) : + QObject( part, name ), + _document( 0 ), + _part( part ), + _psWidget( 0 ), + _usePageLabels( true ), + _visiblePage( -1 ) +{ + KLocale locale( "kghostview" ); + _fallBackPageMedia = pageSizeToString( + static_cast< QPrinter::PageSize >( locale.pageSize() ) ); + _thumbnailService = new ThumbnailService( this ); + + connect( this, SIGNAL( newPageShown( int ) ), + SLOT( updateStatusBarText( int ) ) ); +} + +void KGVMiniWidget::setDocument( KGVDocument* document ) +{ + _document = document; + if( _document ) + connect( _document, SIGNAL( completed() ), + SLOT( slotDocumentOpened() ) ); +} + +QString KGVMiniWidget::pageSizeToString( QPrinter::PageSize pageSize ) +{ + switch( pageSize ) + { + case QPrinter::A3: return "A3"; + case QPrinter::A4: return "A4"; + case QPrinter::A5: return "A5"; + case QPrinter::B4: return "B4"; + case QPrinter::Ledger: return "Ledger"; + case QPrinter::Legal: return "Legal"; + case QPrinter::Letter: return "Letter"; + default: return "Unknown"; + } +} + +void KGVMiniWidget::reset() +{ + /* + if( _psWidget ) + _psWidget->disableInterpreter(); + */ + + // return to document defaults + _options.reset(); + emit setStatusBarText( "" ); +} + +void KGVMiniWidget::setPSWidget( KPSWidget* psWidget ) +{ + _psWidget = psWidget; + // setMagnification( _magnification ); + connect( _psWidget, SIGNAL( newPageImage( QPixmap ) ), + this, SLOT( sendPage() ) ); +} + +void KGVMiniWidget::goToPage() +{ +#if KDE_VERSION >= KDE_MAKE_VERSION(3,1,90) + int num; + bool ok = false; + num = KInputDialog::getInteger(i18n("Go to Page"), i18n("Page:"), 1, + 1, dsc()->page_count(), 1, 10, &ok, _part->widget()); + if (ok) goToPage( num-1 ); +#else + QString num; + bool b = false; + num = KLineEditDlg::getText(i18n("Go to Page"), i18n("Page:"), QString::null, &b, _part->widget(), new QIntValidator(1, dsc()->page_count(), this)); + if (b) goToPage( num.toInt() - 1 ); +#endif +} + +void KGVMiniWidget::info() +{ + if( !document()->isOpen() ) + return; + + InfoDialog* infoDialog = new InfoDialog( _part->widget(), "info", true ); + infoDialog->setup( _part->url().prettyURL(), + dsc()->dsc_title(), dsc()->dsc_date() ); + infoDialog->exec(); + delete infoDialog; +} + +void KGVMiniWidget::goToPage( int page ) +{ + if( _options.page() != page ) { + _options.setPage( page ); + showPage( _options.page() ); + } +} + +void KGVMiniWidget::zoomIn() +{ + if ( _options.zoomIn() ) showPage( _options.page() ); +} + +void KGVMiniWidget::zoomOut() +{ + if ( _options.zoomOut() ) showPage( _options.page() ); +} + +bool KGVMiniWidget::atMaxZoom() const +{ + return !_options.canZoomIn(); +} + +bool KGVMiniWidget::atMinZoom() const +{ + return !_options.canZoomOut(); +} + +void KGVMiniWidget::fitWidth( unsigned int width ) +{ + if ( (orientation() == CDSC_LANDSCAPE) || (orientation() == CDSC_SEASCAPE) ) + setMagnification( ( (double)width / QPaintDevice::x11AppDpiY()) / + ( (double)boundingBox().height() / 72) ); + else // default + setMagnification( ( (double)width / QPaintDevice::x11AppDpiX() ) / + ( (double)boundingBox().width() / 72) ); +} + +void KGVMiniWidget::fitHeight( unsigned int height ) +{ + if ( (orientation() == CDSC_LANDSCAPE) || (orientation() == CDSC_SEASCAPE) ) + setMagnification( ( (double)height / QPaintDevice::x11AppDpiY()) / + ( (double)boundingBox().width() / 72) ); + else //default + setMagnification( ( (double)height / QPaintDevice::x11AppDpiY()) / + ( (double)boundingBox().height() / 72) ); +} + +void KGVMiniWidget::fitWidthHeight( unsigned int w, unsigned int h ) +{ + double magnification = std::min( + ( ( double )h / QPaintDevice::x11AppDpiY() ) / + ( ( double )boundingBox().height() / 72.0 ), + ( ( double )w / QPaintDevice::x11AppDpiX() ) / + ( ( double )boundingBox().width() / 72.0 ) ); + setMagnification( magnification ); +} + +void KGVMiniWidget::firstPage() +{ + goToPage( 0 ); +} + +void KGVMiniWidget::lastPage() +{ + if ( !dsc() ) return; + + goToPage( dsc()->page_count() - 1 ); +} + +bool KGVMiniWidget::prevPage() +{ + if ( !dsc() ) return false; + + int new_page = 0; + + if( dsc()->isStructured() ) { + new_page = _options.page() - 1; + if( new_page < 0 ) + return false; + } + + goToPage( new_page ); + return true; +} + +bool KGVMiniWidget::nextPage() +{ + if ( !dsc() ) return false; + + int new_page = 0; + + if( dsc()->isStructured() ) { + new_page = _options.page() + 1; + if( (unsigned int)new_page >= dsc()->page_count() ) + return false; + } + + goToPage( new_page ); + return true; +} + + +void KGVMiniWidget::redisplay () +{ + if( !document()->psFile() ) + return; + + _psWidget->stopInterpreter(); + showPage( _options.page() ); +} + +void KGVMiniWidget::restoreOverrideOrientation() +{ + _options.restoreOverrideOrientation(); + showPage( _options.page() ); +} + +void KGVMiniWidget::setOverrideOrientation( CDSC_ORIENTATION_ENUM orientation ) +{ + _options.setOverrideOrientation( orientation ); + showPage( _options.page() ); +} + +CDSC_ORIENTATION_ENUM KGVMiniWidget::orientation() const +{ + if( _options.overrideOrientation() != CDSC_ORIENT_UNKNOWN ) + return _options.overrideOrientation(); + else if( dsc()->page_orientation() != CDSC_ORIENT_UNKNOWN ) + return static_cast< CDSC_ORIENTATION_ENUM >( dsc()->page_orientation()); + else if( dsc()->bbox().get() != 0 + && dsc()->bbox()->width() > dsc()->bbox()->height() ) + return CDSC_LANDSCAPE; + else + return CDSC_PORTRAIT; +} + +CDSC_ORIENTATION_ENUM KGVMiniWidget::orientation( int pagenumber ) const +{ + if ( !dsc() || unsigned( pagenumber ) >= dsc()->page_count() ) { + return orientation(); + } + if( _options.overrideOrientation() != CDSC_ORIENT_UNKNOWN ) { + return _options.overrideOrientation(); + } + + if( dsc()->page()[ pagenumber ].orientation != CDSC_ORIENT_UNKNOWN ) { + return static_cast< CDSC_ORIENTATION_ENUM >( dsc()->page()[ pagenumber ].orientation ); + } + if( dsc()->page_orientation() != CDSC_ORIENT_UNKNOWN ) { + return static_cast< CDSC_ORIENTATION_ENUM >( dsc()->page_orientation()); + } + if( !dsc()->epsf() ) { + return CDSC_PORTRAIT; + } + if( dsc()->bbox().get() != 0 + && dsc()->bbox()->width() > dsc()->bbox()->height() ) { + return CDSC_LANDSCAPE; + } + return CDSC_PORTRAIT; +} + +void KGVMiniWidget::restoreOverridePageMedia() +{ + _options.restoreOverridePageMedia(); + redisplay(); + showPage( _options.page() ); +} + +void KGVMiniWidget::setOverridePageMedia( const QString& mediaName ) +{ + _options.setOverridePageMedia( mediaName ); + showPage( _options.page() ); +} + +QString KGVMiniWidget::pageMedia() const +{ + if( !_options.overridePageMedia().isNull() ) + return _options.overridePageMedia(); + else if( dsc()->page_media() != 0 ) + return QString( dsc()->page_media()->name ); + else if( dsc()->bbox().get() != 0 ) + return QString( "BoundingBox" ); + else + return _fallBackPageMedia; +} + +QString KGVMiniWidget::pageMedia( int pagenumber ) const +{ + kdDebug( 4500 ) << "KGVMiniWidget::pageMedia( " << pagenumber << " )" << endl; + if ( !dsc() ) return pageMedia(); + if ( unsigned( pagenumber ) >= dsc()->page_count() ) return pageMedia(); + if( !_options.overridePageMedia().isNull() ) + return _options.overridePageMedia(); + else if( dsc()->page()[ pagenumber ].media != 0 ) + return QString( dsc()->page()[ pagenumber ].media->name ); + else if( dsc()->page_media() != 0 ) + return QString( dsc()->page_media()->name ); + else if( dsc()->bbox().get() != 0 ) + return QString( "BoundingBox" ); + else + return _fallBackPageMedia; +} + +KDSCBBOX KGVMiniWidget::boundingBox() const +{ + QString currentMedia = pageMedia(); + if( currentMedia == "BoundingBox" ) + return KDSCBBOX( *dsc()->bbox().get() ); + else { + QSize size = document()->computePageSize( currentMedia ); + return KDSCBBOX( 0, 0, size.width(), size.height() ); + } +} + +KDSCBBOX KGVMiniWidget::boundingBox( int pageNo ) const +{ + QString currentMedia = pageMedia( pageNo ); + if( currentMedia == "BoundingBox" ) + return KDSCBBOX( *dsc()->bbox().get() ); + else { + QSize size = document()->computePageSize( currentMedia ); + return KDSCBBOX( 0, 0, size.width(), size.height() ); + } +} + +bool KGVMiniWidget::atFirstPage() const +{ + return ( _options.page() == 0 ); +} + +bool KGVMiniWidget::atLastPage() const +{ + return ( _options.page() == static_cast( dsc()->page_count() ) - 1 ); +} + +void KGVMiniWidget::showPage( int pagenumber ) +{ + if( !document()->isOpen() ) + return; + + kdDebug(4500) << "KGVMiniWidget::showPage( " << pagenumber << " )" << endl; + + static_cast< QWidget* >( _psWidget->parent() )->show(); + + _psWidget->setFileName(_document->fileName(), dsc()->isStructured() ); + _psWidget->clear(); + + if( dsc()->isStructured() ) + { + // Coerce page number to fall in range + if( ( unsigned int)pagenumber >= dsc()->page_count() ) + pagenumber = dsc()->page_count() - 1; + if( pagenumber < 0 ) + pagenumber = 0; + + _options.setPage( pagenumber ); + + + _psWidget->setOrientation( orientation( _options.page() ) ); + _psWidget->setBoundingBox( boundingBox( _options.page() ) ); + _psWidget->setMagnification( _options.magnification() ); + + if( !_psWidget->isInterpreterRunning() ) + { + // Start interpreter, send preamble and send the current page. + if( _psWidget->startInterpreter() ) + { + _psWidget->sendPS( psFile(), dsc()->beginprolog(), + dsc()->endprolog() ); + _psWidget->sendPS( psFile(), dsc()->beginsetup(), + dsc()->endsetup() ); + _psWidget->sendPS( psFile(), dsc()->page()[ _options.page() ].begin, + dsc()->page()[ _options.page() ].end ); + _visiblePage = _options.page(); + } + } + else + sendPage(); + } + else + { + _psWidget->setOrientation( orientation() ); + _psWidget->setBoundingBox( boundingBox() ); + _psWidget->setMagnification( _options.magnification() ); + + if( !_psWidget->isInterpreterRunning() ) + { + // This is not a structured document -- start interpreter + _psWidget->startInterpreter(); + if( !dsc() ) + _psWidget->stopInterpreter(); + } + else if( _psWidget->isInterpreterReady() ) + _psWidget->nextPage(); + else + { + /* + KNotifyClient::userEvent + (i18n("KGhostview cannot load the document, \"%1\".\n" + "It appears to be broken.").arg( _fileName ), + KNotifyClient::Messagebox); + _psWidget->disableInterpreter(); + _psFile=0; + + //TODO: More to do to turn off display? + */ + return; + } + } + // Do this after ajusting pagenumber above + _thumbnailService->cancelRequests( -1 , _part->scrollBox(), SLOT( setThumbnail( QPixmap ) ) ); + _thumbnailService->delayedGetThumbnail( pagenumber, _part->scrollBox(), SLOT( setThumbnail( QPixmap ) ), true ); + + emit newPageShown( pagenumber ); +} + +void KGVMiniWidget::sendPage() +{ + // Send the page to the interpreter. + if( !_psWidget->isInterpreterBusy() && _visiblePage != _options.page() ) + { + // Interpreter ready - Fire off next page + _psWidget->clear(); + _psWidget->nextPage(); + _psWidget->sendPS( psFile(), dsc()->page()[ _options.page() ].begin, + dsc()->page()[ _options.page() ].end ); + _visiblePage = _options.page(); + } +} + +void KGVMiniWidget::updateStatusBarText( int pageNumber ) +{ + if( !dsc() ) + return; + + if( dsc()->isStructured() ) + { + QString text; + + if( pageNumber == -1 ) + text = i18n( "Page 1" ); + else + if( !_usePageLabels || document()->format() == KGVDocument::PDF ) + text = i18n( "Page %1 of %2" ) + .arg( pageNumber + 1 ) + .arg( dsc()->page_count() ); + else + text = i18n( "Page %1 (%2 of %3)" ) + .arg( dsc()->page()[ _options.page() ].label ) + .arg( pageNumber + 1 ) + .arg( dsc()->page_count() ); + + emit setStatusBarText( text ); + } +} + +void KGVMiniWidget::buildTOC() +{ + if( !dsc() ) + return; + + // Build table of contents + // Well, that's what it used to be called !! + + int last_page = 0; + + MarkList* marklist = _part->markList(); + + if( dsc()->isStructured() ) { + if( _usePageLabels ) + for( unsigned i = 0; i < dsc()->page_count(); ++i ) { + unsigned j = i; + if( dsc()->page_order() == CDSC_DESCEND ) + j = ( dsc()->page_count() - 1 ) - i; + last_page = atoi( dsc()->page()[j].label ); + } + + // finally set marked list + QString s; + for( unsigned i = 0; i < dsc()->page_count(); ++i ) { + const char * label = dsc()->page()[ i ].label; + QString tip = QString::fromLocal8Bit( label ? label : "" ); + + if( !_usePageLabels ) + s.setNum( i + 1 ); + else + s = tip; + + marklist->insertItem( s, i, tip ); + } + } + else { + marklist->insertItem( QString::fromLatin1( "1" ), 0 ); + } +} + +void KGVMiniWidget::setMagnification( double magnification ) +{ + if ( magnification != _options.magnification() ) { + _options.setMagnification( magnification ); + showPage( _options.page() ); + } +} + +void KGVMiniWidget::enablePageLabels( bool b ) +{ + if( _usePageLabels != b ) + { + _usePageLabels = b; + updateStatusBarText( _options.page() ); + buildTOC(); + } +} + +void KGVMiniWidget::slotDocumentOpened() +{ + buildTOC(); + showPage( _options.page() ); +} + +void KGVMiniWidget::setDisplayOptions( const DisplayOptions& newOptions ) +{ + _options = newOptions; +} + +#include "kgv_miniwidget.moc" + + +// vim:sw=4:sts=4:ts=8:sta:tw=78:noet diff --git a/kghostview/kgv_miniwidget.h b/kghostview/kgv_miniwidget.h new file mode 100644 index 00000000..3c445d14 --- /dev/null +++ b/kghostview/kgv_miniwidget.h @@ -0,0 +1,173 @@ +/** + * Copyright (C) 1997-2003 the KGhostView authors. See file AUTHORS. + * + * 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 __KGV_MINIWIDGET_H +#define __KGV_MINIWIDGET_H + +#include + +#include "dscparse_adapter.h" +#include "kgv.h" +#include "kgvdocument.h" +#include "displayoptions.h" + +#include "thumbnailservice.h" + +#include + +class InfoDialog; +class KGVPart; +class KPSWidget; +class MarkList; + +class KGVMiniWidget : public QObject +{ + Q_OBJECT + +public: + KGVMiniWidget( KGVPart* part, const char* name = 0 ); + + void setDocument( KGVDocument* document ); + + static QString pageSizeToString( QPrinter::PageSize ); + + void setPSWidget( KPSWidget* psWidget ); + + void setDisplayOptions( const DisplayOptions& newOptions ); + const DisplayOptions& displayOptions() const { return _options; } + + void restoreOverrideOrientation(); + void setOverrideOrientation( CDSC_ORIENTATION_ENUM ); + + void restoreOverridePageMedia(); + void setOverridePageMedia( const QString& mediaName ); + + ThumbnailService* getThumbnailService() { return _thumbnailService; } + + /** + * Enable/disable fancy, document-supplied page labels. + **/ + void enablePageLabels( bool e = true ); + bool arePageLabelsEnabled () { return _usePageLabels; } + + /** + * Return true if the current page is the first page, false otherwise. + */ + bool atFirstPage() const; + /** + * Return true if the current page is the last page, false otherwise. + */ + bool atLastPage() const; + + /** + * Return true if we're zoomed in fully, false otherwise. + */ + bool atMaxZoom() const; + /** + * Return true if we're zoomed out fully, false otherwise. + */ + bool atMinZoom() const; + + int currentPage() const { return _options.page(); } + +public slots: + bool prevPage(); + bool nextPage(); + void firstPage(); + void lastPage(); + void goToPage(); + void goToPage( int page ); + + void zoomIn(); + void zoomOut(); + + void fitWidth( unsigned int ); + void fitHeight( unsigned int ); + void fitWidthHeight( unsigned int, unsigned int ); + + void info(); + + /** + * Redisplay the page if the file has changed on disk. + **/ + void redisplay(); + +signals: + /** + * Page changed. + */ + void newPageShown( int pageNumber ); // Should this one be under DOCUMENT? + + void newPageImage( QPixmap image ); + + void setStatusBarText( const QString& ); + +protected: + void showPage( int pageNumber ); + void buildTOC(); + +protected slots: + void sendPage(); + void updateStatusBarText( int pageNumber ); + +protected: + void reset(); + +private: + + CDSC_ORIENTATION_ENUM orientation() const; + CDSC_ORIENTATION_ENUM orientation( int pageNo ) const; + + QString pageMedia() const; + QString pageMedia( int pageNo ) const; + + KDSCBBOX boundingBox() const; + KDSCBBOX boundingBox( int pageNo ) const; + + void setMagnification( double ); + + KDSC* const dsc() const + { return _document ? _document->dsc() : 0; } + FILE* psFile() + { return document()->psFile(); } + KGVDocument* const document() const + { return _document; } + +private slots: + void slotDocumentOpened(); + +private: + + friend class ThumbnailService; + KGVDocument* _document; + + KGVPart* _part; + KPSWidget* _psWidget; + ThumbnailService* _thumbnailService; + + bool _usePageLabels; + + int _visiblePage; + + DisplayOptions _options; + QString _fallBackPageMedia; +}; + +#endif + +// vim:sw=4:sts=4:ts=8:sta:tw=78:noet diff --git a/kghostview/kgv_part.rc b/kghostview/kgv_part.rc new file mode 100644 index 00000000..1ecc846a --- /dev/null +++ b/kghostview/kgv_part.rc @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + &File + + + + &Edit + + + + + + + + &View + + + + + + + + + + + + + + + + + &Settings + + + + + + + + + + + + + &Main Toolbar + + + + + + + + + + diff --git a/kghostview/kgv_view.cpp b/kghostview/kgv_view.cpp new file mode 100644 index 00000000..3c25ef41 --- /dev/null +++ b/kghostview/kgv_view.cpp @@ -0,0 +1,1037 @@ +/** + * Copyright (C) 2000-2002 the KGhostView authors. See file AUTHORS. + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "kgv_view.h" +#include "kgv_miniwidget.h" +#include "kgvconfigdialog.h" +#include "kgvdocument.h" +#include "kgvpagedecorator.h" +#include "kgvpageview.h" +#include "kgvmainwidget.h" +#include "kpswidget.h" +#include "kgvfactory.h" +#include "logwindow.h" +#include "marklist.h" +#include "scrollbox.h" +#include "version.h" +#include "configuration.h" + +#include + +namespace KGV { + /* + * This is because Qt's iterators + * are not standard iterators bc of missing typedefs, + * so they are only *almost* STL compatible + */ + template + unsigned distance( T a, T b ) { + unsigned res = 0; + while ( a != b ) { + ++res; + ++a; + } + return res; + } +} + +KGVPart::KGVPart( QWidget* parentWidget, const char*, + QObject* parent, const char* name, + const QStringList &args ) : + KParts::ReadOnlyPart( parent, name ), + _fitTimer( new QTimer( this ) ), + _job( 0 ), + _mimetypeScanner( 0 ), + _dirtyHandler( new QTimer( this ) ), + _isGuiInitialized( false ), + _isFileDirty( false ), + _stickyOptions( false ), + _embeddedInKGhostView( !args.contains( "KParts::ReadOnlyPart" ) ), + _customZoomIndex( -1 ) +{ + setInstance( KGVFactory::instance() ); + + // Don't show the progress info dialog if we're embedded in Konqueror. + setProgressInfoEnabled( !args.contains( "Browser/View") ); + + _document = new KGVDocument( this ); + connect( _document, SIGNAL( fileChangeFailed() ), + this, SLOT( slotCancelWatch() ) ); + connect( _document, SIGNAL( completed() ), + this, SLOT( slotOpenFileCompleted() ) ); + connect( _document, SIGNAL( canceled( const QString& ) ), + this, SIGNAL( canceled( const QString& ) ) ); + + _fileWatcher = new KDirWatch( this ); + connect( _fileWatcher, SIGNAL( dirty( const QString& ) ), + this, SLOT( slotFileDirty( const QString& ) ) ); + connect( _dirtyHandler, SIGNAL( timeout() ), + this, SLOT( slotDoFileDirty() ) ); + + // Setup main widget + _mainWidget = new KGVMainWidget( parentWidget ); + _mainWidget->setFocusPolicy( QWidget::StrongFocus ); + _mainWidget->installEventFilter( this ); + _mainWidget->setAcceptDrops( true ); + connect( _mainWidget, SIGNAL( spacePressed() ), + this, SLOT( slotReadDown() ) ); + connect( _mainWidget, SIGNAL( urlDropped( const KURL& ) ), + this, SLOT( openURL( const KURL& ) ) ); + + QHBoxLayout* hlay = new QHBoxLayout( _mainWidget, 0, 0 ); + QVBoxLayout* vlay = new QVBoxLayout( hlay ); + + const int PAGELIST_WIDTH = 75; + + _scrollBox = new ScrollBox( _mainWidget , "scrollbox" ); + _scrollBox->setFixedWidth( PAGELIST_WIDTH ); + _scrollBox->setMinimumHeight( PAGELIST_WIDTH ); + vlay->addWidget( _scrollBox ); + + _divider = new QFrame( _mainWidget, "divider" ); + _divider->setFrameStyle( QFrame::Panel | QFrame::Raised ); + _divider->setLineWidth( 1 ); + _divider->setMinimumWidth( 3 ); + hlay->addWidget( _divider ); + + _pageView = new KGVPageView( _mainWidget, "pageview" ); + _pageView->viewport()->setBackgroundMode( QWidget::PaletteMid ); + hlay->addWidget( _pageView, 1 ); + _mainWidget->setFocusProxy( _pageView ); + setWidget( _mainWidget ); + + _pageDecorator = new KGVPageDecorator( _pageView->viewport() ); + _pageDecorator->hide(); + + + _psWidget = new KPSWidget( _pageDecorator ); + _psWidget->readSettings(); + _pageView->setPage( _pageDecorator ); + connect( _psWidget, SIGNAL( output( char*, int ) ), + this, SLOT( slotGhostscriptOutput( char*, int ) ) ); + + connect( _psWidget, SIGNAL( ghostscriptError( const QString& ) ), + this, SLOT( slotGhostscriptError( const QString& ) ) ); + + + _logWindow = new LogWindow( i18n( "Ghostscript Messages" ), _mainWidget, "logwindow" ); + _showLogWindow = false; + + connect( _logWindow, SIGNAL( configureGS() ), SLOT( slotConfigure() ) ); + + _docManager = new KGVMiniWidget( this ); + _docManager->setPSWidget( _psWidget ); + _docManager->setDocument( document() ); + + _markList = new MarkList( _mainWidget, "marklist", _docManager ); + _markList->setFixedWidth( PAGELIST_WIDTH ); + vlay->addWidget( _markList, 1 ); + connect( _markList, SIGNAL( contextMenuRequested ( int, int, const QPoint& ) ), + this, SLOT( showPopup( int, int, const QPoint& ) ) ); + + + connect( _markList, SIGNAL( selected( int ) ), + _docManager, SLOT( goToPage( int ) ) ); + connect( _docManager, SIGNAL( newPageShown( int ) ), + _markList, SLOT( select( int ) ) ); + connect( _docManager, SIGNAL( setStatusBarText( const QString& ) ), + this, SIGNAL( setStatusBarText( const QString& ) ) ); + connect( _scrollBox, SIGNAL( valueChangedRelative( int, int ) ), + _pageView, SLOT( scrollBy( int, int ) ) ); + connect( _pageView, SIGNAL( pageSizeChanged( const QSize& ) ), + _scrollBox, SLOT( setPageSize( const QSize& ) ) ); + connect( _pageView, SIGNAL( viewSizeChanged( const QSize& ) ), + _scrollBox, SLOT( setViewSize( const QSize& ) ) ); + connect( _pageView, SIGNAL( contentsMoving( int, int ) ), + _scrollBox, SLOT( setViewPos( int, int ) ) ); + + //-- File Menu ---------------------------------------------------------- + KStdAction::saveAs( document(), SLOT( saveAs() ), + actionCollection() ); + new KAction( i18n( "Document &Info" ), 0, + miniWidget(), SLOT( info() ), + actionCollection(), "info" ); + + //-- Edit Menu ----------------------------------------------------- + _popup = new KPopupMenu( _markList, "marklist_menu" ); + + KAction *act = new KAction( i18n( "Mark Current Page" ), "flag", CTRL+SHIFT+Key_M, + _markList, SLOT( markCurrent() ), + actionCollection(), "mark_current" ); + act->plug( _popup ); + act = new KAction( i18n( "Mark &All Pages" ), 0, + _markList, SLOT( markAll() ), + actionCollection(), "mark_all" ); + act->plug( _popup ); + act = new KAction( i18n( "Mark &Even Pages" ), 0, + _markList, SLOT( markEven() ), + actionCollection(), "mark_even" ); + act->plug( _popup ); + act = new KAction( i18n( "Mark &Odd Pages" ), 0, + _markList, SLOT( markOdd() ), + actionCollection(), "mark_odd" ); + act->plug( _popup ); + act = new KAction( i18n( "&Toggle Page Marks" ), 0, + _markList, SLOT( toggleMarks() ), + actionCollection(), "toggle" ); + act->plug( _popup ); + act = new KAction( i18n("&Remove Page Marks"), 0, + _markList, SLOT( removeMarks() ), + actionCollection(), "remove" ); + act->plug( _popup ); + + // TODO -- disable entry if there aren't any page names + + //-- View Menu ---------------------------------------------------------- + _selectOrientation = new KSelectAction( i18n( "&Orientation" ), 0, 0, 0, + actionCollection(), "orientation_menu" ); + _selectMedia = new KSelectAction( i18n( "Paper &Size" ), 0, 0, 0, + actionCollection(), "media_menu" ); + + _flick = new KToggleAction( i18n( "No &Flicker" ), 0, + this, SLOT( slotFlicker() ), + actionCollection(), "no_flicker" ); + + QStringList orientations; + orientations.append( i18n( "Auto" ) ); + orientations.append( i18n( "Portrait" ) ); + orientations.append( i18n( "Landscape" ) ); + orientations.append( i18n( "Upside Down" ) ); + orientations.append( i18n( "Seascape" ) ); + _selectOrientation->setItems( orientations ); + + connect( _selectOrientation, SIGNAL( activated( int ) ), + this, SLOT( slotOrientation( int ) ) ); + connect( _selectMedia, SIGNAL( activated( int ) ), + this, SLOT( slotMedia( int ) ) ); + + { + KShortcut zoomInShort = KStdAccel::zoomIn(); + zoomInShort.append( KKey( CTRL+Key_Equal ) ); + _zoomIn = KStdAction::zoomIn( this, SLOT( slotZoomIn() ), + actionCollection(), "zoomIn" ); + _zoomIn->setShortcut( zoomInShort ); + } + _zoomOut = KStdAction::zoomOut( this, SLOT( slotZoomOut() ), + actionCollection(), "zoomOut" ); + _zoomTo = new KSelectAction( i18n( "Zoom" ), "viewmag", 0, actionCollection(), "zoomTo" ); + connect( _zoomTo, SIGNAL( activated( const QString & ) ), this, SLOT( slotZoom( const QString& ) ) ); + _zoomTo->setEditable( true ); + _zoomTo->clear(); + QValueList mags = DisplayOptions::normalMagnificationValues(); + QStringList zooms; + int idx = 0; + int cur = 0; + for ( QValueList::iterator first = mags.begin(), last = mags.end(); + first != last; + ++first ) { + QString str = QString( "%1%" ).arg( KGlobal::locale()->formatNumber( *first * 100.0, 2 )); + str.remove( KGlobal::locale()->decimalSymbol() + "00" ); + zooms << str; + if ( *first == 1.0 ) idx = cur; + ++cur; + } + _zoomTo->setItems( zooms ); + _zoomTo->setCurrentItem( idx ); + + _fitWidth = new KAction( i18n( "&Fit to Page Width" ), 0, this, + SLOT( slotFitToPage() ), actionCollection(), + "fit_to_page"); + _fitScreen = new KAction( i18n( "&Fit to Screen" ), Key_S, this, + SLOT( slotFitToScreen() ), actionCollection(), + "fit_to_screen"); + + _prevPage = new KAction( i18n( "Previous Page" ), CTRL+Key_PageUp, this, SLOT( slotPrevPage() ), + actionCollection(), "prevPage" ); + _prevPage->setWhatsThis( i18n( "Moves to the previous page of the document" ) ); + + _nextPage = new KAction( i18n( "Next Page" ), CTRL + Key_PageDown, this, SLOT( slotNextPage() ), + actionCollection(), "nextPage" ); + _nextPage->setWhatsThis( i18n( "Moves to the next page of the document" ) ); + + _firstPage = KStdAction::firstPage( this, SLOT( slotGotoStart() ), + actionCollection(), "goToStart" ); + _firstPage->setWhatsThis( i18n( "Moves to the first page of the document" ) ); + + _lastPage = KStdAction::lastPage( this, SLOT( slotGotoEnd() ), + actionCollection(), "goToEnd" ); + _lastPage->setWhatsThis( i18n( "Moves to the last page of the document" ) ); + + KShortcut readUpShort = KStdAccel::shortcut( KStdAccel::Prior ); + readUpShort.append( KKey( SHIFT+Key_Space ) ); + _readUp = new KAction( i18n( "Read Up" ), "up", + readUpShort, this, SLOT( slotReadUp() ), + actionCollection(), "readUp" ); + + KShortcut readDownShort = KStdAccel::shortcut( KStdAccel::Next ); + readDownShort.append( KKey( Key_Space ) ); + _readDown = new KAction( i18n( "Read Down" ), "down", + readDownShort, this, SLOT( slotReadDown() ), + actionCollection(), "readDown" ); + + _gotoPage = KStdAction::gotoPage( _docManager, SLOT( goToPage() ), + actionCollection(), "goToPage" ); + + //-- Settings Menu ------------------------------------------------------ + _showScrollBars = new KToggleAction( i18n( "Show &Scrollbars" ), 0, + actionCollection(), "show_scrollbars" ); + _showScrollBars->setCheckedState(i18n("Hide &Scrollbars")); + _watchFile = new KToggleAction( i18n( "&Watch File" ), 0, + this, SLOT( slotWatchFile() ), + actionCollection(), "watch_file" ); + _showPageList = new KToggleAction( i18n( "Show &Page List" ), 0, + actionCollection(), "show_page_list" ); + _showPageList->setCheckedState(i18n("Hide &Page List")); + _showPageLabels = new KToggleAction( i18n("Show Page &Labels"), 0, + actionCollection(), "show_page_labels" ); + _showPageLabels->setCheckedState(i18n("Hide Page &Labels")); + KStdAction::preferences( this, SLOT( slotConfigure() ), actionCollection() ); + connect( _showScrollBars, SIGNAL( toggled( bool ) ), + SLOT( showScrollBars( bool ) ) ); + connect( _showPageList, SIGNAL( toggled( bool ) ), + SLOT( showMarkList( bool ) ) ); + connect( _showPageLabels, SIGNAL( toggled( bool ) ), + SLOT( showPageLabels( bool ) ) ); + + _extension = new KGVBrowserExtension( this ); + + setXMLFile( "kgv_part.rc" ); + + connect( miniWidget(), SIGNAL( newPageShown( int ) ), + this, SLOT( slotNewPage( int ) ) ); + connect( _pageView, SIGNAL( contentsMoving( int, int ) ), + this, SLOT( slotPageMoved( int, int ) ) ); + + connect( _pageView, SIGNAL( nextPage() ), SLOT( slotNextPage() )); + connect( _pageView, SIGNAL( prevPage() ), SLOT( slotPrevPage() )); + connect( _pageView, SIGNAL( zoomIn() ), SLOT( slotZoomIn() )); + connect( _pageView, SIGNAL( zoomOut() ), SLOT( slotZoomOut() )); + connect( _pageView, SIGNAL( ReadUp() ), SLOT( slotReadUp() )); + connect( _pageView, SIGNAL( ReadDown() ), SLOT( slotReadDown() )); + + QStringList items = document()->mediaNames(); + items.prepend( i18n( "Auto ") ); + _selectMedia->setItems( items ); + + readSettings(); + + updatePageDepActions(); +} + +KGVPart::~KGVPart() +{ + if ( _job ) _job -> kill(); + delete _mimetypeScanner; + writeSettings(); +} + +KAboutData* KGVPart::createAboutData() +{ + KAboutData* about = new KAboutData( "kghostview", I18N_NOOP( "KGhostView"), + KGHOSTVIEW_VERSION, + I18N_NOOP( "Viewer for PostScript (.ps, .eps) and Portable Document Format (.pdf) files"), + KAboutData::License_GPL, + "(C) 1998 Mark Donohoe, (C) 1999-2000 David Sweet, " + "(C) 2000-2003 Wilco Greven", + I18N_NOOP( "KGhostView displays, prints, and saves " + "PostScript and PDF files.\n" + "Based on original work by Tim Theisen." ) ); + about->addAuthor( "Luís Pedro Coelho", + I18N_NOOP( "Current maintainer" ), + "luis@luispedro.org", + "http://luispedro.org" ); + about->addAuthor( "Wilco Greven", + I18N_NOOP( "Maintainer 2000-2003" ), + "greven@kde.org" ); + about->addAuthor( "David Sweet", + I18N_NOOP( "Maintainer 1999-2000" ), + "dsweet@kde.org", + "http://www.andamooka.org/~dsweet" ); + about->addAuthor( "Mark Donohoe", + I18N_NOOP( "Original author" ), + "donohoe@kde.org" ); + about->addAuthor( "David Faure", + I18N_NOOP( "Basis for shell"), + "faure@kde.org" ); + about->addAuthor( "Daniel Duley", + I18N_NOOP( "Port to KParts" ), + "mosfet@kde.org" ); + about->addAuthor( "Espen Sand", + I18N_NOOP( "Dialog boxes" ), + "espen@kde.org" ); + about->addCredit( "Russell Lang of Ghostgum Software Pty Ltd", + I18N_NOOP( "for contributing GSView's DSC parser." ), + 0, + "http://www.ghostgum.com.au/" ); + about->addCredit( "The Ghostscript authors", + 0, 0, + "http://www.cs.wisc.edu/~ghost/" ); + return about; +} + +bool KGVPart::closeURL() +{ + document()->close(); + _psWidget->stopInterpreter(); + _docManager->getThumbnailService()->reset(); + _markList->clear(); + _pageDecorator->hide(); + _scrollBox->clear(); + _isFileDirty = false; + if ( _job ) + { + _job -> kill(); + _job = 0; + } + if( _mimetypeScanner != 0 ) + _mimetypeScanner->abort(); + if( !m_file.isEmpty() ) + _fileWatcher->removeFile( m_file ); + _mimetype = QString::null; + updatePageDepActions(); + stateChanged( "initState" ); + return KParts::ReadOnlyPart::closeURL(); +} + +void KGVPart::writeSettings() +{ + KConfigGroup general( KGVFactory::instance()->config(), "General" ); + if ( !_embeddedInKGhostView ) + general.writeEntry( "Display Options", DisplayOptions::toString( miniWidget()->displayOptions() ) ); + general.sync(); +} + +void KGVPart::readSettings() +{ + KConfigGroup general( KGVFactory::instance()->config(), "General" ); + + _showScrollBars->setChecked( Configuration::showScrollBars() ); + showScrollBars( _showScrollBars->isChecked() ); + + _watchFile->setChecked( Configuration::watchFile() ); + slotWatchFile(); + + _showPageList->setChecked( Configuration::showPageList() ); + showMarkList( _showPageList->isChecked() ); + + _showPageLabels->setChecked( Configuration::watchFile() ); + showPageLabels( _showPageLabels->isChecked() ); + + _showLogWindow = Configuration::messages(); + if ( !_embeddedInKGhostView ) { + DisplayOptions options; + if ( DisplayOptions::fromString( options, general.readEntry( "Display Options" ) ) ) + setDisplayOptions( options ); + } + _psWidget->readSettings(); +} + +void KGVPart::slotScrollLeft() +{ + _pageView->scrollLeft(); +} + +void KGVPart::slotFlicker() +{ + if ( _psWidget ) _psWidget->setDoubleBuffering( _flick->isChecked() ); +} + +void KGVPart::slotScrollRight() +{ + _pageView->scrollRight(); +} + +void KGVPart::slotScrollUp() +{ + _pageView->scrollUp(); +} + +void KGVPart::slotScrollDown() +{ + _pageView->scrollDown(); +} + +void KGVPart::slotReadUp() +{ + if( !( document() && document()->isOpen() ) ) + return; + + if( !_pageView->readUp() ) { + if (_docManager->prevPage()) + _pageView->scrollBottom(); + } +} + +void KGVPart::slotReadDown() +{ + if( !( document() && document()->isOpen() ) ) + return; + + if( !_pageView->readDown() ) { + if( _docManager->nextPage() ) + _pageView->scrollTop(); + } +} + +void KGVPart::slotPrevPage() +{ + if( !document() || !document()->isOpen() ) return; + _docManager->prevPage(); +} + +void KGVPart::slotNextPage() +{ + if( !document() || !document()->isOpen() ) return; + _docManager->nextPage(); +} + +void KGVPart::slotGotoStart() +{ + _docManager->firstPage(); + _pageView->scrollTop(); +} + +void KGVPart::slotGotoEnd() +{ + _docManager->lastPage(); + _pageView->scrollTop(); +} + +void KGVPart::slotWatchFile() +{ + if( _watchFile->isChecked() ) + _fileWatcher->startScan(); + else { + _dirtyHandler->stop(); + _fileWatcher->stopScan(); + } +} + +void KGVPart::slotCancelWatch() +{ + _fileWatcher->stopScan(); + _watchFile->setChecked( false ); +} + +/* +void KGVPart::slotFitWidth() +{ + _docManager->fitWidth( pageView()->viewport()->width() - + 2*( pageDecorator()->margin() + pageDecorator()->borderWidth() ) ); +} +*/ + +void KGVPart::updateZoomActions() +{ + if( !( document() && document()->isOpen() ) ) + return; + + _zoomIn->setEnabled(!_docManager->atMaxZoom()); + _zoomOut->setEnabled(!_docManager->atMinZoom()); + _zoomTo->setEnabled( true ); + QStringList items = _zoomTo->items(); + bool updateItems = false; + if (_customZoomIndex != -1) + { + items.remove(items.at(_customZoomIndex)); + _customZoomIndex = -1; + updateItems = true; + } + double zoom = floor(miniWidget()->displayOptions().magnification()*1000.0) / 10.0; + unsigned idx = 0; + for ( QStringList::iterator first = items.begin(), last = items.end(); + first != last; + ++first ) { + QString cur = *first; + cur.remove( cur.find( '%' ), 1 ); + cur = cur.simplifyWhiteSpace(); + bool ok = false; + double z = cur.toDouble(&ok); + if ( ok ) { + if (std::abs( z - zoom ) < 0.1 ) { + if (updateItems) + _zoomTo->setItems( items ); + _zoomTo->setCurrentItem( idx ); + return; + } + if ( z > zoom ) + break; + } + ++idx; + } + + // Show percentage that isn't predefined + QString str = QString( "%1%" ).arg( KGlobal::locale()->formatNumber( zoom, 2 )); + str.remove( KGlobal::locale()->decimalSymbol() + "00" ); + items.insert( items.at(idx), 1, str ); + _zoomTo->setItems( items ); + _zoomTo->setCurrentItem( idx ); + _customZoomIndex = idx; +} + +void KGVPart::updatePageDepActions() +{ + bool hasDoc = document() && document()->isOpen(); + + _fitWidth->setEnabled( hasDoc ); + _fitScreen->setEnabled( hasDoc ); + + _prevPage->setEnabled( hasDoc && !_docManager->atFirstPage() ); + _firstPage->setEnabled( hasDoc && !_docManager->atFirstPage() ); + _nextPage->setEnabled( hasDoc && !_docManager->atLastPage() ); + _lastPage->setEnabled( hasDoc && !_docManager->atLastPage() ); + _gotoPage->setEnabled( hasDoc && + !(_docManager->atFirstPage() && _docManager->atLastPage()) ); + + updateReadUpDownActions(); +} + +void KGVPart::updateReadUpDownActions() +{ + if( !( document() && document()->isOpen() ) ) + { + _readUp->setEnabled( false ); + _readDown->setEnabled( false ); + return; + } + + if( _docManager->atFirstPage() && _pageView->atTop() ) + _readUp->setEnabled( false ); + else + _readUp->setEnabled( true ); + + if( _docManager->atLastPage() && _pageView->atBottom() ) + _readDown->setEnabled( false ); + else + _readDown->setEnabled( true ); +} + +bool KGVPart::openURL( const KURL& url ) +{ + if( !url.isValid() ) + return false; + if( !closeURL() ) + return false; + + m_url = url; + if ( !_stickyOptions ) _options.reset(); + + emit setWindowCaption( m_url.prettyURL() ); + + _mimetypeScanner = new KGVRun( m_url, 0, m_url.isLocalFile(), false ); + connect( _mimetypeScanner, SIGNAL( finished( const QString& ) ), + SLOT( slotMimetypeFinished( const QString& ) ) ); + connect( _mimetypeScanner, SIGNAL( error() ), + SLOT( slotMimetypeError() ) ); + + return true; +} + +void KGVPart::openURLContinue() +{ + kdDebug(4500) << "KGVPart::openURLContinue()" << endl; + if( m_url.isLocalFile() ) + { + emit started( 0 ); + m_file = m_url.path(); + document()->openFile( m_file, _mimetype ); + } + else + { + m_bTemp = true; + // Use same extension as remote file. This is important for + // mimetype-determination (e.g. koffice) + QString extension; + QString fileName = m_url.fileName(); + int extensionPos = fileName.findRev( '.' ); + if( extensionPos != -1 ) + extension = fileName.mid( extensionPos ); // keep the '.' + KTempFile tempFile( QString::null, extension ); + m_file = tempFile.name(); + _tmpFile.setName( m_file ); + _tmpFile.open( IO_ReadWrite ); + + /* + d->m_job = KIO::file_copy( m_url, m_file, 0600, true, false, d->m_showProgressInfo ); + emit started( d->m_job ); + connect( d->m_job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotJobFinished ( KIO::Job * ) ) ); + */ + + _job = KIO::get( m_url, false, isProgressInfoEnabled() ); + + connect( _job, SIGNAL( data( KIO::Job*, const QByteArray& ) ), + SLOT( slotData( KIO::Job*, const QByteArray& ) ) ); + connect( _job, SIGNAL( result( KIO::Job* ) ), + SLOT( slotJobFinished( KIO::Job* ) ) ); + + emit started( _job ); + } +} + +bool KGVPart::openFile() +{ + return false; +} + +void KGVPart::slotOpenFileCompleted() +{ + _docManager->getThumbnailService()->setEnabled( true ); + if( _isFileDirty ) + { + _docManager->redisplay(); + _isFileDirty = false; + } + else + { + if ( !_stickyOptions ) setDisplayOptions( DisplayOptions() ); + _stickyOptions = false; + + stateChanged( "documentState" ); + if ( !_fileWatcher->contains( m_file ) ) + _fileWatcher->addFile( m_file ); + slotWatchFile(); + updateZoomActions(); + emit completed(); + } +} + +void KGVPart::slotGhostscriptOutput( char* data, int len ) +{ + _logWindow->append( QString::fromLocal8Bit( data, len ) ); + if( _showLogWindow ) + _logWindow->show(); +} + + +void KGVPart::slotGhostscriptError( const QString& error ) +{ + _logWindow->setLabel( i18n( "An error occurred in rendering.
" + "%1
" + "The display may contain errors.
" + "Below are any error messages which were received from Ghostscript " + "(%2) " + "which may help you.
" ) + .arg( error ) + .arg( Configuration::interpreter() ), + true ); + // The true above makes it show a "configure gs" option, but maybe we + // should trigger an auto-redetection? + // LPC (13 Apr 2003) + _logWindow->show(); +} + + +void KGVPart::guiActivateEvent( KParts::GUIActivateEvent* event ) +{ + if( event->activated() && !_isGuiInitialized ) + { + stateChanged( "initState" ); + _isGuiInitialized = true; + } + KParts::ReadOnlyPart::guiActivateEvent( event ); +} + +void KGVPart::slotData( KIO::Job* job, const QByteArray& data ) +{ + Q_ASSERT( _job == job ); + + kdDebug(4500) << "KGVPart::slotData: received " << data.size() << " bytes." << endl; + + _tmpFile.writeBlock( data ); +} + +void KGVPart::slotMimetypeFinished( const QString& type ) +{ + kdDebug(4500) << "KGVPart::slotMimetypeFinished( " << type << " )" << endl; + _mimetype = type; + if( !_mimetypeScanner || _mimetypeScanner->hasError() ) + emit canceled( QString::null ); + else + openURLContinue(); + _mimetypeScanner = 0; +} + +void KGVPart::slotMimetypeError() +{ + kdDebug(4500) << "KGVPart::slotMimetypeError()" << endl; + _mimetypeScanner = 0; + emit started( 0 ); + //kapp->processEvents(); + emit canceled( QString::null ); +} + +void KGVPart::slotJobFinished( KIO::Job* job ) +{ + Q_ASSERT( _job == job ); + + kdDebug(4500) << "KGVPart::slotJobFinished" << endl; + + _job = 0; + + _tmpFile.close(); + + if( job->error() ) + emit canceled( job->errorString() ); + else + document()->openFile( m_file, _mimetype ); +} + +void KGVPart::slotFileDirty( const QString& fileName ) +{ + // The beauty of this is that each start cancels the previous one. + // This means that timeout() is only fired when there have + // no changes to the file for the last 750 milisecs. + // This is supposed to ensure that we don't update on every other byte + // that gets written to the file. + if ( fileName == m_file ) + { + _dirtyHandler->start( 750, true ); + } +} + +void KGVPart::slotDoFileDirty() +{ + kdDebug(4500) << "KGVPart::File changed" << endl; + _isFileDirty = true; + reloadFile(); +} + +void KGVPart::slotNewPage( int ) +{ + updatePageDepActions(); + //media->setCurrentItem (miniWidget()->getSize()-1); + //orientation->setCurrentItem (miniWidget()->getOrientation()-1); + //TODO -- zoom +} + +void KGVPart::slotPageMoved( int, int ) +{ + updateReadUpDownActions(); +} + +void KGVPart::slotOrientation( int id ) +{ + switch( id ) { + case 0: miniWidget()->restoreOverrideOrientation(); break; + case 1: miniWidget()->setOverrideOrientation( CDSC_PORTRAIT ); break; + case 2: miniWidget()->setOverrideOrientation( CDSC_LANDSCAPE ); break; + case 3: miniWidget()->setOverrideOrientation( CDSC_UPSIDEDOWN ); break; + case 4: miniWidget()->setOverrideOrientation( CDSC_SEASCAPE ); break; + default: ; + } +} + +void KGVPart::slotMedia( int id ) +{ + if( id == 0 ) + miniWidget()->restoreOverridePageMedia(); + else + miniWidget()->setOverridePageMedia( _document->mediaNames()[id-1] ); +} + +void KGVPart::showScrollBars( bool show ) +{ + _pageView->enableScrollBars( show ); +} + +void KGVPart::showMarkList( bool show ) +{ + _markList->setShown( show ); + _scrollBox->setShown( show ); + _divider->setShown( show ); +} + +void KGVPart::showPageLabels( bool show ) +{ + _docManager->enablePageLabels( show ); +} + +void KGVPart::slotZoomIn() +{ + _docManager->zoomIn(); + updateZoomActions(); +} + +void KGVPart::slotZoomOut() +{ + _docManager->zoomOut(); + updateZoomActions(); +} + +void KGVPart::slotZoom( const QString& nz ) +{ + QString z = nz; + double zoom; + z.remove( z.find( '%' ), 1 ); + zoom = KGlobal::locale()->readNumber( z ) / 100; + kdDebug( 4500 ) << "ZOOM = " << nz << ", setting zoom = " << zoom << endl; + + DisplayOptions options = miniWidget()->displayOptions(); + options.setMagnification( zoom ); + miniWidget()->setDisplayOptions( options ); + miniWidget()->redisplay(); + _mainWidget->setFocus(); + updateZoomActions(); +} + +void KGVPart::slotFitToPage() +{ + kdDebug(4500) << "KGVPart::slotFitToPage()" << endl; + if( pageView()->page() ) + miniWidget()->fitWidth( pageView()->viewport()->width() - 16 ); + // We subtract 16 pixels because of the page decoration. + updateZoomActions(); +} + +void KGVPart::slotFitToScreen() +{ + kdDebug(4500) << "KGVPart::slotFitToScreen()" << endl; + if ( _fitTimer->isActive() ) { + disconnect( _fitTimer, SIGNAL( timeout() ), this, 0 ); + connect( _fitTimer, SIGNAL( timeout() ), SLOT( slotDoFitToScreen() ) ); + } + else slotDoFitToScreen(); +} + +void KGVPart::slotDoFitToScreen() +{ + kdDebug(4500) << "KGVPart::slotDoFitToScreen()" << endl; + if( pageView()->page() ) + miniWidget()->fitWidthHeight( pageView()->viewport()->width() - 16, + pageView()->viewport()->height() - 16 ); + updateZoomActions(); +} + +void KGVPart::reloadFile() +{ + _psWidget->stopInterpreter(); + _docManager->getThumbnailService()->reset(); + document()->openFile( m_file, _mimetype ); +} + +void KGVPart::slotConfigure() +{ + ConfigDialog::showSettings( this ); +} + +void KGVPart::slotConfigurationChanged() +{ + readSettings(); + _psWidget->readSettings(); + miniWidget()->redisplay(); +} + +void KGVPart::setDisplayOptions( const DisplayOptions& options ) +{ + kdDebug(4500) << "KGVPart::setDisplayOptions()" << endl; + _stickyOptions = true; + _markList->select( options.page() ); + _docManager->setDisplayOptions( options ); + _selectOrientation->setCurrentItem( options.overrideOrientation() ); + QStringList medias = document()->mediaNames(); + QStringList::Iterator now = medias.find( options.overridePageMedia() ); + if ( now != medias.end() ){ + // The options are displayed in inverted order. + // Therefore, size() - index gets you the display index + _selectMedia->setCurrentItem( medias.size() - KGV::distance( medias.begin(), now ) ); + } else { + _selectMedia->setCurrentItem( 0 ); + } +} + + +KGVBrowserExtension::KGVBrowserExtension( KGVPart *parent ) : + KParts::BrowserExtension( parent, "KGVBrowserExtension" ) +{ + emit enableAction( "print", true ); + setURLDropHandlingEnabled( true ); +} + +void KGVBrowserExtension::print() +{ + ((KGVPart *)parent())->document()->print(); +} + + +KGVRun::KGVRun( const KURL& url, mode_t mode, bool isLocalFile, + bool showProgressInfo ) : + KRun( url, mode, isLocalFile, showProgressInfo ) +{ + connect( this, SIGNAL( finished() ), SLOT( emitFinishedWithMimetype() ) ); +} + +KGVRun::~KGVRun() +{} + +void KGVRun::foundMimeType( const QString& mimetype ) +{ + kdDebug(4500) << "KGVRun::foundMimeType( " << mimetype << " )" << endl; + + if( m_job && m_job->inherits( "KIO::TransferJob" ) ) + { + KIO::TransferJob *job = static_cast< KIO::TransferJob* >( m_job ); + job->putOnHold(); + m_job = 0; + } + + _mimetype = mimetype; + + m_bFinished = true; + m_timer.start( 0, true ); +} + + +void KGVPart::updateFullScreen( bool fs ) +{ + if ( fs ) showMarkList( false ); + else showMarkList( _showPageList->isChecked() ); +} + +void KGVPart::showPopup( int, int, const QPoint& pos ) +{ + _popup->exec( pos ); +} + +#include "kgv_view.moc" + + +// vim:sw=4:sts=4:ts=8:sta:tw=78:noet diff --git a/kghostview/kgv_view.h b/kghostview/kgv_view.h new file mode 100644 index 00000000..3a426f58 --- /dev/null +++ b/kghostview/kgv_view.h @@ -0,0 +1,268 @@ +/** + * Copyright (C) 2000-2002 the KGhostView authors. See file AUTHORS. + * + * 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 __KGV_VIEW_H +#define __KGV_VIEW_H + +#include // QByteArray +#include + +#include +#include +#include + +#include "displayoptions.h" + +class QFrame; +class QWidget; + +class KAboutData; +class KAction; +class KActionCollection; +class KDirWatch; +class KInstance; +class KPopupMenu; +class KSelectAction; +class KToggleAction; + +class KGVBrowserExtension; +class KGVConfigDialog; +class KGVDocument; +class KGVMiniWidget; +class KGVPageView; +class KGVPageDecorator; +class KGVRun; +class KPSWidget; +class LogWindow; +class MarkList; +class ScrollBox; + +class KGVPart: public KParts::ReadOnlyPart +{ + Q_OBJECT +public: + KGVPart( QWidget* parentWidget, const char* widgetName, + QObject* parent, const char* name, + const QStringList& args = QStringList() ); + + virtual ~KGVPart(); + + KGVMiniWidget* miniWidget() const { return _docManager; } + MarkList* markList() const { return _markList; } + ScrollBox* scrollBox() { return _scrollBox; } + KGVPageView* pageView() const { return _pageView; } + KGVPageDecorator* pageDecorator() const { return _pageDecorator; } + KGVDocument* document() const { return _document; } + + + /** + * Reimplemented from ReadOnlyPart in order to delete the file from + * KDirWatch's list. + */ + virtual bool closeURL(); + + KDE_EXPORT static KAboutData* createAboutData(); + +public slots: + /** + * Reimplemented from ReadOnlyPart so that incoming data can be sent + * through the DSC parser immediately on arrival. + */ + virtual bool openURL( const KURL& ); + virtual void openURLContinue(); + + /** + * Reloads the current file. + * No action if no file is loaded + */ + void reloadFile(); + + void updateFullScreen( bool ); + + void showPopup( int, int, const QPoint &pos ); + + void slotScrollLeft(); + void slotScrollRight(); + void slotScrollUp(); + void slotScrollDown(); + void slotReadDown(); + void slotFlicker(); + void slotReadUp(); + void slotPrevPage(); + void slotNextPage(); + void slotGotoStart(); + void slotGotoEnd(); + + void slotFitToPage(); + void slotFitToScreen(); + void slotDoFitToScreen(); + + void showScrollBars( bool ); + void slotCancelWatch(); + void showMarkList( bool ); + void showPageLabels( bool ); + + void slotZoomIn(); + void slotZoomOut(); + + void slotZoom( const QString& ); + + void slotConfigure(); + void slotConfigurationChanged(); + + /** + * Sets the display options in a sticky way. + * This means that the file being opened or the next one to be open will + * get these options. This is useful for session management or commandline + * arguments + */ + void setDisplayOptions( const DisplayOptions& opts ); + +protected slots: + void slotData( KIO::Job*, const QByteArray& ); + void slotJobFinished( KIO::Job* ); + + void slotMimetypeFinished( const QString& ); + void slotMimetypeError(); + + void slotFileDirty( const QString& ); + void slotDoFileDirty(); + + void slotOrientation (int); + void slotMedia (int); + void slotNewPage( int ); + void slotPageMoved( int, int ); + void slotWatchFile(); + + void slotOpenFileCompleted(); + +protected: + virtual void guiActivateEvent( KParts::GUIActivateEvent* ); + + // reimplemented from ReadOnlyPart + virtual bool openFile(); + + void updatePageDepActions(); + void updateZoomActions(); + void updateReadUpDownActions(); + + void readSettings(); + void writeSettings(); + +private slots: + void slotGhostscriptOutput( char* data, int len ); + void slotGhostscriptError( const QString& ); + +private: + KGVBrowserExtension* _extension; + + KGVDocument* _document; + + QWidget* _mainWidget; + KGVPageView* _pageView; + KGVPageDecorator* _pageDecorator; + KPSWidget* _psWidget; + ScrollBox* _scrollBox; + QFrame* _divider; + MarkList* _markList; + KGVMiniWidget* _docManager; + + LogWindow* _logWindow; + + QTimer* _fitTimer; + + KSelectAction* _selectOrientation; + KSelectAction* _selectMedia; + KAction* _zoomIn; + KAction* _zoomOut; + KSelectAction* _zoomTo; + KAction * _fitWidth; + KAction * _fitScreen; + KAction* _prevPage; + KAction* _nextPage; + KAction* _firstPage; + KAction* _lastPage; + KAction* _readUp; + KAction* _readDown; + KAction* _gotoPage; + KToggleAction* _showScrollBars; + KToggleAction* _watchFile; + KToggleAction* _flick; + KToggleAction* _showPageList; + KToggleAction* _showPageLabels; + KPopupMenu* _popup; + + QFile _tmpFile; + KIO::TransferJob* _job; + KDirWatch* _fileWatcher; + KGVRun* _mimetypeScanner; + QTimer* _dirtyHandler; + + QString _mimetype; + + bool _isGuiInitialized : 1; + bool _isFileDirty : 1; + bool _showLogWindow : 1; + bool _stickyOptions : 1; + bool _embeddedInKGhostView : 1; + + int _customZoomIndex; + + DisplayOptions _options; +}; + + +class KGVBrowserExtension : public KParts::BrowserExtension +{ + Q_OBJECT + friend class KGVPart; // emits our signals +public: + KGVBrowserExtension( KGVPart* parent ); + virtual ~KGVBrowserExtension() {} + +public slots: + // Automatically detected by konqueror + void print(); +}; + +class KGVRun : public KRun +{ + Q_OBJECT + +public: + KGVRun( const KURL& url, mode_t mode = 0, + bool isLocalFile = false, bool showProgressInfo = true ); + + virtual ~KGVRun(); + +signals: + void finished( const QString& mimetype ); + +protected: + void foundMimeType( const QString& mimetype ); + +protected slots: + void emitFinishedWithMimetype() { emit finished( _mimetype ); } + +private: + QString _mimetype; +}; + +#endif + +// vim:sw=4:sts=4:ts=8:sta:tw=78:noet diff --git a/kghostview/kgvconfigdialog.cpp b/kghostview/kgvconfigdialog.cpp new file mode 100644 index 00000000..a9952008 --- /dev/null +++ b/kghostview/kgvconfigdialog.cpp @@ -0,0 +1,154 @@ +/** + * Copyright (C) 2000-2002 the KGhostView authors. See file AUTHORS. + * + * 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. + */ + + +// Add header files alphabetically + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "configuration.h" +#include "kgv_view.h" +#include "kgvfactory.h" + +#include "generalsettingswidget.h" +#include "gssettingswidget.h" + +#include "kgvconfigdialog.h" + + +namespace { + QString getGSVersion( QString fullPathToExec ) + { + QString res; + QString chkVersion = KProcess::quote(fullPathToExec) + " --version"; + FILE* p = popen( QFile::encodeName(chkVersion), "r" ); + if( p ) { + // FIXME: a badly configured interpreter can hang us + QFile qp; + qp.open( IO_ReadOnly, p ); + qp.readLine( res, 80 ); + qp.close(); + pclose( p ); + res = res.stripWhiteSpace(); + } + kdDebug(4500) << "kgvconfigdialog.cpp::{unamed}::getGSVersion() returning " << res << endl; + return res; + } + + + /* A mechanism for triggering redetection of gs versions: + * + * The idea is that whenever we find we need to workaround a certain version of gs, + * we cannot rely that there will solelly be a new kghostviewrc, but that users will + * upgrade kghostview. Therefore, whenever we want to trigger redection on a new version, + * we increment the counter below. It should have the old value from the previous version + * of kghostview and this function will get called. + * + */ + + /* On a related note: + * We don't detect upgrades (or downgrades, for that matter) of gs. + * I am seeing if I can get the version out of gs as a side effect to displaying a file. + * This way, using kconfig:/Ghostscript/GS Version we will see whether the version has changed + * and trigger a redetection without the trouble of running "gs --version" on each launch. + * + * LPC (9 April 2003) + */ + /* currentRedetection value log: + * + * 1- remove -dMaxBitmap for gs 6.5x + * 2- see if it supports .setsafe ( see bug:57291 ). + */ + const int currentRedetection = 2; + + + /* Here are the issues we found so far in version of gs: + * + * - gs before 6.50 uses device x11alpha instead of x11 + * - gs 6.5x does not work well with -dMaxBitmap=... + * - gs 6.52 and earlier as well as 7.0x for x < 4 don't support the .setsafe operator + * + */ + + QString recommendSetSafe( QString version ) + { + if ( version < QString::number( 6.53 ) ) return QString::number( 6.53 ); + if ( version[ 0 ] == '7' && version < QString::number( 7.04 ) ) return QString::number( 7.05 ); + return QString::null; + } + // This function should contain all the gs version specific workarounds. + void redoGSDetection() + { + kdDebug(4500) << "kgvconfigdialog.cpp::{unnamed}::redoGSDetection()" << endl; + QString version = getGSVersion( Configuration::interpreter() ); + QString recommended = recommendSetSafe( version ); + if ( !recommended.isNull() ) { + KMessageBox::sorry( 0, + i18n( "Your version of gs (version %1) is too old, since it has security issues " + "which are impossible to resolve. Please upgrade to a newer version.\n" + "KGhostView will try to work with it, but it may not display any files at all.\n" + "Version %2 seems to be appropriate on your system, although newer versions will work as well." ) + .arg( version ) + .arg( recommended ) ); + } + if ( version < QString::number( 7.00 ) ) + { + QStringList arguments = QStringList::split( ' ', Configuration::antialiasingArguments() ); + arguments.remove( QString::fromLatin1( "-dMaxBitmap=10000000" ) ); + QString antiAliasArgs = arguments.join( " " ); + + Configuration::setAntialiasingArguments( antiAliasArgs ); + } + + Configuration::setRedetectionCounter( currentRedetection ); + Configuration::setVersion( version ); + } +} // namespace + +void ConfigDialog::showSettings( KGVPart* main ) { + const char* name = "kghostview-settings"; + if ( KConfigDialog::showDialog( name ) ) return; + + if ( Configuration::redetectionCounter() < currentRedetection ) redoGSDetection(); + + KConfigDialog* dialog = new KConfigDialog( 0, name, + Configuration::self(), KDialogBase::IconList ); + dialog->addPage( new GeneralSettingsWidget( 0, "general-settings" ), + i18n( "General" ), QString::fromLatin1( "kghostview" ) ); + GSSettingsWidget *gssw = new GSSettingsWidget( 0, "gs-settings" ); + dialog->addPage( gssw, i18n( "Ghostscript\nConfiguration" ), QString::fromLatin1( "pdf" ) ); + + gssw->setDetectedVersion(Configuration::version()); + + QObject::connect( dialog, SIGNAL( settingsChanged() ), main, SLOT( slotConfigurationChanged() ) ); + dialog->show(); +} + + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/kgvconfigdialog.h b/kghostview/kgvconfigdialog.h new file mode 100644 index 00000000..3f7ddead --- /dev/null +++ b/kghostview/kgvconfigdialog.h @@ -0,0 +1,32 @@ +/** + * Copyright (C) 2000-2002 the KGhostView authors. See file AUTHORS. + * + * 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 _INTERPRETER_DIALOG_H_ +#define _INTERPRETER_DIALOG_H_ + +class KGVPart; + +namespace ConfigDialog { + void showSettings( KGVPart* ); + +} + +#endif + + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/kgvdocument.cpp b/kghostview/kgvdocument.cpp new file mode 100644 index 00000000..d5b7df41 --- /dev/null +++ b/kghostview/kgvdocument.cpp @@ -0,0 +1,864 @@ +/** + * Copyright (C) 1997-2003 the KGhostView authors. See file AUTHORS. + * + * 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 +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "configuration.h" +#include "kdscerrordialog.h" +#include "kgv_miniwidget.h" +#include "marklist.h" +#include "kgvfactory.h" + +extern "C" { +#include "ps.h" +} + +#include "kgvdocument.h" + +using namespace std; +using namespace KGV; + +KGVDocument::KGVDocument( KGVPart* part, const char* name ) : + QObject( part, name ), + _psFile( 0 ), + _part( part ), + _tmpUnzipped( 0 ), + _tmpFromPDF( 0 ), + _tmpDSC( 0 ), + _isFileOpen( false ), + _dsc( 0 ) + +{ + readSettings(); + + _pdf2dsc = new Pdf2dsc( _interpreterPath, this ); + connect( _pdf2dsc, SIGNAL( finished( bool ) ), + SLOT( openPDFFileContinue( bool ) ) ); +} + +KGVDocument::~KGVDocument() +{ + close(); +} + +void KGVDocument::readSettings() +{ + _interpreterPath = Configuration::interpreter(); +} + +/*- OPENING and READING ---------------------------------------------------*/ + +void KGVDocument::openFile( const QString& name, const QString& mimetype ) +{ + kdDebug(4500) << "KGVDocument::openFile" << endl; + + close(); + _fileName = name; + _mimetype = mimetype; + + QTimer::singleShot( 0, this, SLOT( doOpenFile() ) ); +} + +void KGVDocument::doOpenFile() +{ + QFileInfo fileInfo( _fileName ); + if( !fileInfo.exists() ) + { + KMessageBox::sorry( _part->widget(), + i18n( "Could not open %1: " + "File does not exist." ) + .arg( _fileName ) ); + emit canceled( QString() ); + return; + } + if( !fileInfo.isReadable() ) + { + KMessageBox::sorry( _part->widget(), + i18n( "Could not open %1: " + "Permission denied." ) + .arg( _fileName ) ); + emit canceled( QString() ); + return; + } + + if( uncompressFile() ) + { + kdDebug( 4500 ) << "FILENAME: " << _fileName << endl; + KMimeType::Ptr mimetype = KMimeType::findByPath( _fileName ); + kdDebug(4500) << "KGVDocument::mimetype: " << mimetype->name() + << endl; + _mimetype = mimetype->name(); + } + + // If the file contains a PDF document, create a DSC description file + // of the PDF document. This can be passed to Ghostscript just like + // an ordinary PS file. + if( _mimetype == "application/pdf" + || _mimetype == "application/x-pdf" ) // see bug:67474 + { + _tmpDSC = new KTempFile( QString::null, ".ps" ); + Q_CHECK_PTR( _tmpDSC ); + if( _tmpDSC->status() != 0 ) { + KMessageBox::error( _part->widget(), + i18n( "Could not create temporary file: %1" ) + .arg( strerror( _tmpDSC->status() ) ) ); + emit canceled( QString() ); + return; + } + + // When pdf2dsc has finished the program will continue with + // openPDFFileContinue. + _pdf2dsc->run( _fileName, _tmpDSC->name() ); + return; + } + else if( _mimetype == "application/postscript" + || _mimetype == "application/x-postscript" // see bug:71546 + || _mimetype == "application/illustrator" + || _mimetype == "image/x-eps" + || _mimetype == "text/plain" ) + { + _format = PS; + openPSFile(); + return; + } + else + { + KMessageBox::sorry( _part->widget(), + i18n( "Could not open %1 " + "which has type %2. KGhostview can " + "only load PostScript (.ps, .eps) and Portable " + "Document Format (.pdf) files." ) + .arg( _fileName ) + .arg( _mimetype ) ); + emit canceled( QString() ); + return; + } +} + +bool KGVDocument::uncompressFile() +{ + // If the file is gzipped, gunzip it to the temporary file _tmpUnzipped. + kdDebug(4500) << "KGVDocument::uncompressFile()" << endl; + + auto_ptr filterDev( KFilterDev::deviceForFile( _fileName, _mimetype, true ) ); + if ( !filterDev.get() ) { + KMimeType::Ptr mt = KMimeType::mimeType(_mimetype); + if ( (_fileName.right( 3 ) == ".gz") || mt->is("application/x-gzip") ) { + kdDebug(4500) << "KGVDocument::uncompressFile(): manually guessing gzip" << endl; + filterDev.reset( KFilterDev::deviceForFile( _fileName, "application/x-gzip", true ) ); + } else if ( (_fileName.right( 4 ) == ".bz2") || mt->is("application/x-bzip2") ) { + kdDebug(4500) << "KGVDocument::uncompressFile(): manually guessing bzip2" << endl; + filterDev.reset( KFilterDev::deviceForFile( _fileName, "application/x-bzip2", true ) ); + } else { + kdDebug( 4500 ) << "KGVDocument::uncompressFile(): Unable to guess " << _fileName << endl; + } + if ( !filterDev.get() ) + return false; + } + if( !filterDev->open( IO_ReadOnly ) ) + { + KMessageBox::error( _part->widget(), + i18n( "Could not uncompress %1." ) + .arg( _fileName ) ); + emit canceled( QString() ); + return false; + } + + _tmpUnzipped = new KTempFile; + Q_CHECK_PTR( _tmpUnzipped ); + if( _tmpUnzipped->status() != 0 ) + { + KMessageBox::error( _part->widget(), + i18n( "Could not create temporary file: %2" ) + .arg( strerror( _tmpUnzipped->status() ) ) ); + emit canceled( QString() ); + return false; + } + + + QByteArray buf( 8192 ); + int read = 0, wrtn = 0; + while( ( read = filterDev->readBlock( buf.data(), buf.size() ) ) + > 0 ) + { + wrtn = _tmpUnzipped->file()->writeBlock( buf.data(), read ); + if( read != wrtn ) + break; + } + + if( read != 0 ) + { + KMessageBox::error( _part->widget(), + i18n( "Could not uncompress %1." ) + .arg( _fileName ) ); + emit canceled( QString() ); + return false; + } + + _tmpUnzipped->close(); + _fileName = _tmpUnzipped->name(); + return true; +} + +void KGVDocument::openPDFFileContinue( bool pdf2dscResult ) +{ + kdDebug(4500) << "KGVDocument::openPDFFileContinue" << endl; + + if( !pdf2dscResult ) + { + KMessageBox::error( _part->widget(), + i18n( "Could not open file %1." ) + .arg( _part->url().url() ) ); + emit canceled( QString() ); + return; + } + + _tmpDSC->close(); + _format = PDF; + + openPSFile(_tmpDSC->name()); +} + +void KGVDocument::openPSFile(const QString &file) +{ + QString fileName = file.isEmpty() ? _fileName : file; + kdDebug(4500) << "KGVDocument::openPSFile (" << fileName << ")" << endl; + + FILE* fp = fopen( QFile::encodeName( fileName ), "r"); + if( fp == 0 ) + { + KMessageBox::error( _part->widget(), + i18n( "Error opening file %1: %2" ) + .arg( _part->url().url() ) + .arg( strerror( errno ) ) ); + emit canceled( "" ); + return; + } + else + { + _psFile = fp; + _isFileOpen = true; + scanDSC(); + emit completed(); + } +} + +void KGVDocument::fileChanged( const QString& name ) +{ + kdDebug(4500) << "KGVDocument: fileChanged " << name << endl; + + if( !_psFile ) + return; + + // unsigned int savepage = _currentPage; + + /* + if( openFile( name ) ) + goToPage( savepage ); + else + emit fileChangeFailed(); + */ +} + +void KGVDocument::scanDSC() +{ + _dsc = new KDSC(); + + // Disable errorDialog for now while KDSCErrorDialog isn't fully + // implemented + // KDSCErrorDialog errorDialog; + // KDSCErrorThreshold errorHandler( 3, &errorDialog ); + // _dsc->setErrorHandler( &errorHandler ); + + char buf[4096]; + int count; + /* + QTime clock; + clock.start(); + */ + while( ( count = fread( buf, sizeof(char), sizeof( buf ), _psFile ) ) != 0 ) + { + _dsc->scanData( buf, count ); + /* + if( clock.elapsed() > 10 ) + { + kapp->processEvents(); + clock.start(); + } + */ + } + _dsc->fixup(); + // _dsc->setErrorHandler( 0 ); +} + +void KGVDocument::close() +{ + _pdf2dsc->kill(); + _isFileOpen = false; + + delete _dsc; + _dsc = 0; + + if( _psFile ) + { + fclose( _psFile ); + _psFile = 0; + } + + clearTemporaryFiles(); +} + +bool KGVDocument::convertFromPDF( const QString& saveFileName, + unsigned int firstPage, + unsigned int lastPage ) +{ + // TODO -- timeout/fail on this conversion (it can hang on a bad pdf) + // TODO -- use output from gs (leave out -q) to drive a progress bar + KProcess process; + process << _interpreterPath + << "-q" + << "-dNOPAUSE" + << "-dBATCH" + << "-dSAFER" + << "-dPARANOIDSAFER" + << "-sDEVICE=pswrite" + << ( QCString("-sOutputFile=")+QFile::encodeName(saveFileName) ) + << ( QString("-dFirstPage=")+QString::number( firstPage ) ) + << ( QString("-dLastPage=")+QString::number( lastPage ) ) + << "-c" + << "save" + << "pop" + << "-f" + << QFile::encodeName(_fileName); + + /*QValueList args = process.args(); + QValueList::Iterator it = args.begin(); + for ( ; it != args.end() ; ++it ) + kdDebug(4500) << ( *it ) << endl;*/ + + if( !process.start( KProcess::Block ) ) + { + kdError() << "convertFromPDF: Couldn't start gs process" << endl; + // TODO -- error message (gs not found?) + return false; + } + if ( !process.normalExit() || process.exitStatus() != 0 ) + { + kdError() << "convertFromPDF: normalExit=" << process.normalExit() << " exitStatus=" << process.exitStatus() << endl; + // TODO -- error message (can't open, strerr()) + return false; + } + + return true; +} + +void KGVDocument::clearTemporaryFiles() +{ + if( _tmpUnzipped ) { + _tmpUnzipped->setAutoDelete( true ); + delete _tmpUnzipped; + _tmpUnzipped = 0; + } + if( _tmpFromPDF ) { + _tmpFromPDF->setAutoDelete( true ); + delete _tmpFromPDF; + _tmpFromPDF = 0; + } + if( _tmpDSC ) { + _tmpDSC->setAutoDelete( true ); + delete _tmpDSC; + _tmpDSC = 0; + } +} + + +/*- DOCUMENT --------------------------------------------------------------*/ + +QStringList KGVDocument::mediaNames() const +{ + QStringList names; + + const CDSCMEDIA* m = dsc_known_media; + while( m->name ) { + names << m->name; + m++; + } + + if( isOpen() && dsc()->media() ) { + for( unsigned int i = 0; i < dsc()->media_count(); i++ ) { + if( dsc()->media()[i] && dsc()->media()[i]->name ) + names << dsc()->media()[i]->name; + } + } + + return names; +} + +const CDSCMEDIA* KGVDocument::findMediaByName( const QString& mediaName ) const +{ + if( !isOpen() ) + return 0; + + if( dsc()->media() ) { + for( unsigned int i = 0; i < dsc()->media_count(); i++ ) { + if( dsc()->media()[i] && dsc()->media()[i]->name + && qstricmp( mediaName.local8Bit(), + dsc()->media()[i]->name ) == 0 ) { + return dsc()->media()[i]; + } + } + } + /* It didn't match %%DocumentPaperSizes: */ + /* Try our known media */ + const CDSCMEDIA *m = dsc_known_media; + while( m->name ) { + if( qstricmp( mediaName.local8Bit(), m->name ) == 0 ) { + return m; + } + m++; + } + + return 0; +} + +QSize KGVDocument::computePageSize( const QString& mediaName ) const +{ + kdDebug(4500) << "KGVDocument::computePageSize( " << mediaName << " )" << endl; + + if( mediaName == "BoundingBox" ) { + if( dsc()->bbox().get() != 0 ) + return dsc()->bbox()->size(); + else + return QSize( 0, 0 ); + } + + const CDSCMEDIA* m = findMediaByName( mediaName ); + Q_ASSERT( m ); + return QSize( static_cast( m->width ), static_cast( m->height ) ); +} + + +/*- PRINTING and SAVING ---------------------------------------------------*/ + +QString KGVDocument::pageListToRange( const PageList& pageList ) +{ + QString range; + + // Iterators marking the begin and end of a successive sequence + // of pages. + PageList::const_iterator bss( pageList.begin() ); + PageList::const_iterator ess; + + PageList::const_iterator it ( pageList.begin() ); + + while( it != pageList.end() ) + { + ess = it++; + + // If ess points to the end of a successive sequence of pages, + // add the stringrepresentation of the sequence to range and + // update bss. + if( it == pageList.end() || *it != (*ess) + 1 ) + { + if( !range.isEmpty() ) + range += ","; + + if( bss == ess ) + range += QString::number( *ess ); + else + range += QString( "%1-%2" ).arg( *bss ).arg( *ess ); + + bss = it; + } + } + + return range; +} + +void KGVDocument::print() +{ + if( !dsc() ) return; + + KPrinter printer; + + if( dsc()->isStructured() ) + { + printer.setPageSelection( KPrinter::ApplicationSide ); + + printer.setCurrentPage( _part->miniWidget()->displayOptions().page() + 1 ); + printer.setMinMax( 1, dsc()->page_count() ); + printer.setOption( "kde-range", + pageListToRange( _part->markList()->markList() ) ); + + if( printer.setup( _part->widget(), i18n("Print %1").arg(_part->url().fileName()) ) ) + { + KTempFile tf( QString::null, ".ps" ); + if( tf.status() == 0 ) + { + if ( printer.pageList().empty() ) { + KMessageBox::sorry( 0, + i18n( "Printing failed because the list of " + "pages to be printed was empty." ), + i18n( "Error Printing" ) ); + } else if ( savePages( tf.name(), printer.pageList() ) ) { + printer.printFiles( QStringList( tf.name() ), true ); + } else { + KMessageBox::error( 0, i18n( "Printing failure:
Could not convert to PostScript
" ) ); + } + } + else + { + // TODO: Proper error handling + ; + } + } + } + else + { + printer.setPageSelection( KPrinter::SystemSide ); + + if( printer.setup( _part->widget(), i18n("Print %1").arg(_part->url().fileName()) ) ) + printer.printFiles( _fileName ); + } +} + +void KGVDocument::saveAs() +{ + if( !isOpen() ) + return; + + KURL saveURL = KFileDialog::getSaveURL( + _part->url().isLocalFile() + ? _part->url().url() + : _part->url().fileName(), + QString::null, + _part->widget(), + QString::null ); + if( !KIO::NetAccess::upload( _fileName, + saveURL, + static_cast( 0 ) ) ) { + // TODO: Proper error dialog + } +} + +bool KGVDocument::savePages( const QString& saveFileName, + const PageList& pageList ) +{ + if( pageList.empty() ) + return true; + + if( _format == PDF ) + { + KTempFile psSaveFile( QString::null, ".ps" ); + psSaveFile.setAutoDelete( true ); + if( psSaveFile.status() != 0 ) + return false; + + // Find the minimum and maximum pagenumber in pageList. + int minPage = pageList.first(), maxPage = pageList.first(); + for( PageList::const_iterator ci = pageList.begin(); + ci != pageList.end(); ++ci ) + { + minPage = QMIN( *ci, minPage ); + maxPage = QMAX( *ci, maxPage ); + } + + + // TODO: Optimize "print whole document" case + // + // The convertion below from PDF to PS creates a temporary file which, in + // the case where we are printing the whole document will then be + // completelly copied to another temporary file. + // + // In very large files, the inefficiency is visible (measured in + // seconds). + // + // luis_pedro 4 Jun 2003 + + + + // Convert the pages in the range [minPage,maxPage] from PDF to + // PostScript. + if( !convertFromPDF( psSaveFile.name(), + minPage, maxPage ) ) + return false; + + // The page minPage in the original file becomes page 1 in the + // converted file. We still have to select the desired pages from + // this file, so we need to take into account that difference. + PageList normedPageList; + transform( pageList.begin(), pageList.end(), + back_inserter( normedPageList ), + bind2nd( minus(), minPage - 1 ) ); + + // Finally select the desired pages from the converted file. + psCopyDoc( psSaveFile.name(), saveFileName, normedPageList ); + } + else + { + psCopyDoc( _fileName, saveFileName, pageList ); + } + + return true; +} + +// length calculates string length at compile time +// can only be used with character constants +#define length( a ) ( sizeof( a ) - 1 ) + +// Copy the headers, marked pages, and trailer to fp + +bool KGVDocument::psCopyDoc( const QString& inputFile, + const QString& outputFile, const PageList& pageList ) +{ + FILE* from; + FILE* to; + char text[ PSLINELENGTH ]; + char* comment; + bool pages_written = false; + bool pages_atend = false; + unsigned int i = 0; + unsigned int pages = 0; + long here; + + kdDebug(4500) << "KGVDocument: Copying pages from " << inputFile << " to " + << outputFile << endl; + + pages = pageList.size(); + + if( pages == 0 ) { + KMessageBox::sorry( 0, + i18n( "Printing failed because the list of " + "pages to be printed was empty." ), + i18n( "Error Printing" ) ); + return false; + } + + from = fopen( QFile::encodeName( inputFile ), "r" ); + to = fopen( QFile::encodeName( outputFile ), "w" ); + + // Hack in order to make printing of PDF files work. FIXME + CDSC* dsc; + + if( _format == PS ) + dsc = _dsc->cdsc(); + else { + FILE* fp = fopen( QFile::encodeName( inputFile ), "r"); + char buf[256]; + int count; + dsc = dsc_init( 0 ); + while( ( count = fread( buf, 1, sizeof( buf ), fp ) ) != 0 ) + dsc_scan_data( dsc, buf, count ); + fclose( fp ); + if( !dsc ) + return false; + + dsc_fixup( dsc ); + } + + here = dsc->begincomments; + while( ( comment = pscopyuntil( from, to, here, + dsc->endcomments, "%%Pages:" ) ) ) { + here = ftell( from ); + if( pages_written || pages_atend ) { + free( comment ); + continue; + } + sscanf( comment + length("%%Pages:" ), "%256s", text ); + text[256] = 0; // Just in case of an overflow + if( strcmp( text, "(atend)" ) == 0 ) { + fputs( comment, to ); + pages_atend = true; + } + else { + switch ( sscanf( comment + length( "%%Pages:" ), "%*d %u", &i ) ) { + case 1: + fprintf( to, "%%%%Pages: %d %d\n", pages, i ); + break; + default: + fprintf( to, "%%%%Pages: %d\n", pages ); + break; + } + pages_written = true; + } + free(comment); + } + pscopy( from, to, dsc->beginpreview, dsc->endpreview ); + pscopy( from, to, dsc->begindefaults, dsc->enddefaults ); + pscopy( from, to, dsc->beginprolog, dsc->endprolog ); + pscopy( from, to, dsc->beginsetup, dsc->endsetup ); + + //TODO -- Check that a all dsc attributes are copied + + unsigned int count = 1; + PageList::const_iterator it; + for( it = pageList.begin(); it != pageList.end(); ++it ) { + i = (*it) - 1; + comment = pscopyuntil( from, to, dsc->page[i].begin, + dsc->page[i].end, "%%Page:" ); + if ( comment ) free( comment ); + fprintf( to, "%%%%Page: %s %d\n", dsc->page[i].label, + count++ ); + pscopy( from, to, -1, dsc->page[i].end ); + } + + here = dsc->begintrailer; + while( ( comment = pscopyuntil( from, to, here, + dsc->endtrailer, "%%Pages:" ) ) ) { + here = ftell( from ); + if ( pages_written ) { + free( comment ); + continue; + } + switch ( sscanf( comment + length( "%%Pages:" ), "%*d %u", &i ) ) { + case 1: + fprintf( to, "%%%%Pages: %d %d\n", pages, i ); + break; + default: + fprintf( to, "%%%%Pages: %d\n", pages ); + break; + } + pages_written = true; + free( comment ); + } + + fclose( from ); + fclose( to ); + + if( _format == PDF ) + dsc_free( dsc ); + + return true; +} + +#undef length + + +/*- Conversion stuff ------------------------------------------------------*/ + +/* +void KGVDocument::runPdf2ps( const QString& pdfName, + const QString& dscName ) +{ + KProcess process; + process << _interpreterPath + << "-dNODISPLAY" + << "-dQUIET" + << QString( "-sPDFname=%1" ).arg( pdfName ) + << QString( "-sDSCnamale locale( "kghostview" ); + _fallBackPageMedia = pageSizeToString( + static_cast< QPrinter::PageSize >( locale.pageSize() ) ); + + _usePageLabels = false; +e=%1" ).arg( dscName ) + << "pdf2dsc.ps" + << "-c" + << "quit"; + + connect( &process, SIGNAL( processExited( KProcess* ) ), + this, SLOT( pdf2psExited( KProcess* ) ) ); + + kdDebug(4500) << "KGVDocument: pdf2ps started" << endl; + process.start( KProcess::NotifyOnExit ); +} + +void KGVDocument::pdf2psExited( KProcess* process ) +{ + kdDebug(4500) << "KGVDocument: pdf2ps exited" << endl; + + emit pdf2psFinished( process.normalExit() && process.exitStatus() != 0 ); +} +*/ + +Pdf2dsc::Pdf2dsc( const QString& ghostscriptPath, QObject* parent, const char* name ) : + QObject( parent, name ), + _process( 0 ), + _ghostscriptPath( ghostscriptPath ) +{} + +Pdf2dsc::~Pdf2dsc() +{ + kill(); +} + +void Pdf2dsc::run( const QString& pdfName, const QString& dscName ) +{ + kill(); + + _process = new KProcess; + *_process << _ghostscriptPath + << "-dSAFER" + << "-dPARANOIDSAFER" + << "-dDELAYSAFER" + << "-dNODISPLAY" + << "-dQUIET" + << QString( "-sPDFname=%1" ).arg( pdfName ) + << QString( "-sDSCname=%1" ).arg( dscName ) + << "-c" + << "<< /PermitFileReading [ PDFname ] /PermitFileWriting [ DSCname ] /PermitFileControl [] >> setuserparams .locksafe" + << "-f" + << "pdf2dsc.ps" + << "-c" + << "quit"; + + connect( _process, SIGNAL( processExited( KProcess* ) ), + this, SLOT( processExited() ) ); + + kdDebug(4500) << "Pdf2dsc: started" << endl; + _process->start( KProcess::NotifyOnExit ); +} + +void Pdf2dsc::kill() +{ + if( _process != 0 ) + { + kdDebug(4500) << "Pdf2dsc: killing current process" << endl; + delete _process; + _process = 0; + } +} + +void Pdf2dsc::processExited() +{ + kdDebug(4500) << "Pdf2dsc: process exited" << endl; + + emit finished( _process->normalExit() && _process->exitStatus() == 0 ); + delete _process; + _process = 0; +} + +#include "kgvdocument.moc" + + +// vim:sw=4:sts=4:ts=8:sta:tw=78:noet diff --git a/kghostview/kgvdocument.h b/kghostview/kgvdocument.h new file mode 100644 index 00000000..960843f8 --- /dev/null +++ b/kghostview/kgvdocument.h @@ -0,0 +1,195 @@ +/** + * Copyright (C) 1997-2003 the KGhostView authors. See file AUTHORS. + * + * 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 __KGV_DOCUMENT_H__ +#define __KGV_DOCUMENT_H__ + +#include +#include +#include + +#include "kgv.h" +#include "dscparse_adapter.h" +#include "kgv_view.h" + +class KPrinter; +class KTempFile; +class Pdf2dsc; + +class KGVDocument : public QObject +{ + Q_OBJECT + +public: + enum Format { PS, PDF }; + + KGVDocument( KGVPart* part, const char* name = 0 ); + ~KGVDocument(); + + void readSettings(); + + /** + * Is a file currently open? + */ + bool isOpen() const; + + /** + * Open the @em local file @p filename asynchronously. + */ + void openFile( const QString& filename, const QString& mimetype ); + + /** + * Close the document. + */ + void close(); + + const QString& fileName() const { return _fileName; } + FILE* psFile() { return _psFile; } + + Format format() const { return _format; } + + /** + * @return the document structure for the current document, or 0 if no + * file is loaded. + */ + KDSC* const dsc() const; + + /** + * A list of page media (sizes). + */ + QStringList mediaNames() const; + + const CDSCMEDIA* findMediaByName( const QString& mediaName ) const; + + QSize computePageSize( const QString& pageMedia ) const; + + static QString pageSizeToString( QPrinter::PageSize ); + + /** + * Returns a QString which contains a range representation of @p pageList. + * Examples: [1,3] -> "1,3" + * [1,2,3] -> "1-3" + * [1,3,4,5,8] -> "1,3-5,8" + */ + static QString pageListToRange( const KGV::PageList& ); + +public slots: + void fileChanged( const QString& ); + + void saveAs(); + void print(); + +signals: + /** + * Emitted if a fileChanged() call fails. + */ + void fileChangeFailed(); + + void completed(); + void canceled( const QString& ); + +protected: + void scanDSC(); + void clearTemporaryFiles(); + + /** + * Tries to uncompress the file. Returns true if it uncompressed the file + * ( it changes _fileName to point to the uncompressed version of the file ). + * Else, it does nothing and returns false. + * + * What type of files this is able to uncompress will depend on the + * kdelibs installed. Generally it will work for .gz and .bz2 + */ + bool uncompressFile(); + void openPSFile(const QString &file=QString::null); + +protected: + bool savePages( const QString& saveFileName, + const KGV::PageList& pageList ); + + bool psCopyDoc( const QString& inputFile, const QString& outputFile, + const KGV::PageList& pageList ); + + bool convertFromPDF( const QString& saveFileName, + unsigned int firstPage, unsigned int lastPage ); + +protected slots: + void doOpenFile(); + void openPDFFileContinue( bool pdf2dscResult ); + +private: + FILE* _psFile; + + QString _fileName; + QString _mimetype; + + KGVPart* _part; + + Format _format; + + KTempFile* _tmpUnzipped; + KTempFile* _tmpFromPDF; + KTempFile* _tmpDSC; + + Pdf2dsc* _pdf2dsc; + + QString _interpreterPath; + + bool _isFileOpen; + + KDSC* _dsc; +}; + + +class Pdf2dsc : public QObject +{ + Q_OBJECT + +public: + Pdf2dsc( const QString& ghostscriptPath, QObject* parent = 0, const char* name = 0 ); + ~Pdf2dsc(); + + void run( const QString& pdfName, const QString& dscName ); + void kill(); + +signals: + void finished( bool result ); + +protected slots: + void processExited(); + +private: + KProcess* _process; + QString _ghostscriptPath; +}; + + +inline KDSC* const KGVDocument::dsc() const +{ + return _dsc; +} + +inline bool KGVDocument::isOpen() const +{ + return _isFileOpen; +} + + +#endif + +// vim:sw=4:sts=4:ts=8:sta:tw=78:noet diff --git a/kghostview/kgvfactory.cpp b/kghostview/kgvfactory.cpp new file mode 100644 index 00000000..edf20144 --- /dev/null +++ b/kghostview/kgvfactory.cpp @@ -0,0 +1,105 @@ +/** + * Copyright (C) 2003, Lus Pedro Coelho, + * based on kdelibs/kparts/genericfactory.h + * + * 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 +#include +#include +#include +#include +#include "kgv_view.h" + +#include "kgvfactory.h" + +KGVFactory::KGVFactory() +{ + if ( s_self ) + kdWarning() << "KGVFactory instantiated more than once!" << endl; + s_self = this; +} + +KGVFactory::~KGVFactory() +{ + delete s_aboutData; + delete s_instance; + s_aboutData = 0; + s_instance = 0; + s_self = 0; +} + +KInstance *KGVFactory::createInstance() +{ + KInstance* res = new KInstance( aboutData() ); + return res; +} + +KGVFactory *KGVFactory::s_self; +KInstance *KGVFactory::s_instance; +KAboutData *KGVFactory::s_aboutData; + +KParts::Part *KGVFactory::createPartObject( QWidget *parentWidget, const char *widgetName, + QObject *parent, const char *name, + const char *className, + const QStringList &args_ ) +{ + QStringList args = args_; + /* Below is the reason why we must + * have our own factory instead of + * typedef KParts::GenericFactory KGVFactory + * + * as we did before. + */ + args << QString::fromLatin1( className ); + if ( !strcmp( className, "Browser/View" ) ) { + className = "KParts::ReadOnlyPart"; + } + KGVPart *part = KDEPrivate::ConcreteFactory::create( parentWidget, + widgetName, + parent, + name, + className, + args ); + + if ( part && !qstrcmp( className, "KParts::ReadOnlyPart" ) ) + { + KParts::ReadWritePart *rwp = dynamic_cast( part ); + if ( rwp ) + rwp->setReadWrite( false ); + } + return part; +} + +KInstance *KGVFactory::instance() +{ + if ( !s_instance ) + { + if ( s_self ) + s_instance = s_self->createInstance(); + else + s_instance = new KInstance( aboutData() ); + } + return s_instance; +} + +KAboutData *KGVFactory::aboutData() +{ + if ( !s_aboutData ) + s_aboutData = KGVPart::createAboutData(); + return s_aboutData; +} + diff --git a/kghostview/kgvfactory.h b/kghostview/kgvfactory.h new file mode 100644 index 00000000..238e3557 --- /dev/null +++ b/kghostview/kgvfactory.h @@ -0,0 +1,50 @@ +/** + * Copyright (C) 2003, Lus Pedro Coelho, + * based on kdelibs/kparts/genericfactory.h + * + * 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 KGVPart_H_INCLUDE_GUARD_ +#define KGVPart_H_INCLUDE_GUARD_ + +#include +#include + +class KInstance; +class KAboutData; + +class KDE_EXPORT KGVFactory : public KParts::Factory +{ + public: + KGVFactory(); + virtual ~KGVFactory(); + static KInstance *instance(); + static KAboutData *aboutData(); + + virtual KParts::Part *createPartObject( QWidget *parentWidget, const char *widgetName, + QObject *parent, const char *name, + const char *className, + const QStringList &args ); + + protected: + virtual KInstance *createInstance(); + private: + static KGVFactory*s_self; + static KInstance *s_instance; + static KAboutData *s_aboutData; +}; + +#endif + diff --git a/kghostview/kgvmainwidget.cpp b/kghostview/kgvmainwidget.cpp new file mode 100644 index 00000000..2bad7f84 --- /dev/null +++ b/kghostview/kgvmainwidget.cpp @@ -0,0 +1,50 @@ +/** + * Copyright (C) 2001-2002 the KGhostView authors. See file AUTHORS. + * + * 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 "kgvmainwidget.h" +#include +#include + +KGVMainWidget::KGVMainWidget( QWidget* parent, const char* name ) + : QWidget( parent, name ) {} + +void KGVMainWidget::keyPressEvent( QKeyEvent* event ) +{ + if( event->key() == Key_Space && event->state() != ShiftButton ) { + event->accept(); + emit spacePressed(); + } +} + +void KGVMainWidget::dropEvent( QDropEvent* ev ) +{ + KURL::List lst; + if ( KURLDrag::decode( ev, lst ) ) { + emit urlDropped( lst.first() ); + } +} + + +void KGVMainWidget::dragEnterEvent( QDragEnterEvent * ev ) +{ + ev->accept(); +} + +#include "kgvmainwidget.moc" + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/kgvmainwidget.h b/kghostview/kgvmainwidget.h new file mode 100644 index 00000000..0e79fbd6 --- /dev/null +++ b/kghostview/kgvmainwidget.h @@ -0,0 +1,45 @@ +/** + * Copyright (C) 2001-2002 the KGhostView authors. See file AUTHORS. + * + * 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 KGVMAINWIDGET_H +#define KGVMAINWIDGET_H + +#include + +class KURL; + +class KGVMainWidget : public QWidget +{ + Q_OBJECT + +public: + KGVMainWidget( QWidget* parent = 0, const char* name = 0 ); + +signals: + void spacePressed(); + void urlDropped( const KURL& ); + +protected: + virtual void keyPressEvent( QKeyEvent* ); + virtual void dragEnterEvent( QDragEnterEvent* ); + virtual void dropEvent( QDropEvent* ); +}; + +#endif + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/kgvpagedecorator.cpp b/kghostview/kgvpagedecorator.cpp new file mode 100644 index 00000000..e1eccfc7 --- /dev/null +++ b/kghostview/kgvpagedecorator.cpp @@ -0,0 +1,106 @@ +/** + * Copyright (C) 2001-2002 the KGhostView authors. See file AUTHORS. + * + * 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 +#include +#include +#include + +#include "kgvpagedecorator.h" + +KGVPageDecorator::KGVPageDecorator( QWidget* parent, const char* name ) : + QHBox( parent, name ), + _margin( 5 ), + _borderWidth( 1 ), + _shadowOffset( 2, 2 ) +{ + setFrameStyle( Box | Plain ); + setLineWidth( _margin + _borderWidth ); + setBackgroundMode( NoBackground ); + setAutoMask( true ); +} + +bool KGVPageDecorator::eventFilter( QObject* o, QEvent* e ) +{ + switch( e->type() ) { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + return event( e ); + default: + ; + } + return QHBox::eventFilter( o, e ); +} + +void KGVPageDecorator::childEvent( QChildEvent* e ) +{ + if( e->child()->isWidgetType() && e->inserted() ) + e->child()->installEventFilter( this ); +} + +void KGVPageDecorator::drawFrame( QPainter* p ) +{ + QRect r( frameRect().topLeft() + QPoint(_margin,_margin), + frameRect().bottomRight() - QPoint(_margin,_margin) ); + + if( !r.isValid() ) + return; + + const QColorGroup& cg = colorGroup(); + + r.moveCenter( r.center() + _shadowOffset ); + qDrawPlainRect( p, r, cg.shadow(), _shadowOffset.manhattanLength() ); + + r.moveCenter( r.center() - _shadowOffset ); + qDrawPlainRect( p, r, cg.foreground(), _borderWidth ); +} + +void KGVPageDecorator::drawMask( QPainter* p ) +{ + QRect r( frameRect().topLeft() + QPoint(_margin,_margin), + frameRect().bottomRight() - QPoint(_margin,_margin) ); + + if( !r.isValid() ) + return; + + QColorGroup cg( color1, color1, color1, color1, color1, color1, color1, + color1, color0 ); + QBrush brush( cg.foreground() ); + + r.moveCenter( r.center() + _shadowOffset ); + qDrawPlainRect( p, r, cg.foreground(), _shadowOffset.manhattanLength() ); + + r.moveCenter( r.center() - _shadowOffset ); + qDrawPlainRect( p, r, cg.foreground(), _borderWidth, &brush ); +} + +void KGVPageDecorator::updateMask() +{ + QBitmap bm( size() ); + bm.fill( color0 ); + QPainter p( &bm, this ); + p.setPen( color1 ); + p.setBrush( color1 ); + drawMask( &p ); + p.end(); + setMask( bm ); +} + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/kgvpagedecorator.h b/kghostview/kgvpagedecorator.h new file mode 100644 index 00000000..72ceb956 --- /dev/null +++ b/kghostview/kgvpagedecorator.h @@ -0,0 +1,81 @@ +/** + * Copyright (C) 2001-2002 the KGhostView authors. See file AUTHORS. + * + * 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 KGVPAGEDECORATOR_H +#define KGVPAGEDECORATOR_H + +#include + +class KGVPageDecorator : public QHBox +{ +public: + KGVPageDecorator( QWidget* parent = 0, const char* name = 0 ); + ~KGVPageDecorator() { ; } + + unsigned int margin() const; + unsigned int borderWidth() const; + + /** + * Reimplemented from QObject to let mouse events from child widgets + * appear to come from this widget. + */ + bool eventFilter( QObject*, QEvent* ); + +protected: + /** + * Reimplemented from QObject to automatically insert an event filter + * on child widgets. + */ + virtual void childEvent( QChildEvent* ); + + /** + * Reimplemented from QFrame to draw a pageshadow like frame. + */ + virtual void drawFrame( QPainter* ); + + /** + * Draw the mask of both the frame and the contents in order to create a + * partially transparent frame. + */ + virtual void drawMask( QPainter* ); + + /** + * Reimplemented from QWidget. It uses @ref drawMask() to draw the mask + * of the frame when transparency is required. + */ + virtual void updateMask(); + +private: + unsigned int _margin; + unsigned int _borderWidth; + QPoint _shadowOffset; +}; + +inline unsigned int KGVPageDecorator::margin() const +{ + return _margin; +} + +inline unsigned int KGVPageDecorator::borderWidth() const +{ + return _borderWidth; +} + +#endif + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/kgvpageview.cpp b/kghostview/kgvpageview.cpp new file mode 100644 index 00000000..8a8af585 --- /dev/null +++ b/kghostview/kgvpageview.cpp @@ -0,0 +1,254 @@ +/** + * Copyright (C) 2001-2002 the KGhostView authors. See file AUTHORS. + * + * 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 + +#include + +#include "kgvpageview.h" + +KGVPageView::KGVPageView( QWidget* parent, const char* name ) + : QScrollView( parent, name ) +{ + _page = 0; + + setFocusPolicy( QWidget::StrongFocus ); + viewport()->setFocusPolicy( QWidget::WheelFocus ); +} + +void KGVPageView::setPage( QWidget* page ) +{ + if( page != 0 ) { + addChild( page ); + centerContents(); + _page = page; + } +} + +bool KGVPageView::atTop() const +{ + return verticalScrollBar()->value() == verticalScrollBar()->minValue(); +} + +bool KGVPageView::atBottom() const +{ + return verticalScrollBar()->value() == verticalScrollBar()->maxValue(); +} + +bool KGVPageView::eventFilter( QObject* o, QEvent* e ) +{ + if ( o == _page && e->type() == QEvent::Resize ) { + // We need to call QScrollView::eventFilter before centerContents, + // otherwise a loop will be introduced. + bool result = QScrollView::eventFilter( o, e ); + centerContents(); + emit pageSizeChanged( _page->size() ); + return result; + } + return QScrollView::eventFilter( o, e ); +} + + +void KGVPageView::wheelEvent( QWheelEvent *e ) +{ + int delta = e->delta(); + e->accept(); + if ((e->state() & ControlButton) == ControlButton) { + if ( e->delta() < 0 ) + emit zoomOut(); + else + emit zoomIn(); + } + else if ( delta <= -120 && atBottom() ) + { + emit ReadDown(); + } + else if ( delta >= 120 && atTop()) + { + emit ReadUp(); + } + + else + QScrollView::wheelEvent( e ); +} +void KGVPageView::mousePressEvent( QMouseEvent * e ) +{ + if ( e->button() & LeftButton ) + { + _dragGrabPos = e -> globalPos(); + setCursor( sizeAllCursor ); + } + else if ( e->button() & MidButton ) + { + emit ReadDown(); + } + else if ( e -> button() & RightButton ) + { + emit rightClick(); + } +} + +void KGVPageView::mouseReleaseEvent( QMouseEvent *e ) +{ + if ( e -> button() & LeftButton ) + { + setCursor( arrowCursor ); + } +} + +void KGVPageView::mouseMoveEvent( QMouseEvent * e ) +{ + if ( e->state() & LeftButton ) + { + QPoint delta = _dragGrabPos - e->globalPos(); + scrollBy( delta.x(), delta.y() ); + _dragGrabPos = e->globalPos(); + } +} + +bool KGVPageView::readUp() +{ + if( atTop() ) + return false; + else { + int newValue = QMAX( verticalScrollBar()->value() - height() + 50, + verticalScrollBar()->minValue() ); + + /* + int step = 10; + int value = verticalScrollBar()->value(); + while( value > newValue - step ) { + verticalScrollBar()->setValue( value ); + value -= step; + } + */ + + verticalScrollBar()->setValue( newValue ); + return true; + } +} + +bool KGVPageView::readDown() +{ + if( atBottom() ) + return false; + else { + int newValue = QMIN( verticalScrollBar()->value() + height() - 50, + verticalScrollBar()->maxValue() ); + + /* + int step = 10; + int value = verticalScrollBar()->value(); + while( value < newValue + step ) { + verticalScrollBar()->setValue( value ); + value += step; + } + */ + + verticalScrollBar()->setValue( newValue ); + return true; + } +} + +void KGVPageView::scrollRight() +{ + horizontalScrollBar()->addLine(); +} + +void KGVPageView::scrollLeft() +{ + horizontalScrollBar()->subtractLine(); +} + +void KGVPageView::scrollDown() +{ + verticalScrollBar()->addLine(); +} + +void KGVPageView::scrollUp() +{ + verticalScrollBar()->subtractLine(); +} + +void KGVPageView::scrollBottom() +{ + verticalScrollBar()->setValue( verticalScrollBar()->maxValue() ); +} + +void KGVPageView::scrollTop() +{ + verticalScrollBar()->setValue( verticalScrollBar()->minValue() ); +} + +void KGVPageView::enableScrollBars( bool b ) +{ + setHScrollBarMode( b ? Auto : AlwaysOff ); + setVScrollBarMode( b ? Auto : AlwaysOff ); +} + +void KGVPageView::keyPressEvent( QKeyEvent* e ) +{ + switch ( e->key() ) { + case Key_Up: + scrollUp(); + break; + case Key_Down: + scrollDown(); + break; + case Key_Left: + scrollLeft(); + break; + case Key_Right: + scrollRight(); + break; + default: + e->ignore(); + return; + } + e->accept(); +} + +void KGVPageView::viewportResizeEvent( QResizeEvent* e ) +{ + QScrollView::viewportResizeEvent( e ); + emit viewSizeChanged( viewport()->size() ); + centerContents(); +} + +void KGVPageView::centerContents() +{ + if( !_page ) + return; + + int newX = 0; + int newY = 0; + + QSize newViewportSize = viewportSize( _page->width(), + _page->height() ); + + if( newViewportSize.width() > _page->width() ) + newX = ( newViewportSize.width() - _page->width() )/2; + if( newViewportSize.height() > _page->height() ) + newY = ( newViewportSize.height() - _page->height() )/2; + + moveChild( _page, newX, newY ); +} + +#include "kgvpageview.moc" + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/kgvpageview.h b/kghostview/kgvpageview.h new file mode 100644 index 00000000..9a1abac3 --- /dev/null +++ b/kghostview/kgvpageview.h @@ -0,0 +1,105 @@ +/** + * Copyright (C) 2001-2002 the KGhostView authors. See file AUTHORS. + * + * 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 KGVPAGEVIEW_H +#define KGVPAGEVIEW_H + +#include + +/** + * KGVPageView is a customized QScrollView, which can hold one page. This page + * will be centered on the viewport. Furthermore it adds the ability to scroll + * the page by dragging it using the mouse. + */ +class KGVPageView : public QScrollView +{ + Q_OBJECT + +public: + KGVPageView( QWidget* parent = 0, const char* name = 0 ); + ~KGVPageView() { ; } + + void setPage( QWidget* ); + QWidget* page() const { return _page; } + + /** + * Return true if the top resp. bottom of the page is visible. + */ + bool atTop() const; + bool atBottom() const; + + /** + * Turn the scrollbars on/off. + */ + void enableScrollBars( bool); + + /** + * @reimplemented + */ + bool eventFilter( QObject*, QEvent* ); + +public slots: + bool readUp(); + bool readDown(); + void scrollUp(); + void scrollDown(); + void scrollRight(); + void scrollLeft(); + void scrollBottom(); + void scrollTop(); + +signals: + void viewSizeChanged( const QSize& ); + void pageSizeChanged( const QSize& ); + void nextPage(); + void zoomOut(); + void zoomIn(); + void prevPage(); + void rightClick(); + void ReadUp(); + void ReadDown(); + +protected: + virtual void keyPressEvent( QKeyEvent* ); + + /** + * Reimplemented to from QScrollView to make sure that the page is centered + * when it fits in the viewport. + */ + virtual void viewportResizeEvent( QResizeEvent* ); + + virtual void mousePressEvent( QMouseEvent *e ); + virtual void mouseReleaseEvent( QMouseEvent *e ); + virtual void mouseMoveEvent( QMouseEvent *e ); + virtual void wheelEvent( QWheelEvent * ); + + /** + * If the viewport is larger than the page, center the page on the + * viewport. + */ + void centerContents(); + +private: + QPoint _dragGrabPos; + QWidget* _page; +}; + +#endif + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/kgvshell.cpp b/kghostview/kgvshell.cpp new file mode 100644 index 00000000..1dc546d5 --- /dev/null +++ b/kghostview/kgvshell.cpp @@ -0,0 +1,370 @@ +/** + * Copyright (C) 2000-2002 the KGhostView authors. See file AUTHORS. + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include "kgv_miniwidget.h" +#include "kgv_view.h" +#include "kgvpageview.h" +#include "displayoptions.h" +#include "fullscreenfilter.h" + +#undef Always // avoid X11/Qt namespace clash +#include "kgvshell.moc" + +//TODO -- disable GUI when no file +//TODO -- don't stay open when no file, go directly to KFileDialog + +KGVShell::KGVShell() : + _tmpFile( 0 ) +{ + m_gvpart = KParts::ComponentFactory::createPartInstanceFromLibrary< KGVPart >( "libkghostviewpart", this, "kgvpart", + this, "kgvpart" ); + + /*---- File -----------------------------------------------------------*/ + openact = + KStdAction::open( this, SLOT( slotFileOpen() ), + actionCollection() ); + recent = + KStdAction::openRecent( this, SLOT( openURL( const KURL& ) ), + actionCollection() ); + KStdAction::print( m_gvpart->document(), SLOT( print() ), + actionCollection() ); + (void) + KStdAction::quit( this, SLOT( slotQuit() ), actionCollection() ); + + /*---- View -----------------------------------------------------------*/ + new KAction( i18n( "&Reload" ), "reload", + KStdAccel::shortcut( KStdAccel::Reload ), + m_gvpart, SLOT( reloadFile() ), + actionCollection(), "reload" ); + new KAction( i18n( "&Maximize" ), Key_M, this, + SLOT( slotMaximize() ), actionCollection(), + "maximize"); + _showMenuBarAction = KStdAction::showMenubar( this, SLOT( slotShowMenubar() ), actionCollection() ); + + /*---- Settings -------------------------------------------------------*/ +#if KDE_VERSION >= KDE_MAKE_VERSION(3,1,90) + createStandardStatusBarAction(); +#endif + setAutoSaveSettings(); + setStandardToolBarMenuEnabled(true); +#if KDE_VERSION >= KDE_MAKE_VERSION(3,1,90) + m_fullScreenAction = KStdAction::fullScreen( this, SLOT( slotUpdateFullScreen() ), actionCollection(), this ); +#else + m_fullScreenAction = new KToggleAction( this, SLOT( slotUpdateFullScreen() ) ); +#endif + KStdAction::configureToolbars( this, SLOT( slotConfigureToolbars() ), actionCollection() ); + KStdAction::keyBindings(guiFactory(), SLOT(configureShortcuts()), +actionCollection()); + + //_popup = new KPopupMenu( i18n( "Full Screen Options" ), this, "rmb popup" ); + _popup = new KPopupMenu( this, "rmb popup" ); + _popup->insertTitle( i18n( "Full Screen Options" ) ); + m_fullScreenAction->plug( _popup ); + _showMenuBarAction->plug( _popup ); + + m_fsFilter = new FullScreenFilter( *this ); + + // Just save them automatically is destructor. (TODO: of kgv_view!) + //KStdAction::saveOptions ( this, SLOT (slotWriteSettings()), actionCollection()); + + setXMLFile( "kghostviewui.rc" ); + + // We could, at the user's option, make this connection and kghostview + // will always resize to fit the width of the page. But, for now, + // let's not. + // connect ( m_gvpart->widget(), SIGNAL (sizeHintChanged()), this, SLOT (slotResize ()) ); + + setCentralWidget( m_gvpart->widget() ); + createGUI( m_gvpart ); + + connect( m_gvpart->pageView(), SIGNAL( rightClick() ),SLOT( slotRMBClick() ) ); + connect( m_gvpart, SIGNAL( canceled(const QString&) ),SLOT( slotReset() ) ); + connect( m_gvpart, SIGNAL( completed() ), SLOT( slotDocumentState() ) ); + + if (!initialGeometrySet()) + resize(640,400); + + readSettings(); + stateChanged( "initState" ); + + // Make sure the view has the keyboard focus. + m_gvpart->widget()->setFocus(); +} + +KGVShell::~KGVShell() +{ + writeSettings(); + + if( _tmpFile ) + { + _tmpFile->setAutoDelete( true ); + delete _tmpFile; + _tmpFile = 0; + } + + // delete m_gvpart; +} + +void +KGVShell::slotQuit() +{ + kapp->closeAllWindows(); +} + +void KGVShell::slotShowMenubar() +{ + if ( _showMenuBarAction->isChecked() ) menuBar()->show(); + else menuBar()->hide(); +} + +void +KGVShell::setDisplayOptions( const DisplayOptions& options ) +{ + m_gvpart->setDisplayOptions( options ); +} + +void KGVShell::slotReset() +{ + kdDebug( 4500 ) << "KGVShell::slotReset()" << endl; + stateChanged( "initState" ); +} + +void +KGVShell::readProperties( KConfig *config ) +{ + KURL url = KURL::fromPathOrURL( config->readPathEntry( "URL" ) ); + if ( url.isValid() ) { + openURL( url ); + DisplayOptions options; + if ( DisplayOptions::fromString( options, config->readEntry( "Display Options" ) ) ) m_gvpart->setDisplayOptions( options ); + } +} + +void +KGVShell::saveProperties( KConfig* config ) +{ + config->writePathEntry( "URL", m_gvpart->url().prettyURL() ); + config->writeEntry( "Display Options", DisplayOptions::toString( m_gvpart->miniWidget()->displayOptions() ) ); +} + +void +KGVShell::readSettings() +{ + recent->loadEntries( KGlobal::config() ); + QStringList items = recent->items(); + +// Code copied from kviewshell.cpp: +// Constant source of annoyance in KDVI < 1.0: the 'recent-files' +// menu contains lots of files which don't exist (any longer). Thus, +// we'll sort out the non-existent files here. + + for ( QStringList::Iterator it = items.begin(); it != items.end(); ++it ) { + KURL url(*it); + if (url.isLocalFile()) { + QFileInfo info(url.path()); + if (!info.exists()) + recent->removeURL(url); + } + } + + applyMainWindowSettings(KGlobal::config(), "MainWindow"); + + KGlobal::config()->setDesktopGroup(); + bool fullScreen = KGlobal::config()->readBoolEntry( "FullScreen", false ); + setFullScreen( fullScreen ); + _showMenuBarAction->setChecked( menuBar()->isVisible() ); +} + +void +KGVShell::writeSettings() +{ + saveMainWindowSettings(KGlobal::config(), "MainWindow"); + + recent->saveEntries( KGlobal::config() ); + + KGlobal::config()->setDesktopGroup(); + KGlobal::config()->writeEntry( "FullScreen", m_fullScreenAction->isChecked()); + + KGlobal::config()->sync(); +} + +void +KGVShell::openURL( const KURL & url ) +{ + if( m_gvpart->openURL( url ) ) recent->addURL (url); +} + +void +KGVShell::openStdin() +{ + if( _tmpFile ) + { + _tmpFile->setAutoDelete( true ); + delete _tmpFile; + } + + _tmpFile = new KTempFile; + _tmpFile->setAutoDelete( true ); + + if( _tmpFile->status() != 0 ) { + KMessageBox::error( this, + i18n( "Could not create temporary file: %1" ) + .arg( strerror( _tmpFile->status() ) ) ); + return; + } + + QByteArray buf( BUFSIZ ); + int read = 0, wrtn = 0; + while( ( read = fread( buf.data(), sizeof(char), buf.size(), stdin ) ) + > 0 ) { + wrtn = _tmpFile->file()->writeBlock( buf.data(), read ); + if( read != wrtn ) + break; + kapp->processEvents(); + } + + if( read != 0 ) { + KMessageBox::error( this, + i18n( "Could not open standard input stream: %1" ) + .arg( strerror( errno ) ) ); + return; + } + + _tmpFile->close(); + + if( m_gvpart->openURL( KURL::fromPathOrURL( _tmpFile->name() ) ) ) setCaption( "stdin" ); +} + +void KGVShell::slotFileOpen() +{ + KURL url = KFileDialog::getOpenURL( cwd, i18n( + "*.ps *.ps.bz2 *.ps.gz *.eps *.eps.gz *.pdf|All Document Files\n" + "*.ps *.ps.bz2 *.ps.gz|PostScript Files\n" + "*.pdf *.pdf.gz *.pdf.bz2|Portable Document Format (PDF) Files\n" + "*.eps *.eps.gz *.eps.bz2|Encapsulated PostScript Files\n" + "*|All Files" ) ); + + if( !url.isEmpty() ) { + openURL( url ); + } +} + +void KGVShell::slotDocumentState() +{ + stateChanged( "documentState" ); +} + + +void KGVShell::slotMaximize() +{ + kdDebug(4500) << "KGVShell::slotMaximize()" << endl; + KWin::setState( winId(), NET::MaxHoriz | NET::MaxVert ); + // If we do it now, it comes to nothing since it would work + // on the current (non-maximized) size + QTimer::singleShot( 800, m_gvpart, SLOT( slotFitToPage() ) ); +} + +void KGVShell::slotResize() +{ + resize( m_gvpart->pageView()->sizeHint().width(), height() ); +} + +void KGVShell::setFullScreen( bool useFullScreen ) +{ + if( useFullScreen ) + showFullScreen(); + else if( isFullScreen()) + showNormal(); +} + +void KGVShell::slotUpdateFullScreen() +{ + if( m_fullScreenAction->isChecked()) + { + menuBar()->hide(); + statusBar()->hide(); + toolBar()->hide(); + m_gvpart->updateFullScreen( true ); + showFullScreen(); + kapp->installEventFilter( m_fsFilter ); + if ( m_gvpart->document()->isOpen() ) + m_gvpart->slotFitToPage(); + } + else + { + kapp->removeEventFilter( m_fsFilter ); + m_gvpart->updateFullScreen( false ); + menuBar()->show(); +#if KDE_VERSION >= KDE_MAKE_VERSION(3,1,90) + KToggleAction *statusbarAction = dynamic_cast(actionCollection()->action(KStdAction::name(KStdAction::ShowStatusbar))); + assert( statusbarAction ); + if (statusbarAction->isChecked()) statusBar()->show(); +#endif + toolBar()->show(); + showNormal(); + } +} + +void KGVShell::slotConfigureToolbars() +{ + saveMainWindowSettings( KGlobal::config(), "MainWindow" ); + KEditToolbar dlg( factory() ); + connect(&dlg,SIGNAL(newToolbarConfig()),this,SLOT(slotNewToolbarConfig())); + dlg.exec(); +} + +void KGVShell::slotNewToolbarConfig() +{ + applyMainWindowSettings( KGlobal::config(), "MainWindow" ); +} + +void KGVShell::slotRMBClick() +{ + _popup->exec( QCursor::pos() ); +} + + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/kgvshell.h b/kghostview/kgvshell.h new file mode 100644 index 00000000..872430c1 --- /dev/null +++ b/kghostview/kgvshell.h @@ -0,0 +1,92 @@ +/** + * Copyright (C) 2000-2002 the KGhostView authors. See file AUTHORS. + * + * 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 __KGVSHELL_H__ +#define __KGVSHELL_H__ + +#include + +#include + +class QTimer; + +class KRecentFilesAction; +class ScrollBox; +class KGVPart; +class KAction; +class KConfig; +class KTempFile; +class KPopupMenu; +class DisplayOptions; +class FullScreenFilter; + +class KDE_EXPORT KGVShell : public KParts::MainWindow +{ + Q_OBJECT + +public: + KGVShell(); + virtual ~KGVShell(); + +public slots: + void openURL( const KURL& url ); + void openStdin(); + void setDisplayOptions( const DisplayOptions& ); + void slotRMBClick(); + +protected slots: + void slotFileOpen(); + void slotShowMenubar(); + void slotQuit(); + void slotMaximize(); + void slotResize(); + void slotUpdateFullScreen(); + void slotReset(); + void slotDocumentState(); + void slotConfigureToolbars(); + void slotNewToolbarConfig(); + +protected: + // session management + virtual void saveProperties( KConfig *config ); + virtual void readProperties( KConfig *config ); + + void readSettings(); + void writeSettings(); + void enableStateDepActions( bool enable ); + void setFullScreen( bool ); + +private: + + friend class FullScreenFilter; + + KGVPart* m_gvpart; + QString cwd; + + KAction* openact; + KToggleAction* _showMenuBarAction; + KToggleAction* m_fullScreenAction; + FullScreenFilter* m_fsFilter; + KPopupMenu* _popup; + KRecentFilesAction* recent; + KTempFile* _tmpFile; // Used for storing data received from stdin +}; + +#endif + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/kpswidget.cpp b/kghostview/kpswidget.cpp new file mode 100644 index 00000000..b51cda5e --- /dev/null +++ b/kghostview/kpswidget.cpp @@ -0,0 +1,530 @@ +/** + * Copyright (C) 2000-2003 the KGhostView authors. See file AUTHORS. + * + * 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 "kpswidget.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "configuration.h" + +#include +#include + +int handler( Display* d, XErrorEvent* e ) +{ + char msg[80], req[80], number[80]; + + XGetErrorText( d, e->error_code, msg, sizeof( msg ) ); + sprintf( number, "%d", e->request_code ); + XGetErrorDatabaseText( d, "XRequest", number, "", + req, sizeof( req ) ); + return 0; +} + +int orientation2angle( CDSC_ORIENTATION_ENUM orientation ) +{ + Q_ASSERT( orientation != CDSC_ORIENT_UNKNOWN ); + + int angle = 0; + + switch( orientation ) + { + case CDSC_ORIENT_UNKNOWN: break; // Catched by Q_ASSERT + case CDSC_PORTRAIT: angle = 0; break; + case CDSC_LANDSCAPE: angle = 90; break; + case CDSC_UPSIDEDOWN: angle = 180; break; + case CDSC_SEASCAPE: angle = 270; break; + } + + return angle; +} + +QCString palette2String( Configuration::EnumPalette::type palette ) +{ + QCString str; + + switch( palette ) + { + case Configuration::EnumPalette::Color: str = "Color"; break; + case Configuration::EnumPalette::Grayscale: str = "Grayscale"; break; + case Configuration::EnumPalette::Monochrome: str = "Monochrome"; break; + default: kdWarning( 4500 ) << "palette2String(): unkown palette" << endl; + str = "Color"; + } + + return str; +} + + +KPSWidget::KPSWidget( QWidget* parent, const char* name ) : + QWidget ( parent, name ), + _gsWindow ( None ), + _usePipe ( false ), + _doubleBuffer ( false ), + _ghostscriptDirty ( false ), + _orientation ( CDSC_PORTRAIT ), + _magnification ( 1 ), + _palette ( Configuration::EnumPalette::Color ), + _widgetDirty ( true ), + _process ( 0 ), + _buffer ( 0 ), + _stdinReady ( false ), + _interpreterBusy ( false ), + _interpreterReady ( false ) +{ + XSetErrorHandler( handler ); + + // Create the Atoms used to communicate with Ghostscript. + const char* const atomNames[] = { "GHOSTVIEW", "GHOSTVIEW_COLORS", + "NEXT", "PAGE", "DONE" }; + XInternAtoms( x11Display(), const_cast( atomNames ), + 5, false, _atoms ); + + // readSettings() TODO +} + +KPSWidget::~KPSWidget() +{ + if ( _buffer ) operator delete( _buffer ); + stopInterpreter(); +} + +bool KPSWidget::isInterpreterReady() const +{ + return isInterpreterRunning() && _interpreterReady; +} + +bool KPSWidget::isInterpreterBusy() const +{ + return _interpreterBusy; +} + +bool KPSWidget::isInterpreterRunning() const +{ + return ( _process && _process->isRunning() ); +} + +bool KPSWidget::nextPage() +{ + if( !isInterpreterReady() ) + return false; + + if( _gsWindow == None ) { + kdDebug(4500) << "communication window unknown!" << endl; + return false; + } + + _interpreterReady = false; + _interpreterBusy = true; + setCursor( waitCursor ); + + XEvent e; + e.xclient.type = ClientMessage; + e.xclient.display = x11Display(); + e.xclient.window = _gsWindow; + e.xclient.message_type = _atoms[NEXT]; + e.xclient.format = 32; + + XSendEvent( x11Display(), _gsWindow, false, 0, &e ); + XFlush( x11Display() ); + return true; +} + + +void KPSWidget::clear() +{ + //_backgroundPixmap.fill(); +} + + +bool KPSWidget::sendPS( FILE* fp, unsigned int begin, unsigned int end ) +{ + kdDebug(4500) << "KPSWidget::sendPS" << endl; + + if( !isInterpreterRunning() ) + return false; + + // Create a new record to add to the queue. + _inputQueue.push( Record( fp, begin, end - begin ) ); + + // Start processing the queue. + if( _stdinReady ) + gs_input(_process); + + return true; +} + +void KPSWidget::setGhostscriptPath( const QString& path ) +{ + kdDebug() << "KPSWidget::setGhostscriptPath( " << path << " )" << endl; + if( _ghostscriptPath != path ) + { + _ghostscriptPath = path; + stopInterpreter(); + _ghostscriptDirty = true; + } +} + +void KPSWidget::setGhostscriptArguments( const QStringList& arguments ) +{ + if( _ghostscriptArguments != arguments ) + { + _ghostscriptArguments = arguments; + stopInterpreter(); + _ghostscriptDirty = true; + } +} + +void KPSWidget::setFileName( const QString& fileName, bool usePipe ) +{ + if(( _fileName != fileName ) || (_usePipe != usePipe)) + { + _usePipe = usePipe; + _fileName = fileName; + stopInterpreter(); + _ghostscriptDirty = true; + } +} + +void KPSWidget::setOrientation( CDSC_ORIENTATION_ENUM orientation ) +{ + if( _orientation != orientation ) + { + _orientation = orientation; + stopInterpreter(); + _widgetDirty = true; + } +} + +void KPSWidget::setBoundingBox( const KDSCBBOX& boundingBox ) +{ + if( _boundingBox != boundingBox ) + { + _boundingBox = boundingBox; + stopInterpreter(); + _widgetDirty = true; + } +} + +void KPSWidget::setMagnification( double magnification ) +{ + if( kAbs( magnification - _magnification ) > 0.0001 ) + { + _magnification = magnification; + stopInterpreter(); + _widgetDirty = true; + } +} + +void KPSWidget::setPalette( Configuration::EnumPalette::type palette ) +{ + if( _palette != palette ) + { + _palette = palette; + stopInterpreter(); + _widgetDirty = true; + } +} + +void KPSWidget::setDoubleBuffering( bool db ) +{ + if( _doubleBuffer != db ) + { + _doubleBuffer = db; + stopInterpreter(); + _widgetDirty = true; + } +} + +namespace { + /* Rounding up is better than normal rounding because it is better to have a pixel too many than one too little. + * If we have one too many, no one will notice. If we have one too little, gs complains. + * + * I have a file which isn't displayed (gs error) without this fix. + */ + inline int round_up( double x ) + { + return static_cast( ceil( x ) ); + } +} + +void KPSWidget::setupWidget() +{ + if( !_widgetDirty ) + return; + + Q_ASSERT( orientation() != CDSC_ORIENT_UNKNOWN ); + + const float dpiX = _magnification * x11AppDpiX(); + const float dpiY = _magnification * x11AppDpiY(); + + int newWidth = 0, newHeight = 0; + if( orientation() == CDSC_PORTRAIT || orientation() == CDSC_UPSIDEDOWN ) + { + newWidth = round_up( boundingBox().width() * dpiX / 72.0 ); + newHeight = round_up( boundingBox().height() * dpiY / 72.0 ); + } + else + { + newWidth = round_up( boundingBox().height() * dpiX / 72.0 ); + newHeight = round_up( boundingBox().width() * dpiY / 72.0 ); + } + + if( newWidth != width() || newHeight != height() ) + { + setEraseColor( white ); + setFixedSize( newWidth, newHeight ); + kapp->processEvents(); + + _backgroundPixmap.resize( size() ); + _backgroundPixmap.fill( white ); + // The line below is needed to work around certain "features" of styles such as liquid + // see bug:61711 for more info (LPC, 20 Aug '03) + setBackgroundOrigin( QWidget::WidgetOrigin ); + setErasePixmap( _backgroundPixmap ); + } + + char data[512]; + + sprintf( data, "%ld %d %d %d %d %d %g %g", + ( _doubleBuffer ? 0 : _backgroundPixmap.handle() ), + orientation2angle( orientation() ), + boundingBox().llx(), boundingBox().lly(), + boundingBox().urx(), boundingBox().ury(), + dpiX, dpiY ); + XChangeProperty( x11Display(), winId(), + _atoms[GHOSTVIEW], + XA_STRING, 8, PropModeReplace, + (unsigned char*) data, strlen( data ) ); + + sprintf( data, "%s %d %d", + palette2String( _palette ).data(), + (int)BlackPixel( x11Display(), DefaultScreen( x11Display() ) ), + (int)WhitePixel( x11Display(), DefaultScreen( x11Display() ) ) ); + XChangeProperty( x11Display(), winId(), + _atoms[GHOSTVIEW_COLORS], + XA_STRING, 8, PropModeReplace, + (unsigned char*) data, strlen( data ) ); + + // Make sure the properties are updated immediately. + XSync( x11Display(), false ); + + repaint(); + + _widgetDirty = false; +} + +bool KPSWidget::startInterpreter() +{ + setupWidget(); + + _process = new KProcess; + if ( _doubleBuffer ) _process->setEnvironment( "GHOSTVIEW", QString( "%1 %2" ).arg( winId() ).arg( _backgroundPixmap.handle() ) ); + else _process->setEnvironment( "GHOSTVIEW", QString::number( winId() ) ); + + *_process << _ghostscriptPath.local8Bit(); + *_process << _ghostscriptArguments; + + if( _usePipe ) + *_process << + // The following two lines are their to ensure that we are allowed to read _fileName + "-dDELAYSAFER" << "-sInputFile="+_fileName << "-c" << + "<< /PermitFileReading [ InputFile ] /PermitFileWriting [] /PermitFileControl [] >> setuserparams .locksafe" << + "-"; + else + *_process << _fileName << "-c" << "quit"; + + connect( _process, SIGNAL( processExited( KProcess* ) ), + this, SLOT( slotProcessExited( KProcess* ) ) ); + connect( _process, SIGNAL( receivedStdout( KProcess*, char*, int ) ), + this, SLOT( gs_output( KProcess*, char*, int ) ) ); + connect( _process, SIGNAL( receivedStderr( KProcess*, char*, int ) ), + this, SLOT( gs_output( KProcess*, char*, int ) ) ); + connect( _process, SIGNAL( wroteStdin( KProcess*) ), + this, SLOT( gs_input( KProcess* ) ) ); + + kapp->flushX(); + + // Finally fire up the interpreter. + kdDebug(4500) << "KPSWidget: starting interpreter" << endl; + if( _process->start( KProcess::NotifyOnExit, + _usePipe ? KProcess::All : KProcess::AllOutput ) ) + { + _interpreterBusy = true; + setCursor( waitCursor ); + + _stdinReady = true; + _interpreterReady = false; + _ghostscriptDirty = false; + + return true; + } + else + { + KMessageBox::error( this, + i18n( "Could not start Ghostscript. This is most likely " + "caused by an incorrectly specified interpreter." ) ); + return false; + } +} + +void KPSWidget::stopInterpreter() +{ + kdDebug(4500) << "KPSWidget::stopInterpreter()" << endl; + // if( !_interpreterBusy ) return; + + if( isInterpreterRunning() ) + _process->kill( SIGHUP ); + + _process = 0; + while ( !_inputQueue.empty() ) _inputQueue.pop(); + + _interpreterBusy = false; + unsetCursor(); +} + +void KPSWidget::interpreterFailed() +{ + stopInterpreter(); +} + +void KPSWidget::slotProcessExited( KProcess* process ) +{ + kdDebug(4500) << "KPSWidget: process exited" << endl; + + if ( process == _process ) + { + kdDebug( 4500 ) << "KPSWidget::slotProcessExited(): looks like it was not a clean exit." << endl; + if ( process->normalExit() ) { + emit ghostscriptError( QString( i18n( "Exited with error code %1." ).arg( process->exitStatus() ) ) ); + } else { + emit ghostscriptError( QString( i18n( "Process killed or crashed." ) ) ); + } + _process = 0; + stopInterpreter(); + unsetCursor(); + } +} + +void KPSWidget::gs_output( KProcess*, char* buffer, int len ) +{ + emit output( buffer, len ); +} + +void KPSWidget::gs_input( KProcess* process ) +{ + kdDebug(4500) << "KPSWidget::gs_input" << endl; + + if (process != _process) + { + kdDebug(4500) << "KPSWidget::gs_input(): process != _process" << endl; + return; + } + _stdinReady = true; + + while( ! _inputQueue.empty() && _inputQueue.front().len == 0 ) _inputQueue.pop(); + if( _inputQueue.empty() ) { + _interpreterReady = true; + return; + } + + Record& current = _inputQueue.front(); + + if ( fseek( current.fp, current.begin, SEEK_SET ) ) { + kdDebug(4500) << "KPSWidget::gs_input(): seek failed!" << endl; + interpreterFailed(); + return; + } + Q_ASSERT( current.len > 0 ); + + const unsigned buffer_size = 4096; + if ( !_buffer ) _buffer = static_cast( operator new( buffer_size ) ); + const int bytesRead = fread( _buffer, sizeof (char), + QMIN( buffer_size, current.len ), + current.fp ); + if( bytesRead > 0 ) + { + current.begin += bytesRead; + current.len -= bytesRead; + if( process && process->writeStdin( _buffer, bytesRead ) ) + _stdinReady = false; + else + interpreterFailed(); + } + else + interpreterFailed(); +} + +void KPSWidget::readSettings() +{ + setGhostscriptPath( Configuration::interpreter() ); + + QStringList arguments; + + if( Configuration::antialiasing() ) + arguments = QStringList::split( " ", Configuration::antialiasingArguments() ); + else + arguments = QStringList::split( " ", Configuration::nonAntialiasingArguments() ); + + if( !Configuration::platformFonts() ) + arguments << "-dNOPLATFONTS"; + + arguments << "-dNOPAUSE" << "-dQUIET" << "-dSAFER" << "-dPARANOIDSAFER"; + + setGhostscriptArguments( arguments ); + + setPalette( static_cast( Configuration::palette() ) ); +} + +bool KPSWidget::x11Event( XEvent* e ) +{ + if( e->type == ClientMessage ) + { + _gsWindow = e->xclient.data.l[0]; + + if( e->xclient.message_type == _atoms[PAGE] ) + { + kdDebug(4500) << "KPSWidget: received PAGE" << endl; + _interpreterBusy = false; + unsetCursor(); + emit newPageImage( _backgroundPixmap ); + if ( _doubleBuffer ) setErasePixmap( _backgroundPixmap ); + return true; + } + else if( e->xclient.message_type == _atoms[DONE] ) + { + kdDebug(4500) << "KPSWidget: received DONE" << endl; + stopInterpreter(); + return true; + } + } + return QWidget::x11Event( e ); +} + +#include "kpswidget.moc" + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/kpswidget.h b/kghostview/kpswidget.h new file mode 100644 index 00000000..66ef0b14 --- /dev/null +++ b/kghostview/kpswidget.h @@ -0,0 +1,387 @@ +/** + * Copyright (C) 2000-2003 the KGhostView authors. See file AUTHORS. + * + * 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 __KPSWIDGET_H__ +#define __KPSWIDGET_H__ + +#include +#include +#include +#include +#include + +#include "dscparse_adapter.h" +#include "configuration.h" + +#include + +class KProcess; + +class KGVConfigDialog; +class MessagesDialog; + +/** + * @class KPSWidget + * + * @brief KPSWidget is a widget on which Ghostscript can render. + * + * @ref ghostscript_interface + */ + +class KPSWidget : public QWidget +{ + Q_OBJECT + +public: + KPSWidget( QWidget* parent = 0, const char* name = 0 ); + ~KPSWidget(); + + /** + * Start up the Ghostscript interpreter. Returns true if Ghostscript + * could be started; otherwise false. + */ + bool startInterpreter(); + + /** + * Stop the interpreter process. + */ + void stopInterpreter(); + + /** + * Returns true if the interpreter is ready for new input. + */ + bool isInterpreterReady() const; + + bool isInterpreterBusy() const; + + /** + * Returns true if the interpreter is running; otherwise returns false. + */ + bool isInterpreterRunning() const; + + /** + * Tell ghostscript to start the next page. + * Returns false if ghostscript is not running, or not ready to start + * another page. If another page is started, sets the _interpreterReady + * flag and cursor. + */ + bool nextPage(); + + /** + * Queue a portion of a PostScript file for output to ghostscript and + * start processing the queue. + * + * fp: FILE* of the file in question. Should be seek()able. + * begin: position in file to start. + * len: number of bytes to write. + * + * If an interpreter is not running, nothing is queued and false is + * returned. + */ + bool sendPS( FILE*, unsigned int begin, unsigned int end ); + + /** + * Sets the filename of the ghostscript input. + * @p usePipe indicates whether we use a pipe for + * communication or let ghoscript read the file itself. + */ + void setFileName( const QString&, bool usePipe ); + + /** + * Set the bounding box of the drawable. See my comment in the source + * file. + */ + void setBoundingBox( const KDSCBBOX& ); + + /** + * Set the orientation of the page. + */ + void setOrientation( CDSC_ORIENTATION_ENUM ); + + /** + * Sets the resolution according to the physical resolution of the screen + * and the magnification value. + */ + void setMagnification( double magnification ); + + /** + * @return the boundingbox of the drawable. + */ + const KDSCBBOX& boundingBox() const; + + /** + * @return the current orientation. + */ + CDSC_ORIENTATION_ENUM orientation() const; + + /** + * Double buffering means that all the drawing is done outside the + * screen and the finished picture is then flashed to the screen. + * This reduces flicker ( to almost none ) at the price of speed. + * + * By default, KPSWidget is *not* double buffered. + */ + bool isDoubleBuffered() const { return _doubleBuffer; } + void setDoubleBuffering( bool n ); + + + void clear(); + +public slots: + /** + * Call this when the settings have changed. + */ + void readSettings(); +signals: + /** + * This signal gets emited whenever a page is finished, but contains a reference to the pixmap + * used to hold the image. + * + * Don't change the pixmap or bad things will happen. This is the backing pixmap of the display. + */ + void newPageImage( QPixmap image ); + + /** + * This signal is emitted whenever the ghostscript process has + * written data to stdout or stderr. + */ + void output( char* data, int len ); + + /** + * This means that gs exited uncleanly + * + * @param msg a translated error message to display the user which may be null if we cannot tell anything important + */ + void ghostscriptError( const QString& mgs ); + +protected: + struct Record + { + Record( FILE* fp_, long begin_, unsigned len_ ) + :fp( fp_ ), begin( begin_ ), len( len_ ) { } + + FILE* fp; + long begin; + unsigned int len; + }; + + // void resizeEvent( QResizeEvent* ); + bool x11Event( XEvent* ); + + /** + * Setup the widget according to the current settings for the + * boundingBox, the resolution and the orientation. This involves + * the following things: + * - Resize the widget + * - Resize and clear the background pixmap. + * - Setup the GHOSTVIEW and GHOSTVIEW_COLORS properties. + * + * Make sure ghostscript isn't running when calling this method. + */ + void setupWidget(); + + void setGhostscriptPath( const QString& ); + void setGhostscriptArguments( const QStringList& ); + void setPalette( Configuration::EnumPalette::type ); + +protected slots: + void gs_input( KProcess* ); + void gs_output( KProcess*, char* buffer, int len ); + void interpreterFailed(); + void slotProcessExited( KProcess* ); + +private: + Window _gsWindow; // Destination of ghostscript messages. + + enum AtomName { GHOSTVIEW = 0, GHOSTVIEW_COLORS, NEXT, PAGE, DONE }; + Atom _atoms[5]; + + QPixmap _backgroundPixmap; + + /** + * The following properties determine how Ghostscript is started. + * If any of these is changed, Ghostscript needs to be restarted. + */ + QString _ghostscriptPath; + QStringList _ghostscriptArguments; + QString _fileName; + bool _usePipe; + bool _doubleBuffer; + + /** + * Flag set when one of the properties _ghostscriptPath, + * _ghostscriptArguments or _fileName has been changed. + */ + bool _ghostscriptDirty; + + /** + * The following properties determine how Ghostscript renders its + * pages. If any of these is changed, the widget needs to be setup, + * and Ghostscript needs to be restarted. + */ + CDSC_ORIENTATION_ENUM _orientation; + KDSCBBOX _boundingBox; + float _magnification; + Configuration::EnumPalette::type _palette; + + /** + * Flag set when one of the properties _orientation, _boundingBox, + * _dpi[X|Y] or _palette has been changed. + */ + bool _widgetDirty; + + KProcess* _process; + char* _buffer; + + std::queue _inputQueue; + + bool _stdinReady; + bool _interpreterBusy; + bool _interpreterReady; +}; + +inline const KDSCBBOX& KPSWidget::boundingBox() const +{ + return _boundingBox; +} + +inline CDSC_ORIENTATION_ENUM KPSWidget::orientation() const +{ + return _orientation; +} + +/** + * @page ghostview_interface Ghostview interface to Ghostscript + * + * When the GHOSTVIEW environment variable is set, Ghostscript draws on + * an existing drawable rather than creating its own window. Ghostscript + * can be directed to draw on either a window or a pixmap. + * + * + * @section window Drawing on a Window + * + * The GHOSTVIEW environment variable contains the window id of the target + * window. The window id is an integer. Ghostscript will use the attributes + * of the window to obtain the width, height, colormap, screen, and visual of + * the window. The remainder of the information is gotten from the GHOSTVIEW + * property on that window. + * + * + * @section pixmap Drawing on a Pixmap + * + * The GHOSTVIEW environment variable contains a window id and a pixmap id. + * They are integers separated by white space. Ghostscript will use the + * attributes of the window to obtain the colormap, screen, and visual to use. + * The width and height will be obtained from the pixmap. The remainder of the + * information, is gotten from the GHOSTVIEW property on the window. In this + * case, the property is deleted when read. + * + * + * @section gv_variable The GHOSTVIEW environment variable + * + * @par parameters: + * window-id [pixmap-id] + * + * @par scanf format: + * @code "%d %d" @endcode + * + * @par Explanation of the parameters + * @li @e window-id: + * tells Ghostscript where to: + * - read the GHOSTVIEW property + * - send events + * If pixmap-id is not present, Ghostscript will draw on this window. + * + * @li @e pixmap-id: + * If present, tells Ghostscript that a pixmap will be used as the + * final destination for drawing. The window will not be touched for + * drawing purposes. + * + * + * @section gv_property The GHOSTVIEW property + * + * @par type: + * STRING + * + * @par parameters: + * bpixmap orient llx lly urx ury xdpi ydpi [left bottom top right] + * + * + * @par scanf format: + * @code "%d %d %d %d %d %d %f %f %d %d %d %d" @endcode + * + * @par Explanation of the parameters + * @li @e bpixmap: + * pixmap id of the backing pixmap for the window. If no pixmap is to + * be used, this parameter should be zero. This parameter must be zero + * when drawing on a pixmap. + * + * @li orient: + * orientation of the page. The number represents clockwise rotation + * of the paper in degrees. Permitted values are 0, 90, 180, 270. + * + * @li llx, lly, urx, ury: + * Bounding box of the drawable. The bounding box is specified in + * PostScript points in default user coordinates. (Note the word + * @e drawable. This means that this bounding box is generally not + * the same as the BoundingBox specified in the DSC. In case + * DocumentMedia is specified, it is equal to the Media's bounding + * box.) + * + * @li xdpi, ydpi: + * Resolution of window. (This can be derived from the other + * parameters, but not without roundoff error. These values are + * included to avoid this error.) + * + * @li left, bottom, top, right (optional): + * Margins around the window. The margins extend the imageable area + * beyond the boundaries of the window. This is primarily used for + * popup zoom windows. I have encountered several instances of + * PostScript programs that position themselves with respect to the + * imageable area. The margins are specified in PostScript points. + * If omitted, the margins are assumed to be 0. + * + * + * @section events Events from Ghostscript + * + * If the final destination is a pixmap, the client will get a property + * notify event when Ghostscript reads the GHOSTVIEW property causing it to + * be deleted. + * + * Ghostscript sends events to the window where it read the GHOSTVIEW + * property. These events are of type ClientMessage. The message_type is set + * to either PAGE or DONE. The first long data value gives the window to be + * used to send replies to Ghostscript. The second long data value gives the + * primary drawable. If rendering to a pixmap, it is the primary drawable. + * If rendering to a window, the backing pixmap is the primary drawable. If + * no backing pixmap is employed, then the window is the primary drawable. + * This field is necessary to distinguish multiple Ghostscripts rendering to + * separate pixmaps where the GHOSTVIEW property was placed on the same + * window. + * + * The PAGE message indicates that a "page" has completed. Ghostscript will + * wait until it receives a ClientMessage whose message_type is NEXT before + * continuing. + * + * The DONE message indicates that Ghostscript has finished processing. + */ + +#endif // __KPSWIDGET_H__ + + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/logwindow.cpp b/kghostview/logwindow.cpp new file mode 100644 index 00000000..df2e5765 --- /dev/null +++ b/kghostview/logwindow.cpp @@ -0,0 +1,76 @@ +/** + * Copyright (C) 2003 the KGhostView authors. See file AUTHORS. + * + * 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 +#include +#include + +#include +#include +#include + +#include "logwindow.h" + +LogWindow::LogWindow( const QString& caption, + QWidget* parent, const char* name) : + KDialogBase( parent, name, false, caption, User1|Close, Close, false, + KStdGuiItem::clear() ) +{ + QVBox * display = makeVBoxMainWidget(); + + _errorIndication = new QLabel( "", display, "logview-label" ); + _errorIndication->hide(); + + _configureGS = new KURLLabel( i18n( "Configure Ghostscript" ), QString::null, display ); + _configureGS->hide(); + + _logView = new QTextEdit( display, "logview" ); + _logView->setTextFormat( Qt::PlainText ); + _logView->setReadOnly( true ); + _logView->setWordWrap( QTextEdit::NoWrap ); + _logView->setFont( KGlobalSettings::fixedFont() ); + _logView->setMinimumWidth( 80 * fontMetrics().width( " " ) ); + + connect( this, SIGNAL( user1Clicked() ), SLOT( clear() ) ); + connect( _configureGS, SIGNAL( leftClickedURL() ), SLOT( emitConfigureGS() ) ); +} + +void LogWindow::emitConfigureGS() { + emit configureGS(); +} + +void LogWindow::append( const QString& message ) +{ + _logView->append( message ); +} + +void LogWindow::clear() +{ + _logView->clear(); + _errorIndication->clear(); +} + +void LogWindow::setLabel( const QString& text, bool showConfigureGS ) +{ + _errorIndication->setText( text ); + _errorIndication->show(); + if ( showConfigureGS ) _configureGS->show(); + else _configureGS->hide(); +} + +#include "logwindow.moc" diff --git a/kghostview/logwindow.h b/kghostview/logwindow.h new file mode 100644 index 00000000..4eb099e0 --- /dev/null +++ b/kghostview/logwindow.h @@ -0,0 +1,55 @@ +/** + * Copyright (C) 2003 the KGhostView authors. See file AUTHORS. + * + * 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 LOGWINDOW_H +#define LOGWINDOW_H + +#include + +class QLabel; +class QTextEdit; +class KURLLabel; + +class LogWindow : public KDialogBase +{ + Q_OBJECT + +public: + LogWindow( const QString& caption, + QWidget* parent = 0, const char* name = 0 ); + +public slots: + void append( const QString& message ); + void clear(); + void setLabel( const QString&, bool showConfigureGSLink ); + +private slots: + void emitConfigureGS(); + +signals: + void configureGS(); + +private: + QLabel* _errorIndication; + QTextEdit* _logView; + KURLLabel* _configureGS; +}; + +#endif + +// vim:sw=4:sts=4:ts=8:sta:tw=78:noet diff --git a/kghostview/main.cpp b/kghostview/main.cpp new file mode 100644 index 00000000..26574ddf --- /dev/null +++ b/kghostview/main.cpp @@ -0,0 +1,71 @@ +/** + * Copyright (C) 1997-2002 the KGhostView authors. See file AUTHORS. + * + * 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 + +#include +#include +#include +#include +#include + +#include "kgvshell.h" +#include "kgv_view.h" +#include "displayoptions.h" + +static KCmdLineOptions options[] = +{ + { "page ", I18N_NOOP( "Page to open. Use --page=3 to show the third page, for example. Note that if the page does not exist, any other page may be displayed" ), "1" }, + { "scale ", I18N_NOOP( "Magnification of the display" ), "1.0" }, + { "orientation ", I18N_NOOP( "The orientation of the shown image. Use either \"auto\", \"portrait\", \"landscape\", \"upsidedown\" or \"seascape\"" ), "auto" }, + { "portrait", I18N_NOOP( "Equivalent to orientation=portrait" ), 0 }, + { "landscape", I18N_NOOP( "Equivalent to orientation=landscape" ), 0 }, + { "upsidedown", I18N_NOOP( "Equivalent to orientation=upsidedown" ), 0 }, + { "seascape", I18N_NOOP( "Equivalent to orientation=seascape" ), 0 }, + // { "watch", I18N_NOOP( "Turns on watching of a file. This means that whenever the file changes while you are viewing it, kghostview automatically reloads it. This option (which can also be turned on in the menu) is especially useful if you are generating your files from latex or a similar tool." ), 0 }, + // { "page-size", I18N_NOOP( "The page size.\nUse either something like \"A4\" or you can display exact pixel size width-height" ), "auto" } + { "+[URL]", I18N_NOOP( "Location to open" ), 0 }, + KCmdLineLastOption +}; + +int main( int argc, char** argv ) +{ + KCmdLineArgs::init( argc, argv, KGVPart::createAboutData() ); + KCmdLineArgs::addCmdLineOptions( options ); + KApplication app; + KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); + + if( kapp->isRestored() ) + RESTORE( KGVShell ) + else { + KGVShell* shell = new KGVShell; + if( args->count() == 1 ) { + if( QString( args->arg(0) ) == "-" ) { + shell->openStdin(); + } else { + shell->openURL( args->url(0) ); + } + shell->setDisplayOptions( DisplayOptions::parse( args ) ); + } + shell->show(); + } + args->clear(); + return app.exec(); +} + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/marklist.cpp b/kghostview/marklist.cpp new file mode 100644 index 00000000..674630ed --- /dev/null +++ b/kghostview/marklist.cpp @@ -0,0 +1,242 @@ +/** + * Copyright (C) 1997-2002 the KGhostView authors. See file AUTHORS. + * + * 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 "marklist.moc" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "kgv_miniwidget.h" + +MarkListItem::MarkListItem(QWidget *parent, const QString &text, const QString &tip, const QColor &color, KGVMiniWidget* miniW, int pageNum) + : QWidget( parent ), + _miniWidget( miniW ), + _pageNum( pageNum ), + _requested( false ) +{ + //kdDebug( 4500 ) << "MarkListItem::MarkListItem( _ , " << text <<" , " << tip << " , " << color << ", _ ," << pageNum << " )" << endl; + QBoxLayout *l = new QVBoxLayout( this, 5, 0 ); + _thumbnailW = new QWidget( this ); + _checkBox = new QCheckBox( text, this ); + l->addWidget( _thumbnailW, 1 ); + l->addWidget( _checkBox, 0, Qt::AlignHCenter ); + QWhatsThis::add( _checkBox, i18n( "Using this checkbox you can select pages for printing." ) ); + setFixedHeight( 100 ); + _backgroundColor = color; + setPaletteBackgroundColor( _backgroundColor ); + QToolTip::add(this, tip); + // TODO: Put a little page number or other place-holder when there is no thumbnail to display. +} + +bool MarkListItem::isChecked() const +{ + return _checkBox->isChecked(); +} + +void MarkListItem::toggle() +{ + _checkBox->toggle(); +} + +void MarkListItem::setChecked( bool checked ) +{ + _checkBox->setChecked(checked); +} + +void MarkListItem::setPixmap( QPixmap thumbnail ) +{ + // The line below is needed to work around certain "features" of styles such as liquid + // see bug:61711 for more info (LPC, 20 Aug '03) + _thumbnailW->setBackgroundOrigin( QWidget::WidgetOrigin ); + _thumbnailW->setPaletteBackgroundPixmap( thumbnail.convertToImage().smoothScale( _thumbnailW->size() ) ); + _requested = false; +} + +void MarkListItem::setSelected( bool selected ) +{ + if (selected) + setPaletteBackgroundColor( QApplication::palette().active().highlight() ); + else + setPaletteBackgroundColor( _backgroundColor ); +} + +void MarkListItem::resizeEvent( QResizeEvent * ) +{ + if ( _thumbnailW->paletteBackgroundPixmap() ) + _thumbnailW->setPaletteBackgroundPixmap( _thumbnailW->paletteBackgroundPixmap()->convertToImage().smoothScale( _thumbnailW->size() ) ); +} + +void MarkListItem::paintEvent( QPaintEvent* ) +{ + /* TODO: + * We should cancel things which flipped into view and then flipped out. + * + * Now, if one scrolls through a 1000 page document to the end and then lingers on the + * last pages, these will take forever to appear in thumbnail form. + */ + if ( _requested ) return; + if ( !_thumbnailW->paletteBackgroundPixmap() || _thumbnailW->paletteBackgroundPixmap()->isNull() ) { + _miniWidget->getThumbnailService()->delayedGetThumbnail( _pageNum, this, SLOT( setPixmap( QPixmap ) ) ); + _requested = true; + } +} + + +/* MarkList */ + +MarkList::MarkList( QWidget* parent, const char* name, KGVMiniWidget* mini) + : QTable( parent, name ), + _selected ( -1 ), +_miniWidget( mini ) +{ + setNumCols( 1 ); + setLeftMargin( 0 ); // we don't want the vertical header + horizontalHeader()->setLabel( 0, i18n("Page") ); + + connect( this, SIGNAL( currentChanged( int, int ) ), + this, SIGNAL( selected( int ) ) ); +} + +QValueList MarkList::markList() const +{ + QValueList list; + MarkListItem *_item; + for(int i = 0; i < numRows(); i++) + { + _item = dynamic_cast( cellWidget( i, 0 ) ); + assert( _item ); + if ( _item->isChecked() ) list << (i + 1); + } + return list; +} + +void MarkList::insertItem( const QString& text, int index, const QString& tip) +{ + MarkListItem *_item; + _item = new MarkListItem( this, text, tip, viewport()->paletteBackgroundColor(), _miniWidget, index ); + setNumRows( index + 1 ); + setCellWidget( index, 0, _item ); + setRowHeight( index, _item->height() ); +} + +void MarkList::select( int index ) +{ + MarkListItem *_item; + setCurrentCell( index, 0 ); + _item = dynamic_cast( cellWidget( _selected, 0 ) ); + if (_item) _item -> setSelected( false ); + _selected = index; + _item = dynamic_cast( cellWidget( _selected, 0 ) ); + if (_item) _item -> setSelected( true ); + clearFocus(); +} + +void MarkList::clear() +{ + for ( int i = 0; i != numRows() ; ++i ) { + clearCellWidget( i, 0 ); + } + setNumRows( 0 ); +} + +void MarkList::markCurrent() +{ + MarkListItem *_item = dynamic_cast( cellWidget( currentRow(), 0 ) ); + assert( _item ); + _item->toggle(); +} + +void MarkList::markAll() +{ + MarkListItem *_item; + for(int i = 0; i < numRows(); i++) + { + _item = dynamic_cast( cellWidget( i, 0 ) ); + assert( _item ); + _item->setChecked( true ); + } +} + +void MarkList::markEven() +{ + MarkListItem *_item; + for(int i = 1; i < numRows(); i = i + 2) + { + _item = dynamic_cast( cellWidget( i, 0 ) ); + assert( _item ); + _item->setChecked( true ); + } +} + +void MarkList::markOdd() +{ + MarkListItem *_item; + for(int i = 0; i < numRows(); i = i + 2) + { + _item = dynamic_cast( cellWidget( i, 0 ) ); + assert( _item ); + _item->setChecked( true ); + } +} + +void MarkList::toggleMarks() +{ + MarkListItem *_item; + for(int i = 0; i < numRows(); i++) + { + _item = dynamic_cast( cellWidget( i, 0 ) ); + assert( _item ); + _item->toggle(); + } +} + +void MarkList::removeMarks() +{ + MarkListItem *_item; + for( int i = 0; i < numRows(); i++ ) { + _item = dynamic_cast( cellWidget( i, 0 ) ); + assert( _item ); + _item->setChecked( false ); + } +} + +void MarkList::viewportResizeEvent ( QResizeEvent * ) +{ + MarkListItem *_item; + if( visibleWidth() != columnWidth( 0 ) ) + { + setColumnWidth( 0, visibleWidth() ); + for( int i = 0; i < numRows(); ++i ) + { + _item = dynamic_cast( cellWidget( i, 0 ) ); + assert( _item ); + _item->setFixedSize( visibleWidth(), _item->height() ); + } + } +} + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/marklist.h b/kghostview/marklist.h new file mode 100644 index 00000000..18589af3 --- /dev/null +++ b/kghostview/marklist.h @@ -0,0 +1,88 @@ +/** + * Copyright (C) 1997-2002 the KGhostView authors. See file AUTHORS. + * + * 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 MARKLIST_H +#define MARKLIST_H + +#include +#include + +class KGVMiniWidget; + +class MarkListItem : public QWidget +{ + Q_OBJECT +public: + MarkListItem( QWidget *parent, const QString &text, const QString &tip, const QColor &color, KGVMiniWidget*, int ); + + bool isChecked() const; + +public slots: + void toggle(); + void setChecked( bool checked ); + void setPixmap( QPixmap thumbnail ); + + void setSelected( bool selected ); + +private: + void resizeEvent( QResizeEvent * ); + void paintEvent( QPaintEvent* ); +private: + QWidget *_thumbnailW; + QCheckBox *_checkBox; + QColor _backgroundColor; + KGVMiniWidget* _miniWidget; + const int _pageNum; + bool _requested; +}; + +class MarkList: public QTable +{ + Q_OBJECT + +public: + MarkList( QWidget* parent = 0, const char* name = 0, KGVMiniWidget* = 0 ); + + QValueList markList() const; + void insertItem( const QString& text, int index = -1, + const QString& tip = QString::null ); + +public slots: + void select( int index ); + void markCurrent(); + void markAll(); + void markEven(); + void markOdd(); + void toggleMarks(); + void removeMarks(); + void clear(); + +protected: + virtual void viewportResizeEvent ( QResizeEvent * ); + +signals: + void selected( int ); + +private: + int _selected; + KGVMiniWidget* _miniWidget; +}; + +#endif + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/part_init.cpp b/kghostview/part_init.cpp new file mode 100644 index 00000000..76036948 --- /dev/null +++ b/kghostview/part_init.cpp @@ -0,0 +1,22 @@ +// part_init.cpp +// Copyright (C) 2004 Dominique Devriese + +// 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 "kgvfactory.h" + +K_EXPORT_COMPONENT_FACTORY( libkghostviewpart, KGVFactory ) + diff --git a/kghostview/ps.c b/kghostview/ps.c new file mode 100644 index 00000000..1ff4effa --- /dev/null +++ b/kghostview/ps.c @@ -0,0 +1,188 @@ +/* + * ps.c -- Postscript scanning and copying routines. + * Copyright (C) 1992 Timothy O. Theisen + * + * 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. + * + * Author: Tim Theisen Systems Programmer + * Internet: tim@cs.wisc.edu Department of Computer Sciences + * UUCP: uwvax!tim University of Wisconsin-Madison + * Phone: (608)262-0438 1210 West Dayton Street + * FAX: (608)262-9777 Madison, WI 53706 + */ + +#include +#include +#include + +#include "ps.h" + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif +#ifndef BUFSIZ +#define BUFSIZ 1024 +#endif + +/* length calculates string length at compile time */ +/* can only be used with character constants */ +#define length(a) (sizeof(a)-1) +#define iscomment(a, b) (strncmp(a, b, length(b)) == 0) +#define DSCcomment(a) (a[0] == '%' && a[1] == '%') + +/* + * pscopy -- copy lines of Postscript from a section of one file + * to another file. + * Automatically switch to binary copying whenever + * %%BeginBinary/%%EndBinary or %%BeginData/%%EndData + * comments are encountered. + */ + +void +pscopy(from, to, begin, end) + FILE *from; + FILE *to; + long begin; /* set negative to avoid initial seek */ + long end; +{ + char line[PSLINELENGTH]; /* 255 characters + 1 newline + 1 NULL */ + char text[PSLINELENGTH]; /* Temporary storage for text */ + unsigned int num; + unsigned int i; + char buf[BUFSIZ]; + + if (begin >= 0) fseek(from, begin, SEEK_SET); + while (ftell(from) < end) { + + fgets(line, sizeof line, from); + fputs(line, to); + + if (!(DSCcomment(line) && iscomment(line+2, "Begin"))) { + /* Do nothing */ + } else if (iscomment(line+7, "Data:")) { + int rc = 0; + text[0] = '\0'; + rc = sscanf(line+length("%%BeginData:"), "%d %*s %256s", &num,text); + text[256] = '\0'; + if (rc >= 1) { + if (strcmp(text, "Lines") == 0) { + for (i=0; i < num; i++) { + fgets(line, sizeof line, from); + fputs(line, to); + } + } else { + while (num > BUFSIZ) { + fread(buf, sizeof (char), BUFSIZ, from); + fwrite(buf, sizeof (char), BUFSIZ, to); + num -= BUFSIZ; + } + fread(buf, sizeof (char), num, from); + fwrite(buf, sizeof (char), num, to); + } + } + } else if (iscomment(line+7, "Binary:")) { + if(sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) { + while (num > BUFSIZ) { + fread(buf, sizeof (char), BUFSIZ, from); + fwrite(buf, sizeof (char), BUFSIZ, to); + num -= BUFSIZ; + } + fread(buf, sizeof (char), num, from); + fwrite(buf, sizeof (char), num, to); + } + } + } +} + +/* + * pscopyuntil -- copy lines of Postscript from a section of one file + * to another file until a particular comment is reached. + * Automatically switch to binary copying whenever + * %%BeginBinary/%%EndBinary or %%BeginData/%%EndData + * comments are encountered. + */ + +char * +pscopyuntil(from, to, begin, end, comment) + FILE *from; + FILE *to; + long begin; /* set negative to avoid initial seek */ + long end; + const char *comment; +{ + char line[PSLINELENGTH]; /* 255 characters + 1 newline + 1 NULL */ + char text[PSLINELENGTH]; /* Temporary storage for text */ + unsigned int num; + unsigned int i; + int comment_length; + char buf[BUFSIZ]; + char *cp; + + comment_length = strlen(comment); + if (begin >= 0) fseek(from, begin, SEEK_SET); + while (ftell(from) < end) { + + fgets(line, sizeof line, from); + + /* iscomment cannot be used here, + * because comment_length is not known at compile time. */ + if (strncmp(line, comment, comment_length) == 0) { + cp = (char *) malloc(strlen(line)+1); + if (cp == NULL) { + fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n"); + exit(-1); + } + strcpy(cp, line); + return cp; + } + fputs(line, to); + if (!(DSCcomment(line) && iscomment(line+2, "Begin"))) { + /* Do nothing */ + } else if (iscomment(line+7, "Data:")) { + int rc = 0; + text[0] = '\0'; + rc = sscanf(line+length("%%BeginData:"), "%d %*s %256s", &num,text); + text[256] = '\0'; + if (rc >= 1) { + if (strcmp(text, "Lines") == 0) { + for (i=0; i < num; i++) { + fgets(line, sizeof line, from); + fputs(line, to); + } + } else { + while (num > BUFSIZ) { + fread(buf, sizeof (char), BUFSIZ, from); + fwrite(buf, sizeof (char), BUFSIZ, to); + num -= BUFSIZ; + } + fread(buf, sizeof (char), num, from); + fwrite(buf, sizeof (char), num, to); + } + } + } else if (iscomment(line+7, "Binary:")) { + if(sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) { + while (num > BUFSIZ) { + fread(buf, sizeof (char), BUFSIZ, from); + fwrite(buf, sizeof (char), BUFSIZ, to); + num -= BUFSIZ; + } + fread(buf, sizeof (char), num, from); + fwrite(buf, sizeof (char), num, to); + } + } + } + return NULL; +} + diff --git a/kghostview/ps.h b/kghostview/ps.h new file mode 100644 index 00000000..3cb4ea9c --- /dev/null +++ b/kghostview/ps.h @@ -0,0 +1,44 @@ +/* + * ps.h -- Include file for PostScript routines. + * Copyright (C) 1992 Timothy O. Theisen + * + * 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. + * + * Author: Tim Theisen Systems Programmer + * Internet: tim@cs.wisc.edu Department of Computer Sciences + * UUCP: uwvax!tim University of Wisconsin-Madison + * Phone: (608)262-0438 1210 West Dayton Street + * FAX: (608)262-9777 Madison, WI 53706 + */ + +#ifndef _PS_H +#define _PS_H + +#define PSLINELENGTH 257 /* 255 characters + 1 newline + 1 NULL */ + + /* Copy a portion of the PostScript file */ + +void pscopy(FILE *from, FILE *to, long begin, long end); + + /* Copy a portion of the PostScript file upto a comment */ + +char *pscopyuntil(FILE *from, FILE *to, long begin, long end, + const char *comment); + +#endif + +/* + * vim:sw=4:sts=4:ts=8:noet + */ diff --git a/kghostview/scrollbox.cpp b/kghostview/scrollbox.cpp new file mode 100644 index 00000000..8be3ab61 --- /dev/null +++ b/kghostview/scrollbox.cpp @@ -0,0 +1,129 @@ +/** + * Copyright (C) 1997-2002 the KGhostView authors. See file AUTHORS. + * + * 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 +#include +#include + +#include "scrollbox.h" + +ScrollBox::ScrollBox( QWidget* parent, const char* name ) + : QFrame( parent, name ) +{ + setFrameStyle( Panel | Sunken ); +} + +void ScrollBox::mousePressEvent( QMouseEvent* e ) +{ + mouse = e->pos(); + if( e->button() == RightButton ) + emit button3Pressed(); + if( e->button() == MidButton ) + emit button2Pressed(); +} + +void ScrollBox::mouseMoveEvent( QMouseEvent* e ) +{ + if( e->state() != LeftButton ) + return; + + int dx = ( e->pos().x() - mouse.x() ) * pagesize.width() / width(); + int dy = ( e->pos().y() - mouse.y() ) * pagesize.height() / height(); + + // Notify the word what the view position has changed + // The word in turn will notify as that view position has changed + // Even if coordinates are out of range QScrollView handles + // this properly + emit valueChanged( QPoint( viewpos.x() + dx, viewpos.y() + dy ) ); + emit valueChangedRelative( dx, dy ); + + mouse = e->pos(); +} + +void ScrollBox::resizeEvent( QResizeEvent * ) +{ + if ( paletteBackgroundPixmap() ) + setPaletteBackgroundPixmap( paletteBackgroundPixmap()->convertToImage().smoothScale( size() ) ); +} + +void ScrollBox::drawContents( QPainter* paint ) +{ + if ( pagesize.isEmpty() ) + return; + + + /* FIXME: + * + * The logic below is flawed because the page info given to us + * contains the borders used for page decoration, while we assume + * that it means only the actual displayed document. + * + */ + + QRect c( contentsRect() ); + + paint -> setPen( Qt::red ); + + int len = pagesize.width(); + int x = c.x() + c.width() * viewpos.x() / len; + int w = c.width() * viewsize.width() / len ; + if ( w > c.width() ) w = c.width(); + + len = pagesize.height(); + int y = c.y() + c.height() * viewpos.y() / len; + int h = c.height() * viewsize.height() / len; + if ( h > c.height() ) h = c.height(); + + paint->drawRect( x, y, w, h ); +} + +void ScrollBox::setPageSize( const QSize& s ) +{ + pagesize = s; + setFixedHeight( s.height() * width() / s.width() ); + repaint(); +} + +void ScrollBox::setViewSize( const QSize& s ) +{ + viewsize = s; + repaint(); +} + +void ScrollBox::setViewPos( const QPoint& pos ) +{ + viewpos = pos; + repaint(); +} + +void ScrollBox::setThumbnail( QPixmap img ) +{ + // The line below is needed to work around certain "features" of styles such as liquid + // see bug:61711 for more info (LPC, 20 Aug '03) + setBackgroundOrigin( QWidget::WidgetOrigin ); + setPaletteBackgroundPixmap( img.convertToImage().smoothScale( size() ) ); +} + +void ScrollBox::clear() +{ + unsetPalette(); +} + +#include "scrollbox.moc" + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/scrollbox.h b/kghostview/scrollbox.h new file mode 100644 index 00000000..a815c655 --- /dev/null +++ b/kghostview/scrollbox.h @@ -0,0 +1,60 @@ +/** + * Copyright (C) 1997-2002 the KGhostView authors. See file AUTHORS. + * + * 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 __SCROLLBOX_H__ +#define __SCROLLBOX_H__ + +#include +#include + +class ScrollBox: public QFrame +{ + Q_OBJECT + +public: + ScrollBox( QWidget* parent = 0, const char* name = 0 ); + +public slots: + void setPageSize( const QSize& ); + void setViewSize( const QSize& ); + void setViewPos( const QPoint& ); + void setViewPos( int x, int y ) { setViewPos( QPoint( x, y ) ); } + void setThumbnail( QPixmap img ); + void clear(); + +signals: + void valueChanged( const QPoint& ); + void valueChangedRelative( int dx, int dy ); + void button2Pressed(); + void button3Pressed(); + +protected: + void mousePressEvent( QMouseEvent *); + void mouseMoveEvent( QMouseEvent *); + void drawContents( QPainter *); + void resizeEvent( QResizeEvent * ); + +private: + QPoint viewpos, mouse; + QSize pagesize; + QSize viewsize; +}; + +#endif + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/thumbnailservice.cpp b/kghostview/thumbnailservice.cpp new file mode 100644 index 00000000..4d653cfa --- /dev/null +++ b/kghostview/thumbnailservice.cpp @@ -0,0 +1,161 @@ +/** + * Copyright (C) 1997-2003 the KGhostView authors. See file AUTHORS. + * + * 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 "thumbnailservice.h" + +#include "kgv_miniwidget.h" +#include "kpswidget.h" +#include "kgv_view.h" + +#include +#include +#include +#include +#include + +ThumbnailService::ThumbnailService( KGVMiniWidget* parent, const char* name ) : + QObject( parent, name ), + _mini( parent ), + timer_( new QTimer( this ) ), + _busy( false ), + _enabled( false ) +{ + _thumbnailDrawer = new KPSWidget( parent->_part->widget(), "thumbnail-drawer" ); + _thumbnailDrawer->readSettings(); + connect( _thumbnailDrawer, SIGNAL( newPageImage( QPixmap ) ), SLOT( slotDone( QPixmap ) ) ); + connect( timer_, SIGNAL( timeout() ), SLOT( processOne() ) ); + _thumbnailDrawer->hide(); +} + +ThumbnailService::~ThumbnailService() +{ +} + +bool ThumbnailService::Request::operator < ( ThumbnailService::Request b ) const +{ + if ( urgent != b.urgent ) return urgent; + if ( page != b.page ) return page < b.page; + // below is just so that == can be in terms of "<" + if ( receiver != b.receiver ) return std::less()( receiver, b.receiver ); + if ( slot != b.slot ) return std::strcmp( slot, b.slot ) < 0; + return false; +} + +void ThumbnailService::delayedGetThumbnail( const int page, QObject* rec, const char* slot, bool urgent ) +{ + kdDebug( 4500 ) << "ThumbnailService::delayedGetThumbnail: request for page " << page << endl; + pending.insert( Request( page, rec, slot, urgent ) ); + if ( !_busy ) { + _busy = true; + // The reason for the code below might not be obvious: + // It is much nicer to have the the thumbnails appear from top to bottom. + // However, when several are requested at once (or almost), then we cannot control the order + // unless we delay a bit the first one + if ( urgent ) processOne(); + else timer_->start( 150, true ); + } +} + +void ThumbnailService::cancelRequests( const int page, QObject* rec, const char* slot ) +{ + std::set::iterator first = pending.begin(), last = pending.end(); + while ( first != last ) { + if ( ( page == -1 || page == first->page ) && + ( !rec || rec == first->receiver ) && + ( !slot || !strcmp( slot, first->slot ) ) ) { + std::set::iterator next = first; + ++next; + pending.erase( first ); + first = next; + } else { + ++first; + } + } +} + +void ThumbnailService::reset() +{ + kdDebug( 4500 ) << "ThumbnailService::reset()" << endl; + timer_->stop(); + pending.clear(); + assert( _thumbnailDrawer ); + _thumbnailDrawer->stopInterpreter(); + _busy = false; + _enabled = false; +} + +void ThumbnailService::setEnabled( const bool e ) +{ + kdDebug( 4500 ) << "ThumbnailService::setEnabled( " << ( e ? "true" : "false" ) << " )" << endl; + _enabled = e; + if ( _enabled && _busy ) processOne(); +} + +void ThumbnailService::slotDone( QPixmap pix ) +{ + kdDebug( 4500 ) << "ThumbnailService::slotDone(): got page" << endl; + pix.detach(); + emit relayPixmap( pix ); + processOne(); +} + + +void ThumbnailService::processOne() +{ + kdDebug( 4500 ) << "ThumbnailService::processOne()" << endl; + if ( !_enabled ) return; + if ( !_mini || !_mini->dsc() || !_mini->dsc()->isStructured() ) { + _busy = false; + pending.clear(); + return; + } + assert( _thumbnailDrawer ); + if ( pending.empty() ) { + _busy = false; + return; + } + _busy = true; + FILE* file = _mini->psFile(); + Request req = *pending.begin(); + kdDebug( 4500 ) << "ThumbnailService::processOne(): processing " << req.page << "(of " << pending.size() << " requests)" << endl; + disconnect( SIGNAL( relayPixmap( QPixmap ) ) ); + while ( !pending.empty() && req.page == pending.begin()->page ) { + req = *pending.begin(); + connect( this, SIGNAL( relayPixmap( QPixmap ) ), req.receiver, req.slot ); + pending.erase( pending.begin() ); + } + _thumbnailDrawer->setOrientation( _mini->orientation( req.page ) ); + _thumbnailDrawer->setBoundingBox( _mini->boundingBox( req.page ) ); + _thumbnailDrawer->setMagnification( 0.2 ); + if ( !_thumbnailDrawer->isInterpreterRunning() ) { + _thumbnailDrawer->setFileName( _mini->_document->fileName(), true ); + _thumbnailDrawer->startInterpreter(); + _thumbnailDrawer->sendPS( file, _mini->dsc()->beginprolog(), + _mini->dsc()->endprolog() ); + _thumbnailDrawer->sendPS( file, _mini->dsc()->beginsetup(), + _mini->dsc()->endsetup() ); + } + else { + _thumbnailDrawer->nextPage(); + } + _thumbnailDrawer->sendPS( file, _mini->dsc()->page()[ req.page ].begin, + _mini->dsc()->page()[ req.page ].end ); +} + +#include "thumbnailservice.moc" + diff --git a/kghostview/thumbnailservice.h b/kghostview/thumbnailservice.h new file mode 100644 index 00000000..d1981242 --- /dev/null +++ b/kghostview/thumbnailservice.h @@ -0,0 +1,92 @@ +#ifndef THUMBNAILSERVICE_H +#define THUMBNAILSERVICE_H +/** + * Copyright (C) 1997-2003 the KGhostView authors. See file AUTHORS. + * + * 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 +#include +#include +#include +#include + +class KPSWidget; +class KGVMiniWidget; +class QTimer; + +class ThumbnailService : public QObject { + Q_OBJECT + public: + ThumbnailService( KGVMiniWidget* parent, const char* name = 0 ); + ~ThumbnailService(); + + public slots: + void delayedGetThumbnail( int page, QObject* receiver, const char* slot, bool urgent = false ); + /** + * Cancels the request matching the signature below. + * + * @param page the page of the request. Use "-1" for wildcard + * @param receiver the receiver. Use null for wildcard + * @param slot Use null for wildcard + */ + void cancelRequests( int page, QObject* receiver, const char* slot); + + void reset(); + /** + * This "suspends" the service. + * Unlike @ref reset(), if you call setEnabled( false ), + * old requests will be kept and will be serviced when + * you call setEnabled( true ) later. + */ + void setEnabled( bool ); + + signals: + /** + * Don't connect to this directly + */ + void relayPixmap( QPixmap ); + + private slots: + void slotDone( QPixmap ); + void processOne(); + + private: + + struct Request { + Request( int p, QObject* r, const char* s ) : + page( p ), receiver( r ), slot( s ), urgent( false ) { } + Request( int p, QObject* r, const char* s, bool u ) : + page( p ), receiver( r ), slot( s ), urgent( u ) { } + + int page; + QObject* receiver; + const char* slot; + bool urgent; + bool operator < ( Request ) const; + }; + static bool pageCmp( Request, Request ); + std::set pending; + QGuardedPtr _thumbnailDrawer; + KGVMiniWidget* _mini; + QTimer* timer_; + bool _busy; + bool _enabled; +}; + +// vim:sw=4:sts=4:ts=8:sta:tw=78:noet +#endif // THUMBNAILSERVICE_H + diff --git a/kghostview/update-to-xt-names.pl b/kghostview/update-to-xt-names.pl new file mode 100644 index 00000000..1aa07403 --- /dev/null +++ b/kghostview/update-to-xt-names.pl @@ -0,0 +1,36 @@ +#!/usr/bin/perl + +my $group = ''; +my $key = ''; +my $value = ''; + +while (<>) { + if (/^\s.*$/) { next } + if (/^\s*#.*$/) { next } + if (/\[(.*)\]/) { + $group = $1; + } elsif (/^(.*)=(.*)$/) { + $key = $1; + $value = $2; + } else { next } + + if (!$group || !$key) { next } + + if ( $group eq 'General' ) { + if ( $key eq 'Palette' ) { + if ($value eq 'color') { + print "Palette=Color\n"; + } elsif ($value eq 'monochrome') { + print "Palette=Monochrome\n"; + } elsif ($value eq 'grayscale') { + print "Palette=Grayscale\n"; + } else { + print "Palette=Color\n"; + } + } + if ( $key eq 'Interpreter' ) { + print "# DELETE [General]Interpreter\n"; + } + } +} + diff --git a/kghostview/version.h b/kghostview/version.h new file mode 100644 index 00000000..81cf5df2 --- /dev/null +++ b/kghostview/version.h @@ -0,0 +1,4 @@ +#define KGHOSTVIEW_VERSION "0.20" + + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/viewcontrol.cpp b/kghostview/viewcontrol.cpp new file mode 100644 index 00000000..cc66d598 --- /dev/null +++ b/kghostview/viewcontrol.cpp @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** A dialog for the selection of the view of a document. +** +** Copyright (C) 1997 by Mark Donohoe. +** Based on original work by Tim Theisen. +** +** This code is freely distributable under the GNU Public License. +** +*****************************************************************************/ + +#include +#include +#include +#include +#include +#include + + +#include "viewcontrol.h" +#include "viewcontrol.moc" + +#include +#include +#include +#include + +ViewControl::ViewControl( QWidget *parent, const char *name ) + : QDialog( parent, name ) +{ + setFocusPolicy(QWidget::StrongFocus); + + QBoxLayout *topLayout = new QVBoxLayout( this, 10 ); + + QGroupBox* vcGroupBox; + vcGroupBox = new QGroupBox( this ); + vcGroupBox->setFrameStyle( QFrame::NoFrame ); + //vcGroupBox->setTitle( i18n("Force Changes To") ); + //vcGroupBox->setAlignment( 1 ); + + topLayout->addWidget( vcGroupBox, 10 ); + + QGridLayout *grid = new QGridLayout( vcGroupBox, 3, 2, 10 ); + + grid->setRowStretch(0,0); + grid->setRowStretch(1,10); + + + grid->setColStretch(0,0); + grid->setColStretch(1,10); + + + magComboBox = new QComboBox( FALSE, vcGroupBox ); + magComboBox->setFixedHeight( magComboBox->sizeHint().height() ); + + + //magComboBox->hide(); + + connect ( magComboBox, SIGNAL (activated (int)), + this, SLOT (slotMagSelection (int)) ); + grid->addWidget( magComboBox, 0, 1 ); + + + + mediaComboBox = new QComboBox( FALSE, vcGroupBox ); + mediaComboBox->setFixedHeight( magComboBox->sizeHint().height() ); + + connect ( mediaComboBox, SIGNAL (activated (int)), + this, SLOT (slotMediaSelection (int)) ); + + grid->addWidget( mediaComboBox, 1, 1 ); + + orientComboBox = new QComboBox( FALSE, vcGroupBox ); + orientComboBox->insertItem(i18n("Portrait")); + orientComboBox->insertItem(i18n("Landscape")); + orientComboBox->insertItem(i18n("Seascape")); + orientComboBox->insertItem(i18n("Upside Down")); + orientComboBox->setFixedHeight( magComboBox->sizeHint().height() ); + + connect ( orientComboBox, SIGNAL (activated (int)), + this, SLOT (slotOrientSelection (int)) ); + grid->addWidget( orientComboBox, 2, 1 ); + + int labelWidth = 0; + + QLabel* vcLabel; + vcLabel = new QLabel( magComboBox, i18n("&Magnification"), vcGroupBox ); + vcLabel->setAlignment( AlignRight | AlignVCenter | ShowPrefix ); + if ( vcLabel->sizeHint().width() > labelWidth ) + labelWidth = vcLabel->sizeHint().width(); + vcLabel->setMinimumWidth( labelWidth ); + + vcLabel->hide(); + + grid->addWidget( vcLabel, 0, 0 ); + + + vcLabel = new QLabel( mediaComboBox, i18n("M&edia"), vcGroupBox ); + vcLabel->setAlignment( AlignRight | AlignVCenter | ShowPrefix ); + if ( vcLabel->sizeHint().width() > labelWidth ) + labelWidth = vcLabel->sizeHint().width(); + vcLabel->setMinimumWidth( labelWidth ); + + grid->addWidget( vcLabel, 1, 0 ); + + vcLabel = new QLabel( orientComboBox, i18n("&Orientation"), vcGroupBox ); + vcLabel->setAlignment( AlignRight | AlignVCenter | ShowPrefix ); + if ( vcLabel->sizeHint().width() > labelWidth ) + labelWidth = vcLabel->sizeHint().width(); + vcLabel->setMinimumWidth( labelWidth ); + + grid->addWidget( vcLabel, 2, 0 ); + + vcGroupBox->setMinimumHeight( 2*orientComboBox->sizeHint().height()+20 ); + vcGroupBox->setMinimumWidth( + 40 + labelWidth + orientComboBox->sizeHint().width() ); + + KSeparator* sep = new KSeparator( KSeparator::HLine, this); + topLayout->addWidget( sep ); + + // CREATE BUTTONS + + KButtonBox *bbox = new KButtonBox( this ); + bbox->addStretch( 10 ); + + apply = bbox->addButton( KStdGuiItem::apply() ); + connect( apply, SIGNAL(clicked()), SLOT(slotApplyClicked()) ); + + QPushButton *closebtn = bbox->addButton( KStdGuiItem::close() ); + connect( closebtn, SIGNAL(clicked()), SLOT(reject()) ); + + + bbox->layout(); + topLayout->addWidget( bbox ); + + topLayout->activate(); + + prevmag = prevmedia = prevorient = 0; + applyEnable (false); +} + +void +ViewControl::updateMag (int mag) +{ + magComboBox->setCurrentItem (mag); + prevmag = mag; +} + + +void +ViewControl::applyEnable (bool enable) +{ + apply->setEnabled (enable); +} + +void +ViewControl::slotApplyClicked() +{ + emit applyChanges(); + applyEnable (false); +} + +void +ViewControl::slotMagSelection (int i) +{ + if (i != prevmag) + { + applyEnable (true); + prevmag = i; + } +} + +void +ViewControl::slotMediaSelection (int i) +{ + if (i != prevmedia) + { + applyEnable (true); + prevmedia = i; + } +} + +void +ViewControl::slotOrientSelection (int i) +{ + if (i != prevorient) + { + applyEnable (true); + prevorient = i; + } +} + + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kghostview/viewcontrol.h b/kghostview/viewcontrol.h new file mode 100644 index 00000000..3e8bcd70 --- /dev/null +++ b/kghostview/viewcontrol.h @@ -0,0 +1,44 @@ +#ifndef VIEWCONTROL_H +#define VIEWCONTROL_H + +#include +class QComboBox; +class QPushButton; + + +class ViewControl : public QDialog +{ + Q_OBJECT +public: + ViewControl( QWidget *parent, const char *name ); + QComboBox* magComboBox; + QComboBox* mediaComboBox; + QComboBox* orientComboBox; + QPushButton *apply; + + /** + * Update the mag combo box. + **/ + void updateMag (int mag); + + /** + * Enable/disable the apply button. + **/ + void applyEnable (bool enable); + +protected: + int prevmag, prevmedia, prevorient; + +public slots: + void slotApplyClicked(); + void slotMagSelection (int i); + void slotMediaSelection (int i); + void slotOrientSelection (int i); + +signals: + void applyChanges(); +}; + +#endif + +// vim:sw=4:sts=4:ts=8:noet diff --git a/kiconedit/AUTHORS b/kiconedit/AUTHORS new file mode 100644 index 00000000..dd2047ae --- /dev/null +++ b/kiconedit/AUTHORS @@ -0,0 +1,10 @@ +Copyright 1998 by Thomas Tanghus +Copyright 2000 by John Califf + +Original Author: + Thomas Tanghus + +Current Maintainers: + John Califf + Laurent Montel + diff --git a/kiconedit/Makefile.am b/kiconedit/Makefile.am new file mode 100644 index 00000000..c2536935 --- /dev/null +++ b/kiconedit/Makefile.am @@ -0,0 +1,26 @@ +INCLUDES = $(all_includes) +SUBDIRS = pics + +bin_PROGRAMS = kiconedit + +kiconedit_SOURCES = utils.cpp main.cpp kiconedit.cpp kicongrid.cpp \ + kiconcolors.cpp kcolorgrid.cpp palettetoolbar.cpp\ + kicon.cpp kresize.cpp knew.cpp properties.cpp \ + kiconeditslots.cpp kiconconfig.cpp + +kiconedit_METASOURCES = AUTO + +# the library search path. +kiconedit_LDFLAGS = $(all_libraries) $(KDE_RPATH) +kiconedit_LDADD = $(LIB_KFILE) -lkdeprint + +DISTCLEANFILES = *~ .deps/* .libs/* + +rcdir = $(kde_datadir)/kiconedit +rc_DATA = kiconeditui.rc + +xdg_apps_DATA = kiconedit.desktop + +messages: rc.cpp + $(XGETTEXT) rc.cpp $(kiconedit_SOURCES) -o $(podir)/kiconedit.pot + diff --git a/kiconedit/NEWS b/kiconedit/NEWS new file mode 100644 index 00000000..ba7ef218 --- /dev/null +++ b/kiconedit/NEWS @@ -0,0 +1,68 @@ +KDE Icon Editor +_______________ + +------------------------------------------------------------------------------ + News and fixes in version 0.4.0: +------------------------------------------------------------------------------ + - Enabled loading other image types than XPM. + - Repainting large pictures is very much faster now. + - Added drop site indication when using XDND. + - Added QWhatsThis help (this is great!). + - Started playing with XDND. The toolbar now has a drag source and the grid + supports both XDND and KDND. + - Added rulers (can be toggled from the configuration dialog). + - Circular selection. + - Configuration dialog: + - Shortcut keys. + - Appearance. + - Templates. + - Miscellaneous (paste mode, show rulers etc.). + +------------------------------------------------------------------------------ + News and fixes in version 0.3.2: +------------------------------------------------------------------------------ + - German translations. (thanks to Gregor Zumstein ) + - Solaris didn't like TRANSPARENT definition. (thanks to Alastair Burt ) + - Crashed on empty string in strlen. (thanks to Alastair Burt ) + - Russian translations (thanks to Andy Pershin ) + +------------------------------------------------------------------------------ + News and fixes in version 0.3.1: +------------------------------------------------------------------------------ + - Icon templates installed in the wrong directory. + - Templates didn't load. + +------------------------------------------------------------------------------ + News and fixes in version 0.3: +------------------------------------------------------------------------------ + - Complete rewrite of the drawing grid. Should now be faster and more flexible. + - New class KIcon for file manipulation. + - The "Line" tool can now draw 45 dgr. angles. + - Smooth resizing of icons if linked with QT >= 1.40. + - Improved loading/saving images with transparent pixels. + - Loading and saving should now work on non-local files. + +------------------------------------------------------------------------------ + News and fixes in version 0.2: +------------------------------------------------------------------------------ + - Saves restore file when closed by session management or by crash. + - Fixed multi instance handling. + - Added toolbar button for creating new instances. + - Added danish translation. + - Added statusbar field for messages. + - Saves window size. + - Couldn't toggle grid from the menu. + - Added "Toggle toolbar", "Toggle drawing tools" and "Toggle statusbar" to the + "View" menu. This as well as the *Bar positions is saved between sessions. + - Grid state and zoom factor saved between sessions. + - The clipboard is checked with short intervals to check if there's a pixmap. + - The cursor hotspots are now correct. + - Cursor position is shown in the statusbar. + - Removed a lot of memory leaks and made the general memory footprint some smaller. + - New tools: "Find pixel", "Flood Fill", "Filled Circle" and "Filled Ellipse". + - Clipboard now supports selection of regions and inserting into existing image. + - Speeded up loading of pixmaps by some thousand percents ;-) + - Preview has scrollbars if it doesn't fit. + + + diff --git a/kiconedit/kcolorgrid.cpp b/kiconedit/kcolorgrid.cpp new file mode 100644 index 00000000..a3793cb2 --- /dev/null +++ b/kiconedit/kcolorgrid.cpp @@ -0,0 +1,335 @@ +/* + kiconedit - a small graphics drawing program for creating KDE icons + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.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 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 + +#include + +#include "kcolorgrid.h" + +void KColorArray::remove(int idx) +{ + int oldsize = size(); + if(idx >= (int)size()) + { + kdWarning() << "KColorArray::remove: Index " << idx << " out of range" << endl; + return; + } + KColorArray tmp(*this); + tmp.detach(); + resize(size()-1); + for(int i = idx; i < oldsize-1; i++) + at(i) = tmp[i+1]; + //kdDebug(4640) << "KColorArray::remove() " << at(idx) << "\t-\tsize: " << size() << endl; +} + +void KColorArray::append(uint c) +{ + resize(size()+1); + at(size()-1) = c; + //kdDebug(4640) << "KColorArray::append() " << c << "\t-\tsize: " << size() << endl; +} + +uint KColorArray::closestMatch(uint color) +{ + //kdDebug(4640) << "KColorArray: " << c << endl; + uint c = color & ~OPAQUE_MASK, d = 0xffffff, t; + //kdDebug(4640) << "KColorArray: " << c << endl; + //kdDebug(4640) << "KColorArray: " << c|OPAQUE_MASK << endl; + uint cb = c; + for(uint i = 0; i < size(); i++) + { + if (at(i) > cb) + t = at(i) - cb; + else + t = cb - at(i); + if( t < d ) + { + d = t; + c = at(i); + } + } + return c|OPAQUE_MASK; +} + +KColorGrid::KColorGrid(QWidget *parent, const char *name, int space) + : QWidget(parent, name, Qt::WResizeNoErase|Qt::WRepaintNoErase) +{ + //kdDebug(4640) << "KColorGrid - constructor" << endl; + s = space; + rows = cols = totalwidth = totalheight = 0; + setCellSize(10); + setGridState(Plain); + setGrid(true); + numcolors.resize(0); + gridcolors.resize(0); + + //kdDebug(4640) << "KColorGrid - constructor - done" << endl; +} +/* +void KColorGrid::show() +{ + //updateScrollBars(); + QWidget::show(); +} +*/ +void KColorGrid::paintEvent(QPaintEvent *e) +{ + //kdDebug(4640) << "KColorGrid::paintEvent" << endl; + + //updateScrollBars(); + //QWidget::paintEvent(e); + + const QRect urect = e->rect(); + + //kdDebug(4640) << "Update rect = ( " << //urect.left() << ", " << urect.top() << ", " << urect.width() << ", " << urect.height() << " )" << endl; + + + int firstcol = getX(urect.x())-1; + int firstrow = getY(urect.y())-1; + int lastcol = getX(urect.right())+1; + int lastrow = getY(urect.bottom())+1; + + QWMatrix matrix; + QPixmap pm(urect.width(),urect.height()); + pm.fill(paletteBackgroundColor()); + QPainter p; + p.begin( &pm ); + + firstrow = (firstrow < 0) ? 0 : firstrow; + firstcol = (firstcol < 0) ? 0 : firstcol; + lastrow = (lastrow >= rows) ? rows : lastrow; + lastcol = (lastcol >= cols) ? cols : lastcol; + //kdDebug(4640) << urect.x() << " x " << urect.y() << " - row: " << urect.width() << " x " << urect.height() << endl; + //kdDebug(4640) << "col: " << firstcol << " -> " << lastcol << " - row: " << firstrow << " -> " << lastrow << endl; + +/* + if(this->isA("KDrawGrid")) + kdDebug(4640) << "KDrawGrid\n firstcol: " << firstcol << "\n lastcol: " << lastcol << "\n firstrow: " << firstrow << "\n lastrow: " << lastrow << endl; +*/ + for(int i = firstrow; i < lastrow; i++) + { + //if(this->isA("KDrawGrid")) + // kdDebug(4640) << "Updating row " << i << endl; + for(int j = firstcol; j < lastcol; j++) + { + matrix.translate( (j*cellsize)-urect.x(), (i*cellsize)-urect.y() ); + p.setWorldMatrix( matrix ); + //p.setClipRect(j*cellsize, i*cellsize, cellsize, cellsize); + paintCell(&p, i, j); + //p.setClipping(FALSE); + matrix.reset(); + p.setWorldMatrix( matrix ); + } + //kapp->processEvents(); + } + + matrix.translate(-urect.x(),-urect.y()); + p.setWorldMatrix( matrix ); + paintForeground(&p,e); + + p.end(); + + bitBlt(this,urect.topLeft(),&pm,QRect(0,0,pm.width(),pm.height())); + +} + +void KColorGrid::paintForeground(QPainter* , QPaintEvent* ) +{ +} + +/* +void KColorGrid::resizeEvent(QResizeEvent *) +{ + //kdDebug(4640) << "resize: width: " << width() << " - total: " << totalwidth << endl; + //kdDebug(4640) << "resize: height: " << height() << " - total: " << totalheight << endl; +} +*/ + +QSize KColorGrid::sizeHint() const +{ + return QSize(totalwidth, totalheight); +} + +int KColorGrid::getY( int y ) +{ + if(y > (totalheight-1)) + y = totalheight; + if(cellsize == 1) + return y; + return (y/cellsize); +} + +int KColorGrid::getX( int x ) +{ + if( x > totalwidth-1) + x = totalwidth; + if(cellsize == 1) + return x; + return (x/cellsize); +} + +const QRect KColorGrid::viewRect() +{ + //kdDebug(4640) << "viewRect" << endl; + const QRect r(0, 0, width(), height()); + //kdDebug(4640) << "viewRect - " << x << " x " << y << " - " << w << " x " << h << endl; + return r; +} + +void KColorGrid::setNumRows(int n) +{ + //kdDebug(4640) << "setNumRows" << endl; + if(n < 0 || n == rows) + return; + + rows = n; + + gridcolors.resize(n*numCols()); + //QTableView::setNumRows(n); + totalheight = (n * cellsize) + 1; + resize(totalwidth, totalheight); + //kdDebug(4640) << "setNumRows() - gridcolors: " << gridcolors.size() << " size: " << numCols()*numRows() << endl; +} + +void KColorGrid::setNumCols(int n) +{ + //kdDebug(4640) << "setNumCols" << endl; + if(n < 0) + return; + int on = numCols(); + KColorArray gc(gridcolors); + gc.detach(); + //kdDebug(4640) << "gc size: " << gc.size() << " numrows: " << numRows() << endl; + gridcolors.resize(n*numRows()); + cols = n; + + totalwidth = (n * cellsize) + 1; + resize(totalwidth, totalheight); + //kdDebug(4640) << "numRows: " << numRows() << endl; + //kdDebug(4640) << "gridcolor: " << gridcolors.size() << " grid: " << numRows()*numCols() << endl; + if(numRows() == 0) + return; + + for(int i = 0; i < numRows(); i++) + { + for(int j = 0; j < n; j++) + { + //kdDebug(4640) << "row " << i << " , col " << j << endl; + if(j < on ) //If there's something to read here -- i.e. we're within the original grid + { + //kdDebug(4640) << (i*numCols())+j << " " << (i*on)+j << endl; + gridcolors.at((i*numCols())+j) = gc.at((i*on)+j); + } + else //Initialize to something.. + { + if (gc.size()) //Have some pixels originally.. + gridcolors.at((i*numCols())+j) = gc.at(0); + else + gridcolors.at((i*numCols())+j) = 0; //Picks something #### Update numcolors? + } + } + } + + //kdDebug(4640) << "setNumCols() - gridcolors: " << gridcolors.size() << " size: " << numCols()*numRows() << endl; +} + +void KColorGrid::fill( uint color) +{ + gridcolors.fill(color); + numcolors.resize(1); + numcolors.at(0) = color; + emit colorschanged(numcolors.size(), numcolors.data()); +} + +void KColorGrid::setColor( int colNum, uint col, bool update ) +{ + //kdDebug(4640) << "KColorGrid::setColor" << endl; + uint oldcolor = gridcolors[colNum]; + gridcolors[colNum] = col; + + if(!update) + return; + + //kdDebug(4640) << "KColorGrid::setColor - before adding" << endl; + if(!numcolors.contains(col)) + { + //kdDebug(4640) << "KColorGrid::setColor() - adding " << // col << " - " << qRed(col) << " " << qGreen(col) << " " << qBlue(col) << endl; + numcolors.append(col); + //kdDebug(4640) << "KColorGrid::setColor() - adding done " << numcolors.size()-1 << endl; + //numcolors++; + emit addingcolor(col); + } + + //kdDebug(4640) << "KColorGrid::setColor - before removing" << endl; + if(!gridcolors.contains(oldcolor)) + { + int idx = numcolors.find(oldcolor); + if(idx != -1) + { + //kdDebug(4640) << "KColorGrid::setColor() - removing " << // oldcolor << " - " << qRed(oldcolor) << " " << qGreen(oldcolor) << " " << qBlue(oldcolor) << endl; + numcolors.remove(idx); + //kdDebug(4640) << "KColorGrid::setColor() - removing done" << endl; + emit colorschanged(numcolors.size(), numcolors.data()); + } + //numcolors--; + } + + //kdDebug(4640) << "KColorGrid::setColor - before updateCell" << endl; + repaint((colNum%numCols())*cellsize,(colNum/numCols())*cellsize, cellsize, cellsize); + //updateCell( colNum/numCols(), colNum%numCols(), false ); + //kdDebug(4640) << "KColorGrid::setColor - after updateCell" << endl; +} + +void KColorGrid::updateCell( int row, int col, bool ) +{ + //kdDebug(4640) << "updateCell - before repaint" << endl; + QWMatrix matrix; + QPainter p; + p.begin( this ); + matrix.translate( (col*cellsize), (row*cellsize) ); + p.setWorldMatrix( matrix ); + paintCell(&p, row, col); + p.end(); + +} + +void KColorGrid::updateColors() +{ + numcolors.resize(0); + for(int i = 0; i < (int)gridcolors.size(); i++) + { + uint col = gridcolors.at(i); + if(!numcolors.contains(col)) + numcolors.append(col); + } + emit colorschanged(numcolors.size(), numcolors.data()); +} + +void KColorGrid::setCellSize( int s ) +{ + cellsize = s; + totalwidth = (numCols() * s) + 1; + totalheight = (numRows() * s) + 1; + resize(totalwidth, totalheight); + if ( isVisible() ) + repaint(viewRect(), false); +} +#include "kcolorgrid.moc" diff --git a/kiconedit/kcolorgrid.h b/kiconedit/kcolorgrid.h new file mode 100644 index 00000000..2bb7c856 --- /dev/null +++ b/kiconedit/kcolorgrid.h @@ -0,0 +1,104 @@ +/* + kiconedit - a small graphics drawing program for creating KDE icons + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.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 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 __KCOLORGRID_H__ +#define __KCOLORGRID_H__ + +#include +#include +#include + +#include "utils.h" + +#define KArrayUint QMemArray + +class KColorArray : public KArrayUint +{ +public: + void remove(int idx); + void append(uint); + uint closestMatch(uint); +}; + +class KColorGrid : public QWidget +{ +private: + Q_OBJECT +public: + KColorGrid( QWidget * parent = 0, const char *name = 0, int spacing = 0); + virtual ~KColorGrid() {}; + + enum GridState { Plain, Shaded }; + + void setSpacing(int space) { s = space; update(); } + void setGridState(GridState state) { gridstate = state;} + GridState gridState() { return gridstate; } + void setGrid(bool state) { hasgrid = state; } + int spacing() { return s; } + bool hasGrid() { return hasgrid; } + uint numColors() { return numcolors.size(); } + uint colors( uint *c ) { c = numcolors.data(); return numcolors.size(); } + bool contains(uint c) { return numcolors.contains(c); } + uint colorAt(int idx) { return gridcolors.at(idx); } + uint *data() {return numcolors.data(); } + void fill(uint color); + int numCols() { return cols; } + int numRows() { return rows; } + + virtual void setCellSize( int s ); + virtual int cellSize() { return cellsize; } + virtual QSize sizeHint() const; + + void setSize(const QSize s) { setNumRows(s.height()); setNumCols(s.width()); } + +public slots: + //virtual void show(); + +signals: + void addingcolor(uint); + void colorschanged(uint, uint*); + +protected: + void updateCell(int row, int col, bool f); + virtual void paintForeground( QPainter* p, QPaintEvent* e); + virtual void paintCell( QPainter *p, int row, int col) = 0; + virtual void paintEvent(QPaintEvent *); + //virtual void resizeEvent(QResizeEvent *); + void setColor(int colNum, uint, bool update = true ); + void updateColors(); + virtual void setNumRows(int); + virtual void setNumCols(int); + virtual int totalWidth() { return totalwidth; } + virtual int totalHeight() { return totalheight; } + int findRow(int y) { return getY(y); } + int getY(int y); + int findCol(int x) { return getX(x); } + int getX(int x); + const QRect viewRect(); + +//private: + int s, cellsize, totalwidth, totalheight; + int rows, cols, ypos, xpos; + GridState gridstate; + bool hasgrid; + KColorArray gridcolors, numcolors; +}; + +#endif //__KCOLORGRID_H__ diff --git a/kiconedit/kicon.cpp b/kiconedit/kicon.cpp new file mode 100644 index 00000000..92f1bc0b --- /dev/null +++ b/kiconedit/kicon.cpp @@ -0,0 +1,279 @@ +/* + KDE Icon Editor - a small graphics drawing program for the KDE + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.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 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 + +#include + +#include +#include +#include +#include +#include +#include + +#include "kicon.h" +#include "utils.h" + +KIconEditIcon::KIconEditIcon(QObject *parent, const QImage *img, KURL url) + : QObject(parent) +{ + f = 0; + _lastdir = "/"; + //checkUnNamedBackup(img); + + if(!url.isEmpty()) + { + open(img, url); + } +} + + +KIconEditIcon::~KIconEditIcon() +{ +} + + +bool KIconEditIcon::open(const QImage *image, KURL url) +{ + QImage *img = (QImage*)image; + + if(url.isEmpty()) + return false; + + kdDebug(4640) << "KIconEditIcon::open " << url.prettyURL() << endl; + + if(!url.isValid()) // try to see if it is a relative filename + { + kdDebug(4640) << "KIconEditIcon::open (malformed) " << url.prettyURL() << endl; + + QFileInfo fi(url.url()); + if(fi.isRelative()) + url = "file:" + fi.absFilePath(); + + if(!url.isValid()) // Giving up + { + QString msg = i18n("The URL: %1 \nseems to be malformed.\n").arg(url.url()); + KMessageBox::sorry((QWidget*)parent(), msg); + return false; + } + } + + QString filename; + + if(url.isLocalFile()) + { + filename = url.path(); + } + else + { + if(!KIO::NetAccess::download( url, filename, (QWidget*)parent() )) + { + QString msg = i18n("There was an error loading:\n%1\n").arg(url.prettyURL()); + KMessageBox::error((QWidget*)parent(), msg); + return false; + } + } + + bool loadedOk = img->load(filename); + + if(!url.isLocalFile()) + { + KIO::NetAccess::removeTempFile( filename ); + } + + if(!loadedOk) + { + QString msg = i18n("There was an error loading:\n%1\n").arg(url.prettyURL()); + KMessageBox::error((QWidget*)parent(), msg); + } + else + { + kdDebug(4640) << "KIconEditIcon::open - Image loaded" << endl; + + // _url is saved off for use in saving the image to the same + // file later - should include full path + if(url.isLocalFile()) + { + _url = url.path(); + } + else + { + _url = ""; + } + + kdDebug(4640) << "KIcon: _url: " << _url << endl; + + // this causes updates of preview, color palettes, etc. + emit loaded(img); + kdDebug(4640) << "loaded(img)" << endl; + + // this is the name that shows up in status bar - + // should be filename with path + emit newname(url.prettyURL()); + kdDebug(4640) << "newname(_url) : " << url.prettyURL() << endl; + + emit addrecent(url.prettyURL()); + + kdDebug(4640) << "KIconEditIcon::open - done" << endl; + } + + return loadedOk; +} + + + +bool KIconEditIcon::promptForFile(const QImage *img) +{ + kdDebug(4640) << "KIconEditIcon::promptForFile(const QImage *img)" << endl; + /* + QString filter = i18n("*|All Files (*)\n" + "*.xpm|XPM (*.xpm)\n" + "*.png|PNG (*.png)\n" + "*.gif|GIF files (*.gif)\n" + "*.jpg|JPEG files (*.jpg)\n" + "*.ico|Icon files (*.ico)\n"); + + + KURL url = KFileDialog::getOpenURL( QString::null, filter ); + */ + bool loaded = false; + KURL url = KFileDialog::getImageOpenURL( QString::null, static_cast(parent()) ); + + if( !url.isEmpty() ) + { + loaded = open( img, url ); + } + + return loaded; +} + + + +bool KIconEditIcon::saveAs(const QImage *image) +{ + kdDebug(4640) << "KIconEditIcon::saveAs" << endl; + + QString file; + + //Get list of file types.. + KFileDialog *dialog=new KFileDialog(QString::null, QString::null, static_cast(parent()), "file dialog", true); + dialog->setCaption( i18n("Save Icon As") ); + dialog->setKeepLocation( true ); + dialog->setMimeFilter( KImageIO::mimeTypes(KImageIO::Writing), "image/png" ); + dialog->setOperationMode( KFileDialog::Saving ); + + if(dialog->exec()==QDialog::Accepted) + { + file = dialog->selectedFile(); + if( file.isNull() ) + { + delete dialog; + return false; + } + if ( !KImageIO::canWrite(KImageIO::type(file)) ) + { + if ( KImageIO::canWrite(KImageIO::typeForMime(dialog->currentFilter())) ) + file += "."+KImageIO::suffix(KImageIO::typeForMime(dialog->currentFilter())); + else + file += ".png"; + } + } + else + { + delete dialog; + return false; + } + + delete dialog; + + if(QFile::exists(file)) + { + int r=KMessageBox::warningContinueCancel(static_cast(parent()), + i18n( "A file named \"%1\" already exists. " + "Overwrite it?" ).arg(file), + i18n( "Overwrite File?" ), + i18n( "&Overwrite" ) ); + + if(r==KMessageBox::Cancel) + { + return false; + } + } + + return save( image, file ); +} + + + +bool KIconEditIcon::save(const QImage *image, const QString &_filename) +{ + kdDebug(4640) << "KIconEditIcon::save" << endl; + QString filename = _filename; + + if(filename.isEmpty()) + { + if(_url.isEmpty()) + { + return saveAs(image); + } + else + { + KURL turl(_url); + filename = turl.path(); + } + } + + QImage *img = (QImage*)image; + img->setAlphaBuffer(true); + + KURL turl(filename); + QString str = turl.path(); + bool savedOk = false; + + /* base image type on file extension - let kimageio + take care of this determination */ + + if(img->save(str, KImageIO::type(str).ascii())) + { + kdDebug(4640) << "img->save()) successful" << endl; + emit saved(); + _url = filename; + + // emit signal to change title bar to reflect new name + emit newname(filename); + kdDebug(4640) << "newname(filenamme) : " << _url << endl; + savedOk = true; + emit addrecent(filename); + } + else + { + QString msg = i18n("There was an error saving:\n%1\n").arg(str); + KMessageBox::error((QWidget*)parent(), msg); + kdDebug(4640) << "KIconEditIcon::save - " << msg << endl; + } + + kdDebug(4640) << "KIconEditIcon::save - done" << endl; + + return savedOk; +} + + +#include "kicon.moc" diff --git a/kiconedit/kicon.h b/kiconedit/kicon.h new file mode 100644 index 00000000..3af48c14 --- /dev/null +++ b/kiconedit/kicon.h @@ -0,0 +1,78 @@ +/* + KDE Icon Editor - a small icon drawing program for the KDE. + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.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 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 __KICON_H__ +#define __KICON_H__ + +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(HAVE_FCNTL_H) && !defined(HAVE_FLOCK) +#include +#endif + +#ifdef HAVE_STDC_HEADERS +#include +#endif +#include +#include +#include + +class QImage; + +class KIconEditIcon : public QObject +{ + Q_OBJECT +public: + KIconEditIcon(QObject*, const QImage*, KURL url = KURL() ); + ~KIconEditIcon(); + + bool isLocal() { return local; } + QString url() { return _url; } + void setUrl( const QString & u ) { _url = u; }; + +public slots: + bool open(const QImage*, KURL url = KURL()); + bool promptForFile(const QImage*); + bool save(const QImage*, const QString &filename=QString::null); + bool saveAs(const QImage*); + +signals: + void newmessage( const QString &); + void newname(const QString &); + void addrecent(const QString &); + void opennewwin(const QString &); + void loaded(QImage *); + void saved(); + +protected: + bool local; + QString _url; + QString _lastdir; + FILE *f; +}; + +#endif //__KICON_H__ diff --git a/kiconedit/kiconcolors.cpp b/kiconedit/kiconcolors.cpp new file mode 100644 index 00000000..549f74d2 --- /dev/null +++ b/kiconedit/kiconcolors.cpp @@ -0,0 +1,170 @@ +/* + KDE Icon Editor - a small graphics drawing program for the KDE + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.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 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 +#include + +#include + +#include "kiconcolors.h" + +KDrawColors::KDrawColors(QWidget *parent) : KColorGrid(parent, 0, 3) +{ + kdDebug(4640) << "KDrawColors - constructor" << endl; + setCellSize(17); + setGrid(true); + setGridState(KColorGrid::Shaded); + selected = 0; + kdDebug(4640) << "KDrawColors - constructor - done" << endl; +} + +void KDrawColors::paintCell( QPainter *painter, int row, int col ) +{ + //KColorGrid::paintCell(painter, row, col); + uint c = colorAt( row * numCols() + col ); + QBrush brush(c); + int d = spacing(); + + qDrawShadePanel( painter, d, d, cellSize()-d, cellSize()-d, + colorGroup(), true, 1, &brush); + if ( row * numCols() + col == selected) + painter->drawWinFocusRect( d+1, d+1, cellSize()-(2*d)+1, cellSize()-(2*d)+1 ); +} + +void KDrawColors::mouseReleaseEvent( QMouseEvent *e ) +{ + int row = findRow( e->pos().y() ); + int col = findCol( e->pos().x() ); + int cell = row * numCols() + col; + + if ( selected != cell ) + { + int prevSel = selected; + selected = cell; + updateCell( prevSel/numCols(), prevSel%numCols(), FALSE ); + updateCell( row, col, FALSE ); + } + + emit newColor(colorAt(cell)|OPAQUE_MASK); +} + +KSysColors::KSysColors(QWidget *parent) : KDrawColors(parent) +{ + kdDebug(4640) << "KSysColors - constructor" << endl; + + setNumRows(7); + setNumCols(6); + //fill(backgroundColor().rgb()|OPAQUE_MASK); + setFixedSize(numCols()*cellSize(), numRows()*cellSize()); + fill(TRANSPARENT|OPAQUE_MASK); + + int numcells = 42; + + kdDebug(4640) << "KSysColors - constructor - before setColor" << endl; + for(int i = 0; i < numcells; i++) + { + setColor(i, iconpalette[i]|OPAQUE_MASK); + } + kdDebug(4640) << "KSysColors - constructor - done" << endl; +} + +KCustomColors::KCustomColors(QWidget *parent) : KDrawColors(parent) +{ + kdDebug(4640) << "KCustomColors - constructor" << endl; + setNumRows(3); + setNumCols(6); + fill(TRANSPARENT|OPAQUE_MASK); + setFixedSize(numCols()*cellSize(), numRows()*cellSize()); + freecells = new bool[numRows()*numCols()]; + for(int i = 0; i < numRows()*numCols(); i++) + freecells[i] = true; + kdDebug(4640) << "KCustomColors - constructor - done" << endl; +} + +KCustomColors::~KCustomColors() +{ + delete [] freecells; +} + +void KCustomColors::mouseDoubleClickEvent(QMouseEvent *e) +{ + int row = findRow( e->pos().y() ); + int col = findCol( e->pos().x() ); + int cell = row * numCols() + col; + QColor color=colorAt(cell); + if(KColorDialog::getColor(color)) + { + setColor(cell, color.rgb()); + emit newColor(color.rgb()|OPAQUE_MASK); + freecells[cell] = false; + } +} + +void KCustomColors::addColor(uint c) +{ + if(!contains(c)) + { + int f = getFreeCell(); + if(f != -1) + { + QColor color(c); + if(!color.isValid()) + { + kdDebug(4640) << "KCustomColors::addColor: Not a valid color: " << c << endl; + return; + } + //kdDebug(4640) << "KCustomColors::addColor: Adding color: " << c << " - " << qRed(c) << " " << qGreen(c) << " " << qBlue(c) << endl; + setColor(f, c); + freecells[f] = false; + } + } +} + +int KCustomColors::getFreeCell() +{ + for (int i = 0; i < numRows()*numCols(); i++) + { + if(freecells[i]) + { + if(i+1 < numRows()*numCols()) + freecells[i+1] = true; + else + freecells[0] = true; + return i; + break; + } + } + freeAllCells(); // start over again - not very elegant + return 0; +} + +void KCustomColors::freeAllCells() +{ + for (int i = 0; i < numRows()*numCols(); i++) + freecells[i] = true; +} + +void KCustomColors::clear() +{ + fill(TRANSPARENT); + freeAllCells(); + update(); +} +#include "kiconcolors.moc" diff --git a/kiconedit/kiconcolors.h b/kiconedit/kiconcolors.h new file mode 100644 index 00000000..a4293ff3 --- /dev/null +++ b/kiconedit/kiconcolors.h @@ -0,0 +1,83 @@ +/* + kiconedit - a small graphics drawing program for creating KDE icons + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.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 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 __KDRAWCOLORS_H__ +#define __KDRAWCOLORS_H__ + +#include + +#include + +#include "kcolorgrid.h" +#include "utils.h" + +class KDrawColors : public KColorGrid +{ + Q_OBJECT +public: + KDrawColors(QWidget *parent); + + //bool hasColor(uint); + +signals: + void newColor(uint); + +protected: + virtual void paintCell( QPainter*, int, int ); + virtual void mouseReleaseEvent(QMouseEvent*); + + int selected; +}; + +class KCustomColors : public KDrawColors +{ + Q_OBJECT +public: + KCustomColors(QWidget *parent); + ~KCustomColors(); + + void addColor(uint); + void clear(); + +protected: + virtual void mouseDoubleClickEvent(QMouseEvent*); + int getFreeCell(); + void freeAllCells(); + +protected: + bool *freecells; + QPopupMenu *popup; +}; + +class KSysColors : public KDrawColors +{ + Q_OBJECT +public: + + KSysColors(QWidget *parent); + +}; + + + +#endif //__KDRAWCOLORS_H__ + + + diff --git a/kiconedit/kiconconfig.cpp b/kiconedit/kiconconfig.cpp new file mode 100644 index 00000000..e7677e30 --- /dev/null +++ b/kiconedit/kiconconfig.cpp @@ -0,0 +1,589 @@ +/* + KDE Icon Editor - a small graphics drawing program for the KDE + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.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 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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kiconconfig.h" +#include "kiconedit.h" + +#ifndef PICS_INCLUDED +#define PICS_INCLUDED +#include "pics/logo.xpm" +#endif + +// little helper: +static inline QPixmap loadIcon( const char * name ) +{ + return KGlobal::instance()->iconLoader() + ->loadIcon( QString::fromLatin1(name), KIcon::NoGroup, KIcon::SizeMedium ); +} + +KTemplateEditDlg::KTemplateEditDlg(QWidget *parent) + : KDialogBase(parent, "KTemplateEditDlg", true, i18n( "Icon Template" ), + Ok|Cancel ) +{ + QFrame *frame = makeMainWidget(); + QVBoxLayout *ml = new QVBoxLayout(frame); + QGroupBox *grp = new QGroupBox(i18n("Template"), frame); + grp->setColumnLayout(0, Qt::Vertical); + grp->layout()->setSpacing(spacingHint()); + grp->layout()->setMargin(marginHint()); + QGridLayout *l = new QGridLayout(grp->layout()); + + ln_name = new QLineEdit( grp ); + connect( ln_name, SIGNAL( textChanged( const QString & ) ), + SLOT( slotTextChanged() ) ); + QLabel* lb_name = new QLabel( ln_name, i18n( "Description:" ), grp ); + + ln_path = new KURLRequester(grp); + connect( ln_path, SIGNAL( textChanged( const QString & ) ), + SLOT( slotTextChanged() ) ); + QLabel* lb_path = new QLabel( ln_path, i18n( "Path:" ), grp ); + + l->addWidget(lb_name, 0, 0); + l->addWidget(ln_name, 0, 1); + l->addWidget(lb_path, 1, 0); + l->addWidget(ln_path, 1, 1); + + ml->addWidget( grp, 1); + + slotTextChanged(); + + setMinimumSize( 400, 150 ); +} + +void KTemplateEditDlg::slotTextChanged() +{ + QString name = ln_name->text(), path = ln_path->url(); + enableButtonOK(name.length() && path.length()); +} + +void KTemplateEditDlg::setName(const QString & name) +{ + ln_name->setText(name); +} + +QString KTemplateEditDlg::name() +{ + return ln_name->text(); +} + +void KTemplateEditDlg::setPath(const QString & path) +{ + ln_path->setURL(path); +} + +QString KTemplateEditDlg::path() +{ + return ln_path->url(); +} + +KTemplateConfig::KTemplateConfig(QWidget *parent) : QWidget(parent) +{ + kdDebug(4640) << "KTemplateConfig constructor" << endl; + + btadd = btremove = btedit = 0L; + + QGroupBox* grp = new QGroupBox( i18n( "Templates" ), this ); + grp->setColumnLayout( 0, Qt::Horizontal ); + + templates = new KIconListBox( grp ); + connect( templates, SIGNAL( highlighted( int ) ), + SLOT( checkSelection( int ) ) ); + connect( templates, SIGNAL(doubleClicked( QListBoxItem * ) ), + SLOT( edit() ) ); + + QVBoxLayout* ml = new QVBoxLayout( this ); + ml->addWidget( grp ); + + QVBoxLayout* l = new QVBoxLayout( grp->layout(), KDialog::spacingHint() ); + l->addWidget( templates ); + + for( unsigned int i = 0; i < KIconTemplateContainer::self()->count(); i++ ) + templates->insertItem( new KIconListBoxItem( *KIconTemplateContainer::self()->at( i ) ) ) ; + + KButtonBox *bbox = new KButtonBox( grp ); + + btadd = bbox->addButton( i18n( "&Add..." ) ); + connect( btadd, SIGNAL( clicked() ), SLOT( add() ) ); + + btedit = bbox->addButton( i18n( "&Edit..." ) ); + connect( btedit, SIGNAL( clicked() ), SLOT( edit() ) ); + btedit->setEnabled( false ); + + btremove = bbox->addButton( i18n( "&Remove" ) ); + connect( btremove, SIGNAL( clicked() ), SLOT( remove() ) ); + btremove->setEnabled( false ); + + bbox->addStretch( 1 ); + + bbox->layout(); + l->addWidget( bbox ); +} + +KTemplateConfig::~KTemplateConfig() +{ +} + +void KTemplateConfig::saveSettings() +{ + kdDebug(4640) << "KTemplateConfig::saveSettings" << endl; + + KIconTemplateContainer::self()->clear(); + + for(int i = 0; i < (int)templates->count(); i++) + { + KIconTemplateContainer::self()->append(templates->iconTemplate(i)); + } + KIconTemplateContainer::self()->save(); + kdDebug(4640) << "KTemplateConfig::saveSettings - done" << endl; + +} + +void KTemplateConfig::checkSelection(int) +{ + kdDebug(4640) << "KTemplateConfig::checkSelection" << endl; + if(templates->currentItem() != -1) + { + if(btremove) btremove->setEnabled(true); + if(btedit) btedit->setEnabled(true); + } + else + { + if(btremove) btremove->setEnabled(false); + if(btedit) btedit->setEnabled(false); + } + kdDebug(4640) << "KTemplateConfig::checkSelection - done" << endl; +} + +void KTemplateConfig::remove() +{ + templates->removeItem(templates->currentItem()); +} + +void KTemplateConfig::add() +{ + KTemplateEditDlg dlg(this); + if(dlg.exec()) + { + KIconTemplate it; + it.path = dlg.path(); + it.title = dlg.name(); + templates->insertItem(new KIconListBoxItem(it)); + } +} + +void KTemplateConfig::edit() +{ + KTemplateEditDlg dlg(this); + dlg.setPath(templates->path(templates->currentItem())); + dlg.setName(templates->text(templates->currentItem())); + templates->item(templates->currentItem()); + if(dlg.exec()) + { + //Edit the entry + KIconTemplate &it=templates->iconTemplate(templates->currentItem()); + it.path = dlg.path(); + it.title = dlg.name(); + static_cast(templates->item(templates->currentItem()))->reloadIcon(); + templates->update(); + } +} + +KBackgroundConfig::KBackgroundConfig( QWidget* parent ) + : QWidget( parent ) +{ + kdDebug(4640) << "KBackgroundConfig - constructor" << endl; + + lb_ex = 0L; + + KIconEditProperties *props = KIconEditProperties::self(); + + pixpath = props->bgPixmap(); + pix.load(pixpath); + if(pix.isNull()) + { + kdDebug(4640) << "BGPIX: " << pixpath << " not valid!" << endl; + QPixmap pmlogo((const char**)logo); + pix = pmlogo; + } + + QVBoxLayout *mainLayout = new QVBoxLayout( this ); + + QGroupBox *grp1 = new QGroupBox( i18n( "Select Background" ), this ); + grp1->setColumnLayout(0, Qt::Vertical ); + grp1->layout()->setSpacing( KDialog::spacingHint() ); + grp1->layout()->setMargin( KDialog::marginHint() ); + mainLayout->addWidget( grp1 ); + + QGridLayout *grp1Layout = new QGridLayout( grp1->layout(), 3, 2 ); + + QButtonGroup* btngrp = new QButtonGroup( grp1 ); + btngrp->setExclusive( true ); + btngrp->setFrameStyle( QFrame::NoFrame ); + connect( btngrp, SIGNAL( clicked( int ) ), SLOT( slotBackgroundMode( int ) ) ); + grp1Layout->addWidget( btngrp, 0, 0 ); + + QVBoxLayout *bgl = new QVBoxLayout( btngrp, 5 ); + + QRadioButton *rbc = new QRadioButton( i18n( "Use co&lor" ), btngrp ); + btngrp->insert( rbc, 0 ); + bgl->addWidget( rbc ); + + QRadioButton *rbp = new QRadioButton( i18n( "Use pix&map" ), btngrp ); + btngrp->insert( rbp, 1 ); + bgl->addWidget( rbp ); + + bgl->addStretch( 1 ); + + QVBox *bbox = new QVBox( grp1 ); + grp1Layout->addWidget( bbox, 0, 1 ); + + btcolor = new KColorButton(props->bgColor(), bbox) ; + connect(btcolor, SIGNAL(changed(const QColor &)), + SLOT( selectColor(const QColor &))); + + btpix = new QPushButton(i18n( "Choose..." ), bbox); + connect( btpix, SIGNAL( clicked() ), SLOT( selectPixmap() ) ); + + QGroupBox *grp2 = new QGroupBox( i18n( "Preview" ), this ); + mainLayout->addWidget( grp2, 1 ); + + QBoxLayout *l2 = new QVBoxLayout( grp2, 15 ); + + l2->addSpacing( 10 ); + + lb_ex = new QLabel( grp2 ); + lb_ex->setFrameStyle( QFrame::Panel | QFrame::Sunken ); + l2->addWidget( lb_ex ); + +/* + l1->addWidget( btngrp, 0, AlignLeft ); + l1->addLayout( l1r ); +*/ + bgmode = props->bgMode(); + + if( bgmode == QWidget::FixedPixmap ) + { + btngrp->setButton( 1 ); + btcolor->setEnabled( false ); + lb_ex->setBackgroundPixmap( pix ); + } + else + { + btngrp->setButton( 0 ); + btpix->setEnabled( false ); + lb_ex->setBackgroundColor(btcolor->color()); + } +} + +KBackgroundConfig::~KBackgroundConfig() +{ +} + +void KBackgroundConfig::slotBackgroundMode(int id) +{ + if(id == 0) + { + bgmode = QWidget::FixedColor; + btpix->setEnabled(false); + btcolor->setEnabled(true); + if(lb_ex) + lb_ex->setBackgroundColor(btcolor->color()); + } + else + { + bgmode = QWidget::FixedPixmap; + btpix->setEnabled(true); + btcolor->setEnabled(false); + if(lb_ex) + lb_ex->setBackgroundPixmap(pix); + } +} + +void KBackgroundConfig::saveSettings() +{ + kdDebug(4640) << "KBackgroundConfig::saveSettings" << endl; + KIconEditProperties *props = KIconEditProperties::self(); + props->setBgMode( bgmode ); + props->setBgPixmap( pixpath ); + props->setBgColor( btcolor->color() ); + kdDebug(4640) << "KBackgroundConfig::saveSettings - done" << endl; +} + +void KBackgroundConfig::selectColor(const QColor & newColor) +{ + lb_ex->setBackgroundColor(newColor); +} + +void KBackgroundConfig::selectPixmap() +{ + // KURL url = KFileDialog::getOpenURL("/", "*.xpm"); + KURL url = KFileDialog::getImageOpenURL("/"); + + if( url.isEmpty() ) + return; + + if( !url.isLocalFile() ) + { + KMessageBox::sorry( 0L, i18n( "Only local files are supported yet." ) ); + return; + } + + QPixmap p(url.path()); + + if( !p.isNull() ) + { + lb_ex->setBackgroundPixmap( p ); + pixpath = url.path(); + } +} + +KMiscConfig::KMiscConfig(QWidget *parent) : QWidget(parent) +{ + kdDebug(4640) << "KMiscConfig - constructor" << endl; + + KIconEditProperties* props = KIconEditProperties::self(); + + QBoxLayout *ml = new QVBoxLayout( this, 0, 5 ); + + QCheckBox *cbp = new QCheckBox( i18n( "Paste &transparent pixels" ), this ); + connect( cbp, SIGNAL( toggled( bool ) ), SLOT( pasteMode( bool ) ) ); + ml->addWidget(cbp); + + QCheckBox *cbr = new QCheckBox( i18n( "Show &rulers" ), this ); + connect( cbr, SIGNAL( toggled( bool ) ), SLOT( showRulers( bool ) ) ); + ml->addWidget(cbr); + + QButtonGroup* btngrp = new QButtonGroup( i18n( "Transparency Display" ), this); + btngrp->setExclusive( true ); + connect( btngrp, SIGNAL( clicked( int ) ), SLOT( slotTransparencyDisplayType( int ) ) ); + ml->addWidget( btngrp ); + + QVBoxLayout *tgl = new QVBoxLayout( btngrp, KDialog::marginHint(), KDialog::spacingHint() ); + tgl->insertSpacing(0, 10); + + QHBoxLayout *hl = new QHBoxLayout(tgl); + + QRadioButton *solidColorRButton = new QRadioButton( i18n( "&Solid color:" ), btngrp ); + btngrp->insert( solidColorRButton, 0 ); + hl->addWidget( solidColorRButton ); + + m_solidColorButton = new KColorButton(props->transparencySolidColor(), btngrp); + btngrp->insert( m_solidColorButton, 2 ); + hl->addWidget(m_solidColorButton); + //connect(btcolor, SIGNAL(changed(const QColor &)), + // SLOT( selectColor(const QColor &))); + + QRadioButton *checkerboardRButton = new QRadioButton( i18n( "Checker&board" ), btngrp ); + btngrp->insert( checkerboardRButton, 1 ); + tgl->addWidget( checkerboardRButton ); + + QGridLayout *grid = new QGridLayout(tgl, 3, 3); + grid->addColSpacing(0, 40); + grid->setColStretch(1, 1); + grid->setColStretch(2, 1); + + m_checkerboardSizeCombo = new QComboBox(btngrp); + m_checkerboardSizeCombo->insertItem( i18n( "Small" ) ); + m_checkerboardSizeCombo->insertItem( i18n( "Medium" ) ); + m_checkerboardSizeCombo->insertItem( i18n( "Large" ) ); + m_checkerboardSizeCombo->setCurrentItem(props->checkerboardSize()); + + QLabel *label = new QLabel(m_checkerboardSizeCombo, i18n("Si&ze:"), btngrp); + + grid->addWidget(label, 0, 1); + grid->addWidget(m_checkerboardSizeCombo, 0, 2); + + m_checkerboardColor1Button = new KColorButton(props->checkerboardColor1(), btngrp); + label = new QLabel(m_checkerboardColor1Button, i18n("Color &1:"), btngrp); + + grid->addWidget(label, 1, 1); + grid->addWidget(m_checkerboardColor1Button, 1, 2); + + m_checkerboardColor2Button = new KColorButton(props->checkerboardColor2(), btngrp); + label = new QLabel(m_checkerboardColor2Button, i18n("Color &2:"), btngrp); + + grid->addWidget(label, 2, 1); + grid->addWidget(m_checkerboardColor2Button, 2, 2); + + if(props->transparencyDisplayType() == KIconEditGrid::TRD_CHECKERBOARD) + { + checkerboardRButton->setChecked(true); + m_checkerboardColor1Button->setEnabled(true); + m_checkerboardColor2Button->setEnabled(true); + m_checkerboardSizeCombo->setEnabled(true); + + solidColorRButton->setChecked(false); + m_solidColorButton->setEnabled(false); + } + else + { + checkerboardRButton->setChecked(false); + m_checkerboardColor1Button->setEnabled(false); + m_checkerboardColor2Button->setEnabled(false); + m_checkerboardSizeCombo->setEnabled(false); + + solidColorRButton->setChecked(true); + m_solidColorButton->setEnabled(true); + } + + ml->addStretch(1); + + cbp->setChecked( props->pasteTransparent() ); + cbr->setChecked( props->showRulers() ); +} + +KMiscConfig::~KMiscConfig() +{ + +} + +void KMiscConfig::saveSettings() +{ + kdDebug(4640) << "KMiscConfig::saveSettings" << endl; + KIconEditProperties* props = KIconEditProperties::self(); + props->setPasteTransparent( pastemode ); + props->setShowRulers( showrulers ); + if(m_solidColorButton->isEnabled()) + { + props->setTransparencyDisplayType(KIconEditGrid::TRD_SOLIDCOLOR); + props->setTransparencySolidColor(m_solidColorButton->color()); + } + else + { + props->setTransparencyDisplayType(KIconEditGrid::TRD_CHECKERBOARD); + props->setCheckerboardColor1(m_checkerboardColor1Button->color()); + props->setCheckerboardColor2(m_checkerboardColor2Button->color()); + props->setCheckerboardSize((KIconEditGrid::CheckerboardSize)m_checkerboardSizeCombo->currentItem()); + } +} + +void KMiscConfig::pasteMode(bool mode) +{ + pastemode = mode; +} + +void KMiscConfig::showRulers(bool mode) +{ + showrulers = mode; +} + +void KMiscConfig::slotTransparencyDisplayType(int id) +{ + if(id == 0) + { + m_checkerboardColor1Button->setEnabled(false); + m_checkerboardColor2Button->setEnabled(false); + m_checkerboardSizeCombo->setEnabled(false); + + m_solidColorButton->setEnabled(true); + } + else + if(id == 1) + { + m_checkerboardColor1Button->setEnabled(true); + m_checkerboardColor2Button->setEnabled(true); + m_checkerboardSizeCombo->setEnabled(true); + + m_solidColorButton->setEnabled(false); + } +} + +KIconConfig::KIconConfig(QWidget *parent) + : KDialogBase(KDialogBase::IconList, i18n("Configure"), + KDialogBase::Help | + KDialogBase::Ok | + KDialogBase::Apply | + KDialogBase::Cancel, + KDialogBase::Ok, + parent, "configDialog", true, true) +{ + setHelp(QString::null); + //KWin::setIcons(winId(), kapp->icon(), kapp->miniIcon()); + connect(this, SIGNAL(finished()), this, SLOT(finis())); + + QVBox* page = addVBoxPage(i18n("Icon Templates"), QString::null, loadIcon("icons")); + temps = new KTemplateConfig(page); + + page = addVBoxPage(i18n("Background"), QString::null, loadIcon("background")); + backs = new KBackgroundConfig(page); + + page = addVBoxPage(i18n("Icon Grid"), QString::null, loadIcon("kiconedit")); + misc = new KMiscConfig(page); + + QSize min(300, 400); + + if (300 < sizeHint().width()) { min.setWidth(sizeHint().width()); } + if (400 < sizeHint().height()) { min.setHeight(sizeHint().height()); } + + resize(min); +} + +KIconConfig::~KIconConfig() +{ + //delete dict; +} + +void KIconConfig::slotApply() +{ + kdDebug(4640) << "KIconEditConfig::saveSettings" << endl; + + temps->saveSettings(); + backs->saveSettings(); + misc->saveSettings(); + + for (KIconEdit* window = KIconEdit::windowList.first(); + window; + window = KIconEdit::windowList.next()) + { + window->updateProperties(); + } +} + +void KIconConfig::slotOk() +{ + slotApply(); + KDialogBase::slotOk(); +} + +void KIconConfig::finis() +{ + delayedDestruct(); +} + +#include "kiconconfig.moc" diff --git a/kiconedit/kiconconfig.h b/kiconedit/kiconconfig.h new file mode 100644 index 00000000..04483732 --- /dev/null +++ b/kiconedit/kiconconfig.h @@ -0,0 +1,153 @@ +/* + KDE Icon Editor - a small icon drawing program for the KDE. + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.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 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 __KICONCONFIG_H__ +#define __KICONCONFIG_H__ + +#include +#include + +#include "knew.h" +#include "utils.h" +#include "properties.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +class KAccel; +class KKeyChooser; +class KColorButton; +class KURLRequester; +class QComboBox; + +class KTemplateEditDlg : public KDialogBase +{ + Q_OBJECT +public: + KTemplateEditDlg(QWidget *); + ~KTemplateEditDlg() {}; + + QString name(); + QString path(); + void setName(const QString &); + void setPath(const QString &); + +public slots: + void slotTextChanged(); + +protected: + QLineEdit *ln_name; + KURLRequester *ln_path; +}; + +class KTemplateConfig : public QWidget +{ + Q_OBJECT +public: + KTemplateConfig(QWidget*); + ~KTemplateConfig(); + + void saveSettings(); + +protected slots: + void add(); + void edit(); + void remove(); + void checkSelection(int); + +protected: + KIconListBox *templates; + QPushButton *btadd, *btedit, *btremove; +}; + +class KBackgroundConfig : public QWidget +{ + Q_OBJECT +public: + KBackgroundConfig(QWidget *parent); + ~KBackgroundConfig(); + +public slots: + void saveSettings(); + void selectColor(const QColor & newColor); + void selectPixmap(); + +signals: + +protected slots: + void slotBackgroundMode(int); + +protected: + KColorButton *btcolor; + QPushButton *btpix; + QPixmap pix; + QString pixpath; + QWidget::BackgroundMode bgmode; + QLabel *lb_ex; +}; + +class KMiscConfig : public QWidget +{ + Q_OBJECT +public: + KMiscConfig(QWidget *parent); + ~KMiscConfig(); + +public slots: + void saveSettings(); + void pasteMode(bool); + void showRulers(bool); + +protected slots: + void slotTransparencyDisplayType(int); + +signals: + +protected: + bool pastemode, showrulers; + QRadioButton *rbp; + KColorButton *m_solidColorButton; + KColorButton *m_checkerboardColor1Button; + KColorButton *m_checkerboardColor2Button; + QComboBox *m_checkerboardSizeCombo; +}; + +class KIconConfig : public KDialogBase +{ + Q_OBJECT + +public: + + KIconConfig(QWidget *parent); + ~KIconConfig(); + +protected slots: + void slotApply(); + void slotOk(); + void finis(); + +protected: + KTemplateConfig *temps; + KBackgroundConfig *backs; + KMiscConfig *misc; +}; + +#endif //__KICONCONFIG_H__ diff --git a/kiconedit/kiconedit.cpp b/kiconedit/kiconedit.cpp new file mode 100644 index 00000000..13cd4b89 --- /dev/null +++ b/kiconedit/kiconedit.cpp @@ -0,0 +1,497 @@ +/* + kiconedit - a small graphics drawing program for the KDE + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.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 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 +#include + +#include +#include +#include +#include +#include +#include + +#include "kiconedit.h" +#include "palettetoolbar.h" + +WindowList KIconEdit::windowList; + +KIconEdit::KIconEdit(const QImage image, const char *name) + : KMainWindow(0, name) +{ + init(); + img = image; + img.detach(); + grid->load(&img); + grid->setModified(true); +} + +KIconEdit::KIconEdit(KURL url, const char *name) + : KMainWindow(0, name) +{ + init(); + icon->open(&img, url); +} + +void KIconEdit::init() +{ + setMinimumSize( 600, 540 ); + + windowList.append(this); + setCaption(kapp->caption()); + + m_paletteToolBar = 0L; + statusbar = 0L; + + history = new KCommandHistory( actionCollection(), true ); + + gridview = new KGridView(&img, history, this); + grid = gridview->grid(); + icon = new KIconEditIcon(this, &grid->image()); + + setAcceptDrops(true); + + setupActions(); + setupStatusBar(); + setStandardToolBarMenuEnabled( true ); + + createGUI(); + + connect(this, SIGNAL(newname(const QString &)), + SLOT( slotUpdateStatusName(const QString &))); + + connect( icon, SIGNAL( saved()), SLOT(slotSaved())); + connect( icon, SIGNAL( loaded(QImage *)), grid, SLOT(load(QImage *))); + connect( icon, SIGNAL(opennewwin(const QString &)), + SLOT(slotNewWin(const QString &))); + connect(icon, SIGNAL(newname(const QString &)), + SLOT( slotUpdateStatusName(const QString &))); + connect(icon, SIGNAL(newmessage(const QString &)), + SLOT( slotUpdateStatusMessage(const QString &))); + connect(icon, SIGNAL(addrecent(const QString &)), + SLOT( addRecent(const QString &))); + + connect( m_paletteToolBar, SIGNAL( newColor(uint)), + grid, SLOT(setColorSelection(uint))); + + connect( grid, SIGNAL( changed(const QPixmap &) ), + m_paletteToolBar, SLOT( previewChanged(const QPixmap &) ) ); + connect( grid, SIGNAL( addingcolor(uint) ), + m_paletteToolBar, SLOT(addColor(uint))); + connect( grid, SIGNAL( colorschanged(uint, uint*) ), + m_paletteToolBar, SLOT(addColors(uint, uint*))); + + connect(grid, SIGNAL(sizechanged(int, int)), + SLOT( slotUpdateStatusSize(int, int))); + connect(grid, SIGNAL(poschanged(int, int)), + SLOT( slotUpdateStatusPos(int, int))); + connect(grid, SIGNAL(scalingchanged(int)), + SLOT( slotUpdateStatusScaling(int))); + connect(grid, SIGNAL(scalingchanged(int)), + SLOT( slotUpdateZoom(int))); + connect( grid, SIGNAL( addingcolor(uint) ), + SLOT(slotUpdateStatusColors(uint))); + connect(grid, SIGNAL(colorschanged(uint, uint*)), + SLOT( slotUpdateStatusColors(uint, uint*))); + connect(grid, SIGNAL(newmessage(const QString &)), + SLOT( slotUpdateStatusMessage(const QString &))); + connect(grid, SIGNAL(clipboarddata(bool)), + SLOT( slotUpdatePaste(bool))); + connect(grid, SIGNAL(colorSelected(uint)), + m_paletteToolBar, SLOT(currentColorChanged(uint))); + connect(grid, SIGNAL(modifiedchanged(bool)), + SLOT( slotUpdateStatusModified(bool))); + gridview->checkClipboard(); //Not very elegant, but fixes a buglet + + connect(grid, SIGNAL(selecteddata(bool)), SLOT( slotUpdateCopy(bool))); + + kdDebug(4640) << "Updating statusbar" << endl; + slotUpdateStatusSize(grid->cols(), grid->rows()); + slotUpdateStatusScaling(grid->scaling()); + + slotUpdateZoom( grid->scaling() ); + + if(icon->url().length()) + slotUpdateStatusName(icon->url()); + else + slotUpdateStatusName(i18n("Untitled")); + + slotUpdateCopy(false); + + uint *c = 0, n = 0; + n = grid->getColors(c); + slotUpdateStatusColors(n, c); + + setCentralWidget(gridview); + + applyMainWindowSettings( kapp->config(), "MainWindowSettings" ); + updateProperties(); + + updateAccels(); + show(); + moveDockWindow( m_paletteToolBar, Qt::DockRight, true, 0 ); +} + +KIconEdit::~KIconEdit() +{ + windowList.remove(this); + + if (windowList.count() < 1) + { + kapp->quit(); + } +} + +bool KIconEdit::queryClose() +{ + bool cancel = false; + if (grid->isModified()) + { + int r = KMessageBox::warningYesNoCancel(this, + i18n("The current file has been modified.\nDo you want to save it?"), QString::null, KStdGuiItem::save(), KStdGuiItem::discard()); + + switch(r) + { + case KMessageBox::Yes: + if (!icon->save(&grid->image())) + { + cancel = true; + } + break; + case KMessageBox::Cancel: + cancel = true; + break; + case KMessageBox::No: + default: + break; + } + } + + if(!cancel) + { + writeConfig(); + } + return (!cancel); +} + +// this is for exit by request of the session manager +void KIconEdit::saveProperties(KConfig *config ) +{ + kdDebug(4640) << "KIconEdit::saveProperties" << endl; + + config->writePathEntry("Name", icon->url()); +} + +// this is for instances opened by the session manager +void KIconEdit::readProperties(KConfig *config) +{ + kdDebug(4640) << "KIconEdit::readProperties" << endl; + + QString entry = config->readPathEntry("Name"); // no default + if (entry.isEmpty()) return; + icon->open(&grid->image(), KURL::fromPathOrURL( entry )); +} + +/* + this is for normal exits or request from "Options->Save options". +*/ +void KIconEdit::writeConfig() +{ + KConfig *config = kapp->config(); + m_actRecent->saveEntries( kapp->config() ); + + KIconEditProperties::self()->save(); + + saveMainWindowSettings( config, "MainWindowSettings" ); +} + +QSize KIconEdit::sizeHint() const +{ + if(gridview) + return gridview->sizeHint(); + else + return QSize(-1, -1); +} + +void KIconEdit::setupActions() +{ + kdDebug(4640) << "setupActions" << endl; + + KAction *action; + KRadioAction *toolAction; + KShortcut cut; + + // File Menu + action = new KAction(i18n("New &Window"), "window_new", cut, + this, SLOT(slotNewWin()), actionCollection(), "file_new_window"); + action->setWhatsThis(i18n("New window\n\nOpens a new icon editor window.")); + + action = KStdAction::openNew(this, SLOT(slotNew()), actionCollection()); + action->setWhatsThis(i18n("New\n\nCreate a new icon, either from a" + " template or by specifying the size")); + + action = KStdAction::open(this, SLOT(slotOpen()), actionCollection()); + action->setWhatsThis(i18n("Open\n\nOpen an existing icon")); + + m_actRecent = KStdAction::openRecent(this, + SLOT(slotOpenRecent(const KURL&)), actionCollection()); + m_actRecent->setMaxItems(15); // FIXME should be configurable! + m_actRecent->loadEntries(kapp->config()); + + action = KStdAction::save(this, SLOT(slotSave()), actionCollection()); + action->setWhatsThis(i18n("Save\n\nSave the current icon")); + + KStdAction::saveAs(this, SLOT(slotSaveAs()), actionCollection()); + + action = KStdAction::print(this, SLOT(slotPrint()), actionCollection()); + action->setWhatsThis(i18n("Print\n\nOpens a print dialog to let you print" + " the current icon.")); + + KStdAction::close(this, SLOT(slotClose()), actionCollection()); + + // Edit Menu + + m_actCut = KStdAction::cut(this, SLOT(slotCut()), actionCollection()); + m_actCut->setWhatsThis(i18n("Cut\n\nCut the current selection out of the" + " icon.\n\n(Tip: You can make both rectangular and circular selections)")); + + m_actCopy = KStdAction::copy(this, SLOT(slotCopy()), actionCollection()); + m_actCopy->setWhatsThis(i18n("Copy\n\nCopy the current selection out of the" + " icon.\n\n(Tip: You can make both rectangular and circular selections)")); + + m_actPaste = KStdAction::paste(this, SLOT(slotPaste()), actionCollection()); + m_actPaste->setWhatsThis(i18n("Paste\n\n" + "Paste the contents of the clipboard into the current icon.\n\n" + "If the contents are larger than the current icon you can paste them" + " in a new window.\n\n" + "(Tip: Select \"Paste transparent pixels\" in the configuration dialog" + " if you also want to paste transparency.)")); + + m_actPasteNew = new KAction( i18n( "Paste as &New" ), cut, grid, + SLOT( editPasteAsNew() ), actionCollection(), "edit_paste_as_new" ); + + KStdAction::clear(this, SLOT(slotClear()), actionCollection()); + KStdAction::selectAll(this, SLOT(slotSelectAll()), actionCollection()); + + action = new KAction(i18n("Resi&ze..."), "transform", cut, + grid, SLOT(editResize()), actionCollection(), "edit_resize"); + action->setWhatsThis(i18n("Resize\n\nSmoothly resizes the icon while" + " trying to preserve the contents")); + + action = new KAction(i18n("&GrayScale"), "grayscale", cut, + grid, SLOT(grayScale()), actionCollection(), "edit_grayscale"); + action->setWhatsThis(i18n("Gray scale\n\nGray scale the current icon.\n" + "(Warning: The result is likely to contain colors not in the icon" + " palette")); + + // View Menu + m_actZoomIn = KStdAction::zoomIn(this, SLOT(slotZoomIn()), + actionCollection()); + m_actZoomIn->setWhatsThis(i18n("Zoom in\n\nZoom in by one.")); + + m_actZoomOut = KStdAction::zoomOut(this, SLOT(slotZoomOut()), + actionCollection()); + m_actZoomOut->setWhatsThis(i18n("Zoom out\n\nZoom out by one.")); + + KActionMenu *actMenu = new KActionMenu( i18n( "&Zoom" ), "viewmag", + actionCollection(), "view_zoom" ); + + // xgettext:no-c-format + action = new KAction( i18n( "100%" ), cut, this, SLOT( slotZoom1() ), + actionCollection(), "view_zoom_1" ); + actMenu->insert( action ); + // xgettext:no-c-format + action = new KAction( i18n( "200%" ), cut, this, SLOT( slotZoom2() ), + actionCollection(), "view_zoom_2" ); + actMenu->insert( action ); + // xgettext:no-c-format + action = new KAction( i18n( "500%" ), cut, this, SLOT( slotZoom5() ), + actionCollection(), "view_zoom_5" ); + actMenu->insert( action ); + // xgettext:no-c-format + action = new KAction( i18n( "1000%" ), cut, this, SLOT( slotZoom10() ), + actionCollection(), "view_zoom_10" ); + actMenu->insert( action ); + + // Settings Menu + KStdAction::keyBindings(this, SLOT(slotConfigureKeys()), + actionCollection()); + KStdAction::preferences(this, SLOT(slotConfigureSettings()), + actionCollection()); + + createStandardStatusBarAction(); + + KToggleAction *toggle; + + toggle = new KToggleAction( i18n( "Show &Grid" ), "grid", + cut, this, SLOT( slotShowGrid() ), actionCollection(), + "options_show_grid" ); + toggle->setCheckedState(i18n("Hide &Grid")); + toggle->setWhatsThis( i18n( "Show grid\n\nToggles the grid in the icon" + " edit grid on/off" ) ); + toggle->setChecked( KIconEditProperties::self()->showGrid() ); + + // Tools Menu + toolAction = new KRadioAction(i18n("Color Picker"), "colorpicker", + cut, this, SLOT(slotToolPointer()), actionCollection(), + "tool_find_pixel"); + toolAction->setExclusiveGroup("toolActions"); + toolAction->setWhatsThis(i18n("Color Picker\n\nThe color of the pixel clicked" + " on will be the current draw color")); + + toolAction = new KRadioAction(i18n("Freehand"), "paintbrush", + cut, this, SLOT(slotToolFreehand()), actionCollection(), + "tool_freehand"); + toolAction->setExclusiveGroup("toolActions"); + toolAction->setWhatsThis(i18n("Free hand\n\nDraw non-linear lines")); + + toolAction->setChecked( true ); + grid->setTool(KIconEditGrid::Freehand); + + toolAction = new KRadioAction(i18n("Rectangle"), "rectangle", + cut, this, SLOT(slotToolRectangle()), actionCollection(), + "tool_rectangle"); + toolAction->setExclusiveGroup("toolActions"); + toolAction->setWhatsThis(i18n("Rectangle\n\nDraw a rectangle")); + + toolAction = new KRadioAction(i18n("Filled Rectangle"), "filledrectangle", + cut, this, SLOT(slotToolFilledRectangle()), actionCollection(), + "tool_filled_rectangle"); + toolAction->setExclusiveGroup("toolActions"); + toolAction->setWhatsThis(i18n("Filled rectangle\n\nDraw a filled rectangle")); + + toolAction = new KRadioAction(i18n("Circle"), "circle", + cut, this, SLOT(slotToolCircle()), actionCollection(), + "tool_circle"); + toolAction->setExclusiveGroup("toolActions"); + toolAction->setWhatsThis(i18n("Circle\n\nDraw a circle")); + + toolAction = new KRadioAction(i18n("Filled Circle"), "filledcircle", + cut, this, SLOT(slotToolFilledCircle()), actionCollection(), + "tool_filled_circle"); + toolAction->setExclusiveGroup("toolActions"); + toolAction->setWhatsThis(i18n("Filled circle\n\nDraw a filled circle")); + + toolAction = new KRadioAction(i18n("Ellipse"), "ellipse", + cut, this, SLOT(slotToolEllipse()), actionCollection(), + "tool_ellipse"); + toolAction->setExclusiveGroup("toolActions"); + toolAction->setWhatsThis(i18n("Ellipse\n\nDraw an ellipse")); + + toolAction = new KRadioAction(i18n("Filled Ellipse"), "filledellipse", + cut, this, SLOT(slotToolFilledEllipse()), actionCollection(), + "tool_filled_ellipse"); + toolAction->setExclusiveGroup("toolActions"); + toolAction->setWhatsThis(i18n("Filled ellipse\n\nDraw a filled ellipse")); + + toolAction = new KRadioAction(i18n("Spray"), "airbrush", + cut, this, SLOT(slotToolSpray()), actionCollection(), + "tool_spray"); + toolAction->setExclusiveGroup("toolActions"); + toolAction->setWhatsThis(i18n("Spray\n\nDraw scattered pixels in the" + " current color")); + + toolAction = new KRadioAction(i18n("Flood Fill"), "fill", + cut, this, SLOT(slotToolFlood()), actionCollection(), + "tool_flood_fill"); + toolAction->setExclusiveGroup("toolActions"); + toolAction->setWhatsThis(i18n("Flood fill\n\nFill adjoining pixels with" + " the same color with the current color")); + + toolAction = new KRadioAction(i18n("Line"), "line", + cut, this, SLOT(slotToolLine()), actionCollection(), + "tool_line"); + toolAction->setExclusiveGroup("toolActions"); + toolAction->setWhatsThis(i18n("Line\n\nDraw a straight line vertically," + " horizontally or at 45 deg. angles")); + + toolAction = new KRadioAction(i18n("Eraser (Transparent)"), "eraser", + cut, this, SLOT(slotToolEraser()), actionCollection(), + "tool_eraser"); + toolAction->setExclusiveGroup("toolActions"); + toolAction->setWhatsThis(i18n("Erase\n\nErase pixels. Set the pixels to" + " be transparent\n\n(Tip: If you want to draw transparency with a" + " different tool, first click on \"Erase\" then on the tool you want" + " to use)")); + + toolAction = new KRadioAction(i18n("Rectangular Selection"), + "selectrect", cut, this, SLOT(slotToolSelectRect()), + actionCollection(), "edit_select_rectangle"); + toolAction->setExclusiveGroup( "toolActions" ); + toolAction->setWhatsThis(i18n("Select\n\nSelect a rectangular section" + " of the icon using the mouse.")); + + toolAction = new KRadioAction(i18n("Circular Selection"), + "selectcircle", cut, this, SLOT(slotToolSelectCircle()), + actionCollection(), "edit_select_circle"); + toolAction->setExclusiveGroup( "toolActions" ); + toolAction->setWhatsThis(i18n("Select\n\nSelect a circular section of the" + " icon using the mouse.")); +} + +void KIconEdit::updateAccels() +{ + actionCollection()->readShortcutSettings(); +} + +QWidget *KIconEdit::createContainer( QWidget *parent, int index, + const QDomElement &element, int &id ) +{ + if ( element.attribute( "name" ) == "paletteToolBar" ) + { + m_paletteToolBar = new PaletteToolBar( this, "paletteToolBar" ); + m_paletteToolBar->setText( i18n( "Palette Toolbar" ) ); + return m_paletteToolBar; + } + + return KXMLGUIBuilder::createContainer( parent, index, element, id ); +} + +bool KIconEdit::setupStatusBar() +{ + statusbar = statusBar(); + + QString str = i18n("Statusbar\n\nThe statusbar gives information on" + " the status of the current icon. The fields are:\n\n" + "\t- Application messages\n\t- Cursor position\n\t- Size\n\t- Zoom factor\n" + "\t- Number of colors"); + QWhatsThis::add(statusBar(), str); + + statusbar->insertFixedItem("99999,99999", 0, true); + statusbar->insertFixedItem("99999 x 99999", 1, true); + statusbar->insertFixedItem(" 1:999", 2, true); + str = i18n("Colors: %1").arg(9999999); + statusbar->insertFixedItem(str, 3, true); + statusbar->insertItem("", 4); + + statusbar->changeItem( "", 0); + statusbar->changeItem( "", 1); + statusbar->changeItem( "", 2); + statusbar->changeItem( "", 3); + + return true; +} + +void KIconEdit::addRecent(const QString & path) +{ + m_actRecent->addURL(KURL( path )); +} + +#include "kiconedit.moc" diff --git a/kiconedit/kiconedit.desktop b/kiconedit/kiconedit.desktop new file mode 100644 index 00000000..be70ac9f --- /dev/null +++ b/kiconedit/kiconedit.desktop @@ -0,0 +1,95 @@ +[Desktop Entry] +GenericName=Icon Editor +GenericName[af]=Ikoon Redigeerder +GenericName[ar]=محرر الإيقونات +GenericName[bg]=Редактор на икони +GenericName[br]=Aozer arlunioù +GenericName[bs]=Editor ikona +GenericName[ca]=Editor d'icones +GenericName[cs]=Editor ikon +GenericName[cy]=Golygydd Eiconau +GenericName[da]=Ikoneditor +GenericName[de]=Editor für Arbeitsflächensymbole +GenericName[el]=Επεξεργαστής εικονιδίων +GenericName[eo]=Ilo por pentri kaj redakti piktogramojn +GenericName[es]=Editor de iconos +GenericName[et]=Ikoonide redaktor +GenericName[eu]=Ikono editorea +GenericName[fa]=ویرایشگر شمایل +GenericName[fi]=Kuvakemuokkain +GenericName[fr]=Éditeur d'icônes +GenericName[ga]=Eagarthóir Deilbhíní +GenericName[gl]=Editor de iconas +GenericName[he]=עורך סמלים +GenericName[hi]=प्रतीक (आइकॉन) संपादक +GenericName[hr]=Uređivač ikona +GenericName[hu]=Ikonszerkesztő +GenericName[is]=Táknmyndaritill +GenericName[it]=Editor di icone +GenericName[ja]=アイコンエディタ +GenericName[kk]=Таңбаша өңдегіші +GenericName[km]=កម្មវិធី​និពន្ធ​រូបតំណាង +GenericName[lt]=Ženkliukų redaktorius +GenericName[lv]=Ikonu Redaktors +GenericName[ms]=Editor Ikon +GenericName[nb]=Ikonredigerer +GenericName[nds]=Lüttbildeditor +GenericName[ne]=प्रतिमा सम्पादक +GenericName[nl]=Pictogrambewerker +GenericName[nn]=Ikonredigering +GenericName[nso]=Mofetosi wa Seemedi +GenericName[pa]=ਆਈਕਾਨ ਸੰਪਾਦਕ +GenericName[pl]=Edytor ikon +GenericName[pt]=Editor de Ícones +GenericName[pt_BR]=Editor de Ícones +GenericName[ro]=Editor de iconiţe +GenericName[ru]=Редактор пиктограмм +GenericName[se]=Govašdoaimmaheaddji +GenericName[sk]=Editor ikon +GenericName[sl]=Urejevalnik ikon +GenericName[sr]=Уређивач икона +GenericName[sr@Latn]=Uređivač ikona +GenericName[sv]=Ikoneditor +GenericName[ta]= கேசின்னம் திருத்தி +GenericName[tg]=Муҳаррири ишорот +GenericName[th]=เครื่องมือแก้ไขไอคอน +GenericName[tr]=Simge Düzenleyici +GenericName[uk]=Редактор піктограм +GenericName[uz]=Nishoncha tahrirchi +GenericName[uz@cyrillic]=Нишонча таҳрирчи +GenericName[ven]=Musengulusi wa Aikhono +GenericName[wa]=Aspougneu d' imådjetes +GenericName[xh]=Umhleli we Icon +GenericName[zh_CN]=图标编辑器 +GenericName[zh_HK]=圖示編輯器 +GenericName[zh_TW]=圖示編輯器 +GenericName[zu]=Umhleli we Icon +Name=KIconEdit +Name[af]=K-ikoon-redigeer +Name[ar]=برنامج KIconEdit +Name[cy]=KGolyguEicon +Name[eo]=Piktogramredaktilo +Name[hi]=के-आइकॉन-एडिट +Name[hr]=Uređivač ikona +Name[is]=Táknmyndaritill +Name[lv]=KIkonuRedaktors +Name[ms]=KIkonEdit +Name[ne]=केडीई प्रतिमा सम्पादन +Name[pl]=Edytor ikon +Name[pt_BR]=KEditor de Ícones +Name[ro]=Editor iconiţe +Name[sv]=Kiconedit +Name[ta]=கேசின்னம் திருத்து +Name[tr]=K Icon Düzenleyici +Name[ven]=U sengulusa ha aikhono ya K +Name[zh_TW]=KIconEdit 圖示編輯器 +MimeType=image/x-xpm;image/x-ico;image/png;image/jpeg; +Exec=kiconedit -caption "%c" %i %m %u +Icon=kiconedit +Path= +DocPath=kiconedit/index.html +Type=Application +Terminal=false + +X-DCOP-ServiceType=Multi +Categories=Qt;KDE;Graphics;X-KDE-More; diff --git a/kiconedit/kiconedit.h b/kiconedit/kiconedit.h new file mode 100644 index 00000000..54227206 --- /dev/null +++ b/kiconedit/kiconedit.h @@ -0,0 +1,157 @@ +/* + kiconedit - a small graphics drawing program for creating KDE icons + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.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 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 __KICONEDIT_H__ +#define __KICONEDIT_H__ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "knew.h" +#include "kicon.h" +#include "kiconconfig.h" +#include "kicongrid.h" +#include "kresize.h" +#include "properties.h" + +class KIconEdit; +class KCommandHistory; +typedef QPtrList WindowList; + +class QWhatsThis; +class QToolButton; +class QLabel; +class PaletteToolBar; + +/** +* KIconEdit +* @short KIconEdit +* @author Thomas Tanghus +* @version 0.4 +*/ +class KIconEdit : public KMainWindow +{ + Q_OBJECT +public: + KIconEdit( KURL url = KURL(), const char *name = "kiconedit"); + KIconEdit( const QImage image, const char *name = "kiconedit"); + ~KIconEdit(); + + virtual QSize sizeHint() const; + static WindowList windowList; + +signals: + void newname(const QString &); + +public slots: + virtual void saveProperties(KConfig*); + virtual void readProperties(KConfig*); + void updateProperties(); + +protected slots: + void slotNewWin(const QString & url = 0); + void slotNew(); + void slotOpen(); + void slotClose(); + void slotSave(); + void slotSaveAs(); + void slotPrint(); + void slotZoomIn(); + void slotZoomOut(); + void slotZoom1(); + void slotZoom2(); + void slotZoom5(); + void slotZoom10(); + void slotCopy(); + void slotCut(); + void slotPaste(); + void slotClear(); + void slotSaved(); + void slotSelectAll(); + void slotOpenRecent(const KURL&); + void slotToolPointer(); + void slotToolFreehand(); + void slotToolRectangle(); + void slotToolFilledRectangle(); + void slotToolCircle(); + void slotToolFilledCircle(); + void slotToolEllipse(); + void slotToolFilledEllipse(); + void slotToolSpray(); + void slotToolFlood(); + void slotToolLine(); + void slotToolEraser(); + void slotToolSelectRect(); + void slotToolSelectCircle(); + void slotConfigureSettings(); + void slotConfigureKeys(); + void slotShowGrid(); + void slotUpdateZoom( int ); + void slotUpdateStatusColors(uint); + void slotUpdateStatusColors(uint, uint*); + void slotUpdateStatusPos(int, int); + void slotUpdateStatusSize(int, int); + void slotUpdateStatusMessage(const QString &); + void slotUpdateStatusName(const QString &); + void slotUpdateStatusModified(bool); + void slotUpdateStatusScaling(int); + void slotUpdatePaste(bool); + void slotUpdateCopy(bool); + void slotOpenBlank(const QSize); + void addRecent(const QString &); + + virtual void dragEnterEvent(QDragEnterEvent* event); + virtual void dropEvent(QDropEvent *e); + +protected: + void init(); + void setupActions(); + bool setupStatusBar(); + void writeConfig(); + void updateAccels(); + + virtual bool queryClose(); + virtual QWidget *createContainer( QWidget*, int, const QDomElement&, int& ); + + KCommandHistory* history; + PaletteToolBar *m_paletteToolBar; + KStatusBar *statusbar; + KIconEditGrid *grid; + KGridView *gridview; + KIconEditIcon *icon; + QImage img; + QString m_name; + + KAction *m_actCopy, *m_actPaste, *m_actCut, *m_actPasteNew; + KAction *m_actZoomIn, *m_actZoomOut; + KRecentFilesAction *m_actRecent; +}; + +#endif //__KICONEDIT_H__ diff --git a/kiconedit/kiconeditslots.cpp b/kiconedit/kiconeditslots.cpp new file mode 100644 index 00000000..0d57d28e --- /dev/null +++ b/kiconedit/kiconeditslots.cpp @@ -0,0 +1,543 @@ +/* + KDE Icon Editor - a small graphics drawing program for the KDE + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.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 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 +#include + +#include +#include +#include +#include +#include +#include + +#include "kiconedit.h" +#include "kiconcolors.h" +#include "palettetoolbar.h" + +#ifndef PICS_INCLUDED +#define PICS_INCLUDED +#include "pics/logo.xpm" +#endif + +void KIconEdit::updateProperties() +{ + KIconEditProperties *props = KIconEditProperties::self(); + gridview->setShowRulers(props->showRulers()); + if(props->bgMode() == QWidget::FixedPixmap) + { + QPixmap pix(props->bgPixmap()); + if(pix.isNull()) + { + QPixmap pmlogo((const char**)logo); + pix = pmlogo; + } + gridview->viewPortWidget()->viewport()->setBackgroundPixmap(pix); + m_paletteToolBar->setPreviewBackground(pix); + } + else + { + gridview->viewPortWidget()->viewport() + ->setBackgroundColor(props->bgColor()); + m_paletteToolBar->setPreviewBackground(props->bgColor()); + } + grid->setTransparencyDisplayType(props->transparencyDisplayType()); + grid->setTransparencySolidColor(props->transparencySolidColor()); + grid->setCheckerboardColor1(props->checkerboardColor1()); + grid->setCheckerboardColor2(props->checkerboardColor2()); + grid->setCheckerboardSize(props->checkerboardSize()); + grid->update(); +} + +void KIconEdit::slotNewWin(const QString & url) +{ + //kdDebug(4640) << "KIconEdit::openNewWin() - " << url << endl; + + KIconEdit *w = new KIconEdit(KURL(url), "kiconedit"); + Q_CHECK_PTR(w); +} + + +void KIconEdit::slotNew() +{ + bool cancel = false; + if (grid->isModified()) + { + int r = KMessageBox::warningYesNoCancel(this, + i18n("The current file has been modified.\nDo you want to save it?"), QString::null, KStdGuiItem::save(), KStdGuiItem::discard()); + + switch(r) + { + case KMessageBox::Yes: + if(!icon->save(&grid->image())) + { + cancel = true; + } + break; + + case KMessageBox::No: + break; + + case KMessageBox::Cancel: + cancel = true; + break; + + default: + break; + } + } + if(!cancel) + { + KNewIcon newicon(this); + if(newicon.exec()) + { + int r = newicon.openStyle(); + if(r == KNewIcon::Blank) + { + grid->editClear(); + const QSize s = newicon.templateSize(); + //kdDebug(4640) << "Size: " << s.width() << " x " << s.height() << endl; + grid->setSize(s); + grid->setModified(false); + } + else if(r == KNewIcon::Template) + { + QString str = newicon.templatePath(); + icon->open(&grid->image(), KURL( str )); + } + icon->setUrl(""); + emit newname(i18n("Untitled")); + } + } +} + + +void KIconEdit::slotOpen() +{ + bool cancel = false; + + if( grid->isModified() ) + { + int r = KMessageBox::warningYesNoCancel(this, + i18n("The current file has been modified.\nDo you want to save it?"),QString::null, KStdGuiItem::save(), KStdGuiItem::discard()); + + switch( r ) + { + case KMessageBox::Yes: + if(!icon->save( &grid->image() )) + { + cancel = true; + } + break; + + case KMessageBox::No: + break; + + case KMessageBox::Cancel: + cancel = true; + break; + + default: + break; + } + } + + if( !cancel ) + { + if (icon->promptForFile( &grid->image() )) + { + grid->setModified(false); + } + } +} + +/* + close only the current window +*/ +void KIconEdit::slotClose() +{ + //kdDebug(4640) << "KIconEdit: Closing " << endl; + close(); +} + +void KIconEdit::slotSave() +{ + //kdDebug(4640) << "KIconEdit: slotSave() " << endl; + icon->save(&grid->image()); +} + + +void KIconEdit::slotSaveAs() +{ + //kdDebug(4640) << "KIconEdit: slotSaveAs() " << endl; + icon->saveAs(&grid->image()); +} + + +void KIconEdit::slotPrint() +{ + KPrinter printer; + + if ( printer.setup(this, i18n("Print %1").arg(icon->url().section('/', -1))) ) + { + int margin = 10, yPos = 0; + printer.setCreator("KDE Icon Editor"); + + QPainter p; + p.begin( &printer ); + QFontMetrics fm = p.fontMetrics(); + // need width/height + QPaintDeviceMetrics metrics( &printer ); + + p.drawText( margin, margin + yPos, metrics.width(), fm.lineSpacing(), + ExpandTabs | DontClip, icon->url() ); + yPos = yPos + fm.lineSpacing(); + p.drawPixmap( margin, margin + yPos, grid->pixmap() ); + p.end(); + } +} + +void KIconEdit::slotZoomIn() +{ + grid->zoom(DirIn); +} + +void KIconEdit::slotZoomOut() +{ + grid->zoom(DirOut); +} + +void KIconEdit::slotZoom1() +{ + grid->zoomTo(1); +} + +void KIconEdit::slotZoom2() +{ + grid->zoomTo(2); +} + +void KIconEdit::slotZoom5() +{ + grid->zoomTo(5); +} + +void KIconEdit::slotZoom10() +{ + grid->zoomTo(10); +} + +void KIconEdit::slotCopy() +{ + grid->editCopy(); +} + +void KIconEdit::slotCut() +{ + grid->editCopy(true); +} + +void KIconEdit::slotPaste() +{ + static_cast(actionCollection() + ->action("tool_find_pixel"))->setChecked(true); + grid->setTool(KIconEditGrid::Find); + grid->editPaste(); +} + +void KIconEdit::slotClear() +{ + grid->editClear(); +} + +void KIconEdit::slotSelectAll() +{ + grid->setTool(KIconEditGrid::SelectRect); + grid->editSelectAll(); +} + +void KIconEdit::slotOpenRecent(const KURL& iconFile) +{ + bool cancel = false; + + if( grid->isModified() ) + { + int r = KMessageBox::warningYesNoCancel(this, + i18n("The current file has been modified.\nDo you want to save it?"),QString::null, KStdGuiItem::save(), KStdGuiItem::discard()); + + switch( r ) + { + case KMessageBox::Yes: + if (!icon->save( &grid->image() )) + { + cancel = true; + } + break; + + case KMessageBox::No: + break; + + case KMessageBox::Cancel: + cancel = true; + break; + + default: + break; + } + } + + if( !cancel ) + { + if(icon->open(&grid->image(), iconFile)) + { + grid->setModified(false); + } + } +} + +void KIconEdit::slotConfigureSettings() +{ + KIconConfig* c = new KIconConfig(this); + c->exec(); + delete c; +} + +void KIconEdit::slotConfigureKeys() +{ + KKeyDialog::configure(actionCollection()); + + KIconEdit *ki = 0L; + for (ki = windowList.first(); ki; ki = windowList.next()) + { + if (ki != this) + { + ki->updateAccels(); + } + } +} + +void KIconEdit::slotShowGrid() +{ + bool b = KIconEditProperties::self()->showGrid(); + grid->setGrid( !b ); + KIconEditProperties::self()->setShowGrid( !b ); +} + +void KIconEdit::slotToolPointer() +{ + grid->setTool(KIconEditGrid::Find); +} + +void KIconEdit::slotToolFreehand() +{ + grid->setTool(KIconEditGrid::Freehand); +} + +void KIconEdit::slotToolRectangle() +{ + grid->setTool(KIconEditGrid::Rect); +} + +void KIconEdit::slotToolFilledRectangle() +{ + grid->setTool(KIconEditGrid::FilledRect); +} + +void KIconEdit::slotToolCircle() +{ + grid->setTool(KIconEditGrid::Circle); +} + +void KIconEdit::slotToolFilledCircle() +{ + grid->setTool(KIconEditGrid::FilledCircle); +} + +void KIconEdit::slotToolEllipse() +{ + grid->setTool(KIconEditGrid::Ellipse); +} + +void KIconEdit::slotToolFilledEllipse() +{ + grid->setTool(KIconEditGrid::FilledEllipse); +} + +void KIconEdit::slotToolSpray() +{ + grid->setTool(KIconEditGrid::Spray); +} + +void KIconEdit::slotToolFlood() +{ + grid->setTool(KIconEditGrid::FloodFill); +} + +void KIconEdit::slotToolLine() +{ + grid->setTool(KIconEditGrid::Line); +} + +void KIconEdit::slotToolEraser() +{ + grid->setTool(KIconEditGrid::Eraser); +} + +void KIconEdit::slotToolSelectRect() +{ + grid->setTool(KIconEditGrid::SelectRect); +} + +void KIconEdit::slotToolSelectCircle() +{ + grid->setTool(KIconEditGrid::SelectCircle); +} + +void KIconEdit::slotSaved() +{ + grid->setModified(false); +} + +void KIconEdit::slotUpdateZoom( int s ) +{ + m_actZoomOut->setEnabled( s>1 ); +} + +void KIconEdit::slotUpdateStatusPos(int x, int y) +{ + QString str = i18n("Status Position", "%1, %2").arg(x).arg(y); + statusbar->changeItem( str, 0); +} + +void KIconEdit::slotUpdateStatusSize(int x, int y) +{ + QString str = i18n("Status Size", "%1 x %2").arg(x).arg(y); + statusbar->changeItem( str, 1); +} + +void KIconEdit::slotUpdateStatusScaling(int s) +{ + KIconEditProperties::self()->setGridScale( s ); + QString str; + + str.sprintf("1:%d", s); + statusbar->changeItem( str, 2); +} + +void KIconEdit::slotUpdateStatusColors(uint) +{ + QString str = i18n("Colors: %1").arg(grid->numColors()); + statusbar->changeItem( str, 3); +} + +void KIconEdit::slotUpdateStatusColors(uint n, uint *) +{ + QString str = i18n("Colors: %1").arg(n); + statusbar->changeItem( str, 3); +} + + +void KIconEdit::slotUpdateStatusMessage(const QString & msg) +{ + statusbar->changeItem( msg, 4); +} + + +void KIconEdit::slotUpdateStatusName(const QString & name) +{ + m_name = name; + + QString text = m_name; + + if(grid->isModified()) + { + text += " ["+i18n("modified")+"]"; + } + + setCaption(text); +} + + +void KIconEdit::slotUpdateStatusModified(bool) +{ + slotUpdateStatusName(m_name); +} + +void KIconEdit::slotUpdatePaste(bool state) +{ + m_actPaste->setEnabled(state); + m_actPasteNew->setEnabled(state); +} + + +void KIconEdit::slotUpdateCopy(bool state) +{ + m_actCopy->setEnabled(state); + m_actCut->setEnabled(state); +} + + +void KIconEdit::slotOpenBlank(const QSize s) +{ + grid->loadBlank( s.width(), s.height()); +} + + +void KIconEdit::dragEnterEvent(QDragEnterEvent* e) +{ + e->accept(KURLDrag::canDecode(e)); +} + + +/* + accept drop of a file - opens file in current window + old code to drop image, as image, should be removed +*/ +void KIconEdit::dropEvent( QDropEvent *e ) +{ + //kdDebug(4640) << "Got QDropEvent!" << endl; + + KURL::List fileList; + bool loadedinthis = false; + + if(KURLDrag::decode(e, fileList)) + { + for(KURL::List::ConstIterator it = fileList.begin(); + it != fileList.end(); ++it) + { + //kdDebug(4640) << "In dropEvent for " << (*it).prettyURL() << endl; + const KURL &url = *it; + if(url.isValid()) + { + if (!grid->isModified() && !loadedinthis) + { + icon->open(&grid->image(), url); + loadedinthis = true; + } + else + { + slotNewWin(url.url()); + } + } + } + } +} + + diff --git a/kiconedit/kiconeditui.rc b/kiconedit/kiconeditui.rc new file mode 100644 index 00000000..cdef162c --- /dev/null +++ b/kiconedit/kiconeditui.rc @@ -0,0 +1,66 @@ + + + + &File + + + &Edit + + + + + + &Tools + + + + + + + + + + + + + + + + + &Settings + + + + + Main Toolbar + + + + + + + + + + Tools Toolbar + + + + + + + + + + + + + + + + + + Pallette Toolbar + + + diff --git a/kiconedit/kicongrid.cpp b/kiconedit/kicongrid.cpp new file mode 100644 index 00000000..abfb848e --- /dev/null +++ b/kiconedit/kicongrid.cpp @@ -0,0 +1,2263 @@ +/* + KDE Icon Editor - a small graphics drawing program for the KDE. + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.org) + + Includes portions of code from Qt, + Copyright (C) 1992-2000 Trolltech AS. + + 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 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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "kresize.h" +#include "properties.h" +#include "kicongrid.h" +#include "kiconedit.h" +#ifndef PICS_INCLUDED +#include "pics/logo.xpm" +#define PICS_INCLUDED +#endif + +#include + +void DrawCommand::execute() +{ + oldcolor = *((uint*)image->scanLine(y) + x); + *((uint*)image->scanLine(y) + x) = newcolor; + int cell = y * grid->numCols() + x; + grid->setUndoColor( cell, newcolor, false ); +} + +void DrawCommand::unexecute() +{ + *((uint*)image->scanLine(y) + x) = oldcolor; + int cell = y * grid->numCols() + x; + grid->setUndoColor( cell, oldcolor, false ); +} + +void RepaintCommand::execute() +{ + grid->update( area); +} + +KGridView::KGridView(QImage *image, KCommandHistory* history, QWidget *parent, const char *name) +: QFrame(parent, name) +{ + _corner = 0L; + _hruler = _vruler = 0L; + _grid = 0L; + + acceptdrop = false; + + KIconEditProperties *props = KIconEditProperties::self(); + + viewport = new QScrollView(this); + Q_CHECK_PTR(viewport); + + _grid = new KIconEditGrid(image, history, viewport->viewport()); + Q_CHECK_PTR(_grid); + viewport->addChild(_grid); + _grid->setGrid(props->showGrid()); + _grid->setCellSize(props->gridScale()); + + QString str = i18n( "Icon draw grid\n\nThe icon grid is the area where" + " you draw the icons.\nYou can zoom in and out using the magnifying" + " glasses on the toolbar.\n(Tip: Hold the magnify button down for a" + " few seconds to zoom to a predefined scale)" ); + QWhatsThis::add( _grid, str ); + + if(props->bgMode() == FixedPixmap) + { + QPixmap pix(props->bgPixmap()); + if(pix.isNull()) + { + QPixmap pmlogo((const char **)logo); + pix = pmlogo; + } + viewport->viewport()->setBackgroundPixmap(pix); + _grid->setBackgroundPixmap(pix); + } + else + { + viewport->viewport()->setBackgroundColor(props->bgColor()); + } + + _corner = new QFrame(this); + _corner->setFrameStyle(QFrame::WinPanel | QFrame::Raised); + + _hruler = new KRuler(Qt::Horizontal, this); + _hruler->setEndLabel(i18n("width")); + _hruler->setOffset( -2 ); + _hruler->setRange(0, 1000); + + _vruler = new KRuler(Qt::Vertical, this); + _vruler->setEndLabel(i18n("height")); + _vruler->setOffset( -2 ); + _vruler->setRange(0, 1000); + + str = i18n( "Rulers\n\nThis is a visual representation of the current" + " cursor position" ); + QWhatsThis::add( _hruler, str ); + QWhatsThis::add( _vruler, str ); + + connect(_grid, SIGNAL(scalingchanged(int)), SLOT(scalingChange(int))); + connect(_grid, SIGNAL(sizechanged(int, int)), SLOT(sizeChange(int, int))); + connect(_grid, SIGNAL(needPainting()), SLOT(paintGrid())); + connect( _grid, SIGNAL(xposchanged(int)), _hruler, SLOT(slotNewValue(int)) ); + connect( _grid, SIGNAL(yposchanged(int)), _vruler, SLOT(slotNewValue(int)) ); + connect(viewport, SIGNAL(contentsMoving(int, int)), SLOT(moving(int, int))); + + setSizes(); + QResizeEvent e(size(), size()); + resizeEvent(&e); +} + +void KGridView::paintGrid() +{ + _grid->update(viewRect()); +} + +void KGridView::setSizes() +{ + if(KIconEditProperties::self()->showRulers()) + { + _hruler->setLittleMarkDistance(_grid->scaling()); + _vruler->setLittleMarkDistance(_grid->scaling()); + + _hruler->setMediumMarkDistance(5); + _vruler->setMediumMarkDistance(5); + + _hruler->setBigMarkDistance(10); + _vruler->setBigMarkDistance(10); + + _hruler->setShowTinyMarks(true); + _hruler->setShowLittleMarks(false); + _hruler->setShowMediumMarks(true); + _hruler->setShowBigMarks(true); + _hruler->setShowEndMarks(true); + + _vruler->setShowTinyMarks(true); + _vruler->setShowLittleMarks(false); + _vruler->setShowMediumMarks(true); + _vruler->setShowBigMarks(true); + _vruler->setShowEndMarks(true); + + _hruler->setPixelPerMark(_grid->scaling()); + _vruler->setPixelPerMark(_grid->scaling()); + + _hruler->setMaxValue(_grid->width()+20); + _vruler->setMaxValue(_grid->height()+20); + + _hruler->show(); + _vruler->show(); + + _corner->show(); + //resize(_grid->width()+_vruler->width(), _grid->height()+_hruler->height()); + } + else + { + _hruler->hide(); + _vruler->hide(); + _corner->hide(); + //resize(_grid->size()); + } +} + +void KGridView::sizeChange(int, int) +{ + setSizes(); +} + +void KGridView::moving(int x, int y) +{ + _hruler->setOffset(abs(x)); + _vruler->setOffset(abs(y)); +} + +void KGridView::scalingChange(int) +{ + setSizes(); +} + +void KGridView::setShowRulers(bool mode) +{ + KIconEditProperties::self()->setShowRulers( mode ); + setSizes(); + QResizeEvent e(size(), size()); + resizeEvent(&e); +} + +void KGridView::setAcceptDrop(bool a) +{ + if(a == acceptdrop) return; + acceptdrop = a; + paintDropSite(); +} + +void KGridView::checkClipboard() +{ + _grid->checkClipboard(); +} + +const QRect KGridView::viewRect() +{ + int x, y, cx, cy; + if(viewport->horizontalScrollBar()->isVisible()) + { + x = viewport->contentsX(); + cx = viewport->viewport()->width(); + } + else + { + x = 0; + cx = viewport->contentsWidth(); + } + + if(viewport->verticalScrollBar()->isVisible()) + { + y = viewport->contentsY(); + cy = viewport->viewport()->height(); + } + else + { + y = 0; + cy = viewport->contentsHeight(); + } + + return QRect(x, y, cx, cy); +} + +void KGridView::paintDropSite() +{ + QPainter p; + p.begin( _grid ); + p.setRasterOp (NotROP); + p.drawRect(viewRect()); + p.end(); +} + +void KGridView::paintEvent(QPaintEvent *) +{ + if(acceptdrop) + paintDropSite(); +} + + +void KGridView::resizeEvent(QResizeEvent*) +{ + kdDebug(4640) << "KGridView::resizeEvent" << endl; + + setSizes(); + + if(KIconEditProperties::self()->showRulers()) + { + _hruler->setGeometry(_vruler->width(), 0, width(), _hruler->height()); + _vruler->setGeometry(0, _hruler->height(), _vruler->width(), height()); + + _corner->setGeometry(0, 0, _vruler->width(), _hruler->height()); + viewport->setGeometry(_corner->width(), _corner->height(), + width()-_corner->width(), height()-_corner->height()); + } + else + viewport->setGeometry(0, 0, width(), height()); +} + + +KIconEditGrid::KIconEditGrid(QImage *image, KCommandHistory* h, QWidget *parent, const char *name) + : KColorGrid(parent, name, 1) +{ + img = image; + history = h; + selected = 0; + m_command = 0; + + // the 42 normal kde colors - there can be an additional + // 18 custom colors in the custom colors palette + for(uint i = 0; i < 42; i++) + iconcolors.append(iconpalette[i]); + + setupImageHandlers(); + btndown = isselecting = ispasting = modified = false; + + img->create(32, 32, 32); + img->setAlphaBuffer(true); + clearImage(img); + + currentcolor = qRgb(0,0,0)|OPAQUE_MASK; + emit colorSelected(currentcolor); + + setMouseTracking(true); + + setNumRows(32); + setNumCols(32); + fill(TRANSPARENT); + + connect( kapp->clipboard(), SIGNAL(dataChanged()), SLOT(checkClipboard())); + connect( h, SIGNAL(commandExecuted()), this, SLOT(updatePreviewPixmap() )); + createCursors(); + + KIconEditProperties *props = KIconEditProperties::self(); + + setTransparencyDisplayType(props->transparencyDisplayType()); + setTransparencySolidColor(props->transparencySolidColor()); + setCheckerboardColor1(props->checkerboardColor1()); + setCheckerboardColor2(props->checkerboardColor2()); + setCheckerboardSize(props->checkerboardSize()); +} + +KIconEditGrid::~KIconEditGrid() +{ + kdDebug(4640) << "KIconEditGrid - destructor: done" << endl; +} + +void KIconEditGrid::paintEvent(QPaintEvent *e) +{ + const QRect cellsRect(0, 0, numCols() * cellSize(), numRows() * cellSize()); + const QRect paintCellsRect = cellsRect.intersect(e->rect()); + + if(!paintCellsRect.isEmpty()) + { + //QTime time; + + //time.start(); + + QRgb *imageBuffer = new QRgb[paintCellsRect.width() * paintCellsRect.height()]; + const int cellsize = cellSize(); + const int firstCellPixelsRemaining = cellsize - paintCellsRect.left() % cellsize; + + if(transparencyDisplayType() == TRD_SOLIDCOLOR) + { + const QRgb backgroundColor = transparencySolidColor().rgb(); + const int backgroundRed = transparencySolidColor().red(); + const int backgroundGreen = transparencySolidColor().green(); + const int backgroundBlue = transparencySolidColor().blue(); + const int firstCellX = paintCellsRect.left() / cellsize; + + for(int y = paintCellsRect.top(); y <= paintCellsRect.bottom(); y++) + { + QRgb *dest = imageBuffer + (y - paintCellsRect.top()) * paintCellsRect.width(); + + if(y % cellsize == 0 || dest == imageBuffer) + { + // Paint the first scanline in each block of cellSize() identical lines. + // The remaineder can just be copied from this one. + const int cellY = y / cellsize; + QRgb *src = gridcolors.data() + cellY * numCols() + firstCellX; + + QRgb sourcePixel = *src++; + int sourceAlpha = qAlpha(sourcePixel); + + QRgb c; + + if(sourceAlpha == 255) + { + c = sourcePixel; + } + else + if(sourceAlpha == 0) + { + c = backgroundColor; + } + else + { + const int sourceRed = qRed(sourcePixel); + const int sourceGreen = qGreen(sourcePixel); + const int sourceBlue = qBlue(sourcePixel); + + int r = (sourceAlpha * (sourceRed - backgroundRed)) + 0x80; + r = backgroundRed + ((r + (r >> 8)) >> 8); + + int g = (sourceAlpha * (sourceGreen - backgroundGreen)) + 0x80; + g = backgroundGreen + ((g + (g >> 8)) >> 8); + + int b = (sourceAlpha * (sourceBlue - backgroundBlue)) + 0x80; + b = backgroundBlue + ((b + (b >> 8)) >> 8); + + c = qRgb(r, g, b); + } + + int cellPixelsRemaining = firstCellPixelsRemaining; + + for(int x = paintCellsRect.left(); x <= paintCellsRect.right(); x++) + { + if(cellPixelsRemaining == 0) + { + cellPixelsRemaining = cellsize; + + // Fetch the next source pixel + sourcePixel = *src++; + sourceAlpha = qAlpha(sourcePixel); + + if(sourceAlpha == 255) + { + c = sourcePixel; + } + else + if(sourceAlpha == 0) + { + c = backgroundColor; + } + else + { + const int sourceRed = qRed(sourcePixel); + const int sourceGreen = qGreen(sourcePixel); + const int sourceBlue = qBlue(sourcePixel); + + //int r = backgroundRed + (sourceAlpha * (sourceRed - backgroundRed)) / 255; + //int g = backgroundGreen + (sourceAlpha * (sourceGreen - backgroundGreen)) / 255; + //int b = backgroundBlue + (sourceAlpha * (sourceBlue - backgroundBlue)) / 255; + + int r = (sourceAlpha * (sourceRed - backgroundRed)) + 0x80; + r = backgroundRed + ((r + (r >> 8)) >> 8); + + int g = (sourceAlpha * (sourceGreen - backgroundGreen)) + 0x80; + g = backgroundGreen + ((g + (g >> 8)) >> 8); + + int b = (sourceAlpha * (sourceBlue - backgroundBlue)) + 0x80; + b = backgroundBlue + ((b + (b >> 8)) >> 8); + + c = qRgb(r, g, b); + } + } + + cellPixelsRemaining--; + + *dest++ = c; + } + } + else + { + // Copy the scanline above. + memcpy(dest, dest - paintCellsRect.width(), paintCellsRect.width() * sizeof(QRgb)); + } + } + } + else + { + int squareSize; + const int fixedPointMultiplier = 4; + + if(checkerboardSize() == CHK_SMALL) + { + squareSize = (cellSize() * fixedPointMultiplier) / 4; + } + else + if(checkerboardSize() == CHK_MEDIUM) + { + squareSize = (cellSize() * fixedPointMultiplier) / 2; + } + else + { + squareSize = (2 * cellSize() * fixedPointMultiplier) / 2; + } + + QRgb *color1ScanLine = new QRgb[paintCellsRect.width()]; + QRgb *color2ScanLine = new QRgb[paintCellsRect.width()]; + QRgb *color1Buffer = color1ScanLine; + QRgb *color2Buffer = color2ScanLine; + + for(int x = paintCellsRect.left(); x <= paintCellsRect.right(); x++) + { + if((((x * fixedPointMultiplier) / squareSize) & 1) == 0) + { + *color1Buffer++ = checkerboardColor1().rgb(); + *color2Buffer++ = checkerboardColor2().rgb(); + } + else + { + *color1Buffer++ = checkerboardColor2().rgb(); + *color2Buffer++ = checkerboardColor1().rgb(); + } + } + + const int firstCellX = paintCellsRect.left() / cellsize; + const int firstCellPixelsRemaining = cellsize - paintCellsRect.left() % cellsize; + int lastCellY = -1; + int lastLineFirstSquareColour = 0; + + for(int y = paintCellsRect.top(); y <= paintCellsRect.bottom(); y++) + { + QRgb *dest = imageBuffer + (y - paintCellsRect.top()) * paintCellsRect.width(); + const int cellY = y / cellsize; + + int firstSquareColour; + const QRgb *checkerboardSrc; + + if((((y * fixedPointMultiplier) / squareSize) & 1) == 0) + { + firstSquareColour = 1; + checkerboardSrc = color1ScanLine; + } + else + { + firstSquareColour = 2; + checkerboardSrc = color2ScanLine; + } + + if(cellY == lastCellY && firstSquareColour == lastLineFirstSquareColour) + { + // Copy the scanline above. + memcpy(dest, dest - paintCellsRect.width(), paintCellsRect.width() * sizeof(QRgb)); + } + else + { + QRgb *src = gridcolors.data() + cellY * numCols() + firstCellX; + + QRgb sourcePixel = *src++; + int sourceRed = qRed(sourcePixel); + int sourceGreen = qGreen(sourcePixel); + int sourceBlue = qBlue(sourcePixel); + int sourceAlpha = qAlpha(sourcePixel); + + int cellPixelsRemaining = firstCellPixelsRemaining; + + for(int x = paintCellsRect.left(); x <= paintCellsRect.right(); x++) + { + if(cellPixelsRemaining == 0) + { + cellPixelsRemaining = cellsize; + + // Fetch the next source pixel + sourcePixel = *src++; + sourceRed = qRed(sourcePixel); + sourceGreen = qGreen(sourcePixel); + sourceBlue = qBlue(sourcePixel); + sourceAlpha = qAlpha(sourcePixel); + } + + cellPixelsRemaining--; + + QRgb c; + + if(sourceAlpha == 255) + { + c = sourcePixel; + } + else + if(sourceAlpha == 0) + { + c = *checkerboardSrc; + } + else + { + const int backgroundColor = *checkerboardSrc; + const int backgroundRed = qRed(backgroundColor); + const int backgroundGreen = qGreen(backgroundColor); + const int backgroundBlue = qBlue(backgroundColor); + + //int r = backgroundRed + (sourceAlpha * (sourceRed - backgroundRed)) / 255; + //int g = backgroundGreen + (sourceAlpha * (sourceGreen - backgroundGreen)) / 255; + //int b = backgroundBlue + (sourceAlpha * (sourceBlue - backgroundBlue)) / 255; + + int r = (sourceAlpha * (sourceRed - backgroundRed)) + 0x80; + r = backgroundRed + ((r + (r >> 8)) >> 8); + + int g = (sourceAlpha * (sourceGreen - backgroundGreen)) + 0x80; + g = backgroundGreen + ((g + (g >> 8)) >> 8); + + int b = (sourceAlpha * (sourceBlue - backgroundBlue)) + 0x80; + b = backgroundBlue + ((b + (b >> 8)) >> 8); + + c = qRgb(r, g, b); + } + + *dest++ = c; + checkerboardSrc++; + } + } + + lastCellY = cellY; + lastLineFirstSquareColour = firstSquareColour; + } + + delete [] color1ScanLine; + delete [] color2ScanLine; + } + + QImage image((uchar *)(imageBuffer), paintCellsRect.width(), paintCellsRect.height(), 32, 0, 0, +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + QImage::LittleEndian); +#else + QImage::BigEndian); +#endif + Q_ASSERT(!image.isNull()); + + QPixmap _pixmap; + _pixmap.convertFromImage(image); + + QPainter p; + p.begin(&_pixmap); + paintForeground(&p, e); + p.end(); + + bitBlt(this, paintCellsRect.left(), paintCellsRect.top(), &_pixmap); + + //kdDebug(4640) << "Image render elapsed: " << time.elapsed() << endl; + + delete [] imageBuffer; + } +} + +void KIconEditGrid::paintForeground(QPainter* p, QPaintEvent* e) +{ + QWMatrix matrix; + + matrix.translate(-e->rect().x(), -e->rect().y()); + p->setWorldMatrix( matrix ); + + QRect cellsRect(0, 0, numCols() * cellSize(), numRows() * cellSize()); + QRect paintCellsRect = cellsRect.intersect(e->rect()); + + if(!paintCellsRect.isEmpty()) + { + int firstColumn = paintCellsRect.left() / cellSize(); + int lastColumn = paintCellsRect.right() / cellSize(); + + int firstRow = paintCellsRect.top() / cellSize(); + int lastRow = paintCellsRect.bottom() / cellSize(); + + p->setPen(QColor(0, 0, 0)); + p->setBrush(QColor(0, 0, 0)); + + for(int column = firstColumn; column <= lastColumn; column++) + { + for(int row = firstRow; row <= lastRow; row++) + { + int x = column * cellSize(); + int y = row * cellSize(); + + if((ispasting || isselecting) && isMarked(column, row)) + { + p->drawWinFocusRect(x + 1, y + 1, cellSize() - 2, cellSize() - 2); + } + else + { + switch( tool ) + { + case FilledRect: + case Rect: + case Ellipse: + case Circle: + case FilledEllipse: + case FilledCircle: + case Line: + if(btndown && isMarked(column, row)) + { + if(cellSize() > 1) + { + p->drawWinFocusRect( x + 1, y + 1, cellSize() - 2, cellSize() - 2); + } + else + { + p->drawPoint(x, y); + } + } + break; + + default: + break; + } + } + } + } + } + + if(hasGrid()&& !(cellSize()==1)) + { + p->setPen(QColor(0, 0, 0)); + int x = e->rect().x() - ((e->rect().x() % cellSize()) + cellSize()); + if(x < 0) x = 0; + int y = e->rect().y() - ((e->rect().y() % cellSize()) + cellSize()); + if(y < 0) y = 0; + int cx = e->rect().right() + cellSize(); + int cy = e->rect().bottom() + cellSize(); + + // draw grid lines + for(int i = x; i < cx; i += cellSize()) + p->drawLine(i, y, i, cy); + + for(int i = y; i < cy; i += cellSize()) + p->drawLine(x, i, cx, i); + } +} + +void KIconEditGrid::mousePressEvent( QMouseEvent *e ) +{ + if(!e || (e->button() != LeftButton)) + return; + + int row = findRow( e->pos().y() ); + int col = findCol( e->pos().x() ); + //int cell = row * numCols() + col; + + if(!img->valid(col, row)) + return; + + btndown = true; + start.setX(col); + start.setY(row); + + if(ispasting) + { + ispasting = false; + editPaste(true); + } + + if(isselecting) + { + QPointArray a(pntarray.copy()); + pntarray.resize(0); + drawPointArray(a, Mark); + emit selecteddata(false); + } + + switch( tool ) + { + case SelectRect: + case SelectCircle: + isselecting = true; + break; + default: + break; + } +} + +void KIconEditGrid::mouseMoveEvent( QMouseEvent *e ) +{ + if(!e) return; + + int row = findRow( e->pos().y() ); + int col = findCol( e->pos().x() ); + int cell = row * numCols() + col; + + if(img->valid(col, row)) + { + //kdDebug(4640) << col << " X " << row << endl; + emit poschanged(col, row); + // for the rulers + emit xposchanged((col*scaling())+scaling()/2); + emit yposchanged((row*scaling())+scaling()/2); + } + + QPoint tmpp(col, row); + if(tmpp == end) return; + + // need to use intersection of rectangles to allow pasting + // only that part of clip image which intersects -jwc- + if(ispasting && !btndown && img->valid(col, row)) + { + if( (col + cbsize.width()) > (numCols()-1) ) + insrect.setX(numCols()-insrect.width()); + else + insrect.setX(col); + if( (row + cbsize.height()) > (numRows()-1) ) + insrect.setY(numRows()-insrect.height()); + else + insrect.setY(row); + + insrect.setSize(cbsize); + start = insrect.topLeft(); + end = insrect.bottomRight(); + drawRect(false); + return; + } + + if(!img->valid(col, row) || !btndown) + return; + + end.setX(col); + end.setY(row); + + if(isselecting) + { + if(tool == SelectRect) + drawRect(false); + else + drawEllipse(false); + return; + } + + bool erase=false; + switch( tool ) + { + case Eraser: + erase=true; + + case Freehand: + { + if( !m_command ) + m_command = new KMacroCommand( i18n("Free Hand") ); + + if(erase) + setColor( cell, TRANSPARENT ); + else + setColor( cell, currentcolor ); + + if ( selected != cell ) + { + setModified( true ); + int prevSel = selected; + selected = cell; + QRect area = QRect( col*cellsize,row*cellsize, cellsize, cellsize ).unite( + QRect ( (prevSel%numCols())*cellsize,(prevSel/numCols())*cellsize, cellsize, cellsize ) ); + + m_command->addCommand( new RepaintCommand( area, this ) ); + DrawCommand* dc = new DrawCommand( col, row, colorAt(cell), img, this ); + RepaintCommand* rp = new RepaintCommand( area, this ); + dc->execute(); + rp->execute(); + m_command->addCommand( dc ); + m_command->addCommand( rp ); + } + break; + } + case Find: + { + iconcolors.closestMatch(colorAt(cell)); + if ( selected != cell ) + { + int prevSel = selected; + selected = cell; + update((prevSel%numCols())*cellsize,(prevSel/numCols())*cellsize, cellsize, cellsize); + update(col*cellsize,row*cellsize, cellsize, cellsize); + emit colorSelected(colorAt(selected)); + } + break; + } + case Ellipse: + case Circle: + case FilledEllipse: + case FilledCircle: + { + drawEllipse(false); + break; + } + case FilledRect: + case Rect: + { + drawRect(false); + break; + } + case Line: + { + drawLine(false, false); + break; + } + case Spray: + { + drawSpray(QPoint(col, row)); + setModified(true); + break; + } + default: + break; + } + + p = *img; + emit changed(QPixmap(p)); +} + +void KIconEditGrid::mouseReleaseEvent( QMouseEvent *e ) +{ + if(!e || (e->button() != LeftButton)) + return; + + int row = findRow( e->pos().y() ); + int col = findCol( e->pos().x() ); + btndown = false; + end.setX(col); + end.setY(row); + int cell = row * numCols() + col; + bool erase=false; + switch( tool ) + { + case Eraser: + erase=true; + //currentcolor = TRANSPARENT; + case Freehand: + { + if(!img->valid(col, row)) + return; + if(erase) + setColor( cell, TRANSPARENT ); + else + setColor( cell, currentcolor ); + //if ( selected != cell ) + //{ + setModified( true ); + int prevSel = selected; + selected = cell; + update((prevSel%numCols())*cellsize,(prevSel/numCols())*cellsize, cellsize, cellsize); + update(col*cellsize,row*cellsize, cellsize, cellsize); + //updateCell( prevSel/numCols(), prevSel%numCols(), FALSE ); + //updateCell( row, col, FALSE ); + *((uint*)img->scanLine(row) + col) = colorAt(cell); + p = *img; + //} + + if( m_command ) { + history->addCommand( m_command, false ); + m_command = 0; + } + + break; + } + case Ellipse: + case Circle: + case FilledEllipse: + case FilledCircle: + { + drawEllipse(true); + break; + } + case FilledRect: + case Rect: + { + drawRect(true); + break; + } + case Line: + { + drawLine(true, false); + break; + } + case Spray: + { + drawSpray(QPoint(col, row)); + break; + } + case FloodFill: + { + QApplication::setOverrideCursor(waitCursor); + drawFlood(col, row, colorAt(cell)); + QApplication::restoreOverrideCursor(); + updateColors(); + emit needPainting(); + p = *img; + break; + } + case Find: + { + currentcolor = colorAt(cell); + if ( selected != cell ) + { + int prevSel = selected; + selected = cell; + update((prevSel%numCols())*cellsize,(prevSel/numCols())*cellsize, cellsize, cellsize); + update(col*cellsize,row*cellsize, cellsize, cellsize); + emit colorSelected(currentcolor); + //updateCell( prevSel/numCols(), prevSel%numCols(), FALSE ); + //updateCell( row, col, FALSE ); + } + + break; + } + default: + break; + } + + emit changed(QPixmap(p)); + //emit colorschanged(numColors(), data()); +} + +//void KIconEditGrid::setColorSelection( const QColor &color ) +void KIconEditGrid::setColorSelection( uint c ) +{ + currentcolor = c; + emit colorSelected(currentcolor); +} + +void KIconEditGrid::loadBlank( int w, int h ) +{ + img->create(w, h, 32); + img->setAlphaBuffer(true); + clearImage(img); + setNumRows(h); + setNumCols(w); + fill(TRANSPARENT); + emit sizechanged(numCols(), numRows()); + emit colorschanged(numColors(), data()); + history->clear(); +} + + + +void KIconEditGrid::load( QImage *image) +{ + kdDebug(4640) << "KIconEditGrid::load" << endl; + + setUpdatesEnabled(false); + + if(image == 0L) + { + QString msg = i18n("There was an error loading a blank image.\n"); + KMessageBox::error(this, msg); + return; + } + + *img = image->convertDepth(32); + img->setAlphaBuffer(true); + setNumRows(img->height()); + setNumCols(img->width()); + + for(int y = 0; y < numRows(); y++) + { + uint *l = (uint*)img->scanLine(y); + for(int x = 0; x < numCols(); x++, l++) + { + setColor((y*numCols())+x, *l, false); + } + //kdDebug(4640) << "Row: " << y << endl; + kapp->processEvents(200); + } + + updateColors(); + emit sizechanged(numCols(), numRows()); + emit colorschanged(numColors(), data()); + emit changed(pixmap()); + setUpdatesEnabled(true); + emit needPainting(); + //repaint(viewRect(), false); + history->clear(); +} + +const QPixmap &KIconEditGrid::pixmap() +{ + if(!img->isNull()) + p = *img; + //p.convertFromImage(*img, 0); + return(p); +} + +void KIconEditGrid::getImage(QImage *image) +{ + kdDebug(4640) << "KIconEditGrid::getImage" << endl; + *image = *img; +} + +bool KIconEditGrid::zoomTo(int scale) +{ + QApplication::setOverrideCursor(waitCursor); + setUpdatesEnabled(false); + setCellSize( scale ); + setUpdatesEnabled(true); + emit needPainting(); + QApplication::restoreOverrideCursor(); + emit scalingchanged(cellSize()); + + if(scale == 1) + return false; + return true; +} + +bool KIconEditGrid::zoom(Direction d) +{ + int f = (d == DirIn) ? (cellSize()+1) : (cellSize()-1); + QApplication::setOverrideCursor(waitCursor); + setUpdatesEnabled(false); + setCellSize( f ); + setUpdatesEnabled(true); + //emit needPainting(); + QApplication::restoreOverrideCursor(); + + emit scalingchanged(cellSize()); + if(d == DirOut && cellSize() <= 1) + return false; + return true; +} + +void KIconEditGrid::checkClipboard() +{ + bool ok = false; + QImage tmp = clipboardImage(ok); + if(ok) + emit clipboarddata(true); + else + { + emit clipboarddata(false); + } +} + +QImage KIconEditGrid::clipboardImage(bool &ok) +{ + //###### Remove me later. + //Workaround Qt bug -- check whether format provided first. + //Code below is from QDragObject, to match the mimetype list.... + + QStrList fileFormats = QImageIO::inputFormats(); + fileFormats.first(); + bool oneIsSupported = false; + while ( fileFormats.current() ) + { + QCString format = fileFormats.current(); + QCString type = "image/" + format.lower(); + if (kapp->clipboard()->data()->provides(type ) ) + { + oneIsSupported = true; + } + fileFormats.next(); + } + if (!oneIsSupported) + { + ok = false; + return QImage(); + } + + QImage image = kapp->clipboard()->image(); + ok = !image.isNull(); + if ( ok ) + { + image = image.convertDepth(32); + image.setAlphaBuffer(true); + } + return image; +} + + +void KIconEditGrid::editSelectAll() +{ + start.setX(0); + start.setY(0); + end.setX(numCols()-1); + end.setY(numRows()-1); + isselecting = true; + drawRect(false); + emit newmessage(i18n("All selected")); +} + +void KIconEditGrid::editClear() +{ + clearImage(img); + fill(TRANSPARENT); + update(); + setModified(true); + p = *img; + emit changed(p); + emit newmessage(i18n("Cleared")); +} + +QImage KIconEditGrid::getSelection(bool cut) +{ + const QRect rect = pntarray.boundingRect(); + int nx = 0, ny = 0, nw = 0, nh = 0; + rect.rect(&nx, &ny, &nw, &nh); + + QImage tmp(nw, nh, 32); + tmp.setAlphaBuffer(true); + clearImage(&tmp); + + int s = pntarray.size(); + + for(int i = 0; i < s; i++) + { + int x = pntarray[i].x(); + int y = pntarray[i].y(); + if(img->valid(x, y) && rect.contains(QPoint(x, y))) + { + *((uint*)tmp.scanLine(y-ny) + (x-nx)) = *((uint*)img->scanLine(y) + x); + if(cut) + { + *((uint*)img->scanLine(y) + x) = TRANSPARENT; + setColor( (y*numCols()) + x, TRANSPARENT, false ); + } + } + } + + QPointArray a(pntarray.copy()); + pntarray.resize(0); + drawPointArray(a, Mark); + emit selecteddata(false); + if(cut) + { + updateColors(); + update(rect.x()*cellSize(), rect.y()*cellSize(), + rect.width()*cellSize(), rect.height()*cellSize()); + p = *img; + emit changed(p); + emit colorschanged(numColors(), data()); + emit newmessage(i18n("Selected area cut")); + setModified(true); + } + else + emit newmessage(i18n("Selected area copied")); + + return tmp; +} + +void KIconEditGrid::editCopy(bool cut) +{ + kapp->clipboard()->setImage(getSelection(cut)); + isselecting = false; +} + + +void KIconEditGrid::editPaste(bool paste) +{ + bool ok = false; + QImage tmp = clipboardImage(ok); + + KIconEditProperties *props = KIconEditProperties::self(); + + if(ok) + { + if( (tmp.size().width() > img->size().width()) + || (tmp.size().height() > img->size().height()) ) + { + if(KMessageBox::warningYesNo(this, + i18n("The clipboard image is larger than the current" + " image!\nPaste as new image?"),QString::null,i18n("Paste"), i18n("Do Not Paste")) == 0) + { + editPasteAsNew(); + } + return; + } + else if(!paste) + { + ispasting = true; + cbsize = tmp.size(); + return; + // emit newmessage(i18n("Pasting")); + } + else + { + //kdDebug(4640) << "KIconEditGrid: Pasting at: " << insrect.x() << " x " << insrect.y() << endl; + QApplication::setOverrideCursor(waitCursor); + + for(int y = insrect.y(), ny = 0; y < numRows() && ny < insrect.height(); y++, ny++) + { + uint *l = ((uint*)img->scanLine(y)+insrect.x()); + uint *cl = (uint*)tmp.scanLine(ny); + for(int x = insrect.x(), nx = 0; x < numCols() && nx < insrect.width(); x++, nx++, l++, cl++) + { + if(props->pasteTransparent()) + { + *l = *cl; + } + else + { + // Porter-Duff Over composition + double alphaS = qAlpha(*cl) / 255.0; + double alphaD = qAlpha(*l) / 255.0; + + double r = qRed(*cl) * alphaS + (1 - alphaS) * qRed(*l) * alphaD; + double g = qGreen(*cl) * alphaS + (1 - alphaS) * qGreen(*l) * alphaD; + double b = qBlue(*cl) * alphaS + (1 - alphaS) * qBlue(*l) * alphaD; + double a = alphaS + (1 - alphaS) * alphaD; + + // Remove multiplication by alpha + + if(a > 0) + { + r /= a; + g /= a; + b /= a; + } + else + { + r = 0; + g = 0; + b = 0; + } + + int ir = (int)(r + 0.5); + + if(ir < 0) + { + ir = 0; + } + else + if(ir > 255) + { + ir = 255; + } + + int ig = (int)(g + 0.5); + + if(ig < 0) + { + ig = 0; + } + else + if(ig > 255) + { + ig = 255; + } + + int ib = (int)(b + 0.5); + + if(ib < 0) + { + ib = 0; + } + else + if(ib > 255) + { + ib = 255; + } + + int ia = (int)((a * 255) + 0.5); + + if(ia < 0) + { + ia = 0; + } + else + if(ia > 255) + { + ia = 255; + } + + *l = qRgba(ir, ig, ib, ia); + } + + setColor((y*numCols())+x, (uint)*l, false); + } + } + updateColors(); + update(insrect.x()*cellSize(), insrect.y()*cellSize(), + insrect.width()*cellSize(), insrect.height()*cellSize()); + + QApplication::restoreOverrideCursor(); + + setModified(true); + p = *img; + emit changed(QPixmap(p)); + emit sizechanged(numCols(), numRows()); + emit colorschanged(numColors(), data()); + emit newmessage(i18n("Done pasting")); + } + } + else + { + QString msg = i18n("Invalid pixmap data in clipboard!\n"); + KMessageBox::sorry(this, msg); + } +} + + +void KIconEditGrid::editPasteAsNew() +{ + bool ok = false; + QImage tmp = clipboardImage(ok); + + if(ok) + { + if(isModified()) + { + KIconEdit *w = new KIconEdit(tmp); + Q_CHECK_PTR(w); + } + else + { + *img = tmp; + load(img); + setModified(true); + //repaint(viewRect(), false); + + p = *img; + emit changed(QPixmap(p)); + emit sizechanged(numCols(), numRows()); + emit colorschanged(numColors(), data()); + emit newmessage(i18n("Done pasting")); + history->clear(); + } + } + else + { + QString msg = i18n("Invalid pixmap data in clipboard!\n"); + KMessageBox::error(this, msg); + } +} + + +void KIconEditGrid::editResize() +{ + kdDebug(4640) << "KIconGrid::editResize" << endl; + KResizeDialog *rs = new KResizeDialog(this, 0, QSize(numCols(), numRows())); + if(rs->exec()) + { + const QSize s = rs->getSize(); + *img = img->smoothScale(s.width(), s.height()); + load(img); + + setModified(true); + } + delete rs; +} + + +void KIconEditGrid::setSize(const QSize s) +{ + kdDebug(4640) << "::setSize: " << s.width() << " x " << s.height() << endl; + + img->create(s.width(), s.height(), 32); + img->setAlphaBuffer(true); + clearImage(img); + load(img); +} + + +void KIconEditGrid::createCursors() +{ + QBitmap mask(22, 22); + QPixmap pix; + + cursor_normal = QCursor(arrowCursor); + + pix = BarIcon("colorpicker-cursor"); + if(pix.isNull()) + { + cursor_colorpicker = cursor_normal; + kdDebug(4640) << "KIconEditGrid: Error loading colorpicker-cursor.xpm" << endl; + } + else + { + mask = pix.createHeuristicMask(); + pix.setMask(mask); + cursor_colorpicker = QCursor(pix, 1, 21); + } + + pix = BarIcon("paintbrush-cursor"); + if(pix.isNull()) + { + cursor_paint = cursor_normal; + kdDebug(4640) << "KIconEditGrid: Error loading paintbrush.xpm" << endl; + } + else + { + mask = pix.createHeuristicMask(); + pix.setMask(mask); + cursor_paint = QCursor(pix, 0, 19); + } + + pix = BarIcon("fill-cursor"); + if(pix.isNull()) + { + cursor_flood = cursor_normal; + kdDebug(4640) << "KIconEditGrid: Error loading fill-cursor.xpm" << endl; + } + else + { + mask = pix.createHeuristicMask(); + pix.setMask(mask); + cursor_flood = QCursor(pix, 3, 20); + } + + pix = BarIcon("aim-cursor"); + if(pix.isNull()) + { + cursor_aim = cursor_normal; + kdDebug(4640) << "KIconEditGrid: Error loading aim-cursor.xpm" << endl; + } + else + { + mask = pix.createHeuristicMask(); + pix.setMask(mask); + cursor_aim = QCursor(pix, 10, 10); + } + + pix = BarIcon("airbrush-cursor"); + if(pix.isNull()) + { + cursor_spray = cursor_normal; + kdDebug(4640) << "KIconEditGrid: Error loading airbrush-cursor.xpm" << endl; + } + else + { + mask = pix.createHeuristicMask(true); + pix.setMask(mask); + cursor_spray = QCursor(pix, 0, 20); + } + + pix = BarIcon("eraser-cursor"); + if(pix.isNull()) + { + cursor_erase = cursor_normal; + kdDebug(4640) << "KIconEditGrid: Error loading eraser-cursor.xpm" << endl; + } + else + { + mask = pix.createHeuristicMask(true); + pix.setMask(mask); + cursor_erase = QCursor(pix, 1, 16); + } +} + + + +void KIconEditGrid::setTool(DrawTool t) +{ + btndown = false; + tool = t; + + if(tool != SelectRect && tool != SelectCircle) + isselecting = false; + + switch( tool ) + { + case SelectRect: + isselecting = true; + setCursor(cursor_aim); + break; + case SelectCircle: + isselecting = true; + setCursor(cursor_aim); + break; + case Line: + case Ellipse: + case Circle: + case FilledEllipse: + case FilledCircle: + case FilledRect: + case Rect: + setCursor(cursor_aim); + break; + case Freehand: + setCursor(cursor_paint); + break; + case Spray: + setCursor(cursor_spray); + break; + case Eraser: + setCursor(cursor_erase); + break; + case FloodFill: + setCursor(cursor_flood); + break; + case Find: + setCursor(cursor_colorpicker); + break; + default: + break; + } +} + + +void KIconEditGrid::drawFlood(int x, int y, uint oldcolor) +{ + if((!img->valid(x, y)) + || (colorAt((y * numCols())+x) != oldcolor) + || (colorAt((y * numCols())+x) == currentcolor)) + return; + + *((uint*)img->scanLine(y) + x) = currentcolor; + setColor((y*numCols())+x, currentcolor, false); + + setModified(true); + + drawFlood(x, y-1, oldcolor); + drawFlood(x, y+1, oldcolor); + drawFlood(x-1, y, oldcolor); + drawFlood(x+1, y, oldcolor); + //TODO: add undo +} + + +void KIconEditGrid::drawSpray(QPoint point) +{ + int x = (point.x()-5); + int y = (point.y()-5); + + //kdDebug(4640) << "drawSpray() - " << x << " X " << y << endl; + + pntarray.resize(0); + int points = 0; + for(int i = 1; i < 4; i++, points++) + { + int dx = (rand() % 10); + int dy = (rand() % 10); + pntarray.putPoints(points, 1, x+dx, y+dy); + } + + drawPointArray(pntarray, Draw); +} + + +//This routine is from Qt sources -- it's the branch of QPointArray::makeEllipse( int x, int y, int w, int h ) that's not normally compiled +//It seems like KIconEdit relied on the Qt1 semantics for makeEllipse, which broke +//the tool with reasonably recent Qt versions. +//Thankfully, Qt includes the old code #ifdef'd, which is hence included here +static void QPA_makeEllipse(QPointArray& ar, int x, int y, int w, int h ) +{ // midpoint, 1/4 ellipse + if ( w <= 0 || h <= 0 ) { + if ( w == 0 || h == 0 ) { + ar.resize( 0 ); + return; + } + if ( w < 0 ) { // negative width + w = -w; + x -= w; + } + if ( h < 0 ) { // negative height + h = -h; + y -= h; + } + } + int s = (w+h+2)/2; // max size of xx,yy array + int *px = new int[s]; // 1/4th of ellipse + int *py = new int[s]; + int xx, yy, i=0; + double d1, d2; + double a2=(w/2)*(w/2), b2=(h/2)*(h/2); + xx = 0; + yy = int(h/2); + d1 = b2 - a2*(h/2) + 0.25*a2; + px[i] = xx; + py[i] = yy; + i++; + while ( a2*(yy-0.5) > b2*(xx+0.5) ) { // region 1 + if ( d1 < 0 ) { + d1 = d1 + b2*(3.0+2*xx); + xx++; + } else { + d1 = d1 + b2*(3.0+2*xx) + 2.0*a2*(1-yy); + xx++; + yy--; + } + px[i] = xx; + py[i] = yy; + i++; + } + d2 = b2*(xx+0.5)*(xx+0.5) + a2*(yy-1)*(yy-1) - a2*b2; + while ( yy > 0 ) { // region 2 + if ( d2 < 0 ) { + d2 = d2 + 2.0*b2*(xx+1) + a2*(3-2*yy); + xx++; + yy--; + } else { + d2 = d2 + a2*(3-2*yy); + yy--; + } + px[i] = xx; + py[i] = yy; + i++; + } + s = i; + ar.resize( 4*s ); // make full point array + x += w/2; + y += h/2; + for ( i=0; i end.x()) + { + cx = x - end.x(); + x = x - cx; + } + else + cx = end.x() - x; + if(y > end.y()) + { + cy = y - end.y(); + y = y - cy; + } + else + cy = end.y() - y; + + int d = (cx > cy) ? cx : cy; + + //kdDebug(4640) << x << ", " << y << " - " << d << " " << d << endl; + pntarray.resize(0); + drawPointArray(a, Mark); + + if(tool == Circle || tool == FilledCircle || tool == SelectCircle) + QPA_makeEllipse(pntarray, x, y, d, d); + else if(tool == Ellipse || tool == FilledEllipse) + QPA_makeEllipse(pntarray, x, y, cx, cy); + + if((tool == FilledEllipse) || (tool == FilledCircle) + || (tool == SelectCircle)) + { + int s = pntarray.size(); + int points = s; + for(int i = 0; i < s; i++) + { + int x = pntarray[i].x(); + int y = pntarray[i].y(); + for(int j = 0; j < s; j++) + { + if((pntarray[j].y() == y) && (pntarray[j].x() > x)) + { + for(int k = x; k < pntarray[j].x(); k++, points++) + pntarray.putPoints(points, 1, k, y); + break; + } + } + } + } + + drawPointArray(pntarray, Mark); + + if(tool == SelectCircle && pntarray.size() > 0 && !ispasting) + emit selecteddata(true); +} + + +void KIconEditGrid::drawRect(bool drawit) +{ + if(drawit) + { + drawPointArray(pntarray, Draw); + p = *img; + emit changed(p); + return; + } + + QPointArray a(pntarray.copy()); + int x = start.x(), y = start.y(), cx, cy; + + if(x > end.x()) + { + cx = x - end.x(); + x = x - cx; + } + else + cx = end.x() - x; + if(y > end.y()) + { + cy = y - end.y(); + y = y - cy; + } + else + cy = end.y() - y; + + //kdDebug(4640) << x << ", " << y << " - " << cx << " " << cy << endl; + pntarray.resize(0); + drawPointArray(a, Mark); // remove previous marking + + int points = 0; + bool pasting = ispasting; + + if(tool == FilledRect || (tool == SelectRect)) + { + for(int i = x; i <= x + (pasting ? cx + 1 : cx); i++) + { + for(int j = y; j <= y+cy; j++, points++) + pntarray.putPoints(points, 1, i, j); + } + } + else + { + for(int i = x; i <= x+cx; i++, points++) + pntarray.putPoints(points, 1, i, y); + for(int i = y; i <= y+cy; i++, points++) + pntarray.putPoints(points, 1, x, i); + for(int i = x; i <= x+cx; i++, points++) + pntarray.putPoints(points, 1, i, y+cy); + for(int i = y; i <= y+cy; i++, points++) + pntarray.putPoints(points, 1, x+cx, i); + } + + drawPointArray(pntarray, Mark); + + if(tool == SelectRect && pntarray.size() > 0 && !ispasting) + emit selecteddata(true); +} + + +void KIconEditGrid::drawLine(bool drawit, bool drawStraight) +{ + if(drawit) + { + drawPointArray(pntarray, Draw); + p = *img; + emit changed(p); + return; + } + + QPointArray a(pntarray.copy()); + pntarray.resize(0); + + // remove previous marking + drawPointArray(a, Mark); + + int x, y, dx, dy, delta; + + dx = end.x() - start.x(); + dy = end.y() - start.y(); + x = start.x(); + y = start.y(); + + delta = QMAX(abs(dx), abs(dy)); + int deltaX = abs(dx); + int deltaY = abs(dy); + + if ((drawStraight) && (delta > 0)) + { + dx /= delta; + dy /= delta; + + for(int i = 0; i <= delta; i++) + { + pntarray.putPoints(i, 1, x, y); + x += dx; + y += dy; + } + } + + else if ((delta > 0) && (deltaX >= deltaY)) + { + for(int i = 0; i <= deltaX; i++) + { + pntarray.putPoints(i, 1, x, y); + + if(dx > 0) + x++; + else + x--; + + if(dy >= 0) + y = start.y() + (abs(start.x() - x) * deltaY) / deltaX; + else + y = start.y() - (abs(start.x() - x) * deltaY) / deltaX; + } + } + + else if ((delta > 0) && (deltaY > deltaX)) + { + for(int i = 0; i <= deltaY; i++) + { + pntarray.putPoints(i, 1, x, y); + + if(dy > 0) + y++; + else + y--; + + if(dx >= 0) + x = start.x() + (abs(start.y() - y) * deltaX) / deltaY; + else + x = start.x() - (abs(start.y() - y) * deltaX) / deltaY; + } + } + + drawPointArray(pntarray, Mark); +} + + +void KIconEditGrid::drawPointArray(QPointArray a, DrawAction action) +{ + QRect area( a.boundingRect().x()*cellSize()-1, a.boundingRect().y()*cellSize()-1, + a.boundingRect().width()*cellSize()+1, a.boundingRect().height()*cellSize()+1 ); + + KMacroCommand* macro = 0; + bool doupdate = false; + + if( a.size() > 0 && action == Draw ) { + // might cause a memmory leak, if + // macro is never used and never + // added to the history! TODO: Fix this + macro = new KMacroCommand( i18n("Drawn Array") ); + RepaintCommand* rc = new RepaintCommand( area, this ); + macro->addCommand( rc ); + } + + int s = a.size(); //((rect.size().width()) * (rect.size().height())); + for(int i = 0; i < s; i++) + { + int x = a[i].x(); + int y = a[i].y(); + + if(img->valid(x, y) && a.boundingRect().contains(a[ i ])) + { + //kdDebug(4640) << "x: " << x << " - y: " << y << endl; + switch( action ) + { + case Draw: + { + DrawCommand* dc = new DrawCommand( x, y, currentcolor, img, this ); + dc->execute(); + //*((uint*)img->scanLine(y) + x) = currentcolor; //colors[cell]|OPAQUE; + //int cell = y * numCols() + x; + //setColor( cell, currentcolor, false ); + doupdate = true; + //updateCell( y, x, FALSE ); + macro->addCommand( dc ); + break; + } + + case Mark: + case UnMark: + update(x*cellsize,y*cellsize, cellsize, cellsize); + //updateCell( y, x, true ); + break; + + default: + break; + } + } + } + + + if(doupdate) + { + setModified( true ); + updateColors(); + RepaintCommand* rc = new RepaintCommand( area, this ); + rc->execute(); + macro->addCommand( rc ); + pntarray.resize(0); + // add to undo/redo history + history->addCommand( macro, false ); } +} + +void KIconEditGrid::updatePreviewPixmap() +{ + p = *img; + emit changed(QPixmap(p)); +} + + +bool KIconEditGrid::isMarked(QPoint point) +{ + return isMarked(point.x(), point.y()); +} + + +bool KIconEditGrid::isMarked(int x, int y) +{ + if(((y * numCols()) + x) == selected) + return true; + + int s = pntarray.size(); + for(int i = 0; i < s; i++) + { + if(y == pntarray[i].y() && x == pntarray[i].x()) + return true; + } + + return false; +} + + +// Fast diffuse dither to 3x3x3 color cube +// Based on Qt's image conversion functions +static bool kdither_32_to_8( const QImage *src, QImage *dst ) +{ + register QRgb *p; + uchar *b; + int y; + + //printf("kconvert_32_to_8\n"); + + if ( !dst->create(src->width(), src->height(), 8, 256) ) { + kdWarning() << "OImage: destination image not valid" << endl; + return FALSE; + } + + int ncols = 256; + + static uint bm[16][16]; + static int init=0; + if (!init) + { + // Build a Bayer Matrix for dithering + init = 1; + int n, i, j; + + bm[0][0]=0; + + for (n=1; n<16; n*=2) + { + for (i=0; isetNumColors( ncols ); + +#define MAX_R 2 +#define MAX_G 2 +#define MAX_B 2 +#define INDEXOF(r,g,b) (((r)*(MAX_G+1)+(g))*(MAX_B+1)+(b)) + + int rc, gc, bc; + + for ( rc=0; rc<=MAX_R; rc++ ) // build 2x2x2 color cube + for ( gc=0; gc<=MAX_G; gc++ ) + for ( bc=0; bc<=MAX_B; bc++ ) + { + dst->setColor( INDEXOF(rc,gc,bc), + qRgb( rc*255/MAX_R, gc*255/MAX_G, bc*255/MAX_B ) ); + } + + int sw = src->width(); + int* line1[3]; + int* line2[3]; + int* pv[3]; + + line1[0] = new int[src->width()]; + line2[0] = new int[src->width()]; + line1[1] = new int[src->width()]; + line2[1] = new int[src->width()]; + line1[2] = new int[src->width()]; + line2[2] = new int[src->width()]; + pv[0] = new int[sw]; + pv[1] = new int[sw]; + pv[2] = new int[sw]; + + for ( y=0; y < src->height(); y++ ) + { + p = (QRgb *)src->scanLine(y); + b = dst->scanLine(y); + int endian = (QImage::systemByteOrder() == QImage::BigEndian); + int x; + uchar* q = src->scanLine(y); + uchar* q2 = src->scanLine(y+1 < src->height() ? y + 1 : 0); + for (int chan = 0; chan < 3; chan++) + { + b = dst->scanLine(y); + int *l1 = (y&1) ? line2[chan] : line1[chan]; + int *l2 = (y&1) ? line1[chan] : line2[chan]; + if ( y == 0 ) + { + for (int i=0; iheight() ) + { + for (int i=0; i>4; + l2[x+1] += err>>4; + } + l2[x]+=(err*5)>>4; + if (x>1) + l2[x-1]+=(err*3)>>4; + } + } + else + { + for (x=sw; x-->0; ) + { + int pix = QMAX(QMIN(2, (l1[x] * 2 + 128)/ 255), 0); + int err = l1[x] - pix * 255 / 2; + pv[chan][x] = pix; + + // Spread the error around... + if ( x > 0 ) + { + l1[x-1] += (err*7)>>4; + l2[x-1] += err>>4; + } + l2[x]+=(err*5)>>4; + if (x+1 < sw) + l2[x+1]+=(err*3)>>4; + } + } + } + if (endian) + { + for (x=0; xheight(); y++) + { + uint *l = (uint*)img->scanLine(y); + for(int x = 0; x < img->width(); x++, l++) + { + if(*l < 0xff000000) + { + *l = *l | 0xff000000; + } + } + } + + load(img); + return; + +/* +#if QT_VERSION > 140 + *img = img->convertDepthWithPalette(32, iconpalette, 42); + load(img); + return; +#endif +*/ + + QApplication::setOverrideCursor(waitCursor); + for(int y = 0; y < numRows(); y++) + { + uint *l = (uint*)img->scanLine(y); + for(int x = 0; x < numCols(); x++, l++) + { + if(*l != TRANSPARENT) + { + if(!iconcolors.contains(*l)) + *l = iconcolors.closestMatch(*l); + } + } + } + + load(img); + setModified(true); + QApplication::restoreOverrideCursor(); +} + + +void KIconEditGrid::grayScale() +{ + for(int y = 0; y < numRows(); y++) + { + uint *l = (uint*)img->scanLine(y); + for(int x = 0; x < numCols(); x++, l++) + { + if(*l != TRANSPARENT) + { + uint c = qGray(*l); + *l = qRgba(c, c, c, qAlpha(*l)); + } + } + } + + load(img); + setModified(true); +} + + +void KIconEditGrid::clearImage(QImage *image) +{ + if(image->depth() != 32) + { + image->fill(TRANSPARENT); + } + else + { + // QImage::fill() does not set the alpha channel so do it + // manually. + for(int y = 0; y < image->height(); y++) + { + uint *l = (uint*)image->scanLine(y); + for(int x = 0; x < image->width(); x++, l++) + { + *l = TRANSPARENT; + } + } + } +} + + +void KIconEditGrid::setModified(bool m) +{ + if(m != modified) + { + modified = m; + emit modifiedchanged(m); + } +} + + +#include "kicongrid.moc" +// vim: set ts=4: diff --git a/kiconedit/kicongrid.h b/kiconedit/kicongrid.h new file mode 100644 index 00000000..24730735 --- /dev/null +++ b/kiconedit/kicongrid.h @@ -0,0 +1,263 @@ +/* + KDE Icon Editor - a small graphics drawing program for the KDE. + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.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 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 __KICONEDITGRID_H__ +#define __KICONEDITGRID_H__ + +#include +#include +#include +#include +#include +#include +#include + +#include "kcolorgrid.h" + +class KCommandHistory; +class KRuler; +class KIconEditGrid; +class QScrollView; + +enum Direction { + DirIn = 0, DirOut = 1, + DirUp = DirIn, DirDown = DirOut, + DirLeft, DirRight +}; + +class DrawCommand : public KCommand { + public: + DrawCommand( int xx, int yy, uint newcol, QImage* img, KIconEditGrid* g ) { + x = xx; + y = yy; + newcolor = newcol; + image = img; + grid = g; + } + + void execute(); + void unexecute(); + QString name() const { + return i18n("Drawed Something"); + } + + protected: + int x; + int y; + uint newcolor; + uint oldcolor; + QImage* image; + KIconEditGrid* grid; +}; + +class RepaintCommand : public KCommand { + public: + RepaintCommand( QRect a, KIconEditGrid* g ) { + area = a; + grid = g; + } + + void execute(); + void unexecute() { + execute(); + } + + QString name() const { + return "repainted"; + } + protected: + KIconEditGrid* grid; + QRect area; +}; + +class KGridView : public QFrame +{ + Q_OBJECT +public: + KGridView( QImage *image, KCommandHistory* history, QWidget * parent = 0, const char *name = 0); + + KRuler *hruler() { return _hruler;} + KRuler *vruler() { return _vruler;} + QFrame *corner() { return _corner;} + KIconEditGrid *grid() { return _grid; } + void setShowRulers(bool mode); + void setAcceptDrop(bool a); + const QRect viewRect(); + QScrollView *viewPortWidget() { return viewport;} + +public slots: + void sizeChange(int, int); + void moving(int, int); + void scalingChange(int); + void paintGrid(); + void checkClipboard(); + +protected: + virtual void paintEvent(QPaintEvent*); + virtual void resizeEvent(QResizeEvent*); + void paintDropSite(); + void setSizes(); + + QFrame *_corner; + KIconEditGrid *_grid; + KRuler *_hruler, *_vruler; + QScrollView *viewport; + bool acceptdrop; +}; + +/** +* KIconEditGrid +* @short KIconEditGrid +* @author Thomas Tanghus +* @version 0.3 +*/ +class KIconEditGrid : public KColorGrid +{ + Q_OBJECT +public: + KIconEditGrid( QImage *image, KCommandHistory* h, QWidget * parent = 0, const char *name = 0); + virtual ~KIconEditGrid(); + + enum DrawTool { Line, Freehand, FloodFill, Spray, Rect, FilledRect, Circle, + FilledCircle, Ellipse, FilledEllipse, Eraser, SelectRect, SelectCircle, Find }; + enum DrawAction { Mark, UnMark, Draw }; + + void setGrid(bool g) { KColorGrid::setGrid(g); emit needPainting(); } + bool isModified() { return modified; }; + void setModified(bool m); + const QPixmap &pixmap(); + const QImage &image() { return *img; } + QImage clipboardImage(bool &ok); + QImage getSelection(bool); + int rows() { return numRows(); }; + int cols() { return numCols(); }; + uint getColors( uint *_colors) { return colors(_colors); } + bool isMarked(QPoint p); + bool isMarked(int x, int y); + int scaling() { return cellSize(); } + void loadBlank( int w = 0, int h = 0); + void setUndoColor( int colNum, uint v, bool update = true ) { + setColor( colNum, v, update ); + }; + + enum TransparencyDisplayType + { + TRD_SOLIDCOLOR, + TRD_CHECKERBOARD + }; + enum CheckerboardSize + { + CHK_SMALL = 0, + CHK_MEDIUM = 1, + CHK_LARGE = 2 + }; + + TransparencyDisplayType transparencyDisplayType() const { return m_transparencyDisplayType; } + QColor checkerboardColor1() const { return m_checkerboardColor1; } + QColor checkerboardColor2() const { return m_checkerboardColor2; } + CheckerboardSize checkerboardSize() const { return m_checkerboardSize; } + QColor transparencySolidColor() const { return m_transparencySolidColor; } + + void setTransparencyDisplayType(TransparencyDisplayType t) { m_transparencyDisplayType = t; } + void setCheckerboardColor1(const QColor& c) { m_checkerboardColor1 = c; } + void setCheckerboardColor2(const QColor& c) { m_checkerboardColor2 = c; } + void setCheckerboardSize(CheckerboardSize size) { m_checkerboardSize = size; } + void setTransparencySolidColor(const QColor& c) { m_transparencySolidColor = c; } + +public slots: + void load( QImage *); + void editCopy(bool cut = false); + void editPaste(bool paste = false); + void editPasteAsNew(); + void editSelectAll(); + void editClear(); + void getImage(QImage *image); +//#if QT_VERSION <= 140 + void editResize(); +//#endif + void setSize(const QSize s); + void grayScale(); + void mapToKDEPalette(); + void setTool(DrawTool tool); + bool zoom(Direction direct); + bool zoomTo(int); + + void checkClipboard(); + +signals: + void scalingchanged(int); + void changed( const QPixmap & ); + void sizechanged( int, int ); + void poschanged( int, int ); + void xposchanged( int ); + void yposchanged( int ); + void newmessage(const QString &); + void clipboarddata(bool); + void selecteddata(bool); + void needPainting(); + void modifiedchanged(bool); + void colorSelected(uint); + +protected slots: + void setColorSelection( uint ); + void updatePreviewPixmap(); + +protected: + virtual void paintEvent(QPaintEvent*); + virtual void paintCell( QPainter*, int, int ) {} + virtual void paintForeground(QPainter* p, QPaintEvent* e); + virtual void mousePressEvent(QMouseEvent*); + virtual void mouseReleaseEvent(QMouseEvent*); + virtual void mouseMoveEvent(QMouseEvent*); + void createCursors(); + void drawPointArray(QPointArray, DrawAction); + void drawEllipse(bool); + void drawLine(bool drawIt, bool drawStraight); + void drawRect(bool); + void drawSpray(QPoint); + void drawFlood(int x, int y, uint oldcolor); + static void clearImage(QImage *image); + + uint currentcolor; + QPoint start, end; + QRect insrect; + QSize cbsize; + QImage *img; + QPixmap p; + int selected, tool; //, numrows, numcols; + bool modified, btndown, ispasting, isselecting; + QPointArray pntarray; + KColorArray iconcolors; + KCommandHistory* history; + KMacroCommand* m_command; + QCursor cursor_normal, cursor_aim, cursor_flood, cursor_spray, cursor_erase, cursor_paint, cursor_colorpicker; + TransparencyDisplayType m_transparencyDisplayType; + QColor m_checkerboardColor1; + QColor m_checkerboardColor2; + CheckerboardSize m_checkerboardSize; + QColor m_transparencySolidColor; +}; + + + +#endif //__KICONEDITGRID_H__ + + + diff --git a/kiconedit/knew.cpp b/kiconedit/knew.cpp new file mode 100644 index 00000000..214952b0 --- /dev/null +++ b/kiconedit/knew.cpp @@ -0,0 +1,326 @@ +/* + KDE Draw - a small graphics drawing program for the KDE + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.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 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "knew.h" + +KIconTemplateContainer* KIconTemplateContainer::instance = 0; + +void createStandardTemplates(KIconTemplateContainer *list) +{ + KIconLoader *kil = KGlobal::iconLoader(); + + KIconTemplate it; + it.path = kil->iconPath("standard", KIcon::User); + it.title = i18n("Standard File"); + list->append(it); + + it.path = kil->iconPath("source", KIcon::User); + it.title = i18n("Source File"); + list->append(it); + + it.path = kil->iconPath("compressed", KIcon::User); + it.title = i18n("Compressed File"); + list->append(it); + + it.path = kil->iconPath("folder", KIcon::User); + it.title = i18n("Standard Folder"); + list->append(it); + + it.path = kil->iconPath("package", KIcon::User); + it.title = i18n("Standard Package"); + list->append(it); + + it.path = kil->iconPath("mini-folder", KIcon::User); + it.title = i18n("Mini Folder"); + list->append(it); + + it.path = kil->iconPath("mini-package", KIcon::User); + it.title = i18n("Mini Package"); + list->append(it); +} + +void KIconTemplateContainer::save() +{ + KConfig *k = kapp->config(); + k->setGroup("Templates"); + + QStringList names; + for (QValueListIterator iter = begin(); iter != end(); iter++) + { + names.append((*iter).title); + } + + k->writeEntry("Names", names); + + for(unsigned int i = 0; i < names.count(); i++) + { + k->writePathEntry(names[i], (*this)[i].path); + } +} + +KIconTemplateContainer::KIconTemplateContainer() : QValueList() +{ + QStrList names; + KConfig *k = kapp->config(); + k->setGroup("Templates"); + k->readListEntry("Names", names); + for(int i = 0; i < (int)names.count(); i++) + { + KIconTemplate it; + it.path = k->readPathEntry(names.at(i)); + it.title = names.at(i); + //kdDebug(4640) << "Template: " << names.at(i) << "\n" << path.data() << endl; + append(it); + } + + if(count() == 0) + { + createStandardTemplates(this); + } +} + +KIconTemplateContainer::~KIconTemplateContainer() +{ + clear(); +} + +KIconListBoxItem::KIconListBoxItem( KIconTemplate t ) + : QListBoxItem(), icontemplate(t) +{ + //kdDebug(4640) << "KIconListBoxItem - " << t->path.data() << ", " << t->title.data() << endl; + + pm.load(t.path); + setText( t.title ); +} + +void KIconListBoxItem::reloadIcon() +{ + pm.load(icontemplate.path); + setText( icontemplate.title ); +} + + + +void KIconListBoxItem::paint( QPainter *p ) +{ + p->drawPixmap( 3, 0, pm ); + QFontMetrics fm = p->fontMetrics(); + int yPos; // vertical text position + if ( pm.height() < fm.height() ) + yPos = fm.ascent() + fm.leading()/2; + else + yPos = pm.height()/2 - fm.height()/2 + fm.ascent(); + p->drawText( pm.width() + 5, yPos, text() ); +} + +int KIconListBoxItem::height(const QListBox *lb ) const +{ + return QMAX( pm.height(), lb->fontMetrics().lineSpacing() + 1 ); +} + +int KIconListBoxItem::width(const QListBox *lb ) const +{ + return pm.width() + lb->fontMetrics().width( text() ) + 6; +} + +NewSelect::NewSelect(QWidget *parent) : QWidget( parent ) +{ + wiz = (KWizard*) parent; + grp = new QButtonGroup( this ); + connect( grp, SIGNAL( clicked( int ) ), SLOT( buttonClicked( int ) ) ); + grp->setExclusive( true ); + + QVBoxLayout* ml = new QVBoxLayout( this ); + ml->addWidget( grp, 1 ); + //ml->addWidget(grp, 10, AlignLeft); + QVBoxLayout* l = new QVBoxLayout( grp, 10 ); + + rbscratch = new QRadioButton( i18n( "Create from scratch" ), grp ); + l->addWidget( rbscratch, 1 ); + //l->addWidget(rbscratch, 5, AlignLeft); + + rbtempl = new QRadioButton( i18n( "Create from template" ), grp ); + l->addWidget( rbtempl, 1 ); + //l->addWidget(rbtempl, 5, AlignLeft); + + //grp->setMinimumSize(grp->childrenRect().size()); + + grp->setButton( 0 ); +} + +NewSelect::~NewSelect() +{ +} + +void NewSelect::buttonClicked(int id) +{ + //kdDebug(4640) << "Button: " << id << endl; + + emit iconopenstyle(id); +} + +NewFromTemplate::NewFromTemplate( QWidget* parent ) + : QWidget( parent ) +{ + wiz = (KWizard*) parent; + + QVBoxLayout* ml = new QVBoxLayout(this); + + grp = new QGroupBox( i18n( "Templates" ), this ); + ml->addWidget( grp, 1 ); + //ml->addWidget(grp, 10, AlignLeft); + + QHBoxLayout* l = new QHBoxLayout( grp, 15 ); + + templates = new KIconListBox( grp ); + connect( templates, SIGNAL( highlighted( int ) ), SLOT( checkSelection( int ) ) ); + l->addWidget( templates ); + + for( int i = 0; i < (int) KIconTemplateContainer::self()->count(); i++ ) + templates->insertItem( new KIconListBoxItem( *KIconTemplateContainer::self()->at( i ) ) ); +} + +NewFromTemplate::~NewFromTemplate() +{ +} + +void NewFromTemplate::checkSelection( int ) +{ + //kdDebug(4640) << "checkSelection(int) " << templates->currentItem() << endl; + if( templates->currentItem() != -1 ) + wiz->finishButton()->setEnabled( true ); + else + wiz->finishButton()->setEnabled( false ); +} + +KNewIcon::KNewIcon( QWidget* parent ) + : KWizard( parent, 0, true ) +{ + //kdDebug(4640) << "KNewIcon" << endl; + setCaption( i18n( "Create New Icon" ) ); + resize( 400, 250 ); + + openstyle = 0; + + finishButton()->setEnabled( true ); + cancelButton()->setEnabled( true ); + nextButton()->setEnabled( false ); + + select = new NewSelect( this ); + connect( select, SIGNAL( iconopenstyle( int ) ), SLOT( iconOpenStyle( int ) ) ); + + scratch = new KResizeWidget( this, 0, QSize( 32, 32 ) ); + // this doesn't accept default valid size, besides spin buttons won't allow + // an invalid size to be set by the user - forces user to change valid default + // size to create the new icon object - + connect( scratch, SIGNAL( validSize( bool ) ), SLOT( checkPage( bool ) ) ); + connect(this, SIGNAL(selected(const QString &)), this, SLOT(checkPage(const QString &))); + templ = new NewFromTemplate(this); + templ->hide(); + + addPage(select, i18n("Select Icon Type")); + addPage(scratch, i18n("Create From Scratch")); + act = scratch; + //addPage(templ, i18n("Create From Template")); +} + +KNewIcon::~KNewIcon() +{ + delete select; + delete scratch; + delete templ; +} + +void KNewIcon::okClicked() +{ + if(openstyle == Blank) + emit newicon(scratch->getSize()); + else + emit newicon(templ->path()); + hide(); + setResult(1); + accept(); +} + +void KNewIcon::cancelClicked() +{ + hide(); + setResult(0); + reject(); +} + +void KNewIcon::iconOpenStyle(int style) +{ + openstyle = style; + + if( act ) + removePage( act ); + + if(openstyle == Blank) + { + act = scratch; + setNextEnabled( act, true ); + addPage( scratch, i18n( "Create From Scratch" ) ); + } + else if( openstyle == Template ) + { + act = templ; + setNextEnabled( act, true ); + addPage( templ, i18n( "Create From Template" ) ); + } +} + +void KNewIcon::checkPage( bool b) +{ + //kdDebug(4640) << "checkPage(int) " << openstyle << " " << p << endl; + if(openstyle == Blank) + finishButton()->setEnabled(true); + else if( !b ) + finishButton()->setEnabled(false); + else + templ->checkSelection(0); +} + +void KNewIcon::checkPage(const QString &) +{ + if(currentPage() == select || openstyle == Blank) + finishButton()->setEnabled(true); + else + finishButton()->setEnabled(false); +} +#include "knew.moc" + + + + + diff --git a/kiconedit/knew.h b/kiconedit/knew.h new file mode 100644 index 00000000..8801faf7 --- /dev/null +++ b/kiconedit/knew.h @@ -0,0 +1,164 @@ +/* + KDE Draw - a small graphics drawing program for the KDE. + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.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 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 __KNEWICON_H__ +#define __KNEWICON_H__ + +#include +#include +#include +#include + +#include + +#include "kresize.h" + +class KIconListBox; +class KIconTemplateContainer; +class QButtonGroup; +class QRadioButton; +class QGroupBox; + +struct KIconTemplate +{ + QString path; + QString title; +}; + +class KIconListBoxItem : public QListBoxItem +{ +public: + KIconListBoxItem( KIconTemplate ); + + + const QString path() { return icontemplate.path; } + KIconTemplate& iconTemplate() { return icontemplate; } + void reloadIcon(); + +protected: + virtual void paint( QPainter * ); + virtual int height( const QListBox * ) const; + virtual int width( const QListBox * ) const; +private: + QPixmap pm; + KIconTemplate icontemplate; +}; + +class KIconListBox : public QListBox +{ + Q_OBJECT +public: + KIconListBox( QWidget *parent ) : QListBox(parent) {} ; + const QString path(int idx) { return ((KIconListBoxItem*)item(idx))->path(); } + KIconTemplate& iconTemplate(int idx) { return ((KIconListBoxItem*)item(idx))->iconTemplate(); } + +}; + +class KIconTemplateContainer : public QValueList +{ +public: + static KIconTemplateContainer* self() + { + if (!instance) + instance = new KIconTemplateContainer; + return instance; + } + + void save(); + +private: + static KIconTemplateContainer* instance; + + const KIconTemplateContainer operator = (const KIconTemplateContainer&); + KIconTemplateContainer(const KIconTemplateContainer&); + + KIconTemplateContainer(); + ~KIconTemplateContainer(); +}; + +class NewSelect : public QWidget +{ + Q_OBJECT +public: + NewSelect(QWidget *parent); + ~NewSelect(); + +signals: + void iconopenstyle(int); + +protected slots: + void buttonClicked(int); + +protected: + KWizard *wiz; + QButtonGroup *grp; + QRadioButton *rbscratch, *rbtempl; +}; + +class NewFromTemplate : public QWidget +{ + Q_OBJECT +public: + NewFromTemplate(QWidget *parent); + ~NewFromTemplate(); + + const QString path() { return QString(templates->path(templates->currentItem())); } + +public slots: + void checkSelection(int); + +protected: + KIconListBox *templates; + KWizard *wiz; + QGroupBox *grp; +}; + +class KNewIcon : public KWizard +{ + Q_OBJECT +public: + KNewIcon(QWidget *parent); + ~KNewIcon(); + + enum { Blank = 0, Template = 1}; + int openStyle() { return openstyle; } + const QString templatePath() { return QString(templ->path()); } + const QSize templateSize() { return scratch->getSize(); } + +protected slots: + void okClicked(); + void cancelClicked(); + void iconOpenStyle(int); + void checkPage(bool); + void checkPage(const QString &); + +signals: + void newicon(const QSize); + void newicon(const QString); + +protected: + NewSelect *select; + KResizeWidget *scratch; + NewFromTemplate *templ; + QWidget *act; + int openstyle; +}; + +#endif // __KNEWICON_H__ diff --git a/kiconedit/kresize.cpp b/kiconedit/kresize.cpp new file mode 100644 index 00000000..82a86ee3 --- /dev/null +++ b/kiconedit/kresize.cpp @@ -0,0 +1,83 @@ +/* + KDE Draw - a small graphics drawing program for the KDE + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.org) + Copyright (C) 2002 Nadeem Hasan ( nhasan@kde.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 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 +#include +#include + +#include +#include + +#include "kresize.h" + +KResizeWidget::KResizeWidget( QWidget* parent, const char* name, + const QSize& size ) : QWidget( parent, name ) +{ + QHBoxLayout* genLayout = new QHBoxLayout( this ); + + QGroupBox* group = new QGroupBox( i18n( "Size" ), this ); + group->setColumnLayout( 0, Qt::Horizontal ); + genLayout->addWidget( group ); + + QHBoxLayout* layout = new QHBoxLayout( group->layout(), 6 ); + + m_width = new KIntSpinBox( 1, 200, 1, 1, 10, group ); + m_width->setValue( size.width() ); + layout->addWidget( m_width, 1 ); + + QLabel* label = new QLabel( "X", group ); + layout->addWidget( label ); + + m_height = new KIntSpinBox( 1, 200, 1, 1, 10, group); + m_height->setValue( size.height() ); + layout->addWidget( m_height, 1 ); + + setMinimumSize( 200, 100 ); +} + +KResizeWidget::~KResizeWidget() +{ +} + +const QSize KResizeWidget::getSize() +{ + return QSize( m_width->value(), m_height->value() ); +} + +KResizeDialog::KResizeDialog( QWidget* parent, const char* name, + const QSize size ) + : KDialogBase( parent, name, true, i18n( "Select Size" ), Ok|Cancel ) +{ + m_resize = new KResizeWidget( this, "resize widget", size ); + + setMainWidget( m_resize ); +} + +KResizeDialog::~KResizeDialog() +{ +} + +const QSize KResizeDialog::getSize() +{ + return m_resize->getSize(); +} + +#include "kresize.moc" diff --git a/kiconedit/kresize.h b/kiconedit/kresize.h new file mode 100644 index 00000000..691a4bd9 --- /dev/null +++ b/kiconedit/kresize.h @@ -0,0 +1,62 @@ +/* + KDE Draw - a small graphics drawing program for the KDE. + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.org) + Copyright ( C ) 2002 Nadeem Hasan ( nhasan@kde.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 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 __KRESIZE_H__ +#define __KRESIZE_H__ + +#include + +class KIntSpinBox; + +class KResizeWidget : public QWidget +{ + Q_OBJECT + +public: + + KResizeWidget( QWidget* parent, const char* name, const QSize& ); + ~KResizeWidget(); + + const QSize getSize(); + +private: + + KIntSpinBox *m_width; + KIntSpinBox *m_height; +}; + +class KResizeDialog : public KDialogBase +{ + Q_OBJECT + +public: + + KResizeDialog( QWidget* parent, const char* name, const QSize s ); + ~KResizeDialog(); + + const QSize getSize(); + +private: + + KResizeWidget* m_resize; +}; + +#endif //__KRESIZE_H__ diff --git a/kiconedit/main.cpp b/kiconedit/main.cpp new file mode 100644 index 00000000..52abdd09 --- /dev/null +++ b/kiconedit/main.cpp @@ -0,0 +1,89 @@ +/* + KDE Draw - a small graphics drawing program for the KDE. + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.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. +*/ + +// A lot of this code is lifted from KMail. Thanks, guys! + +#include + +#include +#include +#include +#include +#include + +#include "kiconedit.h" +#include "config.h" +#include "properties.h" + +static const char description[] = + I18N_NOOP("KDE Icon Editor"); + +static KCmdLineOptions options[] = +{ + { "+[file(s)]" , I18N_NOOP("Icon file(s) to open"), 0 }, + KCmdLineLastOption +}; + +int main(int argc, char **argv) +{ + KAboutData aboutData( "kiconedit", I18N_NOOP("KIconEdit"), + VERSION, description, KAboutData::License_GPL, + "(c) 1998, Thomas Tanghus"); + + aboutData.addAuthor("Thomas Tanghus",0, "tanghus@kde.org"); + aboutData.addAuthor("John Califf",0, "jcaliff@compuzone.net"); + aboutData.addAuthor("Laurent Montel",0, "lmontel@mandrakesoft.com"); + aboutData.addAuthor("Aaron J. Seigo",0, "aseigo@olympusproject.org"); + aboutData.addCredit( "Nadeem Hasan", "Rewrote UI to use XMLGUI\n" + "Lots of fixes and cleanup", "nhasan@nadmm.com" ); + aboutData.addCredit( "Adrian Page", I18N_NOOP("Bug fixes and GUI tidy up"), + "Adrian.Page@tesco.net" ); + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); // Add our own options. + + KApplication a; + +// setSignalHandler(signalHandler); + + if (a.isRestored()) + { + RESTORE(KIconEdit); + } + else + { + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + for(int i = 0; i < args->count(); i++) + { + KIconEdit *ki = new KIconEdit(args->url(i), "kiconedit"); + Q_CHECK_PTR(ki); + } + + if (args->count() == 0) + { + KIconEdit *ki = new KIconEdit; + Q_CHECK_PTR(ki); + } + args->clear(); + } + + int rc = a.exec(); + delete KIconEditProperties::self(); + return rc; +} + diff --git a/kiconedit/palettetoolbar.cpp b/kiconedit/palettetoolbar.cpp new file mode 100644 index 00000000..207442e1 --- /dev/null +++ b/kiconedit/palettetoolbar.cpp @@ -0,0 +1,178 @@ +/* + kiconedit - a small graphics drawing program for the KDE + Copyright ( C ) 1998 Thomas Tanghus ( tanghus@kde.org ) + Copyright ( C ) 2002 Nadeem Hasan ( nhasan@kde.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 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 +#include +#include +#include + +#include +#include + +#include "kiconcolors.h" +#include "palettetoolbar.h" + +PaletteToolBar::PaletteToolBar( QWidget *parent, const char *name ) + : KToolBar( parent, name ) +{ + QWidget *base = new QWidget( this ); + + QBoxLayout::Direction d = orientation() == Qt::Horizontal? + QBoxLayout::LeftToRight : QBoxLayout::TopToBottom; + m_layout = new QBoxLayout( base, d, 2, 6 ); + + m_lblPreview = new QLabel( base ); + m_lblPreview->setFrameStyle( QFrame::Panel|QFrame::Sunken ); + m_lblPreview->setFixedHeight( 64 ); + m_lblPreview->setAlignment( Qt::AlignHCenter|Qt::AlignVCenter ); + QWhatsThis::add(m_lblPreview, i18n( "Preview\n\nThis is a 1:1 preview" + " of the current icon" ) ); + m_layout->addWidget( m_lblPreview ); + + m_currentColorView = new QLabel( base ); + m_currentColorView->setFrameStyle( QFrame::Panel|QFrame::Sunken ); + m_currentColorView->setFixedHeight( 24 ); + m_currentColorView->setAlignment( Qt::AlignHCenter|Qt::AlignVCenter ); + QWhatsThis::add(m_currentColorView, i18n( "Current color\n\nThis is the currently selected color" ) ); + m_layout->addWidget( m_currentColorView ); + + QVBoxLayout *vlayout = new QVBoxLayout( m_layout, 0 ); + QLabel *l = new QLabel( i18n( "System colors:" ), base ); + vlayout->addWidget( l ); + m_sysColors = new KSysColors( base ); + QWhatsThis::add(m_sysColors, i18n( "System colors\n\nHere you can select" + " colors from the KDE icon palette" ) ); + + vlayout->addWidget( m_sysColors ); + + connect( m_sysColors, SIGNAL( newColor(uint) ), + SIGNAL( newColor(uint) ) ); + + vlayout = new QVBoxLayout( m_layout, 0 ); + l = new QLabel( i18n( "Custom colors:" ), base ); + vlayout->addWidget( l ); + m_customColors = new KCustomColors( base ); + QWhatsThis::add(m_customColors, i18n( "Custom colors\n\nHere you can" + " build a palette of custom colors.\nDouble-click on a box to edit" + " the color" ) ); + + vlayout->addWidget( m_customColors ); + + connect( m_customColors, SIGNAL( newColor(uint) ), + SIGNAL( newColor(uint) ) ); + connect( this, SIGNAL( newColor(uint)), + this, SLOT(currentColorChanged(uint))); + currentColorChanged(OPAQUE_MASK|0); + + setEnableContextMenu( false ); + setMovingEnabled( false ); +} + +void PaletteToolBar::setOrientation( Orientation o ) +{ + if( barPos() == Floating ) + o = o == Qt::Vertical ? Qt::Horizontal : Qt::Vertical; + + QBoxLayout::Direction d = o == Qt::Horizontal? QBoxLayout::LeftToRight + : QBoxLayout::TopToBottom; + m_layout->setDirection( d ); + + QDockWindow::setOrientation( o ); +} + +void PaletteToolBar::previewChanged( const QPixmap &p ) +{ + m_lblPreview->setPixmap( p ); +} + +void PaletteToolBar::addColors( uint n, uint *c ) +{ + m_customColors->clear(); + for( uint i = 0; i < n; i++ ) + addColor( c[ i ] ); +} + +void PaletteToolBar::addColor( uint color ) +{ + if( !m_sysColors->contains( color ) ) + m_customColors->addColor( color ); +} + +void PaletteToolBar::setPreviewBackground( QPixmap pixmap ) +{ + m_lblPreview->setBackgroundPixmap(pixmap); +} + +void PaletteToolBar::setPreviewBackground( const QColor& colour ) +{ + m_lblPreview->setBackgroundColor(colour); +} + +void PaletteToolBar::currentColorChanged(uint color) +{ + if(qAlpha(color) == 255) + { + m_currentColorView->setBackgroundColor(color); + } + else + { + // Show the colour as if drawn over a checkerboard pattern + const int squareWidth = 8; + const uint lightColour = qRgb(255, 255, 255); + const uint darkColour = qRgb(127, 127, 127); + + QPixmap pm(2 * squareWidth, 2 * squareWidth); + QPainter p(&pm); + + double alpha = qAlpha(color) / 255.0; + + int r = int(qRed(color) * alpha + (1 - alpha) * qRed(lightColour) + 0.5); + int g = int(qGreen(color) * alpha + (1 - alpha) * qGreen(lightColour) + 0.5); + int b = int(qBlue(color) * alpha + (1 - alpha) * qBlue(lightColour) + 0.5); + + uint squareColour = qRgb(r, g, b); + + p.setPen(Qt::NoPen); + p.setBrush(squareColour); + p.drawRect(0, 0, squareWidth, squareWidth); + p.drawRect(squareWidth, squareWidth, squareWidth, squareWidth); + + r = int(qRed(color) * alpha + (1 - alpha) * qRed(darkColour) + 0.5); + g = int(qGreen(color) * alpha + (1 - alpha) * qGreen(darkColour) + 0.5); + b = int(qBlue(color) * alpha + (1 - alpha) * qBlue(darkColour) + 0.5); + + squareColour = qRgb(r, g, b); + + p.setBrush(squareColour); + p.drawRect(squareWidth, 0, squareWidth, squareWidth); + p.drawRect(0, squareWidth, squareWidth, squareWidth); + + p.end(); + + m_currentColorView->setBackgroundPixmap(pm); + } +} + +#include "palettetoolbar.moc" + +/* vim: et sw=2 ts=2 +*/ + diff --git a/kiconedit/palettetoolbar.h b/kiconedit/palettetoolbar.h new file mode 100644 index 00000000..83cb3960 --- /dev/null +++ b/kiconedit/palettetoolbar.h @@ -0,0 +1,63 @@ +/* + kiconedit - a small graphics drawing program for the KDE + Copyright ( C ) 1998 Thomas Tanghus ( tanghus@kde.org ) + Copyright ( C ) 2002 Nadeem Hasan ( nhasan@kde.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 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 PALLETTETOOLBAR_H +#define PALLETTETOOLBAR_H + +#include + +class QBoxLayout; +class QLabel; +class KSysColors; +class KCustomColors; + +class PaletteToolBar : public KToolBar +{ + Q_OBJECT + + public: + PaletteToolBar( QWidget *parent, const char *name = 0L ); + + signals: + void newColor( uint c ); + + public slots: + virtual void setOrientation( Orientation o ); + void previewChanged( const QPixmap &p ); + void addColors( uint n, uint *c ); + void addColor( uint color ); + void setPreviewBackground( QPixmap pixmap ); + void setPreviewBackground( const QColor& colour ); + void currentColorChanged(uint color); + + private: + QBoxLayout *m_layout; + QLabel *m_lblPreview; + QLabel *m_currentColorView; + KSysColors *m_sysColors; + KCustomColors *m_customColors; +}; + +#endif // PALLETTETOOLBAR_H + +/* vim: et sw=2 ts=2 +*/ + diff --git a/kiconedit/pics/Makefile.am b/kiconedit/pics/Makefile.am new file mode 100644 index 00000000..1a0b167e --- /dev/null +++ b/kiconedit/pics/Makefile.am @@ -0,0 +1,5 @@ + +SUBDIRS = icons toolbar + +KDE_ICON = kiconedit + diff --git a/kiconedit/pics/hi16-app-kiconedit.png b/kiconedit/pics/hi16-app-kiconedit.png new file mode 100644 index 00000000..ff16bcae Binary files /dev/null and b/kiconedit/pics/hi16-app-kiconedit.png differ diff --git a/kiconedit/pics/hi22-app-kiconedit.png b/kiconedit/pics/hi22-app-kiconedit.png new file mode 100644 index 00000000..8bb080c7 Binary files /dev/null and b/kiconedit/pics/hi22-app-kiconedit.png differ diff --git a/kiconedit/pics/hi32-app-kiconedit.png b/kiconedit/pics/hi32-app-kiconedit.png new file mode 100644 index 00000000..604b17dd Binary files /dev/null and b/kiconedit/pics/hi32-app-kiconedit.png differ diff --git a/kiconedit/pics/hi48-app-kiconedit.png b/kiconedit/pics/hi48-app-kiconedit.png new file mode 100644 index 00000000..b95bffae Binary files /dev/null and b/kiconedit/pics/hi48-app-kiconedit.png differ diff --git a/kiconedit/pics/icons/Makefile.am b/kiconedit/pics/icons/Makefile.am new file mode 100644 index 00000000..4acb372f --- /dev/null +++ b/kiconedit/pics/icons/Makefile.am @@ -0,0 +1,5 @@ +pics_DATA = source.png \ + standard.png \ + compressed.png + +picsdir = $(kde_datadir)/kiconedit/pics diff --git a/kiconedit/pics/icons/compressed.png b/kiconedit/pics/icons/compressed.png new file mode 100644 index 00000000..c919f3bf Binary files /dev/null and b/kiconedit/pics/icons/compressed.png differ diff --git a/kiconedit/pics/icons/source.png b/kiconedit/pics/icons/source.png new file mode 100644 index 00000000..8351e380 Binary files /dev/null and b/kiconedit/pics/icons/source.png differ diff --git a/kiconedit/pics/icons/standard.png b/kiconedit/pics/icons/standard.png new file mode 100644 index 00000000..df1e8318 Binary files /dev/null and b/kiconedit/pics/icons/standard.png differ diff --git a/kiconedit/pics/logo.xpm b/kiconedit/pics/logo.xpm new file mode 100644 index 00000000..97dab29d --- /dev/null +++ b/kiconedit/pics/logo.xpm @@ -0,0 +1,137 @@ +/* XPM */ +static const char *logo[]={ +"260 87 47 1", +"J c #9e9e9e", +"b c #9f9f9f", +"f c #a0a0a0", +"I c #a1a1a1", +"c c #a2a2a2", +"B c #a3a3a3", +"G c #a4a4a4", +"O c #a5a5a5", +"a c #a6a6a6", +"v c #a7a7a7", +"N c #a8a8a8", +"R c #a9a9a9", +"z c #aaaaaa", +"p c #ababab", +"w c #acacac", +"t c #adadad", +"Q c #aeaeae", +"P c #afafaf", +"o c #b0b0b0", +"S c #b1b1b1", +"K c #b2b2b2", +"C c #b3b3b3", +"M c #b4b4b4", +"s c #b5b5b5", +"k c #b6b6b6", +"n c #b7b7b7", +"H c #b8b8b8", +"A c #b9b9b9", +"d c #bababa", +"u c #bbbbbb", +"x c #bcbcbc", +"l c #bdbdbd", +"q c #bebebe", +"r c #bfbfbf", +"e c #c0c0c0", +"D c #c1c1c1", +"E c #c2c2c2", +"L c #c3c3c3", +"F c #c4c4c4", +"i c #c5c5c5", +"h c #c6c6c6", +"# c #c7c7c7", +"j c #c8c8c8", +"y c #c9c9c9", +"g c #cacaca", +"m c #cbcbcb", +". c #cccccc", +"....................#abcdebfg.hbijklm...................................#abcdebfg.hbijklm...................................#abcdebfg.hbijklm...................................#abcdebfg.hbijklm...................................#abcdebfg.hbijklm...............", +"................gni.opqrcstbu..vd...................................gni.opqrcstbu..vd...................................gni.opqrcstbu..vd...................................gni.opqrcstbu..vd...................................gni.opqrcstbu..vd...................", +"................qbu.wk..qbxbv..y....................................qbu.wk..qbxbv..y....................................qbu.wk..qbxbv..y....................................qbu.wk..qbxbv..y....................................qbu.wk..qbxbv..y....................", +"........iszA....qB..svm..vsCbr.........Dd.sE................iszA....qB..svm..vsCbr.........Dd.sE................iszA....qB..svm..vsCbr.........Dd.sE................iszA....qB..svm..vsCbr.........Dd.sE................iszA....qB..svm..vsCbr.........Dd.sE........", +"........sbbl.#..Ffg.jGog.zp.l#.........jh.Hp................sbbl.#..Ffg.jGog.zp.l#.........jh.Hp................sbbl.#..Ffg.jGog.zp.l#.........jh.Hp................sbbl.#..Ffg.jGog.zp.l#.........jh.Hp................sbbl.#..Ffg.jGog.zp.l#.........jh.Hp........", +".....dm.obbFmfH.mBu..iaIvbq...............yIE............dm.obbFmfH.mBu..iaIvbq...............yIE............dm.obbFmfH.mBu..iaIvbq...............yIE............dm.obbFmfH.mBu..iaIvbq...............yIE............dm.obbFmfH.mBu..iaIvbq...............yIE.......", +"...#pbu.pbJg.CbE.sGg.AKunL.................MNrKj.......#pbu.pbJg.CbE.sGg.AKunL.................MNrKj.......#pbu.pbJg.CbE.sGg.AKunL.................MNrKj.......#pbu.pbJg.CbE.sGg.AKunL.................MNrKj.......#pbu.pbJg.CbE.sGg.AKunL.................MNrKj....", +"...EJbGmabB..ycp.#ONHBE....................#ffHg.......EJbGmabB..ycp.#ONHBE....................#ffHg.......EJbGmabB..ycp.#ONHBE....................#ffHg.......EJbGmabB..ycp.#ONHBE....................#ffHg.......EJbGmabB..ycp.#ONHBE....................#ffHg....", +"....PbbHfbGh..xbHDOswq..............NF......acg.........PbbHfbGh..xbHDOswq..............NF......acg.........PbbHfbGh..xbHDOswq..............NF......acg.........PbbHfbGh..xbHDOswq..............NF......acg.........PbbHfbGh..xbHDOswq..............NF......acg.....", +".hDixfbcbbbbwD.nbbz.................pp......jGC......hDixfbcbbbbwD.nbbz.................pp......jGC......hDixfbcbbbbwD.nbbz.................pp......jGC......hDixfbcbbbbwD.nbbz.................pp......jGC......hDixfbcbbbbwD.nbbz.................pp......jGC.....", +".KbbpsbbfBbbbbNuLqg.................lbr..CF..rfE.....KbbpsbbfBbbbbNuLqg.................lbr..CF..rfE.....KbbpsbbfBbbbbNuLqg.................lbr..CF..rfE.....KbbpsbbfBbbbbNuLqg.................lbr..CF..rfE.....KbbpsbbfBbbbbNuLqg.................lbr..CF..rfE....", +".QbbAgGbbuAObbbQm...................gBOm.PB#..KOg....QbbAgGbbuAObbbQm...................gBOm.PB#..KOg....QbbAgGbbuAObbbQm...................gBOm.PB#..KOg....QbbAgGbbuAObbbQm...................gBOm.PB#..KOg....QbbAgGbbuAObbbQm...................gBOm.PB#..KOg...", +"..qIF.lbbOgmlNzg....................yvbn.hfP..#ONg....qIF.lbbOgmlNzg....................yvbn.hfP..#ONg....qIF.lbbOgmlNzg....................yvbn.hfP..#ONg....qIF.lbbOgmlNzg....................yvbn.hfP..#ONg....qIF.lbbOgmlNzg....................yvbn.hfP..#ONg..", +"...vx..Rbbn.npwA....................MGGIj.MfFmvqbL.....vx..Rbbn.npwA....................MGGIj.MfFmvqbL.....vx..Rbbn.npwA....................MGGIj.MfFmvqbL.....vx..Rbbn.npwA....................MGGIj.MfFmvqbL.....vx..Rbbn.npwA....................MGGIj.MfFmvqbL..", +"..HJo..LbbNmObbr................#y..anebS.gRcSbyrm....HJo..LbbNmObbr................#y..anebS.gRcSbyrm....HJo..LbbNmObbr................#y..anebS.gRcSbyrm....HJo..LbbNmObbr................#y..anebS.gRcSbyrm....HJo..LbbNmObbr................#y..anebS.gRcSbyrm..", +".Lbbbl..SMyQQEqy...............sbBj.Od.nJA.gKvn......Lbbbl..SMyQQEqy...............sbBj.Od.nJA.gKvn......Lbbbl..SMyQQEqy...............sbBj.Od.nJA.gKvn......Lbbbl..SMyQQEqy...............sbBj.Od.nJA.gKvn......Lbbbl..SMyQQEqy...............sbBj.Od.nJA.gKvn.....", +"..wpMGPrLdNbL.................yflad.to.ibbvRq.........wpMGPrLdNbL.................yflad.to.ibbvRq.........wpMGPrLdNbL.................yflad.to.ibbvRq.........wpMGPrLdNbL.................yflad.to.ibbvRq.........wpMGPrLdNbL.................yflad.to.ibbvRq.......", +".....ubbNpbbM..............Dnhibmwn.lfEhbsul.............ubbNpbbM..............Dnhibmwn.lfEhbsul.............ubbNpbbM..............Dnhibmwn.lfEhbsul.............ubbNpbbM..............Dnhibmwn.lfEhbsul.............ubbNpbbM..............Dnhibmwn.lfEhbsul........", +".....sbBg.KJC...........DFiIQBEbjOq..PINOm...............sbBg.KJC...........DFiIQBEbjOq..PINOm...............sbBg.KJC...........DFiIQBEbjOq..PINOm...............sbBg.KJC...........DFiIQBEbjOq..PINOm...............sbBg.KJC...........DFiIQBEbjOq..PINOm..........", +".....Fkd..mxF...........qzAz.Cazvcg..QtKh................Fkd..mxF...........qzAz.Cazvcg..QtKh................Fkd..mxF...........qzAz.Cazvcg..QtKh................Fkd..mxF...........qzAz.Cazvcg..QtKh................Fkd..mxF...........qzAz.Cazvcg..QtKh...........", +"...........rL...........gbvQ.gGHBOiiwOy........................rL...........gbvQ.gGHBOiiwOy........................rL...........gbvQ.gGHBOiiwOy........................rL...........gbvQ.gGHBOiiwOy........................rL...........gbvQ.gGHBOiiwOy.............", +".....................LHL.wbO..dOiNbfoj...................................LHL.wbO..dOiNbfoj...................................LHL.wbO..dOiNbfoj...................................LHL.wbO..dOiNbfoj...................................LHL.wbO..dOiNbfoj..............", +"....................EIbcPFfJ#.yfD.E#....................................EIbcPFfJ#.yfD.E#....................................EIbcPFfJ#.yfD.E#....................................EIbcPFfJ#.yfD.E#....................................EIbcPFfJ#.yfD.E#................", +"................jwe.QKyjvwKbk..Pr...................................jwe.QKyjvwKbk..Pr...................................jwe.QKyjvwKbk..Pr...................................jwe.QKyjvwKbk..Pr...................................jwe.QKyjvwKbk..Pr...................", +"..........mj....lbD.tM..FbxbBm................................mj....lbD.tM..FbxbBm................................mj....lbD.tM..FbxbBm................................mj....lbD.tM..FbxbBm................................mj....lbD.tM..FbxbBm......................", +"........ezfH....rB..ABy..RKlfl.........qs.Pl................ezfH....rB..ABy..RKlfl.........qs.Pl................ezfH....rB..ABy..RKlfl.........qs.Pl................ezfH....rB..ABy..RKlfl.........qs.Pl................ezfH....rB..ABy..RKlfl.........qs.Pl........", +"........Mbbrmxm.#bj.mpvEyvw.#m..........m.la................Mbbrmxm.#bj.mpvEyvw.#m..........m.la................Mbbrmxm.#bj.mpvEyvw.#m..........m.la................Mbbrmxm.#bj.mpvEyvw.#m..........m.la................Mbbrmxm.#bj.mpvEyvw.#m..........m.la........", +"....jQy.Qbbi.BQ..as..htfbci...............mOx...........jQy.Qbbi.BQ..as..htfbci...............mOx...........jQy.Qbbi.BQ..as..htfbci...............mOx...........jQy.Qbbi.BQ..as..htfbci...............mOx...........jQy.Qbbi.BQ..as..htfbci...............mOx.......", +"...LBbs.Rbfg.dbx.xfF.ssiEm.................AGMa#.......LBbs.Rbfg.dbx.xfF.ssiEm.................AGMa#.......LBbs.Rbfg.dbx.xfF.ssiEm.................AGMa#.......LBbs.Rbfg.dbx.xfF.ssiEm.................AGMa#.......LBbs.Rbfg.dbx.xfF.ssiEm.................AGMa#....", +"...hIbIjGbO..mvOmhNIwBh.............#......gfIE........hIbIjGbO..mvOmhNIwBh.............#......gfIE........hIbIjGbO..mvOmhNIwBh.............#......gfIE........hIbIjGbO..mvOmhNIwBh.............#......gfIE........hIbIjGbO..mvOmhNIwBh.............#......gfIE.....", +"....kbbKfbcum.LftABDnh..............Bq......wIh.........kbbKfbcum.LftABDnh..............Bq......wIh.........kbbKfbcum.LftABDnh..............Bq......wIh.........kbbKfbcum.LftABDnh..............Bq......wIh.........kbbKfbcum.LftABDnh..............Bq......wIh.....", +".DkAkGbbbbbbBkjeGbC.................Qam.....gRw......DkAkGbbbbbbBkjeGbC.................Qam.....gRw......DkAkGbbbbbbBkjeGbC.................Qam.....gRw......DkAkGbbbbbbBkjeGbC.................Qam.....gRw......DkAkGbbbbbbBkjeGbC.................Qam.....gRw.....", +".PbbQxbbfzJbbbfomy..................DbH..zx..iIu.....PbbQxbbfzJbbbfomy..................DbH..zx..iIu.....PbbQxbbfzJbbbfomy..................DbH..zx..iIu.....PbbQxbbfzJbbbfomy..................DbH..zx..iIu.....PbbQxbbfzJbbbfomy..................DbH..zx..iIu....", +".kIbl.zbbkFofbbn.....................vIj.MbE..AIi....kIbl.zbbkFofbbn.....................vIj.MbE..AIi....kIbl.zbbkFofbbn.....................vIj.MbE..AIi....kIbl.zbbkFofbbn.....................vIj.MbE..AIi....kIbl.zbbkFofbbn.....................vIj.MbE..AIi...", +"..#BF.LbbI#.FCCy....................hBbK.yBz..Epcy....#BF.LbbI#.FCCy....................hBbK.yBz..Epcy....#BF.LbbI#.FCCy....................hBbK.yBz..Epcy....#BF.LbbI#.FCCy....................hBbK.yBz..Epcy....#BF.LbbI#.FCCy....................hBbK.yBz..Epcy..", +"..mOA..obbo.KIOH....................QRRbL.ubxgBLfF....mOA..obbo.KIOH....................QRRbL.ubxgBLfF....mOA..obbo.KIOH....................QRRbL.ubxgBLfF....mOA..obbo.KIOH....................QRRbL.ubxgBLfF....mOA..obbo.KIOH....................QRRbL.ubxgBLfF..", +".gQbp..#IbojcfbD...............mlD..OAiBz..Kbvfyy....gQbp..#IbojcfbD...............mlD..OAiBz..Kbvfyy....gQbp..#IbojcfbD...............mlD..OAiBz..Kbvfyy....gQbp..#IbojcfbD...............mlD..OAiBz..Kbvfyy....gQbp..#IbojcfbD...............mlD..OAiBz..Kbvfyy...", +".LbbbKm.dr#ak.ym...............pcbF.OA.ubQygxKD......LbbbKm.dr#ak.ym...............pcbF.OA.ubQygxKD......LbbbKm.dr#ak.ym...............pcbF.OA.ubQygxKD......LbbbKm.dr#ak.ym...............pcbF.OA.ubQygxKD......LbbbKm.dr#ak.ym...............pcbF.OA.ubQygxKD.....", +"..nkrpGMnPIbD.................#bFRA.Sw.#bfbIe.........nkrpGMnPIbD.................#bFRA.Sw.#bfbIe.........nkrpGMnPIbD.................#bFRA.Sw.#bfbIe.........nkrpGMnPIbD.................#bFRA.Sw.#bfbIe.........nkrpGMnPIbD.................#bFRA.Sw.#bfbIe.......", +".....dbbCkfbS..............kpqib.wH.EfdLbeh#.............dbbCkfbS..............kpqib.wH.EfdLbeh#.............dbbCkfbS..............kpqib.wH.EfdLbeh#.............dbbCkfbS..............kpqib.wH.EfdLbeh#.............dbbCkfbS..............kpqib.wH.EfdLbeh#........", +".....Mbv..xBx...........xqEIdIlfLBD..kJfp................Mbv..xBx...........xqEIdIlfLBD..kJfp................Mbv..xBx...........xqEIdIlfLBD..kJfp................Mbv..xBx...........xqEIdIlfLBD..kJfp................Mbv..xBx...........xqEIdIlfLBD..kJfp...........", +".....gDE...ur...........EOnw.uBofGm.yakqm................gDE...ur...........EOnw.uBofGm.yakqm................gDE...ur...........EOnw.uBofGm.yakqm................gDE...ur...........EOnw.uBofGm.yakqm................gDE...ur...........EOnw.uBofGm.yakqm...........", +"...........hj...........mIcw..NsRcAABtm........................hj...........mIcw..NsRcAABtm........................hj...........mIcw..NsRcAABtm........................hj...........mIcw..NsRcAABtm........................hj...........mIcw..NsRcAABtm.............", +".....................dtngCbB..rByMfvx....................................dtngCbB..rByMfvx....................................dtngCbB..rByMfvx....................................dtngCbB..rByMfvx....................................dtngCbB..rByMfvx...............", +".................m..uINROFBbL.gIl....................................m..uINROFBbL.gIl....................................m..uINROFBbL.gIl....................................m..uINROFBbL.gIl....................................m..uINROFBbL.gIl...................", +"................FId.ws.mPOkbK..AL...................................FId.ws.mPOkbK..AL...................................FId.ws.mPOkbK..AL...................................FId.ws.mPOkbK..AL...................................FId.ws.mPOkbK..AL...................", +".........gDL....lI#.oS..jIdcIj.........gj.Fg.................gDL....lI#.oS..jIdcIj.........gj.Fg.................gDL....lI#.oS..jIdcIj.........gj.Fg.................gDL....lI#.oS..jIdcIj.........gj.Fg.................gDL....lI#.oS..jIdcIj.........gj.Fg........", +"........dfbd....Dc..qfL..pPivr.........rH.ok................dfbd....Dc..qfL..pPivr.........rH.ok................dfbd....Dc..qfL..pPivr.........rH.ok................dfbd....Dc..qfL..pPivr.........rH.ok................dfbd....Dc..qfL..pPivr.........rH.ok........", +".....m..Cbbemoj.ybi..sInlGP...............Dcg............m..Cbbemoj.ybi..sInlGP...............Dcg............m..Cbbemoj.ybi..sInlGP...............Dcg............m..Cbbemoj.ybi..sInlGP...............Dcg............m..Cbbemoj.ybi..sInlGP...............Dcg.......", +"....eGh.Qbb#.vvg.zP..LoOfwy................Rs.j.........eGh.Qbb#.vvg.zP..LoOfwy................Rs.j.........eGh.Qbb#.vvg.zP..LoOfwy................Rs.j.........eGh.Qbb#.vvg.zP..LoOfwy................Rs.j.........eGh.Qbb#.vvg.zP..LoOfwy................Rs.j.....", +"...rbbP.RbI..ebk.Ebx.QH....................qfNB#.......rbbP.RbI..ebk.Ebx.QH....................qfNB#.......rbbP.RbI..ebk.Ebx.QH....................qfNB#.......rbbP.RbI..ebk.Ebx.QH....................qfNB#.......rbbP.RbI..ebk.Ebx.QH....................qfNB#....", +"...gGbbFBbv...tcjiRIcRg.............lm.....mIBy........gGbbFBbv...tcjiRIcRg.............lm.....mIBy........gGbbFBbv...tcjiRIcRg.............lm.....mIBy........gGbbFBbv...tcjiRIcRg.............lm.....mIBy........gGbbFBbv...tcjiRIcRg.............lm.....mIBy.....", +"....ubbpbbbPL.jGGPByLm..............GH......kbD.........ubbpbbbPL.jGGPByLm..............GH......kbD.........ubbpbbbPL.jGGPByLm..............GH......kbD.........ubbpbbbPL.jGGPByLm..............GH......kbD.........ubbpbbbPL.jGGPByLm..............GH......kbD.....", +".uzQQRbbbbbbbzq#PNx.................Ccj..#...oag.....uzQQRbbbbbbbzq#PNx.................Ccj..#...oag.....uzQQRbbbbbbbzq#PNx.................Ccj..#...oag.....uzQQRbbbbbbbzq#PNx.................Ccj..#...oag.....uzQQRbbbbbbbzq#PNx.................Ccj..#...oag....", +".wbbSEJbfCBbbbbvm...................ibS..vK..yGC.....wbbSEJbfCBbbbbvm...................ibS..vK..yGC.....wbbSEJbfCBbbbbvm...................ibS..vK..yGC.....wbbSEJbfCBbbbbvm...................ibS..vK..yGC.....wbbSEJbfCBbbbbvm...................ibS..vK..yGC....", +".rNbD.obbSmuabbe.....................pbF.dbx..ebl....rNbD.obbSmuabbe.....................pbF.dbx..ebl....rNbD.obbSmuabbe.....................pbF.dbx..ebl....rNbD.obbSmuabbe.....................pbF.dbx..ebl....rNbD.obbSmuabbe.....................pbF.dbx..ebl...", +"...OD.#IbbL.LnnL....................ebbp.mvOmmdKb#.....OD.#IbbL.LnnL....................ebbp.mvOmmdKb#.....OD.#IbbL.LnnL....................ebbp.mvOmmdKb#.....OD.#IbbL.LnnL....................ebbp.mvOmmdKb#.....OD.#IbbL.LnnL....................ebbp.mvOmmdKb#..", +"..jBk..nbbz.Qbbd....................pPobq.EbK#fhRh....jBk..nbbz.Qbbd....................pPobq.EbK#fhRh....jBk..nbbz.Qbbd....................pPobq.EbK#fhRh....jBk..nbbz.Qbbd....................pPobq.EbK#fhRh....jBk..nbbz.Qbbd....................pPobq.EbK#fhRh..", +".#abay.gOIxEBpvF...............hSn..GdyROy.xIbGg.....#abay.gOIxEBpvF...............hSn..GdyROy.xIbGg.....#abay.gOIxEBpvF...............hSn..GdyROy.xIbGg.....#abay.gOIxEBpvF...............hSn..GdyROy.xIbGg.....#abay.gOIxEBpvF...............hSn..GdyROy.xIbGg....", +".#IbbRF.EhqIq.................mOzfe.Nk.rbOqeDqy......#IbbRF.EhqIq.................mOzfe.Nk.rbOqeDqy......#IbbRF.EhqIq.................mOzfe.Nk.rbOqeDqy......#IbbRF.EhqIq.................mOzfe.Nk.rbOqeDqy......#IbbRF.EhqIq.................mOzfe.Nk.rbOqeDqy.....", +"..eEgKbNpGbbl...............m.hbjpH.MvmjbOOaF.........eEgKbNpGbbl...............m.hbjpH.MvmjbOOaF.........eEgKbNpGbbl...............m.hbjpH.MvmjbOOaF.........eEgKbNpGbbl...............m.hbjpH.MvmjbOOaF.........eEgKbNpGbbl...............m.hbjpH.MvmjbOOaF.......", +".....HbbqDBbt...........m.mpfMhbmpA.#cPdbi...............HbbqDBbt...........m.mpfMhbmpA.#cPdbi...............HbbqDBbt...........m.mpfMhbmpA.#cPdbi...............HbbqDBbt...........m.mpfMhbmpA.#cPdbi...............HbbqDBbt...........m.mpfMhbmpA.#cPdbi..........", +".....Hfw..Lti...........dkqGiOsIAfF..AfbM................Hfw..Lti...........dkqGiOsIAfF..AfbM................Hfw..Lti...........dkqGiOsIAfF..AfbM................Hfw..Lti...........dkqGiOsIAfF..AfbM................Hfw..Lti...........dkqGiOsIAfF..AfbM...........", +"......gj...nx...........hIKQ.Efkbv..Ecey..................gj...nx...........hIKQ.Efkbv..Ecey..................gj...nx...........hIKQ.Efkbv..Ecey..................gj...nx...........hIKQ.Efkbv..Ecey..................gj...nx...........hIKQ.Efkbv..Ecey............", +"...........m............mBbz..QoCbQQfH.........................m............mBbz..QoCbQQfH.........................m............mBbz..QoCbQQfH.........................m............mBbz..QoCbQQfH.........................m............mBbz..QoCbQQfH..............", +"....................mPIwFdbIm.EfjrpKh...................................mPIwFdbIm.EfjrpKh...................................mPIwFdbIm.EfjrpKh...................................mPIwFdbIm.EfjrpKh...................................mPIwFdbIm.EfjrpKh...............", +".................Eg.saCMfqvbr.mBd....................................Eg.saCMfqvbr.mBd....................................Eg.saCMfqvbr.mBd....................................Eg.saCMfqvbr.mBd....................................Eg.saCMfqvbr.mBd...................", +"................ebH.pn..ncdbw..Dy...................................ebH.pn..ncdbw..Dy...................................ebH.pn..ncdbw..Dy...................................ebH.pn..ncdbw..Dy...................................ebH.pn..ncdbw..Dy...................", +"........gekq....lcm.Kw..mGHNbL.........hD.l#................gekq....lcm.Kw..mGHNbL.........hD.l#................gekq....lcm.Kw..mGHNbL.........hD.l#................gekq....lcm.Kw..mGHNbL.........hD.l#................gekq....lcm.Kw..mGHNbL.........hD.l#........", +"........nbbx....Lfm.Ffd..ptmKL.........Lr.Co................nbbx....Lfm.Ffd..ptmKL.........Lr.Co................nbbx....Lfm.Ffd..ptmKL.........Lr.Co................nbbx....Lfm.Ffd..ptmKL.........Lr.Co................nbbx....Lfm.Ffd..ptmKL.........Lr.Co........", +".....F..SbbEmOD.gfe..rIpKfk...............hf#............F..SbbEmOD.gfe..rIpKfk...............hf#............F..SbbEmOD.gfe..rIpKfk...............hf#............F..SbbEmOD.gfe..rIpKfk...............hf#............F..SbbEmOD.gfe..rIpKfk...............hf#.......", +"...msbD.wbbj.tc#.PR..qoowHm................PPylg.......msbD.wbbj.tc#.PR..qoowHm................PPylg.......msbD.wbbj.tc#.PR..qoowHm................PPylg.......msbD.wbbj.tc#.PR..qoowHm................PPylg.......msbD.wbbj.tc#.PR..qoowHm................PPylg....", +"...rbbR.vbc..hfo.hcSLNl....................Lbfwj.......rbbR.vbc..hfo.hcSLNl....................Lbfwj.......rbbR.vbc..hfo.hcSLNl....................Lbfwj.......rbbR.vbc..hfo.hcSLNl....................Lbfwj.......rbbR.vbc..hfo.hcSLNl....................Lbfwj....", +"....Nbbqcbvm..MbELNzIM..............Kj......BBm.........Nbbqcbvm..MbELNzIM..............Kj......BBm.........Nbbqcbvm..MbELNzIM..............Kj......BBm.........Nbbqcbvm..MbELNzIM..............Kj......BBm.........Nbbqcbvm..MbELNzIM..............Kj......BBm.....", +".g..qJbObbbOAymwbaO.................vS......rfd......g..qJbObbbOAymwbaO.................vS......rfd......g..qJbObbbOAymwbaO.................vS......rfd......g..qJbObbbOAymwbaO.................vS......rfd......g..qJbObbbOAymwbaO.................vS......rfd.....", +".sbcpobbJbbbbICidCi.................HbF..ly..nI#.....sbcpobbJbbbbICidCi.................HbF..ly..nI#.....sbcpobbJbbbbICidCi.................HbF..ly..nI#.....sbcpobbJbbbbICidCi.................HbF..ly..nI#.....sbcpobbJbbbbICidCi.................HbF..ly..nI#....", +".zbbkjIbbdQbbbbvm...................jfp..zRg.mzp.....zbbkjIbbdQbbbbvm...................jfp..zRg.mzp.....zbbkjIbbdQbbbbvm...................jfp..zRg.mzp.....zbbkjIbbdQbbbbvm...................jfp..zRg.mzp.....zbbkjIbbdQbbbbvm...................jfp..zRg.mzp....", +".jCfL.kbbz.hSfGh....................mzbq.Dbs..hIK....jCfL.kbbz.hSfGh....................mzbq.Dbs..hIK....jCfL.kbbz.hSfGh....................mzbq.Dbs..hIK....jCfL.kbbz.hSfGh....................mzbq.Dbs..hIK....jCfL.kbbz.hSfGh....................mzbq.Dbs..hIK...", +"...vq.gGbbq.qMCl....................dffOm.tIjmoAbi.....vq.gGbbq.qMCl....................dffOm.tIjmoAbi.....vq.gGbbq.qMCl....................dffOm.tIjmoAbi.....vq.gGbbq.qMCl....................dffOm.tIjmoAbi.....vq.gGbbq.qMCl....................dffOm.tIjmoAbi..", +"..EIM..lbbv.Rbbl....................NMHbn.#cRxb#Mj....EIM..lbbv.Rbbl....................NMHbn.#cRxb#Mj....EIM..lbbv.Rbbl....................NMHbn.#cRxb#Mj....EIM..lbbv.Rbbl....................NMHbn.#cRxb#Mj....EIM..lbbv.Rbbl....................NMHbn.#cRxb#Mj..", +".iIbIL..zNiAvnKj...............qapm.GumoIL.Fvbwm.....iIbIL..zNiAvnKj...............qapm.GumoIL.Fvbwm.....iIbIL..zNiAvnKj...............qapm.GumoIL.Fvbwm.....iIbIL..zNiAvnKj...............qapm.GumoIL.Fvbwm.....iIbIL..zNiAvnKj...............qapm.GumoIL.Fvbwm....", +".gGIRBdgjiCbE.................gICBx.zM.EbfKsDy.......gGIRBdgjiCbE.................gICBx.zM.EbfKsDy.......gGIRBdgjiCbE.................gICBx.zM.EbfKsDy.......gGIRBdgjiCbE.................gICBx.zM.EbfKsDy.......gGIRBdgjiCbE.................gICBx.zM.EbfKsDy......", +"..jm.HbbIIbbA..............jEmibgwn.HBjjbwoKy.........jm.HbbIIbbA..............jEmibgwn.HBjjbwoKy.........jm.HbbIIbbA..............jEmibgwn.HBjjbwoKy.........jm.HbbIIbbA..............jEmibgwn.HBjjbwoKy.........jm.HbbIIbbA..............jEmibgwn.HBjjbwoKy.......", +".....kbIygRbt...........hyyBGRFbgRu.gvvoIy...............kbIygRbt...........hyyBGRFbgRu.gvvoIy...............kbIygRbt...........hyyBGRFbgRu.gvvoIy...............kbIygRbt...........hyyBGRFbgRu.gvvoIy...............kbIygRbt...........hyyBGRFbgRu.gvvoIy..........", +".....qzK..ykj...........uouvmptOPf#..kvvl................qzK..ykj...........uouvmptOPf#..kvvl................qzK..ykj...........uouvmptOPf#..kvvl................qzK..ykj...........uouvmptOPf#..kvvl................qzK..ykj...........uouvmptOPf#..kvvl...........", +"...........Aq...........ybtQ.#fHfvmmnIi........................Aq...........ybtQ.#fHfvmmnIi........................Aq...........ybtQ.#fHfvmmnIi........................Aq...........ybtQ.#fHfvmmnIi........................Aq...........ybtQ.#fHfvmmnIi.............", +".....................yLmmvbN..MplIBBaE...................................yLmmvbN..MplIBBaE...................................yLmmvbN..MplIBBaE...................................yLmmvbN..MplIBBaE...................................yLmmvbN..MplIBBaE.............."}; diff --git a/kiconedit/pics/toolbar/Makefile.am b/kiconedit/pics/toolbar/Makefile.am new file mode 100644 index 00000000..8e3cb6e2 --- /dev/null +++ b/kiconedit/pics/toolbar/Makefile.am @@ -0,0 +1,28 @@ +toolbar_DATA = fileclose.png \ + circle.png \ + filledcircle.png \ + line.png \ + paintbrush-cursor.xpm \ + airbrush-cursor.xpm \ + ellipse.png \ + filledellipse.png \ + rectangle.png \ + filledrectangle.png \ + areaselect.png \ + selectrect.png \ + selectcircle.png \ + fill-cursor.xpm \ + grid.png \ + pointer.png \ + aim.png \ + aim-cursor.xpm \ + window_new.png \ + grayscale.png \ + kdepalette.png \ + transform.png \ + eraser-cursor.xpm \ + colorpicker-cursor.xpm + + + +toolbardir = $(kde_datadir)/kiconedit/pics diff --git a/kiconedit/pics/toolbar/aim-cursor.xpm b/kiconedit/pics/toolbar/aim-cursor.xpm new file mode 100644 index 00000000..ecef295f --- /dev/null +++ b/kiconedit/pics/toolbar/aim-cursor.xpm @@ -0,0 +1,28 @@ +/* XPM */ +static char *aim[]={ +"22 22 3 1", +". c None", +"a c #000000", +"# c #ffffff", +"......................", +"..........#...........", +".........#a#..........", +".........#a#..........", +".........#a#..........", +".........#a#..........", +".........#a#..........", +".........#a#..........", +".........#a#..........", +"..#######...#######...", +".#aaaaaaa...aaaaaaa#..", +"..#######...#######...", +"..........a...........", +".........#a#..........", +".........#a#..........", +".........#a#..........", +".........#a#..........", +".........#a#..........", +".........#a#..........", +"..........#...........", +"......................", +"......................"}; diff --git a/kiconedit/pics/toolbar/aim.png b/kiconedit/pics/toolbar/aim.png new file mode 100644 index 00000000..ed0088a7 Binary files /dev/null and b/kiconedit/pics/toolbar/aim.png differ diff --git a/kiconedit/pics/toolbar/airbrush-cursor.xpm b/kiconedit/pics/toolbar/airbrush-cursor.xpm new file mode 100644 index 00000000..2fd8314d --- /dev/null +++ b/kiconedit/pics/toolbar/airbrush-cursor.xpm @@ -0,0 +1,35 @@ +/* XPM */ +static char *airbrush[]={ +"22 22 10 1", +". c None", +"a c #000000", +"d c #2a2a2a", +"g c #303030", +"c c #444444", +"h c #555555", +"f c #808080", +"b c #aaaaaa", +"e c #c8c8c8", +"# c #ffffff", +"..................#aa#", +".................#abca", +"................#abcca", +"...####........#abccda", +"..#aaaa#......#abccda#", +".#a####a#....#abccda#.", +".#a#eeba#...#abccda#..", +".#a#eeba#..#abccda#...", +".#a#eeba#.#abccda#....", +".#a#eeba##abccda#.....", +".#a#ebba#abccda#......", +".#a#bbbfaeccda#.......", +"..#a#bfgaebda#.#####..", +"..#a#bfaebffa##ddddd#.", +"...#afaebbfa##ddaaada#", +"..#a#eebbfadddda###da#", +".#a#eebbfa#aaaa#..#da#", +"#a#eebbfa#.####..#da#.", +"#aeebbfa#.......#da#..", +".#ebbfa#.......#da#...", +"dhfffa#.......#da#....", +"hd.aa#........#da#...."}; diff --git a/kiconedit/pics/toolbar/areaselect.png b/kiconedit/pics/toolbar/areaselect.png new file mode 100644 index 00000000..de3fe8fb Binary files /dev/null and b/kiconedit/pics/toolbar/areaselect.png differ diff --git a/kiconedit/pics/toolbar/circle.png b/kiconedit/pics/toolbar/circle.png new file mode 100644 index 00000000..ccb5c9db Binary files /dev/null and b/kiconedit/pics/toolbar/circle.png differ diff --git a/kiconedit/pics/toolbar/colorpicker-cursor.xpm b/kiconedit/pics/toolbar/colorpicker-cursor.xpm new file mode 100644 index 00000000..8edc155e --- /dev/null +++ b/kiconedit/pics/toolbar/colorpicker-cursor.xpm @@ -0,0 +1,36 @@ +/* XPM */ +static char *colorpicker[]={ +"22 22 11 1", +". c None", +"# c #000000", +"f c #151515", +"e c #2a2a2a", +"c c #333333", +"d c #3a3a3a", +"i c #808080", +"g c #aaaaaa", +"b c #d5d5d5", +"h c #dcdcdc", +"a c #ffffff", +"..................##a.", +".................#bc#a", +"................#bdcc#", +"...............#bddce#", +"..............#bddcef#", +"............##bddcef#a", +"...........#bdddcef#a.", +"............#becef#a..", +"...........#agbee#a...", +"..........#ahgibf#a...", +".........#ahgi#.#a....", +"........#ahgi#........", +".......#ahgi#.........", +"......#ahgi#..........", +".....#ahgi#...........", +"....#ahgi#............", +"...#ahgi#.............", +"..#ahgi#..............", +".#ahgi#...............", +".#hgi#................", +"#ig##.................", +"#i#..................."}; diff --git a/kiconedit/pics/toolbar/ellipse.png b/kiconedit/pics/toolbar/ellipse.png new file mode 100644 index 00000000..658b944d Binary files /dev/null and b/kiconedit/pics/toolbar/ellipse.png differ diff --git a/kiconedit/pics/toolbar/eraser-cursor.xpm b/kiconedit/pics/toolbar/eraser-cursor.xpm new file mode 100644 index 00000000..12c07f11 --- /dev/null +++ b/kiconedit/pics/toolbar/eraser-cursor.xpm @@ -0,0 +1,32 @@ +/* XPM */ +static char *eraser[]={ +"22 22 7 1", +"b c #000080", +"e c #800000", +"a c #8080ff", +"d c #c00000", +"# c #c0c0ff", +"c c #ffc0c0", +". c #ffffff", +"......................", +"...............#aa....", +"..............#aaaa...", +".............#aaaaaa..", +"............#aaaaaaaa.", +"...........#aaaaaaaaa.", +"..........#aaaaaaaaab.", +".........#aaaaaaaaab..", +"........#aaaaaaaaab...", +".......c##aaaaaaab....", +"......cdd##aaaaab.....", +".....cdddd##aaab......", +"....cdddddd##ab.......", +"...cdddddddd#b........", +"..cddddddddde.........", +".cddddddddde..........", +".ccddddddde...........", +".cccddddde............", +"..cccddde.............", +"...cccde..............", +"....cce...............", +"......................"}; diff --git a/kiconedit/pics/toolbar/fileclose.png b/kiconedit/pics/toolbar/fileclose.png new file mode 100644 index 00000000..906b2ec5 Binary files /dev/null and b/kiconedit/pics/toolbar/fileclose.png differ diff --git a/kiconedit/pics/toolbar/fill-cursor.xpm b/kiconedit/pics/toolbar/fill-cursor.xpm new file mode 100644 index 00000000..d5ca3034 --- /dev/null +++ b/kiconedit/pics/toolbar/fill-cursor.xpm @@ -0,0 +1,36 @@ +/* XPM */ +static char *fill[]={ +"22 22 11 1", +". c None", +"a c #000000", +"i c #222222", +"c c #2a2a2a", +"e c #333333", +"g c #3a3a3a", +"d c #404040", +"h c #555555", +"f c #aaaaaa", +"b c #d5d5d5", +"# c #ffffff", +"......................", +"............#.........", +"...........#a#........", +"..........#aba#.......", +".........#abcca#......", +"........#adceca#......", +".......#afdcecca#.....", +"......#abcedcecca#....", +".....#afcgeedeeca#....", +"...##fddcggeeeecca#...", +"..#fdccddcggeeeecca#..", +".#ddcdcdddcggeeeeca#..", +".#dccbdddddcggeeecca#.", +".#ddcddbbdddgggeeccba#", +".#ddhadddbddggggeebia#", +".#fda#adddbdddggebca#.", +".#fda##aaddbbddgbca#..", +".#fda#.##adddbdbca#...", +"..#da#...#aaddbca#....", +"..#fa#....##abca#.....", +"..#f#.......#aa#......", +"...#.........##......."}; diff --git a/kiconedit/pics/toolbar/filledcircle.png b/kiconedit/pics/toolbar/filledcircle.png new file mode 100644 index 00000000..1431fbe2 Binary files /dev/null and b/kiconedit/pics/toolbar/filledcircle.png differ diff --git a/kiconedit/pics/toolbar/filledellipse.png b/kiconedit/pics/toolbar/filledellipse.png new file mode 100644 index 00000000..3f1d6220 Binary files /dev/null and b/kiconedit/pics/toolbar/filledellipse.png differ diff --git a/kiconedit/pics/toolbar/filledrectangle.png b/kiconedit/pics/toolbar/filledrectangle.png new file mode 100644 index 00000000..1a011a63 Binary files /dev/null and b/kiconedit/pics/toolbar/filledrectangle.png differ diff --git a/kiconedit/pics/toolbar/flood-cursor.xpm b/kiconedit/pics/toolbar/flood-cursor.xpm new file mode 100644 index 00000000..8707443d --- /dev/null +++ b/kiconedit/pics/toolbar/flood-cursor.xpm @@ -0,0 +1,32 @@ +/* XPM */ +static char *flood[]={ +"22 22 7 1", +"b c #000000", +"c c #303030", +"# c #808080", +"e c #a0a0a4", +"a c #c0c0c0", +"d c #dcdcdc", +". c #ffffff", +"......................", +"......................", +"...........##.........", +"..........####........", +".........##aa##.......", +".........##ba##.......", +".........##.b##.......", +".......cc##..b#.......", +".....cccd##d..b.......", +"....cccdd#b.d..b......", +"...ccceddbdb.d..b.....", +"..eccceeddbdd.d..b....", +"..ecccceeddddd.d..b...", +"..ecccebeeddddd.d.b...", +"..eccceebeeddddd.b....", +"..eccc.eebeeddd.b.....", +"..eecc..eebeeddb......", +"...eec...eebeeb.......", +"....e.....eebb........", +"...........ee.........", +"......................", +"......................"}; diff --git a/kiconedit/pics/toolbar/flood.png b/kiconedit/pics/toolbar/flood.png new file mode 100644 index 00000000..45e1130b Binary files /dev/null and b/kiconedit/pics/toolbar/flood.png differ diff --git a/kiconedit/pics/toolbar/grayscale.png b/kiconedit/pics/toolbar/grayscale.png new file mode 100644 index 00000000..3b475550 Binary files /dev/null and b/kiconedit/pics/toolbar/grayscale.png differ diff --git a/kiconedit/pics/toolbar/grid.png b/kiconedit/pics/toolbar/grid.png new file mode 100644 index 00000000..acf1b687 Binary files /dev/null and b/kiconedit/pics/toolbar/grid.png differ diff --git a/kiconedit/pics/toolbar/kdepalette.png b/kiconedit/pics/toolbar/kdepalette.png new file mode 100644 index 00000000..705865a2 Binary files /dev/null and b/kiconedit/pics/toolbar/kdepalette.png differ diff --git a/kiconedit/pics/toolbar/line.png b/kiconedit/pics/toolbar/line.png new file mode 100644 index 00000000..25964286 Binary files /dev/null and b/kiconedit/pics/toolbar/line.png differ diff --git a/kiconedit/pics/toolbar/paintbrush-cursor.xpm b/kiconedit/pics/toolbar/paintbrush-cursor.xpm new file mode 100644 index 00000000..fa4a1e32 --- /dev/null +++ b/kiconedit/pics/toolbar/paintbrush-cursor.xpm @@ -0,0 +1,36 @@ +/* XPM */ +static char *paintbrush[]={ +"22 22 11 1", +". c None", +"a c #000000", +"d c #272727", +"i c #2c2c2c", +"h c #303030", +"c c #3b3b3b", +"g c #aaaaaa", +"e c #c8c8c8", +"b c #d5d5d5", +"f c #ececec", +"# c #ffffff", +".................#abcc", +"................#abccc", +"...............#abcccd", +"..............#abcccdd", +".............#abcccdda", +"............#abcccdda#", +"...........#abcccdda#.", +"..........#abcccdda#..", +"..........abcccdda#...", +".........##cccdda#....", +".........#eecdda#.....", +"......##f#eegda#......", +".....#aabeggga#.......", +"....#abbchgaa#........", +"...#abcccda##.........", +"...abcccdda#..........", +"..#abccddia#..........", +".#abccdiaa#...........", +"#abdddaa##............", +"aaaaaa##..............", +"######................", +"......................"}; diff --git a/kiconedit/pics/toolbar/paintbrush.png b/kiconedit/pics/toolbar/paintbrush.png new file mode 100644 index 00000000..53774e19 Binary files /dev/null and b/kiconedit/pics/toolbar/paintbrush.png differ diff --git a/kiconedit/pics/toolbar/pointer.png b/kiconedit/pics/toolbar/pointer.png new file mode 100644 index 00000000..62229be5 Binary files /dev/null and b/kiconedit/pics/toolbar/pointer.png differ diff --git a/kiconedit/pics/toolbar/rectangle.png b/kiconedit/pics/toolbar/rectangle.png new file mode 100644 index 00000000..7075cf10 Binary files /dev/null and b/kiconedit/pics/toolbar/rectangle.png differ diff --git a/kiconedit/pics/toolbar/selectcircle.png b/kiconedit/pics/toolbar/selectcircle.png new file mode 100644 index 00000000..91f528ec Binary files /dev/null and b/kiconedit/pics/toolbar/selectcircle.png differ diff --git a/kiconedit/pics/toolbar/selectrect.png b/kiconedit/pics/toolbar/selectrect.png new file mode 100644 index 00000000..0ce3aa21 Binary files /dev/null and b/kiconedit/pics/toolbar/selectrect.png differ diff --git a/kiconedit/pics/toolbar/spraycan-cursor.xpm b/kiconedit/pics/toolbar/spraycan-cursor.xpm new file mode 100644 index 00000000..13d84b80 --- /dev/null +++ b/kiconedit/pics/toolbar/spraycan-cursor.xpm @@ -0,0 +1,30 @@ +/* XPM */ +static char *spraycan[]={ +"22 22 5 1", +"# c #000000", +"c c #808080", +"b c #a0a0a4", +"a c #c0c0c0", +". c #ffffff", +"......................", +"......................", +"......................", +"......................", +"........##............", +"#.#..#..#a####........", +".........#a.#.#.......", +"......#..#b#a..#......", +".#.......##aaa..#.....", +"....#....#cbaaa..#....", +".........b#cbaaa..#...", +"..#...#..bc#cbaaa..#..", +"..........bc#cbaaa..#.", +".....#.....bc#cbaaa..#", +"............bc#cbaaa#.", +".............bc#cba#..", +"..............bc#c#...", +"...............bc#....", +"................b.....", +"......................", +"......................", +"......................"}; diff --git a/kiconedit/pics/toolbar/spraycan.png b/kiconedit/pics/toolbar/spraycan.png new file mode 100644 index 00000000..c2ce7e8d Binary files /dev/null and b/kiconedit/pics/toolbar/spraycan.png differ diff --git a/kiconedit/pics/toolbar/transform.png b/kiconedit/pics/toolbar/transform.png new file mode 100644 index 00000000..3a5ca2b3 Binary files /dev/null and b/kiconedit/pics/toolbar/transform.png differ diff --git a/kiconedit/pics/toolbar/window_new.png b/kiconedit/pics/toolbar/window_new.png new file mode 100644 index 00000000..4d0a40a0 Binary files /dev/null and b/kiconedit/pics/toolbar/window_new.png differ diff --git a/kiconedit/properties.cpp b/kiconedit/properties.cpp new file mode 100644 index 00000000..0f2c1f44 --- /dev/null +++ b/kiconedit/properties.cpp @@ -0,0 +1,147 @@ +/* + KDE Icon Editor - a small graphics drawing program for the KDE + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.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 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 +#include +#include + +#include "properties.h" + +KIconEditProperties* KIconEditProperties::m_self = 0; + +KIconEditProperties* KIconEditProperties::self() +{ + if (!m_self) + m_self = new KIconEditProperties(); + return m_self; +} + +KIconEditProperties::KIconEditProperties() : QObject() +{ + KConfig *config = kapp->config(); + + config->setGroup( "Appearance" ); + + m_bgMode = (QWidget::BackgroundMode)config->readNumEntry( "BackgroundMode", QWidget::FixedPixmap); + m_bgColor = config->readColorEntry( "BackgroundColor", &gray); + m_bgPixmap = config->readPathEntry("BackgroundPixmap"); + + config->setGroup( "Grid" ); + m_pasteTransparent = config->readBoolEntry( "PasteTransparent", false ); + m_showGrid = config->readBoolEntry( "ShowGrid", true ); + m_gridScale = config->readNumEntry( "GridScaling", 10 ); + m_showRulers = config->readBoolEntry( "ShowRulers", true ); + + if(config->readEntry( "TransparencyDisplayType", "Checkerboard" ) == "Checkerboard") + { + m_transparencyDisplayType = KIconEditGrid::TRD_CHECKERBOARD; + } + else + { + m_transparencyDisplayType = KIconEditGrid::TRD_SOLIDCOLOR; + } + + QColor checkColor1(255, 255, 255); + QColor checkColor2(127, 127, 127); + + m_checkerboardColor1 = config->readColorEntry( "CheckerboardColor1", &checkColor1); + m_checkerboardColor2 = config->readColorEntry( "CheckerboardColor2", &checkColor2); + + QString checkerboardSize = config->readEntry( "CheckerboardSize", "Medium" ); + + if(checkerboardSize == "Small") + { + m_checkerboardSize = KIconEditGrid::CHK_SMALL; + } + else + if(checkerboardSize == "Medium") + { + m_checkerboardSize = KIconEditGrid::CHK_MEDIUM; + } + else + { + m_checkerboardSize = KIconEditGrid::CHK_LARGE; + } + + QColor solidColor(255, 255, 255); + m_transparencySolidColor = config->readColorEntry( "TransparencySolidColor", &solidColor); +} + +KIconEditProperties::~KIconEditProperties() +{ + kdDebug(4640) << "KIconEditProperties: Deleting properties" << endl; + m_self = 0; +} + +void KIconEditProperties::save() +{ + KConfig *config = kapp->config(); + + config->setGroup( "Appearance" ); + + config->writeEntry("BackgroundMode", m_bgMode ); + config->writeEntry("BackgroundColor", m_bgColor ); + config->writePathEntry("BackgroundPixmap", m_bgPixmap ); + + config->setGroup( "Grid" ); + config->writeEntry("PasteTransparent", m_pasteTransparent ); + config->writeEntry("ShowGrid", m_showGrid ); + config->writeEntry("GridScaling", m_gridScale ); + config->writeEntry("ShowRulers", m_showRulers ); + + QString transparencyDisplayType; + + switch(m_transparencyDisplayType) + { + case KIconEditGrid::TRD_SOLIDCOLOR: + transparencyDisplayType = "SolidColor"; + break; + case KIconEditGrid::TRD_CHECKERBOARD: + default: + transparencyDisplayType = "Checkerboard"; + break; + } + + config->writeEntry( "TransparencyDisplayType", transparencyDisplayType ); + config->writeEntry( "CheckerboardColor1", m_checkerboardColor1 ); + config->writeEntry( "CheckerboardColor2", m_checkerboardColor2 ); + + QString checkerboardSize; + + switch(m_checkerboardSize) + { + case KIconEditGrid::CHK_SMALL: + checkerboardSize = "Small"; + break; + case KIconEditGrid::CHK_MEDIUM: + checkerboardSize = "Medium"; + break; + case KIconEditGrid::CHK_LARGE: + default: + checkerboardSize = "Large"; + break; + } + + config->writeEntry( "CheckerboardSize", checkerboardSize ); + config->writeEntry( "TransparencySolidColor", m_transparencySolidColor ); + + config->sync(); +} + diff --git a/kiconedit/properties.h b/kiconedit/properties.h new file mode 100644 index 00000000..e94f6d2c --- /dev/null +++ b/kiconedit/properties.h @@ -0,0 +1,82 @@ +/* + kiconedit - a small graphics drawing program the KDE. + + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.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 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 __PROPS_H__ +#define __PROPS_H__ + +#include + +#include "kicongrid.h" + +class KIconEditProperties : public QObject +{ +public: + static KIconEditProperties* self(); + ~KIconEditProperties(); + + QString bgPixmap() { return m_bgPixmap; } + QColor bgColor() { return m_bgColor; } + QWidget::BackgroundMode bgMode() { return m_bgMode; } + bool showGrid() { return m_showGrid; } + bool pasteTransparent() { return m_pasteTransparent; } + bool showRulers() { return m_showRulers; } + int gridScale() { return m_gridScale; } + + KIconEditGrid::TransparencyDisplayType transparencyDisplayType() const { return m_transparencyDisplayType; } + QColor checkerboardColor1() const { return m_checkerboardColor1; } + QColor checkerboardColor2() const { return m_checkerboardColor2; } + KIconEditGrid::CheckerboardSize checkerboardSize() const { return m_checkerboardSize; } + QColor transparencySolidColor() const { return m_transparencySolidColor; } + + void setBgPixmap( const QString &p ) { m_bgPixmap = p; } + void setBgColor( const QColor &c ) { m_bgColor = c; } + void setBgMode( QWidget::BackgroundMode m ) { m_bgMode = m; } + void setShowGrid( bool b ) { m_showGrid = b; } + void setPasteTransparent( bool b ) { m_pasteTransparent = b; } + void setShowRulers( bool b ) { m_showRulers = b; } + void setGridScale( int s ) { m_gridScale = s; } + void setTransparencyDisplayType(KIconEditGrid::TransparencyDisplayType t) { m_transparencyDisplayType = t; } + void setCheckerboardColor1(const QColor& c) { m_checkerboardColor1 = c; } + void setCheckerboardColor2(const QColor& c) { m_checkerboardColor2 = c; } + void setCheckerboardSize(KIconEditGrid::CheckerboardSize size) { m_checkerboardSize = size; } + void setTransparencySolidColor(const QColor& c) { m_transparencySolidColor = c; } + + void save(); + +protected: + KIconEditProperties(); + QString m_bgPixmap; + QColor m_bgColor; + QWidget::BackgroundMode m_bgMode; + bool m_showGrid; + bool m_pasteTransparent; + bool m_showRulers; + int m_gridScale; + KIconEditGrid::TransparencyDisplayType m_transparencyDisplayType; + QColor m_checkerboardColor1; + QColor m_checkerboardColor2; + KIconEditGrid::CheckerboardSize m_checkerboardSize; + QColor m_transparencySolidColor; + + static KIconEditProperties* m_self; +}; + +#endif //__PROPS_H__ diff --git a/kiconedit/utils.cpp b/kiconedit/utils.cpp new file mode 100644 index 00000000..1af52803 --- /dev/null +++ b/kiconedit/utils.cpp @@ -0,0 +1,134 @@ +/* + KDE Icon Editor - a small graphics drawing program for the KDE + + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.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 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 +#include +#include + +#include "utils.h" +#include "config.h" + +imageFormats *formats = 0L; + +void setupImageHandlers() +{ + if(formats != 0L) + return; + + KImageIO::registerFormats(); + + kdDebug(4640) << "Initializing formats" << endl; + formats = new imageFormats; + Q_CHECK_PTR(formats); + formats->setAutoDelete(true); + formats->append(new imageFormat("GIF", "GIF", "gif")); +#ifdef HAVE_LIBJPEG + formats->append(new imageFormat("JFIF", "JPEG", "jpg")); +#endif + formats->append(new imageFormat("XPM", "XPM", "xpm")); + formats->append(new imageFormat("ICO", "Windows Icon File", "ico")); +/* +#ifdef HAVE_LIBJPEG + QImageIO::defineIOHandler("JFIF","^\377\330\377\340", 0, read_jpeg_jfif, NULL); +#endif +*/ +} + +// Simple copy operation on local files (isn't there something like this in the libs?) +bool copyFile(const QString &src, const QString &dest) +{ + QFile f_src(src); + QFile f_dest(dest); + QFileInfo fi(f_src); + uint src_size = fi.size(); + kdDebug(4640) << "Size: " << src_size << endl; + + if ( f_src.open(IO_ReadOnly) ) + { // file opened successfully + if ( !f_dest.open(IO_WriteOnly) ) + { + kdDebug(4640) << "copyFile - There was an error opening destination file: " << dest << endl; + f_src.close(); + return false; + } + char *data = new char[src_size]; + if(f_src.readBlock(data, src_size) == -1) + { + kdDebug(4640) << "copyFile - There was an error reading source file: " << src << endl; + f_src.close(); + f_dest.close(); + delete [] data; + return false; + } + if(f_dest.writeBlock(data, src_size) == -1) + { + kdDebug(4640) << "copyFile - There was an error writing to destination file: " << dest << endl; + f_src.close(); + f_dest.close(); + delete [] data; + return false; + } + + f_src.close(); + f_dest.close(); + delete [] data; + return true; + } + kdDebug(4640) << "copyFile - There was an error opening source file: " << src << endl; + return false; +} + +bool removeFile(const QString &file) +{ + if(file.length() > 0 && QFile::exists(file)) + { + QDir d; + kdDebug(4640) << "Removing " << file << endl; + if(!d.remove(file)) + { + kdDebug(4640) << "removeFile - There was an error removing the file: " << file << endl; + return false; + } + return true; + } + return false; +} + +bool moveFile(const QString &src, const QString &dest) +{ + if(copyFile(src, dest)) + return removeFile(src); + return false; +} + +uint kdeColor(uint color) +{ + uint c = iconpalette[0]|OPAQUE_MASK; + + for(uint i = 0; i < 42; i++) + { + //kdDebug(4640) << "Color #" << i << " " << iconpalette[i] << endl; + if( (iconpalette[i]|OPAQUE_MASK) - c < (iconpalette[i]|OPAQUE_MASK) - color) + c = iconpalette[i]|OPAQUE_MASK; + } + //kdDebug(4640) << color << " -> " << c << endl; + return c; +} diff --git a/kiconedit/utils.h b/kiconedit/utils.h new file mode 100644 index 00000000..c1e1a4c0 --- /dev/null +++ b/kiconedit/utils.h @@ -0,0 +1,73 @@ +/* + kiconedit - a small graphics drawing program for the KDE + + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.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 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 __UTILS_H__ +#define __UTILS_H__ + +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif // HAVE_CONFIG_H + +#include +#include +#include +#include + +#define OPAQUE_MASK 0xff000000 + +#ifdef TRANSPARENT +#undef TRANSPARENT +#endif +#define TRANSPARENT 0x00000000 + +const uint iconpalette[42] = { // kde palette + 0x303030,0x585858,0x808080,0xa0a0a0,0xc3c3c3,0xdcdcdc, + 0x000040,0x004000,0x000000,0x004040,0x404000,0x000000, + 0x000080,0x008000,0x800000,0x008080,0x808000,0x800080, + 0x0000c0,0x00c000,0xc00000,0x00c0c0,0xc0c000,0xc000c0, + 0x0000ff,0x00ff00,0xff0000,0x00ffff,0xffff00,0xff00ff, + 0xc0c0ff,0xc0ffc0,0xffc0c0,0xc0ffff,0xffffc0,0xffc0ff, + 0x0080ff,0x0058c0,0x58a8ff,0xa8dcff,0xffffff,0x000000}; + +struct imageFormat +{ + imageFormat(const char *f, const char *t, const char *e) { format = f; title = t, extension = e;} + const char *format; + const char *title; + const char *extension; +}; + +typedef QPtrList imageFormats; +extern imageFormats *formats; + +void setupImageHandlers(); + +bool copyFile(const QString &src, const QString &dest); +bool removeFile(const QString &file); +bool moveFile(const QString &src, const QString &dest); +uint kdeColor(uint c); + +#endif //__UTILS_H__ + + + diff --git a/kiconedit/version.h b/kiconedit/version.h new file mode 100644 index 00000000..8f04bb6e --- /dev/null +++ b/kiconedit/version.h @@ -0,0 +1,36 @@ +/* + kiconedit - a small graphics drawing program for the KDE + + Copyright (C) 1998 Thomas Tanghus (tanghus@kde.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 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 __KIE_VERSION_H__ +#define __KIE_VERSION_H__ + +#define KIE_VERSION_MAJOR 0 +#define KIE_VERSION_MINOR 4 +#define KIE_VERSION_RELEASE 0 +#define KIE_VERSION ((KIE_VERSION_MAJOR * 100) + (KIE_VERSION_MINOR *10) + KIE_VERSION_RELEASE) +#define KIE_VERSION_STRING "0.4.0" + + + +#endif // __KIE_VERSION_H__ + + + diff --git a/kmrml/AUTHORS b/kmrml/AUTHORS new file mode 100644 index 00000000..9e0745fb --- /dev/null +++ b/kmrml/AUTHORS @@ -0,0 +1 @@ +Carsten Pfeiffer diff --git a/kmrml/ChangeLog b/kmrml/ChangeLog new file mode 100644 index 00000000..9dbd3ea3 --- /dev/null +++ b/kmrml/ChangeLog @@ -0,0 +1,28 @@ +Uh er, looks like I didn't add all the other changes lately :} Sorry... + +Sun May 6 04:40:52 2001 Carsten Pfeiffer + + * UI is a bit nicer now (arrangement of thumbnail items) + + * it's possible to search by example, i.e. by right-clicking + on one or more images and selecting "search for similar images" + + * tiny bit of code cleanup + +Sat May 5 02:30:21 2001 Carsten Pfeiffer + + * argh, fixed the bug that files couldn't get downloaded by + clicking on them and that the statusbar isn't updated. + casts suck :} That took me a lot of time to find out :( + + * added middle-button -> create new window + + * scroll to top when loading a new page + + * show standard popupmenu on right-click on image + + * schedule the slaves instead of creating all at once + +Sam Apr 28 00:09:17 CEST 2001 - Carsten Pfeiffer + o Initial Creation + didn't do any entries until something is actually working :) diff --git a/kmrml/Makefile.am b/kmrml/Makefile.am new file mode 100644 index 00000000..c48d9eb6 --- /dev/null +++ b/kmrml/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = kmrml diff --git a/kmrml/README b/kmrml/README new file mode 100644 index 00000000..59f2dd9b --- /dev/null +++ b/kmrml/README @@ -0,0 +1,95 @@ +kio_mrml and mrml_part + +Carsten Pfeiffer 2001/05/03 +---------------------------------------------------------------------- +These are the sources for an mrml kioslave and an accompanying KPart. + + +How does it work in Konqueror? +============================== +For now, the MrmlPart is rather a proof of concept, than a full blown +MRML client. + +You can start the MrmlPart by entering an appropriate URL into Konqueror, +e.g. mrml://user:pass@host.domain:port +user, pass and domain are optional, so if you're running a server locally +yourself, you can enter mrml://localhost to make Konqueror show the +MrmlPart. If you don't have a running GIFT-server, you can try out +mrml://viper.unige.ch:12790 as an example. Then, Konqueror will try to +connect the server at the given URL and show you a list of +image-collections the server has available. You can specify the number +of images a query should return and you can hit the Search-button +to actually start the query. If you don't give an image as example for +the query, it will return random images from the collection. + +Shortly after hitting the Search-button, you will see a list of images +as thumbnails. Below every image is a small rectangle showing the +similarity of the image with the example image(s). The longer the +rectangle, the better the match. + +Even easier than entering the mrml URL is right-clicking on an image +in Konqueror and selecting "Search for similar images..." in the context +menu. This will open up a new Konqueror window where the query will start +automatically. By default, this will try to contact a local server, i.e +mrml://localhost. You can configure different servers in the KControl +Module (System -> Advanced Search). The last chosen server will be used +for those queries. + +Note that a remote server surely can't access an image from your home +direcory though. I have to think a little bit about the usability of +this :) The greatest use of this is when you've indexed your files +and running an own GIFT server anyway. Ideally, the server could be +started on demand, when a query comes up. + + +MrmlPart: +========= + This KPart makes use of the mrml ioslave to provide a full MRML +client. MRML, Multimedia Retrieval Markup Language (see +http://www.mrml.net) is a means to query CBIR (Content Based Image +Retrieval) servers. An OpenSource server is the GIFT (GNU Image +Finding Tool), see www.mrml.net for downloading the GIFT. + +You can query for images by choosing one or more "example" images. +The server will search for images that have similarities to the +example(s) you gave. Queries can be refined by specifying relevance, +i.e. by including and excluding parts of the previous search result. + + +mrml ioslave: +============= + Basically this is not much more than a slave for asynchronous +transport of "data". With the URL, you can specify the user, password +and port, as well as the url of the server to connect to. + +The data exchange of client <-> slave is done via metaData, with an +"mrml_data" key. The data that the slave sends to the client is sent +in one big chunk, after all the data has arrived at the slave. This +could be made configurable later. + +With a little tuning, one could turn this into a generic slave +which can transport any kind of data. + +[mrmlsearch] +This little baby is called from Konqueror's popupmenu, when you hit +"Search for similar images...". This program simply gets the URLs +from Konqueror and creates a query of the form +mrml://host.com/?relevant=url1;url2;url3;url4.... +It will use the currently selected host in the KControl module +System -> Advanced Search to perform the query. + +mrmlsearch will then invoke "kfmclient openURL query" to start open +a new Konqueror window and perform the query. + + +Thanks go to Wolfgang Mller for his +work on the GIFT and for making me write this frontend :) I really +had a WOW-effect about the GIFT, when MrmlPart returned the first +query results. + +New versions of this package can be found at +http://devel-home.kde.org/~pfeiffer/kmrml/ +See http://www.mrml.net for downloading the GIFT and more information. + +Have fun, + Carsten Pfeiffer diff --git a/kmrml/README.DEVELOPMENT b/kmrml/README.DEVELOPMENT new file mode 100644 index 00000000..6fbe600d --- /dev/null +++ b/kmrml/README.DEVELOPMENT @@ -0,0 +1,41 @@ +This file gives an overview of the structure of the kmrml package. + +kmrml consists of the following: + +- kio_mrml: an ioslave that is able to contact an mrml daemon (i.e. the GIFT) + and transports the data from the daemon to its master (i.e. the + MrmlPart) as XML (MRML, Multimedia Retrieval Markup Language) + +- MrmlPart: the konqueror-embeddable controller and view + +- mrmlsearch: a small tool that is e.g. called from Konqueror's ContextMenu + "Search for similar images" to start an image query. + +- kcontrol/: a KDE Control Center module for configuring parts of the GIFT, + i.e. indexing directories, specifying GIFT hosts, etc. + +- server/: a kded module, i.e. a tiny little daemon, that can be told via + DCOP to start, restart upon failure and automatically/manually + stop services. It is completely independent of GIFT/kmrml. + It is used to have one centralized place where the gift server + is started (ensuring this happens only once, restarting it upon + failure and stopping the gift after all kio_mrml instances + have been killed. + +lib/: common stuff used by more than one module + + +Useful URLs: + +The MRML DTD: +http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/gift/gift/dtd/mrml.dtd?rev=HEAD&content-type=text/plain + +The GIFT Homepage: +http://www.gnu.org/software/gift + +The fer-de-lance project homepage, under which the GIFT and kmrml are living +http://www.fer-de-lance.org + + +2002/08/08 +Carsten Pfeiffer diff --git a/kmrml/TODO b/kmrml/TODO new file mode 100644 index 00000000..85a9aa7f --- /dev/null +++ b/kmrml/TODO @@ -0,0 +1,15 @@ +- Konqueror Properties dialog for indexing directory? Or just a context menu entry? +- make use of BrowserExtension, provide the actions +- contextmenu +- better layouting? +- better keyboard support +- progress report from slave +- transfer mrml in chunks as data arrives? +- finish algorithm configuration +- integrate with KPaint so you can paint an example image +- integrate with kamera, so that images from your digicam will be indexed automatically +- create Konq ContextMenu plugin instead of the ServiceMenu thing (mrmlsearch binary) +- proper browserextension (restorestate/savestate, history, implement actions) +- a panel applet or tray app KDirWatching indexable dirs and re-indexing on demand + +lots more probably diff --git a/kmrml/example-session.mrml b/kmrml/example-session.mrml new file mode 100644 index 00000000..27b5c009 --- /dev/null +++ b/kmrml/example-session.mrml @@ -0,0 +1,142 @@ + + + cui-block-texture-histogram="no" + collection-id="c-0-40-20-27-3-101-5-116-0" + cui-pr-percentage-of-features="70" + cui-block-texture-blocks="no" + cui-weighting-function="ClassicalIDF" + cui-base-type="inverted_file" + cui-block-color-histogram="no" + cui-block-color-blocks="no" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kmrml/kmrml.lsm b/kmrml/kmrml.lsm new file mode 100644 index 00000000..4b2dfeb6 --- /dev/null +++ b/kmrml/kmrml.lsm @@ -0,0 +1,27 @@ +Begin3 +Title: MRML for KDE -- Content based image retrieval +Version: 0.3.2 +Entered-date: 2001/06/05 +Description: MRML is short for Multimedia Retrieval Markup Language, + which defines a protocol for querying a server for images + based on their content. See http://www.mrml.net about MRML + and the GNU Image Finding Tool (GIFT), an MRML server. + + This package consists of an mrml kio-slave that handles + the communication with the MRML server and a KPart to + be embedded e.g. into Konqueror. + + With those, you can search for images by giving an example + image and let the server look up similar images. The query + result can be refined by giving positive/negative feedback. +Keywords: Image retrieval, GIFT, MRML, Konqueror, KDE, Qt +Author: Carsten Pfeiffer +Maintained-by: Carsten Pfeiffer +Home-page: http://devel-home.kde.org/~pfeiffer/kmrml/ +Alternate-site: ftp://ftp.kde.org/pub/kde/unstable/apps/utils +Primary-site: http://devel-home.kde.org/~pfeiffer/kmrml/ + xxxxxx kmrml-0.3.2.tgz + xxx kmrml-0.3.2.lsm +Platform: Unix. Needs KDE 3.x +Copying-policy: GPL +End diff --git a/kmrml/kmrml.spec b/kmrml/kmrml.spec new file mode 100644 index 00000000..79dbab29 --- /dev/null +++ b/kmrml/kmrml.spec @@ -0,0 +1,62 @@ +%define version 0.3 +%define release 1 +%define serial 1 +%define prefix /opt/kde3 + +Name: kmrml +Summary: MRML for KDE -- Content based image retrieval +Version: %{version} +Release: %{release} +Serial: %{serial} +Source: http://devel-home.kde.org/~pfeiffer/kmrml/kmrml-%{version}.tgz +URL: http://devel-home.kde.org/~pfeiffer/kmrml/ +Copyright: GPL +Packager: Carsten Pfeiffer +Group: X11/KDE/Utilities +BuildRoot: /tmp/kmrml-%{version}-root +Prefix: %{prefix} + +%description +MRML is short for Multimedia Retrieval Markup Language, +which defines a protocol for querying a server for images +based on their content. See http://www.mrml.net about MRML +and the GNU Image Finding Tool (GIFT), an MRML server. + +This package consists of an mrml kio-slave that handles +the communication with the MRML server and a KPart to +be embedded e.g. into Konqueror. + +With those, you can search for images by giving an example +image and let the server look up similar images. The query +result can be refined by giving positive/negative feedback. + +Install with '--prefix $KDEDIR' unless you have KDE in /opt/kde3 + +%prep +rm -rf $RPM_BUILD_ROOT + +%setup -n kmrml-%{version} + +%build +export KDEDIR=%{prefix} +CXXFLAGS="$RPM_OPT_FLAGS -fno-exceptions -malign-functions=2 -malign-jumps=2 -malign-loops=2 -pipe" LDFLAGS=-s ./configure --prefix=%{prefix} --enable-final --disable-debug +mkdir -p $RPM_BUILD_ROOT +make + +%install +make install DESTDIR=$RPM_BUILD_ROOT + +cd $RPM_BUILD_ROOT + +find . -type d | sed '1,2d;s,^\.,\%attr(-\,root\,root) \%dir ,' > $RPM_BUILD_DIR/file.list.%{name} + +find . -type f | sed 's,^\.,\%attr(-\,root\,root) ,' >> $RPM_BUILD_DIR/file.list.%{name} + +find . -type l | sed 's,^\.,\%attr(-\,root\,root) ,' >> $RPM_BUILD_DIR/file.list.%{name} + +%clean +rm -rf $RPM_BUILD_ROOT +rm -f $RPM_BUILD_DIR/file.list.%{name} + +%files -f ../file.list.%{name} + diff --git a/kmrml/kmrml/Makefile.am b/kmrml/kmrml/Makefile.am new file mode 100644 index 00000000..440e1123 --- /dev/null +++ b/kmrml/kmrml/Makefile.am @@ -0,0 +1,41 @@ +SUBDIRS = server lib kcontrol +INCLUDES= -I$(top_srcdir)/kmrml/kmrml/lib $(all_includes) +METASOURCES = AUTO + +LIB_KMRMLSTUFF = $(top_builddir)/kmrml/kmrml/lib/libkmrmlstuff.la + +####### Files + +kde_module_LTLIBRARIES = kio_mrml.la libkmrmlpart.la + +kio_mrml_la_SOURCES = mrml.cpp +kio_mrml_la_LIBADD = $(LIB_KMRMLSTUFF) $(LIB_KIO) +kio_mrml_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module + +libkmrmlpart_la_SOURCES = mrml_part.cpp mrml_view.cpp loader.cpp \ + mrml_elements.cpp mrml_creator.cpp browser.cpp algorithmdialog.cpp \ + collectioncombo.cpp algorithmcombo.cpp propertysheet.cpp +libkmrmlpart_la_LIBADD = $(LIB_KMRMLSTUFF) $(LIB_KPARTS) +libkmrmlpart_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) + +services_DATA = mrml.protocol mrml_part.desktop +servicesdir = $(kde_servicesdir) + +mimetypes_DATA = mrml.desktop +mimetypesdir = $(kde_mimedir)/text + +servicemenu_DATA = mrml-servicemenu.desktop +servicemenudir = $(kde_datadir)/konqueror/servicemenus + +############################################# +bin_PROGRAMS = +lib_LTLIBRARIES = +kdeinit_LTLIBRARIES = mrmlsearch.la + +mrmlsearch_la_LIBADD = $(LIB_KMRMLSTUFF) $(LIB_KDECORE) +mrmlsearch_la_LDFLAGS = $(all_libraries) -module -avoid-version +mrmlsearch_la_SOURCES = mrmlsearch.cpp + +messages: + $(EXTRACTRC) */*.ui > rc.cpp + $(XGETTEXT) *.h *.cpp */*.cpp */*.h -o $(podir)/kmrml.pot diff --git a/kmrml/kmrml/algorithmcombo.cpp b/kmrml/kmrml/algorithmcombo.cpp new file mode 100644 index 00000000..b22556df --- /dev/null +++ b/kmrml/kmrml/algorithmcombo.cpp @@ -0,0 +1,66 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "algorithmcombo.h" + +#include + +using namespace KMrml; + +// ### copycat of CollectionCombo... moc can't handle templates unfortunately.. +// could use base-class MrmlElement.... + +AlgorithmCombo::AlgorithmCombo( QWidget *parent, const char *name ) + : KComboBox( false, parent, name ), + m_algorithms( 0L ) +{ + connect( this, SIGNAL( activated( const QString& ) ), + SLOT( slotActivated( const QString& ) )); +} + +AlgorithmCombo::~AlgorithmCombo() +{ +} + +void AlgorithmCombo::setAlgorithms( const AlgorithmList *algorithms ) +{ + assert( algorithms != 0L ); + + clear(); + m_algorithms = algorithms; + insertStringList( algorithms->itemNames() ); + // #### block signals here? +} + +void AlgorithmCombo::setCurrent( const Algorithm& coll ) +{ + setCurrentItem( coll.name() ); +} + +Algorithm AlgorithmCombo::current() const +{ + return m_algorithms->findByName( currentText() ); +} + +void AlgorithmCombo::slotActivated( const QString& name ) +{ + Algorithm coll = m_algorithms->findByName( name ); + emit selected( coll ); +} + +#include "algorithmcombo.moc" diff --git a/kmrml/kmrml/algorithmcombo.h b/kmrml/kmrml/algorithmcombo.h new file mode 100644 index 00000000..3e151933 --- /dev/null +++ b/kmrml/kmrml/algorithmcombo.h @@ -0,0 +1,54 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef ALGORITHMCOMBO_H +#define ALGORITHMCOMBO_H + +#include + +#include "mrml_elements.h" + +namespace KMrml +{ + + class AlgorithmCombo : public KComboBox + { + Q_OBJECT + + public: + AlgorithmCombo( QWidget *parent, const char *name = 0 ); + ~AlgorithmCombo(); + + void setAlgorithms( const AlgorithmList * algorithms ); + void setCurrent( const Algorithm& coll ); + + Algorithm current() const; + + signals: + void selected( const Algorithm& ); + + private slots: + void slotActivated( const QString& ); + + private: + const AlgorithmList *m_algorithms; + }; + +} + +#endif // ALGORITHMCOMBO_H diff --git a/kmrml/kmrml/algorithmdialog.cpp b/kmrml/kmrml/algorithmdialog.cpp new file mode 100644 index 00000000..cb62fd84 --- /dev/null +++ b/kmrml/kmrml/algorithmdialog.cpp @@ -0,0 +1,132 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "algorithmdialog.h" +#include "algorithmcombo.h" +#include "collectioncombo.h" + +#include +#include +#include +#include +#include +#include + +#include + +using namespace KMrml; + +class ScrollView : public QScrollView +{ +public: + ScrollView(QWidget* parent = 0, const char* name = 0) + : QScrollView(parent, name) + { + setFrameStyle(QFrame::NoFrame); + m_frame = new QFrame(viewport(), "ScrollView::m_frame"); + m_frame->setFrameStyle(QFrame::NoFrame); + addChild(m_frame, 0, 0); + }; + + QFrame* frame() {return m_frame;}; + +protected: + virtual void viewportResizeEvent(QResizeEvent* ev) + { + QScrollView::viewportResizeEvent(ev); + m_frame->resize( kMax(m_frame->sizeHint().width(), ev->size().width()), + kMax(m_frame->sizeHint().height(), ev->size().height())); + }; + +private: + QFrame* m_frame; +}; + +AlgorithmDialog::AlgorithmDialog( const AlgorithmList& algorithms, + const CollectionList& collections, + const Collection& currentColl, + QWidget *parent, const char *name ) + : KDialogBase( parent, name, false, i18n("Configure Query Algorithms"), + Ok | Cancel, Ok, false ), + m_allAlgorithms( algorithms ), + m_collections( collections ) +{ + QWidget *box = makeMainWidget(); + + QVBoxLayout *mainLayout = new QVBoxLayout( box, 0, KDialog::spacingHint(), + "mainLayout"); + + QHBoxLayout *collectionLayout = new QHBoxLayout( 0L, 0, 0, "coll layout"); + collectionLayout->addWidget( new QLabel( i18n("Collection: "), box )); + + m_collectionCombo = new CollectionCombo( box, "collection combo" ); + m_collectionCombo->setCollections( &m_collections ); + collectionLayout->addWidget( m_collectionCombo ); + + mainLayout->addLayout( collectionLayout ); + mainLayout->addSpacing( 14 ); + + QHBox *algoHLayout = new QHBox( box ); + (void) new QLabel( i18n("Algorithm: "), algoHLayout); + m_algoCombo = new AlgorithmCombo( algoHLayout, "algo combo" ); + + QVGroupBox *groupBox = new QVGroupBox( box, "groupBox" ); + mainLayout->addWidget( groupBox ); + algoHLayout->raise(); + + ScrollView *scrollView = new ScrollView( groupBox, "scroll view" ); + m_view = scrollView->frame(); + QVBoxLayout *viewLayout = new QVBoxLayout( scrollView ); + viewLayout->setSpacing( KDialog::spacingHint() ); + + + collectionChanged( currentColl ); + + connect( m_algoCombo, SIGNAL( selected( const Algorithm& ) ), + SLOT( initGUI( const Algorithm& ) )); + connect( m_collectionCombo, SIGNAL( selected( const Collection& ) ), + SLOT( collectionChanged( const Collection& ) )); + + algoHLayout->adjustSize(); + mainLayout->activate(); + algoHLayout->move( groupBox->x() + 10, groupBox->y() - 12 ); + + box->setMinimumWidth( algoHLayout->sizeHint().width() + + 4 * KDialog::spacingHint() ); +} + +AlgorithmDialog::~AlgorithmDialog() +{ +} + +void AlgorithmDialog::collectionChanged( const Collection& coll ) +{ + m_algosForCollection = m_allAlgorithms.algorithmsForCollection( coll ); + m_algoCombo->setAlgorithms( &m_algosForCollection ); + + initGUI( m_algoCombo->current() ); +} + +void AlgorithmDialog::initGUI( const Algorithm& algo ) +{ + m_algo = algo; + + +} + +#include "algorithmdialog.moc" diff --git a/kmrml/kmrml/algorithmdialog.h b/kmrml/kmrml/algorithmdialog.h new file mode 100644 index 00000000..740a95bf --- /dev/null +++ b/kmrml/kmrml/algorithmdialog.h @@ -0,0 +1,60 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef ALGORITHMDIALOG_H +#define ALGORITHMDIALOG_H + +#include + +#include "mrml_elements.h" + +namespace KMrml +{ + class AlgorithmCombo; + class CollectionCombo; + + class AlgorithmDialog : public KDialogBase + { + Q_OBJECT + + public: + AlgorithmDialog( const AlgorithmList&, const CollectionList&, + const Collection& currentColl, + QWidget *parent = 0, const char *name = 0 ); + ~AlgorithmDialog(); + + private slots: + void collectionChanged( const Collection& ); + void initGUI( const Algorithm& algo ); + + private: + Algorithm m_algo; + AlgorithmList m_allAlgorithms; + AlgorithmList m_algosForCollection; + CollectionList m_collections; + + CollectionCombo *m_collectionCombo; + AlgorithmCombo *m_algoCombo; + + QFrame *m_view; + }; + +} + +#endif // ALGORITHMDIALOG_H diff --git a/kmrml/kmrml/browser.cpp b/kmrml/kmrml/browser.cpp new file mode 100644 index 00000000..f2453243 --- /dev/null +++ b/kmrml/kmrml/browser.cpp @@ -0,0 +1,63 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "browser.h" +#include "mrml_part.h" + +#include + +using namespace KMrml; + +Browser::Browser( MrmlPart *parent, const char *name ) + : KParts::BrowserExtension( parent, name ), + m_part( parent ) +{ + +} + +Browser::~Browser() +{ + +} + +void Browser::saveState( QDataStream& stream ) +{ +// BrowserExtension::saveState( stream ); + + m_part->saveState( stream ); +} + +void Browser::restoreState( QDataStream& stream ) +{ +// BrowserExtension::restoreState( stream ); + // ### BrowserExtension::restoreState() calls openURL() at the end (arghh). + + m_part->restoreState( stream ); +} + +int Browser::xOffset() +{ + return static_cast( m_part->widget())->contentsX(); +} + +int Browser::yOffset() +{ + return static_cast( m_part->widget())->contentsY(); +} + +#include "browser.moc" diff --git a/kmrml/kmrml/browser.h b/kmrml/kmrml/browser.h new file mode 100644 index 00000000..11661ed5 --- /dev/null +++ b/kmrml/kmrml/browser.h @@ -0,0 +1,48 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef BROWSER_H +#define BROWSER_H + +#include + +namespace KMrml +{ + class MrmlPart; + + class Browser : public KParts::BrowserExtension + { + Q_OBJECT + + public: + Browser( MrmlPart *parent, const char *name ); + ~Browser(); + + virtual void saveState( QDataStream& stream ); + virtual void restoreState( QDataStream& stream ); + + virtual int xOffset(); + virtual int yOffset(); + + private: + MrmlPart *m_part; + }; + +} + +#endif // BROWSER_H diff --git a/kmrml/kmrml/collectioncombo.cpp b/kmrml/kmrml/collectioncombo.cpp new file mode 100644 index 00000000..b45d7ebf --- /dev/null +++ b/kmrml/kmrml/collectioncombo.cpp @@ -0,0 +1,95 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "collectioncombo.h" + +#include + +using namespace KMrml; + +CollectionCombo::CollectionCombo( QWidget *parent, const char *name ) + : KComboBox( false, parent, name ), + m_collections( 0L ) +{ + connect( this, SIGNAL( activated( const QString& ) ), + SLOT( slotActivated( const QString& ) )); +} + +CollectionCombo::~CollectionCombo() +{ +} + +void CollectionCombo::setCollections( const CollectionList *collections ) +{ + assert( collections != 0L ); + + clear(); + m_collections = collections; + insertStringList( collections->itemNames() ); + // #### block signals here? +} + +void CollectionCombo::setCurrent( const Collection& coll ) +{ + setCurrentItem( coll.name() ); +} + +Collection CollectionCombo::current() const +{ + return m_collections->findByName( currentText() ); +} + +void CollectionCombo::slotActivated( const QString& name ) +{ + Collection coll = m_collections->findByName( name ); + emit selected( coll ); +} + +QDataStream& KMrml::operator<<( QDataStream& stream, + const CollectionCombo& combo ) +{ + int count = combo.count(); + stream << count; + for ( int i = 0; i < count; i++ ) + stream << combo.text( i ); + + stream << combo.currentItem(); + return stream; +} + +QDataStream& KMrml::operator>>( QDataStream& stream, CollectionCombo& combo ) +{ + combo.clear(); + + int count; + stream >> count; + QString text; + for ( int i = 0; i < count; i++ ) + { + stream >> text; + combo.insertItem( text ); + } + + int current; + stream >> current; + combo.setCurrentItem( current ); + + return stream; +} + +#include "collectioncombo.moc" diff --git a/kmrml/kmrml/collectioncombo.h b/kmrml/kmrml/collectioncombo.h new file mode 100644 index 00000000..3ca67a64 --- /dev/null +++ b/kmrml/kmrml/collectioncombo.h @@ -0,0 +1,57 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef COLLECTIONCOMBO_H +#define COLLECTIONCOMBO_H + +#include + +#include "mrml_elements.h" + +namespace KMrml +{ + + class CollectionCombo : public KComboBox + { + Q_OBJECT + + public: + CollectionCombo( QWidget *parent, const char *name = 0 ); + ~CollectionCombo(); + + void setCollections( const CollectionList * collections ); + void setCurrent( const Collection& coll ); + + Collection current() const; + + signals: + void selected( const Collection& ); + + private slots: + void slotActivated( const QString& ); + + private: + const CollectionList *m_collections; + }; + + QDataStream& operator<<( QDataStream& stream, const CollectionCombo& ); + QDataStream& operator>>( QDataStream& stream, CollectionCombo& ); + +} + +#endif // COLLECTIONCOMBO_H diff --git a/kmrml/kmrml/kcontrol/Makefile.am b/kmrml/kmrml/kcontrol/Makefile.am new file mode 100644 index 00000000..c1330cfd --- /dev/null +++ b/kmrml/kmrml/kcontrol/Makefile.am @@ -0,0 +1,25 @@ +LIB_KMRMLSTUFF = $(top_builddir)/kmrml/kmrml/lib/libkmrmlstuff.la + +kde_module_LTLIBRARIES = kcm_kmrml.la + +kcm_kmrml_la_SOURCES = kcmkmrml.cpp mainpage.cpp indexer.cpp serverconfigwidget.ui indexcleaner.cpp +kcm_kmrml_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined +kcm_kmrml_la_LIBADD = $(LIB_KMRMLSTUFF) $(LIB_KIO) +INCLUDES= -I$(top_srcdir)/kmrml/kmrml/lib $(all_includes) + +kcm_kmrml_la_METASOURCES = AUTO + +noinst_HEADERS = kcmkmrml.h mainpage.h serverconfigwidget.h indexer.h indexcleaner.h + +xdg_apps_DATA = kcmkmrml.desktop + +#check_PROGRAMS = indextest +#indextest_SOURCES = indextest.cpp indexer.cpp +#indextest_LDADD = $(LIB_KMRMLSTUFF) $(LIB_KDECORE) +#indextest_LDFLAGS = $(all_libraries) + + + +#pics_DATA = play.png +#picsdir = $(kde_datadir)/kcontrol/pics + diff --git a/kmrml/kmrml/kcontrol/indexcleaner.cpp b/kmrml/kmrml/kcontrol/indexcleaner.cpp new file mode 100644 index 00000000..5f5eea93 --- /dev/null +++ b/kmrml/kmrml/kcontrol/indexcleaner.cpp @@ -0,0 +1,96 @@ +#include +#include + +#include +#include "indexcleaner.h" + +#include +#if KDE_VERSION < 306 + #define QUOTE( x ) x +#else + #define QUOTE( x ) KProcess::quote( x ) +#endif + +using namespace KMrmlConfig; + +IndexCleaner::IndexCleaner( const QStringList& dirs, + const KMrml::Config *config, + QObject *parent, const char *name ) + : QObject( parent, name ), + m_dirs( dirs ), + m_config( config ), + m_process( 0L ) +{ + m_stepSize = 100 / dirs.count(); +} + +IndexCleaner::~IndexCleaner() +{ + if ( m_process ) + { + m_process->kill(); + delete m_process; + m_process = 0L; + } +} + +void IndexCleaner::start() +{ + startNext(); +} + +void IndexCleaner::slotExited( KProcess *proc ) +{ + emit advance( m_stepSize ); + + if ( !proc->normalExit() ) + kdWarning() << "Error removing old indexed directory" << endl; + + m_process = 0L; + + startNext(); +} + +void IndexCleaner::startNext() +{ + if ( m_dirs.isEmpty() ) + { + emit advance( 100 ); + emit finished(); + return; + } + +#if KDE_VERSION < 306 + m_process = new KShellProcess(); +#else + m_process = new KProcess(); + m_process->setUseShell( true ); +#endif + connect( m_process, SIGNAL( processExited( KProcess * )), + SLOT( slotExited( KProcess * ) )); + + QString cmd = m_config->removeCollectionCommandLine(); + + QString dir = m_dirs.first(); + m_dirs.pop_front(); + + int index = cmd.find( "%d" ); + if ( index != -1 ) + cmd.replace( index, 2, QUOTE( dir ) ); + else // no %d? What else can we do? + cmd.append( QString::fromLatin1(" ") + QUOTE( dir ) ); + + *m_process << cmd; + + if ( !m_process->start() ) + { + kdWarning() << "Error starting: " << cmd << endl; + + delete m_process; + m_process = 0L; + + startNext(); + } +} + +#include "indexcleaner.moc" diff --git a/kmrml/kmrml/kcontrol/indexcleaner.h b/kmrml/kmrml/kcontrol/indexcleaner.h new file mode 100644 index 00000000..0ddcaac4 --- /dev/null +++ b/kmrml/kmrml/kcontrol/indexcleaner.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** $Id$ +** +** Copyright (C) 2002 Carsten Pfeiffer +** +****************************************************************************/ + +#ifndef INDEXCLEANER_H +#define INDEXCLEANER_H + +#include +#include + +class KProcess; + +namespace KMrml +{ + class Config; +} + +namespace KMrmlConfig +{ + class IndexCleaner : public QObject + { + Q_OBJECT + + public: + IndexCleaner( const QStringList& dirs, const KMrml::Config *config, + QObject *parent = 0, const char *name = 0 ); + ~IndexCleaner(); + + void start(); + + signals: + void advance( int value ); + void finished(); + + private slots: + void slotExited( KProcess * ); + + private: + int m_stepSize; + void startNext(); + + QStringList m_dirs; + const KMrml::Config *m_config; + KProcess *m_process; + }; + +} + + +#endif // INDEXCLEANER_H diff --git a/kmrml/kmrml/kcontrol/indexer.cpp b/kmrml/kmrml/kcontrol/indexer.cpp new file mode 100644 index 00000000..a3bb6b7d --- /dev/null +++ b/kmrml/kmrml/kcontrol/indexer.cpp @@ -0,0 +1,190 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include + +#include +#include +#include +#include + +#include "indexer.h" + +#include +#if KDE_VERSION < 306 + #define QUOTE( x ) x +#else + #define QUOTE( x ) KProcess::quote( x ) +#endif + +using namespace KMrmlConfig; + +Indexer::Indexer( const KMrml::Config* config, + QObject *parent, const char *name ) + : QObject( parent, name ), + m_config( config ), + m_dirCount( 0 ) +{ + m_process = new KProcIO(); +#if KDE_VERSION >= 306 + m_process->setUseShell( true ); +#endif + m_process->setEnvironment( "LC_ALL", "C" ); + connect( m_process, SIGNAL( processExited( KProcess * )), + SLOT( processFinished( KProcess * ))); + connect( m_process, SIGNAL( readReady( KProcIO * )), + SLOT( slotCanRead( KProcIO * )) ); +} + +Indexer::~Indexer() +{ + delete m_process; +} + +void Indexer::startIndexing( const QStringList& dirs ) +{ + if ( m_process->isRunning() ) + return; + + m_dirs = dirs; + m_dirCount = dirs.count(); + processNext(); +} + +void Indexer::processFinished( KProcess *proc ) +{ + // still more directories to index? + if ( !m_dirs.isEmpty() ) + processNext(); + else + { + if ( proc->normalExit() ) + emit finished( proc->exitStatus() ); + else + emit finished( -1000 ); + } +} + + +void Indexer::processNext() +{ + m_currentDir = m_dirs.first(); + m_dirs.pop_front(); + while ( m_currentDir.endsWith( "/" ) ) + m_currentDir.remove( m_currentDir.length() -1, 1 ); + + m_process->resetAll(); + + QString cmd = m_config->addCollectionCommandLine().simplifyWhiteSpace().stripWhiteSpace(); + + // in the commandline, replace %d with the directory to process and + // %t with the thumbnail dir + int index = cmd.find( "%d" ); // ### QFile::encodeName()? + if ( index != -1 ) + cmd.replace( index, 2, QUOTE( m_currentDir ) ); + index = cmd.find( "%t" ); + if ( index != -1 ) + cmd.replace( index, 2, QUOTE(m_currentDir + "_thumbnails") ); + +// qDebug("****** command: %s", cmd.latin1()); +#if KDE_VERSION >= 306 + *m_process << cmd; +#else + QStringList params = QStringList::split( ' ', cmd ); + QStringList::Iterator it = params.begin(); + for ( ; it != params.end(); ++it ) + *m_process << *it; +#endif + + emit progress( 0, i18n("Next Folder:
%1").arg( m_currentDir )); + m_process->start(); +} + +void Indexer::slotCanRead( KProcIO *proc ) +{ + static const QString& sprogress = KGlobal::staticQString("PROGRESS: "); + static const QString& r1 = /* PROGRESS: 1 of 6 done (15%) */ + KGlobal::staticQString( "(\\d+) of (\\d+) done \\((\\d+)%\\)" ); + + QString line; + int bytes = -1; + while ( (bytes = proc->readln( line )) != -1 ) + { + // examine the output. + // We're looking for lines like: + // PROGRESS: 1 of 6 done (15%) + // PROGRESS: 99% + // PROGRESS: 100% + + if ( !line.startsWith( sprogress ) ) // uninteresting debug output + continue; + else // parse output + { + // cut off "PROGRESS: " + line = line.mid( sprogress.length() ); + line = line.simplifyWhiteSpace().stripWhiteSpace(); +// qDebug("*** START LINE ***"); +// qDebug("%s", line.latin1()); +// qDebug("*** END LINE ***"); + + // case 1: image processing, below 99% + if ( line.at( line.length() -1 ) == ')' ) + { + QRegExp regxp( r1 ); + int pos = regxp.search( line ); + if ( pos > -1 ) + { + QString currentFile = regxp.cap( 1 ); + QString numFiles = regxp.cap( 2 ); + QString percent = regxp.cap( 3 ); + +// qDebug( "current: %s, number: %s, percent: %s", currentFile.latin1(), numFiles.latin1(), percent.latin1()); + bool ok = false; + int perc = percent.toInt( &ok ); + if ( ok ) + { + uint dirsLeft = m_dirs.count(); + QString message = i18n( "Processing folder %1 of %2:
%3
File %4 of %5.
").arg( m_dirCount - dirsLeft ).arg( m_dirCount).arg( m_currentDir ).arg( currentFile ).arg( numFiles ); + emit progress( perc, message ); + } + } + } + + + // case 2: file writing, 99% or done, 100% + else + { + QString percent = line.left( line.length() - 1 ); + + bool ok = false; + int number = percent.toInt( &ok ); + if ( ok ) + { + QString message = (number == 100) ? + i18n("Finished.") : i18n("Writing data..."); + emit progress( number, message ); + } + else + kdDebug() << "Error while parsing gift-add-collection.pl output" << endl; + } + } + } +} + +#include "indexer.moc" diff --git a/kmrml/kmrml/kcontrol/indexer.h b/kmrml/kmrml/kcontrol/indexer.h new file mode 100644 index 00000000..97335a70 --- /dev/null +++ b/kmrml/kmrml/kcontrol/indexer.h @@ -0,0 +1,68 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef INDEXER_H +#define INDEXER_H + +#include + +#include + +class KProcess; +class KProcIO; + +namespace KMrmlConfig +{ + class Indexer : public QObject + { + Q_OBJECT + + public: + Indexer( const KMrml::Config *config, + QObject *parent = 0L, const char *name = 0 ); + ~Indexer(); + + void startIndexing( const QStringList& dirs ); + void stop(); + + signals: + void progress( int percent, const QString& text ); + void finished( int returnCode ); + + + private slots: + void slotCanRead( KProcIO * ); + void processFinished( KProcess * ); + + private: + void processNext(); + + KProcIO *m_process; + const KMrml::Config *m_config; + + uint m_dirCount; + QStringList m_dirs; + QString m_currentDir; + + }; + + +} + + +#endif // INDEXER_H diff --git a/kmrml/kmrml/kcontrol/indextest.cpp b/kmrml/kmrml/kcontrol/indextest.cpp new file mode 100644 index 00000000..161ca798 --- /dev/null +++ b/kmrml/kmrml/kcontrol/indextest.cpp @@ -0,0 +1,43 @@ +#include "indexer.h" +#include +#include "indextest.moc" + +#include +#include +#include + +using namespace KMrmlConfig; + +IndexTest::IndexTest() +{ + KMrml::Config *config = new KMrml::Config( KGlobal::config() ); + Indexer *indexer = new Indexer( *config, this ); + connect( indexer, SIGNAL( finished( bool )), SLOT( slotFinished( bool ))); + connect( indexer, SIGNAL( progress( int, const QString& )), + SLOT( slotProgress( int, const QString& ))); + + indexer->startIndexing( "/home/gis/testcoll" ); +} + +IndexTest::~IndexTest() +{ + +} + +void IndexTest::slotFinished( bool success ) +{ + qDebug("##### FINISHED: %i", success ); +} + +void IndexTest::slotProgress( int percent, const QString& message ) +{ + qDebug("--- progress: %i: %s", percent, message.latin1()); +} + +int main( int argc, char **argv ) +{ + KApplication app( argc, argv, "indextest" ); + IndexTest *test = new IndexTest(); + + return app.exec(); +} diff --git a/kmrml/kmrml/kcontrol/indextest.h b/kmrml/kmrml/kcontrol/indextest.h new file mode 100644 index 00000000..5f85f5f1 --- /dev/null +++ b/kmrml/kmrml/kcontrol/indextest.h @@ -0,0 +1,26 @@ +/**************************************************************************** +** $Id$ +** +** Copyright (C) 2002 Carsten Pfeiffer +** +****************************************************************************/ + +#ifndef INDEXTEST_H +#define INDEXTEST_H + +class IndexTest : public QObject +{ + Q_OBJECT + +public: + IndexTest(); + ~IndexTest(); + +private slots: + void slotFinished( bool success ); + void slotProgress( int percent, const QString& message ); + +}; + + +#endif // INDEXTEST_H diff --git a/kmrml/kmrml/kcontrol/kcmkmrml.cpp b/kmrml/kmrml/kcontrol/kcmkmrml.cpp new file mode 100644 index 00000000..43e46b03 --- /dev/null +++ b/kmrml/kmrml/kcontrol/kcmkmrml.cpp @@ -0,0 +1,146 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kcmkmrml.h" +#include + +#include "mainpage.h" +#include + +using namespace KMrmlConfig; + +static const int COL_FILENAME = 1; + +typedef KGenericFactory MrmlFactory; +K_EXPORT_COMPONENT_FACTORY( kcm_kmrml, MrmlFactory("kmrml") ) + +KCMKMrml::KCMKMrml(QWidget *parent, const char *name, const QStringList & ): + KCModule(MrmlFactory::instance(), parent, name) +{ + KAboutData* ab = new KAboutData( + "kcmkmrml", + I18N_NOOP("KCMKMrml"), + KMRML_VERSION, + I18N_NOOP("Advanced Search Control Module"), + KAboutData::License_GPL, + I18N_NOOP( "Copyright 2002, Carsten Pfeiffer" ), + 0, + "http://devel-home.kde.org/~pfeiffer/kmrml/" ); + ab->addAuthor( "Carsten Pfeiffer", 0, "pfeiffer@kde.org" ); + setAboutData( ab ); + + QVBoxLayout *layout = new QVBoxLayout( this ); + layout->setSpacing( KDialog::spacingHint() ); + m_mainPage = new MainPage( this, "main page" ); + + layout->addWidget( m_mainPage ); + + connect( m_mainPage, SIGNAL( changed( bool ) ), SIGNAL( changed( bool ))); + + checkGiftInstallation(); +} + +KCMKMrml::~KCMKMrml() +{ +} + +void KCMKMrml::checkGiftInstallation() +{ + QString giftExe = KGlobal::dirs()->findExe( "gift" ); + QString giftAddCollectionExe = KGlobal::dirs()->findExe( "gift-add-collection.pl" ); + + if ( giftExe.isEmpty() || giftAddCollectionExe.isEmpty() ) + { + QString errorMessage = + i18n("Cannot find executables \"gift\" and/or \"gift-add-collection.pl\" in the PATH.\n" + "Please install the \"GNU Image Finding Tool\"."); + KMessageBox::error( this, errorMessage ); + m_mainPage->hide(); + QLabel *errorLabel = new QLabel( errorMessage, this ); + errorLabel->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) ); + KURLLabel *urlLabel = new KURLLabel( "http://www.gnu.org/software/gift", QString::null, this ); + urlLabel->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); + connect( urlLabel, SIGNAL( leftClickedURL( const QString& )), kapp, SLOT( invokeBrowser( const QString& )) ); + QLayout *l = layout(); + l->addItem( new QSpacerItem( 0, 10, QSizePolicy::Minimum, QSizePolicy::Expanding ) ); + l->add( errorLabel ); + l->add( urlLabel ); + l->addItem( new QSpacerItem( 0, 10, QSizePolicy::Minimum, QSizePolicy::Expanding ) ); + errorLabel->show(); + } + else + load(); +} + +void KCMKMrml::defaults() +{ + if (KMessageBox::warningContinueCancel(this, + i18n("Do you really want the configuration to be reset " + "to the defaults?"), i18n("Reset Configuration"), KStdGuiItem::cont()) + != KMessageBox::Continue) + return; + + m_mainPage->resetDefaults(); + + emit changed( true ); +} + +void KCMKMrml::load() +{ + m_mainPage->load(); + + emit changed( true ); +} + +void KCMKMrml::save() +{ + m_mainPage->save(); + + emit changed( false ); +} + +QString KCMKMrml::quickHelp() const +{ + return i18n("

Image Index

" + "KDE can make use of the GNU Image Finding Tool (GIFT) to " + "perform queries based not just on filenames, but on " + "file content." + "

For example, you can search for an image by giving an example " + "image that looks similar to the one you are looking for.

" + "

For this to work, your image directories need to be " + "indexed by, for example, the GIFT server.

" + "

Here you can configure the servers (you can also query " + "remote servers) and the directories to index.

" + ); +} + +#include "kcmkmrml.moc" diff --git a/kmrml/kmrml/kcontrol/kcmkmrml.desktop b/kmrml/kmrml/kcontrol/kcmkmrml.desktop new file mode 100644 index 00000000..d9dd1f02 --- /dev/null +++ b/kmrml/kmrml/kcontrol/kcmkmrml.desktop @@ -0,0 +1,176 @@ +[Desktop Entry] +Exec=kcmshell kcmkmrml +Icon=folder_image +Type=Application + +X-KDE-ModuleType=Library +X-KDE-Library=kmrml + +Name=Image Index +Name[ar]=فهرس الصور +Name[bg]=Графичен индекс +Name[br]=Meneger ar skeudenn +Name[bs]=Indeks slika +Name[ca]=Índex d'imatge +Name[cs]=Rejstřík obrázků +Name[cy]=Mynegai Delweddau +Name[da]=Billedindeks +Name[de]=Bildindex +Name[el]=Ευρετήριο εικόνων +Name[eo]=Bildindekso +Name[es]=Índice de imágenes +Name[et]=Pildiindeks +Name[eu]=Irudiaren indizea +Name[fa]=نمایۀ تصویر +Name[fi]=Kuvahakemisto +Name[fr]=Indexation des images +Name[gl]=Índice imaxe +Name[he]=אינדקס תמונות +Name[hi]=छवि सूची +Name[hu]=Képkereső +Name[is]=Myndayfirlit +Name[it]=Indice di immagini +Name[ja]=画像インデックス +Name[kk]=Кескіндер индексі +Name[km]=លិបិក្រម​រូបភាព +Name[lt]=Paveikslėlių rodyklė +Name[ms]=Indeks Imej +Name[nb]=Bildeindeks +Name[nds]=Bildindex +Name[ne]=छवि अनुक्रमणिका +Name[nl]=Afbeeldingenindex +Name[nn]=Biletindeks +Name[nso]=Palo ya Ponagalo +Name[pl]=Spis obrazków +Name[pt]=Índice de Imagens +Name[pt_BR]=Índice de Imagens +Name[ro]=Index imagini +Name[ru]=Индексирование изображений +Name[se]=Govvaindeaksa +Name[sk]=Katalóg obrázkov +Name[sl]=Seznam slik +Name[sr]=Индекс слика +Name[sr@Latn]=Indeks slika +Name[sv]=Bildindex +Name[ta]=பிம்ப அட்டவணை +Name[tg]=Индексатсия кардани тасвирот +Name[th]=ดัชนีรูปภาพ +Name[tr]=Resim İndeksi +Name[uk]=Індекс зображень +Name[uz]=Rasm indeksi +Name[uz@cyrillic]=Расм индекси +Name[ven]=Index ya tshifanyiso +Name[wa]=Indecse des imådjes +Name[xh]=Isalathisi Somfanekiso +Name[zh_CN]=图像索引 +Name[zh_HK]=圖像索引 +Name[zh_TW]=影像索引 +Name[zu]=Isiqalo Sesithombe + +Comment=Configuration for using the GNU Image Finding Tool +Comment[ar]=اعدادات لاستخدام أداة GNU للبحث عن الصور +Comment[bg]=Настройване на програмата за индексиране и търсене на изображения +Comment[bs]=Podešavanje za upotrebu GNU Alata za pronalaženje slika +Comment[ca]=Configuració per a l'ús de l'eina de cerca d'imatges GNU +Comment[cs]=Konfigurace používání nástroje GNU Image Finding Tool +Comment[cy]=Ffurfweddiad am ddefnyddio'r Erfyn Canfod Delweddau GNU +Comment[da]=Indstilling for brug af GNU Image Finding Tool +Comment[de]=Einrichtung für die Benutzung des GNU Bildersuchwerkzeugs (GNU Image Finding Tool) +Comment[el]=Ρύθμιση για τη χρήση του εργαλείου αναζήτησης εικόνων GIFT +Comment[es]=Configuración para utilizar la herramienta de búsqueda de imágenes de GNU +Comment[et]=Seadistused GNU pildileidmisrakenduse kasutamiseks +Comment[eu]=GNU irudi aurkitzailea erabiltzeko konfigurazioa +Comment[fa]=پیکربندی برای استفاده از ابزار یافتن تصویر GNU +Comment[fi]=Asetukset GNU Image Finding Tool -ohjelman käyttöä varten +Comment[fr]=Configuration pour l'utilisation du GNU Image Finding Tool +Comment[gl]=Configuración para empregar a «GNU Image Finding Tool» +Comment[he]=שינוי הגדרות כלי חיפוש התמונות של GNU +Comment[hi]=ग्नू छवि खोज औज़ार को उपयोग करने के लिए कॉन्फ़िगरेशन +Comment[hu]=A GIFT képkereső szolgáltatás beállításai +Comment[is]=Stillingar til þess að nota GNU myndleitartólið +Comment[it]=Configurazione della ricerca delle immagini +Comment[ja]=GIFT (GNU Image Finding Tool) を使用するための設定 +Comment[kk]=GNU Image Finding Tool кескінді табу құралын пайдалану баптаулары +Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​ដើម្បី​ប្រើ​ឧបករណ៍​ស្វែងរក​រូបភាព​របស់ GNU +Comment[lt]=GNU paveikslėlių paieškos įrankio konfigūracija +Comment[ms]=Konfigurasi untuk mengguna Alat Carian Imej GNU +Comment[nb]=Tilpass GNU bildesøkingsverktøy +Comment[nds]=Inrichten för dat GNU-Bildsöökwarktüüch +Comment[ne]=GNU छवि फेला पार्ने उपकरण प्रयोगका लागि कन्फिगरेसन +Comment[nl]=Configuratie voor het gebruik van de GNU Image Finding Tool +Comment[nn]=Oppsett av GNU Image Finding Tool +Comment[pl]=Konfiguracja Gifta (narzędzia do szukania obrazków GNU) +Comment[pt]=Configuração da Ferramenta de Procura de Imagens da GNU +Comment[pt_BR]=Configuração para o uso da Ferramenta de Procura de Imagens GNU +Comment[ro]=Configurare pentru GNU Image Finding Tool +Comment[ru]=Настройка использования программы поиска изображений GNU Image Finding Tool +Comment[se]=Heivet GNU Image Finding Tool +Comment[sk]=Konfigurácia pre GNU Image Finding Tool +Comment[sl]=Nastavitve za uporabo orodja GNU za iskanje slik +Comment[sr]=Подешавање коришћења GNU-овог алата за тражење слика +Comment[sr@Latn]=Podešavanje korišćenja GNU-ovog alata za traženje slika +Comment[sv]=Inställning för att använda GNU:s bildsökverktyg +Comment[ta]=GNU பிம்ப தேடுதல் கருவியை பயன்படுத்துவதற்கான அமைப்பு +Comment[tg]=Танзимоти истифодабарии барномаиҷустуҷӯи тасвироти GNU Image Finding Tool +Comment[tr]=GNU Resim Bulma Aracı yapılandırması +Comment[uk]=Налаштування засобу пошуку зображень GNU +Comment[ven]=Nzudzanyo yau shumisa tshishumiswa tshau toda tshifanyiso tsha GNU +Comment[wa]=Apontiaedje po-z eployî l' usteye di cweraedje d' imådjes di GNU +Comment[xh]=Uqwalaselo lokusebenzisa Isixhobo Sokufumana Umfanekiso we GNU +Comment[zh_CN]=使用 GNU 图像查找工具的配置 +Comment[zh_HK]=GNU 圖像搜尋工具的設定 +Comment[zh_TW]= GNU 影像搜尋工具組態 +Comment[zu]=Inhlanganiselo yokusebenzisa Ithuluzi Lokuthola Isithombe se-GNU + +Keywords=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR +Keywords[ar]=صور,بحث,استعلام,Find,Gift,kmrml,mrml,CBIR +Keywords[bg]=изображения, търсене, заявка, картинка, картинки, снимки, Images, Search, Query, Find, Gift, kmrml, mrml, CBIR +Keywords[bs]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR,slike,pretraga,upit,nađi +Keywords[ca]=Imatges,Cerca,Consulta,Busca,Gift,kmrml,mrml,CBIR +Keywords[cs]=Obrázky,Hledat,Dotaz,Najít,Gift,kmrml,mrml,CBIR +Keywords[cy]=Delweddau,Chwilio,Canfod,Gift,kmrml,mrml,CBIR +Keywords[da]=Billeder,Søgning,Forespørgsel,Find,Gave,kmrml,mrml,CBIR +Keywords[de]=Bilder,Suche,Anfrage,finden,Geschenk,kmrml,mrml,CBIR +Keywords[el]=Εικόνες,Αναζήτηση,Ερώτηση,Αναζήτηση,Gift,kmrml,mrml,CBIR +Keywords[es]=Imágenes,Búsqueda,Consulta,Buscar,Gift,kmrml,mrml,CBIR +Keywords[et]=pildid,otsing,päring,leia,Gift,kmrml,mrml,CBIR +Keywords[eu]=Irudiak,Bilaketa,Bilatu,Galdetu,Gift,kmrml,mrml,CBIR +Keywords[fa]=تصاویر، جستجو، پرس‌و‌جو، یافتن، Gift،kmrml،mrml،CBIR +Keywords[fi]=Kuvat,Haku,Etsi,Lahja,kmrml,mrml,CBIR +Keywords[fr]=Images,Recherche,Requête,Chercher,Gift,kmrml,mrml,CBIR +Keywords[gl]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR, imaxes, procura +Keywords[he]=תמונות,חיפוש,שאילתה,Gift,kmrml,mrml,CBIR, Images,Search,Query,Find +Keywords[hi]=छवि, खोज,ढूंढ,तलाश,उपहार,केएमआरएमएल,एमआरएमएल,सीबीआईआर +Keywords[hu]=képek,keresés,lekérdezés,találat,Gift,kmrml,mrml,CBIR +Keywords[it]=immagini,ricerca,trovare,Gift,kmrml,mrml,CBIR +Keywords[ja]=画像,検索,クエリ,検索,Gift,kmrml,mrml,CBIR +Keywords[km]=រូបភាព,ស្វែងរក,សួរ,រក,Gift,kmrml,mrml,CBIR +Keywords[lt]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR, paveikslėliai,paieška,paklausimas +Keywords[nb]=Bilder,Søk,Spørringer,Finn,Gift,kmrml,mrml,CBIR +Keywords[nds]=Biller,Söök,Anfraag,söken,Gaav,kmrml,mrml,CBIR +Keywords[nl]=illustraties,figuren,figuur,afbeeldingen,plaatjes,zoeken,find,gift,kmrml,mrml,CBIR,images +Keywords[nn]=bilete,søk,spørjing,finn,gåve,kmrml,mrml,CBIR +Keywords[nso]=Diponagalo,Nyaka,Kgokgonego,Hwetsa,Mpho,kmrml,mrml,CBIR +Keywords[pl]=Obrazki,Szukanie,Zapytanie,Szukaj,Gift,kmrml,mrml,CBIR +Keywords[pt]=Imagens,Procurar,Pesquisar,Encontrar,Prenda,kmrml,mrml,CBIR +Keywords[pt_BR]=Imagens,Busca,Consulta,Procurar,Presente,kmrml,mrml,CBIR +Keywords[ro]=imagini,căutare,caută,interogare,găseşte,dar,kmrml,mrml,CBIR +Keywords[ru]=изображения,поиск,запрос,kmrml,mrml,CBIR +Keywords[sk]=Obrázky,Hľadanie,Dotazy,Nájsť,kmrml,mrml,CBIR +Keywords[sl]=slike,iskanje,povpraševanje,išči,najdi,gift,kmrml,mrml,CBIR +Keywords[sr]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR,слике,тражи,упит,нађи,поклон +Keywords[sr@Latn]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR,slike,traži,upit,nađi,poklon +Keywords[sv]=Bilder,Sök,Förfrågan,Hitta,Gift,kmrml,mrml,CBIR +Keywords[ta]=பிம்பங்கள், தேடு, கேள்வி, கண்டுபிடி,பரிசு,kmrml,mrml,CBIR +Keywords[tg]=тасвирот,ҷустуҷӯӣ,дархост,kmrml,mrml,CBIR +Keywords[tr]=Resimler,Ara,Arama,kmrml,mrml,CBIR +Keywords[uk]=зображення,пошук,запит,знайти,подарунок,kmrml,mrml,CBIR +Keywords[ven]=Zwifanyiso,Toda,Mbudziso,Wana,Mpho,kmrml,mrml,CBIR +Keywords[wa]=Imådjes,Cweri,Cweraedje,Trover,Gift,kmrml,mrml,CBIR +Keywords[xh]=Imifanekiso,Uphendlo,Ubuzo,fumana,Isiphiwo,kmrml,mrml,CBIR +Keywords[zh_CN]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR,图像,搜索,查询,查找,礼物 +Keywords[zh_HK]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR,圖像,搜尋,查詢,尋找 +Keywords[zh_TW]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR,影像,搜尋,查詢,尋找 +Keywords[zu]=Izithombe,Funa,Buza,Thola,Isipho,kmrml,mrml,CBIR + +Categories=Qt;KDE;Settings;X-KDE-settings-system; diff --git a/kmrml/kmrml/kcontrol/kcmkmrml.h b/kmrml/kmrml/kcontrol/kcmkmrml.h new file mode 100644 index 00000000..b0bb2443 --- /dev/null +++ b/kmrml/kmrml/kcontrol/kcmkmrml.h @@ -0,0 +1,52 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KCMKMRML_H +#define KCMKMRML_H + +#include + +class KAboutData; +class KURLRequester; + +namespace KMrmlConfig +{ + class MainPage; + + class KCMKMrml : public KCModule + { + Q_OBJECT + + public: + KCMKMrml(QWidget *parent, const char *name, const QStringList &); + virtual ~KCMKMrml(); + + virtual void defaults(); + virtual void load(); + virtual void save(); + virtual QString quickHelp() const; + + private: + void checkGiftInstallation(); + + MainPage *m_mainPage; + }; + +} + +#endif diff --git a/kmrml/kmrml/kcontrol/mainpage.cpp b/kmrml/kmrml/kcontrol/mainpage.cpp new file mode 100644 index 00000000..514b9cf6 --- /dev/null +++ b/kmrml/kmrml/kcontrol/mainpage.cpp @@ -0,0 +1,501 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include // MAX_PORT_VALUE + +#include "serverconfigwidget.h" +#include "mainpage.h" +#include "indexer.h" +#include "indexcleaner.h" + +#include +#include + +using namespace KMrmlConfig; + + +MainPage::MainPage( QWidget *parent, const char *name ) + : QVBox( parent, name ), + m_indexer( 0L ), + m_indexCleaner( 0L ), + m_progressDialog( 0L ), + m_performIndexing( false ), + m_locked( false ) +{ + m_config = new KMrml::Config(); + setSpacing( KDialog::spacingHint() ); + + QVGroupBox *gBox = new QVGroupBox( i18n("Indexing Server Configuration"), + this ); + m_serverWidget = new ServerConfigWidget( gBox, "server config widget" ); + QString tip = i18n("Hostname of the Indexing Server"); + QToolTip::add( m_serverWidget->m_hostLabel, tip ); + QToolTip::add( m_serverWidget->m_hostCombo, tip ); + + m_serverWidget->m_portInput->setRange( 0, MAX_PORT_VALUE ); + +#if KDE_VERSION >= 306 + KURLRequester *requester = new KURLRequester( this, "dir requester" ); + requester->setMode( KFile::Directory | KFile::ExistingOnly | KFile::LocalOnly ); + requester->setURL( KGlobalSettings::documentPath() ); + connect( requester, SIGNAL( openFileDialog( KURLRequester * )), + SLOT( slotRequesterClicked( KURLRequester * ))); + + m_listBox = new KEditListBox( i18n("Folders to Be Indexed" ), + requester->customEditor(), this, "listbox", + false, + KEditListBox::Add | KEditListBox::Remove ); +#else + m_listBox = new KEditListBox( i18n("Folders to Be Indexed" ), + this, "listbox", false, + KEditListBox::Add | KEditListBox::Remove ); +#endif + + connect( m_listBox, SIGNAL( changed() ), SLOT( slotDirectoriesChanged() )); + connect( m_serverWidget->m_hostCombo, SIGNAL( textChanged(const QString&)), + SLOT( slotHostChanged() )); + connect( m_serverWidget->m_portInput, SIGNAL( valueChanged( int )), + SLOT( slotPortChanged( int ) )); + connect ( m_serverWidget->m_useAuth, SIGNAL( toggled(bool) ), + SLOT( slotUseAuthChanged( bool ) )); + connect( m_serverWidget->m_userEdit, SIGNAL( textChanged( const QString&)), + SLOT( slotUserChanged( const QString& ) )); + connect( m_serverWidget->m_passEdit, SIGNAL( textChanged( const QString&)), + SLOT( slotPassChanged( const QString& ) )); + + connect( m_serverWidget->m_addButton, SIGNAL( clicked() ), + SLOT( slotAddClicked() )); + connect( m_serverWidget->m_removeButton, SIGNAL( clicked() ), + SLOT( slotRemoveClicked() )); + + connect( m_serverWidget->m_hostCombo, SIGNAL( activated( const QString& )), + SLOT( slotHostActivated( const QString& ))); + connect( m_serverWidget->m_hostCombo, SIGNAL( returnPressed() ), + SLOT( slotAddClicked() )); + + connect( m_serverWidget->m_autoPort, SIGNAL( toggled( bool ) ), + SLOT( slotAutoPortChanged( bool ) )); + + m_serverWidget->m_hostCombo->setTrapReturnKey( true ); + m_serverWidget->m_hostCombo->setFocus(); +} + +MainPage::~MainPage() +{ + delete m_config; +} + +void MainPage::resetDefaults() +{ + blockSignals( true ); + + initFromSettings( KMrml::ServerSettings::defaults() ); + + m_serverWidget->m_hostCombo->clear(); + m_serverWidget->m_hostCombo->insertItem( m_settings.host ); + + m_listBox->clear(); + + // slotHostChanged(); not necessary, will be called by Qt signals + slotUseAuthChanged( m_serverWidget->m_useAuth->isChecked() ); + + blockSignals( false ); +} + +void MainPage::load() +{ + blockSignals( true ); + + initFromSettings( m_config->defaultSettings() ); + + m_serverWidget->m_hostCombo->clear(); + m_serverWidget->m_hostCombo->insertStringList( m_config->hosts() ); + m_serverWidget->m_hostCombo->setCurrentItem( m_settings.host ); + + m_listBox->clear(); + m_listBox->insertStringList( m_config->indexableDirectories() ); + + // slotHostChanged(); not necessary, will be called by Qt signals + slotUseAuthChanged( m_serverWidget->m_useAuth->isChecked() ); + + blockSignals( false ); +} + +void MainPage::save() +{ + m_config->addSettings( m_settings ); + m_config->setDefaultHost( m_settings.host ); + + QStringList indexDirs = m_listBox->items(); + QStringList oldIndexDirs = m_config->indexableDirectories(); + QStringList removedDirs = difference( oldIndexDirs, indexDirs ); + + m_config->setIndexableDirectories( indexDirs ); + if ( indexDirs.isEmpty() ) + KMessageBox::information( this, + i18n("You did not specify any folders to " + "be indexed. This means you will be " + "unable to perform queries on your " + "computer."), + "kcmkmrml_no_directories_specified" ); + + if ( m_config->sync() ) + KIO::SlaveConfig::self()->reset(); + + processIndexDirs( removedDirs ); +} + +QStringList MainPage::difference( const QStringList& oldIndexDirs, + const QStringList& newIndexDirs ) const +{ + QStringList result; + + QString slash = QString::fromLatin1("/"); + QStringList::ConstIterator oldIt = oldIndexDirs.begin(); + QString oldDir, newDir; + + for ( ; oldIt != oldIndexDirs.end(); oldIt++ ) + { + bool removed = true; + oldDir = *oldIt; + + while ( oldDir.endsWith( slash ) ) // remove slashes + oldDir.remove( oldDir.length() - 1, 1 ); + + QStringList::ConstIterator newIt = newIndexDirs.begin(); + for ( ; newIt != newIndexDirs.end(); newIt++ ) + { + newDir = *newIt; + while ( newDir.endsWith( slash ) ) // remove slashes + newDir.remove( newDir.length() - 1, 1 ); + + if ( oldDir == newDir ) + { + removed = false; + break; + } + } + + if ( removed ) + result.append( *oldIt ); // not oldDir -- maybe gift needs slashes + } + + return result; +} + +void MainPage::initFromSettings( const KMrml::ServerSettings& settings ) +{ + m_settings = settings; + + m_locked = true; + + m_serverWidget->m_portInput->setValue( settings.configuredPort ); + m_serverWidget->m_autoPort->setChecked( settings.autoPort ); + m_serverWidget->m_useAuth->setChecked( settings.useAuth ); + m_serverWidget->m_userEdit->setText( settings.user ); + m_serverWidget->m_passEdit->setText( settings.pass ); + + m_locked = false; +} + +void MainPage::slotHostActivated( const QString& host ) +{ + // implicitly save the current settings when another host was chosen + m_config->addSettings( m_settings ); + + initFromSettings( m_config->settingsForHost( host ) ); +} + +void MainPage::slotHostChanged() +{ + QString host = m_serverWidget->m_hostCombo->currentText(); + m_listBox->setEnabled( (host == "localhost") ); + + KMrml::ServerSettings settings = m_config->settingsForHost( host ); + enableWidgetsFor( settings ); +} + +void MainPage::slotUseAuthChanged( bool enable ) +{ + m_settings.useAuth = enable; + m_serverWidget->m_userEdit->setEnabled( enable ); + m_serverWidget->m_passEdit->setEnabled( enable ); + + if ( enable ) + m_serverWidget->m_userEdit->setFocus(); + + if ( !m_locked ) + changed(); +} + +void MainPage::slotUserChanged( const QString& user ) +{ + if ( m_locked ) + return; + + m_settings.user = user; + changed(); +} + +void MainPage::slotPassChanged( const QString& pass ) +{ + if ( m_locked ) + return; + + m_settings.pass = pass; + changed(); +} + +void MainPage::slotPortChanged( int port ) +{ + if ( m_locked ) + return; + + m_settings.configuredPort = (unsigned short int) port; + changed(); +} + +void MainPage::slotAutoPortChanged( bool on ) +{ + if ( m_locked ) + return; + + m_settings.autoPort = on; + m_serverWidget->m_portInput->setEnabled( !on ); + changed(); +} + +void MainPage::slotRequesterClicked( KURLRequester *requester ) +{ + static bool init = true; + if ( !init ) + return; + + init = false; + + requester->setCaption(i18n("Select Folder You Want to Index")); +} + +void MainPage::slotAddClicked() +{ + QString host = m_serverWidget->m_hostCombo->currentText(); + m_settings.host = host; + + m_config->addSettings( m_settings ); + m_serverWidget->m_hostCombo->insertItem( host ); + m_serverWidget->m_hostCombo->setCurrentItem( host ); + + enableWidgetsFor( m_settings ); +} + +void MainPage::slotRemoveClicked() +{ + QString host = m_serverWidget->m_hostCombo->currentText(); + if ( host.isEmpty() ) // should never happen + return; + + m_config->removeSettings( host ); + m_serverWidget->m_hostCombo->removeItem( m_serverWidget->m_hostCombo->currentItem() ); + m_serverWidget->m_hostCombo->setCurrentItem( 0 ); + + host = m_serverWidget->m_hostCombo->currentText(); + initFromSettings( m_config->settingsForHost( host ) ); +} + +void MainPage::enableWidgetsFor( const KMrml::ServerSettings& settings ) +{ + QString host = settings.host; + bool enableWidgets = (m_config->hosts().findIndex( host ) > -1); + m_serverWidget->m_addButton->setEnabled(!enableWidgets && !host.isEmpty()); + m_serverWidget->m_removeButton->setEnabled( enableWidgets && + !host.isEmpty() && + host != "localhost" ); + + m_serverWidget->m_autoPort->setEnabled( host == "localhost" ); + bool portEnable = enableWidgets && (settings.autoPort || + !m_serverWidget->m_autoPort->isEnabled()); + m_serverWidget->m_portLabel->setEnabled( portEnable && !m_serverWidget->m_autoPort->isChecked()); + m_serverWidget->m_portInput->setEnabled( portEnable && !m_serverWidget->m_autoPort->isChecked()); + + m_serverWidget->m_useAuth->setEnabled( enableWidgets ); + m_serverWidget->m_userLabel->setEnabled( enableWidgets ); + m_serverWidget->m_passLabel->setEnabled( enableWidgets ); + m_serverWidget->m_userEdit->setEnabled( enableWidgets ); + m_serverWidget->m_passEdit->setEnabled( enableWidgets ); + + bool useAuth = m_serverWidget->m_useAuth->isChecked(); + m_serverWidget->m_userEdit->setEnabled( useAuth ); + m_serverWidget->m_passEdit->setEnabled( useAuth ); +} + +void MainPage::slotDirectoriesChanged() +{ + m_performIndexing = true; + changed(); +} + +void MainPage::processIndexDirs( const QStringList& removeDirs ) +{ + // ### how to remove indexed directories? + if ( !m_performIndexing || + (removeDirs.isEmpty() && m_config->indexableDirectories().isEmpty()) ) + return; + + delete m_progressDialog; + delete m_indexCleaner; + m_indexCleaner = 0L; + delete m_indexer; + m_indexer = 0L; + + m_progressDialog = new KProgressDialog( this, "indexing dialog", + i18n("Removing old Index Files"), + i18n("Processing..."), + true ); + m_progressDialog->setAutoClose( false ); + m_progressDialog->setMinimumWidth( 300 ); + connect( m_progressDialog, SIGNAL( cancelClicked() ), + SLOT( slotCancelIndexing() )); + + // argh -- don't automatically show the dialog + m_progressDialog->setMinimumDuration( INT_MAX ); + + if ( !removeDirs.isEmpty() ) + { + m_indexCleaner = new IndexCleaner( removeDirs, m_config, this ); + connect( m_indexCleaner, SIGNAL( advance( int ) ), + m_progressDialog->progressBar(), SLOT( advance( int ) )); + connect( m_indexCleaner, SIGNAL( finished() ), + SLOT( slotMaybeIndex() ) ); + m_indexCleaner->start(); + } + else + { + slotMaybeIndex(); + } + if ( m_progressDialog ) + m_progressDialog->exec(); +} + +void MainPage::slotMaybeIndex() +{ + delete m_indexCleaner; // Stop in the name of the law! + m_indexCleaner = 0L; + + m_progressDialog->setLabel( i18n("Finished.") ); + + if ( m_config->indexableDirectories().isEmpty() ) + return; + + if ( KMessageBox::questionYesNo( this, + i18n("The settings have been saved. Now, " + "the configured directories need to " + "be indexed. This may take a while. " + "Do you want to do this now?"), + i18n("Start Indexing Now?"), + i18n("Index"), i18n("Do Not Index"), + "ask_startIndexing" + ) != KMessageBox::Yes ) + return; + m_progressDialog->setCaption( i18n("Indexing Folders") ); + m_progressDialog->setLabel( i18n("Processing...") ); + m_progressDialog->progressBar()->setProgress( 0 ); + + // do the indexing + m_indexer = new Indexer( m_config, this, "Indexer" ); + connect( m_indexer, SIGNAL( progress( int, const QString& )), + SLOT( slotIndexingProgress( int, const QString& ) )); + connect( m_indexer, SIGNAL( finished( int )), + SLOT( slotIndexingFinished( int ) )); + m_indexer->startIndexing( m_config->indexableDirectories() ); +} + + +void MainPage::slotIndexingProgress( int percent, const QString& message ) +{ + m_progressDialog->progressBar()->setValue( percent ); + m_progressDialog->setLabel( message ); +} + +void MainPage::slotIndexingFinished( int returnCode ) +{ + if ( returnCode != 0 ) + { + QString syserr; + if ( returnCode == 127 ) + syserr = i18n("Is the \"GNU Image Finding Tool\" properly installed?"); + else + { + char *err = strerror( returnCode ); + if ( err ) + syserr = QString::fromLocal8Bit( err ); + else + syserr = i18n("Unknown error: %1").arg( returnCode ); + } + + KMessageBox::detailedError( this, i18n("An error occurred during indexing. The index might be invalid."), + syserr, i18n("Indexing Aborted") ); + } + else + m_performIndexing = false; + + delete m_indexer; + m_indexer = 0L; + if ( m_progressDialog ) + { + m_progressDialog->deleteLater(); + m_progressDialog = 0L; + } +} + +void MainPage::slotCancelIndexing() +{ + delete m_indexCleaner; + m_indexCleaner = 0L; + + delete m_indexer; + m_indexer = 0L; + if ( m_progressDialog ) + { + m_progressDialog->deleteLater(); + m_progressDialog = 0L; + } +} + + +#include "mainpage.moc" diff --git a/kmrml/kmrml/kcontrol/mainpage.h b/kmrml/kmrml/kcontrol/mainpage.h new file mode 100644 index 00000000..e91b4168 --- /dev/null +++ b/kmrml/kmrml/kcontrol/mainpage.h @@ -0,0 +1,109 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef MAINPAGE_H +#define MAINPAGE_H + +#include + +#include + +class QCheckBox; +class KComboBox; +class KEditListBox; +class KIntNumInput; +class KLineEdit; +class KProgressDialog; +class KURLRequester; + +namespace KMrml +{ + class Config; +} + +class ServerConfigWidget; + +namespace KMrmlConfig +{ + class Indexer; + class IndexCleaner; + + class MainPage : public QVBox + { + Q_OBJECT + + public: + MainPage( QWidget *parent, const char *name ); + ~MainPage(); + + void resetDefaults(); + void load(); + void save(); + + signals: + void changed( bool ); + + private slots: + void changed() { emit changed( true ); } + void slotRequesterClicked( KURLRequester * ); + void slotHostChanged(); + void slotUseAuthChanged( bool ); + void slotUserChanged( const QString& ); + void slotPassChanged( const QString& ); + void slotPortChanged( int ); + void slotAutoPortChanged( bool ); + + void slotAddClicked(); + void slotRemoveClicked(); + + void slotHostActivated( const QString& ); + + void slotDirectoriesChanged(); + + void slotMaybeIndex(); + void slotIndexingProgress( int percent, const QString& message ); + void slotIndexingFinished( int returnCode ); + void slotCancelIndexing(); + + + private: + void enableWidgetsFor( const KMrml::ServerSettings& settings ); + void initFromSettings( const KMrml::ServerSettings& settings ); + + void processIndexDirs( const QStringList& removedDirs ); + + QStringList difference( const QStringList& oldIndexDirs, + const QStringList& newIndexDirs ) const; + + ServerConfigWidget *m_serverWidget; + KEditListBox *m_listBox; + KMrml::Config *m_config; + KMrmlConfig::Indexer *m_indexer; + KMrmlConfig::IndexCleaner *m_indexCleaner; + KProgressDialog *m_progressDialog; + + KMrml::ServerSettings m_settings; + bool m_performIndexing; + bool m_locked; + }; + +} + + + +#endif // MAINPAGE_H diff --git a/kmrml/kmrml/kcontrol/serverconfigwidget.ui b/kmrml/kmrml/kcontrol/serverconfigwidget.ui new file mode 100644 index 00000000..e0a08007 --- /dev/null +++ b/kmrml/kmrml/kcontrol/serverconfigwidget.ui @@ -0,0 +1,272 @@ + +ServerConfigWidget + + + ServerConfigWidget + + + + 0 + 0 + 455 + 321 + + + + + unnamed + + + 11 + + + 6 + + + + Layout7 + + + + unnamed + + + 0 + + + 6 + + + + Layout4 + + + + unnamed + + + 0 + + + 6 + + + + m_hostCombo + + + + 3 + 0 + 0 + 0 + + + + true + + + + + m_addButton + + + &Add + + + + + m_removeButton + + + &Remove + + + + + + + Layout6 + + + + unnamed + + + 0 + + + 6 + + + + m_portInput + + + + 7 + 0 + 0 + 0 + + + + TCP/IP Port Number of the Indexing Server + + + + + m_autoPort + + + Au&to + + + Tries to automatically determine the port. This works only for local servers. + + + + + Spacer3 + + + Horizontal + + + Expanding + + + + 200 + 0 + + + + + + + + m_hostLabel + + + Ho&stname: + + + m_hostCombo + + + + + m_portLabel + + + P&ort: + + + m_portInput + + + + + + + m_useAuth + + + Per&form authentication + + + + + Layout12 + + + + unnamed + + + 0 + + + 6 + + + + Spacer1 + + + Horizontal + + + Fixed + + + + 16 + 16 + + + + + + Layout6 + + + + unnamed + + + 0 + + + 6 + + + + m_userLabel + + + &Username: + + + m_userEdit + + + + + m_passEdit + + + + + m_passLabel + + + &Password: + + + m_passEdit + + + + + m_userEdit + + + + + + + + + + m_hostCombo + m_addButton + m_removeButton + m_portInput + m_useAuth + m_userEdit + m_passEdit + + + diff --git a/kmrml/kmrml/lib/Makefile.am b/kmrml/kmrml/lib/Makefile.am new file mode 100644 index 00000000..4201f04f --- /dev/null +++ b/kmrml/kmrml/lib/Makefile.am @@ -0,0 +1,11 @@ +noinst_LTLIBRARIES = libkmrmlstuff.la +libkmrmlstuff_la_SOURCES = kmrml_config.cpp mrml_shared.cpp mrml_utils.cpp\ +watcher_stub.cpp +noinst_HEADERS = kmrml_config.h mrml_shared.h mrml_utils.h watcher_stub.h + +METASOURCES = AUTO + +libkmrmlstuff_la_LDFLAGS = $(all_libraries) -no-undefined +libkmrmlstuff_la_LIBADD = $(LIB_KDECORE) + +INCLUDES = -I$(top_srcdir) $(all_includes) diff --git a/kmrml/kmrml/lib/kmrml_config.cpp b/kmrml/kmrml/lib/kmrml_config.cpp new file mode 100644 index 00000000..a88e8404 --- /dev/null +++ b/kmrml/kmrml/lib/kmrml_config.cpp @@ -0,0 +1,339 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "kmrml_config.h" + +#include +#if KDE_VERSION < 307 + #define QUOTE( x ) x +#else + #define QUOTE( x ) KProcess::quote( x ) +#endif + +using namespace KMrml; + +// #define DEFAULT_ADDCOLLECTION_CMD "gift-add-collection.pl --thumbnail-dir=%t --local-encoding %d" +#define DEFAULT_ADDCOLLECTION_CMD "gift-add-collection.pl --gift-home=%h --thumbnail-dir=%t --local-encoding=%e %d" +#define DEFAULT_REMOVECOLLECTION_CMD "gift-add-collection.pl --gift-home=%h --local-encoding=%e --remove-collection %d" + +#define DEFAULT_MRMLD_CMD "gift --port %p --datadir %d" +#define DEFAULT_MRMLD_CMD_AUTOPORT "gift --datadir %d" + +#define CONFIG_GROUP "MRML Settings" +#define DEFAULT_HOST "localhost" +#define DEFAULT_USER "kmrml" +#define DEFAULT_PASS "none" +#define DEFAULT_AUTH false +#define DEFAULT_AUTOPORT true +const int DEFAULT_PORT = 12789; + +Config::Config() +{ + m_ownConfig = new KConfig( "kio_mrmlrc", false, false ); + m_config = m_ownConfig; + + init(); +} + +Config::Config( KConfig *config ) + : m_config( config ), + m_ownConfig( 0L ) +{ + init(); +} + +Config::~Config() +{ + delete m_ownConfig; +} + +void Config::init() +{ + m_config->setGroup( CONFIG_GROUP ); + m_defaultHost = m_config->readEntry( "Default Host" ); + if ( m_defaultHost.isEmpty() ) + m_defaultHost = DEFAULT_HOST; + + m_hostList = m_config->readListEntry( "Host List" ); + if ( m_hostList.isEmpty() ) + m_hostList.append( DEFAULT_HOST ); + + m_serverStartedIndividually = + m_config->readBoolEntry( "ServerStartedIndividually", false ); +} + +bool Config::sync() +{ + bool notifySlaves = m_config->isDirty(); + m_config->sync(); + return notifySlaves; + + // This moved to kcontrol/MainPage::save() so we don't have to link against + // KIO and need a full KApplication instance to work (so that the tiny + // mrmlsearch binary can also use this class) + // tell the ioslaves about the new configuration +// if ( notifySlaves ) +// KIO::SlaveConfig::self()->reset(); +} + +void Config::setDefaultHost( const QString& host ) +{ + m_defaultHost = host.isEmpty() ? + QString::fromLatin1(DEFAULT_HOST) : host; + + m_config->setGroup( CONFIG_GROUP ); + m_config->writeEntry( "Default Host", m_defaultHost ); +} + +ServerSettings Config::settingsForLocalHost() const +{ + return settingsForHost( "localhost" ); +} + +ServerSettings Config::settingsForHost( const QString& host ) const +{ + KConfigGroup config( m_config, settingsGroup( host ) ); + ServerSettings settings; + + settings.host = host; + settings.configuredPort = config.readUnsignedNumEntry( "Port", + DEFAULT_PORT ); + settings.autoPort = (host == "localhost") && + config.readBoolEntry("Automatically determine Port", + DEFAULT_AUTOPORT ); + settings.user = config.readEntry( "Username", DEFAULT_USER ); + settings.pass = config.readEntry( "Password", DEFAULT_PASS ); + settings.useAuth = config.readBoolEntry( "Perform Authentication", + DEFAULT_AUTH ); + + return settings; +} + +void Config::addSettings( const ServerSettings& settings ) +{ + QString host = settings.host; + if ( m_hostList.find( host ) == m_hostList.end() ) + m_hostList.append( host ); + + m_config->setGroup( CONFIG_GROUP ); + m_config->writeEntry( "Host List", m_hostList ); + + m_config->setGroup( settingsGroup( host ) ); + m_config->writeEntry( "Host", host ); + m_config->writeEntry( "Port", settings.configuredPort ); + m_config->writeEntry( "Automatically determine Port", settings.autoPort ); + m_config->writeEntry( "Username", settings.user ); + m_config->writeEntry( "Password", settings.pass ); + m_config->writeEntry( "Perform Authentication", settings.useAuth ); +} + +bool Config::removeSettings( const QString& host ) +{ + bool success = m_config->deleteGroup( settingsGroup( host ) ); + if ( success ) + { + m_hostList.remove( host ); + m_config->setGroup( CONFIG_GROUP ); + } + + return success; +} + +QStringList Config::indexableDirectories() const +{ + m_config->setGroup( CONFIG_GROUP ); + return m_config->readListEntry( "Indexable Directories" ); +} + +void Config::setIndexableDirectories( const QStringList& dirs ) +{ + m_config->setGroup( CONFIG_GROUP ); + m_config->writeEntry( "Indexable Directories", dirs ); +} + +QString Config::addCollectionCommandLine() const +{ + m_config->setGroup( CONFIG_GROUP ); + QString cmd = m_config->readEntry( "AddCollection Commandline", + DEFAULT_ADDCOLLECTION_CMD ); + int index = cmd.find( "%h" ); + if ( index != -1 ) + cmd.replace( index, 2, QUOTE( mrmldDataDir() ) ); + + index = cmd.find( "%e" ); + if ( index != -1 ) + cmd.replace( index, 2, QTextCodec::codecForLocale()->mimeName() ); + + return cmd; +} + +void Config::setAddCollectionCommandLine( const QString& cmd ) +{ + m_config->setGroup( CONFIG_GROUP ); + m_config->writeEntry( "AddCollection Commandline", cmd ); +} + +QString Config::removeCollectionCommandLine() const +{ + m_config->setGroup( CONFIG_GROUP ); + QString cmd = m_config->readEntry( "RemoveCollection Commandline", + DEFAULT_REMOVECOLLECTION_CMD ); + int index = cmd.find( "%h" ); + if ( index != -1 ) + cmd.replace( index, 2, QUOTE( mrmldDataDir() ) ); + + index = cmd.find( "%e" ); + if ( index != -1 ) + cmd.replace( index, 2, QTextCodec::codecForLocale()->mimeName() ); + + return cmd; +} + +void Config::setRemoveCollectionCommandLine( const QString& cmd ) +{ + m_config->setGroup( CONFIG_GROUP ); + m_config->writeEntry( "RemoveCollection Commandline", cmd ); +} + +QString Config::mrmldCommandline() const +{ + ServerSettings settings = settingsForLocalHost(); + + m_config->setGroup( CONFIG_GROUP ); + QString cmd = m_config->readEntry( "MrmmlDaemon Commandline", + settings.autoPort ? + DEFAULT_MRMLD_CMD_AUTOPORT : + DEFAULT_MRMLD_CMD ); + + // add data directory and port to the commandline + int index = cmd.find( "%p" ); + if ( index != -1 ) + { + QString port = settings.autoPort ? + QString::null : QString::number( settings.configuredPort ); + cmd.replace( index, 2, port ); + } + index = cmd.find( "%d" ); + if ( index != -1 ) + { + cmd.replace( index, 2, QUOTE( mrmldDataDir() ) ); + } + + qDebug("***** commandline: %s", cmd.latin1()); + + return cmd; +} + +QString Config::mrmldDataDir() +{ + QString dir = KGlobal::dirs()->saveLocation( "data", + "kmrml/mrmld-data/" ); + if ( dir.isEmpty() ) // fallback + dir = QDir::homeDirPath() + "/"; + + return dir; +} + +void Config::setMrmldCommandLine( const QString& cmd ) +{ + m_config->setGroup( CONFIG_GROUP ); + m_config->writeEntry( "MrmmlDaemon Commandline", cmd ); +} + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// + +ServerSettings::ServerSettings() + : configuredPort( 0 ), + autoPort( true ), + useAuth( false ) +{ +} + +ServerSettings::ServerSettings( const QString& host, unsigned short int port, + bool autoPort, bool useAuth, + const QString& user, const QString& pass ) +{ + this->host = host; + this->configuredPort = port; + this->autoPort = autoPort; + this->useAuth = useAuth; + this->user = user; + this->pass = pass; +} + +// static +ServerSettings ServerSettings::defaults() +{ + return ServerSettings( DEFAULT_HOST, DEFAULT_PORT, + (!strcmp(DEFAULT_HOST, "localhost") && DEFAULT_PORT), + DEFAULT_AUTH, DEFAULT_USER, DEFAULT_PASS ); +} + +KURL ServerSettings::getUrl() const +{ + KURL url; + url.setProtocol( "mrml" ); + url.setHost( host ); + if ( !autoPort ) + url.setPort( configuredPort ); + + if ( useAuth && user.isEmpty() ) + { + url.setUser( user ); + url.setPass( pass ); + } + + return url; +} + +unsigned short int ServerSettings::port() const +{ + if ( autoPort ) + { + QString portsFile = Config::mrmldDataDir() + "gift-port.txt"; + QFile file( portsFile ); + if ( file.open( IO_ReadOnly ) ) + { + QString line; + (void) file.readLine( line, 6 ); +// qDebug("**** read: %s", line.latin1()); + + file.close(); + + bool ok; + unsigned short int p = line.toUShort( &ok ); + if ( ok ) + return p; + } + else + kdWarning() << "Can't open \"" << portsFile << "\" to automatically determine the gift port" << endl; + } + + return configuredPort; +} diff --git a/kmrml/kmrml/lib/kmrml_config.h b/kmrml/kmrml/lib/kmrml_config.h new file mode 100644 index 00000000..3b6baa40 --- /dev/null +++ b/kmrml/kmrml/lib/kmrml_config.h @@ -0,0 +1,123 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KMRML_CONFIG_H +#define KMRML_CONFIG_H + +class KConfig; + +#include +#include + +namespace KMrml +{ + class ServerSettings + { + public: + ServerSettings(); + ServerSettings(const QString& host, unsigned short int port, + bool autoPort, bool useAuth, const + QString& user, const QString& pass); + + // does NOT set the port in the KURL object, if autoPort is selected + // kio_mrml is going to determine itself (via ServerSettings::port()). + // This deuglifies the mrml:/ url a bit (no port is shown) + KURL getUrl() const; + + QString host; + QString user; + QString pass; + unsigned short int configuredPort; + bool autoPort :1; // only possible with host == localhost + bool useAuth :1; + + static ServerSettings defaults(); + + // returns configuredPort or the automatically determined port, + // depending on the value of autoPort + unsigned short int port() const; + }; + + class Config + { + public: + Config(); + Config( KConfig *config ); // does not take ownership of KConfig + ~Config(); + + bool sync(); + + ServerSettings defaultSettings() const + { + return settingsForHost( m_defaultHost ); + } + + ServerSettings settingsForLocalHost() const; + ServerSettings settingsForHost( const QString& host ) const; + + void setDefaultHost( const QString& host ); + + /** + * Indexed by the hostname -- ensures there are no dupes + */ + void addSettings( const ServerSettings& settings ); + + bool removeSettings( const QString& host ); + + QStringList hosts() const { return m_hostList; } + + /** + * The list of indexable directories -- only applicable to "localhost" + */ + QStringList indexableDirectories() const; + void setIndexableDirectories( const QStringList& dirs ); + + QString addCollectionCommandLine() const; + void setAddCollectionCommandLine( const QString& cmd ); + + QString removeCollectionCommandLine() const; + void setRemoveCollectionCommandLine( const QString& cmd ); + + void setMrmldCommandLine( const QString& cmd ); + QString mrmldCommandline() const; + + // e.g. Wolfgang needs this :) + bool serverStartedIndividually() const { + return m_serverStartedIndividually; + } + + static QString mrmldDataDir(); + + private: + void init(); + + QString settingsGroup( const QString& host ) const + { + return QString::fromLatin1( "SettingsFor: " ).append( host ); + } + + bool m_serverStartedIndividually; + QString m_defaultHost; + QStringList m_hostList; + + KConfig *m_config; + KConfig *m_ownConfig; + }; +} + +#endif // KMRML_CONFIG_H diff --git a/kmrml/kmrml/lib/mrml_shared.cpp b/kmrml/kmrml/lib/mrml_shared.cpp new file mode 100644 index 00000000..0c5b692b --- /dev/null +++ b/kmrml/kmrml/lib/mrml_shared.cpp @@ -0,0 +1,235 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "mrml_shared.h" + +// mrml stuff +const QString * MrmlShared::m_sessionId = 0L; +const QString * MrmlShared::m_transactionId = 0L; +const QString * MrmlShared::m_algorithm = 0L; +const QString * MrmlShared::m_algorithmId = 0L; +const QString * MrmlShared::m_algorithmName = 0L; +const QString * MrmlShared::m_algorithmList = 0L; +const QString * MrmlShared::m_algorithmType = 0L; +const QString * MrmlShared::m_collectionId = 0L; +const QString * MrmlShared::m_collectionList = 0L; +const QString * MrmlShared::m_collection = 0L; +const QString * MrmlShared::m_collectionName = 0L; +const QString * MrmlShared::m_queryParadigm = 0L; +const QString * MrmlShared::m_queryParadigmList = 0L; +const QString * MrmlShared::m_configureSession = 0L; + +const QString * MrmlShared::m_propertySheet = 0L; +const QString * MrmlShared::m_propertySheetId = 0L; +const QString * MrmlShared::m_propertySheetType = 0L; +const QString * MrmlShared::m_sendName = 0L; +const QString * MrmlShared::m_sendType = 0L; +const QString * MrmlShared::m_sendValue = 0L; +const QString * MrmlShared::m_maxSubsetSize = 0L; +const QString * MrmlShared::m_minSubsetSize = 0L; +const QString * MrmlShared::m_caption = 0L; +const QString * MrmlShared::m_from = 0L; +const QString * MrmlShared::m_to = 0L; +const QString * MrmlShared::m_step = 0L; +const QString * MrmlShared::m_sendBooleanInverted = 0L; + +const QString * MrmlShared::m_element = 0L; +const QString * MrmlShared::m_attribute = 0L; +const QString * MrmlShared::m_attributeName = 0L; +const QString * MrmlShared::m_attributeValue = 0L; +const QString * MrmlShared::m_children = 0L; +const QString * MrmlShared::m_none = 0L; + +const QString * MrmlShared::m_multiSet = 0L; +const QString * MrmlShared::m_subset = 0L; +const QString * MrmlShared::m_setElement = 0L; +const QString * MrmlShared::m_boolean = 0L; +const QString * MrmlShared::m_numeric = 0L; +const QString * MrmlShared::m_textual = 0L; +const QString * MrmlShared::m_panel = 0L; +const QString * MrmlShared::m_clone = 0L; +const QString * MrmlShared::m_reference = 0L; + +const QString * MrmlShared::m_visibility = 0L; +const QString * MrmlShared::m_visible = 0L; +const QString * MrmlShared::m_invisible = 0L; +const QString * MrmlShared::m_popup = 0L; +// const QString * MrmlShared::m_ = 0L; + +// meta-data +const QString * MrmlShared::m_mrml_data = 0L; + +// kio_mrml tasks +const QString * MrmlShared::m_kio_task = 0L; +const QString * MrmlShared::m_kio_initialize = 0L; +const QString * MrmlShared::m_kio_startQuery = 0L; + + +int MrmlShared::s_references = 0; + +void MrmlShared::ref() +{ + if ( s_references == 0 ) + init(); + + s_references++; +} + +bool MrmlShared::deref() +{ + if ( s_references > 0 ) + s_references--; + + if ( s_references == 0 ) + { + // ### delete all strings here... + + return true; + } + + return false; +} + +void MrmlShared::init() +{ + m_sessionId = new QString ( "session-id" ) ; + m_transactionId = new QString ( "transaction-id" ) ; + m_algorithm = new QString ( "algorithm" ) ; + m_algorithmId = new QString ( "algorithm-id" ) ; + m_algorithmName = new QString ( "algorithm-name" ) ; + m_algorithmList = new QString ( "algorithm-list" ) ; + m_algorithmType = new QString ( "algorithm-type" ) ; + m_collectionId = new QString ( "collection-id" ) ; + m_collectionList = new QString ( "collection-list" ) ; + m_collection = new QString ( "collection" ) ; + m_collectionName = new QString ( "collection-name" ) ; + m_queryParadigm = new QString ( "query-paradigm" ) ; + m_queryParadigmList = new QString ( "query-paradigm-list" ) ; + m_configureSession = new QString ( "configure-session" ) ; + + m_propertySheet = new QString ( "property-sheet" ) ; + m_propertySheetId = new QString ( "property-sheet-id" ) ; + m_propertySheetType = new QString ( "property-sheet-type" ) ; + m_sendName = new QString ( "send-name" ) ; + m_sendType = new QString ( "send-type" ) ; + m_sendValue = new QString ( "send-value" ) ; + m_maxSubsetSize = new QString ( "maxsubsetsize" ) ; + m_minSubsetSize = new QString ( "minsubsetsize" ) ; + m_caption = new QString ( "caption" ) ; + m_from = new QString ( "from" ) ; + m_to = new QString ( "to" ) ; + m_step = new QString ( "step" ) ; + m_sendBooleanInverted = new QString ( "send-boolean-inverted" ) ; + + m_element = new QString ( "element" ) ; + m_attribute = new QString ( "attribute" ) ; + m_attributeName = new QString ( "attribute-name" ) ; + m_attributeValue = new QString ( "attribute-value" ) ; + m_children = new QString ( "children" ) ; + m_none = new QString ( "none" ) ; + + m_multiSet = new QString ( "multi-set" ) ; + m_subset = new QString ( "subset" ) ; + m_setElement = new QString ( "set-element" ) ; + m_boolean = new QString ( "boolean" ) ; + m_numeric = new QString ( "numeric" ) ; + m_textual = new QString ( "textual" ) ; + m_panel = new QString ( "panel" ) ; + m_clone = new QString ( "clone" ) ; + m_reference = new QString ( "reference" ) ; + + m_visibility = new QString ( "visibility" ) ; + m_visible = new QString ( "visible" ) ; + m_invisible = new QString ( "invisible" ) ; + m_popup = new QString ( "popup" ) ; +// m_ = new QString ( "" ) ; + +// meta-data + m_mrml_data = new QString ( "mrml_data" ) ; + +// kio_mrml tasks + m_kio_task = new QString ( "kio_task" ) ; + m_kio_initialize = new QString ( "kio_initialize" ) ; + m_kio_startQuery = new QString ( "kio_startQuery" ) ; +} + +void MrmlShared::cleanup() +{ + delete m_sessionId; + delete m_transactionId; + delete m_algorithm; + delete m_algorithmId; + delete m_algorithmName; + delete m_algorithmList; + delete m_algorithmType; + delete m_collectionId; + delete m_collectionList; + delete m_collection; + delete m_collectionName; + delete m_queryParadigm; + delete m_queryParadigmList; + delete m_configureSession; + + // property sheet stuff + delete m_propertySheet; + delete m_propertySheetId; + delete m_propertySheetType; + delete m_sendName; + delete m_sendType; + delete m_sendValue; + delete m_maxSubsetSize; + delete m_minSubsetSize; + delete m_caption; + delete m_from; + delete m_to; + delete m_step; + delete m_sendBooleanInverted; + + delete m_multiSet; + delete m_subset; + delete m_setElement; + delete m_boolean; + delete m_numeric; + delete m_textual; + delete m_panel; + delete m_clone; + delete m_reference; + + delete m_element; + delete m_attribute; + delete m_attributeName; + delete m_attributeValue; + delete m_children; + delete m_none; + + delete m_visibility; + delete m_visible; + delete m_invisible; + delete m_popup; +// delete m_; + + // meta-data + delete m_mrml_data; + + // kio_mrml tasks + delete m_kio_task; + delete m_kio_initialize; + delete m_kio_startQuery; + +} diff --git a/kmrml/kmrml/lib/mrml_shared.h b/kmrml/kmrml/lib/mrml_shared.h new file mode 100644 index 00000000..aff2a98d --- /dev/null +++ b/kmrml/kmrml/lib/mrml_shared.h @@ -0,0 +1,166 @@ +/* This file is part of the KDE project + Copyright (C) 2001,2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef SHARED_H +#define SHARED_H + +// maybe use mrml_const.h from libMRML, unfortunately not installed +// by gift 0.1.6pre2 + +#include +#include + +class MrmlShared +{ +public: +// attribute/element names for mrml + static void ref(); + static bool deref(); + + static const QString& sessionId() { return *m_sessionId; } + static const QString& transactionId() { return *m_transactionId; } + static const QString& algorithm() { return *m_algorithm; } + static const QString& algorithmId() { return *m_algorithmId; } + static const QString& algorithmName() { return *m_algorithmName; } + static const QString& algorithmList() { return *m_algorithmList; } + static const QString& algorithmType() { return *m_algorithmType; } + static const QString& collectionId() { return *m_collectionId; } + static const QString& collectionList() { return *m_collectionList; } + static const QString& collection() { return *m_collection; } + static const QString& collectionName() { return *m_collectionName; } + static const QString& queryParadigm() { return *m_queryParadigm; } + static const QString& queryParadigmList() { return *m_queryParadigmList; } + static const QString& configureSession() { return *m_configureSession; } + + // property sheet stuff + static const QString& propertySheet() { return *m_propertySheet; } + static const QString& propertySheetId() { return *m_propertySheetId; } + static const QString& propertySheetType() { return *m_propertySheetType; } + static const QString& sendName() { return *m_sendName; } + static const QString& sendType() { return *m_sendType; } + static const QString& sendValue() { return *m_sendValue; } + static const QString& maxSubsetSize() { return *m_maxSubsetSize; } + static const QString& minSubsetSize() { return *m_minSubsetSize; } + static const QString& caption() { return *m_caption; } + static const QString& from() { return *m_from; } + static const QString& to() { return *m_to; } + static const QString& step() { return *m_step; } + static const QString& sendBooleanInverted() { return *m_sendBooleanInverted; } + + static const QString& multiSet() { return *m_multiSet; } + static const QString& subset() { return *m_subset; } + static const QString& setElement() { return *m_setElement; } + static const QString& boolean() { return *m_boolean; } + static const QString& numeric() { return *m_numeric; } + static const QString& textual() { return *m_textual; } + static const QString& panel() { return *m_panel; } + static const QString& clone() { return *m_clone; } + static const QString& reference() { return *m_reference; } + + static const QString& element() { return *m_element; } + static const QString& attribute() { return *m_attribute; } + static const QString& attributeName() { return *m_attributeName; } + static const QString& attributeValue() { return *m_attributeValue; } + static const QString& children() { return *m_children; } + static const QString& none() { return *m_none; } + + static const QString& visibility() { return *m_visibility; } + static const QString& visible() { return *m_visible; } + static const QString& invisible() { return *m_invisible; } + static const QString& popup() { return *m_popup; } +// static const QString& () { return *m_; } + + // meta-data + static const QString& mrml_data() { return *m_mrml_data; } + + // kio_mrml tasks + static const QString& kio_task() { return *m_kio_task; } + static const QString& kio_initialize() { return *m_kio_initialize; } + static const QString& kio_startQuery() { return *m_kio_startQuery; } + + +private: + static const QString * m_sessionId; + static const QString * m_transactionId; + static const QString * m_algorithm; + static const QString * m_algorithmId; + static const QString * m_algorithmName; + static const QString * m_algorithmList; + static const QString * m_algorithmType; + static const QString * m_collectionId; + static const QString * m_collectionList; + static const QString * m_collection; + static const QString * m_collectionName; + static const QString * m_queryParadigm; + static const QString * m_queryParadigmList; + static const QString * m_configureSession; + + // property sheet stuff + static const QString * m_propertySheet; + static const QString * m_propertySheetId; + static const QString * m_propertySheetType; + static const QString * m_sendName; + static const QString * m_sendType; + static const QString * m_sendValue; + static const QString * m_maxSubsetSize; + static const QString * m_minSubsetSize; + static const QString * m_caption; + static const QString * m_from; + static const QString * m_to; + static const QString * m_step; + static const QString * m_sendBooleanInverted; + + static const QString * m_multiSet; + static const QString * m_subset; + static const QString * m_setElement; + static const QString * m_boolean; + static const QString * m_numeric; + static const QString * m_textual; + static const QString * m_panel; + static const QString * m_clone; + static const QString * m_reference; + + static const QString * m_element; + static const QString * m_attribute; + static const QString * m_attributeName; + static const QString * m_attributeValue; + static const QString * m_children; + static const QString * m_none; + + static const QString * m_visibility; + static const QString * m_visible; + static const QString * m_invisible; + static const QString * m_popup; +// static const QString * m_; + + // meta-data + static const QString * m_mrml_data; + + // kio_mrml tasks + static const QString * m_kio_task; + static const QString * m_kio_initialize; + static const QString * m_kio_startQuery; + +private: + static void cleanup(); + static void init(); + + static int s_references; +}; + +#endif // SHARED_H diff --git a/kmrml/kmrml/lib/mrml_utils.cpp b/kmrml/kmrml/lib/mrml_utils.cpp new file mode 100644 index 00000000..f20dad6a --- /dev/null +++ b/kmrml/kmrml/lib/mrml_utils.cpp @@ -0,0 +1,89 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include + +#include "watcher_stub.h" + +#include "mrml_utils.h" + +// after 100 of no use, terminate the mrmld +#define TIMEOUT 100 +// how often to restart the mrmld in case of failure +#define NUM_RESTARTS 5 + +using namespace KMrml; + +KStaticDeleter utils_sd; + +Util *Util::s_self = 0L; + +Util::Util() +{ + // we need our own dcopclient, when used in kio_mrml + if ( !DCOPClient::mainClient() ) + { + DCOPClient::setMainClient( new DCOPClient() ); + if ( !DCOPClient::mainClient()->attach() ) + qWarning( "kio_mrml: Can't attach to DCOP Server."); + } +} + +Util::~Util() +{ + if ( this == s_self ) + s_self = 0L; +} + +Util *Util::self() +{ + if ( !s_self ) + s_self = utils_sd.setObject( new Util() ); + return s_self; +} + +bool Util::requiresLocalServerFor( const KURL& url ) +{ + return url.host().isEmpty() || url.host() == "localhost"; +} + +bool Util::startLocalServer( const Config& config ) +{ + if ( config.serverStartedIndividually() ) + return true; + + DCOPClient *client = DCOPClient::mainClient(); + + // ### check if it's already running (add dcop method to Watcher) + Watcher_stub watcher( client, "kded", "daemonwatcher"); + return ( watcher.requireDaemon( client->appId(), + "mrmld", config.mrmldCommandline(), + TIMEOUT, NUM_RESTARTS ) + && watcher.ok() ); +} + +void Util::unrequireLocalServer() +{ + DCOPClient *client = DCOPClient::mainClient(); + + Watcher_stub watcher( client, "kded", "daemonwatcher"); + watcher.unrequireDaemon( client->appId(), "mrmld" ); +} diff --git a/kmrml/kmrml/lib/mrml_utils.h b/kmrml/kmrml/lib/mrml_utils.h new file mode 100644 index 00000000..25f39d98 --- /dev/null +++ b/kmrml/kmrml/lib/mrml_utils.h @@ -0,0 +1,50 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +#ifndef MRML_UTILS_H +#define MRML_UTILS_H + +#include + +#include + +#include "kmrml_config.h" + +namespace KMrml +{ + class Util : public QObject + { + public: + static Util * self(); + ~Util(); + + bool requiresLocalServerFor( const KURL& url ); + bool startLocalServer( const Config& config ); + void unrequireLocalServer(); +// bool isLocalServerRunning(); + + private: + static Util *s_self; + Util(); + }; + + +} + +#endif // MRML_UTILS_H diff --git a/kmrml/kmrml/lib/version.h b/kmrml/kmrml/lib/version.h new file mode 100644 index 00000000..5cf8e270 --- /dev/null +++ b/kmrml/kmrml/lib/version.h @@ -0,0 +1,6 @@ +#ifndef VERSION_H +#define VERSION_H + +#define KMRML_VERSION "0.3.2" + +#endif // VERSION_H diff --git a/kmrml/kmrml/lib/watcher_stub.cpp b/kmrml/kmrml/lib/watcher_stub.cpp new file mode 100644 index 00000000..cf84818b --- /dev/null +++ b/kmrml/kmrml/lib/watcher_stub.cpp @@ -0,0 +1,95 @@ +// +// Generated in ../server/ via dcopidl -- needs to be in the lib tho. +// Regenerate when necessary by uncommenting the watcher.stub in +// ../server/Makefile.am +// + +#include "watcher_stub.h" +#include + +#include + +namespace KMrml { + +Watcher_stub::Watcher_stub( const QCString& app, const QCString& obj ) + : DCOPStub( app, obj ) +{ +} + +Watcher_stub::Watcher_stub( DCOPClient* client, const QCString& app, const QCString& obj ) + : DCOPStub( client, app, obj ) +{ +} + +bool Watcher_stub::requireDaemon( const QCString& arg0, const QString& arg1, const QString& arg2, uint arg3, int arg4 ) +{ + bool result; + if ( !dcopClient() ) { + setStatus( CallFailed ); + return false; + } + QByteArray data, replyData; + QCString replyType; + QDataStream arg( data, IO_WriteOnly ); + arg << arg0; + arg << arg1; + arg << arg2; + arg << arg3; + arg << arg4; + if ( dcopClient()->call( app(), obj(), "requireDaemon(QCString,QString,QString,uint,int)", data, replyType, replyData ) ) { + if ( replyType == "bool" ) { + QDataStream _reply_stream( replyData, IO_ReadOnly ); + _reply_stream >> result; + setStatus( CallSucceeded ); + } else { + callFailed(); + } + } else { + callFailed(); + } + return result; +} + +void Watcher_stub::unrequireDaemon( const QCString& arg0, const QString& arg1 ) +{ + if ( !dcopClient() ) { + setStatus( CallFailed ); + return; + } + QByteArray data, replyData; + QCString replyType; + QDataStream arg( data, IO_WriteOnly ); + arg << arg0; + arg << arg1; + if ( dcopClient()->call( app(), obj(), "unrequireDaemon(QCString,QString)", data, replyType, replyData ) ) { + setStatus( CallSucceeded ); + } else { + callFailed(); + } +} + +QStringList Watcher_stub::runningDaemons() +{ + QStringList result; + if ( !dcopClient() ) { + setStatus( CallFailed ); + return result; + } + QByteArray data, replyData; + QCString replyType; + if ( dcopClient()->call( app(), obj(), "runningDaemons()", data, replyType, replyData ) ) { + if ( replyType == "QStringList" ) { + QDataStream _reply_stream( replyData, IO_ReadOnly ); + _reply_stream >> result; + setStatus( CallSucceeded ); + } else { + callFailed(); + } + } else { + callFailed(); + } + return result; +} + +} // namespace + diff --git a/kmrml/kmrml/lib/watcher_stub.h b/kmrml/kmrml/lib/watcher_stub.h new file mode 100644 index 00000000..04b1292e --- /dev/null +++ b/kmrml/kmrml/lib/watcher_stub.h @@ -0,0 +1,36 @@ +// +// Generated in ../server/ via dcopidl -- needs to be in the lib tho. +// Regenerate when necessary by uncommenting the watcher.stub in +// ../server/Makefile.am +// + +#ifndef __WATCHER_STUB__ +#define __WATCHER_STUB__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace KMrml { + +class Watcher_stub : public DCOPStub +{ +public: + Watcher_stub( const QCString& app, const QCString& id ); + Watcher_stub( DCOPClient* client, const QCString& app, const QCString& id ); + virtual bool requireDaemon( const QCString& clientAppId, const QString& daemonKey, const QString& commandline, uint timeout, int numRestarts ); + virtual void unrequireDaemon( const QCString& clientAppId, const QString& daemonKey ); + virtual QStringList runningDaemons(); +protected: + Watcher_stub() : DCOPStub( never_use ) {}; +}; + +} // namespace + +#endif diff --git a/kmrml/kmrml/loader.cpp b/kmrml/kmrml/loader.cpp new file mode 100644 index 00000000..cc59c172 --- /dev/null +++ b/kmrml/kmrml/loader.cpp @@ -0,0 +1,121 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include + +#include "loader.h" + +Loader *Loader::s_self = 0L; + +KStaticDeleter sd; + +Loader * Loader::self() +{ + if ( !s_self ) + s_self = sd.setObject( new Loader() ); + + return s_self; +} + +Loader::Loader() : QObject() +{ +} + +Loader::~Loader() +{ + disconnect( this, SIGNAL( finished( const KURL&, const QByteArray& ))); + + DownloadIterator it = m_downloads.begin(); + for ( ; it != m_downloads.end(); ++it ) { + it.key()->kill(); + delete it.data(); + } + + s_self = 0L; +} + +void Loader::requestDownload( const KURL& url ) +{ + DownloadIterator it = m_downloads.begin(); + for ( ; it != m_downloads.end(); ++it ) { + if ( it.key()->url() == url ) + return; + } + + KIO::TransferJob *job = KIO::get( url, false, false ); + KIO::Scheduler::scheduleJob(job); + + connect( job , SIGNAL( data( KIO::Job *, const QByteArray& )), + SLOT( slotData( KIO::Job *, const QByteArray& ))); + connect( job , SIGNAL( result( KIO::Job * )), + SLOT( slotResult( KIO::Job * ))); + + Download *d = new Download(); + m_downloads.insert( job, d ); +} + +void Loader::slotData( KIO::Job *job, const QByteArray& data ) +{ + DownloadIterator it = m_downloads.find( static_cast(job) ); + if ( it != m_downloads.end() ) { + QBuffer& buffer = it.data()->m_buffer; + if ( !buffer.isOpen() ) + buffer.open( IO_ReadWrite ); + if ( !buffer.isOpen() ) { + qDebug("********* EEK, can't open buffer for thumbnail download!"); + return; + } + + buffer.writeBlock( data.data(), data.size() ); + } +} + +void Loader::slotResult( KIO::Job *job ) +{ + KIO::TransferJob *tjob = static_cast( job ); + + DownloadIterator it = m_downloads.find( tjob ); + if ( it != m_downloads.end() ) { + Download *d = it.data(); + + if ( job->error() != 0 ) + emit finished( tjob->url(), QByteArray() ); + else + emit finished( tjob->url(), d->m_buffer.buffer() ); + + delete d; + m_downloads.remove( it ); + } +} + + +// ### simultaneous downloads with multiple views? reference count downloads! +void Loader::removeDownload( const KURL& url ) +{ + DownloadIterator it = m_downloads.begin(); + for ( ; it != m_downloads.end(); ++it ) { + if ( it.key()->url() == url ) { + it.key()->kill(); + delete it.data(); + return; + } + } +} + +#include "loader.moc" diff --git a/kmrml/kmrml/loader.h b/kmrml/kmrml/loader.h new file mode 100644 index 00000000..5e81a2e4 --- /dev/null +++ b/kmrml/kmrml/loader.h @@ -0,0 +1,72 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef LOADER_H +#define LOADER_H + +#include +#include +#include +#include + +#include +#include + +class Download +{ +public: + ~Download() { + if ( m_buffer.isOpen() ) + m_buffer.close(); + } + QBuffer m_buffer; + // add context of MrmlPart for progress? +}; + + +class Loader : public QObject +{ + friend class gcc_sucks; + Q_OBJECT + +public: + static Loader *self(); + ~Loader(); + + void requestDownload( const KURL& url ); + + void removeDownload( const KURL& url ); + +signals: + void finished( const KURL& url, const QByteArray& ); + +private slots: + void slotData( KIO::Job *, const QByteArray& ); + void slotResult( KIO::Job * ); + +private: + Loader(); + + QMap m_downloads; + typedef QMapIterator DownloadIterator; + + static Loader *s_self; + +}; + +#endif // LOADER_H diff --git a/kmrml/kmrml/mrml-servicemenu.desktop b/kmrml/kmrml/mrml-servicemenu.desktop new file mode 100644 index 00000000..2d9a938c --- /dev/null +++ b/kmrml/kmrml/mrml-servicemenu.desktop @@ -0,0 +1,67 @@ +[Desktop Entry] +ServiceTypes=image/png,image/jpeg,image/gif,image/tiff,image/bmp,image/x-xpm,image/x-xbm,image/x-png +Actions=search; + +[Desktop Action search] +Name=Search for Similar Images... +Name[af]=Soektog vir Soortgelyk Beelde... +Name[ar]=بحث عن الصور المتشابهه... +Name[bg]=Търсене на подобни изображения... +Name[bs]=Traženje sličnih slika... +Name[ca]=Cerca imatges similars... +Name[cs]=Hledat podobný obrázek... +Name[cy]=Chwilio am Ddelweddau Tebyg... +Name[da]=Søg efter lignende filer... +Name[de]=Nach ähnlichen Bildern suchen ... +Name[el]=Αναζήτηση για παρόμοιες εικόνες... +Name[eo]=Serĉi Similajn Bildojn... +Name[es]=Búsqueda de imágenes similares... +Name[et]=Otsi sarnaseid pilte... +Name[eu]=Bilatu antzeko irudiak... +Name[fa]=جستجو برای تصاویر مشابه... +Name[fi]=Etsi samankaltaisia kuvia... +Name[fr]=Recherche d'images semblables... +Name[gl]=Procurar imaxes semellantes... +Name[he]=חיפוש תמונות דומות... +Name[hi]=एक जैसे छवियों के लिए ढूंढें... +Name[hu]=Ehhez hasonló képek keresése... +Name[is]=Leita að svipuðum myndum... +Name[it]=Cerca immagini simili... +Name[ja]=同じような画像を検索... +Name[kk]=Ұқсас кескіндерді іздеу... +Name[km]=ស្វែងរក​រូបភាព​ស្រដៀង​គ្នា... +Name[lt]=Panašių paveikslėlių paieška... +Name[ms]=Cari Imej Serupa... +Name[nb]=Søk etter liknende bilder … +Name[nds]=Na lieke Biller söken... +Name[ne]=उस्तै छविका लागि खोजी गर्नुहोस्... +Name[nl]=Zoeken naar vergelijkbare afbeeldingen... +Name[nn]=Søk etter liknande bilete … +Name[nso]=Nyako ya Diponagalo tseo di Swanago... +Name[pl]=Szukaj podobnych obrazków +Name[pt]=Procurar por Imagens Semelhantes... +Name[pt_BR]=Procurar por Imagens Parecidas... +Name[ro]=Caută imagini similare... +Name[ru]=Поиск похожих изображений... +Name[se]=Oza seammalágana govaid … +Name[sk]=Hľadať podobné obrázky... +Name[sl]=Išči podobne slike ... +Name[sr]=Потражи сличне слике... +Name[sr@Latn]=Potraži slične slike... +Name[sv]=Sök efter liknande bilder... +Name[ta]=இதே போன்ற பிம்பங்களை தேடுக... +Name[tg]=Ҷустуҷӯи тасвироти якхела... +Name[th]=ค้นหาภาพที่เหมือนกัน... +Name[tr]=Benzer Resimleri Ara... +Name[uk]=Пошук схожих зображень... +Name[uz]=Oʻxshash rasmlarni qidirish +Name[uz@cyrillic]=Ўхшаш расмларни қидириш +Name[ven]=Todani zwifanyiso zwielanaho... +Name[wa]=Cweri après des rshonnantès imådjes... +Name[xh]=Phendla Imifanekiso Efanayo... +Name[zh_CN]=搜索类似图像... +Name[zh_HK]=尋找類似的圖像... +Name[zh_TW]=尋找類似的影像... +Name[zu]=Sesha ukuthola Izithombe Ezifanayo.... +Icon=image +Exec=mrmlsearch %U diff --git a/kmrml/kmrml/mrml.cpp b/kmrml/kmrml/mrml.cpp new file mode 100644 index 00000000..082d037b --- /dev/null +++ b/kmrml/kmrml/mrml.cpp @@ -0,0 +1,267 @@ +/* This file is part of the KDE project + Copyright (C) 2001,2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#include +#include +#include +#include + +#include + +#include "mrml.h" + +extern "C" { + KDE_EXPORT int kdemain( int argc, char **argv ) + { + KLocale::setMainCatalogue("kdelibs"); + KInstance instance( "kio_mrml" ); + KGlobal::locale()->insertCatalogue( "kmrml" ); + + kdDebug() << "Starting MRML " << getpid() << endl; + + if (argc != 4) + { + fprintf(stderr, "Usage: kio_mrml protocol domain-socket1 domain-socket2\n"); + exit(-1); + } + + Mrml slave(argv[2], argv[3]); + slave.dispatchLoop(); + + kdDebug() << "Done" << endl; + return 0; + } +} + +const int Mrml::bufsize = 8192; + +Mrml::Mrml( const QCString& pool_socket, const QCString& app_socket ) + : TCPSlaveBase( 12789, "mrml", pool_socket, app_socket ), + m_config( KGlobal::config() ) +{ + MrmlShared::ref(); +} + +Mrml::~Mrml() +{ + KMrml::Util::self()->unrequireLocalServer(); + + closeDescriptor(); + MrmlShared::deref(); +} + +bool Mrml::checkLocalServer( const KURL& url ) +{ + if ( KMrml::Util::self()->requiresLocalServerFor( url ) ) + { + if ( !KMrml::Util::self()->startLocalServer( m_config ) ) + return false; + } + + return true; +} + +void Mrml::get( const KURL& url ) +{ +// qDebug("******* getting: %s (user: %s)", url.url().latin1(), url.user().latin1()); + + if ( !checkLocalServer( url ) ) + { + error( KIO::ERR_SLAVE_DEFINED, i18n("Unable to start the Indexing Server. " + "Aborting the query.") ); + return; + } + + int retriesLeft = 5; +tryConnect: + + QCString utf8; + bool sendError = (retriesLeft <= 0); + + if ( connectToHost( url.host(), port(url), sendError ) ) + { +// qDebug(" connected!"); + + QString task = metaData( MrmlShared::kio_task() ); + + if ( task == MrmlShared::kio_initialize() ) { + startSession( url ); + } + + else if ( task == MrmlShared::kio_startQuery() ) { + QString meta = metaData( MrmlShared::mrml_data() ); + if ( meta.isEmpty() ) { + closeDescriptor(); + error( KIO::ERR_SLAVE_DEFINED, i18n("No MRML data is available.") ); + return; + } + + utf8 = meta.utf8(); + write( utf8, utf8.length() ); + + emitData( readAll() ); + } + + // no task metadata available, we're called from KonqRun or something + // like that. Emitting the mimetype seems to suffice for now. After + // that, MrmlPart is going to start and start the get() again. + else + { + mimeType( "text/mrml" ); + finished(); + } + + } + else + { + if ( retriesLeft-- >= 0 ) + { +#ifdef HAVE_USLEEP + usleep( 500 ); // wait a while for gift to start up +#endif + goto tryConnect; + return; + } + + error( KIO::ERR_COULD_NOT_CONNECT, + i18n("Could not connect to GIFT server.") ); + return; + } + + closeDescriptor(); + //data( QByteArray() ); // send an empty QByteArray to signal end of data. + finished(); +} + +// make sure we're connected when you call this! +QCString Mrml::readAll() +{ + QCString data; + + char buf[bufsize]; + ssize_t bytes = 0; + + while ( (bytes = read( buf, bufsize-1 )) > 0 ) { + buf[bytes] = '\0'; + data.append( buf ); + } + +// qDebug("*** readAll()::: %i, %s", data.length(), data.data()); + return data; +} + +QCString Mrml::loginString() +{ + return ""; +} + +QCString Mrml::getConfigurationString() +{ + return ""; +} + +// ### needed? +QCString Mrml::getSessionsString( const QString& username, + const QString& password ) +{ + QCString data = "" ); + + return data; +} + + +bool Mrml::startSession( const KURL& url ) +{ + // might first ask for collections, and then for algorithms for the + // desired collection-id + + // Wolfgang says, we shouldn't create an own session-id here, as gcc 2.95 + // apparently makes problems in exception handling somehow. So we simply + // accept the server's session-id. + QString msg = mrmlString( QString::null ).arg( + " \ + \ + \ + " ).arg( user( url )); + + QCString utf8 = msg.utf8(); +// qDebug(":::Writing: %s", utf8.data()); + write( utf8, utf8.length() ); + + emitData( readAll() ); + + return true; +} + +QString Mrml::mrmlString( const QString& sessionId, const QString& transactionId ) +{ + QString msg = + " \ + \ + %1 \ + "; + + if ( sessionId.isEmpty() ) // when we don't have one yet + return msg.arg( "%1" ); + + if ( transactionId.isNull() ) + return msg.arg( "%1" ).arg( sessionId ); + else + return msg.arg( "%1") + .arg( sessionId ).arg( transactionId ); +} + +void Mrml::emitData( const QCString& msg ) +{ + mimeType( "text/mrml" ); + data( msg ); + processedSize( msg.count() ); +} + +void Mrml::mimetype( const KURL& url ) +{ + if ( url.protocol() == "mrml" ) { + mimeType( "text/mrml" ); + finished(); + } + else + KIO::TCPSlaveBase::mimetype( url ); +} diff --git a/kmrml/kmrml/mrml.desktop b/kmrml/kmrml/mrml.desktop new file mode 100644 index 00000000..73abf1e0 --- /dev/null +++ b/kmrml/kmrml/mrml.desktop @@ -0,0 +1,60 @@ +[Desktop Entry] +Comment=Multimedia Retrieval Markup Language Document +Comment[af]=Multimedia Onttrekking Opmerk Taal Dokument +Comment[ar]=مستند لغة ترميز استرجاع الوسائط المتعددة +Comment[bs]=Multimedia Retrieval Markup Language dokument +Comment[ca]=Document de llenguatge de marcatge de recuperació multimèdia +Comment[cs]=Multimedia Retrieval Markup Language dokument +Comment[cy]=Dogfen Multimedia Retrieval Markup Language +Comment[da]=Multimedia Retrieval Markup Language-dokument +Comment[de]=Multimedia Suche- und Beschreibungssprache-Dokument (MRML-Dokument) +Comment[el]=Έγγραφο Multimedia Retrieval Markup Language +Comment[es]=Documento de lenguaje de descripción de descargas multimedia +Comment[et]=Multimeedia otsingu märgistuskeele (MRML) dokument +Comment[eu]=Multimedia Retrieval Markup Language dokumentua +Comment[fa]=سند زبان نشان‌گذاری بازیابی چند رسانه‌ای +Comment[fi]=Multimedianhakuasiakirja +Comment[fr]=Document en langage Multimedia Retrieval Markup (MRML) +Comment[he]=מסמך שפת סימון לאחזור מולטימדיה +Comment[hi]=मल्टीमीडिया रिट्राइवल मार्कअप लैंग्वेज दस्तावेज़ +Comment[hu]=MRML-fájl +Comment[is]=Multimedia Retrieval Markup Language skjal +Comment[it]=Documento MRML +Comment[ja]=Multimedia Retrieval Markup Language ドキュメント +Comment[kk]=MRML (Multimedia Retrieval Markup Language) құжаты +Comment[km]=ឯកសារ Multimedia Retrieval Markup Language +Comment[lt]=Multimedia Retrieval Markup kalbos dokumentas +Comment[ms]=Dokumen Bahasa Capaian Tandatas Multimedia +Comment[nb]=«Multimedia Retrieval Markup Language»-dokument +Comment[nds]=Dokment in de Affraag-Utteekspraak för Multimedia-Dokmenten +Comment[ne]=मल्टिमिडिया पुन: प्राप्ति मार्कअप भाषा कागजात +Comment[nl]=Multimedia Retrieval Markup Language-document +Comment[nn]=«Multimedia Retrieval Markup Language»-dokument +Comment[nso]=Tokomane ya Leleme la Peakanyo ya Kutullo ya Multimedia +Comment[pl]=Dokument MRML (Język Znacznikowy Pozyskiwania Multimediów) +Comment[pt]=Documento de Multimedia Retrieval Markup Language +Comment[pt_BR]=Documento da Linguagem de Marcação de Recuperação Multimídia +Comment[ro]=Document MRML (limbaj de marcare pentru căutări multimedia) +Comment[ru]=Документ MRML (Multimedia Retrieval Markup Language) +Comment[se]=«Multimedia Retrieval Markup Language»-dokumeanta +Comment[sk]=Dokument Multimedia Retrieval Markup Language +Comment[sl]=Dokument Multimedia Retrieval Markup Language +Comment[sr]=Документ у обележивачком језику за добављање мултимедије (MRML) +Comment[sr@Latn]=Dokument u obeleživačkom jeziku za dobavljanje multimedije (MRML) +Comment[sv]=Multimedia Retrieval Markup Language-dokument +Comment[ta]=பல் ஊடக திரும்பப்பெறு அடையாள மொழி ஆவணம் +Comment[tg]=Санади MRML (Multimedia Retrieval Markup Language) +Comment[th]=เอกสาร Multimedia Retrieval Markup Language +Comment[tr]=Multimedia Retrieval Markup Language Belgesi +Comment[uk]=Документ формату зберігання мультимедіа +Comment[ven]=Manwalwa a luambo lwau humbula zwa khasho nnzhi +Comment[xh]=Uxwebhu Lolwimi Lophawulo phezulu Lokufumana i Multimedia +Comment[zh_CN]=多媒体检索标记语言文档 +Comment[zh_HK]=多媒體取得標記語言文件 +Comment[zh_TW]=多媒體補償標記語言文件 +Comment[zu]=Ushicilelo Lwe-Multimedia Retrieval Markup Language +Icon=html +Type=MimeType +MimeType=text/mrml +Patterns=*.mrml;*.MRML; +X-KDE-AutoEmbed=true diff --git a/kmrml/kmrml/mrml.h b/kmrml/kmrml/mrml.h new file mode 100644 index 00000000..f8088ef6 --- /dev/null +++ b/kmrml/kmrml/mrml.h @@ -0,0 +1,84 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef MRML_H +#define MRML_H + + +#include +#include + +#include +#include "mrml_shared.h" + +class Mrml : public KIO::TCPSlaveBase +{ +public: + Mrml( const QCString&, const QCString& ); + ~Mrml(); + + virtual void get( const KURL& url ); + + virtual void mimetype( const KURL& url ); + +private: + QCString readAll(); + void emitData( const QCString& ); + + bool startSession( const KURL& url ); + + // helpers + inline QString sessionId() { + return metaData( MrmlShared::sessionId() ); + } + + // misc + short int port( const KURL& url ) + { + return (url.port() != 0) ? + url.port() : + m_config.settingsForHost( url.host() ).port(); + } + + static QString mrmlString( const QString& sessionId, + const QString& transactionId = QString::null ); + + static QCString loginString(); + static QCString getConfigurationString(); + static QCString getSessionsString( const QString& username, + const QString& password ); + QString user( const KURL& url ) { + return url.hasUser() ? + url.user() : m_config.defaultSettings().user; + } + QString pass( const KURL& url ) { + return url.hasPass() ? + url.pass() : m_config.defaultSettings().pass; + } + + bool checkLocalServer( const KURL& url ); + + static const int bufsize; + QString defaultUser; + QString defaultPass; + + KMrml::Config m_config; + +}; + +#endif // MRML_H diff --git a/kmrml/kmrml/mrml.protocol b/kmrml/kmrml/mrml.protocol new file mode 100644 index 00000000..c3a732eb --- /dev/null +++ b/kmrml/kmrml/mrml.protocol @@ -0,0 +1,10 @@ +[Protocol] +exec=kio_mrml +protocol=mrml +input=none +output=filesystem +reading=true +defaultMimetype=text/mrml +determineMimetypeFromExtension=false +Icon=image +DocPath=kioslave/mrml.html diff --git a/kmrml/kmrml/mrml_creator.cpp b/kmrml/kmrml/mrml_creator.cpp new file mode 100644 index 00000000..fce84e36 --- /dev/null +++ b/kmrml/kmrml/mrml_creator.cpp @@ -0,0 +1,76 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "mrml_creator.h" + +QDomElement MrmlCreator::createMrml( QDomDocument& doc, + const QString& sessionId, + const QString& transactionId ) +{ + QDomElement mrml = doc.createElement( "mrml" ); + doc.appendChild( mrml ); + mrml.setAttribute( MrmlShared::sessionId(), sessionId ); + if ( !transactionId.isNull() ) + mrml.setAttribute( MrmlShared::transactionId(), transactionId ); + + return mrml; +} + +QDomElement MrmlCreator::configureSession( QDomElement& mrml, + const KMrml::Algorithm& algo, + const QString& sessionId ) +{ + QDomDocument doc = mrml.ownerDocument(); + QDomElement config = doc.createElement( MrmlShared::configureSession() ); + mrml.appendChild( config ); + config.setAttribute( MrmlShared::sessionId(), sessionId ); + algo.toElement( config ); + + return config; +} + +QDomElement MrmlCreator::addQuery( QDomElement& mrml, int resultSize ) +{ + QDomElement query = mrml.ownerDocument().createElement("query-step"); + mrml.appendChild( query ); + // query.setAttribute( "query-step-id", "5" ); // ### + query.setAttribute( "result-size", QString::number( resultSize )); + return query; +} + +QDomElement MrmlCreator::addRelevanceList( QDomElement& query ) +{ + QDomElement elem = + query.ownerDocument().createElement("user-relevance-element-list"); + query.appendChild( elem ); + return elem; +} + +/** + * Creates a with the given attributes set. + */ +void MrmlCreator::createRelevanceElement( QDomDocument& doc, + QDomElement& parent, + const QString& url, + Relevance relevance ) +{ + QDomElement element = doc.createElement( "user-relevance-element" ); + element.setAttribute( "image-location", url ); + element.setAttribute( "user-relevance", QString::number( relevance ) ); + parent.appendChild( element ); +} diff --git a/kmrml/kmrml/mrml_creator.h b/kmrml/kmrml/mrml_creator.h new file mode 100644 index 00000000..2cc59e7a --- /dev/null +++ b/kmrml/kmrml/mrml_creator.h @@ -0,0 +1,49 @@ +/* This file is part of the KDE project + Copyright (C) 2001,2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef MRML_CREATOR_H +#define MRML_CREATOR_H + +#include + +#include + +#include "mrml_elements.h" +#include "mrml_shared.h" + +namespace MrmlCreator +{ + enum Relevance { Relevant = 1, Irrelevant = -1 }; + + QDomElement createMrml( QDomDocument& doc, + const QString& sessionId, + const QString& transactionId = QString::null ); + QDomElement configureSession( QDomElement& mrml, + const KMrml::Algorithm& algo, + const QString& sessionId ); + QDomElement addQuery( QDomElement& mrml, int resultSize ); + QDomElement addRelevanceList( QDomElement& query ); + /** + * Creates a with the given attributes set. + */ + void createRelevanceElement( QDomDocument& doc, QDomElement& parent, + const QString& url, Relevance relevance ); + +} + +#endif // MRML_CREATOR_H diff --git a/kmrml/kmrml/mrml_elements.cpp b/kmrml/kmrml/mrml_elements.cpp new file mode 100644 index 00000000..20f3d04e --- /dev/null +++ b/kmrml/kmrml/mrml_elements.cpp @@ -0,0 +1,358 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "mrml_elements.h" +#include "mrml_shared.h" + +#include + +#include + +using namespace KMrml; + +// +// MrmlElement is currently the baseclass for Algorithm and Collection. Both +// may have a single child-element , with a number of +// elements as children. +// + +MrmlElement::MrmlElement( const QDomElement& elem ) +{ + QValueList list = + KMrml::directChildElements( elem, MrmlShared::queryParadigmList() ); + + Q_ASSERT( list.count() < 2 ); // There can be only one. + + if ( list.count() ) + m_paradigms.initFromDOM( list.first() ); +} + + +void MrmlElement::setOtherAttributes( QDomElement& elem ) const +{ + QMapConstIterator it = m_attributes.begin(); + for ( ; it != m_attributes.end(); ++it ) + { + elem.setAttribute( it.key(), it.data() ); + } +} + + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// + + +AlgorithmList AlgorithmList::algorithmsForCollection( const Collection& coll ) const +{ + AlgorithmList list; + + AlgorithmList::ConstIterator it = begin(); + for ( ; it != end(); ++it ) + { + Algorithm algo = *it; + if ( algo.paradigms().matches( coll.paradigms() ) ) + { + algo.setCollectionId( coll.id() ); + list.append( algo ); + } + } + + return list; +} + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// + + +Collection::Collection( const QDomElement& elem ) + : MrmlElement( elem ) +{ + QDomNamedNodeMap attrs = elem.attributes(); + for ( uint i = 0; i < attrs.length(); i++ ) + { + QDomAttr attribute = attrs.item( i ).toAttr(); + QString name = attribute.name(); + + if ( name == MrmlShared::collectionName() ) + m_name = attribute.value(); + else if ( name == MrmlShared::collectionId() ) + m_id = attribute.value(); + + else // custom attributes + m_attributes.insert( name, attribute.value() ); + } +} + + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// + + +Algorithm::Algorithm( const QDomElement& elem ) + : MrmlElement( elem ) +{ + QDomNamedNodeMap attrs = elem.attributes(); + + for ( uint i = 0; i < attrs.length(); i++ ) + { + QDomAttr attribute = attrs.item( i ).toAttr(); + QString name = attribute.name(); + + if ( name == MrmlShared::algorithmName() ) + m_name = attribute.value(); + else if ( name == MrmlShared::algorithmId() ) + m_id = attribute.value(); + else if ( name == MrmlShared::algorithmType() ) + m_type = attribute.value(); + + // not really necessary + else if ( name == MrmlShared::collectionId() ) + m_collectionId = attribute.value(); + + else // custom attributes + m_attributes.insert( name, attribute.value() ); + } + + QDomElement propsElem = firstChildElement(elem, MrmlShared::propertySheet()); + m_propertySheet.initFromDOM( propsElem ); + + qDebug("############# new algorithm: name: %s, id: %s, type: %s", m_name.latin1(), m_id.latin1(), m_type.latin1()); +} + +Algorithm Algorithm::defaultAlgorithm() +{ + Algorithm algo; + algo.m_id = "adefault"; + algo.m_type = "adefault"; // ### not in the DTD + algo.m_name = "dummy"; + + return algo; +} + +QDomElement Algorithm::toElement( QDomElement& parent ) const +{ + QDomDocument doc = parent.ownerDocument(); + QDomElement algorithm = doc.createElement( MrmlShared::algorithm() ); + parent.appendChild( algorithm ); + setOtherAttributes( algorithm ); + + if ( !m_name.isEmpty() ) + algorithm.setAttribute( MrmlShared::algorithmName(), m_name ); + if ( !m_id.isEmpty() ) + algorithm.setAttribute( MrmlShared::algorithmId(), m_id ); + if ( !m_type.isEmpty() ) + algorithm.setAttribute( MrmlShared::algorithmType(), m_type ); + + if ( !m_collectionId.isEmpty() ) + algorithm.setAttribute( MrmlShared::collectionId(), m_collectionId ); + return algorithm; +} + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// + + +QueryParadigm::QueryParadigm( const QDomElement& elem ) +{ + QDomNamedNodeMap attrs = elem.attributes(); + for ( uint i = 0; i < attrs.count(); i++ ) + { + QDomAttr attr = attrs.item( i ).toAttr(); + m_attributes.insert( attr.name(), attr.value() ); + if ( attr.name() == "type" ) + m_type = attr.value(); + } +} + +bool QueryParadigm::matches( const QueryParadigm& other ) const +{ + return m_attributes.isEmpty() || other.m_attributes.isEmpty() || + equalMaps( m_attributes, other.m_attributes ); +} + +bool QueryParadigm::equalMaps( const QMap m1, + const QMap m2 ) +{ + if ( m1.count() != m2.count() ) + return false; + + QMapConstIterator it = m1.begin(); + for ( ; it != m1.end(); ++it ) + { + QMapConstIterator it2 = m2.find( it.key() ); + if ( it2 == m2.end() || it.data() != it2.data() ) + return false; + } + + return true; +} + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// + + +void QueryParadigmList::initFromDOM( const QDomElement& elem ) +{ + clear(); + + QValueList list = + KMrml::directChildElements( elem, MrmlShared::queryParadigm() ); + + QValueListConstIterator it = list.begin(); + for ( ; it != list.end(); ++it ) + { + append( QueryParadigm( *it )); + } +} + +// two QueryParadigmLists match, when there is at least one pair of +// QueryParadigms that match (all attribute-value pairs are equal, or there +// are no attributes at all). +bool QueryParadigmList::matches( const QueryParadigmList& other ) const +{ + ConstIterator it = begin(); + + for ( ; it != end(); ++it ) + { + ConstIterator oit = other.begin(); + for ( ; oit != other.end(); ++oit ) + if ( (*it).matches( *oit ) ) + return true; + } + + return false; +} + + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// + +QValueList KMrml::directChildElements( const QDomElement& parent, + const QString& tagName ) +{ + QValueList list; + + QDomNode node = parent.firstChild(); + while ( !node.isNull() ) + { + if ( node.isElement() && node.nodeName() == tagName ) + list.append( node.toElement() ); + + node = node.nextSibling(); + } + + return list; +} + +QDomElement KMrml::firstChildElement( const QDomElement& parent, + const QString& tagName ) +{ + QDomNode node = parent.firstChild(); + while ( !node.isNull() ) + { + if ( node.isElement() && node.nodeName() == tagName ) + return node.toElement(); + + node = node.nextSibling(); + } + + return QDomElement(); +} + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// + + +QDataStream& KMrml::operator<<( QDataStream& stream, const QueryParadigm& ) +{ + + return stream; +} +QDataStream& KMrml::operator>>( QDataStream& stream, QueryParadigm& ) +{ + + return stream; +} + +QDataStream& KMrml::operator<<( QDataStream& stream, const QueryParadigmList& ) +{ + + return stream; +} +QDataStream& KMrml::operator>>( QDataStream& stream, QueryParadigmList& ) +{ + + return stream; +} + +QDataStream& KMrml::operator<<( QDataStream& stream, const MrmlElement& ) +{ + + return stream; +} +QDataStream& KMrml::operator>>( QDataStream& stream, MrmlElement& ) +{ + + return stream; +} + +QDataStream& KMrml::operator<<( QDataStream& stream, const Algorithm& ) +{ + + return stream; +} +QDataStream& KMrml::operator>>( QDataStream& stream, Algorithm& ) +{ + + return stream; +} + +QDataStream& KMrml::operator<<( QDataStream& stream, const Collection& ) +{ + + return stream; +} +QDataStream& KMrml::operator>>( QDataStream& stream, Collection& ) +{ + return stream; +} + +template QDataStream& KMrml::operator<<( QDataStream& stream, + const MrmlElementList& ) +{ + + return stream; +} +template QDataStream& KMrml::operator>>( QDataStream& stream, + MrmlElementList& ) +{ + + return stream; +} + +QDataStream& KMrml::operator<<( QDataStream& stream, const AlgorithmList& ) +{ + + return stream; +} +QDataStream& KMrml::operator>>( QDataStream& stream, AlgorithmList& ) +{ + + return stream; +} + diff --git a/kmrml/kmrml/mrml_elements.h b/kmrml/kmrml/mrml_elements.h new file mode 100644 index 00000000..09d2a4a8 --- /dev/null +++ b/kmrml/kmrml/mrml_elements.h @@ -0,0 +1,255 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef MRML_ELEMENTS_H +#define MRML_ELEMENTS_H + +#include +#include +#include +#include + +#include "mrml_shared.h" +#include "propertysheet.h" + +#include + +namespace KMrml +{ + class PropertySheet; + + class QueryParadigm + { + public: + QueryParadigm() {} + QueryParadigm( const QDomElement& elem ); + bool matches( const QueryParadigm& other ) const; + QString type() const { return m_type; } + +// bool operator== ( const QueryParadigm& p1, const QueryParadigm& p2 ) + + private: + QString m_type; + QMap m_attributes; + + static bool equalMaps( const QMap, + const QMap ); + }; + + class QueryParadigmList : protected QValueList + { + public: + typedef QValueListIterator Iterator; + typedef QValueListConstIterator ConstIterator; + + void initFromDOM( const QDomElement& elem ); + bool matches( const QueryParadigmList& other ) const; + }; + + class MrmlElement + { + public: + MrmlElement() {} + MrmlElement( const QDomElement& elem ); + virtual ~MrmlElement() {} + + QString id() const { return m_id; } + QString name() const { return m_name; } + QString attribute( const QString& name ) const { return m_attributes[ name ]; } + QueryParadigmList paradigms() const { return m_paradigms; } + + + QMapConstIterator attributeIterator() const { + return m_attributes.begin(); + } + QMapConstIterator end() const { return m_attributes.end(); } + + bool isValid() const { return !m_name.isNull() && !m_id.isNull(); } + + protected: + QString m_id; + QString m_name; + QueryParadigmList m_paradigms; + QMap m_attributes; + + void setOtherAttributes( QDomElement& elem ) const; + }; + + class Algorithm : public MrmlElement + { + public: + Algorithm() { m_collectionId = "adefault"; } + Algorithm( const QDomElement& elem ); + QString type() const { return m_type; } + + QString collectionId() const + { + return m_collectionId; + } + void setCollectionId( const QString& id ) + { + m_collectionId = id; + } + + QDomElement toElement( QDomElement& parent ) const; + const PropertySheet& propertySheet() const; + + static Algorithm defaultAlgorithm(); + + private: + QString m_type; + PropertySheet m_propertySheet; + + QString m_collectionId; + }; + + class Collection : public MrmlElement + { + public: + Collection() {} + Collection( const QDomElement& elem ); + }; + + template class MrmlElementList : public QValueList + { + public: + typedef QValueListIterator Iterator; + typedef QValueListConstIterator ConstIterator; + + /** + * Creates an invalid element. + */ + MrmlElementList( const QString& tagName ) : + QValueList(), + m_tagName( tagName ) {} + MrmlElementList( const QDomElement& elem, const QString& tagName ) : + QValueList(), + m_tagName( tagName ) + { + initFromDOM( elem ); + } + virtual ~MrmlElementList() {}; + + void initFromDOM( const QDomElement& elem ) + { + assert( !m_tagName.isEmpty() ); + + QValueList::clear(); + + QDomNodeList list = elem.elementsByTagName( m_tagName ); + for ( uint i = 0; i < list.length(); i++ ) + { + QDomElement elem = list.item( i ).toElement(); + t item( elem ); + if ( item.isValid() ) + append( item ); + } + } + + t findByName( const QString& name ) const + { + QValueListConstIterator it = QValueList::begin(); + for ( ; it != QValueList::end(); ++it ) + { + if ( (*it).name() == name ) + return *it; + } + + return t(); + } + + t findById( const QString& id ) const + { + QValueListConstIterator it = QValueList::begin(); + for ( ; it != QValueList::end(); ++it ) + { + if ( (*it).id() == id ) + return *it; + } + + return MrmlElement(); + } + + QStringList itemNames() const { + QStringList list; + QValueListConstIterator it = QValueList::begin(); + for ( ; it != QValueList::end(); ++it ) + list.append( (*it).name() ); + + return list; + } + + void setItemName( const QString& tagName ) { m_tagName = tagName; } + QString tagName() const { return m_tagName; } + + private: + QString m_tagName; + MrmlElementList(); + }; + + class AlgorithmList : public MrmlElementList + { + public: + AlgorithmList() : + MrmlElementList( MrmlShared::algorithm() ) + {} + + AlgorithmList algorithmsForCollection( const Collection& coll ) const; + }; + + class CollectionList : public MrmlElementList + { + public: + CollectionList() : + MrmlElementList( MrmlShared::collection() ) + {} + }; + + + QValueList directChildElements( const QDomElement& parent, + const QString& tagName); + QDomElement firstChildElement( const QDomElement& parent, + const QString& tagName ); + + + QDataStream& operator<<( QDataStream& stream, const QueryParadigm& ); + QDataStream& operator>>( QDataStream& stream, QueryParadigm& ); + + QDataStream& operator<<( QDataStream& stream, const QueryParadigmList& ); + QDataStream& operator>>( QDataStream& stream, QueryParadigmList& ); + + QDataStream& operator<<( QDataStream& stream, const MrmlElement& ); + QDataStream& operator>>( QDataStream& stream, MrmlElement& ); + + QDataStream& operator<<( QDataStream& stream, const Algorithm& ); + QDataStream& operator>>( QDataStream& stream, Algorithm& ); + + QDataStream& operator<<( QDataStream& stream, const Collection& ); + QDataStream& operator>>( QDataStream& stream, Collection& ); + + template QDataStream& operator<<( QDataStream&, + const MrmlElementList& ); + template QDataStream& operator>>( QDataStream&, + MrmlElementList& ); + + QDataStream& operator<<( QDataStream&, const AlgorithmList& ); + QDataStream& operator>>( QDataStream&, AlgorithmList& ); + +} + +#endif // MRML_ELEMENTS_H diff --git a/kmrml/kmrml/mrml_part.cpp b/kmrml/kmrml/mrml_part.cpp new file mode 100644 index 00000000..4d3f65e6 --- /dev/null +++ b/kmrml/kmrml/mrml_part.cpp @@ -0,0 +1,857 @@ +/* This file is part of the KDE project + Copyright (C) 2001,2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "algorithmdialog.h" +#include "browser.h" +#include "collectioncombo.h" +#include "mrml_creator.h" +#include "mrml_elements.h" +#include "mrml_shared.h" +#include "mrml_view.h" +#include "mrml_part.h" +#include "version.h" + +using namespace KMrml; + +extern "C" +{ + void * init_libkmrmlpart() { + return new KMrml::PartFactory(); + } +} + +KInstance * PartFactory::s_instance = 0L; + +PartFactory::PartFactory() + : KParts::Factory() +{ + MrmlShared::ref(); +} + +PartFactory::~PartFactory() +{ + MrmlShared::deref(); + delete s_instance; + s_instance = 0L; +} + +KInstance * PartFactory::instance() +{ + if ( !s_instance ) { + s_instance = new KInstance( "kmrml" ); + KGlobal::locale()->insertCatalogue( "kmrml" ); + } + return s_instance; +} + +KParts::Part * PartFactory::createPartObject( QWidget *parentWidget, + const char *widgetName, + QObject *parent, + const char *name, + const char *, + const QStringList& args ) +{ + return new MrmlPart( parentWidget, widgetName, parent, name, args ); +} + + +// can't use this due to MrmlShared ref-counting +// typedef KParts::GenericFactory PartFactory; +// K_EXPORT_COMPONENT_FACTORY( mrmlpart, PartFactory ) + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// + + +uint MrmlPart::s_sessionId = 0; + +MrmlPart::MrmlPart( QWidget *parentWidget, const char * /* widgetName */, + QObject *parent, const char *name, + const QStringList& /* args */ ) + : KParts::ReadOnlyPart( parent, name ), + m_job( 0L ), + m_status( NeedCollection ) +{ + m_sessionId = QString::number( s_sessionId++ ).prepend("kmrml_"); + + setName( "MRML Part" ); + m_browser = new Browser( this, "mrml browserextension"); + setInstance( PartFactory::instance(), true ); // do load plugins :) + KConfig *config = PartFactory::instance()->config(); + config->setGroup("MRML Settings"); + + QVBox *box = new QVBox( parentWidget, "main mrml box" ); + m_view = new MrmlView( box, "MrmlView" ); + connect( m_view, SIGNAL( activated( const KURL&, ButtonState )), + this, SLOT( slotActivated( const KURL&, ButtonState ))); + connect( m_view, SIGNAL( onItem( const KURL& )), + this, SLOT( slotSetStatusBar( const KURL& ))); + + m_panel = new QHGroupBox( box, "buttons box" ); + + QGrid *comboGrid = new QGrid( 2, m_panel, "combo grid" ); + comboGrid->setSpacing( KDialog::spacingHint() ); + + (void) new QLabel( i18n("Server to query:"), comboGrid ); + + m_hostCombo = new KComboBox( false, comboGrid, "host combo" ); + initHostCombo(); + connect( m_hostCombo, SIGNAL( activated( const QString& ) ), + SLOT( slotHostComboActivated( const QString& ))); + + (void) new QLabel( i18n("Search in collection:"), comboGrid ); + m_collectionCombo = new CollectionCombo( comboGrid, "collection-combo" ); + // will be re-set in initCollections(), but we need to set it here to + // prevent crashes when the connection to the server fails + m_collectionCombo->setCollections( &m_collections ); + + m_algoButton = new QPushButton( QString::null, m_panel ); + m_algoButton->setPixmap( SmallIcon("configure") ); + m_algoButton->setFixedSize( m_algoButton->sizeHint() ); + connect( m_algoButton, SIGNAL( clicked() ), + SLOT( slotConfigureAlgorithm() )); + QToolTip::add( m_algoButton, i18n("Configure algorithm") ); + + QWidget *spacer = new QWidget( m_panel ); + spacer->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, + QSizePolicy::Minimum ) ); + + int resultSize = config->readNumEntry( "Result-size", 20 ); + m_resultSizeInput = new KIntNumInput( resultSize, m_panel ); + m_resultSizeInput->setRange( 1, 100 ); + m_resultSizeInput->setLabel( i18n("Maximum result images:") ); + + QVBox *tmp = new QVBox( m_panel ); + m_random = new QCheckBox( i18n("Random search"), tmp ); + + m_startButton = new QPushButton( QString::null, tmp ); + connect( m_startButton, SIGNAL( clicked() ), SLOT( slotStartClicked() )); + setStatus( NeedCollection ); + + setWidget( box ); + + // setXMLFile( "mrml_part.rc" ); + + slotSetStatusBar( QString::null ); + + enableServerDependentWidgets( false ); +} + +MrmlPart::~MrmlPart() +{ + closeURL(); +} + +void MrmlPart::enableServerDependentWidgets( bool enable ) +{ + m_collectionCombo->setEnabled( enable ); + m_algoButton->setEnabled( enable && false ); // ### re-enable!!! +} + +void MrmlPart::initCollections( const QDomElement& elem ) +{ + m_collections.initFromDOM( elem ); + + m_collectionCombo->setCollections( &m_collections ); + enableServerDependentWidgets( m_collectionCombo->count() > 0 ); + + if ( m_collectionCombo->count() == 0 ) + { + KMessageBox::information( widget(), + i18n("There is no image collection available\n" + "at %1.\n"), i18n("No Image Collection")); + setStatus( NeedCollection ); + } + else + m_collectionCombo->updateGeometry(); // adjust the entire grid +} + +void MrmlPart::initAlgorithms( const QDomElement& elem ) +{ + m_algorithms.initFromDOM( elem ); +} + +// this is where we start! +bool MrmlPart::openURL( const KURL& url ) +{ + closeURL(); + + if ( url.protocol() != "mrml" || !url.isValid() ) { + qWarning("MrmlPart::openURL: cannot handle url: %s", url.prettyURL().latin1()); + return false; // what to do with that? + } + + m_url = url; + QString host = url.host().isEmpty() ? + QString::fromLatin1("localhost") : url.host(); + + m_hostCombo->setCurrentItem( host ); + + // urls we need to download before starting the query + KURL::List downloadList; + + m_queryList.clear(); + QString param = url.queryItem( "relevant" ); + QStringList list = QStringList::split( ';', param ); + + // we can only search by example on localhost + if ( host != "localhost" ) + { + if ( !list.isEmpty() ) + KMessageBox::sorry( m_view, + i18n("You can only search by example images " + "on a local indexing server."), + i18n("Only Local Servers Possible") ); + } + + else // localhost query + { + for( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) + { + KURL u; + if ( (*it).at(0) == '/' ) + u.setPath( *it ); + else + u = *it; + + if ( u.isValid() ) + { + if ( u.isLocalFile() ) + m_queryList.append( u ); + else + downloadList.append( u ); + } + } + + + // ### we need a real solution for this! + // gift refuses to start when no config file is available. + if ( !QFile::exists( m_config.mrmldDataDir() + "/gift-config.mrml" ) ) + { + if ( KMessageBox::questionYesNo(0L, + i18n("There are no indexable folders " + "specified. Do you want to configure them " + "now?"), + i18n("Configuration Missing"), + i18n("Configure"), + i18n("Do Not Configure"), + "kmrml_ask_configure_gift" ) + == KMessageBox::Yes ) + { + KApplication::kdeinitExec( "kcmshell", + QString::fromLatin1("kcmkmrml")); + setStatus( NeedCollection ); + return false; + } + } + } + + + if ( !downloadList.isEmpty() ) + downloadReferenceFiles( downloadList ); + else + contactServer( m_url ); + + return true; +} + +void MrmlPart::contactServer( const KURL& url ) +{ + m_job = transferJob( url ); + + m_job->addMetaData( MrmlShared::kio_task(), MrmlShared::kio_initialize() ); + + QString host = url.host().isEmpty() ? + QString::fromLatin1("localhost") : url.host(); + + slotSetStatusBar( i18n("Connecting to indexing server at %1...").arg( host )); +} + +// +// schedules a download all urls of downloadList (all remote and wellformed) +// No other downloads are running (closeURL() has been called before) +// +void MrmlPart::downloadReferenceFiles( const KURL::List& downloadList ) +{ + assert( m_downloadJobs.isEmpty() ); + + KURL::List::ConstIterator it = downloadList.begin(); + for ( ; it != downloadList.end(); it++ ) + { + QString extension; + int index = (*it).fileName().findRev( '.' ); + if ( index != -1 ) + extension = (*it).fileName().mid( index ); + + KTempFile tmpFile( QString::null, extension ); + if ( tmpFile.status() != 0 ) + { + kdWarning() << "Can't create temporary file, skipping: " << *it << endl; + + continue; + } + + m_tempFiles.append( tmpFile.name() ); + KURL destURL; + destURL.setPath( tmpFile.name() ); + + KIO::FileCopyJob *job = KIO::file_copy( *it, destURL, -1, + true /* overwrite tmpfile */ ); + connect( job, SIGNAL( result( KIO::Job * ) ), + SLOT( slotDownloadResult( KIO::Job * ) )); + m_downloadJobs.append( job ); + // ### should this be only called for one job? + emit started( job ); + } + + if ( !m_downloadJobs.isEmpty() ) + slotSetStatusBar( i18n("Downloading reference files...") ); + else // probably never happens + contactServer( m_url ); +} + +bool MrmlPart::closeURL() +{ + m_view->stopDownloads(); + m_view->clear(); + + QPtrListIterator it( m_downloadJobs ); + for ( ; it.current(); ++it ) + it.current()->kill(); + m_downloadJobs.clear(); + + QStringList::Iterator tit = m_tempFiles.begin(); + for ( ; tit != m_tempFiles.end(); ++tit ) + QFile::remove( *tit ); + m_tempFiles.clear(); + + if ( m_job ) { + m_job->kill(); + m_job = 0L; + } + + setStatus( NeedCollection ); + + return true; +} + +KIO::TransferJob * MrmlPart::transferJob( const KURL& url ) +{ + KIO::TransferJob *job = KIO::get( url, true, false ); // reload, no gui + job->setAutoErrorHandlingEnabled( true, m_view ); + connect( job, SIGNAL( result( KIO::Job * )), + SLOT( slotResult( KIO::Job * ))); + connect( job, SIGNAL( data( KIO::Job *, const QByteArray& )), + SLOT( slotData( KIO::Job *, const QByteArray& ))); + +// ### +// connect( job, SIGNAL( infoMessage( KIO::Job *, const QString& )), +// SLOT( slotResult( KIO::Job *, const QString& ))); + + job->setWindow( widget() ); + if ( !m_sessionId.isEmpty() ) + job->addMetaData( MrmlShared::sessionId(), m_sessionId ); + + emit started( job ); + emit setWindowCaption( url.prettyURL() ); + setStatus( InProgress ); + + return job; +} + +void MrmlPart::slotResult( KIO::Job *job ) +{ + if ( job == m_job ) + m_job = 0L; + + slotSetStatusBar( QString::null ); + + if ( !job->error() ) + emit completed(); + else { + emit canceled( job->errorString() ); +// qDebug("*** canceled: error: %s", job->errorString().latin1()); + } + + + bool auto_random = m_view->isEmpty() && m_queryList.isEmpty(); + m_random->setChecked( auto_random ); + m_random->setEnabled( !auto_random ); + setStatus( job->error() ? NeedCollection : CanSearch ); + + if ( !job->error() && !m_queryList.isEmpty() ) { + // we have a connection and we got a list of relevant URLs to query for + // (via the URL) + + createQuery( &m_queryList ); + m_queryList.clear(); + } +} + +// ### when user cancels download, we crash :( +void MrmlPart::slotDownloadResult( KIO::Job *job ) +{ + assert( job->inherits( "KIO::FileCopyJob" ) ); + KIO::FileCopyJob *copyJob = static_cast( job ); + + if ( !copyJob->error() ) + m_queryList.append( copyJob->destURL() ); + + m_downloadJobs.removeRef( copyJob ); + + if ( m_downloadJobs.isEmpty() ) // finally, we can start the query! + { + if ( m_queryList.isEmpty() ) // rather unlikely, but could happen ;) + { + kdWarning() << "Couldn't download the reference files. Will start a random search now" << endl; + } + + contactServer( m_url ); + } +} + +// mrml-document in the bytearray +void MrmlPart::slotData( KIO::Job *, const QByteArray& data ) +{ + if ( data.isEmpty() ) + return; + + QDomDocument doc; + doc.setContent( data ); + + if ( !doc.isNull() ) + parseMrml( doc ); +} + +void MrmlPart::parseMrml( QDomDocument& doc ) +{ + QDomNode mrml = doc.documentElement(); // root element + if ( !mrml.isNull() ) { + QDomNode child = mrml.firstChild(); + for ( ; !child.isNull(); child = child.nextSibling() ) { +// qDebug("**** HERE %s", child.nodeName().latin1()); + if ( child.isElement() ) { + QDomElement elem = child.toElement(); + + QString tagName = elem.tagName(); + + if ( tagName == "acknowledge-session-op" ) + m_sessionId = elem.attribute( MrmlShared::sessionId() ); + + else if ( tagName == MrmlShared::algorithmList() ) { + initAlgorithms( elem ); + } + + else if ( tagName == MrmlShared::collectionList() ) { + initCollections( elem ); + } + + else if ( tagName == "error" ) { + KMessageBox::information( widget(), + i18n("Server returned error:\n%1\n") + .arg( elem.attribute( "message" )), + i18n("Server Error") ); + } + + else if ( tagName == "query-result" ) { + m_view->clear(); + parseQueryResult( elem ); + } + + + } // child.isElement() + } + } // !mrml.isNull() +} + +void MrmlPart::parseQueryResult( QDomElement& queryResult ) +{ + QDomNode child = queryResult.firstChild(); + for ( ; !child.isNull(); child = child.nextSibling() ) { + if ( child.isElement() ) { + QDomElement elem = child.toElement(); + QString tagName = elem.tagName(); + + if ( tagName == "query-result-element-list" ) { + QValueList list = + KMrml::directChildElements( elem, "query-result-element" ); + + QValueListConstIterator it = list.begin(); + for ( ; it != list.end(); ++it ) + { + QDomNamedNodeMap a = (*it).attributes(); + m_view->addItem( KURL( (*it).attribute("image-location" ) ), + KURL( (*it).attribute("thumbnail-location" ) ), + (*it).attribute("calculated-similarity")); + + } + } + + else if ( tagName == "query-result" ) + parseQueryResult( elem ); + } + } +} + +// creates/stops the query when the Start/Stop button was pressed +void MrmlPart::slotStartClicked() +{ + if ( m_status == InProgress ) + { + closeURL(); + m_startButton->setText( i18n("&Search" ) ); + return; + } + + // we need to reconnect, if the initial openURL() didn't work due to + // the gift not being available. + if ( m_status == NeedCollection ) + { + openURL( m_url ); + return; + } + + // cut off an eventual query and reference from the url, when the user + // performs a real query (otherwise restoreState() would restore and + // re-do the query from the URL + m_url.setRef( QString::null ); + m_url.setQuery( QString::null ); + + createQuery(); + m_browser->openURLNotify(); +} + +// +// relevantItems is 0L when called from slotStartClicked() and set to a +// non-empty list when called initially, from the commandline. +// +void MrmlPart::createQuery( const KURL::List * relevantItems ) +{ + if ( relevantItems && relevantItems->isEmpty() ) + return; + + QDomDocument doc( "mrml" ); + QDomElement mrml = MrmlCreator::createMrml( doc, + sessionId(), + transactionId() ); + + Collection coll = currentCollection(); +// qDebug("** collection: name: %s, id: %s, valid: %i", coll.name().latin1(), coll.id().latin1(), coll.isValid()); + Algorithm algo = firstAlgorithmForCollection( coll ); +// qDebug("** algorithm: name: %s, id: %s, valid: %i, collection-id: %s", algo.name().latin1(), algo.id().latin1(), algo.isValid(), algo.collectionId().latin1()); + + if ( algo.isValid() ) + { + MrmlCreator::configureSession( mrml, algo, sessionId() ); + } + + QDomElement query = MrmlCreator::addQuery( mrml, + m_resultSizeInput->value() ); + if ( algo.isValid() ) + query.setAttribute( MrmlShared::algorithmId(), algo.id() ); + + // ### result-cutoff, query-type? + + // start-up with/without urls on the commandline via mrmlsearch + if ( relevantItems ) + { + QDomElement elem = MrmlCreator::addRelevanceList( query ); + KURL::List::ConstIterator it = relevantItems->begin(); + for ( ; it != relevantItems->end(); ++it ) + MrmlCreator::createRelevanceElement( doc, elem, (*it).url(), + MrmlCreator::Relevant ); + } + + // get relevant items from the view? Only do this when relevantItems is 0L + else if ( !m_random->isChecked() ) + { + QDomElement relevants = MrmlCreator::addRelevanceList( query ); + m_view->addRelevanceToQuery( doc, relevants ); + } + + performQuery( doc ); +} + +Collection MrmlPart::currentCollection() const +{ + return m_collectionCombo->current(); +} + +Algorithm MrmlPart::firstAlgorithmForCollection( const Collection& coll ) const +{ + if ( !m_algorithms.isEmpty() ) + { + AlgorithmList::ConstIterator it = m_algorithms.begin(); + for ( ; it != m_algorithms.end(); ++it ) + { + Algorithm algo = *it; + if ( algo.paradigms().matches( coll.paradigms() ) ) + { + algo.setCollectionId( coll.id() ); + return algo; + } + } + } + + qDebug("#################### -> ADEFAULT!"); + Algorithm algo = Algorithm::defaultAlgorithm(); + algo.setCollectionId( coll.id() ); + return algo; +} + +// emits the given QDomDocument for eventual plugins, checks after that +// if there are any relevance elements. If there are none, random search is +// implied and performed. +// finally, the search is actually started +void MrmlPart::performQuery( QDomDocument& doc ) +{ + QDomElement mrml = doc.documentElement(); + + emit aboutToStartQuery( doc ); // let plugins play with it :) + + // no items available? All "neutral"? -> random search + + QDomElement queryStep = KMrml::firstChildElement( mrml, "query-step" ); + bool randomSearch = false; + + if ( !queryStep.isNull() ) + { + QDomElement relevanceList = + KMrml::firstChildElement(queryStep, "user-relevance-element-list"); + QValueList relevanceElements = + KMrml::directChildElements( relevanceList, + "user-relevance-element" ); + + randomSearch = relevanceElements.isEmpty(); + + if ( randomSearch ) + { + m_random->setChecked( true ); + m_random->setEnabled( false ); + queryStep.setAttribute("query-type", "at-random"); + + // remove user-relevance-element-list element for random search + relevanceList.parentNode().removeChild( relevanceList ); + } + } + else + { + KMessageBox::error( m_view, i18n("Error formulating the query. The " + "\"query-step\" element is missing."), + i18n("Query Error") ); + } + + m_job = transferJob( url() ); + slotSetStatusBar( randomSearch ? i18n("Random search...") : + i18n("Searching...") ); + m_job->addMetaData( MrmlShared::kio_task(), MrmlShared::kio_startQuery() ); + qDebug("\n\nSending XML:\n%s", doc.toString().latin1()); + m_job->addMetaData( MrmlShared::mrml_data(), doc.toString() ); +} + +void MrmlPart::slotSetStatusBar( const QString& text ) +{ + if ( text.isEmpty() ) + emit setStatusBarText( i18n("Ready.") ); + else + emit setStatusBarText( text ); +} + +void MrmlPart::slotActivated( const KURL& url, ButtonState button ) +{ + if ( button == LeftButton ) + emit m_browser->openURLRequest( url ); + else if ( button == MidButton ) + emit m_browser->createNewWindow( url ); + else if ( button == RightButton ) { + // enableExtensionActions( url, true ); // for now + emit m_browser->popupMenu( QCursor::pos(), url, QString::null ); + // enableExtensionActions( url, false ); + } +} + +void MrmlPart::enableExtensionActions( const KURL& url, bool enable ) +{ + bool del = KProtocolInfo::supportsDeleting( url ); + emit m_browser->enableAction( "copy", enable ); + emit m_browser->enableAction( "trash", del ); + emit m_browser->enableAction( "del", del ); + emit m_browser->enableAction( "shred", url.isLocalFile() ); + emit m_browser->enableAction( "properties", enable ); + // emit m_browser->enableAction( "print", enable ); // ### later +} + + +// only implemented because it's abstract in the baseclass +bool MrmlPart::openFile() +{ + return false; +} + +void MrmlPart::slotConfigureAlgorithm() +{ + m_algoButton->setEnabled( false ); + + m_algoConfig = new AlgorithmDialog( m_algorithms, m_collections, + currentCollection(), + m_view, "algorithm configuration" ); + connect( m_algoConfig, SIGNAL( applyClicked() ), + SLOT( slotApplyAlgoConfig() )); + connect( m_algoConfig, SIGNAL( finished() ), + SLOT( slotAlgoConfigFinished() )); + + m_algoConfig->show(); +} + +void MrmlPart::slotApplyAlgoConfig() +{ + // ### +} + +void MrmlPart::slotAlgoConfigFinished() +{ + if ( m_algoConfig->result() == QDialog::Accepted ) + slotApplyAlgoConfig(); + + m_algoButton->setEnabled( true ); + m_algoConfig->deleteLater(); + m_algoConfig = 0L; +} + +void MrmlPart::initHostCombo() +{ + m_hostCombo->clear(); + m_hostCombo->insertStringList( m_config.hosts() ); +} + +void MrmlPart::slotHostComboActivated( const QString& host ) +{ + ServerSettings settings = m_config.settingsForHost( host ); + openURL( settings.getUrl() ); +} + +void MrmlPart::setStatus( Status status ) +{ + switch ( status ) + { + case NeedCollection: + m_startButton->setText( i18n("&Connect") ); + break; + case CanSearch: + m_startButton->setText( i18n("&Search") ); + break; + case InProgress: + m_startButton->setText( i18n("Sto&p") ); + break; + }; + + m_status = status; +} + + +void MrmlPart::saveState( QDataStream& stream ) +{ + stream << url(); + stream << m_sessionId; + stream << m_queryList; +// stream << m_algorithms; +// stream << m_collections; + + stream << m_resultSizeInput->value(); + stream << *m_collectionCombo; + + m_view->saveState( stream ); +} + +void MrmlPart::restoreState( QDataStream& stream ) +{ + KURL url; + stream >> url; + + stream >> m_sessionId; + stream >> m_queryList; +// stream >> m_algorithms; +// stream >> m_collections; + + int resultSize; + stream >> resultSize; + m_resultSizeInput->setValue( resultSize ); + stream >> *m_collectionCombo; + + m_view->restoreState( stream ); + +// openURL( url ); + m_url = url; +} + +KAboutData * MrmlPart::createAboutData() +{ + KAboutData *data = new KAboutData( + "kmrml", + I18N_NOOP("MRML Client for KDE"), + KMRML_VERSION, + I18N_NOOP("A tool to search for images by their content"), + KAboutData::License_GPL, + I18N_NOOP("(c) 2001-2002, Carsten Pfeiffer"), + 0, + I18N_NOOP("http://devel-home.kde.org/~pfeiffer/kmrml/") ); + + data->addAuthor( "Carsten Pfeiffer", + I18N_NOOP("Developer, Maintainer"), + "pfeiffer@kde.org" ); + data->addCredit( "Wolfgang Mller", + I18N_NOOP("Developer of the GIFT, Helping Hand") ); + + return data; +} + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// + +#include "mrml_part.moc" diff --git a/kmrml/kmrml/mrml_part.desktop b/kmrml/kmrml/mrml_part.desktop new file mode 100644 index 00000000..90017794 --- /dev/null +++ b/kmrml/kmrml/mrml_part.desktop @@ -0,0 +1,67 @@ +[Desktop Entry] +Type=Service +Exec=blahfoo +Name=MRML View +Name[ar]=برنامج MRML View +Name[br]=Gwel MRML +Name[ca]=Vista MRML +Name[cs]=MRML pohled +Name[cy]=Gwelydd MRML +Name[da]=MRML-visning +Name[de]=MRML-Ansicht +Name[el]=Προβολή MRML +Name[eo]=MRML-Rigardo +Name[es]=Vista de MRML +Name[et]=MRML vaade +Name[eu]=MRML ikuspegia +Name[fa]=نمای MRML +Name[fi]=MRML-näkymä +Name[fr]=Affichage MRML +Name[ga]=Amharc MRML +Name[gl]=Visor MRML +Name[he]=תצוגת MRML +Name[hi]=MRML दृश्य +Name[hu]=MRML-nézet +Name[is]=MRML sýn +Name[it]=Visione MRML +Name[ja]=MRML ビュー +Name[kk]=MRML файлдарды қарау +Name[km]=ទិដ្ឋភាព MRML +Name[lt]=MRML peržiūra +Name[ms]=Paparan MRML +Name[nds]=MRML-Ansicht +Name[ne]=MRML दृश्य +Name[nl]=MRML-weergave +Name[nso]=Pono ya MRML +Name[pa]=MRML ਝਲਕ +Name[pl]=Widok MRML +Name[pt]=Janela de MRML +Name[pt_BR]=Visualização de MRML +Name[ro]=Vizualizare MRML +Name[ru]=Просмотр MRML +Name[se]=MRML-čájeheapmi +Name[sk]=Prehliadač MRML +Name[sl]=Pregledovalnik MRML +Name[sr]=MRML приказивач +Name[sr@Latn]=MRML prikazivač +Name[ta]=MRML காட்சி +Name[tg]=Намоиши MRML +Name[th]=ดู MRML +Name[tr]=MRML Görünümü +Name[uk]=Перегляд MRML +Name[ven]=Mbonalelo ya MRML +Name[xh]=MRML Imbono +Name[zh_CN]=MRML 查看器 +Name[zh_HK]=MRML 檢視 +Name[zh_TW]=MRML 檢視器 +Name[zu]=Umbukiso we-MRML +MimeType=text/mrml +ServiceTypes=KParts/ReadOnlyPart +X-KDE-Library=libkmrmlpart +#X-KDE-BrowserView-AllowAsDefault=true +#X-KDE-BrowserView-HideFromMenus=true +#X-KDE-BrowserView-Args=IconView +#X-KDE-BrowserView-ModeProperty=viewMode +#X-KDE-BrowserView-ModePropertyValue=IconView +Icon=view_icon +InitialPreference=10 diff --git a/kmrml/kmrml/mrml_part.h b/kmrml/kmrml/mrml_part.h new file mode 100644 index 00000000..110d290a --- /dev/null +++ b/kmrml/kmrml/mrml_part.h @@ -0,0 +1,175 @@ +/* This file is part of the KDE project + Copyright (C) 2001,2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef MRMLPART_H +#define MRMLPART_H + +#include +#include + +#include +#include +#include + +#include + +#include "mrml_elements.h" + +class QCheckBox; +class QHGroupBox; +class QPushButton; + +class KAboutData; +class KComboBox; +class KIntNumInput; + +namespace KIO { + class FileCopyJob; + class TransferJob; +} + +namespace KMrml +{ + +class AlgorithmDialog; +class Browser; +class CollectionCombo; +class MrmlView; + +class MrmlPart : public KParts::ReadOnlyPart +{ + Q_OBJECT + +public: + enum Status { NeedCollection, CanSearch, InProgress }; + + MrmlPart( QWidget *parentWidget, const char *widgetName, + QObject *parent, const char *name, const QStringList& args ); + ~MrmlPart(); + + QString sessionId() const { return m_sessionId; } + QString transactionId() const { return QString::null; } // ### + + void saveState( QDataStream& stream ); + void restoreState( QDataStream& stream ); + + static KAboutData *createAboutData(); + +public slots: + virtual bool openURL( const KURL& ); + virtual bool closeURL(); + + void slotActivated( const KURL& url, ButtonState ); + +protected: + virtual bool openFile(); + Algorithm firstAlgorithmForCollection( const Collection& coll ) const; + Collection currentCollection() const; + +signals: + /** + * allow plugins to extend the query + */ + void aboutToStartQuery( QDomDocument& ); + +private slots: + void slotStartClicked(); + void slotSetStatusBar( const QString& ); + void slotSetStatusBar( const KURL& url ) { slotSetStatusBar( url.prettyURL() ); } + void slotHostComboActivated( const QString& ); + + void slotResult( KIO::Job * ); + void slotData( KIO::Job *, const QByteArray& ); + + void slotDownloadResult( KIO::Job * ); + + void slotConfigureAlgorithm(); + void slotApplyAlgoConfig(); + void slotAlgoConfigFinished(); + +private: + void createQuery( const KURL::List * relevantItems = 0L ); + void initCollections( const QDomElement& ); + void initAlgorithms( const QDomElement& ); + void performQuery( QDomDocument& doc ); + void parseMrml( QDomDocument& doc ); + void parseQueryResult( QDomElement& ); + void enableExtensionActions( const KURL& url, bool enable ); + KIO::TransferJob * transferJob( const KURL& url ); + + void initHostCombo(); + void enableServerDependentWidgets( bool enable ); + + void setStatus( Status status ); + + void contactServer( const KURL& url ); + void downloadReferenceFiles( const KURL::List& downloadList ); + + KIO::TransferJob *m_job; + MrmlView *m_view; + Config m_config; + KIntNumInput * m_resultSizeInput; + CollectionCombo * m_collectionCombo; + QPushButton *m_algoButton; + QHGroupBox *m_panel; + QPushButton *m_startButton; + QCheckBox *m_random; + Browser *m_browser; + AlgorithmDialog *m_algoConfig; + KComboBox *m_hostCombo; + + QPtrList m_downloadJobs; + QStringList m_tempFiles; + + QString m_sessionId; + KURL::List m_queryList; // a list of valid LOCAL (!) urls to query for + + CollectionList m_collections; + AlgorithmList m_algorithms; + + Status m_status; + static uint s_sessionId; + +}; + +class PartFactory : public KParts::Factory +{ + Q_OBJECT + +public: + PartFactory(); + ~PartFactory(); + + static KInstance * instance(); + +protected: + virtual KParts::Part * createPartObject( QWidget *parentWidget = 0, + const char *widgetName = 0, + QObject *parent = 0, + const char *name = 0, + const char *classname = "KParts::Part", + const QStringList& args = QStringList() ); + +private: + static KInstance * s_instance; + +}; + +} + +#endif // MRMLPART_H diff --git a/kmrml/kmrml/mrml_view.cpp b/kmrml/kmrml/mrml_view.cpp new file mode 100644 index 00000000..71f3c741 --- /dev/null +++ b/kmrml/kmrml/mrml_view.cpp @@ -0,0 +1,480 @@ +/* This file is part of the KDE project + Copyright (C) 2001,2002 Carsten Pfeiffer + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "loader.h" +#include "mrml_creator.h" +#include "mrml_view.h" + +using namespace KMrml; + +MrmlView::MrmlView( QWidget *parent, const char *name ) + : QScrollView( parent, name ) +{ + setStaticBackground( true ); + setResizePolicy( Manual ); + setHScrollBarMode( AlwaysOff ); + enableClipper( true ); // ### test this + + m_items.setAutoDelete( true ); + + connect( Loader::self(), SIGNAL( finished(const KURL&, const QByteArray&)), + SLOT( slotDownloadFinished( const KURL&, const QByteArray& ))); + + m_timer = new QTimer( this ); + connect( m_timer, SIGNAL( timeout() ), SLOT( slotLayout() )); + + // we need a pixmap to be shown when no thumbnail is available for a + // query result image + QLabel l( i18n( "No thumbnail available" ), 0L ); + l.setFixedSize( 80, 80 ); + l.setAlignment( WordBreak | AlignCenter ); +// l.setFrameStyle( QLabel::Box | QLabel::Plain ); +// l.setLineWidth( 1 ); + l.setPaletteBackgroundColor( Qt::white ); + l.setPaletteForegroundColor( Qt::black ); + m_unavailablePixmap = QPixmap::grabWidget( &l ); +} + +MrmlView::~MrmlView() +{ +} + +MrmlViewItem * MrmlView::addItem( const KURL& url, const KURL& thumbURL, + const QString& similarity ) +{ + bool ok; + double value = similarity.toDouble( &ok ); + if ( !ok || value < 0.05 ) + return 0L; + + return addItem( url, thumbURL, value ); +} + +MrmlViewItem * MrmlView::addItem( const KURL& url, const KURL& thumbURL, + double similarity ) +{ + if ( !url.isValid() ) { + qWarning( "MrmlPart: received malformed URL from query: %s", + url.prettyURL().isNull() ? "(null)" : url.prettyURL().latin1() ); + return 0L; + } + +// qDebug("** url: %s", thumbURL.url().latin1()); + + MrmlViewItem *item = new MrmlViewItem( url, thumbURL, similarity, this ); + QPixmap *pixmap = getPixmap( thumbURL ); + if ( pixmap ) + item->setPixmap( *pixmap ); + + m_items.append( item ); + + m_timer->start( 0, true ); + return item; +} + +void MrmlView::addRelevanceToQuery( QDomDocument& document, + QDomElement& parent ) +{ + QPtrListIterator it( m_items ); + for( ; it.current(); ++it ) { + it.current()->createRelevanceElement( document, parent ); + } +} + +void MrmlView::clear() +{ + m_items.clear(); // items are deleted and removed from scrollview + setContentsPos( 0, 0 ); +} + +QPixmap * MrmlView::getPixmap( const KURL& url ) +{ + QString u = url.url(); + QPixmap *pix = m_pixmapCache.find( u ); + if ( pix ) + return pix; + + if ( url.isLocalFile() ) { + QPixmap p; + if ( !p.load( url.path() ) ) + p = m_unavailablePixmap; + + m_pixmapCache.insert( u, p ); + return m_pixmapCache.find( u ); + } + else { // remote url, download with KIO + Loader::self()->requestDownload( url ); + } + + return 0L; +} + +void MrmlView::slotDownloadFinished( const KURL& url, const QByteArray& data ) +{ + QPtrListIterator it( m_items ); + for( ; it.current(); ++it ) { + MrmlViewItem *item = it.current(); + if ( item->thumbURL() == url ) + { + QPixmap p; + if ( data.isEmpty() || !p.loadFromData( data ) ) + p = m_unavailablePixmap; + + m_pixmapCache.insert( url.url(), p ); + item->setPixmap( p ); + + slotLayout(); + return; + } + } +} + +void MrmlView::stopDownloads() +{ + Loader *loader = Loader::self(); + QPtrListIterator it( m_items ); + for( ; it.current(); ++it ) { + MrmlViewItem *item = it.current(); + if ( !item->hasRemotePixmap() ) + loader->removeDownload( item->url() ); + } +} + +void MrmlView::slotLayout() +{ + int itemWidth = 0; + QPtrListIterator it( m_items ); + + for ( ; it.current(); ++it ) { + itemWidth = QMAX( itemWidth, it.current()->sizeHint().width() ); + } + + if ( itemWidth == 0 ) + return; + + + uint itemsPerRow = visibleWidth() / itemWidth; + int margin = (visibleWidth() - (itemsPerRow * itemWidth)) / 2; + int rowHeight = 0; + uint item = 0; + uint y = 5; + + // pointing to the first item of a row + QPtrListIterator rowIt( m_items ); + + for ( it.toFirst(); it.current(); ++it ) { + if ( item >= itemsPerRow ) { + item = 0; + y += rowHeight; + rowHeight = 0; + } + + if ( item == 0 ) + rowIt = it; + + rowHeight = QMAX( rowHeight, it.current()->sizeHint().height() ); + addChild( it.current(), margin + item * itemWidth, y ); + it.current()->show(); + + item++; + + // resize all items of the current row so they all have the same size + if ( item >= itemsPerRow || it.atLast() ) + { + for ( uint i = 0; (i < itemsPerRow && rowIt.current()); i++ ) + { + rowIt.current()->resize( itemWidth, rowHeight ); + ++rowIt; + } + } + } + + resizeContents( visibleWidth(), y + rowHeight ); +} + +void MrmlView::resizeEvent( QResizeEvent *e ) +{ + int oldW = visibleWidth(); + QScrollView::resizeEvent( e ); + + if ( visibleWidth() != oldW ) + slotLayout(); +} + +void MrmlView::saveState( QDataStream& stream ) +{ + stream << m_items.count(); + QPtrListIterator it( m_items ); + for( ; it.current(); ++it ) { + stream << *it.current(); + } + +} + +void MrmlView::restoreState( QDataStream& stream ) +{ + stopDownloads(); + clear(); + + int count; + stream >> count; + + KURL url, thumbURL; + double similarity; + Q_UINT32 relevance; + MrmlViewItem *item; + + + for ( int i = 0; i < count; i++ ) + { + stream >> url; + stream >> thumbURL; + stream >> similarity; + stream >> relevance; + + item = addItem( url, thumbURL, similarity ); + if ( item ) + item->setRelevance( (MrmlViewItem::Relevance) relevance ); + } +} + +QDataStream& KMrml::operator<<( QDataStream& stream, + const KMrml::MrmlViewItem& item ) +{ + return stream << item.url() + << item.thumbURL() + << item.similarity() + << static_cast( item.relevance() ); +} + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// + + +MrmlViewItem::MrmlViewItem( const KURL& url, const KURL& thumbURL, + double similarity, MrmlView *view, + const char *name ) + : QFrame( view->viewport() , name ), + m_view( view ), + m_url( url ), + m_thumbURL( thumbURL ), + similarityFullWidth( 120 ), // ### + m_hasRemotePixmap( false ) +{ + if ( m_similarity != -1 ) + m_similarity = QMAX( 0.0, QMIN( 1.0, similarity )); + setFrameStyle( Panel | Sunken ); + setMouseTracking( true ); + + m_combo = new KComboBox( this ); + QToolTip::add( m_combo, i18n("You can refine queries by giving feedback about the current result and pressing the Search button again.") ); + m_combo->insertItem( i18n("Relevant"), Relevant ); + m_combo->insertItem( i18n("Neutral"), Neutral ); + m_combo->insertItem( i18n("Irrelevant"), Irrelevant ); + m_combo->adjustSize(); + m_combo->setCurrentItem( Neutral ); + + /* + if ( similarity > -1 ) + QToolTip::add( this, QString::fromLatin1("%1
%1
") + .arg( url ) + .arg(i18n("Similarity: %1").arg( QString::number(similarity)))); + else + QToolTip::add( this, QString::fromLatin1("%1").arg( url ) ); + */ + + setMinimumSize( 130, 130 ); // ### +} + +MrmlViewItem::~MrmlViewItem() +{ +} + +void MrmlViewItem::setPixmap( const QPixmap& pix ) +{ + if ( !m_url.isLocalFile() ) + m_hasRemotePixmap = true; + + m_pixmap = pix; + adjustSize(); + update(); +} + +void MrmlViewItem::paintEvent( QPaintEvent *e ) +{ + QFrame::paintEvent( e ); + + if ( !m_pixmap.isNull() ) { + bitBlt( this, pixmapX(), pixmapY(), + &m_pixmap, 0, 0, m_pixmap.width(), m_pixmap.height(), + CopyROP ); + } + + if ( m_similarity >= 0 ) { + QPainter p( this ); + QPen pen( colorGroup().highlight(), 1, QPen::SolidLine ); + p.setPen( pen ); + int x = margin; + int y = m_combo->y() - similarityHeight - 2; + int w = (int) (similarityFullWidth * m_similarity); + int h = similarityHeight; + p.drawRect( x, y, similarityFullWidth, h ); + p.fillRect( x, y, w, h, colorGroup().highlight() ); + } +} + +void MrmlViewItem::resizeEvent( QResizeEvent *e ) +{ + QFrame::resizeEvent( e ); + + int y = height() - m_combo->height() - margin; + m_combo->move( width()/2 - m_combo->width()/2, y ); +} + +QSize MrmlViewItem::sizeHint() const +{ + int w = QMAX( QMAX(minimumHeight(), m_combo->width()), m_pixmap.width() ); + w += 2 * margin; + + int h = m_pixmap.isNull() ? margin : margin + spacing + m_pixmap.height(); + h += (m_similarity > -1) ? similarityHeight + spacing : 0; + h += m_combo->height() + margin; + + return QSize( w, h ); +} + +void MrmlViewItem::mousePressEvent( QMouseEvent *e ) +{ + QFrame::mousePressEvent( e ); + pressedPos.setX( 0 ); + pressedPos.setY( 0 ); + + + if ( e->button() == LeftButton || e->button() == MidButton ) { + if ( hitsPixmap( e->pos() ) ) + pressedPos = e->pos(); + } + else if ( e->button() == RightButton && hitsPixmap( e->pos() ) ) + emit view()->activated( m_url, e->button() ); +} + +void MrmlViewItem::mouseMoveEvent( QMouseEvent *e ) +{ + if ( hitsPixmap( e->pos() ) ) { + if ( !ownCursor() ) { // nice hacklet :) + setCursor( KCursor::handCursor() ); + emit view()->onItem( m_url ); + } + } + else { + if ( ownCursor() ) { + unsetCursor(); + emit view()->onItem( KURL() ); + } + } + + if ( (e->state() & LeftButton) && !pressedPos.isNull() ) { + QPoint dist = e->pos() - pressedPos; + if ( dist.manhattanLength() > KGlobalSettings::dndEventDelay() ) { + // start drag here + KURL::List urls; + // ### support multiple files? + urls.append( m_url ); + KURLDrag *drag = new KURLDrag( urls, this ); + drag->setPixmap( KMimeType::pixmapForURL( m_url ) ); + drag->drag(); + } + } +} + +void MrmlViewItem::mouseReleaseEvent( QMouseEvent *e ) +{ + if ( hitsPixmap( e->pos() )) { + QPoint dist = e->pos() - pressedPos; + if ( dist.manhattanLength() < KGlobalSettings::dndEventDelay() ) { + emit view()->activated( m_url, e->button() ); + } + } +} + +bool MrmlViewItem::hitsPixmap( const QPoint& pos ) const +{ + if ( m_pixmap.isNull() ) + return false; + + if ( pos.x() > pixmapX() && pos.x() < pixmapX() + m_pixmap.width() && + pos.y() > pixmapY() && pos.y() < pixmapY() + m_pixmap.height() ) + return true; + return false; +} + +void MrmlViewItem::createRelevanceElement( QDomDocument& document, + QDomElement& parent ) +{ + int rel = m_combo->currentItem(); + if ( rel == Neutral ) + return; + + MrmlCreator::createRelevanceElement( document, parent, m_url.url(), + (rel == Relevant) ? MrmlCreator::Relevant : MrmlCreator::Irrelevant ); +} + +MrmlViewItem::Relevance MrmlViewItem::relevance() const +{ + return (Relevance) m_combo->currentItem(); +} + +void MrmlViewItem::setRelevance( Relevance relevance ) +{ + m_combo->setCurrentItem( relevance ); +} + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// + + +int MrmlViewItemList::compareItems( QPtrCollection::Item item1, + QPtrCollection::Item item2 ) +{ + double s1 = (static_cast( item1 ))->similarity(); + double s2 = (static_cast( item2 ))->similarity(); + + if ( s1 < s2 ) + return 1; + else if ( s1 > s2 ) + return -1; + else + return 0; +} + +#include "mrml_view.moc" diff --git a/kmrml/kmrml/mrml_view.h b/kmrml/kmrml/mrml_view.h new file mode 100644 index 00000000..f6c9f58c --- /dev/null +++ b/kmrml/kmrml/mrml_view.h @@ -0,0 +1,180 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef MRML_VIEW_H +#define MRML_VIEW_H + +#include +#include +#include +#include +#include +#include + +class QDomDocument; +class QDomElement; +class QTimer; + +class KComboBox; + +namespace KMrml +{ + +class MrmlViewItem; + + +class MrmlViewItemList : public QPtrList +{ +protected: + // sort by similarity + virtual int compareItems( QPtrCollection::Item, QPtrCollection::Item ); + +}; + + +class MrmlView : public QScrollView +{ + friend class MrmlViewItem; + + Q_OBJECT + +public: + MrmlView( QWidget *parent = 0L, const char *name = 0L ); + ~MrmlView(); + + MrmlViewItem * addItem( const KURL& url, const KURL& thumbURL, + const QString& similarity ); + MrmlViewItem * addItem( const KURL& url, const KURL& thumbURL, + double similarity ); + + + void addRelevanceToQuery( QDomDocument&, QDomElement& parent ); + + void clear(); + + bool isEmpty() const { return m_items.isEmpty(); } + + void stopDownloads(); + + void saveState( QDataStream& stream ); + void restoreState( QDataStream& stream ); + +signals: + void activated( const KURL& url, ButtonState button ); + void onItem( const KURL& url ); + +protected: + virtual void resizeEvent( QResizeEvent * ); + +private slots: + void slotLayout(); + void slotDownloadFinished( const KURL&, const QByteArray& ); + +private: + /** + * @returns a _temporary_ pointer to a pixmap. Copy it! + */ + QPixmap * getPixmap( const KURL& url ); + + MrmlViewItemList m_items; + QTimer *m_timer; + QPixmapCache m_pixmapCache; + QPixmap m_unavailablePixmap; + + +}; + + +class MrmlViewItem : public QFrame +{ + Q_OBJECT + +public: + enum Relevance + { + Relevant = 0, + Neutral = 1, + Irrelevant = 2 + }; + + MrmlViewItem( const KURL& url, const KURL& thumbURL, double similarity, + MrmlView *view, const char *name=0L ); + virtual ~MrmlViewItem(); + + void setPixmap( const QPixmap& pixmap ); + + void createRelevanceElement( QDomDocument& document, QDomElement& parent ); + + double similarity() const { return m_similarity; } + + void setSimilarity( double value ); + + virtual QSize sizeHint() const; + + const KURL& url() const { return m_url; } + const KURL& thumbURL() const { return m_thumbURL; } + + bool hasRemotePixmap() const { return !m_thumbURL.isLocalFile() && m_hasRemotePixmap; } + + Relevance relevance() const; + void setRelevance( Relevance relevance ); + +protected: + virtual void paintEvent( QPaintEvent * ); + virtual void resizeEvent( QResizeEvent * ); + + virtual void mousePressEvent( QMouseEvent * ); + virtual void mouseMoveEvent( QMouseEvent * ); + virtual void mouseReleaseEvent( QMouseEvent * ); + +private: + bool hitsPixmap( const QPoint& ) const; + MrmlView * view() const { return m_view; } + + inline int pixmapX() const { + return QMAX( margin, (width() - m_pixmap.width()) / 2); + } + inline int pixmapY() const { + return m_combo->y() - similarityHeight - m_pixmap.height() - margin; + } + + KComboBox *m_combo; // for relevance + MrmlView *m_view; + + KURL m_url; + KURL m_thumbURL; + + QPixmap m_pixmap; + + double m_similarity; + const int similarityFullWidth; + bool m_hasRemotePixmap; + + QPoint pressedPos; + + static const int spacing = 3; + static const int margin = 5; + static const int similarityHeight = 4; + +}; + +QDataStream& operator <<( QDataStream& stream, const KMrml::MrmlViewItem& ); + +} + +#endif // MRML_VIEW_H diff --git a/kmrml/kmrml/mrmlsearch.cpp b/kmrml/kmrml/mrmlsearch.cpp new file mode 100644 index 00000000..6f411313 --- /dev/null +++ b/kmrml/kmrml/mrmlsearch.cpp @@ -0,0 +1,74 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +// This little baby is called from Konqueror's popupmenu, when you hit +// "Search for similar images...". This program simply gets the URLs +// from Konqueror and creates a query of the form +// mrml://host.com/?relevant=url1;url2;url3;url4.... +// By default, the mrml URL is mrml://localhost", but you can override that +// by editing ~/.kde/share/config/kio_mrmlrc and adding +// [MRML Settings] +// Default URL=mrml://url.to.your.giftserver.com +// +// mrmlsearch will then invoke "kfmclient openURL query" to start open +// a new Konqueror window and perform the query. + +#include + +#include +#include +#include +#include +#include +#include + +#include + +extern "C" KDE_EXPORT int kdemain( int argc, char **argv ) +{ + QString query; + + for ( int i = 1; i < argc; i++ ) { + if ( i > 1 ) + query += ';'; + QString path = QFile::decodeName( argv[i] ); + if ( path.at( 0 ) == '/' ) { + KURL u; + u.setPath( path ); + path = u.url(); + } + query.append( path ); + } + + KInstance instance( "kio_mrml" ); + + KMrml::Config config( instance.config() ); + KMrml::ServerSettings settings = config.defaultSettings(); + KURL url; + url.setProtocol( "mrml" ); + url.setHost( settings.host ); + + query = KURL::encode_string_no_slash( query ); + query.prepend( "?relevant=" ); // this is not encoded! + url.setQuery( query ); + qDebug("***** Query: %s ** URL: %s", query.latin1(), url.url().latin1()); + + return execlp( "kfmclient", + "kfmclient", "openURL", QFile::encodeName(url.url()).data(), + "text/mrml", (void *)0 ); +} diff --git a/kmrml/kmrml/propertysheet.cpp b/kmrml/kmrml/propertysheet.cpp new file mode 100644 index 00000000..ec46aac0 --- /dev/null +++ b/kmrml/kmrml/propertysheet.cpp @@ -0,0 +1,206 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "propertysheet.h" + +#include "mrml_elements.h" +#include "mrml_shared.h" + +#include +#include + +using namespace KMrml; + +template class QValueList; + +PropertySheet::PropertySheet() +{ + init(); +} + +PropertySheet::PropertySheet( const QDomElement& elem ) +{ + init(); + + initFromDOM( elem ); +} + +PropertySheet::PropertySheet( const PropertySheet& ps ) +{ + *this = ps; +} + +PropertySheet& PropertySheet::operator= ( const PropertySheet& ps ) +{ + if ( &ps == this ) + return *this; + + m_visibility = ps.m_visibility; + m_type = ps.m_type; + m_caption = ps.m_caption; + m_id = ps.m_id; + + m_sendType = ps.m_sendType; + m_sendName = ps.m_sendName; + m_sendValue = ps.m_sendValue; + + m_minRange = ps.m_minRange; + m_maxRange = ps.m_maxRange; + m_stepSize = ps.m_stepSize; + + m_minSubsetSize = ps.m_minSubsetSize; + m_maxSubsetSize = ps.m_maxSubsetSize; + + // deep copy of m_subSheets + QPtrListIterator it( ps.m_subSheets ); + for ( ; it.current(); ++it ) + m_subSheets.append( new PropertySheet( *it.current() ) ); + + return *this; +} + +void PropertySheet::init() +{ + m_subSheets.setAutoDelete( true ); + m_visibility = Visible; +} + +void PropertySheet::initFromDOM( const QDomElement& elem ) +{ + m_subSheets.clear(); + + m_visibility = getVisibility( elem.attribute( MrmlShared::visibility() )); + m_type = getType( elem.attribute( MrmlShared::propertySheetType() ) ); + m_caption = elem.attribute( MrmlShared::caption() ); + m_id = elem.attribute( MrmlShared::propertySheetId() ); + m_sendType = getSendType( elem.attribute( MrmlShared::sendType() )); + m_sendName = elem.attribute( MrmlShared::sendName() ); + m_sendValue = elem.attribute( MrmlShared::sendValue() ); + m_minRange = toInt( elem.attribute( MrmlShared::from() )); + m_maxRange = toInt( elem.attribute( MrmlShared::to() )); + m_stepSize = toInt( elem.attribute( MrmlShared::step() )); + + m_minSubsetSize = toInt( elem.attribute( MrmlShared::minSubsetSize() )); + m_maxSubsetSize = toInt( elem.attribute( MrmlShared::maxSubsetSize() )); + + QValueList children = + KMrml::directChildElements( elem, MrmlShared::propertySheet() ); + QValueListConstIterator it = children.begin(); + for ( ; it != children.end(); ++it ) + m_subSheets.append( new PropertySheet( *it ) ); +} + +QWidget * PropertySheet::createWidget( QWidget */*parent*/, const char */*name*/ ) +{ + QWidget *w = 0L; + + switch ( m_type ) + { + case Numeric: + { +// KIntNumInput *input = new KIntNumInput(); + break; + } + + case Subset: + { + if ( m_minSubsetSize == 1 && m_maxSubsetSize == 1 ) + { + + } + + break; + } + + default: + qDebug("** can't create widget for type: %i", m_type); + } + + return w; +} + + +// +// static methods +// +PropertySheet::Visibility PropertySheet::getVisibility( const QString& value ) +{ + Visibility vis; + + if ( value == MrmlShared::invisible() ) + vis = Invisible; + else if ( value == MrmlShared::popup() ) + vis = Popup; + else + vis = Visible; // default value + + return vis; +} + +PropertySheet::Type PropertySheet::getType( const QString& value ) +{ + Type type = (Type) 0; + + if ( value == MrmlShared::multiSet() ) + type = MultiSet; + else if ( value == MrmlShared::subset() ) + type = Subset; + else if ( value == MrmlShared::setElement() ) + type = SetElement; + else if ( value == MrmlShared::boolean() ) + type = Boolean; + else if ( value == MrmlShared::numeric() ) + type = Numeric; + else if ( value == MrmlShared::textual() ) + type = Textual; + else if ( value == MrmlShared::panel() ) + type = Panel; + else if ( value == MrmlShared::clone() ) + type = Clone; + else if ( value == MrmlShared::reference() ) + type = Reference; + + return type; +} + +PropertySheet::SendType PropertySheet::getSendType( const QString& value ) +{ + SendType type = (SendType) 0; + + if ( value == MrmlShared::element() ) + type = Element; + else if ( value == MrmlShared::attribute() ) + type = Attribute; + else if ( value == MrmlShared::attributeName() ) + type = AttributeName; + else if ( value == MrmlShared::attributeValue() ) + type = AttributeValue; + else if ( value == MrmlShared::children() ) + type = Children; + else if ( value == MrmlShared::none() ) + type = None; + + return type; +} + +int PropertySheet::toInt( const QString& value, int defaultValue ) +{ + bool ok = false; + int res = value.toInt( &ok ); + return ok ? res : defaultValue; +} diff --git a/kmrml/kmrml/propertysheet.h b/kmrml/kmrml/propertysheet.h new file mode 100644 index 00000000..029d0242 --- /dev/null +++ b/kmrml/kmrml/propertysheet.h @@ -0,0 +1,113 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef PROPERTYSHEET_H +#define PROPERTYSHEET_H + +#include +#include +#include + +class QWidget; + +namespace KMrml +{ + class PropertySheet + { + public: + enum Type + { + MultiSet = 1, // ?? + Subset, // radio-button/combobox or listbox + SetElement, // CheckBox -> disables/enables children? + Boolean, // CheckBox + Numeric, // Slider/Spinbox + Textual, // lineedit + Panel, // groupbox? + Clone, + Reference + }; + enum Visibility + { + Visible, + Invisible, + Popup + }; + enum SendType + { + Element = 1, + Attribute, + AttributeName, + AttributeValue, + Children, + None + }; + + PropertySheet(); + PropertySheet( const QDomElement& elem ); + PropertySheet( const PropertySheet& ps ); + ~PropertySheet() {}; + + PropertySheet& operator=( const PropertySheet& ps ); + + bool isValid() const { + // required mrml attributes + return !m_id.isNull() && m_type != 0 && m_sendType != 0; + } + void initFromDOM( const QDomElement& elem ); + + void toElement( QDomElement& parent ); + + QWidget * createWidget( QWidget *parent, const char *name = 0 ); + + private: + static Visibility getVisibility( const QString& value ); + static Type getType( const QString& value ); + static SendType getSendType( const QString& value ); + static int toInt( const QString& value, int defaultValue = 0 ); + + void init(); + + + // update operator=() when adding data members! + + QPtrList m_subSheets; + Visibility m_visibility; + Type m_type; + QString m_caption; + QString m_id; + + SendType m_sendType; + QString m_sendName; + QString m_sendValue; + + int m_minRange; + int m_maxRange; + int m_stepSize; + + // Type = Subset && m_minSubsetSize == m_maxSubsetSize == 1 -> Combobox + // or radio buttons. + // > max > 1 -> Listbox with multiselection + int m_minSubsetSize; + int m_maxSubsetSize; + + }; + +} + +#endif // PROPERTYSHEET_H diff --git a/kmrml/kmrml/propertywidgets.cpp b/kmrml/kmrml/propertywidgets.cpp new file mode 100644 index 00000000..ef00b18f --- /dev/null +++ b/kmrml/kmrml/propertywidgets.cpp @@ -0,0 +1,121 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "propertywidgets.h" + +IntegerWidget::IntegerWidget( const PropertySheet& sheet, + QWidget *parent, const char *name ) + : QHBox( parent, name ) +{ + +} + +IntegerWidget::~IntegerWidget() +{ + +} + +int IntegerWidget::value() const +{ + +} + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// + +ComboWidget::ComboWidget( const PropertySheet& sheet, + QWidget *parent, const char *name ) + : QHBox( parent, name ) +{ + +} + +ComboWidget::~ComboWidget() +{ + +} + +QString ComboWidget::value() const +{ + +} + + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// + +CheckBoxWidget::CheckBoxWidget( const PropertySheet& sheet, + QWidget *parent, const char *name ) + : QHBox( parent, name ) +{ + +} + +CheckBoxWidget::~CheckBoxWidget() +{ + +} + +bool CheckBoxWidget::value() const +{ + +} + + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// + +LineEditWidget::LineEditWidget( const PropertySheet& sheet, + QWidget *parent, const char *name ) + : QHBox( parent, name ) +{ + +} + +LineEditWidget::~LineEditWidget() +{ + +} + +QString LineEditWidget::value() const +{ + +} + + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// + +ListBoxWidget::ListBoxWidget( const PropertySheet& sheet, + QWidget *parent, const char *name ) + : QHBox( parent, name ) +{ + +} + +ListBoxWidget::~ListBoxWidget() +{ + +} + +QStringList ListBoxWidget::value() const +{ + +} + +#include "propertywidgets.moc" diff --git a/kmrml/kmrml/propertywidgets.h b/kmrml/kmrml/propertywidgets.h new file mode 100644 index 00000000..c738d03d --- /dev/null +++ b/kmrml/kmrml/propertywidgets.h @@ -0,0 +1,108 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef PROPERTYWIDGETS_H +#define PROPERTYWIDGETS_H + +#include + +#include "propertysheet.h" + +namespace KMrml +{ + class IntegerWidget : public QHBox + { + Q_OBJECT + + public: + IntegerWidget( const PropertySheet& sheet, + QWidget *parent = parent, const char *name = 0L ); + ~IntegerWidget(); + + int value() const; + + private: + + }; + + class ComboWidget : public QHBox + { + Q_OBJECT + + public: + ComboWidget( const PropertySheet& sheet, + QWidget *parent = parent, const char *name = 0L ); + ~ComboWidget(); + + QString value() const; + + private: + + }; + + class CheckBoxWidget : public QHBox + { + Q_OBJECT + + public: + CheckBoxWidget( const PropertySheet& sheet, + QWidget *parent = parent, const char *name = 0L ); + ~CheckBoxWidget(); + + bool value(); + + private: + + + }; + + + class LineEditWidget : public QHBox + { + Q_OBJECT + + public: + LineEditWidget( const PropertySheet& sheet, + QWidget *parent = parent, const char *name = 0L ); + ~LineEditWidget(); + + QString value(); + + private: + + }; + + class ListBoxWidget : public QHBox + { + Q_OBJECT + + public: + ListBoxWidget( const PropertySheet& sheet, + QWidget *parent = parent, const char *name = 0L ); + ~ListBoxWidget(); + + QStringList values(); + + private: + + }; + +}; + + +#endif // PROPERTYWIDGETS_H diff --git a/kmrml/kmrml/server/Makefile.am b/kmrml/kmrml/server/Makefile.am new file mode 100644 index 00000000..875684b0 --- /dev/null +++ b/kmrml/kmrml/server/Makefile.am @@ -0,0 +1,12 @@ +kde_module_LTLIBRARIES = kded_daemonwatcher.la + +INCLUDES = $(all_includes) +kded_daemonwatcher_la_SOURCES = watcher.cpp watcher.skel +# watcher.stub +kded_daemonwatcher_la_LDFLAGS = $(all_libraries) -module -avoid-version +kded_daemonwatcher_la_LIBADD = $(LIB_KSYCOCA) $(LIB_KDEUI) + +METASOURCES = AUTO + +servicesdir = $(kde_servicesdir)/kded +services_DATA = daemonwatcher.desktop diff --git a/kmrml/kmrml/server/daemonwatcher.desktop b/kmrml/kmrml/server/daemonwatcher.desktop new file mode 100644 index 00000000..c29495b4 --- /dev/null +++ b/kmrml/kmrml/server/daemonwatcher.desktop @@ -0,0 +1,103 @@ +[Desktop Entry] +Type=Service +Name=KDED KMRML Daemon Watcher +Name[ar]=مراقب KDED KMRML Daemon +Name[bs]=KDED KMRML nadzor demona +Name[ca]=Dimoni vigilant KDED KMRL +Name[cs]=Sledovač KMRML démonů +Name[cy]=Gwyliwr Ellyll KMRML KDED +Name[da]=KDED KMRML-dæmon-overvåger +Name[de]=Überwachung der KDE-Bildersuche +Name[el]=Επόπτης δαίμονα KMRML KDED +Name[es]=Guardián del demonio KDED KMRML +Name[et]=KDED KMRML deemoni jälgija +Name[eu]=KDED KMRML deabru behatzailea +Name[fa]=پایشگر شبح KDED KMRML +Name[fi]=KDED KMRML-palvelimen tarkkailija +Name[fr]=Observateur KDE du démon KMRML +Name[gl]=Vixiante do daemon de KDED KMRML +Name[he]=צופה תהליכי הרקע של KDED KMRML +Name[hi]=KDED KMRML डेमन वाचर +Name[hu]=KDED KMRML szolgáltatásfigyelő +Name[is]=Eftirlit með KDED KMRML þjóninum +Name[it]=Controllo del demone KDED KMRML +Name[ja]=KDED KMRML デーモンウォッチャー +Name[kk]=KDED KMRML қызметі +Name[km]=កម្មវិធី​ឃ្លាំមើល​ដេមិន KDED KMRML +Name[lt]=KDED KMRML tarnybos stebėtojas +Name[ms]=Pemerhati Daemon KDED KMRML +Name[nb]=KDED KMRML nisseovervåker +Name[nds]=KMRML-Luerdämoon för KDED +Name[ne]=KDED KMRML डेइमन दर्शक +Name[nl]=KDED KMRML-daemonbeheer +Name[nn]=KDED KMRML-nisseovervaking +Name[pl]=Monitor usług KMRML +Name[pt]=Monitor KMRML de Servidores KDED +Name[pt_BR]=Sentinela de Serviços KDED +Name[ro]=Demon KDED pentru MRML +Name[ru]=Служба MRML +Name[se]=KDED KMRML-duogášprográmmagoziheaddji +Name[sk]=Sledovanie démona KDED KMRML +Name[sl]=Opazovalnik demona KMRML za KDED +Name[sr]=KDED KMRML демон за праћење +Name[sr@Latn]=KDED KMRML demon za praćenje +Name[sv]=KDED KMRML-demonbevakare +Name[ta]=KDED டிமென் வாட்சர் +Name[tg]=Мудири демони KDED KMRML +Name[th]=ตัวเฝ้าดูแดมอน KDED KMRML +Name[tr]=KDED KMRML Aracı İzleyici +Name[uk]=Спостерігач демону KDED KMRML +Name[zh_CN]=KDED KMRML 守护程序监视器 +Name[zh_HK]=KDED KMRML 系統程式監察器 +Name[zh_TW]=KDED KMRML 伺服程式監看器 +Comment=Starts daemons on demand and restarts them on failure +Comment[bg]=Стартиране на демоните при заявка и рестартиране на демони при грешка +Comment[bs]=Pokreće demone po potrebi i restartuje ih ako se sruše +Comment[ca]=Engega els dimonis sota petició i els torna a engegar si fallen +Comment[cs]=Spouští démony na požádání a restartuje je při selhání +Comment[da]=Starter dæmoner ved forespørgsel og genstarter dem ved fejl +Comment[de]=Startet KMRML-Dienste bei Bedarf und im Fehlerfall neu +Comment[el]=Εκκινεί δαίμονες όταν ζητηθεί και τους επανεκκινεί κατά την αποτυχία +Comment[es]=Inicia los demonios bajo demanda y los reinicia si fallan +Comment[et]=Käivitab nõudmisel deemoneid ja taaskäivitab neid ebaõnnestumise korral +Comment[eu]=Demonioak hasi eta bukau egiten ditu eskatzen zaionean +Comment[fa]=شبحها را بر اساس نیاز آغاز می‌کند و هنگام خرابی آنها را بازآغازی می‌کند +Comment[fi]=Käynnistää palvelimia tarpeen mukaan ja uudelleenkäynnistää ne virheen yhteydessä +Comment[fr]=Lance les démons à la demande et les redémarre en cas d'échec +Comment[gl]=Iniciar daemons cando sexa preciso e reinicialos se fallan. +Comment[he]=מפעיל תהליכי רקע לפי דרישה ומפעיל אותם מחדש במקרה של כשל +Comment[hu]=Szükség esetén elindítja, hiba esetén újraindítja a szolgáltatásokat +Comment[is]=Ræsir þjóna þegar þarf og endurræsir þá ef þeir bregðast +Comment[it]=Avvia i demoni su richiesta e li riavvia in caso di problemi +Comment[ja]=デーモンをオンデマンドで起動し、失敗したときは再起動します。 +Comment[kk]=Талап бойынша қызметті жегу, жаңылса қайта жегу +Comment[km]=ចាប់ផ្ដើម​ដេមិន​នៅ​ពេល​ត្រូវការ ហើយ​ចាប់ផ្ដើម​ពួក​វា​ឡើង​វិញ​នៅ​ពេល​បរាជ័យ +Comment[lt]=Paleidžia tarnybas pagal pareikalavimą ir paleidžia iš naujo nesėkmės atveju +Comment[ms]=Mulakan daemons atas permintaan dan mula semula atas kegagalan +Comment[nb]=Starter nisser på forespørsler og starter dem igjen ved feil. +Comment[nds]=Start Achtergrundperzessen op Nafraag un bi Fehlers nieg +Comment[ne]=माग गरेको बेलामा डेइमन सुरु गर्दछ र अफफल भएमा फेरि सुरु गर्दछ +Comment[nl]=Start achtergrondprogramma's op en herstart deze indien nodig +Comment[nn]=Startar nissar når dei trengst og startar dei om att ved feil +Comment[pl]=Uruchamia usługi na żądanie i wznawia je po awarii +Comment[pt]=Inicia os servidores a pedido e reinicia-os em caso de falha +Comment[pt_BR]=Inicia serviços sob demanda e reinicia-os em caso de falha +Comment[ro]=Porneşte demonii la cerere şi îi reporneşte în caz de eroare +Comment[ru]=Поддержка протокола MRML +Comment[sk]=Spustí démonov podľa požiadaviek a pri zlyhaní ich reštartuje +Comment[sl]=Na zahtevo zažene demone in jih ob napaki znova zažene +Comment[sr]=На захтев покреће демоне и поново их покреће ако се сруше +Comment[sr@Latn]=Na zahtev pokreće demone i ponovo ih pokreće ako se sruše +Comment[sv]=Starta demoner vid behov och starta om dem vid fel +Comment[ta]=அவசிய நேரத்தில் டிமென்னை துவக்குகிறது. இயலாதபோது திரும்ப துவக்குகிறது +Comment[tg]=Оғози демон аз рӯи дархост ва ҳангоми нуқсони он аз сари нав оғоз намудан. +Comment[tr]=İstek halinde programı başlatır ve hata durumunda yeniden başlatır. +Comment[uk]=Запускає демони при потребі та перезапускає їх при аварії +Comment[zh_CN]=按需启动守护程序并在失败时重新启动 +Comment[zh_HK]=依要求啟動系統程式並在失敗時重新啟動它們。 +Comment[zh_TW]=需要時啟動守護程式,失敗的話重新啟動 +ServiceTypes=KDEDModule +X-KDE-ModuleType=Library +X-KDE-Library=daemonwatcher +X-KDE-FactoryName=daemonwatcher +X-KDE-Kded-load-on-demand=true diff --git a/kmrml/kmrml/server/watcher.cpp b/kmrml/kmrml/server/watcher.cpp new file mode 100644 index 00000000..e6137cc5 --- /dev/null +++ b/kmrml/kmrml/server/watcher.cpp @@ -0,0 +1,280 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include + +#include +#include +#include +#include +#include + +#include "watcher.h" + +using namespace KMrml; + +Watcher::Watcher( const QCString& name ) + : KDEDModule( name ) +{ + m_daemons.setAutoDelete( true ); + + // safety, for clients that die without unregistering + KApplication::dcopClient()->setNotifications( true ); + connect( KApplication::dcopClient(), + SIGNAL( applicationRemoved( const QCString& )), + SLOT( slotAppUnregistered( const QCString& ))); +} + +Watcher::~Watcher() +{ + KApplication::dcopClient()->setNotifications( false ); +} + +bool Watcher::requireDaemon( const QCString& clientAppId, + const QString& daemonKey, + const QString& commandline, + uint timeout /* seconds */, + int restartOnFailure ) +{ + if ( !KApplication::dcopClient()->isApplicationRegistered( clientAppId ) ) + kdWarning() << "Watcher::requireDaemon: " << daemonKey + << ": Client AppID is not registered with DCOP: " + << clientAppId << endl; + + DaemonData *daemon = m_daemons.find( daemonKey ); + + if ( daemon ) + { + if ( !daemon->apps.find( clientAppId ) ) + daemon->apps.append( clientAppId ); + + // timeout, commandline and restart values are: first come, first serve + return true; // process already running, all fine + } + + else // start daemon + { + daemon = new DaemonData( daemonKey, commandline, + timeout, restartOnFailure ); + m_daemons.insert( daemonKey, daemon ); + daemon->apps.append( clientAppId ); + +#if KDE_VERSION >= 306 + daemon->process = new KProcess(); + daemon->process->setUseShell( true ); +#else + daemon->process = new KShellProcess(); +#endif + daemon->process->setEnvironment( "LC_ALL", "C" ); + daemon->process->setEnvironment( "LANG", "C" ); + daemon->process->setEnvironment( "LANGUAGE", "C" ); + *daemon->process << commandline; + connect( daemon->process, SIGNAL( processExited( KProcess * ) ), + SLOT( slotProcExited( KProcess * ))); + return startDaemon( daemon ); + } +} + +void Watcher::unrequireDaemon( const QCString& clientAppId, + const QString& daemonKey ) +{ + unrequireDaemon( m_daemons.find( daemonKey ), clientAppId ); +} + +void Watcher::unrequireDaemon( DaemonData *daemon, + const QCString& clientAppId ) +{ + if ( daemon ) + { + daemon->apps.remove( clientAppId ); + if ( daemon->apps.isEmpty() ) + { + if ( !daemon->timer ) + { + daemon->timer = new QTimer(); + connect( daemon->timer, SIGNAL( timeout() ), + SLOT( slotTimeout() )); + } + daemon->timer->start( daemon->timeout * 1000, true ); + } + } + else + kdWarning() << "Watcher::unrequireDaemon: daemon unknown. client: " + << clientAppId << endl; +} + +QStringList Watcher::runningDaemons() const +{ + QStringList result; + QDictIterator it( m_daemons ); + for ( ; it.current(); ++it ) + result.append( it.current()->commandline ); + + return result; +} + +void Watcher::slotProcExited( KProcess *proc ) +{ + DaemonData *daemon = findDaemonFromProcess( proc ); + + if ( proc->normalExit() ) + { + emitExited( daemon ); + return; + } + + if ( daemon ) + { + if ( --daemon->restartOnFailure <= 0 ) + { + if ( KMessageBox::questionYesNo( 0L, + i18n("The server with the command line" + "
%1
" + "is not available anymore. Do you want to " + "restart it?" ).arg( daemon->commandline ), + i18n("Service Failure"), i18n("Restart Server"), i18n("Do Not Restart") ) + == KMessageBox::Yes ) + { + daemon->restartOnFailure = 1; + } + } + + if ( daemon->restartOnFailure > 0 ) + { + startDaemon( daemon ); + return; + } + } + + emitFailure( daemon ); +} + +bool Watcher::startDaemon( DaemonData *daemon ) +{ + if ( daemon->process->start( KProcess::NotifyOnExit ) ) + return true; + + else + { + if ( KMessageBox::questionYesNo( 0L, + i18n("Unable to start the server with the " + "command line" + "
%1
" + "Try again?").arg( daemon->commandline ), + i18n("Service Failure"), i18n("Try Again"), i18n("Do Not Try") ) + == KMessageBox::Yes ) + { + return startDaemon( daemon ); + } + } + + return false; +} + +void Watcher::slotTimeout() +{ + QTimer *timer = static_cast( const_cast( sender() ) ); + DaemonData *daemon = findDaemonFromTimer( timer ); + if ( daemon ) + { + if ( daemon->apps.isEmpty() ) + { + // the daemon and KProcess might get deleted by killing the + // KProcess (through slotProcExited()), so don't dereference + // daemon after proc->kill() + QString key = daemon->daemonKey; + + // noone registered during the timeout, so kill the daemon + if ( !daemon->process->kill() ) + daemon->process->kill( SIGKILL ); + + m_daemons.remove( key ); + } + } +} + +DaemonData * Watcher::findDaemonFromProcess( KProcess *proc ) +{ + DaemonData *daemon; + QDictIterator it( m_daemons ); + for ( ; (daemon = it.current()); ++it ) + { + if ( daemon->process == proc ) + return daemon; + } + + return 0L; +} + +DaemonData * Watcher::findDaemonFromTimer( QTimer *timer ) +{ + DaemonData *daemon; + QDictIterator it( m_daemons ); + for ( ; (daemon = it.current()); ++it ) + { + if ( daemon->timer == timer ) + return daemon; + } + + return 0L; +} + +void Watcher::slotAppUnregistered( const QCString& appId ) +{ + if ( m_daemons.isEmpty() ) + return; + + DaemonData *daemon; + QDictIterator it( m_daemons ); + for ( ; (daemon = it.current()); ++it ) + { + if ( daemon->apps.find( appId ) != -1 ) + unrequireDaemon( daemon, appId ); + } +} + +void Watcher::emitExited( DaemonData *daemon ) +{ + if ( daemon ) + { + daemonExited( daemon->daemonKey, + daemon->process->pid(), + daemon->process->exitStatus() ); + + m_daemons.remove( daemon->daemonKey ); + } +} + +void Watcher::emitFailure( DaemonData *daemon ) +{ + if ( daemon ) + { + daemonDied( daemon->daemonKey, daemon->process->pid() ); + m_daemons.remove( daemon->daemonKey ); // deletes daemon + KProcess + } +} + +extern "C" { + KDE_EXPORT KDEDModule *create_daemonwatcher(const QCString & obj ) + { + return new Watcher( obj ); + } +} + + +#include "watcher.moc" diff --git a/kmrml/kmrml/server/watcher.h b/kmrml/kmrml/server/watcher.h new file mode 100644 index 00000000..67d9b5e1 --- /dev/null +++ b/kmrml/kmrml/server/watcher.h @@ -0,0 +1,107 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Carsten Pfeiffer + + 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, version 2. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef LAUNCHER_H +#define LAUNCHER_H + +#include +#include +#include +#include +#include + +#include +#include + +namespace KMrml +{ + class DaemonData + { + public: + DaemonData( const QString& key, const QString& cmd, + uint time, int numRestarts ) + : daemonKey( key ), + commandline( cmd ), + timeout( time ), + apps( true ), // deep copies + restartOnFailure( numRestarts ), + process( 0L ), + timer( 0L ) + { + } + ~DaemonData() + { + delete process; + delete timer; + } + QString daemonKey; + QString commandline; + uint timeout; + QStrList apps; + int restartOnFailure; + KProcess *process; + QTimer *timer; + }; + + class Watcher : public KDEDModule + { + Q_OBJECT + K_DCOP + + public: + Watcher( const QCString& name = "daemonwatcher" ); + ~Watcher(); + + k_dcop: + virtual bool requireDaemon( const QCString& clientAppId, + const QString& daemonKey, + const QString& commandline, + uint timeout = 60 /* seconds */, + int numRestarts = 5 ); + virtual void unrequireDaemon( const QCString& clientAppId, + const QString& daemonKey ); + virtual QStringList runningDaemons() const; + + k_dcop_signals: + void daemonExited(const QString& daemonKey, pid_t pid, int exitStatus); + void daemonDied( const QString& daemonKey, pid_t pid ); + + protected: + bool startDaemon( DaemonData *daemon ); + + protected slots: + virtual void slotTimeout(); + + private: + void unrequireDaemon( DaemonData *daemon, const QCString& clientAppId); + DaemonData *findDaemonFromProcess( KProcess *proc ); + DaemonData *findDaemonFromTimer( QTimer *timer ); + + void emitExited( DaemonData *daemon ); + void emitFailure( DaemonData *daemon ); + + private slots: + void slotProcExited( KProcess *proc ); + void slotAppUnregistered( const QCString& appId ); + + QDict m_daemons; + }; + +} + +#endif // LAUNCHER_H diff --git a/kolourpaint/AUTHORS b/kolourpaint/AUTHORS new file mode 100644 index 00000000..c4befef2 --- /dev/null +++ b/kolourpaint/AUTHORS @@ -0,0 +1,112 @@ + +Authors +======= + +Clarence Dang +Maintainer + +Thurston Dang +Chief Investigator + +Kristof Borrey +Icons + +Kazuki Ohta +InputMethod Support + +Nuno Pinheiro +Icons + +Danny Allen +Icons + +Martin Koller +Scanning Support + + +Thanks To +========= + +Rashid N. Achilov +Toyohiro Asukai +Bela-Andreas Bargel +Waldo Bastian +Ismail Belhachmi +Sashmit Bhaduri +Antonio Bianco +Stephan Binner +Markus Brueffer +Rob Buis +Lucijan Busch +Mikhail Capone +Enrico Ceppi +Tom Chance +Albert Astals Cid +Jennifer Dang +Lawrence Dang +Christoph Eckert +David Faure +P. Fisher +Nicolas Goutte +Herbert Graeber +Brad Grant +David Greenaway +Wilco Greven +Hubert Grininger +Adriaan de Groot +Esben Mose Hansen +Nadeem Hasan +Simon Hausmann +Michael Hoehne +Andrew J +Werner Joss +Derek Kite +Tobias Koenig +Dmitry Kolesnikov +Stephan Kulow +Eric Laffoon +Michael Lake +Sebastien Laout +David Ling +Volker Lochte +Anders Lund +Jacek Masiulaniec +Benjamin Meyer +Amir Michail +Robert Moszczynski +Dirk Mueller +Ruivaldo Neto +Ralf Nolden +Steven Pasternak +Cedric Pasteur +Erik K. Pedersen +Dennis Pennekamp +Jos Poortvliet +Boudewijn Rempt +Marcos Rodriguez +Matt Rogers +Francisco Jose Canizares Santofimia +Bram Schoenmakers +Dirk Schonberger +Lutz Schweizer +Emmeran Seehuber +Peter Simonsson +Andrew Simpson +A T Somers +Igor Stepin +Stephen Sweeney +Bart Symons +Stefan Taferner +Hogne Titlestad +Brandon Mark Turner +Jonathan Turner +Stephan Unknown +Dries Verachtert +Simon Vermeersch +Lauri Watts +Mark Wege +Christoph Wiesen +Andre Wobbeking +Luke-Jr +Maxim_86ualb2 +Michele diff --git a/kolourpaint/BUGS b/kolourpaint/BUGS new file mode 100644 index 00000000..84f3391f --- /dev/null +++ b/kolourpaint/BUGS @@ -0,0 +1,154 @@ + +Please send bug reports and feature requests to http://bugs.kde.org/. +Don't hesitate to report bugs nor hesitate to send us your wishes - it +provides valuable feedback that will help to improve future versions of +KolourPaint and you will not receive flames for reporting duplicates. + + +This file lists known bugs in this version that are not considered +"release critical" and are difficult to fix: + + +1. Flicker when zooming in/out. + +3. Tool Box & Colour Box RMB ToolBar Menus do not work. + +4. Image dialog spinboxes should accept Enter Key (instead of the dialog's + OK button) after the user has typed something. + + OR + + Spinboxes should signal that their values have changed every time the + user changes the text (rather than after pressing Enter or clicking on + another spinbox etc.). + + The need for the "Update Preview" button and the difficulty of keeping + the percentages and dimensions in sync in the Resize / Scale dialog are + manifestations of the current QSpinBox behaviour. + +6. a) The undo history and document modified state are not updated during + the drawing of multi-segment shapes (Polygon, Connected Lines, + Curve). They are however updated after shapes' completion. + + b) The text and brush-like tools set the document modified flag even if + user cancels the draw operation. + + c) Select a region, manipulate it (e.g. move), undo - the document is + still marked as modified (because 2 commands - the create selection + and the move - were added but only one was undone). + +7. Certain shapes may have the wrong size (usually only a pixel off and + only in extreme cases) e.g. an ellipse of height 1 always has a width 1 + pixel less than it should be. This is a Qt bug. + +8. At zoom levels that aren't multiples of 100%, parts of the image may + appear to move when the user interacts with it. Other minor redraw + glitches may also occur at such zoom levels. + +9. Keyboard shortcut changes do not propagate to other KolourPaint windows + (but will propagate to future windows). + +10. "File/Open Recent" entries are not updated interprocess. + +11. The blinking text cursor will "disappear" if you type more text than + you can fit in a text box. + +12. You cannot select only parts of the text you write. + +13. Due to a workaround for a Qt bug, writing text with the foreground + colour set to transparent is incredibly slow. Write your text in + another colour and then set the foreground colour to transparent after + you've finished typing to avoid this issue. + +14. The text cursor may be momentarily misrendered when scrolling the view. + +17. a) Using KolourPaint on a remote X display may result in redraw errors + and pixel data corruption. + + b) KolourPaint is screen depth dependent. Opening an image with a + an alpha channel and/or a depth higher than the screen and then + saving it will likely result in loss of colour information. Also, + 8-bit screens are not supported at all. To reduce data loss, run + your screen at 24-bit. This bug will be addressed in a future + version of KolourPaint. + +19. Read support for EPS files is extremely slow. You should not enable + the "Save Preview" dialog when saving to EPS. This is an issue with + KDE. + +20. Pasting a large image (esp. one that doesn't compress well as PNG) + into an image editor (not necessarily KolourPaint) running as + different process from the KolourPaint which was the source of the + image, on a sufficiently slow computer, may fail with the following + output to STDERR: + + "kolourpaint: ERROR: kpMainWindow::paste() with sel without pixmap + QClipboard: timed out while sending data" + + This is a Qt bug. + +21. It is not always possible to copy and paste between 2 instances of + KolourPaint running different Qt versions. See + QDataStream::setVersion(). + +22. The Emboss, Blur and Sharpen effects give different results depending + on _both_: + + a) The KDE version KolourPaint was compiled with + (due to KImageEffect not supporting strength settings for these + effects in KDE 3.0, KolourPaint repeats these effects in order to + simulate strength) + + b) The KDE version KolourPaint is running under + (e.g. for the same function calls, KDE 3.2's effects are slower but + give better results than those in KDE 3.0) + +23. Changing tool options while in the middle of a drawing option may + confuse KolourPaint. For instance: + + a) With the brush tools, the cursor incorrectly appears. + + b) With the rectangle-based tools, the temporary pixmap does not resize + when the line width increases. + +25. Sometimes when you take a screenshot of a window, and then paste in a + new window, it will be greyscale. When pasting again, it will still be + greyscale. Cannot consistently reproduce. [Thurston] + +26. Drawing with the keyboard is unreliable. Depending on the X server, + either holding down Enter may continually switch between drawing and + not drawing or KolourPaint may fail to detect the release of the Enter + key. + +27. InputMethod has not been tested at zoom levels other than 100%. + +28. KolourPaint has not been tested against invalid or malicious clipboard + data. + + +Issue with XFree86 <= 3.3.6 with the "Emulate3Buttons" Option +============================================================= + +When drawing, clicking the left or right mouse button that did not +initiate the current operation will, in this order: + +1. finalise the current drawing operation +2. attempt to paste the contents of the middle-mouse-button clipboard + +instead of canceling the current drawing operation. + +This is due to XFree86 sending a release notification for the button that +initiated the drawing operation, followed by a press notification for the +emulated 3rd button; instead of just a single press notification for the +button that is intended to cancel the operation. This works correctly in +XFree86 4.x with "Emulate3Buttons" on because it is harder to trigger the +emulation for the 3rd button as it is only invoked if the left and right +buttons are pressed at almost the same time. + +Possible solutions: + +a) Use XFree86 4.x or an X server from another vendor (e.g. X.org). +b) Press Escape in KolourPaint to cancel the current drawing operation + instead of using the problematic click method described above. +c) Disable "Emulate3Buttons". + diff --git a/kolourpaint/COPYING b/kolourpaint/COPYING new file mode 100644 index 00000000..df47eb9b --- /dev/null +++ b/kolourpaint/COPYING @@ -0,0 +1,23 @@ +Copyright (c) 2003,2004,2005,2006 Clarence Dang +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/kolourpaint/ChangeLog b/kolourpaint/ChangeLog new file mode 100644 index 00000000..9acd0397 --- /dev/null +++ b/kolourpaint/ChangeLog @@ -0,0 +1,15 @@ + +For logs of _every_ single change made to KolourPaint between any date or +revision, visit: + + http://websvn.kde.org/trunk/KDE/kdegraphics/kolourpaint + + http://websvn.kde.org/branches/KDE//kdegraphics/kolourpaint + http://websvn.kde.org/tags/KDE//kdegraphics/kolourpaint + + http://websvn.kde.org/branches/kolourpaint + http://websvn.kde.org/tags/kolourpaint + + +For a summary of user-visible changes between each release, read NEWS. + diff --git a/kolourpaint/Makefile.am b/kolourpaint/Makefile.am new file mode 100644 index 00000000..35da2859 --- /dev/null +++ b/kolourpaint/Makefile.am @@ -0,0 +1,76 @@ +SUBDIRS = cursors pics pixmapfx tools views widgets + +bin_PROGRAMS = kolourpaint + + +kolourpaint.o: kolourpaintlicense.h kolourpaintversion.h + +kolourpaintlicense.h : $(srcdir)/COPYING + echo "static const char * const kpLicenseText =" > kolourpaintlicense.h + cat $(srcdir)/COPYING | sed -e 's/"/\\"/g' -e 's/$$/\\n"/g' -e 's/^/ "/g' >> kolourpaintlicense.h + echo ";" >> kolourpaintlicense.h + +kolourpaintversion.h : $(srcdir)/VERSION + echo "static const char * const kpVersionText =" > kolourpaintversion.h + cat $(srcdir)/VERSION | sed -e 's/"/\\"/g' -e 's/$$/"/g' -e 's/^/ "/g' >> kolourpaintversion.h + echo ";" >> kolourpaintversion.h + +CLEANFILES = kolourpaintlicense.h kolourpaintversion.h + + +kolourpaint_SOURCES = kolourpaint.cpp \ + kpdocument.cpp \ + kpdocumentmetainfo.cpp \ + kpdocumentsaveoptions.cpp \ + kpdocumentsaveoptionswidget.cpp \ + kpview.cpp \ + kpcolor.cpp kpcommandhistory.cpp \ + kpmainwindow.cpp \ + kpmainwindow_edit.cpp kpmainwindow_help.cpp \ + kpmainwindow_image.cpp kpmainwindow_tools.cpp \ + kpmainwindow_file.cpp kpmainwindow_settings.cpp kpmainwindow_statusbar.cpp \ + kpmainwindow_text.cpp \ + kpmainwindow_view.cpp \ + kpselection.cpp kpselectiondrag.cpp kpselectiontransparency.cpp \ + kpsinglekeytriggersaction.cpp \ + kptemppixmap.cpp kptextstyle.cpp \ + kpthumbnail.cpp \ + kptool.cpp \ + kpviewmanager.cpp \ + kpviewscrollablecontainer.cpp \ + kpwidgetmapper.cpp +kolourpaint_LDFLAGS = $(all_libraries) $(KDE_RPATH) +kolourpaint_LDADD = $(LIB_KDEPRINT) \ + cursors/libkolourpaintcursors.la \ + pixmapfx/libkolourpaintpixmapfx.la \ + tools/libkolourpainttools.la \ + views/libkolourpaintviews.la \ + widgets/libkolourpaintwidgets.la + +AM_CPPFLAGS = -I$(srcdir)/cursors -I$(srcdir)/interfaces \ + -I$(srcdir)/pixmapfx \ + -I$(srcdir)/tools \ + -I$(srcdir)/views \ + -I$(srcdir)/widgets $(all_includes) + +METASOURCES = AUTO + +rcdir = $(kde_datadir)/kolourpaint +rc_DATA = kolourpaintui.rc + +xdg_apps_DATA = kolourpaint.desktop + +messages: rc.cpp + $(EXTRACTRC) *.rc *.ui \ + cursors/*.rc cursors/*.ui \ + pixmapfx/*.rc pixmapfx/*.ui \ + tools/*.rc tools/*.ui \ + widgets/*.rc widgets/*.ui \ + >> rc.cpp + $(XGETTEXT) *.cpp *.h \ + cursors/*.cpp cursors/*.h \ + pixmapfx/*.cpp pixmapfx/*.h \ + tools/*.cpp tools/*.h \ + widgets/*.cpp widgets/*.h \ + -o $(podir)/kolourpaint.pot + diff --git a/kolourpaint/NEWS b/kolourpaint/NEWS new file mode 100644 index 00000000..43828069 --- /dev/null +++ b/kolourpaint/NEWS @@ -0,0 +1,349 @@ + +KolourPaint 1.4_relight Series (branches/KDE/3.5/) +=============================== + +KolourPaint 1.4.9_relight (Frozen ???) + + * Ensure selection operations always repaint correctly + [the effects of this change are unlikely to be functionality visible] + +KolourPaint 1.4.8_relight (Frozen 2007-10-08) + + * Always enable the paste actions to guarantee that pasting from + non-Qt applications is always allowed (non-Qt applications do not + notify KolourPaint when they place objects into the clipboard) + + * Paste transparent pixels as white instead of uninitialized colors, + when the app does not support pasting transparent pixels (such as + OpenOffice.org) + + * Make "Edit / Paste in New Window" always paste white pixels as white + (it used to paste them as transparent when the selection transparency + mode was set to Transparent) + + * Saving, exporting and printing a document with an active text box, + that has opaque text and a transparent background, antialiases the + text with the document below + + * "Edit / Paste From File..." respects the "Transparent" selection mode + + * Focus an input field when the "Skew", "Rotate" and "Resize / Scale" + dialogs are displayed -- this allows the user to edit values without + an extra mouse click + + * Add error dialogs for: + - if scanning support is unavailable + - running out of graphics memory during a scan + + * Other minor changes -- some of these are: + - Finish the current shape in more cases of menu item accesses + - [internal] kpDocument::selectionCopyOntoDocument() marks the document + as modified + - More comments + +KolourPaint 1.4.7_relight (Frozen 2007-05-14) + + * Save local files atomically - KolourPaint will no longer truncate + an existing file if the KImageIO library for the file format is + missing or if you run out of disk space. + + * Add "File / Scan..." feature (Martin Koller) + + * Add global session save/restore (Bug #94651) + + * Make "File / Open Recent" consistently work when multiple windows are + open + + * CTRL+C'ing a text box also places the text in the middle-mouse-button + clipboard, in lieu of being able to highlight the text to do this + + * Change minimum allowed zoom level for the grid from 600% to 400% + +KolourPaint 1.4.6_relight (Frozen 2007-01-13) + + * Fix crash triggered by rapidly deselecting the selection after + drag-scaling it (Bug #117866) + [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/] + +KolourPaint 1.4.5_relight (Frozen 2006-09-19) + + * Translation updates + +KolourPaint 1.4.4_relight (Frozen 2006-07-12) + + * Minor code cleanups and corrections + +KolourPaint 1.4.3_relight (Frozen 2006-05-02) + + * Probably translation updates + +KolourPaint 1.4.2_relight (Frozen 2006-03-12) + + * Printing improvements (Bug #108976) + - Respect image DPI + - Fit image to page if image is too big + - Centre image on page + [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/] + +KolourPaint 1.4.1_relight (Frozen 2006-01-15) + + * Updated documentation (Thurston) + +KolourPaint 1.4_relight (Frozen 2005-11-08) + + * New icons (Danny Allen, Nuno Pinheiro) + + * Tool Box icon size is 22x22, not 16x16, at screen resolution >= 1024x768 + + * CTRL + Mouse Wheel = Zoom + + * While freehand selection scaling, holding Shift maintains aspect ratio + + * Prevent accidental drags in the Colour Palette from pasting text + containing the colour code + [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/] + + * Cells in the bottom row and cells in the rightmost column of the Colour + Palette are now the same size as the other cells + [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/] + + * Text drops to the empty part of the scrollview will not be placed + outside the document + [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/] + + * Rename icons from "hi" to "cr" - back to the state of 1.0 (Danny Allen) + but leave application icons as "hi" (Jonathan Riddell) + + * Enforce text box font height to prevent e.g. Chinese characters in + buggy fonts from enlarging the text box and putting the cursor out of + sync with the text + [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/] + + * Clicking in a text box selects a character based on its midpoint - + not leftmost point - to be consistent with all text editors + (esp. noticeable with big fonts) + [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/] + + * Return and Numpad 5 Key now draw + [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/] + + * Tool Actions placed outside the Tool Box resize with their toolbars + [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/] + + * Ensure Color Similarity maximum is 30, not 29 due to gcc4 + [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/] + + * Tool Box traps right clicks (for the RMB Menu) on top of tool options + widgets and the empty part of the Tool Box + [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/] + + * Correct and update image format associations to all formats supported + by KDE 3.5 (kdelibs/kimgio/:r466654) + + * String fixes (Stefan Winter) + [also in branches/KDE/3.4/] + + * Other string fixes (Malcolm Hunter, Clarence Dang, Stephan Binner) + + +KolourPaint 1.4_light Series (branches/KDE/3.4/) +============================ + +KolourPaint 1.4_light (Frozen 2005-02-22) + * Antialias text when the text box has a transparent background (Bug #24) + [later backported to branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/] + * Add Unzoomed Thumbnail Mode and Thumbnail Rectangle + * Add RMB context menu for when a selection tool is active (closing KDE + Bug #92882) + * More intuitive "Set as Image" behaviour (esp. with selection borders). + Thanks to Michael Lake for the feedback. + [later backported to branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/] + * InputMethod support + [later backported to branches/kolourpaint/1.2_kde3/] + * Save "More Effects" dialog's last effect to config file + * Save "Resize / Scale" dialog's last "Keep aspect ratio" setting to + config file + * Add "Help / Acquiring Screenshots" + * Fix selection regressions introduced in 1.2: + - Make selection dragging with CTRL work again (copies selection onto + document) + - When creating freeform selections, include the starting point; also + avoids a QRegion crash with constructing 1-point regions + [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/] + * Fix other selection bugs: + - When the user drags very quickly on a resize handle, resize the + selection instead of moving it + - Draw resize handles above the grid lines - not below - so that the + handles are always visible if they are supposed to be there + [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/] + * Smaller selection and text box resize handles (visually not + actually) - covers up fewer selected pixels, doesn't cover up text + [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/] + * Restore mouse cursor after deselecting selection/text tools + [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/] + * Empty text clipboard fixes: + - Don't get stuck on a wait cursor after attempting to paste empty + text into a text box + - Prevent pasting text from creating a new text box if text is empty + - Prevent copying of empty text box + [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/] + * Speed up renderer (most noticeable with diagonal drag-scrolling at + high zoom) + - Don't paint anything outside of the view's visible region + (previously, clipped only on view _widget_ region) + - Region-aware: paint component rectangles of the update region, + rather than the bounding rectangle + [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/] + * When changing between colour depth and quality widgets in the save + filedialog, make sure "Convert to:" and "Quality:" are correctly + rendered (hacking around a Qt redraw glitch) + [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/] + * Fix crash after using the Colour Picker if it was the first used tool + [kolourpaint-1.2.2_kde3-color_picker_crash.diff] + [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/] + * Fix crash due to text box when scaling image behind it + [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/] + * Even when the thumbnail has focus (and not the main window), blink the + text cursor in all views + [kolourpaint-1.2.2_kde3-thumbnail_blink_text_cursor.diff] + [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/] + * Correct "Soften" and "Sharpen" commands' command history names + * Correct invert commands' command history names + * Fix remaining untranslatable strings (closing KDE Bug #85785) + [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/] + * Update image format associations to all formats supported by KDE 3.4 + * Remove unused images in doc directory + [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/] + * Correct kolourpaint.desktop "Terminal=" and "Categories=" syntax + (Benjamin Meyer) + + +KolourPaint 1.2 Series (branches/KDE/3.3/) +====================== + +Version 1.2 "ByFiat Everytime" (2004-08-18) + * Add up to 500 levels of Undo/Redo (minimum of 10 levels, maximum of + 500 as long as the total history size < 16MB) + * Add freehand resizing of image + * Add freehand smooth scaling of selections + * [also in 1.0 branch] New icons (Kristof Borrey) + * [also in 1.0 branch] Prefer Crystal SVG text icons over KolourPaint's + * [also in 1.0 branch] Add documentation in the KDE Help Centre + * Add drag scrolling + * Add "More Effects" dialog: + - Balance (Brightness, Contrast, Gamma) + - Emboss + - Flatten + - Invert (with choice of channels) + - Reduce Colours + - Soften & Sharpen + * File saving improvements: + - Support colour depths (optional dithering) and "colour monochrome" + - Support JPEG quality + - Realtime file dialog preview with estimated file size + - Retain PNG metadata + - Prompt when attempting lossy save + - Correctly save transparent selections (not as opaque) + * Dither more often when loading (and pasting) images for better quality + * Single key shortcuts for all tools and tool options (automatically + turned off when editing text but can then use Alt+Shift+) + * Arrow keys now move one document pixel - not view pixel - at a time + (more usable when zoomed in) + * Fix selection bugs: + - Fix duplicate "Selection: Create" undo entries (Bug #5a) + - Allow redoing of selection operation if border deselected (Bug #5b) + - Don't print to STDERR when undoing a selection border create + operation and border has already been deselected + - [also in 1.0 branch] When pulling a selection from the document, + only set the bits of the document to the background colour where the + transparent selection is opaque in the same place (this is only + noticeable with colour similarity turned on). Now moving a + selection away and then back to its original place is always a NOP + as it should be. + * Selections can be deselected using Esc or clicking on icon in Tool Box + * Accidental drag detection when deselecting selections or text boxes + * Prevent selection from being moved completely offscreen (at least 1 + pixel of the selection will stay within the view) + * Speed up copying selection when transparency is on + * Improve Text Tool usability: + - Allow single click creation of text box with a sane default size + - Allow freehand resizing of text boxes + - Add Opaque/Transparent selector for greater usability and + consistency with selections + - Minimum size is now 7x7 document pixels (1x1 - not 4x4 - border) + - Text cursor doesn't overlap border anymore + - When dropping text, paste at drop point + - When MMB pasting creates a new text box, do so at mouse position + * When MMB pasting text in an existing box, correctly paste multiline + clipboard contents + * Improve text quality: + - With a transparent background, don't antialias foreground opaque + text with arbitrarily chosen black + - Make sure transparent text shows up on opaque (usually, grey was + problematic) background + * Improve Resize/Scale dialog usability: + - Add Smooth Scale (useful for creating screenshot thumbnails) + - Allow manipulating image when selection is active + - Operation choices stand out as massive, easily clickable buttons + - Default focus on operation choices + * Warn if Resize/Scale, Rotate or Skew will take lots of memory + * Limit startup image size to 2048x2048 + * Eliminate flicker when scrolling + * Thumbnail fixes: + - Reduce flicker when appearing (Bug #2) + - More reasonable minimum size (actually enforce it) + - [also in 1.0 branch] Use deleteLater() + - [also in 1.0 branch] Save geometry even if it's closed very quickly + after a geometry change + * Restore last used tool and tool options on startup + * Add Export, Copy To File, Paste From File, Paste in New Window, + Full Screen Mode + * Add Zoom In/Out buttons to main toolbar + * Rename Crop options in an attempt to reduce confusion: + - "Autocrop" --> "Remove Internal Border" when selection active + - "Crop Outside Selection" --> "Set as Image (Crop)" + * "Set as Image" changes: + - Enable for text boxes + - Underneath transparent bits of selection, fill image with + transparent rather than with background colour + * Permit "reloading" of an empty document + * Fixes when the current URL doesn't exist: + - Don't reload if underlying file disappeared + - Don't add non-existent file to Recent Files history + - Ask to save before mailing or setting as wallpaper + * Only enable Show Path when there is a URL + * Pop up dialog (instead of printing to STDERR) and disable Edit/Paste + on CTRL+V if the clipboard contents disappeared due to the source + application quitting (and Klipper didn't retain clipboard contents) + * Image/Clear now always sets _everything_ within the selection boundary + to the background colour - including transparent pixels + * Add Preview button to Colour Similarity Dialog to work around Bug #4 + regarding spinboxes and enter key + * Colour Picker disallows trying to pick colour outside of image + * Make sure colour palette contains valid and visible colours at 8-bit + * [also in 1.0 branch] Fix (big) memory leak on kpSelection destruction + (Albert Astals Cid) + * Don't leak image dialogs' memory + * [also in 1.0 branch] Don't let C++ destruct the mask bitmap before its + painter when dbl-clicking the color eraser does NOP (avoids + QPaintDevice and X error) + * [also in 1.0 branch] Check for QImageDrag::canDecode() before calling + QImageDrag::decode() (prevents X and valgrind errors) + * [also in 1.0 branch] Fix compilation problem with QT_NO_ASCII_CAST + (Waldo Bastian) + * [also in 1.0 branch] Decrease application preference to below that of + a viewer (Stephan Kulow) + * Remember dialog dimensions + * Remove double dialog margins + * Fix missing i18n()'s + * Fix some untranslatable strings + * [also in 1.0 branch] Corrected several strings + * Remove unused icons + + +KolourPaint 1.0 Series (branches/kolourpaint/1.0/) +====================== + +Version 1.0 "Seagull" (2004-02-29) + * First stable release + diff --git a/kolourpaint/README b/kolourpaint/README new file mode 100644 index 00000000..b045e3b9 --- /dev/null +++ b/kolourpaint/README @@ -0,0 +1,102 @@ + +KolourPaint Version 1.4.9_relight (KDE 3.5.9 Release Frozen ???) +http://www.kolourpaint.org/ + +Copyright (c) 2003,2004,2005,2006 Clarence Dang + + +For licensing and warranty information, read COPYING. +For known problems with this release of KolourPaint, read BUGS. +For what changes have been made, read NEWS. +For developer information, checkout branches/kolourpaint/control/. +For general information, read this file (README): + + +1. What is KolourPaint? +======================= + +KolourPaint is a free, easy-to-use paint program for KDE. + +It aims to be conceptually simple to understand; providing a level of +functionality targeted towards the average user. It's designed for daily +tasks like: + +* Painting - drawing diagrams and "finger painting" +* Image Manipulation - editing screenshots and photos; applying effects +* Icon Editing - drawing clipart and logos with transparency + +It's not an unusable and monolithic program where simple tasks like drawing +lines become near impossible. Nor is it so simple that it lacks essential +features like Undo/Redo. + +KolourPaint is opensource software written in C++ using the Qt and KDE +libraries. + + +2. Features +=========== + +* Undo/Redo Support (10-500 levels of history depending on memory usage) + +* Tools (single key shortcuts available for all tools) + - Brush, Color Eraser, Color Picker, Connected Lines a.k.a. Polyline + - Curve, Ellipse, Eraser, Flood Fill, Line, Pen, Polygon, Rectangle + - Rounded Rectangle, Spraycan, Text + +* Selections (fully undo- and redo-able) + - Rectangular, Elliptical, Free-Form shapes + - Choice between Opaque and Transparent selections + - Full Clipboard/Edit Menu support + - Freehand resizeable + +* Colour Similarity means that you can fill regions in dithered images and + photos + +* Transparency + - Draw transparent icons and logos on a checkerboard background + - All tools can draw in the "Transparent Colour" + +* Image Effects + - Autocrop / Remove Internal Border + - Balance (Brightness, Contrast, Gamma) + - Clear, Emboss, Flatten, Flip, Invert (with choice of channels) + - Reduce Colours, Reduce to Greyscale, Resize, Rotate + - Scale, Set as Image (Crop), Skew, Smooth Scale, Soften & Sharpen + +* Close-up Editing + - Zoom (from 0.01x to 16x) + - Grid + - Thumbnail + +* File Operations + - Open/Save in all file formats provided by KImageIO + (PNG, JPEG, BMP, ICO, PCX, TIFF,...) with preview + - Print, Print Preview + - Mail + - Set as Wallpaper + + +3. Updates & More Information +============================= + +Visit: http://www.kolourpaint.org/ + + +4. Support +========== + +Visit: http://www.kolourpaint.org/ + +If you have any questions about compiling, installing or using KolourPaint, +don't be afraid to contact us. We try to support all versions of +KolourPaint and even issues with 3rd party binary packages. + + +5. Feedback +=========== + +Please send bug reports and feature requests to http://bugs.kde.org/. +Don't hesitate to report bugs nor hesitate to send us your wishes - it +provides valuable feedback that will help to improve future versions of +KolourPaint and you will not receive flames for reporting duplicates. + diff --git a/kolourpaint/VERSION b/kolourpaint/VERSION new file mode 100644 index 00000000..8b2f0f9b --- /dev/null +++ b/kolourpaint/VERSION @@ -0,0 +1 @@ +1.4.8_relight-post diff --git a/kolourpaint/cursors/Makefile.am b/kolourpaint/cursors/Makefile.am new file mode 100644 index 00000000..5ae0504a --- /dev/null +++ b/kolourpaint/cursors/Makefile.am @@ -0,0 +1,11 @@ +INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../cursors -I$(srcdir)/../interfaces \ + -I$(srcdir)/../pixmapfx \ + -I$(srcdir)/../tools \ + -I$(srcdir)/../views \ + -I$(srcdir)/../widgets $(all_includes) + +noinst_LTLIBRARIES = libkolourpaintcursors.la +libkolourpaintcursors_la_SOURCES = kpcursorlightcross.cpp kpcursorprovider.cpp + +METASOURCES = AUTO + diff --git a/kolourpaint/cursors/kpcursorlightcross.cpp b/kolourpaint/cursors/kpcursorlightcross.cpp new file mode 100644 index 00000000..0595d320 --- /dev/null +++ b/kolourpaint/cursors/kpcursorlightcross.cpp @@ -0,0 +1,128 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_CURSOR_LIGHT_CROSS 0 + + +#include + +#include +#include + +#include + + +enum PixelValue +{ + White, Black, Transparent +}; + +static void setPixel (unsigned char *colorBitmap, + unsigned char *maskBitmap, + int width, + int y, int x, enum PixelValue pv) +{ + const int ColorBlack = 1; + const int ColorWhite = 0; + + const int MaskOpaque = 1; + const int MaskTransparent = 0; + + int colorValue, maskValue; + + switch (pv) + { + case White: + colorValue = ColorWhite; + maskValue = MaskOpaque; + break; + + case Black: + colorValue = ColorBlack; + maskValue = MaskOpaque; + break; + + case Transparent: + default: + colorValue = ColorWhite; + maskValue = MaskTransparent; + break; + } + + if (colorValue) + colorBitmap [y * (width / 8) + (x / 8)] |= (1 << (x % 8)); + + if (maskValue) + maskBitmap [y * (width / 8) + (x / 8)] |= (1 << (x % 8)); +} + + +const QCursor *kpMakeCursorLightCross () +{ +#if DEBUG_KP_CURSOR_LIGHT_CROSS + kdDebug () << "kpMakeCursorLightCross() " << endl; +#endif + + const int side = 24; + const int byteSize = (side * side) / 8; + unsigned char *colorBitmap = new unsigned char [byteSize]; + unsigned char *maskBitmap = new unsigned char [byteSize]; + + memset (colorBitmap, 0, byteSize); + memset (maskBitmap, 0, byteSize); + + const int oddSide = side - 1; + const int strokeLen = oddSide * 3 / 8; + + for (int i = 0; i < strokeLen; i++) + { + const enum PixelValue pv = (i % 2) ? Black : White; + + #define X_(val) (val) + #define Y_(val) (val) + #define DRAW(y,x) setPixel (colorBitmap, maskBitmap, side, (y), (x), pv) + // horizontal + DRAW (Y_(side / 2), X_(1 + i)); + DRAW (Y_(side / 2), X_(side - 1 - i)); + + // vertical + DRAW (Y_(1 + i), X_(side / 2)); + DRAW (Y_(side - 1 - i), X_(side / 2)); + #undef DRAW + #undef Y_ + #undef X_ + } + + QCursor *cursor = new QCursor (QBitmap (side, side, colorBitmap, true/*little endian bit order*/), + QBitmap (side, side, maskBitmap, true/*little endian bit order*/)); + + delete [] maskBitmap; + delete [] colorBitmap; + + return cursor; +} + diff --git a/kolourpaint/cursors/kpcursorlightcross.h b/kolourpaint/cursors/kpcursorlightcross.h new file mode 100644 index 00000000..d2bf83e1 --- /dev/null +++ b/kolourpaint/cursors/kpcursorlightcross.h @@ -0,0 +1,38 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kp_cursor_light_cross_h__ +#define __kp_cursor_light_cross_h__ + + +class QCursor; + +const QCursor *kpMakeCursorLightCross (); + + +#endif // __kp_cursor_light_cross_h__ diff --git a/kolourpaint/cursors/kpcursorprovider.cpp b/kolourpaint/cursors/kpcursorprovider.cpp new file mode 100644 index 00000000..45d43801 --- /dev/null +++ b/kolourpaint/cursors/kpcursorprovider.cpp @@ -0,0 +1,49 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include + +#include + +#include + + +static const QCursor *theLightCursor = 0; + + +// public static +QCursor kpCursorProvider::lightCross () +{ + // TODO: don't leak (although it's cleaned up on exit by OS anyway) + if (!theLightCursor) + theLightCursor = kpMakeCursorLightCross (); + + return *theLightCursor; +} diff --git a/kolourpaint/cursors/kpcursorprovider.h b/kolourpaint/cursors/kpcursorprovider.h new file mode 100644 index 00000000..191b4f78 --- /dev/null +++ b/kolourpaint/cursors/kpcursorprovider.h @@ -0,0 +1,43 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kp_cursor_provider_h__ +#define __kp_cursor_provider_h__ + + +class QCursor; + + +class kpCursorProvider +{ +public: + static QCursor lightCross (); +}; + + +#endif // __kp_cursor_provider_h__ diff --git a/kolourpaint/kolourpaint.cpp b/kolourpaint/kolourpaint.cpp new file mode 100644 index 00000000..b9ba0f0c --- /dev/null +++ b/kolourpaint/kolourpaint.cpp @@ -0,0 +1,229 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include +#include +#include +#include +#include +#include +#include + +// for srand +#include +#include +#include + +#include +#include + +#include +#include + + +static const KCmdLineOptions cmdLineOptions [] = +{ + {"+[file]", I18N_NOOP ("Image file to open"), 0}, + KCmdLineLastOption +}; + + +int main (int argc, char *argv []) +{ + KAboutData aboutData + ( + "kolourpaint", + I18N_NOOP ("KolourPaint"), + kpVersionText, + I18N_NOOP ("Paint Program for KDE"), + KAboutData::License_Custom, + 0/*copyright statement - see licence instead*/, + 0/*no free text*/, + "http://www.kolourpaint.org/" + ); + + + // this is _not_ the same as KAboutData::License_BSD + aboutData.setLicenseText (kpLicenseText); + + + // SYNC: with AUTHORS + + aboutData.addAuthor ("Clarence Dang", I18N_NOOP ("Maintainer"), "dang@kde.org"); + aboutData.addAuthor ("Thurston Dang", I18N_NOOP ("Chief Investigator"), + "thurston_dang@users.sourceforge.net"); + aboutData.addAuthor ("Kristof Borrey", I18N_NOOP ("Icons"), "borrey@kde.org"); + aboutData.addAuthor ("Kazuki Ohta", I18N_NOOP ("InputMethod Support"), "mover@hct.zaq.ne.jp"); + aboutData.addAuthor ("Nuno Pinheiro", I18N_NOOP ("Icons"), "nf.pinheiro@gmail.com"); + aboutData.addAuthor ("Danny Allen", I18N_NOOP ("Icons"), "dannya40uk@yahoo.co.uk"); + aboutData.addAuthor ("Martin Koller", + 0/*STRING: string freeze prevents us from writing: Scanning Support*/, + "m.koller@surfeu.at"); + + + aboutData.addCredit ("Rashid N. Achilov"); + aboutData.addCredit ("Toyohiro Asukai"); + aboutData.addCredit ("Bela-Andreas Bargel"); + aboutData.addCredit ("Waldo Bastian"); + aboutData.addCredit ("Ismail Belhachmi"); + aboutData.addCredit ("Sashmit Bhaduri"); + aboutData.addCredit ("Antonio Bianco"); + aboutData.addCredit ("Stephan Binner"); + aboutData.addCredit ("Markus Brueffer"); + aboutData.addCredit ("Rob Buis"); + aboutData.addCredit ("Lucijan Busch"); + aboutData.addCredit ("Mikhail Capone"); + aboutData.addCredit ("Enrico Ceppi"); + aboutData.addCredit ("Tom Chance"); + aboutData.addCredit ("Albert Astals Cid"); + aboutData.addCredit ("Jennifer Dang"); + aboutData.addCredit ("Lawrence Dang"); + aboutData.addCredit ("Christoph Eckert"); + aboutData.addCredit ("David Faure"); + aboutData.addCredit ("P. Fisher"); + aboutData.addCredit ("Nicolas Goutte"); + aboutData.addCredit ("Herbert Graeber"); + aboutData.addCredit ("Brad Grant"); + aboutData.addCredit ("David Greenaway"); + aboutData.addCredit ("Wilco Greven"); + aboutData.addCredit ("Hubert Grininger"); + aboutData.addCredit ("Adriaan de Groot"); + aboutData.addCredit ("Esben Mose Hansen"); + aboutData.addCredit ("Nadeem Hasan"); + aboutData.addCredit ("Simon Hausmann"); + aboutData.addCredit ("Michael Hoehne"); + aboutData.addCredit ("Andrew J"); + aboutData.addCredit ("Werner Joss"); + aboutData.addCredit ("Derek Kite"); + aboutData.addCredit ("Tobias Koenig"); + aboutData.addCredit ("Dmitry Kolesnikov"); + aboutData.addCredit ("Stephan Kulow"); + aboutData.addCredit ("Eric Laffoon"); + aboutData.addCredit ("Michael Lake"); + aboutData.addCredit ("Sebastien Laout"); + aboutData.addCredit ("David Ling"); + aboutData.addCredit ("Volker Lochte"); + aboutData.addCredit ("Anders Lund"); + aboutData.addCredit ("Jacek Masiulaniec"); + aboutData.addCredit ("Benjamin Meyer"); + aboutData.addCredit ("Amir Michail"); + aboutData.addCredit ("Robert Moszczynski"); + aboutData.addCredit ("Dirk Mueller"); + aboutData.addCredit ("Ruivaldo Neto"); + aboutData.addCredit ("Ralf Nolden"); + aboutData.addCredit ("Steven Pasternak"); + aboutData.addCredit ("Cédric Pasteur"); + aboutData.addCredit ("Erik K. Pedersen"); + aboutData.addCredit ("Dennis Pennekamp"); + aboutData.addCredit ("Jos Poortvliet"); + aboutData.addCredit ("Boudewijn Rempt"); + aboutData.addCredit ("Marcos Rodriguez"); + aboutData.addCredit ("Matt Rogers"); + aboutData.addCredit ("Francisco Jose Canizares Santofimia"); + aboutData.addCredit ("Bram Schoenmakers"); + aboutData.addCredit ("Dirk Schönberger"); + aboutData.addCredit ("Lutz Schweizer"); + aboutData.addCredit ("Emmeran Seehuber"); + aboutData.addCredit ("Peter Simonsson"); + aboutData.addCredit ("Andrew Simpson"); + aboutData.addCredit ("A T Somers"); + aboutData.addCredit ("Igor Stepin"); + aboutData.addCredit ("Stephen Sweeney"); + aboutData.addCredit ("Bart Symons"); + aboutData.addCredit ("Stefan Taferner"); + aboutData.addCredit ("Hogne Titlestad"); + aboutData.addCredit ("Brandon Mark Turner"); + aboutData.addCredit ("Jonathan Turner"); + aboutData.addCredit ("Stephan Unknown"); + aboutData.addCredit ("Dries Verachtert"); + aboutData.addCredit ("Simon Vermeersch"); + aboutData.addCredit ("Lauri Watts"); + aboutData.addCredit ("Mark Wege"); + aboutData.addCredit ("Christoph Wiesen"); + aboutData.addCredit ("Andre Wobbeking"); + aboutData.addCredit ("Luke-Jr"); + aboutData.addCredit ("Maxim_86ualb2"); + aboutData.addCredit ("Michele"); + + + KCmdLineArgs::init (argc, argv, &aboutData); + KCmdLineArgs::addCmdLineOptions (cmdLineOptions); + + KApplication app; + + + // mainly for changing wallpaper :) + DCOPClient *client = app.dcopClient (); + if (!client->attach ()) + kdError () << "Could not contact DCOP server" << endl; + + // mainly for the Spraycan Tool + srand ((unsigned int) (getpid () + getppid ())); + + // access more formats + KImageIO::registerFormats (); + + + // Qt says this is necessary but I don't think it is... + QObject::connect (&app, SIGNAL (lastWindowClosed ()), + &app, SLOT (quit ())); + + + if (app.isRestored ()) + { + // Creates a kpMainWindow using the default constructor and then + // calls kpMainWindow::readProperties(). + RESTORE (kpMainWindow) + } + else + { + kpMainWindow *mainWindow; + KCmdLineArgs *args = KCmdLineArgs::parsedArgs (); + + if (args->count () >= 1) + { + for (int i = 0; i < args->count (); i++) + { + mainWindow = new kpMainWindow (args->url (i)); + mainWindow->show (); + } + } + else + { + mainWindow = new kpMainWindow (); + mainWindow->show (); + } + + args->clear (); + } + + + return app.exec (); +} diff --git a/kolourpaint/kolourpaint.desktop b/kolourpaint/kolourpaint.desktop new file mode 100644 index 00000000..8a586219 --- /dev/null +++ b/kolourpaint/kolourpaint.desktop @@ -0,0 +1,92 @@ +[Desktop Entry] + +Name=KolourPaint +Name[nb]=KPaint +Name[ne]=रङ पेन्ट +Name[pa]=ਕੇ-ਰੰਗ-ਪੇਂਟ +Name[sv]=Kolourpaint +Name[ta]=நிற பெயின்ட் +Name[zh_TW]=KolourPaint 小畫家 +GenericName=Paint Program +GenericName[af]=Verf Program +GenericName[ar]=برنامج تلوين +GenericName[bg]=Графичен редактор +GenericName[br]=Goulev tresañ +GenericName[bs]=Jednostavni program za crtanje +GenericName[ca]=Programa de pintura +GenericName[cs]=Kreslící program +GenericName[cy]=Rhaglen Peintio +GenericName[da]=Maleprogram +GenericName[de]=Mal- und Zeichenprogramm +GenericName[el]=Πρόγραμμα ζωγραφικής +GenericName[eo]=Pentrilo +GenericName[es]=Programa de pintura +GenericName[et]=Joonistusprogramm +GenericName[eu]=Marrazteko programa +GenericName[fa]=برنامۀ رنگ +GenericName[fi]=Piirto-ohjelma +GenericName[fr]=Petit programme de dessin +GenericName[ga]=Clár Péinteála +GenericName[gl]=Programa de debuxo +GenericName[he]=תוכנית ציור +GenericName[hi]=छवि बनाने का प्रोग्राम +GenericName[hr]=Program za slikanje +GenericName[hu]=Rajzolóprogram +GenericName[is]=Teikniforrit +GenericName[it]=Programma di disegno +GenericName[ja]=ペイントプログラム +GenericName[kk]=Сурет салу бағдарламасы +GenericName[km]=កម្មវិធី​គូរ +GenericName[lt]=Piešimo programa +GenericName[lv]=Krāsošanas Programma +GenericName[ms]=Program Mewarna +GenericName[mt]=Programm sempliċi tat-tpinġija +GenericName[nb]=Maleprogram +GenericName[nds]=Maalprogramm +GenericName[ne]=पेन्ट कार्यक्रम +GenericName[nl]=Tekenprogramma +GenericName[nn]=Måleprogram +GenericName[nso]=Lenaneo la Paint +GenericName[pa]=ਰੰਗ ਕਾਰਜ +GenericName[pl]=Program Paint +GenericName[pt]=Programa de Pintura +GenericName[pt_BR]=Programa de Pintura +GenericName[ro]=Program de desenare +GenericName[ru]=Графический редактор +GenericName[rw]=Porogaramu Gusiga irangi +GenericName[se]=Málenprográmma +GenericName[sk]=Kreslenie +GenericName[sl]=Slikarski program +GenericName[sr]=Програм за сликање +GenericName[sr@Latn]=Program za slikanje +GenericName[sv]=Ritprogram +GenericName[ta]=பெயிண்ட் நிரலி +GenericName[tg]=Муҳаррири графикӣ +GenericName[th]=โปรแกรมวาดภาพธรรมดาๆ +GenericName[tr]=Boyama Programı +GenericName[uk]=Програма для малювання +GenericName[uz]=Chizish dasturi +GenericName[uz@cyrillic]=Чизиш дастури +GenericName[ven]=Mbekanyamushumo ya Pennde +GenericName[wa]=Program di dessinaedje +GenericName[xh]=Udweliso lwenkqubo lwepeyinti +GenericName[zh_CN]=绘图程序 +GenericName[zh_HK]=繪圖程式 +GenericName[zh_TW]=繪圖程式 +GenericName[zu]=Elila Iprogremu Kapende +Icon=kolourpaint + +Type=Application +Exec=kolourpaint %u +DocPath=kolourpaint/index.html + +# SYNC: Run branches/kolourpaint/control/scripts/gen_mimetype_line.sh in +# the version of kdelibs/kimgio/ (e.g. KDE 3.5) KolourPaint is +# shipped with. +MimeType=image/fax-g3;image/gif;image/jp2;image/jpeg;image/png;image/tiff;image/x-bmp;image/x-dds;image/x-eps;image/x-exr;image/x-hdr;image/x-ico;image/x-pcx;image/x-portable-bitmap;image/x-portable-greymap;image/x-portable-pixmap;image/x-rgb;image/x-targa;image/x-vnd.adobe.photoshop;image/x-xbm;image/x-xcf-gimp;image/x-xpm;video/x-mng; + +Categories=Qt;KDE;Graphics; +Terminal=false +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Multi + diff --git a/kolourpaint/kolourpaintui.rc b/kolourpaint/kolourpaintui.rc new file mode 100644 index 00000000..876c3e38 --- /dev/null +++ b/kolourpaint/kolourpaintui.rc @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + &View + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + &Image + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Selection Tool RMB Menu + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kolourpaint/kpcolor.cpp b/kolourpaint/kpcolor.cpp new file mode 100644 index 00000000..a9dc000b --- /dev/null +++ b/kolourpaint/kpcolor.cpp @@ -0,0 +1,360 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_COLOR 0 + + +#include + +#include + +#include + + +// public static +const int kpColor::Exact = 0; + +// public static +const kpColor kpColor::invalid; // TODO: what's wrong with explicitly specifying () constructor? +const kpColor kpColor::transparent (0, 0, 0, true/*isTransparent*/); + + +kpColor::kpColor () + : m_rgbaIsValid (false), + m_colorCacheIsValid (false) +{ +} + +kpColor::kpColor (int red, int green, int blue, bool isTransparent) + : m_colorCacheIsValid (false) +{ + if (red < 0 || red > 255 || + green < 0 || green > 255 || + blue < 0 || blue > 255) + { + kdError () << "kpColor::(r=" << red + << ",g=" << green + << ",b=" << blue + << ",t=" << isTransparent + << ") passed out of range values" << endl; + m_rgbaIsValid = false; + return; + } + + m_rgba = qRgba (red, green, blue, isTransparent ? 0 : 255/*opaque*/); + m_rgbaIsValid = true; +} + +kpColor::kpColor (const QRgb &rgba) + : m_colorCacheIsValid (false) +{ + if (qAlpha (rgba) > 0 && qAlpha (rgba) < 255) + { + kdError () << "kpColor::(QRgb) passed translucent alpha " + << qAlpha (rgba) + << " - trying to recover" + << endl; + + // Forget the alpha channel - make it opaque + m_rgba = qRgb (qRed (m_rgba), qGreen (m_rgba), qBlue (m_rgba)); + m_rgbaIsValid = true; + } + else + { + m_rgba = rgba; + m_rgbaIsValid = true; + } +} + +kpColor::kpColor (const kpColor &rhs) + : m_rgbaIsValid (rhs.m_rgbaIsValid), + m_rgba (rhs.m_rgba), + m_colorCacheIsValid (rhs.m_colorCacheIsValid), + m_colorCache (rhs.m_colorCache) +{ +} + +// friend +QDataStream &operator<< (QDataStream &stream, const kpColor &color) +{ + stream << int (color.m_rgbaIsValid) << int (color.m_rgba); + + return stream; +} + +// friend +QDataStream &operator>> (QDataStream &stream, kpColor &color) +{ + int a, b; + stream >> a >> b; + color.m_rgbaIsValid = a; + color.m_rgba = b; + + color.m_colorCacheIsValid = false; + + return stream; +} + +kpColor &kpColor::operator= (const kpColor &rhs) +{ + // (as soon as you add a ptr, you won't be complaining to me that this + // method was unnecessary :)) + + if (this == &rhs) + return *this; + + m_rgbaIsValid = rhs.m_rgbaIsValid; + m_rgba = rhs.m_rgba; + m_colorCacheIsValid = rhs.m_colorCacheIsValid; + m_colorCache = rhs.m_colorCache; + + return *this; +} + +bool kpColor::operator== (const kpColor &rhs) const +{ + return isSimilarTo (rhs, kpColor::Exact); +} + +bool kpColor::operator!= (const kpColor &rhs) const +{ + return !(*this == rhs); +} + + +template +inline dtype square (dtype val) +{ + return val * val; +} + +// public static +int kpColor::processSimilarity (double colorSimilarity) +{ + // sqrt (dr ^ 2 + dg ^ 2 + db ^ 2) <= colorSimilarity * sqrt (255 ^ 2 * 3) + // dr ^ 2 + dg ^ 2 + db ^ 2 <= (colorSimilarity ^ 2) * (255 ^ 2 * 3) + + return int (square (colorSimilarity) * (square (255) * 3)); +} + +bool kpColor::isSimilarTo (const kpColor &rhs, int processedSimilarity) const +{ + // Are we the same? + if (this == &rhs) + return true; + + + // Do we dither in terms of validity? + if (isValid () != rhs.isValid ()) + return false; + + // Are both of us invalid? + if (!isValid ()) + return true; + + // --- both are now valid --- + + + if (isTransparent () != rhs.isTransparent ()) + return false; + + // Are both of us transparent? + if (isTransparent ()) + return true; + + // --- both are now valid and opaque --- + + + if (m_rgba == rhs.m_rgba) + return true; + + + if (processedSimilarity == kpColor::Exact) + return false; + else + { + return (square (qRed (m_rgba) - qRed (rhs.m_rgba)) + + square (qGreen (m_rgba) - qGreen (rhs.m_rgba)) + + square (qBlue (m_rgba) - qBlue (rhs.m_rgba)) + <= processedSimilarity); + } +} + +kpColor::~kpColor () +{ +} + + +// public +bool kpColor::isValid () const +{ + return m_rgbaIsValid; +} + + +// public +int kpColor::red () const +{ + if (!m_rgbaIsValid) + { + kdError () << "kpColor::red() called with invalid kpColor" << endl; + return 0; + } + + if (isTransparent ()) + { + kdError () << "kpColor::red() called with transparent kpColor" << endl; + return 0; + } + + return qRed (m_rgba); +} + +// public +int kpColor::green () const +{ + if (!m_rgbaIsValid) + { + kdError () << "kpColor::green() called with invalid kpColor" << endl; + return 0; + } + + if (isTransparent ()) + { + kdError () << "kpColor::green() called with transparent kpColor" << endl; + return 0; + } + + return qGreen (m_rgba); +} + +// public +int kpColor::blue () const +{ + if (!m_rgbaIsValid) + { + kdError () << "kpColor::blue() called with invalid kpColor" << endl; + return 0; + } + + if (isTransparent ()) + { + kdError () << "kpColor::blue() called with transparent kpColor" << endl; + return 0; + } + + return qBlue (m_rgba); +} + +// public +int kpColor::alpha () const +{ + if (!m_rgbaIsValid) + { + kdError () << "kpColor::alpha() called with invalid kpColor" << endl; + return 0; + } + + const int alpha = qAlpha (m_rgba); + + if (alpha > 0 && alpha < 255) + { + kdError () << "kpColor::alpha() called with translucent kpColor alpha=" << alpha << endl; + + // no translucency + return alpha ? 255 : 0; + } + else + { + return alpha; + } +} + +// public +bool kpColor::isTransparent () const +{ + return (alpha () == 0); +} + +// public +bool kpColor::isOpaque () const +{ + return (alpha () == 255); +} + + +// public +QRgb kpColor::toQRgb () const +{ + if (!m_rgbaIsValid) + { + kdError () << "kpColor::toQRgb() called with invalid kpColor" << endl; + return 0; + } + + return m_rgba; +} + +// public +const QColor &kpColor::toQColor () const +{ + if (!m_rgbaIsValid) + { + kdError () << "kpColor::toQColor() called with invalid kpColor" << endl; + return Qt::black; + } + + if (m_colorCacheIsValid) + return m_colorCache; + + if (qAlpha (m_rgba) < 255) + { + kdError () << "kpColor::toQColor() called with not fully opaque kpColor alpha=" + << qAlpha (m_rgba) + << endl; + return Qt::black; + } + + m_colorCache = QColor (m_rgba); + if (!m_colorCache.isValid ()) + { + kdError () << "kpColor::toQColor () internal error - could not return valid QColor" + << endl; + return Qt::black; + } + + m_colorCacheIsValid = true; + + return m_colorCache; +} + +// public +QColor kpColor::maskColor () const +{ + return isTransparent () ? Qt::color0 : Qt::color1; +} diff --git a/kolourpaint/kpcolor.h b/kolourpaint/kpcolor.h new file mode 100644 index 00000000..131d4b61 --- /dev/null +++ b/kolourpaint/kpcolor.h @@ -0,0 +1,101 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kp_color_h__ +#define __kp_color_h__ + + +#include + +class QDataStream; + + +// +// kpColor is an object-oriented abstraction of QRgb, with the additional +// restriction of following the KolourPaint convention of only supporting +// totally transparent and totally opaque colors. It also provides better +// error handling, reporting (noisy kdError()'s) and recovery. +// +// In general, you should pass around kpColor objects instead of QRgb +// and QColor. Only convert an opaque kpColor to a QColor (using toQColor()) +// if you need to draw something onscreen. Constructing a kpColor object +// from QColor is probably wrong since onscreen representations of color +// are not guaranteed to be faithful (due to QColor color allocation). +// +class kpColor +{ +public: + kpColor (); + kpColor (int red, int green, int blue, bool isTransparent = false); + kpColor (const QRgb &rgba); + kpColor (const kpColor &rhs); + friend QDataStream &operator<< (QDataStream &stream, const kpColor &color); + friend QDataStream &operator>> (QDataStream &stream, kpColor &color); + kpColor &operator= (const kpColor &rhs); + bool operator== (const kpColor &rhs) const; + bool operator!= (const kpColor &rhs) const; + + static int processSimilarity (double colorSimilarity); + static const int Exact; // "isSimilarTo (rhs, kpColor::Exact)" == "== rhs" + // Usage: isSimilarTo (rhs, kpColor::processSimilarity (.1)) checks for + // Color Similarity within 10% + bool isSimilarTo (const kpColor &rhs, int processedSimilarity) const; + ~kpColor (); + + static const kpColor invalid; + static const kpColor transparent; + + bool isValid () const; + + int red () const; + int green () const; + int blue () const; + int alpha () const; + bool isTransparent () const; + bool isOpaque () const; + + // Cast operators will most likely result in careless conversions so + // use explicit functions instead: + QRgb toQRgb () const; + + // (only valid if isOpaque()) + // (const QColor & return results in fewer color reallocations) + const QColor &toQColor () const; + + QColor maskColor () const; + +private: + bool m_rgbaIsValid; + QRgb m_rgba; + + mutable bool m_colorCacheIsValid; + mutable QColor m_colorCache; +}; + + +#endif // __kp_color_h__ diff --git a/kolourpaint/kpcommandhistory.cpp b/kolourpaint/kpcommandhistory.cpp new file mode 100644 index 00000000..33010918 --- /dev/null +++ b/kolourpaint/kpcommandhistory.cpp @@ -0,0 +1,939 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_COMMAND_HISTORY 0 + + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +//template +static void clearPointerList (QValueList *listPtr) +{ + if (!listPtr) + return; + + for (QValueList ::iterator it = listPtr->begin (); + it != listPtr->end (); + it++) + { + delete (*it); + } + + listPtr->clear (); +} + + +// +// kpCommand +// + +kpCommand::kpCommand (kpMainWindow *mainWindow) + : m_mainWindow (mainWindow) +{ + if (!mainWindow) + kdError () << "kpCommand::kpCommand() passed 0 mainWindow" << endl; +} + +kpCommand::~kpCommand () +{ +} + + +// protected +kpMainWindow *kpCommand::mainWindow () const +{ + return m_mainWindow; +} + + +// protected +kpDocument *kpCommand::document () const +{ + return m_mainWindow ? m_mainWindow->document () : 0; +} + +// protected +kpSelection *kpCommand::selection () const +{ + kpDocument *doc = document (); + if (!doc) + return 0; + + return doc->selection (); +} + + +// protected +kpViewManager *kpCommand::viewManager () const +{ + return m_mainWindow ? m_mainWindow->viewManager () : 0; +} + + +// +// kpNamedCommand +// + +kpNamedCommand::kpNamedCommand (const QString &name, kpMainWindow *mainWindow) + : kpCommand (mainWindow), + m_name (name) +{ +} + +kpNamedCommand::~kpNamedCommand () +{ +} + + +// public virtual [base kpCommand] +QString kpNamedCommand::name () const +{ + return m_name; +} + + +// +// kpMacroCommand +// + +struct kpMacroCommandPrivate +{ +}; + +kpMacroCommand::kpMacroCommand (const QString &name, kpMainWindow *mainWindow) + : kpNamedCommand (name, mainWindow), + d (new kpMacroCommandPrivate ()) +{ +} + +kpMacroCommand::~kpMacroCommand () +{ + clearPointerList (&m_commandList); + delete d; +} + + +// public virtual [base kpCommand] +int kpMacroCommand::size () const +{ +#if DEBUG_KP_COMMAND_HISTORY && 0 + kdDebug () << "kpMacroCommand::size()" << endl; +#endif + int s = 0; + +#if DEBUG_KP_COMMAND_HISTORY && 0 + kdDebug () << "\tcalculating:" << endl; +#endif + for (QValueList ::const_iterator it = m_commandList.begin (); + it != m_commandList.end (); + it++) + { + #if DEBUG_KP_COMMAND_HISTORY && 0 + kdDebug () << "\t\tcurrentSize=" << s << " + " + << (*it)->name () << ".size=" << (*it)->size () + << endl; + #endif + if (s > INT_MAX - (*it)->size ()) + { + #if DEBUG_KP_COMMAND_HISTORY && 0 + kdDebug () << "\t\t\toverflow" << endl; + #endif + s = INT_MAX; + break; + } + else + { + s += (*it)->size (); + } + } + +#if DEBUG_KP_COMMAND_HISTORY && 0 + kdDebug () << "\treturning " << s << endl; +#endif + return s; +} + + +// public virtual [base kpCommand] +void kpMacroCommand::execute () +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpMacroCommand::execute()" << endl; +#endif + for (QValueList ::const_iterator it = m_commandList.begin (); + it != m_commandList.end (); + it++) + { + #if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "\texecuting " << (*it)->name () << endl; + #endif + (*it)->execute (); + } +} + +// public virtual [base kpCommand] +void kpMacroCommand::unexecute () +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpMacroCommand::unexecute()" << endl; +#endif + QValueList ::const_iterator it = m_commandList.end (); + it--; + + while (it != m_commandList.end ()) + { + #if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "\tunexecuting " << (*it)->name () << endl; + #endif + (*it)->unexecute (); + + it--; + } +} + + +// public +void kpMacroCommand::addCommand (kpCommand *command) +{ + m_commandList.push_back (command); +} + + +// +// kpCommandHistoryBase +// + +struct kpCommandHistoryBasePrivate +{ +}; + + +kpCommandHistoryBase::kpCommandHistoryBase (bool doReadConfig, + KActionCollection *ac) + : d (new kpCommandHistoryBasePrivate ()) +{ + m_actionUndo = new KToolBarPopupAction (undoActionText (), + QString::fromLatin1 ("undo"), + KStdAccel::shortcut (KStdAccel::Undo), + this, SLOT (undo ()), + ac, KStdAction::name (KStdAction::Undo)); + + m_actionRedo = new KToolBarPopupAction (redoActionText (), + QString::fromLatin1 ("redo"), + KStdAccel::shortcut (KStdAccel::Redo), + this, SLOT (redo ()), + ac, KStdAction::name (KStdAction::Redo)); + + + m_actionUndo->setEnabled (false); + m_actionRedo->setEnabled (false); + + + connect (m_actionUndo->popupMenu (), SIGNAL (activated (int)), + this, SLOT (undoUpToNumber (int))); + connect (m_actionRedo->popupMenu (), SIGNAL (activated (int)), + this, SLOT (redoUpToNumber (int))); + + + m_undoMinLimit = 10; + m_undoMaxLimit = 500; + m_undoMaxLimitSizeLimit = 16 * 1048576; + + + m_documentRestoredPosition = 0; + + + if (doReadConfig) + readConfig (); +} + +kpCommandHistoryBase::~kpCommandHistoryBase () +{ + clearPointerList (&m_undoCommandList); + clearPointerList (&m_redoCommandList); + + delete d; +} + + +// public +int kpCommandHistoryBase::undoLimit () const +{ + return undoMinLimit (); +} + +// public +void kpCommandHistoryBase::setUndoLimit (int limit) +{ + setUndoMinLimit (limit); +} + + +// public +int kpCommandHistoryBase::undoMinLimit () const +{ + return m_undoMinLimit; +} + +// public +void kpCommandHistoryBase::setUndoMinLimit (int limit) +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpCommandHistoryBase::setUndoMinLimit(" + << limit << ")" + << endl; +#endif + + if (limit < 1 || limit > 5000/*"ought to be enough for anybody"*/) + { + kdError () << "kpCommandHistoryBase::setUndoMinLimit(" + << limit << ")" + << endl; + return; + } + + if (limit == m_undoMinLimit) + return; + + m_undoMinLimit = limit; + trimCommandListsUpdateActions (); +} + + +// public +int kpCommandHistoryBase::undoMaxLimit () const +{ + return m_undoMaxLimit; +} + +// public +void kpCommandHistoryBase::setUndoMaxLimit (int limit) +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpCommandHistoryBase::setUndoMaxLimit(" + << limit << ")" + << endl; +#endif + + if (limit < 1 || limit > 5000/*"ought to be enough for anybody"*/) + { + kdError () << "kpCommandHistoryBase::setUndoMaxLimit(" + << limit << ")" + << endl; + return; + } + + if (limit == m_undoMaxLimit) + return; + + m_undoMaxLimit = limit; + trimCommandListsUpdateActions (); +} + + +// public +int kpCommandHistoryBase::undoMaxLimitSizeLimit () const +{ + return m_undoMaxLimitSizeLimit; +} + +// public +void kpCommandHistoryBase::setUndoMaxLimitSizeLimit (int sizeLimit) +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpCommandHistoryBase::setUndoMaxLimitSizeLimit(" + << sizeLimit << ")" + << endl; +#endif + + if (sizeLimit < 0 || + sizeLimit > (500 * 1048576)/*"ought to be enough for anybody"*/) + { + kdError () << "kpCommandHistoryBase::setUndoMaxLimitSizeLimit(" + << sizeLimit << ")" + << endl; + return; + } + + if (sizeLimit == m_undoMaxLimitSizeLimit) + return; + + m_undoMaxLimitSizeLimit = sizeLimit; + trimCommandListsUpdateActions (); +} + + +// public +void kpCommandHistoryBase::readConfig () +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpCommandHistoryBase::readConfig()" << endl; +#endif + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupUndoRedo); + KConfigBase *cfg = cfgGroupSaver.config (); + + setUndoMinLimit (cfg->readNumEntry (kpSettingUndoMinLimit, undoMinLimit ())); + setUndoMaxLimit (cfg->readNumEntry (kpSettingUndoMaxLimit, undoMaxLimit ())); + setUndoMaxLimitSizeLimit (cfg->readNumEntry (kpSettingUndoMaxLimitSizeLimit, + undoMaxLimitSizeLimit ())); + + trimCommandListsUpdateActions (); +} + +// public +void kpCommandHistoryBase::writeConfig () +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpCommandHistoryBase::writeConfig()" << endl; +#endif + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupUndoRedo); + KConfigBase *cfg = cfgGroupSaver.config (); + + cfg->writeEntry (kpSettingUndoMinLimit, undoMinLimit ()); + cfg->writeEntry (kpSettingUndoMaxLimit, undoMaxLimit ()); + cfg->writeEntry (kpSettingUndoMaxLimitSizeLimit, undoMaxLimitSizeLimit ()); + + cfg->sync (); +} + + +// public +void kpCommandHistoryBase::addCommand (kpCommand *command, bool execute) +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpCommandHistoryBase::addCommand(" + << command + << ",execute=" << execute << ")" + << endl; +#endif + + if (execute) + command->execute (); + + m_undoCommandList.push_front (command); + clearPointerList (&m_redoCommandList); + +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "\tdocumentRestoredPosition=" << m_documentRestoredPosition + << endl; +#endif + if (m_documentRestoredPosition != INT_MAX) + { + if (m_documentRestoredPosition > 0) + m_documentRestoredPosition = INT_MAX; + else + m_documentRestoredPosition--; + #if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "\t\tdocumentRestoredPosition=" << m_documentRestoredPosition + << endl; + #endif + } + + trimCommandListsUpdateActions (); +} + +// public +void kpCommandHistoryBase::clear () +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpCommandHistoryBase::clear()" << endl; +#endif + + clearPointerList (&m_undoCommandList); + clearPointerList (&m_redoCommandList); + + m_documentRestoredPosition = 0; + + updateActions (); +} + + +// protected slot +void kpCommandHistoryBase::undoInternal () +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpCommandHistoryBase::undoInternal()" << endl; +#endif + + kpCommand *undoCommand = nextUndoCommand (); + if (!undoCommand) + return; + + undoCommand->unexecute (); + + + m_undoCommandList.erase (m_undoCommandList.begin ()); + m_redoCommandList.push_front (undoCommand); + + +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "\tdocumentRestoredPosition=" << m_documentRestoredPosition + << endl; +#endif + if (m_documentRestoredPosition != INT_MAX) + { + m_documentRestoredPosition++; + if (m_documentRestoredPosition == 0) + emit documentRestored (); + #if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "\t\tdocumentRestoredPosition=" << m_documentRestoredPosition + << endl; + #endif + } +} + +// protected slot +void kpCommandHistoryBase::redoInternal () +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpCommandHistoryBase::redoInternal()" << endl; +#endif + + kpCommand *redoCommand = nextRedoCommand (); + if (!redoCommand) + return; + + redoCommand->execute (); + + + m_redoCommandList.erase (m_redoCommandList.begin ()); + m_undoCommandList.push_front (redoCommand); + + +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "\tdocumentRestoredPosition=" << m_documentRestoredPosition + << endl; +#endif + if (m_documentRestoredPosition != INT_MAX) + { + m_documentRestoredPosition--; + if (m_documentRestoredPosition == 0) + emit documentRestored (); + #if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "\t\tdocumentRestoredPosition=" << m_documentRestoredPosition + << endl; + #endif + } +} + + +// public slot virtual +void kpCommandHistoryBase::undo () +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpCommandHistoryBase::undo()" << endl; +#endif + + undoInternal (); + trimCommandListsUpdateActions (); +} + +// public slot virtual +void kpCommandHistoryBase::redo () +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpCommandHistoryBase::redo()" << endl; +#endif + + redoInternal (); + trimCommandListsUpdateActions (); +} + + +// public slot virtual +void kpCommandHistoryBase::undoUpToNumber (int which) +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpCommandHistoryBase::undoUpToNumber(" << which << ")" << endl; +#endif + + for (int i = 0; + i <= which && !m_undoCommandList.isEmpty (); + i++) + { + undoInternal (); + } + + trimCommandListsUpdateActions (); +} + +// public slot virtual +void kpCommandHistoryBase::redoUpToNumber (int which) +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpCommandHistoryBase::redoUpToNumber(" << which << ")" << endl; +#endif + + for (int i = 0; + i <= which && !m_redoCommandList.isEmpty (); + i++) + { + redoInternal (); + } + + trimCommandListsUpdateActions (); +} + + +// protected +QString kpCommandHistoryBase::undoActionText () const +{ + kpCommand *undoCommand = nextUndoCommand (); + + if (undoCommand) + return i18n ("&Undo: %1").arg (undoCommand->name ()); + else + return i18n ("&Undo"); +} + +// protected +QString kpCommandHistoryBase::redoActionText () const +{ + kpCommand *redoCommand = nextRedoCommand (); + + if (redoCommand) + return i18n ("&Redo: %1").arg (redoCommand->name ()); + else + return i18n ("&Redo"); +} + + +// protected +void kpCommandHistoryBase::trimCommandListsUpdateActions () +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpCommandHistoryBase::trimCommandListsUpdateActions()" << endl; +#endif + + trimCommandLists (); + updateActions (); +} + +// protected +void kpCommandHistoryBase::trimCommandList (QValueList *commandList) +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpCommandHistoryBase::trimCommandList()" << endl; + QTime timer; timer.start (); +#endif + + if (!commandList) + { + kdError () << "kpCommandHistoryBase::trimCommandList() passed 0 commandList" + << endl; + return; + } + + +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "\tsize=" << commandList->size () + << " undoMinLimit=" << m_undoMinLimit + << " undoMaxLimit=" << m_undoMaxLimit + << " undoMaxLimitSizeLimit=" << m_undoMaxLimitSizeLimit + << endl; +#endif + if ((int) commandList->size () <= m_undoMinLimit) + { + #if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "\t\tsize under undoMinLimit - done" << endl; + #endif + return; + } + + +#if DEBUG_KP_COMMAND_HISTORY && 0 + kdDebug () << "\tsize over undoMinLimit - iterating thru cmds:" << endl; +#endif + + QValueList ::iterator it = commandList->begin (); + int upto = 0; + + int sizeSoFar = 0; + + while (it != commandList->end ()) + { + bool advanceIt = true; + + if (sizeSoFar <= m_undoMaxLimitSizeLimit) + { + if (sizeSoFar > INT_MAX - (*it)->size ()) + sizeSoFar = INT_MAX; + else + sizeSoFar += (*it)->size (); + } + + #if DEBUG_KP_COMMAND_HISTORY && 0 + kdDebug () << "\t\t" << upto << ":" + << " name='" << (*it)->name () + << "' size=" << (*it)->size () + << " sizeSoFar=" << sizeSoFar + << endl; + #endif + + if (upto >= m_undoMinLimit) + { + if (upto >= m_undoMaxLimit || + sizeSoFar > m_undoMaxLimitSizeLimit) + { + #if DEBUG_KP_COMMAND_HISTORY && 0 + kdDebug () << "\t\t\tkill" << endl; + #endif + delete (*it); + it = m_undoCommandList.erase (it); + advanceIt = false; + } + } + + if (advanceIt) + it++; + upto++; + } + +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "\ttook " << timer.elapsed () << "ms" << endl; +#endif +} + +// protected +void kpCommandHistoryBase::trimCommandLists () +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpCommandHistoryBase::trimCommandLists()" << endl; +#endif + + trimCommandList (&m_undoCommandList); + trimCommandList (&m_redoCommandList); + +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "\tdocumentRestoredPosition=" << m_documentRestoredPosition + << endl; +#endif + if (m_documentRestoredPosition != INT_MAX) + { + #if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "\t\tundoCmdList.size=" << m_undoCommandList.size () + << " redoCmdList.size=" << m_redoCommandList.size () + << endl; + #endif + if (m_documentRestoredPosition > (int) m_redoCommandList.size () || + -m_documentRestoredPosition > (int) m_undoCommandList.size ()) + { + #if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "\t\t\tinvalidate documentRestoredPosition" << endl; + #endif + m_documentRestoredPosition = INT_MAX; + } + } +} + + +static void populatePopupMenu (KPopupMenu *popupMenu, + const QString &undoOrRedo, + const QValueList &commandList) +{ + if (!popupMenu) + return; + + popupMenu->clear (); + + QValueList ::const_iterator it = commandList.begin (); + int i = 0; + while (i < 10 && it != commandList.end ()) + { + popupMenu->insertItem (i18n ("%1: %2").arg (undoOrRedo).arg ((*it)->name ()), i/*id*/); + i++, it++; + } + + if (it != commandList.end ()) + { + // TODO: maybe have a scrollview show all the items instead + KPopupTitle *title = new KPopupTitle (popupMenu); + title->setTitle (i18n ("%n more item", "%n more items", + commandList.size () - i)); + + popupMenu->insertItem (title); + } +} + + +// protected +void kpCommandHistoryBase::updateActions () +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpCommandHistoryBase::updateActions()" << endl; +#endif + + m_actionUndo->setEnabled ((bool) nextUndoCommand ()); + m_actionUndo->setText (undoActionText ()); +#if DEBUG_KP_COMMAND_HISTORY + QTime timer; timer.start (); +#endif + populatePopupMenu (m_actionUndo->popupMenu (), + i18n ("Undo"), + m_undoCommandList); +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "\tpopuplatePopupMenu undo=" << timer.elapsed () + << "ms" << endl;; +#endif + + m_actionRedo->setEnabled ((bool) nextRedoCommand ()); + m_actionRedo->setText (redoActionText ()); +#if DEBUG_KP_COMMAND_HISTORY + timer.restart (); +#endif + populatePopupMenu (m_actionRedo->popupMenu (), + i18n ("Redo"), + m_redoCommandList); +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "\tpopuplatePopupMenu redo=" << timer.elapsed () + << "ms" << endl; +#endif +} + + +// public +kpCommand *kpCommandHistoryBase::nextUndoCommand () const +{ + if (m_undoCommandList.isEmpty ()) + return 0; + + return m_undoCommandList.first (); +} + +// public +kpCommand *kpCommandHistoryBase::nextRedoCommand () const +{ + if (m_redoCommandList.isEmpty ()) + return 0; + + return m_redoCommandList.first (); +} + + +// public +void kpCommandHistoryBase::setNextUndoCommand (kpCommand *command) +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpCommandHistoryBase::setNextUndoCommand(" + << command + << ")" + << endl; +#endif + + if (m_undoCommandList.isEmpty ()) + return; + + + delete m_undoCommandList [0]; + m_undoCommandList [0] = command; + + + trimCommandListsUpdateActions (); +} + + +// public slot virtual +void kpCommandHistoryBase::documentSaved () +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpCommandHistoryBase::documentSaved()" << endl; +#endif + + m_documentRestoredPosition = 0; +} + + +// +// kpCommandHistory +// + +kpCommandHistory::kpCommandHistory (bool doReadConfig, kpMainWindow *mainWindow) + : kpCommandHistoryBase (doReadConfig, mainWindow->actionCollection ()), + m_mainWindow (mainWindow) +{ +} + +kpCommandHistory::~kpCommandHistory () +{ +} + + +// public slot virtual [base KCommandHistory] +void kpCommandHistory::undo () +{ +#if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "kpCommandHistory::undo() CALLED!" << endl; +#endif + if (m_mainWindow && m_mainWindow->toolHasBegunShape ()) + { + #if DEBUG_KP_COMMAND_HISTORY + kdDebug () << "\thas begun shape - cancel draw" << endl; + #endif + m_mainWindow->tool ()->cancelShapeInternal (); + } + else + kpCommandHistoryBase::undo (); +} + +// public slot virtual [base KCommandHistory] +void kpCommandHistory::redo () +{ + if (m_mainWindow && m_mainWindow->toolHasBegunShape ()) + { + // Not completely obvious but what else can we do? + // + // Ignoring the request would not be intuitive for tools like + // Polygon & Polyline (where it's not always apparent to the user + // that s/he's still drawing a shape even though the mouse isn't + // down). + m_mainWindow->tool ()->cancelShapeInternal (); + } + else + kpCommandHistoryBase::redo (); +} + +#include diff --git a/kolourpaint/kpcommandhistory.h b/kolourpaint/kpcommandhistory.h new file mode 100644 index 00000000..a1541512 --- /dev/null +++ b/kolourpaint/kpcommandhistory.h @@ -0,0 +1,255 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_COMMAND_HISTORY_H +#define KP_COMMAND_HISTORY_H + +#include +#include +#include + + +class KActionCollection; +class KToolBarPopupAction; + +class kpDocument; +class kpMainWindow; +class kpSelection; +class kpViewManager; + + +class kpCommand +{ +public: + kpCommand (kpMainWindow *mainWindow); + virtual ~kpCommand (); + +public: + virtual QString name () const = 0; + + // Returns the estimated size in bytes. + // + // You only have to factor in the size of variables that change according + // to the amount of input e.g. pixmap size, text size. There is no need + // to include the size of O(1) variables unless they are huge. + // + // If in doubt, return the largest possible amount of memory that your + // command will take. This is better than making the user unexpectedly + // run out of memory. + virtual int size () const = 0; + + virtual void execute () = 0; + virtual void unexecute () = 0; + +protected: + kpMainWindow *mainWindow () const; + + kpDocument *document () const; + kpSelection *selection () const; + + kpViewManager *viewManager () const; + +protected: + kpMainWindow *m_mainWindow; +}; + + +class kpNamedCommand : public kpCommand +{ +public: + kpNamedCommand (const QString &name, kpMainWindow *mainWindow); + virtual ~kpNamedCommand (); + + virtual QString name () const; + +protected: + QString m_name; +}; + + +class kpMacroCommand : public kpNamedCommand +{ +public: + kpMacroCommand (const QString &name, kpMainWindow *mainWindow); + virtual ~kpMacroCommand (); + + + // + // kpCommand Interface + // + + virtual int size () const; + + virtual void execute (); + virtual void unexecute (); + + + // + // Interface + // + + void addCommand (kpCommand *command); + +protected: + QValueList m_commandList; + +private: + class kpMacroCommandPrivate *d; +}; + + +// Clone of KCommandHistory with features required by KolourPaint: +// - nextUndoCommand()/nextRedoCommand() +// - undo/redo history limited by both number and size +// +// Features not required by KolourPaint (e.g. commandExecuted()) are not +// implemented and undo limit == redo limit. So compared to +// KCommandHistory, this is only "almost source compatible". +class kpCommandHistoryBase : public QObject +{ +Q_OBJECT + +public: + kpCommandHistoryBase (bool doReadConfig, KActionCollection *ac); + virtual ~kpCommandHistoryBase (); + +public: + // (provided for compatibility with KCommandHistory) + int undoLimit () const; + void setUndoLimit (int limit); + + + int undoMinLimit () const; + void setUndoMinLimit (int limit); + + int undoMaxLimit () const; + void setUndoMaxLimit (int limit); + + int undoMaxLimitSizeLimit () const; + void setUndoMaxLimitSizeLimit (int sizeLimit); + +public: + // Read and write above config + void readConfig (); + void writeConfig (); + +public: + void addCommand (kpCommand *command, bool execute = true); + void clear (); + +protected slots: + // (same as undo() & redo() except they don't call + // trimCommandListsUpdateActions()) + void undoInternal (); + void redoInternal (); + +public slots: + virtual void undo (); + virtual void redo (); + + virtual void undoUpToNumber (int which); + virtual void redoUpToNumber (int which); + +protected: + QString undoActionText () const; + QString redoActionText () const; + + void trimCommandListsUpdateActions (); + void trimCommandList (QValueList *commandList); + void trimCommandLists (); + void updateActions (); + +public: + kpCommand *nextUndoCommand () const; + kpCommand *nextRedoCommand () const; + + void setNextUndoCommand (kpCommand *command); + +public slots: + virtual void documentSaved (); + +signals: + void documentRestored (); + +protected: + KToolBarPopupAction *m_actionUndo, *m_actionRedo; + + // (Front element is the next one) + QValueList m_undoCommandList; + QValueList m_redoCommandList; + + int m_undoMinLimit, m_undoMaxLimit, m_undoMaxLimitSizeLimit; + + // What you have to do to get back to the document's unmodified state: + // * -x: must Undo x times + // * 0: unmodified + // * +x: must Redo x times + // * INT_MAX: can never become unmodified again + // + // ASSUMPTION: will never have INT_MAX commands in any list. + int m_documentRestoredPosition; + +private: + class kpCommandHistoryBasePrivate *d; +}; + + +// Intercepts Undo/Redo requests: +// +// If the user is currently drawing a shape, it cancels it. +// Else it passes on the Undo/Redo request to kpCommandHistoryBase. +// +// TODO: This is wrong. It won't work if the Undo action is disabled, +// for instance. +// +// Maybe the real solution is to call kpCommandHistoryBase::addCommand() +// as _soon_ as the shape starts - not after it ends. But the +// trouble with this solution is that if the user Undoes/cancels +// the shape s/he's currently drawing, it would replace a Redo +// slot in the history. Arguably you shouldn't be able to Redo +// something you never finished drawing. +// +// The solution is to add this functionality to kpCommandHistoryBase. +class kpCommandHistory : public kpCommandHistoryBase +{ +Q_OBJECT + +public: + kpCommandHistory (bool doReadConfig, kpMainWindow *mainWindow); + virtual ~kpCommandHistory (); + +public slots: + virtual void undo (); + virtual void redo (); + +protected: + kpMainWindow *m_mainWindow; +}; + + +#endif // KP_COMMAND_HISTORY_H diff --git a/kolourpaint/kpdefs.h b/kolourpaint/kpdefs.h new file mode 100644 index 00000000..15faaee0 --- /dev/null +++ b/kolourpaint/kpdefs.h @@ -0,0 +1,151 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kp_defs_h__ +#define __kp_defs_h__ + + +#include + +#include +#include +#include +#include + +#include + + +#define KP_IS_QT_3_3 (QT_VERSION >= 0x030300 && 1) +#define KP_IS_KDE_3_3 ((KDE_VERSION_MAJOR >= 3 && KDE_VERSION_MINOR >= 3) && 1) + + +// approx. 2896x2896x32bpp or 3344x3344x24bpp (TODO: 24==32?) or 4096*4096x16bpp +#define KP_BIG_IMAGE_SIZE (32 * 1048576) + + +#define KP_PI 3.141592653589793238462 + + +#define KP_DEGREES_TO_RADIANS(deg) ((deg) * KP_PI / 180.0) +#define KP_RADIANS_TO_DEGREES(rad) ((rad) * 180.0 / KP_PI) + + +#define KP_INVALID_POINT QPoint (INT_MIN / 8, INT_MIN / 8) +#define KP_INVALID_WIDTH (INT_MIN / 8) +#define KP_INVALID_HEIGHT (INT_MIN / 8) +#define KP_INVALID_SIZE QSize (INT_MIN / 8, INT_MIN / 8) + + +// +// Settings +// + +#define kpSettingsGroupGeneral QString::fromLatin1 ("General Settings") +#define kpSettingFirstTime QString::fromLatin1 ("First Time") +#define kpSettingShowGrid QString::fromLatin1 ("Show Grid") +#define kpSettingShowPath QString::fromLatin1 ("Show Path") +#define kpSettingColorSimilarity QString::fromLatin1 ("Color Similarity") +#define kpSettingDitherOnOpen QString::fromLatin1 ("Dither on Open if Screen is 15/16bpp and Image Num Colors More Than") +#define kpSettingPrintImageCenteredOnPage QString::fromLatin1 ("Print Image Centered On Page") + +#define kpSettingsGroupFileSaveAs QString::fromLatin1 ("File/Save As") +#define kpSettingsGroupFileExport QString::fromLatin1 ("File/Export") +#define kpSettingsGroupEditCopyTo QString::fromLatin1 ("Edit/Copy To") + +#define kpSettingForcedMimeType QString::fromLatin1 ("Forced MimeType") +#define kpSettingForcedColorDepth QString::fromLatin1 ("Forced Color Depth") +#define kpSettingForcedDither QString::fromLatin1 ("Forced Dither") +#define kpSettingForcedQuality QString::fromLatin1 ("Forced Quality") + +#define kpSettingLastDocSize QString::fromLatin1 ("Last Document Size") + +#define kpSettingMoreEffectsLastEffect QString::fromLatin1 ("More Effects - Last Effect") + +#define kpSettingResizeScaleLastKeepAspect QString::fromLatin1 ("Resize Scale - Last Keep Aspect") + + +#define kpSettingsGroupMimeTypeProperties QString::fromLatin1 ("MimeType Properties Version 1.2-2") +#define kpSettingMimeTypeMaximumColorDepth QString::fromLatin1 ("Maximum Color Depth") +#define kpSettingMimeTypeHasConfigurableColorDepth QString::fromLatin1 ("Configurable Color Depth") +#define kpSettingMimeTypeHasConfigurableQuality QString::fromLatin1 ("Configurable Quality Setting") + + +#define kpSettingsGroupUndoRedo QString::fromLatin1 ("Undo/Redo Settings") +#define kpSettingUndoMinLimit QString::fromLatin1 ("Min Limit") +#define kpSettingUndoMaxLimit QString::fromLatin1 ("Max Limit") +#define kpSettingUndoMaxLimitSizeLimit QString::fromLatin1 ("Max Limit Size Limit") + + +#define kpSettingsGroupThumbnail QString::fromLatin1 ("Thumbnail Settings") +#define kpSettingThumbnailShown QString::fromLatin1 ("Shown") +#define kpSettingThumbnailGeometry QString::fromLatin1 ("Geometry") +#define kpSettingThumbnailZoomed QString::fromLatin1 ("Zoomed") +#define kpSettingThumbnailShowRectangle QString::fromLatin1 ("ShowRectangle") + + +#define kpSettingsGroupPreviewSave QString::fromLatin1 ("Save Preview Settings") +#define kpSettingPreviewSaveGeometry QString::fromLatin1 ("Geometry") +#define kpSettingPreviewSaveUpdateDelay QString::fromLatin1 ("Update Delay") + + +#define kpSettingsGroupTools QString::fromLatin1 ("Tool Settings") +#define kpSettingLastTool QString::fromLatin1 ("Last Used Tool") +#define kpSettingToolBoxIconSize QString::fromLatin1 ("Tool Box Icon Size") + + +#define kpSettingsGroupText QString::fromLatin1 ("Text Settings") +#define kpSettingFontFamily QString::fromLatin1 ("Font Family") +#define kpSettingFontSize QString::fromLatin1 ("Font Size") +#define kpSettingBold QString::fromLatin1 ("Bold") +#define kpSettingItalic QString::fromLatin1 ("Italic") +#define kpSettingUnderline QString::fromLatin1 ("Underline") +#define kpSettingStrikeThru QString::fromLatin1 ("Strike Thru") + + +#define kpSettingsGroupFlattenEffect QString::fromLatin1 ("Flatten Effect Settings") +#define kpSettingFlattenEffectColor1 QString::fromLatin1 ("Color1") +#define kpSettingFlattenEffectColor2 QString::fromLatin1 ("Color2") + + +// +// Session Restore Setting +// + +// URL of the document in the main window. +// +// This key only exists if the document does. If it exists, it can be empty. +// The URL need not point to a file that exists e.g. "kolourpaint doesnotexist.png". +#define kpSessionSettingDocumentUrl QString::fromLatin1 ("Session Document Url") + +// The size of a document which is not from a URL e.g. "kolourpaint doesnotexist.png". +// This key does not exist for documents from URLs. +#define kpSessionSettingNotFromUrlDocumentSize QString::fromLatin1 ("Session Not-From-Url Document Size") + + +#endif // __kp_defs_h__ + diff --git a/kolourpaint/kpdocument.cpp b/kolourpaint/kpdocument.cpp new file mode 100644 index 00000000..801b922e --- /dev/null +++ b/kolourpaint/kpdocument.cpp @@ -0,0 +1,1539 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_DOCUMENT 0 + + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +struct kpDocumentPrivate +{ + kpDocumentPrivate () + { + } +}; + + +kpDocument::kpDocument (int w, int h, kpMainWindow *mainWindow) + : m_constructorWidth (w), m_constructorHeight (h), + m_mainWindow (mainWindow), + m_isFromURL (false), + m_savedAtLeastOnceBefore (false), + m_saveOptions (new kpDocumentSaveOptions ()), + m_metaInfo (new kpDocumentMetaInfo ()), + m_modified (false), + m_selection (0), + m_oldWidth (-1), m_oldHeight (-1), + d (new kpDocumentPrivate ()) +{ +#if DEBUG_KP_DOCUMENT && 0 + kdDebug () << "kpDocument::kpDocument (" << w << "," << h << ")" << endl; +#endif + + m_pixmap = new QPixmap (w, h); + m_pixmap->fill (Qt::white); +} + +kpDocument::~kpDocument () +{ + delete d; + + delete m_pixmap; + + delete m_saveOptions; + delete m_metaInfo; + + delete m_selection; +} + + +kpMainWindow *kpDocument::mainWindow () const +{ + return m_mainWindow; +} + +void kpDocument::setMainWindow (kpMainWindow *mainWindow) +{ + m_mainWindow = mainWindow; +} + + +/* + * File I/O + */ + +// public static +QPixmap kpDocument::convertToPixmapAsLosslessAsPossible ( + const QImage &image, + const kpPixmapFX::WarnAboutLossInfo &wali, + + kpDocumentSaveOptions *saveOptions, + kpDocumentMetaInfo *metaInfo) +{ + if (image.isNull ()) + return QPixmap (); + + +#if DEBUG_KP_DOCUMENT + kdDebug () << "\timage: depth=" << image.depth () + << " (X display=" << QColor::numBitPlanes () << ")" + << " hasAlphaBuffer=" << image.hasAlphaBuffer () + << endl; +#endif + + if (saveOptions) + { + saveOptions->setColorDepth (image.depth ()); + saveOptions->setDither (false); // avoid double dithering when saving + } + + if (metaInfo) + { + metaInfo->setDotsPerMeterX (image.dotsPerMeterX ()); + metaInfo->setDotsPerMeterY (image.dotsPerMeterY ()); + metaInfo->setOffset (image.offset ()); + + QValueList keyList = image.textList (); + for (QValueList ::const_iterator it = keyList.begin (); + it != keyList.end (); + it++) + { + metaInfo->setText (*it, image.text (*it)); + } + + #if DEBUG_KP_DOCUMENT + metaInfo->printDebug ("\tmetaInfo"); + #endif + } + +#if DEBUG_KP_DOCUMENT && 1 +{ + if (image.width () <= 16 && image.height () <= 16) + { + kdDebug () << "Image dump:" << endl; + + for (int y = 0; y < image.height (); y++) + { + for (int x = 0; x < image.width (); x++) + { + const QRgb rgb = image.pixel (x, y); + fprintf (stderr, " %08X", rgb); + } + fprintf (stderr, "\n"); + } + } +} +#endif + + + QPixmap newPixmap = kpPixmapFX::convertToPixmapAsLosslessAsPossible (image, wali); + + +#if DEBUG_KP_DOCUMENT && 1 +{ + const QImage image2 = kpPixmapFX::convertToImage (newPixmap); + kdDebug () << "(Converted to pixmap) Image dump:" << endl; + + bool differsFromOrgImage = false; + unsigned long hash = 0; + int numDiff = 0; + for (int y = 0; y < image2.height (); y++) + { + for (int x = 0; x < image2.width (); x++) + { + const QRgb rgb = image2.pixel (x, y); + hash += ((x % 2) + 1) * rgb; + if (rgb != image.pixel (x, y)) + { + differsFromOrgImage = true; + numDiff++; + } + if (image2.width () <= 16 && image2.height () <= 16) + fprintf (stderr, " %08X", rgb); + } + if (image2.width () <= 16 && image2.height () <= 16) + fprintf (stderr, "\n"); + } + + kdDebug () << "\tdiffersFromOrgImage=" + << differsFromOrgImage + << " numDiff=" + << numDiff + << " hash=" << hash << endl; +} +#endif + + return newPixmap; +} + +// public static +QPixmap kpDocument::getPixmapFromFile (const KURL &url, bool suppressDoesntExistDialog, + QWidget *parent, + kpDocumentSaveOptions *saveOptions, + kpDocumentMetaInfo *metaInfo) +{ +#if DEBUG_KP_DOCUMENT + kdDebug () << "kpDocument::getPixmapFromFile(" << url << "," << parent << ")" << endl; +#endif + + if (saveOptions) + *saveOptions = kpDocumentSaveOptions (); + + if (metaInfo) + *metaInfo = kpDocumentMetaInfo (); + + + QString tempFile; + if (url.isEmpty () || !KIO::NetAccess::download (url, tempFile, parent)) + { + if (!suppressDoesntExistDialog) + { + KMessageBox::sorry (parent, + i18n ("Could not open \"%1\".") + .arg (kpDocument::prettyFilenameForURL (url))); + } + + return QPixmap (); + } + + + QImage image; + + // sync: remember to "KIO::NetAccess::removeTempFile (tempFile)" in all exit paths + { + QString detectedMimeType = KImageIO::mimeType (tempFile); + if (saveOptions) + saveOptions->setMimeType (detectedMimeType); + + #if DEBUG_KP_DOCUMENT + kdDebug () << "\ttempFile=" << tempFile << endl; + kdDebug () << "\tmimetype=" << detectedMimeType << endl; + kdDebug () << "\tsrc=" << url.path () << endl; + kdDebug () << "\tmimetype of src=" << KImageIO::mimeType (url.path ()) << endl; + #endif + + if (detectedMimeType.isEmpty ()) + { + KMessageBox::sorry (parent, + i18n ("Could not open \"%1\" - unknown mimetype.") + .arg (kpDocument::prettyFilenameForURL (url))); + KIO::NetAccess::removeTempFile (tempFile); + return QPixmap (); + } + + + image = QImage (tempFile); + KIO::NetAccess::removeTempFile (tempFile); + } + + + if (image.isNull ()) + { + KMessageBox::sorry (parent, + i18n ("Could not open \"%1\" - unsupported image format.\n" + "The file may be corrupt.") + .arg (kpDocument::prettyFilenameForURL (url))); + return QPixmap (); + } + + const QPixmap newPixmap = kpDocument::convertToPixmapAsLosslessAsPossible (image, + kpPixmapFX::WarnAboutLossInfo ( + i18n ("The image \"%1\"" + " may have more colors than the current screen mode." + " In order to display it, some colors may be changed." + " Try increasing your screen depth to at least %2bpp." + + "\nIt also" + + " contains translucency which is not fully" + " supported. The translucency data will be" + " approximated with a 1-bit transparency mask.") + .arg (prettyFilenameForURL (url)), + i18n ("The image \"%1\"" + " may have more colors than the current screen mode." + " In order to display it, some colors may be changed." + " Try increasing your screen depth to at least %2bpp.") + .arg (prettyFilenameForURL (url)), + i18n ("The image \"%1\"" + " contains translucency which is not fully" + " supported. The translucency data will be" + " approximated with a 1-bit transparency mask.") + .arg (prettyFilenameForURL (url)), + "docOpen", + parent), + saveOptions, + metaInfo); + + if (newPixmap.isNull ()) + { + KMessageBox::sorry (parent, + i18n ("Could not open \"%1\" - out of graphics memory.") + .arg (kpDocument::prettyFilenameForURL (url))); + return QPixmap (); + } + +#if DEBUG_KP_DOCUMENT + kdDebug () << "\tpixmap: depth=" << newPixmap.depth () + << " hasAlphaChannelOrMask=" << newPixmap.hasAlpha () + << " hasAlphaChannel=" << newPixmap.hasAlphaChannel () + << endl; +#endif + + + return newPixmap; +} + +void kpDocument::openNew (const KURL &url) +{ +#if DEBUG_KP_DOCUMENT + kdDebug () << "KpDocument::openNew (" << url << ")" << endl; +#endif + + m_pixmap->fill (Qt::white); + + setURL (url, false/*not from url*/); + *m_saveOptions = kpDocumentSaveOptions (); + *m_metaInfo = kpDocumentMetaInfo (); + m_modified = false; + + emit documentOpened (); +} + +bool kpDocument::open (const KURL &url, bool newDocSameNameIfNotExist) +{ +#if DEBUG_KP_DOCUMENT + kdDebug () << "kpDocument::open (" << url << ")" << endl; +#endif + + kpDocumentSaveOptions newSaveOptions; + kpDocumentMetaInfo newMetaInfo; + QPixmap newPixmap = kpDocument::getPixmapFromFile (url, + newDocSameNameIfNotExist/*suppress "doesn't exist" dialog*/, + m_mainWindow, + &newSaveOptions, + &newMetaInfo); + + if (!newPixmap.isNull ()) + { + delete m_pixmap; + m_pixmap = new QPixmap (newPixmap); + + setURL (url, true/*is from url*/); + *m_saveOptions = newSaveOptions; + *m_metaInfo = newMetaInfo; + m_modified = false; + + emit documentOpened (); + return true; + } + + if (newDocSameNameIfNotExist) + { + if (!url.isEmpty () && + // not just a permission error? + !KIO::NetAccess::exists (url, true/*open*/, m_mainWindow)) + { + openNew (url); + } + else + { + openNew (KURL ()); + } + + return true; + } + else + { + return false; + } +} + +bool kpDocument::save (bool overwritePrompt, bool lossyPrompt) +{ +#if DEBUG_KP_DOCUMENT + kdDebug () << "kpDocument::save(" + << "overwritePrompt=" << overwritePrompt + << ",lossyPrompt=" << lossyPrompt + << ") url=" << m_url + << " savedAtLeastOnceBefore=" << savedAtLeastOnceBefore () + << endl; +#endif + + // TODO: check feels weak + if (m_url.isEmpty () || m_saveOptions->mimeType ().isEmpty ()) + { + KMessageBox::detailedError (m_mainWindow, + i18n ("Could not save image - insufficient information."), + i18n ("URL: %1\n" + "Mimetype: %2") + .arg (prettyURL ()) + .arg (m_saveOptions->mimeType ().isEmpty () ? + i18n ("") : + m_saveOptions->mimeType ()), + i18n ("Internal Error")); + return false; + } + + return saveAs (m_url, *m_saveOptions, + overwritePrompt, + lossyPrompt); +} + + +// public static +bool kpDocument::lossyPromptContinue (const QPixmap &pixmap, + const kpDocumentSaveOptions &saveOptions, + QWidget *parent) +{ +#if DEBUG_KP_DOCUMENT + kdDebug () << "kpDocument::lossyPromptContinue()" << endl; +#endif + +#define QUIT_IF_CANCEL(messageBoxCommand) \ +{ \ + if (messageBoxCommand != KMessageBox::Continue) \ + { \ + return false; \ + } \ +} + + const int lossyType = saveOptions.isLossyForSaving (pixmap); + if (lossyType & (kpDocumentSaveOptions::MimeTypeMaximumColorDepthLow | + kpDocumentSaveOptions::Quality)) + { + QUIT_IF_CANCEL ( + KMessageBox::warningContinueCancel (parent, + i18n ("

The %1 format may not be able" + " to preserve all of the image's color information.

" + + "

Are you sure you want to save in this format?

") + .arg (KMimeType::mimeType (saveOptions.mimeType ())->comment ()), + // TODO: caption misleading for lossless formats that have + // low maximum colour depth + i18n ("Lossy File Format"), + KStdGuiItem::save (), + QString::fromLatin1 ("SaveInLossyMimeTypeDontAskAgain"))); + } + else if (lossyType & kpDocumentSaveOptions::ColorDepthLow) + { + QUIT_IF_CANCEL ( + KMessageBox::warningContinueCancel (parent, + i18n ("

Saving the image at the low color depth of %1-bit" + " may result in the loss of color information." + + " Any transparency will also be removed.

" + + "

Are you sure you want to save at this color depth?

") + .arg (saveOptions.colorDepth ()), + i18n ("Low Color Depth"), + KStdGuiItem::save (), + QString::fromLatin1 ("SaveAtLowColorDepthDontAskAgain"))); + } +#undef QUIT_IF_CANCEL + + return true; +} + +// public static +bool kpDocument::savePixmapToDevice (const QPixmap &pixmap, + QIODevice *device, + const kpDocumentSaveOptions &saveOptions, + const kpDocumentMetaInfo &metaInfo, + bool lossyPrompt, + QWidget *parent, + bool *userCancelled) +{ + if (userCancelled) + *userCancelled = false; + + QString type = KImageIO::typeForMime (saveOptions.mimeType ()); +#if DEBUG_KP_DOCUMENT + kdDebug () << "\tmimeType=" << saveOptions.mimeType () + << " type=" << type << endl; +#endif + + if (lossyPrompt && !lossyPromptContinue (pixmap, saveOptions, parent)) + { + if (userCancelled) + *userCancelled = true; + + #if DEBUG_KP_DOCUMENT + kdDebug () << "\treturning false because of lossyPrompt" << endl; + #endif + return false; + } + + + QPixmap pixmapToSave = + kpPixmapFX::pixmapWithDefinedTransparentPixels (pixmap, + Qt::white); // CONFIG + QImage imageToSave = kpPixmapFX::convertToImage (pixmapToSave); + + + // TODO: fix dup with kpDocumentSaveOptions::isLossyForSaving() + const bool useSaveOptionsColorDepth = + (saveOptions.mimeTypeHasConfigurableColorDepth () && + !saveOptions.colorDepthIsInvalid ()); + const bool useSaveOptionsQuality = + (saveOptions.mimeTypeHasConfigurableQuality () && + !saveOptions.qualityIsInvalid ()); + + + // + // Reduce colors if required + // + + if (useSaveOptionsColorDepth && + imageToSave.depth () != saveOptions.colorDepth ()) + { + imageToSave = ::convertImageDepth (imageToSave, + saveOptions.colorDepth (), + saveOptions.dither ()); + } + + + // + // Write Meta Info + // + + imageToSave.setDotsPerMeterX (metaInfo.dotsPerMeterX ()); + imageToSave.setDotsPerMeterY (metaInfo.dotsPerMeterY ()); + imageToSave.setOffset (metaInfo.offset ()); + + QValueList keyList = metaInfo.textList (); + for (QValueList ::const_iterator it = keyList.begin (); + it != keyList.end (); + it++) + { + imageToSave.setText ((*it).key, (*it).lang, metaInfo.text (*it)); + } + + + // + // Save at required quality + // + + int quality = -1; // default + + if (useSaveOptionsQuality) + quality = saveOptions.quality (); + + if (!imageToSave.save (device, type.latin1 (), quality)) + { + #if DEBUG_KP_DOCUMENT + kdDebug () << "\tQImage::save() returned false" << endl; + #endif + return false; + } + + +#if DEBUG_KP_DOCUMENT + kdDebug () << "\tsave OK" << endl; +#endif + return true; +} + +static void CouldNotCreateTemporaryFileDialog (QWidget *parent) +{ + KMessageBox::error (parent, + i18n ("Could not save image - unable to create temporary file.")); +} + +static void CouldNotSaveDialog (const KURL &url, QWidget *parent) +{ + // TODO: use file.errorString() + KMessageBox::error (parent, + i18n ("Could not save as \"%1\".") + .arg (kpDocument::prettyFilenameForURL (url))); +} + +// public static +bool kpDocument::savePixmapToFile (const QPixmap &pixmap, + const KURL &url, + const kpDocumentSaveOptions &saveOptions, + const kpDocumentMetaInfo &metaInfo, + bool overwritePrompt, + bool lossyPrompt, + QWidget *parent) +{ + // TODO: Use KIO::NetAccess:mostLocalURL() for accessing home:/ (and other + // such local URLs) for efficiency and because only local writes + // are atomic. +#if DEBUG_KP_DOCUMENT + kdDebug () << "kpDocument::savePixmapToFile (" + << url + << ",overwritePrompt=" << overwritePrompt + << ",lossyPrompt=" << lossyPrompt + << ")" << endl; + saveOptions.printDebug (QString::fromLatin1 ("\tsaveOptions")); + metaInfo.printDebug (QString::fromLatin1 ("\tmetaInfo")); +#endif + + if (overwritePrompt && KIO::NetAccess::exists (url, false/*write*/, parent)) + { + int result = KMessageBox::warningContinueCancel (parent, + i18n ("A document called \"%1\" already exists.\n" + "Do you want to overwrite it?") + .arg (prettyFilenameForURL (url)), + QString::null, + i18n ("Overwrite")); + + if (result != KMessageBox::Continue) + { + #if DEBUG_KP_DOCUMENT + kdDebug () << "\tuser doesn't want to overwrite" << endl; + #endif + + return false; + } + } + + + if (lossyPrompt && !lossyPromptContinue (pixmap, saveOptions, parent)) + { + #if DEBUG_KP_DOCUMENT + kdDebug () << "\treturning false because of lossyPrompt" << endl; + #endif + return false; + } + + + // Local file? + if (url.isLocalFile ()) + { + const QString filename = url.path (); + + // sync: All failure exit paths _must_ call KSaveFile::abort() or + // else, the KSaveFile destructor will overwrite the file, + // , despite the failure. + KSaveFile atomicFileWriter (filename); + { + if (atomicFileWriter.status () != 0) + { + // We probably don't need this as has not been + // opened. + atomicFileWriter.abort (); + + #if DEBUG_KP_DOCUMENT + kdDebug () << "\treturning false because could not open KSaveFile" + << " status=" << atomicFileWriter.status () << endl; + #endif + ::CouldNotCreateTemporaryFileDialog (parent); + return false; + } + + // Write to local temporary file. + if (!savePixmapToDevice (pixmap, atomicFileWriter.file (), + saveOptions, metaInfo, + false/*no lossy prompt*/, + parent)) + { + atomicFileWriter.abort (); + + #if DEBUG_KP_DOCUMENT + kdDebug () << "\treturning false because could not save pixmap to device" + << endl; + #endif + ::CouldNotSaveDialog (url, parent); + return false; + } + + // Atomically overwrite local file with the temporary file + // we saved to. + if (!atomicFileWriter.close ()) + { + atomicFileWriter.abort (); + + #if DEBUG_KP_DOCUMENT + kdDebug () << "\tcould not close KSaveFile" << endl; + #endif + ::CouldNotSaveDialog (url, parent); + return false; + } + } // sync KSaveFile.abort() + } + // Remote file? + else + { + // Create temporary file that is deleted when the variable goes + // out of scope. + KTempFile tempFile; + tempFile.setAutoDelete (true); + + QString filename = tempFile.name (); + if (filename.isEmpty ()) + { + #if DEBUG_KP_DOCUMENT + kdDebug () << "\treturning false because tempFile empty" << endl; + #endif + ::CouldNotCreateTemporaryFileDialog (parent); + return false; + } + + // Write to local temporary file. + QFile file (filename); + { + if (!file.open (IO_WriteOnly)) + { + #if DEBUG_KP_DOCUMENT + kdDebug () << "\treturning false because can't open file" + << " errorString=" << file.errorString () << endl; + #endif + ::CouldNotCreateTemporaryFileDialog (parent); + return false; + } + + if (!savePixmapToDevice (pixmap, &file, + saveOptions, metaInfo, + false/*no lossy prompt*/, + parent)) + { + #if DEBUG_KP_DOCUMENT + kdDebug () << "\treturning false because could not save pixmap to device" + << endl; + #endif + ::CouldNotSaveDialog (url, parent); + return false; + } + } + file.close (); + if (file.status () != IO_Ok) + { + #if DEBUG_KP_DOCUMENT + kdDebug () << "\treturning false because could not close" << endl; + #endif + ::CouldNotSaveDialog (url, parent); + return false; + } + + // Copy local temporary file to overwrite remote. + // TODO: No one seems to know how to do this atomically + // [http://lists.kde.org/?l=kde-core-devel&m=117845162728484&w=2]. + // At least, fish:// (ssh) is definitely not atomic. + if (!KIO::NetAccess::upload (filename, url, parent)) + { + #if DEBUG_KP_DOCUMENT + kdDebug () << "\treturning false because could not upload" << endl; + #endif + KMessageBox::error (parent, + i18n ("Could not save image - failed to upload.")); + return false; + } + } + + + return true; +} + +bool kpDocument::saveAs (const KURL &url, + const kpDocumentSaveOptions &saveOptions, + bool overwritePrompt, + bool lossyPrompt) +{ +#if DEBUG_KP_DOCUMENT + kdDebug () << "kpDocument::saveAs (" << url << "," + << saveOptions.mimeType () << ")" << endl; +#endif + + if (kpDocument::savePixmapToFile (pixmapWithSelection (), + url, + saveOptions, *metaInfo (), + overwritePrompt, + lossyPrompt, + m_mainWindow)) + { + setURL (url, true/*is from url*/); + *m_saveOptions = saveOptions; + m_modified = false; + + m_savedAtLeastOnceBefore = true; + + emit documentSaved (); + return true; + } + else + { + return false; + } +} + +// public +bool kpDocument::savedAtLeastOnceBefore () const +{ + return m_savedAtLeastOnceBefore; +} + +// public +KURL kpDocument::url () const +{ + return m_url; +} + +// public +void kpDocument::setURL (const KURL &url, bool isFromURL) +{ + m_url = url; + m_isFromURL = isFromURL; +} + +// public +bool kpDocument::isFromURL (bool checkURLStillExists) const +{ + if (!m_isFromURL) + return false; + + if (!checkURLStillExists) + return true; + + return (!m_url.isEmpty () && + KIO::NetAccess::exists (m_url, true/*open*/, m_mainWindow)); +} + + +// static +QString kpDocument::prettyURLForURL (const KURL &url) +{ + if (url.isEmpty ()) + return i18n ("Untitled"); + else + return url.prettyURL (0, KURL::StripFileProtocol); +} + +QString kpDocument::prettyURL () const +{ + return prettyURLForURL (m_url); +} + + +// static +QString kpDocument::prettyFilenameForURL (const KURL &url) +{ + if (url.isEmpty ()) + return i18n ("Untitled"); + else if (url.fileName ().isEmpty ()) + return prettyURLForURL (url); // better than the name "" + else + return url.fileName (); +} + +QString kpDocument::prettyFilename () const +{ + return prettyFilenameForURL (m_url); +} + + +// public +const kpDocumentSaveOptions *kpDocument::saveOptions () const +{ + return m_saveOptions; +} + +// public +void kpDocument::setSaveOptions (const kpDocumentSaveOptions &saveOptions) +{ + *m_saveOptions = saveOptions; +} + + +// public +const kpDocumentMetaInfo *kpDocument::metaInfo () const +{ + return m_metaInfo; +} + +// public +void kpDocument::setMetaInfo (const kpDocumentMetaInfo &metaInfo) +{ + *m_metaInfo = metaInfo; +} + + +/* + * Properties + */ + +void kpDocument::setModified (bool yes) +{ + if (yes == m_modified) + return; + + m_modified = yes; + + if (yes) + emit documentModified (); +} + +bool kpDocument::isModified () const +{ + return m_modified; +} + +bool kpDocument::isEmpty () const +{ + return url ().isEmpty () && !isModified (); +} + + +int kpDocument::constructorWidth () const +{ + return m_constructorWidth; +} + +int kpDocument::width (bool ofSelection) const +{ + if (ofSelection && m_selection) + return m_selection->width (); + else + return m_pixmap->width (); +} + +int kpDocument::oldWidth () const +{ + return m_oldWidth; +} + +void kpDocument::setWidth (int w, const kpColor &backgroundColor) +{ + resize (w, height (), backgroundColor); +} + + +int kpDocument::constructorHeight () const +{ + return m_constructorHeight; +} + +int kpDocument::height (bool ofSelection) const +{ + if (ofSelection && m_selection) + return m_selection->height (); + else + return m_pixmap->height (); +} + +int kpDocument::oldHeight () const +{ + return m_oldHeight; +} + +void kpDocument::setHeight (int h, const kpColor &backgroundColor) +{ + resize (width (), h, backgroundColor); +} + +QRect kpDocument::rect (bool ofSelection) const +{ + if (ofSelection && m_selection) + return m_selection->boundingRect (); + else + return m_pixmap->rect (); +} + + +/* + * Pixmap access + */ + +// public +QPixmap kpDocument::getPixmapAt (const QRect &rect) const +{ + return kpPixmapFX::getPixmapAt (*m_pixmap, rect); +} + +// public +void kpDocument::setPixmapAt (const QPixmap &pixmap, const QPoint &at) +{ +#if DEBUG_KP_DOCUMENT && 0 + kdDebug () << "kpDocument::setPixmapAt (pixmap (w=" + << pixmap.width () + << ",h=" << pixmap.height () + << "), x=" << at.x () + << ",y=" << at.y () + << endl; +#endif + + kpPixmapFX::setPixmapAt (m_pixmap, at, pixmap); + slotContentsChanged (QRect (at.x (), at.y (), pixmap.width (), pixmap.height ())); +} + +// public +void kpDocument::paintPixmapAt (const QPixmap &pixmap, const QPoint &at) +{ + kpPixmapFX::paintPixmapAt (m_pixmap, at, pixmap); + slotContentsChanged (QRect (at.x (), at.y (), pixmap.width (), pixmap.height ())); +} + + +// public +QPixmap *kpDocument::pixmap (bool ofSelection) const +{ + if (ofSelection) + { + if (m_selection && m_selection->pixmap ()) + return m_selection->pixmap (); + else + return 0; + } + else + return m_pixmap; +} + +// public +void kpDocument::setPixmap (const QPixmap &pixmap) +{ + m_oldWidth = width (), m_oldHeight = height (); + + *m_pixmap = pixmap; + + if (m_oldWidth == width () && m_oldHeight == height ()) + slotContentsChanged (pixmap.rect ()); + else + slotSizeChanged (width (), height ()); +} + +// public +void kpDocument::setPixmap (bool ofSelection, const QPixmap &pixmap) +{ + if (ofSelection) + { + if (!m_selection) + { + kdError () << "kpDocument::setPixmap(ofSelection=true) without sel" << endl; + return; + } + + m_selection->setPixmap (pixmap); + } + else + setPixmap (pixmap); +} + + +// private +void kpDocument::updateToolsSingleKeyTriggersEnabled () +{ + if (m_mainWindow) + { + // Disable single key shortcuts when the user is editing text + m_mainWindow->enableActionsSingleKeyTriggers (!m_selection || !m_selection->isText ()); + } +} + + +// public +kpSelection *kpDocument::selection () const +{ + return m_selection; +} + +// public +void kpDocument::setSelection (const kpSelection &selection) +{ +#if DEBUG_KP_DOCUMENT && 0 + kdDebug () << "kpDocument::setSelection() sel boundingRect=" + << selection.boundingRect () + << endl; +#endif + + kpViewManager *vm = m_mainWindow ? m_mainWindow->viewManager () : 0; + if (vm) + vm->setQueueUpdates (); + + bool hadSelection = (bool) m_selection; + + + const bool isTextChanged = (m_mainWindow->toolIsTextTool () != + (selection.type () == kpSelection::Text)); + + // We don't change the Selection Tool if the new selection's + // shape is merely different to the current tool's (e.g. rectangular + // vs elliptical) because: + // + // 1. All image selection tools support editing selections of all the + // different shapes anyway. + // 2. Suppose the user is trying out different drags of selection borders + // and then decides to paste a differently shaped selection before continuing + // to try out different borders. If the pasting were to switch to + // a differently shaped tool, the borders drawn after the paste would + // be using a new shape rather than the shape before the paste. This + // could get irritating so we don't do the switch. + // + if (m_mainWindow && + (!m_mainWindow->toolIsASelectionTool () || isTextChanged)) + { + // Switch to the appropriately shaped selection tool + // _before_ we change the selection + // (all selection tool's ::end() functions nuke the current selection) + switch (selection.type ()) + { + case kpSelection::Rectangle: + m_mainWindow->slotToolRectSelection (); + break; + case kpSelection::Ellipse: + m_mainWindow->slotToolEllipticalSelection (); + break; + case kpSelection::Points: + m_mainWindow->slotToolFreeFormSelection (); + break; + case kpSelection::Text: + m_mainWindow->slotToolText (); + break; + default: + break; + } + } + + + if (m_selection) + { + // TODO: Emitting this, before setting the new selection, is bogus + // since it would redraw the old selection. + // + // Luckily, this doesn't matter thanks to the + // kpViewManager::setQueueUpdates() call above. + if (m_selection->pixmap ()) + slotContentsChanged (m_selection->boundingRect ()); + else + // TODO: Should emit contentsChanged() instead? + // I don't think it matters since contentsChanged() is + // connected to updateViews() anyway (see + // kpMainWindow::setDocument ()). + vm->updateViews (m_selection->boundingRect ()); + + delete m_selection; + } + + m_selection = new kpSelection (selection); + + // TODO: this coupling is bad, careless and lazy + if (m_mainWindow) + { + if (!m_selection->isText ()) + { + if (m_selection->transparency () != m_mainWindow->selectionTransparency ()) + { + kdDebug () << "kpDocument::setSelection() sel's transparency differs " + "from mainWindow's transparency - setting mainWindow's transparency " + "to sel" + << endl; + kdDebug () << "\tisOpaque: sel=" << m_selection->transparency ().isOpaque () + << " mainWindow=" << m_mainWindow->selectionTransparency ().isOpaque () + << endl; + m_mainWindow->setSelectionTransparency (m_selection->transparency ()); + } + } + else + { + if (m_selection->textStyle () != m_mainWindow->textStyle ()) + { + kdDebug () << "kpDocument::setSelection() sel's textStyle differs " + "from mainWindow's textStyle - setting mainWindow's textStyle " + "to sel" + << endl; + m_mainWindow->setTextStyle (m_selection->textStyle ()); + } + } + } + + updateToolsSingleKeyTriggersEnabled (); + +#if DEBUG_KP_DOCUMENT && 0 + kdDebug () << "\tcheck sel " << (int *) m_selection + << " boundingRect=" << m_selection->boundingRect () + << endl; +#endif + if (m_selection->pixmap ()) + slotContentsChanged (m_selection->boundingRect ()); + else + // TODO: Should emit contentsChanged() instead? + // I don't think it matters since contentsChanged() is + // connected to updateViews() anyway (see + // kpMainWindow::setDocument ()). + vm->updateViews (m_selection->boundingRect ()); + + // There's no need to disconnect() the old selection since we: + // + // 1. Connect our _copy_ of the given selection. + // 2. We delete our copy when setSelection() is called again. + // + // See code above for both. + connect (m_selection, SIGNAL (changed (const QRect &)), + this, SLOT (slotContentsChanged (const QRect &))); + + + if (!hadSelection) + emit selectionEnabled (true); + + if (isTextChanged) + emit selectionIsTextChanged (selection.type () == kpSelection::Text); + + if (vm) + vm->restoreQueueUpdates (); +} + +// public +QPixmap kpDocument::getSelectedPixmap (const QBitmap &maskBitmap_) const +{ + kpSelection *sel = selection (); + + // must have a selection region + if (!sel) + { + kdError () << "kpDocument::getSelectedPixmap() no sel region" << endl; + return QPixmap (); + } + + // easy if we already have it :) + if (sel->pixmap ()) + return *sel->pixmap (); + + + const QRect boundingRect = sel->boundingRect (); + if (!boundingRect.isValid ()) + { + kdError () << "kpDocument::getSelectedPixmap() boundingRect invalid" << endl; + return QPixmap (); + } + + + QBitmap maskBitmap = maskBitmap_; + if (maskBitmap.isNull () && + !sel->isRectangular ()) + { + maskBitmap = sel->maskForOwnType (); + + if (maskBitmap.isNull ()) + { + kdError () << "kpDocument::getSelectedPixmap() could not get mask" << endl; + return QPixmap (); + } + } + + + QPixmap selPixmap = getPixmapAt (boundingRect); + + if (!maskBitmap.isNull ()) + { + // Src Dest = Result + // ----------------- + // 0 0 0 + // 0 1 0 + // 1 0 0 + // 1 1 1 + QBitmap selMaskBitmap = kpPixmapFX::getNonNullMask (selPixmap); + bitBlt (&selMaskBitmap, + QPoint (0, 0), + &maskBitmap, + QRect (0, 0, maskBitmap.width (), maskBitmap.height ()), + Qt::AndROP); + selPixmap.setMask (selMaskBitmap); + } + + return selPixmap; +} + +// public +bool kpDocument::selectionPullFromDocument (const kpColor &backgroundColor) +{ + kpViewManager *vm = m_mainWindow ? m_mainWindow->viewManager () : 0; + + kpSelection *sel = selection (); + + // must have a selection region + if (!sel) + { + kdError () << "kpDocument::selectionPullFromDocument() no sel region" << endl; + return false; + } + + // should not already have a pixmap + if (sel->pixmap ()) + { + kdError () << "kpDocument::selectionPullFromDocument() already has pixmap" << endl; + return false; + } + + const QRect boundingRect = sel->boundingRect (); + if (!boundingRect.isValid ()) + { + kdError () << "kpDocument::selectionPullFromDocument() boundingRect invalid" << endl; + return false; + } + + + // + // Figure out mask for non-rectangular selections + // + + QBitmap maskBitmap = sel->maskForOwnType (true/*return null bitmap for rectangular*/); + + + // + // Get selection pixmap from document + // + + QPixmap selPixmap = getSelectedPixmap (maskBitmap); + + if (vm) + vm->setQueueUpdates (); + + sel->setPixmap (selPixmap); + + + // + // Fill opaque bits of the hole in the document + // + + // TODO: this assumes backgroundColor == sel->transparency ().transparentColor() + const QPixmap selTransparentPixmap = sel->transparentPixmap (); + + if (backgroundColor.isOpaque ()) + { + QPixmap erasePixmap (boundingRect.width (), boundingRect.height ()); + erasePixmap.fill (backgroundColor.toQColor ()); + + if (selTransparentPixmap.mask ()) + erasePixmap.setMask (*selTransparentPixmap.mask ()); + + paintPixmapAt (erasePixmap, boundingRect.topLeft ()); + } + else + { + kpPixmapFX::paintMaskTransparentWithBrush (m_pixmap, + boundingRect.topLeft (), + kpPixmapFX::getNonNullMask (selTransparentPixmap)); + slotContentsChanged (boundingRect); + } + + if (vm) + vm->restoreQueueUpdates (); + + return true; +} + +// public +bool kpDocument::selectionDelete () +{ + kpSelection *sel = selection (); + + if (!sel) + return false; + + const QRect boundingRect = sel->boundingRect (); + if (!boundingRect.isValid ()) + return false; + + bool selectionHadPixmap = m_selection ? (bool) m_selection->pixmap () : false; + + delete m_selection; + m_selection = 0; + + + // HACK to prevent document from being modified when + // user cancels dragging out a new selection + if (selectionHadPixmap) + slotContentsChanged (boundingRect); + else + emit contentsChanged (boundingRect); + + emit selectionEnabled (false); + + + updateToolsSingleKeyTriggersEnabled (); + + return true; +} + +// public +bool kpDocument::selectionCopyOntoDocument (bool useTransparentPixmap) +{ + kpSelection *sel = selection (); + + // must have a pixmap already + if (!sel) + return false; + + // hasn't actually been lifted yet + if (!sel->pixmap ()) + return true; + + const QRect boundingRect = sel->boundingRect (); + if (!boundingRect.isValid ()) + return false; + + if (!sel->isText ()) + { + // We can't use kpSelection::paint() since that always uses the + // transparent pixmap. + paintPixmapAt (useTransparentPixmap ? sel->transparentPixmap () : sel->opaquePixmap (), + boundingRect.topLeft ()); + } + else + { + // (for antialiasing with background) + sel->paint (m_pixmap, rect ()); + } + + slotContentsChanged (boundingRect); + + return true; +} + +// public +bool kpDocument::selectionPushOntoDocument (bool useTransparentPixmap) +{ + return (selectionCopyOntoDocument (useTransparentPixmap) && selectionDelete ()); +} + +// public +QPixmap kpDocument::pixmapWithSelection () const +{ +#if DEBUG_KP_DOCUMENT && 1 + kdDebug () << "kpDocument::pixmapWithSelection()" << endl; +#endif + + // Have floating selection? + if (m_selection && m_selection->pixmap ()) + { + #if DEBUG_KP_DOCUMENT && 1 + kdDebug () << "\tselection @ " << m_selection->boundingRect () << endl; + #endif + QPixmap output = *m_pixmap; + + m_selection->paint (&output, rect ()); + + return output; + } + else + { + #if DEBUG_KP_DOCUMENT && 1 + kdDebug () << "\tno selection" << endl; + #endif + return *m_pixmap; + } +} + + +/* + * Transformations + */ + +void kpDocument::fill (const kpColor &color) +{ +#if DEBUG_KP_DOCUMENT + kdDebug () << "kpDocument::fill ()" << endl; +#endif + + kpPixmapFX::fill (m_pixmap, color); + slotContentsChanged (m_pixmap->rect ()); +} + +void kpDocument::resize (int w, int h, const kpColor &backgroundColor, bool fillNewAreas) +{ +#if DEBUG_KP_DOCUMENT + kdDebug () << "kpDocument::resize (" << w << "," << h << "," << fillNewAreas << ")" << endl; +#endif + + m_oldWidth = width (), m_oldHeight = height (); + +#if DEBUG_KP_DOCUMENT && 1 + kdDebug () << "\toldWidth=" << m_oldWidth + << " oldHeight=" << m_oldHeight + << endl; +#endif + + if (w == m_oldWidth && h == m_oldHeight) + return; + + kpPixmapFX::resize (m_pixmap, w, h, backgroundColor, fillNewAreas); + + slotSizeChanged (width (), height ()); +} + + +/* + * Slots + */ + +void kpDocument::slotContentsChanged (const QRect &rect) +{ + setModified (); + emit contentsChanged (rect); +} + +void kpDocument::slotSizeChanged (int newWidth, int newHeight) +{ + setModified (); + emit sizeChanged (newWidth, newHeight); + emit sizeChanged (QSize (newWidth, newHeight)); +} + +void kpDocument::slotSizeChanged (const QSize &newSize) +{ + slotSizeChanged (newSize.width (), newSize.height ()); +} + +#include diff --git a/kolourpaint/kpdocument.h b/kolourpaint/kpdocument.h new file mode 100644 index 00000000..d75e36ff --- /dev/null +++ b/kolourpaint/kpdocument.h @@ -0,0 +1,260 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_DOCUMENT_H +#define KP_DOCUMENT_H + +#include +#include +#include + +#include + +#include + + +class QImage; +class QIODevice; +class QPixmap; +class QPoint; +class QRect; +class QSize; + +class kpColor; +class kpDocumentSaveOptions; +class kpDocumentMetaInfo; +class kpMainWindow; +class kpSelection; + + +class kpDocument : public QObject +{ +Q_OBJECT + +public: + kpDocument (int w, int h, kpMainWindow *mainWindow); + ~kpDocument (); + + kpMainWindow *mainWindow () const; + void setMainWindow (kpMainWindow *mainWindow); + + + /* + * File I/O + */ + + // Wraps kpPixmapFX::convertToPixmapAsLosslessAsPossible() but also + // returns document meta information. + static QPixmap convertToPixmapAsLosslessAsPossible ( + const QImage &image, + const kpPixmapFX::WarnAboutLossInfo &wali = kpPixmapFX::WarnAboutLossInfo (), + kpDocumentSaveOptions *saveOptions = 0, + kpDocumentMetaInfo *metaInfo = 0); + + static QPixmap getPixmapFromFile (const KURL &url, bool suppressDoesntExistDialog, + QWidget *parent, + kpDocumentSaveOptions *saveOptions = 0, + kpDocumentMetaInfo *metaInfo = 0); + // TODO: fix: open*() should only be called once. + // Create a new kpDocument() if you want to open again. + void openNew (const KURL &url); + bool open (const KURL &url, bool newDocSameNameIfNotExist = false); + + static bool lossyPromptContinue (const QPixmap &pixmap, + const kpDocumentSaveOptions &saveOptions, + QWidget *parent); + static bool savePixmapToDevice (const QPixmap &pixmap, + QIODevice *device, + const kpDocumentSaveOptions &saveOptions, + const kpDocumentMetaInfo &metaInfo, + bool lossyPrompt, + QWidget *parent, + bool *userCancelled = 0); + static bool savePixmapToFile (const QPixmap &pixmap, + const KURL &url, + const kpDocumentSaveOptions &saveOptions, + const kpDocumentMetaInfo &metaInfo, + bool overwritePrompt, + bool lossyPrompt, + QWidget *parent); + bool save (bool overwritePrompt = false, bool lossyPrompt = false); + bool saveAs (const KURL &url, + const kpDocumentSaveOptions &saveOptions, + bool overwritePrompt = true, + bool lossyPrompt = true); + + // Returns whether save() or saveAs() have ever been called and returned true + bool savedAtLeastOnceBefore () const; + + KURL url () const; + void setURL (const KURL &url, bool isFromURL); + + // Returns whether the document's pixmap was successfully opened from + // or saved to the URL returned by url(). This is not true for a + // new kpDocument and in the case of open() being passed + // "newDocSameNameIfNotExist = true" when the URL doesn't exist. + // + // If this returns true and the kpDocument hasn't been modified, + // this gives a pretty good indication that the pixmap stored at url() + // is equal to pixmap() (unless the something has happened to that url + // outside of KolourPaint). + bool isFromURL (bool checkURLStillExists = true) const; + + // (will convert: empty URL --> "Untitled") + static QString prettyURLForURL (const KURL &url); + QString prettyURL () const; + + // (will convert: empty URL --> "Untitled") + static QString prettyFilenameForURL (const KURL &url); + QString prettyFilename () const; + + // (guaranteed to return valid pointer) + + const kpDocumentSaveOptions *saveOptions () const; + void setSaveOptions (const kpDocumentSaveOptions &saveOptions); + + const kpDocumentMetaInfo *metaInfo () const; + void setMetaInfo (const kpDocumentMetaInfo &metaInfo); + + + /* + * Properties (modified, width, height, color depth...) + */ + + void setModified (bool yes = true); + bool isModified () const; + bool isEmpty () const; + + int constructorWidth () const; // as passed to the constructor + int width (bool ofSelection = false) const; + int oldWidth () const; // only valid in a slot connected to sizeChanged() + void setWidth (int w, const kpColor &backgroundColor); + + int constructorHeight () const; // as passed to the constructor + int height (bool ofSelection = false) const; + int oldHeight () const; // only valid in a slot connected to sizeChanged() + void setHeight (int h, const kpColor &backgroundColor); + + QRect rect (bool ofSelection = false) const; + + + /* + * Pixmap access + */ + + // get a copy of a bit of the doc's pixmap + // (not including the selection) + QPixmap getPixmapAt (const QRect &rect) const; + + void setPixmapAt (const QPixmap &pixmap, const QPoint &at); + + void paintPixmapAt (const QPixmap &pixmap, const QPoint &at); + + // (not including the selection) + QPixmap *pixmap (bool ofSelection = false) const; + void setPixmap (const QPixmap &pixmap); + void setPixmap (bool ofSelection, const QPixmap &pixmap); + +private: + void updateToolsSingleKeyTriggersEnabled (); + +public: + kpSelection *selection () const; + void setSelection (const kpSelection &selection); + + // TODO: this always returns opaque pixmap - need transparent ver + QPixmap getSelectedPixmap (const QBitmap &maskBitmap = QBitmap ()) const; + + bool selectionPullFromDocument (const kpColor &backgroundColor); + bool selectionDelete (); + bool selectionCopyOntoDocument (bool useTransparentPixmap = true); + bool selectionPushOntoDocument (bool useTransparentPixmap = true); + + // same as pixmap() but returns a _copy_ of the current pixmap + // + any selection pasted on top + QPixmap pixmapWithSelection () const; + + + /* + * Transformations + * (convenience only - you could achieve the same effect (and more) with + * kpPixmapFX: these functions do not affect the selection) + */ + + void fill (const kpColor &color); + void resize (int w, int h, const kpColor &backgroundColor, bool fillNewAreas = true); + + +public slots: + // these will emit signals! + void slotContentsChanged (const QRect &rect); + void slotSizeChanged (int newWidth, int newHeight); + void slotSizeChanged (const QSize &newSize); + +signals: + void documentOpened (); + void documentSaved (); + + // Emitted whenever the isModified() flag changes from false to true. + // This is the _only_ signal that may be emitted in addition to the others. + void documentModified (); + + void contentsChanged (const QRect &rect); + void sizeChanged (int newWidth, int newHeight); // see oldWidth(), oldHeight() + void sizeChanged (const QSize &newSize); + + void selectionEnabled (bool on); + + // HACK: until we support Text Selection -> Rectangular Selection for Image ops + void selectionIsTextChanged (bool isText); + +private: + int m_constructorWidth, m_constructorHeight; + kpMainWindow *m_mainWindow; + QPixmap *m_pixmap; + + KURL m_url; + bool m_isFromURL; + bool m_savedAtLeastOnceBefore; + + kpDocumentSaveOptions *m_saveOptions; + kpDocumentMetaInfo *m_metaInfo; + + bool m_modified; + + kpSelection *m_selection; + + int m_oldWidth, m_oldHeight; + + // There is no need to maintain binary compatibility at this stage. + // The d-pointer is just so that you can experiment without recompiling + // the kitchen sink. + class kpDocumentPrivate *d; +}; + +#endif // KP_DOCUMENT_H diff --git a/kolourpaint/kpdocumentmetainfo.cpp b/kolourpaint/kpdocumentmetainfo.cpp new file mode 100644 index 00000000..5e5fc6ae --- /dev/null +++ b/kolourpaint/kpdocumentmetainfo.cpp @@ -0,0 +1,186 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +#include + +#include + + +struct kpDocumentMetaInfoPrivate +{ + int m_dotsPerMeterX, m_dotsPerMeterY; + QPoint m_offset; + + QMap m_textMap; +}; + + +// public +kpDocumentMetaInfo::kpDocumentMetaInfo () + : d (new kpDocumentMetaInfoPrivate ()) +{ + d->m_dotsPerMeterX = 0; + d->m_dotsPerMeterY = 0; + d->m_offset = QPoint (0, 0); +} + +kpDocumentMetaInfo::kpDocumentMetaInfo (const kpDocumentMetaInfo &rhs) + : d (new kpDocumentMetaInfoPrivate ()) +{ + d->m_dotsPerMeterX = rhs.dotsPerMeterX (); + d->m_dotsPerMeterY = rhs.dotsPerMeterY (); + d->m_offset = rhs.offset (); + d->m_textMap = rhs.textMap (); +} + +// public +kpDocumentMetaInfo::~kpDocumentMetaInfo () +{ + delete d; +} + + +// public +kpDocumentMetaInfo &kpDocumentMetaInfo::operator= (const kpDocumentMetaInfo &rhs) +{ + d->m_dotsPerMeterX = rhs.dotsPerMeterX (); + d->m_dotsPerMeterY = rhs.dotsPerMeterY (); + d->m_offset = rhs.offset (); + d->m_textMap = rhs.textMap (); + + return *this; +} + + +// public +void kpDocumentMetaInfo::printDebug (const QString &prefix) const +{ + const QString usedPrefix = !prefix.isEmpty () ? + prefix + QString::fromLatin1 (":") : + QString::null; + + kdDebug () << usedPrefix << endl; + + kdDebug () << "dotsPerMeter X=" << dotsPerMeterX () + << " Y=" << dotsPerMeterY () + << " offset=" << offset () << endl; + + QValueList keyList = textList (); + for (QValueList ::const_iterator it = keyList.begin (); + it != keyList.end (); + it++) + { + kdDebug () << "key=" << (*it).key + << " lang=" << (*it).lang + << " text=" << text (*it) + << endl; + } + + kdDebug () << usedPrefix << "ENDS" << endl; +} + + +// public +int kpDocumentMetaInfo::dotsPerMeterX () const +{ + return d->m_dotsPerMeterX; +} + +// public +void kpDocumentMetaInfo::setDotsPerMeterX (int val) +{ + d->m_dotsPerMeterX = val; +} + + +// public +int kpDocumentMetaInfo::dotsPerMeterY () const +{ + return d->m_dotsPerMeterY; +} + +// public +void kpDocumentMetaInfo::setDotsPerMeterY (int val) +{ + d->m_dotsPerMeterY = val; +} + + +// public +QPoint kpDocumentMetaInfo::offset () const +{ + return d->m_offset; +} + +// public +void kpDocumentMetaInfo::setOffset (const QPoint &point) +{ + d->m_offset = point; +} + + +// public +QMap kpDocumentMetaInfo::textMap () const +{ + return d->m_textMap; +} + +// public +QValueList kpDocumentMetaInfo::textList () const +{ + return d->m_textMap.keys (); +} + + +// public +QString kpDocumentMetaInfo::text (const QImageTextKeyLang &itkl) const +{ + return d->m_textMap [itkl]; +} + +// public +QString kpDocumentMetaInfo::text (const char *key, const char *lang) const +{ + return text (QImageTextKeyLang (key, lang)); +} + + +// public +void kpDocumentMetaInfo::setText (const QImageTextKeyLang &itkl, + const QString &string) +{ + d->m_textMap [itkl] = string; +} + +// public +void kpDocumentMetaInfo::setText (const char *key, const char *lang, + const QString &string) +{ + setText (QImageTextKeyLang (key, lang), string); +} diff --git a/kolourpaint/kpdocumentmetainfo.h b/kolourpaint/kpdocumentmetainfo.h new file mode 100644 index 00000000..15e1408f --- /dev/null +++ b/kolourpaint/kpdocumentmetainfo.h @@ -0,0 +1,90 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_DOCUMENT_META_INFO +#define KP_DOCUMENT_META_INFO + + +#include +#include +#include +#include + + +class QPoint; + + +class kpDocumentMetaInfo +{ +public: + kpDocumentMetaInfo (); + kpDocumentMetaInfo (const kpDocumentMetaInfo &rhs); + virtual ~kpDocumentMetaInfo (); + +private: + bool operator== (const kpDocumentMetaInfo &rhs) const; + bool operator!= (const kpDocumentMetaInfo &rhs) const; + +public: + kpDocumentMetaInfo &operator= (const kpDocumentMetaInfo &rhs); + + + void printDebug (const QString &prefix) const; + + + // See QImage documentation + + int dotsPerMeterX () const; + void setDotsPerMeterX (int val); + + int dotsPerMeterY () const; + void setDotsPerMeterY (int val); + + + QPoint offset () const; + void setOffset (const QPoint &point); + + + QMap textMap () const; + QValueList textList () const; + + QString text (const QImageTextKeyLang &itkl) const; + QString text (const char *key, const char *lang) const; + void setText (const QImageTextKeyLang &itkl, const QString &string); + void setText (const char *key, const char *lang, const QString &string); + + +private: + // There is no need to maintain binary compatibility at this stage. + // The d-pointer is just so that you can experiment without recompiling + // the kitchen sink. + class kpDocumentMetaInfoPrivate *d; +}; + + +#endif // KP_DOCUMENT_META_INFO diff --git a/kolourpaint/kpdocumentsaveoptions.cpp b/kolourpaint/kpdocumentsaveoptions.cpp new file mode 100644 index 00000000..701b6b51 --- /dev/null +++ b/kolourpaint/kpdocumentsaveoptions.cpp @@ -0,0 +1,561 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_DOCUMENT_SAVE_OPTIONS 0 + + +#include + +#include +#include + +#include +#include +#include + +#include + + +struct kpDocumentSaveOptionsPrivate +{ + QString m_mimeType; + int m_colorDepth; + bool m_dither; + int m_quality; +}; + + +kpDocumentSaveOptions::kpDocumentSaveOptions () + : d (new kpDocumentSaveOptionsPrivate ()) +{ + d->m_mimeType = invalidMimeType (); + d->m_colorDepth = invalidColorDepth (); + d->m_dither = initialDither (); + d->m_quality = invalidQuality (); +} + +kpDocumentSaveOptions::kpDocumentSaveOptions (const kpDocumentSaveOptions &rhs) + : d (new kpDocumentSaveOptionsPrivate ()) +{ + d->m_mimeType = rhs.mimeType (); + d->m_colorDepth = rhs.colorDepth (); + d->m_dither = rhs.dither (); + d->m_quality = rhs.quality (); +} + +kpDocumentSaveOptions::kpDocumentSaveOptions (QString mimeType, int colorDepth, bool dither, int quality) + : d (new kpDocumentSaveOptionsPrivate ()) +{ + d->m_mimeType = mimeType; + d->m_colorDepth = colorDepth; + d->m_dither = dither; + d->m_quality = quality; +} + +kpDocumentSaveOptions::~kpDocumentSaveOptions () +{ + delete d; +} + + +// public +bool kpDocumentSaveOptions::operator== (const kpDocumentSaveOptions &rhs) const +{ + return (mimeType () == rhs.mimeType () && + colorDepth () == rhs.colorDepth () && + dither () == rhs.dither () && + quality () == rhs.quality ()); +} + +// public +bool kpDocumentSaveOptions::operator!= (const kpDocumentSaveOptions &rhs) const +{ + return !(*this == rhs); +} + + +// public +kpDocumentSaveOptions &kpDocumentSaveOptions::operator= (const kpDocumentSaveOptions &rhs) +{ + setMimeType (rhs.mimeType ()); + setColorDepth (rhs.colorDepth ()); + setDither (rhs.dither ()); + setQuality (rhs.quality ()); + + return *this; +} + + +// public +void kpDocumentSaveOptions::printDebug (const QString &prefix) const +{ + const QString usedPrefix = !prefix.isEmpty () ? + prefix + QString::fromLatin1 (": ") : + QString::null; + + kdDebug () << usedPrefix + << "mimeType=" << mimeType () + << " colorDepth=" << colorDepth () + << " dither=" << dither () + << " quality=" << quality () + << endl; +} + + +// public +QString kpDocumentSaveOptions::mimeType () const +{ + return d->m_mimeType; +} + +// public +void kpDocumentSaveOptions::setMimeType (const QString &mimeType) +{ + d->m_mimeType = mimeType; +} + + +// public static +QString kpDocumentSaveOptions::invalidMimeType () +{ + return QString::null; +} + +// public static +bool kpDocumentSaveOptions::mimeTypeIsInvalid (const QString &mimeType) +{ + return (mimeType == invalidMimeType ()); +} + +// public +bool kpDocumentSaveOptions::mimeTypeIsInvalid () const +{ + return mimeTypeIsInvalid (mimeType ()); +} + + +// public +int kpDocumentSaveOptions::colorDepth () const +{ + return d->m_colorDepth; +} + +// public +void kpDocumentSaveOptions::setColorDepth (int depth) +{ + d->m_colorDepth = depth; +} + + +// public static +int kpDocumentSaveOptions::invalidColorDepth () +{ + return -1; +} + +// public static +bool kpDocumentSaveOptions::colorDepthIsInvalid (int colorDepth) +{ + return (colorDepth != 1 && colorDepth != 8 && colorDepth != 32); +} + +// public +bool kpDocumentSaveOptions::colorDepthIsInvalid () const +{ + return colorDepthIsInvalid (colorDepth ()); +} + + +// public +bool kpDocumentSaveOptions::dither () const +{ + return d->m_dither; +} + +// public +void kpDocumentSaveOptions::setDither (bool dither) +{ + d->m_dither = dither; +} + + +// public static +int kpDocumentSaveOptions::initialDither () +{ + return false; // to avoid accidental double dithering +} + + +// public +int kpDocumentSaveOptions::quality () const +{ + return d->m_quality; +} + +// public +void kpDocumentSaveOptions::setQuality (int quality) +{ + d->m_quality = quality; +} + + +// public static +int kpDocumentSaveOptions::invalidQuality () +{ + return -2; +} + +// public static +bool kpDocumentSaveOptions::qualityIsInvalid (int quality) +{ + return (quality < -1 || quality > 100); +} + +// public +bool kpDocumentSaveOptions::qualityIsInvalid () const +{ + return qualityIsInvalid (quality ()); +} + + +// public static +QString kpDocumentSaveOptions::defaultMimeType (KConfigBase *config) +{ + return config->readEntry (kpSettingForcedMimeType, + QString::fromLatin1 ("image/png")); +} + +// public static +void kpDocumentSaveOptions::saveDefaultMimeType (KConfigBase *config, + const QString &mimeType) +{ + config->writeEntry (kpSettingForcedMimeType, mimeType); +} + + +// public static +int kpDocumentSaveOptions::defaultColorDepth (KConfigBase *config) +{ + int colorDepth = + config->readNumEntry (kpSettingForcedColorDepth, -1); + + if (colorDepthIsInvalid (colorDepth)) + { + // (not screen depth, in case of transparency) + colorDepth = 32; + } + + return colorDepth; +} + +// public static +void kpDocumentSaveOptions::saveDefaultColorDepth (KConfigBase *config, int colorDepth) +{ + config->writeEntry (kpSettingForcedColorDepth, colorDepth); +} + + +// public static +int kpDocumentSaveOptions::defaultDither (KConfigBase *config) +{ + return config->readBoolEntry (kpSettingForcedDither, initialDither ()); +} + +// public static +void kpDocumentSaveOptions::saveDefaultDither (KConfigBase *config, bool dither) +{ + config->writeEntry (kpSettingForcedDither, dither); +} + + +// public static +int kpDocumentSaveOptions::defaultQuality (KConfigBase *config) +{ + int val = config->readNumEntry (kpSettingForcedQuality, -1); + if (qualityIsInvalid (val)) + val = -1; + + return val; +} + +// public static +void kpDocumentSaveOptions::saveDefaultQuality (KConfigBase *config, int quality) +{ + config->writeEntry (kpSettingForcedQuality, quality); +} + + +// public static +kpDocumentSaveOptions kpDocumentSaveOptions::defaultDocumentSaveOptions (KConfigBase *config) +{ + kpDocumentSaveOptions saveOptions; + saveOptions.setMimeType (defaultMimeType (config)); + saveOptions.setColorDepth (defaultColorDepth (config)); + saveOptions.setDither (defaultDither (config)); + saveOptions.setQuality (defaultQuality (config)); + +#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS + saveOptions.printDebug ("kpDocumentSaveOptions::defaultDocumentSaveOptions()"); +#endif + + return saveOptions; +} + +// public static +bool kpDocumentSaveOptions::saveDefaultDifferences (KConfigBase *config, + const kpDocumentSaveOptions &oldDocInfo, + const kpDocumentSaveOptions &newDocInfo) +{ + bool savedSomething = false; + +#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS + kdDebug () << "kpDocumentSaveOptions::saveDefaultDifferences()" << endl; + oldDocInfo.printDebug ("\told"); + newDocInfo.printDebug ("\tnew"); +#endif + + if (newDocInfo.mimeType () != oldDocInfo.mimeType ()) + { + saveDefaultMimeType (config, newDocInfo.mimeType ()); + savedSomething = true; + } + + if (newDocInfo.colorDepth () != oldDocInfo.colorDepth ()) + { + saveDefaultColorDepth (config, newDocInfo.colorDepth ()); + savedSomething = true; + } + + if (newDocInfo.dither () != oldDocInfo.dither ()) + { + saveDefaultDither (config, newDocInfo.dither ()); + savedSomething = true; + } + + if (newDocInfo.quality () != oldDocInfo.quality ()) + { + saveDefaultQuality (config, newDocInfo.quality ()); + savedSomething = true; + } + + return savedSomething; +} + + +static QStringList mimeTypesSupportingProperty (const QString &property, + const QStringList &defaultMimeTypesWithPropertyList) +{ + QStringList mimeTypeList; + + KConfigGroupSaver cfgGroupSaver (KGlobal::config (), + kpSettingsGroupMimeTypeProperties); + KConfigBase *cfg = cfgGroupSaver.config (); + + if (cfg->hasKey (property)) + { + mimeTypeList = cfg->readListEntry (property); + } + else + { + mimeTypeList = defaultMimeTypesWithPropertyList; + + cfg->writeEntry (property, mimeTypeList); + cfg->sync (); + } + + return mimeTypeList; +} + +static bool mimeTypeSupportsProperty (const QString &mimeType, + const QString &property, const QStringList &defaultMimeTypesWithPropertyList) +{ + const QStringList mimeTypeList = mimeTypesSupportingProperty ( + property, defaultMimeTypesWithPropertyList); + + return mimeTypeList.contains (mimeType); +} + + +// SYNC: update mime info +// +// Only care about writable mimetypes. +// +// Run "branches/kolourpaint/control/scripts/gen_mimetype_line.sh Write" in +// the version of kdelibs/kimgio/ (e.g. KDE 3.5) KolourPaint is shipped with, +// to check for any new mimetypes to add info for. In the methods below, +// you can specify this info (maximum color depth, whether it's lossy etc.). +// +// Update the below list also and bump up "kpSettingsGroupMimeTypeProperties" +// in kpdefs.h. +// +// Currently, Depth and Quality settings are mutually exclusive with +// Depth overriding Quality. I've currently favoured Quality with the +// below mimetypes (i.e. all lossy mimetypes are only given Quality settings, +// no Depth settings). +// +// Mimetypes done: +// image/jp2 [UNTESTED] +// image/jpeg +// image/png +// image/x-bmp +// image/x-eps +// image/x-pcx +// image/x-portable-bitmap +// image/x-portable-greymap +// image/x-portable-pixmap +// image/x-rgb +// image/x-targa +// image/x-xbm +// image/x-xpm +// +// To test whether depth is configurable, write an image in the new +// mimetype with all depths and read each one back. See what +// kpDocument thinks the depth is when it gets QImage to read it. + + +// public static +int kpDocumentSaveOptions::mimeTypeMaximumColorDepth (const QString &mimeType) +{ + QStringList defaultList; + + // SYNC: update mime info here + + // Greyscale actually (unenforced since depth not set to configurable) + defaultList << QString::fromLatin1 ("image/x-eps:32"); + + defaultList << QString::fromLatin1 ("image/x-portable-bitmap:1"); + + // Greyscale actually (unenforced since depth not set to configurable) + defaultList << QString::fromLatin1 ("image/x-portable-greymap:8"); + + defaultList << QString::fromLatin1 ("image/x-xbm:1"); + + const QStringList mimeTypeList = mimeTypesSupportingProperty ( + kpSettingMimeTypeMaximumColorDepth, defaultList); + + const QString mimeTypeColon = mimeType + QString::fromLatin1 (":"); + for (QStringList::const_iterator it = mimeTypeList.begin (); + it != mimeTypeList.end (); + it++) + { + if ((*it).startsWith (mimeTypeColon)) + { + int number = (*it).mid (mimeTypeColon.length ()).toInt (); + if (!colorDepthIsInvalid (number)) + { + return number; + } + } + } + + return 32; +} + +// public +int kpDocumentSaveOptions::mimeTypeMaximumColorDepth () const +{ + return mimeTypeMaximumColorDepth (mimeType ()); +} + + +// public static +bool kpDocumentSaveOptions::mimeTypeHasConfigurableColorDepth (const QString &mimeType) +{ + QStringList defaultMimeTypes; + + // SYNC: update mime info here + defaultMimeTypes << QString::fromLatin1 ("image/png"); + defaultMimeTypes << QString::fromLatin1 ("image/x-bmp"); + defaultMimeTypes << QString::fromLatin1 ("image/x-pcx"); + + // TODO: Only 1, 24 not 8; Qt only sees 32 but "file" cmd realises + // it's either 1 or 24. + defaultMimeTypes << QString::fromLatin1 ("image/x-rgb"); + + // TODO: Only 8 and 24 - no 1. + defaultMimeTypes << QString::fromLatin1 ("image/x-xpm"); + + return mimeTypeSupportsProperty (mimeType, + kpSettingMimeTypeHasConfigurableColorDepth, + defaultMimeTypes); +} + +// public +bool kpDocumentSaveOptions::mimeTypeHasConfigurableColorDepth () const +{ + return mimeTypeHasConfigurableColorDepth (mimeType ()); +} + + +// public static +bool kpDocumentSaveOptions::mimeTypeHasConfigurableQuality (const QString &mimeType) +{ + QStringList defaultMimeTypes; + + // SYNC: update mime info here + defaultMimeTypes << QString::fromLatin1 ("image/jp2"); + defaultMimeTypes << QString::fromLatin1 ("image/jpeg"); + + return mimeTypeSupportsProperty (mimeType, + kpSettingMimeTypeHasConfigurableQuality, + defaultMimeTypes); +} + +// public +bool kpDocumentSaveOptions::mimeTypeHasConfigurableQuality () const +{ + return mimeTypeHasConfigurableQuality (mimeType ()); +} + + +// public +int kpDocumentSaveOptions::isLossyForSaving (const QPixmap &pixmap) const +{ + int ret = 0; + + if (mimeTypeMaximumColorDepth () < pixmap.depth ()) + { + ret |= MimeTypeMaximumColorDepthLow; + } + + if (mimeTypeHasConfigurableColorDepth () && + !colorDepthIsInvalid () /*TODO: prevent*/ && + (colorDepth () < pixmap.depth () || + colorDepth () < 32 && pixmap.mask ())) + { + ret |= ColorDepthLow; + } + + if (mimeTypeHasConfigurableQuality () && + !qualityIsInvalid ()) + { + ret |= Quality; + } + + return ret; +} + diff --git a/kolourpaint/kpdocumentsaveoptions.h b/kolourpaint/kpdocumentsaveoptions.h new file mode 100644 index 00000000..0d77ec2c --- /dev/null +++ b/kolourpaint/kpdocumentsaveoptions.h @@ -0,0 +1,150 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_DOCUMENT_SAVE_OPTIONS_H +#define KP_DOCUMENT_SAVE_OPTIONS_H + + +class QPixmap; +class QString; + +class KConfigBase; + + +class kpDocumentSaveOptions +{ +public: + kpDocumentSaveOptions (); + kpDocumentSaveOptions (const kpDocumentSaveOptions &rhs); + kpDocumentSaveOptions (QString mimeType, int colorDepth, bool dither, int quality); + virtual ~kpDocumentSaveOptions (); + + bool operator== (const kpDocumentSaveOptions &rhs) const; + bool operator!= (const kpDocumentSaveOptions &rhs) const; + + kpDocumentSaveOptions &operator= (const kpDocumentSaveOptions &rhs); + + + void printDebug (const QString &prefix) const; + + + QString mimeType () const; + void setMimeType (const QString &mimeType); + + static QString invalidMimeType (); + static bool mimeTypeIsInvalid (const QString &mimeType); + bool mimeTypeIsInvalid () const; + + + int colorDepth () const; + void setColorDepth (int depth); + + static int invalidColorDepth (); + static bool colorDepthIsInvalid (int colorDepth); + bool colorDepthIsInvalid () const; + + + bool dither () const; + void setDither (bool dither); + + static int initialDither (); + + + int quality () const; + void setQuality (int quality); + + static int invalidQuality (); + static bool qualityIsInvalid (int quality); + bool qualityIsInvalid () const; + + + // (All assume that 's group has been set) + // (None of them call KConfigBase::reparseConfig() nor KConfigBase::sync()) + + static QString defaultMimeType (KConfigBase *config); + static void saveDefaultMimeType (KConfigBase *config, const QString &mimeType); + + static int defaultColorDepth (KConfigBase *config); + static void saveDefaultColorDepth (KConfigBase *config, int colorDepth); + + static int defaultDither (KConfigBase *config); + static void saveDefaultDither (KConfigBase *config, bool dither); + + static int defaultQuality (KConfigBase *config); + static void saveDefaultQuality (KConfigBase *config, int quality); + + + static kpDocumentSaveOptions defaultDocumentSaveOptions (KConfigBase *config); + // (returns true if it encountered a difference (and saved it to )) + static bool saveDefaultDifferences (KConfigBase *config, + const kpDocumentSaveOptions &oldDocInfo, + const kpDocumentSaveOptions &newDocInfo); + + +public: + // (purely for informational purposes - not enforced by this class) + static int mimeTypeMaximumColorDepth (const QString &mimeType); + int mimeTypeMaximumColorDepth () const; + + + static bool mimeTypeHasConfigurableColorDepth (const QString &mimeType); + bool mimeTypeHasConfigurableColorDepth () const; + + static bool mimeTypeHasConfigurableQuality (const QString &mimeType); + bool mimeTypeHasConfigurableQuality () const; + + + // TODO: checking for mask loss due to format e.g. BMP + enum LossyType + { + LossLess = 0, + + // mimeTypeMaximumColorDepth() < .depth() + MimeTypeMaximumColorDepthLow = 1, + // i.e. colorDepth() < .depth() || + // colorDepth() < 32 && .mask() + ColorDepthLow = 2, + // i.e. mimeTypeHasConfigurableQuality() + Quality = 4 + }; + + // Returns whether saving with these options will result in + // loss of information. Returned value is the bitwise OR of + // LossType enum possiblities. + int isLossyForSaving (const QPixmap &pixmap) const; + + +private: + // There is no need to maintain binary compatibility at this stage. + // The d-pointer is just so that you can experiment without recompiling + // the kitchen sink. + class kpDocumentSaveOptionsPrivate *d; +}; + + +#endif // KP_DOCUMENT_SAVE_OPTIONS_H diff --git a/kolourpaint/kpdocumentsaveoptionswidget.cpp b/kolourpaint/kpdocumentsaveoptionswidget.cpp new file mode 100644 index 00000000..39edf5b8 --- /dev/null +++ b/kolourpaint/kpdocumentsaveoptionswidget.cpp @@ -0,0 +1,951 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET 0 + + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +// protected static +const QSize kpDocumentSaveOptionsPreviewDialog::s_pixmapLabelMinimumSize (25, 25); + + +kpDocumentSaveOptionsPreviewDialog::kpDocumentSaveOptionsPreviewDialog ( + QWidget *parent, + const char *name) + : QWidget (parent, name, + Qt::WType_TopLevel | + Qt::WStyle_Customize | + Qt::WStyle_DialogBorder | + Qt::WStyle_Title), +#if 0 +KDialogBase (parent, name, false/*non-modal*/, + i18n ("Save Preview"), + 0/*no buttons*/), +#endif + m_filePixmap (0), + m_fileSize (0) +{ + setCaption (i18n ("Save Preview")); + + QWidget *baseWidget = this;//new QWidget (this); + //setMainWidget (baseWidget); + + + QGridLayout *lay = new QGridLayout (baseWidget, 2, 1, + KDialog::marginHint (), KDialog::spacingHint ()); + + m_filePixmapLabel = new kpResizeSignallingLabel (baseWidget); + m_fileSizeLabel = new QLabel (baseWidget); + + + m_filePixmapLabel->setMinimumSize (s_pixmapLabelMinimumSize); + + + lay->addWidget (m_filePixmapLabel, 0, 0); + lay->addWidget (m_fileSizeLabel, 1, 0, Qt::AlignHCenter); + + + lay->setRowStretch (0, 1); + + + connect (m_filePixmapLabel, SIGNAL (resized ()), + this, SLOT (updatePixmapPreview ())); +} + +kpDocumentSaveOptionsPreviewDialog::~kpDocumentSaveOptionsPreviewDialog () +{ + delete m_filePixmap; +} + + +// public +QSize kpDocumentSaveOptionsPreviewDialog::preferredMinimumSize () const +{ + const int contentsWidth = 180; + const int totalMarginsWidth = 2 * KDialog::marginHint (); + + return QSize (contentsWidth + totalMarginsWidth, + contentsWidth * 3 / 4 + totalMarginsWidth); +} + + +// public slot +void kpDocumentSaveOptionsPreviewDialog::setFilePixmapAndSize (const QPixmap &pixmap, + int fileSize) +{ + delete m_filePixmap; + m_filePixmap = new QPixmap (pixmap); + + updatePixmapPreview (); + + m_fileSize = fileSize; + + const int pixmapSize = kpPixmapFX::pixmapSize (pixmap); + const int percent = pixmapSize ? + QMAX (1, fileSize * 100 / pixmapSize) : + 0; +#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "kpDocumentSaveOptionsPreviewDialog::setFilePixmapAndSize()" + << " pixmapSize=" << pixmapSize + << " fileSize=" << fileSize + << " raw fileSize/pixmapSize%=" + << (pixmapSize ? fileSize * 100 / pixmapSize : 0) + << endl; +#endif + + // HACK: I don't know if the percentage thing will work well and we're + // really close to the message freeze so provide alt. texts to choose + // from during the message freeze :) + const QString alternateText0 = i18n ("%1 bytes"); + const QString alternateText1 = i18n ("%1 bytes (%2%)"); + const QString alternateText2 = i18n ("%1 B"); + const QString alternateText3 = i18n ("%1 B (%2%)"); + const QString alternateText4 = i18n ("%1 B (approx. %2%)"); + const QString alternateText5 = i18n ("%1B"); + const QString alternateText6 = i18n ("%1B (%2%)"); + const QString alternateText7 = i18n ("%1B (approx. %2%)"); + m_fileSizeLabel->setText (i18n ("%1 bytes (approx. %2%)") + .arg (KGlobal::locale ()->formatLong (m_fileSize)) + .arg (percent)); +} + +// public slot +void kpDocumentSaveOptionsPreviewDialog::updatePixmapPreview () +{ +#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "kpDocumentSaveOptionsPreviewDialog::updatePreviewPixmap()" + << " filePixmapLabel.size=" << m_filePixmapLabel->size () + << " filePixmap.size=" << m_filePixmap->size () + << endl; +#endif + + if (m_filePixmap) + { + int maxNewWidth = QMIN (m_filePixmap->width (), + m_filePixmapLabel->width ()), + maxNewHeight = QMIN (m_filePixmap->height (), + m_filePixmapLabel->height ()); + + double keepsAspect = kpToolPreviewDialog::aspectScale ( + maxNewWidth, maxNewHeight, + m_filePixmap->width (), m_filePixmap->height ()); + #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "\tmaxNewWidth=" << maxNewWidth + << " maxNewHeight=" << maxNewHeight + << " keepsAspect=" << keepsAspect + << endl; + #endif + + + const int newWidth = kpToolPreviewDialog::scaleDimension ( + m_filePixmap->width (), + keepsAspect, + 1, + maxNewWidth); + const int newHeight = kpToolPreviewDialog::scaleDimension ( + m_filePixmap->height (), + keepsAspect, + 1, + maxNewHeight); + #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "\tnewWidth=" << newWidth + << " newHeight=" << newHeight + << endl; + #endif + + + QPixmap transformedPixmap = + kpPixmapFX::scale (*m_filePixmap, + newWidth, newHeight); + + + QPixmap labelPixmap (m_filePixmapLabel->width (), + m_filePixmapLabel->height ()); + kpPixmapFX::fill (&labelPixmap, kpColor::transparent); + kpPixmapFX::setPixmapAt (&labelPixmap, + (labelPixmap.width () - transformedPixmap.width ()) / 2, + (labelPixmap.height () - transformedPixmap.height ()) / 2, + transformedPixmap); + + + m_filePixmapLabel->setPixmap (labelPixmap); + } + else + { + m_filePixmapLabel->setPixmap (QPixmap ()); + } +} + + +// protected virtual [base QWidget] +void kpDocumentSaveOptionsPreviewDialog::closeEvent (QCloseEvent *e) +{ +#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "kpDocumentSaveOptionsPreviewDialog::closeEvent()" << endl; +#endif + + QWidget::closeEvent (e); + + emit finished (); +} + +// protected virtual [base QWidget] +void kpDocumentSaveOptionsPreviewDialog::moveEvent (QMoveEvent *e) +{ +#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "kpDocumentSaveOptionsPreviewDialog::moveEvent()" << endl; +#endif + + QWidget::moveEvent (e); + + emit moved (); +} + +// protected virtual [base QWidget] +void kpDocumentSaveOptionsPreviewDialog::resizeEvent (QResizeEvent *e) +{ +#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "kpDocumentSaveOptionsPreviewDialog::resizeEvent()" << endl; +#endif + + QWidget::resizeEvent (e); + + emit resized (); +} + + +kpDocumentSaveOptionsWidget::kpDocumentSaveOptionsWidget ( + const QPixmap &docPixmap, + const kpDocumentSaveOptions &saveOptions, + const kpDocumentMetaInfo &metaInfo, + QWidget *parent, const char *name) + : QWidget (parent, name), + m_visualParent (parent) +{ + init (); + setDocumentSaveOptions (saveOptions); + setDocumentPixmap (docPixmap); + setDocumentMetaInfo (metaInfo); +} + +kpDocumentSaveOptionsWidget::kpDocumentSaveOptionsWidget ( + QWidget *parent, const char *name) + : QWidget (parent, name), + m_visualParent (parent) +{ + init (); +} + +// private +void kpDocumentSaveOptionsWidget::init () +{ + m_documentPixmap = 0; + m_previewDialog = 0; + m_visualParent = 0; + + + m_colorDepthLabel = new QLabel (i18n ("Convert &to:"), this); + m_colorDepthCombo = new KComboBox (this); + + m_colorDepthSpaceWidget = new QWidget (this); + + m_qualityLabel = new QLabel (i18n ("Quali&ty:"), this); + m_qualityInput = new KIntNumInput (this); + // Note that we set min to 1 not 0 since "0 Quality" is a bit misleading + // and 101 quality settings would be weird. So we lose 1 quality setting + // according to QImage::save(). + // TODO: 100 quality is also misleading since that implies perfect quality. + m_qualityInput->setRange (1, 100, 1/*step*/, true/*slider*/); + + m_previewButton = new KPushButton (i18n ("&Preview"), this); + m_previewButton->setToggleButton (true); + + + m_colorDepthLabel->setBuddy (m_colorDepthCombo); + + m_qualityLabel->setBuddy (m_qualityInput); + + + QHBoxLayout *lay = new QHBoxLayout (this, 0/*margin*/, KDialog::spacingHint ()); + + lay->addWidget (m_colorDepthLabel, 0/*stretch*/, Qt::AlignLeft); + lay->addWidget (m_colorDepthCombo, 0/*stretch*/); + + lay->addWidget (m_colorDepthSpaceWidget, 1/*stretch*/); + + lay->addWidget (m_qualityLabel, 0/*stretch*/, Qt::AlignLeft); + lay->addWidget (m_qualityInput, 2/*stretch*/); + + lay->addWidget (m_previewButton, 0/*stretch*/, Qt::AlignRight); + + + connect (m_colorDepthCombo, SIGNAL (activated (int)), + this, SLOT (slotColorDepthSelected ())); + connect (m_colorDepthCombo, SIGNAL (activated (int)), + this, SLOT (updatePreview ())); + + connect (m_qualityInput, SIGNAL (valueChanged (int)), + this, SLOT (updatePreviewDelayed ())); + + connect (m_previewButton, SIGNAL (toggled (bool)), + this, SLOT (showPreview (bool))); + + + m_updatePreviewDelay = 200/*ms*/; + + m_updatePreviewTimer = new QTimer (this); + connect (m_updatePreviewTimer, SIGNAL (timeout ()), + this, SLOT (updatePreview ())); + + m_updatePreviewDialogLastRelativeGeometryTimer = new QTimer (this); + connect (m_updatePreviewDialogLastRelativeGeometryTimer, SIGNAL (timeout ()), + this, SLOT (updatePreviewDialogLastRelativeGeometry ())); + + + setMode (None); + + slotColorDepthSelected (); +} + +kpDocumentSaveOptionsWidget::~kpDocumentSaveOptionsWidget () +{ +#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "kpDocumentSaveOptionsWidget::()" << endl; +#endif + hidePreview (); + + delete m_documentPixmap; +} + + +// public +void kpDocumentSaveOptionsWidget::setVisualParent (QWidget *visualParent) +{ +#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "kpDocumentSaveOptionsWidget::setVisualParent(" + << visualParent << ")" << endl; +#endif + + m_visualParent = visualParent; +} + + +// protected +bool kpDocumentSaveOptionsWidget::mimeTypeHasConfigurableColorDepth () const +{ + return kpDocumentSaveOptions::mimeTypeHasConfigurableColorDepth (mimeType ()); +} + +// protected +bool kpDocumentSaveOptionsWidget::mimeTypeHasConfigurableQuality () const +{ + return kpDocumentSaveOptions::mimeTypeHasConfigurableQuality (mimeType ()); +} + + +// public +QString kpDocumentSaveOptionsWidget::mimeType () const +{ + return m_baseDocumentSaveOptions.mimeType (); +} + +// public slots +void kpDocumentSaveOptionsWidget::setMimeType (const QString &string) +{ +#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "kpDocumentSaveOptionsWidget::setMimeType(" << string + << ") maxColorDepth=" + << kpDocumentSaveOptions::mimeTypeMaximumColorDepth (string) + << endl; +#endif + + const int newMimeTypeMaxDepth = + kpDocumentSaveOptions::mimeTypeMaximumColorDepth (string); + +#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "\toldMimeType=" << mimeType () + << " maxColorDepth=" + << kpDocumentSaveOptions::mimeTypeMaximumColorDepth ( + mimeType ()) + << endl; +#endif + + if (mimeType ().isEmpty () || + kpDocumentSaveOptions::mimeTypeMaximumColorDepth (mimeType ()) != + newMimeTypeMaxDepth) + { + m_colorDepthCombo->clear (); + + m_colorDepthCombo->insertItem (i18n ("Monochrome"), 0); + m_colorDepthCombo->insertItem (i18n ("Monochrome (Dithered)"), 1); + + if (newMimeTypeMaxDepth >= 8) + { + m_colorDepthCombo->insertItem (i18n ("256 Color"), 2); + m_colorDepthCombo->insertItem (i18n ("256 Color (Dithered)"), 3); + } + + if (newMimeTypeMaxDepth >= 24) + { + m_colorDepthCombo->insertItem (i18n ("24-bit Color"), 4); + } + + if (m_colorDepthComboLastSelectedItem >= 0 && + m_colorDepthComboLastSelectedItem < m_colorDepthCombo->count ()) + { + #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "\tsetting colorDepthCombo to " + << m_colorDepthComboLastSelectedItem << endl; + #endif + + m_colorDepthCombo->setCurrentItem (m_colorDepthComboLastSelectedItem); + } + else + { + #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "\tsetting colorDepthCombo to max item since" + << " m_colorDepthComboLastSelectedItem=" + << m_colorDepthComboLastSelectedItem + << " out of range" << endl; + #endif + + m_colorDepthCombo->setCurrentItem (m_colorDepthCombo->count () - 1); + } + } + + + m_baseDocumentSaveOptions.setMimeType (string); + + if (mimeTypeHasConfigurableColorDepth ()) + setMode (ColorDepth); + else if (mimeTypeHasConfigurableQuality ()) + setMode (Quality); + else + setMode (None); + + updatePreview (); +} + + +// public +int kpDocumentSaveOptionsWidget::colorDepth () const +{ + if (mode () & ColorDepth) + { + switch (m_colorDepthCombo->currentItem ()) + { + case 0: + case 1: + return 1; + + case 2: + case 3: + return 8; + + case 4: + return 32; + + default: + return kpDocumentSaveOptions::invalidColorDepth (); + } + } + else + { + return m_baseDocumentSaveOptions.colorDepth (); + } +} + +// public +bool kpDocumentSaveOptionsWidget::dither () const +{ + if (mode () & ColorDepth) + { + return (m_colorDepthCombo->currentItem () == 1 || + m_colorDepthCombo->currentItem () == 3); + } + else + { + return m_baseDocumentSaveOptions.dither (); + } +} + +// protected static +int kpDocumentSaveOptionsWidget::colorDepthComboItemFromColorDepthAndDither ( + int depth, bool dither) +{ + if (depth == 1) + { + if (!dither) + { + return 0; + } + else + { + return 1; + } + } + else if (depth == 8) + { + if (!dither) + { + return 2; + } + else + { + return 3; + } + } + else if (depth == 32) + { + return 4; + } + else + { + return -1; + } +} + +// public slots +void kpDocumentSaveOptionsWidget::setColorDepthDither (int newDepth, bool newDither) +{ +#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "kpDocumentSaveOptionsWidget::setColorDepthDither(" + << "depth=" << newDepth + << ",dither=" << newDither + << ")" << endl; +#endif + + m_baseDocumentSaveOptions.setColorDepth (newDepth); + m_baseDocumentSaveOptions.setDither (newDither); + + + const int comboItem = colorDepthComboItemFromColorDepthAndDither ( + newDepth, newDither); + // TODO: Ignoring when comboItem >= m_colorDepthCombo->count() is wrong. + // This happens if this mimeType has configurable colour depth + // and an incorrect maximum colour depth (less than a QImage of + // this mimeType, opened by kpDocument). + if (comboItem >= 0 && comboItem < m_colorDepthCombo->count ()) + m_colorDepthCombo->setCurrentItem (comboItem); + + + slotColorDepthSelected (); +} + + +// protected slot +void kpDocumentSaveOptionsWidget::slotColorDepthSelected () +{ + if (mode () & ColorDepth) + { + m_colorDepthComboLastSelectedItem = m_colorDepthCombo->currentItem (); + } + else + { + m_colorDepthComboLastSelectedItem = + colorDepthComboItemFromColorDepthAndDither ( + m_baseDocumentSaveOptions.colorDepth (), + m_baseDocumentSaveOptions.dither ()); + } + +#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "kpDocumentSaveOptionsWidget::slotColorDepthSelected()" + << " mode&ColorDepth=" << (mode () & ColorDepth) + << " colorDepthComboLastSelectedItem=" + << m_colorDepthComboLastSelectedItem + << endl; +#endif +} + + +// public +int kpDocumentSaveOptionsWidget::quality () const +{ + if (mode () & Quality) + { + return m_qualityInput->value (); + } + else + { + return m_baseDocumentSaveOptions.quality (); + } +} + +// public +void kpDocumentSaveOptionsWidget::setQuality (int newQuality) +{ +#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "kpDocumentSaveOptionsWidget::setQuality(" + << newQuality << ")" << endl; +#endif + + m_baseDocumentSaveOptions.setQuality (newQuality); + m_qualityInput->setValue (newQuality == -1/*QImage::save() default*/ ? + 75 : + newQuality); +} + + +// public +kpDocumentSaveOptions kpDocumentSaveOptionsWidget::documentSaveOptions () const +{ + return kpDocumentSaveOptions (mimeType (), colorDepth (), dither (), quality ()); +} + +// public +void kpDocumentSaveOptionsWidget::setDocumentSaveOptions ( + const kpDocumentSaveOptions &saveOptions) +{ + setMimeType (saveOptions.mimeType ()); + setColorDepthDither (saveOptions.colorDepth (), saveOptions.dither ()); + setQuality (saveOptions.quality ()); +} + + +// public +void kpDocumentSaveOptionsWidget::setDocumentPixmap (const QPixmap &documentPixmap) +{ + delete m_documentPixmap; + m_documentPixmap = new QPixmap (documentPixmap); + + updatePreview (); +} + +// public +void kpDocumentSaveOptionsWidget::setDocumentMetaInfo ( + const kpDocumentMetaInfo &metaInfo) +{ + m_documentMetaInfo = metaInfo; + + updatePreview (); +} + + +// public +kpDocumentSaveOptionsWidget::Mode kpDocumentSaveOptionsWidget::mode () const +{ + return m_mode; +} + +// public +void kpDocumentSaveOptionsWidget::setMode (Mode mode) +{ + m_mode = mode; + + + // If mode == None, we show still show the Color Depth widgets but disabled + m_colorDepthLabel->setShown (mode != Quality); + m_colorDepthCombo->setShown (mode != Quality); + m_colorDepthSpaceWidget->setShown (mode != Quality); + + m_qualityLabel->setShown (mode == Quality); + m_qualityInput->setShown (mode == Quality); + + + m_colorDepthLabel->setEnabled (mode == ColorDepth); + m_colorDepthCombo->setEnabled (mode == ColorDepth); + + m_qualityLabel->setEnabled (mode == Quality); + m_qualityInput->setEnabled (mode == Quality); + + + // SYNC: HACK: When changing between color depth and quality widgets, + // we change the height of "this", causing the text on the labels + // to move but the first instance of the text doesn't get erased. + // Qt bug. + QTimer::singleShot (0, this, SLOT (repaintLabels ())); +} + +// protected slot +void kpDocumentSaveOptionsWidget::repaintLabels () +{ + if (mode () != Quality) + m_colorDepthLabel->repaint (); + if (mode () == Quality) + m_qualityLabel->repaint (); +} + + +// protected slot +void kpDocumentSaveOptionsWidget::showPreview (bool yes) +{ +#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "kpDocumentSaveOptionsWidget::showPreview(" << yes << ")" + << " m_previewDialog=" << bool (m_previewDialog) + << endl; +#endif + + if (yes == bool (m_previewDialog)) + return; + + if (!m_visualParent) + return; + + if (yes) + { + m_previewDialog = new kpDocumentSaveOptionsPreviewDialog (m_visualParent, "previewSaveDialog"); + updatePreview (); + + connect (m_previewDialog, SIGNAL (finished ()), + this, SLOT (hidePreview ())); + + + KConfigGroupSaver cfgGroupSaver (KGlobal::config (), kpSettingsGroupPreviewSave); + KConfigBase *cfg = cfgGroupSaver.config (); + + if (cfg->hasKey (kpSettingPreviewSaveUpdateDelay)) + { + m_updatePreviewDelay = cfg->readNumEntry (kpSettingPreviewSaveUpdateDelay); + } + else + { + cfg->writeEntry (kpSettingPreviewSaveUpdateDelay, m_updatePreviewDelay); + cfg->sync (); + } + + if (m_updatePreviewDelay < 0) + m_updatePreviewDelay = 0; + #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "\tread cfg preview dialog update delay=" + << m_updatePreviewDelay + << endl; + #endif + + + if (m_previewDialogLastRelativeGeometry.isEmpty ()) + { + #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "\tread cfg preview dialog last rel geometry" << endl; + #endif + KConfigGroupSaver cfgGroupSaver (KGlobal::config (), kpSettingsGroupPreviewSave); + KConfigBase *cfg = cfgGroupSaver.config (); + + m_previewDialogLastRelativeGeometry = cfg->readRectEntry ( + kpSettingPreviewSaveGeometry); + } + + #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "\tpreviewDialogLastRelativeGeometry=" + << m_previewDialogLastRelativeGeometry + << " visualParent->rect()=" << m_visualParent->rect () + << endl; + #endif + + QRect relativeGeometry; + if (!m_previewDialogLastRelativeGeometry.isEmpty () && + m_visualParent->rect ().intersects (m_previewDialogLastRelativeGeometry)) + { + #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "\tok" << endl; + #endif + relativeGeometry = m_previewDialogLastRelativeGeometry; + } + else + { + #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "\t\tinvalid" << endl; + #endif + const int margin = 20; + + relativeGeometry = + QRect (m_visualParent->width () - + m_previewDialog->preferredMinimumSize ().width () - + margin, + margin * 2, // Avoid folder combo + m_previewDialog->preferredMinimumSize ().width (), + m_previewDialog->preferredMinimumSize ().height ()); + } + + + const QRect globalGeometry = + kpWidgetMapper::toGlobal (m_visualParent, + relativeGeometry); + #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "\trelativeGeometry=" << relativeGeometry + << " globalGeometry=" << globalGeometry + << endl; + #endif + + m_previewDialog->resize (globalGeometry.size ()); + m_previewDialog->move (globalGeometry.topLeft ()); + + + m_previewDialog->show (); + + + #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "\tgeometry after show=" + << QRect (m_previewDialog->x (), m_previewDialog->y (), + m_previewDialog->width (), m_previewDialog->height ()) + << endl; + #endif + + updatePreviewDialogLastRelativeGeometry (); + + connect (m_previewDialog, SIGNAL (moved ()), + this, SLOT (updatePreviewDialogLastRelativeGeometry ())); + connect (m_previewDialog, SIGNAL (resized ()), + this, SLOT (updatePreviewDialogLastRelativeGeometry ())); + + m_updatePreviewDialogLastRelativeGeometryTimer->start (200/*ms*/); + } + else + { + m_updatePreviewDialogLastRelativeGeometryTimer->stop (); + + KConfigGroupSaver cfgGroupSaver (KGlobal::config (), kpSettingsGroupPreviewSave); + KConfigBase *cfg = cfgGroupSaver.config (); + + cfg->writeEntry (kpSettingPreviewSaveGeometry, m_previewDialogLastRelativeGeometry); + cfg->sync (); + + #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "\tsaving preview geometry " + << m_previewDialogLastRelativeGeometry + << " (Qt would have us believe " + << kpWidgetMapper::fromGlobal (m_visualParent, + QRect (m_previewDialog->x (), m_previewDialog->y (), + m_previewDialog->width (), m_previewDialog->height ())) + << ")" + << endl; + #endif + + m_previewDialog->deleteLater (); + m_previewDialog = 0; + } +} + +// protected slot +void kpDocumentSaveOptionsWidget::hidePreview () +{ + if (m_previewButton->isOn ()) + m_previewButton->toggle (); +} + + +// protected slot +void kpDocumentSaveOptionsWidget::updatePreviewDelayed () +{ + m_updatePreviewTimer->start (m_updatePreviewDelay, true/*single shot*/); +} + +// protected slot +void kpDocumentSaveOptionsWidget::updatePreview () +{ + if (!m_previewDialog || !m_documentPixmap) + return; + + + m_updatePreviewTimer->stop (); + + + QApplication::setOverrideCursor (Qt::waitCursor); + + QByteArray data; + + QBuffer buffer (data); + buffer.open (IO_WriteOnly); + kpDocument::savePixmapToDevice (*m_documentPixmap, + &buffer, + documentSaveOptions (), + m_documentMetaInfo, + false/*no lossy prompt*/, + this); + buffer.close (); + + + QImage image; + image.loadFromData (data, + KImageIO::typeForMime (mimeType ()).latin1 ()); + + // TODO: merge with kpDocument::getPixmapFromFile() + m_previewDialog->setFilePixmapAndSize ( + kpPixmapFX::convertToPixmapAsLosslessAsPossible (image), + data.size ()); + + QApplication::restoreOverrideCursor (); +} + +// protected slot +void kpDocumentSaveOptionsWidget::updatePreviewDialogLastRelativeGeometry () +{ +#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "kpDocumentSaveOptionsWidget::" + << "updatePreviewDialogLastRelativeGeometry()" + << endl; +#endif + + if (m_previewDialog && m_previewDialog->isVisible ()) + { + m_previewDialogLastRelativeGeometry = + kpWidgetMapper::fromGlobal (m_visualParent, + QRect (m_previewDialog->x (), m_previewDialog->y (), + m_previewDialog->width (), m_previewDialog->height ())); + #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "\tcaching pos = " + << m_previewDialogLastRelativeGeometry + << endl; + #endif + } + else + { + #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET + kdDebug () << "\tnot visible - ignoring geometry" << endl; + #endif + } +} + + +#include diff --git a/kolourpaint/kpdocumentsaveoptionswidget.h b/kolourpaint/kpdocumentsaveoptionswidget.h new file mode 100644 index 00000000..50bd35aa --- /dev/null +++ b/kolourpaint/kpdocumentsaveoptionswidget.h @@ -0,0 +1,200 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_DOCUMENT_SAVE_OPTIONS_WIDGET_H +#define KP_DOCUMENT_SAVE_OPTIONS_WIDGET_H + + +#include + +#include + + +class QPixmap; +class QLabel; + +class kpResizeSignallingLabel; + + +class kpDocumentSaveOptionsPreviewDialog : public QWidget +{ +Q_OBJECT + +public: + kpDocumentSaveOptionsPreviewDialog (QWidget *parent, const char *name = 0); + virtual ~kpDocumentSaveOptionsPreviewDialog (); + + QSize preferredMinimumSize () const; + +protected: + static const QSize s_pixmapLabelMinimumSize; + +signals: + void moved (); + void resized (); + void finished (); + +public slots: + void setFilePixmapAndSize (const QPixmap &filePixmap, int fileSize); + void updatePixmapPreview (); + +protected: + virtual void closeEvent (QCloseEvent *e); + virtual void moveEvent (QMoveEvent *e); + virtual void resizeEvent (QResizeEvent *e); + +protected: + QPixmap *m_filePixmap; + int m_fileSize; + + kpResizeSignallingLabel *m_filePixmapLabel; + QLabel *m_fileSizeLabel; +}; + + +#include +#include + +#include +#include + + +class QLabel; +class QTimer; + +class KComboBox; +class KIntNumInput; +class KPushButton; + + +class kpDocumentSaveOptionsWidget : public QWidget +{ +Q_OBJECT + +public: + kpDocumentSaveOptionsWidget (const QPixmap &docPixmap, + const kpDocumentSaveOptions &saveOptions, + const kpDocumentMetaInfo &metaInfo, + QWidget *parent, const char *name = 0); + kpDocumentSaveOptionsWidget (QWidget *parent, const char *name = 0); +private: + void init (); +public: + virtual ~kpDocumentSaveOptionsWidget (); + + + // is usually the filedialog + void setVisualParent (QWidget *visualParent); + + +protected: + bool mimeTypeHasConfigurableColorDepth () const; + bool mimeTypeHasConfigurableQuality () const; + +public: + QString mimeType () const; +public slots: + void setMimeType (const QString &string); + +public: + int colorDepth () const; + bool dither () const; +protected: + static int colorDepthComboItemFromColorDepthAndDither (int depth, bool dither); +public slots: + void setColorDepthDither (int depth, + bool dither = kpDocumentSaveOptions::initialDither ()); +protected slots: + void slotColorDepthSelected (); + +public: + int quality () const; +public slots: + void setQuality (int newQuality); + +public: + kpDocumentSaveOptions documentSaveOptions () const; +public slots: + void setDocumentSaveOptions (const kpDocumentSaveOptions &saveOptions); + + +public: + void setDocumentPixmap (const QPixmap &documentPixmap); + void setDocumentMetaInfo (const kpDocumentMetaInfo &metaInfo); + + +protected: + enum Mode + { + // (mutually exclusive) + None, ColorDepth, Quality + }; + + Mode mode () const; + void setMode (Mode mode); + +protected slots: + void repaintLabels (); + + +protected slots: + void showPreview (bool yes = true); + void hidePreview (); + void updatePreviewDelayed (); + void updatePreview (); + void updatePreviewDialogLastRelativeGeometry (); + + +protected: + QWidget *m_visualParent; + + Mode m_mode; + + QPixmap *m_documentPixmap; + + kpDocumentSaveOptions m_baseDocumentSaveOptions; + kpDocumentMetaInfo m_documentMetaInfo; + + QLabel *m_colorDepthLabel; + KComboBox *m_colorDepthCombo; + int m_colorDepthComboLastSelectedItem; + QWidget *m_colorDepthSpaceWidget; + + QLabel *m_qualityLabel; + KIntNumInput *m_qualityInput; + + KPushButton *m_previewButton; + kpDocumentSaveOptionsPreviewDialog *m_previewDialog; + QRect m_previewDialogLastRelativeGeometry; + QTimer *m_updatePreviewTimer; + int m_updatePreviewDelay; + QTimer *m_updatePreviewDialogLastRelativeGeometryTimer; +}; + + +#endif // KP_DOCUMENT_SAVE_OPTIONS_WIDGET_H diff --git a/kolourpaint/kpmainwindow.cpp b/kolourpaint/kpmainwindow.cpp new file mode 100644 index 00000000..9af3177b --- /dev/null +++ b/kolourpaint/kpmainwindow.cpp @@ -0,0 +1,1061 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if DEBUG_KP_MAIN_WINDOW + #include +#endif + + +kpMainWindow::kpMainWindow () + : KMainWindow (0/*parent*/, "mainWindow"), + m_isFullyConstructed (false) +{ + init (); + open (KURL (), true/*create an empty doc*/); + + m_isFullyConstructed = true; +} + +kpMainWindow::kpMainWindow (const KURL &url) + : KMainWindow (0/*parent*/, "mainWindow"), + m_isFullyConstructed (false) +{ + init (); + open (url, true/*create an empty doc with the same url if url !exist*/); + + m_isFullyConstructed = true; +} + +kpMainWindow::kpMainWindow (kpDocument *newDoc) + : KMainWindow (0/*parent*/, "mainWindow"), + m_isFullyConstructed (false) +{ + init (); + setDocument (newDoc); + + m_isFullyConstructed = true; +} + + +// public +double kpMainWindow::configColorSimilarity () const +{ + return m_configColorSimilarity; +} + +// public +void kpMainWindow::configSetColorSimilarity (double val) +{ + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral); + KConfigBase *cfg = cfgGroupSaver.config (); + + cfg->writeEntry (kpSettingColorSimilarity, m_configColorSimilarity = val); + cfg->sync (); +} + + +// private +void kpMainWindow::readGeneralSettings () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tkpMainWindow(" << name () << ")::readGeneralSettings()" << endl; +#endif + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral); + KConfigBase *cfg = cfgGroupSaver.config (); + + m_configFirstTime = cfg->readBoolEntry (kpSettingFirstTime, true); + m_configShowGrid = cfg->readBoolEntry (kpSettingShowGrid, false); + m_configShowPath = cfg->readBoolEntry (kpSettingShowPath, false); + m_configColorSimilarity = cfg->readDoubleNumEntry (kpSettingColorSimilarity, 0); + d->m_moreEffectsDialogLastEffect = cfg->readNumEntry (kpSettingMoreEffectsLastEffect); + d->m_resizeScaleDialogLastKeepAspect = cfg->readBoolEntry (kpSettingResizeScaleLastKeepAspect, false); + + +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tGeneral Settings: firstTime=" << m_configFirstTime + << " showGrid=" << m_configShowGrid + << " showPath=" << m_configShowPath + << " colorSimilarity=" << m_configColorSimilarity + << " moreEffectsDialogLastEffect=" << d->m_moreEffectsDialogLastEffect + << " resizeScaleDialogLastKeepAspect=" << d->m_resizeScaleDialogLastKeepAspect + << endl; +#endif +} + +// private +void kpMainWindow::readThumbnailSettings () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tkpMainWindow(" << name () << ")::readThumbnailSettings()" << endl; +#endif + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupThumbnail); + KConfigBase *cfg = cfgGroupSaver.config (); + + m_configThumbnailShown = cfg->readBoolEntry (kpSettingThumbnailShown, false); + m_configThumbnailGeometry = cfg->readRectEntry (kpSettingThumbnailGeometry); + m_configZoomedThumbnail = cfg->readBoolEntry (kpSettingThumbnailZoomed, true); + d->m_configThumbnailShowRectangle = cfg->readBoolEntry (kpSettingThumbnailShowRectangle, true); + +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tThumbnail Settings: shown=" << m_configThumbnailShown + << " geometry=" << m_configThumbnailGeometry + << " zoomed=" << m_configZoomedThumbnail + << " showRectangle=" << d->m_configThumbnailShowRectangle + << endl; +#endif +} + +// private +void kpMainWindow::init () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow(" << name () << ")::init()" << endl; + QTime totalTime; totalTime.start (); + QTime time; time.start (); +#endif + + d = new kpMainWindowPrivate; + + m_scrollView = 0; + m_mainView = 0; + m_thumbnail = 0; + m_thumbnailView = 0; + m_document = 0; + m_viewManager = 0; + m_colorToolBar = 0; + m_toolToolBar = 0; + m_commandHistory = 0; + m_statusBarCreated = false; + m_settingSelectionTransparency = 0; + m_settingTextStyle = 0; + + m_docResizeToBeCompleted = false; + + + // + // set mainwindow properties + // + + setMinimumSize (320, 260); + setAcceptDrops (true); +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tTIME: little init = " << time.restart () << "msec" << endl; +#endif + + + // + // read config + // + + // KConfig::readEntry() does not actually reread from disk, hence doesn't + // realise what other processes have done e.g. Settings / Show Path + kapp->config ()->reparseConfiguration (); +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tTIME: reparseConfig = " << time.restart () << "msec" << endl; +#endif + + readGeneralSettings (); +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tTIME: readGeneralSettings = " << time.restart () << "msec" << endl; +#endif + + readThumbnailSettings (); +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tTIME: readThumbnailSettings = " << time.restart () << "msec" << endl; +#endif + + + // + // create GUI + // + + setupActions (); +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tTIME: setupActions = " << time.restart () << "msec" << endl; +#endif + + createStatusBar (); +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tTIME: createStatusBar = " << time.restart () << "msec" << endl; +#endif + + createGUI (); +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tTIME: createGUI = " << time.restart () << "msec" << endl; +#endif + + + // + // create more GUI + // + + m_colorToolBar = new kpColorToolBar (i18n ("Color Box"), this, "Color Box"); +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tTIME: new kpColorToolBar = " << time.restart () << "msec" << endl; +#endif + + createToolBox (); +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tTIME: createToolBox = " << time.restart () << "msec" << endl; +#endif + + m_scrollView = new kpViewScrollableContainer (this, "scrollView"); + connect (m_scrollView, SIGNAL (beganDocResize ()), + this, SLOT (slotBeganDocResize ())); + connect (m_scrollView, SIGNAL (continuedDocResize (const QSize &)), + this, SLOT (slotContinuedDocResize (const QSize &))); + connect (m_scrollView, SIGNAL (cancelledDocResize ()), + this, SLOT (slotCancelledDocResize ())); + connect (m_scrollView, SIGNAL (endedDocResize (const QSize &)), + this, SLOT (slotEndedDocResize (const QSize &))); + + connect (m_scrollView, SIGNAL (statusMessageChanged (const QString &)), + this, SLOT (slotDocResizeMessageChanged (const QString &))); + + connect (m_scrollView, SIGNAL (contentsMoving (int, int)), + this, SLOT (slotScrollViewAboutToScroll ())); + setCentralWidget (m_scrollView); + m_scrollView->show (); +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tTIME: m_scrollView = " << time.restart () << "msec" << endl; +#endif + + + // + // set initial pos/size of GUI + // + + setAutoSaveSettings (); + + // Put our non-XMLGUI toolbars in a sane place, the first time around + // (have to do this _after_ setAutoSaveSettings as that applies default + // (i.e. random) settings to the toolbars) + if (m_configFirstTime) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tfirstTime: positioning toolbars" << endl; + #endif + + m_toolToolBar->setBarPos (KToolBar::Left); + m_colorToolBar->setBarPos (KToolBar::Bottom); + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral); + KConfigBase *cfg = cfgGroupSaver.config (); + + cfg->writeEntry (kpSettingFirstTime, m_configFirstTime = false); + cfg->sync (); + } + +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tall done in " << totalTime.elapsed () << "msec" << endl; +#endif +} + + +// private virtual [base KMainWindow] +void kpMainWindow::readProperties (KConfig *cfg) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow<" << this << ">::readProperties()" << endl; +#endif + + // No document at all? + if (!cfg->hasKey (kpSessionSettingDocumentUrl)) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tno url - no document" << endl; + #endif + setDocument (0); + } + // Have a document. + else + { + const KURL url (cfg->readEntry (kpSessionSettingDocumentUrl)); + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\turl=" << url << endl; + #endif + + const QSize notFromURLDocSize = + cfg->readSizeEntry (kpSessionSettingNotFromUrlDocumentSize); + + // Is from URL? + if (notFromURLDocSize.isEmpty ()) + { + // If this fails, the empty document that kpMainWindow::kpMainWindow() + // created is left untouched. + openInternal (url, defaultDocSize (), + false/*show error message if url !exist*/); + } + // Not from URL? + else + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tnot from url; doc size=" << notFromURLDocSize << endl; + #endif + // Either we have an empty URL or we have a "kolourpaint doesnotexist.png" + // URL. Regarding the latter case, if a file now actually exists at that + // URL, we do open it - ignoring notFromURLDocSize - to avoid putting + // the user in a situation where he might accidentally overwrite an + // existing file. + openInternal (url, notFromURLDocSize, + true/*create an empty doc with the same url if url !exist*/); + } + } + +} + +// private virtual [base KMainWindow] +// WARNING: KMainWindow API Doc says "No user interaction is allowed +// in this function!" +void kpMainWindow::saveProperties (KConfig *cfg) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow<" << this << ">::saveProperties()" << endl; +#endif + + // No document at all? + if (!m_document) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tno url - no document" << endl; + #endif + } + // Have a document. + else + { + // Save URL in all cases: + // + // a) m_document->isFromURL() + // b) !m_document->isFromURL() [save size in this case] + // i) No URL + // ii) URL (from "kolourpaint doesnotexist.png") + + const KURL url = m_document->url (); + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\turl=" << url << endl; + #endif + cfg->writeEntry (kpSessionSettingDocumentUrl, url.url ()); + + // Not from URL e.g. "kolourpaint doesnotexist.png"? + // + // Note that "kolourpaint doesexist.png" is considered to be from + // a URL even if it was deleted in the background (hence the + // "false" arg to isFromURL()). This is because the user expects + // it to be from a URL, so when we session restore, we pop up a + // "cannot find file" dialog, instead of silently creating a new, + // blank document. + if (!m_document->isFromURL (false/*don't bother checking exists*/)) + { + // If we don't have a URL either: + // + // a) it was not modified - so we can use either width() or + // constructorWidth() (they'll be equal). + // b) the changes were discarded so we use the initial width, + // constructorWidth(). + // + // Similarly for height() and constructorHeight(). + const QSize docSize (m_document->constructorWidth (), + m_document->constructorHeight ()); + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tnot from url; doc size=" << docSize << endl; + #endif + cfg->writeEntry (kpSessionSettingNotFromUrlDocumentSize, docSize); + } + + + // Local session save i.e. queryClose() was not called beforehand + // (see QApplication::saveState())? + #if 0 + if (m_document->isModified ()) + { + // TODO: Implement by saving the current image to a persistent file. + // We do this instead of saving/mutating the backing image file + // as no one expects a file save on a session save without a + // "do you want to save" dialog first. + // + // I don't think any KDE application implements local session saving. + // + // --- The below code does not compile but shows you want to do --- + + // Create unique name for the document in this main window. + const KURL tempURL = homeDir + + "kolourpaint session " + sessionID + + mainWindowPtrToString + ".png"; + // TODO: Use lossless PNG saving options. + kpDocumentSaveOptions pngSaveOptions; + + if (kpDocument::savePixmapToFile (m_document->pixmapWithSelection (), + tempURL, + pngSaveOptions, *m_document->metaInfo (), + false/*no overwrite prompt*/, + false/*no lossy prompt*/, + this)) + { + // readProperties() will still open kpSessionSettingDocumentUrl + // (as that's the expected URL) and will then add commands to: + // + // 1. Resize the document to the size of image at + // kpSessionSettingDocumentUnsavedContentsUrl, if the sizes + // differ. + // 2. Paste the kpSessionSettingDocumentUnsavedContentsUrl image + // (setting the main window's selection mode to opaque beforehand). + // + // It will then delete the file at + // kpSessionSettingDocumentUnsavedContentsUrl. + cfg->writeEntry (kpSessionSettingDocumentUnsavedContentsUrl, + tempURL.url ()); + } + else + { + // Not much we can do - we aren't allowed to throw up a dialog. + } + } + #endif + } +} + + +kpMainWindow::~kpMainWindow () +{ + m_isFullyConstructed = false; + + // delete document & views + setDocument (0); + + delete m_commandHistory; m_commandHistory = 0; + delete m_scrollView; m_scrollView = 0; + + delete d; d = 0; +} + + +// public +kpDocument *kpMainWindow::document () const +{ + return m_document; +} + +// public +kpViewManager *kpMainWindow::viewManager () const +{ + return m_viewManager; +} + +// public +kpColorToolBar *kpMainWindow::colorToolBar () const +{ + return m_colorToolBar; +} + +// public +kpToolToolBar *kpMainWindow::toolToolBar () const +{ + return m_toolToolBar; +} + +// public +kpCommandHistory *kpMainWindow::commandHistory () const +{ + return m_commandHistory; +} + + +// private +void kpMainWindow::setupActions () +{ + setupFileMenuActions (); + setupEditMenuActions (); + setupViewMenuActions (); + setupImageMenuActions (); + setupSettingsMenuActions (); + setupHelpMenuActions (); + + setupTextToolBarActions (); + setupToolActions (); +} + +// private +void kpMainWindow::enableDocumentActions (bool enable) +{ + enableFileMenuDocumentActions (enable); + enableEditMenuDocumentActions (enable); + enableViewMenuDocumentActions (enable); + enableImageMenuDocumentActions (enable); + enableSettingsMenuDocumentActions (enable); + enableHelpMenuDocumentActions (enable); +} + + +// public +bool kpMainWindow::actionsSingleKeyTriggersEnabled () const +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::actionsSingleKeyTriggersEnabled()" << endl; + QTime timer; timer.start (); +#endif + + if (m_toolToolBar) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\ttime=" << timer.restart () << endl; + #endif + return m_toolToolBar->toolsSingleKeyTriggersEnabled (); + } + + return (m_actionPrevToolOptionGroup1->singleKeyTriggersEnabled () || + m_actionNextToolOptionGroup1->singleKeyTriggersEnabled () || + m_actionPrevToolOptionGroup2->singleKeyTriggersEnabled () || + m_actionNextToolOptionGroup2->singleKeyTriggersEnabled ()); +} + +// public +void kpMainWindow::enableActionsSingleKeyTriggers (bool enable) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::enableActionsSingleKeyTriggers(" + << enable << ")" << endl; + QTime timer; timer.start (); +#endif + + if (m_toolToolBar) + m_toolToolBar->enableToolsSingleKeyTriggers (enable); + + m_actionPrevToolOptionGroup1->enableSingleKeyTriggers (enable); + m_actionNextToolOptionGroup1->enableSingleKeyTriggers (enable); + m_actionPrevToolOptionGroup2->enableSingleKeyTriggers (enable); + m_actionNextToolOptionGroup2->enableSingleKeyTriggers (enable); + +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\ttime=" << timer.restart () << endl; +#endif +} + + +// private +void kpMainWindow::setDocument (kpDocument *newDoc) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::setDocument (" << newDoc << ")" << endl; +#endif + + // is it a close operation? + if (!newDoc) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tdisabling actions" << endl; + #endif + + // sync with the bit marked "sync" below + + if (m_colorToolBar) + m_colorToolBar->setEnabled (false); + else + { + kdError () << "kpMainWindow::setDocument() without colorToolBar" + << endl; + } + + enableTextToolBarActions (false); + } + + // Always disable the tools. + // If we decide to open a new document/mainView we want + // kpTool::begin() to be called again e.g. in case it sets the cursor. + // kpViewManager won't do this because we nuke it to avoid stale state. + enableToolsDocumentActions (false); + + if (!newDoc) + { + enableDocumentActions (false); + } + +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tdestroying views" << endl; +#endif + + delete m_mainView; m_mainView = 0; + slotDestroyThumbnail (); + +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tdestroying viewManager" << endl; +#endif + + // viewManager will die and so will the selection + m_actionCopy->setEnabled (false); + m_actionCut->setEnabled (false); + m_actionDelete->setEnabled (false); + m_actionDeselect->setEnabled (false); + m_actionCopyToFile->setEnabled (false); + + delete m_viewManager; m_viewManager = 0; + +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tdestroying document" << endl; + kdDebug () << "\t\tm_document=" << m_document << endl; +#endif + // destroy current document + delete m_document; + m_document = newDoc; + + + if (!m_lastCopyToURL.isEmpty ()) + m_lastCopyToURL.setFileName (QString::null); + m_copyToFirstTime = true; + + if (!m_lastExportURL.isEmpty ()) + m_lastExportURL.setFileName (QString::null); + m_exportFirstTime = true; + + + // not a close operation? + if (m_document) + { + if (m_document->mainWindow () != this) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tchanging doc's mainWindow from " + << m_document->mainWindow () + << " to this=" + << this + << endl; + #endif + m_document->setMainWindow (this); + } + + #if DEBUG_KP_MAIN_WINDOW + kdDebug () <<"\tcreating viewManager" << endl; + #endif + m_viewManager = new kpViewManager (this); + + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tcreating views" << endl; + #endif + m_mainView = new kpZoomedView (m_document, m_toolToolBar, m_viewManager, + 0/*buddyView*/, + m_scrollView, + m_scrollView->viewport (), "mainView"); + if (m_scrollView) + { + m_scrollView->addChild (m_mainView); + } + else + kdError () << "kpMainWindow::setDocument() without scrollView" << endl; + m_viewManager->registerView (m_mainView); + m_mainView->show (); + + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\thooking up document signals" << endl; + #endif + + // Copy/Cut/Deselect/Delete + connect (m_document, SIGNAL (selectionEnabled (bool)), + m_actionCut, SLOT (setEnabled (bool))); + connect (m_document, SIGNAL (selectionEnabled (bool)), + m_actionCopy, SLOT (setEnabled (bool))); + connect (m_document, SIGNAL (selectionEnabled (bool)), + m_actionDelete, SLOT (setEnabled (bool))); + connect (m_document, SIGNAL (selectionEnabled (bool)), + m_actionDeselect, SLOT (setEnabled (bool))); + connect (m_document, SIGNAL (selectionEnabled (bool)), + m_actionCopyToFile, SLOT (setEnabled (bool))); + + // this code won't actually enable any actions at this stage + // (fresh document) but better safe than sorry + m_actionCopy->setEnabled (m_document->selection ()); + m_actionCut->setEnabled (m_document->selection ()); + m_actionDeselect->setEnabled (m_document->selection ()); + m_actionDelete->setEnabled (m_document->selection ()); + m_actionCopyToFile->setEnabled (m_document->selection ()); + + connect (m_document, SIGNAL (selectionEnabled (bool)), + this, SLOT (slotImageMenuUpdateDueToSelection ())); + connect (m_document, SIGNAL (selectionIsTextChanged (bool)), + this, SLOT (slotImageMenuUpdateDueToSelection ())); + + // Status bar + connect (m_document, SIGNAL (documentOpened ()), + this, SLOT (recalculateStatusBar ())); + + connect (m_document, SIGNAL (sizeChanged (const QSize &)), + this, SLOT (setStatusBarDocSize (const QSize &))); + + // Caption (url, modified) + connect (m_document, SIGNAL (documentModified ()), + this, SLOT (slotUpdateCaption ())); + connect (m_document, SIGNAL (documentOpened ()), + this, SLOT (slotUpdateCaption ())); + connect (m_document, SIGNAL (documentSaved ()), + this, SLOT (slotUpdateCaption ())); + + // File/Reload action only available with non-empty URL + connect (m_document, SIGNAL (documentSaved ()), + this, SLOT (slotEnableReload ())); + + connect (m_document, SIGNAL (documentSaved ()), + this, SLOT (slotEnableSettingsShowPath ())); + + // Command history + if (m_commandHistory) + { + connect (m_commandHistory, SIGNAL (documentRestored ()), + this, SLOT (slotDocumentRestored ())); // caption "!modified" + connect (m_document, SIGNAL (documentSaved ()), + m_commandHistory, SLOT (documentSaved ())); + } + else + { + kdError () << "kpMainWindow::setDocument() without commandHistory" + << endl; + } + + // Sync document -> views + connect (m_document, SIGNAL (contentsChanged (const QRect &)), + m_viewManager, SLOT (updateViews (const QRect &))); + connect (m_document, SIGNAL (sizeChanged (int, int)), + m_viewManager, SLOT (adjustViewsToEnvironment ())); + + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tenabling actions" << endl; + #endif + + // sync with the bit marked "sync" above + + if (m_colorToolBar) + m_colorToolBar->setEnabled (true); + else + { + kdError () << "kpMainWindow::setDocument() without colorToolBar" + << endl; + } + + + // Hide the text toolbar - it will be shown by kpToolText::begin() + enableTextToolBarActions (false); + + enableToolsDocumentActions (true); + + enableDocumentActions (true); + + // TODO: The thumbnail auto zoom doesn't work because it thinks its + // width == 1 when !this->isShown(). So for consistency, + // never create the thumbnail. + #if 0 + if (m_configThumbnailShown) + { + if (isShown ()) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tcreating thumbnail immediately" << endl; + #endif + slotCreateThumbnail (); + } + // this' geometry is weird ATM + else + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tcreating thumbnail LATER" << endl; + #endif + QTimer::singleShot (0, this, SLOT (slotCreateThumbnail ())); + } + } + #endif + } + +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tupdating mainWindow elements" << endl; +#endif + + slotImageMenuUpdateDueToSelection (); + recalculateStatusBar (); + slotUpdateCaption (); // Untitled to start with + slotEnableReload (); + slotEnableSettingsShowPath (); + + if (m_commandHistory) + m_commandHistory->clear (); + +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tdocument and views ready to go!" << endl; +#endif +} + + +// private virtual [base KMainWindow] +bool kpMainWindow::queryClose () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::queryClose()" << endl; +#endif + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + if (!m_document || !m_document->isModified ()) + return true; // ok to close current doc + + int result = KMessageBox::warningYesNoCancel (this, + i18n ("The document \"%1\" has been modified.\n" + "Do you want to save it?") + .arg (m_document->prettyFilename ()), + QString::null/*caption*/, + KStdGuiItem::save (), KStdGuiItem::discard ()); + + switch (result) + { + case KMessageBox::Yes: + return slotSave (); // close only if save succeeds + case KMessageBox::No: + return true; // close without saving + default: + return false; // don't close current doc + } +} + + +// private virtual [base QWidget] +void kpMainWindow::dragEnterEvent (QDragEnterEvent *e) +{ + e->accept (kpSelectionDrag::canDecode (e) || + KURLDrag::canDecode (e) || + QTextDrag::canDecode (e)); +} + +// private virtual [base QWidget] +void kpMainWindow::dropEvent (QDropEvent *e) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::dropEvent" << e->pos () << endl; +#endif + + kpSelection sel; + KURL::List urls; + QString text; + + if (kpSelectionDrag::decode (e, sel/*ref*/, pasteWarnAboutLossInfo ())) + { + sel.setTransparency (selectionTransparency ()); + // TODO: drop at point like with QTextDrag below? + paste (sel); + } + else if (KURLDrag::decode (e, urls/*ref*/)) + { + for (KURL::List::ConstIterator it = urls.begin (); it != urls.end (); it++) + { + open (*it); + } + } + else if (QTextDrag::decode (e, text/*ref*/)) + { + QPoint selTopLeft = KP_INVALID_POINT; + const QPoint globalPos = QWidget::mapToGlobal (e->pos ()); + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tpos toGlobal=" << globalPos << endl; + #endif + + kpView *view = 0; + + if (m_viewManager) + { + view = m_viewManager->viewUnderCursor (); + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tviewUnderCursor=" << view << endl; + #endif + if (!view) + { + // HACK: see kpViewManager::setViewUnderCursor() to see why + // it's not reliable + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tattempting to discover view" << endl; + + if (m_mainView && m_scrollView) + { + kdDebug () << "\t\t\tmainView->globalRect=" + << kpWidgetMapper::toGlobal (m_mainView, m_mainView->rect ()) + << " scrollView->globalRect=" + << kpWidgetMapper::toGlobal (m_scrollView, + QRect (0, 0, + m_scrollView->visibleWidth (), + m_scrollView->visibleHeight ())) + << endl; + } + #endif + if (m_thumbnailView && + kpWidgetMapper::toGlobal (m_thumbnailView, m_thumbnailView->rect ()) + .contains (globalPos)) + { + // TODO: Code will never get executed. + // Thumbnail doesn't accept drops. + view = m_thumbnailView; + } + else if (m_mainView && + kpWidgetMapper::toGlobal (m_mainView, m_mainView->rect ()) + .contains (globalPos) && + m_scrollView && + kpWidgetMapper::toGlobal (m_scrollView, + QRect (0, 0, + m_scrollView->visibleWidth (), + m_scrollView->visibleHeight ())) + .contains (globalPos)) + { + view = m_mainView; + } + } + } + + if (view) + { + const QPoint viewPos = view->mapFromGlobal (globalPos); + const QPoint docPoint = view->transformViewToDoc (viewPos); + + // viewUnderCursor() is hacky and can return a view when we aren't + // over one thanks to drags. + if (m_document && m_document->rect ().contains (docPoint)) + { + selTopLeft = docPoint; + + // TODO: In terms of doc pixels, would be inconsistent behaviour + // based on zoomLevel of view. + // selTopLeft -= QPoint (-view->selectionResizeHandleAtomicSize (), + // -view->selectionResizeHandleAtomicSize ()); + } + } + + pasteText (text, true/*force new text selection*/, selTopLeft); + } +} + + +// private slot +void kpMainWindow::slotScrollViewAboutToScroll () +{ +#if DEBUG_KP_MAIN_WINDOW && 0 + kdDebug () << "kpMainWindow::slotScrollViewAboutToScroll() tool=" + << tool () << " viewManager=" << viewManager () << endl; + if (viewManager ()) + { + kdDebug () << "\tfastUpdates=" << viewManager ()->fastUpdates () + << " queueUpdates=" << viewManager ()->queueUpdates () + << endl; + } + else + { + // We're getting a late signal from the scrollview (thanks to + // a timer inside the QScrollView). By now, setDocument() has + // already killed the document(), tool() and viewManager(). + } +#endif + + QTimer::singleShot (0, this, SLOT (slotScrollViewAfterScroll ())); +} + +// private slot +void kpMainWindow::slotScrollViewAfterScroll () +{ +#if DEBUG_KP_MAIN_WINDOW && 0 + kdDebug () << "kpMainWindow::slotScrollViewAfterScroll() tool=" + << tool () << endl; +#endif + + if (tool ()) + { + tool ()->somethingBelowTheCursorChanged (); + } +} + + +// private virtual [base QWidget] +void kpMainWindow::moveEvent (QMoveEvent * /*e*/) +{ + if (m_thumbnail) + { + // Disabled because it lags too far behind the mainWindow + // m_thumbnail->move (m_thumbnail->pos () + (e->pos () - e->oldPos ())); + + notifyThumbnailGeometryChanged (); + } +} + + +// private slot +void kpMainWindow::slotUpdateCaption () +{ + if (m_document) + { + setCaption (m_configShowPath ? m_document->prettyURL () + : m_document->prettyFilename (), + m_document->isModified ()); + } + else + { + setCaption (QString::null, false); + } +} + +// private slot +void kpMainWindow::slotDocumentRestored () +{ + if (m_document) + m_document->setModified (false); + slotUpdateCaption (); +} + + +#include diff --git a/kolourpaint/kpmainwindow.h b/kolourpaint/kpmainwindow.h new file mode 100644 index 00000000..f5514848 --- /dev/null +++ b/kolourpaint/kpmainwindow.h @@ -0,0 +1,739 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_MAIN_WINDOW_H +#define KP_MAIN_WINDOW_H + + +#define DEBUG_KP_MAIN_WINDOW 0 + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + + +class QPainter; +class QPoint; +class QPopupMenu; +class QRect; +class QSize; +class QStringList; + +class KAction; +class KFontAction; +class KFontSizeAction; +class KSelectAction; +class KToggleAction; +class KToolBar; +class KPrinter; +class KRecentFilesAction; +class KScanDialog; +class KToggleFullScreenAction; + +class kpColor; +class kpColorToolBar; +class kpCommand; +class kpCommandHistory; +class kpDocument; +class kpDocumentMetaInfo; +class kpDocumentSaveOptions; +class kpViewManager; +class kpViewScrollableContainer; +class kpSelection; +class kpSelectionTransparency; +class kpSingleKeyTriggersAction; +class kpSqueezedTextLabel; +class kpTextStyle; +class kpThumbnail; +class kpThumbnailView; +class kpTool; +class kpToolText; +class kpToolToolBar; +class kpZoomedView; + + +class kpMainWindow : public KMainWindow +{ +Q_OBJECT + +public: + // Opens a new window with a blank document. + kpMainWindow (); + + // Opens a new window with the document specified by + // or creates a blank document if could not be opened. + kpMainWindow (const KURL &url); + + // Opens a new window with the document + // ( can be 0 although this would result in a new + // window without a document at all). + kpMainWindow (kpDocument *newDoc); + +public: + double configColorSimilarity () const; + void configSetColorSimilarity (double val); + +private: + bool m_configFirstTime; + bool m_configShowGrid; + bool m_configShowPath; + double m_configColorSimilarity; + + bool m_configThumbnailShown; + QRect m_configThumbnailGeometry; + bool m_configZoomedThumbnail; + + void readGeneralSettings (); + void readThumbnailSettings (); + void init (); + + // (only called for restoring a previous session e.g. starting KDE with + // a previously saved session; it's not called on normal KolourPaint + // startup) + virtual void readProperties (KConfig *cfg); + // (only called for saving the current session e.g. logging out of KDE + // with the KolourPaint window open; it's not called on normal KolourPaint + // exit) + virtual void saveProperties (KConfig *cfg); + +public: + ~kpMainWindow (); + +private: + bool m_isFullyConstructed; + +public: + kpDocument *document () const; + kpViewManager *viewManager () const; + kpColorToolBar *colorToolBar () const; + kpToolToolBar *toolToolBar () const; + kpCommandHistory *commandHistory () const; + +private: + kpViewScrollableContainer *m_scrollView; + kpZoomedView *m_mainView; + kpThumbnail *m_thumbnail; + kpThumbnailView *m_thumbnailView; + kpDocument *m_document; + kpViewManager *m_viewManager; + kpColorToolBar *m_colorToolBar; + kpToolToolBar *m_toolToolBar; + kpCommandHistory *m_commandHistory; + +private: + void setupActions (); + void enableDocumentActions (bool enable = true); + +public: + bool actionsSingleKeyTriggersEnabled () const; + void enableActionsSingleKeyTriggers (bool enable = true); + +private: + void setDocument (kpDocument *newDoc); + + virtual bool queryClose (); + + virtual void dragEnterEvent (QDragEnterEvent *e); + virtual void dropEvent (QDropEvent *e); + +private slots: + void slotScrollViewAboutToScroll (); + void slotScrollViewAfterScroll (); + +private: + virtual void moveEvent (QMoveEvent *e); + +private slots: + void slotUpdateCaption (); + void slotDocumentRestored (); + + + /* + * Tools + */ + +private: + void setupToolActions (); + void createToolBox (); + void enableToolsDocumentActions (bool enable = true); + +private slots: + void updateToolOptionPrevNextActionsEnabled (); + +private: + kpTool *m_toolAirSpray, *m_toolBrush, *m_toolColorPicker, + *m_toolColorWasher, *m_toolCurve, *m_toolEllipse, + *m_toolEllipticalSelection, *m_toolEraser, + *m_toolFloodFill, *m_toolFreeFormSelection, + *m_toolLine, *m_toolPen, *m_toolPolygon, + *m_toolPolyline, *m_toolRectangle, *m_toolRectSelection, + *m_toolRoundedRectangle; + kpToolText *m_toolText; + + QPtrList m_tools; + int m_lastToolNumber; + + bool m_toolActionsEnabled; + kpSingleKeyTriggersAction *m_actionPrevToolOptionGroup1, + *m_actionNextToolOptionGroup1, + *m_actionPrevToolOptionGroup2, + *m_actionNextToolOptionGroup2; + + int m_settingSelectionTransparency; + + int m_docResizeWidth, m_docResizeHeight; + bool m_docResizeToBeCompleted; + +public: + kpTool *tool () const; + bool toolHasBegunShape () const; + bool toolIsASelectionTool (bool includingTextTool = true) const; + bool toolIsTextTool () const; + + kpSelectionTransparency selectionTransparency () const; + // The drawing background color is set to .transparentColor() + // if the is in Transparent mode or if + // is true (not the default). [x] + // + // If is in Opaque mode and is false, + // the background color is not changed because: + // + // 1. It is ignored by the selection in Opaque mode anyway. + // 2. This avoids irritating the user with an unnecessary background + // color change. + // + // The only case where you should set to true is in + // kpToolSelectionTransparencyCommand to ensure that the state + // is identical to when the command was constructed. + // Later: I don't think setting it to true is ever necessary since: + // + // 1. The background color only counts in Transparent mode. + // + // 2. Any kpToolSelectionTransparencyCommand that switches to + // Transparent mode will automatically set the background + // color due to the first part of [x] anyway. + // + // The other fields of are copied into the main window + // as expected. + void setSelectionTransparency (const kpSelectionTransparency &transparency, + bool forceColorChange = false); + int settingSelectionTransparency () const; + +private slots: + void slotToolSelected (kpTool *tool); + +private: + void readLastTool (); + int toolNumber () const; + void saveLastTool (); + +private: + bool maybeDragScrollingMainView () const; +private slots: + bool slotDragScroll (const QPoint &docPoint, + const QPoint &docLastPoint, + int zoomLevel, + bool *didSomething); + bool slotEndDragScroll (); + +private slots: + void slotBeganDocResize (); + void slotContinuedDocResize (const QSize &size); + void slotCancelledDocResize (); + void slotEndedDocResize (const QSize &size); + + void slotDocResizeMessageChanged (const QString &string); + +private slots: + void slotActionPrevToolOptionGroup1 (); + void slotActionNextToolOptionGroup1 (); + void slotActionPrevToolOptionGroup2 (); + void slotActionNextToolOptionGroup2 (); + +public slots: + void slotToolAirSpray (); + void slotToolBrush (); + void slotToolColorPicker (); + void slotToolColorWasher (); + void slotToolCurve (); + void slotToolEllipse (); + void slotToolEllipticalSelection (); + void slotToolEraser (); + void slotToolFloodFill (); + void slotToolFreeFormSelection (); + void slotToolLine (); + void slotToolPen (); + void slotToolPolygon (); + void slotToolPolyline (); + void slotToolRectangle (); + void slotToolRectSelection (); + void slotToolRoundedRectangle (); + void slotToolText (); + + + /* + * File Menu + */ + +private: + void setupFileMenuActions (); + void enableFileMenuDocumentActions (bool enable = true); + + KAction *m_actionNew, *m_actionOpen; + KRecentFilesAction *m_actionOpenRecent; + KAction *m_actionScan, *m_actionSave, *m_actionSaveAs, *m_actionExport, + *m_actionReload, + *m_actionPrint, *m_actionPrintPreview, + *m_actionMail, + *m_actionSetAsWallpaperTiled, *m_actionSetAsWallpaperCentered, + *m_actionClose, *m_actionQuit; + + KScanDialog *m_scanDialog; + + KURL m_lastExportURL; + kpDocumentSaveOptions m_lastExportSaveOptions; + bool m_exportFirstTime; + +private: + void addRecentURL (const KURL &url); + +private slots: + void slotNew (); + +private: + QSize defaultDocSize () const; + void saveDefaultDocSize (const QSize &size); + +private: + bool shouldOpenInNewWindow () const; + void setDocumentChoosingWindow (kpDocument *doc); + +private: + kpDocument *openInternal (const KURL &url, + const QSize &fallbackDocSize, + bool newDocSameNameIfNotExist); + // Same as above except that it: + // + // 1. Assumes a default fallback document size. + // 2. If the URL is successfully opened (with the special exception of + // the "kolourpaint doesnotexist.png" case), it is bubbled up to the + // top in the Recent Files Action. + // + // As a result of this behavior, this should only be called in response + // to a user open request e.g. File / Open or "kolourpaint doesexist.png". + // It should not be used for session restore - in that case, it does not + // make sense to bubble the Recent Files list. + bool open (const KURL &url, bool newDocSameNameIfNotExist = false); + + KURL::List askForOpenURLs (const QString &caption, + const QString &startURL, + bool allowMultipleURLs = true); + +private slots: + void slotOpen (); + void slotOpenRecent (const KURL &url); + + void slotScan (); + void slotScanned (const QImage &image, int); + + bool save (bool localOnly = false); + bool slotSave (); + +private: + KURL askForSaveURL (const QString &caption, + const QString &startURL, + const QPixmap &pixmapToBeSaved, + const kpDocumentSaveOptions &startSaveOptions, + const kpDocumentMetaInfo &docMetaInfo, + const QString &forcedSaveOptionsGroup, + bool localOnly, + kpDocumentSaveOptions *chosenSaveOptions, + bool isSavingForFirstTime, + bool *allowOverwritePrompt, + bool *allowLossyPrompt); + +private slots: + bool saveAs (bool localOnly = false); + bool slotSaveAs (); + + bool slotExport (); + + void slotEnableReload (); + bool slotReload (); + +private: + void sendFilenameToPrinter (KPrinter *printer); + void sendPixmapToPrinter (KPrinter *printer, bool showPrinterSetupDialog); + +private slots: + void slotPrint (); + void slotPrintPreview (); + + void slotMail (); + +private: + void setAsWallpaper (bool centered); +private slots: + void slotSetAsWallpaperCentered (); + void slotSetAsWallpaperTiled (); + + void slotClose (); + void slotQuit (); + + + /* + * Edit Menu + */ + +private: + kpPixmapFX::WarnAboutLossInfo pasteWarnAboutLossInfo (); + void setupEditMenuActions (); + void enableEditMenuDocumentActions (bool enable = true); + + bool m_editMenuDocumentActionsEnabled; + + KAction *m_actionUndo, *m_actionRedo, + *m_actionCut, *m_actionCopy, + *m_actionPaste, *m_actionPasteInNewWindow, + *m_actionDelete, + *m_actionSelectAll, *m_actionDeselect, + *m_actionCopyToFile, *m_actionPasteFromFile; + + KURL m_lastPasteFromURL; + + KURL m_lastCopyToURL; + kpDocumentSaveOptions m_lastCopyToSaveOptions; + bool m_copyToFirstTime; + +public: + QPopupMenu *selectionToolRMBMenu (); + +private slots: + void slotCut (); + void slotCopy (); + void slotEnablePaste (); +private: + QRect calcUsefulPasteRect (int pixmapWidth, int pixmapHeight); + void paste (const kpSelection &sel, + bool forceTopLeft = false); +public: + // ( is ignored if is empty) + void pasteText (const QString &text, + bool forceNewTextSelection = false, + const QPoint &newTextSelectionTopLeft = KP_INVALID_POINT); + void pasteTextAt (const QString &text, const QPoint &point, + // Allow tiny adjustment of so that mouse + // pointer is not exactly on top of the topLeft of + // any new text selection (so that it doesn't look + // weird by being on top of a resize handle just after + // a paste). + bool allowNewTextSelectionPointShift = false); +public slots: + void slotPaste (); +private slots: + void slotPasteInNewWindow (); +public slots: + void slotDelete (); + + void slotSelectAll (); +private: + void addDeselectFirstCommand (kpCommand *cmd); +public slots: + void slotDeselect (); +private slots: + void slotCopyToFile (); + void slotPasteFromFile (); + + + /* + * View Menu + */ + +private: + bool m_viewMenuDocumentActionsEnabled; + + void setupViewMenuActions (); + bool viewMenuDocumentActionsEnabled () const; + void enableViewMenuDocumentActions (bool enable = true); + void actionShowGridUpdate (); + + KAction *m_actionFullScreenBIC, + *m_actionActualSize, + *m_actionFitToPage, *m_actionFitToWidth, *m_actionFitToHeight, + *m_actionZoomIn, *m_actionZoomOut; + KSelectAction *m_actionZoom; + KToggleAction *m_actionShowGrid, + *m_actionShowThumbnail, *m_actionZoomedThumbnail; + + QValueVector m_zoomList; + +private: + void sendZoomListToActionZoom (); + int zoomLevelFromString (const QString &string); + QString zoomLevelToString (int zoomLevel); + void zoomTo (int zoomLevel, bool centerUnderCursor = false); + +private slots: + void finishZoomTo (); + +private slots: + void slotActualSize (); + void slotFitToPage (); + void slotFitToWidth (); + void slotFitToHeight (); + +public: + void zoomIn (bool centerUnderCursor = false); + void zoomOut (bool centerUnderCursor = false); + +public slots: + void slotZoomIn (); + void slotZoomOut (); + +private: + void zoomAccordingToZoomAction (bool centerUnderCursor = false); + +private slots: + void slotZoom (); + + void slotShowGridToggled (); +private: + void updateMainViewGrid (); + +private: + QRect mapToGlobal (const QRect &rect) const; + QRect mapFromGlobal (const QRect &rect) const; + +private slots: + void slotDestroyThumbnailIfNotVisible (bool tnIsVisible); + void slotDestroyThumbnail (); + void slotDestroyThumbnailInitatedByUser (); + void slotCreateThumbnail (); + +private: + QTimer *m_thumbnailSaveConfigTimer; + +public: + void notifyThumbnailGeometryChanged (); + +private slots: + void slotSaveThumbnailGeometry (); + void slotShowThumbnailToggled (); + void updateThumbnailZoomed (); + void slotZoomedThumbnailToggled (); + void slotThumbnailShowRectangleToggled (); + +private: + void enableViewZoomedThumbnail (bool enable = true); + void enableViewShowThumbnailRectangle (bool enable = true); + void enableThumbnailOptionActions (bool enable = true); + void createThumbnailView (); + void destroyThumbnailView (); + void updateThumbnail (); + + + /* + * Image Menu + */ + +private: + bool isSelectionActive () const; + bool isTextSelection () const; + + QString autoCropText () const; + + void setupImageMenuActions (); + void enableImageMenuDocumentActions (bool enable = true); + + bool m_imageMenuDocumentActionsEnabled; + + KAction *m_actionResizeScale, + *m_actionCrop, *m_actionAutoCrop, + *m_actionFlip, *m_actionRotate, *m_actionSkew, + *m_actionConvertToBlackAndWhite, *m_actionConvertToGrayscale, + *m_actionMoreEffects, + *m_actionInvertColors, *m_actionClear; + +private slots: + void slotImageMenuUpdateDueToSelection (); + +public: + kpColor backgroundColor (bool ofSelection = false) const; + void addImageOrSelectionCommand (kpCommand *cmd, + bool addSelCreateCmdIfSelAvail = true, + bool addSelPullCmdIfSelAvail = true); + +private slots: + void slotResizeScale (); +public slots: + void slotCrop (); +private slots: + void slotAutoCrop (); + void slotFlip (); + void slotRotate (); + void slotSkew (); + void slotConvertToBlackAndWhite (); + void slotConvertToGrayscale (); + void slotInvertColors (); + void slotClear (); + void slotMoreEffects (); + + + /* + * Settings Menu + */ + +private: + void setupSettingsMenuActions (); + void enableSettingsMenuDocumentActions (bool enable = true); + + KToggleAction *m_actionShowPath; + KAction *m_actionKeyBindings, *m_actionConfigureToolbars, *m_actionConfigure; + KToggleFullScreenAction *m_actionFullScreen; + +private slots: + void slotFullScreen (); + + void slotEnableSettingsShowPath (); + void slotShowPathToggled (); + + void slotKeyBindings (); + + void slotConfigureToolBars (); + void slotNewToolBarConfig (); + + void slotConfigure (); + + + /* + * Status Bar + */ + +private: + bool m_statusBarCreated; + kpSqueezedTextLabel *m_statusBarMessageLabel; + + bool m_statusBarShapeLastPointsInitialised; + QPoint m_statusBarShapeLastStartPoint, m_statusBarShapeLastEndPoint; + bool m_statusBarShapeLastSizeInitialised; + QSize m_statusBarShapeLastSize; + + enum + { + StatusBarItemMessage, + StatusBarItemShapePoints, + StatusBarItemShapeSize, + StatusBarItemDocSize, + StatusBarItemDocDepth, + StatusBarItemZoom + }; + + void addPermanentStatusBarItem (int id, int maxTextLen); + void createStatusBar (); + +private slots: + void setStatusBarMessage (const QString &message = QString::null); + void setStatusBarShapePoints (const QPoint &startPoint = KP_INVALID_POINT, + const QPoint &endPoint = KP_INVALID_POINT); + void setStatusBarShapeSize (const QSize &size = KP_INVALID_SIZE); + void setStatusBarDocSize (const QSize &size = KP_INVALID_SIZE); + void setStatusBarDocDepth (int depth = 0); + void setStatusBarZoom (int zoom = 0); + + void recalculateStatusBarMessage (); + void recalculateStatusBarShape (); + + void recalculateStatusBar (); + + + /* + * Text ToolBar + */ + +private: + void setupTextToolBarActions (); + void readAndApplyTextSettings (); + +public: + void enableTextToolBarActions (bool enable = true); + +private slots: + void slotTextFontFamilyChanged (); + void slotTextFontSizeChanged (); + void slotTextBoldChanged (); + void slotTextItalicChanged (); + void slotTextUnderlineChanged (); + void slotTextStrikeThruChanged (); + +public: + KToolBar *textToolBar (); + bool isTextStyleBackgroundOpaque () const; + kpTextStyle textStyle () const; + void setTextStyle (const kpTextStyle &textStyle_); + int settingTextStyle () const; + +private: + KFontAction *m_actionTextFontFamily; + KFontSizeAction *m_actionTextFontSize; + KToggleAction *m_actionTextBold, *m_actionTextItalic, + *m_actionTextUnderline, *m_actionTextStrikeThru; + + int m_settingTextStyle; + QString m_textOldFontFamily; + int m_textOldFontSize; + + + /* + * Help Menu + */ +private: + void setupHelpMenuActions (); + void enableHelpMenuDocumentActions (bool enable = true); + +private slots: + void slotHelpTakingScreenshots (); + void slotHelpTakingScreenshotsFollowLink (const QString &link); + + +private: + // There is no need to maintain binary compatibility at this stage. + // The d-pointer is just so that you can experiment without recompiling + // the kitchen sink. + class kpMainWindowPrivate *d; +}; + + +#endif // KP_MAIN_WINDOW_H diff --git a/kolourpaint/kpmainwindow_edit.cpp b/kolourpaint/kpmainwindow_edit.cpp new file mode 100644 index 00000000..3cf9b4f6 --- /dev/null +++ b/kolourpaint/kpmainwindow_edit.cpp @@ -0,0 +1,1069 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// private +kpPixmapFX::WarnAboutLossInfo kpMainWindow::pasteWarnAboutLossInfo () +{ + return kpPixmapFX::WarnAboutLossInfo ( + i18n ("The image to be pasted" + " may have more colors than the current screen mode." + " In order to display it, some colors may be changed." + " Try increasing your screen depth to at least %1bpp." + + "\nIt also" + + " contains translucency which is not fully" + " supported. The translucency data will be" + " approximated with a 1-bit transparency mask."), + i18n ("The image to be pasted" + " may have more colors than the current screen mode." + " In order to display it, some colors may be changed." + " Try increasing your screen depth to at least %1bpp."), + i18n ("The image to be pasted" + " contains translucency which is not fully" + " supported. The translucency data will be" + " approximated with a 1-bit transparency mask."), + "paste", + this); +} + + +// private +void kpMainWindow::setupEditMenuActions () +{ + KActionCollection *ac = actionCollection (); + + + // Undo/Redo + // CONFIG: need GUI + m_commandHistory = new kpCommandHistory (true/*read config*/, this); + + if (m_configFirstTime) + { + // (so that cfg-file-editing user can modify in the meantime) + m_commandHistory->writeConfig (); + } + + + m_actionCut = KStdAction::cut (this, SLOT (slotCut ()), ac); + m_actionCopy = KStdAction::copy (this, SLOT (slotCopy ()), ac); + m_actionPaste = KStdAction::paste (this, SLOT (slotPaste ()), ac); + m_actionPasteInNewWindow = new KAction (i18n ("Paste in &New Window"), + Qt::CTRL + Qt::SHIFT + Qt::Key_V, + this, SLOT (slotPasteInNewWindow ()), ac, "edit_paste_in_new_window"); + + //m_actionDelete = KStdAction::clear (this, SLOT (slotDelete ()), ac); + m_actionDelete = new KAction (i18n ("&Delete Selection"), 0, + this, SLOT (slotDelete ()), ac, "edit_clear"); + + m_actionSelectAll = KStdAction::selectAll (this, SLOT (slotSelectAll ()), ac); + m_actionDeselect = KStdAction::deselect (this, SLOT (slotDeselect ()), ac); + + + m_actionCopyToFile = new KAction (i18n ("C&opy to File..."), 0, + this, SLOT (slotCopyToFile ()), ac, "edit_copy_to_file"); + m_actionPasteFromFile = new KAction (i18n ("Paste &From File..."), 0, + this, SLOT (slotPasteFromFile ()), ac, "edit_paste_from_file"); + + + m_editMenuDocumentActionsEnabled = false; + enableEditMenuDocumentActions (false); + + // Paste should always be enabled, as long as there is something paste + // (independent of whether we have a document or not) + connect (QApplication::clipboard (), SIGNAL (dataChanged ()), + this, SLOT (slotEnablePaste ())); + slotEnablePaste (); +} + +// private +void kpMainWindow::enableEditMenuDocumentActions (bool enable) +{ + // m_actionCut + // m_actionCopy + // m_actionPaste + // m_actionPasteInNewWindow + + // m_actionDelete + + m_actionSelectAll->setEnabled (enable); + // m_actionDeselect + + m_editMenuDocumentActionsEnabled = enable; + + // m_actionCopyToFile + // Unlike m_actionPaste, we disable this if there is no document. + // This is because "File / Open" would do the same thing, if there is + // no document. + m_actionPasteFromFile->setEnabled (enable); +} + + +// public +QPopupMenu *kpMainWindow::selectionToolRMBMenu () +{ + return (QPopupMenu *) guiFactory ()->container ("selectionToolRMBMenu", this); +} + + +// private slot +void kpMainWindow::slotCut () +{ +#if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "kpMainWindow::slotCut() CALLED" << endl; +#endif + + if (!m_document || !m_document->selection ()) + { + kdError () << "kpMainWindow::slotCut () doc=" << m_document + << " sel=" << (m_document ? m_document->selection () : 0) + << endl; + return; + } + + + QApplication::setOverrideCursor (Qt::waitCursor); + + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + slotCopy (); + slotDelete (); + + QApplication::restoreOverrideCursor (); + +} + +// private slot +void kpMainWindow::slotCopy () +{ +#if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "kpMainWindow::slotCopy() CALLED" << endl; +#endif + + if (!m_document || !m_document->selection ()) + { + kdError () << "kpMainWindow::slotCopy () doc=" << m_document + << " sel=" << (m_document ? m_document->selection () : 0) + << endl; + return; + } + + + QApplication::setOverrideCursor (Qt::waitCursor); + + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + kpSelection sel = *m_document->selection (); + // Transparency doesn't get sent across the aether so nuke it now + // so that transparency mask doesn't get needlessly recalculated + // if we ever call sel.setPixmap(). + sel.setTransparency (kpSelectionTransparency ()); + + if (sel.isText ()) + { + if (!sel.text ().isEmpty ()) + { + QApplication::clipboard ()->setData (new QTextDrag (sel.text ()), + QClipboard::Clipboard); + + // SYNC: Normally, users highlight text and press CTRL+C. + // Highlighting text copies it to the X11 "middle + // mouse button" clipboard. CTRL+C copies it to the + // separate, Windows-like "CTRL+V" clipboard. + // + // However, KolourPaint doesn't support highlighting. + // So when they press CTRL+C to copy all text, simulate + // the highlighting by copying the text to the "middle + // mouse button" clipboard. We don't do this for images + // as no one ever middle-mouse-pastes images. + // + // Note that we don't share the QTextDrag pointer with + // the above in case Qt doesn't expect it. + // + // Once we change KolourPaint to support highlighted text + // and CTRL+C to copy only the highlighted text, delete + // this code. + QApplication::clipboard ()->setData (new QTextDrag (sel.text ()), + QClipboard::Selection); + } + } + else + { + QPixmap rawPixmap; + + if (sel.pixmap ()) + rawPixmap = *sel.pixmap (); + else + rawPixmap = m_document->getSelectedPixmap (); + + // Some apps, such as OpenOffice.org 2.0.4, ignore the image mask + // when pasting. For transparent pixels, the uninitialized RGB + // values are used. Fix this by initializing those values to a + // neutral color -- white. + // + // Strangely enough, OpenOffice.org respects the mask when inserting + // an image from a file, as opposed to pasting one from the clipboard. + sel.setPixmap ( + kpPixmapFX::pixmapWithDefinedTransparentPixels ( + rawPixmap, + Qt::white)); // CONFIG + + QApplication::clipboard ()->setData (new kpSelectionDrag (sel), + QClipboard::Clipboard); + } + + QApplication::restoreOverrideCursor (); +} + + +static bool HasSomethingToPaste (kpMainWindow *mw) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow(" << mw->name () << "):HasSomethingToPaste()" << endl; + QTime timer; + timer.start (); +#else + (void) mw; +#endif + + bool hasSomething = false; + + QMimeSource *ms = QApplication::clipboard ()->data (QClipboard::Clipboard); + if (ms) + { + // It's faster to test for QTextDrag::canDecode() first due to the + // lazy evaluation of the '||' operator. + hasSomething = (QTextDrag::canDecode (ms) || + kpSelectionDrag::canDecode (ms)); + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t" << mw->name () << "***canDecode=" << timer.restart () << endl; + for (int i = 0; ; i++) + { + const char *fmt = ms->format (i); + if (!fmt) + break; + + kdDebug () << "\t'" << fmt << "'" << endl; + } + #endif + } + + return hasSomething; +} + +// HACK: SYNC: Non-Qt apps do not cause QApplication::clipboard() to +// emit dataChanged(). We don't want to have our paste +// action disabled when we can actually paste something. +// +// So we make sure the paste action is always enabled and +// before any paste, we check if there's actually something +// to paste (HasSomethingToPasteWithDialogIfNot ()). + +#if 1 // Hack code path + + +// Call before any paste only. +static bool HasSomethingToPasteWithDialogIfNot (kpMainWindow *mw) +{ + if (::HasSomethingToPaste (mw)) + return true; + + // STRING: Unfortunately, we are in a string freeze. +#if 1 + (void) mw; +#else + QApplication::setOverrideCursor (Qt::arrowCursor); + + KMessageBox::sorry (mw, + STRING_FREEZE_i18n ("

There is nothing in the clipboard to paste.

"), + STRING_FREEZE_i18n ("Cannot Paste")); + + QApplication::restoreOverrideCursor (); +#endif + + return false; +} + +// private slot +void kpMainWindow::slotEnablePaste () +{ + const bool shouldEnable = true; + m_actionPasteInNewWindow->setEnabled (shouldEnable); + m_actionPaste->setEnabled (shouldEnable); +} + + +#else // No hack + + +// Call before any paste only. +static bool HasSomethingToPasteWithDialogIfNot (kpMainWindow *) +{ + // We will not be called if there's nothing to paste, as the paste + // action would have been disabled. But do _not_ assert that + // (see the slotPaste() "data unexpectedly disappeared" KMessageBox). + return true; +} + +// private slot +void kpMainWindow::slotEnablePaste () +{ + const bool shouldEnable = ::HasSomethingToPaste (this); + m_actionPasteInNewWindow->setEnabled (shouldEnable); + m_actionPaste->setEnabled (shouldEnable); +} + + +#endif + + +// private +QRect kpMainWindow::calcUsefulPasteRect (int pixmapWidth, int pixmapHeight) +{ +#if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "kpMainWindow::calcUsefulPasteRect(" + << pixmapWidth << "," << pixmapHeight + << ")" + << endl; +#endif + if (!m_document) + { + kdError () << "kpMainWindow::calcUsefulPasteRect() without doc" << endl; + return QRect (); + } + + // TODO: 1st choice is to paste sel near but not overlapping last deselect point + + if (m_mainView && m_scrollView) + { + const QPoint viewTopLeft (m_scrollView->contentsX (), + m_scrollView->contentsY ()); + + const QPoint docTopLeft = m_mainView->transformViewToDoc (viewTopLeft); + + if ((docTopLeft.x () + pixmapWidth <= m_document->width () && + docTopLeft.y () + pixmapHeight <= m_document->height ()) || + pixmapWidth <= docTopLeft.x () || + pixmapHeight <= docTopLeft.y ()) + { + return QRect (docTopLeft.x (), docTopLeft.y (), + pixmapWidth, pixmapHeight); + } + } + + return QRect (0, 0, pixmapWidth, pixmapHeight); +} + +// private +void kpMainWindow::paste (const kpSelection &sel, bool forceTopLeft) +{ +#if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "kpMainWindow::paste(forceTopLeft=" << forceTopLeft << ")" + << endl; +#endif + + if (!sel.pixmap ()) + { + kdError () << "kpMainWindow::paste() with sel without pixmap" << endl; + return; + } + + QApplication::setOverrideCursor (Qt::waitCursor); + + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + + // + // Make sure we've got a document (esp. with File/Close) + // + + if (!m_document) + { + kpDocument *newDoc = new kpDocument ( + sel.width (), sel.height (), this); + + // will also create viewManager + setDocument (newDoc); + } + + + // + // Paste as new selection + // + + kpSelection selInUsefulPos = sel; + if (!forceTopLeft) + selInUsefulPos.moveTo (calcUsefulPasteRect (sel.width (), sel.height ()).topLeft ()); + addDeselectFirstCommand (new kpToolSelectionCreateCommand ( + selInUsefulPos.isText () ? + i18n ("Text: Create Box") : + i18n ("Selection: Create"), + selInUsefulPos, + this)); + + +#if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "sel.size=" << QSize (sel.width (), sel.height ()) + << " document.size=" + << QSize (m_document->width (), m_document->height ()) + << endl; +#endif + + // If the selection is bigger than the document, automatically + // resize the document (with the option of Undo'ing) to fit + // the selection. + // + // No annoying dialog necessary. + // + if (sel.width () > m_document->width () || + sel.height () > m_document->height ()) + { + m_commandHistory->addCommand ( + new kpToolResizeScaleCommand ( + false/*act on doc, not sel*/, + QMAX (sel.width (), m_document->width ()), + QMAX (sel.height (), m_document->height ()), + kpToolResizeScaleCommand::Resize, + this)); + } + + + QApplication::restoreOverrideCursor (); +} + +// public +void kpMainWindow::pasteText (const QString &text, + bool forceNewTextSelection, + const QPoint &newTextSelectionTopLeft) +{ +#if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "kpMainWindow::pasteText(" << text + << ",forceNewTextSelection=" << forceNewTextSelection + << ",newTextSelectionTopLeft=" << newTextSelectionTopLeft + << ")" << endl; +#endif + + if (text.isEmpty ()) + return; + + + // sync: restoreOverrideCursor() in all exit paths + QApplication::setOverrideCursor (Qt::waitCursor); + + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + + QValueVector textLines (1, QString::null); + + for (int i = 0; i < (int) text.length (); i++) + { + if (text [i] == '\n') + textLines.push_back (QString::null); + else + textLines [textLines.size () - 1].append (text [i]); + } + + + if (!forceNewTextSelection && + m_document && m_document->selection () && + m_document->selection ()->isText () && + m_commandHistory && m_viewManager) + { + #if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "\treusing existing Text Selection" << endl; + #endif + + kpMacroCommand *macroCmd = new kpMacroCommand (i18n ("Text: Paste"), + this); + + for (int i = 0; i < (int) textLines.size (); i++) + { + if (i > 0) + { + macroCmd->addCommand ( + new kpToolTextEnterCommand ( + QString::null/*uninteresting child of macroCmd*/, + m_viewManager->textCursorRow (), + m_viewManager->textCursorCol (), + this)); + } + + macroCmd->addCommand ( + new kpToolTextInsertCommand ( + QString::null/*uninteresting child of macroCmd*/, + m_viewManager->textCursorRow (), + m_viewManager->textCursorCol (), + textLines [i], + this)); + } + + m_commandHistory->addCommand (macroCmd, false/*no exec*/); + } + else + { + #if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "\tcreating Text Selection" << endl; + #endif + + const kpTextStyle ts = textStyle (); + const QFontMetrics fontMetrics = ts.fontMetrics (); + + int height = textLines.size () * fontMetrics.height (); + if (textLines.size () >= 1) + height += (textLines.size () - 1) * fontMetrics.leading (); + + int width = 0; + for (QValueVector ::const_iterator it = textLines.begin (); + it != textLines.end (); + it++) + { + const int w = fontMetrics.width (*it); + if (w > width) + width = w; + } + + + const int selWidth = QMAX (kpSelection::minimumWidthForTextStyle (ts), + width + kpSelection::textBorderSize () * 2); + const int selHeight = QMAX (kpSelection::minimumHeightForTextStyle (ts), + height + kpSelection::textBorderSize () * 2); + kpSelection sel (QRect (0, 0, selWidth, selHeight), + textLines, + ts); + + if (newTextSelectionTopLeft != KP_INVALID_POINT) + { + sel.moveTo (newTextSelectionTopLeft); + paste (sel, true/*force topLeft*/); + } + else + { + paste (sel); + } + } + + + QApplication::restoreOverrideCursor (); +} + +// public +void kpMainWindow::pasteTextAt (const QString &text, const QPoint &point, + bool allowNewTextSelectionPointShift) +{ +#if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "kpMainWindow::pasteTextAt(" << text + << ",point=" << point + << ",allowNewTextSelectionPointShift=" + << allowNewTextSelectionPointShift + << ")" << endl; +#endif + + QApplication::setOverrideCursor (Qt::waitCursor); + + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + + if (m_document && + m_document->selection () && + m_document->selection ()->isText () && + m_document->selection ()->pointIsInTextArea (point)) + { + kpSelection *sel = m_document->selection (); + + const int row = sel->textRowForPoint (point); + const int col = sel->textColForPoint (point); + + m_viewManager->setTextCursorPosition (row, col); + + pasteText (text); + } + else + { + QPoint pointToUse = point; + + if (allowNewTextSelectionPointShift) + { + // TODO: In terms of doc pixels, would be inconsistent behaviour + // based on zoomLevel of view. + // pointToUse -= QPoint (-view->selectionResizeHandleAtomicSize (), + // -view->selectionResizeHandleAtomicSize ()); + } + + pasteText (text, true/*force new text selection*/, pointToUse); + } + + QApplication::restoreOverrideCursor (); +} + +// public slot +void kpMainWindow::slotPaste () +{ +#if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "kpMainWindow::slotPaste() CALLED" << endl; +#endif + + // sync: restoreOverrideCursor() in all exit paths + QApplication::setOverrideCursor (Qt::waitCursor); + + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + + if (!::HasSomethingToPasteWithDialogIfNot (this)) + { + QApplication::restoreOverrideCursor (); + return; + } + + + // + // Acquire the pixmap + // + + QMimeSource *ms = QApplication::clipboard ()->data (QClipboard::Clipboard); + if (!ms) + { + kdError () << "kpMainWindow::slotPaste() without mimeSource" << endl; + QApplication::restoreOverrideCursor (); + return; + } + + kpSelection sel; + QString text; + if (kpSelectionDrag::decode (ms, sel/*ref*/, pasteWarnAboutLossInfo ())) + { + sel.setTransparency (selectionTransparency ()); + paste (sel); + } + else if (QTextDrag::decode (ms, text/*ref*/)) + { + pasteText (text); + } + else + { + QApplication::restoreOverrideCursor (); + + kdDebug () << "kpMainWindow::slotPaste() could not decode selection" << endl; + kdDebug () << "\tFormats supported:" << endl; + for (int i = 0; ms->format (i); i++) + { + kdDebug () << "\t\t" << i << ":" << ms->format (i) << endl; + } + + // TODO: fix Klipper + KMessageBox::sorry (this, + i18n ("

KolourPaint cannot paste the contents of" + " the clipboard as the data unexpectedly disappeared.

" + + "

This usually occurs if the application which was" + " responsible" + " for the clipboard contents has been closed.

"), + i18n ("Cannot Paste")); + + // TODO: PROPAGATE: interprocess + if (KMainWindow::memberList) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\thave memberList" << endl; + #endif + + for (QPtrList ::const_iterator it = KMainWindow::memberList->begin (); + it != KMainWindow::memberList->end (); + it++) + { + kpMainWindow *mw = dynamic_cast (*it); + + if (!mw) + { + kdError () << "kpMainWindow::slotPaste() given fake kpMainWindow: " << (*it) << endl; + continue; + } + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tmw=" << mw << endl; + #endif + + mw->slotEnablePaste (); + } + } + + return; + } + + QApplication::restoreOverrideCursor (); +} + +// private slot +void kpMainWindow::slotPasteInNewWindow () +{ +#if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "kpMainWindow::slotPasteInNewWindow() CALLED" << endl; +#endif + + // sync: restoreOverrideCursor() in all exit paths + QApplication::setOverrideCursor (Qt::waitCursor); + + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + + if (!::HasSomethingToPasteWithDialogIfNot (this)) + { + QApplication::restoreOverrideCursor (); + return; + } + + + // + // Pasting must ensure that: + // + // Requirement 1. the document is the same size as the image to be pasted. + // Requirement 2. transparent pixels in the image must remain as transparent. + // + + kpMainWindow *win = new kpMainWindow (0/*no document*/); + win->show (); + + // Make "Edit / Paste in New Window" always paste white pixels as white. + // Don't let selection transparency get in the way and paste them as + // transparent. + kpSelectionTransparency transparency = win->selectionTransparency (); + if (transparency.isTransparent ()) + { + #if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "\tchanging selection transparency to opaque" << endl; + #endif + transparency.setOpaque (); + // Since we are setting selection transparency programmatically + // -- as opposed to in response to user input -- this will not + // affect the selection transparency tool option widget's "last used" + // config setting. + win->setSelectionTransparency (transparency); + } + + // (this handles Requirement 1. above) + win->slotPaste (); + + // (this handles Requirement 2. above; + // slotDeselect() is not enough unless the document is filled with the + // transparent color in advance) + win->slotCrop (); + + + QApplication::restoreOverrideCursor (); +} + +// public slot +void kpMainWindow::slotDelete () +{ +#if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "kpMainWindow::slotDelete() CALLED" << endl; +#endif + if (!m_actionDelete->isEnabled ()) + { + #if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "\taction not enabled - was probably called from kpTool::keyPressEvent()" << endl; + #endif + return; + } + + if (!m_document || !m_document->selection ()) + { + kdError () << "kpMainWindow::slotDelete () doc=" << m_document + << " sel=" << (m_document ? m_document->selection () : 0) + << endl; + return; + } + + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + addImageOrSelectionCommand (new kpToolSelectionDestroyCommand ( + m_document->selection ()->isText () ? + i18n ("Text: Delete Box") : // not to be confused with i18n ("Text: Delete") + i18n ("Selection: Delete"), + false/*no push onto doc*/, + this)); +} + + +// private slot +void kpMainWindow::slotSelectAll () +{ +#if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "kpMainWindow::slotSelectAll() CALLED" << endl; +#endif + if (!m_document) + { + kdError () << "kpMainWindow::slotSelectAll() without doc" << endl; + return; + } + + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + if (m_document->selection ()) + slotDeselect (); + + // just the border - don't actually pull pixmap from doc yet + m_document->setSelection (kpSelection (kpSelection::Rectangle, m_document->rect (), selectionTransparency ())); + + if (tool ()) + tool ()->somethingBelowTheCursorChanged (); +} + + +// private +void kpMainWindow::addDeselectFirstCommand (kpCommand *cmd) +{ +#if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "kpMainWindow::addDeselectFirstCommand(" + << cmd + << ")" + << endl; +#endif + + + kpSelection *sel = m_document->selection (); + +#if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "\tsel=" << sel << endl; +#endif + + if (sel) + { + // if you just dragged out something with no action then + // forget the drag + if (!sel->pixmap ()) + { + #if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "\tjust a fresh border - was nop - delete" << endl; + #endif + m_document->selectionDelete (); + if (tool ()) + tool ()->somethingBelowTheCursorChanged (); + + if (cmd) + m_commandHistory->addCommand (cmd); + } + else + { + #if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "\treal selection with pixmap - push onto doc cmd" << endl; + #endif + kpCommand *deselectCommand = new kpToolSelectionDestroyCommand ( + sel->isText () ? + i18n ("Text: Finish") : + i18n ("Selection: Deselect"), + true/*push onto document*/, + this); + + if (cmd) + { + kpMacroCommand *macroCmd = new kpMacroCommand (cmd->name (), this); + macroCmd->addCommand (deselectCommand); + macroCmd->addCommand (cmd); + m_commandHistory->addCommand (macroCmd); + } + else + m_commandHistory->addCommand (deselectCommand); + } + } + else + { + if (cmd) + m_commandHistory->addCommand (cmd); + } +} + + +// public slot +void kpMainWindow::slotDeselect () +{ +#if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "kpMainWindow::slotDeselect() CALLED" << endl; +#endif + if (!m_document || !m_document->selection ()) + { + kdError () << "kpMainWindow::slotDeselect() doc=" << m_document + << " sel=" << (m_document ? m_document->selection () : 0) + << endl; + return; + } + + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + addDeselectFirstCommand (0); +} + + +// private slot +void kpMainWindow::slotCopyToFile () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotCopyToFile()" << endl; +#endif + + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + + if (!m_document->selection ()) + return; + + kpSelection sel = *m_document->selection (); + + QPixmap pixmapToSave; + + if (!sel.pixmap ()) + { + // Not a floating selection - user has just selected a region; + // haven't pulled it off yet so probably don't expect and can't + // visualise selection transparency so give opaque, not transparent + // pixmap. + pixmapToSave = m_document->getSelectedPixmap (); + } + else + pixmapToSave = sel.transparentPixmap (); + + + kpDocumentSaveOptions chosenSaveOptions; + bool allowOverwritePrompt, allowLossyPrompt; + KURL chosenURL = askForSaveURL (i18n ("Copy to File"), + m_lastCopyToURL.url (), + pixmapToSave, + m_lastCopyToSaveOptions, + kpDocumentMetaInfo (), + kpSettingsGroupEditCopyTo, + false/*allow remote files*/, + &chosenSaveOptions, + m_copyToFirstTime, + &allowOverwritePrompt, + &allowLossyPrompt); + + if (chosenURL.isEmpty ()) + return; + + + if (!kpDocument::savePixmapToFile (pixmapToSave, + chosenURL, + chosenSaveOptions, kpDocumentMetaInfo (), + allowOverwritePrompt, + allowLossyPrompt, + this)) + { + return; + } + + + addRecentURL (chosenURL); + + + m_lastCopyToURL = chosenURL; + m_lastCopyToSaveOptions = chosenSaveOptions; + + m_copyToFirstTime = false; +} + +// private slot +void kpMainWindow::slotPasteFromFile () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotPasteFromFile()" << endl; +#endif + + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + + KURL::List urls = askForOpenURLs (i18n ("Paste From File"), + m_lastPasteFromURL.url (), + false/*only 1 URL*/); + + if (urls.count () != 1) + return; + + KURL url = urls.first (); + m_lastPasteFromURL = url; + + + QPixmap pixmap = kpDocument::getPixmapFromFile (url, + false/*show error message if doesn't exist*/, + this); + + + if (pixmap.isNull ()) + return; + + + addRecentURL (url); + + paste (kpSelection (kpSelection::Rectangle, + QRect (0, 0, pixmap.width (), pixmap.height ()), + pixmap, + selectionTransparency ())); +} + diff --git a/kolourpaint/kpmainwindow_file.cpp b/kolourpaint/kpmainwindow_file.cpp new file mode 100644 index 00000000..b30b323e --- /dev/null +++ b/kolourpaint/kpmainwindow_file.cpp @@ -0,0 +1,1409 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +// private +void kpMainWindow::setupFileMenuActions () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::setupFileMenuActions()" << endl; +#endif + KActionCollection *ac = actionCollection (); + + m_actionNew = KStdAction::openNew (this, SLOT (slotNew ()), ac); + m_actionOpen = KStdAction::open (this, SLOT (slotOpen ()), ac); + + m_actionOpenRecent = KStdAction::openRecent (this, SLOT (slotOpenRecent (const KURL &)), ac); + m_actionOpenRecent->loadEntries (kapp->config ()); +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\trecent URLs=" << m_actionOpenRecent->items () << endl; +#endif + + m_actionSave = KStdAction::save (this, SLOT (slotSave ()), ac); + m_actionSaveAs = KStdAction::saveAs (this, SLOT (slotSaveAs ()), ac); + + m_actionExport = new KAction (i18n ("E&xport..."), 0, + this, SLOT (slotExport ()), ac, "file_export"); + + m_actionScan = new KAction (i18n ("Scan..."), SmallIcon ("scanner"), 0, + this, SLOT (slotScan ()), ac, "file_scan"); + + //m_actionRevert = KStdAction::revert (this, SLOT (slotRevert ()), ac); + m_actionReload = new KAction (i18n ("Reloa&d"), KStdAccel::reload (), + this, SLOT (slotReload ()), ac, "file_revert"); + slotEnableReload (); + + m_actionPrint = KStdAction::print (this, SLOT (slotPrint ()), ac); + m_actionPrintPreview = KStdAction::printPreview (this, SLOT (slotPrintPreview ()), ac); + + m_actionMail = KStdAction::mail (this, SLOT (slotMail ()), ac); + + m_actionSetAsWallpaperCentered = new KAction (i18n ("Set as Wa&llpaper (Centered)"), 0, + this, SLOT (slotSetAsWallpaperCentered ()), ac, "file_set_as_wallpaper_centered"); + m_actionSetAsWallpaperTiled = new KAction (i18n ("Set as Wallpaper (&Tiled)"), 0, + this, SLOT (slotSetAsWallpaperTiled ()), ac, "file_set_as_wallpaper_tiled"); + + m_actionClose = KStdAction::close (this, SLOT (slotClose ()), ac); + m_actionQuit = KStdAction::quit (this, SLOT (slotQuit ()), ac); + + m_scanDialog = 0; + + enableFileMenuDocumentActions (false); +} + +// private +void kpMainWindow::enableFileMenuDocumentActions (bool enable) +{ + // m_actionNew + // m_actionOpen + + // m_actionOpenRecent + + m_actionSave->setEnabled (enable); + m_actionSaveAs->setEnabled (enable); + + m_actionExport->setEnabled (enable); + + // m_actionReload + + m_actionPrint->setEnabled (enable); + m_actionPrintPreview->setEnabled (enable); + + m_actionMail->setEnabled (enable); + + m_actionSetAsWallpaperCentered->setEnabled (enable); + m_actionSetAsWallpaperTiled->setEnabled (enable); + + m_actionClose->setEnabled (enable); + // m_actionQuit->setEnabled (enable); +} + + +// private +void kpMainWindow::addRecentURL (const KURL &url) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::addRecentURL(" << url << ")" << endl; +#endif + if (url.isEmpty ()) + return; + + + KConfig *cfg = kapp->config (); + + // KConfig::readEntry() does not actually reread from disk, hence doesn't + // realise what other processes have done e.g. Settings / Show Path + cfg->reparseConfiguration (); + + // HACK: Something might have changed interprocess. + // If we could PROPAGATE: interprocess, then this wouldn't be required. + m_actionOpenRecent->loadEntries (cfg); + + m_actionOpenRecent->addURL (url); + + m_actionOpenRecent->saveEntries (cfg); + cfg->sync (); + +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tnew recent URLs=" << m_actionOpenRecent->items () << endl; +#endif + + + // TODO: PROPAGATE: interprocess + if (KMainWindow::memberList) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\thave memberList" << endl; + #endif + + for (QPtrList ::const_iterator it = KMainWindow::memberList->begin (); + it != KMainWindow::memberList->end (); + it++) + { + kpMainWindow *mw = dynamic_cast (*it); + + if (!mw) + { + kdError () << "kpMainWindow::addRecentURL() given fake kpMainWindow: " << (*it) << endl; + continue; + } + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tmw=" << mw << endl; + #endif + + if (mw != this) + { + // WARNING: Do not use KRecentFilesAction::setItems() + // - it does not work since only its superclass, + // KSelectAction, implements setItems() and can't + // update KRecentFilesAction's URL list. + + // Avoid URL memory leak in KRecentFilesAction::loadEntries(). + mw->m_actionOpenRecent->clearURLList (); + + mw->m_actionOpenRecent->loadEntries (cfg); + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\t\tcheck recent URLs=" + << mw->m_actionOpenRecent->items () << endl; + #endif + } + } + } +} + + +// private slot +void kpMainWindow::slotNew () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + if (m_document) + { + kpMainWindow *win = new kpMainWindow (); + win->show (); + } + else + { + open (KURL (), true/*create an empty doc*/); + } +} + + +// private +QSize kpMainWindow::defaultDocSize () const +{ + // KConfig::readEntry() does not actually reread from disk, hence doesn't + // realise what other processes have done e.g. Settings / Show Path + kapp->config ()->reparseConfiguration (); + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral); + KConfigBase *cfg = cfgGroupSaver.config (); + + QSize docSize = cfg->readSizeEntry (kpSettingLastDocSize); + + if (docSize.isEmpty ()) + { + docSize = QSize (400, 300); + } + else + { + // Don't get too big or you'll thrash (or even lock up) the computer + // just by opening a window + docSize = QSize (QMIN (2048, docSize.width ()), + QMIN (2048, docSize.height ())); + } + + return docSize; +} + +// private +void kpMainWindow::saveDefaultDocSize (const QSize &size) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tCONFIG: saving Last Doc Size = " << size << endl; +#endif + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral); + KConfigBase *cfg = cfgGroupSaver.config (); + + cfg->writeEntry (kpSettingLastDocSize, size); + cfg->sync (); +} + + +// private +bool kpMainWindow::shouldOpenInNewWindow () const +{ + return (m_document && !m_document->isEmpty ()); +} + +// private +void kpMainWindow::setDocumentChoosingWindow (kpDocument *doc) +{ + // need new window? + if (shouldOpenInNewWindow ()) + { + // send doc to new window + kpMainWindow *win = new kpMainWindow (doc); + win->show (); + } + else + { + // set up views, doc signals + setDocument (doc); + } +} + + +// private +kpDocument *kpMainWindow::openInternal (const KURL &url, + const QSize &fallbackDocSize, + bool newDocSameNameIfNotExist) +{ + // create doc + kpDocument *newDoc = new kpDocument (fallbackDocSize.width (), + fallbackDocSize.height (), + this); + if (!newDoc->open (url, newDocSameNameIfNotExist)) + { + delete newDoc; + return 0; + } + + // Send document to current or new window. + setDocumentChoosingWindow (newDoc); + + return newDoc; +} + +// private +bool kpMainWindow::open (const KURL &url, bool newDocSameNameIfNotExist) +{ + kpDocument *newDoc = openInternal (url, + defaultDocSize (), + newDocSameNameIfNotExist); + if (newDoc) + { + if (newDoc->isFromURL (false/*don't bother checking exists*/)) + addRecentURL (url); + return true; + } + else + { + return false; + } +} + + +// private +KURL::List kpMainWindow::askForOpenURLs (const QString &caption, const QString &startURL, + bool allowMultipleURLs) +{ + QStringList mimeTypes = KImageIO::mimeTypes (KImageIO::Reading); +#if DEBUG_KP_MAIN_WINDOW + QStringList sortedMimeTypes = mimeTypes; + sortedMimeTypes.sort (); + kdDebug () << "kpMainWindow::askForURLs(allowMultiple=" + << allowMultipleURLs + << ")" << endl + << "\tmimeTypes=" << mimeTypes << endl + << "\tsortedMimeTypes=" << sortedMimeTypes << endl; +#endif + QString filter = mimeTypes.join (" "); + + KFileDialog fd (startURL, filter, this, "fd", true/*modal*/); + fd.setCaption (caption); + fd.setOperationMode (KFileDialog::Opening); + if (allowMultipleURLs) + fd.setMode (KFile::Files); + fd.setPreviewWidget (new KImageFilePreview (&fd)); + + if (fd.exec ()) + return fd.selectedURLs (); + else + return KURL::List (); +} + +// private slot +void kpMainWindow::slotOpen () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + + const KURL::List urls = askForOpenURLs (i18n ("Open Image"), + m_document ? m_document->url ().url () : QString::null); + + for (KURL::List::const_iterator it = urls.begin (); + it != urls.end (); + it++) + { + open (*it); + } +} + +// private slot +void kpMainWindow::slotOpenRecent (const KURL &url) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotOpenRecent(" << url << ")" << endl; + kdDebug () << "\titems=" << m_actionOpenRecent->items () << endl; +#endif + + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + open (url); + + // If the open is successful, addRecentURL() would have bubbled up the + // URL in the File / Open Recent action. As a side effect, the URL is + // deselected. + // + // If the open fails, we should deselect the URL: + // + // 1. for consistency + // + // 2. because it has not been opened. + // + m_actionOpenRecent->setCurrentItem (-1); +} + + +// private slot +void kpMainWindow::slotScan () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotScan() scanDialog=" << m_scanDialog << endl; +#endif + + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + + if (!m_scanDialog) + { + // Create scan dialog by looking for plugin. + // [takes about 500ms on 350Mhz] + m_scanDialog = KScanDialog::getScanDialog (this, "scandialog", true/*modal*/); + + // No scanning support (kdegraphics/libkscan) installed? + // [Remove $KDEDIR/share/servicetypes/kscan.desktop and + // $KDEDIR/share/services/scanservice.desktop to simulate this] + if (!m_scanDialog) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tcould not create scan dialog" << endl; + #endif + // Instead, we could try to create the scan dialog in the ctor + // and just disable the action in the first place, removing + // the need for this dialog. + // + // But this increases startup time and is a bit risky e.g. if + // the scan support hangs, KolourPaint would not be able to be + // started at all. + // + // Also, disabling the action is bad because the scan support + // can be installed while KolourPaint is still running. + KMessageBox::sorry (this, + i18n ("Scanning support is not installed."), + i18n ("No Scanning Support")); + return; + } + + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tcreated scanDialog=" << m_scanDialog << endl; + #endif + connect (m_scanDialog, SIGNAL (finalImage (const QImage &, int)), + SLOT (slotScanned (const QImage &, int))); + } + + +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tcalling setup" << endl; +#endif + // Bring up dialog to select scan device. + if (m_scanDialog->setup ()) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tOK - showing dialog" << endl; + #endif + // Called only if scanner configured/available. + // + // In reality, this seems to be called even if you press "Cancel" in + // the KScanDialog::setup() dialog! + m_scanDialog->show (); + } + else + { + // Have never seen this code path execute even if "Cancel" is pressed. + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tFAIL" << endl; + #endif + } +} + +// private slot +void kpMainWindow::slotScanned (const QImage &image, int) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotScanned() image.rect=" << image.rect () << endl; +#endif + +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\thiding dialog" << endl; +#endif + // (KScanDialog does not close itself after a scan is made) + // + // Close the dialog, first thing: + // + // 1. This means that any dialogs we bring up won't be nested on top. + // + // 2. We don't want to return from this method but forget to close + // the dialog. So do it before anything else. + m_scanDialog->hide (); + + // (just in case there's some drawing between slotScan() exiting and + // us being called) + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + + // TODO: Maybe this code should be moved into kpdocument.cpp - + // since it resembles the responsibilities of kpDocument::open(). + + // Convert QImage to kpDocument's image format, gathering meta info + // from QImage. + kpDocumentSaveOptions saveOptions; + kpDocumentMetaInfo metaInfo; + const QPixmap pixmap = kpDocument::convertToPixmapAsLosslessAsPossible ( + image, + kpMainWindow::pasteWarnAboutLossInfo (), + &saveOptions, + &metaInfo); + + if (pixmap.isNull ()) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tcould not convert to pixmap" << endl; + #endif + KMessageBox::sorry (this, + i18n ("Cannot scan - out of graphics memory."), + i18n ("Cannot Scan")); + return; + } + + + // Create document from image and meta info. + kpDocument *doc = new kpDocument (pixmap.width (), pixmap.height (), this); + doc->setPixmap (pixmap); + doc->setSaveOptions (saveOptions); + doc->setMetaInfo (metaInfo); + + + // Send document to current or new window. + setDocumentChoosingWindow (doc); +} + + +// private slot +bool kpMainWindow::save (bool localOnly) +{ + if (m_document->url ().isEmpty () || + KImageIO::mimeTypes (KImageIO::Writing) + .findIndex (m_document->saveOptions ()->mimeType ()) < 0 || + // SYNC: kpDocument::getPixmapFromFile() can't determine quality + // from file so it has been set initially to an invalid value. + (m_document->saveOptions ()->mimeTypeHasConfigurableQuality () && + m_document->saveOptions ()->qualityIsInvalid ()) || + (localOnly && !m_document->url ().isLocalFile ())) + { + return saveAs (localOnly); + } + else + { + if (m_document->save (false/*no overwrite prompt*/, + !m_document->savedAtLeastOnceBefore ()/*lossy prompt*/)) + { + addRecentURL (m_document->url ()); + return true; + } + else + return false; + } +} + +// private slot +bool kpMainWindow::slotSave () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + return save (); +} + +// private +KURL kpMainWindow::askForSaveURL (const QString &caption, + const QString &startURL, + const QPixmap &pixmapToBeSaved, + const kpDocumentSaveOptions &startSaveOptions, + const kpDocumentMetaInfo &docMetaInfo, + const QString &forcedSaveOptionsGroup, + bool localOnly, + kpDocumentSaveOptions *chosenSaveOptions, + bool isSavingForFirstTime, + bool *allowOverwritePrompt, + bool *allowLossyPrompt) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::askForURL() startURL=" << startURL << endl; + startSaveOptions.printDebug ("\tstartSaveOptions"); +#endif + + bool reparsedConfiguration = false; + + // KConfig::readEntry() does not actually reread from disk, hence doesn't + // realise what other processes have done e.g. Settings / Show Path + // so reparseConfiguration() must be called +#define SETUP_READ_CFG() \ + if (!reparsedConfiguration) \ + { \ + kapp->config ()->reparseConfiguration (); \ + reparsedConfiguration = true; \ + } \ + \ + KConfigGroupSaver cfgGroupSaver (kapp->config (), forcedSaveOptionsGroup); \ + KConfigBase *cfg = cfgGroupSaver.config (); + + + if (chosenSaveOptions) + *chosenSaveOptions = kpDocumentSaveOptions (); + + if (allowOverwritePrompt) + *allowOverwritePrompt = true; // play it safe for now + + if (allowLossyPrompt) + *allowLossyPrompt = true; // play it safe for now + + + kpDocumentSaveOptions fdSaveOptions = startSaveOptions; + + QStringList mimeTypes = KImageIO::mimeTypes (KImageIO::Writing); +#if DEBUG_KP_MAIN_WINDOW + QStringList sortedMimeTypes = mimeTypes; + sortedMimeTypes.sort (); + kdDebug () << "\tmimeTypes=" << mimeTypes << endl + << "\tsortedMimeTypes=" << sortedMimeTypes << endl; +#endif + if (mimeTypes.isEmpty ()) + { + kdError () << "No KImageIO output mimetypes!" << endl; + return KURL (); + } + +#define MIME_TYPE_IS_VALID() (!fdSaveOptions.mimeTypeIsInvalid () && \ + mimeTypes.findIndex (fdSaveOptions.mimeType ()) >= 0) + if (!MIME_TYPE_IS_VALID ()) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tmimeType=" << fdSaveOptions.mimeType () + << " not valid, get default" << endl; + #endif + + SETUP_READ_CFG (); + + fdSaveOptions.setMimeType (kpDocumentSaveOptions::defaultMimeType (cfg)); + + + if (!MIME_TYPE_IS_VALID ()) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tmimeType=" << fdSaveOptions.mimeType () + << " not valid, get hardcoded" << endl; + #endif + if (mimeTypes.findIndex ("image/png") > -1) + fdSaveOptions.setMimeType ("image/png"); + else if (mimeTypes.findIndex ("image/x-bmp") > -1) + fdSaveOptions.setMimeType ("image/x-bmp"); + else + fdSaveOptions.setMimeType (mimeTypes.first ()); + } + } +#undef MIME_TYPE_IN_LIST + + if (fdSaveOptions.colorDepthIsInvalid ()) + { + SETUP_READ_CFG (); + + fdSaveOptions.setColorDepth (kpDocumentSaveOptions::defaultColorDepth (cfg)); + fdSaveOptions.setDither (kpDocumentSaveOptions::defaultDither (cfg)); + } + + if (fdSaveOptions.qualityIsInvalid ()) + { + SETUP_READ_CFG (); + + fdSaveOptions.setQuality (kpDocumentSaveOptions::defaultQuality (cfg)); + } +#if DEBUG_KP_MAIN_WINDOW + fdSaveOptions.printDebug ("\tcorrected saveOptions passed to fileDialog"); +#endif + + kpDocumentSaveOptionsWidget *saveOptionsWidget = + new kpDocumentSaveOptionsWidget (pixmapToBeSaved, + fdSaveOptions, + docMetaInfo, + this); + + KFileDialog fd (startURL, QString::null, this, "fd", true/*modal*/, + saveOptionsWidget); + saveOptionsWidget->setVisualParent (&fd); + fd.setCaption (caption); + fd.setOperationMode (KFileDialog::Saving); +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tmimeTypes=" << mimeTypes << endl; +#endif + fd.setMimeFilter (mimeTypes, fdSaveOptions.mimeType ()); + if (localOnly) + fd.setMode (KFile::File | KFile::LocalOnly); + + connect (&fd, SIGNAL (filterChanged (const QString &)), + saveOptionsWidget, SLOT (setMimeType (const QString &))); + + + if (fd.exec ()) + { + kpDocumentSaveOptions newSaveOptions = saveOptionsWidget->documentSaveOptions (); + #if DEBUG_KP_MAIN_WINDOW + newSaveOptions.printDebug ("\tnewSaveOptions"); + #endif + + KConfigGroupSaver cfgGroupSaver (kapp->config (), forcedSaveOptionsGroup); + KConfigBase *cfg = cfgGroupSaver.config (); + + // Save options user forced - probably want to use them in future + kpDocumentSaveOptions::saveDefaultDifferences (cfg, + fdSaveOptions, newSaveOptions); + cfg->sync (); + + + if (chosenSaveOptions) + *chosenSaveOptions = newSaveOptions; + + + bool shouldAllowOverwritePrompt = + (fd.selectedURL () != startURL || + newSaveOptions.mimeType () != startSaveOptions.mimeType ()); + if (allowOverwritePrompt) + { + *allowOverwritePrompt = shouldAllowOverwritePrompt; + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tallowOverwritePrompt=" << *allowOverwritePrompt << endl; + #endif + } + + if (allowLossyPrompt) + { + // SYNC: kpDocumentSaveOptions elements - everything except quality + // (one quality setting is "just as lossy" as another so no + // need to continually warn due to quality change) + *allowLossyPrompt = + (isSavingForFirstTime || + shouldAllowOverwritePrompt || + newSaveOptions.mimeType () != startSaveOptions.mimeType () || + newSaveOptions.colorDepth () != startSaveOptions.colorDepth () || + newSaveOptions.dither () != startSaveOptions.dither ()); + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tallowLossyPrompt=" << *allowLossyPrompt << endl; + #endif + } + + + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tselectedURL=" << fd.selectedURL () << endl; + #endif + return fd.selectedURL (); + } + else + return KURL (); +#undef SETUP_READ_CFG +} + + +// private slot +bool kpMainWindow::saveAs (bool localOnly) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::saveAs URL=" << m_document->url () << endl; +#endif + + kpDocumentSaveOptions chosenSaveOptions; + bool allowOverwritePrompt, allowLossyPrompt; + KURL chosenURL = askForSaveURL (i18n ("Save Image As"), + m_document->url ().url (), + m_document->pixmapWithSelection (), + *m_document->saveOptions (), + *m_document->metaInfo (), + kpSettingsGroupFileSaveAs, + localOnly, + &chosenSaveOptions, + !m_document->savedAtLeastOnceBefore (), + &allowOverwritePrompt, + &allowLossyPrompt); + + + if (chosenURL.isEmpty ()) + return false; + + + if (!m_document->saveAs (chosenURL, chosenSaveOptions, + allowOverwritePrompt, + allowLossyPrompt)) + { + return false; + } + + + addRecentURL (chosenURL); + + return true; +} + +// private slot +bool kpMainWindow::slotSaveAs () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + return saveAs (); +} + +// private slot +bool kpMainWindow::slotExport () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotExport()" << endl; +#endif + + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + + kpDocumentSaveOptions chosenSaveOptions; + bool allowOverwritePrompt, allowLossyPrompt; + KURL chosenURL = askForSaveURL (i18n ("Export"), + m_lastExportURL.url (), + m_document->pixmapWithSelection (), + m_lastExportSaveOptions, + *m_document->metaInfo (), + kpSettingsGroupFileExport, + false/*allow remote files*/, + &chosenSaveOptions, + m_exportFirstTime, + &allowOverwritePrompt, + &allowLossyPrompt); + + + if (chosenURL.isEmpty ()) + return false; + + + if (!kpDocument::savePixmapToFile (m_document->pixmapWithSelection (), + chosenURL, + chosenSaveOptions, *m_document->metaInfo (), + allowOverwritePrompt, + allowLossyPrompt, + this)) + { + return false; + } + + + addRecentURL (chosenURL); + + + m_lastExportURL = chosenURL; + m_lastExportSaveOptions = chosenSaveOptions; + + m_exportFirstTime = false; + + return true; +} + + +// private slot +void kpMainWindow::slotEnableReload () +{ + m_actionReload->setEnabled (m_document); +} + +// private slot +bool kpMainWindow::slotReload () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + if (!m_document) + return false; + + + KURL oldURL = m_document->url (); + + + if (m_document->isModified ()) + { + int result = KMessageBox::Cancel; + + if (m_document->isFromURL (false/*don't bother checking exists*/) && !oldURL.isEmpty ()) + { + result = KMessageBox::warningContinueCancel (this, + i18n ("The document \"%1\" has been modified.\n" + "Reloading will lose all changes since you last saved it.\n" + "Are you sure?") + .arg (m_document->prettyFilename ()), + QString::null/*caption*/, + i18n ("&Reload")); + } + else + { + result = KMessageBox::warningContinueCancel (this, + i18n ("The document \"%1\" has been modified.\n" + "Reloading will lose all changes.\n" + "Are you sure?") + .arg (m_document->prettyFilename ()), + QString::null/*caption*/, + i18n ("&Reload")); + } + + if (result != KMessageBox::Continue) + return false; + } + + + kpDocument *doc = 0; + + // If it's _supposed to_ come from a URL or it exists + if (m_document->isFromURL (false/*don't bother checking exists*/) || + (!oldURL.isEmpty () && KIO::NetAccess::exists (oldURL, true/*open*/, this))) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotReload() reloading from disk!" << endl; + #endif + + doc = new kpDocument (1, 1, this); + if (!doc->open (oldURL)) + { + delete doc; doc = 0; + return false; + } + + addRecentURL (oldURL); + } + else + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotReload() create doc" << endl; + #endif + + doc = new kpDocument (m_document->constructorWidth (), + m_document->constructorHeight (), + this); + doc->setURL (oldURL, false/*not from URL*/); + } + + + setDocument (doc); + + return true; +} + + +// private +void kpMainWindow::sendFilenameToPrinter (KPrinter *printer) +{ + KURL url = m_document->url (); + if (!url.isEmpty ()) + { + int dot; + + QString fileName = url.fileName (); + dot = fileName.findRev ('.'); + + // file.ext but not .hidden-file? + if (dot > 0) + fileName.truncate (dot); + + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::sendFilenameToPrinter() fileName=" + << fileName + << " dir=" + << url.directory () + << endl; + #endif + printer->setDocName (fileName); + printer->setDocFileName (fileName); + printer->setDocDirectory (url.directory ()); + } +} + + +static const double InchesPerMeter = 100 / 2.54; + + +// TODO: GUI should allow viewing & changing of DPI. + + +static bool shouldPrintImageCenteredOnPage () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpmainwindow_file.cpp:shouldPrintImageCenteredOnPage()" << endl; +#endif + bool ret; + + KConfigGroupSaver cfgGroupSaver (KGlobal::config (), + kpSettingsGroupGeneral); + KConfigBase *cfg = cfgGroupSaver.config (); + + if (cfg->hasKey (kpSettingPrintImageCenteredOnPage)) + { + ret = cfg->readBoolEntry (kpSettingPrintImageCenteredOnPage); + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tread: " << ret << endl; + #endif + } + else + { + ret = true; +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tfirst time - writing default: " << ret << endl; +#endif + cfg->writeEntry (kpSettingPrintImageCenteredOnPage, ret); + cfg->sync (); + } + + return ret; +} + + +// private +void kpMainWindow::sendPixmapToPrinter (KPrinter *printer, + bool showPrinterSetupDialog) +{ + // Get image to be printed. + QPixmap pixmap = m_document->pixmapWithSelection (); + + + // Get image DPI. + double pixmapDotsPerMeterX = + double (m_document->metaInfo ()->dotsPerMeterX ()); + double pixmapDotsPerMeterY = + double (m_document->metaInfo ()->dotsPerMeterY ()); +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::sendPixmapToPrinter() pixmap:" + << " width=" << pixmap.width () + << " height=" << pixmap.height () + << " dotsPerMeterX=" << pixmapDotsPerMeterX + << " dotsPerMeterY=" << pixmapDotsPerMeterY + << endl; +#endif + + // Image DPI invalid (e.g. new image, could not read from file + // or Qt3 doesn't implement DPI for JPEG)? + if (pixmapDotsPerMeterX < 1 || pixmapDotsPerMeterY < 1) + { + // Even if just one DPI dimension is invalid, mutate both DPI + // dimensions as we have no information about the intended + // aspect ratio anyway (and other dimension likely to be invalid). + + // When rendering text onto a document, the fonts are rasterised + // according to the screen's DPI. + // TODO: I think we should use the image's DPI. Technically + // possible? + // + // So no matter what computer you draw text on, you get + // the same pixels. + // + // So we must print at the screen's DPI to get the right text size. + // + // Unfortunately, this means that moving to a different screen DPI + // affects printing. If you edited the image at a different screen + // DPI than when you print, you get incorrect results. Furthermore, + // this is bogus if you don't have text in your image. Worse still, + // what if you have multiple screens connected to the same computer + // with different DPIs? + // TODO: mysteriously, someone else is setting this to 96dpi always. + QPaintDeviceMetrics screenMetrics (&pixmap/*screen element*/); + const int dpiX = screenMetrics.logicalDpiX (), + dpiY = screenMetrics.logicalDpiY (); + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tusing screen dpi: x=" << dpiX << " y=" << dpiY << endl; + #endif + + pixmapDotsPerMeterX = dpiX * InchesPerMeter; + pixmapDotsPerMeterY = dpiY * InchesPerMeter; + } + + + // Get page size (excluding margins). + // Coordinate (0,0) is the X here: + // mmmmm + // mX m + // m m m = margin + // m m + // mmmmm + QPaintDeviceMetrics printerMetrics (printer); + const int printerWidthMM = printerMetrics.widthMM (); + const int printerHeightMM = printerMetrics.heightMM (); +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tprinter: widthMM=" << printerWidthMM + << " heightMM=" << printerHeightMM + << endl; +#endif + + + double dpiX = pixmapDotsPerMeterX / InchesPerMeter; + double dpiY = pixmapDotsPerMeterY / InchesPerMeter; +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tpixmap: dpiX=" << dpiX << " dpiY=" << dpiY << endl; +#endif + + + // + // If image doesn't fit on page at intended DPI, change the DPI. + // + + const double scaleDpiX = (pixmap.width () / (printerWidthMM / 25.4)) + / dpiX; + const double scaleDpiY = (pixmap.height () / (printerHeightMM / 25.4)) + / dpiY; + const double scaleDpi = QMAX (scaleDpiX, scaleDpiY); +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tscaleDpi: x=" << scaleDpiX << " y=" << scaleDpiY + << " --> scale at " << scaleDpi << " to fit?" + << endl; +#endif + + // Need to increase resolution to fit page? + if (scaleDpi > 1.0) + { + dpiX *= scaleDpi; + dpiY *= scaleDpi; + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\t\tto fit page, scaled to:" + << " dpiX=" << dpiX << " dpiY=" << dpiY << endl; + #endif + } + + + // Make sure DPIs are equal as that's all QPrinter::setResolution() + // supports. We do this in such a way that we only ever stretch an + // image, to avoid losing information. Don't antialias as the printer + // will do that to translate our DPI to its physical resolution and + // double-antialiasing looks bad. + if (dpiX > dpiY) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tdpiX > dpiY; stretching pixmap height to equalise DPIs to dpiX=" + << dpiX << endl; + #endif + kpPixmapFX::scale (&pixmap, + pixmap.width (), + QMAX (1, qRound (pixmap.height () * dpiX / dpiY)), + false/*don't antialias*/); + + dpiY = dpiX; + } + else if (dpiY > dpiX) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tdpiY > dpiX; stretching pixmap width to equalise DPIs to dpiY=" + << dpiY << endl; + #endif + kpPixmapFX::scale (&pixmap, + QMAX (1, qRound (pixmap.width () * dpiY / dpiX)), + pixmap.height (), + false/*don't antialias*/); + + dpiX = dpiY; + } + + + // ASSERT: dpiX == dpiY + // QPrinter::setResolution() has to be called before QPrinter::setup(). + printer->setResolution (QMAX (1, qRound (dpiX))); + + + double originX = 0, originY = 0; + + // Centre image on page? + if (shouldPrintImageCenteredOnPage ()) + { + originX = (printerWidthMM * dpiX / 25.4 - pixmap.width ()) / 2; + originY = (printerHeightMM * dpiY / 25.4 - pixmap.height ()) / 2; + } + +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\torigin: x=" << originX << " y=" << originY << endl; +#endif + + + sendFilenameToPrinter (printer); + + if (showPrinterSetupDialog) + { + // The user can mutate margins at their own risk in this dialog. + // It doesn't seem to affect the size of the page as reported + // by QPaintDeviceMetrics::{width,height}MM(). + if (!printer->setup (this)) + return; + } + + + // Send pixmap to printer. + QPainter painter; + painter.begin (printer); + painter.drawPixmap (qRound (originX), qRound (originY), pixmap); + painter.end (); +} + + +// private slot +void kpMainWindow::slotPrint () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + KPrinter printer; + + sendPixmapToPrinter (&printer, true/*showPrinterSetupDialog*/); +} + +// private slot +void kpMainWindow::slotPrintPreview () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + // TODO: get it to reflect default printer's settings + KPrinter printer (false/*separate settings from ordinary printer*/); + + // TODO: pass "this" as parent + printer.setPreviewOnly (true); + + sendPixmapToPrinter (&printer, false/*don't showPrinterSetupDialog*/); +} + + +// private slot +void kpMainWindow::slotMail () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + if (m_document->url ().isEmpty ()/*no name*/ || + !m_document->isFromURL () || + m_document->isModified ()/*needs to be saved*/) + { + int result = KMessageBox::questionYesNo (this, + i18n ("You must save this image before sending it.\n" + "Do you want to save it?"), + QString::null, + KStdGuiItem::save (), KStdGuiItem::cancel ()); + + if (result == KMessageBox::Yes) + { + if (!save ()) + { + // save failed or aborted - don't email + return; + } + } + else + { + // don't want to save - don't email + return; + } + } + + kapp->invokeMailer ( + QString::null/*to*/, + QString::null/*cc*/, + QString::null/*bcc*/, + m_document->prettyFilename()/*subject*/, + QString::null/*body*/, + QString::null/*messageFile*/, + QStringList (m_document->url ().url ())/*attachments*/); +} + + +// private +void kpMainWindow::setAsWallpaper (bool centered) +{ + if (m_document->url ().isEmpty ()/*no name*/ || + !m_document->url ().isLocalFile ()/*remote file*/ || + !m_document->isFromURL () || + m_document->isModified ()/*needs to be saved*/) + { + QString question; + + if (!m_document->url ().isLocalFile ()) + { + question = i18n ("Before this image can be set as the wallpaper, " + "you must save it as a local file.\n" + "Do you want to save it?"); + } + else + { + question = i18n ("Before this image can be set as the wallpaper, " + "you must save it.\n" + "Do you want to save it?"); + } + + int result = KMessageBox::questionYesNo (this, + question, QString::null, + KStdGuiItem::save (), KStdGuiItem::cancel ()); + + if (result == KMessageBox::Yes) + { + // save() is smart enough to pop up a filedialog if it's a + // remote file that should be saved locally + if (!save (true/*localOnly*/)) + { + // save failed or aborted - don't set the wallpaper + return; + } + } + else + { + // don't want to save - don't set wallpaper + return; + } + } + + + QByteArray data; + QDataStream dataStream (data, IO_WriteOnly); + + // write path +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::setAsWallpaper() path=" + << m_document->url ().path () << endl; +#endif + dataStream << QString (m_document->url ().path ()); + + // write position: + // + // SYNC: kdebase/kcontrol/background/bgsettings.h: + // 1 = Centered + // 2 = Tiled + // 6 = Scaled + // 9 = lastWallpaperMode + // + // Why restrict the user to Centered & Tiled? + // Why don't we let the user choose if it should be common to all desktops? + // Why don't we rewrite the Background control page? + // + // Answer: This is supposed to be a quick & convenient feature. + // + // If you want more options, go to kcontrol for that kind of + // flexiblity. We don't want to slow down average users, who see way too + // many dialogs already and probably haven't even heard of "Centered Maxpect"... + // + dataStream << int (centered ? 1 : 2); + + + // I'm going to all this trouble because the user might not have kdebase + // installed so kdebase/kdesktop/KBackgroundIface.h might not be around + // to be compiled in (where user == developer :)) + if (!KApplication::dcopClient ()->send ("kdesktop", "KBackgroundIface", + "setWallpaper(QString,int)", data)) + { + KMessageBox::sorry (this, i18n ("Could not change wallpaper.")); + } +} + +// private slot +void kpMainWindow::slotSetAsWallpaperCentered () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + setAsWallpaper (true/*centered*/); +} + +// private slot +void kpMainWindow::slotSetAsWallpaperTiled () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + setAsWallpaper (false/*tiled*/); +} + + +// private slot +void kpMainWindow::slotClose () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotClose()" << endl; +#endif + + if (!queryClose ()) + return; + + setDocument (0); +} + +// private slot +void kpMainWindow::slotQuit () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotQuit()" << endl; +#endif + + close (); // will call queryClose() +} + diff --git a/kolourpaint/kpmainwindow_help.cpp b/kolourpaint/kpmainwindow_help.cpp new file mode 100644 index 00000000..fb1fc790 --- /dev/null +++ b/kolourpaint/kpmainwindow_help.cpp @@ -0,0 +1,219 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +// private +void kpMainWindow::setupHelpMenuActions () +{ + KActionCollection *ac = actionCollection (); + + + // Explanation for action name: + // "Taking" is like a digital camera when you record the image and is + // analogous to pressing PrintScreen. However, "Acquiring" is when + // the image is brought into KolourPaint, just as you would acquire + // from a digital camera in future versions of KolourPaint. Hence + // "Acquiring" is more appropriate. + // -- Thurston + d->m_actionHelpTakingScreenshots = new KAction ( + i18n ("Acquiring &Screenshots"), 0, + this, SLOT (slotHelpTakingScreenshots ()), + ac, "help_taking_screenshots"); + + + enableHelpMenuDocumentActions (false); +} + +// private +void kpMainWindow::enableHelpMenuDocumentActions (bool /*enable*/) +{ +} + + +// SYNC: kdebase/kwin/kwinbindings.cpp +static QString printScreenShortcutString () +{ + KConfigGroupSaver cfgGroupSaver (KGlobal::config (), "Global Shortcuts"); + KConfigBase *cfg = cfgGroupSaver.config (); + + // TODO: i18n() entry name? kwinbindings.cpp seems to but it doesn't + // make sense. + const QString cfgEntryString = cfg->readEntry ("Desktop Screenshot"); + + + // (only use 1st key sequence, if it exists) + const QString humanReadableShortcut = + KShortcut (cfgEntryString).seq (0).toString (); + + if (!humanReadableShortcut.isEmpty ()) + { + return humanReadableShortcut; + } + else + { + // (localised) + return KKey (Qt::CTRL + Qt::Key_Print).toString (); + } +} + + +// private slot +void kpMainWindow::slotHelpTakingScreenshots () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotHelpTakingScreenshots()" << endl; +#endif + + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + + // TODO: Totally bogus logic if kwin not running under same user as KolourPaint. + // SYNC: KWin contains PrintScreen key logic + QCStringList dcopApps = KApplication::dcopClient ()->registeredApplications (); +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tdcopApps=" << dcopApps << endl; +#endif + bool isRunningKDE = (dcopApps.findIndex ("kwin") >= 0); + +#if 0 +{ + int i = 0; + FILE *fp = fopen ("/home/kdevel/kolourpaint.tmp", "rt"); + if (fp && fscanf (fp, "Hello: %d", &i) == 1) + isRunningKDE = i, fclose (fp); +} +#endif + + QString message; + if (isRunningKDE) + { + message = i18n + ( + "

" + "To acquire a screenshot, press %1." + " The screenshot will be placed into the clipboard" + " and you will be able to paste it in KolourPaint." + "

" + + "

" + "You may configure the Desktop Screenshot shortcut" + " in the KDE Control Center" + " module Keyboard Shortcuts." + "

" + + "

Alternatively, you may try the application" + " KSnapshot." + "

" + ); + } + else + { + message = i18n + ( + "

" + "You do not appear to be running KDE." + "

" + + // We tell them this much even though they aren't running KDE + // to entice them to use KDE since it's so easy. + "

" + "Once you have loaded KDE:
" + "

" + "To acquire a screenshot, press %1." + " The screenshot will be placed into the clipboard" + " and you will be able to paste it in KolourPaint." + "
" + "

" + + "

Alternatively, you may try the application" + " KSnapshot." + "

" + ); + } + + // TODO: Totally bogus logic if kwin not running under same user as KolourPaint. + message = message.arg (::printScreenShortcutString ()); + + // Add extra vertical space + message += "

 

"; + + + KDialogBase dlg (this, "helpTakingScreenshotsDialog", true/*modal*/, + i18n ("Acquiring Screenshots"), + KDialogBase::Close, KDialogBase::Close/*default btn*/, + true/*separator line*/); + + KActiveLabel *messageLabel = new KActiveLabel (message, &dlg); + disconnect (messageLabel, SIGNAL (linkClicked (const QString &)), + messageLabel, SLOT (openLink (const QString &))); + connect (messageLabel, SIGNAL (linkClicked (const QString &)), + this, SLOT (slotHelpTakingScreenshotsFollowLink (const QString &))); + + dlg.setMainWidget (messageLabel); + + dlg.exec (); +} + +// private +void kpMainWindow::slotHelpTakingScreenshotsFollowLink (const QString &link) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotHelpTakingScreenshotsFollowLink(" + << link << ")" << endl; +#endif + + if (link == "configure kde shortcuts") + { + KRun::runCommand ("kcmshell keys"); + } + else if (link == "run ksnapshot") + { + KRun::runCommand ("ksnapshot"); + } + else + { + kdError () << "kpMainWindow::slotHelpTakingScreenshotsFollowLink(" + << link << ")" << endl; + } +} diff --git a/kolourpaint/kpmainwindow_image.cpp b/kolourpaint/kpmainwindow_image.cpp new file mode 100644 index 00000000..7f662af7 --- /dev/null +++ b/kolourpaint/kpmainwindow_image.cpp @@ -0,0 +1,474 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// private +bool kpMainWindow::isSelectionActive () const +{ + return (m_document ? bool (m_document->selection ()) : false); +} + +// private +bool kpMainWindow::isTextSelection () const +{ + return (m_document && m_document->selection () && + m_document->selection ()->isText ()); +} + + +// private +QString kpMainWindow::autoCropText () const +{ + return kpToolAutoCropCommand::name (isSelectionActive (), + kpToolAutoCropCommand::ShowAccel); +} + + +// private +void kpMainWindow::setupImageMenuActions () +{ + KActionCollection *ac = actionCollection (); + + m_actionResizeScale = new KAction (i18n ("R&esize / Scale..."), Qt::CTRL + Qt::Key_E, + this, SLOT (slotResizeScale ()), ac, "image_resize_scale"); + + m_actionCrop = new KAction (i18n ("Se&t as Image (Crop)"), Qt::CTRL + Qt::Key_T, + this, SLOT (slotCrop ()), ac, "image_crop"); + + m_actionAutoCrop = new KAction (autoCropText (), Qt::CTRL + Qt::Key_U, + this, SLOT (slotAutoCrop ()), ac, "image_auto_crop"); + + m_actionFlip = new KAction (i18n ("&Flip..."), Qt::CTRL + Qt::Key_F, + this, SLOT (slotFlip ()), ac, "image_flip"); + + m_actionRotate = new KAction (i18n ("&Rotate..."), Qt::CTRL + Qt::Key_R, + this, SLOT (slotRotate ()), ac, "image_rotate"); + + m_actionSkew = new KAction (i18n ("S&kew..."), Qt::CTRL + Qt::Key_K, + this, SLOT (slotSkew ()), ac, "image_skew"); + + m_actionConvertToBlackAndWhite = new KAction (i18n ("Reduce to Mo&nochrome (Dithered)"), 0, + this, SLOT (slotConvertToBlackAndWhite ()), ac, "image_convert_to_black_and_white"); + + m_actionConvertToGrayscale = new KAction (i18n ("Reduce to &Grayscale"), 0, + this, SLOT (slotConvertToGrayscale ()), ac, "image_convert_to_grayscale"); + + m_actionInvertColors = new KAction (i18n ("&Invert Colors"), Qt::CTRL + Qt::Key_I, + this, SLOT (slotInvertColors ()), ac, "image_invert_colors"); + + m_actionClear = new KAction (i18n ("C&lear"), Qt::CTRL + Qt::SHIFT + Qt::Key_N, + this, SLOT (slotClear ()), ac, "image_clear"); + + m_actionMoreEffects = new KAction (i18n ("&More Effects..."), Qt::CTRL + Qt::Key_M, + this, SLOT (slotMoreEffects ()), ac, "image_more_effects"); + + enableImageMenuDocumentActions (false); +} + +// private +void kpMainWindow::enableImageMenuDocumentActions (bool enable) +{ + m_actionResizeScale->setEnabled (enable); + m_actionCrop->setEnabled (enable); + m_actionAutoCrop->setEnabled (enable); + m_actionFlip->setEnabled (enable); + m_actionRotate->setEnabled (enable); + m_actionSkew->setEnabled (enable); + m_actionConvertToBlackAndWhite->setEnabled (enable); + m_actionConvertToGrayscale->setEnabled (enable); + m_actionInvertColors->setEnabled (enable); + m_actionClear->setEnabled (enable); + m_actionMoreEffects->setEnabled (enable); + + m_imageMenuDocumentActionsEnabled = enable; +} + + +// private slot +void kpMainWindow::slotImageMenuUpdateDueToSelection () +{ + KMenuBar *mBar = menuBar (); + if (!mBar) // just in case + return; + + int mBarNumItems = (int) mBar->count (); + for (int index = 0; index < mBarNumItems; index++) + { + int id = mBar->idAt (index); + + // SYNC: kolourpaintui.rc + QString menuBarItemTextImage = i18n ("&Image"); + QString menuBarItemTextSelection = i18n ("Select&ion"); + + const QString menuBarItemText = mBar->text (id); + if (menuBarItemText == menuBarItemTextImage || + menuBarItemText == menuBarItemTextSelection) + { + if (isSelectionActive ()) + mBar->changeItem (id, menuBarItemTextSelection); + else + mBar->changeItem (id, menuBarItemTextImage); + + break; + } + } + + + m_actionResizeScale->setEnabled (m_imageMenuDocumentActionsEnabled); + m_actionCrop->setEnabled (m_imageMenuDocumentActionsEnabled && + isSelectionActive ()); + + const bool enable = (m_imageMenuDocumentActionsEnabled && !isTextSelection ()); + m_actionAutoCrop->setText (autoCropText ()); + m_actionAutoCrop->setEnabled (enable); + m_actionFlip->setEnabled (enable); + m_actionRotate->setEnabled (enable); + m_actionSkew->setEnabled (enable); + m_actionConvertToBlackAndWhite->setEnabled (enable); + m_actionConvertToGrayscale->setEnabled (enable); + m_actionInvertColors->setEnabled (enable); + m_actionClear->setEnabled (enable); + m_actionMoreEffects->setEnabled (enable); +} + + +// public +kpColor kpMainWindow::backgroundColor (bool ofSelection) const +{ + if (ofSelection) + return kpColor::transparent; + else + { + if (m_colorToolBar) + return m_colorToolBar->backgroundColor (); + else + { + kdError () << "kpMainWindow::backgroundColor() without colorToolBar" << endl; + return kpColor::invalid; + } + } +} + + +// public +void kpMainWindow::addImageOrSelectionCommand (kpCommand *cmd, + bool addSelCreateCmdIfSelAvail, + bool addSelPullCmdIfSelAvail) +{ +#if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "kpMainWindow::addImageOrSelectionCommand()" + << " addSelCreateCmdIfSelAvail=" << addSelCreateCmdIfSelAvail + << " addSelPullCmdIfSelAvail=" << addSelPullCmdIfSelAvail + << endl; +#endif + + if (!m_document) + { + kdError () << "kpMainWindow::addImageOrSelectionCommand() without doc" << endl; + return; + } + + + if (m_viewManager) + m_viewManager->setQueueUpdates (); + + + kpSelection *sel = m_document->selection (); +#if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "\tsel=" << sel + << " sel->pixmap=" << (sel ? sel->pixmap () : 0) + << endl; +#endif + if (addSelCreateCmdIfSelAvail && sel && !sel->pixmap ()) + { + // create selection region + kpCommand *createCommand = new kpToolSelectionCreateCommand ( + i18n ("Selection: Create"), + *sel, + this); + + if (kpToolSelectionCreateCommand::nextUndoCommandIsCreateBorder (commandHistory ())) + commandHistory ()->setNextUndoCommand (createCommand); + else + commandHistory ()->addCommand (createCommand, + false/*no exec - user already dragged out sel*/); + } + + + if (addSelPullCmdIfSelAvail && sel && !sel->pixmap ()) + { + kpMacroCommand *macroCmd = new kpMacroCommand (cmd->name (), this); + + macroCmd->addCommand (new kpToolSelectionPullFromDocumentCommand ( + QString::null/*uninteresting child of macro cmd*/, + this)); + + macroCmd->addCommand (cmd); + + m_commandHistory->addCommand (macroCmd); + } + else + { + m_commandHistory->addCommand (cmd); + } + + + if (m_viewManager) + m_viewManager->restoreQueueUpdates (); +} + +// private slot +void kpMainWindow::slotResizeScale () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + kpToolResizeScaleDialog dialog (this); + dialog.setKeepAspectRatio (d->m_resizeScaleDialogLastKeepAspect); + + if (dialog.exec () && !dialog.isNoOp ()) + { + kpToolResizeScaleCommand *cmd = new kpToolResizeScaleCommand ( + dialog.actOnSelection (), + dialog.imageWidth (), dialog.imageHeight (), + dialog.type (), + this); + + bool addSelCreateCommand = (dialog.actOnSelection () || + cmd->scaleSelectionWithImage ()); + bool addSelPullCommand = dialog.actOnSelection (); + + addImageOrSelectionCommand ( + cmd, + addSelCreateCommand, + addSelPullCommand); + + // Resized document? + if (!dialog.actOnSelection () && + dialog.type () == kpToolResizeScaleCommand::Resize) + { + // TODO: this should be the responsibility of kpDocument + saveDefaultDocSize (QSize (dialog.imageWidth (), dialog.imageHeight ())); + } + } + + + if (d->m_resizeScaleDialogLastKeepAspect != dialog.keepAspectRatio ()) + { + d->m_resizeScaleDialogLastKeepAspect = dialog.keepAspectRatio (); + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral); + KConfigBase *cfg = cfgGroupSaver.config (); + + cfg->writeEntry (kpSettingResizeScaleLastKeepAspect, + d->m_resizeScaleDialogLastKeepAspect); + cfg->sync (); + } +} + +// public slot +void kpMainWindow::slotCrop () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + if (!m_document || !m_document->selection ()) + { + kdError () << "kpMainWindow::slotCrop() doc=" << m_document + << " sel=" << (m_document ? m_document->selection () : 0) + << endl; + return; + } + + + ::kpToolCrop (this); +} + +// private slot +void kpMainWindow::slotAutoCrop () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + ::kpToolAutoCrop (this); +} + +// private slot +void kpMainWindow::slotFlip () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + kpToolFlipDialog dialog ((bool) m_document->selection (), this); + + if (dialog.exec () && !dialog.isNoOp ()) + { + addImageOrSelectionCommand ( + new kpToolFlipCommand (m_document->selection (), + dialog.getHorizontalFlip (), dialog.getVerticalFlip (), + this)); + } +} + +// private slot +void kpMainWindow::slotRotate () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + kpToolRotateDialog dialog ((bool) m_document->selection (), this); + + if (dialog.exec () && !dialog.isNoOp ()) + { + addImageOrSelectionCommand ( + new kpToolRotateCommand (m_document->selection (), + dialog.angle (), + this)); + } +} + +// private slot +void kpMainWindow::slotSkew () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + kpToolSkewDialog dialog ((bool) m_document->selection (), this); + + if (dialog.exec () && !dialog.isNoOp ()) + { + addImageOrSelectionCommand ( + new kpToolSkewCommand (m_document->selection (), + dialog.horizontalAngle (), dialog.verticalAngle (), + this)); + } +} + +// private slot +void kpMainWindow::slotConvertToBlackAndWhite () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + addImageOrSelectionCommand ( + new kpEffectReduceColorsCommand (1/*depth*/, true/*dither*/, + m_document->selection (), this)); +} + +// private slot +void kpMainWindow::slotConvertToGrayscale () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + addImageOrSelectionCommand ( + new kpToolConvertToGrayscaleCommand (m_document->selection (), this)); +} + +// private slot +void kpMainWindow::slotInvertColors () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + addImageOrSelectionCommand ( + new kpEffectInvertCommand (m_document->selection (), this)); +} + +// private slot +void kpMainWindow::slotClear () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + addImageOrSelectionCommand ( + new kpToolClearCommand (m_document->selection (), this)); +} + +// private slot +void kpMainWindow::slotMoreEffects () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + kpEffectsDialog dialog ((bool) m_document->selection (), this); + dialog.selectEffect (d->m_moreEffectsDialogLastEffect); + + if (dialog.exec () && !dialog.isNoOp ()) + { + addImageOrSelectionCommand (dialog.createCommand ()); + } + + + if (d->m_moreEffectsDialogLastEffect != dialog.selectedEffect ()) + { + d->m_moreEffectsDialogLastEffect = dialog.selectedEffect (); + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral); + KConfigBase *cfg = cfgGroupSaver.config (); + + cfg->writeEntry (kpSettingMoreEffectsLastEffect, + d->m_moreEffectsDialogLastEffect); + cfg->sync (); + } +} diff --git a/kolourpaint/kpmainwindow_p.h b/kolourpaint/kpmainwindow_p.h new file mode 100644 index 00000000..9ec94eaa --- /dev/null +++ b/kolourpaint/kpmainwindow_p.h @@ -0,0 +1,49 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_MAIN_WINDOW_P_H +#define KP_MAIN_WINDOW_P_H + + +class KAction; +class KToggleAction; + + +struct kpMainWindowPrivate +{ + bool m_configThumbnailShowRectangle; + KToggleAction *m_actionShowThumbnailRectangle; + + KAction *m_actionHelpTakingScreenshots; + + int m_moreEffectsDialogLastEffect; + bool m_resizeScaleDialogLastKeepAspect; +}; + + +#endif // KP_MAIN_WINDOW_P_H diff --git a/kolourpaint/kpmainwindow_settings.cpp b/kolourpaint/kpmainwindow_settings.cpp new file mode 100644 index 00000000..609f7dfe --- /dev/null +++ b/kolourpaint/kpmainwindow_settings.cpp @@ -0,0 +1,209 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +// private +void kpMainWindow::setupSettingsMenuActions () +{ + KActionCollection *ac = actionCollection (); + + + // Settings/Toolbars |> %s + setStandardToolBarMenuEnabled (true); + + // Settings/Show Statusbar + createStandardStatusBarAction (); + + + m_actionFullScreen = KStdAction::fullScreen (this, SLOT (slotFullScreen ()), ac, + this/*window*/); + + + m_actionShowPath = new KToggleAction (i18n ("Show &Path"), 0, + this, SLOT (slotShowPathToggled ()), ac, "settings_show_path"); + m_actionShowPath->setCheckedState (i18n ("Hide &Path")); + slotEnableSettingsShowPath (); + + + m_actionKeyBindings = KStdAction::keyBindings (this, SLOT (slotKeyBindings ()), ac); + m_actionConfigureToolbars = KStdAction::configureToolbars (this, SLOT (slotConfigureToolBars ()), ac); + // m_actionConfigure = KStdAction::preferences (this, SLOT (slotConfigure ()), ac); + + + enableSettingsMenuDocumentActions (false); +} + +// private +void kpMainWindow::enableSettingsMenuDocumentActions (bool /*enable*/) +{ +} + + +// private slot +void kpMainWindow::slotFullScreen () +{ + if (m_actionFullScreen->isChecked ()) + showFullScreen (); + else + showNormal (); +} + + +// private slot +void kpMainWindow::slotEnableSettingsShowPath () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotEnableSettingsShowPath()" << endl; +#endif + + const bool enable = (m_document && !m_document->url ().isEmpty ()); + + m_actionShowPath->setEnabled (enable); + m_actionShowPath->setChecked (enable && m_configShowPath); +} + +// private slot +void kpMainWindow::slotShowPathToggled () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotShowPathToggled()" << endl; +#endif + + m_configShowPath = m_actionShowPath->isChecked (); + + slotUpdateCaption (); + + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral); + KConfigBase *cfg = cfgGroupSaver.config (); + + cfg->writeEntry (kpSettingShowPath, m_configShowPath); + cfg->sync (); +} + + +// private slot +void kpMainWindow::slotKeyBindings () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotKeyBindings()" << endl; +#endif + + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + + bool singleKeyTriggersDisabled = !actionsSingleKeyTriggersEnabled (); + + if (singleKeyTriggersDisabled) + enableActionsSingleKeyTriggers (true); + + + if (KKeyDialog::configure (actionCollection (), this)) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tdialog accepted" << endl; + #endif + // TODO: PROPAGATE: thru mainWindow's and interprocess + + if (singleKeyTriggersDisabled) + enableActionsSingleKeyTriggers (false); + } +} + + +// private slot +void kpMainWindow::slotConfigureToolBars () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotConfigureToolBars()" << endl; +#endif + + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + + //saveMainWindowSettings (kapp->config (), autoSaveGroup ()); + + KEditToolbar dialog (actionCollection (), + QString::null/*default ui.rc file*/, + true/*global resource*/, + this/*parent*/); + // Clicking on OK after Apply brings up the dialog (below) again. + // Bug with KEditToolBar. + dialog.showButtonApply (false); + connect (&dialog, SIGNAL (newToolbarConfig ()), + this, SLOT (slotNewToolBarConfig ())); + + dialog.exec (); +} + +// private slot +void kpMainWindow::slotNewToolBarConfig () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotNewToolBarConfig()" << endl; +#endif + + // Wouldn't it be nice if createGUI () didn't nuke all the KToolBar's? + // (including my non-XMLGUI ones whose states take a _lot_ of effort to + // restore). + // TODO: this message is probably unacceptable - so restore the state of + // my toolbars instead. + KMessageBox::information (this, + i18n ("You have to restart KolourPaint for these changes to take effect."), + i18n ("Toolbar Settings Changed"), + QString::fromLatin1 ("ToolBarSettingsChanged")); + + //createGUI(); + //applyMainWindowSettings (kapp->config (), autoSaveGroup ()); +} + + +// private slot +void kpMainWindow::slotConfigure () +{ + // TODO +} diff --git a/kolourpaint/kpmainwindow_statusbar.cpp b/kolourpaint/kpmainwindow_statusbar.cpp new file mode 100644 index 00000000..ed854604 --- /dev/null +++ b/kolourpaint/kpmainwindow_statusbar.cpp @@ -0,0 +1,417 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_STATUS_BAR (DEBUG_KP_MAIN_WINDOW && 0) + + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +// private +void kpMainWindow::addPermanentStatusBarItem (int id, int maxTextLen) +{ + KStatusBar *sb = statusBar (); + + QString textWithMaxLen; + textWithMaxLen.fill (QString::number (8/*big fat*/).at (0), + maxTextLen); //+ 2/*spaces on either side*/); + + sb->insertFixedItem (textWithMaxLen, id, true/*permanent, place on the right*/); + sb->changeItem (QString::null, id); +} + +// private +void kpMainWindow::createStatusBar () +{ + KStatusBar *sb = statusBar (); + + // 9999 pixels "ought to be enough for anybody" + const int maxDimenLength = 4; + + //sb->insertItem (QString::null, StatusBarItemMessage, 1/*stretch*/); + //sb->setItemAlignment (StatusBarItemMessage, Qt::AlignLeft | Qt::AlignVCenter); + + m_statusBarMessageLabel = new kpSqueezedTextLabel (sb); + //m_statusBarMessageLabel->setShowEllipsis (false); + sb->addWidget (m_statusBarMessageLabel, 1/*stretch*/); + + addPermanentStatusBarItem (StatusBarItemShapePoints, + (maxDimenLength + 1/*,*/ + maxDimenLength) * 2 + 3/* - */); + addPermanentStatusBarItem (StatusBarItemShapeSize, + (1/*+/-*/ + maxDimenLength) * 2 + 1/*x*/); + + addPermanentStatusBarItem (StatusBarItemDocSize, + maxDimenLength + 1/*x*/ + maxDimenLength); + addPermanentStatusBarItem (StatusBarItemDocDepth, + 5/*XXbpp*/); + + addPermanentStatusBarItem (StatusBarItemZoom, + 5/*1600%*/); + + m_statusBarShapeLastPointsInitialised = false; + m_statusBarShapeLastSizeInitialised = false; + m_statusBarCreated = true; +} + + + +// private slot +void kpMainWindow::setStatusBarMessage (const QString &message) +{ +#if DEBUG_STATUS_BAR && 1 + kdDebug () << "kpMainWindow::setStatusBarMessage(" + << message + << ") ok=" << m_statusBarCreated + << endl; +#endif + + if (!m_statusBarCreated) + return; + + //statusBar ()->changeItem (message, StatusBarItemMessage); + m_statusBarMessageLabel->setText (message); +} + +// private slot +void kpMainWindow::setStatusBarShapePoints (const QPoint &startPoint, + const QPoint &endPoint) +{ +#if DEBUG_STATUS_BAR && 0 + kdDebug () << "kpMainWindow::setStatusBarShapePoints(" + << startPoint << "," << endPoint + << ") ok=" << m_statusBarCreated + << endl; +#endif + + if (!m_statusBarCreated) + return; + + if (m_statusBarShapeLastPointsInitialised && + startPoint == m_statusBarShapeLastStartPoint && + endPoint == m_statusBarShapeLastEndPoint) + { + #if DEBUG_STATUS_BAR && 0 + kdDebug () << "\tNOP" << endl; + #endif + return; + } + + if (startPoint == KP_INVALID_POINT) + { + statusBar ()->changeItem (QString::null, StatusBarItemShapePoints); + } + else if (endPoint == KP_INVALID_POINT) + { + statusBar ()->changeItem (i18n ("%1,%2") + .arg (startPoint.x ()) + .arg (startPoint.y ()), + StatusBarItemShapePoints); + } + else + { + statusBar ()->changeItem (i18n ("%1,%2 - %3,%4") + .arg (startPoint.x ()) + .arg (startPoint.y ()) + .arg (endPoint.x ()) + .arg (endPoint.y ()), + StatusBarItemShapePoints); + } + + m_statusBarShapeLastStartPoint = startPoint; + m_statusBarShapeLastEndPoint = endPoint; + m_statusBarShapeLastPointsInitialised = true; +} + +// private slot +void kpMainWindow::setStatusBarShapeSize (const QSize &size) +{ +#if DEBUG_STATUS_BAR && 0 + kdDebug () << "kpMainWindow::setStatusBarShapeSize(" + << size + << ") ok=" << m_statusBarCreated + << endl; +#endif + + if (!m_statusBarCreated) + return; + + if (m_statusBarShapeLastSizeInitialised && + size == m_statusBarShapeLastSize) + { + #if DEBUG_STATUS_BAR && 0 + kdDebug () << "\tNOP" << endl; + #endif + return; + } + + if (size == KP_INVALID_SIZE) + { + statusBar ()->changeItem (QString::null, StatusBarItemShapeSize); + } + else + { + statusBar ()->changeItem (i18n ("%1x%2") + .arg (size.width ()) + .arg (size.height ()), + StatusBarItemShapeSize); + } + + m_statusBarShapeLastSize = size; + m_statusBarShapeLastSizeInitialised = true; +} + +// private slot +void kpMainWindow::setStatusBarDocSize (const QSize &size) +{ +#if DEBUG_STATUS_BAR && 0 + kdDebug () << "kpMainWindow::setStatusBarDocSize(" + << size + << ") ok=" << m_statusBarCreated + << endl; +#endif + + if (!m_statusBarCreated) + return; + + if (size == KP_INVALID_SIZE) + { + statusBar ()->changeItem (QString::null, StatusBarItemDocSize); + } + else + { + statusBar ()->changeItem (i18n ("%1x%2") + .arg (size.width ()) + .arg (size.height ()), + StatusBarItemDocSize); + } +} + +// private slot +void kpMainWindow::setStatusBarDocDepth (int depth) +{ +#if DEBUG_STATUS_BAR && 0 + kdDebug () << "kpMainWindow::setStatusBarDocDepth(" + << depth + << ") ok=" << m_statusBarCreated + << endl; +#endif + + if (!m_statusBarCreated) + return; + + if (depth <= 0) + { + statusBar ()->changeItem (QString::null, StatusBarItemDocDepth); + } + else + { + statusBar ()->changeItem (i18n ("%1bpp").arg (depth), + StatusBarItemDocDepth); + } +} + +// private slot +void kpMainWindow::setStatusBarZoom (int zoom) +{ +#if DEBUG_STATUS_BAR && 0 + kdDebug () << "kpMainWindow::setStatusBarZoom(" + << zoom + << ") ok=" << m_statusBarCreated + << endl; +#endif + + if (!m_statusBarCreated) + return; + + if (zoom <= 0) + { + statusBar ()->changeItem (QString::null, StatusBarItemZoom); + } + else + { + statusBar ()->changeItem (i18n ("%1%").arg (zoom), + StatusBarItemZoom); + } +} + +void kpMainWindow::recalculateStatusBarMessage () +{ +#if DEBUG_STATUS_BAR && 1 + kdDebug () << "kpMainWindow::recalculateStatusBarMessage()" << endl; +#endif + QString scrollViewMessage = m_scrollView->statusMessage (); +#if DEBUG_STATUS_BAR && 1 + kdDebug () << "\tscrollViewMessage=" << scrollViewMessage << endl; + kdDebug () << "\tresizing doc? " << !m_scrollView->newDocSize ().isEmpty () + << endl; + kdDebug () << "\tviewUnderCursor? " + << (m_viewManager && m_viewManager->viewUnderCursor ()) + << endl; +#endif + + // HACK: To work around kpViewScrollableContainer's unreliable + // status messages (which in turn is due to Qt not updating + // QWidget::hasMouse() on drags and we needing to hack around it) + if (!scrollViewMessage.isEmpty () && + m_scrollView->newDocSize ().isEmpty () && + m_viewManager && m_viewManager->viewUnderCursor ()) + { + #if DEBUG_STATUS_BAR && 1 + kdDebug () << "\t\tnot resizing & viewUnderCursor - message is wrong - clearing" + << endl; + #endif + m_scrollView->blockSignals (true); + m_scrollView->clearStatusMessage (); + m_scrollView->blockSignals (false); + + scrollViewMessage = QString::null; + #if DEBUG_STATUS_BAR && 1 + kdDebug () << "\t\t\tdone" << endl; + #endif + } + + if (!scrollViewMessage.isEmpty ()) + { + setStatusBarMessage (scrollViewMessage); + } + else + { + const kpTool *t = tool (); + if (t) + { + setStatusBarMessage (t->userMessage ()); + } + else + { + setStatusBarMessage (); + } + } +} + +// private slot +void kpMainWindow::recalculateStatusBarShape () +{ +#if DEBUG_STATUS_BAR && 0 + kdDebug () << "kpMainWindow::recalculateStatusBarShape()" << endl; +#endif + + QSize docResizeTo = m_scrollView->newDocSize (); +#if DEBUG_STATUS_BAR && 0 + kdDebug () << "\tdocResizeTo=" << docResizeTo << endl; +#endif + if (docResizeTo.isValid ()) + { + const QPoint startPoint (m_document->width (), m_document->height ()); + #if DEBUG_STATUS_BAR && 0 + kdDebug () << "\thavedMovedFromOrgSize=" + << m_scrollView->haveMovedFromOriginalDocSize () << endl; + #endif + if (!m_scrollView->haveMovedFromOriginalDocSize ()) + { + setStatusBarShapePoints (startPoint); + setStatusBarShapeSize (); + } + else + { + const int newWidth = docResizeTo.width (); + const int newHeight = docResizeTo.height (); + + setStatusBarShapePoints (startPoint, QPoint (newWidth, newHeight)); + const QPoint sizeAsPoint (QPoint (newWidth, newHeight) - startPoint); + setStatusBarShapeSize (QSize (sizeAsPoint.x (), sizeAsPoint.y ())); + } + } + else + { + const kpTool *t = tool (); + #if DEBUG_STATUS_BAR && 0 + kdDebug () << "\ttool=" << t << endl; + #endif + if (t) + { + setStatusBarShapePoints (t->userShapeStartPoint (), + t->userShapeEndPoint ()); + setStatusBarShapeSize (t->userShapeSize ()); + } + else + { + setStatusBarShapePoints (); + setStatusBarShapeSize (); + } + } +} + +// private slot +void kpMainWindow::recalculateStatusBar () +{ +#if DEBUG_STATUS_BAR && 1 + kdDebug () << "kpMainWindow::recalculateStatusBar() ok=" + << m_statusBarCreated + << endl; +#endif + + if (!m_statusBarCreated) + return; + + recalculateStatusBarMessage (); + recalculateStatusBarShape (); + + if (m_document) + { + setStatusBarDocSize (QSize (m_document->width (), m_document->height ())); + setStatusBarDocDepth (m_document->pixmap ()->depth ()); + } + else + { + setStatusBarDocSize (); + setStatusBarDocDepth (); + } + + if (m_mainView) + { + setStatusBarZoom (m_mainView->zoomLevelX ()); + } + else + { + setStatusBarZoom (); + } +} diff --git a/kolourpaint/kpmainwindow_text.cpp b/kolourpaint/kpmainwindow_text.cpp new file mode 100644 index 00000000..d5694dea --- /dev/null +++ b/kolourpaint/kpmainwindow_text.cpp @@ -0,0 +1,395 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +// private +void kpMainWindow::setupTextToolBarActions () +{ + KActionCollection *ac = actionCollection (); + + m_actionTextFontFamily = new KFontAction (i18n ("Font Family"), 0/*shortcut*/, + this, SLOT (slotTextFontFamilyChanged ()), ac, "text_font_family"); + m_actionTextFontSize = new KFontSizeAction (i18n ("Font Size"), 0/*shortcut*/, + this, SLOT (slotTextFontSizeChanged ()), ac, "text_font_size"); + + m_actionTextBold = new KToggleAction (i18n ("Bold"), + "text_bold"/*icon*/, 0/*shortcut*/, + this, SLOT (slotTextBoldChanged ()), ac, "text_bold"); + m_actionTextItalic = new KToggleAction (i18n ("Italic"), + "text_italic"/*icon*/, 0/*shortcut*/, + this, SLOT (slotTextItalicChanged ()), ac, "text_italic"); + m_actionTextUnderline = new KToggleAction (i18n ("Underline"), + "text_under"/*icon*/, 0/*shortcut*/, + this, SLOT (slotTextUnderlineChanged ()), ac, "text_underline"); + m_actionTextStrikeThru = new KToggleAction (i18n ("Strike Through"), + "text_strike"/*icon*/, 0/*shortcut*/, + this, SLOT (slotTextStrikeThruChanged ()), ac, "text_strike_thru"); + + + readAndApplyTextSettings (); + + + enableTextToolBarActions (false); +} + +// private +void kpMainWindow::readAndApplyTextSettings () +{ + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupText); + KConfigBase *cfg = cfgGroupSaver.config (); + + m_actionTextFontFamily->setFont (cfg->readEntry (kpSettingFontFamily, QString::fromLatin1 ("Times"))); + m_actionTextFontSize->setFontSize (cfg->readNumEntry (kpSettingFontSize, 14)); + m_actionTextBold->setChecked (cfg->readBoolEntry (kpSettingBold, false)); + m_actionTextItalic->setChecked (cfg->readBoolEntry (kpSettingItalic, false)); + m_actionTextUnderline->setChecked (cfg->readBoolEntry (kpSettingUnderline, false)); + m_actionTextStrikeThru->setChecked (cfg->readBoolEntry (kpSettingStrikeThru, false)); + + m_textOldFontFamily = m_actionTextFontFamily->font (); + m_textOldFontSize = m_actionTextFontSize->fontSize (); +} + + +// public +void kpMainWindow::enableTextToolBarActions (bool enable) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::enableTextToolBarActions(" << enable << ")" << endl; +#endif + + m_actionTextFontFamily->setEnabled (enable); + m_actionTextFontSize->setEnabled (enable); + m_actionTextBold->setEnabled (enable); + m_actionTextItalic->setEnabled (enable); + m_actionTextUnderline->setEnabled (enable); + m_actionTextStrikeThru->setEnabled (enable); + + if (textToolBar ()) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\thave toolbar - setShown" << endl; + #endif + textToolBar ()->setShown (enable); + } +} + + +// private slot +void kpMainWindow::slotTextFontFamilyChanged () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotTextFontFamilyChanged() alive=" + << m_isFullyConstructed + << " fontFamily=" + << m_actionTextFontFamily->font () + << endl; +#endif + + if (!m_isFullyConstructed) + return; + + if (m_toolText && m_toolText->hasBegun ()) + { + m_toolText->slotFontFamilyChanged (m_actionTextFontFamily->font (), + m_textOldFontFamily); + } + + // Since editable KSelectAction's steal focus from view, switch back to mainView + // TODO: back to the last view + if (m_mainView) + m_mainView->setFocus (); + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupText); + KConfigBase *cfg = cfgGroupSaver.config (); + cfg->writeEntry (kpSettingFontFamily, m_actionTextFontFamily->font ()); + cfg->sync (); + + m_textOldFontFamily = m_actionTextFontFamily->font (); +} + +// private slot +void kpMainWindow::slotTextFontSizeChanged () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotTextFontSizeChanged() alive=" + << m_isFullyConstructed + << " fontSize=" + << m_actionTextFontSize->fontSize () + << endl; +#endif + + if (!m_isFullyConstructed) + return; + + if (m_toolText && m_toolText->hasBegun ()) + { + m_toolText->slotFontSizeChanged (m_actionTextFontSize->fontSize (), + m_textOldFontSize); + } + + // Since editable KSelectAction's steal focus from view, switch back to mainView + // TODO: back to the last view + if (m_mainView) + m_mainView->setFocus (); + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupText); + KConfigBase *cfg = cfgGroupSaver.config (); + cfg->writeEntry (kpSettingFontSize, m_actionTextFontSize->fontSize ()); + cfg->sync (); + + m_textOldFontSize = m_actionTextFontSize->fontSize (); +} + +// private slot +void kpMainWindow::slotTextBoldChanged () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotTextFontBoldChanged() alive=" + << m_isFullyConstructed + << " bold=" + << m_actionTextBold->isChecked () + << endl; +#endif + + if (!m_isFullyConstructed) + return; + + if (m_toolText && m_toolText->hasBegun ()) + m_toolText->slotBoldChanged (m_actionTextBold->isChecked ()); + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupText); + KConfigBase *cfg = cfgGroupSaver.config (); + cfg->writeEntry (kpSettingBold, m_actionTextBold->isChecked ()); + cfg->sync (); +} + +// private slot +void kpMainWindow::slotTextItalicChanged () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotTextFontItalicChanged() alive=" + << m_isFullyConstructed + << " bold=" + << m_actionTextItalic->isChecked () + << endl; +#endif + + if (!m_isFullyConstructed) + return; + + if (m_toolText && m_toolText->hasBegun ()) + m_toolText->slotItalicChanged (m_actionTextItalic->isChecked ()); + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupText); + KConfigBase *cfg = cfgGroupSaver.config (); + cfg->writeEntry (kpSettingItalic, m_actionTextItalic->isChecked ()); + cfg->sync (); +} + +// private slot +void kpMainWindow::slotTextUnderlineChanged () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotTextFontUnderlineChanged() alive=" + << m_isFullyConstructed + << " underline=" + << m_actionTextUnderline->isChecked () + << endl; +#endif + + if (!m_isFullyConstructed) + return; + + if (m_toolText && m_toolText->hasBegun ()) + m_toolText->slotUnderlineChanged (m_actionTextUnderline->isChecked ()); + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupText); + KConfigBase *cfg = cfgGroupSaver.config (); + cfg->writeEntry (kpSettingUnderline, m_actionTextUnderline->isChecked ()); + cfg->sync (); +} + +// private slot +void kpMainWindow::slotTextStrikeThruChanged () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotTextStrikeThruChanged() alive=" + << m_isFullyConstructed + << " strikeThru=" + << m_actionTextStrikeThru->isChecked () + << endl; +#endif + + if (!m_isFullyConstructed) + return; + + if (m_toolText && m_toolText->hasBegun ()) + m_toolText->slotStrikeThruChanged (m_actionTextStrikeThru->isChecked ()); + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupText); + KConfigBase *cfg = cfgGroupSaver.config (); + cfg->writeEntry (kpSettingStrikeThru, m_actionTextStrikeThru->isChecked ()); + cfg->sync (); +} + + +// public +KToolBar *kpMainWindow::textToolBar () +{ + return toolBar ("textToolBar"); +} + +bool kpMainWindow::isTextStyleBackgroundOpaque () const +{ + if (m_toolToolBar) + { + kpToolWidgetOpaqueOrTransparent *oot = + m_toolToolBar->toolWidgetOpaqueOrTransparent (); + + if (oot) + { + return oot->isOpaque (); + } + } + + return true; +} + +// public +kpTextStyle kpMainWindow::textStyle () const +{ + return kpTextStyle (m_actionTextFontFamily->font (), + m_actionTextFontSize->fontSize (), + m_actionTextBold->isChecked (), + m_actionTextItalic->isChecked (), + m_actionTextUnderline->isChecked (), + m_actionTextStrikeThru->isChecked (), + m_colorToolBar ? m_colorToolBar->foregroundColor () : kpColor::invalid, + m_colorToolBar ? m_colorToolBar->backgroundColor () : kpColor::invalid, + isTextStyleBackgroundOpaque ()); +} + +// public +void kpMainWindow::setTextStyle (const kpTextStyle &textStyle_) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::setTextStyle()" << endl; +#endif + + m_settingTextStyle++; + + + if (textStyle_.fontFamily () != m_actionTextFontFamily->font ()) + { + m_actionTextFontFamily->setFont (textStyle_.fontFamily ()); + slotTextFontFamilyChanged (); + } + + if (textStyle_.fontSize () != m_actionTextFontSize->fontSize ()) + { + m_actionTextFontSize->setFontSize (textStyle_.fontSize ()); + slotTextFontSizeChanged (); + } + + if (textStyle_.isBold () != m_actionTextBold->isChecked ()) + { + m_actionTextBold->setChecked (textStyle_.isBold ()); + slotTextBoldChanged (); + } + + if (textStyle_.isItalic () != m_actionTextItalic->isChecked ()) + { + m_actionTextItalic->setChecked (textStyle_.isItalic ()); + slotTextItalicChanged (); + } + + if (textStyle_.isUnderline () != m_actionTextUnderline->isChecked ()) + { + m_actionTextUnderline->setChecked (textStyle_.isUnderline ()); + slotTextUnderlineChanged (); + } + + if (textStyle_.isStrikeThru () != m_actionTextStrikeThru->isChecked ()) + { + m_actionTextStrikeThru->setChecked (textStyle_.isStrikeThru ()); + slotTextStrikeThruChanged (); + } + + + if (textStyle_.foregroundColor () != m_colorToolBar->foregroundColor ()) + { + m_colorToolBar->setForegroundColor (textStyle_.foregroundColor ()); + } + + if (textStyle_.backgroundColor () != m_colorToolBar->backgroundColor ()) + { + m_colorToolBar->setBackgroundColor (textStyle_.backgroundColor ()); + } + + + if (textStyle_.isBackgroundOpaque () != isTextStyleBackgroundOpaque ()) + { + if (m_toolToolBar) + { + kpToolWidgetOpaqueOrTransparent *oot = + m_toolToolBar->toolWidgetOpaqueOrTransparent (); + + if (oot) + { + oot->setOpaque (textStyle_.isBackgroundOpaque ()); + } + } + } + + + m_settingTextStyle--; +} + +// public +int kpMainWindow::settingTextStyle () const +{ + return m_settingTextStyle; +} + diff --git a/kolourpaint/kpmainwindow_tools.cpp b/kolourpaint/kpmainwindow_tools.cpp new file mode 100644 index 00000000..fb86f91f --- /dev/null +++ b/kolourpaint/kpmainwindow_tools.cpp @@ -0,0 +1,646 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// private +void kpMainWindow::setupToolActions () +{ + m_tools.setAutoDelete (true); + + m_tools.append (m_toolFreeFormSelection = new kpToolFreeFormSelection (this)); + m_tools.append (m_toolRectSelection = new kpToolRectSelection (this)); + + m_tools.append (m_toolEllipticalSelection = new kpToolEllipticalSelection (this)); + m_tools.append (m_toolText = new kpToolText (this)); + + m_tools.append (m_toolLine = new kpToolLine (this)); + m_tools.append (m_toolPen = new kpToolPen (this)); + + m_tools.append (m_toolEraser = new kpToolEraser (this)); + m_tools.append (m_toolBrush = new kpToolBrush (this)); + + m_tools.append (m_toolFloodFill = new kpToolFloodFill (this)); + m_tools.append (m_toolColorPicker = new kpToolColorPicker (this)); + + m_tools.append (m_toolColorWasher = new kpToolColorWasher (this)); + m_tools.append (m_toolAirSpray = new kpToolAirSpray (this)); + + m_tools.append (m_toolRoundedRectangle = new kpToolRoundedRectangle (this)); + m_tools.append (m_toolRectangle = new kpToolRectangle (this)); + + m_tools.append (m_toolPolygon = new kpToolPolygon (this)); + m_tools.append (m_toolEllipse = new kpToolEllipse (this)); + + m_tools.append (m_toolPolyline = new kpToolPolyline (this)); + m_tools.append (m_toolCurve = new kpToolCurve (this)); + + + KActionCollection *ac = actionCollection (); + + m_actionPrevToolOptionGroup1 = new kpSingleKeyTriggersAction ( + i18n ("Previous Tool Option (Group #1)"), + kpTool::shortcutForKey (Qt::Key_1), + this, SLOT (slotActionPrevToolOptionGroup1 ()), + ac, "prev_tool_option_group_1"); + m_actionNextToolOptionGroup1 = new kpSingleKeyTriggersAction ( + i18n ("Next Tool Option (Group #1)"), + kpTool::shortcutForKey (Qt::Key_2), + this, SLOT (slotActionNextToolOptionGroup1 ()), + ac, "next_tool_option_group_1"); + + m_actionPrevToolOptionGroup2 = new kpSingleKeyTriggersAction ( + i18n ("Previous Tool Option (Group #2)"), + kpTool::shortcutForKey (Qt::Key_3), + this, SLOT (slotActionPrevToolOptionGroup2 ()), + ac, "prev_tool_option_group_2"); + m_actionNextToolOptionGroup2 = new kpSingleKeyTriggersAction ( + i18n ("Next Tool Option (Group #2)"), + kpTool::shortcutForKey (Qt::Key_4), + this, SLOT (slotActionNextToolOptionGroup2 ()), + ac, "next_tool_option_group_2"); +} + +// private +void kpMainWindow::createToolBox () +{ + m_toolToolBar = new kpToolToolBar (i18n ("Tool Box"), this, 2/*columns/rows*/, "Tool Box"); + connect (m_toolToolBar, SIGNAL (sigToolSelected (kpTool *)), + this, SLOT (slotToolSelected (kpTool *))); + connect (m_toolToolBar, SIGNAL (toolWidgetOptionSelected ()), + this, SLOT (updateToolOptionPrevNextActionsEnabled ())); + + for (QPtrList ::const_iterator it = m_tools.begin (); + it != m_tools.end (); + it++) + { + m_toolToolBar->registerTool (*it); + } + + + // (from config file) + readLastTool (); + + + enableToolsDocumentActions (false); +} + +// private +void kpMainWindow::enableToolsDocumentActions (bool enable) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::enableToolsDocumentsAction(" << enable << ")" << endl; +#endif + + m_toolActionsEnabled = enable; + + + if (enable && !m_toolToolBar->isEnabled ()) + { + kpTool *previousTool = m_toolToolBar->previousTool (); + + // select tool for enabled Tool Box + + if (previousTool) + m_toolToolBar->selectPreviousTool (); + else + { + if (m_lastToolNumber >= 0 && m_lastToolNumber < (int) m_tools.count ()) + m_toolToolBar->selectTool (m_tools.at (m_lastToolNumber)); + else + m_toolToolBar->selectTool (m_toolPen); + } + } + else if (!enable && m_toolToolBar->isEnabled ()) + { + // don't have a disabled Tool Box with an enabled Tool + m_toolToolBar->selectTool (0); + } + + + m_toolToolBar->setEnabled (enable); + + + for (QPtrList ::const_iterator it = m_tools.begin (); + it != m_tools.end (); + it++) + { + kpToolAction *action = (*it)->action (); + if (action) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tchanging enabled state of " << (*it)->name () << endl; + #endif + + if (!enable && action->isChecked ()) + action->setChecked (false); + + action->setEnabled (enable); + } + else + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tno action for " << (*it)->name () << endl; + #endif + } + } + + + updateToolOptionPrevNextActionsEnabled (); +} + +// private slot +void kpMainWindow::updateToolOptionPrevNextActionsEnabled () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::updateToolOptionPrevNextActionsEnabled()" + << " numShownToolWidgets=" + << m_toolToolBar->numShownToolWidgets () + << endl; +#endif + + const bool enable = m_toolActionsEnabled; + + + m_actionPrevToolOptionGroup1->setEnabled (enable && + m_toolToolBar->shownToolWidget (0) && + m_toolToolBar->shownToolWidget (0)->hasPreviousOption ()); + m_actionNextToolOptionGroup1->setEnabled (enable && + m_toolToolBar->shownToolWidget (0) && + m_toolToolBar->shownToolWidget (0)->hasNextOption ()); + + m_actionPrevToolOptionGroup2->setEnabled (enable && + m_toolToolBar->shownToolWidget (1) && + m_toolToolBar->shownToolWidget (1)->hasPreviousOption ()); + m_actionNextToolOptionGroup2->setEnabled (enable && + m_toolToolBar->shownToolWidget (1) && + m_toolToolBar->shownToolWidget (1)->hasNextOption ()); +} + + +// public +kpTool *kpMainWindow::tool () const +{ + return m_toolToolBar ? m_toolToolBar->tool () : 0; +} + +// public +bool kpMainWindow::toolHasBegunShape () const +{ + kpTool *currentTool = tool (); + return (currentTool && currentTool->hasBegunShape ()); +} + +// public +bool kpMainWindow::toolIsASelectionTool (bool includingTextTool) const +{ + kpTool *currentTool = tool (); + + return ((currentTool == m_toolFreeFormSelection) || + (currentTool == m_toolRectSelection) || + (currentTool == m_toolEllipticalSelection) || + (currentTool == m_toolText && includingTextTool)); +} + +// public +bool kpMainWindow::toolIsTextTool () const +{ + return (tool () == m_toolText); +} + + +// public +kpSelectionTransparency kpMainWindow::selectionTransparency () const +{ + kpToolWidgetOpaqueOrTransparent *oot = m_toolToolBar->toolWidgetOpaqueOrTransparent (); + if (!oot) + { + kdError () << "kpMainWindow::selectionTransparency() without opaqueOrTransparent widget" << endl; + return kpSelectionTransparency (); + } + + return kpSelectionTransparency (oot->isOpaque (), backgroundColor (), m_colorToolBar->colorSimilarity ()); +} + +// public +void kpMainWindow::setSelectionTransparency (const kpSelectionTransparency &transparency, bool forceColorChange) +{ +#if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "kpMainWindow::setSelectionTransparency() isOpaque=" << transparency.isOpaque () + << " color=" << (transparency.transparentColor ().isValid () ? (int *) transparency.transparentColor ().toQRgb () : 0) + << " forceColorChange=" << forceColorChange + << endl; +#endif + + kpToolWidgetOpaqueOrTransparent *oot = m_toolToolBar->toolWidgetOpaqueOrTransparent (); + if (!oot) + { + kdError () << "kpMainWindow::setSelectionTransparency() without opaqueOrTransparent widget" << endl; + return; + } + + m_settingSelectionTransparency++; + + oot->setOpaque (transparency.isOpaque ()); + if (transparency.isTransparent () || forceColorChange) + { + m_colorToolBar->setColor (1, transparency.transparentColor ()); + m_colorToolBar->setColorSimilarity (transparency.colorSimilarity ()); + } + + m_settingSelectionTransparency--; +} + +// public +int kpMainWindow::settingSelectionTransparency () const +{ + return m_settingSelectionTransparency; +} + + +// private slot +void kpMainWindow::slotToolSelected (kpTool *tool) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotToolSelected (" << tool << ")" << endl; +#endif + + kpTool *previousTool = m_toolToolBar ? m_toolToolBar->previousTool () : 0; + + if (previousTool) + { + disconnect (previousTool, SIGNAL (movedAndAboutToDraw (const QPoint &, const QPoint &, int, bool *)), + this, SLOT (slotDragScroll (const QPoint &, const QPoint &, int, bool *))); + disconnect (previousTool, SIGNAL (endedDraw (const QPoint &)), + this, SLOT (slotEndDragScroll ())); + disconnect (previousTool, SIGNAL (cancelledShape (const QPoint &)), + this, SLOT (slotEndDragScroll ())); + + disconnect (previousTool, SIGNAL (userMessageChanged (const QString &)), + this, SLOT (recalculateStatusBarMessage ())); + disconnect (previousTool, SIGNAL (userShapePointsChanged (const QPoint &, const QPoint &)), + this, SLOT (recalculateStatusBarShape ())); + disconnect (previousTool, SIGNAL (userShapeSizeChanged (const QSize &)), + this, SLOT (recalculateStatusBarShape ())); + + disconnect (m_colorToolBar, SIGNAL (colorsSwapped (const kpColor &, const kpColor &)), + previousTool, SLOT (slotColorsSwappedInternal (const kpColor &, const kpColor &))); + disconnect (m_colorToolBar, SIGNAL (foregroundColorChanged (const kpColor &)), + previousTool, SLOT (slotForegroundColorChangedInternal (const kpColor &))); + disconnect (m_colorToolBar, SIGNAL (backgroundColorChanged (const kpColor &)), + previousTool, SLOT (slotBackgroundColorChangedInternal (const kpColor &))); + disconnect (m_colorToolBar, SIGNAL (colorSimilarityChanged (double, int)), + previousTool, SLOT (slotColorSimilarityChangedInternal (double, int))); + } + + if (tool) + { + connect (tool, SIGNAL (movedAndAboutToDraw (const QPoint &, const QPoint &, int, bool *)), + this, SLOT (slotDragScroll (const QPoint &, const QPoint &, int, bool *))); + connect (tool, SIGNAL (endedDraw (const QPoint &)), + this, SLOT (slotEndDragScroll ())); + connect (tool, SIGNAL (cancelledShape (const QPoint &)), + this, SLOT (slotEndDragScroll ())); + + connect (tool, SIGNAL (userMessageChanged (const QString &)), + this, SLOT (recalculateStatusBarMessage ())); + connect (tool, SIGNAL (userShapePointsChanged (const QPoint &, const QPoint &)), + this, SLOT (recalculateStatusBarShape ())); + connect (tool, SIGNAL (userShapeSizeChanged (const QSize &)), + this, SLOT (recalculateStatusBarShape ())); + recalculateStatusBar (); + + connect (m_colorToolBar, SIGNAL (colorsSwapped (const kpColor &, const kpColor &)), + tool, SLOT (slotColorsSwappedInternal (const kpColor &, const kpColor &))); + connect (m_colorToolBar, SIGNAL (foregroundColorChanged (const kpColor &)), + tool, SLOT (slotForegroundColorChangedInternal (const kpColor &))); + connect (m_colorToolBar, SIGNAL (backgroundColorChanged (const kpColor &)), + tool, SLOT (slotBackgroundColorChangedInternal (const kpColor &))); + connect (m_colorToolBar, SIGNAL (colorSimilarityChanged (double, int)), + tool, SLOT (slotColorSimilarityChangedInternal (double, int))); + + + saveLastTool (); + } + + updateToolOptionPrevNextActionsEnabled (); +} + + +// private +void kpMainWindow::readLastTool () +{ + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupTools); + KConfigBase *cfg = cfgGroupSaver.config (); + + m_lastToolNumber = cfg->readNumEntry (kpSettingLastTool, -1); +} + + +// private +int kpMainWindow::toolNumber () const +{ + int number = 0; + for (QPtrList ::const_iterator it = m_tools.begin (); + it != m_tools.end (); + it++) + { + if (*it == tool ()) + return number; + + number++; + } + + return -1; +} + +// private +void kpMainWindow::saveLastTool () +{ + int number = toolNumber (); + if (number < 0 || number >= (int) m_tools.count ()) + return; + + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupTools); + KConfigBase *cfg = cfgGroupSaver.config (); + + cfg->writeEntry (kpSettingLastTool, number); + cfg->sync (); +} + + +// private +bool kpMainWindow::maybeDragScrollingMainView () const +{ + return (tool () && m_mainView && + tool ()->viewUnderStartPoint () == m_mainView); +} + +// private slot +bool kpMainWindow::slotDragScroll (const QPoint &docPoint, + const QPoint &docLastPoint, + int zoomLevel, + bool *scrolled) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotDragScroll() maybeDragScrolling=" + << maybeDragScrollingMainView () + << endl; +#endif + + if (maybeDragScrollingMainView ()) + { + return m_scrollView->beginDragScroll (docPoint, docLastPoint, zoomLevel, scrolled); + } + else + { + return false; + } +} + +// private slot +bool kpMainWindow::slotEndDragScroll () +{ + // (harmless if haven't started drag scroll) + return m_scrollView->endDragScroll (); +} + + +// private slot +void kpMainWindow::slotBeganDocResize () +{ + if (toolHasBegunShape ()) + tool ()->endShapeInternal (); + + recalculateStatusBarShape (); +} + +// private slot +void kpMainWindow::slotContinuedDocResize (const QSize &) +{ + recalculateStatusBarShape (); +} + +// private slot +void kpMainWindow::slotCancelledDocResize () +{ + recalculateStatusBar (); +} + +// private slot +void kpMainWindow::slotEndedDocResize (const QSize &size) +{ +#define DOC_RESIZE_COMPLETED() \ +{ \ + m_docResizeToBeCompleted = false; \ + recalculateStatusBar (); \ +} + + // Prevent statusbar updates + m_docResizeToBeCompleted = true; + + m_docResizeWidth = (size.width () > 0 ? size.width () : 1), + m_docResizeHeight = (size.height () > 0 ? size.height () : 1); + + if (m_docResizeWidth == m_document->width () && + m_docResizeHeight == m_document->height ()) + { + DOC_RESIZE_COMPLETED (); + return; + } + + + // Blank status to avoid confusion if dialog comes up + setStatusBarMessage (); + setStatusBarShapePoints (); + setStatusBarShapeSize (); + + + if (kpTool::warnIfBigImageSize (m_document->width (), + m_document->height (), + m_docResizeWidth, m_docResizeHeight, + i18n ("

Resizing the image to" + " %1x%2 may take a substantial amount of memory." + " This can reduce system" + " responsiveness and cause other application resource" + " problems.

" + + "

Are you sure want to resize the" + " image?

") + .arg (m_docResizeWidth) + .arg (m_docResizeHeight), + i18n ("Resize Image?"), + i18n ("R&esize Image"), + this)) + { + m_commandHistory->addCommand ( + new kpToolResizeScaleCommand ( + false/*doc, not sel*/, + m_docResizeWidth, m_docResizeHeight, + kpToolResizeScaleCommand::Resize, + this)); + + saveDefaultDocSize (QSize (m_docResizeWidth, m_docResizeHeight)); + } + + + DOC_RESIZE_COMPLETED (); + +#undef DOC_RESIZE_COMPLETED +} + +// private slot +void kpMainWindow::slotDocResizeMessageChanged (const QString &string) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotDocResizeMessageChanged(" << string + << ") docResizeToBeCompleted=" << m_docResizeToBeCompleted + << endl; +#else + (void) string; +#endif + + if (m_docResizeToBeCompleted) + return; + + recalculateStatusBarMessage (); +} + + +// private slot +void kpMainWindow::slotActionPrevToolOptionGroup1 () +{ + if (!m_toolToolBar->shownToolWidget (0)) + return; + + m_toolToolBar->shownToolWidget (0)->selectPreviousOption (); + updateToolOptionPrevNextActionsEnabled (); +} + +// private slot +void kpMainWindow::slotActionNextToolOptionGroup1 () +{ + if (!m_toolToolBar->shownToolWidget (0)) + return; + + m_toolToolBar->shownToolWidget (0)->selectNextOption (); + updateToolOptionPrevNextActionsEnabled (); +} + + +// private slot +void kpMainWindow::slotActionPrevToolOptionGroup2 () +{ + if (!m_toolToolBar->shownToolWidget (1)) + return; + + m_toolToolBar->shownToolWidget (1)->selectPreviousOption (); + updateToolOptionPrevNextActionsEnabled (); +} + +// private slot +void kpMainWindow::slotActionNextToolOptionGroup2 () +{ + if (!m_toolToolBar->shownToolWidget (1)) + return; + + m_toolToolBar->shownToolWidget (1)->selectNextOption (); + updateToolOptionPrevNextActionsEnabled (); +} + + +// public slots + +#define SLOT_TOOL(toolName) \ +void kpMainWindow::slotTool##toolName () \ +{ \ + if (!m_toolToolBar) \ + return; \ + \ + if (tool () == m_tool##toolName) \ + return; \ + \ + m_toolToolBar->selectTool (m_tool##toolName); \ +} + +SLOT_TOOL (AirSpray) +SLOT_TOOL (Brush) +SLOT_TOOL (ColorPicker) +SLOT_TOOL (ColorWasher) +SLOT_TOOL (Curve) +SLOT_TOOL (Ellipse) +SLOT_TOOL (EllipticalSelection) +SLOT_TOOL (Eraser) +SLOT_TOOL (FloodFill) +SLOT_TOOL (FreeFormSelection) +SLOT_TOOL (Line) +SLOT_TOOL (Pen) +SLOT_TOOL (Polygon) +SLOT_TOOL (Polyline) +SLOT_TOOL (Rectangle) +SLOT_TOOL (RectSelection) +SLOT_TOOL (RoundedRectangle) +SLOT_TOOL (Text) diff --git a/kolourpaint/kpmainwindow_view.cpp b/kolourpaint/kpmainwindow_view.cpp new file mode 100644 index 00000000..1aa9b5dc --- /dev/null +++ b/kolourpaint/kpmainwindow_view.cpp @@ -0,0 +1,1151 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_ZOOM_FLICKER 0 + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// private +void kpMainWindow::setupViewMenuActions () +{ + m_viewMenuDocumentActionsEnabled = false; + m_thumbnailSaveConfigTimer = 0; + + + KActionCollection *ac = actionCollection (); + + /*m_actionFullScreen = KStdAction::fullScreen (0, 0, ac); + m_actionFullScreen->setEnabled (false);*/ + + + m_actionActualSize = KStdAction::actualSize (this, SLOT (slotActualSize ()), ac); + /*m_actionFitToPage = KStdAction::fitToPage (this, SLOT (slotFitToPage ()), ac); + m_actionFitToWidth = KStdAction::fitToWidth (this, SLOT (slotFitToWidth ()), ac); + m_actionFitToHeight = KStdAction::fitToHeight (this, SLOT (slotFitToHeight ()), ac);*/ + + + m_actionZoomIn = KStdAction::zoomIn (this, SLOT (slotZoomIn ()), ac); + m_actionZoomOut = KStdAction::zoomOut (this, SLOT (slotZoomOut ()), ac); + + + m_actionZoom = new KSelectAction (i18n ("&Zoom"), 0, + this, SLOT (slotZoom ()), actionCollection (), "view_zoom_to"); + m_actionZoom->setEditable (true); + + // create the zoom list for the 1st call to zoomTo() below + m_zoomList.append (10); m_zoomList.append (25); m_zoomList.append (33); + m_zoomList.append (50); m_zoomList.append (67); m_zoomList.append (75); + m_zoomList.append (100); + m_zoomList.append (200); m_zoomList.append (300); + m_zoomList.append (400); m_zoomList.append (600); m_zoomList.append (800); + m_zoomList.append (1000); m_zoomList.append (1200); m_zoomList.append (1600); + + + m_actionShowGrid = new KToggleAction (i18n ("Show &Grid"), CTRL + Key_G, + this, SLOT (slotShowGridToggled ()), actionCollection (), "view_show_grid"); + m_actionShowGrid->setCheckedState (i18n ("Hide &Grid")); + + + // TODO: This doesn't work when the thumbnail has focus. + // Testcase: Press CTRL+H twice on a fresh KolourPaint. + // The second CTRL+H doesn't close the thumbnail. + m_actionShowThumbnail = new KToggleAction (i18n ("Show T&humbnail"), CTRL + Key_H, + this, SLOT (slotShowThumbnailToggled ()), actionCollection (), "view_show_thumbnail"); + m_actionShowThumbnail->setCheckedState (i18n ("Hide T&humbnail")); + + // Please do not use setCheckedState() here - it wouldn't make sense + m_actionZoomedThumbnail = new KToggleAction (i18n ("Zoo&med Thumbnail Mode"), 0, + this, SLOT (slotZoomedThumbnailToggled ()), actionCollection (), "view_zoomed_thumbnail"); + + // For consistency with the above action, don't use setCheckedState() + // + // Also, don't use "Show Thumbnail Rectangle" because if entire doc + // can be seen in scrollView, checking option won't "Show" anything + // since rect _surrounds_ entire doc (hence, won't be rendered). + d->m_actionShowThumbnailRectangle = new KToggleAction ( + i18n ("Enable Thumbnail &Rectangle"), + 0, + this, SLOT (slotThumbnailShowRectangleToggled ()), + actionCollection (), "view_show_thumbnail_rectangle"); + + + enableViewMenuDocumentActions (false); +} + +// private +bool kpMainWindow::viewMenuDocumentActionsEnabled () const +{ + return m_viewMenuDocumentActionsEnabled; +} + +// private +void kpMainWindow::enableViewMenuDocumentActions (bool enable) +{ + m_viewMenuDocumentActionsEnabled = enable; + + + m_actionActualSize->setEnabled (enable); + /*m_actionFitToPage->setEnabled (enable); + m_actionFitToWidth->setEnabled (enable); + m_actionFitToHeight->setEnabled (enable);*/ + + m_actionZoomIn->setEnabled (enable); + m_actionZoomOut->setEnabled (enable); + + m_actionZoom->setEnabled (enable); + + actionShowGridUpdate (); + + m_actionShowThumbnail->setEnabled (enable); + enableThumbnailOptionActions (enable); + + + // TODO: for the time being, assume that we start at zoom 100% + // with no grid + + // This function is only called when a new document is created + // or an existing document is closed. So the following will + // always be correct: + + zoomTo (100); +} + +// private +void kpMainWindow::actionShowGridUpdate () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::actionShowGridUpdate()" << endl; +#endif + const bool enable = (viewMenuDocumentActionsEnabled () && + m_mainView && m_mainView->canShowGrid ()); + + m_actionShowGrid->setEnabled (enable); + m_actionShowGrid->setChecked (enable && m_configShowGrid); +} + + +// private +void kpMainWindow::sendZoomListToActionZoom () +{ + QStringList items; + + const QValueVector ::ConstIterator zoomListEnd (m_zoomList.end ()); + for (QValueVector ::ConstIterator it = m_zoomList.begin (); + it != zoomListEnd; + it++) + { + items << zoomLevelToString (*it); + } + + // Work around a KDE bug - KSelectAction::setItems() enables the action. + // David Faure said it won't be fixed because it's a feature used by + // KRecentFilesAction. + bool e = m_actionZoom->isEnabled (); + m_actionZoom->setItems (items); + if (e != m_actionZoom->isEnabled ()) + m_actionZoom->setEnabled (e); +} + +// private +int kpMainWindow::zoomLevelFromString (const QString &string) +{ + // loop until not digit + int i; + for (i = 0; i < (int) string.length () && string.at (i).isDigit (); i++) + ; + + // convert zoom level to number + bool ok = false; + int zoomLevel = string.left (i).toInt (&ok); + + if (!ok || zoomLevel <= 0 || zoomLevel > 3200) + return 0; // error + else + return zoomLevel; +} + +// private +QString kpMainWindow::zoomLevelToString (int zoomLevel) +{ + return i18n ("%1%").arg (zoomLevel); +} + +// private +void kpMainWindow::zoomTo (int zoomLevel, bool centerUnderCursor) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::zoomTo (" << zoomLevel << ")" << endl; +#endif + + if (zoomLevel <= 0) + zoomLevel = m_mainView ? m_mainView->zoomLevelX () : 100; + +// mute point since the thumbnail suffers from this too +#if 0 + else if (m_mainView && m_mainView->zoomLevelX () % 100 == 0 && zoomLevel % 100) + { + if (KMessageBox::warningContinueCancel (this, + i18n ("Setting the zoom level to a value that is not a multiple of 100% " + "results in imprecise editing and redraw glitches.\n" + "Do you really want to set to zoom level to %1%?") + .arg (zoomLevel), + QString::null/*caption*/, + i18n ("Set Zoom Level to %1%").arg (zoomLevel), + "DoNotAskAgain_ZoomLevelNotMultipleOf100") != KMessageBox::Continue) + { + zoomLevel = m_mainView->zoomLevelX (); + } + } +#endif + + int index = 0; + QValueVector ::Iterator it = m_zoomList.begin (); + + while (index < (int) m_zoomList.count () && zoomLevel > *it) + it++, index++; + + if (zoomLevel != *it) + m_zoomList.insert (it, zoomLevel); + + sendZoomListToActionZoom (); + m_actionZoom->setCurrentItem (index); + + + if (viewMenuDocumentActionsEnabled ()) + { + m_actionActualSize->setEnabled (zoomLevel != 100); + + m_actionZoomIn->setEnabled (m_actionZoom->currentItem () < (int) m_zoomList.count () - 1); + m_actionZoomOut->setEnabled (m_actionZoom->currentItem () > 0); + } + + + if (m_viewManager) + m_viewManager->setQueueUpdates (); + + + if (m_scrollView) + { + m_scrollView->setUpdatesEnabled (false); + if (m_scrollView->viewport ()) + m_scrollView->viewport ()->setUpdatesEnabled (false); + } + + if (m_mainView) + { + m_mainView->setUpdatesEnabled (false); + + if (m_scrollView && m_scrollView->viewport ()) + { + // Ordinary flicker is better than the whole view moving + QPainter p (m_mainView); + p.fillRect (m_mainView->rect (), + m_scrollView->viewport ()->colorGroup ().background ()); + } + } + + + if (m_scrollView && m_mainView) + { + #if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "\tscrollView contentsX=" << m_scrollView->contentsX () + << " contentsY=" << m_scrollView->contentsY () + << " contentsWidth=" << m_scrollView->contentsWidth () + << " contentsHeight=" << m_scrollView->contentsHeight () + << " visibleWidth=" << m_scrollView->visibleWidth () + << " visibleHeight=" << m_scrollView->visibleHeight () + << " oldZoomX=" << m_mainView->zoomLevelX () + << " oldZoomY=" << m_mainView->zoomLevelY () + << " newZoom=" << zoomLevel + << " mainViewX=" << m_scrollView->childX (m_mainView) + << " mainViewY=" << m_scrollView->childY (m_mainView) + << endl; + #endif + + // TODO: when changing from no scrollbars to scrollbars, Qt lies about + // visibleWidth() & visibleHeight() (doesn't take into account the + // space taken by the would-be scrollbars) until it updates the + // scrollview; hence the centring is off by about 5-10 pixels. + + // TODO: use visibleRect() for greater accuracy? + + int viewX, viewY; + + bool targetDocAvail = false; + double targetDocX, targetDocY; + + if (centerUnderCursor && + m_viewManager && m_viewManager->viewUnderCursor ()) + { + kpView *const vuc = m_viewManager->viewUnderCursor (); + QPoint viewPoint = vuc->mouseViewPoint (); + + // vuc->transformViewToDoc() returns QPoint which only has int + // accuracy so we do X and Y manually. + targetDocX = vuc->transformViewToDocX (viewPoint.x ()); + targetDocY = vuc->transformViewToDocY (viewPoint.y ()); + targetDocAvail = true; + + if (vuc != m_mainView) + viewPoint = vuc->transformViewToOtherView (viewPoint, m_mainView); + + viewX = viewPoint.x (); + viewY = viewPoint.y (); + } + else + { + viewX = m_scrollView->contentsX () + + QMIN (m_mainView->width (), + m_scrollView->visibleWidth ()) / 2; + viewY = m_scrollView->contentsY () + + QMIN (m_mainView->height (), + m_scrollView->visibleHeight ()) / 2; + } + + int newCenterX = viewX * zoomLevel / m_mainView->zoomLevelX (); + int newCenterY = viewY * zoomLevel / m_mainView->zoomLevelY (); + + m_mainView->setZoomLevel (zoomLevel, zoomLevel); + #if DEBUG_ZOOM_FLICKER + { + kdDebug () << "FLICKER: just setZoomLevel" << endl; + QTime timer; timer.start (); + while (timer.elapsed () < 1000) + ; + } + #endif + + #if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "\tvisibleWidth=" << m_scrollView->visibleWidth () + << " visibleHeight=" << m_scrollView->visibleHeight () + << endl; + kdDebug () << "\tnewCenterX=" << newCenterX + << " newCenterY=" << newCenterY << endl; + #endif + + m_scrollView->center (newCenterX, newCenterY); + #if DEBUG_ZOOM_FLICKER + { + kdDebug () << "FLICKER: just centred" << endl; + QTime timer; timer.start (); + while (timer.elapsed () < 2000) + ; + } + #endif + + if (centerUnderCursor && + targetDocAvail && + m_viewManager && m_viewManager->viewUnderCursor ()) + { + kpView *const vuc = m_viewManager->viewUnderCursor (); + + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tcenterUnderCursor: reposition cursor; viewUnderCursor=" + << vuc->name () << endl; + #endif + + const double viewX = vuc->transformDocToViewX (targetDocX); + const double viewY = vuc->transformDocToViewY (targetDocY); + // Rounding error from zooming in and out :( + // TODO: do everything in terms of tool doc points in type "double". + const QPoint viewPoint ((int) viewX, (int) viewY); + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tdoc: (" << targetDocX << "," << targetDocY << ")" + << " viewUnderCursor: (" << viewX << "," << viewY << ")" + << endl; + #endif + + if (vuc->clipRegion ().contains (viewPoint)) + { + const QPoint globalPoint = + kpWidgetMapper::toGlobal (vuc, viewPoint); + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tglobalPoint=" << globalPoint << endl; + #endif + + // TODO: Determine some sane cursor flashing indication - + // cursor movement is convenient but not conventional. + // + // Major problem: if using QApplication::setOverrideCursor() + // and in some stage of flash and window quits. + // + // Or if using kpView::setCursor() and change tool. + QCursor::setPos (globalPoint); + } + // e.g. Zoom to 200%, scroll mainView to bottom-right. + // Unzoomed Thumbnail shows top-left portion of bottom-right of + // mainView. + // + // Aim cursor at bottom-right of thumbnail and zoom out with + // CTRL+Wheel. + // + // If mainView is now small enough to largely not need scrollbars, + // Unzoomed Thumbnail scrolls to show _top-left_ portion + // _of top-left_ of mainView. + // + // Unzoomed Thumbnail no longer contains the point we zoomed out + // on top of. + else + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\twon't move cursor - would get outside view" + << endl; + #endif + + // TODO: Sane cursor flashing indication that indicates + // that the normal cursor movement didn't happen. + } + } + + #if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "\t\tcheck (contentsX=" << m_scrollView->contentsX () + << ",contentsY=" << m_scrollView->contentsY () + << ")" << endl; + #endif + } + + if (m_mainView) + { + actionShowGridUpdate (); + #if DEBUG_ZOOM_FLICKER + { + kdDebug () << "FLICKER: updated grid action" << endl; + QTime timer; timer.start (); + while (timer.elapsed () < 1000) + ; + } + #endif + + + updateMainViewGrid (); + #if DEBUG_ZOOM_FLICKER + { + kdDebug () << "FLICKER: just updated grid" << endl; + QTime timer; timer.start (); + while (timer.elapsed () < 1000) + ; + } + #endif + + + // Since Zoom Level KSelectAction on ToolBar grabs focus after changing + // Zoom, switch back to the Main View. + // TODO: back to the last view + m_mainView->setFocus (); + #if DEBUG_ZOOM_FLICKER + { + kdDebug () << "FLICKER: just set focus to mainview" << endl; + QTime timer; timer.start (); + while (timer.elapsed () < 1000) + ; + } + #endif + + } +#if 1 + // The view magnified and moved beneath the cursor + if (tool ()) + tool ()->somethingBelowTheCursorChanged (); + #if DEBUG_ZOOM_FLICKER + { + kdDebug () << "FLICKER: signalled something below cursor" << endl; + QTime timer; timer.start (); + while (timer.elapsed () < 1000) + ; + } + #endif +#endif + + // HACK: make sure all of Qt's update() calls trigger + // kpView::paintEvent() _now_ so that they can be queued by us + // (until kpViewManager::restoreQueueUpdates()) to reduce flicker + // caused mainly by m_scrollView->center() + // + // TODO: remove flicker completely + //QTimer::singleShot (0, this, SLOT (finishZoomTo ())); + + // Later: I don't think there is an update() that needs to be queued + // - let's reduce latency instead. + finishZoomTo (); +} + +// private slot +void kpMainWindow::finishZoomTo () +{ +#if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "\tkpMainWindow::finishZoomTo enter" << endl; +#endif + +#if DEBUG_ZOOM_FLICKER +{ + kdDebug () << "FLICKER: inside finishZoomTo" << endl; + QTime timer; timer.start (); + while (timer.elapsed () < 2000) + ; +} +#endif + + // TODO: setUpdatesEnabled() should really return to old value + // - not neccessarily "true" + + if (m_mainView) + { + m_mainView->setUpdatesEnabled (true); + m_mainView->update (); + } + +#if DEBUG_ZOOM_FLICKER +{ + kdDebug () << "FLICKER: just updated mainView" << endl; + QTime timer; timer.start (); + while (timer.elapsed () < 1000) + ; +} +#endif + + if (m_scrollView) + { + if (m_scrollView->viewport ()) + { + m_scrollView->viewport ()->setUpdatesEnabled (true); + m_scrollView->viewport ()->update (); + } + #if DEBUG_ZOOM_FLICKER + { + kdDebug () << "FLICKER: just updated scrollView::viewport()" << endl; + QTime timer; timer.start (); + while (timer.elapsed () < 1000) + ; + } + #endif + + m_scrollView->setUpdatesEnabled (true); + m_scrollView->update (); + #if DEBUG_ZOOM_FLICKER + { + kdDebug () << "FLICKER: just updated scrollView" << endl; + QTime timer; timer.start (); + while (timer.elapsed () < 1000) + ; + } + #endif + + } + + + if (m_viewManager && m_viewManager->queueUpdates ()/*just in case*/) + m_viewManager->restoreQueueUpdates (); +#if DEBUG_ZOOM_FLICKER +{ + kdDebug () << "FLICKER: restored vm queued updates" << endl; + QTime timer; timer.start (); + while (timer.elapsed () < 1000) + ; +} +#endif + + setStatusBarZoom (m_mainView ? m_mainView->zoomLevelX () : 0); + +#if DEBUG_KP_MAIN_WINDOW && 1 + kdDebug () << "\tkpMainWindow::finishZoomTo done" << endl; +#endif + +#if DEBUG_ZOOM_FLICKER +{ + kdDebug () << "FLICKER: finishZoomTo done" << endl; + QTime timer; timer.start (); + while (timer.elapsed () < 1000) + ; +} +#endif +} + + +// private slot +void kpMainWindow::slotActualSize () +{ + zoomTo (100); +} + +// private slot +void kpMainWindow::slotFitToPage () +{ + if (!m_scrollView || !m_document) + return; + + // doc_width * zoom / 100 <= view_width && + // doc_height * zoom / 100 <= view_height && + // 1 <= zoom <= 3200 + + zoomTo (QMIN (3200, QMAX (1, QMIN (m_scrollView->visibleWidth () * 100 / m_document->width (), + m_scrollView->visibleHeight () * 100 / m_document->height ())))); +} + +// private slot +void kpMainWindow::slotFitToWidth () +{ + if (!m_scrollView || !m_document) + return; + + // doc_width * zoom / 100 <= view_width && + // 1 <= zoom <= 3200 + + zoomTo (QMIN (3200, QMAX (1, m_scrollView->visibleWidth () * 100 / m_document->width ()))); +} + +// private slot +void kpMainWindow::slotFitToHeight () +{ + if (!m_scrollView || !m_document) + return; + + // doc_height * zoom / 100 <= view_height && + // 1 <= zoom <= 3200 + + zoomTo (QMIN (3200, QMAX (1, m_scrollView->visibleHeight () * 100 / m_document->height ()))); +} + + +// public +void kpMainWindow::zoomIn (bool centerUnderCursor) +{ + const int targetItem = m_actionZoom->currentItem () + 1; + + if (targetItem >= (int) m_zoomList.count ()) + return; + + m_actionZoom->setCurrentItem (targetItem); + zoomAccordingToZoomAction (centerUnderCursor); +} + +// public +void kpMainWindow::zoomOut (bool centerUnderCursor) +{ + const int targetItem = m_actionZoom->currentItem () - 1; + + if (targetItem < 0) + return; + + m_actionZoom->setCurrentItem (targetItem); + zoomAccordingToZoomAction (centerUnderCursor); +} + + +// public slot +void kpMainWindow::slotZoomIn () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotZoomIn ()" << endl; +#endif + + zoomIn (false/*don't center under cursor*/); +} + +// public slot +void kpMainWindow::slotZoomOut () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotZoomOut ()" << endl; +#endif + + zoomOut (false/*don't center under cursor*/); +} + + +// public +void kpMainWindow::zoomAccordingToZoomAction (bool centerUnderCursor) +{ + zoomTo (zoomLevelFromString (m_actionZoom->currentText ()), + centerUnderCursor); +} + +// private slot +void kpMainWindow::slotZoom () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotZoom () index=" << m_actionZoom->currentItem () + << " text='" << m_actionZoom->currentText () << "'" << endl; +#endif + zoomAccordingToZoomAction (false/*don't center under cursor*/); +} + + +// private slot +void kpMainWindow::slotShowGridToggled () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotActionShowGridToggled()" << endl; +#endif + + updateMainViewGrid (); + + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral); + KConfigBase *cfg = cfgGroupSaver.config (); + + cfg->writeEntry (kpSettingShowGrid, m_configShowGrid = m_actionShowGrid->isChecked ()); + cfg->sync (); +} + +// private +void kpMainWindow::updateMainViewGrid () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::updateMainViewGrid ()" << endl; +#endif + + if (m_mainView) + m_mainView->showGrid (m_actionShowGrid->isChecked ()); +} + + +// private +QRect kpMainWindow::mapToGlobal (const QRect &rect) const +{ + return kpWidgetMapper::toGlobal (this, rect); +} + +// private +QRect kpMainWindow::mapFromGlobal (const QRect &rect) const +{ + return kpWidgetMapper::fromGlobal (this, rect); +} + + +// public slot +void kpMainWindow::slotDestroyThumbnailIfNotVisible (bool tnIsVisible) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotDestroyThumbnailIfNotVisible(isVisible=" + << tnIsVisible + << ")" + << endl; +#endif + + if (!tnIsVisible) + { + slotDestroyThumbnailInitatedByUser (); + } +} + +// private slot +void kpMainWindow::slotDestroyThumbnail () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotDestroyThumbnail()" << endl; +#endif + + m_actionShowThumbnail->setChecked (false); + enableThumbnailOptionActions (false); + updateThumbnail (); +} + +// private slot +void kpMainWindow::slotDestroyThumbnailInitatedByUser () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotDestroyThumbnailInitiatedByUser()" << endl; +#endif + + m_actionShowThumbnail->setChecked (false); + slotShowThumbnailToggled (); +} + +// private slot +void kpMainWindow::slotCreateThumbnail () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotCreateThumbnail()" << endl; +#endif + + m_actionShowThumbnail->setChecked (true); + enableThumbnailOptionActions (true); + updateThumbnail (); +} + +// public +void kpMainWindow::notifyThumbnailGeometryChanged () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::notifyThumbnailGeometryChanged()" << endl; +#endif + + if (!m_thumbnailSaveConfigTimer) + { + m_thumbnailSaveConfigTimer = new QTimer (this); + connect (m_thumbnailSaveConfigTimer, SIGNAL (timeout ()), + this, SLOT (slotSaveThumbnailGeometry ())); + } + + m_thumbnailSaveConfigTimer->start (500/*msec*/, true/*single shot*/); +} + +// private slot +void kpMainWindow::slotSaveThumbnailGeometry () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::saveThumbnailGeometry()" << endl; +#endif + + if (!m_thumbnail) + return; + + QRect rect (m_thumbnail->x (), m_thumbnail->y (), + m_thumbnail->width (), m_thumbnail->height ()); +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tthumbnail relative geometry=" << rect << endl; +#endif + + m_configThumbnailGeometry = mapFromGlobal (rect); + +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tCONFIG: saving thumbnail geometry " + << m_configThumbnailGeometry + << endl; +#endif + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupThumbnail); + KConfigBase *cfg = cfgGroupSaver.config (); + + cfg->writeEntry (kpSettingThumbnailGeometry, m_configThumbnailGeometry); + cfg->sync (); +} + +// private slot +void kpMainWindow::slotShowThumbnailToggled () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotShowThumbnailToggled()" << endl; +#endif + + m_configThumbnailShown = m_actionShowThumbnail->isChecked (); + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupThumbnail); + KConfigBase *cfg = cfgGroupSaver.config (); + + cfg->writeEntry (kpSettingThumbnailShown, m_configThumbnailShown); + cfg->sync (); + + + enableThumbnailOptionActions (m_actionShowThumbnail->isChecked ()); + updateThumbnail (); +} + +// private slot +void kpMainWindow::updateThumbnailZoomed () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::updateThumbnailZoomed() zoomed=" + << m_actionZoomedThumbnail->isChecked () << endl; +#endif + + if (!m_thumbnailView) + return; + + destroyThumbnailView (); + createThumbnailView (); +} + +// private slot +void kpMainWindow::slotZoomedThumbnailToggled () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotZoomedThumbnailToggled()" << endl; +#endif + + m_configZoomedThumbnail = m_actionZoomedThumbnail->isChecked (); + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupThumbnail); + KConfigBase *cfg = cfgGroupSaver.config (); + + cfg->writeEntry (kpSettingThumbnailZoomed, m_configZoomedThumbnail); + cfg->sync (); + + + updateThumbnailZoomed (); +} + +// private slot +void kpMainWindow::slotThumbnailShowRectangleToggled () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::slotThumbnailShowRectangleToggled()" << endl; +#endif + + d->m_configThumbnailShowRectangle = d->m_actionShowThumbnailRectangle->isChecked (); + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupThumbnail); + KConfigBase *cfg = cfgGroupSaver.config (); + + cfg->writeEntry (kpSettingThumbnailShowRectangle, d->m_configThumbnailShowRectangle); + cfg->sync (); + + + if (m_thumbnailView) + { + m_thumbnailView->showBuddyViewScrollableContainerRectangle ( + d->m_actionShowThumbnailRectangle->isChecked ()); + } +} + +// private +void kpMainWindow::enableViewZoomedThumbnail (bool enable) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::enableSettingsViewZoomedThumbnail()" << endl; +#endif + + m_actionZoomedThumbnail->setEnabled (enable && + m_actionShowThumbnail->isChecked ()); + + // Note: Don't uncheck if disabled - being able to see the zoomed state + // before turning on the thumbnail can be useful. + m_actionZoomedThumbnail->setChecked (m_configZoomedThumbnail); +} + +// private +void kpMainWindow::enableViewShowThumbnailRectangle (bool enable) +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::enableViewShowThumbnailRectangle()" << endl; +#endif + + d->m_actionShowThumbnailRectangle->setEnabled (enable && + m_actionShowThumbnail->isChecked ()); + + // Note: Don't uncheck if disabled for consistency with + // enableViewZoomedThumbnail() + d->m_actionShowThumbnailRectangle->setChecked ( + d->m_configThumbnailShowRectangle); +} + +// private +void kpMainWindow::enableThumbnailOptionActions (bool enable) +{ + enableViewZoomedThumbnail (enable); + enableViewShowThumbnailRectangle (enable); +} + + +// private +void kpMainWindow::createThumbnailView () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tcreating new kpView:" << endl; +#endif + + if (m_thumbnailView) + { + kdDebug () << "kpMainWindow::createThumbnailView() had to destroy view" << endl; + destroyThumbnailView (); + } + + if (m_actionZoomedThumbnail->isChecked ()) + { + m_thumbnailView = new kpZoomedThumbnailView ( + m_document, m_toolToolBar, m_viewManager, + m_mainView, + 0/*scrollableContainer*/, + m_thumbnail, "thumbnailView"); + } + else + { + m_thumbnailView = new kpUnzoomedThumbnailView ( + m_document, m_toolToolBar, m_viewManager, + m_mainView, + 0/*scrollableContainer*/, + m_thumbnail, "thumbnailView"); + + } + + m_thumbnailView->showBuddyViewScrollableContainerRectangle ( + d->m_actionShowThumbnailRectangle->isChecked ()); + + +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tgive kpThumbnail the kpView:" << endl; +#endif + if (m_thumbnail) + m_thumbnail->setView (m_thumbnailView); + else + kdError () << "kpMainWindow::createThumbnailView() no thumbnail" << endl; + +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tregistering the kpView:" << endl; +#endif + if (m_viewManager) + m_viewManager->registerView (m_thumbnailView); +} + +// private +void kpMainWindow::destroyThumbnailView () +{ + if (!m_thumbnailView) + return; + + if (m_viewManager) + m_viewManager->unregisterView (m_thumbnailView); + + if (m_thumbnail) + m_thumbnail->setView (0); + + m_thumbnailView->deleteLater (); m_thumbnailView = 0; +} + + +// private +void kpMainWindow::updateThumbnail () +{ +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "kpMainWindow::updateThumbnail()" << endl; +#endif + bool enable = m_actionShowThumbnail->isChecked (); + +#if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tthumbnail=" + << bool (m_thumbnail) + << " action_isChecked=" + << enable + << endl; +#endif + + if (bool (m_thumbnail) == enable) + return; + + if (!m_thumbnail) + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tcreating thumbnail" << endl; + #endif + + // Read last saved geometry before creating thumbnail & friends + // in case they call notifyThumbnailGeometryChanged() + QRect thumbnailGeometry = m_configThumbnailGeometry; + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tlast used geometry=" << thumbnailGeometry << endl; + #endif + + m_thumbnail = new kpThumbnail (this, "thumbnail"); + + createThumbnailView (); + + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tmoving thumbnail to right place" << endl; + #endif + if (!thumbnailGeometry.isEmpty () && + QRect (0, 0, width (), height ()).intersects (thumbnailGeometry)) + { + const QRect geometry = mapToGlobal (thumbnailGeometry); + m_thumbnail->resize (geometry.size ()); + m_thumbnail->move (geometry.topLeft ()); + } + else + { + if (m_scrollView) + { + const int margin = 20; + const int initialWidth = 160, initialHeight = 120; + + QRect geometryRect (width () - initialWidth - margin * 2, + m_scrollView->y () + margin, + initialWidth, + initialHeight); + + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tcreating geometry=" << geometryRect << endl; + #endif + + geometryRect = mapToGlobal (geometryRect); + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tmap to global=" << geometryRect << endl; + #endif + m_thumbnail->resize (geometryRect.size ()); + m_thumbnail->move (geometryRect.topLeft ()); + } + } + + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tshowing thumbnail" << endl; + #endif + m_thumbnail->show (); + + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tconnecting thumbnail::visibilityChange to destroy slot" << endl; + #endif + connect (m_thumbnail, SIGNAL (visibilityChanged (bool)), + this, SLOT (slotDestroyThumbnailIfNotVisible (bool))); + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\t\tDONE" << endl; + #endif + } + else + { + #if DEBUG_KP_MAIN_WINDOW + kdDebug () << "\tdestroying thumbnail" << endl; + #endif + + if (m_thumbnailSaveConfigTimer && m_thumbnailSaveConfigTimer->isActive ()) + { + m_thumbnailSaveConfigTimer->stop (); + slotSaveThumbnailGeometry (); + } + + + destroyThumbnailView (); + + + disconnect (m_thumbnail, SIGNAL (visibilityChanged (bool)), + this, SLOT (slotDestroyThumbnailIfNotVisible (bool))); + + m_thumbnail->deleteLater (); m_thumbnail = 0; + } +} diff --git a/kolourpaint/kpselection.cpp b/kolourpaint/kpselection.cpp new file mode 100644 index 00000000..eb5924cf --- /dev/null +++ b/kolourpaint/kpselection.cpp @@ -0,0 +1,1446 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_SELECTION 0 + + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + + +kpSelection::kpSelection (const kpSelectionTransparency &transparency) + : QObject (), + m_type (kpSelection::Rectangle), + m_pixmap (0) +{ + setTransparency (transparency); +} + +kpSelection::kpSelection (Type type, const QRect &rect, const QPixmap &pixmap, + const kpSelectionTransparency &transparency) + : QObject (), + m_type (type), + m_rect (rect) +{ + calculatePoints (); + m_pixmap = pixmap.isNull () ? 0 : new QPixmap (pixmap); + + setTransparency (transparency); +} + +kpSelection::kpSelection (Type type, const QRect &rect, const kpSelectionTransparency &transparency) + : QObject (), + m_type (type), + m_rect (rect), + m_pixmap (0) +{ + calculatePoints (); + + setTransparency (transparency); +} + +kpSelection::kpSelection (const QRect &rect, + const QValueVector &textLines_, + const kpTextStyle &textStyle_) + : QObject (), + m_type (Text), + m_rect (rect), + m_pixmap (0), + m_textStyle (textStyle_) +{ + calculatePoints (); + + setTextLines (textLines_); +} + +kpSelection::kpSelection (const QPointArray &points, const QPixmap &pixmap, + const kpSelectionTransparency &transparency) + : QObject (), + m_type (Points), + m_rect (points.boundingRect ()), + m_points (points) +{ + m_pixmap = pixmap.isNull () ? 0 : new QPixmap (pixmap); + m_points.detach (); + + setTransparency (transparency); +} + +kpSelection::kpSelection (const QPointArray &points, const kpSelectionTransparency &transparency) + : QObject (), + m_type (Points), + m_rect (points.boundingRect ()), + m_points (points), + m_pixmap (0) +{ + m_points.detach (); + + setTransparency (transparency); +} + +kpSelection::kpSelection (const kpSelection &rhs) + : QObject (), + m_type (rhs.m_type), + m_rect (rhs.m_rect), + m_points (rhs.m_points), + m_pixmap (rhs.m_pixmap ? new QPixmap (*rhs.m_pixmap) : 0), + m_textLines (rhs.m_textLines), + m_textStyle (rhs.m_textStyle), + m_transparency (rhs.m_transparency), + m_transparencyMask (rhs.m_transparencyMask) +{ + m_points.detach (); +} + +kpSelection &kpSelection::operator= (const kpSelection &rhs) +{ + if (this == &rhs) + return *this; + + m_type = rhs.m_type; + m_rect = rhs.m_rect; + m_points = rhs.m_points; + m_points.detach (); + + delete m_pixmap; + m_pixmap = rhs.m_pixmap ? new QPixmap (*rhs.m_pixmap) : 0; + + m_textLines = rhs.m_textLines; + m_textStyle = rhs.m_textStyle; + + m_transparency = rhs.m_transparency; + m_transparencyMask = rhs.m_transparencyMask; + + return *this; +} + + +// friend +QDataStream &operator<< (QDataStream &stream, const kpSelection &selection) +{ +#if DEBUG_KP_SELECTION && 1 + kdDebug () << "kpSelection::operator<<(sel: rect=" << selection.boundingRect () + << " pixmap rect=" << (selection.pixmap () ? selection.pixmap ()->rect () : QRect ()) + << endl; +#endif + stream << int (selection.m_type); + stream << selection.m_rect; + stream << selection.m_points; +#if DEBUG_KP_SELECTION && 1 + kdDebug () << "\twrote type=" << int (selection.m_type) << " rect=" << selection.m_rect + << " and points" << endl; +#endif + + // TODO: need for text? + // For now we just use QTextDrag for Text Selections so this point is mute. + if (selection.m_pixmap) + { + const QImage image = kpPixmapFX::convertToImage (*selection.m_pixmap); + #if DEBUG_KP_SELECTION && 1 + kdDebug () << "\twrote image rect=" << image.rect () << endl; + #endif + stream << image; + } + else + { + #if DEBUG_KP_SELECTION && 1 + kdDebug () << "\twrote no image because no pixmap" << endl; + #endif + stream << QImage (); + } + + //stream << selection.m_textLines; + //stream << selection.m_textStyle; + + return stream; +} + +// friend +QDataStream &operator>> (QDataStream &stream, kpSelection &selection) +{ + selection.readFromStream (stream); + return stream; +} + +// public +// TODO: KolourPaint has not been tested against invalid or malicious +// clipboard data [Bug #28]. +void kpSelection::readFromStream (QDataStream &stream, + const kpPixmapFX::WarnAboutLossInfo &wali) +{ +#if DEBUG_KP_SELECTION && 1 + kdDebug () << "kpSelection::readFromStream()" << endl; +#endif + int typeAsInt; + stream >> typeAsInt; + m_type = kpSelection::Type (typeAsInt); +#if DEBUG_KP_SELECTION && 1 + kdDebug () << "\ttype=" << typeAsInt << endl; +#endif + + stream >> m_rect; + stream >> m_points; + m_points.detach (); +#if DEBUG_KP_SELECTION && 1 + kdDebug () << "\trect=" << m_rect << endl; + //kdDebug () << "\tpoints=" << m_points << endl; +#endif + + QImage image; + stream >> image; + delete m_pixmap; + if (!image.isNull ()) + m_pixmap = new QPixmap (kpPixmapFX::convertToPixmap (image, false/*no dither*/, wali)); + else + m_pixmap = 0; +#if DEBUG_KP_SELECTION && 1 + kdDebug () << "\timage: w=" << image.width () << " h=" << image.height () + << " depth=" << image.depth () << endl; + if (m_pixmap) + { + kdDebug () << "\tpixmap: w=" << m_pixmap->width () << " h=" << m_pixmap->height () + << endl; + } + else + { + kdDebug () << "\tpixmap: none" << endl; + } +#endif + + //stream >> m_textLines; + //stream >> m_textStyle; +} + +kpSelection::~kpSelection () +{ + delete m_pixmap; m_pixmap = 0; +} + + +// private +void kpSelection::calculatePoints () +{ + if (m_type == kpSelection::Points) + return; + + if (m_type == kpSelection::Ellipse) + { + m_points.makeEllipse (m_rect.x (), m_rect.y (), + m_rect.width (), m_rect.height ()); + return; + } + + if (m_type == kpSelection::Rectangle || m_type == kpSelection::Text) + { + // OPT: not space optimal - redoes corners + m_points.resize (m_rect.width () * 2 + m_rect.height () * 2); + + int pointsUpto = 0; + + // top + for (int x = 0; x < m_rect.width (); x++) + m_points [pointsUpto++] = QPoint (m_rect.x () + x, m_rect.top ()); + + // right + for (int y = 0; y < m_rect.height (); y++) + m_points [pointsUpto++] = QPoint (m_rect.right (), m_rect.y () + y); + + // bottom + for (int x = m_rect.width () - 1; x >= 0; x--) + m_points [pointsUpto++] = QPoint (m_rect.x () + x, m_rect.bottom ()); + + // left + for (int y = m_rect.height () - 1; y >= 0; y--) + m_points [pointsUpto++] = QPoint (m_rect.left (), m_rect.y () + y); + + return; + } + + kdError () << "kpSelection::calculatePoints() with unknown type" << endl; + return; +} + + +// public +kpSelection::Type kpSelection::type () const +{ + return m_type; +} + +// public +bool kpSelection::isRectangular () const +{ + return (m_type == Rectangle || m_type == Text); +} + +// public +bool kpSelection::isText () const +{ + return (m_type == Text); +} + +// public +QString kpSelection::name () const +{ + if (m_type == Text) + return i18n ("Text"); + + return i18n ("Selection"); +} + + +// public +int kpSelection::size () const +{ + return kpPixmapFX::pointArraySize (m_points) + + kpPixmapFX::pixmapSize (m_pixmap) + + kpPixmapFX::stringSize (text ()) + + kpPixmapFX::pixmapSize (m_transparencyMask); +} + + +// public +QBitmap kpSelection::maskForOwnType (bool nullForRectangular) const +{ + if (!m_rect.isValid ()) + { + kdError () << "kpSelection::maskForOwnType() boundingRect invalid" << endl; + return QBitmap (); + } + + + if (isRectangular ()) + { + if (nullForRectangular) + return QBitmap (); + + QBitmap maskBitmap (m_rect.width (), m_rect.height ()); + maskBitmap.fill (Qt::color1/*opaque*/); + return maskBitmap; + } + + + QBitmap maskBitmap (m_rect.width (), m_rect.height ()); + maskBitmap.fill (Qt::color0/*transparent*/); + + QPainter painter; + painter.begin (&maskBitmap); + painter.setPen (Qt::color1)/*opaque*/; + painter.setBrush (Qt::color1/*opaque*/); + + if (m_type == kpSelection::Ellipse) + painter.drawEllipse (0, 0, m_rect.width (), m_rect.height ()); + else if (m_type == kpSelection::Points) + { + QPointArray points = m_points; + points.detach (); + points.translate (-m_rect.x (), -m_rect.y ()); + + painter.drawPolygon (points, false/*even-odd algo*/); + } + + painter.end (); + + + return maskBitmap; +} + + +// public +QPoint kpSelection::topLeft () const +{ + return m_rect.topLeft (); +} + +// public +QPoint kpSelection::point () const +{ + return m_rect.topLeft (); +} + + +// public +int kpSelection::x () const +{ + return m_rect.x (); +} + +// public +int kpSelection::y () const +{ + return m_rect.y (); +} + + +// public +void kpSelection::moveBy (int dx, int dy) +{ +#if DEBUG_KP_SELECTION && 1 + kdDebug () << "kpSelection::moveBy(" << dx << "," << dy << ")" << endl; +#endif + + if (dx == 0 && dy == 0) + return; + + QRect oldRect = boundingRect (); + +#if DEBUG_KP_SELECTION && 1 + kdDebug () << "\toldRect=" << oldRect << endl; +#endif + + m_rect.moveBy (dx, dy); + m_points.translate (dx, dy); +#if DEBUG_KP_SELECTION && 1 + kdDebug () << "\tnewRect=" << m_rect << endl; +#endif + + emit changed (oldRect); + emit changed (boundingRect ()); +} + +// public +void kpSelection::moveTo (int dx, int dy) +{ + moveTo (QPoint (dx, dy)); +} + +// public +void kpSelection::moveTo (const QPoint &topLeftPoint) +{ +#if DEBUG_KP_SELECTION && 1 + kdDebug () << "kpSelection::moveTo(" << topLeftPoint << ")" << endl; +#endif + QRect oldBoundingRect = boundingRect (); +#if DEBUG_KP_SELECTION && 1 + kdDebug () << "\toldBoundingRect=" << oldBoundingRect << endl; +#endif + if (topLeftPoint == oldBoundingRect.topLeft ()) + return; + + QPoint delta (topLeftPoint - oldBoundingRect.topLeft ()); + moveBy (delta.x (), delta.y ()); +} + + +// public +QPointArray kpSelection::points () const +{ + return m_points; +} + +// public +QPointArray kpSelection::pointArray () const +{ + return m_points; +} + +// public +QRect kpSelection::boundingRect () const +{ + return m_rect; +} + +// public +int kpSelection::width () const +{ + return boundingRect ().width (); +} + +// public +int kpSelection::height () const +{ + return boundingRect ().height (); +} + +// public +bool kpSelection::contains (const QPoint &point) const +{ + QRect rect = boundingRect (); + +#if DEBUG_KP_SELECTION && 1 + kdDebug () << "kpSelection::contains(" << point + << ") rect==" << rect + << " #points=" << m_points.size () + << endl; +#endif + + if (!rect.contains (point)) + return false; + + // OPT: QRegion is probably incredibly slow - cache + // We can't use the m_pixmap (if avail) and get the transparency of + // the pixel at that point as it may be transparent but still within the + // border + switch (m_type) + { + case kpSelection::Rectangle: + case kpSelection::Text: + return true; + case kpSelection::Ellipse: + return QRegion (m_rect, QRegion::Ellipse).contains (point); + case kpSelection::Points: + // TODO: make this always include the border + // (draw up a rect sel in this mode to see what I mean) + return QRegion (m_points, false/*even-odd algo*/).contains (point); + default: + return false; + } +} + +// public +bool kpSelection::contains (int x, int y) +{ + return contains (QPoint (x, y)); +} + + +// public +QPixmap *kpSelection::pixmap () const +{ + return m_pixmap; +} + +// public +void kpSelection::setPixmap (const QPixmap &pixmap) +{ + delete m_pixmap; + // TODO: If isText(), setting pixmap() to 0 is unexpected (implies + // it's a border, not a text box) but saves memory when using + // that kpSelection::setPixmap (QPixmap ()) hack. + m_pixmap = pixmap.isNull () ? 0 : new QPixmap (pixmap); + QRect changedRect = boundingRect (); + + if (m_pixmap) + { + const bool changedSize = (m_pixmap->width () != m_rect.width () || + m_pixmap->height () != m_rect.height ()); + const bool changedFromText = (m_type == Text); + if (changedSize || changedFromText) + { + if (changedSize) + { + kdError () << "kpSelection::setPixmap() changes the size of the selection!" + << " old:" + << " w=" << m_rect.width () + << " h=" << m_rect.height () + << " new:" + << " w=" << m_pixmap->width () + << " h=" << m_pixmap->height () + << endl; + } + + if (changedFromText) + { + kdError () << "kpSelection::setPixmap() changed from text" << endl; + } + + m_type = kpSelection::Rectangle; + m_rect = QRect (m_rect.x (), m_rect.y (), + m_pixmap->width (), m_pixmap->height ()); + calculatePoints (); + + m_textLines = QValueVector (); + + changedRect = changedRect.unite (boundingRect ()); + } + } + + calculateTransparencyMask (); + + emit changed (changedRect); +} + + +// public +bool kpSelection::usesBackgroundPixmapToPaint () const +{ + // Opaque text with transparent background needs to antialias with + // doc pixmap below it. + return (isText () && + m_textStyle.foregroundColor ().isOpaque () && + m_textStyle.effectiveBackgroundColor ().isTransparent ()); +} + +static int mostContrastingValue (int val) +{ + if (val <= 127) + return 255; + else + return 0; +} + +static QRgb mostContrastingRGB (QRgb val) +{ + return qRgba (mostContrastingValue (qRed (val)), + mostContrastingValue (qGreen (val)), + mostContrastingValue (qBlue (val)), + mostContrastingValue (qAlpha (val))); +} + +// private +static void drawTextLines (QPainter *painter, QPainter *maskPainter, + const QRect &rect, + const QValueVector &textLines) +{ + if (!painter->clipRegion ().isEmpty () || !maskPainter->clipRegion ().isEmpty ()) + { + // TODO: fix esp. before making method public + kdError () << "kpselection.cpp:drawTextLines() can't deal with existing painter clip regions" << endl; + return; + } + + +#define PAINTER_CALL(cmd) \ +{ \ + if (painter->isActive ()) \ + painter->cmd; \ + \ + if (maskPainter->isActive ()) \ + maskPainter->cmd; \ +} + + + // Can't do this because the line heights become + // >QFontMetrics::height() if you type Chinese characters (!) and then + // the cursor gets out of sync. + // PAINTER_CALL (drawText (rect, 0/*flags*/, text ())); + + +#if 0 + const QFontMetrics fontMetrics (painter->fontMetrics ()); + + kdDebug () << "height=" << fontMetrics.height () + << " leading=" << fontMetrics.leading () + << " ascent=" << fontMetrics.ascent () + << " descent=" << fontMetrics.descent () + << " lineSpacing=" << fontMetrics.lineSpacing () + << endl; +#endif + + + PAINTER_CALL (setClipRect (rect, QPainter::CoordPainter/*transform*/)); + + int baseLine = rect.y () + painter->fontMetrics ().ascent (); + for (QValueVector ::const_iterator it = textLines.begin (); + it != textLines.end (); + it++) + { + PAINTER_CALL (drawText (rect.x (), baseLine, *it)); + baseLine += painter->fontMetrics ().lineSpacing (); + } + + +#undef PAINTER_CALL +} + +// private +void kpSelection::paintOpaqueText (QPixmap *destPixmap, const QRect &docRect) const +{ + if (!isText () || !m_textStyle.foregroundColor ().isOpaque ()) + return; + + + const QRect modifyingRect = docRect.intersect (boundingRect ()); + if (modifyingRect.isEmpty ()) + return; + + + QBitmap destPixmapMask; + QPainter destPixmapPainter, destPixmapMaskPainter; + + if (destPixmap->mask ()) + { + if (m_textStyle.effectiveBackgroundColor ().isTransparent ()) + { + QRect modifyingRectRelPixmap = modifyingRect; + modifyingRectRelPixmap.moveBy (-docRect.x (), -docRect.y ()); + + // Set the RGB of transparent pixels to foreground colour to avoid + // anti-aliasing the foreground coloured text with undefined RGBs. + kpPixmapFX::setPixmapAt (destPixmap, + modifyingRectRelPixmap, + kpPixmapFX::pixmapWithDefinedTransparentPixels ( + kpPixmapFX::getPixmapAt (*destPixmap, modifyingRectRelPixmap), + m_textStyle.foregroundColor ().toQColor ())); + } + + destPixmapMask = *destPixmap->mask (); + destPixmapMaskPainter.begin (&destPixmapMask); + destPixmapMaskPainter.translate (-docRect.x (), -docRect.y ()); + destPixmapMaskPainter.setPen (Qt::color1/*opaque*/); + destPixmapMaskPainter.setFont (m_textStyle.font ()); + } + + destPixmapPainter.begin (destPixmap); + destPixmapPainter.translate (-docRect.x (), -docRect.y ()); + destPixmapPainter.setPen (m_textStyle.foregroundColor ().toQColor ()); + destPixmapPainter.setFont (m_textStyle.font ()); + + + if (m_textStyle.effectiveBackgroundColor ().isOpaque ()) + { + destPixmapPainter.fillRect ( + boundingRect (), + m_textStyle.effectiveBackgroundColor ().toQColor ()); + + if (destPixmapMaskPainter.isActive ()) + { + destPixmapMaskPainter.fillRect ( + boundingRect (), + Qt::color1/*opaque*/); + } + } + + + ::drawTextLines (&destPixmapPainter, &destPixmapMaskPainter, + textAreaRect (), + textLines ()); + + + if (destPixmapPainter.isActive ()) + destPixmapPainter.end (); + + if (destPixmapMaskPainter.isActive ()) + destPixmapMaskPainter.end (); + + + if (!destPixmapMask.isNull ()) + destPixmap->setMask (destPixmapMask); +} + +// private +QPixmap kpSelection::transparentForegroundTextPixmap () const +{ + if (!isText () || !m_textStyle.foregroundColor ().isTransparent ()) + return QPixmap (); + + + QPixmap pixmap (m_rect.width (), m_rect.height ()); + QBitmap pixmapMask (m_rect.width (), m_rect.height ()); + + + // Iron out stupid case first + if (m_textStyle.effectiveBackgroundColor ().isTransparent ()) + { + pixmapMask.fill (Qt::color0/*transparent*/); + pixmap.setMask (pixmapMask); + return pixmap; + } + + + // -- Foreground transparent, background opaque -- + + + QFont font = m_textStyle.font (); + // TODO: why doesn't "font.setStyleStrategy (QFont::NoAntialias);" + // let us avoid the hack below? + + + QPainter pixmapPainter, pixmapMaskPainter; + + pixmap.fill (m_textStyle.effectiveBackgroundColor ().toQColor ()); + pixmapPainter.begin (&pixmap); + // HACK: Transparent foreground colour + antialiased fonts don't + // work - they don't seem to be able to draw in + // Qt::color0/*transparent*/ (but Qt::color1 seems Ok). + // So we draw in a contrasting color to the background so that + // we can identify the transparent pixels for manually creating + // the mask. + pixmapPainter.setPen ( + QColor (mostContrastingRGB (m_textStyle.effectiveBackgroundColor ().toQRgb () & RGB_MASK))); + pixmapPainter.setFont (font); + + + pixmapMask.fill (Qt::color1/*opaque*/); + pixmapMaskPainter.begin (&pixmapMask); + pixmapMaskPainter.setPen (Qt::color0/*transparent*/); + pixmapMaskPainter.setFont (font); + + + QRect rect (textAreaRect ()); + rect.moveBy (-m_rect.x (), -m_rect.y ()); + ::drawTextLines (&pixmapPainter, &pixmapMaskPainter, + rect, + textLines ()); + + + if (pixmapPainter.isActive ()) + pixmapPainter.end (); + + if (pixmapMaskPainter.isActive ()) + pixmapMaskPainter.end (); + + +#if DEBUG_KP_SELECTION + kdDebug () << "\tinvoking foreground transparency hack" << endl; +#endif + QImage image = kpPixmapFX::convertToImage (pixmap); + QRgb backgroundRGB = image.pixel (0, 0); // on textBorderSize() + + pixmapMaskPainter.begin (&pixmapMask); + for (int y = 0; y < image.height (); y++) + { + for (int x = 0; x < image.width (); x++) + { + if (image.pixel (x, y) == backgroundRGB) + pixmapMaskPainter.setPen (Qt::color1/*opaque*/); + else + pixmapMaskPainter.setPen (Qt::color0/*transparent*/); + + pixmapMaskPainter.drawPoint (x, y); + } + } + pixmapMaskPainter.end (); + + + if (!pixmapMask.isNull ()) + pixmap.setMask (pixmapMask); + + + return pixmap; +} + +// public +void kpSelection::paint (QPixmap *destPixmap, const QRect &docRect) const +{ + if (!isText ()) + { + if (pixmap () && !pixmap ()->isNull ()) + { + kpPixmapFX::paintPixmapAt (destPixmap, + topLeft () - docRect.topLeft (), + transparentPixmap ()); + } + } + else + { + #if DEBUG_KP_SELECTION + kdDebug () << "kpSelection::paint() textStyle: fcol=" + << (int *) m_textStyle.foregroundColor ().toQRgb () + << " bcol=" + << (int *) m_textStyle.effectiveBackgroundColor ().toQRgb () + << endl; + #endif + + if (m_textStyle.foregroundColor ().isOpaque ()) + { + // (may have to antialias with background so don't use m_pixmap) + paintOpaqueText (destPixmap, docRect); + } + else + { + if (!m_pixmap) + { + kdError () << "kpSelection::paint() without m_pixmap?" << endl; + return; + } + + // (transparent foreground slow to render, no antialiasing + // so use m_pixmap cache) + kpPixmapFX::paintPixmapAt (destPixmap, + topLeft () - docRect.topLeft (), + *m_pixmap); + } + } +} + +// private +void kpSelection::calculateTextPixmap () +{ + if (!isText ()) + { + kdError () << "kpSelection::calculateTextPixmap() not text sel" + << endl; + return; + } + + delete m_pixmap; + + if (m_textStyle.foregroundColor().isOpaque ()) + { + m_pixmap = new QPixmap (m_rect.width (), m_rect.height ()); + + if (usesBackgroundPixmapToPaint ()) + kpPixmapFX::fill (m_pixmap, kpColor::transparent); + + paintOpaqueText (m_pixmap, m_rect); + } + else + { + m_pixmap = new QPixmap (transparentForegroundTextPixmap ()); + } +} + + +// public static +QString kpSelection::textForTextLines (const QValueVector &textLines_) +{ + if (textLines_.isEmpty ()) + return QString::null; + + QString bigString = textLines_ [0]; + + for (QValueVector ::const_iterator it = textLines_.begin () + 1; + it != textLines_.end (); + it++) + { + bigString += QString::fromLatin1 ("\n"); + bigString += (*it); + } + + return bigString; +} + +// public +QString kpSelection::text () const +{ + if (!isText ()) + { + return QString::null; + } + + return textForTextLines (m_textLines); +} + +// public +QValueVector kpSelection::textLines () const +{ + if (!isText ()) + { + kdError () << "kpSelection::textLines() not a text selection" << endl; + return QValueVector (); + } + + return m_textLines; +} + +// public +void kpSelection::setTextLines (const QValueVector &textLines_) +{ + if (!isText ()) + { + kdError () << "kpSelection::setTextLines() not a text selection" << endl; + return; + } + + m_textLines = textLines_; + if (m_textLines.isEmpty ()) + { + kdError () << "kpSelection::setTextLines() passed no lines" << endl; + m_textLines.push_back (QString::null); + } + calculateTextPixmap (); + emit changed (boundingRect ()); +} + +// public static +int kpSelection::textBorderSize () +{ + return 1; +} + +// public +QRect kpSelection::textAreaRect () const +{ + if (!isText ()) + { + kdError () << "kpSelection::textAreaRect() not a text selection" << endl; + return QRect (); + } + + return QRect (m_rect.x () + textBorderSize (), + m_rect.y () + textBorderSize (), + m_rect.width () - textBorderSize () * 2, + m_rect.height () - textBorderSize () * 2); +} + +// public +bool kpSelection::pointIsInTextBorderArea (const QPoint &globalPoint) const +{ + if (!isText ()) + { + kdError () << "kpSelection::pointIsInTextBorderArea() not a text selection" << endl; + return false; + } + + return (m_rect.contains (globalPoint) && !pointIsInTextArea (globalPoint)); +} + +// public +bool kpSelection::pointIsInTextArea (const QPoint &globalPoint) const +{ + if (!isText ()) + { + kdError () << "kpSelection::pointIsInTextArea() not a text selection" << endl; + return false; + } + + return textAreaRect ().contains (globalPoint); +} + + +// public +void kpSelection::textResize (int width, int height) +{ + if (!isText ()) + { + kdError () << "kpSelection::textResize() not a text selection" << endl; + return; + } + + QRect oldRect = m_rect; + + m_rect = QRect (oldRect.x (), oldRect.y (), width, height); + + calculatePoints (); + calculateTextPixmap (); + + emit changed (m_rect.unite (oldRect)); +} + + +// public static +int kpSelection::minimumWidthForTextStyle (const kpTextStyle &) +{ + return (kpSelection::textBorderSize () * 2 + 5); +} + +// public static +int kpSelection::minimumHeightForTextStyle (const kpTextStyle &) +{ + return (kpSelection::textBorderSize () * 2 + 5); +} + +// public static +QSize kpSelection::minimumSizeForTextStyle (const kpTextStyle &textStyle) +{ + return QSize (minimumWidthForTextStyle (textStyle), + minimumHeightForTextStyle (textStyle)); +} + + +// public static +int kpSelection::preferredMinimumWidthForTextStyle (const kpTextStyle &textStyle) +{ + const int about15CharsWidth = + textStyle.fontMetrics ().width ( + QString::fromLatin1 ("1234567890abcde")); + + const int preferredMinWidth = + QMAX (150, + textBorderSize () * 2 + about15CharsWidth); + + return QMAX (minimumWidthForTextStyle (textStyle), + QMIN (250, preferredMinWidth)); +} + +// public static +int kpSelection::preferredMinimumHeightForTextStyle (const kpTextStyle &textStyle) +{ + const int preferredMinHeight = + textBorderSize () * 2 + textStyle.fontMetrics ().height (); + + return QMAX (minimumHeightForTextStyle (textStyle), + QMIN (150, preferredMinHeight)); +} + +// public static +QSize kpSelection::preferredMinimumSizeForTextStyle (const kpTextStyle &textStyle) +{ + return QSize (preferredMinimumWidthForTextStyle (textStyle), + preferredMinimumHeightForTextStyle (textStyle)); +} + + +// public +int kpSelection::minimumWidth () const +{ + if (isText ()) + return minimumWidthForTextStyle (textStyle ()); + else + return 1; +} + +// public +int kpSelection::minimumHeight () const +{ + if (isText ()) + return minimumHeightForTextStyle (textStyle ()); + else + return 1; +} + +// public +QSize kpSelection::minimumSize () const +{ + return QSize (minimumWidth (), minimumHeight ()); +} + + +// public +int kpSelection::textRowForPoint (const QPoint &globalPoint) const +{ + if (!isText ()) + { + kdError () << "kpSelection::textRowForPoint() not a text selection" << endl; + return -1; + } + + if (!pointIsInTextArea (globalPoint)) + return -1; + + const QFontMetrics fontMetrics (m_textStyle.fontMetrics ()); + + int row = (globalPoint.y () - textAreaRect ().y ()) / + fontMetrics.lineSpacing (); + if (row >= (int) m_textLines.size ()) + row = m_textLines.size () - 1; + + return row; +} + +// public +int kpSelection::textColForPoint (const QPoint &globalPoint) const +{ + if (!isText ()) + { + kdError () << "kpSelection::textColForPoint() not a text selection" << endl; + return -1; + } + + int row = textRowForPoint (globalPoint); + if (row < 0 || row >= (int) m_textLines.size ()) + return -1; + + const int localX = globalPoint.x () - textAreaRect ().x (); + + const QFontMetrics fontMetrics (m_textStyle.fontMetrics ()); + + // (should be 0 but call just in case) + int charLocalLeft = fontMetrics.width (m_textLines [row], 0); + + // OPT: binary search or guess location then move + for (int col = 0; col < (int) m_textLines [row].length (); col++) + { + // OPT: fontMetrics::charWidth() might be faster + const int nextCharLocalLeft = fontMetrics.width (m_textLines [row], col + 1); + if (localX <= (charLocalLeft + nextCharLocalLeft) / 2) + return col; + + charLocalLeft = nextCharLocalLeft; + } + + return m_textLines [row].length ()/*past end of line*/; +} + +// public +QPoint kpSelection::pointForTextRowCol (int row, int col) +{ + if (!isText ()) + { + kdError () << "kpSelection::pointForTextRowCol() not a text selection" << endl; + return KP_INVALID_POINT; + } + + if (row < 0 || row >= (int) m_textLines.size () || + col < 0 || col > (int) m_textLines [row].length ()) + { + #if DEBUG_KP_SELECTION && 1 + kdDebug () << "kpSelection::pointForTextRowCol(" + << row << "," + << col << ") out of range" + << " textLines='" + << text () + << "'" + << endl; + #endif + return KP_INVALID_POINT; + } + + const QFontMetrics fontMetrics (m_textStyle.fontMetrics ()); + + const int x = fontMetrics.width (m_textLines [row], col); + const int y = row * fontMetrics.height () + + (row >= 1 ? row * fontMetrics.leading () : 0); + + return textAreaRect ().topLeft () + QPoint (x, y); +} + +// public +kpTextStyle kpSelection::textStyle () const +{ + if (!isText ()) + { + kdError () << "kpSelection::textStyle() not a text selection" << endl; + } + + return m_textStyle; +} + +// public +void kpSelection::setTextStyle (const kpTextStyle &textStyle_) +{ + if (!isText ()) + { + kdError () << "kpSelection::setTextStyle() not a text selection" << endl; + return; + } + + m_textStyle = textStyle_; + calculateTextPixmap (); + emit changed (boundingRect ()); +} + +// public +QPixmap kpSelection::opaquePixmap () const +{ + QPixmap *p = pixmap (); + if (p) + { + return *p; + } + else + { + return QPixmap (); + } +} + +// private +void kpSelection::calculateTransparencyMask () +{ +#if DEBUG_KP_SELECTION + kdDebug () << "kpSelection::calculateTransparencyMask()" << endl; +#endif + + if (isText ()) + { + #if DEBUG_KP_SELECTION + kdDebug () << "\ttext - no need for transparency mask" << endl; + #endif + m_transparencyMask.resize (0, 0); + return; + } + + if (!m_pixmap) + { + #if DEBUG_KP_SELECTION + kdDebug () << "\tno pixmap - no need for transparency mask" << endl; + #endif + m_transparencyMask.resize (0, 0); + return; + } + + if (m_transparency.isOpaque ()) + { + #if DEBUG_KP_SELECTION + kdDebug () << "\topaque - no need for transparency mask" << endl; + #endif + m_transparencyMask.resize (0, 0); + return; + } + + m_transparencyMask.resize (m_pixmap->width (), m_pixmap->height ()); + + QImage image = kpPixmapFX::convertToImage (*m_pixmap); + QPainter transparencyMaskPainter (&m_transparencyMask); + + bool hasTransparent = false; + for (int y = 0; y < m_pixmap->height (); y++) + { + for (int x = 0; x < m_pixmap->width (); x++) + { + if (kpPixmapFX::getColorAtPixel (image, x, y).isSimilarTo (m_transparency.transparentColor (), + m_transparency.processedColorSimilarity ())) + { + transparencyMaskPainter.setPen (Qt::color1/*make it transparent*/); + hasTransparent = true; + } + else + { + transparencyMaskPainter.setPen (Qt::color0/*keep pixel as is*/); + } + + transparencyMaskPainter.drawPoint (x, y); + } + } + + transparencyMaskPainter.end (); + + if (!hasTransparent) + { + #if DEBUG_KP_SELECTION + kdDebug () << "\tcolour useless - completely opaque" << endl; + #endif + m_transparencyMask.resize (0, 0); + return; + } +} + +// public +QPixmap kpSelection::transparentPixmap () const +{ + QPixmap pixmap = opaquePixmap (); + + if (!m_transparencyMask.isNull ()) + { + kpPixmapFX::paintMaskTransparentWithBrush (&pixmap, QPoint (0, 0), + m_transparencyMask); + } + + return pixmap; +} + +// public +kpSelectionTransparency kpSelection::transparency () const +{ + return m_transparency; +} + +// public +bool kpSelection::setTransparency (const kpSelectionTransparency &transparency, + bool checkTransparentPixmapChanged) +{ + if (m_transparency == transparency) + return false; + + m_transparency = transparency; + + bool haveChanged = true; + + QBitmap oldTransparencyMask = m_transparencyMask; + calculateTransparencyMask (); + + + if (oldTransparencyMask.width () == m_transparencyMask.width () && + oldTransparencyMask.height () == m_transparencyMask.height ()) + { + if (m_transparencyMask.isNull ()) + { + #if DEBUG_KP_SELECTION + kdDebug () << "\tboth old and new pixmaps are null - nothing changed" << endl; + #endif + haveChanged = false; + } + else if (checkTransparentPixmapChanged) + { + QImage oldTransparencyMaskImage = kpPixmapFX::convertToImage (oldTransparencyMask); + QImage newTransparencyMaskImage = kpPixmapFX::convertToImage (m_transparencyMask); + + bool changed = false; + for (int y = 0; y < oldTransparencyMaskImage.height () && !changed; y++) + { + for (int x = 0; x < oldTransparencyMaskImage.width () && !changed; x++) + { + if (kpPixmapFX::getColorAtPixel (oldTransparencyMaskImage, x, y) != + kpPixmapFX::getColorAtPixel (newTransparencyMaskImage, x, y)) + { + #if DEBUG_KP_SELECTION + kdDebug () << "\tdiffer at " << QPoint (x, y) + << " old=" << (int *) kpPixmapFX::getColorAtPixel (oldTransparencyMaskImage, x, y).toQRgb () + << " new=" << (int *) kpPixmapFX::getColorAtPixel (newTransparencyMaskImage, x, y).toQRgb () + << endl; + #endif + changed = true; + break; + } + } + } + + if (!changed) + haveChanged = false; + } + } + + + if (haveChanged) + emit changed (boundingRect ()); + + return haveChanged; +} + + +// private +void kpSelection::flipPoints (bool horiz, bool vert) +{ + QRect oldRect = boundingRect (); + + m_points.translate (-oldRect.x (), -oldRect.y ()); + + const QWMatrix matrix = kpPixmapFX::flipMatrix (oldRect.width (), oldRect.height (), + horiz, vert); + m_points = matrix.map (m_points); + + m_points.translate (oldRect.x (), oldRect.y ()); +} + + +// public +void kpSelection::flip (bool horiz, bool vert) +{ +#if DEBUG_KP_SELECTION && 1 + kdDebug () << "kpSelection::flip(horiz=" << horiz + << ",vert=" << vert << ")" << endl; +#endif + + flipPoints (horiz, vert); + + + if (m_pixmap) + { + #if DEBUG_KP_SELECTION && 1 + kdDebug () << "\thave pixmap - flipping that" << endl; + #endif + kpPixmapFX::flip (m_pixmap, horiz, vert); + } + + if (!m_transparencyMask.isNull ()) + { + #if DEBUG_KP_SELECTION && 1 + kdDebug () << "\thave transparency mask - flipping that" << endl; + #endif + kpPixmapFX::flip (&m_transparencyMask, horiz, vert); + } + + + emit changed (boundingRect ()); +} + +#include + diff --git a/kolourpaint/kpselection.h b/kolourpaint/kpselection.h new file mode 100644 index 00000000..69b836b9 --- /dev/null +++ b/kolourpaint/kpselection.h @@ -0,0 +1,237 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kpselection_h__ +#define __kpselection_h__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +class QSize; + + +/* + * Holds a selection - will also be used for the clipboard + * so that we can retain the border. + */ +class kpSelection : public QObject +{ +Q_OBJECT + +public: + enum Type + { + Rectangle, + Ellipse, + Points, + Text + }; + + // (for any) + kpSelection (const kpSelectionTransparency &transparency = kpSelectionTransparency ()); + + // (for Rectangle & Ellipse) + kpSelection (Type type, const QRect &rect, const QPixmap &pixmap = QPixmap (), + const kpSelectionTransparency &transparency = kpSelectionTransparency ()); + kpSelection (Type type, const QRect &rect, const kpSelectionTransparency &transparency); + + // (for Text) + kpSelection (const QRect &rect, const QValueVector &textLines_, const kpTextStyle &textStyle_); + + // (for Points) + kpSelection (const QPointArray &points, const QPixmap &pixmap = QPixmap (), + const kpSelectionTransparency &transparency = kpSelectionTransparency ()); + kpSelection (const QPointArray &points, const kpSelectionTransparency &transparency); + + kpSelection (const kpSelection &rhs); + kpSelection &operator= (const kpSelection &rhs); + friend QDataStream &operator<< (QDataStream &stream, const kpSelection &selection); + friend QDataStream &operator>> (QDataStream &stream, kpSelection &selection); + void readFromStream (QDataStream &stream, + const kpPixmapFX::WarnAboutLossInfo &wali = + kpPixmapFX::WarnAboutLossInfo ()); + ~kpSelection (); + +private: + void calculatePoints (); + +public: + Type type () const; + bool isRectangular () const; + bool isText () const; + // returns either i18n ("Selection") or i18n ("Text") + QString name () const; + + int size () const; + + QBitmap maskForOwnType (bool nullForRectangular = false) const; + + // synonyms + QPoint topLeft () const; + QPoint point () const; + + int x () const; + int y () const; + + void moveBy (int dx, int dy); + void moveTo (int dx, int dy); + void moveTo (const QPoint &topLeftPoint); + + // synonyms + QPointArray points () const; + QPointArray pointArray () const; + + QRect boundingRect () const; + int width () const; + int height () const; + + + // (for non-rectangular selections, may return false even if + // kpView::onSelectionResizeHandle()) + bool contains (const QPoint &point) const; + bool contains (int x, int y); + + + // (Avoid using for text selections since text selection may + // require a background for antialiasing purposes - use paint() + // instead, else no antialising) + QPixmap *pixmap () const; + void setPixmap (const QPixmap &pixmap); + + bool usesBackgroundPixmapToPaint () const; + +private: + void paintOpaqueText (QPixmap *destPixmap, const QRect &docRect) const; + QPixmap transparentForegroundTextPixmap () const; + +public: + // ( is the document rectangle that <*destPixmap> represents) + void paint (QPixmap *destPixmap, const QRect &docRect) const; + +private: + void calculateTextPixmap (); + +public: + static QString textForTextLines (const QValueVector &textLines_); + QString text () const; // textLines() as one long string + QValueVector textLines () const; + void setTextLines (const QValueVector &textLines_); + + static int textBorderSize (); + QRect textAreaRect () const; + bool pointIsInTextBorderArea (const QPoint &globalPoint) const; + bool pointIsInTextArea (const QPoint &globalPoint) const; + + + void textResize (int width, int height); + + // TODO: Enforce in kpSelection, not just in kpToolSelection & when pasting + // (in kpMainWindow). + // Be more robust when external enforcement fails. + static int minimumWidthForTextStyle (const kpTextStyle &); + static int minimumHeightForTextStyle (const kpTextStyle &); + static QSize minimumSizeForTextStyle (const kpTextStyle &); + + static int preferredMinimumWidthForTextStyle (const kpTextStyle &textStyle); + static int preferredMinimumHeightForTextStyle (const kpTextStyle &textStyle); + static QSize preferredMinimumSizeForTextStyle (const kpTextStyle &textStyle); + + int minimumWidth () const; + int minimumHeight () const; + QSize minimumSize () const; + + int textRowForPoint (const QPoint &globalPoint) const; + int textColForPoint (const QPoint &globalPoint) const; + QPoint pointForTextRowCol (int row, int col); + + kpTextStyle textStyle () const; + void setTextStyle (const kpTextStyle &textStyle); + + // TODO: ret val inconstent with pixmap() + // - fix when merge with kpTempPixmap + QPixmap opaquePixmap () const; // same as pixmap() + +private: + void calculateTransparencyMask (); + +public: + // Returns opaquePixmap() after applying kpSelectionTransparency + QPixmap transparentPixmap () const; + + kpSelectionTransparency transparency () const; + // Returns whether or not the selection changed due to setting the + // transparency info. If is set, + // it will try harder to return false (although the check is + // expensive). + bool setTransparency (const kpSelectionTransparency &transparency, + bool checkTransparentPixmapChanged = false); + +private: + void flipPoints (bool horiz, bool vert); + +public: + void flip (bool horiz, bool vert); + +signals: + void changed (const QRect &docRect); + +private: + // OPT: use implicit sharing + + Type m_type; + QRect m_rect; + QPointArray m_points; + QPixmap *m_pixmap; + + QValueVector m_textLines; + kpTextStyle m_textStyle; + + kpSelectionTransparency m_transparency; + QBitmap m_transparencyMask; + +private: + // There is no need to maintain binary compatibility at this stage. + // The d-pointer is just so that you can experiment without recompiling + // the kitchen sink. + class kpSelectionPrivate *d; +}; + +#endif // __kpselection_h__ diff --git a/kolourpaint/kpselectiondrag.cpp b/kolourpaint/kpselectiondrag.cpp new file mode 100644 index 00000000..23ab9a4e --- /dev/null +++ b/kolourpaint/kpselectiondrag.cpp @@ -0,0 +1,294 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_SELECTION_DRAG 0 + + +#include + +#include + +#include + +#include +#include + + +// public static +const char * const kpSelectionDrag::selectionMimeType = "application/x-kolourpaint-selection"; + + +kpSelectionDrag::kpSelectionDrag (QWidget *dragSource, const char *name) + : QImageDrag (dragSource, name) +{ +} + +kpSelectionDrag::kpSelectionDrag (const QImage &image, QWidget *dragSource, const char *name) + : QImageDrag (image, dragSource, name) +{ +} + +kpSelectionDrag::kpSelectionDrag (const kpSelection &sel, QWidget *dragSource, const char *name) + : QImageDrag (dragSource, name) +{ + setSelection (sel); +} + +kpSelectionDrag::~kpSelectionDrag () +{ +} + + +// public +void kpSelectionDrag::setSelection (const kpSelection &sel) +{ + if (!sel.pixmap ()) + { + kdError () << "kpSelectionDrag::setSelection() without pixmap" << endl; + return; + } + + m_selection = sel; + + // OPT: an awful waste of memory storing image in both selection and QImage + + // HACK: need to set image else QImageDrag::format() lies + setImage (kpPixmapFX::convertToImage (*m_selection.pixmap ())); +} + +// protected +bool kpSelectionDrag::holdsSelection () const +{ + return bool (m_selection.pixmap ()); +} + + +// public virtual [base QMimeSource] +const char *kpSelectionDrag::format (int which) const +{ +#if DEBUG_KP_SELECTION_DRAG && 0 + kdDebug () << "kpSelectionDrag::format(" << which << ")" << endl; +#endif + const char *ret = QImageDrag::format (which); + if (ret) + { + #if DEBUG_KP_SELECTION_DRAG && 0 + kdDebug () << "\tQImageDrag reports " << ret << endl; + #endif + return ret; + } + + int i; + for (i = 0; QImageDrag::format (i); i++) + ; + +#if DEBUG_KP_SELECTION_DRAG && 0 + kdDebug () << "\tend of QImageDrag format list at " << i << endl; +#endif + + if (i == which) + { + #if DEBUG_KP_SELECTION_DRAG && 0 + kdDebug () << "\treturning own mimetype" << endl; + #endif + return kpSelectionDrag::selectionMimeType; + } + else + { + #if DEBUG_KP_SELECTION_DRAG && 0 + kdDebug () << "\treturning non-existent" << endl; + #endif + return 0; + } +} + +// public virtual [base QMimeSource] +// Don't need to override in Qt 3.2 (the QMimeSource base will work) +// but we do so just in case QImageDrag later decides to override it. +bool kpSelectionDrag::provides (const char *mimeType) const +{ +#if DEBUG_KP_SELECTION_DRAG + kdDebug () << "kpSelectionDrag::provides(" << mimeType << ")" << endl; +#endif + + if (!mimeType) + return false; + + return (!strcmp (mimeType, kpSelectionDrag::selectionMimeType) || + QImageDrag::provides (mimeType)); +} + +// public virtual [base QMimeSource] +QByteArray kpSelectionDrag::encodedData (const char *mimeType) const +{ +#if DEBUG_KP_SELECTION_DRAG + kdDebug () << "kpSelectionDrag::encodedData(" << mimeType << ")" << endl; +#endif + + if (!mimeType) + return QByteArray (); + + if (!strcmp (mimeType, kpSelectionDrag::selectionMimeType)) + { + QByteArray ba; + QDataStream stream (ba, IO_WriteOnly); + + #if DEBUG_KP_SELECTION_DRAG + kdDebug () << "\twant it as kpSelection in QByteArray" << endl; + #endif + + if (holdsSelection ()) + { + #if DEBUG_KP_SELECTION_DRAG + kdDebug () << "\t\thave selection - return it" << endl; + #endif + stream << m_selection; + } + else + { + #if DEBUG_KP_SELECTION_DRAG + kdDebug () << "\t\thave image - call kpSelectionDrag::decode(QImage)" << endl; + #endif + QImage image; + if (kpSelectionDrag::decode (this, image/*ref*/)) + { + #if DEBUG_KP_SELECTION_DRAG + kdDebug () << "\t\t\tok - returning sel with image w=" + << image.width () + << " h=" + << image.height () + << endl; + #endif + + QPixmap pixmap = kpPixmapFX::convertToPixmapAsLosslessAsPossible (image); + + stream << kpSelection (kpSelection::Rectangle, + QRect (0, 0, pixmap.width (), pixmap.height ()), + pixmap); + } + else + { + kdError () << "kpSelectionDrag::encodedData(" << mimeType << ")" + << " kpSelectionDrag(QImage) could not decode data into QImage" + << endl; + stream << kpSelection (); + } + } + + return ba; + } + else + { + #if DEBUG_KP_SELECTION_DRAG + kdDebug () << "\twant it as QImage in QByteArray" << endl; + #endif + + return QImageDrag::encodedData (mimeType); + } +} + + +// public static +bool kpSelectionDrag::canDecode (const QMimeSource *e) +{ +#if DEBUG_KP_SELECTION_DRAG + kdDebug () << "kpSelectionDrag::canDecode()" << endl; +#endif + + if (!e) + return false; + + return (e->provides (kpSelectionDrag::selectionMimeType) || + QImageDrag::canDecode (e)); +} + + +// public static +bool kpSelectionDrag::decode (const QMimeSource *e, QImage &img) +{ +#if DEBUG_KP_SELECTION_DRAG + kdDebug () << "kpSelectionDrag::decode(QImage)" << endl; +#endif + if (!e) + return false; + + return (QImageDrag::canDecode (e) && // prevents X errors, jumps based on unitialised values... + QImageDrag::decode (e, img/*ref*/)); +} + +// public static +bool kpSelectionDrag::decode (const QMimeSource *e, kpSelection &sel, + const kpPixmapFX::WarnAboutLossInfo &wali) +{ +#if DEBUG_KP_SELECTION_DRAG + kdDebug () << "kpSelectionDrag::decode(kpSelection)" << endl; +#endif + if (!e) + return false; + + if (e->provides (kpSelectionDrag::selectionMimeType)) + { + #if DEBUG_KP_SELECTION_DRAG + kdDebug () << "\tmimeSource provides selection - just return it in QByteArray" << endl; + #endif + QByteArray data = e->encodedData (kpSelectionDrag::selectionMimeType); + QDataStream stream (data, IO_ReadOnly); + + // (no need for wali as kpSelection's by definition only support QPixmap's) + stream >> sel; + } + else + { + #if DEBUG_KP_SELECTION_DRAG + kdDebug () << "\tmimeSource doesn't provide selection - try image" << endl; + #endif + + QImage image; + if (kpSelectionDrag::decode (e, image/*ref*/)) + { + #if DEBUG_KP_SELECTION_DRAG + kdDebug () << "\tok w=" << image.width () << " h=" << image.height () << endl; + #endif + + sel = kpSelection (kpSelection::Rectangle, + QRect (0, 0, image.width (), image.height ()), + kpPixmapFX::convertToPixmapAsLosslessAsPossible (image, wali)); + } + else + { + #if DEBUG_KP_SELECTION_DRAG + kdDebug () << "kpSelectionDrag::decode(kpSelection) mimeSource had no sel " + "and could not decode to image" << endl; + #endif + return false; + } + } + + return true; +} + +#include diff --git a/kolourpaint/kpselectiondrag.h b/kolourpaint/kpselectiondrag.h new file mode 100644 index 00000000..5aae82d9 --- /dev/null +++ b/kolourpaint/kpselectiondrag.h @@ -0,0 +1,71 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kp_selection_drag_h__ +#define __kp_selection_drag_h__ + +#include + +#include +#include + + +class kpSelectionDrag : public QImageDrag +{ +Q_OBJECT + +public: + kpSelectionDrag (QWidget *dragSource = 0, const char *name = 0); + kpSelectionDrag (const QImage &image, QWidget *dragSource = 0, const char *name = 0); + kpSelectionDrag (const kpSelection &sel, QWidget *dragSource = 0, const char *name = 0); + virtual ~kpSelectionDrag (); + + static const char * const selectionMimeType; + + void setSelection (const kpSelection &sel); + +protected: + bool holdsSelection () const; + +public: + virtual const char *format (int which = 0) const; + virtual bool provides (const char *mimeType) const; + virtual QByteArray encodedData (const char *mimeType) const; + + static bool canDecode (const QMimeSource *e); + static bool decode (const QMimeSource *e, QImage &img); + static bool decode (const QMimeSource *e, kpSelection &sel, + const kpPixmapFX::WarnAboutLossInfo &wali = + kpPixmapFX::WarnAboutLossInfo ()); + +protected: + kpSelection m_selection; +}; + + +#endif // __kp_selection_drag_h__ diff --git a/kolourpaint/kpselectiontransparency.cpp b/kolourpaint/kpselectiontransparency.cpp new file mode 100644 index 00000000..62919be4 --- /dev/null +++ b/kolourpaint/kpselectiontransparency.cpp @@ -0,0 +1,178 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_SELECTION_TRANSPARENCY 0 + + +#include + +#include + +#include +#include + + +kpSelectionTransparency::kpSelectionTransparency () + : m_isOpaque (true) +{ + setColorSimilarity (0); +} + +kpSelectionTransparency::kpSelectionTransparency (const kpColor &transparentColor, double colorSimilarity) + : m_isOpaque (false), + m_transparentColor (transparentColor) +{ + setColorSimilarity (colorSimilarity); +} + +kpSelectionTransparency::kpSelectionTransparency (bool isOpaque, const kpColor &transparentColor, + double colorSimilarity) + : m_isOpaque (isOpaque), + m_transparentColor (transparentColor) +{ + setColorSimilarity (colorSimilarity); +} + +bool kpSelectionTransparency::operator== (const kpSelectionTransparency &rhs) const +{ +#if DEBUG_KP_SELECTION_TRANSPARENCY && 0 + kdDebug () << "kpSelectionTransparency::operator==()" << endl; +#endif + + if (m_isOpaque != rhs.m_isOpaque) + { + #if DEBUG_KP_SELECTION_TRANSPARENCY && 0 + kdDebug () << "\tdifferent opacity: lhs=" << m_isOpaque + << " rhs=" << rhs.m_isOpaque + << endl; + #endif + return false; + } + + if (m_isOpaque) + { + #if DEBUG_KP_SELECTION_TRANSPARENCY && 0 + kdDebug () << "\tboth opaque - eq" << endl; + #endif + return true; + } + +#if DEBUG_KP_SELECTION_TRANSPARENCY && 0 + kdDebug () << "\tcolours: lhs=" << (int *) m_transparentColor.toQRgb () + << " rhs=" << (int *) rhs.m_transparentColor.toQRgb () + << endl; + kdDebug () << "\tcolour similarity: lhs=" << m_colorSimilarity + << " rhs=" << rhs.m_colorSimilarity + << endl; +#endif + + return (m_transparentColor == rhs.m_transparentColor && + m_colorSimilarity == rhs.m_colorSimilarity); +} + +bool kpSelectionTransparency::operator!= (const kpSelectionTransparency &rhs) const +{ + return !(*this == rhs); +} + +kpSelectionTransparency::~kpSelectionTransparency () +{ +} + + +// public +bool kpSelectionTransparency::isOpaque () const +{ + return m_isOpaque; +} + +// public +bool kpSelectionTransparency::isTransparent () const +{ + return !isOpaque (); +} + +// public +void kpSelectionTransparency::setOpaque (bool yes) +{ + m_isOpaque = yes; +} + +// public +void kpSelectionTransparency::setTransparent (bool yes) +{ + setOpaque (!yes); +} + + +// public +kpColor kpSelectionTransparency::transparentColor () const +{ + if (m_isOpaque) + { + // There are legitimate uses for this so no kdError() + kdDebug () << "kpSelectionTransparency::transparentColor() " + "getting transparent color even though opaque" << endl; + } + + return m_transparentColor; +} + +// public +void kpSelectionTransparency::setTransparentColor (const kpColor &transparentColor) +{ + m_transparentColor = transparentColor; +} + + +// public +double kpSelectionTransparency::colorSimilarity () const +{ + if (m_colorSimilarity < 0 || + m_colorSimilarity > kpColorSimilarityDialog::maximumColorSimilarity) + { + kdError () << "kpSelectionTransparency::colorSimilarity() invalid colorSimilarity" << endl; + return 0; + } + + return m_colorSimilarity; +} + +// pubulic +void kpSelectionTransparency::setColorSimilarity (double colorSimilarity) +{ + m_colorSimilarity = colorSimilarity; + m_processedColorSimilarity = kpColor::processSimilarity (colorSimilarity); +} + +// public +int kpSelectionTransparency::processedColorSimilarity () const +{ + return m_processedColorSimilarity; +} + diff --git a/kolourpaint/kpselectiontransparency.h b/kolourpaint/kpselectiontransparency.h new file mode 100644 index 00000000..690c4c1e --- /dev/null +++ b/kolourpaint/kpselectiontransparency.h @@ -0,0 +1,80 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __kp_selection_transparency_h__ +#define __kp_selection_transparency_h__ + +#include + + +// This does not apply to the Text Tool. Use kpTextStyle for that. +class kpSelectionTransparency +{ +public: + // Opaque selection + kpSelectionTransparency (); + // Selection that's transparent at pixels with + kpSelectionTransparency (const kpColor &transparentColor, double colorSimilarity); + // If , is allowed to be anything + // (including invalid) as the color would have no effect. + // However, you are encouraged to set it as you would if !, + // because setTransparent(true) might be called later, after which + // the would suddenly become important. + // + // It is a similar case with , although + // must be in-range (see kpColorSimilarityDialog). + kpSelectionTransparency (bool isOpaque, const kpColor &transparentColor, double colorSimilarity); + // Returns whether they are visually equivalent. + // This is the same as a memcmp() except that if they are both opaque, + // this function will return true regardless of the transparentColor's. + bool operator== (const kpSelectionTransparency &rhs) const; + bool operator!= (const kpSelectionTransparency &rhs) const; + ~kpSelectionTransparency (); + + bool isOpaque () const; + bool isTransparent () const; + void setOpaque (bool yes = true); + void setTransparent (bool yes = true); + + // If isOpaque(), transparentColor() is generally not called because + // the transparent color would have no effect. + kpColor transparentColor () const; + void setTransparentColor (const kpColor &transparentColor); + + double colorSimilarity () const; + void setColorSimilarity (double colorSimilarity); + int processedColorSimilarity () const; + +private: + bool m_isOpaque; + kpColor m_transparentColor; + double m_colorSimilarity; + int m_processedColorSimilarity; +}; + + +#endif // __kp_selection_transparency_h__ diff --git a/kolourpaint/kpsinglekeytriggersaction.cpp b/kolourpaint/kpsinglekeytriggersaction.cpp new file mode 100644 index 00000000..d3b64002 --- /dev/null +++ b/kolourpaint/kpsinglekeytriggersaction.cpp @@ -0,0 +1,155 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_SINGLE_KEY_TRIGGERS_ACTION 0 + + +// +// kpSingleKeyTriggersActionInterface +// + + +#include + +#include + +#include + + +kpSingleKeyTriggersActionInterface::kpSingleKeyTriggersActionInterface () +{ + m_singleKeyTriggersEnabled = true; +} + +kpSingleKeyTriggersActionInterface::~kpSingleKeyTriggersActionInterface () +{ +} + + +// public +bool kpSingleKeyTriggersActionInterface::singleKeyTriggersEnabled () const +{ + return m_singleKeyTriggersEnabled; +} + +// public +void kpSingleKeyTriggersActionInterface::enableSingleKeyTriggers (bool enable) +{ +#if DEBUG_KP_SINGLE_KEY_TRIGGERS_ACTION + kdDebug () << "kpSingleKeyTriggersActionInterface(" << /*virtual*/actionName () + << ")::enableSingleKeyTriggers(" << enable << ")" + << endl; +#endif + + if (enable == m_singleKeyTriggersEnabled) + { + #if DEBUG_KP_SINGLE_KEY_TRIGGERS_ACTION + kdDebug () << "\tnop" << endl; + #endif + return; + } + + m_singleKeyTriggersEnabled = enable; + + + if (enable) + { + #if DEBUG_KP_SINGLE_KEY_TRIGGERS_ACTION + kdDebug () << "\tre-enabling to " << m_fullShortcut.toString () << endl; + #endif + /*pure virtual*/actionSetShortcut (m_fullShortcut); + } + else // disable single key triggers + { + m_fullShortcut = /*pure virtual*/actionShortcut (); + + KShortcut newShortcut; + if (kpTool::containsSingleKeyTrigger (m_fullShortcut, &newShortcut)) + { + #if DEBUG_KP_SINGLE_KEY_TRIGGERS_ACTION + kdDebug () << "\tchange shortcuts: old=" + << m_fullShortcut.toString () + << " new=" + << newShortcut.toString () + << endl; + #endif + /*pure virtual*/actionSetShortcut (newShortcut); + } + else + { + #if DEBUG_KP_SINGLE_KEY_TRIGGERS_ACTION + kdDebug () << "\tshortcut is untouched " + << m_fullShortcut.toString () + << endl; + #endif + } + } +} + + +// +// kpSingleKeyTriggersAction +// + + +kpSingleKeyTriggersAction::kpSingleKeyTriggersAction (const QString &text, + const KShortcut &shortcut, + const QObject *receiver, const char *slot, + KActionCollection *parent, const char *name) + : KAction (text, shortcut, receiver, slot, parent, name) +{ +} + +kpSingleKeyTriggersAction::~kpSingleKeyTriggersAction () +{ +} + + +// +// kpSingleKeyTriggersAction implements kpSingleKeyTriggersActionInterface +// + +// public virtual [base kpSingleKeyTriggersActionInterface] +const char *kpSingleKeyTriggersAction::actionName () const +{ + return name (); +} + +// public virtual [base kpSingleKeyTriggersActionInterface] +KShortcut kpSingleKeyTriggersAction::actionShortcut () const +{ + return shortcut (); +} + +// public virtual [base kpSingleKeyTriggersActionInterface] +void kpSingleKeyTriggersAction::actionSetShortcut (const KShortcut &shortcut) +{ + setShortcut (shortcut); +} + + +#include diff --git a/kolourpaint/kpsinglekeytriggersaction.h b/kolourpaint/kpsinglekeytriggersaction.h new file mode 100644 index 00000000..fc404bd5 --- /dev/null +++ b/kolourpaint/kpsinglekeytriggersaction.h @@ -0,0 +1,82 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef KP_SINGLE_KEY_TRIGGERS_ACTION_H +#define KP_SINGLE_KEY_TRIGGERS_ACTION_H + + +#include + + +class kpSingleKeyTriggersActionInterface +{ +public: + kpSingleKeyTriggersActionInterface (); + virtual ~kpSingleKeyTriggersActionInterface (); + + bool singleKeyTriggersEnabled () const; + void enableSingleKeyTriggers (bool enable = true); + + // Avoid inheritance diamond by not deriving from KAction + // so you'll have to implement these by talking to your base KAction. + virtual const char *actionName () const { return 0; } + virtual KShortcut actionShortcut () const = 0; + virtual void actionSetShortcut (const KShortcut &shortcut) = 0; + +protected: + bool m_singleKeyTriggersEnabled; + KShortcut m_fullShortcut; +}; + + +#include + + +class kpSingleKeyTriggersAction : public KAction, + public kpSingleKeyTriggersActionInterface +{ +Q_OBJECT + +public: + kpSingleKeyTriggersAction (const QString &text, + const KShortcut &shortcut, + const QObject *receiver, const char *slot, + KActionCollection *parent, const char *name); + virtual ~kpSingleKeyTriggersAction (); + + + // + // kpSingleKeyTriggersActionInterface + // + + virtual const char *actionName () const; + virtual KShortcut actionShortcut () const; + virtual void actionSetShortcut (const KShortcut &shortcut); +}; + + +#endif // KP_SINGLE_KEY_TRIGGERS_ACTION_H diff --git a/kolourpaint/kptemppixmap.cpp b/kolourpaint/kptemppixmap.cpp new file mode 100644 index 00000000..55f669ee --- /dev/null +++ b/kolourpaint/kptemppixmap.cpp @@ -0,0 +1,148 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_TEMP_PIXMAP 0 + + +#include + +#include +#include + + +kpTempPixmap::kpTempPixmap (bool isBrush, RenderMode renderMode, + const QPoint &topLeft, const QPixmap &pixmap) + : m_isBrush (isBrush), + m_renderMode (renderMode), + m_topLeft (topLeft), + m_pixmap (pixmap) +{ +} + +kpTempPixmap::kpTempPixmap (const kpTempPixmap &rhs) + : m_isBrush (rhs.m_isBrush), + m_renderMode (rhs.m_renderMode), + m_topLeft (rhs.m_topLeft), + m_pixmap (rhs.m_pixmap) +{ +} + +kpTempPixmap &kpTempPixmap::operator= (const kpTempPixmap &rhs) +{ + if (this == &rhs) + return *this; + + m_isBrush = rhs.m_isBrush; + m_renderMode = rhs.m_renderMode; + m_topLeft = rhs.m_topLeft; + m_pixmap = rhs.m_pixmap; + + return *this; +} + +kpTempPixmap::~kpTempPixmap () +{ +} + + +// public +bool kpTempPixmap::isBrush () const +{ + return m_isBrush; +} + +// public +kpTempPixmap::RenderMode kpTempPixmap::renderMode () const +{ + return m_renderMode; +} + +// public +QPoint kpTempPixmap::topLeft () const +{ + return m_topLeft; +} + +// public +QPixmap kpTempPixmap::pixmap () const +{ + return m_pixmap; +} + + +// public +bool kpTempPixmap::isVisible (const kpViewManager *vm) const +{ + return m_isBrush ? (bool) vm->viewUnderCursor () : true; +} + +// public +QRect kpTempPixmap::rect () const +{ + return QRect (m_topLeft.x (), m_topLeft.y (), + m_pixmap.width (), m_pixmap.height ()); +} + +// public +int kpTempPixmap::width () const +{ + return m_pixmap.width (); +} + +// public +int kpTempPixmap::height () const +{ + return m_pixmap.height (); +} + + +// public +bool kpTempPixmap::mayChangeDocumentMask () const +{ + return (m_renderMode == SetPixmap || + m_renderMode == PaintMaskTransparentWithBrush); +} + +// public +void kpTempPixmap::paint (QPixmap *destPixmap, const QRect &docRect) const +{ +#define PARAMS destPixmap, m_topLeft - docRect.topLeft (), m_pixmap + switch (m_renderMode) + { + case SetPixmap: + kpPixmapFX::setPixmapAt (PARAMS); + break; + case PaintPixmap: + kpPixmapFX::paintPixmapAt (PARAMS); + break; + case PaintMaskTransparentWithBrush: + kpPixmapFX::paintMaskTransparentWithBrush (PARAMS); + break; + } +#undef PARAMS +} diff --git a/kolourpaint/kptemppixmap.h b/kolourpaint/kptemppixmap.h new file mode 100644 index 00000000..6ddb9413 --- /dev/null +++ b/kolourpaint/kptemppixmap.h @@ -0,0 +1,90 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// TODO: maybe merge with kpSelection? + + +#ifndef __kp_temp_pixmap_h__ +#define __kp_temp_pixmap_h__ + + +#include +#include + +class kpViewManager; + + +class kpTempPixmap +{ +public: + enum RenderMode + { + SetPixmap, + PaintPixmap, + PaintMaskTransparentWithBrush + }; + + /* + * Specifies that its visibility is dependent on whether or + * not the mouse cursor is inside a view. If false, the + * pixmap is always displayed. + */ + kpTempPixmap (bool isBrush, RenderMode renderMode, const QPoint &topLeft, const QPixmap &pixmap); + kpTempPixmap (const kpTempPixmap &rhs); + kpTempPixmap &operator= (const kpTempPixmap &rhs); + ~kpTempPixmap (); + + bool isBrush () const; + RenderMode renderMode () const; + QPoint topLeft () const; + QPixmap pixmap () const; + + bool isVisible (const kpViewManager *vm) const; + QRect rect () const; + int width () const; + int height () const; + + + // Returns whether a call to paint() may change <*destPixmap>'s mask + bool mayChangeDocumentMask () const; + + /* + * Draws itself onto <*destPixmap>, given that <*destPixmap> represents + * the unzoomed of the kpDocument. You should check for + * visibility before calling this function. + */ + void paint (QPixmap *destPixmap, const QRect &docRect) const; + +private: + bool m_isBrush; + RenderMode m_renderMode; + QPoint m_topLeft; + QPixmap m_pixmap; +}; + + +#endif // __kp_temp_pixmap_h__ diff --git a/kolourpaint/kptextstyle.cpp b/kolourpaint/kptextstyle.cpp new file mode 100644 index 00000000..9f4d8fce --- /dev/null +++ b/kolourpaint/kptextstyle.cpp @@ -0,0 +1,279 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include +#include +#include + + +kpTextStyle::kpTextStyle () + : m_fontSize (0), + m_isBold (false), m_isItalic (false), + m_isUnderline (false), m_isStrikeThru (false), + m_isBackgroundOpaque (true) +{ +} + +kpTextStyle::kpTextStyle (const QString &fontFamily, + int fontSize, + bool isBold, bool isItalic, + bool isUnderline, bool isStrikeThru, + const kpColor &fcolor, const kpColor &bcolor, + bool isBackgroundOpaque) + : m_fontFamily (fontFamily), + m_fontSize (fontSize), + m_isBold (isBold), m_isItalic (isItalic), + m_isUnderline (isUnderline), m_isStrikeThru (isStrikeThru), + m_foregroundColor (fcolor), m_backgroundColor (bcolor), + m_isBackgroundOpaque (isBackgroundOpaque) +{ +} + +kpTextStyle::~kpTextStyle () +{ +} + + +// friend +QDataStream &operator<< (QDataStream &stream, const kpTextStyle &textStyle) +{ + stream << textStyle.m_fontFamily; + stream << textStyle.m_fontSize; + + stream << int (textStyle.m_isBold) << int (textStyle.m_isItalic) + << int (textStyle.m_isUnderline) << int (textStyle.m_isStrikeThru); + + stream << textStyle.m_foregroundColor << textStyle.m_backgroundColor; + + stream << int (textStyle.m_isBackgroundOpaque); + + return stream; +} + +// friend +QDataStream &operator>> (QDataStream &stream, kpTextStyle &textStyle) +{ + stream >> textStyle.m_fontFamily; + stream >> textStyle.m_fontSize; + + int a, b, c, d; + stream >> a >> b >> c >> d; + textStyle.m_isBold = a; + textStyle.m_isItalic = b; + textStyle.m_isUnderline = c; + textStyle.m_isStrikeThru = d; + + stream >> textStyle.m_foregroundColor >> textStyle.m_backgroundColor; + + int e; + stream >> e; + textStyle.m_isBackgroundOpaque = e; + + return stream; +} + +// public +bool kpTextStyle::operator== (const kpTextStyle &rhs) const +{ + return (m_fontFamily == rhs.m_fontFamily && + m_fontSize == rhs.m_fontSize && + m_isBold == rhs.m_isBold && + m_isItalic == rhs.m_isItalic && + m_isUnderline == rhs.m_isUnderline && + m_isStrikeThru == rhs.m_isStrikeThru && + m_foregroundColor == rhs.m_foregroundColor && + m_backgroundColor == rhs.m_backgroundColor && + m_isBackgroundOpaque == rhs.m_isBackgroundOpaque); +} + +// public +bool kpTextStyle::operator!= (const kpTextStyle &rhs) const +{ + return !(*this == rhs); +} + + +// public +QString kpTextStyle::fontFamily () const +{ + return m_fontFamily; +} + +// public +void kpTextStyle::setFontFamily (const QString &f) +{ + m_fontFamily = f; +} + + +// public +int kpTextStyle::fontSize () const +{ + return m_fontSize; +} + +// public +void kpTextStyle::setFontSize (int s) +{ + m_fontSize = s; +} + + +// public +bool kpTextStyle::isBold () const +{ + return m_isBold; +} + +// public +void kpTextStyle::setBold (bool yes) +{ + m_isBold = yes; +} + + +// public +bool kpTextStyle::isItalic () const +{ + return m_isItalic; +} + +// public +void kpTextStyle::setItalic (bool yes) +{ + m_isItalic = yes; +} + + +// public +bool kpTextStyle::isUnderline () const +{ + return m_isUnderline; +} + +// public +void kpTextStyle::setUnderline (bool yes) +{ + m_isUnderline = yes; +} + + +// public +bool kpTextStyle::isStrikeThru () const +{ + return m_isStrikeThru; +} + +// public +void kpTextStyle::setStrikeThru (bool yes) +{ + m_isStrikeThru = yes; +} + + +// public +kpColor kpTextStyle::foregroundColor () const +{ + return m_foregroundColor; +} + +// public +void kpTextStyle::setForegroundColor (const kpColor &fcolor) +{ + m_foregroundColor = fcolor; +} + + +// public +kpColor kpTextStyle::backgroundColor () const +{ + return m_backgroundColor; +} + +// public +void kpTextStyle::setBackgroundColor (const kpColor &bcolor) +{ + m_backgroundColor = bcolor; +} + + +// public +bool kpTextStyle::isBackgroundOpaque () const +{ + return m_isBackgroundOpaque; +} + +// public +void kpTextStyle::setBackgroundOpaque (bool yes) +{ + m_isBackgroundOpaque = yes; +} + + +// public +bool kpTextStyle::isBackgroundTransparent () const +{ + return !m_isBackgroundOpaque; +} + +// public +void kpTextStyle::setBackgroundTransparent (bool yes) +{ + m_isBackgroundOpaque = !yes; +} + + +// public +kpColor kpTextStyle::effectiveBackgroundColor () const +{ + if (isBackgroundOpaque ()) + return backgroundColor (); + else + return kpColor::transparent; +} + + +// public +QFont kpTextStyle::font () const +{ + QFont fnt (m_fontFamily, m_fontSize); + fnt.setBold (m_isBold); + fnt.setItalic (m_isItalic); + fnt.setUnderline (m_isUnderline); + fnt.setStrikeOut (m_isStrikeThru); + + return fnt; +} + +// public +QFontMetrics kpTextStyle::fontMetrics () const +{ + return QFontMetrics (font ()); +} diff --git a/kolourpaint/kptextstyle.h b/kolourpaint/kptextstyle.h new file mode 100644 index 00000000..9356ce2c --- /dev/null +++ b/kolourpaint/kptextstyle.h @@ -0,0 +1,108 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __kp_text_style_h__ +#define __kp_text_style_h__ + +#include + +#include + +class QDataStream; +class QFont; +class QFontMetrics; + +class kpTextStyle +{ +public: + kpTextStyle (); + kpTextStyle (const QString &fontFamily, + int fontSize, + bool isBold, bool isItalic, + bool isUnderline, bool isStrikeThru, + const kpColor &fcolor, + const kpColor &bcolor, + bool isBackgroundOpaque); + ~kpTextStyle (); + + + friend QDataStream &operator<< (QDataStream &stream, const kpTextStyle &textStyle); + friend QDataStream &operator>> (QDataStream &stream, kpTextStyle &textStyle); + bool operator== (const kpTextStyle &rhs) const; + bool operator!= (const kpTextStyle &rhs) const; + + + QString fontFamily () const; + void setFontFamily (const QString &f); + + int fontSize () const; + void setFontSize (int s); + + bool isBold () const; + void setBold (bool yes = true); + + bool isItalic () const; + void setItalic (bool yes = true); + + bool isUnderline () const; + void setUnderline (bool yes = true); + + bool isStrikeThru () const; + void setStrikeThru (bool yes = true); + + kpColor foregroundColor () const; + void setForegroundColor (const kpColor &fcolor); + + // Note: This is the _input_ backgroundColor without applying any + // isBackground(Opaque|Transparent)() transformation. + // See effectiveBackgroundColor(). + kpColor backgroundColor () const; + void setBackgroundColor (const kpColor &bcolor); + + bool isBackgroundOpaque () const; + void setBackgroundOpaque (bool yes = true); + + bool isBackgroundTransparent () const; + void setBackgroundTransparent (bool yes = true); + + + // If isBackgroundOpaque(), returns backgroundColor(). + // Else, returns kpColor::transparent. + kpColor effectiveBackgroundColor () const; + + QFont font () const; + QFontMetrics fontMetrics () const; + +private: + QString m_fontFamily; + int m_fontSize; + bool m_isBold, m_isItalic, m_isUnderline, m_isStrikeThru; + kpColor m_foregroundColor, m_backgroundColor; + bool m_isBackgroundOpaque; +}; + +#endif // __kp_text_style_h__ diff --git a/kolourpaint/kpthumbnail.cpp b/kolourpaint/kpthumbnail.cpp new file mode 100644 index 00000000..a45164ac --- /dev/null +++ b/kolourpaint/kpthumbnail.cpp @@ -0,0 +1,213 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_THUMBNAIL 0 + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + + +// TODO: get out of the Alt+Tab list +kpThumbnail::kpThumbnail (kpMainWindow *parent, const char *name) +#if KP_IS_QT_3_3 + : QDockWindow (QDockWindow::OutsideDock, parent, name), +#else // With Qt <3.3, OutsideDock requires parent = 0, + // sync: make sure outside of dock + : QDockWindow (QDockWindow::InDock, parent, name), + #warning "Using Qt <3.3: the thumbnail will flicker more when appearing" +#endif + m_mainWindow (parent), + m_view (0) +{ + if (!parent) + kdError () << "kpThumbnail::kpThumbnail() requires parent" << endl; + + +#if !KP_IS_QT_3_3 + if (parent) + { + hide (); + + // sync: make sure outside of dock + parent->moveDockWindow (this, Qt::DockTornOff); + } +#endif + + + if (parent) + { + // Prevent thumbnail from docking - it's _really_ irritating otherwise + parent->leftDock ()->setAcceptDockWindow (this, false); + parent->rightDock ()->setAcceptDockWindow (this, false); + parent->topDock ()->setAcceptDockWindow (this, false); + parent->bottomDock ()->setAcceptDockWindow (this, false); + } + + + QSize layoutMinimumSize = layout () ? layout ()->minimumSize () : QSize (); +#if DEBUG_KP_THUMBNAIL + kdDebug () << "\tlayout=" << layout () + << " minSize=" << (layout () ? layout ()->minimumSize () : QSize ()) << endl; + kdDebug () << "\tboxLayout=" << boxLayout () + << " minSize=" << (boxLayout () ? boxLayout ()->minimumSize () : QSize ()) + << endl; +#endif + if (layout ()) + layout ()->setResizeMode (QLayout::FreeResize); + setMinimumSize (QMAX (layoutMinimumSize.width (), 64), + QMAX (layoutMinimumSize.height (), 64)); + + + // Enable "X" Close Button + setCloseMode (QDockWindow::Always); + + setResizeEnabled (true); + + updateCaption (); +} + +kpThumbnail::~kpThumbnail () +{ +} + + +// public +kpThumbnailView *kpThumbnail::view () const +{ + return m_view; +} + +// public +void kpThumbnail::setView (kpThumbnailView *view) +{ +#if DEBUG_KP_THUMBNAIL + kdDebug () << "kpThumbnail::setView(" << view << ")" << endl; +#endif + + if (m_view == view) + return; + + + if (m_view) + { + disconnect (m_view, SIGNAL (destroyed ()), + this, SLOT (slotViewDestroyed ())); + disconnect (m_view, SIGNAL (zoomLevelChanged (int, int)), + this, SLOT (updateCaption ())); + + boxLayout ()->remove (m_view); + } + + m_view = view; + + if (m_view) + { + connect (m_view, SIGNAL (destroyed ()), + this, SLOT (slotViewDestroyed ())); + connect (m_view, SIGNAL (zoomLevelChanged (int, int)), + this, SLOT (updateCaption ())); + updateCaption (); + + boxLayout ()->addWidget (m_view); + m_view->show (); + } +} + + +// public slot +void kpThumbnail::updateCaption () +{ + setCaption (view () ? view ()->caption () : i18n ("Thumbnail")); +} + + +// public slot virtual [base QDockWindow] +void kpThumbnail::dock () +{ +#if DEBUG_KP_THUMBNAIL + kdDebug () << "kpThumbnail::dock() CALLED - ignoring request" << endl; +#endif + + // --- ignore all requests to dock --- +} + + +// protected slot +void kpThumbnail::slotViewDestroyed () +{ +#if DEBUG_KP_THUMBNAIL + kdDebug () << "kpThumbnail::slotViewDestroyed()" << endl; +#endif + + m_view = 0; + updateCaption (); +} + + +// protected virtual [base QWidget] +void kpThumbnail::resizeEvent (QResizeEvent *e) +{ +#if DEBUG_KP_THUMBNAIL + kdDebug () << "kpThumbnail::resizeEvent(" << width () + << "," << height () << ")" << endl; +#endif + + QDockWindow::resizeEvent (e); + + // updateVariableZoom (); TODO: is below a good idea since this commented out + + if (m_mainWindow) + { + m_mainWindow->notifyThumbnailGeometryChanged (); + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + } +} + +// protected virtual [base QWidget] +void kpThumbnail::moveEvent (QMoveEvent * /*e*/) +{ + if (m_mainWindow) + m_mainWindow->notifyThumbnailGeometryChanged (); +} + + +#include diff --git a/kolourpaint/kpthumbnail.h b/kolourpaint/kpthumbnail.h new file mode 100644 index 00000000..183dc2f1 --- /dev/null +++ b/kolourpaint/kpthumbnail.h @@ -0,0 +1,68 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kp_thumbnail_h__ +#define __kp_thumbnail_h__ + +#include + +class kpMainWindow; +class kpThumbnailView; + + +class kpThumbnail : public QDockWindow +{ +Q_OBJECT + +public: + kpThumbnail (kpMainWindow *parent, const char *name = 0); + virtual ~kpThumbnail (); + +public: + kpThumbnailView *view () const; + void setView (kpThumbnailView *view); + +public slots: + void updateCaption (); + + virtual void dock (); + +protected slots: + void slotViewDestroyed (); + +protected: + virtual void resizeEvent (QResizeEvent *e); + virtual void moveEvent (QMoveEvent *e); + +private: + kpMainWindow *m_mainWindow; + kpThumbnailView *m_view; +}; + + +#endif // __kp_thumbnail_h__ diff --git a/kolourpaint/kptool.cpp b/kolourpaint/kptool.cpp new file mode 100644 index 00000000..8d337c5b --- /dev/null +++ b/kolourpaint/kptool.cpp @@ -0,0 +1,1666 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_TOOL 0 + + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// +// kpTool +// + +struct kpToolPrivate +{ +}; + + +kpTool::kpTool (const QString &text, const QString &description, + int key, + kpMainWindow *mainWindow, const char *name) +{ + init (text, description, key, mainWindow, name); +} + +kpTool::~kpTool () +{ + // before destructing, stop using the tool + if (m_began) + endInternal (); + + if (m_action) + { + if (m_mainWindow && m_mainWindow->actionCollection ()) + m_mainWindow->actionCollection ()->remove (m_action); + else + delete m_action; + } + + delete d; +} + + +// private +void kpTool::init (const QString &text, const QString &description, + int key, + kpMainWindow *mainWindow, const char *name) +{ + d = new kpToolPrivate (); + + m_key = key; + m_action = 0; + m_ignoreColorSignals = 0; + m_shiftPressed = false, m_controlPressed = false, m_altPressed = false; // set in beginInternal() + m_beganDraw = false; + m_text = text, m_description = description, m_name = name; + m_mainWindow = mainWindow; + m_began = false; + m_viewUnderStartPoint = 0; + m_userShapeStartPoint = KP_INVALID_POINT; + m_userShapeEndPoint = KP_INVALID_POINT; + m_userShapeSize = KP_INVALID_SIZE; + + createAction (); +} + + +// private +void kpTool::createAction () +{ +#if DEBUG_KP_TOOL && 0 + kdDebug () << "kpTool(" << name () << "::createAction()" << endl; +#endif + + if (!m_mainWindow) + { + kdError () << "kpTool::createAction() without mw" << endl; + return; + } + + KActionCollection *ac = m_mainWindow->actionCollection (); + if (!ac) + { + kdError () << "kpTool::createAction() without ac" << endl; + return; + } + + + if (m_action) + { + // TODO: I don't think this will ever be executed as we are not called + // outside of the constructor. + #if DEBUG_KP_TOOL + kdDebug () << "\tdeleting existing" << endl; + #endif + ac->remove (m_action); + m_action = 0; + } + + + m_action = new kpToolAction (text (), iconName (), shortcutForKey (m_key), + this, SLOT (slotActionActivated ()), + m_mainWindow->actionCollection (), name ()); + m_action->setExclusiveGroup (QString::fromLatin1 ("Tool Box Actions")); + m_action->setWhatsThis (description ()); + + connect (m_action, SIGNAL (toolTipChanged (const QString &)), + this, SLOT (slotActionToolTipChanged (const QString &))); +} + + +// protected slot +void kpTool::slotActionToolTipChanged (const QString &string) +{ + emit actionToolTipChanged (string); +} + + +// public +QString kpTool::text () const +{ + return m_text; +} + +// public +void kpTool::setText (const QString &text) +{ + m_text = text; + + if (m_action) + m_action->setText (m_text); + else + createAction (); +} + + +// public static +QString kpTool::toolTipForTextAndShortcut (const QString &text, + const KShortcut &shortcut) +{ + for (int i = 0; i < (int) shortcut.count (); i++) + { + const KKeySequence seq = shortcut.seq (i); + if (seq.count () == 1 && containsSingleKeyTrigger (seq)) + { + return i18n (" ()", + "%1 (%2)") + .arg (text, seq.toString ()); + } + } + + return text; +} + +// public static +QString kpTool::toolTip () const +{ + return toolTipForTextAndShortcut (text (), shortcut ()); +} + + +// public +int kpTool::key () const +{ + return m_key; +} + +// public +void kpTool::setKey (int key) +{ + m_key = key; + + if (m_action) + // TODO: this probably not wise since it nukes the user's settings + m_action->setShortcut (shortcutForKey (m_key)); + else + createAction (); +} + +// public static +KShortcut kpTool::shortcutForKey (int key) +{ + KShortcut shortcut; + + if (key) + { + shortcut.append (KKeySequence (KKey (key))); + // (CTRL+, ALT+, CTRL+ALT+, CTRL+SHIFT+ + // all clash with global KDE shortcuts) + shortcut.append (KKeySequence (KKey (Qt::ALT + Qt::SHIFT + key))); + } + + return shortcut; +} + +// public +KShortcut kpTool::shortcut () const +{ + return m_action ? m_action->shortcut () : KShortcut (); +} + + +// public static +bool kpTool::keyIsText (int key) +{ + // TODO: should work like !QKeyEvent::text().isEmpty() + return !(key & (Qt::MODIFIER_MASK ^ Qt::SHIFT)); +} + +// public static +bool kpTool::containsSingleKeyTrigger (const KKeySequence &seq) +{ + for (int i = 0; i < (int) seq.count (); i++) + { + const KKey key = seq.key (i); + if (keyIsText (key.keyCodeQt ())) + return true; + } + + return false; +} + +// public static +bool kpTool::containsSingleKeyTrigger (const KShortcut &shortcut, + KShortcut *shortcutWithoutSingleKeyTriggers) +{ + if (shortcutWithoutSingleKeyTriggers) + *shortcutWithoutSingleKeyTriggers = shortcut; + + + KShortcut newShortcut; + bool needNewShortcut = false; + + for (int i = 0; i < (int) shortcut.count (); i++) + { + const KKeySequence seq = shortcut.seq (i); + + if (containsSingleKeyTrigger (seq)) + { + needNewShortcut = true; + } + else + { + newShortcut.append (seq); + } + } + + + if (needNewShortcut && shortcutWithoutSingleKeyTriggers) + *shortcutWithoutSingleKeyTriggers = newShortcut; + + return needNewShortcut; +} + + +// public +bool kpTool::singleKeyTriggersEnabled () const +{ + return (m_action ? m_action->singleKeyTriggersEnabled () : true); +} + +// public +void kpTool::enableSingleKeyTriggers (bool enable) +{ +#if DEBUG_KP_TOOL && 0 + kdDebug () << "kpTool(" << name () << ")::enableSingleKeyTriggers(" + << enable << ")" << endl; +#endif + + if (!m_action) + { + #if DEBUG_KP_TOOL && 0 + kdDebug () << "\tno action" << endl; + #endif + return; + } + + m_action->enableSingleKeyTriggers (enable); +} + + +// public +QString kpTool::description () const +{ + return m_description; +} + +// public +void kpTool::setDescription (const QString &description) +{ + m_description = description; + + if (m_action) + m_action->setWhatsThis (m_description); + else + createAction (); +} + + +// public +const char *kpTool::name () const +{ + return m_name; +} + + +// static +QRect kpTool::neededRect (const QRect &rect, int lineWidth) +{ + int x1, y1, x2, y2; + rect.coords (&x1, &y1, &x2, &y2); + + if (lineWidth < 1) + lineWidth = 1; + + return QRect (QPoint (x1 - lineWidth + 1, y1 - lineWidth + 1), + QPoint (x2 + lineWidth - 1, y2 + lineWidth - 1)); +} + +// static +QPixmap kpTool::neededPixmap (const QPixmap &pixmap, const QRect &boundingRect) +{ + return kpPixmapFX::getPixmapAt (pixmap, boundingRect); +} + + +// public +bool kpTool::hasCurrentPoint () const +{ + return (viewUnderStartPoint () || viewUnderCursor ()); +} + +// public +QPoint kpTool::currentPoint (bool zoomToDoc) const +{ +#if DEBUG_KP_TOOL && 0 + kdDebug () << "kpTool::currentPoint(zoomToDoc=" << zoomToDoc << ")" << endl; + kdDebug () << "\tviewUnderStartPoint=" + << (viewUnderStartPoint () ? viewUnderStartPoint ()->name () : "(none)") + << " viewUnderCursor=" + << (viewUnderCursor () ? viewUnderCursor ()->name () : "(none)") + << endl; +#endif + + kpView *v = viewUnderStartPoint (); + if (!v) + { + v = viewUnderCursor (); + if (!v) + { + #if DEBUG_KP_TOOL && 0 + kdDebug () << "\tno view - returning sentinel" << endl; + #endif + return KP_INVALID_POINT; + } + } + + + const QPoint globalPos = QCursor::pos (); + const QPoint viewPos = v->mapFromGlobal (globalPos); +#if DEBUG_KP_TOOL && 0 + kdDebug () << "\tglobalPos=" << globalPos + << " viewPos=" << viewPos + << endl; +#endif + if (!zoomToDoc) + return viewPos; + + + const QPoint docPos = v->transformViewToDoc (viewPos); +#if DEBUG_KP_TOOL && 0 + kdDebug () << "\tdocPos=" << docPos << endl; +#endif + return docPos; +} + + +// public slot +void kpTool::somethingBelowTheCursorChanged () +{ + somethingBelowTheCursorChanged (currentPoint (), + currentPoint (false/*view point*/)); +} + +// private +// TODO: don't dup code from mouseMoveEvent() +void kpTool::somethingBelowTheCursorChanged (const QPoint ¤tPoint_, + const QPoint ¤tViewPoint_) +{ +#if DEBUG_KP_TOOL && 0 + kdDebug () << "kpTool::somethingBelowTheCursorChanged(docPoint=" + << currentPoint_ + << " viewPoint=" + << currentViewPoint_ + << ")" << endl; + kdDebug () << "\tviewUnderStartPoint=" + << (viewUnderStartPoint () ? viewUnderStartPoint ()->name () : "(none)") + << " viewUnderCursor=" + << (viewUnderCursor () ? viewUnderCursor ()->name () : "(none)") + << endl; + kdDebug () << "\tbegan draw=" << m_beganDraw << endl; +#endif + + m_currentPoint = currentPoint_; + m_currentViewPoint = currentViewPoint_; + + if (m_beganDraw) + { + if (m_currentPoint != KP_INVALID_POINT) + { + draw (m_currentPoint, m_lastPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + m_lastPoint = m_currentPoint; + } + } + else + { + hover (m_currentPoint); + } +} + + +void kpTool::beginInternal () +{ +#if DEBUG_KP_TOOL + kdDebug () << "kpTool::beginInternal()" << endl; +#endif + + if (!m_began) + { + // clear leftover statusbar messages + setUserMessage (); + m_currentPoint = currentPoint (); + m_currentViewPoint = currentPoint (false/*view point*/); + setUserShapePoints (m_currentPoint); + + // TODO: Audit all the code in this file - states like "m_began" & + // "m_beganDraw" should be set before calling user func. + // Also, m_currentPoint should be more frequently initialised. + + // call user virtual func + begin (); + + // we've starting using the tool... + m_began = true; + + // but we haven't started drawing with it + m_beganDraw = false; + + + uint keyState = KApplication::keyboardModifiers (); + + m_shiftPressed = (keyState & KApplication::ShiftModifier); + m_controlPressed = (keyState & KApplication::ControlModifier); + + // TODO: Can't do much about ALT - unless it's always KApplication::Modifier1? + // Ditto for everywhere else where I set SHIFT & CTRL but not alt. + m_altPressed = false; + } +} + +void kpTool::endInternal () +{ + if (m_began) + { + // before we can stop using the tool, we must stop the current drawing operation (if any) + if (hasBegunShape ()) + endShapeInternal (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + + // call user virtual func + end (); + + // clear leftover statusbar messages + setUserMessage (); + setUserShapePoints (currentPoint ()); + + // we've stopped using the tool... + m_began = false; + + // and so we can't be drawing with it + m_beganDraw = false; + + if (m_mainWindow) + { + kpToolToolBar *tb = m_mainWindow->toolToolBar (); + if (tb) + { + tb->hideAllToolWidgets (); + } + } + + } +} + +// virtual +void kpTool::begin () +{ +#if DEBUG_KP_TOOL + kdDebug () << "kpTool::begin() base implementation" << endl; +#endif +} + +// virtual +void kpTool::end () +{ +#if DEBUG_KP_TOOL + kdDebug () << "kpTool::end() base implementation" << endl; +#endif +} + +void kpTool::beginDrawInternal () +{ + if (!m_beganDraw) + { + beginDraw (); + + m_beganDraw = true; + emit beganDraw (m_currentPoint); + } +} + +// virtual +void kpTool::beginDraw () +{ +} + +// virtual +void kpTool::hover (const QPoint &point) +{ +#if DEBUG_KP_TOOL + kdDebug () << "kpTool::hover" << point + << " base implementation" + << endl; +#endif + + setUserShapePoints (point); +} + +// virtual +void kpTool::globalDraw () +{ +} + +// virtual +void kpTool::reselect () +{ +#if DEBUG_KP_TOOL + kdDebug () << "kpTool::reselect() base implementation" << endl; +#endif +} + + +// public +QIconSet kpTool::iconSet (int forceSize) const +{ +#if DEBUG_KP_TOOL && 0 + kdDebug () << "kpTool(" << name () << ")::iconSet(forceSize=" << forceSize << ")" << endl; +#endif + // (robust in case BarIcon() default arg changes) + if (forceSize > 0) + return BarIconSet (name (), forceSize); + else + return BarIconSet (name ()); +} + +// public +QString kpTool::iconName () const +{ + return name (); +} + +// public +kpToolAction *kpTool::action () +{ + if (!m_action) + createAction (); + + return m_action; +} + + +// protected slots +void kpTool::slotActionActivated () +{ + emit actionActivated (); +} + + +// virtual +void kpTool::draw (const QPoint &, const QPoint &, const QRect &) +{ +} + +// also called by kpView +void kpTool::cancelShapeInternal () +{ + if (hasBegunShape ()) + { + m_beganDraw = false; + cancelShape (); + m_viewUnderStartPoint = 0; + + emit cancelledShape (viewUnderCursor () ? m_currentPoint : KP_INVALID_POINT); + + if (viewUnderCursor ()) + hover (m_currentPoint); + else + { + m_currentPoint = KP_INVALID_POINT; + m_currentViewPoint = KP_INVALID_POINT; + hover (m_currentPoint); + } + + if (returnToPreviousToolAfterEndDraw ()) + { + kpToolToolBar *tb = mainWindow ()->toolToolBar (); + + // (don't end up with no tool selected) + if (tb->previousTool ()) + { + // endInternal() will be called by kpMainWindow (thanks to this line) + // so we won't have the view anymore + tb->selectPreviousTool (); + } + } + } +} + +// virtual +void kpTool::cancelShape () +{ + kdWarning () << "Tool cannot cancel operation!" << endl; +} + +void kpTool::releasedAllButtons () +{ +} + +void kpTool::endDrawInternal (const QPoint &thisPoint, const QRect &normalizedRect, + bool wantEndShape) +{ +#if DEBUG_KP_TOOL && 1 + kdDebug () << "kpTool::endDrawInternal() wantEndShape=" << wantEndShape << endl; +#endif + + if (wantEndShape && !hasBegunShape ()) + return; + else if (!wantEndShape && !hasBegunDraw ()) + return; + + m_beganDraw = false; + + if (wantEndShape) + { + #if DEBUG_KP_TOOL && 0 + kdDebug () << "\tcalling endShape()" << endl; + #endif + endShape (thisPoint, normalizedRect); + } + else + { + #if DEBUG_KP_TOOL && 0 + kdDebug () << "\tcalling endDraw()" << endl; + #endif + endDraw (thisPoint, normalizedRect); + } + m_viewUnderStartPoint = 0; + + emit endedDraw (m_currentPoint); + if (viewUnderCursor ()) + hover (m_currentPoint); + else + { + m_currentPoint = KP_INVALID_POINT; + m_currentViewPoint = KP_INVALID_POINT; + hover (m_currentPoint); + } + + if (returnToPreviousToolAfterEndDraw ()) + { + kpToolToolBar *tb = mainWindow ()->toolToolBar (); + + // (don't end up with no tool selected) + if (tb->previousTool ()) + { + // endInternal() will be called by kpMainWindow (thanks to this line) + // so we won't have the view anymore + tb->selectPreviousTool (); + } + } +} + +// private +void kpTool::endShapeInternal (const QPoint &thisPoint, const QRect &normalizedRect) +{ + endDrawInternal (thisPoint, normalizedRect, true/*end shape*/); +} + +// virtual +void kpTool::endDraw (const QPoint &, const QRect &) +{ +} + +kpMainWindow *kpTool::mainWindow () const +{ + return m_mainWindow; +} + +kpDocument *kpTool::document () const +{ + return m_mainWindow ? m_mainWindow->document () : 0; +} + +kpView *kpTool::viewUnderCursor () const +{ + kpViewManager *vm = viewManager (); + return vm ? vm->viewUnderCursor () : 0; +} + +kpViewManager *kpTool::viewManager () const +{ + return m_mainWindow ? m_mainWindow->viewManager () : 0; +} + +kpToolToolBar *kpTool::toolToolBar () const +{ + return m_mainWindow ? m_mainWindow->toolToolBar () : 0; +} + +kpColor kpTool::color (int which) const +{ + if (m_mainWindow) + return m_mainWindow->colorToolBar ()->color (which); + else + { + kdError () << "kpTool::color () without mainWindow" << endl; + return kpColor::invalid; + } +} + +kpColor kpTool::foregroundColor () const +{ + return color (0); +} + +kpColor kpTool::backgroundColor () const +{ + return color (1); +} + + +double kpTool::colorSimilarity () const +{ + if (m_mainWindow) + return m_mainWindow->colorToolBar ()->colorSimilarity (); + else + { + kdError () << "kpTool::colorSimilarity() without mainWindow" << endl; + return 0; + } +} + +int kpTool::processedColorSimilarity () const +{ + if (m_mainWindow) + return m_mainWindow->colorToolBar ()->processedColorSimilarity (); + else + { + kdError () << "kpTool::processedColorSimilarity() without mainWindow" << endl; + return kpColor::Exact; + } +} + + +kpColor kpTool::oldForegroundColor () const +{ + if (m_mainWindow) + return m_mainWindow->colorToolBar ()->oldForegroundColor (); + else + { + kdError () << "kpTool::oldForegroundColor() without mainWindow" << endl; + return kpColor::invalid; + } +} + +kpColor kpTool::oldBackgroundColor () const +{ + if (m_mainWindow) + return m_mainWindow->colorToolBar ()->oldBackgroundColor (); + else + { + kdError () << "kpTool::oldBackgroundColor() without mainWindow" << endl; + return kpColor::invalid; + } +} + +double kpTool::oldColorSimilarity () const +{ + if (m_mainWindow) + return m_mainWindow->colorToolBar ()->oldColorSimilarity (); + else + { + kdError () << "kpTool::oldColorSimilarity() without mainWindow" << endl; + return 0; + } +} + + +void kpTool::slotColorsSwappedInternal (const kpColor &newForegroundColor, + const kpColor &newBackgroundColor) +{ + if (careAboutColorsSwapped ()) + { + slotColorsSwapped (newForegroundColor, newBackgroundColor); + m_ignoreColorSignals = 2; + } + else + m_ignoreColorSignals = 0; +} + +void kpTool::slotForegroundColorChangedInternal (const kpColor &color) +{ + if (m_ignoreColorSignals > 0) + { + #if DEBUG_KP_TOOL && 1 + kdDebug () << "kpTool::slotForegroundColorChangedInternal() ignoreColorSignals=" << m_ignoreColorSignals << endl; + #endif + m_ignoreColorSignals--; + return; + } + + slotForegroundColorChanged (color); +} + +void kpTool::slotBackgroundColorChangedInternal (const kpColor &color) +{ + if (m_ignoreColorSignals > 0) + { + #if DEBUG_KP_TOOL && 1 + kdDebug () << "kpTool::slotBackgroundColorChangedInternal() ignoreColorSignals=" << m_ignoreColorSignals << endl; + #endif + m_ignoreColorSignals--; + return; + } + + slotBackgroundColorChanged (color); +} + +void kpTool::slotColorSimilarityChangedInternal (double similarity, int processedSimilarity) +{ + slotColorSimilarityChanged (similarity, processedSimilarity); +} + +bool kpTool::currentPointNextToLast () const +{ + if (m_lastPoint == QPoint (-1, -1)) + return true; + + int dx = kAbs (m_currentPoint.x () - m_lastPoint.x ()); + int dy = kAbs (m_currentPoint.y () - m_lastPoint.y ()); + + return (dx <= 1 && dy <= 1); +} + +bool kpTool::currentPointCardinallyNextToLast () const +{ + if (m_lastPoint == QPoint (-1, -1)) + return true; + + int dx = kAbs (m_currentPoint.x () - m_lastPoint.x ()); + int dy = kAbs (m_currentPoint.y () - m_lastPoint.y ()); + + return (dx + dy <= 1); +} + +kpCommandHistory *kpTool::commandHistory () const +{ + return m_mainWindow ? m_mainWindow->commandHistory () : 0; +} + +void kpTool::mousePressEvent (QMouseEvent *e) +{ +#if DEBUG_KP_TOOL && 1 + kdDebug () << "kpTool::mousePressEvent pos=" << e->pos () + << " btnStateBefore=" << (int) e->state () + << " btnStateAfter=" << (int) e->stateAfter () + << " button=" << (int) e->button () + << " beganDraw=" << m_beganDraw << endl; +#endif + + // state of all the buttons - not just the one that triggered the event (button()) + Qt::ButtonState buttonState = e->stateAfter (); + + if (m_mainWindow && e->button () == Qt::MidButton) + { + const QString text = QApplication::clipboard ()->text (QClipboard::Selection); + #if DEBUG_KP_TOOL && 1 + kdDebug () << "\tMMB pasteText='" << text << "'" << endl; + #endif + if (!text.isEmpty ()) + { + if (hasBegunShape ()) + { + #if DEBUG_KP_TOOL && 1 + kdDebug () << "\t\thasBegunShape - end" << endl; + #endif + endShapeInternal (m_currentPoint, + QRect (m_startPoint, m_currentPoint).normalize ()); + } + + if (viewUnderCursor ()) + { + m_mainWindow->pasteTextAt (text, + viewUnderCursor ()->transformViewToDoc (e->pos ()), + true/*adjust topLeft so that cursor isn't + on top of resize handle*/); + } + + return; + } + } + + int mb = mouseButton (buttonState); +#if DEBUG_KP_TOOL && 1 + kdDebug () << "\tmb=" << mb << " m_beganDraw=" << m_beganDraw << endl; +#endif + + if (mb == -1 && !m_beganDraw) return; // ignore + + if (m_beganDraw) + { + if (mb == -1 || mb != m_mouseButton) + { + #if DEBUG_KP_TOOL && 1 + kdDebug () << "\tCancelling operation as " << mb << " == -1 or != " << m_mouseButton << endl; + #endif + + kpView *view = viewUnderStartPoint (); + if (!view) + { + kdError () << "kpTool::mousePressEvent() cancel without a view under the start point!" << endl; + } + + // if we get a mousePressEvent when we're drawing, then the other + // mouse button must have been pressed + m_currentPoint = view ? view->transformViewToDoc (e->pos ()) : QPoint (-1, -1); + m_currentViewPoint = view ? e->pos () : QPoint (-1, -1); + cancelShapeInternal (); + } + + return; + } + + kpView *view = viewUnderCursor (); + if (!view) + { + kdError () << "kpTool::mousePressEvent() without a view under the cursor!" << endl; + } + +#if DEBUG_KP_TOOL && 1 + if (view) + kdDebug () << "\tview=" << view->name () << endl; +#endif + + + // let user know what mouse button is being used for entire draw + m_mouseButton = mouseButton (buttonState); + m_shiftPressed = (buttonState & Qt::ShiftButton); + m_controlPressed = (buttonState & Qt::ControlButton); + m_altPressed = (buttonState & Qt::AltButton); + m_startPoint = m_currentPoint = view ? view->transformViewToDoc (e->pos ()) : QPoint (-1, -1); + m_currentViewPoint = view ? e->pos () : QPoint (-1, -1); + m_viewUnderStartPoint = view; + m_lastPoint = QPoint (-1, -1); + +#if DEBUG_KP_TOOL && 1 + kdDebug () << "\tBeginning draw @ " << m_currentPoint << endl; +#endif + + beginDrawInternal (); + + draw (m_currentPoint, m_lastPoint, QRect (m_currentPoint, m_currentPoint)); + m_lastPoint = m_currentPoint; +} + +void kpTool::mouseMoveEvent (QMouseEvent *e) +{ +#if DEBUG_KP_TOOL && 0 + kdDebug () << "kpTool::mouseMoveEvent pos=" << e->pos () + << " btnStateAfter=" << (int) e->stateAfter () << endl; + kpView *v0 = viewUnderCursor (), + *v1 = viewManager ()->viewUnderCursor (true/*use Qt*/), + *v2 = viewUnderStartPoint (); + kdDebug () << "\tviewUnderCursor=" << (v0 ? v0->name () : "(none)") + << " viewUnderCursorQt=" << (v1 ? v1->name () : "(none)") + << " viewUnderStartPoint=" << (v2 ? v2->name () : "(none)") + << endl; + kdDebug () << "\tfocusWidget=" << kapp->focusWidget () << endl; +#endif + + Qt::ButtonState buttonState = e->stateAfter (); + m_shiftPressed = (buttonState & Qt::ShiftButton); + m_controlPressed = (buttonState & Qt::ControlButton); + m_altPressed = (buttonState & Qt::AltButton); + + if (m_beganDraw) + { + kpView *view = viewUnderStartPoint (); + if (!view) + { + kdError () << "kpTool::mouseMoveEvent() without a view under the start point!" << endl; + return; + } + + m_currentPoint = view->transformViewToDoc (e->pos ()); + m_currentViewPoint = e->pos (); + + #if DEBUG_KP_TOOL && 0 + kdDebug () << "\tDraw!" << endl; + #endif + + bool dragScrolled = false; + movedAndAboutToDraw (m_currentPoint, m_lastPoint, view->zoomLevelX (), &dragScrolled); + + if (dragScrolled) + { + m_currentPoint = currentPoint (); + m_currentViewPoint = currentPoint (false/*view point*/); + + // Scrollview has scrolled contents and has scheduled an update + // for the newly exposed region. If draw() schedules an update + // as well (instead of immediately updating), the scrollview's + // update will be executed first and it'll only update part of + // the screen resulting in ugly tearing of the viewManager's + // tempPixmap. + viewManager ()->setFastUpdates (); + } + + draw (m_currentPoint, m_lastPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + + if (dragScrolled) + viewManager ()->restoreFastUpdates (); + + m_lastPoint = m_currentPoint; + } + else + { + kpView *view = viewUnderCursor (); + if (!view) // possible if cancelShape()'ed but still holding down initial mousebtn + { + m_currentPoint = KP_INVALID_POINT; + m_currentViewPoint = KP_INVALID_POINT; + return; + } + + m_currentPoint = view->transformViewToDoc (e->pos ()); + m_currentViewPoint = e->pos (); + hover (m_currentPoint); + } +} + +void kpTool::mouseReleaseEvent (QMouseEvent *e) +{ +#if DEBUG_KP_TOOL && 1 + kdDebug () << "kpTool::mouseReleaseEvent pos=" << e->pos () + << " btnStateBefore=" << (int) e->state () + << " btnStateAfter=" << (int) e->stateAfter () + << " button=" << (int) e->button () << endl; +#endif + + if (m_beganDraw) // didn't cancelShape() + { + kpView *view = viewUnderStartPoint (); + if (!view) + { + kdError () << "kpTool::mouseReleaseEvent() without a view under the start point!" << endl; + return; + } + + m_currentPoint = view ? view->transformViewToDoc (e->pos ()) : QPoint (-1, -1); + m_currentViewPoint = view ? e->pos () : QPoint (-1, -1); + endDrawInternal (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + } + + if ((e->stateAfter () & Qt::MouseButtonMask) == 0) + { + releasedAllButtons (); + } +} + +void kpTool::wheelEvent (QWheelEvent *e) +{ +#if DEBUG_KP_TOOL + kdDebug () << "kpTool::wheelEvent() state=" << e->state () + << " hasBegunDraw=" << hasBegunDraw () + << " delta=" << e->delta () + << endl; +#endif + + e->ignore (); + + // If CTRL not pressed, bye. + if ((e->state () & Qt::ControlButton) == 0) + return; + + // If drawing, bye; don't care if a shape in progress though. + if (hasBegunDraw ()) + return; + + + // Zoom in/out depending on wheel direction. + + // Moved wheel away from user? + if (e->delta () > 0) + { + m_mainWindow->zoomIn (true/*center under cursor*/); + e->accept (); + } + // Moved wheel towards user? + else if (e->delta () < 0) + { + #if 1 + m_mainWindow->zoomOut (true/*center under cursor - make zoom in/out + stay under same doc pos*/); + #else + m_mainWindow->zoomOut (false/*don't center under cursor - as is + confusing behaviour when zooming + out*/); + #endif + e->accept (); + } +} + + +void kpTool::keyPressEvent (QKeyEvent *e) +{ +#if DEBUG_KP_TOOL && 0 + kdDebug () << "kpTool::keyPressEvent() e->key=" << e->key () << endl; +#endif + + int dx = 0, dy = 0; + + e->ignore (); + + switch (e->key ()) + { + case 0: + case Qt::Key_unknown: + #if DEBUG_KP_TOOL && 0 + kdDebug () << "kpTool::keyPressEvent() picked up unknown key!" << endl; + #endif + // --- fall thru and update all modifiers --- + case Qt::Key_Alt: + case Qt::Key_Shift: + case Qt::Key_Control: + keyUpdateModifierState (e); + + e->accept (); + break; + + case Qt::Key_Delete: + m_mainWindow->slotDelete (); + break; + + /* + * QCursor::setPos conveniently causes mouseMoveEvents :) + */ + + case Qt::Key_Home: dx = -1, dy = -1; break; + case Qt::Key_Up: dy = -1; break; + case Qt::Key_PageUp: dx = +1, dy = -1; break; + + case Qt::Key_Left: dx = -1; break; + case Qt::Key_Right: dx = +1; break; + + case Qt::Key_End: dx = -1, dy = +1; break; + case Qt::Key_Down: dy = +1; break; + case Qt::Key_PageDown: dx = +1, dy = +1; break; + + case Qt::Key_Enter: + case Qt::Key_Return: + case Qt::Key_Insert: + case Qt::Key_Clear/*Numpad 5 Key*/: + { + kpView *view = viewUnderCursor (); // TODO: wrong for dragging lines outside of view (for e.g.) + if (view) + { + // TODO: what about the modifiers + QMouseEvent me (QEvent::MouseButtonPress, + view->mapFromGlobal (QCursor::pos ()), + Qt::LeftButton, + 0); + mousePressEvent (&me); + e->accept (); + } + + break; + }} + + kpView *view = viewUnderCursor (); + if (view && (dx || dy)) + { + QPoint oldPoint = view->mapFromGlobal (QCursor::pos ()); + #if DEBUG_KP_TOOL && 0 + kdDebug () << "\toldPoint=" << oldPoint + << " dx=" << dx << " dy=" << dy << endl; + #endif + + + const int viewIncX = (dx ? QMAX (1, view->zoomLevelX () / 100) * dx : 0); + const int viewIncY = (dy ? QMAX (1, view->zoomLevelY () / 100) * dy : 0); + + int newViewX = oldPoint.x () + viewIncX; + int newViewY = oldPoint.y () + viewIncY; + + + #if DEBUG_KP_TOOL && 0 + kdDebug () << "\tnewPoint=" << QPoint (newViewX, newViewY) << endl; + #endif + + if (view->transformViewToDoc (QPoint (newViewX, newViewY)) == + view->transformViewToDoc (oldPoint)) + { + newViewX += viewIncX, newViewY += viewIncY; + + #if DEBUG_KP_TOOL && 0 + kdDebug () << "\tneed adjust for doc - newPoint=" + << QPoint (newViewX, newViewY) << endl; + #endif + } + + + // TODO: visible width/height (e.g. with scrollbars) + int x = QMIN (QMAX (newViewX, 0), view->width () - 1); + int y = QMIN (QMAX (newViewY, 0), view->height () - 1); + + QCursor::setPos (view->mapToGlobal (QPoint (x, y))); + e->accept (); + } +} + +void kpTool::keyReleaseEvent (QKeyEvent *e) +{ +#if DEBUG_KP_TOOL && 0 + kdDebug () << "kpTool::keyReleaseEvent() e->key=" << e->key () << endl; +#endif + + e->ignore (); + + switch (e->key ()) + { + case 0: + case Qt::Key_unknown: + #if DEBUG_KP_TOOL + kdDebug () << "kpTool::keyReleaseEvent() picked up unknown key!" << endl; + #endif + // HACK: around Qt bug: if you hold a modifier before you start the + // program and then release it over the view, + // Qt reports it as the release of an unknown key + // --- fall thru and update all modifiers --- + case Qt::Key_Alt: + case Qt::Key_Shift: + case Qt::Key_Control: + keyUpdateModifierState (e); + + e->accept (); + break; + + case Qt::Key_Escape: + if (hasBegunDraw ()) + { + cancelShapeInternal (); + e->accept (); + } + + break; + + case Qt::Key_Enter: + case Qt::Key_Return: + case Qt::Key_Insert: + case Qt::Key_Clear/*Numpad 5 Key*/: + { + kpView *view = viewUnderCursor (); + if (view) + { + QMouseEvent me (QEvent::MouseButtonRelease, + view->mapFromGlobal (QCursor::pos ()), + Qt::LeftButton, + Qt::LeftButton); + mouseReleaseEvent (&me); + e->accept (); + } + break; + }} +} + +// private +void kpTool::keyUpdateModifierState (QKeyEvent *e) +{ +#if DEBUG_KP_TOOL && 0 + kdDebug () << "kpTool::updateModifierState() e->key=" << e->key () << endl; + kdDebug () << "\tshift=" + << (e->stateAfter () & Qt::ShiftButton) + << " control=" + << (e->stateAfter () & Qt::ControlButton) + << " alt=" + << (e->stateAfter () & Qt::AltButton) + << endl; +#endif + if (e->key () & (Qt::Key_Alt | Qt::Key_Shift | Qt::Key_Control)) + { + #if DEBUG_KP_TOOL && 0 + kdDebug () << "\t\tmodifier changed - use e's claims" << endl; + #endif + setShiftPressed (e->stateAfter () & Qt::ShiftButton); + setControlPressed (e->stateAfter () & Qt::ControlButton); + setAltPressed (e->stateAfter () & Qt::AltButton); + } + else + { + #if DEBUG_KP_TOOL && 0 + kdDebug () << "\t\tmodifiers not changed - figure out the truth" << endl; + #endif + uint keyState = KApplication::keyboardModifiers (); + + setShiftPressed (keyState & KApplication::ShiftModifier); + setControlPressed (keyState & KApplication::ControlModifier); + + // TODO: Can't do much about ALT - unless it's always KApplication::Modifier1? + // Ditto for everywhere else where I set SHIFT & CTRL but not alt. + setAltPressed (e->stateAfter () & Qt::AltButton); + } +} + + +void kpTool::notifyModifierStateChanged () +{ + if (careAboutModifierState ()) + { + if (m_beganDraw) + draw (m_currentPoint, m_lastPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + else + { + m_currentPoint = currentPoint (); + m_currentViewPoint = currentPoint (false/*view point*/); + hover (m_currentPoint); + } + } +} + +void kpTool::setShiftPressed (bool pressed) +{ + if (pressed == m_shiftPressed) + return; + + m_shiftPressed = pressed; + + notifyModifierStateChanged (); +} + +void kpTool::setControlPressed (bool pressed) +{ + if (pressed == m_controlPressed) + return; + + m_controlPressed = pressed; + + notifyModifierStateChanged (); +} + +void kpTool::setAltPressed (bool pressed) +{ + if (pressed = m_altPressed) + return; + + m_altPressed = pressed; + + notifyModifierStateChanged (); +} + +void kpTool::focusInEvent (QFocusEvent *) +{ +} + +void kpTool::focusOutEvent (QFocusEvent *) +{ +#if DEBUG_KP_TOOL && 0 + kdDebug () << "kpTool::focusOutEvent() beganDraw=" << m_beganDraw << endl; +#endif + + if (m_beganDraw) + endDrawInternal (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); +} + +void kpTool::enterEvent (QEvent *) +{ +#if DEBUG_KP_TOOL && 1 + kdDebug () << "kpTool::enterEvent() beganDraw=" << m_beganDraw << endl; +#endif +} + +void kpTool::leaveEvent (QEvent *) +{ +#if DEBUG_KP_TOOL && 1 + kdDebug () << "kpTool::leaveEvent() beganDraw=" << m_beganDraw << endl; +#endif + + // if we haven't started drawing (e.g. dragging a rectangle)... + if (!m_beganDraw) + { + m_currentPoint = KP_INVALID_POINT; + m_currentViewPoint = KP_INVALID_POINT; + hover (m_currentPoint); + } +} + +// static +int kpTool::mouseButton (const Qt::ButtonState &buttonState) +{ + // we have nothing to do with mid-buttons + if (buttonState & Qt::MidButton) + return -1; + + // both left & right together is quite meaningless... + Qt::ButtonState bothButtons = (Qt::ButtonState) (Qt::LeftButton | Qt::RightButton); + if ((buttonState & bothButtons) == bothButtons) + return -1; + + if (buttonState & Qt::LeftButton) + return 0; + else if (buttonState & Qt::RightButton) + return 1; + else + return -1; +} + + +/* + * User Notifications + */ + + +// public static +QString kpTool::cancelUserMessage (int mouseButton) +{ + if (mouseButton == 0) + return i18n ("Right click to cancel."); + else + return i18n ("Left click to cancel."); +} + +// public +QString kpTool::cancelUserMessage () const +{ + return cancelUserMessage (m_mouseButton); +} + + +// public +QString kpTool::userMessage () const +{ + return m_userMessage; +} + +// public +void kpTool::setUserMessage (const QString &userMessage) +{ + m_userMessage = userMessage; + + if (m_userMessage.isEmpty ()) + m_userMessage = text (); + else + m_userMessage.prepend (i18n ("%1: ").arg (text ())); + + emit userMessageChanged (m_userMessage); +} + + +// public +QPoint kpTool::userShapeStartPoint () const +{ + return m_userShapeStartPoint; +} + +// public +QPoint kpTool::userShapeEndPoint () const +{ + return m_userShapeEndPoint; +} + +// public static +int kpTool::calculateLength (int start, int end) +{ + if (start <= end) + { + return end - start + 1; + } + else + { + return end - start - 1; + } +} + +// public +void kpTool::setUserShapePoints (const QPoint &startPoint, + const QPoint &endPoint, + bool setSize) +{ + m_userShapeStartPoint = startPoint; + m_userShapeEndPoint = endPoint; + emit userShapePointsChanged (m_userShapeStartPoint, m_userShapeEndPoint); + + if (setSize) + { + if (startPoint != KP_INVALID_POINT && + endPoint != KP_INVALID_POINT) + { + setUserShapeSize (calculateLength (startPoint.x (), endPoint.x ()), + calculateLength (startPoint.y (), endPoint.y ())); + } + else + { + setUserShapeSize (); + } + } +} + + +// public +QSize kpTool::userShapeSize () const +{ + return m_userShapeSize; +} + +// public +int kpTool::userShapeWidth () const +{ + return m_userShapeSize.width (); +} + +// public +int kpTool::userShapeHeight () const +{ + return m_userShapeSize.height (); +} + +// public +void kpTool::setUserShapeSize (const QSize &size) +{ + m_userShapeSize = size; + + emit userShapeSizeChanged (m_userShapeSize); + emit userShapeSizeChanged (m_userShapeSize.width (), + m_userShapeSize.height ()); +} + +// public +void kpTool::setUserShapeSize (int width, int height) +{ + setUserShapeSize (QSize (width, height)); +} + + +// public static +bool kpTool::warnIfBigImageSize (int oldWidth, int oldHeight, + int newWidth, int newHeight, + const QString &text, + const QString &caption, + const QString &continueButtonText, + QWidget *parent) +{ +#if DEBUG_KP_TOOL + kdDebug () << "kpTool::warnIfBigImageSize()" + << " old: w=" << oldWidth << " h=" << oldWidth + << " new: w=" << newWidth << " h=" << newHeight + << " pixmapSize=" + << kpPixmapFX::pixmapSize (newWidth, + newHeight, + QPixmap::defaultDepth ()) + << " vs BigImageSize=" << KP_BIG_IMAGE_SIZE + << endl; +#endif + + // Only got smaller or unchanged - don't complain + if (!(newWidth > oldWidth || newHeight > oldHeight)) + { + return true; + } + + // Was already large - user was warned before, don't annoy him/her again + if (kpPixmapFX::pixmapSize (oldWidth, oldHeight, QPixmap::defaultDepth ()) >= + KP_BIG_IMAGE_SIZE) + { + return true; + } + + if (kpPixmapFX::pixmapSize (newWidth, newHeight, QPixmap::defaultDepth ()) >= + KP_BIG_IMAGE_SIZE) + { + int accept = KMessageBox::warningContinueCancel (parent, + text, + caption, + continueButtonText, + QString::fromLatin1 ("BigImageDontAskAgain")); + + return (accept == KMessageBox::Continue); + } + else + { + return true; + } +} + + +#include diff --git a/kolourpaint/kptool.h b/kolourpaint/kptool.h new file mode 100644 index 00000000..ba7ee75e --- /dev/null +++ b/kolourpaint/kptool.h @@ -0,0 +1,422 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __kp_tool_h__ +#define __kp_tool_h__ + +#include +#include +#include +#include +#include + +#include + + +class QIconSet; +class QPixmap; + +class KKeySequence; +class KShortcut; + +class kpColor; +class kpColorToolBar; +class kpCommandHistory; +class kpDocument; +class kpView; +class kpViewManager; +class kpMainWindow; +class kpToolAction; +class kpToolToolBar; + + +// Base class for all tools +class kpTool : public QObject +{ +Q_OBJECT + +public: + kpTool (const QString &text, const QString &description, + int key, + kpMainWindow *mainWindow, const char *name); + virtual ~kpTool (); + +private: + void init (const QString &text, const QString &description, + int key, + kpMainWindow *mainWindow, const char *name); + + +protected: + void createAction (); + + int m_key; + kpToolAction *m_action; + +signals: + void actionToolTipChanged (const QString &string); + +protected slots: + void slotActionToolTipChanged (const QString &string); + +public: + QString text () const; + void setText (const QString &text); + + static QString toolTipForTextAndShortcut (const QString &text, + const KShortcut &shortcut); + QString toolTip () const; + + QString description () const; + void setDescription (const QString &description); + + int key () const; + void setKey (int key); + + // Given a single , returns a shortcut with + // (disabled when the user is editing text) and as an alternate, + // +. + static KShortcut shortcutForKey (int key); + KShortcut shortcut () const; + + static bool keyIsText (int key); + static bool containsSingleKeyTrigger (const KKeySequence &seq); + static bool containsSingleKeyTrigger (const KShortcut &shortcut, + KShortcut *shortcutWithoutSingleKeyTriggers); + + bool singleKeyTriggersEnabled () const; + void enableSingleKeyTriggers (bool enable = true); + + const char *name () const; + + + static QRect neededRect (const QRect &rect, int lineWidth); + static QPixmap neededPixmap (const QPixmap &pixmap, const QRect &boundingRect); + + bool hasCurrentPoint () const; + // Returns the position of the cursor relative to the topleft point of + // the current view (viewUnderStartPoint() or viewUnderCursor() otherwise). + // + // If neither viewUnderStartPoint() nor viewUnderCursor() + // (i.e. !hasCurrentPoint()), then it returns KP_INVALID_POINT. + // + // If is set (default), then it returns the position in the + // document. This theoretically == m_currentPoint (when m_currentPoint + // is defined) but I wouldn't bet on it. This function is useful when + // m_currentPoint isn't necessarily defined (outside of beginDraw(),draw() + // and hover()). + // + // If is not set, then it returns an unzoomed view coordinate. + // + // Keep in mind that if viewUnderStartPoint(), this can return coordinates + // outside of the document/view. + QPoint currentPoint (bool zoomToDoc = true) const; + +public slots: + // Call this when something below the mouse cursor may have changed + // and/or if the view has moved relative to the cursor (as opposed to + // the cursor moving relative to the view, which would trigger a + // mouseMoveEvent and all would be well without such hacks) + // e.g. when zooming or scrolling the view or when deleting a selection. + // + // This calls hover() or draw() to let the tool know. The Brush Tool + // can then update the position of the Brush Cursor. The Selection + // Tool can update the real cursor. The Line Tool can update the current + // line. The statubar gets correct coordinates. etc. etc. + void somethingBelowTheCursorChanged (); + +private: + // Same as above except that you claim you know better than currentPoint() + void somethingBelowTheCursorChanged (const QPoint ¤tPoint_, + const QPoint ¤tViewPoint_); + +public: + // called when the tool is selected + virtual void begin (); + + // called when the tool is deselected + virtual void end (); + + // set after begin() has been called, unset after end() has been called + bool hasBegun () const { return m_began; } + + bool hasBegunDraw () const { return m_beganDraw; } + + virtual bool hasBegunShape () const { return hasBegunDraw (); } + + // called when user double-left-clicks on Tool Icon (not view) + virtual void globalDraw (); + + // called when the user clicks on the Tool Icon even though it's already + // the current tool (used by the selection tools to deselect) + virtual void reselect (); + +signals: + // emitted after beginDraw() has been called + void beganDraw (const QPoint &point); + + // Emitted just before draw() is called in mouseMoveEvent(). Slots + // connected to this signal should return in whether the + // mouse pos may have changed. Used by drag scrolling. + void movedAndAboutToDraw (const QPoint ¤tPoint, const QPoint &lastPoint, + int zoomLevel, + bool *scrolled); + + // emitted after endDraw() has been called + void endedDraw (const QPoint &point); + + // emitted after cancelShape() has been called + void cancelledShape (const QPoint &point); + + +public: + QIconSet iconSet (int forceSize = 0) const; + QString iconName () const; + kpToolAction *action (); + +signals: + // User clicked on the tool's action - i.e. select this tool + void actionActivated (); + +protected slots: + void slotActionActivated (); + + +protected: + virtual bool returnToPreviousToolAfterEndDraw () const { return false; } + virtual bool careAboutModifierState () const { return false; } + virtual bool careAboutColorsSwapped () const { return false; } + + virtual void beginDraw (); + + // mouse move without button pressed + // (only m_currentPoint & m_currentViewPoint is defined) + virtual void hover (const QPoint &point); + + // this is useful for "instant" tools like the Pen & Eraser + virtual void draw (const QPoint &thisPoint, const QPoint &lastPoint, + const QRect &normalizedRect); + + // (m_mouseButton will not change from beginDraw()) + virtual void cancelShape (); + virtual void releasedAllButtons (); + + virtual void endDraw (const QPoint &thisPoint, const QRect &normalizedRect); + + virtual void endShape (const QPoint &thisPoint = QPoint (), + const QRect &normalizedRect = QRect ()) + { + endDraw (thisPoint, normalizedRect); + } + + kpMainWindow *mainWindow () const; + kpDocument *document () const; + kpViewManager *viewManager () const; + kpToolToolBar *toolToolBar () const; + kpView *viewUnderStartPoint () const { return m_viewUnderStartPoint; } + kpView *viewUnderCursor () const; + kpCommandHistory *commandHistory () const; + + kpColor color (int which) const; + + kpColor foregroundColor () const; + kpColor backgroundColor () const; + + double colorSimilarity () const; + int processedColorSimilarity () const; + +protected: + int m_ignoreColorSignals; + +protected slots: + void slotColorsSwappedInternal (const kpColor &newForegroundColor, + const kpColor &newBackgroundColor); + void slotForegroundColorChangedInternal (const kpColor &color); + void slotBackgroundColorChangedInternal (const kpColor &color); + void slotColorSimilarityChangedInternal (double similarity, int processedSimilarity); + +protected slots: // TODO: there is no reason why these should be slots + virtual void slotColorsSwapped (const kpColor & /*newForegroundColor*/, const kpColor & /*newBackgroundColor*/) {} + virtual void slotForegroundColorChanged (const kpColor & /*color*/) {} + virtual void slotBackgroundColorChanged (const kpColor & /*color*/) {} + virtual void slotColorSimilarityChanged (double /*similarity*/, int /*processedSimilarity*/) {}; + +protected: + // (only valid in slots connected to the respective signals above) + kpColor oldForegroundColor () const; + kpColor oldBackgroundColor () const; + double oldColorSimilarity () const; + +protected: + // returns true if m_currentPoint <= 1 pixel away from m_lastPoint + // or if there was no lastPoint + bool currentPointNextToLast () const; // (includes diagonal adjacency) + bool currentPointCardinallyNextToLast () const; // (only cardinally adjacent i.e. horiz & vert; no diag) + + int m_mouseButton; /* 0 = left, 1 = right */ + bool m_shiftPressed, m_controlPressed, m_altPressed; // m_altPressed is unreliable + bool m_beganDraw; // set after beginDraw() is called, unset before endDraw() is called + QPoint m_startPoint, + m_currentPoint, m_currentViewPoint, + m_lastPoint; + +protected: + friend class kpCommandHistory; + friend class kpMainWindow; + friend class kpToolToolBar; + void beginInternal (); + void endInternal (); + + void beginDrawInternal (); + void endDrawInternal (const QPoint &thisPoint, const QRect &normalizedRect, + bool wantEndShape = false); + void cancelShapeInternal (); + void endShapeInternal (const QPoint &thisPoint = QPoint (), + const QRect &normalizedRect = QRect ()); + + friend class kpView; + + // If you're reimplementing any of these, you probably don't know what + // you're doing - reimplement begin(),beginDraw(),draw(),cancelShape(), + // endDraw() etc. instead. + virtual void mousePressEvent (QMouseEvent *e); + virtual void mouseMoveEvent (QMouseEvent *e); + virtual void mouseReleaseEvent (QMouseEvent *e); + virtual void wheelEvent (QWheelEvent *e); + + virtual void keyPressEvent (QKeyEvent *e); + virtual void keyReleaseEvent (QKeyEvent *e); + + virtual void imStartEvent(QIMEvent *){} + virtual void imComposeEvent(QIMEvent *){} + virtual void imEndEvent(QIMEvent *){} + +private: + void keyUpdateModifierState (QKeyEvent *e); + void notifyModifierStateChanged (); +protected: + virtual void setShiftPressed (bool pressed); + virtual void setControlPressed (bool pressed); + virtual void setAltPressed (bool pressed); + virtual void focusInEvent (QFocusEvent *e); + virtual void focusOutEvent (QFocusEvent *e); + virtual void enterEvent (QEvent *e); + virtual void leaveEvent (QEvent *e); + + // 0 = left, 1 = right, -1 = other (none, left+right, mid) + static int mouseButton (const Qt::ButtonState &buttonState); + + QString m_text, m_description; + const char *m_name; + + kpMainWindow *m_mainWindow; + bool m_began; + + kpView *m_viewUnderStartPoint; + + + /* + * User Notifications (Status Bar) + */ + +public: + // Returns "(Left|Right) click to cancel." where Left or Right is chosen + // depending on which one is the _opposite_ of + static QString cancelUserMessage (int mouseButton); + QString cancelUserMessage () const; + + QString userMessage () const; + void setUserMessage (const QString &userMessage = QString::null); + + QPoint userShapeStartPoint () const; + QPoint userShapeEndPoint () const; + static int calculateLength (int start, int end); + void setUserShapePoints (const QPoint &startPoint = KP_INVALID_POINT, + const QPoint &endPoint = KP_INVALID_POINT, + bool setSize = true); + + QSize userShapeSize () const; + int userShapeWidth () const; + int userShapeHeight () const; + void setUserShapeSize (const QSize &size = KP_INVALID_SIZE); + void setUserShapeSize (int width, int height); + +signals: + void userMessageChanged (const QString &userMessage); + void userShapePointsChanged (const QPoint &startPoint = KP_INVALID_POINT, + const QPoint &endPoint = KP_INVALID_POINT); + void userShapeSizeChanged (const QSize &size); + void userShapeSizeChanged (int width, int height); + +protected: + QString m_userMessage; + QPoint m_userShapeStartPoint, m_userShapeEndPoint; + QSize m_userShapeSize; + + +public: + // Call this before the user tries to cause the document or selection + // to resize from x to x. + // If at least one dimension increases, the new dimensions will take a + // large amount of memory (which causes thrashing, instability) and + // the old dimensions did not take a large amount of memory, ask the + // user if s/he really wants to perform the operation. + // + // Returns true if the operation should proceed, false otherwise. + // + // In order to make the translators' lives possible, this function cannot + // generate the ,
were in range) + virtual bool setSelected (int row, int col, bool saveAsDefault); + bool setSelected (int row, int col); + + bool selectPreviousOption (); + bool selectNextOption (); + +signals: + void optionSelected (int row, int col); + +protected: + virtual void mousePressEvent (QMouseEvent *e); + virtual void drawContents (QPainter *painter); + + void setInvertSelectedPixmap (bool yes = true) { m_invertSelectedPixmap = yes; } + bool m_invertSelectedPixmap; + + // coulbe be a QFrame or a ComboBox + QWidget *m_baseWidget; + + QValueVector < QValueVector > m_pixmaps; + QValueVector < QValueVector > m_toolTips; + + QValueVector < QValueVector > m_pixmapRects; + + int m_selectedRow, m_selectedCol; +}; + +#endif // __kp_tool_widget_base_h__ diff --git a/kolourpaint/widgets/kptoolwidgetbrush.cpp b/kolourpaint/widgets/kptoolwidgetbrush.cpp new file mode 100644 index 00000000..046dc8b5 --- /dev/null +++ b/kolourpaint/widgets/kptoolwidgetbrush.cpp @@ -0,0 +1,184 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_TOOL_WIDGET_BRUSH 0 + + +#include + +#include +#include + +#include +#include + +#include + + +/* sync: */ +static int brushSize [][3] = +{ + {8, 4, 1/*like Pen*/}, + {9, 5, 2}, + {9, 5, 2}, + {9, 5, 2} +}; + +#define BRUSH_SIZE_NUM_COLS (int (sizeof (brushSize [0]) / sizeof (brushSize [0][0]))) +#define BRUSH_SIZE_NUM_ROWS (int (sizeof (brushSize) / sizeof (brushSize [0]))) + +kpToolWidgetBrush::kpToolWidgetBrush (QWidget *parent, const char *name) + : kpToolWidgetBase (parent, name) +{ + setInvertSelectedPixmap (); + + QPixmap *pm = m_brushBitmaps; + + for (int shape = 0; shape < BRUSH_SIZE_NUM_ROWS; shape++) + { + for (int i = 0; i < BRUSH_SIZE_NUM_COLS; i++) + { + int w = (width () - 2/*margin*/ - 2/*spacing*/) / BRUSH_SIZE_NUM_COLS; + int h = (height () - 2/*margin*/ - 3/*spacing*/) / BRUSH_SIZE_NUM_ROWS; + pm->resize ((w <= 0 ? width () : w), + (h <= 0 ? height () : h)); + + const int s = brushSize [shape][i]; + QRect rect; + + if (s >= pm->width () || s >= pm->height ()) + rect = QRect (0, 0, pm->width (), pm->height ()); + else + { + rect = QRect ((pm->width () - s) / 2, + (pm->height () - s) / 2, + s, + s); + } + + #if DEBUG_KP_TOOL_WIDGET_BRUSH + kdDebug () << "kpToolWidgetBrush::kpToolWidgetBrush() rect=" << rect << endl; + #endif + + pm->fill (Qt::white); + + QPainter painter (pm); + painter.setPen (Qt::black); + painter.setBrush (Qt::black); + + // sync: + switch (shape) + { + case 0: + painter.drawEllipse (rect); + break; + case 1: + painter.drawRect (rect); + break; + case 2: + painter.drawLine (rect.topRight (), rect.bottomLeft ()); + break; + case 3: + painter.drawLine (rect.topLeft (), rect.bottomRight ()); + break; + } + painter.end (); + + pm->setMask (pm->createHeuristicMask ()); + addOption (*pm, brushName (shape, i)/*tooltip*/); + + pm++; + } + + startNewOptionRow (); + } + + finishConstruction (0, 0); +} + +kpToolWidgetBrush::~kpToolWidgetBrush () +{ +} + + +// private +QString kpToolWidgetBrush::brushName (int shape, int whichSize) +{ + int s = brushSize [shape][whichSize]; + + if (s == 1) + return i18n ("1x1"); + + QString shapeName; + + // sync: + switch (shape) + { + case 0: + shapeName = i18n ("Circle"); + break; + case 1: + shapeName = i18n ("Square"); + break; + case 2: + // TODO: is this really the name of a shape? :) + shapeName = i18n ("Slash"); + break; + case 3: + // TODO: is this really the name of a shape? :) + shapeName = i18n ("Backslash"); + break; + } + + if (shapeName.isEmpty ()) + return QString::null; + + return i18n ("%1x%2 %3").arg (s).arg (s).arg (shapeName); +} + +QPixmap kpToolWidgetBrush::brush () const +{ + return m_brushBitmaps [selectedRow () * BRUSH_SIZE_NUM_COLS + selectedCol ()]; +} + +bool kpToolWidgetBrush::brushIsDiagonalLine () const +{ + // sync: + return (selectedRow () >= 2); +} + +// virtual protected slot [base kpToolWidgetBase] +bool kpToolWidgetBrush::setSelected (int row, int col, bool saveAsDefault) +{ + const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault); + if (ret) + emit brushChanged (brush (), brushIsDiagonalLine ()); + return ret; +} + +#include diff --git a/kolourpaint/widgets/kptoolwidgetbrush.h b/kolourpaint/widgets/kptoolwidgetbrush.h new file mode 100644 index 00000000..db222e79 --- /dev/null +++ b/kolourpaint/widgets/kptoolwidgetbrush.h @@ -0,0 +1,61 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolwidgetbrush_h__ +#define __kptoolwidgetbrush_h__ + +#include + +#include + +class kpToolWidgetBrush : public kpToolWidgetBase +{ +Q_OBJECT + +public: + kpToolWidgetBrush (QWidget *parent, const char *name); + virtual ~kpToolWidgetBrush (); + +private: + QString brushName (int shape, int whichSize); + +public: + QPixmap brush () const; + bool brushIsDiagonalLine () const; + +signals: + void brushChanged (const QPixmap &pixmap, bool isDiagonalLine); + +protected slots: + virtual bool setSelected (int row, int col, bool saveAsDefault); + +private: + QPixmap m_brushBitmaps [16]; +}; + +#endif // __kptoolwidgetbrush_h__ diff --git a/kolourpaint/widgets/kptoolwidgeterasersize.cpp b/kolourpaint/widgets/kptoolwidgeterasersize.cpp new file mode 100644 index 00000000..cc58c0d1 --- /dev/null +++ b/kolourpaint/widgets/kptoolwidgeterasersize.cpp @@ -0,0 +1,161 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_TOOL_WIDGET_ERASER_SIZE 0 + + +#include + +#include +#include + +#include +#include + +#include +#include + + +static int eraserSizes [] = {2, 3, 5, 9, 17, 29}; +static const int numEraserSizes = int (sizeof (eraserSizes) / sizeof (eraserSizes [0])); + + +kpToolWidgetEraserSize::kpToolWidgetEraserSize (QWidget *parent, const char *name) + : kpToolWidgetBase (parent, name) +{ + setInvertSelectedPixmap (); + + m_cursorPixmaps = new QPixmap [numEraserSizes]; + QPixmap *cursorPixmap = m_cursorPixmaps; + + for (int i = 0; i < numEraserSizes; i++) + { + if (i == 3 || i == 5) + startNewOptionRow (); + + int s = eraserSizes [i]; + + cursorPixmap->resize (s, s); + cursorPixmap->fill (Qt::black); + + + QPixmap previewPixmap (s, s); + if (i < 3) + { + // HACK: kpToolWidgetBase's layout code sucks and gives uneven spacing + previewPixmap.resize ((width () - 4) / 3, 9); + } + + QPainter painter (&previewPixmap); + QRect rect ((previewPixmap.width () - s) / 2, (previewPixmap.height () - s) / 2, s, s); + painter.fillRect (rect, Qt::black); + painter.end (); + + QBitmap mask (previewPixmap.width (), previewPixmap.height ()); + mask.fill (Qt::color0/*transparent*/); + + QPainter maskPainter (&mask); + maskPainter.fillRect (rect, Qt::color1/*opaque*/); + maskPainter.end (); + + previewPixmap.setMask (mask); + + + addOption (previewPixmap, i18n ("%1x%2").arg (s).arg (s)/*tooltip*/); + + + cursorPixmap++; + } + + finishConstruction (1, 0); +} + +kpToolWidgetEraserSize::~kpToolWidgetEraserSize () +{ + delete [] m_cursorPixmaps; +} + +int kpToolWidgetEraserSize::eraserSize () const +{ + return eraserSizes [selected ()]; +} + +QPixmap kpToolWidgetEraserSize::cursorPixmap (const kpColor &color) const +{ +#if DEBUG_KP_TOOL_WIDGET_ERASER_SIZE + kdDebug () << "kpToolWidgetEraseSize::cursorPixmap() selected=" << selected () + << " numEraserSizes=" << numEraserSizes + << endl; +#endif + + // TODO: why are we even storing m_cursorPixmaps? + QPixmap pixmap = m_cursorPixmaps [selected ()]; + if (color.isOpaque ()) + pixmap.fill (color.toQColor ()); + + + bool showBorder = (pixmap.width () > 2 && pixmap.height () > 2); + + if (showBorder) + { + QPainter painter (&pixmap); + painter.setPen (Qt::black); + painter.drawRect (pixmap.rect ()); + } + + + if (color.isTransparent ()) + { + QBitmap maskBitmap (pixmap.width (), pixmap.height ()); + maskBitmap.fill (Qt::color0/*transparent*/); + + + if (showBorder) + { + QPainter maskBitmapPainter (&maskBitmap); + maskBitmapPainter.setPen (Qt::color1/*opaque*/); + maskBitmapPainter.drawRect (maskBitmap.rect ()); + } + + + pixmap.setMask (maskBitmap); + } + + + return pixmap; +} + +// virtual protected slot [base kpToolWidgetBase] +bool kpToolWidgetEraserSize::setSelected (int row, int col, bool saveAsDefault) +{ + const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault); + if (ret) + emit eraserSizeChanged (eraserSize ()); + return ret; +} + +#include diff --git a/kolourpaint/widgets/kptoolwidgeterasersize.h b/kolourpaint/widgets/kptoolwidgeterasersize.h new file mode 100644 index 00000000..71093fd6 --- /dev/null +++ b/kolourpaint/widgets/kptoolwidgeterasersize.h @@ -0,0 +1,59 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolwidgeterasersize_h__ +#define __kptoolwidgeterasersize_h__ + +#include +#include + + +class kpColor; + +class kpToolWidgetEraserSize : public kpToolWidgetBase +{ +Q_OBJECT + +public: + kpToolWidgetEraserSize (QWidget *parent, const char *name); + virtual ~kpToolWidgetEraserSize (); + + int eraserSize () const; + QPixmap cursorPixmap (const kpColor &color) const; + +signals: + void eraserSizeChanged (int size); + +protected slots: + virtual bool setSelected (int row, int col, bool saveAsDefault); + +private: + QPixmap *m_cursorPixmaps; +}; + +#endif // __kptoolwidgeterasersize_h__ diff --git a/kolourpaint/widgets/kptoolwidgetfillstyle.cpp b/kolourpaint/widgets/kptoolwidgetfillstyle.cpp new file mode 100644 index 00000000..74c174ce --- /dev/null +++ b/kolourpaint/widgets/kptoolwidgetfillstyle.cpp @@ -0,0 +1,222 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_TOOL_WIDGET_FILL_STYLE 0 + + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + + +kpToolWidgetFillStyle::kpToolWidgetFillStyle (QWidget *parent, const char *name) + : kpToolWidgetBase (parent, name) +{ + setInvertSelectedPixmap (); + + for (int i = 0; i < (int) FillStyleNum; i++) + { + QPixmap pixmap; + + pixmap = fillStylePixmap ((FillStyle) i, + (width () - 2/*margin*/) * 3 / 4, + (height () - 2/*margin*/ - 2/*spacing*/) * 3 / (3 * 4)); + addOption (pixmap, fillStyleName ((FillStyle) i)/*tooltip*/); + + startNewOptionRow (); + } + + finishConstruction (0, 0); +} + +kpToolWidgetFillStyle::~kpToolWidgetFillStyle () +{ +} + + +// private +QPixmap kpToolWidgetFillStyle::fillStylePixmap (FillStyle fs, int w, int h) +{ + QPixmap pixmap ((w <= 0 ? width () : w), (h <= 0 ? height () : h)); + pixmap.fill (Qt::white); + + QPainter painter (&pixmap); + + painter.setPen (QPen (Qt::black, 2)); + painter.setBrush (brushForFillStyle (fs, + kpColor (Qt::black.rgb ())/*foreground*/, + kpColor (Qt::gray.rgb ())/*background*/)); + + painter.drawRect (2, 2, w - 3, h - 3); + + painter.end (); + + + QBitmap mask (pixmap.width (), pixmap.height ()); + mask.fill (Qt::color0); + + painter.begin (&mask); + painter.setPen (QPen (Qt::color1, 2)); + + if (fs == FillWithBackground || fs == FillWithForeground) + painter.setBrush (Qt::color1); + + painter.drawRect (2, 2, w - 3, h - 3); + + painter.end (); + + pixmap.setMask (mask); + + return pixmap; +} + +// private +QString kpToolWidgetFillStyle::fillStyleName (FillStyle fs) const +{ + // do not complain about the "useless" breaks + // as the return statements might not be return statements one day + + switch (fs) + { + case NoFill: + return i18n ("No Fill"); + break; + case FillWithBackground: + return i18n ("Fill with Background Color"); + break; + case FillWithForeground: + return i18n ("Fill with Foreground Color"); + break; + default: + return QString::null; + break; + } +} + + +// public +kpToolWidgetFillStyle::FillStyle kpToolWidgetFillStyle::fillStyle () const +{ +#if DEBUG_KP_TOOL_WIDGET_FILL_STYLE + kdDebug () << "kpToolWidgetFillStyle::fillStyle() selected=" + << selectedRow () + << endl; +#endif + return (FillStyle) selectedRow (); +} + +// public static +QBrush kpToolWidgetFillStyle::maskBrushForFillStyle (FillStyle fs, + const kpColor &foregroundColor, + const kpColor &backgroundColor) +{ + // do not complain about the "useless" breaks + // as the return statements might not be return statements one day + + switch (fs) + { + case NoFill: + return Qt::NoBrush; + break; + case FillWithBackground: + return QBrush (backgroundColor.maskColor ()); + break; + case FillWithForeground: + return QBrush (foregroundColor.maskColor ()); + break; + default: + return Qt::NoBrush; + break; + } +} + +QBrush kpToolWidgetFillStyle::maskBrush (const kpColor &foregroundColor, + const kpColor &backgroundColor) +{ + return maskBrushForFillStyle (fillStyle (), foregroundColor, backgroundColor); +} + +// public static +QBrush kpToolWidgetFillStyle::brushForFillStyle (FillStyle fs, + const kpColor &foregroundColor, + const kpColor &backgroundColor) +{ + // do not complain about the "useless" breaks + // as the return statements might not be return statements one day + + // sync: kptoolpolygon.cpp pixmap() + + switch (fs) + { + case NoFill: + return Qt::NoBrush; + break; + case FillWithBackground: + if (backgroundColor.isOpaque ()) + return QBrush (backgroundColor.toQColor ()); + else + return Qt::NoBrush; + break; + case FillWithForeground: + if (foregroundColor.isOpaque ()) + return QBrush (foregroundColor.toQColor ()); + else + return Qt::NoBrush; + break; + default: + return Qt::NoBrush; + break; + } +} + +// public +QBrush kpToolWidgetFillStyle::brush (const kpColor &foregroundColor, + const kpColor &backgroundColor) +{ + return brushForFillStyle (fillStyle (), foregroundColor, backgroundColor); +} + + +// virtual protected slot [base kpToolWidgetBase] +bool kpToolWidgetFillStyle::setSelected (int row, int col, bool saveAsDefault) +{ + const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault); + if (ret) + emit fillStyleChanged (fillStyle ()); + return ret; +} + +#include diff --git a/kolourpaint/widgets/kptoolwidgetfillstyle.h b/kolourpaint/widgets/kptoolwidgetfillstyle.h new file mode 100644 index 00000000..219d47f2 --- /dev/null +++ b/kolourpaint/widgets/kptoolwidgetfillstyle.h @@ -0,0 +1,80 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolwidgetfillstyle_h__ +#define __kptoolwidgetfillstyle_h__ + +#include + +class QBrush; + +class kpColor; + +class kpToolWidgetFillStyle : public kpToolWidgetBase +{ +Q_OBJECT + +public: + kpToolWidgetFillStyle (QWidget *parent, const char *name); + virtual ~kpToolWidgetFillStyle (); + + enum FillStyle + { + NoFill, + FillWithBackground, + FillWithForeground, + FillStyleNum /* not (a valid FillStyle) */ + }; + +private: + QPixmap fillStylePixmap (FillStyle fs, int width, int height); + QString fillStyleName (FillStyle fs) const; + +public: + FillStyle fillStyle () const; + + static QBrush maskBrushForFillStyle (FillStyle fs, + const kpColor &foregroundColor, + const kpColor &backgroundColor); + QBrush maskBrush (const kpColor &foregroundColor, + const kpColor &backgroundColor); + + static QBrush brushForFillStyle (FillStyle fs, + const kpColor &foregroundColor, + const kpColor &backgroundColor); + QBrush brush (const kpColor &foregroundColor, + const kpColor &backgroundColor); + +signals: + void fillStyleChanged (kpToolWidgetFillStyle::FillStyle fillStyle); + +protected slots: + virtual bool setSelected (int row, int col, bool saveAsDefault); +}; + +#endif // __kptoolwidgetfillstyle_h__ diff --git a/kolourpaint/widgets/kptoolwidgetlinewidth.cpp b/kolourpaint/widgets/kptoolwidgetlinewidth.cpp new file mode 100644 index 00000000..27e34ecb --- /dev/null +++ b/kolourpaint/widgets/kptoolwidgetlinewidth.cpp @@ -0,0 +1,97 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include +#include + +#include + + +static int lineWidths [] = {1, 2, 3, 5, 8}; + +kpToolWidgetLineWidth::kpToolWidgetLineWidth (QWidget *parent, const char *name) + : kpToolWidgetBase (parent, name) +{ + setInvertSelectedPixmap (); + + int numLineWidths = sizeof (lineWidths) / sizeof (lineWidths [0]); + + int w = (width () - 2/*margin*/) * 3 / 4; + int h = (height () - 2/*margin*/ - (numLineWidths - 1)/*spacing*/) * 3 / (numLineWidths * 4); + + for (int i = 0; i < numLineWidths; i++) + { + QPixmap pixmap ((w <= 0 ? width () : w), + (h <= 0 ? height () : h)); + pixmap.fill (Qt::white); + + QBitmap maskBitmap (pixmap.width (), pixmap.height ()); + maskBitmap.fill (Qt::color0/*transparent*/); + + + QPainter painter (&pixmap), maskPainter (&maskBitmap); + painter.setPen (Qt::black), maskPainter.setPen (Qt::color1/*opaque*/); + painter.setBrush (Qt::black), maskPainter.setBrush (Qt::color1/*opaque*/); + + QRect rect = QRect (0, (pixmap.height () - lineWidths [i]) / 2, + pixmap.width (), lineWidths [i]); + painter.drawRect (rect), maskPainter.drawRect (rect); + + painter.end (), maskPainter.end (); + + + pixmap.setMask (maskBitmap); + + addOption (pixmap, QString::number (lineWidths [i])); + startNewOptionRow (); + } + + finishConstruction (0, 0); +} + +kpToolWidgetLineWidth::~kpToolWidgetLineWidth () +{ +} + +int kpToolWidgetLineWidth::lineWidth () const +{ + return lineWidths [selectedRow ()]; +} + +// virtual protected slot [base kpToolWidgetBase] +bool kpToolWidgetLineWidth::setSelected (int row, int col, bool saveAsDefault) +{ + const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault); + if (ret) + emit lineWidthChanged (lineWidth ()); + return ret; +} + +#include diff --git a/kolourpaint/widgets/kptoolwidgetlinewidth.h b/kolourpaint/widgets/kptoolwidgetlinewidth.h new file mode 100644 index 00000000..3255e443 --- /dev/null +++ b/kolourpaint/widgets/kptoolwidgetlinewidth.h @@ -0,0 +1,51 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolwidgetlinewidth_h__ +#define __kptoolwidgetlinewidth_h__ + +#include + +class kpToolWidgetLineWidth : public kpToolWidgetBase +{ +Q_OBJECT + +public: + kpToolWidgetLineWidth (QWidget *parent, const char *name); + virtual ~kpToolWidgetLineWidth (); + + int lineWidth () const; + +signals: + void lineWidthChanged (int width); + +protected slots: + virtual bool setSelected (int row, int col, bool saveAsDefault); +}; + +#endif // __kptoolwidgetlinewidth_h__ diff --git a/kolourpaint/widgets/kptoolwidgetopaqueortransparent.cpp b/kolourpaint/widgets/kptoolwidgetopaqueortransparent.cpp new file mode 100644 index 00000000..41b55d0f --- /dev/null +++ b/kolourpaint/widgets/kptoolwidgetopaqueortransparent.cpp @@ -0,0 +1,100 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_TOOL_WIDGET_OPAQUE_OR_TRANSPARENT 0 + + +#include + +#include +#include +#include + + +kpToolWidgetOpaqueOrTransparent::kpToolWidgetOpaqueOrTransparent (QWidget *parent, const char *name) + : kpToolWidgetBase (parent, name) +{ + setInvertSelectedPixmap (false); + + addOption (UserIcon ("option_opaque"), i18n ("Opaque")/*tooltip*/); + startNewOptionRow (); + addOption (UserIcon ("option_transparent"), i18n ("Transparent")/*tooltip*/); + + finishConstruction (0, 0); +} + +kpToolWidgetOpaqueOrTransparent::~kpToolWidgetOpaqueOrTransparent () +{ +} + + +// public +bool kpToolWidgetOpaqueOrTransparent::isOpaque () const +{ + return (selected () == 0); +} + +// public +bool kpToolWidgetOpaqueOrTransparent::isTransparent () const +{ + return (!isOpaque ()); +} + +// public +void kpToolWidgetOpaqueOrTransparent::setOpaque (bool yes) +{ +#if DEBUG_KP_TOOL_WIDGET_OPAQUE_OR_TRANSPARENT && 1 + kdDebug () << "kpToolWidgetOpaqueOrTransparent::setOpaque(" << yes << ")" << endl; +#endif + setSelected (yes ? 0 : 1, 0, false/*don't save*/); +} + +// public +void kpToolWidgetOpaqueOrTransparent::setTransparent (bool yes) +{ +#if DEBUG_KP_TOOL_WIDGET_OPAQUE_OR_TRANSPARENT && 1 + kdDebug () << "kpToolWidgetOpaqueOrTransparent::setTransparent(" << yes << ")" << endl; +#endif + setSelected (yes ? 1 : 0, 0, false/*don't save*/); +} + + +// protected slot virtual [base kpToolWidgetBase] +bool kpToolWidgetOpaqueOrTransparent::setSelected (int row, int col, bool saveAsDefault) +{ +#if DEBUG_KP_TOOL_WIDGET_OPAQUE_OR_TRANSPARENT && 1 + kdDebug () << "kpToolWidgetOpaqueOrTransparent::setSelected(" + << row << "," << col << ")" << endl; +#endif + const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault); + if (ret) + emit isOpaqueChanged (isOpaque ()); + return ret; +} + + +#include diff --git a/kolourpaint/widgets/kptoolwidgetopaqueortransparent.h b/kolourpaint/widgets/kptoolwidgetopaqueortransparent.h new file mode 100644 index 00000000..c24cd308 --- /dev/null +++ b/kolourpaint/widgets/kptoolwidgetopaqueortransparent.h @@ -0,0 +1,56 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kp_tool_widget_opaque_or_transparent_h__ +#define __kp_tool_widget_opaque_or_transparent_h__ + + +#include + +class kpToolWidgetOpaqueOrTransparent : public kpToolWidgetBase +{ +Q_OBJECT + +public: + kpToolWidgetOpaqueOrTransparent (QWidget *parent, const char *name); + virtual ~kpToolWidgetOpaqueOrTransparent (); + + bool isOpaque () const; + bool isTransparent () const; + void setOpaque (bool yes = true); + void setTransparent (bool yes = true); + +signals: + void isOpaqueChanged (bool isOpaque_); + +protected slots: + virtual bool setSelected (int row, int col, bool saveAsDefault); +}; + + +#endif // kp_tool_widget_opaque_or_transparent_h__ diff --git a/kolourpaint/widgets/kptoolwidgetspraycansize.cpp b/kolourpaint/widgets/kptoolwidgetspraycansize.cpp new file mode 100644 index 00000000..161e5015 --- /dev/null +++ b/kolourpaint/widgets/kptoolwidgetspraycansize.cpp @@ -0,0 +1,119 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_TOOL_WIDGET_SPRAYCAN_SIZE 0 + + +#include + +#include +#include +#include + +#include +#include +#include + +#include + + +static int spraycanSizes [] = {9, 17, 29}; + +kpToolWidgetSpraycanSize::kpToolWidgetSpraycanSize (QWidget *parent, const char *name) + : kpToolWidgetBase (parent, name) +{ +#if DEBUG_KP_TOOL_WIDGET_SPRAYCAN_SIZE + kdDebug () << "kpToolWidgetSpraycanSize::kpToolWidgetSpraycanSize() CALLED!" << endl; +#endif + + for (int i = 0; i < int (sizeof (spraycanSizes) / sizeof (spraycanSizes [0])); i++) + { + int s = spraycanSizes [i]; + QString iconName = QString ("tool_spraycan_%1x%1").arg (s).arg(s); + + #if DEBUG_KP_TOOL_WIDGET_SPRAYCAN_SIZE + kdDebug () << "\ticonName=" << iconName << endl; + #endif + + QPixmap pixmap (s, s); + pixmap.fill (Qt::white); + + QPainter painter (&pixmap); + painter.drawPixmap (0, 0, UserIcon (iconName)); + painter.end (); + + QImage image = kpPixmapFX::convertToImage (pixmap); + + QBitmap mask (pixmap.width (), pixmap.height ()); + mask.fill (Qt::color0); + + painter.begin (&mask); + painter.setPen (Qt::color1); + + for (int y = 0; y < image.height (); y++) + { + for (int x = 0; x < image.width (); x++) + { + if ((image.pixel (x, y) & RGB_MASK) == 0/*black*/) + painter.drawPoint (x, y); // mark as opaque + } + } + + painter.end (); + + pixmap.setMask (mask); + + addOption (pixmap, i18n ("%1x%2").arg (s).arg (s)/*tooltip*/); + if (i == 1) + startNewOptionRow (); + } + + finishConstruction (0, 0); +} + +kpToolWidgetSpraycanSize::~kpToolWidgetSpraycanSize () +{ +} + + +// public +int kpToolWidgetSpraycanSize::spraycanSize () const +{ + return spraycanSizes [selected ()]; +} + +// protected slot virtual [base kpToolWidgetBase] +bool kpToolWidgetSpraycanSize::setSelected (int row, int col, bool saveAsDefault) +{ + const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault); + if (ret) + emit spraycanSizeChanged (spraycanSize ()); + return ret; +} + +#include diff --git a/kolourpaint/widgets/kptoolwidgetspraycansize.h b/kolourpaint/widgets/kptoolwidgetspraycansize.h new file mode 100644 index 00000000..b4233a80 --- /dev/null +++ b/kolourpaint/widgets/kptoolwidgetspraycansize.h @@ -0,0 +1,51 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolwidgetspraycansize_h__ +#define __kptoolwidgetspraycansize_h__ + +#include + +class kpToolWidgetSpraycanSize : public kpToolWidgetBase +{ +Q_OBJECT + +public: + kpToolWidgetSpraycanSize (QWidget *parent, const char *name); + virtual ~kpToolWidgetSpraycanSize (); + + int spraycanSize () const; + +signals: + void spraycanSizeChanged (int size); + +protected slots: + virtual bool setSelected (int row, int col, bool saveAsDefault); +}; + +#endif // __kptoolwidgetspraycansize_h__ diff --git a/kooka/AUTHORS b/kooka/AUTHORS new file mode 100644 index 00000000..41f6d7f2 --- /dev/null +++ b/kooka/AUTHORS @@ -0,0 +1,2 @@ +Ivan Shvedunov +Klaas Freitag diff --git a/kooka/CHANGES b/kooka/CHANGES new file mode 100644 index 00000000..0b384de6 --- /dev/null +++ b/kooka/CHANGES @@ -0,0 +1,158 @@ +-> Nov. 2000, Klaas Freitag : +initial version + +- December 2000, Klaas Freitag : + +Added support for calling the external ocr program gocr of Joerg +Schulenburg and friends. See http://jocr.sourceforge.net for +details. Mind that still everything is under construction, even if +there could be some interesting screen hots around. + +OCR works best with smaller parts of text scanned black-and-white +scanned with about 150 dpi. + +-> Released version 0.2 on kde.org + +- December 2000, Klaas Freitag : + +* Reworked the ocr integration: Nice start- and finish-dialog, + animated status image, opening a text editor with the result text + via mime mechanism of KDE (KRun). OCR-Parameter get stored via KConfig. + OCR may be performed on the entire image or the selection. + +* Reworked the save assistant: New layout and fully KDE2-Compliant. + Still no new Image format help texts. + +* Reworked the startup dialog: Allows to select the scan device from a + list of available devices, possible to set the startup scan device + 'forever'. + +* Resizing of the scan parameters. The scan parameters shell should + take as much as space as it needs. It is not longer fix sized now. + +* Mirroring in three kinds of the displayed image with toolbar and menubar + entries. That needed that the packager is able to handle changes on already + saved images. + +* Creation of new images from the selection on the image canvas. + +- Jan 2001, Klaas Freitag : + +* Rotating of images. + +* Opening images in a kde graphic app. + +* Proper error messages if a changed image cant be saved. + +* drag and drop support: Pull an image from konqueror on the scanpackager ! + The image wil be importet. + +* print support (basic) + +* basic configuration support + + ... and losts of other, small bug fixes, unfortunately not mentionend very + well here. Sorry for that, I will try to do better. + +/* ================================================================================ */ + +-> Released version 0.3 in kdegraphics/kooka for KDE 2.2 +The released version does actually not have too many new + +- July 2001, Klaas Freitag + +* fixed the img_saver-bug that the 'Do not ask again' is not honored. + Now it should be, if it is checked, the format-Dialog will not be + displayed again. + +* added a new section Image saver to the properties dialog + +* some changes to the image saver to display the image type (Lineart etc. ) + +* bugfixes in the image Saver + +/* ================================================================================ */ +Nov 2001: +Added a combo box below kooka's gallery widget. Since the gallery and the +the preview window are in a tabwidget together, user complained that they +do not see the directory they are scanning to while working on the preview +page. The combobox shows the currently selected directory and is always +visible. The user can use the combo to change the target dir without leaving +the preview page. + +Nov 2001: +Replaced the old ScanPackager object by a new one based on the new KFileTreeView +Widget in kdelibs/kfile. Hopefully soon full KURL support and more than one image +repository. + +Nov 2001: +Moved preview image to a hidden directory under $KDEHOME/share/apps/ScanImages/.previews +That makes the preview images invisible in the Packager. + +/* ================================================================================ */ + +many bugfixes for KDE 3.0 -> Released Kooka 0.35 for KDE 3.0 + +Released Kooka 0.36 for KDE 3.0.1 + +Mai 2002: + Added Thumbnail View with Preference Dialog => Kooka Release 0.37 + Completed About dialog and added the Webpage http://kooka.kde.org + +/* ================================================================================ */ + +For Kooka 0.38: Introduced KDockWidgets to make the GUI configurable to everybodies +needs. + +/* ================================================================================ */ + +For Kooka 0.39: + +* Fixed problem with gocr: gocr always resulted in (PICTURE) - fixed + it by changing the save format for images to gocr. This bug happens + only with gocr 0.3.5 (and probably higher). + +* Renaming images inline reimplemented again. + +* exported Gallery Actions to appear in the menu bar again. + +* added a progress bar and bugfixes to the thumbview + +* added halftoning to the scanservice and thus kooka + +* fixed bugs in the resolving of dependencies of scanner parameters. + +/* ================================================================================ */ + +For Kooka 0.40: + +* Added Kadmos-Check to configure.in.in + +* Changed the Mainwindow to be KParts-Mainwindow,neccessary for using Parts in Kooka + +* OCR: Code massive reorganised. More ability to use different ocr engines. + +* OCR: Preparation to use Kadmos OCR engine. + +* OCR: Result not longer in a separat dialog, but in a editor part. + +* Scanpackager uses KookaImage more consequently. That provides meta data where needed + +* Improved image viewer from libkscan: Holds zoom settings over images + +* image information in status bar. + +/* ================================================================================ */ + +For Kooka 0.41: + +* Added support for ocrad OCR software. + +* Added image printing tab to the tab dialog, good printing support. + +* fixed some bugs with OCR result image handling. + +* libkscan: Fixed a cast bug with scan source selection + +* Improved support for tiff images, handle images with different x- and y resolution + correctly. diff --git a/kooka/COPYING b/kooka/COPYING new file mode 100644 index 00000000..0b84a43f --- /dev/null +++ b/kooka/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +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 give any other recipients of the Program a copy of this License +along with the Program. + +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 Program or any portion +of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +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 Program, 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 Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) 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; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, 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 executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or 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 counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program 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. + + 5. 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 Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. 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 Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program 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 Program. + +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. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program 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. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 Program +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 Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, 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 + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/kooka/CREDITS b/kooka/CREDITS new file mode 100644 index 00000000..cbb0bf8b --- /dev/null +++ b/kooka/CREDITS @@ -0,0 +1,4 @@ +Kooka and KScan has been derived from the the 1997 work of Ivan +Shvedunov , his homepage can be found at +http://rf-hp.npi.msu.su. + diff --git a/kooka/INSTALL b/kooka/INSTALL new file mode 100644 index 00000000..28fadaa7 --- /dev/null +++ b/kooka/INSTALL @@ -0,0 +1,181 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + diff --git a/kooka/Makefile.am b/kooka/Makefile.am new file mode 100644 index 00000000..6fec098e --- /dev/null +++ b/kooka/Makefile.am @@ -0,0 +1,46 @@ +## Makefile.am for kooka + +SUBDIRS = pics + +bin_PROGRAMS = kooka +METASOURCES = AUTO + +kooka_SOURCES = main.cpp kooka.cpp kookaview.cpp kookapref.cpp \ + img_saver.cpp ksaneocr.cpp \ + kookaimage.cpp kookaimagemeta.cpp scanpackager.cpp \ + imgnamecombo.cpp imageselectline.cpp \ + thumbview.cpp thumbviewitem.cpp \ + dwmenuaction.cpp kocrbase.cpp \ + kocrgocr.cpp kocrkadmos.cpp kadmosocr.cpp ocrword.cpp \ + ocrresedit.cpp kookaprint.cpp imgprintdialog.cpp \ + kocrocrad.cpp +# pagesetup.cpp + +kooka_LDADD = $(LIB_KFILE) -lkdeprint -lktexteditor $(LIBTIFF) $(top_builddir)/libkscan/libkscan.la $(KADMOS_LIB) $(LIB_KSPELL) +kooka_LDFLAGS = $(KDE_RPATH) $(all_libraries) + +INCLUDES = -I$(top_srcdir)/libkscan $(all_includes) $(LIBSANE_INCLUDES) $(KADMOS_INC) + +noinst_HEADERS = \ +kookaview.h scanpackager.h \ +img_saver.h ksaneocr.h \ +formathelp.h kooka.h \ +kookaiface.h thumbview.h thumbviewitem.h \ +kookapref.h resource.h \ +imgnamecombo.h imageselectline.h kookaimage.h kookaimagemeta.h \ +kocrbase.h kocrgocr.h kocrkadmos.h \ +kadmosocr.h ocrword.h ocrresedit.h kookaprint.h imgprintdialog.h \ +kocrocrad.h + +# pagesetup.h + +appdatadir = $(kde_datadir)/kooka +appdata_DATA = kookaui.rc + +kde_conf_DATA = kookarc + +xdg_apps_DATA = kooka.desktop + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/kooka.pot + diff --git a/kooka/README b/kooka/README new file mode 100644 index 00000000..8ae6fa54 --- /dev/null +++ b/kooka/README @@ -0,0 +1,66 @@ +Kooka +===== + +Kooka is a raster image scan program for the KDE system. + + PLEASE READ THE FILE "WARNING" FIRST ! + +It uses the SANE-lib (http://www.sane-project.org/) and the the +KScan-library which is a KDE module for scanner access. + +KScan and Kooka are under construction. Don't expect everything to work +fine. If you want to help, please send patches to freitag@suse.de. + +Features: +========= + +Kooka's main features are: + +Scanner Support using SANE: +- Scanner support using SANE. Kooka _DOES_NOT_ support all features that SANE + and its backends offer. It takes a small subset of the available options. +- Kooka offers a GUI to change the most important scanner options like resolution, + mode, threshold etc. These options are generated on the fly, depending on the + scanner capabilities. +- Kooka offers a preview-function and the user can select the scan area interactively + or automatically. + +Image Storage: +- Kooka provides an assistant to save your acquired images. +- Filenames are generated automatically to support multiple scans. +- Kooka manages the scanned images in a tree view where the user can delete and + export images. + +Image Manipulation: +- Kooka provides basic image manipulation functions like rotation, mirroring. +- Cut images to fit size. + +Image Viewing: +- Scanned images can be viewed by clicking them in the tree view. +- The viewer has a zoom function. + +OCR: +- Kooka supports Joerg Schulenburg's gocr, an open source program + for optical character recognition (OCR). Kooka starts the OCR program + and displays its output. Best results with bw-images scanned with ~150 DPI +- Support for the commercial OCR/ICR package KADMOS of the reRecognition + GmbH Kreuzlingen. Please read README.KADMOS for more information. + +Problems: +========= + +* Kooka does not yet support all options SANE offers. That will +improve in the future. However, I don't know if it makes sense to +support all, even not very common options, some scanners offer. Lets +see what is necessary and makes sense for the purpose of Kooka. + +* Kooka does not yet have a strategy for very large images :(. It uses +the Qt QImage/QPixmap as is. On some displays, that causes problems. + +* Automatic document feeder (ADF) support is not yet working correctly. + +---------------------------------------------------------------------- +Klaas Freitag + +$Id$ + diff --git a/kooka/README.KADMOS b/kooka/README.KADMOS new file mode 100644 index 00000000..a6242155 --- /dev/null +++ b/kooka/README.KADMOS @@ -0,0 +1,73 @@ +Kooka and KADMOS integration +============================ + +This file describes how to make Kooka working with the KADMOS OCR/ICR +engine. + +KAMDOS is commercial OCR/ICR software component of the company + + reRecognition GmbH + Hafenstr. 50B + 8280 Kreuzlingen + Switzerland + Tel.: +41 71 6780000 + Fax: +41 71 6780099 + www.reRecognition.com + +and Kooka can be build using the linux version of the component in +order to achive very good ocr results. + +Please contact re Recognition directly if you like to obtain or test +KADMOS. Note that if you are linking against KADMOS, you loose the +permission to use the GPL Qt version, so you need a commercial Qt +version as well. + +Configuration +------------- + +As Kooka does not require KADMOS, it is neccessary to configure +Kooka to use the KADMOS library. This could be done by calling the +configure script of Kooka's source distribution with following +parameter: +./configure --with-kadmos-dir=/where/kadmos.h/resides/ + +The configure script tries to locate the file kadmos.h in the +directory that was specified. The KADMOS library is expected in the +same directory. Build the source after configuring with KADMOS. Kooka +enables the code to work with KADMOS in the source and links the +library. + +Installation +------------ + +KADMOS is linked statically and thus there is no need for special +installation of the KADMOS library. + +Installation of the Classifier Files: + +KADMOS needs classifier files for the ocr process which come with +the KADMOS developer's toolkit. The classifier files need to be installed +in the KDE application data directory for Kooka in a subdirectory named +classifiers. If your KDE installation goes to /opt/kde3/, this is for +example /opt/kde3/share/apps/kooka/classifiers. Kooka picks the +available classifiers up automatically. + +The classifiers are named in the following way: + +[fontkind][country/region].rec, +where fontkinds are +ttf -> machine print font +hand -> handprint (isolated) +norm -> OCR norm font + + +For example the following classifier names are used: + +ttfus.rec US machineprint classifiers +handus.rec US handwriting classifiers +norm.rec Special OCR character sets, not localized + + +---------------------------------------------------------------------- +Klaas Freitag +$Id$ diff --git a/kooka/TODO b/kooka/TODO new file mode 100644 index 00000000..ce5f3967 --- /dev/null +++ b/kooka/TODO @@ -0,0 +1,26 @@ +To be continued: + +Object ScanParams: +- Resizing. On startup, the object comes up in a nearly fixed size, suiting the + mustek-backend very well ;) - thats the one I use at home. The cool solution + would be if the object 'knows' and tells what size (especially height) it wants + to have. + + -> This should be done now. Please check, if it works for other than mustek + backends. + +Startup: + +- Changing the 'Dont ask me on startup'-decision. If the user checks the button + in the startup dialog never to ask which scan device to use, it is not possible + to revert this decision. Need a page in the Preferences dialog. + +OCR: + +- The ocr result window does not appear properly on very large result images + provided by gocr. Kooka should resize the result image to a reasonable size. + +Scan Packager: + +- The scan packager needs major rework. Enhancements like metadata in XML etc + should be included. diff --git a/kooka/WARNING b/kooka/WARNING new file mode 100644 index 00000000..bee996d5 --- /dev/null +++ b/kooka/WARNING @@ -0,0 +1,28 @@ + +Scanning with Kooka and KScan +============================= + +Kooka and KScan use the SANE library to attach to the scanner +hardware. It cannot be avoided by any library that a program sends +commands to the scanner which can damage it. Especially very cheap +scanners sometimes do not have a hardware protection against driving +the bed to far, which can cause terrible noise and damage :-( + +That is why you should be warned running Kooka or the KDE scanservice +the first time. Even if there were no reportings that something bad +happens to any scanner models using Kooka yet, but it can not be +garanteed. + +Starting to scan the first time, be sure to sit next to your scanner +having your hand on the power-off switch. Switch off immediately if +you hear unexpected noises or if something strange happens. + +If you find errors, please dont ask the SANE-people without having +made sure that your error is _really_ a SANE error. Most probably, you +found an KScan or Kooka-Error, which should be reported at +http://bugs.kde.org + + +- Klaas Freitag + +$Id$ diff --git a/kooka/configure.in.in b/kooka/configure.in.in new file mode 100644 index 00000000..df590f5d --- /dev/null +++ b/kooka/configure.in.in @@ -0,0 +1,33 @@ +dnl AC_SEARCH_LIBS(pgm2asc,Pgm2asc) +dnl AC_CHECK_LIB(Pgm2asc,pgm2asc) +dnl should define HAVE_LIBPGM2ASC if available + +AC_ARG_WITH([kadmos], + [AC_HELP_STRING([--with-kadmos], + [Enable the kadmos OCR engine @<:@default=check@:>@])], + [], with_kadmos=check) + +AC_ARG_WITH([kadmos-dir], + AC_HELP_STRING([--with-kadmos-dir], + [sets the path to the kadmos engine @<:@default=/usr/local@:>@]), + [ac_kadmos_value=$withval], [ac_kadmos_value=/usr/local]) + +KADMOS_INC= +KADMOS_LIB= + +if test "x$with_kadmos" != xno; then + if test -r "$ac_kadmos_value/kadmos.h"; then + KADMOS_INC="-I$ac_kadmos_value" + KADMOS_LIB="$ac_kadmos_value/librep.a" + AC_DEFINE_UNQUOTED(HAVE_KADMOS, 1, [Defines if your system has the kadmos libraries]) + else + AC_MSG_WARN([couldn't find kadmos engine header file under $ac_kadmos_value/kadmos.h]) + fi + + if test "x$with_kadmos" != xcheck && test -z "$KADMOS_LIB"; then + AC_MSG_ERROR([--with-kadmos was given, but test for kadmos failed]) + fi +fi + +AC_SUBST(KADMOS_LIB) +AC_SUBST(KADMOS_INC) diff --git a/kooka/dwmenuaction.cpp b/kooka/dwmenuaction.cpp new file mode 100644 index 00000000..abe57f23 --- /dev/null +++ b/kooka/dwmenuaction.cpp @@ -0,0 +1,72 @@ +/*************************************************************************** + dwmenuaction.cpp - dockwidget visibility switches to actions + ------------------- + begin : 16.07.2002 + copyright : (C) 1999 by Klaas Freitag + email : freitag@suse.de + + $Id$ + Based on code from the from Joseph Wenninger (kate project) +***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#include "dwmenuaction.h" +#include "dwmenuaction.moc" +//------------------------------------- + +dwMenuAction::dwMenuAction( const QString& text, const KShortcut& cut, + KDockWidget *dw,QObject* parent, + KDockMainWindow *mw, const char* name ) + :KToggleAction(text,cut,parent,name),m_dw(dw),m_mw(mw) +{ + connect(this,SIGNAL(toggled(bool)),this,SLOT(slotToggled(bool))); + connect(m_dw->dockManager(),SIGNAL(change()),this,SLOT(anDWChanged())); + connect(m_dw,SIGNAL(destroyed()),this,SLOT(slotWidgetDestroyed())); + setChecked(m_dw->mayBeHide()); +} + + +dwMenuAction::~dwMenuAction(){;} + +void dwMenuAction::anDWChanged() +{ + if (isChecked() && m_dw->mayBeShow()) setChecked(false); + else if ((!isChecked()) && m_dw->mayBeHide()) setChecked(true); +} + + +void dwMenuAction::slotToggled(bool t) +{ + + if ((!t) && m_dw->mayBeHide() ) m_dw->undock(); + else + if ( t && m_dw->mayBeShow() ) m_mw->makeDockVisible(m_dw); + +} + + +void dwMenuAction::slotWidgetDestroyed() +{ + unplugAll(); + deleteLater(); +} + + +/* END */ diff --git a/kooka/dwmenuaction.h b/kooka/dwmenuaction.h new file mode 100644 index 00000000..9b1698ed --- /dev/null +++ b/kooka/dwmenuaction.h @@ -0,0 +1,62 @@ +/*************************************************************************** + dwmenuaction.h - dockwidget visibility switches to actions + ------------------- + begin : 16.07.2002 + copyright : (C) 1999 by Klaas Freitag + email : freitag@suse.de + + $Id$ + Based on code from the from Joseph Wenninger (kate project) +***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#ifndef __DW_MENU_ACTION +#define __DW_MENU_ACTION +#include +#include +#include + +/** + * This class is just a helper class since the KDockWidget classes do not yet + * export KActions but only a QPopup-Pointer, which is quite useless in case + * you have a xml-file driven gui. + * This class provides Actions for show and hide parts of the GUI (dockwidgets) + * Maybe that classes can be removed as soon the DockWidget know Actions + */ +class dwMenuAction:public KToggleAction +{ + Q_OBJECT +public: + dwMenuAction( const QString& text, + const KShortcut& cut = KShortcut(), + KDockWidget *dw=0, QObject* parent = 0, + KDockMainWindow * mw=0, const char* name = 0 ); + virtual ~dwMenuAction(); + +private: + KDockWidget *m_dw; + KDockMainWindow *m_mw; +protected slots: + void slotToggled(bool); + void anDWChanged(); + void slotWidgetDestroyed(); +}; + +#endif diff --git a/kooka/formathelp.h b/kooka/formathelp.h new file mode 100644 index 00000000..7887a240 --- /dev/null +++ b/kooka/formathelp.h @@ -0,0 +1,43 @@ +/*************************************************************************** + formathelp.h - description + ------------------- + begin : Mon Dec 27 1999 + copyright : (C) 1999 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#define HELP_BMP i18n("The bitmap-format is a well known format,\n" \ + "often used for 256 color images under " \ + "MS Windows.\n Suitable for color and " \ + "lineart-pictures\n" ) +#define HELP_PNM i18n("Portable Anymap\n" \ + ""\ + "" ) +#define HELP_JPG i18n("Jpeg is a high compression,\nquality " \ + "losing format for color\npictures " \ + "with many different colors." \ + "" ) + +#define HELP_EPS i18n("EPS is Encapsulated Postscript.\n " \ + "Initially it's a printer definition\n " \ + "language. Use this format if you\n" \ + "want to print the image or use\n" \ + "it with e.g. TeX" ) diff --git a/kooka/imageselectline.cpp b/kooka/imageselectline.cpp new file mode 100644 index 00000000..f8677f1f --- /dev/null +++ b/kooka/imageselectline.cpp @@ -0,0 +1,105 @@ +/*************************************************************************** + imageselectline.cpp - select a background image. + ------------------- + begin : Fri Dec 17 1999 + copyright : (C) 1999 by Klaas Freitag + email : freitag@suse.de + + $Id$ + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "imageselectline.h" + +/* ############################################################################## */ + +/* + * This widget just combines a label, a combobox holding a path and a select button + * together in a row. The button opens a file selector box to pick a file. + */ + +ImageSelectLine::ImageSelectLine( QWidget *parent, const QString& text ) + : QHBox( parent ) +{ + setSpacing( 5 ); + (void) new QLabel( text, this ); + m_urlCombo = new KURLComboBox( KURLComboBox::Files, this ); + m_buttFileSelect = new QPushButton( this ); + m_buttFileSelect->setPixmap( SmallIcon( "fileopen" ) ); + + m_urlCombo->setMaxItems(5); + + connect( m_urlCombo, SIGNAL( urlActivated( const KURL& )), + this, SLOT( slUrlActivated( const KURL& ))); + + connect( m_buttFileSelect, SIGNAL( clicked() ), + this, SLOT( slSelectFile())); +} + +void ImageSelectLine::slSelectFile() +{ + KURL newUrl; + newUrl = KFileDialog::getImageOpenURL(); + + QStringList l = m_urlCombo->urls(); + + if( ! newUrl.isEmpty()) + { + l.prepend( newUrl.url() ); + m_urlCombo->setURLs( l ); + m_currUrl = newUrl; + } +} + +void ImageSelectLine::slUrlActivated( const KURL& url ) +{ + kdDebug(28000) << "Activating url: " << url.url() << endl; + m_currUrl = url; +} + +KURL ImageSelectLine::selectedURL() const +{ + return m_currUrl; +} + +void ImageSelectLine::setURL( const KURL& url ) +{ + if( m_urlCombo ) m_urlCombo->setURL( url ); + m_currUrl = url; +} + +void ImageSelectLine::setURLs( const QStringList& list ) +{ + if( m_urlCombo ) m_urlCombo->setURLs( list ); +} + +#include "imageselectline.moc" diff --git a/kooka/imageselectline.h b/kooka/imageselectline.h new file mode 100644 index 00000000..991cb3fd --- /dev/null +++ b/kooka/imageselectline.h @@ -0,0 +1,66 @@ +/*************************************************************************** + imageselectline.h - select a background image. + ------------------- + begin : ? + copyright : (C) 2002 by Klaas Freitag + email : freitag@suse.de + + $Id$ +***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#ifndef __IMGSELECTLINE_H__ +#define __IMGSELECTLINE_H__ + +#include + +/** + * + */ + +class KURL; +class KURLComboBox; +class QPushButton; +class QStringList; + +class ImageSelectLine:public QHBox +{ + Q_OBJECT +public: + ImageSelectLine( QWidget *parent, const QString& text ); + + KURL selectedURL() const; + void setURL( const KURL& ); + void setURLs( const QStringList& ); + +protected slots: + void slSelectFile(); + void slUrlActivated( const KURL& ); + +private: + + KURL m_currUrl; + KURLComboBox *m_urlCombo; + QPushButton *m_buttFileSelect; + +}; + + +#endif diff --git a/kooka/img_saver.cpp b/kooka/img_saver.cpp new file mode 100644 index 00000000..1d7cf1d7 --- /dev/null +++ b/kooka/img_saver.cpp @@ -0,0 +1,897 @@ +/*************************************************************************** + img_saver.cpp - description + ------------------- + begin : Mon Dec 27 1999 + copyright : (C) 1999 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "resource.h" +#include "img_saver.h" +#include "previewer.h" +#include "kookaimage.h" + +FormatDialog::FormatDialog( QWidget *parent, const QString&, const char *name ) + :KDialogBase( parent, name, true, + /* Tabbed,*/ i18n( "Kooka Save Assistant" ), + Ok|Cancel, Ok ) + +{ + buildHelp(); + // readConfig(); + // QFrame *page = addPage( QString( "Save the image") ); + QFrame *page = new QFrame( this ); + page->setFrameStyle( QFrame::Box | QFrame::Sunken ); + Q_CHECK_PTR( page ); + setMainWidget( page ); + + QVBoxLayout *bigdad = new QVBoxLayout( page, marginHint(), spacingHint()); + Q_CHECK_PTR(bigdad); + + // some nice words + QLabel *l0 = new QLabel( page ); + Q_CHECK_PTR(l0); + l0->setText( i18n( "Save Assistant

Select an image format to save the scanned image." )); + bigdad->addWidget( l0 ); + + KSeparator* sep = new KSeparator( KSeparator::HLine, page); + bigdad->addWidget( sep ); + + // Layout-Boxes + // QHBoxLayout *hl1= new QHBoxLayout( ); // Caption + QHBoxLayout *lhBigMiddle = new QHBoxLayout( spacingHint() ); // Big middle + Q_CHECK_PTR(lhBigMiddle); + bigdad->addLayout( lhBigMiddle ); + QVBoxLayout *lvFormatSel = new QVBoxLayout( spacingHint() ); // Selection List + Q_CHECK_PTR(lvFormatSel); + lhBigMiddle->addLayout( lvFormatSel ); + + // Insert Scrolled List for formats + QLabel *l1 = new QLabel( page ); + Q_CHECK_PTR(l1); + l1->setText( i18n( "Available image formats:" )); + + lb_format = new QListBox( page, "ListBoxFormats" ); + Q_CHECK_PTR(lb_format); + +#ifdef USE_KIMAGEIO + QStringList fo = KImageIO::types(); +#else + QStringList fo = QImage::outputFormatList(); +#endif + kdDebug(28000) << "#### have " << fo.count() << " image types" << endl; + lb_format->insertStringList( fo ); + connect( lb_format, SIGNAL( highlighted(const QString&)), + SLOT( showHelp(const QString&))); + + // Insert label for helptext + l_help = new QLabel( page ); + Q_CHECK_PTR(l_help); + l_help->setFrameStyle( QFrame::Panel|QFrame::Sunken ); + l_help->setText( i18n("-No format selected-" )); + l_help->setAlignment( AlignVCenter | AlignHCenter ); + l_help->setMinimumWidth(230); + + // Insert Selbox for subformat + l2 = new QLabel( page ); + Q_CHECK_PTR(l2); + l2->setText( i18n( "Select the image sub-format" )); + cb_subf = new QComboBox( page, "ComboSubFormat" ); + Q_CHECK_PTR( cb_subf ); + + // Checkbox to store setting + cbDontAsk = new QCheckBox(i18n("Don't ask again for the save format if it is defined."), + page ); + Q_CHECK_PTR( cbDontAsk ); + + QFrame *hl = new QFrame(page); + Q_CHECK_PTR( hl ); + hl->setFrameStyle( QFrame::HLine|QFrame::Sunken ); + + // bigdad->addWidget( l_caption, 1 ); + lvFormatSel->addWidget( l1, 1 ); + lvFormatSel->addWidget( lb_format, 6 ); + lvFormatSel->addWidget( l2, 1 ); + lvFormatSel->addWidget( cb_subf, 1 ); + + lhBigMiddle->addWidget( l_help, 2 ); + //bigdad->addStretch(1); + bigdad->addWidget( hl, 1 ); + bigdad->addWidget( cbDontAsk , 2 ); + + bigdad->activate(); + +} + +void FormatDialog::showHelp( const QString& item ) +{ + QString helptxt = format_help[ item ]; + + if( !helptxt.isEmpty() ) { + // Set the hint + l_help->setText( helptxt ); + + // and check subformats + check_subformat( helptxt ); + } else { + l_help->setText( i18n("-no hint available-" )); + } +} + +void FormatDialog::check_subformat( const QString & format ) +{ + // not yet implemented + kdDebug(28000) << "This is format in check_subformat: " << format << endl; + cb_subf->setEnabled( false ); + // l2 = Label "select subformat" ->bad name :-| + l2->setEnabled( false ); +} + +void FormatDialog::setSelectedFormat( QString fo ) +{ + QListBoxItem *item = lb_format->findItem( fo ); + + if( item ) + { + // Select it. + lb_format->setSelected( lb_format->index(item), true ); + } +} + + +QString FormatDialog::getFormat( ) const +{ + int item = lb_format->currentItem(); + + if( item > -1 ) + { + const QString f = lb_format->text( item ); + return( f ); + } + return( "BMP" ); +} + + +QCString FormatDialog::getSubFormat( ) const +{ + // Not yet... + return( "" ); +} + +#include "formathelp.h" +void FormatDialog::buildHelp( void ) +{ + format_help.insert( QString::fromLatin1("BMP"), HELP_BMP ); + format_help.insert( QString::fromLatin1("PNM"), HELP_PNM ); + format_help.insert( QString::fromLatin1("JPEG"), HELP_JPG ); + format_help.insert( QString::fromLatin1("JPG"), HELP_JPG ); + format_help.insert( QString::fromLatin1("EPS"), HELP_EPS ); +} + + +/* ********************************************************************** */ + +ImgSaver::ImgSaver( QWidget *parent, const KURL dir_name ) + : QObject( parent ) +{ + + if( dir_name.isEmpty() || dir_name.protocol() != "file" ) + { + kdDebug(28000) << "ImageServer initialised with wrong dir " << dir_name.url() << endl; + directory = Previewer::galleryRoot(); + } + else + { + /* A path was given */ + if( dir_name.protocol() != "file" ) + { + kdDebug(28000) << "ImgSaver: Can only save local image, sorry !" << endl; + } + else + { + directory = dir_name.directory(true, false); + } + } + + kdDebug(28000) << "ImageSaver uses dir <" << directory << endl; + createDir( directory ); + readConfig(); + + last_file = ""; + last_format =""; + +} + + +ImgSaver::ImgSaver( QWidget *parent ) + :QObject( parent ) +{ + directory = Previewer::galleryRoot(); + createDir( directory ); + + readConfig(); + + last_file = ""; + last_format =""; + +} + + +/* Needs a full qualified directory name */ +void ImgSaver::createDir( const QString& dir ) +{ + KURL url( dir ); + + if( ! KIO::NetAccess::exists(url, false, 0) ) + { + kdDebug(28000) << "Wrn: Directory <" << dir << "> does not exist -> try to create !" << endl; + // if( mkdir( QFile::encodeName( dir ), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH ) != 0 ) + if( KIO::mkdir( KURL(dir))) + { + KMessageBox::sorry(0, i18n("The folder\n%1\n does not exist and could not be created;\n" + "please check the permissions.").arg(dir)); + } + } +#if 0 + if( ! fi.isWritable() ) + { + KMessageBox::sorry(0, i18n("The directory\n%1\n is not writeable;\nplease check the permissions.") + .arg(dir)); + } +#endif +} + +/** + * This function asks the user for a filename or creates + * one by itself, depending on the settings + **/ +ImgSaveStat ImgSaver::saveImage( QImage *image ) +{ + ImgSaveStat stat; + picType imgType; + + if( !image ) return( ISS_ERR_PARAM ); + + /* Find out what kind of image it is */ + if( image->depth() > 8 ) + { + imgType = PT_HICOLOR_IMAGE; + } + else + { + if( image->depth() == 1 || image->numColors() == 2 ) + { + kdDebug(28000) << "This is black And White!" << endl; + imgType = PT_BW_IMAGE; + } + else + { + imgType = PT_COLOR_IMAGE; + if( image->allGray() ) + { + imgType = PT_GRAY_IMAGE; + } + } + } + + + QString format = findFormat( imgType ); + QString subformat = findSubFormat( format ); + // Call save-Function with this params + + if( format.isEmpty() ) + { + kdDebug(28000) << "Save canceled by user -> no save !" << endl; + return( ISS_SAVE_CANCELED ); + } + + kdDebug(28000) << "saveImage: Directory is " << directory << endl; + QString filename = createFilename( format ); + + KConfig *konf = KGlobal::config (); + konf->setGroup( OP_FILE_GROUP ); + + if( konf->readBoolEntry( OP_ASK_FILENAME, false ) ) + { + bool ok; + QString text = KInputDialog::getText( i18n( "Filename" ), i18n("Enter filename:"), + filename, &ok ); + + if(ok) + { + filename = text; + } + } + + QString fi = directory + "/" + filename; + + if( extension(fi).isEmpty() ) + { + if( ! fi.endsWith( "." ) ) + { + fi+= "."; + } + fi+=format.lower(); + } + + + kdDebug(28000) << "saveImage: saving file <" << fi << ">" << endl; + stat = save( image, fi, format, subformat ); + + return( stat ); + +} + +/** + * This member creates a filename for the image to save. + * This is done by numbering all existing files and adding + * one + **/ +QString ImgSaver::createFilename( QString format ) +{ + if( format.isNull() || format.isEmpty() ) return( 0 ); + + QString s = "kscan_*." + format.lower(); + QDir files( directory, s ); + long c = 1; + + QString num; + num.setNum(c); + QString fname = "kscan_" + num.rightJustify(4, '0') + "." + format.lower(); + + while( files.exists( fname ) ) { + num.setNum(++c); + fname = "kscan_" + num.rightJustify(4, '0') + "." + format.lower(); + } + + return( fname ); +} + +/** + * This function gets a filename from the parent. The filename must not be relative. + **/ +ImgSaveStat ImgSaver::saveImage( QImage *image, const KURL& filename, const QString& imgFormat ) +{ + QString format = imgFormat; + + /* Check if the filename is local */ + if( !filename.isLocalFile()) + { + kdDebug(29000) << "ImgSaver: Can only save local image, sorry !" << endl; + return( ISS_ERR_PROTOCOL ); + } + + QString localFilename; + localFilename = filename.directory( false, true) + filename.fileName(); + + kdDebug(28000) << "saveImage: Saving "<< localFilename << " in format " << format << endl; + if( format.isEmpty() ) + format = "BMP"; + + return( save( image, localFilename, format, "" ) ); +} + + +/* + * findFormat does all the stuff with the dialog. + */ +QString ImgSaver::findFormat( picType type ) +{ + QString format; + KConfig *konf = KGlobal::config (); + konf->setGroup( OP_FILE_GROUP ); + + if( type == PT_THUMBNAIL ) + { + return( "BMP" ); + } + + // real images + switch( type ) + { + case PT_THUMBNAIL: + format = konf->readEntry( OP_FORMAT_THUMBNAIL, "BMP" ); + kdDebug( 28000) << "Format for Thumbnails: " << format << endl; + break; + case PT_PREVIEW: + format = konf->readEntry( OP_PREVIEW_FORMAT, "BMP" ); + kdDebug( 28000) << "Format for Preview: " << format << endl; + break; + case PT_COLOR_IMAGE: + format = konf->readEntry( OP_FORMAT_COLOR, "nothing" ); + kdDebug( 28000 ) << "Format for Color: " << format << endl; + break; + case PT_GRAY_IMAGE: + format = konf->readEntry( OP_FORMAT_GRAY, "nothing" ); + kdDebug( 28000 ) << "Format for Gray: " << format << endl; + break; + case PT_BW_IMAGE: + format = konf->readEntry( OP_FORMAT_BW, "nothing" ); + kdDebug( 28000 ) << "Format for BlackAndWhite: " << format << endl; + break; + case PT_HICOLOR_IMAGE: + format = konf->readEntry( OP_FORMAT_HICOLOR, "nothing" ); + kdDebug( 28000 ) << "Format for HiColorImage: " << format << endl; + break; + default: + format = "nothing"; + kdDebug( 28000 ) << "ERR: Could not find image type !" << endl; + + break; + } + + if( type != PT_PREVIEW ) /* Use always bmp-Default for preview scans */ + { + if( format == "nothing" || ask_for_format ) + { + format = startFormatDialog( type ); + } + } + return( format ); + +} + +QString ImgSaver::picTypeAsString( picType type ) const +{ + QString res; + + switch( type ) + { + case PT_COLOR_IMAGE: + res = i18n( "palleted color image (16 or 24 bit depth)" ); + break; + case PT_GRAY_IMAGE: + res = i18n( "palleted gray scale image (16 bit depth)" ); + break; + case PT_BW_IMAGE: + res = i18n( "lineart image (black and white, 1 bit depth)" ); + break; + case PT_HICOLOR_IMAGE: + res = i18n( "high (or true-) color image, not palleted" ); + break; + default: + res = i18n( "Unknown image type" ); + break; + } + return( res ); +} + + +QString ImgSaver::startFormatDialog( picType type) +{ + + FormatDialog fd( 0, picTypeAsString( type ), "FormatDialog" ); + + // set default values + if( type != PT_PREVIEW ) + { + QString defFormat = getFormatForType( type ); + fd.setSelectedFormat( defFormat ); + } + + QString format; + if( fd.exec() ) + { + format = fd.getFormat(); + kdDebug(28000) << "Storing to format <" << format << ">" << endl; + bool ask = fd.askForFormat(); + kdDebug(28000)<< "Store askFor is " << ask << endl; + storeFormatForType( type, format, ask ); + subformat = fd.getSubFormat(); + } + return( format ); +} + + +/* + * This method returns true if the image format given in format is remembered + * for that image type. + */ +bool ImgSaver::isRememberedFormat( picType type, QString format ) const +{ + if( getFormatForType( type ) == format ) + { + return( true ); + } + else + { + return( false ); + } + +} + + + + +QString ImgSaver::getFormatForType( picType type ) const +{ + KConfig *konf = KGlobal::config (); + Q_CHECK_PTR( konf ); + konf->setGroup( OP_FILE_GROUP ); + + QString f; + + switch( type ) + { + case PT_COLOR_IMAGE: + f = konf->readEntry( OP_FORMAT_COLOR, "BMP" ); + break; + case PT_GRAY_IMAGE: + f = konf->readEntry( OP_FORMAT_GRAY, "BMP" ); + break; + case PT_BW_IMAGE: + f = konf->readEntry( OP_FORMAT_BW, "BMP" ); + break; + case PT_HICOLOR_IMAGE: + f = konf->readEntry( OP_FORMAT_HICOLOR, "BMP" ); + break; + default: + f = "BMP"; + break; + } + return( f ); +} + + +void ImgSaver::storeFormatForType( picType type, QString format, bool ask ) +{ + KConfig *konf = KGlobal::config (); + Q_CHECK_PTR( konf ); + konf->setGroup( OP_FILE_GROUP ); + + konf->writeEntry( OP_FILE_ASK_FORMAT, ask ); + ask_for_format = ask; + + switch( type ) + { + case PT_COLOR_IMAGE: + konf->writeEntry( OP_FORMAT_COLOR, format ); + break; + case PT_GRAY_IMAGE: + konf->writeEntry( OP_FORMAT_GRAY, format ); + break; + case PT_BW_IMAGE: + konf->writeEntry( OP_FORMAT_BW, format ); + break; + case PT_HICOLOR_IMAGE: + konf->writeEntry( OP_FORMAT_HICOLOR, format ); + break; + default: + kdDebug(28000) << "Wrong Type - cant store format setting" << endl; + break; + } + konf->sync(); +} + + +QString ImgSaver::findSubFormat( QString format ) +{ + kdDebug(28000) << "Searching Subformat for " << format << endl; + return( subformat ); + +} + +/** + private save() does the work to save the image. + the filename must be complete and local. +**/ +ImgSaveStat ImgSaver::save( QImage *image, const QString &filename, + const QString &format, + const QString &subformat ) +{ + + bool result = false; + kdDebug(28000) << "in ImgSaver::save: saving " << filename << endl; + if( ! format || !image ) + { + kdDebug(28000) << "ImgSaver ERROR: Wrong parameter Format <" << format << "> or image" << endl; + return( ISS_ERR_PARAM ); + } + + if( image ) + { + // remember the last processed file - only the filename - no path + QFileInfo fi( filename ); + QString dirPath = fi.dirPath(); + QDir dir = QDir( dirPath ); + + if( ! dir.exists() ) + { + /* The dir to save in always should exist, except in the first preview save */ + kdDebug(28000) << "Creating dir " << dirPath << endl; + if( !dir.mkdir( dirPath ) ) + { + kdDebug(28000) << "ERR: Could not create directory" << endl; + } + } + + if( fi.exists() && !fi.isWritable() ) + { + kdDebug(28000) << "Cant write to file <" << filename << ">, cant save !" << endl; + result = false; + return( ISS_ERR_PERM ); + } + + /* Check the format, is it writable ? */ +#ifdef USE_KIMAGEIO + if( ! KImageIO::canWrite( format ) ) + { + kdDebug(28000) << "Cant write format <" << format << ">" << endl; + result = false; + return( ISS_ERR_FORMAT_NO_WRITE ); + } +#endif + kdDebug(28000) << "ImgSaver: saving image to <" << filename << "> as <" << format << "/" << subformat <<">" << endl; + + result = image->save( filename, format.latin1() ); + + + last_file = fi.absFilePath(); + last_format = format.latin1(); + } + + if( result ) + return( ISS_OK ); + else { + last_file = ""; + last_format = ""; + return( ISS_ERR_UNKNOWN ); + } + +} + + +void ImgSaver::readConfig( void ) +{ + + KConfig *konf = KGlobal::config (); + Q_CHECK_PTR( konf ); + konf->setGroup( OP_FILE_GROUP ); + ask_for_format = konf->readBoolEntry( OP_FILE_ASK_FORMAT, true ); + + QDir home = QDir::home(); +} + + + + + +QString ImgSaver::errorString( ImgSaveStat stat ) +{ + QString re; + + switch( stat ) { + case ISS_OK: re = i18n( " image save OK " ); break; + case ISS_ERR_PERM: re = i18n( " permission error " ); break; + case ISS_ERR_FILENAME: re = i18n( " bad filename " ); break; + case ISS_ERR_NO_SPACE: re = i18n( " no space on device " ); break; + case ISS_ERR_FORMAT_NO_WRITE: re = i18n( " could not write image format " ); break; + case ISS_ERR_PROTOCOL: re = i18n( " can not write file using that protocol "); break; + case ISS_SAVE_CANCELED: re = i18n( " user canceled saving " ); break; + case ISS_ERR_UNKNOWN: re = i18n( " unknown error " ); break; + case ISS_ERR_PARAM: re = i18n( " parameter wrong " ); break; + + default: re = ""; + } + return( re ); + +} + +QString ImgSaver::extension( const KURL& url ) +{ + QString extension = url.fileName(); + + int dotPos = extension.findRev( '.' ); + if( dotPos > 0 ) + { + int len = extension.length(); + extension = extension.right( len - dotPos -1 ); + } + else + { + /* No extension was supplied */ + extension = QString(); + } + return extension; +} + + +bool ImgSaver::renameImage( const KURL& fromUrl, KURL& toUrl, bool askExt, QWidget *overWidget ) +{ + /* Check if the provided filename has a extension */ + QString extTo = extension( toUrl ); + QString extFrom = extension( fromUrl ); + KURL targetUrl( toUrl ); + + if( extTo.isEmpty() && !extFrom.isEmpty() ) + { + /* Ask if the extension should be added */ + int result = KMessageBox::Yes; + QString fName = toUrl.fileName(); + if( ! fName.endsWith( "." ) ) + { + fName += "."; + } + fName += extFrom; + + if( askExt ) + { + + QString s; + s = i18n("The filename you supplied has no file extension.\nShould the correct one be added automatically? "); + s += i18n( "That would result in the new filename: %1" ).arg( fName); + + result = KMessageBox::questionYesNo(overWidget, s, i18n( "Extension Missing"), + i18n("Add Extension"), i18n("Do Not Add"), + "AutoAddExtensions" ); + } + + if( result == KMessageBox::Yes ) + { + targetUrl.setFileName( fName ); + kdDebug(28000) << "Rename file to " << targetUrl.prettyURL() << endl; + } + } + else if( !extFrom.isEmpty() && extFrom != extTo ) + { + if( ! ((extFrom.lower() == "jpeg" && extTo.lower() == "jpg") || + (extFrom.lower() == "jpg" && extTo.lower() == "jpeg" ))) + { + /* extensions differ -> TODO */ + KMessageBox::error( overWidget, + i18n("Format changes of images are currently not supported."), + i18n("Wrong Extension Found" )); + return(false); + } + } + + bool success = false; + + if( KIO::NetAccess::exists( targetUrl, false,0 ) ) + { + kdDebug(28000)<< "Target already exists - can not copy" << endl; + } + else + { + if( KIO::file_move(fromUrl, targetUrl) ) + { + success = true; + } + } + return( success ); +} + + +QString ImgSaver::tempSaveImage( KookaImage *img, const QString& format, int colors ) +{ + + KTempFile *tmpFile = new KTempFile( QString(), "."+format.lower()); + tmpFile->setAutoDelete( false ); + tmpFile->close(); + + KookaImage tmpImg; + + if( colors != -1 && img->numColors() != colors ) + { + // Need to convert image + if( colors == 1 || colors == 8 || colors == 24 || colors == 32 ) + { + tmpImg = img->convertDepth( colors ); + img = &tmpImg; + } + else + { + kdDebug(29000) << "ERROR: Wrong color depth requested: " << colors << endl; + img = 0; + } + } + + QString name; + if( img ) + { + name = tmpFile->name(); + + if( ! img->save( name, format.latin1() ) ) name = QString(); + } + delete tmpFile; + return name; +} + +bool ImgSaver::copyImage( const KURL& fromUrl, const KURL& toUrl, QWidget *overWidget ) +{ + + /* Check if the provided filename has a extension */ + QString extTo = extension( toUrl ); + QString extFrom = extension( fromUrl ); + KURL targetUrl( toUrl ); + + if( extTo.isEmpty() && !extFrom.isEmpty()) + { + /* Ask if the extension should be added */ + int result = KMessageBox::Yes; + QString fName = toUrl.fileName(); + if( ! fName.endsWith( "." )) + fName += "."; + fName += extFrom; + + QString s; + s = i18n("The filename you supplied has no file extension.\nShould the correct one be added automatically? "); + s += i18n( "That would result in the new filename: %1" ).arg( fName); + + result = KMessageBox::questionYesNo(overWidget, s, i18n( "Extension Missing"), + i18n("Add Extension"), i18n("Do Not Add"), + "AutoAddExtensions" ); + + if( result == KMessageBox::Yes ) + { + targetUrl.setFileName( fName ); + } + } + else if( !extFrom.isEmpty() && extFrom != extTo ) + { + /* extensions differ -> TODO */ + if( ! ((extFrom.lower() == "jpeg" && extTo.lower() == "jpg") || + (extFrom.lower() == "jpg" && extTo.lower() == "jpeg" ))) + { + KMessageBox::error( overWidget, i18n("Format changes of images are currently not supported."), + i18n("Wrong Extension Found" )); + return(false); + } + } + + KIO::Job *copyjob = KIO::copy( fromUrl, targetUrl, false ); + + return( copyjob ? true : false ); +} + + +/* extension needs to be added */ + +#include "img_saver.moc" diff --git a/kooka/img_saver.h b/kooka/img_saver.h new file mode 100644 index 00000000..f9a29898 --- /dev/null +++ b/kooka/img_saver.h @@ -0,0 +1,208 @@ +/*************************************************************************** + img_saver.h - description + ------------------- + begin : Mon Dec 27 1999 + copyright : (C) 1999 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#ifndef __IMG_SAVER_H__ +#define __IMG_SAVER_H__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define OP_FILE_ASK_FORMAT "AskForSaveFormat" +#define OP_ASK_FILENAME "AskForFilename" +#define OP_FORMAT_HICOLOR "HiColorSaveFormat" +#define OP_FORMAT_COLOR "ColorSaveFormat" +#define OP_FORMAT_GRAY "GraySaveFormat" +#define OP_FORMAT_BW "BWSaveFormat" +#define OP_FORMAT_THUMBNAIL "ThumbnailFormat" +#define OP_PREVIEW_GROUP "ScanPreview" +#define OP_PREVIEW_FILE "PreviewFile" +#define OP_PREVIEW_FORMAT "PreviewFormat" +#define OP_FILE_GROUP "Files" + + +/** + * enum ImgSaveStat: + * Errorflags for the save. These enums are returned by the + * all image save operations and the calling object my display + * a human readable Error-Message on this information + **/ +typedef enum { + ISS_OK, /* Image save OK */ + ISS_ERR_PERM, /* permission Error */ + ISS_ERR_FILENAME, /* bad filename */ + ISS_ERR_NO_SPACE, /* no space on device */ + ISS_ERR_FORMAT_NO_WRITE, /* Image format can not be written */ + ISS_ERR_UNKNOWN, + ISS_ERR_PARAM, /* Parameter wrong */ + ISS_ERR_PROTOCOL, + ISS_SAVE_CANCELED + +} ImgSaveStat; + +/** + * enum picType: + * Specifies the type of the image to save. This is important for + * getting the format. + **/ +typedef enum { + PT_PREVIEW, + PT_THUMBNAIL, + PT_HICOLOR_IMAGE, + PT_COLOR_IMAGE, + PT_GRAY_IMAGE, + PT_BW_IMAGE, + PT_FINISHED +} picType; + + +class KookaImage; +/** + * Class FormatDialog: + * Asks the user for the image-Format and gives help for + * selecting it. + **/ + +class FormatDialog:public KDialogBase +{ + Q_OBJECT +public: + FormatDialog( QWidget *parent, const QString&, const char * ); + + + QString getFormat( ) const; + QCString getSubFormat( ) const; + QString errorString( ImgSaveStat stat ); + + bool askForFormat( ) const + { return( ! cbDontAsk->isChecked()); } + +public slots: + void setSelectedFormat( QString ); + + +protected slots: + void showHelp( const QString& item ); + +private: + + void check_subformat( const QString & format ); + void buildHelp( void ); + void readConfig( void ); + + QMap format_help; + QComboBox *cb_subf; + QListBox *lb_format; + QLabel *l_help; + QLabel *l2; + QCheckBox *cbRemember; + QCheckBox *cbDontAsk; +}; + +/** + * Class ImgSaver: + * The main class of this module. It manages all saving of images + * in kooka + * It asks the user for the img-format if desired, creates thumbnails + * and cares for database entries (later ;) + **/ + +class ImgSaver:public QObject { + Q_OBJECT +public: + /** + * constructor of the image-saver object. + * name is the name of a subdirectory of the save directory, + * which can be given in dir. If no dir is given, an + * dir ~/.ksane is created. + * @param dir Name of the save root directory + * @param name Name of a subdirectory in the saveroot. + **/ + ImgSaver( QWidget *parent, const KURL ); + ImgSaver( QWidget *parent ); + + QString errorString( ImgSaveStat ); + /** + * returns the name of the last file that was saved by ImgSaver. + */ + QString lastFilename() const { return( last_file ); } + KURL lastFileUrl() const { return( KURL(last_file )); } + /** + * returns the image format of the last saved image. + */ + QCString lastSaveFormat( void ) const { return( last_format ); } + + QString getFormatForType( picType ) const; + void storeFormatForType( picType, QString, bool ); + bool isRememberedFormat( picType type, QString format ) const; + + /* static function that exports a file */ + static bool copyImage( const KURL& fromUrl, const KURL& toUrl, QWidget *overWidget=0 ); + static bool renameImage( const KURL& fromUrl, KURL& toUrl, bool askExt=false, QWidget *overWidget=0 ); + static QString tempSaveImage( KookaImage *img, const QString& format, int colors = -1 ); + + /* static function that returns the extension of an url */ + static QString extension( const KURL& ); + +public slots: + ImgSaveStat saveImage( QImage *image ); + ImgSaveStat saveImage( QImage *image, const KURL& filename, const QString& imgFormat ); + +private: + QString picTypeAsString( picType type ) const; + QString findFormat( picType type ); + QString findSubFormat( QString format ); + void createDir( const QString& ); + + ImgSaveStat save( QImage *image, const QString &filename, const QString &format, + const QString &subformat ); + QString createFilename( QString format ); + void readConfig( void ); + QString startFormatDialog( picType ); + + // QStrList all_formats; + QString directory; // dir where the image should be saved + QString last_file; + QCString subformat; + QCString last_format; + bool ask_for_format; + + // QDict formats; +}; + +#endif diff --git a/kooka/imgnamecombo.cpp b/kooka/imgnamecombo.cpp new file mode 100644 index 00000000..77b59a0d --- /dev/null +++ b/kooka/imgnamecombo.cpp @@ -0,0 +1,93 @@ +/*************************************************************************** + imgnamecombo.cpp - combobox for image names + ------------------- + begin : Tue Nov 13 2001 + copyright : (C) 2001 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#include +#include +#include + +#include + +#include +#include +#include + +#include "imgnamecombo.h" +#include "img_saver.h" + +ImageNameCombo::ImageNameCombo( QWidget *parent ) + : KComboBox( parent ) +{ + setInsertionPolicy( QComboBox::AtTop ); +} + +ImageNameCombo::~ImageNameCombo() +{ + +} + +void ImageNameCombo::slotPathRemove( KFileTreeBranch *branch, const QString& relPath ) +{ + QString path = branch->name() + QString::fromLatin1(" - ") + relPath; + + kdDebug(28000) << "ImageNameCombo: Removing " << path << endl; + QString select = currentText(); + + if( items.contains( path )) + { + kdDebug(28000) << "ImageNameCombo: Item exists-> deleting" << endl; + items.remove( path ); + } + + /* */ + rewriteList( branch, select ); +} + +void ImageNameCombo::rewriteList( KFileTreeBranch *branch, const QString& selText ) +{ + clear(); + for ( QStringList::Iterator it = items.begin(); it != items.end(); ++it ) + { + insertItem( branch->pixmap(), *it ); + } + + int index = items.findIndex( selText ); + setCurrentItem( index ); +} + +void ImageNameCombo::slotGalleryPathChanged( KFileTreeBranch* branch, const QString& relativPath ) +{ + QString newPath; + + newPath = branch->name() + QString::fromLatin1(" - ") + relativPath; + + kdDebug( 28000) << "Inserting " << newPath << " to combobox" << endl; + + setCurrentItem( newPath, true /* insert if missing */ ); +} + +/* The End */ +#include "imgnamecombo.moc" diff --git a/kooka/imgnamecombo.h b/kooka/imgnamecombo.h new file mode 100644 index 00000000..a577929e --- /dev/null +++ b/kooka/imgnamecombo.h @@ -0,0 +1,57 @@ +/*************************************************************************** + imgnamecombo.h - combobox for image names + ------------------- + begin : Tue Nov 13 2001 + copyright : (C) 2001 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + + +#ifndef IMGNAMECOMBO_H +#define IMGNAMECOMBO_H + + +#include + +/** + *@author Klaas Freitag +*/ + +class QListViewItem; +class KFileBranch; + +class ImageNameCombo: public KComboBox +{ + Q_OBJECT +public: + ImageNameCombo( QWidget* ); + ~ImageNameCombo(); + +public slots: + + void slotGalleryPathChanged( KFileTreeBranch* branch, const QString& relativPath ); + void slotPathRemove( KFileTreeBranch *branch, const QString& relPath ); +private: + void rewriteList( KFileTreeBranch *, const QString& selText ); + QStringList items; +}; + +#endif diff --git a/kooka/imgprintdialog.cpp b/kooka/imgprintdialog.cpp new file mode 100644 index 00000000..f9aa3930 --- /dev/null +++ b/kooka/imgprintdialog.cpp @@ -0,0 +1,302 @@ +/*************************************************************************** + imgprintdialog.h - Kooka's Image Printing + ------------------- + begin : May 2003 + copyright : (C) 1999 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ +#include "imgprintdialog.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "kookaimage.h" +#include +#include +#include +#include +#include + +#define ID_SCREEN 0 +#define ID_ORIG 1 +#define ID_CUSTOM 2 +#define ID_FIT_PAGE 3 + +ImgPrintDialog::ImgPrintDialog( KookaImage *img, QWidget *parent, const char* name ) + : KPrintDialogPage( parent, name ), + m_image(img), + m_ignoreSignal(false) +{ + setTitle(i18n("Image Printing")); + QVBoxLayout *layout = new QVBoxLayout( this ); + // layout->setMargin( KDialog::marginHint() ); + // layout->setSpacing( KDialog::spacingHint() ); + + m_scaleRadios = new QButtonGroup( 2, Qt::Vertical, i18n("Image Print Size"), this ); + m_scaleRadios->setRadioButtonExclusive(true); + connect( m_scaleRadios, SIGNAL(clicked(int)), SLOT(slScaleChanged(int))); + + m_rbScreen = new QRadioButton( i18n("Scale to same size as on screen"), + m_scaleRadios ); + QToolTip::add( m_rbScreen, i18n("Screen scaling. That prints according to the screen resolution.")); + + m_scaleRadios->insert( m_rbScreen, ID_SCREEN ); + + m_rbOrigSize = new QRadioButton( i18n("Original size (calculate from scan resolution)"), + m_scaleRadios ); + QToolTip::add( m_rbOrigSize, + i18n("Calculates the print size from the scan resolution. Enter the scan resolution in the dialog field below." )); + m_scaleRadios->insert( m_rbOrigSize, ID_ORIG ); + + + m_rbScale = new QRadioButton( i18n("Scale image to custom dimension"), m_scaleRadios ); + QToolTip::add( m_rbScale, + i18n("Set the print size yourself in the dialog below. The image is centered on the paper.")); + + m_scaleRadios->insert( m_rbScale, ID_CUSTOM ); + + m_rbFitPage = new QRadioButton( i18n("Scale image to fit to page"), m_scaleRadios ); + QToolTip::add( m_rbFitPage, i18n("Printout uses maximum space on the selected pager. Aspect ratio is maintained.")); + m_scaleRadios->insert( m_rbFitPage, ID_FIT_PAGE ); + + layout->addWidget( m_scaleRadios ); + + + QHBoxLayout *hbox = new QHBoxLayout( this ); + layout->addLayout( hbox ); + + /** Box for Image Resolutions **/ + QVGroupBox *group1 = new QVGroupBox( i18n("Resolutions"), this ); + hbox->addWidget( group1 ); + + /* Postscript generation resolution */ + m_psDraft = new QCheckBox( i18n("Generate low resolution PostScript (fast draft print)"), + group1, "cbPostScriptRes" ); + m_psDraft->setChecked( false ); + + + /* Scan resolution of the image */ + m_dpi = new KIntNumInput( group1 ); + m_dpi->setLabel( i18n("Scan resolution (dpi) " ), AlignVCenter ); + m_dpi->setValue( 300 ); + m_dpi->setSuffix( i18n(" dpi")); + + /* Label for displaying the screen Resolution */ + m_screenRes = new QLabel( group1 ); + + /** Box for Image Print Size **/ + QVGroupBox *group = new QVGroupBox( i18n("Image Print Size"), this ); + hbox->addWidget( group ); + + m_sizeW = new KIntNumInput( group ); + m_sizeW->setLabel( i18n("Image width:"), AlignVCenter ); + m_sizeW->setSuffix( i18n(" mm")); + connect( m_sizeW, SIGNAL(valueChanged(int)), SLOT(slCustomWidthChanged(int))); + m_sizeH = new KIntNumInput( m_sizeW, AlignVCenter, group ); + m_sizeH->setLabel( i18n("Image height:"), AlignVCenter); + m_sizeH->setSuffix( i18n(" mm")); + connect( m_sizeH, SIGNAL(valueChanged(int)), SLOT(slCustomHeightChanged(int))); + + m_ratio = new QCheckBox( i18n("Maintain aspect ratio"), group, "cbAspectRatio" ); + m_ratio->setChecked(true); + + + QWidget *spaceEater = new QWidget( this ); + spaceEater->setSizePolicy( QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored )); + layout->addWidget( spaceEater ); + + /* Set start values */ + m_rbScreen->setChecked(true); + slScaleChanged( ID_SCREEN ); +} + +void ImgPrintDialog::setImage( KookaImage *img ) +{ + if( ! img ) return; + + // TODO: get scan resolution out of the image + +} + +void ImgPrintDialog::setOptions(const QMap& opts) +{ + // m_autofit->setChecked(opts["app-img-autofit"] == "1"); + QString scale = opts[OPT_SCALING]; + + kdDebug(28000) << "In setOption" << endl; + + if( scale == "scan" ) + m_rbOrigSize->setChecked(true); + else if( scale == "custom" ) + m_rbScale->setChecked(true); + else + m_rbScreen->setChecked(true); + + int help = opts[OPT_SCAN_RES].toInt(); + m_dpi->setValue( help ); + + help = opts[OPT_WIDTH].toInt(); + m_sizeW->setValue( help ); + + help = opts[OPT_HEIGHT].toInt(); + m_sizeH->setValue( help ); + + help = opts[OPT_SCREEN_RES].toInt(); + m_screenRes->setText(i18n( "Screen resolution: %1 dpi").arg(help)); + + help = opts[OPT_PSGEN_DRAFT].toInt(); + m_psDraft->setChecked( help == 1 ); + + help = opts[OPT_RATIO].toInt(); + m_ratio->setChecked( help == 1 ); + +} + + +void ImgPrintDialog::getOptions(QMap& opts, bool ) +{ + // TODO: Check for meaning of include_def ! + // kdDebug(28000) << "In getOption with include_def: " << include_def << endl; + + QString scale = "screen"; + if( m_rbOrigSize->isChecked() ) + scale = "scan"; + else if( m_rbScale->isChecked() ) + scale = "custom"; + else if( m_rbFitPage->isChecked() ) + scale = "fitpage"; + + opts[OPT_SCALING] = scale; + + opts[OPT_SCAN_RES] = QString::number( m_dpi->value() ); + opts[OPT_WIDTH] = QString::number( m_sizeW->value() ); + opts[OPT_HEIGHT] = QString::number( m_sizeH->value() ); + opts[OPT_PSGEN_DRAFT] = QString::number( m_psDraft->isChecked() ); + opts[OPT_RATIO] = QString::number( m_ratio->isChecked() ); + + { + QPaintDeviceMetrics metric( this ); + opts[OPT_SCREEN_RES] = QString::number( metric.logicalDpiX()); + } +} + +bool ImgPrintDialog::isValid(QString& msg) +{ + /* check if scan reso is higher than 0 in case its needed */ + int id = m_scaleRadios->id( m_scaleRadios->selected()); + if( id == ID_ORIG && m_dpi->value() == 0 ) + { + msg = i18n("Please specify a scan resolution larger than 0"); + return false; + } + else if( id == ID_CUSTOM && (m_sizeW->value() == 0 || m_sizeH->value() == 0 ) ) + { + msg = i18n("For custom printing, a valid size should be specified.\n" + "At least one dimension is zero."); + } + + return true; +} + +void ImgPrintDialog::slScaleChanged( int id ) +{ + if( id == ID_SCREEN ) + { + /* disalbe size, scan res. */ + m_dpi->setEnabled(false); + m_ratio->setEnabled(false); + m_sizeW->setEnabled(false); + m_sizeH->setEnabled(false); + } + else if( id == ID_ORIG ) + { + /* disable size */ + m_dpi->setEnabled(true); + m_ratio->setEnabled(false); + m_sizeW->setEnabled(false); + m_sizeH->setEnabled(false); + } + else if( id == ID_CUSTOM ) + { + m_dpi->setEnabled(false); + m_ratio->setEnabled(true); + m_sizeW->setEnabled(true); + m_sizeH->setEnabled(true); + } + else if( id == ID_FIT_PAGE ) + { + m_dpi->setEnabled(false); + m_ratio->setEnabled(true); + m_sizeW->setEnabled(false); + m_sizeH->setEnabled(false); + } +} + +void ImgPrintDialog::slCustomWidthChanged( int val ) +{ + if( m_ignoreSignal ) + { + m_ignoreSignal = false; + return; + } + + /* go out here if scaling is not custom */ + if( m_scaleRadios->id( m_scaleRadios->selected()) != ID_CUSTOM ) return; + + /* go out here if maintain aspect ration is off */ + if( ! m_ratio->isChecked() ) return; + + m_ignoreSignal = true; + kdDebug(28000) << "Setting value to horizontal size" << endl; + m_sizeH->setValue( int( double(val) * + double(m_image->height())/double(m_image->width()) ) ); + +} + +void ImgPrintDialog::slCustomHeightChanged( int val ) +{ + if( m_ignoreSignal ) + { + m_ignoreSignal = false; + return; + } + + /* go out here if scaling is not custom */ + if( m_scaleRadios->id( m_scaleRadios->selected()) != ID_CUSTOM ) return; + + /* go out here if maintain aspect ration is off */ + if( ! m_ratio->isChecked() ) return; + + m_ignoreSignal = true; + kdDebug(28000) << "Setting value to vertical size" << endl; + m_sizeW->setValue( int( double(val) * + double(m_image->width())/double(m_image->height()) ) ); + +} + +#include "imgprintdialog.moc" diff --git a/kooka/imgprintdialog.h b/kooka/imgprintdialog.h new file mode 100644 index 00000000..845cc038 --- /dev/null +++ b/kooka/imgprintdialog.h @@ -0,0 +1,89 @@ +/*************************************************************************** + imgprintdialog.h - Kooka's Image Printing + ------------------- + begin : May 2003 + copyright : (C) 1999 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#ifndef __IMGPRINTDIALOG_H__ +#define __IMGPRINTDIALOG_H__ + +#include +#include +#include + +#include "kookaimage.h" + +#define OPT_SCALING "kde-kooka-scaling" +#define OPT_SCAN_RES "kde-kooka-scanres" +#define OPT_SCREEN_RES "kde-kooka-screenres" +#define OPT_WIDTH "kde-kooka-width" +#define OPT_HEIGHT "kde-kooka-height" +#define OPT_PSGEN_DRAFT "kde-kooka-psdraft" +#define OPT_RATIO "kde-kooka-ratio" +#define OPT_FITPAGE "kde-kooka-fitpage" +class QWidget; +class QString; +class QLabel; +class KIntNumInput; +class KookaImage; +class QVButtonGroup; +class QRadioButton; +class QCheckBox; + +class ImgPrintDialog: public KPrintDialogPage +{ + Q_OBJECT +public: + ImgPrintDialog( KookaImage *img, QWidget *parent=0L, const char* name=0L ); + + void setOptions(const QMap& opts); + void getOptions(QMap& opts, bool include_def = false); + bool isValid(QString& msg); + + void setImage( KookaImage *img ); + +protected slots: + void slScaleChanged( int id ); + void slCustomWidthChanged(int); + void slCustomHeightChanged(int); + +private: + QButtonGroup *m_scaleRadios; + QRadioButton *m_rbOrigSize; + QRadioButton *m_rbScale; + QRadioButton *m_rbScreen; + QRadioButton *m_rbFitPage; + + KIntNumInput *m_sizeW; + KIntNumInput *m_sizeH; + KIntNumInput *m_dpi; + + QCheckBox *m_psDraft; + QCheckBox *m_ratio; + + KookaImage *m_image; + QLabel *m_screenRes; + bool m_ignoreSignal; +}; + +#endif diff --git a/kooka/kadmosocr.cpp b/kooka/kadmosocr.cpp new file mode 100644 index 00000000..72f9324b --- /dev/null +++ b/kooka/kadmosocr.cpp @@ -0,0 +1,432 @@ +/*************************************************************************** + kadmosocr.cpp - Kadmos cpp interface + ------------------- + begin : Fri Jun 30 2000 + + (c) 2002 re Recognition AG Hafenstrasse 50b CH-8280 Kreuzlingen + Switzerland Phone: +41 (0)71 6780000 Fax: +41 (0)71 6780099 + Website: www.reRecognition.com E-mail: info@reRecognition.com + + Author: Tamas Nagy (nagy@rerecognition.com) + Klaas Freitag + Heike Stuerzenhofecker + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +/* Kadmos CPP object oriented interface */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "kadmosocr.h" +#include "ocrword.h" + +#ifdef HAVE_KADMOS + +using namespace Kadmos; + +/* -------------------- CRep -------------------- */ +CRep::CRep() + :QObject() +{ + memset(&m_RepData, 0, sizeof(m_RepData)); + m_Error = RE_SUCCESS; + m_undetectChar = QChar('_'); +} + +CRep::~CRep() +{ +} + +RelGraph* CRep::getGraphKnode(int line, int offset ) +{ + Kadmos::RepResult *res = getRepResult(line); + if( res ) + return ( &(getRepResult(line)->rel_graph[0])+offset); + else + return 0L; + +} + + +RepResult* CRep::getRepResult(int line) +{ + if( line<0 || line >= m_RepData.rep_result_len ) return 0L; + return &(m_RepData.rep_result[line]); +} + +RelResult* CRep::getRelResult(int line, RelGraph* graph, int alternative) +{ + if( ! ( graph && getRepResult(line))) return 0L; + int offset = graph->result_number[alternative]; + return( &(getRepResult(line)->rel_result[0]) + offset ); +} + + +KADMOS_ERROR CRep::Init(const char* ClassifierFilename) +{ + /* prepare RepData structure */ + m_RepData.init.rel_grid_maxlen = GRID_MAX_LEN; + m_RepData.init.rel_graph_maxlen = GRAPH_MAX_LEN; + m_RepData.init.rel_result_maxlen = CHAR_MAX_LEN; + m_RepData.init.rep_memory_size = LINE_MAX_LEN * sizeof(RepResult) + + (long)LINE_MAX_LEN * CHAR_MAX_LEN * (sizeof(RelGraph)+ + sizeof(RelResult)); + m_RepData.init.rep_memory = malloc( m_RepData.init.rep_memory_size ); + if (!m_RepData.init.rep_memory) { + CheckError(); + return m_Error; + } + strcpy(m_RepData.init.version, INC_KADMOS); + + m_Error = rep_init(&m_RepData, (char*)ClassifierFilename); + CheckError(); + return m_Error; +} + +void CRep::run() // KADMOS_ERROR CRep::Recognize() +{ + kdDebug(28000) << "ooo Locked and ocr!" << endl; + m_Error = rep_do(&m_RepData); + CheckError(); +} + +KADMOS_ERROR CRep::End() +{ + m_Error = rep_end(&m_RepData); + CheckError(); + return m_Error; +} + +int CRep::GetMaxLine() +{ + return m_RepData.rep_result_len; +} + +const char* CRep::RepTextLine(int nLine, unsigned char RejectLevel, int RejectChar, long Format) +{ + m_Error = rep_textline(&m_RepData, nLine, m_Line, + 2*CHAR_MAX_LEN, RejectLevel, RejectChar, Format); + CheckError(); + return m_Line; +} + +/** + * This method handles the given line. It takes repRes and goes through the + * kadmos result tree structures recursivly. + */ +ocrWordList CRep::getLineWords( int line ) +{ + ocrWordList repWords; + bool ok = true; + + Kadmos::RepResult *repRes = getRepResult(line); + + if( ! repRes ) + { + kdDebug(28000) << "repRes-Pointer is null" << endl; + ok = false; + } + + if( ok ) + { + int nextKnode=0; + + do + { + QString resultWord; + QRect boundingRect; + + int newNextKnode = nextBestWord( line, nextKnode, resultWord, boundingRect ); + boundingRect.moveBy( repRes->left, repRes->top ); + + ocrWord newWord; + newWord = resultWord; + newWord.setKnode(nextKnode); + newWord.setLine(line); + newWord.setRect(boundingRect); + repWords.push_back(newWord); + + /* set nextKnode to the next Knode */ + nextKnode = newNextKnode; + + + // Alternativen: + // partStrings( line, nextKnode, QString()); // fills m_parts - list with alternative words + // nextKnode = newNextKnode; + // kdDebug(28000) << "NextKnodeWord: " << resultWord << endl; + } + while( nextKnode > 0 ); + } + return repWords; +} + + +/* This fills theWord with the next best word and returns the + * next knode or 0 if there is no next node + */ +int CRep::nextBestWord( int line, int knode, QString& theWord, QRect& brect ) +{ + + Kadmos::RelGraph *relg = getGraphKnode( line, knode ); + // kdDebug(28000) << "GraphKnode is " << knode << endl; + int nextKnode = knode; + + while( relg ) + { + Kadmos::RelResult *relr = getRelResult( line, relg, 0 ); // best alternative + if( relr ) + { + // kdDebug(28000) << "Leading Blanks: " << relg->leading_blanks << + // " und Knode " << knode << endl; + char c = relr->rec_char[0][0]; + QChar newChar = c; + if( c == 0 ) + { + kdDebug(28000) << "Undetected char found !" << endl; + newChar = m_undetectChar; + } + + if ( (nextKnode != knode) && (relg->leading_blanks > 0)) + { + /* this means the word ends here. */ + // kdDebug(28000) << "----" << theWord << endl; + relg = 0L; /* Leave the loop. */ + } + else + { + /* append the character */ + theWord.append(newChar); + + /* save the bounding rect */ + // kdDebug(28000) << "LEFT: " << relr->left << " TOP: " << relr->top << endl; + QRect r( relr->left, relr->top, relr->width, relr->height ); + + if( brect.isNull() ) + { + brect = r; + } + else + { + brect = brect.unite( r ); + } + + /* next knode */ + if( relg->next[0] > 0 ) + { + nextKnode = relg->next[0]; + relg = getGraphKnode( line, nextKnode ); + } + else + { + /* end of the line */ + nextKnode = 0; + relg = 0L; + } + } + } + } + return( nextKnode ); +} + + + +void CRep::partStrings( int line, int graphKnode, QString soFar ) +{ + /* The following knodes after a word break */ + Kadmos::RelGraph *relg = getGraphKnode( line, graphKnode ); + // kdDebug(28000) << "GraphKnode is " << graphKnode << endl; + + QString theWord=""; + for( int resNo=0; resNo < SEG_ALT; resNo++ ) + { + // kdDebug(28000) << "Alternative " << resNo << " is " << relg->result_number[resNo] << endl; + if( relg->result_number[resNo] == -1 ) + { + /* This means that there is no other alternative. Go out here. */ + break; + } + + Kadmos::RelResult *relr = getRelResult( line, relg, resNo ); + theWord = QChar(relr->rec_char[0][0]); + + if ( !soFar.isEmpty() && relg->leading_blanks ) + { + /* this means the previous words end. */ + // TODO: This forgets the alternatives of _this_ first character of the new word. + + kdDebug(28000) << "---- " << soFar << endl; + m_parts << soFar; + break; + } + else + { + /* make a QString from this single char and append it. */ + soFar += theWord; + } + + if( relg->next[resNo] > 0 ) + { + /* There is a follower to this knode. Combine the result list from a recursive call + * to this function with the follower knode. + */ + partStrings( line, relg->next[resNo], soFar ); + } + else + { + /* There is no follower */ + kdDebug(28000) << "No followers - theWord is " << soFar << endl; + m_parts<bits(); + m_RepData.image.imgtype = IMGTYPE_PIXELARRAY; + m_RepData.image.width = Image->width(); + m_RepData.image.height = Image->height(); + m_RepData.image.bitsperpixel = Image->depth(); + m_RepData.image.alignment = 1; + m_RepData.image.fillorder = FILLORDER_MSB2LSB; + // color + if( Image->depth() == 1 || (Image->numColors()==2 && Image->depth() == 8) ) + { + m_RepData.image.color=COLOR_BINARY; + kdDebug(28000) << "Setting Binary" << endl; + } else if( Image->isGrayscale() ) { + m_RepData.image.color = COLOR_GRAY; + kdDebug(28000) << "Setting GRAY" << endl; + + } else { + m_RepData.image.color = COLOR_RGB; + kdDebug(28000) << "Setting Color RGB" << endl; + } + // orientation + m_RepData.image.orientation = ORIENTATION_TOPLEFT; + m_RepData.image.photometric = PHOTOMETRIC_MINISWHITE; + m_RepData.image.resunit = RESUNIT_INCH; + m_RepData.image.xresolution = 200; + m_RepData.image.yresolution = 200; + + CheckError(); + + return RE_SUCCESS; +} + +void CRep::SetNoiseReduction(bool bNoiseReduction) +{ + if (bNoiseReduction) { + m_RepData.parm.prep |= PREP_AUTO_NOISEREDUCTION; + } + else { + m_RepData.parm.prep &= !PREP_AUTO_NOISEREDUCTION; + } +} + +void CRep::SetScaling(bool bScaling) +{ + if (bScaling) { + m_RepData.parm.prep |= PREP_SCALING; + } + else { + m_RepData.parm.prep &= !PREP_SCALING; + } +} + +void CRep::CheckError() +{ + if ( kadmosError() ) + { + kdDebug(28000) << "KADMOS ERROR: " << getErrorText() << endl; + } +} + +/* returns a QString containing the string describing the kadmos error */ +QString CRep::getErrorText() const +{ + re_ErrorText Err; + re_GetErrorText(&Err); + return QString::fromLocal8Bit( Err.text ); +} + +bool CRep::kadmosError() +{ + return m_Error != RE_SUCCESS; +} + +#include "kadmosocr.moc" + +#endif /* HAVE_KADMOS */ + + +// } /* End of Kadmos namespace */ diff --git a/kooka/kadmosocr.h b/kooka/kadmosocr.h new file mode 100644 index 00000000..12056209 --- /dev/null +++ b/kooka/kadmosocr.h @@ -0,0 +1,143 @@ +/*************************************************************************** + kadmosocr.h - Kadmos cpp interface + ------------------- + begin : Fri Jun 30 2000 + + (c) 2002 re Recognition AG Hafenstrasse 50b CH-8280 Kreuzlingen + Switzerland Phone: +41 (0)71 6780000 Fax: +41 (0)71 6780099 + Website: www.reRecognition.com E-mail: info@reRecognition.com + + Author: Tamas Nagy (nagy@rerecognition.com) + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#ifndef __KADMOS_OCR_ +#define __KADMOS_OCR_ + +#include +#include + +#include "config.h" + +#ifdef HAVE_KADMOS +/* class declarations */ +class QImage; +class QPixmap; +class QColor; +class QStringList; +class QRect; + + +class ocrWord; +class ocrWordList; + +namespace Kadmos { + +/* include files */ + +#include "kadmos.h" +#include + +/* ---------------------------------------- REP ---------------------------------------- */ +//! Maximum number of lines in a paragraph + const int LINE_MAX_LEN = 100; + const int GRID_MAX_LEN = 50; //!< Maximum number of grid elements in a line + const int GRAPH_MAX_LEN = 500; //!< Maximum number of graph elements in a line + const int CHAR_MAX_LEN = 500; //!< Maximum number of characters in a line + + /* Error handling */ + const char CPP_ERROR[] = "Kadmos CPP interface error"; + + /* ==== CRep ========================================= */ + class CRep : public QObject + { + Q_OBJECT + public: + CRep(); + virtual ~CRep(); + + RepResult* getRepResult(int line=0); + RelGraph* getGraphKnode(int line, int offset=0); + RelResult* getRelResult(int line, Kadmos::RelGraph* graph, int alternative=0); + + + /** + @param ClassifierFilename is a name of a classifier file (*.rec) + */ + KADMOS_ERROR Init(const char* ClassifierFile); + + virtual void run(); + virtual bool finished() { return true; } + // KADMOS_ERROR Recognize(); + KADMOS_ERROR End(); + + /** + @param Image is an image object + */ + KADMOS_ERROR SetImage(QImage* Image); + KADMOS_ERROR SetImage( const QString ); + int GetMaxLine(); + + ocrWordList getLineWords( int line ); + + const char* RepTextLine(int Line, unsigned char RejectLevel=128, + int RejectChar='~', long Format=TEXT_FORMAT_ANSI); + + void analyseLine(int, QPixmap* ); + /** Enable/disable noise reduction + @param TRUE(enable)/FALSE(disable) noise reduction + */ + void SetNoiseReduction(bool bNoiseReduction); + + /** Enable/disable scaling (size normalization) + @param TRUE(enable)/FALSE(disable) scaling (size normalization) + */ + void SetScaling(bool bScaling); + + /* draw graphic visualiser into the pixmap pointed to */ + virtual void drawLineBox( QPixmap*, const QRect& ); + virtual void drawCharBox( QPixmap*, const QRect& ); + virtual void drawBox( QPixmap*, const QRect&, const QColor& ); + + int nextBestWord( int line, int knode, QString& theWord, QRect& brect ); + + /* Error text in QString */ + QString getErrorText() const; + bool kadmosError(); + private: + void partStrings( int line, int graphKnode, QString soFar ); + void CheckError(); + + RepData m_RepData; + KADMOS_ERROR m_Error; + char m_Line[2*CHAR_MAX_LEN]; + int m_currLine; + QStringList m_parts; + QString m_theWord; + int m_recurse; + + QChar m_undetectChar; + }; + +} /* End of Kadmos namespace */ + +#endif /* HAVE KADMOS */ + +#endif /* header tagging */ diff --git a/kooka/kocrbase.cpp b/kooka/kocrbase.cpp new file mode 100644 index 00000000..889739e7 --- /dev/null +++ b/kooka/kocrbase.cpp @@ -0,0 +1,368 @@ +/*************************************************************************** + kocrbase.cpp - base dialog for ocr + ------------------- + begin : Fri Now 10 2000 + copyright : (C) 2000 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "resource.h" +#include "kocrbase.h" +#include "ksaneocr.h" +#include "kookaimage.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +KOCRBase::KOCRBase( QWidget *parent, KSpellConfig *spellConfig, + KDialogBase::DialogType face ) + :KDialogBase( face, i18n("Optical Character Recognition"), + User2|Close|User1, User1, parent,0, false, true, + KGuiItem( i18n("Start OCR" ), "launch", + i18n("Start the Optical Character Recognition process" )), + KGuiItem( i18n("Cancel" ), "stopocr", + i18n("Stop the OCR Process" ))), + m_animation(0L), + m_metaBox(0L), + m_imgHBox(0L), + m_previewPix(0L), + m_currImg(0L), + m_spellConfig(spellConfig), + m_wantSpellCfg(true), + m_userWantsSpellCheck(true), + m_cbWantCheck(0L), + m_gbSpellOpts(0L) +{ + kdDebug(28000) << "OCR Base Dialog!" << endl; + // Layout-Boxes + + KConfig *konf = KGlobal::config (); + KConfigGroupSaver gs( konf, CFG_OCR_KSPELL ); + m_userWantsSpellCheck = konf->readBoolEntry(CFG_WANT_KSPELL, true); + + /* Connect signals which disable the fields and store the configuration */ + connect( this, SIGNAL( user1Clicked()), this, SLOT( writeConfig())); + connect( this, SIGNAL( user1Clicked()), this, SLOT( startOCR() )); + connect( this, SIGNAL( user2Clicked()), this, SLOT( stopOCR() )); + m_previewSize.setWidth(200); + m_previewSize.setHeight(300); + + enableButton( User1, true ); /* start ocr */ + enableButton( User2, false ); /* Cancel */ + enableButton( Close, true ); +} + + +KAnimWidget* KOCRBase::getAnimation(QWidget *parent) +{ + if( ! m_animation ) + { + m_animation = new KAnimWidget( QString("kde"), 48, parent, "ANIMATION" ); + } + return( m_animation ); +} + +EngineError KOCRBase::setupGui() +{ + ocrIntro(); + imgIntro(); + if( m_wantSpellCfg ) spellCheckIntro(); + + return ENG_OK; +} + +void KOCRBase::imgIntro() +{ + m_imgPage = addVBoxPage( i18n("Image") ); + (void) new QLabel( i18n("Image Information"), m_imgPage ); + + // Caption - Label and image + m_imgHBox = new QHBox( m_imgPage ); + + m_imgHBox->setSpacing( KDialog::spacingHint()); + + m_previewPix = new QLabel( m_imgHBox ); + m_previewPix->setPixmap(QPixmap()); + m_previewPix->setFixedSize(m_previewSize); + m_previewPix->setAlignment( Qt::AlignCenter ); + m_previewPix->setFrameStyle( QFrame::Panel | QFrame::Sunken ); + // m_previewPix->resize(m_previewSize); + + /* See introduceImage where the meta box is filled with data from the + * incoming widget. + */ + m_metaBox = new QVBox( m_imgHBox ); +} + +/* + * This creates a Tab OCR + */ +void KOCRBase::ocrIntro( ) +{ + m_ocrPage = addVBoxPage( i18n("OCR") ); + + // Caption - Label and image + /* labelstring */ + (void) new QLabel( i18n("Starting Optical Character Recognition with %1

"). + arg( ocrEngineName() ), m_ocrPage ); + // Find the kadmos logo and display if available + KStandardDirs stdDir; + QString logo = stdDir.findResource( "data", "kooka/pics/" + ocrEngineLogo() ); + + kdDebug(28000)<< "Reading logo " << logo << endl; + QPixmap pix; + QWidget *pa = m_ocrPage; + + if( pix.load( logo )) + { + QHBox *hb_cap = new QHBox( m_ocrPage ); + hb_cap->setSpacing( KDialog::spacingHint()); + + QLabel *imgLab = new QLabel( hb_cap ); + imgLab->setAlignment( Qt::AlignHCenter | Qt::AlignTop ); + imgLab->setPixmap( pix ); + pa = hb_cap; + } + + (void) new KActiveLabel( ocrEngineDesc(), pa ); +} + + +void KOCRBase::spellCheckIntro() +{ + m_spellchkPage = addVBoxPage( i18n("Spell-checking") ); + + /* Want the spell checking at all? Checkbox here */ + QGroupBox *gb1 = new QGroupBox( 1, Qt::Horizontal, i18n("OCR Post Processing"), m_spellchkPage ); + m_cbWantCheck = new QCheckBox( i18n("Enable spell-checking for validation of the OCR result"), + gb1 ); + /* Spellcheck options */ + m_gbSpellOpts = new QGroupBox( 1, Qt::Horizontal, i18n("Spell-Check Options"), + m_spellchkPage ); + + KSpellConfig *sCfg = new KSpellConfig( m_gbSpellOpts, "SPELLCHK", m_spellConfig, false ); + /* A space eater */ + QWidget *spaceEater = new QWidget(m_spellchkPage); + spaceEater->setSizePolicy( QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored )); + + /* connect toggle button */ + connect( m_cbWantCheck, SIGNAL(toggled(bool)), this, SLOT(slWantSpellcheck(bool))); + m_cbWantCheck->setChecked( m_userWantsSpellCheck ); + m_gbSpellOpts->setEnabled( m_userWantsSpellCheck ); + m_spellConfig = sCfg; + + connect( sCfg, SIGNAL(configChanged()), + this, SLOT(slSpellConfigChanged())); +} + +void KOCRBase::slSpellConfigChanged() +{ + kdDebug(28000) << "Spellcheck config changed" << endl; +} + + + +void KOCRBase::stopAnimation() +{ + if( m_animation ) + m_animation->stop(); +} + +void KOCRBase::startAnimation() +{ + if( m_animation ) + m_animation->start(); +} + +KOCRBase::~KOCRBase() +{ + +} + +void KOCRBase::introduceImage( KookaImage* img) +{ + if( ! (img && img->isFileBound()) ) return; + KFileMetaInfo info = img->fileMetaInfo(); + QStringList groups; + if ( info.isValid() ) + groups = info.preferredGroups(); + + delete m_metaBox; + m_metaBox = new QVBox( m_imgHBox ); + + /* Start to create a preview job for the thumb */ + KURL::List li(img->url()); + KIO::Job *m_job = KIO::filePreview(li, m_previewSize.width(), + m_previewSize.height()); + + if( m_job ) + { + connect( m_job, SIGNAL( result( KIO::Job * )), + this, SLOT( slPreviewResult( KIO::Job * ))); + connect( m_job, SIGNAL( gotPreview( const KFileItem*, const QPixmap& )), + SLOT( slGotPreview( const KFileItem*, const QPixmap& ) )); + /* KIO::Jo result is called in any way: Success, Failed, Error, + * thus connecting the failed is not really necessary. + */ + } + + for ( QStringList::Iterator it = groups.begin(); it != groups.end(); ++it ) + { + QString theGroup(*it); + + kdDebug(29000) << "handling the group " << theGroup << endl; + + QStringList keys = info.group(theGroup).supportedKeys(); + + if( keys.count() > 0 ) + { + // info.groupInfo( theGroup )->translatedName() + // FIXME: howto get the translated group name? + QLabel *lGroup = new QLabel( theGroup, m_metaBox ); + lGroup->setBackgroundColor( QColor(gray)); + lGroup->setMargin( KDialog::spacingHint()); + + QGrid *nGrid = new QGrid( 2, m_metaBox ); + nGrid->setSpacing( KDialog::spacingHint()); + for ( QStringList::Iterator keyIt = keys.begin(); keyIt != keys.end(); ++keyIt ) + { + KFileMetaInfoItem item = info.item(*keyIt); + QString itKey = item.translatedKey(); + if( itKey.isEmpty() ) + itKey = item.key(); + if( ! itKey.isEmpty() ) + { + (void) new QLabel( item.translatedKey() + ": ", nGrid ); + (void) new QLabel( item.string(), nGrid ); + kdDebug(29000) << "hasKey " << *keyIt << endl; + } + } + } + } + QWidget *spaceEater = new QWidget( m_metaBox ); + spaceEater->setSizePolicy( QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored )); + m_metaBox->show(); +} + +void KOCRBase::slPreviewResult(KIO::Job *job ) +{ + // nothing + if( job && job->error() > 0 ) + { + kdDebug(28000) << "Thumbnail Creation ERROR: " << job->errorString() << endl; + job->showErrorDialog( 0 ); + } +} + +void KOCRBase::slGotPreview( const KFileItem*, const QPixmap& newPix ) +{ + kdDebug(28000) << "Got the preview" << endl; + m_previewPix->setPixmap(newPix); + + if( m_previewPix && m_currImg ) + { + m_previewPix->setPixmap(newPix); + } +} + + +void KOCRBase::writeConfig() +{ + +} + +bool KOCRBase::wantSpellCheck() +{ + return m_userWantsSpellCheck; +} + +void KOCRBase::startOCR() +{ + /* en- and disable the buttons */ + kdDebug(28000) << "Base: Starting OCR" << endl; + + enableFields(false); + enableButton( User1, false ); /* Start OCR */ + enableButton( User2, true ); /* Stop OCR */ + enableButton( Close, true ); + + startAnimation(); +} + +void KOCRBase::stopOCR() +{ + enableFields(true); + + enableButton( User1, true ); /* start ocr */ + enableButton( User2, false ); /* Cancel */ + enableButton( Close, true ); + + stopAnimation(); + +} + +void KOCRBase::enableFields(bool) +{ + +} + +void KOCRBase::slWantSpellcheck( bool wantIt ) +{ + if( m_gbSpellOpts ) + { + m_gbSpellOpts->setEnabled( wantIt ); + } + m_userWantsSpellCheck = wantIt; + + KConfig *konf = KGlobal::config (); + KConfigGroupSaver gs( konf, CFG_OCR_KSPELL ); + konf->writeEntry( CFG_WANT_KSPELL, wantIt ); +} + +/* The End ;) */ +#include "kocrbase.moc" diff --git a/kooka/kocrbase.h b/kooka/kocrbase.h new file mode 100644 index 00000000..05987b1d --- /dev/null +++ b/kooka/kocrbase.h @@ -0,0 +1,158 @@ +/*************************************************************************** + kocrbase.h - base dialog for OCR + ------------------- + begin : Sun Jun 11 2000 + copyright : (C) 2000 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#ifndef KOCRBASE_H +#define KOCRBASE_H + +#include +#include +#include +#include + +#include +#include +#include + +#include "ksaneocr.h" +/** + *@author Klaas Freitag + */ + + +class KookaImage; +class QHBox; +class QVBox; +class QLabel; +class QSize; +class KSpellConfig; +class QCheckBox; +class QGroupBox; + +class KOCRBase: public KDialogBase +{ + Q_OBJECT +public: + KOCRBase( QWidget *, KSpellConfig *spellConfig, + KDialogBase::DialogType face = KDialogBase::Plain ); + ~KOCRBase(); + + virtual EngineError setupGui(); + + /** + * @return the name of the ocr engine + */ + virtual QString ocrEngineName() const { return QString(); } + + /** + * @return the filename (without path) of the logo of the ocr engine. + * the logo needs to be installed in $KDEDIR/share/apps/kooka/pics + */ + virtual QString ocrEngineLogo() const { return QString(); } + + /** + * @return a description string of the ocr engine + */ + virtual QString ocrEngineDesc() const { return QString(); } + + QVBox* ocrPage() const { return m_ocrPage; } + QVBox* imagePage() const { return m_imgPage; } + + KSpellConfig* spellConfig() const + { return m_spellConfig; } + + bool wantSpellCheck(); + +public slots: + virtual void stopAnimation(); + virtual void startAnimation(); + + virtual void introduceImage( KookaImage* ); + + virtual void startOCR(); + virtual void stopOCR(); + /** + * enable or disable dialog fields. This slot is called when the ocr process starts + * with parameter state=false and called again if the gui should accept user input + * again after ocr finished with parameter true. + */ + virtual void enableFields(bool state); + +protected: + /** + * This creates a a tab OCR in the dialog and creates a small intro about the + * ocr engine used. + * It calls the virtual subs ocrEngineName, ocrEngineLogo and ocrEngineDesc which + * must return the approbiate values for the engines. + * @return a pointer to a VBox in which further elements can be layouted + */ + virtual void ocrIntro(); + + /** + * This creates a a tab Image Info in the dialog and creates a image description + * about the current image to ocr. + */ + virtual void imgIntro(); + + /** + * This sets up the spellchecking configuration + */ + virtual void spellCheckIntro(); + + +protected slots: + virtual KAnimWidget* getAnimation(QWidget*); + virtual void writeConfig(); + virtual void slSpellConfigChanged(); + + /** + * hit if the user toggles the want-spellcheck checkbox + */ + virtual void slWantSpellcheck( bool wantIt ); + +private slots: + virtual void slPreviewResult( KIO::Job* ); + virtual void slGotPreview( const KFileItem*, const QPixmap& ); + +private: + KAnimWidget *m_animation; + QVBox *m_ocrPage; + QVBox *m_imgPage; + QVBox *m_spellchkPage; + QVBox *m_metaBox; + QHBox *m_imgHBox; + QLabel *m_previewPix; + KookaImage *m_currImg; + + KSpellConfig *m_spellConfig; + bool m_wantSpellCfg; /* show the spellcheck options? */ + bool m_userWantsSpellCheck; /* user has enabled/disabled spellcheck */ + QSize m_previewSize; + + QCheckBox *m_cbWantCheck; + QGroupBox *m_gbSpellOpts; +}; + +#endif diff --git a/kooka/kocrgocr.cpp b/kooka/kocrgocr.cpp new file mode 100644 index 00000000..cfc4c92c --- /dev/null +++ b/kooka/kocrgocr.cpp @@ -0,0 +1,201 @@ +/*************************************************************************** + kocrgocr.cpp - GOCR ocr dialog + ------------------- + begin : Fri Now 10 2000 + copyright : (C) 2000 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +/* $Id$ */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "resource.h" +#include "ksaneocr.h" // TODO: Really needed? +#include "kocrgocr.h" +#include "kocrgocr.moc" +#include +#include "kookaimage.h" +#include "kookapref.h" +#include +#include + +/* defines for konfig-reading */ + +#define CFG_GOCR_DUSTSIZE "gocrDustSize" +#define CFG_GOCR_GRAYLEVEL "gocrGrayLevel" +#define CFG_GOCR_SPACEWIDTH "gocrSpaceWidth" + + + +KGOCRDialog::KGOCRDialog( QWidget *parent, KSpellConfig *spellConfig ) + :KOCRBase( parent, spellConfig, KDialogBase::Tabbed ), + m_ocrCmd( QString()) +{ + kdDebug(28000) << "Starting KOCR-Start-Dialog!" << endl; + // Layout-Boxes +} + +QString KGOCRDialog::ocrEngineLogo() const +{ + return "gocr.png"; +} + +QString KGOCRDialog::ocrEngineName() const +{ + return i18n("GOCR" ); +} + +QString KGOCRDialog::ocrEngineDesc() const +{ + return i18n("GOCR is an Open Source project " + "for optical character recognition.

" + "The author of gocr is Joerg Schulenburg
" + "For more information about gocr see " + "" + "http://jocr.sourceforge.net"); +} + +EngineError KGOCRDialog::setupGui() +{ + KOCRBase::setupGui(); + + QVBox *page = ocrPage(); + Q_CHECK_PTR( page ); + + KConfig *conf = KGlobal::config (); + conf->setGroup( CFG_GROUP_OCR_DIA ); + + // Horizontal line + // (void) new KSeparator( KSeparator::HLine, page); + + // Entry-Field. + QString res = conf->readPathEntry( CFG_GOCR_BINARY, "notFound" ); + if( res == "notFound" ) + { + res = KookaPreferences::tryFindGocr(); + if( res.isEmpty() ) + { + /* Popup here telling that the config needs to be called */ + KMessageBox::sorry( this, i18n( "The path to the gocr binary is not configured yet.\n" + "Please go to the Kooka configuration and enter the path manually."), + i18n("OCR Software Not Found") ); + } + } + + if( res.isEmpty() ) + res = i18n("Not found"); + else + m_ocrCmd = res; + + (void) new QLabel( i18n("Using GOCR binary: ") + res, page ); + (void) new KSeparator( KSeparator::HLine, page); + + QHBox *hb = new QHBox(page); + hb->setSpacing( KDialog::spacingHint()); + QVBox *innerBox = new QVBox( hb ); + innerBox->setSpacing( KDialog::spacingHint()); + /* This is for a 'work-in-progress'-Animation */ + getAnimation(hb); + + /* Slider for OCR-Options */ + sliderGrayLevel = new KScanSlider( innerBox , i18n("&Gray level"), 0, 254, true, 160 ); + int numdefault = conf->readNumEntry( CFG_GOCR_GRAYLEVEL, 160 ); + sliderGrayLevel->slSetSlider( numdefault ); + QToolTip::add( sliderGrayLevel, + i18n( "The numeric value gray pixels are \nconsidered to be black.\n\nDefault is 160")); + + sliderDustSize = new KScanSlider( innerBox, i18n("&Dust size" ), 0, 60, true, 10 ); + numdefault = conf->readNumEntry( CFG_GOCR_DUSTSIZE, 10 ); + sliderDustSize->slSetSlider( numdefault ); + QToolTip::add( sliderDustSize, + i18n( "Clusters smaller than this value\nwill be considered to be dust and \nremoved from the image.\n\nDefault is 10")); + + sliderSpace = new KScanSlider( innerBox, i18n( "&Space width" ), 0, 60, true, 0 ); + numdefault = conf->readNumEntry( CFG_GOCR_SPACEWIDTH, 0 ); + sliderSpace->slSetSlider( numdefault ); + QToolTip::add( sliderSpace, i18n("Spacing between characters.\n\nDefault is 0 what means autodetection")); + + return ENG_OK; +} + +void KGOCRDialog::introduceImage( KookaImage *img ) +{ + if( !img ) return; + + KOCRBase::introduceImage( img ); + + + bool isOn = true; + + if( img->numColors() > 0 && img->numColors() <3 ) + { + kdDebug(29000) << "introduceImage: Have " << img->numColors() << " colors on depth " << img->depth() << endl; + + /* that means it is a black-and-white image. Thus we do not need the GrayLevel slider */ + isOn = false; + } + + if( sliderGrayLevel ) + sliderGrayLevel->setEnabled( isOn ); + +} + + +KGOCRDialog::~KGOCRDialog() +{ + +} + +void KGOCRDialog::writeConfig( void ) +{ + KConfig *conf = KGlobal::config (); + conf->setGroup( CFG_GROUP_OCR_DIA ); + + conf->writeEntry( CFG_GOCR_BINARY, QString(getOCRCmd())); + conf->writeEntry( CFG_GOCR_GRAYLEVEL, getGraylevel()); + conf->writeEntry( CFG_GOCR_DUSTSIZE, getDustsize()); + conf->writeEntry( CFG_GOCR_SPACEWIDTH, getSpaceWidth()); +} + + +void KGOCRDialog::enableFields(bool b) +{ + kdDebug(28000) << "About to disable the entry fields" << endl; + sliderGrayLevel->setEnabled( b ); + sliderDustSize->setEnabled( b ); + sliderSpace->setEnabled( b ); +} + +/* The End ;) */ + diff --git a/kooka/kocrgocr.h b/kooka/kocrgocr.h new file mode 100644 index 00000000..619cfedd --- /dev/null +++ b/kooka/kocrgocr.h @@ -0,0 +1,86 @@ +/*************************************************************************** + kocrgocr.h - ocr dialog for GOCR + ------------------- + begin : Sun Jun 11 2000 + copyright : (C) 2000 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + + +#ifndef KOCRGOCR_H +#define KOCRGOCR_H + +#include +#include +#include + +#include +#include + +#include "kocrbase.h" +/** + *@author Klaas Freitag + */ + +class KSpellConfig; + +class KGOCRDialog: public KOCRBase +{ + Q_OBJECT +public: + KGOCRDialog( QWidget*, KSpellConfig* ); + ~KGOCRDialog(); + + QString getOCRCmd( void ) const + { return m_ocrCmd;} + + int getGraylevel( void ) const + { return( sliderGrayLevel->value());} + int getDustsize( void ) const + { return( sliderDustSize->value());} + int getSpaceWidth( void ) const + { return( sliderSpace->value());} + + EngineError setupGui(); + + QString ocrEngineName() const; + QString ocrEngineDesc() const; + QString ocrEngineLogo() const; + +public slots: + void enableFields(bool); + void introduceImage( KookaImage* ); + +protected: + void writeConfig(); + + +private: + + + KScanSlider *sliderGrayLevel; + KScanSlider *sliderDustSize; + KScanSlider *sliderSpace; + + QString m_ocrCmd; +}; + +#endif diff --git a/kooka/kocrkadmos.cpp b/kooka/kocrkadmos.cpp new file mode 100644 index 00000000..b4d58244 --- /dev/null +++ b/kooka/kocrkadmos.cpp @@ -0,0 +1,521 @@ +/*************************************************************************** + kocrstartdia.cpp - description + ------------------- + begin : Fri Now 10 2000 + copyright : (C) 2000 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "resource.h" +#include "ksaneocr.h" // TODO: Really needed? +#include "kocrkadmos.h" +#include "kocrkadmos.moc" + +#include +#include +#include +#include + + +/* defines for konfig-reading */ +#define CFG_GROUP_KADMOS "Kadmos" +#define CFG_KADMOS_CLASSIFIER_PATH "classifierPath" +#define CFG_KADMOS_CLASSIFIER "classifier" + + +#define CNTRY_CZ i18n( "Czech Republic, Slovakia") +#define CNTRY_GB i18n( "Great Britain, USA" ) + +KadmosDialog::KadmosDialog( QWidget *parent, KSpellConfig *spellConfig ) + :KOCRBase( parent, spellConfig, KDialogBase::Tabbed ), + m_cbNoise(0), + m_cbAutoscale(0), + m_haveNorm(false) +{ + kdDebug(28000) << "Starting KOCR-Start-Dialog!" << endl; + // Layout-Boxes + findClassifiers(); +} + +QString KadmosDialog::ocrEngineLogo() const +{ + return "kadmoslogo.png"; +} + +QString KadmosDialog::ocrEngineName() const +{ + return i18n("KADMOS OCR/ICR"); +} + +QString KadmosDialog::ocrEngineDesc() const +{ + return i18n("This version of Kooka was linked with the KADMOS OCR/ICR engine, a " + "commercial engine for optical character recognition.

" + "Kadmos is a product of re Recognition AG
" + "For more information about Kadmos OCR see " + "" + "http://www.rerecognition.com"); +} + + +EngineError KadmosDialog::findClassifiers() +{ + findClassifierPath(); + + KLocale *locale = KGlobal::locale(); + QStringList allCountries = locale->allLanguagesTwoAlpha (); + for ( QStringList::Iterator it = allCountries.begin(); + it != allCountries.end(); ++it ) + { + m_longCountry2short[locale->twoAlphaToCountryName(*it)] = *it; + } + m_longCountry2short[i18n("European Countries")] = "eu"; + m_longCountry2short[ CNTRY_CZ ] = "cz"; + m_longCountry2short[ CNTRY_GB ] = "us"; + + QStringList lst; + + /* custom Path */ + if( ! m_customClassifierPath.isEmpty() ) + { + QDir dir( m_customClassifierPath ); + + QStringList lst1 = dir.entryList( "ttf*.rec" ); + + for ( QStringList::Iterator it = lst1.begin(); it != lst1.end(); ++it ) + { + lst << m_customClassifierPath + *it; + } + + lst1 = dir.entryList( "hand*.rec" ); + + for ( QStringList::Iterator it = lst1.begin(); it != lst1.end(); ++it ) + { + lst << m_customClassifierPath + *it; + } + + lst1 = dir.entryList( "norm*.rec" ); + + for ( QStringList::Iterator it = lst1.begin(); it != lst1.end(); ++it ) + { + lst << m_customClassifierPath + *it; + } + } + else + { + /* standard location */ + KStandardDirs stdDir; + kdDebug(28000) << "Starting to read resource" << endl; + + lst = stdDir.findAllResources( "data", + "kooka/classifiers/*.rec", + true, /* recursive */ + true ); /* uniqu */ + } + + + /* no go through lst and sort out hand-, ttf- and norm classifier */ + for ( QStringList::Iterator it = lst.begin(); it != lst.end(); ++it ) + { + QFileInfo fi( *it); + QString name = fi.fileName().lower(); + + kdDebug(28000) << "Checking file " << *it << endl; + + if( name.startsWith( "ttf" ) ) + { + QString lang = name.mid(3,2); + if( allCountries.contains(lang) ) + { + QString lngCountry = locale->twoAlphaToCountryName(lang); + if( lngCountry.isEmpty() ) + lngCountry = name; + m_ttfClassifier << lngCountry; + kdDebug(28000) << "ttf: Insert country " << lngCountry << endl; + } + else if( lang == "cz" ) + { + m_ttfClassifier << CNTRY_CZ; + } + else if( lang == "us" ) + { + m_ttfClassifier << CNTRY_GB; + } + else + { + m_ttfClassifier << name; + kdDebug(28000) << "ttf: Unknown country" << endl; + } + } + else if( name.startsWith( "hand" ) ) + { + QString lang = name.mid(4,2); + if( allCountries.contains(lang) ) + { + QString lngCountry = locale->twoAlphaToCountryName(lang); + if( lngCountry.isEmpty() ) + lngCountry = name; + m_handClassifier << lngCountry; + } + else if( lang == "cz" ) + { + m_handClassifier << i18n( "Czech Republic, Slovakia"); + } + else if( lang == "us" ) + { + m_handClassifier << i18n( "Great Britain, USA" ); + } + else + { + kdDebug(28000) << "Hand: Unknown country " << lang << endl; + m_handClassifier << name; + } + } + else if( name.startsWith( "norm" )) + { + m_haveNorm = true; + } + + kdDebug(28000) << "Found classifier: " << *it << endl; + m_classifierPath << *it; + } + + if( m_handClassifier.count()+m_ttfClassifier.count()>0 ) + { + /* There are classifiers */ + return ENG_OK; + } + else + { + /* Classifier are missing */ + return ENG_DATA_MISSING; + } +} + + +EngineError KadmosDialog::findClassifierPath() +{ + KStandardDirs stdDir; + EngineError err = ENG_OK; + + KConfig *conf = KGlobal::config (); + KConfigGroupSaver gs( conf, CFG_GROUP_KADMOS ); + + m_customClassifierPath = conf->readPathEntry( CFG_KADMOS_CLASSIFIER_PATH ); +#if 0 + if( m_customClassifierPath == "NotFound" ) + { + /* Wants the classifiers from the standard kde paths */ + KMessageBox::error(0, i18n("The classifier files for KADMOS could not be found.\n" + "OCR with KADMOS will not be possible!\n\n" + "Change the OCR engine in the preferences dialog."), + i18n("Installation Error") ); + } + else + { + m_classifierPath = customPath; + } +#endif + return err; + +} + + +EngineError KadmosDialog::setupGui() +{ + + EngineError err = KOCRBase::setupGui(); + + // setupPreprocessing( addVBoxPage( i18n("Preprocessing"))); + // setupSegmentation( addVBoxPage( i18n("Segmentation"))); + // setupClassification( addVBoxPage( i18n("Classification"))); + + /* continue page setup on the first page */ + QVBox *page = ocrPage(); + + // Horizontal line + (void) new KSeparator( KSeparator::HLine, page); + + // FIXME: dynamic classifier reading. + + (void) new QLabel( i18n("Please classify the font type and language of the text on the image:"), + page ); + QHBox *locBox = new QHBox( page ); + m_bbFont = new QButtonGroup(1, Qt::Horizontal, i18n("Font Type Selection"), locBox); + + m_rbMachine = new QRadioButton( i18n("Machine print"), m_bbFont ); + m_rbHand = new QRadioButton( i18n("Hand writing"), m_bbFont ); + m_rbNorm = new QRadioButton( i18n("Norm font"), m_bbFont ); + + m_gbLang = new QGroupBox(1, Qt::Horizontal, i18n("Country"), locBox); + + + m_cbLang = new QComboBox( m_gbLang ); + m_cbLang->setCurrentText( KLocale::defaultCountry() ); + + connect( m_bbFont, SIGNAL(clicked(int)), this, SLOT(slFontChanged(int) )); + m_rbMachine->setChecked(true); + + /* --- */ + QHBox *innerBox = new QHBox( page ); + innerBox->setSpacing( KDialog::spacingHint()); + + QButtonGroup *cbGroup = new QButtonGroup( 1, Qt::Horizontal, i18n("OCR Modifier"), innerBox ); + Q_CHECK_PTR(cbGroup); + + m_cbNoise = new QCheckBox( i18n( "Enable automatic noise reduction" ), cbGroup ); + m_cbAutoscale = new QCheckBox( i18n( "Enable automatic scaling"), cbGroup ); + + getAnimation(innerBox); + // (void) new QWidget ( page ); + + if( err != ENG_OK ) + { + enableFields(false); + enableButton(User1, false ); + } + + if( m_ttfClassifier.count() == 0 ) + { + m_rbMachine->setEnabled(false); + } + if( m_handClassifier.count() == 0 ) + { + m_rbHand->setEnabled(false); + } + if( !m_haveNorm ) + m_rbNorm->setEnabled(false); + + if( (m_ttfClassifier.count() + m_handClassifier.count()) == 0 && ! m_haveNorm ) + { + KMessageBox::error(0, i18n("The classifier files for KADMOS could not be found.\n" + "OCR with KADMOS will not be possible!\n\n" + "Change the OCR engine in the preferences dialog."), + i18n("Installation Error") ); + err = ENG_BAD_SETUP; + } + else + slFontChanged( 0 ); // Load machine print font language list + return err; +} + +void KadmosDialog::slFontChanged( int id ) +{ + m_cbLang->clear(); + + KConfig *conf = KGlobal::config (); + KConfigGroupSaver gs( conf, CFG_GROUP_KADMOS ); + + + + m_customClassifierPath = conf->readPathEntry( CFG_KADMOS_CLASSIFIER_PATH ); + + bool enable = true; + + if( id == 0 ) /* Machine Print */ + { + m_cbLang->insertStringList( m_ttfClassifier ); + } + else if( id == 1 ) /* Hand Writing */ + { + m_cbLang->insertStringList( m_handClassifier ); + } + else if( id == 2 ) /* Norm Font */ + { + enable = false; + } + m_cbLang->setEnabled( enable ); +} + + +void KadmosDialog::setupPreprocessing( QVBox* ) +{ + +} + +void KadmosDialog::setupSegmentation( QVBox* ) +{ + +} + +void KadmosDialog::setupClassification( QVBox* ) +{ + +} +/* + * returns the complete path of the classifier selected in the + * GUI in the parameter path. The result value indicates if there + * was one found. + */ + +bool KadmosDialog::getSelClassifier( QString& path ) const +{ + QString classifier = getSelClassifierName(); + + QString cmplPath; + /* + * Search the complete path for the classifier file name + * returned from the getSelClassifierName method + */ + for ( QStringList::ConstIterator it = m_classifierPath.begin(); + it != m_classifierPath.end(); ++it ) + { + QFileInfo fi( *it ); + if( fi.fileName() == classifier ) + { + cmplPath = *it; + break; + } + } + + bool res = true; + + if( cmplPath.isEmpty() ) + { + /* hm, no path was found */ + kdDebug(28000) << "ERR; The entire path is empty, joking?" << endl; + res = false; + } + else + { + /* Check if the classifier exists on the HD. If not, return an empty string */ + QFileInfo fi(cmplPath); + + if( res && ! fi.exists() ) + { + kdDebug(28000) << "Classifier file does not exist" << endl; + path = i18n("Classifier file %1 does not exist").arg(classifier); + res = false; + } + + if( res && ! fi.isReadable() ) + { + kdDebug(28000) << "Classifier file could not be read" << endl; + path = i18n("Classifier file %1 is not readable").arg(classifier); + res = false; + } + + if( res ) + path = cmplPath; + } + return res; +} + +QString KadmosDialog::getSelClassifierName() const +{ + QButton *butt = m_bbFont->selected(); + + QString fType, rType; + + if( butt ) + { + int fontTypeID = m_bbFont->id(butt); + if( fontTypeID == 0 ) + fType = "ttf"; + else if( fontTypeID == 1 ) + fType = "hand"; + else if( fontTypeID == 2 ) + fType = "norm"; + else + kdDebug(28000) << "ERR: Wrong Font Type ID" << endl; + } + + /* Get the long text from the combo box */ + QString selLang = m_cbLang->currentText(); + QString trans; + if( fType != "norm" && m_longCountry2short.contains( selLang )) + { + QString langType = m_longCountry2short[selLang]; + trans = fType+langType+".rec"; + } + else + { + if( selLang.endsWith( ".rec" )) + { + /* can be a undetected */ + trans = selLang; + } + else if( fType == "norm" ) + { + trans = "norm.rec"; + } + else + kdDebug(28000) << "ERROR: Not a valid classifier" << endl; + } + kdDebug(28000) << "Returning trans. "<< trans << endl; + return( trans ); +} + +bool KadmosDialog::getAutoScale() +{ + return( m_cbAutoscale ? m_cbAutoscale->isChecked() : false ); +} + +bool KadmosDialog::getNoiseReduction() +{ + return( m_cbNoise ? m_cbNoise->isChecked() : false ); + +} + +KadmosDialog::~KadmosDialog() +{ + +} + +void KadmosDialog::writeConfig( void ) +{ + +} + + +void KadmosDialog::enableFields( bool state ) +{ + kdDebug(28000) << "About to disable the entry fields" << endl; + m_cbNoise->setEnabled( state ); + m_cbAutoscale->setEnabled( state ); + + m_bbFont->setEnabled( state ); + m_gbLang->setEnabled( state ); +} + + +/* The End ;) */ + diff --git a/kooka/kocrkadmos.h b/kooka/kocrkadmos.h new file mode 100644 index 00000000..38247cc9 --- /dev/null +++ b/kooka/kocrkadmos.h @@ -0,0 +1,128 @@ +/*************************************************************************** + kocrkadmos.h - ocr dialog for KADMOS ocr engine + ------------------- + begin : Sun Jun 11 2000 + copyright : (C) 2000 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + + +#ifndef KOCRKADMOS_H +#define KOCRKADMOS_H + +#include +#include + +#include "kocrbase.h" +/** + *@author Klaas Freitag + */ + + + +class KScanCombo; +class QWidget; +class QButtonGroup; +class KConfig; +class QCheckBox; +class KSpellConfig; +class QRadioButton; + +class KadmosClassifier /* Not yet used FIXME */ +{ +public: + KadmosClassifier( QString lang, QString filename ); + QString getCmplFilename() const { return path+filename; } + QString getFilename() const { return filename; } + QString language() const { return languagesName; } + + void setPath( const QString& p ) { path=p; } +private: + + QString filename; + QString path; + QString languagesName; +}; + + +class KadmosDialog: public KOCRBase +{ + Q_OBJECT +public: + KadmosDialog( QWidget *, KSpellConfig *spellConfig ); + ~KadmosDialog(); + + typedef QMap StrMap; + + EngineError setupGui(); + bool getAutoScale(); + bool getNoiseReduction(); + bool getSelClassifier(QString&) const; + QString getSelClassifierName() const; + + QString ocrEngineName() const; + QString ocrEngineDesc() const; + QString ocrEngineLogo() const; + +public slots: + void enableFields(bool); + +protected: + void writeConfig(); + + void setupPreprocessing( QVBox *box ); + void setupSegmentation( QVBox *box ); + void setupClassification( QVBox *box ); + + EngineError findClassifiers(); + EngineError findClassifierPath(); +private slots: + + void slFontChanged( int id ); + +private: + StrMap m_classifierTranslate; + + QCheckBox *m_cbNoise; + QCheckBox *m_cbAutoscale; + QString m_customClassifierPath; + + QButtonGroup *m_bbFont; + + QRadioButton *m_rbMachine; + QRadioButton *m_rbHand; + QRadioButton *m_rbNorm; + + QGroupBox *m_gbLang; + + QComboBox *m_cbLang; + + QStringList m_ttfClassifier; + QStringList m_handClassifier; + QStringList m_classifierPath; + + bool m_haveNorm; + + typedef QMap StringMap; + StringMap m_longCountry2short; +}; + +#endif diff --git a/kooka/kocrocrad.cpp b/kooka/kocrocrad.cpp new file mode 100644 index 00000000..1ce94f65 --- /dev/null +++ b/kooka/kocrocrad.cpp @@ -0,0 +1,263 @@ +/*************************************************************************** + kocrocrad.cpp - ocrad dialog + ------------------- + begin : Tue Jul 15 2003 + copyright : (C) 2003 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +/* $Id$ */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "resource.h" +#include "kocrocrad.h" +#include +#include "kookaimage.h" +#include "kookapref.h" +#include +#include +#include + + + +ocradDialog::ocradDialog( QWidget *parent, KSpellConfig *spellConfig ) + :KOCRBase( parent, spellConfig, KDialogBase::Tabbed ), + m_ocrCmd( QString()), + m_orfUrlRequester(0L), + m_layoutMode(0), + m_binaryLabel(0), + m_proc(0), + m_version(0) +{ + kdDebug(28000) << "Starting ocrad-Start-Dialog!" << endl; + // Layout-Boxes +} + +QString ocradDialog::ocrEngineLogo() const +{ + return "ocrad.png"; +} + +QString ocradDialog::ocrEngineName() const +{ + return i18n("ocrad" ); +} + +QString ocradDialog::ocrEngineDesc() const +{ + return i18n("ocrad is a Free Software project " + "for optical character recognition.

" + "The author of ocrad is Antonio Diaz
" + "For more information about ocrad see " + "" + "http://www.gnu.org/software/ocrad/ocrad.html

" + "Images should be scanned in black/white mode for ocrad.
" + "Best results are achieved if the characters are at least 20 pixels high.

" + "Problems arise, as usual, with very bold or very light or broken characters, " + "the same with merged character groups."); +} + + +int ocradDialog::layoutDetectionMode() const +{ + return m_layoutMode->currentItem(); +} + +EngineError ocradDialog::setupGui() +{ + KOCRBase::setupGui(); + + QVBox *page = ocrPage(); + Q_CHECK_PTR( page ); + + KConfig *conf = KGlobal::config (); + conf->setGroup( CFG_GROUP_OCR_DIA ); + + // Horizontal line + // (void) new KSeparator( KSeparator::HLine, page); + + // Entry-Field. + QString res = conf->readPathEntry( CFG_OCRAD_BINARY, "notFound" ); + if( res == "notFound" ) + { + res = KookaPreferences::tryFindBinary("ocrad", CFG_OCRAD_BINARY); + if( res.isEmpty() ) + { + /* Popup here telling that the config needs to be called */ + KMessageBox::sorry( this, i18n( "The path to the ocrad binary is not configured yet.\n" + "Please go to the Kooka configuration and enter the path manually."), + i18n("OCR Software Not Found") ); + } + } + + if( res.isEmpty() ) + res = i18n("Not found"); + else + m_ocrCmd = res; + + /** layout detection button **/ + conf->setGroup( CFG_GROUP_OCRAD ); + int layoutDetect = conf->readNumEntry( CFG_OCRAD_LAYOUT_DETECTION, 0 ); + kdDebug(28000) << "Layout detection from config: " << layoutDetect << endl; + + (void) new KSeparator( KSeparator::HLine, page); + QHBox *hb1 = new QHBox(page); + hb1->setSpacing( KDialog::spacingHint() ); + (void) new QLabel( i18n("OCRAD layout analysis mode: "), hb1); + m_layoutMode = new QComboBox(hb1); + m_layoutMode->insertItem(i18n("No Layout Detection"), 0 ); + m_layoutMode->insertItem(i18n("Column Detection"), 1 ); + m_layoutMode->insertItem(i18n("Full Layout Detection"), 2); + m_layoutMode->setCurrentItem(layoutDetect); + + /** stating the ocrad binary **/ + (void) new KSeparator( KSeparator::HLine, page); + QHBox *hb = new QHBox(page); + hb->setSpacing( KDialog::spacingHint()); + + m_binaryLabel = new QLabel( i18n("Using ocrad binary: ") + res, hb ); + + // retrieve Program version and display + version(res); + + getAnimation(hb); + + /* This is for a 'work-in-progress'-Animation */ + + return ENG_OK; +} + +void ocradDialog::introduceImage( KookaImage *img ) +{ + if( !img ) return; + + KOCRBase::introduceImage( img ); +} + + +ocradDialog::~ocradDialog() +{ + if( m_proc ) + delete m_proc; +} + +void ocradDialog::writeConfig( void ) +{ + KConfig *conf = KGlobal::config (); + conf->setGroup( CFG_GROUP_OCR_DIA ); + + conf->writeEntry( CFG_OCRAD_BINARY, QString(getOCRCmd())); + + conf->setGroup( CFG_GROUP_OCRAD ); + conf->writeEntry( CFG_OCRAD_LAYOUT_DETECTION, m_layoutMode->currentItem()); +} + + +void ocradDialog::enableFields(bool ) +{ + kdDebug(28000) << "About to disable the entry fields" << endl; +} + +/* Later: Allow interactive loading of orf files + * for now, return emty string + */ +QString ocradDialog::orfUrl() const +{ + if( m_orfUrlRequester ) + return m_orfUrlRequester->url(); + else + return QString(); +} + +void ocradDialog::version( const QString& exe ) +{ + if( m_proc ) delete m_proc; + + m_proc = new KProcess; + + kdDebug(28000) << "Using " << exe << " as command" << endl; + *m_proc << exe; + *m_proc << QString("-V"); + + connect( m_proc, SIGNAL(receivedStdout(KProcess *, char *, int )), + this, SLOT(slReceiveStdIn(KProcess *, char *, int ))); + + if( ! m_proc->start( KProcess::NotifyOnExit, KProcess::Stdout ) ) + { + slReceiveStdIn( 0, (char*) "unknown", 7 ); + } +} + +void ocradDialog::slReceiveStdIn( KProcess*, char *buffer, int buflen) +{ + QString vstr = QString::fromUtf8(buffer, buflen); + + kdDebug(28000) << "Got input: "<< buffer << endl; + + QRegExp rx; + rx.setPattern("GNU Ocrad version ([\\d\\.]+)"); + if( rx.search( vstr ) > -1 ) + { + QString vStr = rx.cap(1); + vStr.remove(0,2); + + m_version = vStr.toInt(); + QString v = i18n("Version: ") + rx.cap(1); + + if( m_binaryLabel ) + { + m_binaryLabel->setText(m_binaryLabel->text() + "\n" + v ); + m_binaryLabel->update(); + } + } +} + +/* + * returns the numeric version of the ocrad program. It is queried in the slot + * slReceiveStdIn, which parses the output of the ocrad -V call. + * + * Attention: This method returns 10 for ocrad v. 0.10 and 8 for ocrad-0.8 + */ +int ocradDialog::getNumVersion() +{ + return m_version; +} + +#include "kocrocrad.moc" + +/* The End ;) */ + diff --git a/kooka/kocrocrad.h b/kooka/kocrocrad.h new file mode 100644 index 00000000..d268f403 --- /dev/null +++ b/kooka/kocrocrad.h @@ -0,0 +1,106 @@ +/*************************************************************************** + kocrocrad.h - ocr dialog for ocrad + ------------------- + begin : Tue Jul 15 2003 + copyright : (C) 2003 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + + +#ifndef KOCROCRAD_H +#define KOCROCRAD_H + +#include +#include +#include + +#include +#include + +#include "kocrbase.h" + +#define CFG_GROUP_OCRAD "ocrad" +#define CFG_OCRAD_LAYOUT_DETECTION "layoutDetection" +#define CFG_OCRAD_EXTRA_ARGUMENTS "extraArguments" +#define CFG_OCRAD_FORMAT "format" +#define CFG_OCRAD_CHARSET "charset" +/** + *@author Klaas Freitag + */ + +class KSpellConfig; +class KURLRequester; +class KProcess; +class QLabel; +class QComboBox; + +class ocradDialog: public KOCRBase +{ + Q_OBJECT +public: + ocradDialog( QWidget*, KSpellConfig* ); + ~ocradDialog(); + + QString getOCRCmd( void ) const + { return m_ocrCmd;} + + EngineError setupGui(); + + QString ocrEngineName() const; + QString ocrEngineDesc() const; + QString ocrEngineLogo() const; + + QString orfUrl() const; + + int layoutDetectionMode() const; + + /** + * returns the numeric version of the ocrad program. + * + * Attention: This method returns 10 for ocrad v. 0.10 and 8 for ocrad-0.8 + */ + int getNumVersion(); + +public slots: + void enableFields(bool); + void introduceImage( KookaImage* ); + +protected: + void writeConfig(); + + +private: + void version( const QString& exe ); + +private slots: + void slReceiveStdIn( KProcess *proc, char *buffer, int buflen); + +private: + + QString m_ocrCmd; + KURLRequester *m_orfUrlRequester; + QComboBox *m_layoutMode; + QLabel *m_binaryLabel; + KProcess *m_proc; + int m_version; +}; + +#endif diff --git a/kooka/kooka.cpp b/kooka/kooka.cpp new file mode 100644 index 00000000..3e3d660d --- /dev/null +++ b/kooka/kooka.cpp @@ -0,0 +1,465 @@ +/************************************************************************** + kooka.cpp - Main program class + ------------------- + begin : Sun Jan 16 2000 + copyright : (C) 2000 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ +#include "kooka.h" +#include "kookaview.h" +#include "resource.h" + +#include "kookapref.h" +#include "imgprintdialog.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DOCK_SIZES "DockSizes" + + +Kooka::Kooka( const QCString& deviceToUse) + : KParts::DockMainWindow( 0, "Kooka" ), + m_printer(0), + m_prefDialogIndex(0) +{ + /* Start to create the main view framework */ + m_view = new KookaView( this, deviceToUse); + + /* Call createGUI on the ocr-result view */ + setXMLFile( "kookaui.rc", true ); + + setAcceptDrops(false); // Waba: Not (yet?) supported + KConfig *konf = KGlobal::config (); + readDockConfig ( konf, DOCK_SIZES ); + + // then, setup our actions + setupActions(); + + createGUI(0L); // m_view->ocrResultPart()); + // and a status bar + statusBar()->insertItem( QString(), KookaView::StatusTemp ); + statusBar()->show(); + + // allow the view to change the statusbar and caption + connect(m_view, SIGNAL(signalChangeStatusbar(const QString&)), + this, SLOT(changeStatusbar(const QString&))); + connect(m_view, SIGNAL(signalCleanStatusbar(void)), + this, SLOT(cleanStatusbar())); + connect(m_view, SIGNAL(signalChangeCaption(const QString&)), + this, SLOT(changeCaption(const QString&))); + + changeCaption( i18n( "KDE Scanning" )); + + setAutoSaveSettings( QString::fromLatin1("General Options"), + true ); +} + +void Kooka::createMyGUI( KParts::Part *part ) +{ + kdDebug(28000) << "Part changed, Creating gui" << endl; + createGUI(part); + +} + +Kooka::~Kooka() +{ + KConfig *konf = KGlobal::config (); + m_view->slCloseScanDevice(); + writeDockConfig ( konf, DOCK_SIZES ); + delete m_printer; +} + +void Kooka::startup( void ) +{ + kdDebug(29000) << "Starting startup !" << endl; + if( m_view ) m_view->loadStartupImage(); +} + + +void Kooka::setupActions() +{ + + KStdAction::print(this, SLOT(filePrint()), actionCollection()); + KStdAction::quit(this , SLOT(close()), actionCollection()); + + KStdAction::keyBindings(guiFactory(), SLOT(configureShortcuts()), +actionCollection()); + KStdAction::configureToolbars(this, SLOT(optionsConfigureToolbars()), + actionCollection()); + KStdAction::preferences(this, SLOT(optionsPreferences()), actionCollection()); + + m_view->createDockMenu(actionCollection(), this, "settings_show_docks" ); + + /* Image Viewer action Toolbar - OCR, Scaling etc. */ + (void) new KAction(i18n("&OCR Image..."), "ocr", CTRL+Key_O, + m_view, SLOT(doOCR()), + actionCollection(), "ocrImage" ); + + (void) new KAction(i18n("O&CR on Selection..."), "ocr-select", CTRL+Key_C, + m_view, SLOT(doOCRonSelection()), + actionCollection(), "ocrImageSelect" ); + + KAction *act; + act = new KAction(i18n("Scale to W&idth"), "scaletowidth", CTRL+Key_I, + m_view, SLOT( slIVScaleToWidth()), + actionCollection(), "scaleToWidth" ); + m_view->connectViewerAction( act ); + + act = new KAction(i18n("Scale to &Height"), "scaletoheight", CTRL+Key_H, + m_view, SLOT( slIVScaleToHeight()), + actionCollection(), "scaleToHeight" ); + m_view->connectViewerAction( act ); + + act = new KAction(i18n("Original &Size"), "scaleorig", CTRL+Key_S, + m_view, SLOT( slIVScaleOriginal()), + actionCollection(), "scaleOriginal" ); + m_view->connectViewerAction( act ); + +#ifdef QICONSET_HONOUR_ON_OFF + /* The Toggleaction does not seem to handle the on/off icon from QIconSet */ + QIconSet lockSet; + lockSet.setPixmap(BarIcon("lock") , QIconSet::Automatic, QIconSet::Normal, QIconSet::On ); + lockSet.setPixmap(BarIcon("unlock"), QIconSet::Automatic, QIconSet::Normal, QIconSet::Off); + act = new KToggleAction ( i18n("Keep &Zoom Setting"), lockSet, CTRL+Key_Z, + actionCollection(), "keepZoom" ); +#else + act = new KToggleAction( i18n("Keep &Zoom Setting"), BarIcon("lockzoom"), CTRL+Key_Z, + actionCollection(), "keepZoom" ); +#endif + + connect( act, SIGNAL( toggled( bool ) ), m_view->getImageViewer(), + SLOT(setKeepZoom(bool))); + + m_view->connectViewerAction( act ); + + /* thumbview and gallery actions */ + act = new KAction(i18n("Set Zoom..."), "viewmag", 0, + m_view, SLOT( slIVShowZoomDialog()), + actionCollection(), "showZoomDialog" ); + m_view->connectViewerAction( act ); + + (void) new KAction(i18n("Create From Selectio&n"), "crop", CTRL+Key_N, + m_view, SLOT( slCreateNewImgFromSelection() ), + actionCollection(), "createFromSelection" ); + + (void) new KAction(i18n("Mirror Image &Vertically"), "mirror-vert", CTRL+Key_V, + this, SLOT( slMirrorVertical() ), + actionCollection(), "mirrorVertical" ); + + (void) new KAction(i18n("&Mirror Image Horizontally"), "mirror-horiz", CTRL+Key_M, + this, SLOT( slMirrorHorizontal() ), + actionCollection(), "mirrorHorizontal" ); + + (void) new KAction(i18n("Mirror Image &Both Directions"), "mirror-both", CTRL+Key_B, + this, SLOT( slMirrorBoth() ), + actionCollection(), "mirrorBoth" ); + + (void) new KAction(i18n("Open Image in &Graphic Application..."), "fileopen", CTRL+Key_G, + m_view, SLOT( slOpenCurrInGraphApp() ), + actionCollection(), "openInGraphApp" ); + + act = new KAction(i18n("&Rotate Image Clockwise"), "rotate_cw", CTRL+Key_R, + this, SLOT( slRotateClockWise() ), + actionCollection(), "rotateClockwise" ); + m_view->connectViewerAction( act ); + + act = new KAction(i18n("Rotate Image Counter-Clock&wise"), "rotate_ccw", CTRL+Key_W, + this, SLOT( slRotateCounterClockWise() ), + actionCollection(), "rotateCounterClockwise" ); + m_view->connectViewerAction( act ); + + act = new KAction(i18n("Rotate Image 180 &Degrees"), "rotate", CTRL+Key_D, + this, SLOT( slRotate180() ), + actionCollection(), "upsitedown" ); + m_view->connectViewerAction( act ); + + /* Gallery actions */ + act = new KAction(i18n("&Create Folder..."), "folder_new", 0, + m_view->gallery(), SLOT( slotCreateFolder() ), + actionCollection(), "foldernew" ); + m_view->connectGalleryAction( act ); + + act = new KAction(i18n("&Save Image..."), "filesave", 0, + m_view->gallery(), SLOT( slotExportFile() ), + actionCollection(), "saveImage" ); + m_view->connectGalleryAction( act ); + + act = new KAction(i18n("&Import Image..."), "inline_image", 0, + m_view->gallery(), SLOT( slotImportFile() ), + actionCollection(), "importImage" ); + m_view->connectGalleryAction( act ); + + act = new KAction(i18n("&Delete Image"), "edittrash", 0, + m_view->gallery(), SLOT( slotDeleteItems() ), + actionCollection(), "deleteImage" ); + m_view->connectGalleryAction( act ); + + act = new KAction(i18n("&Unload Image"), "fileclose", 0, + m_view->gallery(), SLOT( slotUnloadItems() ), + actionCollection(), "unloadImage" ); + m_view->connectGalleryAction( act ); + +#if 0 + /* not yet supported actions - coming post 3.1 */ + (void) new KAction(i18n("&Load Scan Parameters"), "bookmark_add", CTRL+Key_L, + m_view, SLOT(slLoadScanParams()), + actionCollection(), "loadscanparam" ); + + (void) new KAction(i18n("Save &Scan Parameters"), "bookmark_add", CTRL+Key_S, + m_view, SLOT(slSaveScanParams()), + actionCollection(), "savescanparam" ); +#endif + + (void) new KAction(i18n("Select Scan Device"), "scanner", 0, + m_view, SLOT( slSelectDevice()), + actionCollection(), "selectsource" ); + + (void) new KAction( i18n("Enable All Warnings && Messages"), 0, + this, SLOT(slEnableWarnings()), + actionCollection(), "enable_msgs"); + + + m_saveOCRTextAction = new KAction( i18n("Save OCR Res&ult Text"), "filesaveas", CTRL+Key_U, + m_view, SLOT(slSaveOCRResult()), + actionCollection(), "saveOCRResult"); +} + + +void Kooka::saveProperties(KConfig *config) +{ + // the 'config' object points to the session managed + // config file. anything you write here will be available + // later when this app is restored + + //if (!m_view->currentURL().isNull()) + // config->writePathEntry("lastURL", m_view->currentURL()); + kdDebug(28000) << "In kooka's saveProperties !" << endl; + config->setGroup( KOOKA_STATE_GROUP ); + config->writeEntry( PREFERENCE_DIA_TAB, m_prefDialogIndex ); + m_view->saveProperties( config ); +} + +void Kooka::readProperties(KConfig *config) +{ + (void) config; + // the 'config' object points to the session managed + // config file. this function is automatically called whenever + // the app is being restored. read in here whatever you wrote + // in 'saveProperties' + config->setGroup( KOOKA_STATE_GROUP ); + m_prefDialogIndex = config->readNumEntry( PREFERENCE_DIA_TAB, 0 ); + // QString url = config->readPathEntry("lastURL"); + +} + +void Kooka::dragEnterEvent(QDragEnterEvent *event) +{ + // accept uri drops only + event->accept(KURLDrag::canDecode(event)); +} + +#if 0 +void Kooka::dropEvent(QDropEvent *event) +{ + // this is a very simplistic implementation of a drop event. we + // will only accept a dropped URL. the Qt dnd code can do *much* + // much more, so please read the docs there + KURL::List uri; + + // see if we can decode a URI.. if not, just ignore it + if (KURLDrag::decode(event, uri) && !uri.isEmpty()) + { + // okay, we have a URI.. process it + const KURL &url = uri.first(); + kdDebug(29000) << "Importing URI " << url.url() << endl; + + // TODO: Do something with url + // Waba: See also setAcceptDrops() above + } +} + +void Kooka::fileNew() +{ + // this slot is called whenever the File->New menu is selected, + // the New shortcut is pressed (usually CTRL+N) or the New toolbar + // button is clicked + + // create a new window + (new Kooka)->show(); +} + +void Kooka::fileOpen() +{ + // this slot is called whenever the File->Open menu is selected, + // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar + // button is clicked +} + +void Kooka::fileSave() +{ + // this slot is called whenever the File->Save menu is selected, + // the Save shortcut is pressed (usually CTRL+S) or the Save toolbar + // button is clicked + + // save the current file +} + + +void Kooka::fileSaveAs() +{ + // this slot is called whenever the File->Save As menu is selected, + QStrList strlist; + strlist.append( "BMP" ); + strlist.append( "JPEG" ); + FormatDialog fd( 0, "FormatDialog", &strlist ); + fd.exec(); + +} +#endif + +void Kooka::filePrint() +{ + // this slot is called whenever the File->Print menu is selected, + // the Print shortcut is pressed (usually CTRL+P) or the Print toolbar + // button is clicked + m_view->print(); + +} + +void Kooka::optionsShowScanParams() +{ + m_view->slSetScanParamsVisible( m_scanParamsAction->isChecked() ); +} + +void Kooka::optionsShowPreviewer() +{ + m_view->slSetTabWVisible( m_previewerAction->isChecked()); +} + +void Kooka::optionsConfigureToolbars() +{ + // use the standard toolbar editor + saveMainWindowSettings(KGlobal::config(), autoSaveGroup()); + KEditToolbar dlg(factory()); + connect(&dlg, SIGNAL(newToolbarConfig()), SLOT(newToolbarConfig())); + dlg.exec(); +} + +void Kooka::newToolbarConfig() +{ + // OK/Apply pressed in the toolbar editor + applyMainWindowSettings(KGlobal::config(), autoSaveGroup()); +} + +void Kooka::optionsPreferences() +{ + // popup some sort of preference dialog, here + KookaPreferences dlg; + dlg.showPage( m_prefDialogIndex ); + connect( &dlg, SIGNAL( dataSaved() ), m_view, SLOT(slFreshUpThumbView())); + + if (dlg.exec()) + { + // redo your settings + m_prefDialogIndex = dlg.activePageIndex(); + // m_view->slFreshUpThumbView(); + } +} + +void Kooka::changeStatusbar(const QString& text) +{ + // display the text on the statusbar + statusBar()->changeItem( text, KookaView::StatusTemp ); +} + +void Kooka::changeCaption(const QString& text) +{ + // display the text on the caption + setCaption(text); +} + +void Kooka::slMirrorVertical( void ) +{ + m_view->slMirrorImage( KookaView::MirrorVertical ); +} + +void Kooka::slMirrorHorizontal( void ) +{ + m_view->slMirrorImage( KookaView::MirrorHorizontal ); +} + +void Kooka::slMirrorBoth( void ) +{ + m_view->slMirrorImage( KookaView::MirrorBoth ); +} + +void Kooka::slRotateClockWise( void ) +{ + m_view->slRotateImage( 90 ); +} + +void Kooka::slRotateCounterClockWise( void ) +{ + m_view->slRotateImage( -90 ); + +} + +void Kooka::slRotate180( void ) +{ + m_view->slRotateImage( 180 ); +} + +void Kooka::slEnableWarnings( ) +{ + KMessageBox::information (this, i18n("All messages and warnings will now be shown.")); + KMessageBox::enableAllMessages(); + kapp->config()->reparseConfiguration(); +} + +#include "kooka.moc" diff --git a/kooka/kooka.desktop b/kooka/kooka.desktop new file mode 100644 index 00000000..19cd3f35 --- /dev/null +++ b/kooka/kooka.desktop @@ -0,0 +1,78 @@ +[Desktop Entry] +Type=Application +Exec=kooka %i %m %U +Icon=scanner +Path= +Terminal=false +DocPath=kooka/index.html +GenericName=Scan & OCR Program +GenericName[af]=Skandeer & Optiese karakter herkenning Program +GenericName[ar]=برنامج للمسح الضوئي +GenericName[bg]=Сканиране +GenericName[bs]=Program za skeniranje i OCR +GenericName[ca]=Programa d'escaneig i OCR +GenericName[cs]=Program pro skenování a OCR +GenericName[cy]=Rhaglen Sganio ac OCR +GenericName[da]=Skanne- & OCR-program +GenericName[de]=Scan- und OCR-Programm +GenericName[el]=Πρόγραμμα Σάρωσης & OCR +GenericName[eo]=Bildbitiga programo kaj tekstrekono +GenericName[es]=OCR y explorador con un escáner +GenericName[et]=Skaneerimise ja OMT rakendus +GenericName[eu]=Eskaneatzeko eta OCR programa +GenericName[fa]=پویش و برنامۀ OCR +GenericName[fi]=Skannaus- ja tekstintunnistusohjelma +GenericName[fr]=Numérisation et reconnaissance de caractères +GenericName[gl]=Programa para escanear e facer OCR +GenericName[he]=תוכנית סריקה וזיהוי תווים אופטי +GenericName[hi]=स्कैन व ऑप्टिकल कैरेक्टर रिकॉग्नीशन प्रोग्राम (OCR) +GenericName[hr]=Program za skaniranje i OCR +GenericName[hu]=Lapolvasó +GenericName[is]=Forrit til að skanna inn myndir +GenericName[it]=Programma di scansione e OCR +GenericName[ja]=スキャン & OCR プログラム +GenericName[kk]=Сканерге түсіру және танып-талдау +GenericName[km]=កម្មវិធី​ស្កេន & OCR +GenericName[lt]=Skanavimo ir teksto atpažinimo programa +GenericName[lv]=Skanēšanas un OCR Programma +GenericName[ms]=Program Imbas & OCR +GenericName[nb]=Et skanne-og OCR-program +GenericName[nds]=Inlees- un OTR-Programm +GenericName[ne]=स्क्यान र OCR कार्यक्रम +GenericName[nl]=Scan- en OCR-programma +GenericName[nn]=Skanne- og tekstattkjenningsprogram +GenericName[pl]=Program do skanowania i rozpoznawania pisma +GenericName[pt]=Programa de Digitalização e OCR +GenericName[pt_BR]=Um programa de Digitalização & OCR +GenericName[ro]=Scanare imagini şi OCR +GenericName[ru]=Сканирование и распознавание текста +GenericName[sk]=Skenovací program s OCR +GenericName[sl]=Program za skeniranje in prepoznavanje znakov +GenericName[sr]=Програм за скенирање и препознавање текста +GenericName[sr@Latn]=Program za skeniranje i prepoznavanje teksta +GenericName[sv]=Bildläsar- och OCR-program +GenericName[ta]=வருடு & OCR நிரலி +GenericName[tg]=Барномаи сканеронӣ ва шиносоии матн +GenericName[th]=โปรแกรมสแกนภาพและ OCR +GenericName[tr]=Tarayıcı ve karakter tanıma programı +GenericName[uk]=Програма сканування та розпізнавання символів +GenericName[ven]=U nanga & Mbekanyamushumo ya OCR +GenericName[wa]=Programe di scanaedje eyet di ricnoxhance di tecse +GenericName[xh]=Udweliso Lwenkqubo Yemita Yovavanyo +GenericName[zh_CN]=扫描和文字识别程序 +GenericName[zh_HK]=掃描和文字辦識程式 +GenericName[zh_TW]=掃描和文字辦識程式 +GenericName[zu]=Scan & OCR Iprogremu +Name=Kooka +Name[ar]=برنامج Kooka +Name[eo]=Kokao +Name[hi]=कूका +Name[is]=Skanni +Name[ko]=쿠카 +Name[ne]=कोओका +Name[pa]=ਕੋਕਾ +Name[ta]=கூக்கா +Name[zh_TW]=Kooka 掃描器 + +X-DCOP-ServiceType=Multi +Categories=Qt;KDE;Graphics; diff --git a/kooka/kooka.h b/kooka/kooka.h new file mode 100644 index 00000000..66f59e0c --- /dev/null +++ b/kooka/kooka.h @@ -0,0 +1,141 @@ +/************************************************************************** + kooka.h - Main program class + ------------------- + begin : Sun Jan 16 2000 + copyright : (C) 2000 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#ifndef KOOKA_H +#define KOOKA_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#define KOOKA_STATE_GROUP "State" +#define PREFERENCE_DIA_TAB "PreferencesTab" + +class KPrinter; +class KToggleAction; +class KActionMenu; +class KookaView; + +/** + * This class serves as the main window for Kooka. It handles the + * menus, toolbars, and status bars. + * + * @short Main window class + * @author Klaas Freitag + * @version 0.1 + */ +class Kooka : public KParts::DockMainWindow +{ + Q_OBJECT +public: + /** + * Default Constructor + */ + Kooka(const QCString& deviceToUse); + + /** + * Default Destructor + */ + ~Kooka(); + + /** + * Startup, loads (at the moment) only the last displayed image + **/ + void startup( void ); + + +protected: + /** + * Overridden virtuals for Qt drag 'n drop (XDND) + */ + virtual void dragEnterEvent(QDragEnterEvent *event); + // virtual void dropEvent(QDropEvent *event); + + /** + * This function is called when it is time for the app to save its + * properties for session management purposes. + */ + void saveProperties(KConfig *); + + /** + * This function is called when this app is restored. The KConfig + * object points to the session management config file that was saved + * with @ref saveProperties + */ + void readProperties(KConfig *); + + +private slots: + + void createMyGUI( KParts::Part* ); + + void filePrint(); + /* ImageViewer-Actions */ + + void optionsShowScanParams(); + void optionsShowPreviewer(); + void optionsConfigureToolbars(); + void optionsPreferences(); + + void changeStatusbar(const QString& text); + void cleanStatusbar(void) { changeStatusbar(""); } + void changeCaption(const QString& text); + void newToolbarConfig(); + + // void fileSaveAs(); + + void slMirrorVertical( void ); + void slMirrorHorizontal( void ); + void slMirrorBoth( void ); + + void slRotateClockWise( void ); + void slRotateCounterClockWise( void ); + void slRotate180( void ); + + void slEnableWarnings(); + +private: + void setupAccel(); + void setupActions(); + +private: + KookaView *m_view; + + KPrinter *m_printer; + KToggleAction *m_scanParamsAction; + KToggleAction *m_previewerAction; + KActionMenu *m_settingsShowDocks; + + KAction *m_saveOCRTextAction; + int m_prefDialogIndex; +}; + +#endif // KOOKA_H diff --git a/kooka/kookaiface.h b/kooka/kookaiface.h new file mode 100644 index 00000000..ab6fcbee --- /dev/null +++ b/kooka/kookaiface.h @@ -0,0 +1,13 @@ +#ifndef KOOKAIFACE_H +#define KOOKAIFACE_H + +#include + +class KookaIface : virtual public DCOPObject +{ + K_DCOP +public: + +}; + +#endif // KOOKAIFACE_H diff --git a/kooka/kookaimage.cpp b/kooka/kookaimage.cpp new file mode 100644 index 00000000..4db87728 --- /dev/null +++ b/kooka/kookaimage.cpp @@ -0,0 +1,413 @@ +/*************************************************************************** + kookaimage.cpp - Kooka's Image + ------------------- + begin : Thu Nov 20 2001 + copyright : (C) 1999 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#include +#include +#include + +#include "kookaimage.h" +#include "config.h" +#ifdef HAVE_LIBTIFF +#include +#include +#endif +/** + *@author Klaas Freitag + */ + + +KookaImage::KookaImage( ) + : QImage(), + m_subImages(-1), + m_subNo(0), + m_parent(0), + m_fileBound(false), + m_tileCols(0) +{ + +} + +/* constructor for subimages */ +KookaImage::KookaImage( int subNo, KookaImage *p ) + : QImage(), + m_subImages(-1), + m_subNo(subNo), + m_parent( p ), + m_fileItem(0L), + m_fileBound(false), + m_tileCols(0) +{ + kdDebug(28000) << "Setting subimageNo to " << subNo << endl; +} + +KookaImage& KookaImage::operator=(const KookaImage& img) +{ + QImage::operator=(img); + + m_subImages = img.subImagesCount(); + m_subNo = img.m_subNo; + m_parent = img.m_parent; + m_url = img.m_url; + m_fileItem = img.m_fileItem; + + return *this; +} + +KookaImage& KookaImage::operator=(const QImage& img) +{ + QImage::operator=(img); + return *this; +} + +KFileItem* KookaImage::fileItem() const +{ + return m_fileItem; +} + +void KookaImage::setFileItem( KFileItem* it ) +{ + m_fileItem = it; +} + +const KFileMetaInfo KookaImage::fileMetaInfo( ) +{ + QString filename = localFileName( ); + if( ! filename.isEmpty() ) + { + kdDebug(28000) << "Fetching metainfo for " << filename << endl; + const KFileMetaInfo info( filename ); + return info; + } + else + return KFileMetaInfo(); +} + +QString KookaImage::localFileName( ) const +{ + + if( ! m_url.isEmpty() ) + return( m_url.directory() + "/" + m_url.fileName()); + else + return QString(); +} + +bool KookaImage::loadFromUrl( const KURL& url ) +{ + bool ret = true; + m_url = url; + QString filename = localFileName( ); + QString format ( imageFormat( filename )); + + /* if the format was not recogniseable, check the extension, if it is tif, try to read it by + * tifflib */ + if( format.isNull() ) + { + if( filename.endsWith( "tif" ) || filename.endsWith( "tiff" ) || + filename.endsWith( "TIF" ) || filename.endsWith( "TIFF" ) ) + { + format = "tif"; + kdDebug(28000) << "Setting format to tif by extension" << endl; + } + } + + kdDebug(28000) << "Image format to load: <" << format << "> from file <" << filename << ">" << endl; + bool haveTiff = false; + + if( !m_url.isLocalFile() ) + { + kdDebug(28000)<<"ERROR: Can not laod non-local images -> not yet implemented!" << endl; + return false; + } + +#ifdef HAVE_LIBTIFF + TIFF* tif = 0; + m_subImages = 0; + + if( format == "tif" || + format == "TIF" || + format == "TIFF" || + format == "tiff" ) + { + /* if it is tiff, check with Tifflib if it is multiple sided */ + kdDebug(28000) << "Trying to load TIFF!" << endl; + tif = TIFFOpen(filename.latin1(), "r"); + if (tif) + { + do { + m_subImages++; + } while (TIFFReadDirectory(tif)); + kdDebug(28000) << m_subImages << " TIFF-directories found" << endl; + + haveTiff = true; + } + } +#endif + if( !haveTiff ) + { + /* Qt can only read one image */ + ret = load(filename); + if( ret ) + { + m_subImages = 0; + m_subNo = 0; + } + } +#ifdef HAVE_LIBTIFF + else + { + loadTiffDir( filename, 0); + /* its a tiff, read by tifflib directly */ + // Find the width and height of the image + } +#endif + + m_fileBound = ret; + return( ret ); +} + + +KookaImage::KookaImage( const QImage& img ) + : QImage( img ) + /* m_subImages( 1 ) */ +{ + m_subImages = 0; + + /* Load one QImage, can not be Tiff yet. */ + kdDebug(28000) << "constructor from other image here " << endl; +} + + +/* loads the number stored in m_subNo */ +void KookaImage::extractNow() +{ + kdDebug(28000) << "extracting a subimage number " << m_subNo << endl; + + KookaImage *parent = parentImage(); + + if( parent ) + { + loadTiffDir( parent->localFileName(), m_subNo ); + } + else + { + kdDebug(28000) << "ERR: No parent defined - can not laod subimage" << endl; + } +} + +KURL KookaImage::url() const +{ + return m_url; +} + +bool KookaImage::loadTiffDir( const QString& filename, int no ) +{ +#ifdef HAVE_LIBTIFF + int imgWidth, imgHeight; + TIFF* tif = 0; + /* if it is tiff, check with Tifflib if it is multiple sided */ + kdDebug(28000) << "Trying to load TIFF, subimage number "<< no << endl; + tif = TIFFOpen(filename.latin1(), "r"); + if (!tif) + return false; + + if( ! TIFFSetDirectory( tif, no ) ) + { + kdDebug(28000) << "ERR: could not set Directory " << no << endl; + TIFFClose(tif); + return false; + } + + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &imgWidth); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imgHeight); + + + /* TODO: load bw-image correctly only 2 bit */ + // KookaImage tmpImg; + create( imgWidth, imgHeight, 32 ); + if (TIFFReadRGBAImage(tif, imgWidth, imgHeight, (uint32*) bits(),0)) + { + // successfully read. now convert. + // reverse red and blue + uint32 *data; + data = (uint32 *)bits(); + for( unsigned i = 0; i < unsigned(imgWidth * imgHeight); ++i ) + { + uint32 red = ( 0x00FF0000 & data[i] ) >> 16; + uint32 blue = ( 0x000000FF & data[i] ) << 16; + data[i] &= 0xFF00FF00; + data[i] += red + blue; + } + + // reverse image (it's upside down) + unsigned h = unsigned(imgHeight); + for( unsigned ctr = 0; ctr < h>>1; ) + { + unsigned *line1 = (unsigned *)scanLine( ctr ); + unsigned *line2 = (unsigned *)scanLine( imgHeight + - ( ++ctr ) ); + + unsigned w = unsigned(imgWidth); + for( unsigned x = 0; x < w; x++ ) + { + int temp = *line1; + *line1 = *line2; + *line2 = temp; + line1++; + line2++; + } + } + } + + /* fetch the x- and y-resolutions to adjust images */ + float xReso, yReso; + bool resosFound; + resosFound = TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xReso ); + resosFound &= TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yReso ); + kdDebug(28000)<< "Tiff image: X-Resol.: " << xReso << " and Y-Resol.: " << yReso << endl; + + TIFFClose(tif); + + /* Check now if resolution in x- and y-direction differ. If so, stretch the image + * accordingly. + */ + if( resosFound && xReso != yReso ) + { + if( xReso > yReso ) + { + float yScalefactor = xReso / yReso; + kdDebug(28000) << "Different resolution x/y, rescaling with factor " << yScalefactor << endl; + /* rescale the image */ + *this = smoothScale( imgWidth, int(imgHeight*yScalefactor), QImage::ScaleFree ); + } + else + { + /* yReso > xReso */ + float scalefactor = yReso / xReso; + kdDebug(28000) << "Different resolution x/y, rescaling x with factor " << scalefactor << endl; + /* rescale the image */ + *this = smoothScale( int(imgWidth*scalefactor), imgHeight, QImage::ScaleFree ); + + } + } + +#endif + return true; +} + + +int KookaImage::subImagesCount() const +{ + return( m_subImages ); +} + +KookaImage::~KookaImage() +{ + +} + +KookaImage* KookaImage::parentImage() const +{ + return( m_parent ); +} + +bool KookaImage::isSubImage() const +{ + return( subImagesCount() ); +} + +/* + * tiling + */ +int KookaImage::cutToTiles( const QSize maxSize, int& rows, int& cols, TileMode ) +{ + QSize imgSize = size(); + + int w = imgSize.width(); + if( w > maxSize.width() ) + { + // image is wider than paper + w = maxSize.width(); + } + int h = imgSize.height(); + if( h > maxSize.height() ) + { + // image is wider than paper + h = maxSize.height(); + } + + int absX = 0; // absolute x position from where to start print + int absY = 0; // on the image, left top corner of the part to print + rows = 0; + + while( h ) // Loop over height, cut in vertical direction + { + rows++; + cols = 0; + while( w ) // Loop over width, cut in horizontal direction + { + cols++; + m_tileVector.append( QRect( absX, absY, w, h )); + + absX += w+1; + w = imgSize.width() - absX; + + // if w < 0, this was the last loop, set w to zero to stop loop + if( w < 0 ) w = 0; + + // if > 0 here, a new page is required + if( w > 0 ) + { + if( w > maxSize.width() ) w = maxSize.width(); + } + } + // Reset the X-values to start on the left border again + absX = 0; + // start with full width again + w = imgSize.width(); + if( w > maxSize.width() ) + w = maxSize.width(); + + absY += h+1; + h = imgSize.height() - absY; + + if( h < 0 ) h = 0; // be sure to meet the break condition + if( h > maxSize.height()) h = maxSize.height(); // limit to page height + } + m_tileCols = cols; + + return m_tileVector.count(); +} + + + +QRect KookaImage::getTileRect( int rowPos, int colPos ) const +{ + int indx = rowPos*m_tileCols+colPos; + kdDebug(28000) << "Tile Index: " << indx << endl; + const QRect r = m_tileVector[(rowPos)*m_tileCols + colPos]; + + return r; +} diff --git a/kooka/kookaimage.h b/kooka/kookaimage.h new file mode 100644 index 00000000..84018d4d --- /dev/null +++ b/kooka/kookaimage.h @@ -0,0 +1,170 @@ +/*************************************************************************** + kookaimage.h - Kooka's Image + ------------------- + begin : Thu Nov 20 2001 + copyright : (C) 1999 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + + + +#ifndef KOOKAIMAGE_H +#define KOOKAIMAGE_H +#include +#include +#include +#include +#include + +#include + +class KFileItem; + +/** + * @author Klaas Freitag + * + * class that represents an image, very much as QImage. But this one can contain + * multiple pages. + */ + +typedef enum { MaxCut, MediumCut } TileMode; + +class KookaImage: public QImage +{ +public: + + KookaImage( ); + /** + * creating a subimage for a parent image. + * @param subNo contains the sequence number of subimages to create. + * @param p is the parent image. + */ + KookaImage( int subNo, KookaImage *p ); + KookaImage( const QImage& img ); + + KookaImage& operator=(const KookaImage& ); + KookaImage& operator=(const QImage& ); + /** + * load an image from a KURL. This method reads the entire file and sets + * the values for subimage count. + */ + bool loadFromUrl( const KURL& ); + + ~KookaImage(); + + /** + * the amount of subimages. This is 0 if there are no subimages. + */ + int subImagesCount() const; + + /** + * the parent image. + */ + KookaImage* parentImage() const; + + /** + * returns true if this is a subimage. + */ + bool isSubImage() const; + + /** + * extracts the correct subimage according to the number given in the constructor. + */ + void extractNow(); + + KURL url() const; + QString localFileName( ) const; + + /** + * Set and get the KFileItem of the image. Note that the KFileItem pointer returned + * may be zero. + */ + KFileItem* fileItem() const; + void setFileItem( KFileItem* ); + + /** + * @return the KFileMetaInfo + **/ + const KFileMetaInfo fileMetaInfo( ); + + /** + * set the url of the kooka image. Note that loadFromUrl sets this + * url automatically. + */ + void setUrl( const KURL& url ) + { m_url = url; } + + /** + * checks if the image is file bound ie. was loaded from file. If this + * method returns false, fileMetaInfo and FileItem are undefined. + */ + bool isFileBound()const { return m_fileBound; } + + /** + * Create tiles on the given image. That is just cut the image in parts + * while non of the parts is larger than maxSize and store the rect list. + * The parameters rows and cols contain the number of rows and cols after + * tiling. If both are one, the image is smaller than maxSize, thus the + * left-top tile is index 1,1. + * Use getTile() to read the QRect list. + */ + int cutToTiles( const QSize maxSize, int& rows, int& cols, TileMode mode = MaxCut ); + + /** + * read tiles from the tile list. The image needs to be tiled by method + * cutToTiles before. + */ + QRect getTileRect( int rowPos, int colPos ) const; + + /** + * retrieve the sub number of this image. + */ + int subNumber() const { return m_subNo; } + +private: + int m_subImages; + bool loadTiffDir( const QString&, int ); + + /* if subNo is 0, the image is the one and only. If it is larger than 0, the + * parent contains the filename */ + int m_subNo; + + /* In case being a subimage */ + KookaImage *m_parent; + KURL m_url; + /* Fileitem if available */ + KFileItem *m_fileItem; + bool m_fileBound; + + QValueVector m_tileVector; + int m_tileCols; /* number of tile columns */ +}; + + +class KookaImageList: public QPtrList +{ +public: + KookaImageList() {} + ~KookaImageList() {} +}; + + +#endif diff --git a/kooka/kookaimagemeta.cpp b/kooka/kookaimagemeta.cpp new file mode 100644 index 00000000..7ba1963d --- /dev/null +++ b/kooka/kookaimagemeta.cpp @@ -0,0 +1,51 @@ +/*************************************************************************** + kookaimage.cpp - Kooka's Image + ------------------- + begin : Thu Nov 20 2001 + copyright : (C) 1999 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#include "kookaimagemeta.h" + +KookaImageMeta::KookaImageMeta( ) : + m_scanResolution(-1), + m_scanResolutionY(-1) +{ + +} + +void KookaImageMeta::setScanResolution( int x, int y) +{ + m_scanResolutionY = y; + m_scanResolution = x; + +} + +int KookaImageMeta::getScanResolutionX() const +{ + return m_scanResolution; +} + +int KookaImageMeta::getScanResolutionY() const +{ + return m_scanResolutionY; +} diff --git a/kooka/kookaimagemeta.h b/kooka/kookaimagemeta.h new file mode 100644 index 00000000..fd269ddd --- /dev/null +++ b/kooka/kookaimagemeta.h @@ -0,0 +1,54 @@ +/*************************************************************************** + kookaimagemeta.h - Kooka's Image Meta Data + ------------------- + begin : Thu Nov 20 2001 + copyright : (C) 1999 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#ifndef KOOKAIMAGEMETA_H +#define KOOKAIMAGEMETA_H + + +/** + * @author Klaas Freitag + * + */ + + +class KookaImageMeta +{ +public: + + KookaImageMeta( ); + ~KookaImageMeta() { ;} + + void setScanResolution( int x, int y=-1); + int getScanResolutionX() const; + int getScanResolutionY() const; + +private: + int m_scanResolution; + int m_scanResolutionY; + +}; + +#endif diff --git a/kooka/kookapref.cpp b/kooka/kookapref.cpp new file mode 100644 index 00000000..c5996275 --- /dev/null +++ b/kooka/kookapref.cpp @@ -0,0 +1,547 @@ +/*************************************************************************** + kookapref.cpp - Kookas preferences dialog + ------------------- + begin : Wed Jan 5 2000 + copyright : (C) 2000 by Klaas Freitag + email : + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + + +#include "kookapref.h" +#include "img_saver.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include "config.h" +#include "thumbview.h" +#include "imageselectline.h" +#include "kscanslider.h" +#include "ksaneocr.h" + +#include +#include +#include +#include + +KookaPreferences::KookaPreferences() + : KDialogBase(IconList, i18n("Preferences"), + Help|Default|Ok|Apply|Cancel, Ok ) +{ + // this is the base class for your preferences dialog. it is now + // a Treelist dialog.. but there are a number of other + // possibilities (including Tab, Swallow, and just Plain) + konf = KGlobal::config (); + + setupStartupPage(); + setupSaveFormatPage(); + setupThumbnailPage(); + setupOCRPage(); +} + +void KookaPreferences::setupOCRPage() +{ + konf->setGroup( CFG_GROUP_OCR_DIA ); + + QFrame *page = addPage( i18n("OCR"), i18n("Optical Character Recognition" ), + BarIcon("ocrImage", KIcon::SizeMedium ) ); + + QVBoxLayout *top = new QVBoxLayout( page, 0, spacingHint() ); + + bool haveGocr = false; + bool haveOcrad = false; + bool haveKadmos = false; + + /* + * Switch ocr engines + */ + QButtonGroup *engGroup = new QButtonGroup( 1, Qt::Horizontal, i18n("OCR Engine to Use"), page ); + m_gocrBut = new QRadioButton( i18n("GOCR engine") , engGroup ); + m_kadmosBut = new QRadioButton( i18n("KADMOS engine"), engGroup ); + m_ocradBut = new QRadioButton( i18n("OCRAD engine"), engGroup ); + m_kadmosBut->setChecked(false); + m_gocrBut->setChecked(false); + m_ocradBut->setChecked(false); + top->addWidget( engGroup ); + + /* + * GOCR Option Box + */ + QVGroupBox *gp = new QVGroupBox( i18n("GOCR OCR"), page ); + m_urlReqGocr = binaryCheckBox( gp, "gocr" ); + connect( m_urlReqGocr, SIGNAL( textChanged( const QString& )), + this, SLOT( slCheckOnGOCR( const QString& ))); + QString cmdGocr = tryFindBinary( "gocr", CFG_GOCR_BINARY ); + kdDebug(28000) << "Found gocr command: " << cmdGocr << endl; + m_gocrBut->setEnabled(false); + if( !cmdGocr.isEmpty() ) + { + /* Found the command */ + m_urlReqGocr->setURL( cmdGocr ); + m_gocrBut->setEnabled(true); + haveGocr = true; + } + top->addWidget( gp ); + + /* + * OCRAD Option Box + */ + gp = new QVGroupBox( i18n("OCRAD OCR"), page ); + m_urlReqOcrad = binaryCheckBox( gp, "ocrad" ); + connect( m_urlReqOcrad, SIGNAL( textChanged( const QString& )), + this, SLOT( slCheckOnOCRAD( const QString& ))); + QString cmdOcrad = tryFindBinary( "ocrad", CFG_OCRAD_BINARY ); + kdDebug(28000) << "Found ocrad command: " << cmdOcrad << endl; + m_ocradBut->setEnabled(false); + if( !cmdOcrad.isEmpty() ) + { + /* Found the command */ + m_urlReqOcrad->setURL( cmdOcrad ); + m_ocradBut->setEnabled(true); + haveOcrad = true; + } + top->addWidget( gp ); + + /* + * Global Kadmos Options + */ + QVGroupBox *kgp = new QVGroupBox( i18n("KADMOS OCR"), page ); + +#ifdef HAVE_KADMOS + (void) new QLabel( i18n("The KADMOS OCR engine is available"), kgp); + m_kadmosBut->setChecked(true); + m_kadmosBut->setEnabled(true); + haveKadmos = true; +#else + (void) new QLabel( i18n("The KADMOS OCR engine is not available in this version of Kooka"), kgp ); + m_kadmosBut->setEnabled(false); +#endif + top->addWidget( kgp ); + QWidget *spaceEater = new QWidget( page ); + spaceEater->setSizePolicy( QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored )); + top->addWidget( spaceEater ); + + /* + * Now read the config value CFG_OCR_ENGINE and set the radios to the value if available + */ + QString useEngine = konf->readEntry( CFG_OCR_ENGINE, "ocrad" ); + if( useEngine != "notFound" ) + { + if( useEngine == "gocr" && haveGocr ) + { + m_gocrBut->setChecked(true); + m_prevOCREngine = "gocr"; + } + else if( useEngine == "ocrad" && haveOcrad ) + { + m_ocradBut->setChecked(true); + m_prevOCREngine = "ocrad"; + } + else if( useEngine == "kadmos" && haveKadmos ) + { + m_kadmosBut->setChecked(true); + m_prevOCREngine = "kadmos"; + } + } +} + +KURLRequester* KookaPreferences::binaryCheckBox( QWidget *parent, const QString& program ) +{ + QHBox *hbox = new QHBox( parent ); + + (void) new QLabel( i18n("Select the %1 binary to use:").arg( program ), hbox ); + KURLRequester* urlRequester = new KURLRequester( parent ); + urlRequester->setMode( KFile::File | KFile::ExistingOnly | KFile::LocalOnly ); + + QToolTip::add( urlRequester, + i18n( "Enter the path to %1, the optical-character-recognition " + "command line tool.").arg(program)); + return urlRequester; +} + + +QString KookaPreferences::tryFindGocr( void ) +{ + return( tryFindBinary( "gocr", CFG_GOCR_BINARY ) ); +} + +QString KookaPreferences::tryFindBinary( const QString& bin, const QString& configKey ) +{ + + /* First check the config files for an entry */ + KConfig *cfg = KGlobal::config(); + cfg->setGroup(CFG_GROUP_OCR_DIA); + QString res = cfg->readPathEntry( configKey /* CFG_GOCR_BINARY */, "notFound" ); + + if( res != "notFound" ) + { + QFileInfo fi( res ); + if( fi.exists() && fi.isExecutable() && !fi.isDir() && res.contains(bin) ) + { + return res; + } + } + + res = QString(); + + QStringList locations; + locations.append( "/usr/bin/" + bin ); + locations.append( "/bin/" + bin ); + locations.append( "/usr/X11R6/bin/"+bin ); + locations.append( "/usr/local/bin/"+bin ); + + for ( QStringList::Iterator it = locations.begin(); it != locations.end(); ++it ) + { + QString cmd = *it; + kdDebug(28000) << "checking command " << cmd << endl; + QFileInfo fi( cmd ); + if( fi.exists() && fi.isExecutable() && !fi.isDir()) + { + res = cmd; + kdDebug(28000) << "found command " << res << endl; + break; + } + } + + return( res ); +} + + +void KookaPreferences::slCheckOnGOCR( const QString& cmd ) +{ + if( checkOCRBinIntern( cmd, "gocr", false )) + { + // cmd exists and is executable + m_gocrBut->setEnabled( true ); + } + else + { + m_gocrBut->setEnabled( false ); + } +} + +void KookaPreferences::slCheckOnOCRAD( const QString& cmd ) +{ + if( checkOCRBinIntern( cmd, "ocrad", false )) + { + // cmd exists and is executable + m_ocradBut->setEnabled( true ); + } + else + { + m_ocradBut->setEnabled( false ); + } +} + +#if 0 +void KookaPreferences::checkOCRBinarySilent( const QString& cmd ) +{ + // checkOCRBinIntern( cmd, this->sender(), false); +} +#endif +bool KookaPreferences::checkOCRBinIntern( const QString& cmd, const QString& tool, bool show_msg ) +{ + if( ! cmd.contains( tool )) return false; + + bool ret = true; + QFileInfo fi( cmd ); + if( ! fi.exists() ) + { + if( show_msg ) + KMessageBox::sorry( this, i18n( "The path does not lead to a valid binary.\n" + "Please check your installation and/or install the program."), + i18n("OCR Software Not Found") ); + ret = false; + } + else + { + /* File exists, check if not dir and executable */ + if( fi.isDir() || (! fi.isExecutable()) ) + { + if( show_msg ) + KMessageBox::sorry( this, i18n( "The program exists, but is not executable.\n" + "Please check your installation and/or install the binary properly."), + i18n("OCR Software Not Executable") ); + ret = false; + } + } + + return ret; +} + + + +void KookaPreferences::setupStartupPage() +{ + + /* startup options */ + konf->setGroup( GROUP_STARTUP ); + + QFrame *page = addPage( i18n("Startup"), i18n("Kooka Startup Preferences" ), + BarIcon("gear", KIcon::SizeMedium ) ); + QVBoxLayout *top = new QVBoxLayout( page, 0, spacingHint() ); + /* Description-Label */ + top->addWidget( new QLabel( i18n("Note that changing these options will affect Kooka's next start!"), page )); + + /* Query for network scanner (Checkbox) */ + cbNetQuery = new QCheckBox( i18n("Query network for available scanners"), + page, "CB_NET_QUERY" ); + QToolTip::add( cbNetQuery, + i18n( "Check this if you want a network query for available scanners.\nNote that this does not mean a query over the entire network but only the stations configured for SANE!" )); + cbNetQuery->setChecked( ! (konf->readBoolEntry( STARTUP_ONLY_LOCAL, false )) ); + + + /* Show scanner selection box on startup (Checkbox) */ + cbShowScannerSelection = new QCheckBox( i18n("Show the scanner selection box on next startup"), + page, "CB_SHOW_SELECTION" ); + QToolTip::add( cbShowScannerSelection, + i18n( "Check this if you once checked 'do not show the scanner selection on startup',\nbut you want to see it again." )); + + cbShowScannerSelection->setChecked( !konf->readBoolEntry( STARTUP_SKIP_ASK, false )); + + /* Read startup image on startup (Checkbox) */ + cbReadStartupImage = new QCheckBox( i18n("Load the last image into the viewer on startup"), + page, "CB_LOAD_ON_START" ); + QToolTip::add( cbReadStartupImage, + i18n( "Check this if you want Kooka to load the last selected image into the viewer on startup.\nIf your images are large, that might slow down Kooka's start." )); + cbReadStartupImage->setChecked( konf->readBoolEntry( STARTUP_READ_IMAGE, true)); + + /* -- */ + + top->addWidget( cbNetQuery ); + top->addWidget( cbShowScannerSelection ); + top->addWidget( cbReadStartupImage ); + + top->addStretch(10); + +} + +void KookaPreferences::setupSaveFormatPage( ) +{ + konf->setGroup( OP_FILE_GROUP ); + QFrame *page = addPage( i18n("Image Saving"), i18n("Configure Image Save Assistant" ), + BarIcon("filesave", KIcon::SizeMedium ) ); + QVBoxLayout *top = new QVBoxLayout( page, 0, spacingHint() ); + + /* Skip the format asking if a format entry exists */ + cbSkipFormatAsk = new QCheckBox( i18n("Always display image save assistant"), + page, "CB_IMGASSIST_QUERY" ); + cbSkipFormatAsk->setChecked( konf->readBoolEntry( OP_FILE_ASK_FORMAT, true )); + QToolTip::add( cbSkipFormatAsk, i18n("Check this if you want to see the image save assistant even if there is a default format for the image type." )); + top->addWidget( cbSkipFormatAsk ); + + cbFilenameAsk = new QCheckBox( i18n("Ask for filename when saving file"), + page, "CB_ASK_FILENAME" ); + cbFilenameAsk->setChecked( konf->readBoolEntry( OP_ASK_FILENAME, false)); + QToolTip::add( cbFilenameAsk, i18n("Check this if you want to enter a filename when an image has been scanned." )); + top->addWidget( cbFilenameAsk ); + + + + top->addStretch(10); +} + +void KookaPreferences::setupThumbnailPage() +{ + konf->setGroup( THUMB_GROUP ); + + QFrame *page = addPage( i18n("Thumbnail View"), i18n("Thumbnail Gallery View" ), + BarIcon("thumbnail", KIcon::SizeMedium ) ); + QVBoxLayout *top = new QVBoxLayout( page, 0, spacingHint() ); + + top->addWidget( new QLabel( i18n("Here you can configure the appearance of the thumbnail view of your scan picture gallery."),page )); + + /* Backgroundimage */ + KStandardDirs stdDir; + QString bgImg = konf->readPathEntry( BG_WALLPAPER ); + if( bgImg.isEmpty() ) + bgImg = stdDir.findResource( "data", STD_TILE_IMG ); + + /* image file selector */ + QVGroupBox *hgb1 = new QVGroupBox( i18n("Thumbview Background" ), page ); + m_tileSelector = new ImageSelectLine( hgb1, i18n("Select background image:")); + kdDebug(28000) << "Setting tile url " << bgImg << endl; + m_tileSelector->setURL( KURL(bgImg) ); + + top->addWidget( hgb1 ); + + /* Add the Boxes to configure size, framestyle and background */ + QVGroupBox *hgb2 = new QVGroupBox( i18n("Thumbnail Size" ), page ); + QVGroupBox *hgb3 = new QVGroupBox( i18n("Thumbnail Frame" ), page ); + + /* Thumbnail size */ + int w = konf->readNumEntry( PIXMAP_WIDTH, 100); + int h = konf->readNumEntry( PIXMAP_HEIGHT, 120 ); + QGrid *lGrid = new QGrid( 2, hgb2 ); + lGrid->setSpacing( 2 ); + QLabel *l1 = new QLabel( i18n("Thumbnail maximum &width:"), lGrid ); + m_thumbWidth = new KIntNumInput( w, lGrid ); + m_thumbWidth->setMinValue(1); + l1->setBuddy( m_thumbWidth ); + + lGrid->setSpacing( 4 ); + l1 = new QLabel( i18n("Thumbnail maximum &height:"), lGrid ); + m_thumbHeight = new KIntNumInput( m_thumbWidth, h, lGrid ); + m_thumbHeight->setMinValue(1); + l1->setBuddy( m_thumbHeight ); + + /* Frame Stuff */ + int frameWidth = konf->readNumEntry( THUMB_MARGIN, 3 ); + QColor col1 = konf->readColorEntry( MARGIN_COLOR1, &(colorGroup().base())); + QColor col2 = konf->readColorEntry( MARGIN_COLOR2, &(colorGroup().foreground())); + + QGrid *fGrid = new QGrid( 2, hgb3 ); + fGrid->setSpacing( 2 ); + l1 = new QLabel(i18n("Thumbnail &frame width:"), fGrid ); + m_frameWidth = new KIntNumInput( frameWidth, fGrid ); + m_frameWidth->setMinValue(0); + l1->setBuddy( m_frameWidth ); + + l1 = new QLabel(i18n("Frame color &1: "), fGrid ); + m_colButt1 = new KColorButton( col1, fGrid ); + l1->setBuddy( m_colButt1 ); + + l1 = new QLabel(i18n("Frame color &2: "), fGrid ); + m_colButt2 = new KColorButton( col2, fGrid ); + l1->setBuddy( m_colButt2 ); + /* TODO: Gradient type */ + + top->addWidget( hgb2, 10); + top->addWidget( hgb3, 10); + top->addStretch(10); + +} + + +void KookaPreferences::slotOk( void ) +{ + slotApply(); + accept(); + +} + + +void KookaPreferences::slotApply( void ) +{ + /* ** startup options ** */ + + /** write the global one, to read from libkscan also */ + konf->setGroup(QString::fromLatin1(GROUP_STARTUP)); + bool cbVal = !(cbShowScannerSelection->isChecked()); + kdDebug(28000) << "Writing for " << STARTUP_SKIP_ASK << ": " << cbVal << endl; + konf->writeEntry( STARTUP_SKIP_ASK, cbVal, true, true ); /* global flag goes to kdeglobals */ + + /* only search for local (=non-net) scanners ? */ + konf->writeEntry( STARTUP_ONLY_LOCAL, !cbNetQuery->isChecked(), true, true ); /* global */ + + /* Should kooka open the last displayed image in the viewer ? */ + if( cbReadStartupImage ) + konf->writeEntry( STARTUP_READ_IMAGE, cbReadStartupImage->isChecked()); + + /* ** Image saver option(s) ** */ + konf->setGroup( OP_FILE_GROUP ); + bool showFormatAssist = cbSkipFormatAsk->isChecked(); + konf->writeEntry( OP_FILE_ASK_FORMAT, showFormatAssist ); + konf->writeEntry( OP_ASK_FILENAME, cbFilenameAsk->isChecked() ); + + /* ** Thumbnail options ** */ + konf->setGroup( THUMB_GROUP ); + konf->writeEntry( PIXMAP_WIDTH, m_thumbWidth->value() ); + konf->writeEntry( PIXMAP_HEIGHT, m_thumbHeight->value() ); + konf->writeEntry( THUMB_MARGIN, m_frameWidth->value() ); + konf->writeEntry( MARGIN_COLOR1, m_colButt1->color()); + konf->writeEntry( MARGIN_COLOR2, m_colButt2->color()); + + KURL bgUrl = m_tileSelector->selectedURL().url(); + bgUrl.setProtocol(""); + kdDebug(28000) << "Writing tile-pixmap " << bgUrl.prettyURL() << endl; + konf->writePathEntry( BG_WALLPAPER, bgUrl.url() ); + + /* ** OCR Options ** */ + konf->setGroup( CFG_GROUP_OCR_DIA ); + QString eng( "gocr" ); + + if( m_ocradBut->isChecked() ) + eng = "ocrad"; + + if( m_kadmosBut && m_kadmosBut->isChecked() ) + eng = "kadmos"; + + if( eng != m_prevOCREngine ) + { + // selection of the ocr engine has changed. Popup button. + KMessageBox::sorry( this, i18n( "The OCR engine settings were changed.\n" + "Note that Kooka needs to be restarted to change the OCR engine."), + i18n("OCR Engine Change") ); + } + + konf->writeEntry(CFG_OCR_ENGINE, eng ); + + QString path = m_urlReqGocr->url(); + if( ! path.isEmpty() ) + konf->writePathEntry( CFG_GOCR_BINARY, path ); + + path = m_urlReqOcrad->url(); + if( ! path.isEmpty() ) + konf->writePathEntry( CFG_OCRAD_BINARY, path ); + + konf->sync(); + + emit dataSaved(); +} + +void KookaPreferences::slotDefault( void ) +{ + cbNetQuery->setChecked( true ); + cbShowScannerSelection->setChecked( true); + cbReadStartupImage->setChecked( true); + cbSkipFormatAsk->setChecked( true ); + KStandardDirs stdDir; + QString bgImg = stdDir.findResource( "data", STD_TILE_IMG ); + m_tileSelector->setURL( KURL(bgImg) ); + m_thumbWidth->setValue( 100 ); + m_thumbHeight->setValue( 120 ); + QColor col1 = QColor( colorGroup().base()); + QColor col2 = QColor( colorGroup().foreground()); + + m_frameWidth->setValue( 3 ); + m_colButt1->setColor( col1 ); + m_colButt2->setColor( col2 ); + m_gocrBut->setChecked(true); +} + + + +#include "kookapref.moc" + diff --git a/kooka/kookapref.h b/kooka/kookapref.h new file mode 100644 index 00000000..c5ab34c0 --- /dev/null +++ b/kooka/kookapref.h @@ -0,0 +1,100 @@ +/*************************************************************************** + kookapref.h - Preferences + ------------------- + begin : Sun Jan 16 2000 + copyright : (C) 2000 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ +#ifndef KOOKAPREF_H +#define KOOKAPREF_H + +#include +#include + +class KConfig; +class QLabel; +class KIntNumInput; +class KColorButton; +class ImageSelectLine; +class KScanEntry; +class QRadioButton; +class KURLRequester; +class QCheckBox; + +#define STARTUP_READ_IMAGE "ReadImageOnStart" +#define CFG_GROUP_OCR_DIA "ocrDialog" +#define CFG_OCRAD_BINARY "ocradBinary" +#define CFG_GOCR_BINARY "gocrBinary" + +class KookaPreferences : public KDialogBase +{ + Q_OBJECT +public: + KookaPreferences(); + static QString tryFindGocr( void ); + static QString tryFindBinary( const QString&, const QString& ); + +public slots: + void slotOk( void ); + void slotApply( void ); + void slotDefault( void ); + +private slots: + bool checkOCRBinIntern( const QString&, const QString&, bool ); + + void slCheckOnGOCR( const QString& ); + void slCheckOnOCRAD( const QString& ); + +signals: + void dataSaved(); + +private: + void setupStartupPage(); + void setupSaveFormatPage(); + void setupThumbnailPage(); + void setupOCRPage(); + KURLRequester* binaryCheckBox( QWidget *, const QString& ); + + QCheckBox *cbNetQuery; + QCheckBox *cbSkipFormatAsk; + QCheckBox *cbFilenameAsk; + QCheckBox *cbShowScannerSelection; + KConfig *konf; + QCheckBox *cbReadStartupImage; + + KIntNumInput *m_thumbWidth; + KIntNumInput *m_thumbHeight; + KIntNumInput *m_frameWidth; + ImageSelectLine *m_tileSelector; + KColorButton *m_colButt1; + KColorButton *m_colButt2; + + KURLRequester *m_urlReqGocr; + KURLRequester *m_urlReqOcrad; + + QRadioButton *m_gocrBut; + QRadioButton *m_kadmosBut; + QRadioButton *m_ocradBut; + QString m_prevOCREngine; +}; + + +#endif // KOOKAPREF_H diff --git a/kooka/kookaprint.cpp b/kooka/kookaprint.cpp new file mode 100644 index 00000000..6e0554e9 --- /dev/null +++ b/kooka/kookaprint.cpp @@ -0,0 +1,410 @@ +/*************************************************************************** + kookaprint.cpp - Printing from the gallery + ------------------- + begin : Tue May 13 2003 + copyright : (C) 1999 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#include "kookaprint.h" +#include "kookaimage.h" +#include +#include +#include +#include +#include "imgprintdialog.h" +#include +#include + +KookaPrint::KookaPrint( KPrinter *printer ) + :QObject(), + m_printer(printer), + m_extraMarginPercent(10) +{ + +} + +bool KookaPrint::printImage( KookaImage *img ) +{ + bool result = true; + if( ! m_printer || !img) return false; + + QString psMode = m_printer->option( OPT_PSGEN_DRAFT ); + kdDebug(28000) << "User setting for quality: " << psMode << endl; + +#if 0 + if( psMode == "1" ) + m_printer->setResolution( 75 ); + else + m_printer->setResolution( 600 ); +#endif + + /* Create painter _after_ setting Resolution */ + QPainter painter(m_printer); + m_painter = &painter; + KookaImage tmpImg; + QPoint pt(0, 0); // the top-left corner (image will be centered) + + // We use a QPaintDeviceMetrics to know the actual page size in pixel, + // this gives the real painting area + QPaintDeviceMetrics printermetrics( m_painter->device() ); + + int screenRes = m_printer->option( OPT_SCREEN_RES ).toInt(); + // int printerRes = printermetrics.logicalDpiX(); + int printerRes = m_printer->resolution(); + + QString scale = m_printer->option( OPT_SCALING ); + + int reso = screenRes; + + if( scale == "scan" ) + { + /* Scale to original size */ + reso = m_printer->option( OPT_SCAN_RES ).toInt(); + } + else if( scale == "custom" ) + { + // kdDebug(28000) << "Not yet implemented: Custom scale" << endl; + double userWidthInch = (m_printer->option( OPT_WIDTH ).toDouble() / 25.4 ); + reso = int( double(img->width()) / userWidthInch ); + + kdDebug(28000) << "Custom resolution: " << reso << endl; + + } + else if( scale == "fitpage" ) + { + kdDebug(28000) << "Printing using maximum space on page" << endl; + printFittingToPage( img ); + reso = 0; // to skip the printing on this page. + } + + /* Scale the image for printing */ + kdDebug(28000) << "Printer-Resolution: " << printerRes << " and scale-Reso: " << reso << endl; + QSize margins = m_printer->margins(); + kdDebug(28000) << "Printer-Margins left: " << margins.width() << " and top " << margins.height() + << endl; + if( reso > 0) + { + double sizeInch = double(img->width()) / double(reso); + int newWidth = int(sizeInch * printerRes); + + printerRes = printermetrics.logicalDpiY(); + sizeInch = double(img->height()) / double(reso); + int newHeight = int(sizeInch * printerRes ); + + kdDebug(28000) << "Scaling to printer size " << newWidth << " x " << newHeight << endl; + + tmpImg = img->smoothScale(newWidth, newHeight, QImage::ScaleFree); + + QSize sz = tmpImg.size(); // the current image size + QSize maxOnPage = maxPageSize(); // the maximum space on one side + + int maxRows, maxCols; + int subpagesCnt = tmpImg.cutToTiles( maxOnPage, maxRows, maxCols ); + + kdDebug(28000) << "Subpages count: " << subpagesCnt << + " Columns:" << maxCols << " Rows:" << maxRows << endl; + + int cnt = 0; + + for( int row = 0; row < maxRows; row++ ) + { + for( int col = 0; col < maxCols; col++ ) + { + const QRect part = tmpImg.getTileRect( row, col ); + const QSize imgSize = part.size(); + + kdDebug(28000) << "Printing part from " << part.x() << "/" << part.y() + << " width:"<< part.width() << " and height " << part.height() << endl; + QImage tileImg = tmpImg.copy( part ); + + m_painter->drawImage( printPosTopLeft(imgSize), tileImg ); + drawCornerMarker( imgSize, row, col, maxRows, maxCols ); + cnt++; + if( cnt < subpagesCnt ) + m_printer->newPage(); + } + } + } + + m_painter = 0; // no, this is not a memory leak. + return result; +} + +void KookaPrint::printFittingToPage(KookaImage *img) +{ + if( ! img || ! m_painter ) return; + + KookaImage tmpImg; + + QString psMode = m_printer->option( OPT_RATIO ); + bool maintainAspect = (psMode == "1"); + + QSize s = maxPageSize(); + + double wAspect = double(s.width()) / double(img->width()); + double hAspect = double(s.height()) / double(img->height()); + + // take the smaller one. + double aspect = wAspect; + if( hAspect < wAspect ) aspect = hAspect; + + // default: maintain aspect ratio. + int newWidth = int( double( img->width() ) * aspect ); + int newHeight = int( double( img->height()) * aspect ); + + if( ! maintainAspect ) + { + newWidth = int( double( img->width() ) * wAspect ); + newHeight = int( double( img->height() ) * hAspect ); + } + + tmpImg = img->smoothScale(newWidth, newHeight, QImage::ScaleFree); + + m_painter->drawImage( 0,0, tmpImg ); + +} + + +void KookaPrint::drawMarkerAroundPoint( const QPoint& p ) +{ + if( ! m_painter ) return; + const int len = 10; + + m_painter->drawLine( p-QPoint(len,0), p+QPoint(len,0)); + m_painter->drawLine( p-QPoint(0,len), p+QPoint(0,len)); + +} + + +void KookaPrint::drawCutSign( const QPoint& p, int num, MarkerDirection dir ) +{ + QBrush saveB = m_painter->brush(); + int start = 0; + const int radius=20; + + QColor brushColor( Qt::red ); + int toffX=0; + int toffY=0; + QString numStr = QString::number(num); + + QFontMetrics fm = m_painter->fontMetrics(); + int textWidth = fm.width( numStr )/2; + int textHeight = fm.width( numStr )/2; + int textYOff = 0; + int textXOff = 0; + switch( dir ) + { + case SW: + start = -90; + brushColor = Qt::green; + toffX =-1; + toffY = 1; + textXOff = -1*textWidth; + textYOff = textHeight; + break; + case NW: + start = -180; + brushColor = Qt::blue; + toffX =-1; + toffY =-1; + textXOff = -1*textWidth; + textYOff = textHeight; + break; + case NO: + start = -270; + brushColor = Qt::yellow; + toffX = 1; + toffY = -1; + textXOff = -1*textWidth; + textYOff = textHeight; + + break; + case SO: + start = 0; + brushColor = Qt::magenta; + toffX = 1; + toffY = 1; + textXOff = -1*textWidth; + textYOff = textHeight; + break; + default: + start = 0; + } + + /* to draw around the point p, subtraction of the half radius is needed */ + int x = p.x()-radius/2; + int y = p.y()-radius/2; + + // m_painter->drawRect( x, y, radius, radius ); /* debug !!! */ + const int tAway = radius*3/4; + + QRect bRect = fm.boundingRect( QString::number(num)); + int textX = p.x()+ tAway * toffX + textXOff; + int textY = p.y()+ tAway * toffY + textYOff; + + // m_painter->drawRect( textX, textY, bRect.width(), bRect.height() ); + kdDebug(28000) << "Drawing to position " << textX << "/" << textY << endl; + m_painter->drawText( textX, + textY, + QString::number(num)); + QBrush b( brushColor, NoBrush /* remove this to get debug color*/ ); + + + m_painter->setBrush( b ); + m_painter->drawPie( x, y, radius, radius, 16*start, -16*90 ); + + m_painter->setBrush( saveB ); +} + + +/* + * draws the circle and the numbers that indicate the pages to glue to the side + */ +void KookaPrint::drawCornerMarker( const QSize& imgSize, int row, int col, int maxRows, int maxCols ) +{ + QPoint p; + + kdDebug(28000) << "Marker: Row: " << row << " and col " << col <<" from max " + << maxRows << "x" << maxCols << endl; + + // Top left. + p = printPosTopLeft( imgSize ); + drawMarkerAroundPoint( p ); + int indx = maxCols*row+col+1; + if( maxRows > 1 || maxCols > 1 ) + { + if( col > 0 ) + drawCutSign( p, indx-1, SW ); + if( row > 0 ) + drawCutSign( p, indx-maxCols, NO ); + + if( row > 0 && col > 0 ) + drawCutSign( p, indx-maxCols-1, NW ); + } + + // Top Right + p = printPosTopRight( imgSize ); + drawMarkerAroundPoint( p ); + if( maxRows > 1 || maxCols > 1 ) + { + if( col < maxCols-1 ) + drawCutSign( p, indx+1, SO ); + if( row > 0 ) + drawCutSign( p, indx-maxCols, NW ); + if( row > 0 && col < maxCols-1 ) + drawCutSign( p, indx-maxCols+1, NO ); + } + + // Bottom Right + p = printPosBottomRight( imgSize ); + if( maxRows > 1 || maxCols > 1 ) + { + if( col < maxCols-1 ) + drawCutSign( p, indx+1, NO ); + if( row < maxRows-1 ) + drawCutSign( p, indx+maxCols, SW ); + if( row < maxRows -1 && col < maxCols-1 ) + drawCutSign( p, indx+maxCols, SO ); + } + + // p += QPoint( 1, 1 ); + drawMarkerAroundPoint( p ); /* at bottom right */ + + /* Bottom left */ + p = printPosBottomLeft( imgSize ); + // p += QPoint( -1, 1 ); + if( maxRows > 1 || maxCols > 1 ) + { + if( col > 0 ) + drawCutSign( p, indx-1, NW ); + if( row < maxRows-1 ) + drawCutSign( p, indx+maxCols, SO ); + if( row < maxRows -1 && col > 0 ) + drawCutSign( p, indx+maxCols-1, SW ); + } + drawMarkerAroundPoint( p ); /* at bottom left */ +} + +QSize KookaPrint::maxPageSize( int extraShrinkPercent ) const +{ + if( ! m_painter ) return QSize(); + QPaintDeviceMetrics printermetrics( m_painter->device() ); + + double extraShrink = double(100-extraShrinkPercent)/100.0; + + QSize retSize( printermetrics.width(), printermetrics.height() ); + + if( extraShrinkPercent > 0 ) + retSize = QSize( int(double(printermetrics.width())* extraShrink) , + int(double(printermetrics.height())* extraShrink )); + return retSize; +} + +int KookaPrint::extraMarginPix() const +{ + QSize max = maxPageSize(); + /* take the half extra margin */ + return int(double(max.width())*double(m_extraMarginPercent) / 100.0 / 2.0); +} + +QPoint KookaPrint::printPosTopLeft( const QSize& imgSize ) const +{ + QSize max = maxPageSize(); + /* take the half extra margin */ + int eMargin = extraMarginPix(); + + return QPoint( eMargin + (max.width() - imgSize.width())/2, + eMargin + (max.height() - imgSize.height())/2 ); +} + +QPoint KookaPrint::printPosTopRight(const QSize& imgSize) const +{ + QSize max = maxPageSize(); + /* take the half extra margin */ + int eMargin = extraMarginPix(); + + return QPoint( eMargin + (max.width() - imgSize.width())/2+imgSize.width(), + eMargin + (max.height() - imgSize.height())/2 ); +} + +QPoint KookaPrint::printPosBottomLeft(const QSize& imgSize) const +{ + QSize max = maxPageSize(); + int eMargin = extraMarginPix(); + /* take the half extra margin */ + return QPoint( eMargin+(max.width() - imgSize.width())/2, + eMargin+(max.height() - imgSize.height())/2 + imgSize.height() ); +} + +QPoint KookaPrint::printPosBottomRight(const QSize& imgSize) const +{ + QSize max = maxPageSize(); + /* take the half extra margin */ + int eMargin = extraMarginPix(); + + return QPoint( eMargin+(max.width() - imgSize.width())/2 + imgSize.width(), + eMargin+(max.height() - imgSize.height())/2 + imgSize.height() ); +} + + + +#include "kookaprint.moc" diff --git a/kooka/kookaprint.h b/kooka/kookaprint.h new file mode 100644 index 00000000..5f87d973 --- /dev/null +++ b/kooka/kookaprint.h @@ -0,0 +1,95 @@ +/*************************************************************************** + kookaprint.h - Printing from the gallery + ------------------- + begin : Tue May 13 2003 + copyright : (C) 1999 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#ifndef __KOOKA_PRINT_H__ +#define __KOOKA_PRINT_H__ + +#include +#include +#include +#include +#include + +class KookaImage; +class KPrinter; +class QPainter; +class KLineEdit; + + +class ImageSettings : public KPrintDialogPage +{ +public: + void setOptions( const QMap& opts ); + void getOptions( QMap& opts, bool include_def = false ); + bool isValid( QString& msg ); + +private: + KLineEdit *m_width, *m_height; + +}; + + +class KookaPrint:public QObject +{ + Q_OBJECT +public: + KookaPrint(KPrinter*); + + /** + * The top left edge of the required print position + */ + virtual QPoint printPosTopLeft(const QSize&) const; + virtual QPoint printPosTopRight(const QSize&) const; + virtual QPoint printPosBottomLeft(const QSize&) const; + virtual QPoint printPosBottomRight(const QSize&) const; + + virtual int extraMarginPix() const; + + /** + * The maximum pixel size of the image (or imagepart) on + * the current page + */ + virtual QSize maxPageSize( int extraShrinkPercent = 0 ) const; + +public slots: + + bool printImage( KookaImage* ); + void printFittingToPage(KookaImage *img); +protected: + typedef enum { SW, NW, NO, SO } MarkerDirection; + + virtual void drawMarkerAroundPoint( const QPoint& ); + virtual void drawCutSign( const QPoint&, int, MarkerDirection ); + virtual void drawCornerMarker( const QSize&, int, int, int, int ); + +private: + + KPrinter *m_printer; + QPainter *m_painter; + int m_extraMarginPercent; +}; + +#endif diff --git a/kooka/kookarc b/kooka/kookarc new file mode 100644 index 00000000..13875fff --- /dev/null +++ b/kooka/kookarc @@ -0,0 +1,121 @@ +[DockSizes] +Kookas MainDock,Preview ,Thumbs:first_name=Kookas MainDock,Preview\s +Kookas MainDock,Preview ,Thumbs:last_name=Thumbs +Kookas MainDock,Preview ,Thumbs:orientation=0 +Kookas MainDock,Preview ,Thumbs:parent=yes +Kookas MainDock,Preview ,Thumbs:sepPos=72 +Kookas MainDock,Preview ,Thumbs:stayButton=false +Kookas MainDock,Preview ,Thumbs:type=GROUP +Kookas MainDock,Preview :curTab=0 +Kookas MainDock,Preview :parent=yes +Kookas MainDock,Preview :stayButton=false +Kookas MainDock,Preview :tabNames=Kookas MainDock,Preview\s +Kookas MainDock,Preview :type=TAB_GROUP +Kookas MainDock,Thumbs,Preview :curTab=1 +Kookas MainDock,Thumbs,Preview :parent=yes +Kookas MainDock,Thumbs,Preview :stayButton=false +Kookas MainDock,Thumbs,Preview :tabNames=Kookas MainDock,Thumbs,Preview\s +Kookas MainDock,Thumbs,Preview :type=TAB_GROUP +Kookas MainDock,Thumbs:curTab=1 +Kookas MainDock,Thumbs:first_name=Kookas MainDock +Kookas MainDock,Thumbs:last_name=Thumbs +Kookas MainDock,Thumbs:orientation=0 +Kookas MainDock,Thumbs:parent=yes +Kookas MainDock,Thumbs:sepPos=54 +Kookas MainDock,Thumbs:stayButton=false +Kookas MainDock,Thumbs:tabNames=Kookas MainDock,Thumbs +Kookas MainDock,Thumbs:type=TAB_GROUP +Kookas MainDock:stayButton=false +Kookas MainDock:type=DOCK +Main:Geometry=40,60,980,760 +Main:dock=Kookas MainDock +Main:view=Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs +Main:visible=false +NameList=Kookas MainDock,Thumbs,Scanpackager,Recent,Scan Parameter,Preview ,Kookas MainDock\\,Preview ,Kookas MainDock\\,Preview \\,Thumbs,Recent\\,Scan Parameter,Scanpackager\\,Recent\\,Scan Parameter,Scanpackager\\,Recent\\,Scan Parameter\\,Kookas MainDock\\,Preview \\,Thumbs +Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:first_name=Preview ,Scanpackager,Recent,Scan Parameter +Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:last_name=Kookas MainDock,Thumbs +Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:orientation=1 +Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:parent=yes +Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:sepPos=38 +Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:stayButton=false +Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:type=GROUP +Preview ,Scanpackager,Recent,Scan Parameter:first_name=Preview ,Scanpackager,Recent +Preview ,Scanpackager,Recent,Scan Parameter:last_name=Scan Parameter +Preview ,Scanpackager,Recent,Scan Parameter:orientation=0 +Preview ,Scanpackager,Recent,Scan Parameter:parent=yes +Preview ,Scanpackager,Recent,Scan Parameter:sepPos=50 +Preview ,Scanpackager,Recent,Scan Parameter:stayButton=false +Preview ,Scanpackager,Recent,Scan Parameter:type=GROUP +Preview ,Scanpackager,Recent:first_name=Preview ,Scanpackager +Preview ,Scanpackager,Recent:last_name=Recent +Preview ,Scanpackager,Recent:orientation=0 +Preview ,Scanpackager,Recent:parent=yes +Preview ,Scanpackager,Recent:sepPos=84 +Preview ,Scanpackager,Recent:stayButton=false +Preview ,Scanpackager,Recent:type=GROUP +Preview ,Scanpackager:first_name=Preview\s +Preview ,Scanpackager:last_name=Scanpackager +Preview ,Scanpackager:orientation=0 +Preview ,Scanpackager:parent=yes +Preview ,Scanpackager:sepPos=50 +Preview ,Scanpackager:stayButton=false +Preview ,Scanpackager:type=GROUP +Preview :stayButton=false +Preview :type=DOCK +Recent,Scan Parameter:first_name=Recent +Recent,Scan Parameter:last_name=Scan Parameter +Recent,Scan Parameter:orientation=0 +Recent,Scan Parameter:parent=yes +Recent,Scan Parameter:sepPos=14 +Recent,Scan Parameter:stayButton=false +Recent,Scan Parameter:type=GROUP +Recent:stayButton=false +Recent:type=DOCK +Scan Parameter:stayButton=false +Scan Parameter:type=DOCK +Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:first_name=Scanpackager,Preview ,Recent,Scan Parameter +Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:last_name=Kookas MainDock,Thumbs +Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:orientation=1 +Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:parent=yes +Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:sepPos=38 +Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:stayButton=false +Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:type=GROUP +Scanpackager,Preview ,Recent,Scan Parameter:first_name=Scanpackager,Preview\s +Scanpackager,Preview ,Recent,Scan Parameter:last_name=Recent,Scan Parameter +Scanpackager,Preview ,Recent,Scan Parameter:orientation=0 +Scanpackager,Preview ,Recent,Scan Parameter:parent=yes +Scanpackager,Preview ,Recent,Scan Parameter:sepPos=48 +Scanpackager,Preview ,Recent,Scan Parameter:stayButton=false +Scanpackager,Preview ,Recent,Scan Parameter:type=GROUP +Scanpackager,Preview :curTab=0 +Scanpackager,Preview :parent=yes +Scanpackager,Preview :stayButton=false +Scanpackager,Preview :tabNames=Scanpackager,Preview\s +Scanpackager,Preview :type=TAB_GROUP +Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:first_name=Scanpackager,Recent,Scan Parameter +Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:last_name=Kookas MainDock,Preview ,Thumbs +Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:orientation=1 +Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:parent=yes +Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:sepPos=41 +Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:stayButton=false +Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:type=GROUP +Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :first_name=Scanpackager,Recent,Scan Parameter +Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :last_name=Kookas MainDock,Thumbs,Preview\s +Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :orientation=1 +Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :parent=yes +Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :sepPos=38 +Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :stayButton=false +Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :type=GROUP +Scanpackager,Recent,Scan Parameter:first_name=Scanpackager +Scanpackager,Recent,Scan Parameter:last_name=Recent,Scan Parameter +Scanpackager,Recent,Scan Parameter:orientation=0 +Scanpackager,Recent,Scan Parameter:parent=yes +Scanpackager,Recent,Scan Parameter:sepPos=42 +Scanpackager,Recent,Scan Parameter:stayButton=false +Scanpackager,Recent,Scan Parameter:type=GROUP +Scanpackager:stayButton=false +Scanpackager:type=DOCK +Thumbs:stayButton=false +Thumbs:type=DOCK +Version=0.0.5 + diff --git a/kooka/kookaui.rc b/kooka/kookaui.rc new file mode 100644 index 00000000..77d3cf4e --- /dev/null +++ b/kooka/kookaui.rc @@ -0,0 +1,62 @@ + + + +

&File + + + + + + + + &Image + + + + + + + + + + + + + + + + + + + + &Settings + + + + + + + + + + + Image Viewer Toolbar + + + + + + + + + + + + + + + + + + + diff --git a/kooka/kookaview.cpp b/kooka/kookaview.cpp new file mode 100644 index 00000000..f1c1d8d0 --- /dev/null +++ b/kooka/kookaview.cpp @@ -0,0 +1,1083 @@ +/*************************************************************************** + kookaview.cpp - kookas visible stuff + ------------------- + begin : ? + copyright : (C) 1999 by Klaas Freitag + email : freitag@suse.de + + $Id$ + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#include "kookaview.h" +#include "resource.h" +#include "kscandevice.h" +#include "imgscaninfo.h" +#include "devselector.h" +#include "ksaneocr.h" +#include "img_saver.h" +#include "kookapref.h" +#include "imgnamecombo.h" +#include "thumbview.h" +#include "dwmenuaction.h" +#include "kookaimage.h" +#include "kookaimagemeta.h" +#include "ocrresedit.h" +#include "kookaprint.h" +#include "imgprintdialog.h" +#if 0 +#include "paramsetdialogs.h" +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +#define STARTUP_IMG_SELECTION "SelectedImageOnStartup" + + +KookaView::KookaView( KParts::DockMainWindow *parent, const QCString& deviceToUse) + : QObject(), + m_ocrResultImg(0), + ocrFabric(0), + m_mainDock(0), + m_dockScanParam(0), + m_dockThumbs(0), + m_dockPackager(0), + m_dockRecent(0), + m_dockPreview(0), + m_dockOCRText(0), + m_mainWindow(parent), + m_ocrResEdit(0) +{ + KIconLoader *loader = KGlobal::iconLoader(); + scan_params = 0L; + preview_canvas = 0L; + + m_mainDock = parent->createDockWidget( "Kookas MainDock", + loader->loadIcon( "folder_image", KIcon::Small ), + 0L, i18n("Image Viewer")); + m_mainDock->setEnableDocking(KDockWidget::DockNone ); + m_mainDock->setDockSite( KDockWidget::DockFullSite ); + + parent->setView( m_mainDock); + parent->setMainDockWidget( m_mainDock); + + img_canvas = new ImageCanvas( m_mainDock ); + img_canvas->setMinimumSize(100,200); + img_canvas->enableContextMenu(true); + connect( img_canvas, SIGNAL( imageReadOnly(bool)), + this, SLOT(slViewerReadOnly(bool))); + + KPopupMenu *ctxtmenu = static_cast(img_canvas->contextMenu()); + if( ctxtmenu ) + ctxtmenu->insertTitle(i18n("Image View")); + m_mainDock->setWidget( img_canvas ); + + /** Thumbview **/ + m_dockThumbs = parent->createDockWidget( "Thumbs", + loader->loadIcon( "thumbnail", KIcon::Small ), + 0L, i18n("Thumbnails")); + m_dockThumbs->setDockSite(KDockWidget::DockFullSite ); + + /* thumbnail viewer widget */ + m_thumbview = new ThumbView( m_dockThumbs); + m_dockThumbs->setWidget( m_thumbview ); + + m_dockThumbs->manualDock( m_mainDock, // dock target + KDockWidget::DockBottom, // dock site + 20 ); // relation target/this (in percent) + + /** Packager Dock **/ + /* A new packager to contain the already scanned images */ + m_dockPackager = parent->createDockWidget( "Scanpackager", + loader->loadIcon( "palette_color", KIcon::Small ), + 0L, i18n("Gallery")); + m_dockPackager->setDockSite(KDockWidget::DockFullSite); + packager = new ScanPackager( m_dockPackager ); + m_dockPackager->setWidget( packager ); + m_dockPackager->manualDock( m_mainDock, // dock target + KDockWidget::DockLeft, // dock site + 30 ); // relation target/this (in percent) + + + connect( packager, SIGNAL(showThumbnails( KFileTreeViewItem* )), + this, SLOT( slShowThumbnails( KFileTreeViewItem* ))); + connect( m_thumbview, SIGNAL( selectFromThumbnail( const KURL& )), + packager, SLOT( slSelectImage(const KURL&))); + + /* + * Create a Kombobox that holds the last folders visible even on the preview page + */ + m_dockRecent = parent->createDockWidget( "Recent", + loader->loadIcon( "image", KIcon::Small ), + 0L, i18n("Gallery Folders")); + + m_dockRecent->setDockSite(KDockWidget::DockFullSite); + + QHBox *recentBox = new QHBox( m_dockRecent ); + recentBox->setMargin(KDialog::marginHint()); + QLabel *lab = new QLabel( i18n("Gallery:"), recentBox ); + lab->setSizePolicy( QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed) ); + recentFolder = new ImageNameCombo( recentBox ); + + m_dockRecent->setWidget( recentBox ); + m_dockRecent->manualDock( m_dockPackager, // dock target + KDockWidget::DockBottom, // dock site + 5 ); // relation target/this (in percent) + + + + connect( packager, SIGNAL( galleryPathSelected( KFileTreeBranch*, const QString&)), + recentFolder, SLOT( slotGalleryPathChanged( KFileTreeBranch*, const QString& ))); + + connect( packager, SIGNAL( directoryToRemove( KFileTreeBranch*, const QString&)), + recentFolder, SLOT( slotPathRemove( KFileTreeBranch*, const QString& ))); + + connect( recentFolder, SIGNAL(activated( const QString& )), + packager, SLOT(slotSelectDirectory( const QString& ))); + + /* the object from the kscan lib to handle low level scanning */ + m_dockScanParam = parent->createDockWidget( "Scan Parameter", + loader->loadIcon( "folder", KIcon::Small ), + 0L, i18n("Scan Parameter")); + // + m_dockScanParam->setDockSite(KDockWidget::DockFullSite); + + m_dockScanParam->setWidget( 0 ); // later + sane = new KScanDevice( m_dockScanParam ); + Q_CHECK_PTR(sane); + + m_dockScanParam->manualDock( m_dockRecent, // dock target + KDockWidget::DockBottom, // dock site + 20 ); // relation target/this (in percent) + m_dockScanParam->hide(); + + /* select the scan device, either user or from config, this creates and assembles + * the complete scanner options dialog + * scan_params must be zero for that */ + + m_dockPreview = parent->createDockWidget( "Preview ", + loader->loadIcon( "viewmag", KIcon::Small ), + 0L, i18n("Scan Preview")); + + preview_canvas = new Previewer( m_dockPreview ); + { + preview_canvas->setMinimumSize( 100,100); + + /* since the scan_params will be created in slSelectDevice, do the + * connections later + */ + } + m_dockPreview->setWidget( preview_canvas ); + m_dockPreview->manualDock( m_mainDock, // dock target + KDockWidget::DockCenter, // dock site + 100 ); // relation target/this (in percent) + + /* Create a text editor part for ocr results */ + + m_dockOCRText = parent->createDockWidget( "OCRResults", + loader->loadIcon("edit", KIcon::Small ), + 0L, i18n("OCR Result Text")); + // m_textEdit + m_ocrResEdit = new ocrResEdit( m_dockOCRText ); + + if( m_ocrResEdit ) + { + m_dockOCRText->setWidget( m_ocrResEdit ); // m_textEdit->widget() ); + m_dockOCRText->manualDock( m_dockThumbs, // dock target + KDockWidget::DockCenter, // dock site + 100 ); // relation target/this (in percent) + + m_ocrResEdit->setTextFormat( Qt::PlainText ); + m_ocrResEdit->setWordWrap( QTextEdit::NoWrap ); + // m_dockOCRText->hide(); + } + + if( slSelectDevice(deviceToUse)) + { + /* Load from config which tab page was selected last time */ + } + + /* New image created after scanning */ + connect(sane, SIGNAL(sigNewImage(QImage*,ImgScanInfo*)), this, SLOT(slNewImageScanned(QImage*,ImgScanInfo*))); + /* New preview image */ + connect(sane, SIGNAL(sigNewPreview(QImage*,ImgScanInfo *)), this, SLOT( slNewPreview(QImage*,ImgScanInfo *))); + + connect( sane, SIGNAL( sigScanStart() ), this, SLOT( slScanStart())); + connect( sane, SIGNAL( sigScanFinished(KScanStat)), this, SLOT(slScanFinished(KScanStat))); + connect( sane, SIGNAL( sigAcquireStart()), this, SLOT( slAcquireStart())); + /* Image canvas should show a new document */ + connect( packager, SIGNAL( showImage( KookaImage* )), + this, SLOT( slShowAImage( KookaImage*))); + + connect( packager, SIGNAL( aboutToShowImage(const KURL&)), + this, SLOT( slStartLoading( const KURL& ))); + + /* Packager unloads the image */ + connect( packager, SIGNAL( unloadImage( KookaImage* )), + this, SLOT( slUnloadAImage( KookaImage*))); + + /* a image changed mostly through a image manipulation method like rotate */ + connect( packager, SIGNAL( fileChanged( KFileItem* )), + m_thumbview, SLOT( slImageChanged( KFileItem* ))); + + connect( packager, SIGNAL( fileRenamed( KFileItem*, const KURL& )), + m_thumbview, SLOT( slImageRenamed( KFileItem*, const KURL& ))); + + connect( packager, SIGNAL( fileDeleted( KFileItem* )), + m_thumbview, SLOT( slImageDeleted( KFileItem* ))); + + + packager->openRoots(); + + /* Status Bar */ + KStatusBar *statBar = m_mainWindow->statusBar(); + + // statBar->insertItem(QString("1"), SBAR_ZOOM, 0, true ); + statBar->insertItem( QString("-"), StatusImage, 0, true ); + + /* Set a large enough size */ + int w = statBar->fontMetrics(). + width(img_canvas->imageInfoString(2000, 2000, 48)); + kdDebug(28000) << "Fixed size for status bar: " << w << " from string " << img_canvas->imageInfoString(2000, 2000, 48) << endl; + statBar->setItemFixed( StatusImage, w ); + +} + + +KookaView::~KookaView() +{ + saveProperties( KGlobal::config () ); + delete preview_canvas; + + kdDebug(28000)<< "Finished saving config data" << endl; +} + +void KookaView::slViewerReadOnly( bool ) +{ + /* retrieve actions that could change the image */ +} + + +bool KookaView::slSelectDevice( const QCString& useDevice ) +{ + + kdDebug(28000) << "Kookaview: select a device!" << endl; + bool haveConnection = false; + + QCString selDevice; + /* in case useDevice is the term 'gallery', the user does not want to + * connect to a scanner, but only work in gallery mode. Otherwise, try + * to read the device to use from config or from a user dialog */ + if( useDevice != "gallery" ) + { + selDevice = useDevice; + if( selDevice.isEmpty()) + { + selDevice = userDeviceSelection(); + } + } + + if( !selDevice.isEmpty() ) + { + kdDebug(28000) << "Opening device " << selDevice << endl; + + if( connectedDevice == selDevice ) { + kdDebug( 28000) << "Device " << selDevice << " is already selected!" << endl; + return( true ); + } + + if( scan_params ) + { + /* This deletes the existing scan_params^-object */ + slCloseScanDevice(); + } + + /* This connects to the selected scanner */ + scan_params = new ScanParams( m_dockScanParam ); + Q_CHECK_PTR(scan_params); + + if( sane->openDevice( selDevice ) == KSCAN_OK ) + { + connect( scan_params, SIGNAL( scanResolutionChanged( int, int )), + preview_canvas, SLOT( slNewScanResolutions( int, int ))); + + if( ! scan_params->connectDevice( sane ) ) + { + kdDebug(28000) << "Connecting to the scanner failed :( ->TODO" << endl; + } + else + { + haveConnection = true; + connectedDevice = selDevice; + + /* New Rectangle selection in the preview, now scanimge exists */ + ImageCanvas *previewCanvas = preview_canvas->getImageCanvas(); + connect( previewCanvas , SIGNAL( newRect(QRect)), + scan_params, SLOT(slCustomScanSize(QRect))); + connect( previewCanvas, SIGNAL( noRect()), + scan_params, SLOT(slMaximalScanSize())); + // connect( scan_params, SIGNAL( scanResolutionChanged( int, int )), + // preview_canvas, SLOT( slNewScanResolutions( int, int ))); + /* load the preview image */ + if( preview_canvas ) + { + preview_canvas->setPreviewImage( sane->loadPreviewImage() ); + + /* Call this after the devic is actually open */ + preview_canvas->slConnectScanner( sane ); + } + } + } + else + { + kdDebug(28000) << "Could not open device <" << selDevice << ">" << endl; + scan_params->connectDevice(0); + } + + /* show the widget again */ + + m_dockScanParam->setWidget( scan_params ); + + m_dockScanParam->show(); + } + else + { + // no devices available or starting in gallery mode + if( scan_params ) + scan_params->connectDevice( 0L ); + } + return( haveConnection ); +} + +QCString KookaView::userDeviceSelection( ) const +{ + /* Human readable scanner descriptions */ + QStringList hrbackends; + + /* a list of backends the scan backend knows */ + QStrList backends = sane->getDevices(); + QStrListIterator it( backends ); + + QCString selDevice; + if( backends.count() > 0 ) + { + while( it ) + { + kdDebug( 28000 ) << "Found backend: " << it.current() << endl; + hrbackends.append( sane->getScannerName( it.current() )); + ++it; + } + + /* allow the user to select one */ + DeviceSelector ds( 0, backends, hrbackends ); + selDevice = ds.getDeviceFromConfig( ); + + if( selDevice.isEmpty() || selDevice.isNull() ) + { + kdDebug(29000) << "selDevice not found - starting selector!" << selDevice << endl; + if ( ds.exec() == QDialog::Accepted ) + { + selDevice = ds.getSelectedDevice(); + } + } + } + return( selDevice ); +} + + +void KookaView::loadStartupImage( void ) +{ + kdDebug( 28000) << "Starting to load startup image" << endl; + + /* Now set the configured stuff */ + KConfig *konf = KGlobal::config (); + if( konf ) + { + konf->setGroup(GROUP_STARTUP); + bool wantReadOnStart = konf->readBoolEntry( STARTUP_READ_IMAGE, true ); + + if( wantReadOnStart ) + { + QString startup = konf->readPathEntry( STARTUP_IMG_SELECTION ); + + if( !startup.isEmpty() ) + { + kdDebug(28000) << "Loading startup image !" << endl; + packager->slSelectImage( KURL(startup) ); + } + } + else + { + kdDebug(28000) << "Do not load startup image due to config value" << endl; + } + } +} + + +void KookaView::print() +{ + /* For now, print a single file. Later, print multiple images to one page */ + KookaImage *img = packager->getCurrImage(); + if ( !img ) + return; + KPrinter printer; // ( true, pMode ); + printer.setUsePrinterResolution(true); + printer.addDialogPage( new ImgPrintDialog( img )); + + if( printer.setup( m_mainWindow, i18n("Print %1").arg(img->localFileName().section('/', -1)) )) + { + KookaPrint kookaprint( &printer ); + kookaprint.printImage(img); + } +} + +void KookaView::slNewPreview( QImage *new_img, ImgScanInfo * ) +{ + if( new_img ) + { + if( ! new_img->isNull() ) + { + /* flip preview to front */ + m_dockPreview->makeDockVisible(); + } + preview_canvas->newImage( new_img ); + } +} + + +bool KookaView::ToggleVisibility( int item ) +{ + QWidget *w = 0; + bool ret = false; + + switch( item ) + { + case ID_VIEW_SCANPARAMS: + w = scan_params; + break; + case ID_VIEW_POOL: + w = preview_canvas; + break; + default: + w = 0; + } + + if( w ) + { + if( w->isVisible() ) + { + w->hide(); + ret = false; + } + else + { + w->show(); + ret = true; + } + } + return ret; +} + + +void KookaView::doOCRonSelection( void ) +{ + emit( signalChangeStatusbar( i18n("Starting OCR on selection" ))); + + KookaImage img; + + if( img_canvas->selectedImage(&img) ) + { + startOCR( &img ); + } + emit( signalCleanStatusbar() ); +} + +/* Does OCR on the entire picture */ +void KookaView::doOCR( void ) +{ + emit( signalChangeStatusbar( i18n("Starting OCR on the entire image" ))); + KookaImage *img = packager->getCurrImage(); + startOCR( img ); + emit( signalCleanStatusbar( )); +} + +void KookaView::startOCR( KookaImage *img ) +{ + if( img && ! img->isNull() ) + { + if( ocrFabric == 0L ) + { + ocrFabric = new KSANEOCR( m_mainDock, KGlobal::config() ); + ocrFabric->setImageCanvas( img_canvas ); + + connect( ocrFabric, SIGNAL( newOCRResultText( const QString& )), + m_ocrResEdit, SLOT(setText( const QString& ))); + + connect( ocrFabric, SIGNAL( newOCRResultText( const QString& )), + m_dockOCRText, SLOT( show() )); + + connect( ocrFabric, SIGNAL( repaintOCRResImage( )), + img_canvas, SLOT(repaint())); + + connect( ocrFabric, SIGNAL( clearOCRResultText()), + m_ocrResEdit, SLOT(clear())); + + connect( ocrFabric, SIGNAL( updateWord(int, const QString&, const QString& )), + m_ocrResEdit, SLOT( slUpdateOCRResult( int, const QString&, const QString& ))); + + connect( ocrFabric, SIGNAL( ignoreWord(int, const ocrWord&)), + m_ocrResEdit, SLOT( slIgnoreWrongWord( int, const ocrWord& ))); + + connect( ocrFabric, SIGNAL( markWordWrong(int, const ocrWord& )), + m_ocrResEdit, SLOT( slMarkWordWrong( int, const ocrWord& ))); + + connect( ocrFabric, SIGNAL( readOnlyEditor( bool )), + m_ocrResEdit, SLOT( setReadOnly( bool ))); + + connect( ocrFabric, SIGNAL( selectWord( int, const ocrWord& )), + m_ocrResEdit, SLOT( slSelectWord( int, const ocrWord& ))); + + } + + Q_CHECK_PTR( ocrFabric ); + ocrFabric->slSetImage( img ); + + if( !ocrFabric->startOCRVisible(m_mainDock) ) + { + KMessageBox::sorry(0, i18n("Could not start OCR-Process.\n" + "Probably there is already one running." )); + + } + } +} + + +void KookaView::slOCRResultImage( const QPixmap& pix ) +{ + kdDebug(28000) << "Showing OCR Result Image" << endl; + if( ! img_canvas ) return; + + if( m_ocrResultImg ) + { + img_canvas->newImage(0L); + delete m_ocrResultImg; + } + + m_ocrResultImg = new QImage(); + *m_ocrResultImg = pix; + img_canvas->newImage( m_ocrResultImg ); + img_canvas->setReadOnly(true); // ocr result images should be read only. +} + +void KookaView::slScanStart( ) +{ + kdDebug(28000) << "Scan starts " << endl; + if( scan_params ) + { + scan_params->setEnabled( false ); + KLed *led = scan_params->operationLED(); + if( led ) + { + led->setColor( Qt::red ); + led->setState( KLed::On ); + } + } +} + +void KookaView::slAcquireStart( ) +{ + kdDebug(28000) << "Acquire starts " << endl; + if( scan_params ) + { + KLed *led = scan_params->operationLED(); + if( led ) + { + led->setColor( Qt::green ); + } + } +} + +void KookaView::slNewImageScanned( QImage* img, ImgScanInfo* si ) +{ + KookaImageMeta *meta = new KookaImageMeta; + meta->setScanResolution(si->getXResolution(), si->getYResolution()); + packager->slAddImage(img, meta); +} + + + +void KookaView::slScanFinished( KScanStat stat ) +{ + kdDebug(28000) << "Scan finished with status " << stat << endl; + if( scan_params ) + { + scan_params->setEnabled( true ); + KLed *led = scan_params->operationLED(); + if( led ) + { + led->setColor( Qt::green ); + led->setState( KLed::Off ); + } + } +} + + +void KookaView::slCloseScanDevice( ) +{ + kdDebug(28000) << "Scanner Device closes down !" << endl; + if( scan_params ) { + delete scan_params; + scan_params = 0; + m_dockScanParam->setWidget(0L); + m_dockScanParam->hide(); + } + + sane->slCloseDevice(); +} + +void KookaView::slCreateNewImgFromSelection() +{ + if( img_canvas->rootImage() ) + { + emit( signalChangeStatusbar( i18n("Create new image from selection" ))); + QImage img; + if( img_canvas->selectedImage( &img ) ) + { + packager->slAddImage( &img ); + } + emit( signalCleanStatusbar( )); + } + +} + + +void KookaView::slRotateImage(int angle) +{ + // QImage *img = (QImage*) img_canvas->rootImage(); + KookaImage *img = packager->getCurrImage(); + bool doUpdate = true; + + if( img ) + { + QImage resImg; + + QApplication::setOverrideCursor(waitCursor); + switch( angle ) + { + case 90: + emit( signalChangeStatusbar( i18n("Rotate image 90 degrees" ))); + resImg = rotateRight( img ); + break; + case 180: + emit( signalChangeStatusbar( i18n("Rotate image 180 degrees" ))); + resImg = rotate180( img ); + break; + case 270: + case -90: + emit( signalChangeStatusbar( i18n("Rotate image -90 degrees" ))); + resImg = rotateLeft( img ); + + break; + default: + kdDebug(28000) << "Not supported yet !" << endl; + doUpdate = false; + + break; + } + QApplication::restoreOverrideCursor(); + + /* updateCurrImage does the status-bar cleanup */ + if( doUpdate ) + updateCurrImage( resImg ); + else + emit(signalCleanStatusbar()); + } + +} + + + +void KookaView::slMirrorImage( MirrorType m ) +{ + const QImage *img = img_canvas->rootImage(); + bool doUpdate = true; + + if( img ) + { + QImage resImg; + + QApplication::setOverrideCursor(waitCursor); + switch( m ) + { + case MirrorVertical: + emit( signalChangeStatusbar( i18n("Mirroring image vertically" ))); + resImg = img->mirror(); + break; + case MirrorHorizontal: + emit( signalChangeStatusbar( i18n("Mirroring image horizontally" ))); + resImg = img->mirror( true, false ); + break; + case MirrorBoth: + emit( signalChangeStatusbar( i18n("Mirroring image in both directions" ))); + resImg = img->mirror( true, true ); + break; + default: + kdDebug(28000) << "Mirroring: no way ;)" << endl; + doUpdate = false; + } + QApplication::restoreOverrideCursor(); + + /* updateCurrImage does the status-bar cleanup */ + if( doUpdate ) + updateCurrImage( resImg ); + else + emit(signalCleanStatusbar()); + + // img_canvas->newImage( ); + } +} + + +void KookaView::slSaveOCRResult() +{ + if( ! m_ocrResEdit ) return; + m_ocrResEdit->slSaveText(); + +} + + +void KookaView::slLoadScanParams( ) +{ + if( ! sane ) return; +#if 0 + /* not yet cooked */ + LoadSetDialog loadDialog( m_mainDock, sane->shortScannerName(), sane ); + if( loadDialog.exec()) + { + kdDebug(28000)<< "Executed successfully" << endl; + } +#endif +} + +void KookaView::slSaveScanParams( ) +{ + if( !sane ) return; + + /* not yet cooked */ +#if 0 + KScanOptSet optSet( "SaveSet" ); + + sane->getCurrentOptions( &optSet ); + SaveSetDialog dialog( m_mainDock /* this */ , &optSet ); + if( dialog.exec()) + { + kdDebug(28000)<< "Executed successfully" << endl; + QString name = dialog.paramSetName(); + QString desc = dialog.paramSetDescription(); + sane->slSaveScanConfigSet( name, desc ); + } +#endif +} + +void KookaView::slShowAImage( KookaImage *img ) +{ + kdDebug(28000) << "Show new Image" << endl; + if( img_canvas ) + { + img_canvas->newImage( img ); + img_canvas->setReadOnly(false); + } + + /* tell ocr about */ + if( ocrFabric ) + { + ocrFabric->slSetImage( img ); + } + + /* Status Bar */ + KStatusBar *statBar = m_mainWindow->statusBar(); + if( img_canvas ) + statBar->changeItem( img_canvas->imageInfoString(), StatusImage ); +} + +void KookaView::slUnloadAImage( KookaImage * ) +{ + kdDebug(28000) << "Unloading Image" << endl; + if( img_canvas ) + { + img_canvas->newImage( 0L ); + } +} + + +void KookaView::slShowThumbnails(KFileTreeViewItem *dirKfi, bool forceRedraw ) +{ + /* If no item is specified, use the current one */ + if( ! dirKfi ) + { + /* do on the current visible dir */ + KFileTreeViewItem *kftvi = packager->currentKFileTreeViewItem(); + if ( !kftvi ) + { + return; + } + + if( kftvi->isDir()) + { + dirKfi = kftvi; + } + else + { + kftvi = static_cast(static_cast(kftvi)->parent()); + dirKfi = kftvi; + forceRedraw = true; + packager->setSelected( static_cast(dirKfi), true ); + } + } + + kdDebug(28000) << "Showing thumbs for " << dirKfi->url().prettyURL() << endl; + + /* Only do the new thumbview if the old is on another dir */ + if( m_thumbview && (forceRedraw || m_thumbview->currentDir() != dirKfi->url()) ) + { + m_thumbview->clear(); + /* Find a list of child KFileItems */ + if( forceRedraw ) m_thumbview->readSettings(); + + KFileItemList fileItemsList; + + QListViewItem * myChild = dirKfi->firstChild(); + while( myChild ) + { + fileItemsList.append( static_cast(myChild)->fileItem()); + myChild = myChild->nextSibling(); + } + + m_thumbview->slNewFileItems( fileItemsList ); + m_thumbview->setCurrentDir( dirKfi->url()); + // m_thumbview->arrangeItemsInGrid(); + } + +} + +/* this slot is called when the user clicks on an image in the packager + * and loading of the image starts + */ +void KookaView::slStartLoading( const KURL& url ) +{ + emit( signalChangeStatusbar( i18n("Loading %1" ).arg( url.prettyURL() ) )); + + // if( m_stack->visibleWidget() != img_canvas ) + // { + // m_stack->raiseWidget( img_canvas ); + // } + +} + + +void KookaView::updateCurrImage( QImage& img ) +{ + if( ! img_canvas->readOnly() ) + { + emit( signalChangeStatusbar( i18n("Storing image changes" ))); + packager->slotCurrentImageChanged( &img ); + emit( signalCleanStatusbar()); + } + else + { + emit( signalChangeStatusbar( i18n("Can not save image, it is write protected!"))); + kdDebug(28000) << "Image is write protected, no saving!" << endl; + } +} + + +void KookaView::saveProperties(KConfig *config) +{ + kdDebug(28000) << "Saving Properties for KookaView !" << endl; + config->setGroup( GROUP_STARTUP ); + /* Get with path */ + config->writePathEntry( STARTUP_IMG_SELECTION, packager->getCurrImageFileName(true)); + +} + + +void KookaView::slOpenCurrInGraphApp( void ) +{ + QString file; + + if( packager ) + { + KFileTreeViewItem *ftvi = packager->currentKFileTreeViewItem(); + + if( ! ftvi ) return; + + kdDebug(28000) << "Trying to open <" << ftvi->url().prettyURL()<< ">" << endl; + KURL::List urllist; + + urllist.append( ftvi->url()); + + KRun::displayOpenWithDialog( urllist ); + } +} + + +QImage KookaView::rotateLeft( QImage *m_img ) +{ + QImage rot; + + if( m_img ) + { + QWMatrix m; + + m.rotate(-90); + rot = m_img->xForm(m); + } + return( rot ); +} + +QImage KookaView::rotateRight( QImage *m_img ) +{ + QImage rot; + + if( m_img ) + { + QWMatrix m; + + m.rotate(+90); + rot = m_img->xForm(m); + } + return( rot ); +} + +QImage KookaView::rotate180( QImage *m_img ) +{ + QImage rot; + + if( m_img ) + { + QWMatrix m; + + m.rotate(+180); + rot = m_img->xForm(m); + } + return( rot ); +} + + + +void KookaView::connectViewerAction( KAction *action ) +{ + QPopupMenu *popup = img_canvas->contextMenu(); + kdDebug(29000) << "This is the popup: " << popup << endl; + if( popup && action ) + { + action->plug( popup ); + } +} + +void KookaView::connectGalleryAction( KAction *action ) +{ + QPopupMenu *popup = packager->contextMenu(); + + if( popup && action ) + { + action->plug( popup ); + } +} + +void KookaView::slFreshUpThumbView() +{ + if( m_thumbview ) + { + /* readSettings returns true if something changes */ + if( m_thumbview->readSettings() ) + { + kdDebug(28000) << "Thumbview-Settings changed, readraw thumbs" << endl; + /* new settings */ + slShowThumbnails(0, true); + } + } +} + +void KookaView::createDockMenu( KActionCollection *col, KDockMainWindow *mainWin, const char * name ) +{ + KActionMenu *actionMenu = new KActionMenu( i18n("Tool Views"), "view_icon", col, name ); + + actionMenu->insert( new dwMenuAction( i18n("Show Image Viewer"), + KShortcut(), m_mainDock, col, + mainWin, "dock_viewer" )); + + actionMenu->insert( new dwMenuAction( i18n("Show Preview"), + KShortcut(), m_dockPreview, col, + mainWin, "dock_preview" )); + + actionMenu->insert( new dwMenuAction( i18n("Show Recent Gallery Folders"), + KShortcut(), m_dockRecent, col, + mainWin, "dock_recent" )); + actionMenu->insert( new dwMenuAction( i18n("Show Gallery"), + KShortcut(), m_dockPackager, col, + mainWin, "dock_gallery" )); + + actionMenu->insert( new dwMenuAction( i18n("Show Thumbnail Window"), + KShortcut(), m_dockThumbs, col, + mainWin, "dock_thumbs" )); + + actionMenu->insert( new dwMenuAction( i18n("Show Scan Parameters"), + KShortcut(), m_dockScanParam, col, + mainWin, "dock_scanparams" )); + + actionMenu->insert( new dwMenuAction( i18n("Show OCR Results"), + KShortcut(), m_dockOCRText, col, + mainWin, "dock_ocrResults" )); +} + + +#include "kookaview.moc" diff --git a/kooka/kookaview.h b/kooka/kookaview.h new file mode 100644 index 00000000..a1f7898a --- /dev/null +++ b/kooka/kookaview.h @@ -0,0 +1,241 @@ +/*************************************************************************** + kookaview.h - Main view + ------------------- + begin : Sun Jan 16 2000 + copyright : (C) 2000 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ +#ifndef KOOKAVIEW_H +#define KOOKAVIEW_H + +#include +#include +#include "kookaiface.h" +#include +#include +#include +#include +#include + +#include +#include + +// application specific includes +#include "kscandevice.h" +#include "previewer.h" +#include "scanpackager.h" +#include "scanparams.h" +#include "img_canvas.h" + +class KDockWidget; +class QPainter; +class KSANEOCR; +class KConfig; +class KPrinter; +class KComboBox; +class KAction; +class KActionCollection; +class ThumbView; +class KookaImage; +class QPixmap; +class ocrResEdit; +/** + * This is the main view class for Kooka. Most of the non-menu, + * non-toolbar, and non-statusbar (e.g., non frame) GUI code should go + * here. + * + * @short Main view + * @author Klaas Freitag + * @version 0.1 + */ +class KookaView : public QObject +{ + Q_OBJECT +public: + typedef enum { MirrorVertical, MirrorHorizontal, MirrorBoth } MirrorType; + typedef enum { StatusTemp, StatusImage } StatusBarIDs; + + /** + * Default constructor + */ + KookaView(KParts::DockMainWindow *parent, const QCString& deviceToUse); + + /** + * Destructor + */ + virtual ~KookaView(); + + /** + * Print this view to any medium -- paper or not + */ + void print( ); + + bool ToggleVisibility( int ); + void loadStartupImage( void ); + KDockWidget *mainDockWidget( ) { return m_mainDock; } + + void createDockMenu( KActionCollection*, KDockMainWindow *, const char *); + + ScanPackager *gallery() { return packager; } + + // KParts::Part* ocrResultPart() { return m_textEdit; } + + ImageCanvas *getImageViewer() { return img_canvas; } +public slots: + void slShowPreview() { } + void slShowPackager() { } + void slNewPreview( QImage *, ImgScanInfo * ); + + void slSetScanParamsVisible( bool v ) + { if( v ) scan_params->show(); else scan_params->hide(); } + void slSetTabWVisible( bool v ) + { if( v ) preview_canvas->show(); else preview_canvas->hide(); } + + void doOCR( void ); + void doOCRonSelection( void ); + + void slStartPreview() { if( scan_params ) scan_params->slAcquirePreview(); } + void slStartFinalScan() { if( scan_params ) scan_params->slStartScan(); } + + void slCreateNewImgFromSelection( void ); + + void slRotateImage( int ); + + void slMirrorImage( MirrorType ); + + void slIVScaleToWidth( void ) + { if( img_canvas ) img_canvas->handle_popup(ImageCanvas::ID_FIT_WIDTH );} + void slIVScaleToHeight( void ) + { if( img_canvas ) img_canvas->handle_popup(ImageCanvas::ID_FIT_HEIGHT );} + void slIVScaleOriginal( void ) + { if( img_canvas ) img_canvas->handle_popup(ImageCanvas::ID_ORIG_SIZE ); } + void slIVShowZoomDialog( ) + { if( img_canvas ) img_canvas->handle_popup(ImageCanvas::ID_POP_ZOOM ); } + + void slOpenCurrInGraphApp( void ); + + void slSaveOCRResult(); + + void slLoadScanParams( ); + void slSaveScanParams( ); + + void slOCRResultImage( const QPixmap& ); + + void slShowThumbnails( KFileTreeViewItem *dirKfi = 0, bool forceRedraw=false); + void slFreshUpThumbView(); + + /** + * slot that show the image viewer + */ + void slStartLoading( const KURL& url ); + /** + * starts ocr on the image the parameter is pointing to + **/ + void startOCR( KookaImage* ); + + void slCloseScanDevice(); + void saveProperties( KConfig* ); + + /** + * slot to select the scanner device. Does all the work with selection + * of scanner, disconnection of the old device and connecting the new. + */ + bool slSelectDevice(const QCString& useDevice=QCString()); + + void connectViewerAction( KAction *action ); + void connectGalleryAction( KAction *action ); + + void slScanStart(); + void slScanFinished( KScanStat stat ); + void slAcquireStart(); + + +protected slots: + + void slShowAImage( KookaImage* ); + void slUnloadAImage( KookaImage* ); + + /** + * called from the scandevice if a new Image was successfully scanned. + * Needs to convert the one-page-QImage to a KookaImage + */ + void slNewImageScanned(QImage*, ImgScanInfo*); + + /** + * called if an viewer image was set to read only or back to read write state. + */ + void slViewerReadOnly( bool ro ); +signals: + /** + * Use this signal to change the content of the statusbar + */ + void signalChangeStatusbar(const QString& text); + + /** + * Use this signal to clean up the statusbar + */ + void signalCleanStatusbar( void ); + + /** + * Use this signal to change the content of the caption + */ + void signalChangeCaption(const QString& text); + +private: + QImage rotateRight( QImage* ); + QImage rotateLeft ( QImage* ); + QImage rotate180 ( QImage* ); + QCString userDeviceSelection( ) const; + + void updateCurrImage( QImage& ) ; + + ImageCanvas *img_canvas; + ThumbView *m_thumbview; + + Previewer *preview_canvas; + ScanPackager *packager; + ScanParams *scan_params; + + KScanDevice *sane; + KComboBox *recentFolder; + + QCString connectedDevice; + + QImage *m_ocrResultImg; + int image_pool_id; + int preview_id; + + KSANEOCR *ocrFabric; + + KDockWidget *m_mainDock; + KDockWidget *m_dockScanParam; + KDockWidget *m_dockThumbs; + KDockWidget *m_dockPackager; + KDockWidget *m_dockRecent; + KDockWidget *m_dockPreview; + KDockWidget *m_dockOCRText; + + KMainWindow *m_mainWindow; + + ocrResEdit *m_ocrResEdit; +}; + +#endif // KOOKAVIEW_H diff --git a/kooka/ksaneocr.cpp b/kooka/ksaneocr.cpp new file mode 100644 index 00000000..cf10d682 --- /dev/null +++ b/kooka/ksaneocr.cpp @@ -0,0 +1,1493 @@ +/*************************************************************************** + ksaneocr.cpp - generic ocr + ------------------- + begin : Fri Jun 30 2000 + copyright : (C) 2000 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +/* $Id$ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "img_saver.h" +#include "kadmosocr.h" +#include "kocrbase.h" +#include "kocrkadmos.h" +#include "kocrocrad.h" +#include "config.h" +#include "ksaneocr.h" +#include "kocrgocr.h" +#include "kookaimage.h" +#include "kookapref.h" +#include "ocrword.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Thread support is disabled here because the kadmos lib seems not to be + * thread save unfortunately. See slotKadmosResult-comments for more information + */ + +KSANEOCR::KSANEOCR( QWidget*, KConfig *cfg ): + m_ocrProcessDia(0L), + daemon(0L), + visibleOCRRunning(false), + m_resultImage(0), + m_imgCanvas(0L), + m_spell(0L), + m_wantKSpell(true), + m_kspellVisible(true), + m_hideDiaWhileSpellcheck(true), + m_spellInitialConfig(0L), + m_parent(0L), + m_ocrCurrLine(0), + m_currHighlight(-1), + m_applyFilter(false), + m_unlinkORF(true) +{ + KConfig *konf = KGlobal::config (); + m_ocrEngine = OCRAD; + m_img = 0L; + m_tmpFile = 0L; + + if( cfg ) + m_hideDiaWhileSpellcheck = cfg->readBoolEntry( HIDE_BASE_DIALOG, true ); + /* + * a initial config is needed as a starting point for the config dialog + * but also for ocr without visible dialog. + */ + m_spellInitialConfig = new KSpellConfig( 0L, 0L ,0L, false ); + + if( konf ) + { + /* -- ocr dialog information -- */ + konf->setGroup( CFG_GROUP_OCR_DIA ); + QString eng = konf->readEntry(CFG_OCR_ENGINE, "ocrad"); + + if( eng == "ocrad" ) + { + m_ocrEngine = OCRAD; + } + else if( eng == "gocr" ) + { + m_ocrEngine = GOCR; + } +#ifdef HAVE_KADMOS + else if( eng == QString("kadmos") ) m_ocrEngine = KADMOS; +#endif + kdDebug(28000) << "OCR engine is " << eng << endl; + + m_unlinkORF = konf->readBoolEntry( CFG_OCR_CLEANUP, true ); + } + + /* resize m_blocks to size 1 since there is at least one block */ + m_blocks.resize(1); + +} + + +KSANEOCR::~KSANEOCR() +{ + if( daemon ) { + delete( daemon ); + daemon = 0; + } + if ( m_tmpFile ) + { + m_tmpFile->setAutoDelete( true ); + delete m_tmpFile; + } + + if( m_resultImage ) + { + delete m_resultImage; + m_resultImage = 0; + } + + if( m_img ) delete m_img; + if( m_spellInitialConfig ) delete m_spellInitialConfig; +} + +/* + * This slot is called to introduce a new image, usually if the user clicks on a + * new image either in the gallery or on the thumbnailview. + */ +void KSANEOCR::slSetImage(KookaImage *img ) +{ + if( ! img ) return ; + + if( m_img ) + delete m_img; + + // FIXME: copy all the image is bad. + m_img = new KookaImage(*img); + + if( m_ocrProcessDia ) + { + m_ocrProcessDia->introduceImage( m_img ); + } + + m_applyFilter = false; +} + +/* + * Request to visualise a line-box in the source image, KADMOS Engine + */ +void KSANEOCR::slLineBox( const QRect& ) +{ + if( ! m_img ) return; +} + + +/* + * starts visual ocr process. Depending on the ocr engine, this function creates + * a new dialog, and shows it. + */ +bool KSANEOCR::startOCRVisible( QWidget *parent ) +{ + if( visibleOCRRunning ) return( false ); + bool res = true; + + m_parent = parent; + + if( m_ocrEngine == GOCR ) + { + m_ocrProcessDia = new KGOCRDialog ( parent, m_spellInitialConfig ); + } + else if( m_ocrEngine == OCRAD ) + { + m_ocrProcessDia = new ocradDialog( parent, m_spellInitialConfig ); + } + else if( m_ocrEngine == KADMOS ) + { +#ifdef HAVE_KADMOS +/*** Kadmos Engine OCR ***/ + m_ocrProcessDia = new KadmosDialog( parent, m_spellInitialConfig ); +#else + KMessageBox::sorry(0, i18n("This version of Kooka was not compiled with KADMOS support.\n" + "Please select another OCR engine in Kooka's options dialog.")); + kdDebug(28000) << "Sorry, this version of Kooka has no KADMOS support" << endl; +#endif /* HAVE_KADMOS */ + } + else + { + kdDebug(28000) << "ERR Unknown OCR engine requested!" << endl; + } + + /* + * this part is independant from the engine again + */ + if( m_ocrProcessDia ) + { + m_ocrProcessDia->setupGui(); + + m_ocrProcessDia->introduceImage( m_img ); + visibleOCRRunning = true; + + connect( m_ocrProcessDia, SIGNAL( user1Clicked()), this, SLOT( startOCRProcess() )); + connect( m_ocrProcessDia, SIGNAL( closeClicked()), this, SLOT( slotClose() )); + connect( m_ocrProcessDia, SIGNAL( user2Clicked()), this, SLOT( slotStopOCR() )); + m_ocrProcessDia->show(); + + } + return( res ); +} + +/** + * This method should be called by the engine specific finish slots. + * It does the not engine dependant cleanups like re-enabling buttons etc. + */ + +void KSANEOCR::finishedOCRVisible( bool success ) +{ + bool doSpellcheck = m_wantKSpell; + + if( m_ocrProcessDia ) + { + m_ocrProcessDia->stopOCR(); + doSpellcheck = m_ocrProcessDia->wantSpellCheck(); + } + + if( success ) + { + QString goof = ocrResultText(); + + emit newOCRResultText(goof); + + if( m_imgCanvas ) + { + if( m_resultImage != 0 ) delete m_resultImage; + kdDebug(28000) << "Result image name: " << m_ocrResultImage << endl; + m_resultImage = new QImage( m_ocrResultImage, "BMP" ); + kdDebug(28000) << "New result image has dimensions: " << m_resultImage->width() << "x" << m_resultImage->height()<< endl; + /* The image canvas is non-zero. Set it to our image */ + m_imgCanvas->newImageHoldZoom( m_resultImage ); + m_imgCanvas->setReadOnly(true); + + /* now handle double clicks to jump to the word */ + m_applyFilter=true; + } + + /** now it is time to invoke the dictionary if required **/ + emit readOnlyEditor( false ); + + if( doSpellcheck ) + { + m_ocrCurrLine = 0; + /* + * create a new kspell object, based on the config of the base dialog + */ + + connect( new KSpell( m_parent, i18n("Kooka OCR Dictionary Check"), + this, SLOT( slSpellReady(KSpell*)), + m_ocrProcessDia->spellConfig() ), + SIGNAL( death()), this, SLOT(slSpellDead())); + } + + delete m_ocrProcessDia; + m_ocrProcessDia = 0L; + + } + + visibleOCRRunning = false; + cleanUpFiles(); + + + kdDebug(28000) << "# ocr finished #" << endl; +} + +/* + * starting the spell check on line m_ocrCurrLine if the line exists. + * If not, the function returns. + */ +void KSANEOCR::startLineSpellCheck() +{ + if( m_ocrCurrLine < m_ocrPage.size() ) + { + m_checkStrings = (m_ocrPage[m_ocrCurrLine]).stringList(); + + /* In case the checklist is empty, call the result slot immediately */ + if( m_checkStrings.count() == 0 ) + { + slCheckListDone(false); + return; + } + + kdDebug(28000)<< "Wordlist (size " << m_ocrPage[m_ocrCurrLine].count() << ", line " << m_ocrCurrLine << "):" << m_checkStrings.join(", ") << endl; + + // if( list.count() > 0 ) + + m_spell->checkList( &m_checkStrings, m_kspellVisible ); + kdDebug(28000)<< "Started!" << endl; + /** + * This call ends in three slots: + * 1. slMisspelling: Hit _before_ the dialog (if any) appears. Time to + * mark the wrong word. + * 2. slSpellCorrected: Hit if the user decided which word to use. + * 3. slCheckListDone: The line is finished. The global counter needs to be + * increased and this function needs to be called again. + **/ + + } + else + { + kdDebug(28000) << k_funcinfo <<" -- no more lines !" << endl; + m_spell->cleanUp(); + } +} + + + +/* User Cancel is called when the user does not really start the + * ocr but uses the cancel-Button to come out of the Dialog */ +void KSANEOCR::slotClose() +{ + kdDebug(28000) << "closing ocr Dialog" << endl; + if( daemon && daemon->isRunning() ) + { + kdDebug(28000) << "Still running - Killing daemon with Sig. 9" << endl; + daemon->kill(9); + } + finishedOCRVisible(false); +} + +void KSANEOCR::slotStopOCR() +{ + kdDebug(28000) << "closing ocr Dialog" << endl; + if( daemon && daemon->isRunning() ) + { + kdDebug(28000) << "Killing daemon with Sig. 9" << endl; + daemon->kill(9); + // that leads to the process being destroyed. + KMessageBox::error(0, i18n("The OCR-process was stopped.") ); + } + +} + +void KSANEOCR::startOCRAD( ) +{ + ocradDialog *ocrDia = static_cast(m_ocrProcessDia); + + m_ocrResultImage = ocrDia->orfUrl(); + const QString cmd = ocrDia->getOCRCmd(); + + // if( m_ocrResultImage.isEmpty() ) + { + /* The url is empty. Start the program to fill up a temp file */ + m_ocrResultImage = ImgSaver::tempSaveImage( m_img, "BMP", 8 ); // m_tmpFile->name(); + kdDebug(28000) << "The new image name is <" << m_ocrResultImage << ">" << endl; + } + + m_ocrImagePBM = ImgSaver::tempSaveImage( m_img, "PBM", 1 ); + + /* temporar file for orf result */ + KTempFile *tmpOrf = new KTempFile( QString(), ".orf" ); + tmpOrf->setAutoDelete( false ); + tmpOrf->close(); + m_tmpOrfName = QFile::encodeName(tmpOrf->name()); + + + if( daemon ) + { + delete( daemon ); + daemon = 0; + } + + daemon = new KProcess; + Q_CHECK_PTR(daemon); + + *daemon << cmd; + *daemon << QString("-x"); + *daemon << m_tmpOrfName; // the orf result file + *daemon << QFile::encodeName( m_ocrImagePBM ); // The name of the image + *daemon << QString("-l"); + *daemon << QString::number( ocrDia->layoutDetectionMode()); + + KConfig *konf = KGlobal::config (); + KConfigGroupSaver( konf, CFG_GROUP_OCRAD ); + + QString format = konf->readEntry( CFG_OCRAD_FORMAT, "utf8"); + *daemon << QString("-F"); + *daemon << format; + + QString charset = konf->readEntry( CFG_OCRAD_CHARSET, "iso-8859-15"); + *daemon << QString("-c"); + *daemon << charset; + + + QString addArgs = konf->readEntry( CFG_OCRAD_EXTRA_ARGUMENTS, QString() ); + + if( !addArgs.isEmpty() ) + { + kdDebug(28000) << "Setting additional args from config for ocrad: " << addArgs << endl; + *daemon << addArgs; + } + + m_ocrResultText = ""; + + connect(daemon, SIGNAL(processExited(KProcess *)), + this, SLOT( ocradExited(KProcess*))); + connect(daemon, SIGNAL(receivedStdout(KProcess *, char*, int)), + this, SLOT( ocradStdIn(KProcess*, char*, int))); + connect(daemon, SIGNAL(receivedStderr(KProcess *, char*, int)), + this, SLOT( ocradStdErr(KProcess*, char*, int))); + + if (!daemon->start(KProcess::NotifyOnExit, KProcess::All)) + { + kdDebug(28000) << "Error starting ocrad-daemon!" << endl; + } + else + { + kdDebug(28000) << "Start OK" << endl; + + } + delete tmpOrf; +} + + +void KSANEOCR::ocradExited(KProcess* ) +{ + kdDebug(28000) << "ocrad exit " << endl; + QString err; + bool parseRes = true; + + if( ! readORF(m_tmpOrfName, err) ) + { + KMessageBox::error( m_parent, + i18n("Parsing of the OCR Result File failed:") + err, + i18n("Parse Problem")); + parseRes = false; + } + finishedOCRVisible( parseRes ); + +} + +void KSANEOCR::ocradStdErr(KProcess*, char* buffer, int buflen) +{ + QString errorBuffer = QString::fromLocal8Bit(buffer, buflen); + kdDebug(28000) << "ocrad says on stderr: " << errorBuffer << endl; + +} + +void KSANEOCR::ocradStdIn(KProcess*, char* buffer, int buflen) +{ + QString errorBuffer = QString::fromLocal8Bit(buffer, buflen); + kdDebug(28000) << "ocrad says on stdin: " << errorBuffer << endl; +} + + + + +/* + * This slot is fired if the user clicks on the 'Start' button of the GUI, no + * difference which engine is active. + */ +void KSANEOCR::startOCRProcess( void ) +{ + if( ! m_ocrProcessDia ) return; + + /* starting the animation, setting fields disabled */ + m_ocrProcessDia->startOCR(); + + kapp->processEvents(); + if( m_ocrEngine == OCRAD ) + { + startOCRAD(); + } + + if( m_ocrEngine == GOCR ) + { + /* + * Starting a gocr process + */ + + KGOCRDialog *gocrDia = static_cast(m_ocrProcessDia); + + const QString cmd = gocrDia->getOCRCmd(); + + /* Save the image to a temp file */ + + /** + * Save images formats: + * Black&White: PBM + * Gray: PGM + * Bunt: PPM + */ + QString format; + if( m_img->depth() == 1 ) + format = "PBM"; + else if( m_img->isGrayscale() ) + format = "PGM"; + else + format = "PPM"; + + QString tmpFile = ImgSaver::tempSaveImage( m_img, format ); // m_tmpFile->name(); + + kdDebug(28000) << "Starting GOCR-Command: " << cmd << " on file " << tmpFile + << ", format " << format << endl; + + if( daemon ) { + delete( daemon ); + daemon = 0; + } + + daemon = new KProcess; + Q_CHECK_PTR(daemon); + m_ocrResultText = ""; + + connect(daemon, SIGNAL(processExited(KProcess *)), + this, SLOT( gocrExited(KProcess*))); + connect(daemon, SIGNAL(receivedStdout(KProcess *, char*, int)), + this, SLOT( gocrStdIn(KProcess*, char*, int))); + connect(daemon, SIGNAL(receivedStderr(KProcess *, char*, int)), + this, SLOT( gocrStdErr(KProcess*, char*, int))); + + QString opt; + *daemon << QFile::encodeName(cmd); + *daemon << "-x"; + *daemon << "-"; + if( !( m_img->numColors() > 0 && m_img->numColors() <3 )) /* not a bw-image */ + { + *daemon << "-l"; + opt.setNum(gocrDia->getGraylevel()); + *daemon << opt; + } + *daemon << "-s"; + opt.setNum(gocrDia->getSpaceWidth()); + *daemon << opt; + *daemon << "-d"; + opt.setNum(gocrDia->getDustsize()); + *daemon << opt; + + // Write an result image + *daemon << "-v"; + *daemon << "32"; + + // Unfortunately this is fixed by gocr. + m_ocrResultImage = "out30.bmp"; + + *daemon << QFile::encodeName(tmpFile); + + m_ocrCurrLine = 0; // Important in gocrStdIn to store the results + + if (!daemon->start(KProcess::NotifyOnExit, KProcess::All)) + { + kdDebug(28000) << "Error starting daemon!" << endl; + } + else + { + kdDebug(28000) << "Start OK" << endl; + + } + } +#ifdef HAVE_KADMOS + if( m_ocrEngine == KADMOS ) + { + KadmosDialog *kadDia = static_cast(m_ocrProcessDia); + + kdDebug(28000) << "Starting Kadmos OCR Engine" << endl; + + QString clasPath; /* target where the clasPath is written in */ + if( ! kadDia->getSelClassifier( clasPath ) ) + { + KMessageBox::error( m_parent, + i18n("The classifier file necessary for OCR cannot be loaded: %1;\n" + "OCR with the KADMOS engine is not possible." ). + arg(clasPath), i18n("KADMOS Installation Problem")); + finishedOCRVisible(false); + return; + } + QCString c = clasPath.latin1(); + + kdDebug(28000) << "Using classifier " << c << endl; + m_rep.Init( c ); + if( m_rep.kadmosError() ) /* check if kadmos initialised OK */ + { + KMessageBox::error( m_parent, + i18n("The KADMOS OCR system could not be started:\n") + + m_rep.getErrorText()+ + i18n("\nPlease check the configuration." ), + i18n("KADMOS Failure") ); + } + else + { + /** Since initialising succeeded, we start the ocr here **/ + m_rep.SetNoiseReduction( kadDia->getNoiseReduction() ); + m_rep.SetScaling( kadDia->getAutoScale() ); + kdDebug(28000) << "Image size " << m_img->width() << " x " << m_img->height() << endl; + kdDebug(28000) << "Image depth " << m_img->depth() << ", colors: " << m_img->numColors() << endl; +#define USE_KADMOS_FILEOP /* use a save-file for OCR instead of filling the reImage struct manually */ +#ifdef USE_KADMOS_FILEOP + m_tmpFile = new KTempFile( QString(), QString("bmp")); + m_tmpFile->setAutoDelete( false ); + m_tmpFile->close(); + QString tmpFile = m_tmpFile->name(); + kdDebug() << "Saving to file " << tmpFile << endl; + m_img->save( tmpFile, "BMP" ); + m_rep.SetImage(tmpFile); +#else + m_rep.SetImage(m_img); +#endif + // rep.Recognize(); + m_rep.run(); + + /* Dealing with threads or no threads (using QT_THREAD_SUPPORT to distinguish) + * If threads are here, the recognition task is started in its own thread. The gui thread + * needs to wait until the recognition thread is finished. Therefore, a timer is fired once + * that calls slotKadmosResult and checks if the recognition task is finished. If it is not, + * a new one-shot-timer is fired in slotKadmosResult. If it is, the OCR result can be + * processed. + * In case the system has no threads, the method start of the recognition engine does not + * return until it is ready, the user has to live with a non responsive gui while + * recognition is performed. The start()-method is implemented as a wrapper to the run() + * method of CRep, which does the recognition job. Instead of pulling up a timer, simply + * the result slot is called if start()=run() has finished. In the result slot, finished() + * is only a dummy always returning true to avoid more preprocessor tags here. + * Hope that works ... + * It does not :( That is why it is not used here. Maybe some day... + */ + } +#ifdef QT_THREAD_SUPPORT + /* start a timer and wait until it fires. */ + QTimer::singleShot( 500, this, SLOT( slotKadmosResult() )); +#else + slotKadmosResult(); +#endif + + } +#endif /* HAVE_KADMOS */ +} + +/* + * This method is called to check if the kadmos process was already finished, if + * thread support is enabled (check for preprocessor variable QT_THREAD_SUPPORT) + * The problem is that the kadmos library seems not to be thread stable so thread + * support should not be enabled by default. In case threads are enabled, this slot + * checks if the KADMOS engine is finished already and if not it fires a timer. + */ + +void KSANEOCR::slotKadmosResult() +{ +#ifdef HAVE_KADMOS + kdDebug(28000) << "check for Recognition finished" << endl; + + + if( m_rep.finished() ) + { + /* The recognition thread is finished. */ + kdDebug(28000) << "kadmos is finished." << endl; + + m_ocrResultText = ""; + if( ! m_rep.kadmosError() ) + { + int lines = m_rep.GetMaxLine(); + kdDebug(28000) << "Count lines: " << lines << endl; + m_ocrPage.clear(); + m_ocrPage.resize( lines ); + + for( int line = 0; line < m_rep.GetMaxLine(); line++ ) + { + // ocrWordList wordList = m_rep.getLineWords(line); + /* call an ocr engine independent method to use the spellbook */ + ocrWordList words = m_rep.getLineWords(line); + kdDebug(28000) << "Have " << words.count() << " entries in list" << endl; + m_ocrPage[line]=words; + } + + /* show results of ocr */ + m_rep.End(); + } + finishedOCRVisible( !m_rep.kadmosError() ); + + } + else + { + /* recognition thread is not yet finished. Wait another half a second. */ + QTimer::singleShot( 500, this, SLOT( slotKadmosResult() )); + /* Never comes here if no threads exist on the system */ + } +#endif /* HAVE_KADMOS */ +} + + + + +/* + * + */ +void KSANEOCR::gocrExited(KProcess* d) +{ + kdDebug(28000) << "daemonExited start !" << endl; + + /* Now all the text of gocr is in the member m_ocrResultText. This one must + * be split up now to m_ocrPage. First break up the lines, resize m_ocrPage + * accordingly and than go through every line and create ocrwords for every + * word. + */ + QStringList lines = QStringList::split( '\n', m_ocrResultText, true ); + + m_ocrPage.clear(); + m_ocrPage.resize( lines.count() ); + + kdDebug(28000) << "RESULT " << m_ocrResultText << " was splitted to lines " << lines.count() << endl; + + unsigned int lineCnt = 0; + + for ( QStringList::Iterator it = lines.begin(); it != lines.end(); ++it ) + { + kdDebug(28000) << "Splitting up line " << *it << endl; + ocrWordList ocrLine; + + QStringList words = QStringList::split( QRegExp( "\\s+" ), *it, false ); + for ( QStringList::Iterator itWord = words.begin(); itWord != words.end(); ++itWord ) + { + kdDebug(28000) << "Appending to results: " << *itWord << endl; + ocrLine.append( ocrWord( *itWord )); + } + m_ocrPage[lineCnt] = ocrLine; + lineCnt++; + } + kdDebug(28000) << "Finished to split!" << endl; + /* set the result pixmap to the result pix of gocr */ + if( ! m_resPixmap.load( m_ocrResultImage ) ) + { + kdDebug(28000) << "Can not load result image!" << endl; + } + + /* load the gocr result image */ + if( m_img ) delete m_img; + m_img = new KookaImage(); + m_img->load( "out30.bmp" ); + + finishedOCRVisible( d->normalExit() ); +} + +/* + * A sample orf snippet: + * + * # Ocr Results File. Created by GNU ocrad version 0.3pre1 + * total blocks 2 + * block 1 0 0 560 344 + * lines 5 + * line 1 chars 10 height 26 + * 71 109 17 26;2,'0'1,'o'0 + * 93 109 15 26;2,'1'1,'l'0 + * 110 109 18 26;1,'2'0 + * 131 109 18 26;1,'3'0 + * 151 109 19 26;1,'4'0 + * 172 109 17 26;1,'5'0 + * 193 109 17 26;1,'6'0 + * 213 108 17 27;1,'7'0 + * 232 109 18 26;1,'8'0 + * 253 109 17 26;1,'9'0 + * line 2 chars 14 height 27 + * + */ + +bool KSANEOCR::readORF( const QString& fileName, QString& errStr ) +{ + QFile file( fileName ); + QRegExp rx; + bool error = false; + + /* use a global line number counter here, not the one from the orf. The orf one + * starts at 0 for every block, but we want line-no counting page global here. + */ + unsigned int lineNo = 0; + int blockCnt = 0; + int currBlock = -1; + + + /* Fetch the numeric version of ocrad */ + ocradDialog *ocrDia = static_cast(m_ocrProcessDia); + int ocradVersion = 0; + if( ocrDia ) + { + ocradVersion = ocrDia->getNumVersion(); + } + + /* clear the ocr result page */ + m_ocrPage.clear(); + kdDebug(28000) << "***** starting to analyse orf at " << fileName << " *****" << endl; + + /* some checks on the orf */ + QFileInfo fi( fileName ); + if( ! fi.exists() ) { + error = true; + errStr = i18n("The orf %1 does not exist.").arg(fileName); + } + if( ! error && ! fi.isReadable() ) { + error = true; + errStr = i18n("Permission denied on file %1.").arg(fileName); + } + + + if ( !error && file.open( IO_ReadOnly ) ) + { + QTextStream stream( &file ); + QString line; + QString recLine; // recognised line + + while ( !stream.atEnd() ) + { + line = stream.readLine().stripWhiteSpace(); // line of text excluding '\n' + int len = line.length(); + + if( ! line.startsWith( "#" )) // Comments + { + kdDebug(28000) << "# Line check |" << line << "|" << endl; + if( line.startsWith( "total blocks " ) ) // total count fo blocks, must be first line + { + blockCnt = line.right( len - 13 /* QString("total blocks ").length() */ ).toInt(); + kdDebug(28000) << "Amount of blocks: " << blockCnt << endl; + m_blocks.resize(blockCnt); + } + else if( line.startsWith( "total text blocks " )) + { + blockCnt = line.right( len - 18 /* QString("total text blocks ").length() */ ).toInt(); + kdDebug(28000) << "Amount of blocks (V. 10): " << blockCnt << endl; + m_blocks.resize(blockCnt); + } + else if( line.startsWith( "block ") || line.startsWith( "text block ") ) + { + rx.setPattern("^.*block\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)"); + if( rx.search( line ) > -1) + { + currBlock = (rx.cap(1).toInt())-1; + kdDebug(28000) << "Setting current block " << currBlock << endl; + QRect r( rx.cap(2).toInt(), rx.cap(3).toInt(), rx.cap(4).toInt(), rx.cap(5).toInt()); + m_blocks[currBlock] = r; + } + else + { + kdDebug(28000) << "WRN: Unknown block line: " << line << endl; + // Not a killing bug + } + } + else if( line.startsWith( "lines " )) + { + int lineCnt = line.right( len - 6 /* QString("lines ").length() */).toInt(); + m_ocrPage.resize(m_ocrPage.size()+lineCnt); + kdDebug(28000) << "Resized ocrPage to linecount " << lineCnt << endl; + } + else if( line.startsWith( "line" )) + { + // line 5 chars 13 height 20 + rx.setPattern("^line\\s+(\\d+)\\s+chars\\s+(\\d+)\\s+height\\s+\\d+" ); + if( rx.search( line )>-1 ) + { + kdDebug(28000) << "RegExp-Result: " << rx.cap(1) << " : " << rx.cap(2) << endl; + int charCount = rx.cap(2).toInt(); + ocrWord word; + QRect brect; + ocrWordList ocrLine; + ocrLine.setBlock(currBlock); + /* Loop over all characters in the line. Every char has it's own line + * defined in the orf file */ + kdDebug(28000) << "Found " << charCount << " chars for line " << lineNo << endl; + + for( int c=0; c < charCount && !stream.atEnd(); c++ ) + { + /* Read one line per character */ + QString charLine = stream.readLine(); + int semiPos = charLine.find(';'); + if( semiPos == -1 ) + { + kdDebug(28000) << "invalid line: " << charLine << endl; + } + else + { + QString rectStr = charLine.left( semiPos ); + QString results = charLine.remove(0, semiPos+1 ); + bool lineErr = false; + + // rectStr contains the rectangle info of for the character + // results contains the real result caracter + + // find the amount of alternatives. + int altCount = 0; + int h = results.find(','); // search the first comma + if( h > -1 ) { + // kdDebug(28000) << "Results of count search: " << results.left(h) << endl; + altCount = results.left(h).toInt(); + results = results.remove( 0, h+1 ).stripWhiteSpace(); + } else { + lineErr = true; + } + // kdDebug(28000) << "Results-line after cutting the alter: " << results << endl; + QChar detectedChar = UndetectedChar; + if( !lineErr ) + { + /* take the first alternative only FIXME */ + if( altCount > 0 ) + detectedChar = results[1]; + // kdDebug(28000) << "Found " << altCount << " alternatives for " + // << QString(detectedChar) << endl; + } + + /* Analyse the rectangle */ + if( ! lineErr && detectedChar != ' ' ) + { + // kdDebug(28000) << "STRING: " << rectStr << "<" << endl; + rx.setPattern( "(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)"); + if( rx.search( rectStr ) != -1 ) + { + /* unite the rectangles */ + QRect privRect( rx.cap(1).toInt(), rx.cap(2).toInt(), + rx.cap(3).toInt(), rx.cap(4).toInt() ); + word.setRect( word.rect() | privRect ); + } + else + { + kdDebug(28000) << "ERR: Unable to read rect info for char!" << endl; + lineErr = true; + } + } + + if( ! lineErr ) + { + /* store word if finished by a space */ + if( detectedChar == ' ' ) + { + /* add the block offset to the rect of the word */ + QRect r = word.rect(); + if( ocradVersion < 10 ) + { + QRect blockRect = m_blocks[currBlock]; + r.moveBy( blockRect.x(), blockRect.y()); + } + + word.setRect( r ); + ocrLine.append( word ); + word = ocrWord(); + } + else + { + word.append( detectedChar ); + } + } + } + } + if( !word.isEmpty() ) + { + /* add the block offset to the rect of the word */ + QRect r = word.rect(); + if( ocradVersion < 10 ) + { + QRect blockRect = m_blocks[currBlock]; + r.moveBy( blockRect.x(), blockRect.y()); + } + word.setRect( r ); + + ocrLine.append( word ); + } + if( lineNo < m_ocrPage.size() ) + { + kdDebug(29000) << "Store result line no " << lineNo << "=\"" << + ocrLine.first() << "..." << endl; + m_ocrPage[lineNo] = ocrLine; + lineNo++; + } + else + { + kdDebug(28000) << "ERR: line index overflow: " << lineNo << endl; + } + } + else + { + kdDebug(28000) << "ERR: Unknown line found: " << line << endl; + } + } + else + { + kdDebug(29000) << "Unknown line: " << line << endl; + } + } /* is a comment? */ + + } + file.close(); + } + return !error; +} + + +void KSANEOCR::cleanUpFiles( void ) +{ + if( m_tmpFile ) + { + delete m_tmpFile; + m_tmpFile = 0L; + } + + if( ! m_ocrResultImage.isEmpty()) + { + kdDebug(28000) << "Unlinking OCR Result image file!" << endl; + unlink(QFile::encodeName(m_ocrResultImage)); + m_ocrResultImage = QString(); + } + + if( ! m_ocrImagePBM.isEmpty()) + { + kdDebug(28000) << "Unlinking OCR PBM file!" << endl; + unlink( QFile::encodeName(m_ocrImagePBM)); + m_ocrImagePBM = QString(); + } + + if( ! m_tmpOrfName.isEmpty() ) + { + if( m_unlinkORF ) + { + unlink(QFile::encodeName(m_tmpOrfName)); + m_tmpOrfName = QString(); + } + else + { + kdDebug(28000) << "Do NOT unlink temp orf file " << m_tmpOrfName << endl; + } + } + + /* Delete the debug images of gocr ;) */ + unlink( "out20.bmp" ); +} + + +void KSANEOCR::gocrStdErr(KProcess*, char* buffer, int buflen) +{ + QString errorBuffer = QString::fromLocal8Bit(buffer, buflen); + kdDebug(28000) << "gocr says: " << errorBuffer << endl; + +} + + +void KSANEOCR::gocrStdIn(KProcess*, char* buffer, int buflen) +{ + QString aux = QString::fromLocal8Bit(buffer, buflen); + + QRegExp rx( "^\\s*\\d+\\s+\\d+"); + if( rx.search( aux ) > -1 ) + { + /* calculate ocr progress for gocr */ + int progress = rx.capturedTexts()[0].toInt(); + int subProgress = rx.capturedTexts()[1].toInt(); + // kdDebug(28000) << "Emitting progress: " << progress << endl; + emit ocrProgress( progress, subProgress ); + } + else + { + m_ocrResultText += aux; + } + + // kdDebug(28000) << aux << endl; + +} + +/* + * Assemble the result text + */ +QString KSANEOCR::ocrResultText() +{ + QString res; + const QString space(" "); + + /* start from the back and search the original word to replace it */ + QValueVector::iterator pageIt; + + for( pageIt = m_ocrPage.begin(); pageIt != m_ocrPage.end(); ++pageIt ) + { + /* thats goes over all lines */ + QValueList::iterator lineIt; + for( lineIt = (*pageIt).begin(); lineIt != (*pageIt).end(); ++lineIt ) + { + res += space + *lineIt; + } + res += "\n"; + } + kdDebug(28000) << "Returning result String " << res << endl; + return res; +} + + +/* -------------------------------------------------------------------------------- + * event filter to filter the mouse events to the image viewer + */ + +void KSANEOCR::setImageCanvas( ImageCanvas *canvas ) +{ + m_imgCanvas = canvas; + + m_imgCanvas->installEventFilter( this ); +} + + +bool KSANEOCR::eventFilter( QObject *object, QEvent *event ) +{ + QWidget *w = (QWidget*) object; + + if( m_applyFilter && m_imgCanvas && w == m_imgCanvas ) + { + if( event->type() == QEvent::MouseButtonDblClick ) + { + QMouseEvent *mev = static_cast(event); + + int x = mev->x(); + int y = mev->y(); + int scale = m_imgCanvas->getScaleFactor(); + + m_imgCanvas->viewportToContents( mev->x(), mev->y(), + x, y ); + + kdDebug(28000) << "Clicked to " << x << "/" << y << ", scale " << scale << endl; + if( scale != 100 ) + { + // Scale is e.g. 50 that means tha the image is only half of size. + // thus the clicked coords must be multiplied with 2 + y = int(double(y)*100/scale); + x = int(double(x)*100/scale); + } + /* now search the word that was clicked on */ + QValueVector::iterator pageIt; + + int line = 0; + bool valid = false; + ocrWord wordToFind; + + for( pageIt = m_ocrPage.begin(); pageIt != m_ocrPage.end(); ++pageIt ) + { + QRect r = (*pageIt).wordListRect(); + + if( y > r.top() && y < r.bottom() ) + { + kdDebug(28000)<< "It is in between " << r.top() << "/" << r.bottom() + << ", line " << line << endl; + valid = true; + break; + } + line++; + } + + /* + * If valid, we have the line into which the user clicked. Now we + * have to find out the actual word + */ + if( valid ) + { + valid = false; + /* find the word in the line and mark it */ + ocrWordList words = *pageIt; + ocrWordList::iterator wordIt; + + for( wordIt = words.begin(); wordIt != words.end() && !valid; ++wordIt ) + { + QRect r = (*wordIt).rect(); + if( x > r.left() && x < r.right() ) + { + wordToFind = *wordIt; + valid = true; + } + } + + } + + /* + * if valid, the wordToFind contains the correct word now. + */ + if( valid ) + { + kdDebug(28000) << "Found the clicked word " << wordToFind << endl; + emit selectWord( line, wordToFind ); + } + + return true; + } + } + return false; +} + + + +/* -------------------------------------------------------------------------------- + * Spellbook support + */ + + +/* + * This slot is hit when the checkWord method of KSpell thinks a word is wrong. + * KSpell detects the correction by itself and delivers it in newword here. + * To see all alternatives KSpell proposes, slMissspelling must be used. + */ +void KSANEOCR::slSpellCorrected( const QString& originalword, + const QString& newword, + unsigned int pos ) +{ + kdDebug(28000) << "Corrected: Original Word " << originalword << " was corrected to " + << newword << ", pos ist " << pos << endl; + + kdDebug(28000) << "Dialog state is " << m_spell->dlgResult() << endl; + + if( slUpdateWord( m_ocrCurrLine, pos, originalword, newword ) ) + { + if( m_imgCanvas && m_currHighlight > -1 ) + { + if( m_applyFilter ) + m_imgCanvas->removeHighlight( m_currHighlight ); + } + else + { + kdDebug(28000) << "No highlighting to remove!" << endl; + } + } + +} + + +void KSANEOCR::slSpellIgnoreWord( const QString& word ) +{ + ocrWord ignoreOCRWord; + + ignoreOCRWord = ocrWordFromKSpellWord( m_ocrCurrLine, word ); + if( ! ignoreOCRWord.isEmpty() ) + { + emit ignoreWord( m_ocrCurrLine, ignoreOCRWord ); + + if( m_imgCanvas && m_currHighlight > -1 ) + { + m_imgCanvas->removeHighlight( m_currHighlight ); + + /* create a new highlight. That will never be removed */ + QBrush brush; + QPen pen( gray, 1 ); + QRect r = ignoreOCRWord.rect(); + r.moveBy(0,2); // a bit offset to the top + + if( m_applyFilter ) + m_imgCanvas->highlight( r, pen, brush ); + } + } +} + +ocrWord KSANEOCR::ocrWordFromKSpellWord( int line, const QString& word ) +{ + ocrWord resWord; + if( lineValid(line) ) + { + ocrWordList words = m_ocrPage[line]; + + words.findFuzzyIndex( word, resWord ); + } + + return resWord; +} + + +bool KSANEOCR::lineValid( int line ) +{ + bool ret = false; + + if( line >= 0 && (uint)line < m_ocrPage.count() ) + ret = true; + + return ret; +} + +void KSANEOCR::slMisspelling( const QString& originalword, const QStringList& suggestions, + unsigned int pos ) +{ + /* for the first try, use the first suggestion */ + ocrWord s( suggestions.first()); + kdDebug(28000) << "Misspelled: " << originalword << " at position " << pos << endl; + + int line = m_ocrCurrLine; + m_currHighlight = -1; + + // ocrWord resWord = ocrWordFromKSpellWord( line, originalword ); + ocrWordList words = m_ocrPage[line]; + ocrWord resWord; + kdDebug(28000) << "Size of wordlist (line " << line << "): " << words.count() << endl; + + if( pos < words.count() ) + { + resWord = words[pos]; + } + + if( ! resWord.isEmpty() ) + { + QBrush brush; + brush.setColor( QColor(red)); // , "Dense4Pattern" ); + brush.setStyle( Qt::Dense4Pattern ); + QPen pen( red, 2 ); + QRect r = resWord.rect(); + + r.moveBy(0,2); // a bit offset to the top + + if( m_applyFilter ) + m_currHighlight = m_imgCanvas->highlight( r, pen, brush, true ); + + kdDebug(28000) << "Position ist " << r.x() << ", " << r.y() << ", width: " + << r.width() << ", height: " << r.height() << endl; + + /* draw a line under the word to check */ + + /* copy the source */ + emit repaintOCRResImage(); + } + else + { + kdDebug(28000) << "Could not find the ocrword for " << originalword << endl; + } + + emit markWordWrong( line, resWord ); +} + +/* + * This is the global starting point for spell checking of the ocr result. + * After the KSpell object was created in method finishedOCRVisible, this + * slot is called if the KSpell-object feels itself ready for operation. + * Coming into this slot, the spelling starts in a line by line manner + */ +void KSANEOCR::slSpellReady( KSpell *spell ) +{ + m_spell = spell; + connect ( m_spell, SIGNAL( misspelling( const QString&, const QStringList&, + unsigned int )), + this, SLOT( slMisspelling(const QString& , + const QStringList& , + unsigned int ))); + connect( m_spell, SIGNAL( corrected ( const QString&, const QString&, unsigned int )), + this, SLOT( slSpellCorrected( const QString&, const QString&, unsigned int ))); + + connect( m_spell, SIGNAL( ignoreword( const QString& )), + this, SLOT( slSpellIgnoreWord( const QString& ))); + + connect( m_spell, SIGNAL( done(bool)), this, SLOT(slCheckListDone(bool))); + + kdDebug(28000) << "Spellcheck available" << endl; + + if( m_ocrProcessDia && m_hideDiaWhileSpellcheck ) + m_ocrProcessDia->hide(); + emit readOnlyEditor( true ); + startLineSpellCheck(); +} + +/** + * slot called after either the spellcheck finished or the KSpell object found + * out that it does not want to run because of whatever problems came up. + * If it is an KSpell-init problem, the m_spell variable is still zero and + * Kooka pops up a warning. + */ +void KSANEOCR::slSpellDead() +{ + if( ! m_spell ) + { + kdDebug(28000) << "Spellcheck NOT available" << endl; + /* Spellchecking has not yet been existing, thus there is a base problem with + * spellcheck on this system. + */ + KMessageBox::error( m_parent, + i18n("Spell-checking cannot be started on this system.\n" + "Please check the configuration" ), + i18n("Spell-Check") ); + + } + else + { + if( m_spell->status() == KSpell::Cleaning ) + { + kdDebug(28000) << "KSpell cleans up" << endl; + } + else if( m_spell->status() == KSpell::Finished ) + { + kdDebug(28000) << "KSpell finished" << endl; + } + else if( m_spell->status() == KSpell::Error ) + { + kdDebug(28000) << "KSpell finished with Errors" << endl; + } + else if( m_spell->status() == KSpell::Crashed ) + { + kdDebug(28000) << "KSpell Chrashed" << endl; + } + else + { + kdDebug(28000) << "KSpell finished with unknown state!" << endl; + } + + /* save the current config */ + delete m_spell; + m_spell = 0L; + + /* reset values */ + m_checkStrings.clear(); + m_ocrCurrLine = 0; + if( m_imgCanvas && m_currHighlight > -1 ) + m_imgCanvas->removeHighlight( m_currHighlight ); + + } + if( m_ocrProcessDia ) + m_ocrProcessDia->show(); + emit readOnlyEditor( false ); +} + + +/** + * This slot reads the current line from the member m_ocrCurrLine and + * writes the corrected wordlist to the member page word lists + */ +void KSANEOCR::slCheckListDone(bool) +{ + + /* + * nothing needs to be updated here in the texts, because it is already done + * in the slSpellCorrected slot + */ + + /* Check the dialog state here */ + if( m_spell->dlgResult() == KS_CANCEL || + m_spell->dlgResult() == KS_STOP ) + { + /* stop processing */ + m_spell->cleanUp(); + } + else + { + m_ocrCurrLine++; + kdDebug(28000) << "Starting spellcheck from CheckListDone" << endl; + startLineSpellCheck(); + } +} + +/** + * updates the word at position spellWordIndx in line line to the new word newWord. + * The original word was origWord. This slot is called from slSpellCorrected + * + */ +bool KSANEOCR::slUpdateWord( int line, int spellWordIndx, const QString& origWord, + const QString& newWord ) +{ + bool result = false; + + if( lineValid( line )) + { + ocrWordList words = m_ocrPage[line]; + kdDebug(28000) << "Updating word " << origWord << " to " << newWord << endl; + + if( words.updateOCRWord( words[spellWordIndx] /* origWord */, newWord ) ) // searches for the word and updates + { + result = true; + emit updateWord( line, origWord, newWord ); + } + else + kdDebug(28000) << "WRN: Update from " << origWord << " to " << newWord << " failed" << endl; + + } + else + { + kdDebug(28000) << "WRN: Line " << line << " no not valid!" << endl; + } + return result; +} + + +char KSANEOCR::UndetectedChar = '_'; + +/* -- */ +#include "ksaneocr.moc" diff --git a/kooka/ksaneocr.h b/kooka/ksaneocr.h new file mode 100644 index 00000000..425718dc --- /dev/null +++ b/kooka/ksaneocr.h @@ -0,0 +1,285 @@ +/*************************************************************************** + ksaneocr.h - ocr-engine class + ------------------- + begin : Fri Jun 30 2000 + copyright : (C) 2000 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#ifndef KSANEOCR_H +#define KSANEOCR_H +#include +#include + +#include "ocrword.h" + +#define CFG_OCR_ENGINE "ocrEngine" +#define CFG_OCR_CLEANUP "unlinkORF" /* delete orf file? */ + +#define CFG_OCR_KSPELL "ocrSpellSettings" +#define CFG_WANT_KSPELL "ocrKSpellEnabled" +#define CFG_KS_NOROOTAFFIX "KSpell_NoRootAffix" +#define CFG_KS_RUNTOGETHER "KSpell_RunTogether" +#define CFG_KS_DICTIONARY "KSpell_Dictionary" +#define CFG_KS_DICTFROMLIST "KSpell_DictFromList" +#define CFG_KS_ENCODING "KSpell_Encoding" +#define CFG_KS_CLIENT "KSpell_Client" + + +#define HIDE_BASE_DIALOG "hideOCRDialogWhileSpellCheck" +/** + *@author Klaas Freitag + */ + +class KOCRBase; +class KookaImage; +class KTempFile; +class KProcess; +class QRect; +class QPixmap; +class QStringList; +class KSpell; +class KSpellConfig; +class ImageCanvas; +class KConfig; +// class ocrWord; +// class ocrPage; + +#ifdef HAVE_KADMOS +#include "kadmosocr.h" +#endif + +/* + * Error Classifier the report errors on bad engine setup + */ +typedef enum{ ENG_ERROR, ENG_OK, ENG_DATA_MISSING, ENG_BAD_SETUP } EngineError; + +class KSANEOCR : public QObject +{ + Q_OBJECT +public: + enum OCREngines{ GOCR, OCRAD, KADMOS }; + + KSANEOCR( QWidget*, KConfig *); + ~KSANEOCR(); + + bool startOCRVisible( QWidget* parent=0); + + void finishedOCRVisible( bool ); + + /** + * checks after a ocr run if the line number exists in the result + */ + bool lineValid( int line ); + +#ifdef HAVE_KADMOS + bool startKadmosOCR(); +#endif + + /** + * return the final ocr result + */ + + QString ocrResultText(); + + /** + * @return the current spell config. + */ + KSpellConfig* ocrSpellConfig() const + { return m_spellInitialConfig; } + + + /** + * Sets an image Canvas that displays the result image of ocr. If this + * is set to zero (or never set) no result image is displayed. + * The ocr fabric passes a new image to the canvas which is a copy of + * the image to ocr. + */ + void setImageCanvas( ImageCanvas* canvas ); + +signals: + void newOCRResultText( const QString& ); + void clearOCRResultText(); + void newOCRResultPixmap( const QPixmap& ); + + /** + * progress of the ocr process. The first integer is the main progress, + * the second the sub progress. If there is only on progress, it is the + * first parameter, the second is always -1 than. + * Both have a range from 0..100. + * Note that this signal may not be emitted if the engine does not support + * progress. + */ + void ocrProgress(int, int); + + /** + * select a word in the editor in line line. + */ + void selectWord( int line, const ocrWord& word ); + + /** + * signal to indicate that a ocr text must be updated due to better results + * retrieved from spell check. The internal ocr data structure is already + * updated when this signal is fired. + * + * @param line the line in which the word must be changed (start at 0) + * @param wordFrom the original word + * @param wordTo the new word(s). + */ + void updateWord( int line, const QString& wordFrom, const QString& wordTo ); + + /** + * signal to indicate that word word was ignored by the user. This should result + * in a special coloring in the editor. + */ + void ignoreWord( int, const ocrWord& ); + + /** + * signal that comes if a word is considered to be wrong in the editor. + * The word should be marked in any way, e.g. with a signal color. + **/ + void markWordWrong( int, const ocrWord& ); + + /** + * signal the tells that the result image was modified. + */ + void repaintOCRResImage( ); + + /** + * indicates that the text editor holding the text that came through + * newOCRResultText should be set to readonly or not. Can be connected + * to QTextEdit::setReadOnly directly. + */ + void readOnlyEditor( bool ); + +public slots: + void slSetImage( KookaImage* ); + + void slLineBox( const QRect& ); + +protected: + /** + * Start spell checking on a specific line that is stored in m_ocrCurrLine. + * This method starts the spell checking. + **/ + void startLineSpellCheck(); + ocrWord ocrWordFromKSpellWord( int line, const QString& word ); + + /** + * Eventhandler to handle the mouse events to the image viewer showing the + * ocr result image + */ + bool eventFilter( QObject *object, QEvent *event ); + + void startOCRAD(); +protected slots: + void slotClose (); + void slotStopOCR(); + + void slSpellReady( KSpell* ); + void slSpellDead( ); + /** + * a new list of ocr results of the current ocr process arrived and is available + * in the member m_ocrPage[line] + */ + // void gotOCRLine( int line ); + + void slMisspelling( const QString& originalword, + const QStringList& suggestions, + unsigned int pos ); + void slSpellCorrected( const QString& originalword, + const QString& newword, + unsigned int pos ); + + void slSpellIgnoreWord( const QString& word ); + + void slCheckListDone( bool ); + + bool slUpdateWord( int line, int spellWordIndx, + const QString& origWord, + const QString& newWord ); + +private slots: + + void slotKadmosResult(); + void startOCRProcess( void ); + void gocrStdIn(KProcess*, char* buffer, int buflen); + void gocrStdErr(KProcess*, char* buffer, int buflen); + void gocrExited(KProcess*); + + void ocradStdIn(KProcess*, char* buffer, int buflen); + void ocradStdErr(KProcess*, char* buffer, int buflen); + void ocradExited(KProcess*); + + /* + * reads orf files from a file and fills the result structures + * accordingly. + */ + bool readORF( const QString&, QString& ); + +private: + void cleanUpFiles( void ); + + + KOCRBase *m_ocrProcessDia; + KProcess *daemon; + bool visibleOCRRunning; + KTempFile *m_tmpFile; + + KookaImage *m_img; + QString m_ocrResultText; + QString m_ocrResultImage; + QString m_ocrImagePBM; + QString m_tmpOrfName; + QImage *m_resultImage; + + OCREngines m_ocrEngine; + QPixmap m_resPixmap; + QPixmap m_storePixmap; + + ImageCanvas *m_imgCanvas; + + KSpell *m_spell; + bool m_wantKSpell; + bool m_kspellVisible; + bool m_hideDiaWhileSpellcheck; + KSpellConfig *m_spellInitialConfig; + + /* ValueVector of wordLists for every line of ocr results */ + ocrBlock m_ocrPage; /* one block contains all lines of the page */ + QWidget *m_parent; + /* current processed line to speed kspell correction */ + unsigned m_ocrCurrLine; + QStringList m_checkStrings; + + int m_currHighlight; + bool m_applyFilter; + + bool m_unlinkORF; + rectList m_blocks; // dimensions of blocks + + static char UndetectedChar; +#ifdef HAVE_KADMOS + Kadmos::CRep m_rep; +#endif +}; + +#endif diff --git a/kooka/main.cpp b/kooka/main.cpp new file mode 100644 index 00000000..086d3ddf --- /dev/null +++ b/kooka/main.cpp @@ -0,0 +1,121 @@ +/*************************************************************************** + main.cpp - description + ------------------- + begin : Thu Dec 9 20:16:54 MET 1999 + + copyright : (C) 1999 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kooka.h" +#include "version.h" + +static const char description[] = + "Kooka is a KDE application which provides access to scanner hardware\n" + "using the SANE library.\n" + "Kooka helps you scan, save your image in the correct image format\n" + "and perform Optical Character Recognition on it, using gocr, Joerg\n" + "Schulenburg's and friends' Open Source ocr program."; + +static const char license[] = +"This program is distributed under the terms of the GPL v2 as publishec by\n" +"the Free Software Foundation\n\n" +"As a special exception, permission is given to link this program\n" +"with any version of the KADMOS ocr/icr engine of reRecognition GmbH,\n" +"Kreuzlingen and distribute the resulting executable without\n" +"including the source code for KADMOS in the source distribution.\n\n" +"As a special exception, permission is given to link this program\n" +"with any edition of Qt, and distribute the resulting executable,\n" +"without including the source code for Qt in the source distribution.\n"; + + +static KCmdLineOptions options[] = +{ + { "d ", I18N_NOOP("The SANE compatible device specification (e.g. umax:/dev/sg0)"), "" }, + { "g", I18N_NOOP("Gallery mode - do not connect to scanner"), "" }, + KCmdLineLastOption +}; + + + +int main( int argc, char *argv[] ) +{ + KAboutData about("kooka", I18N_NOOP("Kooka"), KOOKA_VERSION, I18N_NOOP(description), + KAboutData::License_GPL_V2, "(C) 2000 Klaas Freitag", 0, + I18N_NOOP("http://kooka.kde.org")); + + about.addAuthor( "Klaas Freitag", I18N_NOOP("developer"), "freitag@suse.de" ); + about.addAuthor( "Mat Colton", I18N_NOOP("graphics, web"), "mat@colton.de" ); + about.setLicenseText( license ); + + KCmdLineArgs::init(argc, argv, &about); + KCmdLineArgs::addCmdLineOptions( options ); // Add my own options. + + KApplication app; + KGlobal::locale()->insertCatalogue("libkscan"); + KImageIO::registerFormats(); + KIconLoader *loader = KGlobal::iconLoader(); + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + QCString devToUse = args->getOption( "d" ); + if( args->isSet("g") ) + { + devToUse = "gallery"; + } + kdDebug( 29000) << "DevToUse is " << devToUse << endl; + + if (args->count() == 1) + { + args->usage(); + // exit(-1); + } + + + Kooka *kooka = new Kooka(devToUse); + app.setMainWidget( kooka ); + + KWin::setIcons(kooka->winId(), loader->loadIcon( "scanner", KIcon::Desktop ), + loader->loadIcon("scanner", KIcon::Small) ); + + kooka->show(); + app.processEvents(); + kooka->startup(); + args->clear(); + int ret = app.exec(); + + return ret; + +} diff --git a/kooka/ocrresedit.cpp b/kooka/ocrresedit.cpp new file mode 100644 index 00000000..a289a079 --- /dev/null +++ b/kooka/ocrresedit.cpp @@ -0,0 +1,148 @@ +/*************************************************************************** + ocrresedit.cpp - ocr result editor widget + ------------------- + begin : Tue 12 Feb 2003 + copyright : (C) 2003 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ +#include + +#include "ocrresedit.h" +#include "ocrword.h" +#include +#include +#include + +#include +#include + +/* -------------------- ocrResEdit -------------------- */ + +ocrResEdit::ocrResEdit( QWidget *parent ) + : QTextEdit(parent) +{ + m_updateColor.setNamedColor( "SeaGreen"); + m_ignoreColor.setNamedColor( "CadetBlue4" ); + m_wrnColor.setNamedColor( "firebrick2" ); +} + + +void ocrResEdit::slMarkWordWrong( int line, const ocrWord& word ) +{ + // m_textEdit->setSelection( line, + slReplaceWord( line, word, word, m_wrnColor ); +} + + +void ocrResEdit::slUpdateOCRResult( int line, const QString& wordFrom, + const QString& wordTo ) +{ + /* the index is quite useless here, since the text could have had been + * changed by corrections before. Thus better search the word and update + * it. + */ + slReplaceWord( line, wordFrom, wordTo, m_updateColor ); + +} + + +void ocrResEdit::slIgnoreWrongWord( int line, const ocrWord& word ) +{ + slReplaceWord( line, word, word, m_ignoreColor ); +} + + +void ocrResEdit::slSelectWord( int line, const ocrWord& word ) +{ + if( line < paragraphs() ) + { + QString editLine = text(line); + int cnt = editLine.contains( word); + + if( cnt > 0 ) + { + int pos = editLine.find(word); + setCursorPosition( line, pos ); + setSelection( line, pos, line, pos + word.length()); + } + } +} + +void ocrResEdit::slReplaceWord( int line, const QString& wordFrom, + const QString& wordTo, const QColor& color ) +{ + kdDebug(28000) << "Updating word " << wordFrom << " in line " << line << endl; + + bool isRO = isReadOnly(); + + if( line < paragraphs() ) + { + QString editLine = text(line); + int cnt = editLine.contains( wordFrom ); + + if( cnt > 0 ) + { + int pos = editLine.find(wordFrom); + setSelection( line, pos, line, pos+wordFrom.length()); + + QColor saveCol = this->color(); + setColor( color ); + if( isRO ) { + setReadOnly(false); + } + insert( wordTo, unsigned (4) ); + if( isRO ) { + setReadOnly( true ); + } + setColor(saveCol); + } + else + { + kdDebug(28000) << "WRN: Paragraph does not contain word " << wordFrom << endl; + } + + } + else + { + kdDebug(28000) << "WRN: editor does not have line " << line << endl; + } +} + + +void ocrResEdit::slSaveText() +{ + QString fileName = KFileDialog::getSaveFileName( (QDir::home()).path(), + "*.txt", + this, + i18n("Save OCR Result Text") ); + if( fileName.isEmpty() ) + return; + QFile file( fileName ); + if ( file.open( IO_WriteOnly ) ) + { + QTextStream stream( &file ); + stream << text(); + file.close(); + } +} + +#include "ocrresedit.moc" +/* */ diff --git a/kooka/ocrresedit.h b/kooka/ocrresedit.h new file mode 100644 index 00000000..6c483db4 --- /dev/null +++ b/kooka/ocrresedit.h @@ -0,0 +1,65 @@ +/*************************************************************************** + ocrresedit.h - ocr-result edit widget + ------------------- + begin : Fri 12 Feb 2003 + copyright : (C) 2003 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#ifndef _OCR_RESEDIT_ +#define _OCR_RESEDIT_ + +#include + +class QString; +class QColor; +class ocrWord; + +class ocrResEdit : public QTextEdit +{ + Q_OBJECT +public: + ocrResEdit( QWidget *parent ); + +public slots: + void slUpdateOCRResult( int line, const QString& wordFrom, + const QString& wordTo ); + + void slMarkWordWrong( int line, const ocrWord& word ); + + void slIgnoreWrongWord( int line, const ocrWord& word ); + + void slSelectWord( int line, const ocrWord& word ); + + void slSaveText(); + +protected slots: + void slReplaceWord( int line, const QString& wordFrom, + const QString& wordTo, const QColor& color ); + +private: + QColor m_updateColor; + QColor m_ignoreColor; + QColor m_wrnColor; + +}; + +#endif diff --git a/kooka/ocrword.cpp b/kooka/ocrword.cpp new file mode 100644 index 00000000..1bd29f3e --- /dev/null +++ b/kooka/ocrword.cpp @@ -0,0 +1,157 @@ +/*************************************************************************** + ocrword.cpp - ocr-result word and wordlist + ------------------- + begin : Fri Jan 10 2003 + copyright : (C) 2003 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#include +#include "ocrword.h" +#include +#include +#include +#include + +/* -------------------- ocrWord -------------------- */ +ocrWord::ocrWord( const QString& s ) + : QString(s) +{ + +} + +ocrWord::ocrWord() : QString() +{ + +} + +#if 0 +QRect ocrWord::boundingRect() +{ + QRect r; + + return r; +} +#endif + +/* -------------------- CocrWordList ------------------ */ +ocrWordList::ocrWordList() + :QValueList(), + m_block(0) +{ + // setAutoDelete( true ); +} + +QStringList ocrWordList::stringList() +{ + QStringList res; + QRegExp rx("[,\\.-]"); + ocrWordList::iterator it; + + for ( it = begin(); it != end(); ++it ) + { +#if 0 + /* Uncommented this to prevent an error that occurs if the lenght of the + * spellchecked stringlist and the ocr_page wordlist are not the same length. + * For the ocrpage words connected with a dash are one word while the code + * below parts them into two. That confuses the replacement code if the user + * decided. Solution: KSpell should treat dash-linked words correctly. + * We live with the problem here that dashes bring confusion ;-) + */ + if( (*it).contains( rx ) ) + res += QStringList::split( rx, (*it) ); + else +#endif + res << *it; + } + return res; + +} + +bool ocrWordList::updateOCRWord( const QString& from, const QString& to ) +{ + ocrWordList::iterator it; + bool res = false; + + for( it = begin(); it != end(); ++it ) + { + QString word = (*it); + kdDebug(28000) << "updateOCRWord in list: Comparing word " << word << endl; + if( word.contains( from, true ) ) // case sensitive search + { + word.replace( from, to ); + *it = ocrWord( word ); + res = true; + break; + } + } + return res; +} + +QRect ocrWordList::wordListRect() +{ + QRect rect; + + ocrWordList::iterator it; + + for( it = begin(); it != end(); ++it ) + { + rect = rect.unite( (*it).rect() ); + } + return rect; +} + + +/* + * since kspell removes , - | / etc. from words while they remain in the words + * in the ocr wordlist. + * This search goes through the wordlist and tries to find the words without caring + * for special chars. It simply removes all chars from the words that are not alphanumeric. + */ +bool ocrWordList::findFuzzyIndex( const QString& word, ocrWord& resWord ) +{ + ocrWordList::iterator it; + bool res = false; + + for( it = begin(); it != end() && !res; ++it ) + { + QString fuzzyword = (*it); + fuzzyword.remove( QRegExp( "\\W" )); // Remove all non-word characters. + fuzzyword.remove( '_' ); + + // kdDebug(28000) << "findFuzzy: Comparing word " << fuzzyword << " which was " + // << (*it) << " with " << word << endl; + if( fuzzyword == word ) + { + resWord = *it; + res = true; + } + } + return res; + +} + +void ocrWordList::setBlock( int b ) +{ + m_block = b; +} + +/* */ diff --git a/kooka/ocrword.h b/kooka/ocrword.h new file mode 100644 index 00000000..606acb9f --- /dev/null +++ b/kooka/ocrword.h @@ -0,0 +1,111 @@ +/*************************************************************************** + ocrword.h - ocr-result word and wordlist + ------------------- + begin : Fri 10 Jan 2003 + copyright : (C) 2003 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#ifndef _OCR_WORD_ +#define _OCR_WORD_ + +#include +#include +#include +#include + +class QString; +class QRect; + + +/* ==== ocrWord ====================================== */ +class ocrWord : public QString +{ +public: + ocrWord(const QString& s); + ocrWord(); + QStringList getAlternatives() + { return m_alternatives; } + + void setAlternatives( const QString& s ) + { m_alternatives.append(s); } + + // QRect boundingRect(); + + void setKnode( int k ) + { m_startKnode = k; } + void setLine( int l ) + { m_line = l; } + + int getLine() const { return m_line; } + int getKnode() const { return m_startKnode; } + + void setRect( const QRect& r ) + { m_position = r; } + QRect rect() + { return m_position; } + +private: + QStringList m_alternatives; + int m_startKnode; + int m_line; + QRect m_position; +}; + +/* ==== ocrWordList ====================================== */ + +/** + * This represents a line of words in an ocr'ed document + */ +class ocrWordList : public QValueList +{ +public: + ocrWordList(); + QStringList stringList(); + + bool updateOCRWord( const QString& from, const QString& to ); + + bool findFuzzyIndex( const QString& word, ocrWord& resWord ); + + QRect wordListRect( ); + + void setBlock( int b ); + int block() const { return m_block; } + +private: + int m_block; +}; + +/** + * All lines of a block: A value vector containing as much as entries + * as lines are available in a block. Needs to be resized acordingly. + */ +typedef QValueVector ocrBlock; + +/** + * Blocks taken together form the page. + * Attention: Needs to be resized to the amount of blocks !! + */ +typedef QValueVector ocrBlockPage; + +typedef QValueVector rectList; + +#endif diff --git a/kooka/pics/Makefile.am b/kooka/pics/Makefile.am new file mode 100644 index 00000000..f8f4440b --- /dev/null +++ b/kooka/pics/Makefile.am @@ -0,0 +1,8 @@ +# Add all of your pixmaps here +pics_DATA = mirror-both.png mirror-horiz.png mirror-vert.png scaletoheight.png \ + scaletowidth.png scaleorig.png ocr.png ocr-select.png newfromselect.png \ + thumbviewtile.png gocr.png ocrad.png lockzoom.png + + +# This is where it will all be installed +picsdir = $(kde_datadir)/kooka/pics diff --git a/kooka/pics/gocr.png b/kooka/pics/gocr.png new file mode 100644 index 00000000..575ebea9 Binary files /dev/null and b/kooka/pics/gocr.png differ diff --git a/kooka/pics/lockzoom.png b/kooka/pics/lockzoom.png new file mode 100644 index 00000000..dbfa1a7e Binary files /dev/null and b/kooka/pics/lockzoom.png differ diff --git a/kooka/pics/mirror-both.png b/kooka/pics/mirror-both.png new file mode 100644 index 00000000..e275689b Binary files /dev/null and b/kooka/pics/mirror-both.png differ diff --git a/kooka/pics/mirror-horiz.png b/kooka/pics/mirror-horiz.png new file mode 100644 index 00000000..eb537f40 Binary files /dev/null and b/kooka/pics/mirror-horiz.png differ diff --git a/kooka/pics/mirror-vert.png b/kooka/pics/mirror-vert.png new file mode 100644 index 00000000..d3c29462 Binary files /dev/null and b/kooka/pics/mirror-vert.png differ diff --git a/kooka/pics/newfromselect.png b/kooka/pics/newfromselect.png new file mode 100644 index 00000000..93a75ec8 Binary files /dev/null and b/kooka/pics/newfromselect.png differ diff --git a/kooka/pics/ocr-select.png b/kooka/pics/ocr-select.png new file mode 100644 index 00000000..db076898 Binary files /dev/null and b/kooka/pics/ocr-select.png differ diff --git a/kooka/pics/ocr.png b/kooka/pics/ocr.png new file mode 100644 index 00000000..c68f0616 Binary files /dev/null and b/kooka/pics/ocr.png differ diff --git a/kooka/pics/ocrad.png b/kooka/pics/ocrad.png new file mode 100644 index 00000000..01e41184 Binary files /dev/null and b/kooka/pics/ocrad.png differ diff --git a/kooka/pics/scaleorig.png b/kooka/pics/scaleorig.png new file mode 100644 index 00000000..8c696f48 Binary files /dev/null and b/kooka/pics/scaleorig.png differ diff --git a/kooka/pics/scaletoheight.png b/kooka/pics/scaletoheight.png new file mode 100644 index 00000000..b84d971b Binary files /dev/null and b/kooka/pics/scaletoheight.png differ diff --git a/kooka/pics/scaletowidth.png b/kooka/pics/scaletowidth.png new file mode 100644 index 00000000..90e33617 Binary files /dev/null and b/kooka/pics/scaletowidth.png differ diff --git a/kooka/pics/thumbviewtile.png b/kooka/pics/thumbviewtile.png new file mode 100644 index 00000000..6f806851 Binary files /dev/null and b/kooka/pics/thumbviewtile.png differ diff --git a/kooka/resource.h b/kooka/resource.h new file mode 100644 index 00000000..51c9488f --- /dev/null +++ b/kooka/resource.h @@ -0,0 +1,94 @@ +/*************************************************************************** + resource.h - description + ------------------- + begin : Thu Dec 9 20:16:54 MET 1999 + + copyright : (C) 1999 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#ifndef RESSOURCE_H +#define RESSOURCE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + + +/////////////////////////////////////////////////////////////////// +// resource.h -- contains macros used for commands + + +/////////////////////////////////////////////////////////////////// +// COMMAND VALUES FOR MENUBAR AND TOOLBAR ENTRIES + + +/////////////////////////////////////////////////////////////////// +// File-menu entries +#define ID_FILE_NEW 10020 +#define ID_FILE_OPEN 10030 + +#define ID_FILE_SAVE 10050 +#define ID_FILE_SAVE_AS 10060 +#define ID_FILE_CLOSE 10070 + +#define ID_FILE_PRINT 10080 + +#define ID_FILE_QUIT 10100 + + +/////////////////////////////////////////////////////////////////// +// Edit-menu entries +#define ID_EDIT_UNDO 11010 +#define ID_EDIT_REDO 11020 +#define ID_EDIT_COPY 11030 +#define ID_EDIT_CUT 11040 +#define ID_EDIT_PASTE 11050 +#define ID_EDIT_SELECT_ALL 11060 + + +/////////////////////////////////////////////////////////////////// +// View-menu entries +#define ID_VIEW_TOOLBAR 12010 +#define ID_VIEW_STATUSBAR 12020 +#define ID_VIEW_PREVIEW 12021 +#define ID_VIEW_POOL 12022 +#define ID_VIEW_SCANPARAMS 12023 + + +/////////////////////////////////////////////////////////////////// +// View-menu entries +#define ID_SCAN_PREVIEW 13010 +#define ID_SCAN_FINAL 13020 + +/////////////////////////////////////////////////////////////////// +// Help-menu entries +#define ID_HELP_ABOUT 1002 + +/////////////////////////////////////////////////////////////////// +// General application values +#define IDS_APP_ABOUT "Ksanetest\n Version " VERSION + +#define IDS_DEFAULT "Ready." + +#endif // RESOURCE_H + + diff --git a/kooka/scanpackager.cpp b/kooka/scanpackager.cpp new file mode 100644 index 00000000..7af7f151 --- /dev/null +++ b/kooka/scanpackager.cpp @@ -0,0 +1,1261 @@ +/*************************************************************************** + scanpackager.cpp - description + ------------------- + begin : Fri Dec 17 1999 + copyright : (C) 1999 by Klaas Freitag + email : freitag@suse.de + + $Id$ + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#include "scanpackager.h" +#include "resource.h" +#include "img_saver.h" +#include "kookaimage.h" +#include "kookaimagemeta.h" +#include "previewer.h" +#include "devselector.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STARTUP_FIRST_START "firstStart" + + +/* ----------------------------------------------------------------------- */ +/* Constructor Scan Packager */ +ScanPackager::ScanPackager( QWidget *parent ) : KFileTreeView( parent ) +{ + // TODO: + setItemsRenameable (true ); + setDefaultRenameAction( QListView::Reject ); + addColumn( i18n("Image Name" )); + setColumnAlignment( 0, AlignLeft ); + + addColumn( i18n("Size") ); + setColumnAlignment( 1, AlignRight ); + setColumnAlignment( 2, AlignRight ); + + addColumn( i18n("Format" )); setColumnAlignment( 3, AlignRight ); + + /* Drag and Drop */ + setDragEnabled( true ); + setDropVisualizer(true); + setAcceptDrops(true); + + connect( this, SIGNAL(dropped( QWidget*, QDropEvent*, KURL::List&, KURL& )), + this, SLOT( slotUrlsDropped( QWidget*, QDropEvent*, KURL::List&, KURL& ))); + + kdDebug(28000) << "connected Drop-Signal" << endl; + setRenameable ( 0, true ); + setRenameable ( 1, false ); + setRenameable ( 2, false ); + setRenameable ( 3, false ); + + setRootIsDecorated( false ); + + connect( this, SIGNAL( clicked( QListViewItem*)), + SLOT( slClicked(QListViewItem*))); + + connect( this, SIGNAL( rightButtonPressed( QListViewItem *, const QPoint &, int )), + SLOT( slShowContextMenue(QListViewItem *, const QPoint &, int ))); + + connect( this, SIGNAL(itemRenamed (QListViewItem*, const QString &, int ) ), this, + SLOT(slFileRename( QListViewItem*, const QString&, int))); + + + img_counter = 1; + /* Set the current export dir to home */ + m_currCopyDir = QDir::home().absPath(); + m_currImportDir = m_currCopyDir; + + /* Preload frequently used icons */ + KIconLoader *loader = KGlobal::iconLoader(); + m_floppyPixmap = loader->loadIcon( "3floppy_unmount", KIcon::Small ); + m_grayPixmap = loader->loadIcon( "palette_gray", KIcon::Small ); + m_bwPixmap = loader->loadIcon( "palette_lineart", KIcon::Small ); + m_colorPixmap = loader->loadIcon( "palette_color", KIcon::Small ); + + m_startup = true; + + /* create a context menu and set the title */ + m_contextMenu = new KPopupMenu(); + static_cast(m_contextMenu)->insertTitle( i18n( "Gallery" )); + +} + +void ScanPackager::openRoots() +{ + /* standard root always exists, ImgRoot creates it */ + KURL rootUrl(Previewer::galleryRoot()); + kdDebug(28000) << "Open standard root " << rootUrl.url() << endl; + + openRoot( rootUrl, true ); + m_defaultBranch->setOpen(true); + + /* open more configurable image repositories TODO */ +} + +KFileTreeBranch* ScanPackager::openRoot( const KURL& root, bool ) +{ + KIconLoader *loader = KGlobal::iconLoader(); + + /* working on the global branch. FIXME */ + m_defaultBranch = addBranch( root, i18n("Kooka Gallery"), + loader->loadIcon( "folder_image", KIcon::Small ), + false /* do not showHidden */ ); + + // Q_CHECK_PTR( m_defaultBranch ); + m_defaultBranch->setOpenPixmap( loader->loadIcon( "folder_blue_open", KIcon::Small )); + + setDirOnlyMode( m_defaultBranch, false ); + m_defaultBranch->setShowExtensions( true ); // false ); + + connect( m_defaultBranch, SIGNAL( newTreeViewItems( KFileTreeBranch*, const KFileTreeViewItemList& )), + this, SLOT( slotDecorate(KFileTreeBranch*, const KFileTreeViewItemList& ))); + + connect( m_defaultBranch, SIGNAL( directoryChildCount( KFileTreeViewItem* , int )), + this, SLOT( slotDirCount( KFileTreeViewItem *, int ))); + + connect( m_defaultBranch, SIGNAL( deleteItem( KFileItem* )), + this, SLOT( slotDeleteFromBranch(KFileItem*))); + + connect( m_defaultBranch, SIGNAL( populateFinished( KFileTreeViewItem * )), + this, SLOT( slotStartupFinished( KFileTreeViewItem * ))); + + + return( m_defaultBranch ); +} + +void ScanPackager::slotStartupFinished( KFileTreeViewItem *it ) +{ + if( m_startup && (it == m_defaultBranch->root()) ) + { + kdDebug(28000) << "Slot population finished hit!" << endl; + + /* If nothing is selected, select the root. */ + if( ! currentKFileTreeViewItem() ) + { + (m_defaultBranch->root())->setSelected( true ); + } + + m_startup = false; + } +} + +void ScanPackager::slotDirCount( KFileTreeViewItem* item, int cnt ) +{ + if( item && item->isDir() ) + { + QString cc = i18n( "one item", "%n items", cnt); + item->setText( 1, cc ); + } + else + { + kdDebug(28000) << "Item is NOT directory - do not set child count!" << endl; + } +} + +void ScanPackager::slotDecorate( KFileTreeViewItem* item ) +{ + if( !item ) return; + if( item->isDir()) + { + // done in extra slot. + kdDebug(28000) << "Decorating directory!" << endl; + } + else + + { + KFileItem *kfi = item->fileItem(); + + KookaImage *img = 0L; + + if( kfi ) + { + img = static_cast(kfi->extraData( this )); + } + + if( img ) + { + + /* The image appears to be loaded to memory. */ + if( img->depth() == 1 ) + { + /* a bw-image */ + item->setPixmap( 0, m_bwPixmap ); + } + else + { + if( img->isGrayscale() ) + { + item->setPixmap( 0, m_grayPixmap ); + } + else + { + item->setPixmap( 0, m_colorPixmap ); + } + } + + /* set image size in pixels */ + QString t = i18n( "%1 x %2" ).arg( img->width()).arg(img->height()); + item->setText( 1, t ); + kdDebug( 28000) << "Image loaded and decorated!" << endl; + } + else + { + /* Item is not yet loaded. Display file information */ + item->setPixmap( 0, m_floppyPixmap ); + if ( kfi ) + { + item->setText(1, KIO::convertSize( kfi->size() )); + } + } + + /* Image format */ + QString format = getImgFormat( item ); + item->setText( 2, format ); + } + + // This code is quite similar to m_nextUrlToSelect in KFileTreeView::slotNewTreeViewItems + // When scanning a new image, we wait for the KDirLister to notice the new file, + // and then we have the KFileTreeViewItem that we need to display the image. + if ( ! m_nextUrlToShow.isEmpty() ) + { + if( m_nextUrlToShow.equals(item->url(), true )) + { + m_nextUrlToShow = KURL(); // do this first to prevent recursion + slClicked( item ); + setCurrentItem(item); // neccessary in case of new file from D&D + } + } +} + + + + +void ScanPackager::slotDecorate( KFileTreeBranch* branch, const KFileTreeViewItemList& list ) +{ + (void) branch; + kdDebug(28000) << "decorating slot for list !" << endl; + + KFileTreeViewItemListIterator it( list ); + + bool end = false; + for( ; !end && it.current(); ++it ) + { + KFileTreeViewItem *kftvi = *it; + slotDecorate( kftvi ); + emit fileChanged( kftvi->fileItem() ); + } +} + + + +void ScanPackager::slFileRename( QListViewItem* it, const QString& newStr, int ) +{ + + bool success = true; + if( !it ) return; + + if( newStr.isEmpty() ) + success = false; + + KFileTreeViewItem *item = static_cast(it); + + /* Free memory and imform everybody who is interested. */ + KURL urlFrom = item->url(); + KURL urlTo( urlFrom ); + + /* clean filename and apply new name */ + urlTo.setFileName(""); + urlTo.setFileName(newStr); + + if( success ) + { + if( urlFrom == urlTo ) + { + kdDebug(28000) << "Renaming to same url does not make sense!" << endl; + success = false; + } + else + { + /* clear selection, because the renamed image comes in through + * kdirlister again + */ + slotUnloadItem( item ); + + kdDebug(28000) << "Renaming to " << urlTo.prettyURL() << + " from " << urlFrom.prettyURL() << endl; + + /* to urlTo the really used filename is written */ + setSelected( item, false ); + + if( ImgSaver::renameImage( urlFrom, urlTo, false, this ) ) + { + kdDebug(28000) << "renaming OK" << endl; + emit fileRenamed( item->fileItem(), urlTo ); + success=true; + } + else + { + success = false; + } + } + } + + if( !success ) + { + kdDebug(28000) << "renaming failed" << endl; + /* restore the name */ + item->setText(0, urlFrom.fileName() ); + setSelected( item, true ); + + } + +} + + +/* ----------------------------------------------------------------------- */ +/* + * Method that checks if the new filename a user enters while renaming an image is valid. + * It checks for a proper extension. + */ +QString ScanPackager::buildNewFilename( QString cmplFilename, QString currFormat ) const +{ + /* cmplFilename = new name the user wishes. + * currFormat = the current format of the image. + * if the new filename has a valid extension, which is the same as the + * format of the current, fine. A ''-String has to be returned. + */ + QFileInfo fiNew( cmplFilename ); + QString base = fiNew.baseName(); + QString newExt = fiNew.extension( false ).lower(); + QString nowExt = currFormat.lower(); + QString ext = ""; + + kdDebug(28000) << "Filename wanted: "<< cmplFilename << " <"< <" << nowExt<<">" < return the currFormat-Extension */ + ext = base + "." + currFormat; + } + else if( newExt == nowExt ) + { + /* also good, no reason to put another extension */ + ext = cmplFilename; + } + else + { + /* new Ext. differs from the current extension. Later. */ + KMessageBox::sorry( 0L, i18n( "You entered a file extension that differs from the existing one. That is not yet possible. Converting 'on the fly' is planned for a future release.\n" + "Kooka corrects the extension."), + i18n("On the Fly Conversion")); + ext = base + "." + currFormat; + } + return( ext ); +} + +/* ----------------------------------------------------------------------- */ +/* This method returns the directory of an image or directory. + */ +QString ScanPackager::itemDirectory( const KFileTreeViewItem* item, bool relativ ) const +{ + if( ! item ) + { + kdDebug(28000) << "ERR: itemDirectory without item" << endl; + return QString::null; + } + + QString relativUrl= (item->url()).prettyURL(); + + if( ! item->isDir() ) + { + // Cut off the filename in case it is not a dir + relativUrl.truncate( relativUrl.findRev( '/' )+1); + } + else + { + /* add a "/" to the directory if not there */ + if( ! relativUrl.endsWith( "/" ) ) + relativUrl.append( "/" ); + } + + if( relativ ) + { + KFileTreeBranch *branch = item->branch(); + if( branch ) + { + kdDebug(28000) << "Relativ URL of the file " << relativUrl << endl; + QString rootUrl = (branch->rootUrl()).prettyURL(); // directory of branch root + + if( relativUrl.startsWith( rootUrl )) + { + relativUrl.remove( 0, rootUrl.length() ); + + if( relativUrl.isEmpty() ) relativUrl = "/"; // The root + } + else + { + kdDebug(28000) << "ERR: Item-URL does not start with root url " << rootUrl << endl; + } + } + } + return( relativUrl ); +} +/* ----------------------------------------------------------------------- */ +/* This slot receives a string from the gallery-path combobox shown under the + * image gallery. The form of the string coming in here is - < + * relativ directory under the branch. Now it is to assemble a complete path + * from the data, find out which KFileTreeViewItem is associated with it and + * call slClicked with it. + */ + +void ScanPackager::slotSelectDirectory( const QString & dirString ) +{ + kdDebug(28000) << "Trying to decode directory string " << dirString << endl; + + QString searchFor = QString::fromLatin1(" - "); + int pos = dirString.find( searchFor ); + + if( pos > -1 ) + { + /* Splitting up the string coming in */ + QString branchName = dirString.left( pos ); + QString relPath( dirString ); + + relPath = relPath.remove( 0, pos + searchFor.length()); + + kdDebug(28000) << "Splitted up to branch <" << branchName << "> and <" << relPath << endl; + + KFileTreeViewItem *kfi = findItem( branchName, relPath ); + + if( kfi ) + { + kdDebug(28000) << "got a new item to select !" << endl; + ensureItemVisible(kfi); + setCurrentItem(kfi); + slClicked(kfi); // load thumbnails for this dir etc. + } + } +} + +/* ----------------------------------------------------------------------- */ +/* This slot is called when clicking on an item. */ +void ScanPackager::slClicked( QListViewItem *newItem ) +{ + KFileTreeViewItem *item = static_cast(newItem); + + if( item ) // can be 0, when clicking where no item is present + { + kdDebug(28000) << "Clicked - newItem !" << endl; + /* Check if directory, hide image for now, later show a thumb view */ + if( item->isDir()) + { + kdDebug(28000) << "clicked: Is a directory !" << endl; + emit( showImage( 0L )); + kdDebug(28000) << "emitting showThumbnails" << endl; + } + else + { + /* if not a dir, load the image if necessary. This is done by loadImageForItem, + * which is async( TODO ). The image finally arrives in slotImageArrived */ + QApplication::setOverrideCursor(waitCursor); + emit( aboutToShowImage( item->url())); + loadImageForItem( item ); + QApplication::restoreOverrideCursor(); + } + + /* emit a signal indicating the new directory if there is a new one */ + QString wholeDir = itemDirectory( item, false ); /* not relativ to root */ + + if( currSelectedDir != wholeDir ) + { + currSelectedDir = wholeDir; + QString relativUrl = itemDirectory( item, true ); + kdDebug(28000) << "Emitting " << relativUrl << " as new relative Url" << endl; + /* Emit the signal with branch and the relative path */ + emit( galleryPathSelected( item->branch(), relativUrl )); + + if( item->isDir() ) + { + emit( showThumbnails( item )); + } + else + { + emit( showThumbnails( static_cast(item->parent()))); + } + } + else + { + // kdDebug(28000) << "directory is not new: " << currSelectedDir << endl; + } + } +} + +void ScanPackager::loadImageForItem( KFileTreeViewItem *item ) +{ + + if( ! item ) return; + bool result = true; + + KFileItem *kfi = item->fileItem(); + if( ! kfi ) return; + + KookaImage *img = static_cast( kfi->extraData(this)); + + if( img ) + { + kdDebug(28000) << "Image already loaded." << endl; + /* result is still true, image must be shown. */ + } + else + { + /* The image needs to be loaded. Possibly it is a multi-page image. + * If it is, the kookaImage has a subImageCount larger than one. We + * create an subimage-item for every subimage, but do not yet load + * them. + */ + KURL url = item->url(); + + img = new KookaImage( ); + if( !img || !img->loadFromUrl( url ) ) + { + kdDebug(28000) << "Loading KookaImage from File failed!" << endl; + result = false; + } + else + { + /* store the fileitem */ + img->setFileItem( kfi ); + + /* care for subimages, create items for them */ + kdDebug(28000) << "subImage-count: " << img->subImagesCount() << endl; + if( img->subImagesCount() > 1 ) + { + KIconLoader *loader = KGlobal::iconLoader(); + kdDebug(28000) << "SubImages existing!" << endl; + + /* Start at the image with index 1, that makes one less than are actually in the + * image. But image 0 was already created above. */ + KFileTreeViewItem *prevItem=0; + for( int i = 1; i < img->subImagesCount(); i++ ) + { + kdDebug(28000) << "Creating subimage no " << i << endl; + KFileItem *newKfi = new KFileItem( *kfi ); + KFileTreeViewItem *subImgItem = new KFileTreeViewItem( item, newKfi, item->branch()); + + if( prevItem ) + { + subImgItem->moveItem( prevItem ); + } + prevItem = subImgItem; + + subImgItem->setPixmap( 0, loader->loadIcon( "editcopy", KIcon::Small )); + subImgItem->setText( 0, i18n("Sub-image %1").arg( i ) ); + KookaImage *subImgImg = new KookaImage( i, img ); + subImgImg->setFileItem( newKfi ); + newKfi->setExtraData( (void*) this, (void*) subImgImg ); + } + } + } + } + + + if( result && img ) + { + if( img->isSubImage() ) + { + kdDebug(28000) << "it _is_ a subimage" << endl; + /* load if not loaded */ + if( img->isNull()) + { + kdDebug(28000) << "extracting subimage" << endl; + img->extractNow(); + } + else + { + kdDebug(28000) << "Is not a null image" << endl; + } + } + slImageArrived( item, img ); + } +} + +/* Hit this slot with a file for a kfiletreeviewitem. */ +void ScanPackager::slImageArrived( KFileTreeViewItem *item, KookaImage* image ) +{ + if( item && image ) + { + /* Associate the image for the Scanpackager-Object. */ + KFileItem *kfi = item->fileItem(); + if( kfi ) + { + kfi->setExtraData( (void*) this, (void*) image ); + } + slotDecorate( item ); + emit( showImage( image )); + } +} + +KookaImage* ScanPackager::getCurrImage() const +{ + KFileTreeViewItem *curr = currentKFileTreeViewItem(); + KookaImage *img = 0L; + + if( curr ) + { + KFileItem *kfi = curr->fileItem(); + if( kfi ) + { + img = static_cast(kfi->extraData( this )); + } + } + return(img); +} + + +QString ScanPackager::getCurrImageFileName( bool withPath = true ) const +{ + QString result = ""; + + KFileTreeViewItem *curr = currentKFileTreeViewItem(); + if( ! curr ) + { + kdDebug( 28000) << "getCurrImageFileName: nothing selected !"<< endl; + } + else + { + if( withPath ) + { + result = localFileName(curr); + } + else + { + KURL url( localFileName(curr)); + url = curr->url(); + result = url.fileName(); + } + } + return( result ); +} + +/* ----------------------------------------------------------------------- */ +QCString ScanPackager::getImgFormat( KFileTreeViewItem* item ) const +{ + + QCString cstr; + + if( !item ) return( cstr ); +#if 0 + KFileItem *kfi = item->fileItem(); + + QString mime = kfi->mimetype(); +#endif + + // TODO find the real extension for use with the filename ! + // temporarely: + QString f = localFileName( item ); + + return( QImage::imageFormat( f )); + +} + +QString ScanPackager::localFileName( KFileTreeViewItem *it ) const +{ + if( ! it ) return( QString::null ); + + KURL url = it->url(); + + QString res; + + if( url.isLocalFile()) + { + res = url.directory( false, true ) + url.fileName(); + } + + return( res ); +} + +/* Called if the image exists but was changed by image manipulation func */ +void ScanPackager::slotCurrentImageChanged( QImage *img ) +{ + KFileTreeViewItem *curr = currentKFileTreeViewItem(); + if( ! curr ) + { + kdDebug(28000) << "ImageChanged: nothing selected !" << endl; + return; + } + + /* Do not save directories */ + if( curr->isDir() ) return; + + /* unload image and free memory */ + slotUnloadItem( curr ); + + const QString filename = localFileName( curr ); + const QCString format = getImgFormat( curr ); + ImgSaver saver( this ); + ImgSaveStat is_stat = ISS_OK; + is_stat = saver.saveImage( img, filename, format ); + + if( is_stat == ISS_ERR_FORMAT_NO_WRITE ) + { + KMessageBox::error( this, i18n( "Cannot write this image format.\nImage will not be saved!"), + i18n("Save Error") ); + } + else if( is_stat == ISS_ERR_PERM ) + { + KMessageBox::error( this, i18n( "Image file is write protected.\nImage will not be saved!"), + i18n("Save Error") ); + + } + else if( is_stat == ISS_ERR_PROTOCOL ) + { + KMessageBox::sorry( this, i18n( "Cannot save the image, because the file is local.\n" + "Kooka will support other protocols later."), + i18n("Save Error") ); + + } + else if( is_stat != ISS_OK ) + { + kdDebug(28000) << "Error while saving existing image !" << endl; + } + + if( img && !img->isNull()) + { + emit( imageChanged( curr->fileItem())); + KookaImage *newImage = new KookaImage(*img); + slImageArrived( curr, newImage ); + } +} + + +/* ----------------------------------------------------------------------- */ +/* This slot takes a new scanned Picture and saves it. + * It urgently needs to make a deep copy of the image ! + */ +void ScanPackager::slAddImage( QImage *img, KookaImageMeta* ) +{ + ImgSaveStat is_stat = ISS_OK; + /* Save the image with the help of the ImgSaver */ + if( ! img ) return; + + /* currently selected item is the directory or a file item */ + KFileTreeViewItem *curr = currentKFileTreeViewItem(); + + /* Use root if nothing is selected */ + if( ! curr ) + { + KFileTreeBranch *b = branches().at(0); /* There should be at least one */ + + if( b ) + { + curr = findItem( b, i18n( "Incoming/" ) ); + if( ! curr ) curr = b->root(); + } + + /* If curr is still undefined, something very tough has happend. Go away here */ + if( !curr ) return; + + setSelected( curr, true ); + } + + /* find the directory above the current one */ + + KURL dir(itemDirectory( curr )); + + /* Path of curr sel item */ + ImgSaver img_saver( this, dir ); + + is_stat = img_saver.saveImage( img ); + if( is_stat == ISS_ERR_FORMAT_NO_WRITE ) + { + KMessageBox::error( this, i18n( "Cannot write this image format.\nImage will not be saved!"), + i18n("Save Error") ); + } + else if( is_stat == ISS_ERR_PERM ) + { + KMessageBox::error( this, i18n( "Image file is write protected.\nImage will not be saved!"), + i18n("Save Error") ); + + } + else if( is_stat != ISS_OK ) + { + if( is_stat == ISS_SAVE_CANCELED ) + { + return; + } + kdDebug(28000) << "ERROR: Saving failed: " << img_saver.errorString( is_stat ) << endl; + /* And now ?? */ + } + + /* Add the new image to the list of new images */ + KURL lurl = img_saver.lastFileUrl(); + + KFileTreeBranchList branchlist = branches(); + KFileTreeBranch *kookaBranch = branchlist.at(0); + + QString strdir = itemDirectory(curr); + if(strdir.endsWith(QString("/"))) strdir.truncate( strdir.length() - 1 ); + kdDebug(28000) << "Updating directory with " << strdir << endl; + + if( kookaBranch ) kookaBranch->updateDirectory( KURL(strdir) ); + slotSetNextUrlToSelect( lurl ); + m_nextUrlToShow = lurl; + + QString s; + /* Count amount of children of the father */ + QListViewItem *paps = curr->parent(); + if( curr->isDir() ) /* take only father if the is no directory */ + paps = curr; + + if( paps ) + { + int childcount = paps->childCount(); + s = i18n("%1 images").arg(childcount); + paps->setText( 1, s); + setOpen( paps, true ); + } + +} + +/* ----------------------------------------------------------------------- */ +/* selects and opens the file with the given name. This is used to restore the + * last displayed image by its name. + */ +void ScanPackager::slSelectImage( const KURL& name ) +{ + + KFileTreeViewItem *found = spFindItem( UrlSearch, name.url() ); + + if( found ) + { + kdDebug(28000) << "slSelectImage: Found an item !" << endl; + ensureItemVisible( found ); + setCurrentItem( found ); + slClicked( found ); + } + +} + + +KFileTreeViewItem *ScanPackager::spFindItem( SearchType type, const QString name, const KFileTreeBranch *branch ) +{ + /* Prepare a list of branches to go through. If the parameter branch is set, search + * only in the parameter branch. If it is zero, search all branches returned by + * kfiletreeview.branches() + */ + KFileTreeBranchList branchList; + + if( branch ) + { + branchList.append( branch ); + } + else + { + branchList = branches(); + } + + + KFileTreeBranchIterator it( branchList ); + KFileItem *kfi = 0L; + KFileTreeViewItem *foundItem = 0L; + + /* Leave the loop in case kfi is defined */ + KFileTreeBranch *branchloop = 0L; + for( ; !kfi && it.current(); ++it ) + { + branchloop = *it; + KURL url(name); + switch( type ) + { + case Dummy: + kdDebug(28000) << "Dummy search skipped !" << endl; + break; + case NameSearch: + kdDebug(28000) << "ScanPackager: searching for " << name << endl; + kfi = branchloop->findByName( name ); + break; + case UrlSearch: + kdDebug(28000) << "ScanPackager: URL search for " << name << endl; + kfi = branchloop->find( url ); + break; + default: + kdDebug(28000) << "Scanpackager: Wrong search type !" << endl; + break; + } + + } + if( kfi ) + { + foundItem = static_cast(kfi->extraData(branchloop)); + kdDebug(28000) << "spFindItem: Success !" << foundItem << endl; + } + return( foundItem ); +} + +/* ----------------------------------------------------------------------- */ +void ScanPackager::slShowContextMenue(QListViewItem *lvi, const QPoint &p, int col ) +{ + kdDebug(28000) << "Showing Context Menue" << endl; + (void) col; + + KFileTreeViewItem *curr = 0; + + if( lvi ) + { + curr = currentKFileTreeViewItem(); + if( curr->isDir() ) + setSelected( curr, true ); + } + + if( m_contextMenu ) + { + m_contextMenu->exec( p ); + } + +} + +/* ----------------------------------------------------------------------- */ + +void ScanPackager::slotExportFile( ) +{ + KFileTreeViewItem *curr = currentKFileTreeViewItem(); + if( ! curr ) return; + + if( curr->isDir() ) + { + kdDebug(28000) << "Not yet implemented!" << endl; + } + else + { + KURL fromUrl( curr->url()); + QString filter = "*." + getImgFormat(curr).lower(); + filter += "\n*|" + i18n( "All Files" ); + + // initial += fromUrl.filename(false); + QString initial = m_currCopyDir + "/"; + initial += fromUrl.filename(false); + KURL fileName = KFileDialog::getSaveURL ( initial, + filter, this ); + + if ( fileName.isValid() ) // got a file name + { + if( fromUrl == fileName ) return; + + /* Since it is asynchron, we will never get if it succeeded. */ + ImgSaver::copyImage( fromUrl, fileName ); + + /* remember the filename for the next export */ + fileName.setFileName( QString()); + m_currCopyDir = fileName.url( ); + } + } +} + + +void ScanPackager::slotImportFile() +{ + KFileTreeViewItem *curr = currentKFileTreeViewItem(); + if( ! curr ) return; + + KURL impTarget = curr->url(); + + if( ! curr->isDir() ) + { + KFileTreeViewItem *pa = static_cast(curr->parent()); + impTarget = pa->url(); + } + kdDebug(28000) << "Importing to " << impTarget.url() << endl; + + KURL impUrl = KFileDialog::getImageOpenURL ( m_currImportDir, this, i18n("Import Image File to Gallery")); + + if( ! impUrl.isEmpty() ) + { + m_currImportDir = impUrl.url(); + impTarget.addPath( impUrl.fileName()); // append the name of the sourcefile to the path + m_nextUrlToShow = impTarget; + ImgSaver::copyImage( impUrl, impTarget ); + } +} + + + +void ScanPackager::slotUrlsDropped( QWidget*, QDropEvent* ev, KURL::List& urls, KURL& copyTo ) +{ + if( !urls.isEmpty() ) + { + kdDebug(28000) << "Kooka drop event!" << endl; + // kdDebug(28000) << "Kooka drop event. First src url=" << urls.first() << " copyTo=" << copyTo + // << " move=" << ( ev->action() == QDropEvent::Move ) << endl; + + /* first make the last url to copy to the one to select next */ + if( ! urls.empty() ) + { + KURL nextSel = copyTo; + nextSel.addPath( urls.back().fileName(false)); + + kdDebug(28000) << "Selecting next url: " << nextSel.url() << endl; + m_nextUrlToShow = nextSel; + // slotSetNextUrlToSelect( nextSel ); + } + + if ( ev->action() == QDropEvent::Move ) + copyjob = KIO::move( urls, copyTo, true ); + else + copyjob = KIO::copy( urls, copyTo, true ); + } +} + +void ScanPackager::slotCanceled( KIO::Job* ) +{ + kdDebug(28000) << i18n("Canceled by user") << endl; +} + + +/* ----------------------------------------------------------------------- */ +void ScanPackager::slotUnloadItems( ) +{ + KFileTreeViewItem *curr = currentKFileTreeViewItem(); + emit( showImage( 0L )); + slotUnloadItem( curr ); +} + +void ScanPackager::slotUnloadItem( KFileTreeViewItem *curr ) +{ + if( ! curr ) return; + + if( curr->isDir()) + { + KFileTreeViewItem *child = static_cast(curr->firstChild()); + while( child ) + { + kdDebug(28000) << "Unloading item " << child << endl; + slotUnloadItem( child ); + child = static_cast (child->nextSibling()); + } + } + else + { + KFileItem *kfi = curr->fileItem(); + KookaImage *image = static_cast(kfi->extraData( this )); + + /* If image is zero, ok, than there is nothing to unload :) */ + if( image ) + { + if( image->subImagesCount() > 0 ) + { + KFileTreeViewItem *child = static_cast(curr->firstChild()); + + while( child ) + { + KFileTreeViewItem *nextChild = 0; + kdDebug(28000) << "Unloading subimage item " << child << endl; + slotUnloadItem( child ); + nextChild = static_cast (child->nextSibling()); + delete child; + child = nextChild; + } + } + + emit( unloadImage( image )); + delete image; + kfi->removeExtraData( this ); + slotDecorate( curr ); + } + } +} + +/* ----------------------------------------------------------------------- */ +void ScanPackager::slotDeleteItems( ) +{ + KFileTreeViewItem *curr = currentKFileTreeViewItem(); + if( ! curr ) return; + + KURL urlToDel = curr->url(); + QListViewItem *nextToSelect = curr->nextSibling(); + + kdDebug(28000) << "Deleting: " << urlToDel.prettyURL() << endl; + bool ask = true; /* for later use */ + + int result = KMessageBox::Yes; + + KFileItem *item = curr->fileItem(); + if( ask ) + { + QString s; + s = i18n("Do you really want to delete this image?\nIt cannot be restored!" ); + if( item->isDir() ) + { + s = i18n("Do you really want to delete the folder %1\nand all the images inside?").arg(""); + } + result = KMessageBox::warningContinueCancel(this, s, i18n( "Delete Collection Item"), + KStdGuiItem::del(), "AskForDeleteFiles" ); + } + + /* Since we are currently talking about local files here, NetAccess is OK */ + if( result == KMessageBox::Continue ) + { + if( KIO::NetAccess::del( urlToDel, 0 )) + { + if( nextToSelect ) + setSelected( nextToSelect, true ); + /* TODO: remove the directory from the imageNameCombobox */ + if( curr && item->isDir() ) + { + /* The directory needs to be removed from the name combo */ + emit(directoryToRemove( curr->branch(), itemDirectory( curr, true ) )); + } + + } + else + kdDebug(28000) << "Deleting files failed" << endl; + + } +} + +/* ----------------------------------------------------------------------- */ +void ScanPackager::slotCreateFolder( ) +{ + bool ok; + QString folder = KInputDialog::getText( i18n( "New Folder" ), + i18n( "Please enter a name for the new folder:" ), QString::null, + &ok, this ); + + if( ok ) + { + /* KIO create folder goes here */ + + KFileTreeViewItem *it = currentKFileTreeViewItem(); + if( it ) + { + KURL url = it->url(); + + /* If a directory is selected, the filename needs not to be deleted */ + if( ! it->isDir()) + url.setFileName( "" ); + /* add the folder name from user input */ + url.addPath( folder ); + kdDebug(28000) << "Creating folder " << url.prettyURL() << endl; + + /* Since the new directory arrives in the packager in the newItems-slot, we set a + * variable urlToSelectOnArrive here. The newItems-slot will honor it and select + * the treeviewitem with that url. + */ + slotSetNextUrlToSelect( url ); + + if( ! KIO::NetAccess::mkdir( url, 0, -1 )) + { + kdDebug(28000) << "ERR: creation of " << url.prettyURL() << " failed !" << endl; + } + else + { + /* created successfully */ + /* open the branch if necessary and select the new folder */ + + } + } + } +} + + +/* ----------------------------------------------------------------------- */ +QString ScanPackager::getImgName( QString name_on_disk ) +{ + QString s; + (void) name_on_disk; + + s = i18n("image %1").arg(img_counter++); + return( s ); +} + +/* ----------------------------------------------------------------------- */ +ScanPackager::~ScanPackager(){ + kdDebug(29000) << "Destructor of ScanPackager" << endl; + +} + +/* called whenever one branch detects a deleted file */ +void ScanPackager::slotDeleteFromBranch( KFileItem* kfi ) +{ + emit fileDeleted( kfi ); +} + +void ScanPackager::contentsDragMoveEvent( QDragMoveEvent *e ) +{ + if( ! acceptDrag( e ) ) + { + e->ignore(); + return; + } + + QListViewItem *afterme = 0; + QListViewItem *parent = 0; + + findDrop( e->pos(), parent, afterme ); + + // "afterme" is 0 when aiming at a directory itself + QListViewItem *item = afterme ? afterme : parent; + + if( item ) + { + bool isDir = static_cast (item)->isDir(); + if( isDir ) { + KFileTreeView::contentsDragMoveEvent( e ); // for the autoopen code + return; + } + } + e->acceptAction(); +} + + +#include "scanpackager.moc" diff --git a/kooka/scanpackager.h b/kooka/scanpackager.h new file mode 100644 index 00000000..13173050 --- /dev/null +++ b/kooka/scanpackager.h @@ -0,0 +1,167 @@ +/*************************************************************************** + scanpackager.h - description + ------------------- + begin : Fri Dec 17 1999 + copyright : (C) 1999 by Klaas Freitag + email : freitag@suse.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + + +#ifndef SCANPACKAGER_H +#define SCANPACKAGER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/** + *@author Klaas Freitag + */ + +class KURL; +class QPopupMenu; +class KFileTreeViewItem; +class KookaImage; +class KookaImageMeta; +class KFileTreeBranch; + + +typedef enum{ Dummy, NameSearch, UrlSearch } SearchType; + +class JobDescription +{ +public: + enum JobType { NoJob, ImportJob, RenameJob, ExportJob }; + JobDescription():jobType( NoJob ), kioJob(0L), pitem(0L) {} + JobDescription( KIO::Job* kiojob, KFileTreeViewItem *new_item, JobType type ) : + jobType(type), kioJob(kiojob), pitem(new_item) {} + + JobType type( void ) { return( jobType ); } + KFileTreeViewItem *item( void ) { return( pitem ); } + KIO::Job* job( void ){ return( kioJob ); } +private: + JobType jobType; + KIO::Job* kioJob; + KFileTreeViewItem* pitem; +}; + +class ScanPackager : public KFileTreeView +{ + Q_OBJECT +public: + ScanPackager( QWidget *parent); + ~ScanPackager(); + virtual QString getImgName( QString name_on_disk ); + + QString getCurrImageFileName( bool ) const; + KookaImage* getCurrImage() const; + + KFileTreeBranch* openRoot( const KURL&, bool open=false ); + + QPopupMenu *contextMenu() const { return m_contextMenu; } + void openRoots(); + +public slots: + void slSelectImage( const KURL& ); + void slAddImage( QImage *img, KookaImageMeta* meta = 0 ); + void slShowContextMenue(QListViewItem *, const QPoint &, int ); + + void slotExportFile( ); + void slotImportFile(); + void slotCanceled(KIO::Job*); + void slotCurrentImageChanged( QImage* ); + + void slotDecorate( KFileTreeViewItem* ); + void slotDecorate( KFileTreeBranch*, const KFileTreeViewItemList& ); + + void slotSelectDirectory( const QString& ); + +protected: + virtual void contentsDragMoveEvent( QDragMoveEvent *e ); + +protected slots: + void slClicked( QListViewItem * ); + void slFileRename( QListViewItem*, const QString&, int ); + // void slFilenameChanged( KFileTreeViewItem*, const KURL & ); + void slImageArrived( KFileTreeViewItem *item, KookaImage* image ); + void slotCreateFolder( ); + void slotDeleteItems( ); + void slotUnloadItems( ); + void slotUnloadItem( KFileTreeViewItem *curr ); + void slotDirCount( KFileTreeViewItem *item, int cnt ); + void slotUrlsDropped( QWidget*, QDropEvent*, KURL::List& urls, KURL& copyTo ); + void slotDeleteFromBranch( KFileItem* ); + void slotStartupFinished( KFileTreeViewItem * ); +signals: + void showImage ( KookaImage* ); + void deleteImage( KookaImage* ); + void unloadImage( KookaImage* ); + void galleryPathSelected( KFileTreeBranch* branch, const QString& relativPath ); + void directoryToRemove( KFileTreeBranch *branch, const QString& relativPath ); + void showThumbnails( KFileTreeViewItem* ); + + void aboutToShowImage( const KURL& ); /* starting to load image */ + void imageChanged( KFileItem* ); /* the image has changed */ + + void fileDeleted( KFileItem* ); + void fileChanged( KFileItem* ); + void fileRenamed( KFileItem*, const KURL& ); + +private: + QString localFileName( KFileTreeViewItem* it ) const; + void loadImageForItem( KFileTreeViewItem* item ); + QCString getImgFormat( KFileTreeViewItem* item ) const; + + QString buildNewFilename( QString cmplFilename, QString currFormat ) const; + KFileTreeViewItem *spFindItem( SearchType type, const QString name, const KFileTreeBranch* branch = 0 ); + QString itemDirectory( const KFileTreeViewItem*, bool relativ = false ) const; + + // int readDir( QListViewItem *parent, QString dir_to_read ); + void showContextMenu( QPoint p, bool show_folder = true ); + + QString m_currImportDir; + QString m_currCopyDir; + QString currSelectedDir; + KIO::Job *copyjob; + int img_counter; + QPopupMenu *m_contextMenu; + + // like m_nextUrlToSelect in KFileTreeView but for our own purposes (showing the image) + KURL m_nextUrlToShow; + + QPixmap m_floppyPixmap; + QPixmap m_grayPixmap; + QPixmap m_bwPixmap; + QPixmap m_colorPixmap; + + KFileTreeBranch *m_defaultBranch; + bool m_startup; +}; + +#endif diff --git a/kooka/thumbview.cpp b/kooka/thumbview.cpp new file mode 100644 index 00000000..5dfa93b6 --- /dev/null +++ b/kooka/thumbview.cpp @@ -0,0 +1,494 @@ +/*************************************************************************** + thumbview.cpp - Class to display thumbnailed images + ------------------- + begin : Tue Apr 18 2002 + copyright : (C) 2002 by Klaas Freitag + email : freitag@suse.de + + $Id$ + ***************************************************************************/ + + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "thumbview.h" +#include "thumbview.moc" + +#include "thumbviewitem.h" + + + +ThumbView::ThumbView( QWidget *parent, const char *name ) + : QVBox( parent ), + m_iconView(0), + m_job(0) +{ + setMargin(3); + m_pixWidth = 0; + m_pixHeight = 0; + m_thumbMargin = 5; + m_iconView = new KIconView( this, name ); + m_progress = new KProgress( this ); + m_progress->hide(); + + m_pixWidth = 100; + m_pixHeight = 100; + + readSettings(); + + m_basePix.resize( QSize( m_pixWidth, m_pixHeight ) ); + m_basePix.fill(); // fills white per default TODO + + + m_iconView->setItemsMovable( false ); + + slSetBackGround(); + + connect( m_iconView, SIGNAL( executed( QIconViewItem* )), + this, SLOT( slDoubleClicked( QIconViewItem* ))); + + m_pendingJobs.setAutoDelete(false); +} + +ThumbView::~ThumbView() +{ + saveConfig(); +} + +bool ThumbView::readSettings() +{ + KConfig *cfg = KGlobal::config(); + cfg->setGroup( THUMB_GROUP ); + bool dirty = false; + + QColor color; + color = cfg->readColorEntry( MARGIN_COLOR1, &(colorGroup().base())); + if( color != m_marginColor1 ) + { + dirty = true; + m_marginColor1 = color; + } + + color = cfg->readColorEntry( MARGIN_COLOR2, &(colorGroup().foreground())); + if( color != m_marginColor2 ) + { + dirty = true; + m_marginColor2 = color; + } + + int value; + bool sizeDirty = false; + value = cfg->readNumEntry( THUMB_MARGIN, 5 ); + if( value != m_thumbMargin ) + { + sizeDirty = true; + m_thumbMargin = value; + } + + value = cfg->readNumEntry( PIXMAP_WIDTH, 100 ); + if( value != m_pixWidth || m_pixWidth == 0 ) + { + sizeDirty = true; + m_pixWidth = value; + } + + value = cfg->readNumEntry( PIXMAP_HEIGHT, 120 ); + if( value != m_pixHeight || m_pixHeight == 0 ) + { + sizeDirty = true; + m_pixHeight = value; + } + + if( sizeDirty ) + { + int gX = 2*m_thumbMargin+m_pixWidth+10; + int gY = 2*m_thumbMargin+m_pixHeight+10; + m_iconView->setGridX(gX); + m_iconView->setGridY(gY); + kdDebug(28000) << "Setting Grid " << gX << " - " << gY << endl; + } + + KStandardDirs stdDir; + QString newBgImg = cfg->readEntry( BG_WALLPAPER, stdDir.findResource( "data", STD_TILE_IMG ) ); + + if( m_bgImg != newBgImg ) + { + m_bgImg = newBgImg; + slSetBackGround(); + } + + return (sizeDirty || dirty); +} + +void ThumbView::slDoubleClicked( QIconViewItem *qIt ) +{ + ThumbViewItem *it = static_cast( qIt ); + + if( it ) + { + const KURL url = it->itemUrl(); + + emit( selectFromThumbnail( url )); + } +} + +void ThumbView::slSetBackGround( ) +{ + QPixmap bgPix; + if( m_bgImg.isEmpty()) + { + bgPix.resize( QSize(16, 16)); + bgPix.fill( QPixmap::blue ); + } + else + { + bgPix.load( m_bgImg ); + } + + m_iconView->setPaletteBackgroundPixmap ( bgPix ); + setPaletteBackgroundPixmap ( bgPix ); + +} + +void ThumbView::slImageChanged( KFileItem *kfit ) +{ + if( ! kfit ) return; + // kdDebug(28000) << "changes to one thumbnail!" << endl; + + KURL thumbDir = currentDir(); + KURL itemUrl = kfit->url(); + + /* delete filename */ + itemUrl.setFileName( QString()); + if( !itemUrl.equals( thumbDir, true )) + { + // kdDebug(28000) << "returning, because directory does not match: " << itemUrl.prettyURL() << endl; + // kdDebug(28000) << "and my URL: " << thumbDir.prettyURL() << endl; + return; + } + + if( deleteImage( kfit )) + { + kdDebug(28000) << "was changed, deleted first!" << endl; + } + /* Trigger a new reading */ + KFileItemList li; + li.append( kfit ); + slNewFileItems( li ); +} + +void ThumbView::slImageRenamed( KFileItem *kfit, const KURL& newUrl ) +{ + const KURL url = kfit->url(); + + if( kfit->isDir() ) { + clear(); + } + + for ( QIconViewItem *item = m_iconView->firstItem(); item; item = item->nextItem() ) + { + ThumbViewItem *it=static_cast( item ); + + if( url == it->itemUrl() ) + { + it->setItemUrl( newUrl ); + + break; + } + } +} + + +void ThumbView::slCheckForUpdate( KFileItem *kfit ) +{ + if( ! kfit ) return; + + kdDebug(28000) << "Checking for update of thumbview!" << endl; + + KURL searchUrl = kfit->url(); + bool haveItem = false; + + /* iterate over all icon items and compare urls. + * TODO: Check the parent url to avoid iteration over all */ + for ( QIconViewItem *item = m_iconView->firstItem(); item && !haveItem; + item = item->nextItem() ) + { + if( searchUrl == static_cast(item)->itemUrl() ) + { + haveItem = true; + } + } + + /* if we still do not have the item, it is not in the thumbview. */ + if( ! haveItem ) + { + KFileItemList kfiList; + + kfiList.append( kfit ); + slNewFileItems( kfiList ); + } + +} + + +bool ThumbView::deleteImage( KFileItem *kfit ) +{ + if( ! kfit ) return false; + + + KURL searchUrl = kfit->url(); + bool haveItem = false; + + /* iterate over all icon items and compare urls. + * TODO: Check the parent url to avoid iteration over all */ + for ( QIconViewItem *item = m_iconView->firstItem(); item && !haveItem; item = item->nextItem() ) + { + if( searchUrl == static_cast(item)->itemUrl() ) + { + m_iconView->takeItem( item ); + haveItem = true; + } + } + kdDebug(28000) << "Deleting image from thumbview, result is " << haveItem << endl; + return( haveItem ); +} + +void ThumbView::slImageDeleted( KFileItem *kfit ) +{ + deleteImage( kfit ); + + + /* + From a mail from Waldo pointing out two probs in Thumbview: + + 1) KDirLister is the owner of the KFileItems it emits, this means + that you must watch it's deleteItem() signal vigourously, + otherwise you may end up with KFileItems that are already + deleted. This burden is propagated to classes that use + KDirLister, such as KFileIconView. + + This has a tendency to go wrong in combination with PreviewJob, + because it stores a list of KFileItems while running. This has + the potential to crash if the fileitems are being deleted + during this time. The remedy is to make sure to remove + fileitems that get deleted from the PreviewJob with + PreviewJob::removeItem. + + */ + if( m_job ) /* is a job running? Remove the item from it if existing. */ + { + m_job->removeItem( kfit ); + } + + /* check if it is in the pending list */ + m_pendingJobs.removeRef(kfit); +} + + +void ThumbView::slNewFileItems( const KFileItemList& items ) +{ + kdDebug(28000) << "Creating thumbnails for fileItemList" << endl; + + /* Fill the pending jobs list. */ + KFileItemListIterator it( items ); + KFileItem *item = 0; + for ( ; (item = it.current()); ++it ) + { + QString filename = item->url().prettyURL(); + if( item->isDir() ) + { + /* create a dir pixmap */ + } + else + { + QPixmap p(m_basePix) ; + QPixmap mime( item->pixmap(0) ); + + if( p.width() > mime.width() && p.height() > mime.height() ) + { + QPainter paint( &p ); + paint.drawPixmap( (p.width()-mime.width())/2, + (p.height()-mime.height())/2, + mime ); + paint.flush(); + } + + /* Create a new empty preview pixmap and store the pointer to it */ + ThumbViewItem *newIconViewIt = new ThumbViewItem( m_iconView, + item->url().filename(), + createPixmap( p ), + item ); + + newIconViewIt->setItemUrl( item->url() ); + + /* tell the file item about the iconView-representation */ + item->setExtraData( this, newIconViewIt ); + + m_pendingJobs.append( item ); + } + } + + /* + From a mail from Waldo Bastian pointing out problems with thumbview: + + 2) I think you may end up creating two PreviewJob's in parallel + when the slNewFileItems() function is called two times in + quick succession. The current code doesn't seem to expect + that, given the comment in slPreviewResult(). In the light of + 1) it might become fatal since you will not be able to call + PreviewJob::removeItem on the proper job. I suggest to queue + new items when a job is already running and start a new job + once the first one is finished when there are any items left + in the queue. Don't forget to delete items from the queue if + they get deleted in the mean time. + + The strategy is as follows: In the global list m_pendingJobs + the jobs to start are appended. Only if m_job is zero (no job + is running) a job is started on the current m_pendingJobs list. + The m_pendingJobs list is clear afterwords. + */ + + if( ! m_job && m_pendingJobs.count() > 0 ) + { + /* Progress-Bar */ + m_progress->show(); + m_progress->setTotalSteps(m_pendingJobs.count()); + m_cntJobsStarted = 0; + + /* start a preview-job */ + m_job = KIO::filePreview(m_pendingJobs, m_pixWidth, m_pixHeight ); + + if( m_job ) + { + connect( m_job, SIGNAL( result( KIO::Job * )), + this, SLOT( slPreviewResult( KIO::Job * ))); + connect( m_job, SIGNAL( gotPreview( const KFileItem*, const QPixmap& )), + SLOT( slGotPreview( const KFileItem*, const QPixmap& ) )); + + m_pendingJobs.clear(); + + /* KIO::Jo result is called in any way: Success, Failed, Error, + * thus connecting the failed is not really necessary. + */ + // connect( job, SIGNAL( failed( const KFileItem* )), + // this, SLOT( slotFailed( const KFileItem* ) )); + + } + } +} + + + +void ThumbView::slGotPreview( const KFileItem* newFileItem, const QPixmap& newPix ) +{ + if( ! newFileItem ) return; + KFileIconViewItem *item = static_cast(const_cast(newFileItem->extraData( this ))); + + if( ! item ) return; + + item->setPixmap( createPixmap(newPix) ); + m_cntJobsStarted+=1; + + m_progress->setProgress(m_cntJobsStarted); + + // kdDebug(28000)<< "jobs-Counter: " << m_cntJobsStarted << endl; + +} + +void ThumbView::slPreviewResult( KIO::Job *job ) +{ + if( job && job->error() > 0 ) + { + kdDebug(28000) << "Thumbnail Creation ERROR: " << job->errorString() << endl; + job->showErrorDialog( 0 ); + } + + if( job != m_job ) + { + kdDebug(28000) << "Very obscure: Job finished is not mine!" << endl; + } + /* finished */ + kdDebug(28000) << "Thumbnail job finished." << endl; + m_cntJobsStarted = 0; + m_progress->reset(); + m_progress->hide(); + m_job = 0L; + + /* maybe there is a new job to start because of pending items? */ + if( m_pendingJobs.count() > 0 ) + { + slNewFileItems( KFileItemList() ); /* Call with an empty list */ + } +} + + +QPixmap ThumbView::createPixmap( const QPixmap& preview ) const +{ + QImage ires = KImageEffect::unbalancedGradient( QSize( 2*m_thumbMargin+ preview.width(), + 2*m_thumbMargin+ preview.height()), + m_marginColor1, m_marginColor2, + KImageEffect::DiagonalGradient ); + + + QPixmap pixRet; + pixRet.convertFromImage( ires ); + QPainter p( &pixRet ); + + p.drawPixmap( m_thumbMargin, m_thumbMargin, preview ); + p.flush(); + // draw on pixmap + + return( pixRet ); +} + + +void ThumbView::clear() +{ + if( m_job ) + m_job->kill( false /* not silently to get result-signal */ ); + m_iconView->clear(); +} + + +void ThumbView::saveConfig() +{ + KConfig *cfg = KGlobal::config(); + cfg->setGroup( THUMB_GROUP ); + + cfg->writeEntry( MARGIN_COLOR1, m_marginColor1 ); + cfg->writeEntry( MARGIN_COLOR2, m_marginColor2 ); + cfg->writeEntry( PIXMAP_WIDTH, m_pixWidth ); + cfg->writeEntry( PIXMAP_HEIGHT, m_pixHeight ); + cfg->writeEntry( THUMB_MARGIN, m_thumbMargin ); + + +} diff --git a/kooka/thumbview.h b/kooka/thumbview.h new file mode 100644 index 00000000..c16afa84 --- /dev/null +++ b/kooka/thumbview.h @@ -0,0 +1,153 @@ +/*************************************************************************** + thumbview.h - Class to display thumbnailed images + ------------------- + begin : Tue Apr 18 2002 + copyright : (C) 2002 by Klaas Freitag + email : freitag@suse.de + + $Id$ + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#ifndef __THUMBVIEW_H__ +#define __THUMBVIEW_H__ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* KConfig group definitions */ +#define MARGIN_COLOR1 "MarginColor1" +#define MARGIN_COLOR2 "MarginColor2" +#define PIXMAP_WIDTH "pixmapWidth" +#define PIXMAP_HEIGHT "pixmapHeight" +#define THUMB_MARGIN "thumbnailMargin" +#define THUMB_GROUP "thumbnailView" +#define BG_WALLPAPER "BackGroundTile" +#define STD_TILE_IMG "kooka/pics/thumbviewtile.png" + +class QPixmap; +class QListViewItem; +class KProgress; +class KIO::PreviewJob; + +class ThumbView: public QVBox /* KIconView */ +{ + Q_OBJECT + +public: + + ThumbView( QWidget *parent, const char *name=0 ); + ~ThumbView(); + + void setCurrentDir( const KURL& s) + { m_currentDir = s; } + KURL currentDir( ) const + { return m_currentDir; } + + QSize tumbSize( ) const + { + return( QSize( m_pixWidth, m_pixHeight )); + } + + int thumbMargin() const + { + return m_thumbMargin; + } +public slots: + void slSetThumbSize( int w, int h ) + { + m_pixWidth = w; + m_pixHeight = h; + } + void slSetThumbSize( const QSize& s ) + { + m_pixWidth = s.width(); + m_pixHeight = s.height(); + } + + void slSetThumbMargin( int m ) + { + m_thumbMargin = m; + } + + void slNewFileItems( const KFileItemList& ); + void slGotPreview( const KFileItem*, const QPixmap& ); + void slPreviewResult( KIO::Job* ); + + /** + * This connects to the IconView's executed signal and tells the packager + * to select the image + */ + void slDoubleClicked( QIconViewItem* ); + + /** + * indication that a image changed, needs to be reloaded. + */ + void slImageChanged( KFileItem * ); + void slImageDeleted( KFileItem * ); + void slSetBackGround( ); + void slCheckForUpdate( KFileItem* ); + bool readSettings(); + void clear(); + + void slImageRenamed( KFileItem*, const KURL& ); + +protected: + + void saveConfig(); + +signals: + /** + * selects a QListViewItem from the thumbnail. This signal only makes + * sense if connected to a ScanPackager. + */ + void selectFromThumbnail( const KURL& ); + +private: + QPixmap createPixmap( const QPixmap& ) const; + + bool deleteImage( KFileItem* ); + KIconView *m_iconView; + KProgress *m_progress; + + KURL m_currentDir; + QPixmap m_basePix; + int m_pixWidth; + int m_pixHeight; + int m_thumbMargin; + QColor m_marginColor1; + QColor m_marginColor2; + QString m_bgImg; + int m_cntJobsStarted; + KIO::PreviewJob *m_job; + + KFileItemList m_pendingJobs; +}; + +#endif diff --git a/kooka/thumbviewitem.cpp b/kooka/thumbviewitem.cpp new file mode 100644 index 00000000..7f2d01f6 --- /dev/null +++ b/kooka/thumbviewitem.cpp @@ -0,0 +1,49 @@ +/*************************************************************************** + thumbviewitem.cpp - Thumbview item class + ------------------- + begin : Tue Apr 24 2002 + copyright : (C) 2002 by Klaas Freitag + email : freitag@suse.de + + $Id$ + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#include +#include + +#include "thumbview.h" +#include "thumbviewitem.h" + +ThumbViewItem::ThumbViewItem(QIconView *parent, const QString &text, + const QPixmap &pixmap, + KFileItem *fi ) + :KFileIconViewItem( parent, text, pixmap,fi ) +{ + +} + +void ThumbViewItem:: setItemUrl( const KURL& u ) +{ + m_url = u; + setText( m_url.fileName()); +} + + diff --git a/kooka/thumbviewitem.h b/kooka/thumbviewitem.h new file mode 100644 index 00000000..745c2b25 --- /dev/null +++ b/kooka/thumbviewitem.h @@ -0,0 +1,60 @@ +/*************************************************************************** + thumbviewitem.h - Thumbnailview items + ------------------- + begin : Tue Apr 24 2002 + copyright : (C) 2002 by Klaas Freitag + email : freitag@suse.de + + $Id$ + ***************************************************************************/ + +/*************************************************************************** + * * + * This file may be distributed and/or modified under the terms of the * + * GNU General Public License version 2 as published by the Free Software * + * Foundation and appearing in the file COPYING included in the * + * packaging of this file. * + * + * As a special exception, permission is given to link this program * + * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, * + * Kreuzlingen and distribute the resulting executable without * + * including the source code for KADMOS in the source distribution. * + * + * As a special exception, permission is given to link this program * + * with any edition of Qt, and distribute the resulting executable, * + * without including the source code for Qt in the source distribution. * + * * + ***************************************************************************/ + +#ifndef __THUMBVIEWITEM_H__ +#define __THUMBVIEWITEM_H__ + +#include +#include +#include +#include +#include + +class KFileTreeViewItem; + + +class ThumbViewItem: public KFileIconViewItem +{ +public: + ThumbViewItem( QIconView *parent, + const QString &text, + const QPixmap &pixmap, + KFileItem *fi ); + + void setItemUrl( const KURL& u ); + + KURL itemUrl() const + { return m_url; } + +private: + KURL m_url; + + +}; + +#endif diff --git a/kooka/version.h b/kooka/version.h new file mode 100644 index 00000000..2d9da5f7 --- /dev/null +++ b/kooka/version.h @@ -0,0 +1,4 @@ +#ifndef KOOKA_VERSION +#define KOOKA_VERSION "0.44" +#endif + diff --git a/kpdf/AUTHORS b/kpdf/AUTHORS new file mode 100644 index 00000000..e0aae2a7 --- /dev/null +++ b/kpdf/AUTHORS @@ -0,0 +1,6 @@ +Albert Astals Cid +Enrico Ros +Wilco Greven +Christophe Devriese + +XPdf is written by Glyph & Cog, LLC diff --git a/kpdf/COPYING b/kpdf/COPYING new file mode 100644 index 00000000..0b84a43f --- /dev/null +++ b/kpdf/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +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 give any other recipients of the Program a copy of this License +along with the Program. + +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 Program or any portion +of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +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 Program, 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 Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) 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; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, 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 executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or 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 counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program 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. + + 5. 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 Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. 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 Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program 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 Program. + +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. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program 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. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 Program +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 Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, 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 + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/kpdf/Makefile.am b/kpdf/Makefile.am new file mode 100644 index 00000000..fd5ccb49 --- /dev/null +++ b/kpdf/Makefile.am @@ -0,0 +1,30 @@ +SUBDIRS = xpdf conf core ui shell + +INCLUDES = -I$(srcdir)/xpdf -I$(srcdir)/xpdf/goo -I$(top_builddir)/kpdf $(all_includes) $(FREETYPE_CFLAGS) + +METASOURCES = AUTO + +messages: rc.cpp + $(EXTRACTRC) `find . -name "*.rc" -o -name "*.ui"` >> rc.cpp + $(XGETTEXT) `find . -name "*.cpp" -o -name "*.cc" -o -name "*.h"` -o $(podir)/kpdf.pot + +KDE_ICON = kpdf + +######################################################################### +# KPART SECTION +######################################################################### +kde_module_LTLIBRARIES = libkpdfpart.la + +libkpdfpart_la_SOURCES = dcop.skel error.cpp part.cpp +libkpdfpart_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +libkpdfpart_la_LIBADD = xpdf/xpdf/libxpdf.la conf/libkpdfconf.la \ + core/libkpdfcore.la ui/libkpdfui.la $(LIB_KPARTS) \ + $(LIB_KFILE) $(LIB_KDEPRINT) $(LIB_KUTILS) -lm + +partdesktopdir = $(kde_servicesdir) +partdesktop_DATA = kpdf_part.desktop + +partrcdir = $(kde_datadir)/kpdfpart +partrc_DATA = part.rc + +part.lo: conf/settings.h diff --git a/kpdf/README.internals.png b/kpdf/README.internals.png new file mode 100644 index 00000000..92153173 Binary files /dev/null and b/kpdf/README.internals.png differ diff --git a/kpdf/TODO b/kpdf/TODO new file mode 100644 index 00000000..6a00e14a --- /dev/null +++ b/kpdf/TODO @@ -0,0 +1,173 @@ +TODO - KPdf MAIN HEAD +Legend: + ADD - ADDed (new feature) + CHG - CHanGed (existing behavior) + FIX - FIXed (bug or regression) + MRG - MeRGed (code from a branch or a patch) + +In progress: + -- 2005-Feb-26: Merge from 'kpdf_annotations' branch -- + +More items (first items will enter 'In progress list' first): +-> pageview: add scrollbar marks for bookmarks (like kate) +-> screen editing (annotations): framework (BR67300,BR62793) +-> screen editing (annotations): tools (BR67300), yellow notes 'post-it' like +-> go to next/previous bookmark actions (showing in thumbnailslist rmb popup too) +-> viewport restoring: sometimes it seems to restore the viewport a bit under where it was +-> viewport restoring: save the page width setting between runs (save/restore zoom factor) +-> presentation: provide a pageX/totalPages indicator in addition to the circle one +-> cleanup code and update README.png +-> search: use shortcut for 'find next' action (not the default one) in find-ahead +-> show Viewport in ThumbnailsList (blended/contour) +-> Delay TOC (DocumentSynapsis) generation (and move it on thread) +-> add a way to handle "named xpdf links" in KPDFLink instead of resolving all destinations + when displaying a page (speedups a lot generation of page with many links) +-> refactor ThumbnailsList to do internal rendering as pageview does (way faster + than using QScrollView + inserted Widgets and saves 8% on document loading) +-> usability: layout 2PPV [1 2,3 4,5 6] -> [1,2 3,4 5]. add option for 'ebook' style alignment +-> usability: trigger redraw on 'filter text' on current page (need new highligh engine first) +-> abstract TextPage generation (the last xpdf dependant class!). then go dancing in the + streets. +-> Dom framework to cache document metadata. It should archive those types of data: + (NOTE: already Dom'ed object is marked with 'X') + - Synopsis will go there after 1st generation (so we can edit it too) + - Document info (after the 1st gen) + - Bookmarked pages + - Current Viewport and 10 history steps + - Edited pages (rotated/with_data for example) + - Overlay editing (hilighting/notations/etc..) + - Presentation related overrides (FS mode, individual / global transitions) + - ..more stuff.. but this isn't a problem, since a QDom is flexible by design + The Object will reside into the Document and must not be accessible by Oservers in + a direct way. Dom format, relations to other classes and accessing must be specified + in a separated diagram or text file. +-> add kpdf manual in PDF format loaded on the first startup or on menu->help->manual + this visually explains basic usage, mouse buttons functions & more.. +-> take care of TODOs in code +-> ADD: click over image allows "save image" [60% done (activerect of type image)] +-> export all text in plain_text/html +-> extract(export?) images (have a look at ImageOutputDev.cc and pdfimages.cc from xpdf (not in our xpdf sources)) +-> text selection in wordprocessor style (very hard) +-> zoom: fit text (with configurable margin) +-> bookview: 3d opengl widget for viewing the document as a real book (turning pages, etc..) +-> open gzipped (.pdf.gz?) files +-> kspeech TTS interface. speech {document / page / selection(done)} +-> automatic online dictionaries / translators (BR80338) +-> core: pdf forms support +-> add OCR for building TextPages out of pure graphical (aka scanned) pages +-> rotate the whole document / individual pages - Have a look at the fifth parameter of displayPage, it is the rotation, so it should not be THAT hard to implement +-> presentation: implement missing transitions (6/11 done) +-> presentation: add some gfx tools (like a red pencil) +-> presentation: save a flag (to the xml) to open a pdf in presentation mode +-> presentation: wheel not visible on black. gradient appreciated on lighter backgrounds. +-> investigate 'Splash' lack of smoothness at low resolutions (see lines in thumbnails) +-> add search on the toc widget (a 'prune on type' lineedit like in thumbnails widget) +-> goto 'logical' page (usually differs from pdf's page) (req. by Luca Burrelli) +-> use shortcuts for next and prev page even in presenatation mode (by Tobias Koenig) +-> move some document related features from part to the document (see find, goto dialog, ...) +-> Albert: Read pdf specification and see if paths with length = 1 are allowed, in case they are allowed see how to fix 97131 without skipping paths with length = 1 +-> tools: ruler, measure: distance, perimeter, ?area?, color picker +-> export: export to other formats keeping formatting (a dream.. except for PNG :-) (PS is easy, we just have PSOutputDev that does it :-D) +-> history as a toolbox child (collecting Doc's viewport changes notifications) + +Done (newest features come first): +-- merging from kdpf_annotations branch -- +-> ADD: presentation: link following (BR98388) +-> ADD: Save zoom setting on exit +-> ADD: Put fonts used by the document on the properties dialog +-> ADD: partial implementation of XYZ links +-> ADD: google-like search on thumbnails +-> ADD: use kde wallet for storing passwords of protected files +-> ADD: Obey DRM is now a configuration option +-> FIX: leakfix when closing document while thread was running (no more leaks now) +-> FIX: direct hi-performance pixels manipulation for highlighting (instead of the obsoleted setRasterOp) +-> CHG: new search api. supports multiple searches at once, multiple highlighs per page +-> ADD: pageView moves smoothly when searching / moving in history +-> ADD: better bookmark rendering in thumbnailslist (show 'clip overlay') +-> CHG: changes and cleanups in pageView's mouse handling functions +-> ADD: KTTSD simple support: speech selection using kspeech api via pure dcop (don't break compatibiltiy) +-> CHG: right click and drag while in 'normal' mode changes to 'selection' mode and selects +-> FIX: complete valgrind check and leakfix (2 leaks were present) [27-Jan-04] +-> ADD: history, forward/back history actions, history links and xml storage (10 steps) +-> ADD: rmb popup on thumbnailslist (the popup shared with pageView: same behavior) +-> ADD: display 'current page' / 'total pages' with analog indicator, active labels, etc +-> CHG: Presentation mode is now Ctrl+Shift+p instead of F9 because it was colliding with Konqueror's toggle sidebar +-> FIX: various in memory unallocator, preload with single pages, pageview +-> FIX: optimized pageView (removed 1 waster req on start, lowered reqs) +-> FIX: memory unloading order and hard swap avoiding +-> CHG: open and open-recent buttons unified in Shell +-> CHG: lens icon for the find-ahead messages +-> ADD: page preloading +-> FIX: smarter memory management / prioritize queries +-> ADD: type ahead search in pageview (type '/' then the word to search..) (JakubS) +-> FIX: scroll page if the the searched string is not visible +-> FIX: use a global Viewport over the document (linked views, real link following, location restoring, etc) +-> FIX: wrong zoom buttons order (BR74248) (check consistancy with kdvi/kviewshell/kghostview/.. (not konq)) +-> ADD: presentation: cursor modes: hidden, visible, hidden with delay (Tobias) +-> ADD: presentation: default transition which is used when no transition is defined in document (Tobias) +-> ADD: presentation: support for automatic advance and loop on last page (Tobias) +-> ADD: presentation: add additional presentation page to settings dialog (Tobias) +-> CHG: presentation: the round wheel indicator can be clicked to change page +-> FIX: layout margins on pageView +-> ADD: restore the last active page when a file is opened again +-> ADD: Save bookmarks into a file so you they get recovered when opening the same file again (Albert) +-> FIX: searchline back to work +-> CHG: DocumentInfo is now a DomTree and the properties dialog is dynamically generated (Tobias) +-> ADD: Presentation transitions are loaded from the pdf files as well as fullscreen state (Tobias) +-> Merged on HEAD on 2005-01-02 (The branch is frozen, development continues here) +-> FIX: Fix my update cursor FIX :-D +-> ADD: Make kpdf aware of Find and GoToPage actions +-> FIX: Update cursor correctly when a link moves to a page and the cursor is over a link on that page +-> ADD: Asyncronous PDF Generator implementation (for the user: faster UI, preloading, etc..) +-> FIX: Memory manager (free cache if needed, avoid disk swap and oom) +-> ADD: Presentation View (only the 'glitter' transition implemented for now) +-> FIX: FixPack1 [dyn_zoom repaints, initial panel width, zoom_lineedit focus proxy, searchwidget refactor{thumbs restoring on clear, buttons size, less code}, hilight bookmarked thumbnails] +-> FIX: Some fullScreen loving, if we are on fullscreen put an action on RMB menu ti get out of it, if we were on fullScreen mode on exit bring back correctly if we were also seeing toolbar or menubar +-> FIX: When in non continuous mode and scrolling up a page, set the viewport at the bottom of the page (Albert) +-> ADD: Show the window maximized when the user opens the program for the very first time (Albert) +-> ADD: Use 'Generators' as providers for contents generation +-> ADD: Add properties dialog (Albert) +-> ADD: Support for show/hide menubar in rmb menu, different from HEAD so that supports Konqueror too (Albert) +-> ADD: Watch File option (Albert) +-> ADD: import Marco Martin's "another kpdf icon" (kde-look: 16146) (Albert) +-> ADD: dynamic zoom with mid mouse button (click and drag up-down to zoom in-out) +-> FIX: merge select text & select gfx, two sections on the same pop-up menu +-> ADD: reading aids (inverted display, recolor, black/white, draw link border, draw image border) +-> FIX: zoom preserved when switching modes and flickerless drawing +-> ADD: Printing as PS instead of as image (Albert) +-> ADD: Remember page on session logout and put the document in it on session restore (Albert) +-> ADD: gfx capturing tool +-> ADD: composited renderer framework (in addition to a fast light one) +-> FIX: pageview repaint done internally (speed boost and reduced memory consumption) +-> ADD: KConfigXT settings framework and Accessibility config (acc. code mostly not done) +-> FIX: workaround for scrollview bug 1/2 (painting hidden widgets under certain circumstances) +-> ADD: zoom into a rect defined by mouse (aka zoom to window) +-> FIX: sheet rotation in landscape case +-> ADD: Some dcop functions (goToPage, openDocument and give # of pages) (Albert) +-> MRG: link following ('actionMovie' kind is missing) +-> ADD: text selection (rectangular blocks) in selection mode +-> ADD: autoscroll page with Shift+Up/Dn keys (exact konqueror's behavior) +-> CHG: remake single page mode +-> FIX: zoom buttons in sync with text +-> ADD: continuous mode +-> ADD: multiple pages per view (gui selects 1 or 2 ppv) +-> MRG: the option to open password protected files (from head) +-> MRG: the Table Of Contents (from head) +-> ADD: a 'search bar' with prune-as-you-type feature +-> MRG: Albert's search ported and implemented case sensitive +-> CHG: smart handling of pixmap using an Observer ID (thumbnails are gone, only pixmaps now) +-> FIX: some toolbar/menu changes +-> ADD: outline bottom and right edges (of pages) +-> FIX: centering pages in the view +-> FIX: kpdf output at 100% has exactly the same size as acroread now +-> CHG: qsplitter layouting +-> FIX: zooming works as expected (and added 'fit to page' too) +-> ADD: new go to page dialog +-> GHG: previews sorted by visible areas (prioritize items where the scrollbar is) +-> FIX: previews speedup: 50-100% +-> CHG: use local instead of X memory for thumbnails (..) +-> MRG: merge lots of kpdf_part and part (centralview) code (to simplify/clenup) +-> The branch 'kpdf_experiments' was created at this point. Code refactoring started. +-> ADD: Completely use xpdf code for rendering that solves most font problems (Albert) +-> MRG: Replace xpdf version with lastest one (3.00) that supports PDF 1.5 (Albert) +-> newest added features are at the top of the list diff --git a/kpdf/VERSION b/kpdf/VERSION new file mode 100644 index 00000000..146734d9 --- /dev/null +++ b/kpdf/VERSION @@ -0,0 +1 @@ +KPDF v0.5.10 diff --git a/kpdf/conf/Makefile.am b/kpdf/conf/Makefile.am new file mode 100644 index 00000000..d115e8f9 --- /dev/null +++ b/kpdf/conf/Makefile.am @@ -0,0 +1,13 @@ +INCLUDES = -I$(srcdir)/.. -I$(top_builddir)/kpdf $(all_includes) + +METASOURCES = AUTO + +libkpdfconf_la_SOURCES = dlggeneral.ui dlgperformance.ui dlgaccessibility.ui \ + dlgpresentation.ui \ + preferencesdialog.cpp settings.kcfgc + +noinst_LTLIBRARIES = libkpdfconf.la + +kde_kcfg_DATA = kpdf.kcfg + +preferencesdialog.lo: settings.h diff --git a/kpdf/conf/dlgaccessibility.ui b/kpdf/conf/dlgaccessibility.ui new file mode 100644 index 00000000..a9f6495d --- /dev/null +++ b/kpdf/conf/dlgaccessibility.ui @@ -0,0 +1,576 @@ + +DlgAccessibility + + + DlgAccessibility + + + + 0 + 0 + 376 + 364 + + + + + unnamed + + + 0 + + + + kcfg_HighlightImages + + + Draw border around &Images + + + + + kcfg_HighlightLinks + + + Draw border around &Links + + + + + kcfg_ChangeColors + + + + 5 + 4 + 0 + 0 + + + + Change &Colors + + + true + + + false + + + + unnamed + + + + warn + + + + 5 + 4 + 0 + 0 + + + + + 80 + 0 + 0 + + + + Warning: these options can badly affect drawing speed. + + + PlainText + + + + + kcfg_RenderMode + + + false + + + + 5 + 4 + 0 + 0 + + + + NoFrame + + + 0 + + + + + + + unnamed + + + 0 + + + + radioInverted + + + &Invert colors + + + true + + + + + radioNormal + + + Change &paper color + + + + + layout5 + + + + unnamed + + + + spacer14_3 + + + Horizontal + + + Fixed + + + + 16 + 20 + + + + + + textLabel1 + + + false + + + Paper color: + + + kcfg_PaperColor + + + + + kcfg_PaperColor + + + false + + + + + + + + spacer7_2 + + + Horizontal + + + Expanding + + + + 30 + 20 + + + + + + + + radioRecolor + + + &Change dark and light colors + + + + + layout2 + + + + unnamed + + + 0 + + + + spacer12_2 + + + Horizontal + + + Expanding + + + + 48 + 21 + + + + + + kcfg_RecolorBackground + + + false + + + + + + + + spacer14_2 + + + Horizontal + + + Fixed + + + + 16 + 20 + + + + + + kcfg_RecolorForeground + + + false + + + + + + + + spacer12 + + + Horizontal + + + Expanding + + + + 48 + 21 + + + + + + textLabel3_2 + + + false + + + Light color: + + + + + spacer14 + + + Horizontal + + + Fixed + + + + 16 + 20 + + + + + + textLabel3 + + + false + + + Dark color: + + + + + + + radioContrast + + + Convert to &black and white + + + + + layout5 + + + + unnamed + + + + textLabel2_2 + + + false + + + Contrast: + + + + + spacer10_2 + + + Horizontal + + + Expanding + + + + 48 + 21 + + + + + + spacer11_2 + + + Horizontal + + + Fixed + + + + 16 + 20 + + + + + + spacer11 + + + Horizontal + + + Fixed + + + + 16 + 20 + + + + + + spacer10 + + + Horizontal + + + Expanding + + + + 48 + 21 + + + + + + kcfg_BWContrast + + + false + + + + 7 + 0 + 0 + 0 + + + + 1 + + + Horizontal + + + + + kcfg_BWThreshold + + + false + + + + 7 + 0 + 0 + 0 + + + + 16 + + + Horizontal + + + + + textLabel2 + + + false + + + Threshold: + + + + + + + + + + + + + radioRecolor + toggled(bool) + textLabel3 + setEnabled(bool) + + + radioRecolor + toggled(bool) + kcfg_RecolorForeground + setEnabled(bool) + + + radioRecolor + toggled(bool) + textLabel3_2 + setEnabled(bool) + + + radioRecolor + toggled(bool) + kcfg_RecolorBackground + setEnabled(bool) + + + radioContrast + toggled(bool) + textLabel2 + setEnabled(bool) + + + radioContrast + toggled(bool) + kcfg_BWThreshold + setEnabled(bool) + + + radioNormal + toggled(bool) + textLabel1 + setEnabled(bool) + + + radioNormal + toggled(bool) + kcfg_PaperColor + setEnabled(bool) + + + radioContrast + toggled(bool) + textLabel2_2 + setEnabled(bool) + + + radioContrast + toggled(bool) + kcfg_BWContrast + setEnabled(bool) + + + kcfg_ChangeColors + toggled(bool) + kcfg_RenderMode + setEnabled(bool) + + + + kdialog.h + + + + kcolorbutton.h + kcolorbutton.h + kcolorbutton.h + + diff --git a/kpdf/conf/dlggeneral.ui b/kpdf/conf/dlggeneral.ui new file mode 100644 index 00000000..0319d1b4 --- /dev/null +++ b/kpdf/conf/dlggeneral.ui @@ -0,0 +1,171 @@ + +DlgGeneral + + + DlgGeneral + + + + 0 + 0 + 320 + 300 + + + + + unnamed + + + 0 + + + + groupBox2 + + + Program Look + + + + unnamed + + + + layout4 + + + + unnamed + + + + kcfg_ShowSearchBar + + + true + + + Show &search bar in thumbnails list + + + + + kcfg_SyncThumbnailsViewport + + + true + + + Link the &thumbnails with the page + + + + + kcfg_ShowScrollBars + + + Show scroll&bars + + + + + kcfg_ShowOSD + + + Show &hints and info messages + + + + + kcfg_ObeyDRM + + + &Obey DRM limitations + + + + + kcfg_WatchFile + + + &Watch file + + + + + + + layout3_2 + + + + unnamed + + + + pixmapLabel1_2 + + + + 0 + 0 + 0 + 0 + + + + "kpdf", 32 + + + + + spacerV1 + + + Vertical + + + Minimum + + + + 20 + 1 + + + + + + + + + + spacer3 + + + Vertical + + + Expanding + + + + 20 + 20 + + + + + + + kdialog.h + kiconloader.h + dlggeneral.ui.h + + + showEvent( QShowEvent * ) + +DesktopIcon + + diff --git a/kpdf/conf/dlggeneral.ui.h b/kpdf/conf/dlggeneral.ui.h new file mode 100644 index 00000000..8eafde39 --- /dev/null +++ b/kpdf/conf/dlggeneral.ui.h @@ -0,0 +1,26 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you want to add, delete, or rename functions or slots, use +** Qt Designer to update this file, preserving your code. +** +** You should not define a constructor or destructor in this file. +** Instead, write your code in functions called init() and destroy(). +** These will automatically be called by the form's constructor and +** destructor. +*****************************************************************************/ + +#include + +#include + +void DlgGeneral::showEvent( QShowEvent * ) +{ +#if KPDF_FORCE_DRM + kcfg_ObeyDRM->hide(); +#else + if (kapp->authorize("skip_drm")) kcfg_ObeyDRM->show(); + else kcfg_ObeyDRM->hide(); +#endif +} + diff --git a/kpdf/conf/dlgperformance.ui b/kpdf/conf/dlgperformance.ui new file mode 100644 index 00000000..c0c90eb1 --- /dev/null +++ b/kpdf/conf/dlgperformance.ui @@ -0,0 +1,278 @@ + +DlgPerformance + + + DlgPerformance + + + + 0 + 0 + 284 + 222 + + + + + unnamed + + + 0 + + + + groupBox1 + + + + 5 + 4 + 0 + 0 + + + + CPU Usage + + + + unnamed + + + + layout9 + + + + unnamed + + + + kcfg_EnableCompositing + + + Enable &transparency effects + + + + + kcfg_EnableThreading + + + Enable &background generation + + + + + + + layout6_2 + + + + unnamed + + + + pixmapLabel1_2 + + + + 0 + 0 + 0 + 0 + + + + "kcmprocessor", 32 + + + + + spacer7_2 + + + Vertical + + + Minimum + + + + 21 + 1 + + + + + + + + + + kcfg_MemoryLevel + + + + 5 + 4 + 0 + 0 + + + + Memory Usage + + + + unnamed + + + + descLabel + + + + + + PlainText + + + WordBreak|AlignVCenter + + + + + layout5 + + + + unnamed + + + + lowRadio + + + &Low + + + + + normalRadio + + + &Normal (default) + + + + + aggressiveRadio + + + &Aggressive + + + + + + + layout6 + + + + unnamed + + + + pixmapLabel1 + + + + 0 + 0 + 0 + 0 + + + + "kcmmemory", 32 + + + + + spacer7 + + + Vertical + + + Minimum + + + + 21 + 1 + + + + + + + + + + spacer1 + + + Vertical + + + Expanding + + + + 21 + 16 + + + + + + + + lowRadio + toggled(bool) + DlgPerformance + lowRadio_toggled(bool) + + + normalRadio + toggled(bool) + DlgPerformance + normalRadio_toggled(bool) + + + aggressiveRadio + toggled(bool) + DlgPerformance + aggressiveRadio_toggled(bool) + + + + kdialog.h + kiconloader.h + dlgperformance.ui.h + + + lowRadio_toggled( bool on ) + normalRadio_toggled( bool on ) + aggressiveRadio_toggled( bool on ) + + + init() + +DesktopIcon + + diff --git a/kpdf/conf/dlgperformance.ui.h b/kpdf/conf/dlgperformance.ui.h new file mode 100644 index 00000000..4a13310e --- /dev/null +++ b/kpdf/conf/dlgperformance.ui.h @@ -0,0 +1,38 @@ +/*************************************************************************** + * Copyright (C) 2004 by Enrico Ros * + * * + * 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. * + ***************************************************************************/ + +#include + +// The purpose of this file is only to display a sort of descriptive text +// when the user clicks on each memory profile. + +void DlgPerformance::init() +{ + QFont labelFont = descLabel->font(); + labelFont.setBold( true ); + descLabel->setFont( labelFont ); +} + +void DlgPerformance::lowRadio_toggled( bool on ) +{ + if ( on ) + descLabel->setText( i18n("Keeps used memory as low as possible. Do not reuse anything. (For systems with low memory.)") ); +} + +void DlgPerformance::normalRadio_toggled( bool on ) +{ + if ( on ) + descLabel->setText( i18n("A good compromise between memory usage and speed gain. Preload next page and boost searches. (For systems with 256MB of memory, typically.)") ); +} + +void DlgPerformance::aggressiveRadio_toggled( bool on ) +{ + if ( on ) + descLabel->setText( i18n("Keeps everything in memory. Preload next pages. Boost searches. (For systems with more than 512MB of memory.)") ); +} diff --git a/kpdf/conf/dlgpresentation.ui b/kpdf/conf/dlgpresentation.ui new file mode 100644 index 00000000..ba65f7b1 --- /dev/null +++ b/kpdf/conf/dlgpresentation.ui @@ -0,0 +1,282 @@ + +DlgPresentation + + + DlgPresentation + + + + 0 + 0 + 294 + 261 + + + + + unnamed + + + 0 + + + + groupBox1 + + + Navigation + + + + unnamed + + + + layout1 + + + + unnamed + + + + kcfg_SlidesAdvanceTime + + + false + + + sec. + + + 5 + + + + + kcfg_SlidesAdvance + + + Advance every: + + + + + kcfg_SlidesLoop + + + Loop after last page + + + + + + + + + groupBox2 + + + Appearance + + + + unnamed + + + + + Blinds Vertical + + + + + Blinds Horizontal + + + + + Box In + + + + + Box Out + + + + + Dissolve + + + + + Glitter Down + + + + + Glitter Right + + + + + Glitter Right-Down + + + + + Random Transition + + + + + Replace + + + + + Split Horizontal In + + + + + Split Horizontal Out + + + + + Split Vertical In + + + + + Split Vertical Out + + + + + Wipe Down + + + + + Wipe Right + + + + + Wipe Left + + + + + Wipe Up + + + + kcfg_SlidesTransition + + + + + textLabel1 + + + Default transition: + + + + + textLabel2 + + + Mouse cursor: + + + + + + Hidden After Delay + + + + + Always Visible + + + + + Always Hidden + + + + kcfg_SlidesCursor + + + + + textLabel3 + + + Background color: + + + + + kcfg_SlidesBackgroundColor + + + + + + + + kcfg_SlidesShowSummary + + + Show s&ummary page + + + + + kcfg_SlidesShowProgress + + + Show &progress indicator + + + + + + + bspace + + + Vertical + + + Expanding + + + + 20 + 1 + + + + + + + + kcfg_SlidesAdvance + toggled(bool) + kcfg_SlidesAdvanceTime + setEnabled(bool) + + + + + kcolorbutton.h + + diff --git a/kpdf/conf/kpdf.kcfg b/kpdf/conf/kpdf.kcfg new file mode 100644 index 00000000..d980fd95 --- /dev/null +++ b/kpdf/conf/kpdf.kcfg @@ -0,0 +1,177 @@ + + + + + + Qt::white + + + false + + + false + + + false + + + Inverted + + + + + + + + + + + + 0x600000 + + + 0xF0F0F0 + + + 127 + 2 + 253 + + + 2 + 2 + 6 + + + + + true + + + true + + + true + + + + + true + + + true + + + + + + true + + + true + + + 1 + 1 + 8 + + + 0 + 2 + + + 1.0 + 0.1 + 4.0 + + + + + true + + + + + Normal + + + + + + + + + true + + + true + + + + + false + + + 5 + 1 + 3600 + + + false + + + Qt::black + + + Replace + + + + + + + + + + + + + + + + + + + + + + + HiddenDelay + + + + + + + + true + + + false + + + + + false + + + + + + false + + + diff --git a/kpdf/conf/preferencesdialog.cpp b/kpdf/conf/preferencesdialog.cpp new file mode 100644 index 00000000..7968d3fd --- /dev/null +++ b/kpdf/conf/preferencesdialog.cpp @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (C) 2004 by Enrico Ros * + * * + * 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. * + ***************************************************************************/ + +#include + +// single config pages +#include "dlggeneral.h" +#include "dlgperformance.h" +#include "dlgaccessibility.h" +#include "dlgpresentation.h" + +// reimplementing this +#include "preferencesdialog.h" + +PreferencesDialog::PreferencesDialog( QWidget * parent, KConfigSkeleton * skeleton ) + : KConfigDialog( parent, "preferences", skeleton ) +{ + m_general = new DlgGeneral(0); + m_performance = new DlgPerformance(0); + m_accessibility = new DlgAccessibility(0); + m_presentation = new DlgPresentation(0); + + addPage( m_general, i18n("General"), "kpdf", i18n("General Options") ); + addPage( m_accessibility, i18n("Accessibility"), "access", i18n("Reading Aids") ); + addPage( m_performance, i18n("Performance"), "launch", i18n("Performance Tuning") ); + addPage( m_presentation, i18n("Presentation"), "kpresenter_kpr", + i18n("Options for Presentation Mode") ); +} diff --git a/kpdf/conf/preferencesdialog.h b/kpdf/conf/preferencesdialog.h new file mode 100644 index 00000000..475320ab --- /dev/null +++ b/kpdf/conf/preferencesdialog.h @@ -0,0 +1,44 @@ +/*************************************************************************** + * Copyright (C) 2004 by Enrico Ros * + * * + * 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. * + ***************************************************************************/ + +#ifndef _PREFERENCESDIALOG_H +#define _PREFERENCESDIALOG_H + +#include +#include "conf/settings.h" + +class QWidget; +class KConfigSkeleton; + +class DlgGeneral; +class DlgPerformance; +class DlgAccessibility; +class DlgPresentation; + +class PreferencesDialog : public KConfigDialog +{ + + public: + PreferencesDialog( QWidget * parent, KConfigSkeleton * config ); + + protected: +// void updateSettings(); // Called when OK/Apply is pressed. +// void updateWidgets(); // Called upon construction or when Reset is pressed +// void updateWidgetsDefault(); // Called when Defaults button is pressed +// bool hasChanged(); // In order to correctly disable/enable Apply button +// bool isDefault(); // In order to correctly disable/enable Defaults button + + private: + DlgGeneral * m_general; + DlgPerformance * m_performance; + DlgAccessibility * m_accessibility; + DlgPresentation * m_presentation; +}; + +#endif diff --git a/kpdf/conf/settings.kcfgc b/kpdf/conf/settings.kcfgc new file mode 100644 index 00000000..bfdad9ee --- /dev/null +++ b/kpdf/conf/settings.kcfgc @@ -0,0 +1,4 @@ +ClassName=KpdfSettings +File=kpdf.kcfg +Mutators=true +Singleton=true diff --git a/kpdf/configure.in.bot b/kpdf/configure.in.bot new file mode 100644 index 00000000..03feefcc --- /dev/null +++ b/kpdf/configure.in.bot @@ -0,0 +1,30 @@ +if test -z "$FREETYPE_CONFIG"; then + echo "" + echo "You're missing freetype development libs." + echo "KPDF will not be build without them" + echo "" +fi + +if test x$FREETYPE_VERSION != x; then + if test $FREETYPE_VERSION -lt 9008003; then + echo "" + echo "You're using freetype older than 2.1.10, it is not mandatory" + echo "to use 2.1.10 but kpdf improves its rendering in some pdf with it" + echo "" + fi +fi + +if test -z "$XFT_LIBS"; then + echo "" + echo "You're missing XFT development libs." + echo "KPDF will not be build without them" + echo "" +fi + +if test "$HAVE_LIBJPEG" = "no"; then + echo "" + echo "You're missing libjpeg development libs." + echo "KPDF will not be build without them" + echo "" +fi + diff --git a/kpdf/configure.in.in b/kpdf/configure.in.in new file mode 100644 index 00000000..db883adb --- /dev/null +++ b/kpdf/configure.in.in @@ -0,0 +1,124 @@ +dnl ##### Check for FreeType 2.0.5+. +dnl ##### (Note: FT_Get_Name_Index was added in FT 2.0.5, and is +dnl ##### the reason that Xpdf requires 2.0.5+.) + +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 + FREETYPE_VERSION=`$FREETYPE_CONFIG --version 2>/dev/null | sed -e 's/libfreetype //' | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'` + if test -n "$FREETYPE_VERSION" && test "$FREETYPE_VERSION" -ge 9000000; 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`" + AC_DEFINE_UNQUOTED(HAVE_FREETYPE, 1, [Defines if your system has the freetype library]) + else + AC_MSG_WARN([You need at least libfreetype 2.0.5]) + DO_NOT_COMPILE="$DO_NOT_COMPILE kpdf" + fi +else + DO_NOT_COMPILE="$DO_NOT_COMPILE kpdf" +fi + +AC_SUBST(FREETYPE_VERSION) +AC_SUBST(LIBFREETYPE_LIBS) +AC_SUBST(LIBFREETYPE_CFLAGS) +AC_SUBST(LIBFREETYPE_RPATH) + +# Check for dirent +AC_HEADER_DIRENT + +# Check for xft +KDE_PKG_CHECK_MODULES(XFT, xft >= 2.0, , + # This older xft-config stuff can (eventually) go away. + KDE_FIND_PATH(xft-config, XFT_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin],) + if "$XFT_CONFIG"; then + XFT_CFLAGS="`$XFT_CONFIG --cflags`" + XFT_LIBS="`$XFT_CONFIG --libs`" + fi + AC_SUBST(XFT_CFLAGS) + AC_SUBST(XFT_LIBS) +) + +if test -z "$XFT_LIBS"; then + DO_NOT_COMPILE="$DO_NOT_COMPILE kpdf" +fi + +dnl ##### Check for libpaper (Debian). +LIBPAPER_LIBS= +KDE_CHECK_HEADER(paper.h, [ + LIBPAPER_LIBS='-lpaper' + AC_DEFINE_UNQUOTED(HAVE_PAPER_H, 1, [Define to 1 if you have the header file.]) +], + AC_DEFINE_UNQUOTED(HAVE_PAPER_H, 0, [Define to 1 if you have the header file.]) +) +AC_SUBST(LIBPAPER_LIBS) + +AC_CHECK_FUNCS(fseek64 mkstemp mkstemps popen) + +AC_FIND_FILE(xpdfrc, [/etc /usr/local/etc /etc/xpdf], xpdfrc) +if test "$xpdfrc" != NO; then + AC_DEFINE_UNQUOTED(SYSTEM_XPDFRC, "$xpdfrc/xpdfrc", [Define the location your xpdfrc]) +fi + +dnl #### Check for FSEEK variants +KDE_CHECK_LARGEFILE +AC_FUNC_FSEEKO +AC_CHECK_FUNCS(fseek64, xpdf_cv_func_fseek64=yes, xpdf_cv_func_fseek64=no) +AC_CHECK_FUNCS(ftell64, xpdf_cv_func_ftell64=yes, xpdf_cv_func_ftell64=no) +if test "$xpdf_cv_func_fseek64" = yes -a "$xpdf_cv_func_ftell64" = yes; then + AC_DEFINE(HAVE_FSEEK64, 1) +else + AC_DEFINE(HAVE_FSEEK64, 0) +fi + +dnl #### Enable the user to enable multithearind on xpdf +AC_ARG_ENABLE(multithreaded-kpdf, + AC_HELP_STRING([--enable-multithreaded-kpdf],[include support for multithreading in xpdf code inside kpdf. Has nothing to do with threaded generation of contents, this is configurable via a dialog inside the program itself]), +[ + case $enableval in + yes) + AC_DEFINE(MULTITHREADED, 1, [Defines if use multithreading in xpdf code inside kpdf]) + ;; + no) + AC_DEFINE(MULTITHREADED, 0, [Defines if use multithreading in xpdf code inside kpdf]) + ;; + *) + AC_DEFINE(MULTITHREADED, 1, [Defines if use multithreading in xpdf code inside kpdf]) + ;; + esac +] +, AC_DEFINE(MULTITHREADED, 0, [Defines if use multithreading in xpdf code inside kpdf]) +) + +dnl #### Enable the user to decide if he wants to force drm or not +AC_ARG_ENABLE(force-kpdf-drm, + AC_HELP_STRING([--enable-force-kpdf-drm],[Forces kpdf to check for DRM to decide if you can copy/print protected pdf. (default=no)]), +[ + case $enableval in + yes) + AC_DEFINE(KPDF_FORCE_DRM, 1, [Defines if force the use DRM in kpdf]) + ;; + no) + AC_DEFINE(KPDF_FORCE_DRM, 0, [Defines if force the use DRM in kpdf]) + ;; + *) + AC_DEFINE(KPDF_FORCE_DRM, 1, [Defines if force the use DRM in kpdf]) + ;; + esac +] +, AC_DEFINE(KPDF_FORCE_DRM, 0, [Defines if force the use DRM in kpdf]) +) + +KDE_CHECK_COMPILER_FLAG([fno-regmove], SUPPORTS_NOREGMOVE=true, SUPPORTS_NOREGMOVE=false) +if test "x$SUPPORTS_NOREGMOVE" = xtrue; then + NOREGMOVE="-fno-regmove" +fi +AC_SUBST(NOREGMOVE) diff --git a/kpdf/core/Makefile.am b/kpdf/core/Makefile.am new file mode 100644 index 00000000..74c77485 --- /dev/null +++ b/kpdf/core/Makefile.am @@ -0,0 +1,13 @@ +SUBDIRS = generator_pdf generator_kimgio + +INCLUDES = -I$(srcdir)/generator_pdf -I$(srcdir)/.. -I$(srcdir)/../xpdf -I$(srcdir)/../xpdf/goo -I$(top_builddir)/kpdf $(all_includes) + +METASOURCES = AUTO + +libkpdfcore_la_LIBADD = ./generator_pdf/libgeneratorpdf.la ./generator_kimgio/libgeneratorkimgio.la +libkpdfcore_la_SOURCES = document.cpp link.cpp page.cpp pagetransition.cpp + +noinst_LTLIBRARIES = libkpdfcore.la + +document.lo: ../conf/settings.h +page.lo: ../conf/settings.h diff --git a/kpdf/core/document.cpp b/kpdf/core/document.cpp new file mode 100644 index 00000000..25e19d9a --- /dev/null +++ b/kpdf/core/document.cpp @@ -0,0 +1,1634 @@ +/*************************************************************************** + * Copyright (C) 2004 by Enrico Ros * + * Copyright (C) 2004-2005 by Albert Astals Cid * + * * + * 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. * + ***************************************************************************/ + +// qt/kde/system includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// local includes +#include "document.h" +#include "observer.h" +#include "page.h" +#include "link.h" +#include "generator_pdf/generator_pdf.h" // PDF generator +#include "generator_kimgio/generator_kimgio.h" // KIMGIO generator +#include "conf/settings.h" + +// structures used internally by KPDFDocument for local variables storage +class AllocatedPixmap; +class RunningSearch; +class KPDFDocumentPrivate +{ + public: + // find descriptors, mapped by ID (we handle multiple searches) + QMap< int, RunningSearch * > searches; + int m_lastSearchID; + + // needed because for remote documents docFileName is a local file and + // we want the remote url when the document refers to relativeNames + KURL url; + + // cached stuff + QString docFileName; + QString xmlFileName; + + // a list of the mimetypes qimage can understand + QStringList kimgioMimes; + + // viewport stuff + QValueList< DocumentViewport > viewportHistory; + QValueList< DocumentViewport >::iterator viewportIterator; + DocumentViewport nextDocumentViewport; // see KPDFLink::Goto for an explanation + + // observers / requests / allocator stuff + QMap< int, DocumentObserver * > observers; + QValueList< PixmapRequest * > pixmapRequestsStack; + QValueList< AllocatedPixmap * > allocatedPixmapsFifo; + int allocatedPixmapsTotalMemory; + + // timers (memory checking / info saver) + QTimer * memCheckTimer; + QTimer * saveBookmarksTimer; +}; + +struct AllocatedPixmap +{ + // owner of the page + int id; + int page; + int memory; + // public constructor: initialize data + AllocatedPixmap( int i, int p, int m ) : id( i ), page( p ), memory( m ) {}; +}; + +struct RunningSearch +{ + // store search properties + int continueOnPage; + NormalizedRect continueOnMatch; + QValueList< int > highlightedPages; + + // fields related to previous searches (used for 'continueSearch') + QString cachedString; + KPDFDocument::SearchType cachedType; + bool cachedCaseSensitive; + bool cachedViewportMove; + bool cachedNoDialogs; + QColor cachedColor; +}; + +#define foreachObserver( cmd ) {\ + QMap< int, DocumentObserver * >::iterator it=d->observers.begin(), end=d->observers.end();\ + for ( ; it != end ; ++ it ) { (*it)-> cmd ; } } + + +/** KPDFDocument **/ + +KPDFDocument::KPDFDocument(QWidget *widget) + : QObject(widget), generator( 0 ), d( new KPDFDocumentPrivate ) +{ + d->allocatedPixmapsTotalMemory = 0; + d->memCheckTimer = 0; + d->saveBookmarksTimer = 0; + d->m_lastSearchID = -1; + KImageIO::registerFormats(); + QStringList list = QImage::inputFormatList(); + QStringList::Iterator it = list.begin(); + while( it != list.end() ) + { + d->kimgioMimes << KMimeType::findByPath(QString("foo.%1").arg(*it), 0, true)->name(); + ++it; + } +} + +KPDFDocument::~KPDFDocument() +{ + // delete generator, pages, and related stuff + closeDocument(); + + // delete the private structure + delete d; +} + + +bool KPDFDocument::openDocument( const QString & docFile, const KURL & url, const KMimeType::Ptr &mime ) +{ + // docFile is always local so we can use QFile on it + QFile fileReadTest( docFile ); + if ( !fileReadTest.open( IO_ReadOnly ) ) + { + d->docFileName = QString::null; + return false; + } + // determine the related "xml document-info" filename + d->url = url; + d->docFileName = docFile; + QString fn = docFile.contains('/') ? docFile.section('/', -1, -1) : docFile; + fn = "kpdf/" + QString::number(fileReadTest.size()) + "." + fn + ".xml"; + fileReadTest.close(); + d->xmlFileName = locateLocal( "data", fn ); + + // create the generator based on the file's mimetype + if ( (*mime).is( "application/pdf" ) ) + generator = new PDFGenerator( this ); +// else if ( mimeName == "application/postscript" ) +// kdError() << "PS generator not available" << endl; + else + { + QStringList::Iterator it = d->kimgioMimes.begin(); + while( it != d->kimgioMimes.end() ) + { + kdDebug() << *it << endl; + if ( (*mime).is( *it ) ) + { + generator = new KIMGIOGenerator( this ); + break; + } + ++it; + } + if ( it == d->kimgioMimes.end() ) + { + kdWarning() << "Unknown mimetype '" << mime->name() << "'." << endl; + return false; + } + } + + // 1. load Document (and set busy cursor while loading) + QApplication::setOverrideCursor( waitCursor ); + bool openOk = generator->loadDocument( docFile, pages_vector ); + QApplication::restoreOverrideCursor(); + if ( !openOk || pages_vector.size() <= 0 ) + { + delete generator; + generator = 0; + return openOk; + } + + // 2. load Additional Data (our bookmarks and metadata) about the document + loadDocumentInfo(); + + // 3. setup observers inernal lists and data + foreachObserver( notifySetup( pages_vector, true ) ); + + // 4. set initial page (restoring the page saved in xml if loaded) + DocumentViewport loadedViewport = (*d->viewportIterator); + if ( loadedViewport.pageNumber != -1 ) + (*d->viewportIterator) = DocumentViewport(); + else + loadedViewport.pageNumber = 0; + setViewport( loadedViewport ); + + // start bookmark saver timer + if ( !d->saveBookmarksTimer ) + { + d->saveBookmarksTimer = new QTimer( this ); + connect( d->saveBookmarksTimer, SIGNAL( timeout() ), this, SLOT( saveDocumentInfo() ) ); + } + d->saveBookmarksTimer->start( 5 * 60 * 1000 ); + + // start memory check timer + if ( !d->memCheckTimer ) + { + d->memCheckTimer = new QTimer( this ); + connect( d->memCheckTimer, SIGNAL( timeout() ), this, SLOT( slotTimedMemoryCheck() ) ); + } + d->memCheckTimer->start( 2000 ); + + if (d->nextDocumentViewport.pageNumber != -1) + { + setViewport(d->nextDocumentViewport); + d->nextDocumentViewport = DocumentViewport(); + } + + return true; +} + +void KPDFDocument::closeDocument() +{ + // save document info if a document is still opened + if ( generator && pages_vector.size() > 0 ) + saveDocumentInfo(); + + // stop timers + if ( d->memCheckTimer ) + d->memCheckTimer->stop(); + if ( d->saveBookmarksTimer ) + d->saveBookmarksTimer->stop(); + + // delete contents generator + delete generator; + generator = 0; + + d->url = KURL(); + + // remove requests left in queue + QValueList< PixmapRequest * >::iterator sIt = d->pixmapRequestsStack.begin(); + QValueList< PixmapRequest * >::iterator sEnd = d->pixmapRequestsStack.end(); + for ( ; sIt != sEnd; ++sIt ) + delete *sIt; + d->pixmapRequestsStack.clear(); + + // send an empty list to observers (to free their data) + foreachObserver( notifySetup( QValueVector< KPDFPage * >(), true ) ); + + // delete pages and clear 'pages_vector' container + QValueVector< KPDFPage * >::iterator pIt = pages_vector.begin(); + QValueVector< KPDFPage * >::iterator pEnd = pages_vector.end(); + for ( ; pIt != pEnd; ++pIt ) + delete *pIt; + pages_vector.clear(); + + // clear 'memory allocation' descriptors + QValueList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); + QValueList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); + for ( ; aIt != aEnd; ++aIt ) + delete *aIt; + d->allocatedPixmapsFifo.clear(); + + // clear 'running searches' descriptors + QMap< int, RunningSearch * >::iterator rIt = d->searches.begin(); + QMap< int, RunningSearch * >::iterator rEnd = d->searches.end(); + for ( ; rIt != rEnd; ++rIt ) + delete *rIt; + d->searches.clear(); + + // reset internal variables + d->viewportHistory.clear(); + d->viewportHistory.append( DocumentViewport() ); + d->viewportIterator = d->viewportHistory.begin(); + d->allocatedPixmapsTotalMemory = 0; +} + + +void KPDFDocument::addObserver( DocumentObserver * pObserver ) +{ + // keep the pointer to the observer in a map + d->observers[ pObserver->observerId() ] = pObserver; + + // if the observer is added while a document is already opened, tell it + if ( !pages_vector.isEmpty() ) + { + pObserver->notifySetup( pages_vector, true ); + pObserver->notifyViewportChanged( false /*disables smoothMove*/ ); + } +} + +void KPDFDocument::removeObserver( DocumentObserver * pObserver ) +{ + // remove observer from the map. it won't receive notifications anymore + if ( d->observers.contains( pObserver->observerId() ) ) + { + // free observer's pixmap data + int observerId = pObserver->observerId(); + QValueVector::iterator it = pages_vector.begin(), end = pages_vector.end(); + for ( ; it != end; ++it ) + (*it)->deletePixmap( observerId ); + + // [MEM] free observer's allocation descriptors + QValueList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); + QValueList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); + while ( aIt != aEnd ) + { + AllocatedPixmap * p = *aIt; + if ( p->id == observerId ) + { + aIt = d->allocatedPixmapsFifo.remove( aIt ); + delete p; + } + else + ++aIt; + } + + // delete observer entry from the map + d->observers.remove( observerId ); + } +} + +void KPDFDocument::reparseConfig() +{ + // reparse generator config and if something changed clear KPDFPages + if ( generator && generator->reparseConfig() ) + { + // invalidate pixmaps + QValueVector::iterator it = pages_vector.begin(), end = pages_vector.end(); + for ( ; it != end; ++it ) + (*it)->deletePixmapsAndRects(); + + // [MEM] remove allocation descriptors + QValueList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); + QValueList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); + for ( ; aIt != aEnd; ++aIt ) + delete *aIt; + d->allocatedPixmapsFifo.clear(); + d->allocatedPixmapsTotalMemory = 0; + + // send reload signals to observers + foreachObserver( notifyContentsCleared( DocumentObserver::Pixmap ) ); + } + + // free memory if in 'low' profile + if ( KpdfSettings::memoryLevel() == KpdfSettings::EnumMemoryLevel::Low && + !d->allocatedPixmapsFifo.isEmpty() && !pages_vector.isEmpty() ) + cleanupPixmapMemory(); +} + + +QWidget *KPDFDocument::widget() const +{ + return static_cast(parent()); +} + +bool KPDFDocument::isOpened() const +{ + return generator; +} + +const DocumentInfo * KPDFDocument::documentInfo() const +{ + return generator ? generator->generateDocumentInfo() : NULL; +} + +const DocumentSynopsis * KPDFDocument::documentSynopsis() const +{ + return generator ? generator->generateDocumentSynopsis() : NULL; +} + +const KPDFPage * KPDFDocument::page( uint n ) const +{ + return ( n < pages_vector.count() ) ? pages_vector[n] : 0; +} + +const DocumentViewport & KPDFDocument::viewport() const +{ + return (*d->viewportIterator); +} + +uint KPDFDocument::currentPage() const +{ + return (*d->viewportIterator).pageNumber; +} + +uint KPDFDocument::pages() const +{ + return pages_vector.size(); +} + +KURL KPDFDocument::currentDocument() const +{ + return d->url; +} + +bool KPDFDocument::isAllowed( int flags ) const +{ + return generator ? generator->isAllowed( flags ) : false; +} + +bool KPDFDocument::historyAtBegin() const +{ + return d->viewportIterator == d->viewportHistory.begin(); +} + +bool KPDFDocument::historyAtEnd() const +{ + return d->viewportIterator == --(d->viewportHistory.end()); +} + +QString KPDFDocument::getMetaData( const QString & key, const QString & option ) const +{ + return generator ? generator->getMetaData( key, option ) : QString(); +} + +bool KPDFDocument::supportsSearching() const +{ + return generator ? generator->supportsSearching() : false; +} + +bool KPDFDocument::hasFonts() const +{ + return generator ? generator->hasFonts() : false; +} + +void KPDFDocument::putFontInfo(KListView *list) +{ + if (generator) generator->putFontInfo(list); +} + +void KPDFDocument::requestPixmaps( const QValueList< PixmapRequest * > & requests ) +{ + if ( !generator ) + { + // delete requests.. + QValueList< PixmapRequest * >::const_iterator rIt = requests.begin(), rEnd = requests.end(); + for ( ; rIt != rEnd; ++rIt ) + delete *rIt; + // ..and return + return; + } + + // 1. [CLEAN STACK] remove previous requests of requesterID + int requesterID = requests.first()->id; + QValueList< PixmapRequest * >::iterator sIt = d->pixmapRequestsStack.begin(), sEnd = d->pixmapRequestsStack.end(); + while ( sIt != sEnd ) + { + if ( (*sIt)->id == requesterID ) + { + // delete request and remove it from stack + delete *sIt; + sIt = d->pixmapRequestsStack.remove( sIt ); + } + else + ++sIt; + } + + // 2. [ADD TO STACK] add requests to stack + bool threadingDisabled = !KpdfSettings::enableThreading(); + QValueList< PixmapRequest * >::const_iterator rIt = requests.begin(), rEnd = requests.end(); + for ( ; rIt != rEnd; ++rIt ) + { + // set the 'page field' (see PixmapRequest) and check if it is valid + PixmapRequest * request = *rIt; + if ( !(request->page = pages_vector[ request->pageNumber ]) ) + { + // skip requests referencing an invalid page (must not happen) + delete request; + continue; + } + + if ( !request->async ) + request->priority = 0; + + if ( request->async && threadingDisabled ) + request->async = false; + + // add request to the 'stack' at the right place + if ( !request->priority ) + // add priority zero requests to the top of the stack + d->pixmapRequestsStack.append( request ); + else + { + // insert in stack sorted by priority + sIt = d->pixmapRequestsStack.begin(); + sEnd = d->pixmapRequestsStack.end(); + while ( sIt != sEnd && (*sIt)->priority > request->priority ) + ++sIt; + d->pixmapRequestsStack.insert( sIt, request ); + } + } + + // 3. [START FIRST GENERATION] if generator is ready, start a new generation, + // or else (if gen is running) it will be started when the new contents will + //come from generator (in requestDone()) + if ( generator->canGeneratePixmap() ) + sendGeneratorRequest(); +} + +void KPDFDocument::requestTextPage( uint page ) +{ + KPDFPage * kp = pages_vector[ page ]; + if ( !generator || !kp ) + return; + + // Memory management for TextPages + + generator->generateSyncTextPage( kp ); +} +/* REFERENCE IMPLEMENTATION: better calling setViewport from other code +void KPDFDocument::setNextPage() +{ + // advance page and set viewport on observers + if ( (*d->viewportIterator).pageNumber < (int)pages_vector.count() - 1 ) + setViewport( DocumentViewport( (*d->viewportIterator).pageNumber + 1 ) ); +} + +void KPDFDocument::setPrevPage() +{ + // go to previous page and set viewport on observers + if ( (*d->viewportIterator).pageNumber > 0 ) + setViewport( DocumentViewport( (*d->viewportIterator).pageNumber - 1 ) ); +} +*/ +void KPDFDocument::setViewportPage( int page, int excludeId, bool smoothMove ) +{ + // clamp page in range [0 ... numPages-1] + if ( page < 0 ) + page = 0; + else if ( page > (int)pages_vector.count() ) + page = pages_vector.count() - 1; + + // make a viewport from the page and broadcast it + setViewport( DocumentViewport( page ), excludeId, smoothMove ); +} + +void KPDFDocument::setViewport( const DocumentViewport & viewport, int excludeId, bool smoothMove ) +{ + // if already broadcasted, don't redo it + DocumentViewport & oldViewport = *d->viewportIterator; + if ( viewport == oldViewport ) + kdDebug() << "setViewport with the same viewport." << endl; + + // set internal viewport taking care of history + if ( oldViewport.pageNumber == viewport.pageNumber || oldViewport.pageNumber == -1 ) + { + // if page is unchanged save the viewport at current position in queue + oldViewport = viewport; + } + else + { + // remove elements after viewportIterator in queue + d->viewportHistory.erase( ++d->viewportIterator, d->viewportHistory.end() ); + + // keep the list to a reasonable size by removing head when needed + if ( d->viewportHistory.count() >= 100 ) + d->viewportHistory.pop_front(); + + // add the item at the end of the queue + d->viewportIterator = d->viewportHistory.append( viewport ); + } + + // notify change to all other (different from id) observers + QMap< int, DocumentObserver * >::iterator it = d->observers.begin(), end = d->observers.end(); + for ( ; it != end ; ++ it ) + if ( it.key() != excludeId ) + (*it)->notifyViewportChanged( smoothMove ); + + // [MEM] raise position of currently viewed page in allocation queue + if ( d->allocatedPixmapsFifo.count() > 1 ) + { + const int page = viewport.pageNumber; + QValueList< AllocatedPixmap * > viewportPixmaps; + QValueList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); + QValueList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); + while ( aIt != aEnd ) + { + if ( (*aIt)->page == page ) + { + viewportPixmaps.append( *aIt ); + aIt = d->allocatedPixmapsFifo.remove( aIt ); + continue; + } + ++aIt; + } + if ( !viewportPixmaps.isEmpty() ) + d->allocatedPixmapsFifo += viewportPixmaps; + } +} + +void KPDFDocument::setPrevViewport() +// restore viewport from the history +{ + if ( d->viewportIterator != d->viewportHistory.begin() ) + { + // restore previous viewport and notify it to observers + --d->viewportIterator; + foreachObserver( notifyViewportChanged( true ) ); + } +} + +void KPDFDocument::setNextViewport() +// restore next viewport from the history +{ + QValueList< DocumentViewport >::iterator nextIterator = d->viewportIterator; + ++nextIterator; + if ( nextIterator != d->viewportHistory.end() ) + { + // restore next viewport and notify it to observers + ++d->viewportIterator; + foreachObserver( notifyViewportChanged( true ) ); + } +} + +void KPDFDocument::setNextDocumentViewport( const DocumentViewport & viewport ) +{ + d->nextDocumentViewport = viewport; +} + + +bool KPDFDocument::searchText( int searchID, const QString & text, bool fromStart, bool caseSensitive, + SearchType type, bool moveViewport, const QColor & color, bool noDialogs ) +{ + // don't perform searches on empty docs + if ( !generator || pages_vector.isEmpty() ) + return false; + + // if searchID search not recorded, create new descriptor and init params + if ( !d->searches.contains( searchID ) ) + { + RunningSearch * search = new RunningSearch(); + search->continueOnPage = -1; + d->searches[ searchID ] = search; + } + if (d->m_lastSearchID != searchID) + { + resetSearch(d->m_lastSearchID); + } + d->m_lastSearchID = searchID; + RunningSearch * s = d->searches[ searchID ]; + + // update search stucture + bool newText = text != s->cachedString; + s->cachedString = text; + s->cachedType = type; + s->cachedCaseSensitive = caseSensitive; + s->cachedViewportMove = moveViewport; + s->cachedNoDialogs = noDialogs; + s->cachedColor = color; + + // global data for search + bool foundAMatch = false; + QValueList< int > pagesToNotify; + + // remove highlights from pages and queue them for notifying changes + pagesToNotify += s->highlightedPages; + QValueList< int >::iterator it = s->highlightedPages.begin(), end = s->highlightedPages.end(); + for ( ; it != end; ++it ) + pages_vector[ *it ]->deleteHighlights( searchID ); + s->highlightedPages.clear(); + + // set hourglass cursor + QApplication::setOverrideCursor( waitCursor ); + + // 1. ALLDOC - proces all document marking pages + if ( type == AllDoc ) + { + // search and highlight text on all pages + QValueVector< KPDFPage * >::iterator it = pages_vector.begin(), end = pages_vector.end(); + for ( ; it != end; ++it ) + { + // get page (from the first to the last) + KPDFPage * page = *it; + int pageNumber = page->number(); + + // request search page if needed + if ( !page->hasSearchPage() ) + requestTextPage( pageNumber ); + + // loop on a page adding highlights for all found items + bool addedHighlights = false; + NormalizedRect * lastMatch = 0; + while ( 1 ) + { + if ( lastMatch ) + lastMatch = page->findText( text, caseSensitive, lastMatch ); + else + lastMatch = page->findText( text, caseSensitive ); + + if ( !lastMatch ) + break; + + // add highligh rect to the page + page->setHighlight( searchID, lastMatch, color ); + addedHighlights = true; + } + + // if added highlights, udpate internals and queue page for notify + if ( addedHighlights ) + { + foundAMatch = true; + s->highlightedPages.append( pageNumber ); + if ( !pagesToNotify.contains( pageNumber ) ) + pagesToNotify.append( pageNumber ); + } + } + + // reset cursor to previous shape + QApplication::restoreOverrideCursor(); + + // send page lists if found anything new + //if ( foundAMatch ) ?maybe? + foreachObserver( notifySetup( pages_vector, false ) ); + } + // 2. NEXTMATCH - find next matching item (or start from top) + else if ( type == NextMatch ) + { + // find out from where to start/resume search from + int viewportPage = (*d->viewportIterator).pageNumber; + int currentPage = fromStart ? 0 : ((s->continueOnPage != -1) ? s->continueOnPage : viewportPage); + KPDFPage * lastPage = fromStart ? 0 : pages_vector[ currentPage ]; + + // continue checking last SearchPage first (if it is the current page) + NormalizedRect * match = 0; + if ( lastPage && lastPage->number() == s->continueOnPage ) + { + if ( newText ) + match = lastPage->findText( text, caseSensitive ); + else + match = lastPage->findText( text, caseSensitive, &s->continueOnMatch ); + if ( !match ) + currentPage++; + } + + // if no match found, loop through the whole doc, starting from currentPage + if ( !match ) + { + const int pageCount = pages_vector.count(); + for ( int i = 0; i < pageCount; i++ ) + { + if ( currentPage >= pageCount ) + { + if ( noDialogs || KMessageBox::questionYesNo(widget(), i18n("End of document reached.\nContinue from the beginning?"), QString::null, KStdGuiItem::cont(), KStdGuiItem::cancel()) == KMessageBox::Yes ) + currentPage = 0; + else + break; + } + // get page + KPDFPage * page = pages_vector[ currentPage ]; + // request search page if needed + if ( !page->hasSearchPage() ) + requestTextPage( page->number() ); + // if found a match on the current page, end the loop + if ( (match = page->findText( text, caseSensitive )) ) + break; + currentPage++; + } + } + + // reset cursor to previous shape + QApplication::restoreOverrideCursor(); + + // if a match has been found.. + if ( match ) + { + // update the RunningSearch structure adding this match.. + foundAMatch = true; + s->continueOnPage = currentPage; + s->continueOnMatch = *match; + s->highlightedPages.append( currentPage ); + // ..add highlight to the page.. + pages_vector[ currentPage ]->setHighlight( searchID, match, color ); + + // ..queue page for notifying changes.. + if ( !pagesToNotify.contains( currentPage ) ) + pagesToNotify.append( currentPage ); + + // ..move the viewport to show the searched word centered + if ( moveViewport ) + { + DocumentViewport searchViewport( currentPage ); + searchViewport.rePos.enabled = true; + searchViewport.rePos.normalizedX = (match->left + match->right) / 2.0; + searchViewport.rePos.normalizedY = (match->top + match->bottom) / 2.0; + setViewport( searchViewport, -1, true ); + } + } + else if ( !noDialogs ) + KMessageBox::information( widget(), i18n("No matches found for '%1'.").arg( text ) ); + } + // 3. PREVMATCH //TODO + else if ( type == PrevMatch ) + { + } + // 4. GOOGLE* - process all document marking pages + else if ( type == GoogleAll || type == GoogleAny ) + { + // search and highlight every word in 'text' on all pages + bool matchAll = type == GoogleAll; + QStringList words = QStringList::split( " ", text ); + int wordsCount = words.count(), + hueStep = (wordsCount > 1) ? (60 / (wordsCount - 1)) : 60, + baseHue, baseSat, baseVal; + color.getHsv( &baseHue, &baseSat, &baseVal ); + QValueVector< KPDFPage * >::iterator it = pages_vector.begin(), end = pages_vector.end(); + for ( ; it != end; ++it ) + { + // get page (from the first to the last) + KPDFPage * page = *it; + int pageNumber = page->number(); + + // request search page if needed + if ( !page->hasSearchPage() ) + requestTextPage( pageNumber ); + + // loop on a page adding highlights for all found items + bool allMatched = wordsCount > 0, + anyMatched = false; + for ( int w = 0; w < wordsCount; w++ ) + { + QString word = words[ w ]; + int newHue = baseHue - w * hueStep; + if ( newHue < 0 ) + newHue += 360; + QColor wordColor = QColor( newHue, baseSat, baseVal, QColor::Hsv ); + NormalizedRect * lastMatch = 0; + // add all highlights for current word + bool wordMatched = false; + while ( 1 ) + { + if ( lastMatch ) + lastMatch = page->findText( word, caseSensitive, lastMatch ); + else + lastMatch = page->findText( word, caseSensitive ); + + if ( !lastMatch ) + break; + + // add highligh rect to the page + page->setHighlight( searchID, lastMatch, wordColor ); + wordMatched = true; + } + allMatched = allMatched && wordMatched; + anyMatched = anyMatched || wordMatched; + } + + // if not all words are present in page, remove partial highlights + if ( !allMatched && matchAll ) + page->deleteHighlights( searchID ); + + // if page contains all words, udpate internals and queue page for notify + if ( (allMatched && matchAll) || (anyMatched && !matchAll) ) + { + foundAMatch = true; + s->highlightedPages.append( pageNumber ); + if ( !pagesToNotify.contains( pageNumber ) ) + pagesToNotify.append( pageNumber ); + } + } + + // reset cursor to previous shape + QApplication::restoreOverrideCursor(); + + // send page lists to update observers (since some filter on bookmarks) + foreachObserver( notifySetup( pages_vector, false ) ); + } + + // notify observers about highlights changes + QValueList< int >::iterator nIt = pagesToNotify.begin(), nEnd = pagesToNotify.end(); + for ( ; nIt != nEnd; ++nIt ) + foreachObserver( notifyPageChanged( *nIt, DocumentObserver::Highlights ) ); + + // return if search has found one or more matches + return foundAMatch; +} + +bool KPDFDocument::continueSearch( int searchID ) +{ + // check if searchID is present in runningSearches + if ( !d->searches.contains( searchID ) ) + return false; + + // start search with cached parameters from last search by searchID + RunningSearch * p = d->searches[ searchID ]; + return searchText( searchID, p->cachedString, false, p->cachedCaseSensitive, + p->cachedType, p->cachedViewportMove, p->cachedColor, + p->cachedNoDialogs ); +} + +void KPDFDocument::resetSearch( int searchID ) +{ + // check if searchID is present in runningSearches + if ( !d->searches.contains( searchID ) ) + return; + + // get previous parameters for search + RunningSearch * s = d->searches[ searchID ]; + + // unhighlight pages and inform observers about that + QValueList< int >::iterator it = s->highlightedPages.begin(), end = s->highlightedPages.end(); + for ( ; it != end; ++it ) + { + int pageNumber = *it; + pages_vector[ pageNumber ]->deleteHighlights( searchID ); + foreachObserver( notifyPageChanged( pageNumber, DocumentObserver::Highlights ) ); + } + + // send the setup signal too (to update views that filter on matches) + foreachObserver( notifySetup( pages_vector, false ) ); + + // remove serch from the runningSearches list and delete it + d->searches.remove( searchID ); + delete s; +} + +bool KPDFDocument::continueLastSearch() +{ + return continueSearch( d->m_lastSearchID ); +} + + +void KPDFDocument::toggleBookmark( int n ) +{ + KPDFPage * page = ( n < (int)pages_vector.count() ) ? pages_vector[ n ] : 0; + if ( page ) + { + page->setBookmark( !page->hasBookmark() ); + foreachObserver( notifyPageChanged( n, DocumentObserver::Bookmark ) ); + } +} + +void KPDFDocument::processLink( const KPDFLink * link ) +{ + if ( !link ) + return; + + switch( link->linkType() ) + { + case KPDFLink::Goto: { + const KPDFLinkGoto * go = static_cast< const KPDFLinkGoto * >( link ); + d->nextDocumentViewport = go->destViewport(); + + // Explanation of why d->nextDocumentViewport is needed + // all openRelativeFile does is launch a signal telling we + // want to open another URL, the problem is that when the file is + // non local, the loading is done assynchronously so you can't + // do a setViewport after the if as it was because you are doing the setViewport + // on the old file and when the new arrives there is no setViewport for it and + // it does not show anything + + // first open filename if link is pointing outside this document + if ( go->isExternal() && !openRelativeFile( go->fileName() ) ) + { + kdWarning() << "Link: Error opening '" << go->fileName() << "'." << endl; + return; + } + else + { + if (d->nextDocumentViewport.pageNumber == -1) return; + setViewport( d->nextDocumentViewport, -1, true ); + d->nextDocumentViewport = DocumentViewport(); + } + + } break; + + case KPDFLink::Execute: { + const KPDFLinkExecute * exe = static_cast< const KPDFLinkExecute * >( link ); + QString fileName = exe->fileName(); + if ( fileName.endsWith( ".pdf" ) || fileName.endsWith( ".PDF" ) ) + { + openRelativeFile( fileName ); + return; + } + + // Albert: the only pdf i have that has that kind of link don't define + // an application and use the fileName as the file to open + fileName = giveAbsolutePath( fileName ); + KMimeType::Ptr mime = KMimeType::findByPath( fileName ); + // Check executables + if ( KRun::isExecutableFile( fileName, mime->name() ) ) + { + // Don't have any pdf that uses this code path, just a guess on how it should work + if ( !exe->parameters().isEmpty() ) + { + fileName = giveAbsolutePath( exe->parameters() ); + mime = KMimeType::findByPath( fileName ); + if ( KRun::isExecutableFile( fileName, mime->name() ) ) + { + // this case is a link pointing to an executable with a parameter + // that also is an executable, possibly a hand-crafted pdf + KMessageBox::information( widget(), i18n("The pdf file is trying to execute an external application and for your safety kpdf does not allow that.") ); + return; + } + } + else + { + // this case is a link pointing to an executable with no parameters + // core developers find unacceptable executing it even after asking the user + KMessageBox::information( widget(), i18n("The pdf file is trying to execute an external application and for your safety kpdf does not allow that.") ); + return; + } + } + + KService::Ptr ptr = KServiceTypeProfile::preferredService( mime->name(), "Application" ); + if ( ptr ) + { + KURL::List lst; + lst.append( fileName ); + KRun::run( *ptr, lst ); + } + else + KMessageBox::information( widget(), i18n( "No application found for opening file of mimetype %1." ).arg( mime->name() ) ); + } break; + + case KPDFLink::Action: { + const KPDFLinkAction * action = static_cast< const KPDFLinkAction * >( link ); + switch( action->actionType() ) + { + case KPDFLinkAction::PageFirst: + setViewportPage( 0 ); + break; + case KPDFLinkAction::PagePrev: + if ( (*d->viewportIterator).pageNumber > 0 ) + setViewportPage( (*d->viewportIterator).pageNumber - 1 ); + break; + case KPDFLinkAction::PageNext: + if ( (*d->viewportIterator).pageNumber < (int)pages_vector.count() - 1 ) + setViewportPage( (*d->viewportIterator).pageNumber + 1 ); + break; + case KPDFLinkAction::PageLast: + setViewportPage( pages_vector.count() - 1 ); + break; + case KPDFLinkAction::HistoryBack: + setPrevViewport(); + break; + case KPDFLinkAction::HistoryForward: + setNextViewport(); + break; + case KPDFLinkAction::Quit: + emit quit(); + break; + case KPDFLinkAction::Presentation: + emit linkPresentation(); + break; + case KPDFLinkAction::EndPresentation: + emit linkEndPresentation(); + break; + case KPDFLinkAction::Find: + emit linkFind(); + break; + case KPDFLinkAction::GoToPage: + emit linkGoToPage(); + break; + case KPDFLinkAction::Close: + emit close(); + break; + } + } break; + + case KPDFLink::Browse: { + const KPDFLinkBrowse * browse = static_cast< const KPDFLinkBrowse * >( link ); + // if the url is a mailto one, invoke mailer + if ( browse->url().startsWith( "mailto:", false ) ) + kapp->invokeMailer( browse->url() ); + else + { + QString url = browse->url(); + + // fix for #100366, documents with relative links that are the form of http:foo.pdf + if (url.find("http:") == 0 && url.find("http://") == -1 && url.right(4) == ".pdf") + { + openRelativeFile(url.mid(5)); + return; + } + + // Albert: this is not a leak! + new KRun(url); + } + } break; + + case KPDFLink::Movie: + //const KPDFLinkMovie * browse = static_cast< const KPDFLinkMovie * >( link ); + // TODO this (Movie link) + break; + } +} + +bool KPDFDocument::print( KPrinter &printer ) +{ + return generator ? generator->print( printer ) : false; +} + +void KPDFDocument::requestDone( PixmapRequest * req ) +{ +#ifndef NDEBUG + if ( !generator->canGeneratePixmap() ) + kdDebug() << "requestDone with generator not in READY state." << endl; +#endif + + // [MEM] 1.1 find and remove a previous entry for the same page and id + QValueList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin(); + QValueList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end(); + for ( ; aIt != aEnd; ++aIt ) + if ( (*aIt)->page == req->pageNumber && (*aIt)->id == req->id ) + { + AllocatedPixmap * p = *aIt; + d->allocatedPixmapsFifo.remove( aIt ); + d->allocatedPixmapsTotalMemory -= p->memory; + delete p; + break; + } + + if ( d->observers.contains( req->id ) ) + { + // [MEM] 1.2 append memory allocation descriptor to the FIFO + int memoryBytes = 4 * req->width * req->height; + AllocatedPixmap * memoryPage = new AllocatedPixmap( req->id, req->pageNumber, memoryBytes ); + d->allocatedPixmapsFifo.append( memoryPage ); + d->allocatedPixmapsTotalMemory += memoryBytes; + + // 2. notify an observer that its pixmap changed + d->observers[ req->id ]->notifyPageChanged( req->pageNumber, DocumentObserver::Pixmap ); + } +#ifndef NDEBUG + else + kdWarning() << "Receiving a done request for the defunct observer " << req->id << endl; +#endif + + // 3. delete request + delete req; + + // 4. start a new generation if some is pending + if ( !d->pixmapRequestsStack.isEmpty() ) + sendGeneratorRequest(); +} + +void KPDFDocument::sendGeneratorRequest() +{ + // find a request + PixmapRequest * request = 0; + while ( !d->pixmapRequestsStack.isEmpty() && !request ) + { + PixmapRequest * r = d->pixmapRequestsStack.last(); + d->pixmapRequestsStack.pop_back(); + // request only if page isn't already present + if ( !r->page->hasPixmap( r->id, r->width, r->height ) ) + request = r; + else + delete r; + } + + // if no request found (or already generated), return + if ( !request ) + return; + + // [MEM] preventive memory freeing + int pixmapBytes = 4 * request->width * request->height; + if ( pixmapBytes > (1024 * 1024) ) + cleanupPixmapMemory( pixmapBytes ); + + // submit the request to the generator + generator->generatePixmap( request ); +} + +void KPDFDocument::cleanupPixmapMemory( int /*sure? bytesOffset*/ ) +{ + // [MEM] choose memory parameters based on configuration profile + int clipValue = -1; + int memoryToFree = -1; + switch ( KpdfSettings::memoryLevel() ) + { + case KpdfSettings::EnumMemoryLevel::Low: + memoryToFree = d->allocatedPixmapsTotalMemory; + break; + + case KpdfSettings::EnumMemoryLevel::Normal: + memoryToFree = d->allocatedPixmapsTotalMemory - getTotalMemory() / 3; + clipValue = (d->allocatedPixmapsTotalMemory - getFreeMemory()) / 2; + break; + + case KpdfSettings::EnumMemoryLevel::Aggressive: + clipValue = (d->allocatedPixmapsTotalMemory - getFreeMemory()) / 2; + break; + } + + if ( clipValue > memoryToFree ) + memoryToFree = clipValue; + + if ( memoryToFree > 0 ) + { + // [MEM] free memory starting from older pixmaps + int pagesFreed = 0; + QValueList< AllocatedPixmap * >::iterator pIt = d->allocatedPixmapsFifo.begin(); + QValueList< AllocatedPixmap * >::iterator pEnd = d->allocatedPixmapsFifo.end(); + while ( (pIt != pEnd) && (memoryToFree > 0) ) + { + AllocatedPixmap * p = *pIt; + if ( d->observers[ p->id ]->canUnloadPixmap( p->page ) ) + { + // update internal variables + pIt = d->allocatedPixmapsFifo.remove( pIt ); + d->allocatedPixmapsTotalMemory -= p->memory; + memoryToFree -= p->memory; + pagesFreed++; + // delete pixmap + pages_vector[ p->page ]->deletePixmap( p->id ); + // delete allocation descriptor + delete p; + } else + ++pIt; + } + //p--rintf("freeMemory A:[%d -%d = %d] \n", d->allocatedPixmapsFifo.count() + pagesFreed, pagesFreed, d->allocatedPixmapsFifo.count() ); + } +} + +int KPDFDocument::getTotalMemory() +{ + static int cachedValue = 0; + if ( cachedValue ) + return cachedValue; + +#ifdef __linux__ + // if /proc/meminfo doesn't exist, return 128MB + QFile memFile( "/proc/meminfo" ); + if ( !memFile.open( IO_ReadOnly ) ) + return (cachedValue = 134217728); + + // read /proc/meminfo and sum up the contents of 'MemFree', 'Buffers' + // and 'Cached' fields. consider swapped memory as used memory. + QTextStream readStream( &memFile ); + while ( !readStream.atEnd() ) + { + QString entry = readStream.readLine(); + if ( entry.startsWith( "MemTotal:" ) ) + return (cachedValue = (1024 * entry.section( ' ', -2, -2 ).toInt())); + } +#endif + return (cachedValue = 134217728); +} + +int KPDFDocument::getFreeMemory() +{ + static QTime lastUpdate = QTime::currentTime(); + static int cachedValue = 0; + + if ( lastUpdate.secsTo( QTime::currentTime() ) <= 2 ) + return cachedValue; + +#ifdef __linux__ + // if /proc/meminfo doesn't exist, return MEMORY FULL + QFile memFile( "/proc/meminfo" ); + if ( !memFile.open( IO_ReadOnly ) ) + return 0; + + // read /proc/meminfo and sum up the contents of 'MemFree', 'Buffers' + // and 'Cached' fields. consider swapped memory as used memory. + int memoryFree = 0; + QString entry; + QTextStream readStream( &memFile ); + while ( !readStream.atEnd() ) + { + entry = readStream.readLine(); + if ( entry.startsWith( "MemFree:" ) || + entry.startsWith( "Buffers:" ) || + entry.startsWith( "Cached:" ) || + entry.startsWith( "SwapFree:" ) ) + memoryFree += entry.section( ' ', -2, -2 ).toInt(); + if ( entry.startsWith( "SwapTotal:" ) ) + memoryFree -= entry.section( ' ', -2, -2 ).toInt(); + } + memFile.close(); + + lastUpdate = QTime::currentTime(); + + return ( cachedValue = ( 1024 * memoryFree ) ); +#else + // tell the memory is full.. will act as in LOW profile + return 0; +#endif +} + +void KPDFDocument::loadDocumentInfo() +// note: load data and stores it internally (document or pages). observers +// are still uninitialized at this point so don't access them +{ + //kdDebug() << "Using '" << d->xmlFileName << "' as document info file." << endl; + QFile infoFile( d->xmlFileName ); + if ( !infoFile.exists() || !infoFile.open( IO_ReadOnly ) ) + return; + + // Load DOM from XML file + QDomDocument doc( "documentInfo" ); + if ( !doc.setContent( &infoFile ) ) + { + kdDebug() << "Could not set content" << endl; + infoFile.close(); + return; + } + infoFile.close(); + + QDomElement root = doc.documentElement(); + if ( root.tagName() != "documentInfo" ) + return; + + // Parse the DOM tree + QDomNode topLevelNode = root.firstChild(); + while ( topLevelNode.isElement() ) + { + QString catName = topLevelNode.toElement().tagName(); + + // Get bookmarks list from DOM + if ( catName == "bookmarkList" ) + { + QDomNode n = topLevelNode.firstChild(); + QDomElement e; + int pageNumber; + bool ok; + while ( n.isElement() ) + { + e = n.toElement(); + if (e.tagName() == "page") + { + pageNumber = e.text().toInt(&ok); + if ( ok && pageNumber >= 0 && pageNumber < (int)pages_vector.count() ) + pages_vector[ pageNumber ]->setBookmark( true ); + } + n = n.nextSibling(); + } + } // + // Get 'general info' from the DOM + else if ( catName == "generalInfo" ) + { + QDomNode infoNode = topLevelNode.firstChild(); + while ( infoNode.isElement() ) + { + QDomElement infoElement = infoNode.toElement(); + + // compatibility: [pre-3.4 viewport storage] @remove after 3.4 relase + if ( infoElement.tagName() == "activePage" ) + { + if ( infoElement.hasAttribute( "viewport" ) ) + *d->viewportIterator = DocumentViewport( infoElement.attribute( "viewport" ) ); + } + + // restore viewports history + if ( infoElement.tagName() == "history" ) + { + // clear history + d->viewportHistory.clear(); + // append old viewports + QDomNode historyNode = infoNode.firstChild(); + while ( historyNode.isElement() ) + { + QDomElement historyElement = historyNode.toElement(); + if ( historyElement.hasAttribute( "viewport" ) ) + { + QString vpString = historyElement.attribute( "viewport" ); + d->viewportIterator = d->viewportHistory.append( + DocumentViewport( vpString ) ); + } + historyNode = historyNode.nextSibling(); + } + // consistancy check + if ( d->viewportHistory.isEmpty() ) + d->viewportIterator = d->viewportHistory.append( DocumentViewport() ); + } + infoNode = infoNode.nextSibling(); + } + } // + topLevelNode = topLevelNode.nextSibling(); + } // +} + +QString KPDFDocument::giveAbsolutePath( const QString & fileName ) +{ + if ( !d->url.isValid() ) + return QString::null; + + return d->url.upURL().url() + fileName; +} + +bool KPDFDocument::openRelativeFile( const QString & fileName ) +{ + QString absFileName = giveAbsolutePath( fileName ); + if ( absFileName.isNull() ) + return false; + + kdDebug() << "openDocument: '" << absFileName << "'" << endl; + + emit openURL( absFileName ); + return true; +} + + +void KPDFDocument::saveDocumentInfo() const +{ + if ( d->docFileName.isNull() ) + return; + + QFile infoFile( d->xmlFileName ); + if (infoFile.open( IO_WriteOnly | IO_Truncate) ) + { + // Create DOM + QDomDocument doc( "documentInfo" ); + QDomElement root = doc.createElement( "documentInfo" ); + doc.appendChild( root ); + + // Add bookmark list to DOM + QDomElement bookmarkList = doc.createElement( "bookmarkList" ); + root.appendChild( bookmarkList ); + + for ( uint i = 0; i < pages_vector.count() ; i++ ) + { + if ( pages_vector[i]->hasBookmark() ) + { + QDomElement page = doc.createElement( "page" ); + page.appendChild( doc.createTextNode( QString::number(i) ) ); + + bookmarkList.appendChild( page ); + } + } + + // Add general info to DOM + QDomElement generalInfo = doc.createElement( "generalInfo" ); + root.appendChild( generalInfo ); + + // ... saves history up to 10 viewports + QValueList< DocumentViewport >::iterator backIterator = d->viewportIterator; + if ( backIterator != d->viewportHistory.end() ) + { + // go back up to 10 steps from the current viewportIterator + int backSteps = 10; + while ( backSteps-- && backIterator != d->viewportHistory.begin() ) + --backIterator; + + // create history root node + QDomElement historyNode = doc.createElement( "history" ); + generalInfo.appendChild( historyNode ); + + // add old[backIterator] and present[viewportIterator] items + QValueList< DocumentViewport >::iterator endIt = d->viewportIterator; + ++endIt; + while ( backIterator != endIt ) + { + QString name = (backIterator == d->viewportIterator) ? "current" : "oldPage"; + QDomElement historyEntry = doc.createElement( name ); + historyEntry.setAttribute( "viewport", (*backIterator).toString() ); + historyNode.appendChild( historyEntry ); + ++backIterator; + } + } + + // Save DOM to XML file + QString xml = doc.toString(); + QTextStream os( &infoFile ); + os << xml; + } + infoFile.close(); +} + +void KPDFDocument::slotTimedMemoryCheck() +{ + // [MEM] clean memory (for 'free mem dependant' profiles only) + if ( KpdfSettings::memoryLevel() != KpdfSettings::EnumMemoryLevel::Low && + d->allocatedPixmapsTotalMemory > 1024*1024 ) + cleanupPixmapMemory(); +} + + +/** DocumentViewport **/ + +DocumentViewport::DocumentViewport( int n ) + : pageNumber( n ) +{ + // default settings + rePos.enabled = false; + rePos.normalizedX = 0.5; + rePos.normalizedY = 0.0; + rePos.pos = Center; + autoFit.enabled = false; + autoFit.width = false; + autoFit.height = false; +} + +DocumentViewport::DocumentViewport( const QString & xmlDesc ) + : pageNumber( -1 ) +{ + // default settings (maybe overridden below) + rePos.enabled = false; + rePos.normalizedX = 0.5; + rePos.normalizedY = 0.0; + rePos.pos = Center; + autoFit.enabled = false; + autoFit.width = false; + autoFit.height = false; + + // check for string presence + if ( xmlDesc.isEmpty() ) + return; + + // decode the string + bool ok; + int field = 0; + QString token = xmlDesc.section( ';', field, field ); + while ( !token.isEmpty() ) + { + // decode the current token + if ( field == 0 ) + { + pageNumber = token.toInt( &ok ); + if ( !ok ) + return; + } + else if ( token.startsWith( "C1" ) ) + { + rePos.enabled = true; + rePos.normalizedX = token.section( ':', 1, 1 ).toDouble(); + rePos.normalizedY = token.section( ':', 2, 2 ).toDouble(); + rePos.pos = Center; + } + else if ( token.startsWith( "C2" ) ) + { + rePos.enabled = true; + rePos.normalizedX = token.section( ':', 1, 1 ).toDouble(); + rePos.normalizedY = token.section( ':', 2, 2 ).toDouble(); + if (token.section( ':', 3, 3 ).toInt() == 1) rePos.pos = Center; + else rePos.pos = TopLeft; + } + else if ( token.startsWith( "AF1" ) ) + { + autoFit.enabled = true; + autoFit.width = token.section( ':', 1, 1 ) == "T"; + autoFit.height = token.section( ':', 2, 2 ) == "T"; + } + // proceed tokenizing string + field++; + token = xmlDesc.section( ';', field, field ); + } +} + +QString DocumentViewport::toString() const +{ + // start string with page number + QString s = QString::number( pageNumber ); + // if has center coordinates, save them on string + if ( rePos.enabled ) + s += QString( ";C2:" ) + QString::number( rePos.normalizedX ) + + ':' + QString::number( rePos.normalizedY ) + + ':' + QString::number( rePos.pos ); + // if has autofit enabled, save its state on string + if ( autoFit.enabled ) + s += QString( ";AF1:" ) + (autoFit.width ? "T" : "F") + + ':' + (autoFit.height ? "T" : "F"); + return s; +} + +bool DocumentViewport::operator==( const DocumentViewport & vp ) const +{ + bool equal = ( pageNumber == vp.pageNumber ) && + ( rePos.enabled == vp.rePos.enabled ) && + ( autoFit.enabled == vp.autoFit.enabled ); + if ( !equal ) + return false; + if ( rePos.enabled && + (( rePos.normalizedX != vp.rePos.normalizedX) || + ( rePos.normalizedY != vp.rePos.normalizedY ) || rePos.pos != vp.rePos.pos) ) + return false; + if ( autoFit.enabled && + (( autoFit.width != vp.autoFit.width ) || + ( autoFit.height != vp.autoFit.height )) ) + return false; + return true; +} + + +/** DocumentInfo **/ + +DocumentInfo::DocumentInfo() + : QDomDocument( "DocumentInformation" ) +{ + QDomElement docElement = createElement( "DocumentInfo" ); + appendChild( docElement ); +} + +void DocumentInfo::set( const QString &key, const QString &value, + const QString &title ) +{ + QDomElement docElement = documentElement(); + QDomElement element; + + // check whether key already exists + QDomNodeList list = docElement.elementsByTagName( key ); + if ( list.count() > 0 ) + element = list.item( 0 ).toElement(); + else + element = createElement( key ); + + element.setAttribute( "value", value ); + element.setAttribute( "title", title ); + + if ( list.count() == 0 ) + docElement.appendChild( element ); +} + +QString DocumentInfo::get( const QString &key ) const +{ + QDomElement docElement = documentElement(); + QDomElement element; + + // check whether key already exists + QDomNodeList list = docElement.elementsByTagName( key ); + if ( list.count() > 0 ) + return list.item( 0 ).toElement().attribute( "value" ); + else + return QString(); +} + + +/** DocumentSynopsis **/ + +DocumentSynopsis::DocumentSynopsis() + : QDomDocument( "DocumentSynopsis" ) +{ + // void implementation, only subclassed for naming +} + +#include "document.moc" diff --git a/kpdf/core/document.h b/kpdf/core/document.h new file mode 100644 index 00000000..8e4c1d8e --- /dev/null +++ b/kpdf/core/document.h @@ -0,0 +1,225 @@ +/*************************************************************************** + * Copyright (C) 2004 by Enrico Ros * + * Copyright (C) 2004-2005 by Albert Astals Cid * + * * + * 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. * + ***************************************************************************/ + +#ifndef _KPDF_DOCUMENT_H_ +#define _KPDF_DOCUMENT_H_ + +#include +#include +#include +#include + +#include + +class KPDFPage; +class KPDFLink; +class DocumentObserver; +class DocumentViewport; +class DocumentInfo; +class DocumentSynopsis; +class Generator; +class PixmapRequest; +class KListView; +class KPrinter; +class KURL; + +/** + * @short The Document. Heart of everything. Actions take place here. + * + * The Document is the main object in KPDF. All views query the Document to + * get data/properties or even for accessing pages (in a 'const' way). + * + * It is designed to keep it detached from the document type (pdf, ps, you + * name it..) so whenever you want to get some data, it asks its internals + * generator to do the job and return results in a format-indepedent way. + * + * Apart from the generator (the currently running one) the document stores + * all the Pages ('KPDFPage' class) of the current document in a vector and + * notifies all the registered DocumentObservers when some content changes. + * + * For a better understanding of hieracies @see README.internals.png + * @see DocumentObserver, KPDFPage + */ +class KPDFDocument : public QObject +{ + Q_OBJECT + public: + KPDFDocument( QWidget *widget ); + ~KPDFDocument(); + + // document handling + bool openDocument( const QString & docFile, const KURL & url, const KMimeType::Ptr &mime ); + void closeDocument(); + + // misc methods + void addObserver( DocumentObserver * pObserver ); + void removeObserver( DocumentObserver * pObserver ); + void reparseConfig(); + + // enum definitions + enum Permission { AllowModify = 1, AllowCopy = 2, AllowPrint = 4, AllowNotes = 8 }; + + // returns the widget where the document is shown + QWidget *widget() const; + + // query methods (const ones) + bool isOpened() const; + const DocumentInfo * documentInfo() const; + const DocumentSynopsis * documentSynopsis() const; + const KPDFPage * page( uint page ) const; + const DocumentViewport & viewport() const; + uint currentPage() const; + uint pages() const; + KURL currentDocument() const; + bool isAllowed( int /*Document::Permisison(s)*/ ) const; + bool historyAtBegin() const; + bool historyAtEnd() const; + QString getMetaData( const QString & key, const QString & option = QString() ) const; + bool supportsSearching() const; + bool hasFonts() const; + void putFontInfo(KListView *list); + + // perform actions on document / pages + void setViewportPage( int page, int excludeId = -1, bool smoothMove = false ); + void setViewport( const DocumentViewport & viewport, int excludeId = -1, bool smoothMove = false ); + void setPrevViewport(); + void setNextViewport(); + void setNextDocumentViewport( const DocumentViewport & viewport ); + void requestPixmaps( const QValueList< PixmapRequest * > & requests ); + void requestTextPage( uint page ); + + enum SearchType { NextMatch, PrevMatch, AllDoc, GoogleAll, GoogleAny }; + bool searchText( int searchID, const QString & text, bool fromStart, bool caseSensitive, + SearchType type, bool moveViewport, const QColor & color, bool noDialogs = false ); + bool continueSearch( int searchID ); + void resetSearch( int searchID ); + bool continueLastSearch(); + void toggleBookmark( int page ); + void processLink( const KPDFLink * link ); + bool print( KPrinter &printer ); + + // notifications sent by generator + void requestDone( PixmapRequest * request ); + + signals: + void close(); + void quit(); + void linkFind(); + void linkGoToPage(); + void openURL(const KURL &url); + void linkPresentation(); + void linkEndPresentation(); + + private: + void sendGeneratorRequest(); + // memory management related functions + void cleanupPixmapMemory( int bytesOffset = 0 ); + int getTotalMemory(); + int getFreeMemory(); + // more private functions + void loadDocumentInfo(); + QString giveAbsolutePath( const QString & fileName ); + bool openRelativeFile( const QString & fileName ); + + Generator * generator; + QValueVector< KPDFPage * > pages_vector; + class KPDFDocumentPrivate * d; + + private slots: + void saveDocumentInfo() const; + void slotTimedMemoryCheck(); +}; + + +/** + * @short A view on the document. + * + * The Viewport structure is the 'current view' over the document. Contained + * data is broadcasted between observers to syncronize their viewports to get + * the 'I scroll one view and others scroll too' views. + */ +class DocumentViewport +{ + public: + /** data fields **/ + // the page nearest the center of the viewport + int pageNumber; + + // enum definitions + enum Position { Center = 1, TopLeft = 2}; + + // if reCenter.enabled, this contains the viewport center + struct { + bool enabled; + double normalizedX; + double normalizedY; + Position pos; + } rePos; + + // if autoFit.enabled, page must be autofitted in the viewport + struct { + bool enabled; + bool width; + bool height; + } autoFit; + + /** class methods **/ + // allowed constructors, don't use others + DocumentViewport( int pageNumber = -1 ); + DocumentViewport( const QString & xmlDesc ); + QString toString() const; + bool operator==( const DocumentViewport & vp ) const; +}; + +/** + * @short A dom tree containing informations about the document. + * + * The Info structure can be filled in by generators to display metadata + * about the currently opened file. + */ +class DocumentInfo : public QDomDocument +{ + public: + DocumentInfo(); + + /** + * Sets a value for a special key. The title should be an i18n'ed + * string, since it's used in the document information dialog. + */ + void set( const QString &key, const QString &value, + const QString &title = QString() ); + + /** + * Returns the value for a given key or an empty string when the + * key doesn't exist. + */ + QString get( const QString &key ) const; +}; + +/** + * @short A Dom tree that describes the Table of Contents. + * + * The Synopsis (TOC or Table Of Contents for friends) is represented via + * a dom tree where each nod has an internal name (displayed in the listview) + * and one or more attributes. + * + * In the tree the tag name is the 'screen' name of the entry. A tag can have + * attributes. Here follows the list of tag attributes with meaning: + * - Viewport: A string description of the referred viewport + * - ViewportName: A 'named reference' to the viewport that must be converted + * using getMetaData( "NamedViewport", *viewport_name* ) + */ +class DocumentSynopsis : public QDomDocument +{ + public: + DocumentSynopsis(); +}; + +#endif diff --git a/kpdf/core/generator.h b/kpdf/core/generator.h new file mode 100644 index 00000000..ca0ea015 --- /dev/null +++ b/kpdf/core/generator.h @@ -0,0 +1,115 @@ +/*************************************************************************** + * Copyright (C) 2004 by Enrico Ros * + * * + * 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. * + ***************************************************************************/ + +#ifndef _KPDF_GENERATOR_H_ +#define _KPDF_GENERATOR_H_ + +#include +#include +#include +#include "core/document.h" +class KListView; +class KPrinter; +class KPDFPage; +class KPDFLink; +class PixmapRequest; + +/* Note: on contents generation and asyncronous queries. + * Many observers may want to request data syncronously or asyncronously. + * - Sync requests. These should be done in-place. + * - Async request must be done in real background. That usually means a + * thread, such as QThread derived classes. + * Once contents are available, they must be immediately stored in the + * KPDFPage they refer to, and a signal is emitted as soon as storing + * (even for sync or async queries) has been done. + */ + +/** + * @short [Abstract Class] The information generator. + * + * Most of class members are pure virtuals and they must be implemented to + * provide a class that builds contents (graphics and text). + * + * Generation/query is requested by the 'KPDFDocument' class only, and that + * class stores the resulting data into 'KPDFPage's. The data will then be + * displayed by the GUI components (pageView, thumbnailList, etc..). + */ +class Generator : public QObject +{ + public: + /** virtual methods to reimplement **/ + // load a document and fill up the pagesVector + virtual bool loadDocument( const QString & fileName, QValueVector< KPDFPage * > & pagesVector ) = 0; + + // Document description and Table of contents + virtual const DocumentInfo * generateDocumentInfo() { return 0L; } + virtual const DocumentSynopsis * generateDocumentSynopsis() { return 0L; } + + // DRM handling + virtual bool isAllowed( int /*Document::Permisison(s)*/ ) { return true; } + + // page contents generation + virtual bool canGeneratePixmap() = 0; + virtual void generatePixmap( PixmapRequest * request ) = 0; + virtual void generateSyncTextPage( KPDFPage * page ) = 0; + + // capability querying + virtual bool supportsSearching() const = 0; + virtual bool hasFonts() const = 0; + + // font related + virtual void putFontInfo(KListView *list) = 0; + + // print document using already configured kprinter + virtual bool print( KPrinter& /*printer*/ ) { return false; } + // access meta data of the generator + virtual QString getMetaData( const QString &/*key*/, const QString &/*option*/ ) { return QString(); } + // tell generator to re-parse configuration and return true if something changed + virtual bool reparseConfig() { return false; } + + /** 'signals' to send events the KPDFDocument **/ + // tell the document that the job has been completed + void signalRequestDone( PixmapRequest * request ) { m_document->requestDone( request ); } + + /** constructor: takes the Document as a parameter **/ + Generator( KPDFDocument * doc ) : m_document( doc ) {}; + + protected: + KPDFDocument * m_document; + + private: + Generator(); +}; + +/** + * @short Describes a pixmap type request. + */ +struct PixmapRequest +{ + PixmapRequest( int rId, int n, int w, int h, int p, bool a = false ) + : id( rId ), pageNumber( n ), width( w ), height( h ), + priority( p ), async( a ), page( 0 ) {}; + + // observer id + int id; + // page number and size + int pageNumber; + int width; + int height; + // asyncronous request priority (less is better, 0 is max) + int priority; + // generate the pixmap in a thread and notify observer when done + bool async; + + // this field is set by the Docuemnt prior passing the + // request to the generator + KPDFPage * page; +}; + +#endif diff --git a/kpdf/core/generator_kimgio/Makefile.am b/kpdf/core/generator_kimgio/Makefile.am new file mode 100644 index 00000000..5a93221d --- /dev/null +++ b/kpdf/core/generator_kimgio/Makefile.am @@ -0,0 +1,6 @@ +INCLUDES = -I$(srcdir)/../../ $(all_includes) + +libgeneratorkimgio_la_LDFLAGS = $(all_libraries) +libgeneratorkimgio_la_SOURCES = generator_kimgio.cpp + +noinst_LTLIBRARIES = libgeneratorkimgio.la diff --git a/kpdf/core/generator_kimgio/generator_kimgio.cpp b/kpdf/core/generator_kimgio/generator_kimgio.cpp new file mode 100644 index 00000000..bb754686 --- /dev/null +++ b/kpdf/core/generator_kimgio/generator_kimgio.cpp @@ -0,0 +1,72 @@ +/*************************************************************************** + * Copyright (C) 2005 by Albert Astals Cid * + * * + * 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. * + ***************************************************************************/ + +#include +#include +#include + +#include "core/page.h" +#include "generator_kimgio.h" + +KIMGIOGenerator::KIMGIOGenerator( KPDFDocument * document ) : Generator( document ) +{ +} + +KIMGIOGenerator::~KIMGIOGenerator() +{ + delete m_pix; +} + +bool KIMGIOGenerator::loadDocument( const QString & fileName, QValueVector & pagesVector ) +{ + m_pix = new QPixmap(fileName); + + pagesVector.resize( 1 ); + + KPDFPage * page = new KPDFPage( 0, m_pix->width(), m_pix->height(), 0 ); + pagesVector[0] = page; + + return true; +} + +bool KIMGIOGenerator::canGeneratePixmap() +{ + return true; +} + +void KIMGIOGenerator::generatePixmap( PixmapRequest * request ) +{ + QPixmap *p = new QPixmap(*m_pix); + request->page->setPixmap(request->id, p); +} + +void KIMGIOGenerator::generateSyncTextPage( KPDFPage * ) +{ +} + +bool KIMGIOGenerator::supportsSearching() const +{ + return false; +} + +bool KIMGIOGenerator::hasFonts() const +{ + return false; +} + +void KIMGIOGenerator::putFontInfo( KListView * ) +{ +} + +bool KIMGIOGenerator::print( KPrinter& printer ) +{ + QPainter p(&printer); + p.drawPixmap(0, 0, *m_pix); + return true; +} diff --git a/kpdf/core/generator_kimgio/generator_kimgio.h b/kpdf/core/generator_kimgio/generator_kimgio.h new file mode 100644 index 00000000..bda411f2 --- /dev/null +++ b/kpdf/core/generator_kimgio/generator_kimgio.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * Copyright (C) 2005 by Albert Astals Cid * + * * + * 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. * + ***************************************************************************/ + +#ifndef _KPDF_GENERATOR_PNG_H_ +#define _KPDF_GENERATOR_PNG_H_ + +#include "core/generator.h" + +class KIMGIOGenerator : public Generator +{ + public: + KIMGIOGenerator( KPDFDocument * document ); + virtual ~KIMGIOGenerator(); + + // [INHERITED] load a document and fill up the pagesVector + bool loadDocument( const QString & fileName, QValueVector & pagesVector ); + + // [INHERITED] perform actions on document / pages + bool canGeneratePixmap(); + void generatePixmap( PixmapRequest * request ); + void generateSyncTextPage( KPDFPage * page ); + + // [INHERITED] capability querying + bool supportsSearching() const; + bool hasFonts() const; + + // font related + void putFontInfo(KListView *list); + + // [INHERITED] print document using already configured kprinter + bool print( KPrinter& printer ); + + private: + QPixmap *m_pix; +}; + +#endif diff --git a/kpdf/core/generator_pdf/Makefile.am b/kpdf/core/generator_pdf/Makefile.am new file mode 100644 index 00000000..700740b7 --- /dev/null +++ b/kpdf/core/generator_pdf/Makefile.am @@ -0,0 +1,10 @@ +INCLUDES = -I$(srcdir)/../.. -I$(srcdir)/../../xpdf -I$(srcdir)/../../xpdf/goo -I$(srcdir)/../../xpdf/splash -I$(top_builddir)/kpdf $(all_includes) + +libgeneratorpdf_la_LDFLAGS = $(all_libraries) +libgeneratorpdf_la_SOURCES = generator_pdf.cpp gp_outputdev.cpp + +noinst_LTLIBRARIES = libgeneratorpdf.la + +KDE_OPTIONS = nofinal + +generator_pdf.lo: ../../conf/settings.h diff --git a/kpdf/core/generator_pdf/generator_pdf.cpp b/kpdf/core/generator_pdf/generator_pdf.cpp new file mode 100644 index 00000000..7ad34152 --- /dev/null +++ b/kpdf/core/generator_pdf/generator_pdf.cpp @@ -0,0 +1,1258 @@ +/*************************************************************************** + * Copyright (C) 2004 by Albert Astals Cid * + * Copyright (C) 2004 by Enrico Ros * + * * + * 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. * + ***************************************************************************/ + +// qt/kde includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// xpdf includes +#include "xpdf/Object.h" +#include "xpdf/Dict.h" +#include "xpdf/Annot.h" +#include "xpdf/PSOutputDev.h" +#include "xpdf/TextOutputDev.h" +#include "xpdf/Link.h" +#include "xpdf/ErrorCodes.h" +#include "xpdf/UnicodeMap.h" +#include "xpdf/Outline.h" +#include "goo/GList.h" + +// local includes +#include "generator_pdf.h" +#include "gp_outputdev.h" +#include "core/observer.h" //for PAGEVIEW_ID +#include "core/page.h" +#include "core/pagetransition.h" +#include "conf/settings.h" + +#include + +#include + +// id for DATA_READY PDFPixmapGeneratorThread Event +#define TGE_DATAREADY_ID 6969 + +/** NOTES on threading: + * internal: thread race prevention is done via the 'docLock' mutex. the + * mutex is needed only because we have the asyncronous thread; else + * the operations are all within the 'gui' thread, scheduled by the + * Qt scheduler and no mutex is needed. + * external: dangerous operations are all locked via mutex internally, and the + * only needed external thing is the 'canGeneratePixmap' method + * that tells if the generator is free (since we don't want an + * internal queue to store PixmapRequests). A generatedPixmap call + * without the 'ready' flag set, results in undefined behavior. + * So, as example, printing while generating a pixmap asyncronously is safe, + * it might only block the gui thread by 1) waiting for the mutex to unlock + * in async thread and 2) doing the 'heavy' print operation. + */ + +PDFGenerator::PDFGenerator( KPDFDocument * doc ) + : Generator( doc ), pdfdoc( 0 ), kpdfOutputDev( 0 ), ready( true ), + pixmapRequest( 0 ), docInfoDirty( true ), docSynopsisDirty( true ) +{ + // generate kpdfOutputDev and cache page color + reparseConfig(); + // generate the pixmapGeneratorThread + generatorThread = new PDFPixmapGeneratorThread( this ); +} + +PDFGenerator::~PDFGenerator() +{ + // first stop and delete the generator thread + if ( generatorThread ) + { + generatorThread->wait(); + delete generatorThread; + } + // remove other internal objects + docLock.lock(); + delete kpdfOutputDev; + delete pdfdoc; + docLock.unlock(); +} + + +//BEGIN Generator inherited functions +bool PDFGenerator::loadDocument( const QString & filePath, QValueVector & pagesVector ) +{ +#ifndef NDEBUG + if ( pdfdoc ) + { + kdDebug() << "PDFGenerator: multiple calls to loadDocument. Check it." << endl; + return false; + } +#endif + // create PDFDoc for the given file + pdfdoc = new PDFDoc( new GString( QFile::encodeName( filePath ) ), 0, 0 ); + + // if the file didn't open correctly it might be encrypted, so ask for a pass + bool firstInput = true; + bool triedWallet = false; + KWallet::Wallet * wallet = 0; + int keep = 1; + while ( !pdfdoc->isOk() && pdfdoc->getErrorCode() == errEncrypted ) + { + QCString password; + + // 1.A. try to retrieve the first password from the kde wallet system + if ( !triedWallet ) + { + QString walletName = KWallet::Wallet::NetworkWallet(); + wallet = KWallet::Wallet::openWallet( walletName ); + if ( wallet ) + { + // use the KPdf folder (and create if missing) + if ( !wallet->hasFolder( "KPdf" ) ) + wallet->createFolder( "KPdf" ); + wallet->setFolder( "KPdf" ); + + // look for the pass in that folder + QString retrievedPass; + if ( !wallet->readPassword( filePath.section('/', -1, -1), retrievedPass ) ) + password = retrievedPass.local8Bit(); + } + triedWallet = true; + } + + // 1.B. if not retrieved, ask the password using the kde password dialog + if ( password.isNull() ) + { + QString prompt; + if ( firstInput ) + prompt = i18n( "Please insert the password to read the document:" ); + else + prompt = i18n( "Incorrect password. Try again:" ); + firstInput = false; + + // if the user presses cancel, abort opening + if ( KPasswordDialog::getPassword( password, prompt, wallet ? &keep : 0 ) != KPasswordDialog::Accepted ) + break; + } + + // 2. reopen the document using the password + GString * pwd2 = new GString( QString::fromLocal8Bit(password.data()).latin1() ); + delete pdfdoc; + pdfdoc = new PDFDoc( new GString( QFile::encodeName( filePath ) ), pwd2, pwd2 ); + delete pwd2; + + // 3. if the password is correct and the user chose to remember it, store it to the wallet + if ( pdfdoc->isOk() && wallet && /*safety check*/ wallet->isOpen() && keep > 0 ) + { + QString goodPass = QString::fromLocal8Bit( password.data() ); + wallet->writePassword( filePath.section('/', -1, -1), goodPass ); + } + } + if ( !pdfdoc->isOk() ) + { + delete pdfdoc; + pdfdoc = 0; + return false; + } + + // initialize output device for rendering current pdf + kpdfOutputDev->initDevice( pdfdoc ); + + // build Pages (currentPage was set -1 by deletePages) + uint pageCount = pdfdoc->getNumPages(); + pagesVector.resize( pageCount ); + for ( uint i = 0; i < pageCount ; i++ ) + { + KPDFPage * page = new KPDFPage( i, pdfdoc->getPageCropWidth(i+1), + pdfdoc->getPageCropHeight(i+1), + pdfdoc->getPageRotate(i+1) ); + addTransition( i, page ); + pagesVector[i] = page; + } + + // the file has been loaded correctly + return true; +} + + +const DocumentInfo * PDFGenerator::generateDocumentInfo() +{ + if ( docInfoDirty ) + { + docLock.lock(); + // compile internal structure reading properties from PDFDoc + docInfo.set( "title", getDocumentInfo("Title"), i18n("Title") ); + docInfo.set( "subject", getDocumentInfo("Subject"), i18n("Subject") ); + docInfo.set( "author", getDocumentInfo("Author"), i18n("Author") ); + docInfo.set( "keywords", getDocumentInfo("Keywords"), i18n("Keywords") ); + docInfo.set( "creator", getDocumentInfo("Creator"), i18n("Creator") ); + docInfo.set( "producer", getDocumentInfo("Producer"), i18n("Producer") ); + docInfo.set( "creationDate", getDocumentDate("CreationDate"), i18n("Created") ); + docInfo.set( "modificationDate", getDocumentDate("ModDate"), i18n("Modified") ); + docInfo.set( "mimeType", "application/pdf" ); + if ( pdfdoc ) + { + docInfo.set( "format", i18n( "PDF v. ", "PDF v. %1" ) + .arg( QString::number( pdfdoc->getPDFVersion() ) ), i18n( "Format" ) ); + docInfo.set( "encryption", pdfdoc->isEncrypted() ? i18n( "Encrypted" ) : i18n( "Unencrypted" ), + i18n("Security") ); + docInfo.set( "optimization", pdfdoc->isLinearized() ? i18n( "Yes" ) : i18n( "No" ), + i18n("Optimized") ); + docInfo.set( "pages", QString::number( pdfdoc->getCatalog()->getNumPages() ), i18n("Pages") ); + } + else + { + docInfo.set( "format", "PDF", i18n( "Format" ) ); + docInfo.set( "encryption", i18n( "Unknown Encryption" ), i18n( "Security" ) ); + docInfo.set( "optimization", i18n( "Unknown Optimization" ), i18n( "Optimized" ) ); + } + docLock.unlock(); + + // if pdfdoc is valid then we cached good info -> don't cache them again + if ( pdfdoc ) + docInfoDirty = false; + } + return &docInfo; +} + +const DocumentSynopsis * PDFGenerator::generateDocumentSynopsis() +{ + if ( !docSynopsisDirty ) + return &docSyn; + + if ( !pdfdoc ) + return NULL; + + Outline * outline = pdfdoc->getOutline(); + if ( !outline ) + return NULL; + + GList * items = outline->getItems(); + if ( !items || items->getLength() < 1 ) + return NULL; + + docLock.lock(); + docSyn = DocumentSynopsis(); + if ( items->getLength() > 0 ) + addSynopsisChildren( &docSyn, items ); + docLock.unlock(); + + docSynopsisDirty = false; + return &docSyn; +} + +bool PDFGenerator::isAllowed( int permissions ) +{ +#if !KPDF_FORCE_DRM + if (kapp->authorize("skip_drm") && !KpdfSettings::obeyDRM()) return true; +#endif + + bool b = true; + if (permissions & KPDFDocument::AllowModify) b = b && pdfdoc->okToChange(); + if (permissions & KPDFDocument::AllowCopy) b = b && pdfdoc->okToCopy(); + if (permissions & KPDFDocument::AllowPrint) b = b && pdfdoc->okToPrint(); + if (permissions & KPDFDocument::AllowNotes) b = b && pdfdoc->okToAddNotes(); + return b; +} + +bool PDFGenerator::canGeneratePixmap() +{ + return ready; +} + +void PDFGenerator::generatePixmap( PixmapRequest * request ) +{ +#ifndef NDEBUG + if ( !ready ) + kdDebug() << "calling generatePixmap() when not in READY state!" << endl; +#endif + // update busy state (not really needed here, because the flag needs to + // be set only to prevent asking a pixmap while the thread is running) + ready = false; + + // debug requests to this (xpdf) generator + //kdDebug() << "id: " << request->id << " is requesting " << (request->async ? "ASYNC" : "sync") << " pixmap for page " << request->page->number() << " [" << request->width << " x " << request->height << "]." << endl; + + /** asyncronous requests (generation in PDFPixmapGeneratorThread::run() **/ + if ( request->async ) + { + // start the generation into the thread + generatorThread->startGeneration( request ); + return; + } + + /** syncronous request: in-place generation **/ + // compute dpi used to get an image with desired width and height + KPDFPage * page = request->page; + double fakeDpiX = request->width * 72.0 / page->width(), + fakeDpiY = request->height * 72.0 / page->height(); + + // setup kpdf output device: text page is generated only if we are at 72dpi. + // since we can pre-generate the TextPage at the right res.. why not? + bool genTextPage = !page->hasSearchPage() && (request->width == page->width()) && + (request->height == page->height()); + // generate links and image rects if rendering pages on pageview + bool genObjectRects = request->id & (PAGEVIEW_ID | PRESENTATION_ID); + + // 0. LOCK [waits for the thread end] + docLock.lock(); + + // 1. Set OutputDev parameters and Generate contents + // note: thread safety is set on 'false' for the GUI (this) thread + kpdfOutputDev->setParams( request->width, request->height, genObjectRects, genObjectRects, false ); + pdfdoc->displayPage( kpdfOutputDev, page->number() + 1, fakeDpiX, fakeDpiY, 0, false, true, false ); + if ( genObjectRects ) + pdfdoc->processLinks( kpdfOutputDev, page->number() + 1 ); + + // 2. Take data from outputdev and attach it to the Page + page->setPixmap( request->id, kpdfOutputDev->takePixmap() ); + if ( genObjectRects ) + page->setObjectRects( kpdfOutputDev->takeObjectRects() ); + + // 3. UNLOCK [re-enables shared access] + docLock.unlock(); + + if ( genTextPage ) + generateSyncTextPage( page ); + + // update ready state + ready = true; + + // notify the new generation + signalRequestDone( request ); +} + +void PDFGenerator::generateSyncTextPage( KPDFPage * page ) +{ + // build a TextPage... + TextOutputDev td(NULL, gTrue, gFalse, gFalse); + docLock.lock(); + pdfdoc->displayPage( &td, page->number()+1, 72, 72, 0, false, true, false ); + // ..and attach it to the page + page->setSearchPage( td.takeText() ); + docLock.unlock(); +} + +bool PDFGenerator::supportsSearching() const +{ + return true; +} + +bool PDFGenerator::hasFonts() const +{ + return true; +} + +void PDFGenerator::putFontInfo(KListView *list) +{ + Page *page; + Dict *resDict; + Annots *annots; + Object obj1, obj2; + int pg, i; + + Ref *fonts; + int fontsLen; + int fontsSize; + + list->addColumn(i18n("Name")); + list->addColumn(i18n("Type")); + list->addColumn(i18n("Embedded")); + list->addColumn(i18n("File")); + + docLock.lock(); + + fonts = NULL; + fontsLen = fontsSize = 0; + QValueVector visitedXObjects; + for (pg = 1; pg <= pdfdoc->getNumPages(); ++pg) + { + page = pdfdoc->getCatalog()->getPage(pg); + if ((resDict = page->getResourceDict())) + { + scanFonts(resDict, list, &fonts, fontsLen, fontsSize, &visitedXObjects); + } + annots = new Annots(pdfdoc->getXRef(), pdfdoc->getCatalog(), page->getAnnots(&obj1)); + obj1.free(); + for (i = 0; i < annots->getNumAnnots(); ++i) + { + if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) + { + obj1.streamGetDict()->lookup("Resources", &obj2); + if (obj2.isDict()) + { + scanFonts(obj2.getDict(), list, &fonts, fontsLen, fontsSize, &visitedXObjects); + } + obj2.free(); + } + obj1.free(); + } + delete annots; + } + gfree(fonts); + + docLock.unlock(); +} + +bool PDFGenerator::print( KPrinter& printer ) +{ + // PageSize is a CUPS artificially created setting + QString ps = printer.option("PageSize"); + int paperWidth, paperHeight; + int marginTop, marginLeft, marginRight, marginBottom; + marginTop = (int)printer.option("kde-margin-top").toDouble(); + marginLeft = (int)printer.option("kde-margin-left").toDouble(); + marginRight = (int)printer.option("kde-margin-right").toDouble(); + marginBottom = (int)printer.option("kde-margin-bottom").toDouble(); + bool forceRasterize = printer.option("kde-kpdf-forceRaster").toInt(); + + if (ps.find(QRegExp("w\\d+h\\d+")) == 0) + { + // size not supported by Qt, CUPS gives us the size as wWIDTHhHEIGHT, at least on the printers i tester + // remove the w + ps = ps.mid(1); + int hPos = ps.find("h"); + paperWidth = ps.left(hPos).toInt(); + paperHeight = ps.mid(hPos+1).toInt(); + } + else + { + // size is supported by Qt, we get either the pageSize name or nothing because the CUPS driver + // does not do any translation, then use KPrinter::pageSize to get the page size + KPrinter::PageSize qtPageSize; + if (!ps.isEmpty()) qtPageSize = pageNameToPageSize(ps); + else qtPageSize = printer.pageSize(); + + QPrinter dummy(QPrinter::PrinterResolution); + dummy.setFullPage(true); + dummy.setPageSize((QPrinter::PageSize)qtPageSize); + + QPaintDeviceMetrics metrics(&dummy); + paperWidth = metrics.width(); + paperHeight = metrics.height(); + } + + KTempFile tf( QString::null, ".ps" ); + globalParams->setPSPaperWidth(paperWidth); + globalParams->setPSPaperHeight(paperHeight); + QString pstitle = getDocumentInfo("Title", true); + if ( pstitle.isEmpty() ) + { + pstitle = m_document->currentDocument().fileName( false ); + } + // this looks non-unicode-safe and it is. anything other than ASCII is not specified + // and some printers actually stop printing when they encounter non-ASCII characters in the + // Postscript %%Title tag + QCString pstitle8Bit = pstitle.latin1(); + const char* pstitlechar; + if (!pstitle.isEmpty()) + { + pstitlechar = pstitle8Bit.data(); + for (unsigned char* p = (unsigned char*) pstitle8Bit.data(); *p; ++p) + if (*p >= 0x80) + *p = '?'; + + printer.setDocName(pstitle); + } + else + { + pstitlechar = 0; + } + PSOutputDev *psOut = new PSOutputDev(const_cast(tf.name().latin1()), const_cast(pstitlechar), pdfdoc->getXRef(), pdfdoc->getCatalog(), 1, pdfdoc->getNumPages(), psModePS, marginLeft, marginBottom, paperWidth - marginRight, paperHeight - marginTop, forceRasterize); + + if (psOut->isOk()) + { + double xScale = ((double)paperWidth - (double)marginLeft - (double)marginRight) / (double)paperWidth; + double yScale = ((double)paperHeight - (double)marginBottom - (double)marginTop) / (double)paperHeight; + + if ( abs((int)(xScale * 100) - (int)(yScale * 100)) > 5 ) { + int result = KMessageBox::questionYesNo(m_document->widget(), + i18n("The margins you specified change the page aspect ratio. Do you want to print with the aspect ratio changed or do you want the margins to be adapted so that the aspect ratio is preserved?"), + i18n("Aspect ratio change"), + i18n("Print with specified margins"), + i18n("Print adapting margins to keep aspect ratio"), + "kpdfStrictlyObeyMargins"); + if (result == KMessageBox::Yes) psOut->setScale(xScale, yScale); + } + + QValueList pageList; + + if (!printer.previewOnly()) + { + pageList = printer.pageList(); + } + else + { + for(int i = 1; i <= pdfdoc->getNumPages(); i++) pageList.append(i); + } + + QValueList::const_iterator pIt = pageList.begin(), pEnd = pageList.end(); + docLock.lock(); + for ( ; pIt != pEnd; ++pIt ) + { + pdfdoc->displayPage(psOut, *pIt, 72, 72, 0, false, globalParams->getPSCrop(), gTrue); + } + docLock.unlock(); + + // needs to be here so that the file is flushed, do not merge with the one + // in the else + delete psOut; + printer.printFiles(tf.name(), true); + return true; + } + else + { + delete psOut; + return false; + } +} + +static GString *QStringToGString(const QString &s) { + int len = s.length(); + char *cstring = (char *)gmallocn(s.length(), sizeof(char)); + for (int i = 0; i < len; ++i) + cstring[i] = s.at(i).unicode(); + return new GString(cstring, len); +} + +static QString unicodeToQString(Unicode* u, int len) { + QString ret; + ret.setLength(len); + QChar* qch = (QChar*) ret.unicode(); + for (;len;--len) + *qch++ = (QChar) *u++; + return ret; +} + +static QString UnicodeParsedString(GString *s1) { + GBool isUnicode; + int i; + Unicode u; + QString result; + if ( ( s1->getChar(0) & 0xff ) == 0xfe && ( s1->getChar(1) & 0xff ) == 0xff ) + { + isUnicode = gTrue; + i = 2; + } + else + { + isUnicode = gFalse; + i = 0; + } + while ( i < s1->getLength() ) + { + if ( isUnicode ) + { + u = ( ( s1->getChar(i) & 0xff ) << 8 ) | ( s1->getChar(i+1) & 0xff ); + i += 2; + } + else + { + u = s1->getChar(i) & 0xff; + ++i; + } + result += unicodeToQString( &u, 1 ); + } + return result; +} + +QString PDFGenerator::getMetaData( const QString & key, const QString & option ) +{ + if ( key == "StartFullScreen" ) + { + // asking for the 'start in fullscreen mode' (pdf property) + if ( pdfdoc->getCatalog()->getPageMode() == Catalog::FullScreen ) + return "yes"; + } + else if ( key == "NamedViewport" && !option.isEmpty() ) + { + // asking for the page related to a 'named link destination'. the + // option is the link name. @see addSynopsisChildren. + DocumentViewport viewport; + GString * namedDest = QStringToGString(option); + docLock.lock(); + LinkDest * destination = pdfdoc->findDest( namedDest ); + if ( destination ) + { + fillViewportFromLink( viewport, destination ); + } + docLock.unlock(); + delete namedDest; + if ( viewport.pageNumber >= 0 ) + return viewport.toString(); + } + else if ( key == "OpenTOC" ) + { + if ( pdfdoc->getCatalog()->getPageMode() == Catalog::UseOutlines ) + return "yes"; + } + return QString(); +} + +bool PDFGenerator::reparseConfig() +{ + // load paper color from Settings or use the white default color + QColor color = ( (KpdfSettings::renderMode() == KpdfSettings::EnumRenderMode::Paper ) && + KpdfSettings::changeColors() ) ? KpdfSettings::paperColor() : Qt::white; + // if paper color is changed we have to rebuild every visible pixmap in addition + // to the outputDevice. it's the 'heaviest' case, other effect are just recoloring + // over the page rendered on 'standard' white background. + if ( color != paperColor || !kpdfOutputDev ) + { + paperColor = color; + SplashColor splashCol; + splashCol[0] = paperColor.red(); + splashCol[1] = paperColor.green(); + splashCol[2] = paperColor.blue(); + // rebuild the output device using the new paper color and initialize it + docLock.lock(); + delete kpdfOutputDev; + kpdfOutputDev = new KPDFOutputDev( splashCol ); + if ( pdfdoc ) + kpdfOutputDev->initDevice( pdfdoc ); + docLock.unlock(); + return true; + } + return false; +} +//END Generator inherited functions + +void PDFGenerator::scanFonts(Dict *resDict, KListView *list, Ref **fonts, int &fontsLen, int &fontsSize, QValueVector *visitedXObjects) +{ + Object obj1, obj2, xObjDict, xObj, xObj2, resObj; + Ref r; + GfxFontDict *gfxFontDict; + GfxFont *font; + int i; + + // scan the fonts in this resource dictionary + gfxFontDict = NULL; + resDict->lookupNF("Font", &obj1); + if (obj1.isRef()) + { + obj1.fetch(pdfdoc->getXRef(), &obj2); + if (obj2.isDict()) + { + r = obj1.getRef(); + gfxFontDict = new GfxFontDict(pdfdoc->getXRef(), &r, obj2.getDict()); + } + obj2.free(); + } + else if (obj1.isDict()) + { + gfxFontDict = new GfxFontDict(pdfdoc->getXRef(), NULL, obj1.getDict()); + } + if (gfxFontDict) + { + for (i = 0; i < gfxFontDict->getNumFonts(); ++i) + { + if ((font = gfxFontDict->getFont(i))) scanFont(font, list, fonts, fontsLen, fontsSize); + } + delete gfxFontDict; + } + obj1.free(); + + // recursively scan any resource dictionaries in objects in this + // resource dictionary + resDict->lookup("XObject", &xObjDict); + if (xObjDict.isDict()) { + for (i = 0; i < xObjDict.dictGetLength(); ++i) { + xObjDict.dictGetValNF(i, &xObj); + if (xObj.isRef()) { + bool alreadySeen = false; + // check for an already-seen XObject + for (int k = 0; k < visitedXObjects->count(); ++k) { + if (xObj.getRef().num == visitedXObjects->at(k).num && + xObj.getRef().gen == visitedXObjects->at(k).gen) { + alreadySeen = true; + } + } + + if (alreadySeen) { + xObj.free(); + continue; + } + + visitedXObjects->append(xObj.getRef()); + } + + xObj.fetch(pdfdoc->getXRef(), &xObj2); + + if (xObj2.isStream()) { + xObj2.streamGetDict()->lookup("Resources", &resObj); + if (resObj.isDict() && resObj.getDict() != resDict) { + scanFonts(resObj.getDict(), list, fonts, fontsLen, fontsSize, visitedXObjects); + } + resObj.free(); + } + xObj.free(); + xObj2.free(); + } + } + xObjDict.free(); +} + +void PDFGenerator::scanFont(GfxFont *font, KListView *list, Ref **fonts, int &fontsLen, int &fontsSize) +{ + Ref fontRef, embRef; + Object fontObj, toUnicodeObj; + GString *name; + GBool emb; + int i; + + QString fontTypeNames[12] = { + i18n("unknown"), + i18n("Type 1"), + i18n("Type 1C"), + i18n("OT means OpenType", "Type 1C (OT)"), + i18n("Type 3"), + i18n("TrueType"), + i18n("OT means OpenType", "TrueType (OT)"), + i18n("CID Type 0"), + i18n("CID Type 0C"), + i18n("OT means OpenType", "CID Type 0C (OT)"), + i18n("CID TrueType"), + i18n("OT means OpenType", "CID TrueType (OT)") + }; + + fontRef = *font->getID(); + + // check for an already-seen font + for (i = 0; i < fontsLen; ++i) + { + if (fontRef.num == (*fonts)[i].num && fontRef.gen == (*fonts)[i].gen) + { + return; + } + } + + // font name + name = font->getOrigName(); + + // check for an embedded font + if (font->getType() == fontType3) emb = gTrue; + else emb = font->getEmbeddedFontID(&embRef); + + QString sName, sEmb, sPath; + if (name) + { + sName = name->getCString(); + if (!emb) + { + DisplayFontParam *dfp = globalParams->getDisplayFont(name); + if (dfp) + { + if (dfp -> kind == displayFontT1) sPath = dfp->t1.fileName->getCString(); + else sPath = dfp->tt.fileName->getCString(); + } + else sPath = i18n("-"); + } + else sPath = i18n("-"); + } + else + { + sName = i18n("[none]"); + sPath = i18n("-"); + } + sEmb = emb ? i18n("Yes") : i18n("No"); + new KListViewItem(list, sName, fontTypeNames[font->getType()], sEmb, sPath); + + // add this font to the list + if (fontsLen == fontsSize) + { + fontsSize += 32; + *fonts = (Ref *)grealloc(*fonts, fontsSize * sizeof(Ref)); + } + (*fonts)[fontsLen++] = *font->getID(); +} + +QString PDFGenerator::getDocumentInfo( const QString & data, bool canReturnNull ) const +// note: MUTEX is LOCKED while calling this +{ + // [Albert] Code adapted from pdfinfo.cc on xpdf + Object info; + if ( !pdfdoc ) + return canReturnNull ? QString::null : i18n( "Unknown" ); + + pdfdoc->getDocInfo( &info ); + if ( !info.isDict() ) + return canReturnNull ? QString::null : i18n( "Unknown" ); + + Object obj; + Dict *infoDict = info.getDict(); + + if ( infoDict->lookup( (char*)data.latin1(), &obj )->isString() ) + { + QString result = UnicodeParsedString(obj.getString()); + obj.free(); + info.free(); + return result; + } + obj.free(); + info.free(); + return canReturnNull ? QString::null : i18n( "Unknown" ); +} + +QString PDFGenerator::getDocumentDate( const QString & data ) const +// note: MUTEX is LOCKED while calling this +{ + // [Albert] Code adapted from pdfinfo.cc on xpdf + if ( !pdfdoc ) + return i18n( "Unknown Date" ); + + Object info; + pdfdoc->getDocInfo( &info ); + if ( !info.isDict() ) + return i18n( "Unknown Date" ); + + Object obj; + int year, mon, day, hour, min, sec; + Dict *infoDict = info.getDict(); + UnicodeMap *uMap = globalParams->getTextEncoding(); + QString result; + + if ( !uMap ) + return i18n( "Unknown Date" ); + + if ( infoDict->lookup( (char*)data.latin1(), &obj )->isString() ) + { + QString s = UnicodeParsedString(obj.getString()); + if ( s[0] == 'D' && s[1] == ':' ) + s = s.mid(2); + + if ( !s.isEmpty() && sscanf( s.latin1(), "%4d%2d%2d%2d%2d%2d", &year, &mon, &day, &hour, &min, &sec ) == 6 ) + { + QDate d( year, mon, day ); //CHECK: it was mon-1, Jan->0 (??) + QTime t( hour, min, sec ); + if ( d.isValid() && t.isValid() ) + result = KGlobal::locale()->formatDateTime( QDateTime(d, t), false, true ); + else + result = s; + } + else + result = s; + } + else + result = i18n( "Unknown Date" ); + obj.free(); + info.free(); + return result; +} + +void PDFGenerator::addSynopsisChildren( QDomNode * parent, GList * items ) +{ + int numItems = items->getLength(); + for ( int i = 0; i < numItems; ++i ) + { + // iterate over every object in 'items' + OutlineItem * outlineItem = (OutlineItem *)items->get( i ); + + // 1. create element using outlineItem's title as tagName + QString name; + Unicode * uniChar = outlineItem->getTitle(); + int titleLength = outlineItem->getTitleLength(); + name = unicodeToQString(uniChar, titleLength); + if ( name.isEmpty() ) + continue; + QDomElement item = docSyn.createElement( name ); + parent->appendChild( item ); + + // 2. find the page the link refers to + LinkAction * a = outlineItem->getAction(); + if ( a && ( a->getKind() == actionGoTo || a->getKind() == actionGoToR ) ) + { + // page number is contained/referenced in a LinkGoTo + LinkGoTo * g = static_cast< LinkGoTo * >( a ); + LinkDest * destination = g->getDest(); + if ( !destination && g->getNamedDest() ) + { + // no 'destination' but an internal 'named reference'. we could + // get the destination for the page now, but it's VERY time consuming, + // so better storing the reference and provide the viewport as metadata + // on demand + GString *s = g->getNamedDest(); + QChar *charArray = new QChar[s->getLength()]; + for (int i = 0; i < s->getLength(); ++i) charArray[i] = QChar(s->getCString()[i]); + QString option(charArray, s->getLength()); + item.setAttribute( "ViewportName", option ); + delete[] charArray; + } + else if ( destination && destination->isOk() ) + { + DocumentViewport vp; + fillViewportFromLink( vp, destination ); + item.setAttribute( "Viewport", vp.toString() ); + } + if ( a->getKind() == actionGoToR ) + { + LinkGoToR * g2 = static_cast< LinkGoToR * >( a ); + item.setAttribute( "ExternalFileName", g2->getFileName()->getCString() ); + } + } + + item.setAttribute( "Open", QVariant( (bool)outlineItem->isOpen() ).toString() ); + + // 3. recursively descend over children + outlineItem->open(); + GList * children = outlineItem->getKids(); + if ( children ) + addSynopsisChildren( &item, children ); + } +} + +void PDFGenerator::fillViewportFromLink( DocumentViewport &viewport, LinkDest *destination ) +{ + if ( !destination->isPageRef() ) + viewport.pageNumber = destination->getPageNum() - 1; + else + { + Ref ref = destination->getPageRef(); + viewport.pageNumber = pdfdoc->findPage( ref.num, ref.gen ) - 1; + } + + if (viewport.pageNumber < 0) return; + if (viewport.pageNumber >= pdfdoc->getNumPages()) return; + + // get destination position + // TODO add other attributes to the viewport (taken from link) +// switch ( destination->getKind() ) +// { +// case destXYZ: + if (destination->getChangeLeft() || destination->getChangeTop()) + { + double CTM[6]; + Page *page = pdfdoc->getCatalog()->getPage( viewport.pageNumber + 1 ); + // TODO remember to change this if we implement DPI and/or rotation + page->getDefaultCTM(CTM, 72.0, 72.0, 0, gFalse, gTrue); + + int left, top; + // this is OutputDev::cvtUserToDev + left = (int)(CTM[0] * destination->getLeft() + CTM[2] * destination->getTop() + CTM[4] + 0.5); + top = (int)(CTM[1] * destination->getLeft() + CTM[3] * destination->getTop() + CTM[5] + 0.5); + + viewport.rePos.normalizedX = (double)left / (double)page->getCropWidth(); + viewport.rePos.normalizedY = (double)top / (double)page->getCropHeight(); + viewport.rePos.enabled = true; + viewport.rePos.pos = DocumentViewport::TopLeft; + } + /* TODO + if ( dest->getChangeZoom() ) + make zoom change*/ +/* break; + + default: + // implement the others cases + break;*/ +// } +} + +void PDFGenerator::addTransition( int pageNumber, KPDFPage * page ) +{ + Page *pdfPage = pdfdoc->getCatalog()->getPage( pageNumber + 1 ); + if ( !pdfPage ) + return; + + PageTransition *pdfTransition = pdfPage->getTransition(); + if ( !pdfTransition || pdfTransition->getType() == PageTransition::Replace ) + return; + + KPDFPageTransition *transition = new KPDFPageTransition(); + switch ( pdfTransition->getType() ) { + case PageTransition::Replace: + // won't get here, added to avoid warning + break; + case PageTransition::Split: + transition->setType( KPDFPageTransition::Split ); + break; + case PageTransition::Blinds: + transition->setType( KPDFPageTransition::Blinds ); + break; + case PageTransition::Box: + transition->setType( KPDFPageTransition::Box ); + break; + case PageTransition::Wipe: + transition->setType( KPDFPageTransition::Wipe ); + break; + case PageTransition::Dissolve: + transition->setType( KPDFPageTransition::Dissolve ); + break; + case PageTransition::Glitter: + transition->setType( KPDFPageTransition::Glitter ); + break; + case PageTransition::Fly: + transition->setType( KPDFPageTransition::Fly ); + break; + case PageTransition::Push: + transition->setType( KPDFPageTransition::Push ); + break; + case PageTransition::Cover: + transition->setType( KPDFPageTransition::Cover ); + break; + case PageTransition::Uncover: + transition->setType( KPDFPageTransition::Uncover ); + break; + case PageTransition::Fade: + transition->setType( KPDFPageTransition::Fade ); + break; + } + + transition->setDuration( pdfTransition->getDuration() ); + + switch ( pdfTransition->getAlignment() ) { + case PageTransition::Horizontal: + transition->setAlignment( KPDFPageTransition::Horizontal ); + break; + case PageTransition::Vertical: + transition->setAlignment( KPDFPageTransition::Vertical ); + break; + } + + switch ( pdfTransition->getDirection() ) { + case PageTransition::Inward: + transition->setDirection( KPDFPageTransition::Inward ); + break; + case PageTransition::Outward: + transition->setDirection( KPDFPageTransition::Outward ); + break; + } + + transition->setAngle( pdfTransition->getAngle() ); + transition->setScale( pdfTransition->getScale() ); + transition->setIsRectangular( pdfTransition->isRectangular() == gTrue ); + + page->setTransition( transition ); +} + + + +void PDFGenerator::customEvent( QCustomEvent * event ) +{ + // catch generator 'ready events' only + if ( event->type() != TGE_DATAREADY_ID ) + return; + +#if 0 + // check if thread is running (has to be stopped now) + if ( generatorThread->running() ) + { + // if so, wait for effective thread termination + if ( !generatorThread->wait( 9999 /*10s timeout*/ ) ) + { + kdWarning() << "PDFGenerator: thread sent 'data available' " + << "signal but had problems ending." << endl; + return; + } +} +#endif + + // 1. the mutex must be unlocked now + if ( docLock.locked() ) + { + kdWarning() << "PDFGenerator: 'data available' but mutex still " + << "held. Recovering." << endl; + // syncronize GUI thread (must not happen) + docLock.lock(); + docLock.unlock(); + } + + // 2. put thread's generated data into the KPDFPage + PixmapRequest * request = static_cast< PixmapRequest * >( event->data() ); + QImage * outImage = generatorThread->takeImage(); + TextPage * outTextPage = generatorThread->takeTextPage(); + QValueList< ObjectRect * > outRects = generatorThread->takeObjectRects(); + + request->page->setPixmap( request->id, new QPixmap( *outImage ) ); + delete outImage; + if ( outTextPage ) + request->page->setSearchPage( outTextPage ); + if ( !outRects.isEmpty() ) + request->page->setObjectRects( outRects ); + + // 3. tell generator that data has been taken + generatorThread->endGeneration(); + + // update ready state + ready = true; + // notify the new generation + signalRequestDone( request ); +} + + + +/** The PDF Pixmap Generator Thread **/ + +struct PPGThreadPrivate +{ + // reference to main objects + PDFGenerator * generator; + PixmapRequest * currentRequest; + + // internal temp stored items. don't delete this. + QImage * m_image; + TextPage * m_textPage; + QValueList< ObjectRect * > m_rects; + bool m_rectsTaken; +}; + +PDFPixmapGeneratorThread::PDFPixmapGeneratorThread( PDFGenerator * gen ) + : d( new PPGThreadPrivate() ) +{ + d->generator = gen; + d->currentRequest = 0; + d->m_image = 0; + d->m_textPage = 0; + d->m_rectsTaken = true; +} + +PDFPixmapGeneratorThread::~PDFPixmapGeneratorThread() +{ + // delete internal objects if the class is deleted before the gui thread + // takes the data + delete d->m_image; + delete d->m_textPage; + if ( !d->m_rectsTaken && d->m_rects.count() ) + { + QValueList< ObjectRect * >::iterator it = d->m_rects.begin(), end = d->m_rects.end(); + for ( ; it != end; ++it ) + delete *it; + } + delete d->currentRequest; + // delete internal storage structure + delete d; +} + +void PDFPixmapGeneratorThread::startGeneration( PixmapRequest * request ) +{ +#ifndef NDEBUG + // check if a generation is already running + if ( d->currentRequest ) + { + kdDebug() << "PDFPixmapGeneratorThread: requesting a pixmap " + << "when another is being generated." << endl; + delete request; + return; + } + + // check if the mutex is already held + if ( d->generator->docLock.locked() ) + { + kdDebug() << "PDFPixmapGeneratorThread: requesting a pixmap " + << "with the mutex already held." << endl; + delete request; + return; + } +#endif + // set generation parameters and run thread + d->currentRequest = request; + start( QThread::InheritPriority ); +} + +void PDFPixmapGeneratorThread::endGeneration() +{ +#ifndef NDEBUG + // check if a generation is already running + if ( !d->currentRequest ) + { + kdDebug() << "PDFPixmapGeneratorThread: 'end generation' called " + << "but generation was not started." << endl; + return; + } +#endif + // reset internal members preparing for a new generation + d->currentRequest = 0; +} + +QImage * PDFPixmapGeneratorThread::takeImage() const +{ + QImage * img = d->m_image; + d->m_image = 0; + return img; +} + +TextPage * PDFPixmapGeneratorThread::takeTextPage() const +{ + TextPage * tp = d->m_textPage; + d->m_textPage = 0; + return tp; +} + +QValueList< ObjectRect * > PDFPixmapGeneratorThread::takeObjectRects() const +{ + d->m_rectsTaken = true; + return d->m_rects; +} + +void PDFPixmapGeneratorThread::run() +// perform contents generation, when the MUTEX is already LOCKED +// @see PDFGenerator::generatePixmap( .. ) (and be aware to sync the code) +{ + // compute dpi used to get an image with desired width and height + KPDFPage * page = d->currentRequest->page; + int width = d->currentRequest->width, + height = d->currentRequest->height; + double fakeDpiX = width * 72.0 / page->width(), + fakeDpiY = height * 72.0 / page->height(); + + // setup kpdf output device: text page is generated only if we are at 72dpi. + // since we can pre-generate the TextPage at the right res.. why not? + bool genTextPage = !page->hasSearchPage() && + ( width == page->width() ) && + ( height == page->height() ); + + // generate links and image rects if rendering pages on pageview + bool genObjectRects = d->currentRequest->id & (PAGEVIEW_ID | PRESENTATION_ID); + + // 0. LOCK s[tart locking XPDF thread unsafe classes] + d->generator->docLock.lock(); + + // 1. set OutputDev parameters and Generate contents + d->generator->kpdfOutputDev->setParams( width, height, + genObjectRects, genObjectRects, TRUE /*thread safety*/ ); + d->generator->pdfdoc->displayPage( d->generator->kpdfOutputDev, page->number() + 1, + fakeDpiX, fakeDpiY, 0, false, true, false ); + if ( genObjectRects ) + d->generator->pdfdoc->processLinks( d->generator->kpdfOutputDev, page->number() + 1 ); + + // 2. grab data from the OutputDev and store it locally (note takeIMAGE) +#ifndef NDEBUG + if ( d->m_image ) + kdDebug() << "PDFPixmapGeneratorThread: previous image not taken" << endl; + if ( d->m_textPage ) + kdDebug() << "PDFPixmapGeneratorThread: previous textpage not taken" << endl; +#endif + d->m_image = d->generator->kpdfOutputDev->takeImage(); + d->m_rects = d->generator->kpdfOutputDev->takeObjectRects(); + d->m_rectsTaken = false; + + if ( genTextPage ) + { + TextOutputDev td(NULL, gTrue, gFalse, gFalse); + d->generator->pdfdoc->displayPage( &td, page->number()+1, 72, 72, 0, false, true, false ); + // ..and attach it to the page + d->m_textPage = td.takeText(); + } + + // 3. [UNLOCK] mutex + d->generator->docLock.unlock(); + + // notify the GUI thread that data is pending and can be read + QCustomEvent * readyEvent = new QCustomEvent( TGE_DATAREADY_ID ); + readyEvent->setData( d->currentRequest ); + QApplication::postEvent( d->generator, readyEvent ); +} diff --git a/kpdf/core/generator_pdf/generator_pdf.h b/kpdf/core/generator_pdf/generator_pdf.h new file mode 100644 index 00000000..ca267b18 --- /dev/null +++ b/kpdf/core/generator_pdf/generator_pdf.h @@ -0,0 +1,150 @@ +/*************************************************************************** + * Copyright (C) 2004 by Albert Astals Cid * + * Copyright (C) 2004 by Enrico Ros * + * * + * 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. * + ***************************************************************************/ + +#ifndef _KPDF_GENERATOR_PDF_H_ +#define _KPDF_GENERATOR_PDF_H_ + +#include +#include +#include +#include +#include "core/generator.h" +#include "core/document.h" +#include "core/link.h" + +class Dict; +class GfxFont; +class LinkDest; +class Ref; +class PDFDoc; +class GList; +class TextPage; + +class ObjectRect; +class KPDFOutputDev; +class PDFPixmapGeneratorThread; + +/** + * @short A generator that builds contents from a PDF document. + * + * All Generator features are supported and implented by this one. + * Internally this holds a reference to xpdf's core objects and provides + * contents generation using the PDFDoc object and a couple of OutputDevices + * called KPDFOutputDev and KPDFTextDev (both defined in gp_outputdev.h). + * + * For generating page contents we tell PDFDoc to render a page and grab + * contents from out OutputDevs when rendering finishes. + * + * Background asyncronous contents providing is done via a QThread inherited + * class defined at the bottom of the file. + */ +class PDFGenerator : public Generator +{ + public: + PDFGenerator( KPDFDocument * document ); + virtual ~PDFGenerator(); + + // [INHERITED] load a document and fill up the pagesVector + bool loadDocument( const QString & fileName, QValueVector & pagesVector ); + + // [INHERITED] document informations + const DocumentInfo * generateDocumentInfo(); + const DocumentSynopsis * generateDocumentSynopsis(); + + // [INHERITED] document informations + bool isAllowed( int permissions ); + + // [INHERITED] perform actions on document / pages + bool canGeneratePixmap(); + void generatePixmap( PixmapRequest * request ); + void generateSyncTextPage( KPDFPage * page ); + + // [INHERITED] capability querying + bool supportsSearching() const; + bool hasFonts() const; + + // [INHERITED] font related + void putFontInfo(KListView *list); + + // [INHERITED] print page using an already configured kprinter + bool print( KPrinter& printer ); + + // [INHERITED] reply to some metadata requests + QString getMetaData( const QString & key, const QString & option ); + + // [INHERITED] reparse configuration + bool reparseConfig(); + + private: + // friend class to access private document related variables + friend class PDFPixmapGeneratorThread; + + void scanFonts(Dict *resDict, KListView *list, Ref **fonts, int &fontsLen, int &fontsSize, QValueVector *visitedXObjects); + void scanFont(GfxFont *font, KListView *list, Ref **fonts, int &fontsLen, int &fontsSize); + + void fillViewportFromLink( DocumentViewport &viewport, LinkDest *destination ); + + // private functions for accessing document informations via PDFDoc + QString getDocumentInfo( const QString & data, bool canReturnNull = false ) const; + QString getDocumentDate( const QString & data ) const; + // private function for creating the document synopsis hieracy + void addSynopsisChildren( QDomNode * parent, GList * items ); + // private function for creating the transition information + void addTransition( int pageNumber, KPDFPage * page ); + // (async related) receive data from the generator thread + void customEvent( QCustomEvent * ); + + // xpdf dependant stuff + QMutex docLock; + PDFDoc * pdfdoc; + KPDFOutputDev * kpdfOutputDev; + QColor paperColor; + + // asyncronous generation related stuff + PDFPixmapGeneratorThread * generatorThread; + + // misc variables for document info and synopsis caching + bool ready; + PixmapRequest * pixmapRequest; + bool docInfoDirty; + DocumentInfo docInfo; + bool docSynopsisDirty; + DocumentSynopsis docSyn; +}; + + +/** + * @short A thread that builds contents for PDFGenerator in the background. + * + */ +class PDFPixmapGeneratorThread : public QThread +{ + public: + PDFPixmapGeneratorThread( PDFGenerator * generator ); + ~PDFPixmapGeneratorThread(); + + // set the request to the thread (it will be reparented) + void startGeneration( PixmapRequest * request ); + // end generation + void endGeneration(); + + // methods for getting contents from the GUI thread + QImage * takeImage() const; + TextPage * takeTextPage() const; + QValueList< ObjectRect * > takeObjectRects() const; + + private: + // can't be called from the outside (but from startGeneration) + void run(); + + class PPGThreadPrivate * d; +}; + +#endif diff --git a/kpdf/core/generator_pdf/gp_outputdev.cpp b/kpdf/core/generator_pdf/gp_outputdev.cpp new file mode 100644 index 00000000..c55ccd7c --- /dev/null +++ b/kpdf/core/generator_pdf/gp_outputdev.cpp @@ -0,0 +1,397 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by Christophe Devriese * + * * + * Copyright (C) 2003 by Andy Goossens * + * Copyright (C) 2003 by Scott Wheeler * + * Copyright (C) 2003 by Ingo Klöcker * + * Copyright (C) 2003 by Will Andrews * + * Copyright (C) 2004 by Dominique Devriese * + * Copyright (C) 2004 by Waldo Bastian * + * Copyright (C) 2004 by Albert Astals Cid * + * * + * 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. * + ***************************************************************************/ + +#ifdef __GNUC__ +#pragma implementation +#endif + +#include +#include +#include + +#include "gp_outputdev.h" +#include "generator_pdf.h" +#include "core/document.h" // for DocumentViewport +#include "core/page.h" +#include "core/link.h" +#include "xpdf/Link.h" +#include "xpdf/GfxState.h" +#include "xpdf/TextOutputDev.h" +#include "splash/SplashBitmap.h" + +//NOTE: XPDF/Splash *implementation dependant* code is marked with '###' + +/** KPDFOutputDev implementation **/ + +KPDFOutputDev::KPDFOutputDev( SplashColor paperColor ) + : SplashOutputDev( splashModeRGB8, 4, false, paperColor ), + m_doc( 0 ), m_pixmap( 0 ), m_image( 0 ) +{ +} + +KPDFOutputDev::~KPDFOutputDev() +{ + clear(); +} + +void KPDFOutputDev::initDevice( PDFDoc * pdfDoc ) +{ + m_doc = pdfDoc; + startDoc( pdfDoc->getXRef() ); +} + +void KPDFOutputDev::setParams( int width, int height, bool genL, bool genI, bool safe ) +{ + clear(); + + m_pixmapWidth = width; + m_pixmapHeight = height; + + m_qtThreadSafety = safe; + m_generateLinks = genL; + m_generateImages = genI; +} + +QPixmap * KPDFOutputDev::takePixmap() +{ + QPixmap * pix = m_pixmap; + m_pixmap = 0; + return pix; +} + +QImage * KPDFOutputDev::takeImage() +{ + QImage * img = m_image; + m_image = 0; + return img; +} + +QValueList< ObjectRect * > KPDFOutputDev::takeObjectRects() +{ + if ( m_rects.isEmpty() ) + return m_rects; + QValueList< ObjectRect * > rectsCopy( m_rects ); + m_rects.clear(); + return rectsCopy; +} + +//BEGIN - OutputDev hooked calls +void KPDFOutputDev::endPage() +{ + SplashOutputDev::endPage(); + + int bh = getBitmap()->getHeight(), + bw = getBitmap()->getWidth(); + // TODO The below loop can be avoided if using the code that is commented here and + // we change splashModeRGB8 to splashModeARGB8 the problem is that then bug101800.pdf + // does not work +/* SplashColorPtr dataPtr = getBitmap()->getDataPtr(); + // construct a qimage SHARING the raw bitmap data in memory + QImage * img = new QImage( dataPtr, bw, bh, 32, 0, 0, QImage::IgnoreEndian );*/ + QImage * img = new QImage( bw, bh, 32 ); + SplashColorPtr pixel = new Guchar[4]; + for (int i = 0; i < bw; i++) + { + for (int j = 0; j < bh; j++) + { + getBitmap()->getPixel(i, j, pixel); + img->setPixel( i, j, qRgb( pixel[0], pixel[1], pixel[2] ) ); + } + } + delete [] pixel; + + // use the QImage or convert it immediately to QPixmap for better + // handling and memory unloading + if ( m_qtThreadSafety ) + { + delete m_image; + // it may happen (in fact it doesn't) that we need a rescaling + if ( bw != m_pixmapWidth && bh != m_pixmapHeight ) + m_image = new QImage( img->smoothScale( m_pixmapWidth, m_pixmapHeight ) ); + else + // dereference image from the xpdf memory + m_image = new QImage( img->copy() ); + } + else + { + delete m_pixmap; + // it may happen (in fact it doesn't) that we need a rescaling + if ( bw != m_pixmapWidth || bh != m_pixmapHeight ) + m_pixmap = new QPixmap( img->smoothScale( m_pixmapWidth, m_pixmapHeight ) ); + else + m_pixmap = new QPixmap( *img ); + } + + // destroy the shared descriptor and (###) unload underlying xpdf bitmap + delete img; + SplashOutputDev::startPage( 0, NULL ); +} + +void KPDFOutputDev::processLink( Link * link, Catalog * catalog ) +{ + if ( !link->isOk() ) + return; + + if ( m_generateLinks ) + { + // create the link descriptor + KPDFLink * l = generateLink( link->getAction() ); + if ( l ) + { + // create the page rect representing the link + double x1, y1, x2, y2; + link->getRect( &x1, &y1, &x2, &y2 ); + int left, top, right, bottom; + cvtUserToDev( x1, y1, &left, &top ); + cvtUserToDev( x2, y2, &right, &bottom ); + double nl = (double)left / (double)m_pixmapWidth, + nt = (double)top / (double)m_pixmapHeight, + nr = (double)right / (double)m_pixmapWidth, + nb = (double)bottom / (double)m_pixmapHeight; + // create the rect using normalized coords and attach the KPDFLink to it + ObjectRect * rect = new ObjectRect( nl, nt, nr, nb, ObjectRect::Link, l ); + // add the ObjectRect to the vector container + m_rects.push_front( rect ); + } + } + SplashOutputDev::processLink( link, catalog ); +} + +void KPDFOutputDev::drawImage( GfxState *state, Object *ref, Stream *str, + int _width, int _height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg ) +{ + if ( m_generateImages ) + { + // find out image rect from the Coord Transform Matrix + double * ctm = state->getCTM(); + int left = (int)ctm[4], + top = (int)ctm[5], + width = (int)ctm[0], + height = (int)ctm[3]; + // normalize width + if ( width < 0 ) + { + width = -width; + left -= width; + } + // normalize height + if ( height < 0 ) + { + height = -height; + top -= height; + } + if ( width > 10 && height > 10 ) + { + // build a descriptor for the image rect + double nl = (double)left / (double)m_pixmapWidth, + nt = (double)top / (double)m_pixmapHeight, + nr = (double)(left + width) / (double)m_pixmapWidth, + nb = (double)(top + height) / (double)m_pixmapHeight; + // create the rect using normalized coords and set it of KPDFImage type + ObjectRect * rect = new ObjectRect( nl, nt, nr, nb, ObjectRect::Image, 0 ); + // add the ObjectRect to the vector container + m_rects.push_back( rect ); + } + } + SplashOutputDev::drawImage( state, ref, str, _width, _height, colorMap, maskColors, inlineImg ); +} +//END - OutputDev hooked calls + +//BEGIN - private helpers +void KPDFOutputDev::clear() +{ + // delete rects + if ( m_rects.count() ) + { + QValueList< ObjectRect * >::iterator it = m_rects.begin(), end = m_rects.end(); + for ( ; it != end; ++it ) + delete *it; + m_rects.clear(); + } + // delete pixmap + if ( m_pixmap ) + { + delete m_pixmap; + m_pixmap = 0; + } + // delete image + if ( m_image ) + { + delete m_image; + m_image = 0; + } +} + +KPDFLink * KPDFOutputDev::generateLink( LinkAction * a ) +// note: this function is called when processing a page, when the MUTEX is already LOCKED +{ + KPDFLink * link = NULL; + if ( a ) switch ( a->getKind() ) + { + case actionGoTo: + { + LinkGoTo * g = (LinkGoTo *) a; + // ceate link: no ext file, namedDest, object pointer + link = new KPDFLinkGoto( QString::null, decodeViewport( g->getNamedDest(), g->getDest() ) ); + } + break; + + case actionGoToR: + { + LinkGoToR * g = (LinkGoToR *) a; + // copy link file + const char * fileName = g->getFileName()->getCString(); + // ceate link: fileName, namedDest, object pointer + link = new KPDFLinkGoto( (QString)fileName, decodeViewport( g->getNamedDest(), g->getDest() ) ); + } + break; + + case actionLaunch: + { + LinkLaunch * e = (LinkLaunch *)a; + GString * p = e->getParams(); + link = new KPDFLinkExecute( e->getFileName()->getCString(), p ? p->getCString() : 0 ); + } + break; + + case actionNamed: + { + const char * name = ((LinkNamed *)a)->getName()->getCString(); + if ( !strcmp( name, "NextPage" ) ) + link = new KPDFLinkAction( KPDFLinkAction::PageNext ); + else if ( !strcmp( name, "PrevPage" ) ) + link = new KPDFLinkAction( KPDFLinkAction::PagePrev ); + else if ( !strcmp( name, "FirstPage" ) ) + link = new KPDFLinkAction( KPDFLinkAction::PageFirst ); + else if ( !strcmp( name, "LastPage" ) ) + link = new KPDFLinkAction( KPDFLinkAction::PageLast ); + else if ( !strcmp( name, "GoBack" ) ) + link = new KPDFLinkAction( KPDFLinkAction::HistoryBack ); + else if ( !strcmp( name, "GoForward" ) ) + link = new KPDFLinkAction( KPDFLinkAction::HistoryForward ); + else if ( !strcmp( name, "Quit" ) ) + link = new KPDFLinkAction( KPDFLinkAction::Quit ); + else if ( !strcmp( name, "GoToPage" ) ) + link = new KPDFLinkAction( KPDFLinkAction::GoToPage ); + else if ( !strcmp( name, "Find" ) ) + link = new KPDFLinkAction( KPDFLinkAction::Find ); + else if ( !strcmp( name, "Close" ) ) + link = new KPDFLinkAction( KPDFLinkAction::Close ); + else + kdDebug() << "Unknown named action: '" << name << "'" << endl; + } + break; + + case actionURI: + link = new KPDFLinkBrowse( ((LinkURI *)a)->getURI()->getCString() ); + break; + + case actionMovie: +/* { TODO this (Movie link) + m_type = Movie; + LinkMovie * m = (LinkMovie *) a; + // copy Movie parameters (2 IDs and a const char *) + Ref * r = m->getAnnotRef(); + m_refNum = r->num; + m_refGen = r->gen; + copyString( m_uri, m->getTitle()->getCString() ); + } +*/ break; + + case actionUnknown: + kdDebug() << "Unknown link." << endl; + break; + } + + // link may be zero at that point + return link; +} + +DocumentViewport KPDFOutputDev::decodeViewport( GString * namedDest, LinkDest * dest ) +// note: this function is called when processing a page, when the MUTEX is already LOCKED +{ + DocumentViewport vp( -1 ); + bool deleteDest = false; + + if ( namedDest && !dest ) + { + deleteDest = true; + dest = m_doc->findDest( namedDest ); + } + + if ( !dest || !dest->isOk() ) + { + if (deleteDest) delete dest; + return vp; + } + + // get destination page number + if ( !dest->isPageRef() ) + vp.pageNumber = dest->getPageNum() - 1; + else + { + Ref ref = dest->getPageRef(); + vp.pageNumber = m_doc->findPage( ref.num, ref.gen ) - 1; + } + + // get destination position + // TODO add other attributes to the viewport (taken from link) + switch ( dest->getKind() ) + { + case destXYZ: + if (dest->getChangeLeft() || dest->getChangeTop()) + { + int left, top; + cvtUserToDev( dest->getLeft(), dest->getTop(), &left, &top ); + vp.rePos.normalizedX = (double)left / (double)m_pixmapWidth; + vp.rePos.normalizedY = (double)top / (double)m_pixmapHeight; + vp.rePos.enabled = true; + vp.rePos.pos = DocumentViewport::TopLeft; + } + /* TODO + if ( dest->getChangeZoom() ) + make zoom change*/ + break; + + case destFit: + case destFitB: + //vp.fitWidth = true; + //vp.fitHeight = true; + break; + + case destFitH: + case destFitBH: +// read top, fit Width + //vp.fitWidth = true; + break; + + case destFitV: + case destFitBV: +// read left, fit Height + //vp.fitHeight = true; + break; + + case destFitR: +// read and fit left,bottom,right,top + break; + } + + if (deleteDest) delete dest; + return vp; +} +//END - private helpers + diff --git a/kpdf/core/generator_pdf/gp_outputdev.h b/kpdf/core/generator_pdf/gp_outputdev.h new file mode 100644 index 00000000..e08724e0 --- /dev/null +++ b/kpdf/core/generator_pdf/gp_outputdev.h @@ -0,0 +1,90 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by Christophe Devriese * + * * + * Copyright (C) 2003 by Helio Chissini de Castro * + * * + * Copyright (C) 2004 by Dominique Devriese * + * Copyright (C) 2004 by Albert Astals Cid * + * * + * 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. * + ***************************************************************************/ + +#ifndef KPDFOUTPUTDEV_H +#define KPDFOUTPUTDEV_H + +#ifdef __GNUC__ +#pragma interface +#endif + +#include +#include "xpdf/PDFDoc.h" // for 'Object' +#include "xpdf/SplashOutputDev.h" + +class QPixmap; +class KPDFLink; +class ObjectRect; +class DocumentViewport; + +/** + * @short A SplashOutputDev renderer that grabs text and links. + * + * This output device: + * - renders the page using SplashOutputDev (its parent) + * - harvests text into a textPage (for searching text) + * - harvests links and collects them + * - collects images and collects them + */ +class KPDFOutputDev : public SplashOutputDev +{ + public: + KPDFOutputDev( SplashColor paperColor ); + virtual ~KPDFOutputDev(); + + // initialize device -> attach device to PDFDoc + void initDevice( class PDFDoc * pdfDoc ); + + // set parameters before rendering *each* page + // @param qtThreadSafety: duplicate memory buffer (slow but safe) + void setParams( int pixmapWidth, int pixmapHeight, + bool decodeLinks, bool decodeImages, bool qtThreadSafety = false ); + + // takes pointers out of the class (so deletion it's up to others) + QPixmap * takePixmap(); + QImage * takeImage(); + QValueList< ObjectRect * > takeObjectRects(); + + /** inherited from OutputDev */ + // End a page. + virtual void endPage(); + //----- link borders + virtual void processLink(Link *link, Catalog *catalog); + //----- image drawing + virtual void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, + GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg); + + private: + // delete all interal objects and data + void clear(); + // generate a valid KPDFLink subclass (or null) from a xpdf's LinkAction + KPDFLink * generateLink( LinkAction * a ); + // fills up a Viewport structure out of a given LinkGoto link + DocumentViewport decodeViewport( GString *, class LinkDest * ); + + // generator switches and parameters + bool m_qtThreadSafety; + bool m_generateLinks; + bool m_generateImages; + int m_pixmapWidth; + int m_pixmapHeight; + + // Internal objects + PDFDoc * m_doc; + QPixmap * m_pixmap; + QImage * m_image; + QValueList< ObjectRect * > m_rects; // objectRects (links/images) +}; + +#endif diff --git a/kpdf/core/link.cpp b/kpdf/core/link.cpp new file mode 100644 index 00000000..d8e47a49 --- /dev/null +++ b/kpdf/core/link.cpp @@ -0,0 +1,65 @@ +/*************************************************************************** + * Copyright (C) 2004 by Enrico Ros * + * * + * 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. * + ***************************************************************************/ + +// local includes +#include "link.h" + +#include + +KPDFLink::~KPDFLink() +{ +} + +QString KPDFLinkGoto::linkTip() const +{ + return m_extFileName.isEmpty() ? ( m_vp.pageNumber != -1 ? i18n( "Go to page %1" ).arg( m_vp.pageNumber + 1 ) : QString::null ) : i18n("Open external file"); +} + +QString KPDFLinkExecute::linkTip() const +{ + return i18n( "Execute '%1'..." ).arg( m_fileName ); +} + +QString KPDFLinkBrowse::linkTip() const +{ + return m_url; +} + +QString KPDFLinkAction::linkTip() const +{ + switch ( m_type ) + { + case PageFirst: + return i18n( "First Page" ); + case PagePrev: + return i18n( "Previous Page" ); + case PageNext: + return i18n( "Next Page" ); + case PageLast: + return i18n( "Last Page" ); + case HistoryBack: + return i18n( "Back" ); + case HistoryForward: + return i18n( "Forward" ); + case Quit: + return i18n( "Quit" ); + case Presentation: + return i18n( "Start Presentation" ); + case EndPresentation: + return i18n( "End Presentation" ); + case Find: + return i18n( "Find..." ); + case GoToPage: + return i18n( "Go To Page..." ); + case Close: + default: ; + } + + return QString::null; +} diff --git a/kpdf/core/link.h b/kpdf/core/link.h new file mode 100644 index 00000000..10420c50 --- /dev/null +++ b/kpdf/core/link.h @@ -0,0 +1,118 @@ +/*************************************************************************** + * Copyright (C) 2004 by Enrico Ros * + * * + * 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. * + ***************************************************************************/ + +#ifndef _KPDF_LINK_H_ +#define _KPDF_LINK_H_ + +#include +#include +#include "core/document.h" // for DocumentViewport + +/** + * @short Encapsulates data that describes a link. + * + * This is the base class for links. It makes mandatory for inherited + * widgets to reimplement the 'linkType' method and return the type of + * the link described by the reimplemented class. + */ +class KPDFLink +{ + public: + // get link type (inherited classes mustreturn an unique identifier) + enum LinkType { Goto, Execute, Browse, Action, Movie }; + virtual LinkType linkType() const = 0; + virtual QString linkTip() const { return QString::null; } + + // virtual destructor (remove warnings) + virtual ~KPDFLink(); +}; + + +/** Goto: a viewport and maybe a reference to an external filename **/ +class KPDFLinkGoto : public KPDFLink +{ + public: + // query for goto parameters + bool isExternal() const { return !m_extFileName.isEmpty(); } + const QString & fileName() const { return m_extFileName; } + const DocumentViewport & destViewport() const { return m_vp; } + + // create a KPDFLink_Goto + KPDFLinkGoto( QString extFileName, const DocumentViewport & vp ) { m_extFileName = extFileName; m_vp = vp; } + LinkType linkType() const { return Goto; } + QString linkTip() const; + + private: + QString m_extFileName; + DocumentViewport m_vp; +}; + +/** Execute: filename and parameters to execute **/ +class KPDFLinkExecute : public KPDFLink +{ + public: + // query for filename / parameters + const QString & fileName() const { return m_fileName; } + const QString & parameters() const { return m_parameters; } + + // create a KPDFLink_Execute + KPDFLinkExecute( const QString & file, const QString & params ) { m_fileName = file; m_parameters = params; } + LinkType linkType() const { return Execute; } + QString linkTip() const; + + private: + QString m_fileName; + QString m_parameters; +}; + +/** Browse: an URL to open, ranging from 'http://' to 'mailto:' etc.. **/ +class KPDFLinkBrowse : public KPDFLink +{ + public: + // query for URL + const QString & url() const { return m_url; } + + // create a KPDFLink_Browse + KPDFLinkBrowse( const QString &url ) { m_url = url; } + LinkType linkType() const { return Browse; } + QString linkTip() const; + + private: + QString m_url; +}; + +/** Action: contains an action to perform on document / kpdf **/ +class KPDFLinkAction : public KPDFLink +{ + public: + // define types of actions + enum ActionType { PageFirst, PagePrev, PageNext, PageLast, HistoryBack, HistoryForward, Quit, Presentation, EndPresentation, Find, GoToPage, Close }; + + // query for action type + ActionType actionType() const { return m_type; } + + // create a KPDFLink_Action + KPDFLinkAction( enum ActionType actionType ) { m_type = actionType; } + LinkType linkType() const { return Action; } + QString linkTip() const; + + private: + ActionType m_type; +}; + +/** Movie: Not yet defined -> think renaming to 'Media' link **/ +class KPDFLinkMovie : public KPDFLink +// TODO this (Movie link) +{ + public: + KPDFLinkMovie() {}; + LinkType linkType() const { return Movie; } +}; + +#endif diff --git a/kpdf/core/observer.h b/kpdf/core/observer.h new file mode 100644 index 00000000..28f07bf5 --- /dev/null +++ b/kpdf/core/observer.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (C) 2005 by Enrico Ros * + * Copyright (C) 2005 by Albert Astals Cid * + * * + * 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. * + ***************************************************************************/ + +#ifndef _KPDF_DOCUMENTOBSERVER_H_ +#define _KPDF_DOCUMENTOBSERVER_H_ + +#include +#include + +/** IDs for observers. Globally defined here. **/ +#define PRESENTATION_ID 1 +#define PART_ID 2 +#define PAGEVIEW_ID 3 +#define THUMBNAILS_ID 4 +#define TOC_ID 5 +#define MINIBAR_ID 6 + +/** PRIORITIES for requests. Globally defined here. **/ +#define PAGEVIEW_PRIO 1 +#define PAGEVIEW_PRELOAD_PRIO 4 +#define THUMBNAILS_PRIO 2 +#define THUMBNAILS_PRELOAD_PRIO 5 +#define PRESENTATION_PRIO 0 +#define PRESENTATION_PRELOAD_PRIO 3 + +class KPDFPage; + +/** + * @short Base class for objects being notified when something changes. + * + * Inherit this class and call KPDFDocument->addObserver( yourClass ) to get + * notified of asyncronous events (new pixmap generated, or changed, etc..). + */ +class DocumentObserver +{ + public: + // you must give each observer a unique ID (used for notifications) + virtual uint observerId() const = 0; + + // commands from the Document to all observers + enum ChangedFlags { Pixmap = 1, Bookmark = 2, Highlights = 4 }; + virtual void notifySetup( const QValueVector< KPDFPage * > & /*pages*/, bool /*documentChanged*/ ) {}; + virtual void notifyViewportChanged( bool /*smoothMove*/ ) {}; + virtual void notifyPageChanged( int /*pageNumber*/, int /*changedFlags*/ ) {}; + virtual void notifyContentsCleared( int /*changedFlags*/ ) {}; + + // queries to observers + virtual bool canUnloadPixmap( int /*pageNum*/ ) { return true; } +}; + +#endif diff --git a/kpdf/core/page.cpp b/kpdf/core/page.cpp new file mode 100644 index 00000000..e6a847a8 --- /dev/null +++ b/kpdf/core/page.cpp @@ -0,0 +1,327 @@ +/*************************************************************************** + * Copyright (C) 2004 by Enrico Ros * + * * + * 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. * + ***************************************************************************/ + +// qt/kde includes +#include +#include +#include +#include + +// local includes +#include "page.h" +#include "pagetransition.h" +#include "link.h" +#include "conf/settings.h" +#include "xpdf/TextOutputDev.h" + + +/** class KPDFPage **/ + +KPDFPage::KPDFPage( uint page, float w, float h, int r ) + : m_number( page ), m_rotation( r ), m_width( w ), m_height( h ), + m_bookmarked( false ), m_text( 0 ), m_transition( 0 ) +{ + // if landscape swap width <-> height (rotate 90deg CCW) + if ( r == 90 || r == 270 ) + { + m_width = h; + m_height = w; + } + // avoid Division-By-Zero problems in the program + if ( m_width <= 0 ) + m_width = 1; + if ( m_height <= 0 ) + m_height = 1; +} + +KPDFPage::~KPDFPage() +{ + deletePixmapsAndRects(); + deleteHighlights(); + delete m_text; + delete m_transition; +} + + +bool KPDFPage::hasPixmap( int id, int width, int height ) const +{ + if ( !m_pixmaps.contains( id ) ) + return false; + if ( width == -1 || height == -1 ) + return true; + QPixmap * p = m_pixmaps[ id ]; + return p ? ( p->width() == width && p->height() == height ) : false; +} + +bool KPDFPage::hasSearchPage() const +{ + return m_text != 0; +} + +bool KPDFPage::hasBookmark() const +{ + return m_bookmarked; +} + +bool KPDFPage::hasObjectRect( double x, double y ) const +{ + if ( m_rects.count() < 1 ) + return false; + QValueList< ObjectRect * >::const_iterator it = m_rects.begin(), end = m_rects.end(); + for ( ; it != end; ++it ) + if ( (*it)->contains( x, y ) ) + return true; + return false; +} + +bool KPDFPage::hasHighlights( int s_id ) const +{ + // simple case: have no highlights + if ( m_highlights.isEmpty() ) + return false; + // simple case: we have highlights and no id to match + if ( s_id == -1 ) + return true; + // iterate on the highlights list to find an entry by id + QValueList< HighlightRect * >::const_iterator it = m_highlights.begin(), end = m_highlights.end(); + for ( ; it != end; ++it ) + if ( (*it)->s_id == s_id ) + return true; + return false; +} + +bool KPDFPage::hasTransition() const +{ + return m_transition != 0; +} + + +NormalizedRect * KPDFPage::findText( const QString & text, bool strictCase, NormalizedRect * lastRect ) const +{ + if ( text.isEmpty() ) + return 0; + + // create a xpf's Unicode (unsigned int) array for the given text + const QChar * str = text.unicode(); + int len = text.length(); + QMemArray u(len); + for (int i = 0; i < len; ++i) + u[i] = str[i].unicode(); + + // find out the direction of search + enum SearchDir { FromTop, NextMatch, PrevMatch } dir = lastRect ? NextMatch : FromTop; + double sLeft, sTop, sRight, sBottom; + if ( dir == NextMatch ) + { + sLeft = lastRect->left * m_width; + sTop = lastRect->top * m_height; + sRight = lastRect->right * m_width; + sBottom = lastRect->bottom * m_height; + } + + // this loop is only for 'bad case' matches + bool found = false; + while ( !found ) + { + if ( dir == FromTop ) + found = m_text->findText( const_cast(static_cast(u)), len, gTrue, gTrue, gFalse, gFalse, strictCase, gFalse, &sLeft, &sTop, &sRight, &sBottom ); + else if ( dir == NextMatch ) + found = m_text->findText( const_cast(static_cast(u)), len, gFalse, gTrue, gTrue, gFalse, strictCase, gFalse, &sLeft, &sTop, &sRight, &sBottom ); + else if ( dir == PrevMatch ) + // FIXME: this doesn't work as expected (luckily backward search isn't yet used) + // TODO: check if the new xpdf 3.01 code is able of searching backwards + found = m_text->findText( const_cast(static_cast(u)), len, gTrue, gFalse, gFalse, gTrue, strictCase, gTrue, &sLeft, &sTop, &sRight, &sBottom ); + + // if not found (even in case unsensitive search), terminate + if ( !found ) + break; + } + + // if the page was found, return a new normalizedRect + if ( found ) + return new NormalizedRect( sLeft / m_width, sTop / m_height, sRight / m_width, sBottom / m_height ); + return 0; +} + +const QString KPDFPage::getText( const NormalizedRect & rect ) const +{ + if ( !m_text ) + return QString::null; + int left = (int)( rect.left * m_width ), + top = (int)( rect.top * m_height ), + right = (int)( rect.right * m_width ), + bottom = (int)( rect.bottom * m_height ); + GString * text = m_text->getText( left, top, right, bottom ); + QString result = QString::fromUtf8( text->getCString() ); + delete text; + return result; +} + +const ObjectRect * KPDFPage::hasObject( ObjectRect::ObjectType type, double x, double y ) const +{ + QValueList< ObjectRect * >::const_iterator it = m_rects.begin(), end = m_rects.end(); + for ( ; it != end; ++it ) + if ( (*it)->contains( x, y ) ) + if ((*it)->objectType() == type) return *it; + return 0; +} + +const KPDFPageTransition * KPDFPage::getTransition() const +{ + return m_transition; +} + + +void KPDFPage::setPixmap( int id, QPixmap * pixmap ) +{ + if ( m_pixmaps.contains( id ) ) + delete m_pixmaps[id]; + m_pixmaps[id] = pixmap; +} + +void KPDFPage::setSearchPage( TextPage * tp ) +{ + delete m_text; + m_text = tp; +} + +void KPDFPage::setBookmark( bool state ) +{ + m_bookmarked = state; +} + +void KPDFPage::setObjectRects( const QValueList< ObjectRect * > rects ) +{ + QValueList< ObjectRect * >::iterator it = m_rects.begin(), end = m_rects.end(); + for ( ; it != end; ++it ) + delete *it; + m_rects = rects; +} + +void KPDFPage::setHighlight( int s_id, NormalizedRect * &rect, const QColor & color ) +{ + // create a HighlightRect descriptor taking values from params + HighlightRect * hr = new HighlightRect(); + hr->s_id = s_id; + hr->color = color; + hr->left = rect->left; + hr->top = rect->top; + hr->right = rect->right; + hr->bottom = rect->bottom; + // append the HighlightRect to the list + m_highlights.append( hr ); + // delete old object and change reference + delete rect; + rect = hr; +} + +void KPDFPage::setTransition( KPDFPageTransition * transition ) +{ + delete m_transition; + m_transition = transition; +} + +void KPDFPage::deletePixmap( int id ) +{ + if ( m_pixmaps.contains( id ) ) + { + delete m_pixmaps[ id ]; + m_pixmaps.remove( id ); + } +} + +void KPDFPage::deletePixmapsAndRects() +{ + // delete all stored pixmaps + QMap::iterator it = m_pixmaps.begin(), end = m_pixmaps.end(); + for ( ; it != end; ++it ) + delete *it; + m_pixmaps.clear(); + // delete ObjectRects + QValueList< ObjectRect * >::iterator rIt = m_rects.begin(), rEnd = m_rects.end(); + for ( ; rIt != rEnd; ++rIt ) + delete *rIt; + m_rects.clear(); +} + +void KPDFPage::deleteHighlights( int s_id ) +{ + // delete highlights by ID + QValueList< HighlightRect * >::iterator it = m_highlights.begin(), end = m_highlights.end(); + while ( it != end ) + { + HighlightRect * highlight = *it; + if ( s_id == -1 || highlight->s_id == s_id ) + { + it = m_highlights.remove( it ); + delete highlight; + } + else + ++it; + } +} + + +/** class NormalizedRect **/ + +NormalizedRect::NormalizedRect() + : left( 0.0 ), top( 0.0 ), right( 0.0 ), bottom( 0.0 ) {} + +NormalizedRect::NormalizedRect( double l, double t, double r, double b ) + // note: check for swapping coords? + : left( l ), top( t ), right( r ), bottom( b ) {} + +NormalizedRect::NormalizedRect( const QRect & r, double xScale, double yScale ) + : left( (double)r.left() / xScale ), top( (double)r.top() / yScale ), + right( (double)r.right() / xScale ), bottom( (double)r.bottom() / yScale ) {} + +bool NormalizedRect::contains( double x, double y ) const +{ + return x >= left && x <= right && y >= top && y <= bottom; +} + +bool NormalizedRect::intersects( const NormalizedRect & r ) const +{ + return (r.left < right) && (r.right > left) && (r.top < bottom) && (r.bottom > top); +} + +bool NormalizedRect::intersects( double l, double t, double r, double b ) const +{ + return (l < right) && (r > left) && (t < bottom) && (b > top); +} + +QRect NormalizedRect::geometry( int xScale, int yScale ) const +{ + int l = (int)( left * xScale ), + t = (int)( top * yScale ), + r = (int)( right * xScale ), + b = (int)( bottom * yScale ); + return QRect( l, t, r - l + 1, b - t + 1 ); +} + + +/** class ObjectRect **/ + +ObjectRect::ObjectRect( double l, double t, double r, double b, ObjectType type, void * pnt ) + // assign coordinates swapping them if negative width or height + : NormalizedRect( r > l ? l : r, b > t ? t : b, r > l ? r : l, b > t ? b : t ), + m_objectType( type ), m_pointer( pnt ) +{ +} + +ObjectRect::~ObjectRect() +{ + if ( !m_pointer ) + return; + + if ( m_objectType == Link ) + delete static_cast( m_pointer ); + else + kdDebug() << "Object deletion not implemented for type '" << m_objectType << "' ." << endl; +} diff --git a/kpdf/core/page.h b/kpdf/core/page.h new file mode 100644 index 00000000..ebd6e522 --- /dev/null +++ b/kpdf/core/page.h @@ -0,0 +1,149 @@ +/*************************************************************************** + * Copyright (C) 2004 by Enrico Ros * + * * + * 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. * + ***************************************************************************/ + +#ifndef _KPDF_PAGE_H_ +#define _KPDF_PAGE_H_ + +#include +#include + +class QPixmap; +class QRect; +class TextPage; +class KPDFPageTransition; +class HighlightRect; +class Annotation; + +/** + * @short A rect in normalized [0,1] coordinates. + */ +class NormalizedRect +{ + public: + double left, top, right, bottom; + + NormalizedRect(); + NormalizedRect( double l, double t, double r, double b ); + NormalizedRect( const QRect & r, double xScale, double yScale ); + + bool contains( double x, double y ) const; + bool intersects( const NormalizedRect & normRect ) const; + bool intersects( double l, double t, double r, double b ) const; + + QRect geometry( int xScale, int yScale ) const; +}; + +/** + * @short NormalizedRect that contains a reference to an object. + * + * These rects contains a pointer to a kpdf object (such as a link or something + * like that). The pointer is read and stored as 'void pointer' so cast is + * performed by accessors based on the value returned by objectType(). Objects + * are reparented to this class. + * + * Type / Class correspondency tab: + * - Link : class KPDFLink : description of a link + * - Image : class KPDFImage : description of an image (n/a) + */ +class ObjectRect : public NormalizedRect +{ + public: + // definition of the types of storable objects + enum ObjectType { Link, Image }; + + // default constructor: initialize all parameters + ObjectRect( double l, double t, double r, double b, ObjectType typ, void * obj ); + ~ObjectRect(); + + // query type and get a const pointer to the stored object + inline ObjectType objectType() const { return m_objectType; } + inline const void * pointer() const { return m_pointer; } + + private: + ObjectType m_objectType; + void * m_pointer; +}; + +/** + * @short Collector for all the data belonging to a page. + * + * The KPDFPage class contains pixmaps (referenced using observers id as key), + * a search page (a class used internally for retrieving text), rect classes + * (that describe links or other active areas in the current page) and more. + * + * All coordinates are normalized to the page, so {x,y} are valid in [0,1] + * range as long as NormalizedRect components. + * + * Note: The class takes ownership of all objects. + */ +class KPDFPage +{ + public: + KPDFPage( uint number, float width, float height, int rotation ); + ~KPDFPage(); + + // query properties (const read-only methods) + inline int number() const { return m_number; } + inline int rotation() const { return m_rotation; } + inline float width() const { return m_width; } + inline float height() const { return m_height; } + inline float ratio() const { return m_height / m_width; } + bool hasPixmap( int p_id, int width = -1, int height = -1 ) const; + bool hasSearchPage() const; + bool hasBookmark() const; + bool hasObjectRect( double x, double y ) const; + bool hasHighlights( int s_id = -1 ) const; + //bool hasAnnotation( double x, double y ) const; + bool hasTransition() const; + + NormalizedRect * findText( const QString & text, bool keepCase, NormalizedRect * last = 0 ) const; + const QString getText( const NormalizedRect & rect ) const; + const ObjectRect * hasObject( ObjectRect::ObjectType type, double x, double y ) const; + //const Annotation * getAnnotation( double x, double y ) const; + const KPDFPageTransition * getTransition() const; + + // operations: set/delete contents (by KPDFDocument) + void setPixmap( int p_id, QPixmap * pixmap ); + void setSearchPage( TextPage * text ); + void setBookmark( bool state ); + void setObjectRects( const QValueList< ObjectRect * > rects ); + void setHighlight( int s_id, NormalizedRect * &r, const QColor & color ); + //void setAnnotation( Annotation * annotation ); + void setTransition( KPDFPageTransition * transition ); + void deletePixmap( int p_id ); + void deletePixmapsAndRects(); + void deleteHighlights( int s_id = -1 ); + + private: + friend class PagePainter; + int m_number, m_rotation; + float m_width, m_height; + bool m_bookmarked; + + QMap< int, QPixmap * > m_pixmaps; + TextPage * m_text; + QValueList< ObjectRect * > m_rects; + QValueList< HighlightRect * > m_highlights; + //QValueList< Annotation * > m_annotations; + KPDFPageTransition * m_transition; +}; + + +/** + * Internal Storage: normalized colored highlight owned by id + */ +struct HighlightRect : public NormalizedRect +{ + // searchID of the highlight owner + int s_id; + // color of the highlight + QColor color; +}; + +#endif diff --git a/kpdf/core/pagetransition.cpp b/kpdf/core/pagetransition.cpp new file mode 100644 index 00000000..cdf04a7f --- /dev/null +++ b/kpdf/core/pagetransition.cpp @@ -0,0 +1,28 @@ +/*************************************************************************** + * Copyright (C) 2005 by Tobias Koenig * + * * + * 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. * + ***************************************************************************/ + +// local includes +#include "pagetransition.h" + +/** class KPDFPageTransition **/ + +KPDFPageTransition::KPDFPageTransition( Type type ) + : m_type( type ), + m_duration( 1 ), + m_alignment( Horizontal ), + m_direction( Inward ), + m_angle( 0 ), + m_scale( 1.0 ), + m_rectangular( false ) +{ +} + +KPDFPageTransition::~KPDFPageTransition() +{ +} diff --git a/kpdf/core/pagetransition.h b/kpdf/core/pagetransition.h new file mode 100644 index 00000000..70792355 --- /dev/null +++ b/kpdf/core/pagetransition.h @@ -0,0 +1,86 @@ +/*************************************************************************** + * Copyright (C) 2005 by Tobias Koenig * + * * + * 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. * + ***************************************************************************/ + +#ifndef _KPDF_PAGE_TRANSITION_H_ +#define _KPDF_PAGE_TRANSITION_H_ + +/** + * @short Information object for the transition effect of a page. + */ +class KPDFPageTransition +{ + public: + enum Type { + Replace, + Split, + Blinds, + Box, + Wipe, + Dissolve, + Glitter, + Fly, + Push, + Cover, + Uncover, + Fade + }; + + enum Alignment { + Horizontal, + Vertical + }; + + enum Direction { + Inward, + Outward + }; + + KPDFPageTransition( Type type = Replace ); + ~KPDFPageTransition(); + + // Get type of the transition. + inline Type type() const { return m_type; } + + // Get duration of the transition in seconds. + inline int duration() const { return m_duration; } + + // Get dimension in which the transition effect occurs. + inline Alignment alignment() const { return m_alignment; } + + // Get direction of motion of the transition effect. + inline Direction direction() const { return m_direction; } + + // Get direction in which the transition effect moves. + inline int angle() const { return m_angle; } + + // Get starting or ending scale. (Fly only) + inline double scale() const { return m_scale; } + + // Returns true if the area to be flown is rectangular and opaque. (Fly only) + inline bool isRectangular() const { return m_rectangular; } + + inline void setType( Type type ) { m_type = type; } + inline void setDuration( int duration ) { m_duration = duration; } + inline void setAlignment( Alignment alignment ) { m_alignment = alignment; } + inline void setDirection( Direction direction ) { m_direction = direction; } + inline void setAngle( int angle ) { m_angle = angle; } + inline void setScale( double scale ) { m_scale = scale; } + inline void setIsRectangular( bool rectangular ) { m_rectangular = rectangular; } + + private: + Type m_type; + int m_duration; + Alignment m_alignment; + Direction m_direction; + int m_angle; + double m_scale; + bool m_rectangular; +}; + +#endif diff --git a/kpdf/dcop.h b/kpdf/dcop.h new file mode 100644 index 00000000..61a916d8 --- /dev/null +++ b/kpdf/dcop.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2004 by Albert Astals Cid * + * * + * 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. * + ***************************************************************************/ + +#ifndef MY_INTERFACE_H +#define MY_INTERFACE_H + +#include +#include + +class kpdf_dcop : virtual public DCOPObject +{ +K_DCOP + k_dcop: + virtual ASYNC goToPage(uint page) = 0; + virtual ASYNC openDocument(KURL doc) = 0; + virtual uint pages() = 0; + virtual uint currentPage() = 0; + virtual KURL currentDocument() = 0; + virtual void slotPreferences() = 0; + virtual void slotFind() = 0; + virtual void slotPrintPreview() = 0; + virtual void slotPreviousPage() = 0; + virtual void slotNextPage() = 0; + virtual void slotGotoFirst() = 0; + virtual void slotGotoLast() = 0; + virtual void slotTogglePresentation() = 0; +}; + +#endif diff --git a/kpdf/error.cpp b/kpdf/error.cpp new file mode 100644 index 00000000..028fe7e3 --- /dev/null +++ b/kpdf/error.cpp @@ -0,0 +1,44 @@ +/*************************************************************************** + * Copyright (C) 1996-2003 Glyph & Cog, LLC * + * Copyright (C) 2004 by Albert Astals Cid * + * * + * 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. * + ***************************************************************************/ + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include "xpdf/GlobalParams.h" +#include "xpdf/Error.h" + +#include + +#include + +void CDECL error(int pos, char *msg, ...) { + va_list args; + QString emsg, tmsg; + char buffer[1024]; // should be big enough + + // NB: this can be called before the globalParams object is created + if (globalParams && globalParams->getErrQuiet()) { + return; + } + if (pos >= 0) { + emsg = QString("Error (%1): ").arg(pos); + } else { + emsg = "Error: "; + } + va_start(args, msg); + vsprintf(buffer, msg, args); + va_end(args); + emsg += buffer; + kdDebug() << emsg << endl; +} diff --git a/kpdf/hi128-app-kpdf.png b/kpdf/hi128-app-kpdf.png new file mode 100644 index 00000000..c89f9472 Binary files /dev/null and b/kpdf/hi128-app-kpdf.png differ diff --git a/kpdf/hi16-app-kpdf.png b/kpdf/hi16-app-kpdf.png new file mode 100644 index 00000000..b4616cbd Binary files /dev/null and b/kpdf/hi16-app-kpdf.png differ diff --git a/kpdf/hi22-app-kpdf.png b/kpdf/hi22-app-kpdf.png new file mode 100644 index 00000000..12d9aaad Binary files /dev/null and b/kpdf/hi22-app-kpdf.png differ diff --git a/kpdf/hi32-app-kpdf.png b/kpdf/hi32-app-kpdf.png new file mode 100644 index 00000000..2f721dfb Binary files /dev/null and b/kpdf/hi32-app-kpdf.png differ diff --git a/kpdf/hi48-app-kpdf.png b/kpdf/hi48-app-kpdf.png new file mode 100644 index 00000000..086fad9c Binary files /dev/null and b/kpdf/hi48-app-kpdf.png differ diff --git a/kpdf/hi64-app-kpdf.png b/kpdf/hi64-app-kpdf.png new file mode 100644 index 00000000..46fac6ac Binary files /dev/null and b/kpdf/hi64-app-kpdf.png differ diff --git a/kpdf/hisc-app-kpdf.svgz b/kpdf/hisc-app-kpdf.svgz new file mode 100644 index 00000000..259103a2 Binary files /dev/null and b/kpdf/hisc-app-kpdf.svgz differ diff --git a/kpdf/kpdf_part.desktop b/kpdf/kpdf_part.desktop new file mode 100644 index 00000000..ec55d0dd --- /dev/null +++ b/kpdf/kpdf_part.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Icon=kpdf +Name=KPDF +Name[ar]=برنامج KPDF +Name[hi]=के-पीडीएफ +Name[zh_TW]=KPDF 檢視器 +MimeType=application/pdf +InitialPreference=7 +ServiceTypes=KParts/ReadOnlyPart +X-KDE-Library=libkpdfpart +Type=Service diff --git a/kpdf/part.cpp b/kpdf/part.cpp new file mode 100644 index 00000000..69ad7f00 --- /dev/null +++ b/kpdf/part.cpp @@ -0,0 +1,1100 @@ +/*************************************************************************** + * Copyright (C) 2002 by Wilco Greven * + * Copyright (C) 2002 by Chris Cheney * + * Copyright (C) 2002 by Malcolm Hunter * + * Copyright (C) 2003-2004 by Christophe Devriese * + * * + * Copyright (C) 2003 by Daniel Molkentin * + * Copyright (C) 2003 by Andy Goossens * + * Copyright (C) 2003 by Dirk Mueller * + * Copyright (C) 2003 by Laurent Montel * + * Copyright (C) 2004 by Dominique Devriese * + * Copyright (C) 2004 by Christoph Cullmann * + * Copyright (C) 2004 by Henrique Pinto * + * Copyright (C) 2004 by Waldo Bastian * + * Copyright (C) 2004-2006 by Albert Astals Cid * + * Copyright (C) 2004 by Antti Markus * + * * + * 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. * + ***************************************************************************/ + +// qt/kde includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// local includes +#include "xpdf/GlobalParams.h" +#include "part.h" +#include "ui/pageview.h" +#include "ui/thumbnaillist.h" +#include "ui/searchwidget.h" +#include "ui/toc.h" +#include "ui/minibar.h" +#include "ui/propertiesdialog.h" +#include "ui/presentationwidget.h" +#include "conf/preferencesdialog.h" +#include "conf/settings.h" +#include "core/document.h" +#include "core/page.h" + +class PDFOptionsPage : public KPrintDialogPage +{ + public: + PDFOptionsPage() + { + setTitle( i18n( "PDF Options" ) ); + QVBoxLayout *layout = new QVBoxLayout(this); + m_forceRaster = new QCheckBox(i18n("Force rasterization"), this); + QToolTip::add(m_forceRaster, i18n("Rasterize into an image before printing")); + QWhatsThis::add(m_forceRaster, i18n("Forces the rasterization of each page into an image before printing it. This usually gives somewhat worse results, but is useful when printing documents that appear to print incorrectly.")); + layout->addWidget(m_forceRaster); + layout->addStretch(1); + } + + void getOptions( QMap& opts, bool incldef = false ) + { + Q_UNUSED(incldef); + opts[ "kde-kpdf-forceRaster" ] = QString::number( m_forceRaster->isChecked() ); + } + + void setOptions( const QMap& opts ) + { + m_forceRaster->setChecked( opts[ "kde-kpdf-forceRaster" ].toInt() ); + } + + private: + QCheckBox *m_forceRaster; +}; + +// definition of searchID for this class +#define PART_SEARCH_ID 1 + +typedef KParts::GenericFactory KPDFPartFactory; +K_EXPORT_COMPONENT_FACTORY(libkpdfpart, KPDFPartFactory) + +using namespace KPDF; + +unsigned int Part::m_count = 0; + +Part::Part(QWidget *parentWidget, const char *widgetName, + QObject *parent, const char *name, + const QStringList & /*args*/ ) + : DCOPObject("kpdf"), KParts::ReadOnlyPart(parent, name), m_showMenuBarAction(0), m_showFullScreenAction(0), + m_actionsSearched(false), m_searchStarted(false) +{ + // connect the started signal to tell the job the mimetypes we like + connect(this, SIGNAL(started(KIO::Job *)), this, SLOT(setMimeTypes(KIO::Job *))); + + // connect the completed signal so we can put the window caption when loading remote files + connect(this, SIGNAL(completed()), this, SLOT(emitWindowCaption())); + connect(this, SIGNAL(canceled(const QString &)), this, SLOT(emitWindowCaption())); + + // load catalog for translation + KGlobal::locale()->insertCatalogue("kpdf"); + + // create browser extension (for printing when embedded into browser) + m_bExtension = new BrowserExtension(this); + + // xpdf 'extern' global class (m_count is a static instance counter) + //if ( m_count ) TODO check if we need to insert these lines.. + // delete globalParams; + globalParams = new GlobalParams(""); + globalParams->setupBaseFonts(NULL); + m_count++; + + // we need an instance + setInstance(KPDFPartFactory::instance()); + + // build the document + m_document = new KPDFDocument(widget()); + connect( m_document, SIGNAL( linkFind() ), this, SLOT( slotFind() ) ); + connect( m_document, SIGNAL( linkGoToPage() ), this, SLOT( slotGoToPage() ) ); + connect( m_document, SIGNAL( linkPresentation() ), this, SLOT( slotShowPresentation() ) ); + connect( m_document, SIGNAL( linkEndPresentation() ), this, SLOT( slotHidePresentation() ) ); + connect( m_document, SIGNAL( openURL(const KURL &) ), this, SLOT( openURLFromDocument(const KURL &) ) ); + connect( m_document, SIGNAL( close() ), this, SLOT( close() ) ); + + if (parent && parent->metaObject()->slotNames(true).contains("slotQuit()")) + connect( m_document, SIGNAL( quit() ), parent, SLOT( slotQuit() ) ); + else + connect( m_document, SIGNAL( quit() ), this, SLOT( cannotQuit() ) ); + + // widgets: ^searchbar (toolbar containing label and SearchWidget) +// m_searchToolBar = new KToolBar( parentWidget, "searchBar" ); +// m_searchToolBar->boxLayout()->setSpacing( KDialog::spacingHint() ); +// QLabel * sLabel = new QLabel( i18n( "&Search:" ), m_searchToolBar, "kde toolbar widget" ); +// m_searchWidget = new SearchWidget( m_searchToolBar, m_document ); +// sLabel->setBuddy( m_searchWidget ); +// m_searchToolBar->setStretchableWidget( m_searchWidget ); + + // widgets: [] splitter [] + m_splitter = new QSplitter( parentWidget, widgetName ); + m_splitter->setOpaqueResize( true ); + setWidget( m_splitter ); + + m_showLeftPanel = new KToggleAction( i18n( "Show &Navigation Panel"), "show_side_panel", 0, this, SLOT( slotShowLeftPanel() ), actionCollection(), "show_leftpanel" ); + m_showLeftPanel->setCheckedState( i18n( "Hide &Navigation Panel") ); + m_showLeftPanel->setShortcut( "CTRL+L" ); + m_showLeftPanel->setChecked( KpdfSettings::showLeftPanel() ); + + // widgets: [left panel] | [] + m_leftPanel = new QWidget( m_splitter ); + m_leftPanel->setMinimumWidth( 90 ); + m_leftPanel->setMaximumWidth( 300 ); + QVBoxLayout * leftPanelLayout = new QVBoxLayout( m_leftPanel ); + + // widgets: [left toolbox/..] | [] + m_toolBox = new QToolBox( m_leftPanel ); + leftPanelLayout->addWidget( m_toolBox ); + + int index; + // [left toolbox: Table of Contents] | [] + // dummy wrapper with layout to enable horizontal scroll bars (bug: 147233) + QWidget *tocWrapper = new QWidget(m_toolBox); + QVBoxLayout *tocWrapperLayout = new QVBoxLayout(tocWrapper); + m_tocFrame = new TOC( tocWrapper, m_document ); + tocWrapperLayout->add(m_tocFrame); + connect(m_tocFrame, SIGNAL(hasTOC(bool)), this, SLOT(enableTOC(bool))); + index = m_toolBox->addItem( tocWrapper, QIconSet(SmallIcon("text_left")), i18n("Contents") ); + m_toolBox->setItemToolTip(index, i18n("Contents")); + enableTOC( false ); + + // [left toolbox: Thumbnails and Bookmarks] | [] + QVBox * thumbsBox = new ThumbnailsBox( m_toolBox ); + m_searchWidget = new SearchWidget( thumbsBox, m_document ); + m_thumbnailList = new ThumbnailList( thumbsBox, m_document ); +// ThumbnailController * m_tc = new ThumbnailController( thumbsBox, m_thumbnailList ); + connect( m_thumbnailList, SIGNAL( urlDropped( const KURL& ) ), SLOT( openURLFromDocument( const KURL & )) ); + connect( m_thumbnailList, SIGNAL( rightClick(const KPDFPage *, const QPoint &) ), this, SLOT( slotShowMenu(const KPDFPage *, const QPoint &) ) ); + // shrink the bottom controller toolbar (too hackish..) + thumbsBox->setStretchFactor( m_searchWidget, 100 ); + thumbsBox->setStretchFactor( m_thumbnailList, 100 ); +// thumbsBox->setStretchFactor( m_tc, 1 ); + index = m_toolBox->addItem( thumbsBox, QIconSet(SmallIcon("thumbnail")), i18n("Thumbnails") ); + m_toolBox->setItemToolTip(index, i18n("Thumbnails")); + m_toolBox->setCurrentItem( thumbsBox ); + + slotShowLeftPanel(); + +/* // [left toolbox: Annotations] | [] + QFrame * editFrame = new QFrame( m_toolBox ); + int iIdx = m_toolBox->addItem( editFrame, QIconSet(SmallIcon("pencil")), i18n("Annotations") ); + m_toolBox->setItemEnabled( iIdx, false );*/ + + // widgets: [../miniBarContainer] | [] + QWidget * miniBarContainer = new QWidget( m_leftPanel ); + leftPanelLayout->addWidget( miniBarContainer ); + QVBoxLayout * miniBarLayout = new QVBoxLayout( miniBarContainer ); + // widgets: [../[spacer/..]] | [] + QWidget * miniSpacer = new QWidget( miniBarContainer ); + miniSpacer->setFixedHeight( 6 ); + miniBarLayout->addWidget( miniSpacer ); + // widgets: [../[../MiniBar]] | [] + m_miniBar = new MiniBar( miniBarContainer, m_document ); + miniBarLayout->addWidget( m_miniBar ); + + // widgets: [] | [right 'pageView'] + m_pageView = new PageView( m_splitter, m_document ); + m_pageView->setFocus(); //usability setting + m_splitter->setFocusProxy(m_pageView); + connect( m_pageView, SIGNAL( urlDropped( const KURL& ) ), SLOT( openURLFromDocument( const KURL & ))); + connect( m_pageView, SIGNAL( rightClick(const KPDFPage *, const QPoint &) ), this, SLOT( slotShowMenu(const KPDFPage *, const QPoint &) ) ); + + // add document observers + m_document->addObserver( this ); + m_document->addObserver( m_thumbnailList ); + m_document->addObserver( m_pageView ); + m_document->addObserver( m_tocFrame ); + m_document->addObserver( m_miniBar ); + + // ACTIONS + KActionCollection * ac = actionCollection(); + + // Page Traversal actions + m_gotoPage = KStdAction::gotoPage( this, SLOT( slotGoToPage() ), ac, "goto_page" ); + m_gotoPage->setShortcut( "CTRL+G" ); + // dirty way to activate gotopage when pressing miniBar's button + connect( m_miniBar, SIGNAL( gotoPage() ), m_gotoPage, SLOT( activate() ) ); + + m_prevPage = KStdAction::prior(this, SLOT(slotPreviousPage()), ac, "previous_page"); + m_prevPage->setWhatsThis( i18n( "Moves to the previous page of the document" ) ); + m_prevPage->setShortcut( 0 ); + // dirty way to activate prev page when pressing miniBar's button + connect( m_miniBar, SIGNAL( prevPage() ), m_prevPage, SLOT( activate() ) ); + + m_nextPage = KStdAction::next(this, SLOT(slotNextPage()), ac, "next_page" ); + m_nextPage->setWhatsThis( i18n( "Moves to the next page of the document" ) ); + m_nextPage->setShortcut( 0 ); + // dirty way to activate next page when pressing miniBar's button + connect( m_miniBar, SIGNAL( nextPage() ), m_nextPage, SLOT( activate() ) ); + + m_firstPage = KStdAction::firstPage( this, SLOT( slotGotoFirst() ), ac, "first_page" ); + m_firstPage->setWhatsThis( i18n( "Moves to the first page of the document" ) ); + + m_lastPage = KStdAction::lastPage( this, SLOT( slotGotoLast() ), ac, "last_page" ); + m_lastPage->setWhatsThis( i18n( "Moves to the last page of the document" ) ); + + m_historyBack = KStdAction::back( this, SLOT( slotHistoryBack() ), ac, "history_back" ); + m_historyBack->setWhatsThis( i18n( "Go to the place you were before" ) ); + + m_historyNext = KStdAction::forward( this, SLOT( slotHistoryNext() ), ac, "history_forward" ); + m_historyNext->setWhatsThis( i18n( "Go to the place you were after" ) ); + + // Find and other actions + m_find = KStdAction::find( this, SLOT( slotFind() ), ac, "find" ); + m_find->setEnabled( false ); + + m_findNext = KStdAction::findNext( this, SLOT( slotFindNext() ), ac, "find_next" ); + m_findNext->setEnabled( false ); + + m_saveAs = KStdAction::saveAs( this, SLOT( slotSaveFileAs() ), ac, "save" ); + m_saveAs->setEnabled( false ); + KAction * prefs = KStdAction::preferences( this, SLOT( slotPreferences() ), ac, "preferences" ); + prefs->setText( i18n( "Configure KPDF..." ) ); + m_printPreview = KStdAction::printPreview( this, SLOT( slotPrintPreview() ), ac ); + m_printPreview->setEnabled( false ); + + m_showProperties = new KAction(i18n("&Properties"), "info", 0, this, SLOT(slotShowProperties()), ac, "properties"); + m_showProperties->setEnabled( false ); + + m_showPresentation = new KAction( i18n("P&resentation"), "kpresenter_kpr", "Ctrl+Shift+P", this, SLOT(slotShowPresentation()), ac, "presentation"); + m_showPresentation->setEnabled( false ); + + // attach the actions of the children widgets too + m_pageView->setupActions( ac ); + + // apply configuration (both internal settings and GUI configured items) + QValueList splitterSizes = KpdfSettings::splitterSizes(); + if ( !splitterSizes.count() ) + { + // the first time use 1/10 for the panel and 9/10 for the pageView + splitterSizes.push_back( 50 ); + splitterSizes.push_back( 500 ); + } + m_splitter->setSizes( splitterSizes ); + // get notified about splitter size changes (HACK that will be removed + // by connecting to Qt4::QSplitter's sliderMoved()) + m_pageView->installEventFilter( this ); + m_watcher = new KDirWatch( this ); + connect( m_watcher, SIGNAL( dirty( const QString& ) ), this, SLOT( slotFileDirty( const QString& ) ) ); + m_dirtyHandler = new QTimer( this ); + connect( m_dirtyHandler, SIGNAL( timeout() ),this, SLOT( slotDoFileDirty() ) ); + m_saveSplitterSizeTimer = new QTimer( this ); + connect( m_saveSplitterSizeTimer, SIGNAL( timeout() ),this, SLOT( saveSplitterSize() ) ); + + slotNewConfig(); + + // [SPEECH] check for KTTSD presence and usability + KTrader::OfferList offers = KTrader::self()->query("DCOP/Text-to-Speech", "Name == 'KTTSD'"); + KpdfSettings::setUseKTTSD( (offers.count() > 0) ); + KpdfSettings::writeConfig(); + + // set our XML-UI resource file + setXMLFile("part.rc"); + updateViewActions(); +} + +Part::~Part() +{ + delete m_tocFrame; + delete m_pageView; + delete m_thumbnailList; + delete m_miniBar; + + delete m_document; + if ( --m_count == 0 ) + delete globalParams; +} + +void Part::notifyViewportChanged( bool /*smoothMove*/ ) +{ + // update actions if the page is changed + static int lastPage = -1; + int viewportPage = m_document->viewport().pageNumber; + if ( viewportPage != lastPage ) + { + updateViewActions(); + lastPage = viewportPage; + } +} + +void Part::goToPage(uint i) +{ + if ( i <= m_document->pages() ) + m_document->setViewportPage( i - 1 ); +} + +void Part::openDocument(KURL doc) +{ + openURL(doc); +} + +uint Part::pages() +{ + return m_document->pages(); +} + +uint Part::currentPage() +{ + if ( m_document->pages() == 0 ) return 0; + else return m_document->currentPage()+1; +} + +KURL Part::currentDocument() +{ + return m_document->currentDocument(); +} + +//this don't go anywhere but is required by genericfactory.h +KAboutData* Part::createAboutData() +{ + // the non-i18n name here must be the same as the directory in + // which the part's rc file is installed ('partrcdir' in the + // Makefile) + KAboutData* aboutData = new KAboutData("kpdfpart", I18N_NOOP("KPDF::Part"), "0.1"); + aboutData->addAuthor("Wilco Greven", 0, "greven@kde.org"); + return aboutData; +} + +bool Part::openFile() +{ + KMimeType::Ptr mime; + if ( m_bExtension->urlArgs().serviceType.isEmpty() ) + { + if (!m_jobMime.isEmpty()) + { + mime = KMimeType::mimeType(m_jobMime); + if ( mime->is( "application/octet-stream" ) ) + { + mime = KMimeType::findByPath( m_file ); + } + } + else + { + mime = KMimeType::findByPath( m_file ); + } + } + else + { + mime = KMimeType::mimeType( m_bExtension->urlArgs().serviceType ); + } + if ( (*mime).is( "application/postscript" ) ) + { + QString app = KStandardDirs::findExe( "ps2pdf" ); + if ( !app.isNull() ) + { + if ( QFile::exists(m_file) ) + { + KTempFile tf( QString::null, ".pdf" ); + if ( tf.status() == 0 ) + { + tf.close(); + m_temporaryLocalFile = tf.name(); + + KProcess *p = new KProcess; + *p << app; + *p << m_file << m_temporaryLocalFile; + m_pageView->showText(i18n("Converting from ps to pdf..."), 0); + connect(p, SIGNAL(processExited(KProcess *)), this, SLOT(psTransformEnded())); + p -> start(); + return true; + } + else return false; + } + else return false; + } + else + { + KMessageBox::error(widget(), i18n("You do not have ps2pdf installed, so kpdf cannot open postscript files.")); + return false; + } + } + + m_temporaryLocalFile = QString::null; + + bool ok = m_document->openDocument( m_file, url(), mime ); + + // update one-time actions + m_find->setEnabled( ok && m_document-> supportsSearching()); + m_findNext->setEnabled( ok && m_document-> supportsSearching()); + m_saveAs->setEnabled( ok ); + m_printPreview->setEnabled( ok ); + m_showProperties->setEnabled( ok ); + m_showPresentation->setEnabled( ok ); + + // update viewing actions + updateViewActions(); + + if ( !ok ) + { + // if can't open document, update windows so they display blank contents + m_pageView->updateContents(); + m_thumbnailList->updateContents(); + return false; + } + + // set the file to the fileWatcher + if ( !m_watcher->contains(m_file) ) + m_watcher->addFile(m_file); + + // if the 'OpenTOC' flag is set, open the TOC + if ( m_document->getMetaData( "OpenTOC" ) == "yes" && m_toolBox->isItemEnabled( 0 ) ) + { + m_toolBox->setCurrentIndex( 0 ); + } + // if the 'StartFullScreen' flag is set, start presentation + if ( m_document->getMetaData( "StartFullScreen" ) == "yes" ) + { + KMessageBox::information(m_presentationWidget, i18n("The document is going to be launched on presentation mode because the file requested it."), QString::null, "autoPresentationWarning"); + slotShowPresentation(); + } + + return true; +} + +void Part::openURLFromDocument(const KURL &url) +{ + m_bExtension->openURLNotify(); + m_bExtension->setLocationBarURL(url.prettyURL()); + openURL(url); +} + +bool Part::openURL(const KURL &url) +{ + // note: this can be the right place to check the file for gz or bz2 extension + // if it matches then: download it (if not local) extract to a temp file using + // KTar and proceed with the URL of the temporary file + + m_jobMime = QString::null; + + // this calls the above 'openURL' method + bool b = KParts::ReadOnlyPart::openURL(url); + + // these setWindowCaption calls only work for local files + if ( !b ) + { + KMessageBox::error( widget(), i18n("Could not open %1").arg( url.prettyURL() ) ); + emit setWindowCaption(""); + } + else + { + m_viewportDirty.pageNumber = -1; + emit setWindowCaption(url.filename()); + } + emit enablePrintAction(b); + return b; +} + +void Part::setMimeTypes(KIO::Job *job) +{ + if (job) + { + job->addMetaData("accept", "application/pdf, */*;q=0.5"); + connect(job, SIGNAL(mimetype(KIO::Job*,const QString&)), this, SLOT(readMimeType(KIO::Job*,const QString&))); + } +} + +void Part::readMimeType(KIO::Job *, const QString &mime) +{ + m_jobMime = mime; +} + +void Part::emitWindowCaption() +{ + // these setWindowCaption call only works for remote files + if (m_document->isOpened()) emit setWindowCaption(url().filename()); + else emit setWindowCaption(""); +} + +bool Part::closeURL() +{ + if (!m_temporaryLocalFile.isNull()) + { + QFile::remove( m_temporaryLocalFile ); + m_temporaryLocalFile = QString::null; + } + + slotHidePresentation(); + m_find->setEnabled( false ); + m_findNext->setEnabled( false ); + m_saveAs->setEnabled( false ); + m_printPreview->setEnabled( false ); + m_showProperties->setEnabled( false ); + m_showPresentation->setEnabled( false ); + emit setWindowCaption(""); + emit enablePrintAction(false); + m_searchStarted = false; + if (!m_file.isEmpty()) m_watcher->removeFile(m_file); + m_document->closeDocument(); + updateViewActions(); + m_searchWidget->clearText(); + return KParts::ReadOnlyPart::closeURL(); +} + +bool Part::eventFilter( QObject * watched, QEvent * e ) +{ + // if pageView has been resized, save splitter sizes + if ( watched == m_pageView && e->type() == QEvent::Resize ) + m_saveSplitterSizeTimer->start(500, true); + + // only intercept events, don't block them + return false; +} + +void Part::slotShowLeftPanel() +{ + bool showLeft = m_showLeftPanel->isChecked(); + KpdfSettings::setShowLeftPanel(showLeft); + KpdfSettings::writeConfig(); + // show/hide left qtoolbox + m_leftPanel->setShown( showLeft ); + // this needs to be hidden explicitly to disable thumbnails gen + m_thumbnailList->setShown( showLeft ); +} + +void Part::slotFileDirty( const QString& fileName ) +{ + // The beauty of this is that each start cancels the previous one. + // This means that timeout() is only fired when there have + // no changes to the file for the last 750 milisecs. + // This is supposed to ensure that we don't update on every other byte + // that gets written to the file. + if ( fileName == m_file ) + { + m_dirtyHandler->start( 750, true ); + } +} + +void Part::slotDoFileDirty() +{ + if (m_viewportDirty.pageNumber == -1) + { + m_viewportDirty = m_document->viewport(); + m_dirtyToolboxIndex = m_toolBox->currentIndex(); + m_wasPresentationOpen = ((PresentationWidget*)m_presentationWidget != 0); + m_pageView->showText(i18n("Reloading the document..."), 0); + } + + if (KParts::ReadOnlyPart::openURL(KURL::fromPathOrURL(m_file))) + { + if (m_viewportDirty.pageNumber >= (int)m_document->pages()) m_viewportDirty.pageNumber = (int)m_document->pages() - 1; + m_document->setViewport(m_viewportDirty); + m_viewportDirty.pageNumber = -1; + if ( m_toolBox->currentIndex() != m_dirtyToolboxIndex && m_toolBox->isItemEnabled( m_dirtyToolboxIndex ) ) + { + m_toolBox->setCurrentIndex( m_dirtyToolboxIndex ); + } + if (m_wasPresentationOpen) slotShowPresentation(); + emit enablePrintAction(true); + emit setWindowCaption(url().filename()); + } + else + { + m_watcher->addFile(m_file); + m_dirtyHandler->start( 750, true ); + } +} + +void Part::close() +{ + if (parent() && strcmp(parent()->name(), "KPDF::Shell") == 0) + { + closeURL(); + } + else KMessageBox::information(widget(), i18n("This link points to a close document action that does not work when using the embedded viewer."), QString::null, "warnNoCloseIfNotInKPDF"); +} + +void Part::updateViewActions() +{ + bool opened = m_document->pages() > 0; + if ( opened ) + { + bool atBegin = m_document->currentPage() < 1; + bool atEnd = m_document->currentPage() >= (m_document->pages() - 1); + m_gotoPage->setEnabled( m_document->pages() > 1 ); + m_firstPage->setEnabled( !atBegin ); + m_prevPage->setEnabled( !atBegin ); + m_lastPage->setEnabled( !atEnd ); + m_nextPage->setEnabled( !atEnd ); + m_historyBack->setEnabled( !m_document->historyAtBegin() ); + m_historyNext->setEnabled( !m_document->historyAtEnd() ); + } + else + { + m_gotoPage->setEnabled( false ); + m_firstPage->setEnabled( false ); + m_lastPage->setEnabled( false ); + m_prevPage->setEnabled( false ); + m_nextPage->setEnabled( false ); + m_historyBack->setEnabled( false ); + m_historyNext->setEnabled( false ); + } +} + +void Part::enableTOC(bool enable) +{ + m_toolBox->setItemEnabled(0, enable); +} + +void Part::psTransformEnded() +{ + QString aux = m_file; + m_file = m_temporaryLocalFile; + openFile(); + m_file = aux; // so watching works, we have to watch the ps file not the autogenerated pdf + m_watcher->removeFile(m_temporaryLocalFile); + if ( !m_watcher->contains(m_file) ) + m_watcher->addFile(m_file); +} + +void Part::cannotQuit() +{ + KMessageBox::information(widget(), i18n("This link points to a quit application action that does not work when using the embedded viewer."), QString::null, "warnNoQuitIfNotInKPDF"); +} + +void Part::saveSplitterSize() +{ + KpdfSettings::setSplitterSizes( m_splitter->sizes() ); + KpdfSettings::writeConfig(); +} + +//BEGIN go to page dialog +class KPDFGotoPageDialog : public KDialogBase +{ +public: + KPDFGotoPageDialog(QWidget *p, int current, int max) : KDialogBase(p, 0L, true, i18n("Go to Page"), Ok | Cancel, Ok) { + QWidget *w = new QWidget(this); + setMainWidget(w); + + QVBoxLayout *topLayout = new QVBoxLayout( w, 0, spacingHint() ); + e1 = new KIntNumInput(current, w); + e1->setRange(1, max); + e1->setEditFocus(true); + + QLabel *label = new QLabel( e1,i18n("&Page:"), w ); + topLayout->addWidget(label); + topLayout->addWidget(e1); + topLayout->addSpacing(spacingHint()); // A little bit extra space + topLayout->addStretch(10); + e1->setFocus(); + } + + int getPage() { + return e1->value(); + } + + protected: + KIntNumInput *e1; +}; +//END go to page dialog + +void Part::slotGoToPage() +{ + KPDFGotoPageDialog pageDialog( m_pageView, m_document->currentPage() + 1, m_document->pages() ); + if ( pageDialog.exec() == QDialog::Accepted ) + m_document->setViewportPage( pageDialog.getPage() - 1 ); +} + +void Part::slotPreviousPage() +{ + if ( m_document->isOpened() && !(m_document->currentPage() < 1) ) + m_document->setViewportPage( m_document->currentPage() - 1 ); +} + +void Part::slotNextPage() +{ + if ( m_document->isOpened() && m_document->currentPage() < (m_document->pages() - 1) ) + m_document->setViewportPage( m_document->currentPage() + 1 ); +} + +void Part::slotGotoFirst() +{ + if ( m_document->isOpened() ) + m_document->setViewportPage( 0 ); +} + +void Part::slotGotoLast() +{ + if ( m_document->isOpened() ) + m_document->setViewportPage( m_document->pages() - 1 ); +} + +void Part::slotHistoryBack() +{ + m_document->setPrevViewport(); +} + +void Part::slotHistoryNext() +{ + m_document->setNextViewport(); +} + +void Part::slotFind() +{ + static bool savedCaseSensitive = false; + KFindDialog dlg( widget() ); + dlg.setHasCursor( false ); + if ( !m_searchHistory.empty() ) + dlg.setFindHistory( m_searchHistory ); +#if KDE_IS_VERSION(3,3,90) + dlg.setSupportsBackwardsFind( false ); + dlg.setSupportsWholeWordsFind( false ); + dlg.setSupportsRegularExpressionFind( false ); +#endif + if ( savedCaseSensitive ) + { + dlg.setOptions( dlg.options() | KFindDialog::CaseSensitive ); + } + if ( dlg.exec() == QDialog::Accepted ) + { + savedCaseSensitive = dlg.options() & KFindDialog::CaseSensitive; + m_searchHistory = dlg.findHistory(); + m_searchStarted = true; + m_document->resetSearch( PART_SEARCH_ID ); + m_document->searchText( PART_SEARCH_ID, dlg.pattern(), false, savedCaseSensitive, + KPDFDocument::NextMatch, true, qRgb( 255, 255, 64 ) ); + } +} + +void Part::slotFindNext() +{ + if (!m_document->continueLastSearch()) + slotFind(); +} + +void Part::slotSaveFileAs() +{ + KURL saveURL = KFileDialog::getSaveURL( url().isLocalFile() ? url().url() : url().fileName(), QString::null, widget() ); + if ( saveURL.isValid() && !saveURL.isEmpty() ) + { + if (saveURL == url()) + { + KMessageBox::information( widget(), i18n("You are trying to overwrite \"%1\" with itself. This is not allowed. Please save it in another location.").arg(saveURL.filename()) ); + return; + } + if ( KIO::NetAccess::exists( saveURL, false, widget() ) ) + { + if (KMessageBox::warningContinueCancel( widget(), i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?").arg(saveURL.filename()), QString::null, i18n("Overwrite")) != KMessageBox::Continue) + return; + } + + if ( !KIO::NetAccess::file_copy( m_file, saveURL, -1, true ) ) + KMessageBox::information( 0, i18n("File could not be saved in '%1'. Try to save it to another location.").arg( saveURL.prettyURL() ) ); + } +} + +void Part::slotPreferences() +{ + // an instance the dialog could be already created and could be cached, + // in which case you want to display the cached dialog + if ( PreferencesDialog::showDialog( "preferences" ) ) + return; + + // we didn't find an instance of this dialog, so lets create it + PreferencesDialog * dialog = new PreferencesDialog( m_pageView, KpdfSettings::self() ); + // keep us informed when the user changes settings + connect( dialog, SIGNAL( settingsChanged() ), this, SLOT( slotNewConfig() ) ); + + dialog->show(); +} + +void Part::slotNewConfig() +{ + // Apply settings here. A good policy is to check wether the setting has + // changed before applying changes. + + // Watch File + bool watchFile = KpdfSettings::watchFile(); + if ( watchFile && m_watcher->isStopped() ) + m_watcher->startScan(); + if ( !watchFile && !m_watcher->isStopped() ) + { + m_dirtyHandler->stop(); + m_watcher->stopScan(); + } + + bool showSearch = KpdfSettings::showSearchBar(); + if ( m_searchWidget->isShown() != showSearch ) + m_searchWidget->setShown( showSearch ); + + // Main View (pageView) + QScrollView::ScrollBarMode scrollBarMode = KpdfSettings::showScrollBars() ? + QScrollView::AlwaysOn : QScrollView::AlwaysOff; + if ( m_pageView->hScrollBarMode() != scrollBarMode ) + { + m_pageView->setHScrollBarMode( scrollBarMode ); + m_pageView->setVScrollBarMode( scrollBarMode ); + } + + // update document settings + m_document->reparseConfig(); + + // update Main View and ThumbnailList contents + // TODO do this only when changing KpdfSettings::renderMode() + m_pageView->updateContents(); + if ( KpdfSettings::showLeftPanel() && m_thumbnailList->isShown() ) + m_thumbnailList->updateWidgets(); +} + +void Part::slotPrintPreview() +{ + if (m_document->pages() == 0) return; + + double width, height; + int landscape, portrait; + KPrinter printer; + const KPDFPage *page; + + printer.setMinMax(1, m_document->pages()); + printer.setPreviewOnly( true ); + + // if some pages are landscape and others are not the most common win as kprinter does + // not accept a per page setting + landscape = 0; + portrait = 0; + for (uint i = 0; i < m_document->pages(); i++) + { + page = m_document->page(i); + width = page->width(); + height = page->height(); + if (page->rotation() == 90 || page->rotation() == 270) qSwap(width, height); + if (width > height) landscape++; + else portrait++; + } + if (landscape > portrait) printer.setOption("orientation-requested", "4"); + + doPrint(printer); +} + +void Part::slotShowMenu(const KPDFPage *page, const QPoint &point) +{ + bool reallyShow = false; + if (!m_actionsSearched) + { + // the quest for options_show_menubar + KXMLGUIClient *client; + KActionCollection *ac; + KActionPtrList::const_iterator it, end, begin; + KActionPtrList actions; + + if (factory()) + { + QPtrList clients(factory()->clients()); + QPtrListIterator clientsIt( clients ); + for( ; (!m_showMenuBarAction || !m_showFullScreenAction) && clientsIt.current(); ++clientsIt) + { + client = clientsIt.current(); + ac = client->actionCollection(); + actions = ac->actions(); + end = actions.end(); + begin = actions.begin(); + for ( it = begin; it != end; ++it ) + { + if (QString((*it)->name()) == "options_show_menubar") m_showMenuBarAction = (KToggleAction*)(*it); + if (QString((*it)->name()) == "fullscreen") m_showFullScreenAction = (KToggleAction*)(*it); + } + } + } + m_actionsSearched = true; + } + + + KPopupMenu *popup = new KPopupMenu( widget(), "rmb popup" ); + if (page) + { + popup->insertTitle( i18n( "Page %1" ).arg( page->number() + 1 ) ); + if ( page->hasBookmark() ) + popup->insertItem( SmallIcon("bookmark"), i18n("Remove Bookmark"), 1 ); + else + popup->insertItem( SmallIcon("bookmark_add"), i18n("Add Bookmark"), 1 ); + if ( m_pageView->canFitPageWidth() ) + popup->insertItem( SmallIcon("viewmagfit"), i18n("Fit Width"), 2 ); + //popup->insertItem( SmallIcon("pencil"), i18n("Edit"), 3 ); + //popup->setItemEnabled( 3, false ); + reallyShow = true; + } +/* + //Albert says: I have not ported this as i don't see it does anything + if ( d->mouseOnRect ) // and rect->objectType() == ObjectRect::Image ... + { + m_popup->insertItem( SmallIcon("filesave"), i18n("Save Image..."), 4 ); + m_popup->setItemEnabled( 4, false ); +}*/ + + if ((m_showMenuBarAction && !m_showMenuBarAction->isChecked()) || (m_showFullScreenAction && m_showFullScreenAction->isChecked())) + { + popup->insertTitle( i18n( "Tools" ) ); + if (m_showMenuBarAction && !m_showMenuBarAction->isChecked()) m_showMenuBarAction->plug(popup); + if (m_showFullScreenAction && m_showFullScreenAction->isChecked()) m_showFullScreenAction->plug(popup); + reallyShow = true; + + } + + if (reallyShow) + { + switch ( popup->exec(point) ) + { + case 1: + m_document->toggleBookmark( page->number() ); + break; + case 2: + m_pageView->fitPageWidth( page->number() ); + break; + // case 3: // switch to edit mode + // break; + } + } + delete popup; +} + +void Part::slotShowProperties() +{ + PropertiesDialog *d = new PropertiesDialog(widget(), m_document); + d->exec(); + delete d; +} + +void Part::slotShowPresentation() +{ + if ( !m_presentationWidget ) + { + m_presentationWidget = new PresentationWidget( widget(), m_document ); + m_presentationWidget->setupActions( actionCollection() ); + } +} + +void Part::slotHidePresentation() +{ + if ( m_presentationWidget ) + delete (PresentationWidget*) m_presentationWidget; +} + +void Part::slotTogglePresentation() +{ + if ( m_document->isOpened() ) + { + if ( !m_presentationWidget ) + { + m_presentationWidget = new PresentationWidget( widget(), m_document ); + m_presentationWidget->setupActions( actionCollection() ); + } + else delete (PresentationWidget*) m_presentationWidget; + } +} + +void Part::slotPrint() +{ + if (m_document->pages() == 0) return; + + double width, height; + int landscape, portrait; + KPrinter printer; + const KPDFPage *page; + + printer.setPageSelection(KPrinter::ApplicationSide); + printer.setMinMax(1, m_document->pages()); + printer.setCurrentPage(m_document->currentPage()+1); + + // if some pages are landscape and others are not the most common win as kprinter does + // not accept a per page setting + landscape = 0; + portrait = 0; + for (uint i = 0; i < m_document->pages(); i++) + { + page = m_document->page(i); + width = page->width(); + height = page->height(); + if (page->rotation() == 90 || page->rotation() == 270) qSwap(width, height); + if (width > height) landscape++; + else portrait++; + } + if (landscape > portrait) printer.setOrientation(KPrinter::Landscape); + + KPrinter::addDialogPage(new PDFOptionsPage()); + if (printer.setup(widget())) doPrint( printer ); +} + +void Part::doPrint(KPrinter &printer) +{ + if (!m_document->isAllowed(KPDFDocument::AllowPrint)) + { + KMessageBox::error(widget(), i18n("Printing this document is not allowed.")); + return; + } + + if (!m_document->print(printer)) + { + KMessageBox::error(widget(), i18n("Could not print the document. Please report to bugs.kde.org")); + } +} + +void Part::restoreDocument(KConfig* config) +{ + KURL url ( config->readPathEntry( "URL" ) ); + if ( url.isValid() ) + { + QString viewport = config->readEntry( "Viewport" ); + if (!viewport.isEmpty()) m_document->setNextDocumentViewport( DocumentViewport( viewport ) ); + openURL( url ); + } +} + +void Part::saveDocumentRestoreInfo(KConfig* config) +{ + config->writePathEntry( "URL", url().url() ); + config->writeEntry( "Viewport", m_document->viewport().toString() ); +} + +/* +* BrowserExtension class +*/ +BrowserExtension::BrowserExtension(Part* parent) + : KParts::BrowserExtension( parent, "KPDF::BrowserExtension" ) +{ + emit enableAction("print", true); + setURLDropHandlingEnabled(true); +} + +void BrowserExtension::print() +{ + static_cast(parent())->slotPrint(); +} + +#include "part.moc" diff --git a/kpdf/part.h b/kpdf/part.h new file mode 100644 index 00000000..be572c5f --- /dev/null +++ b/kpdf/part.h @@ -0,0 +1,212 @@ +/*************************************************************************** + * Copyright (C) 2002 by Wilco Greven * + * Copyright (C) 2003-2004 by Christophe Devriese * + * * + * Copyright (C) 2003 by Andy Goossens * + * Copyright (C) 2003 by Laurent Montel * + * Copyright (C) 2004 by Dominique Devriese * + * Copyright (C) 2004-2006 by Albert Astals Cid * + * * + * 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. * + ***************************************************************************/ + +#ifndef _KPDF_PART_H_ +#define _KPDF_PART_H_ + +#include +#include +#include +#include "core/document.h" +#include "core/observer.h" +#include "dcop.h" + +class QWidget; +class QSplitter; +class QToolBox; + +class KURL; +class KAction; +class KConfig; +class KDirWatch; +class KToggleAction; +class KSelectAction; +class KAboutData; +class KPrinter; + +class ThumbnailList; +class ThumbnailController; +class PageView; +class PresentationWidget; +class SearchWidget; +class TOC; +class MiniBar; + +namespace KPDF { + +class BrowserExtension; + +/** + * This is a "Part". It that does all the real work in a KPart + * application. + * + * @short Main Part + * @author Wilco Greven + * @version 0.2 + */ +class Part : public KParts::ReadOnlyPart, public DocumentObserver, virtual public kpdf_dcop +{ +Q_OBJECT + +public: + // Default constructor + Part(QWidget* parentWidget, const char* widgetName, + QObject* parent, const char* name, const QStringList& args); + + // Destructor + ~Part(); + + // inherited from DocumentObserver + uint observerId() const { return PART_ID; } + void notifyViewportChanged( bool smoothMove ); + + static KAboutData* createAboutData(); + + ASYNC goToPage(uint page); + ASYNC openDocument(KURL doc); + uint pages(); + uint currentPage(); + KURL currentDocument(); + +signals: + void enablePrintAction(bool enable); + +protected: + // reimplemented from KParts::ReadOnlyPart + bool openFile(); + bool openURL(const KURL &url); + bool closeURL(); + // filter that watches for splitter size changes + bool eventFilter( QObject * watched, QEvent * e ); + +protected slots: + void openURLFromDocument(const KURL &url); + // connected to actions + void slotGoToPage(); + void slotPreviousPage(); + void slotNextPage(); + void slotGotoFirst(); + void slotGotoLast(); + void slotHistoryBack(); + void slotHistoryNext(); + void slotFind(); + void slotFindNext(); + void slotSaveFileAs(); + void slotPreferences(); + void slotNewConfig(); + void slotPrintPreview(); + void slotShowMenu(const KPDFPage *page, const QPoint &point); + void slotShowProperties(); + void slotShowLeftPanel(); + void slotShowPresentation(); + void slotHidePresentation(); + void slotTogglePresentation(); + void close(); + // can be connected to widget elements + void updateViewActions(); + void enableTOC(bool enable); + void psTransformEnded(); + void cannotQuit(); + void saveSplitterSize(); + void setMimeTypes(KIO::Job *job); + void readMimeType(KIO::Job *job, const QString &mime); + void emitWindowCaption(); + +public slots: + // connected to Shell action (and browserExtension), not local one + void slotPrint(); + void restoreDocument(KConfig* config); + void saveDocumentRestoreInfo(KConfig* config); + void slotFileDirty( const QString& ); + void slotDoFileDirty(); + +private: + void doPrint( KPrinter& printer ); + + // the document + KPDFDocument * m_document; + QString m_temporaryLocalFile; + + // main widgets + QSplitter *m_splitter; + QWidget *m_leftPanel; + QToolBox *m_toolBox; + SearchWidget *m_searchWidget; + QGuardedPtr m_thumbnailList; + QGuardedPtr m_pageView; + QGuardedPtr m_tocFrame; + QGuardedPtr m_miniBar; + QGuardedPtr m_presentationWidget; + + // static instances counter + static unsigned int m_count; + + // this is a hack because we can not use writeConfig on part destructor + // and we don't want to writeconfig every time someone moves the splitter + // so we use a QTimer each 500 ms + QTimer *m_saveSplitterSizeTimer; + + KDirWatch *m_watcher; + QTimer *m_dirtyHandler; + DocumentViewport m_viewportDirty; + bool m_wasPresentationOpen; + int m_dirtyToolboxIndex; + + // Remember the search history + QStringList m_searchHistory; + + // mimetype got from the job + QString m_jobMime; + + // actions + KAction *m_gotoPage; + KAction *m_prevPage; + KAction *m_nextPage; + KAction *m_firstPage; + KAction *m_lastPage; + KAction *m_historyBack; + KAction *m_historyNext; + KAction *m_find; + KAction *m_findNext; + KAction *m_saveAs; + KAction *m_printPreview; + KAction *m_showProperties; + KAction *m_showPresentation; + KToggleAction* m_showMenuBarAction; + KToggleAction* m_showLeftPanel; + KToggleAction* m_showFullScreenAction; + bool m_actionsSearched; + bool m_searchStarted; + BrowserExtension *m_bExtension; +}; + + +class BrowserExtension : public KParts::BrowserExtension +{ +Q_OBJECT + +public: + BrowserExtension(Part*); + +public slots: + // Automatically detected by the host. + void print(); +}; + +} + +#endif + +// vim:ts=2:sw=2:tw=78:et diff --git a/kpdf/part.rc b/kpdf/part.rc new file mode 100644 index 00000000..aa7409c8 --- /dev/null +++ b/kpdf/part.rc @@ -0,0 +1,64 @@ + + + + &File + + + + + + &Edit + + + + &View + + + + + + + + + + + + &Go + + + + + + + + + + + + &Tools + + + + + &Settings + + + + +Main Toolbar + + + + + + + + + + + + + + + + diff --git a/kpdf/shell/Makefile.am b/kpdf/shell/Makefile.am new file mode 100644 index 00000000..e8416ef1 --- /dev/null +++ b/kpdf/shell/Makefile.am @@ -0,0 +1,15 @@ +INCLUDES = -I$(srcdir)/xpdf -I$(srcdir)/xpdf/goo -I$(top_builddir)/kpdf $(all_includes) $(FREETYPE_CFLAGS) + +METASOURCES = AUTO + +bin_PROGRAMS = kpdf + +kpdf_SOURCES = main.cpp shell.cpp +kpdf_LDFLAGS = $(KDE_RPATH) $(all_libraries) +kpdf_LDADD = $(LIB_KPARTS) + +EXTRA_DIST = kpdf.desktop +xdg_apps_DATA = kpdf.desktop + +shellrcdir = $(kde_datadir)/kpdf +shellrc_DATA = shell.rc diff --git a/kpdf/shell/kpdf.desktop b/kpdf/shell/kpdf.desktop new file mode 100644 index 00000000..a276611d --- /dev/null +++ b/kpdf/shell/kpdf.desktop @@ -0,0 +1,82 @@ +[Desktop Entry] +MimeType=application/pdf; +Terminal=false +Name=KPDF +Name[ar]=برنامج KPDF +Name[hi]=के-पीडीएफ +Name[zh_TW]=KPDF 檢視器 +GenericName=PDF Viewer +GenericName[ar]=عارض ملفات PDF +GenericName[az]=PDF Nümayişçisi +GenericName[bg]=Преглед на документи PDF +GenericName[br]=Gweler PDF +GenericName[bs]=Preglednik PDF dokumenata +GenericName[ca]=Visualitzador de PDF +GenericName[cs]=Prohlížeč PDF souborů +GenericName[cy]=Gwelydd PDF +GenericName[da]=PDF-fremviser +GenericName[de]=PDF-Betrachter +GenericName[el]=Προβολέας PDF +GenericName[eo]=PDF-rigardilo +GenericName[es]=Visor de PDF +GenericName[et]=PDF-failide näitaja +GenericName[eu]=PDF ikustailua +GenericName[fa]=مشاهده‌گر PDF +GenericName[fi]=PDF-näytin +GenericName[fr]=Afficheur PDF +GenericName[ga]=Amharcán PDF +GenericName[gl]=Visor PDF +GenericName[he]=מציג PDF +GenericName[hi]=पीडीएफ प्रदर्शक +GenericName[hr]=Preglednik PDF dokumenata +GenericName[hu]=PDF-nézegető +GenericName[id]=Viewer PDF +GenericName[is]=PDF sjá +GenericName[it]=Visore PDF +GenericName[ja]=PDF ビューア +GenericName[kk]=PDF файлдарын қарау +GenericName[km]=កម្មវិធី​មើល PDF +GenericName[lt]=PDF Žiūriklis +GenericName[lv]=PDF Skatītājs +GenericName[mk]=Прикажувач на PDF датотеки +GenericName[ms]=Pemapar PDF +GenericName[mt]=Werrej PDF +GenericName[nb]=PDF-fremviser +GenericName[nds]=PDF-Kieker +GenericName[ne]=PDF दर्शक +GenericName[nl]=PDF-weergaveprogramma +GenericName[nn]=PDF-lesar +GenericName[pa]=PDF ਦਰਸ਼ਕ +GenericName[pl]=Przeglądarka plików PDF +GenericName[pt]=Visualizador de PDFs +GenericName[pt_BR]=Visualizador de arquivos PDF +GenericName[ro]=Vizualizor PDF +GenericName[ru]=Просмотр PDF +GenericName[rw]=Mugaragaza PDF +GenericName[se]=PDF-čájeheaddji +GenericName[sk]=Prehliadač PDF +GenericName[sl]=Pregledovalnik datotek PDF +GenericName[sr]=PDF приказивач +GenericName[sr@Latn]=PDF prikazivač +GenericName[sv]=PDF-visare +GenericName[ta]=PS/PDF காட்சி +GenericName[tg]=Хондани санадоти PDF +GenericName[th]=ตัวแสดงผล PDF +GenericName[tr]=PDF Görüntüleyici +GenericName[uk]=Переглядач PDF +GenericName[uz]=PDF koʻruvchi +GenericName[uz@cyrillic]=PDF кўрувчи +GenericName[ven]=Tshivhoni tsha PDF +GenericName[wa]=Håyneu di documints PDF +GenericName[xh]=Umboniseli we PDF +GenericName[zh_CN]=PDF 查看器 +GenericName[zh_HK]=PDF 檢視器 +GenericName[zh_TW]=PDF 檢視器 +GenericName[zu]=Umboniseli we PDF +Exec=kpdf %U %i -caption "%c" +Icon=kpdf +Type=Application +DocPath=kpdf/index.html +InitialPreference=7 +Categories=Qt;KDE;Graphics;Viewer; + diff --git a/kpdf/shell/main.cpp b/kpdf/shell/main.cpp new file mode 100644 index 00000000..20aa3eee --- /dev/null +++ b/kpdf/shell/main.cpp @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (C) 2002 by Wilco Greven * + * Copyright (C) 2003 by Christophe Devriese * + * * + * Copyright (C) 2003 by Laurent Montel * + * Copyright (C) 2003-2004 by Albert Astals Cid * + * Copyright (C) 2004 by Andy Goossens * + * * + * 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. * + ***************************************************************************/ + +#include "shell.h" +#include +#include +#include +#include + +static const char description[] = +I18N_NOOP("kpdf, a kde pdf viewer based on xpdf"); + +static const char version[] = "0.5.10"; + +static KCmdLineOptions options[] = +{ + { "+[URL]", I18N_NOOP("Document to open"), 0 }, + KCmdLineLastOption +}; + +int main(int argc, char** argv) +{ + KAboutData about( + "kpdf", + I18N_NOOP("KPDF"), + version, + description, + KAboutData::License_GPL, + "(C) 2002 Wilco Greven, Christophe Devriese\n(C) 2004-2005 Albert Astals Cid, Enrico Ros"); + + about.addAuthor("Wilco Greven", 0, "greven@kde.org"); + about.addAuthor("Christophe Devriese", 0, "oelewapperke@oelewapperke.org"); + about.addAuthor("Laurent Montel", 0, "montel@kde.org"); + about.addAuthor("Albert Astals Cid", I18N_NOOP("Current mantainer"), "astals11@terra.es"); + about.addAuthor("Enrico Ros", 0, "eros.kde@email.it"); + + about.addCredit("Derek Noonburg", I18N_NOOP("Xpdf author"), 0, "http://www.foolabs.com/xpdf/"); + about.addCredit("Marco Martin", I18N_NOOP("Icon"), 0, "m4rt@libero.it"); + + KCmdLineArgs::init(argc, argv, &about); + KCmdLineArgs::addCmdLineOptions( options ); + KApplication app; + + // see if we are starting with session management + if (app.isRestored()) + { + RESTORE(KPDF::Shell); + } else { + // no session.. just start up normally + KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); + + if (args->count() == 0) + { + KPDF::Shell* widget = new KPDF::Shell; + widget->show(); + } + else + { + for (int i = 0; i < args->count(); ++i) + { + KPDF::Shell* widget = new KPDF::Shell(args->url(i)); + widget->show(); + } + } + args->clear(); + } + + return app.exec(); +} + +// vim:ts=2:sw=2:tw=78:et diff --git a/kpdf/shell/shell.cpp b/kpdf/shell/shell.cpp new file mode 100644 index 00000000..82b18fa6 --- /dev/null +++ b/kpdf/shell/shell.cpp @@ -0,0 +1,262 @@ +/*************************************************************************** + * Copyright (C) 2002 by Wilco Greven * + * Copyright (C) 2002 by Chris Cheney * + * Copyright (C) 2003 by Benjamin Meyer * + * Copyright (C) 2003-2004 by Christophe Devriese * + * * + * Copyright (C) 2003 by Laurent Montel * + * Copyright (C) 2003-2004 by Albert Astals Cid * + * Copyright (C) 2003 by Luboš Luňák * + * Copyright (C) 2003 by Malcolm Hunter * + * Copyright (C) 2004 by Dominique Devriese * + * Copyright (C) 2004 by Dirk Mueller * + * * + * 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. * + ***************************************************************************/ + +// qt/kde includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// local includes +#include "shell.h" + +using namespace KPDF; + +Shell::Shell() + : KParts::MainWindow(0, "KPDF::Shell"), m_menuBarWasShown(true), m_toolBarWasShown(true) +{ + init(); +} + +Shell::Shell(const KURL &url) + : KParts::MainWindow(0, "KPDF::Shell"), m_menuBarWasShown(true), m_toolBarWasShown(true) +{ + m_openUrl = url; + init(); +} + +void Shell::init() +{ + // set the shell's ui resource file + setXMLFile("shell.rc"); + + // this routine will find and load our Part. it finds the Part by + // name which is a bad idea usually.. but it's alright in this + // case since our Part is made for this Shell + KParts::Factory *factory = (KParts::Factory *) KLibLoader::self()->factory("libkpdfpart"); + if (factory) + { + // now that the Part is loaded, we cast it to a Part to get + // our hands on it + m_part = (KParts::ReadOnlyPart*) factory->createPart(this, "kpdf_part", this, 0, "KParts::ReadOnlyPart"); + if (m_part) + { + // then, setup our actions + setupActions(); + // tell the KParts::MainWindow that this is indeed the main widget + setCentralWidget(m_part->widget()); + // and integrate the part's GUI with the shell's + setupGUI(Keys | Save); + createGUI(m_part); + m_showToolBarAction = static_cast(toolBarMenuAction()); + } + } + else + { + // if we couldn't find our Part, we exit since the Shell by + // itself can't do anything useful + KMessageBox::error(this, i18n("Unable to find kpdf part.")); + m_part = 0; + return; + } + connect( this, SIGNAL( restoreDocument(KConfig*) ),m_part, SLOT( restoreDocument(KConfig*))); + connect( this, SIGNAL( saveDocumentRestoreInfo(KConfig*) ), m_part, SLOT( saveDocumentRestoreInfo(KConfig*))); + connect( m_part, SIGNAL( enablePrintAction(bool) ), m_printAction, SLOT( setEnabled(bool))); + + readSettings(); + if (!KGlobal::config()->hasGroup("MainWindow")) + { + KMainWindowInterface kmwi(this); + kmwi.maximize(); + } + setAutoSaveSettings(); + + if (m_openUrl.isValid()) QTimer::singleShot(0, this, SLOT(delayedOpen())); +} + +void Shell::delayedOpen() +{ + openURL(m_openUrl); +} + +Shell::~Shell() +{ + if(m_part) writeSettings(); +} + +void Shell::openURL( const KURL & url ) +{ + if ( m_part ) + { + bool openOk = m_part->openURL( url ); + if ( openOk ) + m_recent->addURL( url ); + else + m_recent->removeURL( url ); + } +} + + +void Shell::readSettings() +{ + m_recent->loadEntries( KGlobal::config() ); + m_recent->setEnabled( true ); // force enabling + m_recent->setToolTip( i18n("Click to open a file\nClick and hold to open a recent file") ); + + KGlobal::config()->setDesktopGroup(); + bool fullScreen = KGlobal::config()->readBoolEntry( "FullScreen", false ); + setFullScreen( fullScreen ); +} + +void Shell::writeSettings() +{ + m_recent->saveEntries( KGlobal::config() ); + KGlobal::config()->setDesktopGroup(); + KGlobal::config()->writeEntry( "FullScreen", m_fullScreenAction->isChecked()); + KGlobal::config()->sync(); +} + +void Shell::setupActions() +{ + KAction * openAction = KStdAction::open(this, SLOT(fileOpen()), actionCollection()); + m_recent = KStdAction::openRecent( this, SLOT( openURL( const KURL& ) ), actionCollection() ); + connect( m_recent, SIGNAL( activated() ), openAction, SLOT( activate() ) ); + m_recent->setWhatsThis( i18n( "Click to open a file or Click and hold to select a recent file" ) ); + m_printAction = KStdAction::print( m_part, SLOT( slotPrint() ), actionCollection() ); + m_printAction->setEnabled( false ); + KStdAction::quit(this, SLOT(slotQuit()), actionCollection()); + + setStandardToolBarMenuEnabled(true); + + m_showMenuBarAction = KStdAction::showMenubar( this, SLOT( slotShowMenubar() ), actionCollection()); + KStdAction::configureToolbars(this, SLOT(optionsConfigureToolbars()), actionCollection()); + m_fullScreenAction = KStdAction::fullScreen( this, SLOT( slotUpdateFullScreen() ), actionCollection(), this ); +} + +void Shell::saveProperties(KConfig* config) +{ + // the 'config' object points to the session managed + // config file. anything you write here will be available + // later when this app is restored + emit saveDocumentRestoreInfo(config); +} + +void Shell::readProperties(KConfig* config) +{ + // the 'config' object points to the session managed + // config file. this function is automatically called whenever + // the app is being restored. read in here whatever you wrote + // in 'saveProperties' + if(m_part) + { + emit restoreDocument(config); + } +} + + void +Shell::fileOpen() +{ + // this slot is called whenever the File->Open menu is selected, + // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar + // button is clicked + KURL url = KFileDialog::getOpenURL( QString::null, "application/pdf application/postscript" );//getOpenFileName(); + + if (!url.isEmpty()) + openURL(url); +} + + void +Shell::optionsConfigureToolbars() +{ + KEditToolbar dlg(factory()); + connect(&dlg, SIGNAL(newToolbarConfig()), this, SLOT(applyNewToolbarConfig())); + dlg.exec(); +} + + void +Shell::applyNewToolbarConfig() +{ + applyMainWindowSettings(KGlobal::config(), "MainWindow"); +} + +void Shell::slotQuit() +{ + kapp->closeAllWindows(); +} + +// only called when starting the program +void Shell::setFullScreen( bool useFullScreen ) +{ + if( useFullScreen ) + showFullScreen(); + else + showNormal(); +} + +void Shell::slotUpdateFullScreen() +{ + if(m_fullScreenAction->isChecked()) + { + m_menuBarWasShown = m_showMenuBarAction->isChecked(); + m_showMenuBarAction->setChecked(false); + menuBar()->hide(); + + m_toolBarWasShown = m_showToolBarAction->isChecked(); + m_showToolBarAction->setChecked(false); + toolBar()->hide(); + + showFullScreen(); + } + else + { + if (m_menuBarWasShown) + { + m_showMenuBarAction->setChecked(true); + menuBar()->show(); + } + if (m_toolBarWasShown) + { + m_showToolBarAction->setChecked(true); + toolBar()->show(); + } + showNormal(); + } +} + +void Shell::slotShowMenubar() +{ + if ( m_showMenuBarAction->isChecked() ) + menuBar()->show(); + else + menuBar()->hide(); +} + +#include "shell.moc" diff --git a/kpdf/shell/shell.h b/kpdf/shell/shell.h new file mode 100644 index 00000000..f92df5ce --- /dev/null +++ b/kpdf/shell/shell.h @@ -0,0 +1,112 @@ +/*************************************************************************** + * Copyright (C) 2002 by Wilco Greven * + * Copyright (C) 2003 by Benjamin Meyer * + * Copyright (C) 2003 by Laurent Montel * + * Copyright (C) 2003 by Luboš Luňák * + * Copyright (C) 2004 by Christophe Devriese * + * * + * Copyright (C) 2004 by Albert Astals Cid * + * * + * 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. * + ***************************************************************************/ + +#ifndef _KPDF_SHELL_H_ +#define _KPDF_SHELL_H_ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +namespace KPDF +{ + class Part; + /** + * This is the application "Shell". It has a menubar and a toolbar + * but relies on the "Part" to do all the real work. + * + * @short Application Shell + * @author Wilco Greven + * @version 0.1 + */ + class Shell : public KParts::MainWindow + { + Q_OBJECT + + public: + /** + * Default Constructor + */ + Shell(); + + /** + * Open an url + */ + Shell(const KURL &url); + + /** + * Default Destructor + */ + virtual ~Shell(); + + protected: + /** + * This method is called when it is time for the app to save its + * properties for session management purposes. + */ + void saveProperties(KConfig*); + + /** + * This method is called when this app is restored. The KConfig + * object points to the session management config file that was saved + * with @ref saveProperties + */ + void readProperties(KConfig*); + void readSettings(); + void writeSettings(); + void setFullScreen( bool ); + + public slots: + void slotQuit(); + + private slots: + void fileOpen(); + + void optionsConfigureToolbars(); + void applyNewToolbarConfig(); + void slotUpdateFullScreen(); + void slotShowMenubar(); + + void openURL( const KURL & url ); + void delayedOpen(); + + signals: + void restoreDocument(KConfig* config); + void saveDocumentRestoreInfo(KConfig* config); + + + private: + void setupAccel(); + void setupActions(); + void init(); + + private: + KParts::ReadOnlyPart* m_part; + KRecentFilesAction* m_recent; + KAction* m_printAction; + KToggleAction* m_fullScreenAction; + KToggleAction* m_showMenuBarAction; + KToggleAction* m_showToolBarAction; + bool m_menuBarWasShown, m_toolBarWasShown; + KURL m_openUrl; + }; + +} + +#endif + +// vim:ts=2:sw=2:tw=78:et diff --git a/kpdf/shell/shell.rc b/kpdf/shell/shell.rc new file mode 100644 index 00000000..134d34c7 --- /dev/null +++ b/kpdf/shell/shell.rc @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + Main Toolbar + + + + diff --git a/kpdf/ui/Makefile.am b/kpdf/ui/Makefile.am new file mode 100644 index 00000000..16a4ad50 --- /dev/null +++ b/kpdf/ui/Makefile.am @@ -0,0 +1,17 @@ +INCLUDES = -I$(srcdir)/.. -I$(top_builddir)/kpdf $(all_includes) + +METASOURCES = AUTO + +libkpdfui_la_SOURCES = pagepainter.cpp pageview.cpp pageviewutils.cpp \ + minibar.cpp thumbnaillist.cpp searchwidget.cpp \ + toc.cpp propertiesdialog.cpp presentationwidget.cpp + +noinst_LTLIBRARIES = libkpdfui.la + +pagepainter.lo: ../conf/settings.h +pageview.lo: ../conf/settings.h +pageviewutils.lo: ../conf/settings.h +presentationwidget.lo: ../conf/settings.h +searchwidget.lo: ../conf/settings.h +thumbnaillist.lo: ../conf/settings.h + diff --git a/kpdf/ui/minibar.cpp b/kpdf/ui/minibar.cpp new file mode 100644 index 00000000..1a259add --- /dev/null +++ b/kpdf/ui/minibar.cpp @@ -0,0 +1,436 @@ +/*************************************************************************** + * Copyright (C) 2005 by Enrico Ros * + * Copyright (C) 2006 by Albert Astals Cid * + * * + * 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. * + ***************************************************************************/ + +// qt / kde includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// local includes +#include "core/document.h" +#include "minibar.h" + +// [private widget] show progress +class ProgressWidget : public QWidget +{ + public: + ProgressWidget( MiniBar * parent ); + void setProgress( float percentage ); + + protected: + void mouseMoveEvent( QMouseEvent * e ); + void mousePressEvent( QMouseEvent * e ); + void wheelEvent( QWheelEvent * e ); + void paintEvent( QPaintEvent * e ); + + private: + MiniBar * m_miniBar; + float m_progressPercentage; +}; + +// [private widget] lineEdit for entering/validating page numbers +class PagesEdit : public QLineEdit +{ + public: + PagesEdit( MiniBar * parent ); + void setPagesNumber( int pages ); + void setText( const QString & ); + + protected: + void focusInEvent( QFocusEvent * e ); + void focusOutEvent( QFocusEvent * e ); + void mousePressEvent( QMouseEvent * e ); + void wheelEvent( QWheelEvent * e ); + + private: + MiniBar * m_miniBar; + bool m_eatClick; + QString backString; + QIntValidator * m_validator; +}; + +// [private widget] a flat qpushbutton that enlights on hover +class HoverButton : public QPushButton +{ + public: + HoverButton( QWidget * parent ); + + protected: + void paintEvent( QPaintEvent * e ); + void enterEvent( QPaintEvent * e ); + void leaveEvent( QPaintEvent * e ); +}; + + +/** MiniBar **/ + +MiniBar::MiniBar( QWidget * parent, KPDFDocument * document ) + : QFrame( parent, "miniBar" ), m_document( document ), + m_currentPage( -1 ) +{ + // left spacer + QHBoxLayout * horLayout = new QHBoxLayout( this ); + QSpacerItem * spacerL = new QSpacerItem( 20, 10, QSizePolicy::Expanding ); + horLayout->addItem( spacerL ); + + // central 2r by 3c grid layout that contains all components + QGridLayout * gridLayout = new QGridLayout( 0, 3,5, 2,1 ); + // top spacer 6x6 px +// QSpacerItem * spacerTop = new QSpacerItem( 6, 6, QSizePolicy::Fixed, QSizePolicy::Fixed ); +// gridLayout->addMultiCell( spacerTop, 0, 0, 0, 4 ); + // center progress widget + m_progressWidget = new ProgressWidget( this ); + gridLayout->addMultiCellWidget( m_progressWidget, 0, 0, 0, 4 ); + // bottom: left prev_page button + m_prevButton = new HoverButton( this ); + m_prevButton->setIconSet( SmallIconSet( QApplication::reverseLayout() ? "1rightarrow" : "1leftarrow" ) ); + gridLayout->addWidget( m_prevButton, 1, 0 ); + // bottom: left lineEdit (current page box) + m_pagesEdit = new PagesEdit( this ); + gridLayout->addWidget( m_pagesEdit, 1, 1 ); + // bottom: central '/' label + gridLayout->addWidget( new QLabel( "/", this ), 1, 2 ); + // bottom: right button + m_pagesButton = new HoverButton( this ); + gridLayout->addWidget( m_pagesButton, 1, 3 ); + // bottom: right next_page button + m_nextButton = new HoverButton( this ); + m_nextButton->setIconSet( SmallIconSet( QApplication::reverseLayout() ? "1leftarrow" : "1rightarrow" ) ); + gridLayout->addWidget( m_nextButton, 1, 4 ); + horLayout->addLayout( gridLayout ); + + // right spacer + QSpacerItem * spacerR = new QSpacerItem( 20, 10, QSizePolicy::Expanding ); + horLayout->addItem( spacerR ); + + // customize own look + setFrameStyle( QFrame::StyledPanel | QFrame::Sunken ); + + // connect signals from child widgets to internal handlers / signals bouncers + connect( m_pagesEdit, SIGNAL( returnPressed() ), this, SLOT( slotChangePage() ) ); + connect( m_pagesButton, SIGNAL( clicked() ), this, SIGNAL( gotoPage() ) ); + connect( m_prevButton, SIGNAL( clicked() ), this, SIGNAL( prevPage() ) ); + connect( m_nextButton, SIGNAL( clicked() ), this, SIGNAL( nextPage() ) ); + + // widget starts hidden (will be shown after opening a document) + parent->hide(); +} + +MiniBar::~MiniBar() +{ + m_document->removeObserver( this ); +} + +void MiniBar::notifySetup( const QValueVector< KPDFPage * > & pageVector, bool changed ) +{ + // only process data when document changes + if ( !changed ) + return; + + // if document is closed or has no pages, hide widget + int pages = pageVector.count(); + if ( pages < 1 ) + { + m_currentPage = -1; + static_cast( parent() )->hide(); + return; + } + + // resize width of widgets + int numberWidth = 10 + fontMetrics().width( QString::number( pages ) ); + m_pagesEdit->setMinimumWidth( numberWidth ); + m_pagesEdit->setMaximumWidth( 2 * numberWidth ); + m_pagesButton->setMinimumWidth( numberWidth ); + m_pagesButton->setMaximumWidth( 2 * numberWidth ); + + // resize height of widgets + int fixedHeight = fontMetrics().height() + 2; + if ( fixedHeight < 18 ) + fixedHeight = 18; + m_pagesEdit->setFixedHeight( fixedHeight ); + m_pagesButton->setFixedHeight( fixedHeight ); + m_prevButton->setFixedHeight( fixedHeight ); + m_nextButton->setFixedHeight( fixedHeight ); + + // update child widgets + m_pagesEdit->setPagesNumber( pages ); + m_pagesButton->setText( QString::number( pages ) ); + m_prevButton->setEnabled( false ); + m_nextButton->setEnabled( false ); + static_cast( parent() )->show(); +} + +void MiniBar::notifyViewportChanged( bool /*smoothMove*/ ) +{ + // get current page number + int page = m_document->viewport().pageNumber; + int pages = m_document->pages(); + + // if the document is opened and page is changed + if ( page != m_currentPage && pages > 0 ) + { + // update percentage + m_currentPage = page; + float percentage = pages < 2 ? 1.0 : (float)page / (float)(pages - 1); + m_progressWidget->setProgress( percentage ); + // update prev/next button state + m_prevButton->setEnabled( page > 0 ); + m_nextButton->setEnabled( page < ( pages - 1 ) ); + // update text on widgets + m_pagesEdit->setText( QString::number( page + 1 ) ); + } +} + +void MiniBar::resizeEvent( QResizeEvent * e ) +{ + // auto-hide 'prev' and 'next' buttons if not enough space + const QSize & myHint = minimumSizeHint(); + bool shown = m_prevButton->isVisible() && m_nextButton->isVisible(); + if ( shown && e->size().width() < myHint.width() ) + { + m_prevButton->hide(); + m_nextButton->hide(); + updateGeometry(); + } + else if ( !shown ) + { + int histeresis = m_prevButton->sizeHint().width() * 2 + 2; + if ( e->size().width() > (myHint.width() + histeresis) ) + { + m_prevButton->show(); + m_nextButton->show(); + updateGeometry(); + } + } +} + +void MiniBar::slotChangePage() +{ + // get text from the lineEdit + QString pageNumber = m_pagesEdit->text(); + + // convert it to page number and go to that page + bool ok; + int number = pageNumber.toInt( &ok ) - 1; + if ( ok && number >= 0 && number < (int)m_document->pages() && + number != m_currentPage ) + { + m_document->setViewportPage( number ); + m_pagesEdit->clearFocus(); + } +} + +void MiniBar::slotGotoNormalizedPage( float index ) +{ + // figure out page number and go to that page + int number = (int)( index * (float)m_document->pages() ); + if ( number >= 0 && number < (int)m_document->pages() && + number != m_currentPage ) + m_document->setViewportPage( number ); +} + +void MiniBar::slotEmitNextPage() +{ + // emit signal + nextPage(); +} + +void MiniBar::slotEmitPrevPage() +{ + // emit signal + prevPage(); +} + + + +/** ProgressWidget **/ + +ProgressWidget::ProgressWidget( MiniBar * parent ) + : QWidget( parent, "progress", WNoAutoErase ), + m_miniBar( parent ), m_progressPercentage( -1 ) +{ + setFixedHeight( 4 ); + setMouseTracking( true ); +} + +void ProgressWidget::setProgress( float percentage ) +{ + m_progressPercentage = percentage; + update(); +} + +void ProgressWidget::mouseMoveEvent( QMouseEvent * e ) +{ + if ( e->state() == Qt::LeftButton && width() > 0 ) + m_miniBar->slotGotoNormalizedPage( (float)( QApplication::reverseLayout() ? width() - e->x() : e->x() ) / (float)width() ); +} + +void ProgressWidget::mousePressEvent( QMouseEvent * e ) +{ + if ( e->button() == Qt::LeftButton && width() > 0 ) + m_miniBar->slotGotoNormalizedPage( (float)( QApplication::reverseLayout() ? width() - e->x() : e->x() ) / (float)width() ); +} + +void ProgressWidget::wheelEvent( QWheelEvent * e ) +{ + if ( e->delta() > 0 ) + m_miniBar->slotEmitNextPage(); + else + m_miniBar->slotEmitPrevPage(); +} + +void ProgressWidget::paintEvent( QPaintEvent * e ) +{ + if ( m_progressPercentage < 0.0 ) + return; + + // find out the 'fill' and the 'clear' rectangles + int w = width(), + h = height(), + l = (int)( (float)w * m_progressPercentage ); + QRect cRect = ( QApplication::reverseLayout() ? QRect( 0, 0, w - l, h ) : QRect( l, 0, w - l, h ) ).intersect( e->rect() ); + QRect fRect = ( QApplication::reverseLayout() ? QRect( w - l, 0, l, h ) : QRect( 0, 0, l, h ) ).intersect( e->rect() ); + + // paint rects and a separator line + QPainter p( this ); + if ( cRect.isValid() ) + p.fillRect( cRect, palette().active().highlightedText() ); + if ( fRect.isValid() ) + p.fillRect( fRect, palette().active().highlight() ); + if ( l && l != w ) + { + p.setPen( palette().active().highlight().dark( 120 ) ); + int delta = QApplication::reverseLayout() ? w - l : l; + p.drawLine( delta, 0, delta, h ); + } + // draw a frame-like outline + //p.setPen( palette().active().mid() ); + //p.drawRect( 0,0, w, h ); +} + + +/** PagesEdit **/ + +PagesEdit::PagesEdit( MiniBar * parent ) + : QLineEdit( parent ), m_miniBar( parent ), m_eatClick( false ) +{ + // customize look + setFrameShadow( QFrame::Raised ); + focusOutEvent( 0 ); + + // use an integer validator + m_validator = new QIntValidator( 1, 1, this ); + setValidator( m_validator ); + + // customize text properties + setAlignment( Qt::AlignCenter ); + setMaxLength( 4 ); +} + +void PagesEdit::setPagesNumber( int pages ) +{ + m_validator->setTop( pages ); +} + +void PagesEdit::setText( const QString & text ) +{ + // store a copy of the string + backString = text; + // call default handler if hasn't focus + if ( !hasFocus() ) + QLineEdit::setText( text ); +} + +void PagesEdit::focusInEvent( QFocusEvent * e ) +{ + // select all text + selectAll(); + if ( e->reason() == QFocusEvent::Mouse ) + m_eatClick = true; + // change background color to the default 'edit' color + setLineWidth( 2 ); + setPaletteBackgroundColor( Qt::white ); + // call default handler + QLineEdit::focusInEvent( e ); +} + +void PagesEdit::focusOutEvent( QFocusEvent * e ) +{ + // change background color to a dark tone + setLineWidth( 1 ); + setPaletteBackgroundColor( palette().active().background().light( 105 ) ); + // restore text + QLineEdit::setText( backString ); + // call default handler + QLineEdit::focusOutEvent( e ); +} + +void PagesEdit::mousePressEvent( QMouseEvent * e ) +{ + // if this click got the focus in, don't process the event + if ( !m_eatClick ) + QLineEdit::mousePressEvent( e ); + m_eatClick = false; +} + +void PagesEdit::wheelEvent( QWheelEvent * e ) +{ + if ( e->delta() > 0 ) + m_miniBar->slotEmitNextPage(); + else + m_miniBar->slotEmitPrevPage(); +} + + +/** HoverButton **/ + +HoverButton::HoverButton( QWidget * parent ) + : QPushButton( parent ) +{ + setMouseTracking( true ); +#if KDE_IS_VERSION(3,3,90) + KAcceleratorManager::setNoAccel( this ); +#endif +} + +void HoverButton::enterEvent( QPaintEvent * e ) +{ + update(); + QPushButton::enterEvent( e ); +} + +void HoverButton::leaveEvent( QPaintEvent * e ) +{ + update(); + QPushButton::leaveEvent( e ); +} + +void HoverButton::paintEvent( QPaintEvent * e ) +{ + if ( hasMouse() ) + { + QPushButton::paintEvent( e ); + } + else + { + QPainter p( this ); + p.fillRect(e->rect(), parentWidget() ? parentWidget()->palette().brush(QPalette::Active, QColorGroup::Background) : paletteBackgroundColor()); + drawButtonLabel( &p ); + } +} + +#include "minibar.moc" diff --git a/kpdf/ui/minibar.h b/kpdf/ui/minibar.h new file mode 100644 index 00000000..7c815e5e --- /dev/null +++ b/kpdf/ui/minibar.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 2005 by Enrico Ros * + * Copyright (C) 2006 by Albert Astals Cid * + * * + * 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. * + ***************************************************************************/ + +#ifndef _KPDF_MINIBAR_H_ +#define _KPDF_MINIBAR_H_ + +#include +#include "core/observer.h" + +class KPDFDocument; +class PagesEdit; +class HoverButton; +class ProgressWidget; + +/** + * @short A widget to display page number and change current page. + */ +class MiniBar : public QFrame, public DocumentObserver +{ + Q_OBJECT + public: + MiniBar( QWidget *parent, KPDFDocument * document ); + ~MiniBar(); + + // [INHERITED] from DocumentObserver + uint observerId() const { return MINIBAR_ID; } + void notifySetup( const QValueVector< KPDFPage * > & pages, bool ); + void notifyViewportChanged( bool smoothMove ); + + signals: + void gotoPage(); + void prevPage(); + void nextPage(); + + public slots: + void slotChangePage(); + void slotGotoNormalizedPage( float normIndex ); + void slotEmitNextPage(); + void slotEmitPrevPage(); + + protected: + void resizeEvent( QResizeEvent * ); + + private: + KPDFDocument * m_document; + PagesEdit * m_pagesEdit; + HoverButton * m_prevButton; + HoverButton * m_pagesButton; + HoverButton * m_nextButton; + ProgressWidget * m_progressWidget; + int m_currentPage; +}; + +#endif diff --git a/kpdf/ui/pagepainter.cpp b/kpdf/ui/pagepainter.cpp new file mode 100644 index 00000000..f68df254 --- /dev/null +++ b/kpdf/ui/pagepainter.cpp @@ -0,0 +1,252 @@ +/*************************************************************************** + * Copyright (C) 2005 by Enrico Ros * + * * + * 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. * + ***************************************************************************/ + +// qt / kde includes +#include +#include +#include +#include +#include +#include + +// local includes +#include "pagepainter.h" +#include "core/page.h" +#include "conf/settings.h" + +void PagePainter::paintPageOnPainter( const KPDFPage * page, int id, int flags, + QPainter * destPainter, const QRect & limits, int width, int height ) +{ + QPixmap * pixmap = 0; + + // if a pixmap is present for given id, use it + if ( page->m_pixmaps.contains( id ) ) + pixmap = page->m_pixmaps[ id ]; + + // else find the closest match using pixmaps of other IDs (great optim!) + else if ( !page->m_pixmaps.isEmpty() && width != -1 ) + { + int minDistance = -1; + QMap< int,QPixmap * >::const_iterator it = page->m_pixmaps.begin(), end = page->m_pixmaps.end(); + for ( ; it != end; ++it ) + { + int pixWidth = (*it)->width(), + distance = pixWidth > width ? pixWidth - width : width - pixWidth; + if ( minDistance == -1 || distance < minDistance ) + { + pixmap = *it; + minDistance = distance; + } + } + } + + // if have no pixmap, draw blank page with gray cross and exit + if ( !pixmap ) + { + QColor color = Qt::white; + if ( KpdfSettings::changeColors() ) + { + switch ( KpdfSettings::renderMode() ) + { + case KpdfSettings::EnumRenderMode::Inverted: + color = Qt::black; + break; + case KpdfSettings::EnumRenderMode::Paper: + color = KpdfSettings::paperColor(); + break; + case KpdfSettings::EnumRenderMode::Recolor: + color = KpdfSettings::recolorBackground(); + break; + default: ; + } + } + destPainter->fillRect( limits, color ); + + // draw a cross (to that the pixmap as not yet been loaded) + // helps a lot on pages that take much to render + destPainter->setPen( Qt::gray ); + destPainter->drawLine( 0, 0, width-1, height-1 ); + destPainter->drawLine( 0, height-1, width-1, 0 ); + // idea here: draw a hourglass (or kpdf icon :-) on top-left corner + return; + } + + // find out what to paint over the pixmap (manipulations / overlays) + bool paintAccessibility = (flags & Accessibility) && KpdfSettings::changeColors() && (KpdfSettings::renderMode() != KpdfSettings::EnumRenderMode::Paper); + bool paintHighlights = (flags & Highlights) && !page->m_highlights.isEmpty(); + bool enhanceLinks = (flags & EnhanceLinks) && KpdfSettings::highlightLinks(); + bool enhanceImages = (flags & EnhanceImages) && KpdfSettings::highlightImages(); + // check if there are really some highlightRects to paint + if ( paintHighlights ) + { + // precalc normalized 'limits rect' for intersection + double nXMin = (double)limits.left() / (double)width, + nXMax = (double)limits.right() / (double)width, + nYMin = (double)limits.top() / (double)height, + nYMax = (double)limits.bottom() / (double)height; + // if no rect intersects limits, disable paintHighlights + paintHighlights = false; + QValueList< HighlightRect * >::const_iterator hIt = page->m_highlights.begin(), hEnd = page->m_highlights.end(); + for ( ; hIt != hEnd; ++hIt ) + { + if ( (*hIt)->intersects( nXMin, nYMin, nXMax, nYMax ) ) + { + paintHighlights = true; + break; + } + } + } + + // use backBuffer if 'pixmap direct manipulation' is needed + bool backBuffer = paintAccessibility || paintHighlights; + QPixmap * backPixmap = 0; + QPainter * p = destPainter; + if ( backBuffer ) + { + // let's paint using a buffered painter + backPixmap = new QPixmap( limits.width(), limits.height() ); + p = new QPainter( backPixmap ); + p->translate( -limits.left(), -limits.top() ); + } + + // 1. fast blit the pixmap if it has the right size.. + if ( pixmap->width() == width && pixmap->height() == height ) + p->drawPixmap( limits.topLeft(), *pixmap, limits ); + // ..else set a scale matrix to the painter and paint a quick 'zoomed' pixmap + else + { + p->save(); + // TODO paint only the needed part (note: hope that Qt4 transforms are faster) + p->scale( width / (double)pixmap->width(), height / (double)pixmap->height() ); + p->drawPixmap( 0,0, *pixmap, 0,0, pixmap->width(), pixmap->height() ); + p->restore(); + } + + // 2. mangle pixmap: convert it to 32-bit qimage and perform pixel-level manipulations + if ( backBuffer ) + { + QImage backImage = backPixmap->convertToImage(); + // 2.1. modify pixmap following accessibility settings + if ( paintAccessibility ) + { + switch ( KpdfSettings::renderMode() ) + { + case KpdfSettings::EnumRenderMode::Inverted: + // Invert image pixels using QImage internal function + backImage.invertPixels(false); + break; + case KpdfSettings::EnumRenderMode::Recolor: + // Recolor image using KImageEffect::flatten with dither:0 + KImageEffect::flatten( backImage, KpdfSettings::recolorForeground(), KpdfSettings::recolorBackground() ); + break; + case KpdfSettings::EnumRenderMode::BlackWhite: + // Manual Gray and Contrast + unsigned int * data = (unsigned int *)backImage.bits(); + int val, pixels = backImage.width() * backImage.height(), + con = KpdfSettings::bWContrast(), thr = 255 - KpdfSettings::bWThreshold(); + for( int i = 0; i < pixels; ++i ) + { + val = qGray( data[i] ); + if ( val > thr ) + val = 128 + (127 * (val - thr)) / (255 - thr); + else if ( val < thr ) + val = (128 * val) / thr; + if ( con > 2 ) + { + val = con * ( val - thr ) / 2 + thr; + if ( val > 255 ) + val = 255; + else if ( val < 0 ) + val = 0; + } + data[i] = qRgba( val, val, val, 255 ); + } + break; + } + } + // 2.2. highlight rects in page + if ( paintHighlights ) + { + // draw highlights that are inside the 'limits' paint region + QValueList< HighlightRect * >::const_iterator hIt = page->m_highlights.begin(), hEnd = page->m_highlights.end(); + for ( ; hIt != hEnd; ++hIt ) + { + HighlightRect * r = *hIt; + QRect highlightRect = r->geometry( width, height ); + if ( highlightRect.isValid() && highlightRect.intersects( limits ) ) + { + // find out the rect to highlight on pixmap + highlightRect = highlightRect.intersect( limits ); + highlightRect.moveBy( -limits.left(), -limits.top() ); + + // highlight composition (product: highlight color * destcolor) + unsigned int * data = (unsigned int *)backImage.bits(); + int val, newR, newG, newB, + rh = r->color.red(), + gh = r->color.green(), + bh = r->color.blue(), + offset = highlightRect.top() * backImage.width(); + for( int y = highlightRect.top(); y <= highlightRect.bottom(); ++y ) + { + for( int x = highlightRect.left(); x <= highlightRect.right(); ++x ) + { + val = data[ x + offset ]; + newR = (qRed(val) * rh) / 255; + newG = (qGreen(val) * gh) / 255; + newB = (qBlue(val) * bh) / 255; + data[ x + offset ] = qRgba( newR, newG, newB, 255 ); + } + offset += backImage.width(); + } + } + } + } + backPixmap->convertFromImage( backImage ); + } + + // 3. visually enchance links and images if requested + if ( enhanceLinks || enhanceImages ) + { + QColor normalColor = QApplication::palette().active().highlight(); + QColor lightColor = normalColor.light( 140 ); + // enlarging limits for intersection is like growing the 'rectGeometry' below + QRect limitsEnlarged = limits; + limitsEnlarged.addCoords( -2, -2, 2, 2 ); + // draw rects that are inside the 'limits' paint region as opaque rects + QValueList< ObjectRect * >::const_iterator lIt = page->m_rects.begin(), lEnd = page->m_rects.end(); + for ( ; lIt != lEnd; ++lIt ) + { + ObjectRect * rect = *lIt; + if ( (enhanceLinks && rect->objectType() == ObjectRect::Link) || + (enhanceImages && rect->objectType() == ObjectRect::Image) ) + { + QRect rectGeometry = rect->geometry( width, height ); + if ( rectGeometry.intersects( limitsEnlarged ) ) + { + // expand rect and draw inner border + rectGeometry.addCoords( -1,-1,1,1 ); + p->setPen( lightColor ); + p->drawRect( rectGeometry ); + // expand rect to draw outer border + rectGeometry.addCoords( -1,-1,1,1 ); + p->setPen( normalColor ); + p->drawRect( rectGeometry ); + } + } + } + } + + // 4. if was backbuffering, copy the backPixmap to destination + if ( backBuffer ) + { + delete p; + destPainter->drawPixmap( limits.left(), limits.top(), *backPixmap ); + delete backPixmap; + } +} diff --git a/kpdf/ui/pagepainter.h b/kpdf/ui/pagepainter.h new file mode 100644 index 00000000..21ef7629 --- /dev/null +++ b/kpdf/ui/pagepainter.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2005 by Enrico Ros * + * * + * 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. * + ***************************************************************************/ + +#ifndef _KPDF_PAGEPAINTER_H_ +#define _KPDF_PAGEPAINTER_H_ + +class KPDFPage; +class QPainter; +class QRect; + +/** + * @short Paints a KPDFPage to an open painter using given flags. + */ +class PagePainter +{ + public: + // list of flags passed to the painting function. by OR-ing those flags + // you can decide wether or not to permit drawing of a certain feature. + enum PagePainterFlags { Accessibility = 1, EnhanceLinks = 2, + EnhanceImages = 4, Highlights = 8 }; + + // draw (using painter 'p') the 'page' requested by 'id' using features + // in 'flags'. 'limits' is the bounding rect of the paint operation, + // 'width' and 'height' the expected size of page contents (used only + // to pick up an alternative pixmap if the pixmap of 'id' is missing. + static void paintPageOnPainter( const KPDFPage * page, int id, int flags, + QPainter * p, const QRect & limits, int width = -1, int height = -1 ); +}; + +#endif diff --git a/kpdf/ui/pageview.cpp b/kpdf/ui/pageview.cpp new file mode 100644 index 00000000..247f1b1b --- /dev/null +++ b/kpdf/ui/pageview.cpp @@ -0,0 +1,2114 @@ +/*************************************************************************** + * Copyright (C) 2004 by Enrico Ros * + * Copyright (C) 2004-2006 by Albert Astals Cid * + * * + * With portions of code from kpdf/kpdf_pagewidget.cc by: * + * Copyright (C) 2002 by Wilco Greven * + * Copyright (C) 2003 by Christophe Devriese * + * * + * Copyright (C) 2003 by Laurent Montel * + * Copyright (C) 2003 by Dirk Mueller * + * Copyright (C) 2004 by James Ots * + * * + * 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. * + ***************************************************************************/ + +// qt/kde includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// system includes +#include +#include + +// local includes +#include "pageview.h" +#include "pageviewutils.h" +#include "pagepainter.h" +#include "core/document.h" +#include "core/page.h" +#include "core/link.h" +#include "core/generator.h" +#include "conf/settings.h" + +#define ROUND(x) (int(x + 0.5)) + +// definition of searchID for this class +#define PAGEVIEW_SEARCH_ID 2 + +// structure used internally by PageView for data storage +class PageViewPrivate +{ +public: + // the document, pageviewItems and the 'visible cache' + KPDFDocument * document; + QValueVector< PageViewItem * > items; + QValueList< PageViewItem * > visibleItems; + + // view layout (columns and continuous in Settings), zoom and mouse + PageView::ZoomMode zoomMode; + float zoomFactor; + PageView::MouseMode mouseMode; + QPoint mouseGrabPos; + QPoint mousePressPos; + int mouseMidStartY; + bool mouseOnRect; + QRect mouseSelectionRect; + QColor selectionRectColor; + + // type ahead find + bool typeAheadActive; + QString typeAheadString; + QTimer * findTimeoutTimer; + // viewport move + bool viewportMoveActive; + QTime viewportMoveTime; + QPoint viewportMoveDest; + QTimer * viewportMoveTimer; + // auto scroll + int scrollIncrement; + QTimer * autoScrollTimer; + // other stuff + QTimer * delayResizeTimer; + bool dirtyLayout; + bool blockViewport; // prevents changes to viewport + bool blockPixmapsRequest; // prevent pixmap requests + PageViewMessage * messageWindow; // in pageviewutils.h + PageViewTip * tip; + + // drag scroll + QPoint dragScrollVector; + QTimer dragScrollTimer; + + // actions + KToggleAction * aMouseNormal; + KToggleAction * aMouseSelect; + KToggleAction * aMouseEdit; + KSelectAction * aZoom; + KToggleAction * aZoomFitWidth; + KToggleAction * aZoomFitPage; + KToggleAction * aZoomFitText; + KToggleAction * aViewTwoPages; + KToggleAction * aViewContinuous; + KAction * aPrevAction; +}; + + + +class PageViewTip : public QToolTip +{ + public: + PageViewTip( PageView * view ) + : QToolTip( view->viewport() ), m_view( view ) + { + } + + ~PageViewTip() + { + remove( m_view->viewport() ); + } + + + protected: + void maybeTip( const QPoint &p ); + + private: + PageView * m_view; +}; + +void PageViewTip::maybeTip( const QPoint &_p ) +{ + QPoint p( _p.x() + m_view->contentsX(), _p.y() + m_view->contentsY() ); + PageViewItem * pageItem = m_view->pickItemOnPoint( p.x(), p.y() ); + if ( pageItem && m_view->d->mouseMode == PageView::MouseNormal ) + { + double nX = (double)(p.x() - pageItem->geometry().left()) / (double)pageItem->width(), + nY = (double)(p.y() - pageItem->geometry().top()) / (double)pageItem->height(); + + // if over a ObjectRect (of type Link) change cursor to hand + const ObjectRect * object = pageItem->page()->hasObject( ObjectRect::Link, nX, nY ); + if ( object ) + { + // set tooltip over link's rect + KPDFLink *link = (KPDFLink *)object->pointer(); + QString strtip = link->linkTip(); + if ( !strtip.isEmpty() ) + { + QRect linkRect = object->geometry( pageItem->width(), pageItem->height() ); + linkRect.moveBy( - m_view->contentsX() + pageItem->geometry().left(), - m_view->contentsY() + pageItem->geometry().top() ); + tip( linkRect, strtip ); + } + } + } +} + + + +/* PageView. What's in this file? -> quick overview. + * Code weight (in rows) and meaning: + * 160 - constructor and creating actions plus their connected slots (empty stuff) + * 70 - DocumentObserver inherited methodes (important) + * 550 - events: mouse, keyboard, drag/drop + * 170 - slotRelayoutPages: set contents of the scrollview on continuous/single modes + * 100 - zoom: zooming pages in different ways, keeping update the toolbar actions, etc.. + * other misc functions: only slotRequestVisiblePixmaps and pickItemOnPoint noticeable, + * and many insignificant stuff like this comment :-) + */ +PageView::PageView( QWidget *parent, KPDFDocument *document ) + : QScrollView( parent, "KPDF::pageView", WStaticContents | WNoAutoErase ) +{ + // create and initialize private storage structure + d = new PageViewPrivate(); + d->document = document; + d->zoomMode = (PageView::ZoomMode)KpdfSettings::zoomMode(); + d->zoomFactor = KpdfSettings::zoomFactor(); + d->mouseMode = MouseNormal; + d->mouseMidStartY = -1; + d->mouseOnRect = false; + d->typeAheadActive = false; + d->findTimeoutTimer = 0; + d->viewportMoveActive = false; + d->viewportMoveTimer = 0; + d->scrollIncrement = 0; + d->autoScrollTimer = 0; + d->delayResizeTimer = 0; + d->dirtyLayout = false; + d->blockViewport = false; + d->blockPixmapsRequest = false; + d->messageWindow = new PageViewMessage(this); + d->tip = new PageViewTip( this ); + d->aPrevAction = 0; + + // widget setup: setup focus, accept drops and track mouse + viewport()->setFocusProxy( this ); + viewport()->setFocusPolicy( StrongFocus ); + //viewport()->setPaletteBackgroundColor( Qt::white ); + viewport()->setBackgroundMode( Qt::NoBackground ); + setResizePolicy( Manual ); + setAcceptDrops( true ); + setDragAutoScroll( false ); + viewport()->setMouseTracking( true ); + + // conntect the padding of the viewport to pixmaps requests + connect( this, SIGNAL(contentsMoving(int, int)), this, SLOT(slotRequestVisiblePixmaps(int, int)) ); + connect( &d->dragScrollTimer, SIGNAL(timeout()), this, SLOT(slotDragScroll()) ); + + // set a corner button to resize the view to the page size +// QPushButton * resizeButton = new QPushButton( viewport() ); +// resizeButton->setPixmap( SmallIcon("crop") ); +// setCornerWidget( resizeButton ); +// resizeButton->setEnabled( false ); + // connect(...); + setInputMethodEnabled( true ); + + // schedule the welcome message + QTimer::singleShot( 0, this, SLOT( slotShowWelcome() ) ); +} + +PageView::~PageView() +{ + // delete all widgets + QValueVector< PageViewItem * >::iterator dIt = d->items.begin(), dEnd = d->items.end(); + for ( ; dIt != dEnd; ++dIt ) + delete *dIt; + delete d->tip; + d->tip = 0; + d->document->removeObserver( this ); + delete d; +} + +void PageView::setupActions( KActionCollection * ac ) +{ + // Zoom actions ( higher scales takes lots of memory! ) + d->aZoom = new KSelectAction( i18n( "Zoom" ), "viewmag", 0, this, SLOT( slotZoom() ), ac, "zoom_to" ); + d->aZoom->setEditable( true ); +#if KDE_IS_VERSION(3,4,89) + d->aZoom->setMaxComboViewCount( 13 ); +#endif + updateZoomText(); + + KStdAction::zoomIn( this, SLOT( slotZoomIn() ), ac, "zoom_in" ); + + KStdAction::zoomOut( this, SLOT( slotZoomOut() ), ac, "zoom_out" ); + + d->aZoomFitWidth = new KToggleAction( i18n("Fit to Page &Width"), "view_fit_width", 0, ac, "zoom_fit_width" ); + connect( d->aZoomFitWidth, SIGNAL( toggled( bool ) ), SLOT( slotFitToWidthToggled( bool ) ) ); + + d->aZoomFitPage = new KToggleAction( i18n("Fit to &Page"), "view_fit_window", 0, ac, "zoom_fit_page" ); + connect( d->aZoomFitPage, SIGNAL( toggled( bool ) ), SLOT( slotFitToPageToggled( bool ) ) ); + + d->aZoomFitText = new KToggleAction( i18n("Fit to &Text"), "viewmagfit", 0, ac, "zoom_fit_text" ); + connect( d->aZoomFitText, SIGNAL( toggled( bool ) ), SLOT( slotFitToTextToggled( bool ) ) ); + + // View-Layout actions + d->aViewTwoPages = new KToggleAction( i18n("&Two Pages"), "view_left_right", 0, ac, "view_twopages" ); + connect( d->aViewTwoPages, SIGNAL( toggled( bool ) ), SLOT( slotTwoPagesToggled( bool ) ) ); + d->aViewTwoPages->setChecked( KpdfSettings::viewColumns() > 1 ); + + d->aViewContinuous = new KToggleAction( i18n("&Continuous"), "view_text", 0, ac, "view_continuous" ); + connect( d->aViewContinuous, SIGNAL( toggled( bool ) ), SLOT( slotContinuousToggled( bool ) ) ); + d->aViewContinuous->setChecked( KpdfSettings::viewContinuous() ); + + // Mouse-Mode actions + d->aMouseNormal = new KRadioAction( i18n("&Browse Tool"), "mouse", 0, this, SLOT( slotSetMouseNormal() ), ac, "mouse_drag" ); + d->aMouseNormal->setExclusiveGroup( "MouseType" ); + d->aMouseNormal->setChecked( true ); + + KToggleAction * mz = new KRadioAction( i18n("&Zoom Tool"), "viewmag", 0, this, SLOT( slotSetMouseZoom() ), ac, "mouse_zoom" ); + mz->setExclusiveGroup( "MouseType" ); + + d->aMouseSelect = new KRadioAction( i18n("&Select Tool"), "frame_edit", 0, this, SLOT( slotSetMouseSelect() ), ac, "mouse_select" ); + d->aMouseSelect->setExclusiveGroup( "MouseType" ); + +/* d->aMouseEdit = new KRadioAction( i18n("Draw"), "edit", 0, this, SLOT( slotSetMouseDraw() ), ac, "mouse_draw" ); + d->aMouseEdit->setExclusiveGroup("MouseType"); + d->aMouseEdit->setEnabled( false ); // implement feature before removing this line*/ + + // Other actions + KAction * su = new KAction( i18n("Scroll Up"), 0, this, SLOT( slotScrollUp() ), ac, "view_scroll_up" ); + su->setShortcut( "Shift+Up" ); + + KAction * sd = new KAction( i18n("Scroll Down"), 0, this, SLOT( slotScrollDown() ), ac, "view_scroll_down" ); + sd->setShortcut( "Shift+Down" ); +} + +bool PageView::canFitPageWidth() +{ + return d->zoomMode != ZoomFitWidth; +} + +void PageView::fitPageWidth( int /*page*/ ) +{ + d->aZoom->setCurrentItem(0); + slotZoom(); +} + +//BEGIN DocumentObserver inherited methods +void PageView::notifySetup( const QValueVector< KPDFPage * > & pageSet, bool documentChanged ) +{ + // reuse current pages if nothing new + if ( ( pageSet.count() == d->items.count() ) && !documentChanged ) + { + int count = pageSet.count(); + for ( int i = 0; (i < count) && !documentChanged; i++ ) + if ( (int)pageSet[i]->number() != d->items[i]->pageNumber() ) + documentChanged = true; + if ( !documentChanged ) + return; + } + + // delete all widgets (one for each page in pageSet) + QValueVector< PageViewItem * >::iterator dIt = d->items.begin(), dEnd = d->items.end(); + for ( ; dIt != dEnd; ++dIt ) + delete *dIt; + d->items.clear(); + d->visibleItems.clear(); + + // create children widgets + QValueVector< KPDFPage * >::const_iterator setIt = pageSet.begin(), setEnd = pageSet.end(); + for ( ; setIt != setEnd; ++setIt ) + d->items.push_back( new PageViewItem( *setIt ) ); + + if ( pageSet.count() > 0 ) + // TODO for Enrico: Check if doing always the slotRelayoutPages() is not + // suboptimal in some cases, i'd say it is not but a recheck will not hurt + // Need slotRelayoutPages() here instead of d->dirtyLayout = true + // because opening a pdf from another pdf will not trigger a viewportchange + // so pages are never relayouted + QTimer::singleShot(0, this, SLOT(slotRelayoutPages())); + else + { + // update the mouse cursor when closing because we may have close through a link and + // want the cursor to come back to the normal cursor + updateCursor( viewportToContents( mapFromGlobal( QCursor::pos() ) ) ); + resizeContents( 0, 0 ); + } + + // OSD to display pages + if ( documentChanged && pageSet.count() > 0 && KpdfSettings::showOSD() ) + d->messageWindow->display( + i18n(" Loaded a one-page document.", + " Loaded a %n-page document.", + pageSet.count() ), + PageViewMessage::Info, 4000 ); +} + +void PageView::notifyViewportChanged( bool smoothMove ) +{ + // if we are the one changing viewport, skip this nofity + if ( d->blockViewport ) + return; + + // block setViewport outgoing calls + d->blockViewport = true; + + // find PageViewItem matching the viewport description + const DocumentViewport & vp = d->document->viewport(); + PageViewItem * item = 0; + QValueVector< PageViewItem * >::iterator iIt = d->items.begin(), iEnd = d->items.end(); + for ( ; iIt != iEnd; ++iIt ) + if ( (*iIt)->pageNumber() == vp.pageNumber ) + { + item = *iIt; + break; + } + if ( !item ) + { + kdDebug() << "viewport has no matching item!" << endl; + d->blockViewport = false; + return; + } + + // relayout in "Single Pages" mode or if a relayout is pending + d->blockPixmapsRequest = true; + if ( !KpdfSettings::viewContinuous() || d->dirtyLayout ) + slotRelayoutPages(); + + // restore viewport center or use default {x-center,v-top} alignment + const QRect & r = item->geometry(); + int newCenterX = r.left(), + newCenterY = r.top(); + if ( vp.rePos.enabled ) + { + if (vp.rePos.pos == DocumentViewport::Center) + { + newCenterX += (int)( vp.rePos.normalizedX * (double)r.width() ); + newCenterY += (int)( vp.rePos.normalizedY * (double)r.height() ); + } + else + { + // TopLeft + newCenterX += (int)( vp.rePos.normalizedX * (double)r.width() + viewport()->width() / 2 ); + newCenterY += (int)( vp.rePos.normalizedY * (double)r.height() + viewport()->height() / 2 ); + } + } + else + { + newCenterX += r.width() / 2; + newCenterY += visibleHeight() / 2 - 10; + } + + // if smooth movement requested, setup parameters and start it + if ( smoothMove ) + { + d->viewportMoveActive = true; + d->viewportMoveTime.start(); + d->viewportMoveDest.setX( newCenterX ); + d->viewportMoveDest.setY( newCenterY ); + if ( !d->viewportMoveTimer ) + { + d->viewportMoveTimer = new QTimer( this ); + connect( d->viewportMoveTimer, SIGNAL( timeout() ), + this, SLOT( slotMoveViewport() ) ); + } + d->viewportMoveTimer->start( 25 ); + verticalScrollBar()->setEnabled( false ); + horizontalScrollBar()->setEnabled( false ); + } + else + center( newCenterX, newCenterY ); + d->blockPixmapsRequest = false; + + // request visible pixmaps in the current viewport and recompute it + slotRequestVisiblePixmaps(); + + // enable setViewport calls + d->blockViewport = false; + + // update zoom text if in a ZoomFit/* zoom mode + if ( d->zoomMode != ZoomFixed ) + updateZoomText(); + + // since the page has moved below cursor, update it + updateCursor( viewportToContents( mapFromGlobal( QCursor::pos() ) ) ); +} + +void PageView::notifyPageChanged( int pageNumber, int changedFlags ) +{ + // only handle pixmap / highlight changes notifies + if ( changedFlags & DocumentObserver::Bookmark ) + return; + + // iterate over visible items: if page(pageNumber) is one of them, repaint it + QValueList< PageViewItem * >::iterator iIt = d->visibleItems.begin(), iEnd = d->visibleItems.end(); + for ( ; iIt != iEnd; ++iIt ) + if ( (*iIt)->pageNumber() == pageNumber ) + { + // update item's rectangle plus the little outline + QRect expandedRect = (*iIt)->geometry(); + expandedRect.addCoords( -1, -1, 3, 3 ); + updateContents( expandedRect ); + + // if we were "zoom-dragging" do not overwrite the "zoom-drag" cursor + if ( cursor().shape() != Qt::SizeVerCursor ) + { + // since the page has been regenerated below cursor, update it + updateCursor( viewportToContents( mapFromGlobal( QCursor::pos() ) ) ); + } + break; + } +} + +void PageView::notifyContentsCleared( int changedFlags ) +{ + // if pixmaps were cleared, re-ask them + if ( changedFlags & DocumentObserver::Pixmap ) + slotRequestVisiblePixmaps(); +} + +bool PageView::canUnloadPixmap( int pageNumber ) +{ + // if the item is visible, forbid unloading + QValueList< PageViewItem * >::iterator vIt = d->visibleItems.begin(), vEnd = d->visibleItems.end(); + for ( ; vIt != vEnd; ++vIt ) + if ( (*vIt)->pageNumber() == pageNumber ) + return false; + // if hidden premit unloading + return true; +} +//END DocumentObserver inherited methods + + +void PageView::showText( const QString &text, int ms ) +{ + d->messageWindow->display(text, PageViewMessage::Info, ms ); +} + + +//BEGIN widget events +void PageView::viewportPaintEvent( QPaintEvent * pe ) +{ + // create the rect into contents from the clipped screen rect + QRect viewportRect = viewport()->rect(); + QRect contentsRect = pe->rect().intersect( viewportRect ); + contentsRect.moveBy( contentsX(), contentsY() ); + if ( !contentsRect.isValid() ) + return; + + // create the screen painter. a pixel painted ar contentsX,contentsY + // appears to the top-left corner of the scrollview. + QPainter screenPainter( viewport(), true ); + screenPainter.translate( -contentsX(), -contentsY() ); + + // selectionRect is the normalized mouse selection rect + QRect selectionRect = d->mouseSelectionRect; + if ( !selectionRect.isNull() ) + selectionRect = selectionRect.normalize(); + // selectionRectInternal without the border + QRect selectionRectInternal = selectionRect; + selectionRectInternal.addCoords( 1, 1, -1, -1 ); + // color for blending + QColor selBlendColor = (selectionRect.width() > 8 || selectionRect.height() > 8) ? + d->selectionRectColor : Qt::red; + + // subdivide region into rects + QMemArray allRects = pe->region().rects(); + uint numRects = allRects.count(); + + // preprocess rects area to see if it worths or not using subdivision + uint summedArea = 0; + for ( uint i = 0; i < numRects; i++ ) + { + const QRect & r = allRects[i]; + summedArea += r.width() * r.height(); + } + // very elementary check: SUMj(Region[j].area) is less than boundingRect.area + bool useSubdivision = summedArea < (0.7 * contentsRect.width() * contentsRect.height()); + if ( !useSubdivision ) + numRects = 1; + + // iterate over the rects (only one loop if not using subdivision) + for ( uint i = 0; i < numRects; i++ ) + { + if ( useSubdivision ) + { + // set 'contentsRect' to a part of the sub-divided region + contentsRect = allRects[i].normalize().intersect( viewportRect ); + contentsRect.moveBy( contentsX(), contentsY() ); + if ( !contentsRect.isValid() ) + continue; + } + + // note: this check will take care of all things requiring alpha blending (not only selection) + bool wantCompositing = !selectionRect.isNull() && contentsRect.intersects( selectionRect ); + + if ( wantCompositing && KpdfSettings::enableCompositing() ) + { + // create pixmap and open a painter over it (contents{left,top} becomes pixmap {0,0}) + QPixmap doubleBuffer( contentsRect.size() ); + QPainter pixmapPainter( &doubleBuffer ); + pixmapPainter.translate( -contentsRect.left(), -contentsRect.top() ); + + // 1) Layer 0: paint items and clear bg on unpainted rects + paintItems( &pixmapPainter, contentsRect ); + // 2) Layer 1: pixmap manipulated areas + // 3) Layer 2: paint (blend) transparent selection + if ( !selectionRect.isNull() && selectionRect.intersects( contentsRect ) && + !selectionRectInternal.contains( contentsRect ) ) + { + QRect blendRect = selectionRectInternal.intersect( contentsRect ); + // skip rectangles covered by the selection's border + if ( blendRect.isValid() ) + { + // grab current pixmap into a new one to colorize contents + QPixmap blendedPixmap( blendRect.width(), blendRect.height() ); + copyBlt( &blendedPixmap, 0,0, &doubleBuffer, + blendRect.left() - contentsRect.left(), blendRect.top() - contentsRect.top(), + blendRect.width(), blendRect.height() ); + // blend selBlendColor into the background pixmap + QImage blendedImage = blendedPixmap.convertToImage(); + KImageEffect::blend( selBlendColor.dark(140), blendedImage, 0.2 ); + // copy the blended pixmap back to its place + pixmapPainter.drawPixmap( blendRect.left(), blendRect.top(), blendedImage ); + } + // draw border (red if the selection is too small) + pixmapPainter.setPen( selBlendColor ); + pixmapPainter.drawRect( selectionRect ); + } + // 4) Layer 3: overlays + if ( KpdfSettings::debugDrawBoundaries() ) + { + pixmapPainter.setPen( Qt::blue ); + pixmapPainter.drawRect( contentsRect ); + } + + // finish painting and draw contents + pixmapPainter.end(); + screenPainter.drawPixmap( contentsRect.left(), contentsRect.top(), doubleBuffer ); + } + else + { + // 1) Layer 0: paint items and clear bg on unpainted rects + paintItems( &screenPainter, contentsRect ); + // 2) Layer 1: opaque manipulated ares (filled / contours) + // 3) Layer 2: paint opaque selection + if ( !selectionRect.isNull() && selectionRect.intersects( contentsRect ) && + !selectionRectInternal.contains( contentsRect ) ) + { + screenPainter.setPen( palette().active().highlight().dark(110) ); + screenPainter.drawRect( selectionRect ); + } + // 4) Layer 3: overlays + if ( KpdfSettings::debugDrawBoundaries() ) + { + screenPainter.setPen( Qt::red ); + screenPainter.drawRect( contentsRect ); + } + } + } +} + +void PageView::viewportResizeEvent( QResizeEvent * ) +{ + // start a timer that will refresh the pixmap after 0.5s + if ( !d->delayResizeTimer ) + { + d->delayResizeTimer = new QTimer( this ); + connect( d->delayResizeTimer, SIGNAL( timeout() ), this, SLOT( slotRelayoutPages() ) ); + } + d->delayResizeTimer->start( 333, true ); +} + +void PageView::keyPressEvent( QKeyEvent * e ) +{ + e->accept(); + + // if performing a selection or dyn zooming, disable keys handling + if ( ( !d->mouseSelectionRect.isNull() && e->key() != Qt::Key_Escape ) || d->mouseMidStartY != -1 ) + return; + + // handle 'find as you type' (based on khtml/khtmlview.cpp) + if( d->typeAheadActive ) + { + // backspace: remove a char and search or terminates search + if( e->key() == Key_BackSpace ) + { + if( d->typeAheadString.length() > 1 ) + { + d->typeAheadString = d->typeAheadString.left( d->typeAheadString.length() - 1 ); + bool found = d->document->searchText( PAGEVIEW_SEARCH_ID, d->typeAheadString, true, false, + KPDFDocument::NextMatch, true, qRgb( 128, 255, 128 ), true ); + QString status = found ? i18n("Text found: \"%1\".") : i18n("Text not found: \"%1\"."); + d->messageWindow->display( status.arg(d->typeAheadString.lower()), + found ? PageViewMessage::Find : PageViewMessage::Warning, 4000 ); + d->findTimeoutTimer->start( 3000, true ); + } + else + { + findAheadStop(); + d->document->resetSearch( PAGEVIEW_SEARCH_ID ); + } + } + // F3: go to next occurrency + else if( e->key() == KStdAccel::findNext() ) + { + // part doesn't get this key event because of the keyboard grab + d->findTimeoutTimer->stop(); // restore normal operation during possible messagebox is displayed + // it is needed to grab the keyboard becase people may have Space assigned to a + // accel and without grabbing the keyboard you can not vim-search for space + // because it activates the accel + releaseKeyboard(); + if ( d->document->continueSearch( PAGEVIEW_SEARCH_ID ) ) + d->messageWindow->display( i18n("Text found: \"%1\".").arg(d->typeAheadString.lower()), + PageViewMessage::Find, 3000 ); + d->findTimeoutTimer->start( 3000, true ); + // it is needed to grab the keyboard becase people may have Space assigned to a + // accel and without grabbing the keyboard you can not vim-search for space + // because it activates the accel + grabKeyboard(); + } + // esc and return: end search + else if( e->key() == Key_Escape || e->key() == Key_Return ) + { + findAheadStop(); + } + // other key: add to text and search + else if( !e->text().isEmpty() ) + { + d->typeAheadString += e->text(); + doTypeAheadSearch(); + } + return; + } + else if( e->key() == '/' && d->document->isOpened() && d->document->supportsSearching() ) + { + // stop scrolling the page (if doing it) + if ( d->autoScrollTimer ) + { + d->scrollIncrement = 0; + d->autoScrollTimer->stop(); + } + // start type-adeas search + d->typeAheadString = QString(); + d->messageWindow->display( i18n("Starting -- find text as you type"), PageViewMessage::Find, 3000 ); + d->typeAheadActive = true; + if ( !d->findTimeoutTimer ) + { + // create the timer on demand + d->findTimeoutTimer = new QTimer( this ); + connect( d->findTimeoutTimer, SIGNAL( timeout() ), this, SLOT( findAheadStop() ) ); + } + d->findTimeoutTimer->start( 3000, true ); + // it is needed to grab the keyboard becase people may have Space assigned to a + // accel and without grabbing the keyboard you can not vim-search for space + // because it activates the accel + grabKeyboard(); + return; + } + + // if viewport is moving, disable keys handling + if ( d->viewportMoveActive ) + return; + + // move/scroll page by using keys + switch ( e->key() ) + { + case Key_Up: + case Key_PageUp: + case Key_Backspace: + // if in single page mode and at the top of the screen, go to previous page + if ( KpdfSettings::viewContinuous() || verticalScrollBar()->value() > verticalScrollBar()->minValue() ) + { + if ( e->key() == Key_Up ) + verticalScrollBar()->subtractLine(); + else + verticalScrollBar()->subtractPage(); + } + else if ( d->document->currentPage() > 0 ) + { + // more optimized than document->setPrevPage and then move view to bottom + DocumentViewport newViewport = d->document->viewport(); + newViewport.pageNumber -= 1; + newViewport.rePos.enabled = true; + newViewport.rePos.normalizedY = 1.0; + d->document->setViewport( newViewport ); + } + break; + case Key_Down: + case Key_PageDown: + case Key_Space: + // if in single page mode and at the bottom of the screen, go to next page + if ( KpdfSettings::viewContinuous() || verticalScrollBar()->value() < verticalScrollBar()->maxValue() ) + { + if ( e->key() == Key_Down ) + verticalScrollBar()->addLine(); + else + verticalScrollBar()->addPage(); + } + else if ( d->document->currentPage() < d->items.count() - 1 ) + { + // more optmized than document->setNextPage and then move view to top + DocumentViewport newViewport = d->document->viewport(); + newViewport.pageNumber += 1; + newViewport.rePos.enabled = true; + newViewport.rePos.normalizedY = 0.0; + d->document->setViewport( newViewport ); + } + break; + case Key_Left: + horizontalScrollBar()->subtractLine(); + break; + case Key_Right: + horizontalScrollBar()->addLine(); + break; + case Qt::Key_Escape: + selectionClear(); + d->mousePressPos = QPoint(); + if ( d->aPrevAction ) + { + d->aPrevAction->activate(); + d->aPrevAction = 0; + } + break; + case Key_Shift: + case Key_Control: + if ( d->autoScrollTimer ) + { + if ( d->autoScrollTimer->isActive() ) + d->autoScrollTimer->stop(); + else + slotAutoScoll(); + return; + } + // else fall trhough + default: + e->ignore(); + return; + } + // if a known key has been pressed, stop scrolling the page + if ( d->autoScrollTimer ) + { + d->scrollIncrement = 0; + d->autoScrollTimer->stop(); + } +} + +void PageView::imEndEvent( QIMEvent * e ) +{ + if( d->typeAheadActive ) + { + if( !e->text().isEmpty() ) + { + d->typeAheadString += e->text(); + doTypeAheadSearch(); + e->accept(); + } + } +} + +void PageView::contentsMouseMoveEvent( QMouseEvent * e ) +{ + // don't perform any mouse action when no document is shown + if ( d->items.isEmpty() ) + return; + + // don't perform any mouse action when viewport is autoscrolling + if ( d->viewportMoveActive ) + return; + + // if holding mouse mid button, perform zoom + if ( (e->state() & MidButton) && d->mouseMidStartY >= 0 ) + { + int deltaY = d->mouseMidStartY - e->globalPos().y(); + d->mouseMidStartY = e->globalPos().y(); + d->zoomFactor *= ( 1.0 + ( (double)deltaY / 500.0 ) ); + updateZoom( ZoomRefreshCurrent ); + // uncomment following line to force a complete redraw + viewport()->repaint( false ); + return; + } + + bool leftButton = e->state() & LeftButton, + rightButton = e->state() & RightButton; + switch ( d->mouseMode ) + { + case MouseNormal: + if ( leftButton ) + { + // drag page + if ( !d->mouseGrabPos.isNull() ) + { + // scroll page by position increment + QPoint delta = d->mouseGrabPos - e->globalPos(); + scrollBy( delta.x(), delta.y() ); + d->mouseGrabPos = e->globalPos(); + } + } + else if ( rightButton && !d->mousePressPos.isNull() ) + { + // if mouse moves 5 px away from the press point, switch to 'selection' + int deltaX = d->mousePressPos.x() - e->globalPos().x(), + deltaY = d->mousePressPos.y() - e->globalPos().y(); + if ( deltaX > 5 || deltaX < -5 || deltaY > 5 || deltaY < -5 ) + { + d->aPrevAction = d->aMouseNormal; + d->aMouseSelect->activate(); + QColor selColor = palette().active().highlight().light( 120 ); + selectionStart( e->x() + deltaX, e->y() + deltaY, selColor, false ); + selectionEndPoint( e->x(), e->y() ); + break; + } + } + else + { + // only hovering the page, so update the cursor + updateCursor( e->pos() ); + } + break; + + case MouseZoom: + case MouseSelect: + // set second corner of selection + if ( !d->mousePressPos.isNull() && ( leftButton || d->aPrevAction ) ) + selectionEndPoint( e->x(), e->y() ); + break; + + case MouseEdit: // ? update graphics ? + break; + } +} + +void PageView::contentsMousePressEvent( QMouseEvent * e ) +{ + // don't perform any mouse action when no document is shown + if ( d->items.isEmpty() ) + return; + + // if performing a selection or dyn zooming, disable mouse press + if ( !d->mouseSelectionRect.isNull() || d->mouseMidStartY != -1 || + d->viewportMoveActive ) + return; + + // if the page is scrolling, stop it + if ( d->autoScrollTimer ) + { + d->scrollIncrement = 0; + d->autoScrollTimer->stop(); + } + + // if pressing mid mouse button while not doing other things, begin 'comtinous zoom' mode + if ( e->button() & MidButton ) + { + d->mouseMidStartY = e->globalPos().y(); + setCursor( KCursor::sizeVerCursor() ); + return; + } + + // update press / 'start drag' mouse position + d->mousePressPos = e->globalPos(); + + // handle mode dependant mouse press actions + bool leftButton = e->button() & LeftButton, + rightButton = e->button() & RightButton; + switch ( d->mouseMode ) + { + case MouseNormal: // drag start / click / link following + if ( leftButton ) + { + d->mouseGrabPos = d->mouseOnRect ? QPoint() : d->mousePressPos; + if ( !d->mouseOnRect ) + setCursor( KCursor::sizeAllCursor() ); + } + break; + + case MouseZoom: // set first corner of the zoom rect + if ( leftButton ) + selectionStart( e->x(), e->y(), palette().active().highlight(), false ); + else if ( rightButton ) + updateZoom( ZoomOut ); + break; + + case MouseSelect: // set first corner of the selection rect + if ( leftButton ) + { + QColor selColor = palette().active().highlight().light( 120 ); + selectionStart( e->x(), e->y(), selColor, false ); + } + break; + + case MouseEdit: // ..to do.. + break; + } +} + +void PageView::contentsMouseReleaseEvent( QMouseEvent * e ) +{ + // stop the drag scrolling + d->dragScrollTimer.stop(); + + // don't perform any mouse action when no document is shown + if ( d->items.isEmpty() ) + { + // ..except for right Clicks (emitted even it viewport is empty) + if ( e->button() == RightButton ) + emit rightClick( 0, e->globalPos() ); + return; + } + + // don't perform any mouse action when viewport is autoscrolling + if ( d->viewportMoveActive ) + return; + + // handle mode indepent mid buttom zoom + bool midButton = e->button() & MidButton; + if ( midButton && d->mouseMidStartY > 0 ) + { + d->mouseMidStartY = -1; + // while drag-zooming we could have gone over a link + updateCursor( e->pos() ); + return; + } + + bool leftButton = e->button() & LeftButton, + rightButton = e->button() & RightButton; + switch ( d->mouseMode ) + { + case MouseNormal:{ + // return the cursor to its normal state after dragging + if ( cursor().shape() == Qt::SizeAllCursor ) + updateCursor( e->pos() ); + + PageViewItem * pageItem = pickItemOnPoint( e->x(), e->y() ); + + // if the mouse has not moved since the press, that's a -click- + if ( leftButton && pageItem && d->mousePressPos == e->globalPos()) + { + double nX = (double)(e->x() - pageItem->geometry().left()) / (double)pageItem->width(), + nY = (double)(e->y() - pageItem->geometry().top()) / (double)pageItem->height(); + const ObjectRect * linkRect, * imageRect; + linkRect = pageItem->page()->hasObject( ObjectRect::Link, nX, nY ); + if ( linkRect ) + { + // handle click over a link + const KPDFLink * link = static_cast< const KPDFLink * >( linkRect->pointer() ); + d->document->processLink( link ); + } + else + { + // a link can move us to another page or even to another document, there's no point in trying to process the click on the image once we have processes the click on the link + imageRect = pageItem->page()->hasObject( ObjectRect::Image, nX, nY ); + if ( imageRect ) + { + // handle click over a image + } + // Enrico and me have decided this is not worth the trouble it generates + // else + // { + // if not on a rect, the click selects the page + // d->document->setViewportPage( pageItem->pageNumber(), PAGEVIEW_ID ); + // } + } + } + else if ( rightButton ) + { + // right click (if not within 5 px of the press point, the mode + // had been already changed to 'Selection' instead of 'Normal') + emit rightClick( pageItem ? pageItem->page() : 0, e->globalPos() ); + } + }break; + + case MouseZoom: + // if a selection rect has been defined, zoom into it + if ( leftButton && !d->mouseSelectionRect.isNull() ) + { + QRect selRect = d->mouseSelectionRect.normalize(); + if ( selRect.width() <= 8 && selRect.height() <= 8 ) + { + selectionClear(); + break; + } + + // find out new zoom ratio and normalized view center (relative to the contentsRect) + double zoom = QMIN( (double)visibleWidth() / (double)selRect.width(), (double)visibleHeight() / (double)selRect.height() ); + double nX = (double)(selRect.left() + selRect.right()) / (2.0 * (double)contentsWidth()); + double nY = (double)(selRect.top() + selRect.bottom()) / (2.0 * (double)contentsHeight()); + + // zoom up to 400% + if ( d->zoomFactor <= 4.0 || zoom <= 1.0 ) + { + d->zoomFactor *= zoom; + viewport()->setUpdatesEnabled( false ); + updateZoom( ZoomRefreshCurrent ); + viewport()->setUpdatesEnabled( true ); + } + + // recenter view and update the viewport + center( (int)(nX * contentsWidth()), (int)(nY * contentsHeight()) ); + updateContents(); + + // hide message box and delete overlay window + selectionClear(); + } + break; + + case MouseSelect:{ + + if (d->mouseSelectionRect.isNull() && rightButton) + { + PageViewItem * pageItem = pickItemOnPoint( e->x(), e->y() ); + emit rightClick( pageItem ? pageItem->page() : 0, e->globalPos() ); + } + + // if a selection is defined, display a popup + if ( (!leftButton && !d->aPrevAction) || (leftButton && d->aPrevAction) || + d->mouseSelectionRect.isNull() ) + break; + + QRect selectionRect = d->mouseSelectionRect.normalize(); + if ( selectionRect.width() <= 8 && selectionRect.height() <= 8 ) + { + selectionClear(); + if ( d->aPrevAction ) + { + d->aPrevAction->activate(); + d->aPrevAction = 0; + } + break; + } + + // grab text in selection by extracting it from all intersected pages + QString selectedText; + QValueVector< PageViewItem * >::iterator iIt = d->items.begin(), iEnd = d->items.end(); + for ( ; iIt != iEnd; ++iIt ) + { + PageViewItem * item = *iIt; + const QRect & itemRect = item->geometry(); + if ( selectionRect.intersects( itemRect ) ) + { + // request the textpage if there isn't one + const KPDFPage * kpdfPage = item->page(); + if ( !kpdfPage->hasSearchPage() ) + d->document->requestTextPage( kpdfPage->number() ); + // grab text in the rect that intersects itemRect + QRect relativeRect = selectionRect.intersect( itemRect ); + relativeRect.moveBy( -itemRect.left(), -itemRect.top() ); + NormalizedRect normRect( relativeRect, item->width(), item->height() ); + selectedText += kpdfPage->getText( normRect ); + } + } + + // popup that ask to copy:text and copy/save:image + KPopupMenu menu( this ); + if ( !selectedText.isEmpty() ) + { + menu.insertTitle( i18n( "Text (1 character)", "Text (%n characters)", selectedText.length() ) ); + menu.insertItem( SmallIcon("editcopy"), i18n( "Copy to Clipboard" ), 1 ); + if ( !d->document->isAllowed( KPDFDocument::AllowCopy ) ) + menu.setItemEnabled( 1, false ); + if ( KpdfSettings::useKTTSD() ) + menu.insertItem( SmallIcon("kttsd"), i18n( "Speak Text" ), 2 ); + } + menu.insertTitle( i18n( "Image (%1 by %2 pixels)" ).arg( selectionRect.width() ).arg( selectionRect.height() ) ); + menu.insertItem( SmallIcon("image"), i18n( "Copy to Clipboard" ), 3 ); + menu.insertItem( SmallIcon("filesave"), i18n( "Save to File..." ), 4 ); + int choice = menu.exec( e->globalPos() ); + // IMAGE operation choosen + if ( choice > 2 ) + { + // renders page into a pixmap + QPixmap copyPix( selectionRect.width(), selectionRect.height() ); + QPainter copyPainter( ©Pix ); + copyPainter.translate( -selectionRect.left(), -selectionRect.top() ); + paintItems( ©Painter, selectionRect ); + + if ( choice == 3 ) + { + // [2] copy pixmap to clipboard + QClipboard *cb = QApplication::clipboard(); + cb->setPixmap( copyPix, QClipboard::Clipboard ); + if ( cb->supportsSelection() ) + cb->setPixmap( copyPix, QClipboard::Selection ); + d->messageWindow->display( i18n( "Image [%1x%2] copied to clipboard." ).arg( copyPix.width() ).arg( copyPix.height() ) ); + } + else if ( choice == 4 ) + { + // [3] save pixmap to file + QString fileName = KFileDialog::getSaveFileName( QString::null, "image/png image/jpeg", this ); + if ( fileName.isNull() ) + d->messageWindow->display( i18n( "File not saved." ), PageViewMessage::Warning ); + else + { + QString type( KImageIO::type( fileName ) ); + if ( type.isNull() ) + type = "PNG"; + copyPix.save( fileName, type.latin1() ); + d->messageWindow->display( i18n( "Image [%1x%2] saved to %3 file." ).arg( copyPix.width() ).arg( copyPix.height() ).arg( type ) ); + } + } + } + // TEXT operation choosen + else + { + if ( choice == 1 ) + { + // [1] copy text to clipboard + QClipboard *cb = QApplication::clipboard(); + cb->setText( selectedText, QClipboard::Clipboard ); + if ( cb->supportsSelection() ) + cb->setText( selectedText, QClipboard::Selection ); + } + else if ( choice == 2 ) + { + // [2] speech selection using KTTSD + DCOPClient * client = DCOPClient::mainClient(); + // Albert says is this ever necessary? + // we already attached on Part constructor + // if ( !client->isAttached() ) + // client->attach(); + // If KTTSD not running, start it. + if (!client->isApplicationRegistered("kttsd")) + { + QString error; + if (KApplication::startServiceByDesktopName("kttsd", QStringList(), &error)) + { + d->messageWindow->display( i18n("Starting KTTSD Failed: %1").arg(error) ); + KpdfSettings::setUseKTTSD(false); + KpdfSettings::writeConfig(); + } + } + if ( KpdfSettings::useKTTSD() ) + { + // serialize the text to speech (selectedText) and the + // preferred reader ("" is the default voice) ... + QByteArray data; + QDataStream arg( data, IO_WriteOnly ); + arg << selectedText; + arg << QString(); + QCString replyType; + QByteArray replyData; + // ..and send it to KTTSD + if (client->call( "kttsd", "KSpeech", "setText(QString,QString)", data, replyType, replyData, true )) + { + QByteArray data2; + QDataStream arg2(data2, IO_WriteOnly); + arg2 << 0; + client->send("kttsd", "KSpeech", "startText(uint)", data2 ); + } + } + } + } + + // clear widget selection and invalidate rect + selectionClear(); + + // restore previous action if came from it using right button + if ( d->aPrevAction ) + { + d->aPrevAction->activate(); + d->aPrevAction = 0; + } + }break; + + case MouseEdit: // ? apply [tool] ? + break; + } + + // reset mouse press / 'drag start' position + d->mousePressPos = QPoint(); +} + +void PageView::wheelEvent( QWheelEvent *e ) +{ + // don't perform any mouse action when viewport is autoscrolling + if ( d->viewportMoveActive ) + return; + + if ( !d->document->isOpened() ) + { + QScrollView::wheelEvent( e ); + return; + } + + int delta = e->delta(), + vScroll = verticalScrollBar()->value(); + e->accept(); + if ( (e->state() & ControlButton) == ControlButton ) { + if ( e->delta() < 0 ) + slotZoomOut(); + else + slotZoomIn(); + } + else if ( delta <= -120 && !KpdfSettings::viewContinuous() && vScroll == verticalScrollBar()->maxValue() ) + { + // go to next page + if ( d->document->currentPage() < d->items.count() - 1 ) + { + // more optmized than document->setNextPage and then move view to top + DocumentViewport newViewport = d->document->viewport(); + newViewport.pageNumber += 1; + newViewport.rePos.enabled = true; + newViewport.rePos.normalizedY = 0.0; + d->document->setViewport( newViewport ); + } + } + else if ( delta >= 120 && !KpdfSettings::viewContinuous() && vScroll == verticalScrollBar()->minValue() ) + { + // go to prev page + if ( d->document->currentPage() > 0 ) + { + // more optmized than document->setPrevPage and then move view to bottom + DocumentViewport newViewport = d->document->viewport(); + newViewport.pageNumber -= 1; + newViewport.rePos.enabled = true; + newViewport.rePos.normalizedY = 1.0; + d->document->setViewport( newViewport ); + } + } + else + QScrollView::wheelEvent( e ); + + QPoint cp = viewportToContents(e->pos()); + updateCursor(cp); +} + +void PageView::dragEnterEvent( QDragEnterEvent * ev ) +{ + ev->accept(); +} + +void PageView::dropEvent( QDropEvent * ev ) +{ + KURL::List lst; + if ( KURLDrag::decode( ev, lst ) ) + emit urlDropped( lst.first() ); +} +//END widget events + +void PageView::paintItems( QPainter * p, const QRect & contentsRect ) +{ + // when checking if an Item is contained in contentsRect, instead of + // growing PageViewItems rects (for keeping outline into account), we + // grow the contentsRect + QRect checkRect = contentsRect; + checkRect.addCoords( -3, -3, 1, 1 ); + + // create a region from wich we'll subtract painted rects + QRegion remainingArea( contentsRect ); + + //QValueVector< PageViewItem * >::iterator iIt = d->visibleItems.begin(), iEnd = d->visibleItems.end(); + QValueVector< PageViewItem * >::iterator iIt = d->items.begin(), iEnd = d->items.end(); + for ( ; iIt != iEnd; ++iIt ) + { + // check if a piece of the page intersects the contents rect + if ( !(*iIt)->geometry().intersects( checkRect ) ) + continue; + + PageViewItem * item = *iIt; + QRect pixmapGeometry = item->geometry(); + + // translate the painter so we draw top-left pixmap corner in 0,0 + p->save(); + p->translate( pixmapGeometry.left(), pixmapGeometry.top() ); + + // item pixmap and outline geometry + QRect outlineGeometry = pixmapGeometry; + outlineGeometry.addCoords( -1, -1, 3, 3 ); + + // draw the page outline (little black border and 2px shadow) + if ( !pixmapGeometry.contains( contentsRect ) ) + { + int pixmapWidth = pixmapGeometry.width(), + pixmapHeight = pixmapGeometry.height(); + // draw simple outline + p->setPen( Qt::black ); + p->drawRect( -1, -1, pixmapWidth + 2, pixmapHeight + 2 ); + // draw bottom/right gradient + int levels = 2; + int r = Qt::gray.red() / (levels + 2), + g = Qt::gray.green() / (levels + 2), + b = Qt::gray.blue() / (levels + 2); + for ( int i = 0; i < levels; i++ ) + { + p->setPen( QColor( r * (i+2), g * (i+2), b * (i+2) ) ); + p->drawLine( i, i + pixmapHeight + 1, i + pixmapWidth + 1, i + pixmapHeight + 1 ); + p->drawLine( i + pixmapWidth + 1, i, i + pixmapWidth + 1, i + pixmapHeight ); + p->setPen( Qt::gray ); + p->drawLine( -1, i + pixmapHeight + 1, i - 1, i + pixmapHeight + 1 ); + p->drawLine( i + pixmapWidth + 1, -1, i + pixmapWidth + 1, i - 1 ); + } + } + + // draw the pixmap (note: this modifies the painter) + if ( contentsRect.intersects( pixmapGeometry ) ) + { + QRect pixmapRect = contentsRect.intersect( pixmapGeometry ); + pixmapRect.moveBy( -pixmapGeometry.left(), -pixmapGeometry.top() ); + int flags = PagePainter::Accessibility | PagePainter::EnhanceLinks | + PagePainter::EnhanceImages | PagePainter::Highlights; + PagePainter::paintPageOnPainter( item->page(), PAGEVIEW_ID, flags, p, pixmapRect, + pixmapGeometry.width(), pixmapGeometry.height() ); + } + + // remove painted area from 'remainingArea' and restore painter + remainingArea -= outlineGeometry.intersect( contentsRect ); + p->restore(); + } + + // paint with background color the unpainted area + QMemArray backRects = remainingArea.rects(); + uint backRectsNumber = backRects.count(); + for ( uint jr = 0; jr < backRectsNumber; jr++ ) + p->fillRect( backRects[ jr ], Qt::gray ); +} + +void PageView::updateItemSize( PageViewItem * item, int colWidth, int rowHeight ) +{ + const KPDFPage * kpdfPage = item->page(); + double width = kpdfPage->width(), + height = kpdfPage->height(), + zoom = d->zoomFactor; + + if ( d->zoomMode == ZoomFixed ) + { + width *= zoom; + height *= zoom; + item->setWHZ( (int)width, (int)height, d->zoomFactor ); + } + else if ( d->zoomMode == ZoomFitWidth ) + { + height = kpdfPage->ratio() * colWidth; + item->setWHZ( colWidth, (int)height, (double)colWidth / width ); + d->zoomFactor = (double)colWidth / width; + } + else if ( d->zoomMode == ZoomFitPage ) + { + double scaleW = (double)colWidth / (double)width; + double scaleH = (double)rowHeight / (double)height; + zoom = QMIN( scaleW, scaleH ); + item->setWHZ( (int)(zoom * width), (int)(zoom * height), zoom ); + d->zoomFactor = zoom; + } +#ifndef NDEBUG + else + kdDebug() << "calling updateItemSize with unrecognized d->zoomMode!" << endl; +#endif +} + +PageViewItem * PageView::pickItemOnPoint( int x, int y ) +{ + PageViewItem * item = 0; + QValueList< PageViewItem * >::iterator iIt = d->visibleItems.begin(), iEnd = d->visibleItems.end(); + for ( ; iIt != iEnd; ++iIt ) + { + PageViewItem * i = *iIt; + const QRect & r = i->geometry(); + if ( x < r.right() && x > r.left() && y < r.bottom() ) + { + if ( y > r.top() ) + item = i; + break; + } + } + return item; +} + +void PageView::selectionStart( int x, int y, const QColor & color, bool /*aboveAll*/ ) +{ + d->mouseSelectionRect.setRect( x, y, 1, 1 ); + d->selectionRectColor = color; + // ensures page doesn't scroll + if ( d->autoScrollTimer ) + { + d->scrollIncrement = 0; + d->autoScrollTimer->stop(); + } +} + +void PageView::selectionEndPoint( int x, int y ) +{ + if (x < contentsX()) d->dragScrollVector.setX(x - contentsX()); + else if (contentsX() + viewport()->width() < x) d->dragScrollVector.setX(x - contentsX() - viewport()->width()); + else d->dragScrollVector.setX(0); + + if (y < contentsY()) d->dragScrollVector.setY(y - contentsY()); + else if (contentsY() + viewport()->height() < y) d->dragScrollVector.setY(y - contentsY() - viewport()->height()); + else d->dragScrollVector.setY(0); + + if (d->dragScrollVector != QPoint(0, 0)) + { + if (!d->dragScrollTimer.isActive()) d->dragScrollTimer.start(100); + } + else d->dragScrollTimer.stop(); + + // clip selection to the viewport + QRect viewportRect( contentsX(), contentsY(), visibleWidth(), visibleHeight() ); + x = QMAX( QMIN( x, viewportRect.right() ), viewportRect.left() ); + y = QMAX( QMIN( y, viewportRect.bottom() ), viewportRect.top() ); + // if selection changed update rect + if ( d->mouseSelectionRect.right() != x || d->mouseSelectionRect.bottom() != y ) + { + // send incremental paint events + QRect oldRect = d->mouseSelectionRect.normalize(); + d->mouseSelectionRect.setRight( x ); + d->mouseSelectionRect.setBottom( y ); + QRect newRect = d->mouseSelectionRect.normalize(); + // generate diff region: [ OLD.unite(NEW) - OLD.intersect(NEW) ] + QRegion compoundRegion = QRegion( oldRect ).unite( newRect ); + if ( oldRect.intersects( newRect ) ) + { + QRect intersection = oldRect.intersect( newRect ); + intersection.addCoords( 1, 1, -1, -1 ); + if ( intersection.width() > 20 && intersection.height() > 20 ) + compoundRegion -= intersection; + } + // tassellate region with rects and enqueue paint events + QMemArray rects = compoundRegion.rects(); + for ( uint i = 0; i < rects.count(); i++ ) + updateContents( rects[i] ); + } +} + +void PageView::selectionClear() +{ + updateContents( d->mouseSelectionRect.normalize() ); + d->mouseSelectionRect.setCoords( 0, 0, -1, -1 ); +} + +void PageView::updateZoom( ZoomMode newZoomMode ) +{ + if ( newZoomMode == ZoomFixed ) + { + if ( d->aZoom->currentItem() == 0 ) + newZoomMode = ZoomFitWidth; + else if ( d->aZoom->currentItem() == 1 ) + newZoomMode = ZoomFitPage; + } + + float newFactor = d->zoomFactor; + KAction * checkedZoomAction = 0; + switch ( newZoomMode ) + { + case ZoomFixed:{ //ZoomFixed case + QString z = d->aZoom->currentText(); + newFactor = KGlobal::locale()->readNumber( z.remove( z.find( '%' ), 1 ) ) / 100.0; + }break; + case ZoomIn: + newFactor += (newFactor > 0.99) ? ( newFactor > 1.99 ? 0.5 : 0.2 ) : 0.1; + newZoomMode = ZoomFixed; + break; + case ZoomOut: + newFactor -= (newFactor > 0.99) ? ( newFactor > 1.99 ? 0.5 : 0.2 ) : 0.1; + newZoomMode = ZoomFixed; + break; + case ZoomFitWidth: + checkedZoomAction = d->aZoomFitWidth; + break; + case ZoomFitPage: + checkedZoomAction = d->aZoomFitPage; + break; + case ZoomFitText: + checkedZoomAction = d->aZoomFitText; + break; + case ZoomRefreshCurrent: + newZoomMode = ZoomFixed; + d->zoomFactor = -1; + break; + } + if ( newFactor > 4.0 ) + newFactor = 4.0; + if ( newFactor < 0.1 ) + newFactor = 0.1; + + if ( newZoomMode != d->zoomMode || (newZoomMode == ZoomFixed && newFactor != d->zoomFactor ) ) + { + // rebuild layout and update the whole viewport + d->zoomMode = newZoomMode; + d->zoomFactor = newFactor; + // be sure to block updates to document's viewport + bool prevState = d->blockViewport; + d->blockViewport = true; + slotRelayoutPages(); + d->blockViewport = prevState; + // request pixmaps + slotRequestVisiblePixmaps(); + // update zoom text + updateZoomText(); + // update actions checked state + d->aZoomFitWidth->setChecked( checkedZoomAction == d->aZoomFitWidth ); + d->aZoomFitPage->setChecked( checkedZoomAction == d->aZoomFitPage ); + d->aZoomFitText->setChecked( checkedZoomAction == d->aZoomFitText ); + + // save selected zoom factor + KpdfSettings::setZoomMode(newZoomMode); + KpdfSettings::setZoomFactor(newFactor); + KpdfSettings::writeConfig(); + } +} + +void PageView::updateZoomText() +{ + // use current page zoom as zoomFactor if in ZoomFit/* mode + if ( d->zoomMode != ZoomFixed && d->items.count() > 0 ) + d->zoomFactor = d->items[ QMAX( 0, (int)d->document->currentPage() ) ]->zoomFactor(); + float newFactor = d->zoomFactor; + d->aZoom->clear(); + + // add items that describe fit actions + QStringList translated; + translated << i18n("Fit Width") << i18n("Fit Page"); // << i18n("Fit Text"); + + // add percent items + QString double_oh( "00" ); + const float zoomValue[10] = { 0.125, 0.25, 0.333, 0.5, 0.667, 0.75, 1, 1.25, 1.50, 2 }; + int idx = 0, + selIdx = 2; // use 3 if "fit text" present + bool inserted = false; //use: "d->zoomMode != ZoomFixed" to hide Fit/* zoom ratio + while ( idx < 10 || !inserted ) + { + float value = idx < 10 ? zoomValue[ idx ] : newFactor; + if ( !inserted && newFactor < (value - 0.0001) ) + value = newFactor; + else + idx ++; + if ( value > (newFactor - 0.0001) && value < (newFactor + 0.0001) ) + inserted = true; + if ( !inserted ) + selIdx++; + QString localValue( KGlobal::locale()->formatNumber( value * 100.0, 2 ) ); + localValue.remove( KGlobal::locale()->decimalSymbol() + double_oh ); + translated << QString( "%1%" ).arg( localValue ); + } + d->aZoom->setItems( translated ); + + // select current item in list + if ( d->zoomMode == ZoomFitWidth ) + selIdx = 0; + else if ( d->zoomMode == ZoomFitPage ) + selIdx = 1; + else if ( d->zoomMode == ZoomFitText ) + selIdx = 2; + d->aZoom->setCurrentItem( selIdx ); +} + +void PageView::updateCursor( const QPoint &p ) +{ + // detect the underlaying page (if present) + PageViewItem * pageItem = pickItemOnPoint( p.x(), p.y() ); + if ( pageItem && d->mouseMode == MouseNormal ) + { + double nX = (double)(p.x() - pageItem->geometry().left()) / (double)pageItem->width(), + nY = (double)(p.y() - pageItem->geometry().top()) / (double)pageItem->height(); + + // if over a ObjectRect (of type Link) change cursor to hand + d->mouseOnRect = pageItem->page()->hasObject( ObjectRect::Link, nX, nY ); + if ( d->mouseOnRect ) + setCursor( KCursor::handCursor() ); + else + setCursor( KCursor::arrowCursor() ); + } + else + { + // if there's no page over the cursor and we were showing the pointingHandCursor + // go back to the normal one + d->mouseOnRect = false; + setCursor( KCursor::arrowCursor() ); + } +} + +void PageView::doTypeAheadSearch() +{ + bool found = d->document->searchText( PAGEVIEW_SEARCH_ID, d->typeAheadString, false, false, + KPDFDocument::NextMatch, true, qRgb( 128, 255, 128 ), true ); + QString status = found ? i18n("Text found: \"%1\".") : i18n("Text not found: \"%1\"."); + d->messageWindow->display( status.arg(d->typeAheadString.lower()), + found ? PageViewMessage::Find : PageViewMessage::Warning, 4000 ); + d->findTimeoutTimer->start( 3000, true ); +} + +//BEGIN private SLOTS +void PageView::slotRelayoutPages() +// called by: notifySetup, viewportResizeEvent, slotTwoPagesToggled, slotContinuousToggled, updateZoom +{ + // set an empty container if we have no pages + int pageCount = d->items.count(); + if ( pageCount < 1 ) + { + resizeContents( 0, 0 ); + return; + } + + // if viewport was auto-moving, stop it + if ( d->viewportMoveActive ) + { + d->viewportMoveActive = false; + d->viewportMoveTimer->stop(); + verticalScrollBar()->setEnabled( true ); + horizontalScrollBar()->setEnabled( true ); + } + + // common iterator used in this method and viewport parameters + QValueVector< PageViewItem * >::iterator iIt, iEnd = d->items.end(); + int viewportWidth = visibleWidth(), + viewportHeight = visibleHeight(), + fullWidth = 0, + fullHeight = 0; + QRect viewportRect( contentsX(), contentsY(), viewportWidth, viewportHeight ); + + // set all items geometry and resize contents. handle 'continuous' and 'single' modes separately + if ( KpdfSettings::viewContinuous() ) + { + // Here we find out column's width and row's height to compute a table + // so we can place widgets 'centered in virtual cells'. + int nCols = KpdfSettings::viewColumns(), + nRows = (int)ceil( (float)pageCount / (float)nCols ), + * colWidth = new int[ nCols ], + * rowHeight = new int[ nRows ], + cIdx = 0, + rIdx = 0; + for ( int i = 0; i < nCols; i++ ) + colWidth[ i ] = viewportWidth / nCols; + for ( int i = 0; i < nRows; i++ ) + rowHeight[ i ] = 0; + + // 1) find the maximum columns width and rows height for a grid in + // which each page must well-fit inside a cell + for ( iIt = d->items.begin(); iIt != iEnd; ++iIt ) + { + PageViewItem * item = *iIt; + // update internal page size (leaving a little margin in case of Fit* modes) + updateItemSize( item, colWidth[ cIdx ] - 6, viewportHeight - 8 ); + // find row's maximum height and column's max width + if ( item->width() + 6 > colWidth[ cIdx ] ) + colWidth[ cIdx ] = item->width() + 6; + if ( item->height() > rowHeight[ rIdx ] ) + rowHeight[ rIdx ] = item->height(); + // update col/row indices + if ( ++cIdx == nCols ) + { + cIdx = 0; + rIdx++; + } + } + + // 2) arrange widgets inside cells + int insertX = 0, + insertY = 4; // 2 + 4*d->zoomFactor ? + cIdx = 0; + rIdx = 0; + for ( iIt = d->items.begin(); iIt != iEnd; ++iIt ) + { + PageViewItem * item = *iIt; + int cWidth = colWidth[ cIdx ], + rHeight = rowHeight[ rIdx ]; + // center widget inside 'cells' + item->moveTo( insertX + (cWidth - item->width()) / 2, + insertY + (rHeight - item->height()) / 2 ); + // advance col/row index + insertX += cWidth; + if ( ++cIdx == nCols ) + { + cIdx = 0; + rIdx++; + insertX = 0; + insertY += rHeight + 15; // 5 + 15*d->zoomFactor ? + } + } + + fullHeight = cIdx ? (insertY + rowHeight[ rIdx ] + 10) : insertY; + for ( int i = 0; i < nCols; i++ ) + fullWidth += colWidth[ i ]; + + delete [] colWidth; + delete [] rowHeight; + } + else // viewContinuous is FALSE + { + PageViewItem * currentItem = d->items[ QMAX( 0, (int)d->document->currentPage() ) ]; + + // setup varialbles for a 1(row) x N(columns) grid + int nCols = KpdfSettings::viewColumns(), + * colWidth = new int[ nCols ], + cIdx = 0; + fullHeight = viewportHeight; + for ( int i = 0; i < nCols; i++ ) + colWidth[ i ] = viewportWidth / nCols; + + // 1) find out maximum area extension for the pages + for ( iIt = d->items.begin(); iIt != iEnd; ++iIt ) + { + PageViewItem * item = *iIt; + if ( item == currentItem || (cIdx > 0 && cIdx < nCols) ) + { + // update internal page size (leaving a little margin in case of Fit* modes) + updateItemSize( item, colWidth[ cIdx ] - 6, viewportHeight - 8 ); + // find row's maximum height and column's max width + if ( item->width() + 6 > colWidth[ cIdx ] ) + colWidth[ cIdx ] = item->width() + 6; + if ( item->height() + 8 > fullHeight ) + fullHeight = item->height() + 8; + cIdx++; + } + } + + // 2) hide all widgets except the displayable ones and dispose those + int insertX = 0; + cIdx = 0; + for ( iIt = d->items.begin(); iIt != iEnd; ++iIt ) + { + PageViewItem * item = *iIt; + if ( item == currentItem || (cIdx > 0 && cIdx < nCols) ) + { + // center widget inside 'cells' + item->moveTo( insertX + (colWidth[ cIdx ] - item->width()) / 2, + (fullHeight - item->height()) / 2 ); + // advance col index + insertX += colWidth[ cIdx ]; + cIdx++; + } else + item->setGeometry( 0, 0, -1, -1 ); + } + + for ( int i = 0; i < nCols; i++ ) + fullWidth += colWidth[ i ]; + + delete [] colWidth; + } + + // 3) reset dirty state + d->dirtyLayout = false; + + // 4) update scrollview's contents size and recenter view + bool wasUpdatesEnabled = viewport()->isUpdatesEnabled(); + if ( fullWidth != contentsWidth() || fullHeight != contentsHeight() ) + { + // disable updates and resize the viewportContents + if ( wasUpdatesEnabled ) + viewport()->setUpdatesEnabled( false ); + resizeContents( fullWidth, fullHeight ); + // restore previous viewport if defined and updates enabled + if ( wasUpdatesEnabled ) + { + const DocumentViewport & vp = d->document->viewport(); + if ( vp.pageNumber >= 0 ) + { + int prevX = contentsX(), + prevY = contentsY(); + const QRect & geometry = d->items[ vp.pageNumber ]->geometry(); + double nX = vp.rePos.enabled ? vp.rePos.normalizedX : 0.5, + nY = vp.rePos.enabled ? vp.rePos.normalizedY : 0.0; + center( geometry.left() + ROUND( nX * (double)geometry.width() ), + geometry.top() + ROUND( nY * (double)geometry.height() ) ); + // center() usually moves the viewport, that requests pixmaps too. + // if that doesn't happen we have to request them by hand + if ( prevX == contentsX() && prevY == contentsY() ) + slotRequestVisiblePixmaps(); + } + // or else go to center page + else + center( fullWidth / 2, 0 ); + viewport()->setUpdatesEnabled( true ); + } + } + + // 5) update the whole viewport if updated enabled + if ( wasUpdatesEnabled ) + updateContents(); +} + +void PageView::slotRequestVisiblePixmaps( int newLeft, int newTop ) +{ + // if requests are blocked (because raised by an unwanted event), exit + if ( d->blockPixmapsRequest || d->viewportMoveActive ) + return; + + // precalc view limits for intersecting with page coords inside the lOOp + bool isEvent = newLeft != -1 && newTop != -1 && !d->blockViewport; + QRect viewportRect( isEvent ? newLeft : contentsX(), + isEvent ? newTop : contentsY(), + visibleWidth(), visibleHeight() ); + + // some variables used to determine the viewport + int nearPageNumber = -1; + double viewportCenterX = (viewportRect.left() + viewportRect.right()) / 2.0, + viewportCenterY = (viewportRect.top() + viewportRect.bottom()) / 2.0, + focusedX = 0.5, + focusedY = 0.0, + minDistance = -1.0; + + // iterate over all items + d->visibleItems.clear(); + QValueList< PixmapRequest * > requestedPixmaps; + QValueVector< PageViewItem * >::iterator iIt = d->items.begin(), iEnd = d->items.end(); + for ( ; iIt != iEnd; ++iIt ) + { + PageViewItem * i = *iIt; + + // if the item doesn't intersect the viewport, skip it + if ( !viewportRect.intersects( i->geometry() ) ) + continue; + + // add the item to the 'visible list' + d->visibleItems.push_back( i ); + + // if the item has not the right pixmap, add a request for it + if ( !i->page()->hasPixmap( PAGEVIEW_ID, i->width(), i->height() ) ) + { + PixmapRequest * p = new PixmapRequest( + PAGEVIEW_ID, i->pageNumber(), i->width(), i->height(), PAGEVIEW_PRIO, true ); + requestedPixmaps.push_back( p ); + } + + // look for the item closest to viewport center and the relative + // position between the item and the viewport center + if ( isEvent ) + { + const QRect & geometry = i->geometry(); + // compute distance between item center and viewport center + double distance = hypot( (geometry.left() + geometry.right()) / 2 - viewportCenterX, + (geometry.top() + geometry.bottom()) / 2 - viewportCenterY ); + if ( distance >= minDistance && nearPageNumber != -1 ) + continue; + nearPageNumber = i->pageNumber(); + minDistance = distance; + if ( geometry.height() > 0 && geometry.width() > 0 ) + { + focusedX = ( viewportCenterX - (double)geometry.left() ) / (double)geometry.width(); + focusedY = ( viewportCenterY - (double)geometry.top() ) / (double)geometry.height(); + } + } + } + + // if preloading is enabled, add the pages before and after in preloading + if ( !d->visibleItems.isEmpty() && + KpdfSettings::memoryLevel() != KpdfSettings::EnumMemoryLevel::Low && + KpdfSettings::enableThreading() ) + { + // as the requests are done in the order as they appear in the list, + // request first the next page and then the previous + + // add the page after the 'visible series' in preload + int tailRequest = d->visibleItems.last()->pageNumber() + 1; + if ( tailRequest < (int)d->items.count() ) + { + PageViewItem * i = d->items[ tailRequest ]; + // request the pixmap if not already present + if ( !i->page()->hasPixmap( PAGEVIEW_ID, i->width(), i->height() ) && i->width() > 0 ) + requestedPixmaps.push_back( new PixmapRequest( + PAGEVIEW_ID, i->pageNumber(), i->width(), i->height(), PAGEVIEW_PRELOAD_PRIO, true ) ); + } + + // add the page before the 'visible series' in preload + int headRequest = d->visibleItems.first()->pageNumber() - 1; + if ( headRequest >= 0 ) + { + PageViewItem * i = d->items[ headRequest ]; + // request the pixmap if not already present + if ( !i->page()->hasPixmap( PAGEVIEW_ID, i->width(), i->height() ) && i->width() > 0 ) + requestedPixmaps.push_back( new PixmapRequest( + PAGEVIEW_ID, i->pageNumber(), i->width(), i->height(), PAGEVIEW_PRELOAD_PRIO, true ) ); + } + } + + // send requests to the document + if ( !requestedPixmaps.isEmpty() ) + d->document->requestPixmaps( requestedPixmaps ); + + // if this functions was invoked by viewport events, send update to document + if ( isEvent && nearPageNumber != -1 ) + { + // determine the document viewport + DocumentViewport newViewport( nearPageNumber ); + newViewport.rePos.enabled = true; + newViewport.rePos.normalizedX = focusedX; + newViewport.rePos.normalizedY = focusedY; + // set the viewport to other observers + d->document->setViewport( newViewport , PAGEVIEW_ID); + } +} + +void PageView::slotMoveViewport() +{ + // converge to viewportMoveDest in 1 second + int diffTime = d->viewportMoveTime.elapsed(); + if ( diffTime >= 667 || !d->viewportMoveActive ) + { + center( d->viewportMoveDest.x(), d->viewportMoveDest.y() ); + d->viewportMoveTimer->stop(); + d->viewportMoveActive = false; + slotRequestVisiblePixmaps(); + verticalScrollBar()->setEnabled( true ); + horizontalScrollBar()->setEnabled( true ); + return; + } + + // move the viewport smoothly (kmplot: p(x)=x+x*(1-x)*(1-x)) + float convergeSpeed = (float)diffTime / 667.0, + x = ((float)visibleWidth() / 2.0) + contentsX(), + y = ((float)visibleHeight() / 2.0) + contentsY(), + diffX = (float)d->viewportMoveDest.x() - x, + diffY = (float)d->viewportMoveDest.y() - y; + convergeSpeed *= convergeSpeed * (1.4 - convergeSpeed); + center( (int)(x + diffX * convergeSpeed), + (int)(y + diffY * convergeSpeed ) ); +} + +void PageView::slotAutoScoll() +{ + // the first time create the timer + if ( !d->autoScrollTimer ) + { + d->autoScrollTimer = new QTimer( this ); + connect( d->autoScrollTimer, SIGNAL( timeout() ), this, SLOT( slotAutoScoll() ) ); + } + + // if scrollIncrement is zero, stop the timer + if ( !d->scrollIncrement ) + { + d->autoScrollTimer->stop(); + return; + } + + // compute delay between timer ticks and scroll amount per tick + int index = abs( d->scrollIncrement ) - 1; // 0..9 + const int scrollDelay[10] = { 200, 100, 50, 30, 20, 30, 25, 20, 30, 20 }; + const int scrollOffset[10] = { 1, 1, 1, 1, 1, 2, 2, 2, 4, 4 }; + d->autoScrollTimer->changeInterval( scrollDelay[ index ] ); + scrollBy( 0, d->scrollIncrement > 0 ? scrollOffset[ index ] : -scrollOffset[ index ] ); +} + +void PageView::slotDragScroll() +{ + scrollBy(d->dragScrollVector.x(), d->dragScrollVector.y()); + QPoint p = viewportToContents( mapFromGlobal( QCursor::pos() ) ); + selectionEndPoint( p.x(), p.y() ); +} + +void PageView::findAheadStop() +{ + d->typeAheadActive = false; + d->typeAheadString = ""; + d->messageWindow->display( i18n("Find stopped."), PageViewMessage::Find, 1000 ); + // it is needed to grab the keyboard becase people may have Space assigned to a + // accel and without grabbing the keyboard you can not vim-search for space + // because it activates the accel + releaseKeyboard(); +} + +void PageView::slotShowWelcome() +{ + // show initial welcome text + d->messageWindow->display( i18n( "Welcome" ), PageViewMessage::Info, 2000 ); +} + +void PageView::slotZoom() +{ + setFocus(); + updateZoom( ZoomFixed ); +} + +void PageView::slotZoomIn() +{ + updateZoom( ZoomIn ); +} + +void PageView::slotZoomOut() +{ + updateZoom( ZoomOut ); +} + +void PageView::slotFitToWidthToggled( bool on ) +{ + if ( on ) updateZoom( ZoomFitWidth ); +} + +void PageView::slotFitToPageToggled( bool on ) +{ + if ( on ) updateZoom( ZoomFitPage ); +} + +void PageView::slotFitToTextToggled( bool on ) +{ + if ( on ) updateZoom( ZoomFitText ); +} + +void PageView::slotTwoPagesToggled( bool on ) +{ + uint newColumns = on ? 2 : 1; + if ( KpdfSettings::viewColumns() != newColumns ) + { + KpdfSettings::setViewColumns( newColumns ); + KpdfSettings::writeConfig(); + if ( d->document->pages() > 0 ) + slotRelayoutPages(); + } +} + +void PageView::slotContinuousToggled( bool on ) +{ + if ( KpdfSettings::viewContinuous() != on ) + { + KpdfSettings::setViewContinuous( on ); + KpdfSettings::writeConfig(); + if ( d->document->pages() > 0 ) + slotRelayoutPages(); + } +} + +void PageView::slotSetMouseNormal() +{ + d->mouseMode = MouseNormal; + d->messageWindow->hide(); +} + +void PageView::slotSetMouseZoom() +{ + d->mouseMode = MouseZoom; + d->messageWindow->display( i18n( "Select zooming area. Right-click to zoom out." ), PageViewMessage::Info, -1 ); +} + +void PageView::slotSetMouseSelect() +{ + d->mouseMode = MouseSelect; + d->messageWindow->display( i18n( "Draw a rectangle around the text/graphics to copy." ), PageViewMessage::Info, -1 ); +} + +void PageView::slotSetMouseDraw() +{ + d->mouseMode = MouseEdit; + d->aMouseEdit->setChecked( true ); + d->messageWindow->hide(); +} + +void PageView::slotScrollUp() +{ + if ( d->scrollIncrement < -9 ) + return; + d->scrollIncrement--; + slotAutoScoll(); + setFocus(); +} + +void PageView::slotScrollDown() +{ + if ( d->scrollIncrement > 9 ) + return; + d->scrollIncrement++; + slotAutoScoll(); + setFocus(); +} +//END private SLOTS + +#include "pageview.moc" diff --git a/kpdf/ui/pageview.h b/kpdf/ui/pageview.h new file mode 100644 index 00000000..f6e40991 --- /dev/null +++ b/kpdf/ui/pageview.h @@ -0,0 +1,148 @@ +/*************************************************************************** + * Copyright (C) 2004 by Enrico Ros * + * Copyright (C) 2004 by Albert Astals Cid * + * * + * With portions of code from kpdf/kpdf_pagewidget.h by: * + * Copyright (C) 2002 by Wilco Greven * + * Copyright (C) 2003 by Christophe Devriese * + * * + * Copyright (C) 2003 by Laurent Montel * + * Copyright (C) 2003 by Kurt Pfeifle * + * * + * 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 file follows coding style described in kdebase/kicker/HACKING + +#ifndef _KPDF_PAGEVIEW_H_ +#define _KPDF_PAGEVIEW_H_ + +#include +#include +#include "core/observer.h" + +class KURL; +class KActionCollection; + +class KPDFDocument; +class PageViewItem; +class PageViewPrivate; +class PageViewTip; + +/** + * @short The main view. Handles zoom and continuous mode.. oh, and page + * @short display of course :-) + * ... + */ +class PageView : public QScrollView, public DocumentObserver +{ + Q_OBJECT + + friend class PageViewTip; + + public: + PageView( QWidget *parent, KPDFDocument *document ); + ~PageView(); + + // Zoom mode ( last 4 are internally used only! ) + enum ZoomMode { ZoomFixed, ZoomFitWidth, ZoomFitPage, ZoomFitText, + ZoomIn, ZoomOut, ZoomRefreshCurrent }; + enum MouseMode { MouseNormal, MouseZoom, MouseSelect, MouseEdit }; + + // create actions that interact with this widget + void setupActions( KActionCollection * collection ); + + // used from RMB menu + bool canFitPageWidth(); + void fitPageWidth( int page ); + + // inherited from DocumentObserver + uint observerId() const { return PAGEVIEW_ID; } + void notifySetup( const QValueVector< KPDFPage * > & pages, bool documentChanged ); + void notifyViewportChanged( bool smoothMove ); + void notifyPageChanged( int pageNumber, int changedFlags ); + void notifyContentsCleared( int changedFlags ); + bool canUnloadPixmap( int pageNum ); + + void showText( const QString &text, int ms ); + + signals: + void urlDropped( const KURL& ); + void rightClick( const KPDFPage *, const QPoint & ); + + protected: + // main draw loop, draws pageViews on viewport + void viewportPaintEvent( QPaintEvent * pe ); + void viewportResizeEvent( QResizeEvent* ); + + // mouse / keyboard events + void keyPressEvent( QKeyEvent* ); + void imEndEvent( QIMEvent * ); + void contentsMouseMoveEvent( QMouseEvent* ); + void contentsMousePressEvent( QMouseEvent* ); + void contentsMouseReleaseEvent( QMouseEvent* ); + void wheelEvent( QWheelEvent* ); + + // drag and drop related events + void dragEnterEvent( QDragEnterEvent* ); + void dropEvent( QDropEvent* ); + + private: + // draw items on the opened qpainter + void paintItems( QPainter * p, const QRect & clipRect ); + // update item width and height using current zoom parameters + void updateItemSize( PageViewItem * item, int columnWidth, int rowHeight ); + // return the widget placed on a certain point or 0 if clicking on empty space + PageViewItem * pickItemOnPoint( int x, int y ); + // start / modify / clear selection rectangle + void selectionStart( int x, int y, const QColor & color, bool aboveAll = false ); + void selectionEndPoint( int x, int y ); + void selectionClear(); + // update internal zoom values and end in a slotRelayoutPages(); + void updateZoom( ZoomMode newZm ); + // update the text on the label using global zoom value or current page's one + void updateZoomText(); + // updates cursor + void updateCursor( const QPoint &p ); + // does the type ahead search + void doTypeAheadSearch(); + + // don't want to expose classes in here + class PageViewPrivate * d; + + private slots: + // activated either directly or via QTimer on the viewportResizeEvent + void slotRelayoutPages(); + // activated either directly or via the contentsMoving(int,int) signal + void slotRequestVisiblePixmaps( int left = -1, int top = -1 ); + // activated by the viewport move timer + void slotMoveViewport(); + // activated by the autoscroll timer (Shift+Up/Down keys) + void slotAutoScoll(); + // activated by the dragScroll timer + void slotDragScroll(); + // type-ahead find timeout + void findAheadStop(); + // show the welcome message + void slotShowWelcome(); + + // connected to local actions (toolbar, menu, ..) + void slotZoom(); + void slotZoomIn(); + void slotZoomOut(); + void slotFitToWidthToggled( bool ); + void slotFitToPageToggled( bool ); + void slotFitToTextToggled( bool ); + void slotTwoPagesToggled( bool ); + void slotContinuousToggled( bool ); + void slotSetMouseNormal(); + void slotSetMouseZoom(); + void slotSetMouseSelect(); + void slotSetMouseDraw(); + void slotScrollUp(); + void slotScrollDown(); +}; + +#endif diff --git a/kpdf/ui/pageviewutils.cpp b/kpdf/ui/pageviewutils.cpp new file mode 100644 index 00000000..b9d84137 --- /dev/null +++ b/kpdf/ui/pageviewutils.cpp @@ -0,0 +1,207 @@ +/*************************************************************************** + * Copyright (C) 2004 by Enrico Ros * + * * + * 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. * + ***************************************************************************/ + +// qt/kde includes +#include +#include +#include +#include +#include +#include +#include + +// local includes +#include "pageviewutils.h" +#include "core/page.h" +#include "conf/settings.h" + +PageViewMessage::PageViewMessage( QWidget * parent ) + : QWidget( parent, "pageViewMessage" ), m_timer( 0 ) +{ + setFocusPolicy( NoFocus ); + setBackgroundMode( NoBackground ); + setPaletteBackgroundColor(kapp->palette().color(QPalette::Active, QColorGroup::Background)); + // if the layout is LtR, we can safely place it in the right position + if ( !QApplication::reverseLayout() ) + move( 10, 10 ); + resize( 0, 0 ); + hide(); +} + +void PageViewMessage::display( const QString & message, Icon icon, int durationMs ) +// give to Caesar what Caesar owns: code taken from Amarok's osd.h/.cpp +// "redde (reddite, pl.) cesari quae sunt cesaris", just btw. ;) +{ + if ( !KpdfSettings::showOSD() ) + { + hide(); + return; + } + + // determine text rectangle + QRect textRect = fontMetrics().boundingRect( message ); + textRect.moveBy( -textRect.left(), -textRect.top() ); + textRect.addCoords( 0, 0, 2, 2 ); + int width = textRect.width(), + height = textRect.height(), + textXOffset = 0, + iconXOffset = 0, + shadowOffset = 1; + + // load icon (if set) and update geometry + QPixmap symbol; + if ( icon != None ) + { + switch ( icon ) + { + case Find: + symbol = SmallIcon( "viewmag" ); + break; + case Error: + symbol = SmallIcon( "messagebox_critical" ); + break; + case Warning: + symbol = SmallIcon( "messagebox_warning" ); + break; + default: + symbol = SmallIcon( "messagebox_info" ); + break; + } + if ( QApplication::reverseLayout() ) + { + iconXOffset = 2 + textRect.width(); + } + else + { + textXOffset = 2 + symbol.width(); + } + width += 2 + symbol.width(); + height = QMAX( height, symbol.height() ); + } + QRect geometry( 0, 0, width + 10, height + 8 ); + + // resize pixmap, mask and widget + static QBitmap mask; + mask.resize( geometry.size() ); + m_pixmap.resize( geometry.size() ); + resize( geometry.size() ); + + // create and set transparency mask + QPainter maskPainter( &mask); + mask.fill( Qt::black ); + maskPainter.setBrush( Qt::white ); + maskPainter.drawRoundRect( geometry, 1600 / geometry.width(), 1600 / geometry.height() ); + setMask( mask ); + + // draw background + QPainter bufferPainter( &m_pixmap ); + bufferPainter.setPen( Qt::black ); + bufferPainter.setBrush( paletteBackgroundColor() ); + bufferPainter.drawRoundRect( geometry, 1600 / geometry.width(), 1600 / geometry.height() ); + + // draw icon if present + if ( !symbol.isNull() ) + bufferPainter.drawPixmap( 5 + iconXOffset, 4, symbol, 0, 0, symbol.width(), symbol.height() ); + + // draw shadow and text + int yText = geometry.height() - height / 2; + bufferPainter.setPen( paletteBackgroundColor().dark( 115 ) ); + bufferPainter.drawText( 5 + textXOffset + shadowOffset, yText + 1, message ); + bufferPainter.setPen( foregroundColor() ); + bufferPainter.drawText( 5 + textXOffset, yText, message ); + + // if the layout is RtL, we can move it to the right place only after we + // know how much size it will take + if ( QApplication::reverseLayout() ) + move( parentWidget()->width() - geometry.width() - 10, 10 ); + + // show widget and schedule a repaint + show(); + update(); + + // close the message window after given mS + if ( durationMs > 0 ) + { + if ( !m_timer ) + { + m_timer = new QTimer( this ); + connect( m_timer, SIGNAL( timeout() ), SLOT( hide() ) ); + } + m_timer->start( durationMs, true ); + } else if ( m_timer ) + m_timer->stop(); +} + +void PageViewMessage::paintEvent( QPaintEvent * e ) +{ + QPainter p( this ); + p.drawPixmap( e->rect().topLeft(), m_pixmap, e->rect() ); +} + +void PageViewMessage::mousePressEvent( QMouseEvent * /*e*/ ) +{ + if ( m_timer ) + m_timer->stop(); + hide(); +} + + + +PageViewItem::PageViewItem( const KPDFPage * page ) + : m_page( page ), m_zoomFactor( 1.0 ) +{ +} + +const KPDFPage * PageViewItem::page() const +{ + return m_page; +} + +int PageViewItem::pageNumber() const +{ + return m_page->number(); +} + +const QRect& PageViewItem::geometry() const +{ + return m_geometry; +} + +int PageViewItem::width() const +{ + return m_geometry.width(); +} + +int PageViewItem::height() const +{ + return m_geometry.height(); +} + +double PageViewItem::zoomFactor() const +{ + return m_zoomFactor; +} + +void PageViewItem::setGeometry( int x, int y, int width, int height ) +{ + m_geometry.setRect( x, y, width, height ); +} + +void PageViewItem::setWHZ( int w, int h, double z ) +{ + m_geometry.setWidth( w ); + m_geometry.setHeight( h ); + m_zoomFactor = z; +} + +void PageViewItem::moveTo( int x, int y ) +{ + m_geometry.moveLeft( x ); + m_geometry.moveTop( y ); +} diff --git a/kpdf/ui/pageviewutils.h b/kpdf/ui/pageviewutils.h new file mode 100644 index 00000000..bde9b8d3 --- /dev/null +++ b/kpdf/ui/pageviewutils.h @@ -0,0 +1,72 @@ +/*************************************************************************** + * Copyright (C) 2004 by Enrico Ros * + * * + * 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. * + ***************************************************************************/ + +#ifndef _PAGEVIEW_UTILS_H +#define _PAGEVIEW_UTILS_H + +#include +#include +#include +#include + +class QTimer; + +class PageView; +class KPDFPage; + +/** + * @short PageViewItem represents graphically a kpdfpage into the PageView. + * + * It has methods for settings Item's geometry and other visual properties such + * as the individual zoom factor. + */ +class PageViewItem +{ + public: + PageViewItem( const KPDFPage * page ); + + const KPDFPage * page() const; + int pageNumber() const; + const QRect& geometry() const; + int width() const; + int height() const; + double zoomFactor() const; + + void setGeometry( int x, int y, int width, int height ); + void setWHZ( int w, int h, double zoom ); + void moveTo( int x, int y ); + + private: + const KPDFPage * m_page; + double m_zoomFactor; + QRect m_geometry; +}; + + +/** + * @short A widget that displays messages in the top-left corner. + */ +class PageViewMessage : public QWidget +{ + public: + PageViewMessage( QWidget * parent ); + + enum Icon { None, Info, Warning, Error, Find }; + void display( const QString & message, Icon icon = Info, int durationMs = 4000 ); + + protected: + void paintEvent( QPaintEvent * e ); + void mousePressEvent( QMouseEvent * e ); + + private: + QPixmap m_pixmap; + QTimer * m_timer; +}; + +#endif diff --git a/kpdf/ui/presentationwidget.cpp b/kpdf/ui/presentationwidget.cpp new file mode 100644 index 00000000..c57e2f95 --- /dev/null +++ b/kpdf/ui/presentationwidget.cpp @@ -0,0 +1,1330 @@ +/*************************************************************************** + * Copyright (C) 2004 by Enrico Ros * + * * + * 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. * + ***************************************************************************/ + +// qt/kde includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// system includes +#include +#include + +// local includes +#include "presentationwidget.h" +#include "pagepainter.h" +#include "core/generator.h" +#include "core/page.h" +#include "core/link.h" +#include "conf/settings.h" + + +// comment this to disable the top-right progress indicator +#define ENABLE_PROGRESS_OVERLAY + + +// a frame contains a pointer to the page object, its geometry and the +// transition effect to the next frame +struct PresentationFrame +{ + const KPDFPage * page; + QRect geometry; +}; + + +PresentationWidget::PresentationWidget( QWidget * parent, KPDFDocument * doc ) + : QDialog( parent, "presentationWidget", true, WDestructiveClose | WStyle_NoBorder), + m_pressedLink( 0 ), m_handCursor( false ), m_document( doc ), m_frameIndex( -1 ) +{ + // set look and geometry + setBackgroundMode( Qt::NoBackground ); + + m_width = -1; + + m_accel = new KAccel( this, this, "presentationmode-accel" ); + + // show widget and take control + showFullScreen(); + + // misc stuff + setMouseTracking( true ); + m_transitionTimer = new QTimer( this ); + connect( m_transitionTimer, SIGNAL( timeout() ), this, SLOT( slotTransitionStep() ) ); + m_overlayHideTimer = new QTimer( this ); + connect( m_overlayHideTimer, SIGNAL( timeout() ), this, SLOT( slotHideOverlay() ) ); + m_nextPageTimer = new QTimer( this ); + connect( m_nextPageTimer, SIGNAL( timeout() ), this, SLOT( slotNextPage() ) ); + + // handle cursor appearance as specified in configuration + if ( KpdfSettings::slidesCursor() == KpdfSettings::EnumSlidesCursor::HiddenDelay ) + { + KCursor::setAutoHideCursor( this, true ); + KCursor::setHideCursorDelay( 3000 ); + } + else if ( KpdfSettings::slidesCursor() == KpdfSettings::EnumSlidesCursor::Hidden ) + { + setCursor( KCursor::blankCursor() ); + } +} + +PresentationWidget::~PresentationWidget() +{ + // remove this widget from document observer + m_document->removeObserver( this ); + + // delete frames + QValueVector< PresentationFrame * >::iterator fIt = m_frames.begin(), fEnd = m_frames.end(); + for ( ; fIt != fEnd; ++fIt ) + delete *fIt; +} + +void PresentationWidget::setupActions( KActionCollection * ac ) +{ + m_accel->insert( "previous_page", ac->action( "previous_page" )->shortcut(), this, SLOT( slotPrevPage() ), false, true ); + m_accel->insert( "next_page", ac->action( "next_page" )->shortcut(), this, SLOT( slotNextPage() ), false, true ); + m_accel->insert( "first_page", ac->action( "first_page" )->shortcut(), this, SLOT( slotFirstPage() ), false, true ); + m_accel->insert( "last_page", ac->action( "last_page" )->shortcut(), this, SLOT( slotLastPage() ), false, true ); + m_accel->insert( "presentation", ac->action( "presentation" )->shortcut(), this, SLOT( close() ), false, true ); +} + +void PresentationWidget::notifySetup( const QValueVector< KPDFPage * > & pageSet, bool /*documentChanged*/ ) +{ + // delete previous frames (if any (shouldn't be)) + QValueVector< PresentationFrame * >::iterator fIt = m_frames.begin(), fEnd = m_frames.end(); + for ( ; fIt != fEnd; ++fIt ) + delete *fIt; + if ( !m_frames.isEmpty() ) + kdWarning() << "Frames setup changed while a Presentation is in progress." << endl; + m_frames.clear(); + + // create the new frames + QValueVector< KPDFPage * >::const_iterator setIt = pageSet.begin(), setEnd = pageSet.end(); + float screenRatio = (float)m_height / (float)m_width; + for ( ; setIt != setEnd; ++setIt ) + { + PresentationFrame * frame = new PresentationFrame(); + frame->page = *setIt; + // calculate frame geometry keeping constant aspect ratio + float pageRatio = frame->page->ratio(); + int pageWidth = m_width, + pageHeight = m_height; + if ( pageRatio > screenRatio ) + pageWidth = (int)( (float)pageHeight / pageRatio ); + else + pageHeight = (int)( (float)pageWidth * pageRatio ); + frame->geometry.setRect( (m_width - pageWidth) / 2, + (m_height - pageHeight) / 2, + pageWidth, pageHeight ); + // add the frame to the vector + m_frames.push_back( frame ); + } + + // get metadata from the document + m_metaStrings.clear(); + const DocumentInfo * info = m_document->documentInfo(); + if ( info ) + { + if ( !info->get( "title" ).isNull() ) + m_metaStrings += i18n( "Title: %1" ).arg( info->get( "title" ) ); + if ( !info->get( "author" ).isNull() ) + m_metaStrings += i18n( "Author: %1" ).arg( info->get( "author" ) ); + } + m_metaStrings += i18n( "Pages: %1" ).arg( m_document->pages() ); + m_metaStrings += i18n( "Click to begin" ); +} + +void PresentationWidget::notifyViewportChanged( bool /*smoothMove*/ ) +{ + // discard notifications if displaying the summary + if ( m_frameIndex == -1 && KpdfSettings::slidesShowSummary() ) + return; + + // display the current page + changePage( m_document->viewport().pageNumber ); + + // auto advance to the next page if set + if ( KpdfSettings::slidesAdvance() ) + m_nextPageTimer->start( KpdfSettings::slidesAdvanceTime() * 1000 ); +} + +void PresentationWidget::notifyPageChanged( int pageNumber, int changedFlags ) +{ + // check if it's the last requested pixmap. if so update the widget. + if ( (changedFlags & DocumentObserver::Pixmap) && pageNumber == m_frameIndex ) + generatePage(); +} + +bool PresentationWidget::canUnloadPixmap( int pageNumber ) +{ + // can unload all pixmaps except for the currently visible one + return pageNumber != m_frameIndex; +} + + +// +/* This hack was here to fix 103718 but it's no longer necessary on KDE 3.5 and Lubos asked me to remove it +bool PresentationWidget::event ( QEvent * e ) +{ + if (e -> type() == QEvent::WindowDeactivate) KWin::clearState(winId(), NET::StaysOnTop); + else if (e -> type() == QEvent::WindowActivate) KWin::setState(winId(), NET::StaysOnTop); + return QDialog::event(e); +} +*/ + +void PresentationWidget::keyPressEvent( QKeyEvent * e ) +{ + if (m_width == -1) return; + + if ( e->key() == Key_Left || e->key() == Key_Backspace || e->key() == Key_Prior ) + slotPrevPage(); + else if ( e->key() == Key_Right || e->key() == Key_Space || e->key() == Key_Next ) + slotNextPage(); + else if ( e->key() == Key_Home ) + slotFirstPage(); + else if ( e->key() == Key_End ) + slotLastPage(); + else if ( e->key() == Key_Escape ) + { + if ( m_topBar->isShown() ) + m_topBar->hide(); + else + close(); + } +} + +void PresentationWidget::wheelEvent( QWheelEvent * e ) +{ + // performance note: don't remove the clipping + int div = e->delta() / 120; + if ( div > 0 ) + { + if ( div > 3 ) + div = 3; + while ( div-- ) + slotPrevPage(); + } + else if ( div < 0 ) + { + if ( div < -3 ) + div = -3; + while ( div++ ) + slotNextPage(); + } +} + +void PresentationWidget::mousePressEvent( QMouseEvent * e ) +{ + // pressing left button + if ( e->button() == Qt::LeftButton ) + { + // if pressing on a link, skip other checks + if ( ( m_pressedLink = getLink( e->x(), e->y() ) ) ) + return; + + // handle clicking on top-right overlay + if ( m_overlayGeometry.contains( e->pos() ) ) + { + overlayClick( e->pos() ); + return; + } + + // if no other actions, go to next page + slotNextPage(); + } + // pressing right button + else if ( e->button() == Qt::RightButton ) + slotPrevPage(); +} + +void PresentationWidget::mouseReleaseEvent( QMouseEvent * e ) +{ + // if releasing on the same link we pressed over, execute it + if ( m_pressedLink && e->button() == Qt::LeftButton ) + { + const KPDFLink * link = getLink( e->x(), e->y() ); + if ( link == m_pressedLink ) + m_document->processLink( link ); + m_pressedLink = 0; + } +} + +void PresentationWidget::mouseMoveEvent( QMouseEvent * e ) +{ + // safety check + if ( m_width == -1 ) + return; + + // update cursor and tooltip if hovering a link + if ( KpdfSettings::slidesCursor() != KpdfSettings::EnumSlidesCursor::Hidden ) + testCursorOnLink( e->x(), e->y() ); + + if ( m_topBar->isShown() ) + { + // hide a shown bar when exiting the area + if ( e->y() > ( m_topBar->height() + 1 ) ) + m_topBar->hide(); + } + else + { + // show the bar if reaching top 2 pixels + if ( e->y() <= (geometry().top() + 1) ) + m_topBar->show(); + // handle "dragging the wheel" if clicking on its geometry + else if ( e->state() == Qt::LeftButton && m_overlayGeometry.contains( e->pos() ) ) + overlayClick( e->pos() ); + } +} + +void PresentationWidget::paintEvent( QPaintEvent * pe ) +{ + if (m_width == -1) + { + QRect d = KGlobalSettings::desktopGeometry(this); + m_width = d.width(); + m_height = d.height(); + + // create top toolbar + m_topBar = new KToolBar( this, "presentationBar" ); + m_topBar->setIconSize( 32 ); + m_topBar->setMovingEnabled( false ); + m_topBar->insertButton( QApplication::reverseLayout() ? "1rightarrow" : "1leftarrow", 2, SIGNAL( clicked() ), this, SLOT( slotPrevPage() ) ); + m_topBar->insertButton( QApplication::reverseLayout() ? "1leftarrow" : "1rightarrow", 3, SIGNAL( clicked() ), this, SLOT( slotNextPage() ) ); + m_topBar->insertButton( "exit", 1, SIGNAL( clicked() ), this, SLOT( close() ) ); + m_topBar->setGeometry( 0, 0, m_width, 32 + 10 ); + m_topBar->alignItemRight( 1 ); + m_topBar->hide(); + // change topbar background color + QPalette p = m_topBar->palette(); + p.setColor( QPalette::Active, QColorGroup::Button, Qt::gray ); + p.setColor( QPalette::Active, QColorGroup::Background, Qt::darkGray ); + m_topBar->setPalette( p ); + + // register this observer in document. events will come immediately + m_document->addObserver( this ); + + // show summary if requested + if ( KpdfSettings::slidesShowSummary() ) + generatePage(); + + KMessageBox::information(this, i18n("There are two ways of exiting presentation mode, you can press either ESC key or click with the quit button that appears when placing the mouse in the top-right corner. Of course you can cycle windows (Alt+TAB by default)"), QString::null, "presentationInfo"); + } + + // check painting rect consistancy + QRect r = pe->rect().intersect( geometry() ); + if ( r.isNull() || m_lastRenderedPixmap.isNull() ) + return; + + // blit the pixmap to the screen + QMemArray allRects = pe->region().rects(); + uint numRects = allRects.count(); + for ( uint i = 0; i < numRects; i++ ) + { + const QRect & r = allRects[i]; + if ( !r.isValid() ) + continue; +#ifdef ENABLE_PROGRESS_OVERLAY + if ( KpdfSettings::slidesShowProgress() && r.intersects( m_overlayGeometry ) ) + { + // backbuffer the overlay operation + QPixmap backPixmap( r.size() ); + QPainter pixPainter( &backPixmap ); + + // first draw the background on the backbuffer + pixPainter.drawPixmap( QPoint(0,0), m_lastRenderedPixmap, r ); + + // then blend the overlay (a piece of) over the background + QRect ovr = m_overlayGeometry.intersect( r ); + pixPainter.drawPixmap( ovr.left() - r.left(), ovr.top() - r.top(), + m_lastRenderedOverlay, ovr.left() - m_overlayGeometry.left(), + ovr.top() - m_overlayGeometry.top(), ovr.width(), ovr.height() ); + + // finally blit the pixmap to the screen + pixPainter.end(); + bitBlt( this, r.topLeft(), &backPixmap, backPixmap.rect() ); + } else +#endif + // copy the rendered pixmap to the screen + bitBlt( this, r.topLeft(), &m_lastRenderedPixmap, r ); + } +} +// + + +const KPDFLink * PresentationWidget::getLink( int x, int y, QRect * geometry ) const +{ + // no links on invalid pages + if ( geometry && !geometry->isNull() ) + geometry->setRect( 0, 0, -1, -1 ); + if ( m_frameIndex < 0 || m_frameIndex >= (int)m_frames.size() ) + return 0; + + // get frame, page and geometry + const PresentationFrame * frame = m_frames[ m_frameIndex ]; + const KPDFPage * page = frame->page; + const QRect & frameGeometry = frame->geometry; + + // compute normalized x and y + double nx = (double)(x - frameGeometry.left()) / (double)frameGeometry.width(); + double ny = (double)(y - frameGeometry.top()) / (double)frameGeometry.height(); + + // no links outside the pages + if ( nx < 0 || nx > 1 || ny < 0 || ny > 1 ) + return 0; + + // check if 1) there is an object and 2) it's a link + const ObjectRect * object = page->hasObject( ObjectRect::Link, nx, ny ); + if ( !object ) + return 0; + + // compute link geometry if destination rect present + if ( geometry ) + { + *geometry = object->geometry( frameGeometry.width(), frameGeometry.height() ); + geometry->moveBy( frameGeometry.left(), frameGeometry.top() ); + } + + // return the link pointer + return (KPDFLink *)object->pointer(); +} + +void PresentationWidget::testCursorOnLink( int x, int y ) +{ + // get rect + QRect linkRect; + const KPDFLink * link = getLink( x, y, &linkRect ); + + // only react on changes (in/out from a link) + if ( (link && !m_handCursor) || (!link && m_handCursor) ) + { + // change cursor shape + m_handCursor = link != 0; + setCursor( m_handCursor ? KCursor::handCursor() : KCursor::arrowCursor()); + + // set tooltip over link's rect + QString tip = link ? link->linkTip() : QString::null; + if ( m_handCursor && !tip.isEmpty() ) + QToolTip::add( this, linkRect, tip ); + } +} + +void PresentationWidget::overlayClick( const QPoint & position ) +{ + // clicking the progress indicator + int xPos = position.x() - m_overlayGeometry.x() - m_overlayGeometry.width() / 2, + yPos = m_overlayGeometry.height() / 2 - position.y(); + if ( !xPos && !yPos ) + return; + + // compute angle relative to indicator (note coord transformation) + float angle = 0.5 + 0.5 * atan2( -xPos, -yPos ) / M_PI; + int pageIndex = (int)( angle * ( m_frames.count() - 1 ) + 0.5 ); + + // go to selected page + changePage( pageIndex ); +} + +void PresentationWidget::changePage( int newPage ) +{ + if ( m_frameIndex == newPage ) + return; + + // check if pixmap exists or else request it + m_frameIndex = newPage; + PresentationFrame * frame = m_frames[ m_frameIndex ]; + int pixW = frame->geometry.width(); + int pixH = frame->geometry.height(); + + // if pixmap not inside the KPDFPage we request it and wait for + // notifyPixmapChanged call or else we can proceed to pixmap generation + if ( !frame->page->hasPixmap( PRESENTATION_ID, pixW, pixH ) ) + { + // operation will take long: set busy cursor + QApplication::setOverrideCursor( KCursor::workingCursor() ); + // request the pixmap + QValueList< PixmapRequest * > requests; + requests.push_back( new PixmapRequest( PRESENTATION_ID, m_frameIndex, pixW, pixH, PRESENTATION_PRIO ) ); + // restore cursor + QApplication::restoreOverrideCursor(); + // ask for next and previous page if not in low memory usage setting + if (KpdfSettings::memoryLevel() != KpdfSettings::EnumMemoryLevel::Low && KpdfSettings::enableThreading()) { + if (newPage + 1 < (int)m_document->pages()) + { + PresentationFrame *nextFrame = m_frames[ newPage + 1 ]; + pixW = nextFrame->geometry.width(); + pixH = nextFrame->geometry.height(); + if ( !nextFrame->page->hasPixmap( PRESENTATION_ID, pixW, pixH ) ) + requests.push_back( new PixmapRequest( PRESENTATION_ID, newPage + 1, pixW, pixH, PRESENTATION_PRELOAD_PRIO, true ) ); + } + if (newPage - 1 >= 0) + { + PresentationFrame *prevFrame = m_frames[ newPage - 1 ]; + pixW = prevFrame->geometry.width(); + pixH = prevFrame->geometry.height(); + if ( !prevFrame->page->hasPixmap( PRESENTATION_ID, pixW, pixH ) ) + requests.push_back( new PixmapRequest( PRESENTATION_ID, newPage - 1, pixW, pixH, PRESENTATION_PRELOAD_PRIO, true ) ); + } + } + m_document->requestPixmaps( requests ); + } + else + { + // make the background pixmap + generatePage(); + } + + // set a new viewport in document if page number differs + if ( m_frameIndex != -1 && m_frameIndex != m_document->viewport().pageNumber ) + m_document->setViewportPage( m_frameIndex, PRESENTATION_ID ); +} + +void PresentationWidget::generatePage() +{ + if ( m_lastRenderedPixmap.isNull() ) + m_lastRenderedPixmap.resize( m_width, m_height ); + + // opens the painter over the pixmap + QPainter pixmapPainter; + pixmapPainter.begin( &m_lastRenderedPixmap ); + // generate welcome page + if ( m_frameIndex == -1 ) + generateIntroPage( pixmapPainter ); + // generate a normal pixmap with extended margin filling + if ( m_frameIndex >= 0 && m_frameIndex < (int)m_document->pages() ) + generateContentsPage( m_frameIndex, pixmapPainter ); + pixmapPainter.end(); + + // generate the top-right corner overlay +#ifdef ENABLE_PROGRESS_OVERLAY + if ( KpdfSettings::slidesShowProgress() && m_frameIndex != -1 ) + generateOverlay(); +#endif + + // start transition on pages that have one + const KPDFPageTransition * transition = m_frameIndex != -1 ? + m_frames[ m_frameIndex ]->page->getTransition() : 0; + if ( transition ) + initTransition( transition ); + else { + KPDFPageTransition trans = defaultTransition(); + initTransition( &trans ); + } + + // update cursor + tooltip + if ( KpdfSettings::slidesCursor() != KpdfSettings::EnumSlidesCursor::Hidden ) + { + QPoint p = mapFromGlobal( QCursor::pos() ); + testCursorOnLink( p.x(), p.y() ); + } +} + +void PresentationWidget::generateIntroPage( QPainter & p ) +{ + // use a vertical gray gradient background + int blend1 = m_height / 10, + blend2 = 9 * m_height / 10; + int baseTint = Qt::gray.red(); + for ( int i = 0; i < m_height; i++ ) + { + int k = baseTint; + if ( i < blend1 ) + k -= (int)( baseTint * (i-blend1)*(i-blend1) / (float)(blend1 * blend1) ); + if ( i > blend2 ) + k += (int)( (255-baseTint) * (i-blend2)*(i-blend2) / (float)(blend1 * blend1) ); + p.fillRect( 0, i, m_width, 1, QColor( k, k, k ) ); + } + + // draw kpdf logo in the four corners + QPixmap logo = DesktopIcon( "kpdf", 64 ); + if ( !logo.isNull() ) + { + p.drawPixmap( 5, 5, logo ); + p.drawPixmap( m_width - 5 - logo.width(), 5, logo ); + p.drawPixmap( m_width - 5 - logo.width(), m_height - 5 - logo.height(), logo ); + p.drawPixmap( 5, m_height - 5 - logo.height(), logo ); + } + + // draw metadata text (the last line is 'click to begin') + int strNum = m_metaStrings.count(), + strHeight = m_height / ( strNum + 4 ), + fontHeight = 2 * strHeight / 3; + QFont font( p.font() ); + font.setPixelSize( fontHeight ); + QFontMetrics metrics( font ); + for ( int i = 0; i < strNum; i++ ) + { + // set a font to fit text width + float wScale = (float)metrics.boundingRect( m_metaStrings[i] ).width() / (float)m_width; + QFont f( font ); + if ( wScale > 1.0 ) + f.setPixelSize( (int)( (float)fontHeight / (float)wScale ) ); + p.setFont( f ); + + // text shadow + p.setPen( Qt::darkGray ); + p.drawText( 2, m_height / 4 + strHeight * i + 2, m_width, strHeight, + AlignHCenter | AlignVCenter, m_metaStrings[i] ); + // text body + p.setPen( 128 + (127 * i) / strNum ); + p.drawText( 0, m_height / 4 + strHeight * i, m_width, strHeight, + AlignHCenter | AlignVCenter, m_metaStrings[i] ); + } +} + +void PresentationWidget::generateContentsPage( int pageNum, QPainter & p ) +{ + PresentationFrame * frame = m_frames[ pageNum ]; + + // translate painter and contents rect + QRect geom( frame->geometry ); + p.translate( geom.left(), geom.top() ); + geom.moveBy( -geom.left(), -geom.top() ); + + // draw the page using the shared PagePainter class + int flags = PagePainter::Accessibility; + PagePainter::paintPageOnPainter( frame->page, PRESENTATION_ID, flags, + &p, geom, geom.width(), geom.height() ); + + // restore painter + p.translate( -frame->geometry.left(), -frame->geometry.top() ); + + // fill unpainted areas with background color + QRegion unpainted( QRect( 0, 0, m_width, m_height ) ); + QMemArray rects = unpainted.subtract( frame->geometry ).rects(); + for ( uint i = 0; i < rects.count(); i++ ) + { + const QRect & r = rects[i]; + p.fillRect( r, KpdfSettings::slidesBackgroundColor() ); + } +} + +// from Arthur - Qt4 - (is defined elsewhere as 'qt_div_255' to not break final compilation) +inline int qt_div255(int x) { return (x + (x>>8) + 0x80) >> 8; } +void PresentationWidget::generateOverlay() +{ +#ifdef ENABLE_PROGRESS_OVERLAY + // calculate overlay geometry and resize pixmap if needed + int side = m_width / 16; + m_overlayGeometry.setRect( m_width - side - 4, 4, side, side ); + if ( m_lastRenderedOverlay.width() != side ) + m_lastRenderedOverlay.resize( side, side ); + + // note: to get a sort of antialiasing, we render the pixmap double sized + // and the resulting image is smoothly scaled down. So here we open a + // painter on the double sized pixmap. + side *= 2; + QPixmap doublePixmap( side, side ); + doublePixmap.fill( Qt::black ); + QPainter pixmapPainter( &doublePixmap ); + + // draw PIE SLICES in blue levels (the levels will then be the alpha component) + int pages = m_document->pages(); + if ( pages > 28 ) + { // draw continuous slices + int degrees = (int)( 360 * (float)(m_frameIndex + 1) / (float)pages ); + pixmapPainter.setPen( 0x05 ); + pixmapPainter.setBrush( 0x40 ); + pixmapPainter.drawPie( 2, 2, side - 4, side - 4, 90*16, (360-degrees)*16 ); + pixmapPainter.setPen( 0x40 ); + pixmapPainter.setBrush( 0xF0 ); + pixmapPainter.drawPie( 2, 2, side - 4, side - 4, 90*16, -degrees*16 ); + } + else + { // draw discrete slices + float oldCoord = -90; + for ( int i = 0; i < pages; i++ ) + { + float newCoord = -90 + 360 * (float)(i + 1) / (float)pages; + pixmapPainter.setPen( i <= m_frameIndex ? 0x40 : 0x05 ); + pixmapPainter.setBrush( i <= m_frameIndex ? 0xF0 : 0x40 ); + pixmapPainter.drawPie( 2, 2, side - 4, side - 4, + (int)( -16*(oldCoord + 1) ), (int)( -16*(newCoord - (oldCoord + 2)) ) ); + oldCoord = newCoord; + } + } + int circleOut = side / 4; + pixmapPainter.setPen( Qt::black ); + pixmapPainter.setBrush( Qt::black ); + pixmapPainter.drawEllipse( circleOut, circleOut, side - 2*circleOut, side - 2*circleOut ); + + // draw TEXT using maximum opacity + QFont f( pixmapPainter.font() ); + f.setPixelSize( side / 4 ); + pixmapPainter.setFont( f ); + pixmapPainter.setPen( 0xFF ); + // use a little offset to prettify output + pixmapPainter.drawText( 2, 2, side, side, Qt::AlignCenter, QString::number( m_frameIndex + 1 ) ); + + // end drawing pixmap and halve image + pixmapPainter.end(); + QImage image( doublePixmap.convertToImage().smoothScale( side / 2, side / 2 ) ); + image.setAlphaBuffer( true ); + + // draw circular shadow using the same technique + doublePixmap.fill( Qt::black ); + pixmapPainter.begin( &doublePixmap ); + pixmapPainter.setPen( 0x40 ); + pixmapPainter.setBrush( 0x80 ); + pixmapPainter.drawEllipse( 0, 0, side, side ); + pixmapPainter.end(); + QImage shadow( doublePixmap.convertToImage().smoothScale( side / 2, side / 2 ) ); + + // generate a 2 colors pixmap using mixing shadow (made with highlight color) + // and image (made with highlightedText color) + QColor color = palette().active().highlightedText(); + int red = color.red(), green = color.green(), blue = color.blue(); + color = palette().active().highlight(); + int sRed = color.red(), sGreen = color.green(), sBlue = color.blue(); + // pointers + unsigned int * data = (unsigned int *)image.bits(), + * shadowData = (unsigned int *)shadow.bits(), + pixels = image.width() * image.height(); + // cache data (reduce computation time to 26%!) + int c1 = -1, c2 = -1, cR = 0, cG = 0, cB = 0, cA = 0; + // foreach pixel + for( unsigned int i = 0; i < pixels; ++i ) + { + // alpha for shadow and image + int shadowAlpha = shadowData[i] & 0xFF, + srcAlpha = data[i] & 0xFF; + // cache values + if ( srcAlpha != c1 || shadowAlpha != c2 ) + { + c1 = srcAlpha; + c2 = shadowAlpha; + // fuse color components and alpha value of image over shadow + data[i] = qRgba( + cR = qt_div255( srcAlpha * red + (255 - srcAlpha) * sRed ), + cG = qt_div255( srcAlpha * green + (255 - srcAlpha) * sGreen ), + cB = qt_div255( srcAlpha * blue + (255 - srcAlpha) * sBlue ), + cA = qt_div255( srcAlpha * srcAlpha + (255 - srcAlpha) * shadowAlpha ) + ); + } + else + data[i] = qRgba( cR, cG, cB, cA ); + } + m_lastRenderedOverlay.convertFromImage( image ); + + // start the autohide timer + repaint( m_overlayGeometry, false /*clear*/ ); // toggle with next line + //update( m_overlayGeometry ); + m_overlayHideTimer->start( 2500, true ); +#endif +} + + + +void PresentationWidget::slotNextPage() +{ + // loop when configured + if ( m_frameIndex == (int)m_frames.count() - 1 && KpdfSettings::slidesLoop() ) + m_frameIndex = -1; + + if ( m_frameIndex < (int)m_frames.count() - 1 ) + { + // go to next page + changePage( m_frameIndex + 1 ); + + // auto advance to the next page if set + if ( KpdfSettings::slidesAdvance() ) + m_nextPageTimer->start( KpdfSettings::slidesAdvanceTime() * 1000 ); + } + else + { +#ifdef ENABLE_PROGRESS_OVERLAY + if ( KpdfSettings::slidesShowProgress() ) + generateOverlay(); +#endif + if ( m_transitionTimer->isActive() ) + { + m_transitionTimer->stop(); + update(); + } + } + + // we need the setFocus() call here to let KCursor::autoHide() work correctly + setFocus(); +} + +void PresentationWidget::slotPrevPage() +{ + if ( m_frameIndex > 0 ) + { + // go to previous page + changePage( m_frameIndex - 1 ); + + // auto advance to the next page if set + if ( KpdfSettings::slidesAdvance() ) + m_nextPageTimer->start( KpdfSettings::slidesAdvanceTime() * 1000 ); + } + else + { +#ifdef ENABLE_PROGRESS_OVERLAY + if ( KpdfSettings::slidesShowProgress() ) + generateOverlay(); +#endif + if ( m_transitionTimer->isActive() ) + { + m_transitionTimer->stop(); + update(); + } + } +} + +void PresentationWidget::slotFirstPage() +{ + changePage( 0 ); +} + +void PresentationWidget::slotLastPage() +{ + changePage( (int)m_frames.count() - 1 ); +} + +void PresentationWidget::slotHideOverlay() +{ + QRect geom( m_overlayGeometry ); + m_overlayGeometry.setCoords( 0, 0, -1, -1 ); + update( geom ); +} + +void PresentationWidget::slotTransitionStep() +{ + if ( m_transitionRects.empty() ) + { + // it's better to fix the transition to cover the whole screen than + // enabling the following line that wastes cpu for nothing + //update(); + return; + } + + for ( int i = 0; i < m_transitionMul && !m_transitionRects.empty(); i++ ) + { + update( m_transitionRects.first() ); + m_transitionRects.pop_front(); + } + m_transitionTimer->start( m_transitionDelay, true ); +} + +const KPDFPageTransition PresentationWidget::defaultTransition() const +{ + return defaultTransition( KpdfSettings::slidesTransition() ); +} + +const KPDFPageTransition PresentationWidget::defaultTransition( int type ) const +{ + switch ( type ) + { + case KpdfSettings::EnumSlidesTransition::BlindsHorizontal: + { + KPDFPageTransition transition( KPDFPageTransition::Blinds ); + transition.setAlignment( KPDFPageTransition::Horizontal ); + return transition; + break; + } + case KpdfSettings::EnumSlidesTransition::BlindsVertical: + { + KPDFPageTransition transition( KPDFPageTransition::Blinds ); + transition.setAlignment( KPDFPageTransition::Vertical ); + return transition; + break; + } + case KpdfSettings::EnumSlidesTransition::BoxIn: + { + KPDFPageTransition transition( KPDFPageTransition::Box ); + transition.setDirection( KPDFPageTransition::Inward ); + return transition; + break; + } + case KpdfSettings::EnumSlidesTransition::BoxOut: + { + KPDFPageTransition transition( KPDFPageTransition::Box ); + transition.setDirection( KPDFPageTransition::Outward ); + return transition; + break; + } + case KpdfSettings::EnumSlidesTransition::Dissolve: + { + return KPDFPageTransition( KPDFPageTransition::Dissolve ); + break; + } + case KpdfSettings::EnumSlidesTransition::GlitterDown: + { + KPDFPageTransition transition( KPDFPageTransition::Glitter ); + transition.setAngle( 270 ); + return transition; + break; + } + case KpdfSettings::EnumSlidesTransition::GlitterRight: + { + KPDFPageTransition transition( KPDFPageTransition::Glitter ); + transition.setAngle( 0 ); + return transition; + break; + } + case KpdfSettings::EnumSlidesTransition::GlitterRightDown: + { + KPDFPageTransition transition( KPDFPageTransition::Glitter ); + transition.setAngle( 315 ); + return transition; + break; + } + case KpdfSettings::EnumSlidesTransition::Random: + { + return defaultTransition( KApplication::random() % 18 ); + break; + } + case KpdfSettings::EnumSlidesTransition::SplitHorizontalIn: + { + KPDFPageTransition transition( KPDFPageTransition::Split ); + transition.setAlignment( KPDFPageTransition::Horizontal ); + transition.setDirection( KPDFPageTransition::Inward ); + return transition; + break; + } + case KpdfSettings::EnumSlidesTransition::SplitHorizontalOut: + { + KPDFPageTransition transition( KPDFPageTransition::Split ); + transition.setAlignment( KPDFPageTransition::Horizontal ); + transition.setDirection( KPDFPageTransition::Outward ); + return transition; + break; + } + case KpdfSettings::EnumSlidesTransition::SplitVerticalIn: + { + KPDFPageTransition transition( KPDFPageTransition::Split ); + transition.setAlignment( KPDFPageTransition::Vertical ); + transition.setDirection( KPDFPageTransition::Inward ); + return transition; + break; + } + case KpdfSettings::EnumSlidesTransition::SplitVerticalOut: + { + KPDFPageTransition transition( KPDFPageTransition::Split ); + transition.setAlignment( KPDFPageTransition::Vertical ); + transition.setDirection( KPDFPageTransition::Outward ); + return transition; + break; + } + case KpdfSettings::EnumSlidesTransition::WipeDown: + { + KPDFPageTransition transition( KPDFPageTransition::Wipe ); + transition.setAngle( 270 ); + return transition; + break; + } + case KpdfSettings::EnumSlidesTransition::WipeRight: + { + KPDFPageTransition transition( KPDFPageTransition::Wipe ); + transition.setAngle( 0 ); + return transition; + break; + } + case KpdfSettings::EnumSlidesTransition::WipeLeft: + { + KPDFPageTransition transition( KPDFPageTransition::Wipe ); + transition.setAngle( 180 ); + return transition; + break; + } + case KpdfSettings::EnumSlidesTransition::WipeUp: + { + KPDFPageTransition transition( KPDFPageTransition::Wipe ); + transition.setAngle( 90 ); + return transition; + break; + } + case KpdfSettings::EnumSlidesTransition::Replace: + default: + return KPDFPageTransition( KPDFPageTransition::Replace ); + break; + } +} + +/** ONLY the TRANSITIONS GENERATION function from here on **/ +void PresentationWidget::initTransition( const KPDFPageTransition *transition ) +{ + // if it's just a 'replace' transition, repaint the screen + if ( transition->type() == KPDFPageTransition::Replace ) + { + update(); + return; + } + + const bool isInward = transition->direction() == KPDFPageTransition::Inward; + const bool isHorizontal = transition->alignment() == KPDFPageTransition::Horizontal; + const float totalTime = transition->duration(); + + m_transitionRects.clear(); + + switch( transition->type() ) + { + // split: horizontal / vertical and inward / outward + case KPDFPageTransition::Split: + { + const int steps = isHorizontal ? 100 : 75; + if ( isHorizontal ) + { + if ( isInward ) + { + int xPosition = 0; + for ( int i = 0; i < steps; i++ ) + { + int xNext = ((i + 1) * m_width) / (2 * steps); + m_transitionRects.push_back( QRect( xPosition, 0, xNext - xPosition, m_height ) ); + m_transitionRects.push_back( QRect( m_width - xNext, 0, xNext - xPosition, m_height ) ); + xPosition = xNext; + } + } + else + { + int xPosition = m_width / 2; + for ( int i = 0; i < steps; i++ ) + { + int xNext = ((steps - (i + 1)) * m_width) / (2 * steps); + m_transitionRects.push_back( QRect( xNext, 0, xPosition - xNext, m_height ) ); + m_transitionRects.push_back( QRect( m_width - xPosition, 0, xPosition - xNext, m_height ) ); + xPosition = xNext; + } + } + } + else + { + if ( isInward ) + { + int yPosition = 0; + for ( int i = 0; i < steps; i++ ) + { + int yNext = ((i + 1) * m_height) / (2 * steps); + m_transitionRects.push_back( QRect( 0, yPosition, m_width, yNext - yPosition ) ); + m_transitionRects.push_back( QRect( 0, m_height - yNext, m_width, yNext - yPosition ) ); + yPosition = yNext; + } + } + else + { + int yPosition = m_height / 2; + for ( int i = 0; i < steps; i++ ) + { + int yNext = ((steps - (i + 1)) * m_height) / (2 * steps); + m_transitionRects.push_back( QRect( 0, yNext, m_width, yPosition - yNext ) ); + m_transitionRects.push_back( QRect( 0, m_height - yPosition, m_width, yPosition - yNext ) ); + yPosition = yNext; + } + } + } + m_transitionMul = 2; + m_transitionDelay = (int)( (totalTime * 1000) / steps ); + } break; + + // blinds: horizontal(l-to-r) / vertical(t-to-b) + case KPDFPageTransition::Blinds: + { + const int blinds = isHorizontal ? 8 : 6; + const int steps = m_width / (4 * blinds); + if ( isHorizontal ) + { + int xPosition[ 8 ]; + for ( int b = 0; b < blinds; b++ ) + xPosition[ b ] = (b * m_width) / blinds; + + for ( int i = 0; i < steps; i++ ) + { + int stepOffset = (int)( ((float)i * (float)m_width) / ((float)blinds * (float)steps) ); + for ( int b = 0; b < blinds; b++ ) + { + m_transitionRects.push_back( QRect( xPosition[ b ], 0, stepOffset, m_height ) ); + xPosition[ b ] = stepOffset + (b * m_width) / blinds; + } + } + } + else + { + int yPosition[ 6 ]; + for ( int b = 0; b < blinds; b++ ) + yPosition[ b ] = (b * m_height) / blinds; + + for ( int i = 0; i < steps; i++ ) + { + int stepOffset = (int)( ((float)i * (float)m_height) / ((float)blinds * (float)steps) ); + for ( int b = 0; b < blinds; b++ ) + { + m_transitionRects.push_back( QRect( 0, yPosition[ b ], m_width, stepOffset ) ); + yPosition[ b ] = stepOffset + (b * m_height) / blinds; + } + } + } + m_transitionMul = blinds; + m_transitionDelay = (int)( (totalTime * 1000) / steps ); + } break; + + // box: inward / outward + case KPDFPageTransition::Box: + { + const int steps = m_width / 10; + if ( isInward ) + { + int L = 0, T = 0, R = m_width, B = m_height; + for ( int i = 0; i < steps; i++ ) + { + // compure shrinked box coords + int newL = ((i + 1) * m_width) / (2 * steps); + int newT = ((i + 1) * m_height) / (2 * steps); + int newR = m_width - newL; + int newB = m_height - newT; + // add left, right, topcenter, bottomcenter rects + m_transitionRects.push_back( QRect( L, T, newL - L, B - T ) ); + m_transitionRects.push_back( QRect( newR, T, R - newR, B - T ) ); + m_transitionRects.push_back( QRect( newL, T, newR - newL, newT - T ) ); + m_transitionRects.push_back( QRect( newL, newB, newR - newL, B - newB ) ); + L = newL; T = newT; R = newR, B = newB; + } + } + else + { + int L = m_width / 2, T = m_height / 2, R = L, B = T; + for ( int i = 0; i < steps; i++ ) + { + // compure shrinked box coords + int newL = ((steps - (i + 1)) * m_width) / (2 * steps); + int newT = ((steps - (i + 1)) * m_height) / (2 * steps); + int newR = m_width - newL; + int newB = m_height - newT; + // add left, right, topcenter, bottomcenter rects + m_transitionRects.push_back( QRect( newL, newT, L - newL, newB - newT ) ); + m_transitionRects.push_back( QRect( R, newT, newR - R, newB - newT ) ); + m_transitionRects.push_back( QRect( L, newT, R - L, T - newT ) ); + m_transitionRects.push_back( QRect( L, B, R - L, newB - B ) ); + L = newL; T = newT; R = newR, B = newB; + } + } + m_transitionMul = 4; + m_transitionDelay = (int)( (totalTime * 1000) / steps ); + } break; + + // wipe: implemented for 4 canonical angles + case KPDFPageTransition::Wipe: + { + const int angle = transition->angle(); + const int steps = (angle == 0) || (angle == 180) ? m_width / 8 : m_height / 8; + if ( angle == 0 ) + { + int xPosition = 0; + for ( int i = 0; i < steps; i++ ) + { + int xNext = ((i + 1) * m_width) / steps; + m_transitionRects.push_back( QRect( xPosition, 0, xNext - xPosition, m_height ) ); + xPosition = xNext; + } + } + else if ( angle == 90 ) + { + int yPosition = m_height; + for ( int i = 0; i < steps; i++ ) + { + int yNext = ((steps - (i + 1)) * m_height) / steps; + m_transitionRects.push_back( QRect( 0, yNext, m_width, yPosition - yNext ) ); + yPosition = yNext; + } + } + else if ( angle == 180 ) + { + int xPosition = m_width; + for ( int i = 0; i < steps; i++ ) + { + int xNext = ((steps - (i + 1)) * m_width) / steps; + m_transitionRects.push_back( QRect( xNext, 0, xPosition - xNext, m_height ) ); + xPosition = xNext; + } + } + else if ( angle == 270 ) + { + int yPosition = 0; + for ( int i = 0; i < steps; i++ ) + { + int yNext = ((i + 1) * m_height) / steps; + m_transitionRects.push_back( QRect( 0, yPosition, m_width, yNext - yPosition ) ); + yPosition = yNext; + } + } + else + { + update(); + return; + } + m_transitionMul = 1; + m_transitionDelay = (int)( (totalTime * 1000) / steps ); + } break; + + // dissolve: replace 'random' rects + case KPDFPageTransition::Dissolve: + { + const int gridXsteps = 50; + const int gridYsteps = 38; + const int steps = gridXsteps * gridYsteps; + int oldX = 0; + int oldY = 0; + // create a grid of gridXstep by gridYstep QRects + for ( int y = 0; y < gridYsteps; y++ ) + { + int newY = (int)( m_height * ((float)(y+1) / (float)gridYsteps) ); + for ( int x = 0; x < gridXsteps; x++ ) + { + int newX = (int)( m_width * ((float)(x+1) / (float)gridXsteps) ); + m_transitionRects.push_back( QRect( oldX, oldY, newX - oldX, newY - oldY ) ); + oldX = newX; + } + oldX = 0; + oldY = newY; + } + // randomize the grid + for ( int i = 0; i < steps; i++ ) + { + int n1 = (int)(steps * drand48()); + int n2 = (int)(steps * drand48()); + // swap items if index differs + if ( n1 != n2 ) + { + QRect r = m_transitionRects[ n2 ]; + m_transitionRects[ n2 ] = m_transitionRects[ n1 ]; + m_transitionRects[ n1 ] = r; + } + } + // set global transition parameters + m_transitionMul = 40; + m_transitionDelay = (int)( (m_transitionMul * 1000 * totalTime) / steps ); + } break; + + // glitter: similar to dissolve but has a direction + case KPDFPageTransition::Glitter: + { + const int gridXsteps = 50; + const int gridYsteps = 38; + const int steps = gridXsteps * gridYsteps; + const int angle = transition->angle(); + // generate boxes using a given direction + if ( angle == 90 ) + { + int yPosition = m_height; + for ( int i = 0; i < gridYsteps; i++ ) + { + int yNext = ((gridYsteps - (i + 1)) * m_height) / gridYsteps; + int xPosition = 0; + for ( int j = 0; j < gridXsteps; j++ ) + { + int xNext = ((j + 1) * m_width) / gridXsteps; + m_transitionRects.push_back( QRect( xPosition, yNext, xNext - xPosition, yPosition - yNext ) ); + xPosition = xNext; + } + yPosition = yNext; + } + } + else if ( angle == 180 ) + { + int xPosition = m_width; + for ( int i = 0; i < gridXsteps; i++ ) + { + int xNext = ((gridXsteps - (i + 1)) * m_width) / gridXsteps; + int yPosition = 0; + for ( int j = 0; j < gridYsteps; j++ ) + { + int yNext = ((j + 1) * m_height) / gridYsteps; + m_transitionRects.push_back( QRect( xNext, yPosition, xPosition - xNext, yNext - yPosition ) ); + yPosition = yNext; + } + xPosition = xNext; + } + } + else if ( angle == 270 ) + { + int yPosition = 0; + for ( int i = 0; i < gridYsteps; i++ ) + { + int yNext = ((i + 1) * m_height) / gridYsteps; + int xPosition = 0; + for ( int j = 0; j < gridXsteps; j++ ) + { + int xNext = ((j + 1) * m_width) / gridXsteps; + m_transitionRects.push_back( QRect( xPosition, yPosition, xNext - xPosition, yNext - yPosition ) ); + xPosition = xNext; + } + yPosition = yNext; + } + } + else // if angle is 0 or 315 + { + int xPosition = 0; + for ( int i = 0; i < gridXsteps; i++ ) + { + int xNext = ((i + 1) * m_width) / gridXsteps; + int yPosition = 0; + for ( int j = 0; j < gridYsteps; j++ ) + { + int yNext = ((j + 1) * m_height) / gridYsteps; + m_transitionRects.push_back( QRect( xPosition, yPosition, xNext - xPosition, yNext - yPosition ) ); + yPosition = yNext; + } + xPosition = xNext; + } + } + // add a 'glitter' (1 over 10 pieces is randomized) + int randomSteps = steps / 20; + for ( int i = 0; i < randomSteps; i++ ) + { + int n1 = (int)(steps * drand48()); + int n2 = (int)(steps * drand48()); + // swap items if index differs + if ( n1 != n2 ) + { + QRect r = m_transitionRects[ n2 ]; + m_transitionRects[ n2 ] = m_transitionRects[ n1 ]; + m_transitionRects[ n1 ] = r; + } + } + // set global transition parameters + m_transitionMul = (angle == 90) || (angle == 270) ? gridYsteps : gridXsteps; + m_transitionMul /= 2; + m_transitionDelay = (int)( (m_transitionMul * 1000 * totalTime) / steps ); + } break; + + // implement missing transitions (a binary raster engine needed here) + case KPDFPageTransition::Fly: + + case KPDFPageTransition::Push: + + case KPDFPageTransition::Cover: + + case KPDFPageTransition::Uncover: + + case KPDFPageTransition::Fade: + + default: + update(); + return; + } + + // send the first start to the timer + m_transitionTimer->start( 0, true ); +} + + +#include "presentationwidget.moc" diff --git a/kpdf/ui/presentationwidget.h b/kpdf/ui/presentationwidget.h new file mode 100644 index 00000000..4b0cdf19 --- /dev/null +++ b/kpdf/ui/presentationwidget.h @@ -0,0 +1,108 @@ +/*************************************************************************** + * Copyright (C) 2004 by Enrico Ros * + * * + * 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. * + ***************************************************************************/ + +#ifndef _KPDF_PRESENTATIONWIDGET_H_ +#define _KPDF_PRESENTATIONWIDGET_H_ + +#include +#include +#include +#include +#include "core/observer.h" +#include "core/pagetransition.h" + +class KAccel; +class KActionCollection; +class KToolBar; +class QTimer; + +class KPDFDocument; +class KPDFPage; +class KPDFLink; +class PresentationFrame; + +/** + * @short A widget that shows pages as fullscreen slides (with transitions fx). + * + * This is a fullscreen widget that displays + */ +class PresentationWidget : public QDialog, public DocumentObserver +{ + Q_OBJECT + public: + PresentationWidget( QWidget * parent, KPDFDocument * doc ); + ~PresentationWidget(); + + void setupActions( KActionCollection * ac ); + + // inherited from DocumentObserver + uint observerId() const { return PRESENTATION_ID; } + void notifySetup( const QValueVector< KPDFPage * > & pages, bool documentChanged ); + void notifyViewportChanged( bool smoothMove ); + void notifyPageChanged( int pageNumber, int changedFlags ); + bool canUnloadPixmap( int pageNumber ); + + protected: + // widget events +// bool event( QEvent * e ); + void keyPressEvent( QKeyEvent * e ); + void wheelEvent( QWheelEvent * e ); + void mousePressEvent( QMouseEvent * e ); + void mouseReleaseEvent( QMouseEvent * e ); + void mouseMoveEvent( QMouseEvent * e ); + void paintEvent( QPaintEvent * e ); + + private: + const KPDFLink * getLink( int x, int y, QRect * geometry = 0 ) const; + void testCursorOnLink( int x, int y ); + void overlayClick( const QPoint & position ); + void changePage( int newPage ); + void generatePage(); + void generateIntroPage( QPainter & p ); + void generateContentsPage( int page, QPainter & p ); + void generateOverlay(); + void initTransition( const KPDFPageTransition *transition ); + const KPDFPageTransition defaultTransition() const; + const KPDFPageTransition defaultTransition( int ) const; + + // cache stuff + int m_width; + int m_height; + QPixmap m_lastRenderedPixmap; + QPixmap m_lastRenderedOverlay; + QRect m_overlayGeometry; + const KPDFLink * m_pressedLink; + bool m_handCursor; + + // transition related + QTimer * m_transitionTimer; + QTimer * m_overlayHideTimer; + QTimer * m_nextPageTimer; + int m_transitionDelay; + int m_transitionMul; + QValueList< QRect > m_transitionRects; + + // misc stuff + KPDFDocument * m_document; + QValueVector< PresentationFrame * > m_frames; + int m_frameIndex; + QStringList m_metaStrings; + KToolBar * m_topBar; + KAccel * m_accel; + + private slots: + void slotNextPage(); + void slotPrevPage(); + void slotFirstPage(); + void slotLastPage(); + void slotHideOverlay(); + void slotTransitionStep(); +}; + +#endif diff --git a/kpdf/ui/propertiesdialog.cpp b/kpdf/ui/propertiesdialog.cpp new file mode 100644 index 00000000..d5810a07 --- /dev/null +++ b/kpdf/ui/propertiesdialog.cpp @@ -0,0 +1,94 @@ +/*************************************************************************** + * Copyright (C) 2004 by Albert Astals Cid * + * * + * 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. * + ***************************************************************************/ + +// qt/kde includes +#include +#include +#include +#include +#include +#include + +// local includes +#include "propertiesdialog.h" +#include "core/document.h" + +PropertiesDialog::PropertiesDialog(QWidget *parent, KPDFDocument *doc) + : KDialogBase( Tabbed, i18n( "Unknown File" ), Ok, Ok, parent, 0, true, true ) +{ + // Properties + QFrame *page = addPage(i18n("Properties")); + QGridLayout *layout = new QGridLayout( page, 2, 2, marginHint(), spacingHint() ); + + // get document info, if not present display blank data and a warning + const DocumentInfo * info = doc->documentInfo(); + if ( !info ) { + layout->addWidget( new QLabel( i18n( "No document opened." ), page ), 0, 0 ); + return; + } + + // mime name based on mimetype id + QString mimeName = info->get( "mimeType" ).section( '/', -1 ).upper(); + setCaption( i18n("%1 Properties").arg( mimeName ) ); + + QDomElement docElement = info->documentElement(); + + int row = 0; + int valMaxWidth = 100; + for ( QDomNode node = docElement.firstChild(); !node.isNull(); node = node.nextSibling() ) { + QDomElement element = node.toElement(); + + QString titleString = element.attribute( "title" ); + QString valueString = element.attribute( "value" ); + if ( titleString.isEmpty() || valueString.isEmpty() ) + continue; + + // create labels and layout them + QLabel *key = new QLabel( i18n( "%1:" ).arg( titleString ), page ); + QLabel *value = new KSqueezedTextLabel( valueString, page ); + layout->addWidget( key, row, 0, AlignRight ); + layout->addWidget( value, row, 1 ); + row++; + + // refine maximum width of 'value' labels + valMaxWidth = QMAX( valMaxWidth, fontMetrics().width( valueString ) ); + } + + // add the number of pages if the generator hasn't done it already + QDomNodeList list = docElement.elementsByTagName( "pages" ); + if ( list.count() == 0 ) { + QLabel *key = new QLabel( i18n( "Pages:" ), page ); + QLabel *value = new QLabel( QString::number( doc->pages() ), page ); + + layout->addWidget( key, row, 0 ); + layout->addWidget( value, row, 1 ); + } + + // Fonts + QVBoxLayout *page2Layout = 0; + if (doc->hasFonts()) + { + QFrame *page2 = addPage(i18n("Fonts")); + page2Layout = new QVBoxLayout(page2, 0, KDialog::spacingHint()); + KListView *lv = new KListView(page2); + page2Layout->add(lv); + doc->putFontInfo(lv); + } + + // current width: left column + right column + dialog borders + int width = layout->minimumSize().width() + valMaxWidth + marginHint() + spacingHint() + marginHint() + 30; + if (page2Layout) + { + width = QMAX( width, page2Layout->sizeHint().width() + marginHint() + spacingHint() + 31 ); + } + // stay inside the 2/3 of the screen width + QRect screenContainer = KGlobalSettings::desktopGeometry( this ); + width = QMIN( width, 2*screenContainer.width()/3 ); + resize(width, 1); +} diff --git a/kpdf/ui/propertiesdialog.h b/kpdf/ui/propertiesdialog.h new file mode 100644 index 00000000..7bc39e5a --- /dev/null +++ b/kpdf/ui/propertiesdialog.h @@ -0,0 +1,23 @@ +/*************************************************************************** + * Copyright (C) 2004 by Albert Astals Cid * + * * + * 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. * + ***************************************************************************/ + +#ifndef _PROPERTIESDIALOG_H_ +#define _PROPERTIESDIALOG_H_ + +#include + +class KPDFDocument; + +class PropertiesDialog : public KDialogBase +{ + public: + PropertiesDialog( QWidget *parent, KPDFDocument *doc ); +}; + +#endif diff --git a/kpdf/ui/searchwidget.cpp b/kpdf/ui/searchwidget.cpp new file mode 100644 index 00000000..30a5bcf2 --- /dev/null +++ b/kpdf/ui/searchwidget.cpp @@ -0,0 +1,135 @@ +/*************************************************************************** + * Copyright (C) 2004 by Enrico Ros * + * * + * 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. * + ***************************************************************************/ + +// qt/kde includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// local includes +#include "searchwidget.h" +#include "core/document.h" +#include "conf/settings.h" + +#define CLEAR_ID 1 +#define LEDIT_ID 2 +#define FIND_ID 3 + +SearchWidget::SearchWidget( QWidget * parent, KPDFDocument * document ) + : KToolBar( parent, "iSearchBar" ), m_document( document ), + m_searchType( 0 ), m_caseSensitive( false ) +{ + // change toolbar appearance + setMargin( 3 ); + setFlat( true ); + setIconSize( 16 ); + setMovingEnabled( false ); + + // a timer to ensure that we don't flood the document with requests to search + m_inputDelayTimer = new QTimer(this); + connect( m_inputDelayTimer, SIGNAL( timeout() ), + this, SLOT( startSearch() ) ); + + // 1. text line + insertLined( QString::null, LEDIT_ID, SIGNAL( textChanged(const QString &) ), + this, SLOT( slotTextChanged(const QString &) ), true, + i18n( "Enter at least 3 letters to filter pages" ), 0/*size*/, 1 ); + + // 2. clear button (uses a lineEdit slot, so it must be created after) + insertButton( QApplication::reverseLayout() ? "clear_left" : "locationbar_erase", + CLEAR_ID, SIGNAL( clicked() ), + getLined( LEDIT_ID ), SLOT( clear() ), true, + i18n( "Clear filter" ), 0/*index*/ ); + + // 3.1. create the popup menu for changing filtering features + m_menu = new KPopupMenu( this ); + m_menu->insertItem( i18n("Case Sensitive"), 1 ); + m_menu->insertSeparator( 2 ); + m_menu->insertItem( i18n("Match Phrase"), 3 ); + m_menu->insertItem( i18n("Match All Words"), 4 ); + m_menu->insertItem( i18n("Match Any Word"), 5 ); + m_menu->setItemChecked( 3, true ); + connect( m_menu, SIGNAL( activated(int) ), SLOT( slotMenuChaged(int) ) ); + + // 3.2. create the toolbar button that spawns the popup menu + insertButton( "kpdf", FIND_ID, m_menu, true, i18n( "Filter Options" ), 2/*index*/ ); + + // always maximize the text line + setItemAutoSized( LEDIT_ID ); +} + +void SearchWidget::clearText() +{ + getLined( LEDIT_ID )->clear(); +} + +void SearchWidget::slotTextChanged( const QString & text ) +{ + // if 0 0 && text.length() < 3 ? Qt::darkRed : palette().active().text(); + KLineEdit * lineEdit = getLined( LEDIT_ID ); + lineEdit->setPaletteForegroundColor( color ); + lineEdit->setPaletteBackgroundColor( palette().active().base() ); + m_inputDelayTimer->stop(); + m_inputDelayTimer->start(333, true); +} + +void SearchWidget::slotMenuChaged( int index ) +{ + // update internal variables and checked state + if ( index == 1 ) + { + m_caseSensitive = !m_caseSensitive; + m_menu->setItemChecked( 1, m_caseSensitive ); + } + else if ( index >= 3 && index <= 5 ) + { + m_searchType = index - 3; + for ( int i = 0; i < 3; i++ ) + m_menu->setItemChecked( i + 3, m_searchType == i ); + } + else + return; + + // update search + slotTextChanged( getLined( LEDIT_ID )->text() ); +} + +void SearchWidget::startSearch() +{ + // search text if have more than 3 chars or else clear search + QString text = getLined( LEDIT_ID )->text(); + bool ok = true; + if ( text.length() >= 3 ) + { + KPDFDocument::SearchType type = !m_searchType ? KPDFDocument::AllDoc : + ( (m_searchType > 1) ? KPDFDocument::GoogleAny : + KPDFDocument::GoogleAll ); + ok = m_document->searchText( SW_SEARCH_ID, text, true, m_caseSensitive, + type, false, qRgb( 0, 183, 255 ) ); + } + else + m_document->resetSearch( SW_SEARCH_ID ); + // if not found, use warning colors + if ( !ok ) + { + KLineEdit * lineEdit = getLined( LEDIT_ID ); + lineEdit->setPaletteForegroundColor( Qt::white ); + lineEdit->setPaletteBackgroundColor( Qt::red ); + } +} + +#include "searchwidget.moc" diff --git a/kpdf/ui/searchwidget.h b/kpdf/ui/searchwidget.h new file mode 100644 index 00000000..9f2a1e44 --- /dev/null +++ b/kpdf/ui/searchwidget.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (C) 2004 by Enrico Ros * + * * + * 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. * + ***************************************************************************/ + +#ifndef _KPDF_SEARCHWIDGET_H_ +#define _KPDF_SEARCHWIDGET_H_ + +#include + +class KPopupMenu; +class KPDFDocument; +class m_inputDelayTimer; + +// definition of searchID for this class (publicly available to ThumbnailsList) +#define SW_SEARCH_ID 3 + +/** + * @short A widget for find-as-you-type search. Outputs to the Document. + * + * This widget accepts keyboard input and performs a call to findTextAll(..) + * in the KPDFDocument class when there are 3 or more chars to search for. + * It supports case sensitive/unsensitive(default) and provieds a button + * for switching between the 2 modes. + */ +class SearchWidget : public KToolBar +{ + Q_OBJECT + public: + SearchWidget( QWidget *parent, KPDFDocument *document ); + void clearText(); + + private: + KPDFDocument * m_document; + KPopupMenu * m_menu; + QTimer * m_inputDelayTimer; + int m_searchType; + bool m_caseSensitive; + + private slots: + void slotTextChanged( const QString & text ); + void slotMenuChaged( int index ); + void startSearch(); +}; + +#endif diff --git a/kpdf/ui/thumbnaillist.cpp b/kpdf/ui/thumbnaillist.cpp new file mode 100644 index 00000000..60324533 --- /dev/null +++ b/kpdf/ui/thumbnaillist.cpp @@ -0,0 +1,575 @@ +/*************************************************************************** + * Copyright (C) 2004-2006 by Albert Astals Cid * + * * + * 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. * + ***************************************************************************/ + +// qt/kde includes +#include +#include +#include +#include +#include +#include +#include +#include + +// local includes +#include "thumbnaillist.h" +#include "pagepainter.h" +#include "searchwidget.h" // for SW_SEARCH_ID +#include "core/document.h" +#include "core/generator.h" +#include "core/page.h" +#include "conf/settings.h" + +// ThumbnailWidget represents a single thumbnail in the ThumbnailList +class ThumbnailWidget : public QWidget +{ + public: + ThumbnailWidget( QWidget * parent, const KPDFPage * page, ThumbnailList * tl ); + + // set internal parameters to fit the page in the given width + void resizeFitWidth( int width ); + // set thumbnail's selected state + void setSelected( bool selected ); + + // query methods + int heightHint() const { return m_pixmapHeight + m_labelHeight + m_margin; } + int pixmapWidth() const { return m_pixmapWidth; } + int pixmapHeight() const { return m_pixmapHeight; } + int pageNumber() const { return m_page->number(); } + const KPDFPage * page() const { return m_page; } + + protected: + void mouseReleaseEvent( QMouseEvent * e ); + void paintEvent(QPaintEvent *); + + private: + // the margin around the widget + static int const m_margin = 16; + + // used to access 'forwardRightClick( .. )' and 'getBookmarkOverlay()' + ThumbnailList * m_tl; + const KPDFPage * m_page; + bool m_selected; + int m_pixmapWidth, m_pixmapHeight; + int m_labelHeight, m_labelNumber; +}; + + +/** ThumbnailList implementation **/ + +ThumbnailList::ThumbnailList( QWidget *parent, KPDFDocument *document ) + : QScrollView( parent, "KPDF::Thumbnails", WNoAutoErase | WStaticContents ), + m_document( document ), m_selected( 0 ), m_delayTimer( 0 ), m_bookmarkOverlay( 0 ) +{ + // set scrollbars + setHScrollBarMode( QScrollView::AlwaysOff ); + setVScrollBarMode( QScrollView::AlwaysOn ); + + // dealing with large areas so enable clipper + enableClipper( true ); + + // widget setup: can be focused by tab and mouse click (not wheel) + viewport()->setFocusProxy( this ); + viewport()->setFocusPolicy( StrongFocus ); + setResizePolicy( Manual ); + setAcceptDrops( true ); + setDragAutoScroll( false ); + + // set contents background to the 'base' color + viewport()->setPaletteBackgroundColor( palette().active().base() ); + + setFrameStyle( StyledPanel | Raised ); + connect( this, SIGNAL(contentsMoving(int, int)), this, SLOT(slotRequestVisiblePixmaps(int, int)) ); +} + +ThumbnailList::~ThumbnailList() +{ + m_document->removeObserver( this ); + delete m_bookmarkOverlay; +} + +//BEGIN DocumentObserver inherited methods +void ThumbnailList::notifySetup( const QValueVector< KPDFPage * > & pages, bool documentChanged ) +{ + // if there was a widget selected, save its pagenumber to restore + // its selection (if available in the new set of pages) + int prevPage = -1; + if ( !documentChanged && m_selected ) + { + prevPage = m_selected->page()->number(); + } + + // delete all the Thumbnails + QValueVector::iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end(); + for ( ; tIt != tEnd; ++tIt ) + delete *tIt; + m_thumbnails.clear(); + m_visibleThumbnails.clear(); + m_selected = 0; + + if ( pages.count() < 1 ) + { + resizeContents( 0, 0 ); + return; + } + + // show pages containing hilighted text or bookmarked ones + //RESTORE THIS int flags = Settings::filterBookmarks() ? KPDFPage::Bookmark : KPDFPage::Highlight; + + // if no page matches filter rule, then display all pages + QValueVector< KPDFPage * >::const_iterator pIt = pages.begin(), pEnd = pages.end(); + bool skipCheck = true; + for ( ; pIt != pEnd ; ++pIt ) + //if ( (*pIt)->attributes() & flags ) + if ( (*pIt)->hasHighlights( SW_SEARCH_ID ) ) + skipCheck = false; + + // generate Thumbnails for the given set of pages + int width = clipper()->width(), + totalHeight = 0; + for ( pIt = pages.begin(); pIt != pEnd ; ++pIt ) + //if ( skipCheck || (*pIt)->attributes() & flags ) + if ( skipCheck || (*pIt)->hasHighlights( SW_SEARCH_ID ) ) + { + ThumbnailWidget * t = new ThumbnailWidget( viewport(), *pIt, this ); + t->setFocusProxy( this ); + // add to the scrollview + addChild( t, 0, totalHeight ); + // add to the internal queue + m_thumbnails.push_back( t ); + // update total height (asking widget its own height) + t->resizeFitWidth( width ); + totalHeight += t->heightHint() + 4; + if ( (*pIt)->number() == prevPage ) + { + m_selected = t; + m_selected->setSelected( true ); + } + t->show(); + } + + // update scrollview's contents size (sets scrollbars limits) + resizeContents( width, totalHeight ); + + // request for thumbnail generation + delayedRequestVisiblePixmaps( 200 ); +} + +void ThumbnailList::notifyViewportChanged( bool /*smoothMove*/ ) +{ + // skip notifies for the current page (already selected) + int newPage = m_document->viewport().pageNumber; + if ( m_selected && m_selected->pageNumber() == newPage ) + return; + + // deselect previous thumbnail + if ( m_selected ) + m_selected->setSelected( false ); + m_selected = 0; + + // select the page with viewport and ensure it's centered in the view + m_vectorIndex = 0; + QValueVector::iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end(); + for ( ; tIt != tEnd; ++tIt ) + { + if ( (*tIt)->pageNumber() == newPage ) + { + m_selected = *tIt; + m_selected->setSelected( true ); + if ( KpdfSettings::syncThumbnailsViewport() ) + { + int yOffset = QMAX( visibleHeight() / 4, m_selected->height() / 2 ); + ensureVisible( 0, childY( m_selected ) + m_selected->height()/2, 0, yOffset ); + } + break; + } + m_vectorIndex++; + } +} + +void ThumbnailList::notifyPageChanged( int pageNumber, int /*changedFlags*/ ) +{ + // only handle pixmap changed notifies (the only defined for now) + //if ( !(changedFlags & DocumentObserver::Pixmap) ) + // return; + + // iterate over visible items: if page(pageNumber) is one of them, repaint it + QValueList::iterator vIt = m_visibleThumbnails.begin(), vEnd = m_visibleThumbnails.end(); + for ( ; vIt != vEnd; ++vIt ) + if ( (*vIt)->pageNumber() == pageNumber ) + { + (*vIt)->update(); + break; + } +} + +void ThumbnailList::notifyContentsCleared( int changedFlags ) +{ + // if pixmaps were cleared, re-ask them + if ( changedFlags & DocumentObserver::Pixmap ) + slotRequestVisiblePixmaps(); +} + +bool ThumbnailList::canUnloadPixmap( int pageNumber ) +{ + // if the thubnail 'pageNumber' is one of the visible ones, forbid unloading + QValueList::iterator vIt = m_visibleThumbnails.begin(), vEnd = m_visibleThumbnails.end(); + for ( ; vIt != vEnd; ++vIt ) + if ( (*vIt)->pageNumber() == pageNumber ) + return false; + // if hidden permit unloading + return true; +} +//END DocumentObserver inherited methods + + +void ThumbnailList::updateWidgets() +{ + // find all widgets that intersects the viewport and update them + QRect viewportRect( contentsX(), contentsY(), visibleWidth(), visibleHeight() ); + QValueList::iterator vIt = m_visibleThumbnails.begin(), vEnd = m_visibleThumbnails.end(); + for ( ; vIt != vEnd; ++vIt ) + { + ThumbnailWidget * t = *vIt; + QRect widgetRect( childX( t ), childY( t ), t->width(), t->height() ); + // update only the exposed area of the widget (saves pixels..) + QRect relativeRect = viewportRect.intersect( widgetRect ); + if ( !relativeRect.isValid() ) + continue; + relativeRect.moveBy( -widgetRect.left(), -widgetRect.top() ); + t->update( relativeRect ); + } +} + +void ThumbnailList::forwardRightClick( const KPDFPage * p, const QPoint & t ) +{ + emit rightClick( p, t ); +} + +const QPixmap * ThumbnailList::getBookmarkOverlay() const +{ + return m_bookmarkOverlay; +} + +void ThumbnailList::slotFilterBookmarks( bool filterOn ) +{ + // save state + KpdfSettings::setFilterBookmarks( filterOn ); + KpdfSettings::writeConfig(); + // ask for the 'notifySetup' with a little trick (on reinsertion the + // document sends the list again) + m_document->removeObserver( this ); + m_document->addObserver( this ); +} + + +//BEGIN widget events +void ThumbnailList::keyPressEvent( QKeyEvent * keyEvent ) +{ + if ( m_thumbnails.count() < 1 ) + return keyEvent->ignore(); + + int nextPage = -1; + if ( keyEvent->key() == Key_Up ) + { + if ( !m_selected ) + nextPage = 0; + else if ( m_vectorIndex > 0 ) + nextPage = m_thumbnails[ m_vectorIndex - 1 ]->pageNumber(); + } + else if ( keyEvent->key() == Key_Down ) + { + if ( !m_selected ) + nextPage = 0; + else if ( m_vectorIndex < (int)m_thumbnails.count() - 1 ) + nextPage = m_thumbnails[ m_vectorIndex + 1 ]->pageNumber(); + } + else if ( keyEvent->key() == Key_PageUp ) + verticalScrollBar()->subtractPage(); + else if ( keyEvent->key() == Key_PageDown ) + verticalScrollBar()->addPage(); + else if ( keyEvent->key() == Key_Home ) + nextPage = m_thumbnails[ 0 ]->pageNumber(); + else if ( keyEvent->key() == Key_End ) + nextPage = m_thumbnails[ m_thumbnails.count() - 1 ]->pageNumber(); + + if ( nextPage == -1 ) + return keyEvent->ignore(); + + keyEvent->accept(); + if ( m_selected ) + m_selected->setSelected( false ); + m_selected = 0; + m_document->setViewportPage( nextPage ); +} + +void ThumbnailList::contentsMousePressEvent( QMouseEvent * e ) +{ + if ( e->button() != Qt::LeftButton ) + return; + int clickY = e->y(); + QValueList::iterator vIt = m_visibleThumbnails.begin(), vEnd = m_visibleThumbnails.end(); + for ( ; vIt != vEnd; ++vIt ) + { + ThumbnailWidget * t = *vIt; + int childTop = childY(t); + if ( clickY > childTop && clickY < (childTop + t->height()) ) + { + if ( m_document->viewport().pageNumber != t->pageNumber() ) + m_document->setViewportPage( t->pageNumber() ); + break; + } + } +} + +void ThumbnailList::viewportResizeEvent( QResizeEvent * e ) +{ + if ( m_thumbnails.count() < 1 || width() < 1 ) + return; + + // if width changed resize all the Thumbnails, reposition them to the + // right place and recalculate the contents area + if ( e->size().width() != e->oldSize().width() ) + { + // runs the timer avoiding a thumbnail regeneration by 'contentsMoving' + delayedRequestVisiblePixmaps( 2000 ); + + // resize and reposition items + int totalHeight = 0, + newWidth = e->size().width(); + QValueVector::iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end(); + for ( ; tIt != tEnd; ++tIt ) + { + ThumbnailWidget *t = *tIt; + moveChild( t, 0, totalHeight ); + t->resizeFitWidth( newWidth ); + totalHeight += t->heightHint() + 4; + } + + // update scrollview's contents size (sets scrollbars limits) + resizeContents( newWidth, totalHeight ); + + // ensure selected item remains visible + if ( m_selected ) + ensureVisible( 0, childY( m_selected ) + m_selected->height()/2, 0, visibleHeight()/2 ); + } + else if ( e->size().height() <= e->oldSize().height() ) + return; + + // invalidate the bookmark overlay + if ( m_bookmarkOverlay ) + { + delete m_bookmarkOverlay; + m_bookmarkOverlay = 0; + } + + // update Thumbnails since width has changed or height has increased + delayedRequestVisiblePixmaps( 500 ); +} + +void ThumbnailList::dragEnterEvent( QDragEnterEvent * ev ) +{ + ev->accept(); +} + +void ThumbnailList::dropEvent( QDropEvent * ev ) +{ + KURL::List lst; + if ( KURLDrag::decode( ev, lst ) ) + emit urlDropped( lst.first() ); +} +//END widget events + +//BEGIN internal SLOTS +void ThumbnailList::slotRequestVisiblePixmaps( int /*newContentsX*/, int newContentsY ) +{ + // if an update is already scheduled or the widget is hidden, don't proceed + if ( (m_delayTimer && m_delayTimer->isActive()) || !isShown() ) + return; + + int vHeight = visibleHeight(), + vOffset = newContentsY == -1 ? contentsY() : newContentsY; + + // scroll from the top to the last visible thumbnail + m_visibleThumbnails.clear(); + QValueList< PixmapRequest * > requestedPixmaps; + QValueVector::iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end(); + for ( ; tIt != tEnd; ++tIt ) + { + ThumbnailWidget * t = *tIt; + int top = childY( t ) - vOffset; + if ( top > vHeight ) + break; + if ( top + t->height() < 0 ) + continue; + // add ThumbnailWidget to visible list + m_visibleThumbnails.push_back( t ); + // if pixmap not present add it to requests + if ( !t->page()->hasPixmap( THUMBNAILS_ID, t->pixmapWidth(), t->pixmapHeight() ) ) + { + PixmapRequest * p = new PixmapRequest( + THUMBNAILS_ID, t->pageNumber(), t->pixmapWidth(), t->pixmapHeight(), THUMBNAILS_PRIO, true ); + requestedPixmaps.push_back( p ); + } + } + + // actually request pixmaps + if ( !requestedPixmaps.isEmpty() ) + m_document->requestPixmaps( requestedPixmaps ); +} + +void ThumbnailList::slotDelayTimeout() +{ + // resize the bookmark overlay + delete m_bookmarkOverlay; + int expectedWidth = contentsWidth() / 4; + if ( expectedWidth > 10 ) + m_bookmarkOverlay = new QPixmap( DesktopIcon( "attach", expectedWidth ) ); + else + m_bookmarkOverlay = 0; + + // request pixmaps + slotRequestVisiblePixmaps(); +} +//END internal SLOTS + +void ThumbnailList::delayedRequestVisiblePixmaps( int delayMs ) +{ + if ( !m_delayTimer ) + { + m_delayTimer = new QTimer( this ); + connect( m_delayTimer, SIGNAL( timeout() ), this, SLOT( slotDelayTimeout() ) ); + } + m_delayTimer->start( delayMs, true ); +} + + +/** ThumbnailWidget implementation **/ + +ThumbnailWidget::ThumbnailWidget( QWidget * parent, const KPDFPage * kp, ThumbnailList * tl ) + : QWidget( parent, 0, WNoAutoErase ), m_tl( tl ), m_page( kp ), + m_selected( false ), m_pixmapWidth( 10 ), m_pixmapHeight( 10 ) +{ + m_labelNumber = m_page->number() + 1; + m_labelHeight = QFontMetrics( font() ).height(); +} + +void ThumbnailWidget::resizeFitWidth( int width ) +{ + m_pixmapWidth = width - m_margin; + m_pixmapHeight = (int)(m_page->ratio() * m_pixmapWidth); + resize( width, heightHint() ); +} + +void ThumbnailWidget::setSelected( bool selected ) +{ + // update selected state + if ( m_selected != selected ) + { + m_selected = selected; + update( 0, 0, width(), height() ); + } +} + +void ThumbnailWidget::mouseReleaseEvent( QMouseEvent * e ) +{ + if ( e->button() != Qt::RightButton ) + return; + + m_tl->forwardRightClick( m_page, e->globalPos() ); +} + +void ThumbnailWidget::paintEvent( QPaintEvent * e ) +{ + int width = m_pixmapWidth + m_margin; + int height = m_pixmapHeight + m_margin + m_labelHeight; + QRect clipRect = e->rect(); + if ( !clipRect.isValid() ) + return; + QPainter p( this ); + + // draw the bottom label + highlight mark + QColor fillColor = m_selected ? palette().active().highlight() : palette().active().base(); + p.fillRect( 0, 0, width, height, fillColor ); + p.setPen( m_selected ? palette().active().highlightedText() : palette().active().text() ); + p.drawText( 0, m_pixmapHeight + m_margin, width, m_labelHeight, Qt::AlignCenter, QString::number( m_labelNumber ) ); + + // draw page outline and pixmap + if ( clipRect.top() < m_pixmapHeight + m_margin ) + { + // if page is bookmarked draw a colored border + bool isBookmarked = m_page->hasBookmark(); + // draw the inner rect + p.setPen( isBookmarked ? QColor( 0xFF8000 ) : Qt::black ); + p.drawRect( m_margin/2 - 1, m_margin/2 - 1, m_pixmapWidth + 2, m_pixmapHeight + 2 ); + // draw the clear rect + p.setPen( isBookmarked ? QColor( 0x804000 ) : palette().active().base() ); + // draw the bottom and right shadow edges + if ( !isBookmarked ) + { + int left, right, bottom, top; + left = m_margin/2 + 1; + right = m_margin/2 + m_pixmapWidth + 1; + bottom = m_pixmapHeight + m_margin/2 + 1; + top = m_margin/2 + 1; + p.setPen( Qt::gray ); + p.drawLine( left, bottom, right, bottom ); + p.drawLine( right, top, right, bottom ); + } + + // draw the page using the shared PagePainter class + p.translate( m_margin/2, m_margin/2 ); + clipRect.moveBy( -m_margin/2, -m_margin/2 ); + clipRect = clipRect.intersect( QRect( 0, 0, m_pixmapWidth, m_pixmapHeight ) ); + if ( clipRect.isValid() ) + { + int flags = PagePainter::Accessibility | PagePainter::Highlights; + PagePainter::paintPageOnPainter( m_page, THUMBNAILS_ID, flags, &p, + clipRect, m_pixmapWidth, m_pixmapHeight ); + } + + // draw the bookmark overlay on the top-right corner + const QPixmap * bookmarkPixmap = m_tl->getBookmarkOverlay(); + if ( isBookmarked && bookmarkPixmap ) + { + int pixW = bookmarkPixmap->width(), + pixH = bookmarkPixmap->height(); + clipRect = clipRect.intersect( QRect( m_pixmapWidth - pixW, 0, pixW, pixH ) ); + if ( clipRect.isValid() ) + p.drawPixmap( m_pixmapWidth - pixW, -pixH/8, *bookmarkPixmap ); + } + } +} + + +/** ThumbnailsController implementation **/ + +#define FILTERB_ID 1 + +ThumbnailController::ThumbnailController( QWidget * parent, ThumbnailList * list ) + : KToolBar( parent, "ThumbsControlBar" ) +{ + // change toolbar appearance + setMargin( 3 ); + setFlat( true ); + setIconSize( 16 ); + setMovingEnabled( false ); + + // insert a togglebutton [show only bookmarked pages] + //insertSeparator(); + insertButton( "bookmark", FILTERB_ID, SIGNAL( toggled( bool ) ), + list, SLOT( slotFilterBookmarks( bool ) ), + true, i18n( "Show bookmarked pages only" ) ); + setToggle( FILTERB_ID ); + setButton( FILTERB_ID, KpdfSettings::filterBookmarks() ); + //insertLineSeparator(); +} + + +#include "thumbnaillist.moc" diff --git a/kpdf/ui/thumbnaillist.h b/kpdf/ui/thumbnaillist.h new file mode 100644 index 00000000..e0f84610 --- /dev/null +++ b/kpdf/ui/thumbnaillist.h @@ -0,0 +1,121 @@ +/*************************************************************************** + * Copyright (C) 2004 by Albert Astals Cid * + * * + * 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. * + ***************************************************************************/ + +#ifndef _KPDF_THUMBNAILLIST_H_ +#define _KPDF_THUMBNAILLIST_H_ + +#include +#include +#include +#include +#include "core/observer.h" + +class QTimer; +class KActionCollection; + +class KPDFDocument; +class ThumbnailWidget; + +/** + * @short A scrollview that displays pages pixmaps previews (aka thumbnails). + * + * ... + */ +class ThumbnailList : public QScrollView, public DocumentObserver +{ +Q_OBJECT + public: + ThumbnailList(QWidget *parent, KPDFDocument *document); + ~ThumbnailList(); + + // inherited: return thumbnails observer id + uint observerId() const { return THUMBNAILS_ID; } + // inherited: create thumbnails ( inherited as a DocumentObserver ) + void notifySetup( const QValueVector< KPDFPage * > & pages, bool documentChanged ); + // inherited: hilihght current thumbnail ( inherited as DocumentObserver ) + void notifyViewportChanged( bool smoothMove ); + // inherited: redraw thumbnail ( inherited as DocumentObserver ) + void notifyPageChanged( int pageNumber, int changedFlags ); + // inherited: request all visible pixmap (due to a global shange or so..) + void notifyContentsCleared( int changedFlags ); + // inherited: tell if pixmap is hidden and can be unloaded + bool canUnloadPixmap( int pageNumber ); + + // redraw visible widgets (useful for refreshing contents...) + void updateWidgets(); + + // called by ThumbnailWidgets to send (forward) rightClick signals + void forwardRightClick( const KPDFPage *, const QPoint & ); + // called by ThumbnailWidgets to get the overlay bookmark pixmap + const QPixmap * getBookmarkOverlay() const; + + public slots: + // these are connected to ThumbnailController buttons + void slotFilterBookmarks( bool filterOn ); + + protected: + // scroll up/down the view + void keyPressEvent( QKeyEvent * e ); + + // select a thumbnail by clicking on it + void contentsMousePressEvent( QMouseEvent * ); + + // resize thumbnails to fit the width + void viewportResizeEvent( QResizeEvent * ); + + // file drop related events (an url may be dropped even here) + void dragEnterEvent( QDragEnterEvent* ); + void dropEvent( QDropEvent* ); + + signals: + void urlDropped( const KURL& ); + void rightClick( const KPDFPage *, const QPoint & ); + + private: + void delayedRequestVisiblePixmaps( int delayMs = 0 ); + KPDFDocument *m_document; + ThumbnailWidget *m_selected; + QTimer *m_delayTimer; + QPixmap *m_bookmarkOverlay; + QValueVector m_thumbnails; + QValueList m_visibleThumbnails; + int m_vectorIndex; + + private slots: + // make requests for generating pixmaps for visible thumbnails + void slotRequestVisiblePixmaps( int newContentsX = -1, int newContentsY = -1 ); + // delay timeout: resize overlays and requests pixmaps + void slotDelayTimeout(); +}; + +/** + * @short A vertical boxed container with zero size hint (for insertion on left toolbox) + */ +class ThumbnailsBox : public QVBox +{ + public: + ThumbnailsBox( QWidget * parent ) : QVBox( parent ) {}; + QSize sizeHint() const { return QSize(); } +}; + +/** + * @short A toolbar thar set ThumbnailList properties when clicking on items + * + * This class is the small tolbar that resides in the bottom of the + * ThumbnailsBox container (below ThumbnailList and the SearchLine) and + * emits signals whenever a button is pressed. A click action results + * in invoking some method (or slot) in ThumbnailList. + */ +class ThumbnailController : public KToolBar +{ + public: + ThumbnailController( QWidget * parent, ThumbnailList * thumbnailList ); +}; + +#endif diff --git a/kpdf/ui/toc.cpp b/kpdf/ui/toc.cpp new file mode 100644 index 00000000..6db19933 --- /dev/null +++ b/kpdf/ui/toc.cpp @@ -0,0 +1,175 @@ +/*************************************************************************** + * Copyright (C) 2004-2006 by Albert Astals Cid * + * * + * 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. * + ***************************************************************************/ + +// qt/kde includes +#include +#include +#include + +// local includes +#include "toc.h" +#include "core/link.h" +#include "core/page.h" + +// uncomment following to enable a 2nd column showing the page referred +// by each tree entry note: PDF uses often references to viewports and +// they're slow when converted to page number. drop the 2nd column idea. +//#define TOC_ENABLE_PAGE_COLUMN + +class TOCItem : public KListViewItem +{ + public: + TOCItem( KListView *parent, TOCItem *after, const QDomElement & e ) + : KListViewItem( parent, after, e.tagName() ), m_element( e ) + { +#ifdef TOC_ENABLE_PAGE_COLUMN + if ( e.hasAttribute( "Page" ) ) + setText( 1, e.attribute( "Page" ) ); +#endif + setMultiLinesEnabled(true); + } + + TOCItem( KListViewItem *parent, TOCItem *after, const QDomElement & e ) + : KListViewItem( parent, after, e.tagName() ), m_element( e ) + { +#ifdef TOC_ENABLE_PAGE_COLUMN + if ( e.hasAttribute( "Page" ) ) + setText( 1, e.attribute( "Page" ) ); +#endif + setMultiLinesEnabled(true); + } + + const QDomElement & element() const + { + return m_element; + } + + private: + QDomElement m_element; +}; + +TOC::TOC(QWidget *parent, KPDFDocument *document) : KListView(parent), m_document(document) +{ + addColumn( i18n("Topic") ); +#ifdef TOC_ENABLE_PAGE_COLUMN + addColumn( i18n("Page") ); +#else + header() -> hide(); +#endif + setSorting(-1); + setRootIsDecorated(true); + // the next line causes bug:147233 +// setResizeMode(AllColumns); + setAllColumnsShowFocus(true); + connect(this, SIGNAL(clicked(QListViewItem *)), this, SLOT(slotExecuted(QListViewItem *))); + connect(this, SIGNAL(returnPressed(QListViewItem *)), this, SLOT(slotExecuted(QListViewItem *))); +} + +TOC::~TOC() +{ + m_document->removeObserver( this ); +} + +uint TOC::observerId() const +{ + return TOC_ID; +} + +void TOC::notifySetup( const QValueVector< KPDFPage * > & /*pages*/, bool documentChanged ) +{ + if ( !documentChanged ) + return; + + // clear contents + clear(); + + // request synopsis description (is a dom tree) + const DocumentSynopsis * syn = m_document->documentSynopsis(); + + // if not present, disable the contents tab + if ( !syn ) + { + emit hasTOC( false ); + return; + } + + // else populate the listview and enable the tab + addChildren( *syn ); + emit hasTOC( true ); +} + +void TOC::addChildren( const QDomNode & parentNode, KListViewItem * parentItem ) +{ + // keep track of the current listViewItem + TOCItem * currentItem = 0; + QDomNode n = parentNode.firstChild(); + while( !n.isNull() ) + { + // convert the node to an element (sure it is) + QDomElement e = n.toElement(); + + // insert the entry as top level (listview parented) or 2nd+ level + if ( !parentItem ) + currentItem = new TOCItem( this, currentItem, e ); + else + currentItem = new TOCItem( parentItem, currentItem, e ); + + // descend recursively and advance to the next node + if ( e.hasChildNodes() ) + addChildren( n, currentItem ); + + // open/keep close the item + bool isOpen = false; + if ( e.hasAttribute( "Open" ) ) + isOpen = QVariant( e.attribute( "Open" ) ).toBool(); + currentItem->setOpen( isOpen ); + + n = n.nextSibling(); + } +} + +void TOC::slotExecuted( QListViewItem *i ) +{ + TOCItem* tocItem = dynamic_cast( i ); + // that filters clicks on [+] that for a strange reason don't seem to be TOCItem* + if (tocItem == NULL) + return; + const QDomElement & e = tocItem->element(); + + QString externalFileName = e.attribute( "ExternalFileName" ); + if ( !externalFileName.isEmpty() ) + { + KPDFLinkGoto link( externalFileName, getViewport( e ) ); + m_document->processLink( &link ); + } + else + { + m_document->setViewport( getViewport( e ), TOC_ID ); + } +} + +DocumentViewport TOC::getViewport( const QDomElement &e ) const +{ + if ( e.hasAttribute( "Viewport" ) ) + { + // if the node has a viewport, set it + return DocumentViewport( e.attribute( "Viewport" ) ); + } + else if ( e.hasAttribute( "ViewportName" ) ) + { + // if the node references a viewport, get the reference and set it + const QString & page = e.attribute( "ViewportName" ); + const QString & viewport = m_document->getMetaData( "NamedViewport", page ); + if ( !viewport.isNull() ) + return DocumentViewport( viewport ); + } + return DocumentViewport(); +} + +#include "toc.moc" diff --git a/kpdf/ui/toc.h b/kpdf/ui/toc.h new file mode 100644 index 00000000..eaa398a5 --- /dev/null +++ b/kpdf/ui/toc.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * Copyright (C) 2004-2006 by Albert Astals Cid * + * * + * 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. * + ***************************************************************************/ + +#ifndef _KPDF_TOC_H_ +#define _KPDF_TOC_H_ + +#include +#include +#include "core/document.h" +#include "core/observer.h" + +class KPDFDocument; + +class TOC : public KListView, public DocumentObserver +{ +Q_OBJECT + public: + TOC(QWidget *parent, KPDFDocument *document); + ~TOC(); + + // inherited from DocumentObserver + uint observerId() const; + void notifySetup( const QValueVector< KPDFPage * > & pages, bool documentChanged ); + + signals: + void hasTOC(bool has); + + private slots: + void slotExecuted(QListViewItem *i); + + private: + void addChildren( const QDomNode & parentNode, KListViewItem * parentItem = 0 ); + DocumentViewport getViewport( const QDomElement &e ) const; + KPDFDocument *m_document; +}; + +#endif diff --git a/kpdf/xpdf/Makefile.am b/kpdf/xpdf/Makefile.am new file mode 100644 index 00000000..0474692c --- /dev/null +++ b/kpdf/xpdf/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = fofi goo splash xpdf diff --git a/kpdf/xpdf/README.xpdf b/kpdf/xpdf/README.xpdf new file mode 100644 index 00000000..71fd62e3 --- /dev/null +++ b/kpdf/xpdf/README.xpdf @@ -0,0 +1,405 @@ +Xpdf +==== + +version 3.02 +2007-feb-27 + +The Xpdf software and documentation are +copyright 1996-2007 Glyph & Cog, LLC. + +Email: derekn@foolabs.com +WWW: http://www.foolabs.com/xpdf/ + +The PDF data structures, operators, and specification are +copyright 1985-2006 Adobe Systems Inc. + + +What is Xpdf? +------------- + +Xpdf is an open source viewer for Portable Document Format (PDF) +files. (These are also sometimes also called 'Acrobat' files, from +the name of Adobe's PDF software.) The Xpdf project also includes a +PDF text extractor, PDF-to-PostScript converter, and various other +utilities. + +Xpdf runs under the X Window System on UNIX, VMS, and OS/2. The non-X +components (pdftops, pdftotext, etc.) also run on Win32 systems and +should run on pretty much any system with a decent C++ compiler. + +Xpdf is designed to be small and efficient. It can use Type 1 or +TrueType fonts. + + +Distribution +------------ + +Xpdf is licensed under the GNU General Public License (GPL), version +2. In my opinion, the GPL is a convoluted, confusing, ambiguous mess. +But it's also pervasive, and I'm sick of arguing. And even if it is +confusing, the basic idea is good. + +In order to cut down on the confusion a little bit, here are some +informal clarifications: + +- I don't mind if you redistribute Xpdf in source and/or binary form, + as long as you include all of the documentation: README, man pages + (or help files), and COPYING. (Note that the README file contains a + pointer to a web page with the source code.) + +- Selling a CD-ROM that contains Xpdf is fine with me, as long as it + includes the documentation. I wouldn't mind receiving a sample + copy, but it's not necessary. + +- If you make useful changes to Xpdf, please make the source code + available -- post it on a web site, email it to me, whatever. + +If you're interested in commercial licensing, please see the Glyph & +Cog web site: + + http://www.glyphandcog.com/ + + +Compatibility +------------- + +Xpdf is developed and tested on a Linux 2.4 x86 system. + +In addition, it has been compiled by others on Solaris, AIX, HP-UX, +Digital Unix, Irix, and numerous other Unix implementations, as well +as VMS and OS/2. It should work on pretty much any system which runs +X11 and has Unix-like libraries. You'll need ANSI C++ and C compilers +to compile it. + +The non-X components of Xpdf (pdftops, pdftotext, pdfinfo, pdffonts, +pdftoppm, and pdfimages) can also be compiled on Win32 systems. See +the Xpdf web page for details. + +If you compile Xpdf for a system not listed on the web page, please +let me know. If you're willing to make your binary available by ftp +or on the web, I'll be happy to add a link from the Xpdf web page. I +have decided not to host any binaries I didn't compile myself (for +disk space and support reasons). + +If you can't get Xpdf to compile on your system, send me email and +I'll try to help. + +Xpdf has been ported to the Acorn, Amiga, BeOS, and EPOC. See the +Xpdf web page for links. + + +Getting Xpdf +------------ + +The latest version is available from: + + http://www.foolabs.com/xpdf/ + +or: + + ftp://ftp.foolabs.com/pub/xpdf/ + +Source code and several precompiled executables are available. + +Announcements of new versions are posted to several newsgroups +(comp.text.pdf, comp.os.linux.announce, and others) and emailed to a +list of people. If you'd like to receive email notification of new +versions, just let me know. + + +Running Xpdf +------------ + +To run xpdf, simply type: + + xpdf file.pdf + +To generate a PostScript file, hit the "print" button in xpdf, or run +pdftops: + + pdftops file.pdf + +To generate a plain text file, run pdftotext: + + pdftotext file.pdf + +There are four additional utilities (which are fully described in +their man pages): + + pdfinfo -- dumps a PDF file's Info dictionary (plus some other + useful information) + pdffonts -- lists the fonts used in a PDF file along with various + information for each font + pdftoppm -- converts a PDF file to a series of PPM/PGM/PBM-format + bitmaps + pdfimages -- extracts the images from a PDF file + +Command line options and many other details are described in the man +pages (xpdf.1, etc.) and the VMS help files (xpdf.hlp, etc.). + + +Upgrading from Xpdf 2.xx +------------------------ + +WARNING: Xpdf 3.00 switched to a new PDF rasterizer, which no longer +uses X fonts. You'll need a set of Base-14 fonts -- the URW fonts +distributed with ghostscript can be used for this. Xpdf will search +for the URW fonts, but if you have them installed in a non-standard +directory, you'll need to set up an xpdfrc config file to point to +them. For full details, please see the xpdfrc(5) man page. + + +Compiling Xpdf +-------------- + +See the separate file, INSTALL. + + +Bugs +---- + +If you find a bug in Xpdf, i.e., if it prints an error message, +crashes, or incorrectly displays a document, and you don't see that +bug listed here, please send me email, with a pointer (URL, ftp site, +etc.) to the PDF file. + + +Acknowledgments +--------------- + +Thanks to: + +* Patrick Voigt for help with the remote server code. +* Patrick Moreau, Martin P.J. Zinser, and David Mathog for the VMS + port. +* David Boldt and Rick Rodgers for sample man pages. +* Brendan Miller for the icon idea. +* Olly Betts for help testing pdftotext. +* Peter Ganten for the OS/2 port. +* Michael Richmond for the Win32 port of pdftops and pdftotext and the + xpdf/cygwin/XFree86 build instructions. +* Frank M. Siegert for improvements in the PostScript code. +* Leo Smiers for the decryption patches. +* Rainer Menzner for creating t1lib, and for helping me adapt it to + xpdf. +* Pine Tree Systems A/S for funding the OPI and EPS support in + pdftops. +* Easy Software Products for funding several improvements to the + PostScript output code. +* Tom Kacvinsky for help with FreeType and for being my interface to + the FreeType team. +* Theppitak Karoonboonyanan for help with Thai support. +* Leonard Rosenthol for help and contributions on a bunch of things. +* Alexandros Diamantidis and Maria Adaloglou for help with Greek + support. +* Lawrence Lai for help with the CJK Unicode maps. + +Various people have contributed modifications made for use by the +pdftex project: + +* Han The Thanh +* Martin Schrder of ArtCom GmbH + + +References +---------- + +Adobe Systems Inc., _PDF Reference, sixth edition: Adobe Portable +Document Format version 1.7_. +http://www.adobe.com/devnet/pdf/pdf_reference.html +[The manual for PDF version 1.7.] + +Adobe Systems Inc., "Errata for the PDF Reference, sixth edition, +version 1.7", October 16, 2006. +http://www.adobe.com/devnet/pdf/pdf_reference.html +[The errata for the PDF 1.7 spec.] + +Adobe Systems Inc., _PostScript Language Reference_, 3rd ed. +Addison-Wesley, 1999, ISBN 0-201-37922-8. +[The official PostScript manual.] + +Adobe Systems, Inc., _The Type 42 Font Format Specification_, +Adobe Developer Support Technical Specification #5012. 1998. +http://partners.adobe.com/asn/developer/pdfs/tn/5012.Type42_Spec.pdf +[Type 42 is the format used to embed TrueType fonts in PostScript +files.] + +Adobe Systems, Inc., _Adobe CMap and CIDFont Files Specification_, +Adobe Developer Support Technical Specification #5014. 1995. +http://www.adobe.com/supportservice/devrelations/PDFS/TN/5014.CIDFont_Spec.pdf +[CMap file format needed for Japanese and Chinese font support.] + +Adobe Systems, Inc., _Adobe-Japan1-4 Character Collection for +CID-Keyed Fonts_, Adobe Developer Support Technical Note #5078. +2000. +http://partners.adobe.com/asn/developer/PDFS/TN/5078.CID_Glyph.pdf +[The Adobe Japanese character set.] + +Adobe Systems, Inc., _Adobe-GB1-4 Character Collection for +CID-Keyed Fonts_, Adobe Developer Support Technical Note #5079. +2000. +http://partners.adobe.com/asn/developer/pdfs/tn/5079.Adobe-GB1-4.pdf +[The Adobe Chinese GB (simplified) character set.] + +Adobe Systems, Inc., _Adobe-CNS1-3 Character Collection for +CID-Keyed Fonts_, Adobe Developer Support Technical Note #5080. +2000. +http://partners.adobe.com/asn/developer/PDFS/TN/5080.CNS_CharColl.pdf +[The Adobe Chinese CNS (traditional) character set.] + +Adobe Systems Inc., _Supporting the DCT Filters in PostScript Level +2_, Adobe Developer Support Technical Note #5116. 1992. +http://www.adobe.com/supportservice/devrelations/PDFS/TN/5116.PS2_DCT.PDF +[Description of the DCTDecode filter parameters.] + +Adobe Systems Inc., _Open Prepress Interface (OPI) Specification - +Version 2.0_, Adobe Developer Support Technical Note #5660. 2000. +http://partners.adobe.com/asn/developer/PDFS/TN/5660.OPI_2.0.pdf + +Adobe Systems Inc., CMap files. +ftp://ftp.oreilly.com/pub/examples/nutshell/cjkv/adobe/ +[The actual CMap files for the 16-bit CJK encodings.] + +Adobe Systems Inc., Unicode glyph lists. +http://partners.adobe.com/asn/developer/type/unicodegn.html +http://partners.adobe.com/asn/developer/type/glyphlist.txt +http://partners.adobe.com/asn/developer/type/corporateuse.txt +http://partners.adobe.com/asn/developer/type/zapfdingbats.txt +[Mappings between character names to Unicode.] + +Adobe Systems Inc., OpenType Specification v. 1.4. +http://partners.adobe.com/public/developer/opentype/index_spec.html +[The OpenType font format spec.] + +Aldus Corp., _OPI: Open Prepress Interface Specification 1.3_. 1993. +http://partners.adobe.com/asn/developer/PDFS/TN/OPI_13.pdf + +Anonymous, RC4 source code. +ftp://ftp.ox.ac.uk/pub/crypto/misc/rc4.tar.gz +ftp://idea.sec.dsi.unimi.it/pub/crypt/code/rc4.tar.gz +[This is the algorithm used to encrypt PDF files.] + +T. Boutell, et al., "PNG (Portable Network Graphics) Specification, +Version 1.0". RFC 2083. +[PDF uses the PNG filter algorithms.] + +CCITT, "Information Technology - Digital Compression and Coding of +Continuous-tone Still Images - Requirements and Guidelines", CCITT +Recommendation T.81. +http://www.w3.org/Graphics/JPEG/ +[The official JPEG spec.] + +A. Chernov, "Registration of a Cyrillic Character Set". RFC 1489. +[Documentation for the KOI8-R Cyrillic encoding.] + +Roman Czyborra, "The ISO 8859 Alphabet Soup". +http://czyborra.com/charsets/iso8859.html +[Documentation on the various ISO 859 encodings.] + +L. Peter Deutsch, "ZLIB Compressed Data Format Specification version +3.3". RFC 1950. +[Information on the general format used in FlateDecode streams.] + +L. Peter Deutsch, "DEFLATE Compressed Data Format Specification +version 1.3". RFC 1951. +[The definition of the compression algorithm used in FlateDecode +streams.] + +Morris Dworkin, "Recommendation for Block Cipher Modes of Operation", +National Institute of Standards, NIST Special Publication 800-38A, +2001. +[The cipher block chaining (CBC) mode used with AES in PDF files.] + +Federal Information Processing Standards Publication 197 (FIPS PUBS +197), "Advanced Encryption Standard (AES)", November 26, 2001. +[AES encryption, used in PDF 1.6.] + +Jim Flowers, "X Logical Font Description Conventions", Version 1.5, X +Consortium Standard, X Version 11, Release 6.1. +ftp://ftp.x.org/pub/R6.1/xc/doc/hardcopy/XLFD/xlfd.PS.Z +[The official specification of X font descriptors, including font +transformation matrices.] + +Foley, van Dam, Feiner, and Hughes, _Computer Graphics: Principles and +Practice_, 2nd ed. Addison-Wesley, 1990, ISBN 0-201-12110-7. +[Colorspace conversion functions, Bezier spline math.] + +Robert L. Hummel, _Programmer's Technical Reference: Data and Fax +Communications_. Ziff-Davis Press, 1993, ISBN 1-56276-077-7. +[CCITT Group 3 and 4 fax decoding.] + +ISO/IEC, _Information technology -- Lossy/lossless coding of bi-level +images_. ISO/IEC 14492, First edition (2001-12-15). +http://webstore.ansi.org/ +[The official JBIG2 standard. The final draft of this spec is +available from http://www.jpeg.org/jbighomepage.html.] + +ISO/IEC, _Information technology -- JPEG 2000 image coding system -- +Part 1: Core coding system_. ISO/IEC 15444-1, First edition +(2000-12-15). +http://webstore.ansi.org/ +[The official JPEG 2000 standard. The final committee draft of this +spec is available from http://www.jpeg.org/JPEG2000.html, but there +were changes made to the bitstream format between that draft and the +published spec.] + +ITU, "Standardization of Group 3 facsimile terminals for document +transmission", ITU-T Recommendation T.4, 1999. +ITU, "Facsimile coding schemes and coding control functions for Group 4 +facsimile apparatus", ITU-T Recommendation T.6, 1993. +http://www.itu.int/ +[The official Group 3 and 4 fax standards - used by the CCITTFaxDecode +stream, as well as the JBIG2Decode stream.] + +B. Kaliski, "PKCS #5: Password-Based Cryptography Specification, +Version 2.0". RFC 2898. +[Defines the padding scheme used with AES encryption in PDF files.] + +Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz, "Practical +Fast 1-D DCT Algorithms with 11 Multiplications". IEEE Intl. Conf. on +Acoustics, Speech & Signal Processing, 1989, 988-991. +[The fast IDCT algorithm used in the DCTDecode filter.] + +Microsoft, _TrueType 1.0 Font Files_, rev. 1.66. 1995. +http://www.microsoft.com/typography/tt/tt.htm +[The TrueType font spec (in MS Word format, naturally).] + +V. Ostromoukhov, R.D. Hersch, "Stochastic Clustered-Dot Dithering", +Conf. Color Imaging: Device-Independent Color, Color Hardcopy, and +Graphic Arts IV, 1999, SPIE Vol. 3648, 496-505. +http://diwww.epfl.ch/w3lsp/publications/colour/scd.html +[The stochastic dithering algorithm used in Xpdf.] + +P. Peterlin, "ISO 8859-2 (Latin 2) Resources". +http://sizif.mf.uni-lj.si/linux/cee/iso8859-2.html +[This is a web page with all sorts of useful Latin-2 character set and +font information.] + +Charles Poynton, "Color FAQ". +http://www.inforamp.net/~poynton/ColorFAQ.html +[The mapping from the CIE 1931 (XYZ) color space to RGB.] + +R. Rivest, "The MD5 Message-Digest Algorithm". RFC 1321. +[MD5 is used in PDF document encryption.] + +Thai Industrial Standard, "Standard for Thai Character Codes for +Computers", TIS-620-2533 (1990). +http://www.nectec.or.th/it-standards/std620/std620.htm +[The TIS-620 Thai encoding.] + +Unicode Consortium, "Unicode Home Page". +http://www.unicode.org/ +[Online copy of the Unicode spec.] + +W3C Recommendation, "PNG (Portable Network Graphics) Specification +Version 1.0". +http://www.w3.org/Graphics/PNG/ +[Defines the PNG image predictor.] + +Gregory K. Wallace, "The JPEG Still Picture Compression Standard". +ftp://ftp.uu.net/graphics/jpeg/wallace.ps.gz +[Good description of the JPEG standard. Also published in CACM, April +1991, and submitted to IEEE Transactions on Consumer Electronics.] + +F. Yergeau, "UTF-8, a transformation format of ISO 10646". RFC 2279. +[A commonly used Unicode encoding.] diff --git a/kpdf/xpdf/aconf.h b/kpdf/xpdf/aconf.h new file mode 100644 index 00000000..43b28397 --- /dev/null +++ b/kpdf/xpdf/aconf.h @@ -0,0 +1,17 @@ +/* define it to 0, if you have it, config.h will have it defined to 1 and that will be used*/ +#define HAVE_FSEEK0 0 + +#include + +#define HAVE_T1LIB_H 0 +#define HAVE_FREETYPE_H HAVE_FREETYPE +#define HAVE_FREETYPE_FREETYPE_H HAVE_FREETYPE +#define OPI_SUPPORT 0 +#define TEXTOUT_WORD_LIST 0 +#define HAVE_MKSTEMPS 1 //libkdefakes provides it +#define HAVE_SPLASH 1 +#define SPLASH_CMYK 1 +#define HAVE_XPDFCORE 0 +#define HAVE_WINPDFCORE 0 +#define USE_EXCEPTIONS 0 +#define USE_FIXEDPOINT 0 diff --git a/kpdf/xpdf/fofi/FoFiBase.cc b/kpdf/xpdf/fofi/FoFiBase.cc new file mode 100644 index 00000000..28d0b8ca --- /dev/null +++ b/kpdf/xpdf/fofi/FoFiBase.cc @@ -0,0 +1,156 @@ +//======================================================================== +// +// FoFiBase.cc +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "gmem.h" +#include "FoFiBase.h" + +//------------------------------------------------------------------------ +// FoFiBase +//------------------------------------------------------------------------ + +FoFiBase::FoFiBase(char *fileA, int lenA, GBool freeFileDataA) { + fileData = file = (Guchar *)fileA; + len = lenA; + freeFileData = freeFileDataA; +} + +FoFiBase::~FoFiBase() { + if (freeFileData) { + gfree(fileData); + } +} + +char *FoFiBase::readFile(char *fileName, int *fileLen) { + FILE *f; + char *buf; + int n; + + if (!(f = fopen(fileName, "rb"))) { + return NULL; + } + fseek(f, 0, SEEK_END); + n = (int)ftell(f); + fseek(f, 0, SEEK_SET); + buf = (char *)gmalloc(n); + if ((int)fread(buf, 1, n, f) != n) { + gfree(buf); + fclose(f); + return NULL; + } + fclose(f); + *fileLen = n; + return buf; +} + +int FoFiBase::getS8(int pos, GBool *ok) { + int x; + + if (pos < 0 || pos >= len) { + *ok = gFalse; + return 0; + } + x = file[pos]; + if (x & 0x80) { + x |= ~0xff; + } + return x; +} + +int FoFiBase::getU8(int pos, GBool *ok) { + if (pos < 0 || pos >= len) { + *ok = gFalse; + return 0; + } + return file[pos]; +} + +int FoFiBase::getS16BE(int pos, GBool *ok) { + int x; + + if (pos < 0 || pos+1 >= len) { + *ok = gFalse; + return 0; + } + x = file[pos]; + x = (x << 8) + file[pos+1]; + if (x & 0x8000) { + x |= ~0xffff; + } + return x; +} + +int FoFiBase::getU16BE(int pos, GBool *ok) { + int x; + + if (pos < 0 || pos+1 >= len) { + *ok = gFalse; + return 0; + } + x = file[pos]; + x = (x << 8) + file[pos+1]; + return x; +} + +int FoFiBase::getS32BE(int pos, GBool *ok) { + int x; + + if (pos < 0 || pos+3 >= len) { + *ok = gFalse; + return 0; + } + x = file[pos]; + x = (x << 8) + file[pos+1]; + x = (x << 8) + file[pos+2]; + x = (x << 8) + file[pos+3]; + if (x & 0x80000000) { + x |= ~0xffffffff; + } + return x; +} + +Guint FoFiBase::getU32BE(int pos, GBool *ok) { + Guint x; + + if (pos < 0 || pos+3 >= len) { + *ok = gFalse; + return 0; + } + x = file[pos]; + x = (x << 8) + file[pos+1]; + x = (x << 8) + file[pos+2]; + x = (x << 8) + file[pos+3]; + return x; +} + +Guint FoFiBase::getUVarBE(int pos, int size, GBool *ok) { + Guint x; + int i; + + if (pos < 0 || pos + size > len) { + *ok = gFalse; + return 0; + } + x = 0; + for (i = 0; i < size; ++i) { + x = (x << 8) + file[pos + i]; + } + return x; +} + +GBool FoFiBase::checkRegion(int pos, int size) { + return pos >= 0 && + pos + size >= pos && + pos + size <= len; +} diff --git a/kpdf/xpdf/fofi/FoFiBase.h b/kpdf/xpdf/fofi/FoFiBase.h new file mode 100644 index 00000000..b78840b2 --- /dev/null +++ b/kpdf/xpdf/fofi/FoFiBase.h @@ -0,0 +1,57 @@ +//======================================================================== +// +// FoFiBase.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFIBASE_H +#define FOFIBASE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +//------------------------------------------------------------------------ + +typedef void (*FoFiOutputFunc)(void *stream, char *data, int len); + +//------------------------------------------------------------------------ +// FoFiBase +//------------------------------------------------------------------------ + +class FoFiBase { +public: + + virtual ~FoFiBase(); + +protected: + + FoFiBase(char *fileA, int lenA, GBool freeFileDataA); + static char *readFile(char *fileName, int *fileLen); + + // S = signed / U = unsigned + // 8/16/32/Var = word length, in bytes + // BE = big endian + int getS8(int pos, GBool *ok); + int getU8(int pos, GBool *ok); + int getS16BE(int pos, GBool *ok); + int getU16BE(int pos, GBool *ok); + int getS32BE(int pos, GBool *ok); + Guint getU32BE(int pos, GBool *ok); + Guint getUVarBE(int pos, int size, GBool *ok); + + GBool checkRegion(int pos, int size); + + Guchar *fileData; + Guchar *file; + int len; + GBool freeFileData; +}; + +#endif diff --git a/kpdf/xpdf/fofi/FoFiEncodings.cc b/kpdf/xpdf/fofi/FoFiEncodings.cc new file mode 100644 index 00000000..37a17f5d --- /dev/null +++ b/kpdf/xpdf/fofi/FoFiEncodings.cc @@ -0,0 +1,994 @@ +//======================================================================== +// +// FoFiEncodings.cc +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "FoFiEncodings.h" + +//------------------------------------------------------------------------ +// Type 1 and 1C font data +//------------------------------------------------------------------------ + +char *fofiType1StandardEncoding[256] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "space", + "exclam", + "quotedbl", + "numbersign", + "dollar", + "percent", + "ampersand", + "quoteright", + "parenleft", + "parenright", + "asterisk", + "plus", + "comma", + "hyphen", + "period", + "slash", + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "colon", + "semicolon", + "less", + "equal", + "greater", + "question", + "at", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "bracketleft", + "backslash", + "bracketright", + "asciicircum", + "underscore", + "quoteleft", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "braceleft", + "bar", + "braceright", + "asciitilde", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "exclamdown", + "cent", + "sterling", + "fraction", + "yen", + "florin", + "section", + "currency", + "quotesingle", + "quotedblleft", + "guillemotleft", + "guilsinglleft", + "guilsinglright", + "fi", + "fl", + NULL, + "endash", + "dagger", + "daggerdbl", + "periodcentered", + NULL, + "paragraph", + "bullet", + "quotesinglbase", + "quotedblbase", + "quotedblright", + "guillemotright", + "ellipsis", + "perthousand", + NULL, + "questiondown", + NULL, + "grave", + "acute", + "circumflex", + "tilde", + "macron", + "breve", + "dotaccent", + "dieresis", + NULL, + "ring", + "cedilla", + NULL, + "hungarumlaut", + "ogonek", + "caron", + "emdash", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "AE", + NULL, + "ordfeminine", + NULL, + NULL, + NULL, + NULL, + "Lslash", + "Oslash", + "OE", + "ordmasculine", + NULL, + NULL, + NULL, + NULL, + NULL, + "ae", + NULL, + NULL, + NULL, + "dotlessi", + NULL, + NULL, + "lslash", + "oslash", + "oe", + "germandbls", + NULL, + NULL, + NULL, + NULL +}; + +char *fofiType1ExpertEncoding[256] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "space", + "exclamsmall", + "Hungarumlautsmall", + NULL, + "dollaroldstyle", + "dollarsuperior", + "ampersandsmall", + "Acutesmall", + "parenleftsuperior", + "parenrightsuperior", + "twodotenleader", + "onedotenleader", + "comma", + "hyphen", + "period", + "fraction", + "zerooldstyle", + "oneoldstyle", + "twooldstyle", + "threeoldstyle", + "fouroldstyle", + "fiveoldstyle", + "sixoldstyle", + "sevenoldstyle", + "eightoldstyle", + "nineoldstyle", + "colon", + "semicolon", + "commasuperior", + "threequartersemdash", + "periodsuperior", + "questionsmall", + NULL, + "asuperior", + "bsuperior", + "centsuperior", + "dsuperior", + "esuperior", + NULL, + NULL, + NULL, + "isuperior", + NULL, + NULL, + "lsuperior", + "msuperior", + "nsuperior", + "osuperior", + NULL, + NULL, + "rsuperior", + "ssuperior", + "tsuperior", + NULL, + "ff", + "fi", + "fl", + "ffi", + "ffl", + "parenleftinferior", + NULL, + "parenrightinferior", + "Circumflexsmall", + "hyphensuperior", + "Gravesmall", + "Asmall", + "Bsmall", + "Csmall", + "Dsmall", + "Esmall", + "Fsmall", + "Gsmall", + "Hsmall", + "Ismall", + "Jsmall", + "Ksmall", + "Lsmall", + "Msmall", + "Nsmall", + "Osmall", + "Psmall", + "Qsmall", + "Rsmall", + "Ssmall", + "Tsmall", + "Usmall", + "Vsmall", + "Wsmall", + "Xsmall", + "Ysmall", + "Zsmall", + "colonmonetary", + "onefitted", + "rupiah", + "Tildesmall", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "exclamdownsmall", + "centoldstyle", + "Lslashsmall", + NULL, + NULL, + "Scaronsmall", + "Zcaronsmall", + "Dieresissmall", + "Brevesmall", + "Caronsmall", + NULL, + "Dotaccentsmall", + NULL, + NULL, + "Macronsmall", + NULL, + NULL, + "figuredash", + "hypheninferior", + NULL, + NULL, + "Ogoneksmall", + "Ringsmall", + "Cedillasmall", + NULL, + NULL, + NULL, + "onequarter", + "onehalf", + "threequarters", + "questiondownsmall", + "oneeighth", + "threeeighths", + "fiveeighths", + "seveneighths", + "onethird", + "twothirds", + NULL, + NULL, + "zerosuperior", + "onesuperior", + "twosuperior", + "threesuperior", + "foursuperior", + "fivesuperior", + "sixsuperior", + "sevensuperior", + "eightsuperior", + "ninesuperior", + "zeroinferior", + "oneinferior", + "twoinferior", + "threeinferior", + "fourinferior", + "fiveinferior", + "sixinferior", + "seveninferior", + "eightinferior", + "nineinferior", + "centinferior", + "dollarinferior", + "periodinferior", + "commainferior", + "Agravesmall", + "Aacutesmall", + "Acircumflexsmall", + "Atildesmall", + "Adieresissmall", + "Aringsmall", + "AEsmall", + "Ccedillasmall", + "Egravesmall", + "Eacutesmall", + "Ecircumflexsmall", + "Edieresissmall", + "Igravesmall", + "Iacutesmall", + "Icircumflexsmall", + "Idieresissmall", + "Ethsmall", + "Ntildesmall", + "Ogravesmall", + "Oacutesmall", + "Ocircumflexsmall", + "Otildesmall", + "Odieresissmall", + "OEsmall", + "Oslashsmall", + "Ugravesmall", + "Uacutesmall", + "Ucircumflexsmall", + "Udieresissmall", + "Yacutesmall", + "Thornsmall", + "Ydieresissmall" +}; + +//------------------------------------------------------------------------ +// Type 1C font data +//------------------------------------------------------------------------ + +char *fofiType1CStdStrings[391] = { + ".notdef", + "space", + "exclam", + "quotedbl", + "numbersign", + "dollar", + "percent", + "ampersand", + "quoteright", + "parenleft", + "parenright", + "asterisk", + "plus", + "comma", + "hyphen", + "period", + "slash", + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "colon", + "semicolon", + "less", + "equal", + "greater", + "question", + "at", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "bracketleft", + "backslash", + "bracketright", + "asciicircum", + "underscore", + "quoteleft", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "braceleft", + "bar", + "braceright", + "asciitilde", + "exclamdown", + "cent", + "sterling", + "fraction", + "yen", + "florin", + "section", + "currency", + "quotesingle", + "quotedblleft", + "guillemotleft", + "guilsinglleft", + "guilsinglright", + "fi", + "fl", + "endash", + "dagger", + "daggerdbl", + "periodcentered", + "paragraph", + "bullet", + "quotesinglbase", + "quotedblbase", + "quotedblright", + "guillemotright", + "ellipsis", + "perthousand", + "questiondown", + "grave", + "acute", + "circumflex", + "tilde", + "macron", + "breve", + "dotaccent", + "dieresis", + "ring", + "cedilla", + "hungarumlaut", + "ogonek", + "caron", + "emdash", + "AE", + "ordfeminine", + "Lslash", + "Oslash", + "OE", + "ordmasculine", + "ae", + "dotlessi", + "lslash", + "oslash", + "oe", + "germandbls", + "onesuperior", + "logicalnot", + "mu", + "trademark", + "Eth", + "onehalf", + "plusminus", + "Thorn", + "onequarter", + "divide", + "brokenbar", + "degree", + "thorn", + "threequarters", + "twosuperior", + "registered", + "minus", + "eth", + "multiply", + "threesuperior", + "copyright", + "Aacute", + "Acircumflex", + "Adieresis", + "Agrave", + "Aring", + "Atilde", + "Ccedilla", + "Eacute", + "Ecircumflex", + "Edieresis", + "Egrave", + "Iacute", + "Icircumflex", + "Idieresis", + "Igrave", + "Ntilde", + "Oacute", + "Ocircumflex", + "Odieresis", + "Ograve", + "Otilde", + "Scaron", + "Uacute", + "Ucircumflex", + "Udieresis", + "Ugrave", + "Yacute", + "Ydieresis", + "Zcaron", + "aacute", + "acircumflex", + "adieresis", + "agrave", + "aring", + "atilde", + "ccedilla", + "eacute", + "ecircumflex", + "edieresis", + "egrave", + "iacute", + "icircumflex", + "idieresis", + "igrave", + "ntilde", + "oacute", + "ocircumflex", + "odieresis", + "ograve", + "otilde", + "scaron", + "uacute", + "ucircumflex", + "udieresis", + "ugrave", + "yacute", + "ydieresis", + "zcaron", + "exclamsmall", + "Hungarumlautsmall", + "dollaroldstyle", + "dollarsuperior", + "ampersandsmall", + "Acutesmall", + "parenleftsuperior", + "parenrightsuperior", + "twodotenleader", + "onedotenleader", + "zerooldstyle", + "oneoldstyle", + "twooldstyle", + "threeoldstyle", + "fouroldstyle", + "fiveoldstyle", + "sixoldstyle", + "sevenoldstyle", + "eightoldstyle", + "nineoldstyle", + "commasuperior", + "threequartersemdash", + "periodsuperior", + "questionsmall", + "asuperior", + "bsuperior", + "centsuperior", + "dsuperior", + "esuperior", + "isuperior", + "lsuperior", + "msuperior", + "nsuperior", + "osuperior", + "rsuperior", + "ssuperior", + "tsuperior", + "ff", + "ffi", + "ffl", + "parenleftinferior", + "parenrightinferior", + "Circumflexsmall", + "hyphensuperior", + "Gravesmall", + "Asmall", + "Bsmall", + "Csmall", + "Dsmall", + "Esmall", + "Fsmall", + "Gsmall", + "Hsmall", + "Ismall", + "Jsmall", + "Ksmall", + "Lsmall", + "Msmall", + "Nsmall", + "Osmall", + "Psmall", + "Qsmall", + "Rsmall", + "Ssmall", + "Tsmall", + "Usmall", + "Vsmall", + "Wsmall", + "Xsmall", + "Ysmall", + "Zsmall", + "colonmonetary", + "onefitted", + "rupiah", + "Tildesmall", + "exclamdownsmall", + "centoldstyle", + "Lslashsmall", + "Scaronsmall", + "Zcaronsmall", + "Dieresissmall", + "Brevesmall", + "Caronsmall", + "Dotaccentsmall", + "Macronsmall", + "figuredash", + "hypheninferior", + "Ogoneksmall", + "Ringsmall", + "Cedillasmall", + "questiondownsmall", + "oneeighth", + "threeeighths", + "fiveeighths", + "seveneighths", + "onethird", + "twothirds", + "zerosuperior", + "foursuperior", + "fivesuperior", + "sixsuperior", + "sevensuperior", + "eightsuperior", + "ninesuperior", + "zeroinferior", + "oneinferior", + "twoinferior", + "threeinferior", + "fourinferior", + "fiveinferior", + "sixinferior", + "seveninferior", + "eightinferior", + "nineinferior", + "centinferior", + "dollarinferior", + "periodinferior", + "commainferior", + "Agravesmall", + "Aacutesmall", + "Acircumflexsmall", + "Atildesmall", + "Adieresissmall", + "Aringsmall", + "AEsmall", + "Ccedillasmall", + "Egravesmall", + "Eacutesmall", + "Ecircumflexsmall", + "Edieresissmall", + "Igravesmall", + "Iacutesmall", + "Icircumflexsmall", + "Idieresissmall", + "Ethsmall", + "Ntildesmall", + "Ogravesmall", + "Oacutesmall", + "Ocircumflexsmall", + "Otildesmall", + "Odieresissmall", + "OEsmall", + "Oslashsmall", + "Ugravesmall", + "Uacutesmall", + "Ucircumflexsmall", + "Udieresissmall", + "Yacutesmall", + "Thornsmall", + "Ydieresissmall", + "001.000", + "001.001", + "001.002", + "001.003", + "Black", + "Bold", + "Book", + "Light", + "Medium", + "Regular", + "Roman", + "Semibold" +}; + +Gushort fofiType1CISOAdobeCharset[229] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228 +}; + +Gushort fofiType1CExpertCharset[166] = { + 0, 1, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 109, 110, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + 158, 155, 163, 319, 320, 321, 322, 323, 324, 325, + 326, 150, 164, 169, 327, 328, 329, 330, 331, 332, + 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, + 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, + 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, + 373, 374, 375, 376, 377, 378 +}; + +Gushort fofiType1CExpertSubsetCharset[87] = { + 0, 1, 231, 232, 235, 236, 237, 238, 13, 14, + 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 27, 28, 249, 250, 251, 253, 254, 255, + 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, + 266, 109, 110, 267, 268, 269, 270, 272, 300, 301, + 302, 305, 314, 315, 158, 155, 163, 320, 321, 322, + 323, 324, 325, 326, 150, 164, 169, 327, 328, 329, + 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346 +}; diff --git a/kpdf/xpdf/fofi/FoFiEncodings.h b/kpdf/xpdf/fofi/FoFiEncodings.h new file mode 100644 index 00000000..50e285d7 --- /dev/null +++ b/kpdf/xpdf/fofi/FoFiEncodings.h @@ -0,0 +1,36 @@ +//======================================================================== +// +// FoFiEncodings.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFIENCODINGS_H +#define FOFIENCODINGS_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +//------------------------------------------------------------------------ +// Type 1 and 1C font data +//------------------------------------------------------------------------ + +extern char *fofiType1StandardEncoding[256]; +extern char *fofiType1ExpertEncoding[256]; + +//------------------------------------------------------------------------ +// Type 1C font data +//------------------------------------------------------------------------ + +extern char *fofiType1CStdStrings[391]; +extern Gushort fofiType1CISOAdobeCharset[229]; +extern Gushort fofiType1CExpertCharset[166]; +extern Gushort fofiType1CExpertSubsetCharset[87]; + +#endif diff --git a/kpdf/xpdf/fofi/FoFiTrueType.cc b/kpdf/xpdf/fofi/FoFiTrueType.cc new file mode 100644 index 00000000..a205a068 --- /dev/null +++ b/kpdf/xpdf/fofi/FoFiTrueType.cc @@ -0,0 +1,2040 @@ +//======================================================================== +// +// FoFiTrueType.cc +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gtypes.h" +#include "gmem.h" +#include "GString.h" +#include "GHash.h" +#include "FoFiType1C.h" +#include "FoFiTrueType.h" + +// +// Terminology +// ----------- +// +// character code = number used as an element of a text string +// +// character name = glyph name = name for a particular glyph within a +// font +// +// glyph index = GID = position (within some internal table in the font) +// where the instructions to draw a particular glyph are +// stored +// +// Type 1 fonts +// ------------ +// +// Type 1 fonts contain: +// +// Encoding: array of glyph names, maps char codes to glyph names +// +// Encoding[charCode] = charName +// +// CharStrings: dictionary of instructions, keyed by character names, +// maps character name to glyph data +// +// CharStrings[charName] = glyphData +// +// TrueType fonts +// -------------- +// +// TrueType fonts contain: +// +// 'cmap' table: mapping from character code to glyph index; there may +// be multiple cmaps in a TrueType font +// +// cmap[charCode] = gid +// +// 'post' table: mapping from glyph index to glyph name +// +// post[gid] = glyphName +// +// Type 42 fonts +// ------------- +// +// Type 42 fonts contain: +// +// Encoding: array of glyph names, maps char codes to glyph names +// +// Encoding[charCode] = charName +// +// CharStrings: dictionary of glyph indexes, keyed by character names, +// maps character name to glyph index +// +// CharStrings[charName] = gid +// + +//------------------------------------------------------------------------ + +#define ttcfTag 0x74746366 + +//------------------------------------------------------------------------ + +struct TrueTypeTable { + Guint tag; + Guint checksum; + int offset; + int origOffset; + int len; +}; + +struct TrueTypeCmap { + int platform; + int encoding; + int offset; + int len; + int fmt; +}; + +struct TrueTypeLoca { + int idx; + int origOffset; + int newOffset; + int len; +}; + +#define cmapTag 0x636d6170 +#define glyfTag 0x676c7966 +#define headTag 0x68656164 +#define hheaTag 0x68686561 +#define hmtxTag 0x686d7478 +#define locaTag 0x6c6f6361 +#define nameTag 0x6e616d65 +#define os2Tag 0x4f532f32 +#define postTag 0x706f7374 + +static int cmpTrueTypeLocaOffset(const void *p1, const void *p2) { + TrueTypeLoca *loca1 = (TrueTypeLoca *)p1; + TrueTypeLoca *loca2 = (TrueTypeLoca *)p2; + + if (loca1->origOffset == loca2->origOffset) { + return loca1->idx - loca2->idx; + } + return loca1->origOffset - loca2->origOffset; +} + +static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) { + TrueTypeLoca *loca1 = (TrueTypeLoca *)p1; + TrueTypeLoca *loca2 = (TrueTypeLoca *)p2; + + return loca1->idx - loca2->idx; +} + +static int cmpTrueTypeTableTag(const void *p1, const void *p2) { + TrueTypeTable *tab1 = (TrueTypeTable *)p1; + TrueTypeTable *tab2 = (TrueTypeTable *)p2; + + return (int)tab1->tag - (int)tab2->tag; +} + +//------------------------------------------------------------------------ + +struct T42Table { + char *tag; // 4-byte tag + GBool required; // required by the TrueType spec? +}; + +// TrueType tables to be embedded in Type 42 fonts. +// NB: the table names must be in alphabetical order here. +#define nT42Tables 11 +static T42Table t42Tables[nT42Tables] = { + { "cvt ", gTrue }, + { "fpgm", gTrue }, + { "glyf", gTrue }, + { "head", gTrue }, + { "hhea", gTrue }, + { "hmtx", gTrue }, + { "loca", gTrue }, + { "maxp", gTrue }, + { "prep", gTrue }, + { "vhea", gFalse }, + { "vmtx", gFalse } +}; +#define t42HeadTable 3 +#define t42LocaTable 6 +#define t42GlyfTable 2 +#define t42VheaTable 9 +#define t42VmtxTable 10 + +//------------------------------------------------------------------------ + +// Glyph names in some arbitrary standard order that Apple uses for +// their TrueType fonts. +static char *macGlyphNames[258] = { + ".notdef", "null", "CR", "space", + "exclam", "quotedbl", "numbersign", "dollar", + "percent", "ampersand", "quotesingle", "parenleft", + "parenright", "asterisk", "plus", "comma", + "hyphen", "period", "slash", "zero", + "one", "two", "three", "four", + "five", "six", "seven", "eight", + "nine", "colon", "semicolon", "less", + "equal", "greater", "question", "at", + "A", "B", "C", "D", + "E", "F", "G", "H", + "I", "J", "K", "L", + "M", "N", "O", "P", + "Q", "R", "S", "T", + "U", "V", "W", "X", + "Y", "Z", "bracketleft", "backslash", + "bracketright", "asciicircum", "underscore", "grave", + "a", "b", "c", "d", + "e", "f", "g", "h", + "i", "j", "k", "l", + "m", "n", "o", "p", + "q", "r", "s", "t", + "u", "v", "w", "x", + "y", "z", "braceleft", "bar", + "braceright", "asciitilde", "Adieresis", "Aring", + "Ccedilla", "Eacute", "Ntilde", "Odieresis", + "Udieresis", "aacute", "agrave", "acircumflex", + "adieresis", "atilde", "aring", "ccedilla", + "eacute", "egrave", "ecircumflex", "edieresis", + "iacute", "igrave", "icircumflex", "idieresis", + "ntilde", "oacute", "ograve", "ocircumflex", + "odieresis", "otilde", "uacute", "ugrave", + "ucircumflex", "udieresis", "dagger", "degree", + "cent", "sterling", "section", "bullet", + "paragraph", "germandbls", "registered", "copyright", + "trademark", "acute", "dieresis", "notequal", + "AE", "Oslash", "infinity", "plusminus", + "lessequal", "greaterequal", "yen", "mu1", + "partialdiff", "summation", "product", "pi", + "integral", "ordfeminine", "ordmasculine", "Ohm", + "ae", "oslash", "questiondown", "exclamdown", + "logicalnot", "radical", "florin", "approxequal", + "increment", "guillemotleft", "guillemotright", "ellipsis", + "nbspace", "Agrave", "Atilde", "Otilde", + "OE", "oe", "endash", "emdash", + "quotedblleft", "quotedblright", "quoteleft", "quoteright", + "divide", "lozenge", "ydieresis", "Ydieresis", + "fraction", "currency", "guilsinglleft", "guilsinglright", + "fi", "fl", "daggerdbl", "periodcentered", + "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", + "Ecircumflex", "Aacute", "Edieresis", "Egrave", + "Iacute", "Icircumflex", "Idieresis", "Igrave", + "Oacute", "Ocircumflex", "applelogo", "Ograve", + "Uacute", "Ucircumflex", "Ugrave", "dotlessi", + "circumflex", "tilde", "overscore", "breve", + "dotaccent", "ring", "cedilla", "hungarumlaut", + "ogonek", "caron", "Lslash", "lslash", + "Scaron", "scaron", "Zcaron", "zcaron", + "brokenbar", "Eth", "eth", "Yacute", + "yacute", "Thorn", "thorn", "minus", + "multiply", "onesuperior", "twosuperior", "threesuperior", + "onehalf", "onequarter", "threequarters", "franc", + "Gbreve", "gbreve", "Idot", "Scedilla", + "scedilla", "Cacute", "cacute", "Ccaron", + "ccaron", "dmacron" +}; + +//------------------------------------------------------------------------ +// FoFiTrueType +//------------------------------------------------------------------------ + +FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA, int faceIndexA) { + FoFiTrueType *ff; + + ff = new FoFiTrueType(fileA, lenA, gFalse, faceIndexA); + if (!ff->parsedOk) { + delete ff; + return NULL; + } + return ff; +} + +FoFiTrueType *FoFiTrueType::load(char *fileName, int faceIndexA) { + FoFiTrueType *ff; + char *fileA; + int lenA; + + if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { + return NULL; + } + ff = new FoFiTrueType(fileA, lenA, gTrue, faceIndexA); + if (!ff->parsedOk) { + delete ff; + return NULL; + } + return ff; +} + +FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceIndexA): + FoFiBase(fileA, lenA, freeFileDataA) +{ + tables = NULL; + nTables = 0; + cmaps = NULL; + nCmaps = 0; + nameToGID = NULL; + parsedOk = gFalse; + faceIndex = faceIndexA; + + parse(); +} + +FoFiTrueType::~FoFiTrueType() { + gfree(tables); + gfree(cmaps); + if (nameToGID) { + delete nameToGID; + } +} + +int FoFiTrueType::getNumCmaps() { + return nCmaps; +} + +int FoFiTrueType::getCmapPlatform(int i) { + return cmaps[i].platform; +} + +int FoFiTrueType::getCmapEncoding(int i) { + return cmaps[i].encoding; +} + +int FoFiTrueType::findCmap(int platform, int encoding) { + int i; + + for (i = 0; i < nCmaps; ++i) { + if (cmaps[i].platform == platform && cmaps[i].encoding == encoding) { + return i; + } + } + return -1; +} + +Gushort FoFiTrueType::mapCodeToGID(int i, int c) { + Gushort gid; + int segCnt, segEnd, segStart, segDelta, segOffset; + int cmapFirst, cmapLen; + int pos, a, b, m; + GBool ok; + + if (i < 0 || i >= nCmaps) { + return 0; + } + ok = gTrue; + pos = cmaps[i].offset; + switch (cmaps[i].fmt) { + case 0: + if (c < 0 || c >= cmaps[i].len - 6) { + return 0; + } + gid = getU8(cmaps[i].offset + 6 + c, &ok); + break; + case 4: + segCnt = getU16BE(pos + 6, &ok) / 2; + a = -1; + b = segCnt - 1; + segEnd = getU16BE(pos + 14 + 2*b, &ok); + if (c > segEnd) { + // malformed font -- the TrueType spec requires the last segEnd + // to be 0xffff + return 0; + } + // invariant: seg[a].end < code <= seg[b].end + while (b - a > 1 && ok) { + m = (a + b) / 2; + segEnd = getU16BE(pos + 14 + 2*m, &ok); + if (segEnd < c) { + a = m; + } else { + b = m; + } + } + segStart = getU16BE(pos + 16 + 2*segCnt + 2*b, &ok); + segDelta = getU16BE(pos + 16 + 4*segCnt + 2*b, &ok); + segOffset = getU16BE(pos + 16 + 6*segCnt + 2*b, &ok); + if (c < segStart) { + return 0; + } + if (segOffset == 0) { + gid = (c + segDelta) & 0xffff; + } else { + gid = getU16BE(pos + 16 + 6*segCnt + 2*b + + segOffset + 2 * (c - segStart), &ok); + if (gid != 0) { + gid = (gid + segDelta) & 0xffff; + } + } + break; + case 6: + cmapFirst = getU16BE(pos + 6, &ok); + cmapLen = getU16BE(pos + 8, &ok); + if (c < cmapFirst || c >= cmapFirst + cmapLen) { + return 0; + } + gid = getU16BE(pos + 10 + 2 * (c - cmapFirst), &ok); + break; + default: + return 0; + } + if (!ok) { + return 0; + } + return gid; +} + +int FoFiTrueType::mapNameToGID(char *name) { + if (!nameToGID) { + return 0; + } + return nameToGID->lookupInt(name); +} + +Gushort *FoFiTrueType::getCIDToGIDMap(int *nCIDs) { + FoFiType1C *ff; + Gushort *map; + int i; + + *nCIDs = 0; + if (!openTypeCFF) { + return NULL; + } + i = seekTable("CFF "); + if (!checkRegion(tables[i].offset, tables[i].len)) { + return NULL; + } + if (!(ff = FoFiType1C::make((char *)file + tables[i].offset, + tables[i].len))) { + return NULL; + } + map = ff->getCIDToGIDMap(nCIDs); + delete ff; + return map; +} + +int FoFiTrueType::getEmbeddingRights() { + int i, fsType; + GBool ok; + + if ((i = seekTable("OS/2")) < 0) { + return 4; + } + ok = gTrue; + fsType = getU16BE(tables[i].offset + 8, &ok); + if (!ok) { + return 4; + } + if (fsType & 0x0008) { + return 2; + } + if (fsType & 0x0004) { + return 1; + } + if (fsType & 0x0002) { + return 0; + } + return 3; +} + +void FoFiTrueType::convertToType42(char *psName, char **encoding, + Gushort *codeToGID, + FoFiOutputFunc outputFunc, + void *outputStream) { + GString *buf; + GBool ok; + + if (openTypeCFF) { + return; + } + + // write the header + ok = gTrue; + buf = GString::format("%!PS-TrueTypeFont-{0:2g}\n", + (double)getS32BE(0, &ok) / 65536.0); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + + // begin the font dictionary + (*outputFunc)(outputStream, "10 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, strlen(psName)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/FontType 42 def\n", 17); + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n", + bbox[0], bbox[1], bbox[2], bbox[3]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); + + // write the guts of the dictionary + cvtEncoding(encoding, outputFunc, outputStream); + cvtCharStrings(encoding, codeToGID, outputFunc, outputStream); + cvtSfnts(outputFunc, outputStream, NULL, gFalse); + + // end the dictionary and define the font + (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); +} + +void FoFiTrueType::convertToType1(char *psName, char **newEncoding, + GBool ascii, FoFiOutputFunc outputFunc, + void *outputStream) { + FoFiType1C *ff; + int i; + + if (!openTypeCFF) { + return; + } + i = seekTable("CFF "); + if (!checkRegion(tables[i].offset, tables[i].len)) { + return; + } + if (!(ff = FoFiType1C::make((char *)file + tables[i].offset, + tables[i].len))) { + return; + } + ff->convertToType1(psName, newEncoding, ascii, outputFunc, outputStream); + delete ff; +} + +void FoFiTrueType::convertToCIDType2(char *psName, + Gushort *cidMap, int nCIDs, + GBool needVerticalMetrics, + FoFiOutputFunc outputFunc, + void *outputStream) { + GString *buf; + Gushort cid; + GBool ok; + int i, j, k; + + if (openTypeCFF) { + return; + } + + // write the header + ok = gTrue; + buf = GString::format("%!PS-TrueTypeFont-{0:2g}\n", + (double)getS32BE(0, &ok) / 65536.0); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + + // begin the font dictionary + (*outputFunc)(outputStream, "20 dict begin\n", 14); + (*outputFunc)(outputStream, "/CIDFontName /", 14); + (*outputFunc)(outputStream, psName, strlen(psName)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19); + (*outputFunc)(outputStream, "/FontType 42 def\n", 17); + (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32); + (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24); + (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27); + (*outputFunc)(outputStream, " /Supplement 0 def\n", 20); + (*outputFunc)(outputStream, " end def\n", 10); + (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15); + if (cidMap) { + buf = GString::format("/CIDCount {0:d} def\n", nCIDs); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + if (nCIDs > 32767) { + (*outputFunc)(outputStream, "/CIDMap [", 9); + for (i = 0; i < nCIDs; i += 32768 - 16) { + (*outputFunc)(outputStream, "<\n", 2); + for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) { + (*outputFunc)(outputStream, " ", 2); + for (k = 0; k < 16 && i+j+k < nCIDs; ++k) { + cid = cidMap[i+j+k]; + buf = GString::format("{0:02x}{1:02x}", + (cid >> 8) & 0xff, cid & 0xff); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "\n", 1); + } + (*outputFunc)(outputStream, " >", 3); + } + (*outputFunc)(outputStream, "\n", 1); + (*outputFunc)(outputStream, "] def\n", 6); + } else { + (*outputFunc)(outputStream, "/CIDMap <\n", 10); + for (i = 0; i < nCIDs; i += 16) { + (*outputFunc)(outputStream, " ", 2); + for (j = 0; j < 16 && i+j < nCIDs; ++j) { + cid = cidMap[i+j]; + buf = GString::format("{0:02x}{1:02x}", + (cid >> 8) & 0xff, cid & 0xff); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "\n", 1); + } + (*outputFunc)(outputStream, "> def\n", 6); + } + } else { + // direct mapping - just fill the string(s) with s[i]=i + buf = GString::format("/CIDCount {0:d} def\n", nGlyphs); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + if (nGlyphs > 32767) { + (*outputFunc)(outputStream, "/CIDMap [\n", 10); + for (i = 0; i < nGlyphs; i += 32767) { + j = nGlyphs - i < 32767 ? nGlyphs - i : 32767; + buf = GString::format(" {0:d} string 0 1 {1:d} {{\n", 2 * j, j - 1); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format(" 2 copy dup 2 mul exch {0:d} add -8 bitshift put\n", + i); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format(" 1 index exch dup 2 mul 1 add exch {0:d} add" + " 255 and put\n", i); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, " } for\n", 8); + } + (*outputFunc)(outputStream, "] def\n", 6); + } else { + buf = GString::format("/CIDMap {0:d} string\n", 2 * nGlyphs); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format(" 0 1 {0:d} {{\n", nGlyphs - 1); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, + " 2 copy dup 2 mul exch -8 bitshift put\n", 42); + (*outputFunc)(outputStream, + " 1 index exch dup 2 mul 1 add exch 255 and put\n", 50); + (*outputFunc)(outputStream, " } for\n", 8); + (*outputFunc)(outputStream, "def\n", 4); + } + } + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n", + bbox[0], bbox[1], bbox[2], bbox[3]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); + (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26); + (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30); + (*outputFunc)(outputStream, " /.notdef 0 def\n", 17); + (*outputFunc)(outputStream, " end readonly def\n", 19); + + // write the guts of the dictionary + cvtSfnts(outputFunc, outputStream, NULL, needVerticalMetrics); + + // end the dictionary and define the font + (*outputFunc)(outputStream, + "CIDFontName currentdict end /CIDFont defineresource pop\n", + 56); +} + +void FoFiTrueType::convertToCIDType0(char *psName, + FoFiOutputFunc outputFunc, + void *outputStream) { + FoFiType1C *ff; + int i; + + if (!openTypeCFF) { + return; + } + i = seekTable("CFF "); + if (!checkRegion(tables[i].offset, tables[i].len)) { + return; + } + if (!(ff = FoFiType1C::make((char *)file + tables[i].offset, + tables[i].len))) { + return; + } + ff->convertToCIDType0(psName, outputFunc, outputStream); + delete ff; +} + +void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs, + GBool needVerticalMetrics, + FoFiOutputFunc outputFunc, + void *outputStream) { + GString *buf; + GString *sfntsName; + int n, i, j; + + if (openTypeCFF) { + return; + } + + // write the Type 42 sfnts array + sfntsName = (new GString(psName))->append("_sfnts"); + cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics); + delete sfntsName; + + // write the descendant Type 42 fonts + n = cidMap ? nCIDs : nGlyphs; + for (i = 0; i < n; i += 256) { + (*outputFunc)(outputStream, "10 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, strlen(psName)); + buf = GString::format("_{0:02x} def\n", i >> 8); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/FontType 42 def\n", 17); + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n", + bbox[0], bbox[1], bbox[2], bbox[3]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); + (*outputFunc)(outputStream, "/sfnts ", 7); + (*outputFunc)(outputStream, psName, strlen(psName)); + (*outputFunc)(outputStream, "_sfnts def\n", 11); + (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); + for (j = 0; j < 256 && i+j < n; ++j) { + buf = GString::format("dup {0:d} /c{1:02x} put\n", j, j); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "readonly def\n", 13); + (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32); + (*outputFunc)(outputStream, "/.notdef 0 def\n", 15); + for (j = 0; j < 256 && i+j < n; ++j) { + buf = GString::format("/c{0:02x} {1:d} def\n", + j, cidMap ? cidMap[i+j] : i+j); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "end readonly def\n", 17); + (*outputFunc)(outputStream, + "FontName currentdict end definefont pop\n", 40); + } + + // write the Type 0 parent font + (*outputFunc)(outputStream, "16 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, strlen(psName)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/FontType 0 def\n", 16); + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); + (*outputFunc)(outputStream, "/Encoding [\n", 12); + for (i = 0; i < n; i += 256) { + buf = GString::format("{0:d}\n", i >> 8); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + (*outputFunc)(outputStream, "/FDepVector [\n", 14); + for (i = 0; i < n; i += 256) { + (*outputFunc)(outputStream, "/", 1); + (*outputFunc)(outputStream, psName, strlen(psName)); + buf = GString::format("_{0:02x} findfont\n", i >> 8); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); +} + +void FoFiTrueType::convertToType0(char *psName, + FoFiOutputFunc outputFunc, + void *outputStream) { + FoFiType1C *ff; + int i; + + if (!openTypeCFF) { + return; + } + i = seekTable("CFF "); + if (!checkRegion(tables[i].offset, tables[i].len)) { + return; + } + if (!(ff = FoFiType1C::make((char *)file + tables[i].offset, + tables[i].len))) { + return; + } + ff->convertToType0(psName, outputFunc, outputStream); + delete ff; +} + +void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, + void *outputStream, char *name, + Gushort *codeToGID) { + // this substitute cmap table maps char codes 0000-ffff directly to + // glyphs 0000-ffff + static char cmapTab[36] = { + 0, 0, // table version number + 0, 1, // number of encoding tables + 0, 1, // platform ID + 0, 0, // encoding ID + 0, 0, 0, 12, // offset of subtable + 0, 4, // subtable format + 0, 24, // subtable length + 0, 0, // subtable version + 0, 2, // segment count * 2 + 0, 2, // 2 * 2 ^ floor(log2(segCount)) + 0, 0, // floor(log2(segCount)) + 0, 0, // 2*segCount - 2*2^floor(log2(segCount)) + (char)0xff, (char)0xff, // endCount[0] + 0, 0, // reserved + 0, 0, // startCount[0] + 0, 0, // idDelta[0] + 0, 0 // pad to a mulitple of four bytes + }; + static char nameTab[8] = { + 0, 0, // format + 0, 0, // number of name records + 0, 6, // offset to start of string storage + 0, 0 // pad to multiple of four bytes + }; + static char postTab[32] = { + 0, 1, 0, 0, // format + 0, 0, 0, 0, // italic angle + 0, 0, // underline position + 0, 0, // underline thickness + 0, 0, 0, 0, // fixed pitch + 0, 0, 0, 0, // min Type 42 memory + 0, 0, 0, 0, // max Type 42 memory + 0, 0, 0, 0, // min Type 1 memory + 0, 0, 0, 0 // max Type 1 memory + }; + static char os2Tab[86] = { + 0, 1, // version + 0, 1, // xAvgCharWidth + 0, 0, // usWeightClass + 0, 0, // usWidthClass + 0, 0, // fsType + 0, 0, // ySubscriptXSize + 0, 0, // ySubscriptYSize + 0, 0, // ySubscriptXOffset + 0, 0, // ySubscriptYOffset + 0, 0, // ySuperscriptXSize + 0, 0, // ySuperscriptYSize + 0, 0, // ySuperscriptXOffset + 0, 0, // ySuperscriptYOffset + 0, 0, // yStrikeoutSize + 0, 0, // yStrikeoutPosition + 0, 0, // sFamilyClass + 0, 0, 0, 0, 0, // panose + 0, 0, 0, 0, 0, + 0, 0, 0, 0, // ulUnicodeRange1 + 0, 0, 0, 0, // ulUnicodeRange2 + 0, 0, 0, 0, // ulUnicodeRange3 + 0, 0, 0, 0, // ulUnicodeRange4 + 0, 0, 0, 0, // achVendID + 0, 0, // fsSelection + 0, 0, // usFirstCharIndex + 0, 0, // usLastCharIndex + 0, 0, // sTypoAscender + 0, 0, // sTypoDescender + 0, 0, // sTypoLineGap + 0, 0, // usWinAscent + 0, 0, // usWinDescent + 0, 0, 0, 0, // ulCodePageRange1 + 0, 0, 0, 0 // ulCodePageRange2 + }; + GBool missingCmap, missingName, missingPost, missingOS2; + GBool unsortedLoca, badCmapLen, abbrevHMTX; + int nZeroLengthTables; + int nHMetrics, advWidth, lsb; + TrueTypeLoca *locaTable; + TrueTypeTable *newTables; + char *newNameTab, *newCmapTab, *newHHEATab, *newHMTXTab; + int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next; + int newHHEALen, newHMTXLen; + Guint locaChecksum, glyfChecksum, fileChecksum; + char *tableDir; + char locaBuf[4], checksumBuf[4]; + GBool ok; + Guint t; + int pos, i, j, k, n; + + if (openTypeCFF) { + return; + } + + // check for missing tables + // (Note: if the OS/2 table is missing, the Microsoft PCL5 driver + // will embed a PCL TrueType font with the pitch field set to zero, + // which apparently causes divide-by-zero errors. As far as I can + // tell, the only important field in the OS/2 table is + // xAvgCharWidth.) + missingCmap = (cmapIdx = seekTable("cmap")) < 0; + missingName = seekTable("name") < 0; + missingPost = seekTable("post") < 0; + missingOS2 = seekTable("OS/2") < 0; + + // read the loca table, check to see if it's sorted + locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca)); + unsortedLoca = gFalse; + i = seekTable("loca"); + pos = tables[i].offset; + ok = gTrue; + for (i = 0; i <= nGlyphs; ++i) { + if (locaFmt) { + locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok); + } else { + locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok); + } + if (i > 0 && locaTable[i].origOffset < locaTable[i-1].origOffset) { + unsortedLoca = gTrue; + } + // glyph descriptions must be at least 12 bytes long (nContours, + // xMin, yMin, xMax, yMax, instructionLength - two bytes each); + // invalid glyph descriptions (even if they're never used) make + // Windows choke, so we work around that problem here (ideally, + // this would parse the glyph descriptions in the glyf table and + // remove any that were invalid, but this quick test is a decent + // start) + if (i > 0 && + locaTable[i].origOffset - locaTable[i-1].origOffset > 0 && + locaTable[i].origOffset - locaTable[i-1].origOffset < 12) { + locaTable[i-1].origOffset = locaTable[i].origOffset; + unsortedLoca = gTrue; + } + locaTable[i].idx = i; + } + + // check for zero-length tables + nZeroLengthTables = 0; + for (i = 0; i < nTables; ++i) { + if (tables[i].len == 0) { + ++nZeroLengthTables; + } + } + + // check for an incorrect cmap table length + badCmapLen = gFalse; + cmapLen = 0; // make gcc happy + if (!missingCmap) { + cmapLen = cmaps[0].offset + cmaps[0].len; + for (i = 1; i < nCmaps; ++i) { + if (cmaps[i].offset + cmaps[i].len > cmapLen) { + cmapLen = cmaps[i].offset + cmaps[i].len; + } + } + cmapLen -= tables[cmapIdx].offset; + if (cmapLen > tables[cmapIdx].len) { + badCmapLen = gTrue; + } + } + + // check for an abbreviated hmtx table (this is completely legal, + // but confuses the Microsoft PCL5 printer driver, which generates + // embedded fonts with the pitch field set to zero) + i = seekTable("hhea"); + nHMetrics = getU16BE(tables[i].offset + 34, &ok); + abbrevHMTX = nHMetrics < nGlyphs; + + // if nothing is broken, just write the TTF file as is + if (!missingCmap && !missingName && !missingPost && !missingOS2 && + !unsortedLoca && !badCmapLen && !abbrevHMTX && nZeroLengthTables == 0 && + !name && !codeToGID) { + (*outputFunc)(outputStream, (char *)file, len); + goto done1; + } + + // sort the 'loca' table: some (non-compliant) fonts have + // out-of-order loca tables; in order to correctly handle the case + // where (compliant) fonts have empty entries in the middle of the + // table, cmpTrueTypeLocaOffset uses offset as its primary sort key, + // and idx as its secondary key (ensuring that adjacent entries with + // the same pos value remain in the same order) + glyfLen = 0; // make gcc happy + if (unsortedLoca) { + qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), + &cmpTrueTypeLocaOffset); + for (i = 0; i < nGlyphs; ++i) { + locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset; + } + locaTable[nGlyphs].len = 0; + qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), + &cmpTrueTypeLocaIdx); + pos = 0; + for (i = 0; i <= nGlyphs; ++i) { + locaTable[i].newOffset = pos; + pos += locaTable[i].len; + if (pos & 3) { + pos += 4 - (pos & 3); + } + } + glyfLen = pos; + } + + // compute checksums for the loca and glyf tables + locaChecksum = glyfChecksum = 0; + if (unsortedLoca) { + if (locaFmt) { + for (j = 0; j <= nGlyphs; ++j) { + locaChecksum += locaTable[j].newOffset; + } + } else { + for (j = 0; j <= nGlyphs; j += 2) { + locaChecksum += locaTable[j].newOffset << 16; + if (j + 1 <= nGlyphs) { + locaChecksum += locaTable[j+1].newOffset; + } + } + } + pos = tables[seekTable("glyf")].offset; + for (j = 0; j < nGlyphs; ++j) { + n = locaTable[j].len; + if (n > 0) { + k = locaTable[j].origOffset; + if (checkRegion(pos + k, n)) { + glyfChecksum += computeTableChecksum(file + pos + k, n); + } + } + } + } + + // construct the new name table + if (name) { + n = strlen(name); + newNameLen = (6 + 4*12 + 2 * (3*n + 7) + 3) & ~3; + newNameTab = (char *)gmalloc(newNameLen); + memset(newNameTab, 0, newNameLen); + newNameTab[0] = 0; // format selector + newNameTab[1] = 0; + newNameTab[2] = 0; // number of name records + newNameTab[3] = 4; + newNameTab[4] = 0; // offset to start of string storage + newNameTab[5] = 6 + 4*12; + next = 0; + for (i = 0; i < 4; ++i) { + newNameTab[6 + i*12 + 0] = 0; // platform ID = Microsoft + newNameTab[6 + i*12 + 1] = 3; + newNameTab[6 + i*12 + 2] = 0; // encoding ID = Unicode + newNameTab[6 + i*12 + 3] = 1; + newNameTab[6 + i*12 + 4] = 0x04; // language ID = American English + newNameTab[6 + i*12 + 5] = 0x09; + newNameTab[6 + i*12 + 6] = 0; // name ID + newNameTab[6 + i*12 + 7] = i + 1; + newNameTab[6 + i*12 + 8] = i+1 == 2 ? 0 : ((2*n) >> 8); // string length + newNameTab[6 + i*12 + 9] = i+1 == 2 ? 14 : ((2*n) & 0xff); + newNameTab[6 + i*12 + 10] = next >> 8; // string offset + newNameTab[6 + i*12 + 11] = next & 0xff; + if (i+1 == 2) { + memcpy(newNameTab + 6 + 4*12 + next, "\0R\0e\0g\0u\0l\0a\0r", 14); + next += 14; + } else { + for (j = 0; j < n; ++j) { + newNameTab[6 + 4*12 + next + 2*j] = 0; + newNameTab[6 + 4*12 + next + 2*j + 1] = name[j]; + } + next += 2*n; + } + } + } else { + newNameLen = 0; + newNameTab = NULL; + } + + // construct the new cmap table + if (codeToGID) { + newCmapLen = 44 + 256 * 2; + newCmapTab = (char *)gmalloc(newCmapLen); + newCmapTab[0] = 0; // table version number = 0 + newCmapTab[1] = 0; + newCmapTab[2] = 0; // number of encoding tables = 1 + newCmapTab[3] = 1; + newCmapTab[4] = 0; // platform ID = Microsoft + newCmapTab[5] = 3; + newCmapTab[6] = 0; // encoding ID = Unicode + newCmapTab[7] = 1; + newCmapTab[8] = 0; // offset of subtable + newCmapTab[9] = 0; + newCmapTab[10] = 0; + newCmapTab[11] = 12; + newCmapTab[12] = 0; // subtable format = 4 + newCmapTab[13] = 4; + newCmapTab[14] = 0x02; // subtable length + newCmapTab[15] = 0x20; + newCmapTab[16] = 0; // subtable version = 0 + newCmapTab[17] = 0; + newCmapTab[18] = 0; // segment count * 2 + newCmapTab[19] = 4; + newCmapTab[20] = 0; // 2 * 2 ^ floor(log2(segCount)) + newCmapTab[21] = 4; + newCmapTab[22] = 0; // floor(log2(segCount)) + newCmapTab[23] = 1; + newCmapTab[24] = 0; // 2*segCount - 2*2^floor(log2(segCount)) + newCmapTab[25] = 0; + newCmapTab[26] = 0x00; // endCount[0] + newCmapTab[27] = (char)0xff; + newCmapTab[28] = (char)0xff; // endCount[1] + newCmapTab[29] = (char)0xff; + newCmapTab[30] = 0; // reserved + newCmapTab[31] = 0; + newCmapTab[32] = 0x00; // startCount[0] + newCmapTab[33] = 0x00; + newCmapTab[34] = (char)0xff; // startCount[1] + newCmapTab[35] = (char)0xff; + newCmapTab[36] = 0; // idDelta[0] + newCmapTab[37] = 0; + newCmapTab[38] = 0; // idDelta[1] + newCmapTab[39] = 1; + newCmapTab[40] = 0; // idRangeOffset[0] + newCmapTab[41] = 4; + newCmapTab[42] = 0; // idRangeOffset[1] + newCmapTab[43] = 0; + for (i = 0; i < 256; ++i) { + newCmapTab[44 + 2*i] = codeToGID[i] >> 8; + newCmapTab[44 + 2*i + 1] = codeToGID[i] & 0xff; + } + } else { + newCmapLen = 0; + newCmapTab = NULL; + } + + // generate the new hmtx table and the updated hhea table + if (abbrevHMTX) { + i = seekTable("hhea"); + pos = tables[i].offset; + newHHEALen = 36; + newHHEATab = (char *)gmalloc(newHHEALen); + for (i = 0; i < newHHEALen; ++i) { + newHHEATab[i] = getU8(pos++, &ok); + } + newHHEATab[34] = nGlyphs >> 8; + newHHEATab[35] = nGlyphs & 0xff; + i = seekTable("hmtx"); + pos = tables[i].offset; + newHMTXLen = 4 * nGlyphs; + newHMTXTab = (char *)gmalloc(newHMTXLen); + advWidth = 0; + for (i = 0; i < nHMetrics; ++i) { + advWidth = getU16BE(pos, &ok); + lsb = getU16BE(pos + 2, &ok); + pos += 4; + newHMTXTab[4*i ] = advWidth >> 8; + newHMTXTab[4*i + 1] = advWidth & 0xff; + newHMTXTab[4*i + 2] = lsb >> 8; + newHMTXTab[4*i + 3] = lsb & 0xff; + } + for (; i < nGlyphs; ++i) { + lsb = getU16BE(pos, &ok); + pos += 2; + newHMTXTab[4*i ] = advWidth >> 8; + newHMTXTab[4*i + 1] = advWidth & 0xff; + newHMTXTab[4*i + 2] = lsb >> 8; + newHMTXTab[4*i + 3] = lsb & 0xff; + } + } else { + newHHEATab = newHMTXTab = NULL; + newHHEALen = newHMTXLen = 0; // make gcc happy + } + + // construct the new table directory: + // - keep all original tables with non-zero length + // - fix the cmap table's length, if necessary + // - add missing tables + // - sort the table by tag + // - compute new table positions, including 4-byte alignment + // - (re)compute table checksums + nNewTables = nTables - nZeroLengthTables + + (missingCmap ? 1 : 0) + (missingName ? 1 : 0) + + (missingPost ? 1 : 0) + (missingOS2 ? 1 : 0); + newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable)); + j = 0; + for (i = 0; i < nTables; ++i) { + if (tables[i].len > 0) { + newTables[j] = tables[i]; + newTables[j].origOffset = tables[i].offset; + if (checkRegion(tables[i].offset, newTables[i].len)) { + newTables[j].checksum = + computeTableChecksum(file + tables[i].offset, tables[i].len); + if (tables[i].tag == headTag) { + // don't include the file checksum + newTables[j].checksum -= getU32BE(tables[i].offset + 8, &ok); + } + } + if (newTables[j].tag == cmapTag && codeToGID) { + newTables[j].len = newCmapLen; + newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, + newCmapLen); + } else if (newTables[j].tag == cmapTag && badCmapLen) { + newTables[j].len = cmapLen; + } else if (newTables[j].tag == locaTag && unsortedLoca) { + newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2); + newTables[j].checksum = locaChecksum; + } else if (newTables[j].tag == glyfTag && unsortedLoca) { + newTables[j].len = glyfLen; + newTables[j].checksum = glyfChecksum; + } else if (newTables[j].tag == nameTag && name) { + newTables[j].len = newNameLen; + newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab, + newNameLen); + } else if (newTables[j].tag == hheaTag && abbrevHMTX) { + newTables[j].len = newHHEALen; + newTables[j].checksum = computeTableChecksum((Guchar *)newHHEATab, + newHHEALen); + } else if (newTables[j].tag == hmtxTag && abbrevHMTX) { + newTables[j].len = newHMTXLen; + newTables[j].checksum = computeTableChecksum((Guchar *)newHMTXTab, + newHMTXLen); + } + ++j; + } + } + if (missingCmap) { + newTables[j].tag = cmapTag; + if (codeToGID) { + newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, + newCmapLen); + newTables[j].len = newCmapLen; + } else { + newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab, + sizeof(cmapTab)); + newTables[j].len = sizeof(cmapTab); + } + ++j; + } + if (missingName) { + newTables[j].tag = nameTag; + if (name) { + newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab, + newNameLen); + newTables[j].len = newNameLen; + } else { + newTables[j].checksum = computeTableChecksum((Guchar *)nameTab, + sizeof(nameTab)); + newTables[j].len = sizeof(nameTab); + } + ++j; + } + if (missingPost) { + newTables[j].tag = postTag; + newTables[j].checksum = computeTableChecksum((Guchar *)postTab, + sizeof(postTab)); + newTables[j].len = sizeof(postTab); + ++j; + } + if (missingOS2) { + newTables[j].tag = os2Tag; + newTables[j].checksum = computeTableChecksum((Guchar *)os2Tab, + sizeof(os2Tab)); + newTables[j].len = sizeof(os2Tab); + ++j; + } + qsort(newTables, nNewTables, sizeof(TrueTypeTable), + &cmpTrueTypeTableTag); + pos = 12 + nNewTables * 16; + for (i = 0; i < nNewTables; ++i) { + newTables[i].offset = pos; + pos += newTables[i].len; + if (pos & 3) { + pos += 4 - (pos & 3); + } + } + + // write the table directory + tableDir = (char *)gmalloc(12 + nNewTables * 16); + tableDir[0] = 0x00; // sfnt version + tableDir[1] = 0x01; + tableDir[2] = 0x00; + tableDir[3] = 0x00; + tableDir[4] = (char)((nNewTables >> 8) & 0xff); // numTables + tableDir[5] = (char)(nNewTables & 0xff); + for (i = -1, t = (Guint)nNewTables; t; ++i, t >>= 1) ; + t = 1 << (4 + i); + tableDir[6] = (char)((t >> 8) & 0xff); // searchRange + tableDir[7] = (char)(t & 0xff); + tableDir[8] = (char)((i >> 8) & 0xff); // entrySelector + tableDir[9] = (char)(i & 0xff); + t = nNewTables * 16 - t; + tableDir[10] = (char)((t >> 8) & 0xff); // rangeShift + tableDir[11] = (char)(t & 0xff); + pos = 12; + for (i = 0; i < nNewTables; ++i) { + tableDir[pos ] = (char)(newTables[i].tag >> 24); + tableDir[pos+ 1] = (char)(newTables[i].tag >> 16); + tableDir[pos+ 2] = (char)(newTables[i].tag >> 8); + tableDir[pos+ 3] = (char) newTables[i].tag; + tableDir[pos+ 4] = (char)(newTables[i].checksum >> 24); + tableDir[pos+ 5] = (char)(newTables[i].checksum >> 16); + tableDir[pos+ 6] = (char)(newTables[i].checksum >> 8); + tableDir[pos+ 7] = (char) newTables[i].checksum; + tableDir[pos+ 8] = (char)(newTables[i].offset >> 24); + tableDir[pos+ 9] = (char)(newTables[i].offset >> 16); + tableDir[pos+10] = (char)(newTables[i].offset >> 8); + tableDir[pos+11] = (char) newTables[i].offset; + tableDir[pos+12] = (char)(newTables[i].len >> 24); + tableDir[pos+13] = (char)(newTables[i].len >> 16); + tableDir[pos+14] = (char)(newTables[i].len >> 8); + tableDir[pos+15] = (char) newTables[i].len; + pos += 16; + } + (*outputFunc)(outputStream, tableDir, 12 + nNewTables * 16); + + // compute the file checksum + fileChecksum = computeTableChecksum((Guchar *)tableDir, + 12 + nNewTables * 16); + for (i = 0; i < nNewTables; ++i) { + fileChecksum += newTables[i].checksum; + } + fileChecksum = 0xb1b0afba - fileChecksum; + + // write the tables + for (i = 0; i < nNewTables; ++i) { + if (newTables[i].tag == headTag) { + if (checkRegion(newTables[i].origOffset, newTables[i].len)) { + (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, 8); + checksumBuf[0] = fileChecksum >> 24; + checksumBuf[1] = fileChecksum >> 16; + checksumBuf[2] = fileChecksum >> 8; + checksumBuf[3] = fileChecksum; + (*outputFunc)(outputStream, checksumBuf, 4); + (*outputFunc)(outputStream, + (char *)file + newTables[i].origOffset + 12, + newTables[i].len - 12); + } else { + for (j = 0; j < newTables[i].len; ++j) { + (*outputFunc)(outputStream, "\0", 1); + } + } + } else if (newTables[i].tag == cmapTag && codeToGID) { + (*outputFunc)(outputStream, newCmapTab, newTables[i].len); + } else if (newTables[i].tag == cmapTag && missingCmap) { + (*outputFunc)(outputStream, cmapTab, newTables[i].len); + } else if (newTables[i].tag == nameTag && name) { + (*outputFunc)(outputStream, newNameTab, newTables[i].len); + } else if (newTables[i].tag == nameTag && missingName) { + (*outputFunc)(outputStream, nameTab, newTables[i].len); + } else if (newTables[i].tag == postTag && missingPost) { + (*outputFunc)(outputStream, postTab, newTables[i].len); + } else if (newTables[i].tag == os2Tag && missingOS2) { + (*outputFunc)(outputStream, os2Tab, newTables[i].len); + } else if (newTables[i].tag == hheaTag && abbrevHMTX) { + (*outputFunc)(outputStream, newHHEATab, newTables[i].len); + } else if (newTables[i].tag == hmtxTag && abbrevHMTX) { + (*outputFunc)(outputStream, newHMTXTab, newTables[i].len); + } else if (newTables[i].tag == locaTag && unsortedLoca) { + for (j = 0; j <= nGlyphs; ++j) { + if (locaFmt) { + locaBuf[0] = (char)(locaTable[j].newOffset >> 24); + locaBuf[1] = (char)(locaTable[j].newOffset >> 16); + locaBuf[2] = (char)(locaTable[j].newOffset >> 8); + locaBuf[3] = (char) locaTable[j].newOffset; + (*outputFunc)(outputStream, locaBuf, 4); + } else { + locaBuf[0] = (char)(locaTable[j].newOffset >> 9); + locaBuf[1] = (char)(locaTable[j].newOffset >> 1); + (*outputFunc)(outputStream, locaBuf, 2); + } + } + } else if (newTables[i].tag == glyfTag && unsortedLoca) { + pos = tables[seekTable("glyf")].offset; + for (j = 0; j < nGlyphs; ++j) { + n = locaTable[j].len; + if (n > 0) { + k = locaTable[j].origOffset; + if (checkRegion(pos + k, n)) { + (*outputFunc)(outputStream, (char *)file + pos + k, n); + } else { + for (k = 0; k < n; ++k) { + (*outputFunc)(outputStream, "\0", 1); + } + } + if ((k = locaTable[j].len & 3)) { + (*outputFunc)(outputStream, "\0\0\0\0", 4 - k); + } + } + } + } else { + if (checkRegion(newTables[i].origOffset, newTables[i].len)) { + (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, + newTables[i].len); + } else { + for (j = 0; j < newTables[i].len; ++j) { + (*outputFunc)(outputStream, "\0", 1); + } + } + } + if (newTables[i].len & 3) { + (*outputFunc)(outputStream, "\0\0\0", 4 - (newTables[i].len & 3)); + } + } + + gfree(newHMTXTab); + gfree(newHHEATab); + gfree(newCmapTab); + gfree(newNameTab); + gfree(tableDir); + gfree(newTables); + done1: + gfree(locaTable); +} + +void FoFiTrueType::cvtEncoding(char **encoding, + FoFiOutputFunc outputFunc, + void *outputStream) { + char *name; + GString *buf; + int i; + + (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); + if (encoding) { + for (i = 0; i < 256; ++i) { + if (!(name = encoding[i])) { + name = ".notdef"; + } + buf = GString::format("dup {0:d} /", i); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, name, strlen(name)); + (*outputFunc)(outputStream, " put\n", 5); + } + } else { + for (i = 0; i < 256; ++i) { + buf = GString::format("dup {0:d} /c{1:02x} put\n", i, i); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + } + (*outputFunc)(outputStream, "readonly def\n", 13); +} + +void FoFiTrueType::cvtCharStrings(char **encoding, + Gushort *codeToGID, + FoFiOutputFunc outputFunc, + void *outputStream) { + char *name; + GString *buf; + char buf2[16]; + int i, k; + + // always define '.notdef' + (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32); + (*outputFunc)(outputStream, "/.notdef 0 def\n", 15); + + // if there's no 'cmap' table, punt + if (nCmaps == 0) { + goto err; + } + + // map char name to glyph index: + // 1. use encoding to map name to char code + // 2. use codeToGID to map char code to glyph index + // N.B. We do this in reverse order because font subsets can have + // weird encodings that use the same character name twice, and + // the first definition is probably the one we want. + k = 0; // make gcc happy + for (i = 255; i >= 0; --i) { + if (encoding) { + name = encoding[i]; + } else { + sprintf(buf2, "c%02x", i); + name = buf2; + } + if (name && strcmp(name, ".notdef")) { + k = codeToGID[i]; + // note: Distiller (maybe Adobe's PS interpreter in general) + // doesn't like TrueType fonts that have CharStrings entries + // which point to nonexistent glyphs, hence the (k < nGlyphs) + // test + if (k > 0 && k < nGlyphs) { + (*outputFunc)(outputStream, "/", 1); + (*outputFunc)(outputStream, name, strlen(name)); + buf = GString::format(" {0:d} def\n", k); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + } + } + + err: + (*outputFunc)(outputStream, "end readonly def\n", 17); +} + +void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, + void *outputStream, GString *name, + GBool needVerticalMetrics) { + Guchar headData[54]; + TrueTypeLoca *locaTable; + Guchar *locaData; + TrueTypeTable newTables[nT42Tables]; + Guchar tableDir[12 + nT42Tables*16]; + GBool ok; + Guint checksum; + int nNewTables; + int length, pos, glyfPos, i, j, k; + Guchar vheaTab[36] = { + 0, 1, 0, 0, // table version number + 0, 0, // ascent + 0, 0, // descent + 0, 0, // reserved + 0, 0, // max advance height + 0, 0, // min top side bearing + 0, 0, // min bottom side bearing + 0, 0, // y max extent + 0, 0, // caret slope rise + 0, 1, // caret slope run + 0, 0, // caret offset + 0, 0, // reserved + 0, 0, // reserved + 0, 0, // reserved + 0, 0, // reserved + 0, 0, // metric data format + 0, 1 // number of advance heights in vmtx table + }; + Guchar *vmtxTab; + GBool needVhea, needVmtx; + int advance; + + // construct the 'head' table, zero out the font checksum + i = seekTable("head"); + pos = tables[i].offset; + if (!checkRegion(pos, 54)) { + return; + } + memcpy(headData, file + pos, 54); + headData[8] = headData[9] = headData[10] = headData[11] = (Guchar)0; + + // read the original 'loca' table, pad entries out to 4 bytes, and + // sort it into proper order -- some (non-compliant) fonts have + // out-of-order loca tables; in order to correctly handle the case + // where (compliant) fonts have empty entries in the middle of the + // table, cmpTrueTypeLocaPos uses offset as its primary sort key, + // and idx as its secondary key (ensuring that adjacent entries with + // the same pos value remain in the same order) + locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca)); + i = seekTable("loca"); + pos = tables[i].offset; + ok = gTrue; + for (i = 0; i <= nGlyphs; ++i) { + locaTable[i].idx = i; + if (locaFmt) { + locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok); + } else { + locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok); + } + } + qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), + &cmpTrueTypeLocaOffset); + for (i = 0; i < nGlyphs; ++i) { + locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset; + } + locaTable[nGlyphs].len = 0; + qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), + &cmpTrueTypeLocaIdx); + pos = 0; + for (i = 0; i <= nGlyphs; ++i) { + locaTable[i].newOffset = pos; + pos += locaTable[i].len; + if (pos & 3) { + pos += 4 - (pos & 3); + } + } + + // construct the new 'loca' table + locaData = (Guchar *)gmallocn(nGlyphs + 1, (locaFmt ? 4 : 2)); + for (i = 0; i <= nGlyphs; ++i) { + pos = locaTable[i].newOffset; + if (locaFmt) { + locaData[4*i ] = (Guchar)(pos >> 24); + locaData[4*i+1] = (Guchar)(pos >> 16); + locaData[4*i+2] = (Guchar)(pos >> 8); + locaData[4*i+3] = (Guchar) pos; + } else { + locaData[2*i ] = (Guchar)(pos >> 9); + locaData[2*i+1] = (Guchar)(pos >> 1); + } + } + + // count the number of tables + nNewTables = 0; + for (i = 0; i < nT42Tables; ++i) { + if (t42Tables[i].required || + seekTable(t42Tables[i].tag) >= 0) { + ++nNewTables; + } + } + vmtxTab = NULL; // make gcc happy + advance = 0; // make gcc happy + if (needVerticalMetrics) { + needVhea = seekTable("vhea") < 0; + needVmtx = seekTable("vmtx") < 0; + if (needVhea || needVmtx) { + i = seekTable("head"); + advance = getU16BE(tables[i].offset + 18, &ok); // units per em + if (needVhea) { + ++nNewTables; + } + if (needVmtx) { + ++nNewTables; + } + } + } + + // construct the new table headers, including table checksums + // (pad each table out to a multiple of 4 bytes) + pos = 12 + nNewTables*16; + k = 0; + for (i = 0; i < nT42Tables; ++i) { + length = -1; + checksum = 0; // make gcc happy + if (i == t42HeadTable) { + length = 54; + checksum = computeTableChecksum(headData, 54); + } else if (i == t42LocaTable) { + length = (nGlyphs + 1) * (locaFmt ? 4 : 2); + checksum = computeTableChecksum(locaData, length); + } else if (i == t42GlyfTable) { + length = 0; + checksum = 0; + glyfPos = tables[seekTable("glyf")].offset; + for (j = 0; j < nGlyphs; ++j) { + length += locaTable[j].len; + if (length & 3) { + length += 4 - (length & 3); + } + if (checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) { + checksum += + computeTableChecksum(file + glyfPos + locaTable[j].origOffset, + locaTable[j].len); + } + } + } else { + if ((j = seekTable(t42Tables[i].tag)) >= 0) { + length = tables[j].len; + if (checkRegion(tables[j].offset, length)) { + checksum = computeTableChecksum(file + tables[j].offset, length); + } + } else if (needVerticalMetrics && i == t42VheaTable) { + vheaTab[10] = advance / 256; // max advance height + vheaTab[11] = advance % 256; + length = sizeof(vheaTab); + checksum = computeTableChecksum(vheaTab, length); + } else if (needVerticalMetrics && i == t42VmtxTable) { + length = 4 + (nGlyphs - 1) * 4; + vmtxTab = (Guchar *)gmalloc(length); + vmtxTab[0] = advance / 256; + vmtxTab[1] = advance % 256; + for (j = 2; j < length; j += 2) { + vmtxTab[j] = 0; + vmtxTab[j+1] = 0; + } + checksum = computeTableChecksum(vmtxTab, length); + } else if (t42Tables[i].required) { + //~ error(-1, "Embedded TrueType font is missing a required table ('%s')", + //~ t42Tables[i].tag); + length = 0; + checksum = 0; + } + } + if (length >= 0) { + newTables[k].tag = ((t42Tables[i].tag[0] & 0xff) << 24) | + ((t42Tables[i].tag[1] & 0xff) << 16) | + ((t42Tables[i].tag[2] & 0xff) << 8) | + (t42Tables[i].tag[3] & 0xff); + newTables[k].checksum = checksum; + newTables[k].offset = pos; + newTables[k].len = length; + pos += length; + if (pos & 3) { + pos += 4 - (length & 3); + } + ++k; + } + } + + // construct the table directory + tableDir[0] = 0x00; // sfnt version + tableDir[1] = 0x01; + tableDir[2] = 0x00; + tableDir[3] = 0x00; + tableDir[4] = 0; // numTables + tableDir[5] = nNewTables; + tableDir[6] = 0; // searchRange + tableDir[7] = (Guchar)128; + tableDir[8] = 0; // entrySelector + tableDir[9] = 3; + tableDir[10] = 0; // rangeShift + tableDir[11] = (Guchar)(16 * nNewTables - 128); + pos = 12; + for (i = 0; i < nNewTables; ++i) { + tableDir[pos ] = (Guchar)(newTables[i].tag >> 24); + tableDir[pos+ 1] = (Guchar)(newTables[i].tag >> 16); + tableDir[pos+ 2] = (Guchar)(newTables[i].tag >> 8); + tableDir[pos+ 3] = (Guchar) newTables[i].tag; + tableDir[pos+ 4] = (Guchar)(newTables[i].checksum >> 24); + tableDir[pos+ 5] = (Guchar)(newTables[i].checksum >> 16); + tableDir[pos+ 6] = (Guchar)(newTables[i].checksum >> 8); + tableDir[pos+ 7] = (Guchar) newTables[i].checksum; + tableDir[pos+ 8] = (Guchar)(newTables[i].offset >> 24); + tableDir[pos+ 9] = (Guchar)(newTables[i].offset >> 16); + tableDir[pos+10] = (Guchar)(newTables[i].offset >> 8); + tableDir[pos+11] = (Guchar) newTables[i].offset; + tableDir[pos+12] = (Guchar)(newTables[i].len >> 24); + tableDir[pos+13] = (Guchar)(newTables[i].len >> 16); + tableDir[pos+14] = (Guchar)(newTables[i].len >> 8); + tableDir[pos+15] = (Guchar) newTables[i].len; + pos += 16; + } + + // compute the font checksum and store it in the head table + checksum = computeTableChecksum(tableDir, 12 + nNewTables*16); + for (i = 0; i < nNewTables; ++i) { + checksum += newTables[i].checksum; + } + checksum = 0xb1b0afba - checksum; // because the TrueType spec says so + headData[ 8] = (Guchar)(checksum >> 24); + headData[ 9] = (Guchar)(checksum >> 16); + headData[10] = (Guchar)(checksum >> 8); + headData[11] = (Guchar) checksum; + + // start the sfnts array + if (name) { + (*outputFunc)(outputStream, "/", 1); + (*outputFunc)(outputStream, name->getCString(), name->getLength()); + (*outputFunc)(outputStream, " [\n", 3); + } else { + (*outputFunc)(outputStream, "/sfnts [\n", 9); + } + + // write the table directory + dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream); + + // write the tables + for (i = 0; i < nNewTables; ++i) { + if (i == t42HeadTable) { + dumpString(headData, 54, outputFunc, outputStream); + } else if (i == t42LocaTable) { + length = (nGlyphs + 1) * (locaFmt ? 4 : 2); + dumpString(locaData, length, outputFunc, outputStream); + } else if (i == t42GlyfTable) { + glyfPos = tables[seekTable("glyf")].offset; + for (j = 0; j < nGlyphs; ++j) { + if (locaTable[j].len > 0 && + checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) { + dumpString(file + glyfPos + locaTable[j].origOffset, + locaTable[j].len, outputFunc, outputStream); + } + } + } else { + // length == 0 means the table is missing and the error was + // already reported during the construction of the table + // headers + if ((length = newTables[i].len) > 0) { + if ((j = seekTable(t42Tables[i].tag)) >= 0 && + checkRegion(tables[j].offset, tables[j].len)) { + dumpString(file + tables[j].offset, tables[j].len, + outputFunc, outputStream); + } else if (needVerticalMetrics && i == t42VheaTable) { + dumpString(vheaTab, length, outputFunc, outputStream); + } else if (needVerticalMetrics && i == t42VmtxTable) { + dumpString(vmtxTab, length, outputFunc, outputStream); + gfree(vmtxTab); + } + } + } + } + + // end the sfnts array + (*outputFunc)(outputStream, "] def\n", 6); + + gfree(locaData); + gfree(locaTable); +} + +void FoFiTrueType::dumpString(Guchar *s, int length, + FoFiOutputFunc outputFunc, + void *outputStream) { + GString *buf; + int pad, i, j; + + (*outputFunc)(outputStream, "<", 1); + for (i = 0; i < length; i += 32) { + for (j = 0; j < 32 && i+j < length; ++j) { + buf = GString::format("{0:02x}", s[i+j] & 0xff); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (i % (65536 - 32) == 65536 - 64) { + (*outputFunc)(outputStream, ">\n<", 3); + } else if (i+32 < length) { + (*outputFunc)(outputStream, "\n", 1); + } + } + if (length & 3) { + pad = 4 - (length & 3); + for (i = 0; i < pad; ++i) { + (*outputFunc)(outputStream, "00", 2); + } + } + // add an extra zero byte because the Adobe Type 42 spec says so + (*outputFunc)(outputStream, "00>\n", 4); +} + +Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) { + Guint checksum, word; + int i; + + checksum = 0; + for (i = 0; i+3 < length; i += 4) { + word = ((data[i ] & 0xff) << 24) + + ((data[i+1] & 0xff) << 16) + + ((data[i+2] & 0xff) << 8) + + (data[i+3] & 0xff); + checksum += word; + } + if (length & 3) { + word = 0; + i = length & ~3; + switch (length & 3) { + case 3: + word |= (data[i+2] & 0xff) << 8; + case 2: + word |= (data[i+1] & 0xff) << 16; + case 1: + word |= (data[i ] & 0xff) << 24; + break; + } + checksum += word; + } + return checksum; +} + +void FoFiTrueType::parse() { + Guint topTag; + int pos, ver, i, j; + + parsedOk = gTrue; + + // look for a collection (TTC) + topTag = getU32BE(0, &parsedOk); + if (!parsedOk) { + return; + } + if (topTag == ttcfTag) { + /* TTC font */ + int dircount; + + dircount = getU32BE(8, &parsedOk); + if (!parsedOk) + return; + if (! dircount) { + parsedOk = gFalse; + return; + } + + if (faceIndex >= dircount) + faceIndex = 0; + pos = getU32BE(12 + faceIndex * 4, &parsedOk); + if (! parsedOk) + return; + } else { + pos = 0; + } + + // check the sfnt version + ver = getU32BE(pos, &parsedOk); + if (!parsedOk) { + return; + } + openTypeCFF = ver == 0x4f54544f; // 'OTTO' + + // read the table directory + nTables = getU16BE(pos + 4, &parsedOk); + if (!parsedOk) { + return; + } + tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable)); + pos += 12; + for (i = 0; i < nTables; ++i) { + tables[i].tag = getU32BE(pos, &parsedOk); + tables[i].checksum = getU32BE(pos + 4, &parsedOk); + tables[i].offset = (int)getU32BE(pos + 8, &parsedOk); + tables[i].len = (int)getU32BE(pos + 12, &parsedOk); + if (tables[i].offset + tables[i].len < tables[i].offset || + tables[i].offset + tables[i].len > len) { + parsedOk = gFalse; + } + pos += 16; + } + if (!parsedOk) { + return; + } + + // check for tables that are required by both the TrueType spec and + // the Type 42 spec + if (seekTable("head") < 0 || + seekTable("hhea") < 0 || + seekTable("maxp") < 0 || + seekTable("hmtx") < 0 || + (!openTypeCFF && seekTable("loca") < 0) || + (!openTypeCFF && seekTable("glyf") < 0) || + (openTypeCFF && seekTable("CFF ") < 0)) { + parsedOk = gFalse; + return; + } + + // read the cmaps + if ((i = seekTable("cmap")) >= 0) { + pos = tables[i].offset + 2; + nCmaps = getU16BE(pos, &parsedOk); + pos += 2; + if (!parsedOk) { + return; + } + cmaps = (TrueTypeCmap *)gmallocn(nCmaps, sizeof(TrueTypeCmap)); + for (j = 0; j < nCmaps; ++j) { + cmaps[j].platform = getU16BE(pos, &parsedOk); + cmaps[j].encoding = getU16BE(pos + 2, &parsedOk); + cmaps[j].offset = tables[i].offset + getU32BE(pos + 4, &parsedOk); + pos += 8; + cmaps[j].fmt = getU16BE(cmaps[j].offset, &parsedOk); + cmaps[j].len = getU16BE(cmaps[j].offset + 2, &parsedOk); + } + if (!parsedOk) { + return; + } + } else { + nCmaps = 0; + } + + // get the number of glyphs from the maxp table + i = seekTable("maxp"); + nGlyphs = getU16BE(tables[i].offset + 4, &parsedOk); + if (!parsedOk) { + return; + } + + // get the bbox and loca table format from the head table + i = seekTable("head"); + bbox[0] = getS16BE(tables[i].offset + 36, &parsedOk); + bbox[1] = getS16BE(tables[i].offset + 38, &parsedOk); + bbox[2] = getS16BE(tables[i].offset + 40, &parsedOk); + bbox[3] = getS16BE(tables[i].offset + 42, &parsedOk); + locaFmt = getS16BE(tables[i].offset + 50, &parsedOk); + if (!parsedOk) { + return; + } + + // make sure the loca table is sane (correct length and entries are + // in bounds) + if (!openTypeCFF) { + i = seekTable("loca"); + if (tables[i].len < 0) { + parsedOk = gFalse; + return; + } + if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) { + nGlyphs = tables[i].len / (locaFmt ? 4 : 2) - 1; + } + for (j = 0; j <= nGlyphs; ++j) { + if (locaFmt) { + pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk); + } else { + pos = getU16BE(tables[i].offset + j*2, &parsedOk); + } + if (pos < 0 || pos > len) { + parsedOk = gFalse; + } + } + if (!parsedOk) { + return; + } + } + + // read the post table + readPostTable(); +} + +void FoFiTrueType::readPostTable() { + GString *name; + int tablePos, postFmt, stringIdx, stringPos; + GBool ok; + int i, j, n, m; + + ok = gTrue; + if ((i = seekTable("post")) < 0) { + return; + } + tablePos = tables[i].offset; + postFmt = getU32BE(tablePos, &ok); + if (!ok) { + goto err; + } + if (postFmt == 0x00010000) { + nameToGID = new GHash(gTrue); + for (i = 0; i < 258; ++i) { + nameToGID->add(new GString(macGlyphNames[i]), i); + } + } else if (postFmt == 0x00020000) { + nameToGID = new GHash(gTrue); + n = getU16BE(tablePos + 32, &ok); + if (!ok) { + goto err; + } + if (n > nGlyphs) { + n = nGlyphs; + } + stringIdx = 0; + stringPos = tablePos + 34 + 2*n; + for (i = 0; i < n; ++i) { + j = getU16BE(tablePos + 34 + 2*i, &ok); + if (j < 258) { + nameToGID->removeInt(macGlyphNames[j]); + nameToGID->add(new GString(macGlyphNames[j]), i); + } else { + j -= 258; + if (j != stringIdx) { + for (stringIdx = 0, stringPos = tablePos + 34 + 2*n; + stringIdx < j; + ++stringIdx, stringPos += 1 + getU8(stringPos, &ok)) ; + if (!ok) { + goto err; + } + } + m = getU8(stringPos, &ok); + if (!ok || !checkRegion(stringPos + 1, m)) { + goto err; + } + name = new GString((char *)&file[stringPos + 1], m); + nameToGID->removeInt(name); + nameToGID->add(name, i); + ++stringIdx; + stringPos += 1 + m; + } + } + } else if (postFmt == 0x00028000) { + nameToGID = new GHash(gTrue); + for (i = 0; i < nGlyphs; ++i) { + j = getU8(tablePos + 32 + i, &ok); + if (!ok) { + goto err; + } + if (j < 258) { + nameToGID->removeInt(macGlyphNames[j]); + nameToGID->add(new GString(macGlyphNames[j]), i); + } + } + } + + return; + + err: + if (nameToGID) { + delete nameToGID; + nameToGID = NULL; + } +} + +int FoFiTrueType::seekTable(char *tag) { + Guint tagI; + int i; + + tagI = ((tag[0] & 0xff) << 24) | + ((tag[1] & 0xff) << 16) | + ((tag[2] & 0xff) << 8) | + (tag[3] & 0xff); + for (i = 0; i < nTables; ++i) { + if (tables[i].tag == tagI) { + return i; + } + } + return -1; +} diff --git a/kpdf/xpdf/fofi/FoFiTrueType.h b/kpdf/xpdf/fofi/FoFiTrueType.h new file mode 100644 index 00000000..eadf5c9f --- /dev/null +++ b/kpdf/xpdf/fofi/FoFiTrueType.h @@ -0,0 +1,175 @@ +//======================================================================== +// +// FoFiTrueType.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFITRUETYPE_H +#define FOFITRUETYPE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "FoFiBase.h" + +class GString; +class GHash; +struct TrueTypeTable; +struct TrueTypeCmap; + +//------------------------------------------------------------------------ +// FoFiTrueType +//------------------------------------------------------------------------ + +class FoFiTrueType: public FoFiBase { +public: + + // Create a FoFiTrueType object from a memory buffer. + static FoFiTrueType *make(char *fileA, int lenA, int faceIndexA=0); + + // Create a FoFiTrueType object from a file on disk. + static FoFiTrueType *load(char *fileName, int faceIndexA=0); + + virtual ~FoFiTrueType(); + + // Returns true if this an OpenType font containing CFF data, false + // if it's a TrueType font (or OpenType font with TrueType data). + GBool isOpenTypeCFF() { return openTypeCFF; } + + // Return the number of cmaps defined by this font. + int getNumCmaps(); + + // Return the platform ID of the th cmap. + int getCmapPlatform(int i); + + // Return the encoding ID of the th cmap. + int getCmapEncoding(int i); + + // Return the index of the cmap for , . Returns + // -1 if there is no corresponding cmap. + int findCmap(int platform, int encoding); + + // Return the GID corresponding to according to the th cmap. + Gushort mapCodeToGID(int i, int c); + + // Returns the GID corresponding to according to the post + // table. Returns 0 if there is no mapping for or if the + // font does not have a post table. + int mapNameToGID(char *name); + + // Return the mapping from CIDs to GIDs, and return the number of + // CIDs in *. This is only useful for CID fonts. (Only + // useful for OpenType CFF fonts.) + Gushort *getCIDToGIDMap(int *nCIDs); + + // Returns the least restrictive embedding licensing right (as + // defined by the TrueType spec): + // * 4: OS/2 table is missing or invalid + // * 3: installable embedding + // * 2: editable embedding + // * 1: preview & print embedding + // * 0: restricted license embedding + int getEmbeddingRights(); + + // Convert to a Type 42 font, suitable for embedding in a PostScript + // file. will be used as the PostScript font name (so we + // don't need to depend on the 'name' table in the font). The + // array specifies the mapping from char codes to names. + // If is NULL, the encoding is unknown or undefined. The + // array specifies the mapping from char codes to GIDs. + // (Not useful for OpenType CFF fonts.) + void convertToType42(char *psName, char **encoding, + Gushort *codeToGID, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 1 font, suitable for embedding in a PostScript + // file. This is only useful with 8-bit fonts. If is + // not NULL, it will be used in place of the encoding in the Type 1C + // font. If is true the eexec section will be hex-encoded, + // otherwise it will be left as binary data. If is + // non-NULL, it will be used as the PostScript font name. (Only + // useful for OpenType CFF fonts.) + void convertToType1(char *psName, char **newEncoding, GBool ascii, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 2 CIDFont, suitable for embedding in a + // PostScript file. will be used as the PostScript font + // name (so we don't need to depend on the 'name' table in the + // font). The array maps CIDs to GIDs; it has + // entries. (Not useful for OpenType CFF fonts.) + void convertToCIDType2(char *psName, Gushort *cidMap, int nCIDs, + GBool needVerticalMetrics, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 0 CIDFont, suitable for embedding in a + // PostScript file. will be used as the PostScript font + // name. (Only useful for OpenType CFF fonts.) + void convertToCIDType0(char *psName, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 0 (but non-CID) composite font, suitable for + // embedding in a PostScript file. will be used as the + // PostScript font name (so we don't need to depend on the 'name' + // table in the font). The array maps CIDs to GIDs; it has + // entries. (Not useful for OpenType CFF fonts.) + void convertToType0(char *psName, Gushort *cidMap, int nCIDs, + GBool needVerticalMetrics, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 0 (but non-CID) composite font, suitable for + // embedding in a PostScript file. will be used as the + // PostScript font name. (Only useful for OpenType CFF fonts.) + void convertToType0(char *psName, + FoFiOutputFunc outputFunc, void *outputStream); + + // Write a clean TTF file, filling in missing tables and correcting + // various other errors. If is non-NULL, the font is renamed + // to . If is non-NULL, the font is re-encoded, + // using a Windows Unicode cmap. If is NULL and the font is + // complete and correct, it will be written unmodified. (Not useful + // for OpenType CFF fonts.) + void writeTTF(FoFiOutputFunc outputFunc, void *outputStream, + char *name = NULL, Gushort *codeToGID = NULL); + +private: + + FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceIndexA); + void cvtEncoding(char **encoding, + FoFiOutputFunc outputFunc, + void *outputStream); + void cvtCharStrings(char **encoding, + Gushort *codeToGID, + FoFiOutputFunc outputFunc, + void *outputStream); + void cvtSfnts(FoFiOutputFunc outputFunc, + void *outputStream, GString *name, + GBool needVerticalMetrics); + void dumpString(Guchar *s, int length, + FoFiOutputFunc outputFunc, + void *outputStream); + Guint computeTableChecksum(Guchar *data, int length); + void parse(); + void readPostTable(); + int seekTable(char *tag); + + TrueTypeTable *tables; + int nTables; + TrueTypeCmap *cmaps; + int nCmaps; + int nGlyphs; + int locaFmt; + int bbox[4]; + GHash *nameToGID; + GBool openTypeCFF; + + GBool parsedOk; + int faceIndex; +}; + +#endif diff --git a/kpdf/xpdf/fofi/FoFiType1.cc b/kpdf/xpdf/fofi/FoFiType1.cc new file mode 100644 index 00000000..efad5ee4 --- /dev/null +++ b/kpdf/xpdf/fofi/FoFiType1.cc @@ -0,0 +1,252 @@ +//======================================================================== +// +// FoFiType1.cc +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "FoFiEncodings.h" +#include "FoFiType1.h" + +//------------------------------------------------------------------------ +// FoFiType1 +//------------------------------------------------------------------------ + +FoFiType1 *FoFiType1::make(char *fileA, int lenA) { + return new FoFiType1(fileA, lenA, gFalse); +} + +FoFiType1 *FoFiType1::load(char *fileName) { + char *fileA; + int lenA; + + if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { + return NULL; + } + return new FoFiType1(fileA, lenA, gTrue); +} + +FoFiType1::FoFiType1(char *fileA, int lenA, GBool freeFileDataA): + FoFiBase(fileA, lenA, freeFileDataA) +{ + name = NULL; + encoding = NULL; + parsed = gFalse; +} + +FoFiType1::~FoFiType1() { + int i; + + if (name) { + gfree(name); + } + if (encoding && encoding != fofiType1StandardEncoding) { + for (i = 0; i < 256; ++i) { + gfree(encoding[i]); + } + gfree(encoding); + } +} + +char *FoFiType1::getName() { + if (!parsed) { + parse(); + } + return name; +} + +char **FoFiType1::getEncoding() { + if (!parsed) { + parse(); + } + return encoding; +} + +void FoFiType1::writeEncoded(char **newEncoding, + FoFiOutputFunc outputFunc, void *outputStream) { + char buf[512]; + char *line, *line2, *p; + int i; + + // copy everything up to the encoding + for (line = (char *)file; + line && strncmp(line, "/Encoding", 9); + line = getNextLine(line)) ; + if (!line) { + // no encoding - just copy the whole font file + (*outputFunc)(outputStream, (char *)file, len); + return; + } + (*outputFunc)(outputStream, (char *)file, line - (char *)file); + + // write the new encoding + (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); + (*outputFunc)(outputStream, + "0 1 255 {1 index exch /.notdef put} for\n", 40); + for (i = 0; i < 256; ++i) { + if (newEncoding[i]) { + sprintf(buf, "dup %d /%s put\n", i, newEncoding[i]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + } + (*outputFunc)(outputStream, "readonly def\n", 13); + + // find the end of the encoding data + //~ this ought to parse PostScript tokens + if (!strncmp(line, "/Encoding StandardEncoding def", 30)) { + line = getNextLine(line); + } else { + // skip "/Encoding" + one whitespace char, + // then look for 'def' preceded by PostScript whitespace + p = line + 10; + line = NULL; + for (; p < (char *)file + len; ++p) { + if ((*p == ' ' || *p == '\t' || *p == '\x0a' || + *p == '\x0d' || *p == '\x0c' || *p == '\0') && + p + 4 <= (char *)file + len && + !strncmp(p + 1, "def", 3)) { + line = p + 4; + break; + } + } + } + + // some fonts have two /Encoding entries in their dictionary, so we + // check for a second one here + if (line) { + for (line2 = line, i = 0; + i < 20 && line2 && strncmp(line2, "/Encoding", 9); + line2 = getNextLine(line2), ++i) ; + if (i < 20 && line2) { + (*outputFunc)(outputStream, line, line2 - line); + if (!strncmp(line2, "/Encoding StandardEncoding def", 30)) { + line = getNextLine(line2); + } else { + // skip "/Encoding" + one whitespace char, + // then look for 'def' preceded by PostScript whitespace + p = line2 + 10; + line = NULL; + for (; p < (char *)file + len; ++p) { + if ((*p == ' ' || *p == '\t' || *p == '\x0a' || + *p == '\x0d' || *p == '\x0c' || *p == '\0') && + p + 4 <= (char *)file + len && + !strncmp(p + 1, "def", 3)) { + line = p + 4; + break; + } + } + } + } + + // copy everything after the encoding + if (line) { + (*outputFunc)(outputStream, line, ((char *)file + len) - line); + } + } +} + +char *FoFiType1::getNextLine(char *line) { + while (line < (char *)file + len && *line != '\x0a' && *line != '\x0d') { + ++line; + } + if (line < (char *)file + len && *line == '\x0d') { + ++line; + } + if (line < (char *)file + len && *line == '\x0a') { + ++line; + } + if (line >= (char *)file + len) { + return NULL; + } + return line; +} + +void FoFiType1::parse() { + char *line, *line1, *p, *p2; + char buf[256]; + char c; + int n, code, i, j; + + for (i = 1, line = (char *)file; + i <= 100 && line && (!name || !encoding); + ++i) { + + // get font name + if (!name && !strncmp(line, "/FontName", 9)) { + strncpy(buf, line, 255); + buf[255] = '\0'; + if ((p = strchr(buf+9, '/')) && + (p = strtok(p+1, " \t\n\r"))) { + name = copyString(p); + } + line = getNextLine(line); + + // get encoding + } else if (!encoding && + !strncmp(line, "/Encoding StandardEncoding def", 30)) { + encoding = fofiType1StandardEncoding; + } else if (!encoding && + !strncmp(line, "/Encoding 256 array", 19)) { + encoding = (char **)gmallocn(256, sizeof(char *)); + for (j = 0; j < 256; ++j) { + encoding[j] = NULL; + } + for (j = 0, line = getNextLine(line); + j < 300 && line && (line1 = getNextLine(line)); + ++j, line = line1) { + if ((n = line1 - line) > 255) { + n = 255; + } + strncpy(buf, line, n); + buf[n] = '\0'; + for (p = buf; *p == ' ' || *p == '\t'; ++p) ; + if (!strncmp(p, "dup", 3)) { + for (p += 3; *p == ' ' || *p == '\t'; ++p) ; + for (p2 = p; *p2 >= '0' && *p2 <= '9'; ++p2) ; + if (*p2) { + c = *p2; + *p2 = '\0'; + code = atoi(p); + *p2 = c; + if (code == 8 && *p2 == '#') { + code = 0; + for (++p2; *p2 >= '0' && *p2 <= '7'; ++p2) { + code = code * 8 + (*p2 - '0'); + } + } + if (code < 256) { + for (p = p2; *p == ' ' || *p == '\t'; ++p) ; + if (*p == '/') { + ++p; + for (p2 = p; *p2 && *p2 != ' ' && *p2 != '\t'; ++p2) ; + *p2 = '\0'; + encoding[code] = copyString(p); + } + } + } + } else { + if (strtok(buf, " \t") && + (p = strtok(NULL, " \t\n\r")) && !strcmp(p, "def")) { + break; + } + } + } + //~ check for getinterval/putinterval junk + + } else { + line = getNextLine(line); + } + } + + parsed = gTrue; +} diff --git a/kpdf/xpdf/fofi/FoFiType1.h b/kpdf/xpdf/fofi/FoFiType1.h new file mode 100644 index 00000000..843352b2 --- /dev/null +++ b/kpdf/xpdf/fofi/FoFiType1.h @@ -0,0 +1,59 @@ +//======================================================================== +// +// FoFiType1.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFITYPE1_H +#define FOFITYPE1_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "FoFiBase.h" + +//------------------------------------------------------------------------ +// FoFiType1 +//------------------------------------------------------------------------ + +class FoFiType1: public FoFiBase { +public: + + // Create a FoFiType1 object from a memory buffer. + static FoFiType1 *make(char *fileA, int lenA); + + // Create a FoFiType1 object from a file on disk. + static FoFiType1 *load(char *fileName); + + virtual ~FoFiType1(); + + // Return the font name. + char *getName(); + + // Return the encoding, as an array of 256 names (any of which may + // be NULL). + char **getEncoding(); + + // Write a version of the Type 1 font file with a new encoding. + void writeEncoded(char **newEncoding, + FoFiOutputFunc outputFunc, void *outputStream); + +private: + + FoFiType1(char *fileA, int lenA, GBool freeFileDataA); + + char *getNextLine(char *line); + void parse(); + + char *name; + char **encoding; + GBool parsed; +}; + +#endif diff --git a/kpdf/xpdf/fofi/FoFiType1C.cc b/kpdf/xpdf/fofi/FoFiType1C.cc new file mode 100644 index 00000000..3b28f321 --- /dev/null +++ b/kpdf/xpdf/fofi/FoFiType1C.cc @@ -0,0 +1,2603 @@ +//======================================================================== +// +// FoFiType1C.cc +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include "gmem.h" +#include "GString.h" +#include "FoFiEncodings.h" +#include "FoFiType1C.h" + +//------------------------------------------------------------------------ + +static char hexChars[17] = "0123456789ABCDEF"; + +//------------------------------------------------------------------------ +// FoFiType1C +//------------------------------------------------------------------------ + +FoFiType1C *FoFiType1C::make(char *fileA, int lenA) { + FoFiType1C *ff; + + ff = new FoFiType1C(fileA, lenA, gFalse); + if (!ff->parse()) { + delete ff; + return NULL; + } + return ff; +} + +FoFiType1C *FoFiType1C::load(char *fileName) { + FoFiType1C *ff; + char *fileA; + int lenA; + + if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { + return NULL; + } + ff = new FoFiType1C(fileA, lenA, gTrue); + if (!ff->parse()) { + delete ff; + return NULL; + } + return ff; +} + +FoFiType1C::FoFiType1C(char *fileA, int lenA, GBool freeFileDataA): + FoFiBase(fileA, lenA, freeFileDataA) +{ + name = NULL; + encoding = NULL; + privateDicts = NULL; + fdSelect = NULL; + charset = NULL; +} + +FoFiType1C::~FoFiType1C() { + int i; + + if (name) { + delete name; + } + if (encoding && + encoding != fofiType1StandardEncoding && + encoding != fofiType1ExpertEncoding) { + for (i = 0; i < 256; ++i) { + gfree(encoding[i]); + } + gfree(encoding); + } + if (privateDicts) { + gfree(privateDicts); + } + if (fdSelect) { + gfree(fdSelect); + } + if (charset && + charset != fofiType1CISOAdobeCharset && + charset != fofiType1CExpertCharset && + charset != fofiType1CExpertSubsetCharset) { + gfree(charset); + } +} + +char *FoFiType1C::getName() { + return name ? name->getCString() : (char *)NULL; +} + +char **FoFiType1C::getEncoding() { + return encoding; +} + +Gushort *FoFiType1C::getCIDToGIDMap(int *nCIDs) { + Gushort *map; + int n, i; + + // a CID font's top dict has ROS as the first operator + if (topDict.firstOp != 0x0c1e) { + *nCIDs = 0; + return NULL; + } + + // in a CID font, the charset data is the GID-to-CID mapping, so all + // we have to do is reverse it + n = 0; + for (i = 0; i < nGlyphs; ++i) { + if (charset[i] > n) { + n = charset[i]; + } + } + ++n; + map = (Gushort *)gmallocn(n, sizeof(Gushort)); + memset(map, 0, n * sizeof(Gushort)); + for (i = 0; i < nGlyphs; ++i) { + map[charset[i]] = i; + } + *nCIDs = n; + return map; +} + +void FoFiType1C::convertToType1(char *psName, char **newEncoding, GBool ascii, + FoFiOutputFunc outputFunc, + void *outputStream) { + int psNameLen; + Type1CEexecBuf eb; + Type1CIndex subrIdx; + Type1CIndexVal val; + GString *buf; + char buf2[256]; + char **enc; + GBool ok; + int i; + + if (psName) { + psNameLen = strlen(psName); + } else { + psName = name->getCString(); + psNameLen = name->getLength(); + } + + // write header and font dictionary, up to encoding + ok = gTrue; + (*outputFunc)(outputStream, "%!FontType1-1.0: ", 17); + (*outputFunc)(outputStream, psName, psNameLen); + if (topDict.versionSID != 0) { + getString(topDict.versionSID, buf2, &ok); + (*outputFunc)(outputStream, buf2, strlen(buf2)); + } + (*outputFunc)(outputStream, "\n", 1); + // the dictionary needs room for 12 entries: the following 9, plus + // Private and CharStrings (in the eexec section) and FID (which is + // added by definefont) + (*outputFunc)(outputStream, "12 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontInfo 10 dict dup begin\n", 28); + if (topDict.versionSID != 0) { + (*outputFunc)(outputStream, "/version (", 10); + (*outputFunc)(outputStream, buf2, strlen(buf2)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.noticeSID != 0) { + getString(topDict.noticeSID, buf2, &ok); + (*outputFunc)(outputStream, "/Notice (", 9); + (*outputFunc)(outputStream, buf2, strlen(buf2)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.copyrightSID != 0) { + getString(topDict.copyrightSID, buf2, &ok); + (*outputFunc)(outputStream, "/Copyright (", 12); + (*outputFunc)(outputStream, buf2, strlen(buf2)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.fullNameSID != 0) { + getString(topDict.fullNameSID, buf2, &ok); + (*outputFunc)(outputStream, "/FullName (", 11); + (*outputFunc)(outputStream, buf2, strlen(buf2)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.familyNameSID != 0) { + getString(topDict.familyNameSID, buf2, &ok); + (*outputFunc)(outputStream, "/FamilyName (", 13); + (*outputFunc)(outputStream, buf2, strlen(buf2)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.weightSID != 0) { + getString(topDict.weightSID, buf2, &ok); + (*outputFunc)(outputStream, "/Weight (", 9); + (*outputFunc)(outputStream, buf2, strlen(buf2)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.isFixedPitch) { + (*outputFunc)(outputStream, "/isFixedPitch true def\n", 23); + } else { + (*outputFunc)(outputStream, "/isFixedPitch false def\n", 24); + } + buf = GString::format("/ItalicAngle {0:.4g} def\n", topDict.italicAngle); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format("/UnderlinePosition {0:.4g} def\n", + topDict.underlinePosition); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format("/UnderlineThickness {0:.4g} def\n", + topDict.underlineThickness); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "end readonly def\n", 17); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, psNameLen); + (*outputFunc)(outputStream, " def\n", 5); + buf = GString::format("/PaintType {0:d} def\n", topDict.paintType); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/FontType 1 def\n", 16); + buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] readonly def\n", + topDict.fontMatrix[0], topDict.fontMatrix[1], + topDict.fontMatrix[2], topDict.fontMatrix[3], + topDict.fontMatrix[4], topDict.fontMatrix[5]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] readonly def\n", + topDict.fontBBox[0], topDict.fontBBox[1], + topDict.fontBBox[2], topDict.fontBBox[3]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format("/StrokeWidth {0:.4g} def\n", topDict.strokeWidth); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + if (topDict.uniqueID != 0) { + buf = GString::format("/UniqueID {0:d} def\n", topDict.uniqueID); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + + // write the encoding + (*outputFunc)(outputStream, "/Encoding ", 10); + if (!newEncoding && encoding == fofiType1StandardEncoding) { + (*outputFunc)(outputStream, "StandardEncoding def\n", 21); + } else { + (*outputFunc)(outputStream, "256 array\n", 10); + (*outputFunc)(outputStream, + "0 1 255 {1 index exch /.notdef put} for\n", 40); + enc = newEncoding ? newEncoding : encoding; + for (i = 0; i < 256; ++i) { + if (enc[i]) { + buf = GString::format("dup {0:d} /{1:s} put\n", i, enc[i]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + } + (*outputFunc)(outputStream, "readonly def\n", 13); + } + (*outputFunc)(outputStream, "currentdict end\n", 16); + + // start the binary section + (*outputFunc)(outputStream, "currentfile eexec\n", 18); + eb.outputFunc = outputFunc; + eb.outputStream = outputStream; + eb.ascii = ascii; + eb.r1 = 55665; + eb.line = 0; + + // write the private dictionary + eexecWrite(&eb, "\x83\xca\x73\xd5"); + eexecWrite(&eb, "dup /Private 32 dict dup begin\n"); + eexecWrite(&eb, "/RD {string currentfile exch readstring pop}" + " executeonly def\n"); + eexecWrite(&eb, "/ND {noaccess def} executeonly def\n"); + eexecWrite(&eb, "/NP {noaccess put} executeonly def\n"); + eexecWrite(&eb, "/MinFeature {16 16} def\n"); + eexecWrite(&eb, "/password 5839 def\n"); + if (privateDicts[0].nBlueValues) { + eexecWrite(&eb, "/BlueValues ["); + for (i = 0; i < privateDicts[0].nBlueValues; ++i) { + buf = GString::format("{0:s}{1:d}", + i > 0 ? " " : "", privateDicts[0].blueValues[i]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].nOtherBlues) { + eexecWrite(&eb, "/OtherBlues ["); + for (i = 0; i < privateDicts[0].nOtherBlues; ++i) { + buf = GString::format("{0:s}{1:d}", + i > 0 ? " " : "", privateDicts[0].otherBlues[i]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].nFamilyBlues) { + eexecWrite(&eb, "/FamilyBlues ["); + for (i = 0; i < privateDicts[0].nFamilyBlues; ++i) { + buf = GString::format("{0:s}{1:d}", + i > 0 ? " " : "", privateDicts[0].familyBlues[i]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].nFamilyOtherBlues) { + eexecWrite(&eb, "/FamilyOtherBlues ["); + for (i = 0; i < privateDicts[0].nFamilyOtherBlues; ++i) { + buf = GString::format("{0:s}{1:d}", i > 0 ? " " : "", + privateDicts[0].familyOtherBlues[i]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].blueScale != 0.039625) { + buf = GString::format("/BlueScale {0:.4g} def\n", + privateDicts[0].blueScale); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].blueShift != 7) { + buf = GString::format("/BlueShift {0:d} def\n", privateDicts[0].blueShift); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].blueFuzz != 1) { + buf = GString::format("/BlueFuzz {0:d} def\n", privateDicts[0].blueFuzz); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].hasStdHW) { + buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[0].stdHW); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].hasStdVW) { + buf = GString::format("/StdVW [{0:.4g}] def\n", privateDicts[0].stdVW); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].nStemSnapH) { + eexecWrite(&eb, "/StemSnapH ["); + for (i = 0; i < privateDicts[0].nStemSnapH; ++i) { + buf = GString::format("{0:s}{1:.4g}", + i > 0 ? " " : "", privateDicts[0].stemSnapH[i]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].nStemSnapV) { + eexecWrite(&eb, "/StemSnapV ["); + for (i = 0; i < privateDicts[0].nStemSnapV; ++i) { + buf = GString::format("{0:s}{1:.4g}", + i > 0 ? " " : "", privateDicts[0].stemSnapV[i]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].hasForceBold) { + buf = GString::format("/ForceBold {0:s} def\n", + privateDicts[0].forceBold ? "true" : "false"); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].forceBoldThreshold != 0) { + buf = GString::format("/ForceBoldThreshold {0:.4g} def\n", + privateDicts[0].forceBoldThreshold); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].languageGroup != 0) { + buf = GString::format("/LanguageGroup {0:d} def\n", + privateDicts[0].languageGroup); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].expansionFactor != 0.06) { + buf = GString::format("/ExpansionFactor {0:.4g} def\n", + privateDicts[0].expansionFactor); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + + // set up subroutines + ok = gTrue; + getIndex(privateDicts[0].subrsOffset, &subrIdx, &ok); + if (!ok) { + subrIdx.pos = -1; + } + + // write the CharStrings + buf = GString::format("2 index /CharStrings {0:d} dict dup begin\n", + nGlyphs); + eexecWrite(&eb, buf->getCString()); + delete buf; + for (i = 0; i < nGlyphs; ++i) { + ok = gTrue; + getIndexVal(&charStringsIdx, i, &val, &ok); + if (ok) { + getString(charset[i], buf2, &ok); + if (ok) { + eexecCvtGlyph(&eb, buf2, val.pos, val.len, &subrIdx, &privateDicts[0]); + } + } + } + eexecWrite(&eb, "end\n"); + eexecWrite(&eb, "end\n"); + eexecWrite(&eb, "readonly put\n"); + eexecWrite(&eb, "noaccess put\n"); + eexecWrite(&eb, "dup /FontName get exch definefont pop\n"); + eexecWrite(&eb, "mark currentfile closefile\n"); + + // trailer + if (ascii && eb.line > 0) { + (*outputFunc)(outputStream, "\n", 1); + } + for (i = 0; i < 8; ++i) { + (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65); + } + (*outputFunc)(outputStream, "cleartomark\n", 12); +} + +void FoFiType1C::convertToCIDType0(char *psName, + FoFiOutputFunc outputFunc, + void *outputStream) { + int *cidMap; + GString *charStrings; + int *charStringOffsets; + Type1CIndex subrIdx; + Type1CIndexVal val; + int nCIDs, gdBytes; + GString *buf; + char buf2[256]; + GBool ok; + int gid, offset, n, i, j, k; + + // compute the CID count and build the CID-to-GID mapping + nCIDs = 0; + for (i = 0; i < nGlyphs; ++i) { + if (charset[i] >= nCIDs) { + nCIDs = charset[i] + 1; + } + } + cidMap = (int *)gmallocn(nCIDs, sizeof(int)); + for (i = 0; i < nCIDs; ++i) { + cidMap[i] = -1; + } + for (i = 0; i < nGlyphs; ++i) { + cidMap[charset[i]] = i; + } + + // build the charstrings + charStrings = new GString(); + charStringOffsets = (int *)gmallocn(nCIDs + 1, sizeof(int)); + for (i = 0; i < nCIDs; ++i) { + charStringOffsets[i] = charStrings->getLength(); + if ((gid = cidMap[i]) >= 0) { + ok = gTrue; + getIndexVal(&charStringsIdx, gid, &val, &ok); + if (ok) { + getIndex(privateDicts[fdSelect[gid]].subrsOffset, &subrIdx, &ok); + if (!ok) { + subrIdx.pos = -1; + } + cvtGlyph(val.pos, val.len, charStrings, + &subrIdx, &privateDicts[fdSelect[gid]], gTrue); + } + } + } + charStringOffsets[nCIDs] = charStrings->getLength(); + + // compute gdBytes = number of bytes needed for charstring offsets + // (offset size needs to account for the charstring offset table, + // with a worst case of five bytes per entry, plus the charstrings + // themselves) + i = (nCIDs + 1) * 5 + charStrings->getLength(); + if (i < 0x100) { + gdBytes = 1; + } else if (i < 0x10000) { + gdBytes = 2; + } else if (i < 0x1000000) { + gdBytes = 3; + } else { + gdBytes = 4; + } + + // begin the font dictionary + (*outputFunc)(outputStream, "/CIDInit /ProcSet findresource begin\n", 37); + (*outputFunc)(outputStream, "20 dict begin\n", 14); + (*outputFunc)(outputStream, "/CIDFontName /", 14); + (*outputFunc)(outputStream, psName, strlen(psName)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/CIDFontType 0 def\n", 19); + (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32); + if (topDict.registrySID > 0 && topDict.orderingSID > 0) { + ok = gTrue; + getString(topDict.registrySID, buf2, &ok); + if (ok) { + (*outputFunc)(outputStream, " /Registry (", 13); + (*outputFunc)(outputStream, buf2, strlen(buf2)); + (*outputFunc)(outputStream, ") def\n", 6); + } + ok = gTrue; + getString(topDict.orderingSID, buf2, &ok); + if (ok) { + (*outputFunc)(outputStream, " /Ordering (", 13); + (*outputFunc)(outputStream, buf2, strlen(buf2)); + (*outputFunc)(outputStream, ") def\n", 6); + } + } else { + (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24); + (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27); + } + buf = GString::format(" /Supplement {0:d} def\n", topDict.supplement); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "end def\n", 8); + if (topDict.hasFontMatrix) { + buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n", + topDict.fontMatrix[0], topDict.fontMatrix[1], + topDict.fontMatrix[2], topDict.fontMatrix[3], + topDict.fontMatrix[4], topDict.fontMatrix[5]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } else if (privateDicts[0].hasFontMatrix) { + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + } else { + (*outputFunc)(outputStream, + "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38); + } + buf = GString::format("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] def\n", + topDict.fontBBox[0], topDict.fontBBox[1], + topDict.fontBBox[2], topDict.fontBBox[3]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/FontInfo 1 dict dup begin\n", 27); + (*outputFunc)(outputStream, " /FSType 8 def\n", 16); + (*outputFunc)(outputStream, "end def\n", 8); + + // CIDFont-specific entries + buf = GString::format("/CIDCount {0:d} def\n", nCIDs); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/FDBytes 1 def\n", 15); + buf = GString::format("/GDBytes {0:d} def\n", gdBytes); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/CIDMapOffset 0 def\n", 20); + if (topDict.paintType != 0) { + buf = GString::format("/PaintType {0:d} def\n", topDict.paintType); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format("/StrokeWidth {0:.4g} def\n", topDict.strokeWidth); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + + // FDArray entry + buf = GString::format("/FDArray {0:d} array\n", nFDs); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + for (i = 0; i < nFDs; ++i) { + buf = GString::format("dup {0:d} 10 dict begin\n", i); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/FontType 1 def\n", 16); + if (privateDicts[i].hasFontMatrix) { + buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n", + privateDicts[i].fontMatrix[0], + privateDicts[i].fontMatrix[1], + privateDicts[i].fontMatrix[2], + privateDicts[i].fontMatrix[3], + privateDicts[i].fontMatrix[4], + privateDicts[i].fontMatrix[5]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } else { + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + } + buf = GString::format("/PaintType {0:d} def\n", topDict.paintType); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/Private 32 dict begin\n", 23); + if (privateDicts[i].nBlueValues) { + (*outputFunc)(outputStream, "/BlueValues [", 13); + for (j = 0; j < privateDicts[i].nBlueValues; ++j) { + buf = GString::format("{0:s}{1:d}", + j > 0 ? " " : "", privateDicts[i].blueValues[j]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].nOtherBlues) { + (*outputFunc)(outputStream, "/OtherBlues [", 13); + for (j = 0; j < privateDicts[i].nOtherBlues; ++j) { + buf = GString::format("{0:s}{1:d}", + j > 0 ? " " : "", privateDicts[i].otherBlues[j]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].nFamilyBlues) { + (*outputFunc)(outputStream, "/FamilyBlues [", 14); + for (j = 0; j < privateDicts[i].nFamilyBlues; ++j) { + buf = GString::format("{0:s}{1:d}", + j > 0 ? " " : "", + privateDicts[i].familyBlues[j]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].nFamilyOtherBlues) { + (*outputFunc)(outputStream, "/FamilyOtherBlues [", 19); + for (j = 0; j < privateDicts[i].nFamilyOtherBlues; ++j) { + buf = GString::format("{0:s}{1:d}", j > 0 ? " " : "", + privateDicts[i].familyOtherBlues[j]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].blueScale != 0.039625) { + buf = GString::format("/BlueScale {0:.4g} def\n", + privateDicts[i].blueScale); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].blueShift != 7) { + buf = GString::format("/BlueShift {0:d} def\n", + privateDicts[i].blueShift); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].blueFuzz != 1) { + buf = GString::format("/BlueFuzz {0:d} def\n", privateDicts[i].blueFuzz); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].hasStdHW) { + buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[i].stdHW); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].hasStdVW) { + buf = GString::format("/StdVW [{0:.4g}] def\n", privateDicts[i].stdVW); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].nStemSnapH) { + (*outputFunc)(outputStream, "/StemSnapH [", 12); + for (j = 0; j < privateDicts[i].nStemSnapH; ++j) { + buf = GString::format("{0:s}{1:.4g}", + j > 0 ? " " : "", privateDicts[i].stemSnapH[j]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].nStemSnapV) { + (*outputFunc)(outputStream, "/StemSnapV [", 12); + for (j = 0; j < privateDicts[i].nStemSnapV; ++j) { + buf = GString::format("{0:s}{1:.4g}", + j > 0 ? " " : "", privateDicts[i].stemSnapV[j]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].hasForceBold) { + buf = GString::format("/ForceBold {0:s} def\n", + privateDicts[i].forceBold ? "true" : "false"); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].forceBoldThreshold != 0) { + buf = GString::format("/ForceBoldThreshold {0:.4g} def\n", + privateDicts[i].forceBoldThreshold); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].languageGroup != 0) { + buf = GString::format("/LanguageGroup {0:d} def\n", + privateDicts[i].languageGroup); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].expansionFactor != 0.06) { + buf = GString::format("/ExpansionFactor {0:.4g} def\n", + privateDicts[i].expansionFactor); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "currentdict end def\n", 20); + (*outputFunc)(outputStream, "currentdict end put\n", 20); + } + (*outputFunc)(outputStream, "def\n", 4); + + // start the binary section + offset = (nCIDs + 1) * (1 + gdBytes); + buf = GString::format("(Hex) {0:d} StartData\n", + offset + charStrings->getLength()); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + + // write the charstring offset (CIDMap) table + for (i = 0; i <= nCIDs; i += 6) { + for (j = 0; j < 6 && i+j <= nCIDs; ++j) { + if (i+j < nCIDs && cidMap[i+j] >= 0) { + buf2[0] = (char)fdSelect[cidMap[i+j]]; + } else { + buf2[0] = (char)0; + } + n = offset + charStringOffsets[i+j]; + for (k = gdBytes; k >= 1; --k) { + buf2[k] = (char)(n & 0xff); + n >>= 8; + } + for (k = 0; k <= gdBytes; ++k) { + buf = GString::format("{0:02x}", buf2[k] & 0xff); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + } + (*outputFunc)(outputStream, "\n", 1); + } + + // write the charstring data + n = charStrings->getLength(); + for (i = 0; i < n; i += 32) { + for (j = 0; j < 32 && i+j < n; ++j) { + buf = GString::format("{0:02x}", charStrings->getChar(i+j) & 0xff); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (i + 32 >= n) { + (*outputFunc)(outputStream, ">", 1); + } + (*outputFunc)(outputStream, "\n", 1); + } + + gfree(charStringOffsets); + delete charStrings; + gfree(cidMap); +} + +void FoFiType1C::convertToType0(char *psName, + FoFiOutputFunc outputFunc, + void *outputStream) { + int *cidMap; + Type1CIndex subrIdx; + Type1CIndexVal val; + int nCIDs; + GString *buf; + Type1CEexecBuf eb; + GBool ok; + int fd, i, j, k; + + // compute the CID count and build the CID-to-GID mapping + nCIDs = 0; + for (i = 0; i < nGlyphs; ++i) { + if (charset[i] >= nCIDs) { + nCIDs = charset[i] + 1; + } + } + cidMap = (int *)gmallocn(nCIDs, sizeof(int)); + for (i = 0; i < nCIDs; ++i) { + cidMap[i] = -1; + } + for (i = 0; i < nGlyphs; ++i) { + cidMap[charset[i]] = i; + } + + // write the descendant Type 1 fonts + for (i = 0; i < nCIDs; i += 256) { + + //~ this assumes that all CIDs in this block have the same FD -- + //~ to handle multiple FDs correctly, need to somehow divide the + //~ font up by FD; as a kludge we ignore CID 0, which is .notdef + fd = 0; + for (j = i==0 ? 1 : 0; j < 256 && i+j < nCIDs; ++j) { + if (cidMap[i+j] >= 0) { + fd = fdSelect[cidMap[i+j]]; + break; + } + } + + // font dictionary (unencrypted section) + (*outputFunc)(outputStream, "16 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, strlen(psName)); + buf = GString::format("_{0:02x} def\n", i >> 8); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/FontType 1 def\n", 16); + if (privateDicts[fd].hasFontMatrix) { + buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n", + privateDicts[fd].fontMatrix[0], + privateDicts[fd].fontMatrix[1], + privateDicts[fd].fontMatrix[2], + privateDicts[fd].fontMatrix[3], + privateDicts[fd].fontMatrix[4], + privateDicts[fd].fontMatrix[5]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } else if (topDict.hasFontMatrix) { + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + } else { + (*outputFunc)(outputStream, + "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38); + } + buf = GString::format("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] def\n", + topDict.fontBBox[0], topDict.fontBBox[1], + topDict.fontBBox[2], topDict.fontBBox[3]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format("/PaintType {0:d} def\n", topDict.paintType); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + if (topDict.paintType != 0) { + buf = GString::format("/StrokeWidth {0:.4g} def\n", topDict.strokeWidth); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); + for (j = 0; j < 256 && i+j < nCIDs; ++j) { + buf = GString::format("dup {0:d} /c{1:02x} put\n", j, j); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (j < 256) { + buf = GString::format("{0:d} 1 255 {{ 1 index exch /.notdef put }} for\n", + j); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "readonly def\n", 13); + (*outputFunc)(outputStream, "currentdict end\n", 16); + + // start the binary section + (*outputFunc)(outputStream, "currentfile eexec\n", 18); + eb.outputFunc = outputFunc; + eb.outputStream = outputStream; + eb.ascii = gTrue; + eb.r1 = 55665; + eb.line = 0; + + // start the private dictionary + eexecWrite(&eb, "\x83\xca\x73\xd5"); + eexecWrite(&eb, "dup /Private 32 dict dup begin\n"); + eexecWrite(&eb, "/RD {string currentfile exch readstring pop}" + " executeonly def\n"); + eexecWrite(&eb, "/ND {noaccess def} executeonly def\n"); + eexecWrite(&eb, "/NP {noaccess put} executeonly def\n"); + eexecWrite(&eb, "/MinFeature {16 16} def\n"); + eexecWrite(&eb, "/password 5839 def\n"); + if (privateDicts[fd].nBlueValues) { + eexecWrite(&eb, "/BlueValues ["); + for (k = 0; k < privateDicts[fd].nBlueValues; ++k) { + buf = GString::format("{0:s}{1:d}", + k > 0 ? " " : "", + privateDicts[fd].blueValues[k]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].nOtherBlues) { + eexecWrite(&eb, "/OtherBlues ["); + for (k = 0; k < privateDicts[fd].nOtherBlues; ++k) { + buf = GString::format("{0:s}{1:d}", + k > 0 ? " " : "", + privateDicts[fd].otherBlues[k]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].nFamilyBlues) { + eexecWrite(&eb, "/FamilyBlues ["); + for (k = 0; k < privateDicts[fd].nFamilyBlues; ++k) { + buf = GString::format("{0:s}{1:d}", k > 0 ? " " : "", + privateDicts[fd].familyBlues[k]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].nFamilyOtherBlues) { + eexecWrite(&eb, "/FamilyOtherBlues ["); + for (k = 0; k < privateDicts[fd].nFamilyOtherBlues; ++k) { + buf = GString::format("{0:s}{1:d}", k > 0 ? " " : "", + privateDicts[fd].familyOtherBlues[k]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].blueScale != 0.039625) { + buf = GString::format("/BlueScale {0:.4g} def\n", + privateDicts[fd].blueScale); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].blueShift != 7) { + buf = GString::format("/BlueShift {0:d} def\n", + privateDicts[fd].blueShift); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].blueFuzz != 1) { + buf = GString::format("/BlueFuzz {0:d} def\n", + privateDicts[fd].blueFuzz); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].hasStdHW) { + buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[fd].stdHW); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].hasStdVW) { + buf = GString::format("/StdVW [{0:.4g}] def\n", privateDicts[fd].stdVW); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].nStemSnapH) { + eexecWrite(&eb, "/StemSnapH ["); + for (k = 0; k < privateDicts[fd].nStemSnapH; ++k) { + buf = GString::format("{0:s}{1:.4g}", + k > 0 ? " " : "", privateDicts[fd].stemSnapH[k]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].nStemSnapV) { + eexecWrite(&eb, "/StemSnapV ["); + for (k = 0; k < privateDicts[fd].nStemSnapV; ++k) { + buf = GString::format("{0:s}{1:.4g}", + k > 0 ? " " : "", privateDicts[fd].stemSnapV[k]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].hasForceBold) { + buf = GString::format("/ForceBold {0:s} def\n", + privateDicts[fd].forceBold ? "true" : "false"); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].forceBoldThreshold != 0) { + buf = GString::format("/ForceBoldThreshold {0:.4g} def\n", + privateDicts[fd].forceBoldThreshold); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].languageGroup != 0) { + buf = GString::format("/LanguageGroup {0:d} def\n", + privateDicts[fd].languageGroup); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].expansionFactor != 0.06) { + buf = GString::format("/ExpansionFactor {0:.4g} def\n", + privateDicts[fd].expansionFactor); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + + // set up the subroutines + ok = gTrue; + getIndex(privateDicts[fd].subrsOffset, &subrIdx, &ok); + if (!ok) { + subrIdx.pos = -1; + } + + // start the CharStrings + eexecWrite(&eb, "2 index /CharStrings 256 dict dup begin\n"); + + // write the .notdef CharString + ok = gTrue; + getIndexVal(&charStringsIdx, 0, &val, &ok); + if (ok) { + eexecCvtGlyph(&eb, ".notdef", val.pos, val.len, + &subrIdx, &privateDicts[fd]); + } + + // write the CharStrings + for (j = 0; j < 256 && i+j < nCIDs; ++j) { + if (cidMap[i+j] >= 0) { + ok = gTrue; + getIndexVal(&charStringsIdx, cidMap[i+j], &val, &ok); + if (ok) { + buf = GString::format("c{0:02x}", j); + eexecCvtGlyph(&eb, buf->getCString(), val.pos, val.len, + &subrIdx, &privateDicts[fd]); + delete buf; + } + } + } + eexecWrite(&eb, "end\n"); + eexecWrite(&eb, "end\n"); + eexecWrite(&eb, "readonly put\n"); + eexecWrite(&eb, "noaccess put\n"); + eexecWrite(&eb, "dup /FontName get exch definefont pop\n"); + eexecWrite(&eb, "mark currentfile closefile\n"); + + // trailer + if (eb.line > 0) { + (*outputFunc)(outputStream, "\n", 1); + } + for (j = 0; j < 8; ++j) { + (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65); + } + (*outputFunc)(outputStream, "cleartomark\n", 12); + } + + // write the Type 0 parent font + (*outputFunc)(outputStream, "16 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, strlen(psName)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/FontType 0 def\n", 16); + if (topDict.hasFontMatrix) { + buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n", + topDict.fontMatrix[0], topDict.fontMatrix[1], + topDict.fontMatrix[2], topDict.fontMatrix[3], + topDict.fontMatrix[4], topDict.fontMatrix[5]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } else { + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + } + (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); + (*outputFunc)(outputStream, "/Encoding [\n", 12); + for (i = 0; i < nCIDs; i += 256) { + buf = GString::format("{0:d}\n", i >> 8); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + (*outputFunc)(outputStream, "/FDepVector [\n", 14); + for (i = 0; i < nCIDs; i += 256) { + (*outputFunc)(outputStream, "/", 1); + (*outputFunc)(outputStream, psName, strlen(psName)); + buf = GString::format("_{0:02x} findfont\n", i >> 8); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); + + gfree(cidMap); +} + +void FoFiType1C::eexecCvtGlyph(Type1CEexecBuf *eb, char *glyphName, + int offset, int nBytes, + Type1CIndex *subrIdx, + Type1CPrivateDict *pDict) { + GString *buf; + GString *charBuf; + + // generate the charstring + charBuf = new GString(); + cvtGlyph(offset, nBytes, charBuf, subrIdx, pDict, gTrue); + + buf = GString::format("/{0:s} {1:d} RD ", glyphName, charBuf->getLength()); + eexecWrite(eb, buf->getCString()); + delete buf; + eexecWriteCharstring(eb, (Guchar *)charBuf->getCString(), + charBuf->getLength()); + eexecWrite(eb, " ND\n"); + + delete charBuf; +} + +void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, + Type1CIndex *subrIdx, Type1CPrivateDict *pDict, + GBool top) { + Type1CIndexVal val; + GBool ok, dFP; + double d, dx, dy; + Gushort r2; + Guchar byte; + int pos, subrBias, start, i, k; + + start = charBuf->getLength(); + if (top) { + charBuf->append((char)73); + charBuf->append((char)58); + charBuf->append((char)147); + charBuf->append((char)134); + nOps = 0; + nHints = 0; + firstOp = gTrue; + openPath = gFalse; + } + + pos = offset; + while (pos < offset + nBytes) { + ok = gTrue; + pos = getOp(pos, gTrue, &ok); + if (!ok) { + break; + } + if (!ops[nOps - 1].isNum) { + --nOps; // drop the operator + switch (ops[nOps].op) { + case 0x0001: // hstem + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps); + } + d = 0; + dFP = gFalse; + for (k = 0; k < nOps; k += 2) { + // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints + if (ops[k+1].num < 0) { + d += ops[k].num + ops[k+1].num; + dFP |= ops[k].isFP | ops[k+1].isFP; + cvtNum(d, dFP, charBuf); + cvtNum(-ops[k+1].num, ops[k+1].isFP, charBuf); + } else { + d += ops[k].num; + dFP |= ops[k].isFP; + cvtNum(d, dFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + d += ops[k+1].num; + dFP |= ops[k+1].isFP; + } + charBuf->append((char)1); + } + nHints += nOps / 2; + nOps = 0; + break; + case 0x0003: // vstem + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps); + } + d = 0; + dFP = gFalse; + for (k = 0; k < nOps; k += 2) { + // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints + if (ops[k+1].num < 0) { + d += ops[k].num + ops[k+1].num; + dFP |= ops[k].isFP | ops[k+1].isFP; + cvtNum(d, dFP, charBuf); + cvtNum(-ops[k+1].num, ops[k+1].isFP, charBuf); + } else { + d += ops[k].num; + dFP |= ops[k].isFP; + cvtNum(d, dFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + d += ops[k+1].num; + dFP |= ops[k+1].isFP; + } + charBuf->append((char)3); + } + nHints += nOps / 2; + nOps = 0; + break; + case 0x0004: // vmoveto + if (firstOp) { + cvtGlyphWidth(nOps == 2, charBuf, pDict); + firstOp = gFalse; + } + if (openPath) { + charBuf->append((char)9); + openPath = gFalse; + } + if (nOps != 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + charBuf->append((char)4); + nOps = 0; + break; + case 0x0005: // rlineto + if (nOps < 2 || nOps % 2 != 0) { + //~ error(-1, "Wrong number of args (%d) to Type 2 rlineto", nOps); + } + for (k = 0; k < nOps; k += 2) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + charBuf->append((char)5); + } + nOps = 0; + openPath = gTrue; + break; + case 0x0006: // hlineto + if (nOps < 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hlineto", nOps); + } + for (k = 0; k < nOps; ++k) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + charBuf->append((char)((k & 1) ? 7 : 6)); + } + nOps = 0; + openPath = gTrue; + break; + case 0x0007: // vlineto + if (nOps < 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vlineto", nOps); + } + for (k = 0; k < nOps; ++k) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + charBuf->append((char)((k & 1) ? 6 : 7)); + } + nOps = 0; + openPath = gTrue; + break; + case 0x0008: // rrcurveto + if (nOps < 6 || nOps % 6 != 0) { + //~ error(-1, "Wrong number of args (%d) to Type 2 rrcurveto", nOps); + } + for (k = 0; k < nOps; k += 6) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf); + charBuf->append((char)8); + } + nOps = 0; + openPath = gTrue; + break; + case 0x000a: // callsubr + if (nOps >= 1) { + subrBias = (subrIdx->len < 1240) + ? 107 : (subrIdx->len < 33900) ? 1131 : 32768; + k = subrBias + (int)ops[nOps - 1].num; + --nOps; + ok = gTrue; + getIndexVal(subrIdx, k, &val, &ok); + if (ok) { + cvtGlyph(val.pos, val.len, charBuf, subrIdx, pDict, gFalse); + } + } else { + //~ error(-1, "Too few args to Type 2 callsubr"); + } + // don't clear the stack + break; + case 0x000b: // return + // don't clear the stack + break; + case 0x000e: // endchar / seac + if (firstOp) { + cvtGlyphWidth(nOps == 1 || nOps == 5, charBuf, pDict); + firstOp = gFalse; + } + if (openPath) { + charBuf->append((char)9); + openPath = gFalse; + } + if (nOps == 4) { + cvtNum(0, gFalse, charBuf); + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + charBuf->append((char)12)->append((char)6); + } else if (nOps == 0) { + charBuf->append((char)14); + } else { + //~ error(-1, "Wrong number of args (%d) to Type 2 endchar", nOps); + } + nOps = 0; + break; + case 0x000f: // (obsolete) + // this op is ignored, but we need the glyph width + if (firstOp) { + cvtGlyphWidth(nOps > 0, charBuf, pDict); + firstOp = gFalse; + } + nOps = 0; + break; + case 0x0010: // blend + //~ error(-1, "Unimplemented Type 2 charstring op: %d", file[i]); + nOps = 0; + break; + case 0x0012: // hstemhm + // ignored + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps); + } + nHints += nOps / 2; + nOps = 0; + break; + case 0x0013: // hintmask + // ignored + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps > 0) { + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hintmask/vstemhm", + //~ nOps); + } + nHints += nOps / 2; + } + pos += (nHints + 7) >> 3; + nOps = 0; + break; + case 0x0014: // cntrmask + // ignored + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps > 0) { + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 cntrmask/vstemhm", + //~ nOps); + } + nHints += nOps / 2; + } + pos += (nHints + 7) >> 3; + nOps = 0; + break; + case 0x0015: // rmoveto + if (firstOp) { + cvtGlyphWidth(nOps == 3, charBuf, pDict); + firstOp = gFalse; + } + if (openPath) { + charBuf->append((char)9); + openPath = gFalse; + } + if (nOps != 2) { + //~ error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + charBuf->append((char)21); + nOps = 0; + break; + case 0x0016: // hmoveto + if (firstOp) { + cvtGlyphWidth(nOps == 2, charBuf, pDict); + firstOp = gFalse; + } + if (openPath) { + charBuf->append((char)9); + openPath = gFalse; + } + if (nOps != 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + charBuf->append((char)22); + nOps = 0; + break; + case 0x0017: // vstemhm + // ignored + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps); + } + nHints += nOps / 2; + nOps = 0; + break; + case 0x0018: // rcurveline + if (nOps < 8 || (nOps - 2) % 6 != 0) { + //~ error(-1, "Wrong number of args (%d) to Type 2 rcurveline", nOps); + } + for (k = 0; k < nOps - 2; k += 6) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf); + charBuf->append((char)8); + } + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k].isFP, charBuf); + charBuf->append((char)5); + nOps = 0; + openPath = gTrue; + break; + case 0x0019: // rlinecurve + if (nOps < 8 || (nOps - 6) % 2 != 0) { + //~ error(-1, "Wrong number of args (%d) to Type 2 rlinecurve", nOps); + } + for (k = 0; k < nOps - 6; k += 2) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k].isFP, charBuf); + charBuf->append((char)5); + } + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf); + charBuf->append((char)8); + nOps = 0; + openPath = gTrue; + break; + case 0x001a: // vvcurveto + if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vvcurveto", nOps); + } + if (nOps % 2 == 1) { + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[4].num, ops[4].isFP, charBuf); + charBuf->append((char)8); + k = 5; + } else { + k = 0; + } + for (; k < nOps; k += 4) { + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + charBuf->append((char)8); + } + nOps = 0; + openPath = gTrue; + break; + case 0x001b: // hhcurveto + if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hhcurveto", nOps); + } + if (nOps % 2 == 1) { + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + cvtNum(ops[4].num, ops[4].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + charBuf->append((char)8); + k = 5; + } else { + k = 0; + } + for (; k < nOps; k += 4) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + charBuf->append((char)8); + } + nOps = 0; + openPath = gTrue; + break; + case 0x001d: // callgsubr + if (nOps >= 1) { + k = gsubrBias + (int)ops[nOps - 1].num; + --nOps; + ok = gTrue; + getIndexVal(&gsubrIdx, k, &val, &ok); + if (ok) { + cvtGlyph(val.pos, val.len, charBuf, subrIdx, pDict, gFalse); + } + } else { + //~ error(-1, "Too few args to Type 2 callgsubr"); + } + // don't clear the stack + break; + case 0x001e: // vhcurveto + if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vhcurveto", nOps); + } + for (k = 0; k < nOps && k != nOps-5; k += 4) { + if (k % 8 == 0) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + charBuf->append((char)30); + } else { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + charBuf->append((char)31); + } + } + if (k == nOps-5) { + if (k % 8 == 0) { + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + } else { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + } + charBuf->append((char)8); + } + nOps = 0; + openPath = gTrue; + break; + case 0x001f: // hvcurveto + if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hvcurveto", nOps); + } + for (k = 0; k < nOps && k != nOps-5; k += 4) { + if (k % 8 == 0) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + charBuf->append((char)31); + } else { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + charBuf->append((char)30); + } + } + if (k == nOps-5) { + if (k % 8 == 0) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + } else { + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + } + charBuf->append((char)8); + } + nOps = 0; + openPath = gTrue; + break; + case 0x0c00: // dotsection (should be Type 1 only?) + // ignored + nOps = 0; + break; + case 0x0c03: // and + case 0x0c04: // or + case 0x0c05: // not + case 0x0c08: // store + case 0x0c09: // abs + case 0x0c0a: // add + case 0x0c0b: // sub + case 0x0c0c: // div + case 0x0c0d: // load + case 0x0c0e: // neg + case 0x0c0f: // eq + case 0x0c12: // drop + case 0x0c14: // put + case 0x0c15: // get + case 0x0c16: // ifelse + case 0x0c17: // random + case 0x0c18: // mul + case 0x0c1a: // sqrt + case 0x0c1b: // dup + case 0x0c1c: // exch + case 0x0c1d: // index + case 0x0c1e: // roll + //~ error(-1, "Unimplemented Type 2 charstring op: 12.%d", file[i+1]); + nOps = 0; + break; + case 0x0c22: // hflex + if (nOps != 7) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hflex", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + charBuf->append((char)8); + cvtNum(ops[4].num, ops[4].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[5].num, ops[5].isFP, charBuf); + cvtNum(-ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[6].num, ops[6].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + charBuf->append((char)8); + nOps = 0; + openPath = gTrue; + break; + case 0x0c23: // flex + if (nOps != 13) { + //~ error(-1, "Wrong number of args (%d) to Type 2 flex", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + cvtNum(ops[4].num, ops[4].isFP, charBuf); + cvtNum(ops[5].num, ops[5].isFP, charBuf); + charBuf->append((char)8); + cvtNum(ops[6].num, ops[6].isFP, charBuf); + cvtNum(ops[7].num, ops[7].isFP, charBuf); + cvtNum(ops[8].num, ops[8].isFP, charBuf); + cvtNum(ops[9].num, ops[9].isFP, charBuf); + cvtNum(ops[10].num, ops[10].isFP, charBuf); + cvtNum(ops[11].num, ops[11].isFP, charBuf); + charBuf->append((char)8); + nOps = 0; + openPath = gTrue; + break; + case 0x0c24: // hflex1 + if (nOps != 9) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hflex1", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + cvtNum(ops[4].num, ops[4].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + charBuf->append((char)8); + cvtNum(ops[5].num, ops[5].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[6].num, ops[6].isFP, charBuf); + cvtNum(ops[7].num, ops[7].isFP, charBuf); + cvtNum(ops[8].num, ops[8].isFP, charBuf); + cvtNum(-(ops[1].num + ops[3].num + ops[7].num), + ops[1].isFP | ops[3].isFP | ops[7].isFP, charBuf); + charBuf->append((char)8); + nOps = 0; + openPath = gTrue; + break; + case 0x0c25: // flex1 + if (nOps != 11) { + //~ error(-1, "Wrong number of args (%d) to Type 2 flex1", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + cvtNum(ops[4].num, ops[4].isFP, charBuf); + cvtNum(ops[5].num, ops[5].isFP, charBuf); + charBuf->append((char)8); + cvtNum(ops[6].num, ops[6].isFP, charBuf); + cvtNum(ops[7].num, ops[7].isFP, charBuf); + cvtNum(ops[8].num, ops[8].isFP, charBuf); + cvtNum(ops[9].num, ops[9].isFP, charBuf); + dx = ops[0].num + ops[2].num + ops[4].num + ops[6].num + ops[8].num; + dy = ops[1].num + ops[3].num + ops[5].num + ops[7].num + ops[9].num; + if (fabs(dx) > fabs(dy)) { + cvtNum(ops[10].num, ops[10].isFP, charBuf); + cvtNum(-dy, ops[1].isFP | ops[3].isFP | ops[5].isFP | + ops[7].isFP | ops[9].isFP, charBuf); + } else { + cvtNum(-dx, ops[0].isFP | ops[2].isFP | ops[4].isFP | + ops[6].isFP | ops[8].isFP, charBuf); + cvtNum(ops[10].num, ops[10].isFP, charBuf); + } + charBuf->append((char)8); + nOps = 0; + openPath = gTrue; + break; + default: + //~ error(-1, "Illegal Type 2 charstring op: %04x", + //~ ops[nOps].op); + nOps = 0; + break; + } + } + } + + // charstring encryption + if (top) { + r2 = 4330; + for (i = start; i < charBuf->getLength(); ++i) { + byte = charBuf->getChar(i) ^ (r2 >> 8); + charBuf->setChar(i, byte); + r2 = (byte + r2) * 52845 + 22719; + } + } +} + +void FoFiType1C::cvtGlyphWidth(GBool useOp, GString *charBuf, + Type1CPrivateDict *pDict) { + double w; + GBool wFP; + int i; + + if (useOp) { + w = pDict->nominalWidthX + ops[0].num; + wFP = pDict->nominalWidthXFP | ops[0].isFP; + for (i = 1; i < nOps; ++i) { + ops[i-1] = ops[i]; + } + --nOps; + } else { + w = pDict->defaultWidthX; + wFP = pDict->defaultWidthXFP; + } + cvtNum(0, gFalse, charBuf); + cvtNum(w, wFP, charBuf); + charBuf->append((char)13); +} + +void FoFiType1C::cvtNum(double x, GBool isFP, GString *charBuf) { + Guchar buf[12]; + int y, n; + + n = 0; + if (isFP) { + if (x >= -32768 && x < 32768) { + y = (int)(x * 256.0); + buf[0] = 255; + buf[1] = (Guchar)(y >> 24); + buf[2] = (Guchar)(y >> 16); + buf[3] = (Guchar)(y >> 8); + buf[4] = (Guchar)y; + buf[5] = 255; + buf[6] = 0; + buf[7] = 0; + buf[8] = 1; + buf[9] = 0; + buf[10] = 12; + buf[11] = 12; + n = 12; + } else { + //~ error(-1, "Type 2 fixed point constant out of range"); + } + } else { + y = (int)x; + if (y >= -107 && y <= 107) { + buf[0] = (Guchar)(y + 139); + n = 1; + } else if (y > 107 && y <= 1131) { + y -= 108; + buf[0] = (Guchar)((y >> 8) + 247); + buf[1] = (Guchar)(y & 0xff); + n = 2; + } else if (y < -107 && y >= -1131) { + y = -y - 108; + buf[0] = (Guchar)((y >> 8) + 251); + buf[1] = (Guchar)(y & 0xff); + n = 2; + } else { + buf[0] = 255; + buf[1] = (Guchar)(y >> 24); + buf[2] = (Guchar)(y >> 16); + buf[3] = (Guchar)(y >> 8); + buf[4] = (Guchar)y; + n = 5; + } + } + charBuf->append((char *)buf, n); +} + +void FoFiType1C::eexecWrite(Type1CEexecBuf *eb, char *s) { + Guchar *p; + Guchar x; + + for (p = (Guchar *)s; *p; ++p) { + x = *p ^ (eb->r1 >> 8); + eb->r1 = (x + eb->r1) * 52845 + 22719; + if (eb->ascii) { + (*eb->outputFunc)(eb->outputStream, &hexChars[x >> 4], 1); + (*eb->outputFunc)(eb->outputStream, &hexChars[x & 0x0f], 1); + eb->line += 2; + if (eb->line == 64) { + (*eb->outputFunc)(eb->outputStream, "\n", 1); + eb->line = 0; + } + } else { + (*eb->outputFunc)(eb->outputStream, (char *)&x, 1); + } + } +} + +void FoFiType1C::eexecWriteCharstring(Type1CEexecBuf *eb, + Guchar *s, int n) { + Guchar x; + int i; + + // eexec encryption + for (i = 0; i < n; ++i) { + x = s[i] ^ (eb->r1 >> 8); + eb->r1 = (x + eb->r1) * 52845 + 22719; + if (eb->ascii) { + (*eb->outputFunc)(eb->outputStream, &hexChars[x >> 4], 1); + (*eb->outputFunc)(eb->outputStream, &hexChars[x & 0x0f], 1); + eb->line += 2; + if (eb->line == 64) { + (*eb->outputFunc)(eb->outputStream, "\n", 1); + eb->line = 0; + } + } else { + (*eb->outputFunc)(eb->outputStream, (char *)&x, 1); + } + } +} + +GBool FoFiType1C::parse() { + Type1CIndex fdIdx; + Type1CIndexVal val; + int i; + + parsedOk = gTrue; + + // some tools embed Type 1C fonts with an extra whitespace char at + // the beginning + if (len > 0 && file[0] != '\x01') { + ++file; + --len; + } + + // find the indexes + getIndex(getU8(2, &parsedOk), &nameIdx, &parsedOk); + getIndex(nameIdx.endPos, &topDictIdx, &parsedOk); + getIndex(topDictIdx.endPos, &stringIdx, &parsedOk); + getIndex(stringIdx.endPos, &gsubrIdx, &parsedOk); + if (!parsedOk) { + return gFalse; + } + gsubrBias = (gsubrIdx.len < 1240) ? 107 + : (gsubrIdx.len < 33900) ? 1131 : 32768; + + // read the first font name + getIndexVal(&nameIdx, 0, &val, &parsedOk); + if (!parsedOk) { + return gFalse; + } + name = new GString((char *)&file[val.pos], val.len); + + // read the top dict for the first font + readTopDict(); + + // for CID fonts: read the FDArray dicts and private dicts + if (topDict.firstOp == 0x0c1e) { + if (topDict.fdArrayOffset == 0) { + nFDs = 1; + privateDicts = (Type1CPrivateDict *)gmalloc(sizeof(Type1CPrivateDict)); + readPrivateDict(0, 0, &privateDicts[0]); + } else { + getIndex(topDict.fdArrayOffset, &fdIdx, &parsedOk); + if (!parsedOk) { + return gFalse; + } + nFDs = fdIdx.len; + privateDicts = (Type1CPrivateDict *) + gmallocn(nFDs, sizeof(Type1CPrivateDict)); + for (i = 0; i < nFDs; ++i) { + getIndexVal(&fdIdx, i, &val, &parsedOk); + if (!parsedOk) { + return gFalse; + } + readFD(val.pos, val.len, &privateDicts[i]); + } + } + + // for 8-bit fonts: read the private dict + } else { + privateDicts = (Type1CPrivateDict *)gmalloc(sizeof(Type1CPrivateDict)); + readPrivateDict(topDict.privateOffset, topDict.privateSize, + &privateDicts[0]); + } + + // check for parse errors in the private dict(s) + if (!parsedOk) { + return gFalse; + } + + // get the charstrings index + if (topDict.charStringsOffset <= 0) { + parsedOk = gFalse; + return gFalse; + } + getIndex(topDict.charStringsOffset, &charStringsIdx, &parsedOk); + if (!parsedOk) { + return gFalse; + } + nGlyphs = charStringsIdx.len; + + // for CID fonts: read the FDSelect table + if (topDict.firstOp == 0x0c1e) { + readFDSelect(); + if (!parsedOk) { + return gFalse; + } + } + + // read the charset + if (!readCharset()) { + parsedOk = gFalse; + return gFalse; + } + + // for 8-bit fonts: build the encoding + if (topDict.firstOp != 0x0c14 && topDict.firstOp != 0x0c1e) { + buildEncoding(); + if (!parsedOk) { + return gFalse; + } + } + + return parsedOk; +} + +void FoFiType1C::readTopDict() { + Type1CIndexVal topDictPtr; + int pos; + + topDict.firstOp = -1; + topDict.versionSID = 0; + topDict.noticeSID = 0; + topDict.copyrightSID = 0; + topDict.fullNameSID = 0; + topDict.familyNameSID = 0; + topDict.weightSID = 0; + topDict.isFixedPitch = 0; + topDict.italicAngle = 0; + topDict.underlinePosition = -100; + topDict.underlineThickness = 50; + topDict.paintType = 0; + topDict.charstringType = 2; + topDict.fontMatrix[0] = 0.001; + topDict.fontMatrix[1] = 0; + topDict.fontMatrix[2] = 0; + topDict.fontMatrix[3] = 0.001; + topDict.fontMatrix[4] = 0; + topDict.fontMatrix[5] = 0; + topDict.hasFontMatrix = gFalse; + topDict.uniqueID = 0; + topDict.fontBBox[0] = 0; + topDict.fontBBox[1] = 0; + topDict.fontBBox[2] = 0; + topDict.fontBBox[3] = 0; + topDict.strokeWidth = 0; + topDict.charsetOffset = 0; + topDict.encodingOffset = 0; + topDict.charStringsOffset = 0; + topDict.privateSize = 0; + topDict.privateOffset = 0; + topDict.registrySID = 0; + topDict.orderingSID = 0; + topDict.supplement = 0; + topDict.fdArrayOffset = 0; + topDict.fdSelectOffset = 0; + + getIndexVal(&topDictIdx, 0, &topDictPtr, &parsedOk); + pos = topDictPtr.pos; + nOps = 0; + while (pos < topDictPtr.pos + topDictPtr.len) { + pos = getOp(pos, gFalse, &parsedOk); + if (!parsedOk) { + break; + } + if (!ops[nOps - 1].isNum) { + --nOps; // drop the operator + if (topDict.firstOp < 0) { + topDict.firstOp = ops[nOps].op; + } + switch (ops[nOps].op) { + case 0x0000: topDict.versionSID = (int)ops[0].num; break; + case 0x0001: topDict.noticeSID = (int)ops[0].num; break; + case 0x0c00: topDict.copyrightSID = (int)ops[0].num; break; + case 0x0002: topDict.fullNameSID = (int)ops[0].num; break; + case 0x0003: topDict.familyNameSID = (int)ops[0].num; break; + case 0x0004: topDict.weightSID = (int)ops[0].num; break; + case 0x0c01: topDict.isFixedPitch = (int)ops[0].num; break; + case 0x0c02: topDict.italicAngle = ops[0].num; break; + case 0x0c03: topDict.underlinePosition = ops[0].num; break; + case 0x0c04: topDict.underlineThickness = ops[0].num; break; + case 0x0c05: topDict.paintType = (int)ops[0].num; break; + case 0x0c06: topDict.charstringType = (int)ops[0].num; break; + case 0x0c07: topDict.fontMatrix[0] = ops[0].num; + topDict.fontMatrix[1] = ops[1].num; + topDict.fontMatrix[2] = ops[2].num; + topDict.fontMatrix[3] = ops[3].num; + topDict.fontMatrix[4] = ops[4].num; + topDict.fontMatrix[5] = ops[5].num; + topDict.hasFontMatrix = gTrue; break; + case 0x000d: topDict.uniqueID = (int)ops[0].num; break; + case 0x0005: topDict.fontBBox[0] = ops[0].num; + topDict.fontBBox[1] = ops[1].num; + topDict.fontBBox[2] = ops[2].num; + topDict.fontBBox[3] = ops[3].num; break; + case 0x0c08: topDict.strokeWidth = ops[0].num; break; + case 0x000f: topDict.charsetOffset = (int)ops[0].num; break; + case 0x0010: topDict.encodingOffset = (int)ops[0].num; break; + case 0x0011: topDict.charStringsOffset = (int)ops[0].num; break; + case 0x0012: topDict.privateSize = (int)ops[0].num; + topDict.privateOffset = (int)ops[1].num; break; + case 0x0c1e: topDict.registrySID = (int)ops[0].num; + topDict.orderingSID = (int)ops[1].num; + topDict.supplement = (int)ops[2].num; break; + case 0x0c24: topDict.fdArrayOffset = (int)ops[0].num; break; + case 0x0c25: topDict.fdSelectOffset = (int)ops[0].num; break; + } + nOps = 0; + } + } +} + +// Read a CID font dict (FD) - this pulls out the private dict +// pointer, and reads the private dict. It also pulls the FontMatrix +// (if any) out of the FD. +void FoFiType1C::readFD(int offset, int length, Type1CPrivateDict *pDict) { + int pos, pSize, pOffset; + double fontMatrix[6]; + GBool hasFontMatrix; + + hasFontMatrix = gFalse; + pSize = pOffset = 0; + pos = offset; + nOps = 0; + while (pos < offset + length) { + pos = getOp(pos, gFalse, &parsedOk); + if (!parsedOk) { + return; + } + if (!ops[nOps - 1].isNum) { + if (ops[nOps - 1].op == 0x0012) { + if (nOps < 3) { + parsedOk = gFalse; + return; + } + pSize = (int)ops[0].num; + pOffset = (int)ops[1].num; + break; + } else if (ops[nOps - 1].op == 0x0c07) { + fontMatrix[0] = ops[0].num; + fontMatrix[1] = ops[1].num; + fontMatrix[2] = ops[2].num; + fontMatrix[3] = ops[3].num; + fontMatrix[4] = ops[4].num; + fontMatrix[5] = ops[5].num; + hasFontMatrix = gTrue; + } + nOps = 0; + } + } + readPrivateDict(pOffset, pSize, pDict); + if (hasFontMatrix) { + pDict->fontMatrix[0] = fontMatrix[0]; + pDict->fontMatrix[1] = fontMatrix[1]; + pDict->fontMatrix[2] = fontMatrix[2]; + pDict->fontMatrix[3] = fontMatrix[3]; + pDict->fontMatrix[4] = fontMatrix[4]; + pDict->fontMatrix[5] = fontMatrix[5]; + pDict->hasFontMatrix = gTrue; + } +} + +void FoFiType1C::readPrivateDict(int offset, int length, + Type1CPrivateDict *pDict) { + int pos; + + pDict->hasFontMatrix = gFalse; + pDict->nBlueValues = 0; + pDict->nOtherBlues = 0; + pDict->nFamilyBlues = 0; + pDict->nFamilyOtherBlues = 0; + pDict->blueScale = 0.039625; + pDict->blueShift = 7; + pDict->blueFuzz = 1; + pDict->hasStdHW = gFalse; + pDict->hasStdVW = gFalse; + pDict->nStemSnapH = 0; + pDict->nStemSnapV = 0; + pDict->hasForceBold = gFalse; + pDict->forceBoldThreshold = 0; + pDict->languageGroup = 0; + pDict->expansionFactor = 0.06; + pDict->initialRandomSeed = 0; + pDict->subrsOffset = 0; + pDict->defaultWidthX = 0; + pDict->defaultWidthXFP = gFalse; + pDict->nominalWidthX = 0; + pDict->nominalWidthXFP = gFalse; + + // no dictionary + if (offset == 0 || length == 0) { + return; + } + + pos = offset; + nOps = 0; + while (pos < offset + length) { + pos = getOp(pos, gFalse, &parsedOk); + if (!parsedOk) { + break; + } + if (!ops[nOps - 1].isNum) { + --nOps; // drop the operator + switch (ops[nOps].op) { + case 0x0006: + pDict->nBlueValues = getDeltaIntArray(pDict->blueValues, + type1CMaxBlueValues); + break; + case 0x0007: + pDict->nOtherBlues = getDeltaIntArray(pDict->otherBlues, + type1CMaxOtherBlues); + break; + case 0x0008: + pDict->nFamilyBlues = getDeltaIntArray(pDict->familyBlues, + type1CMaxBlueValues); + break; + case 0x0009: + pDict->nFamilyOtherBlues = getDeltaIntArray(pDict->familyOtherBlues, + type1CMaxOtherBlues); + break; + case 0x0c09: + pDict->blueScale = ops[0].num; + break; + case 0x0c0a: + pDict->blueShift = (int)ops[0].num; + break; + case 0x0c0b: + pDict->blueFuzz = (int)ops[0].num; + break; + case 0x000a: + pDict->stdHW = ops[0].num; + pDict->hasStdHW = gTrue; + break; + case 0x000b: + pDict->stdVW = ops[0].num; + pDict->hasStdVW = gTrue; + break; + case 0x0c0c: + pDict->nStemSnapH = getDeltaFPArray(pDict->stemSnapH, + type1CMaxStemSnap); + break; + case 0x0c0d: + pDict->nStemSnapV = getDeltaFPArray(pDict->stemSnapV, + type1CMaxStemSnap); + break; + case 0x0c0e: + pDict->forceBold = ops[0].num != 0; + pDict->hasForceBold = gTrue; + break; + case 0x0c0f: + pDict->forceBoldThreshold = ops[0].num; + break; + case 0x0c11: + pDict->languageGroup = (int)ops[0].num; + break; + case 0x0c12: + pDict->expansionFactor = ops[0].num; + break; + case 0x0c13: + pDict->initialRandomSeed = (int)ops[0].num; + break; + case 0x0013: + pDict->subrsOffset = offset + (int)ops[0].num; + break; + case 0x0014: + pDict->defaultWidthX = ops[0].num; + pDict->defaultWidthXFP = ops[0].isFP; + break; + case 0x0015: + pDict->nominalWidthX = ops[0].num; + pDict->nominalWidthXFP = ops[0].isFP; + break; + } + nOps = 0; + } + } +} + +void FoFiType1C::readFDSelect() { + int fdSelectFmt, pos, nRanges, gid0, gid1, fd, i, j; + + fdSelect = (Guchar *)gmalloc(nGlyphs); + if (topDict.fdSelectOffset == 0) { + for (i = 0; i < nGlyphs; ++i) { + fdSelect[i] = 0; + } + } else { + pos = topDict.fdSelectOffset; + fdSelectFmt = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + if (fdSelectFmt == 0) { + if (!checkRegion(pos, nGlyphs)) { + parsedOk = gFalse; + return; + } + memcpy(fdSelect, file + pos, nGlyphs); + } else if (fdSelectFmt == 3) { + nRanges = getU16BE(pos, &parsedOk); + pos += 2; + gid0 = getU16BE(pos, &parsedOk); + pos += 2; + for (i = 1; i <= nRanges; ++i) { + fd = getU8(pos++, &parsedOk); + gid1 = getU16BE(pos, &parsedOk); + if (!parsedOk) { + return; + } + pos += 2; + if (gid0 > gid1 || gid1 > nGlyphs) { + //~ error(-1, "Bad FDSelect table in CID font"); + parsedOk = gFalse; + return; + } + for (j = gid0; j < gid1; ++j) { + fdSelect[j] = fd; + } + gid0 = gid1; + } + } else { + //~ error(-1, "Unknown FDSelect table format in CID font"); + for (i = 0; i < nGlyphs; ++i) { + fdSelect[i] = 0; + } + } + } +} + +void FoFiType1C::buildEncoding() { + char buf[256]; + int nCodes, nRanges, encFormat; + int pos, c, sid, nLeft, nSups, i, j; + + if (topDict.encodingOffset == 0) { + encoding = fofiType1StandardEncoding; + + } else if (topDict.encodingOffset == 1) { + encoding = fofiType1ExpertEncoding; + + } else { + encoding = (char **)gmallocn(256, sizeof(char *)); + for (i = 0; i < 256; ++i) { + encoding[i] = NULL; + } + pos = topDict.encodingOffset; + encFormat = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + if ((encFormat & 0x7f) == 0) { + nCodes = 1 + getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + if (nCodes > nGlyphs) { + nCodes = nGlyphs; + } + for (i = 1; i < nCodes; ++i) { + c = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + if (encoding[c]) { + gfree(encoding[c]); + } + encoding[c] = copyString(getString(charset[i], buf, &parsedOk)); + } + } else if ((encFormat & 0x7f) == 1) { + nRanges = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + nCodes = 1; + for (i = 0; i < nRanges; ++i) { + c = getU8(pos++, &parsedOk); + nLeft = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) { + if (c < 256) { + if (encoding[c]) { + gfree(encoding[c]); + } + encoding[c] = copyString(getString(charset[nCodes], buf, + &parsedOk)); + } + ++nCodes; + ++c; + } + } + } + if (encFormat & 0x80) { + nSups = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + for (i = 0; i < nSups; ++i) { + c = getU8(pos++, &parsedOk);; + if (!parsedOk) { + return;; + } + sid = getU16BE(pos, &parsedOk); + pos += 2; + if (!parsedOk) { + return; + } + if (encoding[c]) { + gfree(encoding[c]); + } + encoding[c] = copyString(getString(sid, buf, &parsedOk)); + } + } + } +} + +GBool FoFiType1C::readCharset() { + int charsetFormat, c, pos; + int nLeft, i, j; + + if (topDict.charsetOffset == 0) { + charset = fofiType1CISOAdobeCharset; + } else if (topDict.charsetOffset == 1) { + charset = fofiType1CExpertCharset; + } else if (topDict.charsetOffset == 2) { + charset = fofiType1CExpertSubsetCharset; + } else { + charset = (Gushort *)gmallocn(nGlyphs, sizeof(Gushort)); + for (i = 0; i < nGlyphs; ++i) { + charset[i] = 0; + } + pos = topDict.charsetOffset; + charsetFormat = getU8(pos++, &parsedOk); + if (charsetFormat == 0) { + for (i = 1; i < nGlyphs; ++i) { + charset[i] = (Gushort)getU16BE(pos, &parsedOk); + pos += 2; + if (!parsedOk) { + break; + } + } + } else if (charsetFormat == 1) { + i = 1; + while (i < nGlyphs) { + c = getU16BE(pos, &parsedOk); + pos += 2; + nLeft = getU8(pos++, &parsedOk); + if (!parsedOk) { + break; + } + for (j = 0; j <= nLeft && i < nGlyphs; ++j) { + charset[i++] = (Gushort)c++; + } + } + } else if (charsetFormat == 2) { + i = 1; + while (i < nGlyphs) { + c = getU16BE(pos, &parsedOk); + pos += 2; + nLeft = getU16BE(pos, &parsedOk); + pos += 2; + if (!parsedOk) { + break; + } + for (j = 0; j <= nLeft && i < nGlyphs; ++j) { + charset[i++] = (Gushort)c++; + } + } + } + if (!parsedOk) { + gfree(charset); + charset = NULL; + return gFalse; + } + } + return gTrue; +} + +int FoFiType1C::getOp(int pos, GBool charstring, GBool *ok) { + static char nybChars[16] = "0123456789.ee -"; + Type1COp op; + char buf[65]; + int b0, b1, nyb0, nyb1, x, i; + + b0 = getU8(pos++, ok); + op.isNum = gTrue; + op.isFP = gFalse; + + if (b0 == 28) { + x = getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + if (x & 0x8000) { + x |= ~0xffff; + } + op.num = x; + + } else if (!charstring && b0 == 29) { + x = getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + if (x & 0x80000000) { + x |= ~0xffffffff; + } + op.num = x; + + } else if (!charstring && b0 == 30) { + i = 0; + do { + b1 = getU8(pos++, ok); + nyb0 = b1 >> 4; + nyb1 = b1 & 0x0f; + if (nyb0 == 0xf) { + break; + } + buf[i++] = nybChars[nyb0]; + if (i == 64) { + break; + } + if (nyb0 == 0xc) { + buf[i++] = '-'; + } + if (i == 64) { + break; + } + if (nyb1 == 0xf) { + break; + } + buf[i++] = nybChars[nyb1]; + if (i == 64) { + break; + } + if (nyb1 == 0xc) { + buf[i++] = '-'; + } + } while (i < 64); + buf[i] = '\0'; + op.num = atof(buf); + op.isFP = gTrue; + + } else if (b0 >= 32 && b0 <= 246) { + op.num = b0 - 139; + + } else if (b0 >= 247 && b0 <= 250) { + op.num = ((b0 - 247) << 8) + getU8(pos++, ok) + 108; + + } else if (b0 >= 251 && b0 <= 254) { + op.num = -((b0 - 251) << 8) - getU8(pos++, ok) - 108; + + } else if (charstring && b0 == 255) { + x = getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + if (x & 0x80000000) { + x |= ~0xffffffff; + } + op.num = (double)x / 65536.0; + op.isFP = gTrue; + + } else if (b0 == 12) { + op.isNum = gFalse; + op.op = 0x0c00 + getU8(pos++, ok); + + } else { + op.isNum = gFalse; + op.op = b0; + } + + if (nOps < 49) { + ops[nOps++] = op; + } + + return pos; +} + +// Convert the delta-encoded ops array to an array of ints. +int FoFiType1C::getDeltaIntArray(int *arr, int maxLen) { + int x; + int n, i; + + if ((n = nOps) > maxLen) { + n = maxLen; + } + x = 0; + for (i = 0; i < n; ++i) { + x += (int)ops[i].num; + arr[i] = x; + } + return n; +} + +// Convert the delta-encoded ops array to an array of doubles. +int FoFiType1C::getDeltaFPArray(double *arr, int maxLen) { + double x; + int n, i; + + if ((n = nOps) > maxLen) { + n = maxLen; + } + x = 0; + for (i = 0; i < n; ++i) { + x += ops[i].num; + arr[i] = x; + } + return n; +} + +void FoFiType1C::getIndex(int pos, Type1CIndex *idx, GBool *ok) { + idx->pos = pos; + idx->len = getU16BE(pos, ok); + if (idx->len == 0) { + // empty indexes are legal and contain just the length field + idx->offSize = 0; + idx->startPos = idx->endPos = pos + 2; + } else { + idx->offSize = getU8(pos + 2, ok); + if (idx->offSize < 1 || idx->offSize > 4) { + *ok = gFalse; + } + idx->startPos = pos + 3 + (idx->len + 1) * idx->offSize - 1; + if (idx->startPos < 0 || idx->startPos >= len) { + *ok = gFalse; + } + idx->endPos = idx->startPos + getUVarBE(pos + 3 + idx->len * idx->offSize, + idx->offSize, ok); + if (idx->endPos < idx->startPos || idx->endPos > len) { + *ok = gFalse; + } + } +} + +void FoFiType1C::getIndexVal(Type1CIndex *idx, int i, + Type1CIndexVal *val, GBool *ok) { + int pos0, pos1; + + if (i < 0 || i >= idx->len) { + *ok = gFalse; + return; + } + pos0 = idx->startPos + getUVarBE(idx->pos + 3 + i * idx->offSize, + idx->offSize, ok); + pos1 = idx->startPos + getUVarBE(idx->pos + 3 + (i + 1) * idx->offSize, + idx->offSize, ok); + if (pos0 < idx->startPos || pos0 > idx->endPos || + pos1 <= idx->startPos || pos1 > idx->endPos || + pos1 < pos0) { + *ok = gFalse; + } + val->pos = pos0; + val->len = pos1 - pos0; +} + +char *FoFiType1C::getString(int sid, char *buf, GBool *ok) { + Type1CIndexVal val; + int n; + + if (sid < 391) { + strcpy(buf, fofiType1CStdStrings[sid]); + } else { + sid -= 391; + getIndexVal(&stringIdx, sid, &val, ok); + if (*ok) { + if ((n = val.len) > 255) { + n = 255; + } + strncpy(buf, (char *)&file[val.pos], n); + buf[n] = '\0'; + } else { + buf[0] = '\0'; + } + } + return buf; +} diff --git a/kpdf/xpdf/fofi/FoFiType1C.h b/kpdf/xpdf/fofi/FoFiType1C.h new file mode 100644 index 00000000..eec27555 --- /dev/null +++ b/kpdf/xpdf/fofi/FoFiType1C.h @@ -0,0 +1,233 @@ +//======================================================================== +// +// FoFiType1C.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFITYPE1C_H +#define FOFITYPE1C_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "FoFiBase.h" + +class GString; + +//------------------------------------------------------------------------ + +struct Type1CIndex { + int pos; // absolute position in file + int len; // length (number of entries) + int offSize; // offset size + int startPos; // position of start of index data - 1 + int endPos; // position one byte past end of the index +}; + +struct Type1CIndexVal { + int pos; // absolute position in file + int len; // length, in bytes +}; + +struct Type1CTopDict { + int firstOp; + + int versionSID; + int noticeSID; + int copyrightSID; + int fullNameSID; + int familyNameSID; + int weightSID; + int isFixedPitch; + double italicAngle; + double underlinePosition; + double underlineThickness; + int paintType; + int charstringType; + double fontMatrix[6]; + GBool hasFontMatrix; // CID fonts are allowed to put their + // FontMatrix in the FD instead of the + // top dict + int uniqueID; + double fontBBox[4]; + double strokeWidth; + int charsetOffset; + int encodingOffset; + int charStringsOffset; + int privateSize; + int privateOffset; + + // CIDFont entries + int registrySID; + int orderingSID; + int supplement; + int fdArrayOffset; + int fdSelectOffset; +}; + +#define type1CMaxBlueValues 14 +#define type1CMaxOtherBlues 10 +#define type1CMaxStemSnap 12 + +struct Type1CPrivateDict { + double fontMatrix[6]; + GBool hasFontMatrix; + int blueValues[type1CMaxBlueValues]; + int nBlueValues; + int otherBlues[type1CMaxOtherBlues]; + int nOtherBlues; + int familyBlues[type1CMaxBlueValues]; + int nFamilyBlues; + int familyOtherBlues[type1CMaxOtherBlues]; + int nFamilyOtherBlues; + double blueScale; + int blueShift; + int blueFuzz; + double stdHW; + GBool hasStdHW; + double stdVW; + GBool hasStdVW; + double stemSnapH[type1CMaxStemSnap]; + int nStemSnapH; + double stemSnapV[type1CMaxStemSnap]; + int nStemSnapV; + GBool forceBold; + GBool hasForceBold; + double forceBoldThreshold; + int languageGroup; + double expansionFactor; + int initialRandomSeed; + int subrsOffset; + double defaultWidthX; + GBool defaultWidthXFP; + double nominalWidthX; + GBool nominalWidthXFP; +}; + +struct Type1COp { + GBool isNum; // true -> number, false -> operator + GBool isFP; // true -> floating point number, false -> int + union { + double num; // if num is true + int op; // if num is false + }; +}; + +struct Type1CEexecBuf { + FoFiOutputFunc outputFunc; + void *outputStream; + GBool ascii; // ASCII encoding? + Gushort r1; // eexec encryption key + int line; // number of eexec chars left on current line +}; + +//------------------------------------------------------------------------ +// FoFiType1C +//------------------------------------------------------------------------ + +class FoFiType1C: public FoFiBase { +public: + + // Create a FoFiType1C object from a memory buffer. + static FoFiType1C *make(char *fileA, int lenA); + + // Create a FoFiType1C object from a file on disk. + static FoFiType1C *load(char *fileName); + + virtual ~FoFiType1C(); + + // Return the font name. + char *getName(); + + // Return the encoding, as an array of 256 names (any of which may + // be NULL). This is only useful with 8-bit fonts. + char **getEncoding(); + + // Return the mapping from CIDs to GIDs, and return the number of + // CIDs in *. This is only useful for CID fonts. + Gushort *getCIDToGIDMap(int *nCIDs); + + // Convert to a Type 1 font, suitable for embedding in a PostScript + // file. This is only useful with 8-bit fonts. If is + // not NULL, it will be used in place of the encoding in the Type 1C + // font. If is true the eexec section will be hex-encoded, + // otherwise it will be left as binary data. If is non-NULL, + // it will be used as the PostScript font name. + void convertToType1(char *psName, char **newEncoding, GBool ascii, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 0 CIDFont, suitable for embedding in a + // PostScript file. will be used as the PostScript font + // name. + void convertToCIDType0(char *psName, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 0 (but non-CID) composite font, suitable for + // embedding in a PostScript file. will be used as the + // PostScript font name. + void convertToType0(char *psName, + FoFiOutputFunc outputFunc, void *outputStream); + +private: + + FoFiType1C(char *fileA, int lenA, GBool freeFileDataA); + void eexecCvtGlyph(Type1CEexecBuf *eb, char *glyphName, + int offset, int nBytes, + Type1CIndex *subrIdx, + Type1CPrivateDict *pDict); + void cvtGlyph(int offset, int nBytes, GString *charBuf, + Type1CIndex *subrIdx, Type1CPrivateDict *pDict, + GBool top); + void cvtGlyphWidth(GBool useOp, GString *charBuf, + Type1CPrivateDict *pDict); + void cvtNum(double x, GBool isFP, GString *charBuf); + void eexecWrite(Type1CEexecBuf *eb, char *s); + void eexecWriteCharstring(Type1CEexecBuf *eb, Guchar *s, int n); + GBool parse(); + void readTopDict(); + void readFD(int offset, int length, Type1CPrivateDict *pDict); + void readPrivateDict(int offset, int length, Type1CPrivateDict *pDict); + void readFDSelect(); + void buildEncoding(); + GBool readCharset(); + int getOp(int pos, GBool charstring, GBool *ok); + int getDeltaIntArray(int *arr, int maxLen); + int getDeltaFPArray(double *arr, int maxLen); + void getIndex(int pos, Type1CIndex *idx, GBool *ok); + void getIndexVal(Type1CIndex *idx, int i, Type1CIndexVal *val, GBool *ok); + char *getString(int sid, char *buf, GBool *ok); + + GString *name; + char **encoding; + + Type1CIndex nameIdx; + Type1CIndex topDictIdx; + Type1CIndex stringIdx; + Type1CIndex gsubrIdx; + Type1CIndex charStringsIdx; + + Type1CTopDict topDict; + Type1CPrivateDict *privateDicts; + + int nGlyphs; + int nFDs; + Guchar *fdSelect; + Gushort *charset; + int gsubrBias; + + GBool parsedOk; + + Type1COp ops[49]; // operands and operator + int nOps; // number of operands + int nHints; // number of hints for the current glyph + GBool firstOp; // true if we haven't hit the first op yet + GBool openPath; // true if there is an unclosed path +}; + +#endif diff --git a/kpdf/xpdf/fofi/Makefile.am b/kpdf/xpdf/fofi/Makefile.am new file mode 100644 index 00000000..7ca93922 --- /dev/null +++ b/kpdf/xpdf/fofi/Makefile.am @@ -0,0 +1,9 @@ +INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../goo $(all_includes) + +libfofi_la_LDFLAGS = $(all_libraries) +libfofi_la_SOURCES = FoFiBase.cc FoFiEncodings.cc FoFiTrueType.cc \ + FoFiType1.cc FoFiType1C.cc + +METASOURCES = AUTO + +noinst_LTLIBRARIES = libfofi.la diff --git a/kpdf/xpdf/goo/GHash.cc b/kpdf/xpdf/goo/GHash.cc new file mode 100644 index 00000000..b51a7643 --- /dev/null +++ b/kpdf/xpdf/goo/GHash.cc @@ -0,0 +1,380 @@ +//======================================================================== +// +// GHash.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "gmem.h" +#include "GString.h" +#include "GHash.h" + +//------------------------------------------------------------------------ + +struct GHashBucket { + GString *key; + union { + void *p; + int i; + } val; + GHashBucket *next; +}; + +struct GHashIter { + int h; + GHashBucket *p; +}; + +//------------------------------------------------------------------------ + +GHash::GHash(GBool deleteKeysA) { + int h; + + deleteKeys = deleteKeysA; + size = 7; + tab = (GHashBucket **)gmallocn(size, sizeof(GHashBucket *)); + for (h = 0; h < size; ++h) { + tab[h] = NULL; + } + len = 0; +} + +GHash::~GHash() { + GHashBucket *p; + int h; + + for (h = 0; h < size; ++h) { + while (tab[h]) { + p = tab[h]; + tab[h] = p->next; + if (deleteKeys) { + delete p->key; + } + delete p; + } + } + gfree(tab); +} + +void GHash::add(GString *key, void *val) { + GHashBucket *p; + int h; + + // expand the table if necessary + if (len >= size) { + expand(); + } + + // add the new symbol + p = new GHashBucket; + p->key = key; + p->val.p = val; + h = hash(key); + p->next = tab[h]; + tab[h] = p; + ++len; +} + +void GHash::add(GString *key, int val) { + GHashBucket *p; + int h; + + // expand the table if necessary + if (len >= size) { + expand(); + } + + // add the new symbol + p = new GHashBucket; + p->key = key; + p->val.i = val; + h = hash(key); + p->next = tab[h]; + tab[h] = p; + ++len; +} + +void GHash::replace(GString *key, void *val) { + GHashBucket *p; + int h; + + if ((p = find(key, &h))) { + p->val.p = val; + delete key; + } else { + add(key, val); + } +} + +void GHash::replace(GString *key, int val) { + GHashBucket *p; + int h; + + if ((p = find(key, &h))) { + p->val.i = val; + delete key; + } else { + add(key, val); + } +} + +void *GHash::lookup(GString *key) { + GHashBucket *p; + int h; + + if (!(p = find(key, &h))) { + return NULL; + } + return p->val.p; +} + +int GHash::lookupInt(GString *key) { + GHashBucket *p; + int h; + + if (!(p = find(key, &h))) { + return 0; + } + return p->val.i; +} + +void *GHash::lookup(char *key) { + GHashBucket *p; + int h; + + if (!(p = find(key, &h))) { + return NULL; + } + return p->val.p; +} + +int GHash::lookupInt(char *key) { + GHashBucket *p; + int h; + + if (!(p = find(key, &h))) { + return 0; + } + return p->val.i; +} + +void *GHash::remove(GString *key) { + GHashBucket *p; + GHashBucket **q; + void *val; + int h; + + if (!(p = find(key, &h))) { + return NULL; + } + q = &tab[h]; + while (*q != p) { + q = &((*q)->next); + } + *q = p->next; + if (deleteKeys) { + delete p->key; + } + val = p->val.p; + delete p; + --len; + return val; +} + +int GHash::removeInt(GString *key) { + GHashBucket *p; + GHashBucket **q; + int val; + int h; + + if (!(p = find(key, &h))) { + return 0; + } + q = &tab[h]; + while (*q != p) { + q = &((*q)->next); + } + *q = p->next; + if (deleteKeys) { + delete p->key; + } + val = p->val.i; + delete p; + --len; + return val; +} + +void *GHash::remove(char *key) { + GHashBucket *p; + GHashBucket **q; + void *val; + int h; + + if (!(p = find(key, &h))) { + return NULL; + } + q = &tab[h]; + while (*q != p) { + q = &((*q)->next); + } + *q = p->next; + if (deleteKeys) { + delete p->key; + } + val = p->val.p; + delete p; + --len; + return val; +} + +int GHash::removeInt(char *key) { + GHashBucket *p; + GHashBucket **q; + int val; + int h; + + if (!(p = find(key, &h))) { + return 0; + } + q = &tab[h]; + while (*q != p) { + q = &((*q)->next); + } + *q = p->next; + if (deleteKeys) { + delete p->key; + } + val = p->val.i; + delete p; + --len; + return val; +} + +void GHash::startIter(GHashIter **iter) { + *iter = new GHashIter; + (*iter)->h = -1; + (*iter)->p = NULL; +} + +GBool GHash::getNext(GHashIter **iter, GString **key, void **val) { + if (!*iter) { + return gFalse; + } + if ((*iter)->p) { + (*iter)->p = (*iter)->p->next; + } + while (!(*iter)->p) { + if (++(*iter)->h == size) { + delete *iter; + *iter = NULL; + return gFalse; + } + (*iter)->p = tab[(*iter)->h]; + } + *key = (*iter)->p->key; + *val = (*iter)->p->val.p; + return gTrue; +} + +GBool GHash::getNext(GHashIter **iter, GString **key, int *val) { + if (!*iter) { + return gFalse; + } + if ((*iter)->p) { + (*iter)->p = (*iter)->p->next; + } + while (!(*iter)->p) { + if (++(*iter)->h == size) { + delete *iter; + *iter = NULL; + return gFalse; + } + (*iter)->p = tab[(*iter)->h]; + } + *key = (*iter)->p->key; + *val = (*iter)->p->val.i; + return gTrue; +} + +void GHash::killIter(GHashIter **iter) { + delete *iter; + *iter = NULL; +} + +void GHash::expand() { + GHashBucket **oldTab; + GHashBucket *p; + int oldSize, h, i; + + oldSize = size; + oldTab = tab; + size = 2*size + 1; + tab = (GHashBucket **)gmallocn(size, sizeof(GHashBucket *)); + for (h = 0; h < size; ++h) { + tab[h] = NULL; + } + for (i = 0; i < oldSize; ++i) { + while (oldTab[i]) { + p = oldTab[i]; + oldTab[i] = oldTab[i]->next; + h = hash(p->key); + p->next = tab[h]; + tab[h] = p; + } + } + gfree(oldTab); +} + +GHashBucket *GHash::find(GString *key, int *h) { + GHashBucket *p; + + *h = hash(key); + for (p = tab[*h]; p; p = p->next) { + if (!p->key->cmp(key)) { + return p; + } + } + return NULL; +} + +GHashBucket *GHash::find(char *key, int *h) { + GHashBucket *p; + + *h = hash(key); + for (p = tab[*h]; p; p = p->next) { + if (!p->key->cmp(key)) { + return p; + } + } + return NULL; +} + +int GHash::hash(GString *key) { + char *p; + unsigned int h; + int i; + + h = 0; + for (p = key->getCString(), i = 0; i < key->getLength(); ++p, ++i) { + h = 17 * h + (int)(*p & 0xff); + } + return (int)(h % size); +} + +int GHash::hash(char *key) { + char *p; + unsigned int h; + + h = 0; + for (p = key; *p; ++p) { + h = 17 * h + (int)(*p & 0xff); + } + return (int)(h % size); +} diff --git a/kpdf/xpdf/goo/GHash.h b/kpdf/xpdf/goo/GHash.h new file mode 100644 index 00000000..31aba932 --- /dev/null +++ b/kpdf/xpdf/goo/GHash.h @@ -0,0 +1,78 @@ +//======================================================================== +// +// GHash.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef GHASH_H +#define GHASH_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +class GString; +struct GHashBucket; +struct GHashIter; + +//------------------------------------------------------------------------ + +class GHash { +public: + + GHash(GBool deleteKeysA = gFalse); + ~GHash(); + void add(GString *key, void *val); + void add(GString *key, int val); + void replace(GString *key, void *val); + void replace(GString *key, int val); + void *lookup(GString *key); + int lookupInt(GString *key); + void *lookup(char *key); + int lookupInt(char *key); + void *remove(GString *key); + int removeInt(GString *key); + void *remove(char *key); + int removeInt(char *key); + int getLength() { return len; } + void startIter(GHashIter **iter); + GBool getNext(GHashIter **iter, GString **key, void **val); + GBool getNext(GHashIter **iter, GString **key, int *val); + void killIter(GHashIter **iter); + +private: + + void expand(); + GHashBucket *find(GString *key, int *h); + GHashBucket *find(char *key, int *h); + int hash(GString *key); + int hash(char *key); + + GBool deleteKeys; // set if key strings should be deleted + int size; // number of buckets + int len; // number of entries + GHashBucket **tab; +}; + +#define deleteGHash(hash, T) \ + do { \ + GHash *_hash = (hash); \ + { \ + GHashIter *_iter; \ + GString *_key; \ + void *_p; \ + _hash->startIter(&_iter); \ + while (_hash->getNext(&_iter, &_key, &_p)) { \ + delete (T*)_p; \ + } \ + delete _hash; \ + } \ + } while(0) + +#endif diff --git a/kpdf/xpdf/goo/GList.cc b/kpdf/xpdf/goo/GList.cc new file mode 100644 index 00000000..fb5fd628 --- /dev/null +++ b/kpdf/xpdf/goo/GList.cc @@ -0,0 +1,97 @@ +//======================================================================== +// +// GList.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "GList.h" + +//------------------------------------------------------------------------ +// GList +//------------------------------------------------------------------------ + +GList::GList() { + size = 8; + data = (void **)gmallocn(size, sizeof(void*)); + length = 0; + inc = 0; +} + +GList::GList(int sizeA) { + size = sizeA; + data = (void **)gmallocn(size, sizeof(void*)); + length = 0; + inc = 0; +} + +GList::~GList() { + gfree(data); +} + +void GList::append(void *p) { + if (length >= size) { + expand(); + } + data[length++] = p; +} + +void GList::append(GList *list) { + int i; + + while (length + list->length > size) { + expand(); + } + for (i = 0; i < list->length; ++i) { + data[length++] = list->data[i]; + } +} + +void GList::insert(int i, void *p) { + if (length >= size) { + expand(); + } + if (i < length) { + memmove(data+i+1, data+i, (length - i) * sizeof(void *)); + } + data[i] = p; + ++length; +} + +void *GList::del(int i) { + void *p; + + p = data[i]; + if (i < length - 1) { + memmove(data+i, data+i+1, (length - i - 1) * sizeof(void *)); + } + --length; + if (size - length >= ((inc > 0) ? inc : size/2)) { + shrink(); + } + return p; +} + +void GList::sort(int (*cmp)(const void *obj1, const void *obj2)) { + qsort(data, length, sizeof(void *), cmp); +} + +void GList::expand() { + size += (inc > 0) ? inc : size; + data = (void **)greallocn(data, size, sizeof(void*)); +} + +void GList::shrink() { + size -= (inc > 0) ? inc : size/2; + data = (void **)greallocn(data, size, sizeof(void*)); +} diff --git a/kpdf/xpdf/goo/GList.h b/kpdf/xpdf/goo/GList.h new file mode 100644 index 00000000..e4d8ff8f --- /dev/null +++ b/kpdf/xpdf/goo/GList.h @@ -0,0 +1,96 @@ +//======================================================================== +// +// GList.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef GLIST_H +#define GLIST_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +//------------------------------------------------------------------------ +// GList +//------------------------------------------------------------------------ + +class GList { +public: + + // Create an empty list. + GList(); + + // Create an empty list with space for elements. + GList(int sizeA); + + // Destructor - does not free pointed-to objects. + ~GList(); + + //----- general + + // Get the number of elements. + int getLength() { return length; } + + //----- ordered list support + + // Return the th element. + // Assumes 0 <= i < length. + void *get(int i) { return data[i]; } + + // Append an element to the end of the list. + void append(void *p); + + // Append another list to the end of this one. + void append(GList *list); + + // Insert an element at index . + // Assumes 0 <= i <= length. + void insert(int i, void *p); + + // Deletes and returns the element at index . + // Assumes 0 <= i < length. + void *del(int i); + + // Sort the list accoring to the given comparison function. + // NB: this sorts an array of pointers, so the pointer args need to + // be double-dereferenced. + void sort(int (*cmp)(const void *ptr1, const void *ptr2)); + + //----- control + + // Set allocation increment to . If inc > 0, that many + // elements will be allocated every time the list is expanded. + // If inc <= 0, the list will be doubled in size. + void setAllocIncr(int incA) { inc = incA; } + +private: + + void expand(); + void shrink(); + + void **data; // the list elements + int size; // size of data array + int length; // number of elements on list + int inc; // allocation increment +}; + +#define deleteGList(list, T) \ + do { \ + GList *_list = (list); \ + { \ + int _i; \ + for (_i = 0; _i < _list->getLength(); ++_i) { \ + delete (T*)_list->get(_i); \ + } \ + delete _list; \ + } \ + } while (0) + +#endif diff --git a/kpdf/xpdf/goo/GMutex.h b/kpdf/xpdf/goo/GMutex.h new file mode 100644 index 00000000..7fa93d85 --- /dev/null +++ b/kpdf/xpdf/goo/GMutex.h @@ -0,0 +1,49 @@ +//======================================================================== +// +// GMutex.h +// +// Portable mutex macros. +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef GMUTEX_H +#define GMUTEX_H + +// Usage: +// +// GMutex m; +// gInitMutex(&m); +// ... +// gLockMutex(&m); +// ... critical section ... +// gUnlockMutex(&m); +// ... +// gDestroyMutex(&m); + +#ifdef WIN32 + +#include + +typedef CRITICAL_SECTION GMutex; + +#define gInitMutex(m) InitializeCriticalSection(m) +#define gDestroyMutex(m) DeleteCriticalSection(m) +#define gLockMutex(m) EnterCriticalSection(m) +#define gUnlockMutex(m) LeaveCriticalSection(m) + +#else // assume pthreads + +#include + +typedef pthread_mutex_t GMutex; + +#define gInitMutex(m) pthread_mutex_init(m, NULL) +#define gDestroyMutex(m) pthread_mutex_destroy(m) +#define gLockMutex(m) pthread_mutex_lock(m) +#define gUnlockMutex(m) pthread_mutex_unlock(m) + +#endif + +#endif diff --git a/kpdf/xpdf/goo/GString.cc b/kpdf/xpdf/goo/GString.cc new file mode 100644 index 00000000..e21fd3ea --- /dev/null +++ b/kpdf/xpdf/goo/GString.cc @@ -0,0 +1,718 @@ +//======================================================================== +// +// GString.cc +// +// Simple variable-length string type. +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include +#include +#include "gmem.h" +#include "GString.h" + +//------------------------------------------------------------------------ + +union GStringFormatArg { + int i; + Guint ui; + long l; + Gulong ul; + double f; + char c; + char *s; + GString *gs; +}; + +enum GStringFormatType { + fmtIntDecimal, + fmtIntHex, + fmtIntOctal, + fmtIntBinary, + fmtUIntDecimal, + fmtUIntHex, + fmtUIntOctal, + fmtUIntBinary, + fmtLongDecimal, + fmtLongHex, + fmtLongOctal, + fmtLongBinary, + fmtULongDecimal, + fmtULongHex, + fmtULongOctal, + fmtULongBinary, + fmtDouble, + fmtDoubleTrim, + fmtChar, + fmtString, + fmtGString, + fmtSpace +}; + +static char *formatStrings[] = { + "d", "x", "o", "b", "ud", "ux", "uo", "ub", + "ld", "lx", "lo", "lb", "uld", "ulx", "ulo", "ulb", + "f", "g", + "c", + "s", + "t", + "w", + NULL +}; + +//------------------------------------------------------------------------ + +static inline int size(int len) { + int delta; + for (delta = 8; delta < len && delta < 0x100000; delta <<= 1) ; + // this is ((len + 1) + (delta - 1)) & ~(delta - 1) + return (len + delta) & ~(delta - 1); +} + +inline void GString::resize(int length1) { + char *s1; + + if (!s) { + s = new char[size(length1)]; + } else if (size(length1) != size(length)) { + s1 = new char[size(length1)]; + if (length1 < length) { + memcpy(s1, s, length1); + s1[length1] = '\0'; + } else { + memcpy(s1, s, length + 1); + } + delete[] s; + s = s1; + } +} + +GString::GString() { + s = NULL; + resize(length = 0); + s[0] = '\0'; +} + +GString::GString(const char *sA) { + int n = strlen(sA); + + s = NULL; + resize(length = n); + memcpy(s, sA, n + 1); +} + +GString::GString(const char *sA, int lengthA) { + s = NULL; + resize(length = lengthA); + memcpy(s, sA, length * sizeof(char)); + s[length] = '\0'; +} + +GString::GString(GString *str, int idx, int lengthA) { + s = NULL; + resize(length = lengthA); + memcpy(s, str->getCString() + idx, length); + s[length] = '\0'; +} + +GString::GString(GString *str) { + s = NULL; + resize(length = str->getLength()); + memcpy(s, str->getCString(), length + 1); +} + +GString::GString(GString *str1, GString *str2) { + int n1 = str1->getLength(); + int n2 = str2->getLength(); + + s = NULL; + resize(length = n1 + n2); + memcpy(s, str1->getCString(), n1); + memcpy(s + n1, str2->getCString(), n2 + 1); +} + +GString *GString::fromInt(int x) { + char buf[24]; // enough space for 64-bit ints plus a little extra + char *p; + int len; + + formatInt(x, buf, sizeof(buf), gFalse, 0, 10, &p, &len); + return new GString(p, len); +} + +GString *GString::format(char *fmt, ...) { + va_list argList; + GString *s; + + s = new GString(); + va_start(argList, fmt); + s->appendfv(fmt, argList); + va_end(argList); + return s; +} + +GString *GString::formatv(char *fmt, va_list argList) { + GString *s; + + s = new GString(); + s->appendfv(fmt, argList); + return s; +} + +GString::~GString() { + delete[] s; +} + +GString *GString::clear() { + s[length = 0] = '\0'; + resize(0); + return this; +} + +GString *GString::append(char c) { + resize(length + 1); + s[length++] = c; + s[length] = '\0'; + return this; +} + +GString *GString::append(GString *str) { + int n = str->getLength(); + + resize(length + n); + memcpy(s + length, str->getCString(), n + 1); + length += n; + return this; +} + +GString *GString::append(const char *str) { + int n = strlen(str); + + resize(length + n); + memcpy(s + length, str, n + 1); + length += n; + return this; +} + +GString *GString::append(const char *str, int lengthA) { + resize(length + lengthA); + memcpy(s + length, str, lengthA); + length += lengthA; + s[length] = '\0'; + return this; +} + +GString *GString::appendf(char *fmt, ...) { + va_list argList; + + va_start(argList, fmt); + appendfv(fmt, argList); + va_end(argList); + return this; +} + +GString *GString::appendfv(char *fmt, va_list argList) { + GStringFormatArg *args; + int argsLen, argsSize; + GStringFormatArg arg; + int idx, width, prec; + GBool reverseAlign, zeroFill; + GStringFormatType ft; + char buf[65]; + int len, i; + char *p0, *p1, *str; + + argsLen = 0; + argsSize = 8; + args = (GStringFormatArg *)gmallocn(argsSize, sizeof(GStringFormatArg)); + + p0 = fmt; + while (*p0) { + if (*p0 == '{') { + ++p0; + if (*p0 == '{') { + ++p0; + append('{'); + } else { + + // parse the format string + if (!(*p0 >= '0' && *p0 <= '9')) { + break; + } + idx = *p0 - '0'; + for (++p0; *p0 >= '0' && *p0 <= '9'; ++p0) { + idx = 10 * idx + (*p0 - '0'); + } + if (*p0 != ':') { + break; + } + ++p0; + if (*p0 == '-') { + reverseAlign = gTrue; + ++p0; + } else { + reverseAlign = gFalse; + } + width = 0; + zeroFill = *p0 == '0'; + for (; *p0 >= '0' && *p0 <= '9'; ++p0) { + width = 10 * width + (*p0 - '0'); + } + if (*p0 == '.') { + ++p0; + prec = 0; + for (; *p0 >= '0' && *p0 <= '9'; ++p0) { + prec = 10 * prec + (*p0 - '0'); + } + } else { + prec = 0; + } + for (ft = (GStringFormatType)0; + formatStrings[ft]; + ft = (GStringFormatType)(ft + 1)) { + if (!strncmp(p0, formatStrings[ft], strlen(formatStrings[ft]))) { + break; + } + } + if (!formatStrings[ft]) { + break; + } + p0 += strlen(formatStrings[ft]); + if (*p0 != '}') { + break; + } + ++p0; + + // fetch the argument + if (idx > argsLen) { + break; + } + if (idx == argsLen) { + if (argsLen == argsSize) { + argsSize *= 2; + args = (GStringFormatArg *)greallocn(args, argsSize, + sizeof(GStringFormatArg)); + } + switch (ft) { + case fmtIntDecimal: + case fmtIntHex: + case fmtIntOctal: + case fmtIntBinary: + case fmtSpace: + args[argsLen].i = va_arg(argList, int); + break; + case fmtUIntDecimal: + case fmtUIntHex: + case fmtUIntOctal: + case fmtUIntBinary: + args[argsLen].ui = va_arg(argList, Guint); + break; + case fmtLongDecimal: + case fmtLongHex: + case fmtLongOctal: + case fmtLongBinary: + args[argsLen].l = va_arg(argList, long); + break; + case fmtULongDecimal: + case fmtULongHex: + case fmtULongOctal: + case fmtULongBinary: + args[argsLen].ul = va_arg(argList, Gulong); + break; + case fmtDouble: + case fmtDoubleTrim: + args[argsLen].f = va_arg(argList, double); + break; + case fmtChar: + args[argsLen].c = (char)va_arg(argList, int); + break; + case fmtString: + args[argsLen].s = va_arg(argList, char *); + break; + case fmtGString: + args[argsLen].gs = va_arg(argList, GString *); + break; + } + ++argsLen; + } + + // format the argument + arg = args[idx]; + switch (ft) { + case fmtIntDecimal: + formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 10, &str, &len); + break; + case fmtIntHex: + formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 16, &str, &len); + break; + case fmtIntOctal: + formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 8, &str, &len); + break; + case fmtIntBinary: + formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 2, &str, &len); + break; + case fmtUIntDecimal: + formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 10, + &str, &len); + break; + case fmtUIntHex: + formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 16, + &str, &len); + break; + case fmtUIntOctal: + formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 8, &str, &len); + break; + case fmtUIntBinary: + formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 2, &str, &len); + break; + case fmtLongDecimal: + formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 10, &str, &len); + break; + case fmtLongHex: + formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 16, &str, &len); + break; + case fmtLongOctal: + formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 8, &str, &len); + break; + case fmtLongBinary: + formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 2, &str, &len); + break; + case fmtULongDecimal: + formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 10, + &str, &len); + break; + case fmtULongHex: + formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 16, + &str, &len); + break; + case fmtULongOctal: + formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 8, &str, &len); + break; + case fmtULongBinary: + formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 2, &str, &len); + break; + case fmtDouble: + formatDouble(arg.f, buf, sizeof(buf), prec, gFalse, &str, &len); + break; + case fmtDoubleTrim: + formatDouble(arg.f, buf, sizeof(buf), prec, gTrue, &str, &len); + break; + case fmtChar: + buf[0] = arg.c; + str = buf; + len = 1; + reverseAlign = !reverseAlign; + break; + case fmtString: + str = arg.s; + len = strlen(str); + reverseAlign = !reverseAlign; + break; + case fmtGString: + str = arg.gs->getCString(); + len = arg.gs->getLength(); + reverseAlign = !reverseAlign; + break; + case fmtSpace: + str = buf; + len = 0; + width = arg.i; + break; + } + + // append the formatted arg, handling width and alignment + if (!reverseAlign && len < width) { + for (i = len; i < width; ++i) { + append(' '); + } + } + append(str, len); + if (reverseAlign && len < width) { + for (i = len; i < width; ++i) { + append(' '); + } + } + } + + } else if (*p0 == '}') { + ++p0; + if (*p0 == '}') { + ++p0; + } + append('}'); + + } else { + for (p1 = p0 + 1; *p1 && *p1 != '{' && *p1 != '}'; ++p1) ; + append(p0, p1 - p0); + p0 = p1; + } + } + + gfree(args); + return this; +} + +void GString::formatInt(long x, char *buf, int bufSize, + GBool zeroFill, int width, int base, + char **p, int *len) { + static char vals[17] = "0123456789abcdef"; + GBool neg; + int start, i, j; + + i = bufSize; + if ((neg = x < 0)) { + x = -x; + } + start = neg ? 1 : 0; + if (x == 0) { + buf[--i] = '0'; + } else { + while (i > start && x) { + buf[--i] = vals[x % base]; + x /= base; + } + } + if (zeroFill) { + for (j = bufSize - i; i > start && j < width - start; ++j) { + buf[--i] = '0'; + } + } + if (neg) { + buf[--i] = '-'; + } + *p = buf + i; + *len = bufSize - i; +} + +void GString::formatUInt(Gulong x, char *buf, int bufSize, + GBool zeroFill, int width, int base, + char **p, int *len) { + static char vals[17] = "0123456789abcdef"; + int i, j; + + i = bufSize; + if (x == 0) { + buf[--i] = '0'; + } else { + while (i > 0 && x) { + buf[--i] = vals[x % base]; + x /= base; + } + } + if (zeroFill) { + for (j = bufSize - i; i > 0 && j < width; ++j) { + buf[--i] = '0'; + } + } + *p = buf + i; + *len = bufSize - i; +} + +void GString::formatDouble(double x, char *buf, int bufSize, int prec, + GBool trim, char **p, int *len) { + GBool neg, started; + double x2; + int d, i, j; + + if ((neg = x < 0)) { + x = -x; + } + x = floor(x * pow(10, prec) + 0.5); + i = bufSize; + started = !trim; + for (j = 0; j < prec && i > 1; ++j) { + x2 = floor(0.1 * (x + 0.5)); + d = (int)floor(x - 10 * x2 + 0.5); + if (started || d != 0) { + buf[--i] = '0' + d; + started = gTrue; + } + x = x2; + } + if (i > 1 && started) { + buf[--i] = '.'; + } + if (i > 1) { + do { + x2 = floor(0.1 * (x + 0.5)); + d = (int)floor(x - 10 * x2 + 0.5); + buf[--i] = '0' + d; + x = x2; + } while (i > 1 && x); + } + if (neg) { + buf[--i] = '-'; + } + *p = buf + i; + *len = bufSize - i; +} + +GString *GString::insert(int i, char c) { + int j; + + resize(length + 1); + for (j = length + 1; j > i; --j) + s[j] = s[j-1]; + s[i] = c; + ++length; + return this; +} + +GString *GString::insert(int i, GString *str) { + int n = str->getLength(); + int j; + + resize(length + n); + for (j = length; j >= i; --j) + s[j+n] = s[j]; + memcpy(s+i, str->getCString(), n); + length += n; + return this; +} + +GString *GString::insert(int i, const char *str) { + int n = strlen(str); + int j; + + resize(length + n); + for (j = length; j >= i; --j) + s[j+n] = s[j]; + memcpy(s+i, str, n); + length += n; + return this; +} + +GString *GString::insert(int i, const char *str, int lengthA) { + int j; + + resize(length + lengthA); + for (j = length; j >= i; --j) + s[j+lengthA] = s[j]; + memcpy(s+i, str, lengthA); + length += lengthA; + return this; +} + +GString *GString::del(int i, int n) { + int j; + + if (n > 0) { + if (i + n > length) { + n = length - i; + } + for (j = i; j <= length - n; ++j) { + s[j] = s[j + n]; + } + resize(length -= n); + } + return this; +} + +GString *GString::upperCase() { + int i; + + for (i = 0; i < length; ++i) { + if (islower(s[i])) + s[i] = toupper(s[i]); + } + return this; +} + +GString *GString::lowerCase() { + int i; + + for (i = 0; i < length; ++i) { + if (isupper(s[i])) + s[i] = tolower(s[i]); + } + return this; +} + +int GString::cmp(GString *str) { + int n1, n2, i, x; + char *p1, *p2; + + n1 = length; + n2 = str->length; + for (i = 0, p1 = s, p2 = str->s; i < n1 && i < n2; ++i, ++p1, ++p2) { + x = *p1 - *p2; + if (x != 0) { + return x; + } + } + return n1 - n2; +} + +int GString::cmpN(GString *str, int n) { + int n1, n2, i, x; + char *p1, *p2; + + n1 = length; + n2 = str->length; + for (i = 0, p1 = s, p2 = str->s; + i < n1 && i < n2 && i < n; + ++i, ++p1, ++p2) { + x = *p1 - *p2; + if (x != 0) { + return x; + } + } + if (i == n) { + return 0; + } + return n1 - n2; +} + +int GString::cmp(const char *sA) { + int n1, i, x; + const char *p1, *p2; + + n1 = length; + for (i = 0, p1 = s, p2 = sA; i < n1 && *p2; ++i, ++p1, ++p2) { + x = *p1 - *p2; + if (x != 0) { + return x; + } + } + if (i < n1) { + return 1; + } + if (*p2) { + return -1; + } + return 0; +} + +int GString::cmpN(const char *sA, int n) { + int n1, i, x; + const char *p1, *p2; + + n1 = length; + for (i = 0, p1 = s, p2 = sA; i < n1 && *p2 && i < n; ++i, ++p1, ++p2) { + x = *p1 - *p2; + if (x != 0) { + return x; + } + } + if (i == n) { + return 0; + } + if (i < n1) { + return 1; + } + if (*p2) { + return -1; + } + return 0; +} diff --git a/kpdf/xpdf/goo/GString.h b/kpdf/xpdf/goo/GString.h new file mode 100644 index 00000000..dd22e2d8 --- /dev/null +++ b/kpdf/xpdf/goo/GString.h @@ -0,0 +1,136 @@ +//======================================================================== +// +// GString.h +// +// Simple variable-length string type. +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef GSTRING_H +#define GSTRING_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include +#include "gtypes.h" + +class GString { +public: + + // Create an empty string. + GString(); + + // Create a string from a C string. + GString(const char *sA); + + // Create a string from chars at . This string + // can contain null characters. + GString(const char *sA, int lengthA); + + // Create a string from chars at in . + GString(GString *str, int idx, int lengthA); + + // Copy a string. + GString(GString *str); + GString *copy() { return new GString(this); } + + // Concatenate two strings. + GString(GString *str1, GString *str2); + + // Convert an integer to a string. + static GString *fromInt(int x); + + // Create a formatted string. Similar to printf, but without the + // string overflow issues. Formatting elements consist of: + // {:[][.]} + // where: + // - is the argument number (arg 0 is the first argument + // following the format string) -- NB: args must be first used in + // order; they can be reused in any order + // - is the field width -- negative to reverse the alignment; + // starting with a leading zero to zero-fill (for integers) + // - is the number of digits to the right of the decimal + // point (for floating point numbers) + // - is one of: + // d, x, o, b -- int in decimal, hex, octal, binary + // ud, ux, uo, ub -- unsigned int + // ld, lx, lo, lb, uld, ulx, ulo, ulb -- long, unsigned long + // f, g -- double + // c -- char + // s -- string (char *) + // t -- GString * + // w -- blank space; arg determines width + // To get literal curly braces, use {{ or }}. + static GString *format(char *fmt, ...); + static GString *formatv(char *fmt, va_list argList); + + // Destructor. + ~GString(); + + // Get length. + int getLength() { return length; } + + // Get C string. + char *getCString() { return s; } + + // Get th character. + char getChar(int i) { return s[i]; } + + // Change th character. + void setChar(int i, char c) { s[i] = c; } + + // Clear string to zero length. + GString *clear(); + + // Append a character or string. + GString *append(char c); + GString *append(GString *str); + GString *append(const char *str); + GString *append(const char *str, int lengthA); + + // Append a formatted string. + GString *appendf(char *fmt, ...); + GString *appendfv(char *fmt, va_list argList); + + // Insert a character or string. + GString *insert(int i, char c); + GString *insert(int i, GString *str); + GString *insert(int i, const char *str); + GString *insert(int i, const char *str, int lengthA); + + // Delete a character or range of characters. + GString *del(int i, int n = 1); + + // Convert string to all-upper/all-lower case. + GString *upperCase(); + GString *lowerCase(); + + // Compare two strings: -1:< 0:= +1:> + int cmp(GString *str); + int cmpN(GString *str, int n); + int cmp(const char *sA); + int cmpN(const char *sA, int n); + +private: + + int length; + char *s; + + void resize(int length1); + static void formatInt(long x, char *buf, int bufSize, + GBool zeroFill, int width, int base, + char **p, int *len); + static void formatUInt(Gulong x, char *buf, int bufSize, + GBool zeroFill, int width, int base, + char **p, int *len); + static void formatDouble(double x, char *buf, int bufSize, int prec, + GBool trim, char **p, int *len); +}; + +#endif diff --git a/kpdf/xpdf/goo/Makefile.am b/kpdf/xpdf/goo/Makefile.am new file mode 100644 index 00000000..04933cee --- /dev/null +++ b/kpdf/xpdf/goo/Makefile.am @@ -0,0 +1,5 @@ +INCLUDES = -I$(srcdir)/.. + +libgoo_la_SOURCES = GHash.cc GList.cc GString.cc gfile.cc gmem.cc gmempp.cc + +noinst_LTLIBRARIES = libgoo.la diff --git a/kpdf/xpdf/goo/gfile.cc b/kpdf/xpdf/goo/gfile.cc new file mode 100644 index 00000000..54a7be3d --- /dev/null +++ b/kpdf/xpdf/goo/gfile.cc @@ -0,0 +1,731 @@ +//======================================================================== +// +// gfile.cc +// +// Miscellaneous file and directory name manipulation. +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef WIN32 +# include +#else +# if defined(MACOS) +# include +# elif !defined(ACORN) +# include +# include +# include +# endif +# include +# include +# if !defined(VMS) && !defined(ACORN) && !defined(MACOS) +# include +# endif +# if defined(VMS) && (__DECCXX_VER < 50200000) +# include +# endif +#endif // WIN32 +#include "GString.h" +#include "gfile.h" + +// Some systems don't define this, so just make it something reasonably +// large. +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +//------------------------------------------------------------------------ + +GString *getHomeDir() { +#ifdef VMS + //---------- VMS ---------- + return new GString("SYS$LOGIN:"); + +#elif defined(__EMX__) || defined(WIN32) + //---------- OS/2+EMX and Win32 ---------- + char *s; + GString *ret; + + if ((s = getenv("HOME"))) + ret = new GString(s); + else + ret = new GString("."); + return ret; + +#elif defined(ACORN) + //---------- RISCOS ---------- + return new GString("@"); + +#elif defined(MACOS) + //---------- MacOS ---------- + return new GString(":"); + +#else + //---------- Unix ---------- + char *s; + struct passwd *pw; + GString *ret; + + if ((s = getenv("HOME"))) { + ret = new GString(s); + } else { + if ((s = getenv("USER"))) + pw = getpwnam(s); + else + pw = getpwuid(getuid()); + if (pw) + ret = new GString(pw->pw_dir); + else + ret = new GString("."); + } + return ret; +#endif +} + +GString *getCurrentDir() { + char buf[PATH_MAX+1]; + +#if defined(__EMX__) + if (_getcwd2(buf, sizeof(buf))) +#elif defined(WIN32) + if (GetCurrentDirectory(sizeof(buf), buf)) +#elif defined(ACORN) + if (strcpy(buf, "@")) +#elif defined(MACOS) + if (strcpy(buf, ":")) +#else + if (getcwd(buf, sizeof(buf))) +#endif + return new GString(buf); + return new GString(); +} + +GString *appendToPath(GString *path, char *fileName) { +#if defined(VMS) + //---------- VMS ---------- + //~ this should handle everything necessary for file + //~ requesters, but it's certainly not complete + char *p0, *p1, *p2; + char *q1; + + p0 = path->getCString(); + p1 = p0 + path->getLength() - 1; + if (!strcmp(fileName, "-")) { + if (*p1 == ']') { + for (p2 = p1; p2 > p0 && *p2 != '.' && *p2 != '['; --p2) ; + if (*p2 == '[') + ++p2; + path->del(p2 - p0, p1 - p2); + } else if (*p1 == ':') { + path->append("[-]"); + } else { + path->clear(); + path->append("[-]"); + } + } else if ((q1 = strrchr(fileName, '.')) && !strncmp(q1, ".DIR;", 5)) { + if (*p1 == ']') { + path->insert(p1 - p0, '.'); + path->insert(p1 - p0 + 1, fileName, q1 - fileName); + } else if (*p1 == ':') { + path->append('['); + path->append(']'); + path->append(fileName, q1 - fileName); + } else { + path->clear(); + path->append(fileName, q1 - fileName); + } + } else { + if (*p1 != ']' && *p1 != ':') + path->clear(); + path->append(fileName); + } + return path; + +#elif defined(WIN32) + //---------- Win32 ---------- + GString *tmp; + char buf[256]; + char *fp; + + tmp = new GString(path); + tmp->append('/'); + tmp->append(fileName); + GetFullPathName(tmp->getCString(), sizeof(buf), buf, &fp); + delete tmp; + path->clear(); + path->append(buf); + return path; + +#elif defined(ACORN) + //---------- RISCOS ---------- + char *p; + int i; + + path->append("."); + i = path->getLength(); + path->append(fileName); + for (p = path->getCString() + i; *p; ++p) { + if (*p == '/') { + *p = '.'; + } else if (*p == '.') { + *p = '/'; + } + } + return path; + +#elif defined(MACOS) + //---------- MacOS ---------- + char *p; + int i; + + path->append(":"); + i = path->getLength(); + path->append(fileName); + for (p = path->getCString() + i; *p; ++p) { + if (*p == '/') { + *p = ':'; + } else if (*p == '.') { + *p = ':'; + } + } + return path; + +#elif defined(__EMX__) + //---------- OS/2+EMX ---------- + int i; + + // appending "." does nothing + if (!strcmp(fileName, ".")) + return path; + + // appending ".." goes up one directory + if (!strcmp(fileName, "..")) { + for (i = path->getLength() - 2; i >= 0; --i) { + if (path->getChar(i) == '/' || path->getChar(i) == '\\' || + path->getChar(i) == ':') + break; + } + if (i <= 0) { + if (path->getChar(0) == '/' || path->getChar(0) == '\\') { + path->del(1, path->getLength() - 1); + } else if (path->getLength() >= 2 && path->getChar(1) == ':') { + path->del(2, path->getLength() - 2); + } else { + path->clear(); + path->append(".."); + } + } else { + if (path->getChar(i-1) == ':') + ++i; + path->del(i, path->getLength() - i); + } + return path; + } + + // otherwise, append "/" and new path component + if (path->getLength() > 0 && + path->getChar(path->getLength() - 1) != '/' && + path->getChar(path->getLength() - 1) != '\\') + path->append('/'); + path->append(fileName); + return path; + +#else + //---------- Unix ---------- + int i; + + // appending "." does nothing + if (!strcmp(fileName, ".")) + return path; + + // appending ".." goes up one directory + if (!strcmp(fileName, "..")) { + for (i = path->getLength() - 2; i >= 0; --i) { + if (path->getChar(i) == '/') + break; + } + if (i <= 0) { + if (path->getChar(0) == '/') { + path->del(1, path->getLength() - 1); + } else { + path->clear(); + path->append(".."); + } + } else { + path->del(i, path->getLength() - i); + } + return path; + } + + // otherwise, append "/" and new path component + if (path->getLength() > 0 && + path->getChar(path->getLength() - 1) != '/') + path->append('/'); + path->append(fileName); + return path; +#endif +} + +GString *grabPath(char *fileName) { +#ifdef VMS + //---------- VMS ---------- + char *p; + + if ((p = strrchr(fileName, ']'))) + return new GString(fileName, p + 1 - fileName); + if ((p = strrchr(fileName, ':'))) + return new GString(fileName, p + 1 - fileName); + return new GString(); + +#elif defined(__EMX__) || defined(WIN32) + //---------- OS/2+EMX and Win32 ---------- + char *p; + + if ((p = strrchr(fileName, '/'))) + return new GString(fileName, p - fileName); + if ((p = strrchr(fileName, '\\'))) + return new GString(fileName, p - fileName); + if ((p = strrchr(fileName, ':'))) + return new GString(fileName, p + 1 - fileName); + return new GString(); + +#elif defined(ACORN) + //---------- RISCOS ---------- + char *p; + + if ((p = strrchr(fileName, '.'))) + return new GString(fileName, p - fileName); + return new GString(); + +#elif defined(MACOS) + //---------- MacOS ---------- + char *p; + + if ((p = strrchr(fileName, ':'))) + return new GString(fileName, p - fileName); + return new GString(); + +#else + //---------- Unix ---------- + char *p; + + if ((p = strrchr(fileName, '/'))) + return new GString(fileName, p - fileName); + return new GString(); +#endif +} + +GBool isAbsolutePath(char *path) { +#ifdef VMS + //---------- VMS ---------- + return strchr(path, ':') || + (path[0] == '[' && path[1] != '.' && path[1] != '-'); + +#elif defined(__EMX__) || defined(WIN32) + //---------- OS/2+EMX and Win32 ---------- + return path[0] == '/' || path[0] == '\\' || path[1] == ':'; + +#elif defined(ACORN) + //---------- RISCOS ---------- + return path[0] == '$'; + +#elif defined(MACOS) + //---------- MacOS ---------- + return path[0] != ':'; + +#else + //---------- Unix ---------- + return path[0] == '/'; +#endif +} + +GString *makePathAbsolute(GString *path) { +#ifdef VMS + //---------- VMS ---------- + char buf[PATH_MAX+1]; + + if (!isAbsolutePath(path->getCString())) { + if (getcwd(buf, sizeof(buf))) { + path->insert(0, buf); + } + } + return path; + +#elif defined(WIN32) + //---------- Win32 ---------- + char buf[_MAX_PATH]; + char *fp; + + buf[0] = '\0'; + if (!GetFullPathName(path->getCString(), _MAX_PATH, buf, &fp)) { + path->clear(); + return path; + } + path->clear(); + path->append(buf); + return path; + +#elif defined(ACORN) + //---------- RISCOS ---------- + path->insert(0, '@'); + return path; + +#elif defined(MACOS) + //---------- MacOS ---------- + path->del(0, 1); + return path; + +#else + //---------- Unix and OS/2+EMX ---------- + struct passwd *pw; + char buf[PATH_MAX+1]; + GString *s; + char *p1, *p2; + int n; + + if (path->getChar(0) == '~') { + if (path->getChar(1) == '/' || +#ifdef __EMX__ + path->getChar(1) == '\\' || +#endif + path->getLength() == 1) { + path->del(0, 1); + s = getHomeDir(); + path->insert(0, s); + delete s; + } else { + p1 = path->getCString() + 1; +#ifdef __EMX__ + for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ; +#else + for (p2 = p1; *p2 && *p2 != '/'; ++p2) ; +#endif + if ((n = p2 - p1) > PATH_MAX) + n = PATH_MAX; + strncpy(buf, p1, n); + buf[n] = '\0'; + if ((pw = getpwnam(buf))) { + path->del(0, p2 - p1 + 1); + path->insert(0, pw->pw_dir); + } + } + } else if (!isAbsolutePath(path->getCString())) { + if (getcwd(buf, sizeof(buf))) { +#ifndef __EMX__ + path->insert(0, '/'); +#endif + path->insert(0, buf); + } + } + return path; +#endif +} + +time_t getModTime(char *fileName) { +#ifdef WIN32 + //~ should implement this, but it's (currently) only used in xpdf + return 0; +#else + struct stat statBuf; + + if (stat(fileName, &statBuf)) { + return 0; + } + return statBuf.st_mtime; +#endif +} + +GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) { +#if defined(WIN32) + //---------- Win32 ---------- + char *tempDir; + GString *s, *s2; + char buf[32]; + FILE *f2; + int t, i; + + // this has the standard race condition problem, but I haven't found + // a better way to generate temp file names with extensions on + // Windows + if ((tempDir = getenv("TEMP"))) { + s = new GString(tempDir); + s->append('\\'); + } else { + s = new GString(); + } + s->append("x"); + t = (int)time(NULL); + for (i = 0; i < 1000; ++i) { + sprintf(buf, "%d", t + i); + s2 = s->copy()->append(buf); + if (ext) { + s2->append(ext); + } + if (!(f2 = fopen(s2->getCString(), "r"))) { + if (!(f2 = fopen(s2->getCString(), mode))) { + delete s2; + delete s; + return gFalse; + } + *name = s2; + *f = f2; + delete s; + return gTrue; + } + fclose(f2); + delete s2; + } + delete s; + return gFalse; +#elif defined(VMS) || defined(__EMX__) || defined(ACORN) || defined(MACOS) + //---------- non-Unix ---------- + char *s; + + // There is a security hole here: an attacker can create a symlink + // with this file name after the tmpnam call and before the fopen + // call. I will happily accept fixes to this function for non-Unix + // OSs. + if (!(s = tmpnam(NULL))) { + return gFalse; + } + *name = new GString(s); + if (ext) { + (*name)->append(ext); + } + if (!(*f = fopen((*name)->getCString(), mode))) { + delete (*name); + return gFalse; + } + return gTrue; +#else + //---------- Unix ---------- + char *s; + int fd; + + if (ext) { +#if HAVE_MKSTEMPS + if ((s = getenv("TMPDIR"))) { + *name = new GString(s); + } else { + *name = new GString("/tmp"); + } + (*name)->append("/XXXXXX")->append(ext); + fd = mkstemps((*name)->getCString(), strlen(ext)); +#else + if (!(s = tmpnam(NULL))) { + return gFalse; + } + *name = new GString(s); + (*name)->append(ext); + fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600); +#endif + } else { +#if HAVE_MKSTEMP + if ((s = getenv("TMPDIR"))) { + *name = new GString(s); + } else { + *name = new GString("/tmp"); + } + (*name)->append("/XXXXXX"); + fd = mkstemp((*name)->getCString()); +#else // HAVE_MKSTEMP + if (!(s = tmpnam(NULL))) { + return gFalse; + } + *name = new GString(s); + fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600); +#endif // HAVE_MKSTEMP + } + if (fd < 0 || !(*f = fdopen(fd, mode))) { + delete *name; + return gFalse; + } + return gTrue; +#endif +} + +GBool executeCommand(char *cmd) { +#ifdef VMS + return system(cmd) ? gTrue : gFalse; +#else + return system(cmd) ? gFalse : gTrue; +#endif +} + +char *getLine(char *buf, int size, FILE *f) { + int c, i; + + i = 0; + while (i < size - 1) { + if ((c = fgetc(f)) == EOF) { + break; + } + buf[i++] = (char)c; + if (c == '\x0a') { + break; + } + if (c == '\x0d') { + c = fgetc(f); + if (c == '\x0a' && i < size - 1) { + buf[i++] = (char)c; + } else if (c != EOF) { + ungetc(c, f); + } + break; + } + } + buf[i] = '\0'; + if (i == 0) { + return NULL; + } + return buf; +} + +//------------------------------------------------------------------------ +// GDir and GDirEntry +//------------------------------------------------------------------------ + +GDirEntry::GDirEntry(char *dirPath, char *nameA, GBool doStat) { +#ifdef VMS + char *p; +#elif defined(WIN32) + int fa; + GString *s; +#elif defined(ACORN) +#else + struct stat st; + GString *s; +#endif + + name = new GString(nameA); + dir = gFalse; + if (doStat) { +#ifdef VMS + if (!strcmp(nameA, "-") || + ((p = strrchr(nameA, '.')) && !strncmp(p, ".DIR;", 5))) + dir = gTrue; +#elif defined(ACORN) +#else + s = new GString(dirPath); + appendToPath(s, nameA); +#ifdef WIN32 + fa = GetFileAttributes(s->getCString()); + dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY)); +#else + if (stat(s->getCString(), &st) == 0) + dir = S_ISDIR(st.st_mode); +#endif + delete s; +#endif + } +} + +GDirEntry::~GDirEntry() { + delete name; +} + +GDir::GDir(char *name, GBool doStatA) { + path = new GString(name); + doStat = doStatA; +#if defined(WIN32) + GString *tmp; + + tmp = path->copy(); + tmp->append("/*.*"); + hnd = FindFirstFile(tmp->getCString(), &ffd); + delete tmp; +#elif defined(ACORN) +#elif defined(MACOS) +#else + dir = opendir(name); +#ifdef VMS + needParent = strchr(name, '[') != NULL; +#endif +#endif +} + +GDir::~GDir() { + delete path; +#if defined(WIN32) + if (hnd) { + FindClose(hnd); + hnd = NULL; + } +#elif defined(ACORN) +#elif defined(MACOS) +#else + if (dir) + closedir(dir); +#endif +} + +GDirEntry *GDir::getNextEntry() { + GDirEntry *e; + +#if defined(WIN32) + if (hnd) { + e = new GDirEntry(path->getCString(), ffd.cFileName, doStat); + if (hnd && !FindNextFile(hnd, &ffd)) { + FindClose(hnd); + hnd = NULL; + } + } else { + e = NULL; + } +#elif defined(ACORN) +#elif defined(MACOS) +#elif defined(VMS) + struct dirent *ent; + e = NULL; + if (dir) { + if (needParent) { + e = new GDirEntry(path->getCString(), "-", doStat); + needParent = gFalse; + return e; + } + ent = readdir(dir); + if (ent) { + e = new GDirEntry(path->getCString(), ent->d_name, doStat); + } + } +#else + struct dirent *ent; + e = NULL; + if (dir) { + ent = (struct dirent *)readdir(dir); + if (ent && !strcmp(ent->d_name, ".")) { + ent = (struct dirent *)readdir(dir); + } + if (ent) { + e = new GDirEntry(path->getCString(), ent->d_name, doStat); + } + } +#endif + + return e; +} + +void GDir::rewind() { +#ifdef WIN32 + GString *tmp; + + if (hnd) + FindClose(hnd); + tmp = path->copy(); + tmp->append("/*.*"); + hnd = FindFirstFile(tmp->getCString(), &ffd); + delete tmp; +#elif defined(ACORN) +#elif defined(MACOS) +#else + if (dir) + rewinddir(dir); +#ifdef VMS + needParent = strchr(path->getCString(), '[') != NULL; +#endif +#endif +} diff --git a/kpdf/xpdf/goo/gfile.h b/kpdf/xpdf/goo/gfile.h new file mode 100644 index 00000000..82f1d7a9 --- /dev/null +++ b/kpdf/xpdf/goo/gfile.h @@ -0,0 +1,138 @@ +//======================================================================== +// +// gfile.h +// +// Miscellaneous file and directory name manipulation. +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef GFILE_H +#define GFILE_H + +#include +#include +#include +#if defined(WIN32) +# include +# ifdef FPTEX +# include +# else +# include +# endif +#elif defined(ACORN) +#elif defined(MACOS) +# include +#else +# include +# include +# ifdef VMS +# include "vms_dirent.h" +# elif HAVE_DIRENT_H +# include +# define NAMLEN(d) strlen((d)->d_name) +# else +# define dirent direct +# define NAMLEN(d) (d)->d_namlen +# if HAVE_SYS_NDIR_H +# include +# endif +# if HAVE_SYS_DIR_H +# include +# endif +# if HAVE_NDIR_H +# include +# endif +# endif +#endif +#include "gtypes.h" + +class GString; + +//------------------------------------------------------------------------ + +// Get home directory path. +extern GString *getHomeDir(); + +// Get current directory. +extern GString *getCurrentDir(); + +// Append a file name to a path string. may be an empty +// string, denoting the current directory). Returns . +extern GString *appendToPath(GString *path, char *fileName); + +// Grab the path from the front of the file name. If there is no +// directory component in , returns an empty string. +extern GString *grabPath(char *fileName); + +// Is this an absolute path or file name? +extern GBool isAbsolutePath(char *path); + +// Make this path absolute by prepending current directory (if path is +// relative) or prepending user's directory (if path starts with '~'). +extern GString *makePathAbsolute(GString *path); + +// Get the modification time for . Returns 0 if there is an +// error. +extern time_t getModTime(char *fileName); + +// Create a temporary file and open it for writing. If is not +// NULL, it will be used as the file name extension. Returns both the +// name and the file pointer. For security reasons, all writing +// should be done to the returned file pointer; the file may be +// reopened later for reading, but not for writing. The string +// should be "w" or "wb". Returns true on success. +extern GBool openTempFile(GString **name, FILE **f, char *mode, char *ext); + +// Execute . Returns true on success. +extern GBool executeCommand(char *cmd); + +// Just like fgets, but handles Unix, Mac, and/or DOS end-of-line +// conventions. +extern char *getLine(char *buf, int size, FILE *f); + +//------------------------------------------------------------------------ +// GDir and GDirEntry +//------------------------------------------------------------------------ + +class GDirEntry { +public: + + GDirEntry(char *dirPath, char *nameA, GBool doStat); + ~GDirEntry(); + GString *getName() { return name; } + GBool isDir() { return dir; } + +private: + + GString *name; // dir/file name + GBool dir; // is it a directory? +}; + +class GDir { +public: + + GDir(char *name, GBool doStatA = gTrue); + ~GDir(); + GDirEntry *getNextEntry(); + void rewind(); + +private: + + GString *path; // directory path + GBool doStat; // call stat() for each entry? +#if defined(WIN32) + WIN32_FIND_DATA ffd; + HANDLE hnd; +#elif defined(ACORN) +#elif defined(MACOS) +#else + DIR *dir; // the DIR structure from opendir() +#ifdef VMS + GBool needParent; // need to return an entry for [-] +#endif +#endif +}; + +#endif diff --git a/kpdf/xpdf/goo/gmem.cc b/kpdf/xpdf/goo/gmem.cc new file mode 100644 index 00000000..d8962aba --- /dev/null +++ b/kpdf/xpdf/goo/gmem.cc @@ -0,0 +1,315 @@ +/* + * gmem.c + * + * Memory routines with out-of-memory checking. + * + * Copyright 1996-2003 Glyph & Cog, LLC + */ + +#include +#include +#include +#include +#include +#include +#include "gmem.h" + +#ifdef DEBUG_MEM + +typedef struct _GMemHdr { + unsigned int magic; + int size; + int index; + struct _GMemHdr *next, *prev; +} GMemHdr; + +#define gMemHdrSize ((sizeof(GMemHdr) + 7) & ~7) +#define gMemTrlSize (sizeof(long)) + +#define gMemMagic 0xabcd9999 + +#if gmemTrlSize==8 +#define gMemDeadVal 0xdeadbeefdeadbeefUL +#else +#define gMemDeadVal 0xdeadbeefUL +#endif + +/* round data size so trailer will be aligned */ +#define gMemDataSize(size) \ + ((((size) + gMemTrlSize - 1) / gMemTrlSize) * gMemTrlSize) + +static GMemHdr *gMemHead = NULL; +static GMemHdr *gMemTail = NULL; + +static int gMemIndex = 0; +static int gMemAlloc = 0; +static int gMemInUse = 0; + +#endif /* DEBUG_MEM */ + +void *gmalloc(int size) GMEM_EXCEP { +#ifdef DEBUG_MEM + int size1; + char *mem; + GMemHdr *hdr; + void *data; + unsigned long *trl, *p; + + if (size < 0) { +#if USE_EXCEPTIONS + throw GMemException(); +#else + fprintf(stderr, "Invalid memory allocation size\n"); + exit(1); +#endif + } + if (size == 0) { + return NULL; + } + size1 = gMemDataSize(size); + if (!(mem = (char *)malloc(size1 + gMemHdrSize + gMemTrlSize))) { +#if USE_EXCEPTIONS + throw GMemException(); +#else + fprintf(stderr, "Out of memory\n"); + exit(1); +#endif + } + hdr = (GMemHdr *)mem; + data = (void *)(mem + gMemHdrSize); + trl = (unsigned long *)(mem + gMemHdrSize + size1); + hdr->magic = gMemMagic; + hdr->size = size; + hdr->index = gMemIndex++; + if (gMemTail) { + gMemTail->next = hdr; + hdr->prev = gMemTail; + gMemTail = hdr; + } else { + hdr->prev = NULL; + gMemHead = gMemTail = hdr; + } + hdr->next = NULL; + ++gMemAlloc; + gMemInUse += size; + for (p = (unsigned long *)data; p <= trl; ++p) { + *p = gMemDeadVal; + } + return data; +#else + void *p; + + if (size < 0) { +#if USE_EXCEPTIONS + throw GMemException(); +#else + fprintf(stderr, "Invalid memory allocation size\n"); + exit(1); +#endif + } + if (size == 0) { + return NULL; + } + if (!(p = malloc(size))) { +#if USE_EXCEPTIONS + throw GMemException(); +#else + fprintf(stderr, "Out of memory\n"); + exit(1); +#endif + } + return p; +#endif +} + +void *grealloc(void *p, int size) GMEM_EXCEP { +#ifdef DEBUG_MEM + GMemHdr *hdr; + void *q; + int oldSize; + + if (size < 0) { +#if USE_EXCEPTIONS + throw GMemException(); +#else + fprintf(stderr, "Invalid memory allocation size\n"); + exit(1); +#endif + } + if (size == 0) { + if (p) { + gfree(p); + } + return NULL; + } + if (p) { + hdr = (GMemHdr *)((char *)p - gMemHdrSize); + oldSize = hdr->size; + q = gmalloc(size); + memcpy(q, p, size < oldSize ? size : oldSize); + gfree(p); + } else { + q = gmalloc(size); + } + return q; +#else + void *q; + + if (size < 0) { +#if USE_EXCEPTIONS + throw GMemException(); +#else + fprintf(stderr, "Invalid memory allocation size\n"); + exit(1); +#endif + } + if (size == 0) { + if (p) { + free(p); + } + return NULL; + } + if (p) { + q = realloc(p, size); + } else { + q = malloc(size); + } + if (!q) { +#if USE_EXCEPTIONS + throw GMemException(); +#else + fprintf(stderr, "Out of memory\n"); + exit(1); +#endif + } + return q; +#endif +} + +void *gmallocn(int nObjs, int objSize) GMEM_EXCEP { + int n; + + if (nObjs == 0) { + return NULL; + } + n = nObjs * objSize; + if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) { +#if USE_EXCEPTIONS + throw GMemException(); +#else + fprintf(stderr, "Bogus memory allocation size\n"); + exit(1); +#endif + } + return gmalloc(n); +} + +void *gmallocn_checkoverflow(int nObjs, int objSize) GMEM_EXCEP { + int n; + + if (nObjs == 0) { + return NULL; + } + n = nObjs * objSize; + if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) { +#if USE_EXCEPTIONS + throw GMemException(); +#else + fprintf(stderr, "Bogus memory allocation size\n"); + return NULL; +#endif + } + return gmalloc(n); +} + + +void *greallocn(void *p, int nObjs, int objSize) GMEM_EXCEP { + int n; + + if (nObjs == 0) { + if (p) { + gfree(p); + } + return NULL; + } + n = nObjs * objSize; + if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) { +#if USE_EXCEPTIONS + throw GMemException(); +#else + fprintf(stderr, "Bogus memory allocation size\n"); + exit(1); +#endif + } + return grealloc(p, n); +} + +void gfree(void *p) { +#ifdef DEBUG_MEM + int size; + GMemHdr *hdr; + unsigned long *trl, *clr; + + if (p) { + hdr = (GMemHdr *)((char *)p - gMemHdrSize); + if (hdr->magic == gMemMagic && + ((hdr->prev == NULL) == (hdr == gMemHead)) && + ((hdr->next == NULL) == (hdr == gMemTail))) { + if (hdr->prev) { + hdr->prev->next = hdr->next; + } else { + gMemHead = hdr->next; + } + if (hdr->next) { + hdr->next->prev = hdr->prev; + } else { + gMemTail = hdr->prev; + } + --gMemAlloc; + gMemInUse -= hdr->size; + size = gMemDataSize(hdr->size); + trl = (unsigned long *)((char *)hdr + gMemHdrSize + size); + if (*trl != gMemDeadVal) { + fprintf(stderr, "Overwrite past end of block %d at address %p\n", + hdr->index, p); + } + for (clr = (unsigned long *)hdr; clr <= trl; ++clr) { + *clr = gMemDeadVal; + } + free(hdr); + } else { + fprintf(stderr, "Attempted to free bad address %p\n", p); + } + } +#else + if (p) { + free(p); + } +#endif +} + +#ifdef DEBUG_MEM +void gMemReport(FILE *f) { + GMemHdr *p; + + fprintf(f, "%d memory allocations in all\n", gMemIndex); + if (gMemAlloc > 0) { + fprintf(f, "%d memory blocks left allocated:\n", gMemAlloc); + fprintf(f, " index size\n"); + fprintf(f, "-------- --------\n"); + for (p = gMemHead; p; p = p->next) { + fprintf(f, "%8d %8d\n", p->index, p->size); + } + } else { + fprintf(f, "No memory blocks left allocated\n"); + } +} +#endif + +char *copyString(char *s) { + char *s1; + + s1 = (char *)gmalloc(strlen(s) + 1); + strcpy(s1, s); + return s1; +} diff --git a/kpdf/xpdf/goo/gmem.h b/kpdf/xpdf/goo/gmem.h new file mode 100644 index 00000000..ffe5b0da --- /dev/null +++ b/kpdf/xpdf/goo/gmem.h @@ -0,0 +1,80 @@ +/* + * gmem.h + * + * Memory routines with out-of-memory checking. + * + * Copyright 1996-2003 Glyph & Cog, LLC + */ + +#ifndef GMEM_H +#define GMEM_H + +#include +#include + +#if USE_EXCEPTIONS + +class GMemException { +public: + GMemException() {} + ~GMemException() {} +}; + +#define GMEM_EXCEP throw(GMemException) + +#else // USE_EXCEPTIONS + +#define GMEM_EXCEP + +#endif // USE_EXCEPTIONS + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Same as malloc, but prints error message and exits if malloc() + * returns NULL. + */ +extern void *gmalloc(int size) GMEM_EXCEP; + +/* + * Same as realloc, but prints error message and exits if realloc() + * returns NULL. If

is NULL, calls malloc instead of realloc(). + */ +extern void *grealloc(void *p, int size) GMEM_EXCEP; + +/* + * These are similar to gmalloc and grealloc, but take an object count + * and size. The result is similar to allocating nObjs * objSize + * bytes, but there is an additional error check that the total size + * doesn't overflow an int. + */ +extern void *gmallocn(int nObjs, int objSize) GMEM_EXCEP; +extern void *greallocn(void *p, int nObjs, int objSize) GMEM_EXCEP; +extern void *gmallocn_checkoverflow(int nObjs, int objSize) GMEM_EXCEP; + +/* + * Same as free, but checks for and ignores NULL pointers. + */ +extern void gfree(void *p); + +#ifdef DEBUG_MEM +/* + * Report on unfreed memory. + */ +extern void gMemReport(FILE *f); +#else +#define gMemReport(f) +#endif + +/* + * Allocate memory and copy a string into it. + */ +extern char *copyString(char *s); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kpdf/xpdf/goo/gmempp.cc b/kpdf/xpdf/goo/gmempp.cc new file mode 100644 index 00000000..b1ee970d --- /dev/null +++ b/kpdf/xpdf/goo/gmempp.cc @@ -0,0 +1,32 @@ +//======================================================================== +// +// gmempp.cc +// +// Use gmalloc/gfree for C++ new/delete operators. +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include +#include "gmem.h" + +#ifdef DEBUG_MEM + +void *operator new(size_t size) { + return gmalloc((int)size); +} + +void *operator new[](size_t size) { + return gmalloc((int)size); +} + +void operator delete(void *p) { + gfree(p); +} + +void operator delete[](void *p) { + gfree(p); +} + +#endif diff --git a/kpdf/xpdf/goo/gtypes.h b/kpdf/xpdf/goo/gtypes.h new file mode 100644 index 00000000..9f64f57d --- /dev/null +++ b/kpdf/xpdf/goo/gtypes.h @@ -0,0 +1,29 @@ +/* + * gtypes.h + * + * Some useful simple types. + * + * Copyright 1996-2003 Glyph & Cog, LLC + */ + +#ifndef GTYPES_H +#define GTYPES_H + +/* + * These have stupid names to avoid conflicts with some (but not all) + * C++ compilers which define them. + */ +typedef int GBool; +#define gTrue 1 +#define gFalse 0 + +/* + * These have stupid names to avoid conflicts with , + * which on various systems defines some random subset of these. + */ +typedef unsigned char Guchar; +typedef unsigned short Gushort; +typedef unsigned int Guint; +typedef unsigned long Gulong; + +#endif diff --git a/kpdf/xpdf/splash/Makefile.am b/kpdf/xpdf/splash/Makefile.am new file mode 100644 index 00000000..34d41419 --- /dev/null +++ b/kpdf/xpdf/splash/Makefile.am @@ -0,0 +1,8 @@ +INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../fofi -I$(srcdir)/../goo $(LIBFREETYPE_CFLAGS) $(USER_INCLUDES) + +libsplash_la_SOURCES = Splash.cc SplashBitmap.cc SplashClip.cc SplashFTFont.cc SplashFTFontEngine.cc \ + SplashFTFontFile.cc SplashFont.cc SplashFontEngine.cc SplashFontFile.cc SplashFontFileID.cc \ + SplashPath.cc SplashPattern.cc SplashScreen.cc SplashState.cc SplashT1Font.cc \ + SplashT1FontEngine.cc SplashT1FontFile.cc SplashXPath.cc SplashXPathScanner.cc + +noinst_LTLIBRARIES = libsplash.la diff --git a/kpdf/xpdf/splash/Splash.cc b/kpdf/xpdf/splash/Splash.cc new file mode 100644 index 00000000..30179fda --- /dev/null +++ b/kpdf/xpdf/splash/Splash.cc @@ -0,0 +1,3335 @@ +//======================================================================== +// +// Splash.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "SplashErrorCodes.h" +#include "SplashMath.h" +#include "SplashBitmap.h" +#include "SplashState.h" +#include "SplashPath.h" +#include "SplashXPath.h" +#include "SplashXPathScanner.h" +#include "SplashPattern.h" +#include "SplashScreen.h" +#include "SplashFont.h" +#include "SplashGlyphBitmap.h" +#include "Splash.h" + +//------------------------------------------------------------------------ + +// distance of Bezier control point from center for circle approximation +// = (4 * (sqrt(2) - 1) / 3) * r +#define bezierCircle ((SplashCoord)0.55228475) +#define bezierCircle2 ((SplashCoord)(0.5 * 0.55228475)) + +// Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result. +static inline Guchar div255(int x) { + return (Guchar)((x + (x >> 8) + 0x80) >> 8); +} + +//------------------------------------------------------------------------ +// SplashPipe +//------------------------------------------------------------------------ + +#define splashPipeMaxStages 9 + +struct SplashPipe { + // pixel coordinates + int x, y; + + // source pattern + SplashPattern *pattern; + + // source alpha and color + SplashCoord aInput; + GBool usesShape; + Guchar aSrc; + SplashColorPtr cSrc; + SplashColor cSrcVal; + + // non-isolated group alpha0 + Guchar *alpha0Ptr; + + // soft mask + SplashColorPtr softMaskPtr; + + // destination alpha and color + SplashColorPtr destColorPtr; + int destColorMask; + Guchar *destAlphaPtr; + + // shape + SplashCoord shape; + + // result alpha and color + GBool noTransparency; + SplashPipeResultColorCtrl resultColorCtrl; + + // non-isolated group correction + int nonIsolatedGroup; +}; + +SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = { + splashPipeResultColorNoAlphaBlendMono, + splashPipeResultColorNoAlphaBlendMono, + splashPipeResultColorNoAlphaBlendRGB, + splashPipeResultColorNoAlphaBlendRGB +#if SPLASH_CMYK + , + splashPipeResultColorNoAlphaBlendCMYK +#endif +}; + +SplashPipeResultColorCtrl Splash::pipeResultColorAlphaNoBlend[] = { + splashPipeResultColorAlphaNoBlendMono, + splashPipeResultColorAlphaNoBlendMono, + splashPipeResultColorAlphaNoBlendRGB, + splashPipeResultColorAlphaNoBlendRGB +#if SPLASH_CMYK + , + splashPipeResultColorAlphaNoBlendCMYK +#endif +}; + +SplashPipeResultColorCtrl Splash::pipeResultColorAlphaBlend[] = { + splashPipeResultColorAlphaBlendMono, + splashPipeResultColorAlphaBlendMono, + splashPipeResultColorAlphaBlendRGB, + splashPipeResultColorAlphaBlendRGB +#if SPLASH_CMYK + , + splashPipeResultColorAlphaBlendCMYK +#endif +}; + +//------------------------------------------------------------------------ + +static void blendXor(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = src[i] ^ dest[i]; + } +} + +//------------------------------------------------------------------------ +// modified region +//------------------------------------------------------------------------ + +void Splash::clearModRegion() { + modXMin = bitmap->getWidth(); + modYMin = bitmap->getHeight(); + modXMax = -1; + modYMax = -1; +} + +inline void Splash::updateModX(int x) { + if (x < modXMin) { + modXMin = x; + } + if (x > modXMax) { + modXMax = x; + } +} + +inline void Splash::updateModY(int y) { + if (y < modYMin) { + modYMin = y; + } + if (y > modYMax) { + modYMax = y; + } +} + +//------------------------------------------------------------------------ +// pipeline +//------------------------------------------------------------------------ + +inline void Splash::pipeInit(SplashPipe *pipe, int x, int y, + SplashPattern *pattern, SplashColorPtr cSrc, + SplashCoord aInput, GBool usesShape, + GBool nonIsolatedGroup) { + pipeSetXY(pipe, x, y); + pipe->pattern = NULL; + + // source color + if (pattern) { + if (pattern->isStatic()) { + pattern->getColor(x, y, pipe->cSrcVal); + } else { + pipe->pattern = pattern; + } + pipe->cSrc = pipe->cSrcVal; + } else { + pipe->cSrc = cSrc; + } + + // source alpha + pipe->aInput = aInput; + if (!state->softMask) { + if (usesShape) { + pipe->aInput *= 255; + } else { + pipe->aSrc = (Guchar)splashRound(pipe->aInput * 255); + } + } + pipe->usesShape = usesShape; + + // result alpha + if (aInput == 1 && !state->softMask && !usesShape && + !state->inNonIsolatedGroup) { + pipe->noTransparency = gTrue; + } else { + pipe->noTransparency = gFalse; + } + + // result color + if (pipe->noTransparency) { + // the !state->blendFunc case is handled separately in pipeRun + pipe->resultColorCtrl = pipeResultColorNoAlphaBlend[bitmap->mode]; + } else if (!state->blendFunc) { + pipe->resultColorCtrl = pipeResultColorAlphaNoBlend[bitmap->mode]; + } else { + pipe->resultColorCtrl = pipeResultColorAlphaBlend[bitmap->mode]; + } + + // non-isolated group correction + if (nonIsolatedGroup) { + pipe->nonIsolatedGroup = splashColorModeNComps[bitmap->mode]; + } else { + pipe->nonIsolatedGroup = 0; + } +} + +inline void Splash::pipeRun(SplashPipe *pipe) { + Guchar aSrc, aDest, alpha2, alpha0, aResult; + SplashColor cDest, cBlend; + Guchar cResult0, cResult1, cResult2, cResult3; + + //----- source color + + // static pattern: handled in pipeInit + // fixed color: handled in pipeInit + + // dynamic pattern + if (pipe->pattern) { + pipe->pattern->getColor(pipe->x, pipe->y, pipe->cSrcVal); + } + + if (pipe->noTransparency && !state->blendFunc) { + + //----- write destination pixel + + switch (bitmap->mode) { + case splashModeMono1: + cResult0 = pipe->cSrc[0]; + if (state->screen->test(pipe->x, pipe->y, cResult0)) { + *pipe->destColorPtr |= pipe->destColorMask; + } else { + *pipe->destColorPtr &= ~pipe->destColorMask; + } + if (!(pipe->destColorMask >>= 1)) { + pipe->destColorMask = 0x80; + ++pipe->destColorPtr; + } + break; + case splashModeMono8: + *pipe->destColorPtr++ = pipe->cSrc[0]; + break; + case splashModeRGB8: + *pipe->destColorPtr++ = pipe->cSrc[0]; + *pipe->destColorPtr++ = pipe->cSrc[1]; + *pipe->destColorPtr++ = pipe->cSrc[2]; + break; + case splashModeBGR8: + *pipe->destColorPtr++ = pipe->cSrc[2]; + *pipe->destColorPtr++ = pipe->cSrc[1]; + *pipe->destColorPtr++ = pipe->cSrc[0]; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + *pipe->destColorPtr++ = pipe->cSrc[0]; + *pipe->destColorPtr++ = pipe->cSrc[1]; + *pipe->destColorPtr++ = pipe->cSrc[2]; + *pipe->destColorPtr++ = pipe->cSrc[3]; + break; +#endif + } + if (pipe->destAlphaPtr) { + *pipe->destAlphaPtr++ = 255; + } + + } else { + + //----- read destination pixel + + switch (bitmap->mode) { + case splashModeMono1: + cDest[0] = (*pipe->destColorPtr & pipe->destColorMask) ? 0xff : 0x00; + break; + case splashModeMono8: + cDest[0] = *pipe->destColorPtr; + break; + case splashModeRGB8: + cDest[0] = pipe->destColorPtr[0]; + cDest[1] = pipe->destColorPtr[1]; + cDest[2] = pipe->destColorPtr[2]; + break; + case splashModeBGR8: + cDest[0] = pipe->destColorPtr[2]; + cDest[1] = pipe->destColorPtr[1]; + cDest[2] = pipe->destColorPtr[0]; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + cDest[0] = pipe->destColorPtr[0]; + cDest[1] = pipe->destColorPtr[1]; + cDest[2] = pipe->destColorPtr[2]; + cDest[3] = pipe->destColorPtr[3]; + break; +#endif + } + if (pipe->destAlphaPtr) { + aDest = *pipe->destAlphaPtr; + } else { + aDest = 0xff; + } + + //----- blend function + + if (state->blendFunc) { + (*state->blendFunc)(pipe->cSrc, cDest, cBlend, bitmap->mode); + } + + //----- source alpha + + if (state->softMask) { + if (pipe->usesShape) { + aSrc = (Guchar)splashRound(pipe->aInput * *pipe->softMaskPtr++ + * pipe->shape); + } else { + aSrc = (Guchar)splashRound(pipe->aInput * *pipe->softMaskPtr++); + } + } else if (pipe->usesShape) { + // pipe->aInput is premultiplied by 255 in pipeInit + aSrc = (Guchar)splashRound(pipe->aInput * pipe->shape); + } else { + // precomputed in pipeInit + aSrc = pipe->aSrc; + } + + //----- result alpha and non-isolated group element correction + + if (pipe->noTransparency) { + alpha2 = aResult = 255; + } else { + aResult = aSrc + aDest - div255(aSrc * aDest); + + if (pipe->alpha0Ptr) { + alpha0 = *pipe->alpha0Ptr++; + alpha2 = aResult + alpha0 - div255(aResult * alpha0); + } else { + alpha2 = aResult; + } + } + + //----- result color + + cResult0 = cResult1 = cResult2 = cResult3 = 0; // make gcc happy + + switch (pipe->resultColorCtrl) { + +#if SPLASH_CMYK + case splashPipeResultColorNoAlphaBlendCMYK: + cResult3 = div255((255 - aDest) * pipe->cSrc[3] + aDest * cBlend[3]); +#endif + case splashPipeResultColorNoAlphaBlendRGB: + cResult2 = div255((255 - aDest) * pipe->cSrc[2] + aDest * cBlend[2]); + cResult1 = div255((255 - aDest) * pipe->cSrc[1] + aDest * cBlend[1]); + case splashPipeResultColorNoAlphaBlendMono: + cResult0 = div255((255 - aDest) * pipe->cSrc[0] + aDest * cBlend[0]); + break; + + case splashPipeResultColorAlphaNoBlendMono: + if (alpha2 == 0) { + cResult0 = 0; + } else { + cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] + + aSrc * pipe->cSrc[0]) / alpha2); + } + break; + case splashPipeResultColorAlphaNoBlendRGB: + if (alpha2 == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + } else { + cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] + + aSrc * pipe->cSrc[0]) / alpha2); + cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] + + aSrc * pipe->cSrc[1]) / alpha2); + cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] + + aSrc * pipe->cSrc[2]) / alpha2); + } + break; +#if SPLASH_CMYK + case splashPipeResultColorAlphaNoBlendCMYK: + if (alpha2 == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + cResult3 = 0; + } else { + cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] + + aSrc * pipe->cSrc[0]) / alpha2); + cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] + + aSrc * pipe->cSrc[1]) / alpha2); + cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] + + aSrc * pipe->cSrc[2]) / alpha2); + cResult3 = (Guchar)(((alpha2 - aSrc) * cDest[3] + + aSrc * pipe->cSrc[3]) / alpha2); + } + break; +#endif + + case splashPipeResultColorAlphaBlendMono: + if (alpha2 == 0) { + cResult0 = 0; + } else { + cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] + + aSrc * ((255 - aDest) * pipe->cSrc[0] + + aDest * cBlend[0]) / 255) / + alpha2); + } + break; + case splashPipeResultColorAlphaBlendRGB: + if (alpha2 == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + } else { + cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] + + aSrc * ((255 - aDest) * pipe->cSrc[0] + + aDest * cBlend[0]) / 255) / + alpha2); + cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] + + aSrc * ((255 - aDest) * pipe->cSrc[1] + + aDest * cBlend[1]) / 255) / + alpha2); + cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] + + aSrc * ((255 - aDest) * pipe->cSrc[2] + + aDest * cBlend[2]) / 255) / + alpha2); + } + break; +#if SPLASH_CMYK + case splashPipeResultColorAlphaBlendCMYK: + if (alpha2 == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + cResult3 = 0; + } else { + cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] + + aSrc * ((255 - aDest) * pipe->cSrc[0] + + aDest * cBlend[0]) / 255) / + alpha2); + cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] + + aSrc * ((255 - aDest) * pipe->cSrc[1] + + aDest * cBlend[1]) / 255) / + alpha2); + cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] + + aSrc * ((255 - aDest) * pipe->cSrc[2] + + aDest * cBlend[2]) / 255) / + alpha2); + cResult3 = (Guchar)(((alpha2 - aSrc) * cDest[3] + + aSrc * ((255 - aDest) * pipe->cSrc[3] + + aDest * cBlend[3]) / 255) / + alpha2); + } + break; +#endif + } + + //----- non-isolated group correction + + if (aResult != 0) { + switch (pipe->nonIsolatedGroup) { +#if SPLASH_CMYK + case 4: + cResult3 += (cResult3 - cDest[3]) * aDest * + (255 - aResult) / (255 * aResult); +#endif + case 3: + cResult2 += (cResult2 - cDest[2]) * aDest * + (255 - aResult) / (255 * aResult); + cResult1 += (cResult1 - cDest[1]) * aDest * + (255 - aResult) / (255 * aResult); + case 1: + cResult0 += (cResult0 - cDest[0]) * aDest * + (255 - aResult) / (255 * aResult); + case 0: + break; + } + } + + //----- write destination pixel + + switch (bitmap->mode) { + case splashModeMono1: + if (state->screen->test(pipe->x, pipe->y, cResult0)) { + *pipe->destColorPtr |= pipe->destColorMask; + } else { + *pipe->destColorPtr &= ~pipe->destColorMask; + } + if (!(pipe->destColorMask >>= 1)) { + pipe->destColorMask = 0x80; + ++pipe->destColorPtr; + } + break; + case splashModeMono8: + *pipe->destColorPtr++ = cResult0; + break; + case splashModeRGB8: + *pipe->destColorPtr++ = cResult0; + *pipe->destColorPtr++ = cResult1; + *pipe->destColorPtr++ = cResult2; + break; + case splashModeBGR8: + *pipe->destColorPtr++ = cResult2; + *pipe->destColorPtr++ = cResult1; + *pipe->destColorPtr++ = cResult0; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + *pipe->destColorPtr++ = cResult0; + *pipe->destColorPtr++ = cResult1; + *pipe->destColorPtr++ = cResult2; + *pipe->destColorPtr++ = cResult3; + break; +#endif + } + if (pipe->destAlphaPtr) { + *pipe->destAlphaPtr++ = aResult; + } + + } + + ++pipe->x; +} + +inline void Splash::pipeSetXY(SplashPipe *pipe, int x, int y) { + pipe->x = x; + pipe->y = y; + if (state->softMask) { + pipe->softMaskPtr = + &state->softMask->data[y * state->softMask->rowSize + x]; + } + switch (bitmap->mode) { + case splashModeMono1: + pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + (x >> 3)]; + pipe->destColorMask = 0x80 >> (x & 7); + break; + case splashModeMono8: + pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + x]; + break; + case splashModeRGB8: + case splashModeBGR8: + pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x]; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x]; + break; +#endif + } + if (bitmap->alpha) { + pipe->destAlphaPtr = &bitmap->alpha[y * bitmap->width + x]; + } else { + pipe->destAlphaPtr = NULL; + } + if (state->inNonIsolatedGroup && alpha0Bitmap->alpha) { + pipe->alpha0Ptr = + &alpha0Bitmap->alpha[(alpha0Y + y) * alpha0Bitmap->width + + (alpha0X + x)]; + } else { + pipe->alpha0Ptr = NULL; + } +} + +inline void Splash::pipeIncX(SplashPipe *pipe) { + ++pipe->x; + if (state->softMask) { + ++pipe->softMaskPtr; + } + switch (bitmap->mode) { + case splashModeMono1: + if (!(pipe->destColorMask >>= 1)) { + pipe->destColorMask = 0x80; + ++pipe->destColorPtr; + } + break; + case splashModeMono8: + ++pipe->destColorPtr; + break; + case splashModeRGB8: + case splashModeBGR8: + pipe->destColorPtr += 3; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + pipe->destColorPtr += 4; + break; +#endif + } + if (pipe->destAlphaPtr) { + ++pipe->destAlphaPtr; + } + if (pipe->alpha0Ptr) { + ++pipe->alpha0Ptr; + } +} + +inline void Splash::drawPixel(SplashPipe *pipe, int x, int y, GBool noClip) { + if (noClip || state->clip->test(x, y)) { + pipeSetXY(pipe, x, y); + pipeRun(pipe); + updateModX(x); + updateModY(y); + } +} + +inline void Splash::drawAAPixelInit() { + aaBufY = -1; +} + +inline void Splash::drawAAPixel(SplashPipe *pipe, int x, int y) { +#if splashAASize == 4 + static int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3, + 1, 2, 2, 3, 2, 3, 3, 4 }; + int w; +#else + int xx, yy; +#endif + SplashColorPtr p; + int x0, x1, t; + + if (x < 0 || x >= bitmap->width || + y < state->clip->getYMinI() || y > state->clip->getYMaxI()) { + return; + } + + // update aaBuf + if (y != aaBufY) { + memset(aaBuf->getDataPtr(), 0xff, + aaBuf->getRowSize() * aaBuf->getHeight()); + x0 = 0; + x1 = bitmap->width - 1; + state->clip->clipAALine(aaBuf, &x0, &x1, y); + aaBufY = y; + } + + // compute the shape value +#if splashAASize == 4 + p = aaBuf->getDataPtr() + (x >> 1); + w = aaBuf->getRowSize(); + if (x & 1) { + t = bitCount4[*p & 0x0f] + bitCount4[p[w] & 0x0f] + + bitCount4[p[2*w] & 0x0f] + bitCount4[p[3*w] & 0x0f]; + } else { + t = bitCount4[*p >> 4] + bitCount4[p[w] >> 4] + + bitCount4[p[2*w] >> 4] + bitCount4[p[3*w] >> 4]; + } +#else + t = 0; + for (yy = 0; yy < splashAASize; ++yy) { + for (xx = 0; xx < splashAASize; ++xx) { + p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + + ((x * splashAASize + xx) >> 3); + t += (*p >> (7 - ((x * splashAASize + xx) & 7))) & 1; + } + } +#endif + + // draw the pixel + if (t != 0) { + pipeSetXY(pipe, x, y); + pipe->shape *= aaGamma[t]; + pipeRun(pipe); + updateModX(x); + updateModY(y); + } +} + +inline void Splash::drawSpan(SplashPipe *pipe, int x0, int x1, int y, + GBool noClip) { + int x; + + pipeSetXY(pipe, x0, y); + if (noClip) { + for (x = x0; x <= x1; ++x) { + pipeRun(pipe); + } + updateModX(x0); + updateModX(x1); + updateModY(y); + } else { + for (x = x0; x <= x1; ++x) { + if (state->clip->test(x, y)) { + pipeRun(pipe); + updateModX(x); + updateModY(y); + } else { + pipeIncX(pipe); + } + } + } +} + +inline void Splash::drawAALine(SplashPipe *pipe, int x0, int x1, int y) { +#if splashAASize == 4 + static int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3, + 1, 2, 2, 3, 2, 3, 3, 4 }; + SplashColorPtr p0, p1, p2, p3; + int t; +#else + SplashColorPtr p; + int xx, yy, t; +#endif + int x; + +#if splashAASize == 4 + p0 = aaBuf->getDataPtr() + (x0 >> 1); + p1 = p0 + aaBuf->getRowSize(); + p2 = p1 + aaBuf->getRowSize(); + p3 = p2 + aaBuf->getRowSize(); +#endif + pipeSetXY(pipe, x0, y); + for (x = x0; x <= x1; ++x) { + + // compute the shape value +#if splashAASize == 4 + if (x & 1) { + t = bitCount4[*p0 & 0x0f] + bitCount4[*p1 & 0x0f] + + bitCount4[*p2 & 0x0f] + bitCount4[*p3 & 0x0f]; + ++p0; ++p1; ++p2; ++p3; + } else { + t = bitCount4[*p0 >> 4] + bitCount4[*p1 >> 4] + + bitCount4[*p2 >> 4] + bitCount4[*p3 >> 4]; + } +#else + t = 0; + for (yy = 0; yy < splashAASize; ++yy) { + for (xx = 0; xx < splashAASize; ++xx) { + p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + + ((x * splashAASize + xx) >> 3); + t += (*p >> (7 - ((x * splashAASize + xx) & 7))) & 1; + } + } +#endif + + if (t != 0) { + pipe->shape = aaGamma[t]; + pipeRun(pipe); + updateModX(x); + updateModY(y); + } else { + pipeIncX(pipe); + } + } +} + +//------------------------------------------------------------------------ + +// Transform a point from user space to device space. +inline void Splash::transform(SplashCoord *matrix, + SplashCoord xi, SplashCoord yi, + SplashCoord *xo, SplashCoord *yo) { + // [ m[0] m[1] 0 ] + // [xo yo 1] = [xi yi 1] * [ m[2] m[3] 0 ] + // [ m[4] m[5] 1 ] + *xo = xi * matrix[0] + yi * matrix[2] + matrix[4]; + *yo = xi * matrix[1] + yi * matrix[3] + matrix[5]; +} + +//------------------------------------------------------------------------ +// Splash +//------------------------------------------------------------------------ + +Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, + SplashScreenParams *screenParams) { + int i; + + bitmap = bitmapA; + vectorAntialias = vectorAntialiasA; + state = new SplashState(bitmap->width, bitmap->height, vectorAntialias, + screenParams); + if (vectorAntialias) { + aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize, + 1, splashModeMono1, gFalse); + for (i = 0; i <= splashAASize * splashAASize; ++i) { + aaGamma[i] = splashPow((SplashCoord)i / + (SplashCoord)(splashAASize * splashAASize), + 1.5); + } + } else { + aaBuf = NULL; + } + clearModRegion(); + debugMode = gFalse; +} + +Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, + SplashScreen *screenA) { + int i; + + bitmap = bitmapA; + vectorAntialias = vectorAntialiasA; + state = new SplashState(bitmap->width, bitmap->height, vectorAntialias, + screenA); + if (vectorAntialias) { + aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize, + 1, splashModeMono1, gFalse); + for (i = 0; i <= splashAASize * splashAASize; ++i) { + aaGamma[i] = splashPow((SplashCoord)i / + (SplashCoord)(splashAASize * splashAASize), + 1.5); + } + } else { + aaBuf = NULL; + } + clearModRegion(); + debugMode = gFalse; +} + +Splash::~Splash() { + while (state->next) { + restoreState(); + } + delete state; + if (vectorAntialias) { + delete aaBuf; + } +} + +//------------------------------------------------------------------------ +// state read +//------------------------------------------------------------------------ + +SplashCoord *Splash::getMatrix() { + return state->matrix; +} + +SplashPattern *Splash::getStrokePattern() { + return state->strokePattern; +} + +SplashPattern *Splash::getFillPattern() { + return state->fillPattern; +} + +SplashScreen *Splash::getScreen() { + return state->screen; +} + +SplashBlendFunc Splash::getBlendFunc() { + return state->blendFunc; +} + +SplashCoord Splash::getStrokeAlpha() { + return state->strokeAlpha; +} + +SplashCoord Splash::getFillAlpha() { + return state->fillAlpha; +} + +SplashCoord Splash::getLineWidth() { + return state->lineWidth; +} + +int Splash::getLineCap() { + return state->lineCap; +} + +int Splash::getLineJoin() { + return state->lineJoin; +} + +SplashCoord Splash::getMiterLimit() { + return state->miterLimit; +} + +SplashCoord Splash::getFlatness() { + return state->flatness; +} + +SplashCoord *Splash::getLineDash() { + return state->lineDash; +} + +int Splash::getLineDashLength() { + return state->lineDashLength; +} + +SplashCoord Splash::getLineDashPhase() { + return state->lineDashPhase; +} + +SplashClip *Splash::getClip() { + return state->clip; +} + +SplashBitmap *Splash::getSoftMask() { + return state->softMask; +} + +GBool Splash::getInNonIsolatedGroup() { + return state->inNonIsolatedGroup; +} + +//------------------------------------------------------------------------ +// state write +//------------------------------------------------------------------------ + +void Splash::setMatrix(SplashCoord *matrix) { + memcpy(state->matrix, matrix, 6 * sizeof(SplashCoord)); +} + +void Splash::setStrokePattern(SplashPattern *strokePattern) { + state->setStrokePattern(strokePattern); +} + +void Splash::setFillPattern(SplashPattern *fillPattern) { + state->setFillPattern(fillPattern); +} + +void Splash::setScreen(SplashScreen *screen) { + state->setScreen(screen); +} + +void Splash::setBlendFunc(SplashBlendFunc func) { + state->blendFunc = func; +} + +void Splash::setStrokeAlpha(SplashCoord alpha) { + state->strokeAlpha = alpha; +} + +void Splash::setFillAlpha(SplashCoord alpha) { + state->fillAlpha = alpha; +} + +void Splash::setLineWidth(SplashCoord lineWidth) { + state->lineWidth = lineWidth; +} + +void Splash::setLineCap(int lineCap) { + state->lineCap = lineCap; +} + +void Splash::setLineJoin(int lineJoin) { + state->lineJoin = lineJoin; +} + +void Splash::setMiterLimit(SplashCoord miterLimit) { + state->miterLimit = miterLimit; +} + +void Splash::setFlatness(SplashCoord flatness) { + if (flatness < 1) { + state->flatness = 1; + } else { + state->flatness = flatness; + } +} + +void Splash::setLineDash(SplashCoord *lineDash, int lineDashLength, + SplashCoord lineDashPhase) { + state->setLineDash(lineDash, lineDashLength, lineDashPhase); +} + +void Splash::setStrokeAdjust(GBool strokeAdjust) { + state->strokeAdjust = strokeAdjust; +} + +void Splash::clipResetToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + state->clip->resetToRect(x0, y0, x1, y1); +} + +SplashError Splash::clipToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + return state->clip->clipToRect(x0, y0, x1, y1); +} + +SplashError Splash::clipToPath(SplashPath *path, GBool eo) { + return state->clip->clipToPath(path, state->matrix, state->flatness, eo); +} + +void Splash::setSoftMask(SplashBitmap *softMask) { + state->setSoftMask(softMask); +} + +void Splash::setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA, + int alpha0XA, int alpha0YA) { + alpha0Bitmap = alpha0BitmapA; + alpha0X = alpha0XA; + alpha0Y = alpha0YA; + state->inNonIsolatedGroup = gTrue; +} + +//------------------------------------------------------------------------ +// state save/restore +//------------------------------------------------------------------------ + +void Splash::saveState() { + SplashState *newState; + + newState = state->copy(); + newState->next = state; + state = newState; +} + +SplashError Splash::restoreState() { + SplashState *oldState; + + if (!state->next) { + return splashErrNoSave; + } + oldState = state; + state = state->next; + delete oldState; + return splashOk; +} + +//------------------------------------------------------------------------ +// drawing operations +//------------------------------------------------------------------------ + +void Splash::clear(SplashColorPtr color, Guchar alpha) { + SplashColorPtr row, p; + Guchar mono; + int x, y; + + switch (bitmap->mode) { + case splashModeMono1: + mono = (color[0] & 0x80) ? 0xff : 0x00; + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + mono, -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, mono, bitmap->rowSize * bitmap->height); + } + break; + case splashModeMono8: + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + break; + case splashModeRGB8: + if (color[0] == color[1] && color[1] == color[2]) { + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + } else { + row = bitmap->data; + for (y = 0; y < bitmap->height; ++y) { + p = row; + for (x = 0; x < bitmap->width; ++x) { + *p++ = color[2]; + *p++ = color[1]; + *p++ = color[0]; + } + row += bitmap->rowSize; + } + } + break; + case splashModeBGR8: + if (color[0] == color[1] && color[1] == color[2]) { + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + } else { + row = bitmap->data; + for (y = 0; y < bitmap->height; ++y) { + p = row; + for (x = 0; x < bitmap->width; ++x) { + *p++ = color[0]; + *p++ = color[1]; + *p++ = color[2]; + } + row += bitmap->rowSize; + } + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + if (color[0] == color[1] && color[1] == color[2] && color[2] == color[3]) { + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + } else { + row = bitmap->data; + for (y = 0; y < bitmap->height; ++y) { + p = row; + for (x = 0; x < bitmap->width; ++x) { + *p++ = color[0]; + *p++ = color[1]; + *p++ = color[2]; + *p++ = color[3]; + } + row += bitmap->rowSize; + } + } + break; +#endif + } + + if (bitmap->alpha) { + memset(bitmap->alpha, alpha, bitmap->width * bitmap->height); + } + + updateModX(0); + updateModY(0); + updateModX(bitmap->width - 1); + updateModY(bitmap->height - 1); +} + +SplashError Splash::stroke(SplashPath *path) { + SplashPath *path2, *dPath; + + if (debugMode) { + printf("stroke [dash:%d] [width:%.2f]:\n", + state->lineDashLength, (double)state->lineWidth); + dumpPath(path); + } + opClipRes = splashClipAllOutside; + if (path->length == 0) { + return splashErrEmptyPath; + } + path2 = flattenPath(path, state->matrix, state->flatness); + if (state->lineDashLength > 0) { + dPath = makeDashedPath(path2); + delete path2; + path2 = dPath; + } + if (state->lineWidth == 0) { + strokeNarrow(path2); + } else { + strokeWide(path2); + } + delete path2; + return splashOk; +} + +void Splash::strokeNarrow(SplashPath *path) { + SplashPipe pipe; + SplashXPath *xPath; + SplashXPathSeg *seg; + int x0, x1, x2, x3, y0, y1, x, y, t; + SplashCoord dx, dy, dxdy; + SplashClipResult clipRes; + int nClipRes[3]; + int i; + + nClipRes[0] = nClipRes[1] = nClipRes[2] = 0; + + xPath = new SplashXPath(path, state->matrix, state->flatness, gFalse); + + pipeInit(&pipe, 0, 0, state->strokePattern, NULL, state->strokeAlpha, + gFalse, gFalse); + + for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) { + + x0 = splashFloor(seg->x0); + x1 = splashFloor(seg->x1); + y0 = splashFloor(seg->y0); + y1 = splashFloor(seg->y1); + + // horizontal segment + if (y0 == y1) { + if (x0 > x1) { + t = x0; x0 = x1; x1 = t; + } + if ((clipRes = state->clip->testSpan(x0, x1, y0)) + != splashClipAllOutside) { + drawSpan(&pipe, x0, x1, y0, clipRes == splashClipAllInside); + } + + // segment with |dx| > |dy| + } else if (splashAbs(seg->dxdy) > 1) { + dx = seg->x1 - seg->x0; + dy = seg->y1 - seg->y0; + dxdy = seg->dxdy; + if (y0 > y1) { + t = y0; y0 = y1; y1 = t; + t = x0; x0 = x1; x1 = t; + dx = -dx; + dy = -dy; + } + if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0, + x0 <= x1 ? x1 : x0, y1)) + != splashClipAllOutside) { + if (dx > 0) { + x2 = x0; + x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy); + drawSpan(&pipe, x2, (x2 <= x3 - 1) ? x3 - 1 : x2, y0, + clipRes == splashClipAllInside); + x2 = x3; + for (y = y0 + 1; y <= y1 - 1; ++y) { + x3 = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy); + drawSpan(&pipe, x2, x3 - 1, y, clipRes == splashClipAllInside); + x2 = x3; + } + drawSpan(&pipe, x2, x2 <= x1 ? x1 : x2, y1, + clipRes == splashClipAllInside); + } else { + x2 = x0; + x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy); + drawSpan(&pipe, (x3 + 1 <= x2) ? x3 + 1 : x2, x2, y0, + clipRes == splashClipAllInside); + x2 = x3; + for (y = y0 + 1; y <= y1 - 1; ++y) { + x3 = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy); + drawSpan(&pipe, x3 + 1, x2, y, clipRes == splashClipAllInside); + x2 = x3; + } + drawSpan(&pipe, x1, (x1 <= x2) ? x2 : x1, y1, + clipRes == splashClipAllInside); + } + } + + // segment with |dy| > |dx| + } else { + dxdy = seg->dxdy; + if (y0 > y1) { + t = x0; x0 = x1; x1 = t; + t = y0; y0 = y1; y1 = t; + } + if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0, + x0 <= x1 ? x1 : x0, y1)) + != splashClipAllOutside) { + drawPixel(&pipe, x0, y0, clipRes == splashClipAllInside); + for (y = y0 + 1; y <= y1 - 1; ++y) { + x = splashFloor(seg->x0 + ((SplashCoord)y - seg->y0) * dxdy); + drawPixel(&pipe, x, y, clipRes == splashClipAllInside); + } + drawPixel(&pipe, x1, y1, clipRes == splashClipAllInside); + } + } + ++nClipRes[clipRes]; + } + if (nClipRes[splashClipPartial] || + (nClipRes[splashClipAllInside] && nClipRes[splashClipAllOutside])) { + opClipRes = splashClipPartial; + } else if (nClipRes[splashClipAllInside]) { + opClipRes = splashClipAllInside; + } else { + opClipRes = splashClipAllOutside; + } + + delete xPath; +} + +void Splash::strokeWide(SplashPath *path) { + SplashPath *path2; + + path2 = makeStrokePath(path, gFalse); + fillWithPattern(path2, gFalse, state->strokePattern, state->strokeAlpha); + delete path2; +} + +SplashPath *Splash::flattenPath(SplashPath *path, SplashCoord *matrix, + SplashCoord flatness) { + SplashPath *fPath; + SplashCoord flatness2; + Guchar flag; + int i; + + fPath = new SplashPath(); + flatness2 = flatness * flatness; + i = 0; + while (i < path->length) { + flag = path->flags[i]; + if (flag & splashPathFirst) { + fPath->moveTo(path->pts[i].x, path->pts[i].y); + ++i; + } else { + if (flag & splashPathCurve) { + flattenCurve(path->pts[i-1].x, path->pts[i-1].y, + path->pts[i ].x, path->pts[i ].y, + path->pts[i+1].x, path->pts[i+1].y, + path->pts[i+2].x, path->pts[i+2].y, + matrix, flatness2, fPath); + i += 3; + } else { + fPath->lineTo(path->pts[i].x, path->pts[i].y); + ++i; + } + if (path->flags[i-1] & splashPathClosed) { + fPath->close(); + } + } + } + return fPath; +} + +void Splash::flattenCurve(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3, + SplashCoord *matrix, SplashCoord flatness2, + SplashPath *fPath) { + SplashCoord cx[splashMaxCurveSplits + 1][3]; + SplashCoord cy[splashMaxCurveSplits + 1][3]; + int cNext[splashMaxCurveSplits + 1]; + SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh; + SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh; + SplashCoord dx, dy, mx, my, tx, ty, d1, d2; + int p1, p2, p3; + + // initial segment + p1 = 0; + p2 = splashMaxCurveSplits; + cx[p1][0] = x0; cy[p1][0] = y0; + cx[p1][1] = x1; cy[p1][1] = y1; + cx[p1][2] = x2; cy[p1][2] = y2; + cx[p2][0] = x3; cy[p2][0] = y3; + cNext[p1] = p2; + + while (p1 < splashMaxCurveSplits) { + + // get the next segment + xl0 = cx[p1][0]; yl0 = cy[p1][0]; + xx1 = cx[p1][1]; yy1 = cy[p1][1]; + xx2 = cx[p1][2]; yy2 = cy[p1][2]; + p2 = cNext[p1]; + xr3 = cx[p2][0]; yr3 = cy[p2][0]; + + // compute the distances (in device space) from the control points + // to the midpoint of the straight line (this is a bit of a hack, + // but it's much faster than computing the actual distances to the + // line) + transform(matrix, (xl0 + xr3) * 0.5, (yl0 + yr3) * 0.5, &mx, &my); + transform(matrix, xx1, yy1, &tx, &ty); + dx = tx - mx; + dy = ty - my; + d1 = dx*dx + dy*dy; + transform(matrix, xx2, yy2, &tx, &ty); + dx = tx - mx; + dy = ty - my; + d2 = dx*dx + dy*dy; + + // if the curve is flat enough, or no more subdivisions are + // allowed, add the straight line segment + if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) { + fPath->lineTo(xr3, yr3); + p1 = p2; + + // otherwise, subdivide the curve + } else { + xl1 = (xl0 + xx1) * 0.5; + yl1 = (yl0 + yy1) * 0.5; + xh = (xx1 + xx2) * 0.5; + yh = (yy1 + yy2) * 0.5; + xl2 = (xl1 + xh) * 0.5; + yl2 = (yl1 + yh) * 0.5; + xr2 = (xx2 + xr3) * 0.5; + yr2 = (yy2 + yr3) * 0.5; + xr1 = (xh + xr2) * 0.5; + yr1 = (yh + yr2) * 0.5; + xr0 = (xl2 + xr1) * 0.5; + yr0 = (yl2 + yr1) * 0.5; + // add the new subdivision points + p3 = (p1 + p2) / 2; + cx[p1][1] = xl1; cy[p1][1] = yl1; + cx[p1][2] = xl2; cy[p1][2] = yl2; + cNext[p1] = p3; + cx[p3][0] = xr0; cy[p3][0] = yr0; + cx[p3][1] = xr1; cy[p3][1] = yr1; + cx[p3][2] = xr2; cy[p3][2] = yr2; + cNext[p3] = p2; + } + } +} + +SplashPath *Splash::makeDashedPath(SplashPath *path) { + SplashPath *dPath; + SplashCoord lineDashTotal; + SplashCoord lineDashStartPhase, lineDashDist, segLen; + SplashCoord x0, y0, x1, y1, xa, ya; + GBool lineDashStartOn, lineDashOn, newPath; + int lineDashStartIdx, lineDashIdx; + int i, j, k; + + lineDashTotal = 0; + for (i = 0; i < state->lineDashLength; ++i) { + lineDashTotal += state->lineDash[i]; + } + lineDashStartPhase = state->lineDashPhase; + i = splashFloor(lineDashStartPhase / lineDashTotal); + lineDashStartPhase -= (SplashCoord)i * lineDashTotal; + lineDashStartOn = gTrue; + lineDashStartIdx = 0; + while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) { + lineDashStartOn = !lineDashStartOn; + lineDashStartPhase -= state->lineDash[lineDashStartIdx]; + ++lineDashStartIdx; + } + + dPath = new SplashPath(); + + // process each subpath + i = 0; + while (i < path->length) { + + // find the end of the subpath + for (j = i; + j < path->length - 1 && !(path->flags[j] & splashPathLast); + ++j) ; + + // initialize the dash parameters + lineDashOn = lineDashStartOn; + lineDashIdx = lineDashStartIdx; + lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase; + + // process each segment of the subpath + newPath = gTrue; + for (k = i; k < j; ++k) { + + // grab the segment + x0 = path->pts[k].x; + y0 = path->pts[k].y; + x1 = path->pts[k+1].x; + y1 = path->pts[k+1].y; + segLen = splashDist(x0, y0, x1, y1); + + // process the segment + while (segLen > 0) { + + if (lineDashDist >= segLen) { + if (lineDashOn) { + if (newPath) { + dPath->moveTo(x0, y0); + newPath = gFalse; + } + dPath->lineTo(x1, y1); + } + lineDashDist -= segLen; + segLen = 0; + + } else { + xa = x0 + (lineDashDist / segLen) * (x1 - x0); + ya = y0 + (lineDashDist / segLen) * (y1 - y0); + if (lineDashOn) { + if (newPath) { + dPath->moveTo(x0, y0); + newPath = gFalse; + } + dPath->lineTo(xa, ya); + } + x0 = xa; + y0 = ya; + segLen -= lineDashDist; + lineDashDist = 0; + } + + // get the next entry in the dash array + if (lineDashDist <= 0) { + lineDashOn = !lineDashOn; + if (++lineDashIdx == state->lineDashLength) { + lineDashIdx = 0; + } + lineDashDist = state->lineDash[lineDashIdx]; + newPath = gTrue; + } + } + } + i = j + 1; + } + + return dPath; +} + +SplashError Splash::fill(SplashPath *path, GBool eo) { + if (debugMode) { + printf("fill [eo:%d]:\n", eo); + dumpPath(path); + } + return fillWithPattern(path, eo, state->fillPattern, state->fillAlpha); +} + +SplashError Splash::fillWithPattern(SplashPath *path, GBool eo, + SplashPattern *pattern, + SplashCoord alpha) { + SplashPipe pipe; + SplashXPath *xPath; + SplashXPathScanner *scanner; + int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y; + SplashClipResult clipRes, clipRes2; + + if (path->length == 0) { + return splashErrEmptyPath; + } + xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue); + if (vectorAntialias) { + xPath->aaScale(); + } + xPath->sort(); + scanner = new SplashXPathScanner(xPath, eo); + + // get the min and max x and y values + if (vectorAntialias) { + scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI); + } else { + scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI); + } + + // check clipping + if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) + != splashClipAllOutside) { + + // limit the y range + if (yMinI < state->clip->getYMinI()) { + yMinI = state->clip->getYMinI(); + } + if (yMaxI > state->clip->getYMaxI()) { + yMaxI = state->clip->getYMaxI(); + } + + pipeInit(&pipe, 0, yMinI, pattern, NULL, alpha, vectorAntialias, gFalse); + + // draw the spans + if (vectorAntialias) { + for (y = yMinI; y <= yMaxI; ++y) { + scanner->renderAALine(aaBuf, &x0, &x1, y); + if (clipRes != splashClipAllInside) { + state->clip->clipAALine(aaBuf, &x0, &x1, y); + } + drawAALine(&pipe, x0, x1, y); + } + } else { + for (y = yMinI; y <= yMaxI; ++y) { + while (scanner->getNextSpan(y, &x0, &x1)) { + if (clipRes == splashClipAllInside) { + drawSpan(&pipe, x0, x1, y, gTrue); + } else { + // limit the x range + if (x0 < state->clip->getXMinI()) { + x0 = state->clip->getXMinI(); + } + if (x1 > state->clip->getXMaxI()) { + x1 = state->clip->getXMaxI(); + } + clipRes2 = state->clip->testSpan(x0, x1, y); + drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside); + } + } + } + } + } + opClipRes = clipRes; + + delete scanner; + delete xPath; + return splashOk; +} + +SplashError Splash::xorFill(SplashPath *path, GBool eo) { + SplashPipe pipe; + SplashXPath *xPath; + SplashXPathScanner *scanner; + int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y; + SplashClipResult clipRes, clipRes2; + SplashBlendFunc origBlendFunc; + + if (path->length == 0) { + return splashErrEmptyPath; + } + xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue); + xPath->sort(); + scanner = new SplashXPathScanner(xPath, eo); + + // get the min and max x and y values + scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI); + + // check clipping + if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) + != splashClipAllOutside) { + + // limit the y range + if (yMinI < state->clip->getYMinI()) { + yMinI = state->clip->getYMinI(); + } + if (yMaxI > state->clip->getYMaxI()) { + yMaxI = state->clip->getYMaxI(); + } + + origBlendFunc = state->blendFunc; + state->blendFunc = &blendXor; + pipeInit(&pipe, 0, yMinI, state->fillPattern, NULL, 1, gFalse, gFalse); + + // draw the spans + for (y = yMinI; y <= yMaxI; ++y) { + while (scanner->getNextSpan(y, &x0, &x1)) { + if (clipRes == splashClipAllInside) { + drawSpan(&pipe, x0, x1, y, gTrue); + } else { + // limit the x range + if (x0 < state->clip->getXMinI()) { + x0 = state->clip->getXMinI(); + } + if (x1 > state->clip->getXMaxI()) { + x1 = state->clip->getXMaxI(); + } + clipRes2 = state->clip->testSpan(x0, x1, y); + drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside); + } + } + } + state->blendFunc = origBlendFunc; + } + opClipRes = clipRes; + + delete scanner; + delete xPath; + return splashOk; +} + +SplashError Splash::fillChar(SplashCoord x, SplashCoord y, + int c, SplashFont *font) { + SplashGlyphBitmap glyph; + SplashCoord xt, yt; + int x0, y0, xFrac, yFrac; + SplashClipResult clipRes; + + if (debugMode) { + printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n", + (double)x, (double)y, c, c, c); + } + transform(state->matrix, x, y, &xt, &yt); + x0 = splashFloor(xt); + xFrac = splashFloor((xt - x0) * splashFontFraction); + y0 = splashFloor(yt); + yFrac = splashFloor((yt - y0) * splashFontFraction); + if (!font->getGlyph(c, xFrac, yFrac, &glyph, x0, y0, state->clip, &clipRes)) { + return splashErrNoGlyph; + } + if (clipRes != splashClipAllOutside) { + fillGlyph2(x0, y0, &glyph, clipRes == splashClipAllInside); + } + opClipRes = clipRes; + if (glyph.freeData) { + gfree(glyph.data); + } + return splashOk; +} + +void Splash::fillGlyph(SplashCoord x, SplashCoord y, + SplashGlyphBitmap *glyph) { + SplashCoord xt, yt; + int x0, y0; + + transform(state->matrix, x, y, &xt, &yt); + x0 = splashFloor(xt); + y0 = splashFloor(yt); + SplashClipResult clipRes = state->clip->testRect(x0 - glyph->x, + y0 - glyph->y, + x0 - glyph->x + glyph->w - 1, + y0 - glyph->y + glyph->h - 1); + if (clipRes != splashClipAllOutside) { + fillGlyph2(x0, y0, glyph, clipRes == splashClipAllInside); + } + opClipRes = clipRes; +} + +void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip) { + SplashPipe pipe; + int alpha0, alpha; + Guchar *p; + int x1, y1, xx, xx1, yy; + + p = glyph->data; + int xStart = x0 - glyph->x; + int yStart = y0 - glyph->y; + int xxLimit = glyph->w; + int yyLimit = glyph->h; + + if (yStart < 0) + { + p += glyph->w * -yStart; // move p to the beginning of the first painted row + yyLimit += yStart; + yStart = 0; + } + + if (xStart < 0) + { + p += -xStart; // move p to the first painted pixel + xxLimit += xStart; + xStart = 0; + } + + if (xxLimit + xStart >= bitmap->width) xxLimit = bitmap->width - xStart; + if (yyLimit + yStart >= bitmap->height) yyLimit = bitmap->height - yStart; + + if (noClip) { + if (glyph->aa) { + pipeInit(&pipe, xStart, yStart, + state->fillPattern, NULL, state->fillAlpha, gTrue, gFalse); + for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) { + pipeSetXY(&pipe, xStart, y1); + for (xx = 0, x1 = xStart; xx < xxLimit; ++xx, ++x1) { + alpha = p[xx]; + if (alpha != 0) { + pipe.shape = (SplashCoord)(alpha / 255.0); + pipeRun(&pipe); + updateModX(x1); + updateModY(y1); + } else { + pipeIncX(&pipe); + } + } + p += glyph->w; + } + } else { + const int widthEight = (int)ceil(glyph->w / 8.0); + + pipeInit(&pipe, xStart, yStart, + state->fillPattern, NULL, state->fillAlpha, gFalse, gFalse); + for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) { + pipeSetXY(&pipe, xStart, y1); + for (xx = 0, x1 = xStart; xx < xxLimit; xx += 8) { + alpha0 = p[xx / 8]; + for (xx1 = 0; xx1 < 8 && xx + xx1 < xxLimit; ++xx1, ++x1) { + if (alpha0 & 0x80) { + pipeRun(&pipe); + updateModX(x1); + updateModY(y1); + } else { + pipeIncX(&pipe); + } + alpha0 <<= 1; + } + } + p += widthEight; + } + } + } else { + if (glyph->aa) { + pipeInit(&pipe, xStart, yStart, + state->fillPattern, NULL, state->fillAlpha, gTrue, gFalse); + for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) { + pipeSetXY(&pipe, xStart, y1); + for (xx = 0, x1 = xStart; xx < xxLimit; ++xx, ++x1) { + if (state->clip->test(x1, y1)) { + alpha = p[xx]; + if (alpha != 0) { + pipe.shape = (SplashCoord)(alpha / 255.0); + pipeRun(&pipe); + updateModX(x1); + updateModY(y1); + } else { + pipeIncX(&pipe); + } + } else { + pipeIncX(&pipe); + } + } + p += glyph->w; + } + } else { + const int widthEight = (int)ceil(glyph->w / 8.0); + + pipeInit(&pipe, xStart, yStart, + state->fillPattern, NULL, state->fillAlpha, gFalse, gFalse); + for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) { + pipeSetXY(&pipe, xStart, y1); + for (xx = 0, x1 = xStart; xx < xxLimit; xx += 8) { + alpha0 = p[xx / 8]; + for (xx1 = 0; xx1 < 8 && xx + xx1 < xxLimit; ++xx1, ++x1) { + if (state->clip->test(x1, y1)) { + if (alpha0 & 0x80) { + pipeRun(&pipe); + updateModX(x1); + updateModY(y1); + } else { + pipeIncX(&pipe); + } + } else { + pipeIncX(&pipe); + } + alpha0 <<= 1; + } + } + p += widthEight; + } + } + } +} + +SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, + int w, int h, SplashCoord *mat, + GBool glyphMode) { + SplashPipe pipe; + GBool rot; + SplashCoord xScale, yScale, xShear, yShear, yShear1; + int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign; + int ulx, uly, llx, lly, urx, ury, lrx, lry; + int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1; + int xMin, xMax, yMin, yMax; + SplashClipResult clipRes, clipRes2; + int yp, yq, yt, yStep, lastYStep; + int xp, xq, xt, xStep, xSrc; + int k1, spanXMin, spanXMax, spanY; + SplashColorPtr pixBuf, p; + int pixAcc; + int x, y, x1, x2, y2; + SplashCoord y1; + int n, m, i, j; + + if (debugMode) { + printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n", + w, h, (double)mat[0], (double)mat[1], (double)mat[2], + (double)mat[3], (double)mat[4], (double)mat[5]); + } + + if (w == 0 && h == 0) return splashErrZeroImage; + + // check for singular matrix + if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) { + return splashErrSingularMatrix; + } + + // compute scale, shear, rotation, translation parameters + rot = splashAbs(mat[1]) > splashAbs(mat[0]); + if (rot) { + xScale = -mat[1]; + yScale = mat[2] - (mat[0] * mat[3]) / mat[1]; + xShear = -mat[3] / yScale; + yShear = -mat[0] / mat[1]; + } else { + xScale = mat[0]; + yScale = mat[3] - (mat[1] * mat[2]) / mat[0]; + xShear = mat[2] / yScale; + yShear = mat[1] / mat[0]; + } + // Note 1: The PDF spec says that all pixels whose *centers* lie + // within the region get painted -- but that doesn't seem to match + // up with what Acrobat actually does: it ends up leaving gaps + // between image stripes. So we use the same rule here as for + // fills: any pixel that overlaps the region gets painted. + // Note 2: The "glyphMode" flag is a kludge: it switches back to + // "correct" behavior (matching the spec), for use in rendering Type + // 3 fonts. + // Note 3: The +/-0.01 in these computations is to avoid floating + // point precision problems which can lead to gaps between image + // stripes (it can cause image stripes to overlap, but that's a much + // less visible problem). + if (glyphMode) { + if (xScale >= 0) { + tx = splashRound(mat[4]); + tx2 = splashRound(mat[4] + xScale) - 1; + } else { + tx = splashRound(mat[4]) - 1; + tx2 = splashRound(mat[4] + xScale); + } + } else { + if (xScale >= 0) { + tx = splashFloor(mat[4] - 0.01); + tx2 = splashFloor(mat[4] + xScale + 0.01); + } else { + tx = splashFloor(mat[4] + 0.01); + tx2 = splashFloor(mat[4] + xScale - 0.01); + } + } + scaledWidth = abs(tx2 - tx) + 1; + if (glyphMode) { + if (yScale >= 0) { + ty = splashRound(mat[5]); + ty2 = splashRound(mat[5] + yScale) - 1; + } else { + ty = splashRound(mat[5]) - 1; + ty2 = splashRound(mat[5] + yScale); + } + } else { + if (yScale >= 0) { + ty = splashFloor(mat[5] - 0.01); + ty2 = splashFloor(mat[5] + yScale + 0.01); + } else { + ty = splashFloor(mat[5] + 0.01); + ty2 = splashFloor(mat[5] + yScale - 0.01); + } + } + scaledHeight = abs(ty2 - ty) + 1; + xSign = (xScale < 0) ? -1 : 1; + ySign = (yScale < 0) ? -1 : 1; + yShear1 = (SplashCoord)xSign * yShear; + + // clipping + ulx1 = 0; + uly1 = 0; + urx1 = xSign * (scaledWidth - 1); + ury1 = (int)(yShear * urx1); + llx1 = splashRound(xShear * ySign * (scaledHeight - 1)); + lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1); + lrx1 = xSign * (scaledWidth - 1) + + splashRound(xShear * ySign * (scaledHeight - 1)); + lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1); + if (rot) { + ulx = tx + uly1; uly = ty - ulx1; + urx = tx + ury1; ury = ty - urx1; + llx = tx + lly1; lly = ty - llx1; + lrx = tx + lry1; lry = ty - lrx1; + } else { + ulx = tx + ulx1; uly = ty + uly1; + urx = tx + urx1; ury = ty + ury1; + llx = tx + llx1; lly = ty + lly1; + lrx = tx + lrx1; lry = ty + lry1; + } + xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx + : (llx < lrx) ? llx : lrx + : (urx < llx) ? (urx < lrx) ? urx : lrx + : (llx < lrx) ? llx : lrx; + xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx + : (llx > lrx) ? llx : lrx + : (urx > llx) ? (urx > lrx) ? urx : lrx + : (llx > lrx) ? llx : lrx; + yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry + : (lly < lry) ? lly : lry + : (ury < lly) ? (ury < lry) ? ury : lry + : (lly < lry) ? lly : lry; + yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry + : (lly > lry) ? lly : lry + : (ury > lly) ? (ury > lry) ? ury : lry + : (lly > lry) ? lly : lry; + clipRes = state->clip->testRect(xMin, yMin, xMax, yMax); + opClipRes = clipRes; + + // compute Bresenham parameters for x and y scaling + yp = h / scaledHeight; + yq = h % scaledHeight; + xp = w / scaledWidth; + xq = w % scaledWidth; + + // allocate pixel buffer + pixBuf = (SplashColorPtr)gmalloc((yp + 1) * w); + + // initialize the pixel pipe + pipeInit(&pipe, 0, 0, state->fillPattern, NULL, state->fillAlpha, + gTrue, gFalse); + if (vectorAntialias) { + drawAAPixelInit(); + } + + // init y scale Bresenham + yt = 0; + lastYStep = 1; + + for (y = 0; y < scaledHeight; ++y) { + + // y scale Bresenham + yStep = yp; + yt += yq; + if (yt >= scaledHeight) { + yt -= scaledHeight; + ++yStep; + } + + // read row(s) from image + n = (yp > 0) ? yStep : lastYStep; + if (n > 0) { + p = pixBuf; + for (i = 0; i < n; ++i) { + (*src)(srcData, p); + p += w; + } + } + lastYStep = yStep; + + // loop-invariant constants + k1 = splashRound(xShear * ySign * y); + + // clipping test + if (clipRes != splashClipAllInside && + !rot && + (int)(yShear * k1) == + (int)(yShear * (xSign * (scaledWidth - 1) + k1))) { + if (xSign > 0) { + spanXMin = tx + k1; + spanXMax = spanXMin + (scaledWidth - 1); + } else { + spanXMax = tx + k1; + spanXMin = spanXMax - (scaledWidth - 1); + } + spanY = ty + ySign * y + (int)(yShear * k1); + clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY); + if (clipRes2 == splashClipAllOutside) { + continue; + } + } else { + clipRes2 = clipRes; + } + + // init x scale Bresenham + xt = 0; + xSrc = 0; + + // x shear + x1 = k1; + + // y shear + y1 = (SplashCoord)ySign * y + yShear * x1; + // this is a kludge: if yShear1 is negative, then (int)y1 would + // change immediately after the first pixel, which is not what we + // want + if (yShear1 < 0) { + y1 += 0.999; + } + + // loop-invariant constants + n = yStep > 0 ? yStep : 1; + + for (x = 0; x < scaledWidth; ++x) { + + // x scale Bresenham + xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + // rotation + if (rot) { + x2 = (int)y1; + y2 = -x1; + } else { + x2 = x1; + y2 = (int)y1; + } + + // compute the alpha value for (x,y) after the x and y scaling + // operations + m = xStep > 0 ? xStep : 1; + p = pixBuf + xSrc; + pixAcc = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + pixAcc += *p++; + } + p += w - m; + } + + // blend fill color with background + if (pixAcc != 0) { + pipe.shape = (pixAcc == n * m) + ? (SplashCoord)1 + : (SplashCoord)pixAcc / (SplashCoord)(n * m); + if (vectorAntialias && clipRes2 != splashClipAllInside) { + drawAAPixel(&pipe, tx + x2, ty + y2); + } else { + drawPixel(&pipe, tx + x2, ty + y2, clipRes2 == splashClipAllInside); + } + } + + // x scale Bresenham + xSrc += xStep; + + // x shear + x1 += xSign; + + // y shear + y1 += yShear1; + } + } + + // free memory + gfree(pixBuf); + + return splashOk; +} + +SplashError Splash::drawImage(SplashImageSource src, void *srcData, + SplashColorMode srcMode, GBool srcAlpha, + int w, int h, SplashCoord *mat) { + SplashPipe pipe; + GBool ok, rot; + SplashCoord xScale, yScale, xShear, yShear, yShear1; + int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign; + int ulx, uly, llx, lly, urx, ury, lrx, lry; + int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1; + int xMin, xMax, yMin, yMax; + SplashClipResult clipRes, clipRes2; + int yp, yq, yt, yStep, lastYStep; + int xp, xq, xt, xStep, xSrc; + int k1, spanXMin, spanXMax, spanY; + SplashColorPtr colorBuf, p; + SplashColor pix; + Guchar *alphaBuf, *q; +#if SPLASH_CMYK + int pixAcc0, pixAcc1, pixAcc2, pixAcc3; +#else + int pixAcc0, pixAcc1, pixAcc2; +#endif + int alphaAcc; + SplashCoord pixMul, alphaMul, alpha; + int x, y, x1, x2, y2; + SplashCoord y1; + int nComps, n, m, i, j; + + if (debugMode) { + printf("drawImage: srcMode=%d srcAlpha=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n", + srcMode, srcAlpha, w, h, (double)mat[0], (double)mat[1], (double)mat[2], + (double)mat[3], (double)mat[4], (double)mat[5]); + } + + // check color modes + ok = gFalse; // make gcc happy + nComps = 0; // make gcc happy + switch (bitmap->mode) { + case splashModeMono1: + case splashModeMono8: + ok = srcMode == splashModeMono8; + nComps = 1; + break; + case splashModeRGB8: + ok = srcMode == splashModeRGB8; + nComps = 3; + break; + case splashModeBGR8: + ok = srcMode == splashModeBGR8; + nComps = 3; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + ok = srcMode == splashModeCMYK8; + nComps = 4; + break; +#endif + } + if (!ok) { + return splashErrModeMismatch; + } + + // check for singular matrix + if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) { + return splashErrSingularMatrix; + } + + // compute scale, shear, rotation, translation parameters + rot = splashAbs(mat[1]) > splashAbs(mat[0]); + if (rot) { + xScale = -mat[1]; + yScale = mat[2] - (mat[0] * mat[3]) / mat[1]; + xShear = -mat[3] / yScale; + yShear = -mat[0] / mat[1]; + } else { + xScale = mat[0]; + yScale = mat[3] - (mat[1] * mat[2]) / mat[0]; + xShear = mat[2] / yScale; + yShear = mat[1] / mat[0]; + } + // Note 1: The PDF spec says that all pixels whose *centers* lie + // within the region get painted -- but that doesn't seem to match + // up with what Acrobat actually does: it ends up leaving gaps + // between image stripes. So we use the same rule here as for + // fills: any pixel that overlaps the region gets painted. + // Note 2: The +/-0.01 in these computations is to avoid floating + // point precision problems which can lead to gaps between image + // stripes (it can cause image stripes to overlap, but that's a much + // less visible problem). + if (xScale >= 0) { + tx = splashFloor(mat[4] - 0.01); + tx2 = splashFloor(mat[4] + xScale + 0.01); + } else { + tx = splashFloor(mat[4] + 0.01); + tx2 = splashFloor(mat[4] + xScale - 0.01); + } + scaledWidth = abs(tx2 - tx) + 1; + if (yScale >= 0) { + ty = splashFloor(mat[5] - 0.01); + ty2 = splashFloor(mat[5] + yScale + 0.01); + } else { + ty = splashFloor(mat[5] + 0.01); + ty2 = splashFloor(mat[5] + yScale - 0.01); + } + scaledHeight = abs(ty2 - ty) + 1; + xSign = (xScale < 0) ? -1 : 1; + ySign = (yScale < 0) ? -1 : 1; + yShear1 = (SplashCoord)xSign * yShear; + + // clipping + ulx1 = 0; + uly1 = 0; + urx1 = xSign * (scaledWidth - 1); + ury1 = (int)(yShear * urx1); + llx1 = splashRound(xShear * ySign * (scaledHeight - 1)); + lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1); + lrx1 = xSign * (scaledWidth - 1) + + splashRound(xShear * ySign * (scaledHeight - 1)); + lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1); + if (rot) { + ulx = tx + uly1; uly = ty - ulx1; + urx = tx + ury1; ury = ty - urx1; + llx = tx + lly1; lly = ty - llx1; + lrx = tx + lry1; lry = ty - lrx1; + } else { + ulx = tx + ulx1; uly = ty + uly1; + urx = tx + urx1; ury = ty + ury1; + llx = tx + llx1; lly = ty + lly1; + lrx = tx + lrx1; lry = ty + lry1; + } + xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx + : (llx < lrx) ? llx : lrx + : (urx < llx) ? (urx < lrx) ? urx : lrx + : (llx < lrx) ? llx : lrx; + xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx + : (llx > lrx) ? llx : lrx + : (urx > llx) ? (urx > lrx) ? urx : lrx + : (llx > lrx) ? llx : lrx; + yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry + : (lly < lry) ? lly : lry + : (ury < lly) ? (ury < lry) ? ury : lry + : (lly < lry) ? lly : lry; + yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry + : (lly > lry) ? lly : lry + : (ury > lly) ? (ury > lry) ? ury : lry + : (lly > lry) ? lly : lry; + clipRes = state->clip->testRect(xMin, yMin, xMax, yMax); + opClipRes = clipRes; + if (clipRes == splashClipAllOutside) { + return splashOk; + } + + // compute Bresenham parameters for x and y scaling + yp = h / scaledHeight; + yq = h % scaledHeight; + xp = w / scaledWidth; + xq = w % scaledWidth; + + // allocate pixel buffers + colorBuf = (SplashColorPtr)gmalloc((yp + 1) * w * nComps); + if (srcAlpha) { + alphaBuf = (Guchar *)gmalloc((yp + 1) * w); + } else { + alphaBuf = NULL; + } + + pixAcc0 = pixAcc1 = pixAcc2 = 0; // make gcc happy +#if SPLASH_CMYK + pixAcc3 = 0; // make gcc happy +#endif + + // initialize the pixel pipe + pipeInit(&pipe, 0, 0, NULL, pix, state->fillAlpha, + srcAlpha || (vectorAntialias && clipRes != splashClipAllInside), + gFalse); + if (vectorAntialias) { + drawAAPixelInit(); + } + + if (srcAlpha) { + + // init y scale Bresenham + yt = 0; + lastYStep = 1; + + for (y = 0; y < scaledHeight; ++y) { + + // y scale Bresenham + yStep = yp; + yt += yq; + if (yt >= scaledHeight) { + yt -= scaledHeight; + ++yStep; + } + + // read row(s) from image + n = (yp > 0) ? yStep : lastYStep; + if (n > 0) { + p = colorBuf; + q = alphaBuf; + for (i = 0; i < n; ++i) { + (*src)(srcData, p, q); + p += w * nComps; + q += w; + } + } + lastYStep = yStep; + + // loop-invariant constants + k1 = splashRound(xShear * ySign * y); + + // clipping test + if (clipRes != splashClipAllInside && + !rot && + (int)(yShear * k1) == + (int)(yShear * (xSign * (scaledWidth - 1) + k1))) { + if (xSign > 0) { + spanXMin = tx + k1; + spanXMax = spanXMin + (scaledWidth - 1); + } else { + spanXMax = tx + k1; + spanXMin = spanXMax - (scaledWidth - 1); + } + spanY = ty + ySign * y + (int)(yShear * k1); + clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY); + if (clipRes2 == splashClipAllOutside) { + continue; + } + } else { + clipRes2 = clipRes; + } + + // init x scale Bresenham + xt = 0; + xSrc = 0; + + // x shear + x1 = k1; + + // y shear + y1 = (SplashCoord)ySign * y + yShear * x1; + // this is a kludge: if yShear1 is negative, then (int)y1 would + // change immediately after the first pixel, which is not what + // we want + if (yShear1 < 0) { + y1 += 0.999; + } + + // loop-invariant constants + n = yStep > 0 ? yStep : 1; + + switch (srcMode) { + + case splashModeMono1: + case splashModeMono8: + for (x = 0; x < scaledWidth; ++x) { + + // x scale Bresenham + xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + // rotation + if (rot) { + x2 = (int)y1; + y2 = -x1; + } else { + x2 = x1; + y2 = (int)y1; + } + + // compute the filtered pixel at (x,y) after the x and y scaling + // operations + m = xStep > 0 ? xStep : 1; + alphaAcc = 0; + p = colorBuf + xSrc; + q = alphaBuf + xSrc; + pixAcc0 = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + pixAcc0 += *p++; + alphaAcc += *q++; + } + p += w - m; + q += w - m; + } + pixMul = (SplashCoord)1 / (SplashCoord)(n * m); + alphaMul = pixMul * (1.0 / 255.0); + alpha = (SplashCoord)alphaAcc * alphaMul; + + if (alpha > 0) { + pix[0] = (int)((SplashCoord)pixAcc0 * pixMul); + + // set pixel + pipe.shape = alpha; + if (vectorAntialias && clipRes != splashClipAllInside) { + drawAAPixel(&pipe, tx + x2, ty + y2); + } else { + drawPixel(&pipe, tx + x2, ty + y2, + clipRes2 == splashClipAllInside); + } + } + + // x scale Bresenham + xSrc += xStep; + + // x shear + x1 += xSign; + + // y shear + y1 += yShear1; + } + break; + + case splashModeRGB8: + case splashModeBGR8: + for (x = 0; x < scaledWidth; ++x) { + + // x scale Bresenham + xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + // rotation + if (rot) { + x2 = (int)y1; + y2 = -x1; + } else { + x2 = x1; + y2 = (int)y1; + } + + // compute the filtered pixel at (x,y) after the x and y scaling + // operations + m = xStep > 0 ? xStep : 1; + alphaAcc = 0; + p = colorBuf + xSrc * 3; + q = alphaBuf + xSrc; + pixAcc0 = pixAcc1 = pixAcc2 = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + pixAcc0 += *p++; + pixAcc1 += *p++; + pixAcc2 += *p++; + alphaAcc += *q++; + } + p += 3 * (w - m); + q += w - m; + } + pixMul = (SplashCoord)1 / (SplashCoord)(n * m); + alphaMul = pixMul * (1.0 / 255.0); + alpha = (SplashCoord)alphaAcc * alphaMul; + + if (alpha > 0) { + pix[0] = (int)((SplashCoord)pixAcc0 * pixMul); + pix[1] = (int)((SplashCoord)pixAcc1 * pixMul); + pix[2] = (int)((SplashCoord)pixAcc2 * pixMul); + + // set pixel + pipe.shape = alpha; + if (vectorAntialias && clipRes != splashClipAllInside) { + drawAAPixel(&pipe, tx + x2, ty + y2); + } else { + drawPixel(&pipe, tx + x2, ty + y2, + clipRes2 == splashClipAllInside); + } + } + + // x scale Bresenham + xSrc += xStep; + + // x shear + x1 += xSign; + + // y shear + y1 += yShear1; + } + break; + +#if SPLASH_CMYK + case splashModeCMYK8: + for (x = 0; x < scaledWidth; ++x) { + + // x scale Bresenham + xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + // rotation + if (rot) { + x2 = (int)y1; + y2 = -x1; + } else { + x2 = x1; + y2 = (int)y1; + } + + // compute the filtered pixel at (x,y) after the x and y scaling + // operations + m = xStep > 0 ? xStep : 1; + alphaAcc = 0; + p = colorBuf + xSrc * 4; + q = alphaBuf + xSrc; + pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + pixAcc0 += *p++; + pixAcc1 += *p++; + pixAcc2 += *p++; + pixAcc3 += *p++; + alphaAcc += *q++; + } + p += 4 * (w - m); + q += w - m; + } + pixMul = (SplashCoord)1 / (SplashCoord)(n * m); + alphaMul = pixMul * (1.0 / 255.0); + alpha = (SplashCoord)alphaAcc * alphaMul; + + if (alpha > 0) { + pix[0] = (int)((SplashCoord)pixAcc0 * pixMul); + pix[1] = (int)((SplashCoord)pixAcc1 * pixMul); + pix[2] = (int)((SplashCoord)pixAcc2 * pixMul); + pix[3] = (int)((SplashCoord)pixAcc3 * pixMul); + + // set pixel + pipe.shape = alpha; + if (vectorAntialias && clipRes != splashClipAllInside) { + drawAAPixel(&pipe, tx + x2, ty + y2); + } else { + drawPixel(&pipe, tx + x2, ty + y2, + clipRes2 == splashClipAllInside); + } + } + + // x scale Bresenham + xSrc += xStep; + + // x shear + x1 += xSign; + + // y shear + y1 += yShear1; + } + break; +#endif // SPLASH_CMYK + } + } + + } else { + + // init y scale Bresenham + yt = 0; + lastYStep = 1; + + for (y = 0; y < scaledHeight; ++y) { + + // y scale Bresenham + yStep = yp; + yt += yq; + if (yt >= scaledHeight) { + yt -= scaledHeight; + ++yStep; + } + + // read row(s) from image + n = (yp > 0) ? yStep : lastYStep; + if (n > 0) { + p = colorBuf; + for (i = 0; i < n; ++i) { + (*src)(srcData, p, NULL); + p += w * nComps; + } + } + lastYStep = yStep; + + // loop-invariant constants + k1 = splashRound(xShear * ySign * y); + + // clipping test + if (clipRes != splashClipAllInside && + !rot && + (int)(yShear * k1) == + (int)(yShear * (xSign * (scaledWidth - 1) + k1))) { + if (xSign > 0) { + spanXMin = tx + k1; + spanXMax = spanXMin + (scaledWidth - 1); + } else { + spanXMax = tx + k1; + spanXMin = spanXMax - (scaledWidth - 1); + } + spanY = ty + ySign * y + (int)(yShear * k1); + clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY); + if (clipRes2 == splashClipAllOutside) { + continue; + } + } else { + clipRes2 = clipRes; + } + + // init x scale Bresenham + xt = 0; + xSrc = 0; + + // x shear + x1 = k1; + + // y shear + y1 = (SplashCoord)ySign * y + yShear * x1; + // this is a kludge: if yShear1 is negative, then (int)y1 would + // change immediately after the first pixel, which is not what + // we want + if (yShear1 < 0) { + y1 += 0.999; + } + + // loop-invariant constants + n = yStep > 0 ? yStep : 1; + + switch (srcMode) { + + case splashModeMono1: + case splashModeMono8: + for (x = 0; x < scaledWidth; ++x) { + + // x scale Bresenham + xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + // rotation + if (rot) { + x2 = (int)y1; + y2 = -x1; + } else { + x2 = x1; + y2 = (int)y1; + } + + // compute the filtered pixel at (x,y) after the x and y scaling + // operations + m = xStep > 0 ? xStep : 1; + p = colorBuf + xSrc; + pixAcc0 = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + pixAcc0 += *p++; + } + p += w - m; + } + pixMul = (SplashCoord)1 / (SplashCoord)(n * m); + + pix[0] = (int)((SplashCoord)pixAcc0 * pixMul); + + // set pixel + if (vectorAntialias && clipRes != splashClipAllInside) { + pipe.shape = (SplashCoord)1; + drawAAPixel(&pipe, tx + x2, ty + y2); + } else { + drawPixel(&pipe, tx + x2, ty + y2, + clipRes2 == splashClipAllInside); + } + + // x scale Bresenham + xSrc += xStep; + + // x shear + x1 += xSign; + + // y shear + y1 += yShear1; + } + break; + + case splashModeRGB8: + case splashModeBGR8: + for (x = 0; x < scaledWidth; ++x) { + + // x scale Bresenham + xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + // rotation + if (rot) { + x2 = (int)y1; + y2 = -x1; + } else { + x2 = x1; + y2 = (int)y1; + } + + // compute the filtered pixel at (x,y) after the x and y scaling + // operations + m = xStep > 0 ? xStep : 1; + p = colorBuf + xSrc * 3; + pixAcc0 = pixAcc1 = pixAcc2 = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + pixAcc0 += *p++; + pixAcc1 += *p++; + pixAcc2 += *p++; + } + p += 3 * (w - m); + } + pixMul = (SplashCoord)1 / (SplashCoord)(n * m); + + pix[0] = (int)((SplashCoord)pixAcc0 * pixMul); + pix[1] = (int)((SplashCoord)pixAcc1 * pixMul); + pix[2] = (int)((SplashCoord)pixAcc2 * pixMul); + + // set pixel + if (vectorAntialias && clipRes != splashClipAllInside) { + pipe.shape = (SplashCoord)1; + drawAAPixel(&pipe, tx + x2, ty + y2); + } else { + drawPixel(&pipe, tx + x2, ty + y2, + clipRes2 == splashClipAllInside); + } + + // x scale Bresenham + xSrc += xStep; + + // x shear + x1 += xSign; + + // y shear + y1 += yShear1; + } + break; + +#if SPLASH_CMYK + case splashModeCMYK8: + for (x = 0; x < scaledWidth; ++x) { + + // x scale Bresenham + xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + // rotation + if (rot) { + x2 = (int)y1; + y2 = -x1; + } else { + x2 = x1; + y2 = (int)y1; + } + + // compute the filtered pixel at (x,y) after the x and y scaling + // operations + m = xStep > 0 ? xStep : 1; + p = colorBuf + xSrc * 4; + pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + pixAcc0 += *p++; + pixAcc1 += *p++; + pixAcc2 += *p++; + pixAcc3 += *p++; + } + p += 4 * (w - m); + } + pixMul = (SplashCoord)1 / (SplashCoord)(n * m); + + pix[0] = (int)((SplashCoord)pixAcc0 * pixMul); + pix[1] = (int)((SplashCoord)pixAcc1 * pixMul); + pix[2] = (int)((SplashCoord)pixAcc2 * pixMul); + pix[3] = (int)((SplashCoord)pixAcc3 * pixMul); + + // set pixel + if (vectorAntialias && clipRes != splashClipAllInside) { + pipe.shape = (SplashCoord)1; + drawAAPixel(&pipe, tx + x2, ty + y2); + } else { + drawPixel(&pipe, tx + x2, ty + y2, + clipRes2 == splashClipAllInside); + } + + // x scale Bresenham + xSrc += xStep; + + // x shear + x1 += xSign; + + // y shear + y1 += yShear1; + } + break; +#endif // SPLASH_CMYK + } + } + + } + + gfree(colorBuf); + gfree(alphaBuf); + + return splashOk; +} + +SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, + int xDest, int yDest, int w, int h, + GBool noClip, GBool nonIsolated) { + SplashPipe pipe; + SplashColor pixel; + Guchar alpha; + Guchar *ap; + int x, y; + + if (src->mode != bitmap->mode) { + return splashErrModeMismatch; + } + + if (src->alpha) { + pipeInit(&pipe, xDest, yDest, NULL, pixel, state->fillAlpha, + gTrue, nonIsolated); + for (y = 0; y < h; ++y) { + pipeSetXY(&pipe, xDest, yDest + y); + ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc; + for (x = 0; x < w; ++x) { + src->getPixel(xSrc + x, ySrc + y, pixel); + alpha = *ap++; + if (noClip || state->clip->test(xDest + x, yDest + y)) { + // this uses shape instead of alpha, which isn't technically + // correct, but works out the same + pipe.shape = (SplashCoord)(alpha / 255.0); + pipeRun(&pipe); + updateModX(xDest + x); + updateModY(yDest + y); + } else { + pipeIncX(&pipe); + } + } + } + } else { + pipeInit(&pipe, xDest, yDest, NULL, pixel, state->fillAlpha, + gFalse, nonIsolated); + for (y = 0; y < h; ++y) { + pipeSetXY(&pipe, xDest, yDest + y); + for (x = 0; x < w; ++x) { + src->getPixel(xSrc + x, ySrc + y, pixel); + if (noClip || state->clip->test(xDest + x, yDest + y)) { + pipeRun(&pipe); + updateModX(xDest + x); + updateModY(yDest + y); + } else { + pipeIncX(&pipe); + } + } + } + } + + return splashOk; +} + +void Splash::compositeBackground(SplashColorPtr color) { + SplashColorPtr p; + Guchar *q; + Guchar alpha, alpha1, c, color0, color1, color2, color3; + int x, y, mask; + + switch (bitmap->mode) { + case splashModeMono1: + color0 = color[0]; + for (y = 0; y < bitmap->height; ++y) { + p = &bitmap->data[y * bitmap->rowSize]; + q = &bitmap->alpha[y * bitmap->width]; + mask = 0x80; + for (x = 0; x < bitmap->width; ++x) { + alpha = *q++; + alpha1 = 255 - alpha; + c = (*p & mask) ? 0xff : 0x00; + c = div255(alpha1 * color0 + alpha * c); + if (c & 0x80) { + *p |= mask; + } else { + *p &= ~mask; + } + if (!(mask >>= 1)) { + mask = 0x80; + ++p; + } + } + } + break; + case splashModeMono8: + color0 = color[0]; + for (y = 0; y < bitmap->height; ++y) { + p = &bitmap->data[y * bitmap->rowSize]; + q = &bitmap->alpha[y * bitmap->width]; + for (x = 0; x < bitmap->width; ++x) { + alpha = *q++; + alpha1 = 255 - alpha; + p[0] = div255(alpha1 * color0 + alpha * p[0]); + ++p; + } + } + break; + case splashModeRGB8: + case splashModeBGR8: + color0 = color[0]; + color1 = color[1]; + color2 = color[2]; + for (y = 0; y < bitmap->height; ++y) { + p = &bitmap->data[y * bitmap->rowSize]; + q = &bitmap->alpha[y * bitmap->width]; + for (x = 0; x < bitmap->width; ++x) { + alpha = *q++; + alpha1 = 255 - alpha; + p[0] = div255(alpha1 * color0 + alpha * p[0]); + p[1] = div255(alpha1 * color1 + alpha * p[1]); + p[2] = div255(alpha1 * color2 + alpha * p[2]); + p += 3; + } + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + color0 = color[0]; + color1 = color[1]; + color2 = color[2]; + color3 = color[3]; + for (y = 0; y < bitmap->height; ++y) { + p = &bitmap->data[y * bitmap->rowSize]; + q = &bitmap->alpha[y * bitmap->width]; + for (x = 0; x < bitmap->width; ++x) { + alpha = *q++; + alpha1 = 255 - alpha; + p[0] = div255(alpha1 * color0 + alpha * p[0]); + p[1] = div255(alpha1 * color1 + alpha * p[1]); + p[2] = div255(alpha1 * color2 + alpha * p[2]); + p[3] = div255(alpha1 * color3 + alpha * p[3]); + p += 4; + } + } + break; +#endif + } + memset(bitmap->alpha, 255, bitmap->width * bitmap->height); +} + +SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc, + int xDest, int yDest, int w, int h) { + SplashColor pixel; + SplashColorPtr p; + Guchar *q; + int x, y, mask; + + if (src->mode != bitmap->mode) { + return splashErrModeMismatch; + } + + switch (bitmap->mode) { + case splashModeMono1: + for (y = 0; y < h; ++y) { + p = &bitmap->data[(yDest + y) * bitmap->rowSize + (xDest >> 3)]; + mask = 0x80 >> (xDest & 7); + for (x = 0; x < w; ++x) { + src->getPixel(xSrc + x, ySrc + y, pixel); + if (pixel[0]) { + *p |= mask; + } else { + *p &= ~mask; + } + if (!(mask >>= 1)) { + mask = 0x80; + ++p; + } + } + } + break; + case splashModeMono8: + for (y = 0; y < h; ++y) { + p = &bitmap->data[(yDest + y) * bitmap->rowSize + xDest]; + for (x = 0; x < w; ++x) { + src->getPixel(xSrc + x, ySrc + y, pixel); + *p++ = pixel[0]; + } + } + break; + case splashModeRGB8: + case splashModeBGR8: + for (y = 0; y < h; ++y) { + p = &bitmap->data[(yDest + y) * bitmap->rowSize + 3 * xDest]; + for (x = 0; x < w; ++x) { + src->getPixel(xSrc + x, ySrc + y, pixel); + *p++ = pixel[0]; + *p++ = pixel[1]; + *p++ = pixel[2]; + } + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + for (y = 0; y < h; ++y) { + p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest]; + for (x = 0; x < w; ++x) { + src->getPixel(xSrc + x, ySrc + y, pixel); + *p++ = pixel[0]; + *p++ = pixel[1]; + *p++ = pixel[2]; + *p++ = pixel[3]; + } + } + break; +#endif + } + + if (bitmap->alpha) { + for (y = 0; y < h; ++y) { + q = &bitmap->alpha[(yDest + y) * bitmap->width + xDest]; + for (x = 0; x < w; ++x) { + *q++ = 0x00; + } + } + } + + return splashOk; +} + +SplashPath *Splash::makeStrokePath(SplashPath *path, GBool flatten) { + SplashPath *pathIn, *pathOut; + SplashCoord w, d, dx, dy, wdx, wdy, dxNext, dyNext, wdxNext, wdyNext; + SplashCoord crossprod, dotprod, miter, m; + GBool first, last, closed; + int subpathStart, next, i; + int left0, left1, left2, right0, right1, right2, join0, join1, join2; + int leftFirst, rightFirst, firstPt; + + if (flatten) { + pathIn = flattenPath(path, state->matrix, state->flatness); + if (state->lineDashLength > 0) { + pathOut = makeDashedPath(pathIn); + delete pathIn; + pathIn = pathOut; + } + } else { + pathIn = path; + } + + subpathStart = 0; // make gcc happy + closed = gFalse; // make gcc happy + left0 = left1 = right0 = right1 = join0 = join1 = 0; // make gcc happy + leftFirst = rightFirst = firstPt = 0; // make gcc happy + + pathOut = new SplashPath(); + w = state->lineWidth; + + for (i = 0; i < pathIn->length - 1; ++i) { + if (pathIn->flags[i] & splashPathLast) { + continue; + } + if ((first = pathIn->flags[i] & splashPathFirst)) { + subpathStart = i; + closed = pathIn->flags[i] & splashPathClosed; + } + last = pathIn->flags[i+1] & splashPathLast; + + // compute the deltas for segment (i, i+1) + d = splashDist(pathIn->pts[i].x, pathIn->pts[i].y, + pathIn->pts[i+1].x, pathIn->pts[i+1].y); + if (d == 0) { + // we need to draw end caps on zero-length lines + //~ not clear what the behavior should be for splashLineCapButt + //~ with d==0 + dx = 0; + dy = 1; + } else { + d = (SplashCoord)1 / d; + dx = d * (pathIn->pts[i+1].x - pathIn->pts[i].x); + dy = d * (pathIn->pts[i+1].y - pathIn->pts[i].y); + } + wdx = (SplashCoord)0.5 * w * dx; + wdy = (SplashCoord)0.5 * w * dy; + + // compute the deltas for segment (i+1, next) + next = last ? subpathStart + 1 : i + 2; + d = splashDist(pathIn->pts[i+1].x, pathIn->pts[i+1].y, + pathIn->pts[next].x, pathIn->pts[next].y); + if (d == 0) { + // we need to draw end caps on zero-length lines + //~ not clear what the behavior should be for splashLineCapButt + //~ with d==0 + dxNext = 0; + dyNext = 1; + } else { + d = (SplashCoord)1 / d; + dxNext = d * (pathIn->pts[next].x - pathIn->pts[i+1].x); + dyNext = d * (pathIn->pts[next].y - pathIn->pts[i+1].y); + } + wdxNext = (SplashCoord)0.5 * w * dxNext; + wdyNext = (SplashCoord)0.5 * w * dyNext; + + // draw the start cap + pathOut->moveTo(pathIn->pts[i].x - wdy, pathIn->pts[i].y + wdx); + if (i == subpathStart) { + firstPt = pathOut->length - 1; + } + if (first && !closed) { + switch (state->lineCap) { + case splashLineCapButt: + pathOut->lineTo(pathIn->pts[i].x + wdy, pathIn->pts[i].y - wdx); + break; + case splashLineCapRound: + pathOut->curveTo(pathIn->pts[i].x - wdy - bezierCircle * wdx, + pathIn->pts[i].y + wdx - bezierCircle * wdy, + pathIn->pts[i].x - wdx - bezierCircle * wdy, + pathIn->pts[i].y - wdy + bezierCircle * wdx, + pathIn->pts[i].x - wdx, + pathIn->pts[i].y - wdy); + pathOut->curveTo(pathIn->pts[i].x - wdx + bezierCircle * wdy, + pathIn->pts[i].y - wdy - bezierCircle * wdx, + pathIn->pts[i].x + wdy - bezierCircle * wdx, + pathIn->pts[i].y - wdx - bezierCircle * wdy, + pathIn->pts[i].x + wdy, + pathIn->pts[i].y - wdx); + break; + case splashLineCapProjecting: + pathOut->lineTo(pathIn->pts[i].x - wdx - wdy, + pathIn->pts[i].y + wdx - wdy); + pathOut->lineTo(pathIn->pts[i].x - wdx + wdy, + pathIn->pts[i].y - wdx - wdy); + pathOut->lineTo(pathIn->pts[i].x + wdy, + pathIn->pts[i].y - wdx); + break; + } + } else { + pathOut->lineTo(pathIn->pts[i].x + wdy, pathIn->pts[i].y - wdx); + } + + // draw the left side of the segment rectangle + left2 = pathOut->length - 1; + pathOut->lineTo(pathIn->pts[i+1].x + wdy, pathIn->pts[i+1].y - wdx); + + // draw the end cap + if (last && !closed) { + switch (state->lineCap) { + case splashLineCapButt: + pathOut->lineTo(pathIn->pts[i+1].x - wdy, pathIn->pts[i+1].y + wdx); + break; + case splashLineCapRound: + pathOut->curveTo(pathIn->pts[i+1].x + wdy + bezierCircle * wdx, + pathIn->pts[i+1].y - wdx + bezierCircle * wdy, + pathIn->pts[i+1].x + wdx + bezierCircle * wdy, + pathIn->pts[i+1].y + wdy - bezierCircle * wdx, + pathIn->pts[i+1].x + wdx, + pathIn->pts[i+1].y + wdy); + pathOut->curveTo(pathIn->pts[i+1].x + wdx - bezierCircle * wdy, + pathIn->pts[i+1].y + wdy + bezierCircle * wdx, + pathIn->pts[i+1].x - wdy + bezierCircle * wdx, + pathIn->pts[i+1].y + wdx + bezierCircle * wdy, + pathIn->pts[i+1].x - wdy, + pathIn->pts[i+1].y + wdx); + break; + case splashLineCapProjecting: + pathOut->lineTo(pathIn->pts[i+1].x + wdy + wdx, + pathIn->pts[i+1].y - wdx + wdy); + pathOut->lineTo(pathIn->pts[i+1].x - wdy + wdx, + pathIn->pts[i+1].y + wdx + wdy); + pathOut->lineTo(pathIn->pts[i+1].x - wdy, + pathIn->pts[i+1].y + wdx); + break; + } + } else { + pathOut->lineTo(pathIn->pts[i+1].x - wdy, pathIn->pts[i+1].y + wdx); + } + + // draw the right side of the segment rectangle + right2 = pathOut->length - 1; + pathOut->close(); + + // draw the join + join2 = pathOut->length; + if (!last || closed) { + crossprod = dx * dyNext - dy * dxNext; + dotprod = -(dx * dxNext + dy * dyNext); + if (dotprod > 0.99999) { + // avoid a divide-by-zero -- set miter to something arbitrary + // such that sqrt(miter) will exceed miterLimit (and m is never + // used in that situation) + miter = (state->miterLimit + 1) * (state->miterLimit + 1); + m = 0; + } else { + miter = (SplashCoord)2 / ((SplashCoord)1 - dotprod); + if (miter < 1) { + // this can happen because of floating point inaccuracies + miter = 1; + } + m = splashSqrt(miter - 1); + } + + // round join + if (state->lineJoin == splashLineJoinRound) { + pathOut->moveTo(pathIn->pts[i+1].x + (SplashCoord)0.5 * w, + pathIn->pts[i+1].y); + pathOut->curveTo(pathIn->pts[i+1].x + (SplashCoord)0.5 * w, + pathIn->pts[i+1].y + bezierCircle2 * w, + pathIn->pts[i+1].x + bezierCircle2 * w, + pathIn->pts[i+1].y + (SplashCoord)0.5 * w, + pathIn->pts[i+1].x, + pathIn->pts[i+1].y + (SplashCoord)0.5 * w); + pathOut->curveTo(pathIn->pts[i+1].x - bezierCircle2 * w, + pathIn->pts[i+1].y + (SplashCoord)0.5 * w, + pathIn->pts[i+1].x - (SplashCoord)0.5 * w, + pathIn->pts[i+1].y + bezierCircle2 * w, + pathIn->pts[i+1].x - (SplashCoord)0.5 * w, + pathIn->pts[i+1].y); + pathOut->curveTo(pathIn->pts[i+1].x - (SplashCoord)0.5 * w, + pathIn->pts[i+1].y - bezierCircle2 * w, + pathIn->pts[i+1].x - bezierCircle2 * w, + pathIn->pts[i+1].y - (SplashCoord)0.5 * w, + pathIn->pts[i+1].x, + pathIn->pts[i+1].y - (SplashCoord)0.5 * w); + pathOut->curveTo(pathIn->pts[i+1].x + bezierCircle2 * w, + pathIn->pts[i+1].y - (SplashCoord)0.5 * w, + pathIn->pts[i+1].x + (SplashCoord)0.5 * w, + pathIn->pts[i+1].y - bezierCircle2 * w, + pathIn->pts[i+1].x + (SplashCoord)0.5 * w, + pathIn->pts[i+1].y); + + } else { + pathOut->moveTo(pathIn->pts[i+1].x, pathIn->pts[i+1].y); + + // angle < 180 + if (crossprod < 0) { + pathOut->lineTo(pathIn->pts[i+1].x - wdyNext, + pathIn->pts[i+1].y + wdxNext); + // miter join inside limit + if (state->lineJoin == splashLineJoinMiter && + splashSqrt(miter) <= state->miterLimit) { + pathOut->lineTo(pathIn->pts[i+1].x - wdy + wdx * m, + pathIn->pts[i+1].y + wdx + wdy * m); + pathOut->lineTo(pathIn->pts[i+1].x - wdy, + pathIn->pts[i+1].y + wdx); + // bevel join or miter join outside limit + } else { + pathOut->lineTo(pathIn->pts[i+1].x - wdy, pathIn->pts[i+1].y + wdx); + } + + // angle >= 180 + } else { + pathOut->lineTo(pathIn->pts[i+1].x + wdy, + pathIn->pts[i+1].y - wdx); + // miter join inside limit + if (state->lineJoin == splashLineJoinMiter && + splashSqrt(miter) <= state->miterLimit) { + pathOut->lineTo(pathIn->pts[i+1].x + wdy + wdx * m, + pathIn->pts[i+1].y - wdx + wdy * m); + pathOut->lineTo(pathIn->pts[i+1].x + wdyNext, + pathIn->pts[i+1].y - wdxNext); + // bevel join or miter join outside limit + } else { + pathOut->lineTo(pathIn->pts[i+1].x + wdyNext, + pathIn->pts[i+1].y - wdxNext); + } + } + } + + pathOut->close(); + } + + // add stroke adjustment hints + if (state->strokeAdjust) { + if (i >= subpathStart + 1) { + if (i >= subpathStart + 2) { + pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0); + pathOut->addStrokeAdjustHint(left1, right1, join0, left2); + } else { + pathOut->addStrokeAdjustHint(left1, right1, firstPt, left2); + } + pathOut->addStrokeAdjustHint(left1, right1, right2 + 1, right2 + 1); + } + left0 = left1; + left1 = left2; + right0 = right1; + right1 = right2; + join0 = join1; + join1 = join2; + if (i == subpathStart) { + leftFirst = left2; + rightFirst = right2; + } + if (last) { + if (i >= subpathStart + 2) { + pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0); + pathOut->addStrokeAdjustHint(left1, right1, + join0, pathOut->length - 1); + } else { + pathOut->addStrokeAdjustHint(left1, right1, + firstPt, pathOut->length - 1); + } + if (closed) { + pathOut->addStrokeAdjustHint(left1, right1, firstPt, leftFirst); + pathOut->addStrokeAdjustHint(left1, right1, + rightFirst + 1, rightFirst + 1); + pathOut->addStrokeAdjustHint(leftFirst, rightFirst, + left1 + 1, right1); + pathOut->addStrokeAdjustHint(leftFirst, rightFirst, + join1, pathOut->length - 1); + } + } + } + } + + if (pathIn != path) { + delete pathIn; + } + + return pathOut; +} + +void Splash::dumpPath(SplashPath *path) { + int i; + + for (i = 0; i < path->length; ++i) { + printf(" %3d: x=%8.2f y=%8.2f%s%s%s%s\n", + i, (double)path->pts[i].x, (double)path->pts[i].y, + (path->flags[i] & splashPathFirst) ? " first" : "", + (path->flags[i] & splashPathLast) ? " last" : "", + (path->flags[i] & splashPathClosed) ? " closed" : "", + (path->flags[i] & splashPathCurve) ? " curve" : ""); + } +} + +void Splash::dumpXPath(SplashXPath *path) { + int i; + + for (i = 0; i < path->length; ++i) { + printf(" %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f %s%s%s%s%s%s%s\n", + i, (double)path->segs[i].x0, (double)path->segs[i].y0, + (double)path->segs[i].x1, (double)path->segs[i].y1, + (path->segs[i].flags & splashXPathFirst) ? "F" : " ", + (path->segs[i].flags & splashXPathLast) ? "L" : " ", + (path->segs[i].flags & splashXPathEnd0) ? "0" : " ", + (path->segs[i].flags & splashXPathEnd1) ? "1" : " ", + (path->segs[i].flags & splashXPathHoriz) ? "H" : " ", + (path->segs[i].flags & splashXPathVert) ? "V" : " ", + (path->segs[i].flags & splashXPathFlip) ? "P" : " "); + } +} diff --git a/kpdf/xpdf/splash/Splash.h b/kpdf/xpdf/splash/Splash.h new file mode 100644 index 00000000..3c7571fb --- /dev/null +++ b/kpdf/xpdf/splash/Splash.h @@ -0,0 +1,293 @@ +//======================================================================== +// +// Splash.h +// +//======================================================================== + +#ifndef SPLASH_H +#define SPLASH_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" +#include "SplashClip.h" + +class Splash; +class SplashBitmap; +struct SplashGlyphBitmap; +class SplashState; +class SplashPattern; +class SplashScreen; +class SplashPath; +class SplashXPath; +class SplashFont; +struct SplashPipe; + +//------------------------------------------------------------------------ + +// Retrieves the next line of pixels in an image mask. Normally, +// fills in * and returns true. If the image stream is +// exhausted, returns false. +typedef GBool (*SplashImageMaskSource)(void *data, SplashColorPtr pixel); + +// Retrieves the next line of pixels in an image. Normally, fills in +// * and returns true. If the image stream is exhausted, +// returns false. +typedef GBool (*SplashImageSource)(void *data, SplashColorPtr colorLine, + Guchar *alphaLine); + +//------------------------------------------------------------------------ + +enum SplashPipeResultColorCtrl { +#if SPLASH_CMYK + splashPipeResultColorNoAlphaBlendCMYK, +#endif + splashPipeResultColorNoAlphaBlendRGB, + splashPipeResultColorNoAlphaBlendMono, + splashPipeResultColorAlphaNoBlendMono, + splashPipeResultColorAlphaNoBlendRGB, +#if SPLASH_CMYK + splashPipeResultColorAlphaNoBlendCMYK, +#endif + splashPipeResultColorAlphaBlendMono, + splashPipeResultColorAlphaBlendRGB +#if SPLASH_CMYK + , + splashPipeResultColorAlphaBlendCMYK +#endif +}; + +//------------------------------------------------------------------------ +// Splash +//------------------------------------------------------------------------ + +class Splash { +public: + + // Create a new rasterizer object. + Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, + SplashScreenParams *screenParams = NULL); + Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, + SplashScreen *screenA); + + ~Splash(); + + //----- state read + + SplashCoord *getMatrix(); + SplashPattern *getStrokePattern(); + SplashPattern *getFillPattern(); + SplashScreen *getScreen(); + SplashBlendFunc getBlendFunc(); + SplashCoord getStrokeAlpha(); + SplashCoord getFillAlpha(); + SplashCoord getLineWidth(); + int getLineCap(); + int getLineJoin(); + SplashCoord getMiterLimit(); + SplashCoord getFlatness(); + SplashCoord *getLineDash(); + int getLineDashLength(); + SplashCoord getLineDashPhase(); + SplashClip *getClip(); + SplashBitmap *getSoftMask(); + GBool getInNonIsolatedGroup(); + + //----- state write + + void setMatrix(SplashCoord *matrix); + void setStrokePattern(SplashPattern *strokeColor); + void setFillPattern(SplashPattern *fillColor); + void setScreen(SplashScreen *screen); + void setBlendFunc(SplashBlendFunc func); + void setStrokeAlpha(SplashCoord alpha); + void setFillAlpha(SplashCoord alpha); + void setLineWidth(SplashCoord lineWidth); + void setLineCap(int lineCap); + void setLineJoin(int lineJoin); + void setMiterLimit(SplashCoord miterLimit); + void setFlatness(SplashCoord flatness); + // the array will be copied + void setLineDash(SplashCoord *lineDash, int lineDashLength, + SplashCoord lineDashPhase); + void setStrokeAdjust(GBool strokeAdjust); + // NB: uses transformed coordinates. + void clipResetToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + // NB: uses transformed coordinates. + SplashError clipToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + // NB: uses untransformed coordinates. + SplashError clipToPath(SplashPath *path, GBool eo); + void setSoftMask(SplashBitmap *softMask); + void setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA, + int alpha0XA, int alpha0YA); + + //----- state save/restore + + void saveState(); + SplashError restoreState(); + + //----- drawing operations + + // Fill the bitmap with . This is not subject to clipping. + void clear(SplashColorPtr color, Guchar alpha = 0x00); + + // Stroke a path using the current stroke pattern. + SplashError stroke(SplashPath *path); + + // Fill a path using the current fill pattern. + SplashError fill(SplashPath *path, GBool eo); + + // Fill a path, XORing with the current fill pattern. + SplashError xorFill(SplashPath *path, GBool eo); + + // Draw a character, using the current fill pattern. + SplashError fillChar(SplashCoord x, SplashCoord y, int c, SplashFont *font); + + // Draw a glyph, using the current fill pattern. This function does + // not free any data, i.e., it ignores glyph->freeData. + void fillGlyph(SplashCoord x, SplashCoord y, + SplashGlyphBitmap *glyph); + + // Draws an image mask using the fill color. This will read + // lines of pixels from , starting with the top line. "1" + // pixels will be drawn with the current fill color; "0" pixels are + // transparent. The matrix: + // [ mat[0] mat[1] 0 ] + // [ mat[2] mat[3] 0 ] + // [ mat[4] mat[5] 1 ] + // maps a unit square to the desired destination for the image, in + // PostScript style: + // [x' y' 1] = [x y 1] * mat + // Note that the Splash y axis points downward, and the image source + // is assumed to produce pixels in raster order, starting from the + // top line. + SplashError fillImageMask(SplashImageMaskSource src, void *srcData, + int w, int h, SplashCoord *mat, + GBool glyphMode); + + // Draw an image. This will read lines of pixels from + // , starting with the top line. These pixels are assumed to + // be in the source mode, . If is true, the + // alpha values returned by are used; otherwise they are + // ignored. The following combinations of source and target modes + // are supported: + // source target + // ------ ------ + // Mono1 Mono1 + // Mono8 Mono1 -- with dithering + // Mono8 Mono8 + // RGB8 RGB8 + // BGR8 BGR8 + // CMYK8 CMYK8 + // The matrix behaves as for fillImageMask. + SplashError drawImage(SplashImageSource src, void *srcData, + SplashColorMode srcMode, GBool srcAlpha, + int w, int h, SplashCoord *mat); + + // Composite a rectangular region from onto this Splash + // object. + SplashError composite(SplashBitmap *src, int xSrc, int ySrc, + int xDest, int yDest, int w, int h, + GBool noClip, GBool nonIsolated); + + // Composite this Splash object onto a background color. The + // background alpha is assumed to be 1. + void compositeBackground(SplashColorPtr color); + + // Copy a rectangular region from onto the bitmap belonging to + // this Splash object. The destination alpha values are all set to + // zero. + SplashError blitTransparent(SplashBitmap *src, int xSrc, int ySrc, + int xDest, int yDest, int w, int h); + + //----- misc + + // Construct a path for a stroke, given the path to be stroked, and + // using the current line parameters. If is true, this + // function will first flatten the path and handle the linedash. + SplashPath *makeStrokePath(SplashPath *path, GBool flatten = gTrue); + + // Return the associated bitmap. + SplashBitmap *getBitmap() { return bitmap; } + + // Get a bounding box which includes all modifications since the + // last call to clearModRegion. + void getModRegion(int *xMin, int *yMin, int *xMax, int *yMax) + { *xMin = modXMin; *yMin = modYMin; *xMax = modXMax; *yMax = modYMax; } + + // Clear the modified region bounding box. + void clearModRegion(); + + // Get clipping status for the last drawing operation subject to + // clipping. + SplashClipResult getClipRes() { return opClipRes; } + + // Toggle debug mode on or off. + void setDebugMode(GBool debugModeA) { debugMode = debugModeA; } + +#if 1 //~tmp: turn off anti-aliasing temporarily + GBool getVectorAntialias() { return vectorAntialias; } + void setVectorAntialias(GBool vaa) { vectorAntialias = vaa; } +#endif + +private: + + void pipeInit(SplashPipe *pipe, int x, int y, + SplashPattern *pattern, SplashColorPtr cSrc, + SplashCoord aInput, GBool usesShape, + GBool nonIsolatedGroup); + void pipeRun(SplashPipe *pipe); + void pipeSetXY(SplashPipe *pipe, int x, int y); + void pipeIncX(SplashPipe *pipe); + void drawPixel(SplashPipe *pipe, int x, int y, GBool noClip); + void drawAAPixelInit(); + void drawAAPixel(SplashPipe *pipe, int x, int y); + void drawSpan(SplashPipe *pipe, int x0, int x1, int y, GBool noClip); + void drawAALine(SplashPipe *pipe, int x0, int x1, int y); + void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi, + SplashCoord *xo, SplashCoord *yo); + void updateModX(int x); + void updateModY(int y); + void strokeNarrow(SplashPath *path); + void strokeWide(SplashPath *path); + SplashPath *flattenPath(SplashPath *path, SplashCoord *matrix, + SplashCoord flatness); + void flattenCurve(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3, + SplashCoord *matrix, SplashCoord flatness2, + SplashPath *fPath); + SplashPath *makeDashedPath(SplashPath *xPath); + SplashError fillWithPattern(SplashPath *path, GBool eo, + SplashPattern *pattern, SplashCoord alpha); + void fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noclip); + void dumpPath(SplashPath *path); + void dumpXPath(SplashXPath *path); + + static SplashPipeResultColorCtrl pipeResultColorNoAlphaBlend[]; + static SplashPipeResultColorCtrl pipeResultColorAlphaNoBlend[]; + static SplashPipeResultColorCtrl pipeResultColorAlphaBlend[]; + static int pipeNonIsoGroupCorrection[]; + + SplashBitmap *bitmap; + SplashState *state; + SplashBitmap *aaBuf; + int aaBufY; + SplashBitmap *alpha0Bitmap; // for non-isolated groups, this is the + // bitmap containing the alpha0 values + int alpha0X, alpha0Y; // offset within alpha0Bitmap + SplashCoord aaGamma[splashAASize * splashAASize + 1]; + int modXMin, modYMin, modXMax, modYMax; + SplashClipResult opClipRes; + GBool vectorAntialias; + GBool debugMode; +}; + +#endif diff --git a/kpdf/xpdf/splash/SplashBitmap.cc b/kpdf/xpdf/splash/SplashBitmap.cc new file mode 100644 index 00000000..0cb1a752 --- /dev/null +++ b/kpdf/xpdf/splash/SplashBitmap.cc @@ -0,0 +1,188 @@ +//======================================================================== +// +// SplashBitmap.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "gmem.h" +#include "SplashErrorCodes.h" +#include "SplashBitmap.h" + +//------------------------------------------------------------------------ +// SplashBitmap +//------------------------------------------------------------------------ + +SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad, + SplashColorMode modeA, GBool alphaA, + GBool topDown) { + width = widthA; + height = heightA; + mode = modeA; + switch (mode) { + case splashModeMono1: + rowSize = (width + 7) >> 3; + break; + case splashModeMono8: + rowSize = width; + break; + case splashModeRGB8: + case splashModeBGR8: + rowSize = width * 3; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + rowSize = width * 4; + break; +#endif + } + rowSize += rowPad - 1; + rowSize -= rowSize % rowPad; + data = (SplashColorPtr)gmalloc(rowSize * height); + if (!topDown) { + data += (height - 1) * rowSize; + rowSize = -rowSize; + } + if (alphaA) { + alpha = (Guchar *)gmalloc(width * height); + } else { + alpha = NULL; + } +} + + +SplashBitmap::~SplashBitmap() { + if (rowSize < 0) { + gfree(data + (height - 1) * rowSize); + } else { + gfree(data); + } + gfree(alpha); +} + +SplashError SplashBitmap::writePNMFile(char *fileName) { + FILE *f; + SplashColorPtr row, p; + int x, y; + + if (!(f = fopen(fileName, "wb"))) { + return splashErrOpenFile; + } + + switch (mode) { + + case splashModeMono1: + fprintf(f, "P4\n%d %d\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; x += 8) { + fputc(*p ^ 0xff, f); + ++p; + } + row += rowSize; + } + break; + + case splashModeMono8: + fprintf(f, "P5\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; ++x) { + fputc(*p, f); + ++p; + } + row += rowSize; + } + break; + + case splashModeRGB8: + fprintf(f, "P6\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; ++x) { + fputc(splashRGB8R(p), f); + fputc(splashRGB8G(p), f); + fputc(splashRGB8B(p), f); + p += 3; + } + row += rowSize; + } + break; + + case splashModeBGR8: + fprintf(f, "P6\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; ++x) { + fputc(splashBGR8R(p), f); + fputc(splashBGR8G(p), f); + fputc(splashBGR8B(p), f); + p += 3; + } + row += rowSize; + } + break; + +#if SPLASH_CMYK + case splashModeCMYK8: + // PNM doesn't support CMYK + break; +#endif + } + + fclose(f); + return splashOk; +} + +void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) { + SplashColorPtr p; + + if (y < 0 || y >= height || x < 0 || x >= width) { + return; + } + switch (mode) { + case splashModeMono1: + p = &data[y * rowSize + (x >> 3)]; + pixel[0] = (p[0] & (0x80 >> (x & 7))) ? 0xff : 0x00; + break; + case splashModeMono8: + p = &data[y * rowSize + x]; + pixel[0] = p[0]; + break; + case splashModeRGB8: + p = &data[y * rowSize + 3 * x]; + pixel[0] = p[0]; + pixel[1] = p[1]; + pixel[2] = p[2]; + break; + case splashModeBGR8: + p = &data[y * rowSize + 3 * x]; + pixel[0] = p[2]; + pixel[1] = p[1]; + pixel[2] = p[0]; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + p = &data[y * rowSize + 4 * x]; + pixel[0] = p[0]; + pixel[1] = p[1]; + pixel[2] = p[2]; + pixel[3] = p[3]; + break; +#endif + } +} + +Guchar SplashBitmap::getAlpha(int x, int y) { + return alpha[y * width + x]; +} diff --git a/kpdf/xpdf/splash/SplashBitmap.h b/kpdf/xpdf/splash/SplashBitmap.h new file mode 100644 index 00000000..69ab058e --- /dev/null +++ b/kpdf/xpdf/splash/SplashBitmap.h @@ -0,0 +1,61 @@ +//======================================================================== +// +// SplashBitmap.h +// +//======================================================================== + +#ifndef SPLASHBITMAP_H +#define SPLASHBITMAP_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +//------------------------------------------------------------------------ +// SplashBitmap +//------------------------------------------------------------------------ + +class SplashBitmap { +public: + + // Create a new bitmap. It will have x pixels in + // color mode . Rows will be padded out to a multiple of + // bytes. If is false, the bitmap will be stored + // upside-down, i.e., with the last row first in memory. + SplashBitmap(int widthA, int heightA, int rowPad, + SplashColorMode modeA, GBool alphaA, + GBool topDown = gTrue); + + ~SplashBitmap(); + + int getWidth() { return width; } + int getHeight() { return height; } + int getRowSize() { return rowSize; } + int getAlphaRowSize() { return width; } + SplashColorMode getMode() { return mode; } + SplashColorPtr getDataPtr() { return data; } + Guchar *getAlphaPtr() { return alpha; } + + SplashError writePNMFile(char *fileName); + + void getPixel(int x, int y, SplashColorPtr pixel); + Guchar getAlpha(int x, int y); + +private: + + int width, height; // size of bitmap + int rowSize; // size of one row of data, in bytes + // - negative for bottom-up bitmaps + SplashColorMode mode; // color mode + SplashColorPtr data; // pointer to row zero of the color data + Guchar *alpha; // pointer to row zero of the alpha data + // (always top-down) + + friend class Splash; +}; + +#endif diff --git a/kpdf/xpdf/splash/SplashClip.cc b/kpdf/xpdf/splash/SplashClip.cc new file mode 100644 index 00000000..ef8acbab --- /dev/null +++ b/kpdf/xpdf/splash/SplashClip.cc @@ -0,0 +1,382 @@ +//======================================================================== +// +// SplashClip.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "SplashErrorCodes.h" +#include "SplashPath.h" +#include "SplashXPath.h" +#include "SplashXPathScanner.h" +#include "SplashBitmap.h" +#include "SplashClip.h" + +//------------------------------------------------------------------------ +// SplashClip.flags +//------------------------------------------------------------------------ + +#define splashClipEO 0x01 // use even-odd rule + +//------------------------------------------------------------------------ +// SplashClip +//------------------------------------------------------------------------ + +SplashClip::SplashClip(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + GBool antialiasA) { + antialias = antialiasA; + if (x0 < x1) { + xMin = x0; + xMax = x1; + } else { + xMin = x1; + xMax = x0; + } + if (y0 < y1) { + yMin = y0; + yMax = y1; + } else { + yMin = y1; + yMax = y0; + } + xMinI = splashFloor(xMin); + yMinI = splashFloor(yMin); + xMaxI = splashFloor(xMax); + yMaxI = splashFloor(yMax); + paths = NULL; + flags = NULL; + scanners = NULL; + length = size = 0; +} + +SplashClip::SplashClip(SplashClip *clip) { + int i; + + antialias = clip->antialias; + xMin = clip->xMin; + yMin = clip->yMin; + xMax = clip->xMax; + yMax = clip->yMax; + xMinI = clip->xMinI; + yMinI = clip->yMinI; + xMaxI = clip->xMaxI; + yMaxI = clip->yMaxI; + length = clip->length; + size = clip->size; + paths = (SplashXPath **)gmallocn(size, sizeof(SplashXPath *)); + flags = (Guchar *)gmallocn(size, sizeof(Guchar)); + scanners = (SplashXPathScanner **) + gmallocn(size, sizeof(SplashXPathScanner *)); + for (i = 0; i < length; ++i) { + paths[i] = clip->paths[i]->copy(); + flags[i] = clip->flags[i]; + scanners[i] = new SplashXPathScanner(paths[i], flags[i] & splashClipEO); + } +} + +SplashClip::~SplashClip() { + int i; + + for (i = 0; i < length; ++i) { + delete paths[i]; + delete scanners[i]; + } + gfree(paths); + gfree(flags); + gfree(scanners); +} + +void SplashClip::grow(int nPaths) { + if (length + nPaths > size) { + if (size == 0) { + size = 32; + } + while (size < length + nPaths) { + size *= 2; + } + paths = (SplashXPath **)greallocn(paths, size, sizeof(SplashXPath *)); + flags = (Guchar *)greallocn(flags, size, sizeof(Guchar)); + scanners = (SplashXPathScanner **) + greallocn(scanners, size, sizeof(SplashXPathScanner *)); + } +} + +void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + int i; + + for (i = 0; i < length; ++i) { + delete paths[i]; + delete scanners[i]; + } + gfree(paths); + gfree(flags); + gfree(scanners); + paths = NULL; + flags = NULL; + scanners = NULL; + length = size = 0; + + if (x0 < x1) { + xMin = x0; + xMax = x1; + } else { + xMin = x1; + xMax = x0; + } + if (y0 < y1) { + yMin = y0; + yMax = y1; + } else { + yMin = y1; + yMax = y0; + } + xMinI = splashFloor(xMin); + yMinI = splashFloor(yMin); + xMaxI = splashFloor(xMax); + yMaxI = splashFloor(yMax); +} + +SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + if (x0 < x1) { + if (x0 > xMin) { + xMin = x0; + xMinI = splashFloor(xMin); + } + if (x1 < xMax) { + xMax = x1; + xMaxI = splashFloor(xMax); + } + } else { + if (x1 > xMin) { + xMin = x1; + xMinI = splashFloor(xMin); + } + if (x0 < xMax) { + xMax = x0; + xMaxI = splashFloor(xMax); + } + } + if (y0 < y1) { + if (y0 > yMin) { + yMin = y0; + yMinI = splashFloor(yMin); + } + if (y1 < yMax) { + yMax = y1; + yMaxI = splashFloor(yMax); + } + } else { + if (y1 > yMin) { + yMin = y1; + yMinI = splashFloor(yMin); + } + if (y0 < yMax) { + yMax = y0; + yMaxI = splashFloor(yMax); + } + } + return splashOk; +} + +SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix, + SplashCoord flatness, GBool eo) { + SplashXPath *xPath; + + xPath = new SplashXPath(path, matrix, flatness, gTrue); + + // check for an empty path + if (xPath->length == 0) { + xMax = xMin - 1; + yMax = yMin - 1; + xMaxI = splashFloor(xMax); + yMaxI = splashFloor(yMax); + delete xPath; + + // check for a rectangle + } else if (xPath->length == 4 && + ((xPath->segs[0].x0 == xPath->segs[0].x1 && + xPath->segs[0].x0 == xPath->segs[1].x0 && + xPath->segs[0].x0 == xPath->segs[3].x1 && + xPath->segs[2].x0 == xPath->segs[2].x1 && + xPath->segs[2].x0 == xPath->segs[1].x1 && + xPath->segs[2].x0 == xPath->segs[3].x0 && + xPath->segs[1].y0 == xPath->segs[1].y1 && + xPath->segs[1].y0 == xPath->segs[0].y1 && + xPath->segs[1].y0 == xPath->segs[2].y0 && + xPath->segs[3].y0 == xPath->segs[3].y1 && + xPath->segs[3].y0 == xPath->segs[0].y0 && + xPath->segs[3].y0 == xPath->segs[2].y1) || + (xPath->segs[0].y0 == xPath->segs[0].y1 && + xPath->segs[0].y0 == xPath->segs[1].y0 && + xPath->segs[0].y0 == xPath->segs[3].y1 && + xPath->segs[2].y0 == xPath->segs[2].y1 && + xPath->segs[2].y0 == xPath->segs[1].y1 && + xPath->segs[2].y0 == xPath->segs[3].y0 && + xPath->segs[1].x0 == xPath->segs[1].x1 && + xPath->segs[1].x0 == xPath->segs[0].x1 && + xPath->segs[1].x0 == xPath->segs[2].x0 && + xPath->segs[3].x0 == xPath->segs[3].x1 && + xPath->segs[3].x0 == xPath->segs[0].x0 && + xPath->segs[3].x0 == xPath->segs[2].x1))) { + clipToRect(xPath->segs[0].x0, xPath->segs[0].y0, + xPath->segs[2].x0, xPath->segs[2].y0); + delete xPath; + + } else { + grow(1); + if (antialias) { + xPath->aaScale(); + } + xPath->sort(); + paths[length] = xPath; + flags[length] = eo ? splashClipEO : 0; + scanners[length] = new SplashXPathScanner(xPath, eo); + ++length; + } + + return splashOk; +} + +GBool SplashClip::test(int x, int y) { + int i; + + // check the rectangle + if (x < xMinI || x > xMaxI || y < yMinI || y > yMaxI) { + return gFalse; + } + + // check the paths + if (antialias) { + for (i = 0; i < length; ++i) { + if (!scanners[i]->test(x * splashAASize, y * splashAASize)) { + return gFalse; + } + } + } else { + for (i = 0; i < length; ++i) { + if (!scanners[i]->test(x, y)) { + return gFalse; + } + } + } + + return gTrue; +} + +SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin, + int rectXMax, int rectYMax) { + // This tests the rectangle: + // x = [rectXMin, rectXMax + 1) (note: rect coords are ints) + // y = [rectYMin, rectYMax + 1) + // against the clipping region: + // x = [xMin, xMax] (note: clipping coords are fp) + // y = [yMin, yMax] + if ((SplashCoord)(rectXMax + 1) <= xMin || (SplashCoord)rectXMin > xMax || + (SplashCoord)(rectYMax + 1) <= yMin || (SplashCoord)rectYMin > yMax) { + return splashClipAllOutside; + } + if ((SplashCoord)rectXMin >= xMin && (SplashCoord)(rectXMax + 1) <= xMax && + (SplashCoord)rectYMin >= yMin && (SplashCoord)(rectYMax + 1) <= yMax && + length == 0) { + return splashClipAllInside; + } + return splashClipPartial; +} + +SplashClipResult SplashClip::testSpan(int spanXMin, int spanXMax, int spanY) { + int i; + + // This tests the rectangle: + // x = [spanXMin, spanXMax + 1) (note: span coords are ints) + // y = [spanY, spanY + 1) + // against the clipping region: + // x = [xMin, xMax] (note: clipping coords are fp) + // y = [yMin, yMax] + if ((SplashCoord)(spanXMax + 1) <= xMin || (SplashCoord)spanXMin > xMax || + (SplashCoord)(spanY + 1) <= yMin || (SplashCoord)spanY > yMax) { + return splashClipAllOutside; + } + if (!((SplashCoord)spanXMin >= xMin && (SplashCoord)(spanXMax + 1) <= xMax && + (SplashCoord)spanY >= yMin && (SplashCoord)(spanY + 1) <= yMax)) { + return splashClipPartial; + } + if (antialias) { + for (i = 0; i < length; ++i) { + if (!scanners[i]->testSpan(spanXMin * splashAASize, + spanXMax * splashAASize + (splashAASize - 1), + spanY * splashAASize)) { + return splashClipPartial; + } + } + } else { + for (i = 0; i < length; ++i) { + if (!scanners[i]->testSpan(spanXMin, spanXMax, spanY)) { + return splashClipPartial; + } + } + } + return splashClipAllInside; +} + +void SplashClip::clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y) { + int xx0, xx1, xx, yy, i; + SplashColorPtr p; + + // zero out pixels with x < xMin + xx0 = *x0 * splashAASize; + xx1 = splashFloor(xMin * splashAASize); + if (xx1 > aaBuf->getWidth()) { + xx1 = aaBuf->getWidth(); + } + if (xx0 < xx1) { + xx0 &= ~7; + for (yy = 0; yy < splashAASize; ++yy) { + p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3); + for (xx = xx0; xx + 7 < xx1; xx += 8) { + *p++ = 0; + } + if (xx < xx1) { + *p &= 0xff >> (xx1 & 7); + } + } + *x0 = splashFloor(xMin); + } + + // zero out pixels with x > xMax + xx0 = splashFloor(xMax * splashAASize) + 1; + if (xx0 < 0) { + xx0 = 0; + } + xx1 = (*x1 + 1) * splashAASize; + if (xx0 < xx1) { + for (yy = 0; yy < splashAASize; ++yy) { + p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3); + xx = xx0; + if (xx & 7) { + *p &= 0xff00 >> (xx & 7); + xx = (xx & ~7) + 8; + ++p; + } + for (; xx < xx1; xx += 8) { + *p++ = 0; + } + } + *x1 = splashFloor(xMax); + } + + // check the paths + for (i = 0; i < length; ++i) { + scanners[i]->clipAALine(aaBuf, x0, x1, y); + } +} diff --git a/kpdf/xpdf/splash/SplashClip.h b/kpdf/xpdf/splash/SplashClip.h new file mode 100644 index 00000000..8ae2154b --- /dev/null +++ b/kpdf/xpdf/splash/SplashClip.h @@ -0,0 +1,107 @@ +//======================================================================== +// +// SplashClip.h +// +//======================================================================== + +#ifndef SPLASHCLIP_H +#define SPLASHCLIP_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" +#include "SplashMath.h" + +class SplashPath; +class SplashXPath; +class SplashXPathScanner; +class SplashBitmap; + +//------------------------------------------------------------------------ + +enum SplashClipResult { + splashClipAllInside, + splashClipAllOutside, + splashClipPartial +}; + +//------------------------------------------------------------------------ +// SplashClip +//------------------------------------------------------------------------ + +class SplashClip { +public: + + // Create a clip, for the given rectangle. + SplashClip(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + GBool antialiasA); + + // Copy a clip. + SplashClip *copy() { return new SplashClip(this); } + + ~SplashClip(); + + // Reset the clip to a rectangle. + void resetToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + + // Intersect the clip with a rectangle. + SplashError clipToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + + // Interesect the clip with . + SplashError clipToPath(SplashPath *path, SplashCoord *matrix, + SplashCoord flatness, GBool eo); + + // Returns true if (,) is inside the clip. + GBool test(int x, int y); + + // Tests a rectangle against the clipping region. Returns one of: + // - splashClipAllInside if the entire rectangle is inside the + // clipping region, i.e., all pixels in the rectangle are + // visible + // - splashClipAllOutside if the entire rectangle is outside the + // clipping region, i.e., all the pixels in the rectangle are + // clipped + // - splashClipPartial if the rectangle is part inside and part + // outside the clipping region + SplashClipResult testRect(int rectXMin, int rectYMin, + int rectXMax, int rectYMax); + + // Similar to testRect, but tests a horizontal span. + SplashClipResult testSpan(int spanXMin, int spanXMax, int spanY); + + // Clips an anti-aliased line by setting pixels to zero. On entry, + // all non-zero pixels are between and . This function + // will update and . + void clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y); + + // Get the rectangle part of the clip region, in integer coordinates. + int getXMinI() { return xMinI; } + int getXMaxI() { return xMaxI; } + int getYMinI() { return yMinI; } + int getYMaxI() { return yMaxI; } + + // Get the number of arbitrary paths used by the clip region. + int getNumPaths() { return length; } + +private: + + SplashClip(SplashClip *clip); + void grow(int nPaths); + + GBool antialias; + SplashCoord xMin, yMin, xMax, yMax; + int xMinI, yMinI, xMaxI, yMaxI; + SplashXPath **paths; + Guchar *flags; + SplashXPathScanner **scanners; + int length, size; +}; + +#endif diff --git a/kpdf/xpdf/splash/SplashErrorCodes.h b/kpdf/xpdf/splash/SplashErrorCodes.h new file mode 100644 index 00000000..e7f1f0b5 --- /dev/null +++ b/kpdf/xpdf/splash/SplashErrorCodes.h @@ -0,0 +1,34 @@ +//======================================================================== +// +// SplashErrorCodes.h +// +//======================================================================== + +#ifndef SPLASHERRORCODES_H +#define SPLASHERRORCODES_H + +#include + +//------------------------------------------------------------------------ + +#define splashOk 0 // no error + +#define splashErrNoCurPt 1 // no current point + +#define splashErrEmptyPath 2 // zero points in path + +#define splashErrBogusPath 3 // only one point in subpath + +#define splashErrNoSave 4 // state stack is empty + +#define splashErrOpenFile 5 // couldn't open file + +#define splashErrNoGlyph 6 // couldn't get the requested glyph + +#define splashErrModeMismatch 7 // invalid combination of color modes + +#define splashErrSingularMatrix 8 // matrix is singular + +#define splashErrZeroImage 9 // image of 0x0 + +#endif diff --git a/kpdf/xpdf/splash/SplashFTFont.cc b/kpdf/xpdf/splash/SplashFTFont.cc new file mode 100644 index 00000000..42d92af4 --- /dev/null +++ b/kpdf/xpdf/splash/SplashFTFont.cc @@ -0,0 +1,375 @@ +//======================================================================== +// +// SplashFTFont.cc +// +//======================================================================== + +#include + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include FT_OUTLINE_H +#include FT_SIZES_H +#include FT_GLYPH_H +#include "gmem.h" +#include "SplashMath.h" +#include "SplashGlyphBitmap.h" +#include "SplashPath.h" +#include "SplashFTFontEngine.h" +#include "SplashFTFontFile.h" +#include "SplashFTFont.h" + +//------------------------------------------------------------------------ + +static int glyphPathMoveTo(const FT_Vector *pt, void *path); +static int glyphPathLineTo(const FT_Vector *pt, void *path); +static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt, + void *path); +static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2, + const FT_Vector *pt, void *path); + +//------------------------------------------------------------------------ +// SplashFTFont +//------------------------------------------------------------------------ + +SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA, + SplashCoord *textMatA): + SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa) +{ + FT_Face face; + SplashCoord size, div; + int x, y; + + face = fontFileA->face; + if (FT_New_Size(face, &sizeObj)) { + return; + } + face->size = sizeObj; + size = splashSqrt(mat[2]*mat[2] + mat[3]*mat[3]); + if (FT_Set_Pixel_Sizes(face, 0, (int)size)) { + return; + } + // if the textMat values are too small, FreeType's fixed point + // arithmetic doesn't work so well + textScale = splashSqrt(textMat[2]*textMat[2] + textMat[3]*textMat[3]) / size; + + div = face->bbox.xMax > 20000 ? 65536 : 1; + + // transform the four corners of the font bounding box -- the min + // and max values form the bounding box of the transformed font + x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMin) / + (div * face->units_per_EM)); + xMin = xMax = x; + y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMin) / + (div * face->units_per_EM)); + yMin = yMax = y; + x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMax) / + (div * face->units_per_EM)); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMax) / + (div * face->units_per_EM)); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMin) / + (div * face->units_per_EM)); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMin) / + (div * face->units_per_EM)); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMax) / + (div * face->units_per_EM)); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMax) / + (div * face->units_per_EM)); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + // This is a kludge: some buggy PDF generators embed fonts with + // zero bounding boxes. + if (xMax == xMin) { + xMin = 0; + xMax = (int)size; + } + if (yMax == yMin) { + yMin = 0; + yMax = (int)((SplashCoord)1.2 * size); + } + + // compute the transform matrix +#if USE_FIXEDPOINT + matrix.xx = (FT_Fixed)((mat[0] / size).getRaw()); + matrix.yx = (FT_Fixed)((mat[1] / size).getRaw()); + matrix.xy = (FT_Fixed)((mat[2] / size).getRaw()); + matrix.yy = (FT_Fixed)((mat[3] / size).getRaw()); + textMatrix.xx = (FT_Fixed)((textMat[0] / (size * textScale)).getRaw()); + textMatrix.yx = (FT_Fixed)((textMat[1] / (size * textScale)).getRaw()); + textMatrix.xy = (FT_Fixed)((textMat[2] / (size * textScale)).getRaw()); + textMatrix.yy = (FT_Fixed)((textMat[3] / (size * textScale)).getRaw()); +#else + matrix.xx = (FT_Fixed)((mat[0] / size) * 65536); + matrix.yx = (FT_Fixed)((mat[1] / size) * 65536); + matrix.xy = (FT_Fixed)((mat[2] / size) * 65536); + matrix.yy = (FT_Fixed)((mat[3] / size) * 65536); + textMatrix.xx = (FT_Fixed)((textMat[0] / (size * textScale)) * 65536); + textMatrix.yx = (FT_Fixed)((textMat[1] / (size * textScale)) * 65536); + textMatrix.xy = (FT_Fixed)((textMat[2] / (size * textScale)) * 65536); + textMatrix.yy = (FT_Fixed)((textMat[3] / (size * textScale)) * 65536); +#endif +} + +SplashFTFont::~SplashFTFont() { +} + +GBool SplashFTFont::getGlyph(int c, int xFrac, int /*yFrac*/, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) { + return SplashFont::getGlyph(c, xFrac, 0, bitmap, x0, y0, clip, clipRes); +} + +GBool SplashFTFont::makeGlyph(int c, int xFrac, int /*yFrac*/, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) { + SplashFTFontFile *ff; + FT_Vector offset; + FT_GlyphSlot slot; + FT_UInt gid; + int rowSize; + Guchar *p, *q; + int i; + + ff = (SplashFTFontFile *)fontFile; + + ff->face->size = sizeObj; + offset.x = (FT_Pos)(int)((SplashCoord)xFrac * splashFontFractionMul * 64); + offset.y = 0; + FT_Set_Transform(ff->face, &matrix, &offset); + slot = ff->face->glyph; + + if (ff->codeToGID && c < ff->codeToGIDLen) { + gid = (FT_UInt)ff->codeToGID[c]; + } else { + gid = (FT_UInt)c; + } + if (ff->trueType && gid == 0) { + // skip the TrueType notdef glyph + return gFalse; + } + + // if we have the FT2 bytecode interpreter, autohinting won't be used +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + if (FT_Load_Glyph(ff->face, gid, + aa ? FT_LOAD_NO_BITMAP : FT_LOAD_DEFAULT)) { + return gFalse; + } +#else + // FT2's autohinting doesn't always work very well (especially with + // font subsets), so turn it off if anti-aliasing is enabled; if + // anti-aliasing is disabled, this seems to be a tossup - some fonts + // look better with hinting, some without, so leave hinting on + if (FT_Load_Glyph(ff->face, gid, + aa ? FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP + : FT_LOAD_DEFAULT)) { + return gFalse; + } +#endif + + FT_Glyph_Metrics *glyphMetrics = &(ff->face->glyph->metrics); + // prelimirary values from FT_Glyph_Metrics + bitmap->x = splashRound(-glyphMetrics->horiBearingX / 64.0); + bitmap->y = splashRound(glyphMetrics->horiBearingY / 64.0); + bitmap->w = splashRound(glyphMetrics->width / 64.0); + bitmap->h = splashRound(glyphMetrics->height / 64.0); + + *clipRes = clip->testRect(x0 - bitmap->x, + y0 - bitmap->y, + x0 - bitmap->x + bitmap->w - 1, + y0 - bitmap->y + bitmap->h - 1); + if (*clipRes == splashClipAllOutside) + { + bitmap->freeData = gFalse; + return gTrue; + } + + if (FT_Render_Glyph(slot, aa ? ft_render_mode_normal + : ft_render_mode_mono)) { + return gFalse; + } + + bitmap->x = -slot->bitmap_left; + bitmap->y = slot->bitmap_top; + bitmap->w = slot->bitmap.width; + bitmap->h = slot->bitmap.rows; + bitmap->aa = aa; + if (aa) { + rowSize = bitmap->w; + } else { + rowSize = (bitmap->w + 7) >> 3; + } + bitmap->data = (Guchar *)gmalloc(rowSize * bitmap->h); + bitmap->freeData = gTrue; + for (i = 0, p = bitmap->data, q = slot->bitmap.buffer; + i < bitmap->h; + ++i, p += rowSize, q += slot->bitmap.pitch) { + memcpy(p, q, rowSize); + } + + return gTrue; +} + +struct SplashFTFontPath { + SplashPath *path; + SplashCoord textScale; + GBool needClose; +}; + +SplashPath *SplashFTFont::getGlyphPath(int c) { + static FT_Outline_Funcs outlineFuncs = { +#if FREETYPE_MINOR <= 1 + (int (*)(FT_Vector *, void *))&glyphPathMoveTo, + (int (*)(FT_Vector *, void *))&glyphPathLineTo, + (int (*)(FT_Vector *, FT_Vector *, void *))&glyphPathConicTo, + (int (*)(FT_Vector *, FT_Vector *, FT_Vector *, void *))&glyphPathCubicTo, +#else + &glyphPathMoveTo, + &glyphPathLineTo, + &glyphPathConicTo, + &glyphPathCubicTo, +#endif + 0, 0 + }; + SplashFTFontFile *ff; + SplashFTFontPath path; + FT_GlyphSlot slot; + FT_UInt gid; + FT_Glyph glyph; + + ff = (SplashFTFontFile *)fontFile; + ff->face->size = sizeObj; + FT_Set_Transform(ff->face, &textMatrix, NULL); + slot = ff->face->glyph; + if (ff->codeToGID && c < ff->codeToGIDLen) { + gid = ff->codeToGID[c]; + } else { + gid = (FT_UInt)c; + } + if (ff->trueType && gid == 0) { + // skip the TrueType notdef glyph + return NULL; + } + if (FT_Load_Glyph(ff->face, gid, FT_LOAD_NO_BITMAP)) { + return NULL; + } + if (FT_Get_Glyph(slot, &glyph)) { + return NULL; + } + path.path = new SplashPath(); + path.textScale = textScale; + path.needClose = gFalse; + FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline, + &outlineFuncs, &path); + if (path.needClose) { + path.path->close(); + } + FT_Done_Glyph(glyph); + return path.path; +} + +static int glyphPathMoveTo(const FT_Vector *pt, void *path) { + SplashFTFontPath *p = (SplashFTFontPath *)path; + + if (p->needClose) { + p->path->close(); + p->needClose = gFalse; + } + p->path->moveTo((SplashCoord)pt->x * p->textScale / 64.0, + (SplashCoord)pt->y * p->textScale / 64.0); + return 0; +} + +static int glyphPathLineTo(const FT_Vector *pt, void *path) { + SplashFTFontPath *p = (SplashFTFontPath *)path; + + p->path->lineTo((SplashCoord)pt->x * p->textScale / 64.0, + (SplashCoord)pt->y * p->textScale / 64.0); + p->needClose = gTrue; + return 0; +} + +static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt, + void *path) { + SplashFTFontPath *p = (SplashFTFontPath *)path; + SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc; + + if (!p->path->getCurPt(&x0, &y0)) { + return 0; + } + xc = (SplashCoord)ctrl->x * p->textScale / 64.0; + yc = (SplashCoord)ctrl->y * p->textScale / 64.0; + x3 = (SplashCoord)pt->x * p->textScale / 64.0; + y3 = (SplashCoord)pt->y * p->textScale / 64.0; + + // A second-order Bezier curve is defined by two endpoints, p0 and + // p3, and one control point, pc: + // + // p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3 + // + // A third-order Bezier curve is defined by the same two endpoints, + // p0 and p3, and two control points, p1 and p2: + // + // p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3 + // + // Applying some algebra, we can convert a second-order curve to a + // third-order curve: + // + // p1 = (1/3) * (p0 + 2pc) + // p2 = (1/3) * (2pc + p3) + + x1 = (SplashCoord)(1.0 / 3.0) * (x0 + (SplashCoord)2 * xc); + y1 = (SplashCoord)(1.0 / 3.0) * (y0 + (SplashCoord)2 * yc); + x2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * xc + x3); + y2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * yc + y3); + + p->path->curveTo(x1, y1, x2, y2, x3, y3); + p->needClose = gTrue; + return 0; +} + +static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2, + const FT_Vector *pt, void *path) { + SplashFTFontPath *p = (SplashFTFontPath *)path; + + p->path->curveTo((SplashCoord)ctrl1->x * p->textScale / 64.0, + (SplashCoord)ctrl1->y * p->textScale / 64.0, + (SplashCoord)ctrl2->x * p->textScale / 64.0, + (SplashCoord)ctrl2->y * p->textScale / 64.0, + (SplashCoord)pt->x * p->textScale / 64.0, + (SplashCoord)pt->y * p->textScale / 64.0); + p->needClose = gTrue; + return 0; +} + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H diff --git a/kpdf/xpdf/splash/SplashFTFont.h b/kpdf/xpdf/splash/SplashFTFont.h new file mode 100644 index 00000000..e014ba3f --- /dev/null +++ b/kpdf/xpdf/splash/SplashFTFont.h @@ -0,0 +1,58 @@ +//======================================================================== +// +// SplashFTFont.h +// +//======================================================================== + +#ifndef SPLASHFTFONT_H +#define SPLASHFTFONT_H + +#include + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include +#include FT_FREETYPE_H +#include "SplashFont.h" + +class SplashFTFontFile; + +//------------------------------------------------------------------------ +// SplashFTFont +//------------------------------------------------------------------------ + +class SplashFTFont: public SplashFont { +public: + + SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA, + SplashCoord *textMatA); + + virtual ~SplashFTFont(); + + // Munge xFrac and yFrac before calling SplashFont::getGlyph. + virtual GBool getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes); + + // Rasterize a glyph. The and values are the same + // as described for getGlyph. + virtual GBool makeGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes); + + // Return the path for a glyph. + virtual SplashPath *getGlyphPath(int c); + +private: + + FT_Size sizeObj; + FT_Matrix matrix; + FT_Matrix textMatrix; + SplashCoord textScale; +}; + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#endif diff --git a/kpdf/xpdf/splash/SplashFTFontEngine.cc b/kpdf/xpdf/splash/SplashFTFontEngine.cc new file mode 100644 index 00000000..02996de7 --- /dev/null +++ b/kpdf/xpdf/splash/SplashFTFontEngine.cc @@ -0,0 +1,194 @@ +//======================================================================== +// +// SplashFTFontEngine.cc +// +//======================================================================== + +#include + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#ifndef WIN32 +# include +#endif +#include "gmem.h" +#include "GString.h" +#include "gfile.h" +#include "FoFiTrueType.h" +#include "FoFiType1C.h" +#include "SplashFTFontFile.h" +#include "SplashFTFontEngine.h" + +#ifdef VMS +#if (__VMS_VER < 70000000) +extern "C" int unlink(char *filename); +#endif +#endif + +//------------------------------------------------------------------------ +/* +static void fileWrite(void *stream, char *data, int len) { + fwrite(data, 1, len, (FILE *)stream); +} +*/ + +//------------------------------------------------------------------------ +// SplashFTFontEngine +//------------------------------------------------------------------------ + +SplashFTFontEngine::SplashFTFontEngine(GBool aaA, FT_Library libA) { + FT_Int major, minor, patch; + + aa = aaA; + lib = libA; + + // as of FT 2.1.8, CID fonts are indexed by CID instead of GID + FT_Library_Version(lib, &major, &minor, &patch); + useCIDs = major > 2 || + (major == 2 && (minor > 1 || (minor == 1 && patch > 7))); +} + +SplashFTFontEngine *SplashFTFontEngine::init(GBool aaA) { + FT_Library libA; + + if (FT_Init_FreeType(&libA)) { + return NULL; + } + return new SplashFTFontEngine(aaA, libA); +} + +SplashFTFontEngine::~SplashFTFontEngine() { + FT_Done_FreeType(lib); +} + +SplashFontFile *SplashFTFontEngine::loadType1Font(SplashFontFileID *idA, + SplashFontSrc *src, + char **enc) { + return SplashFTFontFile::loadType1Font(this, idA, src, enc); +} + +SplashFontFile *SplashFTFontEngine::loadType1CFont(SplashFontFileID *idA, + SplashFontSrc *src, + char **enc) { + return SplashFTFontFile::loadType1Font(this, idA, src, enc); +} + +SplashFontFile *SplashFTFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA, + SplashFontSrc *src, + char **enc) { + return SplashFTFontFile::loadType1Font(this, idA, src, enc); +} + +SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA, + SplashFontSrc *src) { + FoFiType1C *ff; + Gushort *cidToGIDMap; + int nCIDs; + SplashFontFile *ret; + + // check for a CFF font + if (useCIDs) { + cidToGIDMap = NULL; + nCIDs = 0; + } else { + if (src->isFile) { + ff = FoFiType1C::load(src->fileName->getCString()); + } else { + ff = FoFiType1C::make(src->buf, src->bufLen); + } + if (ff) { + cidToGIDMap = ff->getCIDToGIDMap(&nCIDs); + delete ff; + } else { + cidToGIDMap = NULL; + nCIDs = 0; + } + } + ret = SplashFTFontFile::loadCIDFont(this, idA, src, cidToGIDMap, nCIDs); + if (!ret) { + gfree(cidToGIDMap); + } + return ret; +} + +SplashFontFile *SplashFTFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA, + SplashFontSrc *src) { + FoFiTrueType *ff; + GBool isCID; + Gushort *cidToGIDMap; + int nCIDs; + SplashFontFile *ret; + + cidToGIDMap = NULL; + nCIDs = 0; + isCID = gFalse; + if (!useCIDs) { + if (src->isFile) { + ff = FoFiTrueType::load(src->fileName->getCString()); + } else { + ff = FoFiTrueType::make(src->buf, src->bufLen); + } + if (ff) { + if (ff->isOpenTypeCFF()) { + cidToGIDMap = ff->getCIDToGIDMap(&nCIDs); + } + delete ff; + } + } + ret = SplashFTFontFile::loadCIDFont(this, idA, src, + cidToGIDMap, nCIDs); + if (!ret) { + gfree(cidToGIDMap); + } + return ret; +} + +SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA, + SplashFontSrc *src, + Gushort *codeToGID, + int codeToGIDLen, + int faceIndex) { +#if 0 + FoFiTrueType *ff; + GString *tmpFileName; + FILE *tmpFile; + SplashFontFile *ret; + + if (!(ff = FoFiTrueType::load(fileName))) { + return NULL; + } + tmpFileName = NULL; + if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) { + delete ff; + return NULL; + } + ff->writeTTF(&fileWrite, tmpFile); + delete ff; + fclose(tmpFile); + ret = SplashFTFontFile::loadTrueTypeFont(this, idA, + tmpFileName->getCString(), + gTrue, codeToGID, codeToGIDLen); + if (ret) { + if (deleteFile) { + unlink(fileName); + } + } else { + unlink(tmpFileName->getCString()); + } + delete tmpFileName; + return ret; +#else + SplashFontFile *ret; + ret = SplashFTFontFile::loadTrueTypeFont(this, idA, src, + codeToGID, codeToGIDLen, + faceIndex); + return ret; +#endif +} + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H diff --git a/kpdf/xpdf/splash/SplashFTFontEngine.h b/kpdf/xpdf/splash/SplashFTFontEngine.h new file mode 100644 index 00000000..294d20c6 --- /dev/null +++ b/kpdf/xpdf/splash/SplashFTFontEngine.h @@ -0,0 +1,60 @@ +//======================================================================== +// +// SplashFTFontEngine.h +// +//======================================================================== + +#ifndef SPLASHFTFONTENGINE_H +#define SPLASHFTFONTENGINE_H + +#include + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include +#include FT_FREETYPE_H +#include "gtypes.h" + +class SplashFontFile; +class SplashFontFileID; +class SplashFontSrc; + +//------------------------------------------------------------------------ +// SplashFTFontEngine +//------------------------------------------------------------------------ + +class SplashFTFontEngine { +public: + + static SplashFTFontEngine *init(GBool aaA); + + ~SplashFTFontEngine(); + + // Load fonts. + SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, char **enc); + SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, char **enc); + SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, SplashFontSrc *src, char **enc); + SplashFontFile *loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src); + SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontSrc *src); + SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src, + Gushort *codeToGID, int codeToGIDLen, int faceIndex = 0); + +private: + + SplashFTFontEngine(GBool aaA, FT_Library libA); + + GBool aa; + FT_Library lib; + GBool useCIDs; + + friend class SplashFTFontFile; + friend class SplashFTFont; +}; + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#endif diff --git a/kpdf/xpdf/splash/SplashFTFontFile.cc b/kpdf/xpdf/splash/SplashFTFontFile.cc new file mode 100644 index 00000000..12725497 --- /dev/null +++ b/kpdf/xpdf/splash/SplashFTFontFile.cc @@ -0,0 +1,125 @@ +//======================================================================== +// +// SplashFTFontFile.cc +// +//======================================================================== + +#include + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "gmem.h" +#include "SplashFTFontEngine.h" +#include "SplashFTFont.h" +#include "SplashFTFontFile.h" +#include "GString.h" + +//------------------------------------------------------------------------ +// SplashFTFontFile +//------------------------------------------------------------------------ + +SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontSrc *src, + char **encA) { + FT_Face faceA; + Gushort *codeToGIDA; + char *name; + int i; + + if (src->isFile) { + if (FT_New_Face(engineA->lib, src->fileName->getCString(), 0, &faceA)) + return NULL; + } else { + if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, 0, &faceA)) + return NULL; + } + codeToGIDA = (Gushort *)gmallocn(256, sizeof(int)); + for (i = 0; i < 256; ++i) { + codeToGIDA[i] = 0; + if ((name = encA[i])) { + codeToGIDA[i] = (Gushort)FT_Get_Name_Index(faceA, name); + } + } + + return new SplashFTFontFile(engineA, idA, src, + faceA, codeToGIDA, 256, gFalse); +} + +SplashFontFile *SplashFTFontFile::loadCIDFont(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontSrc *src, + Gushort *codeToGIDA, + int codeToGIDLenA) { + FT_Face faceA; + + if (src->isFile) { + if (FT_New_Face(engineA->lib, src->fileName->getCString(), 0, &faceA)) + return NULL; + } else { + if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, 0, &faceA)) + return NULL; + } + + return new SplashFTFontFile(engineA, idA, src, + faceA, codeToGIDA, codeToGIDLenA, gFalse); +} + +SplashFontFile *SplashFTFontFile::loadTrueTypeFont(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontSrc *src, + Gushort *codeToGIDA, + int codeToGIDLenA, + int faceIndexA) { + FT_Face faceA; + + if (src->isFile) { + if (FT_New_Face(engineA->lib, src->fileName->getCString(), faceIndexA, &faceA)) + return NULL; + } else { + if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, faceIndexA, &faceA)) + return NULL; + } + + return new SplashFTFontFile(engineA, idA, src, + faceA, codeToGIDA, codeToGIDLenA, gTrue); +} + +SplashFTFontFile::SplashFTFontFile(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontSrc *src, + FT_Face faceA, + Gushort *codeToGIDA, int codeToGIDLenA, + GBool trueTypeA): + SplashFontFile(idA, src) +{ + engine = engineA; + face = faceA; + codeToGID = codeToGIDA; + codeToGIDLen = codeToGIDLenA; + trueType = trueTypeA; +} + +SplashFTFontFile::~SplashFTFontFile() { + if (face) { + FT_Done_Face(face); + } + if (codeToGID) { + gfree(codeToGID); + } +} + +SplashFont *SplashFTFontFile::makeFont(SplashCoord *mat, + SplashCoord *textMat) { + SplashFont *font; + + font = new SplashFTFont(this, mat, textMat); + font->initCache(); + return font; +} + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H diff --git a/kpdf/xpdf/splash/SplashFTFontFile.h b/kpdf/xpdf/splash/SplashFTFontFile.h new file mode 100644 index 00000000..dedc25cf --- /dev/null +++ b/kpdf/xpdf/splash/SplashFTFontFile.h @@ -0,0 +1,72 @@ +//======================================================================== +// +// SplashFTFontFile.h +// +//======================================================================== + +#ifndef SPLASHFTFONTFILE_H +#define SPLASHFTFONTFILE_H + +#include + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include +#include FT_FREETYPE_H +#include "SplashFontFile.h" + +class SplashFontFileID; +class SplashFTFontEngine; + +//------------------------------------------------------------------------ +// SplashFTFontFile +//------------------------------------------------------------------------ + +class SplashFTFontFile: public SplashFontFile { +public: + + static SplashFontFile *loadType1Font(SplashFTFontEngine *engineA, + SplashFontFileID *idA, SplashFontSrc *src, + char **encA); + static SplashFontFile *loadCIDFont(SplashFTFontEngine *engineA, + SplashFontFileID *idA, SplashFontSrc *src, + Gushort *codeToCIDA, int codeToGIDLenA); + static SplashFontFile *loadTrueTypeFont(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontSrc *src, + Gushort *codeToGIDA, + int codeToGIDLenA, + int faceIndexA=0); + + virtual ~SplashFTFontFile(); + + // Create a new SplashFTFont, i.e., a scaled instance of this font + // file. + virtual SplashFont *makeFont(SplashCoord *mat, + SplashCoord *textMat); + +private: + + SplashFTFontFile(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontSrc *src, + FT_Face faceA, + Gushort *codeToGIDA, int codeToGIDLenA, + GBool trueTypeA); + + SplashFTFontEngine *engine; + FT_Face face; + Gushort *codeToGID; + int codeToGIDLen; + GBool trueType; + + friend class SplashFTFont; +}; + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#endif diff --git a/kpdf/xpdf/splash/SplashFont.cc b/kpdf/xpdf/splash/SplashFont.cc new file mode 100644 index 00000000..4a91d5e8 --- /dev/null +++ b/kpdf/xpdf/splash/SplashFont.cc @@ -0,0 +1,201 @@ +//======================================================================== +// +// SplashFont.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "gmem.h" +#include "SplashMath.h" +#include "SplashGlyphBitmap.h" +#include "SplashFontFile.h" +#include "SplashFont.h" + +//------------------------------------------------------------------------ + +struct SplashFontCacheTag { + int c; + short xFrac, yFrac; // x and y fractions + int mru; // valid bit (0x80000000) and MRU index + int x, y, w, h; // offset and size of glyph +}; + +//------------------------------------------------------------------------ +// SplashFont +//------------------------------------------------------------------------ + +SplashFont::SplashFont(SplashFontFile *fontFileA, SplashCoord *matA, + SplashCoord *textMatA, GBool aaA) { + fontFile = fontFileA; + fontFile->incRefCnt(); + mat[0] = matA[0]; + mat[1] = matA[1]; + mat[2] = matA[2]; + mat[3] = matA[3]; + textMat[0] = textMatA[0]; + textMat[1] = textMatA[1]; + textMat[2] = textMatA[2]; + textMat[3] = textMatA[3]; + aa = aaA; + + cache = NULL; + cacheTags = NULL; + + xMin = yMin = xMax = yMax = 0; +} + +void SplashFont::initCache() { + int i; + + // this should be (max - min + 1), but we add some padding to + // deal with rounding errors + glyphW = xMax - xMin + 3; + glyphH = yMax - yMin + 3; + if (aa) { + glyphSize = glyphW * glyphH; + } else { + glyphSize = ((glyphW + 7) >> 3) * glyphH; + } + + // set up the glyph pixmap cache + cacheAssoc = 8; + if (glyphSize <= 256) { + cacheSets = 8; + } else if (glyphSize <= 512) { + cacheSets = 4; + } else if (glyphSize <= 1024) { + cacheSets = 2; + } else { + cacheSets = 1; + } + cache = (Guchar *)gmallocn_checkoverflow(cacheSets * cacheAssoc, glyphSize); + if (cache != NULL) { + cacheTags = (SplashFontCacheTag *)gmallocn(cacheSets * cacheAssoc, + sizeof(SplashFontCacheTag)); + for (i = 0; i < cacheSets * cacheAssoc; ++i) { + cacheTags[i].mru = i & (cacheAssoc - 1); + } + } else { + cacheAssoc = 0; + } +} + +SplashFont::~SplashFont() { + fontFile->decRefCnt(); + if (cache) { + gfree(cache); + } + if (cacheTags) { + gfree(cacheTags); + } +} + +GBool SplashFont::getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) { + SplashGlyphBitmap bitmap2; + int size; + Guchar *p; + int i, j, k; + + // no fractional coordinates for large glyphs or non-anti-aliased + // glyphs + if (!aa || glyphH > 50) { + xFrac = yFrac = 0; + } + + // check the cache + i = (c & (cacheSets - 1)) * cacheAssoc; + for (j = 0; j < cacheAssoc; ++j) { + if ((cacheTags[i+j].mru & 0x80000000) && + cacheTags[i+j].c == c && + (int)cacheTags[i+j].xFrac == xFrac && + (int)cacheTags[i+j].yFrac == yFrac) { + bitmap->x = cacheTags[i+j].x; + bitmap->y = cacheTags[i+j].y; + bitmap->w = cacheTags[i+j].w; + bitmap->h = cacheTags[i+j].h; + for (k = 0; k < cacheAssoc; ++k) { + if (k != j && + (cacheTags[i+k].mru & 0x7fffffff) < + (cacheTags[i+j].mru & 0x7fffffff)) { + ++cacheTags[i+k].mru; + } + } + cacheTags[i+j].mru = 0x80000000; + bitmap->aa = aa; + bitmap->data = cache + (i+j) * glyphSize; + bitmap->freeData = gFalse; + + *clipRes = clip->testRect(x0 - bitmap->x, + y0 - bitmap->y, + x0 - bitmap->x + bitmap->w - 1, + y0 - bitmap->y + bitmap->h - 1); + + return gTrue; + } + } + + // generate the glyph bitmap + if (!makeGlyph(c, xFrac, yFrac, &bitmap2, x0, y0, clip, clipRes)) { + return gFalse; + } + + if (*clipRes == splashClipAllOutside) + { + bitmap->freeData = gFalse; + if (bitmap2.freeData) gfree(bitmap2.data); + return gTrue; + } + + // if the glyph doesn't fit in the bounding box, return a temporary + // uncached bitmap + if (bitmap2.w > glyphW || bitmap2.h > glyphH) { + *bitmap = bitmap2; + return gTrue; + } + + // insert glyph pixmap in cache + if (aa) { + size = bitmap2.w * bitmap2.h; + } else { + size = ((bitmap2.w + 7) >> 3) * bitmap2.h; + } + p = NULL; // make gcc happy + if (cacheAssoc == 0) + { + // we had problems on the malloc of the cache, so ignore it + *bitmap = bitmap2; + } + else + { + for (j = 0; j < cacheAssoc; ++j) { + if ((cacheTags[i+j].mru & 0x7fffffff) == cacheAssoc - 1) { + cacheTags[i+j].mru = 0x80000000; + cacheTags[i+j].c = c; + cacheTags[i+j].xFrac = (short)xFrac; + cacheTags[i+j].yFrac = (short)yFrac; + cacheTags[i+j].x = bitmap2.x; + cacheTags[i+j].y = bitmap2.y; + cacheTags[i+j].w = bitmap2.w; + cacheTags[i+j].h = bitmap2.h; + p = cache + (i+j) * glyphSize; + memcpy(p, bitmap2.data, size); + } else { + ++cacheTags[i+j].mru; + } + } + *bitmap = bitmap2; + bitmap->data = p; + bitmap->freeData = gFalse; + if (bitmap2.freeData) { + gfree(bitmap2.data); + } + } + return gTrue; +} diff --git a/kpdf/xpdf/splash/SplashFont.h b/kpdf/xpdf/splash/SplashFont.h new file mode 100644 index 00000000..82ee0370 --- /dev/null +++ b/kpdf/xpdf/splash/SplashFont.h @@ -0,0 +1,105 @@ +//======================================================================== +// +// SplashFont.h +// +//======================================================================== + +#ifndef SPLASHFONT_H +#define SPLASHFONT_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "SplashTypes.h" +#include "SplashClip.h" + +struct SplashGlyphBitmap; +struct SplashFontCacheTag; +class SplashFontFile; +class SplashPath; + +//------------------------------------------------------------------------ + +// Fractional positioning uses this many bits to the right of the +// decimal points. +#define splashFontFractionBits 2 +#define splashFontFraction (1 << splashFontFractionBits) +#define splashFontFractionMul \ + ((SplashCoord)1 / (SplashCoord)splashFontFraction) + +//------------------------------------------------------------------------ +// SplashFont +//------------------------------------------------------------------------ + +class SplashFont { +public: + + SplashFont(SplashFontFile *fontFileA, SplashCoord *matA, + SplashCoord *textMatA, GBool aaA); + + // This must be called after the constructor, so that the subclass + // constructor has a chance to compute the bbox. + void initCache(); + + virtual ~SplashFont(); + + SplashFontFile *getFontFile() { return fontFile; } + + // Return true if matches the specified font file and matrix. + GBool matches(SplashFontFile *fontFileA, SplashCoord *matA, + SplashCoord *textMatA) { + return fontFileA == fontFile && + matA[0] == mat[0] && matA[1] == mat[1] && + matA[2] == mat[2] && matA[3] == mat[3] && + textMatA[0] == textMat[0] && textMatA[1] == textMat[1] && + textMatA[2] == textMat[2] && textMatA[3] == textMat[3]; + } + + // Get a glyph - this does a cache lookup first, and if not found, + // creates a new bitmap and adds it to the cache. The and + // values are splashFontFractionBits bits each, representing + // the numerators of fractions in [0, 1), where the denominator is + // splashFontFraction = 1 << splashFontFractionBits. Subclasses + // should override this to zero out xFrac and/or yFrac if they don't + // support fractional coordinates. + virtual GBool getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes); + + // Rasterize a glyph. The and values are the same + // as described for getGlyph. + virtual GBool makeGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) = 0; + + // Return the path for a glyph. + virtual SplashPath *getGlyphPath(int c) = 0; + + // Return the font transform matrix. + SplashCoord *getMatrix() { return mat; } + + // Return the glyph bounding box. + void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA) + { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } + +protected: + + SplashFontFile *fontFile; + SplashCoord mat[4]; // font transform matrix + // (text space -> device space) + SplashCoord textMat[4]; // text transform matrix + // (text space -> user space) + GBool aa; // anti-aliasing + int xMin, yMin, xMax, yMax; // glyph bounding box + Guchar *cache; // glyph bitmap cache + SplashFontCacheTag * // cache tags + cacheTags; + int glyphW, glyphH; // size of glyph bitmaps + int glyphSize; // size of glyph bitmaps, in bytes + int cacheSets; // number of sets in cache + int cacheAssoc; // cache associativity (glyphs per set) +}; + +#endif diff --git a/kpdf/xpdf/splash/SplashFontEngine.cc b/kpdf/xpdf/splash/SplashFontEngine.cc new file mode 100644 index 00000000..4dc1b35b --- /dev/null +++ b/kpdf/xpdf/splash/SplashFontEngine.cc @@ -0,0 +1,295 @@ +//======================================================================== +// +// SplashFontEngine.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#if HAVE_T1LIB_H +#include +#endif + +#include +#include +#ifndef WIN32 +# include +#endif +#include "gmem.h" +#include "GString.h" +#include "SplashMath.h" +#include "SplashT1FontEngine.h" +#include "SplashFTFontEngine.h" +#include "SplashFontFile.h" +#include "SplashFontFileID.h" +#include "SplashFont.h" +#include "SplashFontEngine.h" + +#ifdef VMS +#if (__VMS_VER < 70000000) +extern "C" int unlink(char *filename); +#endif +#endif + +//------------------------------------------------------------------------ +// SplashFontEngine +//------------------------------------------------------------------------ + +SplashFontEngine::SplashFontEngine( +#if HAVE_T1LIB_H + GBool enableT1lib, +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + GBool enableFreeType, +#endif + GBool aa) { + int i; + + for (i = 0; i < splashFontCacheSize; ++i) { + fontCache[i] = NULL; + } + +#if HAVE_T1LIB_H + if (enableT1lib) { + t1Engine = SplashT1FontEngine::init(aa); + } else { + t1Engine = NULL; + } +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (enableFreeType) { + ftEngine = SplashFTFontEngine::init(aa); + } else { + ftEngine = NULL; + } +#endif +} + +SplashFontEngine::~SplashFontEngine() { + int i; + + for (i = 0; i < splashFontCacheSize; ++i) { + if (fontCache[i]) { + delete fontCache[i]; + } + } + +#if HAVE_T1LIB_H + if (t1Engine) { + delete t1Engine; + } +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (ftEngine) { + delete ftEngine; + } +#endif +} + +SplashFontFile *SplashFontEngine::getFontFile(SplashFontFileID *id) { + SplashFontFile *fontFile; + int i; + + for (i = 0; i < splashFontCacheSize; ++i) { + if (fontCache[i]) { + fontFile = fontCache[i]->getFontFile(); + if (fontFile && fontFile->getID()->matches(id)) { + return fontFile; + } + } + } + return NULL; +} + +SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA, + SplashFontSrc *src, + char **enc) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_T1LIB_H + if (!fontFile && t1Engine) { + fontFile = t1Engine->loadType1Font(idA, src, enc); + } +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadType1Font(idA, src, enc); + } +#endif + + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (src->isFile) + src->unref(); + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA, + SplashFontSrc *src, + char **enc) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_T1LIB_H + if (!fontFile && t1Engine) { + fontFile = t1Engine->loadType1CFont(idA, sec, enc); + } +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadType1CFont(idA, src, enc); + } +#endif + + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (src->isFile) + src->unref(); + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA, + SplashFontSrc *src, + char **enc) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadOpenTypeT1CFont(idA, src, enc); + } +#endif + + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (src->isFile) + src->unref(); + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA, + SplashFontSrc *src) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadCIDFont(idA, src); + } +#endif + + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (src->isFile) + src->unref(); + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA, + SplashFontSrc *src) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadOpenTypeCFFFont(idA, src); + } +#endif + + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (src->isFile) + src->unref(); + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA, + SplashFontSrc *src, + Gushort *codeToGID, + int codeToGIDLen, + int faceIndex) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadTrueTypeFont(idA, src, + codeToGID, codeToGIDLen, faceIndex); + } +#endif + + if (!fontFile) { + gfree(codeToGID); + } + + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (src->isFile) + src->unref(); + + return fontFile; +} + +SplashFont *SplashFontEngine::getFont(SplashFontFile *fontFile, + SplashCoord *textMat, + SplashCoord *ctm) { + SplashCoord mat[4]; + SplashFont *font; + int i, j; + + mat[0] = textMat[0] * ctm[0] + textMat[1] * ctm[2]; + mat[1] = -(textMat[0] * ctm[1] + textMat[1] * ctm[3]); + mat[2] = textMat[2] * ctm[0] + textMat[3] * ctm[2]; + mat[3] = -(textMat[2] * ctm[1] + textMat[3] * ctm[3]); + if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.01) { + // avoid a singular (or close-to-singular) matrix + mat[0] = 0.01; mat[1] = 0; + mat[2] = 0; mat[3] = 0.01; + } + + font = fontCache[0]; + if (font && font->matches(fontFile, mat, textMat)) { + return font; + } + for (i = 1; i < splashFontCacheSize; ++i) { + font = fontCache[i]; + if (font && font->matches(fontFile, mat, textMat)) { + for (j = i; j > 0; --j) { + fontCache[j] = fontCache[j-1]; + } + fontCache[0] = font; + return font; + } + } + font = fontFile->makeFont(mat, textMat); + if (fontCache[splashFontCacheSize - 1]) { + delete fontCache[splashFontCacheSize - 1]; + } + for (j = splashFontCacheSize - 1; j > 0; --j) { + fontCache[j] = fontCache[j-1]; + } + fontCache[0] = font; + return font; +} diff --git a/kpdf/xpdf/splash/SplashFontEngine.h b/kpdf/xpdf/splash/SplashFontEngine.h new file mode 100644 index 00000000..ace5e9ae --- /dev/null +++ b/kpdf/xpdf/splash/SplashFontEngine.h @@ -0,0 +1,86 @@ +//======================================================================== +// +// SplashFontEngine.h +// +//======================================================================== + +#ifndef SPLASHFONTENGINE_H +#define SPLASHFONTENGINE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +class SplashT1FontEngine; +class SplashFTFontEngine; +class SplashDTFontEngine; +class SplashDT4FontEngine; +class SplashFontFile; +class SplashFontFileID; +class SplashFont; +class SplashFontSrc; + +//------------------------------------------------------------------------ + +#define splashFontCacheSize 16 + +//------------------------------------------------------------------------ +// SplashFontEngine +//------------------------------------------------------------------------ + +class SplashFontEngine { +public: + + // Create a font engine. + SplashFontEngine( +#if HAVE_T1LIB_H + GBool enableT1lib, +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + GBool enableFreeType, +#endif + GBool aa); + + ~SplashFontEngine(); + + // Get a font file from the cache. Returns NULL if there is no + // matching entry in the cache. + SplashFontFile *getFontFile(SplashFontFileID *id); + + // Load fonts - these create new SplashFontFile objects. + SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, char **enc); + SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, char **enc); + SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, SplashFontSrc *src, char **enc); + SplashFontFile *loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src); + SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontSrc *src); + SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src, + Gushort *codeToGID, int codeToGIDLen, int faceIndex = 0); + + // Get a font - this does a cache lookup first, and if not found, + // creates a new SplashFont object and adds it to the cache. The + // matrix, mat = textMat * ctm: + // [ mat[0] mat[1] ] + // [ mat[2] mat[3] ] + // specifies the font transform in PostScript style: + // [x' y'] = [x y] * mat + // Note that the Splash y axis points downward. + SplashFont *getFont(SplashFontFile *fontFile, + SplashCoord *textMat, SplashCoord *ctm); + +private: + + SplashFont *fontCache[splashFontCacheSize]; + +#if HAVE_T1LIB_H + SplashT1FontEngine *t1Engine; +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + SplashFTFontEngine *ftEngine; +#endif +}; + +#endif diff --git a/kpdf/xpdf/splash/SplashFontFile.cc b/kpdf/xpdf/splash/SplashFontFile.cc new file mode 100644 index 00000000..ad58c22d --- /dev/null +++ b/kpdf/xpdf/splash/SplashFontFile.cc @@ -0,0 +1,108 @@ +//======================================================================== +// +// SplashFontFile.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#ifndef WIN32 +# include +#endif +#include "gmem.h" +#include "GString.h" +#include "SplashFontFile.h" +#include "SplashFontFileID.h" + +#ifdef VMS +#if (__VMS_VER < 70000000) +extern "C" int unlink(char *filename); +#endif +#endif + +//------------------------------------------------------------------------ +// SplashFontFile +//------------------------------------------------------------------------ + +SplashFontFile::SplashFontFile(SplashFontFileID *idA, SplashFontSrc *srcA) { + id = idA; + src = srcA; + src->ref(); + refCnt = 0; +} + +SplashFontFile::~SplashFontFile() { + src->unref(); + delete id; +} + +void SplashFontFile::incRefCnt() { + ++refCnt; +} + +void SplashFontFile::decRefCnt() { + if (!--refCnt) { + delete this; + } +} + +// + +SplashFontSrc::SplashFontSrc() { + isFile = gFalse; + deleteSrc = gFalse; + fileName = NULL; + buf = NULL; + refcnt = 1; +} + +SplashFontSrc::~SplashFontSrc() { + if (deleteSrc) { + if (isFile) { + if (fileName) + unlink(fileName->getCString()); + } else { + if (buf) + gfree(buf); + } + } + + if (isFile && fileName) + delete fileName; +} + +void SplashFontSrc::ref() { + refcnt++; +} + +void SplashFontSrc::unref() { + if (! --refcnt) + delete this; +} + +void SplashFontSrc::setFile(GString *file, GBool del) +{ + isFile = gTrue; + fileName = file->copy(); + deleteSrc = del; +} + +void SplashFontSrc::setFile(const char *file, GBool del) +{ + isFile = gTrue; + fileName = new GString(file); + deleteSrc = del; +} + +void SplashFontSrc::setBuf(char *bufA, int bufLenA, GBool del) +{ + isFile = gFalse; + buf = bufA; + bufLen = bufLenA; + deleteSrc = del; +} diff --git a/kpdf/xpdf/splash/SplashFontFile.h b/kpdf/xpdf/splash/SplashFontFile.h new file mode 100644 index 00000000..698d620c --- /dev/null +++ b/kpdf/xpdf/splash/SplashFontFile.h @@ -0,0 +1,77 @@ +//======================================================================== +// +// SplashFontFile.h +// +//======================================================================== + +#ifndef SPLASHFONTFILE_H +#define SPLASHFONTFILE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "SplashTypes.h" + +class GString; +class SplashFontEngine; +class SplashFont; +class SplashFontFileID; + +//------------------------------------------------------------------------ +// SplashFontFile +//------------------------------------------------------------------------ + +struct SplashFontSrc { + SplashFontSrc(); + ~SplashFontSrc(); + + void setFile(GString *file, GBool del); + void setFile(const char *file, GBool del); + void setBuf(char *bufA, int buflenA, GBool del); + + void ref(); + void unref(); + + GBool isFile; + GString *fileName; + char *buf; + int bufLen; + GBool deleteSrc; + int refcnt; +}; + +class SplashFontFile { +public: + + virtual ~SplashFontFile(); + + // Create a new SplashFont, i.e., a scaled instance of this font + // file. + virtual SplashFont *makeFont(SplashCoord *mat, SplashCoord *textMat) = 0; + + // Get the font file ID. + SplashFontFileID *getID() { return id; } + + // Increment the reference count. + void incRefCnt(); + + // Decrement the reference count. If the new value is zero, delete + // the SplashFontFile object. + void decRefCnt(); + +protected: + + SplashFontFile(SplashFontFileID *idA, SplashFontSrc *srcA); + + SplashFontFileID *id; + SplashFontSrc *src; + int refCnt; + + friend class SplashFontEngine; +}; + +#endif diff --git a/kpdf/xpdf/splash/SplashFontFileID.cc b/kpdf/xpdf/splash/SplashFontFileID.cc new file mode 100644 index 00000000..af37cb2f --- /dev/null +++ b/kpdf/xpdf/splash/SplashFontFileID.cc @@ -0,0 +1,23 @@ +//======================================================================== +// +// SplashFontFileID.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "SplashFontFileID.h" + +//------------------------------------------------------------------------ +// SplashFontFileID +//------------------------------------------------------------------------ + +SplashFontFileID::SplashFontFileID() { +} + +SplashFontFileID::~SplashFontFileID() { +} diff --git a/kpdf/xpdf/splash/SplashFontFileID.h b/kpdf/xpdf/splash/SplashFontFileID.h new file mode 100644 index 00000000..bed11d33 --- /dev/null +++ b/kpdf/xpdf/splash/SplashFontFileID.h @@ -0,0 +1,30 @@ +//======================================================================== +// +// SplashFontFileID.h +// +//======================================================================== + +#ifndef SPLASHFONTFILEID_H +#define SPLASHFONTFILEID_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +//------------------------------------------------------------------------ +// SplashFontFileID +//------------------------------------------------------------------------ + +class SplashFontFileID { +public: + + SplashFontFileID(); + virtual ~SplashFontFileID(); + virtual GBool matches(SplashFontFileID *id) = 0; +}; + +#endif diff --git a/kpdf/xpdf/splash/SplashGlyphBitmap.h b/kpdf/xpdf/splash/SplashGlyphBitmap.h new file mode 100644 index 00000000..044ba4a6 --- /dev/null +++ b/kpdf/xpdf/splash/SplashGlyphBitmap.h @@ -0,0 +1,26 @@ +//======================================================================== +// +// SplashGlyphBitmap.h +// +//======================================================================== + +#ifndef SPLASHGLYPHBITMAP_H +#define SPLASHGLYPHBITMAP_H + +#include + +#include "gtypes.h" + +//------------------------------------------------------------------------ +// SplashGlyphBitmap +//------------------------------------------------------------------------ + +struct SplashGlyphBitmap { + int x, y, w, h; // offset and size of glyph + GBool aa; // anti-aliased: true means 8-bit alpha + // bitmap; false means 1-bit + Guchar *data; // bitmap data + GBool freeData; // true if data memory should be freed +}; + +#endif diff --git a/kpdf/xpdf/splash/SplashMath.h b/kpdf/xpdf/splash/SplashMath.h new file mode 100644 index 00000000..12e0eec1 --- /dev/null +++ b/kpdf/xpdf/splash/SplashMath.h @@ -0,0 +1,89 @@ +//======================================================================== +// +// SplashMath.h +// +//======================================================================== + +#ifndef SPLASHMATH_H +#define SPLASHMATH_H + +#include +#if USE_FIXEDPOINT +#include "FixedPoint.h" +#else +#include +#endif +#include "SplashTypes.h" + +static inline SplashCoord splashAbs(SplashCoord x) { +#if USE_FIXEDPOINT + return FixedPoint::abs(x); +#else + return fabs(x); +#endif +} + +static inline int splashFloor(SplashCoord x) { +#if USE_FIXEDPOINT + return FixedPoint::floor(x); +#else + return (int)floor(x); +#endif +} + +static inline int splashCeil(SplashCoord x) { +#if USE_FIXEDPOINT + return FixedPoint::ceil(x); +#else + return (int)ceil(x); +#endif +} + +static inline int splashRound(SplashCoord x) { +#if USE_FIXEDPOINT + return FixedPoint::round(x); +#else + return (int)floor(x + 0.5); +#endif +} + +static inline SplashCoord splashSqrt(SplashCoord x) { +#if USE_FIXEDPOINT + return FixedPoint::sqrt(x); +#else + return sqrt(x); +#endif +} + +static inline SplashCoord splashPow(SplashCoord x, SplashCoord y) { +#if USE_FIXEDPOINT + return FixedPoint::pow(x, y); +#else + return pow(x, y); +#endif +} + +static inline SplashCoord splashDist(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + SplashCoord dx, dy; + dx = x1 - x0; + dy = y1 - y0; +#if USE_FIXEDPOINT + // this handles the situation where dx*dx or dy*dy is too large to + // fit in the 16.16 fixed point format + SplashCoord dxa, dya; + dxa = splashAbs(dx); + dya = splashAbs(dy); + if (dxa == 0 && dya == 0) { + return 0; + } else if (dxa > dya) { + return dxa * FixedPoint::sqrt(dya / dxa + 1); + } else { + return dya * FixedPoint::sqrt(dxa / dya + 1); + } +#else + return sqrt(dx * dx + dy * dy); +#endif +} + +#endif diff --git a/kpdf/xpdf/splash/SplashPath.cc b/kpdf/xpdf/splash/SplashPath.cc new file mode 100644 index 00000000..e3a89271 --- /dev/null +++ b/kpdf/xpdf/splash/SplashPath.cc @@ -0,0 +1,184 @@ +//======================================================================== +// +// SplashPath.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "gmem.h" +#include "SplashErrorCodes.h" +#include "SplashPath.h" + +//------------------------------------------------------------------------ +// SplashPath +//------------------------------------------------------------------------ + +// A path can be in three possible states: +// +// 1. no current point -- zero or more finished subpaths +// [curSubpath == length] +// +// 2. one point in subpath +// [curSubpath == length - 1] +// +// 3. open subpath with two or more points +// [curSubpath < length - 1] + +SplashPath::SplashPath() { + pts = NULL; + flags = NULL; + length = size = 0; + curSubpath = 0; + hints = NULL; + hintsLength = hintsSize = 0; +} + +SplashPath::SplashPath(SplashPath *path) { + length = path->length; + size = path->size; + pts = (SplashPathPoint *)gmallocn(size, sizeof(SplashPathPoint)); + flags = (Guchar *)gmallocn(size, sizeof(Guchar)); + memcpy(pts, path->pts, length * sizeof(SplashPathPoint)); + memcpy(flags, path->flags, length * sizeof(Guchar)); + curSubpath = path->curSubpath; + if (path->hints) { + hintsLength = hintsSize = path->hintsLength; + hints = (SplashPathHint *)gmallocn(hintsSize, sizeof(SplashPathHint)); + memcpy(hints, path->hints, hintsLength * sizeof(SplashPathHint)); + } else { + hints = NULL; + } +} + +SplashPath::~SplashPath() { + gfree(pts); + gfree(flags); + gfree(hints); +} + +// Add space for more points. +void SplashPath::grow(int nPts) { + if (length + nPts > size) { + if (size == 0) { + size = 32; + } + while (size < length + nPts) { + size *= 2; + } + pts = (SplashPathPoint *)greallocn(pts, size, sizeof(SplashPathPoint)); + flags = (Guchar *)greallocn(flags, size, sizeof(Guchar)); + } +} + +void SplashPath::append(SplashPath *path) { + int i; + + curSubpath = length + path->curSubpath; + grow(path->length); + for (i = 0; i < path->length; ++i) { + pts[length] = path->pts[i]; + flags[length] = path->flags[i]; + ++length; + } +} + +SplashError SplashPath::moveTo(SplashCoord x, SplashCoord y) { + if (onePointSubpath()) { + return splashErrBogusPath; + } + grow(1); + pts[length].x = x; + pts[length].y = y; + flags[length] = splashPathFirst | splashPathLast; + curSubpath = length++; + return splashOk; +} + +SplashError SplashPath::lineTo(SplashCoord x, SplashCoord y) { + if (noCurrentPoint()) { + return splashErrNoCurPt; + } + flags[length-1] &= ~splashPathLast; + grow(1); + pts[length].x = x; + pts[length].y = y; + flags[length] = splashPathLast; + ++length; + return splashOk; +} + +SplashError SplashPath::curveTo(SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3) { + if (noCurrentPoint()) { + return splashErrNoCurPt; + } + flags[length-1] &= ~splashPathLast; + grow(3); + pts[length].x = x1; + pts[length].y = y1; + flags[length] = splashPathCurve; + ++length; + pts[length].x = x2; + pts[length].y = y2; + flags[length] = splashPathCurve; + ++length; + pts[length].x = x3; + pts[length].y = y3; + flags[length] = splashPathLast; + ++length; + return splashOk; +} + +SplashError SplashPath::close() { + if (noCurrentPoint()) { + return splashErrNoCurPt; + } + if (curSubpath == length - 1 || + pts[length - 1].x != pts[curSubpath].x || + pts[length - 1].y != pts[curSubpath].y) { + lineTo(pts[curSubpath].x, pts[curSubpath].y); + } + flags[curSubpath] |= splashPathClosed; + flags[length - 1] |= splashPathClosed; + curSubpath = length; + return splashOk; +} + +void SplashPath::addStrokeAdjustHint(int ctrl0, int ctrl1, + int firstPt, int lastPt) { + if (hintsLength == hintsSize) { + hintsSize = hintsLength ? 2 * hintsLength : 8; + hints = (SplashPathHint *)greallocn(hints, hintsSize, + sizeof(SplashPathHint)); + } + hints[hintsLength].ctrl0 = ctrl0; + hints[hintsLength].ctrl1 = ctrl1; + hints[hintsLength].firstPt = firstPt; + hints[hintsLength].lastPt = lastPt; + ++hintsLength; +} + +void SplashPath::offset(SplashCoord dx, SplashCoord dy) { + int i; + + for (i = 0; i < length; ++i) { + pts[i].x += dx; + pts[i].y += dy; + } +} + +GBool SplashPath::getCurPt(SplashCoord *x, SplashCoord *y) { + if (noCurrentPoint()) { + return gFalse; + } + *x = pts[length - 1].x; + *y = pts[length - 1].y; + return gTrue; +} diff --git a/kpdf/xpdf/splash/SplashPath.h b/kpdf/xpdf/splash/SplashPath.h new file mode 100644 index 00000000..b63ee5df --- /dev/null +++ b/kpdf/xpdf/splash/SplashPath.h @@ -0,0 +1,121 @@ +//======================================================================== +// +// SplashPath.h +// +//======================================================================== + +#ifndef SPLASHPATH_H +#define SPLASHPATH_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +//------------------------------------------------------------------------ +// SplashPathPoint +//------------------------------------------------------------------------ + +struct SplashPathPoint { + SplashCoord x, y; +}; + +//------------------------------------------------------------------------ +// SplashPath.flags +//------------------------------------------------------------------------ + +// first point on each subpath sets this flag +#define splashPathFirst 0x01 + +// last point on each subpath sets this flag +#define splashPathLast 0x02 + +// if the subpath is closed, its first and last points must be +// identical, and must set this flag +#define splashPathClosed 0x04 + +// curve control points set this flag +#define splashPathCurve 0x08 + +//------------------------------------------------------------------------ +// SplashPathHint +//------------------------------------------------------------------------ + +struct SplashPathHint { + int ctrl0, ctrl1; + int firstPt, lastPt; +}; + +//------------------------------------------------------------------------ +// SplashPath +//------------------------------------------------------------------------ + +class SplashPath { +public: + + // Create an empty path. + SplashPath(); + + // Copy a path. + SplashPath *copy() { return new SplashPath(this); } + + ~SplashPath(); + + // Append to . + void append(SplashPath *path); + + // Start a new subpath. + SplashError moveTo(SplashCoord x, SplashCoord y); + + // Add a line segment to the last subpath. + SplashError lineTo(SplashCoord x, SplashCoord y); + + // Add a third-order (cubic) Bezier curve segment to the last + // subpath. + SplashError curveTo(SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3); + + // Close the last subpath, adding a line segment if necessary. + SplashError close(); + + // Add a stroke adjustment hint. The controlling segments are + // and (where segments are identified by their first + // point), and the points to be adjusted are .. . + void addStrokeAdjustHint(int ctrl0, int ctrl1, int firstPt, int lastPt); + + // Add (, ) to every point on this path. + void offset(SplashCoord dx, SplashCoord dy); + + // Get the points on the path. + int getLength() { return length; } + void getPoint(int i, double *x, double *y, Guchar *f) + { *x = pts[i].x; *y = pts[i].y; *f = flags[i]; } + + // Get the current point. + GBool getCurPt(SplashCoord *x, SplashCoord *y); + +private: + + SplashPath(SplashPath *path); + void grow(int nPts); + GBool noCurrentPoint() { return curSubpath == length; } + GBool onePointSubpath() { return curSubpath == length - 1; } + GBool openSubpath() { return curSubpath < length - 1; } + + SplashPathPoint *pts; // array of points + Guchar *flags; // array of flags + int length, size; // length/size of the pts and flags arrays + int curSubpath; // index of first point in last subpath + + SplashPathHint *hints; // list of hints + int hintsLength, hintsSize; + + friend class SplashXPath; + friend class Splash; +}; + +#endif diff --git a/kpdf/xpdf/splash/SplashPattern.cc b/kpdf/xpdf/splash/SplashPattern.cc new file mode 100644 index 00000000..e6a37852 --- /dev/null +++ b/kpdf/xpdf/splash/SplashPattern.cc @@ -0,0 +1,40 @@ +//======================================================================== +// +// SplashPattern.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "SplashMath.h" +#include "SplashScreen.h" +#include "SplashPattern.h" + +//------------------------------------------------------------------------ +// SplashPattern +//------------------------------------------------------------------------ + +SplashPattern::SplashPattern() { +} + +SplashPattern::~SplashPattern() { +} + +//------------------------------------------------------------------------ +// SplashSolidColor +//------------------------------------------------------------------------ + +SplashSolidColor::SplashSolidColor(SplashColorPtr colorA) { + splashColorCopy(color, colorA); +} + +SplashSolidColor::~SplashSolidColor() { +} + +void SplashSolidColor::getColor(int /*x*/, int /*y*/, SplashColorPtr c) { + splashColorCopy(c, color); +} diff --git a/kpdf/xpdf/splash/SplashPattern.h b/kpdf/xpdf/splash/SplashPattern.h new file mode 100644 index 00000000..0a02e9c2 --- /dev/null +++ b/kpdf/xpdf/splash/SplashPattern.h @@ -0,0 +1,65 @@ +//======================================================================== +// +// SplashPattern.h +// +//======================================================================== + +#ifndef SPLASHPATTERN_H +#define SPLASHPATTERN_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashScreen; + +//------------------------------------------------------------------------ +// SplashPattern +//------------------------------------------------------------------------ + +class SplashPattern { +public: + + SplashPattern(); + + virtual SplashPattern *copy() = 0; + + virtual ~SplashPattern(); + + // Return the color value for a specific pixel. + virtual void getColor(int x, int y, SplashColorPtr c) = 0; + + // Returns true if this pattern object will return the same color + // value for all pixels. + virtual GBool isStatic() = 0; + +private: +}; + +//------------------------------------------------------------------------ +// SplashSolidColor +//------------------------------------------------------------------------ + +class SplashSolidColor: public SplashPattern { +public: + + SplashSolidColor(SplashColorPtr colorA); + + virtual SplashPattern *copy() { return new SplashSolidColor(color); } + + virtual ~SplashSolidColor(); + + virtual void getColor(int x, int y, SplashColorPtr c); + + virtual GBool isStatic() { return gTrue; } + +private: + + SplashColor color; +}; + +#endif diff --git a/kpdf/xpdf/splash/SplashScreen.cc b/kpdf/xpdf/splash/SplashScreen.cc new file mode 100644 index 00000000..3e8d36ca --- /dev/null +++ b/kpdf/xpdf/splash/SplashScreen.cc @@ -0,0 +1,385 @@ +//======================================================================== +// +// SplashScreen.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "SplashMath.h" +#include "SplashScreen.h" + +//------------------------------------------------------------------------ + +static SplashScreenParams defaultParams = { + splashScreenDispersed, // type + 2, // size + 2, // dotRadius + 1.0, // gamma + 0.0, // blackThreshold + 1.0 // whiteThreshold +}; + +//------------------------------------------------------------------------ + +struct SplashScreenPoint { + int x, y; + int dist; +}; + +static int cmpDistances(const void *p0, const void *p1) { + return ((SplashScreenPoint *)p0)->dist - ((SplashScreenPoint *)p1)->dist; +} + +//------------------------------------------------------------------------ +// SplashScreen +//------------------------------------------------------------------------ + +// If is true, this generates a 45 degree screen using a +// circular dot spot function. DPI = resolution / ((size / 2) * +// sqrt(2)). If is false, this generates an optimal +// threshold matrix using recursive tesselation. Gamma correction +// (gamma = 1 / 1.33) is also computed here. +SplashScreen::SplashScreen(SplashScreenParams *params) { + Guchar u, black, white; + int i; + + if (!params) { + params = &defaultParams; + } + + switch (params->type) { + + case splashScreenDispersed: + // size must be a power of 2 + for (size = 1; size < params->size; size <<= 1) ; + mat = (Guchar *)gmallocn(size * size, sizeof(Guchar)); + buildDispersedMatrix(size/2, size/2, 1, size/2, 1); + break; + + case splashScreenClustered: + // size must be even + size = (params->size >> 1) << 1; + if (size < 2) { + size = 2; + } + mat = (Guchar *)gmallocn(size * size, sizeof(Guchar)); + buildClusteredMatrix(); + break; + + case splashScreenStochasticClustered: + // size must be at least 2*r + if (params->size < 2 * params->dotRadius) { + size = 2 * params->dotRadius; + } else { + size = params->size; + } + mat = (Guchar *)gmallocn(size * size, sizeof(Guchar)); + buildSCDMatrix(params->dotRadius); + break; + } + + // do gamma correction and compute minVal/maxVal + minVal = 255; + maxVal = 0; + black = splashRound((SplashCoord)255.0 * params->blackThreshold); + if (black < 1) { + black = 1; + } + int whiteAux = splashRound((SplashCoord)255.0 * params->whiteThreshold); + if (whiteAux > 255) { + white = 255; + } else { + white = whiteAux; + } + for (i = 0; i < size * size; ++i) { + u = splashRound((SplashCoord)255.0 * + splashPow((SplashCoord)mat[i] / 255.0, params->gamma)); + if (u < black) { + u = black; + } else if (u >= white) { + u = white; + } + mat[i] = u; + if (u < minVal) { + minVal = u; + } else if (u > maxVal) { + maxVal = u; + } + } +} + +void SplashScreen::buildDispersedMatrix(int i, int j, int val, + int delta, int offset) { + if (delta == 0) { + // map values in [1, size^2] --> [1, 255] + mat[i * size + j] = 1 + (254 * (val - 1)) / (size * size - 1); + } else { + buildDispersedMatrix(i, j, + val, delta / 2, 4*offset); + buildDispersedMatrix((i + delta) % size, (j + delta) % size, + val + offset, delta / 2, 4*offset); + buildDispersedMatrix((i + delta) % size, j, + val + 2*offset, delta / 2, 4*offset); + buildDispersedMatrix((i + 2*delta) % size, (j + delta) % size, + val + 3*offset, delta / 2, 4*offset); + } +} + +void SplashScreen::buildClusteredMatrix() { + SplashCoord *dist; + SplashCoord u, v, d; + Guchar val; + int size2, x, y, x1, y1, i; + + size2 = size >> 1; + + // initialize the threshold matrix + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + mat[y * size + x] = 0; + } + } + + // build the distance matrix + dist = (SplashCoord *)gmallocn(size * size2, sizeof(SplashCoord)); + for (y = 0; y < size2; ++y) { + for (x = 0; x < size2; ++x) { + if (x + y < size2 - 1) { + u = (SplashCoord)x + 0.5 - 0; + v = (SplashCoord)y + 0.5 - 0; + } else { + u = (SplashCoord)x + 0.5 - (SplashCoord)size2; + v = (SplashCoord)y + 0.5 - (SplashCoord)size2; + } + dist[y * size2 + x] = u*u + v*v; + } + } + for (y = 0; y < size2; ++y) { + for (x = 0; x < size2; ++x) { + if (x < y) { + u = (SplashCoord)x + 0.5 - 0; + v = (SplashCoord)y + 0.5 - (SplashCoord)size2; + } else { + u = (SplashCoord)x + 0.5 - (SplashCoord)size2; + v = (SplashCoord)y + 0.5 - 0; + } + dist[(size2 + y) * size2 + x] = u*u + v*v; + } + } + + // build the threshold matrix + minVal = 1; + maxVal = 0; + x1 = y1 = 0; // make gcc happy + for (i = 0; i < size * size2; ++i) { + d = -1; + for (y = 0; y < size; ++y) { + for (x = 0; x < size2; ++x) { + if (mat[y * size + x] == 0 && + dist[y * size2 + x] > d) { + x1 = x; + y1 = y; + d = dist[y1 * size2 + x1]; + } + } + } + // map values in [0, 2*size*size2-1] --> [1, 255] + val = 1 + (254 * (2*i)) / (2*size*size2 - 1); + mat[y1 * size + x1] = val; + val = 1 + (254 * (2*i+1)) / (2*size*size2 - 1); + if (y1 < size2) { + mat[(y1 + size2) * size + x1 + size2] = val; + } else { + mat[(y1 - size2) * size + x1 + size2] = val; + } + } + + gfree(dist); +} + +// Compute the distance between two points on a toroid. +int SplashScreen::distance(int x0, int y0, int x1, int y1) { + int dx0, dx1, dx, dy0, dy1, dy; + + dx0 = abs(x0 - x1); + dx1 = size - dx0; + dx = dx0 < dx1 ? dx0 : dx1; + dy0 = abs(y0 - y1); + dy1 = size - dy0; + dy = dy0 < dy1 ? dy0 : dy1; + return dx * dx + dy * dy; +} + +// Algorithm taken from: +// Victor Ostromoukhov and Roger D. Hersch, "Stochastic Clustered-Dot +// Dithering" in Color Imaging: Device-Independent Color, Color +// Hardcopy, and Graphic Arts IV, SPIE Vol. 3648, pp. 496-505, 1999. +void SplashScreen::buildSCDMatrix(int r) { + SplashScreenPoint *dots, *pts; + int dotsLen, dotsSize; + char *tmpl; + char *grid; + int *region, *dist; + int x, y, xx, yy, x0, x1, y0, y1, i, j, d, iMin, dMin, n; + + //~ this should probably happen somewhere else + srand(123); + + // generate the random space-filling curve + pts = (SplashScreenPoint *)gmallocn(size * size, sizeof(SplashScreenPoint)); + i = 0; + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + pts[i].x = x; + pts[i].y = y; + ++i; + } + } + for (i = 0; i < size * size; ++i) { + j = i + (int)((double)(size * size - i) * + (double)rand() / ((double)RAND_MAX + 1.0)); + x = pts[i].x; + y = pts[i].y; + pts[i].x = pts[j].x; + pts[i].y = pts[j].y; + pts[j].x = x; + pts[j].y = y; + } + + // construct the circle template + tmpl = (char *)gmallocn((r+1)*(r+1), sizeof(char)); + for (y = 0; y <= r; ++y) { + for (x = 0; x <= r; ++x) { + tmpl[y*(r+1) + x] = (x * y <= r * r) ? 1 : 0; + } + } + + // mark all grid cells as free + grid = (char *)gmallocn(size * size, sizeof(char)); + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + grid[y*size + x] = 0; + } + } + + // walk the space-filling curve, adding dots + dotsLen = 0; + dotsSize = 32; + dots = (SplashScreenPoint *)gmallocn(dotsSize, sizeof(SplashScreenPoint)); + for (i = 0; i < size * size; ++i) { + x = pts[i].x; + y = pts[i].y; + if (!grid[y*size + x]) { + if (dotsLen == dotsSize) { + dotsSize *= 2; + dots = (SplashScreenPoint *)greallocn(dots, dotsSize, + sizeof(SplashScreenPoint)); + } + dots[dotsLen++] = pts[i]; + for (yy = 0; yy <= r; ++yy) { + y0 = (y + yy) % size; + y1 = (y - yy + size) % size; + for (xx = 0; xx <= r; ++xx) { + if (tmpl[yy*(r+1) + xx]) { + x0 = (x + xx) % size; + x1 = (x - xx + size) % size; + grid[y0*size + x0] = 1; + grid[y0*size + x1] = 1; + grid[y1*size + x0] = 1; + grid[y1*size + x1] = 1; + } + } + } + } + } + + gfree(tmpl); + gfree(grid); + + // assign each cell to a dot, compute distance to center of dot + region = (int *)gmallocn(size * size, sizeof(int)); + dist = (int *)gmallocn(size * size, sizeof(int)); + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + iMin = 0; + dMin = distance(dots[0].x, dots[0].y, x, y); + for (i = 1; i < dotsLen; ++i) { + d = distance(dots[i].x, dots[i].y, x, y); + if (d < dMin) { + iMin = i; + dMin = d; + } + } + region[y*size + x] = iMin; + dist[y*size + x] = dMin; + } + } + + // compute threshold values + for (i = 0; i < dotsLen; ++i) { + n = 0; + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + if (region[y*size + x] == i) { + pts[n].x = x; + pts[n].y = y; + pts[n].dist = distance(dots[i].x, dots[i].y, x, y); + ++n; + } + } + } + qsort(pts, n, sizeof(SplashScreenPoint), &cmpDistances); + for (j = 0; j < n; ++j) { + // map values in [0 .. n-1] --> [255 .. 1] + mat[pts[j].y * size + pts[j].x] = 255 - (254 * j) / (n - 1); + } + } + + gfree(pts); + gfree(region); + gfree(dist); + + gfree(dots); +} + +SplashScreen::SplashScreen(SplashScreen *screen) { + size = screen->size; + mat = (Guchar *)gmallocn(size * size, sizeof(Guchar)); + memcpy(mat, screen->mat, size * size * sizeof(Guchar)); + minVal = screen->minVal; + maxVal = screen->maxVal; +} + +SplashScreen::~SplashScreen() { + gfree(mat); +} + +int SplashScreen::test(int x, int y, Guchar value) { + int xx, yy; + + if (value < minVal) { + return 0; + } + if (value >= maxVal) { + return 1; + } + if ((xx = x % size) < 0) { + xx = -xx; + } + if ((yy = y % size) < 0) { + yy = -yy; + } + return value < mat[yy * size + xx] ? 0 : 1; +} + +GBool SplashScreen::isStatic(Guchar value) { + return value < minVal || value >= maxVal; +} diff --git a/kpdf/xpdf/splash/SplashScreen.h b/kpdf/xpdf/splash/SplashScreen.h new file mode 100644 index 00000000..2baa9b5d --- /dev/null +++ b/kpdf/xpdf/splash/SplashScreen.h @@ -0,0 +1,56 @@ +//======================================================================== +// +// SplashScreen.h +// +//======================================================================== + +#ifndef SPLASHSCREEN_H +#define SPLASHSCREEN_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +//------------------------------------------------------------------------ +// SplashScreen +//------------------------------------------------------------------------ + +class SplashScreen { +public: + + SplashScreen(SplashScreenParams *params); + SplashScreen(SplashScreen *screen); + ~SplashScreen(); + + SplashScreen *copy() { return new SplashScreen(this); } + + // Return the computed pixel value (0=black, 1=white) for the gray + // level at (, ). + int test(int x, int y, Guchar value); + + // Returns true if value is above the white threshold or below the + // black threshold, i.e., if the corresponding halftone will be + // solid white or black. + GBool isStatic(Guchar value); + +private: + + void buildDispersedMatrix(int i, int j, int val, + int delta, int offset); + void buildClusteredMatrix(); + int distance(int x0, int y0, int x1, int y1); + void buildSCDMatrix(int r); + + Guchar *mat; // threshold matrix + int size; // size of the threshold matrix + Guchar minVal; // any pixel value below minVal generates + // solid black + Guchar maxVal; // any pixel value above maxVal generates + // solid white +}; + +#endif diff --git a/kpdf/xpdf/splash/SplashState.cc b/kpdf/xpdf/splash/SplashState.cc new file mode 100644 index 00000000..e2c34c44 --- /dev/null +++ b/kpdf/xpdf/splash/SplashState.cc @@ -0,0 +1,165 @@ +//======================================================================== +// +// SplashState.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "gmem.h" +#include "SplashPattern.h" +#include "SplashScreen.h" +#include "SplashClip.h" +#include "SplashBitmap.h" +#include "SplashState.h" + +//------------------------------------------------------------------------ +// SplashState +//------------------------------------------------------------------------ + +// number of components in each color mode +int splashColorModeNComps[] = { + 1, 1, 3, 3, 4 +}; + +SplashState::SplashState(int width, int height, GBool vectorAntialias, + SplashScreenParams *screenParams) { + SplashColor color; + + matrix[0] = 1; matrix[1] = 0; + matrix[2] = 0; matrix[3] = 1; + matrix[4] = 0; matrix[5] = 0; + memset(&color, 0, sizeof(SplashColor)); + strokePattern = new SplashSolidColor(color); + fillPattern = new SplashSolidColor(color); + screen = new SplashScreen(screenParams); + blendFunc = NULL; + strokeAlpha = 1; + fillAlpha = 1; + lineWidth = 0; + lineCap = splashLineCapButt; + lineJoin = splashLineJoinMiter; + miterLimit = 10; + flatness = 1; + lineDash = NULL; + lineDashLength = 0; + lineDashPhase = 0; + strokeAdjust = gFalse; + clip = new SplashClip(0, 0, width - 0.001, height - 0.001, vectorAntialias); + softMask = NULL; + deleteSoftMask = gFalse; + inNonIsolatedGroup = gFalse; + next = NULL; +} + +SplashState::SplashState(int width, int height, GBool vectorAntialias, + SplashScreen *screenA) { + SplashColor color; + + matrix[0] = 1; matrix[1] = 0; + matrix[2] = 0; matrix[3] = 1; + matrix[4] = 0; matrix[5] = 0; + memset(&color, 0, sizeof(SplashColor)); + strokePattern = new SplashSolidColor(color); + fillPattern = new SplashSolidColor(color); + screen = screenA->copy(); + blendFunc = NULL; + strokeAlpha = 1; + fillAlpha = 1; + lineWidth = 0; + lineCap = splashLineCapButt; + lineJoin = splashLineJoinMiter; + miterLimit = 10; + flatness = 1; + lineDash = NULL; + lineDashLength = 0; + lineDashPhase = 0; + strokeAdjust = gFalse; + clip = new SplashClip(0, 0, width - 0.001, height - 0.001, vectorAntialias); + softMask = NULL; + deleteSoftMask = gFalse; + inNonIsolatedGroup = gFalse; + next = NULL; +} + +SplashState::SplashState(SplashState *state) { + memcpy(matrix, state->matrix, 6 * sizeof(SplashCoord)); + strokePattern = state->strokePattern->copy(); + fillPattern = state->fillPattern->copy(); + screen = state->screen->copy(); + blendFunc = state->blendFunc; + strokeAlpha = state->strokeAlpha; + fillAlpha = state->fillAlpha; + lineWidth = state->lineWidth; + lineCap = state->lineCap; + lineJoin = state->lineJoin; + miterLimit = state->miterLimit; + flatness = state->flatness; + if (state->lineDash) { + lineDashLength = state->lineDashLength; + lineDash = (SplashCoord *)gmallocn(lineDashLength, sizeof(SplashCoord)); + memcpy(lineDash, state->lineDash, lineDashLength * sizeof(SplashCoord)); + } else { + lineDash = NULL; + lineDashLength = 0; + } + lineDashPhase = state->lineDashPhase; + strokeAdjust = state->strokeAdjust; + clip = state->clip->copy(); + softMask = state->softMask; + deleteSoftMask = gFalse; + inNonIsolatedGroup = state->inNonIsolatedGroup; + next = NULL; +} + +SplashState::~SplashState() { + delete strokePattern; + delete fillPattern; + delete screen; + gfree(lineDash); + delete clip; + if (deleteSoftMask && softMask) { + delete softMask; + } +} + +void SplashState::setStrokePattern(SplashPattern *strokePatternA) { + delete strokePattern; + strokePattern = strokePatternA; +} + +void SplashState::setFillPattern(SplashPattern *fillPatternA) { + delete fillPattern; + fillPattern = fillPatternA; +} + +void SplashState::setScreen(SplashScreen *screenA) { + delete screen; + screen = screenA; +} + +void SplashState::setLineDash(SplashCoord *lineDashA, int lineDashLengthA, + SplashCoord lineDashPhaseA) { + gfree(lineDash); + lineDashLength = lineDashLengthA; + if (lineDashLength > 0) { + lineDash = (SplashCoord *)gmallocn(lineDashLength, sizeof(SplashCoord)); + memcpy(lineDash, lineDashA, lineDashLength * sizeof(SplashCoord)); + } else { + lineDash = NULL; + } + lineDashPhase = lineDashPhaseA; +} + +void SplashState::setSoftMask(SplashBitmap *softMaskA) { + if (deleteSoftMask) { + delete softMask; + } + softMask = softMaskA; + deleteSoftMask = gTrue; +} diff --git a/kpdf/xpdf/splash/SplashState.h b/kpdf/xpdf/splash/SplashState.h new file mode 100644 index 00000000..1f5a88da --- /dev/null +++ b/kpdf/xpdf/splash/SplashState.h @@ -0,0 +1,103 @@ +//======================================================================== +// +// SplashState.h +// +//======================================================================== + +#ifndef SPLASHSTATE_H +#define SPLASHSTATE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashPattern; +class SplashScreen; +class SplashClip; +class SplashBitmap; + +//------------------------------------------------------------------------ +// line cap values +//------------------------------------------------------------------------ + +#define splashLineCapButt 0 +#define splashLineCapRound 1 +#define splashLineCapProjecting 2 + +//------------------------------------------------------------------------ +// line join values +//------------------------------------------------------------------------ + +#define splashLineJoinMiter 0 +#define splashLineJoinRound 1 +#define splashLineJoinBevel 2 + +//------------------------------------------------------------------------ +// SplashState +//------------------------------------------------------------------------ + +class SplashState { +public: + + // Create a new state object, initialized with default settings. + SplashState(int width, int height, GBool vectorAntialias, + SplashScreenParams *screenParams); + SplashState(int width, int height, GBool vectorAntialias, + SplashScreen *screenA); + + // Copy a state object. + SplashState *copy() { return new SplashState(this); } + + ~SplashState(); + + // Set the stroke pattern. This does not copy . + void setStrokePattern(SplashPattern *strokePatternA); + + // Set the fill pattern. This does not copy . + void setFillPattern(SplashPattern *fillPatternA); + + // Set the screen. This does not copy . + void setScreen(SplashScreen *screenA); + + // Set the line dash pattern. This copies the array. + void setLineDash(SplashCoord *lineDashA, int lineDashLengthA, + SplashCoord lineDashPhaseA); + + // Set the soft mask bitmap. + void setSoftMask(SplashBitmap *softMaskA); + +private: + + SplashState(SplashState *state); + + SplashCoord matrix[6]; + SplashPattern *strokePattern; + SplashPattern *fillPattern; + SplashScreen *screen; + SplashBlendFunc blendFunc; + SplashCoord strokeAlpha; + SplashCoord fillAlpha; + SplashCoord lineWidth; + int lineCap; + int lineJoin; + SplashCoord miterLimit; + SplashCoord flatness; + SplashCoord *lineDash; + int lineDashLength; + SplashCoord lineDashPhase; + GBool strokeAdjust; + SplashClip *clip; + SplashBitmap *softMask; + GBool deleteSoftMask; + GBool inNonIsolatedGroup; + + SplashState *next; // used by Splash class + + friend class Splash; +}; + +#endif diff --git a/kpdf/xpdf/splash/SplashT1Font.cc b/kpdf/xpdf/splash/SplashT1Font.cc new file mode 100644 index 00000000..19237e1d --- /dev/null +++ b/kpdf/xpdf/splash/SplashT1Font.cc @@ -0,0 +1,292 @@ +//======================================================================== +// +// SplashT1Font.cc +// +//======================================================================== + +#include + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "SplashMath.h" +#include "SplashGlyphBitmap.h" +#include "SplashPath.h" +#include "SplashT1FontEngine.h" +#include "SplashT1FontFile.h" +#include "SplashT1Font.h" + +//------------------------------------------------------------------------ + +static Guchar bitReverse[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; + +//------------------------------------------------------------------------ +// SplashT1Font +//------------------------------------------------------------------------ + +SplashT1Font::SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA, + SplashCoord *textMatA): + SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa) +{ + T1_TMATRIX matrix; + BBox bbox; + SplashCoord bbx0, bby0, bbx1, bby1; + int x, y; + + t1libID = T1_CopyFont(fontFileA->t1libID); + outlineID = -1; + + // compute font size + size = (float)splashSqrt(mat[2]*mat[2] + mat[3]*mat[3]); + + // transform the four corners of the font bounding box -- the min + // and max values form the bounding box of the transformed font + bbox = T1_GetFontBBox(t1libID); + bbx0 = 0.001 * bbox.llx; + bby0 = 0.001 * bbox.lly; + bbx1 = 0.001 * bbox.urx; + bby1 = 0.001 * bbox.ury; + // some fonts are completely broken, so we fake it (with values + // large enough that most glyphs should fit) + if (bbx0 == 0 && bby0 == 0 && bbx1 == 0 && bby1 == 0) { + bbx0 = bby0 = -0.5; + bbx1 = bby1 = 1.5; + } + x = (int)(mat[0] * bbx0 + mat[2] * bby0); + xMin = xMax = x; + y = (int)(mat[1] * bbx0 + mat[3] * bby0); + yMin = yMax = y; + x = (int)(mat[0] * bbx0 + mat[2] * bby1); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)(mat[1] * bbx0 + mat[3] * bby1); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + x = (int)(mat[0] * bbx1 + mat[2] * bby0); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)(mat[1] * bbx1 + mat[3] * bby0); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + x = (int)(mat[0] * bbx1 + mat[2] * bby1); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)(mat[1] * bbx1 + mat[3] * bby1); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + // This is a kludge: some buggy PDF generators embed fonts with + // zero bounding boxes. + if (xMax == xMin) { + xMin = 0; + xMax = (int)size; + } + if (yMax == yMin) { + yMin = 0; + yMax = (int)(1.2 * size); + } + // Another kludge: an unusually large xMin or yMin coordinate is + // probably wrong. + if (xMin > 0) { + xMin = 0; + } + if (yMin > 0) { + yMin = 0; + } + // Another kludge: t1lib doesn't correctly handle fonts with + // real (non-integer) bounding box coordinates. + if (xMax - xMin > 5000) { + xMin = 0; + xMax = (int)size; + } + if (yMax - yMin > 5000) { + yMin = 0; + yMax = (int)(1.2 * size); + } + + // transform the font + matrix.cxx = (double)mat[0] / size; + matrix.cxy = (double)mat[1] / size; + matrix.cyx = (double)mat[2] / size; + matrix.cyy = (double)mat[3] / size; + T1_TransformFont(t1libID, &matrix); +} + +SplashT1Font::~SplashT1Font() { + T1_DeleteFont(t1libID); + if (outlineID >= 0) { + T1_DeleteFont(outlineID); + } +} + +GBool SplashT1Font::getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) { + return SplashFont::getGlyph(c, 0, 0, bitmap, x0, y0, clip, clipRes); +} + +GBool SplashT1Font::makeGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) { + GLYPH *glyph; + int n, i; + + if (aa) { + glyph = T1_AASetChar(t1libID, c, size, NULL); + } else { + glyph = T1_SetChar(t1libID, c, size, NULL); + } + if (!glyph) { + return gFalse; + } + + bitmap->x = -glyph->metrics.leftSideBearing; + bitmap->y = glyph->metrics.ascent; + bitmap->w = glyph->metrics.rightSideBearing - glyph->metrics.leftSideBearing; + bitmap->h = glyph->metrics.ascent - glyph->metrics.descent; + bitmap->aa = aa; + if (aa) { + bitmap->data = (Guchar *)glyph->bits; + bitmap->freeData = gFalse; + } else { + n = bitmap->h * ((bitmap->w + 7) >> 3); + bitmap->data = (Guchar *)gmalloc(n); + for (i = 0; i < n; ++i) { + bitmap->data[i] = bitReverse[glyph->bits[i] & 0xff]; + } + bitmap->freeData = gTrue; + } + + *clipRes = clip->testRect(x0 - bitmap->x, + y0 - bitmap->y, + x0 - bitmap->x + bitmap->w - 1, + y0 - bitmap->y + bitmap->h - 1); + + return gTrue; +} + +SplashPath *SplashT1Font::getGlyphPath(int c) { + T1_TMATRIX matrix; + SplashPath *path; + T1_OUTLINE *outline; + T1_PATHSEGMENT *seg; + T1_BEZIERSEGMENT *bez; + SplashCoord x, y, x1, y1; + GBool needClose; + + if (outlineID < 0) { + outlineID = T1_CopyFont(((SplashT1FontFile *)fontFile)->t1libID); + outlineSize = (float)splashSqrt(textMat[2]*textMat[2] + + textMat[3]*textMat[3]); + matrix.cxx = (double)textMat[0] / outlineSize; + matrix.cxy = (double)textMat[1] / outlineSize; + matrix.cyx = (double)textMat[2] / outlineSize; + matrix.cyy = (double)textMat[3] / outlineSize; + // t1lib doesn't seem to handle small sizes correctly here, so set + // the size to 1000, and scale the resulting coordinates later + outlineMul = (float)(outlineSize / 65536000.0); + outlineSize = 1000; + T1_TransformFont(outlineID, &matrix); + } + + path = new SplashPath(); + if ((outline = T1_GetCharOutline(outlineID, c, outlineSize, NULL))) { + x = 0; + y = 0; + needClose = gFalse; + for (seg = outline; seg; seg = seg->link) { + switch (seg->type) { + case T1_PATHTYPE_MOVE: + if (needClose) { + path->close(); + needClose = gFalse; + } + x += seg->dest.x * outlineMul; + y += seg->dest.y * outlineMul; + path->moveTo(x, -y); + break; + case T1_PATHTYPE_LINE: + x += seg->dest.x * outlineMul; + y += seg->dest.y * outlineMul; + path->lineTo(x, -y); + needClose = gTrue; + break; + case T1_PATHTYPE_BEZIER: + bez = (T1_BEZIERSEGMENT *)seg; + x1 = x + (SplashCoord)(bez->dest.x * outlineMul); + y1 = y + (SplashCoord)(bez->dest.y * outlineMul); + path->curveTo(x + (SplashCoord)(bez->B.x * outlineMul), + -(y + (SplashCoord)(bez->B.y * outlineMul)), + x + (SplashCoord)(bez->C.x * outlineMul), + -(y + (SplashCoord)(bez->C.y * outlineMul)), + x1, -y1); + x = x1; + y = y1; + needClose = gTrue; + break; + } + } + if (needClose) { + path->close(); + } + T1_FreeOutline(outline); + } + + return path; +} + +#endif // HAVE_T1LIB_H diff --git a/kpdf/xpdf/splash/SplashT1Font.h b/kpdf/xpdf/splash/SplashT1Font.h new file mode 100644 index 00000000..129c6ad5 --- /dev/null +++ b/kpdf/xpdf/splash/SplashT1Font.h @@ -0,0 +1,57 @@ +//======================================================================== +// +// SplashT1Font.h +// +//======================================================================== + +#ifndef SPLASHT1FONT_H +#define SPLASHT1FONT_H + +#include + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashFont.h" + +class SplashT1FontFile; + +//------------------------------------------------------------------------ +// SplashT1Font +//------------------------------------------------------------------------ + +class SplashT1Font: public SplashFont { +public: + + SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA, + SplashCoord *textMatA); + + virtual ~SplashT1Font(); + + // Munge xFrac and yFrac before calling SplashFont::getGlyph. + virtual GBool getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes); + + // Rasterize a glyph. The and values are the same + // as described for getGlyph. + virtual GBool makeGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes); + + // Return the path for a glyph. + virtual SplashPath *getGlyphPath(int c); + +private: + + int t1libID; // t1lib font ID + int outlineID; // t1lib font ID for glyph outlines + float size; + float outlineSize; // size for glyph outlines + float outlineMul; +}; + +#endif // HAVE_T1LIB_H + +#endif diff --git a/kpdf/xpdf/splash/SplashT1FontEngine.cc b/kpdf/xpdf/splash/SplashT1FontEngine.cc new file mode 100644 index 00000000..68530e88 --- /dev/null +++ b/kpdf/xpdf/splash/SplashT1FontEngine.cc @@ -0,0 +1,122 @@ +//======================================================================== +// +// SplashT1FontEngine.cc +// +//======================================================================== + +#include + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#ifndef WIN32 +# include +#endif +#include +#include "GString.h" +#include "gfile.h" +#include "FoFiType1C.h" +#include "SplashT1FontFile.h" +#include "SplashT1FontEngine.h" + +#ifdef VMS +#if (__VMS_VER < 70000000) +extern "C" int unlink(char *filename); +#endif +#endif + +//------------------------------------------------------------------------ + +int SplashT1FontEngine::t1libInitCount = 0; + +//------------------------------------------------------------------------ + +static void fileWrite(void *stream, char *data, int len) { + fwrite(data, 1, len, (FILE *)stream); +} + +//------------------------------------------------------------------------ +// SplashT1FontEngine +//------------------------------------------------------------------------ + +SplashT1FontEngine::SplashT1FontEngine(GBool aaA) { + aa = aaA; +} + +SplashT1FontEngine *SplashT1FontEngine::init(GBool aaA) { + // grayVals[i] = round(i * 255 / 16) + static unsigned long grayVals[17] = { + 0, 16, 32, 48, 64, 80, 96, 112, 128, 143, 159, 175, 191, 207, 223, 239, 255 + }; + + //~ for multithreading: need a mutex here + if (t1libInitCount == 0) { + T1_SetBitmapPad(8); + if (!T1_InitLib(NO_LOGFILE | IGNORE_CONFIGFILE | IGNORE_FONTDATABASE | + T1_NO_AFM)) { + return NULL; + } + if (aaA) { + T1_AASetBitsPerPixel(8); + T1_AASetLevel(T1_AA_HIGH); + T1_AAHSetGrayValues(grayVals); + } else { + T1_AANSetGrayValues(0, 1); + } + } + ++t1libInitCount; + + return new SplashT1FontEngine(aaA); +} + +SplashT1FontEngine::~SplashT1FontEngine() { + //~ for multithreading: need a mutex here + if (--t1libInitCount == 0) { + T1_CloseLib(); + } +} + +SplashFontFile *SplashT1FontEngine::loadType1Font(SplashFontFileID *idA, + SplashFontSrc *src, + char **enc) { + return SplashT1FontFile::loadType1Font(this, idA, fileName, deleteFile, enc); +} + +SplashFontFile *SplashT1FontEngine::loadType1CFont(SplashFontFileID *idA, + SplashFontSrc *src, + char **enc) { + FoFiType1C *ff; + GString *tmpFileName; + FILE *tmpFile; + SplashFontFile *ret; + SplashFontSrc *newsrc; + + if (src->isFile) + ff = FoFiType1C::load(src->fileName); + else + ff = new FoFiType1C(src->buf, src->bufLen, gFalse); + if (! ff) + return NULL; + } + tmpFileName = NULL; + if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) { + delete ff; + return NULL; + } + ff->convertToType1(NULL, NULL, gTrue, &fileWrite, tmpFile); + delete ff; + fclose(tmpFile); + newsrc = new SplashFontSrc; + newsrc->setFile(tmpFileName, gTrue); + delete tmpFileName; + ret = SplashT1FontFile::loadType1Font(this, idA, newsrc, enc); + newsrc->unref(); + return ret; +} + +#endif // HAVE_T1LIB_H diff --git a/kpdf/xpdf/splash/SplashT1FontEngine.h b/kpdf/xpdf/splash/SplashT1FontEngine.h new file mode 100644 index 00000000..57a04487 --- /dev/null +++ b/kpdf/xpdf/splash/SplashT1FontEngine.h @@ -0,0 +1,53 @@ +//======================================================================== +// +// SplashT1FontEngine.h +// +//======================================================================== + +#ifndef SPLASHT1FONTENGINE_H +#define SPLASHT1FONTENGINE_H + +#include + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +class SplashFontFile; +class SplashFontFileID; + +//------------------------------------------------------------------------ +// SplashT1FontEngine +//------------------------------------------------------------------------ + +class SplashT1FontEngine { +public: + + static SplashT1FontEngine *init(GBool aaA); + + ~SplashT1FontEngine(); + + // Load fonts. + SplashFontFile *loadType1Font(SplashFontFileID *idA, char *fileName, + GBool deleteFile, char **enc); + SplashFontFile *loadType1CFont(SplashFontFileID *idA, char *fileName, + GBool deleteFile, char **enc); + +private: + + SplashT1FontEngine(GBool aaA); + + static int t1libInitCount; + GBool aa; + + friend class SplashT1FontFile; + friend class SplashT1Font; +}; + +#endif // HAVE_T1LIB_H + +#endif diff --git a/kpdf/xpdf/splash/SplashT1FontFile.cc b/kpdf/xpdf/splash/SplashT1FontFile.cc new file mode 100644 index 00000000..54312055 --- /dev/null +++ b/kpdf/xpdf/splash/SplashT1FontFile.cc @@ -0,0 +1,117 @@ +//======================================================================== +// +// SplashT1FontFile.cc +// +//======================================================================== + +#include + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "SplashT1FontEngine.h" +#include "SplashT1Font.h" +#include "SplashT1FontFile.h" + +//------------------------------------------------------------------------ +// SplashT1FontFile +//------------------------------------------------------------------------ + +SplashFontFile *SplashT1FontFile::loadType1Font(SplashT1FontEngine *engineA, + SplashFontFileID *idA, + SplashFontSrc *src, + char **encA) { + int t1libIDA; + char **encTmp; + char *encStrTmp; + int encStrSize; + char *encPtr; + int i; + + GString *fileNameA; + SplashFontSrc *newsrc = NULL; + SplashFontFile *ff; + + if (! src->isFile) { + GString *tmpFileName; + FILE *tmpFile; + if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) + return NULL; + fwrite(src->buf, 1, src->bufLen, tmpFile); + fclose(tmpFile); + newsrc = new SplashFontSrc; + newsrc->setFile(tmpFileName, gTrue); + src = newsrc; + delete tmpFileName; + } + fileNameA = src->fileName; + // load the font file + if ((t1libIDA = T1_AddFont(fileNameA)) < 0) { + delete newsrc; + return NULL; + } + T1_LoadFont(t1libIDA); + + // reencode it + encStrSize = 0; + for (i = 0; i < 256; ++i) { + if (encA[i]) { + encStrSize += strlen(encA[i]) + 1; + } + } + encTmp = (char **)gmallocn(257, sizeof(char *)); + encStrTmp = (char *)gmallocn(encStrSize, sizeof(char)); + encPtr = encStrTmp; + for (i = 0; i < 256; ++i) { + if (encA[i]) { + strcpy(encPtr, encA[i]); + encTmp[i] = encPtr; + encPtr += strlen(encPtr) + 1; + } else { + encTmp[i] = ".notdef"; + } + } + encTmp[256] = "custom"; + T1_ReencodeFont(t1libIDA, encTmp); + + ff = new SplashT1FontFile(engineA, idA, src, + t1libIDA, encTmp, encStrTmp); + if (newsrc) + newsrc->unref(); + return ff; +} + +SplashT1FontFile::SplashT1FontFile(SplashT1FontEngine *engineA, + SplashFontFileID *idA, + SplashFontSrc *srcA, + int t1libIDA, char **encA, char *encStrA): + SplashFontFile(idA, srcA) +{ + engine = engineA; + t1libID = t1libIDA; + enc = encA; + encStr = encStrA; +} + +SplashT1FontFile::~SplashT1FontFile() { + gfree(encStr); + gfree(enc); + T1_DeleteFont(t1libID); +} + +SplashFont *SplashT1FontFile::makeFont(SplashCoord *mat, + SplashCoord *textMat) { + SplashFont *font; + + font = new SplashT1Font(this, mat, textMat); + font->initCache(); + return font; +} + +#endif // HAVE_T1LIB_H diff --git a/kpdf/xpdf/splash/SplashT1FontFile.h b/kpdf/xpdf/splash/SplashT1FontFile.h new file mode 100644 index 00000000..4dc93cbf --- /dev/null +++ b/kpdf/xpdf/splash/SplashT1FontFile.h @@ -0,0 +1,58 @@ +//======================================================================== +// +// SplashT1FontFile.h +// +//======================================================================== + +#ifndef SPLASHT1FONTFILE_H +#define SPLASHT1FONTFILE_H + +#include + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashFontFile.h" + +class SplashT1FontEngine; + +//------------------------------------------------------------------------ +// SplashT1FontFile +//------------------------------------------------------------------------ + +class SplashT1FontFile: public SplashFontFile { +public: + + static SplashFontFile *loadType1Font(SplashT1FontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, + char **encA); + + virtual ~SplashT1FontFile(); + + // Create a new SplashT1Font, i.e., a scaled instance of this font + // file. + virtual SplashFont *makeFont(SplashCoord *mat, + SplashCoord *textMat); + +private: + + SplashT1FontFile(SplashT1FontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, + int t1libIDA, char **encA, char *encStrA); + + SplashT1FontEngine *engine; + int t1libID; // t1lib font ID + char **enc; + char *encStr; + + friend class SplashT1Font; +}; + +#endif // HAVE_T1LIB_H + +#endif diff --git a/kpdf/xpdf/splash/SplashTypes.h b/kpdf/xpdf/splash/SplashTypes.h new file mode 100644 index 00000000..35551b90 --- /dev/null +++ b/kpdf/xpdf/splash/SplashTypes.h @@ -0,0 +1,132 @@ +//======================================================================== +// +// SplashTypes.h +// +//======================================================================== + +#ifndef SPLASHTYPES_H +#define SPLASHTYPES_H + +#include +#include "gtypes.h" + +//------------------------------------------------------------------------ +// coordinates +//------------------------------------------------------------------------ + +#if USE_FIXEDPOINT +#include "FixedPoint.h" +typedef FixedPoint SplashCoord; +#else +typedef double SplashCoord; +#endif + +//------------------------------------------------------------------------ +// antialiasing +//------------------------------------------------------------------------ + +#define splashAASize 4 + +//------------------------------------------------------------------------ +// colors +//------------------------------------------------------------------------ + +enum SplashColorMode { + splashModeMono1, // 1 bit per component, 8 pixels per byte, + // MSbit is on the left + splashModeMono8, // 1 byte per component, 1 byte per pixel + splashModeRGB8, // 1 byte per component, 3 bytes per pixel: + // RGBRGB... + splashModeBGR8 // 1 byte per component, 3 bytes per pixel: + // BGRBGR... + +#if SPLASH_CMYK + , + splashModeCMYK8 // 1 byte per component, 4 bytes per pixel: + // CMYKCMYK... +#endif +}; + +// number of components in each color mode +// (defined in SplashState.cc) +extern int splashColorModeNComps[]; + +// max number of components in any SplashColor +#if SPLASH_CMYK +# define splashMaxColorComps 4 +#else +# define splashMaxColorComps 3 +#endif + +typedef Guchar SplashColor[splashMaxColorComps]; +typedef Guchar *SplashColorPtr; + +// RGB8 +static inline Guchar splashRGB8R(SplashColorPtr rgb8) { return rgb8[0]; } +static inline Guchar splashRGB8G(SplashColorPtr rgb8) { return rgb8[1]; } +static inline Guchar splashRGB8B(SplashColorPtr rgb8) { return rgb8[2]; } + +// BGR8 +static inline Guchar splashBGR8R(SplashColorPtr bgr8) { return bgr8[2]; } +static inline Guchar splashBGR8G(SplashColorPtr bgr8) { return bgr8[1]; } +static inline Guchar splashBGR8B(SplashColorPtr bgr8) { return bgr8[0]; } + +#if SPLASH_CMYK +// CMYK8 +static inline Guchar splashCMYK8C(SplashColorPtr cmyk8) { return cmyk8[0]; } +static inline Guchar splashCMYK8M(SplashColorPtr cmyk8) { return cmyk8[1]; } +static inline Guchar splashCMYK8Y(SplashColorPtr cmyk8) { return cmyk8[2]; } +static inline Guchar splashCMYK8K(SplashColorPtr cmyk8) { return cmyk8[3]; } +#endif + +static inline void splashColorCopy(SplashColorPtr dest, SplashColorPtr src) { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; +#if SPLASH_CMYK + dest[3] = src[3]; +#endif +} + +static inline void splashColorXor(SplashColorPtr dest, SplashColorPtr src) { + dest[0] ^= src[0]; + dest[1] ^= src[1]; + dest[2] ^= src[2]; +#if SPLASH_CMYK + dest[3] ^= src[3]; +#endif +} + +//------------------------------------------------------------------------ +// blend functions +//------------------------------------------------------------------------ + +typedef void (*SplashBlendFunc)(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm); + +//------------------------------------------------------------------------ +// screen parameters +//------------------------------------------------------------------------ + +enum SplashScreenType { + splashScreenDispersed, + splashScreenClustered, + splashScreenStochasticClustered +}; + +struct SplashScreenParams { + SplashScreenType type; + int size; + int dotRadius; + SplashCoord gamma; + SplashCoord blackThreshold; + SplashCoord whiteThreshold; +}; + +//------------------------------------------------------------------------ +// error results +//------------------------------------------------------------------------ + +typedef int SplashError; + +#endif diff --git a/kpdf/xpdf/splash/SplashXPath.cc b/kpdf/xpdf/splash/SplashXPath.cc new file mode 100644 index 00000000..71481eff --- /dev/null +++ b/kpdf/xpdf/splash/SplashXPath.cc @@ -0,0 +1,443 @@ +//======================================================================== +// +// SplashXPath.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "SplashMath.h" +#include "SplashPath.h" +#include "SplashXPath.h" + +//------------------------------------------------------------------------ + +struct SplashXPathPoint { + SplashCoord x, y; +}; + +struct SplashXPathAdjust { + int firstPt, lastPt; // range of points + GBool vert; // vertical or horizontal hint + SplashCoord x0a, x0b, // hint boundaries + xma, xmb, + x1a, x1b; + SplashCoord x0, x1, xm; // adjusted coordinates +}; + +//------------------------------------------------------------------------ + +// Transform a point from user space to device space. +inline void SplashXPath::transform(SplashCoord *matrix, + SplashCoord xi, SplashCoord yi, + SplashCoord *xo, SplashCoord *yo) { + // [ m[0] m[1] 0 ] + // [xo yo 1] = [xi yi 1] * [ m[2] m[3] 0 ] + // [ m[4] m[5] 1 ] + *xo = xi * matrix[0] + yi * matrix[2] + matrix[4]; + *yo = xi * matrix[1] + yi * matrix[3] + matrix[5]; +} + +//------------------------------------------------------------------------ +// SplashXPath +//------------------------------------------------------------------------ + +SplashXPath::SplashXPath() { + segs = NULL; + length = size = 0; +} + +SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix, + SplashCoord flatness, GBool closeSubpaths) { + SplashPathHint *hint; + SplashXPathPoint *pts; + SplashXPathAdjust *adjusts, *adjust; + SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xsp, ysp; + SplashCoord adj0, adj1, w; + int ww; + int curSubpath, curSubpathX, i, j; + + // transform the points + pts = (SplashXPathPoint *)gmallocn(path->length, sizeof(SplashXPathPoint)); + for (i = 0; i < path->length; ++i) { + transform(matrix, path->pts[i].x, path->pts[i].y, &pts[i].x, &pts[i].y); + } + + // set up the stroke adjustment hints + if (path->hints) { + adjusts = (SplashXPathAdjust *)gmallocn(path->hintsLength, + sizeof(SplashXPathAdjust)); + for (i = 0; i < path->hintsLength; ++i) { + hint = &path->hints[i]; + if (hint->ctrl0 + 1 >= path->length || hint->ctrl1 + 1 >= path->length) { + gfree(adjusts); + adjusts = NULL; + break; + } + x0 = pts[hint->ctrl0 ].x; y0 = pts[hint->ctrl0 ].y; + x1 = pts[hint->ctrl0 + 1].x; y1 = pts[hint->ctrl0 + 1].y; + x2 = pts[hint->ctrl1 ].x; y2 = pts[hint->ctrl1 ].y; + x3 = pts[hint->ctrl1 + 1].x; y3 = pts[hint->ctrl1 + 1].y; + if (x0 == x1 && x2 == x3) { + adjusts[i].vert = gTrue; + adj0 = x0; + adj1 = x2; + } else if (y0 == y1 && y2 == y3) { + adjusts[i].vert = gFalse; + adj0 = y0; + adj1 = y2; + } else { + gfree(adjusts); + adjusts = NULL; + break; + } + if (adj0 > adj1) { + x0 = adj0; + adj0 = adj1; + adj1 = x0; + } + w = adj1 - adj0; + ww = splashRound(w); + if (ww == 0) { + ww = 1; + } + adjusts[i].x0a = adj0 - 0.01; + adjusts[i].x0b = adj0 + 0.01; + adjusts[i].xma = (SplashCoord)0.5 * (adj0 + adj1) - 0.01; + adjusts[i].xmb = (SplashCoord)0.5 * (adj0 + adj1) + 0.01; + adjusts[i].x1a = adj1 - 0.01; + adjusts[i].x1b = adj1 + 0.01; + adjusts[i].x0 = (SplashCoord)splashRound(adj0); + adjusts[i].x1 = adjusts[i].x0 + ww - 0.01; + adjusts[i].xm = (SplashCoord)0.5 * (adjusts[i].x0 + adjusts[i].x1); + adjusts[i].firstPt = hint->firstPt; + adjusts[i].lastPt = hint->lastPt; + } + + } else { + adjusts = NULL; + } + + // perform stroke adjustment + if (adjusts) { + for (i = 0, adjust = adjusts; i < path->hintsLength; ++i, ++adjust) { + for (j = adjust->firstPt; j <= adjust->lastPt; ++j) { + strokeAdjust(adjust, &pts[j].x, &pts[j].y); + } + } + gfree(adjusts); + } + + segs = NULL; + length = size = 0; + + x0 = y0 = xsp = ysp = 0; // make gcc happy + adj0 = adj1 = 0; // make gcc happy + curSubpath = 0; + curSubpathX = 0; + i = 0; + while (i < path->length) { + + // first point in subpath - skip it + if (path->flags[i] & splashPathFirst) { + x0 = pts[i].x; + y0 = pts[i].y; + xsp = x0; + ysp = y0; + curSubpath = i; + curSubpathX = length; + ++i; + + } else { + + // curve segment + if (path->flags[i] & splashPathCurve) { + x1 = pts[i].x; + y1 = pts[i].y; + x2 = pts[i+1].x; + y2 = pts[i+1].y; + x3 = pts[i+2].x; + y3 = pts[i+2].y; + addCurve(x0, y0, x1, y1, x2, y2, x3, y3, + flatness, + (path->flags[i-1] & splashPathFirst), + (path->flags[i+2] & splashPathLast), + !closeSubpaths && + (path->flags[i-1] & splashPathFirst) && + !(path->flags[i-1] & splashPathClosed), + !closeSubpaths && + (path->flags[i+2] & splashPathLast) && + !(path->flags[i+2] & splashPathClosed)); + x0 = x3; + y0 = y3; + i += 3; + + // line segment + } else { + x1 = pts[i].x; + y1 = pts[i].y; + addSegment(x0, y0, x1, y1, + path->flags[i-1] & splashPathFirst, + path->flags[i] & splashPathLast, + !closeSubpaths && + (path->flags[i-1] & splashPathFirst) && + !(path->flags[i-1] & splashPathClosed), + !closeSubpaths && + (path->flags[i] & splashPathLast) && + !(path->flags[i] & splashPathClosed)); + x0 = x1; + y0 = y1; + ++i; + } + + // close a subpath + if (closeSubpaths && + (path->flags[i-1] & splashPathLast) && + (pts[i-1].x != pts[curSubpath].x || + pts[i-1].y != pts[curSubpath].y)) { + addSegment(x0, y0, xsp, ysp, + gFalse, gTrue, gFalse, gFalse); + } + } + } + + gfree(pts); +} + +// Apply the stroke adjust hints to point : (*, *). +void SplashXPath::strokeAdjust(SplashXPathAdjust *adjust, + SplashCoord *xp, SplashCoord *yp) { + SplashCoord x, y; + + if (adjust->vert) { + x = *xp; + if (x > adjust->x0a && x < adjust->x0b) { + *xp = adjust->x0; + } else if (x > adjust->xma && x < adjust->xmb) { + *xp = adjust->xm; + } else if (x > adjust->x1a && x < adjust->x1b) { + *xp = adjust->x1; + } + } else { + y = *yp; + if (y > adjust->x0a && y < adjust->x0b) { + *yp = adjust->x0; + } else if (y > adjust->xma && y < adjust->xmb) { + *yp = adjust->xm; + } else if (y > adjust->x1a && y < adjust->x1b) { + *yp = adjust->x1; + } + } +} + +SplashXPath::SplashXPath(SplashXPath *xPath) { + length = xPath->length; + size = xPath->size; + segs = (SplashXPathSeg *)gmallocn(size, sizeof(SplashXPathSeg)); + memcpy(segs, xPath->segs, length * sizeof(SplashXPathSeg)); +} + +SplashXPath::~SplashXPath() { + gfree(segs); +} + +// Add space for more segments +void SplashXPath::grow(int nSegs) { + if (length + nSegs > size) { + if (size == 0) { + size = 32; + } + while (size < length + nSegs) { + size *= 2; + } + segs = (SplashXPathSeg *)greallocn(segs, size, sizeof(SplashXPathSeg)); + } +} + +void SplashXPath::addCurve(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3, + SplashCoord flatness, + GBool first, GBool last, GBool end0, GBool end1) { + SplashCoord cx[splashMaxCurveSplits + 1][3]; + SplashCoord cy[splashMaxCurveSplits + 1][3]; + int cNext[splashMaxCurveSplits + 1]; + SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh; + SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh; + SplashCoord dx, dy, mx, my, d1, d2, flatness2; + int p1, p2, p3; + + flatness2 = flatness * flatness; + + // initial segment + p1 = 0; + p2 = splashMaxCurveSplits; + cx[p1][0] = x0; cy[p1][0] = y0; + cx[p1][1] = x1; cy[p1][1] = y1; + cx[p1][2] = x2; cy[p1][2] = y2; + cx[p2][0] = x3; cy[p2][0] = y3; + cNext[p1] = p2; + + while (p1 < splashMaxCurveSplits) { + + // get the next segment + xl0 = cx[p1][0]; yl0 = cy[p1][0]; + xx1 = cx[p1][1]; yy1 = cy[p1][1]; + xx2 = cx[p1][2]; yy2 = cy[p1][2]; + p2 = cNext[p1]; + xr3 = cx[p2][0]; yr3 = cy[p2][0]; + + // compute the distances from the control points to the + // midpoint of the straight line (this is a bit of a hack, but + // it's much faster than computing the actual distances to the + // line) + mx = (xl0 + xr3) * 0.5; + my = (yl0 + yr3) * 0.5; + dx = xx1 - mx; + dy = yy1 - my; + d1 = dx*dx + dy*dy; + dx = xx2 - mx; + dy = yy2 - my; + d2 = dx*dx + dy*dy; + + // if the curve is flat enough, or no more subdivisions are + // allowed, add the straight line segment + if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) { + addSegment(xl0, yl0, xr3, yr3, + p1 == 0 && first, + p2 == splashMaxCurveSplits && last, + p1 == 0 && end0, + p2 == splashMaxCurveSplits && end1); + p1 = p2; + + // otherwise, subdivide the curve + } else { + xl1 = (xl0 + xx1) * 0.5; + yl1 = (yl0 + yy1) * 0.5; + xh = (xx1 + xx2) * 0.5; + yh = (yy1 + yy2) * 0.5; + xl2 = (xl1 + xh) * 0.5; + yl2 = (yl1 + yh) * 0.5; + xr2 = (xx2 + xr3) * 0.5; + yr2 = (yy2 + yr3) * 0.5; + xr1 = (xh + xr2) * 0.5; + yr1 = (yh + yr2) * 0.5; + xr0 = (xl2 + xr1) * 0.5; + yr0 = (yl2 + yr1) * 0.5; + // add the new subdivision points + p3 = (p1 + p2) / 2; + cx[p1][1] = xl1; cy[p1][1] = yl1; + cx[p1][2] = xl2; cy[p1][2] = yl2; + cNext[p1] = p3; + cx[p3][0] = xr0; cy[p3][0] = yr0; + cx[p3][1] = xr1; cy[p3][1] = yr1; + cx[p3][2] = xr2; cy[p3][2] = yr2; + cNext[p3] = p2; + } + } +} + +void SplashXPath::addSegment(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + GBool first, GBool last, GBool end0, GBool end1) { + grow(1); + segs[length].x0 = x0; + segs[length].y0 = y0; + segs[length].x1 = x1; + segs[length].y1 = y1; + segs[length].flags = 0; + if (first) { + segs[length].flags |= splashXPathFirst; + } + if (last) { + segs[length].flags |= splashXPathLast; + } + if (end0) { + segs[length].flags |= splashXPathEnd0; + } + if (end1) { + segs[length].flags |= splashXPathEnd1; + } + if (y1 == y0) { + segs[length].dxdy = segs[length].dydx = 0; + segs[length].flags |= splashXPathHoriz; + if (x1 == x0) { + segs[length].flags |= splashXPathVert; + } + } else if (x1 == x0) { + segs[length].dxdy = segs[length].dydx = 0; + segs[length].flags |= splashXPathVert; + } else { +#if USE_FIXEDPOINT + if (FixedPoint::divCheck(x1 - x0, y1 - y0, &segs[length].dxdy)) { + segs[length].dydx = (SplashCoord)1 / segs[length].dxdy; + } else { + segs[length].dxdy = segs[length].dydx = 0; + if (splashAbs(x1 - x0) > splashAbs(y1 - y0)) { + segs[length].flags |= splashXPathHoriz; + } else { + segs[length].flags |= splashXPathVert; + } + } +#else + segs[length].dxdy = (x1 - x0) / (y1 - y0); + segs[length].dydx = (SplashCoord)1 / segs[length].dxdy; +#endif + } + if (y0 > y1) { + segs[length].flags |= splashXPathFlip; + } + ++length; +} + +static int cmpXPathSegs(const void *arg0, const void *arg1) { + SplashXPathSeg *seg0 = (SplashXPathSeg *)arg0; + SplashXPathSeg *seg1 = (SplashXPathSeg *)arg1; + SplashCoord x0, y0, x1, y1; + + if (seg0->flags & splashXPathFlip) { + x0 = seg0->x1; + y0 = seg0->y1; + } else { + x0 = seg0->x0; + y0 = seg0->y0; + } + if (seg1->flags & splashXPathFlip) { + x1 = seg1->x1; + y1 = seg1->y1; + } else { + x1 = seg1->x0; + y1 = seg1->y0; + } + if (y0 != y1) { + return (y0 > y1) ? 1 : -1; + } + if (x0 != x1) { + return (x0 > x1) ? 1 : -1; + } + return 0; +} + +void SplashXPath::aaScale() { + SplashXPathSeg *seg; + int i; + + for (i = 0, seg = segs; i < length; ++i, ++seg) { + seg->x0 *= splashAASize; + seg->y0 *= splashAASize; + seg->x1 *= splashAASize; + seg->y1 *= splashAASize; + } +} + +void SplashXPath::sort() { + qsort(segs, length, sizeof(SplashXPathSeg), &cmpXPathSegs); +} diff --git a/kpdf/xpdf/splash/SplashXPath.h b/kpdf/xpdf/splash/SplashXPath.h new file mode 100644 index 00000000..43276b84 --- /dev/null +++ b/kpdf/xpdf/splash/SplashXPath.h @@ -0,0 +1,100 @@ +//======================================================================== +// +// SplashXPath.h +// +//======================================================================== + +#ifndef SPLASHXPATH_H +#define SPLASHXPATH_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashPath; +struct SplashXPathAdjust; + +//------------------------------------------------------------------------ + +#define splashMaxCurveSplits (1 << 10) + +//------------------------------------------------------------------------ +// SplashXPathSeg +//------------------------------------------------------------------------ + +struct SplashXPathSeg { + SplashCoord x0, y0; // first endpoint + SplashCoord x1, y1; // second endpoint + SplashCoord dxdy; // slope: delta-x / delta-y + SplashCoord dydx; // slope: delta-y / delta-x + Guint flags; +}; + +#define splashXPathFirst 0x01 // first segment of a subpath +#define splashXPathLast 0x02 // last segment of a subpath +#define splashXPathEnd0 0x04 // first endpoint is end of an open subpath +#define splashXPathEnd1 0x08 // second endpoint is end of an open subpath +#define splashXPathHoriz 0x10 // segment is vertical (y0 == y1) + // (dxdy is undef) +#define splashXPathVert 0x20 // segment is horizontal (x0 == x1) + // (dydx is undef) +#define splashXPathFlip 0x40 // y0 > y1 + +//------------------------------------------------------------------------ +// SplashXPath +//------------------------------------------------------------------------ + +class SplashXPath { +public: + + // Expands (converts to segments) and flattens (converts curves to + // lines) . Transforms all points from user space to device + // space, via . If is true, closes all open + // subpaths. + SplashXPath(SplashPath *path, SplashCoord *matrix, + SplashCoord flatness, GBool closeSubpaths); + + // Copy an expanded path. + SplashXPath *copy() { return new SplashXPath(this); } + + ~SplashXPath(); + + // Multiply all coordinates by splashAASize, in preparation for + // anti-aliased rendering. + void aaScale(); + + // Sort by upper coordinate (lower y), in y-major order. + void sort(); + +private: + + SplashXPath(); + SplashXPath(SplashXPath *xPath); + void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi, + SplashCoord *xo, SplashCoord *yo); + void strokeAdjust(SplashXPathAdjust *adjust, + SplashCoord *xp, SplashCoord *yp); + void grow(int nSegs); + void addCurve(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3, + SplashCoord flatness, + GBool first, GBool last, GBool end0, GBool end1); + void addSegment(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + GBool first, GBool last, GBool end0, GBool end1); + + SplashXPathSeg *segs; + int length, size; // length and size of segs array + + friend class SplashXPathScanner; + friend class SplashClip; + friend class Splash; +}; + +#endif diff --git a/kpdf/xpdf/splash/SplashXPathScanner.cc b/kpdf/xpdf/splash/SplashXPathScanner.cc new file mode 100644 index 00000000..97e5a9bc --- /dev/null +++ b/kpdf/xpdf/splash/SplashXPathScanner.cc @@ -0,0 +1,429 @@ +//======================================================================== +// +// SplashXPathScanner.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "SplashMath.h" +#include "SplashXPath.h" +#include "SplashBitmap.h" +#include "SplashXPathScanner.h" + +//------------------------------------------------------------------------ + +struct SplashIntersect { + int x0, x1; // intersection of segment with [y, y+1) + int count; // EO/NZWN counter increment +}; + +static int cmpIntersect(const void *p0, const void *p1) { + return ((SplashIntersect *)p0)->x0 - ((SplashIntersect *)p1)->x0; +} + +//------------------------------------------------------------------------ +// SplashXPathScanner +//------------------------------------------------------------------------ + +SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eoA) { + SplashXPathSeg *seg; + SplashCoord xMinFP, yMinFP, xMaxFP, yMaxFP; + int i; + + xPath = xPathA; + eo = eoA; + + // compute the bbox + if (xPath->length == 0) { + xMin = yMin = 1; + xMax = yMax = 0; + } else { + seg = &xPath->segs[0]; + if (seg->x0 <= seg->x1) { + xMinFP = seg->x0; + xMaxFP = seg->x1; + } else { + xMinFP = seg->x1; + xMaxFP = seg->x0; + } + if (seg->flags & splashXPathFlip) { + yMinFP = seg->y1; + yMaxFP = seg->y0; + } else { + yMinFP = seg->y0; + yMaxFP = seg->y1; + } + for (i = 1; i < xPath->length; ++i) { + seg = &xPath->segs[i]; + if (seg->x0 < xMinFP) { + xMinFP = seg->x0; + } else if (seg->x0 > xMaxFP) { + xMaxFP = seg->x0; + } + if (seg->x1 < xMinFP) { + xMinFP = seg->x1; + } else if (seg->x1 > xMaxFP) { + xMaxFP = seg->x1; + } + if (seg->flags & splashXPathFlip) { + if (seg->y0 > yMaxFP) { + yMaxFP = seg->y0; + } + } else { + if (seg->y1 > yMaxFP) { + yMaxFP = seg->y1; + } + } + } + xMin = splashFloor(xMinFP); + xMax = splashFloor(xMaxFP); + yMin = splashFloor(yMinFP); + yMax = splashFloor(yMaxFP); + } + + interY = yMin - 1; + xPathIdx = 0; + inter = NULL; + interLen = interSize = 0; +} + +SplashXPathScanner::~SplashXPathScanner() { + gfree(inter); +} + +void SplashXPathScanner::getBBoxAA(int *xMinA, int *yMinA, + int *xMaxA, int *yMaxA) { + *xMinA = xMin / splashAASize; + *yMinA = yMin / splashAASize; + *xMaxA = xMax / splashAASize; + *yMaxA = yMax / splashAASize; +} + +void SplashXPathScanner::getSpanBounds(int y, int *spanXMin, int *spanXMax) { + if (interY != y) { + computeIntersections(y); + } + if (interLen > 0) { + *spanXMin = inter[0].x0; + *spanXMax = inter[interLen - 1].x1; + } else { + *spanXMin = xMax + 1; + *spanXMax = xMax; + } +} + +GBool SplashXPathScanner::test(int x, int y) { + int count, i; + + if (interY != y) { + computeIntersections(y); + } + count = 0; + for (i = 0; i < interLen && inter[i].x0 <= x; ++i) { + if (x <= inter[i].x1) { + return gTrue; + } + count += inter[i].count; + } + return eo ? (count & 1) : (count != 0); +} + +GBool SplashXPathScanner::testSpan(int x0, int x1, int y) { + int count, xx1, i; + + if (interY != y) { + computeIntersections(y); + } + + count = 0; + for (i = 0; i < interLen && inter[i].x1 < x0; ++i) { + count += inter[i].count; + } + + // invariant: the subspan [x0,xx1] is inside the path + xx1 = x0 - 1; + while (xx1 < x1) { + if (i >= interLen) { + return gFalse; + } + if (inter[i].x0 > xx1 + 1 && + !(eo ? (count & 1) : (count != 0))) { + return gFalse; + } + if (inter[i].x1 > xx1) { + xx1 = inter[i].x1; + } + count += inter[i].count; + ++i; + } + + return gTrue; +} + +GBool SplashXPathScanner::getNextSpan(int y, int *x0, int *x1) { + int xx0, xx1; + + if (interY != y) { + computeIntersections(y); + } + if (interIdx >= interLen) { + return gFalse; + } + xx0 = inter[interIdx].x0; + xx1 = inter[interIdx].x1; + interCount += inter[interIdx].count; + ++interIdx; + while (interIdx < interLen && + (inter[interIdx].x0 <= xx1 || + (eo ? (interCount & 1) : (interCount != 0)))) { + if (inter[interIdx].x1 > xx1) { + xx1 = inter[interIdx].x1; + } + interCount += inter[interIdx].count; + ++interIdx; + } + *x0 = xx0; + *x1 = xx1; + return gTrue; +} + +void SplashXPathScanner::computeIntersections(int y) { + SplashCoord xSegMin, xSegMax, ySegMin, ySegMax, xx0, xx1; + SplashXPathSeg *seg; + int i, j; + + // find the first segment that intersects [y, y+1) + i = (y >= interY) ? xPathIdx : 0; + while (i < xPath->length && + xPath->segs[i].y0 < y && xPath->segs[i].y1 < y) { + ++i; + } + xPathIdx = i; + + // find all of the segments that intersect [y, y+1) and create an + // Intersect element for each one + interLen = 0; + for (j = i; j < xPath->length; ++j) { + seg = &xPath->segs[j]; + if (seg->flags & splashXPathFlip) { + ySegMin = seg->y1; + ySegMax = seg->y0; + } else { + ySegMin = seg->y0; + ySegMax = seg->y1; + } + + // ensure that: ySegMin < y+1 + // y <= ySegMax + if (ySegMin >= y + 1) { + break; + } + if (ySegMax < y) { + continue; + } + + if (interLen == interSize) { + if (interSize == 0) { + interSize = 16; + } else { + interSize *= 2; + } + inter = (SplashIntersect *)greallocn(inter, interSize, + sizeof(SplashIntersect)); + } + + if (seg->flags & splashXPathHoriz) { + xx0 = seg->x0; + xx1 = seg->x1; + } else if (seg->flags & splashXPathVert) { + xx0 = xx1 = seg->x0; + } else { + if (seg->x0 < seg->x1) { + xSegMin = seg->x0; + xSegMax = seg->x1; + } else { + xSegMin = seg->x1; + xSegMax = seg->x0; + } + // intersection with top edge + xx0 = seg->x0 + ((SplashCoord)y - seg->y0) * seg->dxdy; + // intersection with bottom edge + xx1 = seg->x0 + ((SplashCoord)y + 1 - seg->y0) * seg->dxdy; + // the segment may not actually extend to the top and/or bottom edges + if (xx0 < xSegMin) { + xx0 = xSegMin; + } else if (xx0 > xSegMax) { + xx0 = xSegMax; + } + if (xx1 < xSegMin) { + xx1 = xSegMin; + } else if (xx1 > xSegMax) { + xx1 = xSegMax; + } + } + if (xx0 < xx1) { + inter[interLen].x0 = splashFloor(xx0); + inter[interLen].x1 = splashFloor(xx1); + } else { + inter[interLen].x0 = splashFloor(xx1); + inter[interLen].x1 = splashFloor(xx0); + } + if (ySegMin <= y && + (SplashCoord)y < ySegMax && + !(seg->flags & splashXPathHoriz)) { + inter[interLen].count = eo ? 1 + : (seg->flags & splashXPathFlip) ? 1 : -1; + } else { + inter[interLen].count = 0; + } + ++interLen; + } + + qsort(inter, interLen, sizeof(SplashIntersect), &cmpIntersect); + + interY = y; + interIdx = 0; + interCount = 0; +} + +void SplashXPathScanner::renderAALine(SplashBitmap *aaBuf, + int *x0, int *x1, int y) { + int xx0, xx1, xx, xxMin, xxMax, yy; + Guchar mask; + SplashColorPtr p; + + memset(aaBuf->getDataPtr(), 0, aaBuf->getRowSize() * aaBuf->getHeight()); + xxMin = aaBuf->getWidth(); + xxMax = -1; + for (yy = 0; yy < splashAASize; ++yy) { + computeIntersections(splashAASize * y + yy); + while (interIdx < interLen) { + xx0 = inter[interIdx].x0; + xx1 = inter[interIdx].x1; + interCount += inter[interIdx].count; + ++interIdx; + while (interIdx < interLen && + (inter[interIdx].x0 <= xx1 || + (eo ? (interCount & 1) : (interCount != 0)))) { + if (inter[interIdx].x1 > xx1) { + xx1 = inter[interIdx].x1; + } + interCount += inter[interIdx].count; + ++interIdx; + } + if (xx0 < 0) { + xx0 = 0; + } + ++xx1; + if (xx1 > aaBuf->getWidth()) { + xx1 = aaBuf->getWidth(); + } + // set [xx0, xx1) to 1 + if (xx0 < xx1) { + xx = xx0; + p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3); + if (xx & 7) { + mask = 0xff >> (xx & 7); + if ((xx & ~7) == (xx1 & ~7)) { + mask &= (Guchar)(0xff00 >> (xx1 & 7)); + } + *p++ |= mask; + xx = (xx & ~7) + 8; + } + for (; xx + 7 < xx1; xx += 8) { + *p++ |= 0xff; + } + if (xx < xx1) { + *p |= (Guchar)(0xff00 >> (xx1 & 7)); + } + } + if (xx0 < xxMin) { + xxMin = xx0; + } + if (xx1 > xxMax) { + xxMax = xx1; + } + } + } + *x0 = xxMin / splashAASize; + *x1 = (xxMax - 1) / splashAASize; +} + +void SplashXPathScanner::clipAALine(SplashBitmap *aaBuf, + int *x0, int *x1, int y) { + int xx0, xx1, xx, yy; + Guchar mask; + SplashColorPtr p; + + for (yy = 0; yy < splashAASize; ++yy) { + xx = *x0 * splashAASize; + computeIntersections(splashAASize * y + yy); + while (interIdx < interLen && xx < (*x1 + 1) * splashAASize) { + xx0 = inter[interIdx].x0; + xx1 = inter[interIdx].x1; + interCount += inter[interIdx].count; + ++interIdx; + while (interIdx < interLen && + (inter[interIdx].x0 <= xx1 || + (eo ? (interCount & 1) : (interCount != 0)))) { + if (inter[interIdx].x1 > xx1) { + xx1 = inter[interIdx].x1; + } + interCount += inter[interIdx].count; + ++interIdx; + } + if (xx0 > aaBuf->getWidth()) { + xx0 = aaBuf->getWidth(); + } + // set [xx, xx0) to 0 + if (xx < xx0) { + p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3); + if (xx & 7) { + mask = (Guchar)(0xff00 >> (xx & 7)); + if ((xx & ~7) == (xx0 & ~7)) { + mask |= 0xff >> (xx0 & 7); + } + *p++ &= mask; + xx = (xx & ~7) + 8; + } + for (; xx + 7 <= xx0; xx += 8) { + *p++ = 0x00; + } + if (xx < xx0) { + *p &= 0xff >> (xx0 & 7); + } + } + if (xx1 >= xx) { + xx = xx1 + 1; + } + } + xx0 = (*x1 + 1) * splashAASize; + if (xx0 > aaBuf->getWidth()) xx0 = aaBuf->getWidth(); + // set [xx, xx0) to 0 + if (xx < xx0) { + p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3); + if (xx & 7) { + mask = (Guchar)(0xff00 >> (xx & 7)); + if ((xx & ~7) == (xx0 & ~7)) { + mask &= 0xff >> (xx0 & 7); + } + *p++ &= mask; + xx = (xx & ~7) + 8; + } + for (; xx + 7 <= xx0; xx += 8) { + *p++ = 0x00; + } + if (xx < xx0) { + *p &= 0xff >> (xx0 & 7); + } + } + } +} diff --git a/kpdf/xpdf/splash/SplashXPathScanner.h b/kpdf/xpdf/splash/SplashXPathScanner.h new file mode 100644 index 00000000..ab02fcc9 --- /dev/null +++ b/kpdf/xpdf/splash/SplashXPathScanner.h @@ -0,0 +1,87 @@ +//======================================================================== +// +// SplashXPathScanner.h +// +//======================================================================== + +#ifndef SPLASHXPATHSCANNER_H +#define SPLASHXPATHSCANNER_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashXPath; +class SplashBitmap; +struct SplashIntersect; + +//------------------------------------------------------------------------ +// SplashXPathScanner +//------------------------------------------------------------------------ + +class SplashXPathScanner { +public: + + // Create a new SplashXPathScanner object. must be sorted. + SplashXPathScanner(SplashXPath *xPathA, GBool eoA); + + ~SplashXPathScanner(); + + // Return the path's bounding box. + void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA) + { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } + + // Return the path's bounding box. + void getBBoxAA(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA); + + // Return the min/max x values for the span at . + void getSpanBounds(int y, int *spanXMin, int *spanXMax); + + // Returns true if (,) is inside the path. + GBool test(int x, int y); + + // Returns true if the entire span ([,], ) is inside the + // path. + GBool testSpan(int x0, int x1, int y); + + // Returns the next span inside the path at . If is + // different than the previous call to getNextSpan, this returns the + // first span at ; otherwise it returns the next span (relative + // to the previous call to getNextSpan). Returns false if there are + // no more spans at . + GBool getNextSpan(int y, int *x0, int *x1); + + // Renders one anti-aliased line into . Returns the min and + // max x coordinates with non-zero pixels in and . + void renderAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y); + + // Clips an anti-aliased line by setting pixels to zero. On entry, + // all non-zero pixels are between and . This function + // will update and . + void clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y); + +private: + + void computeIntersections(int y); + + SplashXPath *xPath; + GBool eo; + int xMin, yMin, xMax, yMax; + + int interY; // current y value + int interIdx; // current index into - used by + // getNextSpan + int interCount; // current EO/NZWN counter - used by + // getNextSpan + int xPathIdx; // current index into - used by + // computeIntersections + SplashIntersect *inter; // intersections array for + int interLen; // number of intersections in + int interSize; // size of the array +}; + +#endif diff --git a/kpdf/xpdf/xpdf/Annot.cc b/kpdf/xpdf/xpdf/Annot.cc new file mode 100644 index 00000000..23df25df --- /dev/null +++ b/kpdf/xpdf/xpdf/Annot.cc @@ -0,0 +1,1556 @@ +//======================================================================== +// +// Annot.cc +// +// Copyright 2000-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "GList.h" +#include "Error.h" +#include "Object.h" +#include "Catalog.h" +#include "Gfx.h" +#include "GfxFont.h" +#include "Lexer.h" +#include "Annot.h" + +//------------------------------------------------------------------------ + +#define annotFlagHidden 0x0002 +#define annotFlagPrint 0x0004 +#define annotFlagNoView 0x0020 + +#define fieldFlagReadOnly 0x00000001 +#define fieldFlagRequired 0x00000002 +#define fieldFlagNoExport 0x00000004 +#define fieldFlagMultiline 0x00001000 +#define fieldFlagPassword 0x00002000 +#define fieldFlagNoToggleToOff 0x00004000 +#define fieldFlagRadio 0x00008000 +#define fieldFlagPushbutton 0x00010000 +#define fieldFlagCombo 0x00020000 +#define fieldFlagEdit 0x00040000 +#define fieldFlagSort 0x00080000 +#define fieldFlagFileSelect 0x00100000 +#define fieldFlagMultiSelect 0x00200000 +#define fieldFlagDoNotSpellCheck 0x00400000 +#define fieldFlagDoNotScroll 0x00800000 +#define fieldFlagComb 0x01000000 +#define fieldFlagRichText 0x02000000 +#define fieldFlagRadiosInUnison 0x02000000 +#define fieldFlagCommitOnSelChange 0x04000000 + +#define fieldQuadLeft 0 +#define fieldQuadCenter 1 +#define fieldQuadRight 2 + +// distance of Bezier control point from center for circle approximation +// = (4 * (sqrt(2) - 1) / 3) * r +#define bezierCircle 0.55228475 + +//------------------------------------------------------------------------ +// AnnotBorderStyle +//------------------------------------------------------------------------ + +AnnotBorderStyle::AnnotBorderStyle(AnnotBorderType typeA, double widthA, + double *dashA, int dashLengthA, + double rA, double gA, double bA) { + type = typeA; + width = widthA; + dash = dashA; + dashLength = dashLengthA; + r = rA; + g = gA; + b = bA; +} + +AnnotBorderStyle::~AnnotBorderStyle() { + if (dash) { + gfree(dash); + } +} + +//------------------------------------------------------------------------ +// Annot +//------------------------------------------------------------------------ + +Annot::Annot(XRef *xrefA, Dict * /*acroForm*/, Dict *dict, Ref *refA) { + Object apObj, asObj, obj1, obj2, obj3; + AnnotBorderType borderType; + double borderWidth; + double *borderDash; + int borderDashLength; + double borderR, borderG, borderB; + double t; + int i; + + ok = gTrue; + xref = xrefA; + ref = *refA; + type = NULL; + appearBuf = NULL; + borderStyle = NULL; + + //----- parse the type + + if (dict->lookup("Subtype", &obj1)->isName()) { + type = new GString(obj1.getName()); + } + obj1.free(); + + //----- parse the rectangle + + if (dict->lookup("Rect", &obj1)->isArray() && + obj1.arrayGetLength() == 4) { + xMin = yMin = xMax = yMax = 0; + if (obj1.arrayGet(0, &obj2)->isNum()) { + xMin = obj2.getNum(); + } + obj2.free(); + if (obj1.arrayGet(1, &obj2)->isNum()) { + yMin = obj2.getNum(); + } + obj2.free(); + if (obj1.arrayGet(2, &obj2)->isNum()) { + xMax = obj2.getNum(); + } + obj2.free(); + if (obj1.arrayGet(3, &obj2)->isNum()) { + yMax = obj2.getNum(); + } + obj2.free(); + if (xMin > xMax) { + t = xMin; xMin = xMax; xMax = t; + } + if (yMin > yMax) { + t = yMin; yMin = yMax; yMax = t; + } + } else { + error(-1, "Bad bounding box for annotation"); + ok = gFalse; + } + obj1.free(); + + //----- parse the flags + + if (dict->lookup("F", &obj1)->isInt()) { + flags = obj1.getInt(); + } else { + flags = 0; + } + obj1.free(); + + //----- parse the border style + + borderType = annotBorderSolid; + borderWidth = 1; + borderDash = NULL; + borderDashLength = 0; + borderR = 0; + borderG = 0; + borderB = 1; + if (dict->lookup("BS", &obj1)->isDict()) { + if (obj1.dictLookup("S", &obj2)->isName()) { + if (obj2.isName("S")) { + borderType = annotBorderSolid; + } else if (obj2.isName("D")) { + borderType = annotBorderDashed; + } else if (obj2.isName("B")) { + borderType = annotBorderBeveled; + } else if (obj2.isName("I")) { + borderType = annotBorderInset; + } else if (obj2.isName("U")) { + borderType = annotBorderUnderlined; + } + } + obj2.free(); + if (obj1.dictLookup("W", &obj2)->isNum()) { + borderWidth = obj2.getNum(); + } + obj2.free(); + if (obj1.dictLookup("D", &obj2)->isArray()) { + borderDashLength = obj2.arrayGetLength(); + borderDash = (double *)gmallocn(borderDashLength, sizeof(double)); + for (i = 0; i < borderDashLength; ++i) { + if (obj2.arrayGet(i, &obj3)->isNum()) { + borderDash[i] = obj3.getNum(); + } else { + borderDash[i] = 1; + } + obj3.free(); + } + } + obj2.free(); + } else { + obj1.free(); + if (dict->lookup("Border", &obj1)->isArray()) { + if (obj1.arrayGetLength() >= 3) { + if (obj1.arrayGet(2, &obj2)->isNum()) { + borderWidth = obj2.getNum(); + } + obj2.free(); + if (obj1.arrayGetLength() >= 4) { + if (obj1.arrayGet(3, &obj2)->isArray()) { + borderType = annotBorderDashed; + borderDashLength = obj2.arrayGetLength(); + borderDash = (double *)gmallocn(borderDashLength, sizeof(double)); + for (i = 0; i < borderDashLength; ++i) { + if (obj2.arrayGet(i, &obj3)->isNum()) { + borderDash[i] = obj3.getNum(); + } else { + borderDash[i] = 1; + } + obj3.free(); + } + } else { + // Adobe draws no border at all if the last element is of + // the wrong type. + borderWidth = 0; + } + obj2.free(); + } + } + } + } + obj1.free(); + if (dict->lookup("C", &obj1)->isArray() && obj1.arrayGetLength() == 3) { + if (obj1.arrayGet(0, &obj2)->isNum()) { + borderR = obj2.getNum(); + } + obj1.free(); + if (obj1.arrayGet(1, &obj2)->isNum()) { + borderG = obj2.getNum(); + } + obj1.free(); + if (obj1.arrayGet(2, &obj2)->isNum()) { + borderB = obj2.getNum(); + } + obj1.free(); + } + obj1.free(); + borderStyle = new AnnotBorderStyle(borderType, borderWidth, + borderDash, borderDashLength, + borderR, borderG, borderB); + + //----- get the annotation appearance + + if (dict->lookup("AP", &apObj)->isDict()) { + if (dict->lookup("AS", &asObj)->isName()) { + if (apObj.dictLookup("N", &obj1)->isDict()) { + if (obj1.dictLookupNF(asObj.getName(), &obj2)->isRef()) { + obj2.copy(&appearance); + ok = gTrue; + } else { + obj2.free(); + if (obj1.dictLookupNF("Off", &obj2)->isRef()) { + obj2.copy(&appearance); + } + } + obj2.free(); + } + obj1.free(); + } else { + if (apObj.dictLookupNF("N", &obj1)->isRef()) { + obj1.copy(&appearance); + } + obj1.free(); + } + asObj.free(); + } + apObj.free(); +} + +Annot::~Annot() { + if (type) { + delete type; + } + appearance.free(); + if (appearBuf) { + delete appearBuf; + } + if (borderStyle) { + delete borderStyle; + } +} + +void Annot::generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm) { + Object mkObj, ftObj, appearDict, drObj, obj1, obj2, obj3; + Dict *mkDict; + MemStream *appearStream; + GfxFontDict *fontDict; + GBool hasCaption; + double w, dx, dy, r; + double *dash; + GString *caption, *da; + GString **text; + GBool *selection; + int dashLength, ff, quadding, comb, nOptions, topIdx, i, j; + + // must be a Widget annotation + if (type->cmp("Widget")) { + return; + } + + appearBuf = new GString(); + + // get the appearance characteristics (MK) dictionary + if (annot->lookup("MK", &mkObj)->isDict()) { + mkDict = mkObj.getDict(); + } else { + mkDict = NULL; + } + + // draw the background + if (mkDict) { + if (mkDict->lookup("BG", &obj1)->isArray() && + obj1.arrayGetLength() > 0) { + setColor(obj1.getArray(), gTrue, 0); + appearBuf->appendf("0 0 {0:.2f} {1:.2f} re f\n", + xMax - xMin, yMax - yMin); + } + obj1.free(); + } + + // get the field type + fieldLookup(field, "FT", &ftObj); + + // get the field flags (Ff) value + if (fieldLookup(field, "Ff", &obj1)->isInt()) { + ff = obj1.getInt(); + } else { + ff = 0; + } + obj1.free(); + + // draw the border + if (mkDict) { + w = borderStyle->getWidth(); + if (w > 0) { + mkDict->lookup("BC", &obj1); + if (!(obj1.isArray() && obj1.arrayGetLength() > 0)) { + mkDict->lookup("BG", &obj1); + } + if (obj1.isArray() && obj1.arrayGetLength() > 0) { + dx = xMax - xMin; + dy = yMax - yMin; + + // radio buttons with no caption have a round border + hasCaption = mkDict->lookup("CA", &obj2)->isString(); + obj2.free(); + if (ftObj.isName("Btn") && (ff & fieldFlagRadio) && !hasCaption) { + r = 0.5 * (dx < dy ? dx : dy); + switch (borderStyle->getType()) { + case annotBorderDashed: + appearBuf->append("["); + borderStyle->getDash(&dash, &dashLength); + for (i = 0; i < dashLength; ++i) { + appearBuf->appendf(" {0:.2f}", dash[i]); + } + appearBuf->append("] 0 d\n"); + // fall through to the solid case + case annotBorderSolid: + case annotBorderUnderlined: + appearBuf->appendf("{0:.2f} w\n", w); + setColor(obj1.getArray(), gFalse, 0); + drawCircle(0.5 * dx, 0.5 * dy, r - 0.5 * w, gFalse); + break; + case annotBorderBeveled: + case annotBorderInset: + appearBuf->appendf("{0:.2f} w\n", 0.5 * w); + setColor(obj1.getArray(), gFalse, 0); + drawCircle(0.5 * dx, 0.5 * dy, r - 0.25 * w, gFalse); + setColor(obj1.getArray(), gFalse, + borderStyle->getType() == annotBorderBeveled ? 1 : -1); + drawCircleTopLeft(0.5 * dx, 0.5 * dy, r - 0.75 * w); + setColor(obj1.getArray(), gFalse, + borderStyle->getType() == annotBorderBeveled ? -1 : 1); + drawCircleBottomRight(0.5 * dx, 0.5 * dy, r - 0.75 * w); + break; + } + + } else { + switch (borderStyle->getType()) { + case annotBorderDashed: + appearBuf->append("["); + borderStyle->getDash(&dash, &dashLength); + for (i = 0; i < dashLength; ++i) { + appearBuf->appendf(" {0:.2f}", dash[i]); + } + appearBuf->append("] 0 d\n"); + // fall through to the solid case + case annotBorderSolid: + appearBuf->appendf("{0:.2f} w\n", w); + setColor(obj1.getArray(), gFalse, 0); + appearBuf->appendf("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re s\n", + 0.5 * w, dx - w, dy - w); + break; + case annotBorderBeveled: + case annotBorderInset: + setColor(obj1.getArray(), gTrue, + borderStyle->getType() == annotBorderBeveled ? 1 : -1); + appearBuf->append("0 0 m\n"); + appearBuf->appendf("0 {0:.2f} l\n", dy); + appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx, dy); + appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, dy - w); + appearBuf->appendf("{0:.2f} {1:.2f} l\n", w, dy - w); + appearBuf->appendf("{0:.2f} {0:.2f} l\n", w); + appearBuf->append("f\n"); + setColor(obj1.getArray(), gTrue, + borderStyle->getType() == annotBorderBeveled ? -1 : 1); + appearBuf->append("0 0 m\n"); + appearBuf->appendf("{0:.2f} 0 l\n", dx); + appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx, dy); + appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, dy - w); + appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, w); + appearBuf->appendf("{0:.2f} {0:.2f} l\n", w); + appearBuf->append("f\n"); + break; + case annotBorderUnderlined: + appearBuf->appendf("{0:.2f} w\n", w); + setColor(obj1.getArray(), gFalse, 0); + appearBuf->appendf("0 0 m {0:.2f} 0 l s\n", dx); + break; + } + + // clip to the inside of the border + appearBuf->appendf("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re W n\n", + w, dx - 2 * w, dy - 2 * w); + } + } + obj1.free(); + } + } + + // get the resource dictionary + acroForm->lookup("DR", &drObj); + + // build the font dictionary + if (drObj.isDict() && drObj.dictLookup("Font", &obj1)->isDict()) { + fontDict = new GfxFontDict(xref, NULL, obj1.getDict()); + } else { + fontDict = NULL; + } + obj1.free(); + + // get the default appearance string + if (fieldLookup(field, "DA", &obj1)->isNull()) { + obj1.free(); + acroForm->lookup("DA", &obj1); + } + if (obj1.isString()) { + da = obj1.getString()->copy(); + } else { + da = NULL; + } + obj1.free(); + + // draw the field contents + if (ftObj.isName("Btn")) { + caption = NULL; + if (mkDict) { + if (mkDict->lookup("CA", &obj1)->isString()) { + caption = obj1.getString()->copy(); + } + obj1.free(); + } + // radio button + if (ff & fieldFlagRadio) { + //~ Acrobat doesn't draw a caption if there is no AP dict (?) + if (fieldLookup(field, "V", &obj1)->isName()) { + if (annot->lookup("AS", &obj2)->isName(obj1.getName())) { + if (caption) { + drawText(caption, da, fontDict, gFalse, 0, fieldQuadCenter, + gFalse, gTrue); + } else { + if (mkDict) { + if (mkDict->lookup("BC", &obj3)->isArray() && + obj3.arrayGetLength() > 0) { + dx = xMax - xMin; + dy = yMax - yMin; + setColor(obj3.getArray(), gTrue, 0); + drawCircle(0.5 * dx, 0.5 * dy, 0.2 * (dx < dy ? dx : dy), + gTrue); + } + obj3.free(); + } + } + } + obj2.free(); + } + obj1.free(); + // pushbutton + } else if (ff & fieldFlagPushbutton) { + if (caption) { + drawText(caption, da, fontDict, gFalse, 0, fieldQuadCenter, + gFalse, gFalse); + } + // checkbox + } else { + // According to the PDF spec the off state must be named "Off", + // and the on state can be named anything, but Acrobat apparently + // looks for "Yes" and treats anything else as off. + if (fieldLookup(field, "V", &obj1)->isName("Yes")) { + if (!caption) { + caption = new GString("3"); // ZapfDingbats checkmark + } + drawText(caption, da, fontDict, gFalse, 0, fieldQuadCenter, + gFalse, gTrue); + } + obj1.free(); + } + if (caption) { + delete caption; + } + } else if (ftObj.isName("Tx")) { + //~ value strings can be Unicode + if (fieldLookup(field, "V", &obj1)->isString()) { + if (fieldLookup(field, "Q", &obj2)->isInt()) { + quadding = obj2.getInt(); + } else { + quadding = fieldQuadLeft; + } + obj2.free(); + comb = 0; + if (ff & fieldFlagComb) { + if (fieldLookup(field, "MaxLen", &obj2)->isInt()) { + comb = obj2.getInt(); + } + obj2.free(); + } + drawText(obj1.getString(), da, fontDict, + ff & fieldFlagMultiline, comb, quadding, gTrue, gFalse); + } + obj1.free(); + } else if (ftObj.isName("Ch")) { + //~ value/option strings can be Unicode + if (fieldLookup(field, "Q", &obj1)->isInt()) { + quadding = obj1.getInt(); + } else { + quadding = fieldQuadLeft; + } + obj1.free(); + // combo box + if (ff & fieldFlagCombo) { + if (fieldLookup(field, "V", &obj1)->isString()) { + drawText(obj1.getString(), da, fontDict, + gFalse, 0, quadding, gTrue, gFalse); + //~ Acrobat draws a popup icon on the right side + } + obj1.free(); + // list box + } else { + if (field->lookup("Opt", &obj1)->isArray()) { + nOptions = obj1.arrayGetLength(); + // get the option text + text = (GString **)gmallocn(nOptions, sizeof(GString *)); + for (i = 0; i < nOptions; ++i) { + text[i] = NULL; + obj1.arrayGet(i, &obj2); + if (obj2.isString()) { + text[i] = obj2.getString()->copy(); + } else if (obj2.isArray() && obj2.arrayGetLength() == 2) { + if (obj2.arrayGet(1, &obj3)->isString()) { + text[i] = obj3.getString()->copy(); + } + obj3.free(); + } + obj2.free(); + if (!text[i]) { + text[i] = new GString(); + } + } + // get the selected option(s) + selection = (GBool *)gmallocn(nOptions, sizeof(GBool)); + //~ need to use the I field in addition to the V field + fieldLookup(field, "V", &obj2); + for (i = 0; i < nOptions; ++i) { + selection[i] = gFalse; + if (obj2.isString()) { + if (!obj2.getString()->cmp(text[i])) { + selection[i] = gTrue; + } + } else if (obj2.isArray()) { + for (j = 0; j < obj2.arrayGetLength(); ++j) { + if (obj2.arrayGet(j, &obj3)->isString() && + !obj3.getString()->cmp(text[i])) { + selection[i] = gTrue; + } + obj3.free(); + } + } + } + obj2.free(); + // get the top index + if (field->lookup("TI", &obj2)->isInt()) { + topIdx = obj2.getInt(); + } else { + topIdx = 0; + } + obj2.free(); + // draw the text + drawListBox(text, selection, nOptions, topIdx, da, fontDict, quadding); + for (i = 0; i < nOptions; ++i) { + delete text[i]; + } + gfree(text); + gfree(selection); + } + obj1.free(); + } + } else if (ftObj.isName("Sig")) { + //~unimp + } else { + error(-1, "Unknown field type"); + } + + if (da) { + delete da; + } + + // build the appearance stream dictionary + appearDict.initDict(xref); + appearDict.dictAdd(copyString("Length"), + obj1.initInt(appearBuf->getLength())); + appearDict.dictAdd(copyString("Subtype"), obj1.initName("Form")); + obj1.initArray(xref); + obj1.arrayAdd(obj2.initReal(0)); + obj1.arrayAdd(obj2.initReal(0)); + obj1.arrayAdd(obj2.initReal(xMax - xMin)); + obj1.arrayAdd(obj2.initReal(yMax - yMin)); + appearDict.dictAdd(copyString("BBox"), &obj1); + + // set the resource dictionary + if (drObj.isDict()) { + appearDict.dictAdd(copyString("Resources"), drObj.copy(&obj1)); + } + drObj.free(); + + // build the appearance stream + appearStream = new MemStream(appearBuf->getCString(), 0, + appearBuf->getLength(), &appearDict); + appearance.free(); + appearance.initStream(appearStream); + + if (fontDict) { + delete fontDict; + } + ftObj.free(); + mkObj.free(); +} + +// Set the current fill or stroke color, based on (which should +// have 1, 3, or 4 elements). If is +1, color is brightened; +// if is -1, color is darkened; otherwise color is not +// modified. +void Annot::setColor(Array *a, GBool fill, int adjust) { + Object obj1; + double color[4]; + int nComps, i; + + nComps = a->getLength(); + if (nComps > 4) { + nComps = 4; + } + for (i = 0; i < nComps && i < 4; ++i) { + if (a->get(i, &obj1)->isNum()) { + color[i] = obj1.getNum(); + } else { + color[i] = 0; + } + obj1.free(); + } + if (nComps == 4) { + adjust = -adjust; + } + if (adjust > 0) { + for (i = 0; i < nComps; ++i) { + color[i] = 0.5 * color[i] + 0.5; + } + } else if (adjust < 0) { + for (i = 0; i < nComps; ++i) { + color[i] = 0.5 * color[i]; + } + } + if (nComps == 4) { + appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:c}\n", + color[0], color[1], color[2], color[3], + fill ? 'k' : 'K'); + } else if (nComps == 3) { + appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:s}\n", + color[0], color[1], color[2], + fill ? "rg" : "RG"); + } else { + appearBuf->appendf("{0:.2f} {1:c}\n", + color[0], + fill ? 'g' : 'G'); + } +} + +// Draw the variable text or caption for a field. +void Annot::drawText(GString *text, GString *da, GfxFontDict *fontDict, + GBool multiline, int comb, int quadding, + GBool txField, GBool forceZapfDingbats) { + GList *daToks; + GString *tok; + GfxFont *font; + double fontSize, fontSize2, border, x, xPrev, y, w, w2, wMax; + int tfPos, tmPos, i, j, k, c; + + //~ if there is no MK entry, this should use the existing content stream, + //~ and only replace the marked content portion of it + //~ (this is only relevant for Tx fields) + + // parse the default appearance string + tfPos = tmPos = -1; + if (da) { + daToks = new GList(); + i = 0; + while (i < da->getLength()) { + while (i < da->getLength() && Lexer::isSpace(da->getChar(i))) { + ++i; + } + if (i < da->getLength()) { + for (j = i + 1; + j < da->getLength() && !Lexer::isSpace(da->getChar(j)); + ++j) ; + daToks->append(new GString(da, i, j - i)); + i = j; + } + } + for (i = 2; i < daToks->getLength(); ++i) { + if (i >= 2 && !((GString *)daToks->get(i))->cmp("Tf")) { + tfPos = i - 2; + } else if (i >= 6 && !((GString *)daToks->get(i))->cmp("Tm")) { + tmPos = i - 6; + } + } + } else { + daToks = NULL; + } + + // force ZapfDingbats + //~ this should create the font if needed (?) + if (forceZapfDingbats) { + if (tfPos >= 0) { + tok = (GString *)daToks->get(tfPos); + if (tok->cmp("/ZaDb")) { + tok->clear(); + tok->append("/ZaDb"); + } + } + } + + // get the font and font size + font = NULL; + fontSize = 0; + if (tfPos >= 0) { + tok = (GString *)daToks->get(tfPos); + if (tok->getLength() >= 1 && tok->getChar(0) == '/') { + if (!fontDict || !(font = fontDict->lookup(tok->getCString() + 1))) { + error(-1, "Unknown font in field's DA string"); + } + } else { + error(-1, "Invalid font name in 'Tf' operator in field's DA string"); + } + tok = (GString *)daToks->get(tfPos + 1); + fontSize = atof(tok->getCString()); + } else { + error(-1, "Missing 'Tf' operator in field's DA string"); + } + + // get the border width + border = borderStyle->getWidth(); + + // setup + if (txField) { + appearBuf->append("/Tx BMC\n"); + } + appearBuf->append("q\n"); + appearBuf->append("BT\n"); + + // multi-line text + if (multiline) { + // note: the comb flag is ignored in multiline mode + + wMax = xMax - xMin - 2 * border - 4; + + // compute font autosize + if (fontSize == 0) { + for (fontSize = 20; fontSize > 1; --fontSize) { + y = yMax - yMin; + w2 = 0; + i = 0; + while (i < text->getLength()) { + getNextLine(text, i, font, fontSize, wMax, &j, &w, &k); + if (w > w2) { + w2 = w; + } + i = k; + y -= fontSize; + } + // approximate the descender for the last line + if (y >= 0.33 * fontSize) { + break; + } + } + if (tfPos >= 0) { + tok = (GString *)daToks->get(tfPos + 1); + tok->clear(); + tok->appendf("{0:.2f}", fontSize); + } + } + + // starting y coordinate + // (note: each line of text starts with a Td operator that moves + // down a line) + y = yMax - yMin; + + // set the font matrix + if (tmPos >= 0) { + tok = (GString *)daToks->get(tmPos + 4); + tok->clear(); + tok->append('0'); + tok = (GString *)daToks->get(tmPos + 5); + tok->clear(); + tok->appendf("{0:.2f}", y); + } + + // write the DA string + if (daToks) { + for (i = 0; i < daToks->getLength(); ++i) { + appearBuf->append((GString *)daToks->get(i))->append(' '); + } + } + + // write the font matrix (if not part of the DA string) + if (tmPos < 0) { + appearBuf->appendf("1 0 0 1 0 {0:.2f} Tm\n", y); + } + + // write a series of lines of text + i = 0; + xPrev = 0; + while (i < text->getLength()) { + + getNextLine(text, i, font, fontSize, wMax, &j, &w, &k); + + // compute text start position + switch (quadding) { + case fieldQuadLeft: + default: + x = border + 2; + break; + case fieldQuadCenter: + x = (xMax - xMin - w) / 2; + break; + case fieldQuadRight: + x = xMax - xMin - border - 2 - w; + break; + } + + // draw the line + appearBuf->appendf("{0:.2f} {1:.2f} Td\n", x - xPrev, -fontSize); + appearBuf->append('('); + for (; i < j; ++i) { + c = text->getChar(i) & 0xff; + if (c == '(' || c == ')' || c == '\\') { + appearBuf->append('\\'); + appearBuf->append(c); + } else if (c < 0x20 || c >= 0x80) { + appearBuf->appendf("\\{0:03o}", c); + } else { + appearBuf->append(c); + } + } + appearBuf->append(") Tj\n"); + + // next line + i = k; + xPrev = x; + } + + // single-line text + } else { + //~ replace newlines with spaces? - what does Acrobat do? + + // comb formatting + if (comb > 0) { + + // compute comb spacing + w = (xMax - xMin - 2 * border) / comb; + + // compute font autosize + if (fontSize == 0) { + fontSize = yMax - yMin - 2 * border; + if (w < fontSize) { + fontSize = w; + } + fontSize = floor(fontSize); + if (tfPos >= 0) { + tok = (GString *)daToks->get(tfPos + 1); + tok->clear(); + tok->appendf("{0:.2f}", fontSize); + } + } + + // compute text start position + switch (quadding) { + case fieldQuadLeft: + default: + x = border + 2; + break; + case fieldQuadCenter: + x = border + 2 + 0.5 * (comb - text->getLength()) * w; + break; + case fieldQuadRight: + x = border + 2 + (comb - text->getLength()) * w; + break; + } + y = 0.5 * (yMax - yMin) - 0.4 * fontSize; + + // set the font matrix + if (tmPos >= 0) { + tok = (GString *)daToks->get(tmPos + 4); + tok->clear(); + tok->appendf("{0:.2f}", x); + tok = (GString *)daToks->get(tmPos + 5); + tok->clear(); + tok->appendf("{0:.2f}", y); + } + + // write the DA string + if (daToks) { + for (i = 0; i < daToks->getLength(); ++i) { + appearBuf->append((GString *)daToks->get(i))->append(' '); + } + } + + // write the font matrix (if not part of the DA string) + if (tmPos < 0) { + appearBuf->appendf("1 0 0 1 {0:.2f} {1:.2f} Tm\n", x, y); + } + + // write the text string + //~ this should center (instead of left-justify) each character within + //~ its comb cell + for (i = 0; i < text->getLength(); ++i) { + if (i > 0) { + appearBuf->appendf("{0:.2f} 0 Td\n", w); + } + appearBuf->append('('); + c = text->getChar(i) & 0xff; + if (c == '(' || c == ')' || c == '\\') { + appearBuf->append('\\'); + appearBuf->append(c); + } else if (c < 0x20 || c >= 0x80) { + appearBuf->appendf("{0:.2f} 0 Td\n", w); + } else { + appearBuf->append(c); + } + appearBuf->append(") Tj\n"); + } + + // regular (non-comb) formatting + } else { + + // compute string width + if (font && !font->isCIDFont()) { + w = 0; + for (i = 0; i < text->getLength(); ++i) { + w += ((Gfx8BitFont *)font)->getWidth(text->getChar(i)); + } + } else { + // otherwise, make a crude estimate + w = text->getLength() * 0.5; + } + + // compute font autosize + if (fontSize == 0) { + fontSize = yMax - yMin - 2 * border; + fontSize2 = (xMax - xMin - 4 - 2 * border) / w; + if (fontSize2 < fontSize) { + fontSize = fontSize2; + } + fontSize = floor(fontSize); + if (tfPos >= 0) { + tok = (GString *)daToks->get(tfPos + 1); + tok->clear(); + tok->appendf("{0:.2f}", fontSize); + } + } + + // compute text start position + w *= fontSize; + switch (quadding) { + case fieldQuadLeft: + default: + x = border + 2; + break; + case fieldQuadCenter: + x = (xMax - xMin - w) / 2; + break; + case fieldQuadRight: + x = xMax - xMin - border - 2 - w; + break; + } + y = 0.5 * (yMax - yMin) - 0.4 * fontSize; + + // set the font matrix + if (tmPos >= 0) { + tok = (GString *)daToks->get(tmPos + 4); + tok->clear(); + tok->appendf("{0:.2f}", x); + tok = (GString *)daToks->get(tmPos + 5); + tok->clear(); + tok->appendf("{0:.2f}", y); + } + + // write the DA string + if (daToks) { + for (i = 0; i < daToks->getLength(); ++i) { + appearBuf->append((GString *)daToks->get(i))->append(' '); + } + } + + // write the font matrix (if not part of the DA string) + if (tmPos < 0) { + appearBuf->appendf("1 0 0 1 {0:.2f} {1:.2f} Tm\n", x, y); + } + + // write the text string + appearBuf->append('('); + for (i = 0; i < text->getLength(); ++i) { + c = text->getChar(i) & 0xff; + if (c == '(' || c == ')' || c == '\\') { + appearBuf->append('\\'); + appearBuf->append(c); + } else if (c < 0x20 || c >= 0x80) { + appearBuf->appendf("\\{0:03o}", c); + } else { + appearBuf->append(c); + } + } + appearBuf->append(") Tj\n"); + } + } + + // cleanup + appearBuf->append("ET\n"); + appearBuf->append("Q\n"); + if (txField) { + appearBuf->append("EMC\n"); + } + + if (daToks) { + deleteGList(daToks, GString); + } +} + +// Draw the variable text or caption for a field. +void Annot::drawListBox(GString **text, GBool *selection, + int nOptions, int topIdx, + GString *da, GfxFontDict *fontDict, GBool quadding) { + GList *daToks; + GString *tok; + GfxFont *font; + double fontSize, fontSize2, border, x, y, w, wMax; + int tfPos, tmPos, i, j, c; + + //~ if there is no MK entry, this should use the existing content stream, + //~ and only replace the marked content portion of it + //~ (this is only relevant for Tx fields) + + // parse the default appearance string + tfPos = tmPos = -1; + if (da) { + daToks = new GList(); + i = 0; + while (i < da->getLength()) { + while (i < da->getLength() && Lexer::isSpace(da->getChar(i))) { + ++i; + } + if (i < da->getLength()) { + for (j = i + 1; + j < da->getLength() && !Lexer::isSpace(da->getChar(j)); + ++j) ; + daToks->append(new GString(da, i, j - i)); + i = j; + } + } + for (i = 2; i < daToks->getLength(); ++i) { + if (i >= 2 && !((GString *)daToks->get(i))->cmp("Tf")) { + tfPos = i - 2; + } else if (i >= 6 && !((GString *)daToks->get(i))->cmp("Tm")) { + tmPos = i - 6; + } + } + } else { + daToks = NULL; + } + + // get the font and font size + font = NULL; + fontSize = 0; + if (tfPos >= 0) { + tok = (GString *)daToks->get(tfPos); + if (tok->getLength() >= 1 && tok->getChar(0) == '/') { + if (!fontDict || !(font = fontDict->lookup(tok->getCString() + 1))) { + error(-1, "Unknown font in field's DA string"); + } + } else { + error(-1, "Invalid font name in 'Tf' operator in field's DA string"); + } + tok = (GString *)daToks->get(tfPos + 1); + fontSize = atof(tok->getCString()); + } else { + error(-1, "Missing 'Tf' operator in field's DA string"); + } + + // get the border width + border = borderStyle->getWidth(); + + // compute font autosize + if (fontSize == 0) { + wMax = 0; + for (i = 0; i < nOptions; ++i) { + if (font && !font->isCIDFont()) { + w = 0; + for (j = 0; j < text[i]->getLength(); ++j) { + w += ((Gfx8BitFont *)font)->getWidth(text[i]->getChar(j)); + } + } else { + // otherwise, make a crude estimate + w = text[i]->getLength() * 0.5; + } + if (w > wMax) { + wMax = w; + } + } + fontSize = yMax - yMin - 2 * border; + fontSize2 = (xMax - xMin - 4 - 2 * border) / wMax; + if (fontSize2 < fontSize) { + fontSize = fontSize2; + } + fontSize = floor(fontSize); + if (tfPos >= 0) { + tok = (GString *)daToks->get(tfPos + 1); + tok->clear(); + tok->appendf("{0:.2f}", fontSize); + } + } + + // draw the text + y = yMax - yMin - 1.1 * fontSize; + for (i = topIdx; i < nOptions; ++i) { + + // setup + appearBuf->append("q\n"); + + // draw the background if selected + if (selection[i]) { + appearBuf->append("0 g f\n"); + appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} re f\n", + border, + y - 0.2 * fontSize, + xMax - xMin - 2 * border, + 1.1 * fontSize); + } + + // setup + appearBuf->append("BT\n"); + + // compute string width + if (font && !font->isCIDFont()) { + w = 0; + for (j = 0; j < text[i]->getLength(); ++j) { + w += ((Gfx8BitFont *)font)->getWidth(text[i]->getChar(j)); + } + } else { + // otherwise, make a crude estimate + w = text[i]->getLength() * 0.5; + } + + // compute text start position + w *= fontSize; + switch (quadding) { + case fieldQuadLeft: + default: + x = border + 2; + break; + case fieldQuadCenter: + x = (xMax - xMin - w) / 2; + break; + case fieldQuadRight: + x = xMax - xMin - border - 2 - w; + break; + } + + // set the font matrix + if (tmPos >= 0) { + tok = (GString *)daToks->get(tmPos + 4); + tok->clear(); + tok->appendf("{0:.2f}", x); + tok = (GString *)daToks->get(tmPos + 5); + tok->clear(); + tok->appendf("{0:.2f}", y); + } + + // write the DA string + if (daToks) { + for (j = 0; j < daToks->getLength(); ++j) { + appearBuf->append((GString *)daToks->get(j))->append(' '); + } + } + + // write the font matrix (if not part of the DA string) + if (tmPos < 0) { + appearBuf->appendf("1 0 0 1 {0:.2f} {1:.2f} Tm\n", x, y); + } + + // change the text color if selected + if (selection[i]) { + appearBuf->append("1 g\n"); + } + + // write the text string + appearBuf->append('('); + for (j = 0; j < text[i]->getLength(); ++j) { + c = text[i]->getChar(j) & 0xff; + if (c == '(' || c == ')' || c == '\\') { + appearBuf->append('\\'); + appearBuf->append(c); + } else if (c < 0x20 || c >= 0x80) { + appearBuf->appendf("\\{0:03o}", c); + } else { + appearBuf->append(c); + } + } + appearBuf->append(") Tj\n"); + + // cleanup + appearBuf->append("ET\n"); + appearBuf->append("Q\n"); + + // next line + y -= 1.1 * fontSize; + } + + if (daToks) { + deleteGList(daToks, GString); + } +} + +// Figure out how much text will fit on the next line. Returns: +// *end = one past the last character to be included +// *width = width of the characters start .. end-1 +// *next = index of first character on the following line +void Annot::getNextLine(GString *text, int start, + GfxFont *font, double fontSize, double wMax, + int *end, double *width, int *next) { + double w, dw; + int j, k, c; + + // figure out how much text will fit on the line + //~ what does Adobe do with tabs? + w = 0; + for (j = start; j < text->getLength() && w <= wMax; ++j) { + c = text->getChar(j) & 0xff; + if (c == 0x0a || c == 0x0d) { + break; + } + if (font && !font->isCIDFont()) { + dw = ((Gfx8BitFont *)font)->getWidth(c) * fontSize; + } else { + // otherwise, make a crude estimate + dw = 0.5 * fontSize; + } + w += dw; + } + if (w > wMax) { + for (k = j; k > start && text->getChar(k-1) != ' '; --k) ; + for (; k > start && text->getChar(k-1) == ' '; --k) ; + if (k > start) { + j = k; + } + if (j == start) { + // handle the pathological case where the first character is + // too wide to fit on the line all by itself + j = start + 1; + } + } + *end = j; + + // compute the width + w = 0; + for (k = start; k < j; ++k) { + if (font && !font->isCIDFont()) { + dw = ((Gfx8BitFont *)font)->getWidth(text->getChar(k)) * fontSize; + } else { + // otherwise, make a crude estimate + dw = 0.5 * fontSize; + } + w += dw; + } + *width = w; + + // next line + while (j < text->getLength() && text->getChar(j) == ' ') { + ++j; + } + if (j < text->getLength() && text->getChar(j) == 0x0d) { + ++j; + } + if (j < text->getLength() && text->getChar(j) == 0x0a) { + ++j; + } + *next = j; +} + +// Draw an (approximate) circle of radius centered at (, ). +// If is true, the circle is filled; otherwise it is stroked. +void Annot::drawCircle(double cx, double cy, double r, GBool fill) { + appearBuf->appendf("{0:.2f} {1:.2f} m\n", + cx + r, cy); + appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", + cx + r, cy + bezierCircle * r, + cx + bezierCircle * r, cy + r, + cx, cy + r); + appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", + cx - bezierCircle * r, cy + r, + cx - r, cy + bezierCircle * r, + cx - r, cy); + appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", + cx - r, cy - bezierCircle * r, + cx - bezierCircle * r, cy - r, + cx, cy - r); + appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", + cx + bezierCircle * r, cy - r, + cx + r, cy - bezierCircle * r, + cx + r, cy); + appearBuf->append(fill ? "f\n" : "s\n"); +} + +// Draw the top-left half of an (approximate) circle of radius +// centered at (, ). +void Annot::drawCircleTopLeft(double cx, double cy, double r) { + double r2; + + r2 = r / sqrt(2.0); + appearBuf->appendf("{0:.2f} {1:.2f} m\n", + cx + r2, cy + r2); + appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", + cx + (1 - bezierCircle) * r2, + cy + (1 + bezierCircle) * r2, + cx - (1 - bezierCircle) * r2, + cy + (1 + bezierCircle) * r2, + cx - r2, + cy + r2); + appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", + cx - (1 + bezierCircle) * r2, + cy + (1 - bezierCircle) * r2, + cx - (1 + bezierCircle) * r2, + cy - (1 - bezierCircle) * r2, + cx - r2, + cy - r2); + appearBuf->append("S\n"); +} + +// Draw the bottom-right half of an (approximate) circle of radius +// centered at (, ). +void Annot::drawCircleBottomRight(double cx, double cy, double r) { + double r2; + + r2 = r / sqrt(2.0); + appearBuf->appendf("{0:.2f} {1:.2f} m\n", + cx - r2, cy - r2); + appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", + cx - (1 - bezierCircle) * r2, + cy - (1 + bezierCircle) * r2, + cx + (1 - bezierCircle) * r2, + cy - (1 + bezierCircle) * r2, + cx + r2, + cy - r2); + appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", + cx + (1 + bezierCircle) * r2, + cy - (1 - bezierCircle) * r2, + cx + (1 + bezierCircle) * r2, + cy + (1 - bezierCircle) * r2, + cx + r2, + cy + r2); + appearBuf->append("S\n"); +} + +// Look up an inheritable field dictionary entry. +Object *Annot::fieldLookup(Dict *field, char *key, Object *obj) { + Dict *dict; + Object parent; + + dict = field; + if (!dict->lookup(key, obj)->isNull()) { + return obj; + } + obj->free(); + if (dict->lookup("Parent", &parent)->isDict()) { + fieldLookup(parent.getDict(), key, obj); + } else { + obj->initNull(); + } + parent.free(); + return obj; +} + +void Annot::draw(Gfx *gfx, GBool printing) { + Object obj; + GBool isLink; + + // check the flags + if ((flags & annotFlagHidden) || + (printing && !(flags & annotFlagPrint)) || + (!printing && (flags & annotFlagNoView))) { + return; + } + + // draw the appearance stream + isLink = type && !type->cmp("Link"); + appearance.fetch(xref, &obj); + gfx->drawAnnot(&obj, isLink ? borderStyle : (AnnotBorderStyle *)NULL, + xMin, yMin, xMax, yMax); + obj.free(); +} + +//------------------------------------------------------------------------ +// Annots +//------------------------------------------------------------------------ + +Annots::Annots(XRef *xref, Catalog *catalog, Object *annotsObj) { + Dict *acroForm; + Annot *annot; + Object obj1; + Ref ref; + int size; + int i; + + annots = NULL; + size = 0; + nAnnots = 0; + + acroForm = catalog->getAcroForm()->isDict() ? + catalog->getAcroForm()->getDict() : NULL; + if (annotsObj->isArray()) { + for (i = 0; i < annotsObj->arrayGetLength(); ++i) { + if (annotsObj->arrayGetNF(i, &obj1)->isRef()) { + ref = obj1.getRef(); + obj1.free(); + annotsObj->arrayGet(i, &obj1); + } else { + ref.num = ref.gen = -1; + } + if (obj1.isDict()) { + annot = new Annot(xref, acroForm, obj1.getDict(), &ref); + if (annot->isOk()) { + if (nAnnots >= size) { + size += 16; + annots = (Annot **)greallocn(annots, size, sizeof(Annot *)); + } + annots[nAnnots++] = annot; + } else { + delete annot; + } + } + obj1.free(); + } + } +} + +Annots::~Annots() { + int i; + + for (i = 0; i < nAnnots; ++i) { + delete annots[i]; + } + gfree(annots); +} + +void Annots::generateAppearances(Dict *acroForm) { + Object obj1, obj2; + Ref ref; + int i; + + if (acroForm->lookup("Fields", &obj1)->isArray()) { + for (i = 0; i < obj1.arrayGetLength(); ++i) { + if (obj1.arrayGetNF(i, &obj2)->isRef()) { + ref = obj2.getRef(); + obj2.free(); + obj1.arrayGet(i, &obj2); + } else { + ref.num = ref.gen = -1; + } + if (obj2.isDict()) { + scanFieldAppearances(obj2.getDict(), &ref, NULL, acroForm); + } + obj2.free(); + } + } + obj1.free(); +} + +void Annots::scanFieldAppearances(Dict *node, Ref *ref, Dict *parent, + Dict *acroForm) { + Annot *annot; + Object obj1, obj2; + Ref ref2; + int i; + + // non-terminal node: scan the children + if (node->lookup("Kids", &obj1)->isArray()) { + for (i = 0; i < obj1.arrayGetLength(); ++i) { + if (obj1.arrayGetNF(i, &obj2)->isRef()) { + ref2 = obj2.getRef(); + obj2.free(); + obj1.arrayGet(i, &obj2); + } else { + ref2.num = ref2.gen = -1; + } + if (obj2.isDict()) { + scanFieldAppearances(obj2.getDict(), &ref2, node, acroForm); + } + obj2.free(); + } + obj1.free(); + return; + } + obj1.free(); + + // terminal node: this is either a combined annot/field dict, or an + // annot dict whose parent is a field + if ((annot = findAnnot(ref))) { + node->lookupNF("Parent", &obj1); + if (!parent || !obj1.isNull()) { + annot->generateFieldAppearance(node, node, acroForm); + } else { + annot->generateFieldAppearance(parent, node, acroForm); + } + obj1.free(); + } +} + +Annot *Annots::findAnnot(Ref *ref) { + int i; + + for (i = 0; i < nAnnots; ++i) { + if (annots[i]->match(ref)) { + return annots[i]; + } + } + return NULL; +} diff --git a/kpdf/xpdf/xpdf/Annot.h b/kpdf/xpdf/xpdf/Annot.h new file mode 100644 index 00000000..5c4de39c --- /dev/null +++ b/kpdf/xpdf/xpdf/Annot.h @@ -0,0 +1,143 @@ +//======================================================================== +// +// Annot.h +// +// Copyright 2000-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef ANNOT_H +#define ANNOT_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +class XRef; +class Catalog; +class Gfx; +class GfxFont; +class GfxFontDict; + +//------------------------------------------------------------------------ +// AnnotBorderStyle +//------------------------------------------------------------------------ + +enum AnnotBorderType { + annotBorderSolid, + annotBorderDashed, + annotBorderBeveled, + annotBorderInset, + annotBorderUnderlined +}; + +class AnnotBorderStyle { +public: + + AnnotBorderStyle(AnnotBorderType typeA, double widthA, + double *dashA, int dashLengthA, + double rA, double gA, double bA); + ~AnnotBorderStyle(); + + AnnotBorderType getType() { return type; } + double getWidth() { return width; } + void getDash(double **dashA, int *dashLengthA) + { *dashA = dash; *dashLengthA = dashLength; } + void getColor(double *rA, double *gA, double *bA) + { *rA = r; *gA = g; *bA = b; } + +private: + + AnnotBorderType type; + double width; + double *dash; + int dashLength; + double r, g, b; +}; + +//------------------------------------------------------------------------ +// Annot +//------------------------------------------------------------------------ + +class Annot { +public: + + Annot(XRef *xrefA, Dict *acroForm, Dict *dict, Ref *refA); + ~Annot(); + GBool isOk() { return ok; } + + void draw(Gfx *gfx, GBool printing); + + // Get appearance object. + Object *getAppearance(Object *obj) { return appearance.fetch(xref, obj); } + + AnnotBorderStyle *getBorderStyle() { return borderStyle; } + + GBool match(Ref *refA) + { return ref.num == refA->num && ref.gen == refA->gen; } + + void generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm); + +private: + + void setColor(Array *a, GBool fill, int adjust); + void drawText(GString *text, GString *da, GfxFontDict *fontDict, + GBool multiline, int comb, int quadding, + GBool txField, GBool forceZapfDingbats); + void drawListBox(GString **text, GBool *selection, + int nOptions, int topIdx, + GString *da, GfxFontDict *fontDict, GBool quadding); + void getNextLine(GString *text, int start, + GfxFont *font, double fontSize, double wMax, + int *end, double *width, int *next); + void drawCircle(double cx, double cy, double r, GBool fill); + void drawCircleTopLeft(double cx, double cy, double r); + void drawCircleBottomRight(double cx, double cy, double r); + Object *fieldLookup(Dict *field, char *key, Object *obj); + + XRef *xref; // the xref table for this PDF file + Ref ref; // object ref identifying this annotation + GString *type; // annotation type + Object appearance; // a reference to the Form XObject stream + // for the normal appearance + GString *appearBuf; + double xMin, yMin, // annotation rectangle + xMax, yMax; + Guint flags; + AnnotBorderStyle *borderStyle; + GBool ok; +}; + +//------------------------------------------------------------------------ +// Annots +//------------------------------------------------------------------------ + +class Annots { +public: + + // Build a list of Annot objects. + Annots(XRef *xref, Catalog *catalog, Object *annotsObj); + + ~Annots(); + + // Iterate through list of annotations. + int getNumAnnots() { return nAnnots; } + Annot *getAnnot(int i) { return annots[i]; } + + // (Re)generate the appearance streams for all annotations belonging + // to a form field. + void generateAppearances(Dict *acroForm); + +private: + + void scanFieldAppearances(Dict *node, Ref *ref, Dict *parent, + Dict *acroForm); + Annot *findAnnot(Ref *ref); + + Annot **annots; + int nAnnots; +}; + +#endif diff --git a/kpdf/xpdf/xpdf/Array.cc b/kpdf/xpdf/xpdf/Array.cc new file mode 100644 index 00000000..8232037b --- /dev/null +++ b/kpdf/xpdf/xpdf/Array.cc @@ -0,0 +1,88 @@ +//======================================================================== +// +// Array.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "Object.h" +#include "Array.h" + +//------------------------------------------------------------------------ +// Array +//------------------------------------------------------------------------ + +Array::Array(XRef *xrefA) { + xref = xrefA; + elems = NULL; + size = length = 0; + ref = 1; +} + +Array::~Array() { + int i; + + for (i = 0; i < length; ++i) + elems[i].free(); + gfree(elems); +} + +void Array::add(Object *elem) { + if (length == size) { + if (length == 0) { + size = 8; + } else { + size *= 2; + } + elems = (Object *)greallocn(elems, size, sizeof(Object)); + } + elems[length] = *elem; + ++length; +} + +Object *Array::get(int i, Object *obj) { + if (i < 0 || i >= length) { +#ifdef DEBUG_MEM + abort(); +#else + return obj->initNull(); +#endif + } + return elems[i].fetch(xref, obj); +} + +Object *Array::getNF(int i, Object *obj) { + if (i < 0 || i >= length) { +#ifdef DEBUG_MEM + abort(); +#else + return obj->initNull(); +#endif + } + return elems[i].copy(obj); +} + +GBool Array::getString(int i, GString *string) +{ + Object obj; + + if (getNF(i, &obj)->isString()) { + string->clear(); + string->append(obj.getString()); + obj.free(); + return gTrue; + } else { + obj.free(); + return gFalse; + } +} diff --git a/kpdf/xpdf/xpdf/Array.h b/kpdf/xpdf/xpdf/Array.h new file mode 100644 index 00000000..1ef65dba --- /dev/null +++ b/kpdf/xpdf/xpdf/Array.h @@ -0,0 +1,59 @@ +//======================================================================== +// +// Array.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef ARRAY_H +#define ARRAY_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "Object.h" + +class XRef; + +//------------------------------------------------------------------------ +// Array +//------------------------------------------------------------------------ + +class Array { +public: + + // Constructor. + Array(XRef *xrefA); + + // Destructor. + ~Array(); + + // Reference counting. + int incRef() { return ++ref; } + int decRef() { return --ref; } + + // Get number of elements. + int getLength() { return length; } + + // Add an element. + void add(Object *elem); + + // Accessors. + Object *get(int i, Object *obj); + Object *getNF(int i, Object *obj); + GBool getString(int i, GString *string); + +private: + + XRef *xref; // the xref table for this PDF file + Object *elems; // array of elements + int size; // size of array + int length; // number of elements in array + int ref; // reference count +}; + +#endif diff --git a/kpdf/xpdf/xpdf/BuiltinFont.cc b/kpdf/xpdf/xpdf/BuiltinFont.cc new file mode 100644 index 00000000..ce989571 --- /dev/null +++ b/kpdf/xpdf/xpdf/BuiltinFont.cc @@ -0,0 +1,65 @@ +//======================================================================== +// +// BuiltinFont.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "FontEncodingTables.h" +#include "BuiltinFont.h" + +//------------------------------------------------------------------------ + +BuiltinFontWidths::BuiltinFontWidths(BuiltinFontWidth *widths, int sizeA) { + int i, h; + + size = sizeA; + tab = (BuiltinFontWidth **)gmallocn(size, sizeof(BuiltinFontWidth *)); + for (i = 0; i < size; ++i) { + tab[i] = NULL; + } + for (i = 0; i < sizeA; ++i) { + h = hash(widths[i].name); + widths[i].next = tab[h]; + tab[h] = &widths[i]; + } +} + +BuiltinFontWidths::~BuiltinFontWidths() { + gfree(tab); +} + +GBool BuiltinFontWidths::getWidth(char *name, Gushort *width) { + int h; + BuiltinFontWidth *p; + + h = hash(name); + for (p = tab[h]; p; p = p->next) { + if (!strcmp(p->name, name)) { + *width = p->width; + return gTrue; + } + } + return gFalse; +} + +int BuiltinFontWidths::hash(char *name) { + char *p; + unsigned int h; + + h = 0; + for (p = name; *p; ++p) { + h = 17 * h + (int)(*p & 0xff); + } + return (int)(h % size); +} diff --git a/kpdf/xpdf/xpdf/BuiltinFont.h b/kpdf/xpdf/xpdf/BuiltinFont.h new file mode 100644 index 00000000..903ed19e --- /dev/null +++ b/kpdf/xpdf/xpdf/BuiltinFont.h @@ -0,0 +1,57 @@ +//======================================================================== +// +// BuiltinFont.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef BUILTINFONT_H +#define BUILTINFONT_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +struct BuiltinFont; +class BuiltinFontWidths; + +//------------------------------------------------------------------------ + +struct BuiltinFont { + char *name; + char **defaultBaseEnc; + short ascent; + short descent; + short bbox[4]; + BuiltinFontWidths *widths; +}; + +//------------------------------------------------------------------------ + +struct BuiltinFontWidth { + char *name; + Gushort width; + BuiltinFontWidth *next; +}; + +class BuiltinFontWidths { +public: + + BuiltinFontWidths(BuiltinFontWidth *widths, int sizeA); + ~BuiltinFontWidths(); + GBool getWidth(char *name, Gushort *width); + +private: + + int hash(char *name); + + BuiltinFontWidth **tab; + int size; +}; + +#endif diff --git a/kpdf/xpdf/xpdf/BuiltinFontTables.cc b/kpdf/xpdf/xpdf/BuiltinFontTables.cc new file mode 100644 index 00000000..9c362389 --- /dev/null +++ b/kpdf/xpdf/xpdf/BuiltinFontTables.cc @@ -0,0 +1,4284 @@ +//======================================================================== +// +// BuiltinFontTables.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include +#include +#include "FontEncodingTables.h" +#include "BuiltinFontTables.h" + +static BuiltinFontWidth courierWidthsTab[] = { + { "Ntilde", 600, NULL }, + { "rcaron", 600, NULL }, + { "kcommaaccent", 600, NULL }, + { "Ncommaaccent", 600, NULL }, + { "Zacute", 600, NULL }, + { "comma", 600, NULL }, + { "cedilla", 600, NULL }, + { "plusminus", 600, NULL }, + { "circumflex", 600, NULL }, + { "dotaccent", 600, NULL }, + { "edotaccent", 600, NULL }, + { "asciitilde", 600, NULL }, + { "colon", 600, NULL }, + { "onehalf", 600, NULL }, + { "dollar", 600, NULL }, + { "Lcaron", 600, NULL }, + { "ntilde", 600, NULL }, + { "Aogonek", 600, NULL }, + { "ncommaaccent", 600, NULL }, + { "minus", 600, NULL }, + { "Iogonek", 600, NULL }, + { "zacute", 600, NULL }, + { "yen", 600, NULL }, + { "space", 600, NULL }, + { "Omacron", 600, NULL }, + { "questiondown", 600, NULL }, + { "emdash", 600, NULL }, + { "Agrave", 600, NULL }, + { "three", 600, NULL }, + { "numbersign", 600, NULL }, + { "lcaron", 600, NULL }, + { "A", 600, NULL }, + { "B", 600, NULL }, + { "C", 600, NULL }, + { "aogonek", 600, NULL }, + { "D", 600, NULL }, + { "E", 600, NULL }, + { "onequarter", 600, NULL }, + { "F", 600, NULL }, + { "G", 600, NULL }, + { "H", 600, NULL }, + { "I", 600, NULL }, + { "J", 600, NULL }, + { "K", 600, NULL }, + { "iogonek", 600, NULL }, + { "L", 600, NULL }, + { "backslash", 600, NULL }, + { "periodcentered", 600, NULL }, + { "M", 600, NULL }, + { "N", 600, NULL }, + { "omacron", 600, NULL }, + { "Tcommaaccent", 600, NULL }, + { "O", 600, NULL }, + { "P", 600, NULL }, + { "Q", 600, NULL }, + { "Uhungarumlaut", 600, NULL }, + { "R", 600, NULL }, + { "Aacute", 600, NULL }, + { "caron", 600, NULL }, + { "S", 600, NULL }, + { "T", 600, NULL }, + { "U", 600, NULL }, + { "agrave", 600, NULL }, + { "V", 600, NULL }, + { "W", 600, NULL }, + { "equal", 600, NULL }, + { "question", 600, NULL }, + { "X", 600, NULL }, + { "Y", 600, NULL }, + { "Z", 600, NULL }, + { "four", 600, NULL }, + { "a", 600, NULL }, + { "Gcommaaccent", 600, NULL }, + { "b", 600, NULL }, + { "c", 600, NULL }, + { "d", 600, NULL }, + { "e", 600, NULL }, + { "f", 600, NULL }, + { "g", 600, NULL }, + { "bullet", 600, NULL }, + { "h", 600, NULL }, + { "i", 600, NULL }, + { "Oslash", 600, NULL }, + { "dagger", 600, NULL }, + { "j", 600, NULL }, + { "k", 600, NULL }, + { "l", 600, NULL }, + { "m", 600, NULL }, + { "n", 600, NULL }, + { "tcommaaccent", 600, NULL }, + { "o", 600, NULL }, + { "ordfeminine", 600, NULL }, + { "ring", 600, NULL }, + { "p", 600, NULL }, + { "q", 600, NULL }, + { "uhungarumlaut", 600, NULL }, + { "r", 600, NULL }, + { "twosuperior", 600, NULL }, + { "aacute", 600, NULL }, + { "s", 600, NULL }, + { "OE", 600, NULL }, + { "t", 600, NULL }, + { "divide", 600, NULL }, + { "u", 600, NULL }, + { "Ccaron", 600, NULL }, + { "v", 600, NULL }, + { "w", 600, NULL }, + { "x", 600, NULL }, + { "y", 600, NULL }, + { "z", 600, NULL }, + { "Gbreve", 600, NULL }, + { "commaaccent", 600, NULL }, + { "hungarumlaut", 600, NULL }, + { "Idotaccent", 600, NULL }, + { "Nacute", 600, NULL }, + { "quotedbl", 600, NULL }, + { "gcommaaccent", 600, NULL }, + { "mu", 600, NULL }, + { "greaterequal", 600, NULL }, + { "Scaron", 600, NULL }, + { "Lslash", 600, NULL }, + { "semicolon", 600, NULL }, + { "oslash", 600, NULL }, + { "lessequal", 600, NULL }, + { "lozenge", 600, NULL }, + { "parenright", 600, NULL }, + { "ccaron", 600, NULL }, + { "Ecircumflex", 600, NULL }, + { "gbreve", 600, NULL }, + { "trademark", 600, NULL }, + { "daggerdbl", 600, NULL }, + { "nacute", 600, NULL }, + { "macron", 600, NULL }, + { "Otilde", 600, NULL }, + { "Emacron", 600, NULL }, + { "ellipsis", 600, NULL }, + { "scaron", 600, NULL }, + { "AE", 600, NULL }, + { "Ucircumflex", 600, NULL }, + { "lslash", 600, NULL }, + { "quotedblleft", 600, NULL }, + { "hyphen", 600, NULL }, + { "guilsinglright", 600, NULL }, + { "quotesingle", 600, NULL }, + { "eight", 600, NULL }, + { "exclamdown", 600, NULL }, + { "endash", 600, NULL }, + { "oe", 600, NULL }, + { "Abreve", 600, NULL }, + { "Umacron", 600, NULL }, + { "ecircumflex", 600, NULL }, + { "Adieresis", 600, NULL }, + { "copyright", 600, NULL }, + { "Egrave", 600, NULL }, + { "slash", 600, NULL }, + { "Edieresis", 600, NULL }, + { "otilde", 600, NULL }, + { "Idieresis", 600, NULL }, + { "parenleft", 600, NULL }, + { "one", 600, NULL }, + { "emacron", 600, NULL }, + { "Odieresis", 600, NULL }, + { "ucircumflex", 600, NULL }, + { "bracketleft", 600, NULL }, + { "Ugrave", 600, NULL }, + { "quoteright", 600, NULL }, + { "Udieresis", 600, NULL }, + { "perthousand", 600, NULL }, + { "Ydieresis", 600, NULL }, + { "umacron", 600, NULL }, + { "abreve", 600, NULL }, + { "Eacute", 600, NULL }, + { "adieresis", 600, NULL }, + { "egrave", 600, NULL }, + { "edieresis", 600, NULL }, + { "idieresis", 600, NULL }, + { "Eth", 600, NULL }, + { "ae", 600, NULL }, + { "asterisk", 600, NULL }, + { "odieresis", 600, NULL }, + { "Uacute", 600, NULL }, + { "ugrave", 600, NULL }, + { "five", 600, NULL }, + { "nine", 600, NULL }, + { "udieresis", 600, NULL }, + { "Zcaron", 600, NULL }, + { "Scommaaccent", 600, NULL }, + { "threequarters", 600, NULL }, + { "guillemotright", 600, NULL }, + { "Ccedilla", 600, NULL }, + { "ydieresis", 600, NULL }, + { "tilde", 600, NULL }, + { "at", 600, NULL }, + { "eacute", 600, NULL }, + { "underscore", 600, NULL }, + { "Euro", 600, NULL }, + { "Dcroat", 600, NULL }, + { "zero", 600, NULL }, + { "multiply", 600, NULL }, + { "eth", 600, NULL }, + { "Scedilla", 600, NULL }, + { "Racute", 600, NULL }, + { "Ograve", 600, NULL }, + { "partialdiff", 600, NULL }, + { "uacute", 600, NULL }, + { "braceleft", 600, NULL }, + { "Thorn", 600, NULL }, + { "zcaron", 600, NULL }, + { "scommaaccent", 600, NULL }, + { "ccedilla", 600, NULL }, + { "Dcaron", 600, NULL }, + { "dcroat", 600, NULL }, + { "scedilla", 600, NULL }, + { "Oacute", 600, NULL }, + { "Ocircumflex", 600, NULL }, + { "ogonek", 600, NULL }, + { "ograve", 600, NULL }, + { "racute", 600, NULL }, + { "Tcaron", 600, NULL }, + { "Eogonek", 600, NULL }, + { "thorn", 600, NULL }, + { "degree", 600, NULL }, + { "registered", 600, NULL }, + { "radical", 600, NULL }, + { "Aring", 600, NULL }, + { "percent", 600, NULL }, + { "six", 600, NULL }, + { "paragraph", 600, NULL }, + { "dcaron", 600, NULL }, + { "Uogonek", 600, NULL }, + { "two", 600, NULL }, + { "summation", 600, NULL }, + { "Igrave", 600, NULL }, + { "Lacute", 600, NULL }, + { "ocircumflex", 600, NULL }, + { "oacute", 600, NULL }, + { "Uring", 600, NULL }, + { "Lcommaaccent", 600, NULL }, + { "tcaron", 600, NULL }, + { "eogonek", 600, NULL }, + { "Delta", 600, NULL }, + { "Ohungarumlaut", 600, NULL }, + { "asciicircum", 600, NULL }, + { "aring", 600, NULL }, + { "grave", 600, NULL }, + { "uogonek", 600, NULL }, + { "bracketright", 600, NULL }, + { "ampersand", 600, NULL }, + { "Iacute", 600, NULL }, + { "lacute", 600, NULL }, + { "igrave", 600, NULL }, + { "Ncaron", 600, NULL }, + { "plus", 600, NULL }, + { "uring", 600, NULL }, + { "quotesinglbase", 600, NULL }, + { "lcommaaccent", 600, NULL }, + { "Yacute", 600, NULL }, + { "ohungarumlaut", 600, NULL }, + { "threesuperior", 600, NULL }, + { "acute", 600, NULL }, + { "section", 600, NULL }, + { "dieresis", 600, NULL }, + { "quotedblbase", 600, NULL }, + { "iacute", 600, NULL }, + { "ncaron", 600, NULL }, + { "florin", 600, NULL }, + { "yacute", 600, NULL }, + { "Rcommaaccent", 600, NULL }, + { "fi", 600, NULL }, + { "fl", 600, NULL }, + { "Acircumflex", 600, NULL }, + { "Cacute", 600, NULL }, + { "Icircumflex", 600, NULL }, + { "guillemotleft", 600, NULL }, + { "germandbls", 600, NULL }, + { "seven", 600, NULL }, + { "Amacron", 600, NULL }, + { "Sacute", 600, NULL }, + { "ordmasculine", 600, NULL }, + { "dotlessi", 600, NULL }, + { "sterling", 600, NULL }, + { "notequal", 600, NULL }, + { "Imacron", 600, NULL }, + { "rcommaaccent", 600, NULL }, + { "Zdotaccent", 600, NULL }, + { "acircumflex", 600, NULL }, + { "cacute", 600, NULL }, + { "Ecaron", 600, NULL }, + { "braceright", 600, NULL }, + { "icircumflex", 600, NULL }, + { "quotedblright", 600, NULL }, + { "amacron", 600, NULL }, + { "sacute", 600, NULL }, + { "imacron", 600, NULL }, + { "cent", 600, NULL }, + { "currency", 600, NULL }, + { "logicalnot", 600, NULL }, + { "zdotaccent", 600, NULL }, + { "Atilde", 600, NULL }, + { "breve", 600, NULL }, + { "bar", 600, NULL }, + { "fraction", 600, NULL }, + { "less", 600, NULL }, + { "ecaron", 600, NULL }, + { "guilsinglleft", 600, NULL }, + { "exclam", 600, NULL }, + { "period", 600, NULL }, + { "Rcaron", 600, NULL }, + { "Kcommaaccent", 600, NULL }, + { "greater", 600, NULL }, + { "atilde", 600, NULL }, + { "brokenbar", 600, NULL }, + { "quoteleft", 600, NULL }, + { "Edotaccent", 600, NULL }, + { "onesuperior", 600, NULL } +}; + +static BuiltinFontWidth courierBoldWidthsTab[] = { + { "Ntilde", 600, NULL }, + { "rcaron", 600, NULL }, + { "kcommaaccent", 600, NULL }, + { "Ncommaaccent", 600, NULL }, + { "Zacute", 600, NULL }, + { "comma", 600, NULL }, + { "cedilla", 600, NULL }, + { "plusminus", 600, NULL }, + { "circumflex", 600, NULL }, + { "dotaccent", 600, NULL }, + { "edotaccent", 600, NULL }, + { "asciitilde", 600, NULL }, + { "colon", 600, NULL }, + { "onehalf", 600, NULL }, + { "dollar", 600, NULL }, + { "Lcaron", 600, NULL }, + { "ntilde", 600, NULL }, + { "Aogonek", 600, NULL }, + { "ncommaaccent", 600, NULL }, + { "minus", 600, NULL }, + { "Iogonek", 600, NULL }, + { "zacute", 600, NULL }, + { "yen", 600, NULL }, + { "space", 600, NULL }, + { "Omacron", 600, NULL }, + { "questiondown", 600, NULL }, + { "emdash", 600, NULL }, + { "Agrave", 600, NULL }, + { "three", 600, NULL }, + { "numbersign", 600, NULL }, + { "lcaron", 600, NULL }, + { "A", 600, NULL }, + { "B", 600, NULL }, + { "C", 600, NULL }, + { "aogonek", 600, NULL }, + { "D", 600, NULL }, + { "E", 600, NULL }, + { "onequarter", 600, NULL }, + { "F", 600, NULL }, + { "G", 600, NULL }, + { "H", 600, NULL }, + { "I", 600, NULL }, + { "J", 600, NULL }, + { "K", 600, NULL }, + { "iogonek", 600, NULL }, + { "backslash", 600, NULL }, + { "L", 600, NULL }, + { "periodcentered", 600, NULL }, + { "M", 600, NULL }, + { "N", 600, NULL }, + { "omacron", 600, NULL }, + { "Tcommaaccent", 600, NULL }, + { "O", 600, NULL }, + { "P", 600, NULL }, + { "Q", 600, NULL }, + { "Uhungarumlaut", 600, NULL }, + { "R", 600, NULL }, + { "Aacute", 600, NULL }, + { "caron", 600, NULL }, + { "S", 600, NULL }, + { "T", 600, NULL }, + { "U", 600, NULL }, + { "agrave", 600, NULL }, + { "V", 600, NULL }, + { "W", 600, NULL }, + { "X", 600, NULL }, + { "question", 600, NULL }, + { "equal", 600, NULL }, + { "Y", 600, NULL }, + { "Z", 600, NULL }, + { "four", 600, NULL }, + { "a", 600, NULL }, + { "Gcommaaccent", 600, NULL }, + { "b", 600, NULL }, + { "c", 600, NULL }, + { "d", 600, NULL }, + { "e", 600, NULL }, + { "f", 600, NULL }, + { "g", 600, NULL }, + { "bullet", 600, NULL }, + { "h", 600, NULL }, + { "i", 600, NULL }, + { "Oslash", 600, NULL }, + { "dagger", 600, NULL }, + { "j", 600, NULL }, + { "k", 600, NULL }, + { "l", 600, NULL }, + { "m", 600, NULL }, + { "n", 600, NULL }, + { "tcommaaccent", 600, NULL }, + { "o", 600, NULL }, + { "ordfeminine", 600, NULL }, + { "ring", 600, NULL }, + { "p", 600, NULL }, + { "q", 600, NULL }, + { "uhungarumlaut", 600, NULL }, + { "r", 600, NULL }, + { "twosuperior", 600, NULL }, + { "aacute", 600, NULL }, + { "s", 600, NULL }, + { "OE", 600, NULL }, + { "t", 600, NULL }, + { "divide", 600, NULL }, + { "u", 600, NULL }, + { "Ccaron", 600, NULL }, + { "v", 600, NULL }, + { "w", 600, NULL }, + { "x", 600, NULL }, + { "y", 600, NULL }, + { "z", 600, NULL }, + { "Gbreve", 600, NULL }, + { "commaaccent", 600, NULL }, + { "hungarumlaut", 600, NULL }, + { "Idotaccent", 600, NULL }, + { "Nacute", 600, NULL }, + { "quotedbl", 600, NULL }, + { "gcommaaccent", 600, NULL }, + { "mu", 600, NULL }, + { "greaterequal", 600, NULL }, + { "Scaron", 600, NULL }, + { "Lslash", 600, NULL }, + { "semicolon", 600, NULL }, + { "oslash", 600, NULL }, + { "lessequal", 600, NULL }, + { "lozenge", 600, NULL }, + { "parenright", 600, NULL }, + { "ccaron", 600, NULL }, + { "Ecircumflex", 600, NULL }, + { "gbreve", 600, NULL }, + { "trademark", 600, NULL }, + { "daggerdbl", 600, NULL }, + { "nacute", 600, NULL }, + { "macron", 600, NULL }, + { "Otilde", 600, NULL }, + { "Emacron", 600, NULL }, + { "ellipsis", 600, NULL }, + { "scaron", 600, NULL }, + { "AE", 600, NULL }, + { "Ucircumflex", 600, NULL }, + { "lslash", 600, NULL }, + { "quotedblleft", 600, NULL }, + { "guilsinglright", 600, NULL }, + { "hyphen", 600, NULL }, + { "quotesingle", 600, NULL }, + { "eight", 600, NULL }, + { "exclamdown", 600, NULL }, + { "endash", 600, NULL }, + { "oe", 600, NULL }, + { "Abreve", 600, NULL }, + { "Umacron", 600, NULL }, + { "ecircumflex", 600, NULL }, + { "Adieresis", 600, NULL }, + { "copyright", 600, NULL }, + { "Egrave", 600, NULL }, + { "slash", 600, NULL }, + { "Edieresis", 600, NULL }, + { "otilde", 600, NULL }, + { "Idieresis", 600, NULL }, + { "parenleft", 600, NULL }, + { "one", 600, NULL }, + { "emacron", 600, NULL }, + { "Odieresis", 600, NULL }, + { "ucircumflex", 600, NULL }, + { "bracketleft", 600, NULL }, + { "Ugrave", 600, NULL }, + { "quoteright", 600, NULL }, + { "Udieresis", 600, NULL }, + { "perthousand", 600, NULL }, + { "Ydieresis", 600, NULL }, + { "umacron", 600, NULL }, + { "abreve", 600, NULL }, + { "Eacute", 600, NULL }, + { "adieresis", 600, NULL }, + { "egrave", 600, NULL }, + { "edieresis", 600, NULL }, + { "idieresis", 600, NULL }, + { "Eth", 600, NULL }, + { "ae", 600, NULL }, + { "asterisk", 600, NULL }, + { "odieresis", 600, NULL }, + { "Uacute", 600, NULL }, + { "ugrave", 600, NULL }, + { "nine", 600, NULL }, + { "five", 600, NULL }, + { "udieresis", 600, NULL }, + { "Zcaron", 600, NULL }, + { "Scommaaccent", 600, NULL }, + { "threequarters", 600, NULL }, + { "guillemotright", 600, NULL }, + { "Ccedilla", 600, NULL }, + { "ydieresis", 600, NULL }, + { "tilde", 600, NULL }, + { "at", 600, NULL }, + { "eacute", 600, NULL }, + { "underscore", 600, NULL }, + { "Euro", 600, NULL }, + { "Dcroat", 600, NULL }, + { "multiply", 600, NULL }, + { "zero", 600, NULL }, + { "eth", 600, NULL }, + { "Scedilla", 600, NULL }, + { "Ograve", 600, NULL }, + { "Racute", 600, NULL }, + { "partialdiff", 600, NULL }, + { "uacute", 600, NULL }, + { "braceleft", 600, NULL }, + { "Thorn", 600, NULL }, + { "zcaron", 600, NULL }, + { "scommaaccent", 600, NULL }, + { "ccedilla", 600, NULL }, + { "Dcaron", 600, NULL }, + { "dcroat", 600, NULL }, + { "Ocircumflex", 600, NULL }, + { "Oacute", 600, NULL }, + { "scedilla", 600, NULL }, + { "ogonek", 600, NULL }, + { "ograve", 600, NULL }, + { "racute", 600, NULL }, + { "Tcaron", 600, NULL }, + { "Eogonek", 600, NULL }, + { "thorn", 600, NULL }, + { "degree", 600, NULL }, + { "registered", 600, NULL }, + { "radical", 600, NULL }, + { "Aring", 600, NULL }, + { "percent", 600, NULL }, + { "six", 600, NULL }, + { "paragraph", 600, NULL }, + { "dcaron", 600, NULL }, + { "Uogonek", 600, NULL }, + { "two", 600, NULL }, + { "summation", 600, NULL }, + { "Igrave", 600, NULL }, + { "Lacute", 600, NULL }, + { "ocircumflex", 600, NULL }, + { "oacute", 600, NULL }, + { "Uring", 600, NULL }, + { "Lcommaaccent", 600, NULL }, + { "tcaron", 600, NULL }, + { "eogonek", 600, NULL }, + { "Delta", 600, NULL }, + { "Ohungarumlaut", 600, NULL }, + { "asciicircum", 600, NULL }, + { "aring", 600, NULL }, + { "grave", 600, NULL }, + { "uogonek", 600, NULL }, + { "bracketright", 600, NULL }, + { "Iacute", 600, NULL }, + { "ampersand", 600, NULL }, + { "igrave", 600, NULL }, + { "lacute", 600, NULL }, + { "Ncaron", 600, NULL }, + { "plus", 600, NULL }, + { "uring", 600, NULL }, + { "quotesinglbase", 600, NULL }, + { "lcommaaccent", 600, NULL }, + { "Yacute", 600, NULL }, + { "ohungarumlaut", 600, NULL }, + { "threesuperior", 600, NULL }, + { "acute", 600, NULL }, + { "section", 600, NULL }, + { "dieresis", 600, NULL }, + { "iacute", 600, NULL }, + { "quotedblbase", 600, NULL }, + { "ncaron", 600, NULL }, + { "florin", 600, NULL }, + { "yacute", 600, NULL }, + { "Rcommaaccent", 600, NULL }, + { "fi", 600, NULL }, + { "fl", 600, NULL }, + { "Acircumflex", 600, NULL }, + { "Cacute", 600, NULL }, + { "Icircumflex", 600, NULL }, + { "guillemotleft", 600, NULL }, + { "germandbls", 600, NULL }, + { "Amacron", 600, NULL }, + { "seven", 600, NULL }, + { "Sacute", 600, NULL }, + { "ordmasculine", 600, NULL }, + { "dotlessi", 600, NULL }, + { "sterling", 600, NULL }, + { "notequal", 600, NULL }, + { "Imacron", 600, NULL }, + { "rcommaaccent", 600, NULL }, + { "Zdotaccent", 600, NULL }, + { "acircumflex", 600, NULL }, + { "cacute", 600, NULL }, + { "Ecaron", 600, NULL }, + { "icircumflex", 600, NULL }, + { "braceright", 600, NULL }, + { "quotedblright", 600, NULL }, + { "amacron", 600, NULL }, + { "sacute", 600, NULL }, + { "imacron", 600, NULL }, + { "cent", 600, NULL }, + { "currency", 600, NULL }, + { "logicalnot", 600, NULL }, + { "zdotaccent", 600, NULL }, + { "Atilde", 600, NULL }, + { "breve", 600, NULL }, + { "bar", 600, NULL }, + { "fraction", 600, NULL }, + { "less", 600, NULL }, + { "ecaron", 600, NULL }, + { "guilsinglleft", 600, NULL }, + { "exclam", 600, NULL }, + { "period", 600, NULL }, + { "Rcaron", 600, NULL }, + { "Kcommaaccent", 600, NULL }, + { "greater", 600, NULL }, + { "atilde", 600, NULL }, + { "brokenbar", 600, NULL }, + { "quoteleft", 600, NULL }, + { "Edotaccent", 600, NULL }, + { "onesuperior", 600, NULL } +}; + +static BuiltinFontWidth courierBoldObliqueWidthsTab[] = { + { "Ntilde", 600, NULL }, + { "rcaron", 600, NULL }, + { "kcommaaccent", 600, NULL }, + { "Ncommaaccent", 600, NULL }, + { "Zacute", 600, NULL }, + { "comma", 600, NULL }, + { "cedilla", 600, NULL }, + { "plusminus", 600, NULL }, + { "circumflex", 600, NULL }, + { "dotaccent", 600, NULL }, + { "edotaccent", 600, NULL }, + { "asciitilde", 600, NULL }, + { "colon", 600, NULL }, + { "onehalf", 600, NULL }, + { "dollar", 600, NULL }, + { "Lcaron", 600, NULL }, + { "ntilde", 600, NULL }, + { "Aogonek", 600, NULL }, + { "ncommaaccent", 600, NULL }, + { "minus", 600, NULL }, + { "Iogonek", 600, NULL }, + { "zacute", 600, NULL }, + { "yen", 600, NULL }, + { "space", 600, NULL }, + { "Omacron", 600, NULL }, + { "questiondown", 600, NULL }, + { "emdash", 600, NULL }, + { "Agrave", 600, NULL }, + { "three", 600, NULL }, + { "numbersign", 600, NULL }, + { "lcaron", 600, NULL }, + { "A", 600, NULL }, + { "B", 600, NULL }, + { "C", 600, NULL }, + { "aogonek", 600, NULL }, + { "D", 600, NULL }, + { "E", 600, NULL }, + { "onequarter", 600, NULL }, + { "F", 600, NULL }, + { "G", 600, NULL }, + { "H", 600, NULL }, + { "I", 600, NULL }, + { "J", 600, NULL }, + { "K", 600, NULL }, + { "iogonek", 600, NULL }, + { "backslash", 600, NULL }, + { "L", 600, NULL }, + { "periodcentered", 600, NULL }, + { "M", 600, NULL }, + { "N", 600, NULL }, + { "omacron", 600, NULL }, + { "Tcommaaccent", 600, NULL }, + { "O", 600, NULL }, + { "P", 600, NULL }, + { "Q", 600, NULL }, + { "Uhungarumlaut", 600, NULL }, + { "R", 600, NULL }, + { "Aacute", 600, NULL }, + { "caron", 600, NULL }, + { "S", 600, NULL }, + { "T", 600, NULL }, + { "U", 600, NULL }, + { "agrave", 600, NULL }, + { "V", 600, NULL }, + { "W", 600, NULL }, + { "X", 600, NULL }, + { "question", 600, NULL }, + { "equal", 600, NULL }, + { "Y", 600, NULL }, + { "Z", 600, NULL }, + { "four", 600, NULL }, + { "a", 600, NULL }, + { "Gcommaaccent", 600, NULL }, + { "b", 600, NULL }, + { "c", 600, NULL }, + { "d", 600, NULL }, + { "e", 600, NULL }, + { "f", 600, NULL }, + { "g", 600, NULL }, + { "bullet", 600, NULL }, + { "h", 600, NULL }, + { "i", 600, NULL }, + { "Oslash", 600, NULL }, + { "dagger", 600, NULL }, + { "j", 600, NULL }, + { "k", 600, NULL }, + { "l", 600, NULL }, + { "m", 600, NULL }, + { "n", 600, NULL }, + { "tcommaaccent", 600, NULL }, + { "o", 600, NULL }, + { "ordfeminine", 600, NULL }, + { "ring", 600, NULL }, + { "p", 600, NULL }, + { "q", 600, NULL }, + { "uhungarumlaut", 600, NULL }, + { "r", 600, NULL }, + { "twosuperior", 600, NULL }, + { "aacute", 600, NULL }, + { "s", 600, NULL }, + { "OE", 600, NULL }, + { "t", 600, NULL }, + { "divide", 600, NULL }, + { "u", 600, NULL }, + { "Ccaron", 600, NULL }, + { "v", 600, NULL }, + { "w", 600, NULL }, + { "x", 600, NULL }, + { "y", 600, NULL }, + { "z", 600, NULL }, + { "Gbreve", 600, NULL }, + { "commaaccent", 600, NULL }, + { "hungarumlaut", 600, NULL }, + { "Idotaccent", 600, NULL }, + { "Nacute", 600, NULL }, + { "quotedbl", 600, NULL }, + { "gcommaaccent", 600, NULL }, + { "mu", 600, NULL }, + { "greaterequal", 600, NULL }, + { "Scaron", 600, NULL }, + { "Lslash", 600, NULL }, + { "semicolon", 600, NULL }, + { "oslash", 600, NULL }, + { "lessequal", 600, NULL }, + { "lozenge", 600, NULL }, + { "parenright", 600, NULL }, + { "ccaron", 600, NULL }, + { "Ecircumflex", 600, NULL }, + { "gbreve", 600, NULL }, + { "trademark", 600, NULL }, + { "daggerdbl", 600, NULL }, + { "nacute", 600, NULL }, + { "macron", 600, NULL }, + { "Otilde", 600, NULL }, + { "Emacron", 600, NULL }, + { "ellipsis", 600, NULL }, + { "scaron", 600, NULL }, + { "AE", 600, NULL }, + { "Ucircumflex", 600, NULL }, + { "lslash", 600, NULL }, + { "quotedblleft", 600, NULL }, + { "guilsinglright", 600, NULL }, + { "hyphen", 600, NULL }, + { "quotesingle", 600, NULL }, + { "eight", 600, NULL }, + { "exclamdown", 600, NULL }, + { "endash", 600, NULL }, + { "oe", 600, NULL }, + { "Abreve", 600, NULL }, + { "Umacron", 600, NULL }, + { "ecircumflex", 600, NULL }, + { "Adieresis", 600, NULL }, + { "copyright", 600, NULL }, + { "Egrave", 600, NULL }, + { "slash", 600, NULL }, + { "Edieresis", 600, NULL }, + { "otilde", 600, NULL }, + { "Idieresis", 600, NULL }, + { "parenleft", 600, NULL }, + { "one", 600, NULL }, + { "emacron", 600, NULL }, + { "Odieresis", 600, NULL }, + { "ucircumflex", 600, NULL }, + { "bracketleft", 600, NULL }, + { "Ugrave", 600, NULL }, + { "quoteright", 600, NULL }, + { "Udieresis", 600, NULL }, + { "perthousand", 600, NULL }, + { "Ydieresis", 600, NULL }, + { "umacron", 600, NULL }, + { "abreve", 600, NULL }, + { "Eacute", 600, NULL }, + { "adieresis", 600, NULL }, + { "egrave", 600, NULL }, + { "edieresis", 600, NULL }, + { "idieresis", 600, NULL }, + { "Eth", 600, NULL }, + { "ae", 600, NULL }, + { "asterisk", 600, NULL }, + { "odieresis", 600, NULL }, + { "Uacute", 600, NULL }, + { "ugrave", 600, NULL }, + { "nine", 600, NULL }, + { "five", 600, NULL }, + { "udieresis", 600, NULL }, + { "Zcaron", 600, NULL }, + { "Scommaaccent", 600, NULL }, + { "threequarters", 600, NULL }, + { "guillemotright", 600, NULL }, + { "Ccedilla", 600, NULL }, + { "ydieresis", 600, NULL }, + { "tilde", 600, NULL }, + { "at", 600, NULL }, + { "eacute", 600, NULL }, + { "underscore", 600, NULL }, + { "Euro", 600, NULL }, + { "Dcroat", 600, NULL }, + { "multiply", 600, NULL }, + { "zero", 600, NULL }, + { "eth", 600, NULL }, + { "Scedilla", 600, NULL }, + { "Ograve", 600, NULL }, + { "Racute", 600, NULL }, + { "partialdiff", 600, NULL }, + { "uacute", 600, NULL }, + { "braceleft", 600, NULL }, + { "Thorn", 600, NULL }, + { "zcaron", 600, NULL }, + { "scommaaccent", 600, NULL }, + { "ccedilla", 600, NULL }, + { "Dcaron", 600, NULL }, + { "dcroat", 600, NULL }, + { "Ocircumflex", 600, NULL }, + { "Oacute", 600, NULL }, + { "scedilla", 600, NULL }, + { "ogonek", 600, NULL }, + { "ograve", 600, NULL }, + { "racute", 600, NULL }, + { "Tcaron", 600, NULL }, + { "Eogonek", 600, NULL }, + { "thorn", 600, NULL }, + { "degree", 600, NULL }, + { "registered", 600, NULL }, + { "radical", 600, NULL }, + { "Aring", 600, NULL }, + { "percent", 600, NULL }, + { "six", 600, NULL }, + { "paragraph", 600, NULL }, + { "dcaron", 600, NULL }, + { "Uogonek", 600, NULL }, + { "two", 600, NULL }, + { "summation", 600, NULL }, + { "Igrave", 600, NULL }, + { "Lacute", 600, NULL }, + { "ocircumflex", 600, NULL }, + { "oacute", 600, NULL }, + { "Uring", 600, NULL }, + { "Lcommaaccent", 600, NULL }, + { "tcaron", 600, NULL }, + { "eogonek", 600, NULL }, + { "Delta", 600, NULL }, + { "Ohungarumlaut", 600, NULL }, + { "asciicircum", 600, NULL }, + { "aring", 600, NULL }, + { "grave", 600, NULL }, + { "uogonek", 600, NULL }, + { "bracketright", 600, NULL }, + { "Iacute", 600, NULL }, + { "ampersand", 600, NULL }, + { "igrave", 600, NULL }, + { "lacute", 600, NULL }, + { "Ncaron", 600, NULL }, + { "plus", 600, NULL }, + { "uring", 600, NULL }, + { "quotesinglbase", 600, NULL }, + { "lcommaaccent", 600, NULL }, + { "Yacute", 600, NULL }, + { "ohungarumlaut", 600, NULL }, + { "threesuperior", 600, NULL }, + { "acute", 600, NULL }, + { "section", 600, NULL }, + { "dieresis", 600, NULL }, + { "iacute", 600, NULL }, + { "quotedblbase", 600, NULL }, + { "ncaron", 600, NULL }, + { "florin", 600, NULL }, + { "yacute", 600, NULL }, + { "Rcommaaccent", 600, NULL }, + { "fi", 600, NULL }, + { "fl", 600, NULL }, + { "Acircumflex", 600, NULL }, + { "Cacute", 600, NULL }, + { "Icircumflex", 600, NULL }, + { "guillemotleft", 600, NULL }, + { "germandbls", 600, NULL }, + { "Amacron", 600, NULL }, + { "seven", 600, NULL }, + { "Sacute", 600, NULL }, + { "ordmasculine", 600, NULL }, + { "dotlessi", 600, NULL }, + { "sterling", 600, NULL }, + { "notequal", 600, NULL }, + { "Imacron", 600, NULL }, + { "rcommaaccent", 600, NULL }, + { "Zdotaccent", 600, NULL }, + { "acircumflex", 600, NULL }, + { "cacute", 600, NULL }, + { "Ecaron", 600, NULL }, + { "icircumflex", 600, NULL }, + { "braceright", 600, NULL }, + { "quotedblright", 600, NULL }, + { "amacron", 600, NULL }, + { "sacute", 600, NULL }, + { "imacron", 600, NULL }, + { "cent", 600, NULL }, + { "currency", 600, NULL }, + { "logicalnot", 600, NULL }, + { "zdotaccent", 600, NULL }, + { "Atilde", 600, NULL }, + { "breve", 600, NULL }, + { "bar", 600, NULL }, + { "fraction", 600, NULL }, + { "less", 600, NULL }, + { "ecaron", 600, NULL }, + { "guilsinglleft", 600, NULL }, + { "exclam", 600, NULL }, + { "period", 600, NULL }, + { "Rcaron", 600, NULL }, + { "Kcommaaccent", 600, NULL }, + { "greater", 600, NULL }, + { "atilde", 600, NULL }, + { "brokenbar", 600, NULL }, + { "quoteleft", 600, NULL }, + { "Edotaccent", 600, NULL }, + { "onesuperior", 600, NULL } +}; + +static BuiltinFontWidth courierObliqueWidthsTab[] = { + { "Ntilde", 600, NULL }, + { "rcaron", 600, NULL }, + { "kcommaaccent", 600, NULL }, + { "Ncommaaccent", 600, NULL }, + { "Zacute", 600, NULL }, + { "comma", 600, NULL }, + { "cedilla", 600, NULL }, + { "plusminus", 600, NULL }, + { "circumflex", 600, NULL }, + { "dotaccent", 600, NULL }, + { "edotaccent", 600, NULL }, + { "asciitilde", 600, NULL }, + { "colon", 600, NULL }, + { "onehalf", 600, NULL }, + { "dollar", 600, NULL }, + { "Lcaron", 600, NULL }, + { "ntilde", 600, NULL }, + { "Aogonek", 600, NULL }, + { "ncommaaccent", 600, NULL }, + { "minus", 600, NULL }, + { "Iogonek", 600, NULL }, + { "zacute", 600, NULL }, + { "yen", 600, NULL }, + { "space", 600, NULL }, + { "Omacron", 600, NULL }, + { "questiondown", 600, NULL }, + { "emdash", 600, NULL }, + { "Agrave", 600, NULL }, + { "three", 600, NULL }, + { "numbersign", 600, NULL }, + { "lcaron", 600, NULL }, + { "A", 600, NULL }, + { "B", 600, NULL }, + { "C", 600, NULL }, + { "aogonek", 600, NULL }, + { "D", 600, NULL }, + { "E", 600, NULL }, + { "onequarter", 600, NULL }, + { "F", 600, NULL }, + { "G", 600, NULL }, + { "H", 600, NULL }, + { "I", 600, NULL }, + { "J", 600, NULL }, + { "K", 600, NULL }, + { "iogonek", 600, NULL }, + { "backslash", 600, NULL }, + { "L", 600, NULL }, + { "periodcentered", 600, NULL }, + { "M", 600, NULL }, + { "N", 600, NULL }, + { "omacron", 600, NULL }, + { "Tcommaaccent", 600, NULL }, + { "O", 600, NULL }, + { "P", 600, NULL }, + { "Q", 600, NULL }, + { "Uhungarumlaut", 600, NULL }, + { "R", 600, NULL }, + { "Aacute", 600, NULL }, + { "caron", 600, NULL }, + { "S", 600, NULL }, + { "T", 600, NULL }, + { "U", 600, NULL }, + { "agrave", 600, NULL }, + { "V", 600, NULL }, + { "W", 600, NULL }, + { "X", 600, NULL }, + { "question", 600, NULL }, + { "equal", 600, NULL }, + { "Y", 600, NULL }, + { "Z", 600, NULL }, + { "four", 600, NULL }, + { "a", 600, NULL }, + { "Gcommaaccent", 600, NULL }, + { "b", 600, NULL }, + { "c", 600, NULL }, + { "d", 600, NULL }, + { "e", 600, NULL }, + { "f", 600, NULL }, + { "g", 600, NULL }, + { "bullet", 600, NULL }, + { "h", 600, NULL }, + { "i", 600, NULL }, + { "Oslash", 600, NULL }, + { "dagger", 600, NULL }, + { "j", 600, NULL }, + { "k", 600, NULL }, + { "l", 600, NULL }, + { "m", 600, NULL }, + { "n", 600, NULL }, + { "tcommaaccent", 600, NULL }, + { "o", 600, NULL }, + { "ordfeminine", 600, NULL }, + { "ring", 600, NULL }, + { "p", 600, NULL }, + { "q", 600, NULL }, + { "uhungarumlaut", 600, NULL }, + { "r", 600, NULL }, + { "twosuperior", 600, NULL }, + { "aacute", 600, NULL }, + { "s", 600, NULL }, + { "OE", 600, NULL }, + { "t", 600, NULL }, + { "divide", 600, NULL }, + { "u", 600, NULL }, + { "Ccaron", 600, NULL }, + { "v", 600, NULL }, + { "w", 600, NULL }, + { "x", 600, NULL }, + { "y", 600, NULL }, + { "z", 600, NULL }, + { "Gbreve", 600, NULL }, + { "commaaccent", 600, NULL }, + { "hungarumlaut", 600, NULL }, + { "Idotaccent", 600, NULL }, + { "Nacute", 600, NULL }, + { "quotedbl", 600, NULL }, + { "gcommaaccent", 600, NULL }, + { "mu", 600, NULL }, + { "greaterequal", 600, NULL }, + { "Scaron", 600, NULL }, + { "Lslash", 600, NULL }, + { "semicolon", 600, NULL }, + { "oslash", 600, NULL }, + { "lessequal", 600, NULL }, + { "lozenge", 600, NULL }, + { "parenright", 600, NULL }, + { "ccaron", 600, NULL }, + { "Ecircumflex", 600, NULL }, + { "gbreve", 600, NULL }, + { "trademark", 600, NULL }, + { "daggerdbl", 600, NULL }, + { "nacute", 600, NULL }, + { "macron", 600, NULL }, + { "Otilde", 600, NULL }, + { "Emacron", 600, NULL }, + { "ellipsis", 600, NULL }, + { "scaron", 600, NULL }, + { "AE", 600, NULL }, + { "Ucircumflex", 600, NULL }, + { "lslash", 600, NULL }, + { "quotedblleft", 600, NULL }, + { "guilsinglright", 600, NULL }, + { "hyphen", 600, NULL }, + { "quotesingle", 600, NULL }, + { "eight", 600, NULL }, + { "exclamdown", 600, NULL }, + { "endash", 600, NULL }, + { "oe", 600, NULL }, + { "Abreve", 600, NULL }, + { "Umacron", 600, NULL }, + { "ecircumflex", 600, NULL }, + { "Adieresis", 600, NULL }, + { "copyright", 600, NULL }, + { "Egrave", 600, NULL }, + { "slash", 600, NULL }, + { "Edieresis", 600, NULL }, + { "otilde", 600, NULL }, + { "Idieresis", 600, NULL }, + { "parenleft", 600, NULL }, + { "one", 600, NULL }, + { "emacron", 600, NULL }, + { "Odieresis", 600, NULL }, + { "ucircumflex", 600, NULL }, + { "bracketleft", 600, NULL }, + { "Ugrave", 600, NULL }, + { "quoteright", 600, NULL }, + { "Udieresis", 600, NULL }, + { "perthousand", 600, NULL }, + { "Ydieresis", 600, NULL }, + { "umacron", 600, NULL }, + { "abreve", 600, NULL }, + { "Eacute", 600, NULL }, + { "adieresis", 600, NULL }, + { "egrave", 600, NULL }, + { "edieresis", 600, NULL }, + { "idieresis", 600, NULL }, + { "Eth", 600, NULL }, + { "ae", 600, NULL }, + { "asterisk", 600, NULL }, + { "odieresis", 600, NULL }, + { "Uacute", 600, NULL }, + { "ugrave", 600, NULL }, + { "nine", 600, NULL }, + { "five", 600, NULL }, + { "udieresis", 600, NULL }, + { "Zcaron", 600, NULL }, + { "Scommaaccent", 600, NULL }, + { "threequarters", 600, NULL }, + { "guillemotright", 600, NULL }, + { "Ccedilla", 600, NULL }, + { "ydieresis", 600, NULL }, + { "tilde", 600, NULL }, + { "at", 600, NULL }, + { "eacute", 600, NULL }, + { "underscore", 600, NULL }, + { "Euro", 600, NULL }, + { "Dcroat", 600, NULL }, + { "multiply", 600, NULL }, + { "zero", 600, NULL }, + { "eth", 600, NULL }, + { "Scedilla", 600, NULL }, + { "Ograve", 600, NULL }, + { "Racute", 600, NULL }, + { "partialdiff", 600, NULL }, + { "uacute", 600, NULL }, + { "braceleft", 600, NULL }, + { "Thorn", 600, NULL }, + { "zcaron", 600, NULL }, + { "scommaaccent", 600, NULL }, + { "ccedilla", 600, NULL }, + { "Dcaron", 600, NULL }, + { "dcroat", 600, NULL }, + { "Ocircumflex", 600, NULL }, + { "Oacute", 600, NULL }, + { "scedilla", 600, NULL }, + { "ogonek", 600, NULL }, + { "ograve", 600, NULL }, + { "racute", 600, NULL }, + { "Tcaron", 600, NULL }, + { "Eogonek", 600, NULL }, + { "thorn", 600, NULL }, + { "degree", 600, NULL }, + { "registered", 600, NULL }, + { "radical", 600, NULL }, + { "Aring", 600, NULL }, + { "percent", 600, NULL }, + { "six", 600, NULL }, + { "paragraph", 600, NULL }, + { "dcaron", 600, NULL }, + { "Uogonek", 600, NULL }, + { "two", 600, NULL }, + { "summation", 600, NULL }, + { "Igrave", 600, NULL }, + { "Lacute", 600, NULL }, + { "ocircumflex", 600, NULL }, + { "oacute", 600, NULL }, + { "Uring", 600, NULL }, + { "Lcommaaccent", 600, NULL }, + { "tcaron", 600, NULL }, + { "eogonek", 600, NULL }, + { "Delta", 600, NULL }, + { "Ohungarumlaut", 600, NULL }, + { "asciicircum", 600, NULL }, + { "aring", 600, NULL }, + { "grave", 600, NULL }, + { "uogonek", 600, NULL }, + { "bracketright", 600, NULL }, + { "Iacute", 600, NULL }, + { "ampersand", 600, NULL }, + { "igrave", 600, NULL }, + { "lacute", 600, NULL }, + { "Ncaron", 600, NULL }, + { "plus", 600, NULL }, + { "uring", 600, NULL }, + { "quotesinglbase", 600, NULL }, + { "lcommaaccent", 600, NULL }, + { "Yacute", 600, NULL }, + { "ohungarumlaut", 600, NULL }, + { "threesuperior", 600, NULL }, + { "acute", 600, NULL }, + { "section", 600, NULL }, + { "dieresis", 600, NULL }, + { "iacute", 600, NULL }, + { "quotedblbase", 600, NULL }, + { "ncaron", 600, NULL }, + { "florin", 600, NULL }, + { "yacute", 600, NULL }, + { "Rcommaaccent", 600, NULL }, + { "fi", 600, NULL }, + { "fl", 600, NULL }, + { "Acircumflex", 600, NULL }, + { "Cacute", 600, NULL }, + { "Icircumflex", 600, NULL }, + { "guillemotleft", 600, NULL }, + { "germandbls", 600, NULL }, + { "Amacron", 600, NULL }, + { "seven", 600, NULL }, + { "Sacute", 600, NULL }, + { "ordmasculine", 600, NULL }, + { "dotlessi", 600, NULL }, + { "sterling", 600, NULL }, + { "notequal", 600, NULL }, + { "Imacron", 600, NULL }, + { "rcommaaccent", 600, NULL }, + { "Zdotaccent", 600, NULL }, + { "acircumflex", 600, NULL }, + { "cacute", 600, NULL }, + { "Ecaron", 600, NULL }, + { "icircumflex", 600, NULL }, + { "braceright", 600, NULL }, + { "quotedblright", 600, NULL }, + { "amacron", 600, NULL }, + { "sacute", 600, NULL }, + { "imacron", 600, NULL }, + { "cent", 600, NULL }, + { "currency", 600, NULL }, + { "logicalnot", 600, NULL }, + { "zdotaccent", 600, NULL }, + { "Atilde", 600, NULL }, + { "breve", 600, NULL }, + { "bar", 600, NULL }, + { "fraction", 600, NULL }, + { "less", 600, NULL }, + { "ecaron", 600, NULL }, + { "guilsinglleft", 600, NULL }, + { "exclam", 600, NULL }, + { "period", 600, NULL }, + { "Rcaron", 600, NULL }, + { "Kcommaaccent", 600, NULL }, + { "greater", 600, NULL }, + { "atilde", 600, NULL }, + { "brokenbar", 600, NULL }, + { "quoteleft", 600, NULL }, + { "Edotaccent", 600, NULL }, + { "onesuperior", 600, NULL } +}; + +static BuiltinFontWidth helveticaWidthsTab[] = { + { "Ntilde", 722, NULL }, + { "rcaron", 333, NULL }, + { "kcommaaccent", 500, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 611, NULL }, + { "comma", 278, NULL }, + { "cedilla", 333, NULL }, + { "plusminus", 584, NULL }, + { "circumflex", 333, NULL }, + { "dotaccent", 333, NULL }, + { "edotaccent", 556, NULL }, + { "asciitilde", 584, NULL }, + { "colon", 278, NULL }, + { "onehalf", 834, NULL }, + { "dollar", 556, NULL }, + { "Lcaron", 556, NULL }, + { "ntilde", 556, NULL }, + { "Aogonek", 667, NULL }, + { "ncommaaccent", 556, NULL }, + { "minus", 584, NULL }, + { "Iogonek", 278, NULL }, + { "zacute", 500, NULL }, + { "yen", 556, NULL }, + { "space", 278, NULL }, + { "Omacron", 778, NULL }, + { "questiondown", 611, NULL }, + { "emdash", 1000, NULL }, + { "Agrave", 667, NULL }, + { "three", 556, NULL }, + { "numbersign", 556, NULL }, + { "lcaron", 299, NULL }, + { "A", 667, NULL }, + { "B", 667, NULL }, + { "C", 722, NULL }, + { "aogonek", 556, NULL }, + { "D", 722, NULL }, + { "E", 667, NULL }, + { "onequarter", 834, NULL }, + { "F", 611, NULL }, + { "G", 778, NULL }, + { "H", 722, NULL }, + { "I", 278, NULL }, + { "J", 500, NULL }, + { "K", 667, NULL }, + { "iogonek", 222, NULL }, + { "backslash", 278, NULL }, + { "L", 556, NULL }, + { "periodcentered", 278, NULL }, + { "M", 833, NULL }, + { "N", 722, NULL }, + { "omacron", 556, NULL }, + { "Tcommaaccent", 611, NULL }, + { "O", 778, NULL }, + { "P", 667, NULL }, + { "Q", 778, NULL }, + { "Uhungarumlaut", 722, NULL }, + { "R", 722, NULL }, + { "Aacute", 667, NULL }, + { "caron", 333, NULL }, + { "S", 667, NULL }, + { "T", 611, NULL }, + { "U", 722, NULL }, + { "agrave", 556, NULL }, + { "V", 667, NULL }, + { "W", 944, NULL }, + { "X", 667, NULL }, + { "question", 556, NULL }, + { "equal", 584, NULL }, + { "Y", 667, NULL }, + { "Z", 611, NULL }, + { "four", 556, NULL }, + { "a", 556, NULL }, + { "Gcommaaccent", 778, NULL }, + { "b", 556, NULL }, + { "c", 500, NULL }, + { "d", 556, NULL }, + { "e", 556, NULL }, + { "f", 278, NULL }, + { "g", 556, NULL }, + { "bullet", 350, NULL }, + { "h", 556, NULL }, + { "i", 222, NULL }, + { "Oslash", 778, NULL }, + { "dagger", 556, NULL }, + { "j", 222, NULL }, + { "k", 500, NULL }, + { "l", 222, NULL }, + { "m", 833, NULL }, + { "n", 556, NULL }, + { "tcommaaccent", 278, NULL }, + { "o", 556, NULL }, + { "ordfeminine", 370, NULL }, + { "ring", 333, NULL }, + { "p", 556, NULL }, + { "q", 556, NULL }, + { "uhungarumlaut", 556, NULL }, + { "r", 333, NULL }, + { "twosuperior", 333, NULL }, + { "aacute", 556, NULL }, + { "s", 500, NULL }, + { "OE", 1000, NULL }, + { "t", 278, NULL }, + { "divide", 584, NULL }, + { "u", 556, NULL }, + { "Ccaron", 722, NULL }, + { "v", 500, NULL }, + { "w", 722, NULL }, + { "x", 500, NULL }, + { "y", 500, NULL }, + { "z", 500, NULL }, + { "Gbreve", 778, NULL }, + { "commaaccent", 250, NULL }, + { "hungarumlaut", 333, NULL }, + { "Idotaccent", 278, NULL }, + { "Nacute", 722, NULL }, + { "quotedbl", 355, NULL }, + { "gcommaaccent", 556, NULL }, + { "mu", 556, NULL }, + { "greaterequal", 549, NULL }, + { "Scaron", 667, NULL }, + { "Lslash", 556, NULL }, + { "semicolon", 278, NULL }, + { "oslash", 611, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 471, NULL }, + { "parenright", 333, NULL }, + { "ccaron", 500, NULL }, + { "Ecircumflex", 667, NULL }, + { "gbreve", 556, NULL }, + { "trademark", 1000, NULL }, + { "daggerdbl", 556, NULL }, + { "nacute", 556, NULL }, + { "macron", 333, NULL }, + { "Otilde", 778, NULL }, + { "Emacron", 667, NULL }, + { "ellipsis", 1000, NULL }, + { "scaron", 500, NULL }, + { "AE", 1000, NULL }, + { "Ucircumflex", 722, NULL }, + { "lslash", 222, NULL }, + { "quotedblleft", 333, NULL }, + { "guilsinglright", 333, NULL }, + { "hyphen", 333, NULL }, + { "quotesingle", 191, NULL }, + { "eight", 556, NULL }, + { "exclamdown", 333, NULL }, + { "endash", 556, NULL }, + { "oe", 944, NULL }, + { "Abreve", 667, NULL }, + { "Umacron", 722, NULL }, + { "ecircumflex", 556, NULL }, + { "Adieresis", 667, NULL }, + { "copyright", 737, NULL }, + { "Egrave", 667, NULL }, + { "slash", 278, NULL }, + { "Edieresis", 667, NULL }, + { "otilde", 556, NULL }, + { "Idieresis", 278, NULL }, + { "parenleft", 333, NULL }, + { "one", 556, NULL }, + { "emacron", 556, NULL }, + { "Odieresis", 778, NULL }, + { "ucircumflex", 556, NULL }, + { "bracketleft", 278, NULL }, + { "Ugrave", 722, NULL }, + { "quoteright", 222, NULL }, + { "Udieresis", 722, NULL }, + { "perthousand", 1000, NULL }, + { "Ydieresis", 667, NULL }, + { "umacron", 556, NULL }, + { "abreve", 556, NULL }, + { "Eacute", 667, NULL }, + { "adieresis", 556, NULL }, + { "egrave", 556, NULL }, + { "edieresis", 556, NULL }, + { "idieresis", 278, NULL }, + { "Eth", 722, NULL }, + { "ae", 889, NULL }, + { "asterisk", 389, NULL }, + { "odieresis", 556, NULL }, + { "Uacute", 722, NULL }, + { "ugrave", 556, NULL }, + { "nine", 556, NULL }, + { "five", 556, NULL }, + { "udieresis", 556, NULL }, + { "Zcaron", 611, NULL }, + { "Scommaaccent", 667, NULL }, + { "threequarters", 834, NULL }, + { "guillemotright", 556, NULL }, + { "Ccedilla", 722, NULL }, + { "ydieresis", 500, NULL }, + { "tilde", 333, NULL }, + { "at", 1015, NULL }, + { "eacute", 556, NULL }, + { "underscore", 556, NULL }, + { "Euro", 556, NULL }, + { "Dcroat", 722, NULL }, + { "multiply", 584, NULL }, + { "zero", 556, NULL }, + { "eth", 556, NULL }, + { "Scedilla", 667, NULL }, + { "Ograve", 778, NULL }, + { "Racute", 722, NULL }, + { "partialdiff", 476, NULL }, + { "uacute", 556, NULL }, + { "braceleft", 334, NULL }, + { "Thorn", 667, NULL }, + { "zcaron", 500, NULL }, + { "scommaaccent", 500, NULL }, + { "ccedilla", 500, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 556, NULL }, + { "Ocircumflex", 778, NULL }, + { "Oacute", 778, NULL }, + { "scedilla", 500, NULL }, + { "ogonek", 333, NULL }, + { "ograve", 556, NULL }, + { "racute", 333, NULL }, + { "Tcaron", 611, NULL }, + { "Eogonek", 667, NULL }, + { "thorn", 556, NULL }, + { "degree", 400, NULL }, + { "registered", 737, NULL }, + { "radical", 453, NULL }, + { "Aring", 667, NULL }, + { "percent", 889, NULL }, + { "six", 556, NULL }, + { "paragraph", 537, NULL }, + { "dcaron", 643, NULL }, + { "Uogonek", 722, NULL }, + { "two", 556, NULL }, + { "summation", 600, NULL }, + { "Igrave", 278, NULL }, + { "Lacute", 556, NULL }, + { "ocircumflex", 556, NULL }, + { "oacute", 556, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 556, NULL }, + { "tcaron", 317, NULL }, + { "eogonek", 556, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 778, NULL }, + { "asciicircum", 469, NULL }, + { "aring", 556, NULL }, + { "grave", 333, NULL }, + { "uogonek", 556, NULL }, + { "bracketright", 278, NULL }, + { "Iacute", 278, NULL }, + { "ampersand", 667, NULL }, + { "igrave", 278, NULL }, + { "lacute", 222, NULL }, + { "Ncaron", 722, NULL }, + { "plus", 584, NULL }, + { "uring", 556, NULL }, + { "quotesinglbase", 222, NULL }, + { "lcommaaccent", 222, NULL }, + { "Yacute", 667, NULL }, + { "ohungarumlaut", 556, NULL }, + { "threesuperior", 333, NULL }, + { "acute", 333, NULL }, + { "section", 556, NULL }, + { "dieresis", 333, NULL }, + { "iacute", 278, NULL }, + { "quotedblbase", 333, NULL }, + { "ncaron", 556, NULL }, + { "florin", 556, NULL }, + { "yacute", 500, NULL }, + { "Rcommaaccent", 722, NULL }, + { "fi", 500, NULL }, + { "fl", 500, NULL }, + { "Acircumflex", 667, NULL }, + { "Cacute", 722, NULL }, + { "Icircumflex", 278, NULL }, + { "guillemotleft", 556, NULL }, + { "germandbls", 611, NULL }, + { "Amacron", 667, NULL }, + { "seven", 556, NULL }, + { "Sacute", 667, NULL }, + { "ordmasculine", 365, NULL }, + { "dotlessi", 278, NULL }, + { "sterling", 556, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 278, NULL }, + { "rcommaaccent", 333, NULL }, + { "Zdotaccent", 611, NULL }, + { "acircumflex", 556, NULL }, + { "cacute", 500, NULL }, + { "Ecaron", 667, NULL }, + { "icircumflex", 278, NULL }, + { "braceright", 334, NULL }, + { "quotedblright", 333, NULL }, + { "amacron", 556, NULL }, + { "sacute", 500, NULL }, + { "imacron", 278, NULL }, + { "cent", 556, NULL }, + { "currency", 556, NULL }, + { "logicalnot", 584, NULL }, + { "zdotaccent", 500, NULL }, + { "Atilde", 667, NULL }, + { "breve", 333, NULL }, + { "bar", 260, NULL }, + { "fraction", 167, NULL }, + { "less", 584, NULL }, + { "ecaron", 556, NULL }, + { "guilsinglleft", 333, NULL }, + { "exclam", 278, NULL }, + { "period", 278, NULL }, + { "Rcaron", 722, NULL }, + { "Kcommaaccent", 667, NULL }, + { "greater", 584, NULL }, + { "atilde", 556, NULL }, + { "brokenbar", 260, NULL }, + { "quoteleft", 222, NULL }, + { "Edotaccent", 667, NULL }, + { "onesuperior", 333, NULL } +}; + +static BuiltinFontWidth helveticaBoldWidthsTab[] = { + { "Ntilde", 722, NULL }, + { "rcaron", 389, NULL }, + { "kcommaaccent", 556, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 611, NULL }, + { "comma", 278, NULL }, + { "cedilla", 333, NULL }, + { "plusminus", 584, NULL }, + { "circumflex", 333, NULL }, + { "dotaccent", 333, NULL }, + { "edotaccent", 556, NULL }, + { "asciitilde", 584, NULL }, + { "colon", 333, NULL }, + { "onehalf", 834, NULL }, + { "dollar", 556, NULL }, + { "Lcaron", 611, NULL }, + { "ntilde", 611, NULL }, + { "Aogonek", 722, NULL }, + { "ncommaaccent", 611, NULL }, + { "minus", 584, NULL }, + { "Iogonek", 278, NULL }, + { "zacute", 500, NULL }, + { "yen", 556, NULL }, + { "space", 278, NULL }, + { "Omacron", 778, NULL }, + { "questiondown", 611, NULL }, + { "emdash", 1000, NULL }, + { "Agrave", 722, NULL }, + { "three", 556, NULL }, + { "numbersign", 556, NULL }, + { "lcaron", 400, NULL }, + { "A", 722, NULL }, + { "B", 722, NULL }, + { "C", 722, NULL }, + { "aogonek", 556, NULL }, + { "D", 722, NULL }, + { "E", 667, NULL }, + { "onequarter", 834, NULL }, + { "F", 611, NULL }, + { "G", 778, NULL }, + { "H", 722, NULL }, + { "I", 278, NULL }, + { "J", 556, NULL }, + { "K", 722, NULL }, + { "iogonek", 278, NULL }, + { "backslash", 278, NULL }, + { "L", 611, NULL }, + { "periodcentered", 278, NULL }, + { "M", 833, NULL }, + { "N", 722, NULL }, + { "omacron", 611, NULL }, + { "Tcommaaccent", 611, NULL }, + { "O", 778, NULL }, + { "P", 667, NULL }, + { "Q", 778, NULL }, + { "Uhungarumlaut", 722, NULL }, + { "R", 722, NULL }, + { "Aacute", 722, NULL }, + { "caron", 333, NULL }, + { "S", 667, NULL }, + { "T", 611, NULL }, + { "U", 722, NULL }, + { "agrave", 556, NULL }, + { "V", 667, NULL }, + { "W", 944, NULL }, + { "X", 667, NULL }, + { "question", 611, NULL }, + { "equal", 584, NULL }, + { "Y", 667, NULL }, + { "Z", 611, NULL }, + { "four", 556, NULL }, + { "a", 556, NULL }, + { "Gcommaaccent", 778, NULL }, + { "b", 611, NULL }, + { "c", 556, NULL }, + { "d", 611, NULL }, + { "e", 556, NULL }, + { "f", 333, NULL }, + { "g", 611, NULL }, + { "bullet", 350, NULL }, + { "h", 611, NULL }, + { "i", 278, NULL }, + { "Oslash", 778, NULL }, + { "dagger", 556, NULL }, + { "j", 278, NULL }, + { "k", 556, NULL }, + { "l", 278, NULL }, + { "m", 889, NULL }, + { "n", 611, NULL }, + { "tcommaaccent", 333, NULL }, + { "o", 611, NULL }, + { "ordfeminine", 370, NULL }, + { "ring", 333, NULL }, + { "p", 611, NULL }, + { "q", 611, NULL }, + { "uhungarumlaut", 611, NULL }, + { "r", 389, NULL }, + { "twosuperior", 333, NULL }, + { "aacute", 556, NULL }, + { "s", 556, NULL }, + { "OE", 1000, NULL }, + { "t", 333, NULL }, + { "divide", 584, NULL }, + { "u", 611, NULL }, + { "Ccaron", 722, NULL }, + { "v", 556, NULL }, + { "w", 778, NULL }, + { "x", 556, NULL }, + { "y", 556, NULL }, + { "z", 500, NULL }, + { "Gbreve", 778, NULL }, + { "commaaccent", 250, NULL }, + { "hungarumlaut", 333, NULL }, + { "Idotaccent", 278, NULL }, + { "Nacute", 722, NULL }, + { "quotedbl", 474, NULL }, + { "gcommaaccent", 611, NULL }, + { "mu", 611, NULL }, + { "greaterequal", 549, NULL }, + { "Scaron", 667, NULL }, + { "Lslash", 611, NULL }, + { "semicolon", 333, NULL }, + { "oslash", 611, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 494, NULL }, + { "parenright", 333, NULL }, + { "ccaron", 556, NULL }, + { "Ecircumflex", 667, NULL }, + { "gbreve", 611, NULL }, + { "trademark", 1000, NULL }, + { "daggerdbl", 556, NULL }, + { "nacute", 611, NULL }, + { "macron", 333, NULL }, + { "Otilde", 778, NULL }, + { "Emacron", 667, NULL }, + { "ellipsis", 1000, NULL }, + { "scaron", 556, NULL }, + { "AE", 1000, NULL }, + { "Ucircumflex", 722, NULL }, + { "lslash", 278, NULL }, + { "quotedblleft", 500, NULL }, + { "guilsinglright", 333, NULL }, + { "hyphen", 333, NULL }, + { "quotesingle", 238, NULL }, + { "eight", 556, NULL }, + { "exclamdown", 333, NULL }, + { "endash", 556, NULL }, + { "oe", 944, NULL }, + { "Abreve", 722, NULL }, + { "Umacron", 722, NULL }, + { "ecircumflex", 556, NULL }, + { "Adieresis", 722, NULL }, + { "copyright", 737, NULL }, + { "Egrave", 667, NULL }, + { "slash", 278, NULL }, + { "Edieresis", 667, NULL }, + { "otilde", 611, NULL }, + { "Idieresis", 278, NULL }, + { "parenleft", 333, NULL }, + { "one", 556, NULL }, + { "emacron", 556, NULL }, + { "Odieresis", 778, NULL }, + { "ucircumflex", 611, NULL }, + { "bracketleft", 333, NULL }, + { "Ugrave", 722, NULL }, + { "quoteright", 278, NULL }, + { "Udieresis", 722, NULL }, + { "perthousand", 1000, NULL }, + { "Ydieresis", 667, NULL }, + { "umacron", 611, NULL }, + { "abreve", 556, NULL }, + { "Eacute", 667, NULL }, + { "adieresis", 556, NULL }, + { "egrave", 556, NULL }, + { "edieresis", 556, NULL }, + { "idieresis", 278, NULL }, + { "Eth", 722, NULL }, + { "ae", 889, NULL }, + { "asterisk", 389, NULL }, + { "odieresis", 611, NULL }, + { "Uacute", 722, NULL }, + { "ugrave", 611, NULL }, + { "nine", 556, NULL }, + { "five", 556, NULL }, + { "udieresis", 611, NULL }, + { "Zcaron", 611, NULL }, + { "Scommaaccent", 667, NULL }, + { "threequarters", 834, NULL }, + { "guillemotright", 556, NULL }, + { "Ccedilla", 722, NULL }, + { "ydieresis", 556, NULL }, + { "tilde", 333, NULL }, + { "dbldaggerumlaut", 556, NULL }, + { "at", 975, NULL }, + { "eacute", 556, NULL }, + { "underscore", 556, NULL }, + { "Euro", 556, NULL }, + { "Dcroat", 722, NULL }, + { "multiply", 584, NULL }, + { "zero", 556, NULL }, + { "eth", 611, NULL }, + { "Scedilla", 667, NULL }, + { "Ograve", 778, NULL }, + { "Racute", 722, NULL }, + { "partialdiff", 494, NULL }, + { "uacute", 611, NULL }, + { "braceleft", 389, NULL }, + { "Thorn", 667, NULL }, + { "zcaron", 500, NULL }, + { "scommaaccent", 556, NULL }, + { "ccedilla", 556, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 611, NULL }, + { "Ocircumflex", 778, NULL }, + { "Oacute", 778, NULL }, + { "scedilla", 556, NULL }, + { "ogonek", 333, NULL }, + { "ograve", 611, NULL }, + { "racute", 389, NULL }, + { "Tcaron", 611, NULL }, + { "Eogonek", 667, NULL }, + { "thorn", 611, NULL }, + { "degree", 400, NULL }, + { "registered", 737, NULL }, + { "radical", 549, NULL }, + { "Aring", 722, NULL }, + { "percent", 889, NULL }, + { "six", 556, NULL }, + { "paragraph", 556, NULL }, + { "dcaron", 743, NULL }, + { "Uogonek", 722, NULL }, + { "two", 556, NULL }, + { "summation", 600, NULL }, + { "Igrave", 278, NULL }, + { "Lacute", 611, NULL }, + { "ocircumflex", 611, NULL }, + { "oacute", 611, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 611, NULL }, + { "tcaron", 389, NULL }, + { "eogonek", 556, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 778, NULL }, + { "asciicircum", 584, NULL }, + { "aring", 556, NULL }, + { "grave", 333, NULL }, + { "uogonek", 611, NULL }, + { "bracketright", 333, NULL }, + { "Iacute", 278, NULL }, + { "ampersand", 722, NULL }, + { "igrave", 278, NULL }, + { "lacute", 278, NULL }, + { "Ncaron", 722, NULL }, + { "plus", 584, NULL }, + { "uring", 611, NULL }, + { "quotesinglbase", 278, NULL }, + { "lcommaaccent", 278, NULL }, + { "Yacute", 667, NULL }, + { "ohungarumlaut", 611, NULL }, + { "threesuperior", 333, NULL }, + { "acute", 333, NULL }, + { "section", 556, NULL }, + { "dieresis", 333, NULL }, + { "iacute", 278, NULL }, + { "quotedblbase", 500, NULL }, + { "ncaron", 611, NULL }, + { "florin", 556, NULL }, + { "yacute", 556, NULL }, + { "Rcommaaccent", 722, NULL }, + { "fi", 611, NULL }, + { "fl", 611, NULL }, + { "Acircumflex", 722, NULL }, + { "Cacute", 722, NULL }, + { "Icircumflex", 278, NULL }, + { "guillemotleft", 556, NULL }, + { "germandbls", 611, NULL }, + { "Amacron", 722, NULL }, + { "seven", 556, NULL }, + { "Sacute", 667, NULL }, + { "ordmasculine", 365, NULL }, + { "dotlessi", 278, NULL }, + { "sterling", 556, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 278, NULL }, + { "rcommaaccent", 389, NULL }, + { "Zdotaccent", 611, NULL }, + { "acircumflex", 556, NULL }, + { "cacute", 556, NULL }, + { "Ecaron", 667, NULL }, + { "icircumflex", 278, NULL }, + { "braceright", 389, NULL }, + { "quotedblright", 500, NULL }, + { "amacron", 556, NULL }, + { "sacute", 556, NULL }, + { "imacron", 278, NULL }, + { "cent", 556, NULL }, + { "currency", 556, NULL }, + { "logicalnot", 584, NULL }, + { "zdotaccent", 500, NULL }, + { "Atilde", 722, NULL }, + { "breve", 333, NULL }, + { "bar", 280, NULL }, + { "fraction", 167, NULL }, + { "less", 584, NULL }, + { "ecaron", 556, NULL }, + { "guilsinglleft", 333, NULL }, + { "exclam", 333, NULL }, + { "period", 278, NULL }, + { "Rcaron", 722, NULL }, + { "Kcommaaccent", 722, NULL }, + { "greater", 584, NULL }, + { "atilde", 556, NULL }, + { "brokenbar", 280, NULL }, + { "quoteleft", 278, NULL }, + { "Edotaccent", 667, NULL }, + { "onesuperior", 333, NULL } +}; + +static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = { + { "Ntilde", 722, NULL }, + { "rcaron", 389, NULL }, + { "kcommaaccent", 556, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 611, NULL }, + { "comma", 278, NULL }, + { "cedilla", 333, NULL }, + { "plusminus", 584, NULL }, + { "circumflex", 333, NULL }, + { "dotaccent", 333, NULL }, + { "edotaccent", 556, NULL }, + { "asciitilde", 584, NULL }, + { "colon", 333, NULL }, + { "onehalf", 834, NULL }, + { "dollar", 556, NULL }, + { "Lcaron", 611, NULL }, + { "ntilde", 611, NULL }, + { "Aogonek", 722, NULL }, + { "ncommaaccent", 611, NULL }, + { "minus", 584, NULL }, + { "Iogonek", 278, NULL }, + { "zacute", 500, NULL }, + { "yen", 556, NULL }, + { "space", 278, NULL }, + { "Omacron", 778, NULL }, + { "questiondown", 611, NULL }, + { "emdash", 1000, NULL }, + { "Agrave", 722, NULL }, + { "three", 556, NULL }, + { "numbersign", 556, NULL }, + { "lcaron", 400, NULL }, + { "A", 722, NULL }, + { "B", 722, NULL }, + { "C", 722, NULL }, + { "aogonek", 556, NULL }, + { "D", 722, NULL }, + { "E", 667, NULL }, + { "onequarter", 834, NULL }, + { "F", 611, NULL }, + { "G", 778, NULL }, + { "H", 722, NULL }, + { "I", 278, NULL }, + { "J", 556, NULL }, + { "K", 722, NULL }, + { "iogonek", 278, NULL }, + { "backslash", 278, NULL }, + { "L", 611, NULL }, + { "periodcentered", 278, NULL }, + { "M", 833, NULL }, + { "N", 722, NULL }, + { "omacron", 611, NULL }, + { "Tcommaaccent", 611, NULL }, + { "O", 778, NULL }, + { "P", 667, NULL }, + { "Q", 778, NULL }, + { "Uhungarumlaut", 722, NULL }, + { "R", 722, NULL }, + { "Aacute", 722, NULL }, + { "caron", 333, NULL }, + { "S", 667, NULL }, + { "T", 611, NULL }, + { "U", 722, NULL }, + { "agrave", 556, NULL }, + { "V", 667, NULL }, + { "W", 944, NULL }, + { "X", 667, NULL }, + { "question", 611, NULL }, + { "equal", 584, NULL }, + { "Y", 667, NULL }, + { "Z", 611, NULL }, + { "four", 556, NULL }, + { "a", 556, NULL }, + { "Gcommaaccent", 778, NULL }, + { "b", 611, NULL }, + { "c", 556, NULL }, + { "d", 611, NULL }, + { "e", 556, NULL }, + { "f", 333, NULL }, + { "g", 611, NULL }, + { "bullet", 350, NULL }, + { "h", 611, NULL }, + { "i", 278, NULL }, + { "Oslash", 778, NULL }, + { "dagger", 556, NULL }, + { "j", 278, NULL }, + { "k", 556, NULL }, + { "l", 278, NULL }, + { "m", 889, NULL }, + { "n", 611, NULL }, + { "tcommaaccent", 333, NULL }, + { "o", 611, NULL }, + { "ordfeminine", 370, NULL }, + { "ring", 333, NULL }, + { "p", 611, NULL }, + { "q", 611, NULL }, + { "uhungarumlaut", 611, NULL }, + { "r", 389, NULL }, + { "twosuperior", 333, NULL }, + { "aacute", 556, NULL }, + { "s", 556, NULL }, + { "OE", 1000, NULL }, + { "t", 333, NULL }, + { "divide", 584, NULL }, + { "u", 611, NULL }, + { "Ccaron", 722, NULL }, + { "v", 556, NULL }, + { "w", 778, NULL }, + { "x", 556, NULL }, + { "y", 556, NULL }, + { "z", 500, NULL }, + { "Gbreve", 778, NULL }, + { "commaaccent", 250, NULL }, + { "hungarumlaut", 333, NULL }, + { "Idotaccent", 278, NULL }, + { "Nacute", 722, NULL }, + { "quotedbl", 474, NULL }, + { "gcommaaccent", 611, NULL }, + { "mu", 611, NULL }, + { "greaterequal", 549, NULL }, + { "Scaron", 667, NULL }, + { "Lslash", 611, NULL }, + { "semicolon", 333, NULL }, + { "oslash", 611, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 494, NULL }, + { "parenright", 333, NULL }, + { "ccaron", 556, NULL }, + { "Ecircumflex", 667, NULL }, + { "gbreve", 611, NULL }, + { "trademark", 1000, NULL }, + { "daggerdbl", 556, NULL }, + { "nacute", 611, NULL }, + { "macron", 333, NULL }, + { "Otilde", 778, NULL }, + { "Emacron", 667, NULL }, + { "ellipsis", 1000, NULL }, + { "scaron", 556, NULL }, + { "AE", 1000, NULL }, + { "Ucircumflex", 722, NULL }, + { "lslash", 278, NULL }, + { "quotedblleft", 500, NULL }, + { "guilsinglright", 333, NULL }, + { "hyphen", 333, NULL }, + { "quotesingle", 238, NULL }, + { "eight", 556, NULL }, + { "exclamdown", 333, NULL }, + { "endash", 556, NULL }, + { "oe", 944, NULL }, + { "Abreve", 722, NULL }, + { "Umacron", 722, NULL }, + { "ecircumflex", 556, NULL }, + { "Adieresis", 722, NULL }, + { "copyright", 737, NULL }, + { "Egrave", 667, NULL }, + { "slash", 278, NULL }, + { "Edieresis", 667, NULL }, + { "otilde", 611, NULL }, + { "Idieresis", 278, NULL }, + { "parenleft", 333, NULL }, + { "one", 556, NULL }, + { "emacron", 556, NULL }, + { "Odieresis", 778, NULL }, + { "ucircumflex", 611, NULL }, + { "bracketleft", 333, NULL }, + { "Ugrave", 722, NULL }, + { "quoteright", 278, NULL }, + { "Udieresis", 722, NULL }, + { "perthousand", 1000, NULL }, + { "Ydieresis", 667, NULL }, + { "umacron", 611, NULL }, + { "abreve", 556, NULL }, + { "Eacute", 667, NULL }, + { "adieresis", 556, NULL }, + { "egrave", 556, NULL }, + { "edieresis", 556, NULL }, + { "idieresis", 278, NULL }, + { "Eth", 722, NULL }, + { "ae", 889, NULL }, + { "asterisk", 389, NULL }, + { "odieresis", 611, NULL }, + { "Uacute", 722, NULL }, + { "ugrave", 611, NULL }, + { "nine", 556, NULL }, + { "five", 556, NULL }, + { "udieresis", 611, NULL }, + { "Zcaron", 611, NULL }, + { "Scommaaccent", 667, NULL }, + { "threequarters", 834, NULL }, + { "guillemotright", 556, NULL }, + { "Ccedilla", 722, NULL }, + { "ydieresis", 556, NULL }, + { "tilde", 333, NULL }, + { "at", 975, NULL }, + { "eacute", 556, NULL }, + { "underscore", 556, NULL }, + { "Euro", 556, NULL }, + { "Dcroat", 722, NULL }, + { "multiply", 584, NULL }, + { "zero", 556, NULL }, + { "eth", 611, NULL }, + { "Scedilla", 667, NULL }, + { "Ograve", 778, NULL }, + { "Racute", 722, NULL }, + { "partialdiff", 494, NULL }, + { "uacute", 611, NULL }, + { "braceleft", 389, NULL }, + { "Thorn", 667, NULL }, + { "zcaron", 500, NULL }, + { "scommaaccent", 556, NULL }, + { "ccedilla", 556, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 611, NULL }, + { "Ocircumflex", 778, NULL }, + { "Oacute", 778, NULL }, + { "scedilla", 556, NULL }, + { "ogonek", 333, NULL }, + { "ograve", 611, NULL }, + { "racute", 389, NULL }, + { "Tcaron", 611, NULL }, + { "Eogonek", 667, NULL }, + { "thorn", 611, NULL }, + { "degree", 400, NULL }, + { "registered", 737, NULL }, + { "radical", 549, NULL }, + { "Aring", 722, NULL }, + { "percent", 889, NULL }, + { "six", 556, NULL }, + { "paragraph", 556, NULL }, + { "dcaron", 743, NULL }, + { "Uogonek", 722, NULL }, + { "two", 556, NULL }, + { "summation", 600, NULL }, + { "Igrave", 278, NULL }, + { "Lacute", 611, NULL }, + { "ocircumflex", 611, NULL }, + { "oacute", 611, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 611, NULL }, + { "tcaron", 389, NULL }, + { "eogonek", 556, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 778, NULL }, + { "asciicircum", 584, NULL }, + { "aring", 556, NULL }, + { "grave", 333, NULL }, + { "uogonek", 611, NULL }, + { "bracketright", 333, NULL }, + { "Iacute", 278, NULL }, + { "ampersand", 722, NULL }, + { "igrave", 278, NULL }, + { "lacute", 278, NULL }, + { "Ncaron", 722, NULL }, + { "plus", 584, NULL }, + { "uring", 611, NULL }, + { "quotesinglbase", 278, NULL }, + { "lcommaaccent", 278, NULL }, + { "Yacute", 667, NULL }, + { "ohungarumlaut", 611, NULL }, + { "threesuperior", 333, NULL }, + { "acute", 333, NULL }, + { "section", 556, NULL }, + { "dieresis", 333, NULL }, + { "iacute", 278, NULL }, + { "quotedblbase", 500, NULL }, + { "ncaron", 611, NULL }, + { "florin", 556, NULL }, + { "yacute", 556, NULL }, + { "Rcommaaccent", 722, NULL }, + { "fi", 611, NULL }, + { "fl", 611, NULL }, + { "Acircumflex", 722, NULL }, + { "Cacute", 722, NULL }, + { "Icircumflex", 278, NULL }, + { "guillemotleft", 556, NULL }, + { "germandbls", 611, NULL }, + { "Amacron", 722, NULL }, + { "seven", 556, NULL }, + { "Sacute", 667, NULL }, + { "ordmasculine", 365, NULL }, + { "dotlessi", 278, NULL }, + { "sterling", 556, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 278, NULL }, + { "rcommaaccent", 389, NULL }, + { "Zdotaccent", 611, NULL }, + { "acircumflex", 556, NULL }, + { "cacute", 556, NULL }, + { "Ecaron", 667, NULL }, + { "icircumflex", 278, NULL }, + { "braceright", 389, NULL }, + { "quotedblright", 500, NULL }, + { "amacron", 556, NULL }, + { "sacute", 556, NULL }, + { "imacron", 278, NULL }, + { "cent", 556, NULL }, + { "currency", 556, NULL }, + { "logicalnot", 584, NULL }, + { "zdotaccent", 500, NULL }, + { "Atilde", 722, NULL }, + { "breve", 333, NULL }, + { "bar", 280, NULL }, + { "fraction", 167, NULL }, + { "less", 584, NULL }, + { "ecaron", 556, NULL }, + { "guilsinglleft", 333, NULL }, + { "exclam", 333, NULL }, + { "period", 278, NULL }, + { "Rcaron", 722, NULL }, + { "Kcommaaccent", 722, NULL }, + { "greater", 584, NULL }, + { "atilde", 556, NULL }, + { "brokenbar", 280, NULL }, + { "quoteleft", 278, NULL }, + { "Edotaccent", 667, NULL }, + { "onesuperior", 333, NULL } +}; + +static BuiltinFontWidth helveticaObliqueWidthsTab[] = { + { "Ntilde", 722, NULL }, + { "rcaron", 333, NULL }, + { "kcommaaccent", 500, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 611, NULL }, + { "comma", 278, NULL }, + { "cedilla", 333, NULL }, + { "plusminus", 584, NULL }, + { "circumflex", 333, NULL }, + { "dotaccent", 333, NULL }, + { "edotaccent", 556, NULL }, + { "asciitilde", 584, NULL }, + { "colon", 278, NULL }, + { "onehalf", 834, NULL }, + { "dollar", 556, NULL }, + { "Lcaron", 556, NULL }, + { "ntilde", 556, NULL }, + { "Aogonek", 667, NULL }, + { "ncommaaccent", 556, NULL }, + { "minus", 584, NULL }, + { "Iogonek", 278, NULL }, + { "zacute", 500, NULL }, + { "yen", 556, NULL }, + { "space", 278, NULL }, + { "Omacron", 778, NULL }, + { "questiondown", 611, NULL }, + { "emdash", 1000, NULL }, + { "Agrave", 667, NULL }, + { "three", 556, NULL }, + { "numbersign", 556, NULL }, + { "lcaron", 299, NULL }, + { "A", 667, NULL }, + { "B", 667, NULL }, + { "C", 722, NULL }, + { "aogonek", 556, NULL }, + { "D", 722, NULL }, + { "E", 667, NULL }, + { "onequarter", 834, NULL }, + { "F", 611, NULL }, + { "G", 778, NULL }, + { "H", 722, NULL }, + { "I", 278, NULL }, + { "J", 500, NULL }, + { "K", 667, NULL }, + { "iogonek", 222, NULL }, + { "backslash", 278, NULL }, + { "L", 556, NULL }, + { "periodcentered", 278, NULL }, + { "M", 833, NULL }, + { "N", 722, NULL }, + { "omacron", 556, NULL }, + { "Tcommaaccent", 611, NULL }, + { "O", 778, NULL }, + { "P", 667, NULL }, + { "Q", 778, NULL }, + { "Uhungarumlaut", 722, NULL }, + { "R", 722, NULL }, + { "Aacute", 667, NULL }, + { "caron", 333, NULL }, + { "S", 667, NULL }, + { "T", 611, NULL }, + { "U", 722, NULL }, + { "agrave", 556, NULL }, + { "V", 667, NULL }, + { "W", 944, NULL }, + { "X", 667, NULL }, + { "question", 556, NULL }, + { "equal", 584, NULL }, + { "Y", 667, NULL }, + { "Z", 611, NULL }, + { "four", 556, NULL }, + { "a", 556, NULL }, + { "Gcommaaccent", 778, NULL }, + { "b", 556, NULL }, + { "c", 500, NULL }, + { "d", 556, NULL }, + { "e", 556, NULL }, + { "f", 278, NULL }, + { "g", 556, NULL }, + { "bullet", 350, NULL }, + { "h", 556, NULL }, + { "i", 222, NULL }, + { "Oslash", 778, NULL }, + { "dagger", 556, NULL }, + { "j", 222, NULL }, + { "k", 500, NULL }, + { "l", 222, NULL }, + { "m", 833, NULL }, + { "n", 556, NULL }, + { "tcommaaccent", 278, NULL }, + { "o", 556, NULL }, + { "ordfeminine", 370, NULL }, + { "ring", 333, NULL }, + { "p", 556, NULL }, + { "q", 556, NULL }, + { "uhungarumlaut", 556, NULL }, + { "r", 333, NULL }, + { "twosuperior", 333, NULL }, + { "aacute", 556, NULL }, + { "s", 500, NULL }, + { "OE", 1000, NULL }, + { "t", 278, NULL }, + { "divide", 584, NULL }, + { "u", 556, NULL }, + { "Ccaron", 722, NULL }, + { "v", 500, NULL }, + { "w", 722, NULL }, + { "x", 500, NULL }, + { "y", 500, NULL }, + { "z", 500, NULL }, + { "Gbreve", 778, NULL }, + { "commaaccent", 250, NULL }, + { "hungarumlaut", 333, NULL }, + { "Idotaccent", 278, NULL }, + { "Nacute", 722, NULL }, + { "quotedbl", 355, NULL }, + { "gcommaaccent", 556, NULL }, + { "mu", 556, NULL }, + { "greaterequal", 549, NULL }, + { "Scaron", 667, NULL }, + { "Lslash", 556, NULL }, + { "semicolon", 278, NULL }, + { "oslash", 611, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 471, NULL }, + { "parenright", 333, NULL }, + { "ccaron", 500, NULL }, + { "Ecircumflex", 667, NULL }, + { "gbreve", 556, NULL }, + { "trademark", 1000, NULL }, + { "daggerdbl", 556, NULL }, + { "nacute", 556, NULL }, + { "macron", 333, NULL }, + { "Otilde", 778, NULL }, + { "Emacron", 667, NULL }, + { "ellipsis", 1000, NULL }, + { "scaron", 500, NULL }, + { "AE", 1000, NULL }, + { "Ucircumflex", 722, NULL }, + { "lslash", 222, NULL }, + { "quotedblleft", 333, NULL }, + { "guilsinglright", 333, NULL }, + { "hyphen", 333, NULL }, + { "quotesingle", 191, NULL }, + { "eight", 556, NULL }, + { "exclamdown", 333, NULL }, + { "endash", 556, NULL }, + { "oe", 944, NULL }, + { "Abreve", 667, NULL }, + { "Umacron", 722, NULL }, + { "ecircumflex", 556, NULL }, + { "Adieresis", 667, NULL }, + { "copyright", 737, NULL }, + { "Egrave", 667, NULL }, + { "slash", 278, NULL }, + { "Edieresis", 667, NULL }, + { "otilde", 556, NULL }, + { "Idieresis", 278, NULL }, + { "parenleft", 333, NULL }, + { "one", 556, NULL }, + { "emacron", 556, NULL }, + { "Odieresis", 778, NULL }, + { "ucircumflex", 556, NULL }, + { "bracketleft", 278, NULL }, + { "Ugrave", 722, NULL }, + { "quoteright", 222, NULL }, + { "Udieresis", 722, NULL }, + { "perthousand", 1000, NULL }, + { "Ydieresis", 667, NULL }, + { "umacron", 556, NULL }, + { "abreve", 556, NULL }, + { "Eacute", 667, NULL }, + { "adieresis", 556, NULL }, + { "egrave", 556, NULL }, + { "edieresis", 556, NULL }, + { "idieresis", 278, NULL }, + { "Eth", 722, NULL }, + { "ae", 889, NULL }, + { "asterisk", 389, NULL }, + { "odieresis", 556, NULL }, + { "Uacute", 722, NULL }, + { "ugrave", 556, NULL }, + { "nine", 556, NULL }, + { "five", 556, NULL }, + { "udieresis", 556, NULL }, + { "Zcaron", 611, NULL }, + { "Scommaaccent", 667, NULL }, + { "threequarters", 834, NULL }, + { "guillemotright", 556, NULL }, + { "Ccedilla", 722, NULL }, + { "ydieresis", 500, NULL }, + { "tilde", 333, NULL }, + { "at", 1015, NULL }, + { "eacute", 556, NULL }, + { "underscore", 556, NULL }, + { "Euro", 556, NULL }, + { "Dcroat", 722, NULL }, + { "multiply", 584, NULL }, + { "zero", 556, NULL }, + { "eth", 556, NULL }, + { "Scedilla", 667, NULL }, + { "Ograve", 778, NULL }, + { "Racute", 722, NULL }, + { "partialdiff", 476, NULL }, + { "uacute", 556, NULL }, + { "braceleft", 334, NULL }, + { "Thorn", 667, NULL }, + { "zcaron", 500, NULL }, + { "scommaaccent", 500, NULL }, + { "ccedilla", 500, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 556, NULL }, + { "Ocircumflex", 778, NULL }, + { "Oacute", 778, NULL }, + { "scedilla", 500, NULL }, + { "ogonek", 333, NULL }, + { "ograve", 556, NULL }, + { "racute", 333, NULL }, + { "Tcaron", 611, NULL }, + { "Eogonek", 667, NULL }, + { "thorn", 556, NULL }, + { "degree", 400, NULL }, + { "registered", 737, NULL }, + { "radical", 453, NULL }, + { "Aring", 667, NULL }, + { "percent", 889, NULL }, + { "six", 556, NULL }, + { "paragraph", 537, NULL }, + { "dcaron", 643, NULL }, + { "Uogonek", 722, NULL }, + { "two", 556, NULL }, + { "summation", 600, NULL }, + { "Igrave", 278, NULL }, + { "Lacute", 556, NULL }, + { "ocircumflex", 556, NULL }, + { "oacute", 556, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 556, NULL }, + { "tcaron", 317, NULL }, + { "eogonek", 556, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 778, NULL }, + { "asciicircum", 469, NULL }, + { "aring", 556, NULL }, + { "grave", 333, NULL }, + { "uogonek", 556, NULL }, + { "bracketright", 278, NULL }, + { "Iacute", 278, NULL }, + { "ampersand", 667, NULL }, + { "igrave", 278, NULL }, + { "lacute", 222, NULL }, + { "Ncaron", 722, NULL }, + { "plus", 584, NULL }, + { "uring", 556, NULL }, + { "quotesinglbase", 222, NULL }, + { "lcommaaccent", 222, NULL }, + { "Yacute", 667, NULL }, + { "ohungarumlaut", 556, NULL }, + { "threesuperior", 333, NULL }, + { "acute", 333, NULL }, + { "section", 556, NULL }, + { "dieresis", 333, NULL }, + { "iacute", 278, NULL }, + { "quotedblbase", 333, NULL }, + { "ncaron", 556, NULL }, + { "florin", 556, NULL }, + { "yacute", 500, NULL }, + { "Rcommaaccent", 722, NULL }, + { "fi", 500, NULL }, + { "fl", 500, NULL }, + { "Acircumflex", 667, NULL }, + { "Cacute", 722, NULL }, + { "Icircumflex", 278, NULL }, + { "guillemotleft", 556, NULL }, + { "germandbls", 611, NULL }, + { "Amacron", 667, NULL }, + { "seven", 556, NULL }, + { "Sacute", 667, NULL }, + { "ordmasculine", 365, NULL }, + { "dotlessi", 278, NULL }, + { "sterling", 556, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 278, NULL }, + { "rcommaaccent", 333, NULL }, + { "Zdotaccent", 611, NULL }, + { "acircumflex", 556, NULL }, + { "cacute", 500, NULL }, + { "Ecaron", 667, NULL }, + { "icircumflex", 278, NULL }, + { "braceright", 334, NULL }, + { "quotedblright", 333, NULL }, + { "amacron", 556, NULL }, + { "sacute", 500, NULL }, + { "imacron", 278, NULL }, + { "cent", 556, NULL }, + { "currency", 556, NULL }, + { "logicalnot", 584, NULL }, + { "zdotaccent", 500, NULL }, + { "Atilde", 667, NULL }, + { "breve", 333, NULL }, + { "bar", 260, NULL }, + { "fraction", 167, NULL }, + { "less", 584, NULL }, + { "ecaron", 556, NULL }, + { "guilsinglleft", 333, NULL }, + { "exclam", 278, NULL }, + { "period", 278, NULL }, + { "Rcaron", 722, NULL }, + { "Kcommaaccent", 667, NULL }, + { "greater", 584, NULL }, + { "atilde", 556, NULL }, + { "brokenbar", 260, NULL }, + { "quoteleft", 222, NULL }, + { "Edotaccent", 667, NULL }, + { "onesuperior", 333, NULL } +}; + +static BuiltinFontWidth symbolWidthsTab[] = { + { "bracketleftex", 384, NULL }, + { "alpha", 631, NULL }, + { "union", 768, NULL }, + { "infinity", 713, NULL }, + { "comma", 250, NULL }, + { "copyrightsans", 790, NULL }, + { "plusminus", 549, NULL }, + { "arrowup", 603, NULL }, + { "apple", 790, NULL }, + { "parenleftbt", 384, NULL }, + { "notelement", 713, NULL }, + { "colon", 278, NULL }, + { "beta", 549, NULL }, + { "braceleftbt", 494, NULL }, + { "Lambda", 686, NULL }, + { "Phi", 763, NULL }, + { "minus", 549, NULL }, + { "space", 250, NULL }, + { "Sigma", 592, NULL }, + { "approxequal", 549, NULL }, + { "minute", 247, NULL }, + { "circleplus", 768, NULL }, + { "Omicron", 722, NULL }, + { "three", 500, NULL }, + { "numbersign", 500, NULL }, + { "lambda", 549, NULL }, + { "phi", 521, NULL }, + { "aleph", 823, NULL }, + { "Tau", 611, NULL }, + { "spade", 753, NULL }, + { "logicaland", 603, NULL }, + { "sigma", 603, NULL }, + { "propersuperset", 713, NULL }, + { "omicron", 549, NULL }, + { "question", 444, NULL }, + { "equal", 549, NULL }, + { "Epsilon", 611, NULL }, + { "emptyset", 823, NULL }, + { "diamond", 753, NULL }, + { "four", 500, NULL }, + { "Mu", 889, NULL }, + { "parenlefttp", 384, NULL }, + { "club", 753, NULL }, + { "bullet", 460, NULL }, + { "Omega", 768, NULL }, + { "tau", 439, NULL }, + { "Upsilon", 690, NULL }, + { "bracelefttp", 494, NULL }, + { "heart", 753, NULL }, + { "divide", 549, NULL }, + { "epsilon", 439, NULL }, + { "logicalor", 603, NULL }, + { "parenleftex", 384, NULL }, + { "greaterequal", 549, NULL }, + { "mu", 576, NULL }, + { "Nu", 722, NULL }, + { "therefore", 863, NULL }, + { "notsubset", 713, NULL }, + { "omega", 686, NULL }, + { "semicolon", 278, NULL }, + { "element", 713, NULL }, + { "upsilon", 576, NULL }, + { "existential", 549, NULL }, + { "integralbt", 686, NULL }, + { "lessequal", 549, NULL }, + { "phi1", 603, NULL }, + { "lozenge", 494, NULL }, + { "trademarkserif", 890, NULL }, + { "parenright", 333, NULL }, + { "reflexsuperset", 713, NULL }, + { "sigma1", 439, NULL }, + { "nu", 521, NULL }, + { "Gamma", 603, NULL }, + { "angleright", 329, NULL }, + { "ellipsis", 1000, NULL }, + { "Rho", 556, NULL }, + { "parenrightbt", 384, NULL }, + { "radicalex", 500, NULL }, + { "eight", 500, NULL }, + { "angleleft", 329, NULL }, + { "arrowdbldown", 603, NULL }, + { "congruent", 549, NULL }, + { "Theta", 741, NULL }, + { "intersection", 768, NULL }, + { "Pi", 768, NULL }, + { "slash", 278, NULL }, + { "registerserif", 790, NULL }, + { "parenleft", 333, NULL }, + { "one", 500, NULL }, + { "gamma", 411, NULL }, + { "bracketleft", 333, NULL }, + { "rho", 549, NULL }, + { "circlemultiply", 768, NULL }, + { "Chi", 722, NULL }, + { "theta", 521, NULL }, + { "pi", 549, NULL }, + { "integraltp", 686, NULL }, + { "Eta", 722, NULL }, + { "product", 823, NULL }, + { "nine", 500, NULL }, + { "five", 500, NULL }, + { "propersubset", 713, NULL }, + { "bracketrightbt", 384, NULL }, + { "trademarksans", 786, NULL }, + { "dotmath", 250, NULL }, + { "integralex", 686, NULL }, + { "chi", 549, NULL }, + { "parenrighttp", 384, NULL }, + { "eta", 603, NULL }, + { "underscore", 500, NULL }, + { "Euro", 750, NULL }, + { "multiply", 549, NULL }, + { "zero", 500, NULL }, + { "partialdiff", 494, NULL }, + { "angle", 768, NULL }, + { "arrowdblleft", 987, NULL }, + { "braceleft", 480, NULL }, + { "parenrightex", 384, NULL }, + { "Rfraktur", 795, NULL }, + { "Zeta", 611, NULL }, + { "braceex", 494, NULL }, + { "arrowdblup", 603, NULL }, + { "arrowdown", 603, NULL }, + { "Ifraktur", 686, NULL }, + { "degree", 400, NULL }, + { "Iota", 333, NULL }, + { "perpendicular", 658, NULL }, + { "radical", 549, NULL }, + { "asteriskmath", 500, NULL }, + { "percent", 833, NULL }, + { "zeta", 494, NULL }, + { "six", 500, NULL }, + { "two", 500, NULL }, + { "weierstrass", 987, NULL }, + { "summation", 713, NULL }, + { "bracketrighttp", 384, NULL }, + { "carriagereturn", 658, NULL }, + { "suchthat", 439, NULL }, + { "arrowvertex", 603, NULL }, + { "Delta", 612, NULL }, + { "iota", 329, NULL }, + { "arrowhorizex", 1000, NULL }, + { "bracketrightex", 384, NULL }, + { "bracketright", 333, NULL }, + { "ampersand", 778, NULL }, + { "plus", 549, NULL }, + { "proportional", 713, NULL }, + { "delta", 494, NULL }, + { "copyrightserif", 790, NULL }, + { "bracerightmid", 494, NULL }, + { "arrowleft", 987, NULL }, + { "second", 411, NULL }, + { "arrowdblboth", 1042, NULL }, + { "florin", 500, NULL }, + { "Psi", 795, NULL }, + { "bracerightbt", 494, NULL }, + { "bracketleftbt", 384, NULL }, + { "seven", 500, NULL }, + { "braceleftmid", 494, NULL }, + { "notequal", 549, NULL }, + { "psi", 686, NULL }, + { "equivalence", 549, NULL }, + { "universal", 713, NULL }, + { "arrowdblright", 987, NULL }, + { "braceright", 480, NULL }, + { "reflexsubset", 713, NULL }, + { "Xi", 645, NULL }, + { "theta1", 631, NULL }, + { "logicalnot", 713, NULL }, + { "Kappa", 722, NULL }, + { "similar", 549, NULL }, + { "bar", 200, NULL }, + { "fraction", 167, NULL }, + { "less", 549, NULL }, + { "registersans", 790, NULL }, + { "omega1", 713, NULL }, + { "exclam", 333, NULL }, + { "Upsilon1", 620, NULL }, + { "bracerighttp", 494, NULL }, + { "xi", 493, NULL }, + { "period", 250, NULL }, + { "Alpha", 722, NULL }, + { "arrowright", 987, NULL }, + { "greater", 549, NULL }, + { "bracketlefttp", 384, NULL }, + { "kappa", 549, NULL }, + { "gradient", 713, NULL }, + { "integral", 274, NULL }, + { "arrowboth", 1042, NULL }, + { "Beta", 667, NULL } +}; + +static BuiltinFontWidth timesBoldWidthsTab[] = { + { "Ntilde", 722, NULL }, + { "rcaron", 444, NULL }, + { "kcommaaccent", 556, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 667, NULL }, + { "comma", 250, NULL }, + { "cedilla", 333, NULL }, + { "plusminus", 570, NULL }, + { "circumflex", 333, NULL }, + { "dotaccent", 333, NULL }, + { "edotaccent", 444, NULL }, + { "asciitilde", 520, NULL }, + { "colon", 333, NULL }, + { "onehalf", 750, NULL }, + { "dollar", 500, NULL }, + { "Lcaron", 667, NULL }, + { "ntilde", 556, NULL }, + { "Aogonek", 722, NULL }, + { "ncommaaccent", 556, NULL }, + { "minus", 570, NULL }, + { "Iogonek", 389, NULL }, + { "zacute", 444, NULL }, + { "yen", 500, NULL }, + { "space", 250, NULL }, + { "Omacron", 778, NULL }, + { "questiondown", 500, NULL }, + { "emdash", 1000, NULL }, + { "Agrave", 722, NULL }, + { "three", 500, NULL }, + { "numbersign", 500, NULL }, + { "lcaron", 394, NULL }, + { "A", 722, NULL }, + { "B", 667, NULL }, + { "C", 722, NULL }, + { "aogonek", 500, NULL }, + { "D", 722, NULL }, + { "E", 667, NULL }, + { "onequarter", 750, NULL }, + { "F", 611, NULL }, + { "G", 778, NULL }, + { "H", 778, NULL }, + { "I", 389, NULL }, + { "J", 500, NULL }, + { "K", 778, NULL }, + { "iogonek", 278, NULL }, + { "backslash", 278, NULL }, + { "L", 667, NULL }, + { "periodcentered", 250, NULL }, + { "M", 944, NULL }, + { "N", 722, NULL }, + { "omacron", 500, NULL }, + { "Tcommaaccent", 667, NULL }, + { "O", 778, NULL }, + { "P", 611, NULL }, + { "Q", 778, NULL }, + { "Uhungarumlaut", 722, NULL }, + { "R", 722, NULL }, + { "Aacute", 722, NULL }, + { "caron", 333, NULL }, + { "S", 556, NULL }, + { "T", 667, NULL }, + { "U", 722, NULL }, + { "agrave", 500, NULL }, + { "V", 722, NULL }, + { "W", 1000, NULL }, + { "X", 722, NULL }, + { "question", 500, NULL }, + { "equal", 570, NULL }, + { "Y", 722, NULL }, + { "Z", 667, NULL }, + { "four", 500, NULL }, + { "a", 500, NULL }, + { "Gcommaaccent", 778, NULL }, + { "b", 556, NULL }, + { "c", 444, NULL }, + { "d", 556, NULL }, + { "e", 444, NULL }, + { "f", 333, NULL }, + { "g", 500, NULL }, + { "bullet", 350, NULL }, + { "h", 556, NULL }, + { "i", 278, NULL }, + { "Oslash", 778, NULL }, + { "dagger", 500, NULL }, + { "j", 333, NULL }, + { "k", 556, NULL }, + { "l", 278, NULL }, + { "m", 833, NULL }, + { "n", 556, NULL }, + { "tcommaaccent", 333, NULL }, + { "o", 500, NULL }, + { "ordfeminine", 300, NULL }, + { "ring", 333, NULL }, + { "p", 556, NULL }, + { "q", 556, NULL }, + { "uhungarumlaut", 556, NULL }, + { "r", 444, NULL }, + { "twosuperior", 300, NULL }, + { "aacute", 500, NULL }, + { "s", 389, NULL }, + { "OE", 1000, NULL }, + { "t", 333, NULL }, + { "divide", 570, NULL }, + { "u", 556, NULL }, + { "Ccaron", 722, NULL }, + { "v", 500, NULL }, + { "w", 722, NULL }, + { "x", 500, NULL }, + { "y", 500, NULL }, + { "z", 444, NULL }, + { "Gbreve", 778, NULL }, + { "commaaccent", 250, NULL }, + { "hungarumlaut", 333, NULL }, + { "Idotaccent", 389, NULL }, + { "Nacute", 722, NULL }, + { "quotedbl", 555, NULL }, + { "gcommaaccent", 500, NULL }, + { "mu", 556, NULL }, + { "greaterequal", 549, NULL }, + { "Scaron", 556, NULL }, + { "Lslash", 667, NULL }, + { "semicolon", 333, NULL }, + { "oslash", 500, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 494, NULL }, + { "parenright", 333, NULL }, + { "ccaron", 444, NULL }, + { "Ecircumflex", 667, NULL }, + { "gbreve", 500, NULL }, + { "trademark", 1000, NULL }, + { "daggerdbl", 500, NULL }, + { "nacute", 556, NULL }, + { "macron", 333, NULL }, + { "Otilde", 778, NULL }, + { "Emacron", 667, NULL }, + { "ellipsis", 1000, NULL }, + { "scaron", 389, NULL }, + { "AE", 1000, NULL }, + { "Ucircumflex", 722, NULL }, + { "lslash", 278, NULL }, + { "quotedblleft", 500, NULL }, + { "guilsinglright", 333, NULL }, + { "hyphen", 333, NULL }, + { "quotesingle", 278, NULL }, + { "eight", 500, NULL }, + { "exclamdown", 333, NULL }, + { "endash", 500, NULL }, + { "oe", 722, NULL }, + { "Abreve", 722, NULL }, + { "Umacron", 722, NULL }, + { "ecircumflex", 444, NULL }, + { "Adieresis", 722, NULL }, + { "copyright", 747, NULL }, + { "Egrave", 667, NULL }, + { "slash", 278, NULL }, + { "Edieresis", 667, NULL }, + { "otilde", 500, NULL }, + { "Idieresis", 389, NULL }, + { "parenleft", 333, NULL }, + { "one", 500, NULL }, + { "emacron", 444, NULL }, + { "Odieresis", 778, NULL }, + { "ucircumflex", 556, NULL }, + { "bracketleft", 333, NULL }, + { "Ugrave", 722, NULL }, + { "quoteright", 333, NULL }, + { "Udieresis", 722, NULL }, + { "perthousand", 1000, NULL }, + { "Ydieresis", 722, NULL }, + { "umacron", 556, NULL }, + { "abreve", 500, NULL }, + { "Eacute", 667, NULL }, + { "adieresis", 500, NULL }, + { "egrave", 444, NULL }, + { "edieresis", 444, NULL }, + { "idieresis", 278, NULL }, + { "Eth", 722, NULL }, + { "ae", 722, NULL }, + { "asterisk", 500, NULL }, + { "odieresis", 500, NULL }, + { "Uacute", 722, NULL }, + { "ugrave", 556, NULL }, + { "nine", 500, NULL }, + { "five", 500, NULL }, + { "udieresis", 556, NULL }, + { "Zcaron", 667, NULL }, + { "Scommaaccent", 556, NULL }, + { "threequarters", 750, NULL }, + { "guillemotright", 500, NULL }, + { "Ccedilla", 722, NULL }, + { "ydieresis", 500, NULL }, + { "tilde", 333, NULL }, + { "at", 930, NULL }, + { "eacute", 444, NULL }, + { "underscore", 500, NULL }, + { "Euro", 500, NULL }, + { "Dcroat", 722, NULL }, + { "multiply", 570, NULL }, + { "zero", 500, NULL }, + { "eth", 500, NULL }, + { "Scedilla", 556, NULL }, + { "Ograve", 778, NULL }, + { "Racute", 722, NULL }, + { "partialdiff", 494, NULL }, + { "uacute", 556, NULL }, + { "braceleft", 394, NULL }, + { "Thorn", 611, NULL }, + { "zcaron", 444, NULL }, + { "scommaaccent", 389, NULL }, + { "ccedilla", 444, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 556, NULL }, + { "Ocircumflex", 778, NULL }, + { "Oacute", 778, NULL }, + { "scedilla", 389, NULL }, + { "ogonek", 333, NULL }, + { "ograve", 500, NULL }, + { "racute", 444, NULL }, + { "Tcaron", 667, NULL }, + { "Eogonek", 667, NULL }, + { "thorn", 556, NULL }, + { "degree", 400, NULL }, + { "registered", 747, NULL }, + { "radical", 549, NULL }, + { "Aring", 722, NULL }, + { "percent", 1000, NULL }, + { "six", 500, NULL }, + { "paragraph", 540, NULL }, + { "dcaron", 672, NULL }, + { "Uogonek", 722, NULL }, + { "two", 500, NULL }, + { "summation", 600, NULL }, + { "Igrave", 389, NULL }, + { "Lacute", 667, NULL }, + { "ocircumflex", 500, NULL }, + { "oacute", 500, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 667, NULL }, + { "tcaron", 416, NULL }, + { "eogonek", 444, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 778, NULL }, + { "asciicircum", 581, NULL }, + { "aring", 500, NULL }, + { "grave", 333, NULL }, + { "uogonek", 556, NULL }, + { "bracketright", 333, NULL }, + { "Iacute", 389, NULL }, + { "ampersand", 833, NULL }, + { "igrave", 278, NULL }, + { "lacute", 278, NULL }, + { "Ncaron", 722, NULL }, + { "plus", 570, NULL }, + { "uring", 556, NULL }, + { "quotesinglbase", 333, NULL }, + { "lcommaaccent", 278, NULL }, + { "Yacute", 722, NULL }, + { "ohungarumlaut", 500, NULL }, + { "threesuperior", 300, NULL }, + { "acute", 333, NULL }, + { "section", 500, NULL }, + { "dieresis", 333, NULL }, + { "iacute", 278, NULL }, + { "quotedblbase", 500, NULL }, + { "ncaron", 556, NULL }, + { "florin", 500, NULL }, + { "yacute", 500, NULL }, + { "Rcommaaccent", 722, NULL }, + { "fi", 556, NULL }, + { "fl", 556, NULL }, + { "Acircumflex", 722, NULL }, + { "Cacute", 722, NULL }, + { "Icircumflex", 389, NULL }, + { "guillemotleft", 500, NULL }, + { "germandbls", 556, NULL }, + { "Amacron", 722, NULL }, + { "seven", 500, NULL }, + { "Sacute", 556, NULL }, + { "ordmasculine", 330, NULL }, + { "dotlessi", 278, NULL }, + { "sterling", 500, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 389, NULL }, + { "rcommaaccent", 444, NULL }, + { "Zdotaccent", 667, NULL }, + { "acircumflex", 500, NULL }, + { "cacute", 444, NULL }, + { "Ecaron", 667, NULL }, + { "icircumflex", 278, NULL }, + { "braceright", 394, NULL }, + { "quotedblright", 500, NULL }, + { "amacron", 500, NULL }, + { "sacute", 389, NULL }, + { "imacron", 278, NULL }, + { "cent", 500, NULL }, + { "currency", 500, NULL }, + { "logicalnot", 570, NULL }, + { "zdotaccent", 444, NULL }, + { "Atilde", 722, NULL }, + { "breve", 333, NULL }, + { "bar", 220, NULL }, + { "fraction", 167, NULL }, + { "less", 570, NULL }, + { "ecaron", 444, NULL }, + { "guilsinglleft", 333, NULL }, + { "exclam", 333, NULL }, + { "period", 250, NULL }, + { "Rcaron", 722, NULL }, + { "Kcommaaccent", 778, NULL }, + { "greater", 570, NULL }, + { "atilde", 500, NULL }, + { "brokenbar", 220, NULL }, + { "quoteleft", 333, NULL }, + { "Edotaccent", 667, NULL }, + { "onesuperior", 300, NULL } +}; + +static BuiltinFontWidth timesBoldItalicWidthsTab[] = { + { "Ntilde", 722, NULL }, + { "rcaron", 389, NULL }, + { "kcommaaccent", 500, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 611, NULL }, + { "comma", 250, NULL }, + { "cedilla", 333, NULL }, + { "plusminus", 570, NULL }, + { "circumflex", 333, NULL }, + { "dotaccent", 333, NULL }, + { "edotaccent", 444, NULL }, + { "asciitilde", 570, NULL }, + { "colon", 333, NULL }, + { "onehalf", 750, NULL }, + { "dollar", 500, NULL }, + { "Lcaron", 611, NULL }, + { "ntilde", 556, NULL }, + { "Aogonek", 667, NULL }, + { "ncommaaccent", 556, NULL }, + { "minus", 606, NULL }, + { "Iogonek", 389, NULL }, + { "zacute", 389, NULL }, + { "yen", 500, NULL }, + { "space", 250, NULL }, + { "Omacron", 722, NULL }, + { "questiondown", 500, NULL }, + { "emdash", 1000, NULL }, + { "Agrave", 667, NULL }, + { "three", 500, NULL }, + { "numbersign", 500, NULL }, + { "lcaron", 382, NULL }, + { "A", 667, NULL }, + { "B", 667, NULL }, + { "C", 667, NULL }, + { "aogonek", 500, NULL }, + { "D", 722, NULL }, + { "E", 667, NULL }, + { "onequarter", 750, NULL }, + { "F", 667, NULL }, + { "G", 722, NULL }, + { "H", 778, NULL }, + { "I", 389, NULL }, + { "J", 500, NULL }, + { "K", 667, NULL }, + { "iogonek", 278, NULL }, + { "backslash", 278, NULL }, + { "L", 611, NULL }, + { "periodcentered", 250, NULL }, + { "M", 889, NULL }, + { "N", 722, NULL }, + { "omacron", 500, NULL }, + { "Tcommaaccent", 611, NULL }, + { "O", 722, NULL }, + { "P", 611, NULL }, + { "Q", 722, NULL }, + { "Uhungarumlaut", 722, NULL }, + { "R", 667, NULL }, + { "Aacute", 667, NULL }, + { "caron", 333, NULL }, + { "S", 556, NULL }, + { "T", 611, NULL }, + { "U", 722, NULL }, + { "agrave", 500, NULL }, + { "V", 667, NULL }, + { "W", 889, NULL }, + { "X", 667, NULL }, + { "question", 500, NULL }, + { "equal", 570, NULL }, + { "Y", 611, NULL }, + { "Z", 611, NULL }, + { "four", 500, NULL }, + { "a", 500, NULL }, + { "Gcommaaccent", 722, NULL }, + { "b", 500, NULL }, + { "c", 444, NULL }, + { "d", 500, NULL }, + { "e", 444, NULL }, + { "f", 333, NULL }, + { "g", 500, NULL }, + { "bullet", 350, NULL }, + { "h", 556, NULL }, + { "i", 278, NULL }, + { "Oslash", 722, NULL }, + { "dagger", 500, NULL }, + { "j", 278, NULL }, + { "k", 500, NULL }, + { "l", 278, NULL }, + { "m", 778, NULL }, + { "n", 556, NULL }, + { "tcommaaccent", 278, NULL }, + { "o", 500, NULL }, + { "ordfeminine", 266, NULL }, + { "ring", 333, NULL }, + { "p", 500, NULL }, + { "q", 500, NULL }, + { "uhungarumlaut", 556, NULL }, + { "r", 389, NULL }, + { "twosuperior", 300, NULL }, + { "aacute", 500, NULL }, + { "s", 389, NULL }, + { "OE", 944, NULL }, + { "t", 278, NULL }, + { "divide", 570, NULL }, + { "u", 556, NULL }, + { "Ccaron", 667, NULL }, + { "v", 444, NULL }, + { "w", 667, NULL }, + { "x", 500, NULL }, + { "y", 444, NULL }, + { "z", 389, NULL }, + { "Gbreve", 722, NULL }, + { "commaaccent", 250, NULL }, + { "hungarumlaut", 333, NULL }, + { "Idotaccent", 389, NULL }, + { "Nacute", 722, NULL }, + { "quotedbl", 555, NULL }, + { "gcommaaccent", 500, NULL }, + { "mu", 576, NULL }, + { "greaterequal", 549, NULL }, + { "Scaron", 556, NULL }, + { "Lslash", 611, NULL }, + { "semicolon", 333, NULL }, + { "oslash", 500, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 494, NULL }, + { "parenright", 333, NULL }, + { "ccaron", 444, NULL }, + { "Ecircumflex", 667, NULL }, + { "gbreve", 500, NULL }, + { "trademark", 1000, NULL }, + { "daggerdbl", 500, NULL }, + { "nacute", 556, NULL }, + { "macron", 333, NULL }, + { "Otilde", 722, NULL }, + { "Emacron", 667, NULL }, + { "ellipsis", 1000, NULL }, + { "scaron", 389, NULL }, + { "AE", 944, NULL }, + { "Ucircumflex", 722, NULL }, + { "lslash", 278, NULL }, + { "quotedblleft", 500, NULL }, + { "guilsinglright", 333, NULL }, + { "hyphen", 333, NULL }, + { "quotesingle", 278, NULL }, + { "eight", 500, NULL }, + { "exclamdown", 389, NULL }, + { "endash", 500, NULL }, + { "oe", 722, NULL }, + { "Abreve", 667, NULL }, + { "Umacron", 722, NULL }, + { "ecircumflex", 444, NULL }, + { "Adieresis", 667, NULL }, + { "copyright", 747, NULL }, + { "Egrave", 667, NULL }, + { "slash", 278, NULL }, + { "Edieresis", 667, NULL }, + { "otilde", 500, NULL }, + { "Idieresis", 389, NULL }, + { "parenleft", 333, NULL }, + { "one", 500, NULL }, + { "emacron", 444, NULL }, + { "Odieresis", 722, NULL }, + { "ucircumflex", 556, NULL }, + { "bracketleft", 333, NULL }, + { "Ugrave", 722, NULL }, + { "quoteright", 333, NULL }, + { "Udieresis", 722, NULL }, + { "perthousand", 1000, NULL }, + { "Ydieresis", 611, NULL }, + { "umacron", 556, NULL }, + { "abreve", 500, NULL }, + { "Eacute", 667, NULL }, + { "adieresis", 500, NULL }, + { "egrave", 444, NULL }, + { "edieresis", 444, NULL }, + { "idieresis", 278, NULL }, + { "Eth", 722, NULL }, + { "ae", 722, NULL }, + { "asterisk", 500, NULL }, + { "odieresis", 500, NULL }, + { "Uacute", 722, NULL }, + { "ugrave", 556, NULL }, + { "nine", 500, NULL }, + { "five", 500, NULL }, + { "udieresis", 556, NULL }, + { "Zcaron", 611, NULL }, + { "Scommaaccent", 556, NULL }, + { "threequarters", 750, NULL }, + { "guillemotright", 500, NULL }, + { "Ccedilla", 667, NULL }, + { "ydieresis", 444, NULL }, + { "tilde", 333, NULL }, + { "at", 832, NULL }, + { "eacute", 444, NULL }, + { "underscore", 500, NULL }, + { "Euro", 500, NULL }, + { "Dcroat", 722, NULL }, + { "multiply", 570, NULL }, + { "zero", 500, NULL }, + { "eth", 500, NULL }, + { "Scedilla", 556, NULL }, + { "Ograve", 722, NULL }, + { "Racute", 667, NULL }, + { "partialdiff", 494, NULL }, + { "uacute", 556, NULL }, + { "braceleft", 348, NULL }, + { "Thorn", 611, NULL }, + { "zcaron", 389, NULL }, + { "scommaaccent", 389, NULL }, + { "ccedilla", 444, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 500, NULL }, + { "Ocircumflex", 722, NULL }, + { "Oacute", 722, NULL }, + { "scedilla", 389, NULL }, + { "ogonek", 333, NULL }, + { "ograve", 500, NULL }, + { "racute", 389, NULL }, + { "Tcaron", 611, NULL }, + { "Eogonek", 667, NULL }, + { "thorn", 500, NULL }, + { "degree", 400, NULL }, + { "registered", 747, NULL }, + { "radical", 549, NULL }, + { "Aring", 667, NULL }, + { "percent", 833, NULL }, + { "six", 500, NULL }, + { "paragraph", 500, NULL }, + { "dcaron", 608, NULL }, + { "Uogonek", 722, NULL }, + { "two", 500, NULL }, + { "summation", 600, NULL }, + { "Igrave", 389, NULL }, + { "Lacute", 611, NULL }, + { "ocircumflex", 500, NULL }, + { "oacute", 500, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 611, NULL }, + { "tcaron", 366, NULL }, + { "eogonek", 444, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 722, NULL }, + { "asciicircum", 570, NULL }, + { "aring", 500, NULL }, + { "grave", 333, NULL }, + { "uogonek", 556, NULL }, + { "bracketright", 333, NULL }, + { "Iacute", 389, NULL }, + { "ampersand", 778, NULL }, + { "igrave", 278, NULL }, + { "lacute", 278, NULL }, + { "Ncaron", 722, NULL }, + { "plus", 570, NULL }, + { "uring", 556, NULL }, + { "quotesinglbase", 333, NULL }, + { "lcommaaccent", 278, NULL }, + { "Yacute", 611, NULL }, + { "ohungarumlaut", 500, NULL }, + { "threesuperior", 300, NULL }, + { "acute", 333, NULL }, + { "section", 500, NULL }, + { "dieresis", 333, NULL }, + { "iacute", 278, NULL }, + { "quotedblbase", 500, NULL }, + { "ncaron", 556, NULL }, + { "florin", 500, NULL }, + { "yacute", 444, NULL }, + { "Rcommaaccent", 667, NULL }, + { "fi", 556, NULL }, + { "fl", 556, NULL }, + { "Acircumflex", 667, NULL }, + { "Cacute", 667, NULL }, + { "Icircumflex", 389, NULL }, + { "guillemotleft", 500, NULL }, + { "germandbls", 500, NULL }, + { "Amacron", 667, NULL }, + { "seven", 500, NULL }, + { "Sacute", 556, NULL }, + { "ordmasculine", 300, NULL }, + { "dotlessi", 278, NULL }, + { "sterling", 500, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 389, NULL }, + { "rcommaaccent", 389, NULL }, + { "Zdotaccent", 611, NULL }, + { "acircumflex", 500, NULL }, + { "cacute", 444, NULL }, + { "Ecaron", 667, NULL }, + { "icircumflex", 278, NULL }, + { "braceright", 348, NULL }, + { "quotedblright", 500, NULL }, + { "amacron", 500, NULL }, + { "sacute", 389, NULL }, + { "imacron", 278, NULL }, + { "cent", 500, NULL }, + { "currency", 500, NULL }, + { "logicalnot", 606, NULL }, + { "zdotaccent", 389, NULL }, + { "Atilde", 667, NULL }, + { "breve", 333, NULL }, + { "bar", 220, NULL }, + { "fraction", 167, NULL }, + { "less", 570, NULL }, + { "ecaron", 444, NULL }, + { "guilsinglleft", 333, NULL }, + { "exclam", 389, NULL }, + { "period", 250, NULL }, + { "Rcaron", 667, NULL }, + { "Kcommaaccent", 667, NULL }, + { "greater", 570, NULL }, + { "atilde", 500, NULL }, + { "brokenbar", 220, NULL }, + { "quoteleft", 333, NULL }, + { "Edotaccent", 667, NULL }, + { "onesuperior", 300, NULL } +}; + +static BuiltinFontWidth timesItalicWidthsTab[] = { + { "Ntilde", 667, NULL }, + { "rcaron", 389, NULL }, + { "kcommaaccent", 444, NULL }, + { "Ncommaaccent", 667, NULL }, + { "Zacute", 556, NULL }, + { "comma", 250, NULL }, + { "cedilla", 333, NULL }, + { "plusminus", 675, NULL }, + { "circumflex", 333, NULL }, + { "dotaccent", 333, NULL }, + { "edotaccent", 444, NULL }, + { "asciitilde", 541, NULL }, + { "colon", 333, NULL }, + { "onehalf", 750, NULL }, + { "dollar", 500, NULL }, + { "Lcaron", 611, NULL }, + { "ntilde", 500, NULL }, + { "Aogonek", 611, NULL }, + { "ncommaaccent", 500, NULL }, + { "minus", 675, NULL }, + { "Iogonek", 333, NULL }, + { "zacute", 389, NULL }, + { "yen", 500, NULL }, + { "space", 250, NULL }, + { "Omacron", 722, NULL }, + { "questiondown", 500, NULL }, + { "emdash", 889, NULL }, + { "Agrave", 611, NULL }, + { "three", 500, NULL }, + { "numbersign", 500, NULL }, + { "lcaron", 300, NULL }, + { "A", 611, NULL }, + { "B", 611, NULL }, + { "C", 667, NULL }, + { "aogonek", 500, NULL }, + { "D", 722, NULL }, + { "E", 611, NULL }, + { "onequarter", 750, NULL }, + { "F", 611, NULL }, + { "G", 722, NULL }, + { "H", 722, NULL }, + { "I", 333, NULL }, + { "J", 444, NULL }, + { "K", 667, NULL }, + { "iogonek", 278, NULL }, + { "backslash", 278, NULL }, + { "L", 556, NULL }, + { "periodcentered", 250, NULL }, + { "M", 833, NULL }, + { "N", 667, NULL }, + { "omacron", 500, NULL }, + { "Tcommaaccent", 556, NULL }, + { "O", 722, NULL }, + { "P", 611, NULL }, + { "Q", 722, NULL }, + { "Uhungarumlaut", 722, NULL }, + { "R", 611, NULL }, + { "Aacute", 611, NULL }, + { "caron", 333, NULL }, + { "S", 500, NULL }, + { "T", 556, NULL }, + { "U", 722, NULL }, + { "agrave", 500, NULL }, + { "V", 611, NULL }, + { "W", 833, NULL }, + { "X", 611, NULL }, + { "question", 500, NULL }, + { "equal", 675, NULL }, + { "Y", 556, NULL }, + { "Z", 556, NULL }, + { "four", 500, NULL }, + { "a", 500, NULL }, + { "Gcommaaccent", 722, NULL }, + { "b", 500, NULL }, + { "c", 444, NULL }, + { "d", 500, NULL }, + { "e", 444, NULL }, + { "f", 278, NULL }, + { "g", 500, NULL }, + { "bullet", 350, NULL }, + { "h", 500, NULL }, + { "i", 278, NULL }, + { "Oslash", 722, NULL }, + { "dagger", 500, NULL }, + { "j", 278, NULL }, + { "k", 444, NULL }, + { "l", 278, NULL }, + { "m", 722, NULL }, + { "n", 500, NULL }, + { "tcommaaccent", 278, NULL }, + { "o", 500, NULL }, + { "ordfeminine", 276, NULL }, + { "ring", 333, NULL }, + { "p", 500, NULL }, + { "q", 500, NULL }, + { "uhungarumlaut", 500, NULL }, + { "r", 389, NULL }, + { "twosuperior", 300, NULL }, + { "aacute", 500, NULL }, + { "s", 389, NULL }, + { "OE", 944, NULL }, + { "t", 278, NULL }, + { "divide", 675, NULL }, + { "u", 500, NULL }, + { "Ccaron", 667, NULL }, + { "v", 444, NULL }, + { "w", 667, NULL }, + { "x", 444, NULL }, + { "y", 444, NULL }, + { "z", 389, NULL }, + { "Gbreve", 722, NULL }, + { "commaaccent", 250, NULL }, + { "hungarumlaut", 333, NULL }, + { "Idotaccent", 333, NULL }, + { "Nacute", 667, NULL }, + { "quotedbl", 420, NULL }, + { "gcommaaccent", 500, NULL }, + { "mu", 500, NULL }, + { "greaterequal", 549, NULL }, + { "Scaron", 500, NULL }, + { "Lslash", 556, NULL }, + { "semicolon", 333, NULL }, + { "oslash", 500, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 471, NULL }, + { "parenright", 333, NULL }, + { "ccaron", 444, NULL }, + { "Ecircumflex", 611, NULL }, + { "gbreve", 500, NULL }, + { "trademark", 980, NULL }, + { "daggerdbl", 500, NULL }, + { "nacute", 500, NULL }, + { "macron", 333, NULL }, + { "Otilde", 722, NULL }, + { "Emacron", 611, NULL }, + { "ellipsis", 889, NULL }, + { "scaron", 389, NULL }, + { "AE", 889, NULL }, + { "Ucircumflex", 722, NULL }, + { "lslash", 278, NULL }, + { "quotedblleft", 556, NULL }, + { "guilsinglright", 333, NULL }, + { "hyphen", 333, NULL }, + { "quotesingle", 214, NULL }, + { "eight", 500, NULL }, + { "exclamdown", 389, NULL }, + { "endash", 500, NULL }, + { "oe", 667, NULL }, + { "Abreve", 611, NULL }, + { "Umacron", 722, NULL }, + { "ecircumflex", 444, NULL }, + { "Adieresis", 611, NULL }, + { "copyright", 760, NULL }, + { "Egrave", 611, NULL }, + { "slash", 278, NULL }, + { "Edieresis", 611, NULL }, + { "otilde", 500, NULL }, + { "Idieresis", 333, NULL }, + { "parenleft", 333, NULL }, + { "one", 500, NULL }, + { "emacron", 444, NULL }, + { "Odieresis", 722, NULL }, + { "ucircumflex", 500, NULL }, + { "bracketleft", 389, NULL }, + { "Ugrave", 722, NULL }, + { "quoteright", 333, NULL }, + { "Udieresis", 722, NULL }, + { "perthousand", 1000, NULL }, + { "Ydieresis", 556, NULL }, + { "umacron", 500, NULL }, + { "abreve", 500, NULL }, + { "Eacute", 611, NULL }, + { "adieresis", 500, NULL }, + { "egrave", 444, NULL }, + { "edieresis", 444, NULL }, + { "idieresis", 278, NULL }, + { "Eth", 722, NULL }, + { "ae", 667, NULL }, + { "asterisk", 500, NULL }, + { "odieresis", 500, NULL }, + { "Uacute", 722, NULL }, + { "ugrave", 500, NULL }, + { "nine", 500, NULL }, + { "five", 500, NULL }, + { "udieresis", 500, NULL }, + { "Zcaron", 556, NULL }, + { "Scommaaccent", 500, NULL }, + { "threequarters", 750, NULL }, + { "guillemotright", 500, NULL }, + { "Ccedilla", 667, NULL }, + { "ydieresis", 444, NULL }, + { "tilde", 333, NULL }, + { "at", 920, NULL }, + { "eacute", 444, NULL }, + { "underscore", 500, NULL }, + { "Euro", 500, NULL }, + { "Dcroat", 722, NULL }, + { "multiply", 675, NULL }, + { "zero", 500, NULL }, + { "eth", 500, NULL }, + { "Scedilla", 500, NULL }, + { "Ograve", 722, NULL }, + { "Racute", 611, NULL }, + { "partialdiff", 476, NULL }, + { "uacute", 500, NULL }, + { "braceleft", 400, NULL }, + { "Thorn", 611, NULL }, + { "zcaron", 389, NULL }, + { "scommaaccent", 389, NULL }, + { "ccedilla", 444, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 500, NULL }, + { "Ocircumflex", 722, NULL }, + { "Oacute", 722, NULL }, + { "scedilla", 389, NULL }, + { "ogonek", 333, NULL }, + { "ograve", 500, NULL }, + { "racute", 389, NULL }, + { "Tcaron", 556, NULL }, + { "Eogonek", 611, NULL }, + { "thorn", 500, NULL }, + { "degree", 400, NULL }, + { "registered", 760, NULL }, + { "radical", 453, NULL }, + { "Aring", 611, NULL }, + { "percent", 833, NULL }, + { "six", 500, NULL }, + { "paragraph", 523, NULL }, + { "dcaron", 544, NULL }, + { "Uogonek", 722, NULL }, + { "two", 500, NULL }, + { "summation", 600, NULL }, + { "Igrave", 333, NULL }, + { "Lacute", 556, NULL }, + { "ocircumflex", 500, NULL }, + { "oacute", 500, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 556, NULL }, + { "tcaron", 300, NULL }, + { "eogonek", 444, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 722, NULL }, + { "asciicircum", 422, NULL }, + { "aring", 500, NULL }, + { "grave", 333, NULL }, + { "uogonek", 500, NULL }, + { "bracketright", 389, NULL }, + { "Iacute", 333, NULL }, + { "ampersand", 778, NULL }, + { "igrave", 278, NULL }, + { "lacute", 278, NULL }, + { "Ncaron", 667, NULL }, + { "plus", 675, NULL }, + { "uring", 500, NULL }, + { "quotesinglbase", 333, NULL }, + { "lcommaaccent", 278, NULL }, + { "Yacute", 556, NULL }, + { "ohungarumlaut", 500, NULL }, + { "threesuperior", 300, NULL }, + { "acute", 333, NULL }, + { "section", 500, NULL }, + { "dieresis", 333, NULL }, + { "iacute", 278, NULL }, + { "quotedblbase", 556, NULL }, + { "ncaron", 500, NULL }, + { "florin", 500, NULL }, + { "yacute", 444, NULL }, + { "Rcommaaccent", 611, NULL }, + { "fi", 500, NULL }, + { "fl", 500, NULL }, + { "Acircumflex", 611, NULL }, + { "Cacute", 667, NULL }, + { "Icircumflex", 333, NULL }, + { "guillemotleft", 500, NULL }, + { "germandbls", 500, NULL }, + { "Amacron", 611, NULL }, + { "seven", 500, NULL }, + { "Sacute", 500, NULL }, + { "ordmasculine", 310, NULL }, + { "dotlessi", 278, NULL }, + { "sterling", 500, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 333, NULL }, + { "rcommaaccent", 389, NULL }, + { "Zdotaccent", 556, NULL }, + { "acircumflex", 500, NULL }, + { "cacute", 444, NULL }, + { "Ecaron", 611, NULL }, + { "icircumflex", 278, NULL }, + { "braceright", 400, NULL }, + { "quotedblright", 556, NULL }, + { "amacron", 500, NULL }, + { "sacute", 389, NULL }, + { "imacron", 278, NULL }, + { "cent", 500, NULL }, + { "currency", 500, NULL }, + { "logicalnot", 675, NULL }, + { "zdotaccent", 389, NULL }, + { "Atilde", 611, NULL }, + { "breve", 333, NULL }, + { "bar", 275, NULL }, + { "fraction", 167, NULL }, + { "less", 675, NULL }, + { "ecaron", 444, NULL }, + { "guilsinglleft", 333, NULL }, + { "exclam", 333, NULL }, + { "period", 250, NULL }, + { "Rcaron", 611, NULL }, + { "Kcommaaccent", 667, NULL }, + { "greater", 675, NULL }, + { "atilde", 500, NULL }, + { "brokenbar", 275, NULL }, + { "quoteleft", 333, NULL }, + { "Edotaccent", 611, NULL }, + { "onesuperior", 300, NULL } +}; + +static BuiltinFontWidth timesRomanWidthsTab[] = { + { "Ntilde", 722, NULL }, + { "rcaron", 333, NULL }, + { "kcommaaccent", 500, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 611, NULL }, + { "comma", 250, NULL }, + { "cedilla", 333, NULL }, + { "plusminus", 564, NULL }, + { "circumflex", 333, NULL }, + { "dotaccent", 333, NULL }, + { "edotaccent", 444, NULL }, + { "asciitilde", 541, NULL }, + { "colon", 278, NULL }, + { "onehalf", 750, NULL }, + { "dollar", 500, NULL }, + { "Lcaron", 611, NULL }, + { "ntilde", 500, NULL }, + { "Aogonek", 722, NULL }, + { "ncommaaccent", 500, NULL }, + { "minus", 564, NULL }, + { "Iogonek", 333, NULL }, + { "zacute", 444, NULL }, + { "yen", 500, NULL }, + { "space", 250, NULL }, + { "Omacron", 722, NULL }, + { "questiondown", 444, NULL }, + { "emdash", 1000, NULL }, + { "Agrave", 722, NULL }, + { "three", 500, NULL }, + { "numbersign", 500, NULL }, + { "lcaron", 344, NULL }, + { "A", 722, NULL }, + { "B", 667, NULL }, + { "C", 667, NULL }, + { "aogonek", 444, NULL }, + { "D", 722, NULL }, + { "E", 611, NULL }, + { "onequarter", 750, NULL }, + { "F", 556, NULL }, + { "G", 722, NULL }, + { "H", 722, NULL }, + { "I", 333, NULL }, + { "J", 389, NULL }, + { "K", 722, NULL }, + { "iogonek", 278, NULL }, + { "backslash", 278, NULL }, + { "L", 611, NULL }, + { "periodcentered", 250, NULL }, + { "M", 889, NULL }, + { "N", 722, NULL }, + { "omacron", 500, NULL }, + { "Tcommaaccent", 611, NULL }, + { "O", 722, NULL }, + { "P", 556, NULL }, + { "Q", 722, NULL }, + { "Uhungarumlaut", 722, NULL }, + { "R", 667, NULL }, + { "Aacute", 722, NULL }, + { "caron", 333, NULL }, + { "S", 556, NULL }, + { "T", 611, NULL }, + { "U", 722, NULL }, + { "agrave", 444, NULL }, + { "V", 722, NULL }, + { "W", 944, NULL }, + { "X", 722, NULL }, + { "question", 444, NULL }, + { "equal", 564, NULL }, + { "Y", 722, NULL }, + { "Z", 611, NULL }, + { "four", 500, NULL }, + { "a", 444, NULL }, + { "Gcommaaccent", 722, NULL }, + { "b", 500, NULL }, + { "c", 444, NULL }, + { "d", 500, NULL }, + { "e", 444, NULL }, + { "f", 333, NULL }, + { "g", 500, NULL }, + { "bullet", 350, NULL }, + { "h", 500, NULL }, + { "i", 278, NULL }, + { "Oslash", 722, NULL }, + { "dagger", 500, NULL }, + { "j", 278, NULL }, + { "k", 500, NULL }, + { "l", 278, NULL }, + { "m", 778, NULL }, + { "n", 500, NULL }, + { "tcommaaccent", 278, NULL }, + { "o", 500, NULL }, + { "ordfeminine", 276, NULL }, + { "ring", 333, NULL }, + { "p", 500, NULL }, + { "q", 500, NULL }, + { "uhungarumlaut", 500, NULL }, + { "r", 333, NULL }, + { "twosuperior", 300, NULL }, + { "aacute", 444, NULL }, + { "s", 389, NULL }, + { "OE", 889, NULL }, + { "t", 278, NULL }, + { "divide", 564, NULL }, + { "u", 500, NULL }, + { "Ccaron", 667, NULL }, + { "v", 500, NULL }, + { "w", 722, NULL }, + { "x", 500, NULL }, + { "y", 500, NULL }, + { "z", 444, NULL }, + { "Gbreve", 722, NULL }, + { "commaaccent", 250, NULL }, + { "hungarumlaut", 333, NULL }, + { "Idotaccent", 333, NULL }, + { "Nacute", 722, NULL }, + { "quotedbl", 408, NULL }, + { "gcommaaccent", 500, NULL }, + { "mu", 500, NULL }, + { "greaterequal", 549, NULL }, + { "Scaron", 556, NULL }, + { "Lslash", 611, NULL }, + { "semicolon", 278, NULL }, + { "oslash", 500, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 471, NULL }, + { "parenright", 333, NULL }, + { "ccaron", 444, NULL }, + { "Ecircumflex", 611, NULL }, + { "gbreve", 500, NULL }, + { "trademark", 980, NULL }, + { "daggerdbl", 500, NULL }, + { "nacute", 500, NULL }, + { "macron", 333, NULL }, + { "Otilde", 722, NULL }, + { "Emacron", 611, NULL }, + { "ellipsis", 1000, NULL }, + { "scaron", 389, NULL }, + { "AE", 889, NULL }, + { "Ucircumflex", 722, NULL }, + { "lslash", 278, NULL }, + { "quotedblleft", 444, NULL }, + { "guilsinglright", 333, NULL }, + { "hyphen", 333, NULL }, + { "quotesingle", 180, NULL }, + { "eight", 500, NULL }, + { "exclamdown", 333, NULL }, + { "endash", 500, NULL }, + { "oe", 722, NULL }, + { "Abreve", 722, NULL }, + { "Umacron", 722, NULL }, + { "ecircumflex", 444, NULL }, + { "Adieresis", 722, NULL }, + { "copyright", 760, NULL }, + { "Egrave", 611, NULL }, + { "slash", 278, NULL }, + { "Edieresis", 611, NULL }, + { "otilde", 500, NULL }, + { "Idieresis", 333, NULL }, + { "parenleft", 333, NULL }, + { "one", 500, NULL }, + { "emacron", 444, NULL }, + { "Odieresis", 722, NULL }, + { "ucircumflex", 500, NULL }, + { "bracketleft", 333, NULL }, + { "Ugrave", 722, NULL }, + { "quoteright", 333, NULL }, + { "Udieresis", 722, NULL }, + { "perthousand", 1000, NULL }, + { "Ydieresis", 722, NULL }, + { "umacron", 500, NULL }, + { "abreve", 444, NULL }, + { "Eacute", 611, NULL }, + { "adieresis", 444, NULL }, + { "egrave", 444, NULL }, + { "edieresis", 444, NULL }, + { "idieresis", 278, NULL }, + { "Eth", 722, NULL }, + { "ae", 667, NULL }, + { "asterisk", 500, NULL }, + { "odieresis", 500, NULL }, + { "Uacute", 722, NULL }, + { "ugrave", 500, NULL }, + { "nine", 500, NULL }, + { "five", 500, NULL }, + { "udieresis", 500, NULL }, + { "Zcaron", 611, NULL }, + { "Scommaaccent", 556, NULL }, + { "threequarters", 750, NULL }, + { "guillemotright", 500, NULL }, + { "Ccedilla", 667, NULL }, + { "ydieresis", 500, NULL }, + { "tilde", 333, NULL }, + { "at", 921, NULL }, + { "eacute", 444, NULL }, + { "underscore", 500, NULL }, + { "Euro", 500, NULL }, + { "Dcroat", 722, NULL }, + { "multiply", 564, NULL }, + { "zero", 500, NULL }, + { "eth", 500, NULL }, + { "Scedilla", 556, NULL }, + { "Ograve", 722, NULL }, + { "Racute", 667, NULL }, + { "partialdiff", 476, NULL }, + { "uacute", 500, NULL }, + { "braceleft", 480, NULL }, + { "Thorn", 556, NULL }, + { "zcaron", 444, NULL }, + { "scommaaccent", 389, NULL }, + { "ccedilla", 444, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 500, NULL }, + { "Ocircumflex", 722, NULL }, + { "Oacute", 722, NULL }, + { "scedilla", 389, NULL }, + { "ogonek", 333, NULL }, + { "ograve", 500, NULL }, + { "racute", 333, NULL }, + { "Tcaron", 611, NULL }, + { "Eogonek", 611, NULL }, + { "thorn", 500, NULL }, + { "degree", 400, NULL }, + { "registered", 760, NULL }, + { "radical", 453, NULL }, + { "Aring", 722, NULL }, + { "percent", 833, NULL }, + { "six", 500, NULL }, + { "paragraph", 453, NULL }, + { "dcaron", 588, NULL }, + { "Uogonek", 722, NULL }, + { "two", 500, NULL }, + { "summation", 600, NULL }, + { "Igrave", 333, NULL }, + { "Lacute", 611, NULL }, + { "ocircumflex", 500, NULL }, + { "oacute", 500, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 611, NULL }, + { "tcaron", 326, NULL }, + { "eogonek", 444, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 722, NULL }, + { "asciicircum", 469, NULL }, + { "aring", 444, NULL }, + { "grave", 333, NULL }, + { "uogonek", 500, NULL }, + { "bracketright", 333, NULL }, + { "Iacute", 333, NULL }, + { "ampersand", 778, NULL }, + { "igrave", 278, NULL }, + { "lacute", 278, NULL }, + { "Ncaron", 722, NULL }, + { "plus", 564, NULL }, + { "uring", 500, NULL }, + { "quotesinglbase", 333, NULL }, + { "lcommaaccent", 278, NULL }, + { "Yacute", 722, NULL }, + { "ohungarumlaut", 500, NULL }, + { "threesuperior", 300, NULL }, + { "acute", 333, NULL }, + { "section", 500, NULL }, + { "dieresis", 333, NULL }, + { "iacute", 278, NULL }, + { "quotedblbase", 444, NULL }, + { "ncaron", 500, NULL }, + { "florin", 500, NULL }, + { "yacute", 500, NULL }, + { "Rcommaaccent", 667, NULL }, + { "fi", 556, NULL }, + { "fl", 556, NULL }, + { "Acircumflex", 722, NULL }, + { "Cacute", 667, NULL }, + { "Icircumflex", 333, NULL }, + { "guillemotleft", 500, NULL }, + { "germandbls", 500, NULL }, + { "Amacron", 722, NULL }, + { "seven", 500, NULL }, + { "Sacute", 556, NULL }, + { "ordmasculine", 310, NULL }, + { "dotlessi", 278, NULL }, + { "sterling", 500, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 333, NULL }, + { "rcommaaccent", 333, NULL }, + { "Zdotaccent", 611, NULL }, + { "acircumflex", 444, NULL }, + { "cacute", 444, NULL }, + { "Ecaron", 611, NULL }, + { "icircumflex", 278, NULL }, + { "braceright", 480, NULL }, + { "quotedblright", 444, NULL }, + { "amacron", 444, NULL }, + { "sacute", 389, NULL }, + { "imacron", 278, NULL }, + { "cent", 500, NULL }, + { "currency", 500, NULL }, + { "logicalnot", 564, NULL }, + { "zdotaccent", 444, NULL }, + { "Atilde", 722, NULL }, + { "breve", 333, NULL }, + { "bar", 200, NULL }, + { "fraction", 167, NULL }, + { "less", 564, NULL }, + { "ecaron", 444, NULL }, + { "guilsinglleft", 333, NULL }, + { "exclam", 333, NULL }, + { "period", 250, NULL }, + { "Rcaron", 667, NULL }, + { "Kcommaaccent", 722, NULL }, + { "greater", 564, NULL }, + { "atilde", 444, NULL }, + { "brokenbar", 200, NULL }, + { "quoteleft", 333, NULL }, + { "Edotaccent", 611, NULL }, + { "onesuperior", 300, NULL } +}; + +static BuiltinFontWidth zapfDingbatsWidthsTab[] = { + { "a81", 438, NULL }, + { "a82", 138, NULL }, + { "a83", 277, NULL }, + { "a84", 415, NULL }, + { "a85", 509, NULL }, + { "a86", 410, NULL }, + { "a87", 234, NULL }, + { "a88", 234, NULL }, + { "a89", 390, NULL }, + { "a140", 788, NULL }, + { "a141", 788, NULL }, + { "a142", 788, NULL }, + { "a143", 788, NULL }, + { "a144", 788, NULL }, + { "a145", 788, NULL }, + { "a146", 788, NULL }, + { "a147", 788, NULL }, + { "a148", 788, NULL }, + { "a149", 788, NULL }, + { "a90", 390, NULL }, + { "a91", 276, NULL }, + { "a92", 276, NULL }, + { "space", 278, NULL }, + { "a93", 317, NULL }, + { "a94", 317, NULL }, + { "a95", 334, NULL }, + { "a96", 334, NULL }, + { "a97", 392, NULL }, + { "a98", 392, NULL }, + { "a99", 668, NULL }, + { "a150", 788, NULL }, + { "a151", 788, NULL }, + { "a152", 788, NULL }, + { "a153", 788, NULL }, + { "a154", 788, NULL }, + { "a155", 788, NULL }, + { "a156", 788, NULL }, + { "a157", 788, NULL }, + { "a158", 788, NULL }, + { "a159", 788, NULL }, + { "a160", 894, NULL }, + { "a161", 838, NULL }, + { "a162", 924, NULL }, + { "a163", 1016, NULL }, + { "a164", 458, NULL }, + { "a165", 924, NULL }, + { "a166", 918, NULL }, + { "a167", 927, NULL }, + { "a168", 928, NULL }, + { "a169", 928, NULL }, + { "a170", 834, NULL }, + { "a171", 873, NULL }, + { "a172", 828, NULL }, + { "a173", 924, NULL }, + { "a174", 917, NULL }, + { "a175", 930, NULL }, + { "a176", 931, NULL }, + { "a177", 463, NULL }, + { "a178", 883, NULL }, + { "a179", 836, NULL }, + { "a180", 867, NULL }, + { "a181", 696, NULL }, + { "a182", 874, NULL }, + { "a183", 760, NULL }, + { "a184", 946, NULL }, + { "a185", 865, NULL }, + { "a186", 967, NULL }, + { "a187", 831, NULL }, + { "a188", 873, NULL }, + { "a189", 927, NULL }, + { "a1", 974, NULL }, + { "a2", 961, NULL }, + { "a3", 980, NULL }, + { "a4", 719, NULL }, + { "a5", 789, NULL }, + { "a6", 494, NULL }, + { "a7", 552, NULL }, + { "a8", 537, NULL }, + { "a9", 577, NULL }, + { "a190", 970, NULL }, + { "a191", 918, NULL }, + { "a192", 748, NULL }, + { "a193", 836, NULL }, + { "a194", 771, NULL }, + { "a195", 888, NULL }, + { "a196", 748, NULL }, + { "a197", 771, NULL }, + { "a198", 888, NULL }, + { "a199", 867, NULL }, + { "a10", 692, NULL }, + { "a11", 960, NULL }, + { "a12", 939, NULL }, + { "a13", 549, NULL }, + { "a14", 855, NULL }, + { "a15", 911, NULL }, + { "a16", 933, NULL }, + { "a17", 945, NULL }, + { "a18", 974, NULL }, + { "a19", 755, NULL }, + { "a20", 846, NULL }, + { "a21", 762, NULL }, + { "a22", 761, NULL }, + { "a23", 571, NULL }, + { "a24", 677, NULL }, + { "a25", 763, NULL }, + { "a26", 760, NULL }, + { "a27", 759, NULL }, + { "a28", 754, NULL }, + { "a29", 786, NULL }, + { "a30", 788, NULL }, + { "a31", 788, NULL }, + { "a32", 790, NULL }, + { "a33", 793, NULL }, + { "a34", 794, NULL }, + { "a35", 816, NULL }, + { "a36", 823, NULL }, + { "a37", 789, NULL }, + { "a38", 841, NULL }, + { "a39", 823, NULL }, + { "a40", 833, NULL }, + { "a41", 816, NULL }, + { "a42", 831, NULL }, + { "a43", 923, NULL }, + { "a44", 744, NULL }, + { "a45", 723, NULL }, + { "a46", 749, NULL }, + { "a47", 790, NULL }, + { "a48", 792, NULL }, + { "a49", 695, NULL }, + { "a100", 668, NULL }, + { "a101", 732, NULL }, + { "a102", 544, NULL }, + { "a103", 544, NULL }, + { "a104", 910, NULL }, + { "a105", 911, NULL }, + { "a106", 667, NULL }, + { "a107", 760, NULL }, + { "a108", 760, NULL }, + { "a109", 626, NULL }, + { "a50", 776, NULL }, + { "a51", 768, NULL }, + { "a52", 792, NULL }, + { "a53", 759, NULL }, + { "a54", 707, NULL }, + { "a55", 708, NULL }, + { "a56", 682, NULL }, + { "a57", 701, NULL }, + { "a58", 826, NULL }, + { "a59", 815, NULL }, + { "a110", 694, NULL }, + { "a111", 595, NULL }, + { "a112", 776, NULL }, + { "a117", 690, NULL }, + { "a118", 791, NULL }, + { "a119", 790, NULL }, + { "a60", 789, NULL }, + { "a61", 789, NULL }, + { "a62", 707, NULL }, + { "a63", 687, NULL }, + { "a64", 696, NULL }, + { "a65", 689, NULL }, + { "a66", 786, NULL }, + { "a67", 787, NULL }, + { "a68", 713, NULL }, + { "a69", 791, NULL }, + { "a200", 696, NULL }, + { "a201", 874, NULL }, + { "a120", 788, NULL }, + { "a121", 788, NULL }, + { "a202", 974, NULL }, + { "a122", 788, NULL }, + { "a203", 762, NULL }, + { "a123", 788, NULL }, + { "a204", 759, NULL }, + { "a124", 788, NULL }, + { "a205", 509, NULL }, + { "a125", 788, NULL }, + { "a206", 410, NULL }, + { "a126", 788, NULL }, + { "a127", 788, NULL }, + { "a128", 788, NULL }, + { "a129", 788, NULL }, + { "a70", 785, NULL }, + { "a71", 791, NULL }, + { "a72", 873, NULL }, + { "a73", 761, NULL }, + { "a74", 762, NULL }, + { "a75", 759, NULL }, + { "a76", 892, NULL }, + { "a77", 892, NULL }, + { "a78", 788, NULL }, + { "a79", 784, NULL }, + { "a130", 788, NULL }, + { "a131", 788, NULL }, + { "a132", 788, NULL }, + { "a133", 788, NULL }, + { "a134", 788, NULL }, + { "a135", 788, NULL }, + { "a136", 788, NULL }, + { "a137", 788, NULL }, + { "a138", 788, NULL }, + { "a139", 788, NULL } +}; + +BuiltinFont builtinFonts[] = { + { "Courier", standardEncoding, 629, -157, { -23, -250, 715, 805}, NULL }, + { "Courier-Bold", standardEncoding, 629, -157, {-113, -250, 749, 801}, NULL }, + { "Courier-BoldOblique", standardEncoding, 629, -157, { -57, -250, 869, 801}, NULL }, + { "Courier-Oblique", standardEncoding, 629, -157, { -27, -250, 849, 805}, NULL }, + { "Helvetica", standardEncoding, 718, -207, {-166, -225, 1000, 931}, NULL }, + { "Helvetica-Bold", standardEncoding, 718, -207, {-170, -228, 1003, 962}, NULL }, + { "Helvetica-BoldOblique", standardEncoding, 718, -207, {-174, -228, 1114, 962}, NULL }, + { "Helvetica-Oblique", standardEncoding, 718, -207, {-170, -225, 1116, 931}, NULL }, + { "Symbol", symbolEncoding, 1010, -293, {-180, -293, 1090, 1010}, NULL }, + { "Times-Bold", standardEncoding, 683, -217, {-168, -218, 1000, 935}, NULL }, + { "Times-BoldItalic", standardEncoding, 683, -217, {-200, -218, 996, 921}, NULL }, + { "Times-Italic", standardEncoding, 683, -217, {-169, -217, 1010, 883}, NULL }, + { "Times-Roman", standardEncoding, 683, -217, {-168, -218, 1000, 898}, NULL }, + { "ZapfDingbats", zapfDingbatsEncoding, 820, -143, { -1, -143, 981, 820}, NULL } +}; + +BuiltinFont *builtinFontSubst[] = { + &builtinFonts[0], + &builtinFonts[3], + &builtinFonts[1], + &builtinFonts[2], + &builtinFonts[4], + &builtinFonts[7], + &builtinFonts[5], + &builtinFonts[6], + &builtinFonts[12], + &builtinFonts[11], + &builtinFonts[9], + &builtinFonts[10] +}; + +void initBuiltinFontTables() { + builtinFonts[0].widths = new BuiltinFontWidths(courierWidthsTab, 315); + builtinFonts[1].widths = new BuiltinFontWidths(courierBoldWidthsTab, 315); + builtinFonts[2].widths = new BuiltinFontWidths(courierBoldObliqueWidthsTab, 315); + builtinFonts[3].widths = new BuiltinFontWidths(courierObliqueWidthsTab, 315); + builtinFonts[4].widths = new BuiltinFontWidths(helveticaWidthsTab, 315); + builtinFonts[5].widths = new BuiltinFontWidths(helveticaBoldWidthsTab, 316); + builtinFonts[6].widths = new BuiltinFontWidths(helveticaBoldObliqueWidthsTab, 315); + builtinFonts[7].widths = new BuiltinFontWidths(helveticaObliqueWidthsTab, 315); + builtinFonts[8].widths = new BuiltinFontWidths(symbolWidthsTab, 190); + builtinFonts[9].widths = new BuiltinFontWidths(timesBoldWidthsTab, 315); + builtinFonts[10].widths = new BuiltinFontWidths(timesBoldItalicWidthsTab, 315); + builtinFonts[11].widths = new BuiltinFontWidths(timesItalicWidthsTab, 315); + builtinFonts[12].widths = new BuiltinFontWidths(timesRomanWidthsTab, 315); + builtinFonts[13].widths = new BuiltinFontWidths(zapfDingbatsWidthsTab, 202); +} + +void freeBuiltinFontTables() { + int i; + + for (i = 0; i < 14; ++i) { + delete builtinFonts[i].widths; + } +} diff --git a/kpdf/xpdf/xpdf/BuiltinFontTables.h b/kpdf/xpdf/xpdf/BuiltinFontTables.h new file mode 100644 index 00000000..eb45549e --- /dev/null +++ b/kpdf/xpdf/xpdf/BuiltinFontTables.h @@ -0,0 +1,23 @@ +//======================================================================== +// +// BuiltinFontTables.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef BUILTINFONTTABLES_H +#define BUILTINFONTTABLES_H + +#include "BuiltinFont.h" + +#define nBuiltinFonts 14 +#define nBuiltinFontSubsts 12 + +extern BuiltinFont builtinFonts[nBuiltinFonts]; +extern BuiltinFont *builtinFontSubst[nBuiltinFontSubsts]; + +extern void initBuiltinFontTables(); +extern void freeBuiltinFontTables(); + +#endif diff --git a/kpdf/xpdf/xpdf/CMap.cc b/kpdf/xpdf/xpdf/CMap.cc new file mode 100644 index 00000000..89905a8c --- /dev/null +++ b/kpdf/xpdf/xpdf/CMap.cc @@ -0,0 +1,408 @@ +//======================================================================== +// +// CMap.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include +#include "gmem.h" +#include "gfile.h" +#include "GString.h" +#include "Error.h" +#include "GlobalParams.h" +#include "PSTokenizer.h" +#include "CMap.h" + +//------------------------------------------------------------------------ + +struct CMapVectorEntry { + GBool isVector; + union { + CMapVectorEntry *vector; + CID cid; + }; +}; + +//------------------------------------------------------------------------ + +static int CMap_getCharFromFile(void *data) { + return fgetc((FILE *)data); +} + +//------------------------------------------------------------------------ + +CMap *CMap::parse(CMapCache *cache, GString *collectionA, + GString *cMapNameA) { + FILE *f; + CMap *cmap; + PSTokenizer *pst; + char tok1[256], tok2[256], tok3[256]; + int n1, n2, n3; + Guint start, end, code; + + if (!(f = globalParams->findCMapFile(collectionA, cMapNameA))) { + + // Check for an identity CMap. + if (!cMapNameA->cmp("Identity") || !cMapNameA->cmp("Identity-H")) { + return new CMap(collectionA->copy(), cMapNameA->copy(), 0); + } + if (!cMapNameA->cmp("Identity-V")) { + return new CMap(collectionA->copy(), cMapNameA->copy(), 1); + } + + error(-1, "Couldn't find '%s' CMap file for '%s' collection", + cMapNameA->getCString(), collectionA->getCString()); + return NULL; + } + + cmap = new CMap(collectionA->copy(), cMapNameA->copy()); + + pst = new PSTokenizer(&CMap_getCharFromFile, f); + pst->getToken(tok1, sizeof(tok1), &n1); + while (pst->getToken(tok2, sizeof(tok2), &n2)) { + if (!strcmp(tok2, "usecmap")) { + if (tok1[0] == '/') { + cmap->useCMap(cache, tok1 + 1); + } + pst->getToken(tok1, sizeof(tok1), &n1); + } else if (!strcmp(tok1, "/WMode")) { + cmap->wMode = atoi(tok2); + pst->getToken(tok1, sizeof(tok1), &n1); + } else if (!strcmp(tok2, "begincodespacerange")) { + while (pst->getToken(tok1, sizeof(tok1), &n1)) { + if (!strcmp(tok1, "endcodespacerange")) { + break; + } + if (!pst->getToken(tok2, sizeof(tok2), &n2) || + !strcmp(tok2, "endcodespacerange")) { + error(-1, "Illegal entry in codespacerange block in CMap"); + break; + } + if (tok1[0] == '<' && tok2[0] == '<' && + n1 == n2 && n1 >= 4 && (n1 & 1) == 0) { + tok1[n1 - 1] = tok2[n1 - 1] = '\0'; + sscanf(tok1 + 1, "%x", &start); + sscanf(tok2 + 1, "%x", &end); + n1 = (n1 - 2) / 2; + cmap->addCodeSpace(cmap->vector, start, end, n1); + } + } + pst->getToken(tok1, sizeof(tok1), &n1); + } else if (!strcmp(tok2, "begincidchar")) { + while (pst->getToken(tok1, sizeof(tok1), &n1)) { + if (!strcmp(tok1, "endcidchar")) { + break; + } + if (!pst->getToken(tok2, sizeof(tok2), &n2) || + !strcmp(tok2, "endcidchar")) { + error(-1, "Illegal entry in cidchar block in CMap"); + break; + } + if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' && + n1 >= 4 && (n1 & 1) == 0)) { + error(-1, "Illegal entry in cidchar block in CMap"); + continue; + } + tok1[n1 - 1] = '\0'; + if (sscanf(tok1 + 1, "%x", &code) != 1) { + error(-1, "Illegal entry in cidchar block in CMap"); + continue; + } + n1 = (n1 - 2) / 2; + cmap->addCIDs(code, code, n1, (CID)atoi(tok2)); + } + pst->getToken(tok1, sizeof(tok1), &n1); + } else if (!strcmp(tok2, "begincidrange")) { + while (pst->getToken(tok1, sizeof(tok1), &n1)) { + if (!strcmp(tok1, "endcidrange")) { + break; + } + if (!pst->getToken(tok2, sizeof(tok2), &n2) || + !strcmp(tok2, "endcidrange") || + !pst->getToken(tok3, sizeof(tok3), &n3) || + !strcmp(tok3, "endcidrange")) { + error(-1, "Illegal entry in cidrange block in CMap"); + break; + } + if (tok1[0] == '<' && tok2[0] == '<' && + n1 == n2 && n1 >= 4 && (n1 & 1) == 0) { + tok1[n1 - 1] = tok2[n1 - 1] = '\0'; + sscanf(tok1 + 1, "%x", &start); + sscanf(tok2 + 1, "%x", &end); + n1 = (n1 - 2) / 2; + cmap->addCIDs(start, end, n1, (CID)atoi(tok3)); + } + } + pst->getToken(tok1, sizeof(tok1), &n1); + } else { + strcpy(tok1, tok2); + } + } + delete pst; + + fclose(f); + + return cmap; +} + +CMap::CMap(GString *collectionA, GString *cMapNameA) { + int i; + + collection = collectionA; + cMapName = cMapNameA; + wMode = 0; + vector = (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry)); + for (i = 0; i < 256; ++i) { + vector[i].isVector = gFalse; + vector[i].cid = 0; + } + refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif +} + +CMap::CMap(GString *collectionA, GString *cMapNameA, int wModeA) { + collection = collectionA; + cMapName = cMapNameA; + wMode = wModeA; + vector = NULL; + refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif +} + +void CMap::useCMap(CMapCache *cache, char *useName) { + GString *useNameStr; + CMap *subCMap; + + useNameStr = new GString(useName); + subCMap = cache->getCMap(collection, useNameStr); + delete useNameStr; + if (!subCMap) { + return; + } + copyVector(vector, subCMap->vector); + subCMap->decRefCnt(); +} + +void CMap::copyVector(CMapVectorEntry *dest, CMapVectorEntry *src) { + int i, j; + + for (i = 0; i < 256; ++i) { + if (src[i].isVector) { + if (!dest[i].isVector) { + dest[i].isVector = gTrue; + dest[i].vector = + (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry)); + for (j = 0; j < 256; ++j) { + dest[i].vector[j].isVector = gFalse; + dest[i].vector[j].cid = 0; + } + } + copyVector(dest[i].vector, src[i].vector); + } else { + if (dest[i].isVector) { + error(-1, "Collision in usecmap"); + } else { + dest[i].cid = src[i].cid; + } + } + } +} + +void CMap::addCodeSpace(CMapVectorEntry *vec, Guint start, Guint end, + Guint nBytes) { + Guint start2, end2; + int startByte, endByte, i, j; + + if (nBytes > 1) { + startByte = (start >> (8 * (nBytes - 1))) & 0xff; + endByte = (end >> (8 * (nBytes - 1))) & 0xff; + start2 = start & ((1 << (8 * (nBytes - 1))) - 1); + end2 = end & ((1 << (8 * (nBytes - 1))) - 1); + for (i = startByte; i <= endByte; ++i) { + if (!vec[i].isVector) { + vec[i].isVector = gTrue; + vec[i].vector = + (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry)); + for (j = 0; j < 256; ++j) { + vec[i].vector[j].isVector = gFalse; + vec[i].vector[j].cid = 0; + } + } + addCodeSpace(vec[i].vector, start2, end2, nBytes - 1); + } + } +} + +void CMap::addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID) { + CMapVectorEntry *vec; + CID cid; + int byte; + Guint i; + + vec = vector; + for (i = nBytes - 1; i >= 1; --i) { + byte = (start >> (8 * i)) & 0xff; + if (!vec[byte].isVector) { + error(-1, "Invalid CID (%0*x - %0*x) in CMap", + 2*nBytes, start, 2*nBytes, end); + return; + } + vec = vec[byte].vector; + } + cid = firstCID; + for (byte = (int)(start & 0xff); byte <= (int)(end & 0xff); ++byte) { + if (vec[byte].isVector) { + error(-1, "Invalid CID (%0*x - %0*x) in CMap", + 2*nBytes, start, 2*nBytes, end); + } else { + vec[byte].cid = cid; + } + ++cid; + } +} + +CMap::~CMap() { + delete collection; + delete cMapName; + if (vector) { + freeCMapVector(vector); + } +#if MULTITHREADED + gDestroyMutex(&mutex); +#endif +} + +void CMap::freeCMapVector(CMapVectorEntry *vec) { + int i; + + for (i = 0; i < 256; ++i) { + if (vec[i].isVector) { + freeCMapVector(vec[i].vector); + } + } + gfree(vec); +} + +void CMap::incRefCnt() { +#if MULTITHREADED + gLockMutex(&mutex); +#endif + ++refCnt; +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif +} + +void CMap::decRefCnt() { + GBool done; + +#if MULTITHREADED + gLockMutex(&mutex); +#endif + done = --refCnt == 0; +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif + if (done) { + delete this; + } +} + +GBool CMap::match(GString *collectionA, GString *cMapNameA) { + return !collection->cmp(collectionA) && !cMapName->cmp(cMapNameA); +} + +CID CMap::getCID(char *s, int len, int *nUsed) { + CMapVectorEntry *vec; + int n, i; + + if (!(vec = vector)) { + // identity CMap + *nUsed = 2; + if (len < 2) { + return 0; + } + return ((s[0] & 0xff) << 8) + (s[1] & 0xff); + } + n = 0; + while (1) { + if (n >= len) { + *nUsed = n; + return 0; + } + i = s[n++] & 0xff; + if (!vec[i].isVector) { + *nUsed = n; + return vec[i].cid; + } + vec = vec[i].vector; + } +} + +//------------------------------------------------------------------------ + +CMapCache::CMapCache() { + int i; + + for (i = 0; i < cMapCacheSize; ++i) { + cache[i] = NULL; + } +} + +CMapCache::~CMapCache() { + int i; + + for (i = 0; i < cMapCacheSize; ++i) { + if (cache[i]) { + cache[i]->decRefCnt(); + } + } +} + +CMap *CMapCache::getCMap(GString *collection, GString *cMapName) { + CMap *cmap; + int i, j; + + if (cache[0] && cache[0]->match(collection, cMapName)) { + cache[0]->incRefCnt(); + return cache[0]; + } + for (i = 1; i < cMapCacheSize; ++i) { + if (cache[i] && cache[i]->match(collection, cMapName)) { + cmap = cache[i]; + for (j = i; j >= 1; --j) { + cache[j] = cache[j - 1]; + } + cache[0] = cmap; + cmap->incRefCnt(); + return cmap; + } + } + if ((cmap = CMap::parse(this, collection, cMapName))) { + if (cache[cMapCacheSize - 1]) { + cache[cMapCacheSize - 1]->decRefCnt(); + } + for (j = cMapCacheSize - 1; j >= 1; --j) { + cache[j] = cache[j - 1]; + } + cache[0] = cmap; + cmap->incRefCnt(); + return cmap; + } + return NULL; +} diff --git a/kpdf/xpdf/xpdf/CMap.h b/kpdf/xpdf/xpdf/CMap.h new file mode 100644 index 00000000..c321a57a --- /dev/null +++ b/kpdf/xpdf/xpdf/CMap.h @@ -0,0 +1,102 @@ +//======================================================================== +// +// CMap.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef CMAP_H +#define CMAP_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "CharTypes.h" + +#if MULTITHREADED +#include "GMutex.h" +#endif + +class GString; +struct CMapVectorEntry; +class CMapCache; + +//------------------------------------------------------------------------ + +class CMap { +public: + + // Create the CMap specified by and . Sets + // the initial reference count to 1. Returns NULL on failure. + static CMap *parse(CMapCache *cache, GString *collectionA, + GString *cMapNameA); + + ~CMap(); + + void incRefCnt(); + void decRefCnt(); + + // Return collection name (-). + GString *getCollection() { return collection; } + + // Return true if this CMap matches the specified , and + // . + GBool match(GString *collectionA, GString *cMapNameA); + + // Return the CID corresponding to the character code starting at + // , which contains bytes. Sets * to the number of + // bytes used by the char code. + CID getCID(char *s, int len, int *nUsed); + + // Return the writing mode (0=horizontal, 1=vertical). + int getWMode() { return wMode; } + +private: + + CMap(GString *collectionA, GString *cMapNameA); + CMap(GString *collectionA, GString *cMapNameA, int wModeA); + void useCMap(CMapCache *cache, char *useName); + void copyVector(CMapVectorEntry *dest, CMapVectorEntry *src); + void addCodeSpace(CMapVectorEntry *vec, Guint start, Guint end, + Guint nBytes); + void addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID); + void freeCMapVector(CMapVectorEntry *vec); + + GString *collection; + GString *cMapName; + int wMode; // writing mode (0=horizontal, 1=vertical) + CMapVectorEntry *vector; // vector for first byte (NULL for + // identity CMap) + int refCnt; +#if MULTITHREADED + GMutex mutex; +#endif +}; + +//------------------------------------------------------------------------ + +#define cMapCacheSize 4 + +class CMapCache { +public: + + CMapCache(); + ~CMapCache(); + + // Get the CMap for the specified character collection. + // Increments its reference count; there will be one reference for + // the cache plus one for the caller of this function. Returns NULL + // on failure. + CMap *getCMap(GString *collection, GString *cMapName); + +private: + + CMap *cache[cMapCacheSize]; +}; + +#endif diff --git a/kpdf/xpdf/xpdf/Catalog.cc b/kpdf/xpdf/xpdf/Catalog.cc new file mode 100644 index 00000000..198703a4 --- /dev/null +++ b/kpdf/xpdf/xpdf/Catalog.cc @@ -0,0 +1,443 @@ +//======================================================================== +// +// Catalog.cc +// +// Copyright 1996-2007 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "Object.h" +#include "XRef.h" +#include "Array.h" +#include "Dict.h" +#include "Page.h" +#include "Error.h" +#include "Link.h" +#include "Catalog.h" + +//------------------------------------------------------------------------ +// Catalog +//------------------------------------------------------------------------ + +Catalog::Catalog(XRef *xrefA) { + Object catDict, pagesDict, pagesDictRef; + Object obj, obj2; + char *alreadyRead; + int numPages0; + int i; + + ok = gTrue; + xref = xrefA; + pages = NULL; + pageRefs = NULL; + numPages = pagesSize = 0; + baseURI = NULL; + + xref->getCatalog(&catDict); + if (!catDict.isDict()) { + error(-1, "Catalog object is wrong type (%s)", catDict.getTypeName()); + goto err1; + } + + // read page tree + catDict.dictLookup("Pages", &pagesDict); + // This should really be isDict("Pages"), but I've seen at least one + // PDF file where the /Type entry is missing. + if (!pagesDict.isDict()) { + error(-1, "Top-level pages object is wrong type (%s)", + pagesDict.getTypeName()); + goto err2; + } + pagesDict.dictLookup("Count", &obj); + // some PDF files actually use real numbers here ("/Count 9.0") + if (!obj.isNum()) { + error(-1, "Page count in top-level pages object is wrong type (%s)", + obj.getTypeName()); + goto err3; + } + pagesSize = numPages0 = (int)obj.getNum(); + obj.free(); + pages = (Page **)gmallocn(pagesSize, sizeof(Page *)); + pageRefs = (Ref *)gmallocn(pagesSize, sizeof(Ref)); + for (i = 0; i < pagesSize; ++i) { + pages[i] = NULL; + pageRefs[i].num = -1; + pageRefs[i].gen = -1; + } + alreadyRead = (char *)gmalloc(xref->getNumObjects()); + memset(alreadyRead, 0, xref->getNumObjects()); + if (catDict.dictLookupNF("Pages", &pagesDictRef)->isRef() && + pagesDictRef.getRefNum() >= 0 && + pagesDictRef.getRefNum() < xref->getNumObjects()) { + alreadyRead[pagesDictRef.getRefNum()] = 1; + } + pagesDictRef.free(); + numPages = readPageTree(pagesDict.getDict(), NULL, 0, alreadyRead); + gfree(alreadyRead); + if (numPages != numPages0) { + error(-1, "Page count in top-level pages object is incorrect"); + } + pagesDict.free(); + + // read named destination dictionary + catDict.dictLookup("Dests", &dests); + + // read root of named destination tree + if (catDict.dictLookup("Names", &obj)->isDict()) { + obj.dictLookup("Dests", &obj2); + destNameTree.init(xref, &obj2); + obj2.free(); + } + obj.free(); + + // read base URI + if (catDict.dictLookup("URI", &obj)->isDict()) { + if (obj.dictLookup("Base", &obj2)->isString()) { + baseURI = obj2.getString()->copy(); + } + obj2.free(); + } + obj.free(); + + // read page mode + if (catDict.dictLookup("PageMode", &obj)->isName()) { + if (strcmp(obj.getName(), "UseNone") == 0) + pageMode = UseNone; + else if (strcmp(obj.getName(), "UseOutlines") == 0) + pageMode = UseOutlines; + else if (strcmp(obj.getName(), "UseThumbs") == 0) + pageMode = UseThumbs; + else if (strcmp(obj.getName(), "FullScreen") == 0) + pageMode = FullScreen; + else if (strcmp(obj.getName(), "UseOC") == 0) + pageMode = UseOC; + else + pageMode = UseNone; + } else { + pageMode = UseNone; + } + obj.free(); + + // get the metadata stream + catDict.dictLookup("Metadata", &metadata); + + // get the structure tree root + catDict.dictLookup("StructTreeRoot", &structTreeRoot); + + // get the outline dictionary + catDict.dictLookup("Outlines", &outline); + + // get the AcroForm dictionary + catDict.dictLookup("AcroForm", &acroForm); + + catDict.free(); + return; + + err3: + obj.free(); + err2: + pagesDict.free(); + err1: + catDict.free(); + dests.initNull(); + ok = gFalse; +} + +Catalog::~Catalog() { + int i; + + if (pages) { + for (i = 0; i < pagesSize; ++i) { + if (pages[i]) { + delete pages[i]; + } + } + gfree(pages); + gfree(pageRefs); + } + dests.free(); + destNameTree.free(); + if (baseURI) { + delete baseURI; + } + metadata.free(); + structTreeRoot.free(); + outline.free(); + acroForm.free(); +} + +GString *Catalog::readMetadata() { + GString *s; + Dict *dict; + Object obj; + int c; + + if (!metadata.isStream()) { + return NULL; + } + dict = metadata.streamGetDict(); + if (!dict->lookup("Subtype", &obj)->isName("XML")) { + error(-1, "Unknown Metadata type: '%s'", + obj.isName() ? obj.getName() : "???"); + } + obj.free(); + s = new GString(); + metadata.streamReset(); + while ((c = metadata.streamGetChar()) != EOF) { + s->append(c); + } + metadata.streamClose(); + return s; +} + +int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start, + char *alreadyRead) { + Object kids; + Object kid; + Object kidRef; + PageAttrs *attrs1, *attrs2; + Page *page; + int i, j; + + attrs1 = new PageAttrs(attrs, pagesDict); + pagesDict->lookup("Kids", &kids); + if (!kids.isArray()) { + error(-1, "Kids object (page %d) is wrong type (%s)", + start+1, kids.getTypeName()); + goto err1; + } + for (i = 0; i < kids.arrayGetLength(); ++i) { + kids.arrayGetNF(i, &kidRef); + if (kidRef.isRef() && + kidRef.getRefNum() >= 0 && + kidRef.getRefNum() < xref->getNumObjects()) { + if (alreadyRead[kidRef.getRefNum()]) { + error(-1, "Loop in Pages tree"); + kidRef.free(); + continue; + } + alreadyRead[kidRef.getRefNum()] = 1; + } + kids.arrayGet(i, &kid); + if (kid.isDict("Page")) { + attrs2 = new PageAttrs(attrs1, kid.getDict()); + page = new Page(xref, start+1, kid.getDict(), attrs2); + if (!page->isOk()) { + ++start; + goto err3; + } + if (start >= pagesSize) { + pagesSize += 32; + pages = (Page **)greallocn(pages, pagesSize, sizeof(Page *)); + pageRefs = (Ref *)greallocn(pageRefs, pagesSize, sizeof(Ref)); + for (j = pagesSize - 32; j < pagesSize; ++j) { + pages[j] = NULL; + pageRefs[j].num = -1; + pageRefs[j].gen = -1; + } + } + pages[start] = page; + if (kidRef.isRef()) { + pageRefs[start].num = kidRef.getRefNum(); + pageRefs[start].gen = kidRef.getRefGen(); + } + ++start; + // This should really be isDict("Pages"), but I've seen at least one + // PDF file where the /Type entry is missing. + } else if (kid.isDict()) { + if ((start = readPageTree(kid.getDict(), attrs1, start, alreadyRead)) + < 0) + goto err2; + } else { + error(-1, "Kid object (page %d) is wrong type (%s)", + start+1, kid.getTypeName()); + } + kid.free(); + kidRef.free(); + } + delete attrs1; + kids.free(); + return start; + + err3: + delete page; + err2: + kid.free(); + err1: + kids.free(); + delete attrs1; + ok = gFalse; + return -1; +} + +int Catalog::findPage(int num, int gen) { + int i; + + for (i = 0; i < numPages; ++i) { + if (pageRefs[i].num == num && pageRefs[i].gen == gen) + return i + 1; + } + return 0; +} + +LinkDest *Catalog::findDest(GString *name) { + LinkDest *dest; + Object obj1, obj2; + GBool found; + + // try named destination dictionary then name tree + found = gFalse; + if (dests.isDict()) { + if (!dests.dictLookup(name->getCString(), &obj1)->isNull()) + found = gTrue; + else + obj1.free(); + } + if (!found) { + if (destNameTree.lookup(name, &obj1)) + found = gTrue; + else + obj1.free(); + } + if (!found) + return NULL; + + // construct LinkDest + dest = NULL; + if (obj1.isArray()) { + dest = new LinkDest(obj1.getArray()); + } else if (obj1.isDict()) { + if (obj1.dictLookup("D", &obj2)->isArray()) + dest = new LinkDest(obj2.getArray()); + else + error(-1, "Bad named destination value"); + obj2.free(); + } else { + error(-1, "Bad named destination value"); + } + obj1.free(); + if (dest && !dest->isOk()) { + delete dest; + dest = NULL; + } + + return dest; +} + +NameTree::NameTree() +{ + size = 0; + length = 0; + entries = NULL; +} + +NameTree::Entry::Entry(Array *array, int index) { + if (!array->getString(index, &name) || !array->getNF(index + 1, &value)) + error(-1, "Invalid page tree"); +} + +NameTree::Entry::~Entry() { + value.free(); +} + +void NameTree::addEntry(Entry *entry) +{ + if (length == size) { + if (length == 0) { + size = 8; + } else { + size *= 2; + } + entries = (Entry **) grealloc (entries, sizeof (Entry *) * size); + } + + entries[length] = entry; + ++length; +} + +void NameTree::init(XRef *xrefA, Object *tree) { + xref = xrefA; + parse(tree); +} + +void NameTree::parse(Object *tree) { + Object names; + Object kids, kid; + int i; + + if (!tree->isDict()) + return; + + // leaf node + if (tree->dictLookup("Names", &names)->isArray()) { + for (i = 0; i < names.arrayGetLength(); i += 2) { + NameTree::Entry *entry; + + entry = new Entry(names.getArray(), i); + addEntry(entry); + } + } + names.free(); + + // root or intermediate node + if (tree->dictLookup("Kids", &kids)->isArray()) { + for (i = 0; i < kids.arrayGetLength(); ++i) { + if (kids.arrayGet(i, &kid)->isDict()) + parse(&kid); + kid.free(); + } + } + kids.free(); +} + +int NameTree::Entry::cmp(const void *voidKey, const void *voidEntry) +{ + GString *key = (GString *) voidKey; + Entry *entry = *(NameTree::Entry **) voidEntry; + + return key->cmp(&entry->name); +} + +GBool NameTree::lookup(GString *name, Object *obj) +{ + Entry *entry; + + Entry **e = (Entry **) bsearch(name, entries, + length, sizeof(Entry *), Entry::cmp); + if (e) entry = *e; + else + { + error(-1, "failed to look up %s\n", name->getCString()); + obj->initNull(); + return gFalse; + } + if (entry != NULL) { + entry->value.fetch(xref, obj); + return gTrue; + } else { + error(-1, "failed to look up %s\n", name->getCString()); + + obj->initNull(); + + return gFalse; + } +} + +void NameTree::free() +{ + int i; + + for (i = 0; i < length; i++) + delete entries[i]; + + gfree(entries); +} diff --git a/kpdf/xpdf/xpdf/Catalog.h b/kpdf/xpdf/xpdf/Catalog.h new file mode 100644 index 00000000..e89ec04d --- /dev/null +++ b/kpdf/xpdf/xpdf/Catalog.h @@ -0,0 +1,137 @@ +//======================================================================== +// +// Catalog.h +// +// Copyright 1996-2007 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef CATALOG_H +#define CATALOG_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +class XRef; +class Object; +class Page; +class PageAttrs; +struct Ref; +class LinkDest; + +//------------------------------------------------------------------------ +// NameTree +//------------------------------------------------------------------------ + +class NameTree { +public: + NameTree(); + void init(XRef *xref, Object *tree); + void parse(Object *tree); + GBool lookup(GString *name, Object *obj); + void free(); + +private: + struct Entry { + Entry(Array *array, int index); + ~Entry(); + GString name; + Object value; + void free(); + static int cmp(const void *key, const void *entry); + }; + + void addEntry(Entry *entry); + + XRef *xref; + Object *root; + Entry **entries; + int size, length; +}; + +//------------------------------------------------------------------------ +// Catalog +//------------------------------------------------------------------------ + +class Catalog { +public: + + enum PageMode { + UseNone, + UseOutlines, + UseThumbs, + FullScreen, + UseOC + }; + + // Constructor. + Catalog(XRef *xrefA); + + // Destructor. + ~Catalog(); + + // Is catalog valid? + GBool isOk() { return ok; } + + // Get number of pages. + int getNumPages() { return numPages; } + + // Get a page. + Page *getPage(int i) { return pages[i-1]; } + + // Get the reference for a page object. + Ref *getPageRef(int i) { return &pageRefs[i-1]; } + + // Return base URI, or NULL if none. + GString *getBaseURI() { return baseURI; } + + // Returns the page mode. + PageMode getPageMode() { return pageMode; } + + // Return the contents of the metadata stream, or NULL if there is + // no metadata. + GString *readMetadata(); + + // Return the structure tree root object. + Object *getStructTreeRoot() { return &structTreeRoot; } + + // Find a page, given its object ID. Returns page number, or 0 if + // not found. + int findPage(int num, int gen); + + // Find a named destination. Returns the link destination, or + // NULL if is not a destination. + LinkDest *findDest(GString *name); + + Object *getDests() { return &dests; } + + Object *getOutline() { return &outline; } + + Object *getAcroForm() { return &acroForm; } + +private: + + XRef *xref; // the xref table for this PDF file + Page **pages; // array of pages + Ref *pageRefs; // object ID for each page + int numPages; // number of pages + int pagesSize; // size of pages array + Object dests; // named destination dictionary + NameTree destNameTree; // name tree + GString *baseURI; // base URI for URI-type links + PageMode pageMode; // page mode + Object metadata; // metadata stream + Object structTreeRoot; // structure tree root dictionary + Object outline; // outline dictionary + Object acroForm; // AcroForm dictionary + GBool ok; // true if catalog is valid + + int readPageTree(Dict *pages, PageAttrs *attrs, int start, + char *alreadyRead); + Object *findDestInTree(Object *tree, GString *name, Object *obj); +}; + +#endif diff --git a/kpdf/xpdf/xpdf/CharCodeToUnicode.cc b/kpdf/xpdf/xpdf/CharCodeToUnicode.cc new file mode 100644 index 00000000..3702a16d --- /dev/null +++ b/kpdf/xpdf/xpdf/CharCodeToUnicode.cc @@ -0,0 +1,540 @@ +//======================================================================== +// +// CharCodeToUnicode.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "gfile.h" +#include "GString.h" +#include "Error.h" +#include "GlobalParams.h" +#include "PSTokenizer.h" +#include "CharCodeToUnicode.h" + +//------------------------------------------------------------------------ + +#define maxUnicodeString 8 + +struct CharCodeToUnicodeString { + CharCode c; + Unicode u[maxUnicodeString]; + int len; +}; + +//------------------------------------------------------------------------ + +static int getCharFromString(void *data) { + char *p; + int c; + + p = *(char **)data; + if (*p) { + c = *p++; + *(char **)data = p; + } else { + c = EOF; + } + return c; +} + +static int getCharFromFile(void *data) { + return fgetc((FILE *)data); +} + +//------------------------------------------------------------------------ + +CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GString *fileName, + GString *collection) { + FILE *f; + Unicode *mapA; + CharCode size, mapLenA; + char buf[64]; + Unicode u; + CharCodeToUnicode *ctu; + + if (!(f = fopen(fileName->getCString(), "r"))) { + error(-1, "Couldn't open cidToUnicode file '%s'", + fileName->getCString()); + return NULL; + } + + size = 32768; + mapA = (Unicode *)gmallocn(size, sizeof(Unicode)); + mapLenA = 0; + + while (getLine(buf, sizeof(buf), f)) { + if (mapLenA == size) { + size *= 2; + mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode)); + } + if (sscanf(buf, "%x", &u) == 1) { + mapA[mapLenA] = u; + } else { + error(-1, "Bad line (%d) in cidToUnicode file '%s'", + (int)(mapLenA + 1), fileName->getCString()); + mapA[mapLenA] = 0; + } + ++mapLenA; + } + fclose(f); + + ctu = new CharCodeToUnicode(collection->copy(), mapA, mapLenA, gTrue, + NULL, 0, 0); + gfree(mapA); + return ctu; +} + +CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode( + GString *fileName) { + FILE *f; + Unicode *mapA; + CharCodeToUnicodeString *sMapA; + CharCode size, oldSize, len, sMapSizeA, sMapLenA; + char buf[256]; + char *tok; + Unicode u0; + Unicode uBuf[maxUnicodeString]; + CharCodeToUnicode *ctu; + int line, n, i; + + if (!(f = fopen(fileName->getCString(), "r"))) { + error(-1, "Couldn't open unicodeToUnicode file '%s'", + fileName->getCString()); + return NULL; + } + + size = 4096; + mapA = (Unicode *)gmallocn(size, sizeof(Unicode)); + memset(mapA, 0, size * sizeof(Unicode)); + len = 0; + sMapA = NULL; + sMapSizeA = sMapLenA = 0; + + line = 0; + while (getLine(buf, sizeof(buf), f)) { + ++line; + if (!(tok = strtok(buf, " \t\r\n")) || + sscanf(tok, "%x", &u0) != 1) { + error(-1, "Bad line (%d) in unicodeToUnicode file '%s'", + line, fileName->getCString()); + continue; + } + n = 0; + while (n < maxUnicodeString) { + if (!(tok = strtok(NULL, " \t\r\n"))) { + break; + } + if (sscanf(tok, "%x", &uBuf[n]) != 1) { + error(-1, "Bad line (%d) in unicodeToUnicode file '%s'", + line, fileName->getCString()); + break; + } + ++n; + } + if (n < 1) { + error(-1, "Bad line (%d) in unicodeToUnicode file '%s'", + line, fileName->getCString()); + continue; + } + if (u0 >= size) { + oldSize = size; + while (u0 >= size) { + size *= 2; + } + mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode)); + memset(mapA + oldSize, 0, (size - oldSize) * sizeof(Unicode)); + } + if (n == 1) { + mapA[u0] = uBuf[0]; + } else { + mapA[u0] = 0; + if (sMapLenA == sMapSizeA) { + sMapSizeA += 16; + sMapA = (CharCodeToUnicodeString *) + greallocn(sMapA, sMapSizeA, sizeof(CharCodeToUnicodeString)); + } + sMapA[sMapLenA].c = u0; + for (i = 0; i < n; ++i) { + sMapA[sMapLenA].u[i] = uBuf[i]; + } + sMapA[sMapLenA].len = n; + ++sMapLenA; + } + if (u0 >= len) { + len = u0 + 1; + } + } + fclose(f); + + ctu = new CharCodeToUnicode(fileName->copy(), mapA, len, gTrue, + sMapA, sMapLenA, sMapSizeA); + gfree(mapA); + return ctu; +} + +CharCodeToUnicode *CharCodeToUnicode::make8BitToUnicode(Unicode *toUnicode) { + return new CharCodeToUnicode(NULL, toUnicode, 256, gTrue, NULL, 0, 0); +} + +CharCodeToUnicode *CharCodeToUnicode::parseCMap(GString *buf, int nBits) { + CharCodeToUnicode *ctu; + char *p; + + ctu = new CharCodeToUnicode(NULL); + p = buf->getCString(); + ctu->parseCMap1(&getCharFromString, &p, nBits); + return ctu; +} + +void CharCodeToUnicode::mergeCMap(GString *buf, int nBits) { + char *p; + + p = buf->getCString(); + parseCMap1(&getCharFromString, &p, nBits); +} + +void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data, + int nBits) { + PSTokenizer *pst; + char tok1[256], tok2[256], tok3[256]; + int nDigits, n1, n2, n3; + CharCode i; + CharCode code1, code2; + GString *name; + FILE *f; + + nDigits = nBits / 4; + pst = new PSTokenizer(getCharFunc, data); + pst->getToken(tok1, sizeof(tok1), &n1); + while (pst->getToken(tok2, sizeof(tok2), &n2)) { + if (!strcmp(tok2, "usecmap")) { + if (tok1[0] == '/') { + name = new GString(tok1 + 1); + if ((f = globalParams->findToUnicodeFile(name))) { + parseCMap1(&getCharFromFile, f, nBits); + fclose(f); + } else { + error(-1, "Couldn't find ToUnicode CMap file for '%s'", + name->getCString()); + } + delete name; + } + pst->getToken(tok1, sizeof(tok1), &n1); + } else if (!strcmp(tok2, "beginbfchar")) { + while (pst->getToken(tok1, sizeof(tok1), &n1)) { + if (!strcmp(tok1, "endbfchar")) { + break; + } + if (!pst->getToken(tok2, sizeof(tok2), &n2) || + !strcmp(tok2, "endbfchar")) { + error(-1, "Illegal entry in bfchar block in ToUnicode CMap"); + break; + } + if (!(n1 == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' && + tok2[0] == '<' && tok2[n2 - 1] == '>')) { + error(-1, "Illegal entry in bfchar block in ToUnicode CMap"); + continue; + } + tok1[n1 - 1] = tok2[n2 - 1] = '\0'; + if (sscanf(tok1 + 1, "%x", &code1) != 1) { + error(-1, "Illegal entry in bfchar block in ToUnicode CMap"); + continue; + } + addMapping(code1, tok2 + 1, n2 - 2, 0); + } + pst->getToken(tok1, sizeof(tok1), &n1); + } else if (!strcmp(tok2, "beginbfrange")) { + while (pst->getToken(tok1, sizeof(tok1), &n1)) { + if (!strcmp(tok1, "endbfrange")) { + break; + } + if (!pst->getToken(tok2, sizeof(tok2), &n2) || + !strcmp(tok2, "endbfrange") || + !pst->getToken(tok3, sizeof(tok3), &n3) || + !strcmp(tok3, "endbfrange")) { + error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); + break; + } + if (!(n1 == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' && + n2 == 2 + nDigits && tok2[0] == '<' && tok2[n2 - 1] == '>')) { + error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); + continue; + } + tok1[n1 - 1] = tok2[n2 - 1] = '\0'; + if (sscanf(tok1 + 1, "%x", &code1) != 1 || + sscanf(tok2 + 1, "%x", &code2) != 1) { + error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); + continue; + } + if (!strcmp(tok3, "[")) { + i = 0; + while (pst->getToken(tok1, sizeof(tok1), &n1) && + code1 + i <= code2) { + if (!strcmp(tok1, "]")) { + break; + } + if (tok1[0] == '<' && tok1[n1 - 1] == '>') { + tok1[n1 - 1] = '\0'; + addMapping(code1 + i, tok1 + 1, n1 - 2, 0); + } else { + error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); + } + ++i; + } + } else if (tok3[0] == '<' && tok3[n3 - 1] == '>') { + tok3[n3 - 1] = '\0'; + for (i = 0; code1 <= code2; ++code1, ++i) { + addMapping(code1, tok3 + 1, n3 - 2, i); + } + + } else { + error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); + } + } + pst->getToken(tok1, sizeof(tok1), &n1); + } else { + strcpy(tok1, tok2); + } + } + delete pst; +} + +void CharCodeToUnicode::addMapping(CharCode code, char *uStr, int n, + int offset) { + CharCode oldLen, i; + Unicode u; + char uHex[5]; + int j; + + if (code >= mapLen) { + oldLen = mapLen; + mapLen = (code + 256) & ~255; + map = (Unicode *)greallocn(map, mapLen, sizeof(Unicode)); + for (i = oldLen; i < mapLen; ++i) { + map[i] = 0; + } + } + if (n <= 4) { + if (sscanf(uStr, "%x", &u) != 1) { + error(-1, "Illegal entry in ToUnicode CMap"); + return; + } + map[code] = u + offset; + } else { + if (sMapLen >= sMapSize) { + sMapSize = sMapSize + 16; + sMap = (CharCodeToUnicodeString *) + greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString)); + } + map[code] = 0; + sMap[sMapLen].c = code; + sMap[sMapLen].len = n / 4; + for (j = 0; j < sMap[sMapLen].len && j < maxUnicodeString; ++j) { + strncpy(uHex, uStr + j*4, 4); + uHex[4] = '\0'; + if (sscanf(uHex, "%x", &sMap[sMapLen].u[j]) != 1) { + error(-1, "Illegal entry in ToUnicode CMap"); + } + } + sMap[sMapLen].u[sMap[sMapLen].len - 1] += offset; + ++sMapLen; + } +} + +CharCodeToUnicode::CharCodeToUnicode(GString *tagA) { + CharCode i; + + tag = tagA; + mapLen = 256; + map = (Unicode *)gmallocn(mapLen, sizeof(Unicode)); + for (i = 0; i < mapLen; ++i) { + map[i] = 0; + } + sMap = NULL; + sMapLen = sMapSize = 0; + refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif +} + +CharCodeToUnicode::CharCodeToUnicode(GString *tagA, Unicode *mapA, + CharCode mapLenA, GBool copyMap, + CharCodeToUnicodeString *sMapA, + int sMapLenA, int sMapSizeA) { + tag = tagA; + mapLen = mapLenA; + if (copyMap) { + map = (Unicode *)gmallocn(mapLen, sizeof(Unicode)); + memcpy(map, mapA, mapLen * sizeof(Unicode)); + } else { + map = mapA; + } + sMap = sMapA; + sMapLen = sMapLenA; + sMapSize = sMapSizeA; + refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif +} + +CharCodeToUnicode::~CharCodeToUnicode() { + if (tag) { + delete tag; + } + gfree(map); + if (sMap) { + gfree(sMap); + } +#if MULTITHREADED + gDestroyMutex(&mutex); +#endif +} + +void CharCodeToUnicode::incRefCnt() { +#if MULTITHREADED + gLockMutex(&mutex); +#endif + ++refCnt; +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif +} + +void CharCodeToUnicode::decRefCnt() { + GBool done; + +#if MULTITHREADED + gLockMutex(&mutex); +#endif + done = --refCnt == 0; +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif + if (done) { + delete this; + } +} + +GBool CharCodeToUnicode::match(GString *tagA) { + return tag && !tag->cmp(tagA); +} + +void CharCodeToUnicode::setMapping(CharCode c, Unicode *u, int len) { + int i, j; + + if (len == 1) { + map[c] = u[0]; + } else { + for (i = 0; i < sMapLen; ++i) { + if (sMap[i].c == c) { + break; + } + } + if (i == sMapLen) { + if (sMapLen == sMapSize) { + sMapSize += 8; + sMap = (CharCodeToUnicodeString *) + greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString)); + } + ++sMapLen; + } + map[c] = 0; + sMap[i].c = c; + sMap[i].len = len; + for (j = 0; j < len && j < maxUnicodeString; ++j) { + sMap[i].u[j] = u[j]; + } + } +} + +int CharCodeToUnicode::mapToUnicode(CharCode c, Unicode *u, int size) { + int i, j; + + if (c >= mapLen) { + return 0; + } + if (map[c]) { + u[0] = map[c]; + return 1; + } + for (i = 0; i < sMapLen; ++i) { + if (sMap[i].c == c) { + for (j = 0; j < sMap[i].len && j < size; ++j) { + u[j] = sMap[i].u[j]; + } + return j; + } + } + return 0; +} + +//------------------------------------------------------------------------ + +CharCodeToUnicodeCache::CharCodeToUnicodeCache(int sizeA) { + int i; + + size = sizeA; + cache = (CharCodeToUnicode **)gmallocn(size, sizeof(CharCodeToUnicode *)); + for (i = 0; i < size; ++i) { + cache[i] = NULL; + } +} + +CharCodeToUnicodeCache::~CharCodeToUnicodeCache() { + int i; + + for (i = 0; i < size; ++i) { + if (cache[i]) { + cache[i]->decRefCnt(); + } + } + gfree(cache); +} + +CharCodeToUnicode *CharCodeToUnicodeCache::getCharCodeToUnicode(GString *tag) { + CharCodeToUnicode *ctu; + int i, j; + + if (cache[0] && cache[0]->match(tag)) { + cache[0]->incRefCnt(); + return cache[0]; + } + for (i = 1; i < size; ++i) { + if (cache[i] && cache[i]->match(tag)) { + ctu = cache[i]; + for (j = i; j >= 1; --j) { + cache[j] = cache[j - 1]; + } + cache[0] = ctu; + ctu->incRefCnt(); + return ctu; + } + } + return NULL; +} + +void CharCodeToUnicodeCache::add(CharCodeToUnicode *ctu) { + int i; + + if (cache[size - 1]) { + cache[size - 1]->decRefCnt(); + } + for (i = size - 1; i >= 1; --i) { + cache[i] = cache[i - 1]; + } + cache[0] = ctu; + ctu->incRefCnt(); +} diff --git a/kpdf/xpdf/xpdf/CharCodeToUnicode.h b/kpdf/xpdf/xpdf/CharCodeToUnicode.h new file mode 100644 index 00000000..04852aea --- /dev/null +++ b/kpdf/xpdf/xpdf/CharCodeToUnicode.h @@ -0,0 +1,117 @@ +//======================================================================== +// +// CharCodeToUnicode.h +// +// Mapping from character codes to Unicode. +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef CHARCODETOUNICODE_H +#define CHARCODETOUNICODE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "CharTypes.h" + +#if MULTITHREADED +#include "GMutex.h" +#endif + +struct CharCodeToUnicodeString; + +//------------------------------------------------------------------------ + +class CharCodeToUnicode { +public: + + // Read the CID-to-Unicode mapping for from the file + // specified by . Sets the initial reference count to 1. + // Returns NULL on failure. + static CharCodeToUnicode *parseCIDToUnicode(GString *fileName, + GString *collection); + + // Create a Unicode-to-Unicode mapping from the file specified by + // . Sets the initial reference count to 1. Returns NULL + // on failure. + static CharCodeToUnicode *parseUnicodeToUnicode(GString *fileName); + + // Create the CharCode-to-Unicode mapping for an 8-bit font. + // is an array of 256 Unicode indexes. Sets the initial + // reference count to 1. + static CharCodeToUnicode *make8BitToUnicode(Unicode *toUnicode); + + // Parse a ToUnicode CMap for an 8- or 16-bit font. + static CharCodeToUnicode *parseCMap(GString *buf, int nBits); + + // Parse a ToUnicode CMap for an 8- or 16-bit font, merging it into + // . + void mergeCMap(GString *buf, int nBits); + + ~CharCodeToUnicode(); + + void incRefCnt(); + void decRefCnt(); + + // Return true if this mapping matches the specified . + GBool match(GString *tagA); + + // Set the mapping for . + void setMapping(CharCode c, Unicode *u, int len); + + // Map a CharCode to Unicode. + int mapToUnicode(CharCode c, Unicode *u, int size); + + // Return the mapping's length, i.e., one more than the max char + // code supported by the mapping. + CharCode getLength() { return mapLen; } + +private: + + void parseCMap1(int (*getCharFunc)(void *), void *data, int nBits); + void addMapping(CharCode code, char *uStr, int n, int offset); + CharCodeToUnicode(GString *tagA); + CharCodeToUnicode(GString *tagA, Unicode *mapA, + CharCode mapLenA, GBool copyMap, + CharCodeToUnicodeString *sMapA, + int sMapLenA, int sMapSizeA); + + GString *tag; + Unicode *map; + CharCode mapLen; + CharCodeToUnicodeString *sMap; + int sMapLen, sMapSize; + int refCnt; +#if MULTITHREADED + GMutex mutex; +#endif +}; + +//------------------------------------------------------------------------ + +class CharCodeToUnicodeCache { +public: + + CharCodeToUnicodeCache(int sizeA); + ~CharCodeToUnicodeCache(); + + // Get the CharCodeToUnicode object for . Increments its + // reference count; there will be one reference for the cache plus + // one for the caller of this function. Returns NULL on failure. + CharCodeToUnicode *getCharCodeToUnicode(GString *tag); + + // Insert into the cache, in the most-recently-used position. + void add(CharCodeToUnicode *ctu); + +private: + + CharCodeToUnicode **cache; + int size; +}; + +#endif diff --git a/kpdf/xpdf/xpdf/CharTypes.h b/kpdf/xpdf/xpdf/CharTypes.h new file mode 100644 index 00000000..d0df630d --- /dev/null +++ b/kpdf/xpdf/xpdf/CharTypes.h @@ -0,0 +1,24 @@ +//======================================================================== +// +// CharTypes.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef CHARTYPES_H +#define CHARTYPES_H + +// Unicode character. +typedef unsigned int Unicode; + +// Character ID for CID character collections. +typedef unsigned int CID; + +// This is large enough to hold any of the following: +// - 8-bit char code +// - 16-bit CID +// - Unicode +typedef unsigned int CharCode; + +#endif diff --git a/kpdf/xpdf/xpdf/CompactFontTables.h b/kpdf/xpdf/xpdf/CompactFontTables.h new file mode 100644 index 00000000..28e16e77 --- /dev/null +++ b/kpdf/xpdf/xpdf/CompactFontTables.h @@ -0,0 +1,464 @@ +//======================================================================== +// +// CompactFontTables.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef COMPACTFONTINFO_H +#define COMPACTFONTINFO_H + +static char *type1CStdStrings[391] = { + ".notdef", + "space", + "exclam", + "quotedbl", + "numbersign", + "dollar", + "percent", + "ampersand", + "quoteright", + "parenleft", + "parenright", + "asterisk", + "plus", + "comma", + "hyphen", + "period", + "slash", + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "colon", + "semicolon", + "less", + "equal", + "greater", + "question", + "at", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "bracketleft", + "backslash", + "bracketright", + "asciicircum", + "underscore", + "quoteleft", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "braceleft", + "bar", + "braceright", + "asciitilde", + "exclamdown", + "cent", + "sterling", + "fraction", + "yen", + "florin", + "section", + "currency", + "quotesingle", + "quotedblleft", + "guillemotleft", + "guilsinglleft", + "guilsinglright", + "fi", + "fl", + "endash", + "dagger", + "daggerdbl", + "periodcentered", + "paragraph", + "bullet", + "quotesinglbase", + "quotedblbase", + "quotedblright", + "guillemotright", + "ellipsis", + "perthousand", + "questiondown", + "grave", + "acute", + "circumflex", + "tilde", + "macron", + "breve", + "dotaccent", + "dieresis", + "ring", + "cedilla", + "hungarumlaut", + "ogonek", + "caron", + "emdash", + "AE", + "ordfeminine", + "Lslash", + "Oslash", + "OE", + "ordmasculine", + "ae", + "dotlessi", + "lslash", + "oslash", + "oe", + "germandbls", + "onesuperior", + "logicalnot", + "mu", + "trademark", + "Eth", + "onehalf", + "plusminus", + "Thorn", + "onequarter", + "divide", + "brokenbar", + "degree", + "thorn", + "threequarters", + "twosuperior", + "registered", + "minus", + "eth", + "multiply", + "threesuperior", + "copyright", + "Aacute", + "Acircumflex", + "Adieresis", + "Agrave", + "Aring", + "Atilde", + "Ccedilla", + "Eacute", + "Ecircumflex", + "Edieresis", + "Egrave", + "Iacute", + "Icircumflex", + "Idieresis", + "Igrave", + "Ntilde", + "Oacute", + "Ocircumflex", + "Odieresis", + "Ograve", + "Otilde", + "Scaron", + "Uacute", + "Ucircumflex", + "Udieresis", + "Ugrave", + "Yacute", + "Ydieresis", + "Zcaron", + "aacute", + "acircumflex", + "adieresis", + "agrave", + "aring", + "atilde", + "ccedilla", + "eacute", + "ecircumflex", + "edieresis", + "egrave", + "iacute", + "icircumflex", + "idieresis", + "igrave", + "ntilde", + "oacute", + "ocircumflex", + "odieresis", + "ograve", + "otilde", + "scaron", + "uacute", + "ucircumflex", + "udieresis", + "ugrave", + "yacute", + "ydieresis", + "zcaron", + "exclamsmall", + "Hungarumlautsmall", + "dollaroldstyle", + "dollarsuperior", + "ampersandsmall", + "Acutesmall", + "parenleftsuperior", + "parenrightsuperior", + "twodotenleader", + "onedotenleader", + "zerooldstyle", + "oneoldstyle", + "twooldstyle", + "threeoldstyle", + "fouroldstyle", + "fiveoldstyle", + "sixoldstyle", + "sevenoldstyle", + "eightoldstyle", + "nineoldstyle", + "commasuperior", + "threequartersemdash", + "periodsuperior", + "questionsmall", + "asuperior", + "bsuperior", + "centsuperior", + "dsuperior", + "esuperior", + "isuperior", + "lsuperior", + "msuperior", + "nsuperior", + "osuperior", + "rsuperior", + "ssuperior", + "tsuperior", + "ff", + "ffi", + "ffl", + "parenleftinferior", + "parenrightinferior", + "Circumflexsmall", + "hyphensuperior", + "Gravesmall", + "Asmall", + "Bsmall", + "Csmall", + "Dsmall", + "Esmall", + "Fsmall", + "Gsmall", + "Hsmall", + "Ismall", + "Jsmall", + "Ksmall", + "Lsmall", + "Msmall", + "Nsmall", + "Osmall", + "Psmall", + "Qsmall", + "Rsmall", + "Ssmall", + "Tsmall", + "Usmall", + "Vsmall", + "Wsmall", + "Xsmall", + "Ysmall", + "Zsmall", + "colonmonetary", + "onefitted", + "rupiah", + "Tildesmall", + "exclamdownsmall", + "centoldstyle", + "Lslashsmall", + "Scaronsmall", + "Zcaronsmall", + "Dieresissmall", + "Brevesmall", + "Caronsmall", + "Dotaccentsmall", + "Macronsmall", + "figuredash", + "hypheninferior", + "Ogoneksmall", + "Ringsmall", + "Cedillasmall", + "questiondownsmall", + "oneeighth", + "threeeighths", + "fiveeighths", + "seveneighths", + "onethird", + "twothirds", + "zerosuperior", + "foursuperior", + "fivesuperior", + "sixsuperior", + "sevensuperior", + "eightsuperior", + "ninesuperior", + "zeroinferior", + "oneinferior", + "twoinferior", + "threeinferior", + "fourinferior", + "fiveinferior", + "sixinferior", + "seveninferior", + "eightinferior", + "nineinferior", + "centinferior", + "dollarinferior", + "periodinferior", + "commainferior", + "Agravesmall", + "Aacutesmall", + "Acircumflexsmall", + "Atildesmall", + "Adieresissmall", + "Aringsmall", + "AEsmall", + "Ccedillasmall", + "Egravesmall", + "Eacutesmall", + "Ecircumflexsmall", + "Edieresissmall", + "Igravesmall", + "Iacutesmall", + "Icircumflexsmall", + "Idieresissmall", + "Ethsmall", + "Ntildesmall", + "Ogravesmall", + "Oacutesmall", + "Ocircumflexsmall", + "Otildesmall", + "Odieresissmall", + "OEsmall", + "Oslashsmall", + "Ugravesmall", + "Uacutesmall", + "Ucircumflexsmall", + "Udieresissmall", + "Yacutesmall", + "Thornsmall", + "Ydieresissmall", + "001.000", + "001.001", + "001.002", + "001.003", + "Black", + "Bold", + "Book", + "Light", + "Medium", + "Regular", + "Roman", + "Semibold" +}; + +static Gushort type1CISOAdobeCharset[229] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228 +}; + +static Gushort type1CExpertCharset[166] = { + 0, 1, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 109, 110, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + 158, 155, 163, 319, 320, 321, 322, 323, 324, 325, + 326, 150, 164, 169, 327, 328, 329, 330, 331, 332, + 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, + 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, + 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, + 373, 374, 375, 376, 377, 378 +}; + +static Gushort type1CExpertSubsetCharset[87] = { + 0, 1, 231, 232, 235, 236, 237, 238, 13, 14, + 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 27, 28, 249, 250, 251, 253, 254, 255, + 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, + 266, 109, 110, 267, 268, 269, 270, 272, 300, 301, + 302, 305, 314, 315, 158, 155, 163, 320, 321, 322, + 323, 324, 325, 326, 150, 164, 169, 327, 328, 329, + 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346 +}; + +#endif diff --git a/kpdf/xpdf/xpdf/Decrypt.cc b/kpdf/xpdf/xpdf/Decrypt.cc new file mode 100644 index 00000000..51e56fb1 --- /dev/null +++ b/kpdf/xpdf/xpdf/Decrypt.cc @@ -0,0 +1,776 @@ +//======================================================================== +// +// Decrypt.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "gmem.h" +#include "Decrypt.h" + +static void rc4InitKey(Guchar *key, int keyLen, Guchar *state); +static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c); +static void aesKeyExpansion(DecryptAESState *s, + Guchar *objKey, int objKeyLen); +static void aesDecryptBlock(DecryptAESState *s, Guchar *in, GBool last); +static void md5(Guchar *msg, int msgLen, Guchar *digest); + +static Guchar passwordPad[32] = { + 0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, + 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08, + 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, + 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a +}; + +//------------------------------------------------------------------------ +// Decrypt +//------------------------------------------------------------------------ + +GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength, + GString *ownerKey, GString *userKey, + int permissions, GString *fileID, + GString *ownerPassword, GString *userPassword, + Guchar *fileKey, GBool encryptMetadata, + GBool *ownerPasswordOk) { + Guchar test[32], test2[32]; + GString *userPassword2; + Guchar fState[256]; + Guchar tmpKey[16]; + Guchar fx, fy; + int len, i, j; + + // try using the supplied owner password to generate the user password + *ownerPasswordOk = gFalse; + if (ownerPassword) { + len = ownerPassword->getLength(); + if (len < 32) { + memcpy(test, ownerPassword->getCString(), len); + memcpy(test + len, passwordPad, 32 - len); + } else { + memcpy(test, ownerPassword->getCString(), 32); + } + md5(test, 32, test); + if (encRevision == 3) { + for (i = 0; i < 50; ++i) { + md5(test, 16, test); + } + } + if (encRevision == 2) { + rc4InitKey(test, keyLength, fState); + fx = fy = 0; + for (i = 0; i < 32; ++i) { + test2[i] = rc4DecryptByte(fState, &fx, &fy, ownerKey->getChar(i)); + } + } else { + memcpy(test2, ownerKey->getCString(), 32); + for (i = 19; i >= 0; --i) { + for (j = 0; j < keyLength; ++j) { + tmpKey[j] = test[j] ^ i; + } + rc4InitKey(tmpKey, keyLength, fState); + fx = fy = 0; + for (j = 0; j < 32; ++j) { + test2[j] = rc4DecryptByte(fState, &fx, &fy, test2[j]); + } + } + } + userPassword2 = new GString((char *)test2, 32); + if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey, + permissions, fileID, userPassword2, fileKey, + encryptMetadata)) { + *ownerPasswordOk = gTrue; + delete userPassword2; + return gTrue; + } + delete userPassword2; + } + + // try using the supplied user password + return makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey, + permissions, fileID, userPassword, fileKey, + encryptMetadata); +} + +GBool Decrypt::makeFileKey2(int /*encVersion*/, int encRevision, int keyLength, + GString *ownerKey, GString *userKey, + int permissions, GString *fileID, + GString *userPassword, Guchar *fileKey, + GBool encryptMetadata) { + Guchar *buf; + Guchar test[32]; + Guchar fState[256]; + Guchar tmpKey[16]; + Guchar fx, fy; + int len, i, j; + GBool ok; + + // generate file key + buf = (Guchar *)gmalloc(72 + fileID->getLength()); + if (userPassword) { + len = userPassword->getLength(); + if (len < 32) { + memcpy(buf, userPassword->getCString(), len); + memcpy(buf + len, passwordPad, 32 - len); + } else { + memcpy(buf, userPassword->getCString(), 32); + } + } else { + memcpy(buf, passwordPad, 32); + } + memcpy(buf + 32, ownerKey->getCString(), 32); + buf[64] = permissions & 0xff; + buf[65] = (permissions >> 8) & 0xff; + buf[66] = (permissions >> 16) & 0xff; + buf[67] = (permissions >> 24) & 0xff; + memcpy(buf + 68, fileID->getCString(), fileID->getLength()); + len = 68 + fileID->getLength(); + if (!encryptMetadata) { + buf[len++] = 0xff; + buf[len++] = 0xff; + buf[len++] = 0xff; + buf[len++] = 0xff; + } + md5(buf, len, fileKey); + if (encRevision == 3) { + for (i = 0; i < 50; ++i) { + md5(fileKey, keyLength, fileKey); + } + } + + // test user password + if (encRevision == 2) { + rc4InitKey(fileKey, keyLength, fState); + fx = fy = 0; + for (i = 0; i < 32; ++i) { + test[i] = rc4DecryptByte(fState, &fx, &fy, userKey->getChar(i)); + } + ok = memcmp(test, passwordPad, 32) == 0; + } else if (encRevision == 3) { + memcpy(test, userKey->getCString(), 32); + for (i = 19; i >= 0; --i) { + for (j = 0; j < keyLength; ++j) { + tmpKey[j] = fileKey[j] ^ i; + } + rc4InitKey(tmpKey, keyLength, fState); + fx = fy = 0; + for (j = 0; j < 32; ++j) { + test[j] = rc4DecryptByte(fState, &fx, &fy, test[j]); + } + } + memcpy(buf, passwordPad, 32); + memcpy(buf + 32, fileID->getCString(), fileID->getLength()); + md5(buf, 32 + fileID->getLength(), buf); + ok = memcmp(test, buf, 16) == 0; + } else { + ok = gFalse; + } + + gfree(buf); + return ok; +} + +//------------------------------------------------------------------------ +// DecryptStream +//------------------------------------------------------------------------ + +DecryptStream::DecryptStream(Stream *strA, Guchar *fileKey, + CryptAlgorithm algoA, int keyLength, + int objNum, int objGen): + FilterStream(strA) +{ + int n, i; + + algo = algoA; + + // construct object key + for (i = 0; i < keyLength; ++i) { + objKey[i] = fileKey[i]; + } + objKey[keyLength] = objNum & 0xff; + objKey[keyLength + 1] = (objNum >> 8) & 0xff; + objKey[keyLength + 2] = (objNum >> 16) & 0xff; + objKey[keyLength + 3] = objGen & 0xff; + objKey[keyLength + 4] = (objGen >> 8) & 0xff; + if (algo == cryptAES) { + objKey[keyLength + 5] = 0x73; // 's' + objKey[keyLength + 6] = 0x41; // 'A' + objKey[keyLength + 7] = 0x6c; // 'l' + objKey[keyLength + 8] = 0x54; // 'T' + n = keyLength + 9; + } else { + n = keyLength + 5; + } + md5(objKey, n, objKey); + if ((objKeyLength = keyLength + 5) > 16) { + objKeyLength = 16; + } +} + +DecryptStream::~DecryptStream() { + delete str; +} + +void DecryptStream::reset() { + int i; + + str->reset(); + switch (algo) { + case cryptRC4: + state.rc4.x = state.rc4.y = 0; + rc4InitKey(objKey, objKeyLength, state.rc4.state); + state.rc4.buf = EOF; + break; + case cryptAES: + aesKeyExpansion(&state.aes, objKey, objKeyLength); + for (i = 0; i < 16; ++i) { + state.aes.cbc[i] = str->getChar(); + } + state.aes.bufIdx = 16; + break; + } +} + +int DecryptStream::getChar() { + Guchar in[16]; + int c, i; + + c = EOF; // make gcc happy + switch (algo) { + case cryptRC4: + if (state.rc4.buf == EOF) { + c = str->getChar(); + if (c != EOF) { + state.rc4.buf = rc4DecryptByte(state.rc4.state, &state.rc4.x, + &state.rc4.y, (Guchar)c); + } + } + c = state.rc4.buf; + state.rc4.buf = EOF; + break; + case cryptAES: + if (state.aes.bufIdx == 16) { + for (i = 0; i < 16; ++i) { + if ((c = str->getChar()) == EOF) { + return EOF; + } + in[i] = (Guchar)c; + } + aesDecryptBlock(&state.aes, in, str->lookChar() == EOF); + } + if (state.aes.bufIdx == 16) { + c = EOF; + } else { + c = state.aes.buf[state.aes.bufIdx++]; + } + break; + } + return c; +} + +int DecryptStream::lookChar() { + Guchar in[16]; + int c, i; + + c = EOF; // make gcc happy + switch (algo) { + case cryptRC4: + if (state.rc4.buf == EOF) { + c = str->getChar(); + if (c != EOF) { + state.rc4.buf = rc4DecryptByte(state.rc4.state, &state.rc4.x, + &state.rc4.y, (Guchar)c); + } + } + c = state.rc4.buf; + break; + case cryptAES: + if (state.aes.bufIdx == 16) { + for (i = 0; i < 16; ++i) { + if ((c = str->getChar()) == EOF) { + return EOF; + } + in[i] = c; + } + aesDecryptBlock(&state.aes, in, str->lookChar() == EOF); + } + if (state.aes.bufIdx == 16) { + c = EOF; + } else { + c = state.aes.buf[state.aes.bufIdx]; + } + break; + } + return c; +} + +GBool DecryptStream::isBinary(GBool last) { + return str->isBinary(last); +} + +//------------------------------------------------------------------------ +// RC4-compatible decryption +//------------------------------------------------------------------------ + +static void rc4InitKey(Guchar *key, int keyLen, Guchar *state) { + Guchar index1, index2; + Guchar t; + int i; + + for (i = 0; i < 256; ++i) + state[i] = i; + index1 = index2 = 0; + for (i = 0; i < 256; ++i) { + index2 = (key[index1] + state[i] + index2) % 256; + t = state[i]; + state[i] = state[index2]; + state[index2] = t; + index1 = (index1 + 1) % keyLen; + } +} + +static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c) { + Guchar x1, y1, tx, ty; + + x1 = *x = (*x + 1) % 256; + y1 = *y = (state[*x] + *y) % 256; + tx = state[x1]; + ty = state[y1]; + state[x1] = ty; + state[y1] = tx; + return c ^ state[(tx + ty) % 256]; +} + +//------------------------------------------------------------------------ +// AES decryption +//------------------------------------------------------------------------ + +static Guchar sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +static Guchar invSbox[256] = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d +}; + +static Guint rcon[11] = { + 0x00000000, // unused + 0x01000000, + 0x02000000, + 0x04000000, + 0x08000000, + 0x10000000, + 0x20000000, + 0x40000000, + 0x80000000, + 0x1b000000, + 0x36000000 +}; + +static inline Guint subWord(Guint x) { + return (sbox[x >> 24] << 24) + | (sbox[(x >> 16) & 0xff] << 16) + | (sbox[(x >> 8) & 0xff] << 8) + | sbox[x & 0xff]; +} + +static inline Guint rotWord(Guint x) { + return ((x << 8) & 0xffffffff) | (x >> 24); +} + +static inline void invSubBytes(Guchar *state) { + int i; + + for (i = 0; i < 16; ++i) { + state[i] = invSbox[state[i]]; + } +} + +static inline void invShiftRows(Guchar *state) { + Guchar t; + + t = state[7]; + state[7] = state[6]; + state[6] = state[5]; + state[5] = state[4]; + state[4] = t; + + t = state[8]; + state[8] = state[10]; + state[10] = t; + t = state[9]; + state[9] = state[11]; + state[11] = t; + + t = state[12]; + state[12] = state[13]; + state[13] = state[14]; + state[14] = state[15]; + state[15] = t; +} + +// {09} \cdot s +static inline Guchar mul09(Guchar s) { + Guchar s2, s4, s8; + + s2 = (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1); + s4 = (s2 & 0x80) ? ((s2 << 1) ^ 0x1b) : (s2 << 1); + s8 = (s4 & 0x80) ? ((s4 << 1) ^ 0x1b) : (s4 << 1); + return s ^ s8; +} + +// {0b} \cdot s +static inline Guchar mul0b(Guchar s) { + Guchar s2, s4, s8; + + s2 = (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1); + s4 = (s2 & 0x80) ? ((s2 << 1) ^ 0x1b) : (s2 << 1); + s8 = (s4 & 0x80) ? ((s4 << 1) ^ 0x1b) : (s4 << 1); + return s ^ s2 ^ s8; +} + +// {0d} \cdot s +static inline Guchar mul0d(Guchar s) { + Guchar s2, s4, s8; + + s2 = (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1); + s4 = (s2 & 0x80) ? ((s2 << 1) ^ 0x1b) : (s2 << 1); + s8 = (s4 & 0x80) ? ((s4 << 1) ^ 0x1b) : (s4 << 1); + return s ^ s4 ^ s8; +} + +// {0e} \cdot s +static inline Guchar mul0e(Guchar s) { + Guchar s2, s4, s8; + + s2 = (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1); + s4 = (s2 & 0x80) ? ((s2 << 1) ^ 0x1b) : (s2 << 1); + s8 = (s4 & 0x80) ? ((s4 << 1) ^ 0x1b) : (s4 << 1); + return s2 ^ s4 ^ s8; +} + +static inline void invMixColumns(Guchar *state) { + int c; + Guchar s0, s1, s2, s3; + + for (c = 0; c < 4; ++c) { + s0 = state[c]; + s1 = state[4+c]; + s2 = state[8+c]; + s3 = state[12+c]; + state[c] = mul0e(s0) ^ mul0b(s1) ^ mul0d(s2) ^ mul09(s3); + state[4+c] = mul09(s0) ^ mul0e(s1) ^ mul0b(s2) ^ mul0d(s3); + state[8+c] = mul0d(s0) ^ mul09(s1) ^ mul0e(s2) ^ mul0b(s3); + state[12+c] = mul0b(s0) ^ mul0d(s1) ^ mul09(s2) ^ mul0e(s3); + } +} + +static inline void invMixColumnsW(Guint *w) { + int c; + Guchar s0, s1, s2, s3; + + for (c = 0; c < 4; ++c) { + s0 = w[c] >> 24; + s1 = w[c] >> 16; + s2 = w[c] >> 8; + s3 = w[c]; + w[c] = ((mul0e(s0) ^ mul0b(s1) ^ mul0d(s2) ^ mul09(s3)) << 24) + | ((mul09(s0) ^ mul0e(s1) ^ mul0b(s2) ^ mul0d(s3)) << 16) + | ((mul0d(s0) ^ mul09(s1) ^ mul0e(s2) ^ mul0b(s3)) << 8) + | (mul0b(s0) ^ mul0d(s1) ^ mul09(s2) ^ mul0e(s3)); + } +} + +static inline void addRoundKey(Guchar *state, Guint *w) { + int c; + + for (c = 0; c < 4; ++c) { + state[c] ^= w[c] >> 24; + state[4+c] ^= w[c] >> 16; + state[8+c] ^= w[c] >> 8; + state[12+c] ^= w[c]; + } +} + +static void aesKeyExpansion(DecryptAESState *s, + Guchar *objKey, int /*objKeyLen*/) { + Guint temp; + int i, round; + + //~ this assumes objKeyLen == 16 + + for (i = 0; i < 4; ++i) { + s->w[i] = (objKey[4*i] << 24) + (objKey[4*i+1] << 16) + + (objKey[4*i+2] << 8) + objKey[4*i+3]; + } + for (i = 4; i < 44; ++i) { + temp = s->w[i-1]; + if (!(i & 3)) { + temp = subWord(rotWord(temp)) ^ rcon[i/4]; + } + s->w[i] = s->w[i-4] ^ temp; + } + for (round = 1; round <= 9; ++round) { + invMixColumnsW(&s->w[round * 4]); + } +} + +static void aesDecryptBlock(DecryptAESState *s, Guchar *in, GBool last) { + int c, round, n, i; + + // initial state + for (c = 0; c < 4; ++c) { + s->state[c] = in[4*c]; + s->state[4+c] = in[4*c+1]; + s->state[8+c] = in[4*c+2]; + s->state[12+c] = in[4*c+3]; + } + + // round 0 + addRoundKey(s->state, &s->w[10 * 4]); + + // rounds 1-9 + for (round = 9; round >= 1; --round) { + invSubBytes(s->state); + invShiftRows(s->state); + invMixColumns(s->state); + addRoundKey(s->state, &s->w[round * 4]); + } + + // round 10 + invSubBytes(s->state); + invShiftRows(s->state); + addRoundKey(s->state, &s->w[0]); + + // CBC + for (c = 0; c < 4; ++c) { + s->buf[4*c] = s->state[c] ^ s->cbc[4*c]; + s->buf[4*c+1] = s->state[4+c] ^ s->cbc[4*c+1]; + s->buf[4*c+2] = s->state[8+c] ^ s->cbc[4*c+2]; + s->buf[4*c+3] = s->state[12+c] ^ s->cbc[4*c+3]; + } + + // save the input block for the next CBC + for (i = 0; i < 16; ++i) { + s->cbc[i] = in[i]; + } + + // remove padding + s->bufIdx = 0; + if (last) { + n = s->buf[15]; + for (i = 15; i >= n; --i) { + s->buf[i] = s->buf[i-n]; + } + s->bufIdx = n; + } +} + +//------------------------------------------------------------------------ +// MD5 message digest +//------------------------------------------------------------------------ + +// this works around a bug in older Sun compilers +static inline Gulong rotateLeft(Gulong x, int r) { + x &= 0xffffffff; + return ((x << r) | (x >> (32 - r))) & 0xffffffff; +} + +static inline Gulong md5Round1(Gulong a, Gulong b, Gulong c, Gulong d, + Gulong Xk, Gulong s, Gulong Ti) { + return b + rotateLeft((a + ((b & c) | (~b & d)) + Xk + Ti), s); +} + +static inline Gulong md5Round2(Gulong a, Gulong b, Gulong c, Gulong d, + Gulong Xk, Gulong s, Gulong Ti) { + return b + rotateLeft((a + ((b & d) | (c & ~d)) + Xk + Ti), s); +} + +static inline Gulong md5Round3(Gulong a, Gulong b, Gulong c, Gulong d, + Gulong Xk, Gulong s, Gulong Ti) { + return b + rotateLeft((a + (b ^ c ^ d) + Xk + Ti), s); +} + +static inline Gulong md5Round4(Gulong a, Gulong b, Gulong c, Gulong d, + Gulong Xk, Gulong s, Gulong Ti) { + return b + rotateLeft((a + (c ^ (b | ~d)) + Xk + Ti), s); +} + +static void md5(Guchar *msg, int msgLen, Guchar *digest) { + Gulong x[16]; + Gulong a, b, c, d, aa, bb, cc, dd; + int n64; + int i, j, k; + + // compute number of 64-byte blocks + // (length + pad byte (0x80) + 8 bytes for length) + n64 = (msgLen + 1 + 8 + 63) / 64; + + // initialize a, b, c, d + a = 0x67452301; + b = 0xefcdab89; + c = 0x98badcfe; + d = 0x10325476; + + // loop through blocks + k = 0; + for (i = 0; i < n64; ++i) { + + // grab a 64-byte block + for (j = 0; j < 16 && k < msgLen - 3; ++j, k += 4) + x[j] = (((((msg[k+3] << 8) + msg[k+2]) << 8) + msg[k+1]) << 8) + msg[k]; + if (i == n64 - 1) { + if (k == msgLen - 3) + x[j] = 0x80000000 + (((msg[k+2] << 8) + msg[k+1]) << 8) + msg[k]; + else if (k == msgLen - 2) + x[j] = 0x800000 + (msg[k+1] << 8) + msg[k]; + else if (k == msgLen - 1) + x[j] = 0x8000 + msg[k]; + else + x[j] = 0x80; + ++j; + while (j < 16) + x[j++] = 0; + x[14] = msgLen << 3; + } + + // save a, b, c, d + aa = a; + bb = b; + cc = c; + dd = d; + + // round 1 + a = md5Round1(a, b, c, d, x[0], 7, 0xd76aa478); + d = md5Round1(d, a, b, c, x[1], 12, 0xe8c7b756); + c = md5Round1(c, d, a, b, x[2], 17, 0x242070db); + b = md5Round1(b, c, d, a, x[3], 22, 0xc1bdceee); + a = md5Round1(a, b, c, d, x[4], 7, 0xf57c0faf); + d = md5Round1(d, a, b, c, x[5], 12, 0x4787c62a); + c = md5Round1(c, d, a, b, x[6], 17, 0xa8304613); + b = md5Round1(b, c, d, a, x[7], 22, 0xfd469501); + a = md5Round1(a, b, c, d, x[8], 7, 0x698098d8); + d = md5Round1(d, a, b, c, x[9], 12, 0x8b44f7af); + c = md5Round1(c, d, a, b, x[10], 17, 0xffff5bb1); + b = md5Round1(b, c, d, a, x[11], 22, 0x895cd7be); + a = md5Round1(a, b, c, d, x[12], 7, 0x6b901122); + d = md5Round1(d, a, b, c, x[13], 12, 0xfd987193); + c = md5Round1(c, d, a, b, x[14], 17, 0xa679438e); + b = md5Round1(b, c, d, a, x[15], 22, 0x49b40821); + + // round 2 + a = md5Round2(a, b, c, d, x[1], 5, 0xf61e2562); + d = md5Round2(d, a, b, c, x[6], 9, 0xc040b340); + c = md5Round2(c, d, a, b, x[11], 14, 0x265e5a51); + b = md5Round2(b, c, d, a, x[0], 20, 0xe9b6c7aa); + a = md5Round2(a, b, c, d, x[5], 5, 0xd62f105d); + d = md5Round2(d, a, b, c, x[10], 9, 0x02441453); + c = md5Round2(c, d, a, b, x[15], 14, 0xd8a1e681); + b = md5Round2(b, c, d, a, x[4], 20, 0xe7d3fbc8); + a = md5Round2(a, b, c, d, x[9], 5, 0x21e1cde6); + d = md5Round2(d, a, b, c, x[14], 9, 0xc33707d6); + c = md5Round2(c, d, a, b, x[3], 14, 0xf4d50d87); + b = md5Round2(b, c, d, a, x[8], 20, 0x455a14ed); + a = md5Round2(a, b, c, d, x[13], 5, 0xa9e3e905); + d = md5Round2(d, a, b, c, x[2], 9, 0xfcefa3f8); + c = md5Round2(c, d, a, b, x[7], 14, 0x676f02d9); + b = md5Round2(b, c, d, a, x[12], 20, 0x8d2a4c8a); + + // round 3 + a = md5Round3(a, b, c, d, x[5], 4, 0xfffa3942); + d = md5Round3(d, a, b, c, x[8], 11, 0x8771f681); + c = md5Round3(c, d, a, b, x[11], 16, 0x6d9d6122); + b = md5Round3(b, c, d, a, x[14], 23, 0xfde5380c); + a = md5Round3(a, b, c, d, x[1], 4, 0xa4beea44); + d = md5Round3(d, a, b, c, x[4], 11, 0x4bdecfa9); + c = md5Round3(c, d, a, b, x[7], 16, 0xf6bb4b60); + b = md5Round3(b, c, d, a, x[10], 23, 0xbebfbc70); + a = md5Round3(a, b, c, d, x[13], 4, 0x289b7ec6); + d = md5Round3(d, a, b, c, x[0], 11, 0xeaa127fa); + c = md5Round3(c, d, a, b, x[3], 16, 0xd4ef3085); + b = md5Round3(b, c, d, a, x[6], 23, 0x04881d05); + a = md5Round3(a, b, c, d, x[9], 4, 0xd9d4d039); + d = md5Round3(d, a, b, c, x[12], 11, 0xe6db99e5); + c = md5Round3(c, d, a, b, x[15], 16, 0x1fa27cf8); + b = md5Round3(b, c, d, a, x[2], 23, 0xc4ac5665); + + // round 4 + a = md5Round4(a, b, c, d, x[0], 6, 0xf4292244); + d = md5Round4(d, a, b, c, x[7], 10, 0x432aff97); + c = md5Round4(c, d, a, b, x[14], 15, 0xab9423a7); + b = md5Round4(b, c, d, a, x[5], 21, 0xfc93a039); + a = md5Round4(a, b, c, d, x[12], 6, 0x655b59c3); + d = md5Round4(d, a, b, c, x[3], 10, 0x8f0ccc92); + c = md5Round4(c, d, a, b, x[10], 15, 0xffeff47d); + b = md5Round4(b, c, d, a, x[1], 21, 0x85845dd1); + a = md5Round4(a, b, c, d, x[8], 6, 0x6fa87e4f); + d = md5Round4(d, a, b, c, x[15], 10, 0xfe2ce6e0); + c = md5Round4(c, d, a, b, x[6], 15, 0xa3014314); + b = md5Round4(b, c, d, a, x[13], 21, 0x4e0811a1); + a = md5Round4(a, b, c, d, x[4], 6, 0xf7537e82); + d = md5Round4(d, a, b, c, x[11], 10, 0xbd3af235); + c = md5Round4(c, d, a, b, x[2], 15, 0x2ad7d2bb); + b = md5Round4(b, c, d, a, x[9], 21, 0xeb86d391); + + // increment a, b, c, d + a += aa; + b += bb; + c += cc; + d += dd; + } + + // break digest into bytes + digest[0] = (Guchar)(a & 0xff); + digest[1] = (Guchar)((a >>= 8) & 0xff); + digest[2] = (Guchar)((a >>= 8) & 0xff); + digest[3] = (Guchar)((a >>= 8) & 0xff); + digest[4] = (Guchar)(b & 0xff); + digest[5] = (Guchar)((b >>= 8) & 0xff); + digest[6] = (Guchar)((b >>= 8) & 0xff); + digest[7] = (Guchar)((b >>= 8) & 0xff); + digest[8] = (Guchar)(c & 0xff); + digest[9] = (Guchar)((c >>= 8) & 0xff); + digest[10] = (Guchar)((c >>= 8) & 0xff); + digest[11] = (Guchar)((c >>= 8) & 0xff); + digest[12] = (Guchar)(d & 0xff); + digest[13] = (Guchar)((d >>= 8) & 0xff); + digest[14] = (Guchar)((d >>= 8) & 0xff); + digest[15] = (Guchar)((d >>= 8) & 0xff); +} diff --git a/kpdf/xpdf/xpdf/Decrypt.h b/kpdf/xpdf/xpdf/Decrypt.h new file mode 100644 index 00000000..56f34b77 --- /dev/null +++ b/kpdf/xpdf/xpdf/Decrypt.h @@ -0,0 +1,95 @@ +//======================================================================== +// +// Decrypt.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef DECRYPT_H +#define DECRYPT_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "GString.h" +#include "Object.h" +#include "Stream.h" + +//------------------------------------------------------------------------ +// Decrypt +//------------------------------------------------------------------------ + +class Decrypt { +public: + + // Generate a file key. The buffer must have space for at + // least 16 bytes. Checks and then + // and returns true if either is correct. Sets if + // the owner password was correct. Either or both of the passwords + // may be NULL, which is treated as an empty string. + static GBool makeFileKey(int encVersion, int encRevision, int keyLength, + GString *ownerKey, GString *userKey, + int permissions, GString *fileID, + GString *ownerPassword, GString *userPassword, + Guchar *fileKey, GBool encryptMetadata, + GBool *ownerPasswordOk); + +private: + + static GBool makeFileKey2(int encVersion, int encRevision, int keyLength, + GString *ownerKey, GString *userKey, + int permissions, GString *fileID, + GString *userPassword, Guchar *fileKey, + GBool encryptMetadata); +}; + +//------------------------------------------------------------------------ +// DecryptStream +//------------------------------------------------------------------------ + +struct DecryptRC4State { + Guchar state[256]; + Guchar x, y; + int buf; +}; + +struct DecryptAESState { + Guint w[44]; + Guchar state[16]; + Guchar cbc[16]; + Guchar buf[16]; + int bufIdx; +}; + +class DecryptStream: public FilterStream { +public: + + DecryptStream(Stream *strA, Guchar *fileKey, + CryptAlgorithm algoA, int keyLength, + int objNum, int objGen); + virtual ~DecryptStream(); + virtual StreamKind getKind() { return strWeird; } + virtual void reset(); + virtual int getChar(); + virtual int lookChar(); + virtual GBool isBinary(GBool last); + virtual Stream *getUndecodedStream() { return this; } + +private: + + CryptAlgorithm algo; + int objKeyLength; + Guchar objKey[16 + 9]; + + union { + DecryptRC4State rc4; + DecryptAESState aes; + } state; +}; + +#endif diff --git a/kpdf/xpdf/xpdf/Dict.cc b/kpdf/xpdf/xpdf/Dict.cc new file mode 100644 index 00000000..dd1517f0 --- /dev/null +++ b/kpdf/xpdf/xpdf/Dict.cc @@ -0,0 +1,95 @@ +//======================================================================== +// +// Dict.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "Object.h" +#include "XRef.h" +#include "Dict.h" + +//------------------------------------------------------------------------ +// Dict +//------------------------------------------------------------------------ + +Dict::Dict(XRef *xrefA) { + xref = xrefA; + entries = NULL; + size = length = 0; + ref = 1; +} + +Dict::~Dict() { + int i; + + for (i = 0; i < length; ++i) { + gfree(entries[i].key); + entries[i].val.free(); + } + gfree(entries); +} + +void Dict::add(char *key, Object *val) { + if (length == size) { + if (length == 0) { + size = 8; + } else { + size *= 2; + } + entries = (DictEntry *)greallocn(entries, size, sizeof(DictEntry)); + } + entries[length].key = key; + entries[length].val = *val; + ++length; +} + +inline DictEntry *Dict::find(char *key) { + int i; + + for (i = 0; i < length; ++i) { + if (!strcmp(key, entries[i].key)) + return &entries[i]; + } + return NULL; +} + +GBool Dict::is(char *type) { + DictEntry *e; + + return (e = find("Type")) && e->val.isName(type); +} + +Object *Dict::lookup(char *key, Object *obj) { + DictEntry *e; + + return (e = find(key)) ? e->val.fetch(xref, obj) : obj->initNull(); +} + +Object *Dict::lookupNF(char *key, Object *obj) { + DictEntry *e; + + return (e = find(key)) ? e->val.copy(obj) : obj->initNull(); +} + +char *Dict::getKey(int i) { + return entries[i].key; +} + +Object *Dict::getVal(int i, Object *obj) { + return entries[i].val.fetch(xref, obj); +} + +Object *Dict::getValNF(int i, Object *obj) { + return entries[i].val.copy(obj); +} diff --git a/kpdf/xpdf/xpdf/Dict.h b/kpdf/xpdf/xpdf/Dict.h new file mode 100644 index 00000000..08f55ecd --- /dev/null +++ b/kpdf/xpdf/xpdf/Dict.h @@ -0,0 +1,77 @@ +//======================================================================== +// +// Dict.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef DICT_H +#define DICT_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "Object.h" + +//------------------------------------------------------------------------ +// Dict +//------------------------------------------------------------------------ + +struct DictEntry { + char *key; + Object val; +}; + +class Dict { +public: + + // Constructor. + Dict(XRef *xrefA); + + // Destructor. + ~Dict(); + + // Reference counting. + int incRef() { return ++ref; } + int decRef() { return --ref; } + + // Get number of entries. + int getLength() { return length; } + + // Add an entry. NB: does not copy key. + void add(char *key, Object *val); + + // Check if dictionary is of specified type. + GBool is(char *type); + + // Look up an entry and return the value. Returns a null object + // if is not in the dictionary. + Object *lookup(char *key, Object *obj); + Object *lookupNF(char *key, Object *obj); + + // Iterative accessors. + char *getKey(int i); + Object *getVal(int i, Object *obj); + Object *getValNF(int i, Object *obj); + + // Set the xref pointer. This is only used in one special case: the + // trailer dictionary, which is read before the xref table is + // parsed. + void setXRef(XRef *xrefA) { xref = xrefA; } + +private: + + XRef *xref; // the xref table for this PDF file + DictEntry *entries; // array of entries + int size; // size of array + int length; // number of entries in dictionary + int ref; // reference count + + DictEntry *find(char *key); +}; + +#endif diff --git a/kpdf/xpdf/xpdf/Error.h b/kpdf/xpdf/xpdf/Error.h new file mode 100644 index 00000000..c7bda4b6 --- /dev/null +++ b/kpdf/xpdf/xpdf/Error.h @@ -0,0 +1,23 @@ +//======================================================================== +// +// Error.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef ERROR_H +#define ERROR_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include +#include "xpdf_config.h" + +extern void CDECL error(int pos, char *msg, ...); + +#endif diff --git a/kpdf/xpdf/xpdf/ErrorCodes.h b/kpdf/xpdf/xpdf/ErrorCodes.h new file mode 100644 index 00000000..b28528df --- /dev/null +++ b/kpdf/xpdf/xpdf/ErrorCodes.h @@ -0,0 +1,36 @@ +//======================================================================== +// +// ErrorCodes.h +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef ERRORCODES_H +#define ERRORCODES_H + +#define errNone 0 // no error + +#define errOpenFile 1 // couldn't open the PDF file + +#define errBadCatalog 2 // couldn't read the page catalog + +#define errDamaged 3 // PDF file was damaged and couldn't be + // repaired + +#define errEncrypted 4 // file was encrypted and password was + // incorrect or not supplied + +#define errHighlightFile 5 // nonexistent or invalid highlight file + +#define errBadPrinter 6 // invalid printer + +#define errPrinting 7 // error during printing + +#define errPermission 8 // PDF file doesn't allow that operation + +#define errBadPageNum 9 // invalid page number + +#define errFileIO 10 // file I/O error + +#endif diff --git a/kpdf/xpdf/xpdf/FontEncodingTables.cc b/kpdf/xpdf/xpdf/FontEncodingTables.cc new file mode 100644 index 00000000..f3b9280a --- /dev/null +++ b/kpdf/xpdf/xpdf/FontEncodingTables.cc @@ -0,0 +1,1824 @@ +//======================================================================== +// +// FontEncodingTables.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include +#include +#include "FontEncodingTables.h" + +char *macRomanEncoding[256] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "space", + "exclam", + "quotedbl", + "numbersign", + "dollar", + "percent", + "ampersand", + "quotesingle", + "parenleft", + "parenright", + "asterisk", + "plus", + "comma", + "hyphen", + "period", + "slash", + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "colon", + "semicolon", + "less", + "equal", + "greater", + "question", + "at", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "bracketleft", + "backslash", + "bracketright", + "asciicircum", + "underscore", + "grave", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "braceleft", + "bar", + "braceright", + "asciitilde", + NULL, + "Adieresis", + "Aring", + "Ccedilla", + "Eacute", + "Ntilde", + "Odieresis", + "Udieresis", + "aacute", + "agrave", + "acircumflex", + "adieresis", + "atilde", + "aring", + "ccedilla", + "eacute", + "egrave", + "ecircumflex", + "edieresis", + "iacute", + "igrave", + "icircumflex", + "idieresis", + "ntilde", + "oacute", + "ograve", + "ocircumflex", + "odieresis", + "otilde", + "uacute", + "ugrave", + "ucircumflex", + "udieresis", + "dagger", + "degree", + "cent", + "sterling", + "section", + "bullet", + "paragraph", + "germandbls", + "registered", + "copyright", + "trademark", + "acute", + "dieresis", + "notequal", + "AE", + "Oslash", + "infinity", + "plusminus", + "lessequal", + "greaterequal", + "yen", + "mu", + "partialdiff", + "summation", + "product", + "pi", + "integral", + "ordfeminine", + "ordmasculine", + "Omega", + "ae", + "oslash", + "questiondown", + "exclamdown", + "logicalnot", + "radical", + "florin", + "approxequal", + "Delta", + "guillemotleft", + "guillemotright", + "ellipsis", + "space", + "Agrave", + "Atilde", + "Otilde", + "OE", + "oe", + "endash", + "emdash", + "quotedblleft", + "quotedblright", + "quoteleft", + "quoteright", + "divide", + "lozenge", + "ydieresis", + "Ydieresis", + "fraction", + "currency", + "guilsinglleft", + "guilsinglright", + "fi", + "fl", + "daggerdbl", + "periodcentered", + "quotesinglbase", + "quotedblbase", + "perthousand", + "Acircumflex", + "Ecircumflex", + "Aacute", + "Edieresis", + "Egrave", + "Iacute", + "Icircumflex", + "Idieresis", + "Igrave", + "Oacute", + "Ocircumflex", + "apple", + "Ograve", + "Uacute", + "Ucircumflex", + "Ugrave", + "dotlessi", + "circumflex", + "tilde", + "macron", + "breve", + "dotaccent", + "ring", + "cedilla", + "hungarumlaut", + "ogonek", + "caron" +}; + +char *macExpertEncoding[256] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "space", + "exclamsmall", + "Hungarumlautsmall", + "centoldstyle", + "dollaroldstyle", + "dollarsuperior", + "ampersandsmall", + "Acutesmall", + "parenleftsuperior", + "parenrightsuperior", + "twodotenleader", + "onedotenleader", + "comma", + "hyphen", + "period", + "fraction", + "zerooldstyle", + "oneoldstyle", + "twooldstyle", + "threeoldstyle", + "fouroldstyle", + "fiveoldstyle", + "sixoldstyle", + "sevenoldstyle", + "eightoldstyle", + "nineoldstyle", + "colon", + "semicolon", + NULL, + "threequartersemdash", + NULL, + "questionsmall", + NULL, + NULL, + NULL, + NULL, + "Ethsmall", + NULL, + NULL, + "onequarter", + "onehalf", + "threequarters", + "oneeighth", + "threeeighths", + "fiveeighths", + "seveneighths", + "onethird", + "twothirds", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "ff", + "fi", + "fl", + "ffi", + "ffl", + "parenleftinferior", + NULL, + "parenrightinferior", + "Circumflexsmall", + "hypheninferior", + "Gravesmall", + "Asmall", + "Bsmall", + "Csmall", + "Dsmall", + "Esmall", + "Fsmall", + "Gsmall", + "Hsmall", + "Ismall", + "Jsmall", + "Ksmall", + "Lsmall", + "Msmall", + "Nsmall", + "Osmall", + "Psmall", + "Qsmall", + "Rsmall", + "Ssmall", + "Tsmall", + "Usmall", + "Vsmall", + "Wsmall", + "Xsmall", + "Ysmall", + "Zsmall", + "colonmonetary", + "onefitted", + "rupiah", + "Tildesmall", + NULL, + NULL, + "asuperior", + "centsuperior", + NULL, + NULL, + NULL, + NULL, + "Aacutesmall", + "Agravesmall", + "Acircumflexsmall", + "Adieresissmall", + "Atildesmall", + "Aringsmall", + "Ccedillasmall", + "Eacutesmall", + "Egravesmall", + "Ecircumflexsmall", + "Edieresissmall", + "Iacutesmall", + "Igravesmall", + "Icircumflexsmall", + "Idieresissmall", + "Ntildesmall", + "Oacutesmall", + "Ogravesmall", + "Ocircumflexsmall", + "Odieresissmall", + "Otildesmall", + "Uacutesmall", + "Ugravesmall", + "Ucircumflexsmall", + "Udieresissmall", + NULL, + "eightsuperior", + "fourinferior", + "threeinferior", + "sixinferior", + "eightinferior", + "seveninferior", + "Scaronsmall", + NULL, + "centinferior", + "twoinferior", + NULL, + "Dieresissmall", + NULL, + "Caronsmall", + "osuperior", + "fiveinferior", + NULL, + "commainferior", + "periodinferior", + "Yacutesmall", + NULL, + "dollarinferior", + NULL, + NULL, + "Thornsmall", + NULL, + "nineinferior", + "zeroinferior", + "Zcaronsmall", + "AEsmall", + "Oslashsmall", + "questiondownsmall", + "oneinferior", + "Lslashsmall", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "Cedillasmall", + NULL, + NULL, + NULL, + NULL, + NULL, + "OEsmall", + "figuredash", + "hyphensuperior", + NULL, + NULL, + NULL, + NULL, + "exclamdownsmall", + NULL, + "Ydieresissmall", + NULL, + "onesuperior", + "twosuperior", + "threesuperior", + "foursuperior", + "fivesuperior", + "sixsuperior", + "sevensuperior", + "ninesuperior", + "zerosuperior", + NULL, + "esuperior", + "rsuperior", + "tsuperior", + NULL, + NULL, + "isuperior", + "ssuperior", + "dsuperior", + NULL, + NULL, + NULL, + NULL, + NULL, + "lsuperior", + "Ogoneksmall", + "Brevesmall", + "Macronsmall", + "bsuperior", + "nsuperior", + "msuperior", + "commasuperior", + "periodsuperior", + "Dotaccentsmall", + "Ringsmall", + NULL, + NULL, + NULL, + NULL +}; + +char *winAnsiEncoding[256] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "space", + "exclam", + "quotedbl", + "numbersign", + "dollar", + "percent", + "ampersand", + "quotesingle", + "parenleft", + "parenright", + "asterisk", + "plus", + "comma", + "hyphen", + "period", + "slash", + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "colon", + "semicolon", + "less", + "equal", + "greater", + "question", + "at", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "bracketleft", + "backslash", + "bracketright", + "asciicircum", + "underscore", + "grave", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "braceleft", + "bar", + "braceright", + "asciitilde", + "bullet", + "Euro", + "bullet", + "quotesinglbase", + "florin", + "quotedblbase", + "ellipsis", + "dagger", + "daggerdbl", + "circumflex", + "perthousand", + "Scaron", + "guilsinglleft", + "OE", + "bullet", + "Zcaron", + "bullet", + "bullet", + "quoteleft", + "quoteright", + "quotedblleft", + "quotedblright", + "bullet", + "endash", + "emdash", + "tilde", + "trademark", + "scaron", + "guilsinglright", + "oe", + "bullet", + "zcaron", + "Ydieresis", + "space", + "exclamdown", + "cent", + "sterling", + "currency", + "yen", + "brokenbar", + "section", + "dieresis", + "copyright", + "ordfeminine", + "guillemotleft", + "logicalnot", + "hyphen", + "registered", + "macron", + "degree", + "plusminus", + "twosuperior", + "threesuperior", + "acute", + "mu", + "paragraph", + "periodcentered", + "cedilla", + "onesuperior", + "ordmasculine", + "guillemotright", + "onequarter", + "onehalf", + "threequarters", + "questiondown", + "Agrave", + "Aacute", + "Acircumflex", + "Atilde", + "Adieresis", + "Aring", + "AE", + "Ccedilla", + "Egrave", + "Eacute", + "Ecircumflex", + "Edieresis", + "Igrave", + "Iacute", + "Icircumflex", + "Idieresis", + "Eth", + "Ntilde", + "Ograve", + "Oacute", + "Ocircumflex", + "Otilde", + "Odieresis", + "multiply", + "Oslash", + "Ugrave", + "Uacute", + "Ucircumflex", + "Udieresis", + "Yacute", + "Thorn", + "germandbls", + "agrave", + "aacute", + "acircumflex", + "atilde", + "adieresis", + "aring", + "ae", + "ccedilla", + "egrave", + "eacute", + "ecircumflex", + "edieresis", + "igrave", + "iacute", + "icircumflex", + "idieresis", + "eth", + "ntilde", + "ograve", + "oacute", + "ocircumflex", + "otilde", + "odieresis", + "divide", + "oslash", + "ugrave", + "uacute", + "ucircumflex", + "udieresis", + "yacute", + "thorn", + "ydieresis" +}; + +char *standardEncoding[256] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "space", + "exclam", + "quotedbl", + "numbersign", + "dollar", + "percent", + "ampersand", + "quoteright", + "parenleft", + "parenright", + "asterisk", + "plus", + "comma", + "hyphen", + "period", + "slash", + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "colon", + "semicolon", + "less", + "equal", + "greater", + "question", + "at", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "bracketleft", + "backslash", + "bracketright", + "asciicircum", + "underscore", + "quoteleft", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "braceleft", + "bar", + "braceright", + "asciitilde", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "exclamdown", + "cent", + "sterling", + "fraction", + "yen", + "florin", + "section", + "currency", + "quotesingle", + "quotedblleft", + "guillemotleft", + "guilsinglleft", + "guilsinglright", + "fi", + "fl", + NULL, + "endash", + "dagger", + "daggerdbl", + "periodcentered", + NULL, + "paragraph", + "bullet", + "quotesinglbase", + "quotedblbase", + "quotedblright", + "guillemotright", + "ellipsis", + "perthousand", + NULL, + "questiondown", + NULL, + "grave", + "acute", + "circumflex", + "tilde", + "macron", + "breve", + "dotaccent", + "dieresis", + NULL, + "ring", + "cedilla", + NULL, + "hungarumlaut", + "ogonek", + "caron", + "emdash", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "AE", + NULL, + "ordfeminine", + NULL, + NULL, + NULL, + NULL, + "Lslash", + "Oslash", + "OE", + "ordmasculine", + NULL, + NULL, + NULL, + NULL, + NULL, + "ae", + NULL, + NULL, + NULL, + "dotlessi", + NULL, + NULL, + "lslash", + "oslash", + "oe", + "germandbls", + NULL, + NULL, + NULL, + NULL +}; + +char *expertEncoding[256] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "space", + "exclamsmall", + "Hungarumlautsmall", + NULL, + "dollaroldstyle", + "dollarsuperior", + "ampersandsmall", + "Acutesmall", + "parenleftsuperior", + "parenrightsuperior", + "twodotenleader", + "onedotenleader", + "comma", + "hyphen", + "period", + "fraction", + "zerooldstyle", + "oneoldstyle", + "twooldstyle", + "threeoldstyle", + "fouroldstyle", + "fiveoldstyle", + "sixoldstyle", + "sevenoldstyle", + "eightoldstyle", + "nineoldstyle", + "colon", + "semicolon", + "commasuperior", + "threequartersemdash", + "periodsuperior", + "questionsmall", + NULL, + "asuperior", + "bsuperior", + "centsuperior", + "dsuperior", + "esuperior", + NULL, + NULL, + NULL, + "isuperior", + NULL, + NULL, + "lsuperior", + "msuperior", + "nsuperior", + "osuperior", + NULL, + NULL, + "rsuperior", + "ssuperior", + "tsuperior", + NULL, + "ff", + "fi", + "fl", + "ffi", + "ffl", + "parenleftinferior", + NULL, + "parenrightinferior", + "Circumflexsmall", + "hyphensuperior", + "Gravesmall", + "Asmall", + "Bsmall", + "Csmall", + "Dsmall", + "Esmall", + "Fsmall", + "Gsmall", + "Hsmall", + "Ismall", + "Jsmall", + "Ksmall", + "Lsmall", + "Msmall", + "Nsmall", + "Osmall", + "Psmall", + "Qsmall", + "Rsmall", + "Ssmall", + "Tsmall", + "Usmall", + "Vsmall", + "Wsmall", + "Xsmall", + "Ysmall", + "Zsmall", + "colonmonetary", + "onefitted", + "rupiah", + "Tildesmall", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "exclamdownsmall", + "centoldstyle", + "Lslashsmall", + NULL, + NULL, + "Scaronsmall", + "Zcaronsmall", + "Dieresissmall", + "Brevesmall", + "Caronsmall", + NULL, + "Dotaccentsmall", + NULL, + NULL, + "Macronsmall", + NULL, + NULL, + "figuredash", + "hypheninferior", + NULL, + NULL, + "Ogoneksmall", + "Ringsmall", + "Cedillasmall", + NULL, + NULL, + NULL, + "onequarter", + "onehalf", + "threequarters", + "questiondownsmall", + "oneeighth", + "threeeighths", + "fiveeighths", + "seveneighths", + "onethird", + "twothirds", + NULL, + NULL, + "zerosuperior", + "onesuperior", + "twosuperior", + "threesuperior", + "foursuperior", + "fivesuperior", + "sixsuperior", + "sevensuperior", + "eightsuperior", + "ninesuperior", + "zeroinferior", + "oneinferior", + "twoinferior", + "threeinferior", + "fourinferior", + "fiveinferior", + "sixinferior", + "seveninferior", + "eightinferior", + "nineinferior", + "centinferior", + "dollarinferior", + "periodinferior", + "commainferior", + "Agravesmall", + "Aacutesmall", + "Acircumflexsmall", + "Atildesmall", + "Adieresissmall", + "Aringsmall", + "AEsmall", + "Ccedillasmall", + "Egravesmall", + "Eacutesmall", + "Ecircumflexsmall", + "Edieresissmall", + "Igravesmall", + "Iacutesmall", + "Icircumflexsmall", + "Idieresissmall", + "Ethsmall", + "Ntildesmall", + "Ogravesmall", + "Oacutesmall", + "Ocircumflexsmall", + "Otildesmall", + "Odieresissmall", + "OEsmall", + "Oslashsmall", + "Ugravesmall", + "Uacutesmall", + "Ucircumflexsmall", + "Udieresissmall", + "Yacutesmall", + "Thornsmall", + "Ydieresissmall" +}; + +char *symbolEncoding[256] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "space", + "exclam", + "universal", + "numbersign", + "existential", + "percent", + "ampersand", + "suchthat", + "parenleft", + "parenright", + "asteriskmath", + "plus", + "comma", + "minus", + "period", + "slash", + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "colon", + "semicolon", + "less", + "equal", + "greater", + "question", + "congruent", + "Alpha", + "Beta", + "Chi", + "Delta", + "Epsilon", + "Phi", + "Gamma", + "Eta", + "Iota", + "theta1", + "Kappa", + "Lambda", + "Mu", + "Nu", + "Omicron", + "Pi", + "Theta", + "Rho", + "Sigma", + "Tau", + "Upsilon", + "sigma1", + "Omega", + "Xi", + "Psi", + "Zeta", + "bracketleft", + "therefore", + "bracketright", + "perpendicular", + "underscore", + "radicalex", + "alpha", + "beta", + "chi", + "delta", + "epsilon", + "phi", + "gamma", + "eta", + "iota", + "phi1", + "kappa", + "lambda", + "mu", + "nu", + "omicron", + "pi", + "theta", + "rho", + "sigma", + "tau", + "upsilon", + "omega1", + "omega", + "xi", + "psi", + "zeta", + "braceleft", + "bar", + "braceright", + "similar", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "Upsilon1", + "minute", + "lessequal", + "fraction", + "infinity", + "florin", + "club", + "diamond", + "heart", + "spade", + "arrowboth", + "arrowleft", + "arrowup", + "arrowright", + "arrowdown", + "degree", + "plusminus", + "second", + "greaterequal", + "multiply", + "proportional", + "partialdiff", + "bullet", + "divide", + "notequal", + "equivalence", + "approxequal", + "ellipsis", + "arrowvertex", + "arrowhorizex", + "carriagereturn", + "aleph", + "Ifraktur", + "Rfraktur", + "weierstrass", + "circlemultiply", + "circleplus", + "emptyset", + "intersection", + "union", + "propersuperset", + "reflexsuperset", + "notsubset", + "propersubset", + "reflexsubset", + "element", + "notelement", + "angle", + "gradient", + "registerserif", + "copyrightserif", + "trademarkserif", + "product", + "radical", + "dotmath", + "logicalnot", + "logicaland", + "logicalor", + "arrowdblboth", + "arrowdblleft", + "arrowdblup", + "arrowdblright", + "arrowdbldown", + "lozenge", + "angleleft", + "registersans", + "copyrightsans", + "trademarksans", + "summation", + "parenlefttp", + "parenleftex", + "parenleftbt", + "bracketlefttp", + "bracketleftex", + "bracketleftbt", + "bracelefttp", + "braceleftmid", + "braceleftbt", + "braceex", + NULL, + "angleright", + "integral", + "integraltp", + "integralex", + "integralbt", + "parenrighttp", + "parenrightex", + "parenrightbt", + "bracketrighttp", + "bracketrightex", + "bracketrightbt", + "bracerighttp", + "bracerightmid", + "bracerightbt", + NULL +}; + +char *zapfDingbatsEncoding[256] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "space", + "a1", + "a2", + "a202", + "a3", + "a4", + "a5", + "a119", + "a118", + "a117", + "a11", + "a12", + "a13", + "a14", + "a15", + "a16", + "a105", + "a17", + "a18", + "a19", + "a20", + "a21", + "a22", + "a23", + "a24", + "a25", + "a26", + "a27", + "a28", + "a6", + "a7", + "a8", + "a9", + "a10", + "a29", + "a30", + "a31", + "a32", + "a33", + "a34", + "a35", + "a36", + "a37", + "a38", + "a39", + "a40", + "a41", + "a42", + "a43", + "a44", + "a45", + "a46", + "a47", + "a48", + "a49", + "a50", + "a51", + "a52", + "a53", + "a54", + "a55", + "a56", + "a57", + "a58", + "a59", + "a60", + "a61", + "a62", + "a63", + "a64", + "a65", + "a66", + "a67", + "a68", + "a69", + "a70", + "a71", + "a72", + "a73", + "a74", + "a203", + "a75", + "a204", + "a76", + "a77", + "a78", + "a79", + "a81", + "a82", + "a83", + "a84", + "a97", + "a98", + "a99", + "a100", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "a101", + "a102", + "a103", + "a104", + "a106", + "a107", + "a108", + "a112", + "a111", + "a110", + "a109", + "a120", + "a121", + "a122", + "a123", + "a124", + "a125", + "a126", + "a127", + "a128", + "a129", + "a130", + "a131", + "a132", + "a133", + "a134", + "a135", + "a136", + "a137", + "a138", + "a139", + "a140", + "a141", + "a142", + "a143", + "a144", + "a145", + "a146", + "a147", + "a148", + "a149", + "a150", + "a151", + "a152", + "a153", + "a154", + "a155", + "a156", + "a157", + "a158", + "a159", + "a160", + "a161", + "a163", + "a164", + "a196", + "a165", + "a192", + "a166", + "a167", + "a168", + "a169", + "a170", + "a171", + "a172", + "a173", + "a162", + "a174", + "a175", + "a176", + "a177", + "a178", + "a179", + "a193", + "a180", + "a199", + "a181", + "a200", + "a182", + NULL, + "a201", + "a183", + "a184", + "a197", + "a185", + "a194", + "a198", + "a186", + "a195", + "a187", + "a188", + "a189", + "a190", + "a191", + NULL +}; diff --git a/kpdf/xpdf/xpdf/FontEncodingTables.h b/kpdf/xpdf/xpdf/FontEncodingTables.h new file mode 100644 index 00000000..8b0a1e7e --- /dev/null +++ b/kpdf/xpdf/xpdf/FontEncodingTables.h @@ -0,0 +1,20 @@ +//======================================================================== +// +// FontEncodingTables.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FONTENCODINGTABLES_H +#define FONTENCODINGTABLES_H + +extern char *macRomanEncoding[]; +extern char *macExpertEncoding[]; +extern char *winAnsiEncoding[]; +extern char *standardEncoding[]; +extern char *expertEncoding[]; +extern char *symbolEncoding[]; +extern char *zapfDingbatsEncoding[]; + +#endif diff --git a/kpdf/xpdf/xpdf/Function.cc b/kpdf/xpdf/xpdf/Function.cc new file mode 100644 index 00000000..eaf8e974 --- /dev/null +++ b/kpdf/xpdf/xpdf/Function.cc @@ -0,0 +1,1575 @@ +//======================================================================== +// +// Function.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include +#include "gmem.h" +#include "Object.h" +#include "Dict.h" +#include "Stream.h" +#include "Error.h" +#include "Function.h" + +//------------------------------------------------------------------------ +// Function +//------------------------------------------------------------------------ + +Function::Function() { +} + +Function::~Function() { +} + +Function *Function::parse(Object *funcObj) { + Function *func; + Dict *dict; + int funcType; + Object obj1; + + if (funcObj->isStream()) { + dict = funcObj->streamGetDict(); + } else if (funcObj->isDict()) { + dict = funcObj->getDict(); + } else if (funcObj->isName("Identity")) { + return new IdentityFunction(); + } else { + error(-1, "Expected function dictionary or stream"); + return NULL; + } + + if (!dict->lookup("FunctionType", &obj1)->isInt()) { + error(-1, "Function type is missing or wrong type"); + obj1.free(); + return NULL; + } + funcType = obj1.getInt(); + obj1.free(); + + if (funcType == 0) { + func = new SampledFunction(funcObj, dict); + } else if (funcType == 2) { + func = new ExponentialFunction(funcObj, dict); + } else if (funcType == 3) { + func = new StitchingFunction(funcObj, dict); + } else if (funcType == 4) { + func = new PostScriptFunction(funcObj, dict); + } else { + error(-1, "Unimplemented function type (%d)", funcType); + return NULL; + } + if (!func->isOk()) { + delete func; + return NULL; + } + + return func; +} + +GBool Function::init(Dict *dict) { + Object obj1, obj2; + int i; + + //----- Domain + if (!dict->lookup("Domain", &obj1)->isArray()) { + error(-1, "Function is missing domain"); + goto err2; + } + m = obj1.arrayGetLength() / 2; + if (m > funcMaxInputs) { + error(-1, "Functions with more than %d inputs are unsupported", + funcMaxInputs); + goto err2; + } + for (i = 0; i < m; ++i) { + obj1.arrayGet(2*i, &obj2); + if (!obj2.isNum()) { + error(-1, "Illegal value in function domain array"); + goto err1; + } + domain[i][0] = obj2.getNum(); + obj2.free(); + obj1.arrayGet(2*i+1, &obj2); + if (!obj2.isNum()) { + error(-1, "Illegal value in function domain array"); + goto err1; + } + domain[i][1] = obj2.getNum(); + obj2.free(); + } + obj1.free(); + + //----- Range + hasRange = gFalse; + n = 0; + if (dict->lookup("Range", &obj1)->isArray()) { + hasRange = gTrue; + n = obj1.arrayGetLength() / 2; + if (n > funcMaxOutputs) { + error(-1, "Functions with more than %d outputs are unsupported", + funcMaxOutputs); + goto err2; + } + for (i = 0; i < n; ++i) { + obj1.arrayGet(2*i, &obj2); + if (!obj2.isNum()) { + error(-1, "Illegal value in function range array"); + goto err1; + } + range[i][0] = obj2.getNum(); + obj2.free(); + obj1.arrayGet(2*i+1, &obj2); + if (!obj2.isNum()) { + error(-1, "Illegal value in function range array"); + goto err1; + } + range[i][1] = obj2.getNum(); + obj2.free(); + } + } + obj1.free(); + + return gTrue; + + err1: + obj2.free(); + err2: + obj1.free(); + return gFalse; +} + +//------------------------------------------------------------------------ +// IdentityFunction +//------------------------------------------------------------------------ + +IdentityFunction::IdentityFunction() { + int i; + + // fill these in with arbitrary values just in case they get used + // somewhere + m = funcMaxInputs; + n = funcMaxOutputs; + for (i = 0; i < funcMaxInputs; ++i) { + domain[i][0] = 0; + domain[i][1] = 1; + } + hasRange = gFalse; +} + +IdentityFunction::~IdentityFunction() { +} + +void IdentityFunction::transform(double *in, double *out) { + int i; + + for (i = 0; i < funcMaxOutputs; ++i) { + out[i] = in[i]; + } +} + +//------------------------------------------------------------------------ +// SampledFunction +//------------------------------------------------------------------------ + +SampledFunction::SampledFunction(Object *funcObj, Dict *dict) { + Stream *str; + int sampleBits; + double sampleMul; + Object obj1, obj2; + Guint buf, bitMask; + int bits; + Guint s; + int i; + + samples = NULL; + sBuf = NULL; + ok = gFalse; + + //----- initialize the generic stuff + if (!init(dict)) { + goto err1; + } + if (!hasRange) { + error(-1, "Type 0 function is missing range"); + goto err1; + } + if (m > sampledFuncMaxInputs) { + error(-1, "Sampled functions with more than %d inputs are unsupported", + sampledFuncMaxInputs); + goto err1; + } + + //----- buffer + sBuf = (double *)gmallocn(1 << m, sizeof(double)); + + //----- get the stream + if (!funcObj->isStream()) { + error(-1, "Type 0 function isn't a stream"); + goto err1; + } + str = funcObj->getStream(); + + //----- Size + if (!dict->lookup("Size", &obj1)->isArray() || + obj1.arrayGetLength() != m) { + error(-1, "Function has missing or invalid size array"); + goto err2; + } + for (i = 0; i < m; ++i) { + obj1.arrayGet(i, &obj2); + if (!obj2.isInt()) { + error(-1, "Illegal value in function size array"); + goto err3; + } + sampleSize[i] = obj2.getInt(); + obj2.free(); + } + obj1.free(); + idxMul[0] = n; + for (i = 1; i < m; ++i) { + idxMul[i] = idxMul[i-1] * sampleSize[i-1]; + } + + //----- BitsPerSample + if (!dict->lookup("BitsPerSample", &obj1)->isInt()) { + error(-1, "Function has missing or invalid BitsPerSample"); + goto err2; + } + sampleBits = obj1.getInt(); + sampleMul = 1.0 / (pow(2.0, (double)sampleBits) - 1); + obj1.free(); + + //----- Encode + if (dict->lookup("Encode", &obj1)->isArray() && + obj1.arrayGetLength() == 2*m) { + for (i = 0; i < m; ++i) { + obj1.arrayGet(2*i, &obj2); + if (!obj2.isNum()) { + error(-1, "Illegal value in function encode array"); + goto err3; + } + encode[i][0] = obj2.getNum(); + obj2.free(); + obj1.arrayGet(2*i+1, &obj2); + if (!obj2.isNum()) { + error(-1, "Illegal value in function encode array"); + goto err3; + } + encode[i][1] = obj2.getNum(); + obj2.free(); + } + } else { + for (i = 0; i < m; ++i) { + encode[i][0] = 0; + encode[i][1] = sampleSize[i] - 1; + } + } + obj1.free(); + for (i = 0; i < m; ++i) { + inputMul[i] = (encode[i][1] - encode[i][0]) / + (domain[i][1] - domain[i][0]); + } + + //----- Decode + if (dict->lookup("Decode", &obj1)->isArray() && + obj1.arrayGetLength() == 2*n) { + for (i = 0; i < n; ++i) { + obj1.arrayGet(2*i, &obj2); + if (!obj2.isNum()) { + error(-1, "Illegal value in function decode array"); + goto err3; + } + decode[i][0] = obj2.getNum(); + obj2.free(); + obj1.arrayGet(2*i+1, &obj2); + if (!obj2.isNum()) { + error(-1, "Illegal value in function decode array"); + goto err3; + } + decode[i][1] = obj2.getNum(); + obj2.free(); + } + } else { + for (i = 0; i < n; ++i) { + decode[i][0] = range[i][0]; + decode[i][1] = range[i][1]; + } + } + obj1.free(); + + //----- samples + nSamples = n; + for (i = 0; i < m; ++i) + nSamples *= sampleSize[i]; + samples = (double *)gmallocn(nSamples, sizeof(double)); + buf = 0; + bits = 0; + bitMask = (1 << sampleBits) - 1; + str->reset(); + for (i = 0; i < nSamples; ++i) { + if (sampleBits == 8) { + s = str->getChar(); + } else if (sampleBits == 16) { + s = str->getChar(); + s = (s << 8) + str->getChar(); + } else if (sampleBits == 32) { + s = str->getChar(); + s = (s << 8) + str->getChar(); + s = (s << 8) + str->getChar(); + s = (s << 8) + str->getChar(); + } else { + while (bits < sampleBits) { + buf = (buf << 8) | (str->getChar() & 0xff); + bits += 8; + } + s = (buf >> (bits - sampleBits)) & bitMask; + bits -= sampleBits; + } + samples[i] = (double)s * sampleMul; + } + str->close(); + + ok = gTrue; + return; + + err3: + obj2.free(); + err2: + obj1.free(); + err1: + return; +} + +SampledFunction::~SampledFunction() { + if (samples) { + gfree(samples); + } + if (sBuf) { + gfree(sBuf); + } +} + +SampledFunction::SampledFunction(SampledFunction *func) { + memcpy(this, func, sizeof(SampledFunction)); + samples = (double *)gmallocn(nSamples, sizeof(double)); + memcpy(samples, func->samples, nSamples * sizeof(double)); + sBuf = (double *)gmallocn(1 << m, sizeof(double)); +} + +void SampledFunction::transform(double *in, double *out) { + double x; + int e[funcMaxInputs][2]; + double efrac0[funcMaxInputs]; + double efrac1[funcMaxInputs]; + int i, j, k, idx, t; + + // map input values into sample array + for (i = 0; i < m; ++i) { + x = (in[i] - domain[i][0]) * inputMul[i] + encode[i][0]; + if (x < 0) { + x = 0; + } else if (x > sampleSize[i] - 1) { + x = sampleSize[i] - 1; + } + e[i][0] = (int)x; + if ((e[i][1] = e[i][0] + 1) >= sampleSize[i]) { + // this happens if in[i] = domain[i][1] + e[i][1] = e[i][0]; + } + efrac1[i] = x - e[i][0]; + efrac0[i] = 1 - efrac1[i]; + } + + // for each output, do m-linear interpolation + for (i = 0; i < n; ++i) { + + // pull 2^m values out of the sample array + for (j = 0; j < (1<>= 1) { + idx += idxMul[k] * (e[k][t & 1]); + } + sBuf[j] = samples[idx]; + } + + // do m sets of interpolations + for (j = 0, t = (1<>= 1) { + for (k = 0; k < t; k += 2) { + sBuf[k >> 1] = efrac0[j] * sBuf[k] + efrac1[j] * sBuf[k+1]; + } + } + + // map output value to range + out[i] = sBuf[0] * (decode[i][1] - decode[i][0]) + decode[i][0]; + if (out[i] < range[i][0]) { + out[i] = range[i][0]; + } else if (out[i] > range[i][1]) { + out[i] = range[i][1]; + } + } +} + +//------------------------------------------------------------------------ +// ExponentialFunction +//------------------------------------------------------------------------ + +ExponentialFunction::ExponentialFunction(Object * /*funcObj*/, Dict *dict) { + Object obj1, obj2; + int i; + + ok = gFalse; + + //----- initialize the generic stuff + if (!init(dict)) { + goto err1; + } + if (m != 1) { + error(-1, "Exponential function with more than one input"); + goto err1; + } + + //----- C0 + if (dict->lookup("C0", &obj1)->isArray()) { + if (hasRange && obj1.arrayGetLength() != n) { + error(-1, "Function's C0 array is wrong length"); + goto err2; + } + n = obj1.arrayGetLength(); + for (i = 0; i < n; ++i) { + obj1.arrayGet(i, &obj2); + if (!obj2.isNum()) { + error(-1, "Illegal value in function C0 array"); + goto err3; + } + c0[i] = obj2.getNum(); + obj2.free(); + } + } else { + if (hasRange && n != 1) { + error(-1, "Function's C0 array is wrong length"); + goto err2; + } + n = 1; + c0[0] = 0; + } + obj1.free(); + + //----- C1 + if (dict->lookup("C1", &obj1)->isArray()) { + if (obj1.arrayGetLength() != n) { + error(-1, "Function's C1 array is wrong length"); + goto err2; + } + for (i = 0; i < n; ++i) { + obj1.arrayGet(i, &obj2); + if (!obj2.isNum()) { + error(-1, "Illegal value in function C1 array"); + goto err3; + } + c1[i] = obj2.getNum(); + obj2.free(); + } + } else { + if (n != 1) { + error(-1, "Function's C1 array is wrong length"); + goto err2; + } + c1[0] = 1; + } + obj1.free(); + + //----- N (exponent) + if (!dict->lookup("N", &obj1)->isNum()) { + error(-1, "Function has missing or invalid N"); + goto err2; + } + e = obj1.getNum(); + obj1.free(); + + ok = gTrue; + return; + + err3: + obj2.free(); + err2: + obj1.free(); + err1: + return; +} + +ExponentialFunction::~ExponentialFunction() { +} + +ExponentialFunction::ExponentialFunction(ExponentialFunction *func) { + memcpy(this, func, sizeof(ExponentialFunction)); +} + +void ExponentialFunction::transform(double *in, double *out) { + double x; + int i; + + if (in[0] < domain[0][0]) { + x = domain[0][0]; + } else if (in[0] > domain[0][1]) { + x = domain[0][1]; + } else { + x = in[0]; + } + for (i = 0; i < n; ++i) { + out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]); + if (hasRange) { + if (out[i] < range[i][0]) { + out[i] = range[i][0]; + } else if (out[i] > range[i][1]) { + out[i] = range[i][1]; + } + } + } + return; +} + +//------------------------------------------------------------------------ +// StitchingFunction +//------------------------------------------------------------------------ + +StitchingFunction::StitchingFunction(Object * /*funcObj*/, Dict *dict) { + Object obj1, obj2; + int i; + + ok = gFalse; + funcs = NULL; + bounds = NULL; + encode = NULL; + scale = NULL; + + //----- initialize the generic stuff + if (!init(dict)) { + goto err1; + } + if (m != 1) { + error(-1, "Stitching function with more than one input"); + goto err1; + } + + //----- Functions + if (!dict->lookup("Functions", &obj1)->isArray()) { + error(-1, "Missing 'Functions' entry in stitching function"); + goto err1; + } + k = obj1.arrayGetLength(); + funcs = (Function **)gmallocn(k, sizeof(Function *)); + bounds = (double *)gmallocn(k + 1, sizeof(double)); + encode = (double *)gmallocn(2 * k, sizeof(double)); + scale = (double *)gmallocn(k, sizeof(double)); + for (i = 0; i < k; ++i) { + funcs[i] = NULL; + } + for (i = 0; i < k; ++i) { + if (!(funcs[i] = Function::parse(obj1.arrayGet(i, &obj2)))) { + goto err2; + } + if (i > 0 && (funcs[i]->getInputSize() != 1 || + funcs[i]->getOutputSize() != funcs[0]->getOutputSize())) { + error(-1, "Incompatible subfunctions in stitching function"); + goto err2; + } + obj2.free(); + } + obj1.free(); + + //----- Bounds + if (!dict->lookup("Bounds", &obj1)->isArray() || + obj1.arrayGetLength() != k - 1) { + error(-1, "Missing or invalid 'Bounds' entry in stitching function"); + goto err1; + } + bounds[0] = domain[0][0]; + for (i = 1; i < k; ++i) { + if (!obj1.arrayGet(i - 1, &obj2)->isNum()) { + error(-1, "Invalid type in 'Bounds' array in stitching function"); + goto err2; + } + bounds[i] = obj2.getNum(); + obj2.free(); + } + bounds[k] = domain[0][1]; + obj1.free(); + + //----- Encode + if (!dict->lookup("Encode", &obj1)->isArray() || + obj1.arrayGetLength() != 2 * k) { + error(-1, "Missing or invalid 'Encode' entry in stitching function"); + goto err1; + } + for (i = 0; i < 2 * k; ++i) { + if (!obj1.arrayGet(i, &obj2)->isNum()) { + error(-1, "Invalid type in 'Encode' array in stitching function"); + goto err2; + } + encode[i] = obj2.getNum(); + obj2.free(); + } + obj1.free(); + + //----- pre-compute the scale factors + for (i = 0; i < k; ++i) { + if (bounds[i] == bounds[i+1]) { + // avoid a divide-by-zero -- in this situation, function i will + // never be used anyway + scale[i] = 0; + } else { + scale[i] = (encode[2*i+1] - encode[2*i]) / (bounds[i+1] - bounds[i]); + } + } + + ok = gTrue; + return; + + err2: + obj2.free(); + err1: + obj1.free(); +} + +StitchingFunction::StitchingFunction(StitchingFunction *func) { + int i; + + k = func->k; + funcs = (Function **)gmallocn(k, sizeof(Function *)); + for (i = 0; i < k; ++i) { + funcs[i] = func->funcs[i]->copy(); + } + bounds = (double *)gmallocn(k + 1, sizeof(double)); + memcpy(bounds, func->bounds, (k + 1) * sizeof(double)); + encode = (double *)gmallocn(2 * k, sizeof(double)); + memcpy(encode, func->encode, 2 * k * sizeof(double)); + scale = (double *)gmallocn(k, sizeof(double)); + memcpy(scale, func->scale, k * sizeof(double)); + ok = gTrue; +} + +StitchingFunction::~StitchingFunction() { + int i; + + if (funcs) { + for (i = 0; i < k; ++i) { + if (funcs[i]) { + delete funcs[i]; + } + } + } + gfree(funcs); + gfree(bounds); + gfree(encode); + gfree(scale); +} + +void StitchingFunction::transform(double *in, double *out) { + double x; + int i; + + if (in[0] < domain[0][0]) { + x = domain[0][0]; + } else if (in[0] > domain[0][1]) { + x = domain[0][1]; + } else { + x = in[0]; + } + for (i = 0; i < k - 1; ++i) { + if (x < bounds[i+1]) { + break; + } + } + x = encode[2*i] + (x - bounds[i]) * scale[i]; + funcs[i]->transform(&x, out); +} + +//------------------------------------------------------------------------ +// PostScriptFunction +//------------------------------------------------------------------------ + +enum PSOp { + psOpAbs, + psOpAdd, + psOpAnd, + psOpAtan, + psOpBitshift, + psOpCeiling, + psOpCopy, + psOpCos, + psOpCvi, + psOpCvr, + psOpDiv, + psOpDup, + psOpEq, + psOpExch, + psOpExp, + psOpFalse, + psOpFloor, + psOpGe, + psOpGt, + psOpIdiv, + psOpIndex, + psOpLe, + psOpLn, + psOpLog, + psOpLt, + psOpMod, + psOpMul, + psOpNe, + psOpNeg, + psOpNot, + psOpOr, + psOpPop, + psOpRoll, + psOpRound, + psOpSin, + psOpSqrt, + psOpSub, + psOpTrue, + psOpTruncate, + psOpXor, + psOpIf, + psOpIfelse, + psOpReturn +}; + +// Note: 'if' and 'ifelse' are parsed separately. +// The rest are listed here in alphabetical order. +// The index in this table is equivalent to the entry in PSOp. +char *psOpNames[] = { + "abs", + "add", + "and", + "atan", + "bitshift", + "ceiling", + "copy", + "cos", + "cvi", + "cvr", + "div", + "dup", + "eq", + "exch", + "exp", + "false", + "floor", + "ge", + "gt", + "idiv", + "index", + "le", + "ln", + "log", + "lt", + "mod", + "mul", + "ne", + "neg", + "not", + "or", + "pop", + "roll", + "round", + "sin", + "sqrt", + "sub", + "true", + "truncate", + "xor" +}; + +#define nPSOps (sizeof(psOpNames) / sizeof(char *)) + +enum PSObjectType { + psBool, + psInt, + psReal, + psOperator, + psBlock +}; + +// In the code array, 'if'/'ifelse' operators take up three slots +// plus space for the code in the subclause(s). +// +// +---------------------------------+ +// | psOperator: psOpIf / psOpIfelse | +// +---------------------------------+ +// | psBlock: ptr= | +// +---------------------------------+ +// | psBlock: ptr= | +// +---------------------------------+ +// | if clause | +// | ... | +// | psOperator: psOpReturn | +// +---------------------------------+ +// | else clause | +// | ... | +// | psOperator: psOpReturn | +// +---------------------------------+ +// | ... | +// +// For 'if', pointer is present in the code stream but unused. + +struct PSObject { + PSObjectType type; + union { + GBool booln; // boolean (stack only) + int intg; // integer (stack and code) + double real; // real (stack and code) + PSOp op; // operator (code only) + int blk; // if/ifelse block pointer (code only) + }; +}; + +#define psStackSize 100 + +class PSStack { +public: + + PSStack() { sp = psStackSize; } + void pushBool(GBool booln); + void pushInt(int intg); + void pushReal(double real); + GBool popBool(); + int popInt(); + double popNum(); + GBool empty() { return sp == psStackSize; } + GBool topIsInt() { return sp < psStackSize && stack[sp].type == psInt; } + GBool topTwoAreInts() + { return sp < psStackSize - 1 && + stack[sp].type == psInt && + stack[sp+1].type == psInt; } + GBool topIsReal() { return sp < psStackSize && stack[sp].type == psReal; } + GBool topTwoAreNums() + { return sp < psStackSize - 1 && + (stack[sp].type == psInt || stack[sp].type == psReal) && + (stack[sp+1].type == psInt || stack[sp+1].type == psReal); } + void copy(int n); + void roll(int n, int j); + void index(int i); + void pop(); + +private: + + GBool checkOverflow(int n = 1); + GBool checkUnderflow(); + GBool checkType(PSObjectType t1, PSObjectType t2); + + PSObject stack[psStackSize]; + int sp; +}; + +GBool PSStack::checkOverflow(int n) { + if (sp - n < 0) { + error(-1, "Stack overflow in PostScript function"); + return gFalse; + } + return gTrue; +} + +GBool PSStack::checkUnderflow() { + if (sp == psStackSize) { + error(-1, "Stack underflow in PostScript function"); + return gFalse; + } + return gTrue; +} + +GBool PSStack::checkType(PSObjectType t1, PSObjectType t2) { + if (stack[sp].type != t1 && stack[sp].type != t2) { + error(-1, "Type mismatch in PostScript function"); + return gFalse; + } + return gTrue; +} + +void PSStack::pushBool(GBool booln) { + if (checkOverflow()) { + stack[--sp].type = psBool; + stack[sp].booln = booln; + } +} + +void PSStack::pushInt(int intg) { + if (checkOverflow()) { + stack[--sp].type = psInt; + stack[sp].intg = intg; + } +} + +void PSStack::pushReal(double real) { + if (checkOverflow()) { + stack[--sp].type = psReal; + stack[sp].real = real; + } +} + +GBool PSStack::popBool() { + if (checkUnderflow() && checkType(psBool, psBool)) { + return stack[sp++].booln; + } + return gFalse; +} + +int PSStack::popInt() { + if (checkUnderflow() && checkType(psInt, psInt)) { + return stack[sp++].intg; + } + return 0; +} + +double PSStack::popNum() { + double ret; + + if (checkUnderflow() && checkType(psInt, psReal)) { + ret = (stack[sp].type == psInt) ? (double)stack[sp].intg : stack[sp].real; + ++sp; + return ret; + } + return 0; +} + +void PSStack::copy(int n) { + int i; + + if (sp + n > psStackSize) { + error(-1, "Stack underflow in PostScript function"); + return; + } + if (!checkOverflow(n)) { + return; + } + for (i = sp + n - 1; i >= sp; --i) { + stack[i - n] = stack[i]; + } + sp -= n; +} + +void PSStack::roll(int n, int j) { + PSObject obj; + int i, k; + + if (j >= 0) { + j %= n; + } else { + j = -j % n; + if (j != 0) { + j = n - j; + } + } + if (n <= 0 || j == 0) { + return; + } + for (i = 0; i < j; ++i) { + obj = stack[sp]; + for (k = sp; k < sp + n - 1; ++k) { + stack[k] = stack[k+1]; + } + stack[sp + n - 1] = obj; + } +} + +void PSStack::index(int i) { + if (!checkOverflow()) { + return; + } + --sp; + stack[sp] = stack[sp + 1 + i]; +} + +void PSStack::pop() { + if (!checkUnderflow()) { + return; + } + ++sp; +} + +PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) { + Stream *str; + int codePtr; + GString *tok; + + code = NULL; + codeSize = 0; + ok = gFalse; + + //----- initialize the generic stuff + if (!init(dict)) { + goto err1; + } + if (!hasRange) { + error(-1, "Type 4 function is missing range"); + goto err1; + } + + //----- get the stream + if (!funcObj->isStream()) { + error(-1, "Type 4 function isn't a stream"); + goto err1; + } + str = funcObj->getStream(); + + //----- parse the function + codeString = new GString(); + str->reset(); + if (!(tok = getToken(str)) || tok->cmp("{")) { + error(-1, "Expected '{' at start of PostScript function"); + if (tok) { + delete tok; + } + goto err1; + } + delete tok; + codePtr = 0; + if (!parseCode(str, &codePtr)) { + goto err2; + } + str->close(); + + ok = gTrue; + + err2: + str->close(); + err1: + return; +} + +PostScriptFunction::PostScriptFunction(PostScriptFunction *func) { + memcpy(this, func, sizeof(PostScriptFunction)); + code = (PSObject *)gmallocn(codeSize, sizeof(PSObject)); + memcpy(code, func->code, codeSize * sizeof(PSObject)); + codeString = func->codeString->copy(); +} + +PostScriptFunction::~PostScriptFunction() { + gfree(code); + delete codeString; +} + +void PostScriptFunction::transform(double *in, double *out) { + PSStack *stack; + int i; + + stack = new PSStack(); + for (i = 0; i < m; ++i) { + //~ may need to check for integers here + stack->pushReal(in[i]); + } + exec(stack, 0); + for (i = n - 1; i >= 0; --i) { + out[i] = stack->popNum(); + if (out[i] < range[i][0]) { + out[i] = range[i][0]; + } else if (out[i] > range[i][1]) { + out[i] = range[i][1]; + } + } + // if (!stack->empty()) { + // error(-1, "Extra values on stack at end of PostScript function"); + // } + delete stack; +} + +GBool PostScriptFunction::parseCode(Stream *str, int *codePtr) { + GString *tok; + char *p; + GBool isReal; + int opPtr, elsePtr; + int a, b, mid, cmp; + + while (1) { + if (!(tok = getToken(str))) { + error(-1, "Unexpected end of PostScript function stream"); + return gFalse; + } + p = tok->getCString(); + if (isdigit(*p) || *p == '.' || *p == '-') { + isReal = gFalse; + for (++p; *p; ++p) { + if (*p == '.') { + isReal = gTrue; + break; + } + } + resizeCode(*codePtr); + if (isReal) { + code[*codePtr].type = psReal; + code[*codePtr].real = atof(tok->getCString()); + } else { + code[*codePtr].type = psInt; + code[*codePtr].intg = atoi(tok->getCString()); + } + ++*codePtr; + delete tok; + } else if (!tok->cmp("{")) { + delete tok; + opPtr = *codePtr; + *codePtr += 3; + resizeCode(opPtr + 2); + if (!parseCode(str, codePtr)) { + return gFalse; + } + if (!(tok = getToken(str))) { + error(-1, "Unexpected end of PostScript function stream"); + return gFalse; + } + if (!tok->cmp("{")) { + elsePtr = *codePtr; + if (!parseCode(str, codePtr)) { + return gFalse; + } + delete tok; + if (!(tok = getToken(str))) { + error(-1, "Unexpected end of PostScript function stream"); + return gFalse; + } + } else { + elsePtr = -1; + } + if (!tok->cmp("if")) { + if (elsePtr >= 0) { + error(-1, "Got 'if' operator with two blocks in PostScript function"); + return gFalse; + } + code[opPtr].type = psOperator; + code[opPtr].op = psOpIf; + code[opPtr+2].type = psBlock; + code[opPtr+2].blk = *codePtr; + } else if (!tok->cmp("ifelse")) { + if (elsePtr < 0) { + error(-1, "Got 'ifelse' operator with one blocks in PostScript function"); + return gFalse; + } + code[opPtr].type = psOperator; + code[opPtr].op = psOpIfelse; + code[opPtr+1].type = psBlock; + code[opPtr+1].blk = elsePtr; + code[opPtr+2].type = psBlock; + code[opPtr+2].blk = *codePtr; + } else { + error(-1, "Expected if/ifelse operator in PostScript function"); + delete tok; + return gFalse; + } + delete tok; + } else if (!tok->cmp("}")) { + delete tok; + resizeCode(*codePtr); + code[*codePtr].type = psOperator; + code[*codePtr].op = psOpReturn; + ++*codePtr; + break; + } else { + a = -1; + b = nPSOps; + // invariant: psOpNames[a] < tok < psOpNames[b] + while (b - a > 1) { + mid = (a + b) / 2; + cmp = tok->cmp(psOpNames[mid]); + if (cmp > 0) { + a = mid; + } else if (cmp < 0) { + b = mid; + } else { + a = b = mid; + } + } + if (cmp != 0) { + error(-1, "Unknown operator '%s' in PostScript function", + tok->getCString()); + delete tok; + return gFalse; + } + delete tok; + resizeCode(*codePtr); + code[*codePtr].type = psOperator; + code[*codePtr].op = (PSOp)a; + ++*codePtr; + } + } + return gTrue; +} + +GString *PostScriptFunction::getToken(Stream *str) { + GString *s; + int c; + GBool comment; + + s = new GString(); + comment = gFalse; + while (1) { + if ((c = str->getChar()) == EOF) { + break; + } + codeString->append(c); + if (comment) { + if (c == '\x0a' || c == '\x0d') { + comment = gFalse; + } + } else if (c == '%') { + comment = gTrue; + } else if (!isspace(c)) { + break; + } + } + if (c == '{' || c == '}') { + s->append((char)c); + } else if (isdigit(c) || c == '.' || c == '-') { + while (1) { + s->append((char)c); + c = str->lookChar(); + if (c == EOF || !(isdigit(c) || c == '.' || c == '-')) { + break; + } + str->getChar(); + codeString->append(c); + } + } else { + while (1) { + s->append((char)c); + c = str->lookChar(); + if (c == EOF || !isalnum(c)) { + break; + } + str->getChar(); + codeString->append(c); + } + } + return s; +} + +void PostScriptFunction::resizeCode(int newSize) { + if (newSize >= codeSize) { + codeSize += 64; + code = (PSObject *)greallocn(code, codeSize, sizeof(PSObject)); + } +} + +void PostScriptFunction::exec(PSStack *stack, int codePtr) { + int i1, i2; + double r1, r2, result; + GBool b1, b2; + + while (1) { + switch (code[codePtr].type) { + case psInt: + stack->pushInt(code[codePtr++].intg); + break; + case psReal: + stack->pushReal(code[codePtr++].real); + break; + case psOperator: + switch (code[codePtr++].op) { + case psOpAbs: + if (stack->topIsInt()) { + stack->pushInt(abs(stack->popInt())); + } else { + stack->pushReal(fabs(stack->popNum())); + } + break; + case psOpAdd: + if (stack->topTwoAreInts()) { + i2 = stack->popInt(); + i1 = stack->popInt(); + stack->pushInt(i1 + i2); + } else { + r2 = stack->popNum(); + r1 = stack->popNum(); + stack->pushReal(r1 + r2); + } + break; + case psOpAnd: + if (stack->topTwoAreInts()) { + i2 = stack->popInt(); + i1 = stack->popInt(); + stack->pushInt(i1 & i2); + } else { + b2 = stack->popBool(); + b1 = stack->popBool(); + stack->pushBool(b1 && b2); + } + break; + case psOpAtan: + r2 = stack->popNum(); + r1 = stack->popNum(); + result = atan2(r1, r2) * 180.0 / M_PI; + if (result < 0) result += 360.0; + stack->pushReal(result); + break; + case psOpBitshift: + i2 = stack->popInt(); + i1 = stack->popInt(); + if (i2 > 0) { + stack->pushInt(i1 << i2); + } else if (i2 < 0) { + stack->pushInt((int)((Guint)i1 >> i2)); + } else { + stack->pushInt(i1); + } + break; + case psOpCeiling: + if (!stack->topIsInt()) { + stack->pushReal(ceil(stack->popNum())); + } + break; + case psOpCopy: + stack->copy(stack->popInt()); + break; + case psOpCos: + stack->pushReal(cos(stack->popNum() * M_PI / 180.0)); + break; + case psOpCvi: + if (!stack->topIsInt()) { + stack->pushInt((int)stack->popNum()); + } + break; + case psOpCvr: + if (!stack->topIsReal()) { + stack->pushReal(stack->popNum()); + } + break; + case psOpDiv: + r2 = stack->popNum(); + r1 = stack->popNum(); + stack->pushReal(r1 / r2); + break; + case psOpDup: + stack->copy(1); + break; + case psOpEq: + if (stack->topTwoAreInts()) { + i2 = stack->popInt(); + i1 = stack->popInt(); + stack->pushBool(i1 == i2); + } else if (stack->topTwoAreNums()) { + r2 = stack->popNum(); + r1 = stack->popNum(); + stack->pushBool(r1 == r2); + } else { + b2 = stack->popBool(); + b1 = stack->popBool(); + stack->pushBool(b1 == b2); + } + break; + case psOpExch: + stack->roll(2, 1); + break; + case psOpExp: + r2 = stack->popNum(); + r1 = stack->popNum(); + stack->pushReal(pow(r1, r2)); + break; + case psOpFalse: + stack->pushBool(gFalse); + break; + case psOpFloor: + if (!stack->topIsInt()) { + stack->pushReal(floor(stack->popNum())); + } + break; + case psOpGe: + if (stack->topTwoAreInts()) { + i2 = stack->popInt(); + i1 = stack->popInt(); + stack->pushBool(i1 >= i2); + } else { + r2 = stack->popNum(); + r1 = stack->popNum(); + stack->pushBool(r1 >= r2); + } + break; + case psOpGt: + if (stack->topTwoAreInts()) { + i2 = stack->popInt(); + i1 = stack->popInt(); + stack->pushBool(i1 > i2); + } else { + r2 = stack->popNum(); + r1 = stack->popNum(); + stack->pushBool(r1 > r2); + } + break; + case psOpIdiv: + i2 = stack->popInt(); + i1 = stack->popInt(); + stack->pushInt(i1 / i2); + break; + case psOpIndex: + stack->index(stack->popInt()); + break; + case psOpLe: + if (stack->topTwoAreInts()) { + i2 = stack->popInt(); + i1 = stack->popInt(); + stack->pushBool(i1 <= i2); + } else { + r2 = stack->popNum(); + r1 = stack->popNum(); + stack->pushBool(r1 <= r2); + } + break; + case psOpLn: + stack->pushReal(log(stack->popNum())); + break; + case psOpLog: + stack->pushReal(log10(stack->popNum())); + break; + case psOpLt: + if (stack->topTwoAreInts()) { + i2 = stack->popInt(); + i1 = stack->popInt(); + stack->pushBool(i1 < i2); + } else { + r2 = stack->popNum(); + r1 = stack->popNum(); + stack->pushBool(r1 < r2); + } + break; + case psOpMod: + i2 = stack->popInt(); + i1 = stack->popInt(); + stack->pushInt(i1 % i2); + break; + case psOpMul: + if (stack->topTwoAreInts()) { + i2 = stack->popInt(); + i1 = stack->popInt(); + //~ should check for out-of-range, and push a real instead + stack->pushInt(i1 * i2); + } else { + r2 = stack->popNum(); + r1 = stack->popNum(); + stack->pushReal(r1 * r2); + } + break; + case psOpNe: + if (stack->topTwoAreInts()) { + i2 = stack->popInt(); + i1 = stack->popInt(); + stack->pushBool(i1 != i2); + } else if (stack->topTwoAreNums()) { + r2 = stack->popNum(); + r1 = stack->popNum(); + stack->pushBool(r1 != r2); + } else { + b2 = stack->popBool(); + b1 = stack->popBool(); + stack->pushBool(b1 != b2); + } + break; + case psOpNeg: + if (stack->topIsInt()) { + stack->pushInt(-stack->popInt()); + } else { + stack->pushReal(-stack->popNum()); + } + break; + case psOpNot: + if (stack->topIsInt()) { + stack->pushInt(~stack->popInt()); + } else { + stack->pushBool(!stack->popBool()); + } + break; + case psOpOr: + if (stack->topTwoAreInts()) { + i2 = stack->popInt(); + i1 = stack->popInt(); + stack->pushInt(i1 | i2); + } else { + b2 = stack->popBool(); + b1 = stack->popBool(); + stack->pushBool(b1 || b2); + } + break; + case psOpPop: + stack->pop(); + break; + case psOpRoll: + i2 = stack->popInt(); + i1 = stack->popInt(); + stack->roll(i1, i2); + break; + case psOpRound: + if (!stack->topIsInt()) { + r1 = stack->popNum(); + stack->pushReal((r1 >= 0) ? floor(r1 + 0.5) : ceil(r1 - 0.5)); + } + break; + case psOpSin: + stack->pushReal(sin(stack->popNum() * M_PI / 180.0)); + break; + case psOpSqrt: + stack->pushReal(sqrt(stack->popNum())); + break; + case psOpSub: + if (stack->topTwoAreInts()) { + i2 = stack->popInt(); + i1 = stack->popInt(); + stack->pushInt(i1 - i2); + } else { + r2 = stack->popNum(); + r1 = stack->popNum(); + stack->pushReal(r1 - r2); + } + break; + case psOpTrue: + stack->pushBool(gTrue); + break; + case psOpTruncate: + if (!stack->topIsInt()) { + r1 = stack->popNum(); + stack->pushReal((r1 >= 0) ? floor(r1) : ceil(r1)); + } + break; + case psOpXor: + if (stack->topTwoAreInts()) { + i2 = stack->popInt(); + i1 = stack->popInt(); + stack->pushInt(i1 ^ i2); + } else { + b2 = stack->popBool(); + b1 = stack->popBool(); + stack->pushBool(b1 ^ b2); + } + break; + case psOpIf: + b1 = stack->popBool(); + if (b1) { + exec(stack, codePtr + 2); + } + codePtr = code[codePtr + 1].blk; + break; + case psOpIfelse: + b1 = stack->popBool(); + if (b1) { + exec(stack, codePtr + 2); + } else { + exec(stack, code[codePtr].blk); + } + codePtr = code[codePtr + 1].blk; + break; + case psOpReturn: + return; + } + break; + default: + error(-1, "Internal: bad object in PostScript function code"); + break; + } + } +} diff --git a/kpdf/xpdf/xpdf/Function.h b/kpdf/xpdf/xpdf/Function.h new file mode 100644 index 00000000..334a4390 --- /dev/null +++ b/kpdf/xpdf/xpdf/Function.h @@ -0,0 +1,229 @@ +//======================================================================== +// +// Function.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FUNCTION_H +#define FUNCTION_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "Object.h" + +class Dict; +class Stream; +struct PSObject; +class PSStack; + +//------------------------------------------------------------------------ +// Function +//------------------------------------------------------------------------ + +#define funcMaxInputs 32 +#define funcMaxOutputs 32 +#define sampledFuncMaxInputs 16 + +class Function { +public: + + Function(); + + virtual ~Function(); + + // Construct a function. Returns NULL if unsuccessful. + static Function *parse(Object *funcObj); + + // Initialize the entries common to all function types. + GBool init(Dict *dict); + + virtual Function *copy() = 0; + + // Return the function type: + // -1 : identity + // 0 : sampled + // 2 : exponential + // 3 : stitching + // 4 : PostScript + virtual int getType() = 0; + + // Return size of input and output tuples. + int getInputSize() { return m; } + int getOutputSize() { return n; } + + double getDomainMin(int i) { return domain[i][0]; } + double getDomainMax(int i) { return domain[i][1]; } + double getRangeMin(int i) { return range[i][0]; } + double getRangeMax(int i) { return range[i][1]; } + GBool getHasRange() { return hasRange; } + + // Transform an input tuple into an output tuple. + virtual void transform(double *in, double *out) = 0; + + virtual GBool isOk() = 0; + +protected: + + int m, n; // size of input and output tuples + double // min and max values for function domain + domain[funcMaxInputs][2]; + double // min and max values for function range + range[funcMaxOutputs][2]; + GBool hasRange; // set if range is defined +}; + +//------------------------------------------------------------------------ +// IdentityFunction +//------------------------------------------------------------------------ + +class IdentityFunction: public Function { +public: + + IdentityFunction(); + virtual ~IdentityFunction(); + virtual Function *copy() { return new IdentityFunction(); } + virtual int getType() { return -1; } + virtual void transform(double *in, double *out); + virtual GBool isOk() { return gTrue; } + +private: +}; + +//------------------------------------------------------------------------ +// SampledFunction +//------------------------------------------------------------------------ + +class SampledFunction: public Function { +public: + + SampledFunction(Object *funcObj, Dict *dict); + virtual ~SampledFunction(); + virtual Function *copy() { return new SampledFunction(this); } + virtual int getType() { return 0; } + virtual void transform(double *in, double *out); + virtual GBool isOk() { return ok; } + + int getSampleSize(int i) { return sampleSize[i]; } + double getEncodeMin(int i) { return encode[i][0]; } + double getEncodeMax(int i) { return encode[i][1]; } + double getDecodeMin(int i) { return decode[i][0]; } + double getDecodeMax(int i) { return decode[i][1]; } + double *getSamples() { return samples; } + +private: + + SampledFunction(SampledFunction *func); + + int // number of samples for each domain element + sampleSize[funcMaxInputs]; + double // min and max values for domain encoder + encode[funcMaxInputs][2]; + double // min and max values for range decoder + decode[funcMaxOutputs][2]; + double // input multipliers + inputMul[funcMaxInputs]; + int idxMul[funcMaxInputs]; // sample array index multipliers + double *samples; // the samples + int nSamples; // size of the samples array + double *sBuf; // buffer for the transform function + GBool ok; +}; + +//------------------------------------------------------------------------ +// ExponentialFunction +//------------------------------------------------------------------------ + +class ExponentialFunction: public Function { +public: + + ExponentialFunction(Object *funcObj, Dict *dict); + virtual ~ExponentialFunction(); + virtual Function *copy() { return new ExponentialFunction(this); } + virtual int getType() { return 2; } + virtual void transform(double *in, double *out); + virtual GBool isOk() { return ok; } + + double *getC0() { return c0; } + double *getC1() { return c1; } + double getE() { return e; } + +private: + + ExponentialFunction(ExponentialFunction *func); + + double c0[funcMaxOutputs]; + double c1[funcMaxOutputs]; + double e; + GBool ok; +}; + +//------------------------------------------------------------------------ +// StitchingFunction +//------------------------------------------------------------------------ + +class StitchingFunction: public Function { +public: + + StitchingFunction(Object *funcObj, Dict *dict); + virtual ~StitchingFunction(); + virtual Function *copy() { return new StitchingFunction(this); } + virtual int getType() { return 3; } + virtual void transform(double *in, double *out); + virtual GBool isOk() { return ok; } + + int getNumFuncs() { return k; } + Function *getFunc(int i) { return funcs[i]; } + double *getBounds() { return bounds; } + double *getEncode() { return encode; } + double *getScale() { return scale; } + +private: + + StitchingFunction(StitchingFunction *func); + + int k; + Function **funcs; + double *bounds; + double *encode; + double *scale; + GBool ok; +}; + +//------------------------------------------------------------------------ +// PostScriptFunction +//------------------------------------------------------------------------ + +class PostScriptFunction: public Function { +public: + + PostScriptFunction(Object *funcObj, Dict *dict); + virtual ~PostScriptFunction(); + virtual Function *copy() { return new PostScriptFunction(this); } + virtual int getType() { return 4; } + virtual void transform(double *in, double *out); + virtual GBool isOk() { return ok; } + + GString *getCodeString() { return codeString; } + +private: + + PostScriptFunction(PostScriptFunction *func); + GBool parseCode(Stream *str, int *codePtr); + GString *getToken(Stream *str); + void resizeCode(int newSize); + void exec(PSStack *stack, int codePtr); + + GString *codeString; + PSObject *code; + int codeSize; + GBool ok; +}; + +#endif diff --git a/kpdf/xpdf/xpdf/Gfx.cc b/kpdf/xpdf/xpdf/Gfx.cc new file mode 100644 index 00000000..b37dcb54 --- /dev/null +++ b/kpdf/xpdf/xpdf/Gfx.cc @@ -0,0 +1,4187 @@ +//======================================================================== +// +// Gfx.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include +#include +#include "gmem.h" +#include "GlobalParams.h" +#include "CharTypes.h" +#include "Object.h" +#include "Array.h" +#include "Dict.h" +#include "Stream.h" +#include "Lexer.h" +#include "Parser.h" +#include "GfxFont.h" +#include "GfxState.h" +#include "OutputDev.h" +#include "Page.h" +#include "Annot.h" +#include "Error.h" +#include "Gfx.h" + +// the MSVC math.h doesn't define this +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +//------------------------------------------------------------------------ +// constants +//------------------------------------------------------------------------ + +// Max recursive depth for a function shading fill. +#define functionMaxDepth 6 + +// Max delta allowed in any color component for a function shading fill. +#define functionColorDelta (dblToCol(1 / 256.0)) + +// Max number of splits along the t axis for an axial shading fill. +#define axialMaxSplits 256 + +// Max delta allowed in any color component for an axial shading fill. +#define axialColorDelta (dblToCol(1 / 256.0)) + +// Max number of splits along the t axis for a radial shading fill. +#define radialMaxSplits 256 + +// Max delta allowed in any color component for a radial shading fill. +#define radialColorDelta (dblToCol(1 / 256.0)) + +// Max recursive depth for a Gouraud triangle shading fill. +#define gouraudMaxDepth 6 + +// Max delta allowed in any color component for a Gouraud triangle +// shading fill. +#define gouraudColorDelta (dblToCol(1 / 256.0)) + +// Max recursive depth for a patch mesh shading fill. +#define patchMaxDepth 6 + +// Max delta allowed in any color component for a patch mesh shading +// fill. +#define patchColorDelta (dblToCol(1 / 256.0)) + +//------------------------------------------------------------------------ +// Operator table +//------------------------------------------------------------------------ + +#ifdef WIN32 // this works around a bug in the VC7 compiler +# pragma optimize("",off) +#endif + +Operator Gfx::opTab[] = { + {"\"", 3, {tchkNum, tchkNum, tchkString}, + &Gfx::opMoveSetShowText}, + {"'", 1, {tchkString}, + &Gfx::opMoveShowText}, + {"B", 0, {tchkNone}, + &Gfx::opFillStroke}, + {"B*", 0, {tchkNone}, + &Gfx::opEOFillStroke}, + {"BDC", 2, {tchkName, tchkProps}, + &Gfx::opBeginMarkedContent}, + {"BI", 0, {tchkNone}, + &Gfx::opBeginImage}, + {"BMC", 1, {tchkName}, + &Gfx::opBeginMarkedContent}, + {"BT", 0, {tchkNone}, + &Gfx::opBeginText}, + {"BX", 0, {tchkNone}, + &Gfx::opBeginIgnoreUndef}, + {"CS", 1, {tchkName}, + &Gfx::opSetStrokeColorSpace}, + {"DP", 2, {tchkName, tchkProps}, + &Gfx::opMarkPoint}, + {"Do", 1, {tchkName}, + &Gfx::opXObject}, + {"EI", 0, {tchkNone}, + &Gfx::opEndImage}, + {"EMC", 0, {tchkNone}, + &Gfx::opEndMarkedContent}, + {"ET", 0, {tchkNone}, + &Gfx::opEndText}, + {"EX", 0, {tchkNone}, + &Gfx::opEndIgnoreUndef}, + {"F", 0, {tchkNone}, + &Gfx::opFill}, + {"G", 1, {tchkNum}, + &Gfx::opSetStrokeGray}, + {"ID", 0, {tchkNone}, + &Gfx::opImageData}, + {"J", 1, {tchkInt}, + &Gfx::opSetLineCap}, + {"K", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, + &Gfx::opSetStrokeCMYKColor}, + {"M", 1, {tchkNum}, + &Gfx::opSetMiterLimit}, + {"MP", 1, {tchkName}, + &Gfx::opMarkPoint}, + {"Q", 0, {tchkNone}, + &Gfx::opRestore}, + {"RG", 3, {tchkNum, tchkNum, tchkNum}, + &Gfx::opSetStrokeRGBColor}, + {"S", 0, {tchkNone}, + &Gfx::opStroke}, + {"SC", -4, {tchkNum, tchkNum, tchkNum, tchkNum}, + &Gfx::opSetStrokeColor}, + {"SCN", -33, {tchkSCN, tchkSCN, tchkSCN, tchkSCN, + tchkSCN, tchkSCN, tchkSCN, tchkSCN, + tchkSCN, tchkSCN, tchkSCN, tchkSCN, + tchkSCN, tchkSCN, tchkSCN, tchkSCN, + tchkSCN, tchkSCN, tchkSCN, tchkSCN, + tchkSCN, tchkSCN, tchkSCN, tchkSCN, + tchkSCN, tchkSCN, tchkSCN, tchkSCN, + tchkSCN, tchkSCN, tchkSCN, tchkSCN, + tchkSCN}, + &Gfx::opSetStrokeColorN}, + {"T*", 0, {tchkNone}, + &Gfx::opTextNextLine}, + {"TD", 2, {tchkNum, tchkNum}, + &Gfx::opTextMoveSet}, + {"TJ", 1, {tchkArray}, + &Gfx::opShowSpaceText}, + {"TL", 1, {tchkNum}, + &Gfx::opSetTextLeading}, + {"Tc", 1, {tchkNum}, + &Gfx::opSetCharSpacing}, + {"Td", 2, {tchkNum, tchkNum}, + &Gfx::opTextMove}, + {"Tf", 2, {tchkName, tchkNum}, + &Gfx::opSetFont}, + {"Tj", 1, {tchkString}, + &Gfx::opShowText}, + {"Tm", 6, {tchkNum, tchkNum, tchkNum, tchkNum, + tchkNum, tchkNum}, + &Gfx::opSetTextMatrix}, + {"Tr", 1, {tchkInt}, + &Gfx::opSetTextRender}, + {"Ts", 1, {tchkNum}, + &Gfx::opSetTextRise}, + {"Tw", 1, {tchkNum}, + &Gfx::opSetWordSpacing}, + {"Tz", 1, {tchkNum}, + &Gfx::opSetHorizScaling}, + {"W", 0, {tchkNone}, + &Gfx::opClip}, + {"W*", 0, {tchkNone}, + &Gfx::opEOClip}, + {"b", 0, {tchkNone}, + &Gfx::opCloseFillStroke}, + {"b*", 0, {tchkNone}, + &Gfx::opCloseEOFillStroke}, + {"c", 6, {tchkNum, tchkNum, tchkNum, tchkNum, + tchkNum, tchkNum}, + &Gfx::opCurveTo}, + {"cm", 6, {tchkNum, tchkNum, tchkNum, tchkNum, + tchkNum, tchkNum}, + &Gfx::opConcat}, + {"cs", 1, {tchkName}, + &Gfx::opSetFillColorSpace}, + {"d", 2, {tchkArray, tchkNum}, + &Gfx::opSetDash}, + {"d0", 2, {tchkNum, tchkNum}, + &Gfx::opSetCharWidth}, + {"d1", 6, {tchkNum, tchkNum, tchkNum, tchkNum, + tchkNum, tchkNum}, + &Gfx::opSetCacheDevice}, + {"f", 0, {tchkNone}, + &Gfx::opFill}, + {"f*", 0, {tchkNone}, + &Gfx::opEOFill}, + {"g", 1, {tchkNum}, + &Gfx::opSetFillGray}, + {"gs", 1, {tchkName}, + &Gfx::opSetExtGState}, + {"h", 0, {tchkNone}, + &Gfx::opClosePath}, + {"i", 1, {tchkNum}, + &Gfx::opSetFlat}, + {"j", 1, {tchkInt}, + &Gfx::opSetLineJoin}, + {"k", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, + &Gfx::opSetFillCMYKColor}, + {"l", 2, {tchkNum, tchkNum}, + &Gfx::opLineTo}, + {"m", 2, {tchkNum, tchkNum}, + &Gfx::opMoveTo}, + {"n", 0, {tchkNone}, + &Gfx::opEndPath}, + {"q", 0, {tchkNone}, + &Gfx::opSave}, + {"re", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, + &Gfx::opRectangle}, + {"rg", 3, {tchkNum, tchkNum, tchkNum}, + &Gfx::opSetFillRGBColor}, + {"ri", 1, {tchkName}, + &Gfx::opSetRenderingIntent}, + {"s", 0, {tchkNone}, + &Gfx::opCloseStroke}, + {"sc", -4, {tchkNum, tchkNum, tchkNum, tchkNum}, + &Gfx::opSetFillColor}, + {"scn", -33, {tchkSCN, tchkSCN, tchkSCN, tchkSCN, + tchkSCN, tchkSCN, tchkSCN, tchkSCN, + tchkSCN, tchkSCN, tchkSCN, tchkSCN, + tchkSCN, tchkSCN, tchkSCN, tchkSCN, + tchkSCN, tchkSCN, tchkSCN, tchkSCN, + tchkSCN, tchkSCN, tchkSCN, tchkSCN, + tchkSCN, tchkSCN, tchkSCN, tchkSCN, + tchkSCN, tchkSCN, tchkSCN, tchkSCN, + tchkSCN}, + &Gfx::opSetFillColorN}, + {"sh", 1, {tchkName}, + &Gfx::opShFill}, + {"v", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, + &Gfx::opCurveTo1}, + {"w", 1, {tchkNum}, + &Gfx::opSetLineWidth}, + {"y", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, + &Gfx::opCurveTo2}, +}; + +#ifdef WIN32 // this works around a bug in the VC7 compiler +# pragma optimize("",on) +#endif + +#define numOps (sizeof(opTab) / sizeof(Operator)) + +//------------------------------------------------------------------------ +// GfxResources +//------------------------------------------------------------------------ + +GfxResources::GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA) { + Object obj1, obj2; + Ref r; + + if (resDict) { + + // build font dictionary + fonts = NULL; + resDict->lookupNF("Font", &obj1); + if (obj1.isRef()) { + obj1.fetch(xref, &obj2); + if (obj2.isDict()) { + r = obj1.getRef(); + fonts = new GfxFontDict(xref, &r, obj2.getDict()); + } + obj2.free(); + } else if (obj1.isDict()) { + fonts = new GfxFontDict(xref, NULL, obj1.getDict()); + } + obj1.free(); + + // get XObject dictionary + resDict->lookup("XObject", &xObjDict); + + // get color space dictionary + resDict->lookup("ColorSpace", &colorSpaceDict); + + // get pattern dictionary + resDict->lookup("Pattern", &patternDict); + + // get shading dictionary + resDict->lookup("Shading", &shadingDict); + + // get graphics state parameter dictionary + resDict->lookup("ExtGState", &gStateDict); + + } else { + fonts = NULL; + xObjDict.initNull(); + colorSpaceDict.initNull(); + patternDict.initNull(); + shadingDict.initNull(); + gStateDict.initNull(); + } + + next = nextA; +} + +GfxResources::~GfxResources() { + if (fonts) { + delete fonts; + } + xObjDict.free(); + colorSpaceDict.free(); + patternDict.free(); + shadingDict.free(); + gStateDict.free(); +} + +GfxFont *GfxResources::lookupFont(char *name) { + GfxFont *font; + GfxResources *resPtr; + + for (resPtr = this; resPtr; resPtr = resPtr->next) { + if (resPtr->fonts) { + if ((font = resPtr->fonts->lookup(name))) + return font; + } + } + error(-1, "Unknown font tag '%s'", name); + return NULL; +} + +GBool GfxResources::lookupXObject(char *name, Object *obj) { + GfxResources *resPtr; + + for (resPtr = this; resPtr; resPtr = resPtr->next) { + if (resPtr->xObjDict.isDict()) { + if (!resPtr->xObjDict.dictLookup(name, obj)->isNull()) + return gTrue; + obj->free(); + } + } + error(-1, "XObject '%s' is unknown", name); + return gFalse; +} + +GBool GfxResources::lookupXObjectNF(char *name, Object *obj) { + GfxResources *resPtr; + + for (resPtr = this; resPtr; resPtr = resPtr->next) { + if (resPtr->xObjDict.isDict()) { + if (!resPtr->xObjDict.dictLookupNF(name, obj)->isNull()) + return gTrue; + obj->free(); + } + } + error(-1, "XObject '%s' is unknown", name); + return gFalse; +} + +void GfxResources::lookupColorSpace(char *name, Object *obj) { + GfxResources *resPtr; + + for (resPtr = this; resPtr; resPtr = resPtr->next) { + if (resPtr->colorSpaceDict.isDict()) { + if (!resPtr->colorSpaceDict.dictLookup(name, obj)->isNull()) { + return; + } + obj->free(); + } + } + obj->initNull(); +} + +GfxPattern *GfxResources::lookupPattern(char *name) { + GfxResources *resPtr; + GfxPattern *pattern; + Object obj; + + for (resPtr = this; resPtr; resPtr = resPtr->next) { + if (resPtr->patternDict.isDict()) { + if (!resPtr->patternDict.dictLookup(name, &obj)->isNull()) { + pattern = GfxPattern::parse(&obj); + obj.free(); + return pattern; + } + obj.free(); + } + } + error(-1, "Unknown pattern '%s'", name); + return NULL; +} + +GfxShading *GfxResources::lookupShading(char *name) { + GfxResources *resPtr; + GfxShading *shading; + Object obj; + + for (resPtr = this; resPtr; resPtr = resPtr->next) { + if (resPtr->shadingDict.isDict()) { + if (!resPtr->shadingDict.dictLookup(name, &obj)->isNull()) { + shading = GfxShading::parse(&obj); + obj.free(); + return shading; + } + obj.free(); + } + } + error(-1, "Unknown shading '%s'", name); + return NULL; +} + +GBool GfxResources::lookupGState(char *name, Object *obj) { + GfxResources *resPtr; + + for (resPtr = this; resPtr; resPtr = resPtr->next) { + if (resPtr->gStateDict.isDict()) { + if (!resPtr->gStateDict.dictLookup(name, obj)->isNull()) { + return gTrue; + } + obj->free(); + } + } + error(-1, "ExtGState '%s' is unknown", name); + return gFalse; +} + +//------------------------------------------------------------------------ +// Gfx +//------------------------------------------------------------------------ + +Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, + double hDPI, double vDPI, PDFRectangle *box, + PDFRectangle *cropBox, int rotate, + GBool (*abortCheckCbkA)(void *data), + void *abortCheckCbkDataA) { + int i; + + xref = xrefA; + subPage = gFalse; + printCommands = globalParams->getPrintCommands(); + + // start the resource stack + res = new GfxResources(xref, resDict, NULL); + + // initialize + out = outA; + state = new GfxState(hDPI, vDPI, box, rotate, out->upsideDown()); + fontChanged = gFalse; + clip = clipNone; + ignoreUndef = 0; + out->startPage(pageNum, state); + out->setDefaultCTM(state->getCTM()); + out->updateAll(state); + for (i = 0; i < 6; ++i) { + baseMatrix[i] = state->getCTM()[i]; + } + formDepth = 0; + abortCheckCbk = abortCheckCbkA; + abortCheckCbkData = abortCheckCbkDataA; + + // set crop box + if (cropBox) { + state->moveTo(cropBox->x1, cropBox->y1); + state->lineTo(cropBox->x2, cropBox->y1); + state->lineTo(cropBox->x2, cropBox->y2); + state->lineTo(cropBox->x1, cropBox->y2); + state->closePath(); + state->clip(); + out->clip(state); + state->clearPath(); + } +} + +Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, + PDFRectangle *box, PDFRectangle *cropBox, + GBool (*abortCheckCbkA)(void *data), + void *abortCheckCbkDataA) { + int i; + + xref = xrefA; + subPage = gTrue; + printCommands = globalParams->getPrintCommands(); + + // start the resource stack + res = new GfxResources(xref, resDict, NULL); + + // initialize + out = outA; + state = new GfxState(72, 72, box, 0, gFalse); + fontChanged = gFalse; + clip = clipNone; + ignoreUndef = 0; + for (i = 0; i < 6; ++i) { + baseMatrix[i] = state->getCTM()[i]; + } + formDepth = 0; + abortCheckCbk = abortCheckCbkA; + abortCheckCbkData = abortCheckCbkDataA; + + // set crop box + if (cropBox) { + state->moveTo(cropBox->x1, cropBox->y1); + state->lineTo(cropBox->x2, cropBox->y1); + state->lineTo(cropBox->x2, cropBox->y2); + state->lineTo(cropBox->x1, cropBox->y2); + state->closePath(); + state->clip(); + out->clip(state); + state->clearPath(); + } +} + +Gfx::~Gfx() { + while (state->hasSaves()) { + restoreState(); + } + if (!subPage) { + out->endPage(); + } + while (res) { + popResources(); + } + if (state) { + delete state; + } +} + +void Gfx::display(Object *obj, GBool topLevel) { + Object obj2; + int i; + + if (obj->isArray()) { + for (i = 0; i < obj->arrayGetLength(); ++i) { + obj->arrayGet(i, &obj2); + if (!obj2.isStream()) { + error(-1, "Weird page contents"); + obj2.free(); + return; + } + obj2.free(); + } + } else if (!obj->isStream()) { + error(-1, "Weird page contents"); + return; + } + parser = new Parser(xref, new Lexer(xref, obj), gFalse); + go(topLevel); + delete parser; + parser = NULL; +} + +void Gfx::go(GBool topLevel) { + Object obj; + Object args[maxArgs]; + int numArgs, i; + int lastAbortCheck; + + // scan a sequence of objects + updateLevel = lastAbortCheck = 0; + numArgs = 0; + parser->getObj(&obj); + while (!obj.isEOF()) { + + // got a command - execute it + if (obj.isCmd()) { + if (printCommands) { + obj.print(stdout); + for (i = 0; i < numArgs; ++i) { + printf(" "); + args[i].print(stdout); + } + printf("\n"); + fflush(stdout); + } + execOp(&obj, args, numArgs); + obj.free(); + for (i = 0; i < numArgs; ++i) + args[i].free(); + numArgs = 0; + + // periodically update display + if (++updateLevel >= 20000) { + out->dump(); + updateLevel = 0; + } + + // check for an abort + if (abortCheckCbk) { + if (updateLevel - lastAbortCheck > 10) { + if ((*abortCheckCbk)(abortCheckCbkData)) { + break; + } + lastAbortCheck = updateLevel; + } + } + + // got an argument - save it + } else if (numArgs < maxArgs) { + args[numArgs++] = obj; + + // too many arguments - something is wrong + } else { + error(getPos(), "Too many args in content stream"); + if (printCommands) { + printf("throwing away arg: "); + obj.print(stdout); + printf("\n"); + fflush(stdout); + } + obj.free(); + } + + // grab the next object + parser->getObj(&obj); + } + obj.free(); + + // args at end with no command + if (numArgs > 0) { + error(getPos(), "Leftover args in content stream"); + if (printCommands) { + printf("%d leftovers:", numArgs); + for (i = 0; i < numArgs; ++i) { + printf(" "); + args[i].print(stdout); + } + printf("\n"); + fflush(stdout); + } + for (i = 0; i < numArgs; ++i) + args[i].free(); + } + + // update display + if (topLevel && updateLevel > 0) { + out->dump(); + } +} + +void Gfx::execOp(Object *cmd, Object args[], int numArgs) { + Operator *op; + char *name; + Object *argPtr; + int i; + + // find operator + name = cmd->getCmd(); + if (!(op = findOp(name))) { + if (ignoreUndef == 0) + error(getPos(), "Unknown operator '%s'", name); + return; + } + + // type check args + argPtr = args; + if (op->numArgs >= 0) { + if (numArgs < op->numArgs) { + error(getPos(), "Too few (%d) args to '%s' operator", numArgs, name); + return; + } + if (numArgs > op->numArgs) { +#if 0 + error(getPos(), "Too many (%d) args to '%s' operator", numArgs, name); +#endif + argPtr += numArgs - op->numArgs; + numArgs = op->numArgs; + } + } else { + if (numArgs > -op->numArgs) { + error(getPos(), "Too many (%d) args to '%s' operator", + numArgs, name); + return; + } + } + for (i = 0; i < numArgs; ++i) { + if (!checkArg(&argPtr[i], op->tchk[i])) { + error(getPos(), "Arg #%d to '%s' operator is wrong type (%s)", + i, name, argPtr[i].getTypeName()); + return; + } + } + + // do it + (this->*op->func)(argPtr, numArgs); +} + +Operator *Gfx::findOp(char *name) { + int a, b, m, cmp; + + a = -1; + b = numOps; + // invariant: opTab[a] < name < opTab[b] + while (b - a > 1) { + m = (a + b) / 2; + cmp = strcmp(opTab[m].name, name); + if (cmp < 0) + a = m; + else if (cmp > 0) + b = m; + else + a = b = m; + } + if (cmp != 0) + return NULL; + return &opTab[a]; +} + +GBool Gfx::checkArg(Object *arg, TchkType type) { + switch (type) { + case tchkBool: return arg->isBool(); + case tchkInt: return arg->isInt(); + case tchkNum: return arg->isNum(); + case tchkString: return arg->isString(); + case tchkName: return arg->isName(); + case tchkArray: return arg->isArray(); + case tchkProps: return arg->isDict() || arg->isName(); + case tchkSCN: return arg->isNum() || arg->isName(); + case tchkNone: return gFalse; + } + return gFalse; +} + +int Gfx::getPos() { + return parser ? parser->getPos() : -1; +} + +//------------------------------------------------------------------------ +// graphics state operators +//------------------------------------------------------------------------ + +void Gfx::opSave(Object * /*args[]*/, int /*numArgs*/) { + saveState(); +} + +void Gfx::opRestore(Object * /*args[]*/, int /*numArgs*/) { + restoreState(); +} + +void Gfx::opConcat(Object args[], int /*numArgs*/) { + state->concatCTM(args[0].getNum(), args[1].getNum(), + args[2].getNum(), args[3].getNum(), + args[4].getNum(), args[5].getNum()); + out->updateCTM(state, args[0].getNum(), args[1].getNum(), + args[2].getNum(), args[3].getNum(), + args[4].getNum(), args[5].getNum()); + fontChanged = gTrue; +} + +void Gfx::opSetDash(Object args[], int /*numArgs*/) { + Array *a; + int length; + Object obj; + double *dash; + int i; + + a = args[0].getArray(); + length = a->getLength(); + if (length == 0) { + dash = NULL; + } else { + dash = (double *)gmallocn(length, sizeof(double)); + for (i = 0; i < length; ++i) { + dash[i] = a->get(i, &obj)->getNum(); + obj.free(); + } + } + state->setLineDash(dash, length, args[1].getNum()); + out->updateLineDash(state); +} + +void Gfx::opSetFlat(Object args[], int /*numArgs*/) { + state->setFlatness((int)args[0].getNum()); + out->updateFlatness(state); +} + +void Gfx::opSetLineJoin(Object args[], int /*numArgs*/) { + state->setLineJoin(args[0].getInt()); + out->updateLineJoin(state); +} + +void Gfx::opSetLineCap(Object args[], int /*numArgs*/) { + state->setLineCap(args[0].getInt()); + out->updateLineCap(state); +} + +void Gfx::opSetMiterLimit(Object args[], int /*numArgs*/) { + state->setMiterLimit(args[0].getNum()); + out->updateMiterLimit(state); +} + +void Gfx::opSetLineWidth(Object args[], int /*numArgs*/) { + state->setLineWidth(args[0].getNum()); + out->updateLineWidth(state); +} + +void Gfx::opSetExtGState(Object args[], int /*numArgs*/) { + Object obj1, obj2, obj3, obj4, obj5; + GfxBlendMode mode; + GBool haveFillOP; + Function *funcs[4]; + GfxColor backdropColor; + GBool haveBackdropColor; + GfxColorSpace *blendingColorSpace; + GBool alpha, isolated, knockout; + int i; + + if (!res->lookupGState(args[0].getName(), &obj1)) { + return; + } + if (!obj1.isDict()) { + error(getPos(), "ExtGState '%s' is wrong type", args[0].getName()); + obj1.free(); + return; + } + if (printCommands) { + printf(" gfx state dict: "); + obj1.print(); + printf("\n"); + } + + // transparency support: blend mode, fill/stroke opacity + if (!obj1.dictLookup("BM", &obj2)->isNull()) { + if (state->parseBlendMode(&obj2, &mode)) { + state->setBlendMode(mode); + out->updateBlendMode(state); + } else { + error(getPos(), "Invalid blend mode in ExtGState"); + } + } + obj2.free(); + if (obj1.dictLookup("ca", &obj2)->isNum()) { + state->setFillOpacity(obj2.getNum()); + out->updateFillOpacity(state); + } + obj2.free(); + if (obj1.dictLookup("CA", &obj2)->isNum()) { + state->setStrokeOpacity(obj2.getNum()); + out->updateStrokeOpacity(state); + } + obj2.free(); + + // fill/stroke overprint + if ((haveFillOP = (obj1.dictLookup("op", &obj2)->isBool()))) { + state->setFillOverprint(obj2.getBool()); + out->updateFillOverprint(state); + } + obj2.free(); + if (obj1.dictLookup("OP", &obj2)->isBool()) { + state->setStrokeOverprint(obj2.getBool()); + out->updateStrokeOverprint(state); + if (!haveFillOP) { + state->setFillOverprint(obj2.getBool()); + out->updateFillOverprint(state); + } + } + obj2.free(); + + // stroke adjust + if (obj1.dictLookup("SA", &obj2)->isBool()) { + state->setStrokeAdjust(obj2.getBool()); + out->updateStrokeAdjust(state); + } + obj2.free(); + + // transfer function + if (obj1.dictLookup("TR2", &obj2)->isNull()) { + obj2.free(); + obj1.dictLookup("TR", &obj2); + } + if (obj2.isName("Default") || + obj2.isName("Identity")) { + funcs[0] = funcs[1] = funcs[2] = funcs[3] = NULL; + state->setTransfer(funcs); + out->updateTransfer(state); + } else if (obj2.isArray() && obj2.arrayGetLength() == 4) { + for (i = 0; i < 4; ++i) { + obj2.arrayGet(i, &obj3); + funcs[i] = Function::parse(&obj3); + obj3.free(); + if (!funcs[i]) { + break; + } + } + if (i == 4) { + state->setTransfer(funcs); + out->updateTransfer(state); + } + } else if (obj2.isName() || obj2.isDict() || obj2.isStream()) { + if ((funcs[0] = Function::parse(&obj2))) { + funcs[1] = funcs[2] = funcs[3] = NULL; + state->setTransfer(funcs); + out->updateTransfer(state); + } + } else if (!obj2.isNull()) { + error(getPos(), "Invalid transfer function in ExtGState"); + } + obj2.free(); + + // soft mask + if (!obj1.dictLookup("SMask", &obj2)->isNull()) { + if (obj2.isName("None")) { + out->clearSoftMask(state); + } else if (obj2.isDict()) { + if (obj2.dictLookup("S", &obj3)->isName("Alpha")) { + alpha = gTrue; + } else { // "Luminosity" + alpha = gFalse; + } + obj3.free(); + funcs[0] = NULL; + if (!obj2.dictLookup("TR", &obj3)->isNull()) { + funcs[0] = Function::parse(&obj3); + if (funcs[0]->getInputSize() != 1 || + funcs[0]->getOutputSize() != 1) { + error(getPos(), + "Invalid transfer function in soft mask in ExtGState"); + delete funcs[0]; + funcs[0] = NULL; + } + } + obj3.free(); + if ((haveBackdropColor = obj2.dictLookup("BC", &obj3)->isArray())) { + for (i = 0; i < gfxColorMaxComps; ++i) { + backdropColor.c[i] = 0; + } + for (i = 0; i < obj3.arrayGetLength() && i < gfxColorMaxComps; ++i) { + obj3.arrayGet(i, &obj4); + if (obj4.isNum()) { + backdropColor.c[i] = dblToCol(obj4.getNum()); + } + obj4.free(); + } + } + obj3.free(); + if (obj2.dictLookup("G", &obj3)->isStream()) { + if (obj3.streamGetDict()->lookup("Group", &obj4)->isDict()) { + blendingColorSpace = NULL; + isolated = knockout = gFalse; + if (!obj4.dictLookup("CS", &obj5)->isNull()) { + blendingColorSpace = GfxColorSpace::parse(&obj5); + } + obj5.free(); + if (obj4.dictLookup("I", &obj5)->isBool()) { + isolated = obj5.getBool(); + } + obj5.free(); + if (obj4.dictLookup("K", &obj5)->isBool()) { + knockout = obj5.getBool(); + } + obj5.free(); + if (!haveBackdropColor) { + if (blendingColorSpace) { + blendingColorSpace->getDefaultColor(&backdropColor); + } else { + //~ need to get the parent or default color space (?) + for (i = 0; i < gfxColorMaxComps; ++i) { + backdropColor.c[i] = 0; + } + } + } + doSoftMask(&obj3, alpha, blendingColorSpace, + isolated, knockout, funcs[0], &backdropColor); + if (funcs[0]) { + delete funcs[0]; + } + } else { + error(getPos(), "Invalid soft mask in ExtGState - missing group"); + } + obj4.free(); + } else { + error(getPos(), "Invalid soft mask in ExtGState - missing group"); + } + obj3.free(); + } else if (!obj2.isNull()) { + error(getPos(), "Invalid soft mask in ExtGState"); + } + } + obj2.free(); + + obj1.free(); +} + +void Gfx::doSoftMask(Object *str, GBool alpha, + GfxColorSpace *blendingColorSpace, + GBool isolated, GBool knockout, + Function *transferFunc, GfxColor *backdropColor) { + Dict *dict, *resDict; + double m[6], bbox[4]; + Object obj1, obj2; + int i; + + // check for excessive recursion + if (formDepth > 20) { + return; + } + + // get stream dict + dict = str->streamGetDict(); + + // check form type + dict->lookup("FormType", &obj1); + if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) { + error(getPos(), "Unknown form type"); + } + obj1.free(); + + // get bounding box + dict->lookup("BBox", &obj1); + if (!obj1.isArray()) { + obj1.free(); + error(getPos(), "Bad form bounding box"); + return; + } + for (i = 0; i < 4; ++i) { + obj1.arrayGet(i, &obj2); + bbox[i] = obj2.getNum(); + obj2.free(); + } + obj1.free(); + + // get matrix + dict->lookup("Matrix", &obj1); + if (obj1.isArray()) { + for (i = 0; i < 6; ++i) { + obj1.arrayGet(i, &obj2); + m[i] = obj2.getNum(); + obj2.free(); + } + } else { + m[0] = 1; m[1] = 0; + m[2] = 0; m[3] = 1; + m[4] = 0; m[5] = 0; + } + obj1.free(); + + // get resources + dict->lookup("Resources", &obj1); + resDict = obj1.isDict() ? obj1.getDict() : (Dict *)NULL; + + // draw it + ++formDepth; + doForm1(str, resDict, m, bbox, gTrue, gTrue, + blendingColorSpace, isolated, knockout, + alpha, transferFunc, backdropColor); + --formDepth; + + if (blendingColorSpace) { + delete blendingColorSpace; + } + obj1.free(); +} + +void Gfx::opSetRenderingIntent(Object * /*args[]*/, int /*numArgs*/) { +} + +//------------------------------------------------------------------------ +// color operators +//------------------------------------------------------------------------ + +void Gfx::opSetFillGray(Object args[], int /*numArgs*/) { + GfxColor color; + + state->setFillPattern(NULL); + state->setFillColorSpace(new GfxDeviceGrayColorSpace()); + out->updateFillColorSpace(state); + color.c[0] = dblToCol(args[0].getNum()); + state->setFillColor(&color); + out->updateFillColor(state); +} + +void Gfx::opSetStrokeGray(Object args[], int /*numArgs*/) { + GfxColor color; + + state->setStrokePattern(NULL); + state->setStrokeColorSpace(new GfxDeviceGrayColorSpace()); + out->updateStrokeColorSpace(state); + color.c[0] = dblToCol(args[0].getNum()); + state->setStrokeColor(&color); + out->updateStrokeColor(state); +} + +void Gfx::opSetFillCMYKColor(Object args[], int /*numArgs*/) { + GfxColor color; + int i; + + state->setFillPattern(NULL); + state->setFillColorSpace(new GfxDeviceCMYKColorSpace()); + out->updateFillColorSpace(state); + for (i = 0; i < 4; ++i) { + color.c[i] = dblToCol(args[i].getNum()); + } + state->setFillColor(&color); + out->updateFillColor(state); +} + +void Gfx::opSetStrokeCMYKColor(Object args[], int /*numArgs*/) { + GfxColor color; + int i; + + state->setStrokePattern(NULL); + state->setStrokeColorSpace(new GfxDeviceCMYKColorSpace()); + out->updateStrokeColorSpace(state); + for (i = 0; i < 4; ++i) { + color.c[i] = dblToCol(args[i].getNum()); + } + state->setStrokeColor(&color); + out->updateStrokeColor(state); +} + +void Gfx::opSetFillRGBColor(Object args[], int /*numArgs*/) { + GfxColor color; + int i; + + state->setFillPattern(NULL); + state->setFillColorSpace(new GfxDeviceRGBColorSpace()); + out->updateFillColorSpace(state); + for (i = 0; i < 3; ++i) { + color.c[i] = dblToCol(args[i].getNum()); + } + state->setFillColor(&color); + out->updateFillColor(state); +} + +void Gfx::opSetStrokeRGBColor(Object args[], int /*numArgs*/) { + GfxColor color; + int i; + + state->setStrokePattern(NULL); + state->setStrokeColorSpace(new GfxDeviceRGBColorSpace()); + out->updateStrokeColorSpace(state); + for (i = 0; i < 3; ++i) { + color.c[i] = dblToCol(args[i].getNum()); + } + state->setStrokeColor(&color); + out->updateStrokeColor(state); +} + +void Gfx::opSetFillColorSpace(Object args[], int /*numArgs*/) { + Object obj; + GfxColorSpace *colorSpace; + GfxColor color; + + state->setFillPattern(NULL); + res->lookupColorSpace(args[0].getName(), &obj); + if (obj.isNull()) { + colorSpace = GfxColorSpace::parse(&args[0]); + } else { + colorSpace = GfxColorSpace::parse(&obj); + } + obj.free(); + if (colorSpace) { + state->setFillColorSpace(colorSpace); + out->updateFillColorSpace(state); + colorSpace->getDefaultColor(&color); + state->setFillColor(&color); + out->updateFillColor(state); + } else { + error(getPos(), "Bad color space (fill)"); + } +} + +void Gfx::opSetStrokeColorSpace(Object args[], int /*numArgs*/) { + Object obj; + GfxColorSpace *colorSpace; + GfxColor color; + + state->setStrokePattern(NULL); + res->lookupColorSpace(args[0].getName(), &obj); + if (obj.isNull()) { + colorSpace = GfxColorSpace::parse(&args[0]); + } else { + colorSpace = GfxColorSpace::parse(&obj); + } + obj.free(); + if (colorSpace) { + state->setStrokeColorSpace(colorSpace); + out->updateStrokeColorSpace(state); + colorSpace->getDefaultColor(&color); + state->setStrokeColor(&color); + out->updateStrokeColor(state); + } else { + error(getPos(), "Bad color space (stroke)"); + } +} + +void Gfx::opSetFillColor(Object args[], int numArgs) { + GfxColor color; + int i; + + if (numArgs != state->getFillColorSpace()->getNComps()) { + error(getPos(), "Incorrect number of arguments in 'sc' command"); + return; + } + state->setFillPattern(NULL); + for (i = 0; i < numArgs; ++i) { + color.c[i] = dblToCol(args[i].getNum()); + } + state->setFillColor(&color); + out->updateFillColor(state); +} + +void Gfx::opSetStrokeColor(Object args[], int numArgs) { + GfxColor color; + int i; + + if (numArgs != state->getStrokeColorSpace()->getNComps()) { + error(getPos(), "Incorrect number of arguments in 'SC' command"); + return; + } + state->setStrokePattern(NULL); + for (i = 0; i < numArgs; ++i) { + color.c[i] = dblToCol(args[i].getNum()); + } + state->setStrokeColor(&color); + out->updateStrokeColor(state); +} + +void Gfx::opSetFillColorN(Object args[], int numArgs) { + GfxColor color; + GfxPattern *pattern; + int i; + + if (state->getFillColorSpace()->getMode() == csPattern) { + if (numArgs > 1) { + if (!((GfxPatternColorSpace *)state->getFillColorSpace())->getUnder() || + numArgs - 1 != ((GfxPatternColorSpace *)state->getFillColorSpace()) + ->getUnder()->getNComps()) { + error(getPos(), "Incorrect number of arguments in 'scn' command"); + return; + } + for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) { + if (args[i].isNum()) { + color.c[i] = dblToCol(args[i].getNum()); + } + } + state->setFillColor(&color); + out->updateFillColor(state); + } + if (args[numArgs-1].isName() && + (pattern = res->lookupPattern(args[numArgs-1].getName()))) { + state->setFillPattern(pattern); + } + + } else { + if (numArgs != state->getFillColorSpace()->getNComps()) { + error(getPos(), "Incorrect number of arguments in 'scn' command"); + return; + } + state->setFillPattern(NULL); + for (i = 0; i < numArgs && i < gfxColorMaxComps; ++i) { + if (args[i].isNum()) { + color.c[i] = dblToCol(args[i].getNum()); + } + } + state->setFillColor(&color); + out->updateFillColor(state); + } +} + +void Gfx::opSetStrokeColorN(Object args[], int numArgs) { + GfxColor color; + GfxPattern *pattern; + int i; + + if (state->getStrokeColorSpace()->getMode() == csPattern) { + if (numArgs > 1) { + if (!((GfxPatternColorSpace *)state->getStrokeColorSpace()) + ->getUnder() || + numArgs - 1 != ((GfxPatternColorSpace *)state->getStrokeColorSpace()) + ->getUnder()->getNComps()) { + error(getPos(), "Incorrect number of arguments in 'SCN' command"); + return; + } + for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) { + if (args[i].isNum()) { + color.c[i] = dblToCol(args[i].getNum()); + } + } + state->setStrokeColor(&color); + out->updateStrokeColor(state); + } + if (args[numArgs-1].isName() && + (pattern = res->lookupPattern(args[numArgs-1].getName()))) { + state->setStrokePattern(pattern); + } + + } else { + if (numArgs != state->getStrokeColorSpace()->getNComps()) { + error(getPos(), "Incorrect number of arguments in 'SCN' command"); + return; + } + state->setStrokePattern(NULL); + for (i = 0; i < numArgs && i < gfxColorMaxComps; ++i) { + if (args[i].isNum()) { + color.c[i] = dblToCol(args[i].getNum()); + } + } + state->setStrokeColor(&color); + out->updateStrokeColor(state); + } +} + +//------------------------------------------------------------------------ +// path segment operators +//------------------------------------------------------------------------ + +void Gfx::opMoveTo(Object args[], int /*numArgs*/) { + state->moveTo(args[0].getNum(), args[1].getNum()); +} + +void Gfx::opLineTo(Object args[], int /*numArgs*/) { + if (!state->isCurPt()) { + error(getPos(), "No current point in lineto"); + return; + } + state->lineTo(args[0].getNum(), args[1].getNum()); +} + +void Gfx::opCurveTo(Object args[], int /*numArgs*/) { + double x1, y1, x2, y2, x3, y3; + + if (!state->isCurPt()) { + error(getPos(), "No current point in curveto"); + return; + } + x1 = args[0].getNum(); + y1 = args[1].getNum(); + x2 = args[2].getNum(); + y2 = args[3].getNum(); + x3 = args[4].getNum(); + y3 = args[5].getNum(); + state->curveTo(x1, y1, x2, y2, x3, y3); +} + +void Gfx::opCurveTo1(Object args[], int /*numArgs*/) { + double x1, y1, x2, y2, x3, y3; + + if (!state->isCurPt()) { + error(getPos(), "No current point in curveto1"); + return; + } + x1 = state->getCurX(); + y1 = state->getCurY(); + x2 = args[0].getNum(); + y2 = args[1].getNum(); + x3 = args[2].getNum(); + y3 = args[3].getNum(); + state->curveTo(x1, y1, x2, y2, x3, y3); +} + +void Gfx::opCurveTo2(Object args[], int /*numArgs*/) { + double x1, y1, x2, y2, x3, y3; + + if (!state->isCurPt()) { + error(getPos(), "No current point in curveto2"); + return; + } + x1 = args[0].getNum(); + y1 = args[1].getNum(); + x2 = args[2].getNum(); + y2 = args[3].getNum(); + x3 = x2; + y3 = y2; + state->curveTo(x1, y1, x2, y2, x3, y3); +} + +void Gfx::opRectangle(Object args[], int /*numArgs*/) { + double x, y, w, h; + + x = args[0].getNum(); + y = args[1].getNum(); + w = args[2].getNum(); + h = args[3].getNum(); + state->moveTo(x, y); + state->lineTo(x + w, y); + state->lineTo(x + w, y + h); + state->lineTo(x, y + h); + state->closePath(); +} + +void Gfx::opClosePath(Object * /*args[]*/, int /*numArgs*/) { + if (!state->isCurPt()) { + error(getPos(), "No current point in closepath"); + return; + } + state->closePath(); +} + +//------------------------------------------------------------------------ +// path painting operators +//------------------------------------------------------------------------ + +void Gfx::opEndPath(Object * /*args[]*/, int /*numArgs*/) { + doEndPath(); +} + +void Gfx::opStroke(Object * /*args[]*/, int /*numArgs*/) { + if (!state->isCurPt()) { + //error(getPos(), "No path in stroke"); + return; + } + if (state->isPath()) { + if (state->getStrokeColorSpace()->getMode() == csPattern) { + doPatternStroke(); + } else { + out->stroke(state); + } + } + doEndPath(); +} + +void Gfx::opCloseStroke(Object * /*args[]*/, int /*numArgs*/) { + if (!state->isCurPt()) { + //error(getPos(), "No path in closepath/stroke"); + return; + } + if (state->isPath()) { + state->closePath(); + if (state->getStrokeColorSpace()->getMode() == csPattern) { + doPatternStroke(); + } else { + out->stroke(state); + } + } + doEndPath(); +} + +void Gfx::opFill(Object * /*args[]*/, int /*numArgs*/) { + if (!state->isCurPt()) { + //error(getPos(), "No path in fill"); + return; + } + if (state->isPath()) { + if (state->getFillColorSpace()->getMode() == csPattern) { + doPatternFill(gFalse); + } else { + out->fill(state); + } + } + doEndPath(); +} + +void Gfx::opEOFill(Object * /*args[]*/, int /*numArgs*/) { + if (!state->isCurPt()) { + //error(getPos(), "No path in eofill"); + return; + } + if (state->isPath()) { + if (state->getFillColorSpace()->getMode() == csPattern) { + doPatternFill(gTrue); + } else { + out->eoFill(state); + } + } + doEndPath(); +} + +void Gfx::opFillStroke(Object * /*args[]*/, int /*numArgs*/) { + if (!state->isCurPt()) { + //error(getPos(), "No path in fill/stroke"); + return; + } + if (state->isPath()) { + if (state->getFillColorSpace()->getMode() == csPattern) { + doPatternFill(gFalse); + } else { + out->fill(state); + } + if (state->getStrokeColorSpace()->getMode() == csPattern) { + doPatternStroke(); + } else { + out->stroke(state); + } + } + doEndPath(); +} + +void Gfx::opCloseFillStroke(Object * /*args[]*/, int /*numArgs*/) { + if (!state->isCurPt()) { + //error(getPos(), "No path in closepath/fill/stroke"); + return; + } + if (state->isPath()) { + state->closePath(); + if (state->getFillColorSpace()->getMode() == csPattern) { + doPatternFill(gFalse); + } else { + out->fill(state); + } + if (state->getStrokeColorSpace()->getMode() == csPattern) { + doPatternStroke(); + } else { + out->stroke(state); + } + } + doEndPath(); +} + +void Gfx::opEOFillStroke(Object * /*args[]*/, int /*numArgs*/) { + if (!state->isCurPt()) { + //error(getPos(), "No path in eofill/stroke"); + return; + } + if (state->isPath()) { + if (state->getFillColorSpace()->getMode() == csPattern) { + doPatternFill(gTrue); + } else { + out->eoFill(state); + } + if (state->getStrokeColorSpace()->getMode() == csPattern) { + doPatternStroke(); + } else { + out->stroke(state); + } + } + doEndPath(); +} + +void Gfx::opCloseEOFillStroke(Object * /*args[]*/, int /*numArgs*/) { + if (!state->isCurPt()) { + //error(getPos(), "No path in closepath/eofill/stroke"); + return; + } + if (state->isPath()) { + state->closePath(); + if (state->getFillColorSpace()->getMode() == csPattern) { + doPatternFill(gTrue); + } else { + out->eoFill(state); + } + if (state->getStrokeColorSpace()->getMode() == csPattern) { + doPatternStroke(); + } else { + out->stroke(state); + } + } + doEndPath(); +} + +void Gfx::doPatternFill(GBool eoFill) { + GfxPattern *pattern; + + // this is a bit of a kludge -- patterns can be really slow, so we + // skip them if we're only doing text extraction, since they almost + // certainly don't contain any text + if (!out->needNonText()) { + return; + } + + if (!(pattern = state->getFillPattern())) { + return; + } + switch (pattern->getType()) { + case 1: + doTilingPatternFill((GfxTilingPattern *)pattern, gFalse, eoFill); + break; + case 2: + doShadingPatternFill((GfxShadingPattern *)pattern, gFalse, eoFill); + break; + default: + error(getPos(), "Unimplemented pattern type (%d) in fill", + pattern->getType()); + break; + } +} + +void Gfx::doPatternStroke() { + GfxPattern *pattern; + + // this is a bit of a kludge -- patterns can be really slow, so we + // skip them if we're only doing text extraction, since they almost + // certainly don't contain any text + if (!out->needNonText()) { + return; + } + + if (!(pattern = state->getStrokePattern())) { + return; + } + switch (pattern->getType()) { + case 1: + doTilingPatternFill((GfxTilingPattern *)pattern, gTrue, gFalse); + break; + case 2: + doShadingPatternFill((GfxShadingPattern *)pattern, gTrue, gFalse); + break; + default: + error(getPos(), "Unimplemented pattern type (%d) in stroke", + pattern->getType()); + break; + } +} + +void Gfx::doTilingPatternFill(GfxTilingPattern *tPat, + GBool stroke, GBool eoFill) { + GfxPatternColorSpace *patCS; + GfxColorSpace *cs; + GfxPath *savedPath; + double xMin, yMin, xMax, yMax, x, y, x1, y1; + double cxMin, cyMin, cxMax, cyMax; + int xi0, yi0, xi1, yi1, xi, yi; + double *ctm, *btm, *ptm; + double m[6], ictm[6], m1[6], imb[6]; + double det; + double xstep, ystep; + int i; + + // get color space + patCS = (GfxPatternColorSpace *)(stroke ? state->getStrokeColorSpace() + : state->getFillColorSpace()); + + // construct a (pattern space) -> (current space) transform matrix + ctm = state->getCTM(); + btm = baseMatrix; + ptm = tPat->getMatrix(); + // iCTM = invert CTM + det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]); + ictm[0] = ctm[3] * det; + ictm[1] = -ctm[1] * det; + ictm[2] = -ctm[2] * det; + ictm[3] = ctm[0] * det; + ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det; + ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det; + // m1 = PTM * BTM = PTM * base transform matrix + m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2]; + m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3]; + m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2]; + m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3]; + m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4]; + m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5]; + // m = m1 * iCTM = (PTM * BTM) * (iCTM) + m[0] = m1[0] * ictm[0] + m1[1] * ictm[2]; + m[1] = m1[0] * ictm[1] + m1[1] * ictm[3]; + m[2] = m1[2] * ictm[0] + m1[3] * ictm[2]; + m[3] = m1[2] * ictm[1] + m1[3] * ictm[3]; + m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4]; + m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5]; + + // construct a (device space) -> (pattern space) transform matrix + det = 1 / (m1[0] * m1[3] - m1[1] * m1[2]); + imb[0] = m1[3] * det; + imb[1] = -m1[1] * det; + imb[2] = -m1[2] * det; + imb[3] = m1[0] * det; + imb[4] = (m1[2] * m1[5] - m1[3] * m1[4]) * det; + imb[5] = (m1[1] * m1[4] - m1[0] * m1[5]) * det; + + // save current graphics state + savedPath = state->getPath()->copy(); + saveState(); + + // set underlying color space (for uncolored tiling patterns); set + // various other parameters (stroke color, line width) to match + // Adobe's behavior + if (tPat->getPaintType() == 2 && (cs = patCS->getUnder())) { + state->setFillColorSpace(cs->copy()); + out->updateFillColorSpace(state); + state->setStrokeColorSpace(cs->copy()); + out->updateStrokeColorSpace(state); + state->setStrokeColor(state->getFillColor()); + } else { + state->setFillColorSpace(new GfxDeviceGrayColorSpace()); + out->updateFillColorSpace(state); + state->setStrokeColorSpace(new GfxDeviceGrayColorSpace()); + out->updateStrokeColorSpace(state); + } + state->setFillPattern(NULL); + out->updateFillColor(state); + state->setStrokePattern(NULL); + out->updateStrokeColor(state); + if (!stroke) { + state->setLineWidth(0); + out->updateLineWidth(state); + } + + // clip to current path + if (stroke) { + state->clipToStrokePath(); + out->clipToStrokePath(state); + } else { + state->clip(); + if (eoFill) { + out->eoClip(state); + } else { + out->clip(state); + } + } + state->clearPath(); + + // get the clip region, check for empty + state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax); + if (cxMin > cxMax || cyMin > cyMax) { + goto err; + } + + // transform clip region bbox to pattern space + xMin = xMax = cxMin * imb[0] + cyMin * imb[2] + imb[4]; + yMin = yMax = cxMin * imb[1] + cyMin * imb[3] + imb[5]; + x1 = cxMin * imb[0] + cyMax * imb[2] + imb[4]; + y1 = cxMin * imb[1] + cyMax * imb[3] + imb[5]; + if (x1 < xMin) { + xMin = x1; + } else if (x1 > xMax) { + xMax = x1; + } + if (y1 < yMin) { + yMin = y1; + } else if (y1 > yMax) { + yMax = y1; + } + x1 = cxMax * imb[0] + cyMin * imb[2] + imb[4]; + y1 = cxMax * imb[1] + cyMin * imb[3] + imb[5]; + if (x1 < xMin) { + xMin = x1; + } else if (x1 > xMax) { + xMax = x1; + } + if (y1 < yMin) { + yMin = y1; + } else if (y1 > yMax) { + yMax = y1; + } + x1 = cxMax * imb[0] + cyMax * imb[2] + imb[4]; + y1 = cxMax * imb[1] + cyMax * imb[3] + imb[5]; + if (x1 < xMin) { + xMin = x1; + } else if (x1 > xMax) { + xMax = x1; + } + if (y1 < yMin) { + yMin = y1; + } else if (y1 > yMax) { + yMax = y1; + } + + // draw the pattern + //~ this should treat negative steps differently -- start at right/top + //~ edge instead of left/bottom (?) + xstep = fabs(tPat->getXStep()); + ystep = fabs(tPat->getYStep()); + xi0 = (int)ceil((xMin - tPat->getBBox()[2]) / xstep); + xi1 = (int)floor((xMax - tPat->getBBox()[0]) / xstep) + 1; + yi0 = (int)ceil((yMin - tPat->getBBox()[3]) / ystep); + yi1 = (int)floor((yMax - tPat->getBBox()[1]) / ystep) + 1; + for (i = 0; i < 4; ++i) { + m1[i] = m[i]; + } + if (out->useTilingPatternFill()) { + m1[4] = m[4]; + m1[5] = m[5]; + out->tilingPatternFill(state, tPat->getContentStream(), + tPat->getPaintType(), tPat->getResDict(), + m1, tPat->getBBox(), + xi0, yi0, xi1, yi1, xstep, ystep); + } else { + for (yi = yi0; yi < yi1; ++yi) { + for (xi = xi0; xi < xi1; ++xi) { + x = xi * xstep; + y = yi * ystep; + m1[4] = x * m[0] + y * m[2] + m[4]; + m1[5] = x * m[1] + y * m[3] + m[5]; + doForm1(tPat->getContentStream(), tPat->getResDict(), + m1, tPat->getBBox()); + } + } + } + + // restore graphics state + err: + restoreState(); + state->setPath(savedPath); +} + +void Gfx::doShadingPatternFill(GfxShadingPattern *sPat, + GBool stroke, GBool eoFill) { + GfxShading *shading; + GfxPath *savedPath; + double *ctm, *btm, *ptm; + double m[6], ictm[6], m1[6]; + double xMin, yMin, xMax, yMax; + double det; + + shading = sPat->getShading(); + + // save current graphics state + savedPath = state->getPath()->copy(); + saveState(); + + // clip to bbox + if (shading->getHasBBox()) { + shading->getBBox(&xMin, &yMin, &xMax, &yMax); + state->moveTo(xMin, yMin); + state->lineTo(xMax, yMin); + state->lineTo(xMax, yMax); + state->lineTo(xMin, yMax); + state->closePath(); + state->clip(); + out->clip(state); + state->setPath(savedPath->copy()); + } + + // clip to current path + if (stroke) { + state->clipToStrokePath(); + out->clipToStrokePath(state); + } else { + state->clip(); + if (eoFill) { + out->eoClip(state); + } else { + out->clip(state); + } + } + + // set the color space + state->setFillColorSpace(shading->getColorSpace()->copy()); + out->updateFillColorSpace(state); + + // background color fill + if (shading->getHasBackground()) { + state->setFillColor(shading->getBackground()); + out->updateFillColor(state); + out->fill(state); + } + state->clearPath(); + + // construct a (pattern space) -> (current space) transform matrix + ctm = state->getCTM(); + btm = baseMatrix; + ptm = sPat->getMatrix(); + // iCTM = invert CTM + det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]); + ictm[0] = ctm[3] * det; + ictm[1] = -ctm[1] * det; + ictm[2] = -ctm[2] * det; + ictm[3] = ctm[0] * det; + ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det; + ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det; + // m1 = PTM * BTM = PTM * base transform matrix + m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2]; + m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3]; + m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2]; + m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3]; + m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4]; + m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5]; + // m = m1 * iCTM = (PTM * BTM) * (iCTM) + m[0] = m1[0] * ictm[0] + m1[1] * ictm[2]; + m[1] = m1[0] * ictm[1] + m1[1] * ictm[3]; + m[2] = m1[2] * ictm[0] + m1[3] * ictm[2]; + m[3] = m1[2] * ictm[1] + m1[3] * ictm[3]; + m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4]; + m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5]; + + // set the new matrix + state->concatCTM(m[0], m[1], m[2], m[3], m[4], m[5]); + out->updateCTM(state, m[0], m[1], m[2], m[3], m[4], m[5]); + +#if 1 //~tmp: turn off anti-aliasing temporarily + GBool vaa = out->getVectorAntialias(); + if (vaa) { + out->setVectorAntialias(gFalse); + } +#endif + + // do shading type-specific operations + switch (shading->getType()) { + case 1: + doFunctionShFill((GfxFunctionShading *)shading); + break; + case 2: + doAxialShFill((GfxAxialShading *)shading); + break; + case 3: + doRadialShFill((GfxRadialShading *)shading); + break; + case 4: + case 5: + doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading); + break; + case 6: + case 7: + doPatchMeshShFill((GfxPatchMeshShading *)shading); + break; + } + +#if 1 //~tmp: turn off anti-aliasing temporarily + if (vaa) { + out->setVectorAntialias(gTrue); + } +#endif + + // restore graphics state + restoreState(); + state->setPath(savedPath); +} + +void Gfx::opShFill(Object args[], int /*numArgs*/) { + GfxShading *shading; + GfxPath *savedPath; + double xMin, yMin, xMax, yMax; + + if (!(shading = res->lookupShading(args[0].getName()))) { + return; + } + + // save current graphics state + savedPath = state->getPath()->copy(); + saveState(); + + // clip to bbox + if (shading->getHasBBox()) { + shading->getBBox(&xMin, &yMin, &xMax, &yMax); + state->moveTo(xMin, yMin); + state->lineTo(xMax, yMin); + state->lineTo(xMax, yMax); + state->lineTo(xMin, yMax); + state->closePath(); + state->clip(); + out->clip(state); + state->clearPath(); + } + + // set the color space + state->setFillColorSpace(shading->getColorSpace()->copy()); + out->updateFillColorSpace(state); + +#if 1 //~tmp: turn off anti-aliasing temporarily + GBool vaa = out->getVectorAntialias(); + if (vaa) { + out->setVectorAntialias(gFalse); + } +#endif + + // do shading type-specific operations + switch (shading->getType()) { + case 1: + doFunctionShFill((GfxFunctionShading *)shading); + break; + case 2: + doAxialShFill((GfxAxialShading *)shading); + break; + case 3: + doRadialShFill((GfxRadialShading *)shading); + break; + case 4: + case 5: + doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading); + break; + case 6: + case 7: + doPatchMeshShFill((GfxPatchMeshShading *)shading); + break; + } + +#if 1 //~tmp: turn off anti-aliasing temporarily + if (vaa) { + out->setVectorAntialias(gTrue); + } +#endif + + // restore graphics state + restoreState(); + state->setPath(savedPath); + + delete shading; +} + +void Gfx::doFunctionShFill(GfxFunctionShading *shading) { + double x0, y0, x1, y1; + GfxColor colors[4]; + + if (out->useShadedFills() && + out->functionShadedFill(state, shading)) { + return; + } + + shading->getDomain(&x0, &y0, &x1, &y1); + shading->getColor(x0, y0, &colors[0]); + shading->getColor(x0, y1, &colors[1]); + shading->getColor(x1, y0, &colors[2]); + shading->getColor(x1, y1, &colors[3]); + doFunctionShFill1(shading, x0, y0, x1, y1, colors, 0); +} + +void Gfx::doFunctionShFill1(GfxFunctionShading *shading, + double x0, double y0, + double x1, double y1, + GfxColor *colors, int depth) { + GfxColor fillColor; + GfxColor color0M, color1M, colorM0, colorM1, colorMM; + GfxColor colors2[4]; + double *matrix; + double xM, yM; + int nComps, i, j; + + nComps = shading->getColorSpace()->getNComps(); + matrix = shading->getMatrix(); + + // compare the four corner colors + for (i = 0; i < 4; ++i) { + for (j = 0; j < nComps; ++j) { + if (abs(colors[i].c[j] - colors[(i+1)&3].c[j]) > functionColorDelta) { + break; + } + } + if (j < nComps) { + break; + } + } + + // center of the rectangle + xM = 0.5 * (x0 + x1); + yM = 0.5 * (y0 + y1); + + // the four corner colors are close (or we hit the recursive limit) + // -- fill the rectangle; but require at least one subdivision + // (depth==0) to avoid problems when the four outer corners of the + // shaded region are the same color + if ((i == 4 && depth > 0) || depth == functionMaxDepth) { + + // use the center color + shading->getColor(xM, yM, &fillColor); + state->setFillColor(&fillColor); + out->updateFillColor(state); + + // fill the rectangle + state->moveTo(x0 * matrix[0] + y0 * matrix[2] + matrix[4], + x0 * matrix[1] + y0 * matrix[3] + matrix[5]); + state->lineTo(x1 * matrix[0] + y0 * matrix[2] + matrix[4], + x1 * matrix[1] + y0 * matrix[3] + matrix[5]); + state->lineTo(x1 * matrix[0] + y1 * matrix[2] + matrix[4], + x1 * matrix[1] + y1 * matrix[3] + matrix[5]); + state->lineTo(x0 * matrix[0] + y1 * matrix[2] + matrix[4], + x0 * matrix[1] + y1 * matrix[3] + matrix[5]); + state->closePath(); + out->fill(state); + state->clearPath(); + + // the four corner colors are not close enough -- subdivide the + // rectangle + } else { + + // colors[0] colorM0 colors[2] + // (x0,y0) (xM,y0) (x1,y0) + // +----------+----------+ + // | | | + // | UL | UR | + // color0M | colorMM | color1M + // (x0,yM) +----------+----------+ (x1,yM) + // | (xM,yM) | + // | LL | LR | + // | | | + // +----------+----------+ + // colors[1] colorM1 colors[3] + // (x0,y1) (xM,y1) (x1,y1) + + shading->getColor(x0, yM, &color0M); + shading->getColor(x1, yM, &color1M); + shading->getColor(xM, y0, &colorM0); + shading->getColor(xM, y1, &colorM1); + shading->getColor(xM, yM, &colorMM); + + // upper-left sub-rectangle + colors2[0] = colors[0]; + colors2[1] = color0M; + colors2[2] = colorM0; + colors2[3] = colorMM; + doFunctionShFill1(shading, x0, y0, xM, yM, colors2, depth + 1); + + // lower-left sub-rectangle + colors2[0] = color0M; + colors2[1] = colors[1]; + colors2[2] = colorMM; + colors2[3] = colorM1; + doFunctionShFill1(shading, x0, yM, xM, y1, colors2, depth + 1); + + // upper-right sub-rectangle + colors2[0] = colorM0; + colors2[1] = colorMM; + colors2[2] = colors[2]; + colors2[3] = color1M; + doFunctionShFill1(shading, xM, y0, x1, yM, colors2, depth + 1); + + // lower-right sub-rectangle + colors2[0] = colorMM; + colors2[1] = colorM1; + colors2[2] = color1M; + colors2[3] = colors[3]; + doFunctionShFill1(shading, xM, yM, x1, y1, colors2, depth + 1); + } +} + +void Gfx::doAxialShFill(GfxAxialShading *shading) { + double xMin, yMin, xMax, yMax; + double x0, y0, x1, y1; + double dx, dy, mul; + GBool dxZero, dyZero; + double tMin, tMax, t, tx, ty; + double s[4], sMin, sMax, tmp; + double ux0, uy0, ux1, uy1, vx0, vy0, vx1, vy1; + double t0, t1, tt; + double ta[axialMaxSplits + 1]; + int next[axialMaxSplits + 1]; + GfxColor color0, color1; + int nComps; + int i, j, k, kk; + + if (out->useShadedFills() && + out->axialShadedFill(state, shading)) { + return; + } + + // get the clip region bbox + state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); + + // compute min and max t values, based on the four corners of the + // clip region bbox + shading->getCoords(&x0, &y0, &x1, &y1); + dx = x1 - x0; + dy = y1 - y0; + dxZero = fabs(dx) < 0.01; + dyZero = fabs(dy) < 0.01; + if (dxZero && dyZero) { + tMin = tMax = 0; + } else { + mul = 1 / (dx * dx + dy * dy); + tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul; + t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul; + if (t < tMin) { + tMin = t; + } else if (t > tMax) { + tMax = t; + } + t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul; + if (t < tMin) { + tMin = t; + } else if (t > tMax) { + tMax = t; + } + t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul; + if (t < tMin) { + tMin = t; + } else if (t > tMax) { + tMax = t; + } + if (tMin < 0 && !shading->getExtend0()) { + tMin = 0; + } + if (tMax > 1 && !shading->getExtend1()) { + tMax = 1; + } + } + + // get the function domain + t0 = shading->getDomain0(); + t1 = shading->getDomain1(); + + // Traverse the t axis and do the shading. + // + // For each point (tx, ty) on the t axis, consider a line through + // that point perpendicular to the t axis: + // + // x(s) = tx + s * -dy --> s = (x - tx) / -dy + // y(s) = ty + s * dx --> s = (y - ty) / dx + // + // Then look at the intersection of this line with the bounding box + // (xMin, yMin, xMax, yMax). In the general case, there are four + // intersection points: + // + // s0 = (xMin - tx) / -dy + // s1 = (xMax - tx) / -dy + // s2 = (yMin - ty) / dx + // s3 = (yMax - ty) / dx + // + // and we want the middle two s values. + // + // In the case where dx = 0, take s0 and s1; in the case where dy = + // 0, take s2 and s3. + // + // Each filled polygon is bounded by two of these line segments + // perpdendicular to the t axis. + // + // The t axis is bisected into smaller regions until the color + // difference across a region is small enough, and then the region + // is painted with a single color. + + // set up: require at least one split to avoid problems when the two + // ends of the t axis have the same color + nComps = shading->getColorSpace()->getNComps(); + ta[0] = tMin; + next[0] = axialMaxSplits / 2; + ta[axialMaxSplits / 2] = 0.5 * (tMin + tMax); + next[axialMaxSplits / 2] = axialMaxSplits; + ta[axialMaxSplits] = tMax; + + // compute the color at t = tMin + if (tMin < 0) { + tt = t0; + } else if (tMin > 1) { + tt = t1; + } else { + tt = t0 + (t1 - t0) * tMin; + } + shading->getColor(tt, &color0); + + // compute the coordinates of the point on the t axis at t = tMin; + // then compute the intersection of the perpendicular line with the + // bounding box + tx = x0 + tMin * dx; + ty = y0 + tMin * dy; + if (dxZero && dyZero) { + sMin = sMax = 0; + } else if (dxZero) { + sMin = (xMin - tx) / -dy; + sMax = (xMax - tx) / -dy; + if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } + } else if (dyZero) { + sMin = (yMin - ty) / dx; + sMax = (yMax - ty) / dx; + if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } + } else { + s[0] = (yMin - ty) / dx; + s[1] = (yMax - ty) / dx; + s[2] = (xMin - tx) / -dy; + s[3] = (xMax - tx) / -dy; + for (j = 0; j < 3; ++j) { + kk = j; + for (k = j + 1; k < 4; ++k) { + if (s[k] < s[kk]) { + kk = k; + } + } + tmp = s[j]; s[j] = s[kk]; s[kk] = tmp; + } + sMin = s[1]; + sMax = s[2]; + } + ux0 = tx - sMin * dy; + uy0 = ty + sMin * dx; + vx0 = tx - sMax * dy; + vy0 = ty + sMax * dx; + + i = 0; + while (i < axialMaxSplits) { + + // bisect until color difference is small enough or we hit the + // bisection limit + j = next[i]; + while (j > i + 1) { + if (ta[j] < 0) { + tt = t0; + } else if (ta[j] > 1) { + tt = t1; + } else { + tt = t0 + (t1 - t0) * ta[j]; + } + shading->getColor(tt, &color1); + for (k = 0; k < nComps; ++k) { + if (abs(color1.c[k] - color0.c[k]) > axialColorDelta) { + break; + } + } + if (k == nComps) { + break; + } + k = (i + j) / 2; + ta[k] = 0.5 * (ta[i] + ta[j]); + next[i] = k; + next[k] = j; + j = k; + } + + // use the average of the colors of the two sides of the region + for (k = 0; k < nComps; ++k) { + color0.c[k] = (color0.c[k] + color1.c[k]) / 2; + } + + // compute the coordinates of the point on the t axis; then + // compute the intersection of the perpendicular line with the + // bounding box + tx = x0 + ta[j] * dx; + ty = y0 + ta[j] * dy; + if (dxZero && dyZero) { + sMin = sMax = 0; + } else if (dxZero) { + sMin = (xMin - tx) / -dy; + sMax = (xMax - tx) / -dy; + if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } + } else if (dyZero) { + sMin = (yMin - ty) / dx; + sMax = (yMax - ty) / dx; + if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } + } else { + s[0] = (yMin - ty) / dx; + s[1] = (yMax - ty) / dx; + s[2] = (xMin - tx) / -dy; + s[3] = (xMax - tx) / -dy; + for (j = 0; j < 3; ++j) { + kk = j; + for (k = j + 1; k < 4; ++k) { + if (s[k] < s[kk]) { + kk = k; + } + } + tmp = s[j]; s[j] = s[kk]; s[kk] = tmp; + } + sMin = s[1]; + sMax = s[2]; + } + ux1 = tx - sMin * dy; + uy1 = ty + sMin * dx; + vx1 = tx - sMax * dy; + vy1 = ty + sMax * dx; + + // set the color + state->setFillColor(&color0); + out->updateFillColor(state); + + // fill the region + state->moveTo(ux0, uy0); + state->lineTo(vx0, vy0); + state->lineTo(vx1, vy1); + state->lineTo(ux1, uy1); + state->closePath(); + out->fill(state); + state->clearPath(); + + // set up for next region + ux0 = ux1; + uy0 = uy1; + vx0 = vx1; + vy0 = vy1; + color0 = color1; + i = next[i]; + } +} + +void Gfx::doRadialShFill(GfxRadialShading *shading) { + double xMin, yMin, xMax, yMax; + double x0, y0, r0, x1, y1, r1, t0, t1; + int nComps; + GfxColor colorA, colorB; + double xa, ya, xb, yb, ra, rb; + double ta, tb, sa, sb; + double sz, xz, yz, sMin, sMax; + GBool enclosed; + int ia, ib, k, n; + double *ctm; + double theta, alpha, angle, t; + + if (out->useShadedFills() && + out->radialShadedFill(state, shading)) { + return; + } + + // get the shading info + shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1); + t0 = shading->getDomain0(); + t1 = shading->getDomain1(); + nComps = shading->getColorSpace()->getNComps(); + + // Compute the point at which r(s) = 0; check for the enclosed + // circles case; and compute the angles for the tangent lines. + if (x0 == x1 && y0 == y1) { + enclosed = gTrue; + theta = 0; // make gcc happy + sz = 0; // make gcc happy + } else if (r0 == r1) { + enclosed = gFalse; + theta = 0; + sz = 0; // make gcc happy + } else { + sz = -r0 / (r1 - r0); + xz = x0 + sz * (x1 - x0); + yz = y0 + sz * (y1 - y0); + enclosed = (xz - x0) * (xz - x0) + (yz - y0) * (yz - y0) <= r0 * r0; + theta = asin(r0 / sqrt((x0 - xz) * (x0 - xz) + (y0 - yz) * (y0 - yz))); + if (r0 > r1) { + theta = -theta; + } + } + if (enclosed) { + alpha = 0; + } else { + alpha = atan2(y1 - y0, x1 - x0); + } + + // compute the (possibly extended) s range + state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); + if (enclosed) { + sMin = 0; + sMax = 1; + } else { + sMin = 1; + sMax = 0; + // solve for x(s) + r(s) = xMin + if ((x1 + r1) - (x0 + r0) != 0) { + sa = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0)); + if (sa < sMin) { + sMin = sa; + } else if (sa > sMax) { + sMax = sa; + } + } + // solve for x(s) - r(s) = xMax + if ((x1 - r1) - (x0 - r0) != 0) { + sa = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0)); + if (sa < sMin) { + sMin = sa; + } else if (sa > sMax) { + sMax = sa; + } + } + // solve for y(s) + r(s) = yMin + if ((y1 + r1) - (y0 + r0) != 0) { + sa = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0)); + if (sa < sMin) { + sMin = sa; + } else if (sa > sMax) { + sMax = sa; + } + } + // solve for y(s) - r(s) = yMax + if ((y1 - r1) - (y0 - r0) != 0) { + sa = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0)); + if (sa < sMin) { + sMin = sa; + } else if (sa > sMax) { + sMax = sa; + } + } + // check against sz + if (r0 < r1) { + if (sMin < sz) { + sMin = sz; + } + } else if (r0 > r1) { + if (sMax > sz) { + sMax = sz; + } + } + // check the 'extend' flags + if (!shading->getExtend0() && sMin < 0) { + sMin = 0; + } + if (!shading->getExtend1() && sMax > 1) { + sMax = 1; + } + } + + // compute the number of steps into which circles must be divided to + // achieve a curve flatness of 0.1 pixel in device space for the + // largest circle (note that "device space" is 72 dpi when generating + // PostScript, hence the relatively small 0.1 pixel accuracy) + ctm = state->getCTM(); + t = fabs(ctm[0]); + if (fabs(ctm[1]) > t) { + t = fabs(ctm[1]); + } + if (fabs(ctm[2]) > t) { + t = fabs(ctm[2]); + } + if (fabs(ctm[3]) > t) { + t = fabs(ctm[3]); + } + if (r0 > r1) { + t *= r0; + } else { + t *= r1; + } + if (t < 1) { + n = 3; + } else { + n = (int)(M_PI / acos(1 - 0.1 / t)); + if (n < 3) { + n = 3; + } else if (n > 200) { + n = 200; + } + } + + // setup for the start circle + ia = 0; + sa = sMin; + ta = t0 + sa * (t1 - t0); + xa = x0 + sa * (x1 - x0); + ya = y0 + sa * (y1 - y0); + ra = r0 + sa * (r1 - r0); + if (ta < t0) { + shading->getColor(t0, &colorA); + } else if (ta > t1) { + shading->getColor(t1, &colorA); + } else { + shading->getColor(ta, &colorA); + } + + // fill the circles + while (ia < radialMaxSplits) { + + // go as far along the t axis (toward t1) as we can, such that the + // color difference is within the tolerance (radialColorDelta) -- + // this uses bisection (between the current value, t, and t1), + // limited to radialMaxSplits points along the t axis; require at + // least one split to avoid problems when the innermost and + // outermost colors are the same + ib = radialMaxSplits; + sb = sMax; + tb = t0 + sb * (t1 - t0); + if (tb < t0) { + shading->getColor(t0, &colorB); + } else if (tb > t1) { + shading->getColor(t1, &colorB); + } else { + shading->getColor(tb, &colorB); + } + while (ib - ia > 1) { + for (k = 0; k < nComps; ++k) { + if (abs(colorB.c[k] - colorA.c[k]) > radialColorDelta) { + break; + } + } + if (k == nComps && ib < radialMaxSplits) { + break; + } + ib = (ia + ib) / 2; + sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin); + tb = t0 + sb * (t1 - t0); + if (tb < t0) { + shading->getColor(t0, &colorB); + } else if (tb > t1) { + shading->getColor(t1, &colorB); + } else { + shading->getColor(tb, &colorB); + } + } + + // compute center and radius of the circle + xb = x0 + sb * (x1 - x0); + yb = y0 + sb * (y1 - y0); + rb = r0 + sb * (r1 - r0); + + // use the average of the colors at the two circles + for (k = 0; k < nComps; ++k) { + colorA.c[k] = (colorA.c[k] + colorB.c[k]) / 2; + } + state->setFillColor(&colorA); + out->updateFillColor(state); + + if (enclosed) { + + // construct path for first circle (counterclockwise) + state->moveTo(xa + ra, ya); + for (k = 1; k < n; ++k) { + angle = ((double)k / (double)n) * 2 * M_PI; + state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); + } + state->closePath(); + + // construct and append path for second circle (clockwise) + state->moveTo(xb + rb, yb); + for (k = 1; k < n; ++k) { + angle = -((double)k / (double)n) * 2 * M_PI; + state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle)); + } + state->closePath(); + + } else { + + // construct the first subpath (clockwise) + state->moveTo(xa + ra * cos(alpha + theta + 0.5 * M_PI), + ya + ra * sin(alpha + theta + 0.5 * M_PI)); + for (k = 0; k < n; ++k) { + angle = alpha + theta + 0.5 * M_PI + - ((double)k / (double)n) * (2 * theta + M_PI); + state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle)); + } + for (k = 0; k < n; ++k) { + angle = alpha - theta - 0.5 * M_PI + + ((double)k / (double)n) * (2 * theta - M_PI); + state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); + } + state->closePath(); + + // construct the second subpath (counterclockwise) + state->moveTo(xa + ra * cos(alpha + theta + 0.5 * M_PI), + ya + ra * sin(alpha + theta + 0.5 * M_PI)); + for (k = 0; k < n; ++k) { + angle = alpha + theta + 0.5 * M_PI + + ((double)k / (double)n) * (-2 * theta + M_PI); + state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle)); + } + for (k = 0; k < n; ++k) { + angle = alpha - theta - 0.5 * M_PI + + ((double)k / (double)n) * (2 * theta + M_PI); + state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); + } + state->closePath(); + } + + // fill the path + out->fill(state); + state->clearPath(); + + // step to the next value of t + ia = ib; + sa = sb; + ta = tb; + xa = xb; + ya = yb; + ra = rb; + colorA = colorB; + } + + if (enclosed) { + // extend the smaller circle + if ((shading->getExtend0() && r0 <= r1) || + (shading->getExtend1() && r1 < r0)) { + if (r0 <= r1) { + ta = t0; + ra = r0; + xa = x0; + ya = y0; + } else { + ta = t1; + ra = r1; + xa = x1; + ya = y1; + } + shading->getColor(ta, &colorA); + state->setFillColor(&colorA); + out->updateFillColor(state); + state->moveTo(xa + ra, ya); + for (k = 1; k < n; ++k) { + angle = ((double)k / (double)n) * 2 * M_PI; + state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); + } + state->closePath(); + out->fill(state); + state->clearPath(); + } + + // extend the larger circle + if ((shading->getExtend0() && r0 > r1) || + (shading->getExtend1() && r1 >= r0)) { + if (r0 > r1) { + ta = t0; + ra = r0; + xa = x0; + ya = y0; + } else { + ta = t1; + ra = r1; + xa = x1; + ya = y1; + } + shading->getColor(ta, &colorA); + state->setFillColor(&colorA); + out->updateFillColor(state); + state->moveTo(xMin, yMin); + state->lineTo(xMin, yMax); + state->lineTo(xMax, yMax); + state->lineTo(xMax, yMin); + state->closePath(); + state->moveTo(xa + ra, ya); + for (k = 1; k < n; ++k) { + angle = ((double)k / (double)n) * 2 * M_PI; + state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); + } + state->closePath(); + out->fill(state); + state->clearPath(); + } + } +} + +void Gfx::doGouraudTriangleShFill(GfxGouraudTriangleShading *shading) { + double x0, y0, x1, y1, x2, y2; + GfxColor color0, color1, color2; + int i; + + for (i = 0; i < shading->getNTriangles(); ++i) { + shading->getTriangle(i, &x0, &y0, &color0, + &x1, &y1, &color1, + &x2, &y2, &color2); + gouraudFillTriangle(x0, y0, &color0, x1, y1, &color1, x2, y2, &color2, + shading->getColorSpace()->getNComps(), 0); + } +} + +void Gfx::gouraudFillTriangle(double x0, double y0, GfxColor *color0, + double x1, double y1, GfxColor *color1, + double x2, double y2, GfxColor *color2, + int nComps, int depth) { + double x01, y01, x12, y12, x20, y20; + GfxColor color01, color12, color20; + int i; + + for (i = 0; i < nComps; ++i) { + if (abs(color0->c[i] - color1->c[i]) > gouraudColorDelta || + abs(color1->c[i] - color2->c[i]) > gouraudColorDelta) { + break; + } + } + if (i == nComps || depth == gouraudMaxDepth) { + state->setFillColor(color0); + out->updateFillColor(state); + state->moveTo(x0, y0); + state->lineTo(x1, y1); + state->lineTo(x2, y2); + state->closePath(); + out->fill(state); + state->clearPath(); + } else { + x01 = 0.5 * (x0 + x1); + y01 = 0.5 * (y0 + y1); + x12 = 0.5 * (x1 + x2); + y12 = 0.5 * (y1 + y2); + x20 = 0.5 * (x2 + x0); + y20 = 0.5 * (y2 + y0); + //~ if the shading has a Function, this should interpolate on the + //~ function parameter, not on the color components + for (i = 0; i < nComps; ++i) { + color01.c[i] = (color0->c[i] + color1->c[i]) / 2; + color12.c[i] = (color1->c[i] + color2->c[i]) / 2; + color20.c[i] = (color2->c[i] + color0->c[i]) / 2; + } + gouraudFillTriangle(x0, y0, color0, x01, y01, &color01, + x20, y20, &color20, nComps, depth + 1); + gouraudFillTriangle(x01, y01, &color01, x1, y1, color1, + x12, y12, &color12, nComps, depth + 1); + gouraudFillTriangle(x01, y01, &color01, x12, y12, &color12, + x20, y20, &color20, nComps, depth + 1); + gouraudFillTriangle(x20, y20, &color20, x12, y12, &color12, + x2, y2, color2, nComps, depth + 1); + } +} + +void Gfx::doPatchMeshShFill(GfxPatchMeshShading *shading) { + int start, i; + + if (shading->getNPatches() > 128) { + start = 3; + } else if (shading->getNPatches() > 64) { + start = 2; + } else if (shading->getNPatches() > 16) { + start = 1; + } else { + start = 0; + } + for (i = 0; i < shading->getNPatches(); ++i) { + fillPatch(shading->getPatch(i), shading->getColorSpace()->getNComps(), + start); + } +} + +void Gfx::fillPatch(GfxPatch *patch, int nComps, int depth) { + GfxPatch patch00, patch01, patch10, patch11; + double xx[4][8], yy[4][8]; + double xxm, yym; + int i; + + for (i = 0; i < nComps; ++i) { + if (abs(patch->color[0][0].c[i] - patch->color[0][1].c[i]) + > patchColorDelta || + abs(patch->color[0][1].c[i] - patch->color[1][1].c[i]) + > patchColorDelta || + abs(patch->color[1][1].c[i] - patch->color[1][0].c[i]) + > patchColorDelta || + abs(patch->color[1][0].c[i] - patch->color[0][0].c[i]) + > patchColorDelta) { + break; + } + } + if (i == nComps || depth == patchMaxDepth) { + state->setFillColor(&patch->color[0][0]); + out->updateFillColor(state); + state->moveTo(patch->x[0][0], patch->y[0][0]); + state->curveTo(patch->x[0][1], patch->y[0][1], + patch->x[0][2], patch->y[0][2], + patch->x[0][3], patch->y[0][3]); + state->curveTo(patch->x[1][3], patch->y[1][3], + patch->x[2][3], patch->y[2][3], + patch->x[3][3], patch->y[3][3]); + state->curveTo(patch->x[3][2], patch->y[3][2], + patch->x[3][1], patch->y[3][1], + patch->x[3][0], patch->y[3][0]); + state->curveTo(patch->x[2][0], patch->y[2][0], + patch->x[1][0], patch->y[1][0], + patch->x[0][0], patch->y[0][0]); + state->closePath(); + out->fill(state); + state->clearPath(); + } else { + for (i = 0; i < 4; ++i) { + xx[i][0] = patch->x[i][0]; + yy[i][0] = patch->y[i][0]; + xx[i][1] = 0.5 * (patch->x[i][0] + patch->x[i][1]); + yy[i][1] = 0.5 * (patch->y[i][0] + patch->y[i][1]); + xxm = 0.5 * (patch->x[i][1] + patch->x[i][2]); + yym = 0.5 * (patch->y[i][1] + patch->y[i][2]); + xx[i][6] = 0.5 * (patch->x[i][2] + patch->x[i][3]); + yy[i][6] = 0.5 * (patch->y[i][2] + patch->y[i][3]); + xx[i][2] = 0.5 * (xx[i][1] + xxm); + yy[i][2] = 0.5 * (yy[i][1] + yym); + xx[i][5] = 0.5 * (xxm + xx[i][6]); + yy[i][5] = 0.5 * (yym + yy[i][6]); + xx[i][3] = xx[i][4] = 0.5 * (xx[i][2] + xx[i][5]); + yy[i][3] = yy[i][4] = 0.5 * (yy[i][2] + yy[i][5]); + xx[i][7] = patch->x[i][3]; + yy[i][7] = patch->y[i][3]; + } + for (i = 0; i < 4; ++i) { + patch00.x[0][i] = xx[0][i]; + patch00.y[0][i] = yy[0][i]; + patch00.x[1][i] = 0.5 * (xx[0][i] + xx[1][i]); + patch00.y[1][i] = 0.5 * (yy[0][i] + yy[1][i]); + xxm = 0.5 * (xx[1][i] + xx[2][i]); + yym = 0.5 * (yy[1][i] + yy[2][i]); + patch10.x[2][i] = 0.5 * (xx[2][i] + xx[3][i]); + patch10.y[2][i] = 0.5 * (yy[2][i] + yy[3][i]); + patch00.x[2][i] = 0.5 * (patch00.x[1][i] + xxm); + patch00.y[2][i] = 0.5 * (patch00.y[1][i] + yym); + patch10.x[1][i] = 0.5 * (xxm + patch10.x[2][i]); + patch10.y[1][i] = 0.5 * (yym + patch10.y[2][i]); + patch00.x[3][i] = 0.5 * (patch00.x[2][i] + patch10.x[1][i]); + patch00.y[3][i] = 0.5 * (patch00.y[2][i] + patch10.y[1][i]); + patch10.x[0][i] = patch00.x[3][i]; + patch10.y[0][i] = patch00.y[3][i]; + patch10.x[3][i] = xx[3][i]; + patch10.y[3][i] = yy[3][i]; + } + for (i = 4; i < 8; ++i) { + patch01.x[0][i-4] = xx[0][i]; + patch01.y[0][i-4] = yy[0][i]; + patch01.x[1][i-4] = 0.5 * (xx[0][i] + xx[1][i]); + patch01.y[1][i-4] = 0.5 * (yy[0][i] + yy[1][i]); + xxm = 0.5 * (xx[1][i] + xx[2][i]); + yym = 0.5 * (yy[1][i] + yy[2][i]); + patch11.x[2][i-4] = 0.5 * (xx[2][i] + xx[3][i]); + patch11.y[2][i-4] = 0.5 * (yy[2][i] + yy[3][i]); + patch01.x[2][i-4] = 0.5 * (patch01.x[1][i-4] + xxm); + patch01.y[2][i-4] = 0.5 * (patch01.y[1][i-4] + yym); + patch11.x[1][i-4] = 0.5 * (xxm + patch11.x[2][i-4]); + patch11.y[1][i-4] = 0.5 * (yym + patch11.y[2][i-4]); + patch01.x[3][i-4] = 0.5 * (patch01.x[2][i-4] + patch11.x[1][i-4]); + patch01.y[3][i-4] = 0.5 * (patch01.y[2][i-4] + patch11.y[1][i-4]); + patch11.x[0][i-4] = patch01.x[3][i-4]; + patch11.y[0][i-4] = patch01.y[3][i-4]; + patch11.x[3][i-4] = xx[3][i]; + patch11.y[3][i-4] = yy[3][i]; + } + //~ if the shading has a Function, this should interpolate on the + //~ function parameter, not on the color components + for (i = 0; i < nComps; ++i) { + patch00.color[0][0].c[i] = patch->color[0][0].c[i]; + patch00.color[0][1].c[i] = (patch->color[0][0].c[i] + + patch->color[0][1].c[i]) / 2; + patch01.color[0][0].c[i] = patch00.color[0][1].c[i]; + patch01.color[0][1].c[i] = patch->color[0][1].c[i]; + patch01.color[1][1].c[i] = (patch->color[0][1].c[i] + + patch->color[1][1].c[i]) / 2; + patch11.color[0][1].c[i] = patch01.color[1][1].c[i]; + patch11.color[1][1].c[i] = patch->color[1][1].c[i]; + patch11.color[1][0].c[i] = (patch->color[1][1].c[i] + + patch->color[1][0].c[i]) / 2; + patch10.color[1][1].c[i] = patch11.color[1][0].c[i]; + patch10.color[1][0].c[i] = patch->color[1][0].c[i]; + patch10.color[0][0].c[i] = (patch->color[1][0].c[i] + + patch->color[0][0].c[i]) / 2; + patch00.color[1][0].c[i] = patch10.color[0][0].c[i]; + patch00.color[1][1].c[i] = (patch00.color[1][0].c[i] + + patch01.color[1][1].c[i]) / 2; + patch01.color[1][0].c[i] = patch00.color[1][1].c[i]; + patch11.color[0][0].c[i] = patch00.color[1][1].c[i]; + patch10.color[0][1].c[i] = patch00.color[1][1].c[i]; + } + fillPatch(&patch00, nComps, depth + 1); + fillPatch(&patch10, nComps, depth + 1); + fillPatch(&patch01, nComps, depth + 1); + fillPatch(&patch11, nComps, depth + 1); + } +} + +void Gfx::doEndPath() { + if (state->isCurPt() && clip != clipNone) { + state->clip(); + if (clip == clipNormal) { + out->clip(state); + } else { + out->eoClip(state); + } + } + clip = clipNone; + state->clearPath(); +} + +//------------------------------------------------------------------------ +// path clipping operators +//------------------------------------------------------------------------ + +void Gfx::opClip(Object * /*args[]*/, int /*numArgs*/) { + clip = clipNormal; +} + +void Gfx::opEOClip(Object * /*args[]*/, int /*numArgs*/) { + clip = clipEO; +} + +//------------------------------------------------------------------------ +// text object operators +//------------------------------------------------------------------------ + +void Gfx::opBeginText(Object * /*args[]*/, int /*numArgs*/) { + state->setTextMat(1, 0, 0, 1, 0, 0); + state->textMoveTo(0, 0); + out->updateTextMat(state); + out->updateTextPos(state); + fontChanged = gTrue; +} + +void Gfx::opEndText(Object * /*args[]*/, int /*numArgs*/) { + out->endTextObject(state); +} + +//------------------------------------------------------------------------ +// text state operators +//------------------------------------------------------------------------ + +void Gfx::opSetCharSpacing(Object args[], int /*numArgs*/) { + state->setCharSpace(args[0].getNum()); + out->updateCharSpace(state); +} + +void Gfx::opSetFont(Object args[], int /*numArgs*/) { + GfxFont *font; + + if (!(font = res->lookupFont(args[0].getName()))) { + return; + } + if (printCommands) { + printf(" font: tag=%s name='%s' %g\n", + font->getTag()->getCString(), + font->getName() ? font->getName()->getCString() : "???", + args[1].getNum()); + fflush(stdout); + } + state->setFont(font, args[1].getNum()); + fontChanged = gTrue; +} + +void Gfx::opSetTextLeading(Object args[], int /*numArgs*/) { + state->setLeading(args[0].getNum()); +} + +void Gfx::opSetTextRender(Object args[], int /*numArgs*/) { + state->setRender(args[0].getInt()); + out->updateRender(state); +} + +void Gfx::opSetTextRise(Object args[], int /*numArgs*/) { + state->setRise(args[0].getNum()); + out->updateRise(state); +} + +void Gfx::opSetWordSpacing(Object args[], int /*numArgs*/) { + state->setWordSpace(args[0].getNum()); + out->updateWordSpace(state); +} + +void Gfx::opSetHorizScaling(Object args[], int /*numArgs*/) { + state->setHorizScaling(args[0].getNum()); + out->updateHorizScaling(state); + fontChanged = gTrue; +} + +//------------------------------------------------------------------------ +// text positioning operators +//------------------------------------------------------------------------ + +void Gfx::opTextMove(Object args[], int /*numArgs*/) { + double tx, ty; + + tx = state->getLineX() + args[0].getNum(); + ty = state->getLineY() + args[1].getNum(); + state->textMoveTo(tx, ty); + out->updateTextPos(state); +} + +void Gfx::opTextMoveSet(Object args[], int /*numArgs*/) { + double tx, ty; + + tx = state->getLineX() + args[0].getNum(); + ty = args[1].getNum(); + state->setLeading(-ty); + ty += state->getLineY(); + state->textMoveTo(tx, ty); + out->updateTextPos(state); +} + +void Gfx::opSetTextMatrix(Object args[], int /*numArgs*/) { + state->setTextMat(args[0].getNum(), args[1].getNum(), + args[2].getNum(), args[3].getNum(), + args[4].getNum(), args[5].getNum()); + state->textMoveTo(0, 0); + out->updateTextMat(state); + out->updateTextPos(state); + fontChanged = gTrue; +} + +void Gfx::opTextNextLine(Object * /*args[]*/, int /*numArgs*/) { + double tx, ty; + + tx = state->getLineX(); + ty = state->getLineY() - state->getLeading(); + state->textMoveTo(tx, ty); + out->updateTextPos(state); +} + +//------------------------------------------------------------------------ +// text string operators +//------------------------------------------------------------------------ + +void Gfx::opShowText(Object args[], int /*numArgs*/) { + if (!state->getFont()) { + error(getPos(), "No font in show"); + return; + } + if (fontChanged) { + out->updateFont(state); + fontChanged = gFalse; + } + out->beginStringOp(state); + doShowText(args[0].getString()); + out->endStringOp(state); +} + +void Gfx::opMoveShowText(Object args[], int /*numArgs*/) { + double tx, ty; + + if (!state->getFont()) { + error(getPos(), "No font in move/show"); + return; + } + if (fontChanged) { + out->updateFont(state); + fontChanged = gFalse; + } + tx = state->getLineX(); + ty = state->getLineY() - state->getLeading(); + state->textMoveTo(tx, ty); + out->updateTextPos(state); + out->beginStringOp(state); + doShowText(args[0].getString()); + out->endStringOp(state); +} + +void Gfx::opMoveSetShowText(Object args[], int /*numArgs*/) { + double tx, ty; + + if (!state->getFont()) { + error(getPos(), "No font in move/set/show"); + return; + } + if (fontChanged) { + out->updateFont(state); + fontChanged = gFalse; + } + state->setWordSpace(args[0].getNum()); + state->setCharSpace(args[1].getNum()); + tx = state->getLineX(); + ty = state->getLineY() - state->getLeading(); + state->textMoveTo(tx, ty); + out->updateWordSpace(state); + out->updateCharSpace(state); + out->updateTextPos(state); + out->beginStringOp(state); + doShowText(args[2].getString()); + out->endStringOp(state); +} + +void Gfx::opShowSpaceText(Object args[], int /*numArgs*/) { + Array *a; + Object obj; + int wMode; + int i; + + if (!state->getFont()) { + error(getPos(), "No font in show/space"); + return; + } + if (fontChanged) { + out->updateFont(state); + fontChanged = gFalse; + } + out->beginStringOp(state); + wMode = state->getFont()->getWMode(); + a = args[0].getArray(); + for (i = 0; i < a->getLength(); ++i) { + a->get(i, &obj); + if (obj.isNum()) { + // this uses the absolute value of the font size to match + // Acrobat's behavior + if (wMode) { + state->textShift(0, -obj.getNum() * 0.001 * + fabs(state->getFontSize())); + } else { + state->textShift(-obj.getNum() * 0.001 * + fabs(state->getFontSize()), 0); + } + out->updateTextShift(state, obj.getNum()); + } else if (obj.isString()) { + doShowText(obj.getString()); + } else { + error(getPos(), "Element of show/space array must be number or string"); + } + obj.free(); + } + out->endStringOp(state); +} + +void Gfx::doShowText(GString *s) { + GfxFont *font; + int wMode; + double riseX, riseY; + CharCode code; + Unicode u[8]; + double x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy, lineX, lineY; + double originX, originY, tOriginX, tOriginY; + double oldCTM[6], newCTM[6]; + double *mat; + Object charProc; + Dict *resDict; + Parser *oldParser; + char *p; + int len, n, uLen, nChars, nSpaces, i; + + font = state->getFont(); + wMode = font->getWMode(); + + if (out->useDrawChar()) { + out->beginString(state, s); + } + + // handle a Type 3 char + if (font->getType() == fontType3 && out->interpretType3Chars()) { + mat = state->getCTM(); + for (i = 0; i < 6; ++i) { + oldCTM[i] = mat[i]; + } + mat = state->getTextMat(); + newCTM[0] = mat[0] * oldCTM[0] + mat[1] * oldCTM[2]; + newCTM[1] = mat[0] * oldCTM[1] + mat[1] * oldCTM[3]; + newCTM[2] = mat[2] * oldCTM[0] + mat[3] * oldCTM[2]; + newCTM[3] = mat[2] * oldCTM[1] + mat[3] * oldCTM[3]; + mat = font->getFontMatrix(); + newCTM[0] = mat[0] * newCTM[0] + mat[1] * newCTM[2]; + newCTM[1] = mat[0] * newCTM[1] + mat[1] * newCTM[3]; + newCTM[2] = mat[2] * newCTM[0] + mat[3] * newCTM[2]; + newCTM[3] = mat[2] * newCTM[1] + mat[3] * newCTM[3]; + newCTM[0] *= state->getFontSize(); + newCTM[1] *= state->getFontSize(); + newCTM[2] *= state->getFontSize(); + newCTM[3] *= state->getFontSize(); + newCTM[0] *= state->getHorizScaling(); + newCTM[2] *= state->getHorizScaling(); + state->textTransformDelta(0, state->getRise(), &riseX, &riseY); + curX = state->getCurX(); + curY = state->getCurY(); + lineX = state->getLineX(); + lineY = state->getLineY(); + oldParser = parser; + p = s->getCString(); + len = s->getLength(); + while (len > 0) { + n = font->getNextChar(p, len, &code, + u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, + &dx, &dy, &originX, &originY); + dx = dx * state->getFontSize() + state->getCharSpace(); + if (n == 1 && *p == ' ') { + dx += state->getWordSpace(); + } + dx *= state->getHorizScaling(); + dy *= state->getFontSize(); + state->textTransformDelta(dx, dy, &tdx, &tdy); + state->transform(curX + riseX, curY + riseY, &x, &y); + saveState(); + state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y); + //~ the CTM concat values here are wrong (but never used) + out->updateCTM(state, 1, 0, 0, 1, 0, 0); + if (!out->beginType3Char(state, curX + riseX, curY + riseY, tdx, tdy, + code, u, uLen)) { + ((Gfx8BitFont *)font)->getCharProc(code, &charProc); + if ((resDict = ((Gfx8BitFont *)font)->getResources())) { + pushResources(resDict); + } + if (charProc.isStream()) { + display(&charProc, gFalse); + } else { + error(getPos(), "Missing or bad Type3 CharProc entry"); + } + out->endType3Char(state); + if (resDict) { + popResources(); + } + charProc.free(); + } + restoreState(); + // GfxState::restore() does *not* restore the current position, + // so we deal with it here using (curX, curY) and (lineX, lineY) + curX += tdx; + curY += tdy; + state->moveTo(curX, curY); + state->textSetPos(lineX, lineY); + p += n; + len -= n; + } + parser = oldParser; + + } else if (out->useDrawChar()) { + state->textTransformDelta(0, state->getRise(), &riseX, &riseY); + p = s->getCString(); + len = s->getLength(); + while (len > 0) { + n = font->getNextChar(p, len, &code, + u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, + &dx, &dy, &originX, &originY); + if (wMode) { + dx *= state->getFontSize(); + dy = dy * state->getFontSize() + state->getCharSpace(); + if (n == 1 && *p == ' ') { + dy += state->getWordSpace(); + } + } else { + dx = dx * state->getFontSize() + state->getCharSpace(); + if (n == 1 && *p == ' ') { + dx += state->getWordSpace(); + } + dx *= state->getHorizScaling(); + dy *= state->getFontSize(); + } + state->textTransformDelta(dx, dy, &tdx, &tdy); + originX *= state->getFontSize(); + originY *= state->getFontSize(); + state->textTransformDelta(originX, originY, &tOriginX, &tOriginY); + out->drawChar(state, state->getCurX() + riseX, state->getCurY() + riseY, + tdx, tdy, tOriginX, tOriginY, code, n, u, uLen); + state->shift(tdx, tdy); + p += n; + len -= n; + } + + } else { + dx = dy = 0; + p = s->getCString(); + len = s->getLength(); + nChars = nSpaces = 0; + while (len > 0) { + n = font->getNextChar(p, len, &code, + u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, + &dx2, &dy2, &originX, &originY); + dx += dx2; + dy += dy2; + if (n == 1 && *p == ' ') { + ++nSpaces; + } + ++nChars; + p += n; + len -= n; + } + if (wMode) { + dx *= state->getFontSize(); + dy = dy * state->getFontSize() + + nChars * state->getCharSpace() + + nSpaces * state->getWordSpace(); + } else { + dx = dx * state->getFontSize() + + nChars * state->getCharSpace() + + nSpaces * state->getWordSpace(); + dx *= state->getHorizScaling(); + dy *= state->getFontSize(); + } + state->textTransformDelta(dx, dy, &tdx, &tdy); + out->drawString(state, s); + state->shift(tdx, tdy); + } + + if (out->useDrawChar()) { + out->endString(state); + } + + updateLevel += 10 * s->getLength(); +} + +//------------------------------------------------------------------------ +// XObject operators +//------------------------------------------------------------------------ + +void Gfx::opXObject(Object args[], int /*numArgs*/) { + char *name; + Object obj1, obj2, obj3, refObj; +#if OPI_SUPPORT + Object opiDict; +#endif + + name = args[0].getName(); + if (!res->lookupXObject(name, &obj1)) { + return; + } + if (!obj1.isStream()) { + error(getPos(), "XObject '%s' is wrong type", name); + obj1.free(); + return; + } +#if OPI_SUPPORT + obj1.streamGetDict()->lookup("OPI", &opiDict); + if (opiDict.isDict()) { + out->opiBegin(state, opiDict.getDict()); + } +#endif + obj1.streamGetDict()->lookup("Subtype", &obj2); + if (obj2.isName("Image")) { + if (out->needNonText()) { + res->lookupXObjectNF(name, &refObj); + doImage(&refObj, obj1.getStream(), gFalse); + refObj.free(); + } + } else if (obj2.isName("Form")) { + res->lookupXObjectNF(name, &refObj); + if (out->useDrawForm() && refObj.isRef()) { + out->drawForm(refObj.getRef()); + } else { + doForm(&obj1); + } + refObj.free(); + } else if (obj2.isName("PS")) { + obj1.streamGetDict()->lookup("Level1", &obj3); + out->psXObject(obj1.getStream(), + obj3.isStream() ? obj3.getStream() : (Stream *)NULL); + } else if (obj2.isName()) { + error(getPos(), "Unknown XObject subtype '%s'", obj2.getName()); + } else { + error(getPos(), "XObject subtype is missing or wrong type"); + } + obj2.free(); +#if OPI_SUPPORT + if (opiDict.isDict()) { + out->opiEnd(state, opiDict.getDict()); + } + opiDict.free(); +#endif + obj1.free(); +} + +void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { + Dict *dict, *maskDict; + int width, height; + int bits, maskBits; + StreamColorSpaceMode csMode; + GBool mask; + GBool invert; + GfxColorSpace *colorSpace, *maskColorSpace; + GfxImageColorMap *colorMap, *maskColorMap; + Object maskObj, smaskObj; + GBool haveColorKeyMask, haveExplicitMask, haveSoftMask; + int maskColors[2*gfxColorMaxComps]; + int maskWidth, maskHeight; + GBool maskInvert; + Stream *maskStr; + Object obj1, obj2; + int i; + + // get info from the stream + bits = 0; + csMode = streamCSNone; + str->getImageParams(&bits, &csMode); + + // get stream dict + dict = str->getDict(); + + // get size + dict->lookup("Width", &obj1); + if (obj1.isNull()) { + obj1.free(); + dict->lookup("W", &obj1); + } + if (obj1.isInt()) + width = obj1.getInt(); + else if (obj1.isReal()) + width = (int)obj1.getReal(); + else + goto err2; + obj1.free(); + dict->lookup("Height", &obj1); + if (obj1.isNull()) { + obj1.free(); + dict->lookup("H", &obj1); + } + if (obj1.isInt()) + height = obj1.getInt(); + else if (obj1.isReal()) + height = (int)obj1.getReal(); + else + goto err2; + obj1.free(); + + // image or mask? + dict->lookup("ImageMask", &obj1); + if (obj1.isNull()) { + obj1.free(); + dict->lookup("IM", &obj1); + } + mask = gFalse; + if (obj1.isBool()) + mask = obj1.getBool(); + else if (!obj1.isNull()) + goto err2; + obj1.free(); + + // bit depth + if (bits == 0) { + dict->lookup("BitsPerComponent", &obj1); + if (obj1.isNull()) { + obj1.free(); + dict->lookup("BPC", &obj1); + } + if (obj1.isInt()) { + bits = obj1.getInt(); + } else if (mask) { + bits = 1; + } else { + goto err2; + } + obj1.free(); + } + + // display a mask + if (mask) { + + // check for inverted mask + if (bits != 1) + goto err1; + invert = gFalse; + dict->lookup("Decode", &obj1); + if (obj1.isNull()) { + obj1.free(); + dict->lookup("D", &obj1); + } + if (obj1.isArray()) { + obj1.arrayGet(0, &obj2); + if (obj2.isInt() && obj2.getInt() == 1) + invert = gTrue; + obj2.free(); + } else if (!obj1.isNull()) { + goto err2; + } + obj1.free(); + + // draw it + out->drawImageMask(state, ref, str, width, height, invert, inlineImg); + + } else { + + // get color space and color map + dict->lookup("ColorSpace", &obj1); + if (obj1.isNull()) { + obj1.free(); + dict->lookup("CS", &obj1); + } + if (obj1.isName()) { + res->lookupColorSpace(obj1.getName(), &obj2); + if (!obj2.isNull()) { + obj1.free(); + obj1 = obj2; + } else { + obj2.free(); + } + } + if (!obj1.isNull()) { + colorSpace = GfxColorSpace::parse(&obj1); + } else if (csMode == streamCSDeviceGray) { + colorSpace = new GfxDeviceGrayColorSpace(); + } else if (csMode == streamCSDeviceRGB) { + colorSpace = new GfxDeviceRGBColorSpace(); + } else if (csMode == streamCSDeviceCMYK) { + colorSpace = new GfxDeviceCMYKColorSpace(); + } else { + colorSpace = NULL; + } + obj1.free(); + if (!colorSpace) { + goto err1; + } + dict->lookup("Decode", &obj1); + if (obj1.isNull()) { + obj1.free(); + dict->lookup("D", &obj1); + } + colorMap = new GfxImageColorMap(bits, &obj1, colorSpace); + obj1.free(); + if (!colorMap->isOk()) { + delete colorMap; + goto err1; + } + + // get the mask + haveColorKeyMask = haveExplicitMask = haveSoftMask = gFalse; + maskStr = NULL; // make gcc happy + maskWidth = maskHeight = 0; // make gcc happy + maskInvert = gFalse; // make gcc happy + maskColorMap = NULL; // make gcc happy + dict->lookup("Mask", &maskObj); + dict->lookup("SMask", &smaskObj); + if (smaskObj.isStream()) { + // soft mask + if (inlineImg) { + goto err1; + } + maskStr = smaskObj.getStream(); + maskDict = smaskObj.streamGetDict(); + maskDict->lookup("Width", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("W", &obj1); + } + if (!obj1.isInt()) { + goto err2; + } + maskWidth = obj1.getInt(); + obj1.free(); + maskDict->lookup("Height", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("H", &obj1); + } + if (!obj1.isInt()) { + goto err2; + } + maskHeight = obj1.getInt(); + obj1.free(); + maskDict->lookup("BitsPerComponent", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("BPC", &obj1); + } + if (!obj1.isInt()) { + goto err2; + } + maskBits = obj1.getInt(); + obj1.free(); + maskDict->lookup("ColorSpace", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("CS", &obj1); + } + if (obj1.isName()) { + res->lookupColorSpace(obj1.getName(), &obj2); + if (!obj2.isNull()) { + obj1.free(); + obj1 = obj2; + } else { + obj2.free(); + } + } + maskColorSpace = GfxColorSpace::parse(&obj1); + obj1.free(); + if (!maskColorSpace || maskColorSpace->getMode() != csDeviceGray) { + goto err1; + } + maskDict->lookup("Decode", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("D", &obj1); + } + maskColorMap = new GfxImageColorMap(maskBits, &obj1, maskColorSpace); + obj1.free(); + if (!maskColorMap->isOk()) { + delete maskColorMap; + goto err1; + } + //~ handle the Matte entry + haveSoftMask = gTrue; + } else if (maskObj.isArray()) { + // color key mask + for (i = 0; + i < maskObj.arrayGetLength() && i < 2*gfxColorMaxComps; + ++i) { + maskObj.arrayGet(i, &obj1); + maskColors[i] = obj1.getInt(); + obj1.free(); + } + haveColorKeyMask = gTrue; + } else if (maskObj.isStream()) { + // explicit mask + if (inlineImg) { + goto err1; + } + maskStr = maskObj.getStream(); + maskDict = maskObj.streamGetDict(); + maskDict->lookup("Width", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("W", &obj1); + } + if (!obj1.isInt()) { + goto err2; + } + maskWidth = obj1.getInt(); + obj1.free(); + maskDict->lookup("Height", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("H", &obj1); + } + if (!obj1.isInt()) { + goto err2; + } + maskHeight = obj1.getInt(); + obj1.free(); + maskDict->lookup("ImageMask", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("IM", &obj1); + } + if (!obj1.isBool() || !obj1.getBool()) { + goto err2; + } + obj1.free(); + maskInvert = gFalse; + maskDict->lookup("Decode", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("D", &obj1); + } + if (obj1.isArray()) { + obj1.arrayGet(0, &obj2); + if (obj2.isInt() && obj2.getInt() == 1) { + maskInvert = gTrue; + } + obj2.free(); + } else if (!obj1.isNull()) { + goto err2; + } + obj1.free(); + haveExplicitMask = gTrue; + } + + // draw it + if (haveSoftMask) { + out->drawSoftMaskedImage(state, ref, str, width, height, colorMap, + maskStr, maskWidth, maskHeight, maskColorMap); + delete maskColorMap; + } else if (haveExplicitMask) { + out->drawMaskedImage(state, ref, str, width, height, colorMap, + maskStr, maskWidth, maskHeight, maskInvert); + } else { + out->drawImage(state, ref, str, width, height, colorMap, + haveColorKeyMask ? maskColors : (int *)NULL, inlineImg); + } + delete colorMap; + + maskObj.free(); + smaskObj.free(); + } + + if ((i = width * height) > 1000) { + i = 1000; + } + updateLevel += i; + + return; + + err2: + obj1.free(); + err1: + error(getPos(), "Bad image parameters"); +} + +void Gfx::doForm(Object *str) { + Dict *dict; + GBool transpGroup, isolated, knockout; + GfxColorSpace *blendingColorSpace; + Object matrixObj, bboxObj; + double m[6], bbox[4]; + Object resObj; + Dict *resDict; + Object obj1, obj2, obj3; + int i; + + // check for excessive recursion + if (formDepth > 20) { + return; + } + + // get stream dict + dict = str->streamGetDict(); + + // check form type + dict->lookup("FormType", &obj1); + if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) { + error(getPos(), "Unknown form type"); + } + obj1.free(); + + // get bounding box + dict->lookup("BBox", &bboxObj); + if (!bboxObj.isArray()) { + bboxObj.free(); + error(getPos(), "Bad form bounding box"); + return; + } + for (i = 0; i < 4; ++i) { + bboxObj.arrayGet(i, &obj1); + bbox[i] = obj1.getNum(); + obj1.free(); + } + bboxObj.free(); + + // get matrix + dict->lookup("Matrix", &matrixObj); + if (matrixObj.isArray()) { + for (i = 0; i < 6; ++i) { + matrixObj.arrayGet(i, &obj1); + m[i] = obj1.getNum(); + obj1.free(); + } + } else { + m[0] = 1; m[1] = 0; + m[2] = 0; m[3] = 1; + m[4] = 0; m[5] = 0; + } + matrixObj.free(); + + // get resources + dict->lookup("Resources", &resObj); + resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL; + + // check for a transparency group + transpGroup = isolated = knockout = gFalse; + blendingColorSpace = NULL; + if (dict->lookup("Group", &obj1)->isDict()) { + if (obj1.dictLookup("S", &obj2)->isName("Transparency")) { + transpGroup = gTrue; + if (!obj1.dictLookup("CS", &obj3)->isNull()) { + blendingColorSpace = GfxColorSpace::parse(&obj3); + } + obj3.free(); + if (obj1.dictLookup("I", &obj3)->isBool()) { + isolated = obj3.getBool(); + } + obj3.free(); + if (obj1.dictLookup("K", &obj3)->isBool()) { + knockout = obj3.getBool(); + } + obj3.free(); + } + obj2.free(); + } + obj1.free(); + + // draw it + ++formDepth; + doForm1(str, resDict, m, bbox, + transpGroup, gFalse, blendingColorSpace, isolated, knockout); + --formDepth; + + if (blendingColorSpace) { + delete blendingColorSpace; + } + resObj.free(); +} + +void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox, + GBool transpGroup, GBool softMask, + GfxColorSpace *blendingColorSpace, + GBool isolated, GBool knockout, + GBool alpha, Function *transferFunc, + GfxColor *backdropColor) { + Parser *oldParser; + double oldBaseMatrix[6]; + int i; + + // push new resources on stack + pushResources(resDict); + + // save current graphics state + saveState(); + + // kill any pre-existing path + state->clearPath(); + + // save current parser + oldParser = parser; + + // set form transformation matrix + state->concatCTM(matrix[0], matrix[1], matrix[2], + matrix[3], matrix[4], matrix[5]); + out->updateCTM(state, matrix[0], matrix[1], matrix[2], + matrix[3], matrix[4], matrix[5]); + + // set form bounding box + state->moveTo(bbox[0], bbox[1]); + state->lineTo(bbox[2], bbox[1]); + state->lineTo(bbox[2], bbox[3]); + state->lineTo(bbox[0], bbox[3]); + state->closePath(); + state->clip(); + out->clip(state); + state->clearPath(); + + if (softMask || transpGroup) { + if (state->getBlendMode() != gfxBlendNormal) { + state->setBlendMode(gfxBlendNormal); + out->updateBlendMode(state); + } + if (state->getFillOpacity() != 1) { + state->setFillOpacity(1); + out->updateFillOpacity(state); + } + if (state->getStrokeOpacity() != 1) { + state->setStrokeOpacity(1); + out->updateStrokeOpacity(state); + } + out->clearSoftMask(state); + out->beginTransparencyGroup(state, bbox, blendingColorSpace, + isolated, knockout, softMask); + } + + // set new base matrix + for (i = 0; i < 6; ++i) { + oldBaseMatrix[i] = baseMatrix[i]; + baseMatrix[i] = state->getCTM()[i]; + } + + // draw the form + display(str, gFalse); + + if (softMask || transpGroup) { + out->endTransparencyGroup(state); + } + + // restore base matrix + for (i = 0; i < 6; ++i) { + baseMatrix[i] = oldBaseMatrix[i]; + } + + // restore parser + parser = oldParser; + + // restore graphics state + restoreState(); + + // pop resource stack + popResources(); + + if (softMask) { + out->setSoftMask(state, bbox, alpha, transferFunc, backdropColor); + } else if (transpGroup) { + out->paintTransparencyGroup(state, bbox); + } + + return; +} + +//------------------------------------------------------------------------ +// in-line image operators +//------------------------------------------------------------------------ + +void Gfx::opBeginImage(Object * /*args[]*/, int /*numArgs*/) { + Stream *str; + int c1, c2; + + // build dict/stream + str = buildImageStream(); + + // display the image + if (str) { + doImage(NULL, str, gTrue); + + // skip 'EI' tag + c1 = str->getUndecodedStream()->getChar(); + c2 = str->getUndecodedStream()->getChar(); + while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) { + c1 = c2; + c2 = str->getUndecodedStream()->getChar(); + } + delete str; + } +} + +Stream *Gfx::buildImageStream() { + Object dict; + Object obj; + char *key; + Stream *str; + + // build dictionary + dict.initDict(xref); + parser->getObj(&obj); + while (!obj.isCmd("ID") && !obj.isEOF()) { + if (!obj.isName()) { + error(getPos(), "Inline image dictionary key must be a name object"); + obj.free(); + } else { + key = copyString(obj.getName()); + obj.free(); + parser->getObj(&obj); + if (obj.isEOF() || obj.isError()) { + gfree(key); + break; + } + dict.dictAdd(key, &obj); + } + parser->getObj(&obj); + } + if (obj.isEOF()) { + error(getPos(), "End of file in inline image"); + obj.free(); + dict.free(); + return NULL; + } + obj.free(); + + // make stream + str = new EmbedStream(parser->getStream(), &dict, gFalse, 0); + str = str->addFilters(&dict); + + return str; +} + +void Gfx::opImageData(Object * /*args[]*/, int /*numArgs*/) { + error(getPos(), "Internal: got 'ID' operator"); +} + +void Gfx::opEndImage(Object * /*args[]*/, int /*numArgs*/) { + error(getPos(), "Internal: got 'EI' operator"); +} + +//------------------------------------------------------------------------ +// type 3 font operators +//------------------------------------------------------------------------ + +void Gfx::opSetCharWidth(Object args[], int /*numArgs*/) { + out->type3D0(state, args[0].getNum(), args[1].getNum()); +} + +void Gfx::opSetCacheDevice(Object args[], int /*numArgs*/) { + out->type3D1(state, args[0].getNum(), args[1].getNum(), + args[2].getNum(), args[3].getNum(), + args[4].getNum(), args[5].getNum()); +} + +//------------------------------------------------------------------------ +// compatibility operators +//------------------------------------------------------------------------ + +void Gfx::opBeginIgnoreUndef(Object * /*args[]*/, int /*numArgs*/) { + ++ignoreUndef; +} + +void Gfx::opEndIgnoreUndef(Object * /*args[]*/, int /*numArgs*/) { + if (ignoreUndef > 0) + --ignoreUndef; +} + +//------------------------------------------------------------------------ +// marked content operators +//------------------------------------------------------------------------ + +void Gfx::opBeginMarkedContent(Object args[], int numArgs) { + if (printCommands) { + printf(" marked content: %s ", args[0].getName()); + if (numArgs == 2) + args[2].print(stdout); + printf("\n"); + fflush(stdout); + } +} + +void Gfx::opEndMarkedContent(Object * /*args[]*/, int /*numArgs*/) { +} + +void Gfx::opMarkPoint(Object args[], int numArgs) { + if (printCommands) { + printf(" mark point: %s ", args[0].getName()); + if (numArgs == 2) + args[2].print(stdout); + printf("\n"); + fflush(stdout); + } +} + +//------------------------------------------------------------------------ +// misc +//------------------------------------------------------------------------ + +void Gfx::drawAnnot(Object *str, AnnotBorderStyle *borderStyle, + double xMin, double yMin, double xMax, double yMax) { + Dict *dict, *resDict; + Object matrixObj, bboxObj, resObj; + Object obj1; + double m[6], bbox[4], ictm[6]; + double *ctm; + double formX0, formY0, formX1, formY1; + double annotX0, annotY0, annotX1, annotY1; + double det, x, y, sx, sy; + double r, g, b; + GfxColor color; + double *dash, *dash2; + int dashLength; + int i; + + //~ can we assume that we're in default user space? + //~ (i.e., baseMatrix = ctm) + + // transform the annotation bbox from default user space to user + // space: (bbox * baseMatrix) * iCTM + ctm = state->getCTM(); + det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]); + ictm[0] = ctm[3] * det; + ictm[1] = -ctm[1] * det; + ictm[2] = -ctm[2] * det; + ictm[3] = ctm[0] * det; + ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det; + ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det; + x = baseMatrix[0] * xMin + baseMatrix[2] * yMin + baseMatrix[4]; + y = baseMatrix[1] * xMin + baseMatrix[3] * yMin + baseMatrix[5]; + annotX0 = ictm[0] * x + ictm[2] * y + ictm[4]; + annotY0 = ictm[1] * x + ictm[3] * y + ictm[5]; + x = baseMatrix[0] * xMax + baseMatrix[2] * yMax + baseMatrix[4]; + y = baseMatrix[1] * xMax + baseMatrix[3] * yMax + baseMatrix[5]; + annotX1 = ictm[0] * x + ictm[2] * y + ictm[4]; + annotY1 = ictm[1] * x + ictm[3] * y + ictm[5]; + if (annotX0 > annotX1) { + x = annotX0; annotX0 = annotX1; annotX1 = x; + } + if (annotY0 > annotY1) { + y = annotY0; annotY0 = annotY1; annotY1 = y; + } + + // draw the appearance stream (if there is one) + if (str->isStream()) { + + // get stream dict + dict = str->streamGetDict(); + + // get the form bounding box + dict->lookup("BBox", &bboxObj); + if (!bboxObj.isArray()) { + bboxObj.free(); + error(getPos(), "Bad form bounding box"); + return; + } + for (i = 0; i < 4; ++i) { + bboxObj.arrayGet(i, &obj1); + bbox[i] = obj1.getNum(); + obj1.free(); + } + bboxObj.free(); + + // get the form matrix + dict->lookup("Matrix", &matrixObj); + if (matrixObj.isArray()) { + for (i = 0; i < 6; ++i) { + matrixObj.arrayGet(i, &obj1); + m[i] = obj1.getNum(); + obj1.free(); + } + } else { + m[0] = 1; m[1] = 0; + m[2] = 0; m[3] = 1; + m[4] = 0; m[5] = 0; + } + matrixObj.free(); + + // transform the form bbox from form space to user space + formX0 = bbox[0] * m[0] + bbox[1] * m[2] + m[4]; + formY0 = bbox[0] * m[1] + bbox[1] * m[3] + m[5]; + formX1 = bbox[2] * m[0] + bbox[3] * m[2] + m[4]; + formY1 = bbox[2] * m[1] + bbox[3] * m[3] + m[5]; + if (formX0 > formX1) { + x = formX0; formX0 = formX1; formX1 = x; + } + if (formY0 > formY1) { + y = formY0; formY0 = formY1; formY1 = y; + } + + // scale the form to fit the annotation bbox + if (formX1 == formX0) { + // this shouldn't happen + sx = 1; + } else { + sx = (annotX1 - annotX0) / (formX1 - formX0); + } + if (formY1 == formY0) { + // this shouldn't happen + sy = 1; + } else { + sy = (annotY1 - annotY0) / (formY1 - formY0); + } + m[0] *= sx; + m[2] *= sx; + m[4] = (m[4] - formX0) * sx + annotX0; + m[1] *= sy; + m[3] *= sy; + m[5] = (m[5] - formY0) * sy + annotY0; + + // get resources + dict->lookup("Resources", &resObj); + resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL; + + // draw it + doForm1(str, resDict, m, bbox); + + resObj.free(); + } + + // draw the border + if (borderStyle && borderStyle->getWidth() > 0) { + if (state->getStrokeColorSpace()->getMode() != csDeviceRGB) { + state->setStrokePattern(NULL); + state->setStrokeColorSpace(new GfxDeviceRGBColorSpace()); + out->updateStrokeColorSpace(state); + } + borderStyle->getColor(&r, &g, &b); + color.c[0] = dblToCol(r); + color.c[1] = dblToCol(g); + color.c[2] = dblToCol(b); + state->setStrokeColor(&color); + out->updateStrokeColor(state); + // compute the width scale factor when going from default user + // space to user space + x = (baseMatrix[0] + baseMatrix[2]) * ictm[0] + + (baseMatrix[1] + baseMatrix[3]) * ictm[2]; + y = (baseMatrix[0] + baseMatrix[2]) * ictm[1] + + (baseMatrix[1] + baseMatrix[3]) * ictm[3]; + x = sqrt(0.5 * (x * x + y * y)); + state->setLineWidth(x * borderStyle->getWidth()); + out->updateLineWidth(state); + borderStyle->getDash(&dash, &dashLength); + if (borderStyle->getType() == annotBorderDashed && dashLength > 0) { + dash2 = (double *)gmallocn(dashLength, sizeof(double)); + for (i = 0; i < dashLength; ++i) { + dash2[i] = x * dash[i]; + } + state->setLineDash(dash2, dashLength, 0); + out->updateLineDash(state); + } + //~ this doesn't currently handle the beveled and engraved styles + state->clearPath(); + state->moveTo(annotX0, out->upsideDown() ? annotY0 : annotY1); + state->lineTo(annotX1, out->upsideDown() ? annotY0 : annotY1); + if (borderStyle->getType() != annotBorderUnderlined) { + state->lineTo(annotX1, out->upsideDown() ? annotY1 : annotY0); + state->lineTo(annotX0, out->upsideDown() ? annotY1 : annotY0); + state->closePath(); + } + out->stroke(state); + } +} + +void Gfx::saveState() { + out->saveState(state); + state = state->save(); +} + +void Gfx::restoreState() { + state = state->restore(); + out->restoreState(state); +} + +void Gfx::pushResources(Dict *resDict) { + res = new GfxResources(xref, resDict, res); +} + +void Gfx::popResources() { + GfxResources *resPtr; + + resPtr = res->getNext(); + delete res; + res = resPtr; +} diff --git a/kpdf/xpdf/xpdf/Gfx.h b/kpdf/xpdf/xpdf/Gfx.h new file mode 100644 index 00000000..0e4263ce --- /dev/null +++ b/kpdf/xpdf/xpdf/Gfx.h @@ -0,0 +1,312 @@ +//======================================================================== +// +// Gfx.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef GFX_H +#define GFX_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +class GString; +class XRef; +class Array; +class Stream; +class Parser; +class Dict; +class Function; +class OutputDev; +class GfxFontDict; +class GfxFont; +class GfxPattern; +class GfxTilingPattern; +class GfxShadingPattern; +class GfxShading; +class GfxFunctionShading; +class GfxAxialShading; +class GfxRadialShading; +class GfxGouraudTriangleShading; +class GfxPatchMeshShading; +struct GfxPatch; +class GfxState; +struct GfxColor; +class GfxColorSpace; +class Gfx; +class PDFRectangle; +class AnnotBorderStyle; + +//------------------------------------------------------------------------ + +enum GfxClipType { + clipNone, + clipNormal, + clipEO +}; + +enum TchkType { + tchkBool, // boolean + tchkInt, // integer + tchkNum, // number (integer or real) + tchkString, // string + tchkName, // name + tchkArray, // array + tchkProps, // properties (dictionary or name) + tchkSCN, // scn/SCN args (number of name) + tchkNone // used to avoid empty initializer lists +}; + +#define maxArgs 33 + +struct Operator { + char name[4]; + int numArgs; + TchkType tchk[maxArgs]; + void (Gfx::*func)(Object args[], int numArgs); +}; + +//------------------------------------------------------------------------ + +class GfxResources { +public: + + GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA); + ~GfxResources(); + + GfxFont *lookupFont(char *name); + GBool lookupXObject(char *name, Object *obj); + GBool lookupXObjectNF(char *name, Object *obj); + void lookupColorSpace(char *name, Object *obj); + GfxPattern *lookupPattern(char *name); + GfxShading *lookupShading(char *name); + GBool lookupGState(char *name, Object *obj); + + GfxResources *getNext() { return next; } + +private: + + GfxFontDict *fonts; + Object xObjDict; + Object colorSpaceDict; + Object patternDict; + Object shadingDict; + Object gStateDict; + GfxResources *next; +}; + +//------------------------------------------------------------------------ +// Gfx +//------------------------------------------------------------------------ + +class Gfx { +public: + + // Constructor for regular output. + Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, + double hDPI, double vDPI, PDFRectangle *box, + PDFRectangle *cropBox, int rotate, + GBool (*abortCheckCbkA)(void *data) = NULL, + void *abortCheckCbkDataA = NULL); + + // Constructor for a sub-page object. + Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, + PDFRectangle *box, PDFRectangle *cropBox, + GBool (*abortCheckCbkA)(void *data) = NULL, + void *abortCheckCbkDataA = NULL); + + ~Gfx(); + + // Interpret a stream or array of streams. + void display(Object *obj, GBool topLevel = gTrue); + + // Display an annotation, given its appearance (a Form XObject), + // border style, and bounding box (in default user space). + void drawAnnot(Object *str, AnnotBorderStyle *borderStyle, + double xMin, double yMin, double xMax, double yMax); + + // Save graphics state. + void saveState(); + + // Restore graphics state. + void restoreState(); + + // Get the current graphics state object. + GfxState *getState() { return state; } + +private: + + XRef *xref; // the xref table for this PDF file + OutputDev *out; // output device + GBool subPage; // is this a sub-page object? + GBool printCommands; // print the drawing commands (for debugging) + GfxResources *res; // resource stack + int updateLevel; + + GfxState *state; // current graphics state + GBool fontChanged; // set if font or text matrix has changed + GfxClipType clip; // do a clip? + int ignoreUndef; // current BX/EX nesting level + double baseMatrix[6]; // default matrix for most recent + // page/form/pattern + int formDepth; + + Parser *parser; // parser for page content stream(s) + + GBool // callback to check for an abort + (*abortCheckCbk)(void *data); + void *abortCheckCbkData; + + static Operator opTab[]; // table of operators + + void go(GBool topLevel); + void execOp(Object *cmd, Object args[], int numArgs); + Operator *findOp(char *name); + GBool checkArg(Object *arg, TchkType type); + int getPos(); + + // graphics state operators + void opSave(Object args[], int numArgs); + void opRestore(Object args[], int numArgs); + void opConcat(Object args[], int numArgs); + void opSetDash(Object args[], int numArgs); + void opSetFlat(Object args[], int numArgs); + void opSetLineJoin(Object args[], int numArgs); + void opSetLineCap(Object args[], int numArgs); + void opSetMiterLimit(Object args[], int numArgs); + void opSetLineWidth(Object args[], int numArgs); + void opSetExtGState(Object args[], int numArgs); + void doSoftMask(Object *str, GBool alpha, + GfxColorSpace *blendingColorSpace, + GBool isolated, GBool knockout, + Function *transferFunc, GfxColor *backdropColor); + void opSetRenderingIntent(Object args[], int numArgs); + + // color operators + void opSetFillGray(Object args[], int numArgs); + void opSetStrokeGray(Object args[], int numArgs); + void opSetFillCMYKColor(Object args[], int numArgs); + void opSetStrokeCMYKColor(Object args[], int numArgs); + void opSetFillRGBColor(Object args[], int numArgs); + void opSetStrokeRGBColor(Object args[], int numArgs); + void opSetFillColorSpace(Object args[], int numArgs); + void opSetStrokeColorSpace(Object args[], int numArgs); + void opSetFillColor(Object args[], int numArgs); + void opSetStrokeColor(Object args[], int numArgs); + void opSetFillColorN(Object args[], int numArgs); + void opSetStrokeColorN(Object args[], int numArgs); + + // path segment operators + void opMoveTo(Object args[], int numArgs); + void opLineTo(Object args[], int numArgs); + void opCurveTo(Object args[], int numArgs); + void opCurveTo1(Object args[], int numArgs); + void opCurveTo2(Object args[], int numArgs); + void opRectangle(Object args[], int numArgs); + void opClosePath(Object args[], int numArgs); + + // path painting operators + void opEndPath(Object args[], int numArgs); + void opStroke(Object args[], int numArgs); + void opCloseStroke(Object args[], int numArgs); + void opFill(Object args[], int numArgs); + void opEOFill(Object args[], int numArgs); + void opFillStroke(Object args[], int numArgs); + void opCloseFillStroke(Object args[], int numArgs); + void opEOFillStroke(Object args[], int numArgs); + void opCloseEOFillStroke(Object args[], int numArgs); + void doPatternFill(GBool eoFill); + void doPatternStroke(); + void doTilingPatternFill(GfxTilingPattern *tPat, + GBool stroke, GBool eoFill); + void doShadingPatternFill(GfxShadingPattern *sPat, + GBool stroke, GBool eoFill); + void opShFill(Object args[], int numArgs); + void doFunctionShFill(GfxFunctionShading *shading); + void doFunctionShFill1(GfxFunctionShading *shading, + double x0, double y0, + double x1, double y1, + GfxColor *colors, int depth); + void doAxialShFill(GfxAxialShading *shading); + void doRadialShFill(GfxRadialShading *shading); + void doGouraudTriangleShFill(GfxGouraudTriangleShading *shading); + void gouraudFillTriangle(double x0, double y0, GfxColor *color0, + double x1, double y1, GfxColor *color1, + double x2, double y2, GfxColor *color2, + int nComps, int depth); + void doPatchMeshShFill(GfxPatchMeshShading *shading); + void fillPatch(GfxPatch *patch, int nComps, int depth); + void doEndPath(); + + // path clipping operators + void opClip(Object args[], int numArgs); + void opEOClip(Object args[], int numArgs); + + // text object operators + void opBeginText(Object args[], int numArgs); + void opEndText(Object args[], int numArgs); + + // text state operators + void opSetCharSpacing(Object args[], int numArgs); + void opSetFont(Object args[], int numArgs); + void opSetTextLeading(Object args[], int numArgs); + void opSetTextRender(Object args[], int numArgs); + void opSetTextRise(Object args[], int numArgs); + void opSetWordSpacing(Object args[], int numArgs); + void opSetHorizScaling(Object args[], int numArgs); + + // text positioning operators + void opTextMove(Object args[], int numArgs); + void opTextMoveSet(Object args[], int numArgs); + void opSetTextMatrix(Object args[], int numArgs); + void opTextNextLine(Object args[], int numArgs); + + // text string operators + void opShowText(Object args[], int numArgs); + void opMoveShowText(Object args[], int numArgs); + void opMoveSetShowText(Object args[], int numArgs); + void opShowSpaceText(Object args[], int numArgs); + void doShowText(GString *s); + + // XObject operators + void opXObject(Object args[], int numArgs); + void doImage(Object *ref, Stream *str, GBool inlineImg); + void doForm(Object *str); + void doForm1(Object *str, Dict *resDict, double *matrix, double *bbox, + GBool transpGroup = gFalse, GBool softMask = gFalse, + GfxColorSpace *blendingColorSpace = NULL, + GBool isolated = gFalse, GBool knockout = gFalse, + GBool alpha = gFalse, Function *transferFunc = NULL, + GfxColor *backdropColor = NULL); + + // in-line image operators + void opBeginImage(Object args[], int numArgs); + Stream *buildImageStream(); + void opImageData(Object args[], int numArgs); + void opEndImage(Object args[], int numArgs); + + // type 3 font operators + void opSetCharWidth(Object args[], int numArgs); + void opSetCacheDevice(Object args[], int numArgs); + + // compatibility operators + void opBeginIgnoreUndef(Object args[], int numArgs); + void opEndIgnoreUndef(Object args[], int numArgs); + + // marked content operators + void opBeginMarkedContent(Object args[], int numArgs); + void opEndMarkedContent(Object args[], int numArgs); + void opMarkPoint(Object args[], int numArgs); + + void pushResources(Dict *resDict); + void popResources(); +}; + +#endif diff --git a/kpdf/xpdf/xpdf/GfxFont.cc b/kpdf/xpdf/xpdf/GfxFont.cc new file mode 100644 index 00000000..8694be47 --- /dev/null +++ b/kpdf/xpdf/xpdf/GfxFont.cc @@ -0,0 +1,1616 @@ +//======================================================================== +// +// GfxFont.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include +#include "gmem.h" +#include "Error.h" +#include "Object.h" +#include "Dict.h" +#include "GlobalParams.h" +#include "CMap.h" +#include "CharCodeToUnicode.h" +#include "FontEncodingTables.h" +#include "BuiltinFontTables.h" +#include "FoFiType1.h" +#include "FoFiType1C.h" +#include "FoFiTrueType.h" +#include "GfxFont.h" + +//------------------------------------------------------------------------ + +struct StdFontMapEntry { + char *altName; + char *properName; +}; + +// Acrobat 4.0 and earlier substituted Base14-compatible fonts without +// providing Widths and a FontDescriptor, so we munge the names into +// the proper Base14 names. This table is from implementation note 44 +// in the PDF 1.4 spec, with some additions based on empirical +// evidence. +static StdFontMapEntry stdFontMap[] = { + { "Arial", "Helvetica" }, + { "Arial,Bold", "Helvetica-Bold" }, + { "Arial,BoldItalic", "Helvetica-BoldOblique" }, + { "Arial,Italic", "Helvetica-Oblique" }, + { "Arial-Bold", "Helvetica-Bold" }, + { "Arial-BoldItalic", "Helvetica-BoldOblique" }, + { "Arial-BoldItalicMT", "Helvetica-BoldOblique" }, + { "Arial-BoldMT", "Helvetica-Bold" }, + { "Arial-Italic", "Helvetica-Oblique" }, + { "Arial-ItalicMT", "Helvetica-Oblique" }, + { "ArialMT", "Helvetica" }, + { "Courier,Bold", "Courier-Bold" }, + { "Courier,BoldItalic", "Courier-BoldOblique" }, + { "Courier,Italic", "Courier-Oblique" }, + { "CourierNew", "Courier" }, + { "CourierNew,Bold", "Courier-Bold" }, + { "CourierNew,BoldItalic", "Courier-BoldOblique" }, + { "CourierNew,Italic", "Courier-Oblique" }, + { "CourierNew-Bold", "Courier-Bold" }, + { "CourierNew-BoldItalic", "Courier-BoldOblique" }, + { "CourierNew-Italic", "Courier-Oblique" }, + { "CourierNewPS-BoldItalicMT", "Courier-BoldOblique" }, + { "CourierNewPS-BoldMT", "Courier-Bold" }, + { "CourierNewPS-ItalicMT", "Courier-Oblique" }, + { "CourierNewPSMT", "Courier" }, + { "Helvetica,Bold", "Helvetica-Bold" }, + { "Helvetica,BoldItalic", "Helvetica-BoldOblique" }, + { "Helvetica,Italic", "Helvetica-Oblique" }, + { "Helvetica-BoldItalic", "Helvetica-BoldOblique" }, + { "Helvetica-Italic", "Helvetica-Oblique" }, + { "Symbol,Bold", "Symbol" }, + { "Symbol,BoldItalic", "Symbol" }, + { "Symbol,Italic", "Symbol" }, + { "TimesNewRoman", "Times-Roman" }, + { "TimesNewRoman,Bold", "Times-Bold" }, + { "TimesNewRoman,BoldItalic", "Times-BoldItalic" }, + { "TimesNewRoman,Italic", "Times-Italic" }, + { "TimesNewRoman-Bold", "Times-Bold" }, + { "TimesNewRoman-BoldItalic", "Times-BoldItalic" }, + { "TimesNewRoman-Italic", "Times-Italic" }, + { "TimesNewRomanPS", "Times-Roman" }, + { "TimesNewRomanPS-Bold", "Times-Bold" }, + { "TimesNewRomanPS-BoldItalic", "Times-BoldItalic" }, + { "TimesNewRomanPS-BoldItalicMT", "Times-BoldItalic" }, + { "TimesNewRomanPS-BoldMT", "Times-Bold" }, + { "TimesNewRomanPS-Italic", "Times-Italic" }, + { "TimesNewRomanPS-ItalicMT", "Times-Italic" }, + { "TimesNewRomanPSMT", "Times-Roman" }, + { "TimesNewRomanPSMT,Bold", "Times-Bold" }, + { "TimesNewRomanPSMT,BoldItalic", "Times-BoldItalic" }, + { "TimesNewRomanPSMT,Italic", "Times-Italic" } +}; + +//------------------------------------------------------------------------ +// GfxFont +//------------------------------------------------------------------------ + +GfxFont *GfxFont::makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict) { + GString *nameA; + GfxFont *font; + Object obj1; + + // get base font name + nameA = NULL; + fontDict->lookup("BaseFont", &obj1); + if (obj1.isName()) { + nameA = new GString(obj1.getName()); + } + obj1.free(); + + // get font type + font = NULL; + fontDict->lookup("Subtype", &obj1); + if (obj1.isName("Type1") || obj1.isName("MMType1")) { + font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1, fontDict); + } else if (obj1.isName("Type1C")) { + font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1C, fontDict); + } else if (obj1.isName("Type3")) { + font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType3, fontDict); + } else if (obj1.isName("TrueType")) { + font = new Gfx8BitFont(xref, tagA, idA, nameA, fontTrueType, fontDict); + } else if (obj1.isName("Type0")) { + font = new GfxCIDFont(xref, tagA, idA, nameA, fontDict); + } else { + error(-1, "Unknown font type: '%s'", + obj1.isName() ? obj1.getName() : "???"); + font = new Gfx8BitFont(xref, tagA, idA, nameA, fontUnknownType, fontDict); + } + obj1.free(); + + return font; +} + +GfxFont::GfxFont(char *tagA, Ref idA, GString *nameA) { + ok = gFalse; + tag = new GString(tagA); + id = idA; + name = nameA; + origName = nameA; + embFontName = NULL; + extFontFile = NULL; +} + +GfxFont::~GfxFont() { + delete tag; + if (origName && origName != name) { + delete origName; + } + if (name) { + delete name; + } + if (embFontName) { + delete embFontName; + } + if (extFontFile) { + delete extFontFile; + } +} + +void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) { + Object obj1, obj2, obj3, obj4; + double t; + int i; + + // assume Times-Roman by default (for substitution purposes) + flags = fontSerif; + + embFontID.num = -1; + embFontID.gen = -1; + missingWidth = 0; + + if (fontDict->lookup("FontDescriptor", &obj1)->isDict()) { + + // get flags + if (obj1.dictLookup("Flags", &obj2)->isInt()) { + flags = obj2.getInt(); + } + obj2.free(); + + // get name + obj1.dictLookup("FontName", &obj2); + if (obj2.isName()) { + embFontName = new GString(obj2.getName()); + } + obj2.free(); + + // look for embedded font file + if (obj1.dictLookupNF("FontFile", &obj2)->isRef()) { + embFontID = obj2.getRef(); + if (type != fontType1) { + error(-1, "Mismatch between font type and embedded font file"); + type = fontType1; + } + } + obj2.free(); + if (embFontID.num == -1 && + obj1.dictLookupNF("FontFile2", &obj2)->isRef()) { + embFontID = obj2.getRef(); + if (type != fontTrueType && type != fontCIDType2) { + error(-1, "Mismatch between font type and embedded font file"); + type = type == fontCIDType0 ? fontCIDType2 : fontTrueType; + } + } + obj2.free(); + if (embFontID.num == -1 && + obj1.dictLookupNF("FontFile3", &obj2)->isRef()) { + if (obj2.fetch(xref, &obj3)->isStream()) { + obj3.streamGetDict()->lookup("Subtype", &obj4); + if (obj4.isName("Type1")) { + embFontID = obj2.getRef(); + if (type != fontType1) { + error(-1, "Mismatch between font type and embedded font file"); + type = fontType1; + } + } else if (obj4.isName("Type1C")) { + embFontID = obj2.getRef(); + if (type != fontType1 && type != fontType1C) { + error(-1, "Mismatch between font type and embedded font file"); + } + type = fontType1C; + } else if (obj4.isName("TrueType")) { + embFontID = obj2.getRef(); + if (type != fontTrueType) { + error(-1, "Mismatch between font type and embedded font file"); + type = fontTrueType; + } + } else if (obj4.isName("CIDFontType0C")) { + embFontID = obj2.getRef(); + if (type != fontCIDType0) { + error(-1, "Mismatch between font type and embedded font file"); + } + type = fontCIDType0C; + } else if (obj4.isName("OpenType")) { + embFontID = obj2.getRef(); + if (type == fontTrueType) { + type = fontTrueTypeOT; + } else if (type == fontType1) { + type = fontType1COT; + } else if (type == fontCIDType0) { + type = fontCIDType0COT; + } else if (type == fontCIDType2) { + type = fontCIDType2OT; + } else { + error(-1, "Mismatch between font type and embedded font file"); + } + } else { + error(-1, "Unknown embedded font type '%s'", + obj4.isName() ? obj4.getName() : "???"); + } + obj4.free(); + } + obj3.free(); + } + obj2.free(); + + // look for MissingWidth + obj1.dictLookup("MissingWidth", &obj2); + if (obj2.isNum()) { + missingWidth = obj2.getNum(); + } + obj2.free(); + + // get Ascent and Descent + obj1.dictLookup("Ascent", &obj2); + if (obj2.isNum()) { + t = 0.001 * obj2.getNum(); + // some broken font descriptors set ascent and descent to 0 + if (t != 0) { + ascent = t; + } + } + obj2.free(); + obj1.dictLookup("Descent", &obj2); + if (obj2.isNum()) { + t = 0.001 * obj2.getNum(); + // some broken font descriptors set ascent and descent to 0 + if (t != 0) { + descent = t; + } + // some broken font descriptors specify a positive descent + if (descent > 0) { + descent = -descent; + } + } + obj2.free(); + + // font FontBBox + if (obj1.dictLookup("FontBBox", &obj2)->isArray()) { + for (i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) { + if (obj2.arrayGet(i, &obj3)->isNum()) { + fontBBox[i] = 0.001 * obj3.getNum(); + } + obj3.free(); + } + } + obj2.free(); + + } + obj1.free(); +} + +CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits, + CharCodeToUnicode *ctu) { + GString *buf; + Object obj1; + int c; + + if (!fontDict->lookup("ToUnicode", &obj1)->isStream()) { + obj1.free(); + return NULL; + } + buf = new GString(); + obj1.streamReset(); + while ((c = obj1.streamGetChar()) != EOF) { + buf->append(c); + } + obj1.streamClose(); + obj1.free(); + if (ctu) { + ctu->mergeCMap(buf, nBits); + } else { + ctu = CharCodeToUnicode::parseCMap(buf, nBits); + } + delete buf; + return ctu; +} + +void GfxFont::findExtFontFile() { + static char *type1Exts[] = { ".pfa", ".pfb", ".ps", "", NULL }; + static char *ttExts[] = { ".ttf", ".ttc", NULL }; + + if (name) { + if (type == fontType1) { + extFontFile = globalParams->findFontFile(name, type1Exts); + } else if (type == fontTrueType) { + extFontFile = globalParams->findFontFile(name, ttExts); + } + } +} + +char *GfxFont::readExtFontFile(int *len) { + FILE *f; + char *buf; + + if (!(f = fopen(extFontFile->getCString(), "rb"))) { + error(-1, "External font file '%s' vanished", extFontFile->getCString()); + return NULL; + } + fseek(f, 0, SEEK_END); + *len = (int)ftell(f); + fseek(f, 0, SEEK_SET); + buf = (char *)gmalloc(*len); + if ((int)fread(buf, 1, *len, f) != *len) { + error(-1, "Error reading external font file '%s'", + extFontFile->getCString()); + } + fclose(f); + return buf; +} + +char *GfxFont::readEmbFontFile(XRef *xref, int *len) { + char *buf; + Object obj1, obj2; + Stream *str; + int c; + int size, i; + + obj1.initRef(embFontID.num, embFontID.gen); + obj1.fetch(xref, &obj2); + if (!obj2.isStream()) { + error(-1, "Embedded font file is not a stream"); + obj2.free(); + obj1.free(); + embFontID.num = -1; + return NULL; + } + str = obj2.getStream(); + + buf = NULL; + i = size = 0; + str->reset(); + while ((c = str->getChar()) != EOF) { + if (i == size) { + size += 4096; + buf = (char *)grealloc(buf, size); + } + buf[i++] = c; + } + *len = i; + str->close(); + + obj2.free(); + obj1.free(); + + return buf; +} + +//------------------------------------------------------------------------ +// Gfx8BitFont +//------------------------------------------------------------------------ + +Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, + GfxFontType typeA, Dict *fontDict): + GfxFont(tagA, idA, nameA) +{ + GString *name2; + BuiltinFont *builtinFont; + char **baseEnc; + GBool baseEncFromFontFile; + char *buf; + int len; + FoFiType1 *ffT1; + FoFiType1C *ffT1C; + int code, code2; + char *charName; + GBool missing, hex; + Unicode toUnicode[256]; + CharCodeToUnicode *utu, *ctu2; + Unicode uBuf[8]; + double mul; + int firstChar, lastChar; + Gushort w; + Object obj1, obj2, obj3; + int n, i, a, b, m; + + type = typeA; + ctu = NULL; + + // do font name substitution for various aliases of the Base 14 font + // names + if (name) { + name2 = name->copy(); + i = 0; + while (i < name2->getLength()) { + if (name2->getChar(i) == ' ') { + name2->del(i); + } else { + ++i; + } + } + a = 0; + b = sizeof(stdFontMap) / sizeof(StdFontMapEntry); + // invariant: stdFontMap[a].altName <= name2 < stdFontMap[b].altName + while (b - a > 1) { + m = (a + b) / 2; + if (name2->cmp(stdFontMap[m].altName) >= 0) { + a = m; + } else { + b = m; + } + } + if (!name2->cmp(stdFontMap[a].altName)) { + name = new GString(stdFontMap[a].properName); + } + delete name2; + } + + // is it a built-in font? + builtinFont = NULL; + if (name) { + for (i = 0; i < nBuiltinFonts; ++i) { + if (!name->cmp(builtinFonts[i].name)) { + builtinFont = &builtinFonts[i]; + break; + } + } + } + + // default ascent/descent values + if (builtinFont) { + ascent = 0.001 * builtinFont->ascent; + descent = 0.001 * builtinFont->descent; + fontBBox[0] = 0.001 * builtinFont->bbox[0]; + fontBBox[1] = 0.001 * builtinFont->bbox[1]; + fontBBox[2] = 0.001 * builtinFont->bbox[2]; + fontBBox[3] = 0.001 * builtinFont->bbox[3]; + } else { + ascent = 0.95; + descent = -0.35; + fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0; + } + + // get info from font descriptor + readFontDescriptor(xref, fontDict); + + // for non-embedded fonts, don't trust the ascent/descent/bbox + // values from the font descriptor + if (builtinFont && embFontID.num < 0) { + ascent = 0.001 * builtinFont->ascent; + descent = 0.001 * builtinFont->descent; + fontBBox[0] = 0.001 * builtinFont->bbox[0]; + fontBBox[1] = 0.001 * builtinFont->bbox[1]; + fontBBox[2] = 0.001 * builtinFont->bbox[2]; + fontBBox[3] = 0.001 * builtinFont->bbox[3]; + } + + // look for an external font file + findExtFontFile(); + + // get font matrix + fontMat[0] = fontMat[3] = 1; + fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0; + if (fontDict->lookup("FontMatrix", &obj1)->isArray()) { + for (i = 0; i < 6 && i < obj1.arrayGetLength(); ++i) { + if (obj1.arrayGet(i, &obj2)->isNum()) { + fontMat[i] = obj2.getNum(); + } + obj2.free(); + } + } + obj1.free(); + + // get Type 3 bounding box, font definition, and resources + if (type == fontType3) { + if (fontDict->lookup("FontBBox", &obj1)->isArray()) { + for (i = 0; i < 4 && i < obj1.arrayGetLength(); ++i) { + if (obj1.arrayGet(i, &obj2)->isNum()) { + fontBBox[i] = obj2.getNum(); + } + obj2.free(); + } + } + obj1.free(); + if (!fontDict->lookup("CharProcs", &charProcs)->isDict()) { + error(-1, "Missing or invalid CharProcs dictionary in Type 3 font"); + charProcs.free(); + } + if (!fontDict->lookup("Resources", &resources)->isDict()) { + resources.free(); + } + } + + //----- build the font encoding ----- + + // Encodings start with a base encoding, which can come from + // (in order of priority): + // 1. FontDict.Encoding or FontDict.Encoding.BaseEncoding + // - MacRoman / MacExpert / WinAnsi / Standard + // 2. embedded or external font file + // 3. default: + // - builtin --> builtin encoding + // - TrueType --> WinAnsiEncoding + // - others --> StandardEncoding + // and then add a list of differences (if any) from + // FontDict.Encoding.Differences. + + // check FontDict for base encoding + hasEncoding = gFalse; + usesMacRomanEnc = gFalse; + baseEnc = NULL; + baseEncFromFontFile = gFalse; + fontDict->lookup("Encoding", &obj1); + if (obj1.isDict()) { + obj1.dictLookup("BaseEncoding", &obj2); + if (obj2.isName("MacRomanEncoding")) { + hasEncoding = gTrue; + usesMacRomanEnc = gTrue; + baseEnc = macRomanEncoding; + } else if (obj2.isName("MacExpertEncoding")) { + hasEncoding = gTrue; + baseEnc = macExpertEncoding; + } else if (obj2.isName("WinAnsiEncoding")) { + hasEncoding = gTrue; + baseEnc = winAnsiEncoding; + } + obj2.free(); + } else if (obj1.isName("MacRomanEncoding")) { + hasEncoding = gTrue; + usesMacRomanEnc = gTrue; + baseEnc = macRomanEncoding; + } else if (obj1.isName("MacExpertEncoding")) { + hasEncoding = gTrue; + baseEnc = macExpertEncoding; + } else if (obj1.isName("WinAnsiEncoding")) { + hasEncoding = gTrue; + baseEnc = winAnsiEncoding; + } + + // check embedded or external font file for base encoding + // (only for Type 1 fonts - trying to get an encoding out of a + // TrueType font is a losing proposition) + ffT1 = NULL; + ffT1C = NULL; + buf = NULL; + if (type == fontType1 && (extFontFile || embFontID.num >= 0)) { + if (extFontFile) { + ffT1 = FoFiType1::load(extFontFile->getCString()); + } else { + buf = readEmbFontFile(xref, &len); + ffT1 = FoFiType1::make(buf, len); + } + if (ffT1) { + if (ffT1->getName()) { + if (embFontName) { + delete embFontName; + } + embFontName = new GString(ffT1->getName()); + } + if (!baseEnc) { + baseEnc = ffT1->getEncoding(); + baseEncFromFontFile = gTrue; + } + } + } else if (type == fontType1C && (extFontFile || embFontID.num >= 0)) { + if (extFontFile) { + ffT1C = FoFiType1C::load(extFontFile->getCString()); + } else { + buf = readEmbFontFile(xref, &len); + ffT1C = FoFiType1C::make(buf, len); + } + if (ffT1C) { + if (ffT1C->getName()) { + if (embFontName) { + delete embFontName; + } + embFontName = new GString(ffT1C->getName()); + } + if (!baseEnc) { + baseEnc = ffT1C->getEncoding(); + baseEncFromFontFile = gTrue; + } + } + } + if (buf) { + gfree(buf); + } + + // get default base encoding + if (!baseEnc) { + if (builtinFont && embFontID.num < 0) { + baseEnc = builtinFont->defaultBaseEnc; + hasEncoding = gTrue; + } else if (type == fontTrueType) { + baseEnc = winAnsiEncoding; + } else { + baseEnc = standardEncoding; + } + } + + // copy the base encoding + for (i = 0; i < 256; ++i) { + enc[i] = baseEnc[i]; + if ((encFree[i] = baseEncFromFontFile) && enc[i]) { + enc[i] = copyString(baseEnc[i]); + } + } + + // some Type 1C font files have empty encodings, which can break the + // T1C->T1 conversion (since the 'seac' operator depends on having + // the accents in the encoding), so we fill in any gaps from + // StandardEncoding + if (type == fontType1C && (extFontFile || embFontID.num >= 0) && + baseEncFromFontFile) { + for (i = 0; i < 256; ++i) { + if (!enc[i] && standardEncoding[i]) { + enc[i] = standardEncoding[i]; + encFree[i] = gFalse; + } + } + } + + // merge differences into encoding + if (obj1.isDict()) { + obj1.dictLookup("Differences", &obj2); + if (obj2.isArray()) { + hasEncoding = gTrue; + code = 0; + for (i = 0; i < obj2.arrayGetLength(); ++i) { + obj2.arrayGet(i, &obj3); + if (obj3.isInt()) { + code = obj3.getInt(); + } else if (obj3.isName()) { + if (code >= 0 && code < 256) { + if (encFree[code]) { + gfree(enc[code]); + } + enc[code] = copyString(obj3.getName()); + encFree[code] = gTrue; + } + ++code; + } else { + error(-1, "Wrong type in font encoding resource differences (%s)", + obj3.getTypeName()); + } + obj3.free(); + } + } + obj2.free(); + } + obj1.free(); + if (ffT1) { + delete ffT1; + } + if (ffT1C) { + delete ffT1C; + } + + //----- build the mapping to Unicode ----- + + // pass 1: use the name-to-Unicode mapping table + missing = hex = gFalse; + for (code = 0; code < 256; ++code) { + if ((charName = enc[code])) { + if (!(toUnicode[code] = globalParams->mapNameToUnicode(charName)) && + strcmp(charName, ".notdef")) { + // if it wasn't in the name-to-Unicode table, check for a + // name that looks like 'Axx' or 'xx', where 'A' is any letter + // and 'xx' is two hex digits + if ((strlen(charName) == 3 && + isalpha(charName[0]) && + isxdigit(charName[1]) && isxdigit(charName[2]) && + ((charName[1] >= 'a' && charName[1] <= 'f') || + (charName[1] >= 'A' && charName[1] <= 'F') || + (charName[2] >= 'a' && charName[2] <= 'f') || + (charName[2] >= 'A' && charName[2] <= 'F'))) || + (strlen(charName) == 2 && + isxdigit(charName[0]) && isxdigit(charName[1]) && + ((charName[0] >= 'a' && charName[0] <= 'f') || + (charName[0] >= 'A' && charName[0] <= 'F') || + (charName[1] >= 'a' && charName[1] <= 'f') || + (charName[1] >= 'A' && charName[1] <= 'F')))) { + hex = gTrue; + } + missing = gTrue; + } + } else { + toUnicode[code] = 0; + } + } + + // pass 2: try to fill in the missing chars, looking for names of + // the form 'Axx', 'xx', 'Ann', 'ABnn', or 'nn', where 'A' and 'B' + // are any letters, 'xx' is two hex digits, and 'nn' is 2-4 + // decimal digits + if (missing && globalParams->getMapNumericCharNames()) { + for (code = 0; code < 256; ++code) { + if ((charName = enc[code]) && !toUnicode[code] && + strcmp(charName, ".notdef")) { + n = strlen(charName); + code2 = -1; + if (hex && n == 3 && isalpha(charName[0]) && + isxdigit(charName[1]) && isxdigit(charName[2])) { + sscanf(charName+1, "%x", &code2); + } else if (hex && n == 2 && + isxdigit(charName[0]) && isxdigit(charName[1])) { + sscanf(charName, "%x", &code2); + } else if (!hex && n >= 2 && n <= 4 && + isdigit(charName[0]) && isdigit(charName[1])) { + code2 = atoi(charName); + } else if (n >= 3 && n <= 5 && + isdigit(charName[1]) && isdigit(charName[2])) { + code2 = atoi(charName+1); + } else if (n >= 4 && n <= 6 && + isdigit(charName[2]) && isdigit(charName[3])) { + code2 = atoi(charName+2); + } + if (code2 >= 0 && code2 <= 0xff) { + toUnicode[code] = (Unicode)code2; + } + } + } + + // if the 'mapUnknownCharNames' flag is set, do a simple pass-through + // mapping for unknown character names + } else if (missing && globalParams->getMapUnknownCharNames()) { + for (code = 0; code < 256; ++code) { + if (!toUnicode[code]) { + toUnicode[code] = code; + } + } + } + + // construct the char code -> Unicode mapping object + ctu = CharCodeToUnicode::make8BitToUnicode(toUnicode); + + // merge in a ToUnicode CMap, if there is one -- this overwrites + // existing entries in ctu, i.e., the ToUnicode CMap takes + // precedence, but the other encoding info is allowed to fill in any + // holes + readToUnicodeCMap(fontDict, 8, ctu); + + // look for a Unicode-to-Unicode mapping + if (name && (utu = globalParams->getUnicodeToUnicode(name))) { + for (i = 0; i < 256; ++i) { + toUnicode[i] = 0; + } + ctu2 = CharCodeToUnicode::make8BitToUnicode(toUnicode); + for (i = 0; i < 256; ++i) { + n = ctu->mapToUnicode((CharCode)i, uBuf, 8); + if (n >= 1) { + n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8); + if (n >= 1) { + ctu2->setMapping((CharCode)i, uBuf, n); + } + } + } + utu->decRefCnt(); + delete ctu; + ctu = ctu2; + } + + //----- get the character widths ----- + + // initialize all widths + for (code = 0; code < 256; ++code) { + widths[code] = missingWidth * 0.001; + } + + // use widths from font dict, if present + fontDict->lookup("FirstChar", &obj1); + firstChar = obj1.isInt() ? obj1.getInt() : 0; + obj1.free(); + if (firstChar < 0 || firstChar > 255) { + firstChar = 0; + } + fontDict->lookup("LastChar", &obj1); + lastChar = obj1.isInt() ? obj1.getInt() : 255; + obj1.free(); + if (lastChar < 0 || lastChar > 255) { + lastChar = 255; + } + mul = (type == fontType3) ? fontMat[0] : 0.001; + fontDict->lookup("Widths", &obj1); + if (obj1.isArray()) { + flags |= fontFixedWidth; + if (obj1.arrayGetLength() < lastChar - firstChar + 1) { + lastChar = firstChar + obj1.arrayGetLength() - 1; + } + for (code = firstChar; code <= lastChar; ++code) { + obj1.arrayGet(code - firstChar, &obj2); + if (obj2.isNum()) { + widths[code] = obj2.getNum() * mul; + if (widths[code] != widths[firstChar]) { + flags &= ~fontFixedWidth; + } + } + obj2.free(); + } + + // use widths from built-in font + } else if (builtinFont) { + // this is a kludge for broken PDF files that encode char 32 + // as .notdef + if (builtinFont->widths->getWidth("space", &w)) { + widths[32] = 0.001 * w; + } + for (code = 0; code < 256; ++code) { + if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) { + widths[code] = 0.001 * w; + } + } + + // couldn't find widths -- use defaults + } else { + // this is technically an error -- the Widths entry is required + // for all but the Base-14 fonts -- but certain PDF generators + // apparently don't include widths for Arial and TimesNewRoman + if (isFixedWidth()) { + i = 0; + } else if (isSerif()) { + i = 8; + } else { + i = 4; + } + if (isBold()) { + i += 2; + } + if (isItalic()) { + i += 1; + } + builtinFont = builtinFontSubst[i]; + // this is a kludge for broken PDF files that encode char 32 + // as .notdef + if (builtinFont->widths->getWidth("space", &w)) { + widths[32] = 0.001 * w; + } + for (code = 0; code < 256; ++code) { + if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) { + widths[code] = 0.001 * w; + } + } + } + obj1.free(); + + ok = gTrue; +} + +Gfx8BitFont::~Gfx8BitFont() { + int i; + + for (i = 0; i < 256; ++i) { + if (encFree[i] && enc[i]) { + gfree(enc[i]); + } + } + ctu->decRefCnt(); + if (charProcs.isDict()) { + charProcs.free(); + } + if (resources.isDict()) { + resources.free(); + } +} + +int Gfx8BitFont::getNextChar(char *s, int /*len*/, CharCode *code, + Unicode *u, int uSize, int *uLen, + double *dx, double *dy, double *ox, double *oy) { + CharCode c; + + *code = c = (CharCode)(*s & 0xff); + *uLen = ctu->mapToUnicode(c, u, uSize); + *dx = widths[c]; + *dy = *ox = *oy = 0; + return 1; +} + +CharCodeToUnicode *Gfx8BitFont::getToUnicode() { + ctu->incRefCnt(); + return ctu; +} + +Gushort *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { + Gushort *map; + int cmapPlatform, cmapEncoding; + int unicodeCmap, macRomanCmap, msSymbolCmap, cmap; + GBool useMacRoman, useUnicode; + char *charName; + Unicode u; + int code, i, n; + + map = (Gushort *)gmallocn(256, sizeof(Gushort)); + for (i = 0; i < 256; ++i) { + map[i] = 0; + } + + // To match up with the Adobe-defined behaviour, we choose a cmap + // like this: + // 1. If the PDF font has an encoding: + // 1a. If the PDF font specified MacRomanEncoding and the + // TrueType font has a Macintosh Roman cmap, use it, and + // reverse map the char names through MacRomanEncoding to + // get char codes. + // 1b. If the TrueType font has a Microsoft Unicode cmap or a + // non-Microsoft Unicode cmap, use it, and use the Unicode + // indexes, not the char codes. + // 1c. If the PDF font is symbolic and the TrueType font has a + // Microsoft Symbol cmap, use it, and use char codes + // directly (possibly with an offset of 0xf000). + // 1d. If the TrueType font has a Macintosh Roman cmap, use it, + // as in case 1a. + // 2. If the PDF font does not have an encoding or the PDF font is + // symbolic: + // 2a. If the TrueType font has a Macintosh Roman cmap, use it, + // and use char codes directly (possibly with an offset of + // 0xf000). + // 2b. If the TrueType font has a Microsoft Symbol cmap, use it, + // and use char codes directly (possible with an offset of + // 0xf000). + // 3. If none of these rules apply, use the first cmap and hope for + // the best (this shouldn't happen). + unicodeCmap = macRomanCmap = msSymbolCmap = -1; + for (i = 0; i < ff->getNumCmaps(); ++i) { + cmapPlatform = ff->getCmapPlatform(i); + cmapEncoding = ff->getCmapEncoding(i); + if ((cmapPlatform == 3 && cmapEncoding == 1) || + cmapPlatform == 0) { + unicodeCmap = i; + } else if (cmapPlatform == 1 && cmapEncoding == 0) { + macRomanCmap = i; + } else if (cmapPlatform == 3 && cmapEncoding == 0) { + msSymbolCmap = i; + } + } + cmap = 0; + useMacRoman = gFalse; + useUnicode = gFalse; + if (hasEncoding) { + if (usesMacRomanEnc && macRomanCmap >= 0) { + cmap = macRomanCmap; + useMacRoman = gTrue; + } else if (unicodeCmap >= 0) { + cmap = unicodeCmap; + useUnicode = gTrue; + } else if ((flags & fontSymbolic) && msSymbolCmap >= 0) { + cmap = msSymbolCmap; + } else if ((flags & fontSymbolic) && macRomanCmap >= 0) { + cmap = macRomanCmap; + } else if (macRomanCmap >= 0) { + cmap = macRomanCmap; + useMacRoman = gTrue; + } + } else { + if (msSymbolCmap >= 0) { + cmap = msSymbolCmap; + } else if (macRomanCmap >= 0) { + cmap = macRomanCmap; + } + } + + // reverse map the char names through MacRomanEncoding, then map the + // char codes through the cmap + if (useMacRoman) { + for (i = 0; i < 256; ++i) { + if ((charName = enc[i])) { + if ((code = globalParams->getMacRomanCharCode(charName))) { + map[i] = ff->mapCodeToGID(cmap, code); + } + } + } + + // map Unicode through the cmap + } else if (useUnicode) { + for (i = 0; i < 256; ++i) { + if (((charName = enc[i]) && + (u = globalParams->mapNameToUnicode(charName))) || + (n = ctu->mapToUnicode((CharCode)i, &u, 1))) { + map[i] = ff->mapCodeToGID(cmap, u); + } + } + + // map the char codes through the cmap, possibly with an offset of + // 0xf000 + } else { + for (i = 0; i < 256; ++i) { + if (!(map[i] = ff->mapCodeToGID(cmap, i))) { + map[i] = ff->mapCodeToGID(cmap, 0xf000 + i); + } + } + } + + // try the TrueType 'post' table to handle any unmapped characters + for (i = 0; i < 256; ++i) { + if (!map[i] && (charName = enc[i])) { + map[i] = (Gushort)(int)ff->mapNameToGID(charName); + } + } + + return map; +} + +Dict *Gfx8BitFont::getCharProcs() { + return charProcs.isDict() ? charProcs.getDict() : (Dict *)NULL; +} + +Object *Gfx8BitFont::getCharProc(int code, Object *proc) { + if (enc[code] && charProcs.isDict()) { + charProcs.dictLookup(enc[code], proc); + } else { + proc->initNull(); + } + return proc; +} + +Dict *Gfx8BitFont::getResources() { + return resources.isDict() ? resources.getDict() : (Dict *)NULL; +} + +//------------------------------------------------------------------------ +// GfxCIDFont +//------------------------------------------------------------------------ + +static int CDECL cmpWidthExcep(const void *w1, const void *w2) { + return ((GfxFontCIDWidthExcep *)w1)->first - + ((GfxFontCIDWidthExcep *)w2)->first; +} + +static int CDECL cmpWidthExcepV(const void *w1, const void *w2) { + return ((GfxFontCIDWidthExcepV *)w1)->first - + ((GfxFontCIDWidthExcepV *)w2)->first; +} + +GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, + Dict *fontDict): + GfxFont(tagA, idA, nameA) +{ + Dict *desFontDict; + GString *collection, *cMapName; + Object desFontDictObj; + Object obj1, obj2, obj3, obj4, obj5, obj6; + CharCodeToUnicode *utu; + CharCode c; + Unicode uBuf[8]; + int c1, c2; + int excepsSize, i, j, k, n; + + ascent = 0.95; + descent = -0.35; + fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0; + cMap = NULL; + ctu = NULL; + widths.defWidth = 1.0; + widths.defHeight = -1.0; + widths.defVY = 0.880; + widths.exceps = NULL; + widths.nExceps = 0; + widths.excepsV = NULL; + widths.nExcepsV = 0; + cidToGID = NULL; + cidToGIDLen = 0; + + // get the descendant font + if (!fontDict->lookup("DescendantFonts", &obj1)->isArray()) { + error(-1, "Missing DescendantFonts entry in Type 0 font"); + obj1.free(); + goto err1; + } + if (!obj1.arrayGet(0, &desFontDictObj)->isDict()) { + error(-1, "Bad descendant font in Type 0 font"); + goto err3; + } + obj1.free(); + desFontDict = desFontDictObj.getDict(); + + // font type + if (!desFontDict->lookup("Subtype", &obj1)) { + error(-1, "Missing Subtype entry in Type 0 descendant font"); + goto err3; + } + if (obj1.isName("CIDFontType0")) { + type = fontCIDType0; + } else if (obj1.isName("CIDFontType2")) { + type = fontCIDType2; + } else { + error(-1, "Unknown Type 0 descendant font type '%s'", + obj1.isName() ? obj1.getName() : "???"); + goto err3; + } + obj1.free(); + + // get info from font descriptor + readFontDescriptor(xref, desFontDict); + + // look for an external font file + findExtFontFile(); + + //----- encoding info ----- + + // char collection + if (!desFontDict->lookup("CIDSystemInfo", &obj1)->isDict()) { + error(-1, "Missing CIDSystemInfo dictionary in Type 0 descendant font"); + goto err3; + } + obj1.dictLookup("Registry", &obj2); + obj1.dictLookup("Ordering", &obj3); + if (!obj2.isString() || !obj3.isString()) { + error(-1, "Invalid CIDSystemInfo dictionary in Type 0 descendant font"); + goto err4; + } + collection = obj2.getString()->copy()->append('-')->append(obj3.getString()); + obj3.free(); + obj2.free(); + obj1.free(); + + // look for a ToUnicode CMap + if (!(ctu = readToUnicodeCMap(fontDict, 16, NULL))) { + + // the "Adobe-Identity" and "Adobe-UCS" collections don't have + // cidToUnicode files + if (collection->cmp("Adobe-Identity") && + collection->cmp("Adobe-UCS")) { + + // look for a user-supplied .cidToUnicode file + if (!(ctu = globalParams->getCIDToUnicode(collection))) { + error(-1, "Unknown character collection '%s'", + collection->getCString()); + // fall-through, assuming the Identity mapping -- this appears + // to match Adobe's behavior + } + } + } + + // look for a Unicode-to-Unicode mapping + if (name && (utu = globalParams->getUnicodeToUnicode(name))) { + if (ctu) { + for (c = 0; c < ctu->getLength(); ++c) { + n = ctu->mapToUnicode(c, uBuf, 8); + if (n >= 1) { + n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8); + if (n >= 1) { + ctu->setMapping(c, uBuf, n); + } + } + } + utu->decRefCnt(); + } else { + ctu = utu; + } + } + + // encoding (i.e., CMap) + //~ need to handle a CMap stream here + //~ also need to deal with the UseCMap entry in the stream dict + if (!fontDict->lookup("Encoding", &obj1)->isName()) { + error(-1, "Missing or invalid Encoding entry in Type 0 font"); + delete collection; + goto err3; + } + cMapName = new GString(obj1.getName()); + obj1.free(); + if (!(cMap = globalParams->getCMap(collection, cMapName))) { + error(-1, "Unknown CMap '%s' for character collection '%s'", + cMapName->getCString(), collection->getCString()); + delete collection; + delete cMapName; + goto err2; + } + delete collection; + delete cMapName; + + // CIDToGIDMap (for embedded TrueType fonts) + if (type == fontCIDType2) { + desFontDict->lookup("CIDToGIDMap", &obj1); + if (obj1.isStream()) { + cidToGIDLen = 0; + i = 64; + cidToGID = (Gushort *)gmallocn(i, sizeof(Gushort)); + obj1.streamReset(); + while ((c1 = obj1.streamGetChar()) != EOF && + (c2 = obj1.streamGetChar()) != EOF) { + if (cidToGIDLen == i) { + i *= 2; + cidToGID = (Gushort *)greallocn(cidToGID, i, sizeof(Gushort)); + } + cidToGID[cidToGIDLen++] = (Gushort)((c1 << 8) + c2); + } + } else if (!obj1.isName("Identity") && !obj1.isNull()) { + error(-1, "Invalid CIDToGIDMap entry in CID font"); + } + obj1.free(); + } + + //----- character metrics ----- + + // default char width + if (desFontDict->lookup("DW", &obj1)->isInt()) { + widths.defWidth = obj1.getInt() * 0.001; + } + obj1.free(); + + // char width exceptions + if (desFontDict->lookup("W", &obj1)->isArray()) { + excepsSize = 0; + i = 0; + while (i + 1 < obj1.arrayGetLength()) { + obj1.arrayGet(i, &obj2); + obj1.arrayGet(i + 1, &obj3); + if (obj2.isInt() && obj3.isInt() && i + 2 < obj1.arrayGetLength()) { + if (obj1.arrayGet(i + 2, &obj4)->isNum()) { + if (widths.nExceps == excepsSize) { + excepsSize += 16; + widths.exceps = (GfxFontCIDWidthExcep *) + greallocn(widths.exceps, + excepsSize, sizeof(GfxFontCIDWidthExcep)); + } + widths.exceps[widths.nExceps].first = obj2.getInt(); + widths.exceps[widths.nExceps].last = obj3.getInt(); + widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001; + ++widths.nExceps; + } else { + error(-1, "Bad widths array in Type 0 font"); + } + obj4.free(); + i += 3; + } else if (obj2.isInt() && obj3.isArray()) { + if (widths.nExceps + obj3.arrayGetLength() > excepsSize) { + excepsSize = (widths.nExceps + obj3.arrayGetLength() + 15) & ~15; + widths.exceps = (GfxFontCIDWidthExcep *) + greallocn(widths.exceps, + excepsSize, sizeof(GfxFontCIDWidthExcep)); + } + j = obj2.getInt(); + for (k = 0; k < obj3.arrayGetLength(); ++k) { + if (obj3.arrayGet(k, &obj4)->isNum()) { + widths.exceps[widths.nExceps].first = j; + widths.exceps[widths.nExceps].last = j; + widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001; + ++j; + ++widths.nExceps; + } else { + error(-1, "Bad widths array in Type 0 font"); + } + obj4.free(); + } + i += 2; + } else { + error(-1, "Bad widths array in Type 0 font"); + ++i; + } + obj3.free(); + obj2.free(); + } + qsort(widths.exceps, widths.nExceps, sizeof(GfxFontCIDWidthExcep), + &cmpWidthExcep); + } + obj1.free(); + + // default metrics for vertical font + if (desFontDict->lookup("DW2", &obj1)->isArray() && + obj1.arrayGetLength() == 2) { + if (obj1.arrayGet(0, &obj2)->isNum()) { + widths.defVY = obj2.getNum() * 0.001; + } + obj2.free(); + if (obj1.arrayGet(1, &obj2)->isNum()) { + widths.defHeight = obj2.getNum() * 0.001; + } + obj2.free(); + } + obj1.free(); + + // char metric exceptions for vertical font + if (desFontDict->lookup("W2", &obj1)->isArray()) { + excepsSize = 0; + i = 0; + while (i + 1 < obj1.arrayGetLength()) { + obj1.arrayGet(i, &obj2); + obj1.arrayGet(i+ 1, &obj3); + if (obj2.isInt() && obj3.isInt() && i + 4 < obj1.arrayGetLength()) { + if (obj1.arrayGet(i + 2, &obj4)->isNum() && + obj1.arrayGet(i + 3, &obj5)->isNum() && + obj1.arrayGet(i + 4, &obj6)->isNum()) { + if (widths.nExcepsV == excepsSize) { + excepsSize += 16; + widths.excepsV = (GfxFontCIDWidthExcepV *) + greallocn(widths.excepsV, + excepsSize, sizeof(GfxFontCIDWidthExcepV)); + } + widths.excepsV[widths.nExcepsV].first = obj2.getInt(); + widths.excepsV[widths.nExcepsV].last = obj3.getInt(); + widths.excepsV[widths.nExcepsV].height = obj4.getNum() * 0.001; + widths.excepsV[widths.nExcepsV].vx = obj5.getNum() * 0.001; + widths.excepsV[widths.nExcepsV].vy = obj6.getNum() * 0.001; + ++widths.nExcepsV; + } else { + error(-1, "Bad widths (W2) array in Type 0 font"); + } + obj6.free(); + obj5.free(); + obj4.free(); + i += 5; + } else if (obj2.isInt() && obj3.isArray()) { + if (widths.nExcepsV + obj3.arrayGetLength() / 3 > excepsSize) { + excepsSize = + (widths.nExcepsV + obj3.arrayGetLength() / 3 + 15) & ~15; + widths.excepsV = (GfxFontCIDWidthExcepV *) + greallocn(widths.excepsV, + excepsSize, sizeof(GfxFontCIDWidthExcepV)); + } + j = obj2.getInt(); + for (k = 0; k < obj3.arrayGetLength(); k += 3) { + if (obj3.arrayGet(k, &obj4)->isNum() && + obj3.arrayGet(k+1, &obj5)->isNum() && + obj3.arrayGet(k+2, &obj6)->isNum()) { + widths.excepsV[widths.nExceps].first = j; + widths.excepsV[widths.nExceps].last = j; + widths.excepsV[widths.nExceps].height = obj4.getNum() * 0.001; + widths.excepsV[widths.nExceps].vx = obj5.getNum() * 0.001; + widths.excepsV[widths.nExceps].vy = obj6.getNum() * 0.001; + ++j; + ++widths.nExcepsV; + } else { + error(-1, "Bad widths (W2) array in Type 0 font"); + } + obj6.free(); + obj5.free(); + obj4.free(); + } + i += 2; + } else { + error(-1, "Bad widths (W2) array in Type 0 font"); + ++i; + } + obj3.free(); + obj2.free(); + } + qsort(widths.excepsV, widths.nExcepsV, sizeof(GfxFontCIDWidthExcepV), + &cmpWidthExcepV); + } + obj1.free(); + + desFontDictObj.free(); + ok = gTrue; + return; + + err4: + obj3.free(); + obj2.free(); + err3: + obj1.free(); + err2: + desFontDictObj.free(); + err1:; +} + +GfxCIDFont::~GfxCIDFont() { + if (cMap) { + cMap->decRefCnt(); + } + if (ctu) { + ctu->decRefCnt(); + } + gfree(widths.exceps); + gfree(widths.excepsV); + if (cidToGID) { + gfree(cidToGID); + } +} + +int GfxCIDFont::getNextChar(char *s, int len, CharCode *code, + Unicode *u, int uSize, int *uLen, + double *dx, double *dy, double *ox, double *oy) { + CID cid; + double w, h, vx, vy; + int n, a, b, m; + + if (!cMap) { + *code = 0; + *uLen = 0; + *dx = *dy = 0; + return 1; + } + + *code = (CharCode)(cid = cMap->getCID(s, len, &n)); + if (ctu) { + *uLen = ctu->mapToUnicode(cid, u, uSize); + } else { + *uLen = 0; + } + + // horizontal + if (cMap->getWMode() == 0) { + w = widths.defWidth; + h = vx = vy = 0; + if (widths.nExceps > 0 && cid >= widths.exceps[0].first) { + a = 0; + b = widths.nExceps; + // invariant: widths.exceps[a].first <= cid < widths.exceps[b].first + while (b - a > 1) { + m = (a + b) / 2; + if (widths.exceps[m].first <= cid) { + a = m; + } else { + b = m; + } + } + if (cid <= widths.exceps[a].last) { + w = widths.exceps[a].width; + } + } + + // vertical + } else { + w = 0; + h = widths.defHeight; + vx = widths.defWidth / 2; + vy = widths.defVY; + if (widths.nExcepsV > 0 && cid >= widths.excepsV[0].first) { + a = 0; + b = widths.nExcepsV; + // invariant: widths.excepsV[a].first <= cid < widths.excepsV[b].first + while (b - a > 1) { + m = (a + b) / 2; + if (widths.excepsV[m].last <= cid) { + a = m; + } else { + b = m; + } + } + if (cid <= widths.excepsV[a].last) { + h = widths.excepsV[a].height; + vx = widths.excepsV[a].vx; + vy = widths.excepsV[a].vy; + } + } + } + + *dx = w; + *dy = h; + *ox = vx; + *oy = vy; + + return n; +} + +int GfxCIDFont::getWMode() { + return cMap ? cMap->getWMode() : 0; +} + +CharCodeToUnicode *GfxCIDFont::getToUnicode() { + if (ctu) { + ctu->incRefCnt(); + } + return ctu; +} + +GString *GfxCIDFont::getCollection() { + return cMap ? cMap->getCollection() : (GString *)NULL; +} + +Gushort *GfxCIDFont::getCodeToGIDMap(FoFiTrueType *ff, int *mapsizep) { + Gushort *map; + int cmapPlatform, cmapEncoding; + int /*unicodeCmap, macRomanCmap, msSymbolCmap, */cmap; +// GBool useMacRoman, useUnicode; +// char *charName; + Unicode u; + int /*code, */i; + int mapsize; + int cidlen; + + *mapsizep = 0; + if (!ctu) return NULL; + + /* we use only unicode cmap */ + cmap = -1; + for (i = 0; i < ff->getNumCmaps(); ++i) { + cmapPlatform = ff->getCmapPlatform(i); + cmapEncoding = ff->getCmapEncoding(i); + if ((cmapPlatform == 3 && cmapEncoding == 1) || cmapPlatform == 0) + cmap = i; + } + if (cmap < 0) + return NULL; + + cidlen = 0; + mapsize = 64; + map = (Gushort *)gmalloc(mapsize * sizeof(Gushort)); + + while (cidlen < ctu->getLength()) { + int n; + if ((n = ctu->mapToUnicode((CharCode)cidlen, &u, 1)) == 0) { + cidlen++; + continue; + } + if (cidlen >= mapsize) { + while (cidlen >= mapsize) + mapsize *= 2; + map = (Gushort *)grealloc(map, mapsize * sizeof(Gushort)); + } + map[cidlen] = ff->mapCodeToGID(cmap, u); + cidlen++; + } + + *mapsizep = cidlen; + return map; +} + +//------------------------------------------------------------------------ +// GfxFontDict +//------------------------------------------------------------------------ + +GfxFontDict::GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict) { + int i; + Object obj1, obj2; + Ref r; + + numFonts = fontDict->getLength(); + fonts = (GfxFont **)gmallocn(numFonts, sizeof(GfxFont *)); + for (i = 0; i < numFonts; ++i) { + fontDict->getValNF(i, &obj1); + obj1.fetch(xref, &obj2); + if (obj2.isDict()) { + if (obj1.isRef()) { + r = obj1.getRef(); + } else { + // no indirect reference for this font, so invent a unique one + // (legal generation numbers are five digits, so any 6-digit + // number would be safe) + r.num = i; + if (fontDictRef) { + r.gen = 100000 + fontDictRef->num; + } else { + r.gen = 999999; + } + } + fonts[i] = GfxFont::makeFont(xref, fontDict->getKey(i), + r, obj2.getDict()); + if (fonts[i] && !fonts[i]->isOk()) { + delete fonts[i]; + fonts[i] = NULL; + } + } else { + error(-1, "font resource is not a dictionary"); + fonts[i] = NULL; + } + obj1.free(); + obj2.free(); + } +} + +GfxFontDict::~GfxFontDict() { + int i; + + for (i = 0; i < numFonts; ++i) { + if (fonts[i]) { + delete fonts[i]; + } + } + gfree(fonts); +} + +GfxFont *GfxFontDict::lookup(char *tag) { + int i; + + for (i = 0; i < numFonts; ++i) { + if (fonts[i] && fonts[i]->matches(tag)) { + return fonts[i]; + } + } + return NULL; +} diff --git a/kpdf/xpdf/xpdf/GfxFont.h b/kpdf/xpdf/xpdf/GfxFont.h new file mode 100644 index 00000000..b4e84812 --- /dev/null +++ b/kpdf/xpdf/xpdf/GfxFont.h @@ -0,0 +1,322 @@ +//======================================================================== +// +// GfxFont.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef GFXFONT_H +#define GFXFONT_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "GString.h" +#include "Object.h" +#include "CharTypes.h" + +class Dict; +class CMap; +class CharCodeToUnicode; +class FoFiTrueType; +struct GfxFontCIDWidths; + +//------------------------------------------------------------------------ +// GfxFontType +//------------------------------------------------------------------------ + +enum GfxFontType { + //----- Gfx8BitFont + fontUnknownType, + fontType1, + fontType1C, + fontType1COT, + fontType3, + fontTrueType, + fontTrueTypeOT, + //----- GfxCIDFont + fontCIDType0, + fontCIDType0C, + fontCIDType0COT, + fontCIDType2, + fontCIDType2OT +}; + +//------------------------------------------------------------------------ +// GfxFontCIDWidths +//------------------------------------------------------------------------ + +struct GfxFontCIDWidthExcep { + CID first; // this record applies to + CID last; // CIDs .. + double width; // char width +}; + +struct GfxFontCIDWidthExcepV { + CID first; // this record applies to + CID last; // CIDs .. + double height; // char height + double vx, vy; // origin position +}; + +struct GfxFontCIDWidths { + double defWidth; // default char width + double defHeight; // default char height + double defVY; // default origin position + GfxFontCIDWidthExcep *exceps; // exceptions + int nExceps; // number of valid entries in exceps + GfxFontCIDWidthExcepV * // exceptions for vertical font + excepsV; + int nExcepsV; // number of valid entries in excepsV +}; + +//------------------------------------------------------------------------ +// GfxFont +//------------------------------------------------------------------------ + +#define fontFixedWidth (1 << 0) +#define fontSerif (1 << 1) +#define fontSymbolic (1 << 2) +#define fontItalic (1 << 6) +#define fontBold (1 << 18) + +class GfxFont { +public: + + // Build a GfxFont object. + static GfxFont *makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict); + + GfxFont(char *tagA, Ref idA, GString *nameA); + + virtual ~GfxFont(); + + GBool isOk() { return ok; } + + // Get font tag. + GString *getTag() { return tag; } + + // Get font dictionary ID. + Ref *getID() { return &id; } + + // Does this font match the tag? + GBool matches(char *tagA) { return !tag->cmp(tagA); } + + // Get base font name. + GString *getName() { return name; } + + // Get the original font name (ignornig any munging that might have + // been done to map to a canonical Base-14 font name). + GString *getOrigName() { return origName; } + + // Get font type. + GfxFontType getType() { return type; } + virtual GBool isCIDFont() { return gFalse; } + + // Get embedded font ID, i.e., a ref for the font file stream. + // Returns false if there is no embedded font. + GBool getEmbeddedFontID(Ref *embID) + { *embID = embFontID; return embFontID.num >= 0; } + + // Get the PostScript font name for the embedded font. Returns + // NULL if there is no embedded font. + GString *getEmbeddedFontName() { return embFontName; } + + // Get the name of the external font file. Returns NULL if there + // is no external font file. + GString *getExtFontFile() { return extFontFile; } + + // Get font descriptor flags. + int getFlags() { return flags; } + GBool isFixedWidth() { return flags & fontFixedWidth; } + GBool isSerif() { return flags & fontSerif; } + GBool isSymbolic() { return flags & fontSymbolic; } + GBool isItalic() { return flags & fontItalic; } + GBool isBold() { return flags & fontBold; } + + // Return the font matrix. + double *getFontMatrix() { return fontMat; } + + // Return the font bounding box. + double *getFontBBox() { return fontBBox; } + + // Return the ascent and descent values. + double getAscent() { return ascent; } + double getDescent() { return descent; } + + // Return the writing mode (0=horizontal, 1=vertical). + virtual int getWMode() { return 0; } + + // Read an external or embedded font file into a buffer. + char *readExtFontFile(int *len); + char *readEmbFontFile(XRef *xref, int *len); + + // Get the next char from a string of bytes, returning the + // char , its Unicode mapping , its displacement vector + // (, ), and its origin offset vector (, ). + // is the number of entries available in , and is set to + // the number actually used. Returns the number of bytes used by + // the char code. + virtual int getNextChar(char *s, int len, CharCode *code, + Unicode *u, int uSize, int *uLen, + double *dx, double *dy, double *ox, double *oy) = 0; + +protected: + + void readFontDescriptor(XRef *xref, Dict *fontDict); + CharCodeToUnicode *readToUnicodeCMap(Dict *fontDict, int nBits, + CharCodeToUnicode *ctu); + void findExtFontFile(); + + GString *tag; // PDF font tag + Ref id; // reference (used as unique ID) + GString *name; // font name + GString *origName; // original font name + GfxFontType type; // type of font + int flags; // font descriptor flags + GString *embFontName; // name of embedded font + Ref embFontID; // ref to embedded font file stream + GString *extFontFile; // external font file name + double fontMat[6]; // font matrix (Type 3 only) + double fontBBox[4]; // font bounding box (Type 3 only) + double missingWidth; // "default" width + double ascent; // max height above baseline + double descent; // max depth below baseline + GBool ok; +}; + +//------------------------------------------------------------------------ +// Gfx8BitFont +//------------------------------------------------------------------------ + +class Gfx8BitFont: public GfxFont { +public: + + Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, + GfxFontType typeA, Dict *fontDict); + + virtual ~Gfx8BitFont(); + + virtual int getNextChar(char *s, int len, CharCode *code, + Unicode *u, int uSize, int *uLen, + double *dx, double *dy, double *ox, double *oy); + + // Return the encoding. + char **getEncoding() { return enc; } + + // Return the Unicode map. + CharCodeToUnicode *getToUnicode(); + + // Return the character name associated with . + char *getCharName(int code) { return enc[code]; } + + // Returns true if the PDF font specified an encoding. + GBool getHasEncoding() { return hasEncoding; } + + // Returns true if the PDF font specified MacRomanEncoding. + GBool getUsesMacRomanEnc() { return usesMacRomanEnc; } + + // Get width of a character. + double getWidth(Guchar c) { return widths[c]; } + + // Return a char code-to-GID mapping for the provided font file. + // (This is only useful for TrueType fonts.) + Gushort *getCodeToGIDMap(FoFiTrueType *ff); + + // Return the Type 3 CharProc dictionary, or NULL if none. + Dict *getCharProcs(); + + // Return the Type 3 CharProc for the character associated with . + Object *getCharProc(int code, Object *proc); + + // Return the Type 3 Resources dictionary, or NULL if none. + Dict *getResources(); + +private: + + char *enc[256]; // char code --> char name + char encFree[256]; // boolean for each char name: if set, + // the string is malloc'ed + CharCodeToUnicode *ctu; // char code --> Unicode + GBool hasEncoding; + GBool usesMacRomanEnc; + double widths[256]; // character widths + Object charProcs; // Type 3 CharProcs dictionary + Object resources; // Type 3 Resources dictionary +}; + +//------------------------------------------------------------------------ +// GfxCIDFont +//------------------------------------------------------------------------ + +class GfxCIDFont: public GfxFont { +public: + + GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, + Dict *fontDict); + + virtual ~GfxCIDFont(); + + virtual GBool isCIDFont() { return gTrue; } + + virtual int getNextChar(char *s, int len, CharCode *code, + Unicode *u, int uSize, int *uLen, + double *dx, double *dy, double *ox, double *oy); + + // Return the writing mode (0=horizontal, 1=vertical). + virtual int getWMode(); + + // Return the Unicode map. + CharCodeToUnicode *getToUnicode(); + + // Get the collection name (-). + GString *getCollection(); + + // Return the CID-to-GID mapping table. These should only be called + // if type is fontCIDType2. + Gushort *getCIDToGID() { return cidToGID; } + int getCIDToGIDLen() { return cidToGIDLen; } + + Gushort *getCodeToGIDMap(FoFiTrueType *ff, int *length); + +private: + + CMap *cMap; // char code --> CID + CharCodeToUnicode *ctu; // CID --> Unicode + GfxFontCIDWidths widths; // character widths + Gushort *cidToGID; // CID --> GID mapping (for embedded + // TrueType fonts) + int cidToGIDLen; +}; + +//------------------------------------------------------------------------ +// GfxFontDict +//------------------------------------------------------------------------ + +class GfxFontDict { +public: + + // Build the font dictionary, given the PDF font dictionary. + GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict); + + // Destructor. + ~GfxFontDict(); + + // Get the specified font. + GfxFont *lookup(char *tag); + + // Iterative access. + int getNumFonts() { return numFonts; } + GfxFont *getFont(int i) { return fonts[i]; } + +private: + + GfxFont **fonts; // list of fonts + int numFonts; // number of fonts +}; + +#endif diff --git a/kpdf/xpdf/xpdf/GfxState.cc b/kpdf/xpdf/xpdf/GfxState.cc new file mode 100644 index 00000000..a00dabe1 --- /dev/null +++ b/kpdf/xpdf/xpdf/GfxState.cc @@ -0,0 +1,4137 @@ +//======================================================================== +// +// GfxState.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include "gmem.h" +#include "Error.h" +#include "Object.h" +#include "Array.h" +#include "Page.h" +#include "GfxState.h" + +//------------------------------------------------------------------------ + +static inline GfxColorComp clip01(GfxColorComp x) { + return (x < 0) ? 0 : (x > gfxColorComp1) ? gfxColorComp1 : x; +} + +static inline double clip01(double x) { + return (x < 0) ? 0 : (x > 1) ? 1 : x; +} + +//------------------------------------------------------------------------ + +struct GfxBlendModeInfo { + char *name; + GfxBlendMode mode; +}; + +static GfxBlendModeInfo gfxBlendModeNames[] = { + { "Normal", gfxBlendNormal }, + { "Compatible", gfxBlendNormal }, + { "Multiply", gfxBlendMultiply }, + { "Screen", gfxBlendScreen }, + { "Overlay", gfxBlendOverlay }, + { "Darken", gfxBlendDarken }, + { "Lighten", gfxBlendLighten }, + { "ColorDodge", gfxBlendColorDodge }, + { "ColorBurn", gfxBlendColorBurn }, + { "HardLight", gfxBlendHardLight }, + { "SoftLight", gfxBlendSoftLight }, + { "Difference", gfxBlendDifference }, + { "Exclusion", gfxBlendExclusion }, + { "Hue", gfxBlendHue }, + { "Saturation", gfxBlendSaturation }, + { "Color", gfxBlendColor }, + { "Luminosity", gfxBlendLuminosity } +}; + +#define nGfxBlendModeNames \ + ((int)((sizeof(gfxBlendModeNames) / sizeof(GfxBlendModeInfo)))) + +//------------------------------------------------------------------------ + +// NB: This must match the GfxColorSpaceMode enum defined in +// GfxState.h +static char *gfxColorSpaceModeNames[] = { + "DeviceGray", + "CalGray", + "DeviceRGB", + "CalRGB", + "DeviceCMYK", + "Lab", + "ICCBased", + "Indexed", + "Separation", + "DeviceN", + "Pattern" +}; + +#define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *))) + +//------------------------------------------------------------------------ +// GfxColorSpace +//------------------------------------------------------------------------ + +GfxColorSpace::GfxColorSpace() { +} + +GfxColorSpace::~GfxColorSpace() { +} + +GfxColorSpace *GfxColorSpace::parse(Object *csObj) { + GfxColorSpace *cs; + Object obj1; + + cs = NULL; + if (csObj->isName()) { + if (csObj->isName("DeviceGray") || csObj->isName("G")) { + cs = new GfxDeviceGrayColorSpace(); + } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) { + cs = new GfxDeviceRGBColorSpace(); + } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) { + cs = new GfxDeviceCMYKColorSpace(); + } else if (csObj->isName("Pattern")) { + cs = new GfxPatternColorSpace(NULL); + } else { + error(-1, "Bad color space '%s'", csObj->getName()); + } + } else if (csObj->isArray()) { + csObj->arrayGet(0, &obj1); + if (obj1.isName("DeviceGray") || obj1.isName("G")) { + cs = new GfxDeviceGrayColorSpace(); + } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) { + cs = new GfxDeviceRGBColorSpace(); + } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) { + cs = new GfxDeviceCMYKColorSpace(); + } else if (obj1.isName("CalGray")) { + cs = GfxCalGrayColorSpace::parse(csObj->getArray()); + } else if (obj1.isName("CalRGB")) { + cs = GfxCalRGBColorSpace::parse(csObj->getArray()); + } else if (obj1.isName("Lab")) { + cs = GfxLabColorSpace::parse(csObj->getArray()); + } else if (obj1.isName("ICCBased")) { + cs = GfxICCBasedColorSpace::parse(csObj->getArray()); + } else if (obj1.isName("Indexed") || obj1.isName("I")) { + cs = GfxIndexedColorSpace::parse(csObj->getArray()); + } else if (obj1.isName("Separation")) { + cs = GfxSeparationColorSpace::parse(csObj->getArray()); + } else if (obj1.isName("DeviceN")) { + cs = GfxDeviceNColorSpace::parse(csObj->getArray()); + } else if (obj1.isName("Pattern")) { + cs = GfxPatternColorSpace::parse(csObj->getArray()); + } else { + error(-1, "Bad color space"); + } + obj1.free(); + } else { + error(-1, "Bad color space - expected name or array"); + } + return cs; +} + +void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange, + int /*maxImgPixel*/) { + int i; + + for (i = 0; i < getNComps(); ++i) { + decodeLow[i] = 0; + decodeRange[i] = 1; + } +} + +int GfxColorSpace::getNumColorSpaceModes() { + return nGfxColorSpaceModes; +} + +char *GfxColorSpace::getColorSpaceModeName(int idx) { + return gfxColorSpaceModeNames[idx]; +} + +//------------------------------------------------------------------------ +// GfxDeviceGrayColorSpace +//------------------------------------------------------------------------ + +GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() { +} + +GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() { +} + +GfxColorSpace *GfxDeviceGrayColorSpace::copy() { + return new GfxDeviceGrayColorSpace(); +} + +void GfxDeviceGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) { + *gray = clip01(color->c[0]); +} + +void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + rgb->r = rgb->g = rgb->b = clip01(color->c[0]); +} + +void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + cmyk->c = cmyk->m = cmyk->y = 0; + cmyk->k = clip01(gfxColorComp1 - color->c[0]); +} + +void GfxDeviceGrayColorSpace::getDefaultColor(GfxColor *color) { + color->c[0] = 0; +} + +//------------------------------------------------------------------------ +// GfxCalGrayColorSpace +//------------------------------------------------------------------------ + +GfxCalGrayColorSpace::GfxCalGrayColorSpace() { + whiteX = whiteY = whiteZ = 1; + blackX = blackY = blackZ = 0; + gamma = 1; +} + +GfxCalGrayColorSpace::~GfxCalGrayColorSpace() { +} + +GfxColorSpace *GfxCalGrayColorSpace::copy() { + GfxCalGrayColorSpace *cs; + + cs = new GfxCalGrayColorSpace(); + cs->whiteX = whiteX; + cs->whiteY = whiteY; + cs->whiteZ = whiteZ; + cs->blackX = blackX; + cs->blackY = blackY; + cs->blackZ = blackZ; + cs->gamma = gamma; + return cs; +} + +GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) { + GfxCalGrayColorSpace *cs; + Object obj1, obj2, obj3; + + arr->get(1, &obj1); + if (!obj1.isDict()) { + error(-1, "Bad CalGray color space"); + obj1.free(); + return NULL; + } + cs = new GfxCalGrayColorSpace(); + if (obj1.dictLookup("WhitePoint", &obj2)->isArray() && + obj2.arrayGetLength() == 3) { + obj2.arrayGet(0, &obj3); + cs->whiteX = obj3.getNum(); + obj3.free(); + obj2.arrayGet(1, &obj3); + cs->whiteY = obj3.getNum(); + obj3.free(); + obj2.arrayGet(2, &obj3); + cs->whiteZ = obj3.getNum(); + obj3.free(); + } + obj2.free(); + if (obj1.dictLookup("BlackPoint", &obj2)->isArray() && + obj2.arrayGetLength() == 3) { + obj2.arrayGet(0, &obj3); + cs->blackX = obj3.getNum(); + obj3.free(); + obj2.arrayGet(1, &obj3); + cs->blackY = obj3.getNum(); + obj3.free(); + obj2.arrayGet(2, &obj3); + cs->blackZ = obj3.getNum(); + obj3.free(); + } + obj2.free(); + if (obj1.dictLookup("Gamma", &obj2)->isNum()) { + cs->gamma = obj2.getNum(); + } + obj2.free(); + obj1.free(); + return cs; +} + +void GfxCalGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) { + *gray = clip01(color->c[0]); +} + +void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + rgb->r = rgb->g = rgb->b = clip01(color->c[0]); +} + +void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + cmyk->c = cmyk->m = cmyk->y = 0; + cmyk->k = clip01(gfxColorComp1 - color->c[0]); +} + +void GfxCalGrayColorSpace::getDefaultColor(GfxColor *color) { + color->c[0] = 0; +} + +//------------------------------------------------------------------------ +// GfxDeviceRGBColorSpace +//------------------------------------------------------------------------ + +GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() { +} + +GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() { +} + +GfxColorSpace *GfxDeviceRGBColorSpace::copy() { + return new GfxDeviceRGBColorSpace(); +} + +void GfxDeviceRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) { + *gray = clip01((GfxColorComp)(0.3 * color->c[0] + + 0.59 * color->c[1] + + 0.11 * color->c[2] + 0.5)); +} + +void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + rgb->r = clip01(color->c[0]); + rgb->g = clip01(color->c[1]); + rgb->b = clip01(color->c[2]); +} + +void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + GfxColorComp c, m, y, k; + + c = clip01(gfxColorComp1 - color->c[0]); + m = clip01(gfxColorComp1 - color->c[1]); + y = clip01(gfxColorComp1 - color->c[2]); + k = c; + if (m < k) { + k = m; + } + if (y < k) { + k = y; + } + cmyk->c = c - k; + cmyk->m = m - k; + cmyk->y = y - k; + cmyk->k = k; +} + +void GfxDeviceRGBColorSpace::getDefaultColor(GfxColor *color) { + color->c[0] = 0; + color->c[1] = 0; + color->c[2] = 0; +} + +//------------------------------------------------------------------------ +// GfxCalRGBColorSpace +//------------------------------------------------------------------------ + +GfxCalRGBColorSpace::GfxCalRGBColorSpace() { + whiteX = whiteY = whiteZ = 1; + blackX = blackY = blackZ = 0; + gammaR = gammaG = gammaB = 1; + mat[0] = 1; mat[1] = 0; mat[2] = 0; + mat[3] = 0; mat[4] = 1; mat[5] = 0; + mat[6] = 0; mat[7] = 0; mat[8] = 1; +} + +GfxCalRGBColorSpace::~GfxCalRGBColorSpace() { +} + +GfxColorSpace *GfxCalRGBColorSpace::copy() { + GfxCalRGBColorSpace *cs; + int i; + + cs = new GfxCalRGBColorSpace(); + cs->whiteX = whiteX; + cs->whiteY = whiteY; + cs->whiteZ = whiteZ; + cs->blackX = blackX; + cs->blackY = blackY; + cs->blackZ = blackZ; + cs->gammaR = gammaR; + cs->gammaG = gammaG; + cs->gammaB = gammaB; + for (i = 0; i < 9; ++i) { + cs->mat[i] = mat[i]; + } + return cs; +} + +GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) { + GfxCalRGBColorSpace *cs; + Object obj1, obj2, obj3; + int i; + + arr->get(1, &obj1); + if (!obj1.isDict()) { + error(-1, "Bad CalRGB color space"); + obj1.free(); + return NULL; + } + cs = new GfxCalRGBColorSpace(); + if (obj1.dictLookup("WhitePoint", &obj2)->isArray() && + obj2.arrayGetLength() == 3) { + obj2.arrayGet(0, &obj3); + cs->whiteX = obj3.getNum(); + obj3.free(); + obj2.arrayGet(1, &obj3); + cs->whiteY = obj3.getNum(); + obj3.free(); + obj2.arrayGet(2, &obj3); + cs->whiteZ = obj3.getNum(); + obj3.free(); + } + obj2.free(); + if (obj1.dictLookup("BlackPoint", &obj2)->isArray() && + obj2.arrayGetLength() == 3) { + obj2.arrayGet(0, &obj3); + cs->blackX = obj3.getNum(); + obj3.free(); + obj2.arrayGet(1, &obj3); + cs->blackY = obj3.getNum(); + obj3.free(); + obj2.arrayGet(2, &obj3); + cs->blackZ = obj3.getNum(); + obj3.free(); + } + obj2.free(); + if (obj1.dictLookup("Gamma", &obj2)->isArray() && + obj2.arrayGetLength() == 3) { + obj2.arrayGet(0, &obj3); + cs->gammaR = obj3.getNum(); + obj3.free(); + obj2.arrayGet(1, &obj3); + cs->gammaG = obj3.getNum(); + obj3.free(); + obj2.arrayGet(2, &obj3); + cs->gammaB = obj3.getNum(); + obj3.free(); + } + obj2.free(); + if (obj1.dictLookup("Matrix", &obj2)->isArray() && + obj2.arrayGetLength() == 9) { + for (i = 0; i < 9; ++i) { + obj2.arrayGet(i, &obj3); + cs->mat[i] = obj3.getNum(); + obj3.free(); + } + } + obj2.free(); + obj1.free(); + return cs; +} + +void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) { + *gray = clip01((GfxColorComp)(0.299 * color->c[0] + + 0.587 * color->c[1] + + 0.114 * color->c[2] + 0.5)); +} + +void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + rgb->r = clip01(color->c[0]); + rgb->g = clip01(color->c[1]); + rgb->b = clip01(color->c[2]); +} + +void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + GfxColorComp c, m, y, k; + + c = clip01(gfxColorComp1 - color->c[0]); + m = clip01(gfxColorComp1 - color->c[1]); + y = clip01(gfxColorComp1 - color->c[2]); + k = c; + if (m < k) { + k = m; + } + if (y < k) { + k = y; + } + cmyk->c = c - k; + cmyk->m = m - k; + cmyk->y = y - k; + cmyk->k = k; +} + +void GfxCalRGBColorSpace::getDefaultColor(GfxColor *color) { + color->c[0] = 0; + color->c[1] = 0; + color->c[2] = 0; +} + +//------------------------------------------------------------------------ +// GfxDeviceCMYKColorSpace +//------------------------------------------------------------------------ + +GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() { +} + +GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() { +} + +GfxColorSpace *GfxDeviceCMYKColorSpace::copy() { + return new GfxDeviceCMYKColorSpace(); +} + +void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, GfxGray *gray) { + *gray = clip01((GfxColorComp)(gfxColorComp1 - color->c[3] + - 0.3 * color->c[0] + - 0.59 * color->c[1] + - 0.11 * color->c[2] + 0.5)); +} + +void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + double c, m, y, k, c1, m1, y1, k1, r, g, b, x; + + c = colToDbl(color->c[0]); + m = colToDbl(color->c[1]); + y = colToDbl(color->c[2]); + k = colToDbl(color->c[3]); + c1 = 1 - c; + m1 = 1 - m; + y1 = 1 - y; + k1 = 1 - k; + // this is a matrix multiplication, unrolled for performance + // C M Y K + x = c1 * m1 * y1 * k1; // 0 0 0 0 + r = g = b = x; + x = c1 * m1 * y1 * k; // 0 0 0 1 + r += 0.1373 * x; + g += 0.1216 * x; + b += 0.1255 * x; + x = c1 * m1 * y * k1; // 0 0 1 0 + r += x; + g += 0.9490 * x; + x = c1 * m1 * y * k; // 0 0 1 1 + r += 0.1098 * x; + g += 0.1020 * x; + x = c1 * m * y1 * k1; // 0 1 0 0 + r += 0.9255 * x; + b += 0.5490 * x; + x = c1 * m * y1 * k; // 0 1 0 1 + r += 0.1412 * x; + x = c1 * m * y * k1; // 0 1 1 0 + r += 0.9294 * x; + g += 0.1098 * x; + b += 0.1412 * x; + x = c1 * m * y * k; // 0 1 1 1 + r += 0.1333 * x; + x = c * m1 * y1 * k1; // 1 0 0 0 + g += 0.6784 * x; + b += 0.9373 * x; + x = c * m1 * y1 * k; // 1 0 0 1 + g += 0.0588 * x; + b += 0.1412 * x; + x = c * m1 * y * k1; // 1 0 1 0 + g += 0.6510 * x; + b += 0.3137 * x; + x = c * m1 * y * k; // 1 0 1 1 + g += 0.0745 * x; + x = c * m * y1 * k1; // 1 1 0 0 + r += 0.1804 * x; + g += 0.1922 * x; + b += 0.5725 * x; + x = c * m * y1 * k; // 1 1 0 1 + b += 0.0078 * x; + x = c * m * y * k1; // 1 1 1 0 + r += 0.2118 * x; + g += 0.2119 * x; + b += 0.2235 * x; + rgb->r = clip01(dblToCol(r)); + rgb->g = clip01(dblToCol(g)); + rgb->b = clip01(dblToCol(b)); +} + +void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + cmyk->c = clip01(color->c[0]); + cmyk->m = clip01(color->c[1]); + cmyk->y = clip01(color->c[2]); + cmyk->k = clip01(color->c[3]); +} + +void GfxDeviceCMYKColorSpace::getDefaultColor(GfxColor *color) { + color->c[0] = 0; + color->c[1] = 0; + color->c[2] = 0; + color->c[3] = gfxColorComp1; +} + +//------------------------------------------------------------------------ +// GfxLabColorSpace +//------------------------------------------------------------------------ + +// This is the inverse of MatrixLMN in Example 4.10 from the PostScript +// Language Reference, Third Edition. +static double xyzrgb[3][3] = { + { 3.240449, -1.537136, -0.498531 }, + { -0.969265, 1.876011, 0.041556 }, + { 0.055643, -0.204026, 1.057229 } +}; + +GfxLabColorSpace::GfxLabColorSpace() { + whiteX = whiteY = whiteZ = 1; + blackX = blackY = blackZ = 0; + aMin = bMin = -100; + aMax = bMax = 100; +} + +GfxLabColorSpace::~GfxLabColorSpace() { +} + +GfxColorSpace *GfxLabColorSpace::copy() { + GfxLabColorSpace *cs; + + cs = new GfxLabColorSpace(); + cs->whiteX = whiteX; + cs->whiteY = whiteY; + cs->whiteZ = whiteZ; + cs->blackX = blackX; + cs->blackY = blackY; + cs->blackZ = blackZ; + cs->aMin = aMin; + cs->aMax = aMax; + cs->bMin = bMin; + cs->bMax = bMax; + cs->kr = kr; + cs->kg = kg; + cs->kb = kb; + return cs; +} + +GfxColorSpace *GfxLabColorSpace::parse(Array *arr) { + GfxLabColorSpace *cs; + Object obj1, obj2, obj3; + + arr->get(1, &obj1); + if (!obj1.isDict()) { + error(-1, "Bad Lab color space"); + obj1.free(); + return NULL; + } + cs = new GfxLabColorSpace(); + if (obj1.dictLookup("WhitePoint", &obj2)->isArray() && + obj2.arrayGetLength() == 3) { + obj2.arrayGet(0, &obj3); + cs->whiteX = obj3.getNum(); + obj3.free(); + obj2.arrayGet(1, &obj3); + cs->whiteY = obj3.getNum(); + obj3.free(); + obj2.arrayGet(2, &obj3); + cs->whiteZ = obj3.getNum(); + obj3.free(); + } + obj2.free(); + if (obj1.dictLookup("BlackPoint", &obj2)->isArray() && + obj2.arrayGetLength() == 3) { + obj2.arrayGet(0, &obj3); + cs->blackX = obj3.getNum(); + obj3.free(); + obj2.arrayGet(1, &obj3); + cs->blackY = obj3.getNum(); + obj3.free(); + obj2.arrayGet(2, &obj3); + cs->blackZ = obj3.getNum(); + obj3.free(); + } + obj2.free(); + if (obj1.dictLookup("Range", &obj2)->isArray() && + obj2.arrayGetLength() == 4) { + obj2.arrayGet(0, &obj3); + cs->aMin = obj3.getNum(); + obj3.free(); + obj2.arrayGet(1, &obj3); + cs->aMax = obj3.getNum(); + obj3.free(); + obj2.arrayGet(2, &obj3); + cs->bMin = obj3.getNum(); + obj3.free(); + obj2.arrayGet(3, &obj3); + cs->bMax = obj3.getNum(); + obj3.free(); + } + obj2.free(); + obj1.free(); + + cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX + + xyzrgb[0][1] * cs->whiteY + + xyzrgb[0][2] * cs->whiteZ); + cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX + + xyzrgb[1][1] * cs->whiteY + + xyzrgb[1][2] * cs->whiteZ); + cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX + + xyzrgb[2][1] * cs->whiteY + + xyzrgb[2][2] * cs->whiteZ); + + return cs; +} + +void GfxLabColorSpace::getGray(GfxColor *color, GfxGray *gray) { + GfxRGB rgb; + + getRGB(color, &rgb); + *gray = clip01((GfxColorComp)(0.299 * rgb.r + + 0.587 * rgb.g + + 0.114 * rgb.b + 0.5)); +} + +void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + double X, Y, Z; + double t1, t2; + double r, g, b; + + // convert L*a*b* to CIE 1931 XYZ color space + t1 = (colToDbl(color->c[0]) + 16) / 116; + t2 = t1 + colToDbl(color->c[1]) / 500; + if (t2 >= (6.0 / 29.0)) { + X = t2 * t2 * t2; + } else { + X = (108.0 / 841.0) * (t2 - (4.0 / 29.0)); + } + X *= whiteX; + if (t1 >= (6.0 / 29.0)) { + Y = t1 * t1 * t1; + } else { + Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0)); + } + Y *= whiteY; + t2 = t1 - colToDbl(color->c[2]) / 200; + if (t2 >= (6.0 / 29.0)) { + Z = t2 * t2 * t2; + } else { + Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0)); + } + Z *= whiteZ; + + // convert XYZ to RGB, including gamut mapping and gamma correction + r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z; + g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z; + b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z; + rgb->r = dblToCol(pow(clip01(r * kr), 0.5)); + rgb->g = dblToCol(pow(clip01(g * kg), 0.5)); + rgb->b = dblToCol(pow(clip01(b * kb), 0.5)); +} + +void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + GfxRGB rgb; + GfxColorComp c, m, y, k; + + getRGB(color, &rgb); + c = clip01(gfxColorComp1 - rgb.r); + m = clip01(gfxColorComp1 - rgb.g); + y = clip01(gfxColorComp1 - rgb.b); + k = c; + if (m < k) { + k = m; + } + if (y < k) { + k = y; + } + cmyk->c = c - k; + cmyk->m = m - k; + cmyk->y = y - k; + cmyk->k = k; +} + +void GfxLabColorSpace::getDefaultColor(GfxColor *color) { + color->c[0] = 0; + if (aMin > 0) { + color->c[1] = dblToCol(aMin); + } else if (aMax < 0) { + color->c[1] = dblToCol(aMax); + } else { + color->c[1] = 0; + } + if (bMin > 0) { + color->c[2] = dblToCol(bMin); + } else if (bMax < 0) { + color->c[2] = dblToCol(bMax); + } else { + color->c[2] = 0; + } +} + +void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange, + int /*maxImgPixel*/) { + decodeLow[0] = 0; + decodeRange[0] = 100; + decodeLow[1] = aMin; + decodeRange[1] = aMax - aMin; + decodeLow[2] = bMin; + decodeRange[2] = bMax - bMin; +} + +//------------------------------------------------------------------------ +// GfxICCBasedColorSpace +//------------------------------------------------------------------------ + +GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA, + Ref *iccProfileStreamA) { + nComps = nCompsA; + alt = altA; + iccProfileStream = *iccProfileStreamA; + rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0; + rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1; +} + +GfxICCBasedColorSpace::~GfxICCBasedColorSpace() { + delete alt; +} + +GfxColorSpace *GfxICCBasedColorSpace::copy() { + GfxICCBasedColorSpace *cs; + int i; + + cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream); + for (i = 0; i < 4; ++i) { + cs->rangeMin[i] = rangeMin[i]; + cs->rangeMax[i] = rangeMax[i]; + } + return cs; +} + +GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) { + GfxICCBasedColorSpace *cs; + Ref iccProfileStreamA; + int nCompsA; + GfxColorSpace *altA; + Dict *dict; + Object obj1, obj2, obj3; + int i; + + arr->getNF(1, &obj1); + if (obj1.isRef()) { + iccProfileStreamA = obj1.getRef(); + } else { + iccProfileStreamA.num = 0; + iccProfileStreamA.gen = 0; + } + obj1.free(); + arr->get(1, &obj1); + if (!obj1.isStream()) { + error(-1, "Bad ICCBased color space (stream)"); + obj1.free(); + return NULL; + } + dict = obj1.streamGetDict(); + if (!dict->lookup("N", &obj2)->isInt()) { + error(-1, "Bad ICCBased color space (N)"); + obj2.free(); + obj1.free(); + return NULL; + } + nCompsA = obj2.getInt(); + obj2.free(); + if (nCompsA > gfxColorMaxComps) { + error(-1, "ICCBased color space with too many (%d > %d) components", + nCompsA, gfxColorMaxComps); + nCompsA = gfxColorMaxComps; + } + if (dict->lookup("Alternate", &obj2)->isNull() || + !(altA = GfxColorSpace::parse(&obj2))) { + switch (nCompsA) { + case 1: + altA = new GfxDeviceGrayColorSpace(); + break; + case 3: + altA = new GfxDeviceRGBColorSpace(); + break; + case 4: + altA = new GfxDeviceCMYKColorSpace(); + break; + default: + error(-1, "Bad ICCBased color space - invalid N"); + obj2.free(); + obj1.free(); + return NULL; + } + } + obj2.free(); + cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA); + if (dict->lookup("Range", &obj2)->isArray() && + obj2.arrayGetLength() == 2 * nCompsA) { + for (i = 0; i < nCompsA; ++i) { + obj2.arrayGet(2*i, &obj3); + cs->rangeMin[i] = obj3.getNum(); + obj3.free(); + obj2.arrayGet(2*i+1, &obj3); + cs->rangeMax[i] = obj3.getNum(); + obj3.free(); + } + } + obj2.free(); + obj1.free(); + return cs; +} + +void GfxICCBasedColorSpace::getGray(GfxColor *color, GfxGray *gray) { + alt->getGray(color, gray); +} + +void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + alt->getRGB(color, rgb); +} + +void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + alt->getCMYK(color, cmyk); +} + +void GfxICCBasedColorSpace::getDefaultColor(GfxColor *color) { + int i; + + for (i = 0; i < nComps; ++i) { + if (rangeMin[i] > 0) { + color->c[i] = dblToCol(rangeMin[i]); + } else if (rangeMax[i] < 0) { + color->c[i] = dblToCol(rangeMax[i]); + } else { + color->c[i] = 0; + } + } +} + +void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow, + double *decodeRange, + int maxImgPixel) { + alt->getDefaultRanges(decodeLow, decodeRange, maxImgPixel); + +#if 0 + // this is nominally correct, but some PDF files don't set the + // correct ranges in the ICCBased dict + int i; + + for (i = 0; i < nComps; ++i) { + decodeLow[i] = rangeMin[i]; + decodeRange[i] = rangeMax[i] - rangeMin[i]; + } +#endif +} + +//------------------------------------------------------------------------ +// GfxIndexedColorSpace +//------------------------------------------------------------------------ + +GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA, + int indexHighA) { + base = baseA; + indexHigh = indexHighA; + lookup = (Guchar *)gmallocn((indexHigh + 1) * base->getNComps(), + sizeof(Guchar)); +} + +GfxIndexedColorSpace::~GfxIndexedColorSpace() { + delete base; + gfree(lookup); +} + +GfxColorSpace *GfxIndexedColorSpace::copy() { + GfxIndexedColorSpace *cs; + + cs = new GfxIndexedColorSpace(base->copy(), indexHigh); + memcpy(cs->lookup, lookup, + (indexHigh + 1) * base->getNComps() * sizeof(Guchar)); + return cs; +} + +GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) { + GfxIndexedColorSpace *cs; + GfxColorSpace *baseA; + int indexHighA; + Object obj1; + int x; + char *s; + int n, i, j; + + if (arr->getLength() != 4) { + error(-1, "Bad Indexed color space"); + goto err1; + } + arr->get(1, &obj1); + if (!(baseA = GfxColorSpace::parse(&obj1))) { + error(-1, "Bad Indexed color space (base color space)"); + goto err2; + } + obj1.free(); + if (!arr->get(2, &obj1)->isInt()) { + error(-1, "Bad Indexed color space (hival)"); + delete baseA; + goto err2; + } + indexHighA = obj1.getInt(); + if (indexHighA < 0 || indexHighA > 255) { + // the PDF spec requires indexHigh to be in [0,255] -- allowing + // values larger than 255 creates a security hole: if nComps * + // indexHigh is greater than 2^31, the loop below may overwrite + // past the end of the array + error(-1, "Bad Indexed color space (invalid indexHigh value)"); + delete baseA; + goto err2; + } + obj1.free(); + cs = new GfxIndexedColorSpace(baseA, indexHighA); + arr->get(3, &obj1); + n = baseA->getNComps(); + if (obj1.isStream()) { + obj1.streamReset(); + for (i = 0; i <= indexHighA; ++i) { + for (j = 0; j < n; ++j) { + if ((x = obj1.streamGetChar()) == EOF) { + error(-1, "Bad Indexed color space (lookup table stream too short)"); + goto err3; + } + cs->lookup[i*n + j] = (Guchar)x; + } + } + obj1.streamClose(); + } else if (obj1.isString()) { + if (obj1.getString()->getLength() < (indexHighA + 1) * n) { + error(-1, "Bad Indexed color space (lookup table string too short)"); + goto err3; + } + s = obj1.getString()->getCString(); + for (i = 0; i <= indexHighA; ++i) { + for (j = 0; j < n; ++j) { + cs->lookup[i*n + j] = (Guchar)*s++; + } + } + } else { + error(-1, "Bad Indexed color space (lookup table)"); + goto err3; + } + obj1.free(); + return cs; + + err3: + delete cs; + err2: + obj1.free(); + err1: + return NULL; +} + +GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color, + GfxColor *baseColor) { + Guchar *p; + double low[gfxColorMaxComps], range[gfxColorMaxComps]; + int n, i; + + n = base->getNComps(); + base->getDefaultRanges(low, range, indexHigh); + p = &lookup[(int)(colToDbl(color->c[0]) + 0.5) * n]; + for (i = 0; i < n; ++i) { + baseColor->c[i] = dblToCol(low[i] + (p[i] / 255.0) * range[i]); + } + return baseColor; +} + +void GfxIndexedColorSpace::getGray(GfxColor *color, GfxGray *gray) { + GfxColor color2; + + base->getGray(mapColorToBase(color, &color2), gray); +} + +void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + GfxColor color2; + + base->getRGB(mapColorToBase(color, &color2), rgb); +} + +void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + GfxColor color2; + + base->getCMYK(mapColorToBase(color, &color2), cmyk); +} + +void GfxIndexedColorSpace::getDefaultColor(GfxColor *color) { + color->c[0] = 0; +} + +void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow, + double *decodeRange, + int maxImgPixel) { + decodeLow[0] = 0; + decodeRange[0] = maxImgPixel; +} + +//------------------------------------------------------------------------ +// GfxSeparationColorSpace +//------------------------------------------------------------------------ + +GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA, + GfxColorSpace *altA, + Function *funcA) { + name = nameA; + alt = altA; + func = funcA; + nonMarking = !name->cmp("None"); +} + +GfxSeparationColorSpace::~GfxSeparationColorSpace() { + delete name; + delete alt; + delete func; +} + +GfxColorSpace *GfxSeparationColorSpace::copy() { + return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy()); +} + +//~ handle the 'All' and 'None' colorants +GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) { + GfxSeparationColorSpace *cs; + GString *nameA; + GfxColorSpace *altA; + Function *funcA; + Object obj1; + + if (arr->getLength() != 4) { + error(-1, "Bad Separation color space"); + goto err1; + } + if (!arr->get(1, &obj1)->isName()) { + error(-1, "Bad Separation color space (name)"); + goto err2; + } + nameA = new GString(obj1.getName()); + obj1.free(); + arr->get(2, &obj1); + if (!(altA = GfxColorSpace::parse(&obj1))) { + error(-1, "Bad Separation color space (alternate color space)"); + goto err3; + } + obj1.free(); + arr->get(3, &obj1); + if (!(funcA = Function::parse(&obj1))) { + goto err4; + } + obj1.free(); + cs = new GfxSeparationColorSpace(nameA, altA, funcA); + return cs; + + err4: + delete altA; + err3: + delete nameA; + err2: + obj1.free(); + err1: + return NULL; +} + +void GfxSeparationColorSpace::getGray(GfxColor *color, GfxGray *gray) { + double x; + double c[gfxColorMaxComps]; + GfxColor color2; + int i; + + x = colToDbl(color->c[0]); + func->transform(&x, c); + for (i = 0; i < alt->getNComps(); ++i) { + color2.c[i] = dblToCol(c[i]); + } + alt->getGray(&color2, gray); +} + +void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + double x; + double c[gfxColorMaxComps]; + GfxColor color2; + int i; + + x = colToDbl(color->c[0]); + func->transform(&x, c); + for (i = 0; i < alt->getNComps(); ++i) { + color2.c[i] = dblToCol(c[i]); + } + alt->getRGB(&color2, rgb); +} + +void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + double x; + double c[gfxColorMaxComps]; + GfxColor color2; + int i; + + x = colToDbl(color->c[0]); + func->transform(&x, c); + for (i = 0; i < alt->getNComps(); ++i) { + color2.c[i] = dblToCol(c[i]); + } + alt->getCMYK(&color2, cmyk); +} + +void GfxSeparationColorSpace::getDefaultColor(GfxColor *color) { + color->c[0] = gfxColorComp1; +} + +//------------------------------------------------------------------------ +// GfxDeviceNColorSpace +//------------------------------------------------------------------------ + +GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA, + GfxColorSpace *altA, + Function *funcA) { + nComps = nCompsA; + alt = altA; + func = funcA; + nonMarking = gFalse; +} + +GfxDeviceNColorSpace::~GfxDeviceNColorSpace() { + int i; + + for (i = 0; i < nComps; ++i) { + delete names[i]; + } + delete alt; + delete func; +} + +GfxColorSpace *GfxDeviceNColorSpace::copy() { + GfxDeviceNColorSpace *cs; + int i; + + cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy()); + for (i = 0; i < nComps; ++i) { + cs->names[i] = names[i]->copy(); + } + cs->nonMarking = nonMarking; + return cs; +} + +//~ handle the 'None' colorant +GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) { + GfxDeviceNColorSpace *cs; + int nCompsA; + GString *namesA[gfxColorMaxComps]; + GfxColorSpace *altA; + Function *funcA; + Object obj1, obj2; + int i; + + if (arr->getLength() != 4 && arr->getLength() != 5) { + error(-1, "Bad DeviceN color space"); + goto err1; + } + if (!arr->get(1, &obj1)->isArray()) { + error(-1, "Bad DeviceN color space (names)"); + goto err2; + } + nCompsA = obj1.arrayGetLength(); + if (nCompsA > gfxColorMaxComps) { + error(-1, "DeviceN color space with too many (%d > %d) components", + nCompsA, gfxColorMaxComps); + nCompsA = gfxColorMaxComps; + } + for (i = 0; i < nCompsA; ++i) { + if (!obj1.arrayGet(i, &obj2)->isName()) { + error(-1, "Bad DeviceN color space (names)"); + obj2.free(); + goto err2; + } + namesA[i] = new GString(obj2.getName()); + obj2.free(); + } + obj1.free(); + arr->get(2, &obj1); + if (!(altA = GfxColorSpace::parse(&obj1))) { + error(-1, "Bad DeviceN color space (alternate color space)"); + goto err3; + } + obj1.free(); + arr->get(3, &obj1); + if (!(funcA = Function::parse(&obj1))) { + goto err4; + } + obj1.free(); + cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA); + cs->nonMarking = gTrue; + for (i = 0; i < nCompsA; ++i) { + cs->names[i] = namesA[i]; + if (namesA[i]->cmp("None")) { + cs->nonMarking = gFalse; + } + } + return cs; + + err4: + delete altA; + err3: + for (i = 0; i < nCompsA; ++i) { + delete namesA[i]; + } + err2: + obj1.free(); + err1: + return NULL; +} + +void GfxDeviceNColorSpace::getGray(GfxColor *color, GfxGray *gray) { + double x[gfxColorMaxComps], c[gfxColorMaxComps]; + GfxColor color2; + int i; + + for (i = 0; i < nComps; ++i) { + x[i] = colToDbl(color->c[i]); + } + func->transform(x, c); + for (i = 0; i < alt->getNComps(); ++i) { + color2.c[i] = dblToCol(c[i]); + } + alt->getGray(&color2, gray); +} + +void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + double x[gfxColorMaxComps], c[gfxColorMaxComps]; + GfxColor color2; + int i; + + for (i = 0; i < nComps; ++i) { + x[i] = colToDbl(color->c[i]); + } + func->transform(x, c); + for (i = 0; i < alt->getNComps(); ++i) { + color2.c[i] = dblToCol(c[i]); + } + alt->getRGB(&color2, rgb); +} + +void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + double x[gfxColorMaxComps], c[gfxColorMaxComps]; + GfxColor color2; + int i; + + for (i = 0; i < nComps; ++i) { + x[i] = colToDbl(color->c[i]); + } + func->transform(x, c); + for (i = 0; i < alt->getNComps(); ++i) { + color2.c[i] = dblToCol(c[i]); + } + alt->getCMYK(&color2, cmyk); +} + +void GfxDeviceNColorSpace::getDefaultColor(GfxColor *color) { + int i; + + for (i = 0; i < nComps; ++i) { + color->c[i] = gfxColorComp1; + } +} + +//------------------------------------------------------------------------ +// GfxPatternColorSpace +//------------------------------------------------------------------------ + +GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) { + under = underA; +} + +GfxPatternColorSpace::~GfxPatternColorSpace() { + if (under) { + delete under; + } +} + +GfxColorSpace *GfxPatternColorSpace::copy() { + return new GfxPatternColorSpace(under ? under->copy() : + (GfxColorSpace *)NULL); +} + +GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) { + GfxPatternColorSpace *cs; + GfxColorSpace *underA; + Object obj1; + + if (arr->getLength() != 1 && arr->getLength() != 2) { + error(-1, "Bad Pattern color space"); + return NULL; + } + underA = NULL; + if (arr->getLength() == 2) { + arr->get(1, &obj1); + if (!(underA = GfxColorSpace::parse(&obj1))) { + error(-1, "Bad Pattern color space (underlying color space)"); + obj1.free(); + return NULL; + } + obj1.free(); + } + cs = new GfxPatternColorSpace(underA); + return cs; +} + +void GfxPatternColorSpace::getGray(GfxColor * /*color*/, GfxGray *gray) { + *gray = 0; +} + +void GfxPatternColorSpace::getRGB(GfxColor * /*color*/, GfxRGB *rgb) { + rgb->r = rgb->g = rgb->b = 0; +} + +void GfxPatternColorSpace::getCMYK(GfxColor * /*color*/, GfxCMYK *cmyk) { + cmyk->c = cmyk->m = cmyk->y = 0; + cmyk->k = 1; +} + +void GfxPatternColorSpace::getDefaultColor(GfxColor * /*color*/) { + // not used +} + +//------------------------------------------------------------------------ +// Pattern +//------------------------------------------------------------------------ + +GfxPattern::GfxPattern(int typeA) { + type = typeA; +} + +GfxPattern::~GfxPattern() { +} + +GfxPattern *GfxPattern::parse(Object *obj) { + GfxPattern *pattern; + Object obj1; + + if (obj->isDict()) { + obj->dictLookup("PatternType", &obj1); + } else if (obj->isStream()) { + obj->streamGetDict()->lookup("PatternType", &obj1); + } else { + return NULL; + } + pattern = NULL; + if (obj1.isInt() && obj1.getInt() == 1) { + pattern = GfxTilingPattern::parse(obj); + } else if (obj1.isInt() && obj1.getInt() == 2) { + pattern = GfxShadingPattern::parse(obj); + } + obj1.free(); + return pattern; +} + +//------------------------------------------------------------------------ +// GfxTilingPattern +//------------------------------------------------------------------------ + +GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) { + GfxTilingPattern *pat; + Dict *dict; + int paintTypeA, tilingTypeA; + double bboxA[4], matrixA[6]; + double xStepA, yStepA; + Object resDictA; + Object obj1, obj2; + int i; + + if (!patObj->isStream()) { + return NULL; + } + dict = patObj->streamGetDict(); + + if (dict->lookup("PaintType", &obj1)->isInt()) { + paintTypeA = obj1.getInt(); + } else { + paintTypeA = 1; + error(-1, "Invalid or missing PaintType in pattern"); + } + obj1.free(); + if (dict->lookup("TilingType", &obj1)->isInt()) { + tilingTypeA = obj1.getInt(); + } else { + tilingTypeA = 1; + error(-1, "Invalid or missing TilingType in pattern"); + } + obj1.free(); + bboxA[0] = bboxA[1] = 0; + bboxA[2] = bboxA[3] = 1; + if (dict->lookup("BBox", &obj1)->isArray() && + obj1.arrayGetLength() == 4) { + for (i = 0; i < 4; ++i) { + if (obj1.arrayGet(i, &obj2)->isNum()) { + bboxA[i] = obj2.getNum(); + } + obj2.free(); + } + } else { + error(-1, "Invalid or missing BBox in pattern"); + } + obj1.free(); + if (dict->lookup("XStep", &obj1)->isNum()) { + xStepA = obj1.getNum(); + } else { + xStepA = 1; + error(-1, "Invalid or missing XStep in pattern"); + } + obj1.free(); + if (dict->lookup("YStep", &obj1)->isNum()) { + yStepA = obj1.getNum(); + } else { + yStepA = 1; + error(-1, "Invalid or missing YStep in pattern"); + } + obj1.free(); + if (!dict->lookup("Resources", &resDictA)->isDict()) { + resDictA.free(); + resDictA.initNull(); + error(-1, "Invalid or missing Resources in pattern"); + } + matrixA[0] = 1; matrixA[1] = 0; + matrixA[2] = 0; matrixA[3] = 1; + matrixA[4] = 0; matrixA[5] = 0; + if (dict->lookup("Matrix", &obj1)->isArray() && + obj1.arrayGetLength() == 6) { + for (i = 0; i < 6; ++i) { + if (obj1.arrayGet(i, &obj2)->isNum()) { + matrixA[i] = obj2.getNum(); + } + obj2.free(); + } + } + obj1.free(); + + pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA, + &resDictA, matrixA, patObj); + resDictA.free(); + return pat; +} + +GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA, + double *bboxA, double xStepA, double yStepA, + Object *resDictA, double *matrixA, + Object *contentStreamA): + GfxPattern(1) +{ + int i; + + paintType = paintTypeA; + tilingType = tilingTypeA; + for (i = 0; i < 4; ++i) { + bbox[i] = bboxA[i]; + } + xStep = xStepA; + yStep = yStepA; + resDictA->copy(&resDict); + for (i = 0; i < 6; ++i) { + matrix[i] = matrixA[i]; + } + contentStreamA->copy(&contentStream); +} + +GfxTilingPattern::~GfxTilingPattern() { + resDict.free(); + contentStream.free(); +} + +GfxPattern *GfxTilingPattern::copy() { + return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep, + &resDict, matrix, &contentStream); +} + +//------------------------------------------------------------------------ +// GfxShadingPattern +//------------------------------------------------------------------------ + +GfxShadingPattern *GfxShadingPattern::parse(Object *patObj) { + Dict *dict; + GfxShading *shadingA; + double matrixA[6]; + Object obj1, obj2; + int i; + + if (!patObj->isDict()) { + return NULL; + } + dict = patObj->getDict(); + + dict->lookup("Shading", &obj1); + shadingA = GfxShading::parse(&obj1); + obj1.free(); + if (!shadingA) { + return NULL; + } + + matrixA[0] = 1; matrixA[1] = 0; + matrixA[2] = 0; matrixA[3] = 1; + matrixA[4] = 0; matrixA[5] = 0; + if (dict->lookup("Matrix", &obj1)->isArray() && + obj1.arrayGetLength() == 6) { + for (i = 0; i < 6; ++i) { + if (obj1.arrayGet(i, &obj2)->isNum()) { + matrixA[i] = obj2.getNum(); + } + obj2.free(); + } + } + obj1.free(); + + return new GfxShadingPattern(shadingA, matrixA); +} + +GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA): + GfxPattern(2) +{ + int i; + + shading = shadingA; + for (i = 0; i < 6; ++i) { + matrix[i] = matrixA[i]; + } +} + +GfxShadingPattern::~GfxShadingPattern() { + delete shading; +} + +GfxPattern *GfxShadingPattern::copy() { + return new GfxShadingPattern(shading->copy(), matrix); +} + +//------------------------------------------------------------------------ +// GfxShading +//------------------------------------------------------------------------ + +GfxShading::GfxShading(int typeA) { + type = typeA; + colorSpace = NULL; +} + +GfxShading::GfxShading(GfxShading *shading) { + int i; + + type = shading->type; + colorSpace = shading->colorSpace->copy(); + for (i = 0; i < gfxColorMaxComps; ++i) { + background.c[i] = shading->background.c[i]; + } + hasBackground = shading->hasBackground; + xMin = shading->xMin; + yMin = shading->yMin; + xMax = shading->xMax; + yMax = shading->yMax; + hasBBox = shading->hasBBox; +} + +GfxShading::~GfxShading() { + if (colorSpace) { + delete colorSpace; + } +} + +GfxShading *GfxShading::parse(Object *obj) { + GfxShading *shading; + Dict *dict; + int typeA; + Object obj1; + + if (obj->isDict()) { + dict = obj->getDict(); + } else if (obj->isStream()) { + dict = obj->streamGetDict(); + } else { + return NULL; + } + + if (!dict->lookup("ShadingType", &obj1)->isInt()) { + error(-1, "Invalid ShadingType in shading dictionary"); + obj1.free(); + return NULL; + } + typeA = obj1.getInt(); + obj1.free(); + + switch (typeA) { + case 1: + shading = GfxFunctionShading::parse(dict); + break; + case 2: + shading = GfxAxialShading::parse(dict); + break; + case 3: + shading = GfxRadialShading::parse(dict); + break; + case 4: + if (obj->isStream()) { + shading = GfxGouraudTriangleShading::parse(4, dict, obj->getStream()); + } else { + error(-1, "Invalid Type 4 shading object"); + goto err1; + } + break; + case 5: + if (obj->isStream()) { + shading = GfxGouraudTriangleShading::parse(5, dict, obj->getStream()); + } else { + error(-1, "Invalid Type 5 shading object"); + goto err1; + } + break; + case 6: + if (obj->isStream()) { + shading = GfxPatchMeshShading::parse(6, dict, obj->getStream()); + } else { + error(-1, "Invalid Type 6 shading object"); + goto err1; + } + break; + case 7: + if (obj->isStream()) { + shading = GfxPatchMeshShading::parse(7, dict, obj->getStream()); + } else { + error(-1, "Invalid Type 7 shading object"); + goto err1; + } + break; + default: + error(-1, "Unimplemented shading type %d", typeA); + goto err1; + } + + return shading; + + err1: + return NULL; +} + +GBool GfxShading::init(Dict *dict) { + Object obj1, obj2; + int i; + + dict->lookup("ColorSpace", &obj1); + if (!(colorSpace = GfxColorSpace::parse(&obj1))) { + error(-1, "Bad color space in shading dictionary"); + obj1.free(); + return gFalse; + } + obj1.free(); + + for (i = 0; i < gfxColorMaxComps; ++i) { + background.c[i] = 0; + } + hasBackground = gFalse; + if (dict->lookup("Background", &obj1)->isArray()) { + if (obj1.arrayGetLength() == colorSpace->getNComps()) { + hasBackground = gTrue; + for (i = 0; i < colorSpace->getNComps(); ++i) { + background.c[i] = dblToCol(obj1.arrayGet(i, &obj2)->getNum()); + obj2.free(); + } + } else { + error(-1, "Bad Background in shading dictionary"); + } + } + obj1.free(); + + xMin = yMin = xMax = yMax = 0; + hasBBox = gFalse; + if (dict->lookup("BBox", &obj1)->isArray()) { + if (obj1.arrayGetLength() == 4) { + hasBBox = gTrue; + xMin = obj1.arrayGet(0, &obj2)->getNum(); + obj2.free(); + yMin = obj1.arrayGet(1, &obj2)->getNum(); + obj2.free(); + xMax = obj1.arrayGet(2, &obj2)->getNum(); + obj2.free(); + yMax = obj1.arrayGet(3, &obj2)->getNum(); + obj2.free(); + } else { + error(-1, "Bad BBox in shading dictionary"); + } + } + obj1.free(); + + return gTrue; +} + +//------------------------------------------------------------------------ +// GfxFunctionShading +//------------------------------------------------------------------------ + +GfxFunctionShading::GfxFunctionShading(double x0A, double y0A, + double x1A, double y1A, + double *matrixA, + Function **funcsA, int nFuncsA): + GfxShading(1) +{ + int i; + + x0 = x0A; + y0 = y0A; + x1 = x1A; + y1 = y1A; + for (i = 0; i < 6; ++i) { + matrix[i] = matrixA[i]; + } + nFuncs = nFuncsA; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = funcsA[i]; + } +} + +GfxFunctionShading::GfxFunctionShading(GfxFunctionShading *shading): + GfxShading(shading) +{ + int i; + + x0 = shading->x0; + y0 = shading->y0; + x1 = shading->x1; + y1 = shading->y1; + for (i = 0; i < 6; ++i) { + matrix[i] = shading->matrix[i]; + } + nFuncs = shading->nFuncs; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = shading->funcs[i]->copy(); + } +} + +GfxFunctionShading::~GfxFunctionShading() { + int i; + + for (i = 0; i < nFuncs; ++i) { + delete funcs[i]; + } +} + +GfxFunctionShading *GfxFunctionShading::parse(Dict *dict) { + GfxFunctionShading *shading; + double x0A, y0A, x1A, y1A; + double matrixA[6]; + Function *funcsA[gfxColorMaxComps]; + int nFuncsA; + Object obj1, obj2; + int i; + + x0A = y0A = 0; + x1A = y1A = 1; + if (dict->lookup("Domain", &obj1)->isArray() && + obj1.arrayGetLength() == 4) { + x0A = obj1.arrayGet(0, &obj2)->getNum(); + obj2.free(); + x1A = obj1.arrayGet(1, &obj2)->getNum(); + obj2.free(); + y0A = obj1.arrayGet(2, &obj2)->getNum(); + obj2.free(); + y1A = obj1.arrayGet(3, &obj2)->getNum(); + obj2.free(); + } + obj1.free(); + + matrixA[0] = 1; matrixA[1] = 0; + matrixA[2] = 0; matrixA[3] = 1; + matrixA[4] = 0; matrixA[5] = 0; + if (dict->lookup("Matrix", &obj1)->isArray() && + obj1.arrayGetLength() == 6) { + matrixA[0] = obj1.arrayGet(0, &obj2)->getNum(); + obj2.free(); + matrixA[1] = obj1.arrayGet(1, &obj2)->getNum(); + obj2.free(); + matrixA[2] = obj1.arrayGet(2, &obj2)->getNum(); + obj2.free(); + matrixA[3] = obj1.arrayGet(3, &obj2)->getNum(); + obj2.free(); + matrixA[4] = obj1.arrayGet(4, &obj2)->getNum(); + obj2.free(); + matrixA[5] = obj1.arrayGet(5, &obj2)->getNum(); + obj2.free(); + } + obj1.free(); + + dict->lookup("Function", &obj1); + if (obj1.isArray()) { + nFuncsA = obj1.arrayGetLength(); + if (nFuncsA > gfxColorMaxComps) { + error(-1, "Invalid Function array in shading dictionary"); + goto err1; + } + for (i = 0; i < nFuncsA; ++i) { + obj1.arrayGet(i, &obj2); + if (!(funcsA[i] = Function::parse(&obj2))) { + goto err2; + } + obj2.free(); + } + } else { + nFuncsA = 1; + if (!(funcsA[0] = Function::parse(&obj1))) { + goto err1; + } + } + obj1.free(); + + shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA, + funcsA, nFuncsA); + if (!shading->init(dict)) { + delete shading; + return NULL; + } + return shading; + + err2: + obj2.free(); + err1: + obj1.free(); + return NULL; +} + +GfxShading *GfxFunctionShading::copy() { + return new GfxFunctionShading(this); +} + +void GfxFunctionShading::getColor(double x, double y, GfxColor *color) { + double in[2], out[gfxColorMaxComps]; + int i; + + // NB: there can be one function with n outputs or n functions with + // one output each (where n = number of color components) + for (i = 0; i < gfxColorMaxComps; ++i) { + out[i] = 0; + } + in[0] = x; + in[1] = y; + for (i = 0; i < nFuncs; ++i) { + funcs[i]->transform(in, &out[i]); + } + for (i = 0; i < gfxColorMaxComps; ++i) { + color->c[i] = dblToCol(out[i]); + } +} + +//------------------------------------------------------------------------ +// GfxAxialShading +//------------------------------------------------------------------------ + +GfxAxialShading::GfxAxialShading(double x0A, double y0A, + double x1A, double y1A, + double t0A, double t1A, + Function **funcsA, int nFuncsA, + GBool extend0A, GBool extend1A): + GfxShading(2) +{ + int i; + + x0 = x0A; + y0 = y0A; + x1 = x1A; + y1 = y1A; + t0 = t0A; + t1 = t1A; + nFuncs = nFuncsA; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = funcsA[i]; + } + extend0 = extend0A; + extend1 = extend1A; +} + +GfxAxialShading::GfxAxialShading(GfxAxialShading *shading): + GfxShading(shading) +{ + int i; + + x0 = shading->x0; + y0 = shading->y0; + x1 = shading->x1; + y1 = shading->y1; + t0 = shading->t0; + y1 = shading->t1; + nFuncs = shading->nFuncs; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = shading->funcs[i]->copy(); + } + extend0 = shading->extend0; + extend1 = shading->extend1; +} + +GfxAxialShading::~GfxAxialShading() { + int i; + + for (i = 0; i < nFuncs; ++i) { + delete funcs[i]; + } +} + +GfxAxialShading *GfxAxialShading::parse(Dict *dict) { + GfxAxialShading *shading; + double x0A, y0A, x1A, y1A; + double t0A, t1A; + Function *funcsA[gfxColorMaxComps]; + int nFuncsA; + GBool extend0A, extend1A; + Object obj1, obj2; + int i; + + x0A = y0A = x1A = y1A = 0; + if (dict->lookup("Coords", &obj1)->isArray() && + obj1.arrayGetLength() == 4) { + x0A = obj1.arrayGet(0, &obj2)->getNum(); + obj2.free(); + y0A = obj1.arrayGet(1, &obj2)->getNum(); + obj2.free(); + x1A = obj1.arrayGet(2, &obj2)->getNum(); + obj2.free(); + y1A = obj1.arrayGet(3, &obj2)->getNum(); + obj2.free(); + } else { + error(-1, "Missing or invalid Coords in shading dictionary"); + goto err1; + } + obj1.free(); + + t0A = 0; + t1A = 1; + if (dict->lookup("Domain", &obj1)->isArray() && + obj1.arrayGetLength() == 2) { + t0A = obj1.arrayGet(0, &obj2)->getNum(); + obj2.free(); + t1A = obj1.arrayGet(1, &obj2)->getNum(); + obj2.free(); + } + obj1.free(); + + dict->lookup("Function", &obj1); + if (obj1.isArray()) { + nFuncsA = obj1.arrayGetLength(); + if (nFuncsA > gfxColorMaxComps) { + error(-1, "Invalid Function array in shading dictionary"); + goto err1; + } + for (i = 0; i < nFuncsA; ++i) { + obj1.arrayGet(i, &obj2); + if (!(funcsA[i] = Function::parse(&obj2))) { + obj1.free(); + obj2.free(); + goto err1; + } + obj2.free(); + } + } else { + nFuncsA = 1; + if (!(funcsA[0] = Function::parse(&obj1))) { + obj1.free(); + goto err1; + } + } + obj1.free(); + + extend0A = extend1A = gFalse; + if (dict->lookup("Extend", &obj1)->isArray() && + obj1.arrayGetLength() == 2) { + extend0A = obj1.arrayGet(0, &obj2)->getBool(); + obj2.free(); + extend1A = obj1.arrayGet(1, &obj2)->getBool(); + obj2.free(); + } + obj1.free(); + + shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A, + funcsA, nFuncsA, extend0A, extend1A); + if (!shading->init(dict)) { + delete shading; + return NULL; + } + return shading; + + err1: + return NULL; +} + +GfxShading *GfxAxialShading::copy() { + return new GfxAxialShading(this); +} + +void GfxAxialShading::getColor(double t, GfxColor *color) { + double out[gfxColorMaxComps]; + int i; + + // NB: there can be one function with n outputs or n functions with + // one output each (where n = number of color components) + for (i = 0; i < gfxColorMaxComps; ++i) { + out[i] = 0; + } + for (i = 0; i < nFuncs; ++i) { + funcs[i]->transform(&t, &out[i]); + } + for (i = 0; i < gfxColorMaxComps; ++i) { + color->c[i] = dblToCol(out[i]); + } +} + +//------------------------------------------------------------------------ +// GfxRadialShading +//------------------------------------------------------------------------ + +GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A, + double x1A, double y1A, double r1A, + double t0A, double t1A, + Function **funcsA, int nFuncsA, + GBool extend0A, GBool extend1A): + GfxShading(3) +{ + int i; + + x0 = x0A; + y0 = y0A; + r0 = r0A; + x1 = x1A; + y1 = y1A; + r1 = r1A; + t0 = t0A; + t1 = t1A; + nFuncs = nFuncsA; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = funcsA[i]; + } + extend0 = extend0A; + extend1 = extend1A; +} + +GfxRadialShading::GfxRadialShading(GfxRadialShading *shading): + GfxShading(shading) +{ + int i; + + x0 = shading->x0; + y0 = shading->y0; + r0 = shading->r0; + x1 = shading->x1; + y1 = shading->y1; + r1 = shading->r1; + t0 = shading->t0; + y1 = shading->t1; + nFuncs = shading->nFuncs; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = shading->funcs[i]->copy(); + } + extend0 = shading->extend0; + extend1 = shading->extend1; +} + +GfxRadialShading::~GfxRadialShading() { + int i; + + for (i = 0; i < nFuncs; ++i) { + delete funcs[i]; + } +} + +GfxRadialShading *GfxRadialShading::parse(Dict *dict) { + GfxRadialShading *shading; + double x0A, y0A, r0A, x1A, y1A, r1A; + double t0A, t1A; + Function *funcsA[gfxColorMaxComps]; + int nFuncsA; + GBool extend0A, extend1A; + Object obj1, obj2; + int i; + + x0A = y0A = r0A = x1A = y1A = r1A = 0; + if (dict->lookup("Coords", &obj1)->isArray() && + obj1.arrayGetLength() == 6) { + x0A = obj1.arrayGet(0, &obj2)->getNum(); + obj2.free(); + y0A = obj1.arrayGet(1, &obj2)->getNum(); + obj2.free(); + r0A = obj1.arrayGet(2, &obj2)->getNum(); + obj2.free(); + x1A = obj1.arrayGet(3, &obj2)->getNum(); + obj2.free(); + y1A = obj1.arrayGet(4, &obj2)->getNum(); + obj2.free(); + r1A = obj1.arrayGet(5, &obj2)->getNum(); + obj2.free(); + } else { + error(-1, "Missing or invalid Coords in shading dictionary"); + goto err1; + } + obj1.free(); + + t0A = 0; + t1A = 1; + if (dict->lookup("Domain", &obj1)->isArray() && + obj1.arrayGetLength() == 2) { + t0A = obj1.arrayGet(0, &obj2)->getNum(); + obj2.free(); + t1A = obj1.arrayGet(1, &obj2)->getNum(); + obj2.free(); + } + obj1.free(); + + dict->lookup("Function", &obj1); + if (obj1.isArray()) { + nFuncsA = obj1.arrayGetLength(); + if (nFuncsA > gfxColorMaxComps) { + error(-1, "Invalid Function array in shading dictionary"); + goto err1; + } + for (i = 0; i < nFuncsA; ++i) { + obj1.arrayGet(i, &obj2); + if (!(funcsA[i] = Function::parse(&obj2))) { + obj1.free(); + obj2.free(); + goto err1; + } + obj2.free(); + } + } else { + nFuncsA = 1; + if (!(funcsA[0] = Function::parse(&obj1))) { + obj1.free(); + goto err1; + } + } + obj1.free(); + + extend0A = extend1A = gFalse; + if (dict->lookup("Extend", &obj1)->isArray() && + obj1.arrayGetLength() == 2) { + extend0A = obj1.arrayGet(0, &obj2)->getBool(); + obj2.free(); + extend1A = obj1.arrayGet(1, &obj2)->getBool(); + obj2.free(); + } + obj1.free(); + + shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A, + funcsA, nFuncsA, extend0A, extend1A); + if (!shading->init(dict)) { + delete shading; + return NULL; + } + return shading; + + err1: + return NULL; +} + +GfxShading *GfxRadialShading::copy() { + return new GfxRadialShading(this); +} + +void GfxRadialShading::getColor(double t, GfxColor *color) { + double out[gfxColorMaxComps]; + int i; + + // NB: there can be one function with n outputs or n functions with + // one output each (where n = number of color components) + for (i = 0; i < gfxColorMaxComps; ++i) { + out[i] = 0; + } + for (i = 0; i < nFuncs; ++i) { + funcs[i]->transform(&t, &out[i]); + } + for (i = 0; i < gfxColorMaxComps; ++i) { + color->c[i] = dblToCol(out[i]); + } +} + +//------------------------------------------------------------------------ +// GfxShadingBitBuf +//------------------------------------------------------------------------ + +class GfxShadingBitBuf { +public: + + GfxShadingBitBuf(Stream *strA); + ~GfxShadingBitBuf(); + GBool getBits(int n, Guint *val); + void flushBits(); + +private: + + Stream *str; + int bitBuf; + int nBits; +}; + +GfxShadingBitBuf::GfxShadingBitBuf(Stream *strA) { + str = strA; + str->reset(); + bitBuf = 0; + nBits = 0; +} + +GfxShadingBitBuf::~GfxShadingBitBuf() { + str->close(); +} + +GBool GfxShadingBitBuf::getBits(int n, Guint *val) { + int x; + + if (nBits >= n) { + x = (bitBuf >> (nBits - n)) & ((1 << n) - 1); + nBits -= n; + } else { + x = 0; + if (nBits > 0) { + x = bitBuf & ((1 << nBits) - 1); + n -= nBits; + nBits = 0; + } + while (n > 0) { + if ((bitBuf = str->getChar()) == EOF) { + nBits = 0; + return gFalse; + } + if (n >= 8) { + x = (x << 8) | bitBuf; + n -= 8; + } else { + x = (x << n) | (bitBuf >> (8 - n)); + nBits = 8 - n; + n = 0; + } + } + } + *val = x; + return gTrue; +} + +void GfxShadingBitBuf::flushBits() { + bitBuf = 0; + nBits = 0; +} + +//------------------------------------------------------------------------ +// GfxGouraudTriangleShading +//------------------------------------------------------------------------ + +GfxGouraudTriangleShading::GfxGouraudTriangleShading( + int typeA, + GfxGouraudVertex *verticesA, int nVerticesA, + int (*trianglesA)[3], int nTrianglesA, + Function **funcsA, int nFuncsA): + GfxShading(typeA) +{ + int i; + + vertices = verticesA; + nVertices = nVerticesA; + triangles = trianglesA; + nTriangles = nTrianglesA; + nFuncs = nFuncsA; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = funcsA[i]; + } +} + +GfxGouraudTriangleShading::GfxGouraudTriangleShading( + GfxGouraudTriangleShading *shading): + GfxShading(shading) +{ + int i; + + nVertices = shading->nVertices; + vertices = (GfxGouraudVertex *)gmallocn(nVertices, sizeof(GfxGouraudVertex)); + memcpy(vertices, shading->vertices, nVertices * sizeof(GfxGouraudVertex)); + nTriangles = shading->nTriangles; + triangles = (int (*)[3])gmallocn(nTriangles * 3, sizeof(int)); + memcpy(triangles, shading->triangles, nTriangles * 3 * sizeof(int)); + nFuncs = shading->nFuncs; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = shading->funcs[i]->copy(); + } +} + +GfxGouraudTriangleShading::~GfxGouraudTriangleShading() { + int i; + + gfree(vertices); + gfree(triangles); + for (i = 0; i < nFuncs; ++i) { + delete funcs[i]; + } +} + +GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse(int typeA, + Dict *dict, + Stream *str) { + GfxGouraudTriangleShading *shading; + Function *funcsA[gfxColorMaxComps]; + int nFuncsA; + int coordBits, compBits, flagBits, vertsPerRow, nRows; + double xMin, xMax, yMin, yMax; + double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps]; + double xMul, yMul; + double cMul[gfxColorMaxComps]; + GfxGouraudVertex *verticesA; + int (*trianglesA)[3]; + int nComps, nVerticesA, nTrianglesA, vertSize, triSize; + Guint x, y, flag; + Guint c[gfxColorMaxComps]; + GfxShadingBitBuf *bitBuf; + Object obj1, obj2; + int i, j, k, state; + + if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) { + coordBits = obj1.getInt(); + } else { + error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary"); + goto err2; + } + obj1.free(); + if (dict->lookup("BitsPerComponent", &obj1)->isInt()) { + compBits = obj1.getInt(); + } else { + error(-1, "Missing or invalid BitsPerComponent in shading dictionary"); + goto err2; + } + obj1.free(); + flagBits = vertsPerRow = 0; // make gcc happy + if (typeA == 4) { + if (dict->lookup("BitsPerFlag", &obj1)->isInt()) { + flagBits = obj1.getInt(); + } else { + error(-1, "Missing or invalid BitsPerFlag in shading dictionary"); + goto err2; + } + obj1.free(); + } else { + if (dict->lookup("VerticesPerRow", &obj1)->isInt()) { + vertsPerRow = obj1.getInt(); + } else { + error(-1, "Missing or invalid VerticesPerRow in shading dictionary"); + goto err2; + } + obj1.free(); + } + if (dict->lookup("Decode", &obj1)->isArray() && + obj1.arrayGetLength() >= 6) { + xMin = obj1.arrayGet(0, &obj2)->getNum(); + obj2.free(); + xMax = obj1.arrayGet(1, &obj2)->getNum(); + obj2.free(); + xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1); + yMin = obj1.arrayGet(2, &obj2)->getNum(); + obj2.free(); + yMax = obj1.arrayGet(3, &obj2)->getNum(); + obj2.free(); + yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1); + for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) { + cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum(); + obj2.free(); + cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum(); + obj2.free(); + cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1); + } + nComps = i; + } else { + error(-1, "Missing or invalid Decode array in shading dictionary"); + goto err2; + } + obj1.free(); + + if (!dict->lookup("Function", &obj1)->isNull()) { + if (obj1.isArray()) { + nFuncsA = obj1.arrayGetLength(); + if (nFuncsA > gfxColorMaxComps) { + error(-1, "Invalid Function array in shading dictionary"); + goto err1; + } + for (i = 0; i < nFuncsA; ++i) { + obj1.arrayGet(i, &obj2); + if (!(funcsA[i] = Function::parse(&obj2))) { + obj1.free(); + obj2.free(); + goto err1; + } + obj2.free(); + } + } else { + nFuncsA = 1; + if (!(funcsA[0] = Function::parse(&obj1))) { + obj1.free(); + goto err1; + } + } + } else { + nFuncsA = 0; + } + obj1.free(); + + nVerticesA = nTrianglesA = 0; + verticesA = NULL; + trianglesA = NULL; + vertSize = triSize = 0; + state = 0; + flag = 0; // make gcc happy + bitBuf = new GfxShadingBitBuf(str); + while (1) { + if (typeA == 4) { + if (!bitBuf->getBits(flagBits, &flag)) { + break; + } + } + if (!bitBuf->getBits(coordBits, &x) || + !bitBuf->getBits(coordBits, &y)) { + break; + } + for (i = 0; i < nComps; ++i) { + if (!bitBuf->getBits(compBits, &c[i])) { + break; + } + } + if (i < nComps) { + break; + } + if (nVerticesA == vertSize) { + vertSize = (vertSize == 0) ? 16 : 2 * vertSize; + verticesA = (GfxGouraudVertex *) + greallocn(verticesA, vertSize, sizeof(GfxGouraudVertex)); + } + verticesA[nVerticesA].x = xMin + xMul * (double)x; + verticesA[nVerticesA].y = yMin + yMul * (double)y; + for (i = 0; i < nComps; ++i) { + verticesA[nVerticesA].color.c[i] = + dblToCol(cMin[i] + cMul[i] * (double)c[i]); + } + ++nVerticesA; + bitBuf->flushBits(); + if (typeA == 4) { + if (state == 0 || state == 1) { + ++state; + } else if (state == 2 || flag > 0) { + if (nTrianglesA == triSize) { + triSize = (triSize == 0) ? 16 : 2 * triSize; + trianglesA = (int (*)[3]) + greallocn(trianglesA, triSize * 3, sizeof(int)); + } + if (state == 2) { + trianglesA[nTrianglesA][0] = nVerticesA - 3; + trianglesA[nTrianglesA][1] = nVerticesA - 2; + trianglesA[nTrianglesA][2] = nVerticesA - 1; + ++state; + } else if (flag == 1) { + trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][1]; + trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2]; + trianglesA[nTrianglesA][2] = nVerticesA - 1; + } else { // flag == 2 + trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][0]; + trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2]; + trianglesA[nTrianglesA][2] = nVerticesA - 1; + } + ++nTrianglesA; + } else { // state == 3 && flag == 0 + state = 1; + } + } + } + delete bitBuf; + if (typeA == 5) { + nRows = nVerticesA / vertsPerRow; + nTrianglesA = (nRows - 1) * 2 * (vertsPerRow - 1); + trianglesA = (int (*)[3])gmallocn(nTrianglesA * 3, sizeof(int)); + k = 0; + for (i = 0; i < nRows - 1; ++i) { + for (j = 0; j < vertsPerRow - 1; ++j) { + trianglesA[k][0] = i * vertsPerRow + j; + trianglesA[k][1] = i * vertsPerRow + j+1; + trianglesA[k][2] = (i+1) * vertsPerRow + j; + ++k; + trianglesA[k][0] = i * vertsPerRow + j+1; + trianglesA[k][1] = (i+1) * vertsPerRow + j; + trianglesA[k][2] = (i+1) * vertsPerRow + j+1; + ++k; + } + } + } + + shading = new GfxGouraudTriangleShading(typeA, verticesA, nVerticesA, + trianglesA, nTrianglesA, + funcsA, nFuncsA); + if (!shading->init(dict)) { + delete shading; + return NULL; + } + return shading; + + err2: + obj1.free(); + err1: + return NULL; +} + +GfxShading *GfxGouraudTriangleShading::copy() { + return new GfxGouraudTriangleShading(this); +} + +void GfxGouraudTriangleShading::getTriangle( + int i, + double *x0, double *y0, GfxColor *color0, + double *x1, double *y1, GfxColor *color1, + double *x2, double *y2, GfxColor *color2) { + double in; + double out[gfxColorMaxComps]; + int v, j; + + v = triangles[i][0]; + *x0 = vertices[v].x; + *y0 = vertices[v].y; + if (nFuncs > 0) { + in = colToDbl(vertices[v].color.c[0]); + for (j = 0; j < nFuncs; ++j) { + funcs[j]->transform(&in, &out[j]); + } + for (j = 0; j < gfxColorMaxComps; ++j) { + color0->c[j] = dblToCol(out[j]); + } + } else { + *color0 = vertices[v].color; + } + v = triangles[i][1]; + *x1 = vertices[v].x; + *y1 = vertices[v].y; + if (nFuncs > 0) { + in = colToDbl(vertices[v].color.c[0]); + for (j = 0; j < nFuncs; ++j) { + funcs[j]->transform(&in, &out[j]); + } + for (j = 0; j < gfxColorMaxComps; ++j) { + color1->c[j] = dblToCol(out[j]); + } + } else { + *color1 = vertices[v].color; + } + v = triangles[i][2]; + *x2 = vertices[v].x; + *y2 = vertices[v].y; + if (nFuncs > 0) { + in = colToDbl(vertices[v].color.c[0]); + for (j = 0; j < nFuncs; ++j) { + funcs[j]->transform(&in, &out[j]); + } + for (j = 0; j < gfxColorMaxComps; ++j) { + color2->c[j] = dblToCol(out[j]); + } + } else { + *color2 = vertices[v].color; + } +} + +//------------------------------------------------------------------------ +// GfxPatchMeshShading +//------------------------------------------------------------------------ + +GfxPatchMeshShading::GfxPatchMeshShading(int typeA, + GfxPatch *patchesA, int nPatchesA, + Function **funcsA, int nFuncsA): + GfxShading(typeA) +{ + int i; + + patches = patchesA; + nPatches = nPatchesA; + nFuncs = nFuncsA; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = funcsA[i]; + } +} + +GfxPatchMeshShading::GfxPatchMeshShading(GfxPatchMeshShading *shading): + GfxShading(shading) +{ + int i; + + nPatches = shading->nPatches; + patches = (GfxPatch *)gmallocn(nPatches, sizeof(GfxPatch)); + memcpy(patches, shading->patches, nPatches * sizeof(GfxPatch)); + nFuncs = shading->nFuncs; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = shading->funcs[i]->copy(); + } +} + +GfxPatchMeshShading::~GfxPatchMeshShading() { + int i; + + gfree(patches); + for (i = 0; i < nFuncs; ++i) { + delete funcs[i]; + } +} + +GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict, + Stream *str) { + GfxPatchMeshShading *shading; + Function *funcsA[gfxColorMaxComps]; + int nFuncsA; + int coordBits, compBits, flagBits; + double xMin, xMax, yMin, yMax; + double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps]; + double xMul, yMul; + double cMul[gfxColorMaxComps]; + GfxPatch *patchesA, *p; + int nComps, nPatchesA, patchesSize, nPts, nColors; + Guint flag; + double x[16], y[16]; + Guint xi, yi; + GfxColorComp c[4][gfxColorMaxComps]; + Guint ci[4]; + GfxShadingBitBuf *bitBuf; + Object obj1, obj2; + int i, j; + + if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) { + coordBits = obj1.getInt(); + } else { + error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary"); + goto err2; + } + obj1.free(); + if (dict->lookup("BitsPerComponent", &obj1)->isInt()) { + compBits = obj1.getInt(); + } else { + error(-1, "Missing or invalid BitsPerComponent in shading dictionary"); + goto err2; + } + obj1.free(); + if (dict->lookup("BitsPerFlag", &obj1)->isInt()) { + flagBits = obj1.getInt(); + } else { + error(-1, "Missing or invalid BitsPerFlag in shading dictionary"); + goto err2; + } + obj1.free(); + if (dict->lookup("Decode", &obj1)->isArray() && + obj1.arrayGetLength() >= 6) { + xMin = obj1.arrayGet(0, &obj2)->getNum(); + obj2.free(); + xMax = obj1.arrayGet(1, &obj2)->getNum(); + obj2.free(); + xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1); + yMin = obj1.arrayGet(2, &obj2)->getNum(); + obj2.free(); + yMax = obj1.arrayGet(3, &obj2)->getNum(); + obj2.free(); + yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1); + for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) { + cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum(); + obj2.free(); + cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum(); + obj2.free(); + cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1); + } + nComps = i; + } else { + error(-1, "Missing or invalid Decode array in shading dictionary"); + goto err2; + } + obj1.free(); + + if (!dict->lookup("Function", &obj1)->isNull()) { + if (obj1.isArray()) { + nFuncsA = obj1.arrayGetLength(); + if (nFuncsA > gfxColorMaxComps) { + error(-1, "Invalid Function array in shading dictionary"); + goto err1; + } + for (i = 0; i < nFuncsA; ++i) { + obj1.arrayGet(i, &obj2); + if (!(funcsA[i] = Function::parse(&obj2))) { + obj1.free(); + obj2.free(); + goto err1; + } + obj2.free(); + } + } else { + nFuncsA = 1; + if (!(funcsA[0] = Function::parse(&obj1))) { + obj1.free(); + goto err1; + } + } + } else { + nFuncsA = 0; + } + obj1.free(); + + nPatchesA = 0; + patchesA = NULL; + patchesSize = 0; + bitBuf = new GfxShadingBitBuf(str); + while (1) { + if (!bitBuf->getBits(flagBits, &flag)) { + break; + } + if (typeA == 6) { + switch (flag) { + case 0: nPts = 12; nColors = 4; break; + case 1: + case 2: + case 3: + default: nPts = 8; nColors = 2; break; + } + } else { + switch (flag) { + case 0: nPts = 16; nColors = 4; break; + case 1: + case 2: + case 3: + default: nPts = 12; nColors = 2; break; + } + } + for (i = 0; i < nPts; ++i) { + if (!bitBuf->getBits(coordBits, &xi) || + !bitBuf->getBits(coordBits, &yi)) { + break; + } + x[i] = xMin + xMul * (double)xi; + y[i] = yMin + yMul * (double)yi; + } + if (i < nPts) { + break; + } + for (i = 0; i < nColors; ++i) { + for (j = 0; j < nComps; ++j) { + if (!bitBuf->getBits(compBits, &ci[j])) { + break; + } + c[i][j] = dblToCol(cMin[j] + cMul[j] * (double)ci[j]); + } + if (j < nComps) { + break; + } + } + if (i < nColors) { + break; + } + if (nPatchesA == patchesSize) { + patchesSize = (patchesSize == 0) ? 16 : 2 * patchesSize; + patchesA = (GfxPatch *)greallocn(patchesA, + patchesSize, sizeof(GfxPatch)); + } + p = &patchesA[nPatchesA]; + if (typeA == 6) { + switch (flag) { + case 0: + p->x[0][0] = x[0]; + p->y[0][0] = y[0]; + p->x[0][1] = x[1]; + p->y[0][1] = y[1]; + p->x[0][2] = x[2]; + p->y[0][2] = y[2]; + p->x[0][3] = x[3]; + p->y[0][3] = y[3]; + p->x[1][3] = x[4]; + p->y[1][3] = y[4]; + p->x[2][3] = x[5]; + p->y[2][3] = y[5]; + p->x[3][3] = x[6]; + p->y[3][3] = y[6]; + p->x[3][2] = x[7]; + p->y[3][2] = y[7]; + p->x[3][1] = x[8]; + p->y[3][1] = y[8]; + p->x[3][0] = x[9]; + p->y[3][0] = y[9]; + p->x[2][0] = x[10]; + p->y[2][0] = y[10]; + p->x[1][0] = x[11]; + p->y[1][0] = y[11]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = c[0][j]; + p->color[0][1].c[j] = c[1][j]; + p->color[1][1].c[j] = c[2][j]; + p->color[1][0].c[j] = c[3][j]; + } + break; + case 1: + p->x[0][0] = patchesA[nPatchesA-1].x[0][3]; + p->y[0][0] = patchesA[nPatchesA-1].y[0][3]; + p->x[0][1] = patchesA[nPatchesA-1].x[1][3]; + p->y[0][1] = patchesA[nPatchesA-1].y[1][3]; + p->x[0][2] = patchesA[nPatchesA-1].x[2][3]; + p->y[0][2] = patchesA[nPatchesA-1].y[2][3]; + p->x[0][3] = patchesA[nPatchesA-1].x[3][3]; + p->y[0][3] = patchesA[nPatchesA-1].y[3][3]; + p->x[1][3] = x[0]; + p->y[1][3] = y[0]; + p->x[2][3] = x[1]; + p->y[2][3] = y[1]; + p->x[3][3] = x[2]; + p->y[3][3] = y[2]; + p->x[3][2] = x[3]; + p->y[3][2] = y[3]; + p->x[3][1] = x[4]; + p->y[3][1] = y[4]; + p->x[3][0] = x[5]; + p->y[3][0] = y[5]; + p->x[2][0] = x[6]; + p->y[2][0] = y[6]; + p->x[1][0] = x[7]; + p->y[1][0] = y[7]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j]; + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; + p->color[1][1].c[j] = c[0][j]; + p->color[1][0].c[j] = c[1][j]; + } + break; + case 2: + p->x[0][0] = patchesA[nPatchesA-1].x[3][3]; + p->y[0][0] = patchesA[nPatchesA-1].y[3][3]; + p->x[0][1] = patchesA[nPatchesA-1].x[3][2]; + p->y[0][1] = patchesA[nPatchesA-1].y[3][2]; + p->x[0][2] = patchesA[nPatchesA-1].x[3][1]; + p->y[0][2] = patchesA[nPatchesA-1].y[3][1]; + p->x[0][3] = patchesA[nPatchesA-1].x[3][0]; + p->y[0][3] = patchesA[nPatchesA-1].y[3][0]; + p->x[1][3] = x[0]; + p->y[1][3] = y[0]; + p->x[2][3] = x[1]; + p->y[2][3] = y[1]; + p->x[3][3] = x[2]; + p->y[3][3] = y[2]; + p->x[3][2] = x[3]; + p->y[3][2] = y[3]; + p->x[3][1] = x[4]; + p->y[3][1] = y[4]; + p->x[3][0] = x[5]; + p->y[3][0] = y[5]; + p->x[2][0] = x[6]; + p->y[2][0] = y[6]; + p->x[1][0] = x[7]; + p->y[1][0] = y[7]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; + p->color[1][1].c[j] = c[0][j]; + p->color[1][0].c[j] = c[1][j]; + } + break; + case 3: + p->x[0][0] = patchesA[nPatchesA-1].x[3][0]; + p->y[0][0] = patchesA[nPatchesA-1].y[3][0]; + p->x[0][1] = patchesA[nPatchesA-1].x[2][0]; + p->y[0][1] = patchesA[nPatchesA-1].y[2][0]; + p->x[0][2] = patchesA[nPatchesA-1].x[1][0]; + p->y[0][2] = patchesA[nPatchesA-1].y[1][0]; + p->x[0][3] = patchesA[nPatchesA-1].x[0][0]; + p->y[0][3] = patchesA[nPatchesA-1].y[0][0]; + p->x[1][3] = x[0]; + p->y[1][3] = y[0]; + p->x[2][3] = x[1]; + p->y[2][3] = y[1]; + p->x[3][3] = x[2]; + p->y[3][3] = y[2]; + p->x[3][2] = x[3]; + p->y[3][2] = y[3]; + p->x[3][1] = x[4]; + p->y[3][1] = y[4]; + p->x[3][0] = x[5]; + p->y[3][0] = y[5]; + p->x[2][0] = x[6]; + p->y[2][0] = y[6]; + p->x[1][0] = x[7]; + p->y[1][0] = y[7]; + for (j = 0; j < nComps; ++j) { + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j]; + p->color[1][1].c[j] = c[0][j]; + p->color[1][0].c[j] = c[1][j]; + } + break; + } + } else { + switch (flag) { + case 0: + p->x[0][0] = x[0]; + p->y[0][0] = y[0]; + p->x[0][1] = x[1]; + p->y[0][1] = y[1]; + p->x[0][2] = x[2]; + p->y[0][2] = y[2]; + p->x[0][3] = x[3]; + p->y[0][3] = y[3]; + p->x[1][3] = x[4]; + p->y[1][3] = y[4]; + p->x[2][3] = x[5]; + p->y[2][3] = y[5]; + p->x[3][3] = x[6]; + p->y[3][3] = y[6]; + p->x[3][2] = x[7]; + p->y[3][2] = y[7]; + p->x[3][1] = x[8]; + p->y[3][1] = y[8]; + p->x[3][0] = x[9]; + p->y[3][0] = y[9]; + p->x[2][0] = x[10]; + p->y[2][0] = y[10]; + p->x[1][0] = x[11]; + p->y[1][0] = y[11]; + p->x[1][1] = x[12]; + p->y[1][1] = y[12]; + p->x[1][2] = x[13]; + p->y[1][2] = y[13]; + p->x[2][2] = x[14]; + p->y[2][2] = y[14]; + p->x[2][1] = x[15]; + p->y[2][1] = y[15]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = c[0][j]; + p->color[0][1].c[j] = c[1][j]; + p->color[1][1].c[j] = c[2][j]; + p->color[1][0].c[j] = c[3][j]; + } + break; + case 1: + p->x[0][0] = patchesA[nPatchesA-1].x[0][3]; + p->y[0][0] = patchesA[nPatchesA-1].y[0][3]; + p->x[0][1] = patchesA[nPatchesA-1].x[1][3]; + p->y[0][1] = patchesA[nPatchesA-1].y[1][3]; + p->x[0][2] = patchesA[nPatchesA-1].x[2][3]; + p->y[0][2] = patchesA[nPatchesA-1].y[2][3]; + p->x[0][3] = patchesA[nPatchesA-1].x[3][3]; + p->y[0][3] = patchesA[nPatchesA-1].y[3][3]; + p->x[1][3] = x[0]; + p->y[1][3] = y[0]; + p->x[2][3] = x[1]; + p->y[2][3] = y[1]; + p->x[3][3] = x[2]; + p->y[3][3] = y[2]; + p->x[3][2] = x[3]; + p->y[3][2] = y[3]; + p->x[3][1] = x[4]; + p->y[3][1] = y[4]; + p->x[3][0] = x[5]; + p->y[3][0] = y[5]; + p->x[2][0] = x[6]; + p->y[2][0] = y[6]; + p->x[1][0] = x[7]; + p->y[1][0] = y[7]; + p->x[1][1] = x[8]; + p->y[1][1] = y[8]; + p->x[1][2] = x[9]; + p->y[1][2] = y[9]; + p->x[2][2] = x[10]; + p->y[2][2] = y[10]; + p->x[2][1] = x[11]; + p->y[2][1] = y[11]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j]; + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; + p->color[1][1].c[j] = c[0][j]; + p->color[1][0].c[j] = c[1][j]; + } + break; + case 2: + p->x[0][0] = patchesA[nPatchesA-1].x[3][3]; + p->y[0][0] = patchesA[nPatchesA-1].y[3][3]; + p->x[0][1] = patchesA[nPatchesA-1].x[3][2]; + p->y[0][1] = patchesA[nPatchesA-1].y[3][2]; + p->x[0][2] = patchesA[nPatchesA-1].x[3][1]; + p->y[0][2] = patchesA[nPatchesA-1].y[3][1]; + p->x[0][3] = patchesA[nPatchesA-1].x[3][0]; + p->y[0][3] = patchesA[nPatchesA-1].y[3][0]; + p->x[1][3] = x[0]; + p->y[1][3] = y[0]; + p->x[2][3] = x[1]; + p->y[2][3] = y[1]; + p->x[3][3] = x[2]; + p->y[3][3] = y[2]; + p->x[3][2] = x[3]; + p->y[3][2] = y[3]; + p->x[3][1] = x[4]; + p->y[3][1] = y[4]; + p->x[3][0] = x[5]; + p->y[3][0] = y[5]; + p->x[2][0] = x[6]; + p->y[2][0] = y[6]; + p->x[1][0] = x[7]; + p->y[1][0] = y[7]; + p->x[1][1] = x[8]; + p->y[1][1] = y[8]; + p->x[1][2] = x[9]; + p->y[1][2] = y[9]; + p->x[2][2] = x[10]; + p->y[2][2] = y[10]; + p->x[2][1] = x[11]; + p->y[2][1] = y[11]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; + p->color[1][1].c[j] = c[0][j]; + p->color[1][0].c[j] = c[1][j]; + } + break; + case 3: + p->x[0][0] = patchesA[nPatchesA-1].x[3][0]; + p->y[0][0] = patchesA[nPatchesA-1].y[3][0]; + p->x[0][1] = patchesA[nPatchesA-1].x[2][0]; + p->y[0][1] = patchesA[nPatchesA-1].y[2][0]; + p->x[0][2] = patchesA[nPatchesA-1].x[1][0]; + p->y[0][2] = patchesA[nPatchesA-1].y[1][0]; + p->x[0][3] = patchesA[nPatchesA-1].x[0][0]; + p->y[0][3] = patchesA[nPatchesA-1].y[0][0]; + p->x[1][3] = x[0]; + p->y[1][3] = y[0]; + p->x[2][3] = x[1]; + p->y[2][3] = y[1]; + p->x[3][3] = x[2]; + p->y[3][3] = y[2]; + p->x[3][2] = x[3]; + p->y[3][2] = y[3]; + p->x[3][1] = x[4]; + p->y[3][1] = y[4]; + p->x[3][0] = x[5]; + p->y[3][0] = y[5]; + p->x[2][0] = x[6]; + p->y[2][0] = y[6]; + p->x[1][0] = x[7]; + p->y[1][0] = y[7]; + p->x[1][1] = x[8]; + p->y[1][1] = y[8]; + p->x[1][2] = x[9]; + p->y[1][2] = y[9]; + p->x[2][2] = x[10]; + p->y[2][2] = y[10]; + p->x[2][1] = x[11]; + p->y[2][1] = y[11]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j]; + p->color[1][1].c[j] = c[0][j]; + p->color[1][0].c[j] = c[1][j]; + } + break; + } + } + ++nPatchesA; + bitBuf->flushBits(); + } + delete bitBuf; + + if (typeA == 6) { + for (i = 0; i < nPatchesA; ++i) { + p = &patchesA[i]; + p->x[1][1] = (-4 * p->x[0][0] + +6 * (p->x[0][1] + p->x[1][0]) + -2 * (p->x[0][3] + p->x[3][0]) + +3 * (p->x[3][1] + p->x[1][3]) + - p->x[3][3]) / 9; + p->y[1][1] = (-4 * p->y[0][0] + +6 * (p->y[0][1] + p->y[1][0]) + -2 * (p->y[0][3] + p->y[3][0]) + +3 * (p->y[3][1] + p->y[1][3]) + - p->y[3][3]) / 9; + p->x[1][2] = (-4 * p->x[0][3] + +6 * (p->x[0][2] + p->x[1][3]) + -2 * (p->x[0][0] + p->x[3][3]) + +3 * (p->x[3][2] + p->x[1][0]) + - p->x[3][0]) / 9; + p->y[1][2] = (-4 * p->y[0][3] + +6 * (p->y[0][2] + p->y[1][3]) + -2 * (p->y[0][0] + p->y[3][3]) + +3 * (p->y[3][2] + p->y[1][0]) + - p->y[3][0]) / 9; + p->x[2][1] = (-4 * p->x[3][0] + +6 * (p->x[3][1] + p->x[2][0]) + -2 * (p->x[3][3] + p->x[0][0]) + +3 * (p->x[0][1] + p->x[2][3]) + - p->x[0][3]) / 9; + p->y[2][1] = (-4 * p->y[3][0] + +6 * (p->y[3][1] + p->y[2][0]) + -2 * (p->y[3][3] + p->y[0][0]) + +3 * (p->y[0][1] + p->y[2][3]) + - p->y[0][3]) / 9; + p->x[2][2] = (-4 * p->x[3][3] + +6 * (p->x[3][2] + p->x[2][3]) + -2 * (p->x[3][0] + p->x[0][3]) + +3 * (p->x[0][2] + p->x[2][0]) + - p->x[0][0]) / 9; + p->y[2][2] = (-4 * p->y[3][3] + +6 * (p->y[3][2] + p->y[2][3]) + -2 * (p->y[3][0] + p->y[0][3]) + +3 * (p->y[0][2] + p->y[2][0]) + - p->y[0][0]) / 9; + } + } + + shading = new GfxPatchMeshShading(typeA, patchesA, nPatchesA, + funcsA, nFuncsA); + if (!shading->init(dict)) { + delete shading; + return NULL; + } + return shading; + + err2: + obj1.free(); + err1: + return NULL; +} + +GfxShading *GfxPatchMeshShading::copy() { + return new GfxPatchMeshShading(this); +} + +//------------------------------------------------------------------------ +// GfxImageColorMap +//------------------------------------------------------------------------ + +GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode, + GfxColorSpace *colorSpaceA) { + GfxIndexedColorSpace *indexedCS; + GfxSeparationColorSpace *sepCS; + int maxPixel, indexHigh; + Guchar *lookup2; + Function *sepFunc; + Object obj; + double x[gfxColorMaxComps]; + double y[gfxColorMaxComps]; + int i, j, k; + + ok = gTrue; + + // bits per component and color space + bits = bitsA; + maxPixel = (1 << bits) - 1; + colorSpace = colorSpaceA; + + // initialize + for (k = 0; k < gfxColorMaxComps; ++k) { + lookup[k] = NULL; + } + + // get decode map + if (decode->isNull()) { + nComps = colorSpace->getNComps(); + colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel); + } else if (decode->isArray()) { + nComps = decode->arrayGetLength() / 2; + if (nComps != colorSpace->getNComps()) { + goto err1; + } + for (i = 0; i < nComps; ++i) { + decode->arrayGet(2*i, &obj); + if (!obj.isNum()) { + goto err2; + } + decodeLow[i] = obj.getNum(); + obj.free(); + decode->arrayGet(2*i+1, &obj); + if (!obj.isNum()) { + goto err2; + } + decodeRange[i] = obj.getNum() - decodeLow[i]; + obj.free(); + } + } else { + goto err1; + } + + // Construct a lookup table -- this stores pre-computed decoded + // values for each component, i.e., the result of applying the + // decode mapping to each possible image pixel component value. + // + // Optimization: for Indexed and Separation color spaces (which have + // only one component), we store color values in the lookup table + // rather than component values. + colorSpace2 = NULL; + nComps2 = 0; + if (colorSpace->getMode() == csIndexed) { + // Note that indexHigh may not be the same as maxPixel -- + // Distiller will remove unused palette entries, resulting in + // indexHigh < maxPixel. + indexedCS = (GfxIndexedColorSpace *)colorSpace; + colorSpace2 = indexedCS->getBase(); + indexHigh = indexedCS->getIndexHigh(); + nComps2 = colorSpace2->getNComps(); + lookup2 = indexedCS->getLookup(); + colorSpace2->getDefaultRanges(x, y, indexHigh); + for (k = 0; k < nComps2; ++k) { + lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1, + sizeof(GfxColorComp)); + for (i = 0; i <= maxPixel; ++i) { + j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5); + if (j < 0) { + j = 0; + } else if (j > indexHigh) { + j = indexHigh; + } + lookup[k][i] = + dblToCol(x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k]); + } + } + } else if (colorSpace->getMode() == csSeparation) { + sepCS = (GfxSeparationColorSpace *)colorSpace; + colorSpace2 = sepCS->getAlt(); + nComps2 = colorSpace2->getNComps(); + sepFunc = sepCS->getFunc(); + for (k = 0; k < nComps2; ++k) { + lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1, + sizeof(GfxColorComp)); + for (i = 0; i <= maxPixel; ++i) { + x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel; + sepFunc->transform(x, y); + lookup[k][i] = dblToCol(y[k]); + } + } + } else { + for (k = 0; k < nComps; ++k) { + lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1, + sizeof(GfxColorComp)); + for (i = 0; i <= maxPixel; ++i) { + lookup[k][i] = dblToCol(decodeLow[k] + + (i * decodeRange[k]) / maxPixel); + } + } + } + + return; + + err2: + obj.free(); + err1: + ok = gFalse; +} + +GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) { + int n, i, k; + + colorSpace = colorMap->colorSpace->copy(); + bits = colorMap->bits; + nComps = colorMap->nComps; + nComps2 = colorMap->nComps2; + colorSpace2 = NULL; + for (k = 0; k < gfxColorMaxComps; ++k) { + lookup[k] = NULL; + } + n = 1 << bits; + if (colorSpace->getMode() == csIndexed) { + colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase(); + for (k = 0; k < nComps2; ++k) { + lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp)); + memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp)); + } + } else if (colorSpace->getMode() == csSeparation) { + colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt(); + for (k = 0; k < nComps2; ++k) { + lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp)); + memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp)); + } + } else { + for (k = 0; k < nComps; ++k) { + lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp)); + memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp)); + } + } + for (i = 0; i < nComps; ++i) { + decodeLow[i] = colorMap->decodeLow[i]; + decodeRange[i] = colorMap->decodeRange[i]; + } + ok = gTrue; +} + +GfxImageColorMap::~GfxImageColorMap() { + int i; + + delete colorSpace; + for (i = 0; i < gfxColorMaxComps; ++i) { + gfree(lookup[i]); + } +} + +void GfxImageColorMap::getGray(Guchar *x, GfxGray *gray) { + GfxColor color; + int i; + + if (colorSpace2) { + for (i = 0; i < nComps2; ++i) { + color.c[i] = lookup[i][x[0]]; + } + colorSpace2->getGray(&color, gray); + } else { + for (i = 0; i < nComps; ++i) { + color.c[i] = lookup[i][x[i]]; + } + colorSpace->getGray(&color, gray); + } +} + +void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) { + GfxColor color; + int i; + + if (colorSpace2) { + for (i = 0; i < nComps2; ++i) { + color.c[i] = lookup[i][x[0]]; + } + colorSpace2->getRGB(&color, rgb); + } else { + for (i = 0; i < nComps; ++i) { + color.c[i] = lookup[i][x[i]]; + } + colorSpace->getRGB(&color, rgb); + } +} + +void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) { + GfxColor color; + int i; + + if (colorSpace2) { + for (i = 0; i < nComps2; ++i) { + color.c[i] = lookup[i][x[0]]; + } + colorSpace2->getCMYK(&color, cmyk); + } else { + for (i = 0; i < nComps; ++i) { + color.c[i] = lookup[i][x[i]]; + } + colorSpace->getCMYK(&color, cmyk); + } +} + +void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) { + int maxPixel, i; + + maxPixel = (1 << bits) - 1; + for (i = 0; i < nComps; ++i) { + color->c[i] = dblToCol(decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel); + } +} + +//------------------------------------------------------------------------ +// GfxSubpath and GfxPath +//------------------------------------------------------------------------ + +GfxSubpath::GfxSubpath(double x1, double y1) { + size = 16; + x = (double *)gmallocn(size, sizeof(double)); + y = (double *)gmallocn(size, sizeof(double)); + curve = (GBool *)gmallocn(size, sizeof(GBool)); + n = 1; + x[0] = x1; + y[0] = y1; + curve[0] = gFalse; + closed = gFalse; +} + +GfxSubpath::~GfxSubpath() { + gfree(x); + gfree(y); + gfree(curve); +} + +// Used for copy(). +GfxSubpath::GfxSubpath(GfxSubpath *subpath) { + size = subpath->size; + n = subpath->n; + x = (double *)gmallocn(size, sizeof(double)); + y = (double *)gmallocn(size, sizeof(double)); + curve = (GBool *)gmallocn(size, sizeof(GBool)); + memcpy(x, subpath->x, n * sizeof(double)); + memcpy(y, subpath->y, n * sizeof(double)); + memcpy(curve, subpath->curve, n * sizeof(GBool)); + closed = subpath->closed; +} + +void GfxSubpath::lineTo(double x1, double y1) { + if (n >= size) { + size += 16; + x = (double *)greallocn(x, size, sizeof(double)); + y = (double *)greallocn(y, size, sizeof(double)); + curve = (GBool *)greallocn(curve, size, sizeof(GBool)); + } + x[n] = x1; + y[n] = y1; + curve[n] = gFalse; + ++n; +} + +void GfxSubpath::curveTo(double x1, double y1, double x2, double y2, + double x3, double y3) { + if (n+3 > size) { + size += 16; + x = (double *)greallocn(x, size, sizeof(double)); + y = (double *)greallocn(y, size, sizeof(double)); + curve = (GBool *)greallocn(curve, size, sizeof(GBool)); + } + x[n] = x1; + y[n] = y1; + x[n+1] = x2; + y[n+1] = y2; + x[n+2] = x3; + y[n+2] = y3; + curve[n] = curve[n+1] = gTrue; + curve[n+2] = gFalse; + n += 3; +} + +void GfxSubpath::close() { + if (x[n-1] != x[0] || y[n-1] != y[0]) { + lineTo(x[0], y[0]); + } + closed = gTrue; +} + +void GfxSubpath::offset(double dx, double dy) { + int i; + + for (i = 0; i < n; ++i) { + x[i] += dx; + y[i] += dy; + } +} + +GfxPath::GfxPath() { + justMoved = gFalse; + size = 16; + n = 0; + firstX = firstY = 0; + subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *)); +} + +GfxPath::~GfxPath() { + int i; + + for (i = 0; i < n; ++i) + delete subpaths[i]; + gfree(subpaths); +} + +// Used for copy(). +GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1, + GfxSubpath **subpaths1, int n1, int size1) { + int i; + + justMoved = justMoved1; + firstX = firstX1; + firstY = firstY1; + size = size1; + n = n1; + subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *)); + for (i = 0; i < n; ++i) + subpaths[i] = subpaths1[i]->copy(); +} + +void GfxPath::moveTo(double x, double y) { + justMoved = gTrue; + firstX = x; + firstY = y; +} + +void GfxPath::lineTo(double x, double y) { + if (justMoved) { + if (n >= size) { + size += 16; + subpaths = (GfxSubpath **) + greallocn(subpaths, size, sizeof(GfxSubpath *)); + } + subpaths[n] = new GfxSubpath(firstX, firstY); + ++n; + justMoved = gFalse; + } + subpaths[n-1]->lineTo(x, y); +} + +void GfxPath::curveTo(double x1, double y1, double x2, double y2, + double x3, double y3) { + if (justMoved) { + if (n >= size) { + size += 16; + subpaths = (GfxSubpath **) + greallocn(subpaths, size, sizeof(GfxSubpath *)); + } + subpaths[n] = new GfxSubpath(firstX, firstY); + ++n; + justMoved = gFalse; + } + subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3); +} + +void GfxPath::close() { + // this is necessary to handle the pathological case of + // moveto/closepath/clip, which defines an empty clipping region + if (justMoved) { + if (n >= size) { + size += 16; + subpaths = (GfxSubpath **) + greallocn(subpaths, size, sizeof(GfxSubpath *)); + } + subpaths[n] = new GfxSubpath(firstX, firstY); + ++n; + justMoved = gFalse; + } + subpaths[n-1]->close(); +} + +void GfxPath::append(GfxPath *path) { + int i; + + if (n + path->n > size) { + size = n + path->n; + subpaths = (GfxSubpath **) + greallocn(subpaths, size, sizeof(GfxSubpath *)); + } + for (i = 0; i < path->n; ++i) { + subpaths[n++] = path->subpaths[i]->copy(); + } + justMoved = gFalse; +} + +void GfxPath::offset(double dx, double dy) { + int i; + + for (i = 0; i < n; ++i) { + subpaths[i]->offset(dx, dy); + } +} + +//------------------------------------------------------------------------ +// GfxState +//------------------------------------------------------------------------ + +GfxState::GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox, + int rotateA, GBool upsideDown) { + double kx, ky; + + hDPI = hDPIA; + vDPI = vDPIA; + rotate = rotateA; + px1 = pageBox->x1; + py1 = pageBox->y1; + px2 = pageBox->x2; + py2 = pageBox->y2; + kx = hDPI / 72.0; + ky = vDPI / 72.0; + if (rotate == 90) { + ctm[0] = 0; + ctm[1] = upsideDown ? ky : -ky; + ctm[2] = kx; + ctm[3] = 0; + ctm[4] = -kx * py1; + ctm[5] = ky * (upsideDown ? -px1 : px2); + pageWidth = kx * (py2 - py1); + pageHeight = ky * (px2 - px1); + } else if (rotate == 180) { + ctm[0] = -kx; + ctm[1] = 0; + ctm[2] = 0; + ctm[3] = upsideDown ? ky : -ky; + ctm[4] = kx * px2; + ctm[5] = ky * (upsideDown ? -py1 : py2); + pageWidth = kx * (px2 - px1); + pageHeight = ky * (py2 - py1); + } else if (rotate == 270) { + ctm[0] = 0; + ctm[1] = upsideDown ? -ky : ky; + ctm[2] = -kx; + ctm[3] = 0; + ctm[4] = kx * py2; + ctm[5] = ky * (upsideDown ? px2 : -px1); + pageWidth = kx * (py2 - py1); + pageHeight = ky * (px2 - px1); + } else { + ctm[0] = kx; + ctm[1] = 0; + ctm[2] = 0; + ctm[3] = upsideDown ? -ky : ky; + ctm[4] = -kx * px1; + ctm[5] = ky * (upsideDown ? py2 : -py1); + pageWidth = kx * (px2 - px1); + pageHeight = ky * (py2 - py1); + } + + fillColorSpace = new GfxDeviceGrayColorSpace(); + strokeColorSpace = new GfxDeviceGrayColorSpace(); + fillColor.c[0] = 0; + strokeColor.c[0] = 0; + fillPattern = NULL; + strokePattern = NULL; + blendMode = gfxBlendNormal; + fillOpacity = 1; + strokeOpacity = 1; + fillOverprint = gFalse; + strokeOverprint = gFalse; + transfer[0] = transfer[1] = transfer[2] = transfer[3] = NULL; + + lineWidth = 1; + lineDash = NULL; + lineDashLength = 0; + lineDashStart = 0; + flatness = 1; + lineJoin = 0; + lineCap = 0; + miterLimit = 10; + strokeAdjust = gFalse; + + font = NULL; + fontSize = 0; + textMat[0] = 1; textMat[1] = 0; + textMat[2] = 0; textMat[3] = 1; + textMat[4] = 0; textMat[5] = 0; + charSpace = 0; + wordSpace = 0; + horizScaling = 1; + leading = 0; + rise = 0; + render = 0; + + path = new GfxPath(); + curX = curY = 0; + lineX = lineY = 0; + + clipXMin = 0; + clipYMin = 0; + clipXMax = pageWidth; + clipYMax = pageHeight; + + saved = NULL; +} + +GfxState::~GfxState() { + int i; + + if (fillColorSpace) { + delete fillColorSpace; + } + if (strokeColorSpace) { + delete strokeColorSpace; + } + if (fillPattern) { + delete fillPattern; + } + if (strokePattern) { + delete strokePattern; + } + for (i = 0; i < 4; ++i) { + if (transfer[i]) { + delete transfer[i]; + } + } + gfree(lineDash); + if (path) { + // this gets set to NULL by restore() + delete path; + } + if (saved) { + delete saved; + } +} + +// Used for copy(); +GfxState::GfxState(GfxState *state) { + int i; + + memcpy(this, state, sizeof(GfxState)); + if (fillColorSpace) { + fillColorSpace = state->fillColorSpace->copy(); + } + if (strokeColorSpace) { + strokeColorSpace = state->strokeColorSpace->copy(); + } + if (fillPattern) { + fillPattern = state->fillPattern->copy(); + } + if (strokePattern) { + strokePattern = state->strokePattern->copy(); + } + for (i = 0; i < 4; ++i) { + if (transfer[i]) { + transfer[i] = state->transfer[i]->copy(); + } + } + if (lineDashLength > 0) { + lineDash = (double *)gmallocn(lineDashLength, sizeof(double)); + memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double)); + } + saved = NULL; +} + +void GfxState::setPath(GfxPath *pathA) { + delete path; + path = pathA; +} + +void GfxState::getUserClipBBox(double *xMin, double *yMin, + double *xMax, double *yMax) { + double ictm[6]; + double xMin1, yMin1, xMax1, yMax1, det, tx, ty; + + // invert the CTM + det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]); + ictm[0] = ctm[3] * det; + ictm[1] = -ctm[1] * det; + ictm[2] = -ctm[2] * det; + ictm[3] = ctm[0] * det; + ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det; + ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det; + + // transform all four corners of the clip bbox; find the min and max + // x and y values + xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4]; + yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5]; + tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4]; + ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5]; + if (tx < xMin1) { + xMin1 = tx; + } else if (tx > xMax1) { + xMax1 = tx; + } + if (ty < yMin1) { + yMin1 = ty; + } else if (ty > yMax1) { + yMax1 = ty; + } + tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4]; + ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5]; + if (tx < xMin1) { + xMin1 = tx; + } else if (tx > xMax1) { + xMax1 = tx; + } + if (ty < yMin1) { + yMin1 = ty; + } else if (ty > yMax1) { + yMax1 = ty; + } + tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4]; + ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5]; + if (tx < xMin1) { + xMin1 = tx; + } else if (tx > xMax1) { + xMax1 = tx; + } + if (ty < yMin1) { + yMin1 = ty; + } else if (ty > yMax1) { + yMax1 = ty; + } + + *xMin = xMin1; + *yMin = yMin1; + *xMax = xMax1; + *yMax = yMax1; +} + +double GfxState::transformWidth(double w) { + double x, y; + + x = ctm[0] + ctm[2]; + y = ctm[1] + ctm[3]; + return w * sqrt(0.5 * (x * x + y * y)); +} + +double GfxState::getTransformedFontSize() { + double x1, y1, x2, y2; + + x1 = textMat[2] * fontSize; + y1 = textMat[3] * fontSize; + x2 = ctm[0] * x1 + ctm[2] * y1; + y2 = ctm[1] * x1 + ctm[3] * y1; + return sqrt(x2 * x2 + y2 * y2); +} + +void GfxState::getFontTransMat(double *m11, double *m12, + double *m21, double *m22) { + *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize; + *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize; + *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize; + *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize; +} + +void GfxState::setCTM(double a, double b, double c, + double d, double e, double f) { + int i; + + ctm[0] = a; + ctm[1] = b; + ctm[2] = c; + ctm[3] = d; + ctm[4] = e; + ctm[5] = f; + + // avoid FP exceptions on badly messed up PDF files + for (i = 0; i < 6; ++i) { + if (ctm[i] > 1e10) { + ctm[i] = 1e10; + } else if (ctm[i] < -1e10) { + ctm[i] = -1e10; + } + } +} + +void GfxState::concatCTM(double a, double b, double c, + double d, double e, double f) { + double a1 = ctm[0]; + double b1 = ctm[1]; + double c1 = ctm[2]; + double d1 = ctm[3]; + int i; + + ctm[0] = a * a1 + b * c1; + ctm[1] = a * b1 + b * d1; + ctm[2] = c * a1 + d * c1; + ctm[3] = c * b1 + d * d1; + ctm[4] = e * a1 + f * c1 + ctm[4]; + ctm[5] = e * b1 + f * d1 + ctm[5]; + + // avoid FP exceptions on badly messed up PDF files + for (i = 0; i < 6; ++i) { + if (ctm[i] > 1e10) { + ctm[i] = 1e10; + } else if (ctm[i] < -1e10) { + ctm[i] = -1e10; + } + } +} + +void GfxState::shiftCTM(double tx, double ty) { + ctm[4] += tx; + ctm[5] += ty; + clipXMin += tx; + clipYMin += ty; + clipXMax += tx; + clipYMax += ty; +} + +void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) { + if (fillColorSpace) { + delete fillColorSpace; + } + fillColorSpace = colorSpace; +} + +void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) { + if (strokeColorSpace) { + delete strokeColorSpace; + } + strokeColorSpace = colorSpace; +} + +void GfxState::setFillPattern(GfxPattern *pattern) { + if (fillPattern) { + delete fillPattern; + } + fillPattern = pattern; +} + +void GfxState::setStrokePattern(GfxPattern *pattern) { + if (strokePattern) { + delete strokePattern; + } + strokePattern = pattern; +} + +void GfxState::setTransfer(Function **funcs) { + int i; + + for (i = 0; i < 4; ++i) { + if (transfer[i]) { + delete transfer[i]; + } + transfer[i] = funcs[i]; + } +} + +void GfxState::setLineDash(double *dash, int length, double start) { + if (lineDash) + gfree(lineDash); + lineDash = dash; + lineDashLength = length; + lineDashStart = start; +} + +void GfxState::clearPath() { + delete path; + path = new GfxPath(); +} + +void GfxState::clip() { + double xMin, yMin, xMax, yMax, x, y; + GfxSubpath *subpath; + int i, j; + + xMin = xMax = yMin = yMax = 0; // make gcc happy + for (i = 0; i < path->getNumSubpaths(); ++i) { + subpath = path->getSubpath(i); + for (j = 0; j < subpath->getNumPoints(); ++j) { + transform(subpath->getX(j), subpath->getY(j), &x, &y); + if (i == 0 && j == 0) { + xMin = xMax = x; + yMin = yMax = y; + } else { + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + } + } + } + if (xMin > clipXMin) { + clipXMin = xMin; + } + if (yMin > clipYMin) { + clipYMin = yMin; + } + if (xMax < clipXMax) { + clipXMax = xMax; + } + if (yMax < clipYMax) { + clipYMax = yMax; + } +} + +void GfxState::clipToStrokePath() { + double xMin, yMin, xMax, yMax, x, y, t0, t1; + GfxSubpath *subpath; + int i, j; + + xMin = xMax = yMin = yMax = 0; // make gcc happy + for (i = 0; i < path->getNumSubpaths(); ++i) { + subpath = path->getSubpath(i); + for (j = 0; j < subpath->getNumPoints(); ++j) { + transform(subpath->getX(j), subpath->getY(j), &x, &y); + if (i == 0 && j == 0) { + xMin = xMax = x; + yMin = yMax = y; + } else { + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + } + } + } + + // allow for the line width + //~ miter joins can extend farther than this + t0 = fabs(ctm[0]); + t1 = fabs(ctm[2]); + if (t0 > t1) { + xMin -= 0.5 * lineWidth * t0; + xMax += 0.5 * lineWidth * t0; + } else { + xMin -= 0.5 * lineWidth * t1; + xMax += 0.5 * lineWidth * t1; + } + t0 = fabs(ctm[0]); + t1 = fabs(ctm[3]); + if (t0 > t1) { + yMin -= 0.5 * lineWidth * t0; + yMax += 0.5 * lineWidth * t0; + } else { + yMin -= 0.5 * lineWidth * t1; + yMax += 0.5 * lineWidth * t1; + } + + if (xMin > clipXMin) { + clipXMin = xMin; + } + if (yMin > clipYMin) { + clipYMin = yMin; + } + if (xMax < clipXMax) { + clipXMax = xMax; + } + if (yMax < clipYMax) { + clipYMax = yMax; + } +} + +void GfxState::textShift(double tx, double ty) { + double dx, dy; + + textTransformDelta(tx, ty, &dx, &dy); + curX += dx; + curY += dy; +} + +void GfxState::shift(double dx, double dy) { + curX += dx; + curY += dy; +} + +GfxState *GfxState::save() { + GfxState *newState; + + newState = copy(); + newState->saved = this; + return newState; +} + +GfxState *GfxState::restore() { + GfxState *oldState; + + if (saved) { + oldState = saved; + + // these attributes aren't saved/restored by the q/Q operators + oldState->path = path; + oldState->curX = curX; + oldState->curY = curY; + oldState->lineX = lineX; + oldState->lineY = lineY; + + path = NULL; + saved = NULL; + delete this; + + } else { + oldState = this; + } + + return oldState; +} + +GBool GfxState::parseBlendMode(Object *obj, GfxBlendMode *mode) { + Object obj2; + int i, j; + + if (obj->isName()) { + for (i = 0; i < nGfxBlendModeNames; ++i) { + if (!strcmp(obj->getName(), gfxBlendModeNames[i].name)) { + *mode = gfxBlendModeNames[i].mode; + return gTrue; + } + } + return gFalse; + } else if (obj->isArray()) { + for (i = 0; i < obj->arrayGetLength(); ++i) { + obj->arrayGet(i, &obj2); + if (!obj2.isName()) { + obj2.free(); + return gFalse; + } + for (j = 0; j < nGfxBlendModeNames; ++j) { + if (!strcmp(obj2.getName(), gfxBlendModeNames[j].name)) { + obj2.free(); + *mode = gfxBlendModeNames[j].mode; + return gTrue; + } + } + obj2.free(); + } + *mode = gfxBlendNormal; + return gTrue; + } else { + return gFalse; + } +} diff --git a/kpdf/xpdf/xpdf/GfxState.h b/kpdf/xpdf/xpdf/GfxState.h new file mode 100644 index 00000000..f85643dc --- /dev/null +++ b/kpdf/xpdf/xpdf/GfxState.h @@ -0,0 +1,1244 @@ +//======================================================================== +// +// GfxState.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef GFXSTATE_H +#define GFXSTATE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "Object.h" +#include "Function.h" + +class Array; +class GfxFont; +class PDFRectangle; +class GfxShading; + +//------------------------------------------------------------------------ +// GfxBlendMode +//------------------------------------------------------------------------ + +enum GfxBlendMode { + gfxBlendNormal, + gfxBlendMultiply, + gfxBlendScreen, + gfxBlendOverlay, + gfxBlendDarken, + gfxBlendLighten, + gfxBlendColorDodge, + gfxBlendColorBurn, + gfxBlendHardLight, + gfxBlendSoftLight, + gfxBlendDifference, + gfxBlendExclusion, + gfxBlendHue, + gfxBlendSaturation, + gfxBlendColor, + gfxBlendLuminosity +}; + +//------------------------------------------------------------------------ +// GfxColorComp +//------------------------------------------------------------------------ + +// 16.16 fixed point color component +typedef int GfxColorComp; + +#define gfxColorComp1 0x10000 + +static inline GfxColorComp dblToCol(double x) { + return (GfxColorComp)(x * gfxColorComp1); +} + +static inline double colToDbl(GfxColorComp x) { + return (double)x / (double)gfxColorComp1; +} + +static inline GfxColorComp byteToCol(Guchar x) { + // (x / 255) << 16 = (0.0000000100000001... * x) << 16 + // = ((x << 8) + (x) + (x >> 8) + ...) << 16 + // = (x << 8) + (x) + (x >> 7) + // [for rounding] + return (GfxColorComp)((x << 8) + x + (x >> 7)); +} + +static inline Guchar colToByte(GfxColorComp x) { + // 255 * x + 0.5 = 256 * x - x + 0x8000 + return (Guchar)(((x << 8) - x + 0x8000) >> 16); +} + +//------------------------------------------------------------------------ +// GfxColor +//------------------------------------------------------------------------ + +#define gfxColorMaxComps funcMaxOutputs + +struct GfxColor { + GfxColorComp c[gfxColorMaxComps]; +}; + +//------------------------------------------------------------------------ +// GfxGray +//------------------------------------------------------------------------ + +typedef GfxColorComp GfxGray; + +//------------------------------------------------------------------------ +// GfxRGB +//------------------------------------------------------------------------ + +struct GfxRGB { + GfxColorComp r, g, b; +}; + +//------------------------------------------------------------------------ +// GfxCMYK +//------------------------------------------------------------------------ + +struct GfxCMYK { + GfxColorComp c, m, y, k; +}; + +//------------------------------------------------------------------------ +// GfxColorSpace +//------------------------------------------------------------------------ + +// NB: The nGfxColorSpaceModes constant and the gfxColorSpaceModeNames +// array defined in GfxState.cc must match this enum. +enum GfxColorSpaceMode { + csDeviceGray, + csCalGray, + csDeviceRGB, + csCalRGB, + csDeviceCMYK, + csLab, + csICCBased, + csIndexed, + csSeparation, + csDeviceN, + csPattern +}; + +class GfxColorSpace { +public: + + GfxColorSpace(); + virtual ~GfxColorSpace(); + virtual GfxColorSpace *copy() = 0; + virtual GfxColorSpaceMode getMode() = 0; + + // Construct a color space. Returns NULL if unsuccessful. + static GfxColorSpace *parse(Object *csObj); + + // Convert to gray, RGB, or CMYK. + virtual void getGray(GfxColor *color, GfxGray *gray) = 0; + virtual void getRGB(GfxColor *color, GfxRGB *rgb) = 0; + virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk) = 0; + + // Return the number of color components. + virtual int getNComps() = 0; + + // Get this color space's default color. + virtual void getDefaultColor(GfxColor *color) = 0; + + // Return the default ranges for each component, assuming an image + // with a max pixel value of . + virtual void getDefaultRanges(double *decodeLow, double *decodeRange, + int maxImgPixel); + + // Returns true if painting operations in this color space never + // mark the page (e.g., the "None" colorant). + virtual GBool isNonMarking() { return gFalse; } + + // Return the number of color space modes + static int getNumColorSpaceModes(); + + // Return the name of the th color space mode. + static char *getColorSpaceModeName(int idx); + +private: +}; + +//------------------------------------------------------------------------ +// GfxDeviceGrayColorSpace +//------------------------------------------------------------------------ + +class GfxDeviceGrayColorSpace: public GfxColorSpace { +public: + + GfxDeviceGrayColorSpace(); + virtual ~GfxDeviceGrayColorSpace(); + virtual GfxColorSpace *copy(); + virtual GfxColorSpaceMode getMode() { return csDeviceGray; } + + virtual void getGray(GfxColor *color, GfxGray *gray); + virtual void getRGB(GfxColor *color, GfxRGB *rgb); + virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + + virtual int getNComps() { return 1; } + virtual void getDefaultColor(GfxColor *color); + +private: +}; + +//------------------------------------------------------------------------ +// GfxCalGrayColorSpace +//------------------------------------------------------------------------ + +class GfxCalGrayColorSpace: public GfxColorSpace { +public: + + GfxCalGrayColorSpace(); + virtual ~GfxCalGrayColorSpace(); + virtual GfxColorSpace *copy(); + virtual GfxColorSpaceMode getMode() { return csCalGray; } + + // Construct a CalGray color space. Returns NULL if unsuccessful. + static GfxColorSpace *parse(Array *arr); + + virtual void getGray(GfxColor *color, GfxGray *gray); + virtual void getRGB(GfxColor *color, GfxRGB *rgb); + virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + + virtual int getNComps() { return 1; } + virtual void getDefaultColor(GfxColor *color); + + // CalGray-specific access. + double getWhiteX() { return whiteX; } + double getWhiteY() { return whiteY; } + double getWhiteZ() { return whiteZ; } + double getBlackX() { return blackX; } + double getBlackY() { return blackY; } + double getBlackZ() { return blackZ; } + double getGamma() { return gamma; } + +private: + + double whiteX, whiteY, whiteZ; // white point + double blackX, blackY, blackZ; // black point + double gamma; // gamma value +}; + +//------------------------------------------------------------------------ +// GfxDeviceRGBColorSpace +//------------------------------------------------------------------------ + +class GfxDeviceRGBColorSpace: public GfxColorSpace { +public: + + GfxDeviceRGBColorSpace(); + virtual ~GfxDeviceRGBColorSpace(); + virtual GfxColorSpace *copy(); + virtual GfxColorSpaceMode getMode() { return csDeviceRGB; } + + virtual void getGray(GfxColor *color, GfxGray *gray); + virtual void getRGB(GfxColor *color, GfxRGB *rgb); + virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + + virtual int getNComps() { return 3; } + virtual void getDefaultColor(GfxColor *color); + +private: +}; + +//------------------------------------------------------------------------ +// GfxCalRGBColorSpace +//------------------------------------------------------------------------ + +class GfxCalRGBColorSpace: public GfxColorSpace { +public: + + GfxCalRGBColorSpace(); + virtual ~GfxCalRGBColorSpace(); + virtual GfxColorSpace *copy(); + virtual GfxColorSpaceMode getMode() { return csCalRGB; } + + // Construct a CalRGB color space. Returns NULL if unsuccessful. + static GfxColorSpace *parse(Array *arr); + + virtual void getGray(GfxColor *color, GfxGray *gray); + virtual void getRGB(GfxColor *color, GfxRGB *rgb); + virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + + virtual int getNComps() { return 3; } + virtual void getDefaultColor(GfxColor *color); + + // CalRGB-specific access. + double getWhiteX() { return whiteX; } + double getWhiteY() { return whiteY; } + double getWhiteZ() { return whiteZ; } + double getBlackX() { return blackX; } + double getBlackY() { return blackY; } + double getBlackZ() { return blackZ; } + double getGammaR() { return gammaR; } + double getGammaG() { return gammaG; } + double getGammaB() { return gammaB; } + double *getMatrix() { return mat; } + +private: + + double whiteX, whiteY, whiteZ; // white point + double blackX, blackY, blackZ; // black point + double gammaR, gammaG, gammaB; // gamma values + double mat[9]; // ABC -> XYZ transform matrix +}; + +//------------------------------------------------------------------------ +// GfxDeviceCMYKColorSpace +//------------------------------------------------------------------------ + +class GfxDeviceCMYKColorSpace: public GfxColorSpace { +public: + + GfxDeviceCMYKColorSpace(); + virtual ~GfxDeviceCMYKColorSpace(); + virtual GfxColorSpace *copy(); + virtual GfxColorSpaceMode getMode() { return csDeviceCMYK; } + + virtual void getGray(GfxColor *color, GfxGray *gray); + virtual void getRGB(GfxColor *color, GfxRGB *rgb); + virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + + virtual int getNComps() { return 4; } + virtual void getDefaultColor(GfxColor *color); + +private: +}; + +//------------------------------------------------------------------------ +// GfxLabColorSpace +//------------------------------------------------------------------------ + +class GfxLabColorSpace: public GfxColorSpace { +public: + + GfxLabColorSpace(); + virtual ~GfxLabColorSpace(); + virtual GfxColorSpace *copy(); + virtual GfxColorSpaceMode getMode() { return csLab; } + + // Construct a Lab color space. Returns NULL if unsuccessful. + static GfxColorSpace *parse(Array *arr); + + virtual void getGray(GfxColor *color, GfxGray *gray); + virtual void getRGB(GfxColor *color, GfxRGB *rgb); + virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + + virtual int getNComps() { return 3; } + virtual void getDefaultColor(GfxColor *color); + + virtual void getDefaultRanges(double *decodeLow, double *decodeRange, + int maxImgPixel); + + // Lab-specific access. + double getWhiteX() { return whiteX; } + double getWhiteY() { return whiteY; } + double getWhiteZ() { return whiteZ; } + double getBlackX() { return blackX; } + double getBlackY() { return blackY; } + double getBlackZ() { return blackZ; } + double getAMin() { return aMin; } + double getAMax() { return aMax; } + double getBMin() { return bMin; } + double getBMax() { return bMax; } + +private: + + double whiteX, whiteY, whiteZ; // white point + double blackX, blackY, blackZ; // black point + double aMin, aMax, bMin, bMax; // range for the a and b components + double kr, kg, kb; // gamut mapping mulitpliers +}; + +//------------------------------------------------------------------------ +// GfxICCBasedColorSpace +//------------------------------------------------------------------------ + +class GfxICCBasedColorSpace: public GfxColorSpace { +public: + + GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA, + Ref *iccProfileStreamA); + virtual ~GfxICCBasedColorSpace(); + virtual GfxColorSpace *copy(); + virtual GfxColorSpaceMode getMode() { return csICCBased; } + + // Construct an ICCBased color space. Returns NULL if unsuccessful. + static GfxColorSpace *parse(Array *arr); + + virtual void getGray(GfxColor *color, GfxGray *gray); + virtual void getRGB(GfxColor *color, GfxRGB *rgb); + virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + + virtual int getNComps() { return nComps; } + virtual void getDefaultColor(GfxColor *color); + + virtual void getDefaultRanges(double *decodeLow, double *decodeRange, + int maxImgPixel); + + // ICCBased-specific access. + GfxColorSpace *getAlt() { return alt; } + +private: + + int nComps; // number of color components (1, 3, or 4) + GfxColorSpace *alt; // alternate color space + double rangeMin[4]; // min values for each component + double rangeMax[4]; // max values for each component + Ref iccProfileStream; // the ICC profile +}; + +//------------------------------------------------------------------------ +// GfxIndexedColorSpace +//------------------------------------------------------------------------ + +class GfxIndexedColorSpace: public GfxColorSpace { +public: + + GfxIndexedColorSpace(GfxColorSpace *baseA, int indexHighA); + virtual ~GfxIndexedColorSpace(); + virtual GfxColorSpace *copy(); + virtual GfxColorSpaceMode getMode() { return csIndexed; } + + // Construct a Lab color space. Returns NULL if unsuccessful. + static GfxColorSpace *parse(Array *arr); + + virtual void getGray(GfxColor *color, GfxGray *gray); + virtual void getRGB(GfxColor *color, GfxRGB *rgb); + virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + + virtual int getNComps() { return 1; } + virtual void getDefaultColor(GfxColor *color); + + virtual void getDefaultRanges(double *decodeLow, double *decodeRange, + int maxImgPixel); + + // Indexed-specific access. + GfxColorSpace *getBase() { return base; } + int getIndexHigh() { return indexHigh; } + Guchar *getLookup() { return lookup; } + GfxColor *mapColorToBase(GfxColor *color, GfxColor *baseColor); + +private: + + GfxColorSpace *base; // base color space + int indexHigh; // max pixel value + Guchar *lookup; // lookup table +}; + +//------------------------------------------------------------------------ +// GfxSeparationColorSpace +//------------------------------------------------------------------------ + +class GfxSeparationColorSpace: public GfxColorSpace { +public: + + GfxSeparationColorSpace(GString *nameA, GfxColorSpace *altA, + Function *funcA); + virtual ~GfxSeparationColorSpace(); + virtual GfxColorSpace *copy(); + virtual GfxColorSpaceMode getMode() { return csSeparation; } + + // Construct a Separation color space. Returns NULL if unsuccessful. + static GfxColorSpace *parse(Array *arr); + + virtual void getGray(GfxColor *color, GfxGray *gray); + virtual void getRGB(GfxColor *color, GfxRGB *rgb); + virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + + virtual int getNComps() { return 1; } + virtual void getDefaultColor(GfxColor *color); + + virtual GBool isNonMarking() { return nonMarking; } + + // Separation-specific access. + GString *getName() { return name; } + GfxColorSpace *getAlt() { return alt; } + Function *getFunc() { return func; } + +private: + + GString *name; // colorant name + GfxColorSpace *alt; // alternate color space + Function *func; // tint transform (into alternate color space) + GBool nonMarking; +}; + +//------------------------------------------------------------------------ +// GfxDeviceNColorSpace +//------------------------------------------------------------------------ + +class GfxDeviceNColorSpace: public GfxColorSpace { +public: + + GfxDeviceNColorSpace(int nCompsA, GfxColorSpace *alt, Function *func); + virtual ~GfxDeviceNColorSpace(); + virtual GfxColorSpace *copy(); + virtual GfxColorSpaceMode getMode() { return csDeviceN; } + + // Construct a DeviceN color space. Returns NULL if unsuccessful. + static GfxColorSpace *parse(Array *arr); + + virtual void getGray(GfxColor *color, GfxGray *gray); + virtual void getRGB(GfxColor *color, GfxRGB *rgb); + virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + + virtual int getNComps() { return nComps; } + virtual void getDefaultColor(GfxColor *color); + + virtual GBool isNonMarking() { return nonMarking; } + + // DeviceN-specific access. + GString *getColorantName(int i) { return names[i]; } + GfxColorSpace *getAlt() { return alt; } + Function *getTintTransformFunc() { return func; } + +private: + + int nComps; // number of components + GString // colorant names + *names[gfxColorMaxComps]; + GfxColorSpace *alt; // alternate color space + Function *func; // tint transform (into alternate color space) + GBool nonMarking; +}; + +//------------------------------------------------------------------------ +// GfxPatternColorSpace +//------------------------------------------------------------------------ + +class GfxPatternColorSpace: public GfxColorSpace { +public: + + GfxPatternColorSpace(GfxColorSpace *underA); + virtual ~GfxPatternColorSpace(); + virtual GfxColorSpace *copy(); + virtual GfxColorSpaceMode getMode() { return csPattern; } + + // Construct a Pattern color space. Returns NULL if unsuccessful. + static GfxColorSpace *parse(Array *arr); + + virtual void getGray(GfxColor *color, GfxGray *gray); + virtual void getRGB(GfxColor *color, GfxRGB *rgb); + virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + + virtual int getNComps() { return 0; } + virtual void getDefaultColor(GfxColor *color); + + // Pattern-specific access. + GfxColorSpace *getUnder() { return under; } + +private: + + GfxColorSpace *under; // underlying color space (for uncolored + // patterns) +}; + +//------------------------------------------------------------------------ +// GfxPattern +//------------------------------------------------------------------------ + +class GfxPattern { +public: + + GfxPattern(int typeA); + virtual ~GfxPattern(); + + static GfxPattern *parse(Object *obj); + + virtual GfxPattern *copy() = 0; + + int getType() { return type; } + +private: + + int type; +}; + +//------------------------------------------------------------------------ +// GfxTilingPattern +//------------------------------------------------------------------------ + +class GfxTilingPattern: public GfxPattern { +public: + + static GfxTilingPattern *parse(Object *patObj); + virtual ~GfxTilingPattern(); + + virtual GfxPattern *copy(); + + int getPaintType() { return paintType; } + int getTilingType() { return tilingType; } + double *getBBox() { return bbox; } + double getXStep() { return xStep; } + double getYStep() { return yStep; } + Dict *getResDict() + { return resDict.isDict() ? resDict.getDict() : (Dict *)NULL; } + double *getMatrix() { return matrix; } + Object *getContentStream() { return &contentStream; } + +private: + + GfxTilingPattern(int paintTypeA, int tilingTypeA, + double *bboxA, double xStepA, double yStepA, + Object *resDictA, double *matrixA, + Object *contentStreamA); + + int paintType; + int tilingType; + double bbox[4]; + double xStep, yStep; + Object resDict; + double matrix[6]; + Object contentStream; +}; + +//------------------------------------------------------------------------ +// GfxShadingPattern +//------------------------------------------------------------------------ + +class GfxShadingPattern: public GfxPattern { +public: + + static GfxShadingPattern *parse(Object *patObj); + virtual ~GfxShadingPattern(); + + virtual GfxPattern *copy(); + + GfxShading *getShading() { return shading; } + double *getMatrix() { return matrix; } + +private: + + GfxShadingPattern(GfxShading *shadingA, double *matrixA); + + GfxShading *shading; + double matrix[6]; +}; + +//------------------------------------------------------------------------ +// GfxShading +//------------------------------------------------------------------------ + +class GfxShading { +public: + + GfxShading(int typeA); + GfxShading(GfxShading *shading); + virtual ~GfxShading(); + + static GfxShading *parse(Object *obj); + + virtual GfxShading *copy() = 0; + + int getType() { return type; } + GfxColorSpace *getColorSpace() { return colorSpace; } + GfxColor *getBackground() { return &background; } + GBool getHasBackground() { return hasBackground; } + void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA) + { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } + GBool getHasBBox() { return hasBBox; } + +protected: + + GBool init(Dict *dict); + + int type; + GfxColorSpace *colorSpace; + GfxColor background; + GBool hasBackground; + double xMin, yMin, xMax, yMax; + GBool hasBBox; +}; + +//------------------------------------------------------------------------ +// GfxFunctionShading +//------------------------------------------------------------------------ + +class GfxFunctionShading: public GfxShading { +public: + + GfxFunctionShading(double x0A, double y0A, + double x1A, double y1A, + double *matrixA, + Function **funcsA, int nFuncsA); + GfxFunctionShading(GfxFunctionShading *shading); + virtual ~GfxFunctionShading(); + + static GfxFunctionShading *parse(Dict *dict); + + virtual GfxShading *copy(); + + void getDomain(double *x0A, double *y0A, double *x1A, double *y1A) + { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; } + double *getMatrix() { return matrix; } + int getNFuncs() { return nFuncs; } + Function *getFunc(int i) { return funcs[i]; } + void getColor(double x, double y, GfxColor *color); + +private: + + double x0, y0, x1, y1; + double matrix[6]; + Function *funcs[gfxColorMaxComps]; + int nFuncs; +}; + +//------------------------------------------------------------------------ +// GfxAxialShading +//------------------------------------------------------------------------ + +class GfxAxialShading: public GfxShading { +public: + + GfxAxialShading(double x0A, double y0A, + double x1A, double y1A, + double t0A, double t1A, + Function **funcsA, int nFuncsA, + GBool extend0A, GBool extend1A); + GfxAxialShading(GfxAxialShading *shading); + virtual ~GfxAxialShading(); + + static GfxAxialShading *parse(Dict *dict); + + virtual GfxShading *copy(); + + void getCoords(double *x0A, double *y0A, double *x1A, double *y1A) + { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; } + double getDomain0() { return t0; } + double getDomain1() { return t1; } + GBool getExtend0() { return extend0; } + GBool getExtend1() { return extend1; } + int getNFuncs() { return nFuncs; } + Function *getFunc(int i) { return funcs[i]; } + void getColor(double t, GfxColor *color); + +private: + + double x0, y0, x1, y1; + double t0, t1; + Function *funcs[gfxColorMaxComps]; + int nFuncs; + GBool extend0, extend1; +}; + +//------------------------------------------------------------------------ +// GfxRadialShading +//------------------------------------------------------------------------ + +class GfxRadialShading: public GfxShading { +public: + + GfxRadialShading(double x0A, double y0A, double r0A, + double x1A, double y1A, double r1A, + double t0A, double t1A, + Function **funcsA, int nFuncsA, + GBool extend0A, GBool extend1A); + GfxRadialShading(GfxRadialShading *shading); + virtual ~GfxRadialShading(); + + static GfxRadialShading *parse(Dict *dict); + + virtual GfxShading *copy(); + + void getCoords(double *x0A, double *y0A, double *r0A, + double *x1A, double *y1A, double *r1A) + { *x0A = x0; *y0A = y0; *r0A = r0; *x1A = x1; *y1A = y1; *r1A = r1; } + double getDomain0() { return t0; } + double getDomain1() { return t1; } + GBool getExtend0() { return extend0; } + GBool getExtend1() { return extend1; } + int getNFuncs() { return nFuncs; } + Function *getFunc(int i) { return funcs[i]; } + void getColor(double t, GfxColor *color); + +private: + + double x0, y0, r0, x1, y1, r1; + double t0, t1; + Function *funcs[gfxColorMaxComps]; + int nFuncs; + GBool extend0, extend1; +}; + +//------------------------------------------------------------------------ +// GfxGouraudTriangleShading +//------------------------------------------------------------------------ + +struct GfxGouraudVertex { + double x, y; + GfxColor color; +}; + +class GfxGouraudTriangleShading: public GfxShading { +public: + + GfxGouraudTriangleShading(int typeA, + GfxGouraudVertex *verticesA, int nVerticesA, + int (*trianglesA)[3], int nTrianglesA, + Function **funcsA, int nFuncsA); + GfxGouraudTriangleShading(GfxGouraudTriangleShading *shading); + virtual ~GfxGouraudTriangleShading(); + + static GfxGouraudTriangleShading *parse(int typeA, Dict *dict, Stream *str); + + virtual GfxShading *copy(); + + int getNTriangles() { return nTriangles; } + void getTriangle(int i, double *x0, double *y0, GfxColor *color0, + double *x1, double *y1, GfxColor *color1, + double *x2, double *y2, GfxColor *color2); + +private: + + GfxGouraudVertex *vertices; + int nVertices; + int (*triangles)[3]; + int nTriangles; + Function *funcs[gfxColorMaxComps]; + int nFuncs; +}; + +//------------------------------------------------------------------------ +// GfxPatchMeshShading +//------------------------------------------------------------------------ + +struct GfxPatch { + double x[4][4]; + double y[4][4]; + GfxColor color[2][2]; +}; + +class GfxPatchMeshShading: public GfxShading { +public: + + GfxPatchMeshShading(int typeA, GfxPatch *patchesA, int nPatchesA, + Function **funcsA, int nFuncsA); + GfxPatchMeshShading(GfxPatchMeshShading *shading); + virtual ~GfxPatchMeshShading(); + + static GfxPatchMeshShading *parse(int typeA, Dict *dict, Stream *str); + + virtual GfxShading *copy(); + + int getNPatches() { return nPatches; } + GfxPatch *getPatch(int i) { return &patches[i]; } + +private: + + GfxPatch *patches; + int nPatches; + Function *funcs[gfxColorMaxComps]; + int nFuncs; +}; + +//------------------------------------------------------------------------ +// GfxImageColorMap +//------------------------------------------------------------------------ + +class GfxImageColorMap { +public: + + // Constructor. + GfxImageColorMap(int bitsA, Object *decode, GfxColorSpace *colorSpaceA); + + // Destructor. + ~GfxImageColorMap(); + + // Return a copy of this color map. + GfxImageColorMap *copy() { return new GfxImageColorMap(this); } + + // Is color map valid? + GBool isOk() { return ok; } + + // Get the color space. + GfxColorSpace *getColorSpace() { return colorSpace; } + + // Get stream decoding info. + int getNumPixelComps() { return nComps; } + int getBits() { return bits; } + + // Get decode table. + double getDecodeLow(int i) { return decodeLow[i]; } + double getDecodeHigh(int i) { return decodeLow[i] + decodeRange[i]; } + + // Convert an image pixel to a color. + void getGray(Guchar *x, GfxGray *gray); + void getRGB(Guchar *x, GfxRGB *rgb); + void getCMYK(Guchar *x, GfxCMYK *cmyk); + void getColor(Guchar *x, GfxColor *color); + +private: + + GfxImageColorMap(GfxImageColorMap *colorMap); + + GfxColorSpace *colorSpace; // the image color space + int bits; // bits per component + int nComps; // number of components in a pixel + GfxColorSpace *colorSpace2; // secondary color space + int nComps2; // number of components in colorSpace2 + GfxColorComp * // lookup table + lookup[gfxColorMaxComps]; + double // minimum values for each component + decodeLow[gfxColorMaxComps]; + double // max - min value for each component + decodeRange[gfxColorMaxComps]; + GBool ok; +}; + +//------------------------------------------------------------------------ +// GfxSubpath and GfxPath +//------------------------------------------------------------------------ + +class GfxSubpath { +public: + + // Constructor. + GfxSubpath(double x1, double y1); + + // Destructor. + ~GfxSubpath(); + + // Copy. + GfxSubpath *copy() { return new GfxSubpath(this); } + + // Get points. + int getNumPoints() { return n; } + double getX(int i) { return x[i]; } + double getY(int i) { return y[i]; } + GBool getCurve(int i) { return curve[i]; } + + // Get last point. + double getLastX() { return x[n-1]; } + double getLastY() { return y[n-1]; } + + // Add a line segment. + void lineTo(double x1, double y1); + + // Add a Bezier curve. + void curveTo(double x1, double y1, double x2, double y2, + double x3, double y3); + + // Close the subpath. + void close(); + GBool isClosed() { return closed; } + + // Add (, ) to each point in the subpath. + void offset(double dx, double dy); + +private: + + double *x, *y; // points + GBool *curve; // curve[i] => point i is a control point + // for a Bezier curve + int n; // number of points + int size; // size of x/y arrays + GBool closed; // set if path is closed + + GfxSubpath(GfxSubpath *subpath); +}; + +class GfxPath { +public: + + // Constructor. + GfxPath(); + + // Destructor. + ~GfxPath(); + + // Copy. + GfxPath *copy() + { return new GfxPath(justMoved, firstX, firstY, subpaths, n, size); } + + // Is there a current point? + GBool isCurPt() { return n > 0 || justMoved; } + + // Is the path non-empty, i.e., is there at least one segment? + GBool isPath() { return n > 0; } + + // Get subpaths. + int getNumSubpaths() { return n; } + GfxSubpath *getSubpath(int i) { return subpaths[i]; } + + // Get last point on last subpath. + double getLastX() { return subpaths[n-1]->getLastX(); } + double getLastY() { return subpaths[n-1]->getLastY(); } + + // Move the current point. + void moveTo(double x, double y); + + // Add a segment to the last subpath. + void lineTo(double x, double y); + + // Add a Bezier curve to the last subpath + void curveTo(double x1, double y1, double x2, double y2, + double x3, double y3); + + // Close the last subpath. + void close(); + + // Append to . + void append(GfxPath *path); + + // Add (, ) to each point in the path. + void offset(double dx, double dy); + +private: + + GBool justMoved; // set if a new subpath was just started + double firstX, firstY; // first point in new subpath + GfxSubpath **subpaths; // subpaths + int n; // number of subpaths + int size; // size of subpaths array + + GfxPath(GBool justMoved1, double firstX1, double firstY1, + GfxSubpath **subpaths1, int n1, int size1); +}; + +//------------------------------------------------------------------------ +// GfxState +//------------------------------------------------------------------------ + +class GfxState { +public: + + // Construct a default GfxState, for a device with resolution + // x , page box , page rotation , and + // coordinate system specified by . + GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox, + int rotateA, GBool upsideDown); + + // Destructor. + ~GfxState(); + + // Copy. + GfxState *copy() { return new GfxState(this); } + + // Accessors. + double getHDPI() { return hDPI; } + double getVDPI() { return vDPI; } + double *getCTM() { return ctm; } + double getX1() { return px1; } + double getY1() { return py1; } + double getX2() { return px2; } + double getY2() { return py2; } + double getPageWidth() { return pageWidth; } + double getPageHeight() { return pageHeight; } + int getRotate() { return rotate; } + GfxColor *getFillColor() { return &fillColor; } + GfxColor *getStrokeColor() { return &strokeColor; } + void getFillGray(GfxGray *gray) + { fillColorSpace->getGray(&fillColor, gray); } + void getStrokeGray(GfxGray *gray) + { strokeColorSpace->getGray(&strokeColor, gray); } + void getFillRGB(GfxRGB *rgb) + { fillColorSpace->getRGB(&fillColor, rgb); } + void getStrokeRGB(GfxRGB *rgb) + { strokeColorSpace->getRGB(&strokeColor, rgb); } + void getFillCMYK(GfxCMYK *cmyk) + { fillColorSpace->getCMYK(&fillColor, cmyk); } + void getStrokeCMYK(GfxCMYK *cmyk) + { strokeColorSpace->getCMYK(&strokeColor, cmyk); } + GfxColorSpace *getFillColorSpace() { return fillColorSpace; } + GfxColorSpace *getStrokeColorSpace() { return strokeColorSpace; } + GfxPattern *getFillPattern() { return fillPattern; } + GfxPattern *getStrokePattern() { return strokePattern; } + GfxBlendMode getBlendMode() { return blendMode; } + double getFillOpacity() { return fillOpacity; } + double getStrokeOpacity() { return strokeOpacity; } + GBool getFillOverprint() { return fillOverprint; } + GBool getStrokeOverprint() { return strokeOverprint; } + Function **getTransfer() { return transfer; } + double getLineWidth() { return lineWidth; } + void getLineDash(double **dash, int *length, double *start) + { *dash = lineDash; *length = lineDashLength; *start = lineDashStart; } + int getFlatness() { return flatness; } + int getLineJoin() { return lineJoin; } + int getLineCap() { return lineCap; } + double getMiterLimit() { return miterLimit; } + GBool getStrokeAdjust() { return strokeAdjust; } + GfxFont *getFont() { return font; } + double getFontSize() { return fontSize; } + double *getTextMat() { return textMat; } + double getCharSpace() { return charSpace; } + double getWordSpace() { return wordSpace; } + double getHorizScaling() { return horizScaling; } + double getLeading() { return leading; } + double getRise() { return rise; } + int getRender() { return render; } + GfxPath *getPath() { return path; } + void setPath(GfxPath *pathA); + double getCurX() { return curX; } + double getCurY() { return curY; } + void getClipBBox(double *xMin, double *yMin, double *xMax, double *yMax) + { *xMin = clipXMin; *yMin = clipYMin; *xMax = clipXMax; *yMax = clipYMax; } + void getUserClipBBox(double *xMin, double *yMin, double *xMax, double *yMax); + double getLineX() { return lineX; } + double getLineY() { return lineY; } + + // Is there a current point/path? + GBool isCurPt() { return path->isCurPt(); } + GBool isPath() { return path->isPath(); } + + // Transforms. + void transform(double x1, double y1, double *x2, double *y2) + { *x2 = ctm[0] * x1 + ctm[2] * y1 + ctm[4]; + *y2 = ctm[1] * x1 + ctm[3] * y1 + ctm[5]; } + void transformDelta(double x1, double y1, double *x2, double *y2) + { *x2 = ctm[0] * x1 + ctm[2] * y1; + *y2 = ctm[1] * x1 + ctm[3] * y1; } + void textTransform(double x1, double y1, double *x2, double *y2) + { *x2 = textMat[0] * x1 + textMat[2] * y1 + textMat[4]; + *y2 = textMat[1] * x1 + textMat[3] * y1 + textMat[5]; } + void textTransformDelta(double x1, double y1, double *x2, double *y2) + { *x2 = textMat[0] * x1 + textMat[2] * y1; + *y2 = textMat[1] * x1 + textMat[3] * y1; } + double transformWidth(double w); + double getTransformedLineWidth() + { return transformWidth(lineWidth); } + double getTransformedFontSize(); + void getFontTransMat(double *m11, double *m12, double *m21, double *m22); + + // Change state parameters. + void setCTM(double a, double b, double c, + double d, double e, double f); + void concatCTM(double a, double b, double c, + double d, double e, double f); + void shiftCTM(double tx, double ty); + void setFillColorSpace(GfxColorSpace *colorSpace); + void setStrokeColorSpace(GfxColorSpace *colorSpace); + void setFillColor(GfxColor *color) { fillColor = *color; } + void setStrokeColor(GfxColor *color) { strokeColor = *color; } + void setFillPattern(GfxPattern *pattern); + void setStrokePattern(GfxPattern *pattern); + void setBlendMode(GfxBlendMode mode) { blendMode = mode; } + void setFillOpacity(double opac) { fillOpacity = opac; } + void setStrokeOpacity(double opac) { strokeOpacity = opac; } + void setFillOverprint(GBool op) { fillOverprint = op; } + void setStrokeOverprint(GBool op) { strokeOverprint = op; } + void setTransfer(Function **funcs); + void setLineWidth(double width) { lineWidth = width; } + void setLineDash(double *dash, int length, double start); + void setFlatness(int flatness1) { flatness = flatness1; } + void setLineJoin(int lineJoin1) { lineJoin = lineJoin1; } + void setLineCap(int lineCap1) { lineCap = lineCap1; } + void setMiterLimit(double limit) { miterLimit = limit; } + void setStrokeAdjust(GBool sa) { strokeAdjust = sa; } + void setFont(GfxFont *fontA, double fontSizeA) + { font = fontA; fontSize = fontSizeA; } + void setTextMat(double a, double b, double c, + double d, double e, double f) + { textMat[0] = a; textMat[1] = b; textMat[2] = c; + textMat[3] = d; textMat[4] = e; textMat[5] = f; } + void setCharSpace(double space) + { charSpace = space; } + void setWordSpace(double space) + { wordSpace = space; } + void setHorizScaling(double scale) + { horizScaling = 0.01 * scale; } + void setLeading(double leadingA) + { leading = leadingA; } + void setRise(double riseA) + { rise = riseA; } + void setRender(int renderA) + { render = renderA; } + + // Add to path. + void moveTo(double x, double y) + { path->moveTo(curX = x, curY = y); } + void lineTo(double x, double y) + { path->lineTo(curX = x, curY = y); } + void curveTo(double x1, double y1, double x2, double y2, + double x3, double y3) + { path->curveTo(x1, y1, x2, y2, curX = x3, curY = y3); } + void closePath() + { path->close(); curX = path->getLastX(); curY = path->getLastY(); } + void clearPath(); + + // Update clip region. + void clip(); + void clipToStrokePath(); + + // Text position. + void textSetPos(double tx, double ty) { lineX = tx; lineY = ty; } + void textMoveTo(double tx, double ty) + { lineX = tx; lineY = ty; textTransform(tx, ty, &curX, &curY); } + void textShift(double tx, double ty); + void shift(double dx, double dy); + + // Push/pop GfxState on/off stack. + GfxState *save(); + GfxState *restore(); + GBool hasSaves() { return saved != NULL; } + + // Misc + GBool parseBlendMode(Object *obj, GfxBlendMode *mode); + +private: + + double hDPI, vDPI; // resolution + double ctm[6]; // coord transform matrix + double px1, py1, px2, py2; // page corners (user coords) + double pageWidth, pageHeight; // page size (pixels) + int rotate; // page rotation angle + + GfxColorSpace *fillColorSpace; // fill color space + GfxColorSpace *strokeColorSpace; // stroke color space + GfxColor fillColor; // fill color + GfxColor strokeColor; // stroke color + GfxPattern *fillPattern; // fill pattern + GfxPattern *strokePattern; // stroke pattern + GfxBlendMode blendMode; // transparency blend mode + double fillOpacity; // fill opacity + double strokeOpacity; // stroke opacity + GBool fillOverprint; // fill overprint + GBool strokeOverprint; // stroke overprint + Function *transfer[4]; // transfer function (entries may be: all + // NULL = identity; last three NULL = + // single function; all four non-NULL = + // R,G,B,gray functions) + + double lineWidth; // line width + double *lineDash; // line dash + int lineDashLength; + double lineDashStart; + int flatness; // curve flatness + int lineJoin; // line join style + int lineCap; // line cap style + double miterLimit; // line miter limit + GBool strokeAdjust; // stroke adjustment + + GfxFont *font; // font + double fontSize; // font size + double textMat[6]; // text matrix + double charSpace; // character spacing + double wordSpace; // word spacing + double horizScaling; // horizontal scaling + double leading; // text leading + double rise; // text rise + int render; // text rendering mode + + GfxPath *path; // array of path elements + double curX, curY; // current point (user coords) + double lineX, lineY; // start of current text line (text coords) + + double clipXMin, clipYMin, // bounding box for clip region + clipXMax, clipYMax; + + GfxState *saved; // next GfxState on stack + + GfxState(GfxState *state); +}; + +#endif diff --git a/kpdf/xpdf/xpdf/GlobalParams.cc b/kpdf/xpdf/xpdf/GlobalParams.cc new file mode 100644 index 00000000..b1083777 --- /dev/null +++ b/kpdf/xpdf/xpdf/GlobalParams.cc @@ -0,0 +1,2989 @@ +//======================================================================== +// +// GlobalParams.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +// KPDF: additional includes for Qt and Xft +#include +#include +#include +// -- gentoo compile fix (XFree 4.3.0, FC 2.2.3, FreeType 2.1.9) -- +// on other distros these 2 lines should't harm +#include +#include FT_FREETYPE_H +// -- ---------------------------------------------------------- -- +#include +#include +#include +#include +#include +#include +#ifdef ENABLE_PLUGINS +# ifndef WIN32 +# include +# endif +#endif +#ifdef WIN32 +# include +#endif +#if HAVE_PAPER_H +#include +#endif +#include "gmem.h" +#include "GString.h" +#include "GList.h" +#include "GHash.h" +#include "gfile.h" +#include "Error.h" +#include "NameToCharCode.h" +#include "CharCodeToUnicode.h" +#include "UnicodeMap.h" +#include "CMap.h" +#include "BuiltinFontTables.h" +#include "FontEncodingTables.h" +#ifdef ENABLE_PLUGINS +# include "XpdfPluginAPI.h" +#endif +#include "GlobalParams.h" + +#include +#include +#include + +#ifdef WIN32 +# define strcasecmp stricmp +#endif + +#if MULTITHREADED +# define lockGlobalParams gLockMutex(&mutex) +# define lockUnicodeMapCache gLockMutex(&unicodeMapCacheMutex) +# define lockCMapCache gLockMutex(&cMapCacheMutex) +# define unlockGlobalParams gUnlockMutex(&mutex) +# define unlockUnicodeMapCache gUnlockMutex(&unicodeMapCacheMutex) +# define unlockCMapCache gUnlockMutex(&cMapCacheMutex) +#else +# define lockGlobalParams +# define lockUnicodeMapCache +# define lockCMapCache +# define unlockGlobalParams +# define unlockUnicodeMapCache +# define unlockCMapCache +#endif + +#include "NameToUnicodeTable.h" +#include "UnicodeMapTables.h" +#include "UTF8.h" + +#ifdef ENABLE_PLUGINS +# ifdef WIN32 +extern XpdfPluginVecTable xpdfPluginVecTable; +# endif +#endif + +//------------------------------------------------------------------------ + +#define cidToUnicodeCacheSize 4 +#define unicodeToUnicodeCacheSize 4 + +//------------------------------------------------------------------------ + +static struct { + char *name; + char *t1FileName; + char *ttFileName; +} displayFontTab[] = { + {"Courier", "n022003l.pfb", "cour.ttf"}, + {"Courier-Bold", "n022004l.pfb", "courbd.ttf"}, + {"Courier-BoldOblique", "n022024l.pfb", "courbi.ttf"}, + {"Courier-Oblique", "n022023l.pfb", "couri.ttf"}, + {"Helvetica", "n019003l.pfb", "arial.ttf"}, + {"Helvetica-Bold", "n019004l.pfb", "arialbd.ttf"}, + {"Helvetica-BoldOblique", "n019024l.pfb", "arialbi.ttf"}, + {"Helvetica-Oblique", "n019023l.pfb", "ariali.ttf"}, + {"Symbol", "s050000l.pfb", NULL}, + {"Times-Bold", "n021004l.pfb", "timesbd.ttf"}, + {"Times-BoldItalic", "n021024l.pfb", "timesbi.ttf"}, + {"Times-Italic", "n021023l.pfb", "timesi.ttf"}, + {"Times-Roman", "n021003l.pfb", "times.ttf"}, + {"ZapfDingbats", "d050000l.pfb", NULL}, + {NULL, NULL, NULL} +}; + +#ifdef WIN32 +static char *displayFontDirs[] = { + "c:/windows/fonts", + "c:/winnt/fonts", + NULL +}; +#else +static char *displayFontDirs[] = { + "/usr/share/ghostscript/fonts", + "/usr/pkg/share/ghostscript/fonts", + "/usr/local/share/ghostscript/fonts", + "/usr/share/fonts/default/Type1", + "/usr/X11R6/lib/X11/fonts/Type1", + "/usr/share/fonts/default/ghostscript", + "/usr/share/fonts/type1/gsfonts", + "/usr/share/fonts/Type1", + NULL +}; +#endif + +//------------------------------------------------------------------------ + +GlobalParams *globalParams = NULL; + +//------------------------------------------------------------------------ +// DisplayFontParam +//------------------------------------------------------------------------ + +DisplayFontParam::DisplayFontParam(GString *nameA, + DisplayFontParamKind kindA) { + name = nameA; + kind = kindA; + switch (kind) { + case displayFontT1: + t1.fileName = NULL; + break; + case displayFontTT: + tt.fileName = NULL; + break; + } +} + +DisplayFontParam::~DisplayFontParam() { + delete name; + switch (kind) { + case displayFontT1: + if (t1.fileName) { + delete t1.fileName; + } + break; + case displayFontTT: + if (tt.fileName) { + delete tt.fileName; + } + break; + } +} + +#ifdef WIN32 + +//------------------------------------------------------------------------ +// WinFontInfo +//------------------------------------------------------------------------ + +class WinFontInfo: public DisplayFontParam { +public: + + GBool bold, italic; + + static WinFontInfo *make(GString *nameA, GBool boldA, GBool italicA, + HKEY regKey, char *winFontDir); + WinFontInfo(GString *nameA, GBool boldA, GBool italicA, + GString *fileNameA); + virtual ~WinFontInfo(); + GBool equals(WinFontInfo *fi); +}; + +WinFontInfo *WinFontInfo::make(GString *nameA, GBool boldA, GBool italicA, + HKEY regKey, char *winFontDir) { + GString *regName; + GString *fileNameA; + char buf[MAX_PATH]; + DWORD n; + char c; + int i; + + //----- find the font file + fileNameA = NULL; + regName = nameA->copy(); + if (boldA) { + regName->append(" Bold"); + } + if (italicA) { + regName->append(" Italic"); + } + regName->append(" (TrueType)"); + n = sizeof(buf); + if (RegQueryValueEx(regKey, regName->getCString(), NULL, NULL, + (LPBYTE)buf, &n) == ERROR_SUCCESS) { + fileNameA = new GString(winFontDir); + fileNameA->append('\\')->append(buf); + } + delete regName; + if (!fileNameA) { + delete nameA; + return NULL; + } + + //----- normalize the font name + i = 0; + while (i < nameA->getLength()) { + c = nameA->getChar(i); + if (c == ' ' || c == ',' || c == '-') { + nameA->del(i); + } else { + ++i; + } + } + + return new WinFontInfo(nameA, boldA, italicA, fileNameA); +} + +WinFontInfo::WinFontInfo(GString *nameA, GBool boldA, GBool italicA, + GString *fileNameA): + DisplayFontParam(nameA, displayFontTT) +{ + bold = boldA; + italic = italicA; + tt.fileName = fileNameA; +} + +WinFontInfo::~WinFontInfo() { +} + +GBool WinFontInfo::equals(WinFontInfo *fi) { + return !name->cmp(fi->name) && bold == fi->bold && italic == fi->italic; +} + +//------------------------------------------------------------------------ +// WinFontList +//------------------------------------------------------------------------ + +class WinFontList { +public: + + WinFontList(char *winFontDirA); + ~WinFontList(); + WinFontInfo *find(GString *font); + +private: + + void add(WinFontInfo *fi); + static int CALLBACK enumFunc1(CONST LOGFONT *font, + CONST TEXTMETRIC *metrics, + DWORD type, LPARAM data); + static int CALLBACK enumFunc2(CONST LOGFONT *font, + CONST TEXTMETRIC *metrics, + DWORD type, LPARAM data); + + GList *fonts; // [WinFontInfo] + HDC dc; // (only used during enumeration) + HKEY regKey; // (only used during enumeration) + char *winFontDir; // (only used during enumeration) +}; + +WinFontList::WinFontList(char *winFontDirA) { + OSVERSIONINFO version; + char *path; + + fonts = new GList(); + dc = GetDC(NULL); + winFontDir = winFontDirA; + version.dwOSVersionInfoSize = sizeof(version); + GetVersionEx(&version); + if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) { + path = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\\"; + } else { + path = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts\\"; + } + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0, + KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, + ®Key) == ERROR_SUCCESS) { + EnumFonts(dc, NULL, &WinFontList::enumFunc1, (LPARAM)this); + RegCloseKey(regKey); + } + ReleaseDC(NULL, dc); +} + +WinFontList::~WinFontList() { + deleteGList(fonts, WinFontInfo); +} + +void WinFontList::add(WinFontInfo *fi) { + int i; + + for (i = 0; i < fonts->getLength(); ++i) { + if (((WinFontInfo *)fonts->get(i))->equals(fi)) { + delete fi; + return; + } + } + fonts->append(fi); +} + +WinFontInfo *WinFontList::find(GString *font) { + GString *name; + GBool bold, italic; + WinFontInfo *fi; + char c; + int n, i; + + name = font->copy(); + + // remove space, comma, dash chars + i = 0; + while (i < name->getLength()) { + c = name->getChar(i); + if (c == ' ' || c == ',' || c == '-') { + name->del(i); + } else { + ++i; + } + } + n = name->getLength(); + + // remove trailing "MT" (Foo-MT, Foo-BoldMT, etc.) + if (!strcmp(name->getCString() + n - 2, "MT")) { + name->del(n - 2, 2); + n -= 2; + } + + // look for "Italic" + if (!strcmp(name->getCString() + n - 6, "Italic")) { + name->del(n - 6, 6); + italic = gTrue; + n -= 6; + } else { + italic = gFalse; + } + + // look for "Bold" + if (!strcmp(name->getCString() + n - 4, "Bold")) { + name->del(n - 4, 4); + bold = gTrue; + n -= 4; + } else { + bold = gFalse; + } + + // remove trailing "MT" (FooMT-Bold, etc.) + if (!strcmp(name->getCString() + n - 2, "MT")) { + name->del(n - 2, 2); + n -= 2; + } + + // remove trailing "PS" + if (!strcmp(name->getCString() + n - 2, "PS")) { + name->del(n - 2, 2); + n -= 2; + } + + // search for the font + fi = NULL; + for (i = 0; i < fonts->getLength(); ++i) { + fi = (WinFontInfo *)fonts->get(i); + if (!fi->name->cmp(name) && fi->bold == bold && fi->italic == italic) { + break; + } + fi = NULL; + } + + delete name; + return fi; +} + +int CALLBACK WinFontList::enumFunc1(CONST LOGFONT *font, + CONST TEXTMETRIC *metrics, + DWORD type, LPARAM data) { + WinFontList *fl = (WinFontList *)data; + + EnumFonts(fl->dc, font->lfFaceName, &WinFontList::enumFunc2, (LPARAM)fl); + return 1; +} + +int CALLBACK WinFontList::enumFunc2(CONST LOGFONT *font, + CONST TEXTMETRIC *metrics, + DWORD type, LPARAM data) { + WinFontList *fl = (WinFontList *)data; + WinFontInfo *fi; + + if (type & TRUETYPE_FONTTYPE) { + if ((fi = WinFontInfo::make(new GString(font->lfFaceName), + font->lfWeight >= 600, + font->lfItalic ? gTrue : gFalse, + fl->regKey, fl->winFontDir))) { + fl->add(fi); + } + } + return 1; +} + +#endif // WIN32 + +//------------------------------------------------------------------------ +// PSFontParam +//------------------------------------------------------------------------ + +PSFontParam::PSFontParam(GString *pdfFontNameA, int wModeA, + GString *psFontNameA, GString *encodingA) { + pdfFontName = pdfFontNameA; + wMode = wModeA; + psFontName = psFontNameA; + encoding = encodingA; +} + +PSFontParam::~PSFontParam() { + delete pdfFontName; + delete psFontName; + if (encoding) { + delete encoding; + } +} + +//------------------------------------------------------------------------ +// KeyBinding +//------------------------------------------------------------------------ + +KeyBinding::KeyBinding(int codeA, int modsA, int contextA, char *cmd0) { + code = codeA; + mods = modsA; + context = contextA; + cmds = new GList(); + cmds->append(new GString(cmd0)); +} + +KeyBinding::KeyBinding(int codeA, int modsA, int contextA, + char *cmd0, char *cmd1) { + code = codeA; + mods = modsA; + context = contextA; + cmds = new GList(); + cmds->append(new GString(cmd0)); + cmds->append(new GString(cmd1)); +} + +KeyBinding::KeyBinding(int codeA, int modsA, int contextA, GList *cmdsA) { + code = codeA; + mods = modsA; + context = contextA; + cmds = cmdsA; +} + +KeyBinding::~KeyBinding() { + deleteGList(cmds, GString); +} + +#ifdef ENABLE_PLUGINS +//------------------------------------------------------------------------ +// Plugin +//------------------------------------------------------------------------ + +class Plugin { +public: + + static Plugin *load(char *type, char *name); + ~Plugin(); + +private: + +#ifdef WIN32 + Plugin(HMODULE libA); + HMODULE lib; +#else + Plugin(void *dlA); + void *dl; +#endif +}; + +Plugin *Plugin::load(char *type, char *name) { + GString *path; + Plugin *plugin; + XpdfPluginVecTable *vt; + XpdfBool (*xpdfInitPlugin)(void); +#ifdef WIN32 + HMODULE libA; +#else + void *dlA; +#endif + + path = globalParams->getBaseDir(); + appendToPath(path, "plugins"); + appendToPath(path, type); + appendToPath(path, name); + +#ifdef WIN32 + path->append(".dll"); + if (!(libA = LoadLibrary(path->getCString()))) { + error(-1, "Failed to load plugin '%s'", + path->getCString()); + goto err1; + } + if (!(vt = (XpdfPluginVecTable *) + GetProcAddress(libA, "xpdfPluginVecTable"))) { + error(-1, "Failed to find xpdfPluginVecTable in plugin '%s'", + path->getCString()); + goto err2; + } +#else + //~ need to deal with other extensions here + path->append(".so"); + if (!(dlA = dlopen(path->getCString(), RTLD_NOW))) { + error(-1, "Failed to load plugin '%s': %s", + path->getCString(), dlerror()); + goto err1; + } + if (!(vt = (XpdfPluginVecTable *)dlsym(dlA, "xpdfPluginVecTable"))) { + error(-1, "Failed to find xpdfPluginVecTable in plugin '%s'", + path->getCString()); + goto err2; + } +#endif + + if (vt->version != xpdfPluginVecTable.version) { + error(-1, "Plugin '%s' is wrong version", path->getCString()); + goto err2; + } + memcpy(vt, &xpdfPluginVecTable, sizeof(xpdfPluginVecTable)); + +#ifdef WIN32 + if (!(xpdfInitPlugin = (XpdfBool (*)(void)) + GetProcAddress(libA, "xpdfInitPlugin"))) { + error(-1, "Failed to find xpdfInitPlugin in plugin '%s'", + path->getCString()); + goto err2; + } +#else + if (!(xpdfInitPlugin = (XpdfBool (*)(void))dlsym(dlA, "xpdfInitPlugin"))) { + error(-1, "Failed to find xpdfInitPlugin in plugin '%s'", + path->getCString()); + goto err2; + } +#endif + + if (!(*xpdfInitPlugin)()) { + error(-1, "Initialization of plugin '%s' failed", + path->getCString()); + goto err2; + } + +#ifdef WIN32 + plugin = new Plugin(libA); +#else + plugin = new Plugin(dlA); +#endif + + delete path; + return plugin; + + err2: +#ifdef WIN32 + FreeLibrary(libA); +#else + dlclose(dlA); +#endif + err1: + delete path; + return NULL; +} + +#ifdef WIN32 +Plugin::Plugin(HMODULE libA) { + lib = libA; +} +#else +Plugin::Plugin(void *dlA) { + dl = dlA; +} +#endif + +Plugin::~Plugin() { + void (*xpdfFreePlugin)(void); + +#ifdef WIN32 + if ((xpdfFreePlugin = (void (*)(void)) + GetProcAddress(lib, "xpdfFreePlugin"))) { + (*xpdfFreePlugin)(); + } + FreeLibrary(lib); +#else + if ((xpdfFreePlugin = (void (*)(void))dlsym(dl, "xpdfFreePlugin"))) { + (*xpdfFreePlugin)(); + } + dlclose(dl); +#endif +} + +#endif // ENABLE_PLUGINS + +//------------------------------------------------------------------------ +// parsing +//------------------------------------------------------------------------ + +GlobalParams::GlobalParams(char *cfgFileName) { + UnicodeMap *map; + GString *fileName; + FILE *f; + int i; + +#if MULTITHREADED + gInitMutex(&mutex); + gInitMutex(&unicodeMapCacheMutex); + gInitMutex(&cMapCacheMutex); +#endif + + initBuiltinFontTables(); + + // scan the encoding in reverse because we want the lowest-numbered + // index for each char name ('space' is encoded twice) + macRomanReverseMap = new NameToCharCode(); + for (i = 255; i >= 0; --i) { + if (macRomanEncoding[i]) { + macRomanReverseMap->add(macRomanEncoding[i], (CharCode)i); + } + } + +#ifdef WIN32 + // baseDir will be set by a call to setBaseDir + baseDir = new GString(); +#else + baseDir = appendToPath(getHomeDir(), ".xpdf"); +#endif + nameToUnicode = new NameToCharCode(); + cidToUnicodes = new GHash(gTrue); + unicodeToUnicodes = new GHash(gTrue); + residentUnicodeMaps = new GHash(); + unicodeMaps = new GHash(gTrue); + cMapDirs = new GHash(gTrue); + toUnicodeDirs = new GList(); + displayFonts = new GHash(); + displayCIDFonts = new GHash(); + displayNamedCIDFonts = new GHash(); +#if HAVE_PAPER_H + char *paperName; + const struct paper *paperType; + paperinit(); + if ((paperName = systempapername())) { + paperType = paperinfo(paperName); + psPaperWidth = (int)paperpswidth(paperType); + psPaperHeight = (int)paperpsheight(paperType); + } else { + error(-1, "No paper information available - using defaults"); + psPaperWidth = defPaperWidth; + psPaperHeight = defPaperHeight; + } + paperdone(); +#else + psPaperWidth = defPaperWidth; + psPaperHeight = defPaperHeight; +#endif + psImageableLLX = psImageableLLY = 0; + psImageableURX = psPaperWidth; + psImageableURY = psPaperHeight; + psCrop = gTrue; + psExpandSmaller = gFalse; + psShrinkLarger = gTrue; + psCenter = gTrue; + psDuplex = gFalse; + psLevel = psLevel2; + psFile = NULL; + psFonts = new GHash(); + psNamedFonts16 = new GList(); + psFonts16 = new GList(); + psEmbedType1 = gTrue; + psEmbedTrueType = gTrue; + psEmbedCIDPostScript = gTrue; + psEmbedCIDTrueType = gTrue; + psPreload = gFalse; + psOPI = gFalse; + psASCIIHex = gFalse; + // KPDF: use always UTF-8 and QString::fromUtf + textEncoding = new GString("UTF-8"); +#if defined(WIN32) + textEOL = eolDOS; +#elif defined(MACOS) + textEOL = eolMac; +#else + textEOL = eolUnix; +#endif + textPageBreaks = gTrue; + textKeepTinyChars = gFalse; + fontDirs = new GList(); + initialZoom = new GString("125"); + continuousView = gFalse; + enableT1lib = gTrue; + enableFreeType = gTrue; + antialias = gTrue; + vectorAntialias = gTrue; + strokeAdjust = gTrue; + screenType = screenUnset; + screenSize = -1; + screenDotRadius = -1; + screenGamma = 1.0; + screenBlackThreshold = 0.0; + screenWhiteThreshold = 1.0; + urlCommand = NULL; + movieCommand = NULL; + mapNumericCharNames = gTrue; + mapUnknownCharNames = gFalse; + createDefaultKeyBindings(); + printCommands = gFalse; + errQuiet = gFalse; + + cidToUnicodeCache = new CharCodeToUnicodeCache(cidToUnicodeCacheSize); + unicodeToUnicodeCache = + new CharCodeToUnicodeCache(unicodeToUnicodeCacheSize); + unicodeMapCache = new UnicodeMapCache(); + cMapCache = new CMapCache(); + +#ifdef WIN32 + winFontList = NULL; +#endif + +#ifdef ENABLE_PLUGINS + plugins = new GList(); + securityHandlers = new GList(); +#endif + + // set up the initial nameToUnicode table + for (i = 0; nameToUnicodeTab[i].name; ++i) { + nameToUnicode->add(nameToUnicodeTab[i].name, nameToUnicodeTab[i].u); + } + + // set up the residentUnicodeMaps table + map = new UnicodeMap("Latin1", gFalse, + latin1UnicodeMapRanges, latin1UnicodeMapLen); + residentUnicodeMaps->add(map->getEncodingName(), map); + map = new UnicodeMap("ASCII7", gFalse, + ascii7UnicodeMapRanges, ascii7UnicodeMapLen); + residentUnicodeMaps->add(map->getEncodingName(), map); + map = new UnicodeMap("Symbol", gFalse, + symbolUnicodeMapRanges, symbolUnicodeMapLen); + residentUnicodeMaps->add(map->getEncodingName(), map); + map = new UnicodeMap("ZapfDingbats", gFalse, zapfDingbatsUnicodeMapRanges, + zapfDingbatsUnicodeMapLen); + residentUnicodeMaps->add(map->getEncodingName(), map); + map = new UnicodeMap("UTF-8", gTrue, &mapUTF8); + residentUnicodeMaps->add(map->getEncodingName(), map); + map = new UnicodeMap("UCS-2", gTrue, &mapUCS2); + residentUnicodeMaps->add(map->getEncodingName(), map); + + // look for a user config file, then a system-wide config file + f = NULL; + fileName = NULL; + if (cfgFileName && cfgFileName[0]) { + fileName = new GString(cfgFileName); + if (!(f = fopen(fileName->getCString(), "r"))) { + delete fileName; + } + } + if (!f) { + fileName = appendToPath(getHomeDir(), xpdfUserConfigFile); + if (!(f = fopen(fileName->getCString(), "r"))) { + delete fileName; + } + } + if (!f) { +#if defined(WIN32) && !defined(__CYGWIN32__) + char buf[512]; + i = GetModuleFileName(NULL, buf, sizeof(buf)); + if (i <= 0 || i >= sizeof(buf)) { + // error or path too long for buffer - just use the current dir + buf[0] = '\0'; + } + fileName = grabPath(buf); + appendToPath(fileName, xpdfSysConfigFile); +#else + fileName = new GString(xpdfSysConfigFile); +#endif + if (!(f = fopen(fileName->getCString(), "r"))) { + delete fileName; + } + } + if (f) { + parseFile(fileName, f); + delete fileName; + fclose(f); + } +} + +void GlobalParams::createDefaultKeyBindings() { + keyBindings = new GList(); + + //----- mouse buttons + keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress1, xpdfKeyModNone, + xpdfKeyContextAny, "startSelection")); + keyBindings->append(new KeyBinding(xpdfKeyCodeMouseRelease1, xpdfKeyModNone, + xpdfKeyContextAny, "endSelection", + "followLinkNoSel")); + keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress2, xpdfKeyModNone, + xpdfKeyContextAny, "startPan")); + keyBindings->append(new KeyBinding(xpdfKeyCodeMouseRelease2, xpdfKeyModNone, + xpdfKeyContextAny, "endPan")); + keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress3, xpdfKeyModNone, + xpdfKeyContextAny, "postPopupMenu")); + keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress4, xpdfKeyModNone, + xpdfKeyContextAny, + "scrollUpPrevPage(16)")); + keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress5, xpdfKeyModNone, + xpdfKeyContextAny, + "scrollDownNextPage(16)")); + keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress6, xpdfKeyModNone, + xpdfKeyContextAny, "scrollLeft(16)")); + keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress7, xpdfKeyModNone, + xpdfKeyContextAny, "scrollRight(16)")); + + //----- keys + keyBindings->append(new KeyBinding(xpdfKeyCodeHome, xpdfKeyModCtrl, + xpdfKeyContextAny, "gotoPage(1)")); + keyBindings->append(new KeyBinding(xpdfKeyCodeHome, xpdfKeyModNone, + xpdfKeyContextAny, "scrollToTopLeft")); + keyBindings->append(new KeyBinding(xpdfKeyCodeEnd, xpdfKeyModCtrl, + xpdfKeyContextAny, "gotoLastPage")); + keyBindings->append(new KeyBinding(xpdfKeyCodeEnd, xpdfKeyModNone, + xpdfKeyContextAny, + "scrollToBottomRight")); + keyBindings->append(new KeyBinding(xpdfKeyCodePgUp, xpdfKeyModNone, + xpdfKeyContextAny, "pageUp")); + keyBindings->append(new KeyBinding(xpdfKeyCodeBackspace, xpdfKeyModNone, + xpdfKeyContextAny, "pageUp")); + keyBindings->append(new KeyBinding(xpdfKeyCodeDelete, xpdfKeyModNone, + xpdfKeyContextAny, "pageUp")); + keyBindings->append(new KeyBinding(xpdfKeyCodePgDn, xpdfKeyModNone, + xpdfKeyContextAny, "pageDown")); + keyBindings->append(new KeyBinding(' ', xpdfKeyModNone, + xpdfKeyContextAny, "pageDown")); + keyBindings->append(new KeyBinding(xpdfKeyCodeLeft, xpdfKeyModNone, + xpdfKeyContextAny, "scrollLeft(16)")); + keyBindings->append(new KeyBinding(xpdfKeyCodeRight, xpdfKeyModNone, + xpdfKeyContextAny, "scrollRight(16)")); + keyBindings->append(new KeyBinding(xpdfKeyCodeUp, xpdfKeyModNone, + xpdfKeyContextAny, "scrollUp(16)")); + keyBindings->append(new KeyBinding(xpdfKeyCodeDown, xpdfKeyModNone, + xpdfKeyContextAny, "scrollDown(16)")); + keyBindings->append(new KeyBinding('o', xpdfKeyModNone, + xpdfKeyContextAny, "open")); + keyBindings->append(new KeyBinding('O', xpdfKeyModNone, + xpdfKeyContextAny, "open")); + keyBindings->append(new KeyBinding('r', xpdfKeyModNone, + xpdfKeyContextAny, "reload")); + keyBindings->append(new KeyBinding('R', xpdfKeyModNone, + xpdfKeyContextAny, "reload")); + keyBindings->append(new KeyBinding('f', xpdfKeyModNone, + xpdfKeyContextAny, "find")); + keyBindings->append(new KeyBinding('F', xpdfKeyModNone, + xpdfKeyContextAny, "find")); + keyBindings->append(new KeyBinding('f', xpdfKeyModCtrl, + xpdfKeyContextAny, "find")); + keyBindings->append(new KeyBinding('g', xpdfKeyModCtrl, + xpdfKeyContextAny, "findNext")); + keyBindings->append(new KeyBinding('p', xpdfKeyModCtrl, + xpdfKeyContextAny, "print")); + keyBindings->append(new KeyBinding('n', xpdfKeyModNone, + xpdfKeyContextScrLockOff, "nextPage")); + keyBindings->append(new KeyBinding('N', xpdfKeyModNone, + xpdfKeyContextScrLockOff, "nextPage")); + keyBindings->append(new KeyBinding('n', xpdfKeyModNone, + xpdfKeyContextScrLockOn, + "nextPageNoScroll")); + keyBindings->append(new KeyBinding('N', xpdfKeyModNone, + xpdfKeyContextScrLockOn, + "nextPageNoScroll")); + keyBindings->append(new KeyBinding('p', xpdfKeyModNone, + xpdfKeyContextScrLockOff, "prevPage")); + keyBindings->append(new KeyBinding('P', xpdfKeyModNone, + xpdfKeyContextScrLockOff, "prevPage")); + keyBindings->append(new KeyBinding('p', xpdfKeyModNone, + xpdfKeyContextScrLockOn, + "prevPageNoScroll")); + keyBindings->append(new KeyBinding('P', xpdfKeyModNone, + xpdfKeyContextScrLockOn, + "prevPageNoScroll")); + keyBindings->append(new KeyBinding('v', xpdfKeyModNone, + xpdfKeyContextAny, "goForward")); + keyBindings->append(new KeyBinding('b', xpdfKeyModNone, + xpdfKeyContextAny, "goBackward")); + keyBindings->append(new KeyBinding('g', xpdfKeyModNone, + xpdfKeyContextAny, "focusToPageNum")); + keyBindings->append(new KeyBinding('0', xpdfKeyModNone, + xpdfKeyContextAny, "zoomPercent(125)")); + keyBindings->append(new KeyBinding('+', xpdfKeyModNone, + xpdfKeyContextAny, "zoomIn")); + keyBindings->append(new KeyBinding('-', xpdfKeyModNone, + xpdfKeyContextAny, "zoomOut")); + keyBindings->append(new KeyBinding('z', xpdfKeyModNone, + xpdfKeyContextAny, "zoomFitPage")); + keyBindings->append(new KeyBinding('w', xpdfKeyModNone, + xpdfKeyContextAny, "zoomFitWidth")); + keyBindings->append(new KeyBinding('f', xpdfKeyModAlt, + xpdfKeyContextAny, + "toggleFullScreenMode")); + keyBindings->append(new KeyBinding('l', xpdfKeyModCtrl, + xpdfKeyContextAny, "redraw")); + keyBindings->append(new KeyBinding('w', xpdfKeyModCtrl, + xpdfKeyContextAny, "closeWindow")); + keyBindings->append(new KeyBinding('?', xpdfKeyModNone, + xpdfKeyContextAny, "about")); + keyBindings->append(new KeyBinding('q', xpdfKeyModNone, + xpdfKeyContextAny, "quit")); + keyBindings->append(new KeyBinding('Q', xpdfKeyModNone, + xpdfKeyContextAny, "quit")); +} + +void GlobalParams::parseFile(GString *fileName, FILE *f) { + int line; + char buf[512]; + + line = 1; + while (getLine(buf, sizeof(buf) - 1, f)) { + parseLine(buf, fileName, line); + ++line; + } +} + +void GlobalParams::parseLine(char *buf, GString *fileName, int line) { + GList *tokens; + GString *cmd, *incFile; + char *p1, *p2; + FILE *f2; + + // break the line into tokens + tokens = new GList(); + p1 = buf; + while (*p1) { + for (; *p1 && isspace(*p1); ++p1) ; + if (!*p1) { + break; + } + if (*p1 == '"' || *p1 == '\'') { + for (p2 = p1 + 1; *p2 && *p2 != *p1; ++p2) ; + ++p1; + } else { + for (p2 = p1 + 1; *p2 && !isspace(*p2); ++p2) ; + } + tokens->append(new GString(p1, p2 - p1)); + p1 = *p2 ? p2 + 1 : p2; + } + + // parse the line + if (tokens->getLength() > 0 && + ((GString *)tokens->get(0))->getChar(0) != '#') { + cmd = (GString *)tokens->get(0); + if (!cmd->cmp("include")) { + if (tokens->getLength() == 2) { + incFile = (GString *)tokens->get(1); + if ((f2 = fopen(incFile->getCString(), "r"))) { + parseFile(incFile, f2); + fclose(f2); + } else { + error(-1, "Couldn't find included config file: '%s' (%s:%d)", + incFile->getCString(), fileName->getCString(), line); + } + } else { + error(-1, "Bad 'include' config file command (%s:%d)", + fileName->getCString(), line); + } + } else if (!cmd->cmp("nameToUnicode")) { + parseNameToUnicode(tokens, fileName, line); + } else if (!cmd->cmp("cidToUnicode")) { + parseCIDToUnicode(tokens, fileName, line); + } else if (!cmd->cmp("unicodeToUnicode")) { + parseUnicodeToUnicode(tokens, fileName, line); + } else if (!cmd->cmp("unicodeMap")) { + parseUnicodeMap(tokens, fileName, line); + } else if (!cmd->cmp("cMapDir")) { + parseCMapDir(tokens, fileName, line); + } else if (!cmd->cmp("toUnicodeDir")) { + parseToUnicodeDir(tokens, fileName, line); + } else if (!cmd->cmp("displayFontT1")) { + parseDisplayFont(tokens, displayFonts, displayFontT1, fileName, line); + } else if (!cmd->cmp("displayFontTT")) { + parseDisplayFont(tokens, displayFonts, displayFontTT, fileName, line); + } else if (!cmd->cmp("displayNamedCIDFontT1")) { + parseDisplayFont(tokens, displayNamedCIDFonts, + displayFontT1, fileName, line); + } else if (!cmd->cmp("displayCIDFontT1")) { + parseDisplayFont(tokens, displayCIDFonts, + displayFontT1, fileName, line); + } else if (!cmd->cmp("displayNamedCIDFontTT")) { + parseDisplayFont(tokens, displayNamedCIDFonts, + displayFontTT, fileName, line); + } else if (!cmd->cmp("displayCIDFontTT")) { + parseDisplayFont(tokens, displayCIDFonts, + displayFontTT, fileName, line); + } else if (!cmd->cmp("psFile")) { + parsePSFile(tokens, fileName, line); + } else if (!cmd->cmp("psFont")) { + parsePSFont(tokens, fileName, line); + } else if (!cmd->cmp("psNamedFont16")) { + parsePSFont16("psNamedFont16", psNamedFonts16, + tokens, fileName, line); + } else if (!cmd->cmp("psFont16")) { + parsePSFont16("psFont16", psFonts16, tokens, fileName, line); + } else if (!cmd->cmp("psPaperSize")) { + parsePSPaperSize(tokens, fileName, line); + } else if (!cmd->cmp("psImageableArea")) { + parsePSImageableArea(tokens, fileName, line); + } else if (!cmd->cmp("psCrop")) { + parseYesNo("psCrop", &psCrop, tokens, fileName, line); + } else if (!cmd->cmp("psExpandSmaller")) { + parseYesNo("psExpandSmaller", &psExpandSmaller, + tokens, fileName, line); + } else if (!cmd->cmp("psShrinkLarger")) { + parseYesNo("psShrinkLarger", &psShrinkLarger, tokens, fileName, line); + } else if (!cmd->cmp("psCenter")) { + parseYesNo("psCenter", &psCenter, tokens, fileName, line); + } else if (!cmd->cmp("psDuplex")) { + parseYesNo("psDuplex", &psDuplex, tokens, fileName, line); + } else if (!cmd->cmp("psLevel")) { + parsePSLevel(tokens, fileName, line); + } else if (!cmd->cmp("psEmbedType1Fonts")) { + parseYesNo("psEmbedType1", &psEmbedType1, tokens, fileName, line); + } else if (!cmd->cmp("psEmbedTrueTypeFonts")) { + parseYesNo("psEmbedTrueType", &psEmbedTrueType, + tokens, fileName, line); + } else if (!cmd->cmp("psEmbedCIDPostScriptFonts")) { + parseYesNo("psEmbedCIDPostScript", &psEmbedCIDPostScript, + tokens, fileName, line); + } else if (!cmd->cmp("psEmbedCIDTrueTypeFonts")) { + parseYesNo("psEmbedCIDTrueType", &psEmbedCIDTrueType, + tokens, fileName, line); + } else if (!cmd->cmp("psPreload")) { + parseYesNo("psPreload", &psPreload, tokens, fileName, line); + } else if (!cmd->cmp("psOPI")) { + parseYesNo("psOPI", &psOPI, tokens, fileName, line); + } else if (!cmd->cmp("psASCIIHex")) { + parseYesNo("psASCIIHex", &psASCIIHex, tokens, fileName, line); + } else if (!cmd->cmp("textEncoding")) { +// Always use UTF-8 and allow QString do the magic +// parseTextEncoding(tokens, fileName, line); + } else if (!cmd->cmp("textEOL")) { + parseTextEOL(tokens, fileName, line); + } else if (!cmd->cmp("textPageBreaks")) { + parseYesNo("textPageBreaks", &textPageBreaks, + tokens, fileName, line); + } else if (!cmd->cmp("textKeepTinyChars")) { + parseYesNo("textKeepTinyChars", &textKeepTinyChars, + tokens, fileName, line); + } else if (!cmd->cmp("fontDir")) { + parseFontDir(tokens, fileName, line); + } else if (!cmd->cmp("initialZoom")) { + parseInitialZoom(tokens, fileName, line); + } else if (!cmd->cmp("continuousView")) { + parseYesNo("continuousView", &continuousView, tokens, fileName, line); + } else if (!cmd->cmp("enableT1lib")) { + parseYesNo("enableT1lib", &enableT1lib, tokens, fileName, line); + } else if (!cmd->cmp("enableFreeType")) { + parseYesNo("enableFreeType", &enableFreeType, tokens, fileName, line); + } else if (!cmd->cmp("antialias")) { + parseYesNo("antialias", &antialias, tokens, fileName, line); + } else if (!cmd->cmp("vectorAntialias")) { + parseYesNo("vectorAntialias", &vectorAntialias, + tokens, fileName, line); + } else if (!cmd->cmp("strokeAdjust")) { + parseYesNo("strokeAdjust", &strokeAdjust, tokens, fileName, line); + } else if (!cmd->cmp("screenType")) { + parseScreenType(tokens, fileName, line); + } else if (!cmd->cmp("screenSize")) { + parseInteger("screenSize", &screenSize, tokens, fileName, line); + } else if (!cmd->cmp("screenDotRadius")) { + parseInteger("screenDotRadius", &screenDotRadius, + tokens, fileName, line); + } else if (!cmd->cmp("screenGamma")) { + parseFloat("screenGamma", &screenGamma, + tokens, fileName, line); + } else if (!cmd->cmp("screenBlackThreshold")) { + parseFloat("screenBlackThreshold", &screenBlackThreshold, + tokens, fileName, line); + } else if (!cmd->cmp("screenWhiteThreshold")) { + parseFloat("screenWhiteThreshold", &screenWhiteThreshold, + tokens, fileName, line); + } else if (!cmd->cmp("urlCommand")) { + parseCommand("urlCommand", &urlCommand, tokens, fileName, line); + } else if (!cmd->cmp("movieCommand")) { + parseCommand("movieCommand", &movieCommand, tokens, fileName, line); + } else if (!cmd->cmp("mapNumericCharNames")) { + parseYesNo("mapNumericCharNames", &mapNumericCharNames, + tokens, fileName, line); + } else if (!cmd->cmp("mapUnknownCharNames")) { + parseYesNo("mapUnknownCharNames", &mapUnknownCharNames, + tokens, fileName, line); + } else if (!cmd->cmp("bind")) { + parseBind(tokens, fileName, line); + } else if (!cmd->cmp("unbind")) { + parseUnbind(tokens, fileName, line); + } else if (!cmd->cmp("printCommands")) { + parseYesNo("printCommands", &printCommands, tokens, fileName, line); + } else if (!cmd->cmp("errQuiet")) { + parseYesNo("errQuiet", &errQuiet, tokens, fileName, line); + } else { + error(-1, "Unknown config file command '%s' (%s:%d)", + cmd->getCString(), fileName->getCString(), line); + if (!cmd->cmp("displayFontX") || + !cmd->cmp("displayNamedCIDFontX") || + !cmd->cmp("displayCIDFontX")) { + error(-1, "-- Xpdf no longer supports X fonts"); + } else if (!cmd->cmp("t1libControl") || !cmd->cmp("freetypeControl")) { + error(-1, "-- The t1libControl and freetypeControl options have been replaced"); + error(-1, " by the enableT1lib, enableFreeType, and antialias options"); + } else if (!cmd->cmp("fontpath") || !cmd->cmp("fontmap")) { + error(-1, "-- the config file format has changed since Xpdf 0.9x"); + } + } + } + + deleteGList(tokens, GString); +} + +void GlobalParams::parseNameToUnicode(GList *tokens, GString *fileName, + int line) { + GString *name; + char *tok1, *tok2; + FILE *f; + char buf[256]; + int line2; + Unicode u; + + if (tokens->getLength() != 2) { + error(-1, "Bad 'nameToUnicode' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + name = (GString *)tokens->get(1); + if (!(f = fopen(name->getCString(), "r"))) { + error(-1, "Couldn't open 'nameToUnicode' file '%s'", + name->getCString()); + return; + } + line2 = 1; + while (getLine(buf, sizeof(buf), f)) { + tok1 = strtok(buf, " \t\r\n"); + tok2 = strtok(NULL, " \t\r\n"); + if (tok1 && tok2) { + sscanf(tok1, "%x", &u); + nameToUnicode->add(tok2, u); + } else { + error(-1, "Bad line in 'nameToUnicode' file (%s:%d)", name, line2); + } + ++line2; + } + fclose(f); +} + +void GlobalParams::parseCIDToUnicode(GList *tokens, GString *fileName, + int line) { + GString *collection, *name, *old; + + if (tokens->getLength() != 3) { + error(-1, "Bad 'cidToUnicode' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + collection = (GString *)tokens->get(1); + name = (GString *)tokens->get(2); + if ((old = (GString *)cidToUnicodes->remove(collection))) { + delete old; + } + cidToUnicodes->add(collection->copy(), name->copy()); +} + +void GlobalParams::parseUnicodeToUnicode(GList *tokens, GString *fileName, + int line) { + GString *font, *file, *old; + + if (tokens->getLength() != 3) { + error(-1, "Bad 'unicodeToUnicode' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + font = (GString *)tokens->get(1); + file = (GString *)tokens->get(2); + if ((old = (GString *)unicodeToUnicodes->remove(font))) { + delete old; + } + unicodeToUnicodes->add(font->copy(), file->copy()); +} + +void GlobalParams::parseUnicodeMap(GList *tokens, GString *fileName, + int line) { + GString *encodingName, *name, *old; + + if (tokens->getLength() != 3) { + error(-1, "Bad 'unicodeMap' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + encodingName = (GString *)tokens->get(1); + name = (GString *)tokens->get(2); + if ((old = (GString *)unicodeMaps->remove(encodingName))) { + delete old; + } + unicodeMaps->add(encodingName->copy(), name->copy()); +} + +void GlobalParams::parseCMapDir(GList *tokens, GString *fileName, int line) { + GString *collection, *dir; + GList *list; + + if (tokens->getLength() != 3) { + error(-1, "Bad 'cMapDir' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + collection = (GString *)tokens->get(1); + dir = (GString *)tokens->get(2); + if (!(list = (GList *)cMapDirs->lookup(collection))) { + list = new GList(); + cMapDirs->add(collection->copy(), list); + } + list->append(dir->copy()); +} + +void GlobalParams::parseToUnicodeDir(GList *tokens, GString *fileName, + int line) { + if (tokens->getLength() != 2) { + error(-1, "Bad 'toUnicodeDir' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + toUnicodeDirs->append(((GString *)tokens->get(1))->copy()); +} + +void GlobalParams::parseDisplayFont(GList *tokens, GHash *fontHash, + DisplayFontParamKind kind, + GString *fileName, int line) { + DisplayFontParam *param, *old; + struct stat statbuf; + + if (tokens->getLength() < 2) { + goto err1; + } + param = new DisplayFontParam(((GString *)tokens->get(1))->copy(), kind); + + switch (kind) { + case displayFontT1: + if (tokens->getLength() != 3) { + goto err2; + } + param->t1.fileName = ((GString *)tokens->get(2))->copy(); + if (stat((param->t1.fileName->getCString)(), &statbuf)) { + delete param; // silently ignore non-existing files + return; + } + break; + case displayFontTT: + if (tokens->getLength() < 3) { + goto err2; + } + param->tt.fileName = ((GString *)tokens->get(2))->copy(); + if (stat((param->tt.fileName->getCString)(), &statbuf)) { + delete param; // silently ignore non-existing files + return; + } + if (tokens->getLength() > 3) + param->tt.faceIndex = atoi(((GString *)tokens->get(3))->getCString()); + else + param->tt.faceIndex = 0; + break; + } + + if ((old = (DisplayFontParam *)fontHash->remove(param->name))) { + delete old; + } + fontHash->add(param->name, param); + return; + + err2: + delete param; + err1: + error(-1, "Bad 'display*Font*' config file command (%s:%d)", + fileName->getCString(), line); +} + +void GlobalParams::parsePSPaperSize(GList *tokens, GString *fileName, + int line) { + GString *tok; + + if (tokens->getLength() == 2) { + tok = (GString *)tokens->get(1); + if (!setPSPaperSize(tok->getCString())) { + error(-1, "Bad 'psPaperSize' config file command (%s:%d)", + fileName->getCString(), line); + } + } else if (tokens->getLength() == 3) { + tok = (GString *)tokens->get(1); + psPaperWidth = atoi(tok->getCString()); + tok = (GString *)tokens->get(2); + psPaperHeight = atoi(tok->getCString()); + psImageableLLX = psImageableLLY = 0; + psImageableURX = psPaperWidth; + psImageableURY = psPaperHeight; + } else { + error(-1, "Bad 'psPaperSize' config file command (%s:%d)", + fileName->getCString(), line); + } +} + +void GlobalParams::parsePSImageableArea(GList *tokens, GString *fileName, + int line) { + if (tokens->getLength() != 5) { + error(-1, "Bad 'psImageableArea' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + psImageableLLX = atoi(((GString *)tokens->get(1))->getCString()); + psImageableLLY = atoi(((GString *)tokens->get(2))->getCString()); + psImageableURX = atoi(((GString *)tokens->get(3))->getCString()); + psImageableURY = atoi(((GString *)tokens->get(4))->getCString()); +} + +void GlobalParams::parsePSLevel(GList *tokens, GString *fileName, int line) { + GString *tok; + + if (tokens->getLength() != 2) { + error(-1, "Bad 'psLevel' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + tok = (GString *)tokens->get(1); + if (!tok->cmp("level1")) { + psLevel = psLevel1; + } else if (!tok->cmp("level1sep")) { + psLevel = psLevel1Sep; + } else if (!tok->cmp("level2")) { + psLevel = psLevel2; + } else if (!tok->cmp("level2sep")) { + psLevel = psLevel2Sep; + } else if (!tok->cmp("level3")) { + psLevel = psLevel3; + } else if (!tok->cmp("level3Sep")) { + psLevel = psLevel3Sep; + } else { + error(-1, "Bad 'psLevel' config file command (%s:%d)", + fileName->getCString(), line); + } +} + +void GlobalParams::parsePSFile(GList *tokens, GString *fileName, int line) { + if (tokens->getLength() != 2) { + error(-1, "Bad 'psFile' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + if (psFile) { + delete psFile; + } + psFile = ((GString *)tokens->get(1))->copy(); +} + +void GlobalParams::parsePSFont(GList *tokens, GString *fileName, int line) { + PSFontParam *param; + + if (tokens->getLength() != 3) { + error(-1, "Bad 'psFont' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + param = new PSFontParam(((GString *)tokens->get(1))->copy(), 0, + ((GString *)tokens->get(2))->copy(), NULL); + psFonts->add(param->pdfFontName, param); +} + +void GlobalParams::parsePSFont16(char *cmdName, GList *fontList, + GList *tokens, GString *fileName, int line) { + PSFontParam *param; + int wMode; + GString *tok; + + if (tokens->getLength() != 5) { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return; + } + tok = (GString *)tokens->get(2); + if (!tok->cmp("H")) { + wMode = 0; + } else if (!tok->cmp("V")) { + wMode = 1; + } else { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return; + } + param = new PSFontParam(((GString *)tokens->get(1))->copy(), + wMode, + ((GString *)tokens->get(3))->copy(), + ((GString *)tokens->get(4))->copy()); + fontList->append(param); +} + +void GlobalParams::parseTextEncoding(GList *tokens, GString *fileName, + int line) { + if (tokens->getLength() != 2) { + error(-1, "Bad 'textEncoding' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + delete textEncoding; + textEncoding = ((GString *)tokens->get(1))->copy(); +} + +void GlobalParams::parseTextEOL(GList *tokens, GString *fileName, int line) { + GString *tok; + + if (tokens->getLength() != 2) { + error(-1, "Bad 'textEOL' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + tok = (GString *)tokens->get(1); + if (!tok->cmp("unix")) { + textEOL = eolUnix; + } else if (!tok->cmp("dos")) { + textEOL = eolDOS; + } else if (!tok->cmp("mac")) { + textEOL = eolMac; + } else { + error(-1, "Bad 'textEOL' config file command (%s:%d)", + fileName->getCString(), line); + } +} + +void GlobalParams::parseFontDir(GList *tokens, GString *fileName, int line) { + if (tokens->getLength() != 2) { + error(-1, "Bad 'fontDir' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + fontDirs->append(((GString *)tokens->get(1))->copy()); +} + +void GlobalParams::parseInitialZoom(GList *tokens, + GString *fileName, int line) { + if (tokens->getLength() != 2) { + error(-1, "Bad 'initialZoom' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + delete initialZoom; + initialZoom = ((GString *)tokens->get(1))->copy(); +} + +void GlobalParams::parseScreenType(GList *tokens, GString *fileName, + int line) { + GString *tok; + + if (tokens->getLength() != 2) { + error(-1, "Bad 'screenType' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + tok = (GString *)tokens->get(1); + if (!tok->cmp("dispersed")) { + screenType = screenDispersed; + } else if (!tok->cmp("clustered")) { + screenType = screenClustered; + } else if (!tok->cmp("stochasticClustered")) { + screenType = screenStochasticClustered; + } else { + error(-1, "Bad 'screenType' config file command (%s:%d)", + fileName->getCString(), line); + } +} + +void GlobalParams::parseBind(GList *tokens, GString *fileName, int line) { + KeyBinding *binding; + GList *cmds; + int code, mods, context, i; + + if (tokens->getLength() < 4) { + error(-1, "Bad 'bind' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + if (!parseKey((GString *)tokens->get(1), (GString *)tokens->get(2), + &code, &mods, &context, + "bind", tokens, fileName, line)) { + return; + } + for (i = 0; i < keyBindings->getLength(); ++i) { + binding = (KeyBinding *)keyBindings->get(i); + if (binding->code == code && + binding->mods == mods && + binding->context == context) { + delete (KeyBinding *)keyBindings->del(i); + break; + } + } + cmds = new GList(); + for (i = 3; i < tokens->getLength(); ++i) { + cmds->append(((GString *)tokens->get(i))->copy()); + } + keyBindings->append(new KeyBinding(code, mods, context, cmds)); +} + +void GlobalParams::parseUnbind(GList *tokens, GString *fileName, int line) { + KeyBinding *binding; + int code, mods, context, i; + + if (tokens->getLength() != 3) { + error(-1, "Bad 'unbind' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + if (!parseKey((GString *)tokens->get(1), (GString *)tokens->get(2), + &code, &mods, &context, + "unbind", tokens, fileName, line)) { + return; + } + for (i = 0; i < keyBindings->getLength(); ++i) { + binding = (KeyBinding *)keyBindings->get(i); + if (binding->code == code && + binding->mods == mods && + binding->context == context) { + delete (KeyBinding *)keyBindings->del(i); + break; + } + } +} + +GBool GlobalParams::parseKey(GString *modKeyStr, GString *contextStr, + int *code, int *mods, int *context, + char *cmdName, + GList * /*tokens*/, GString *fileName, int line) { + char *p0; + + *mods = xpdfKeyModNone; + p0 = modKeyStr->getCString(); + while (1) { + if (!strncmp(p0, "shift-", 6)) { + *mods |= xpdfKeyModShift; + p0 += 6; + } else if (!strncmp(p0, "ctrl-", 5)) { + *mods |= xpdfKeyModCtrl; + p0 += 5; + } else if (!strncmp(p0, "alt-", 4)) { + *mods |= xpdfKeyModAlt; + p0 += 4; + } else { + break; + } + } + + if (!strcmp(p0, "space")) { + *code = ' '; + } else if (!strcmp(p0, "tab")) { + *code = xpdfKeyCodeTab; + } else if (!strcmp(p0, "return")) { + *code = xpdfKeyCodeReturn; + } else if (!strcmp(p0, "enter")) { + *code = xpdfKeyCodeEnter; + } else if (!strcmp(p0, "backspace")) { + *code = xpdfKeyCodeBackspace; + } else if (!strcmp(p0, "insert")) { + *code = xpdfKeyCodeInsert; + } else if (!strcmp(p0, "delete")) { + *code = xpdfKeyCodeDelete; + } else if (!strcmp(p0, "home")) { + *code = xpdfKeyCodeHome; + } else if (!strcmp(p0, "end")) { + *code = xpdfKeyCodeEnd; + } else if (!strcmp(p0, "pgup")) { + *code = xpdfKeyCodePgUp; + } else if (!strcmp(p0, "pgdn")) { + *code = xpdfKeyCodePgDn; + } else if (!strcmp(p0, "left")) { + *code = xpdfKeyCodeLeft; + } else if (!strcmp(p0, "right")) { + *code = xpdfKeyCodeRight; + } else if (!strcmp(p0, "up")) { + *code = xpdfKeyCodeUp; + } else if (!strcmp(p0, "down")) { + *code = xpdfKeyCodeDown; + } else if (p0[0] == 'f' && p0[1] >= '1' && p0[1] <= '9' && !p0[2]) { + *code = xpdfKeyCodeF1 + (p0[1] - '1'); + } else if (p0[0] == 'f' && + ((p0[1] >= '1' && p0[1] <= '2' && p0[2] >= '0' && p0[2] <= '9') || + (p0[1] == '3' && p0[2] >= '0' && p0[2] <= '5')) && + !p0[3]) { + *code = xpdfKeyCodeF1 + 10 * (p0[1] - '0') + (p0[2] - '0') - 1; + } else if (!strncmp(p0, "mousePress", 10) && + p0[10] >= '1' && p0[10] <= '7' && !p0[11]) { + *code = xpdfKeyCodeMousePress1 + (p0[10] - '1'); + } else if (!strncmp(p0, "mouseRelease", 12) && + p0[12] >= '1' && p0[12] <= '7' && !p0[13]) { + *code = xpdfKeyCodeMouseRelease1 + (p0[12] - '1'); + } else if (*p0 >= 0x20 && *p0 <= 0x7e && !p0[1]) { + *code = (int)*p0; + } else { + error(-1, "Bad key/modifier in '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return gFalse; + } + + p0 = contextStr->getCString(); + if (!strcmp(p0, "any")) { + *context = xpdfKeyContextAny; + } else { + *context = xpdfKeyContextAny; + while (1) { + if (!strncmp(p0, "fullScreen", 10)) { + *context |= xpdfKeyContextFullScreen; + p0 += 10; + } else if (!strncmp(p0, "window", 6)) { + *context |= xpdfKeyContextWindow; + p0 += 6; + } else if (!strncmp(p0, "continuous", 10)) { + *context |= xpdfKeyContextContinuous; + p0 += 10; + } else if (!strncmp(p0, "singlePage", 10)) { + *context |= xpdfKeyContextSinglePage; + p0 += 10; + } else if (!strncmp(p0, "overLink", 8)) { + *context |= xpdfKeyContextOverLink; + p0 += 8; + } else if (!strncmp(p0, "offLink", 7)) { + *context |= xpdfKeyContextOffLink; + p0 += 7; + } else if (!strncmp(p0, "outline", 7)) { + *context |= xpdfKeyContextOutline; + p0 += 7; + } else if (!strncmp(p0, "mainWin", 7)) { + *context |= xpdfKeyContextMainWin; + p0 += 7; + } else if (!strncmp(p0, "scrLockOn", 9)) { + *context |= xpdfKeyContextScrLockOn; + p0 += 9; + } else if (!strncmp(p0, "scrLockOff", 10)) { + *context |= xpdfKeyContextScrLockOff; + p0 += 10; + } else { + error(-1, "Bad context in '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return gFalse; + } + if (!*p0) { + break; + } + if (*p0 != ',') { + error(-1, "Bad context in '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return gFalse; + } + ++p0; + } + } + + return gTrue; +} + +void GlobalParams::parseCommand(char *cmdName, GString **val, + GList *tokens, GString *fileName, int line) { + if (tokens->getLength() != 2) { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return; + } + if (*val) { + delete *val; + } + *val = ((GString *)tokens->get(1))->copy(); +} + +void GlobalParams::parseYesNo(char *cmdName, GBool *flag, + GList *tokens, GString *fileName, int line) { + GString *tok; + + if (tokens->getLength() != 2) { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return; + } + tok = (GString *)tokens->get(1); + if (!parseYesNo2(tok->getCString(), flag)) { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + } +} + +GBool GlobalParams::parseYesNo2(char *token, GBool *flag) { + if (!strcmp(token, "yes")) { + *flag = gTrue; + } else if (!strcmp(token, "no")) { + *flag = gFalse; + } else { + return gFalse; + } + return gTrue; +} + +void GlobalParams::parseInteger(char *cmdName, int *val, + GList *tokens, GString *fileName, int line) { + GString *tok; + int i; + + if (tokens->getLength() != 2) { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return; + } + tok = (GString *)tokens->get(1); + if (tok->getLength() == 0) { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return; + } + if (tok->getChar(0) == '-') { + i = 1; + } else { + i = 0; + } + for (; i < tok->getLength(); ++i) { + if (tok->getChar(i) < '0' || tok->getChar(i) > '9') { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return; + } + } + *val = atoi(tok->getCString()); +} + +void GlobalParams::parseFloat(char *cmdName, double *val, + GList *tokens, GString *fileName, int line) { + GString *tok; + int i; + + if (tokens->getLength() != 2) { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return; + } + tok = (GString *)tokens->get(1); + if (tok->getLength() == 0) { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return; + } + if (tok->getChar(0) == '-') { + i = 1; + } else { + i = 0; + } + for (; i < tok->getLength(); ++i) { + if (!((tok->getChar(i) >= '0' && tok->getChar(i) <= '9') || + tok->getChar(i) == '.')) { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return; + } + } + *val = atof(tok->getCString()); +} + +GlobalParams::~GlobalParams() { + GHashIter *iter; + GString *key; + GList *list; + + freeBuiltinFontTables(); + + delete macRomanReverseMap; + + delete baseDir; + delete nameToUnicode; + deleteGHash(cidToUnicodes, GString); + deleteGHash(unicodeToUnicodes, GString); + deleteGHash(residentUnicodeMaps, UnicodeMap); + deleteGHash(unicodeMaps, GString); + deleteGList(toUnicodeDirs, GString); + deleteGHash(displayFonts, DisplayFontParam); + deleteGHash(displayCIDFonts, DisplayFontParam); + deleteGHash(displayNamedCIDFonts, DisplayFontParam); +#ifdef WIN32 + if (winFontList) { + delete winFontList; + } +#endif + if (psFile) { + delete psFile; + } + deleteGHash(psFonts, PSFontParam); + deleteGList(psNamedFonts16, PSFontParam); + deleteGList(psFonts16, PSFontParam); + delete textEncoding; + deleteGList(fontDirs, GString); + delete initialZoom; + if (urlCommand) { + delete urlCommand; + } + if (movieCommand) { + delete movieCommand; + } + deleteGList(keyBindings, KeyBinding); + + cMapDirs->startIter(&iter); + while (cMapDirs->getNext(&iter, &key, (void **)&list)) { + deleteGList(list, GString); + } + delete cMapDirs; + + delete cidToUnicodeCache; + delete unicodeToUnicodeCache; + delete unicodeMapCache; + delete cMapCache; + +#ifdef ENABLE_PLUGINS + delete securityHandlers; + deleteGList(plugins, Plugin); +#endif + +#if MULTITHREADED + gDestroyMutex(&mutex); + gDestroyMutex(&unicodeMapCacheMutex); + gDestroyMutex(&cMapCacheMutex); +#endif +} + +//------------------------------------------------------------------------ + +void GlobalParams::setBaseDir(char *dir) { + delete baseDir; + baseDir = new GString(dir); +} + +void GlobalParams::setupBaseFonts(char *dir) { + GString *fontName; + GString *fileName; +#ifdef WIN32 + HMODULE shell32Lib; + BOOL (__stdcall *SHGetSpecialFolderPathFunc)(HWND hwndOwner, + LPTSTR lpszPath, + int nFolder, + BOOL fCreate); + char winFontDir[MAX_PATH]; +#endif + FILE *f; + DisplayFontParamKind kind; + DisplayFontParam *dfp; + int i, j; + +#ifdef WIN32 + // SHGetSpecialFolderPath isn't available in older versions of + // shell32.dll (Win95 and WinNT4), so do a dynamic load + winFontDir[0] = '\0'; + if ((shell32Lib = LoadLibrary("shell32.dll"))) { + if ((SHGetSpecialFolderPathFunc = + (BOOL (__stdcall *)(HWND hwndOwner, LPTSTR lpszPath, + int nFolder, BOOL fCreate)) + GetProcAddress(shell32Lib, "SHGetSpecialFolderPathA"))) { + if (!(*SHGetSpecialFolderPathFunc)(NULL, winFontDir, + CSIDL_FONTS, FALSE)) { + winFontDir[0] = '\0'; + } + } + } +#endif + for (i = 0; displayFontTab[i].name; ++i) { + fontName = new GString(displayFontTab[i].name); + fileName = NULL; + kind = displayFontT1; // make gcc happy + if (dir) { + fileName = appendToPath(new GString(dir), displayFontTab[i].t1FileName); + kind = displayFontT1; + if ((f = fopen(fileName->getCString(), "rb"))) { + fclose(f); + } else { + delete fileName; + fileName = NULL; + } + } +#ifdef WIN32 + if (!fileName && winFontDir[0] && displayFontTab[i].ttFileName) { + fileName = appendToPath(new GString(winFontDir), + displayFontTab[i].ttFileName); + kind = displayFontTT; + if ((f = fopen(fileName->getCString(), "rb"))) { + fclose(f); + } else { + delete fileName; + fileName = NULL; + } + } + // SHGetSpecialFolderPath(CSIDL_FONTS) doesn't work on Win 2k Server + // or Win2003 Server, or with older versions of shell32.dll, so check + // the "standard" directories + if (displayFontTab[i].ttFileName) { + for (j = 0; !fileName && displayFontDirs[j]; ++j) { + fileName = appendToPath(new GString(displayFontDirs[j]), + displayFontTab[i].ttFileName); + kind = displayFontTT; + if ((f = fopen(fileName->getCString(), "rb"))) { + fclose(f); + } else { + delete fileName; + fileName = NULL; + } + } + } +#else + for (j = 0; !fileName && displayFontDirs[j]; ++j) { + fileName = appendToPath(new GString(displayFontDirs[j]), + displayFontTab[i].t1FileName); + kind = displayFontT1; + if ((f = fopen(fileName->getCString(), "rb"))) { + fclose(f); + } else { + delete fileName; + fileName = NULL; + } + } +#endif + if (!fileName) { + error(-1, "No display font for '%s'", displayFontTab[i].name); + delete fontName; + continue; + } + dfp = new DisplayFontParam(fontName, kind); + dfp->t1.fileName = fileName; + globalParams->addDisplayFont(dfp); + } + +#ifdef WIN32 + if (winFontDir[0]) { + winFontList = new WinFontList(winFontDir); + } +#endif +} + +//------------------------------------------------------------------------ +// accessors +//------------------------------------------------------------------------ + +CharCode GlobalParams::getMacRomanCharCode(char *charName) { + // no need to lock - macRomanReverseMap is constant + return macRomanReverseMap->lookup(charName); +} + +GString *GlobalParams::getBaseDir() { + GString *s; + + lockGlobalParams; + s = baseDir->copy(); + unlockGlobalParams; + return s; +} + +Unicode GlobalParams::mapNameToUnicode(char *charName) { + // no need to lock - nameToUnicode is constant + return nameToUnicode->lookup(charName); +} + +UnicodeMap *GlobalParams::getResidentUnicodeMap(GString *encodingName) { + UnicodeMap *map; + + lockGlobalParams; + map = (UnicodeMap *)residentUnicodeMaps->lookup(encodingName); + unlockGlobalParams; + if (map) { + map->incRefCnt(); + } + return map; +} + +FILE *GlobalParams::getUnicodeMapFile(GString *encodingName) { + GString *fileName; + FILE *f; + + lockGlobalParams; + if ((fileName = (GString *)unicodeMaps->lookup(encodingName))) { + f = fopen(fileName->getCString(), "r"); + } else { + f = NULL; + } + unlockGlobalParams; + return f; +} + +FILE *GlobalParams::findCMapFile(GString *collection, GString *cMapName) { + GList *list; + GString *dir; + GString *fileName; + FILE *f; + int i; + + lockGlobalParams; + if (!(list = (GList *)cMapDirs->lookup(collection))) { + unlockGlobalParams; + return NULL; + } + for (i = 0; i < list->getLength(); ++i) { + dir = (GString *)list->get(i); + fileName = appendToPath(dir->copy(), cMapName->getCString()); + f = fopen(fileName->getCString(), "r"); + delete fileName; + if (f) { + unlockGlobalParams; + return f; + } + } + unlockGlobalParams; + return NULL; +} + +FILE *GlobalParams::findToUnicodeFile(GString *name) { + GString *dir, *fileName; + FILE *f; + int i; + + lockGlobalParams; + for (i = 0; i < toUnicodeDirs->getLength(); ++i) { + dir = (GString *)toUnicodeDirs->get(i); + fileName = appendToPath(dir->copy(), name->getCString()); + f = fopen(fileName->getCString(), "r"); + delete fileName; + if (f) { + unlockGlobalParams; + return f; + } + } + unlockGlobalParams; + return NULL; +} + +// KPDF: parse xpdf font name into family and style +// Helvetica-BoldOblique => name=Helvetica, weight=Bold, slant=Oblique + +void parseStyle(QString& name, int& weight, int& slant, int& width) +{ + if (name.find("MS-") == 0) name = "MS " + name.remove(0,3); + + if (!name.contains('-') && !name.contains(',')) return; + QString type = name.section(QRegExp("[-,]"),-1); + name = name.section(QRegExp("[-,]"),0,-2); + if (type.contains("Oblique")) slant=FC_SLANT_OBLIQUE; + if (type.contains("Italic")) slant=FC_SLANT_ITALIC; + if (type.contains("Bold")) weight=FC_WEIGHT_BOLD; + if (type.contains("Light")) weight=FC_WEIGHT_LIGHT; + if (type.contains("Condensed")) width=FC_WIDTH_CONDENSED; +} + +DisplayFontParam *GlobalParams::getDisplayFont(GString *fontName) { + DisplayFontParam *dfp; + FcPattern *p=0,*m=0; + FcChar8* s; + char * ext; + FcResult res; + + lockGlobalParams; + dfp = (DisplayFontParam *)displayFonts->lookup(fontName); + // KPDF: try to find font using Xft + if (!dfp) { + int weight=FC_WEIGHT_MEDIUM, slant=FC_SLANT_ROMAN, width=FC_WIDTH_NORMAL; + QString name(fontName->getCString()); + + parseStyle(name,weight,slant,width); + p = FcPatternBuild(0,FC_FAMILY,FcTypeString, name.ascii(), + FC_SLANT, FcTypeInteger, slant, FC_WEIGHT, FcTypeInteger, weight, + FC_WIDTH, FcTypeInteger, width, FC_LANG, FcTypeString, "xx", (char*)0); + if (!p) goto fin; + m = XftFontMatch(qt_xdisplay(),qt_xscreen(),p,&res); + if (!m) goto fin; + res = FcPatternGetString (m, FC_FILE, 0, &s); + if (res != FcResultMatch || !s) goto fin; + ext = rindex((char*)s,'.'); + if (!ext) goto fin; + if (!strncasecmp(ext,".ttf",4) || !strncasecmp(ext,".ttc",4)) { + dfp = new DisplayFontParam(fontName->copy(), displayFontTT); + dfp->tt.fileName = new GString((char*)s); + FcPatternGetInteger(m, FC_INDEX, 0, &(dfp->tt.faceIndex)); + } else if (!strncasecmp(ext,".pfa",4) || !strncasecmp(ext,".pfb",4)) { + dfp = new DisplayFontParam(fontName->copy(), displayFontT1); + dfp->t1.fileName = new GString((char*)s); + } else goto fin; + displayFonts->add(dfp->name,dfp); + } +fin: unlockGlobalParams; + if (m) FcPatternDestroy(m); + if (p) FcPatternDestroy(p); + return dfp; +} + +DisplayFontParam *GlobalParams::getDisplayCIDFont(GString *fontName, + GString *collection) { + DisplayFontParam *dfp; + + lockGlobalParams; + if (!fontName || + !(dfp = (DisplayFontParam *)displayNamedCIDFonts->lookup(fontName))) { + dfp = (DisplayFontParam *)displayCIDFonts->lookup(collection); + } + unlockGlobalParams; + if (!dfp) dfp = getDisplayFont(fontName); + return dfp; +} + +GString *GlobalParams::getPSFile() { + GString *s; + + lockGlobalParams; + s = psFile ? psFile->copy() : (GString *)NULL; + unlockGlobalParams; + return s; +} + +int GlobalParams::getPSPaperWidth() { + int w; + + lockGlobalParams; + w = psPaperWidth; + unlockGlobalParams; + return w; +} + +int GlobalParams::getPSPaperHeight() { + int h; + + lockGlobalParams; + h = psPaperHeight; + unlockGlobalParams; + return h; +} + +void GlobalParams::getPSImageableArea(int *llx, int *lly, int *urx, int *ury) { + lockGlobalParams; + *llx = psImageableLLX; + *lly = psImageableLLY; + *urx = psImageableURX; + *ury = psImageableURY; + unlockGlobalParams; +} + +GBool GlobalParams::getPSCrop() { + GBool f; + + lockGlobalParams; + f = psCrop; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getPSExpandSmaller() { + GBool f; + + lockGlobalParams; + f = psExpandSmaller; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getPSShrinkLarger() { + GBool f; + + lockGlobalParams; + f = psShrinkLarger; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getPSCenter() { + GBool f; + + lockGlobalParams; + f = psCenter; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getPSDuplex() { + GBool d; + + lockGlobalParams; + d = psDuplex; + unlockGlobalParams; + return d; +} + +PSLevel GlobalParams::getPSLevel() { + PSLevel level; + + lockGlobalParams; + level = psLevel; + unlockGlobalParams; + return level; +} + +PSFontParam *GlobalParams::getPSFont(GString *fontName) { + PSFontParam *p; + + lockGlobalParams; + p = (PSFontParam *)psFonts->lookup(fontName); + unlockGlobalParams; + return p; +} + +PSFontParam *GlobalParams::getPSFont16(GString *fontName, + GString *collection, int wMode) { + PSFontParam *p; + int i; + + lockGlobalParams; + p = NULL; + if (fontName) { + for (i = 0; i < psNamedFonts16->getLength(); ++i) { + p = (PSFontParam *)psNamedFonts16->get(i); + if (!p->pdfFontName->cmp(fontName) && + p->wMode == wMode) { + break; + } + p = NULL; + } + } + if (!p && collection) { + for (i = 0; i < psFonts16->getLength(); ++i) { + p = (PSFontParam *)psFonts16->get(i); + if (!p->pdfFontName->cmp(collection) && + p->wMode == wMode) { + break; + } + p = NULL; + } + } + unlockGlobalParams; + return p; +} + +GBool GlobalParams::getPSEmbedType1() { + GBool e; + + lockGlobalParams; + e = psEmbedType1; + unlockGlobalParams; + return e; +} + +GBool GlobalParams::getPSEmbedTrueType() { + GBool e; + + lockGlobalParams; + e = psEmbedTrueType; + unlockGlobalParams; + return e; +} + +GBool GlobalParams::getPSEmbedCIDPostScript() { + GBool e; + + lockGlobalParams; + e = psEmbedCIDPostScript; + unlockGlobalParams; + return e; +} + +GBool GlobalParams::getPSEmbedCIDTrueType() { + GBool e; + + lockGlobalParams; + e = psEmbedCIDTrueType; + unlockGlobalParams; + return e; +} + +GBool GlobalParams::getPSPreload() { + GBool preload; + + lockGlobalParams; + preload = psPreload; + unlockGlobalParams; + return preload; +} + +GBool GlobalParams::getPSOPI() { + GBool opi; + + lockGlobalParams; + opi = psOPI; + unlockGlobalParams; + return opi; +} + +GBool GlobalParams::getPSASCIIHex() { + GBool ah; + + lockGlobalParams; + ah = psASCIIHex; + unlockGlobalParams; + return ah; +} + +GString *GlobalParams::getTextEncodingName() { + GString *s; + + lockGlobalParams; + s = textEncoding->copy(); + unlockGlobalParams; + return s; +} + +EndOfLineKind GlobalParams::getTextEOL() { + EndOfLineKind eol; + + lockGlobalParams; + eol = textEOL; + unlockGlobalParams; + return eol; +} + +GBool GlobalParams::getTextPageBreaks() { + GBool pageBreaks; + + lockGlobalParams; + pageBreaks = textPageBreaks; + unlockGlobalParams; + return pageBreaks; +} + +GBool GlobalParams::getTextKeepTinyChars() { + GBool tiny; + + lockGlobalParams; + tiny = textKeepTinyChars; + unlockGlobalParams; + return tiny; +} + +GString *GlobalParams::findFontFile(GString *fontName, char **exts) { + GString *dir, *fileName; + char **ext; + FILE *f; + int i; + + lockGlobalParams; + for (i = 0; i < fontDirs->getLength(); ++i) { + dir = (GString *)fontDirs->get(i); + for (ext = exts; *ext; ++ext) { + fileName = appendToPath(dir->copy(), fontName->getCString()); + fileName->append(*ext); + if ((f = fopen(fileName->getCString(), "rb"))) { + fclose(f); + unlockGlobalParams; + return fileName; + } + delete fileName; + } + } + unlockGlobalParams; + return NULL; +} + +GString *GlobalParams::getInitialZoom() { + GString *s; + + lockGlobalParams; + s = initialZoom->copy(); + unlockGlobalParams; + return s; +} + +GBool GlobalParams::getContinuousView() { + GBool f; + + lockGlobalParams; + f = continuousView; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getEnableT1lib() { + GBool f; + + lockGlobalParams; + f = enableT1lib; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getEnableFreeType() { + GBool f; + + lockGlobalParams; + f = enableFreeType; + unlockGlobalParams; + return f; +} + + +GBool GlobalParams::getAntialias() { + GBool f; + + lockGlobalParams; + f = antialias; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getVectorAntialias() { + GBool f; + + lockGlobalParams; + f = vectorAntialias; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getStrokeAdjust() { + GBool f; + + lockGlobalParams; + f = strokeAdjust; + unlockGlobalParams; + return f; +} + +ScreenType GlobalParams::getScreenType() { + ScreenType t; + + lockGlobalParams; + t = screenType; + unlockGlobalParams; + return t; +} + +int GlobalParams::getScreenSize() { + int size; + + lockGlobalParams; + size = screenSize; + unlockGlobalParams; + return size; +} + +int GlobalParams::getScreenDotRadius() { + int r; + + lockGlobalParams; + r = screenDotRadius; + unlockGlobalParams; + return r; +} + +double GlobalParams::getScreenGamma() { + double gamma; + + lockGlobalParams; + gamma = screenGamma; + unlockGlobalParams; + return gamma; +} + +double GlobalParams::getScreenBlackThreshold() { + double thresh; + + lockGlobalParams; + thresh = screenBlackThreshold; + unlockGlobalParams; + return thresh; +} + +double GlobalParams::getScreenWhiteThreshold() { + double thresh; + + lockGlobalParams; + thresh = screenWhiteThreshold; + unlockGlobalParams; + return thresh; +} + +GBool GlobalParams::getMapNumericCharNames() { + GBool map; + + lockGlobalParams; + map = mapNumericCharNames; + unlockGlobalParams; + return map; +} + +GBool GlobalParams::getMapUnknownCharNames() { + GBool map; + + lockGlobalParams; + map = mapUnknownCharNames; + unlockGlobalParams; + return map; +} + +GList *GlobalParams::getKeyBinding(int code, int mods, int context) { + KeyBinding *binding; + GList *cmds; + int modMask; + int i, j; + + lockGlobalParams; + cmds = NULL; + // for ASCII chars, ignore the shift modifier + modMask = code <= 0xff ? ~xpdfKeyModShift : ~0; + for (i = 0; i < keyBindings->getLength(); ++i) { + binding = (KeyBinding *)keyBindings->get(i); + if (binding->code == code && + (binding->mods & modMask) == (mods & modMask) && + (~binding->context | context) == ~0) { + cmds = new GList(); + for (j = 0; j < binding->cmds->getLength(); ++j) { + cmds->append(((GString *)binding->cmds->get(j))->copy()); + } + break; + } + } + unlockGlobalParams; + return cmds; +} + +GBool GlobalParams::getPrintCommands() { + GBool p; + + lockGlobalParams; + p = printCommands; + unlockGlobalParams; + return p; +} + +GBool GlobalParams::getErrQuiet() { + // no locking -- this function may get called from inside a locked + // section + return errQuiet; +} + +CharCodeToUnicode *GlobalParams::getCIDToUnicode(GString *collection) { + GString *fileName; + CharCodeToUnicode *ctu; + + lockGlobalParams; + if (!(ctu = cidToUnicodeCache->getCharCodeToUnicode(collection))) { + if ((fileName = (GString *)cidToUnicodes->lookup(collection)) && + (ctu = CharCodeToUnicode::parseCIDToUnicode(fileName, collection))) { + cidToUnicodeCache->add(ctu); + } + } + unlockGlobalParams; + return ctu; +} + +CharCodeToUnicode *GlobalParams::getUnicodeToUnicode(GString *fontName) { + CharCodeToUnicode *ctu; + GHashIter *iter; + GString *fontPattern, *fileName; + + lockGlobalParams; + fileName = NULL; + unicodeToUnicodes->startIter(&iter); + while (unicodeToUnicodes->getNext(&iter, &fontPattern, (void **)&fileName)) { + if (strstr(fontName->getCString(), fontPattern->getCString())) { + unicodeToUnicodes->killIter(&iter); + break; + } + fileName = NULL; + } + if (fileName) { + if (!(ctu = unicodeToUnicodeCache->getCharCodeToUnicode(fileName))) { + if ((ctu = CharCodeToUnicode::parseUnicodeToUnicode(fileName))) { + unicodeToUnicodeCache->add(ctu); + } + } + } else { + ctu = NULL; + } + unlockGlobalParams; + return ctu; +} + +UnicodeMap *GlobalParams::getUnicodeMap(GString *encodingName) { + return getUnicodeMap2(encodingName); +} + +UnicodeMap *GlobalParams::getUnicodeMap2(GString *encodingName) { + UnicodeMap *map; + + if (!(map = getResidentUnicodeMap(encodingName))) { + lockUnicodeMapCache; + map = unicodeMapCache->getUnicodeMap(encodingName); + unlockUnicodeMapCache; + } + return map; +} + +CMap *GlobalParams::getCMap(GString *collection, GString *cMapName) { + CMap *cMap; + + lockCMapCache; + cMap = cMapCache->getCMap(collection, cMapName); + unlockCMapCache; + return cMap; +} + +UnicodeMap *GlobalParams::getTextEncoding() { + return getUnicodeMap2(textEncoding); +} + +//------------------------------------------------------------------------ +// functions to set parameters +//------------------------------------------------------------------------ + +void GlobalParams::addDisplayFont(DisplayFontParam *param) { + DisplayFontParam *old; + + lockGlobalParams; + if ((old = (DisplayFontParam *)displayFonts->remove(param->name))) { + delete old; + } + displayFonts->add(param->name, param); + unlockGlobalParams; +} + +void GlobalParams::setPSFile(char *file) { + lockGlobalParams; + if (psFile) { + delete psFile; + } + psFile = new GString(file); + unlockGlobalParams; +} + +GBool GlobalParams::setPSPaperSize(char *size) { + lockGlobalParams; + if (!strcmp(size, "match")) { + psPaperWidth = psPaperHeight = -1; + } else if (!strcmp(size, "letter")) { + psPaperWidth = 612; + psPaperHeight = 792; + } else if (!strcmp(size, "legal")) { + psPaperWidth = 612; + psPaperHeight = 1008; + } else if (!strcmp(size, "A4")) { + psPaperWidth = 595; + psPaperHeight = 842; + } else if (!strcmp(size, "A3")) { + psPaperWidth = 842; + psPaperHeight = 1190; + } else { + unlockGlobalParams; + return gFalse; + } + psImageableLLX = psImageableLLY = 0; + psImageableURX = psPaperWidth; + psImageableURY = psPaperHeight; + unlockGlobalParams; + return gTrue; +} + +void GlobalParams::setPSPaperWidth(int width) { + lockGlobalParams; + psPaperWidth = width; + psImageableLLX = 0; + psImageableURX = psPaperWidth; + unlockGlobalParams; +} + +void GlobalParams::setPSPaperHeight(int height) { + lockGlobalParams; + psPaperHeight = height; + psImageableLLY = 0; + psImageableURY = psPaperHeight; + unlockGlobalParams; +} + +void GlobalParams::setPSImageableArea(int llx, int lly, int urx, int ury) { + lockGlobalParams; + psImageableLLX = llx; + psImageableLLY = lly; + psImageableURX = urx; + psImageableURY = ury; + unlockGlobalParams; +} + +void GlobalParams::setPSCrop(GBool crop) { + lockGlobalParams; + psCrop = crop; + unlockGlobalParams; +} + +void GlobalParams::setPSExpandSmaller(GBool expand) { + lockGlobalParams; + psExpandSmaller = expand; + unlockGlobalParams; +} + +void GlobalParams::setPSShrinkLarger(GBool shrink) { + lockGlobalParams; + psShrinkLarger = shrink; + unlockGlobalParams; +} + +void GlobalParams::setPSCenter(GBool center) { + lockGlobalParams; + psCenter = center; + unlockGlobalParams; +} + +void GlobalParams::setPSDuplex(GBool duplex) { + lockGlobalParams; + psDuplex = duplex; + unlockGlobalParams; +} + +void GlobalParams::setPSLevel(PSLevel level) { + lockGlobalParams; + psLevel = level; + unlockGlobalParams; +} + +void GlobalParams::setPSEmbedType1(GBool embed) { + lockGlobalParams; + psEmbedType1 = embed; + unlockGlobalParams; +} + +void GlobalParams::setPSEmbedTrueType(GBool embed) { + lockGlobalParams; + psEmbedTrueType = embed; + unlockGlobalParams; +} + +void GlobalParams::setPSEmbedCIDPostScript(GBool embed) { + lockGlobalParams; + psEmbedCIDPostScript = embed; + unlockGlobalParams; +} + +void GlobalParams::setPSEmbedCIDTrueType(GBool embed) { + lockGlobalParams; + psEmbedCIDTrueType = embed; + unlockGlobalParams; +} + +void GlobalParams::setPSPreload(GBool preload) { + lockGlobalParams; + psPreload = preload; + unlockGlobalParams; +} + +void GlobalParams::setPSOPI(GBool opi) { + lockGlobalParams; + psOPI = opi; + unlockGlobalParams; +} + +void GlobalParams::setPSASCIIHex(GBool hex) { + lockGlobalParams; + psASCIIHex = hex; + unlockGlobalParams; +} + +void GlobalParams::setTextEncoding(char *encodingName) { + lockGlobalParams; + delete textEncoding; + textEncoding = new GString(encodingName); + unlockGlobalParams; +} + +GBool GlobalParams::setTextEOL(char *s) { + lockGlobalParams; + if (!strcmp(s, "unix")) { + textEOL = eolUnix; + } else if (!strcmp(s, "dos")) { + textEOL = eolDOS; + } else if (!strcmp(s, "mac")) { + textEOL = eolMac; + } else { + unlockGlobalParams; + return gFalse; + } + unlockGlobalParams; + return gTrue; +} + +void GlobalParams::setTextPageBreaks(GBool pageBreaks) { + lockGlobalParams; + textPageBreaks = pageBreaks; + unlockGlobalParams; +} + +void GlobalParams::setTextKeepTinyChars(GBool keep) { + lockGlobalParams; + textKeepTinyChars = keep; + unlockGlobalParams; +} + +void GlobalParams::setInitialZoom(char *s) { + lockGlobalParams; + delete initialZoom; + initialZoom = new GString(s); + unlockGlobalParams; +} + +void GlobalParams::setContinuousView(GBool cont) { + lockGlobalParams; + continuousView = cont; + unlockGlobalParams; +} + +GBool GlobalParams::setEnableT1lib(char *s) { + GBool ok; + + lockGlobalParams; + ok = parseYesNo2(s, &enableT1lib); + unlockGlobalParams; + return ok; +} + +GBool GlobalParams::setEnableFreeType(char *s) { + GBool ok; + + lockGlobalParams; + ok = parseYesNo2(s, &enableFreeType); + unlockGlobalParams; + return ok; +} + + +GBool GlobalParams::setAntialias(char *s) { + GBool ok; + + lockGlobalParams; + ok = parseYesNo2(s, &antialias); + unlockGlobalParams; + return ok; +} + +GBool GlobalParams::setVectorAntialias(char *s) { + GBool ok; + + lockGlobalParams; + ok = parseYesNo2(s, &vectorAntialias); + unlockGlobalParams; + return ok; +} + +void GlobalParams::setScreenType(ScreenType t) { + lockGlobalParams; + screenType = t; + unlockGlobalParams; +} + +void GlobalParams::setScreenSize(int size) { + lockGlobalParams; + screenSize = size; + unlockGlobalParams; +} + +void GlobalParams::setScreenDotRadius(int r) { + lockGlobalParams; + screenDotRadius = r; + unlockGlobalParams; +} + +void GlobalParams::setScreenGamma(double gamma) { + lockGlobalParams; + screenGamma = gamma; + unlockGlobalParams; +} + +void GlobalParams::setScreenBlackThreshold(double thresh) { + lockGlobalParams; + screenBlackThreshold = thresh; + unlockGlobalParams; +} + +void GlobalParams::setScreenWhiteThreshold(double thresh) { + lockGlobalParams; + screenWhiteThreshold = thresh; + unlockGlobalParams; +} + +void GlobalParams::setMapNumericCharNames(GBool map) { + lockGlobalParams; + mapNumericCharNames = map; + unlockGlobalParams; +} + +void GlobalParams::setMapUnknownCharNames(GBool map) { + lockGlobalParams; + mapUnknownCharNames = map; + unlockGlobalParams; +} + +void GlobalParams::setPrintCommands(GBool printCommandsA) { + lockGlobalParams; + printCommands = printCommandsA; + unlockGlobalParams; +} + +void GlobalParams::setErrQuiet(GBool errQuietA) { + lockGlobalParams; + errQuiet = errQuietA; + unlockGlobalParams; +} + +void GlobalParams::addSecurityHandler(XpdfSecurityHandler *handler) { +#ifdef ENABLE_PLUGINS + lockGlobalParams; + securityHandlers->append(handler); + unlockGlobalParams; +#else + (void)handler; +#endif +} + +XpdfSecurityHandler *GlobalParams::getSecurityHandler(char *name) { +#ifdef ENABLE_PLUGINS + XpdfSecurityHandler *hdlr; + int i; + + lockGlobalParams; + for (i = 0; i < securityHandlers->getLength(); ++i) { + hdlr = (XpdfSecurityHandler *)securityHandlers->get(i); + if (!strcasecmp(hdlr->name, name)) { + unlockGlobalParams; + return hdlr; + } + } + unlockGlobalParams; + + if (!loadPlugin("security", name)) { + return NULL; + } + + lockGlobalParams; + for (i = 0; i < securityHandlers->getLength(); ++i) { + hdlr = (XpdfSecurityHandler *)securityHandlers->get(i); + if (!strcmp(hdlr->name, name)) { + unlockGlobalParams; + return hdlr; + } + } + unlockGlobalParams; +#else + (void)name; +#endif + + return NULL; +} + +#ifdef ENABLE_PLUGINS +//------------------------------------------------------------------------ +// plugins +//------------------------------------------------------------------------ + +GBool GlobalParams::loadPlugin(char *type, char *name) { + Plugin *plugin; + + if (!(plugin = Plugin::load(type, name))) { + return gFalse; + } + lockGlobalParams; + plugins->append(plugin); + unlockGlobalParams; + return gTrue; +} + +#endif // ENABLE_PLUGINS diff --git a/kpdf/xpdf/xpdf/GlobalParams.h b/kpdf/xpdf/xpdf/GlobalParams.h new file mode 100644 index 00000000..c0543eda --- /dev/null +++ b/kpdf/xpdf/xpdf/GlobalParams.h @@ -0,0 +1,464 @@ +//======================================================================== +// +// GlobalParams.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef GLOBALPARAMS_H +#define GLOBALPARAMS_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include +#include "gtypes.h" +#include "CharTypes.h" + +#if MULTITHREADED +#include "GMutex.h" +#endif + +class GString; +class GList; +class GHash; +class NameToCharCode; +class CharCodeToUnicode; +class CharCodeToUnicodeCache; +class UnicodeMap; +class UnicodeMapCache; +class CMap; +class CMapCache; +struct XpdfSecurityHandler; +class GlobalParams; +#ifdef WIN32 +class WinFontList; +#endif + +//------------------------------------------------------------------------ + +// The global parameters object. +extern GlobalParams *globalParams; + +//------------------------------------------------------------------------ + +enum DisplayFontParamKind { + displayFontT1, + displayFontTT +}; + +struct DisplayFontParamT1 { + GString *fileName; +}; + +struct DisplayFontParamTT { + GString *fileName; + int faceIndex; +}; + +class DisplayFontParam { +public: + + GString *name; // font name for 8-bit fonts and named + // CID fonts; collection name for + // generic CID fonts + DisplayFontParamKind kind; + union { + DisplayFontParamT1 t1; + DisplayFontParamTT tt; + }; + + DisplayFontParam(GString *nameA, DisplayFontParamKind kindA); + virtual ~DisplayFontParam(); +}; + +//------------------------------------------------------------------------ + +class PSFontParam { +public: + + GString *pdfFontName; // PDF font name for 8-bit fonts and + // named 16-bit fonts; char collection + // name for generic 16-bit fonts + int wMode; // writing mode (0=horiz, 1=vert) for + // 16-bit fonts + GString *psFontName; // PostScript font name + GString *encoding; // encoding, for 16-bit fonts only + + PSFontParam(GString *pdfFontNameA, int wModeA, + GString *psFontNameA, GString *encodingA); + ~PSFontParam(); +}; + +//------------------------------------------------------------------------ + +enum PSLevel { + psLevel1, + psLevel1Sep, + psLevel2, + psLevel2Sep, + psLevel3, + psLevel3Sep +}; + +//------------------------------------------------------------------------ + +enum EndOfLineKind { + eolUnix, // LF + eolDOS, // CR+LF + eolMac // CR +}; + +//------------------------------------------------------------------------ + +enum ScreenType { + screenUnset, + screenDispersed, + screenClustered, + screenStochasticClustered +}; + +//------------------------------------------------------------------------ + +class KeyBinding { +public: + + int code; // 0x20 .. 0xfe = ASCII, + // >=0x10000 = special keys, mouse buttons, + // etc. (xpdfKeyCode* symbols) + int mods; // modifiers (xpdfKeyMod* symbols, or-ed + // together) + int context; // context (xpdfKeyContext* symbols, or-ed + // together) + GList *cmds; // list of commands [GString] + + KeyBinding(int codeA, int modsA, int contextA, char *cmd0); + KeyBinding(int codeA, int modsA, int contextA, char *cmd0, char *cmd1); + KeyBinding(int codeA, int modsA, int contextA, GList *cmdsA); + ~KeyBinding(); +}; + +#define xpdfKeyCodeTab 0x1000 +#define xpdfKeyCodeReturn 0x1001 +#define xpdfKeyCodeEnter 0x1002 +#define xpdfKeyCodeBackspace 0x1003 +#define xpdfKeyCodeInsert 0x1004 +#define xpdfKeyCodeDelete 0x1005 +#define xpdfKeyCodeHome 0x1006 +#define xpdfKeyCodeEnd 0x1007 +#define xpdfKeyCodePgUp 0x1008 +#define xpdfKeyCodePgDn 0x1009 +#define xpdfKeyCodeLeft 0x100a +#define xpdfKeyCodeRight 0x100b +#define xpdfKeyCodeUp 0x100c +#define xpdfKeyCodeDown 0x100d +#define xpdfKeyCodeF1 0x1100 +#define xpdfKeyCodeF35 0x1122 +#define xpdfKeyCodeMousePress1 0x2001 +#define xpdfKeyCodeMousePress2 0x2002 +#define xpdfKeyCodeMousePress3 0x2003 +#define xpdfKeyCodeMousePress4 0x2004 +#define xpdfKeyCodeMousePress5 0x2005 +#define xpdfKeyCodeMousePress6 0x2006 +#define xpdfKeyCodeMousePress7 0x2007 +#define xpdfKeyCodeMouseRelease1 0x2101 +#define xpdfKeyCodeMouseRelease2 0x2102 +#define xpdfKeyCodeMouseRelease3 0x2103 +#define xpdfKeyCodeMouseRelease4 0x2104 +#define xpdfKeyCodeMouseRelease5 0x2105 +#define xpdfKeyCodeMouseRelease6 0x2106 +#define xpdfKeyCodeMouseRelease7 0x2107 +#define xpdfKeyModNone 0 +#define xpdfKeyModShift (1 << 0) +#define xpdfKeyModCtrl (1 << 1) +#define xpdfKeyModAlt (1 << 2) +#define xpdfKeyContextAny 0 +#define xpdfKeyContextFullScreen (1 << 0) +#define xpdfKeyContextWindow (2 << 0) +#define xpdfKeyContextContinuous (1 << 2) +#define xpdfKeyContextSinglePage (2 << 2) +#define xpdfKeyContextOverLink (1 << 4) +#define xpdfKeyContextOffLink (2 << 4) +#define xpdfKeyContextOutline (1 << 6) +#define xpdfKeyContextMainWin (2 << 6) +#define xpdfKeyContextScrLockOn (1 << 8) +#define xpdfKeyContextScrLockOff (2 << 8) + +//------------------------------------------------------------------------ + +class GlobalParams { +public: + + // Initialize the global parameters by attempting to read a config + // file. + GlobalParams(char *cfgFileName); + + ~GlobalParams(); + + void setBaseDir(char *dir); + void setupBaseFonts(char *dir); + + void parseLine(char *buf, GString *fileName, int line); + + //----- accessors + + CharCode getMacRomanCharCode(char *charName); + + GString *getBaseDir(); + Unicode mapNameToUnicode(char *charName); + UnicodeMap *getResidentUnicodeMap(GString *encodingName); + FILE *getUnicodeMapFile(GString *encodingName); + FILE *findCMapFile(GString *collection, GString *cMapName); + FILE *findToUnicodeFile(GString *name); + DisplayFontParam *getDisplayFont(GString *fontName); + DisplayFontParam *getDisplayCIDFont(GString *fontName, GString *collection); + GString *getPSFile(); + int getPSPaperWidth(); + int getPSPaperHeight(); + void getPSImageableArea(int *llx, int *lly, int *urx, int *ury); + GBool getPSDuplex(); + GBool getPSCrop(); + GBool getPSExpandSmaller(); + GBool getPSShrinkLarger(); + GBool getPSCenter(); + PSLevel getPSLevel(); + PSFontParam *getPSFont(GString *fontName); + PSFontParam *getPSFont16(GString *fontName, GString *collection, int wMode); + GBool getPSEmbedType1(); + GBool getPSEmbedTrueType(); + GBool getPSEmbedCIDPostScript(); + GBool getPSEmbedCIDTrueType(); + GBool getPSPreload(); + GBool getPSOPI(); + GBool getPSASCIIHex(); + GString *getTextEncodingName(); + EndOfLineKind getTextEOL(); + GBool getTextPageBreaks(); + GBool getTextKeepTinyChars(); + GString *findFontFile(GString *fontName, char **exts); + GString *getInitialZoom(); + GBool getContinuousView(); + GBool getEnableT1lib(); + GBool getEnableFreeType(); + GBool getAntialias(); + GBool getVectorAntialias(); + GBool getStrokeAdjust(); + ScreenType getScreenType(); + int getScreenSize(); + int getScreenDotRadius(); + double getScreenGamma(); + double getScreenBlackThreshold(); + double getScreenWhiteThreshold(); + GString *getURLCommand() { return urlCommand; } + GString *getMovieCommand() { return movieCommand; } + GBool getMapNumericCharNames(); + GBool getMapUnknownCharNames(); + GList *getKeyBinding(int code, int mods, int context); + GBool getPrintCommands(); + GBool getErrQuiet(); + + CharCodeToUnicode *getCIDToUnicode(GString *collection); + CharCodeToUnicode *getUnicodeToUnicode(GString *fontName); + UnicodeMap *getUnicodeMap(GString *encodingName); + CMap *getCMap(GString *collection, GString *cMapName); + UnicodeMap *getTextEncoding(); + + //----- functions to set parameters + + void addDisplayFont(DisplayFontParam *param); + void setPSFile(char *file); + GBool setPSPaperSize(char *size); + void setPSPaperWidth(int width); + void setPSPaperHeight(int height); + void setPSImageableArea(int llx, int lly, int urx, int ury); + void setPSDuplex(GBool duplex); + void setPSCrop(GBool crop); + void setPSExpandSmaller(GBool expand); + void setPSShrinkLarger(GBool shrink); + void setPSCenter(GBool center); + void setPSLevel(PSLevel level); + void setPSEmbedType1(GBool embed); + void setPSEmbedTrueType(GBool embed); + void setPSEmbedCIDPostScript(GBool embed); + void setPSEmbedCIDTrueType(GBool embed); + void setPSPreload(GBool preload); + void setPSOPI(GBool opi); + void setPSASCIIHex(GBool hex); + void setTextEncoding(char *encodingName); + GBool setTextEOL(char *s); + void setTextPageBreaks(GBool pageBreaks); + void setTextKeepTinyChars(GBool keep); + void setInitialZoom(char *s); + void setContinuousView(GBool cont); + GBool setEnableT1lib(char *s); + GBool setEnableFreeType(char *s); + GBool setAntialias(char *s); + GBool setVectorAntialias(char *s); + void setScreenType(ScreenType t); + void setScreenSize(int size); + void setScreenDotRadius(int r); + void setScreenGamma(double gamma); + void setScreenBlackThreshold(double thresh); + void setScreenWhiteThreshold(double thresh); + void setMapNumericCharNames(GBool map); + void setMapUnknownCharNames(GBool map); + void setPrintCommands(GBool printCommandsA); + void setErrQuiet(GBool errQuietA); + + //----- security handlers + + void addSecurityHandler(XpdfSecurityHandler *handler); + XpdfSecurityHandler *getSecurityHandler(char *name); + +private: + + void createDefaultKeyBindings(); + void parseFile(GString *fileName, FILE *f); + void parseNameToUnicode(GList *tokens, GString *fileName, int line); + void parseCIDToUnicode(GList *tokens, GString *fileName, int line); + void parseUnicodeToUnicode(GList *tokens, GString *fileName, int line); + void parseUnicodeMap(GList *tokens, GString *fileName, int line); + void parseCMapDir(GList *tokens, GString *fileName, int line); + void parseToUnicodeDir(GList *tokens, GString *fileName, int line); + void parseDisplayFont(GList *tokens, GHash *fontHash, + DisplayFontParamKind kind, + GString *fileName, int line); + void parsePSFile(GList *tokens, GString *fileName, int line); + void parsePSPaperSize(GList *tokens, GString *fileName, int line); + void parsePSImageableArea(GList *tokens, GString *fileName, int line); + void parsePSLevel(GList *tokens, GString *fileName, int line); + void parsePSFont(GList *tokens, GString *fileName, int line); + void parsePSFont16(char *cmdName, GList *fontList, + GList *tokens, GString *fileName, int line); + void parseTextEncoding(GList *tokens, GString *fileName, int line); + void parseTextEOL(GList *tokens, GString *fileName, int line); + void parseFontDir(GList *tokens, GString *fileName, int line); + void parseInitialZoom(GList *tokens, GString *fileName, int line); + void parseScreenType(GList *tokens, GString *fileName, int line); + void parseBind(GList *tokens, GString *fileName, int line); + void parseUnbind(GList *tokens, GString *fileName, int line); + GBool parseKey(GString *modKeyStr, GString *contextStr, + int *code, int *mods, int *context, + char *cmdName, + GList *tokens, GString *fileName, int line); + void parseCommand(char *cmdName, GString **val, + GList *tokens, GString *fileName, int line); + void parseYesNo(char *cmdName, GBool *flag, + GList *tokens, GString *fileName, int line); + GBool parseYesNo2(char *token, GBool *flag); + void parseInteger(char *cmdName, int *val, + GList *tokens, GString *fileName, int line); + void parseFloat(char *cmdName, double *val, + GList *tokens, GString *fileName, int line); + UnicodeMap *getUnicodeMap2(GString *encodingName); +#ifdef ENABLE_PLUGINS + GBool loadPlugin(char *type, char *name); +#endif + + //----- static tables + + NameToCharCode * // mapping from char name to + macRomanReverseMap; // MacRomanEncoding index + + //----- user-modifiable settings + + GString *baseDir; // base directory - for plugins, etc. + NameToCharCode * // mapping from char name to Unicode + nameToUnicode; + GHash *cidToUnicodes; // files for mappings from char collections + // to Unicode, indexed by collection name + // [GString] + GHash *unicodeToUnicodes; // files for Unicode-to-Unicode mappings, + // indexed by font name pattern [GString] + GHash *residentUnicodeMaps; // mappings from Unicode to char codes, + // indexed by encoding name [UnicodeMap] + GHash *unicodeMaps; // files for mappings from Unicode to char + // codes, indexed by encoding name [GString] + GHash *cMapDirs; // list of CMap dirs, indexed by collection + // name [GList[GString]] + GList *toUnicodeDirs; // list of ToUnicode CMap dirs [GString] + GHash *displayFonts; // display font info, indexed by font name + // [DisplayFontParam] +#ifdef WIN32 + WinFontList *winFontList; // system TrueType fonts +#endif + GHash *displayCIDFonts; // display CID font info, indexed by + // collection [DisplayFontParam] + GHash *displayNamedCIDFonts; // display CID font info, indexed by + // font name [DisplayFontParam] + GString *psFile; // PostScript file or command (for xpdf) + int psPaperWidth; // paper size, in PostScript points, for + int psPaperHeight; // PostScript output + int psImageableLLX, // imageable area, in PostScript points, + psImageableLLY, // for PostScript output + psImageableURX, + psImageableURY; + GBool psCrop; // crop PS output to CropBox + GBool psExpandSmaller; // expand smaller pages to fill paper + GBool psShrinkLarger; // shrink larger pages to fit paper + GBool psCenter; // center pages on the paper + GBool psDuplex; // enable duplexing in PostScript? + PSLevel psLevel; // PostScript level to generate + GHash *psFonts; // PostScript font info, indexed by PDF + // font name [PSFontParam] + GList *psNamedFonts16; // named 16-bit fonts [PSFontParam] + GList *psFonts16; // generic 16-bit fonts [PSFontParam] + GBool psEmbedType1; // embed Type 1 fonts? + GBool psEmbedTrueType; // embed TrueType fonts? + GBool psEmbedCIDPostScript; // embed CID PostScript fonts? + GBool psEmbedCIDTrueType; // embed CID TrueType fonts? + GBool psPreload; // preload PostScript images and forms into + // memory + GBool psOPI; // generate PostScript OPI comments? + GBool psASCIIHex; // use ASCIIHex instead of ASCII85? + GString *textEncoding; // encoding (unicodeMap) to use for text + // output + EndOfLineKind textEOL; // type of EOL marker to use for text + // output + GBool textPageBreaks; // insert end-of-page markers? + GBool textKeepTinyChars; // keep all characters in text output + GList *fontDirs; // list of font dirs [GString] + GString *initialZoom; // initial zoom level + GBool continuousView; // continuous view mode + GBool enableT1lib; // t1lib enable flag + GBool enableFreeType; // FreeType enable flag + GBool antialias; // font anti-aliasing enable flag + GBool vectorAntialias; // vector anti-aliasing enable flag + GBool strokeAdjust; // stroke adjustment enable flag + ScreenType screenType; // halftone screen type + int screenSize; // screen matrix size + int screenDotRadius; // screen dot radius + double screenGamma; // screen gamma correction + double screenBlackThreshold; // screen black clamping threshold + double screenWhiteThreshold; // screen white clamping threshold + GString *urlCommand; // command executed for URL links + GString *movieCommand; // command executed for movie annotations + GBool mapNumericCharNames; // map numeric char names (from font subsets)? + GBool mapUnknownCharNames; // map unknown char names? + GList *keyBindings; // key & mouse button bindings [KeyBinding] + GBool printCommands; // print the drawing commands + GBool errQuiet; // suppress error messages? + + CharCodeToUnicodeCache *cidToUnicodeCache; + CharCodeToUnicodeCache *unicodeToUnicodeCache; + UnicodeMapCache *unicodeMapCache; + CMapCache *cMapCache; + +#ifdef ENABLE_PLUGINS + GList *plugins; // list of plugins [Plugin] + GList *securityHandlers; // list of loaded security handlers + // [XpdfSecurityHandler] +#endif + +#if MULTITHREADED + GMutex mutex; + GMutex unicodeMapCacheMutex; + GMutex cMapCacheMutex; +#endif +}; + +#endif diff --git a/kpdf/xpdf/xpdf/JArithmeticDecoder.cc b/kpdf/xpdf/xpdf/JArithmeticDecoder.cc new file mode 100644 index 00000000..195b73e1 --- /dev/null +++ b/kpdf/xpdf/xpdf/JArithmeticDecoder.cc @@ -0,0 +1,322 @@ +//======================================================================== +// +// JArithmeticDecoder.cc +// +// Copyright 2002-2004 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "Object.h" +#include "Stream.h" +#include "JArithmeticDecoder.h" + +//------------------------------------------------------------------------ +// JArithmeticDecoderStates +//------------------------------------------------------------------------ + +JArithmeticDecoderStats::JArithmeticDecoderStats(int contextSizeA) { + contextSize = contextSizeA; + cxTab = (Guchar *)gmallocn(contextSize, sizeof(Guchar)); + reset(); +} + +JArithmeticDecoderStats::~JArithmeticDecoderStats() { + gfree(cxTab); +} + +JArithmeticDecoderStats *JArithmeticDecoderStats::copy() { + JArithmeticDecoderStats *stats; + + stats = new JArithmeticDecoderStats(contextSize); + memcpy(stats->cxTab, cxTab, contextSize); + return stats; +} + +void JArithmeticDecoderStats::reset() { + memset(cxTab, 0, contextSize); +} + +void JArithmeticDecoderStats::copyFrom(JArithmeticDecoderStats *stats) { + memcpy(cxTab, stats->cxTab, contextSize); +} + +void JArithmeticDecoderStats::setEntry(Guint cx, int i, int mps) { + cxTab[cx] = (i << 1) + mps; +} + +//------------------------------------------------------------------------ +// JArithmeticDecoder +//------------------------------------------------------------------------ + +Guint JArithmeticDecoder::qeTab[47] = { + 0x56010000, 0x34010000, 0x18010000, 0x0AC10000, + 0x05210000, 0x02210000, 0x56010000, 0x54010000, + 0x48010000, 0x38010000, 0x30010000, 0x24010000, + 0x1C010000, 0x16010000, 0x56010000, 0x54010000, + 0x51010000, 0x48010000, 0x38010000, 0x34010000, + 0x30010000, 0x28010000, 0x24010000, 0x22010000, + 0x1C010000, 0x18010000, 0x16010000, 0x14010000, + 0x12010000, 0x11010000, 0x0AC10000, 0x09C10000, + 0x08A10000, 0x05210000, 0x04410000, 0x02A10000, + 0x02210000, 0x01410000, 0x01110000, 0x00850000, + 0x00490000, 0x00250000, 0x00150000, 0x00090000, + 0x00050000, 0x00010000, 0x56010000 +}; + +int JArithmeticDecoder::nmpsTab[47] = { + 1, 2, 3, 4, 5, 38, 7, 8, 9, 10, 11, 12, 13, 29, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 45, 46 +}; + +int JArithmeticDecoder::nlpsTab[47] = { + 1, 6, 9, 12, 29, 33, 6, 14, 14, 14, 17, 18, 20, 21, 14, 14, + 15, 16, 17, 18, 19, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 46 +}; + +int JArithmeticDecoder::switchTab[47] = { + 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +JArithmeticDecoder::JArithmeticDecoder() { + str = NULL; + dataLen = 0; + limitStream = gFalse; +} + +inline Guint JArithmeticDecoder::readByte() { + if (limitStream) { + --dataLen; + if (dataLen < 0) { + return 0xff; + } + } + return (Guint)str->getChar() & 0xff; +} + +JArithmeticDecoder::~JArithmeticDecoder() { + cleanup(); +} + +void JArithmeticDecoder::start() { + buf0 = readByte(); + buf1 = readByte(); + + // INITDEC + c = (buf0 ^ 0xff) << 16; + byteIn(); + c <<= 7; + ct -= 7; + a = 0x80000000; +} + +void JArithmeticDecoder::restart(int dataLenA) { + int oldDataLen; + + oldDataLen = dataLen; + dataLen = dataLenA; + if (oldDataLen == -1) { + buf1 = readByte(); + } else if (oldDataLen <= -2) { + buf0 = readByte(); + buf1 = readByte(); + } +} + +void JArithmeticDecoder::cleanup() { + if (limitStream) { + while (dataLen > 0) { + buf0 = buf1; + buf1 = readByte(); + } + } +} + +int JArithmeticDecoder::decodeBit(Guint context, + JArithmeticDecoderStats *stats) { + int bit; + Guint qe; + int iCX, mpsCX; + + iCX = stats->cxTab[context] >> 1; + mpsCX = stats->cxTab[context] & 1; + qe = qeTab[iCX]; + a -= qe; + if (c < a) { + if (a & 0x80000000) { + bit = mpsCX; + } else { + // MPS_EXCHANGE + if (a < qe) { + bit = 1 - mpsCX; + if (switchTab[iCX]) { + stats->cxTab[context] = (nlpsTab[iCX] << 1) | (1 - mpsCX); + } else { + stats->cxTab[context] = (nlpsTab[iCX] << 1) | mpsCX; + } + } else { + bit = mpsCX; + stats->cxTab[context] = (nmpsTab[iCX] << 1) | mpsCX; + } + // RENORMD + do { + if (ct == 0) { + byteIn(); + } + a <<= 1; + c <<= 1; + --ct; + } while (!(a & 0x80000000)); + } + } else { + c -= a; + // LPS_EXCHANGE + if (a < qe) { + bit = mpsCX; + stats->cxTab[context] = (nmpsTab[iCX] << 1) | mpsCX; + } else { + bit = 1 - mpsCX; + if (switchTab[iCX]) { + stats->cxTab[context] = (nlpsTab[iCX] << 1) | (1 - mpsCX); + } else { + stats->cxTab[context] = (nlpsTab[iCX] << 1) | mpsCX; + } + } + a = qe; + // RENORMD + do { + if (ct == 0) { + byteIn(); + } + a <<= 1; + c <<= 1; + --ct; + } while (!(a & 0x80000000)); + } + return bit; +} + +int JArithmeticDecoder::decodeByte(Guint context, + JArithmeticDecoderStats *stats) { + int byte; + int i; + + byte = 0; + for (i = 0; i < 8; ++i) { + byte = (byte << 1) | decodeBit(context, stats); + } + return byte; +} + +GBool JArithmeticDecoder::decodeInt(int *x, JArithmeticDecoderStats *stats) { + int s; + Guint v; + int i; + + prev = 1; + s = decodeIntBit(stats); + if (decodeIntBit(stats)) { + if (decodeIntBit(stats)) { + if (decodeIntBit(stats)) { + if (decodeIntBit(stats)) { + if (decodeIntBit(stats)) { + v = 0; + for (i = 0; i < 32; ++i) { + v = (v << 1) | decodeIntBit(stats); + } + v += 4436; + } else { + v = 0; + for (i = 0; i < 12; ++i) { + v = (v << 1) | decodeIntBit(stats); + } + v += 340; + } + } else { + v = 0; + for (i = 0; i < 8; ++i) { + v = (v << 1) | decodeIntBit(stats); + } + v += 84; + } + } else { + v = 0; + for (i = 0; i < 6; ++i) { + v = (v << 1) | decodeIntBit(stats); + } + v += 20; + } + } else { + v = decodeIntBit(stats); + v = (v << 1) | decodeIntBit(stats); + v = (v << 1) | decodeIntBit(stats); + v = (v << 1) | decodeIntBit(stats); + v += 4; + } + } else { + v = decodeIntBit(stats); + v = (v << 1) | decodeIntBit(stats); + } + + if (s) { + if (v == 0) { + return gFalse; + } + *x = -(int)v; + } else { + *x = (int)v; + } + return gTrue; +} + +int JArithmeticDecoder::decodeIntBit(JArithmeticDecoderStats *stats) { + int bit; + + bit = decodeBit(prev, stats); + if (prev < 0x100) { + prev = (prev << 1) | bit; + } else { + prev = (((prev << 1) | bit) & 0x1ff) | 0x100; + } + return bit; +} + +Guint JArithmeticDecoder::decodeIAID(Guint codeLen, + JArithmeticDecoderStats *stats) { + Guint i; + int bit; + + prev = 1; + for (i = 0; i < codeLen; ++i) { + bit = decodeBit(prev, stats); + prev = (prev << 1) | bit; + } + return prev - (1 << codeLen); +} + +void JArithmeticDecoder::byteIn() { + if (buf0 == 0xff) { + if (buf1 > 0x8f) { + ct = 8; + } else { + buf0 = buf1; + buf1 = readByte(); + c = c + 0xfe00 - (buf0 << 9); + ct = 7; + } + } else { + buf0 = buf1; + buf1 = readByte(); + c = c + 0xff00 - (buf0 << 8); + ct = 8; + } +} diff --git a/kpdf/xpdf/xpdf/JArithmeticDecoder.h b/kpdf/xpdf/xpdf/JArithmeticDecoder.h new file mode 100644 index 00000000..a40823dd --- /dev/null +++ b/kpdf/xpdf/xpdf/JArithmeticDecoder.h @@ -0,0 +1,109 @@ +//======================================================================== +// +// JArithmeticDecoder.h +// +// Arithmetic decoder used by the JBIG2 and JPEG2000 decoders. +// +// Copyright 2002-2004 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef JARITHMETICDECODER_H +#define JARITHMETICDECODER_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +class Stream; + +//------------------------------------------------------------------------ +// JArithmeticDecoderStats +//------------------------------------------------------------------------ + +class JArithmeticDecoderStats { +public: + + JArithmeticDecoderStats(int contextSizeA); + ~JArithmeticDecoderStats(); + JArithmeticDecoderStats *copy(); + void reset(); + int getContextSize() { return contextSize; } + void copyFrom(JArithmeticDecoderStats *stats); + void setEntry(Guint cx, int i, int mps); + +private: + + Guchar *cxTab; // cxTab[cx] = (i[cx] << 1) + mps[cx] + int contextSize; + + friend class JArithmeticDecoder; +}; + +//------------------------------------------------------------------------ +// JArithmeticDecoder +//------------------------------------------------------------------------ + +class JArithmeticDecoder { +public: + + JArithmeticDecoder(); + ~JArithmeticDecoder(); + + void setStream(Stream *strA) + { str = strA; dataLen = 0; limitStream = gFalse; } + void setStream(Stream *strA, int dataLenA) + { str = strA; dataLen = dataLenA; limitStream = gTrue; } + + // Start decoding on a new stream. This fills the byte buffers and + // runs INITDEC. + void start(); + + // Restart decoding on an interrupted stream. This refills the + // buffers if needed, but does not run INITDEC. (This is used in + // JPEG 2000 streams when codeblock data is split across multiple + // packets/layers.) + void restart(int dataLenA); + + // Read any leftover data in the stream. + void cleanup(); + + // Decode one bit. + int decodeBit(Guint context, JArithmeticDecoderStats *stats); + + // Decode eight bits. + int decodeByte(Guint context, JArithmeticDecoderStats *stats); + + // Returns false for OOB, otherwise sets * and returns true. + GBool decodeInt(int *x, JArithmeticDecoderStats *stats); + + Guint decodeIAID(Guint codeLen, + JArithmeticDecoderStats *stats); + +private: + + Guint readByte(); + int decodeIntBit(JArithmeticDecoderStats *stats); + void byteIn(); + + static Guint qeTab[47]; + static int nmpsTab[47]; + static int nlpsTab[47]; + static int switchTab[47]; + + Guint buf0, buf1; + Guint c, a; + int ct; + + Guint prev; // for the integer decoder + + Stream *str; + int dataLen; + GBool limitStream; +}; + +#endif diff --git a/kpdf/xpdf/xpdf/JBIG2Stream.cc b/kpdf/xpdf/xpdf/JBIG2Stream.cc new file mode 100644 index 00000000..43f17712 --- /dev/null +++ b/kpdf/xpdf/xpdf/JBIG2Stream.cc @@ -0,0 +1,3648 @@ +//======================================================================== +// +// JBIG2Stream.cc +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "GList.h" +#include "Error.h" +#include "JArithmeticDecoder.h" +#include "JBIG2Stream.h" + +//~ share these tables +#include "Stream-CCITT.h" + +//------------------------------------------------------------------------ + +static int contextSize[4] = { 16, 13, 10, 10 }; +static int refContextSize[2] = { 13, 10 }; + +//------------------------------------------------------------------------ +// JBIG2HuffmanTable +//------------------------------------------------------------------------ + +#define jbig2HuffmanLOW 0xfffffffd +#define jbig2HuffmanOOB 0xfffffffe +#define jbig2HuffmanEOT 0xffffffff + +struct JBIG2HuffmanTable { + int val; + Guint prefixLen; + Guint rangeLen; // can also be LOW, OOB, or EOT + Guint prefix; +}; + +JBIG2HuffmanTable huffTableA[] = { + { 0, 1, 4, 0x000 }, + { 16, 2, 8, 0x002 }, + { 272, 3, 16, 0x006 }, + { 65808, 3, 32, 0x007 }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableB[] = { + { 0, 1, 0, 0x000 }, + { 1, 2, 0, 0x002 }, + { 2, 3, 0, 0x006 }, + { 3, 4, 3, 0x00e }, + { 11, 5, 6, 0x01e }, + { 75, 6, 32, 0x03e }, + { 0, 6, jbig2HuffmanOOB, 0x03f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableC[] = { + { 0, 1, 0, 0x000 }, + { 1, 2, 0, 0x002 }, + { 2, 3, 0, 0x006 }, + { 3, 4, 3, 0x00e }, + { 11, 5, 6, 0x01e }, + { 0, 6, jbig2HuffmanOOB, 0x03e }, + { 75, 7, 32, 0x0fe }, + { -256, 8, 8, 0x0fe }, + { -257, 8, jbig2HuffmanLOW, 0x0ff }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableD[] = { + { 1, 1, 0, 0x000 }, + { 2, 2, 0, 0x002 }, + { 3, 3, 0, 0x006 }, + { 4, 4, 3, 0x00e }, + { 12, 5, 6, 0x01e }, + { 76, 5, 32, 0x01f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableE[] = { + { 1, 1, 0, 0x000 }, + { 2, 2, 0, 0x002 }, + { 3, 3, 0, 0x006 }, + { 4, 4, 3, 0x00e }, + { 12, 5, 6, 0x01e }, + { 76, 6, 32, 0x03e }, + { -255, 7, 8, 0x07e }, + { -256, 7, jbig2HuffmanLOW, 0x07f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableF[] = { + { 0, 2, 7, 0x000 }, + { 128, 3, 7, 0x002 }, + { 256, 3, 8, 0x003 }, + { -1024, 4, 9, 0x008 }, + { -512, 4, 8, 0x009 }, + { -256, 4, 7, 0x00a }, + { -32, 4, 5, 0x00b }, + { 512, 4, 9, 0x00c }, + { 1024, 4, 10, 0x00d }, + { -2048, 5, 10, 0x01c }, + { -128, 5, 6, 0x01d }, + { -64, 5, 5, 0x01e }, + { -2049, 6, jbig2HuffmanLOW, 0x03e }, + { 2048, 6, 32, 0x03f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableG[] = { + { -512, 3, 8, 0x000 }, + { 256, 3, 8, 0x001 }, + { 512, 3, 9, 0x002 }, + { 1024, 3, 10, 0x003 }, + { -1024, 4, 9, 0x008 }, + { -256, 4, 7, 0x009 }, + { -32, 4, 5, 0x00a }, + { 0, 4, 5, 0x00b }, + { 128, 4, 7, 0x00c }, + { -128, 5, 6, 0x01a }, + { -64, 5, 5, 0x01b }, + { 32, 5, 5, 0x01c }, + { 64, 5, 6, 0x01d }, + { -1025, 5, jbig2HuffmanLOW, 0x01e }, + { 2048, 5, 32, 0x01f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableH[] = { + { 0, 2, 1, 0x000 }, + { 0, 2, jbig2HuffmanOOB, 0x001 }, + { 4, 3, 4, 0x004 }, + { -1, 4, 0, 0x00a }, + { 22, 4, 4, 0x00b }, + { 38, 4, 5, 0x00c }, + { 2, 5, 0, 0x01a }, + { 70, 5, 6, 0x01b }, + { 134, 5, 7, 0x01c }, + { 3, 6, 0, 0x03a }, + { 20, 6, 1, 0x03b }, + { 262, 6, 7, 0x03c }, + { 646, 6, 10, 0x03d }, + { -2, 7, 0, 0x07c }, + { 390, 7, 8, 0x07d }, + { -15, 8, 3, 0x0fc }, + { -5, 8, 1, 0x0fd }, + { -7, 9, 1, 0x1fc }, + { -3, 9, 0, 0x1fd }, + { -16, 9, jbig2HuffmanLOW, 0x1fe }, + { 1670, 9, 32, 0x1ff }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableI[] = { + { 0, 2, jbig2HuffmanOOB, 0x000 }, + { -1, 3, 1, 0x002 }, + { 1, 3, 1, 0x003 }, + { 7, 3, 5, 0x004 }, + { -3, 4, 1, 0x00a }, + { 43, 4, 5, 0x00b }, + { 75, 4, 6, 0x00c }, + { 3, 5, 1, 0x01a }, + { 139, 5, 7, 0x01b }, + { 267, 5, 8, 0x01c }, + { 5, 6, 1, 0x03a }, + { 39, 6, 2, 0x03b }, + { 523, 6, 8, 0x03c }, + { 1291, 6, 11, 0x03d }, + { -5, 7, 1, 0x07c }, + { 779, 7, 9, 0x07d }, + { -31, 8, 4, 0x0fc }, + { -11, 8, 2, 0x0fd }, + { -15, 9, 2, 0x1fc }, + { -7, 9, 1, 0x1fd }, + { -32, 9, jbig2HuffmanLOW, 0x1fe }, + { 3339, 9, 32, 0x1ff }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableJ[] = { + { -2, 2, 2, 0x000 }, + { 6, 2, 6, 0x001 }, + { 0, 2, jbig2HuffmanOOB, 0x002 }, + { -3, 5, 0, 0x018 }, + { 2, 5, 0, 0x019 }, + { 70, 5, 5, 0x01a }, + { 3, 6, 0, 0x036 }, + { 102, 6, 5, 0x037 }, + { 134, 6, 6, 0x038 }, + { 198, 6, 7, 0x039 }, + { 326, 6, 8, 0x03a }, + { 582, 6, 9, 0x03b }, + { 1094, 6, 10, 0x03c }, + { -21, 7, 4, 0x07a }, + { -4, 7, 0, 0x07b }, + { 4, 7, 0, 0x07c }, + { 2118, 7, 11, 0x07d }, + { -5, 8, 0, 0x0fc }, + { 5, 8, 0, 0x0fd }, + { -22, 8, jbig2HuffmanLOW, 0x0fe }, + { 4166, 8, 32, 0x0ff }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableK[] = { + { 1, 1, 0, 0x000 }, + { 2, 2, 1, 0x002 }, + { 4, 4, 0, 0x00c }, + { 5, 4, 1, 0x00d }, + { 7, 5, 1, 0x01c }, + { 9, 5, 2, 0x01d }, + { 13, 6, 2, 0x03c }, + { 17, 7, 2, 0x07a }, + { 21, 7, 3, 0x07b }, + { 29, 7, 4, 0x07c }, + { 45, 7, 5, 0x07d }, + { 77, 7, 6, 0x07e }, + { 141, 7, 32, 0x07f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableL[] = { + { 1, 1, 0, 0x000 }, + { 2, 2, 0, 0x002 }, + { 3, 3, 1, 0x006 }, + { 5, 5, 0, 0x01c }, + { 6, 5, 1, 0x01d }, + { 8, 6, 1, 0x03c }, + { 10, 7, 0, 0x07a }, + { 11, 7, 1, 0x07b }, + { 13, 7, 2, 0x07c }, + { 17, 7, 3, 0x07d }, + { 25, 7, 4, 0x07e }, + { 41, 8, 5, 0x0fe }, + { 73, 8, 32, 0x0ff }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableM[] = { + { 1, 1, 0, 0x000 }, + { 2, 3, 0, 0x004 }, + { 7, 3, 3, 0x005 }, + { 3, 4, 0, 0x00c }, + { 5, 4, 1, 0x00d }, + { 4, 5, 0, 0x01c }, + { 15, 6, 1, 0x03a }, + { 17, 6, 2, 0x03b }, + { 21, 6, 3, 0x03c }, + { 29, 6, 4, 0x03d }, + { 45, 6, 5, 0x03e }, + { 77, 7, 6, 0x07e }, + { 141, 7, 32, 0x07f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableN[] = { + { 0, 1, 0, 0x000 }, + { -2, 3, 0, 0x004 }, + { -1, 3, 0, 0x005 }, + { 1, 3, 0, 0x006 }, + { 2, 3, 0, 0x007 }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableO[] = { + { 0, 1, 0, 0x000 }, + { -1, 3, 0, 0x004 }, + { 1, 3, 0, 0x005 }, + { -2, 4, 0, 0x00c }, + { 2, 4, 0, 0x00d }, + { -4, 5, 1, 0x01c }, + { 3, 5, 1, 0x01d }, + { -8, 6, 2, 0x03c }, + { 5, 6, 2, 0x03d }, + { -24, 7, 4, 0x07c }, + { 9, 7, 4, 0x07d }, + { -25, 7, jbig2HuffmanLOW, 0x07e }, + { 25, 7, 32, 0x07f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +//------------------------------------------------------------------------ +// JBIG2HuffmanDecoder +//------------------------------------------------------------------------ + +class JBIG2HuffmanDecoder { +public: + + JBIG2HuffmanDecoder(); + ~JBIG2HuffmanDecoder(); + void setStream(Stream *strA) { str = strA; } + + void reset(); + + // Returns false for OOB, otherwise sets * and returns true. + GBool decodeInt(int *x, JBIG2HuffmanTable *table); + + Guint readBits(Guint n); + Guint readBit(); + + // Sort the table by prefix length and assign prefix values. + void buildTable(JBIG2HuffmanTable *table, Guint len); + +private: + + Stream *str; + Guint buf; + Guint bufLen; +}; + +JBIG2HuffmanDecoder::JBIG2HuffmanDecoder() { + str = NULL; + reset(); +} + +JBIG2HuffmanDecoder::~JBIG2HuffmanDecoder() { +} + +void JBIG2HuffmanDecoder::reset() { + buf = 0; + bufLen = 0; +} + +//~ optimize this +GBool JBIG2HuffmanDecoder::decodeInt(int *x, JBIG2HuffmanTable *table) { + Guint i, len, prefix; + + i = 0; + len = 0; + prefix = 0; + while (table[i].rangeLen != jbig2HuffmanEOT) { + while (len < table[i].prefixLen) { + prefix = (prefix << 1) | readBit(); + ++len; + } + if (prefix == table[i].prefix) { + if (table[i].rangeLen == jbig2HuffmanOOB) { + return gFalse; + } + if (table[i].rangeLen == jbig2HuffmanLOW) { + *x = table[i].val - readBits(32); + } else if (table[i].rangeLen > 0) { + *x = table[i].val + readBits(table[i].rangeLen); + } else { + *x = table[i].val; + } + return gTrue; + } + ++i; + } + return gFalse; +} + +Guint JBIG2HuffmanDecoder::readBits(Guint n) { + Guint x, mask, nLeft; + + mask = (n == 32) ? 0xffffffff : ((1 << n) - 1); + if (bufLen >= n) { + x = (buf >> (bufLen - n)) & mask; + bufLen -= n; + } else { + x = buf & ((1 << bufLen) - 1); + nLeft = n - bufLen; + bufLen = 0; + while (nLeft >= 8) { + x = (x << 8) | (str->getChar() & 0xff); + nLeft -= 8; + } + if (nLeft > 0) { + buf = str->getChar(); + bufLen = 8 - nLeft; + x = (x << nLeft) | ((buf >> bufLen) & ((1 << nLeft) - 1)); + } + } + return x; +} + +Guint JBIG2HuffmanDecoder::readBit() { + if (bufLen == 0) { + buf = str->getChar(); + bufLen = 8; + } + --bufLen; + return (buf >> bufLen) & 1; +} + +void JBIG2HuffmanDecoder::buildTable(JBIG2HuffmanTable *table, Guint len) { + Guint i, j, k, prefix; + JBIG2HuffmanTable tab; + + // stable selection sort: + // - entries with prefixLen > 0, in ascending prefixLen order + // - entry with prefixLen = 0, rangeLen = EOT + // - all other entries with prefixLen = 0 + // (on entry, table[len] has prefixLen = 0, rangeLen = EOT) + for (i = 0; i < len; ++i) { + for (j = i; j < len && table[j].prefixLen == 0; ++j) ; + if (j == len) { + break; + } + for (k = j + 1; k < len; ++k) { + if (table[k].prefixLen > 0 && + table[k].prefixLen < table[j].prefixLen) { + j = k; + } + } + if (j != i) { + tab = table[j]; + for (k = j; k > i; --k) { + table[k] = table[k - 1]; + } + table[i] = tab; + } + } + table[i] = table[len]; + + // assign prefixes + if (table[0].rangeLen != jbig2HuffmanEOT) { + i = 0; + prefix = 0; + table[i++].prefix = prefix++; + for (; table[i].rangeLen != jbig2HuffmanEOT; ++i) { + prefix <<= table[i].prefixLen - table[i-1].prefixLen; + table[i].prefix = prefix++; + } + } +} + +//------------------------------------------------------------------------ +// JBIG2MMRDecoder +//------------------------------------------------------------------------ + +class JBIG2MMRDecoder { +public: + + JBIG2MMRDecoder(); + ~JBIG2MMRDecoder(); + void setStream(Stream *strA) { str = strA; } + void reset(); + int get2DCode(); + int getBlackCode(); + int getWhiteCode(); + Guint get24Bits(); + void skipTo(Guint length); + +private: + + Stream *str; + Guint buf; + Guint bufLen; + Guint nBytesRead; +}; + +JBIG2MMRDecoder::JBIG2MMRDecoder() { + str = NULL; + reset(); +} + +JBIG2MMRDecoder::~JBIG2MMRDecoder() { +} + +void JBIG2MMRDecoder::reset() { + buf = 0; + bufLen = 0; + nBytesRead = 0; +} + +int JBIG2MMRDecoder::get2DCode() { + CCITTCode *p; + + if (bufLen == 0) { + buf = str->getChar() & 0xff; + bufLen = 8; + ++nBytesRead; + p = &twoDimTab1[(buf >> 1) & 0x7f]; + } else if (bufLen == 8) { + p = &twoDimTab1[(buf >> 1) & 0x7f]; + } else { + p = &twoDimTab1[(buf << (7 - bufLen)) & 0x7f]; + if (p->bits < 0 || p->bits > (int)bufLen) { + buf = (buf << 8) | (str->getChar() & 0xff); + bufLen += 8; + ++nBytesRead; + p = &twoDimTab1[(buf >> (bufLen - 7)) & 0x7f]; + } + } + if (p->bits < 0) { + error(str->getPos(), "Bad two dim code in JBIG2 MMR stream"); + return EOF; + } + bufLen -= p->bits; + return p->n; +} + +int JBIG2MMRDecoder::getWhiteCode() { + CCITTCode *p; + Guint code; + + if (bufLen == 0) { + buf = str->getChar() & 0xff; + bufLen = 8; + ++nBytesRead; + } + while (1) { + if (bufLen >= 11 && ((buf >> (bufLen - 7)) & 0x7f) == 0) { + if (bufLen <= 12) { + code = buf << (12 - bufLen); + } else { + code = buf >> (bufLen - 12); + } + p = &whiteTab1[code & 0x1f]; + } else { + if (bufLen <= 9) { + code = buf << (9 - bufLen); + } else { + code = buf >> (bufLen - 9); + } + p = &whiteTab2[code & 0x1ff]; + } + if (p->bits > 0 && p->bits <= (int)bufLen) { + bufLen -= p->bits; + return p->n; + } + if (bufLen >= 12) { + break; + } + buf = (buf << 8) | (str->getChar() & 0xff); + bufLen += 8; + ++nBytesRead; + } + error(str->getPos(), "Bad white code in JBIG2 MMR stream"); + // eat a bit and return a positive number so that the caller doesn't + // go into an infinite loop + --bufLen; + return 1; +} + +int JBIG2MMRDecoder::getBlackCode() { + CCITTCode *p; + Guint code; + + if (bufLen == 0) { + buf = str->getChar() & 0xff; + bufLen = 8; + ++nBytesRead; + } + while (1) { + if (bufLen >= 10 && ((buf >> (bufLen - 6)) & 0x3f) == 0) { + if (bufLen <= 13) { + code = buf << (13 - bufLen); + } else { + code = buf >> (bufLen - 13); + } + p = &blackTab1[code & 0x7f]; + } else if (bufLen >= 7 && ((buf >> (bufLen - 4)) & 0x0f) == 0 && + ((buf >> (bufLen - 6)) & 0x03) != 0) { + if (bufLen <= 12) { + code = buf << (12 - bufLen); + } else { + code = buf >> (bufLen - 12); + } + p = &blackTab2[(code & 0xff) - 64]; + } else { + if (bufLen <= 6) { + code = buf << (6 - bufLen); + } else { + code = buf >> (bufLen - 6); + } + p = &blackTab3[code & 0x3f]; + } + if (p->bits > 0 && p->bits <= (int)bufLen) { + bufLen -= p->bits; + return p->n; + } + if (bufLen >= 13) { + break; + } + buf = (buf << 8) | (str->getChar() & 0xff); + bufLen += 8; + ++nBytesRead; + } + error(str->getPos(), "Bad black code in JBIG2 MMR stream"); + // eat a bit and return a positive number so that the caller doesn't + // go into an infinite loop + --bufLen; + return 1; +} + +Guint JBIG2MMRDecoder::get24Bits() { + while (bufLen < 24) { + buf = (buf << 8) | (str->getChar() & 0xff); + bufLen += 8; + ++nBytesRead; + } + return (buf >> (bufLen - 24)) & 0xffffff; +} + +void JBIG2MMRDecoder::skipTo(Guint length) { + while (nBytesRead < length) { + str->getChar(); + ++nBytesRead; + } +} + +//------------------------------------------------------------------------ +// JBIG2Segment +//------------------------------------------------------------------------ + +enum JBIG2SegmentType { + jbig2SegBitmap, + jbig2SegSymbolDict, + jbig2SegPatternDict, + jbig2SegCodeTable +}; + +class JBIG2Segment { +public: + + JBIG2Segment(Guint segNumA) { segNum = segNumA; } + virtual ~JBIG2Segment() {} + void setSegNum(Guint segNumA) { segNum = segNumA; } + Guint getSegNum() { return segNum; } + virtual JBIG2SegmentType getType() = 0; + +private: + + Guint segNum; +}; + +//------------------------------------------------------------------------ +// JBIG2Bitmap +//------------------------------------------------------------------------ + +struct JBIG2BitmapPtr { + Guchar *p; + int shift; + int x; +}; + +class JBIG2Bitmap: public JBIG2Segment { +public: + + JBIG2Bitmap(Guint segNumA, int wA, int hA); + virtual ~JBIG2Bitmap(); + virtual JBIG2SegmentType getType() { return jbig2SegBitmap; } + JBIG2Bitmap *copy() { return new JBIG2Bitmap(0, this); } + JBIG2Bitmap *getSlice(Guint x, Guint y, Guint wA, Guint hA); + void expand(int newH, Guint pixel); + void clearToZero(); + void clearToOne(); + int getWidth() { return w; } + int getHeight() { return h; } + int getPixel(int x, int y) + { return (x < 0 || x >= w || y < 0 || y >= h) ? 0 : + (data[y * line + (x >> 3)] >> (7 - (x & 7))) & 1; } + void setPixel(int x, int y) + { data[y * line + (x >> 3)] |= 1 << (7 - (x & 7)); } + void clearPixel(int x, int y) + { data[y * line + (x >> 3)] &= 0x7f7f >> (x & 7); } + void getPixelPtr(int x, int y, JBIG2BitmapPtr *ptr); + int nextPixel(JBIG2BitmapPtr *ptr); + void duplicateRow(int yDest, int ySrc); + void combine(JBIG2Bitmap *bitmap, int x, int y, Guint combOp); + Guchar *getDataPtr() { return data; } + int getDataSize() { return h * line; } + +private: + + JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap); + + int w, h, line; + Guchar *data; +}; + +JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, int wA, int hA): + JBIG2Segment(segNumA) +{ + w = wA; + h = hA; + line = (wA + 7) >> 3; + if (w <= 0 || h <= 0 || line <= 0 || h >= (INT_MAX - 1) / line) { + // force a call to gmalloc(-1), which will throw an exception + h = -1; + line = 2; + } + // need to allocate one extra guard byte for use in combine() + data = (Guchar *)gmalloc(h * line + 1); + data[h * line] = 0; +} + +JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap): + JBIG2Segment(segNumA) +{ + w = bitmap->w; + h = bitmap->h; + line = bitmap->line; + if (w <= 0 || h <= 0 || line <= 0 || h >= (INT_MAX - 1) / line) { + // force a call to gmalloc(-1), which will throw an exception + h = -1; + line = 2; + } + // need to allocate one extra guard byte for use in combine() + data = (Guchar *)gmalloc(h * line + 1); + memcpy(data, bitmap->data, h * line); + data[h * line] = 0; +} + +JBIG2Bitmap::~JBIG2Bitmap() { + gfree(data); +} + +//~ optimize this +JBIG2Bitmap *JBIG2Bitmap::getSlice(Guint x, Guint y, Guint wA, Guint hA) { + JBIG2Bitmap *slice; + Guint xx, yy; + + slice = new JBIG2Bitmap(0, wA, hA); + slice->clearToZero(); + for (yy = 0; yy < hA; ++yy) { + for (xx = 0; xx < wA; ++xx) { + if (getPixel(x + xx, y + yy)) { + slice->setPixel(xx, yy); + } + } + } + return slice; +} + +void JBIG2Bitmap::expand(int newH, Guint pixel) { + if (newH <= h || line <= 0 || newH >= (INT_MAX - 1) / line) { + return; + } + // need to allocate one extra guard byte for use in combine() + data = (Guchar *)grealloc(data, newH * line + 1); + if (pixel) { + memset(data + h * line, 0xff, (newH - h) * line); + } else { + memset(data + h * line, 0x00, (newH - h) * line); + } + h = newH; + data[h * line] = 0; +} + +void JBIG2Bitmap::clearToZero() { + memset(data, 0, h * line); +} + +void JBIG2Bitmap::clearToOne() { + memset(data, 0xff, h * line); +} + +inline void JBIG2Bitmap::getPixelPtr(int x, int y, JBIG2BitmapPtr *ptr) { + if (y < 0 || y >= h || x >= w) { + ptr->p = NULL; + ptr->shift = 0; // make gcc happy + ptr->x = 0; // make gcc happy + } else if (x < 0) { + ptr->p = &data[y * line]; + ptr->shift = 7; + ptr->x = x; + } else { + ptr->p = &data[y * line + (x >> 3)]; + ptr->shift = 7 - (x & 7); + ptr->x = x; + } +} + +inline int JBIG2Bitmap::nextPixel(JBIG2BitmapPtr *ptr) { + int pix; + + if (!ptr->p) { + pix = 0; + } else if (ptr->x < 0) { + ++ptr->x; + pix = 0; + } else { + pix = (*ptr->p >> ptr->shift) & 1; + if (++ptr->x == w) { + ptr->p = NULL; + } else if (ptr->shift == 0) { + ++ptr->p; + ptr->shift = 7; + } else { + --ptr->shift; + } + } + return pix; +} + +void JBIG2Bitmap::duplicateRow(int yDest, int ySrc) { + memcpy(data + yDest * line, data + ySrc * line, line); +} + +void JBIG2Bitmap::combine(JBIG2Bitmap *bitmap, int x, int y, + Guint combOp) { + int x0, x1, y0, y1, xx, yy; + Guchar *srcPtr, *destPtr; + Guint src0, src1, src, dest, s1, s2, m1, m2, m3; + GBool oneByte; + + // check for the pathological case where y = -2^31 + if (y < -0x7fffffff) { + return; + } + if (y < 0) { + y0 = -y; + } else { + y0 = 0; + } + if (y + bitmap->h > h) { + y1 = h - y; + } else { + y1 = bitmap->h; + } + if (y0 >= y1) { + return; + } + + if (x >= 0) { + x0 = x & ~7; + } else { + x0 = 0; + } + x1 = x + bitmap->w; + if (x1 > w) { + x1 = w; + } + if (x0 >= x1) { + return; + } + + s1 = x & 7; + s2 = 8 - s1; + m1 = 0xff >> (x1 & 7); + m2 = 0xff << (((x1 & 7) == 0) ? 0 : 8 - (x1 & 7)); + m3 = (0xff >> s1) & m2; + + oneByte = x0 == ((x1 - 1) & ~7); + + for (yy = y0; yy < y1; ++yy) { + + // one byte per line -- need to mask both left and right side + if (oneByte) { + if (x >= 0) { + destPtr = data + (y + yy) * line + (x >> 3); + srcPtr = bitmap->data + yy * bitmap->line; + dest = *destPtr; + src1 = *srcPtr; + switch (combOp) { + case 0: // or + dest |= (src1 >> s1) & m2; + break; + case 1: // and + dest &= ((0xff00 | src1) >> s1) | m1; + break; + case 2: // xor + dest ^= (src1 >> s1) & m2; + break; + case 3: // xnor + dest ^= ((src1 ^ 0xff) >> s1) & m2; + break; + case 4: // replace + dest = (dest & ~m3) | ((src1 >> s1) & m3); + break; + } + *destPtr = dest; + } else { + destPtr = data + (y + yy) * line; + srcPtr = bitmap->data + yy * bitmap->line + (-x >> 3); + dest = *destPtr; + src1 = *srcPtr; + switch (combOp) { + case 0: // or + dest |= src1 & m2; + break; + case 1: // and + dest &= src1 | m1; + break; + case 2: // xor + dest ^= src1 & m2; + break; + case 3: // xnor + dest ^= (src1 ^ 0xff) & m2; + break; + case 4: // replace + dest = (src1 & m2) | (dest & m1); + break; + } + *destPtr = dest; + } + + // multiple bytes per line -- need to mask left side of left-most + // byte and right side of right-most byte + } else { + + // left-most byte + if (x >= 0) { + destPtr = data + (y + yy) * line + (x >> 3); + srcPtr = bitmap->data + yy * bitmap->line; + src1 = *srcPtr++; + dest = *destPtr; + switch (combOp) { + case 0: // or + dest |= src1 >> s1; + break; + case 1: // and + dest &= (0xff00 | src1) >> s1; + break; + case 2: // xor + dest ^= src1 >> s1; + break; + case 3: // xnor + dest ^= (src1 ^ 0xff) >> s1; + break; + case 4: // replace + dest = (dest & (0xff << s2)) | (src1 >> s1); + break; + } + *destPtr++ = dest; + xx = x0 + 8; + } else { + destPtr = data + (y + yy) * line; + srcPtr = bitmap->data + yy * bitmap->line + (-x >> 3); + src1 = *srcPtr++; + xx = x0; + } + + // middle bytes + for (; xx < x1 - 8; xx += 8) { + dest = *destPtr; + src0 = src1; + src1 = *srcPtr++; + src = (((src0 << 8) | src1) >> s1) & 0xff; + switch (combOp) { + case 0: // or + dest |= src; + break; + case 1: // and + dest &= src; + break; + case 2: // xor + dest ^= src; + break; + case 3: // xnor + dest ^= src ^ 0xff; + break; + case 4: // replace + dest = src; + break; + } + *destPtr++ = dest; + } + + // right-most byte + // note: this last byte (src1) may not actually be used, depending + // on the values of s1, m1, and m2 - and in fact, it may be off + // the edge of the source bitmap, which means we need to allocate + // one extra guard byte at the end of each bitmap + dest = *destPtr; + src0 = src1; + src1 = *srcPtr++; + src = (((src0 << 8) | src1) >> s1) & 0xff; + switch (combOp) { + case 0: // or + dest |= src & m2; + break; + case 1: // and + dest &= src | m1; + break; + case 2: // xor + dest ^= src & m2; + break; + case 3: // xnor + dest ^= (src ^ 0xff) & m2; + break; + case 4: // replace + dest = (src & m2) | (dest & m1); + break; + } + *destPtr = dest; + } + } +} + +//------------------------------------------------------------------------ +// JBIG2SymbolDict +//------------------------------------------------------------------------ + +class JBIG2SymbolDict: public JBIG2Segment { +public: + + JBIG2SymbolDict(Guint segNumA, Guint sizeA); + virtual ~JBIG2SymbolDict(); + virtual JBIG2SegmentType getType() { return jbig2SegSymbolDict; } + Guint getSize() { return size; } + void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { bitmaps[idx] = bitmap; } + JBIG2Bitmap *getBitmap(Guint idx) { return bitmaps[idx]; } + void setGenericRegionStats(JArithmeticDecoderStats *stats) + { genericRegionStats = stats; } + void setRefinementRegionStats(JArithmeticDecoderStats *stats) + { refinementRegionStats = stats; } + JArithmeticDecoderStats *getGenericRegionStats() + { return genericRegionStats; } + JArithmeticDecoderStats *getRefinementRegionStats() + { return refinementRegionStats; } + +private: + + Guint size; + JBIG2Bitmap **bitmaps; + JArithmeticDecoderStats *genericRegionStats; + JArithmeticDecoderStats *refinementRegionStats; +}; + +JBIG2SymbolDict::JBIG2SymbolDict(Guint segNumA, Guint sizeA): + JBIG2Segment(segNumA) +{ + Guint i; + + size = sizeA; + bitmaps = (JBIG2Bitmap **)gmallocn(size, sizeof(JBIG2Bitmap *)); + for (i = 0; i < size; ++i) { + bitmaps[i] = NULL; + } + genericRegionStats = NULL; + refinementRegionStats = NULL; +} + +JBIG2SymbolDict::~JBIG2SymbolDict() { + Guint i; + + for (i = 0; i < size; ++i) { + if (bitmaps[i]) { + delete bitmaps[i]; + } + } + gfree(bitmaps); + if (genericRegionStats) { + delete genericRegionStats; + } + if (refinementRegionStats) { + delete refinementRegionStats; + } +} + +//------------------------------------------------------------------------ +// JBIG2PatternDict +//------------------------------------------------------------------------ + +class JBIG2PatternDict: public JBIG2Segment { +public: + + JBIG2PatternDict(Guint segNumA, Guint sizeA); + virtual ~JBIG2PatternDict(); + virtual JBIG2SegmentType getType() { return jbig2SegPatternDict; } + Guint getSize() { return size; } + void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { bitmaps[idx] = bitmap; } + JBIG2Bitmap *getBitmap(Guint idx) { return bitmaps[idx]; } + +private: + + Guint size; + JBIG2Bitmap **bitmaps; +}; + +JBIG2PatternDict::JBIG2PatternDict(Guint segNumA, Guint sizeA): + JBIG2Segment(segNumA) +{ + size = sizeA; + bitmaps = (JBIG2Bitmap **)gmallocn(size, sizeof(JBIG2Bitmap *)); +} + +JBIG2PatternDict::~JBIG2PatternDict() { + Guint i; + + for (i = 0; i < size; ++i) { + delete bitmaps[i]; + } + gfree(bitmaps); +} + +//------------------------------------------------------------------------ +// JBIG2CodeTable +//------------------------------------------------------------------------ + +class JBIG2CodeTable: public JBIG2Segment { +public: + + JBIG2CodeTable(Guint segNumA, JBIG2HuffmanTable *tableA); + virtual ~JBIG2CodeTable(); + virtual JBIG2SegmentType getType() { return jbig2SegCodeTable; } + JBIG2HuffmanTable *getHuffTable() { return table; } + +private: + + JBIG2HuffmanTable *table; +}; + +JBIG2CodeTable::JBIG2CodeTable(Guint segNumA, JBIG2HuffmanTable *tableA): + JBIG2Segment(segNumA) +{ + table = tableA; +} + +JBIG2CodeTable::~JBIG2CodeTable() { + gfree(table); +} + +//------------------------------------------------------------------------ +// JBIG2Stream +//------------------------------------------------------------------------ + +JBIG2Stream::JBIG2Stream(Stream *strA, Object *globalsStreamA): + FilterStream(strA) +{ + pageBitmap = NULL; + + arithDecoder = new JArithmeticDecoder(); + genericRegionStats = new JArithmeticDecoderStats(1 << 1); + refinementRegionStats = new JArithmeticDecoderStats(1 << 1); + iadhStats = new JArithmeticDecoderStats(1 << 9); + iadwStats = new JArithmeticDecoderStats(1 << 9); + iaexStats = new JArithmeticDecoderStats(1 << 9); + iaaiStats = new JArithmeticDecoderStats(1 << 9); + iadtStats = new JArithmeticDecoderStats(1 << 9); + iaitStats = new JArithmeticDecoderStats(1 << 9); + iafsStats = new JArithmeticDecoderStats(1 << 9); + iadsStats = new JArithmeticDecoderStats(1 << 9); + iardxStats = new JArithmeticDecoderStats(1 << 9); + iardyStats = new JArithmeticDecoderStats(1 << 9); + iardwStats = new JArithmeticDecoderStats(1 << 9); + iardhStats = new JArithmeticDecoderStats(1 << 9); + iariStats = new JArithmeticDecoderStats(1 << 9); + iaidStats = new JArithmeticDecoderStats(1 << 1); + huffDecoder = new JBIG2HuffmanDecoder(); + mmrDecoder = new JBIG2MMRDecoder(); + + globalsStreamA->copy(&globalsStream); + segments = globalSegments = NULL; + curStr = NULL; + dataPtr = dataEnd = NULL; +} + +JBIG2Stream::~JBIG2Stream() { + close(); + globalsStream.free(); + delete arithDecoder; + delete genericRegionStats; + delete refinementRegionStats; + delete iadhStats; + delete iadwStats; + delete iaexStats; + delete iaaiStats; + delete iadtStats; + delete iaitStats; + delete iafsStats; + delete iadsStats; + delete iardxStats; + delete iardyStats; + delete iardwStats; + delete iardhStats; + delete iariStats; + delete iaidStats; + delete huffDecoder; + delete mmrDecoder; + delete str; +} + +void JBIG2Stream::reset() { + // read the globals stream + globalSegments = new GList(); + if (globalsStream.isStream()) { + segments = globalSegments; + curStr = globalsStream.getStream(); + curStr->reset(); + arithDecoder->setStream(curStr); + huffDecoder->setStream(curStr); + mmrDecoder->setStream(curStr); + readSegments(); + curStr->close(); + } + + // read the main stream + segments = new GList(); + curStr = str; + curStr->reset(); + arithDecoder->setStream(curStr); + huffDecoder->setStream(curStr); + mmrDecoder->setStream(curStr); + readSegments(); + + if (pageBitmap) { + dataPtr = pageBitmap->getDataPtr(); + dataEnd = dataPtr + pageBitmap->getDataSize(); + } else { + dataPtr = dataEnd = NULL; + } +} + +void JBIG2Stream::close() { + if (pageBitmap) { + delete pageBitmap; + pageBitmap = NULL; + } + if (segments) { + deleteGList(segments, JBIG2Segment); + segments = NULL; + } + if (globalSegments) { + deleteGList(globalSegments, JBIG2Segment); + globalSegments = NULL; + } + dataPtr = dataEnd = NULL; + FilterStream::close(); +} + +int JBIG2Stream::getChar() { + if (dataPtr && dataPtr < dataEnd) { + return (*dataPtr++ ^ 0xff) & 0xff; + } + return EOF; +} + +int JBIG2Stream::lookChar() { + if (dataPtr && dataPtr < dataEnd) { + return (*dataPtr ^ 0xff) & 0xff; + } + return EOF; +} + +GString *JBIG2Stream::getPSFilter(int /*psLevel*/, char * /*indent*/) { + return NULL; +} + +GBool JBIG2Stream::isBinary(GBool /*last*/) { + return str->isBinary(gTrue); +} + +void JBIG2Stream::readSegments() { + Guint segNum, segFlags, segType, page, segLength; + Guint refFlags, nRefSegs; + Guint *refSegs; + int segDataPos; + int c1, c2, c3; + Guint i; + + while (readULong(&segNum)) { + + // segment header flags + if (!readUByte(&segFlags)) { + goto eofError1; + } + segType = segFlags & 0x3f; + + // referred-to segment count and retention flags + if (!readUByte(&refFlags)) { + goto eofError1; + } + nRefSegs = refFlags >> 5; + if (nRefSegs == 7) { + if ((c1 = curStr->getChar()) == EOF || + (c2 = curStr->getChar()) == EOF || + (c3 = curStr->getChar()) == EOF) { + goto eofError1; + } + refFlags = (refFlags << 24) | (c1 << 16) | (c2 << 8) | c3; + nRefSegs = refFlags & 0x1fffffff; + for (i = 0; i < (nRefSegs + 9) >> 3; ++i) { + c1 = curStr->getChar(); + } + } + + // referred-to segment numbers + refSegs = (Guint *)gmallocn(nRefSegs, sizeof(Guint)); + if (segNum <= 256) { + for (i = 0; i < nRefSegs; ++i) { + if (!readUByte(&refSegs[i])) { + goto eofError2; + } + } + } else if (segNum <= 65536) { + for (i = 0; i < nRefSegs; ++i) { + if (!readUWord(&refSegs[i])) { + goto eofError2; + } + } + } else { + for (i = 0; i < nRefSegs; ++i) { + if (!readULong(&refSegs[i])) { + goto eofError2; + } + } + } + + // segment page association + if (segFlags & 0x40) { + if (!readULong(&page)) { + goto eofError2; + } + } else { + if (!readUByte(&page)) { + goto eofError2; + } + } + + // segment data length + if (!readULong(&segLength)) { + goto eofError2; + } + + // keep track of the start of the segment data + segDataPos = getPos(); + + // check for missing page information segment + if (!pageBitmap && ((segType >= 4 && segType <= 7) || + (segType >= 20 && segType <= 43))) { + error(getPos(), "First JBIG2 segment associated with a page must be a page information segment"); + goto syntaxError; + } + + // read the segment data + switch (segType) { + case 0: + if (!readSymbolDictSeg(segNum, segLength, refSegs, nRefSegs)) { + goto syntaxError; + } + break; + case 4: + readTextRegionSeg(segNum, gFalse, gFalse, segLength, refSegs, nRefSegs); + break; + case 6: + readTextRegionSeg(segNum, gTrue, gFalse, segLength, refSegs, nRefSegs); + break; + case 7: + readTextRegionSeg(segNum, gTrue, gTrue, segLength, refSegs, nRefSegs); + break; + case 16: + readPatternDictSeg(segNum, segLength); + break; + case 20: + readHalftoneRegionSeg(segNum, gFalse, gFalse, segLength, + refSegs, nRefSegs); + break; + case 22: + readHalftoneRegionSeg(segNum, gTrue, gFalse, segLength, + refSegs, nRefSegs); + break; + case 23: + readHalftoneRegionSeg(segNum, gTrue, gTrue, segLength, + refSegs, nRefSegs); + break; + case 36: + readGenericRegionSeg(segNum, gFalse, gFalse, segLength); + break; + case 38: + readGenericRegionSeg(segNum, gTrue, gFalse, segLength); + break; + case 39: + readGenericRegionSeg(segNum, gTrue, gTrue, segLength); + break; + case 40: + readGenericRefinementRegionSeg(segNum, gFalse, gFalse, segLength, + refSegs, nRefSegs); + break; + case 42: + readGenericRefinementRegionSeg(segNum, gTrue, gFalse, segLength, + refSegs, nRefSegs); + break; + case 43: + readGenericRefinementRegionSeg(segNum, gTrue, gTrue, segLength, + refSegs, nRefSegs); + break; + case 48: + readPageInfoSeg(segLength); + break; + case 50: + readEndOfStripeSeg(segLength); + break; + case 52: + readProfilesSeg(segLength); + break; + case 53: + readCodeTableSeg(segNum, segLength); + break; + case 62: + readExtensionSeg(segLength); + break; + default: + error(getPos(), "Unknown segment type in JBIG2 stream"); + for (i = 0; i < segLength; ++i) { + if ((c1 = curStr->getChar()) == EOF) { + goto eofError2; + } + } + break; + } + + // Make sure the segment handler read all of the bytes in the + // segment data, unless this segment is marked as having an + // unknown length (section 7.2.7 of the JBIG2 Final Committee Draft) + + if (segLength != 0xffffffff) { + + int segExtraBytes = segDataPos + segLength - getPos(); + if (segExtraBytes > 0) { + + // If we didn't read all of the bytes in the segment data, + // indicate an error, and throw away the rest of the data. + + // v.3.1.01.13 of the LuraTech PDF Compressor Server will + // sometimes generate an extraneous NULL byte at the end of + // arithmetic-coded symbol dictionary segments when numNewSyms + // == 0. Segments like this often occur for blank pages. + + error(getPos(), "%d extraneous byte%s after segment", + segExtraBytes, (segExtraBytes > 1) ? "s" : ""); + + // Burn through the remaining bytes -- inefficient, but + // hopefully we're not doing this much + + int trash; + for (int i = segExtraBytes; i > 0; i--) { + readByte(&trash); + } + + } else if (segExtraBytes < 0) { + + // If we read more bytes than we should have, according to the + // segment length field, note an error. + + error(getPos(), "Previous segment handler read too many bytes"); + + } + + } + + gfree(refSegs); + } + + return; + + syntaxError: + gfree(refSegs); + return; + + eofError2: + gfree(refSegs); + eofError1: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint /*length*/, + Guint *refSegs, Guint nRefSegs) { + JBIG2SymbolDict *symbolDict; + JBIG2HuffmanTable *huffDHTable, *huffDWTable; + JBIG2HuffmanTable *huffBMSizeTable, *huffAggInstTable; + JBIG2Segment *seg; + GList *codeTables; + JBIG2SymbolDict *inputSymbolDict; + Guint flags, sdTemplate, sdrTemplate, huff, refAgg; + Guint huffDH, huffDW, huffBMSize, huffAggInst; + Guint contextUsed, contextRetained; + int sdATX[4], sdATY[4], sdrATX[2], sdrATY[2]; + Guint numExSyms, numNewSyms, numInputSyms, symCodeLen; + JBIG2Bitmap **bitmaps; + JBIG2Bitmap *collBitmap, *refBitmap; + Guint *symWidths; + Guint symHeight, symWidth, totalWidth, x, symID; + int dh, dw, refAggNum, refDX, refDY, bmSize; + GBool ex; + int run, cnt; + Guint i, j, k; + Guchar *p; + + symWidths = NULL; + + // symbol dictionary flags + if (!readUWord(&flags)) { + goto eofError; + } + sdTemplate = (flags >> 10) & 3; + sdrTemplate = (flags >> 12) & 1; + huff = flags & 1; + refAgg = (flags >> 1) & 1; + huffDH = (flags >> 2) & 3; + huffDW = (flags >> 4) & 3; + huffBMSize = (flags >> 6) & 1; + huffAggInst = (flags >> 7) & 1; + contextUsed = (flags >> 8) & 1; + contextRetained = (flags >> 9) & 1; + + // symbol dictionary AT flags + if (!huff) { + if (sdTemplate == 0) { + if (!readByte(&sdATX[0]) || + !readByte(&sdATY[0]) || + !readByte(&sdATX[1]) || + !readByte(&sdATY[1]) || + !readByte(&sdATX[2]) || + !readByte(&sdATY[2]) || + !readByte(&sdATX[3]) || + !readByte(&sdATY[3])) { + goto eofError; + } + } else { + if (!readByte(&sdATX[0]) || + !readByte(&sdATY[0])) { + goto eofError; + } + } + } + + // symbol dictionary refinement AT flags + if (refAgg && !sdrTemplate) { + if (!readByte(&sdrATX[0]) || + !readByte(&sdrATY[0]) || + !readByte(&sdrATX[1]) || + !readByte(&sdrATY[1])) { + goto eofError; + } + } + + // SDNUMEXSYMS and SDNUMNEWSYMS + if (!readULong(&numExSyms) || !readULong(&numNewSyms)) { + goto eofError; + } + + // get referenced segments: input symbol dictionaries and code tables + codeTables = new GList(); + numInputSyms = 0; + for (i = 0; i < nRefSegs; ++i) { + if ((seg = findSegment(refSegs[i]))) { + if (seg->getType() == jbig2SegSymbolDict) { + j = ((JBIG2SymbolDict *)seg)->getSize(); + if (numInputSyms > UINT_MAX - j) { + error(getPos(), "Too many input symbols in JBIG2 symbol dictionary"); + delete codeTables; + goto eofError; + } + numInputSyms += j; + } else if (seg->getType() == jbig2SegCodeTable) { + codeTables->append(seg); + } + } + } + if (numInputSyms > UINT_MAX - numNewSyms) { + error(getPos(), "Too many input symbols in JBIG2 symbol dictionary"); + delete codeTables; + goto eofError; + } + + // compute symbol code length + symCodeLen = 1; + i = (numInputSyms + numNewSyms) >> 1; + while (i) { + ++symCodeLen; + i >>= 1; + } + + // get the input symbol bitmaps + bitmaps = (JBIG2Bitmap **)gmallocn(numInputSyms + numNewSyms, + sizeof(JBIG2Bitmap *)); + for (i = 0; i < numInputSyms + numNewSyms; ++i) { + bitmaps[i] = NULL; + } + k = 0; + inputSymbolDict = NULL; + for (i = 0; i < nRefSegs; ++i) { + if ((seg = findSegment(refSegs[i]))) { + if (seg->getType() == jbig2SegSymbolDict) { + inputSymbolDict = (JBIG2SymbolDict *)seg; + for (j = 0; j < inputSymbolDict->getSize(); ++j) { + bitmaps[k++] = inputSymbolDict->getBitmap(j); + } + } + } + } + + // get the Huffman tables + huffDHTable = huffDWTable = NULL; // make gcc happy + huffBMSizeTable = huffAggInstTable = NULL; // make gcc happy + i = 0; + if (huff) { + if (huffDH == 0) { + huffDHTable = huffTableD; + } else if (huffDH == 1) { + huffDHTable = huffTableE; + } else { + if (i >= (Guint)codeTables->getLength()) { + goto codeTableError; + } + huffDHTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffDW == 0) { + huffDWTable = huffTableB; + } else if (huffDW == 1) { + huffDWTable = huffTableC; + } else { + if (i >= (Guint)codeTables->getLength()) { + goto codeTableError; + } + huffDWTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffBMSize == 0) { + huffBMSizeTable = huffTableA; + } else { + if (i >= (Guint)codeTables->getLength()) { + goto codeTableError; + } + huffBMSizeTable = + ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffAggInst == 0) { + huffAggInstTable = huffTableA; + } else { + if (i >= (Guint)codeTables->getLength()) { + goto codeTableError; + } + huffAggInstTable = + ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + } + delete codeTables; + + // set up the Huffman decoder + if (huff) { + huffDecoder->reset(); + + // set up the arithmetic decoder + } else { + if (contextUsed && inputSymbolDict) { + resetGenericStats(sdTemplate, inputSymbolDict->getGenericRegionStats()); + } else { + resetGenericStats(sdTemplate, NULL); + } + resetIntStats(symCodeLen); + arithDecoder->start(); + } + + // set up the arithmetic decoder for refinement/aggregation + if (refAgg) { + if (contextUsed && inputSymbolDict) { + resetRefinementStats(sdrTemplate, + inputSymbolDict->getRefinementRegionStats()); + } else { + resetRefinementStats(sdrTemplate, NULL); + } + } + + // allocate symbol widths storage + if (huff && !refAgg) { + symWidths = (Guint *)gmallocn(numNewSyms, sizeof(Guint)); + } + + symHeight = 0; + i = 0; + while (i < numNewSyms) { + + // read the height class delta height + if (huff) { + huffDecoder->decodeInt(&dh, huffDHTable); + } else { + arithDecoder->decodeInt(&dh, iadhStats); + } + if (dh < 0 && (Guint)-dh >= symHeight) { + error(getPos(), "Bad delta-height value in JBIG2 symbol dictionary"); + goto syntaxError; + } + symHeight += dh; + symWidth = 0; + totalWidth = 0; + j = i; + + // read the symbols in this height class + while (1) { + + // read the delta width + if (huff) { + if (!huffDecoder->decodeInt(&dw, huffDWTable)) { + break; + } + } else { + if (!arithDecoder->decodeInt(&dw, iadwStats)) { + break; + } + } + if (dw < 0 && (Guint)-dw >= symWidth) { + error(getPos(), "Bad delta-height value in JBIG2 symbol dictionary"); + goto syntaxError; + } + symWidth += dw; + if (i >= numNewSyms) { + error(getPos(), "Too many symbols in JBIG2 symbol dictionary"); + goto syntaxError; + } + + // using a collective bitmap, so don't read a bitmap here + if (huff && !refAgg) { + symWidths[i] = symWidth; + totalWidth += symWidth; + + // refinement/aggregate coding + } else if (refAgg) { + if (huff) { + if (!huffDecoder->decodeInt(&refAggNum, huffAggInstTable)) { + break; + } + } else { + if (!arithDecoder->decodeInt(&refAggNum, iaaiStats)) { + break; + } + } +#if 0 //~ This special case was added about a year before the final draft + //~ of the JBIG2 spec was released. I have encountered some old + //~ JBIG2 images that predate it. + if (0) { +#else + if (refAggNum == 1) { +#endif + if (huff) { + symID = huffDecoder->readBits(symCodeLen); + huffDecoder->decodeInt(&refDX, huffTableO); + huffDecoder->decodeInt(&refDY, huffTableO); + huffDecoder->decodeInt(&bmSize, huffTableA); + huffDecoder->reset(); + arithDecoder->start(); + } else { + symID = arithDecoder->decodeIAID(symCodeLen, iaidStats); + arithDecoder->decodeInt(&refDX, iardxStats); + arithDecoder->decodeInt(&refDY, iardyStats); + } + if (symID >= numInputSyms + i) { + error(getPos(), "Invalid symbol ID in JBIG2 symbol dictionary"); + goto syntaxError; + } + refBitmap = bitmaps[symID]; + bitmaps[numInputSyms + i] = + readGenericRefinementRegion(symWidth, symHeight, + sdrTemplate, gFalse, + refBitmap, refDX, refDY, + sdrATX, sdrATY); + //~ do we need to use the bmSize value here (in Huffman mode)? + } else { + bitmaps[numInputSyms + i] = + readTextRegion(huff, gTrue, symWidth, symHeight, + refAggNum, 0, numInputSyms + i, NULL, + symCodeLen, bitmaps, 0, 0, 0, 1, 0, + huffTableF, huffTableH, huffTableK, huffTableO, + huffTableO, huffTableO, huffTableO, huffTableA, + sdrTemplate, sdrATX, sdrATY); + } + + // non-ref/agg coding + } else { + bitmaps[numInputSyms + i] = + readGenericBitmap(gFalse, symWidth, symHeight, + sdTemplate, gFalse, gFalse, NULL, + sdATX, sdATY, 0); + } + + ++i; + } + + // read the collective bitmap + if (huff && !refAgg) { + huffDecoder->decodeInt(&bmSize, huffBMSizeTable); + huffDecoder->reset(); + if (bmSize == 0) { + collBitmap = new JBIG2Bitmap(0, totalWidth, symHeight); + bmSize = symHeight * ((totalWidth + 7) >> 3); + p = collBitmap->getDataPtr(); + for (k = 0; k < (Guint)bmSize; ++k) { + *p++ = curStr->getChar(); + } + } else { + collBitmap = readGenericBitmap(gTrue, totalWidth, symHeight, + 0, gFalse, gFalse, NULL, NULL, NULL, + bmSize); + } + x = 0; + for (; j < i; ++j) { + bitmaps[numInputSyms + j] = + collBitmap->getSlice(x, 0, symWidths[j], symHeight); + x += symWidths[j]; + } + delete collBitmap; + } + } + + // create the symbol dict object + symbolDict = new JBIG2SymbolDict(segNum, numExSyms); + + // exported symbol list + i = j = 0; + ex = gFalse; + while (i < numInputSyms + numNewSyms) { + if (huff) { + huffDecoder->decodeInt(&run, huffTableA); + } else { + arithDecoder->decodeInt(&run, iaexStats); + } + if (i + run > numInputSyms + numNewSyms || + (ex && j + run > numExSyms)) { + error(getPos(), "Too many exported symbols in JBIG2 symbol dictionary"); + delete symbolDict; + goto syntaxError; + } + if (ex) { + for (cnt = 0; cnt < run; ++cnt) { + symbolDict->setBitmap(j++, bitmaps[i++]->copy()); + } + } else { + i += run; + } + ex = !ex; + } + if (j != numExSyms) { + error(getPos(), "Too few symbols in JBIG2 symbol dictionary"); + delete symbolDict; + goto syntaxError; + } + + for (i = 0; i < numNewSyms; ++i) { + delete bitmaps[numInputSyms + i]; + } + gfree(bitmaps); + if (symWidths) { + gfree(symWidths); + } + + // save the arithmetic decoder stats + if (!huff && contextRetained) { + symbolDict->setGenericRegionStats(genericRegionStats->copy()); + if (refAgg) { + symbolDict->setRefinementRegionStats(refinementRegionStats->copy()); + } + } + + // store the new symbol dict + segments->append(symbolDict); + + return gTrue; + + codeTableError: + error(getPos(), "Missing code table in JBIG2 symbol dictionary"); + delete codeTables; + + syntaxError: + for (i = 0; i < numNewSyms; ++i) { + if (bitmaps[numInputSyms + i]) { + delete bitmaps[numInputSyms + i]; + } + } + gfree(bitmaps); + if (symWidths) { + gfree(symWidths); + } + return gFalse; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); + return gFalse; +} + +void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm, + GBool /*lossless*/, Guint /*length*/, + Guint *refSegs, Guint nRefSegs) { + JBIG2Bitmap *bitmap; + JBIG2HuffmanTable runLengthTab[36]; + JBIG2HuffmanTable *symCodeTab; + JBIG2HuffmanTable *huffFSTable, *huffDSTable, *huffDTTable; + JBIG2HuffmanTable *huffRDWTable, *huffRDHTable; + JBIG2HuffmanTable *huffRDXTable, *huffRDYTable, *huffRSizeTable; + JBIG2Segment *seg; + GList *codeTables; + JBIG2SymbolDict *symbolDict; + JBIG2Bitmap **syms; + Guint w, h, x, y, segInfoFlags, extCombOp; + Guint flags, huff, refine, logStrips, refCorner, transposed; + Guint combOp, defPixel, templ; + int sOffset; + Guint huffFlags, huffFS, huffDS, huffDT; + Guint huffRDW, huffRDH, huffRDX, huffRDY, huffRSize; + Guint numInstances, numSyms, symCodeLen; + int atx[2], aty[2]; + Guint i, k, kk; + int j; + + // region segment info field + if (!readULong(&w) || !readULong(&h) || + !readULong(&x) || !readULong(&y) || + !readUByte(&segInfoFlags)) { + goto eofError; + } + extCombOp = segInfoFlags & 7; + + // rest of the text region header + if (!readUWord(&flags)) { + goto eofError; + } + huff = flags & 1; + refine = (flags >> 1) & 1; + logStrips = (flags >> 2) & 3; + refCorner = (flags >> 4) & 3; + transposed = (flags >> 6) & 1; + combOp = (flags >> 7) & 3; + defPixel = (flags >> 9) & 1; + sOffset = (flags >> 10) & 0x1f; + if (sOffset & 0x10) { + sOffset |= -1 - 0x0f; + } + templ = (flags >> 15) & 1; + huffFS = huffDS = huffDT = 0; // make gcc happy + huffRDW = huffRDH = huffRDX = huffRDY = huffRSize = 0; // make gcc happy + if (huff) { + if (!readUWord(&huffFlags)) { + goto eofError; + } + huffFS = huffFlags & 3; + huffDS = (huffFlags >> 2) & 3; + huffDT = (huffFlags >> 4) & 3; + huffRDW = (huffFlags >> 6) & 3; + huffRDH = (huffFlags >> 8) & 3; + huffRDX = (huffFlags >> 10) & 3; + huffRDY = (huffFlags >> 12) & 3; + huffRSize = (huffFlags >> 14) & 1; + } + if (refine && templ == 0) { + if (!readByte(&atx[0]) || !readByte(&aty[0]) || + !readByte(&atx[1]) || !readByte(&aty[1])) { + goto eofError; + } + } + if (!readULong(&numInstances)) { + goto eofError; + } + + // get symbol dictionaries and tables + codeTables = new GList(); + numSyms = 0; + for (i = 0; i < nRefSegs; ++i) { + if ((seg = findSegment(refSegs[i]))) { + if (seg->getType() == jbig2SegSymbolDict) { + numSyms += ((JBIG2SymbolDict *)seg)->getSize(); + } else if (seg->getType() == jbig2SegCodeTable) { + codeTables->append(seg); + } + } else { + error(getPos(), "Invalid segment reference in JBIG2 text region"); + delete codeTables; + return; + } + } + symCodeLen = 0; + i = 1; + while (i < numSyms) { + ++symCodeLen; + i <<= 1; + } + + // get the symbol bitmaps + syms = (JBIG2Bitmap **)gmallocn(numSyms, sizeof(JBIG2Bitmap *)); + kk = 0; + for (i = 0; i < nRefSegs; ++i) { + if ((seg = findSegment(refSegs[i]))) { + if (seg->getType() == jbig2SegSymbolDict) { + symbolDict = (JBIG2SymbolDict *)seg; + for (k = 0; k < symbolDict->getSize(); ++k) { + syms[kk++] = symbolDict->getBitmap(k); + } + } + } + } + + // get the Huffman tables + huffFSTable = huffDSTable = huffDTTable = NULL; // make gcc happy + huffRDWTable = huffRDHTable = NULL; // make gcc happy + huffRDXTable = huffRDYTable = huffRSizeTable = NULL; // make gcc happy + i = 0; + if (huff) { + if (huffFS == 0) { + huffFSTable = huffTableF; + } else if (huffFS == 1) { + huffFSTable = huffTableG; + } else { + if (i >= (Guint)codeTables->getLength()) { + goto codeTableError; + } + huffFSTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffDS == 0) { + huffDSTable = huffTableH; + } else if (huffDS == 1) { + huffDSTable = huffTableI; + } else if (huffDS == 2) { + huffDSTable = huffTableJ; + } else { + if (i >= (Guint)codeTables->getLength()) { + goto codeTableError; + } + huffDSTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffDT == 0) { + huffDTTable = huffTableK; + } else if (huffDT == 1) { + huffDTTable = huffTableL; + } else if (huffDT == 2) { + huffDTTable = huffTableM; + } else { + if (i >= (Guint)codeTables->getLength()) { + goto codeTableError; + } + huffDTTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffRDW == 0) { + huffRDWTable = huffTableN; + } else if (huffRDW == 1) { + huffRDWTable = huffTableO; + } else { + if (i >= (Guint)codeTables->getLength()) { + goto codeTableError; + } + huffRDWTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffRDH == 0) { + huffRDHTable = huffTableN; + } else if (huffRDH == 1) { + huffRDHTable = huffTableO; + } else { + if (i >= (Guint)codeTables->getLength()) { + goto codeTableError; + } + huffRDHTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffRDX == 0) { + huffRDXTable = huffTableN; + } else if (huffRDX == 1) { + huffRDXTable = huffTableO; + } else { + if (i >= (Guint)codeTables->getLength()) { + goto codeTableError; + } + huffRDXTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffRDY == 0) { + huffRDYTable = huffTableN; + } else if (huffRDY == 1) { + huffRDYTable = huffTableO; + } else { + if (i >= (Guint)codeTables->getLength()) { + goto codeTableError; + } + huffRDYTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffRSize == 0) { + huffRSizeTable = huffTableA; + } else { + if (i >= (Guint)codeTables->getLength()) { + goto codeTableError; + } + huffRSizeTable = + ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + } + delete codeTables; + + // symbol ID Huffman decoding table + if (huff) { + huffDecoder->reset(); + for (i = 0; i < 32; ++i) { + runLengthTab[i].val = i; + runLengthTab[i].prefixLen = huffDecoder->readBits(4); + runLengthTab[i].rangeLen = 0; + } + runLengthTab[32].val = 0x103; + runLengthTab[32].prefixLen = huffDecoder->readBits(4); + runLengthTab[32].rangeLen = 2; + runLengthTab[33].val = 0x203; + runLengthTab[33].prefixLen = huffDecoder->readBits(4); + runLengthTab[33].rangeLen = 3; + runLengthTab[34].val = 0x20b; + runLengthTab[34].prefixLen = huffDecoder->readBits(4); + runLengthTab[34].rangeLen = 7; + runLengthTab[35].prefixLen = 0; + runLengthTab[35].rangeLen = jbig2HuffmanEOT; + huffDecoder->buildTable(runLengthTab, 35); + symCodeTab = (JBIG2HuffmanTable *)gmallocn(numSyms + 1, + sizeof(JBIG2HuffmanTable)); + for (i = 0; i < numSyms; ++i) { + symCodeTab[i].val = i; + symCodeTab[i].rangeLen = 0; + } + i = 0; + while (i < numSyms) { + huffDecoder->decodeInt(&j, runLengthTab); + if (j > 0x200) { + for (j -= 0x200; j && i < numSyms; --j) { + symCodeTab[i++].prefixLen = 0; + } + } else if (j > 0x100) { + for (j -= 0x100; j && i < numSyms; --j) { + symCodeTab[i].prefixLen = symCodeTab[i-1].prefixLen; + ++i; + } + } else { + symCodeTab[i++].prefixLen = j; + } + } + symCodeTab[numSyms].prefixLen = 0; + symCodeTab[numSyms].rangeLen = jbig2HuffmanEOT; + huffDecoder->buildTable(symCodeTab, numSyms); + huffDecoder->reset(); + + // set up the arithmetic decoder + } else { + symCodeTab = NULL; + resetIntStats(symCodeLen); + arithDecoder->start(); + } + if (refine) { + resetRefinementStats(templ, NULL); + } + + bitmap = readTextRegion(huff, refine, w, h, numInstances, + logStrips, numSyms, symCodeTab, symCodeLen, syms, + defPixel, combOp, transposed, refCorner, sOffset, + huffFSTable, huffDSTable, huffDTTable, + huffRDWTable, huffRDHTable, + huffRDXTable, huffRDYTable, huffRSizeTable, + templ, atx, aty); + + gfree(syms); + + // combine the region bitmap into the page bitmap + if (imm) { + if (pageH == 0xffffffff && y + h > curPageH) { + pageBitmap->expand(y + h, pageDefPixel); + } + pageBitmap->combine(bitmap, x, y, extCombOp); + delete bitmap; + + // store the region bitmap + } else { + bitmap->setSegNum(segNum); + segments->append(bitmap); + } + + // clean up the Huffman decoder + if (huff) { + gfree(symCodeTab); + } + + return; + + codeTableError: + error(getPos(), "Missing code table in JBIG2 text region"); + gfree(codeTables); + delete syms; + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); + return; +} + +JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, + int w, int h, + Guint numInstances, + Guint logStrips, + int numSyms, + JBIG2HuffmanTable *symCodeTab, + Guint symCodeLen, + JBIG2Bitmap **syms, + Guint defPixel, Guint combOp, + Guint transposed, Guint refCorner, + int sOffset, + JBIG2HuffmanTable *huffFSTable, + JBIG2HuffmanTable *huffDSTable, + JBIG2HuffmanTable *huffDTTable, + JBIG2HuffmanTable *huffRDWTable, + JBIG2HuffmanTable *huffRDHTable, + JBIG2HuffmanTable *huffRDXTable, + JBIG2HuffmanTable *huffRDYTable, + JBIG2HuffmanTable *huffRSizeTable, + Guint templ, + int *atx, int *aty) { + JBIG2Bitmap *bitmap; + JBIG2Bitmap *symbolBitmap; + Guint strips; + int t, dt, tt, s, ds, sFirst, j; + int rdw, rdh, rdx, rdy, ri, refDX, refDY, bmSize; + Guint symID, inst, bw, bh; + + strips = 1 << logStrips; + + // allocate the bitmap + bitmap = new JBIG2Bitmap(0, w, h); + if (defPixel) { + bitmap->clearToOne(); + } else { + bitmap->clearToZero(); + } + + // decode initial T value + if (huff) { + huffDecoder->decodeInt(&t, huffDTTable); + } else { + arithDecoder->decodeInt(&t, iadtStats); + } + t *= -(int)strips; + + inst = 0; + sFirst = 0; + while (inst < numInstances) { + + // decode delta-T + if (huff) { + huffDecoder->decodeInt(&dt, huffDTTable); + } else { + arithDecoder->decodeInt(&dt, iadtStats); + } + t += dt * strips; + + // first S value + if (huff) { + huffDecoder->decodeInt(&ds, huffFSTable); + } else { + arithDecoder->decodeInt(&ds, iafsStats); + } + sFirst += ds; + s = sFirst; + + // read the instances + while (1) { + + // T value + if (strips == 1) { + dt = 0; + } else if (huff) { + dt = huffDecoder->readBits(logStrips); + } else { + arithDecoder->decodeInt(&dt, iaitStats); + } + tt = t + dt; + + // symbol ID + if (huff) { + if (symCodeTab) { + huffDecoder->decodeInt(&j, symCodeTab); + symID = (Guint)j; + } else { + symID = huffDecoder->readBits(symCodeLen); + } + } else { + symID = arithDecoder->decodeIAID(symCodeLen, iaidStats); + } + + if (symID >= (Guint)numSyms) { + error(getPos(), "Invalid symbol number in JBIG2 text region"); + } else { + + // get the symbol bitmap + symbolBitmap = NULL; + if (refine) { + if (huff) { + ri = (int)huffDecoder->readBit(); + } else { + arithDecoder->decodeInt(&ri, iariStats); + } + } else { + ri = 0; + } + if (ri) { + if (huff) { + huffDecoder->decodeInt(&rdw, huffRDWTable); + huffDecoder->decodeInt(&rdh, huffRDHTable); + huffDecoder->decodeInt(&rdx, huffRDXTable); + huffDecoder->decodeInt(&rdy, huffRDYTable); + huffDecoder->decodeInt(&bmSize, huffRSizeTable); + huffDecoder->reset(); + arithDecoder->start(); + } else { + arithDecoder->decodeInt(&rdw, iardwStats); + arithDecoder->decodeInt(&rdh, iardhStats); + arithDecoder->decodeInt(&rdx, iardxStats); + arithDecoder->decodeInt(&rdy, iardyStats); + } + refDX = ((rdw >= 0) ? rdw : rdw - 1) / 2 + rdx; + refDY = ((rdh >= 0) ? rdh : rdh - 1) / 2 + rdy; + + symbolBitmap = + readGenericRefinementRegion(rdw + syms[symID]->getWidth(), + rdh + syms[symID]->getHeight(), + templ, gFalse, syms[symID], + refDX, refDY, atx, aty); + //~ do we need to use the bmSize value here (in Huffman mode)? + } else { + symbolBitmap = syms[symID]; + } + + // combine the symbol bitmap into the region bitmap + //~ something is wrong here - refCorner shouldn't degenerate into + //~ two cases + bw = symbolBitmap->getWidth() - 1; + bh = symbolBitmap->getHeight() - 1; + if (transposed) { + switch (refCorner) { + case 0: // bottom left + bitmap->combine(symbolBitmap, tt, s, combOp); + break; + case 1: // top left + bitmap->combine(symbolBitmap, tt, s, combOp); + break; + case 2: // bottom right + bitmap->combine(symbolBitmap, tt - bw, s, combOp); + break; + case 3: // top right + bitmap->combine(symbolBitmap, tt - bw, s, combOp); + break; + } + s += bh; + } else { + switch (refCorner) { + case 0: // bottom left + bitmap->combine(symbolBitmap, s, tt - bh, combOp); + break; + case 1: // top left + bitmap->combine(symbolBitmap, s, tt, combOp); + break; + case 2: // bottom right + bitmap->combine(symbolBitmap, s, tt - bh, combOp); + break; + case 3: // top right + bitmap->combine(symbolBitmap, s, tt, combOp); + break; + } + s += bw; + } + if (ri) { + delete symbolBitmap; + } + } + + // next instance + ++inst; + + // next S value + if (huff) { + if (!huffDecoder->decodeInt(&ds, huffDSTable)) { + break; + } + } else { + if (!arithDecoder->decodeInt(&ds, iadsStats)) { + break; + } + } + s += sOffset + ds; + } + } + + return bitmap; +} + +void JBIG2Stream::readPatternDictSeg(Guint segNum, Guint length) { + JBIG2PatternDict *patternDict; + JBIG2Bitmap *bitmap; + Guint flags, patternW, patternH, grayMax, templ, mmr; + int atx[4], aty[4]; + Guint i, x; + + // halftone dictionary flags, pattern width and height, max gray value + if (!readUByte(&flags) || + !readUByte(&patternW) || + !readUByte(&patternH) || + !readULong(&grayMax)) { + goto eofError; + } + templ = (flags >> 1) & 3; + mmr = flags & 1; + + // set up the arithmetic decoder + if (!mmr) { + resetGenericStats(templ, NULL); + arithDecoder->start(); + } + + // read the bitmap + atx[0] = -(int)patternW; aty[0] = 0; + atx[1] = -3; aty[1] = -1; + atx[2] = 2; aty[2] = -2; + atx[3] = -2; aty[3] = -2; + bitmap = readGenericBitmap(mmr, (grayMax + 1) * patternW, patternH, + templ, gFalse, gFalse, NULL, + atx, aty, length - 7); + + // create the pattern dict object + patternDict = new JBIG2PatternDict(segNum, grayMax + 1); + + // split up the bitmap + x = 0; + for (i = 0; i <= grayMax; ++i) { + patternDict->setBitmap(i, bitmap->getSlice(x, 0, patternW, patternH)); + x += patternW; + } + + // free memory + delete bitmap; + + // store the new pattern dict + segments->append(patternDict); + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +void JBIG2Stream::readHalftoneRegionSeg(Guint segNum, GBool imm, + GBool /*lossless*/, Guint /*length*/, + Guint *refSegs, Guint nRefSegs) { + JBIG2Bitmap *bitmap; + JBIG2Segment *seg; + JBIG2PatternDict *patternDict; + JBIG2Bitmap *skipBitmap; + Guint *grayImg; + JBIG2Bitmap *grayBitmap; + JBIG2Bitmap *patternBitmap; + Guint w, h, x, y, segInfoFlags, extCombOp; + Guint flags, mmr, templ, enableSkip, combOp; + Guint gridW, gridH, stepX, stepY, patW, patH; + int atx[4], aty[4]; + int gridX, gridY, xx, yy, bit, j; + Guint bpp, m, n, i; + + // region segment info field + if (!readULong(&w) || !readULong(&h) || + !readULong(&x) || !readULong(&y) || + !readUByte(&segInfoFlags)) { + goto eofError; + } + extCombOp = segInfoFlags & 7; + + // rest of the halftone region header + if (!readUByte(&flags)) { + goto eofError; + } + mmr = flags & 1; + templ = (flags >> 1) & 3; + enableSkip = (flags >> 3) & 1; + combOp = (flags >> 4) & 7; + if (!readULong(&gridW) || !readULong(&gridH) || + !readLong(&gridX) || !readLong(&gridY) || + !readUWord(&stepX) || !readUWord(&stepY)) { + goto eofError; + } + if (w == 0 || h == 0 || w >= INT_MAX / h) { + error(getPos(), "Bad bitmap size in JBIG2 halftone segment"); + return; + } + if (gridH == 0 || gridW >= INT_MAX / gridH) { + error(getPos(), "Bad grid size in JBIG2 halftone segment"); + return; + } + + // get pattern dictionary + if (nRefSegs != 1) { + error(getPos(), "Bad symbol dictionary reference in JBIG2 halftone segment"); + return; + } + if (!(seg = findSegment(refSegs[0])) || + seg->getType() != jbig2SegPatternDict) { + error(getPos(), "Bad symbol dictionary reference in JBIG2 halftone segment"); + return; + } + patternDict = (JBIG2PatternDict *)seg; + bpp = 0; + i = 1; + while (i < patternDict->getSize()) { + ++bpp; + i <<= 1; + } + patW = patternDict->getBitmap(0)->getWidth(); + patH = patternDict->getBitmap(0)->getHeight(); + + // set up the arithmetic decoder + if (!mmr) { + resetGenericStats(templ, NULL); + arithDecoder->start(); + } + + // allocate the bitmap + bitmap = new JBIG2Bitmap(segNum, w, h); + if (flags & 0x80) { // HDEFPIXEL + bitmap->clearToOne(); + } else { + bitmap->clearToZero(); + } + + // compute the skip bitmap + skipBitmap = NULL; + if (enableSkip) { + skipBitmap = new JBIG2Bitmap(0, gridW, gridH); + skipBitmap->clearToZero(); + for (m = 0; m < gridH; ++m) { + for (n = 0; n < gridW; ++n) { + xx = gridX + m * stepY + n * stepX; + yy = gridY + m * stepX - n * stepY; + if (((xx + (int)patW) >> 8) <= 0 || (xx >> 8) >= (int)w || + ((yy + (int)patH) >> 8) <= 0 || (yy >> 8) >= (int)h) { + skipBitmap->setPixel(n, m); + } + } + } + } + + // read the gray-scale image + grayImg = (Guint *)gmallocn(gridW * gridH, sizeof(Guint)); + memset(grayImg, 0, gridW * gridH * sizeof(Guint)); + atx[0] = templ <= 1 ? 3 : 2; aty[0] = -1; + atx[1] = -3; aty[1] = -1; + atx[2] = 2; aty[2] = -2; + atx[3] = -2; aty[3] = -2; + for (j = bpp - 1; j >= 0; --j) { + grayBitmap = readGenericBitmap(mmr, gridW, gridH, templ, gFalse, + enableSkip, skipBitmap, atx, aty, -1); + i = 0; + for (m = 0; m < gridH; ++m) { + for (n = 0; n < gridW; ++n) { + bit = grayBitmap->getPixel(n, m) ^ (grayImg[i] & 1); + grayImg[i] = (grayImg[i] << 1) | bit; + ++i; + } + } + delete grayBitmap; + } + + // decode the image + i = 0; + for (m = 0; m < gridH; ++m) { + xx = gridX + m * stepY; + yy = gridY + m * stepX; + for (n = 0; n < gridW; ++n) { + if (!(enableSkip && skipBitmap->getPixel(n, m))) { + patternBitmap = patternDict->getBitmap(grayImg[i]); + bitmap->combine(patternBitmap, xx >> 8, yy >> 8, combOp); + } + xx += stepX; + yy -= stepY; + ++i; + } + } + + gfree(grayImg); + if (skipBitmap) { + delete skipBitmap; + } + + // combine the region bitmap into the page bitmap + if (imm) { + if (pageH == 0xffffffff && y + h > curPageH) { + pageBitmap->expand(y + h, pageDefPixel); + } + pageBitmap->combine(bitmap, x, y, extCombOp); + delete bitmap; + + // store the region bitmap + } else { + segments->append(bitmap); + } + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +void JBIG2Stream::readGenericRegionSeg(Guint segNum, GBool imm, + GBool /*lossless*/, Guint length) { + JBIG2Bitmap *bitmap; + Guint w, h, x, y, segInfoFlags, extCombOp; + Guint flags, mmr, templ, tpgdOn; + int atx[4], aty[4]; + + // region segment info field + if (!readULong(&w) || !readULong(&h) || + !readULong(&x) || !readULong(&y) || + !readUByte(&segInfoFlags)) { + goto eofError; + } + extCombOp = segInfoFlags & 7; + + // rest of the generic region segment header + if (!readUByte(&flags)) { + goto eofError; + } + mmr = flags & 1; + templ = (flags >> 1) & 3; + tpgdOn = (flags >> 3) & 1; + + // AT flags + if (!mmr) { + if (templ == 0) { + if (!readByte(&atx[0]) || + !readByte(&aty[0]) || + !readByte(&atx[1]) || + !readByte(&aty[1]) || + !readByte(&atx[2]) || + !readByte(&aty[2]) || + !readByte(&atx[3]) || + !readByte(&aty[3])) { + goto eofError; + } + } else { + if (!readByte(&atx[0]) || + !readByte(&aty[0])) { + goto eofError; + } + } + } + + // set up the arithmetic decoder + if (!mmr) { + resetGenericStats(templ, NULL); + arithDecoder->start(); + } + + // read the bitmap + bitmap = readGenericBitmap(mmr, w, h, templ, tpgdOn, gFalse, + NULL, atx, aty, mmr ? length - 18 : 0); + + // combine the region bitmap into the page bitmap + if (imm) { + if (pageH == 0xffffffff && y + h > curPageH) { + pageBitmap->expand(y + h, pageDefPixel); + } + pageBitmap->combine(bitmap, x, y, extCombOp); + delete bitmap; + + // store the region bitmap + } else { + bitmap->setSegNum(segNum); + segments->append(bitmap); + } + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +inline void JBIG2Stream::mmrAddPixels(int a1, int blackPixels, + int *codingLine, int *a0i, int w) { + if (a1 > codingLine[*a0i]) { + if (a1 > w) { + error(getPos(), "JBIG2 MMR row is wrong length ({0:d})", a1); + a1 = w; + } + if ((*a0i & 1) ^ blackPixels) { + ++*a0i; + } + codingLine[*a0i] = a1; + } +} + +inline void JBIG2Stream::mmrAddPixelsNeg(int a1, int blackPixels, + int *codingLine, int *a0i, int w) { + if (a1 > codingLine[*a0i]) { + if (a1 > w) { + error(getPos(), "JBIG2 MMR row is wrong length ({0:d})", a1); + a1 = w; + } + if ((*a0i & 1) ^ blackPixels) { + ++*a0i; + } + codingLine[*a0i] = a1; + } else if (a1 < codingLine[*a0i]) { + if (a1 < 0) { + error(getPos(), "Invalid JBIG2 MMR code"); + a1 = 0; + } + while (*a0i > 0 && a1 <= codingLine[*a0i - 1]) { + --*a0i; + } + codingLine[*a0i] = a1; + } +} + +JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h, + int templ, GBool tpgdOn, + GBool useSkip, JBIG2Bitmap *skip, + int *atx, int *aty, + int mmrDataLength) { + JBIG2Bitmap *bitmap; + GBool ltp; + Guint ltpCX, cx, cx0, cx1, cx2; + JBIG2BitmapPtr cxPtr0, cxPtr1; + JBIG2BitmapPtr atPtr0, atPtr1, atPtr2, atPtr3; + int *refLine, *codingLine; + int code1, code2, code3; + int x, y, a0i, b1i, blackPixels, pix, i; + + bitmap = new JBIG2Bitmap(0, w, h); + bitmap->clearToZero(); + + //----- MMR decode + + if (mmr) { + + mmrDecoder->reset(); + if (w > INT_MAX - 2) { + error(getPos(), "Bad width in JBIG2 generic bitmap"); + // force a call to gmalloc(-1), which will throw an exception + w = -3; + } + // 0 <= codingLine[0] < codingLine[1] < ... < codingLine[n] = w + // ---> max codingLine size = w + 1 + // refLine has one extra guard entry at the end + // ---> max refLine size = w + 2 + codingLine = (int *)gmallocn(w + 1, sizeof(int)); + refLine = (int *)gmallocn(w + 2, sizeof(int)); + codingLine[0] = w; + + for (y = 0; y < h; ++y) { + + // copy coding line to ref line + for (i = 0; codingLine[i] < w; ++i) { + refLine[i] = codingLine[i]; + } + refLine[i++] = w; + refLine[i] = w; + + // decode a line + codingLine[0] = 0; + a0i = 0; + b1i = 0; + blackPixels = 0; + // invariant: + // refLine[b1i-1] <= codingLine[a0i] < refLine[b1i] < refLine[b1i+1] <= w + // exception at left edge: + // codingLine[a0i = 0] = refLine[b1i = 0] = 0 is possible + // exception at right edge: + // refLine[b1i] = refLine[b1i+1] = w is possible + while (codingLine[a0i] < w) { + code1 = mmrDecoder->get2DCode(); + switch (code1) { + case twoDimPass: + mmrAddPixels(refLine[b1i + 1], blackPixels, codingLine, &a0i, w); + if (refLine[b1i + 1] < w) { + b1i += 2; + } + break; + case twoDimHoriz: + code1 = code2 = 0; + if (blackPixels) { + do { + code1 += code3 = mmrDecoder->getBlackCode(); + } while (code3 >= 64); + do { + code2 += code3 = mmrDecoder->getWhiteCode(); + } while (code3 >= 64); + } else { + do { + code1 += code3 = mmrDecoder->getWhiteCode(); + } while (code3 >= 64); + do { + code2 += code3 = mmrDecoder->getBlackCode(); + } while (code3 >= 64); + } + mmrAddPixels(codingLine[a0i] + code1, blackPixels, + codingLine, &a0i, w); + if (codingLine[a0i] < w) { + mmrAddPixels(codingLine[a0i] + code2, blackPixels ^ 1, + codingLine, &a0i, w); + } + while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) { + b1i += 2; + } + break; + case twoDimVertR3: + mmrAddPixels(refLine[b1i] + 3, blackPixels, codingLine, &a0i, w); + blackPixels ^= 1; + if (codingLine[a0i] < w) { + ++b1i; + while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) { + b1i += 2; + } + } + break; + case twoDimVertR2: + mmrAddPixels(refLine[b1i] + 2, blackPixels, codingLine, &a0i, w); + blackPixels ^= 1; + if (codingLine[a0i] < w) { + ++b1i; + while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) { + b1i += 2; + } + } + break; + case twoDimVertR1: + mmrAddPixels(refLine[b1i] + 1, blackPixels, codingLine, &a0i, w); + blackPixels ^= 1; + if (codingLine[a0i] < w) { + ++b1i; + while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) { + b1i += 2; + } + } + break; + case twoDimVert0: + mmrAddPixels(refLine[b1i], blackPixels, codingLine, &a0i, w); + blackPixels ^= 1; + if (codingLine[a0i] < w) { + ++b1i; + while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) { + b1i += 2; + } + } + break; + case twoDimVertL3: + mmrAddPixelsNeg(refLine[b1i] - 3, blackPixels, codingLine, &a0i, w); + blackPixels ^= 1; + if (codingLine[a0i] < w) { + if (b1i > 0) { + --b1i; + } else { + ++b1i; + } + while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) { + b1i += 2; + } + } + break; + case twoDimVertL2: + mmrAddPixelsNeg(refLine[b1i] - 2, blackPixels, codingLine, &a0i, w); + blackPixels ^= 1; + if (codingLine[a0i] < w) { + if (b1i > 0) { + --b1i; + } else { + ++b1i; + } + while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) { + b1i += 2; + } + } + break; + case twoDimVertL1: + mmrAddPixelsNeg(refLine[b1i] - 1, blackPixels, codingLine, &a0i, w); + blackPixels ^= 1; + if (codingLine[a0i] < w) { + if (b1i > 0) { + --b1i; + } else { + ++b1i; + } + while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) { + b1i += 2; + } + } + break; + case EOF: + mmrAddPixels(w, 0, codingLine, &a0i, w); + break; + default: + error(getPos(), "Illegal code in JBIG2 MMR bitmap data"); + mmrAddPixels(w, 0, codingLine, &a0i, w); + break; + } + } + + // convert the run lengths to a bitmap line + i = 0; + while (1) { + for (x = codingLine[i]; x < codingLine[i+1]; ++x) { + bitmap->setPixel(x, y); + } + if (codingLine[i+1] >= w || codingLine[i+2] >= w) { + break; + } + i += 2; + } + } + + if (mmrDataLength >= 0) { + mmrDecoder->skipTo(mmrDataLength); + } else { + if (mmrDecoder->get24Bits() != 0x001001) { + error(getPos(), "Missing EOFB in JBIG2 MMR bitmap data"); + } + } + + gfree(refLine); + gfree(codingLine); + + //----- arithmetic decode + + } else { + // set up the typical row context + ltpCX = 0; // make gcc happy + if (tpgdOn) { + switch (templ) { + case 0: + ltpCX = 0x3953; // 001 11001 0101 0011 + break; + case 1: + ltpCX = 0x079a; // 0011 11001 101 0 + break; + case 2: + ltpCX = 0x0e3; // 001 1100 01 1 + break; + case 3: + ltpCX = 0x18a; // 01100 0101 1 + break; + } + } + + ltp = 0; + cx = cx0 = cx1 = cx2 = 0; // make gcc happy + for (y = 0; y < h; ++y) { + + // check for a "typical" (duplicate) row + if (tpgdOn) { + if (arithDecoder->decodeBit(ltpCX, genericRegionStats)) { + ltp = !ltp; + } + if (ltp) { + if (y > 0) { + bitmap->duplicateRow(y, y-1); + } + continue; + } + } + + switch (templ) { + case 0: + + // set up the context + bitmap->getPixelPtr(0, y-2, &cxPtr0); + cx0 = bitmap->nextPixel(&cxPtr0); + cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0); + bitmap->getPixelPtr(0, y-1, &cxPtr1); + cx1 = bitmap->nextPixel(&cxPtr1); + cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); + cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); + cx2 = 0; + bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0); + bitmap->getPixelPtr(atx[1], y + aty[1], &atPtr1); + bitmap->getPixelPtr(atx[2], y + aty[2], &atPtr2); + bitmap->getPixelPtr(atx[3], y + aty[3], &atPtr3); + + // decode the row + for (x = 0; x < w; ++x) { + + // build the context + cx = (cx0 << 13) | (cx1 << 8) | (cx2 << 4) | + (bitmap->nextPixel(&atPtr0) << 3) | + (bitmap->nextPixel(&atPtr1) << 2) | + (bitmap->nextPixel(&atPtr2) << 1) | + bitmap->nextPixel(&atPtr3); + + // check for a skipped pixel + if (useSkip && skip->getPixel(x, y)) { + pix = 0; + + // decode the pixel + } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { + bitmap->setPixel(x, y); + } + + // update the context + cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 0x07; + cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x1f; + cx2 = ((cx2 << 1) | pix) & 0x0f; + } + break; + + case 1: + + // set up the context + bitmap->getPixelPtr(0, y-2, &cxPtr0); + cx0 = bitmap->nextPixel(&cxPtr0); + cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0); + cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0); + bitmap->getPixelPtr(0, y-1, &cxPtr1); + cx1 = bitmap->nextPixel(&cxPtr1); + cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); + cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); + cx2 = 0; + bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0); + + // decode the row + for (x = 0; x < w; ++x) { + + // build the context + cx = (cx0 << 9) | (cx1 << 4) | (cx2 << 1) | + bitmap->nextPixel(&atPtr0); + + // check for a skipped pixel + if (useSkip && skip->getPixel(x, y)) { + pix = 0; + + // decode the pixel + } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { + bitmap->setPixel(x, y); + } + + // update the context + cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 0x0f; + cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x1f; + cx2 = ((cx2 << 1) | pix) & 0x07; + } + break; + + case 2: + + // set up the context + bitmap->getPixelPtr(0, y-2, &cxPtr0); + cx0 = bitmap->nextPixel(&cxPtr0); + cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0); + bitmap->getPixelPtr(0, y-1, &cxPtr1); + cx1 = bitmap->nextPixel(&cxPtr1); + cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); + cx2 = 0; + bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0); + + // decode the row + for (x = 0; x < w; ++x) { + + // build the context + cx = (cx0 << 7) | (cx1 << 3) | (cx2 << 1) | + bitmap->nextPixel(&atPtr0); + + // check for a skipped pixel + if (useSkip && skip->getPixel(x, y)) { + pix = 0; + + // decode the pixel + } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { + bitmap->setPixel(x, y); + } + + // update the context + cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 0x07; + cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x0f; + cx2 = ((cx2 << 1) | pix) & 0x03; + } + break; + + case 3: + + // set up the context + bitmap->getPixelPtr(0, y-1, &cxPtr1); + cx1 = bitmap->nextPixel(&cxPtr1); + cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); + cx2 = 0; + bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0); + + // decode the row + for (x = 0; x < w; ++x) { + + // build the context + cx = (cx1 << 5) | (cx2 << 1) | + bitmap->nextPixel(&atPtr0); + + // check for a skipped pixel + if (useSkip && skip->getPixel(x, y)) { + pix = 0; + + // decode the pixel + } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { + bitmap->setPixel(x, y); + } + + // update the context + cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x1f; + cx2 = ((cx2 << 1) | pix) & 0x0f; + } + break; + } + } + } + + return bitmap; +} + +void JBIG2Stream::readGenericRefinementRegionSeg(Guint segNum, GBool imm, + GBool /*lossless*/, Guint /*length*/, + Guint *refSegs, + Guint nRefSegs) { + JBIG2Bitmap *bitmap, *refBitmap; + Guint w, h, x, y, segInfoFlags, extCombOp; + Guint flags, templ, tpgrOn; + int atx[2], aty[2]; + JBIG2Segment *seg; + + // region segment info field + if (!readULong(&w) || !readULong(&h) || + !readULong(&x) || !readULong(&y) || + !readUByte(&segInfoFlags)) { + goto eofError; + } + extCombOp = segInfoFlags & 7; + + // rest of the generic refinement region segment header + if (!readUByte(&flags)) { + goto eofError; + } + templ = flags & 1; + tpgrOn = (flags >> 1) & 1; + + // AT flags + if (!templ) { + if (!readByte(&atx[0]) || !readByte(&aty[0]) || + !readByte(&atx[1]) || !readByte(&aty[1])) { + goto eofError; + } + } + + // resize the page bitmap if needed + if (nRefSegs == 0 || imm) { + if (pageH == 0xffffffff && y + h > curPageH) { + pageBitmap->expand(y + h, pageDefPixel); + } + } + + // get referenced bitmap + if (nRefSegs > 1) { + error(getPos(), "Bad reference in JBIG2 generic refinement segment"); + return; + } + if (nRefSegs == 1) { + if (!(seg = findSegment(refSegs[0])) || + seg->getType() != jbig2SegBitmap) { + error(getPos(), "Bad bitmap reference in JBIG2 generic refinement segment"); + return; + } + refBitmap = (JBIG2Bitmap *)seg; + } else { + refBitmap = pageBitmap->getSlice(x, y, w, h); + } + + // set up the arithmetic decoder + resetRefinementStats(templ, NULL); + arithDecoder->start(); + + // read + bitmap = readGenericRefinementRegion(w, h, templ, tpgrOn, + refBitmap, 0, 0, atx, aty); + + // combine the region bitmap into the page bitmap + if (imm) { + pageBitmap->combine(bitmap, x, y, extCombOp); + delete bitmap; + + // store the region bitmap + } else { + bitmap->setSegNum(segNum); + segments->append(bitmap); + } + + // delete the referenced bitmap + if (nRefSegs == 1) { + discardSegment(refSegs[0]); + } else { + delete refBitmap; + } + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +JBIG2Bitmap *JBIG2Stream::readGenericRefinementRegion(int w, int h, + int templ, GBool tpgrOn, + JBIG2Bitmap *refBitmap, + int refDX, int refDY, + int *atx, int *aty) { + JBIG2Bitmap *bitmap; + GBool ltp; + Guint ltpCX, cx, cx0, cx2, cx3, cx4, tpgrCX0, tpgrCX1, tpgrCX2; + JBIG2BitmapPtr cxPtr0, cxPtr1, cxPtr2, cxPtr3, cxPtr4, cxPtr5, cxPtr6; + JBIG2BitmapPtr tpgrCXPtr0, tpgrCXPtr1, tpgrCXPtr2; + int x, y, pix; + + bitmap = new JBIG2Bitmap(0, w, h); + bitmap->clearToZero(); + + // set up the typical row context + if (templ) { + ltpCX = 0x008; + } else { + ltpCX = 0x0010; + } + + ltp = 0; + for (y = 0; y < h; ++y) { + + if (templ) { + + // set up the context + bitmap->getPixelPtr(0, y-1, &cxPtr0); + cx0 = bitmap->nextPixel(&cxPtr0); + bitmap->getPixelPtr(-1, y, &cxPtr1); + refBitmap->getPixelPtr(-refDX, y-1-refDY, &cxPtr2); + refBitmap->getPixelPtr(-1-refDX, y-refDY, &cxPtr3); + cx3 = refBitmap->nextPixel(&cxPtr3); + cx3 = (cx3 << 1) | refBitmap->nextPixel(&cxPtr3); + refBitmap->getPixelPtr(-refDX, y+1-refDY, &cxPtr4); + cx4 = refBitmap->nextPixel(&cxPtr4); + + // set up the typical prediction context + tpgrCX0 = tpgrCX1 = tpgrCX2 = 0; // make gcc happy + if (tpgrOn) { + refBitmap->getPixelPtr(-1-refDX, y-1-refDY, &tpgrCXPtr0); + tpgrCX0 = refBitmap->nextPixel(&tpgrCXPtr0); + tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0); + tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0); + refBitmap->getPixelPtr(-1-refDX, y-refDY, &tpgrCXPtr1); + tpgrCX1 = refBitmap->nextPixel(&tpgrCXPtr1); + tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1); + tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1); + refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &tpgrCXPtr2); + tpgrCX2 = refBitmap->nextPixel(&tpgrCXPtr2); + tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2); + tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2); + } else { + tpgrCXPtr0.p = tpgrCXPtr1.p = tpgrCXPtr2.p = NULL; // make gcc happy + tpgrCXPtr0.shift = tpgrCXPtr1.shift = tpgrCXPtr2.shift = 0; + tpgrCXPtr0.x = tpgrCXPtr1.x = tpgrCXPtr2.x = 0; + } + + for (x = 0; x < w; ++x) { + + // update the context + cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 7; + cx3 = ((cx3 << 1) | refBitmap->nextPixel(&cxPtr3)) & 7; + cx4 = ((cx4 << 1) | refBitmap->nextPixel(&cxPtr4)) & 3; + + if (tpgrOn) { + // update the typical predictor context + tpgrCX0 = ((tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0)) & 7; + tpgrCX1 = ((tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1)) & 7; + tpgrCX2 = ((tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2)) & 7; + + // check for a "typical" pixel + if (arithDecoder->decodeBit(ltpCX, refinementRegionStats)) { + ltp = !ltp; + } + if (tpgrCX0 == 0 && tpgrCX1 == 0 && tpgrCX2 == 0) { + bitmap->clearPixel(x, y); + continue; + } else if (tpgrCX0 == 7 && tpgrCX1 == 7 && tpgrCX2 == 7) { + bitmap->setPixel(x, y); + continue; + } + } + + // build the context + cx = (cx0 << 7) | (bitmap->nextPixel(&cxPtr1) << 6) | + (refBitmap->nextPixel(&cxPtr2) << 5) | + (cx3 << 2) | cx4; + + // decode the pixel + if ((pix = arithDecoder->decodeBit(cx, refinementRegionStats))) { + bitmap->setPixel(x, y); + } + } + + } else { + + // set up the context + bitmap->getPixelPtr(0, y-1, &cxPtr0); + cx0 = bitmap->nextPixel(&cxPtr0); + bitmap->getPixelPtr(-1, y, &cxPtr1); + refBitmap->getPixelPtr(-refDX, y-1-refDY, &cxPtr2); + cx2 = refBitmap->nextPixel(&cxPtr2); + refBitmap->getPixelPtr(-1-refDX, y-refDY, &cxPtr3); + cx3 = refBitmap->nextPixel(&cxPtr3); + cx3 = (cx3 << 1) | refBitmap->nextPixel(&cxPtr3); + refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &cxPtr4); + cx4 = refBitmap->nextPixel(&cxPtr4); + cx4 = (cx4 << 1) | refBitmap->nextPixel(&cxPtr4); + bitmap->getPixelPtr(atx[0], y+aty[0], &cxPtr5); + refBitmap->getPixelPtr(atx[1]-refDX, y+aty[1]-refDY, &cxPtr6); + + // set up the typical prediction context + tpgrCX0 = tpgrCX1 = tpgrCX2 = 0; // make gcc happy + if (tpgrOn) { + refBitmap->getPixelPtr(-1-refDX, y-1-refDY, &tpgrCXPtr0); + tpgrCX0 = refBitmap->nextPixel(&tpgrCXPtr0); + tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0); + tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0); + refBitmap->getPixelPtr(-1-refDX, y-refDY, &tpgrCXPtr1); + tpgrCX1 = refBitmap->nextPixel(&tpgrCXPtr1); + tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1); + tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1); + refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &tpgrCXPtr2); + tpgrCX2 = refBitmap->nextPixel(&tpgrCXPtr2); + tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2); + tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2); + } else { + tpgrCXPtr0.p = tpgrCXPtr1.p = tpgrCXPtr2.p = NULL; // make gcc happy + tpgrCXPtr0.shift = tpgrCXPtr1.shift = tpgrCXPtr2.shift = 0; + tpgrCXPtr0.x = tpgrCXPtr1.x = tpgrCXPtr2.x = 0; + } + + for (x = 0; x < w; ++x) { + + // update the context + cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 3; + cx2 = ((cx2 << 1) | refBitmap->nextPixel(&cxPtr2)) & 3; + cx3 = ((cx3 << 1) | refBitmap->nextPixel(&cxPtr3)) & 7; + cx4 = ((cx4 << 1) | refBitmap->nextPixel(&cxPtr4)) & 7; + + if (tpgrOn) { + // update the typical predictor context + tpgrCX0 = ((tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0)) & 7; + tpgrCX1 = ((tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1)) & 7; + tpgrCX2 = ((tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2)) & 7; + + // check for a "typical" pixel + if (arithDecoder->decodeBit(ltpCX, refinementRegionStats)) { + ltp = !ltp; + } + if (tpgrCX0 == 0 && tpgrCX1 == 0 && tpgrCX2 == 0) { + bitmap->clearPixel(x, y); + continue; + } else if (tpgrCX0 == 7 && tpgrCX1 == 7 && tpgrCX2 == 7) { + bitmap->setPixel(x, y); + continue; + } + } + + // build the context + cx = (cx0 << 11) | (bitmap->nextPixel(&cxPtr1) << 10) | + (cx2 << 8) | (cx3 << 5) | (cx4 << 2) | + (bitmap->nextPixel(&cxPtr5) << 1) | + refBitmap->nextPixel(&cxPtr6); + + // decode the pixel + if ((pix = arithDecoder->decodeBit(cx, refinementRegionStats))) { + bitmap->setPixel(x, y); + } + } + } + } + + return bitmap; +} + +void JBIG2Stream::readPageInfoSeg(Guint /*length*/) { + Guint xRes, yRes, flags, striping; + + if (!readULong(&pageW) || !readULong(&pageH) || + !readULong(&xRes) || !readULong(&yRes) || + !readUByte(&flags) || !readUWord(&striping)) { + goto eofError; + } + pageDefPixel = (flags >> 2) & 1; + defCombOp = (flags >> 3) & 3; + + // allocate the page bitmap + if (pageH == 0xffffffff) { + curPageH = striping & 0x7fff; + } else { + curPageH = pageH; + } + pageBitmap = new JBIG2Bitmap(0, pageW, curPageH); + + // default pixel value + if (pageDefPixel) { + pageBitmap->clearToOne(); + } else { + pageBitmap->clearToZero(); + } + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +void JBIG2Stream::readEndOfStripeSeg(Guint length) { + Guint i; + + // skip the segment + for (i = 0; i < length; ++i) { + curStr->getChar(); + } +} + +void JBIG2Stream::readProfilesSeg(Guint length) { + Guint i; + + // skip the segment + for (i = 0; i < length; ++i) { + curStr->getChar(); + } +} + +void JBIG2Stream::readCodeTableSeg(Guint segNum, Guint /*length*/) { + JBIG2HuffmanTable *huffTab; + Guint flags, oob, prefixBits, rangeBits; + int lowVal, highVal, val; + Guint huffTabSize, i; + + if (!readUByte(&flags) || !readLong(&lowVal) || !readLong(&highVal)) { + goto eofError; + } + oob = flags & 1; + prefixBits = ((flags >> 1) & 7) + 1; + rangeBits = ((flags >> 4) & 7) + 1; + + huffDecoder->reset(); + huffTabSize = 8; + huffTab = (JBIG2HuffmanTable *) + gmallocn(huffTabSize, sizeof(JBIG2HuffmanTable)); + i = 0; + val = lowVal; + while (val < highVal) { + if (i == huffTabSize) { + huffTabSize *= 2; + huffTab = (JBIG2HuffmanTable *) + greallocn(huffTab, huffTabSize, sizeof(JBIG2HuffmanTable)); + } + huffTab[i].val = val; + huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); + huffTab[i].rangeLen = huffDecoder->readBits(rangeBits); + val += 1 << huffTab[i].rangeLen; + ++i; + } + if (i + oob + 3 > huffTabSize) { + huffTabSize = i + oob + 3; + huffTab = (JBIG2HuffmanTable *) + greallocn(huffTab, huffTabSize, sizeof(JBIG2HuffmanTable)); + } + huffTab[i].val = lowVal - 1; + huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); + huffTab[i].rangeLen = jbig2HuffmanLOW; + ++i; + huffTab[i].val = highVal; + huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); + huffTab[i].rangeLen = 32; + ++i; + if (oob) { + huffTab[i].val = 0; + huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); + huffTab[i].rangeLen = jbig2HuffmanOOB; + ++i; + } + huffTab[i].val = 0; + huffTab[i].prefixLen = 0; + huffTab[i].rangeLen = jbig2HuffmanEOT; + huffDecoder->buildTable(huffTab, i); + + // create and store the new table segment + segments->append(new JBIG2CodeTable(segNum, huffTab)); + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +void JBIG2Stream::readExtensionSeg(Guint length) { + Guint i; + + // skip the segment + for (i = 0; i < length; ++i) { + curStr->getChar(); + } +} + +JBIG2Segment *JBIG2Stream::findSegment(Guint segNum) { + JBIG2Segment *seg; + int i; + + for (i = 0; i < globalSegments->getLength(); ++i) { + seg = (JBIG2Segment *)globalSegments->get(i); + if (seg->getSegNum() == segNum) { + return seg; + } + } + for (i = 0; i < segments->getLength(); ++i) { + seg = (JBIG2Segment *)segments->get(i); + if (seg->getSegNum() == segNum) { + return seg; + } + } + return NULL; +} + +void JBIG2Stream::discardSegment(Guint segNum) { + JBIG2Segment *seg; + int i; + + for (i = 0; i < globalSegments->getLength(); ++i) { + seg = (JBIG2Segment *)globalSegments->get(i); + if (seg->getSegNum() == segNum) { + globalSegments->del(i); + return; + } + } + for (i = 0; i < segments->getLength(); ++i) { + seg = (JBIG2Segment *)segments->get(i); + if (seg->getSegNum() == segNum) { + segments->del(i); + return; + } + } +} + +void JBIG2Stream::resetGenericStats(Guint templ, + JArithmeticDecoderStats *prevStats) { + int size; + + size = contextSize[templ]; + if (prevStats && prevStats->getContextSize() == size) { + if (genericRegionStats->getContextSize() == size) { + genericRegionStats->copyFrom(prevStats); + } else { + delete genericRegionStats; + genericRegionStats = prevStats->copy(); + } + } else { + if (genericRegionStats->getContextSize() == size) { + genericRegionStats->reset(); + } else { + delete genericRegionStats; + genericRegionStats = new JArithmeticDecoderStats(1 << size); + } + } +} + +void JBIG2Stream::resetRefinementStats(Guint templ, + JArithmeticDecoderStats *prevStats) { + int size; + + size = refContextSize[templ]; + if (prevStats && prevStats->getContextSize() == size) { + if (refinementRegionStats->getContextSize() == size) { + refinementRegionStats->copyFrom(prevStats); + } else { + delete refinementRegionStats; + refinementRegionStats = prevStats->copy(); + } + } else { + if (refinementRegionStats->getContextSize() == size) { + refinementRegionStats->reset(); + } else { + delete refinementRegionStats; + refinementRegionStats = new JArithmeticDecoderStats(1 << size); + } + } +} + +void JBIG2Stream::resetIntStats(int symCodeLen) { + iadhStats->reset(); + iadwStats->reset(); + iaexStats->reset(); + iaaiStats->reset(); + iadtStats->reset(); + iaitStats->reset(); + iafsStats->reset(); + iadsStats->reset(); + iardxStats->reset(); + iardyStats->reset(); + iardwStats->reset(); + iardhStats->reset(); + iariStats->reset(); + if (iaidStats->getContextSize() == 1 << (symCodeLen + 1)) { + iaidStats->reset(); + } else { + delete iaidStats; + iaidStats = new JArithmeticDecoderStats(1 << (symCodeLen + 1)); + } +} + +GBool JBIG2Stream::readUByte(Guint *x) { + int c0; + + if ((c0 = curStr->getChar()) == EOF) { + return gFalse; + } + *x = (Guint)c0; + return gTrue; +} + +GBool JBIG2Stream::readByte(int *x) { + int c0; + + if ((c0 = curStr->getChar()) == EOF) { + return gFalse; + } + *x = c0; + if (c0 & 0x80) { + *x |= -1 - 0xff; + } + return gTrue; +} + +GBool JBIG2Stream::readUWord(Guint *x) { + int c0, c1; + + if ((c0 = curStr->getChar()) == EOF || + (c1 = curStr->getChar()) == EOF) { + return gFalse; + } + *x = (Guint)((c0 << 8) | c1); + return gTrue; +} + +GBool JBIG2Stream::readULong(Guint *x) { + int c0, c1, c2, c3; + + if ((c0 = curStr->getChar()) == EOF || + (c1 = curStr->getChar()) == EOF || + (c2 = curStr->getChar()) == EOF || + (c3 = curStr->getChar()) == EOF) { + return gFalse; + } + *x = (Guint)((c0 << 24) | (c1 << 16) | (c2 << 8) | c3); + return gTrue; +} + +GBool JBIG2Stream::readLong(int *x) { + int c0, c1, c2, c3; + + if ((c0 = curStr->getChar()) == EOF || + (c1 = curStr->getChar()) == EOF || + (c2 = curStr->getChar()) == EOF || + (c3 = curStr->getChar()) == EOF) { + return gFalse; + } + *x = ((c0 << 24) | (c1 << 16) | (c2 << 8) | c3); + if (c0 & 0x80) { + *x |= -1 - (int)0xffffffff; + } + return gTrue; +} diff --git a/kpdf/xpdf/xpdf/JBIG2Stream.h b/kpdf/xpdf/xpdf/JBIG2Stream.h new file mode 100644 index 00000000..f3443b3d --- /dev/null +++ b/kpdf/xpdf/xpdf/JBIG2Stream.h @@ -0,0 +1,149 @@ +//======================================================================== +// +// JBIG2Stream.h +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef JBIG2STREAM_H +#define JBIG2STREAM_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "Object.h" +#include "Stream.h" + +class GList; +class JBIG2Segment; +class JBIG2Bitmap; +class JArithmeticDecoder; +class JArithmeticDecoderStats; +class JBIG2HuffmanDecoder; +struct JBIG2HuffmanTable; +class JBIG2MMRDecoder; + +//------------------------------------------------------------------------ + +class JBIG2Stream: public FilterStream { +public: + + JBIG2Stream(Stream *strA, Object *globalsStreamA); + virtual ~JBIG2Stream(); + virtual StreamKind getKind() { return strJBIG2; } + virtual void reset(); + virtual void close(); + virtual int getChar(); + virtual int lookChar(); + virtual GString *getPSFilter(int psLevel, char *indent); + virtual GBool isBinary(GBool last = gTrue); + +private: + + void readSegments(); + GBool readSymbolDictSeg(Guint segNum, Guint length, + Guint *refSegs, Guint nRefSegs); + void readTextRegionSeg(Guint segNum, GBool imm, + GBool lossless, Guint length, + Guint *refSegs, Guint nRefSegs); + JBIG2Bitmap *readTextRegion(GBool huff, GBool refine, + int w, int h, + Guint numInstances, + Guint logStrips, + int numSyms, + JBIG2HuffmanTable *symCodeTab, + Guint symCodeLen, + JBIG2Bitmap **syms, + Guint defPixel, Guint combOp, + Guint transposed, Guint refCorner, + int sOffset, + JBIG2HuffmanTable *huffFSTable, + JBIG2HuffmanTable *huffDSTable, + JBIG2HuffmanTable *huffDTTable, + JBIG2HuffmanTable *huffRDWTable, + JBIG2HuffmanTable *huffRDHTable, + JBIG2HuffmanTable *huffRDXTable, + JBIG2HuffmanTable *huffRDYTable, + JBIG2HuffmanTable *huffRSizeTable, + Guint templ, + int *atx, int *aty); + void readPatternDictSeg(Guint segNum, Guint length); + void readHalftoneRegionSeg(Guint segNum, GBool imm, + GBool lossless, Guint length, + Guint *refSegs, Guint nRefSegs); + void readGenericRegionSeg(Guint segNum, GBool imm, + GBool lossless, Guint length); + void mmrAddPixels(int a1, int blackPixels, + int *codingLine, int *a0i, int w); + void mmrAddPixelsNeg(int a1, int blackPixels, + int *codingLine, int *a0i, int w); + JBIG2Bitmap *readGenericBitmap(GBool mmr, int w, int h, + int templ, GBool tpgdOn, + GBool useSkip, JBIG2Bitmap *skip, + int *atx, int *aty, + int mmrDataLength); + void readGenericRefinementRegionSeg(Guint segNum, GBool imm, + GBool lossless, Guint length, + Guint *refSegs, + Guint nRefSegs); + JBIG2Bitmap *readGenericRefinementRegion(int w, int h, + int templ, GBool tpgrOn, + JBIG2Bitmap *refBitmap, + int refDX, int refDY, + int *atx, int *aty); + void readPageInfoSeg(Guint length); + void readEndOfStripeSeg(Guint length); + void readProfilesSeg(Guint length); + void readCodeTableSeg(Guint segNum, Guint length); + void readExtensionSeg(Guint length); + JBIG2Segment *findSegment(Guint segNum); + void discardSegment(Guint segNum); + void resetGenericStats(Guint templ, + JArithmeticDecoderStats *prevStats); + void resetRefinementStats(Guint templ, + JArithmeticDecoderStats *prevStats); + void resetIntStats(int symCodeLen); + GBool readUByte(Guint *x); + GBool readByte(int *x); + GBool readUWord(Guint *x); + GBool readULong(Guint *x); + GBool readLong(int *x); + + Object globalsStream; + Guint pageW, pageH, curPageH; + Guint pageDefPixel; + JBIG2Bitmap *pageBitmap; + Guint defCombOp; + GList *segments; // [JBIG2Segment] + GList *globalSegments; // [JBIG2Segment] + Stream *curStr; + Guchar *dataPtr; + Guchar *dataEnd; + + JArithmeticDecoder *arithDecoder; + JArithmeticDecoderStats *genericRegionStats; + JArithmeticDecoderStats *refinementRegionStats; + JArithmeticDecoderStats *iadhStats; + JArithmeticDecoderStats *iadwStats; + JArithmeticDecoderStats *iaexStats; + JArithmeticDecoderStats *iaaiStats; + JArithmeticDecoderStats *iadtStats; + JArithmeticDecoderStats *iaitStats; + JArithmeticDecoderStats *iafsStats; + JArithmeticDecoderStats *iadsStats; + JArithmeticDecoderStats *iardxStats; + JArithmeticDecoderStats *iardyStats; + JArithmeticDecoderStats *iardwStats; + JArithmeticDecoderStats *iardhStats; + JArithmeticDecoderStats *iariStats; + JArithmeticDecoderStats *iaidStats; + JBIG2HuffmanDecoder *huffDecoder; + JBIG2MMRDecoder *mmrDecoder; +}; + +#endif diff --git a/kpdf/xpdf/xpdf/JPXStream.cc b/kpdf/xpdf/xpdf/JPXStream.cc new file mode 100644 index 00000000..54a9e103 --- /dev/null +++ b/kpdf/xpdf/xpdf/JPXStream.cc @@ -0,0 +1,3144 @@ +//======================================================================== +// +// JPXStream.cc +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "gmem.h" +#include "Error.h" +#include "JArithmeticDecoder.h" +#include "JPXStream.h" + +//~ to do: +// - precincts +// - ROI +// - progression order changes +// - packed packet headers +// - support for palettes, channel maps, etc. +// - make sure all needed JP2/JPX subboxes are parsed (readBoxes) +// - can we assume that QCC segments must come after the QCD segment? +// - skip EPH markers (readTilePartData) +// - handle tilePartToEOC in readTilePartData +// - deal with multiple codeword segments (readTilePartData, +// readCodeBlockData) +// - progression orders 2, 3, and 4 +// - in coefficient decoding (readCodeBlockData): +// - termination pattern: terminate after every coding pass +// - error resilience segmentation symbol +// - selective arithmetic coding bypass +// - vertically causal context formation +// - coeffs longer than 31 bits (should just ignore the extra bits?) +// - handle boxes larger than 2^32 bytes +// - the fixed-point arithmetic won't handle 16-bit pixels + +//------------------------------------------------------------------------ + +// number of contexts for the arithmetic decoder +#define jpxNContexts 19 + +#define jpxContextSigProp 0 // 0 - 8: significance prop and cleanup +#define jpxContextSign 9 // 9 - 13: sign +#define jpxContextMagRef 14 // 14 -16: magnitude refinement +#define jpxContextRunLength 17 // cleanup: run length +#define jpxContextUniform 18 // cleanup: first signif coeff + +//------------------------------------------------------------------------ + +#define jpxPassSigProp 0 +#define jpxPassMagRef 1 +#define jpxPassCleanup 2 + +//------------------------------------------------------------------------ + +// arithmetic decoder context for the significance propagation and +// cleanup passes: +// [horiz][vert][diag][subband] +// where subband = 0 for HL +// = 1 for LH and LL +// = 2 for HH +static Guint sigPropContext[3][3][5][3] = { + {{{ 0, 0, 0 }, // horiz=0, vert=0, diag=0 + { 1, 1, 3 }, // horiz=0, vert=0, diag=1 + { 2, 2, 6 }, // horiz=0, vert=0, diag=2 + { 2, 2, 8 }, // horiz=0, vert=0, diag=3 + { 2, 2, 8 }}, // horiz=0, vert=0, diag=4 + {{ 5, 3, 1 }, // horiz=0, vert=1, diag=0 + { 6, 3, 4 }, // horiz=0, vert=1, diag=1 + { 6, 3, 7 }, // horiz=0, vert=1, diag=2 + { 6, 3, 8 }, // horiz=0, vert=1, diag=3 + { 6, 3, 8 }}, // horiz=0, vert=1, diag=4 + {{ 8, 4, 2 }, // horiz=0, vert=2, diag=0 + { 8, 4, 5 }, // horiz=0, vert=2, diag=1 + { 8, 4, 7 }, // horiz=0, vert=2, diag=2 + { 8, 4, 8 }, // horiz=0, vert=2, diag=3 + { 8, 4, 8 }}}, // horiz=0, vert=2, diag=4 + {{{ 3, 5, 1 }, // horiz=1, vert=0, diag=0 + { 3, 6, 4 }, // horiz=1, vert=0, diag=1 + { 3, 6, 7 }, // horiz=1, vert=0, diag=2 + { 3, 6, 8 }, // horiz=1, vert=0, diag=3 + { 3, 6, 8 }}, // horiz=1, vert=0, diag=4 + {{ 7, 7, 2 }, // horiz=1, vert=1, diag=0 + { 7, 7, 5 }, // horiz=1, vert=1, diag=1 + { 7, 7, 7 }, // horiz=1, vert=1, diag=2 + { 7, 7, 8 }, // horiz=1, vert=1, diag=3 + { 7, 7, 8 }}, // horiz=1, vert=1, diag=4 + {{ 8, 7, 2 }, // horiz=1, vert=2, diag=0 + { 8, 7, 5 }, // horiz=1, vert=2, diag=1 + { 8, 7, 7 }, // horiz=1, vert=2, diag=2 + { 8, 7, 8 }, // horiz=1, vert=2, diag=3 + { 8, 7, 8 }}}, // horiz=1, vert=2, diag=4 + {{{ 4, 8, 2 }, // horiz=2, vert=0, diag=0 + { 4, 8, 5 }, // horiz=2, vert=0, diag=1 + { 4, 8, 7 }, // horiz=2, vert=0, diag=2 + { 4, 8, 8 }, // horiz=2, vert=0, diag=3 + { 4, 8, 8 }}, // horiz=2, vert=0, diag=4 + {{ 7, 8, 2 }, // horiz=2, vert=1, diag=0 + { 7, 8, 5 }, // horiz=2, vert=1, diag=1 + { 7, 8, 7 }, // horiz=2, vert=1, diag=2 + { 7, 8, 8 }, // horiz=2, vert=1, diag=3 + { 7, 8, 8 }}, // horiz=2, vert=1, diag=4 + {{ 8, 8, 2 }, // horiz=2, vert=2, diag=0 + { 8, 8, 5 }, // horiz=2, vert=2, diag=1 + { 8, 8, 7 }, // horiz=2, vert=2, diag=2 + { 8, 8, 8 }, // horiz=2, vert=2, diag=3 + { 8, 8, 8 }}} // horiz=2, vert=2, diag=4 +}; + +// arithmetic decoder context and xor bit for the sign bit in the +// significance propagation pass: +// [horiz][vert][k] +// where horiz/vert are offset by 2 (i.e., range is -2 .. 2) +// and k = 0 for the context +// = 1 for the xor bit +static Guint signContext[5][5][2] = { + {{ 13, 1 }, // horiz=-2, vert=-2 + { 13, 1 }, // horiz=-2, vert=-1 + { 12, 1 }, // horiz=-2, vert= 0 + { 11, 1 }, // horiz=-2, vert=+1 + { 11, 1 }}, // horiz=-2, vert=+2 + {{ 13, 1 }, // horiz=-1, vert=-2 + { 13, 1 }, // horiz=-1, vert=-1 + { 12, 1 }, // horiz=-1, vert= 0 + { 11, 1 }, // horiz=-1, vert=+1 + { 11, 1 }}, // horiz=-1, vert=+2 + {{ 10, 1 }, // horiz= 0, vert=-2 + { 10, 1 }, // horiz= 0, vert=-1 + { 9, 0 }, // horiz= 0, vert= 0 + { 10, 0 }, // horiz= 0, vert=+1 + { 10, 0 }}, // horiz= 0, vert=+2 + {{ 11, 0 }, // horiz=+1, vert=-2 + { 11, 0 }, // horiz=+1, vert=-1 + { 12, 0 }, // horiz=+1, vert= 0 + { 13, 0 }, // horiz=+1, vert=+1 + { 13, 0 }}, // horiz=+1, vert=+2 + {{ 11, 0 }, // horiz=+2, vert=-2 + { 11, 0 }, // horiz=+2, vert=-1 + { 12, 0 }, // horiz=+2, vert= 0 + { 13, 0 }, // horiz=+2, vert=+1 + { 13, 0 }}, // horiz=+2, vert=+2 +}; + +//------------------------------------------------------------------------ + +// constants used in the IDWT +#define idwtAlpha -1.586134342059924 +#define idwtBeta -0.052980118572961 +#define idwtGamma 0.882911075530934 +#define idwtDelta 0.443506852043971 +#define idwtKappa 1.230174104914001 +#define idwtIKappa (1.0 / idwtKappa) + +// number of bits to the right of the decimal point for the fixed +// point arithmetic used in the IDWT +#define fracBits 16 + +//------------------------------------------------------------------------ + +// floor(x / y) +#define jpxFloorDiv(x, y) ((x) / (y)) + +// floor(x / 2^y) +#define jpxFloorDivPow2(x, y) ((x) >> (y)) + +// ceil(x / y) +#define jpxCeilDiv(x, y) (((x) + (y) - 1) / (y)) + +// ceil(x / 2^y) +#define jpxCeilDivPow2(x, y) (((x) + (1 << (y)) - 1) >> (y)) + +//------------------------------------------------------------------------ + +#if 1 //----- disable coverage tracking + +#define cover(idx) + +#else //----- enable coverage tracking + +class JPXCover { +public: + + JPXCover(int sizeA); + ~JPXCover(); + void incr(int idx); + +private: + + int size, used; + int *data; +}; + +JPXCover::JPXCover(int sizeA) { + size = sizeA; + used = -1; + data = (int *)gmallocn(size, sizeof(int)); + memset(data, 0, size * sizeof(int)); +} + +JPXCover::~JPXCover() { + int i; + + printf("JPX coverage:\n"); + for (i = 0; i <= used; ++i) { + printf(" %4d: %8d\n", i, data[i]); + } + gfree(data); +} + +void JPXCover::incr(int idx) { + if (idx < size) { + ++data[idx]; + if (idx > used) { + used = idx; + } + } +} + +JPXCover jpxCover(150); + +#define cover(idx) jpxCover.incr(idx) + +#endif //----- coverage tracking + +//------------------------------------------------------------------------ + +JPXStream::JPXStream(Stream *strA): + FilterStream(strA) +{ + nComps = 0; + bpc = NULL; + width = height = 0; + haveCS = gFalse; + havePalette = gFalse; + haveCompMap = gFalse; + haveChannelDefn = gFalse; + + img.tiles = NULL; + bitBuf = 0; + bitBufLen = 0; + bitBufSkip = gFalse; + byteCount = 0; +} + +JPXStream::~JPXStream() { + close(); + delete str; +} + +void JPXStream::reset() { + str->reset(); + if (readBoxes()) { + curY = img.yOffset; + } else { + // readBoxes reported an error, so we go immediately to EOF + curY = img.ySize; + } + curX = img.xOffset; + curComp = 0; + readBufLen = 0; +} + +void JPXStream::close() { + JPXTile *tile; + JPXTileComp *tileComp; + JPXResLevel *resLevel; + JPXPrecinct *precinct; + JPXSubband *subband; + JPXCodeBlock *cb; + Guint comp, i, k, r, pre, sb; + + gfree(bpc); + bpc = NULL; + if (havePalette) { + gfree(palette.bpc); + gfree(palette.c); + havePalette = gFalse; + } + if (haveCompMap) { + gfree(compMap.comp); + gfree(compMap.type); + gfree(compMap.pComp); + haveCompMap = gFalse; + } + if (haveChannelDefn) { + gfree(channelDefn.idx); + gfree(channelDefn.type); + gfree(channelDefn.assoc); + haveChannelDefn = gFalse; + } + + if (img.tiles) { + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + tile = &img.tiles[i]; + if (tile->tileComps) { + for (comp = 0; comp < img.nComps; ++comp) { + tileComp = &tile->tileComps[comp]; + gfree(tileComp->quantSteps); + gfree(tileComp->data); + gfree(tileComp->buf); + if (tileComp->resLevels) { + for (r = 0; r <= tileComp->nDecompLevels; ++r) { + resLevel = &tileComp->resLevels[r]; + if (resLevel->precincts) { + for (pre = 0; pre < 1; ++pre) { + precinct = &resLevel->precincts[pre]; + if (precinct->subbands) { + for (sb = 0; sb < (Guint)(r == 0 ? 1 : 3); ++sb) { + subband = &precinct->subbands[sb]; + gfree(subband->inclusion); + gfree(subband->zeroBitPlane); + if (subband->cbs) { + for (k = 0; k < subband->nXCBs * subband->nYCBs; ++k) { + cb = &subband->cbs[k]; + gfree(cb->coeffs); + if (cb->arithDecoder) { + delete cb->arithDecoder; + } + if (cb->stats) { + delete cb->stats; + } + } + gfree(subband->cbs); + } + } + gfree(precinct->subbands); + } + } + gfree(img.tiles[i].tileComps[comp].resLevels[r].precincts); + } + } + gfree(img.tiles[i].tileComps[comp].resLevels); + } + } + gfree(img.tiles[i].tileComps); + } + } + gfree(img.tiles); + img.tiles = NULL; + } + FilterStream::close(); +} + +int JPXStream::getChar() { + int c; + + if (readBufLen < 8) { + fillReadBuf(); + } + if (readBufLen == 8) { + c = readBuf & 0xff; + readBufLen = 0; + } else if (readBufLen > 8) { + c = (readBuf >> (readBufLen - 8)) & 0xff; + readBufLen -= 8; + } else if (readBufLen == 0) { + c = EOF; + } else { + c = (readBuf << (8 - readBufLen)) & 0xff; + readBufLen = 0; + } + return c; +} + +int JPXStream::lookChar() { + int c; + + if (readBufLen < 8) { + fillReadBuf(); + } + if (readBufLen == 8) { + c = readBuf & 0xff; + } else if (readBufLen > 8) { + c = (readBuf >> (readBufLen - 8)) & 0xff; + } else if (readBufLen == 0) { + c = EOF; + } else { + c = (readBuf << (8 - readBufLen)) & 0xff; + } + return c; +} + +void JPXStream::fillReadBuf() { + JPXTileComp *tileComp; + Guint tileIdx, tx, ty; + int pix, pixBits; + + do { + if (curY >= img.ySize) { + return; + } + tileIdx = ((curY - img.yTileOffset) / img.yTileSize) * img.nXTiles + + (curX - img.xTileOffset) / img.xTileSize; +#if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid + tileComp = &img.tiles[tileIdx].tileComps[curComp]; +#else + tileComp = &img.tiles[tileIdx].tileComps[havePalette ? 0 : curComp]; +#endif + tx = jpxCeilDiv((curX - img.xTileOffset) % img.xTileSize, tileComp->hSep); + ty = jpxCeilDiv((curY - img.yTileOffset) % img.yTileSize, tileComp->vSep); + pix = (int)tileComp->data[ty * (tileComp->x1 - tileComp->x0) + tx]; + pixBits = tileComp->prec; +#if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid + if (++curComp == img.nComps) { +#else + if (havePalette) { + if (pix >= 0 && pix < palette.nEntries) { + pix = palette.c[pix * palette.nComps + curComp]; + } else { + pix = + pixBits = palette.bpc[curComp]; + } + if (++curComp == (Guint)(havePalette ? palette.nComps : img.nComps)) { +#endif + curComp = 0; + if (++curX == img.xSize) { + curX = img.xOffset; + ++curY; + } + } + if (pixBits == 8) { + readBuf = (readBuf << 8) | (pix & 0xff); + } else { + readBuf = (readBuf << pixBits) | (pix & ((1 << pixBits) - 1)); + } + readBufLen += pixBits; + } while (readBufLen < 8); +} + +GString *JPXStream::getPSFilter(int /*psLevel*/, char * /*indent*/) { + return NULL; +} + +GBool JPXStream::isBinary(GBool /*last*/) { + return str->isBinary(gTrue); +} + +void JPXStream::getImageParams(int *bitsPerComponent, + StreamColorSpaceMode *csMode) { + Guint boxType, boxLen, dataLen, csEnum; + Guint bpc1, dummy, i; + int csMeth, csPrec, csPrec1, dummy2; + StreamColorSpaceMode csMode1; + GBool haveBPC, haveCSMode; + + csPrec = 0; // make gcc happy + haveBPC = haveCSMode = gFalse; + str->reset(); + if (str->lookChar() == 0xff) { + getImageParams2(bitsPerComponent, csMode); + } else { + while (readBoxHdr(&boxType, &boxLen, &dataLen)) { + if (boxType == 0x6a703268) { // JP2 header + cover(0); + // skip the superbox + } else if (boxType == 0x69686472) { // image header + cover(1); + if (readULong(&dummy) && + readULong(&dummy) && + readUWord(&dummy) && + readUByte(&bpc1) && + readUByte(&dummy) && + readUByte(&dummy) && + readUByte(&dummy)) { + *bitsPerComponent = bpc1 + 1; + haveBPC = gTrue; + } + } else if (boxType == 0x636F6C72) { // color specification + cover(2); + if (readByte(&csMeth) && + readByte(&csPrec1) && + readByte(&dummy2)) { + if (csMeth == 1) { + if (readULong(&csEnum)) { + csMode1 = streamCSNone; + if (csEnum == jpxCSBiLevel || + csEnum == jpxCSGrayscale) { + csMode1 = streamCSDeviceGray; + } else if (csEnum == jpxCSCMYK) { + csMode1 = streamCSDeviceCMYK; + } else if (csEnum == jpxCSsRGB || + csEnum == jpxCSCISesRGB || + csEnum == jpxCSROMMRGB) { + csMode1 = streamCSDeviceRGB; + } + if (csMode1 != streamCSNone && + (!haveCSMode || csPrec1 > csPrec)) { + *csMode = csMode1; + csPrec = csPrec1; + haveCSMode = gTrue; + } + for (i = 0; i < dataLen - 7; ++i) { + str->getChar(); + } + } + } else { + for (i = 0; i < dataLen - 3; ++i) { + str->getChar(); + } + } + } + } else if (boxType == 0x6A703263) { // codestream + cover(3); + if (!(haveBPC && haveCSMode)) { + getImageParams2(bitsPerComponent, csMode); + } + break; + } else { + cover(4); + for (i = 0; i < dataLen; ++i) { + str->getChar(); + } + } + } + } + str->close(); +} + +// Get image parameters from the codestream. +void JPXStream::getImageParams2(int *bitsPerComponent, + StreamColorSpaceMode *csMode) { + int segType; + Guint segLen, nComps1, bpc1, dummy, i; + + while (readMarkerHdr(&segType, &segLen)) { + if (segType == 0x51) { // SIZ - image and tile size + cover(5); + if (readUWord(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readUWord(&nComps1) && + readUByte(&bpc1)) { + *bitsPerComponent = (bpc1 & 0x7f) + 1; + // if there's no color space info, take a guess + if (nComps1 == 1) { + *csMode = streamCSDeviceGray; + } else if (nComps1 == 3) { + *csMode = streamCSDeviceRGB; + } else if (nComps1 == 4) { + *csMode = streamCSDeviceCMYK; + } + } + break; + } else { + cover(6); + if (segLen > 2) { + for (i = 0; i < segLen - 2; ++i) { + str->getChar(); + } + } + } + } +} + +GBool JPXStream::readBoxes() { + Guint boxType, boxLen, dataLen; + Guint bpc1, compression, unknownColorspace, ipr; + Guint i, j; + + haveImgHdr = gFalse; + + // check for a naked JPEG 2000 codestream (without the JP2/JPX + // wrapper) -- this appears to be a violation of the PDF spec, but + // Acrobat allows it + if (str->lookChar() == 0xff) { + cover(7); + error(getPos(), "Naked JPEG 2000 codestream, missing JP2/JPX wrapper"); + readCodestream(0); + nComps = img.nComps; + bpc = (Guint *)gmallocn(nComps, sizeof(Guint)); + for (i = 0; i < nComps; ++i) { + bpc[i] = img.tiles[0].tileComps[i].prec; + } + width = img.xSize - img.xOffset; + height = img.ySize - img.yOffset; + return gTrue; + } + + while (readBoxHdr(&boxType, &boxLen, &dataLen)) { + switch (boxType) { + case 0x6a703268: // JP2 header + // this is a grouping box ('superbox') which has no real + // contents and doesn't appear to be used consistently, i.e., + // some things which should be subboxes of the JP2 header box + // show up outside of it - so we simply ignore the JP2 header + // box + cover(8); + break; + case 0x69686472: // image header + cover(9); + if (!readULong(&height) || + !readULong(&width) || + !readUWord(&nComps) || + !readUByte(&bpc1) || + !readUByte(&compression) || + !readUByte(&unknownColorspace) || + !readUByte(&ipr)) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + if (compression != 7) { + error(getPos(), "Unknown compression type in JPX stream"); + return gFalse; + } + bpc = (Guint *)gmallocn(nComps, sizeof(Guint)); + for (i = 0; i < nComps; ++i) { + bpc[i] = bpc1; + } + haveImgHdr = gTrue; + break; + case 0x62706363: // bits per component + cover(10); + if (!haveImgHdr) { + error(getPos(), "Found bits per component box before image header box in JPX stream"); + return gFalse; + } + if (dataLen != nComps) { + error(getPos(), "Invalid bits per component box in JPX stream"); + return gFalse; + } + for (i = 0; i < nComps; ++i) { + if (!readUByte(&bpc[i])) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + } + break; + case 0x636F6C72: // color specification + cover(11); + if (!readColorSpecBox(dataLen)) { + return gFalse; + } + break; + case 0x70636c72: // palette + cover(12); + if (!readUWord(&palette.nEntries) || + !readUByte(&palette.nComps)) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + palette.bpc = (Guint *)gmallocn(palette.nComps, sizeof(Guint)); + palette.c = + (int *)gmallocn(palette.nEntries * palette.nComps, sizeof(int)); + for (i = 0; i < palette.nComps; ++i) { + if (!readUByte(&palette.bpc[i])) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + ++palette.bpc[i]; + } + for (i = 0; i < palette.nEntries; ++i) { + for (j = 0; j < palette.nComps; ++j) { + if (!readNBytes(((palette.bpc[j] & 0x7f) + 7) >> 3, + (palette.bpc[j] & 0x80) ? gTrue : gFalse, + &palette.c[i * palette.nComps + j])) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + } + } + havePalette = gTrue; + break; + case 0x636d6170: // component mapping + cover(13); + compMap.nChannels = dataLen / 4; + compMap.comp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint)); + compMap.type = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint)); + compMap.pComp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint)); + for (i = 0; i < compMap.nChannels; ++i) { + if (!readUWord(&compMap.comp[i]) || + !readUByte(&compMap.type[i]) || + !readUByte(&compMap.pComp[i])) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + } + haveCompMap = gTrue; + break; + case 0x63646566: // channel definition + cover(14); + if (!readUWord(&channelDefn.nChannels)) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + channelDefn.idx = + (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint)); + channelDefn.type = + (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint)); + channelDefn.assoc = + (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint)); + for (i = 0; i < channelDefn.nChannels; ++i) { + if (!readUWord(&channelDefn.idx[i]) || + !readUWord(&channelDefn.type[i]) || + !readUWord(&channelDefn.assoc[i])) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + } + haveChannelDefn = gTrue; + break; + case 0x6A703263: // contiguous codestream + cover(15); + if (!bpc) { + error(getPos(), "JPX stream is missing the image header box"); + } + if (!haveCS) { + error(getPos(), "JPX stream has no supported color spec"); + } + if (!readCodestream(dataLen)) { + return gFalse; + } + break; + default: + cover(16); + for (i = 0; i < dataLen; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + } + break; + } + } + return gTrue; +} + +GBool JPXStream::readColorSpecBox(Guint dataLen) { + JPXColorSpec newCS; + Guint csApprox, csEnum; + Guint i; + GBool ok; + + ok = gFalse; + if (!readUByte(&newCS.meth) || + !readByte(&newCS.prec) || + !readUByte(&csApprox)) { + goto err; + } + switch (newCS.meth) { + case 1: // enumerated colorspace + cover(17); + if (!readULong(&csEnum)) { + goto err; + } + newCS.enumerated.type = (JPXColorSpaceType)csEnum; + switch (newCS.enumerated.type) { + case jpxCSBiLevel: + ok = gTrue; + break; + case jpxCSYCbCr1: + ok = gTrue; + break; + case jpxCSYCbCr2: + ok = gTrue; + break; + case jpxCSYCBCr3: + ok = gTrue; + break; + case jpxCSPhotoYCC: + ok = gTrue; + break; + case jpxCSCMY: + ok = gTrue; + break; + case jpxCSCMYK: + ok = gTrue; + break; + case jpxCSYCCK: + ok = gTrue; + break; + case jpxCSCIELab: + if (dataLen == 7 + 7*4) { + if (!readULong(&newCS.enumerated.cieLab.rl) || + !readULong(&newCS.enumerated.cieLab.ol) || + !readULong(&newCS.enumerated.cieLab.ra) || + !readULong(&newCS.enumerated.cieLab.oa) || + !readULong(&newCS.enumerated.cieLab.rb) || + !readULong(&newCS.enumerated.cieLab.ob) || + !readULong(&newCS.enumerated.cieLab.il)) { + goto err; + } + } else if (dataLen == 7) { + //~ this assumes the 8-bit case + cover(92); + newCS.enumerated.cieLab.rl = 100; + newCS.enumerated.cieLab.ol = 0; + newCS.enumerated.cieLab.ra = 255; + newCS.enumerated.cieLab.oa = 128; + newCS.enumerated.cieLab.rb = 255; + newCS.enumerated.cieLab.ob = 96; + newCS.enumerated.cieLab.il = 0x00443530; + } else { + goto err; + } + ok = gTrue; + break; + case jpxCSsRGB: + ok = gTrue; + break; + case jpxCSGrayscale: + ok = gTrue; + break; + case jpxCSBiLevel2: + ok = gTrue; + break; + case jpxCSCIEJab: + // not allowed in PDF + goto err; + case jpxCSCISesRGB: + ok = gTrue; + break; + case jpxCSROMMRGB: + ok = gTrue; + break; + case jpxCSsRGBYCbCr: + ok = gTrue; + break; + case jpxCSYPbPr1125: + ok = gTrue; + break; + case jpxCSYPbPr1250: + ok = gTrue; + break; + default: + goto err; + } + break; + case 2: // restricted ICC profile + case 3: // any ICC profile (JPX) + case 4: // vendor color (JPX) + cover(18); + for (i = 0; i < dataLen - 3; ++i) { + if (str->getChar() == EOF) { + goto err; + } + } + break; + } + + if (ok && (!haveCS || newCS.prec > cs.prec)) { + cs = newCS; + haveCS = gTrue; + } + + return gTrue; + + err: + error(getPos(), "Error in JPX color spec"); + return gFalse; +} + +GBool JPXStream::readCodestream(Guint /*len*/) { + JPXTile *tile; + JPXTileComp *tileComp; + int segType; + GBool haveSIZ, haveCOD, haveQCD, haveSOT; + Guint precinctSize, style; + Guint segLen, capabilities, comp, i, j, r; + + //----- main header + haveSIZ = haveCOD = haveQCD = haveSOT = gFalse; + do { + if (!readMarkerHdr(&segType, &segLen)) { + error(getPos(), "Error in JPX codestream"); + return gFalse; + } + switch (segType) { + case 0x4f: // SOC - start of codestream + // marker only + cover(19); + break; + case 0x51: // SIZ - image and tile size + cover(20); + if (!readUWord(&capabilities) || + !readULong(&img.xSize) || + !readULong(&img.ySize) || + !readULong(&img.xOffset) || + !readULong(&img.yOffset) || + !readULong(&img.xTileSize) || + !readULong(&img.yTileSize) || + !readULong(&img.xTileOffset) || + !readULong(&img.yTileOffset) || + !readUWord(&img.nComps)) { + error(getPos(), "Error in JPX SIZ marker segment"); + return gFalse; + } + if (haveImgHdr && img.nComps != nComps) { + error(getPos(), "Different number of components in JPX SIZ marker segment"); + return gFalse; + } + img.nXTiles = (img.xSize - img.xTileOffset + img.xTileSize - 1) + / img.xTileSize; + img.nYTiles = (img.ySize - img.yTileOffset + img.yTileSize - 1) + / img.yTileSize; + // check for overflow before allocating memory + if (img.nXTiles <= 0 || img.nYTiles <= 0 || + img.nXTiles >= INT_MAX / img.nYTiles) { + error(getPos(), "Bad tile count in JPX SIZ marker segment"); + return gFalse; + } + img.tiles = (JPXTile *)gmallocn(img.nXTiles * img.nYTiles, + sizeof(JPXTile)); + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + img.tiles[i].tileComps = (JPXTileComp *)gmallocn(img.nComps, + sizeof(JPXTileComp)); + for (comp = 0; comp < img.nComps; ++comp) { + img.tiles[i].tileComps[comp].quantSteps = NULL; + img.tiles[i].tileComps[comp].data = NULL; + img.tiles[i].tileComps[comp].buf = NULL; + img.tiles[i].tileComps[comp].resLevels = NULL; + } + } + for (comp = 0; comp < img.nComps; ++comp) { + if (!readUByte(&img.tiles[0].tileComps[comp].prec) || + !readUByte(&img.tiles[0].tileComps[comp].hSep) || + !readUByte(&img.tiles[0].tileComps[comp].vSep)) { + error(getPos(), "Error in JPX SIZ marker segment"); + return gFalse; + } + img.tiles[0].tileComps[comp].sgned = + (img.tiles[0].tileComps[comp].prec & 0x80) ? gTrue : gFalse; + img.tiles[0].tileComps[comp].prec = + (img.tiles[0].tileComps[comp].prec & 0x7f) + 1; + for (i = 1; i < img.nXTiles * img.nYTiles; ++i) { + img.tiles[i].tileComps[comp] = img.tiles[0].tileComps[comp]; + } + } + haveSIZ = gTrue; + break; + case 0x52: // COD - coding style default + cover(21); + if (!readUByte(&img.tiles[0].tileComps[0].style) || + !readUByte(&img.tiles[0].progOrder) || + !readUWord(&img.tiles[0].nLayers) || + !readUByte(&img.tiles[0].multiComp) || + !readUByte(&img.tiles[0].tileComps[0].nDecompLevels) || + !readUByte(&img.tiles[0].tileComps[0].codeBlockW) || + !readUByte(&img.tiles[0].tileComps[0].codeBlockH) || + !readUByte(&img.tiles[0].tileComps[0].codeBlockStyle) || + !readUByte(&img.tiles[0].tileComps[0].transform)) { + error(getPos(), "Error in JPX COD marker segment"); + return gFalse; + } + img.tiles[0].tileComps[0].codeBlockW += 2; + img.tiles[0].tileComps[0].codeBlockH += 2; + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + if (i != 0) { + img.tiles[i].progOrder = img.tiles[0].progOrder; + img.tiles[i].nLayers = img.tiles[0].nLayers; + img.tiles[i].multiComp = img.tiles[0].multiComp; + } + for (comp = 0; comp < img.nComps; ++comp) { + if (!(i == 0 && comp == 0)) { + img.tiles[i].tileComps[comp].style = + img.tiles[0].tileComps[0].style; + img.tiles[i].tileComps[comp].nDecompLevels = + img.tiles[0].tileComps[0].nDecompLevels; + img.tiles[i].tileComps[comp].codeBlockW = + img.tiles[0].tileComps[0].codeBlockW; + img.tiles[i].tileComps[comp].codeBlockH = + img.tiles[0].tileComps[0].codeBlockH; + img.tiles[i].tileComps[comp].codeBlockStyle = + img.tiles[0].tileComps[0].codeBlockStyle; + img.tiles[i].tileComps[comp].transform = + img.tiles[0].tileComps[0].transform; + } + img.tiles[i].tileComps[comp].resLevels = + (JPXResLevel *)gmallocn( + (img.tiles[i].tileComps[comp].nDecompLevels + 1), + sizeof(JPXResLevel)); + for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { + img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL; + } + } + } + for (r = 0; r <= img.tiles[0].tileComps[0].nDecompLevels; ++r) { + if (img.tiles[0].tileComps[0].style & 0x01) { + cover(91); + if (!readUByte(&precinctSize)) { + error(getPos(), "Error in JPX COD marker segment"); + return gFalse; + } + img.tiles[0].tileComps[0].resLevels[r].precinctWidth = + precinctSize & 0x0f; + img.tiles[0].tileComps[0].resLevels[r].precinctHeight = + (precinctSize >> 4) & 0x0f; + } else { + img.tiles[0].tileComps[0].resLevels[r].precinctWidth = 15; + img.tiles[0].tileComps[0].resLevels[r].precinctHeight = 15; + } + } + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + for (comp = 0; comp < img.nComps; ++comp) { + if (!(i == 0 && comp == 0)) { + for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { + img.tiles[i].tileComps[comp].resLevels[r].precinctWidth = + img.tiles[0].tileComps[0].resLevels[r].precinctWidth; + img.tiles[i].tileComps[comp].resLevels[r].precinctHeight = + img.tiles[0].tileComps[0].resLevels[r].precinctHeight; + } + } + } + } + haveCOD = gTrue; + break; + case 0x53: // COC - coding style component + cover(22); + if (!haveCOD) { + error(getPos(), "JPX COC marker segment before COD segment"); + return gFalse; + } + if ((img.nComps > 256 && !readUWord(&comp)) || + (img.nComps <= 256 && !readUByte(&comp)) || + comp >= img.nComps || + !readUByte(&style) || + !readUByte(&img.tiles[0].tileComps[comp].nDecompLevels) || + !readUByte(&img.tiles[0].tileComps[comp].codeBlockW) || + !readUByte(&img.tiles[0].tileComps[comp].codeBlockH) || + !readUByte(&img.tiles[0].tileComps[comp].codeBlockStyle) || + !readUByte(&img.tiles[0].tileComps[comp].transform)) { + error(getPos(), "Error in JPX COC marker segment"); + return gFalse; + } + img.tiles[0].tileComps[comp].style = + (img.tiles[0].tileComps[comp].style & ~1) | (style & 1); + img.tiles[0].tileComps[comp].codeBlockW += 2; + img.tiles[0].tileComps[comp].codeBlockH += 2; + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + if (i != 0) { + img.tiles[i].tileComps[comp].style = + img.tiles[0].tileComps[comp].style; + img.tiles[i].tileComps[comp].nDecompLevels = + img.tiles[0].tileComps[comp].nDecompLevels; + img.tiles[i].tileComps[comp].codeBlockW = + img.tiles[0].tileComps[comp].codeBlockW; + img.tiles[i].tileComps[comp].codeBlockH = + img.tiles[0].tileComps[comp].codeBlockH; + img.tiles[i].tileComps[comp].codeBlockStyle = + img.tiles[0].tileComps[comp].codeBlockStyle; + img.tiles[i].tileComps[comp].transform = + img.tiles[0].tileComps[comp].transform; + } + img.tiles[i].tileComps[comp].resLevels = + (JPXResLevel *)greallocn( + img.tiles[i].tileComps[comp].resLevels, + (img.tiles[i].tileComps[comp].nDecompLevels + 1), + sizeof(JPXResLevel)); + for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { + img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL; + } + } + for (r = 0; r <= img.tiles[0].tileComps[comp].nDecompLevels; ++r) { + if (img.tiles[0].tileComps[comp].style & 0x01) { + if (!readUByte(&precinctSize)) { + error(getPos(), "Error in JPX COD marker segment"); + return gFalse; + } + img.tiles[0].tileComps[comp].resLevels[r].precinctWidth = + precinctSize & 0x0f; + img.tiles[0].tileComps[comp].resLevels[r].precinctHeight = + (precinctSize >> 4) & 0x0f; + } else { + img.tiles[0].tileComps[comp].resLevels[r].precinctWidth = 15; + img.tiles[0].tileComps[comp].resLevels[r].precinctHeight = 15; + } + } + for (i = 1; i < img.nXTiles * img.nYTiles; ++i) { + for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { + img.tiles[i].tileComps[comp].resLevels[r].precinctWidth = + img.tiles[0].tileComps[comp].resLevels[r].precinctWidth; + img.tiles[i].tileComps[comp].resLevels[r].precinctHeight = + img.tiles[0].tileComps[comp].resLevels[r].precinctHeight; + } + } + break; + case 0x5c: // QCD - quantization default + cover(23); + if (!readUByte(&img.tiles[0].tileComps[0].quantStyle)) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x00) { + img.tiles[0].tileComps[0].nQuantSteps = segLen - 3; + img.tiles[0].tileComps[0].quantSteps = + (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps, + img.tiles[0].tileComps[0].nQuantSteps, + sizeof(Guint)); + for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) { + if (!readUByte(&img.tiles[0].tileComps[0].quantSteps[i])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } + } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x01) { + img.tiles[0].tileComps[0].nQuantSteps = 1; + img.tiles[0].tileComps[0].quantSteps = + (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps, + img.tiles[0].tileComps[0].nQuantSteps, + sizeof(Guint)); + if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[0])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x02) { + img.tiles[0].tileComps[0].nQuantSteps = (segLen - 3) / 2; + img.tiles[0].tileComps[0].quantSteps = + (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps, + img.tiles[0].tileComps[0].nQuantSteps, + sizeof(Guint)); + for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) { + if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[i])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } + } else { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + for (comp = 0; comp < img.nComps; ++comp) { + if (!(i == 0 && comp == 0)) { + img.tiles[i].tileComps[comp].quantStyle = + img.tiles[0].tileComps[0].quantStyle; + img.tiles[i].tileComps[comp].nQuantSteps = + img.tiles[0].tileComps[0].nQuantSteps; + img.tiles[i].tileComps[comp].quantSteps = + (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps, + img.tiles[0].tileComps[0].nQuantSteps, + sizeof(Guint)); + for (j = 0; j < img.tiles[0].tileComps[0].nQuantSteps; ++j) { + img.tiles[i].tileComps[comp].quantSteps[j] = + img.tiles[0].tileComps[0].quantSteps[j]; + } + } + } + } + haveQCD = gTrue; + break; + case 0x5d: // QCC - quantization component + cover(24); + if (!haveQCD) { + error(getPos(), "JPX QCC marker segment before QCD segment"); + return gFalse; + } + if ((img.nComps > 256 && !readUWord(&comp)) || + (img.nComps <= 256 && !readUByte(&comp)) || + comp >= img.nComps || + !readUByte(&img.tiles[0].tileComps[comp].quantStyle)) { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x00) { + img.tiles[0].tileComps[comp].nQuantSteps = + segLen - (img.nComps > 256 ? 5 : 4); + img.tiles[0].tileComps[comp].quantSteps = + (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps, + img.tiles[0].tileComps[comp].nQuantSteps, + sizeof(Guint)); + for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) { + if (!readUByte(&img.tiles[0].tileComps[comp].quantSteps[i])) { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + } + } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x01) { + img.tiles[0].tileComps[comp].nQuantSteps = 1; + img.tiles[0].tileComps[comp].quantSteps = + (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps, + img.tiles[0].tileComps[comp].nQuantSteps, + sizeof(Guint)); + if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[0])) { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x02) { + img.tiles[0].tileComps[comp].nQuantSteps = + (segLen - (img.nComps > 256 ? 5 : 4)) / 2; + img.tiles[0].tileComps[comp].quantSteps = + (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps, + img.tiles[0].tileComps[comp].nQuantSteps, + sizeof(Guint)); + for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) { + if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[i])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } + } else { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + for (i = 1; i < img.nXTiles * img.nYTiles; ++i) { + img.tiles[i].tileComps[comp].quantStyle = + img.tiles[0].tileComps[comp].quantStyle; + img.tiles[i].tileComps[comp].nQuantSteps = + img.tiles[0].tileComps[comp].nQuantSteps; + img.tiles[i].tileComps[comp].quantSteps = + (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps, + img.tiles[0].tileComps[comp].nQuantSteps, + sizeof(Guint)); + for (j = 0; j < img.tiles[0].tileComps[comp].nQuantSteps; ++j) { + img.tiles[i].tileComps[comp].quantSteps[j] = + img.tiles[0].tileComps[comp].quantSteps[j]; + } + } + break; + case 0x5e: // RGN - region of interest + cover(25); +#if 1 //~ ROI is unimplemented + fprintf(stderr, "RGN\n"); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PPM marker segment"); + return gFalse; + } + } +#else + if ((img.nComps > 256 && !readUWord(&comp)) || + (img.nComps <= 256 && !readUByte(&comp)) || + comp >= img.nComps || + !readUByte(&compInfo[comp].defROI.style) || + !readUByte(&compInfo[comp].defROI.shift)) { + error(getPos(), "Error in JPX RGN marker segment"); + return gFalse; + } +#endif + break; + case 0x5f: // POC - progression order change + cover(26); +#if 1 //~ progression order changes are unimplemented + fprintf(stderr, "POC\n"); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PPM marker segment"); + return gFalse; + } + } +#else + nProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7); + progs = (JPXProgOrder *)gmallocn(nProgs, sizeof(JPXProgOrder)); + for (i = 0; i < nProgs; ++i) { + if (!readUByte(&progs[i].startRes) || + !(img.nComps > 256 && readUWord(&progs[i].startComp)) || + !(img.nComps <= 256 && readUByte(&progs[i].startComp)) || + !readUWord(&progs[i].endLayer) || + !readUByte(&progs[i].endRes) || + !(img.nComps > 256 && readUWord(&progs[i].endComp)) || + !(img.nComps <= 256 && readUByte(&progs[i].endComp)) || + !readUByte(&progs[i].progOrder)) { + error(getPos(), "Error in JPX POC marker segment"); + return gFalse; + } + } +#endif + break; + case 0x60: // PPM - packed packet headers, main header + cover(27); +#if 1 //~ packed packet headers are unimplemented + fprintf(stderr, "PPM\n"); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PPM marker segment"); + return gFalse; + } + } +#endif + break; + case 0x55: // TLM - tile-part lengths + // skipped + cover(28); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX TLM marker segment"); + return gFalse; + } + } + break; + case 0x57: // PLM - packet length, main header + // skipped + cover(29); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PLM marker segment"); + return gFalse; + } + } + break; + case 0x63: // CRG - component registration + // skipped + cover(30); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX CRG marker segment"); + return gFalse; + } + } + break; + case 0x64: // COM - comment + // skipped + cover(31); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX COM marker segment"); + return gFalse; + } + } + break; + case 0x90: // SOT - start of tile + cover(32); + haveSOT = gTrue; + break; + default: + cover(33); + error(getPos(), "Unknown marker segment %02x in JPX stream", segType); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + break; + } + } + break; + } + } while (!haveSOT); + + if (!haveSIZ) { + error(getPos(), "Missing SIZ marker segment in JPX stream"); + return gFalse; + } + if (!haveCOD) { + error(getPos(), "Missing COD marker segment in JPX stream"); + return gFalse; + } + if (!haveQCD) { + error(getPos(), "Missing QCD marker segment in JPX stream"); + return gFalse; + } + + //----- read the tile-parts + while (1) { + if (!readTilePart()) { + return gFalse; + } + if (!readMarkerHdr(&segType, &segLen)) { + error(getPos(), "Error in JPX codestream"); + return gFalse; + } + if (segType != 0x90) { // SOT - start of tile + break; + } + } + + if (segType != 0xd9) { // EOC - end of codestream + error(getPos(), "Missing EOC marker in JPX codestream"); + return gFalse; + } + + //----- finish decoding the image + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + tile = &img.tiles[i]; + for (comp = 0; comp < img.nComps; ++comp) { + tileComp = &tile->tileComps[comp]; + inverseTransform(tileComp); + } + if (!inverseMultiCompAndDC(tile)) { + return gFalse; + } + } + + //~ can free memory below tileComps here, and also tileComp.buf + + return gTrue; +} + +GBool JPXStream::readTilePart() { + JPXTile *tile; + JPXTileComp *tileComp; + JPXResLevel *resLevel; + JPXPrecinct *precinct; + JPXSubband *subband; + JPXCodeBlock *cb; + GBool haveSOD; + Guint tileIdx, tilePartLen, tilePartIdx, nTileParts; + GBool tilePartToEOC; + Guint precinctSize, style; + Guint n, nSBs, nx, ny, sbx0, sby0, comp, segLen; + Guint i, j, k, cbX, cbY, r, pre, sb, cbi; + int segType, level; + + // process the SOT marker segment + if (!readUWord(&tileIdx) || + !readULong(&tilePartLen) || + !readUByte(&tilePartIdx) || + !readUByte(&nTileParts)) { + error(getPos(), "Error in JPX SOT marker segment"); + return gFalse; + } + + if (tileIdx >= img.nXTiles * img.nYTiles) { + error(getPos(), "Weird tile index in JPX stream"); + return gFalse; + } + + tilePartToEOC = tilePartLen == 0; + tilePartLen -= 12; // subtract size of SOT segment + + haveSOD = gFalse; + do { + if (!readMarkerHdr(&segType, &segLen)) { + error(getPos(), "Error in JPX tile-part codestream"); + return gFalse; + } + tilePartLen -= 2 + segLen; + switch (segType) { + case 0x52: // COD - coding style default + cover(34); + if (!readUByte(&img.tiles[tileIdx].tileComps[0].style) || + !readUByte(&img.tiles[tileIdx].progOrder) || + !readUWord(&img.tiles[tileIdx].nLayers) || + !readUByte(&img.tiles[tileIdx].multiComp) || + !readUByte(&img.tiles[tileIdx].tileComps[0].nDecompLevels) || + !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockW) || + !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockH) || + !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockStyle) || + !readUByte(&img.tiles[tileIdx].tileComps[0].transform)) { + error(getPos(), "Error in JPX COD marker segment"); + return gFalse; + } + img.tiles[tileIdx].tileComps[0].codeBlockW += 2; + img.tiles[tileIdx].tileComps[0].codeBlockH += 2; + for (comp = 0; comp < img.nComps; ++comp) { + if (comp != 0) { + img.tiles[tileIdx].tileComps[comp].style = + img.tiles[tileIdx].tileComps[0].style; + img.tiles[tileIdx].tileComps[comp].nDecompLevels = + img.tiles[tileIdx].tileComps[0].nDecompLevels; + img.tiles[tileIdx].tileComps[comp].codeBlockW = + img.tiles[tileIdx].tileComps[0].codeBlockW; + img.tiles[tileIdx].tileComps[comp].codeBlockH = + img.tiles[tileIdx].tileComps[0].codeBlockH; + img.tiles[tileIdx].tileComps[comp].codeBlockStyle = + img.tiles[tileIdx].tileComps[0].codeBlockStyle; + img.tiles[tileIdx].tileComps[comp].transform = + img.tiles[tileIdx].tileComps[0].transform; + } + img.tiles[tileIdx].tileComps[comp].resLevels = + (JPXResLevel *)greallocn( + img.tiles[tileIdx].tileComps[comp].resLevels, + (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1), + sizeof(JPXResLevel)); + for (r = 0; + r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; + ++r) { + img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL; + } + } + for (r = 0; r <= img.tiles[tileIdx].tileComps[0].nDecompLevels; ++r) { + if (img.tiles[tileIdx].tileComps[0].style & 0x01) { + if (!readUByte(&precinctSize)) { + error(getPos(), "Error in JPX COD marker segment"); + return gFalse; + } + img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth = + precinctSize & 0x0f; + img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight = + (precinctSize >> 4) & 0x0f; + } else { + img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth = 15; + img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight = 15; + } + } + for (comp = 1; comp < img.nComps; ++comp) { + for (r = 0; + r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; + ++r) { + img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = + img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth; + img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = + img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight; + } + } + break; + case 0x53: // COC - coding style component + cover(35); + if ((img.nComps > 256 && !readUWord(&comp)) || + (img.nComps <= 256 && !readUByte(&comp)) || + comp >= img.nComps || + !readUByte(&style) || + !readUByte(&img.tiles[tileIdx].tileComps[comp].nDecompLevels) || + !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockW) || + !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockH) || + !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockStyle) || + !readUByte(&img.tiles[tileIdx].tileComps[comp].transform)) { + error(getPos(), "Error in JPX COC marker segment"); + return gFalse; + } + img.tiles[tileIdx].tileComps[comp].style = + (img.tiles[tileIdx].tileComps[comp].style & ~1) | (style & 1); + img.tiles[tileIdx].tileComps[comp].codeBlockW += 2; + img.tiles[tileIdx].tileComps[comp].codeBlockH += 2; + img.tiles[tileIdx].tileComps[comp].resLevels = + (JPXResLevel *)greallocn( + img.tiles[tileIdx].tileComps[comp].resLevels, + (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1), + sizeof(JPXResLevel)); + for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) { + img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL; + } + for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) { + if (img.tiles[tileIdx].tileComps[comp].style & 0x01) { + if (!readUByte(&precinctSize)) { + error(getPos(), "Error in JPX COD marker segment"); + return gFalse; + } + img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = + precinctSize & 0x0f; + img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = + (precinctSize >> 4) & 0x0f; + } else { + img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = 15; + img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = 15; + } + } + break; + case 0x5c: // QCD - quantization default + cover(36); + if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantStyle)) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x00) { + img.tiles[tileIdx].tileComps[0].nQuantSteps = + segLen - 3; + img.tiles[tileIdx].tileComps[0].quantSteps = + (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps, + img.tiles[tileIdx].tileComps[0].nQuantSteps, + sizeof(Guint)); + for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) { + if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } + } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x01) { + img.tiles[tileIdx].tileComps[0].nQuantSteps = 1; + img.tiles[tileIdx].tileComps[0].quantSteps = + (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps, + img.tiles[tileIdx].tileComps[0].nQuantSteps, + sizeof(Guint)); + if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[0])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x02) { + img.tiles[tileIdx].tileComps[0].nQuantSteps = (segLen - 3) / 2; + img.tiles[tileIdx].tileComps[0].quantSteps = + (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps, + img.tiles[tileIdx].tileComps[0].nQuantSteps, + sizeof(Guint)); + for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) { + if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } + } else { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + for (comp = 1; comp < img.nComps; ++comp) { + img.tiles[tileIdx].tileComps[comp].quantStyle = + img.tiles[tileIdx].tileComps[0].quantStyle; + img.tiles[tileIdx].tileComps[comp].nQuantSteps = + img.tiles[tileIdx].tileComps[0].nQuantSteps; + img.tiles[tileIdx].tileComps[comp].quantSteps = + (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, + img.tiles[tileIdx].tileComps[0].nQuantSteps, + sizeof(Guint)); + for (j = 0; j < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++j) { + img.tiles[tileIdx].tileComps[comp].quantSteps[j] = + img.tiles[tileIdx].tileComps[0].quantSteps[j]; + } + } + break; + case 0x5d: // QCC - quantization component + cover(37); + if ((img.nComps > 256 && !readUWord(&comp)) || + (img.nComps <= 256 && !readUByte(&comp)) || + comp >= img.nComps || + !readUByte(&img.tiles[tileIdx].tileComps[comp].quantStyle)) { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) == 0x00) { + img.tiles[tileIdx].tileComps[comp].nQuantSteps = + segLen - (img.nComps > 256 ? 5 : 4); + img.tiles[tileIdx].tileComps[comp].quantSteps = + (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, + img.tiles[tileIdx].tileComps[comp].nQuantSteps, + sizeof(Guint)); + for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) { + if (!readUByte(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + } + } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) + == 0x01) { + img.tiles[tileIdx].tileComps[comp].nQuantSteps = 1; + img.tiles[tileIdx].tileComps[comp].quantSteps = + (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, + img.tiles[tileIdx].tileComps[comp].nQuantSteps, + sizeof(Guint)); + if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[0])) { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) + == 0x02) { + img.tiles[tileIdx].tileComps[comp].nQuantSteps = + (segLen - (img.nComps > 256 ? 5 : 4)) / 2; + img.tiles[tileIdx].tileComps[comp].quantSteps = + (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, + img.tiles[tileIdx].tileComps[comp].nQuantSteps, + sizeof(Guint)); + for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) { + if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } + } else { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + break; + case 0x5e: // RGN - region of interest + cover(38); +#if 1 //~ ROI is unimplemented + fprintf(stderr, "RGN\n"); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PPM marker segment"); + return gFalse; + } + } +#else + if ((img.nComps > 256 && !readUWord(&comp)) || + (img.nComps <= 256 && !readUByte(&comp)) || + comp >= img.nComps || + !readUByte(&compInfo[comp].roi.style) || + !readUByte(&compInfo[comp].roi.shift)) { + error(getPos(), "Error in JPX RGN marker segment"); + return gFalse; + } +#endif + break; + case 0x5f: // POC - progression order change + cover(39); +#if 1 //~ progression order changes are unimplemented + fprintf(stderr, "POC\n"); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PPM marker segment"); + return gFalse; + } + } +#else + nTileProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7); + tileProgs = (JPXProgOrder *)gmallocn(nTileProgs, sizeof(JPXProgOrder)); + for (i = 0; i < nTileProgs; ++i) { + if (!readUByte(&tileProgs[i].startRes) || + !(img.nComps > 256 && readUWord(&tileProgs[i].startComp)) || + !(img.nComps <= 256 && readUByte(&tileProgs[i].startComp)) || + !readUWord(&tileProgs[i].endLayer) || + !readUByte(&tileProgs[i].endRes) || + !(img.nComps > 256 && readUWord(&tileProgs[i].endComp)) || + !(img.nComps <= 256 && readUByte(&tileProgs[i].endComp)) || + !readUByte(&tileProgs[i].progOrder)) { + error(getPos(), "Error in JPX POC marker segment"); + return gFalse; + } + } +#endif + break; + case 0x61: // PPT - packed packet headers, tile-part hdr + cover(40); +#if 1 //~ packed packet headers are unimplemented + fprintf(stderr, "PPT\n"); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PPT marker segment"); + return gFalse; + } + } +#endif + case 0x58: // PLT - packet length, tile-part header + // skipped + cover(41); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PLT marker segment"); + return gFalse; + } + } + break; + case 0x64: // COM - comment + // skipped + cover(42); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX COM marker segment"); + return gFalse; + } + } + break; + case 0x93: // SOD - start of data + cover(43); + haveSOD = gTrue; + break; + default: + cover(44); + error(getPos(), "Unknown marker segment %02x in JPX tile-part stream", + segType); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + break; + } + } + break; + } + } while (!haveSOD); + + //----- initialize the tile, precincts, and code-blocks + if (tilePartIdx == 0) { + tile = &img.tiles[tileIdx]; + i = tileIdx / img.nXTiles; + j = tileIdx % img.nXTiles; + if ((tile->x0 = img.xTileOffset + j * img.xTileSize) < img.xOffset) { + tile->x0 = img.xOffset; + } + if ((tile->y0 = img.yTileOffset + i * img.yTileSize) < img.yOffset) { + tile->y0 = img.yOffset; + } + if ((tile->x1 = img.xTileOffset + (j + 1) * img.xTileSize) > img.xSize) { + tile->x1 = img.xSize; + } + if ((tile->y1 = img.yTileOffset + (i + 1) * img.yTileSize) > img.ySize) { + tile->y1 = img.ySize; + } + tile->comp = 0; + tile->res = 0; + tile->precinct = 0; + tile->layer = 0; + tile->maxNDecompLevels = 0; + for (comp = 0; comp < img.nComps; ++comp) { + tileComp = &tile->tileComps[comp]; + if (tileComp->nDecompLevels > tile->maxNDecompLevels) { + tile->maxNDecompLevels = tileComp->nDecompLevels; + } + tileComp->x0 = jpxCeilDiv(tile->x0, tileComp->hSep); + tileComp->y0 = jpxCeilDiv(tile->y0, tileComp->hSep); + tileComp->x1 = jpxCeilDiv(tile->x1, tileComp->hSep); + tileComp->y1 = jpxCeilDiv(tile->y1, tileComp->hSep); + tileComp->cbW = 1 << tileComp->codeBlockW; + tileComp->cbH = 1 << tileComp->codeBlockH; + tileComp->data = (int *)gmallocn((tileComp->x1 - tileComp->x0) * + (tileComp->y1 - tileComp->y0), + sizeof(int)); + if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) { + n = tileComp->x1 - tileComp->x0; + } else { + n = tileComp->y1 - tileComp->y0; + } + tileComp->buf = (int *)gmallocn(n + 8, sizeof(int)); + for (r = 0; r <= tileComp->nDecompLevels; ++r) { + resLevel = &tileComp->resLevels[r]; + k = r == 0 ? tileComp->nDecompLevels + : tileComp->nDecompLevels - r + 1; + resLevel->x0 = jpxCeilDivPow2(tileComp->x0, k); + resLevel->y0 = jpxCeilDivPow2(tileComp->y0, k); + resLevel->x1 = jpxCeilDivPow2(tileComp->x1, k); + resLevel->y1 = jpxCeilDivPow2(tileComp->y1, k); + if (r == 0) { + resLevel->bx0[0] = resLevel->x0; + resLevel->by0[0] = resLevel->y0; + resLevel->bx1[0] = resLevel->x1; + resLevel->by1[0] = resLevel->y1; + } else { + resLevel->bx0[0] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k); + resLevel->by0[0] = resLevel->y0; + resLevel->bx1[0] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k); + resLevel->by1[0] = resLevel->y1; + resLevel->bx0[1] = resLevel->x0; + resLevel->by0[1] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k); + resLevel->bx1[1] = resLevel->x1; + resLevel->by1[1] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k); + resLevel->bx0[2] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k); + resLevel->by0[2] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k); + resLevel->bx1[2] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k); + resLevel->by1[2] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k); + } + resLevel->precincts = (JPXPrecinct *)gmallocn(1, sizeof(JPXPrecinct)); + for (pre = 0; pre < 1; ++pre) { + precinct = &resLevel->precincts[pre]; + precinct->x0 = resLevel->x0; + precinct->y0 = resLevel->y0; + precinct->x1 = resLevel->x1; + precinct->y1 = resLevel->y1; + nSBs = r == 0 ? 1 : 3; + precinct->subbands = + (JPXSubband *)gmallocn(nSBs, sizeof(JPXSubband)); + for (sb = 0; sb < nSBs; ++sb) { + subband = &precinct->subbands[sb]; + subband->x0 = resLevel->bx0[sb]; + subband->y0 = resLevel->by0[sb]; + subband->x1 = resLevel->bx1[sb]; + subband->y1 = resLevel->by1[sb]; + subband->nXCBs = jpxCeilDivPow2(subband->x1, + tileComp->codeBlockW) + - jpxFloorDivPow2(subband->x0, + tileComp->codeBlockW); + subband->nYCBs = jpxCeilDivPow2(subband->y1, + tileComp->codeBlockH) + - jpxFloorDivPow2(subband->y0, + tileComp->codeBlockH); + n = subband->nXCBs > subband->nYCBs ? subband->nXCBs + : subband->nYCBs; + for (subband->maxTTLevel = 0, --n; + n; + ++subband->maxTTLevel, n >>= 1) ; + n = 0; + for (level = subband->maxTTLevel; level >= 0; --level) { + nx = jpxCeilDivPow2(subband->nXCBs, level); + ny = jpxCeilDivPow2(subband->nYCBs, level); + n += nx * ny; + } + subband->inclusion = + (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode)); + subband->zeroBitPlane = + (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode)); + for (k = 0; k < n; ++k) { + subband->inclusion[k].finished = gFalse; + subband->inclusion[k].val = 0; + subband->zeroBitPlane[k].finished = gFalse; + subband->zeroBitPlane[k].val = 0; + } + subband->cbs = (JPXCodeBlock *)gmallocn(subband->nXCBs * + subband->nYCBs, + sizeof(JPXCodeBlock)); + sbx0 = jpxFloorDivPow2(subband->x0, tileComp->codeBlockW); + sby0 = jpxFloorDivPow2(subband->y0, tileComp->codeBlockH); + cb = subband->cbs; + for (cbY = 0; cbY < subband->nYCBs; ++cbY) { + for (cbX = 0; cbX < subband->nXCBs; ++cbX) { + cb->x0 = (sbx0 + cbX) << tileComp->codeBlockW; + cb->x1 = cb->x0 + tileComp->cbW; + if (subband->x0 > cb->x0) { + cb->x0 = subband->x0; + } + if (subband->x1 < cb->x1) { + cb->x1 = subband->x1; + } + cb->y0 = (sby0 + cbY) << tileComp->codeBlockH; + cb->y1 = cb->y0 + tileComp->cbH; + if (subband->y0 > cb->y0) { + cb->y0 = subband->y0; + } + if (subband->y1 < cb->y1) { + cb->y1 = subband->y1; + } + cb->seen = gFalse; + cb->lBlock = 3; + cb->nextPass = jpxPassCleanup; + cb->nZeroBitPlanes = 0; + cb->coeffs = + (JPXCoeff *)gmallocn((1 << (tileComp->codeBlockW + + tileComp->codeBlockH)), + sizeof(JPXCoeff)); + for (cbi = 0; + cbi < (Guint)(1 << (tileComp->codeBlockW + + tileComp->codeBlockH)); + ++cbi) { + cb->coeffs[cbi].flags = 0; + cb->coeffs[cbi].len = 0; + cb->coeffs[cbi].mag = 0; + } + cb->arithDecoder = NULL; + cb->stats = NULL; + ++cb; + } + } + } + } + } + } + } + + return readTilePartData(tileIdx, tilePartLen, tilePartToEOC); +} + +GBool JPXStream::readTilePartData(Guint tileIdx, + Guint tilePartLen, GBool tilePartToEOC) { + JPXTile *tile; + JPXTileComp *tileComp; + JPXResLevel *resLevel; + JPXPrecinct *precinct; + JPXSubband *subband; + JPXCodeBlock *cb; + Guint ttVal; + Guint bits, cbX, cbY, nx, ny, i, j, n, sb; + int level; + + tile = &img.tiles[tileIdx]; + + // read all packets from this tile-part + while (1) { + if (tilePartToEOC) { + //~ peek for an EOC marker + cover(93); + } else if (tilePartLen == 0) { + break; + } + + tileComp = &tile->tileComps[tile->comp]; + resLevel = &tileComp->resLevels[tile->res]; + precinct = &resLevel->precincts[tile->precinct]; + + //----- packet header + + // setup + startBitBuf(tilePartLen); + + // zero-length flag + if (!readBits(1, &bits)) { + goto err; + } + if (!bits) { + // packet is empty -- clear all code-block inclusion flags + cover(45); + for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) { + subband = &precinct->subbands[sb]; + for (cbY = 0; cbY < subband->nYCBs; ++cbY) { + for (cbX = 0; cbX < subband->nXCBs; ++cbX) { + cb = &subband->cbs[cbY * subband->nXCBs + cbX]; + cb->included = gFalse; + } + } + } + } else { + + for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) { + subband = &precinct->subbands[sb]; + for (cbY = 0; cbY < subband->nYCBs; ++cbY) { + for (cbX = 0; cbX < subband->nXCBs; ++cbX) { + cb = &subband->cbs[cbY * subband->nXCBs + cbX]; + + // skip code-blocks with no coefficients + if (cb->x0 >= cb->x1 || cb->y0 >= cb->y1) { + cover(46); + cb->included = gFalse; + continue; + } + + // code-block inclusion + if (cb->seen) { + cover(47); + if (!readBits(1, &cb->included)) { + goto err; + } + } else { + cover(48); + ttVal = 0; + i = 0; + for (level = subband->maxTTLevel; level >= 0; --level) { + nx = jpxCeilDivPow2(subband->nXCBs, level); + ny = jpxCeilDivPow2(subband->nYCBs, level); + j = i + (cbY >> level) * nx + (cbX >> level); + if (!subband->inclusion[j].finished && + !subband->inclusion[j].val) { + subband->inclusion[j].val = ttVal; + } else { + ttVal = subband->inclusion[j].val; + } + while (!subband->inclusion[j].finished && + ttVal <= tile->layer) { + if (!readBits(1, &bits)) { + goto err; + } + if (bits == 1) { + subband->inclusion[j].finished = gTrue; + } else { + ++ttVal; + } + } + subband->inclusion[j].val = ttVal; + if (ttVal > tile->layer) { + break; + } + i += nx * ny; + } + cb->included = level < 0; + } + + if (cb->included) { + cover(49); + + // zero bit-plane count + if (!cb->seen) { + cover(50); + ttVal = 0; + i = 0; + for (level = subband->maxTTLevel; level >= 0; --level) { + nx = jpxCeilDivPow2(subband->nXCBs, level); + ny = jpxCeilDivPow2(subband->nYCBs, level); + j = i + (cbY >> level) * nx + (cbX >> level); + if (!subband->zeroBitPlane[j].finished && + !subband->zeroBitPlane[j].val) { + subband->zeroBitPlane[j].val = ttVal; + } else { + ttVal = subband->zeroBitPlane[j].val; + } + while (!subband->zeroBitPlane[j].finished) { + if (!readBits(1, &bits)) { + goto err; + } + if (bits == 1) { + subband->zeroBitPlane[j].finished = gTrue; + } else { + ++ttVal; + } + } + subband->zeroBitPlane[j].val = ttVal; + i += nx * ny; + } + cb->nZeroBitPlanes = ttVal; + } + + // number of coding passes + if (!readBits(1, &bits)) { + goto err; + } + if (bits == 0) { + cover(51); + cb->nCodingPasses = 1; + } else { + if (!readBits(1, &bits)) { + goto err; + } + if (bits == 0) { + cover(52); + cb->nCodingPasses = 2; + } else { + cover(53); + if (!readBits(2, &bits)) { + goto err; + } + if (bits < 3) { + cover(54); + cb->nCodingPasses = 3 + bits; + } else { + cover(55); + if (!readBits(5, &bits)) { + goto err; + } + if (bits < 31) { + cover(56); + cb->nCodingPasses = 6 + bits; + } else { + cover(57); + if (!readBits(7, &bits)) { + goto err; + } + cb->nCodingPasses = 37 + bits; + } + } + } + } + + // update Lblock + while (1) { + if (!readBits(1, &bits)) { + goto err; + } + if (!bits) { + break; + } + ++cb->lBlock; + } + + // length of compressed data + //~ deal with multiple codeword segments + for (n = cb->lBlock, i = cb->nCodingPasses >> 1; + i; + ++n, i >>= 1) ; + if (!readBits(n, &cb->dataLen)) { + goto err; + } + } + } + } + } + } + tilePartLen = finishBitBuf(); + + //----- packet data + + for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) { + subband = &precinct->subbands[sb]; + for (cbY = 0; cbY < subband->nYCBs; ++cbY) { + for (cbX = 0; cbX < subband->nXCBs; ++cbX) { + cb = &subband->cbs[cbY * subband->nXCBs + cbX]; + if (cb->included) { + if (!readCodeBlockData(tileComp, resLevel, precinct, subband, + tile->res, sb, cb)) { + return gFalse; + } + tilePartLen -= cb->dataLen; + cb->seen = gTrue; + } + } + } + } + + //----- next packet + + switch (tile->progOrder) { + case 0: // layer, resolution level, component, precinct + cover(58); + if (++tile->comp == img.nComps) { + tile->comp = 0; + if (++tile->res == tile->maxNDecompLevels + 1) { + tile->res = 0; + if (++tile->layer == tile->nLayers) { + tile->layer = 0; + } + } + } + break; + case 1: // resolution level, layer, component, precinct + cover(59); + if (++tile->comp == img.nComps) { + tile->comp = 0; + if (++tile->layer == tile->nLayers) { + tile->layer = 0; + if (++tile->res == tile->maxNDecompLevels + 1) { + tile->res = 0; + } + } + } + break; + case 2: // resolution level, precinct, component, layer + //~ this isn't correct -- see B.12.1.3 + cover(60); + if (++tile->layer == tile->nLayers) { + tile->layer = 0; + if (++tile->comp == img.nComps) { + tile->comp = 0; + if (++tile->res == tile->maxNDecompLevels + 1) { + tile->res = 0; + } + } + } + break; + case 3: // precinct, component, resolution level, layer + //~ this isn't correct -- see B.12.1.4 + cover(61); + if (++tile->layer == tile->nLayers) { + tile->layer = 0; + if (++tile->res == tile->maxNDecompLevels + 1) { + tile->res = 0; + if (++tile->comp == img.nComps) { + tile->comp = 0; + } + } + } + break; + case 4: // component, precinct, resolution level, layer + //~ this isn't correct -- see B.12.1.5 + cover(62); + if (++tile->layer == tile->nLayers) { + tile->layer = 0; + if (++tile->res == tile->maxNDecompLevels + 1) { + tile->res = 0; + if (++tile->comp == img.nComps) { + tile->comp = 0; + } + } + } + break; + } + } + + return gTrue; + + err: + error(getPos(), "Error in JPX stream"); + return gFalse; +} + +GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, + JPXResLevel * /*resLevel*/, + JPXPrecinct * /*precinct*/, + JPXSubband * /*subband*/, + Guint res, Guint sb, + JPXCodeBlock *cb) { + JPXCoeff *coeff0, *coeff1, *coeff; + Guint horiz, vert, diag, all, cx, xorBit; + int horizSign, vertSign; + Guint i, x, y0, y1, y2; + + if (cb->arithDecoder) { + cover(63); + cb->arithDecoder->restart(cb->dataLen); + } else { + cover(64); + cb->arithDecoder = new JArithmeticDecoder(); + cb->arithDecoder->setStream(str, cb->dataLen); + cb->arithDecoder->start(); + cb->stats = new JArithmeticDecoderStats(jpxNContexts); + cb->stats->setEntry(jpxContextSigProp, 4, 0); + cb->stats->setEntry(jpxContextRunLength, 3, 0); + cb->stats->setEntry(jpxContextUniform, 46, 0); + } + + for (i = 0; i < cb->nCodingPasses; ++i) { + switch (cb->nextPass) { + + //----- significance propagation pass + case jpxPassSigProp: + cover(65); + for (y0 = cb->y0, coeff0 = cb->coeffs; + y0 < cb->y1; + y0 += 4, coeff0 += 4 << tileComp->codeBlockW) { + for (x = cb->x0, coeff1 = coeff0; + x < cb->x1; + ++x, ++coeff1) { + for (y1 = 0, coeff = coeff1; + y1 < 4 && y0+y1 < cb->y1; + ++y1, coeff += tileComp->cbW) { + if (!(coeff->flags & jpxCoeffSignificant)) { + horiz = vert = diag = 0; + horizSign = vertSign = 2; + if (x > cb->x0) { + if (coeff[-1].flags & jpxCoeffSignificant) { + ++horiz; + horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1; + } + if (y0+y1 > cb->y0) { + diag += (coeff[-(int)tileComp->cbW - 1].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + diag += (coeff[tileComp->cbW - 1].flags + >> jpxCoeffSignificantB) & 1; + } + } + if (x < cb->x1 - 1) { + if (coeff[1].flags & jpxCoeffSignificant) { + ++horiz; + horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1; + } + if (y0+y1 > cb->y0) { + diag += (coeff[-(int)tileComp->cbW + 1].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + diag += (coeff[tileComp->cbW + 1].flags + >> jpxCoeffSignificantB) & 1; + } + } + if (y0+y1 > cb->y0) { + if (coeff[-(int)tileComp->cbW].flags & jpxCoeffSignificant) { + ++vert; + vertSign += (coeff[-(int)tileComp->cbW].flags & jpxCoeffSign) + ? -1 : 1; + } + } + if (y0+y1 < cb->y1 - 1) { + if (coeff[tileComp->cbW].flags & jpxCoeffSignificant) { + ++vert; + vertSign += (coeff[tileComp->cbW].flags & jpxCoeffSign) + ? -1 : 1; + } + } + cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb]; + if (cx != 0) { + if (cb->arithDecoder->decodeBit(cx, cb->stats)) { + coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef; + coeff->mag = (coeff->mag << 1) | 1; + cx = signContext[horizSign][vertSign][0]; + xorBit = signContext[horizSign][vertSign][1]; + if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { + coeff->flags |= jpxCoeffSign; + } + } + ++coeff->len; + coeff->flags |= jpxCoeffTouched; + } + } + } + } + } + ++cb->nextPass; + break; + + //----- magnitude refinement pass + case jpxPassMagRef: + cover(66); + for (y0 = cb->y0, coeff0 = cb->coeffs; + y0 < cb->y1; + y0 += 4, coeff0 += 4 << tileComp->codeBlockW) { + for (x = cb->x0, coeff1 = coeff0; + x < cb->x1; + ++x, ++coeff1) { + for (y1 = 0, coeff = coeff1; + y1 < 4 && y0+y1 < cb->y1; + ++y1, coeff += tileComp->cbW) { + if ((coeff->flags & jpxCoeffSignificant) && + !(coeff->flags & jpxCoeffTouched)) { + if (coeff->flags & jpxCoeffFirstMagRef) { + all = 0; + if (x > cb->x0) { + all += (coeff[-1].flags >> jpxCoeffSignificantB) & 1; + if (y0+y1 > cb->y0) { + all += (coeff[-(int)tileComp->cbW - 1].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + all += (coeff[tileComp->cbW - 1].flags + >> jpxCoeffSignificantB) & 1; + } + } + if (x < cb->x1 - 1) { + all += (coeff[1].flags >> jpxCoeffSignificantB) & 1; + if (y0+y1 > cb->y0) { + all += (coeff[-(int)tileComp->cbW + 1].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + all += (coeff[tileComp->cbW + 1].flags + >> jpxCoeffSignificantB) & 1; + } + } + if (y0+y1 > cb->y0) { + all += (coeff[-(int)tileComp->cbW].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + all += (coeff[tileComp->cbW].flags + >> jpxCoeffSignificantB) & 1; + } + cx = all ? 15 : 14; + } else { + cx = 16; + } + coeff->mag = (coeff->mag << 1) | + cb->arithDecoder->decodeBit(cx, cb->stats); + ++coeff->len; + coeff->flags |= jpxCoeffTouched; + coeff->flags &= ~jpxCoeffFirstMagRef; + } + } + } + } + ++cb->nextPass; + break; + + //----- cleanup pass + case jpxPassCleanup: + cover(67); + for (y0 = cb->y0, coeff0 = cb->coeffs; + y0 < cb->y1; + y0 += 4, coeff0 += 4 << tileComp->codeBlockW) { + for (x = cb->x0, coeff1 = coeff0; + x < cb->x1; + ++x, ++coeff1) { + y1 = 0; + if (y0 + 3 < cb->y1 && + !(coeff1->flags & jpxCoeffTouched) && + !(coeff1[tileComp->cbW].flags & jpxCoeffTouched) && + !(coeff1[2 * tileComp->cbW].flags & jpxCoeffTouched) && + !(coeff1[3 * tileComp->cbW].flags & jpxCoeffTouched) && + (x == cb->x0 || y0 == cb->y0 || + !(coeff1[-(int)tileComp->cbW - 1].flags + & jpxCoeffSignificant)) && + (y0 == cb->y0 || + !(coeff1[-(int)tileComp->cbW].flags + & jpxCoeffSignificant)) && + (x == cb->x1 - 1 || y0 == cb->y0 || + !(coeff1[-(int)tileComp->cbW + 1].flags + & jpxCoeffSignificant)) && + (x == cb->x0 || + (!(coeff1[-1].flags & jpxCoeffSignificant) && + !(coeff1[tileComp->cbW - 1].flags + & jpxCoeffSignificant) && + !(coeff1[2 * tileComp->cbW - 1].flags + & jpxCoeffSignificant) && + !(coeff1[3 * tileComp->cbW - 1].flags + & jpxCoeffSignificant))) && + (x == cb->x1 - 1 || + (!(coeff1[1].flags & jpxCoeffSignificant) && + !(coeff1[tileComp->cbW + 1].flags + & jpxCoeffSignificant) && + !(coeff1[2 * tileComp->cbW + 1].flags + & jpxCoeffSignificant) && + !(coeff1[3 * tileComp->cbW + 1].flags + & jpxCoeffSignificant))) && + (x == cb->x0 || y0+4 == cb->y1 || + !(coeff1[4 * tileComp->cbW - 1].flags & jpxCoeffSignificant)) && + (y0+4 == cb->y1 || + !(coeff1[4 * tileComp->cbW].flags & jpxCoeffSignificant)) && + (x == cb->x1 - 1 || y0+4 == cb->y1 || + !(coeff1[4 * tileComp->cbW + 1].flags + & jpxCoeffSignificant))) { + if (cb->arithDecoder->decodeBit(jpxContextRunLength, cb->stats)) { + y1 = cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats); + y1 = (y1 << 1) | + cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats); + for (y2 = 0, coeff = coeff1; + y2 < y1; + ++y2, coeff += tileComp->cbW) { + ++coeff->len; + } + coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef; + coeff->mag = (coeff->mag << 1) | 1; + ++coeff->len; + cx = signContext[2][2][0]; + xorBit = signContext[2][2][1]; + if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { + coeff->flags |= jpxCoeffSign; + } + ++y1; + } else { + for (y1 = 0, coeff = coeff1; + y1 < 4; + ++y1, coeff += tileComp->cbW) { + ++coeff->len; + } + y1 = 4; + } + } + for (coeff = &coeff1[y1 << tileComp->codeBlockW]; + y1 < 4 && y0 + y1 < cb->y1; + ++y1, coeff += tileComp->cbW) { + if (!(coeff->flags & jpxCoeffTouched)) { + horiz = vert = diag = 0; + horizSign = vertSign = 2; + if (x > cb->x0) { + if (coeff[-1].flags & jpxCoeffSignificant) { + ++horiz; + horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1; + } + if (y0+y1 > cb->y0) { + diag += (coeff[-(int)tileComp->cbW - 1].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + diag += (coeff[tileComp->cbW - 1].flags + >> jpxCoeffSignificantB) & 1; + } + } + if (x < cb->x1 - 1) { + if (coeff[1].flags & jpxCoeffSignificant) { + ++horiz; + horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1; + } + if (y0+y1 > cb->y0) { + diag += (coeff[-(int)tileComp->cbW + 1].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + diag += (coeff[tileComp->cbW + 1].flags + >> jpxCoeffSignificantB) & 1; + } + } + if (y0+y1 > cb->y0) { + if (coeff[-(int)tileComp->cbW].flags & jpxCoeffSignificant) { + ++vert; + vertSign += (coeff[-(int)tileComp->cbW].flags & jpxCoeffSign) + ? -1 : 1; + } + } + if (y0+y1 < cb->y1 - 1) { + if (coeff[tileComp->cbW].flags & jpxCoeffSignificant) { + ++vert; + vertSign += (coeff[tileComp->cbW].flags & jpxCoeffSign) + ? -1 : 1; + } + } + cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb]; + if (cb->arithDecoder->decodeBit(cx, cb->stats)) { + coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef; + coeff->mag = (coeff->mag << 1) | 1; + cx = signContext[horizSign][vertSign][0]; + xorBit = signContext[horizSign][vertSign][1]; + if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { + coeff->flags |= jpxCoeffSign; + } + } + ++coeff->len; + } else { + coeff->flags &= ~jpxCoeffTouched; + } + } + } + } + cb->nextPass = jpxPassSigProp; + break; + } + } + + cb->arithDecoder->cleanup(); + return gTrue; +} + +// Inverse quantization, and wavelet transform (IDWT). This also does +// the initial shift to convert to fixed point format. +void JPXStream::inverseTransform(JPXTileComp *tileComp) { + JPXResLevel *resLevel; + JPXPrecinct *precinct; + JPXSubband *subband; + JPXCodeBlock *cb; + JPXCoeff *coeff0, *coeff; + Guint qStyle, guard, eps, shift; + int shift2; + double mu; + int val; + int *dataPtr; + Guint nx0, ny0, nx1, ny1; + Guint r, cbX, cbY, x, y; + + cover(68); + + //----- (NL)LL subband (resolution level 0) + + resLevel = &tileComp->resLevels[0]; + precinct = &resLevel->precincts[0]; + subband = &precinct->subbands[0]; + + // i-quant parameters + qStyle = tileComp->quantStyle & 0x1f; + guard = (tileComp->quantStyle >> 5) & 7; + if (qStyle == 0) { + cover(69); + eps = (tileComp->quantSteps[0] >> 3) & 0x1f; + shift = guard + eps - 1; + mu = 0; // make gcc happy + } else { + cover(70); + shift = guard - 1 + tileComp->prec; + mu = (double)(0x800 + (tileComp->quantSteps[0] & 0x7ff)) / 2048.0; + } + if (tileComp->transform == 0) { + cover(71); + shift += fracBits; + } + + // copy (NL)LL into the upper-left corner of the data array, doing + // the fixed point adjustment and dequantization along the way + cb = subband->cbs; + for (cbY = 0; cbY < subband->nYCBs; ++cbY) { + for (cbX = 0; cbX < subband->nXCBs; ++cbX) { + for (y = cb->y0, coeff0 = cb->coeffs; + y < cb->y1; + ++y, coeff0 += tileComp->cbW) { + dataPtr = &tileComp->data[(y - subband->y0) + * (tileComp->x1 - tileComp->x0) + + (cb->x0 - subband->x0)]; + for (x = cb->x0, coeff = coeff0; x < cb->x1; ++x, ++coeff) { + val = (int)coeff->mag; + if (val != 0) { + shift2 = shift - (cb->nZeroBitPlanes + coeff->len); + if (shift2 > 0) { + cover(94); + val = (val << shift2) + (1 << (shift2 - 1)); + } else { + cover(95); + val >>= -shift2; + } + if (qStyle == 0) { + cover(96); + if (tileComp->transform == 0) { + cover(97); + val &= -1 << fracBits; + } + } else { + cover(98); + val = (int)((double)val * mu); + } + if (coeff->flags & jpxCoeffSign) { + cover(99); + val = -val; + } + } + *dataPtr++ = val; + } + } + ++cb; + } + } + + //----- IDWT for each level + + for (r = 1; r <= tileComp->nDecompLevels; ++r) { + resLevel = &tileComp->resLevels[r]; + + // (n)LL is already in the upper-left corner of the + // tile-component data array -- interleave with (n)HL/LH/HH + // and inverse transform to get (n-1)LL, which will be stored + // in the upper-left corner of the tile-component data array + if (r == tileComp->nDecompLevels) { + cover(72); + nx0 = tileComp->x0; + ny0 = tileComp->y0; + nx1 = tileComp->x1; + ny1 = tileComp->y1; + } else { + cover(73); + nx0 = tileComp->resLevels[r+1].x0; + ny0 = tileComp->resLevels[r+1].y0; + nx1 = tileComp->resLevels[r+1].x1; + ny1 = tileComp->resLevels[r+1].y1; + } + inverseTransformLevel(tileComp, r, resLevel, nx0, ny0, nx1, ny1); + } +} + +// Do one level of the inverse transform: +// - take (n)LL from the tile-component data array +// - take (n)HL/LH/HH from +// - leave the resulting (n-1)LL in the tile-component data array +void JPXStream::inverseTransformLevel(JPXTileComp *tileComp, + Guint r, JPXResLevel *resLevel, + Guint nx0, Guint ny0, + Guint nx1, Guint ny1) { + JPXPrecinct *precinct; + JPXSubband *subband; + JPXCodeBlock *cb; + JPXCoeff *coeff0, *coeff; + Guint qStyle, guard, eps, shift, t; + int shift2; + double mu; + int val; + int *dataPtr; + Guint xo, yo; + Guint x, y, sb, cbX, cbY; + int xx, yy; + + //----- interleave + + // spread out LL + for (yy = resLevel->y1 - 1; yy >= (int)resLevel->y0; --yy) { + for (xx = resLevel->x1 - 1; xx >= (int)resLevel->x0; --xx) { + tileComp->data[(2 * yy - ny0) * (tileComp->x1 - tileComp->x0) + + (2 * xx - nx0)] = + tileComp->data[(yy - resLevel->y0) * (tileComp->x1 - tileComp->x0) + + (xx - resLevel->x0)]; + } + } + + // i-quant parameters + qStyle = tileComp->quantStyle & 0x1f; + guard = (tileComp->quantStyle >> 5) & 7; + + // interleave HL/LH/HH + precinct = &resLevel->precincts[0]; + for (sb = 0; sb < 3; ++sb) { + + // i-quant parameters + if (qStyle == 0) { + cover(100); + eps = (tileComp->quantSteps[3*r - 2 + sb] >> 3) & 0x1f; + shift = guard + eps - 1; + mu = 0; // make gcc happy + } else { + cover(101); + shift = guard + tileComp->prec; + if (sb == 2) { + cover(102); + ++shift; + } + t = tileComp->quantSteps[qStyle == 1 ? 0 : (3*r - 2 + sb)]; + mu = (double)(0x800 + (t & 0x7ff)) / 2048.0; + } + if (tileComp->transform == 0) { + cover(103); + shift += fracBits; + } + + // copy the subband coefficients into the data array, doing the + // fixed point adjustment and dequantization along the way + xo = (sb & 1) ? 0 : 1; + yo = (sb > 0) ? 1 : 0; + subband = &precinct->subbands[sb]; + cb = subband->cbs; + for (cbY = 0; cbY < subband->nYCBs; ++cbY) { + for (cbX = 0; cbX < subband->nXCBs; ++cbX) { + for (y = cb->y0, coeff0 = cb->coeffs; + y < cb->y1; + ++y, coeff0 += tileComp->cbW) { + dataPtr = &tileComp->data[(2 * y + yo - ny0) + * (tileComp->x1 - tileComp->x0) + + (2 * cb->x0 + xo - nx0)]; + for (x = cb->x0, coeff = coeff0; x < cb->x1; ++x, ++coeff) { + val = (int)coeff->mag; + if (val != 0) { + shift2 = shift - (cb->nZeroBitPlanes + coeff->len); + if (shift2 > 0) { + cover(74); + val = (val << shift2) + (1 << (shift2 - 1)); + } else { + cover(75); + val >>= -shift2; + } + if (qStyle == 0) { + cover(76); + if (tileComp->transform == 0) { + val &= -1 << fracBits; + } + } else { + cover(77); + val = (int)((double)val * mu); + } + if (coeff->flags & jpxCoeffSign) { + cover(78); + val = -val; + } + } + *dataPtr = val; + dataPtr += 2; + } + } + ++cb; + } + } + } + + //----- horizontal (row) transforms + dataPtr = tileComp->data; + for (y = 0; y < ny1 - ny0; ++y) { + inverseTransform1D(tileComp, dataPtr, 1, nx0, nx1); + dataPtr += tileComp->x1 - tileComp->x0; + } + + //----- vertical (column) transforms + dataPtr = tileComp->data; + for (x = 0; x < nx1 - nx0; ++x) { + inverseTransform1D(tileComp, dataPtr, + tileComp->x1 - tileComp->x0, ny0, ny1); + ++dataPtr; + } +} + +void JPXStream::inverseTransform1D(JPXTileComp *tileComp, + int *data, Guint stride, + Guint i0, Guint i1) { + int *buf; + Guint offset, end, i; + + //----- special case for length = 1 + if (i1 - i0 == 1) { + cover(79); + if (i0 & 1) { + cover(104); + *data >>= 1; + } + + } else { + cover(80); + + // choose an offset: this makes even buf[] indexes correspond to + // odd values of i, and vice versa + offset = 3 + (i0 & 1); + end = offset + i1 - i0; + + //----- gather + buf = tileComp->buf; + for (i = 0; i < i1 - i0; ++i) { + buf[offset + i] = data[i * stride]; + } + + //----- extend right + buf[end] = buf[end - 2]; + if (i1 - i0 == 2) { + cover(81); + buf[end+1] = buf[offset + 1]; + buf[end+2] = buf[offset]; + buf[end+3] = buf[offset + 1]; + } else { + cover(82); + buf[end+1] = buf[end - 3]; + if (i1 - i0 == 3) { + cover(105); + buf[end+2] = buf[offset + 1]; + buf[end+3] = buf[offset + 2]; + } else { + cover(106); + buf[end+2] = buf[end - 4]; + if (i1 - i0 == 4) { + cover(107); + buf[end+3] = buf[offset + 1]; + } else { + cover(108); + buf[end+3] = buf[end - 5]; + } + } + } + + //----- extend left + buf[offset - 1] = buf[offset + 1]; + buf[offset - 2] = buf[offset + 2]; + buf[offset - 3] = buf[offset + 3]; + if (offset == 4) { + cover(83); + buf[0] = buf[offset + 4]; + } + + //----- 9-7 irreversible filter + + if (tileComp->transform == 0) { + cover(84); + // step 1 (even) + for (i = 1; i <= end + 2; i += 2) { + buf[i] = (int)(idwtKappa * buf[i]); + } + // step 2 (odd) + for (i = 0; i <= end + 3; i += 2) { + buf[i] = (int)(idwtIKappa * buf[i]); + } + // step 3 (even) + for (i = 1; i <= end + 2; i += 2) { + buf[i] = (int)(buf[i] - idwtDelta * (buf[i-1] + buf[i+1])); + } + // step 4 (odd) + for (i = 2; i <= end + 1; i += 2) { + buf[i] = (int)(buf[i] - idwtGamma * (buf[i-1] + buf[i+1])); + } + // step 5 (even) + for (i = 3; i <= end; i += 2) { + buf[i] = (int)(buf[i] - idwtBeta * (buf[i-1] + buf[i+1])); + } + // step 6 (odd) + for (i = 4; i <= end - 1; i += 2) { + buf[i] = (int)(buf[i] - idwtAlpha * (buf[i-1] + buf[i+1])); + } + + //----- 5-3 reversible filter + + } else { + cover(85); + // step 1 (even) + for (i = 3; i <= end; i += 2) { + buf[i] -= (buf[i-1] + buf[i+1] + 2) >> 2; + } + // step 2 (odd) + for (i = 4; i < end; i += 2) { + buf[i] += (buf[i-1] + buf[i+1]) >> 1; + } + } + + //----- scatter + for (i = 0; i < i1 - i0; ++i) { + data[i * stride] = buf[offset + i]; + } + } +} + +// Inverse multi-component transform and DC level shift. This also +// converts fixed point samples back to integers. +GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) { + JPXTileComp *tileComp; + int coeff, d0, d1, d2, t, minVal, maxVal, zeroVal; + int *dataPtr; + Guint j, comp, x, y; + + //----- inverse multi-component transform + + if (tile->multiComp == 1) { + cover(86); + if (img.nComps < 3 || + tile->tileComps[0].hSep != tile->tileComps[1].hSep || + tile->tileComps[0].vSep != tile->tileComps[1].vSep || + tile->tileComps[1].hSep != tile->tileComps[2].hSep || + tile->tileComps[1].vSep != tile->tileComps[2].vSep) { + return gFalse; + } + + // inverse irreversible multiple component transform + if (tile->tileComps[0].transform == 0) { + cover(87); + j = 0; + for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) { + for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) { + d0 = tile->tileComps[0].data[j]; + d1 = tile->tileComps[1].data[j]; + d2 = tile->tileComps[2].data[j]; + tile->tileComps[0].data[j] = (int)(d0 + 1.402 * d2 + 0.5); + tile->tileComps[1].data[j] = + (int)(d0 - 0.34413 * d1 - 0.71414 * d2 + 0.5); + tile->tileComps[2].data[j] = (int)(d0 + 1.772 * d1 + 0.5); + ++j; + } + } + + // inverse reversible multiple component transform + } else { + cover(88); + j = 0; + for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) { + for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) { + d0 = tile->tileComps[0].data[j]; + d1 = tile->tileComps[1].data[j]; + d2 = tile->tileComps[2].data[j]; + tile->tileComps[1].data[j] = t = d0 - ((d2 + d1) >> 2); + tile->tileComps[0].data[j] = d2 + t; + tile->tileComps[2].data[j] = d1 + t; + ++j; + } + } + } + } + + //----- DC level shift + for (comp = 0; comp < img.nComps; ++comp) { + tileComp = &tile->tileComps[comp]; + + // signed: clip + if (tileComp->sgned) { + cover(89); + minVal = -(1 << (tileComp->prec - 1)); + maxVal = (1 << (tileComp->prec - 1)) - 1; + dataPtr = tileComp->data; + for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) { + for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) { + coeff = *dataPtr; + if (tileComp->transform == 0) { + cover(109); + coeff >>= fracBits; + } + if (coeff < minVal) { + cover(110); + coeff = minVal; + } else if (coeff > maxVal) { + cover(111); + coeff = maxVal; + } + *dataPtr++ = coeff; + } + } + + // unsigned: inverse DC level shift and clip + } else { + cover(90); + maxVal = (1 << tileComp->prec) - 1; + zeroVal = 1 << (tileComp->prec - 1); + dataPtr = tileComp->data; + for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) { + for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) { + coeff = *dataPtr; + if (tileComp->transform == 0) { + cover(112); + coeff >>= fracBits; + } + coeff += zeroVal; + if (coeff < 0) { + cover(113); + coeff = 0; + } else if (coeff > maxVal) { + cover(114); + coeff = maxVal; + } + *dataPtr++ = coeff; + } + } + } + } + + return gTrue; +} + +GBool JPXStream::readBoxHdr(Guint *boxType, Guint *boxLen, Guint *dataLen) { + Guint len, lenH; + + if (!readULong(&len) || + !readULong(boxType)) { + return gFalse; + } + if (len == 1) { + if (!readULong(&lenH) || !readULong(&len)) { + return gFalse; + } + if (lenH) { + error(getPos(), "JPX stream contains a box larger than 2^32 bytes"); + return gFalse; + } + *boxLen = len; + *dataLen = len - 16; + } else if (len == 0) { + *boxLen = 0; + *dataLen = 0; + } else { + *boxLen = len; + *dataLen = len - 8; + } + return gTrue; +} + +int JPXStream::readMarkerHdr(int *segType, Guint *segLen) { + int c; + + do { + do { + if ((c = str->getChar()) == EOF) { + return gFalse; + } + } while (c != 0xff); + do { + if ((c = str->getChar()) == EOF) { + return gFalse; + } + } while (c == 0xff); + } while (c == 0x00); + *segType = c; + if ((c >= 0x30 && c <= 0x3f) || + c == 0x4f || c == 0x92 || c == 0x93 || c == 0xd9) { + *segLen = 0; + return gTrue; + } + return readUWord(segLen); +} + +GBool JPXStream::readUByte(Guint *x) { + int c0; + + if ((c0 = str->getChar()) == EOF) { + return gFalse; + } + *x = (Guint)c0; + return gTrue; +} + +GBool JPXStream::readByte(int *x) { + int c0; + + if ((c0 = str->getChar()) == EOF) { + return gFalse; + } + *x = c0; + if (c0 & 0x80) { + *x |= -1 - 0xff; + } + return gTrue; +} + +GBool JPXStream::readUWord(Guint *x) { + int c0, c1; + + if ((c0 = str->getChar()) == EOF || + (c1 = str->getChar()) == EOF) { + return gFalse; + } + *x = (Guint)((c0 << 8) | c1); + return gTrue; +} + +GBool JPXStream::readULong(Guint *x) { + int c0, c1, c2, c3; + + if ((c0 = str->getChar()) == EOF || + (c1 = str->getChar()) == EOF || + (c2 = str->getChar()) == EOF || + (c3 = str->getChar()) == EOF) { + return gFalse; + } + *x = (Guint)((c0 << 24) | (c1 << 16) | (c2 << 8) | c3); + return gTrue; +} + +GBool JPXStream::readNBytes(int nBytes, GBool signd, int *x) { + int y, c, i; + + y = 0; + for (i = 0; i < nBytes; ++i) { + if ((c = str->getChar()) == EOF) { + return gFalse; + } + y = (y << 8) + c; + } + if (signd) { + if (y & (1 << (8 * nBytes - 1))) { + y |= -1 << (8 * nBytes); + } + } + *x = y; + return gTrue; +} + +GBool JPXStream::readBits(int nBits, Guint *x) { + int c; + + while (bitBufLen < nBits) { + if (byteCount == 0 || (c = str->getChar()) == EOF) { + return gFalse; + } + --byteCount; + if (bitBufSkip) { + bitBuf = (bitBuf << 7) | (c & 0x7f); + bitBufLen += 7; + } else { + bitBuf = (bitBuf << 8) | (c & 0xff); + bitBufLen += 8; + } + bitBufSkip = c == 0xff; + } + *x = (bitBuf >> (bitBufLen - nBits)) & ((1 << nBits) - 1); + bitBufLen -= nBits; + return gTrue; +} + +void JPXStream::startBitBuf(Guint byteCountA) { + bitBufLen = 0; + bitBufSkip = gFalse; + byteCount = byteCountA; +} + +Guint JPXStream::finishBitBuf() { + if (bitBufSkip) { + str->getChar(); + --byteCount; + } + return byteCount; +} diff --git a/kpdf/xpdf/xpdf/JPXStream.h b/kpdf/xpdf/xpdf/JPXStream.h new file mode 100644 index 00000000..e96e7d38 --- /dev/null +++ b/kpdf/xpdf/xpdf/JPXStream.h @@ -0,0 +1,351 @@ +//======================================================================== +// +// JPXStream.h +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef JPXSTREAM_H +#define JPXSTREAM_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "Object.h" +#include "Stream.h" + +class JArithmeticDecoder; +class JArithmeticDecoderStats; + +//------------------------------------------------------------------------ + +enum JPXColorSpaceType { + jpxCSBiLevel = 0, + jpxCSYCbCr1 = 1, + jpxCSYCbCr2 = 3, + jpxCSYCBCr3 = 4, + jpxCSPhotoYCC = 9, + jpxCSCMY = 11, + jpxCSCMYK = 12, + jpxCSYCCK = 13, + jpxCSCIELab = 14, + jpxCSsRGB = 16, + jpxCSGrayscale = 17, + jpxCSBiLevel2 = 18, + jpxCSCIEJab = 19, + jpxCSCISesRGB = 20, + jpxCSROMMRGB = 21, + jpxCSsRGBYCbCr = 22, + jpxCSYPbPr1125 = 23, + jpxCSYPbPr1250 = 24 +}; + +struct JPXColorSpecCIELab { + Guint rl, ol, ra, oa, rb, ob, il; +}; + +struct JPXColorSpecEnumerated { + JPXColorSpaceType type; // color space type + union { + JPXColorSpecCIELab cieLab; + }; +}; + +struct JPXColorSpec { + Guint meth; // method + int prec; // precedence + union { + JPXColorSpecEnumerated enumerated; + }; +}; + +//------------------------------------------------------------------------ + +struct JPXPalette { + Guint nEntries; // number of entries in the palette + Guint nComps; // number of components in each entry + Guint *bpc; // bits per component, for each component + int *c; // color data: + // c[i*nComps+j] = entry i, component j +}; + +//------------------------------------------------------------------------ + +struct JPXCompMap { + Guint nChannels; // number of channels + Guint *comp; // codestream components mapped to each channel + Guint *type; // 0 for direct use, 1 for palette mapping + Guint *pComp; // palette components to use +}; + +//------------------------------------------------------------------------ + +struct JPXChannelDefn { + Guint nChannels; // number of channels + Guint *idx; // channel indexes + Guint *type; // channel types + Guint *assoc; // channel associations +}; + +//------------------------------------------------------------------------ + +struct JPXTagTreeNode { + GBool finished; // true if this node is finished + Guint val; // current value +}; + +//------------------------------------------------------------------------ + +struct JPXCoeff { + Gushort flags; // flag bits + Gushort len; // number of significant bits in mag + Guint mag; // magnitude value +}; + +// coefficient flags +#define jpxCoeffSignificantB 0 +#define jpxCoeffTouchedB 1 +#define jpxCoeffFirstMagRefB 2 +#define jpxCoeffSignB 7 +#define jpxCoeffSignificant (1 << jpxCoeffSignificantB) +#define jpxCoeffTouched (1 << jpxCoeffTouchedB) +#define jpxCoeffFirstMagRef (1 << jpxCoeffFirstMagRefB) +#define jpxCoeffSign (1 << jpxCoeffSignB) + +//------------------------------------------------------------------------ + +struct JPXCodeBlock { + //----- size + Guint x0, y0, x1, y1; // bounds + + //----- persistent state + GBool seen; // true if this code-block has already + // been seen + Guint lBlock; // base number of bits used for pkt data length + Guint nextPass; // next coding pass + + //---- info from first packet + Guint nZeroBitPlanes; // number of zero bit planes + + //----- info for the current packet + Guint included; // code-block inclusion in this packet: + // 0=not included, 1=included + Guint nCodingPasses; // number of coding passes in this pkt + Guint dataLen; // pkt data length + + //----- coefficient data + JPXCoeff *coeffs; // the coefficients + JArithmeticDecoder // arithmetic decoder + *arithDecoder; + JArithmeticDecoderStats // arithmetic decoder stats + *stats; +}; + +//------------------------------------------------------------------------ + +struct JPXSubband { + //----- computed + Guint x0, y0, x1, y1; // bounds + Guint nXCBs, nYCBs; // number of code-blocks in the x and y + // directions + + //----- tag trees + Guint maxTTLevel; // max tag tree level + JPXTagTreeNode *inclusion; // inclusion tag tree for each subband + JPXTagTreeNode *zeroBitPlane; // zero-bit plane tag tree for each + // subband + + //----- children + JPXCodeBlock *cbs; // the code-blocks (len = nXCBs * nYCBs) +}; + +//------------------------------------------------------------------------ + +struct JPXPrecinct { + //----- computed + Guint x0, y0, x1, y1; // bounds of the precinct + + //----- children + JPXSubband *subbands; // the subbands +}; + +//------------------------------------------------------------------------ + +struct JPXResLevel { + //----- from the COD and COC segments (main and tile) + Guint precinctWidth; // log2(precinct width) + Guint precinctHeight; // log2(precinct height) + + //----- computed + Guint x0, y0, x1, y1; // bounds of the tile-comp (for this res level) + Guint bx0[3], by0[3], // subband bounds + bx1[3], by1[3]; + + //---- children + JPXPrecinct *precincts; // the precincts +}; + +//------------------------------------------------------------------------ + +struct JPXTileComp { + //----- from the SIZ segment + GBool sgned; // 1 for signed, 0 for unsigned + Guint prec; // precision, in bits + Guint hSep; // horizontal separation of samples + Guint vSep; // vertical separation of samples + + //----- from the COD and COC segments (main and tile) + Guint style; // coding style parameter (Scod / Scoc) + Guint nDecompLevels; // number of decomposition levels + Guint codeBlockW; // log2(code-block width) + Guint codeBlockH; // log2(code-block height) + Guint codeBlockStyle; // code-block style + Guint transform; // wavelet transformation + + //----- from the QCD and QCC segments (main and tile) + Guint quantStyle; // quantization style + Guint *quantSteps; // quantization step size for each subband + Guint nQuantSteps; // number of entries in quantSteps + + //----- computed + Guint x0, y0, x1, y1; // bounds of the tile-comp, in ref coords + Guint cbW; // code-block width + Guint cbH; // code-block height + + //----- image data + int *data; // the decoded image data + int *buf; // intermediate buffer for the inverse + // transform + + //----- children + JPXResLevel *resLevels; // the resolution levels + // (len = nDecompLevels + 1) +}; + +//------------------------------------------------------------------------ + +struct JPXTile { + //----- from the COD segments (main and tile) + Guint progOrder; // progression order + Guint nLayers; // number of layers + Guint multiComp; // multiple component transformation + + //----- computed + Guint x0, y0, x1, y1; // bounds of the tile, in ref coords + Guint maxNDecompLevels; // max number of decomposition levels used + // in any component in this tile + + //----- progression order loop counters + Guint comp; // component + Guint res; // resolution level + Guint precinct; // precinct + Guint layer; // layer + + //----- children + JPXTileComp *tileComps; // the tile-components (len = JPXImage.nComps) +}; + +//------------------------------------------------------------------------ + +struct JPXImage { + //----- from the SIZ segment + Guint xSize, ySize; // size of reference grid + Guint xOffset, yOffset; // image offset + Guint xTileSize, yTileSize; // size of tiles + Guint xTileOffset, // offset of first tile + yTileOffset; + Guint nComps; // number of components + + //----- computed + Guint nXTiles; // number of tiles in x direction + Guint nYTiles; // number of tiles in y direction + + //----- children + JPXTile *tiles; // the tiles (len = nXTiles * nYTiles) +}; + +//------------------------------------------------------------------------ + +class JPXStream: public FilterStream { +public: + + JPXStream(Stream *strA); + virtual ~JPXStream(); + virtual StreamKind getKind() { return strJPX; } + virtual void reset(); + virtual void close(); + virtual int getChar(); + virtual int lookChar(); + virtual GString *getPSFilter(int psLevel, char *indent); + virtual GBool isBinary(GBool last = gTrue); + virtual void getImageParams(int *bitsPerComponent, + StreamColorSpaceMode *csMode); + +private: + + void fillReadBuf(); + void getImageParams2(int *bitsPerComponent, StreamColorSpaceMode *csMode); + GBool readBoxes(); + GBool readColorSpecBox(Guint dataLen); + GBool readCodestream(Guint len); + GBool readTilePart(); + GBool readTilePartData(Guint tileIdx, + Guint tilePartLen, GBool tilePartToEOC); + GBool readCodeBlockData(JPXTileComp *tileComp, + JPXResLevel *resLevel, + JPXPrecinct *precinct, + JPXSubband *subband, + Guint res, Guint sb, + JPXCodeBlock *cb); + void inverseTransform(JPXTileComp *tileComp); + void inverseTransformLevel(JPXTileComp *tileComp, + Guint r, JPXResLevel *resLevel, + Guint nx0, Guint ny0, + Guint nx1, Guint ny1); + void inverseTransform1D(JPXTileComp *tileComp, + int *data, Guint stride, + Guint i0, Guint i1); + GBool inverseMultiCompAndDC(JPXTile *tile); + GBool readBoxHdr(Guint *boxType, Guint *boxLen, Guint *dataLen); + int readMarkerHdr(int *segType, Guint *segLen); + GBool readUByte(Guint *x); + GBool readByte(int *x); + GBool readUWord(Guint *x); + GBool readULong(Guint *x); + GBool readNBytes(int nBytes, GBool signd, int *x); + GBool readBits(int nBits, Guint *x); + void startBitBuf(Guint byteCountA); + Guint finishBitBuf(); + + Guint nComps; // number of components + Guint *bpc; // bits per component, for each component + Guint width, height; // image size + GBool haveImgHdr; // set if a JP2/JPX image header has been + // found + JPXColorSpec cs; // color specification + GBool haveCS; // set if a color spec has been found + JPXPalette palette; // the palette + GBool havePalette; // set if a palette has been found + JPXCompMap compMap; // the component mapping + GBool haveCompMap; // set if a component mapping has been found + JPXChannelDefn channelDefn; // channel definition + GBool haveChannelDefn; // set if a channel defn has been found + + JPXImage img; // JPEG2000 decoder data + Guint bitBuf; // buffer for bit reads + int bitBufLen; // number of bits in bitBuf + GBool bitBufSkip; // true if next bit should be skipped + // (for bit stuffing) + Guint byteCount; // number of available bytes left + + Guint curX, curY, curComp; // current position for lookChar/getChar + Guint readBuf; // read buffer + Guint readBufLen; // number of valid bits in readBuf +}; + +#endif diff --git a/kpdf/xpdf/xpdf/Lexer.cc b/kpdf/xpdf/xpdf/Lexer.cc new file mode 100644 index 00000000..1ef37175 --- /dev/null +++ b/kpdf/xpdf/xpdf/Lexer.cc @@ -0,0 +1,521 @@ +//======================================================================== +// +// Lexer.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include +#include "Lexer.h" +#include "Error.h" +#include "XRef.h" + +//------------------------------------------------------------------------ + +// A '1' in this array means the character is white space. A '1' or +// '2' means the character ends a name or command. +static char specialChars[256] = { + 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x + 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx +}; + +//------------------------------------------------------------------------ +// Lexer +//------------------------------------------------------------------------ + +Lexer::Lexer(XRef *xrefA, Stream *str) { + Object obj; + + xref = xrefA; + + curStr.initStream(str); + streams = new Array(xref); + streams->add(curStr.copy(&obj)); + strPtr = 0; + freeArray = gTrue; + curStr.streamReset(); +} + +Lexer::Lexer(XRef *xrefA, Object *obj) { + Object obj2; + + xref = xrefA; + + if (obj->isStream()) { + streams = new Array(xref); + freeArray = gTrue; + streams->add(obj->copy(&obj2)); + } else { + streams = obj->getArray(); + freeArray = gFalse; + } + strPtr = 0; + if (streams->getLength() > 0) { + streams->get(strPtr, &curStr); + curStr.streamReset(); + } +} + +Lexer::~Lexer() { + if (!curStr.isNone()) { + curStr.streamClose(); + curStr.free(); + } + if (freeArray) { + delete streams; + } +} + +int Lexer::getChar() { + int c; + + c = EOF; + while (!curStr.isNone() && (c = curStr.streamGetChar()) == EOF) { + curStr.streamClose(); + curStr.free(); + ++strPtr; + if (strPtr < streams->getLength()) { + streams->get(strPtr, &curStr); + curStr.streamReset(); + } + } + return c; +} + +int Lexer::lookChar() { + if (curStr.isNone()) { + return EOF; + } + return curStr.streamLookChar(); +} + +Object *Lexer::getObj(Object *obj, int objNum) { + char *p; + int c, c2; + GBool comment, neg, done; + int numParen; + int xi; + double xf, scale; + GString *s; + int n, m; + + // skip whitespace and comments + comment = gFalse; + while (1) { + if ((c = getChar()) == EOF) { + return obj->initEOF(); + } + if (comment) { + if (c == '\r' || c == '\n') + comment = gFalse; + } else if (c == '%') { + comment = gTrue; + } else if (specialChars[c] != 1) { + break; + } + } + + // start reading token + switch (c) { + + // number + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '-': case '.': + neg = gFalse; + xi = 0; + if (c == '-') { + neg = gTrue; + } else if (c == '.') { + goto doReal; + } else { + xi = c - '0'; + } + while (1) { + c = lookChar(); + if (isdigit(c)) { + getChar(); + xi = xi * 10 + (c - '0'); + } else if (c == '.') { + getChar(); + goto doReal; + } else { + break; + } + } + if (neg) + xi = -xi; + obj->initInt(xi); + break; + doReal: + xf = xi; + scale = 0.1; + while (1) { + c = lookChar(); + if (c == '-') { + // ignore minus signs in the middle of numbers to match + // Adobe's behavior + error(getPos(), "Badly formatted number"); + getChar(); + continue; + } + if (!isdigit(c)) { + break; + } + getChar(); + xf = xf + scale * (c - '0'); + scale *= 0.1; + } + if (neg) + xf = -xf; + obj->initReal(xf); + break; + + // string + case '(': + p = tokBuf; + n = 0; + numParen = 1; + done = gFalse; + s = NULL; + do { + c2 = EOF; + switch (c = getChar()) { + + case EOF: +#if 0 + // This breaks some PDF files, e.g., ones from Photoshop. + case '\r': + case '\n': +#endif + error(getPos(), "Unterminated string"); + done = gTrue; + break; + + case '(': + ++numParen; + c2 = c; + break; + + case ')': + if (--numParen == 0) { + done = gTrue; + } else { + c2 = c; + } + break; + + case '\\': + switch (c = getChar()) { + case 'n': + c2 = '\n'; + break; + case 'r': + c2 = '\r'; + break; + case 't': + c2 = '\t'; + break; + case 'b': + c2 = '\b'; + break; + case 'f': + c2 = '\f'; + break; + case '\\': + case '(': + case ')': + c2 = c; + break; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + c2 = c - '0'; + c = lookChar(); + if (c >= '0' && c <= '7') { + getChar(); + c2 = (c2 << 3) + (c - '0'); + c = lookChar(); + if (c >= '0' && c <= '7') { + getChar(); + c2 = (c2 << 3) + (c - '0'); + } + } + break; + case '\r': + c = lookChar(); + if (c == '\n') { + getChar(); + } + break; + case '\n': + break; + case EOF: + error(getPos(), "Unterminated string"); + done = gTrue; + break; + default: + c2 = c; + break; + } + break; + + default: + c2 = c; + break; + } + + if (c2 != EOF) { + if (n == tokBufSize) { + if (!s) + s = new GString(tokBuf, tokBufSize); + else + s->append(tokBuf, tokBufSize); + p = tokBuf; + n = 0; + + // we are growing see if the document is not malformed and we are growing too much + if (objNum > 0 && xref != NULL) + { + int newObjNum = xref->getNumEntry(curStr.streamGetPos()); + if (newObjNum != objNum) + { + error(getPos(), "Unterminated string"); + done = gTrue; + delete s; + n = -2; + } + } + } + *p++ = (char)c2; + ++n; + } + } while (!done); + if (n >= 0) { + if (!s) + s = new GString(tokBuf, n); + else + s->append(tokBuf, n); + obj->initString(s); + } else { + obj->initEOF(); + } + break; + + // name + case '/': + p = tokBuf; + n = 0; + s = NULL; + while ((c = lookChar()) != EOF && !specialChars[c]) { + getChar(); + if (c == '#') { + c2 = lookChar(); + if (c2 >= '0' && c2 <= '9') { + c = c2 - '0'; + } else if (c2 >= 'A' && c2 <= 'F') { + c = c2 - 'A' + 10; + } else if (c2 >= 'a' && c2 <= 'f') { + c = c2 - 'a' + 10; + } else { + goto notEscChar; + } + getChar(); + c <<= 4; + c2 = getChar(); + if (c2 >= '0' && c2 <= '9') { + c += c2 - '0'; + } else if (c2 >= 'A' && c2 <= 'F') { + c += c2 - 'A' + 10; + } else if (c2 >= 'a' && c2 <= 'f') { + c += c2 - 'a' + 10; + } else { + error(getPos(), "Illegal digit in hex char in name"); + } + } + notEscChar: + if (n == tokBufSize) { + if (!s) + s = new GString(tokBuf, tokBufSize); + else + { + // the spec says 127 is the maximum, we are already at 256 so bail out + error(getPos(), "Name token too long"); + break; + } + p = tokBuf; + n = 0; + } + *p++ = c; + ++n; + } + *p = '\0'; + if (s) { + s->append(tokBuf, n); + obj->initName(s->getCString()); + delete s; + } else obj->initName(tokBuf); + break; + + // array punctuation + case '[': + case ']': + tokBuf[0] = c; + tokBuf[1] = '\0'; + obj->initCmd(tokBuf); + break; + + // hex string or dict punctuation + case '<': + c = lookChar(); + + // dict punctuation + if (c == '<') { + getChar(); + tokBuf[0] = tokBuf[1] = '<'; + tokBuf[2] = '\0'; + obj->initCmd(tokBuf); + + // hex string + } else { + p = tokBuf; + m = n = 0; + c2 = 0; + s = NULL; + while (1) { + c = getChar(); + if (c == '>') { + break; + } else if (c == EOF) { + error(getPos(), "Unterminated hex string"); + break; + } else if (specialChars[c] != 1) { + c2 = c2 << 4; + if (c >= '0' && c <= '9') + c2 += c - '0'; + else if (c >= 'A' && c <= 'F') + c2 += c - 'A' + 10; + else if (c >= 'a' && c <= 'f') + c2 += c - 'a' + 10; + else + error(getPos(), "Illegal character <%02x> in hex string", c); + if (++m == 2) { + if (n == tokBufSize) { + if (!s) + s = new GString(tokBuf, tokBufSize); + else + s->append(tokBuf, tokBufSize); + p = tokBuf; + n = 0; + } + *p++ = (char)c2; + ++n; + c2 = 0; + m = 0; + } + } + } + if (!s) + s = new GString(tokBuf, n); + else + s->append(tokBuf, n); + if (m == 1) + s->append((char)(c2 << 4)); + obj->initString(s); + } + break; + + // dict punctuation + case '>': + c = lookChar(); + if (c == '>') { + getChar(); + tokBuf[0] = tokBuf[1] = '>'; + tokBuf[2] = '\0'; + obj->initCmd(tokBuf); + } else { + error(getPos(), "Illegal character '>'"); + obj->initError(); + } + break; + + // error + case ')': + case '{': + case '}': + error(getPos(), "Illegal character '%c'", c); + obj->initError(); + break; + + // command + default: + p = tokBuf; + *p++ = c; + n = 1; + while ((c = lookChar()) != EOF && !specialChars[c]) { + getChar(); + if (++n == tokBufSize) { + error(getPos(), "Command token too long"); + break; + } + *p++ = c; + } + *p = '\0'; + if (tokBuf[0] == 't' && !strcmp(tokBuf, "true")) { + obj->initBool(gTrue); + } else if (tokBuf[0] == 'f' && !strcmp(tokBuf, "false")) { + obj->initBool(gFalse); + } else if (tokBuf[0] == 'n' && !strcmp(tokBuf, "null")) { + obj->initNull(); + } else { + obj->initCmd(tokBuf); + } + break; + } + + return obj; +} + +void Lexer::skipToNextLine() { + int c; + + while (1) { + c = getChar(); + if (c == EOF || c == '\n') { + return; + } + if (c == '\r') { + if ((c = lookChar()) == '\n') { + getChar(); + } + return; + } + } +} + +GBool Lexer::isSpace(int c) { + return c >= 0 && c <= 0xff && specialChars[c] == 1; +} diff --git a/kpdf/xpdf/xpdf/Lexer.h b/kpdf/xpdf/xpdf/Lexer.h new file mode 100644 index 00000000..3333be9f --- /dev/null +++ b/kpdf/xpdf/xpdf/Lexer.h @@ -0,0 +1,82 @@ +//======================================================================== +// +// Lexer.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef LEXER_H +#define LEXER_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "Object.h" +#include "Stream.h" + +class XRef; + +#define tokBufSize 128 // size of token buffer + +//------------------------------------------------------------------------ +// Lexer +//------------------------------------------------------------------------ + +class Lexer { +public: + + // Construct a lexer for a single stream. Deletes the stream when + // lexer is deleted. + Lexer(XRef *xrefA, Stream *str); + + // Construct a lexer for a stream or array of streams (assumes obj + // is either a stream or array of streams). + Lexer(XRef *xrefA, Object *obj); + + // Destructor. + ~Lexer(); + + // Get the next object from the input stream. + Object *getObj(Object *obj, int objNum = -1); + + // Skip to the beginning of the next line in the input stream. + void skipToNextLine(); + + // Skip over one character. + void skipChar() { getChar(); } + + // Get stream. + Stream *getStream() + { return curStr.isNone() ? (Stream *)NULL : curStr.getStream(); } + + // Get current position in file. This is only used for error + // messages, so it returns an int instead of a Guint. + int getPos() + { return curStr.isNone() ? -1 : (int)curStr.streamGetPos(); } + + // Set position in file. + void setPos(Guint pos, int dir = 0) + { if (!curStr.isNone()) curStr.streamSetPos(pos, dir); } + + // Returns true if is a whitespace character. + static GBool isSpace(int c); + +private: + + int getChar(); + int lookChar(); + + Array *streams; // array of input streams + int strPtr; // index of current stream + Object curStr; // current stream + GBool freeArray; // should lexer free the streams array? + char tokBuf[tokBufSize]; // temporary token buffer + + XRef *xref; +}; + +#endif diff --git a/kpdf/xpdf/xpdf/Link.cc b/kpdf/xpdf/xpdf/Link.cc new file mode 100644 index 00000000..ae2de537 --- /dev/null +++ b/kpdf/xpdf/xpdf/Link.cc @@ -0,0 +1,784 @@ +//======================================================================== +// +// Link.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "GString.h" +#include "Error.h" +#include "Object.h" +#include "Array.h" +#include "Dict.h" +#include "Link.h" + +//------------------------------------------------------------------------ +// LinkAction +//------------------------------------------------------------------------ + +LinkAction *LinkAction::parseDest(Object *obj) { + LinkAction *action; + + action = new LinkGoTo(obj); + if (!action->isOk()) { + delete action; + return NULL; + } + return action; +} + +LinkAction *LinkAction::parseAction(Object *obj, GString *baseURI) { + LinkAction *action; + Object obj2, obj3, obj4; + + if (!obj->isDict()) { + error(-1, "Bad annotation action"); + return NULL; + } + + obj->dictLookup("S", &obj2); + + // GoTo action + if (obj2.isName("GoTo")) { + obj->dictLookup("D", &obj3); + action = new LinkGoTo(&obj3); + obj3.free(); + + // GoToR action + } else if (obj2.isName("GoToR")) { + obj->dictLookup("F", &obj3); + obj->dictLookup("D", &obj4); + action = new LinkGoToR(&obj3, &obj4); + obj3.free(); + obj4.free(); + + // Launch action + } else if (obj2.isName("Launch")) { + action = new LinkLaunch(obj); + + // URI action + } else if (obj2.isName("URI")) { + obj->dictLookup("URI", &obj3); + action = new LinkURI(&obj3, baseURI); + obj3.free(); + + // Named action + } else if (obj2.isName("Named")) { + obj->dictLookup("N", &obj3); + action = new LinkNamed(&obj3); + obj3.free(); + + // Movie action + } else if (obj2.isName("Movie")) { + obj->dictLookupNF("Annot", &obj3); + obj->dictLookup("T", &obj4); + action = new LinkMovie(&obj3, &obj4); + obj3.free(); + obj4.free(); + + // unknown action + } else if (obj2.isName()) { + action = new LinkUnknown(obj2.getName()); + + // action is missing or wrong type + } else { + error(-1, "Bad annotation action"); + action = NULL; + } + + obj2.free(); + + if (action && !action->isOk()) { + delete action; + return NULL; + } + return action; +} + +GString *LinkAction::getFileSpecName(Object *fileSpecObj) { + GString *name; + Object obj1; + + name = NULL; + + // string + if (fileSpecObj->isString()) { + name = fileSpecObj->getString()->copy(); + + // dictionary + } else if (fileSpecObj->isDict()) { +#ifdef WIN32 + if (!fileSpecObj->dictLookup("DOS", &obj1)->isString()) { +#else + if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) { +#endif + obj1.free(); + fileSpecObj->dictLookup("F", &obj1); + } + if (obj1.isString()) { + name = obj1.getString()->copy(); + } else { + error(-1, "Illegal file spec in link"); + } + obj1.free(); + + // error + } else { + error(-1, "Illegal file spec in link"); + } + + // system-dependent path manipulation + if (name) { +#ifdef WIN32 + int i, j; + + // "//...." --> "\...." + // "/x/...." --> "x:\...." + // "/server/share/...." --> "\\server\share\...." + // convert escaped slashes to slashes and unescaped slashes to backslashes + i = 0; + if (name->getChar(0) == '/') { + if (name->getLength() >= 2 && name->getChar(1) == '/') { + name->del(0); + i = 0; + } else if (name->getLength() >= 2 && + ((name->getChar(1) >= 'a' && name->getChar(1) <= 'z') || + (name->getChar(1) >= 'A' && name->getChar(1) <= 'Z')) && + (name->getLength() == 2 || name->getChar(2) == '/')) { + name->setChar(0, name->getChar(1)); + name->setChar(1, ':'); + i = 2; + } else { + for (j = 2; j < name->getLength(); ++j) { + if (name->getChar(j-1) != '\\' && + name->getChar(j) == '/') { + break; + } + } + if (j < name->getLength()) { + name->setChar(0, '\\'); + name->insert(0, '\\'); + i = 2; + } + } + } + for (; i < name->getLength(); ++i) { + if (name->getChar(i) == '/') { + name->setChar(i, '\\'); + } else if (name->getChar(i) == '\\' && + i+1 < name->getLength() && + name->getChar(i+1) == '/') { + name->del(i); + } + } +#else + // no manipulation needed for Unix +#endif + } + + return name; +} + +//------------------------------------------------------------------------ +// LinkDest +//------------------------------------------------------------------------ + +LinkDest::LinkDest(Array *a) { + Object obj1, obj2; + + // initialize fields + left = bottom = right = top = zoom = 0; + ok = gFalse; + + // get page + if (a->getLength() < 2) { + error(-1, "Annotation destination array is too short"); + return; + } + a->getNF(0, &obj1); + if (obj1.isInt()) { + pageNum = obj1.getInt() + 1; + pageIsRef = gFalse; + } else if (obj1.isRef()) { + pageRef.num = obj1.getRefNum(); + pageRef.gen = obj1.getRefGen(); + pageIsRef = gTrue; + } else { + error(-1, "Bad annotation destination"); + goto err2; + } + obj1.free(); + + // get destination type + a->get(1, &obj1); + + // XYZ link + if (obj1.isName("XYZ")) { + kind = destXYZ; + if (a->getLength() < 3) { + changeLeft = gFalse; + } else { + a->get(2, &obj2); + if (obj2.isNull()) { + changeLeft = gFalse; + } else if (obj2.isNum()) { + changeLeft = gTrue; + left = obj2.getNum(); + } else { + error(-1, "Bad annotation destination position"); + goto err1; + } + obj2.free(); + } + if (a->getLength() < 4) { + changeTop = gFalse; + } else { + a->get(3, &obj2); + if (obj2.isNull()) { + changeTop = gFalse; + } else if (obj2.isNum()) { + changeTop = gTrue; + top = obj2.getNum(); + } else { + error(-1, "Bad annotation destination position"); + goto err1; + } + obj2.free(); + } + if (a->getLength() < 5) { + changeZoom = gFalse; + } else { + a->get(4, &obj2); + if (obj2.isNull()) { + changeZoom = gFalse; + } else if (obj2.isNum()) { + changeZoom = gTrue; + zoom = obj2.getNum(); + } else { + error(-1, "Bad annotation destination position"); + goto err1; + } + obj2.free(); + } + + // Fit link + } else if (obj1.isName("Fit")) { + if (a->getLength() < 2) { + error(-1, "Annotation destination array is too short"); + goto err2; + } + kind = destFit; + + // FitH link + } else if (obj1.isName("FitH")) { + if (a->getLength() < 3) { + error(-1, "Annotation destination array is too short"); + goto err2; + } + kind = destFitH; + if (!a->get(2, &obj2)->isNum()) { + error(-1, "Bad annotation destination position"); + kind = destFit; + } + top = obj2.getNum(); + obj2.free(); + + // FitV link + } else if (obj1.isName("FitV")) { + if (a->getLength() < 3) { + error(-1, "Annotation destination array is too short"); + goto err2; + } + kind = destFitV; + if (!a->get(2, &obj2)->isNum()) { + error(-1, "Bad annotation destination position"); + kind = destFit; + } + left = obj2.getNum(); + obj2.free(); + + // FitR link + } else if (obj1.isName("FitR")) { + if (a->getLength() < 6) { + error(-1, "Annotation destination array is too short"); + goto err2; + } + kind = destFitR; + if (!a->get(2, &obj2)->isNum()) { + error(-1, "Bad annotation destination position"); + kind = destFit; + } + left = obj2.getNum(); + obj2.free(); + if (!a->get(3, &obj2)->isNum()) { + error(-1, "Bad annotation destination position"); + kind = destFit; + } + bottom = obj2.getNum(); + obj2.free(); + if (!a->get(4, &obj2)->isNum()) { + error(-1, "Bad annotation destination position"); + kind = destFit; + } + right = obj2.getNum(); + obj2.free(); + if (!a->get(5, &obj2)->isNum()) { + error(-1, "Bad annotation destination position"); + kind = destFit; + } + top = obj2.getNum(); + obj2.free(); + + // FitB link + } else if (obj1.isName("FitB")) { + if (a->getLength() < 2) { + error(-1, "Annotation destination array is too short"); + goto err2; + } + kind = destFitB; + + // FitBH link + } else if (obj1.isName("FitBH")) { + if (a->getLength() < 3) { + error(-1, "Annotation destination array is too short"); + goto err2; + } + kind = destFitBH; + if (!a->get(2, &obj2)->isNum()) { + error(-1, "Bad annotation destination position"); + kind = destFit; + } + top = obj2.getNum(); + obj2.free(); + + // FitBV link + } else if (obj1.isName("FitBV")) { + if (a->getLength() < 3) { + error(-1, "Annotation destination array is too short"); + goto err2; + } + kind = destFitBV; + if (!a->get(2, &obj2)->isNum()) { + error(-1, "Bad annotation destination position"); + kind = destFit; + } + left = obj2.getNum(); + obj2.free(); + + // unknown link kind + } else { + error(-1, "Unknown annotation destination type"); + goto err2; + } + + obj1.free(); + ok = gTrue; + return; + + err1: + obj2.free(); + err2: + obj1.free(); +} + +LinkDest::LinkDest(LinkDest *dest) { + kind = dest->kind; + pageIsRef = dest->pageIsRef; + if (pageIsRef) + pageRef = dest->pageRef; + else + pageNum = dest->pageNum; + left = dest->left; + bottom = dest->bottom; + right = dest->right; + top = dest->top; + zoom = dest->zoom; + changeLeft = dest->changeLeft; + changeTop = dest->changeTop; + changeZoom = dest->changeZoom; + ok = gTrue; +} + +//------------------------------------------------------------------------ +// LinkGoTo +//------------------------------------------------------------------------ + +LinkGoTo::LinkGoTo(Object *destObj) { + dest = NULL; + namedDest = NULL; + + // named destination + if (destObj->isName()) { + namedDest = new GString(destObj->getName()); + } else if (destObj->isString()) { + namedDest = destObj->getString()->copy(); + + // destination dictionary + } else if (destObj->isArray()) { + dest = new LinkDest(destObj->getArray()); + if (!dest->isOk()) { + delete dest; + dest = NULL; + } + + // error + } else { + error(-1, "Illegal annotation destination"); + } +} + +LinkGoTo::~LinkGoTo() { + if (dest) + delete dest; + if (namedDest) + delete namedDest; +} + +//------------------------------------------------------------------------ +// LinkGoToR +//------------------------------------------------------------------------ + +LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) { + dest = NULL; + namedDest = NULL; + + // get file name + fileName = getFileSpecName(fileSpecObj); + + // named destination + if (destObj->isName()) { + namedDest = new GString(destObj->getName()); + } else if (destObj->isString()) { + namedDest = destObj->getString()->copy(); + + // destination dictionary + } else if (destObj->isArray()) { + dest = new LinkDest(destObj->getArray()); + if (!dest->isOk()) { + delete dest; + dest = NULL; + } + + // error + } else { + error(-1, "Illegal annotation destination"); + } +} + +LinkGoToR::~LinkGoToR() { + if (fileName) + delete fileName; + if (dest) + delete dest; + if (namedDest) + delete namedDest; +} + + +//------------------------------------------------------------------------ +// LinkLaunch +//------------------------------------------------------------------------ + +LinkLaunch::LinkLaunch(Object *actionObj) { + Object obj1, obj2; + + fileName = NULL; + params = NULL; + + if (actionObj->isDict()) { + if (!actionObj->dictLookup("F", &obj1)->isNull()) { + fileName = getFileSpecName(&obj1); + } else { + obj1.free(); +#ifdef WIN32 + if (actionObj->dictLookup("Win", &obj1)->isDict()) { + obj1.dictLookup("F", &obj2); + fileName = getFileSpecName(&obj2); + obj2.free(); + if (obj1.dictLookup("P", &obj2)->isString()) { + params = obj2.getString()->copy(); + } + obj2.free(); + } else { + error(-1, "Bad launch-type link action"); + } +#else + //~ This hasn't been defined by Adobe yet, so assume it looks + //~ just like the Win dictionary until they say otherwise. + if (actionObj->dictLookup("Unix", &obj1)->isDict()) { + obj1.dictLookup("F", &obj2); + fileName = getFileSpecName(&obj2); + obj2.free(); + if (obj1.dictLookup("P", &obj2)->isString()) { + params = obj2.getString()->copy(); + } + obj2.free(); + } else { + error(-1, "Bad launch-type link action"); + } +#endif + } + obj1.free(); + } +} + +LinkLaunch::~LinkLaunch() { + if (fileName) + delete fileName; + if (params) + delete params; +} + +//------------------------------------------------------------------------ +// LinkURI +//------------------------------------------------------------------------ + +LinkURI::LinkURI(Object *uriObj, GString *baseURI) { + GString *uri2; + int n; + char c; + + uri = NULL; + if (uriObj->isString()) { + uri2 = uriObj->getString()->copy(); + if (baseURI && baseURI->getLength() > 0) { + n = strcspn(uri2->getCString(), "/:"); + if (n == uri2->getLength() || uri2->getChar(n) == '/') { + uri = baseURI->copy(); + c = uri->getChar(uri->getLength() - 1); + if (c == '/' || c == '?') { + if (uri2->getChar(0) == '/') { + uri2->del(0); + } + } else { + if (uri2->getChar(0) != '/') { + uri->append('/'); + } + } + uri->append(uri2); + delete uri2; + } else { + uri = uri2; + } + } else { + uri = uri2; + } + } else { + error(-1, "Illegal URI-type link"); + } +} + +LinkURI::~LinkURI() { + if (uri) + delete uri; +} + +//------------------------------------------------------------------------ +// LinkNamed +//------------------------------------------------------------------------ + +LinkNamed::LinkNamed(Object *nameObj) { + name = NULL; + if (nameObj->isName()) { + name = new GString(nameObj->getName()); + } +} + +LinkNamed::~LinkNamed() { + if (name) { + delete name; + } +} + +//------------------------------------------------------------------------ +// LinkMovie +//------------------------------------------------------------------------ + +LinkMovie::LinkMovie(Object *annotObj, Object *titleObj) { + annotRef.num = -1; + title = NULL; + if (annotObj->isRef()) { + annotRef = annotObj->getRef(); + } else if (titleObj->isString()) { + title = titleObj->getString()->copy(); + } else { + error(-1, "Movie action is missing both the Annot and T keys"); + } +} + +LinkMovie::~LinkMovie() { + if (title) { + delete title; + } +} + +//------------------------------------------------------------------------ +// LinkUnknown +//------------------------------------------------------------------------ + +LinkUnknown::LinkUnknown(char *actionA) { + action = new GString(actionA); +} + +LinkUnknown::~LinkUnknown() { + delete action; +} + +//------------------------------------------------------------------------ +// Link +//------------------------------------------------------------------------ + +Link::Link(Dict *dict, GString *baseURI) { + Object obj1, obj2; + double t; + + action = NULL; + ok = gFalse; + + // get rectangle + if (!dict->lookup("Rect", &obj1)->isArray()) { + error(-1, "Annotation rectangle is wrong type"); + goto err2; + } + if (!obj1.arrayGet(0, &obj2)->isNum()) { + error(-1, "Bad annotation rectangle"); + goto err1; + } + x1 = obj2.getNum(); + obj2.free(); + if (!obj1.arrayGet(1, &obj2)->isNum()) { + error(-1, "Bad annotation rectangle"); + goto err1; + } + y1 = obj2.getNum(); + obj2.free(); + if (!obj1.arrayGet(2, &obj2)->isNum()) { + error(-1, "Bad annotation rectangle"); + goto err1; + } + x2 = obj2.getNum(); + obj2.free(); + if (!obj1.arrayGet(3, &obj2)->isNum()) { + error(-1, "Bad annotation rectangle"); + goto err1; + } + y2 = obj2.getNum(); + obj2.free(); + obj1.free(); + if (x1 > x2) { + t = x1; + x1 = x2; + x2 = t; + } + if (y1 > y2) { + t = y1; + y1 = y2; + y2 = t; + } + + // look for destination + if (!dict->lookup("Dest", &obj1)->isNull()) { + action = LinkAction::parseDest(&obj1); + + // look for action + } else { + obj1.free(); + if (dict->lookup("A", &obj1)->isDict()) { + action = LinkAction::parseAction(&obj1, baseURI); + } + } + obj1.free(); + + // check for bad action + if (action) { + ok = gTrue; + } + + return; + + err1: + obj2.free(); + err2: + obj1.free(); +} + +Link::~Link() { + if (action) { + delete action; + } +} + +//------------------------------------------------------------------------ +// Links +//------------------------------------------------------------------------ + +Links::Links(Object *annots, GString *baseURI) { + Link *link; + Object obj1, obj2; + int size; + int i; + + links = NULL; + size = 0; + numLinks = 0; + + if (annots->isArray()) { + for (i = 0; i < annots->arrayGetLength(); ++i) { + if (annots->arrayGet(i, &obj1)->isDict()) { + if (obj1.dictLookup("Subtype", &obj2)->isName("Link")) { + link = new Link(obj1.getDict(), baseURI); + if (link->isOk()) { + if (numLinks >= size) { + size += 16; + links = (Link **)greallocn(links, size, sizeof(Link *)); + } + links[numLinks++] = link; + } else { + delete link; + } + } + obj2.free(); + } + obj1.free(); + } + } +} + +Links::~Links() { + int i; + + for (i = 0; i < numLinks; ++i) + delete links[i]; + gfree(links); +} + +LinkAction *Links::find(double x, double y) { + int i; + + for (i = numLinks - 1; i >= 0; --i) { + if (links[i]->inRect(x, y)) { + return links[i]->getAction(); + } + } + return NULL; +} + +GBool Links::onLink(double x, double y) { + int i; + + for (i = 0; i < numLinks; ++i) { + if (links[i]->inRect(x, y)) + return gTrue; + } + return gFalse; +} diff --git a/kpdf/xpdf/xpdf/Link.h b/kpdf/xpdf/xpdf/Link.h new file mode 100644 index 00000000..698f2c85 --- /dev/null +++ b/kpdf/xpdf/xpdf/Link.h @@ -0,0 +1,369 @@ +//======================================================================== +// +// Link.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef LINK_H +#define LINK_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "Object.h" + +class GString; +class Array; +class Dict; + +//------------------------------------------------------------------------ +// LinkAction +//------------------------------------------------------------------------ + +enum LinkActionKind { + actionGoTo, // go to destination + actionGoToR, // go to destination in new file + actionLaunch, // launch app (or open document) + actionURI, // URI + actionNamed, // named action + actionMovie, // movie action + actionUnknown // anything else +}; + +class LinkAction { +public: + + // Destructor. + virtual ~LinkAction() {} + + // Was the LinkAction created successfully? + virtual GBool isOk() = 0; + + // Check link action type. + virtual LinkActionKind getKind() = 0; + + // Parse a destination (old-style action) name, string, or array. + static LinkAction *parseDest(Object *obj); + + // Parse an action dictionary. + static LinkAction *parseAction(Object *obj, GString *baseURI = NULL); + + // Extract a file name from a file specification (string or + // dictionary). + static GString *getFileSpecName(Object *fileSpecObj); +}; + +//------------------------------------------------------------------------ +// LinkDest +//------------------------------------------------------------------------ + +enum LinkDestKind { + destXYZ, + destFit, + destFitH, + destFitV, + destFitR, + destFitB, + destFitBH, + destFitBV +}; + +class LinkDest { +public: + + // Build a LinkDest from the array. + LinkDest(Array *a); + + // Copy a LinkDest. + LinkDest *copy() { return new LinkDest(this); } + + // Was the LinkDest created successfully? + GBool isOk() { return ok; } + + // Accessors. + LinkDestKind getKind() { return kind; } + GBool isPageRef() { return pageIsRef; } + int getPageNum() { return pageNum; } + Ref getPageRef() { return pageRef; } + double getLeft() { return left; } + double getBottom() { return bottom; } + double getRight() { return right; } + double getTop() { return top; } + double getZoom() { return zoom; } + GBool getChangeLeft() { return changeLeft; } + GBool getChangeTop() { return changeTop; } + GBool getChangeZoom() { return changeZoom; } + +private: + + LinkDestKind kind; // destination type + GBool pageIsRef; // is the page a reference or number? + union { + Ref pageRef; // reference to page + int pageNum; // one-relative page number + }; + double left, bottom; // position + double right, top; + double zoom; // zoom factor + GBool changeLeft, changeTop; // for destXYZ links, which position + GBool changeZoom; // components to change + GBool ok; // set if created successfully + + LinkDest(LinkDest *dest); +}; + +//------------------------------------------------------------------------ +// LinkGoTo +//------------------------------------------------------------------------ + +class LinkGoTo: public LinkAction { +public: + + // Build a LinkGoTo from a destination (dictionary, name, or string). + LinkGoTo(Object *destObj); + + // Destructor. + virtual ~LinkGoTo(); + + // Was the LinkGoTo created successfully? + virtual GBool isOk() { return dest || namedDest; } + + // Accessors. + virtual LinkActionKind getKind() { return actionGoTo; } + LinkDest *getDest() { return dest; } + GString *getNamedDest() { return namedDest; } + +private: + + LinkDest *dest; // regular destination (NULL for remote + // link with bad destination) + GString *namedDest; // named destination (only one of dest and + // and namedDest may be non-NULL) +}; + +//------------------------------------------------------------------------ +// LinkGoToR +//------------------------------------------------------------------------ + +class LinkGoToR: public LinkAction { +public: + + // Build a LinkGoToR from a file spec (dictionary) and destination + // (dictionary, name, or string). + LinkGoToR(Object *fileSpecObj, Object *destObj); + + // Destructor. + virtual ~LinkGoToR(); + + // Was the LinkGoToR created successfully? + virtual GBool isOk() { return fileName && (dest || namedDest); } + + // Accessors. + virtual LinkActionKind getKind() { return actionGoToR; } + GString *getFileName() { return fileName; } + LinkDest *getDest() { return dest; } + GString *getNamedDest() { return namedDest; } + +private: + + GString *fileName; // file name + LinkDest *dest; // regular destination (NULL for remote + // link with bad destination) + GString *namedDest; // named destination (only one of dest and + // and namedDest may be non-NULL) +}; + +//------------------------------------------------------------------------ +// LinkLaunch +//------------------------------------------------------------------------ + +class LinkLaunch: public LinkAction { +public: + + // Build a LinkLaunch from an action dictionary. + LinkLaunch(Object *actionObj); + + // Destructor. + virtual ~LinkLaunch(); + + // Was the LinkLaunch created successfully? + virtual GBool isOk() { return fileName != NULL; } + + // Accessors. + virtual LinkActionKind getKind() { return actionLaunch; } + GString *getFileName() { return fileName; } + GString *getParams() { return params; } + +private: + + GString *fileName; // file name + GString *params; // parameters +}; + +//------------------------------------------------------------------------ +// LinkURI +//------------------------------------------------------------------------ + +class LinkURI: public LinkAction { +public: + + // Build a LinkURI given the URI (string) and base URI. + LinkURI(Object *uriObj, GString *baseURI); + + // Destructor. + virtual ~LinkURI(); + + // Was the LinkURI created successfully? + virtual GBool isOk() { return uri != NULL; } + + // Accessors. + virtual LinkActionKind getKind() { return actionURI; } + GString *getURI() { return uri; } + +private: + + GString *uri; // the URI +}; + +//------------------------------------------------------------------------ +// LinkNamed +//------------------------------------------------------------------------ + +class LinkNamed: public LinkAction { +public: + + // Build a LinkNamed given the action name. + LinkNamed(Object *nameObj); + + virtual ~LinkNamed(); + + virtual GBool isOk() { return name != NULL; } + + virtual LinkActionKind getKind() { return actionNamed; } + GString *getName() { return name; } + +private: + + GString *name; +}; + +//------------------------------------------------------------------------ +// LinkMovie +//------------------------------------------------------------------------ + +class LinkMovie: public LinkAction { +public: + + LinkMovie(Object *annotObj, Object *titleObj); + + virtual ~LinkMovie(); + + virtual GBool isOk() { return annotRef.num >= 0 || title != NULL; } + + virtual LinkActionKind getKind() { return actionMovie; } + GBool hasAnnotRef() { return annotRef.num >= 0; } + Ref *getAnnotRef() { return &annotRef; } + GString *getTitle() { return title; } + +private: + + Ref annotRef; + GString *title; +}; + +//------------------------------------------------------------------------ +// LinkUnknown +//------------------------------------------------------------------------ + +class LinkUnknown: public LinkAction { +public: + + // Build a LinkUnknown with the specified action type. + LinkUnknown(char *actionA); + + // Destructor. + virtual ~LinkUnknown(); + + // Was the LinkUnknown create successfully? + virtual GBool isOk() { return action != NULL; } + + // Accessors. + virtual LinkActionKind getKind() { return actionUnknown; } + GString *getAction() { return action; } + +private: + + GString *action; // action subtype +}; + +//------------------------------------------------------------------------ +// Link +//------------------------------------------------------------------------ + +class Link { +public: + + // Construct a link, given its dictionary. + Link(Dict *dict, GString *baseURI); + + // Destructor. + ~Link(); + + // Was the link created successfully? + GBool isOk() { return ok; } + + // Check if point is inside the link rectangle. + GBool inRect(double x, double y) + { return x1 <= x && x <= x2 && y1 <= y && y <= y2; } + + // Get action. + LinkAction *getAction() { return action; } + + // Get the link rectangle. + void getRect(double *xa1, double *ya1, double *xa2, double *ya2) + { *xa1 = x1; *ya1 = y1; *xa2 = x2; *ya2 = y2; } + +private: + + double x1, y1; // lower left corner + double x2, y2; // upper right corner + LinkAction *action; // action + GBool ok; // is link valid? +}; + +//------------------------------------------------------------------------ +// Links +//------------------------------------------------------------------------ + +class Links { +public: + + // Extract links from array of annotations. + Links(Object *annots, GString *baseURI); + + // Destructor. + ~Links(); + + // Iterate through list of links. + int getNumLinks() { return numLinks; } + Link *getLink(int i) { return links[i]; } + + // If point , is in a link, return the associated action; + // else return NULL. + LinkAction *find(double x, double y); + + // Return true if , is in a link. + GBool onLink(double x, double y); + +private: + + Link **links; + int numLinks; +}; + +#endif diff --git a/kpdf/xpdf/xpdf/Makefile.am b/kpdf/xpdf/xpdf/Makefile.am new file mode 100644 index 00000000..4c0593ad --- /dev/null +++ b/kpdf/xpdf/xpdf/Makefile.am @@ -0,0 +1,19 @@ +INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../fofi -I$(srcdir)/../splash -I$(srcdir)/../goo $(LIBFREETYPE_CFLAGS) $(XFT_CFLAGS) $(all_includes) + +libxpdf_la_LDFLAGS = $(all_libraries) +libxpdf_la_LIBADD = $(LIB_X11) $(LIBFREETYPE_LIBS) $(LIBPAPER_LIBS) $(XFT_LIBS) $(LIBJPEG) ../goo/libgoo.la ../fofi/libfofi.la ../splash/libsplash.la +libxpdf_la_SOURCES = Annot.cc Array.cc BuiltinFont.cc BuiltinFontTables.cc \ + Catalog.cc CharCodeToUnicode.cc CMap.cc Decrypt.cc Dict.cc \ + FontEncodingTables.cc Function.cc Gfx.cc \ + GfxFont.cc GfxState.cc GlobalParams.cc JArithmeticDecoder.cc \ + JBIG2Stream.cc Lexer.cc Link.cc NameToCharCode.cc Object.cc Outline.cc \ + OutputDev.cc PDFDoc.cc PDFDocEncoding.cc PreScanOutputDev.cc PSTokenizer.cc \ + Page.cc Parser.cc PSOutputDev.cc SecurityHandler.cc SplashOutputDev.cc Stream.cc JPXStream.cc \ + TextOutputDev.cc UnicodeMap.cc UnicodeTypeTable.cc XRef.cc + +noinst_LTLIBRARIES = libxpdf.la + +# This fixes crash in Bug 109015 which i assume is a compiler bug +# as adding some correctly placed printf in SplashOutputDev::convertPath() makes this +# option unneeded +KDE_CXXFLAGS=$(NOREGMOVE) diff --git a/kpdf/xpdf/xpdf/NameToCharCode.cc b/kpdf/xpdf/xpdf/NameToCharCode.cc new file mode 100644 index 00000000..7ebf4e16 --- /dev/null +++ b/kpdf/xpdf/xpdf/NameToCharCode.cc @@ -0,0 +1,116 @@ +//======================================================================== +// +// NameToCharCode.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "gmem.h" +#include "NameToCharCode.h" + +//------------------------------------------------------------------------ + +struct NameToCharCodeEntry { + char *name; + CharCode c; +}; + +//------------------------------------------------------------------------ + +NameToCharCode::NameToCharCode() { + int i; + + size = 31; + len = 0; + tab = (NameToCharCodeEntry *)gmallocn(size, sizeof(NameToCharCodeEntry)); + for (i = 0; i < size; ++i) { + tab[i].name = NULL; + } +} + +NameToCharCode::~NameToCharCode() { + int i; + + for (i = 0; i < size; ++i) { + if (tab[i].name) { + gfree(tab[i].name); + } + } + gfree(tab); +} + +void NameToCharCode::add(char *name, CharCode c) { + NameToCharCodeEntry *oldTab; + int h, i, oldSize; + + // expand the table if necessary + if (len >= size / 2) { + oldSize = size; + oldTab = tab; + size = 2*size + 1; + tab = (NameToCharCodeEntry *)gmallocn(size, sizeof(NameToCharCodeEntry)); + for (h = 0; h < size; ++h) { + tab[h].name = NULL; + } + for (i = 0; i < oldSize; ++i) { + if (oldTab[i].name) { + h = hash(oldTab[i].name); + while (tab[h].name) { + if (++h == size) { + h = 0; + } + } + tab[h] = oldTab[i]; + } + } + gfree(oldTab); + } + + // add the new name + h = hash(name); + while (tab[h].name && strcmp(tab[h].name, name)) { + if (++h == size) { + h = 0; + } + } + if (!tab[h].name) { + tab[h].name = copyString(name); + } + tab[h].c = c; + + ++len; +} + +CharCode NameToCharCode::lookup(char *name) { + int h; + + h = hash(name); + while (tab[h].name) { + if (!strcmp(tab[h].name, name)) { + return tab[h].c; + } + if (++h == size) { + h = 0; + } + } + return 0; +} + +int NameToCharCode::hash(char *name) { + char *p; + unsigned int h; + + h = 0; + for (p = name; *p; ++p) { + h = 17 * h + (int)(*p & 0xff); + } + return (int)(h % size); +} diff --git a/kpdf/xpdf/xpdf/NameToCharCode.h b/kpdf/xpdf/xpdf/NameToCharCode.h new file mode 100644 index 00000000..65453c3a --- /dev/null +++ b/kpdf/xpdf/xpdf/NameToCharCode.h @@ -0,0 +1,42 @@ +//======================================================================== +// +// NameToCharCode.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef NAMETOCHARCODE_H +#define NAMETOCHARCODE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "CharTypes.h" + +struct NameToCharCodeEntry; + +//------------------------------------------------------------------------ + +class NameToCharCode { +public: + + NameToCharCode(); + ~NameToCharCode(); + + void add(char *name, CharCode c); + CharCode lookup(char *name); + +private: + + int hash(char *name); + + NameToCharCodeEntry *tab; + int size; + int len; +}; + +#endif diff --git a/kpdf/xpdf/xpdf/NameToUnicodeTable.h b/kpdf/xpdf/xpdf/NameToUnicodeTable.h new file mode 100644 index 00000000..c5ecba49 --- /dev/null +++ b/kpdf/xpdf/xpdf/NameToUnicodeTable.h @@ -0,0 +1,1097 @@ +//======================================================================== +// +// NameToUnicodeTable.h +// +// Copyright 2001-2004 Glyph & Cog, LLC +// +//======================================================================== + +static struct { + Unicode u; + char *name; +} nameToUnicodeTab[] = { + {0x0021, "!"}, + {0x0023, "#"}, + {0x0024, "$"}, + {0x0025, "%"}, + {0x0026, "&"}, + {0x0027, "'"}, + {0x0028, "("}, + {0x0029, ")"}, + {0x002a, "*"}, + {0x002b, "+"}, + {0x002c, ","}, + {0x002d, "-"}, + {0x002e, "."}, + {0x002f, "/"}, + {0x0030, "0"}, + {0x0031, "1"}, + {0x0032, "2"}, + {0x0033, "3"}, + {0x0034, "4"}, + {0x0035, "5"}, + {0x0036, "6"}, + {0x0037, "7"}, + {0x0038, "8"}, + {0x0039, "9"}, + {0x003a, ":"}, + {0x003b, ";"}, + {0x003c, "<"}, + {0x003d, "="}, + {0x003e, ">"}, + {0x003f, "?"}, + {0x0040, "@"}, + {0x0041, "A"}, + {0x00c6, "AE"}, + {0x01fc, "AEacute"}, + {0xf7e6, "AEsmall"}, + {0x00c1, "Aacute"}, + {0xf7e1, "Aacutesmall"}, + {0x0102, "Abreve"}, + {0x00c2, "Acircumflex"}, + {0xf7e2, "Acircumflexsmall"}, + {0xf6c9, "Acute"}, + {0xf7b4, "Acutesmall"}, + {0x00c4, "Adieresis"}, + {0xf7e4, "Adieresissmall"}, + {0x00c0, "Agrave"}, + {0xf7e0, "Agravesmall"}, + {0x0391, "Alpha"}, + {0x0386, "Alphatonos"}, + {0x0100, "Amacron"}, + {0x0104, "Aogonek"}, + {0x00c5, "Aring"}, + {0x01fa, "Aringacute"}, + {0xf7e5, "Aringsmall"}, + {0xf761, "Asmall"}, + {0x00c3, "Atilde"}, + {0xf7e3, "Atildesmall"}, + {0x0042, "B"}, + {0x0392, "Beta"}, + {0xf6f4, "Brevesmall"}, + {0xf762, "Bsmall"}, + {0x0043, "C"}, + {0x0106, "Cacute"}, + {0xf6ca, "Caron"}, + {0xf6f5, "Caronsmall"}, + {0x010c, "Ccaron"}, + {0x00c7, "Ccedilla"}, + {0xf7e7, "Ccedillasmall"}, + {0x0108, "Ccircumflex"}, + {0x010a, "Cdotaccent"}, + {0xf7b8, "Cedillasmall"}, + {0x03a7, "Chi"}, + {0xf6f6, "Circumflexsmall"}, + {0xf763, "Csmall"}, + {0x0044, "D"}, + {0x010e, "Dcaron"}, + {0x0110, "Dcroat"}, + {0x2206, "Delta"}, + {0xf6cb, "Dieresis"}, + {0xf6cc, "DieresisAcute"}, + {0xf6cd, "DieresisGrave"}, + {0xf7a8, "Dieresissmall"}, + {0xf6f7, "Dotaccentsmall"}, + {0xf764, "Dsmall"}, + {0x0045, "E"}, + {0x00c9, "Eacute"}, + {0xf7e9, "Eacutesmall"}, + {0x0114, "Ebreve"}, + {0x011a, "Ecaron"}, + {0x00ca, "Ecircumflex"}, + {0xf7ea, "Ecircumflexsmall"}, + {0x00cb, "Edieresis"}, + {0xf7eb, "Edieresissmall"}, + {0x0116, "Edotaccent"}, + {0x00c8, "Egrave"}, + {0xf7e8, "Egravesmall"}, + {0x0112, "Emacron"}, + {0x014a, "Eng"}, + {0x0118, "Eogonek"}, + {0x0395, "Epsilon"}, + {0x0388, "Epsilontonos"}, + {0xf765, "Esmall"}, + {0x0397, "Eta"}, + {0x0389, "Etatonos"}, + {0x00d0, "Eth"}, + {0xf7f0, "Ethsmall"}, + {0x20ac, "Euro"}, + {0x0046, "F"}, + {0xf766, "Fsmall"}, + {0x0047, "G"}, + {0x0393, "Gamma"}, + {0x011e, "Gbreve"}, + {0x01e6, "Gcaron"}, + {0x011c, "Gcircumflex"}, + {0x0122, "Gcommaaccent"}, + {0x0120, "Gdotaccent"}, + {0xf6ce, "Grave"}, + {0xf760, "Gravesmall"}, + {0xf767, "Gsmall"}, + {0x0048, "H"}, + {0x25cf, "H18533"}, + {0x25aa, "H18543"}, + {0x25ab, "H18551"}, + {0x25a1, "H22073"}, + {0x0126, "Hbar"}, + {0x0124, "Hcircumflex"}, + {0xf768, "Hsmall"}, + {0xf6cf, "Hungarumlaut"}, + {0xf6f8, "Hungarumlautsmall"}, + {0x0049, "I"}, + {0x0132, "IJ"}, + {0x00cd, "Iacute"}, + {0xf7ed, "Iacutesmall"}, + {0x012c, "Ibreve"}, + {0x00ce, "Icircumflex"}, + {0xf7ee, "Icircumflexsmall"}, + {0x00cf, "Idieresis"}, + {0xf7ef, "Idieresissmall"}, + {0x0130, "Idotaccent"}, + {0x2111, "Ifraktur"}, + {0x00cc, "Igrave"}, + {0xf7ec, "Igravesmall"}, + {0x012a, "Imacron"}, + {0x012e, "Iogonek"}, + {0x0399, "Iota"}, + {0x03aa, "Iotadieresis"}, + {0x038a, "Iotatonos"}, + {0xf769, "Ismall"}, + {0x0128, "Itilde"}, + {0x004a, "J"}, + {0x0134, "Jcircumflex"}, + {0xf76a, "Jsmall"}, + {0x004b, "K"}, + {0x039a, "Kappa"}, + {0x0136, "Kcommaaccent"}, + {0xf76b, "Ksmall"}, + {0x004c, "L"}, + {0xf6bf, "LL"}, + {0x0139, "Lacute"}, + {0x039b, "Lambda"}, + {0x013d, "Lcaron"}, + {0x013b, "Lcommaaccent"}, + {0x013f, "Ldot"}, + {0x0141, "Lslash"}, + {0xf6f9, "Lslashsmall"}, + {0xf76c, "Lsmall"}, + {0x004d, "M"}, + {0xf6d0, "Macron"}, + {0xf7af, "Macronsmall"}, + {0xf76d, "Msmall"}, + {0x039c, "Mu"}, + {0x004e, "N"}, + {0x0143, "Nacute"}, + {0x0147, "Ncaron"}, + {0x0145, "Ncommaaccent"}, + {0xf76e, "Nsmall"}, + {0x00d1, "Ntilde"}, + {0xf7f1, "Ntildesmall"}, + {0x039d, "Nu"}, + {0x004f, "O"}, + {0x0152, "OE"}, + {0xf6fa, "OEsmall"}, + {0x00d3, "Oacute"}, + {0xf7f3, "Oacutesmall"}, + {0x014e, "Obreve"}, + {0x00d4, "Ocircumflex"}, + {0xf7f4, "Ocircumflexsmall"}, + {0x00d6, "Odieresis"}, + {0xf7f6, "Odieresissmall"}, + {0xf6fb, "Ogoneksmall"}, + {0x00d2, "Ograve"}, + {0xf7f2, "Ogravesmall"}, + {0x01a0, "Ohorn"}, + {0x0150, "Ohungarumlaut"}, + {0x014c, "Omacron"}, + {0x2126, "Omega"}, + {0x038f, "Omegatonos"}, + {0x039f, "Omicron"}, + {0x038c, "Omicrontonos"}, + {0x00d8, "Oslash"}, + {0x01fe, "Oslashacute"}, + {0xf7f8, "Oslashsmall"}, + {0xf76f, "Osmall"}, + {0x00d5, "Otilde"}, + {0xf7f5, "Otildesmall"}, + {0x0050, "P"}, + {0x03a6, "Phi"}, + {0x03a0, "Pi"}, + {0x03a8, "Psi"}, + {0xf770, "Psmall"}, + {0x0051, "Q"}, + {0xf771, "Qsmall"}, + {0x0052, "R"}, + {0x0154, "Racute"}, + {0x0158, "Rcaron"}, + {0x0156, "Rcommaaccent"}, + {0x211c, "Rfraktur"}, + {0x03a1, "Rho"}, + {0xf6fc, "Ringsmall"}, + {0xf772, "Rsmall"}, + {0x0053, "S"}, + {0x250c, "SF010000"}, + {0x2514, "SF020000"}, + {0x2510, "SF030000"}, + {0x2518, "SF040000"}, + {0x253c, "SF050000"}, + {0x252c, "SF060000"}, + {0x2534, "SF070000"}, + {0x251c, "SF080000"}, + {0x2524, "SF090000"}, + {0x2500, "SF100000"}, + {0x2502, "SF110000"}, + {0x2561, "SF190000"}, + {0x2562, "SF200000"}, + {0x2556, "SF210000"}, + {0x2555, "SF220000"}, + {0x2563, "SF230000"}, + {0x2551, "SF240000"}, + {0x2557, "SF250000"}, + {0x255d, "SF260000"}, + {0x255c, "SF270000"}, + {0x255b, "SF280000"}, + {0x255e, "SF360000"}, + {0x255f, "SF370000"}, + {0x255a, "SF380000"}, + {0x2554, "SF390000"}, + {0x2569, "SF400000"}, + {0x2566, "SF410000"}, + {0x2560, "SF420000"}, + {0x2550, "SF430000"}, + {0x256c, "SF440000"}, + {0x2567, "SF450000"}, + {0x2568, "SF460000"}, + {0x2564, "SF470000"}, + {0x2565, "SF480000"}, + {0x2559, "SF490000"}, + {0x2558, "SF500000"}, + {0x2552, "SF510000"}, + {0x2553, "SF520000"}, + {0x256b, "SF530000"}, + {0x256a, "SF540000"}, + {0x015a, "Sacute"}, + {0x0160, "Scaron"}, + {0xf6fd, "Scaronsmall"}, + {0x015e, "Scedilla"}, + {0x015c, "Scircumflex"}, + {0x0218, "Scommaaccent"}, + {0x03a3, "Sigma"}, + {0xf773, "Ssmall"}, + {0x0054, "T"}, + {0x03a4, "Tau"}, + {0x0166, "Tbar"}, + {0x0164, "Tcaron"}, + {0x0162, "Tcommaaccent"}, + {0x0398, "Theta"}, + {0x00de, "Thorn"}, + {0xf7fe, "Thornsmall"}, + {0xf6fe, "Tildesmall"}, + {0xf774, "Tsmall"}, + {0x0055, "U"}, + {0x00da, "Uacute"}, + {0xf7fa, "Uacutesmall"}, + {0x016c, "Ubreve"}, + {0x00db, "Ucircumflex"}, + {0xf7fb, "Ucircumflexsmall"}, + {0x00dc, "Udieresis"}, + {0xf7fc, "Udieresissmall"}, + {0x00d9, "Ugrave"}, + {0xf7f9, "Ugravesmall"}, + {0x01af, "Uhorn"}, + {0x0170, "Uhungarumlaut"}, + {0x016a, "Umacron"}, + {0x0172, "Uogonek"}, + {0x03a5, "Upsilon"}, + {0x03d2, "Upsilon1"}, + {0x03ab, "Upsilondieresis"}, + {0x038e, "Upsilontonos"}, + {0x016e, "Uring"}, + {0xf775, "Usmall"}, + {0x0168, "Utilde"}, + {0x0056, "V"}, + {0xf776, "Vsmall"}, + {0x0057, "W"}, + {0x1e82, "Wacute"}, + {0x0174, "Wcircumflex"}, + {0x1e84, "Wdieresis"}, + {0x1e80, "Wgrave"}, + {0xf777, "Wsmall"}, + {0x0058, "X"}, + {0x039e, "Xi"}, + {0xf778, "Xsmall"}, + {0x0059, "Y"}, + {0x00dd, "Yacute"}, + {0xf7fd, "Yacutesmall"}, + {0x0176, "Ycircumflex"}, + {0x0178, "Ydieresis"}, + {0xf7ff, "Ydieresissmall"}, + {0x1ef2, "Ygrave"}, + {0xf779, "Ysmall"}, + {0x005a, "Z"}, + {0x0179, "Zacute"}, + {0x017d, "Zcaron"}, + {0xf6ff, "Zcaronsmall"}, + {0x017b, "Zdotaccent"}, + {0x0396, "Zeta"}, + {0xf77a, "Zsmall"}, + {0x0022, "\""}, + {0x005c, "\\"}, + {0x005d, "]"}, + {0x005e, "^"}, + {0x005f, "_"}, + {0x0060, "`"}, + {0x0061, "a"}, + {0x00e1, "aacute"}, + {0x0103, "abreve"}, + {0x00e2, "acircumflex"}, + {0x00b4, "acute"}, + {0x0301, "acutecomb"}, + {0x00e4, "adieresis"}, + {0x00e6, "ae"}, + {0x01fd, "aeacute"}, + {0x2015, "afii00208"}, + {0x0410, "afii10017"}, + {0x0411, "afii10018"}, + {0x0412, "afii10019"}, + {0x0413, "afii10020"}, + {0x0414, "afii10021"}, + {0x0415, "afii10022"}, + {0x0401, "afii10023"}, + {0x0416, "afii10024"}, + {0x0417, "afii10025"}, + {0x0418, "afii10026"}, + {0x0419, "afii10027"}, + {0x041a, "afii10028"}, + {0x041b, "afii10029"}, + {0x041c, "afii10030"}, + {0x041d, "afii10031"}, + {0x041e, "afii10032"}, + {0x041f, "afii10033"}, + {0x0420, "afii10034"}, + {0x0421, "afii10035"}, + {0x0422, "afii10036"}, + {0x0423, "afii10037"}, + {0x0424, "afii10038"}, + {0x0425, "afii10039"}, + {0x0426, "afii10040"}, + {0x0427, "afii10041"}, + {0x0428, "afii10042"}, + {0x0429, "afii10043"}, + {0x042a, "afii10044"}, + {0x042b, "afii10045"}, + {0x042c, "afii10046"}, + {0x042d, "afii10047"}, + {0x042e, "afii10048"}, + {0x042f, "afii10049"}, + {0x0490, "afii10050"}, + {0x0402, "afii10051"}, + {0x0403, "afii10052"}, + {0x0404, "afii10053"}, + {0x0405, "afii10054"}, + {0x0406, "afii10055"}, + {0x0407, "afii10056"}, + {0x0408, "afii10057"}, + {0x0409, "afii10058"}, + {0x040a, "afii10059"}, + {0x040b, "afii10060"}, + {0x040c, "afii10061"}, + {0x040e, "afii10062"}, + {0xf6c4, "afii10063"}, + {0xf6c5, "afii10064"}, + {0x0430, "afii10065"}, + {0x0431, "afii10066"}, + {0x0432, "afii10067"}, + {0x0433, "afii10068"}, + {0x0434, "afii10069"}, + {0x0435, "afii10070"}, + {0x0451, "afii10071"}, + {0x0436, "afii10072"}, + {0x0437, "afii10073"}, + {0x0438, "afii10074"}, + {0x0439, "afii10075"}, + {0x043a, "afii10076"}, + {0x043b, "afii10077"}, + {0x043c, "afii10078"}, + {0x043d, "afii10079"}, + {0x043e, "afii10080"}, + {0x043f, "afii10081"}, + {0x0440, "afii10082"}, + {0x0441, "afii10083"}, + {0x0442, "afii10084"}, + {0x0443, "afii10085"}, + {0x0444, "afii10086"}, + {0x0445, "afii10087"}, + {0x0446, "afii10088"}, + {0x0447, "afii10089"}, + {0x0448, "afii10090"}, + {0x0449, "afii10091"}, + {0x044a, "afii10092"}, + {0x044b, "afii10093"}, + {0x044c, "afii10094"}, + {0x044d, "afii10095"}, + {0x044e, "afii10096"}, + {0x044f, "afii10097"}, + {0x0491, "afii10098"}, + {0x0452, "afii10099"}, + {0x0453, "afii10100"}, + {0x0454, "afii10101"}, + {0x0455, "afii10102"}, + {0x0456, "afii10103"}, + {0x0457, "afii10104"}, + {0x0458, "afii10105"}, + {0x0459, "afii10106"}, + {0x045a, "afii10107"}, + {0x045b, "afii10108"}, + {0x045c, "afii10109"}, + {0x045e, "afii10110"}, + {0x040f, "afii10145"}, + {0x0462, "afii10146"}, + {0x0472, "afii10147"}, + {0x0474, "afii10148"}, + {0xf6c6, "afii10192"}, + {0x045f, "afii10193"}, + {0x0463, "afii10194"}, + {0x0473, "afii10195"}, + {0x0475, "afii10196"}, + {0xf6c7, "afii10831"}, + {0xf6c8, "afii10832"}, + {0x04d9, "afii10846"}, + {0x200e, "afii299"}, + {0x200f, "afii300"}, + {0x200d, "afii301"}, + {0x066a, "afii57381"}, + {0x060c, "afii57388"}, + {0x0660, "afii57392"}, + {0x0661, "afii57393"}, + {0x0662, "afii57394"}, + {0x0663, "afii57395"}, + {0x0664, "afii57396"}, + {0x0665, "afii57397"}, + {0x0666, "afii57398"}, + {0x0667, "afii57399"}, + {0x0668, "afii57400"}, + {0x0669, "afii57401"}, + {0x061b, "afii57403"}, + {0x061f, "afii57407"}, + {0x0621, "afii57409"}, + {0x0622, "afii57410"}, + {0x0623, "afii57411"}, + {0x0624, "afii57412"}, + {0x0625, "afii57413"}, + {0x0626, "afii57414"}, + {0x0627, "afii57415"}, + {0x0628, "afii57416"}, + {0x0629, "afii57417"}, + {0x062a, "afii57418"}, + {0x062b, "afii57419"}, + {0x062c, "afii57420"}, + {0x062d, "afii57421"}, + {0x062e, "afii57422"}, + {0x062f, "afii57423"}, + {0x0630, "afii57424"}, + {0x0631, "afii57425"}, + {0x0632, "afii57426"}, + {0x0633, "afii57427"}, + {0x0634, "afii57428"}, + {0x0635, "afii57429"}, + {0x0636, "afii57430"}, + {0x0637, "afii57431"}, + {0x0638, "afii57432"}, + {0x0639, "afii57433"}, + {0x063a, "afii57434"}, + {0x0640, "afii57440"}, + {0x0641, "afii57441"}, + {0x0642, "afii57442"}, + {0x0643, "afii57443"}, + {0x0644, "afii57444"}, + {0x0645, "afii57445"}, + {0x0646, "afii57446"}, + {0x0648, "afii57448"}, + {0x0649, "afii57449"}, + {0x064a, "afii57450"}, + {0x064b, "afii57451"}, + {0x064c, "afii57452"}, + {0x064d, "afii57453"}, + {0x064e, "afii57454"}, + {0x064f, "afii57455"}, + {0x0650, "afii57456"}, + {0x0651, "afii57457"}, + {0x0652, "afii57458"}, + {0x0647, "afii57470"}, + {0x06a4, "afii57505"}, + {0x067e, "afii57506"}, + {0x0686, "afii57507"}, + {0x0698, "afii57508"}, + {0x06af, "afii57509"}, + {0x0679, "afii57511"}, + {0x0688, "afii57512"}, + {0x0691, "afii57513"}, + {0x06ba, "afii57514"}, + {0x06d2, "afii57519"}, + {0x06d5, "afii57534"}, + {0x20aa, "afii57636"}, + {0x05be, "afii57645"}, + {0x05c3, "afii57658"}, + {0x05d0, "afii57664"}, + {0x05d1, "afii57665"}, + {0x05d2, "afii57666"}, + {0x05d3, "afii57667"}, + {0x05d4, "afii57668"}, + {0x05d5, "afii57669"}, + {0x05d6, "afii57670"}, + {0x05d7, "afii57671"}, + {0x05d8, "afii57672"}, + {0x05d9, "afii57673"}, + {0x05da, "afii57674"}, + {0x05db, "afii57675"}, + {0x05dc, "afii57676"}, + {0x05dd, "afii57677"}, + {0x05de, "afii57678"}, + {0x05df, "afii57679"}, + {0x05e0, "afii57680"}, + {0x05e1, "afii57681"}, + {0x05e2, "afii57682"}, + {0x05e3, "afii57683"}, + {0x05e4, "afii57684"}, + {0x05e5, "afii57685"}, + {0x05e6, "afii57686"}, + {0x05e7, "afii57687"}, + {0x05e8, "afii57688"}, + {0x05e9, "afii57689"}, + {0x05ea, "afii57690"}, + {0xfb2a, "afii57694"}, + {0xfb2b, "afii57695"}, + {0xfb4b, "afii57700"}, + {0xfb1f, "afii57705"}, + {0x05f0, "afii57716"}, + {0x05f1, "afii57717"}, + {0x05f2, "afii57718"}, + {0xfb35, "afii57723"}, + {0x05b4, "afii57793"}, + {0x05b5, "afii57794"}, + {0x05b6, "afii57795"}, + {0x05bb, "afii57796"}, + {0x05b8, "afii57797"}, + {0x05b7, "afii57798"}, + {0x05b0, "afii57799"}, + {0x05b2, "afii57800"}, + {0x05b1, "afii57801"}, + {0x05b3, "afii57802"}, + {0x05c2, "afii57803"}, + {0x05c1, "afii57804"}, + {0x05b9, "afii57806"}, + {0x05bc, "afii57807"}, + {0x05bd, "afii57839"}, + {0x05bf, "afii57841"}, + {0x05c0, "afii57842"}, + {0x02bc, "afii57929"}, + {0x2105, "afii61248"}, + {0x2113, "afii61289"}, + {0x2116, "afii61352"}, + {0x202c, "afii61573"}, + {0x202d, "afii61574"}, + {0x202e, "afii61575"}, + {0x200c, "afii61664"}, + {0x066d, "afii63167"}, + {0x02bd, "afii64937"}, + {0x00e0, "agrave"}, + {0x2135, "aleph"}, + {0x03b1, "alpha"}, + {0x03ac, "alphatonos"}, + {0x0101, "amacron"}, + {0x0026, "ampersand"}, + {0xf726, "ampersandsmall"}, + {0x2220, "angle"}, + {0x2329, "angleleft"}, + {0x232a, "angleright"}, + {0x0387, "anoteleia"}, + {0x0105, "aogonek"}, + {0x2248, "approxequal"}, + {0x00e5, "aring"}, + {0x01fb, "aringacute"}, + {0x2194, "arrowboth"}, + {0x21d4, "arrowdblboth"}, + {0x21d3, "arrowdbldown"}, + {0x21d0, "arrowdblleft"}, + {0x21d2, "arrowdblright"}, + {0x21d1, "arrowdblup"}, + {0x2193, "arrowdown"}, + {0xf8e7, "arrowhorizex"}, + {0x2190, "arrowleft"}, + {0x2192, "arrowright"}, + {0x2191, "arrowup"}, + {0x2195, "arrowupdn"}, + {0x21a8, "arrowupdnbse"}, + {0xf8e6, "arrowvertex"}, + {0x005e, "asciicircum"}, + {0x007e, "asciitilde"}, + {0x002a, "asterisk"}, + {0x2217, "asteriskmath"}, + {0xf6e9, "asuperior"}, + {0x0040, "at"}, + {0x00e3, "atilde"}, + {0x0062, "b"}, + {0x005c, "backslash"}, + {0x007c, "bar"}, + {0x03b2, "beta"}, + {0x2588, "block"}, + {0xf8f4, "braceex"}, + {0x007b, "braceleft"}, + {0xf8f3, "braceleftbt"}, + {0xf8f2, "braceleftmid"}, + {0xf8f1, "bracelefttp"}, + {0x007d, "braceright"}, + {0xf8fe, "bracerightbt"}, + {0xf8fd, "bracerightmid"}, + {0xf8fc, "bracerighttp"}, + {0x005b, "bracketleft"}, + {0xf8f0, "bracketleftbt"}, + {0xf8ef, "bracketleftex"}, + {0xf8ee, "bracketlefttp"}, + {0x005d, "bracketright"}, + {0xf8fb, "bracketrightbt"}, + {0xf8fa, "bracketrightex"}, + {0xf8f9, "bracketrighttp"}, + {0x02d8, "breve"}, + {0x00a6, "brokenbar"}, + {0xf6ea, "bsuperior"}, + {0x2022, "bullet"}, + {0x0063, "c"}, + {0x0107, "cacute"}, + {0x02c7, "caron"}, + {0x21b5, "carriagereturn"}, + {0x010d, "ccaron"}, + {0x00e7, "ccedilla"}, + {0x0109, "ccircumflex"}, + {0x010b, "cdotaccent"}, + {0x00b8, "cedilla"}, + {0x00a2, "cent"}, + {0xf6df, "centinferior"}, + {0xf7a2, "centoldstyle"}, + {0xf6e0, "centsuperior"}, + {0x03c7, "chi"}, + {0x25cb, "circle"}, + {0x2297, "circlemultiply"}, + {0x2295, "circleplus"}, + {0x02c6, "circumflex"}, + {0x2663, "club"}, + {0x003a, "colon"}, + {0x20a1, "colonmonetary"}, + {0x002c, "comma"}, + {0xf6c3, "commaaccent"}, + {0xf6e1, "commainferior"}, + {0xf6e2, "commasuperior"}, + {0x2245, "congruent"}, + {0x00a9, "copyright"}, + {0x00a9, "copyrightsans"}, + {0x00a9, "copyrightserif"}, + {0x00a4, "currency"}, + {0xf6d1, "cyrBreve"}, + {0xf6d2, "cyrFlex"}, + {0xf6d4, "cyrbreve"}, + {0xf6d5, "cyrflex"}, + {0x0064, "d"}, + {0x2020, "dagger"}, + {0x2021, "daggerdbl"}, + {0xf6d3, "dblGrave"}, + {0xf6d6, "dblgrave"}, + {0x010f, "dcaron"}, + {0x0111, "dcroat"}, + {0x00b0, "degree"}, + {0x03b4, "delta"}, + {0x2666, "diamond"}, + {0x00a8, "dieresis"}, + {0xf6d7, "dieresisacute"}, + {0xf6d8, "dieresisgrave"}, + {0x0385, "dieresistonos"}, + {0x00f7, "divide"}, + {0x2593, "dkshade"}, + {0x2584, "dnblock"}, + {0x0024, "dollar"}, + {0xf6e3, "dollarinferior"}, + {0xf724, "dollaroldstyle"}, + {0xf6e4, "dollarsuperior"}, + {0x20ab, "dong"}, + {0x02d9, "dotaccent"}, + {0x0323, "dotbelowcomb"}, + {0x0131, "dotlessi"}, + {0xf6be, "dotlessj"}, + {0x22c5, "dotmath"}, + {0xf6eb, "dsuperior"}, + {0x0065, "e"}, + {0x00e9, "eacute"}, + {0x0115, "ebreve"}, + {0x011b, "ecaron"}, + {0x00ea, "ecircumflex"}, + {0x00eb, "edieresis"}, + {0x0117, "edotaccent"}, + {0x00e8, "egrave"}, + {0x0038, "eight"}, + {0x2088, "eightinferior"}, + {0xf738, "eightoldstyle"}, + {0x2078, "eightsuperior"}, + {0x2208, "element"}, + {0x2026, "ellipsis"}, + {0x0113, "emacron"}, + {0x2014, "emdash"}, + {0x2205, "emptyset"}, + {0x2013, "endash"}, + {0x014b, "eng"}, + {0x0119, "eogonek"}, + {0x03b5, "epsilon"}, + {0x03ad, "epsilontonos"}, + {0x003d, "equal"}, + {0x2261, "equivalence"}, + {0x212e, "estimated"}, + {0xf6ec, "esuperior"}, + {0x03b7, "eta"}, + {0x03ae, "etatonos"}, + {0x00f0, "eth"}, + {0x0021, "exclam"}, + {0x203c, "exclamdbl"}, + {0x00a1, "exclamdown"}, + {0xf7a1, "exclamdownsmall"}, + {0x0021, "exclamleft"}, + {0xf721, "exclamsmall"}, + {0x2203, "existential"}, + {0x0066, "f"}, + {0x2640, "female"}, + {0xfb00, "ff"}, + {0xfb03, "ffi"}, + {0xfb04, "ffl"}, + {0xfb01, "fi"}, + {0x2012, "figuredash"}, + {0x25a0, "filledbox"}, + {0x25ac, "filledrect"}, + {0x0035, "five"}, + {0x215d, "fiveeighths"}, + {0x2085, "fiveinferior"}, + {0xf735, "fiveoldstyle"}, + {0x2075, "fivesuperior"}, + {0xfb02, "fl"}, + {0x0192, "florin"}, + {0x0034, "four"}, + {0x2084, "fourinferior"}, + {0xf734, "fouroldstyle"}, + {0x2074, "foursuperior"}, + {0x2044, "fraction"}, + {0x20a3, "franc"}, + {0x0067, "g"}, + {0x03b3, "gamma"}, + {0x011f, "gbreve"}, + {0x01e7, "gcaron"}, + {0x011d, "gcircumflex"}, + {0x0123, "gcommaaccent"}, + {0x0121, "gdotaccent"}, + {0x00df, "germandbls"}, + {0x2207, "gradient"}, + {0x0060, "grave"}, + {0x0300, "gravecomb"}, + {0x003e, "greater"}, + {0x2265, "greaterequal"}, + {0x00ab, "guillemotleft"}, + {0x00bb, "guillemotright"}, + {0x2039, "guilsinglleft"}, + {0x203a, "guilsinglright"}, + {0x0068, "h"}, + {0x0127, "hbar"}, + {0x0125, "hcircumflex"}, + {0x2665, "heart"}, + {0x0309, "hookabovecomb"}, + {0x2302, "house"}, + {0x02dd, "hungarumlaut"}, + {0x002d, "hyphen"}, + {0xf6e5, "hypheninferior"}, + {0xf6e6, "hyphensuperior"}, + {0x0069, "i"}, + {0x00ed, "iacute"}, + {0x012d, "ibreve"}, + {0x00ee, "icircumflex"}, + {0x00ef, "idieresis"}, + {0x00ec, "igrave"}, + {0x0133, "ij"}, + {0x012b, "imacron"}, + {0x221e, "infinity"}, + {0x222b, "integral"}, + {0x2321, "integralbt"}, + {0xf8f5, "integralex"}, + {0x2320, "integraltp"}, + {0x2229, "intersection"}, + {0x25d8, "invbullet"}, + {0x25d9, "invcircle"}, + {0x263b, "invsmileface"}, + {0x012f, "iogonek"}, + {0x03b9, "iota"}, + {0x03ca, "iotadieresis"}, + {0x0390, "iotadieresistonos"}, + {0x03af, "iotatonos"}, + {0xf6ed, "isuperior"}, + {0x0129, "itilde"}, + {0x006a, "j"}, + {0x0135, "jcircumflex"}, + {0x006b, "k"}, + {0x03ba, "kappa"}, + {0x0137, "kcommaaccent"}, + {0x0138, "kgreenlandic"}, + {0x006c, "l"}, + {0x013a, "lacute"}, + {0x03bb, "lambda"}, + {0x013e, "lcaron"}, + {0x013c, "lcommaaccent"}, + {0x0140, "ldot"}, + {0x003c, "less"}, + {0x2264, "lessequal"}, + {0x258c, "lfblock"}, + {0x20a4, "lira"}, + {0xf6c0, "ll"}, + {0x2227, "logicaland"}, + {0x00ac, "logicalnot"}, + {0x2228, "logicalor"}, + {0x017f, "longs"}, + {0x25ca, "lozenge"}, + {0x0142, "lslash"}, + {0xf6ee, "lsuperior"}, + {0x2591, "ltshade"}, + {0x006d, "m"}, + {0x00af, "macron"}, + {0x2642, "male"}, + {0x2212, "minus"}, + {0x2032, "minute"}, + {0xf6ef, "msuperior"}, + {0x00b5, "mu"}, + {0x00d7, "multiply"}, + {0x266a, "musicalnote"}, + {0x266b, "musicalnotedbl"}, + {0x006e, "n"}, + {0x0144, "nacute"}, + {0x0149, "napostrophe"}, + {0x00a0, "nbspace"}, + {0x0148, "ncaron"}, + {0x0146, "ncommaaccent"}, + {0x0039, "nine"}, + {0x2089, "nineinferior"}, + {0xf739, "nineoldstyle"}, + {0x2079, "ninesuperior"}, + {0x00a0, "nonbreakingspace"}, + {0x2209, "notelement"}, + {0x2260, "notequal"}, + {0x2284, "notsubset"}, + {0x207f, "nsuperior"}, + {0x00f1, "ntilde"}, + {0x03bd, "nu"}, + {0x0023, "numbersign"}, + {0x006f, "o"}, + {0x00f3, "oacute"}, + {0x014f, "obreve"}, + {0x00f4, "ocircumflex"}, + {0x00f6, "odieresis"}, + {0x0153, "oe"}, + {0x02db, "ogonek"}, + {0x00f2, "ograve"}, + {0x01a1, "ohorn"}, + {0x0151, "ohungarumlaut"}, + {0x014d, "omacron"}, + {0x03c9, "omega"}, + {0x03d6, "omega1"}, + {0x03ce, "omegatonos"}, + {0x03bf, "omicron"}, + {0x03cc, "omicrontonos"}, + {0x0031, "one"}, + {0x2024, "onedotenleader"}, + {0x215b, "oneeighth"}, + {0xf6dc, "onefitted"}, + {0x00bd, "onehalf"}, + {0x2081, "oneinferior"}, + {0xf731, "oneoldstyle"}, + {0x00bc, "onequarter"}, + {0x00b9, "onesuperior"}, + {0x2153, "onethird"}, + {0x25e6, "openbullet"}, + {0x00aa, "ordfeminine"}, + {0x00ba, "ordmasculine"}, + {0x221f, "orthogonal"}, + {0x00f8, "oslash"}, + {0x01ff, "oslashacute"}, + {0xf6f0, "osuperior"}, + {0x00f5, "otilde"}, + {0x0070, "p"}, + {0x00b6, "paragraph"}, + {0x0028, "parenleft"}, + {0xf8ed, "parenleftbt"}, + {0xf8ec, "parenleftex"}, + {0x208d, "parenleftinferior"}, + {0x207d, "parenleftsuperior"}, + {0xf8eb, "parenlefttp"}, + {0x0029, "parenright"}, + {0xf8f8, "parenrightbt"}, + {0xf8f7, "parenrightex"}, + {0x208e, "parenrightinferior"}, + {0x207e, "parenrightsuperior"}, + {0xf8f6, "parenrighttp"}, + {0x2202, "partialdiff"}, + {0x0025, "percent"}, + {0x002e, "period"}, + {0x00b7, "periodcentered"}, + {0xf6e7, "periodinferior"}, + {0xf6e8, "periodsuperior"}, + {0x22a5, "perpendicular"}, + {0x2030, "perthousand"}, + {0x20a7, "peseta"}, + {0x03c6, "phi"}, + {0x03d5, "phi1"}, + {0x03c0, "pi"}, + {0x002b, "plus"}, + {0x00b1, "plusminus"}, + {0x211e, "prescription"}, + {0x220f, "product"}, + {0x2282, "propersubset"}, + {0x2283, "propersuperset"}, + {0x221d, "proportional"}, + {0x03c8, "psi"}, + {0x0071, "q"}, + {0x003f, "question"}, + {0x00bf, "questiondown"}, + {0xf7bf, "questiondownsmall"}, + {0xf73f, "questionsmall"}, + {0x0022, "quotedbl"}, + {0x201e, "quotedblbase"}, + {0x201c, "quotedblleft"}, + {0x201d, "quotedblright"}, + {0x2018, "quoteleft"}, + {0x201b, "quotereversed"}, + {0x2019, "quoteright"}, + {0x201a, "quotesinglbase"}, + {0x0027, "quotesingle"}, + {0x0072, "r"}, + {0x0155, "racute"}, + {0x221a, "radical"}, + {0xf8e5, "radicalex"}, + {0x0159, "rcaron"}, + {0x0157, "rcommaaccent"}, + {0x2286, "reflexsubset"}, + {0x2287, "reflexsuperset"}, + {0x00ae, "registered"}, + {0x00ae, "registersans"}, + {0x00ae, "registerserif"}, + {0x2310, "revlogicalnot"}, + {0x03c1, "rho"}, + {0x02da, "ring"}, + {0xf6f1, "rsuperior"}, + {0x2590, "rtblock"}, + {0xf6dd, "rupiah"}, + {0x0073, "s"}, + {0x015b, "sacute"}, + {0x0161, "scaron"}, + {0x015f, "scedilla"}, + {0x015d, "scircumflex"}, + {0x0219, "scommaaccent"}, + {0x2033, "second"}, + {0x00a7, "section"}, + {0x003b, "semicolon"}, + {0x0037, "seven"}, + {0x215e, "seveneighths"}, + {0x2087, "seveninferior"}, + {0xf737, "sevenoldstyle"}, + {0x2077, "sevensuperior"}, + {0x2592, "shade"}, + {0x03c3, "sigma"}, + {0x03c2, "sigma1"}, + {0x223c, "similar"}, + {0x0036, "six"}, + {0x2086, "sixinferior"}, + {0xf736, "sixoldstyle"}, + {0x2076, "sixsuperior"}, + {0x002f, "slash"}, + {0x263a, "smileface"}, + {0x0020, "space"}, + {0x2660, "spade"}, + {0xf6f2, "ssuperior"}, + {0x00a3, "sterling"}, + {0x220b, "suchthat"}, + {0x2211, "summation"}, + {0x263c, "sun"}, + {0x0074, "t"}, + {0x03c4, "tau"}, + {0x0167, "tbar"}, + {0x0165, "tcaron"}, + {0x0163, "tcommaaccent"}, + {0x2234, "therefore"}, + {0x03b8, "theta"}, + {0x03d1, "theta1"}, + {0x00fe, "thorn"}, + {0x0033, "three"}, + {0x215c, "threeeighths"}, + {0x2083, "threeinferior"}, + {0xf733, "threeoldstyle"}, + {0x00be, "threequarters"}, + {0xf6de, "threequartersemdash"}, + {0x00b3, "threesuperior"}, + {0x02dc, "tilde"}, + {0x0303, "tildecomb"}, + {0x0384, "tonos"}, + {0x2122, "trademark"}, + {0x2122, "trademarksans"}, + {0x2122, "trademarkserif"}, + {0x25bc, "triagdn"}, + {0x25c4, "triaglf"}, + {0x25ba, "triagrt"}, + {0x25b2, "triagup"}, + {0xf6f3, "tsuperior"}, + {0x0032, "two"}, + {0x2025, "twodotenleader"}, + {0x2082, "twoinferior"}, + {0xf732, "twooldstyle"}, + {0x00b2, "twosuperior"}, + {0x2154, "twothirds"}, + {0x0075, "u"}, + {0x00fa, "uacute"}, + {0x016d, "ubreve"}, + {0x00fb, "ucircumflex"}, + {0x00fc, "udieresis"}, + {0x00f9, "ugrave"}, + {0x01b0, "uhorn"}, + {0x0171, "uhungarumlaut"}, + {0x016b, "umacron"}, + {0x005f, "underscore"}, + {0x2017, "underscoredbl"}, + {0x222a, "union"}, + {0x2200, "universal"}, + {0x0173, "uogonek"}, + {0x2580, "upblock"}, + {0x03c5, "upsilon"}, + {0x03cb, "upsilondieresis"}, + {0x03b0, "upsilondieresistonos"}, + {0x03cd, "upsilontonos"}, + {0x016f, "uring"}, + {0x0169, "utilde"}, + {0x0076, "v"}, + {0x0077, "w"}, + {0x1e83, "wacute"}, + {0x0175, "wcircumflex"}, + {0x1e85, "wdieresis"}, + {0x2118, "weierstrass"}, + {0x1e81, "wgrave"}, + {0x0078, "x"}, + {0x03be, "xi"}, + {0x0079, "y"}, + {0x00fd, "yacute"}, + {0x0177, "ycircumflex"}, + {0x00ff, "ydieresis"}, + {0x00a5, "yen"}, + {0x1ef3, "ygrave"}, + {0x007a, "z"}, + {0x017a, "zacute"}, + {0x017e, "zcaron"}, + {0x017c, "zdotaccent"}, + {0x0030, "zero"}, + {0x2080, "zeroinferior"}, + {0xf730, "zerooldstyle"}, + {0x2070, "zerosuperior"}, + {0x03b6, "zeta"}, + {0x007b, "{"}, + {0x007c, "|"}, + {0x007d, "}"}, + {0x007e, "~"}, + { 0, NULL } +}; diff --git a/kpdf/xpdf/xpdf/Object.cc b/kpdf/xpdf/xpdf/Object.cc new file mode 100644 index 00000000..f0a3a092 --- /dev/null +++ b/kpdf/xpdf/xpdf/Object.cc @@ -0,0 +1,233 @@ +//======================================================================== +// +// Object.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "Object.h" +#include "Array.h" +#include "Dict.h" +#include "Error.h" +#include "Stream.h" +#include "XRef.h" + +//------------------------------------------------------------------------ +// Object +//------------------------------------------------------------------------ + +char *objTypeNames[numObjTypes] = { + "boolean", + "integer", + "real", + "string", + "name", + "null", + "array", + "dictionary", + "stream", + "ref", + "cmd", + "error", + "eof", + "none" +}; + +#ifdef DEBUG_MEM +int Object::numAlloc[numObjTypes] = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +#endif + +Object *Object::initArray(XRef *xref) { + initObj(objArray); + array = new Array(xref); + return this; +} + +Object *Object::initDict(XRef *xref) { + initObj(objDict); + dict = new Dict(xref); + return this; +} + +Object *Object::initDict(Dict *dictA) { + initObj(objDict); + dict = dictA; + dict->incRef(); + return this; +} + +Object *Object::initStream(Stream *streamA) { + initObj(objStream); + stream = streamA; + return this; +} + +Object *Object::copy(Object *obj) { + *obj = *this; + switch (type) { + case objString: + obj->string = string->copy(); + break; + case objName: + obj->name = copyString(name); + break; + case objArray: + array->incRef(); + break; + case objDict: + dict->incRef(); + break; + case objStream: + stream->incRef(); + break; + case objCmd: + obj->cmd = copyString(cmd); + break; + default: + break; + } +#ifdef DEBUG_MEM + ++numAlloc[type]; +#endif + return obj; +} + +Object *Object::fetch(XRef *xref, Object *obj) { + return (type == objRef && xref) ? + xref->fetch(ref.num, ref.gen, obj) : copy(obj); +} + +void Object::free() { + switch (type) { + case objString: + delete string; + break; + case objName: + gfree(name); + break; + case objArray: + if (!array->decRef()) { + delete array; + } + break; + case objDict: + if (!dict->decRef()) { + delete dict; + } + break; + case objStream: + if (!stream->decRef()) { + delete stream; + } + break; + case objCmd: + gfree(cmd); + break; + default: + break; + } +#ifdef DEBUG_MEM + --numAlloc[type]; +#endif + type = objNone; +} + +char *Object::getTypeName() { + return objTypeNames[type]; +} + +void Object::print(FILE *f) { + Object obj; + int i; + + switch (type) { + case objBool: + fprintf(f, "%s", booln ? "true" : "false"); + break; + case objInt: + fprintf(f, "%d", intg); + break; + case objReal: + fprintf(f, "%g", real); + break; + case objString: + fprintf(f, "("); + fwrite(string->getCString(), 1, string->getLength(), f); + fprintf(f, ")"); + break; + case objName: + fprintf(f, "/%s", name); + break; + case objNull: + fprintf(f, "null"); + break; + case objArray: + fprintf(f, "["); + for (i = 0; i < arrayGetLength(); ++i) { + if (i > 0) + fprintf(f, " "); + arrayGetNF(i, &obj); + obj.print(f); + obj.free(); + } + fprintf(f, "]"); + break; + case objDict: + fprintf(f, "<<"); + for (i = 0; i < dictGetLength(); ++i) { + fprintf(f, " /%s ", dictGetKey(i)); + dictGetValNF(i, &obj); + obj.print(f); + obj.free(); + } + fprintf(f, " >>"); + break; + case objStream: + fprintf(f, ""); + break; + case objRef: + fprintf(f, "%d %d R", ref.num, ref.gen); + break; + case objCmd: + fprintf(f, "%s", cmd); + break; + case objError: + fprintf(f, ""); + break; + case objEOF: + fprintf(f, ""); + break; + case objNone: + fprintf(f, ""); + break; + } +} + +void Object::memCheck(FILE *f) { +#ifdef DEBUG_MEM + int i; + int t; + + t = 0; + for (i = 0; i < numObjTypes; ++i) + t += numAlloc[i]; + if (t > 0) { + fprintf(f, "Allocated objects:\n"); + for (i = 0; i < numObjTypes; ++i) { + if (numAlloc[i] > 0) + fprintf(f, " %-20s: %6d\n", objTypeNames[i], numAlloc[i]); + } + } +#else + (void)f; +#endif +} diff --git a/kpdf/xpdf/xpdf/Object.h b/kpdf/xpdf/xpdf/Object.h new file mode 100644 index 00000000..8b1807c5 --- /dev/null +++ b/kpdf/xpdf/xpdf/Object.h @@ -0,0 +1,303 @@ +//======================================================================== +// +// Object.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef OBJECT_H +#define OBJECT_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include +#include +#include "gtypes.h" +#include "gmem.h" +#include "GString.h" + +class XRef; +class Array; +class Dict; +class Stream; + +//------------------------------------------------------------------------ +// Ref +//------------------------------------------------------------------------ + +struct Ref { + int num; // object number + int gen; // generation number +}; + +//------------------------------------------------------------------------ +// object types +//------------------------------------------------------------------------ + +enum ObjType { + // simple objects + objBool, // boolean + objInt, // integer + objReal, // real + objString, // string + objName, // name + objNull, // null + + // complex objects + objArray, // array + objDict, // dictionary + objStream, // stream + objRef, // indirect reference + + // special objects + objCmd, // command name + objError, // error return from Lexer + objEOF, // end of file return from Lexer + objNone // uninitialized object +}; + +#define numObjTypes 14 // total number of object types + +//------------------------------------------------------------------------ +// Object +//------------------------------------------------------------------------ + +#ifdef DEBUG_MEM +#define initObj(t) ++numAlloc[type = t] +#else +#define initObj(t) type = t +#endif + +class Object { +public: + + // Default constructor. + Object(): + type(objNone) {} + + // Initialize an object. + Object *initBool(GBool boolnA) + { initObj(objBool); booln = boolnA; return this; } + Object *initInt(int intgA) + { initObj(objInt); intg = intgA; return this; } + Object *initReal(double realA) + { initObj(objReal); real = realA; return this; } + Object *initString(GString *stringA) + { initObj(objString); string = stringA; return this; } + Object *initName(char *nameA) + { initObj(objName); name = copyString(nameA); return this; } + Object *initNull() + { initObj(objNull); return this; } + Object *initArray(XRef *xref); + Object *initDict(XRef *xref); + Object *initDict(Dict *dictA); + Object *initStream(Stream *streamA); + Object *initRef(int numA, int genA) + { initObj(objRef); ref.num = numA; ref.gen = genA; return this; } + Object *initCmd(char *cmdA) + { initObj(objCmd); cmd = copyString(cmdA); return this; } + Object *initError() + { initObj(objError); return this; } + Object *initEOF() + { initObj(objEOF); return this; } + + // Copy an object. + Object *copy(Object *obj); + + // If object is a Ref, fetch and return the referenced object. + // Otherwise, return a copy of the object. + Object *fetch(XRef *xref, Object *obj); + + // Free object contents. + void free(); + + // Type checking. + ObjType getType() { return type; } + GBool isBool() { return type == objBool; } + GBool isInt() { return type == objInt; } + GBool isReal() { return type == objReal; } + GBool isNum() { return type == objInt || type == objReal; } + GBool isString() { return type == objString; } + GBool isName() { return type == objName; } + GBool isNull() { return type == objNull; } + GBool isArray() { return type == objArray; } + GBool isDict() { return type == objDict; } + GBool isStream() { return type == objStream; } + GBool isRef() { return type == objRef; } + GBool isCmd() { return type == objCmd; } + GBool isError() { return type == objError; } + GBool isEOF() { return type == objEOF; } + GBool isNone() { return type == objNone; } + + // Special type checking. + GBool isName(char *nameA) + { return type == objName && !strcmp(name, nameA); } + GBool isDict(char *dictType); + GBool isStream(char *dictType); + GBool isCmd(char *cmdA) + { return type == objCmd && !strcmp(cmd, cmdA); } + + // Accessors. NB: these assume object is of correct type. + GBool getBool() { return booln; } + int getInt() { return intg; } + double getReal() { return real; } + double getNum() { return type == objInt ? (double)intg : real; } + GString *getString() { return string; } + char *getName() { return name; } + Array *getArray() { return array; } + Dict *getDict() { return dict; } + Stream *getStream() { return stream; } + Ref getRef() { return ref; } + int getRefNum() { return ref.num; } + int getRefGen() { return ref.gen; } + char *getCmd() { return cmd; } + + // Array accessors. + int arrayGetLength(); + void arrayAdd(Object *elem); + Object *arrayGet(int i, Object *obj); + Object *arrayGetNF(int i, Object *obj); + + // Dict accessors. + int dictGetLength(); + void dictAdd(char *key, Object *val); + GBool dictIs(char *dictType); + Object *dictLookup(char *key, Object *obj); + Object *dictLookupNF(char *key, Object *obj); + char *dictGetKey(int i); + Object *dictGetVal(int i, Object *obj); + Object *dictGetValNF(int i, Object *obj); + + // Stream accessors. + GBool streamIs(char *dictType); + void streamReset(); + void streamClose(); + int streamGetChar(); + int streamLookChar(); + char *streamGetLine(char *buf, int size); + Guint streamGetPos(); + void streamSetPos(Guint pos, int dir = 0); + Dict *streamGetDict(); + + // Output. + char *getTypeName(); + void print(FILE *f = stdout); + + // Memory testing. + static void memCheck(FILE *f); + +private: + + ObjType type; // object type + union { // value for each type: + GBool booln; // boolean + int intg; // integer + double real; // real + GString *string; // string + char *name; // name + Array *array; // array + Dict *dict; // dictionary + Stream *stream; // stream + Ref ref; // indirect reference + char *cmd; // command + }; + +#ifdef DEBUG_MEM + static int // number of each type of object + numAlloc[numObjTypes]; // currently allocated +#endif +}; + +//------------------------------------------------------------------------ +// Array accessors. +//------------------------------------------------------------------------ + +#include "Array.h" + +inline int Object::arrayGetLength() + { return array->getLength(); } + +inline void Object::arrayAdd(Object *elem) + { array->add(elem); } + +inline Object *Object::arrayGet(int i, Object *obj) + { return array->get(i, obj); } + +inline Object *Object::arrayGetNF(int i, Object *obj) + { return array->getNF(i, obj); } + +//------------------------------------------------------------------------ +// Dict accessors. +//------------------------------------------------------------------------ + +#include "Dict.h" + +inline int Object::dictGetLength() + { return dict->getLength(); } + +inline void Object::dictAdd(char *key, Object *val) + { dict->add(key, val); } + +inline GBool Object::dictIs(char *dictType) + { return dict->is(dictType); } + +inline GBool Object::isDict(char *dictType) + { return type == objDict && dictIs(dictType); } + +inline Object *Object::dictLookup(char *key, Object *obj) + { return dict->lookup(key, obj); } + +inline Object *Object::dictLookupNF(char *key, Object *obj) + { return dict->lookupNF(key, obj); } + +inline char *Object::dictGetKey(int i) + { return dict->getKey(i); } + +inline Object *Object::dictGetVal(int i, Object *obj) + { return dict->getVal(i, obj); } + +inline Object *Object::dictGetValNF(int i, Object *obj) + { return dict->getValNF(i, obj); } + +//------------------------------------------------------------------------ +// Stream accessors. +//------------------------------------------------------------------------ + +#include "Stream.h" + +inline GBool Object::streamIs(char *dictType) + { return stream->getDict()->is(dictType); } + +inline GBool Object::isStream(char *dictType) + { return type == objStream && streamIs(dictType); } + +inline void Object::streamReset() + { stream->reset(); } + +inline void Object::streamClose() + { stream->close(); } + +inline int Object::streamGetChar() + { return stream->getChar(); } + +inline int Object::streamLookChar() + { return stream->lookChar(); } + +inline char *Object::streamGetLine(char *buf, int size) + { return stream->getLine(buf, size); } + +inline Guint Object::streamGetPos() + { return stream->getPos(); } + +inline void Object::streamSetPos(Guint pos, int dir) + { stream->setPos(pos, dir); } + +inline Dict *Object::streamGetDict() + { return stream->getDict(); } + +#endif diff --git a/kpdf/xpdf/xpdf/Outline.cc b/kpdf/xpdf/xpdf/Outline.cc new file mode 100644 index 00000000..39e89a3c --- /dev/null +++ b/kpdf/xpdf/xpdf/Outline.cc @@ -0,0 +1,151 @@ +//======================================================================== +// +// Outline.cc +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "gmem.h" +#include "GString.h" +#include "GList.h" +#include "Link.h" +#include "PDFDocEncoding.h" +#include "Outline.h" + +//------------------------------------------------------------------------ + +Outline::Outline(Object *outlineObj, XRef *xref) { + Object first, last; + + items = NULL; + if (!outlineObj->isDict()) { + return; + } + items = OutlineItem::readItemList(outlineObj->dictLookupNF("First", &first), + outlineObj->dictLookupNF("Last", &last), + xref); + first.free(); + last.free(); +} + +Outline::~Outline() { + if (items) { + deleteGList(items, OutlineItem); + } +} + +//------------------------------------------------------------------------ + +OutlineItem::OutlineItem(Dict *dict, XRef *xrefA) { + Object obj1; + GString *s; + int i; + + xref = xrefA; + title = NULL; + action = NULL; + kids = NULL; + + if (dict->lookup("Title", &obj1)->isString()) { + s = obj1.getString(); + if ((s->getChar(0) & 0xff) == 0xfe && + (s->getChar(1) & 0xff) == 0xff) { + titleLen = (s->getLength() - 2) / 2; + title = (Unicode *)gmallocn(titleLen, sizeof(Unicode)); + for (i = 0; i < titleLen; ++i) { + title[i] = ((s->getChar(2 + 2*i) & 0xff) << 8) | + (s->getChar(3 + 2*i) & 0xff); + } + } else { + titleLen = s->getLength(); + title = (Unicode *)gmallocn(titleLen, sizeof(Unicode)); + for (i = 0; i < titleLen; ++i) { + title[i] = pdfDocEncoding[s->getChar(i) & 0xff]; + } + } + } else { + titleLen = 0; + } + obj1.free(); + + if (!dict->lookup("Dest", &obj1)->isNull()) { + action = LinkAction::parseDest(&obj1); + } else { + obj1.free(); + if (!dict->lookup("A", &obj1)->isNull()) { + action = LinkAction::parseAction(&obj1); + } + } + obj1.free(); + + dict->lookupNF("First", &firstRef); + dict->lookupNF("Last", &lastRef); + dict->lookupNF("Next", &nextRef); + + startsOpen = gFalse; + if (dict->lookup("Count", &obj1)->isInt()) { + if (obj1.getInt() > 0) { + startsOpen = gTrue; + } + } + obj1.free(); +} + +OutlineItem::~OutlineItem() { + close(); + if (title) { + gfree(title); + } + if (action) { + delete action; + } + firstRef.free(); + lastRef.free(); + nextRef.free(); +} + +GList *OutlineItem::readItemList(Object *firstItemRef, Object *lastItemRef, + XRef *xrefA) { + GList *items; + OutlineItem *item; + Object obj; + Object *p; + + items = new GList(); + p = firstItemRef; + while (p->isRef()) { + if (!p->fetch(xrefA, &obj)->isDict()) { + obj.free(); + break; + } + item = new OutlineItem(obj.getDict(), xrefA); + obj.free(); + items->append(item); + if (p->getRef().num == lastItemRef->getRef().num && + p->getRef().gen == lastItemRef->getRef().gen) { + break; + } + p = &item->nextRef; + } + return items; +} + +void OutlineItem::open() { + if (!kids) { + kids = readItemList(&firstRef, &lastRef, xref); + } +} + +void OutlineItem::close() { + if (kids) { + deleteGList(kids, OutlineItem); + kids = NULL; + } +} diff --git a/kpdf/xpdf/xpdf/Outline.h b/kpdf/xpdf/xpdf/Outline.h new file mode 100644 index 00000000..f38f8d16 --- /dev/null +++ b/kpdf/xpdf/xpdf/Outline.h @@ -0,0 +1,76 @@ +//======================================================================== +// +// Outline.h +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef OUTLINE_H +#define OUTLINE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "Object.h" +#include "CharTypes.h" + +class GString; +class GList; +class XRef; +class LinkAction; + +//------------------------------------------------------------------------ + +class Outline { +public: + + Outline(Object *outlineObj, XRef *xref); + ~Outline(); + + GList *getItems() { return items; } + +private: + + GList *items; // NULL if document has no outline + // [OutlineItem] +}; + +//------------------------------------------------------------------------ + +class OutlineItem { +public: + + OutlineItem(Dict *dict, XRef *xrefA); + ~OutlineItem(); + + static GList *readItemList(Object *firstItemRef, Object *lastItemRef, + XRef *xrefA); + + void open(); + void close(); + + Unicode *getTitle() { return title; } + int getTitleLength() { return titleLen; } + LinkAction *getAction() { return action; } + GBool isOpen() { return startsOpen; } + GBool hasKids() { return firstRef.isRef(); } + GList *getKids() { return kids; } + +private: + + XRef *xref; + Unicode *title; + int titleLen; + LinkAction *action; + Object firstRef; + Object lastRef; + Object nextRef; + GBool startsOpen; + GList *kids; // NULL unless this item is open [OutlineItem] +}; + +#endif diff --git a/kpdf/xpdf/xpdf/OutputDev.cc b/kpdf/xpdf/xpdf/OutputDev.cc new file mode 100644 index 00000000..3ba19973 --- /dev/null +++ b/kpdf/xpdf/xpdf/OutputDev.cc @@ -0,0 +1,131 @@ +//======================================================================== +// +// OutputDev.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "Object.h" +#include "Stream.h" +#include "GfxState.h" +#include "OutputDev.h" + +//------------------------------------------------------------------------ +// OutputDev +//------------------------------------------------------------------------ + +void OutputDev::setDefaultCTM(double *ctm) { + int i; + double det; + + for (i = 0; i < 6; ++i) { + defCTM[i] = ctm[i]; + } + det = 1 / (defCTM[0] * defCTM[3] - defCTM[1] * defCTM[2]); + defICTM[0] = defCTM[3] * det; + defICTM[1] = -defCTM[1] * det; + defICTM[2] = -defCTM[2] * det; + defICTM[3] = defCTM[0] * det; + defICTM[4] = (defCTM[2] * defCTM[5] - defCTM[3] * defCTM[4]) * det; + defICTM[5] = (defCTM[1] * defCTM[4] - defCTM[0] * defCTM[5]) * det; +} + +void OutputDev::cvtDevToUser(double dx, double dy, double *ux, double *uy) { + *ux = defICTM[0] * dx + defICTM[2] * dy + defICTM[4]; + *uy = defICTM[1] * dx + defICTM[3] * dy + defICTM[5]; +} + +void OutputDev::cvtUserToDev(double ux, double uy, int *dx, int *dy) { + *dx = (int)(defCTM[0] * ux + defCTM[2] * uy + defCTM[4] + 0.5); + *dy = (int)(defCTM[1] * ux + defCTM[3] * uy + defCTM[5] + 0.5); +} + +void OutputDev::updateAll(GfxState *state) { + updateLineDash(state); + updateFlatness(state); + updateLineJoin(state); + updateLineCap(state); + updateMiterLimit(state); + updateLineWidth(state); + updateStrokeAdjust(state); + updateFillColorSpace(state); + updateFillColor(state); + updateStrokeColorSpace(state); + updateStrokeColor(state); + updateBlendMode(state); + updateFillOpacity(state); + updateStrokeOpacity(state); + updateFillOverprint(state); + updateStrokeOverprint(state); + updateTransfer(state); + updateFont(state); +} + +GBool OutputDev::beginType3Char(GfxState * /*state*/, double /*x*/, double /*y*/, + double /*dx*/, double /*dy*/, + CharCode /*code*/, Unicode * /*u*/, int /*uLen*/) { + return gFalse; +} + +void OutputDev::drawImageMask(GfxState * /*state*/, Object * /*ref*/, Stream *str, + int width, int height, GBool /*invert*/, + GBool inlineImg) { + int i, j; + + if (inlineImg) { + str->reset(); + j = height * ((width + 7) / 8); + for (i = 0; i < j; ++i) + str->getChar(); + str->close(); + } +} + +void OutputDev::drawImage(GfxState * /*state*/, Object * /*ref*/, Stream *str, + int width, int height, GfxImageColorMap *colorMap, + int * /*maskColors*/, GBool inlineImg) { + int i, j; + + if (inlineImg) { + str->reset(); + j = height * ((width * colorMap->getNumPixelComps() * + colorMap->getBits() + 7) / 8); + for (i = 0; i < j; ++i) + str->getChar(); + str->close(); + } +} + +void OutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream * /*maskStr*/, + int /*maskWidth*/, int /*maskHeight*/, + GBool /*maskInvert*/) { + drawImage(state, ref, str, width, height, colorMap, NULL, gFalse); +} + +void OutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream * /*maskStr*/, + int /*maskWidth*/, int /*maskHeight*/, + GfxImageColorMap * /*maskColorMap*/) { + drawImage(state, ref, str, width, height, colorMap, NULL, gFalse); +} + +#if OPI_SUPPORT +void OutputDev::opiBegin(GfxState *state, Dict *opiDict) { +} + +void OutputDev::opiEnd(GfxState *state, Dict *opiDict) { +} +#endif diff --git a/kpdf/xpdf/xpdf/OutputDev.h b/kpdf/xpdf/xpdf/OutputDev.h new file mode 100644 index 00000000..a4ee37b1 --- /dev/null +++ b/kpdf/xpdf/xpdf/OutputDev.h @@ -0,0 +1,250 @@ +//======================================================================== +// +// OutputDev.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef OUTPUTDEV_H +#define OUTPUTDEV_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "CharTypes.h" + +class GString; +class GfxState; +struct GfxColor; +class GfxColorSpace; +class GfxImageColorMap; +class GfxFunctionShading; +class GfxAxialShading; +class GfxRadialShading; +class Stream; +class Links; +class Link; +class Catalog; +class Page; +class Function; + +//------------------------------------------------------------------------ +// OutputDev +//------------------------------------------------------------------------ + +class OutputDev { +public: + + // Constructor. + OutputDev() {} + + // Destructor. + virtual ~OutputDev() {} + + //----- get info about output device + + // Does this device use upside-down coordinates? + // (Upside-down means (0,0) is the top left corner of the page.) + virtual GBool upsideDown() = 0; + + // Does this device use drawChar() or drawString()? + virtual GBool useDrawChar() = 0; + + // Does this device use tilingPatternFill()? If this returns false, + // tiling pattern fills will be reduced to a series of other drawing + // operations. + virtual GBool useTilingPatternFill() { return gFalse; } + + // Does this device use functionShadedFill(), axialShadedFill(), and + // radialShadedFill()? If this returns false, these shaded fills + // will be reduced to a series of other drawing operations. + virtual GBool useShadedFills() { return gFalse; } + + // Does this device use drawForm()? If this returns false, + // form-type XObjects will be interpreted (i.e., unrolled). + virtual GBool useDrawForm() { return gFalse; } + + // Does this device use beginType3Char/endType3Char? Otherwise, + // text in Type 3 fonts will be drawn with drawChar/drawString. + virtual GBool interpretType3Chars() = 0; + + // Does this device need non-text content? + virtual GBool needNonText() { return gTrue; } + + //----- initialization and control + + // Set default transform matrix. + virtual void setDefaultCTM(double *ctm); + + // Check to see if a page slice should be displayed. If this + // returns false, the page display is aborted. Typically, an + // OutputDev will use some alternate means to display the page + // before returning false. + virtual GBool checkPageSlice(Page * /*page*/, double /*hDPI*/, double /*vDPI*/, + int /*rotate*/, GBool /*useMediaBox*/, GBool /*crop*/, + int /*sliceX*/, int /*sliceY*/, int /*sliceW*/, int /*sliceH*/, + GBool /*printing*/, Catalog * /*catalog*/, + GBool (* /*abortCheckCbk*/)(void *data) = NULL, + void * /*abortCheckCbkData*/ = NULL) + { return gTrue; } + + // Start a page. + virtual void startPage(int /*pageNum*/, GfxState * /*state*/) {} + + // End a page. + virtual void endPage() {} + + // Dump page contents to display. + virtual void dump() {} + + //----- coordinate conversion + + // Convert between device and user coordinates. + virtual void cvtDevToUser(double dx, double dy, double *ux, double *uy); + virtual void cvtUserToDev(double ux, double uy, int *dx, int *dy); + + double *getDefCTM() { return defCTM; } + double *getDefICTM() { return defICTM; } + + //----- save/restore graphics state + virtual void saveState(GfxState * /*state*/) {} + virtual void restoreState(GfxState * /*state*/) {} + + //----- update graphics state + virtual void updateAll(GfxState *state); + virtual void updateCTM(GfxState * /*state*/, double /*m11*/, double /*m12*/, + double /*m21*/, double /*m22*/, double /*m31*/, double /*m32*/) {} + virtual void updateLineDash(GfxState * /*state*/) {} + virtual void updateFlatness(GfxState * /*state*/) {} + virtual void updateLineJoin(GfxState * /*state*/) {} + virtual void updateLineCap(GfxState * /*state*/) {} + virtual void updateMiterLimit(GfxState * /*state*/) {} + virtual void updateLineWidth(GfxState * /*state*/) {} + virtual void updateStrokeAdjust(GfxState * /*state*/) {} + virtual void updateFillColorSpace(GfxState * /*state*/) {} + virtual void updateStrokeColorSpace(GfxState * /*state*/) {} + virtual void updateFillColor(GfxState * /*state*/) {} + virtual void updateStrokeColor(GfxState * /*state*/) {} + virtual void updateBlendMode(GfxState * /*state*/) {} + virtual void updateFillOpacity(GfxState * /*state*/) {} + virtual void updateStrokeOpacity(GfxState * /*state*/) {} + virtual void updateFillOverprint(GfxState * /*state*/) {} + virtual void updateStrokeOverprint(GfxState * /*state*/) {} + virtual void updateTransfer(GfxState * /*state*/) {} + + //----- update text state + virtual void updateFont(GfxState * /*state*/) {} + virtual void updateTextMat(GfxState * /*state*/) {} + virtual void updateCharSpace(GfxState * /*state*/) {} + virtual void updateRender(GfxState * /*state*/) {} + virtual void updateRise(GfxState * /*state*/) {} + virtual void updateWordSpace(GfxState * /*state*/) {} + virtual void updateHorizScaling(GfxState * /*state*/) {} + virtual void updateTextPos(GfxState * /*state*/) {} + virtual void updateTextShift(GfxState * /*state*/, double /*shift*/) {} + + //----- path painting + virtual void stroke(GfxState * /*state*/) {} + virtual void fill(GfxState * /*state*/) {} + virtual void eoFill(GfxState * /*state*/) {} + virtual void tilingPatternFill(GfxState * /*state*/, Object * /*str*/, + int /*paintType*/, Dict * /*resDict*/, + double * /*mat*/, double * /*bbox*/, + int /*x0*/, int /*y0*/, int /*x1*/, int /*y1*/, + double /*xStep*/, double /*yStep*/) {} + virtual GBool functionShadedFill(GfxState * /*state*/, + GfxFunctionShading * /*shading*/) + { return gFalse; } + virtual GBool axialShadedFill(GfxState * /*state*/, GfxAxialShading * /*shading*/) + { return gFalse; } + virtual GBool radialShadedFill(GfxState * /*state*/, GfxRadialShading * /*shading*/) + { return gFalse; } + + //----- path clipping + virtual void clip(GfxState * /*state*/) {} + virtual void eoClip(GfxState * /*state*/) {} + virtual void clipToStrokePath(GfxState * /*state*/) {} + + //----- text drawing + virtual void beginStringOp(GfxState * /*state*/) {} + virtual void endStringOp(GfxState * /*state*/) {} + virtual void beginString(GfxState * /*state*/, GString * /*s*/) {} + virtual void endString(GfxState * /*state*/) {} + virtual void drawChar(GfxState * /*state*/, double /*x*/, double /*y*/, + double /*dx*/, double /*dy*/, + double /*originX*/, double /*originY*/, + CharCode /*code*/, int /*nBytes*/, Unicode * /*u*/, int /*uLen*/) {} + virtual void drawString(GfxState * /*state*/, GString * /*s*/) {} + virtual GBool beginType3Char(GfxState *state, double x, double y, + double dx, double dy, + CharCode code, Unicode *u, int uLen); + virtual void endType3Char(GfxState * /*state*/) {} + virtual void endTextObject(GfxState * /*state*/) {} + + //----- image drawing + virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, + int width, int height, GBool invert, + GBool inlineImg); + virtual void drawImage(GfxState *state, Object *ref, Stream *str, + int width, int height, GfxImageColorMap *colorMap, + int *maskColors, GBool inlineImg); + virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, int maskWidth, int maskHeight, + GBool maskInvert); + virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GfxImageColorMap *maskColorMap); + +#if OPI_SUPPORT + //----- OPI functions + virtual void opiBegin(GfxState *state, Dict *opiDict); + virtual void opiEnd(GfxState *state, Dict *opiDict); +#endif + + //----- Type 3 font operators + virtual void type3D0(GfxState * /*state*/, double /*wx*/, double /*wy*/) {} + virtual void type3D1(GfxState * /*state*/, double /*wx*/, double /*wy*/, + double /*llx*/, double /*lly*/, double /*urx*/, double /*ury*/) {} + + //----- form XObjects + virtual void drawForm(Ref /*id*/) {} + + //----- PostScript XObjects + virtual void psXObject(Stream * /*psStream*/, Stream * /*level1Stream*/) {} + + //----- transparency groups and soft masks + virtual void beginTransparencyGroup(GfxState * /*state*/, double * /*bbox*/, + GfxColorSpace * /*blendingColorSpace*/, + GBool /*isolated*/, GBool /*knockout*/, + GBool /*forSoftMask*/) {} + virtual void endTransparencyGroup(GfxState * /*state*/) {} + virtual void paintTransparencyGroup(GfxState * /*state*/, double * /*bbox*/) {} + virtual void setSoftMask(GfxState * /*state*/, double * /*bbox*/, GBool /*alpha*/, + Function * /*transferFunc*/, GfxColor * /*backdropColor*/) {} + virtual void clearSoftMask(GfxState * /*state*/) {} + + //----- links + virtual void processLink(Link * /*link*/, Catalog * /*catalog*/) {} + +#if 1 //~tmp: turn off anti-aliasing temporarily + virtual GBool getVectorAntialias() { return gFalse; } + virtual void setVectorAntialias(GBool /*vaa*/) {} +#endif + +private: + + double defCTM[6]; // default coordinate transform matrix + double defICTM[6]; // inverse of default CTM +}; + +#endif diff --git a/kpdf/xpdf/xpdf/PDFDoc.cc b/kpdf/xpdf/xpdf/PDFDoc.cc new file mode 100644 index 00000000..dc24d97e --- /dev/null +++ b/kpdf/xpdf/xpdf/PDFDoc.cc @@ -0,0 +1,433 @@ +//======================================================================== +// +// PDFDoc.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include +#ifdef WIN32 +# include +#endif +#include "GString.h" +#include "config.h" +#include "GlobalParams.h" +#include "Page.h" +#include "Catalog.h" +#include "Stream.h" +#include "XRef.h" +#include "Link.h" +#include "OutputDev.h" +#include "Error.h" +#include "ErrorCodes.h" +#include "Lexer.h" +#include "Parser.h" +#include "SecurityHandler.h" +#ifndef DISABLE_OUTLINE +#include "Outline.h" +#endif +#include "PDFDoc.h" + +//------------------------------------------------------------------------ + +#define headerSearchSize 1024 // read this many bytes at beginning of + // file to look for '%PDF' + +//------------------------------------------------------------------------ +// PDFDoc +//------------------------------------------------------------------------ + +PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, + GString *userPassword, void *guiDataA) { + Object obj; + GString *fileName1, *fileName2; + + ok = gFalse; + errCode = errNone; + + guiData = guiDataA; + + file = NULL; + str = NULL; + xref = NULL; + catalog = NULL; +#ifndef DISABLE_OUTLINE + outline = NULL; +#endif + + fileName = fileNameA; + fileName1 = fileName; + + + // try to open file + fileName2 = NULL; +#ifdef VMS + if (!(file = fopen(fileName1->getCString(), "rb", "ctx=stm"))) { + error(-1, "Couldn't open file '%s'", fileName1->getCString()); + errCode = errOpenFile; + return; + } +#else + if (!(file = fopen(fileName1->getCString(), "rb"))) { + fileName2 = fileName->copy(); + fileName2->lowerCase(); + if (!(file = fopen(fileName2->getCString(), "rb"))) { + fileName2->upperCase(); + if (!(file = fopen(fileName2->getCString(), "rb"))) { + error(-1, "Couldn't open file '%s'", fileName->getCString()); + delete fileName2; + errCode = errOpenFile; + return; + } + } + delete fileName2; + } +#endif + + // create stream + obj.initNull(); + str = new FileStream(file, 0, gFalse, 0, &obj); + + ok = setup(ownerPassword, userPassword); +} + +#ifdef WIN32 +PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword, + GString *userPassword, void *guiDataA) { + OSVERSIONINFO version; + wchar_t fileName2[_MAX_PATH + 1]; + Object obj; + int i; + + ok = gFalse; + errCode = errNone; + + guiData = guiDataA; + + file = NULL; + str = NULL; + xref = NULL; + catalog = NULL; +#ifndef DISABLE_OUTLINE + outline = NULL; +#endif + + //~ file name should be stored in Unicode (?) + fileName = new GString(); + for (i = 0; i < fileNameLen; ++i) { + fileName->append((char)fileNameA[i]); + } + + // zero-terminate the file name string + for (i = 0; i < fileNameLen && i < _MAX_PATH; ++i) { + fileName2[i] = fileNameA[i]; + } + fileName2[i] = 0; + + // try to open file + // NB: _wfopen is only available in NT + version.dwOSVersionInfoSize = sizeof(version); + GetVersionEx(&version); + if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) { + file = _wfopen(fileName2, L"rb"); + } else { + file = fopen(fileName->getCString(), "rb"); + } + if (!file) { + error(-1, "Couldn't open file '%s'", fileName->getCString()); + errCode = errOpenFile; + return; + } + + // create stream + obj.initNull(); + str = new FileStream(file, 0, gFalse, 0, &obj); + + ok = setup(ownerPassword, userPassword); +} +#endif + +PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword, + GString *userPassword, void *guiDataA) { + ok = gFalse; + errCode = errNone; + guiData = guiDataA; + if (strA->getFileName()) { + fileName = strA->getFileName()->copy(); + } else { + fileName = NULL; + } + file = NULL; + str = strA; + xref = NULL; + catalog = NULL; +#ifndef DISABLE_OUTLINE + outline = NULL; +#endif + ok = setup(ownerPassword, userPassword); +} + +GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) { + str->reset(); + + char *eof = new char[1025]; + int pos = str->getPos(); + str->setPos(1024, -1); + int i, ch; + for (i = 0; i < 1024; i++) + { + ch = str->getChar(); + if (ch == EOF) + break; + eof[i] = ch; + } + eof[i] = '\0'; + + bool found = false; + for (i = i - 5; i >= 0; i--) { + if (strncmp (&eof[i], "%%EOF", 5) == 0) { + found = true; + break; + } + } + if (!found) + { + error(-1, "Document does not have ending %%EOF"); + errCode = errDamaged; + delete[] eof; + return gFalse; + } + delete[] eof; + + str->setPos(pos); + + // check header + checkHeader(); + + // read xref table + xref = new XRef(str); + if (!xref->isOk()) { + error(-1, "Couldn't read xref table"); + errCode = xref->getErrorCode(); + return gFalse; + } + + // check for encryption + if (!checkEncryption(ownerPassword, userPassword)) { + errCode = errEncrypted; + return gFalse; + } + + // read catalog + catalog = new Catalog(xref); + if (!catalog->isOk()) { + error(-1, "Couldn't read page catalog"); + errCode = errBadCatalog; + return gFalse; + } + +#ifndef DISABLE_OUTLINE + // read outline + outline = new Outline(catalog->getOutline(), xref); +#endif + + // done + return gTrue; +} + +PDFDoc::~PDFDoc() { +#ifndef DISABLE_OUTLINE + if (outline) { + delete outline; + } +#endif + if (catalog) { + delete catalog; + } + if (xref) { + delete xref; + } + if (str) { + delete str; + } + if (file) { + fclose(file); + } + if (fileName) { + delete fileName; + } +} + +// Check for a PDF header on this stream. Skip past some garbage +// if necessary. +void PDFDoc::checkHeader() { + char hdrBuf[headerSearchSize+1]; + char *p; + int i; + + pdfVersion = 0; + for (i = 0; i < headerSearchSize; ++i) { + hdrBuf[i] = str->getChar(); + } + hdrBuf[headerSearchSize] = '\0'; + for (i = 0; i < headerSearchSize - 5; ++i) { + if (!strncmp(&hdrBuf[i], "%PDF-", 5)) { + break; + } + } + if (i >= headerSearchSize - 5) { + error(-1, "May not be a PDF file (continuing anyway)"); + return; + } + str->moveStart(i); + if (!(p = strtok(&hdrBuf[i+5], " \t\n\r"))) { + error(-1, "May not be a PDF file (continuing anyway)"); + return; + } + pdfVersion = atof(p); + if (!(hdrBuf[i+5] >= '0' && hdrBuf[i+5] <= '9') || + pdfVersion > supportedPDFVersionNum + 0.0001) { + error(-1, "PDF version %s -- xpdf supports version %s" + " (continuing anyway)", p, supportedPDFVersionStr); + } +} + +GBool PDFDoc::checkEncryption(GString *ownerPassword, GString *userPassword) { + Object encrypt; + GBool encrypted; + SecurityHandler *secHdlr; + GBool ret; + + xref->getTrailerDict()->dictLookup("Encrypt", &encrypt); + if ((encrypted = encrypt.isDict())) { + if ((secHdlr = SecurityHandler::make(this, &encrypt))) { + if (secHdlr->checkEncryption(ownerPassword, userPassword)) { + // authorization succeeded + xref->setEncryption(secHdlr->getPermissionFlags(), + secHdlr->getOwnerPasswordOk(), + secHdlr->getFileKey(), + secHdlr->getFileKeyLength(), + secHdlr->getEncVersion(), + secHdlr->getEncAlgorithm()); + ret = gTrue; + } else { + // authorization failed + ret = gFalse; + } + delete secHdlr; + } else { + // couldn't find the matching security handler + ret = gFalse; + } + } else { + // document is not encrypted + ret = gTrue; + } + encrypt.free(); + return ret; +} + +void PDFDoc::displayPage(OutputDev *out, int page, + double hDPI, double vDPI, int rotate, + GBool useMediaBox, GBool crop, GBool printing, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { + if (globalParams->getPrintCommands()) { + printf("***** page %d *****\n", page); + } + catalog->getPage(page)->display(out, hDPI, vDPI, + rotate, useMediaBox, crop, printing, catalog, + abortCheckCbk, abortCheckCbkData); +} + +void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage, + double hDPI, double vDPI, int rotate, + GBool useMediaBox, GBool crop, GBool printing, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { + int page; + + for (page = firstPage; page <= lastPage; ++page) { + displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, printing, + abortCheckCbk, abortCheckCbkData); + } +} + +void PDFDoc::displayPageSlice(OutputDev *out, int page, + double hDPI, double vDPI, int rotate, + GBool useMediaBox, GBool crop, GBool printing, + int sliceX, int sliceY, int sliceW, int sliceH, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { + catalog->getPage(page)->displaySlice(out, hDPI, vDPI, + rotate, useMediaBox, crop, + sliceX, sliceY, sliceW, sliceH, + printing, catalog, + abortCheckCbk, abortCheckCbkData); +} + +Links *PDFDoc::getLinks(int page) { + return catalog->getPage(page)->getLinks(catalog); +} + +void PDFDoc::processLinks(OutputDev *out, int page) { + catalog->getPage(page)->processLinks(out, catalog); +} + +GBool PDFDoc::isLinearized() { + Parser *parser; + Object obj1, obj2, obj3, obj4, obj5; + GBool lin; + + lin = gFalse; + obj1.initNull(); + parser = new Parser(xref, + new Lexer(xref, + str->makeSubStream(str->getStart(), gFalse, 0, &obj1)), + gTrue); + parser->getObj(&obj1); + parser->getObj(&obj2); + parser->getObj(&obj3); + parser->getObj(&obj4); + if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") && + obj4.isDict()) { + obj4.dictLookup("Linearized", &obj5); + if (obj5.isNum() && obj5.getNum() > 0) { + lin = gTrue; + } + obj5.free(); + } + obj4.free(); + obj3.free(); + obj2.free(); + obj1.free(); + delete parser; + return lin; +} + +GBool PDFDoc::saveAs(GString *name) { + FILE *f; + int c; + + if (!(f = fopen(name->getCString(), "wb"))) { + error(-1, "Couldn't open file '%s'", name->getCString()); + return gFalse; + } + str->reset(); + while ((c = str->getChar()) != EOF) { + fputc(c, f); + } + str->close(); + fclose(f); + return gTrue; +} diff --git a/kpdf/xpdf/xpdf/PDFDoc.h b/kpdf/xpdf/xpdf/PDFDoc.h new file mode 100644 index 00000000..208b61ef --- /dev/null +++ b/kpdf/xpdf/xpdf/PDFDoc.h @@ -0,0 +1,183 @@ +//======================================================================== +// +// PDFDoc.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef PDFDOC_H +#define PDFDOC_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include +#include "XRef.h" +#include "Catalog.h" +#include "Page.h" + +class GString; +class BaseStream; +class OutputDev; +class Links; +class LinkAction; +class LinkDest; +class Outline; + +//------------------------------------------------------------------------ +// PDFDoc +//------------------------------------------------------------------------ + +class PDFDoc { +public: + + PDFDoc(GString *fileNameA, GString *ownerPassword = NULL, + GString *userPassword = NULL, void *guiDataA = NULL); +#ifdef WIN32 + PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword = NULL, + GString *userPassword = NULL, void *guiDataA = NULL); +#endif + PDFDoc(BaseStream *strA, GString *ownerPassword = NULL, + GString *userPassword = NULL, void *guiDataA = NULL); + ~PDFDoc(); + + // Was PDF document successfully opened? + GBool isOk() { return ok; } + + // Get the error code (if isOk() returns false). + int getErrorCode() { return errCode; } + + // Get file name. + GString *getFileName() { return fileName; } + + // Get the xref table. + XRef *getXRef() { return xref; } + + // Get catalog. + Catalog *getCatalog() { return catalog; } + + // Get base stream. + BaseStream *getBaseStream() { return str; } + + // Get page parameters. + double getPageMediaWidth(int page) + { return catalog->getPage(page)->getMediaWidth(); } + double getPageMediaHeight(int page) + { return catalog->getPage(page)->getMediaHeight(); } + double getPageCropWidth(int page) + { return catalog->getPage(page)->getCropWidth(); } + double getPageCropHeight(int page) + { return catalog->getPage(page)->getCropHeight(); } + int getPageRotate(int page) + { return catalog->getPage(page)->getRotate(); } + + // Get number of pages. + int getNumPages() { return catalog->getNumPages(); } + + // Return the contents of the metadata stream, or NULL if there is + // no metadata. + GString *readMetadata() { return catalog->readMetadata(); } + + // Return the structure tree root object. + Object *getStructTreeRoot() { return catalog->getStructTreeRoot(); } + + // Display a page. + void displayPage(OutputDev *out, int page, + double hDPI, double vDPI, int rotate, + GBool useMediaBox, GBool crop, GBool printing, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); + + // Display a range of pages. + void displayPages(OutputDev *out, int firstPage, int lastPage, + double hDPI, double vDPI, int rotate, + GBool useMediaBox, GBool crop, GBool printing, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); + + // Display part of a page. + void displayPageSlice(OutputDev *out, int page, + double hDPI, double vDPI, int rotate, + GBool useMediaBox, GBool crop, GBool printing, + int sliceX, int sliceY, int sliceW, int sliceH, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); + + // Find a page, given its object ID. Returns page number, or 0 if + // not found. + int findPage(int num, int gen) { return catalog->findPage(num, gen); } + + // Returns the links for the current page, transferring ownership to + // the caller. + Links *getLinks(int page); + + // Find a named destination. Returns the link destination, or + // NULL if is not a destination. + LinkDest *findDest(GString *name) + { return catalog->findDest(name); } + + // Process the links for a page. + void processLinks(OutputDev *out, int page); + +#ifndef DISABLE_OUTLINE + // Return the outline object. + Outline *getOutline() { return outline; } +#endif + + // Is the file encrypted? + GBool isEncrypted() { return xref->isEncrypted(); } + + // Check various permissions. + GBool okToPrint(GBool ignoreOwnerPW = gFalse) + { return xref->okToPrint(ignoreOwnerPW); } + GBool okToChange(GBool ignoreOwnerPW = gFalse) + { return xref->okToChange(ignoreOwnerPW); } + GBool okToCopy(GBool ignoreOwnerPW = gFalse) + { return xref->okToCopy(ignoreOwnerPW); } + GBool okToAddNotes(GBool ignoreOwnerPW = gFalse) + { return xref->okToAddNotes(ignoreOwnerPW); } + + // Is this document linearized? + GBool isLinearized(); + + // Return the document's Info dictionary (if any). + Object *getDocInfo(Object *obj) { return xref->getDocInfo(obj); } + Object *getDocInfoNF(Object *obj) { return xref->getDocInfoNF(obj); } + + // Return the PDF version specified by the file. + double getPDFVersion() { return pdfVersion; } + + // Save this file with another name. + GBool saveAs(GString *name); + + // Return a pointer to the GUI (XPDFCore or WinPDFCore object). + void *getGUIData() { return guiData; } + + +private: + + GBool setup(GString *ownerPassword, GString *userPassword); + void checkHeader(); + GBool checkEncryption(GString *ownerPassword, GString *userPassword); + + GString *fileName; + FILE *file; + BaseStream *str; + void *guiData; + double pdfVersion; + XRef *xref; + Catalog *catalog; +#ifndef DISABLE_OUTLINE + Outline *outline; +#endif + + + GBool ok; + int errCode; +}; + +#endif diff --git a/kpdf/xpdf/xpdf/PDFDocEncoding.cc b/kpdf/xpdf/xpdf/PDFDocEncoding.cc new file mode 100644 index 00000000..89dc3828 --- /dev/null +++ b/kpdf/xpdf/xpdf/PDFDocEncoding.cc @@ -0,0 +1,44 @@ +//======================================================================== +// +// PDFDocEncoding.h +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include "PDFDocEncoding.h" + +Unicode pdfDocEncoding[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 00 + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 10 + 0x02d8, 0x02c7, 0x02c6, 0x02d9, 0x02dd, 0x02db, 0x02da, 0x02dc, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, // 20 + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, // 30 + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, // 40 + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, // 50 + 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, // 60 + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, // 70 + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x0000, + 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x0192, 0x2044, // 80 + 0x2039, 0x203a, 0x2212, 0x2030, 0x201e, 0x201c, 0x201d, 0x2018, + 0x2019, 0x201a, 0x2122, 0xfb01, 0xfb02, 0x0141, 0x0152, 0x0160, // 90 + 0x0178, 0x017d, 0x0131, 0x0142, 0x0153, 0x0161, 0x017e, 0x0000, + 0x20ac, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, // a0 + 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x0000, 0x00ae, 0x00af, + 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, // b0 + 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, + 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, // c0 + 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, + 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, // d0 + 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, + 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, // e0 + 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, + 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, // f0 + 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff +}; diff --git a/kpdf/xpdf/xpdf/PDFDocEncoding.h b/kpdf/xpdf/xpdf/PDFDocEncoding.h new file mode 100644 index 00000000..3259d3e1 --- /dev/null +++ b/kpdf/xpdf/xpdf/PDFDocEncoding.h @@ -0,0 +1,16 @@ +//======================================================================== +// +// PDFDocEncoding.h +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef PDFDOCENCODING_H +#define PDFDOCENCODING_H + +#include "CharTypes.h" + +extern Unicode pdfDocEncoding[256]; + +#endif diff --git a/kpdf/xpdf/xpdf/PSOutputDev.cc b/kpdf/xpdf/xpdf/PSOutputDev.cc new file mode 100644 index 00000000..d35739a5 --- /dev/null +++ b/kpdf/xpdf/xpdf/PSOutputDev.cc @@ -0,0 +1,6307 @@ +//======================================================================== +// +// PSOutputDev.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include +#include +#include "GString.h" +#include "GList.h" +#include "config.h" +#include "GlobalParams.h" +#include "Object.h" +#include "Error.h" +#include "Function.h" +#include "Gfx.h" +#include "GfxState.h" +#include "GfxFont.h" +#include "UnicodeMap.h" +#include "FoFiType1C.h" +#include "FoFiTrueType.h" +#include "Catalog.h" +#include "Page.h" +#include "Stream.h" +#include "Annot.h" +#include "XRef.h" +#include "PreScanOutputDev.h" +#if HAVE_SPLASH +# include "Splash.h" +# include "SplashBitmap.h" +# include "SplashOutputDev.h" +#endif +#include "PSOutputDev.h" + +#ifdef MACOS +// needed for setting type/creator of MacOS files +#include "ICSupport.h" +#endif + +// the MSVC math.h doesn't define this +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +//------------------------------------------------------------------------ + +// Resolution at which pages with transparency will be rasterized. +#define splashDPI 300 + +//------------------------------------------------------------------------ +// PostScript prolog and setup +//------------------------------------------------------------------------ + +// The '~' escapes mark prolog code that is emitted only in certain +// levels: +// +// ~[123][sn] +// ^ ^----- s=psLevel*Sep, n=psLevel* +// +----- 1=psLevel1*, 2=psLevel2*, 3=psLevel3* + +static char *prolog[] = { + "/xpdf 75 dict def xpdf begin", + "% PDF special state", + "/pdfDictSize 15 def", + "~1sn", + "/pdfStates 64 array def", + " 0 1 63 {", + " pdfStates exch pdfDictSize dict", + " dup /pdfStateIdx 3 index put", + " put", + " } for", + "~123sn", + "/pdfSetup {", + " 3 1 roll 2 array astore", + " /setpagedevice where {", + " pop 3 dict begin", + " /PageSize exch def", + " /ImagingBBox null def", + " /Policies 1 dict dup begin /PageSize 3 def end def", + " { /Duplex true def } if", + " currentdict end setpagedevice", + " } {", + " pop pop", + " } ifelse", + "} def", + "~1sn", + "/pdfOpNames [", + " /pdfFill /pdfStroke /pdfLastFill /pdfLastStroke", + " /pdfTextMat /pdfFontSize /pdfCharSpacing /pdfTextRender", + " /pdfTextRise /pdfWordSpacing /pdfHorizScaling /pdfTextClipPath", + "] def", + "~123sn", + "/pdfStartPage {", + "~1sn", + " pdfStates 0 get begin", + "~23sn", + " pdfDictSize dict begin", + "~23n", + " /pdfFillCS [] def", + " /pdfFillXform {} def", + " /pdfStrokeCS [] def", + " /pdfStrokeXform {} def", + "~1n", + " /pdfFill 0 def", + " /pdfStroke 0 def", + "~1s", + " /pdfFill [0 0 0 1] def", + " /pdfStroke [0 0 0 1] def", + "~23sn", + " /pdfFill [0] def", + " /pdfStroke [0] def", + " /pdfFillOP false def", + " /pdfStrokeOP false def", + "~123sn", + " /pdfLastFill false def", + " /pdfLastStroke false def", + " /pdfTextMat [1 0 0 1 0 0] def", + " /pdfFontSize 0 def", + " /pdfCharSpacing 0 def", + " /pdfTextRender 0 def", + " /pdfTextRise 0 def", + " /pdfWordSpacing 0 def", + " /pdfHorizScaling 1 def", + " /pdfTextClipPath [] def", + "} def", + "/pdfEndPage { end } def", + "~23s", + "% separation convention operators", + "/findcmykcustomcolor where {", + " pop", + "}{", + " /findcmykcustomcolor { 5 array astore } def", + "} ifelse", + "/setcustomcolor where {", + " pop", + "}{", + " /setcustomcolor {", + " exch", + " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch", + " 0 4 getinterval cvx", + " [ exch /dup load exch { mul exch dup } /forall load", + " /pop load dup ] cvx", + " ] setcolorspace setcolor", + " } def", + "} ifelse", + "/customcolorimage where {", + " pop", + "}{", + " /customcolorimage {", + " gsave", + " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch", + " 0 4 getinterval", + " [ exch /dup load exch { mul exch dup } /forall load", + " /pop load dup ] cvx", + " ] setcolorspace", + " 10 dict begin", + " /ImageType 1 def", + " /DataSource exch def", + " /ImageMatrix exch def", + " /BitsPerComponent exch def", + " /Height exch def", + " /Width exch def", + " /Decode [1 0] def", + " currentdict end", + " image", + " grestore", + " } def", + "} ifelse", + "~123sn", + "% PDF color state", + "~1n", + "/g { dup /pdfFill exch def setgray", + " /pdfLastFill true def /pdfLastStroke false def } def", + "/G { dup /pdfStroke exch def setgray", + " /pdfLastStroke true def /pdfLastFill false def } def", + "/fCol {", + " pdfLastFill not {", + " pdfFill setgray", + " /pdfLastFill true def /pdfLastStroke false def", + " } if", + "} def", + "/sCol {", + " pdfLastStroke not {", + " pdfStroke setgray", + " /pdfLastStroke true def /pdfLastFill false def", + " } if", + "} def", + "~1s", + "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor", + " /pdfLastFill true def /pdfLastStroke false def } def", + "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor", + " /pdfLastStroke true def /pdfLastFill false def } def", + "/fCol {", + " pdfLastFill not {", + " pdfFill aload pop setcmykcolor", + " /pdfLastFill true def /pdfLastStroke false def", + " } if", + "} def", + "/sCol {", + " pdfLastStroke not {", + " pdfStroke aload pop setcmykcolor", + " /pdfLastStroke true def /pdfLastFill false def", + " } if", + "} def", + "~23n", + "/cs { /pdfFillXform exch def dup /pdfFillCS exch def", + " setcolorspace } def", + "/CS { /pdfStrokeXform exch def dup /pdfStrokeCS exch def", + " setcolorspace } def", + "/sc { pdfLastFill not { pdfFillCS setcolorspace } if", + " dup /pdfFill exch def aload pop pdfFillXform setcolor", + " /pdfLastFill true def /pdfLastStroke false def } def", + "/SC { pdfLastStroke not { pdfStrokeCS setcolorspace } if", + " dup /pdfStroke exch def aload pop pdfStrokeXform setcolor", + " /pdfLastStroke true def /pdfLastFill false def } def", + "/op { /pdfFillOP exch def", + " pdfLastFill { pdfFillOP setoverprint } if } def", + "/OP { /pdfStrokeOP exch def", + " pdfLastStroke { pdfStrokeOP setoverprint } if } def", + "/fCol {", + " pdfLastFill not {", + " pdfFillCS setcolorspace", + " pdfFill aload pop pdfFillXform setcolor", + " pdfFillOP setoverprint", + " /pdfLastFill true def /pdfLastStroke false def", + " } if", + "} def", + "/sCol {", + " pdfLastStroke not {", + " pdfStrokeCS setcolorspace", + " pdfStroke aload pop pdfStrokeXform setcolor", + " pdfStrokeOP setoverprint", + " /pdfLastStroke true def /pdfLastFill false def", + " } if", + "} def", + "~23s", + "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor", + " /pdfLastFill true def /pdfLastStroke false def } def", + "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor", + " /pdfLastStroke true def /pdfLastFill false def } def", + "/ck { 6 copy 6 array astore /pdfFill exch def", + " findcmykcustomcolor exch setcustomcolor", + " /pdfLastFill true def /pdfLastStroke false def } def", + "/CK { 6 copy 6 array astore /pdfStroke exch def", + " findcmykcustomcolor exch setcustomcolor", + " /pdfLastStroke true def /pdfLastFill false def } def", + "/op { /pdfFillOP exch def", + " pdfLastFill { pdfFillOP setoverprint } if } def", + "/OP { /pdfStrokeOP exch def", + " pdfLastStroke { pdfStrokeOP setoverprint } if } def", + "/fCol {", + " pdfLastFill not {", + " pdfFill aload length 4 eq {", + " setcmykcolor", + " }{", + " findcmykcustomcolor exch setcustomcolor", + " } ifelse", + " pdfFillOP setoverprint", + " /pdfLastFill true def /pdfLastStroke false def", + " } if", + "} def", + "/sCol {", + " pdfLastStroke not {", + " pdfStroke aload length 4 eq {", + " setcmykcolor", + " }{", + " findcmykcustomcolor exch setcustomcolor", + " } ifelse", + " pdfStrokeOP setoverprint", + " /pdfLastStroke true def /pdfLastFill false def", + " } if", + "} def", + "~123sn", + "% build a font", + "/pdfMakeFont {", + " 4 3 roll findfont", + " 4 2 roll matrix scale makefont", + " dup length dict begin", + " { 1 index /FID ne { def } { pop pop } ifelse } forall", + " /Encoding exch def", + " currentdict", + " end", + " definefont pop", + "} def", + "/pdfMakeFont16 {", + " exch findfont", + " dup length dict begin", + " { 1 index /FID ne { def } { pop pop } ifelse } forall", + " /WMode exch def", + " currentdict", + " end", + " definefont pop", + "} def", + "~3sn", + "/pdfMakeFont16L3 {", + " 1 index /CIDFont resourcestatus {", + " pop pop 1 index /CIDFont findresource /CIDFontType known", + " } {", + " false", + " } ifelse", + " {", + " 0 eq { /Identity-H } { /Identity-V } ifelse", + " exch 1 array astore composefont pop", + " } {", + " pdfMakeFont16", + " } ifelse", + "} def", + "~123sn", + "% graphics state operators", + "~1sn", + "/q {", + " gsave", + " pdfOpNames length 1 sub -1 0 { pdfOpNames exch get load } for", + " pdfStates pdfStateIdx 1 add get begin", + " pdfOpNames { exch def } forall", + "} def", + "/Q { end grestore } def", + "~23sn", + "/q { gsave pdfDictSize dict begin } def", + "/Q {", + " end grestore", + " /pdfLastFill where {", + " pop", + " pdfLastFill {", + " pdfFillOP setoverprint", + " } {", + " pdfStrokeOP setoverprint", + " } ifelse", + " } if", + "} def", + "~123sn", + "/cm { concat } def", + "/d { setdash } def", + "/i { setflat } def", + "/j { setlinejoin } def", + "/J { setlinecap } def", + "/M { setmiterlimit } def", + "/w { setlinewidth } def", + "% path segment operators", + "/m { moveto } def", + "/l { lineto } def", + "/c { curveto } def", + "/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto", + " neg 0 rlineto closepath } def", + "/h { closepath } def", + "% path painting operators", + "/S { sCol stroke } def", + "/Sf { fCol stroke } def", + "/f { fCol fill } def", + "/f* { fCol eofill } def", + "% clipping operators", + "/W { clip newpath } def", + "/W* { eoclip newpath } def", + "/Ws { strokepath clip newpath } def", + "% text state operators", + "/Tc { /pdfCharSpacing exch def } def", + "/Tf { dup /pdfFontSize exch def", + " dup pdfHorizScaling mul exch matrix scale", + " pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put", + " exch findfont exch makefont setfont } def", + "/Tr { /pdfTextRender exch def } def", + "/Ts { /pdfTextRise exch def } def", + "/Tw { /pdfWordSpacing exch def } def", + "/Tz { /pdfHorizScaling exch def } def", + "% text positioning operators", + "/Td { pdfTextMat transform moveto } def", + "/Tm { /pdfTextMat exch def } def", + "% text string operators", + "/cshow where {", + " pop", + " /cshow2 {", + " dup {", + " pop pop", + " 1 string dup 0 3 index put 3 index exec", + " } exch cshow", + " pop pop", + " } def", + "}{", + " /cshow2 {", + " currentfont /FontType get 0 eq {", + " 0 2 2 index length 1 sub {", + " 2 copy get exch 1 add 2 index exch get", + " 2 copy exch 256 mul add", + " 2 string dup 0 6 5 roll put dup 1 5 4 roll put", + " 3 index exec", + " } for", + " } {", + " dup {", + " 1 string dup 0 3 index put 3 index exec", + " } forall", + " } ifelse", + " pop pop", + " } def", + "} ifelse", + "/awcp {", // awidthcharpath + " exch {", + " false charpath", + " 5 index 5 index rmoveto", + " 6 index eq { 7 index 7 index rmoveto } if", + " } exch cshow2", + " 6 {pop} repeat", + "} def", + "/Tj {", + " fCol", // because stringwidth has to draw Type 3 chars + " 1 index stringwidth pdfTextMat idtransform pop", + " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse", + " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32", + " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0", + " pdfTextMat dtransform", + " 6 5 roll Tj1", + "} def", + "/Tj16 {", + " fCol", // because stringwidth has to draw Type 3 chars + " 2 index stringwidth pdfTextMat idtransform pop", + " sub exch div", + " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32", + " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0", + " pdfTextMat dtransform", + " 6 5 roll Tj1", + "} def", + "/Tj16V {", + " fCol", // because stringwidth has to draw Type 3 chars + " 2 index stringwidth pdfTextMat idtransform exch pop", + " sub exch div", + " 0 pdfWordSpacing pdfTextMat dtransform 32", + " 4 3 roll pdfCharSpacing add 0 exch", + " pdfTextMat dtransform", + " 6 5 roll Tj1", + "} def", + "/Tj1 {", + " 0 pdfTextRise pdfTextMat dtransform rmoveto", + " currentpoint 8 2 roll", + " pdfTextRender 1 and 0 eq {", + " 6 copy awidthshow", + " } if", + " pdfTextRender 3 and dup 1 eq exch 2 eq or {", + " 7 index 7 index moveto", + " 6 copy", + " currentfont /FontType get 3 eq { fCol } { sCol } ifelse", + " false awcp currentpoint stroke moveto", + " } if", + " pdfTextRender 4 and 0 ne {", + " 8 6 roll moveto", + " false awcp", + " /pdfTextClipPath [ pdfTextClipPath aload pop", + " {/moveto cvx}", + " {/lineto cvx}", + " {/curveto cvx}", + " {/closepath cvx}", + " pathforall ] def", + " currentpoint newpath moveto", + " } {", + " 8 {pop} repeat", + " } ifelse", + " 0 pdfTextRise neg pdfTextMat dtransform rmoveto", + "} def", + "/TJm { pdfFontSize 0.001 mul mul neg 0", + " pdfTextMat dtransform rmoveto } def", + "/TJmV { pdfFontSize 0.001 mul mul neg 0 exch", + " pdfTextMat dtransform rmoveto } def", + "/Tclip { pdfTextClipPath cvx exec clip newpath", + " /pdfTextClipPath [] def } def", + "~1ns", + "% Level 1 image operators", + "~1n", + "/pdfIm1 {", + " /pdfImBuf1 4 index string def", + " { currentfile pdfImBuf1 readhexstring pop } image", + "} def", + "~1s", + "/pdfIm1Sep {", + " /pdfImBuf1 4 index string def", + " /pdfImBuf2 4 index string def", + " /pdfImBuf3 4 index string def", + " /pdfImBuf4 4 index string def", + " { currentfile pdfImBuf1 readhexstring pop }", + " { currentfile pdfImBuf2 readhexstring pop }", + " { currentfile pdfImBuf3 readhexstring pop }", + " { currentfile pdfImBuf4 readhexstring pop }", + " true 4 colorimage", + "} def", + "~1ns", + "/pdfImM1 {", + " fCol /pdfImBuf1 4 index 7 add 8 idiv string def", + " { currentfile pdfImBuf1 readhexstring pop } imagemask", + "} def", + "/pdfImM1a {", + " { 2 copy get exch 1 add exch } imagemask", + " pop pop", + "} def", + "~23sn", + "% Level 2 image operators", + "/pdfImBuf 100 string def", + "/pdfIm {", + " image", + " { currentfile pdfImBuf readline", + " not { pop exit } if", + " (%-EOD-) eq { exit } if } loop", + "} def", + "~23s", + "/pdfImSep {", + " findcmykcustomcolor exch", + " dup /Width get /pdfImBuf1 exch string def", + " dup /Decode get aload pop 1 index sub /pdfImDecodeRange exch def", + " /pdfImDecodeLow exch def", + " begin Width Height BitsPerComponent ImageMatrix DataSource end", + " /pdfImData exch def", + " { pdfImData pdfImBuf1 readstring pop", + " 0 1 2 index length 1 sub {", + " 1 index exch 2 copy get", + " pdfImDecodeRange mul 255 div pdfImDecodeLow add round cvi", + " 255 exch sub put", + " } for }", + " 6 5 roll customcolorimage", + " { currentfile pdfImBuf readline", + " not { pop exit } if", + " (%-EOD-) eq { exit } if } loop", + "} def", + "~23sn", + "/pdfImM {", + " fCol imagemask", + " { currentfile pdfImBuf readline", + " not { pop exit } if", + " (%-EOD-) eq { exit } if } loop", + "} def", + "/pr { 2 index 2 index 3 2 roll putinterval 4 add } def", + "/pdfImClip {", + " gsave", + " 0 2 4 index length 1 sub {", + " dup 4 index exch 2 copy", + " get 5 index div put", + " 1 add 3 index exch 2 copy", + " get 3 index div put", + " } for", + " pop pop rectclip", + "} def", + "/pdfImClipEnd { grestore } def", + "~23sn", + "% shading operators", + "/colordelta {", + " false 0 1 3 index length 1 sub {", + " dup 4 index exch get 3 index 3 2 roll get sub abs 0.004 gt {", + " pop true", + " } if", + " } for", + " exch pop exch pop", + "} def", + "/funcCol { func n array astore } def", + "/funcSH {", + " dup 0 eq {", + " true", + " } {", + " dup 6 eq {", + " false", + " } {", + " 4 index 4 index funcCol dup", + " 6 index 4 index funcCol dup", + " 3 1 roll colordelta 3 1 roll", + " 5 index 5 index funcCol dup", + " 3 1 roll colordelta 3 1 roll", + " 6 index 8 index funcCol dup", + " 3 1 roll colordelta 3 1 roll", + " colordelta or or or", + " } ifelse", + " } ifelse", + " {", + " 1 add", + " 4 index 3 index add 0.5 mul exch 4 index 3 index add 0.5 mul exch", + " 6 index 6 index 4 index 4 index 4 index funcSH", + " 2 index 6 index 6 index 4 index 4 index funcSH", + " 6 index 2 index 4 index 6 index 4 index funcSH", + " 5 3 roll 3 2 roll funcSH pop pop", + " } {", + " pop 3 index 2 index add 0.5 mul 3 index 2 index add 0.5 mul", + "~23n", + " funcCol sc", + "~23s", + " funcCol aload pop k", + "~23sn", + " dup 4 index exch mat transform m", + " 3 index 3 index mat transform l", + " 1 index 3 index mat transform l", + " mat transform l pop pop h f*", + " } ifelse", + "} def", + "/axialCol {", + " dup 0 lt {", + " pop t0", + " } {", + " dup 1 gt {", + " pop t1", + " } {", + " dt mul t0 add", + " } ifelse", + " } ifelse", + " func n array astore", + "} def", + "/axialSH {", + " dup 0 eq {", + " true", + " } {", + " dup 8 eq {", + " false", + " } {", + " 2 index axialCol 2 index axialCol colordelta", + " } ifelse", + " } ifelse", + " {", + " 1 add 3 1 roll 2 copy add 0.5 mul", + " dup 4 3 roll exch 4 index axialSH", + " exch 3 2 roll axialSH", + " } {", + " pop 2 copy add 0.5 mul", + "~23n", + " axialCol sc", + "~23s", + " axialCol aload pop k", + "~23sn", + " exch dup dx mul x0 add exch dy mul y0 add", + " 3 2 roll dup dx mul x0 add exch dy mul y0 add", + " dx abs dy abs ge {", + " 2 copy yMin sub dy mul dx div add yMin m", + " yMax sub dy mul dx div add yMax l", + " 2 copy yMax sub dy mul dx div add yMax l", + " yMin sub dy mul dx div add yMin l", + " h f*", + " } {", + " exch 2 copy xMin sub dx mul dy div add xMin exch m", + " xMax sub dx mul dy div add xMax exch l", + " exch 2 copy xMax sub dx mul dy div add xMax exch l", + " xMin sub dx mul dy div add xMin exch l", + " h f*", + " } ifelse", + " } ifelse", + "} def", + "/radialCol {", + " dup t0 lt {", + " pop t0", + " } {", + " dup t1 gt {", + " pop t1", + " } if", + " } ifelse", + " func n array astore", + "} def", + "/radialSH {", + " dup 0 eq {", + " true", + " } {", + " dup 8 eq {", + " false", + " } {", + " 2 index dt mul t0 add radialCol", + " 2 index dt mul t0 add radialCol colordelta", + " } ifelse", + " } ifelse", + " {", + " 1 add 3 1 roll 2 copy add 0.5 mul", + " dup 4 3 roll exch 4 index radialSH", + " exch 3 2 roll radialSH", + " } {", + " pop 2 copy add 0.5 mul dt mul t0 add", + "~23n", + " radialCol sc", + "~23s", + " radialCol aload pop k", + "~23sn", + " encl {", + " exch dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add", + " 0 360 arc h", + " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add", + " 360 0 arcn h f", + " } {", + " 2 copy", + " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add", + " a1 a2 arcn", + " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add", + " a2 a1 arcn h", + " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add", + " a1 a2 arc", + " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add", + " a2 a1 arc h f", + " } ifelse", + " } ifelse", + "} def", + "~123sn", + "end", + NULL +}; + +static char *cmapProlog[] = { + "/CIDInit /ProcSet findresource begin", + "10 dict begin", + " begincmap", + " /CMapType 1 def", + " /CMapName /Identity-H def", + " /CIDSystemInfo 3 dict dup begin", + " /Registry (Adobe) def", + " /Ordering (Identity) def", + " /Supplement 0 def", + " end def", + " 1 begincodespacerange", + " <0000> ", + " endcodespacerange", + " 0 usefont", + " 1 begincidrange", + " <0000> 0", + " endcidrange", + " endcmap", + " currentdict CMapName exch /CMap defineresource pop", + "end", + "10 dict begin", + " begincmap", + " /CMapType 1 def", + " /CMapName /Identity-V def", + " /CIDSystemInfo 3 dict dup begin", + " /Registry (Adobe) def", + " /Ordering (Identity) def", + " /Supplement 0 def", + " end def", + " /WMode 1 def", + " 1 begincodespacerange", + " <0000> ", + " endcodespacerange", + " 0 usefont", + " 1 begincidrange", + " <0000> 0", + " endcidrange", + " endcmap", + " currentdict CMapName exch /CMap defineresource pop", + "end", + "end", + NULL +}; + +//------------------------------------------------------------------------ +// Fonts +//------------------------------------------------------------------------ + +struct PSSubstFont { + char *psName; // PostScript name + double mWidth; // width of 'm' character +}; + +static char *psFonts[] = { + "Courier", + "Courier-Bold", + "Courier-Oblique", + "Courier-BoldOblique", + "Helvetica", + "Helvetica-Bold", + "Helvetica-Oblique", + "Helvetica-BoldOblique", + "Symbol", + "Times-Roman", + "Times-Bold", + "Times-Italic", + "Times-BoldItalic", + "ZapfDingbats", + NULL +}; + +static PSSubstFont psSubstFonts[] = { + {"Helvetica", 0.833}, + {"Helvetica-Oblique", 0.833}, + {"Helvetica-Bold", 0.889}, + {"Helvetica-BoldOblique", 0.889}, + {"Times-Roman", 0.788}, + {"Times-Italic", 0.722}, + {"Times-Bold", 0.833}, + {"Times-BoldItalic", 0.778}, + {"Courier", 0.600}, + {"Courier-Oblique", 0.600}, + {"Courier-Bold", 0.600}, + {"Courier-BoldOblique", 0.600} +}; + +// Info for 8-bit fonts +struct PSFont8Info { + Ref fontID; + Gushort *codeToGID; // code-to-GID mapping for TrueType fonts +}; + +// Encoding info for substitute 16-bit font +struct PSFont16Enc { + Ref fontID; + GString *enc; +}; + +//------------------------------------------------------------------------ +// process colors +//------------------------------------------------------------------------ + +#define psProcessCyan 1 +#define psProcessMagenta 2 +#define psProcessYellow 4 +#define psProcessBlack 8 +#define psProcessCMYK 15 + +//------------------------------------------------------------------------ +// PSOutCustomColor +//------------------------------------------------------------------------ + +class PSOutCustomColor { +public: + + PSOutCustomColor(double cA, double mA, + double yA, double kA, GString *nameA); + ~PSOutCustomColor(); + + double c, m, y, k; + GString *name; + PSOutCustomColor *next; +}; + +PSOutCustomColor::PSOutCustomColor(double cA, double mA, + double yA, double kA, GString *nameA) { + c = cA; + m = mA; + y = yA; + k = kA; + name = nameA; + next = NULL; +} + +PSOutCustomColor::~PSOutCustomColor() { + delete name; +} + +//------------------------------------------------------------------------ + +struct PSOutImgClipRect { + int x0, x1, y0, y1; +}; + +//------------------------------------------------------------------------ +// DeviceNRecoder +//------------------------------------------------------------------------ + +class DeviceNRecoder: public FilterStream { +public: + + DeviceNRecoder(Stream *strA, int widthA, int heightA, + GfxImageColorMap *colorMapA); + virtual ~DeviceNRecoder(); + virtual StreamKind getKind() { return strWeird; } + virtual void reset(); + virtual int getChar() + { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx++]; } + virtual int lookChar() + { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx]; } + virtual GString *getPSFilter(int /*psLevel*/, char * /*indent*/) { return NULL; } + virtual GBool isBinary(GBool /*last*/ = gTrue) { return gTrue; } + virtual GBool isEncoder() { return gTrue; } + +private: + + GBool fillBuf(); + + int width, height; + GfxImageColorMap *colorMap; + Function *func; + ImageStream *imgStr; + int buf[gfxColorMaxComps]; + int pixelIdx; + int bufIdx; + int bufSize; +}; + +DeviceNRecoder::DeviceNRecoder(Stream *strA, int widthA, int heightA, + GfxImageColorMap *colorMapA): + FilterStream(strA) { + width = widthA; + height = heightA; + colorMap = colorMapA; + imgStr = NULL; + pixelIdx = 0; + bufIdx = gfxColorMaxComps; + bufSize = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())-> + getAlt()->getNComps(); + func = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())-> + getTintTransformFunc(); +} + +DeviceNRecoder::~DeviceNRecoder() { + if (imgStr) { + delete imgStr; + } +} + +void DeviceNRecoder::reset() { + imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), + colorMap->getBits()); + imgStr->reset(); +} + +GBool DeviceNRecoder::fillBuf() { + Guchar pixBuf[gfxColorMaxComps]; + GfxColor color; + double x[gfxColorMaxComps], y[gfxColorMaxComps]; + int i; + + if (pixelIdx >= width * height) { + return gFalse; + } + imgStr->getPixel(pixBuf); + colorMap->getColor(pixBuf, &color); + for (i = 0; + i < ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->getNComps(); + ++i) { + x[i] = colToDbl(color.c[i]); + } + func->transform(x, y); + for (i = 0; i < bufSize; ++i) { + buf[i] = (int)(y[i] * 255 + 0.5); + } + bufIdx = 0; + ++pixelIdx; + return gTrue; +} + +//------------------------------------------------------------------------ +// PSOutputDev +//------------------------------------------------------------------------ + +extern "C" { +typedef void (*SignalFunc)(int); +} + +static void outputToFile(void *stream, char *data, int len) { + fwrite(data, 1, len, (FILE *)stream); +} + +PSOutputDev::PSOutputDev(char *fileName, char *pstitle, XRef *xrefA, Catalog *catalog, + int firstPage, int lastPage, PSOutMode modeA, + int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, + GBool forceRasterizeA, + GBool manualCtrlA) { + FILE *f; + PSFileType fileTypeA; + + underlayCbk = NULL; + underlayCbkData = NULL; + overlayCbk = NULL; + overlayCbkData = NULL; + + fontIDs = NULL; + fontFileIDs = NULL; + fontFileNames = NULL; + font8Info = NULL; + font16Enc = NULL; + imgIDs = NULL; + formIDs = NULL; + xobjStack = NULL; + embFontList = NULL; + customColors = NULL; + haveTextClip = gFalse; + t3String = NULL; + + forceRasterize = forceRasterizeA; + + // open file or pipe + if (!strcmp(fileName, "-")) { + fileTypeA = psStdout; + f = stdout; + } else if (fileName[0] == '|') { + fileTypeA = psPipe; +#ifdef HAVE_POPEN +#ifndef WIN32 + signal(SIGPIPE, (SignalFunc)SIG_IGN); +#endif + if (!(f = popen(fileName + 1, "w"))) { + error(-1, "Couldn't run print command '%s'", fileName); + ok = gFalse; + return; + } +#else + error(-1, "Print commands are not supported ('%s')", fileName); + ok = gFalse; + return; +#endif + } else { + fileTypeA = psFile; + if (!(f = fopen(fileName, "w"))) { + error(-1, "Couldn't open PostScript file '%s'", fileName); + ok = gFalse; + return; + } + } + + init(outputToFile, f, fileTypeA, pstitle, + xrefA, catalog, firstPage, lastPage, modeA, + imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA); +} + +void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA, + PSFileType fileTypeA, char *pstitle, XRef *xrefA, Catalog *catalog, + int firstPage, int lastPage, PSOutMode modeA, + int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, + GBool manualCtrlA) { + Page *page; + PDFRectangle *box; + + // initialize + setlocale(LC_NUMERIC,"POSIX"); + ok = gTrue; + outputFunc = outputFuncA; + outputStream = outputStreamA; + fileType = fileTypeA; + xref = xrefA; + level = globalParams->getPSLevel(); + mode = modeA; + paperWidth = globalParams->getPSPaperWidth(); + paperHeight = globalParams->getPSPaperHeight(); + imgLLX = imgLLXA; + imgLLY = imgLLYA; + imgURX = imgURXA; + imgURY = imgURYA; + if (imgLLX == 0 && imgURX == 0 && imgLLY == 0 && imgURY == 0) { + globalParams->getPSImageableArea(&imgLLX, &imgLLY, &imgURX, &imgURY); + } + if (paperWidth < 0 || paperHeight < 0) { + // this check is needed in case the document has zero pages + if (firstPage > 0 && firstPage <= catalog->getNumPages()) { + page = catalog->getPage(firstPage); + paperWidth = (int)ceil(page->getMediaWidth()); + paperHeight = (int)ceil(page->getMediaHeight()); + } else { + paperWidth = 1; + paperHeight = 1; + } + imgLLX = imgLLY = 0; + imgURX = paperWidth; + imgURY = paperHeight; + } + preload = globalParams->getPSPreload(); + manualCtrl = manualCtrlA; + if (mode == psModeForm) { + lastPage = firstPage; + } + processColors = 0; + inType3Char = gFalse; + +#if OPI_SUPPORT + // initialize OPI nesting levels + opi13Nest = 0; + opi20Nest = 0; +#endif + + tx0 = ty0 = -1; + xScale0 = yScale0 = 0; + rotate0 = -1; + clipLLX0 = clipLLY0 = 0; + clipURX0 = clipURY0 = -1; + + // initialize fontIDs, fontFileIDs, and fontFileNames lists + fontIDSize = 64; + fontIDLen = 0; + fontIDs = (Ref *)gmallocn(fontIDSize, sizeof(Ref)); + fontFileIDSize = 64; + fontFileIDLen = 0; + fontFileIDs = (Ref *)gmallocn(fontFileIDSize, sizeof(Ref)); + fontFileNameSize = 64; + fontFileNameLen = 0; + fontFileNames = (GString **)gmallocn(fontFileNameSize, sizeof(GString *)); + psFileNames = (GString **)gmallocn(fontFileNameSize, sizeof(GString *)); + nextTrueTypeNum = 0; + font8InfoLen = 0; + font8InfoSize = 0; + font16EncLen = 0; + font16EncSize = 0; + imgIDLen = 0; + imgIDSize = 0; + formIDLen = 0; + formIDSize = 0; + + xobjStack = new GList(); + numSaves = 0; + numTilingPatterns = 0; + nextFunc = 0; + + // initialize embedded font resource comment list + embFontList = new GString(); + + if (!manualCtrl) { + // this check is needed in case the document has zero pages + if (firstPage > 0 && firstPage <= catalog->getNumPages()) { + writeHeader(firstPage, lastPage, + catalog->getPage(firstPage)->getMediaBox(), + catalog->getPage(firstPage)->getCropBox(), + catalog->getPage(firstPage)->getRotate(), pstitle); + } else { + box = new PDFRectangle(0, 0, 1, 1); + writeHeader(firstPage, lastPage, box, box, 0, pstitle); + delete box; + } + if (mode != psModeForm) { + writePS("%%BeginProlog\n"); + } + writeXpdfProcset(); + if (mode != psModeForm) { + writePS("%%EndProlog\n"); + writePS("%%BeginSetup\n"); + } + writeDocSetup(catalog, firstPage, lastPage); + if (mode != psModeForm) { + writePS("%%EndSetup\n"); + } + } + + // initialize sequential page number + seqPage = 1; +} + +PSOutputDev::~PSOutputDev() { + PSOutCustomColor *cc; + int i; + + if (ok) { + if (!manualCtrl) { + writePS("%%Trailer\n"); + writeTrailer(); + if (mode != psModeForm) { + writePS("%%EOF\n"); + } + } + if (fileType == psFile) { +#ifdef MACOS + ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle); +#endif + fclose((FILE *)outputStream); + } +#ifdef HAVE_POPEN + else if (fileType == psPipe) { + pclose((FILE *)outputStream); +#ifndef WIN32 + signal(SIGPIPE, (SignalFunc)SIG_DFL); +#endif + } +#endif + } + if (embFontList) { + delete embFontList; + } + if (fontIDs) { + gfree(fontIDs); + } + if (fontFileIDs) { + gfree(fontFileIDs); + } + if (fontFileNames) { + for (i = 0; i < fontFileNameLen; ++i) { + delete fontFileNames[i]; + } + gfree(fontFileNames); + } + if (font8Info) { + for (i = 0; i < font8InfoLen; ++i) { + gfree(font8Info[i].codeToGID); + } + gfree(font8Info); + } + if (psFileNames) { + for (i = 0; i < fontFileNameLen; ++i) { + if (psFileNames[i]) + delete psFileNames[i]; + } + gfree(psFileNames); + } + if (font16Enc) { + for (i = 0; i < font16EncLen; ++i) { + delete font16Enc[i].enc; + } + gfree(font16Enc); + } + gfree(imgIDs); + gfree(formIDs); + if (xobjStack) { + delete xobjStack; + } + while (customColors) { + cc = customColors; + customColors = cc->next; + delete cc; + } +} + +void PSOutputDev::writeHeader(int firstPage, int lastPage, + PDFRectangle *mediaBox, PDFRectangle *cropBox, + int pageRotate, char *pstitle) { + Object info, obj1; + double x1, y1, x2, y2; + + switch (mode) { + case psModePS: + writePS("%!PS-Adobe-3.0\n"); + break; + case psModeEPS: + writePS("%!PS-Adobe-3.0 EPSF-3.0\n"); + break; + case psModeForm: + writePS("%!PS-Adobe-3.0 Resource-Form\n"); + break; + } + + xref->getDocInfo(&info); + if (info.isDict() && info.dictLookup("Creator", &obj1)->isString()) { + writePS("%%Creator: "); + writePSTextLine(obj1.getString()); + } + obj1.free(); + info.free(); + if(pstitle) { + writePSFmt("%%Title: {0:s}\n", pstitle); + } + writePSFmt("%%LanguageLevel: {0:d}\n", + (level == psLevel1 || level == psLevel1Sep) ? 1 : + (level == psLevel2 || level == psLevel2Sep) ? 2 : 3); + if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) { + writePS("%%DocumentProcessColors: (atend)\n"); + writePS("%%DocumentCustomColors: (atend)\n"); + } + writePS("%%DocumentSuppliedResources: (atend)\n"); + + switch (mode) { + case psModePS: + writePSFmt("%%DocumentMedia: plain {0:d} {1:d} 0 () ()\n", + paperWidth, paperHeight); + writePSFmt("%%BoundingBox: 0 0 {0:d} {1:d}\n", paperWidth, paperHeight); + writePSFmt("%%Pages: {0:d}\n", lastPage - firstPage + 1); + writePS("%%EndComments\n"); + writePS("%%BeginDefaults\n"); + writePS("%%PageMedia: plain\n"); + writePS("%%EndDefaults\n"); + break; + case psModeEPS: + epsX1 = cropBox->x1; + epsY1 = cropBox->y1; + epsX2 = cropBox->x2; + epsY2 = cropBox->y2; + if (pageRotate == 0 || pageRotate == 180) { + x1 = epsX1; + y1 = epsY1; + x2 = epsX2; + y2 = epsY2; + } else { // pageRotate == 90 || pageRotate == 270 + x1 = 0; + y1 = 0; + x2 = epsY2 - epsY1; + y2 = epsX2 - epsX1; + } + writePSFmt("%%BoundingBox: {0:d} {1:d} {2:d} {3:d}\n", + (int)floor(x1), (int)floor(y1), (int)ceil(x2), (int)ceil(y2)); + if (floor(x1) != ceil(x1) || floor(y1) != ceil(y1) || + floor(x2) != ceil(x2) || floor(y2) != ceil(y2)) { + writePSFmt("%%HiResBoundingBox: {0:.4g} {1:.4g} {2:.4g} {3:.4g}\n", + x1, y1, x2, y2); + } + writePS("%%EndComments\n"); + break; + case psModeForm: + writePS("%%EndComments\n"); + writePS("32 dict dup begin\n"); + writePSFmt("/BBox [{0:d} {1:d} {2:d} {3:d}] def\n", + (int)floor(mediaBox->x1), (int)floor(mediaBox->y1), + (int)ceil(mediaBox->x2), (int)ceil(mediaBox->y2)); + writePS("/FormType 1 def\n"); + writePS("/Matrix [1 0 0 1 0 0] def\n"); + break; + } +} + +void PSOutputDev::writeXpdfProcset() { + GBool lev1, lev2, lev3, sep, nonSep; + char **p; + char *q; + + writePSFmt("%%BeginResource: procset xpdf {0:s} 0\n", xpdfVersion); + writePSFmt("%%Copyright: {0:s}\n", xpdfCopyright); + lev1 = lev2 = lev3 = sep = nonSep = gTrue; + for (p = prolog; *p; ++p) { + if ((*p)[0] == '~') { + lev1 = lev2 = lev3 = sep = nonSep = gFalse; + for (q = *p + 1; *q; ++q) { + switch (*q) { + case '1': lev1 = gTrue; break; + case '2': lev2 = gTrue; break; + case '3': lev3 = gTrue; break; + case 's': sep = gTrue; break; + case 'n': nonSep = gTrue; break; + } + } + } else if ((level == psLevel1 && lev1 && nonSep) || + (level == psLevel1Sep && lev1 && sep) || + (level == psLevel2 && lev2 && nonSep) || + (level == psLevel2Sep && lev2 && sep) || + (level == psLevel3 && lev3 && nonSep) || + (level == psLevel3Sep && lev3 && sep)) { + writePSFmt("{0:s}\n", *p); + } + } + writePS("%%EndResource\n"); + + if (level >= psLevel3) { + for (p = cmapProlog; *p; ++p) { + writePSFmt("{0:s}\n", *p); + } + } +} + +void PSOutputDev::writeDocSetup(Catalog *catalog, + int firstPage, int lastPage) { + Page *page; + Dict *resDict; + Annots *annots; + Object obj1, obj2; + int pg, i; + + if (mode == psModeForm) { + // swap the form and xpdf dicts + writePS("xpdf end begin dup begin\n"); + } else { + writePS("xpdf begin\n"); + } + for (pg = firstPage; pg <= lastPage; ++pg) { + page = catalog->getPage(pg); + if ((resDict = page->getResourceDict())) { + setupResources(resDict); + } + annots = new Annots(xref, catalog, page->getAnnots(&obj1)); + obj1.free(); + for (i = 0; i < annots->getNumAnnots(); ++i) { + if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) { + obj1.streamGetDict()->lookup("Resources", &obj2); + if (obj2.isDict()) { + setupResources(obj2.getDict()); + } + obj2.free(); + } + obj1.free(); + } + delete annots; + } + if (mode != psModeForm) { + if (mode != psModeEPS && !manualCtrl) { + writePSFmt("{0:d} {1:d} {2:s} pdfSetup\n", + paperWidth, paperHeight, + globalParams->getPSDuplex() ? "true" : "false"); + } +#if OPI_SUPPORT + if (globalParams->getPSOPI()) { + writePS("/opiMatrix matrix currentmatrix def\n"); + } +#endif + } +} + +void PSOutputDev::writePageTrailer() { + if (mode != psModeForm) { + writePS("pdfEndPage\n"); + } +} + +void PSOutputDev::writeTrailer() { + PSOutCustomColor *cc; + + if (mode == psModeForm) { + writePS("/Foo exch /Form defineresource pop\n"); + } else { + writePS("end\n"); + writePS("%%DocumentSuppliedResources:\n"); + writePS(embFontList->getCString()); + if (level == psLevel1Sep || level == psLevel2Sep || + level == psLevel3Sep) { + writePS("%%DocumentProcessColors:"); + if (processColors & psProcessCyan) { + writePS(" Cyan"); + } + if (processColors & psProcessMagenta) { + writePS(" Magenta"); + } + if (processColors & psProcessYellow) { + writePS(" Yellow"); + } + if (processColors & psProcessBlack) { + writePS(" Black"); + } + writePS("\n"); + writePS("%%DocumentCustomColors:"); + for (cc = customColors; cc; cc = cc->next) { + writePSFmt(" ({0:s})", cc->name->getCString()); + } + writePS("\n"); + writePS("%%CMYKCustomColor:\n"); + for (cc = customColors; cc; cc = cc->next) { + writePSFmt("%%+ {0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t})\n", + cc->c, cc->m, cc->y, cc->k, cc->name); + } + } + } +} + +void PSOutputDev::setupResources(Dict *resDict) { + Object xObjDict, xObjRef, xObj, patDict, patRef, pat, resObj; + Ref ref0, ref1; + GBool skip; + int i, j; + + setupFonts(resDict); + setupImages(resDict); + setupForms(resDict); + + //----- recursively scan XObjects + resDict->lookup("XObject", &xObjDict); + if (xObjDict.isDict()) { + for (i = 0; i < xObjDict.dictGetLength(); ++i) { + + // avoid infinite recursion on XObjects + skip = gFalse; + if ((xObjDict.dictGetValNF(i, &xObjRef)->isRef())) { + ref0 = xObjRef.getRef(); + for (j = 0; j < xobjStack->getLength(); ++j) { + ref1 = *(Ref *)xobjStack->get(j); + if (ref1.num == ref0.num && ref1.gen == ref0.gen) { + skip = gTrue; + break; + } + } + if (!skip) { + xobjStack->append(&ref0); + } + } + if (!skip) { + + // process the XObject's resource dictionary + xObjDict.dictGetVal(i, &xObj); + if (xObj.isStream()) { + xObj.streamGetDict()->lookup("Resources", &resObj); + if (resObj.isDict()) { + setupResources(resObj.getDict()); + } + resObj.free(); + } + xObj.free(); + } + + if (xObjRef.isRef() && !skip) { + xobjStack->del(xobjStack->getLength() - 1); + } + xObjRef.free(); + } + } + xObjDict.free(); + + //----- recursively scan Patterns + resDict->lookup("Pattern", &patDict); + if (patDict.isDict()) { + inType3Char = gTrue; + for (i = 0; i < patDict.dictGetLength(); ++i) { + + // avoid infinite recursion on Patterns + skip = gFalse; + if ((patDict.dictGetValNF(i, &patRef)->isRef())) { + ref0 = patRef.getRef(); + for (j = 0; j < xobjStack->getLength(); ++j) { + ref1 = *(Ref *)xobjStack->get(j); + if (ref1.num == ref0.num && ref1.gen == ref0.gen) { + skip = gTrue; + break; + } + } + if (!skip) { + xobjStack->append(&ref0); + } + } + if (!skip) { + + // process the Pattern's resource dictionary + patDict.dictGetVal(i, &pat); + if (pat.isStream()) { + pat.streamGetDict()->lookup("Resources", &resObj); + if (resObj.isDict()) { + setupResources(resObj.getDict()); + } + resObj.free(); + } + pat.free(); + } + + if (patRef.isRef() && !skip) { + xobjStack->del(xobjStack->getLength() - 1); + } + patRef.free(); + } + inType3Char = gFalse; + } + patDict.free(); +} + +void PSOutputDev::setupFonts(Dict *resDict) { + Object obj1, obj2; + Ref r; + GfxFontDict *gfxFontDict; + GfxFont *font; + int i; + + if (forceRasterize) return; + + gfxFontDict = NULL; + resDict->lookupNF("Font", &obj1); + if (obj1.isRef()) { + obj1.fetch(xref, &obj2); + if (obj2.isDict()) { + r = obj1.getRef(); + gfxFontDict = new GfxFontDict(xref, &r, obj2.getDict()); + } + obj2.free(); + } else if (obj1.isDict()) { + gfxFontDict = new GfxFontDict(xref, NULL, obj1.getDict()); + } + if (gfxFontDict) { + for (i = 0; i < gfxFontDict->getNumFonts(); ++i) { + if ((font = gfxFontDict->getFont(i))) { + setupFont(font, resDict); + } + } + delete gfxFontDict; + } + obj1.free(); +} + +void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { + Ref fontFileID; + GString *name; + PSFontParam *fontParam; + GString *psName; + char buf[16]; + GBool subst; + UnicodeMap *uMap; + char *charName; + double xs, ys; + int code; + double w1, w2; + double *fm; + int i, j; + DisplayFontParam *dfp; + + // check if font is already set up + for (i = 0; i < fontIDLen; ++i) { + if (fontIDs[i].num == font->getID()->num && + fontIDs[i].gen == font->getID()->gen) { + return; + } + } + + // add entry to fontIDs list + if (fontIDLen >= fontIDSize) { + fontIDSize += 64; + fontIDs = (Ref *)greallocn(fontIDs, fontIDSize, sizeof(Ref)); + } + fontIDs[fontIDLen++] = *font->getID(); + + xs = ys = 1; + subst = gFalse; + + // check for resident 8-bit font + if (font->getName() && + (fontParam = globalParams->getPSFont(font->getName()))) { + psName = new GString(fontParam->psFontName->getCString()); + + // check for embedded Type 1 font + } else if (globalParams->getPSEmbedType1() && + font->getType() == fontType1 && + font->getEmbeddedFontID(&fontFileID)) { + psName = filterPSName(font->getEmbeddedFontName()); + setupEmbeddedType1Font(&fontFileID, psName); + + // check for embedded Type 1C font + } else if (globalParams->getPSEmbedType1() && + font->getType() == fontType1C && + font->getEmbeddedFontID(&fontFileID)) { + // use the PDF font name because the embedded font name might + // not include the subset prefix + psName = filterPSName(font->getOrigName()); + setupEmbeddedType1CFont(font, &fontFileID, psName); + + // check for embedded OpenType - Type 1C font + } else if (globalParams->getPSEmbedType1() && + font->getType() == fontType1COT && + font->getEmbeddedFontID(&fontFileID)) { + // use the PDF font name because the embedded font name might + // not include the subset prefix + psName = filterPSName(font->getOrigName()); + setupEmbeddedOpenTypeT1CFont(font, &fontFileID, psName); + + // check for external Type 1 font file + } else if (globalParams->getPSEmbedType1() && + font->getType() == fontType1 && + font->getExtFontFile()) { + // this assumes that the PS font name matches the PDF font name + psName = font->getName()->copy(); + setupExternalType1Font(font->getExtFontFile(), psName); + + // check for embedded TrueType font + } else if (globalParams->getPSEmbedTrueType() && + (font->getType() == fontTrueType || + font->getType() == fontTrueTypeOT) && + font->getEmbeddedFontID(&fontFileID)) { + psName = filterPSName(font->getEmbeddedFontName()); + setupEmbeddedTrueTypeFont(font, &fontFileID, psName); + + // check for external TrueType font file + } else if (globalParams->getPSEmbedTrueType() && + font->getType() == fontTrueType && + font->getExtFontFile()) { + psName = setupExternalTrueTypeFont(font); + + // check for embedded CID PostScript font + } else if (globalParams->getPSEmbedCIDPostScript() && + font->getType() == fontCIDType0C && + font->getEmbeddedFontID(&fontFileID)) { + psName = filterPSName(font->getEmbeddedFontName()); + setupEmbeddedCIDType0Font(font, &fontFileID, psName); + + // check for embedded CID TrueType font + } else if (globalParams->getPSEmbedCIDTrueType() && + (font->getType() == fontCIDType2 || + font->getType() == fontCIDType2OT) && + font->getEmbeddedFontID(&fontFileID)) { + psName = filterPSName(font->getEmbeddedFontName()); + //~ should check to see if font actually uses vertical mode + setupEmbeddedCIDTrueTypeFont(font, &fontFileID, psName, gTrue); + + // check for embedded OpenType - CID CFF font + } else if (globalParams->getPSEmbedCIDPostScript() && + font->getType() == fontCIDType0COT && + font->getEmbeddedFontID(&fontFileID)) { + psName = filterPSName(font->getEmbeddedFontName()); + setupEmbeddedOpenTypeCFFFont(font, &fontFileID, psName); + + // check for Type 3 font + } else if (font->getType() == fontType3) { + psName = GString::format("T3_{0:d}_{1:d}", + font->getID()->num, font->getID()->gen); + setupType3Font(font, psName, parentResDict); + // check for external CID TrueType font file + } else if (globalParams->getPSEmbedCIDTrueType() && + font->getType() == fontCIDType2 && + font->getExtFontFile()) { + psName = setupExternalCIDTrueTypeFont(font, font->getExtFontFile()); + // do 8-bit font substitution + } else if (!font->isCIDFont()) { + subst = gTrue; + name = font->getName(); + psName = NULL; + if (name) { + for (i = 0; psFonts[i]; ++i) { + if (name->cmp(psFonts[i]) == 0) { + psName = new GString(psFonts[i]); + break; + } + } + } + if (!psName) { + if (font->isFixedWidth()) { + i = 8; + } else if (font->isSerif()) { + i = 4; + } else { + i = 0; + } + if (font->isBold()) { + i += 2; + } + if (font->isItalic()) { + i += 1; + } + psName = new GString(psSubstFonts[i].psName); + for (code = 0; code < 256; ++code) { + if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) && + charName[0] == 'm' && charName[1] == '\0') { + break; + } + } + if (code < 256) { + w1 = ((Gfx8BitFont *)font)->getWidth(code); + } else { + w1 = 0; + } + w2 = psSubstFonts[i].mWidth; + xs = w1 / w2; + if (xs < 0.1) { + xs = 1; + } + if (font->getType() == fontType3) { + // This is a hack which makes it possible to substitute for some + // Type 3 fonts. The problem is that it's impossible to know what + // the base coordinate system used in the font is without actually + // rendering the font. + ys = xs; + fm = font->getFontMatrix(); + if (fm[0] != 0) { + ys *= fm[3] / fm[0]; + } + } else { + ys = 1; + } + } + + // do 16-bit font substitution + } else if ((fontParam = globalParams-> + getPSFont16(font->getName(), + ((GfxCIDFont *)font)->getCollection(), + font->getWMode()))) { + subst = gTrue; + psName = fontParam->psFontName->copy(); + if (font16EncLen >= font16EncSize) { + font16EncSize += 16; + font16Enc = (PSFont16Enc *)greallocn(font16Enc, + font16EncSize, sizeof(PSFont16Enc)); + } + font16Enc[font16EncLen].fontID = *font->getID(); + font16Enc[font16EncLen].enc = fontParam->encoding->copy(); + if ((uMap = globalParams->getUnicodeMap(font16Enc[font16EncLen].enc))) { + uMap->decRefCnt(); + ++font16EncLen; + } else { + error(-1, "Couldn't find Unicode map for 16-bit font encoding '%s'", + font16Enc[font16EncLen].enc->getCString()); + } + + // try the display font for embedding + } else if (globalParams->getPSEmbedCIDTrueType() && + ((GfxCIDFont *)font)->getCollection() && + (dfp = globalParams-> + getDisplayCIDFont(font->getName(), + ((GfxCIDFont *)font)->getCollection())) && + dfp->kind == displayFontTT) { + psName = setupExternalCIDTrueTypeFont(font, dfp->tt.fileName, dfp->tt.faceIndex); + + // give up - can't do anything with this font + } else { + error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)", + font->getName() ? font->getName()->getCString() : "(unnamed)", + ((GfxCIDFont *)font)->getCollection() + ? ((GfxCIDFont *)font)->getCollection()->getCString() + : "(unknown)"); + return; + } + + // generate PostScript code to set up the font + if (font->isCIDFont()) { + if (level == psLevel3 || level == psLevel3Sep) { + writePSFmt("/F{0:d}_{1:d} /{2:t} {3:d} pdfMakeFont16L3\n", + font->getID()->num, font->getID()->gen, psName, + font->getWMode()); + } else { + writePSFmt("/F{0:d}_{1:d} /{2:t} {3:d} pdfMakeFont16\n", + font->getID()->num, font->getID()->gen, psName, + font->getWMode()); + } + } else { + writePSFmt("/F{0:d}_{1:d} /{2:t} {3:.4g} {4:.4g}\n", + font->getID()->num, font->getID()->gen, psName, xs, ys); + for (i = 0; i < 256; i += 8) { + writePS((char *)((i == 0) ? "[ " : " ")); + for (j = 0; j < 8; ++j) { + if (font->getType() == fontTrueType && + !subst && + !((Gfx8BitFont *)font)->getHasEncoding()) { + sprintf(buf, "c%02x", i+j); + charName = buf; + } else { + charName = ((Gfx8BitFont *)font)->getCharName(i+j); + // this is a kludge for broken PDF files that encode char 32 + // as .notdef + if (i+j == 32 && charName && !strcmp(charName, ".notdef")) { + charName = "space"; + } + } + writePS("/"); + writePSName(charName ? charName : (char *)".notdef"); + // the empty name is legal in PDF and PostScript, but PostScript + // uses a double-slash (//...) for "immediately evaluated names", + // so we need to add a space character here + if (charName && !charName[0]) { + writePS(" "); + } + } + writePS((i == 256-8) ? (char *)"]\n" : (char *)"\n"); + } + writePS("pdfMakeFont\n"); + } + + delete psName; +} + +void PSOutputDev::setupEmbeddedType1Font(Ref *id, GString *psName) { + static char hexChar[17] = "0123456789abcdef"; + Object refObj, strObj, obj1, obj2, obj3; + Dict *dict; + int length1, length2, length3; + int c; + int start[4]; + GBool binMode; + int i; + + // check if font is already embedded + for (i = 0; i < fontFileIDLen; ++i) { + if (fontFileIDs[i].num == id->num && + fontFileIDs[i].gen == id->gen) + return; + } + + // add entry to fontFileIDs list + if (fontFileIDLen >= fontFileIDSize) { + fontFileIDSize += 64; + fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); + } + fontFileIDs[fontFileIDLen++] = *id; + + // get the font stream and info + refObj.initRef(id->num, id->gen); + refObj.fetch(xref, &strObj); + refObj.free(); + if (!strObj.isStream()) { + error(-1, "Embedded font file object is not a stream"); + goto err1; + } + if (!(dict = strObj.streamGetDict())) { + error(-1, "Embedded font stream is missing its dictionary"); + goto err1; + } + dict->lookup("Length1", &obj1); + dict->lookup("Length2", &obj2); + dict->lookup("Length3", &obj3); + if (!obj1.isInt() || !obj2.isInt() || !obj3.isInt()) { + error(-1, "Missing length fields in embedded font stream dictionary"); + obj1.free(); + obj2.free(); + obj3.free(); + goto err1; + } + length1 = obj1.getInt(); + length2 = obj2.getInt(); + length3 = obj3.getInt(); + obj1.free(); + obj2.free(); + obj3.free(); + + // beginning comment + writePSFmt("%%BeginResource: font {0:t}\n", psName); + embFontList->append("%%+ font "); + embFontList->append(psName->getCString()); + embFontList->append("\n"); + + // copy ASCII portion of font + strObj.streamReset(); + for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i) { + writePSChar(c); + } + + // figure out if encrypted portion is binary or ASCII + binMode = gFalse; + for (i = 0; i < 4; ++i) { + start[i] = strObj.streamGetChar(); + if (start[i] == EOF) { + error(-1, "Unexpected end of file in embedded font stream"); + goto err1; + } + if (!((start[i] >= '0' && start[i] <= '9') || + (start[i] >= 'A' && start[i] <= 'F') || + (start[i] >= 'a' && start[i] <= 'f'))) + binMode = gTrue; + } + + // convert binary data to ASCII + if (binMode) { + for (i = 0; i < 4; ++i) { + writePSChar(hexChar[(start[i] >> 4) & 0x0f]); + writePSChar(hexChar[start[i] & 0x0f]); + } +#if 0 // this causes trouble for various PostScript printers + // if Length2 is incorrect (too small), font data gets chopped, so + // we take a few extra characters from the trailer just in case + length2 += length3 >= 8 ? 8 : length3; +#endif + while (i < length2) { + if ((c = strObj.streamGetChar()) == EOF) { + break; + } + writePSChar(hexChar[(c >> 4) & 0x0f]); + writePSChar(hexChar[c & 0x0f]); + if (++i % 32 == 0) { + writePSChar('\n'); + } + } + if (i % 32 > 0) { + writePSChar('\n'); + } + + // already in ASCII format -- just copy it + } else { + for (i = 0; i < 4; ++i) { + writePSChar(start[i]); + } + for (i = 4; i < length2; ++i) { + if ((c = strObj.streamGetChar()) == EOF) { + break; + } + writePSChar(c); + } + } + + // write padding and "cleartomark" + for (i = 0; i < 8; ++i) { + writePS("00000000000000000000000000000000" + "00000000000000000000000000000000\n"); + } + writePS("cleartomark\n"); + + // ending comment + writePS("%%EndResource\n"); + + err1: + strObj.streamClose(); + strObj.free(); +} + +//~ This doesn't handle .pfb files or binary eexec data (which only +//~ happens in pfb files?). +void PSOutputDev::setupExternalType1Font(GString *fileName, GString *psName) { + FILE *fontFile; + int c; + int i; + + // check if font is already embedded + for (i = 0; i < fontFileNameLen; ++i) { + if (!fontFileNames[i]->cmp(fileName)) { + return; + } + } + + // add entry to fontFileNames list + if (fontFileNameLen >= fontFileNameSize) { + fontFileNameSize += 64; + fontFileNames = (GString **)greallocn(fontFileNames, + fontFileNameSize, sizeof(GString *)); + psFileNames = (GString **)greallocn(psFileNames, + fontFileNameSize, sizeof(GString *)); + } + fontFileNames[fontFileNameLen] = fileName->copy(); + psFileNames[fontFileNameLen] = psName->copy(); + fontFileNameLen++; + + // beginning comment + writePSFmt("%%BeginResource: font {0:t}\n", psName); + embFontList->append("%%+ font "); + embFontList->append(psName->getCString()); + embFontList->append("\n"); + + // copy the font file + if (!(fontFile = fopen(fileName->getCString(), "rb"))) { + error(-1, "Couldn't open external font file"); + return; + } + while ((c = fgetc(fontFile)) != EOF) { + writePSChar(c); + } + fclose(fontFile); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id, + GString *psName) { + char *fontBuf; + int fontLen; + FoFiType1C *ffT1C; + int i; + + // check if font is already embedded + for (i = 0; i < fontFileIDLen; ++i) { + if (fontFileIDs[i].num == id->num && + fontFileIDs[i].gen == id->gen) + return; + } + + // add entry to fontFileIDs list + if (fontFileIDLen >= fontFileIDSize) { + fontFileIDSize += 64; + fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); + } + fontFileIDs[fontFileIDLen++] = *id; + + // beginning comment + writePSFmt("%%BeginResource: font {0:t}\n", psName); + embFontList->append("%%+ font "); + embFontList->append(psName->getCString()); + embFontList->append("\n"); + + // convert it to a Type 1 font + fontBuf = font->readEmbFontFile(xref, &fontLen); + if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) { + ffT1C->convertToType1(psName->getCString(), NULL, gTrue, + outputFunc, outputStream); + delete ffT1C; + } + gfree(fontBuf); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupEmbeddedOpenTypeT1CFont(GfxFont *font, Ref *id, + GString *psName) { + char *fontBuf; + int fontLen; + FoFiTrueType *ffTT; + int i; + + // check if font is already embedded + for (i = 0; i < fontFileIDLen; ++i) { + if (fontFileIDs[i].num == id->num && + fontFileIDs[i].gen == id->gen) + return; + } + + // add entry to fontFileIDs list + if (fontFileIDLen >= fontFileIDSize) { + fontFileIDSize += 64; + fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); + } + fontFileIDs[fontFileIDLen++] = *id; + + // beginning comment + writePSFmt("%%BeginResource: font {0:t}\n", psName); + embFontList->append("%%+ font "); + embFontList->append(psName->getCString()); + embFontList->append("\n"); + + // convert it to a Type 1 font + fontBuf = font->readEmbFontFile(xref, &fontLen); + if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { + if (ffTT->isOpenTypeCFF()) { + ffTT->convertToType1(psName->getCString(), NULL, gTrue, + outputFunc, outputStream); + } + delete ffTT; + } + gfree(fontBuf); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, + GString *psName) { + char *fontBuf; + int fontLen; + FoFiTrueType *ffTT; + Gushort *codeToGID; + int i; + + // check if font is already embedded + for (i = 0; i < fontFileIDLen; ++i) { + if (fontFileIDs[i].num == id->num && + fontFileIDs[i].gen == id->gen) { + psName->appendf("_{0:d}", nextTrueTypeNum++); + break; + } + } + + // add entry to fontFileIDs list + if (i == fontFileIDLen) { + if (fontFileIDLen >= fontFileIDSize) { + fontFileIDSize += 64; + fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); + } + fontFileIDs[fontFileIDLen++] = *id; + } + + // beginning comment + writePSFmt("%%BeginResource: font {0:t}\n", psName); + embFontList->append("%%+ font "); + embFontList->append(psName->getCString()); + embFontList->append("\n"); + + // convert it to a Type 42 font + fontBuf = font->readEmbFontFile(xref, &fontLen); + if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { + codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT); + ffTT->convertToType42(psName->getCString(), + ((Gfx8BitFont *)font)->getHasEncoding() + ? ((Gfx8BitFont *)font)->getEncoding() + : (char **)NULL, + codeToGID, outputFunc, outputStream); + if (codeToGID) { + if (font8InfoLen >= font8InfoSize) { + font8InfoSize += 16; + font8Info = (PSFont8Info *)greallocn(font8Info, + font8InfoSize, + sizeof(PSFont8Info)); + } + font8Info[font8InfoLen].fontID = *font->getID(); + font8Info[font8InfoLen].codeToGID = codeToGID; + ++font8InfoLen; + } + delete ffTT; + } + gfree(fontBuf); + + // ending comment + writePS("%%EndResource\n"); +} + +GString *PSOutputDev::setupExternalTrueTypeFont(GfxFont *font) { + GString *fileName; + char *fontBuf; + int fontLen; + FoFiTrueType *ffTT; + Gushort *codeToGID; + GString *psName; + int i; + + // check if font is already embedded + fileName = font->getExtFontFile(); + for (i = 0; i < fontFileNameLen; ++i) { + if (!fontFileNames[i]->cmp(fileName)) { + return psFileNames[i]->copy(); + } + } + + psName = filterPSName(font->getName()); + // add entry to fontFileNames list + if (i == fontFileNameLen) { + if (fontFileNameLen >= fontFileNameSize) { + fontFileNameSize += 64; + fontFileNames = + (GString **)greallocn(fontFileNames, + fontFileNameSize, sizeof(GString *)); + psFileNames = + (GString **)greallocn(psFileNames, + fontFileNameSize, sizeof(GString *)); + } + fontFileNames[fontFileNameLen] = fileName->copy(); + psFileNames[fontFileNameLen] = psName->copy(); + fontFileNameLen++; + } + + // beginning comment + writePSFmt("%%BeginResource: font {0:t}\n", psName); + embFontList->append("%%+ font "); + embFontList->append(psName->getCString()); + embFontList->append("\n"); + + // convert it to a Type 42 font + fontBuf = font->readExtFontFile(&fontLen); + if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { + codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT); + ffTT->convertToType42(psName->getCString(), + ((Gfx8BitFont *)font)->getHasEncoding() + ? ((Gfx8BitFont *)font)->getEncoding() + : (char **)NULL, + codeToGID, outputFunc, outputStream); + if (codeToGID) { + if (font8InfoLen >= font8InfoSize) { + font8InfoSize += 16; + font8Info = (PSFont8Info *)greallocn(font8Info, + font8InfoSize, + sizeof(PSFont8Info)); + } + font8Info[font8InfoLen].fontID = *font->getID(); + font8Info[font8InfoLen].codeToGID = codeToGID; + ++font8InfoLen; + } + delete ffTT; + } + gfree(fontBuf); + + // ending comment + writePS("%%EndResource\n"); + return psName; +} + +GString *PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont *font, GString *fileName, int faceIndex) { + FoFiTrueType *ffTT; + Gushort *codeToGID; + GString *psName; + int i; + GString *myFileName; + + myFileName = fileName->copy(); + if (faceIndex > 0) { + char tmp[32]; + sprintf(tmp, ",%d", faceIndex); + myFileName->append(tmp); + } + // check if font is already embedded + for (i = 0; i < fontFileNameLen; ++i) { + if (!fontFileNames[i]->cmp(myFileName)) { + delete myFileName; + return psFileNames[i]->copy(); + } + } + + psName = filterPSName(font->getName()); + // add entry to fontFileNames list + if (i == fontFileNameLen) { + if (fontFileNameLen >= fontFileNameSize) { + fontFileNameSize += 64; + fontFileNames = + (GString **)grealloc(fontFileNames, + fontFileNameSize * sizeof(GString *)); + psFileNames = + (GString **)grealloc(psFileNames, + fontFileNameSize * sizeof(GString *)); + } + } + fontFileNames[fontFileNameLen] = myFileName; + psFileNames[fontFileNameLen] = psName->copy(); + fontFileNameLen++; + + // beginning comment + writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); + embFontList->append("%%+ font "); + embFontList->append(psName->getCString()); + embFontList->append("\n"); + + // convert it to a CID type2 font + if ((ffTT = FoFiTrueType::load(fileName->getCString(), faceIndex))) { + int n = ((GfxCIDFont *)font)->getCIDToGIDLen(); + if (n) { + codeToGID = (Gushort *)gmalloc(n * sizeof(Gushort)); + memcpy(codeToGID, ((GfxCIDFont *)font)->getCIDToGID(), n * sizeof(Gushort)); + } else { + codeToGID = ((GfxCIDFont *)font)->getCodeToGIDMap(ffTT, &n); + } + if (globalParams->getPSLevel() >= psLevel3) { + // Level 3: use a CID font + ffTT->convertToCIDType2(psName->getCString(), + codeToGID, n, gTrue, + outputFunc, outputStream); + } else { + // otherwise: use a non-CID composite font + ffTT->convertToType0(psName->getCString(), + codeToGID, n, gTrue, + outputFunc, outputStream); + } + gfree(codeToGID); + delete ffTT; + } + + // ending comment + writePS("%%EndResource\n"); + return psName; +} + +void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, + GString *psName) { + char *fontBuf; + int fontLen; + FoFiType1C *ffT1C; + int i; + + // check if font is already embedded + for (i = 0; i < fontFileIDLen; ++i) { + if (fontFileIDs[i].num == id->num && + fontFileIDs[i].gen == id->gen) + return; + } + + // add entry to fontFileIDs list + if (fontFileIDLen >= fontFileIDSize) { + fontFileIDSize += 64; + fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); + } + fontFileIDs[fontFileIDLen++] = *id; + + // beginning comment + writePSFmt("%%BeginResource: font {0:t}\n", psName); + embFontList->append("%%+ font "); + embFontList->append(psName->getCString()); + embFontList->append("\n"); + + // convert it to a Type 0 font + fontBuf = font->readEmbFontFile(xref, &fontLen); + if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) { + if (globalParams->getPSLevel() >= psLevel3) { + // Level 3: use a CID font + ffT1C->convertToCIDType0(psName->getCString(), outputFunc, outputStream); + } else { + // otherwise: use a non-CID composite font + ffT1C->convertToType0(psName->getCString(), outputFunc, outputStream); + } + delete ffT1C; + } + gfree(fontBuf); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, + GString *psName, + GBool needVerticalMetrics) { + char *fontBuf; + int fontLen; + FoFiTrueType *ffTT; + int i; + + // check if font is already embedded + for (i = 0; i < fontFileIDLen; ++i) { + if (fontFileIDs[i].num == id->num && + fontFileIDs[i].gen == id->gen) { + psName->appendf("_{0:d}", nextTrueTypeNum++); + break; + } + } + + // add entry to fontFileIDs list + if (fontFileIDLen >= fontFileIDSize) { + fontFileIDSize += 64; + fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); + } + fontFileIDs[fontFileIDLen++] = *id; + + // beginning comment + writePSFmt("%%BeginResource: font {0:t}\n", psName); + embFontList->append("%%+ font "); + embFontList->append(psName->getCString()); + embFontList->append("\n"); + + // convert it to a Type 0 font + fontBuf = font->readEmbFontFile(xref, &fontLen); + if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { + if (globalParams->getPSLevel() >= psLevel3) { + // Level 3: use a CID font + ffTT->convertToCIDType2(psName->getCString(), + ((GfxCIDFont *)font)->getCIDToGID(), + ((GfxCIDFont *)font)->getCIDToGIDLen(), + needVerticalMetrics, + outputFunc, outputStream); + } else { + // otherwise: use a non-CID composite font + ffTT->convertToType0(psName->getCString(), + ((GfxCIDFont *)font)->getCIDToGID(), + ((GfxCIDFont *)font)->getCIDToGIDLen(), + needVerticalMetrics, + outputFunc, outputStream); + } + delete ffTT; + } + gfree(fontBuf); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupEmbeddedOpenTypeCFFFont(GfxFont *font, Ref *id, + GString *psName) { + char *fontBuf; + int fontLen; + FoFiTrueType *ffTT; + int i; + + // check if font is already embedded + for (i = 0; i < fontFileIDLen; ++i) { + if (fontFileIDs[i].num == id->num && + fontFileIDs[i].gen == id->gen) + return; + } + + // add entry to fontFileIDs list + if (fontFileIDLen >= fontFileIDSize) { + fontFileIDSize += 64; + fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); + } + fontFileIDs[fontFileIDLen++] = *id; + + // beginning comment + writePSFmt("%%BeginResource: font {0:t}\n", psName); + embFontList->append("%%+ font "); + embFontList->append(psName->getCString()); + embFontList->append("\n"); + + // convert it to a Type 0 font + fontBuf = font->readEmbFontFile(xref, &fontLen); + if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { + if (ffTT->isOpenTypeCFF()) { + if (globalParams->getPSLevel() >= psLevel3) { + // Level 3: use a CID font + ffTT->convertToCIDType0(psName->getCString(), + outputFunc, outputStream); + } else { + // otherwise: use a non-CID composite font + ffTT->convertToType0(psName->getCString(), outputFunc, outputStream); + } + } + delete ffTT; + } + gfree(fontBuf); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupType3Font(GfxFont *font, GString *psName, + Dict *parentResDict) { + Dict *resDict; + Dict *charProcs; + Object charProc; + Gfx *gfx; + PDFRectangle box; + double *m; + GString *buf; + int i; + + // set up resources used by font + if ((resDict = ((Gfx8BitFont *)font)->getResources())) { + inType3Char = gTrue; + setupResources(resDict); + inType3Char = gFalse; + } else { + resDict = parentResDict; + } + + // beginning comment + writePSFmt("%%BeginResource: font {0:t}\n", psName); + embFontList->append("%%+ font "); + embFontList->append(psName->getCString()); + embFontList->append("\n"); + + // font dictionary + writePS("8 dict begin\n"); + writePS("/FontType 3 def\n"); + m = font->getFontMatrix(); + writePSFmt("/FontMatrix [{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g}] def\n", + m[0], m[1], m[2], m[3], m[4], m[5]); + m = font->getFontBBox(); + writePSFmt("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] def\n", + m[0], m[1], m[2], m[3]); + writePS("/Encoding 256 array def\n"); + writePS(" 0 1 255 { Encoding exch /.notdef put } for\n"); + writePS("/BuildGlyph {\n"); + writePS(" exch /CharProcs get exch\n"); + writePS(" 2 copy known not { pop /.notdef } if\n"); + writePS(" get exec\n"); + writePS("} bind def\n"); + writePS("/BuildChar {\n"); + writePS(" 1 index /Encoding get exch get\n"); + writePS(" 1 index /BuildGlyph get exec\n"); + writePS("} bind def\n"); + if ((charProcs = ((Gfx8BitFont *)font)->getCharProcs())) { + writePSFmt("/CharProcs {0:d} dict def\n", charProcs->getLength()); + writePS("CharProcs begin\n"); + box.x1 = m[0]; + box.y1 = m[1]; + box.x2 = m[2]; + box.y2 = m[3]; + gfx = new Gfx(xref, this, resDict, &box, NULL); + inType3Char = gTrue; + for (i = 0; i < charProcs->getLength(); ++i) { + t3Cacheable = gFalse; + t3NeedsRestore = gFalse; + writePS("/"); + writePSName(charProcs->getKey(i)); + writePS(" {\n"); + gfx->display(charProcs->getVal(i, &charProc)); + charProc.free(); + if (t3String) { + if (t3Cacheable) { + buf = GString::format("{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g} setcachedevice\n", + t3WX, t3WY, t3LLX, t3LLY, t3URX, t3URY); + } else { + buf = GString::format("{0:.4g} {1:.4g} setcharwidth\n", t3WX, t3WY); + } + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, t3String->getCString(), + t3String->getLength()); + delete t3String; + t3String = NULL; + } + if (t3NeedsRestore) { + (*outputFunc)(outputStream, "Q\n", 2); + } + writePS("} def\n"); + } + inType3Char = gFalse; + delete gfx; + writePS("end\n"); + } + writePS("currentdict end\n"); + writePSFmt("/{0:t} exch definefont pop\n", psName); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupImages(Dict *resDict) { + Object xObjDict, xObj, xObjRef, subtypeObj; + int i; + + if (!(mode == psModeForm || inType3Char || preload)) { + return; + } + + resDict->lookup("XObject", &xObjDict); + if (xObjDict.isDict()) { + for (i = 0; i < xObjDict.dictGetLength(); ++i) { + xObjDict.dictGetValNF(i, &xObjRef); + xObjDict.dictGetVal(i, &xObj); + if (xObj.isStream()) { + xObj.streamGetDict()->lookup("Subtype", &subtypeObj); + if (subtypeObj.isName("Image")) { + if (xObjRef.isRef()) { + setupImage(xObjRef.getRef(), xObj.getStream()); + } else { + error(-1, "Image in resource dict is not an indirect reference"); + } + } + subtypeObj.free(); + } + xObj.free(); + xObjRef.free(); + } + } + xObjDict.free(); +} + +void PSOutputDev::setupImage(Ref id, Stream *str) { + GBool useRLE, useCompressed, useASCIIHex; + GString *s; + int c; + int size, line, col, i; + + // check if image is already setup + for (i = 0; i < imgIDLen; ++i) { + if (imgIDs[i].num == id.num && imgIDs[i].gen == id.gen) { + return; + } + } + + // add entry to imgIDs list + if (imgIDLen >= imgIDSize) { + if (imgIDSize == 0) { + imgIDSize = 64; + } else { + imgIDSize *= 2; + } + imgIDs = (Ref *)greallocn(imgIDs, imgIDSize, sizeof(Ref)); + } + imgIDs[imgIDLen++] = id; + + // filters + //~ this does not correctly handle the DeviceN color space + //~ -- need to use DeviceNRecoder + if (level < psLevel2) { + useRLE = gFalse; + useCompressed = gFalse; + useASCIIHex = gTrue; + } else { + s = str->getPSFilter(level < psLevel3 ? 2 : 3, ""); + if (s) { + useRLE = gFalse; + useCompressed = gTrue; + delete s; + } else { + useRLE = gTrue; + useCompressed = gFalse; + } + useASCIIHex = level == psLevel1 || level == psLevel1Sep || + globalParams->getPSASCIIHex(); + } + if (useCompressed) { + str = str->getUndecodedStream(); + } + if (useRLE) { + str = new RunLengthEncoder(str); + } + if (useASCIIHex) { + str = new ASCIIHexEncoder(str); + } else { + str = new ASCII85Encoder(str); + } + + // compute image data size + str->reset(); + col = size = 0; + do { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == (useASCIIHex ? '>' : '~') || c == EOF) { + break; + } + if (c == 'z') { + ++col; + } else { + ++col; + for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == (useASCIIHex ? '>' : '~') || c == EOF) { + break; + } + ++col; + } + } + if (col > 225) { + ++size; + col = 0; + } + } while (c != (useASCIIHex ? '>' : '~') && c != EOF); + // add one entry for the final line of data; add another entry + // because the RunLengthDecode filter may read past the end + ++size; + if (useRLE) { + ++size; + } + writePSFmt("{0:d} array dup /ImData_{1:d}_{2:d} exch def\n", + size, id.num, id.gen); + str->close(); + + // write the data into the array + str->reset(); + line = col = 0; + writePS((char *)(useASCIIHex ? "dup 0 <" : "dup 0 <~")); + do { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == (useASCIIHex ? '>' : '~') || c == EOF) { + break; + } + if (c == 'z') { + writePSChar(c); + ++col; + } else { + writePSChar(c); + ++col; + for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == (useASCIIHex ? '>' : '~') || c == EOF) { + break; + } + writePSChar(c); + ++col; + } + } + // each line is: "dup nnnnn <~...data...~> put" + // so max data length = 255 - 20 = 235 + // chunks are 1 or 4 bytes each, so we have to stop at 232 + // but make it 225 just to be safe + if (col > 225) { + writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n")); + ++line; + writePSFmt((char *)(useASCIIHex ? "dup {0:d} <" : "dup {0:d} <~"), line); + col = 0; + } + } while (c != (useASCIIHex ? '>' : '~') && c != EOF); + writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n")); + if (useRLE) { + ++line; + writePSFmt("{0:d} <> put\n", line); + } else { + writePS("pop\n"); + } + str->close(); + + delete str; +} + +void PSOutputDev::setupForms(Dict *resDict) { + Object xObjDict, xObj, xObjRef, subtypeObj; + int i; + + if (!preload) { + return; + } + + resDict->lookup("XObject", &xObjDict); + if (xObjDict.isDict()) { + for (i = 0; i < xObjDict.dictGetLength(); ++i) { + xObjDict.dictGetValNF(i, &xObjRef); + xObjDict.dictGetVal(i, &xObj); + if (xObj.isStream()) { + xObj.streamGetDict()->lookup("Subtype", &subtypeObj); + if (subtypeObj.isName("Form")) { + if (xObjRef.isRef()) { + setupForm(xObjRef.getRef(), &xObj); + } else { + error(-1, "Form in resource dict is not an indirect reference"); + } + } + subtypeObj.free(); + } + xObj.free(); + xObjRef.free(); + } + } + xObjDict.free(); +} + +void PSOutputDev::setupForm(Ref id, Object *strObj) { + Dict *dict, *resDict; + Object matrixObj, bboxObj, resObj, obj1; + double m[6], bbox[4]; + PDFRectangle box; + Gfx *gfx; + int i; + + // check if form is already defined + for (i = 0; i < formIDLen; ++i) { + if (formIDs[i].num == id.num && formIDs[i].gen == id.gen) { + return; + } + } + + // add entry to formIDs list + if (formIDLen >= formIDSize) { + if (formIDSize == 0) { + formIDSize = 64; + } else { + formIDSize *= 2; + } + formIDs = (Ref *)greallocn(formIDs, formIDSize, sizeof(Ref)); + } + formIDs[formIDLen++] = id; + + dict = strObj->streamGetDict(); + + // get bounding box + dict->lookup("BBox", &bboxObj); + if (!bboxObj.isArray()) { + bboxObj.free(); + error(-1, "Bad form bounding box"); + return; + } + for (i = 0; i < 4; ++i) { + bboxObj.arrayGet(i, &obj1); + bbox[i] = obj1.getNum(); + obj1.free(); + } + bboxObj.free(); + + // get matrix + dict->lookup("Matrix", &matrixObj); + if (matrixObj.isArray()) { + for (i = 0; i < 6; ++i) { + matrixObj.arrayGet(i, &obj1); + m[i] = obj1.getNum(); + obj1.free(); + } + } else { + m[0] = 1; m[1] = 0; + m[2] = 0; m[3] = 1; + m[4] = 0; m[5] = 0; + } + matrixObj.free(); + + // get resources + dict->lookup("Resources", &resObj); + resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL; + + writePSFmt("/f_{0:d}_{1:d} {{\n", id.num, id.gen); + writePS("q\n"); + writePSFmt("[{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g}] cm\n", + m[0], m[1], m[2], m[3], m[4], m[5]); + + box.x1 = bbox[0]; + box.y1 = bbox[1]; + box.x2 = bbox[2]; + box.y2 = bbox[3]; + gfx = new Gfx(xref, this, resDict, &box, &box); + gfx->display(strObj); + delete gfx; + + writePS("Q\n"); + writePS("} def\n"); + + resObj.free(); +} + +GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/, + int rotateA, GBool useMediaBox, GBool crop, + int sliceX, int sliceY, + int sliceW, int sliceH, + GBool printing, Catalog *catalog, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { +#if HAVE_SPLASH + PreScanOutputDev *scan; + GBool rasterize; + SplashOutputDev *splashOut; + SplashColor paperColor; + PDFRectangle box; + GfxState *state; + SplashBitmap *bitmap; + Stream *str0, *str; + Object obj; + Guchar *p; + Guchar col[4]; + double m0, m1, m2, m3, m4, m5; + int c, w, h, x, y, comp, i; + + if (!forceRasterize) { + scan = new PreScanOutputDev(); + page->displaySlice(scan, 72, 72, rotateA, useMediaBox, crop, + sliceX, sliceY, sliceW, sliceH, + printing, catalog, abortCheckCbk, abortCheckCbkData); + rasterize = scan->usesTransparency(); + delete scan; + } else { + rasterize = true; + } + if (!rasterize) { + return gTrue; + } + + // rasterize the page + if (level == psLevel1) { + paperColor[0] = 0xff; + splashOut = new SplashOutputDev(splashModeMono8, 1, gFalse, + paperColor, gTrue, gFalse); +#if SPLASH_CMYK + } else if (level == psLevel1Sep) { + paperColor[0] = paperColor[1] = paperColor[2] = paperColor[3] = 0; + splashOut = new SplashOutputDev(splashModeCMYK8, 1, gFalse, + paperColor, gTrue, gFalse); +#endif + } else { + paperColor[0] = paperColor[1] = paperColor[2] = 0xff; + splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse, + paperColor, gTrue, gFalse); + } + splashOut->startDoc(xref); + page->displaySlice(splashOut, splashDPI, splashDPI, rotateA, + useMediaBox, crop, + sliceX, sliceY, sliceW, sliceH, + printing, catalog, abortCheckCbk, abortCheckCbkData); + + // start the PS page + page->makeBox(splashDPI, splashDPI, rotateA, useMediaBox, gFalse, + sliceX, sliceY, sliceW, sliceH, &box, &crop); + rotateA += page->getRotate(); + if (rotateA >= 360) { + rotateA -= 360; + } else if (rotateA < 0) { + rotateA += 360; + } + state = new GfxState(splashDPI, splashDPI, &box, rotateA, gFalse); + startPage(page->getNum(), state); + delete state; + switch (rotateA) { + case 0: + default: // this should never happen + m0 = box.x2 - box.x1; + m1 = 0; + m2 = 0; + m3 = box.y2 - box.y1; + m4 = box.x1; + m5 = box.y1; + break; + case 90: + m0 = 0; + m1 = box.y2 - box.y1; + m2 = -(box.x2 - box.x1); + m3 = 0; + m4 = box.x2; + m5 = box.y1; + break; + case 180: + m0 = -(box.x2 - box.x1); + m1 = 0; + m2 = 0; + m3 = -(box.y2 - box.y1); + m4 = box.x2; + m5 = box.y2; + break; + case 270: + m0 = 0; + m1 = -(box.y2 - box.y1); + m2 = box.x2 - box.x1; + m3 = 0; + m4 = box.x1; + m5 = box.y2; + break; + } + + //~ need to add the process colors + + // draw the rasterized image + bitmap = splashOut->getBitmap(); + w = bitmap->getWidth(); + h = bitmap->getHeight(); + writePS("gsave\n"); + writePSFmt("[{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g}] concat\n", + m0, m1, m2, m3, m4, m5); + switch (level) { + case psLevel1: + writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n", + w, h, w, -h, h); + p = bitmap->getDataPtr(); + i = 0; + for (y = 0; y < h; ++y) { + for (x = 0; x < w; ++x) { + writePSFmt("{0:02x}", *p++); + if (++i == 32) { + writePSChar('\n'); + i = 0; + } + } + } + if (i != 0) { + writePSChar('\n'); + } + break; + case psLevel1Sep: + writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n", + w, h, w, -h, h); + p = bitmap->getDataPtr(); + i = 0; + col[0] = col[1] = col[2] = col[3] = 0; + for (y = 0; y < h; ++y) { + for (comp = 0; comp < 4; ++comp) { + for (x = 0; x < w; ++x) { + writePSFmt("{0:02x}", p[4*x + comp]); + col[comp] |= p[4*x + comp]; + if (++i == 32) { + writePSChar('\n'); + i = 0; + } + } + } + p += bitmap->getRowSize(); + } + if (i != 0) { + writePSChar('\n'); + } + if (col[0]) { + processColors |= psProcessCyan; + } + if (col[1]) { + processColors |= psProcessMagenta; + } + if (col[2]) { + processColors |= psProcessYellow; + } + if (col[3]) { + processColors |= psProcessBlack; + } + break; + case psLevel2: + case psLevel2Sep: + case psLevel3: + case psLevel3Sep: + writePS("/DeviceRGB setcolorspace\n"); + writePS("<<\n /ImageType 1\n"); + writePSFmt(" /Width {0:d}\n", bitmap->getWidth()); + writePSFmt(" /Height {0:d}\n", bitmap->getHeight()); + writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", w, -h, h); + writePS(" /BitsPerComponent 8\n"); + writePS(" /Decode [0 1 0 1 0 1]\n"); + writePS(" /DataSource currentfile\n"); + if (globalParams->getPSASCIIHex()) { + writePS(" /ASCIIHexDecode filter\n"); + } else { + writePS(" /ASCII85Decode filter\n"); + } + writePS(" /RunLengthDecode filter\n"); + writePS(">>\n"); + writePS("image\n"); + obj.initNull(); + str0 = new MemStream((char *)bitmap->getDataPtr(), 0, w * h * 3, &obj); + str = new RunLengthEncoder(str0); + if (globalParams->getPSASCIIHex()) { + str = new ASCIIHexEncoder(str); + } else { + str = new ASCII85Encoder(str); + } + str->reset(); + while ((c = str->getChar()) != EOF) { + writePSChar(c); + } + str->close(); + delete str; + delete str0; + processColors |= psProcessCMYK; + break; + } + delete splashOut; + writePS("grestore\n"); + + // finish the PS page + endPage(); + + return gFalse; +#else + return gTrue; +#endif +} + +void PSOutputDev::startPage(int pageNum, GfxState *state) { + int x1, y1, x2, y2, width, height; + int imgWidth, imgHeight, imgWidth2, imgHeight2; + GBool landscape; + + + if (mode == psModePS) { + writePSFmt("%%Page: {0:d} {1:d}\n", pageNum, seqPage); + writePS("%%BeginPageSetup\n"); + } + + // underlays + if (underlayCbk) { + (*underlayCbk)(this, underlayCbkData); + } + if (overlayCbk) { + saveState(NULL); + } + + switch (mode) { + + case psModePS: + // rotate, translate, and scale page + imgWidth = imgURX - imgLLX; + imgHeight = imgURY - imgLLY; + x1 = (int)floor(state->getX1()); + y1 = (int)floor(state->getY1()); + x2 = (int)ceil(state->getX2()); + y2 = (int)ceil(state->getY2()); + width = x2 - x1; + height = y2 - y1; + tx = ty = 0; + // rotation and portrait/landscape mode + if (rotate0 >= 0) { + rotate = (360 - rotate0) % 360; + landscape = gFalse; + } else { + rotate = (360 - state->getRotate()) % 360; + if (rotate == 0 || rotate == 180) { + if (width > height && width > imgWidth) { + rotate += 90; + landscape = gTrue; + } else { + landscape = gFalse; + } + } else { // rotate == 90 || rotate == 270 + if (height > width && height > imgWidth) { + rotate = 270 - rotate; + landscape = gTrue; + } else { + landscape = gFalse; + } + } + } + writePSFmt("%%PageOrientation: {0:s}\n", + landscape ? "Landscape" : "Portrait"); + writePS("pdfStartPage\n"); + if (rotate == 0) { + imgWidth2 = imgWidth; + imgHeight2 = imgHeight; + } else if (rotate == 90) { + writePS("90 rotate\n"); + ty = -imgWidth; + imgWidth2 = imgHeight; + imgHeight2 = imgWidth; + } else if (rotate == 180) { + writePS("180 rotate\n"); + imgWidth2 = imgWidth; + imgHeight2 = imgHeight; + tx = -imgWidth; + ty = -imgHeight; + } else { // rotate == 270 + writePS("270 rotate\n"); + tx = -imgHeight; + imgWidth2 = imgHeight; + imgHeight2 = imgWidth; + } + // shrink or expand + if (xScale0 > 0 && yScale0 > 0) { + xScale = xScale0; + yScale = yScale0; + } else if ((globalParams->getPSShrinkLarger() && + (width > imgWidth2 || height > imgHeight2)) || + (globalParams->getPSExpandSmaller() && + (width < imgWidth2 && height < imgHeight2))) { + xScale = (double)imgWidth2 / (double)width; + yScale = (double)imgHeight2 / (double)height; + if (yScale < xScale) { + xScale = yScale; + } else { + yScale = xScale; + } + } else { + xScale = yScale = 1; + } + // deal with odd bounding boxes or clipping + if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { + tx -= xScale * clipLLX0; + ty -= yScale * clipLLY0; + } else { + tx -= xScale * x1; + ty -= yScale * y1; + } + // center + if (tx0 >= 0 && ty0 >= 0) { + tx += rotate == 0 ? tx0 : ty0; + ty += rotate == 0 ? ty0 : -tx0; + } else if (globalParams->getPSCenter()) { + if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { + tx += (imgWidth2 - xScale * (clipURX0 - clipLLX0)) / 2; + ty += (imgHeight2 - yScale * (clipURY0 - clipLLY0)) / 2; + } else { + tx += (imgWidth2 - xScale * width) / 2; + ty += (imgHeight2 - yScale * height) / 2; + } + } + tx += rotate == 0 ? imgLLX : imgLLY; + ty += rotate == 0 ? imgLLY : -imgLLX; + if (tx != 0 || ty != 0) { + writePSFmt("{0:.4g} {1:.4g} translate\n", tx, ty); + } + if (xScale != 1 || yScale != 1) { + writePSFmt("{0:.4f} {1:.4f} scale\n", xScale, yScale); + } + if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { + writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} re W\n", + clipLLX0, clipLLY0, clipURX0 - clipLLX0, clipURY0 - clipLLY0); + } else { + writePSFmt("{0:d} {1:d} {2:d} {3:d} re W\n", x1, y1, x2 - x1, y2 - y1); + } + + writePS("%%EndPageSetup\n"); + ++seqPage; + break; + + case psModeEPS: + writePS("pdfStartPage\n"); + tx = ty = 0; + rotate = (360 - state->getRotate()) % 360; + if (rotate == 0) { + } else if (rotate == 90) { + writePS("90 rotate\n"); + tx = -epsX1; + ty = -epsY2; + } else if (rotate == 180) { + writePS("180 rotate\n"); + tx = -(epsX1 + epsX2); + ty = -(epsY1 + epsY2); + } else { // rotate == 270 + writePS("270 rotate\n"); + tx = -epsX2; + ty = -epsY1; + } + if (tx != 0 || ty != 0) { + writePSFmt("{0:.4g} {1:.4g} translate\n", tx, ty); + } + xScale = yScale = 1; + break; + + case psModeForm: + writePS("/PaintProc {\n"); + writePS("begin xpdf begin\n"); + writePS("pdfStartPage\n"); + tx = ty = 0; + xScale = yScale = 1; + rotate = 0; + break; + } +} + +void PSOutputDev::endPage() { + if (overlayCbk) { + restoreState(NULL); + (*overlayCbk)(this, overlayCbkData); + } + + + if (mode == psModeForm) { + writePS("pdfEndPage\n"); + writePS("end end\n"); + writePS("} def\n"); + writePS("end end\n"); + } else { + if (!manualCtrl) { + writePS("showpage\n"); + } + writePS("%%PageTrailer\n"); + writePageTrailer(); + } +} + +void PSOutputDev::saveState(GfxState * /*state*/) { + writePS("q\n"); + ++numSaves; +} + +void PSOutputDev::restoreState(GfxState * /*state*/) { + writePS("Q\n"); + --numSaves; +} + +void PSOutputDev::updateCTM(GfxState * /*state*/, double m11, double m12, + double m21, double m22, double m31, double m32) { + writePSFmt("[{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g}] cm\n", + m11, m12, m21, m22, m31, m32); +} + +void PSOutputDev::updateLineDash(GfxState *state) { + double *dash; + double start; + int length, i; + + state->getLineDash(&dash, &length, &start); + writePS("["); + for (i = 0; i < length; ++i) { + writePSFmt("{0:.4g}{1:w}", + dash[i] < 0 ? 0 : dash[i], + (i == length-1) ? 0 : 1); + } + writePSFmt("] {0:.4g} d\n", start); +} + +void PSOutputDev::updateFlatness(GfxState *state) { + writePSFmt("{0:d} i\n", state->getFlatness()); +} + +void PSOutputDev::updateLineJoin(GfxState *state) { + writePSFmt("{0:d} j\n", state->getLineJoin()); +} + +void PSOutputDev::updateLineCap(GfxState *state) { + writePSFmt("{0:d} J\n", state->getLineCap()); +} + +void PSOutputDev::updateMiterLimit(GfxState *state) { + writePSFmt("{0:.4g} M\n", state->getMiterLimit()); +} + +void PSOutputDev::updateLineWidth(GfxState *state) { + writePSFmt("{0:.4g} w\n", state->getLineWidth()); +} + +void PSOutputDev::updateFillColorSpace(GfxState *state) { + switch (level) { + case psLevel1: + case psLevel1Sep: + break; + case psLevel2: + case psLevel3: + if (state->getFillColorSpace()->getMode() != csPattern) { + dumpColorSpaceL2(state->getFillColorSpace(), gTrue, gFalse, gFalse); + writePS(" cs\n"); + } + break; + case psLevel2Sep: + case psLevel3Sep: + break; + } +} + +void PSOutputDev::updateStrokeColorSpace(GfxState *state) { + switch (level) { + case psLevel1: + case psLevel1Sep: + break; + case psLevel2: + case psLevel3: + if (state->getStrokeColorSpace()->getMode() != csPattern) { + dumpColorSpaceL2(state->getStrokeColorSpace(), gTrue, gFalse, gFalse); + writePS(" CS\n"); + } + break; + case psLevel2Sep: + case psLevel3Sep: + break; + } +} + +void PSOutputDev::updateFillColor(GfxState *state) { + GfxColor color; + GfxColor *colorPtr; + GfxGray gray; + GfxCMYK cmyk; + GfxSeparationColorSpace *sepCS; + double c, m, y, k; + int i; + + switch (level) { + case psLevel1: + state->getFillGray(&gray); + writePSFmt("{0:.4g} g\n", colToDbl(gray)); + break; + case psLevel1Sep: + state->getFillCMYK(&cmyk); + c = colToDbl(cmyk.c); + m = colToDbl(cmyk.m); + y = colToDbl(cmyk.y); + k = colToDbl(cmyk.k); + writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} k\n", c, m, y, k); + addProcessColor(c, m, y, k); + break; + case psLevel2: + case psLevel3: + if (state->getFillColorSpace()->getMode() != csPattern) { + colorPtr = state->getFillColor(); + writePS("["); + for (i = 0; i < state->getFillColorSpace()->getNComps(); ++i) { + if (i > 0) { + writePS(" "); + } + writePSFmt("{0:.4g}", colToDbl(colorPtr->c[i])); + } + writePS("] sc\n"); + } + break; + case psLevel2Sep: + case psLevel3Sep: + if (state->getFillColorSpace()->getMode() == csSeparation) { + sepCS = (GfxSeparationColorSpace *)state->getFillColorSpace(); + color.c[0] = gfxColorComp1; + sepCS->getCMYK(&color, &cmyk); + writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} ({5:t}) ck\n", + colToDbl(state->getFillColor()->c[0]), + colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k), + sepCS->getName()); + addCustomColor(sepCS); + } else { + state->getFillCMYK(&cmyk); + c = colToDbl(cmyk.c); + m = colToDbl(cmyk.m); + y = colToDbl(cmyk.y); + k = colToDbl(cmyk.k); + writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} k\n", c, m, y, k); + addProcessColor(c, m, y, k); + } + break; + } + t3Cacheable = gFalse; +} + +void PSOutputDev::updateStrokeColor(GfxState *state) { + GfxColor color; + GfxColor *colorPtr; + GfxGray gray; + GfxCMYK cmyk; + GfxSeparationColorSpace *sepCS; + double c, m, y, k; + int i; + + switch (level) { + case psLevel1: + state->getStrokeGray(&gray); + writePSFmt("{0:.4g} G\n", colToDbl(gray)); + break; + case psLevel1Sep: + state->getStrokeCMYK(&cmyk); + c = colToDbl(cmyk.c); + m = colToDbl(cmyk.m); + y = colToDbl(cmyk.y); + k = colToDbl(cmyk.k); + writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} K\n", c, m, y, k); + addProcessColor(c, m, y, k); + break; + case psLevel2: + case psLevel3: + if (state->getStrokeColorSpace()->getMode() != csPattern) { + colorPtr = state->getStrokeColor(); + writePS("["); + for (i = 0; i < state->getStrokeColorSpace()->getNComps(); ++i) { + if (i > 0) { + writePS(" "); + } + writePSFmt("{0:.4g}", colToDbl(colorPtr->c[i])); + } + writePS("] SC\n"); + } + break; + case psLevel2Sep: + case psLevel3Sep: + if (state->getStrokeColorSpace()->getMode() == csSeparation) { + sepCS = (GfxSeparationColorSpace *)state->getStrokeColorSpace(); + color.c[0] = gfxColorComp1; + sepCS->getCMYK(&color, &cmyk); + writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} ({5:t}) CK\n", + colToDbl(state->getStrokeColor()->c[0]), + colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k), + sepCS->getName()); + addCustomColor(sepCS); + } else { + state->getStrokeCMYK(&cmyk); + c = colToDbl(cmyk.c); + m = colToDbl(cmyk.m); + y = colToDbl(cmyk.y); + k = colToDbl(cmyk.k); + writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} K\n", c, m, y, k); + addProcessColor(c, m, y, k); + } + break; + } + t3Cacheable = gFalse; +} + +void PSOutputDev::addProcessColor(double c, double m, double y, double k) { + if (c > 0) { + processColors |= psProcessCyan; + } + if (m > 0) { + processColors |= psProcessMagenta; + } + if (y > 0) { + processColors |= psProcessYellow; + } + if (k > 0) { + processColors |= psProcessBlack; + } +} + +void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) { + PSOutCustomColor *cc; + GfxColor color; + GfxCMYK cmyk; + + for (cc = customColors; cc; cc = cc->next) { + if (!cc->name->cmp(sepCS->getName())) { + return; + } + } + color.c[0] = gfxColorComp1; + sepCS->getCMYK(&color, &cmyk); + cc = new PSOutCustomColor(colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k), + sepCS->getName()->copy()); + cc->next = customColors; + customColors = cc; +} + +void PSOutputDev::updateFillOverprint(GfxState *state) { + if (level >= psLevel2) { + writePSFmt("{0:s} op\n", state->getFillOverprint() ? "true" : "false"); + } +} + +void PSOutputDev::updateStrokeOverprint(GfxState *state) { + if (level >= psLevel2) { + writePSFmt("{0:s} OP\n", state->getStrokeOverprint() ? "true" : "false"); + } +} + +void PSOutputDev::updateTransfer(GfxState *state) { + Function **funcs; + int i; + + funcs = state->getTransfer(); + if (funcs[0] && funcs[1] && funcs[2] && funcs[3]) { + if (level >= psLevel2) { + for (i = 0; i < 4; ++i) { + cvtFunction(funcs[i]); + } + writePS("setcolortransfer\n"); + } else { + cvtFunction(funcs[3]); + writePS("settransfer\n"); + } + } else if (funcs[0]) { + cvtFunction(funcs[0]); + writePS("settransfer\n"); + } else { + writePS("{} settransfer\n"); + } +} + +void PSOutputDev::updateFont(GfxState *state) { + if (state->getFont()) { + writePSFmt("/F{0:d}_{1:d} {2:.4g} Tf\n", + state->getFont()->getID()->num, state->getFont()->getID()->gen, + fabs(state->getFontSize()) < 0.00001 ? 0.00001 + : state->getFontSize()); + } +} + +void PSOutputDev::updateTextMat(GfxState *state) { + double *mat; + + mat = state->getTextMat(); + if (fabs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.00001) { + // avoid a singular (or close-to-singular) matrix + writePSFmt("[0.00001 0 0 0.00001 {0:.4g} {1:.4g}] Tm\n", mat[4], mat[5]); + } else { + writePSFmt("[{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g}] Tm\n", + mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); + } +} + +void PSOutputDev::updateCharSpace(GfxState *state) { + writePSFmt("{0:.4g} Tc\n", state->getCharSpace()); +} + +void PSOutputDev::updateRender(GfxState *state) { + int rm; + + rm = state->getRender(); + writePSFmt("{0:d} Tr\n", rm); + rm &= 3; + if (rm != 0 && rm != 3) { + t3Cacheable = gFalse; + } +} + +void PSOutputDev::updateRise(GfxState *state) { + writePSFmt("{0:.4g} Ts\n", state->getRise()); +} + +void PSOutputDev::updateWordSpace(GfxState *state) { + writePSFmt("{0:.4g} Tw\n", state->getWordSpace()); +} + +void PSOutputDev::updateHorizScaling(GfxState *state) { + double h; + + h = state->getHorizScaling(); + if (fabs(h) < 0.01) { + h = 0.01; + } + writePSFmt("{0:.4g} Tz\n", h); +} + +void PSOutputDev::updateTextPos(GfxState *state) { + writePSFmt("{0:.4g} {1:.4g} Td\n", state->getLineX(), state->getLineY()); +} + +void PSOutputDev::updateTextShift(GfxState *state, double shift) { + if (state->getFont()->getWMode()) { + writePSFmt("{0:.4g} TJmV\n", shift); + } else { + writePSFmt("{0:.4g} TJm\n", shift); + } +} + +void PSOutputDev::stroke(GfxState *state) { + doPath(state->getPath()); + if (t3String) { + // if we're construct a cacheable Type 3 glyph, we need to do + // everything in the fill color + writePS("Sf\n"); + } else { + writePS("S\n"); + } +} + +void PSOutputDev::fill(GfxState *state) { + doPath(state->getPath()); + writePS("f\n"); +} + +void PSOutputDev::eoFill(GfxState *state) { + doPath(state->getPath()); + writePS("f*\n"); +} + +void PSOutputDev::tilingPatternFill(GfxState * /*state*/, Object *str, + int paintType, Dict *resDict, + double *mat, double *bbox, + int x0, int y0, int x1, int y1, + double xStep, double yStep) { + PDFRectangle box; + Gfx *gfx; + + // define a Type 3 font + writePS("8 dict begin\n"); + writePS("/FontType 3 def\n"); + writePS("/FontMatrix [1 0 0 1 0 0] def\n"); + writePSFmt("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] def\n", + bbox[0], bbox[1], bbox[2], bbox[3]); + writePS("/Encoding 256 array def\n"); + writePS(" 0 1 255 { Encoding exch /.notdef put } for\n"); + writePS(" Encoding 120 /x put\n"); + writePS("/BuildGlyph {\n"); + writePS(" exch /CharProcs get exch\n"); + writePS(" 2 copy known not { pop /.notdef } if\n"); + writePS(" get exec\n"); + writePS("} bind def\n"); + writePS("/BuildChar {\n"); + writePS(" 1 index /Encoding get exch get\n"); + writePS(" 1 index /BuildGlyph get exec\n"); + writePS("} bind def\n"); + writePS("/CharProcs 1 dict def\n"); + writePS("CharProcs begin\n"); + box.x1 = bbox[0]; + box.y1 = bbox[1]; + box.x2 = bbox[2]; + box.y2 = bbox[3]; + gfx = new Gfx(xref, this, resDict, &box, NULL); + writePS("/x {\n"); + if (paintType == 2) { + writePSFmt("{0:.4g} 0 {1:.4g} {2:.4g} {3:.4g} {4:.4g} setcachedevice\n", + xStep, bbox[0], bbox[1], bbox[2], bbox[3]); + } else { + if (x1 - 1 <= x0) { + writePS("1 0 setcharwidth\n"); + } else { + writePSFmt("{0:.4g} 0 setcharwidth\n", xStep); + } + } + inType3Char = gTrue; + ++numTilingPatterns; + gfx->display(str); + --numTilingPatterns; + inType3Char = gFalse; + writePS("} def\n"); + delete gfx; + writePS("end\n"); + writePS("currentdict end\n"); + writePSFmt("/xpdfTile{0:d} exch definefont pop\n", numTilingPatterns); + + // draw the tiles + writePSFmt("/xpdfTile{0:d} findfont setfont\n", numTilingPatterns); + writePSFmt("gsave [{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g}] concat\n", + mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); + writePSFmt("{0:d} 1 {1:d} {{ {2:.4g} exch {3:.4g} mul m {4:d} 1 {5:d} {{ pop (x) show }} for }} for\n", + y0, y1 - 1, x0 * xStep, yStep, x0, x1 - 1); + writePS("grestore\n"); +} + +GBool PSOutputDev::functionShadedFill(GfxState * /*state*/, + GfxFunctionShading *shading) { + double x0, y0, x1, y1; + double *mat; + int i; + + if (level == psLevel2Sep || level == psLevel3Sep) { + if (shading->getColorSpace()->getMode() != csDeviceCMYK) { + return gFalse; + } + processColors |= psProcessCMYK; + } + + shading->getDomain(&x0, &y0, &x1, &y1); + mat = shading->getMatrix(); + writePSFmt("/mat [{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g}] def\n", + mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); + writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps()); + if (shading->getNFuncs() == 1) { + writePS("/func "); + cvtFunction(shading->getFunc(0)); + writePS("def\n"); + } else { + writePS("/func {\n"); + for (i = 0; i < shading->getNFuncs(); ++i) { + if (i < shading->getNFuncs() - 1) { + writePS("2 copy\n"); + } + cvtFunction(shading->getFunc(i)); + writePS("exec\n"); + if (i < shading->getNFuncs() - 1) { + writePS("3 1 roll\n"); + } + } + writePS("} def\n"); + } + writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} 0 funcSH\n", x0, y0, x1, y1); + + return gTrue; +} + +GBool PSOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading) { + double xMin, yMin, xMax, yMax; + double x0, y0, x1, y1, dx, dy, mul; + double tMin, tMax, t, t0, t1; + int i; + + if (level == psLevel2Sep || level == psLevel3Sep) { + if (shading->getColorSpace()->getMode() != csDeviceCMYK) { + return gFalse; + } + processColors |= psProcessCMYK; + } + + // get the clip region bbox + state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); + + // compute min and max t values, based on the four corners of the + // clip region bbox + shading->getCoords(&x0, &y0, &x1, &y1); + dx = x1 - x0; + dy = y1 - y0; + if (fabs(dx) < 0.01 && fabs(dy) < 0.01) { + return gTrue; + } else { + mul = 1 / (dx * dx + dy * dy); + tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul; + t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul; + if (t < tMin) { + tMin = t; + } else if (t > tMax) { + tMax = t; + } + t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul; + if (t < tMin) { + tMin = t; + } else if (t > tMax) { + tMax = t; + } + t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul; + if (t < tMin) { + tMin = t; + } else if (t > tMax) { + tMax = t; + } + if (tMin < 0 && !shading->getExtend0()) { + tMin = 0; + } + if (tMax > 1 && !shading->getExtend1()) { + tMax = 1; + } + } + + // get the function domain + t0 = shading->getDomain0(); + t1 = shading->getDomain1(); + + // generate the PS code + writePSFmt("/t0 {0:.4g} def\n", t0); + writePSFmt("/t1 {0:.4g} def\n", t1); + writePSFmt("/dt {0:.4g} def\n", t1 - t0); + writePSFmt("/x0 {0:.4g} def\n", x0); + writePSFmt("/y0 {0:.4g} def\n", y0); + writePSFmt("/dx {0:.4g} def\n", x1 - x0); + writePSFmt("/x1 {0:.4g} def\n", x1); + writePSFmt("/y1 {0:.4g} def\n", y1); + writePSFmt("/dy {0:.4g} def\n", y1 - y0); + writePSFmt("/xMin {0:.4g} def\n", xMin); + writePSFmt("/yMin {0:.4g} def\n", yMin); + writePSFmt("/xMax {0:.4g} def\n", xMax); + writePSFmt("/yMax {0:.4g} def\n", yMax); + writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps()); + if (shading->getNFuncs() == 1) { + writePS("/func "); + cvtFunction(shading->getFunc(0)); + writePS("def\n"); + } else { + writePS("/func {\n"); + for (i = 0; i < shading->getNFuncs(); ++i) { + if (i < shading->getNFuncs() - 1) { + writePS("dup\n"); + } + cvtFunction(shading->getFunc(i)); + writePS("exec\n"); + if (i < shading->getNFuncs() - 1) { + writePS("exch\n"); + } + } + writePS("} def\n"); + } + writePSFmt("{0:.4g} {1:.4g} 0 axialSH\n", tMin, tMax); + + return gTrue; +} + +GBool PSOutputDev::radialShadedFill(GfxState *state, + GfxRadialShading *shading) { + double xMin, yMin, xMax, yMax; + double x0, y0, r0, x1, y1, r1, t0, t1; + double xa, ya, ra; + double sz, xz, yz, sMin, sMax, sa, ta; + double theta, alpha, a1, a2; + GBool enclosed; + int i; + + if (level == psLevel2Sep || level == psLevel3Sep) { + if (shading->getColorSpace()->getMode() != csDeviceCMYK) { + return gFalse; + } + processColors |= psProcessCMYK; + } + + // get the shading info + shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1); + t0 = shading->getDomain0(); + t1 = shading->getDomain1(); + + // Compute the point at which r(s) = 0; check for the enclosed + // circles case; and compute the angles for the tangent lines. + if (r0 == r1) { + enclosed = x0 == x1 && y0 == y1; + theta = 0; + sz = 0; // make gcc happy + } else { + sz = -r0 / (r1 - r0); + xz = x0 + sz * (x1 - x0); + yz = y0 + sz * (y1 - y0); + enclosed = (xz - x0) * (xz - x0) + (yz - y0) * (yz - y0) <= r0 * r0; + theta = asin(r0 / sqrt((x0 - xz) * (x0 - xz) + (y0 - yz) * (y0 - yz))); + if (r0 > r1) { + theta = -theta; + } + } + if (enclosed) { + a1 = 0; + a2 = 360; + } else { + alpha = atan2(y1 - y0, x1 - x0); + a1 = (180 / M_PI) * (alpha + theta) + 90; + a2 = (180 / M_PI) * (alpha - theta) - 90; + while (a2 < a1) { + a2 += 360; + } + } + + // compute the (possibly extended) s range + state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); + if (enclosed) { + sMin = 0; + sMax = 1; + } else { + sMin = 1; + sMax = 0; + // solve for x(s) + r(s) = xMin + if ((x1 + r1) - (x0 + r0) != 0) { + sa = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0)); + if (sa < sMin) { + sMin = sa; + } else if (sa > sMax) { + sMax = sa; + } + } + // solve for x(s) - r(s) = xMax + if ((x1 - r1) - (x0 - r0) != 0) { + sa = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0)); + if (sa < sMin) { + sMin = sa; + } else if (sa > sMax) { + sMax = sa; + } + } + // solve for y(s) + r(s) = yMin + if ((y1 + r1) - (y0 + r0) != 0) { + sa = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0)); + if (sa < sMin) { + sMin = sa; + } else if (sa > sMax) { + sMax = sa; + } + } + // solve for y(s) - r(s) = yMax + if ((y1 - r1) - (y0 - r0) != 0) { + sa = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0)); + if (sa < sMin) { + sMin = sa; + } else if (sa > sMax) { + sMax = sa; + } + } + // check against sz + if (r0 < r1) { + if (sMin < sz) { + sMin = sz; + } + } else if (r0 > r1) { + if (sMax > sz) { + sMax = sz; + } + } + // check the 'extend' flags + if (!shading->getExtend0() && sMin < 0) { + sMin = 0; + } + if (!shading->getExtend1() && sMax > 1) { + sMax = 1; + } + } + + // generate the PS code + writePSFmt("/x0 {0:.4g} def\n", x0); + writePSFmt("/x1 {0:.4g} def\n", x1); + writePSFmt("/dx {0:.4g} def\n", x1 - x0); + writePSFmt("/y0 {0:.4g} def\n", y0); + writePSFmt("/y1 {0:.4g} def\n", y1); + writePSFmt("/dy {0:.4g} def\n", y1 - y0); + writePSFmt("/r0 {0:.4g} def\n", r0); + writePSFmt("/r1 {0:.4g} def\n", r1); + writePSFmt("/dr {0:.4g} def\n", r1 - r0); + writePSFmt("/t0 {0:.4g} def\n", t0); + writePSFmt("/t1 {0:.4g} def\n", t1); + writePSFmt("/dt {0:.4g} def\n", t1 - t0); + writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps()); + writePSFmt("/encl {0:s} def\n", enclosed ? "true" : "false"); + writePSFmt("/a1 {0:.4g} def\n", a1); + writePSFmt("/a2 {0:.4g} def\n", a2); + if (shading->getNFuncs() == 1) { + writePS("/func "); + cvtFunction(shading->getFunc(0)); + writePS("def\n"); + } else { + writePS("/func {\n"); + for (i = 0; i < shading->getNFuncs(); ++i) { + if (i < shading->getNFuncs() - 1) { + writePS("dup\n"); + } + cvtFunction(shading->getFunc(i)); + writePS("exec\n"); + if (i < shading->getNFuncs() - 1) { + writePS("exch\n"); + } + } + writePS("} def\n"); + } + writePSFmt("{0:.4g} {1:.4g} 0 radialSH\n", sMin, sMax); + + // extend the 'enclosed' case + if (enclosed) { + // extend the smaller circle + if ((shading->getExtend0() && r0 <= r1) || + (shading->getExtend1() && r1 < r0)) { + if (r0 <= r1) { + ta = t0; + ra = r0; + xa = x0; + ya = y0; + } else { + ta = t1; + ra = r1; + xa = x1; + ya = y1; + } + if (level == psLevel2Sep || level == psLevel3Sep) { + writePSFmt("{0:.4g} radialCol aload pop k\n", ta); + } else { + writePSFmt("{0:.4g} radialCol sc\n", ta); + } + writePSFmt("{0:.4g} {1:.4g} {2:.4g} 0 360 arc h f*\n", xa, ya, ra); + } + + // extend the larger circle + if ((shading->getExtend0() && r0 > r1) || + (shading->getExtend1() && r1 >= r0)) { + if (r0 > r1) { + ta = t0; + ra = r0; + xa = x0; + ya = y0; + } else { + ta = t1; + ra = r1; + xa = x1; + ya = y1; + } + if (level == psLevel2Sep || level == psLevel3Sep) { + writePSFmt("{0:.4g} radialCol aload pop k\n", ta); + } else { + writePSFmt("{0:.4g} radialCol sc\n", ta); + } + writePSFmt("{0:.4g} {1:.4g} {2:.4g} 0 360 arc h\n", xa, ya, ra); + writePSFmt("{0:.4g} {1:.4g} m {2:.4g} {3:.4g} l {4:.4g} {5:.4g} l {6:.4g} {7:.4g} l h f*\n", + xMin, yMin, xMin, yMax, xMax, yMax, xMax, yMin); + } + } + + return gTrue; +} + +void PSOutputDev::clip(GfxState *state) { + doPath(state->getPath()); + writePS("W\n"); +} + +void PSOutputDev::eoClip(GfxState *state) { + doPath(state->getPath()); + writePS("W*\n"); +} + +void PSOutputDev::clipToStrokePath(GfxState *state) { + doPath(state->getPath()); + writePS("Ws\n"); +} + +void PSOutputDev::doPath(GfxPath *path) { + GfxSubpath *subpath; + double x0, y0, x1, y1, x2, y2, x3, y3, x4, y4; + int n, m, i, j; + + n = path->getNumSubpaths(); + + if (n == 1 && path->getSubpath(0)->getNumPoints() == 5) { + subpath = path->getSubpath(0); + x0 = subpath->getX(0); + y0 = subpath->getY(0); + x4 = subpath->getX(4); + y4 = subpath->getY(4); + if (x4 == x0 && y4 == y0) { + x1 = subpath->getX(1); + y1 = subpath->getY(1); + x2 = subpath->getX(2); + y2 = subpath->getY(2); + x3 = subpath->getX(3); + y3 = subpath->getY(3); + if (x0 == x1 && x2 == x3 && y0 == y3 && y1 == y2) { + writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} re\n", + x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1, + fabs(x2 - x0), fabs(y1 - y0)); + return; + } else if (x0 == x3 && x1 == x2 && y0 == y1 && y2 == y3) { + writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} re\n", + x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2, + fabs(x1 - x0), fabs(y2 - y0)); + return; + } + } + } + + for (i = 0; i < n; ++i) { + subpath = path->getSubpath(i); + m = subpath->getNumPoints(); + writePSFmt("{0:.4g} {1:.4g} m\n", subpath->getX(0), subpath->getY(0)); + j = 1; + while (j < m) { + if (subpath->getCurve(j)) { + writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g} c\n", + subpath->getX(j), subpath->getY(j), + subpath->getX(j+1), subpath->getY(j+1), + subpath->getX(j+2), subpath->getY(j+2)); + j += 3; + } else { + writePSFmt("{0:.4g} {1:.4g} l\n", subpath->getX(j), subpath->getY(j)); + ++j; + } + } + if (subpath->isClosed()) { + writePS("h\n"); + } + } +} + +void PSOutputDev::drawString(GfxState *state, GString *s) { + GfxFont *font; + int wMode; + Gushort *codeToGID; + GString *s2; + double dx, dy, dx2, dy2, originX, originY; + char *p; + UnicodeMap *uMap; + CharCode code; + Unicode u[8]; + char buf[8]; + int len, nChars, uLen, n, m, i, j; + + // check for invisible text -- this is used by Acrobat Capture + if (state->getRender() == 3) { + return; + } + + // ignore empty strings + if (s->getLength() == 0) { + return; + } + + // get the font + if (!(font = state->getFont())) { + return; + } + wMode = font->getWMode(); + + // check for a subtitute 16-bit font + uMap = NULL; + codeToGID = NULL; + if (font->isCIDFont()) { + for (i = 0; i < font16EncLen; ++i) { + if (font->getID()->num == font16Enc[i].fontID.num && + font->getID()->gen == font16Enc[i].fontID.gen) { + uMap = globalParams->getUnicodeMap(font16Enc[i].enc); + break; + } + } + + // check for a code-to-GID map + } else { + for (i = 0; i < font8InfoLen; ++i) { + if (font->getID()->num == font8Info[i].fontID.num && + font->getID()->gen == font8Info[i].fontID.gen) { + codeToGID = font8Info[i].codeToGID; + break; + } + } + } + + // compute width of chars in string, ignoring char spacing and word + // spacing -- the Tj operator will adjust for the metrics of the + // font that's actually used + dx = dy = 0; + nChars = 0; + p = s->getCString(); + len = s->getLength(); + s2 = new GString(); + while (len > 0) { + n = font->getNextChar(p, len, &code, + u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, + &dx2, &dy2, &originX, &originY); + if (font->isCIDFont()) { + if (uMap) { + for (i = 0; i < uLen; ++i) { + m = uMap->mapUnicode(u[i], buf, (int)sizeof(buf)); + for (j = 0; j < m; ++j) { + s2->append(buf[j]); + } + } + //~ this really needs to get the number of chars in the target + //~ encoding - which may be more than the number of Unicode + //~ chars + nChars += uLen; + } else { + s2->append((char)((code >> 8) & 0xff)); + s2->append((char)(code & 0xff)); + ++nChars; + } + } else { + if (!codeToGID || codeToGID[code]) { + s2->append((char)code); + } + } + dx += dx2; + dy += dy2; + p += n; + len -= n; + } + dx *= state->getFontSize() * state->getHorizScaling(); + dy *= state->getFontSize(); + if (uMap) { + uMap->decRefCnt(); + } + + if (s2->getLength() > 0) { + writePSString(s2); + if (font->isCIDFont()) { + if (wMode) { + writePSFmt(" {0:d} {1:.4g} Tj16V\n", nChars, dy); + } else { + writePSFmt(" {0:d} {1:.4g} Tj16\n", nChars, dx); + } + } else { + writePSFmt(" {0:.4g} Tj\n", dx); + } + } + delete s2; + + if (state->getRender() & 4) { + haveTextClip = gTrue; + } +} + +void PSOutputDev::endTextObject(GfxState * /*state*/) { + if (haveTextClip) { + writePS("Tclip\n"); + haveTextClip = gFalse; + } +} + +void PSOutputDev::drawImageMask(GfxState * /*state*/, Object *ref, Stream *str, + int width, int height, GBool invert, + GBool inlineImg) { + int len; + + len = height * ((width + 7) / 8); + switch (level) { + case psLevel1: + case psLevel1Sep: + doImageL1(ref, NULL, invert, inlineImg, str, width, height, len); + break; + case psLevel2: + case psLevel2Sep: + doImageL2(ref, NULL, invert, inlineImg, str, width, height, len, + NULL, NULL, 0, 0, gFalse); + break; + case psLevel3: + case psLevel3Sep: + doImageL3(ref, NULL, invert, inlineImg, str, width, height, len, + NULL, NULL, 0, 0, gFalse); + break; + } +} + +void PSOutputDev::drawImage(GfxState * /*state*/, Object *ref, Stream *str, + int width, int height, GfxImageColorMap *colorMap, + int *maskColors, GBool inlineImg) { + int len; + + len = height * ((width * colorMap->getNumPixelComps() * + colorMap->getBits() + 7) / 8); + switch (level) { + case psLevel1: + doImageL1(ref, colorMap, gFalse, inlineImg, str, width, height, len); + break; + case psLevel1Sep: + //~ handle indexed, separation, ... color spaces + doImageL1Sep(colorMap, gFalse, inlineImg, str, width, height, len); + break; + case psLevel2: + case psLevel2Sep: + doImageL2(ref, colorMap, gFalse, inlineImg, str, + width, height, len, maskColors, NULL, 0, 0, gFalse); + break; + case psLevel3: + case psLevel3Sep: + doImageL3(ref, colorMap, gFalse, inlineImg, str, + width, height, len, maskColors, NULL, 0, 0, gFalse); + break; + } + t3Cacheable = gFalse; +} + +void PSOutputDev::drawMaskedImage(GfxState * /*state*/, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GBool maskInvert) { + int len; + + len = height * ((width * colorMap->getNumPixelComps() * + colorMap->getBits() + 7) / 8); + switch (level) { + case psLevel1: + doImageL1(ref, colorMap, gFalse, gFalse, str, width, height, len); + break; + case psLevel1Sep: + //~ handle indexed, separation, ... color spaces + doImageL1Sep(colorMap, gFalse, gFalse, str, width, height, len); + break; + case psLevel2: + case psLevel2Sep: + doImageL2(ref, colorMap, gFalse, gFalse, str, width, height, len, + NULL, maskStr, maskWidth, maskHeight, maskInvert); + break; + case psLevel3: + case psLevel3Sep: + doImageL3(ref, colorMap, gFalse, gFalse, str, width, height, len, + NULL, maskStr, maskWidth, maskHeight, maskInvert); + break; + } + t3Cacheable = gFalse; +} + +void PSOutputDev::doImageL1(Object *ref, GfxImageColorMap *colorMap, + GBool invert, GBool inlineImg, + Stream *str, int width, int height, int len) { + ImageStream *imgStr; + Guchar pixBuf[gfxColorMaxComps]; + GfxGray gray; + int col, x, y, c, i; + + if ((inType3Char || preload) && !colorMap) { + if (inlineImg) { + // create an array + str = new FixedLengthEncoder(str, len); + str = new ASCIIHexEncoder(str); + str->reset(); + col = 0; + writePS("[<"); + do { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == '>' || c == EOF) { + break; + } + writePSChar(c); + ++col; + // each line is: "<...data...>" + // so max data length = 255 - 4 = 251 + // but make it 240 just to be safe + // chunks are 2 bytes each, so we need to stop on an even col number + if (col == 240) { + writePS(">\n<"); + col = 0; + } + } while (c != '>' && c != EOF); + writePS(">]\n"); + writePS("0\n"); + str->close(); + delete str; + } else { + // set up to use the array already created by setupImages() + writePSFmt("ImData_{0:d}_{1:d} 0\n", ref->getRefNum(), ref->getRefGen()); + } + } + + // image/imagemask command + if ((inType3Char || preload) && !colorMap) { + writePSFmt("{0:d} {1:d} {2:s} [{3:d} 0 0 {4:d} 0 {5:d}] pdfImM1a\n", + width, height, invert ? "true" : "false", + width, -height, height); + } else if (colorMap) { + writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n", + width, height, + width, -height, height); + } else { + writePSFmt("{0:d} {1:d} {2:s} [{3:d} 0 0 {4:d} 0 {5:d}] pdfImM1\n", + width, height, invert ? "true" : "false", + width, -height, height); + } + + // image data + if (!((inType3Char || preload) && !colorMap)) { + + if (colorMap) { + + // set up to process the data stream + imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), + colorMap->getBits()); + imgStr->reset(); + + // process the data stream + i = 0; + for (y = 0; y < height; ++y) { + + // write the line + for (x = 0; x < width; ++x) { + imgStr->getPixel(pixBuf); + colorMap->getGray(pixBuf, &gray); + writePSFmt("{0:02x}", colToByte(gray)); + if (++i == 32) { + writePSChar('\n'); + i = 0; + } + } + } + if (i != 0) { + writePSChar('\n'); + } + str->close(); + delete imgStr; + + // imagemask + } else { + str->reset(); + i = 0; + for (y = 0; y < height; ++y) { + for (x = 0; x < width; x += 8) { + writePSFmt("{0:02x}", str->getChar() & 0xff); + if (++i == 32) { + writePSChar('\n'); + i = 0; + } + } + } + if (i != 0) { + writePSChar('\n'); + } + str->close(); + } + } +} + +void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap, + GBool /*invert*/, GBool /*inlineImg*/, + Stream *str, int width, int height, int /*len*/) { + ImageStream *imgStr; + Guchar *lineBuf; + Guchar pixBuf[gfxColorMaxComps]; + GfxCMYK cmyk; + int x, y, i, comp; + + // width, height, matrix, bits per component + writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n", + width, height, + width, -height, height); + + // allocate a line buffer + lineBuf = (Guchar *)gmalloc(4 * width); + + // set up to process the data stream + imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), + colorMap->getBits()); + imgStr->reset(); + + // process the data stream + i = 0; + for (y = 0; y < height; ++y) { + + // read the line + for (x = 0; x < width; ++x) { + imgStr->getPixel(pixBuf); + colorMap->getCMYK(pixBuf, &cmyk); + lineBuf[4*x+0] = colToByte(cmyk.c); + lineBuf[4*x+1] = colToByte(cmyk.m); + lineBuf[4*x+2] = colToByte(cmyk.y); + lineBuf[4*x+3] = colToByte(cmyk.k); + addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k)); + } + + // write one line of each color component + for (comp = 0; comp < 4; ++comp) { + for (x = 0; x < width; ++x) { + writePSFmt("{0:02x}", lineBuf[4*x + comp]); + if (++i == 32) { + writePSChar('\n'); + i = 0; + } + } + } + } + + if (i != 0) { + writePSChar('\n'); + } + + str->close(); + delete imgStr; + gfree(lineBuf); +} + +void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, + GBool invert, GBool inlineImg, + Stream *str, int width, int height, int len, + int *maskColors, Stream *maskStr, + int maskWidth, int maskHeight, GBool maskInvert) { + Stream *str2; + ImageStream *imgStr; + Guchar *line; + PSOutImgClipRect *rects0, *rects1, *rectsTmp, *rectsOut; + int rects0Len, rects1Len, rectsSize, rectsOutLen, rectsOutSize; + GBool emitRect, addRect, extendRect; + GString *s; + int n, numComps; + GBool useRLE, useASCII, useASCIIHex, useCompressed; + GfxSeparationColorSpace *sepCS; + GfxColor color; + GfxCMYK cmyk; + int c; + int col, i, j, x0, x1, y, maskXor; + + // color key masking + if (maskColors && colorMap && !inlineImg) { + // can't read the stream twice for inline images -- but masking + // isn't allowed with inline images anyway + numComps = colorMap->getNumPixelComps(); + imgStr = new ImageStream(str, width, numComps, colorMap->getBits()); + imgStr->reset(); + rects0Len = rects1Len = rectsOutLen = 0; + rectsSize = rectsOutSize = 64; + rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect)); + rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect)); + rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize, + sizeof(PSOutImgClipRect)); + for (y = 0; y < height; ++y) { + if (!(line = imgStr->getLine())) { + break; + } + i = 0; + rects1Len = 0; + for (x0 = 0; x0 < width; ++x0) { + for (j = 0; j < numComps; ++j) { + if (line[x0*numComps+j] < maskColors[2*j] || + line[x0*numComps+j] > maskColors[2*j+1]) { + break; + } + } + if (j < numComps) { + break; + } + } + for (x1 = x0; x1 < width; ++x1) { + for (j = 0; j < numComps; ++j) { + if (line[x1*numComps+j] < maskColors[2*j] || + line[x1*numComps+j] > maskColors[2*j+1]) { + break; + } + } + if (j == numComps) { + break; + } + } + while (x0 < width || i < rects0Len) { + emitRect = addRect = extendRect = gFalse; + if (x0 >= width) { + emitRect = gTrue; + } else if (i >= rects0Len) { + addRect = gTrue; + } else if (rects0[i].x0 < x0) { + emitRect = gTrue; + } else if (x0 < rects0[i].x0) { + addRect = gTrue; + } else if (rects0[i].x1 == x1) { + extendRect = gTrue; + } else { + emitRect = addRect = gTrue; + } + if (emitRect) { + if (rectsOutLen == rectsOutSize) { + rectsOutSize *= 2; + rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, + sizeof(PSOutImgClipRect)); + } + rectsOut[rectsOutLen].x0 = rects0[i].x0; + rectsOut[rectsOutLen].x1 = rects0[i].x1; + rectsOut[rectsOutLen].y0 = height - y - 1; + rectsOut[rectsOutLen].y1 = height - rects0[i].y0 - 1; + ++rectsOutLen; + ++i; + } + if (addRect || extendRect) { + if (rects1Len == rectsSize) { + rectsSize *= 2; + rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize, + sizeof(PSOutImgClipRect)); + rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize, + sizeof(PSOutImgClipRect)); + } + rects1[rects1Len].x0 = x0; + rects1[rects1Len].x1 = x1; + if (addRect) { + rects1[rects1Len].y0 = y; + } + if (extendRect) { + rects1[rects1Len].y0 = rects0[i].y0; + ++i; + } + ++rects1Len; + for (x0 = x1; x0 < width; ++x0) { + for (j = 0; j < numComps; ++j) { + if (line[x0*numComps+j] < maskColors[2*j] || + line[x0*numComps+j] > maskColors[2*j+1]) { + break; + } + } + if (j < numComps) { + break; + } + } + for (x1 = x0; x1 < width; ++x1) { + for (j = 0; j < numComps; ++j) { + if (line[x1*numComps+j] < maskColors[2*j] || + line[x1*numComps+j] > maskColors[2*j+1]) { + break; + } + } + if (j == numComps) { + break; + } + } + } + } + rectsTmp = rects0; + rects0 = rects1; + rects1 = rectsTmp; + i = rects0Len; + rects0Len = rects1Len; + rects1Len = i; + } + for (i = 0; i < rects0Len; ++i) { + if (rectsOutLen == rectsOutSize) { + rectsOutSize *= 2; + rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, + sizeof(PSOutImgClipRect)); + } + rectsOut[rectsOutLen].x0 = rects0[i].x0; + rectsOut[rectsOutLen].x1 = rects0[i].x1; + rectsOut[rectsOutLen].y0 = height - y - 1; + rectsOut[rectsOutLen].y1 = height - rects0[i].y0 - 1; + ++rectsOutLen; + } + writePSFmt("{0:d} array 0\n", rectsOutLen * 4); + for (i = 0; i < rectsOutLen; ++i) { + writePSFmt("[{0:d} {1:d} {2:d} {3:d}] pr\n", + rectsOut[i].x0, rectsOut[i].y0, + rectsOut[i].x1 - rectsOut[i].x0, + rectsOut[i].y1 - rectsOut[i].y0); + } + writePSFmt("pop {0:d} {1:d} pdfImClip\n", width, height); + gfree(rectsOut); + gfree(rects0); + gfree(rects1); + delete imgStr; + str->close(); + + // explicit masking + } else if (maskStr) { + imgStr = new ImageStream(maskStr, maskWidth, 1, 1); + imgStr->reset(); + rects0Len = rects1Len = rectsOutLen = 0; + rectsSize = rectsOutSize = 64; + rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect)); + rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect)); + rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize, + sizeof(PSOutImgClipRect)); + maskXor = maskInvert ? 1 : 0; + for (y = 0; y < maskHeight; ++y) { + if (!(line = imgStr->getLine())) { + break; + } + i = 0; + rects1Len = 0; + for (x0 = 0; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ; + for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ; + while (x0 < maskWidth || i < rects0Len) { + emitRect = addRect = extendRect = gFalse; + if (x0 >= maskWidth) { + emitRect = gTrue; + } else if (i >= rects0Len) { + addRect = gTrue; + } else if (rects0[i].x0 < x0) { + emitRect = gTrue; + } else if (x0 < rects0[i].x0) { + addRect = gTrue; + } else if (rects0[i].x1 == x1) { + extendRect = gTrue; + } else { + emitRect = addRect = gTrue; + } + if (emitRect) { + if (rectsOutLen == rectsOutSize) { + rectsOutSize *= 2; + rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, + sizeof(PSOutImgClipRect)); + } + rectsOut[rectsOutLen].x0 = rects0[i].x0; + rectsOut[rectsOutLen].x1 = rects0[i].x1; + rectsOut[rectsOutLen].y0 = maskHeight - y - 1; + rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1; + ++rectsOutLen; + ++i; + } + if (addRect || extendRect) { + if (rects1Len == rectsSize) { + rectsSize *= 2; + rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize, + sizeof(PSOutImgClipRect)); + rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize, + sizeof(PSOutImgClipRect)); + } + rects1[rects1Len].x0 = x0; + rects1[rects1Len].x1 = x1; + if (addRect) { + rects1[rects1Len].y0 = y; + } + if (extendRect) { + rects1[rects1Len].y0 = rects0[i].y0; + ++i; + } + ++rects1Len; + for (x0 = x1; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ; + for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ; + } + } + rectsTmp = rects0; + rects0 = rects1; + rects1 = rectsTmp; + i = rects0Len; + rects0Len = rects1Len; + rects1Len = i; + } + for (i = 0; i < rects0Len; ++i) { + if (rectsOutLen == rectsOutSize) { + rectsOutSize *= 2; + rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, + sizeof(PSOutImgClipRect)); + } + rectsOut[rectsOutLen].x0 = rects0[i].x0; + rectsOut[rectsOutLen].x1 = rects0[i].x1; + rectsOut[rectsOutLen].y0 = maskHeight - y - 1; + rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1; + ++rectsOutLen; + } + writePSFmt("{0:d} array 0\n", rectsOutLen * 4); + for (i = 0; i < rectsOutLen; ++i) { + writePSFmt("[{0:d} {1:d} {2:d} {3:d}] pr\n", + rectsOut[i].x0, rectsOut[i].y0, + rectsOut[i].x1 - rectsOut[i].x0, + rectsOut[i].y1 - rectsOut[i].y0); + } + writePSFmt("pop {0:d} {1:d} pdfImClip\n", maskWidth, maskHeight); + gfree(rectsOut); + gfree(rects0); + gfree(rects1); + delete imgStr; + maskStr->close(); + } + + // color space + if (colorMap) { + dumpColorSpaceL2(colorMap->getColorSpace(), gFalse, gTrue, gFalse); + writePS(" setcolorspace\n"); + } + + useASCIIHex = globalParams->getPSASCIIHex(); + + // set up the image data + if (mode == psModeForm || inType3Char || preload) { + if (inlineImg) { + // create an array + str2 = new FixedLengthEncoder(str, len); + str2 = new RunLengthEncoder(str2); + if (useASCIIHex) { + str2 = new ASCIIHexEncoder(str2); + } else { + str2 = new ASCII85Encoder(str2); + } + str2->reset(); + col = 0; + writePS((char *)(useASCIIHex ? "[<" : "[<~")); + do { + do { + c = str2->getChar(); + } while (c == '\n' || c == '\r'); + if (c == (useASCIIHex ? '>' : '~') || c == EOF) { + break; + } + if (c == 'z') { + writePSChar(c); + ++col; + } else { + writePSChar(c); + ++col; + for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) { + do { + c = str2->getChar(); + } while (c == '\n' || c == '\r'); + if (c == (useASCIIHex ? '>' : '~') || c == EOF) { + break; + } + writePSChar(c); + ++col; + } + } + // each line is: "<~...data...~>" + // so max data length = 255 - 6 = 249 + // chunks are 1 or 5 bytes each, so we have to stop at 245 + // but make it 240 just to be safe + if (col > 240) { + writePS((char *)(useASCIIHex ? ">\n<" : "~>\n<~")); + col = 0; + } + } while (c != (useASCIIHex ? '>' : '~') && c != EOF); + writePS((char *)(useASCIIHex ? ">\n" : "~>\n")); + // add an extra entry because the RunLengthDecode filter may + // read past the end + writePS("<>]\n"); + writePS("0\n"); + str2->close(); + delete str2; + } else { + // set up to use the array already created by setupImages() + writePSFmt("ImData_{0:d}_{1:d} 0\n", ref->getRefNum(), ref->getRefGen()); + } + } + + // image dictionary + writePS("<<\n /ImageType 1\n"); + + // width, height, matrix, bits per component + writePSFmt(" /Width {0:d}\n", width); + writePSFmt(" /Height {0:d}\n", height); + writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", + width, -height, height); + if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) { + writePS(" /BitsPerComponent 8\n"); + } else { + writePSFmt(" /BitsPerComponent {0:d}\n", + colorMap ? colorMap->getBits() : 1); + } + + // decode + if (colorMap) { + writePS(" /Decode ["); + if ((level == psLevel2Sep || level == psLevel3Sep) && + colorMap->getColorSpace()->getMode() == csSeparation) { + // this matches up with the code in the pdfImSep operator + n = (1 << colorMap->getBits()) - 1; + writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(0) * n, + colorMap->getDecodeHigh(0) * n); + } else if (colorMap->getColorSpace()->getMode() == csDeviceN) { + numComps = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())-> + getAlt()->getNComps(); + for (i = 0; i < numComps; ++i) { + if (i > 0) { + writePS(" "); + } + writePS("0 1"); + } + } else { + numComps = colorMap->getNumPixelComps(); + for (i = 0; i < numComps; ++i) { + if (i > 0) { + writePS(" "); + } + writePSFmt("{0:.4g} {1:.4g}", + colorMap->getDecodeLow(i), colorMap->getDecodeHigh(i)); + } + } + writePS("]\n"); + } else { + writePSFmt(" /Decode [{0:d} {1:d}]\n", invert ? 1 : 0, invert ? 0 : 1); + } + + // data source + if (mode == psModeForm || inType3Char || preload) { + writePS(" /DataSource { 2 copy get exch 1 add exch }\n"); + } else { + writePS(" /DataSource currentfile\n"); + } + + // filters + s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3, + " "); + if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) || + inlineImg || !s) { + useRLE = gTrue; + useASCII = !(mode == psModeForm || inType3Char || preload); + useCompressed = gFalse; + } else { + useRLE = gFalse; + useASCII = str->isBinary() && + !(mode == psModeForm || inType3Char || preload); + useCompressed = gTrue; + } + if (useASCII) { + writePSFmt(" /ASCII{0:s}Decode filter\n", + useASCIIHex ? "Hex" : "85"); + } + if (useRLE) { + writePS(" /RunLengthDecode filter\n"); + } + if (useCompressed) { + writePS(s->getCString()); + } + if (s) { + delete s; + } + + if (mode == psModeForm || inType3Char || preload) { + + // end of image dictionary + writePSFmt(">>\n{0:s}\n", colorMap ? "image" : "imagemask"); + + // get rid of the array and index + writePS("pop pop\n"); + + } else { + + // cut off inline image streams at appropriate length + if (inlineImg) { + str = new FixedLengthEncoder(str, len); + } else if (useCompressed) { + str = str->getUndecodedStream(); + } + + // recode DeviceN data + if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) { + str = new DeviceNRecoder(str, width, height, colorMap); + } + + // add RunLengthEncode and ASCIIHex/85 encode filters + if (useRLE) { + str = new RunLengthEncoder(str); + } + if (useASCII) { + if (useASCIIHex) { + str = new ASCIIHexEncoder(str); + } else { + str = new ASCII85Encoder(str); + } + } + + // end of image dictionary + writePS(">>\n"); +#if OPI_SUPPORT + if (opi13Nest) { + if (inlineImg) { + // this can't happen -- OPI dictionaries are in XObjects + error(-1, "Internal: OPI in inline image"); + n = 0; + } else { + // need to read the stream to count characters -- the length + // is data-dependent (because of ASCII and RLE filters) + str->reset(); + n = 0; + while ((c = str->getChar()) != EOF) { + ++n; + } + str->close(); + } + // +6/7 for "pdfIm\n" / "pdfImM\n" + // +8 for newline + trailer + n += colorMap ? 14 : 15; + writePSFmt("%%BeginData: {0:d} Hex Bytes\n", n); + } +#endif + if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap && + colorMap->getColorSpace()->getMode() == csSeparation) { + color.c[0] = gfxColorComp1; + sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace(); + sepCS->getCMYK(&color, &cmyk); + writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t}) pdfImSep\n", + colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k), + sepCS->getName()); + } else { + writePSFmt("{0:s}\n", colorMap ? "pdfIm" : "pdfImM"); + } + + // copy the stream data + str->reset(); + while ((c = str->getChar()) != EOF) { + writePSChar(c); + } + str->close(); + + // add newline and trailer to the end + writePSChar('\n'); + writePS("%-EOD-\n"); +#if OPI_SUPPORT + if (opi13Nest) { + writePS("%%EndData\n"); + } +#endif + + // delete encoders + if (useRLE || useASCII || inlineImg) { + delete str; + } + } + + if ((maskColors && colorMap && !inlineImg) || maskStr) { + writePS("pdfImClipEnd\n"); + } +} + +//~ this doesn't currently support OPI +void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap, + GBool invert, GBool inlineImg, + Stream *str, int width, int height, int len, + int *maskColors, Stream *maskStr, + int maskWidth, int maskHeight, GBool maskInvert) { + Stream *str2; + GString *s; + int n, numComps; + GBool useRLE, useASCII, useASCIIHex, useCompressed; + GBool maskUseRLE, maskUseASCII, maskUseCompressed; + GfxSeparationColorSpace *sepCS; + GfxColor color; + GfxCMYK cmyk; + int c; + int col, i; + + useASCIIHex = globalParams->getPSASCIIHex(); + useRLE = useASCII = useCompressed = gFalse; // make gcc happy + maskUseRLE = maskUseASCII = maskUseCompressed = gFalse; // make gcc happy + + // color space + if (colorMap) { + dumpColorSpaceL2(colorMap->getColorSpace(), gFalse, gTrue, gFalse); + writePS(" setcolorspace\n"); + } + + // set up the image data + if (mode == psModeForm || inType3Char || preload) { + if (inlineImg) { + // create an array + str2 = new FixedLengthEncoder(str, len); + str2 = new RunLengthEncoder(str2); + if (useASCIIHex) { + str2 = new ASCIIHexEncoder(str2); + } else { + str2 = new ASCII85Encoder(str2); + } + str2->reset(); + col = 0; + writePS((char *)(useASCIIHex ? "[<" : "[<~")); + do { + do { + c = str2->getChar(); + } while (c == '\n' || c == '\r'); + if (c == (useASCIIHex ? '>' : '~') || c == EOF) { + break; + } + if (c == 'z') { + writePSChar(c); + ++col; + } else { + writePSChar(c); + ++col; + for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) { + do { + c = str2->getChar(); + } while (c == '\n' || c == '\r'); + if (c == (useASCIIHex ? '>' : '~') || c == EOF) { + break; + } + writePSChar(c); + ++col; + } + } + // each line is: "<~...data...~>" + // so max data length = 255 - 6 = 249 + // chunks are 1 or 5 bytes each, so we have to stop at 245 + // but make it 240 just to be safe + if (col > 240) { + writePS((char *)(useASCIIHex ? ">\n<" : "~>\n<~")); + col = 0; + } + } while (c != (useASCIIHex ? '>' : '~') && c != EOF); + writePS((char *)(useASCIIHex ? ">\n" : "~>\n")); + // add an extra entry because the RunLengthDecode filter may + // read past the end + writePS("<>]\n"); + writePS("0\n"); + str2->close(); + delete str2; + } else { + // set up to use the array already created by setupImages() + writePSFmt("ImData_{0:d}_{1:d} 0\n", ref->getRefNum(), ref->getRefGen()); + } + } + + // explicit masking + if (maskStr) { + writePS("<<\n /ImageType 3\n"); + writePS(" /InterleaveType 3\n"); + writePS(" /DataDict\n"); + } + + // image (data) dictionary + writePSFmt("<<\n /ImageType {0:d}\n", (maskColors && colorMap) ? 4 : 1); + + // color key masking + if (maskColors && colorMap) { + writePS(" /MaskColor [\n"); + numComps = colorMap->getNumPixelComps(); + for (i = 0; i < 2 * numComps; i += 2) { + writePSFmt(" {0:d} {1:d}\n", maskColors[i], maskColors[i+1]); + } + writePS(" ]\n"); + } + + // width, height, matrix, bits per component + writePSFmt(" /Width {0:d}\n", width); + writePSFmt(" /Height {0:d}\n", height); + writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", + width, -height, height); + if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) { + writePS(" /BitsPerComponent 8\n"); + } else { + writePSFmt(" /BitsPerComponent {0:d}\n", + colorMap ? colorMap->getBits() : 1); + } + + // decode + if (colorMap) { + writePS(" /Decode ["); + if ((level == psLevel2Sep || level == psLevel3Sep) && + colorMap->getColorSpace()->getMode() == csSeparation) { + // this matches up with the code in the pdfImSep operator + n = (1 << colorMap->getBits()) - 1; + writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(0) * n, + colorMap->getDecodeHigh(0) * n); + } else if (colorMap->getColorSpace()->getMode() == csDeviceN) { + numComps = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())-> + getAlt()->getNComps(); + for (i = 0; i < numComps; ++i) { + if (i > 0) { + writePS(" "); + } + writePS("0 1"); + } + } else { + numComps = colorMap->getNumPixelComps(); + for (i = 0; i < numComps; ++i) { + if (i > 0) { + writePS(" "); + } + writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(i), + colorMap->getDecodeHigh(i)); + } + } + writePS("]\n"); + } else { + writePSFmt(" /Decode [{0:d} {1:d}]\n", invert ? 1 : 0, invert ? 0 : 1); + } + + // data source + if (mode == psModeForm || inType3Char || preload) { + writePS(" /DataSource { 2 copy get exch 1 add exch }\n"); + } else { + writePS(" /DataSource currentfile\n"); + } + + // filters + s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3, + " "); + if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) || + inlineImg || !s) { + useRLE = gTrue; + useASCII = !(mode == psModeForm || inType3Char || preload); + useCompressed = gFalse; + } else { + useRLE = gFalse; + useASCII = str->isBinary() && + !(mode == psModeForm || inType3Char || preload); + useCompressed = gTrue; + } + if (useASCII) { + writePSFmt(" /ASCII{0:s}Decode filter\n", + useASCIIHex ? "Hex" : "85"); + } + if (useRLE) { + writePS(" /RunLengthDecode filter\n"); + } + if (useCompressed) { + writePS(s->getCString()); + } + if (s) { + delete s; + } + + // end of image (data) dictionary + writePS(">>\n"); + + // explicit masking + if (maskStr) { + writePS(" /MaskDict\n"); + writePS("<<\n"); + writePS(" /ImageType 1\n"); + writePSFmt(" /Width {0:d}\n", maskWidth); + writePSFmt(" /Height {0:d}\n", maskHeight); + writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", + maskWidth, -maskHeight, maskHeight); + writePS(" /BitsPerComponent 1\n"); + writePSFmt(" /Decode [{0:d} {1:d}]\n", + maskInvert ? 1 : 0, maskInvert ? 0 : 1); + + // mask data source + writePS(" /DataSource currentfile\n"); + s = maskStr->getPSFilter(3, " "); + if (!s) { + maskUseRLE = gTrue; + maskUseASCII = gTrue; + maskUseCompressed = gFalse; + } else { + maskUseRLE = gFalse; + maskUseASCII = maskStr->isBinary(); + maskUseCompressed = gTrue; + } + if (maskUseASCII) { + writePSFmt(" /ASCII{0:s}Decode filter\n", + useASCIIHex ? "Hex" : "85"); + } + if (maskUseRLE) { + writePS(" /RunLengthDecode filter\n"); + } + if (maskUseCompressed) { + writePS(s->getCString()); + } + if (s) { + delete s; + } + + writePS(">>\n"); + writePS(">>\n"); + } + + if (mode == psModeForm || inType3Char || preload) { + + // image command + writePSFmt("{0:s}\n", colorMap ? "image" : "imagemask"); + + } else { + + if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap && + colorMap->getColorSpace()->getMode() == csSeparation) { + color.c[0] = gfxColorComp1; + sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace(); + sepCS->getCMYK(&color, &cmyk); + writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t}) pdfImSep\n", + colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k), + sepCS->getName()); + } else { + writePSFmt("{0:s}\n", colorMap ? "pdfIm" : "pdfImM"); + } + + } + + // explicit masking + if (maskStr) { + + if (maskUseCompressed) { + maskStr = maskStr->getUndecodedStream(); + } + + // add RunLengthEncode and ASCIIHex/85 encode filters + if (maskUseRLE) { + maskStr = new RunLengthEncoder(maskStr); + } + if (maskUseASCII) { + if (useASCIIHex) { + maskStr = new ASCIIHexEncoder(maskStr); + } else { + maskStr = new ASCII85Encoder(maskStr); + } + } + + // copy the stream data + maskStr->reset(); + while ((c = maskStr->getChar()) != EOF) { + writePSChar(c); + } + maskStr->close(); + writePSChar('\n'); + + // delete encoders + if (maskUseRLE || maskUseASCII) { + delete maskStr; + } + } + + // get rid of the array and index + if (mode == psModeForm || inType3Char || preload) { + writePS("pop pop\n"); + + // image data + } else { + + // cut off inline image streams at appropriate length + if (inlineImg) { + str = new FixedLengthEncoder(str, len); + } else if (useCompressed) { + str = str->getUndecodedStream(); + } + + // recode DeviceN data + if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) { + str = new DeviceNRecoder(str, width, height, colorMap); + } + + // add RunLengthEncode and ASCIIHex/85 encode filters + if (useRLE) { + str = new RunLengthEncoder(str); + } + if (useASCII) { + if (useASCIIHex) { + str = new ASCIIHexEncoder(str); + } else { + str = new ASCII85Encoder(str); + } + } + + // copy the stream data + str->reset(); + while ((c = str->getChar()) != EOF) { + writePSChar(c); + } + str->close(); + + // add newline and trailer to the end + writePSChar('\n'); + writePS("%-EOD-\n"); + + // delete encoders + if (useRLE || useASCII || inlineImg) { + delete str; + } + } +} + +void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace, + GBool genXform, GBool updateColors, + GBool map01) { + GfxCalGrayColorSpace *calGrayCS; + GfxCalRGBColorSpace *calRGBCS; + GfxLabColorSpace *labCS; + GfxIndexedColorSpace *indexedCS; + GfxSeparationColorSpace *separationCS; + GfxDeviceNColorSpace *deviceNCS; + GfxColorSpace *baseCS; + Guchar *lookup, *p; + double x[gfxColorMaxComps], y[gfxColorMaxComps]; + double low[gfxColorMaxComps], range[gfxColorMaxComps]; + GfxColor color; + GfxCMYK cmyk; + Function *func; + int n, numComps, numAltComps; + int byte; + int i, j, k; + + switch (colorSpace->getMode()) { + + case csDeviceGray: + writePS("/DeviceGray"); + if (genXform) { + writePS(" {}"); + } + if (updateColors) { + processColors |= psProcessBlack; + } + break; + + case csCalGray: + calGrayCS = (GfxCalGrayColorSpace *)colorSpace; + writePS("[/CIEBasedA <<\n"); + writePSFmt(" /DecodeA {{{0:.4g} exp}} bind\n", calGrayCS->getGamma()); + writePSFmt(" /MatrixA [{0:.4g} {1:.4g} {2:.4g}]\n", + calGrayCS->getWhiteX(), calGrayCS->getWhiteY(), + calGrayCS->getWhiteZ()); + writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n", + calGrayCS->getWhiteX(), calGrayCS->getWhiteY(), + calGrayCS->getWhiteZ()); + writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n", + calGrayCS->getBlackX(), calGrayCS->getBlackY(), + calGrayCS->getBlackZ()); + writePS(">>]"); + if (genXform) { + writePS(" {}"); + } + if (updateColors) { + processColors |= psProcessBlack; + } + break; + + case csDeviceRGB: + writePS("/DeviceRGB"); + if (genXform) { + writePS(" {}"); + } + if (updateColors) { + processColors |= psProcessCMYK; + } + break; + + case csCalRGB: + calRGBCS = (GfxCalRGBColorSpace *)colorSpace; + writePS("[/CIEBasedABC <<\n"); + writePSFmt(" /DecodeABC [{{{0:.4g} exp}} bind {{{1:.4g} exp}} bind {{{2:.4g} exp}} bind]\n", + calRGBCS->getGammaR(), calRGBCS->getGammaG(), + calRGBCS->getGammaB()); + writePSFmt(" /MatrixABC [{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g} {6:.4g} {7:.4g} {8:.4g}]\n", + calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1], + calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3], + calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5], + calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7], + calRGBCS->getMatrix()[8]); + writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n", + calRGBCS->getWhiteX(), calRGBCS->getWhiteY(), + calRGBCS->getWhiteZ()); + writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n", + calRGBCS->getBlackX(), calRGBCS->getBlackY(), + calRGBCS->getBlackZ()); + writePS(">>]"); + if (genXform) { + writePS(" {}"); + } + if (updateColors) { + processColors |= psProcessCMYK; + } + break; + + case csDeviceCMYK: + writePS("/DeviceCMYK"); + if (genXform) { + writePS(" {}"); + } + if (updateColors) { + processColors |= psProcessCMYK; + } + break; + + case csLab: + labCS = (GfxLabColorSpace *)colorSpace; + writePS("[/CIEBasedABC <<\n"); + if (map01) { + writePS(" /RangeABC [0 1 0 1 0 1]\n"); + writePSFmt(" /DecodeABC [{{100 mul 16 add 116 div}} bind {{{0:.4g} mul {1:.4g} add}} bind {{{2:.4g} mul {3:.4g} add}} bind]\n", + (labCS->getAMax() - labCS->getAMin()) / 500.0, + labCS->getAMin() / 500.0, + (labCS->getBMax() - labCS->getBMin()) / 200.0, + labCS->getBMin() / 200.0); + } else { + writePSFmt(" /RangeABC [0 100 {0:.4g} {1:.4g} {2:.4g} {3:.4g}]\n", + labCS->getAMin(), labCS->getAMax(), + labCS->getBMin(), labCS->getBMax()); + writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n"); + } + writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n"); + writePS(" /DecodeLMN\n"); + writePS(" [{dup 6 29 div ge {dup dup mul mul}\n"); + writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind\n", + labCS->getWhiteX()); + writePS(" {dup 6 29 div ge {dup dup mul mul}\n"); + writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind\n", + labCS->getWhiteY()); + writePS(" {dup 6 29 div ge {dup dup mul mul}\n"); + writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind]\n", + labCS->getWhiteZ()); + writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n", + labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ()); + writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n", + labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ()); + writePS(">>]"); + if (genXform) { + writePS(" {}"); + } + if (updateColors) { + processColors |= psProcessCMYK; + } + break; + + case csICCBased: + // there is no transform function to the alternate color space, so + // we can use it directly + dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt(), + genXform, updateColors, gFalse); + break; + + case csIndexed: + indexedCS = (GfxIndexedColorSpace *)colorSpace; + baseCS = indexedCS->getBase(); + writePS("[/Indexed "); + dumpColorSpaceL2(baseCS, gFalse, gFalse, gTrue); + n = indexedCS->getIndexHigh(); + numComps = baseCS->getNComps(); + lookup = indexedCS->getLookup(); + writePSFmt(" {0:d} <\n", n); + if (baseCS->getMode() == csDeviceN) { + func = ((GfxDeviceNColorSpace *)baseCS)->getTintTransformFunc(); + baseCS->getDefaultRanges(low, range, indexedCS->getIndexHigh()); + if (((GfxDeviceNColorSpace *)baseCS)->getAlt()->getMode() == csLab) { + labCS = (GfxLabColorSpace *)((GfxDeviceNColorSpace *)baseCS)->getAlt(); + } else { + labCS = NULL; + } + numAltComps = ((GfxDeviceNColorSpace *)baseCS)->getAlt()->getNComps(); + p = lookup; + for (i = 0; i <= n; i += 8) { + writePS(" "); + for (j = i; j < i+8 && j <= n; ++j) { + for (k = 0; k < numComps; ++k) { + x[k] = low[k] + (*p++ / 255.0) * range[k]; + } + func->transform(x, y); + if (labCS) { + y[0] /= 100.0; + y[1] = (y[1] - labCS->getAMin()) / + (labCS->getAMax() - labCS->getAMin()); + y[2] = (y[2] - labCS->getBMin()) / + (labCS->getBMax() - labCS->getBMin()); + } + for (k = 0; k < numAltComps; ++k) { + byte = (int)(y[k] * 255 + 0.5); + if (byte < 0) { + byte = 0; + } else if (byte > 255) { + byte = 255; + } + writePSFmt("{0:02x}", byte); + } + if (updateColors) { + color.c[0] = dblToCol(j); + indexedCS->getCMYK(&color, &cmyk); + addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k)); + } + } + writePS("\n"); + } + } else { + for (i = 0; i <= n; i += 8) { + writePS(" "); + for (j = i; j < i+8 && j <= n; ++j) { + for (k = 0; k < numComps; ++k) { + writePSFmt("{0:02x}", lookup[j * numComps + k]); + } + if (updateColors) { + color.c[0] = dblToCol(j); + indexedCS->getCMYK(&color, &cmyk); + addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k)); + } + } + writePS("\n"); + } + } + writePS(">]"); + if (genXform) { + writePS(" {}"); + } + break; + + case csSeparation: + separationCS = (GfxSeparationColorSpace *)colorSpace; + writePS("[/Separation "); + writePSString(separationCS->getName()); + writePS(" "); + dumpColorSpaceL2(separationCS->getAlt(), gFalse, gFalse, gFalse); + writePS("\n"); + cvtFunction(separationCS->getFunc()); + writePS("]"); + if (genXform) { + writePS(" {}"); + } + if (updateColors) { + addCustomColor(separationCS); + } + break; + + case csDeviceN: + // DeviceN color spaces are a Level 3 PostScript feature. + deviceNCS = (GfxDeviceNColorSpace *)colorSpace; + dumpColorSpaceL2(deviceNCS->getAlt(), gFalse, updateColors, map01); + if (genXform) { + writePS(" "); + cvtFunction(deviceNCS->getTintTransformFunc()); + } + break; + + case csPattern: + //~ unimplemented + break; + } +} + +#if OPI_SUPPORT +void PSOutputDev::opiBegin(GfxState *state, Dict *opiDict) { + Object dict; + + if (globalParams->getPSOPI()) { + opiDict->lookup("2.0", &dict); + if (dict.isDict()) { + opiBegin20(state, dict.getDict()); + dict.free(); + } else { + dict.free(); + opiDict->lookup("1.3", &dict); + if (dict.isDict()) { + opiBegin13(state, dict.getDict()); + } + dict.free(); + } + } +} + +void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) { + Object obj1, obj2, obj3, obj4; + double width, height, left, right, top, bottom; + int w, h; + int i; + + writePS("%%BeginOPI: 2.0\n"); + writePS("%%Distilled\n"); + + dict->lookup("F", &obj1); + if (getFileSpec(&obj1, &obj2)) { + writePSFmt("%%ImageFileName: {0:t}\n", obj2.getString()); + obj2.free(); + } + obj1.free(); + + dict->lookup("MainImage", &obj1); + if (obj1.isString()) { + writePSFmt("%%MainImage: {0:t}\n", obj1.getString()); + } + obj1.free(); + + //~ ignoring 'Tags' entry + //~ need to use writePSString() and deal with >255-char lines + + dict->lookup("Size", &obj1); + if (obj1.isArray() && obj1.arrayGetLength() == 2) { + obj1.arrayGet(0, &obj2); + width = obj2.getNum(); + obj2.free(); + obj1.arrayGet(1, &obj2); + height = obj2.getNum(); + obj2.free(); + writePSFmt("%%ImageDimensions: {0:.4g} {1:.4g}\n", width, height); + } + obj1.free(); + + dict->lookup("CropRect", &obj1); + if (obj1.isArray() && obj1.arrayGetLength() == 4) { + obj1.arrayGet(0, &obj2); + left = obj2.getNum(); + obj2.free(); + obj1.arrayGet(1, &obj2); + top = obj2.getNum(); + obj2.free(); + obj1.arrayGet(2, &obj2); + right = obj2.getNum(); + obj2.free(); + obj1.arrayGet(3, &obj2); + bottom = obj2.getNum(); + obj2.free(); + writePSFmt("%%ImageCropRect: {0:.4g} {1:.4g} {2:.4g} {3:.4g}\n", + left, top, right, bottom); + } + obj1.free(); + + dict->lookup("Overprint", &obj1); + if (obj1.isBool()) { + writePSFmt("%%ImageOverprint: {0:s}\n", obj1.getBool() ? "true" : "false"); + } + obj1.free(); + + dict->lookup("Inks", &obj1); + if (obj1.isName()) { + writePSFmt("%%ImageInks: {0:s}\n", obj1.getName()); + } else if (obj1.isArray() && obj1.arrayGetLength() >= 1) { + obj1.arrayGet(0, &obj2); + if (obj2.isName()) { + writePSFmt("%%ImageInks: {0:s} {1:d}", + obj2.getName(), (obj1.arrayGetLength() - 1) / 2); + for (i = 1; i+1 < obj1.arrayGetLength(); i += 2) { + obj1.arrayGet(i, &obj3); + obj1.arrayGet(i+1, &obj4); + if (obj3.isString() && obj4.isNum()) { + writePS(" "); + writePSString(obj3.getString()); + writePSFmt(" {0:.4g}", obj4.getNum()); + } + obj3.free(); + obj4.free(); + } + writePS("\n"); + } + obj2.free(); + } + obj1.free(); + + writePS("gsave\n"); + + writePS("%%BeginIncludedImage\n"); + + dict->lookup("IncludedImageDimensions", &obj1); + if (obj1.isArray() && obj1.arrayGetLength() == 2) { + obj1.arrayGet(0, &obj2); + w = obj2.getInt(); + obj2.free(); + obj1.arrayGet(1, &obj2); + h = obj2.getInt(); + obj2.free(); + writePSFmt("%%IncludedImageDimensions: {0:d} {1:d}\n", w, h); + } + obj1.free(); + + dict->lookup("IncludedImageQuality", &obj1); + if (obj1.isNum()) { + writePSFmt("%%IncludedImageQuality: {0:.4g}\n", obj1.getNum()); + } + obj1.free(); + + ++opi20Nest; +} + +void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) { + Object obj1, obj2; + int left, right, top, bottom, samples, bits, width, height; + double c, m, y, k; + double llx, lly, ulx, uly, urx, ury, lrx, lry; + double tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry; + double horiz, vert; + int i, j; + + writePS("save\n"); + writePS("/opiMatrix2 matrix currentmatrix def\n"); + writePS("opiMatrix setmatrix\n"); + + dict->lookup("F", &obj1); + if (getFileSpec(&obj1, &obj2)) { + writePSFmt("%ALDImageFileName: {0:t}\n", obj2.getString()); + obj2.free(); + } + obj1.free(); + + dict->lookup("CropRect", &obj1); + if (obj1.isArray() && obj1.arrayGetLength() == 4) { + obj1.arrayGet(0, &obj2); + left = obj2.getInt(); + obj2.free(); + obj1.arrayGet(1, &obj2); + top = obj2.getInt(); + obj2.free(); + obj1.arrayGet(2, &obj2); + right = obj2.getInt(); + obj2.free(); + obj1.arrayGet(3, &obj2); + bottom = obj2.getInt(); + obj2.free(); + writePSFmt("%ALDImageCropRect: {0:d} {1:d} {2:d} {3:d}\n", + left, top, right, bottom); + } + obj1.free(); + + dict->lookup("Color", &obj1); + if (obj1.isArray() && obj1.arrayGetLength() == 5) { + obj1.arrayGet(0, &obj2); + c = obj2.getNum(); + obj2.free(); + obj1.arrayGet(1, &obj2); + m = obj2.getNum(); + obj2.free(); + obj1.arrayGet(2, &obj2); + y = obj2.getNum(); + obj2.free(); + obj1.arrayGet(3, &obj2); + k = obj2.getNum(); + obj2.free(); + obj1.arrayGet(4, &obj2); + if (obj2.isString()) { + writePSFmt("%ALDImageColor: {0:.4g} {1:.4g} {2:.4g} {3:.4g} ", + c, m, y, k); + writePSString(obj2.getString()); + writePS("\n"); + } + obj2.free(); + } + obj1.free(); + + dict->lookup("ColorType", &obj1); + if (obj1.isName()) { + writePSFmt("%ALDImageColorType: {0:s}\n", obj1.getName()); + } + obj1.free(); + + //~ ignores 'Comments' entry + //~ need to handle multiple lines + + dict->lookup("CropFixed", &obj1); + if (obj1.isArray()) { + obj1.arrayGet(0, &obj2); + ulx = obj2.getNum(); + obj2.free(); + obj1.arrayGet(1, &obj2); + uly = obj2.getNum(); + obj2.free(); + obj1.arrayGet(2, &obj2); + lrx = obj2.getNum(); + obj2.free(); + obj1.arrayGet(3, &obj2); + lry = obj2.getNum(); + obj2.free(); + writePSFmt("%ALDImageCropFixed: {0:.4g} {1:.4g} {2:.4g} {3:.4g}\n", + ulx, uly, lrx, lry); + } + obj1.free(); + + dict->lookup("GrayMap", &obj1); + if (obj1.isArray()) { + writePS("%ALDImageGrayMap:"); + for (i = 0; i < obj1.arrayGetLength(); i += 16) { + if (i > 0) { + writePS("\n%%+"); + } + for (j = 0; j < 16 && i+j < obj1.arrayGetLength(); ++j) { + obj1.arrayGet(i+j, &obj2); + writePSFmt(" {0:d}", obj2.getInt()); + obj2.free(); + } + } + writePS("\n"); + } + obj1.free(); + + dict->lookup("ID", &obj1); + if (obj1.isString()) { + writePSFmt("%ALDImageID: {0:t}\n", obj1.getString()); + } + obj1.free(); + + dict->lookup("ImageType", &obj1); + if (obj1.isArray() && obj1.arrayGetLength() == 2) { + obj1.arrayGet(0, &obj2); + samples = obj2.getInt(); + obj2.free(); + obj1.arrayGet(1, &obj2); + bits = obj2.getInt(); + obj2.free(); + writePSFmt("%ALDImageType: {0:d} {1:d}\n", samples, bits); + } + obj1.free(); + + dict->lookup("Overprint", &obj1); + if (obj1.isBool()) { + writePSFmt("%ALDImageOverprint: {0:s}\n", + obj1.getBool() ? "true" : "false"); + } + obj1.free(); + + dict->lookup("Position", &obj1); + if (obj1.isArray() && obj1.arrayGetLength() == 8) { + obj1.arrayGet(0, &obj2); + llx = obj2.getNum(); + obj2.free(); + obj1.arrayGet(1, &obj2); + lly = obj2.getNum(); + obj2.free(); + obj1.arrayGet(2, &obj2); + ulx = obj2.getNum(); + obj2.free(); + obj1.arrayGet(3, &obj2); + uly = obj2.getNum(); + obj2.free(); + obj1.arrayGet(4, &obj2); + urx = obj2.getNum(); + obj2.free(); + obj1.arrayGet(5, &obj2); + ury = obj2.getNum(); + obj2.free(); + obj1.arrayGet(6, &obj2); + lrx = obj2.getNum(); + obj2.free(); + obj1.arrayGet(7, &obj2); + lry = obj2.getNum(); + obj2.free(); + opiTransform(state, llx, lly, &tllx, &tlly); + opiTransform(state, ulx, uly, &tulx, &tuly); + opiTransform(state, urx, ury, &turx, &tury); + opiTransform(state, lrx, lry, &tlrx, &tlry); + writePSFmt("%ALDImagePosition: {0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g} {6:.4g} {7:.4g}\n", + tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry); + obj2.free(); + } + obj1.free(); + + dict->lookup("Resolution", &obj1); + if (obj1.isArray() && obj1.arrayGetLength() == 2) { + obj1.arrayGet(0, &obj2); + horiz = obj2.getNum(); + obj2.free(); + obj1.arrayGet(1, &obj2); + vert = obj2.getNum(); + obj2.free(); + writePSFmt("%ALDImageResoution: {0:.4g} {1:.4g}\n", horiz, vert); + obj2.free(); + } + obj1.free(); + + dict->lookup("Size", &obj1); + if (obj1.isArray() && obj1.arrayGetLength() == 2) { + obj1.arrayGet(0, &obj2); + width = obj2.getInt(); + obj2.free(); + obj1.arrayGet(1, &obj2); + height = obj2.getInt(); + obj2.free(); + writePSFmt("%ALDImageDimensions: {0:d} {1:d}\n", width, height); + } + obj1.free(); + + //~ ignoring 'Tags' entry + //~ need to use writePSString() and deal with >255-char lines + + dict->lookup("Tint", &obj1); + if (obj1.isNum()) { + writePSFmt("%ALDImageTint: {0:.4g}\n", obj1.getNum()); + } + obj1.free(); + + dict->lookup("Transparency", &obj1); + if (obj1.isBool()) { + writePSFmt("%ALDImageTransparency: {0:s}\n", + obj1.getBool() ? "true" : "false"); + } + obj1.free(); + + writePS("%%BeginObject: image\n"); + writePS("opiMatrix2 setmatrix\n"); + ++opi13Nest; +} + +// Convert PDF user space coordinates to PostScript default user space +// coordinates. This has to account for both the PDF CTM and the +// PSOutputDev page-fitting transform. +void PSOutputDev::opiTransform(GfxState *state, double x0, double y0, + double *x1, double *y1) { + double t; + + state->transform(x0, y0, x1, y1); + *x1 += tx; + *y1 += ty; + if (rotate == 90) { + t = *x1; + *x1 = -*y1; + *y1 = t; + } else if (rotate == 180) { + *x1 = -*x1; + *y1 = -*y1; + } else if (rotate == 270) { + t = *x1; + *x1 = *y1; + *y1 = -t; + } + *x1 *= xScale; + *y1 *= yScale; +} + +void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) { + Object dict; + + if (globalParams->getPSOPI()) { + opiDict->lookup("2.0", &dict); + if (dict.isDict()) { + writePS("%%EndIncludedImage\n"); + writePS("%%EndOPI\n"); + writePS("grestore\n"); + --opi20Nest; + dict.free(); + } else { + dict.free(); + opiDict->lookup("1.3", &dict); + if (dict.isDict()) { + writePS("%%EndObject\n"); + writePS("restore\n"); + --opi13Nest; + } + dict.free(); + } + } +} + +GBool PSOutputDev::getFileSpec(Object *fileSpec, Object *fileName) { + if (fileSpec->isString()) { + fileSpec->copy(fileName); + return gTrue; + } + if (fileSpec->isDict()) { + fileSpec->dictLookup("DOS", fileName); + if (fileName->isString()) { + return gTrue; + } + fileName->free(); + fileSpec->dictLookup("Mac", fileName); + if (fileName->isString()) { + return gTrue; + } + fileName->free(); + fileSpec->dictLookup("Unix", fileName); + if (fileName->isString()) { + return gTrue; + } + fileName->free(); + fileSpec->dictLookup("F", fileName); + if (fileName->isString()) { + return gTrue; + } + fileName->free(); + } + return gFalse; +} +#endif // OPI_SUPPORT + +void PSOutputDev::type3D0(GfxState * /*state*/, double wx, double wy) { + writePSFmt("{0:.4g} {1:.4g} setcharwidth\n", wx, wy); + writePS("q\n"); + t3NeedsRestore = gTrue; +} + +void PSOutputDev::type3D1(GfxState * /*state*/, double wx, double wy, + double llx, double lly, double urx, double ury) { + t3WX = wx; + t3WY = wy; + t3LLX = llx; + t3LLY = lly; + t3URX = urx; + t3URY = ury; + t3String = new GString(); + writePS("q\n"); + t3Cacheable = gTrue; + t3NeedsRestore = gTrue; +} + +void PSOutputDev::drawForm(Ref id) { + writePSFmt("f_{0:d}_{1:d}\n", id.num, id.gen); +} + +void PSOutputDev::psXObject(Stream *psStream, Stream *level1Stream) { + Stream *str; + int c; + + if ((level == psLevel1 || level == psLevel1Sep) && level1Stream) { + str = level1Stream; + } else { + str = psStream; + } + str->reset(); + while ((c = str->getChar()) != EOF) { + writePSChar(c); + } + str->close(); +} + +//~ can nextFunc be reset to 0 -- maybe at the start of each page? +//~ or maybe at the start of each color space / pattern? +void PSOutputDev::cvtFunction(Function *func) { + SampledFunction *func0; + ExponentialFunction *func2; + StitchingFunction *func3; + PostScriptFunction *func4; + int thisFunc, m, n, nSamples, i, j, k; + + switch (func->getType()) { + + case -1: // identity + writePS("{}\n"); + break; + + case 0: // sampled + func0 = (SampledFunction *)func; + thisFunc = nextFunc++; + m = func0->getInputSize(); + n = func0->getOutputSize(); + nSamples = n; + for (i = 0; i < m; ++i) { + nSamples *= func0->getSampleSize(i); + } + writePSFmt("/xpdfSamples{0:d} [\n", thisFunc); + for (i = 0; i < nSamples; ++i) { + writePSFmt("{0:.4g}\n", func0->getSamples()[i]); + } + writePS("] def\n"); + writePSFmt("{{ {0:d} array {1:d} array {2:d} 2 roll\n", 2*m, m, m+2); + // [e01] [efrac] x0 x1 ... xm-1 + for (i = m-1; i >= 0; --i) { + // [e01] [efrac] x0 x1 ... xi + writePSFmt("{0:.4g} sub {1:.4g} mul {2:.4g} add\n", + func0->getDomainMin(i), + (func0->getEncodeMax(i) - func0->getEncodeMin(i)) / + (func0->getDomainMax(i) - func0->getDomainMin(i)), + func0->getEncodeMin(i)); + // [e01] [efrac] x0 x1 ... xi-1 xi' + writePSFmt("dup 0 lt {{ pop 0 }} {{ dup {0:d} gt {{ pop {1:d} }} if }} ifelse\n", + func0->getSampleSize(i) - 1, func0->getSampleSize(i) - 1); + // [e01] [efrac] x0 x1 ... xi-1 xi' + writePS("dup floor cvi exch dup ceiling cvi exch 2 index sub\n"); + // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi') xi'-floor(xi') + writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+3, i); + // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi') + writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+3, 2*i+1); + // [e01] [efrac] x0 x1 ... xi-1 floor(xi') + writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+2, 2*i); + // [e01] [efrac] x0 x1 ... xi-1 + } + // [e01] [efrac] + for (i = 0; i < n; ++i) { + // [e01] [efrac] y(0) ... y(i-1) + for (j = 0; j < (1<> k) & 1)); + for (k = m - 2; k >= 0; --k) { + writePSFmt("{0:d} mul {1:d} index {2:d} get add\n", + func0->getSampleSize(k), + i + j + 3, + 2 * k + ((j >> k) & 1)); + } + if (n > 1) { + writePSFmt("{0:d} mul {1:d} add ", n, i); + } + writePS("get\n"); + } + // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^m-1) + for (j = 0; j < m; ++j) { + // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^(m-j)-1) + for (k = 0; k < (1 << (m - j)); k += 2) { + // [e01] [efrac] y(0) ... y(i-1) <2^(m-j)-k s values> + writePSFmt("{0:d} index {1:d} get dup\n", + i + k/2 + (1 << (m-j)) - k, j); + writePS("3 2 roll mul exch 1 exch sub 3 2 roll mul add\n"); + writePSFmt("{0:d} 1 roll\n", k/2 + (1 << m-j) - k - 1); + } + // [e01] [efrac] s'(0) s'(1) ... s(2^(m-j-1)-1) + } + // [e01] [efrac] y(0) ... y(i-1) s + writePSFmt("{0:.4g} mul {1:.4g} add\n", + func0->getDecodeMax(i) - func0->getDecodeMin(i), + func0->getDecodeMin(i)); + writePSFmt("dup {0:.4g} lt {{ pop {1:.4g} }} {{ dup {2:.4g} gt {{ pop {3:.4g} }} if }} ifelse\n", + func0->getRangeMin(i), func0->getRangeMin(i), + func0->getRangeMax(i), func0->getRangeMax(i)); + // [e01] [efrac] y(0) ... y(i-1) y(i) + } + // [e01] [efrac] y(0) ... y(n-1) + writePSFmt("{0:d} {1:d} roll pop pop }}\n", n+2, n); + break; + + case 2: // exponential + func2 = (ExponentialFunction *)func; + n = func2->getOutputSize(); + writePSFmt("{{ dup {0:.4g} lt {{ pop {1:.4g} }} {{ dup {2:.4g} gt {{ pop {3:.4g} }} if }} ifelse\n", + func2->getDomainMin(0), func2->getDomainMin(0), + func2->getDomainMax(0), func2->getDomainMax(0)); + // x + for (i = 0; i < n; ++i) { + // x y(0) .. y(i-1) + writePSFmt("{0:d} index {1:.4g} exp {2:.4g} mul {3:.4g} add\n", + i, func2->getE(), func2->getC1()[i] - func2->getC0()[i], + func2->getC0()[i]); + if (func2->getHasRange()) { + writePSFmt("dup {0:.4g} lt {{ pop {1:.4g} }} {{ dup {2:.4g} gt {{ pop {3:.4g} }} if }} ifelse\n", + func2->getRangeMin(i), func2->getRangeMin(i), + func2->getRangeMax(i), func2->getRangeMax(i)); + } + } + // x y(0) .. y(n-1) + writePSFmt("{0:d} {1:d} roll pop }}\n", n+1, n); + break; + + case 3: // stitching + func3 = (StitchingFunction *)func; + thisFunc = nextFunc++; + for (i = 0; i < func3->getNumFuncs(); ++i) { + cvtFunction(func3->getFunc(i)); + writePSFmt("/xpdfFunc{0:d}_{1:d} exch def\n", thisFunc, i); + } + writePSFmt("{{ dup {0:.4g} lt {{ pop {1:.4g} }} {{ dup {2:.4g} gt {{ pop {3:.4g} }} if }} ifelse\n", + func3->getDomainMin(0), func3->getDomainMin(0), + func3->getDomainMax(0), func3->getDomainMax(0)); + for (i = 0; i < func3->getNumFuncs() - 1; ++i) { + writePSFmt("dup {0:.4g} lt {{ {1:.4g} sub {2:.4g} mul {3:.4g} add xpdfFunc{4:d}_{5:d} }} {{\n", + func3->getBounds()[i+1], + func3->getBounds()[i], + func3->getScale()[i], + func3->getEncode()[2*i], + thisFunc, i); + } + writePSFmt("{0:.4g} sub {1:.4g} mul {2:.4g} add xpdfFunc{3:d}_{4:d}\n", + func3->getBounds()[i], + func3->getScale()[i], + func3->getEncode()[2*i], + thisFunc, i); + for (i = 0; i < func3->getNumFuncs() - 1; ++i) { + writePS("} ifelse\n"); + } + writePS("}\n"); + break; + + case 4: // PostScript + func4 = (PostScriptFunction *)func; + writePS(func4->getCodeString()->getCString()); + writePS("\n"); + break; + } +} + +void PSOutputDev::writePSChar(char c) { + if (t3String) { + t3String->append(c); + } else { + (*outputFunc)(outputStream, &c, 1); + } +} + +void PSOutputDev::writePS(char *s) { + if (t3String) { + t3String->append(s); + } else { + (*outputFunc)(outputStream, s, strlen(s)); + } +} + +void PSOutputDev::writePSFmt(const char *fmt, ...) { + va_list args; + GString *buf; + + va_start(args, fmt); + if (t3String) { + t3String->appendfv((char *)fmt, args); + } else { + buf = GString::formatv((char *)fmt, args); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + va_end(args); +} + +void PSOutputDev::writePSString(GString *s) { + Guchar *p; + int n, line; + char buf[8]; + + writePSChar('('); + line = 1; + for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) { + if (line >= 64) { + writePSChar('\\'); + writePSChar('\n'); + line = 0; + } + if (*p == '(' || *p == ')' || *p == '\\') { + writePSChar('\\'); + writePSChar((char)*p); + line += 2; + } else if (*p < 0x20 || *p >= 0x80) { + sprintf(buf, "\\%03o", *p); + writePS(buf); + line += 4; + } else { + writePSChar((char)*p); + ++line; + } + } + writePSChar(')'); +} + +void PSOutputDev::writePSName(char *s) { + char *p; + char c; + + p = s; + while ((c = *p++)) { + if (c <= (char)0x20 || c >= (char)0x7f || + c == '(' || c == ')' || c == '<' || c == '>' || + c == '[' || c == ']' || c == '{' || c == '}' || + c == '/' || c == '%') { + writePSFmt("#{0:02x}", c & 0xff); + } else { + writePSChar(c); + } + } +} + +GString *PSOutputDev::filterPSName(GString *name) { + GString *name2; + char buf[8]; + int i; + char c; + + name2 = new GString(); + + // ghostscript chokes on names that begin with out-of-limits + // numbers, e.g., 1e4foo is handled correctly (as a name), but + // 1e999foo generates a limitcheck error + c = name->getChar(0); + if (c >= '0' && c <= '9') { + name2->append('f'); + } + + for (i = 0; i < name->getLength(); ++i) { + c = name->getChar(i); + if (c <= (char)0x20 || c >= (char)0x7f || + c == '(' || c == ')' || c == '<' || c == '>' || + c == '[' || c == ']' || c == '{' || c == '}' || + c == '/' || c == '%') { + sprintf(buf, "#%02x", c & 0xff); + name2->append(buf); + } else { + name2->append(c); + } + } + return name2; +} + +// Write a DSC-compliant . +void PSOutputDev::writePSTextLine(GString *s) { + int i, j, step; + int c; + + // - DSC comments must be printable ASCII; control chars and + // backslashes have to be escaped (we do cheap Unicode-to-ASCII + // conversion by simply ignoring the high byte) + // - lines are limited to 255 chars (we limit to 200 here to allow + // for the keyword, which was emitted by the caller) + // - lines that start with a left paren are treated as + // instead of , so we escape a leading paren + if (s->getLength() >= 2 && + (s->getChar(0) & 0xff) == 0xfe && + (s->getChar(1) & 0xff) == 0xff) { + i = 3; + step = 2; + } else { + i = 0; + step = 1; + } + for (j = 0; i < s->getLength() && j < 200; i += step) { + c = s->getChar(i) & 0xff; + if (c == '\\') { + writePS("\\\\"); + j += 2; + } else if (c < 0x20 || c > 0x7e || (j == 0 && c == '(')) { + writePSFmt("\\{0:03o}", c); + j += 4; + } else { + writePSChar(c); + ++j; + } + } + writePS("\n"); +} diff --git a/kpdf/xpdf/xpdf/PSOutputDev.h b/kpdf/xpdf/xpdf/PSOutputDev.h new file mode 100644 index 00000000..36c0e8b6 --- /dev/null +++ b/kpdf/xpdf/xpdf/PSOutputDev.h @@ -0,0 +1,391 @@ +//======================================================================== +// +// PSOutputDev.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef PSOUTPUTDEV_H +#define PSOUTPUTDEV_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include +#include "config.h" +#include "Object.h" +#include "GlobalParams.h" +#include "OutputDev.h" + +class Function; +class GfxPath; +class GfxFont; +class GfxColorSpace; +class GfxSeparationColorSpace; +class PDFRectangle; +struct PSFont8Info; +struct PSFont16Enc; +class PSOutCustomColor; + +//------------------------------------------------------------------------ +// PSOutputDev +//------------------------------------------------------------------------ + +enum PSOutMode { + psModePS, + psModeEPS, + psModeForm +}; + +enum PSFileType { + psFile, // write to file + psPipe, // write to pipe + psStdout, // write to stdout + psGeneric // write to a generic stream +}; + +typedef void (*PSOutputFunc)(void *stream, char *data, int len); + +class PSOutputDev: public OutputDev { +public: + + // Open a PostScript output file, and write the prolog. + PSOutputDev(char *fileName, char *pstitle, XRef *xrefA, Catalog *catalog, + int firstPage, int lastPage, PSOutMode modeA, + int imgLLXA = 0, int imgLLYA = 0, + int imgURXA = 0, int imgURYA = 0, + GBool forceRasterize = gFalse, + GBool manualCtrlA = gFalse); + + // Destructor -- writes the trailer and closes the file. + virtual ~PSOutputDev(); + + // Check if file was successfully created. + virtual GBool isOk() { return ok; } + + //---- get info about output device + + // Does this device use upside-down coordinates? + // (Upside-down means (0,0) is the top left corner of the page.) + virtual GBool upsideDown() { return gFalse; } + + // Does this device use drawChar() or drawString()? + virtual GBool useDrawChar() { return gFalse; } + + // Does this device use tilingPatternFill()? If this returns false, + // tiling pattern fills will be reduced to a series of other drawing + // operations. + virtual GBool useTilingPatternFill() { return gTrue; } + + // Does this device use functionShadedFill(), axialShadedFill(), and + // radialShadedFill()? If this returns false, these shaded fills + // will be reduced to a series of other drawing operations. + virtual GBool useShadedFills() + { return level >= psLevel2; } + + // Does this device use drawForm()? If this returns false, + // form-type XObjects will be interpreted (i.e., unrolled). + virtual GBool useDrawForm() { return preload; } + + // Does this device use beginType3Char/endType3Char? Otherwise, + // text in Type 3 fonts will be drawn with drawChar/drawString. + virtual GBool interpretType3Chars() { return gFalse; } + + //----- header/trailer (used only if manualCtrl is true) + + // Write the document-level header. + void writeHeader(int firstPage, int lastPage, + PDFRectangle *mediaBox, PDFRectangle *cropBox, + int pageRotate, char *pstitle); + + // Write the Xpdf procset. + void writeXpdfProcset(); + + // Write the document-level setup. + void writeDocSetup(Catalog *catalog, int firstPage, int lastPage); + + // Write the trailer for the current page. + void writePageTrailer(); + + // Write the document trailer. + void writeTrailer(); + + //----- initialization and control + + // Check to see if a page slice should be displayed. If this + // returns false, the page display is aborted. Typically, an + // OutputDev will use some alternate means to display the page + // before returning false. + virtual GBool checkPageSlice(Page *page, double hDPI, double vDPI, + int rotate, GBool useMediaBox, GBool crop, + int sliceX, int sliceY, int sliceW, int sliceH, + GBool printing, Catalog *catalog, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); + + // Start a page. + virtual void startPage(int pageNum, GfxState *state); + + // End a page. + virtual void endPage(); + + //----- save/restore graphics state + virtual void saveState(GfxState *state); + virtual void restoreState(GfxState *state); + + //----- update graphics state + virtual void updateCTM(GfxState *state, double m11, double m12, + double m21, double m22, double m31, double m32); + virtual void updateLineDash(GfxState *state); + virtual void updateFlatness(GfxState *state); + virtual void updateLineJoin(GfxState *state); + virtual void updateLineCap(GfxState *state); + virtual void updateMiterLimit(GfxState *state); + virtual void updateLineWidth(GfxState *state); + virtual void updateFillColorSpace(GfxState *state); + virtual void updateStrokeColorSpace(GfxState *state); + virtual void updateFillColor(GfxState *state); + virtual void updateStrokeColor(GfxState *state); + virtual void updateFillOverprint(GfxState *state); + virtual void updateStrokeOverprint(GfxState *state); + virtual void updateTransfer(GfxState *state); + + //----- update text state + virtual void updateFont(GfxState *state); + virtual void updateTextMat(GfxState *state); + virtual void updateCharSpace(GfxState *state); + virtual void updateRender(GfxState *state); + virtual void updateRise(GfxState *state); + virtual void updateWordSpace(GfxState *state); + virtual void updateHorizScaling(GfxState *state); + virtual void updateTextPos(GfxState *state); + virtual void updateTextShift(GfxState *state, double shift); + + //----- path painting + virtual void stroke(GfxState *state); + virtual void fill(GfxState *state); + virtual void eoFill(GfxState *state); + virtual void tilingPatternFill(GfxState *state, Object *str, + int paintType, Dict *resDict, + double *mat, double *bbox, + int x0, int y0, int x1, int y1, + double xStep, double yStep); + virtual GBool functionShadedFill(GfxState *state, + GfxFunctionShading *shading); + virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading); + virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading); + + //----- path clipping + virtual void clip(GfxState *state); + virtual void eoClip(GfxState *state); + virtual void clipToStrokePath(GfxState *state); + + //----- text drawing + virtual void drawString(GfxState *state, GString *s); + virtual void endTextObject(GfxState *state); + + //----- image drawing + virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, + int width, int height, GBool invert, + GBool inlineImg); + virtual void drawImage(GfxState *state, Object *ref, Stream *str, + int width, int height, GfxImageColorMap *colorMap, + int *maskColors, GBool inlineImg); + virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, int maskWidth, int maskHeight, + GBool maskInvert); + +#if OPI_SUPPORT + //----- OPI functions + virtual void opiBegin(GfxState *state, Dict *opiDict); + virtual void opiEnd(GfxState *state, Dict *opiDict); +#endif + + //----- Type 3 font operators + virtual void type3D0(GfxState *state, double wx, double wy); + virtual void type3D1(GfxState *state, double wx, double wy, + double llx, double lly, double urx, double ury); + + //----- form XObjects + virtual void drawForm(Ref ref); + + //----- PostScript XObjects + virtual void psXObject(Stream *psStream, Stream *level1Stream); + + //----- miscellaneous + void setOffset(double x, double y) + { tx0 = x; ty0 = y; } + void setScale(double x, double y) + { xScale0 = x; yScale0 = y; } + void setRotate(int rotateA) + { rotate0 = rotateA; } + void setClip(double llx, double lly, double urx, double ury) + { clipLLX0 = llx; clipLLY0 = lly; clipURX0 = urx; clipURY0 = ury; } + void setUnderlayCbk(void (*cbk)(PSOutputDev *psOut, void *data), + void *data) + { underlayCbk = cbk; underlayCbkData = data; } + void setOverlayCbk(void (*cbk)(PSOutputDev *psOut, void *data), + void *data) + { overlayCbk = cbk; overlayCbkData = data; } + +private: + + void init(PSOutputFunc outputFuncA, void *outputStreamA, + PSFileType fileTypeA, char *pstitle, XRef *xrefA, Catalog *catalog, + int firstPage, int lastPage, PSOutMode modeA, + int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, + GBool manualCtrlA); + void setupResources(Dict *resDict); + void setupFonts(Dict *resDict); + void setupFont(GfxFont *font, Dict *parentResDict); + void setupEmbeddedType1Font(Ref *id, GString *psName); + void setupExternalType1Font(GString *fileName, GString *psName); + void setupEmbeddedType1CFont(GfxFont *font, Ref *id, GString *psName); + void setupEmbeddedOpenTypeT1CFont(GfxFont *font, Ref *id, GString *psName); + void setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, GString *psName); + GString *setupExternalTrueTypeFont(GfxFont *font); + void setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, GString *psName); + void setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, GString *psName, + GBool needVerticalMetrics); + void setupEmbeddedOpenTypeCFFFont(GfxFont *font, Ref *id, GString *psName); + GString *setupExternalCIDTrueTypeFont(GfxFont *font, GString *fileName, int faceIndex=0); + void setupType3Font(GfxFont *font, GString *psName, Dict *parentResDict); + void setupImages(Dict *resDict); + void setupImage(Ref id, Stream *str); + void setupForms(Dict *resDict); + void setupForm(Ref id, Object *strObj); + void addProcessColor(double c, double m, double y, double k); + void addCustomColor(GfxSeparationColorSpace *sepCS); + void doPath(GfxPath *path); + void doImageL1(Object *ref, GfxImageColorMap *colorMap, + GBool invert, GBool inlineImg, + Stream *str, int width, int height, int len); + void doImageL1Sep(GfxImageColorMap *colorMap, + GBool invert, GBool inlineImg, + Stream *str, int width, int height, int len); + void doImageL2(Object *ref, GfxImageColorMap *colorMap, + GBool invert, GBool inlineImg, + Stream *str, int width, int height, int len, + int *maskColors, Stream *maskStr, + int maskWidth, int maskHeight, GBool maskInvert); + void doImageL3(Object *ref, GfxImageColorMap *colorMap, + GBool invert, GBool inlineImg, + Stream *str, int width, int height, int len, + int *maskColors, Stream *maskStr, + int maskWidth, int maskHeight, GBool maskInvert); + void dumpColorSpaceL2(GfxColorSpace *colorSpace, + GBool genXform, GBool updateColors, + GBool map01); +#if OPI_SUPPORT + void opiBegin20(GfxState *state, Dict *dict); + void opiBegin13(GfxState *state, Dict *dict); + void opiTransform(GfxState *state, double x0, double y0, + double *x1, double *y1); + GBool getFileSpec(Object *fileSpec, Object *fileName); +#endif + void cvtFunction(Function *func); + void writePSChar(char c); + void writePS(char *s); + void writePSFmt(const char *fmt, ...); + void writePSString(GString *s); + void writePSName(char *s); + GString *filterPSName(GString *name); + void writePSTextLine(GString *s); + + PSLevel level; // PostScript level (1, 2, separation) + PSOutMode mode; // PostScript mode (PS, EPS, form) + int paperWidth; // width of paper, in pts + int paperHeight; // height of paper, in pts + int imgLLX, imgLLY, // imageable area, in pts + imgURX, imgURY; + GBool preload; // load all images into memory, and + // predefine forms + + PSOutputFunc outputFunc; + void *outputStream; + PSFileType fileType; // file / pipe / stdout + GBool manualCtrl; + int seqPage; // current sequential page number + void (*underlayCbk)(PSOutputDev *psOut, void *data); + void *underlayCbkData; + void (*overlayCbk)(PSOutputDev *psOut, void *data); + void *overlayCbkData; + + XRef *xref; // the xref table for this PDF file + + Ref *fontIDs; // list of object IDs of all used fonts + int fontIDLen; // number of entries in fontIDs array + int fontIDSize; // size of fontIDs array + Ref *fontFileIDs; // list of object IDs of all embedded fonts + int fontFileIDLen; // number of entries in fontFileIDs array + int fontFileIDSize; // size of fontFileIDs array + GString **fontFileNames; // list of names of all embedded external fonts + GString **psFileNames; // list of names of all embedded external ps names + int fontFileNameLen; // number of entries in fontFileNames array + int fontFileNameSize; // size of fontFileNames array + int nextTrueTypeNum; // next unique number to append to a TrueType + // font name + PSFont8Info *font8Info; // info for 8-bit fonts + int font8InfoLen; // number of entries in font8Info array + int font8InfoSize; // size of font8Info array + PSFont16Enc *font16Enc; // encodings for substitute 16-bit fonts + int font16EncLen; // number of entries in font16Enc array + int font16EncSize; // size of font16Enc array + Ref *imgIDs; // list of image IDs for in-memory images + int imgIDLen; // number of entries in imgIDs array + int imgIDSize; // size of imgIDs array + Ref *formIDs; // list of IDs for predefined forms + int formIDLen; // number of entries in formIDs array + int formIDSize; // size of formIDs array + GList *xobjStack; // stack of XObject dicts currently being + // processed + int numSaves; // current number of gsaves + int numTilingPatterns; // current number of nested tiling patterns + int nextFunc; // next unique number to use for a function + + double tx0, ty0; // global translation + double xScale0, yScale0; // global scaling + int rotate0; // rotation angle (0, 90, 180, 270) + double clipLLX0, clipLLY0, + clipURX0, clipURY0; + double tx, ty; // global translation for current page + double xScale, yScale; // global scaling for current page + int rotate; // rotation angle for current page + double epsX1, epsY1, // EPS bounding box (unrotated) + epsX2, epsY2; + + GString *embFontList; // resource comments for embedded fonts + + int processColors; // used process colors + PSOutCustomColor // used custom colors + *customColors; + + GBool haveTextClip; // set if text has been drawn with a + // clipping render mode + + GBool inType3Char; // inside a Type 3 CharProc + GString *t3String; // Type 3 content string + double t3WX, t3WY, // Type 3 character parameters + t3LLX, t3LLY, t3URX, t3URY; + GBool t3Cacheable; // cleared if char is not cacheable + GBool t3NeedsRestore; // set if a 'q' operator was issued + GBool forceRasterize; // forces the page to be rasterized + +#if OPI_SUPPORT + int opi13Nest; // nesting level of OPI 1.3 objects + int opi20Nest; // nesting level of OPI 2.0 objects +#endif + + GBool ok; // set up ok? + + + friend class WinPDFPrinter; +}; + +#endif diff --git a/kpdf/xpdf/xpdf/PSTokenizer.cc b/kpdf/xpdf/xpdf/PSTokenizer.cc new file mode 100644 index 00000000..a959cc73 --- /dev/null +++ b/kpdf/xpdf/xpdf/PSTokenizer.cc @@ -0,0 +1,135 @@ +//======================================================================== +// +// PSTokenizer.cc +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "PSTokenizer.h" + +//------------------------------------------------------------------------ + +// A '1' in this array means the character is white space. A '1' or +// '2' means the character ends a name or command. +static char PSTokenizer_specialChars[256] = { + 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x + 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx +}; + +//------------------------------------------------------------------------ + +PSTokenizer::PSTokenizer(int (*getCharFuncA)(void *), void *dataA) { + getCharFunc = getCharFuncA; + data = dataA; + charBuf = -1; +} + +PSTokenizer::~PSTokenizer() { +} + +GBool PSTokenizer::getToken(char *buf, int size, int *length) { + GBool comment, backslash; + int c; + int i; + + // skip whitespace and comments + comment = gFalse; + while (1) { + if ((c = getChar()) == EOF) { + buf[0] = '\0'; + *length = 0; + return gFalse; + } + if (comment) { + if (c == '\x0a' || c == '\x0d') { + comment = gFalse; + } + } else if (c == '%') { + comment = gTrue; + } else if (PSTokenizer_specialChars[c] != 1) { + break; + } + } + + // read a token + i = 0; + buf[i++] = c; + if (c == '(') { + backslash = gFalse; + while ((c = lookChar()) != EOF) { + if (i < size - 1) { + buf[i++] = c; + } + getChar(); + if (c == '\\') { + backslash = gTrue; + } else if (!backslash && c == ')') { + break; + } else { + backslash = gFalse; + } + } + } else if (c == '<') { + while ((c = lookChar()) != EOF) { + getChar(); + if (i < size - 1 && PSTokenizer_specialChars[c] != 1) { + buf[i++] = c; + } + if (c == '>') { + break; + } + } + } else if (c != '[' && c != ']') { + while ((c = lookChar()) != EOF && !PSTokenizer_specialChars[c]) { + getChar(); + if (i < size - 1) { + buf[i++] = c; + } + } + } + buf[i] = '\0'; + *length = i; + + return gTrue; +} + +int PSTokenizer::lookChar() { + if (charBuf < 0) { + charBuf = (*getCharFunc)(data); + } + return charBuf; +} + +int PSTokenizer::getChar() { + int c; + + if (charBuf < 0) { + charBuf = (*getCharFunc)(data); + } + c = charBuf; + charBuf = -1; + return c; +} diff --git a/kpdf/xpdf/xpdf/PSTokenizer.h b/kpdf/xpdf/xpdf/PSTokenizer.h new file mode 100644 index 00000000..4d5ee97f --- /dev/null +++ b/kpdf/xpdf/xpdf/PSTokenizer.h @@ -0,0 +1,41 @@ +//======================================================================== +// +// PSTokenizer.h +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef PSTOKENIZER_H +#define PSTOKENIZER_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +//------------------------------------------------------------------------ + +class PSTokenizer { +public: + + PSTokenizer(int (*getCharFuncA)(void *), void *dataA); + ~PSTokenizer(); + + // Get the next PostScript token. Returns false at end-of-stream. + GBool getToken(char *buf, int size, int *length); + +private: + + int lookChar(); + int getChar(); + + int (*getCharFunc)(void *); + void *data; + int charBuf; +}; + +#endif diff --git a/kpdf/xpdf/xpdf/Page.cc b/kpdf/xpdf/xpdf/Page.cc new file mode 100644 index 00000000..cfeab88b --- /dev/null +++ b/kpdf/xpdf/xpdf/Page.cc @@ -0,0 +1,558 @@ +//======================================================================== +// +// Page.cc +// +// Copyright 1996-2007 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "GlobalParams.h" +#include "Object.h" +#include "Array.h" +#include "Dict.h" +#include "XRef.h" +#include "Link.h" +#include "OutputDev.h" +#ifndef PDF_PARSER_ONLY +#include "Gfx.h" +#include "GfxState.h" +#include "Annot.h" +#endif +#include "Error.h" +#include "Catalog.h" +#include "Page.h" + +//------------------------------------------------------------------------ +// PDFRectangle +//------------------------------------------------------------------------ + +void PDFRectangle::clipTo(PDFRectangle *rect) { + if (x1 < rect->x1) { + x1 = rect->x1; + } else if (x1 > rect->x2) { + x1 = rect->x2; + } + if (x2 < rect->x1) { + x2 = rect->x1; + } else if (x2 > rect->x2) { + x2 = rect->x2; + } + if (y1 < rect->y1) { + y1 = rect->y1; + } else if (y1 > rect->y2) { + y1 = rect->y2; + } + if (y2 < rect->y1) { + y2 = rect->y1; + } else if (y2 > rect->y2) { + y2 = rect->y2; + } +} + +//------------------------------------------------------------------------ +// PageAttrs +//------------------------------------------------------------------------ + +PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { + Object obj1; + + // get old/default values + if (attrs) { + mediaBox = attrs->mediaBox; + cropBox = attrs->cropBox; + haveCropBox = attrs->haveCropBox; + rotate = attrs->rotate; + attrs->resources.copy(&resources); + } else { + // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary + // but some (non-compliant) PDF files don't specify a MediaBox + mediaBox.x1 = 0; + mediaBox.y1 = 0; + mediaBox.x2 = 612; + mediaBox.y2 = 792; + cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0; + haveCropBox = gFalse; + rotate = 0; + resources.initNull(); + } + + // media box + readBox(dict, "MediaBox", &mediaBox); + + // crop box + if (readBox(dict, "CropBox", &cropBox)) { + haveCropBox = gTrue; + } + if (!haveCropBox) { + cropBox = mediaBox; + } + else + { + // cropBox can not be bigger than mediaBox + if (cropBox.x2 - cropBox.x1 > mediaBox.x2 - mediaBox.x1) + { + cropBox.x1 = mediaBox.x1; + cropBox.x2 = mediaBox.x2; + } + if (cropBox.y2 - cropBox.y1 > mediaBox.y2 - mediaBox.y1) + { + cropBox.y1 = mediaBox.y1; + cropBox.y2 = mediaBox.y2; + } + } + + // other boxes + bleedBox = cropBox; + readBox(dict, "BleedBox", &bleedBox); + trimBox = cropBox; + readBox(dict, "TrimBox", &trimBox); + artBox = cropBox; + readBox(dict, "ArtBox", &artBox); + + // clip all other boxes to the media box + cropBox.clipTo(&mediaBox); + bleedBox.clipTo(&mediaBox); + trimBox.clipTo(&mediaBox); + artBox.clipTo(&mediaBox); + + // rotate + dict->lookup("Rotate", &obj1); + if (obj1.isInt()) { + rotate = obj1.getInt(); + } + obj1.free(); + while (rotate < 0) { + rotate += 360; + } + while (rotate >= 360) { + rotate -= 360; + } + + // misc attributes + dict->lookup("LastModified", &lastModified); + dict->lookup("BoxColorInfo", &boxColorInfo); + dict->lookup("Group", &group); + dict->lookup("Metadata", &metadata); + dict->lookup("PieceInfo", &pieceInfo); + dict->lookup("SeparationInfo", &separationInfo); + + // resource dictionary + dict->lookup("Resources", &obj1); + if (obj1.isDict()) { + resources.free(); + obj1.copy(&resources); + } + obj1.free(); +} + +PageAttrs::~PageAttrs() { + lastModified.free(); + boxColorInfo.free(); + group.free(); + metadata.free(); + pieceInfo.free(); + separationInfo.free(); + resources.free(); +} + +GBool PageAttrs::readBox(Dict *dict, char *key, PDFRectangle *box) { + PDFRectangle tmp; + double t; + Object obj1, obj2; + GBool ok; + + dict->lookup(key, &obj1); + if (obj1.isArray() && obj1.arrayGetLength() == 4) { + ok = gTrue; + obj1.arrayGet(0, &obj2); + if (obj2.isNum()) { + tmp.x1 = obj2.getNum(); + } else { + ok = gFalse; + } + obj2.free(); + obj1.arrayGet(1, &obj2); + if (obj2.isNum()) { + tmp.y1 = obj2.getNum(); + } else { + ok = gFalse; + } + obj2.free(); + obj1.arrayGet(2, &obj2); + if (obj2.isNum()) { + tmp.x2 = obj2.getNum(); + } else { + ok = gFalse; + } + obj2.free(); + obj1.arrayGet(3, &obj2); + if (obj2.isNum()) { + tmp.y2 = obj2.getNum(); + } else { + ok = gFalse; + } + obj2.free(); + if (ok) { + if (tmp.x1 > tmp.x2) { + t = tmp.x1; tmp.x1 = tmp.x2; tmp.x2 = t; + } + if (tmp.y1 > tmp.y2) { + t = tmp.y1; tmp.y1 = tmp.y2; tmp.y2 = t; + } + *box = tmp; + } + } else { + ok = gFalse; + } + obj1.free(); + return ok; +} + +//------------------------------------------------------------------------ +// PageTransition +//------------------------------------------------------------------------ + +PageTransition::PageTransition(Dict *dict) + : type(Replace), + duration(1), + alignment(Horizontal), + direction(Inward), + angle(0), + scale(1.0), + rectangular(false) +{ + Object dictObj; + Object obj; + + dict->lookup("Trans", &dictObj); + if (dictObj.isDict()) { + Dict *transDict = dictObj.getDict(); + + if (transDict->lookup("S", &obj)->isName()) { + const char *s = obj.getName(); + if (strcmp("R", s) == 0) + type = Replace; + else if (strcmp("Split", s) == 0) + type = Split; + else if (strcmp("Blinds", s) == 0) + type = Blinds; + else if (strcmp("Box", s) == 0) + type = Box; + else if (strcmp("Wipe", s) == 0) + type = Wipe; + else if (strcmp("Dissolve", s) == 0) + type = Dissolve; + else if (strcmp("Glitter", s) == 0) + type = Glitter; + else if (strcmp("Fly", s) == 0) + type = Fly; + else if (strcmp("Push", s) == 0) + type = Push; + else if (strcmp("Cover", s) == 0) + type = Cover; + else if (strcmp("Uncover", s) == 0) + type = Push; + else if (strcmp("Fade", s) == 0) + type = Cover; + } + obj.free(); + + if (transDict->lookup("D", &obj)->isInt()) { + duration = obj.getInt(); + } + obj.free(); + + if (transDict->lookup("Dm", &obj)->isName()) { + const char *dm = obj.getName(); + if ( strcmp( "H", dm ) == 0 ) + alignment = Horizontal; + else if ( strcmp( "V", dm ) == 0 ) + alignment = Vertical; + } + obj.free(); + + if (transDict->lookup("M", &obj)->isName()) { + const char *m = obj.getName(); + if ( strcmp( "I", m ) == 0 ) + direction = Inward; + else if ( strcmp( "O", m ) == 0 ) + direction = Outward; + } + obj.free(); + + if (transDict->lookup("Di", &obj)->isInt()) { + angle = obj.getInt(); + } + obj.free(); + + if (transDict->lookup("Di", &obj)->isName()) { + if ( strcmp( "None", obj.getName() ) == 0 ) + angle = 0; + } + obj.free(); + + if (transDict->lookup("SS", &obj)->isReal()) { + scale = obj.getReal(); + } + obj.free(); + + if (transDict->lookup("B", &obj)->isBool()) { + rectangular = obj.getBool(); + } + obj.free(); + } + dictObj.free(); +} + +PageTransition::~PageTransition() { +} + +//------------------------------------------------------------------------ +// Page +//------------------------------------------------------------------------ + +Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA) { + ok = gTrue; + xref = xrefA; + num = numA; + + // get attributes + attrs = attrsA; + + // get transition + transition = new PageTransition( pageDict ); + + // annotations + pageDict->lookupNF("Annots", &annots); + if (!(annots.isRef() || annots.isArray() || annots.isNull())) { + error(-1, "Page annotations object (page %d) is wrong type (%s)", + num, annots.getTypeName()); + annots.free(); + goto err2; + } + + // contents + pageDict->lookupNF("Contents", &contents); + if (!(contents.isRef() || contents.isArray() || + contents.isNull())) { + error(-1, "Page contents object (page %d) is wrong type (%s)", + num, contents.getTypeName()); + contents.free(); + goto err1; + } + + return; + + err2: + annots.initNull(); + err1: + contents.initNull(); + ok = gFalse; +} + +Page::~Page() { + delete attrs; + delete transition; + annots.free(); + contents.free(); +} + +Links *Page::getLinks(Catalog *catalog) { + Links *links; + Object obj; + + links = new Links(getAnnots(&obj), catalog->getBaseURI()); + obj.free(); + return links; +} + +void Page::display(OutputDev *out, double hDPI, double vDPI, + int rotate, GBool useMediaBox, GBool crop, + GBool printing, Catalog *catalog, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { + displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, + -1, -1, -1, -1, printing, catalog, + abortCheckCbk, abortCheckCbkData); +} + +void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, + int rotate, GBool useMediaBox, GBool crop, + int sliceX, int sliceY, int sliceW, int sliceH, + GBool printing, Catalog *catalog, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { +#ifndef PDF_PARSER_ONLY + PDFRectangle *mediaBox, *cropBox; + PDFRectangle box; + Gfx *gfx; + Object obj; + Annots *annotList; + Dict *acroForm; + int i; + + if (!out->checkPageSlice(this, hDPI, vDPI, rotate, useMediaBox, crop, + sliceX, sliceY, sliceW, sliceH, + printing, catalog, + abortCheckCbk, abortCheckCbkData)) { + return; + } + + rotate += getRotate(); + if (rotate >= 360) { + rotate -= 360; + } else if (rotate < 0) { + rotate += 360; + } + + makeBox(hDPI, vDPI, rotate, useMediaBox, out->upsideDown(), + sliceX, sliceY, sliceW, sliceH, &box, &crop); + cropBox = getCropBox(); + + if (globalParams->getPrintCommands()) { + mediaBox = getMediaBox(); + printf("***** MediaBox = ll:%g,%g ur:%g,%g\n", + mediaBox->x1, mediaBox->y1, mediaBox->x2, mediaBox->y2); + printf("***** CropBox = ll:%g,%g ur:%g,%g\n", + cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2); + printf("***** Rotate = %d\n", attrs->getRotate()); + } + + gfx = new Gfx(xref, out, num, attrs->getResourceDict(), + hDPI, vDPI, &box, crop ? cropBox : (PDFRectangle *)NULL, + rotate, abortCheckCbk, abortCheckCbkData); + contents.fetch(xref, &obj); + if (!obj.isNull()) { + gfx->saveState(); + gfx->display(&obj); + gfx->restoreState(); + } + obj.free(); + + // draw annotations + annotList = new Annots(xref, catalog, getAnnots(&obj)); + obj.free(); + acroForm = catalog->getAcroForm()->isDict() ? + catalog->getAcroForm()->getDict() : NULL; + if (acroForm) { + if (acroForm->lookup("NeedAppearances", &obj)) { + if (obj.isBool() && obj.getBool()) { + annotList->generateAppearances(acroForm); + } + } + obj.free(); + } + if (annotList->getNumAnnots() > 0) { + if (globalParams->getPrintCommands()) { + printf("***** Annotations\n"); + } + for (i = 0; i < annotList->getNumAnnots(); ++i) { + annotList->getAnnot(i)->draw(gfx, printing); + } + out->dump(); + } + delete annotList; + + delete gfx; +#endif +} + +void Page::makeBox(double hDPI, double vDPI, int rotate, + GBool useMediaBox, GBool upsideDown, + double sliceX, double sliceY, double sliceW, double sliceH, + PDFRectangle *box, GBool *crop) { + PDFRectangle *mediaBox, *cropBox, *baseBox; + double kx, ky; + + mediaBox = getMediaBox(); + cropBox = getCropBox(); + if (sliceW >= 0 && sliceH >= 0) { + baseBox = useMediaBox ? mediaBox : cropBox; + kx = 72.0 / hDPI; + ky = 72.0 / vDPI; + if (rotate == 90) { + if (upsideDown) { + box->x1 = baseBox->x1 + ky * sliceY; + box->x2 = baseBox->x1 + ky * (sliceY + sliceH); + } else { + box->x1 = baseBox->x2 - ky * (sliceY + sliceH); + box->x2 = baseBox->x2 - ky * sliceY; + } + box->y1 = baseBox->y1 + kx * sliceX; + box->y2 = baseBox->y1 + kx * (sliceX + sliceW); + } else if (rotate == 180) { + box->x1 = baseBox->x2 - kx * (sliceX + sliceW); + box->x2 = baseBox->x2 - kx * sliceX; + if (upsideDown) { + box->y1 = baseBox->y1 + ky * sliceY; + box->y2 = baseBox->y1 + ky * (sliceY + sliceH); + } else { + box->y1 = baseBox->y2 - ky * (sliceY + sliceH); + box->y2 = baseBox->y2 - ky * sliceY; + } + } else if (rotate == 270) { + if (upsideDown) { + box->x1 = baseBox->x2 - ky * (sliceY + sliceH); + box->x2 = baseBox->x2 - ky * sliceY; + } else { + box->x1 = baseBox->x1 + ky * sliceY; + box->x2 = baseBox->x1 + ky * (sliceY + sliceH); + } + box->y1 = baseBox->y2 - kx * (sliceX + sliceW); + box->y2 = baseBox->y2 - kx * sliceX; + } else { + box->x1 = baseBox->x1 + kx * sliceX; + box->x2 = baseBox->x1 + kx * (sliceX + sliceW); + if (upsideDown) { + box->y1 = baseBox->y2 - ky * (sliceY + sliceH); + box->y2 = baseBox->y2 - ky * sliceY; + } else { + box->y1 = baseBox->y1 + ky * sliceY; + box->y2 = baseBox->y1 + ky * (sliceY + sliceH); + } + } + } else if (useMediaBox) { + *box = *mediaBox; + } else { + *box = *cropBox; + *crop = gFalse; + } +} + +void Page::processLinks(OutputDev *out, Catalog *catalog) { + Links *links; + int i; + + links = getLinks(catalog); + for (i = 0; i < links->getNumLinks(); ++i) { + out->processLink(links->getLink(i), catalog); + } + delete links; +} + +void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI, + int rotate, GBool useMediaBox, GBool upsideDown) { + GfxState *state; + int i; + + rotate += getRotate(); + if (rotate >= 360) { + rotate -= 360; + } else if (rotate < 0) { + rotate += 360; + } + state = new GfxState(hDPI, vDPI, + useMediaBox ? getMediaBox() : getCropBox(), + rotate, upsideDown); + for (i = 0; i < 6; ++i) { + ctm[i] = state->getCTM()[i]; + } + delete state; +} diff --git a/kpdf/xpdf/xpdf/Page.h b/kpdf/xpdf/xpdf/Page.h new file mode 100644 index 00000000..111554c7 --- /dev/null +++ b/kpdf/xpdf/xpdf/Page.h @@ -0,0 +1,259 @@ +//======================================================================== +// +// Page.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef PAGE_H +#define PAGE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "Object.h" + +class Dict; +class XRef; +class OutputDev; +class Links; +class Catalog; + +//------------------------------------------------------------------------ + +class PDFRectangle { +public: + double x1, y1, x2, y2; + + PDFRectangle() { x1 = y1 = x2 = y2 = 0; } + PDFRectangle(double x1A, double y1A, double x2A, double y2A) + { x1 = x1A; y1 = y1A; x2 = x2A; y2 = y2A; } + GBool isValid() { return x1 != 0 || y1 != 0 || x2 != 0 || y2 != 0; } + void clipTo(PDFRectangle *rect); +}; + +//------------------------------------------------------------------------ +// PageAttrs +//------------------------------------------------------------------------ + +class PageAttrs { +public: + + // Construct a new PageAttrs object by merging a dictionary + // (of type Pages or Page) into another PageAttrs object. If + // is NULL, uses defaults. + PageAttrs(PageAttrs *attrs, Dict *dict); + + // Destructor. + ~PageAttrs(); + + // Accessors. + PDFRectangle *getMediaBox() { return &mediaBox; } + PDFRectangle *getCropBox() { return &cropBox; } + GBool isCropped() { return haveCropBox; } + PDFRectangle *getBleedBox() { return &bleedBox; } + PDFRectangle *getTrimBox() { return &trimBox; } + PDFRectangle *getArtBox() { return &artBox; } + int getRotate() { return rotate; } + GString *getLastModified() + { return lastModified.isString() + ? lastModified.getString() : (GString *)NULL; } + Dict *getBoxColorInfo() + { return boxColorInfo.isDict() ? boxColorInfo.getDict() : (Dict *)NULL; } + Dict *getGroup() + { return group.isDict() ? group.getDict() : (Dict *)NULL; } + Stream *getMetadata() + { return metadata.isStream() ? metadata.getStream() : (Stream *)NULL; } + Dict *getPieceInfo() + { return pieceInfo.isDict() ? pieceInfo.getDict() : (Dict *)NULL; } + Dict *getSeparationInfo() + { return separationInfo.isDict() + ? separationInfo.getDict() : (Dict *)NULL; } + Dict *getResourceDict() + { return resources.isDict() ? resources.getDict() : (Dict *)NULL; } + +private: + + GBool readBox(Dict *dict, char *key, PDFRectangle *box); + + PDFRectangle mediaBox; + PDFRectangle cropBox; + GBool haveCropBox; + PDFRectangle bleedBox; + PDFRectangle trimBox; + PDFRectangle artBox; + int rotate; + Object lastModified; + Object boxColorInfo; + Object group; + Object metadata; + Object pieceInfo; + Object separationInfo; + Object resources; +}; + +//------------------------------------------------------------------------ +// PageTransition +//------------------------------------------------------------------------ +class PageTransition { +public: + enum Type { + Replace, + Split, + Blinds, + Box, + Wipe, + Dissolve, + Glitter, + Fly, + Push, + Cover, + Uncover, + Fade + }; + + enum Alignment { + Horizontal, + Vertical + }; + + enum Direction { + Inward, + Outward + }; + + // Construct a new PageTransition object from a page dictionary. + PageTransition( Dict *dict ); + + // Destructor + ~PageTransition(); + + // Get type of the transition. + Type getType() const { return type; } + + // Get duration of the transition in seconds. + int getDuration() const { return duration; } + + // Get dimension in which the transition effect + // occurs. + Alignment getAlignment() const { return alignment; } + + // Get direction of motion of the transition effect. + Direction getDirection() const { return direction; } + + // Get direction in which the transition effect moves. + int getAngle() const { return angle; } + + // Get starting or ending scale. + double getScale() const { return scale; } + + // Returns true if the area to be flown is rectangular and + // opaque. + GBool isRectangular() const { return rectangular; } +private: + Type type; + int duration; + Alignment alignment; + Direction direction; + int angle; + double scale; + GBool rectangular; +}; + +//------------------------------------------------------------------------ +// Page +//------------------------------------------------------------------------ + +class Page { +public: + + // Constructor. + Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA); + + // Destructor. + ~Page(); + + // Is page valid? + GBool isOk() { return ok; } + + // Get page parameters. + int getNum() { return num; } + PDFRectangle *getMediaBox() { return attrs->getMediaBox(); } + PDFRectangle *getCropBox() { return attrs->getCropBox(); } + GBool isCropped() { return attrs->isCropped(); } + double getMediaWidth() + { return attrs->getMediaBox()->x2 - attrs->getMediaBox()->x1; } + double getMediaHeight() + { return attrs->getMediaBox()->y2 - attrs->getMediaBox()->y1; } + double getCropWidth() + { return attrs->getCropBox()->x2 - attrs->getCropBox()->x1; } + double getCropHeight() + { return attrs->getCropBox()->y2 - attrs->getCropBox()->y1; } + PDFRectangle *getBleedBox() { return attrs->getBleedBox(); } + PDFRectangle *getTrimBox() { return attrs->getTrimBox(); } + PDFRectangle *getArtBox() { return attrs->getArtBox(); } + int getRotate() { return attrs->getRotate(); } + GString *getLastModified() { return attrs->getLastModified(); } + Dict *getBoxColorInfo() { return attrs->getBoxColorInfo(); } + Dict *getGroup() { return attrs->getGroup(); } + Stream *getMetadata() { return attrs->getMetadata(); } + Dict *getPieceInfo() { return attrs->getPieceInfo(); } + Dict *getSeparationInfo() { return attrs->getSeparationInfo(); } + + // Get resource dictionary. + Dict *getResourceDict() { return attrs->getResourceDict(); } + + // Get annotations array. + Object *getAnnots(Object *obj) { return annots.fetch(xref, obj); } + + // Return a list of links. + Links *getLinks(Catalog *catalog); + + // Get contents. + Object *getContents(Object *obj) { return contents.fetch(xref, obj); } + + // Get transition information. + PageTransition *getTransition() const { return transition; } + + // Display a page. + void display(OutputDev *out, double hDPI, double vDPI, + int rotate, GBool useMediaBox, GBool crop, + GBool printing, Catalog *catalog, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); + + // Display part of a page. + void displaySlice(OutputDev *out, double hDPI, double vDPI, + int rotate, GBool useMediaBox, GBool crop, + int sliceX, int sliceY, int sliceW, int sliceH, + GBool printing, Catalog *catalog, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); + + void makeBox(double hDPI, double vDPI, int rotate, + GBool useMediaBox, GBool upsideDown, + double sliceX, double sliceY, double sliceW, double sliceH, + PDFRectangle *box, GBool *crop); + + void processLinks(OutputDev *out, Catalog *catalog); + + // Get the page's default CTM. + void getDefaultCTM(double *ctm, double hDPI, double vDPI, + int rotate, GBool useMediaBox, GBool upsideDown); + +private: + + XRef *xref; // the xref table for this PDF file + int num; // page number + PageAttrs *attrs; // page attributes + PageTransition *transition; // page transition + Object annots; // annotations array + Object contents; // page contents + GBool ok; // true if page is valid +}; + +#endif diff --git a/kpdf/xpdf/xpdf/Parser.cc b/kpdf/xpdf/xpdf/Parser.cc new file mode 100644 index 00000000..65a43d94 --- /dev/null +++ b/kpdf/xpdf/xpdf/Parser.cc @@ -0,0 +1,227 @@ +//======================================================================== +// +// Parser.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "Object.h" +#include "Array.h" +#include "Dict.h" +#include "Decrypt.h" +#include "Parser.h" +#include "XRef.h" +#include "Error.h" + +Parser::Parser(XRef *xrefA, Lexer *lexerA, GBool allowStreamsA) { + xref = xrefA; + lexer = lexerA; + inlineImg = 0; + allowStreams = allowStreamsA; + lexer->getObj(&buf1); + lexer->getObj(&buf2); +} + +Parser::~Parser() { + buf1.free(); + buf2.free(); + delete lexer; +} + +Object *Parser::getObj(Object *obj, Guchar *fileKey, + CryptAlgorithm encAlgorithm, int keyLength, + int objNum, int objGen) { + char *key; + Stream *str; + Object obj2; + int num; + DecryptStream *decrypt; + GString *s, *s2; + int c; + + // refill buffer after inline image data + if (inlineImg == 2) { + buf1.free(); + buf2.free(); + lexer->getObj(&buf1); + lexer->getObj(&buf2); + inlineImg = 0; + } + + // array + if (buf1.isCmd("[")) { + shift(); + obj->initArray(xref); + while (!buf1.isCmd("]") && !buf1.isEOF()) + obj->arrayAdd(getObj(&obj2, fileKey, encAlgorithm, keyLength, + objNum, objGen)); + if (buf1.isEOF()) + error(getPos(), "End of file inside array"); + shift(); + + // dictionary or stream + } else if (buf1.isCmd("<<")) { + shift(objNum); + obj->initDict(xref); + while (!buf1.isCmd(">>") && !buf1.isEOF()) { + if (!buf1.isName()) { + error(getPos(), "Dictionary key must be a name object"); + shift(); + } else { + key = copyString(buf1.getName()); + shift(); + if (buf1.isEOF() || buf1.isError()) { + gfree(key); + break; + } + obj->dictAdd(key, getObj(&obj2, fileKey, encAlgorithm, keyLength, + objNum, objGen)); + } + } + if (buf1.isEOF()) + error(getPos(), "End of file inside dictionary"); + // stream objects are not allowed inside content streams or + // object streams + if (allowStreams && buf2.isCmd("stream")) { + if ((str = makeStream(obj, fileKey, encAlgorithm, keyLength, + objNum, objGen))) { + obj->initStream(str); + } else { + obj->free(); + obj->initError(); + } + } else { + shift(); + } + + // indirect reference or integer + } else if (buf1.isInt()) { + num = buf1.getInt(); + shift(); + if (buf1.isInt() && buf2.isCmd("R")) { + obj->initRef(num, buf1.getInt()); + shift(); + shift(); + } else { + obj->initInt(num); + } + + // string + } else if (buf1.isString() && fileKey) { + s = buf1.getString(); + s2 = new GString(); + obj2.initNull(); + decrypt = new DecryptStream(new MemStream(s->getCString(), 0, + s->getLength(), &obj2), + fileKey, encAlgorithm, keyLength, + objNum, objGen); + decrypt->reset(); + while ((c = decrypt->getChar()) != EOF) { + s2->append((char)c); + } + delete decrypt; + obj->initString(s2); + shift(); + + // simple object + } else { + buf1.copy(obj); + shift(); + } + + return obj; +} + +Stream *Parser::makeStream(Object *dict, Guchar *fileKey, + CryptAlgorithm encAlgorithm, int keyLength, + int objNum, int objGen) { + Object obj; + BaseStream *baseStr; + Stream *str; + Guint pos, endPos, length; + + // get stream start position + lexer->skipToNextLine(); + pos = lexer->getPos(); + + // get length + dict->dictLookup("Length", &obj); + if (obj.isInt()) { + length = (Guint)obj.getInt(); + obj.free(); + } else { + error(getPos(), "Bad 'Length' attribute in stream"); + obj.free(); + return NULL; + } + + // check for length in damaged file + if (xref && xref->getStreamEnd(pos, &endPos)) { + length = endPos - pos; + } + + // in badly damaged PDF files, we can run off the end of the input + // stream immediately after the "stream" token + if (!lexer->getStream()) { + return NULL; + } + baseStr = lexer->getStream()->getBaseStream(); + + // skip over stream data + lexer->setPos(pos + length); + + // refill token buffers and check for 'endstream' + shift(); // kill '>>' + shift(); // kill 'stream' + if (buf1.isCmd("endstream")) { + shift(); + } else { + error(getPos(), "Missing 'endstream'"); + // kludge for broken PDF files: just add 5k to the length, and + // hope its enough + length += 5000; + } + + // make base stream + str = baseStr->makeSubStream(pos, gTrue, length, dict); + + // handle decryption + if (fileKey) { + str = new DecryptStream(str, fileKey, encAlgorithm, keyLength, + objNum, objGen); + } + + // get filters + str = str->addFilters(dict); + + return str; +} + +void Parser::shift(int objNum) { + if (inlineImg > 0) { + if (inlineImg < 2) { + ++inlineImg; + } else { + // in a damaged content stream, if 'ID' shows up in the middle + // of a dictionary, we need to reset + inlineImg = 0; + } + } else if (buf2.isCmd("ID")) { + lexer->skipChar(); // skip char after 'ID' command + inlineImg = 1; + } + buf1.free(); + buf1 = buf2; + if (inlineImg > 0) // don't buffer inline image data + buf2.initNull(); + else + lexer->getObj(&buf2, objNum); +} diff --git a/kpdf/xpdf/xpdf/Parser.h b/kpdf/xpdf/xpdf/Parser.h new file mode 100644 index 00000000..1cca9954 --- /dev/null +++ b/kpdf/xpdf/xpdf/Parser.h @@ -0,0 +1,59 @@ +//======================================================================== +// +// Parser.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef PARSER_H +#define PARSER_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "Lexer.h" + +//------------------------------------------------------------------------ +// Parser +//------------------------------------------------------------------------ + +class Parser { +public: + + // Constructor. + Parser(XRef *xrefA, Lexer *lexerA, GBool allowStreamsA); + + // Destructor. + ~Parser(); + + // Get the next object from the input stream. + Object *getObj(Object *obj, Guchar *fileKey = NULL, + CryptAlgorithm encAlgorithm = cryptRC4, int keyLength = 0, + int objNum = 0, int objGen = 0); + + // Get stream. + Stream *getStream() { return lexer->getStream(); } + + // Get current position in file. + int getPos() { return lexer->getPos(); } + +private: + + XRef *xref; // the xref table for this PDF file + Lexer *lexer; // input stream + GBool allowStreams; // parse stream objects? + Object buf1, buf2; // next two tokens + int inlineImg; // set when inline image data is encountered + + Stream *makeStream(Object *dict, Guchar *fileKey, + CryptAlgorithm encAlgorithm, int keyLength, + int objNum, int objGen); + void shift(int objNum = -1); +}; + +#endif + diff --git a/kpdf/xpdf/xpdf/PreScanOutputDev.cc b/kpdf/xpdf/xpdf/PreScanOutputDev.cc new file mode 100644 index 00000000..52ffeb7f --- /dev/null +++ b/kpdf/xpdf/xpdf/PreScanOutputDev.cc @@ -0,0 +1,257 @@ +//======================================================================== +// +// PreScanOutputDev.cc +// +// Copyright 2005 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "GlobalParams.h" +#include "GfxFont.h" +#include "Link.h" +#include "PreScanOutputDev.h" + +//------------------------------------------------------------------------ +// PreScanOutputDev +//------------------------------------------------------------------------ + +PreScanOutputDev::PreScanOutputDev() { + clearStats(); +} + +PreScanOutputDev::~PreScanOutputDev() { +} + +void PreScanOutputDev::startPage(int /*pageNum*/, GfxState * /*state*/) { +} + +void PreScanOutputDev::endPage() { +} + +void PreScanOutputDev::stroke(GfxState *state) { + double *dash; + int dashLen; + double dashStart; + + check(state->getStrokeColorSpace(), state->getStrokeColor(), + state->getStrokeOpacity(), state->getBlendMode()); + state->getLineDash(&dash, &dashLen, &dashStart); + if (dashLen != 0) { + gdi = gFalse; + } +} + +void PreScanOutputDev::fill(GfxState *state) { + check(state->getFillColorSpace(), state->getFillColor(), + state->getFillOpacity(), state->getBlendMode()); +} + +void PreScanOutputDev::eoFill(GfxState *state) { + check(state->getFillColorSpace(), state->getFillColor(), + state->getFillOpacity(), state->getBlendMode()); +} + +void PreScanOutputDev::clip(GfxState * /*state*/) { + //~ check for a rectangle "near" the edge of the page; + //~ else set gdi to false +} + +void PreScanOutputDev::eoClip(GfxState * /*state*/) { + //~ see clip() +} + +void PreScanOutputDev::beginStringOp(GfxState *state) { + int render; + GfxFont *font; + double m11, m12, m21, m22; + Ref embRef; + DisplayFontParam *dfp; + GBool simpleTTF; + + render = state->getRender(); + if (!(render & 1)) { + check(state->getFillColorSpace(), state->getFillColor(), + state->getFillOpacity(), state->getBlendMode()); + } + if ((render & 3) == 1 || (render & 3) == 2) { + check(state->getStrokeColorSpace(), state->getStrokeColor(), + state->getStrokeOpacity(), state->getBlendMode()); + } + + font = state->getFont(); + state->getFontTransMat(&m11, &m12, &m21, &m22); + simpleTTF = fabs(m11 + m22) < 0.01 && + m11 > 0 && + fabs(m12) < 0.01 && + fabs(m21) < 0.01 && + fabs(state->getHorizScaling() - 1) < 0.001 && + (font->getType() == fontTrueType || + font->getType() == fontTrueTypeOT) && + (font->getEmbeddedFontID(&embRef) || + font->getExtFontFile() || + (font->getName() && + (dfp = globalParams->getDisplayFont(font->getName())) && + dfp->kind == displayFontTT)); + if (simpleTTF) { + //~ need to create a FoFiTrueType object, and check for a Unicode cmap + } + if (state->getRender() != 0 || !simpleTTF) { + gdi = gFalse; + } +} + +void PreScanOutputDev::endStringOp(GfxState * /*state*/) { +} + +GBool PreScanOutputDev::beginType3Char(GfxState * /*state*/, double /*x*/, double /*y*/, + double /*dx*/, double /*dy*/, + CharCode /*code*/, Unicode * /*u*/, int /*uLen*/) { + // return false so all Type 3 chars get rendered (no caching) + return gFalse; +} + +void PreScanOutputDev::endType3Char(GfxState * /*state*/) { +} + +void PreScanOutputDev::drawImageMask(GfxState *state, Object * /*ref*/, Stream *str, + int width, int height, GBool /*invert*/, + GBool inlineImg) { + int i, j; + + check(state->getFillColorSpace(), state->getFillColor(), + state->getFillOpacity(), state->getBlendMode()); + gdi = gFalse; + + if (inlineImg) { + str->reset(); + j = height * ((width + 7) / 8); + for (i = 0; i < j; ++i) + str->getChar(); + str->close(); + } +} + +void PreScanOutputDev::drawImage(GfxState *state, Object * /*ref*/, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + int * /*maskColors*/, GBool inlineImg) { + GfxColorSpace *colorSpace; + int i, j; + + colorSpace = colorMap->getColorSpace(); + if (colorSpace->getMode() == csIndexed) { + colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase(); + } + if (colorSpace->getMode() != csDeviceGray && + colorSpace->getMode() != csCalGray) { + gray = gFalse; + } + mono = gFalse; + if (state->getBlendMode() != gfxBlendNormal) { + transparency = gTrue; + } + gdi = gFalse; + + if (inlineImg) { + str->reset(); + j = height * ((width * colorMap->getNumPixelComps() * + colorMap->getBits() + 7) / 8); + for (i = 0; i < j; ++i) + str->getChar(); + str->close(); + } +} + +void PreScanOutputDev::drawMaskedImage(GfxState *state, Object * /*ref*/, + Stream * /*str*/, + int /*width*/, int /*height*/, + GfxImageColorMap *colorMap, + Stream * /*maskStr*/, + int /*maskWidth*/, int /*maskHeight*/, + GBool /*maskInvert*/) { + GfxColorSpace *colorSpace; + + colorSpace = colorMap->getColorSpace(); + if (colorSpace->getMode() == csIndexed) { + colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase(); + } + if (colorSpace->getMode() != csDeviceGray && + colorSpace->getMode() != csCalGray) { + gray = gFalse; + } + mono = gFalse; + if (state->getBlendMode() != gfxBlendNormal) { + transparency = gTrue; + } + gdi = gFalse; +} + +void PreScanOutputDev::drawSoftMaskedImage(GfxState * /*state*/, Object * /*ref*/, + Stream * /*str*/, + int /*width*/, int /*height*/, + GfxImageColorMap *colorMap, + Stream * /*maskStr*/, + int /*maskWidth*/, int /*maskHeight*/, + GfxImageColorMap * /*maskColorMap*/) { + GfxColorSpace *colorSpace; + + colorSpace = colorMap->getColorSpace(); + if (colorSpace->getMode() == csIndexed) { + colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase(); + } + if (colorSpace->getMode() != csDeviceGray && + colorSpace->getMode() != csCalGray) { + gray = gFalse; + } + mono = gFalse; + transparency = gTrue; + gdi = gFalse; +} + +void PreScanOutputDev::beginTransparencyGroup( + GfxState * /*state*/, double * /*bbox*/, + GfxColorSpace * /*blendingColorSpace*/, + GBool /*isolated*/, GBool /*knockout*/, + GBool /*forSoftMask*/) { + transparency = gTrue; + gdi = gFalse; +} + +void PreScanOutputDev::check(GfxColorSpace *colorSpace, GfxColor *color, + double opacity, GfxBlendMode blendMode) { + GfxRGB rgb; + + if (colorSpace->getMode() == csPattern) { + mono = gFalse; + gray = gFalse; + gdi = gFalse; + } else { + colorSpace->getRGB(color, &rgb); + if (rgb.r != rgb.g || rgb.g != rgb.b || rgb.b != rgb.r) { + mono = gFalse; + gray = gFalse; + } else if (!((rgb.r == 0 && rgb.g == 0 && rgb.b == 0) || + (rgb.r == gfxColorComp1 && + rgb.g == gfxColorComp1 && + rgb.b == gfxColorComp1))) { + mono = gFalse; + } + } + if (opacity != 1 || blendMode != gfxBlendNormal) { + transparency = gTrue; + } +} + +void PreScanOutputDev::clearStats() { + mono = gTrue; + gray = gTrue; + transparency = gFalse; + gdi = gTrue; +} diff --git a/kpdf/xpdf/xpdf/PreScanOutputDev.h b/kpdf/xpdf/xpdf/PreScanOutputDev.h new file mode 100644 index 00000000..c825ddfc --- /dev/null +++ b/kpdf/xpdf/xpdf/PreScanOutputDev.h @@ -0,0 +1,130 @@ +//======================================================================== +// +// PreScanOutputDev.h +// +// Copyright 2005 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef PRESCANOUTPUTDEV_H +#define PRESCANOUTPUTDEV_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "GfxState.h" +#include "OutputDev.h" + +//------------------------------------------------------------------------ +// PreScanOutputDev +//------------------------------------------------------------------------ + +class PreScanOutputDev: public OutputDev { +public: + + // Constructor. + PreScanOutputDev(); + + // Destructor. + virtual ~PreScanOutputDev(); + + //----- get info about output device + + // Does this device use upside-down coordinates? + // (Upside-down means (0,0) is the top left corner of the page.) + virtual GBool upsideDown() { return gTrue; } + + // Does this device use drawChar() or drawString()? + virtual GBool useDrawChar() { return gTrue; } + + // Does this device use beginType3Char/endType3Char? Otherwise, + // text in Type 3 fonts will be drawn with drawChar/drawString. + virtual GBool interpretType3Chars() { return gTrue; } + + //----- initialization and control + + // Start a page. + virtual void startPage(int pageNum, GfxState *state); + + // End a page. + virtual void endPage(); + + //----- path painting + virtual void stroke(GfxState *state); + virtual void fill(GfxState *state); + virtual void eoFill(GfxState *state); + + //----- path clipping + virtual void clip(GfxState *state); + virtual void eoClip(GfxState *state); + + //----- text drawing + virtual void beginStringOp(GfxState *state); + virtual void endStringOp(GfxState *state); + virtual GBool beginType3Char(GfxState *state, double x, double y, + double dx, double dy, + CharCode code, Unicode *u, int uLen); + virtual void endType3Char(GfxState *state); + + //----- image drawing + virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, + int width, int height, GBool invert, + GBool inlineImg); + virtual void drawImage(GfxState *state, Object *ref, Stream *str, + int width, int height, GfxImageColorMap *colorMap, + int *maskColors, GBool inlineImg); + virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, int maskWidth, int maskHeight, + GBool maskInvert); + virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GfxImageColorMap *maskColorMap); + + //----- transparency groups and soft masks + virtual void beginTransparencyGroup(GfxState *state, double *bbox, + GfxColorSpace *blendingColorSpace, + GBool isolated, GBool knockout, + GBool forSoftMask); + + //----- special access + + // Returns true if the operations performed since the last call to + // clearStats() are all monochrome (black or white). + GBool isMonochrome() { return mono; } + + // Returns true if the operations performed since the last call to + // clearStats() are all gray. + GBool isGray() { return gray; } + + // Returns true if the operations performed since the last call to + // clearStats() included any transparency. + GBool usesTransparency() { return transparency; } + + // Returns true if the operations performed since the last call to + // clearStats() are all rasterizable by GDI calls in GDIOutputDev. + GBool isAllGDI() { return gdi; } + + // Clear the stats used by the above functions. + void clearStats(); + +private: + + void check(GfxColorSpace *colorSpace, GfxColor *color, + double opacity, GfxBlendMode blendMode); + + GBool mono; + GBool gray; + GBool transparency; + GBool gdi; +}; + +#endif diff --git a/kpdf/xpdf/xpdf/SecurityHandler.cc b/kpdf/xpdf/xpdf/SecurityHandler.cc new file mode 100644 index 00000000..ea0f9341 --- /dev/null +++ b/kpdf/xpdf/xpdf/SecurityHandler.cc @@ -0,0 +1,390 @@ +//======================================================================== +// +// SecurityHandler.cc +// +// Copyright 2004 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "GString.h" +#include "PDFDoc.h" +#include "Decrypt.h" +#include "Error.h" +#include "GlobalParams.h" +#if HAVE_XPDFCORE +# include "XPDFCore.h" +#elif HAVE_WINPDFCORE +# include "WinPDFCore.h" +#endif +#ifdef ENABLE_PLUGINS +# include "XpdfPluginAPI.h" +#endif +#include "SecurityHandler.h" + +//------------------------------------------------------------------------ +// SecurityHandler +//------------------------------------------------------------------------ + +SecurityHandler *SecurityHandler::make(PDFDoc *docA, Object *encryptDictA) { + Object filterObj; + SecurityHandler *secHdlr; +#ifdef ENABLE_PLUGINS + XpdfSecurityHandler *xsh; +#endif + + encryptDictA->dictLookup("Filter", &filterObj); + if (filterObj.isName("Standard")) { + secHdlr = new StandardSecurityHandler(docA, encryptDictA); + } else if (filterObj.isName()) { +#ifdef ENABLE_PLUGINS + if ((xsh = globalParams->getSecurityHandler(filterObj.getName()))) { + secHdlr = new ExternalSecurityHandler(docA, encryptDictA, xsh); + } else { +#endif + error(-1, "Couldn't find the '%s' security handler", + filterObj.getName()); + secHdlr = NULL; +#ifdef ENABLE_PLUGINS + } +#endif + } else { + error(-1, "Missing or invalid 'Filter' entry in encryption dictionary"); + secHdlr = NULL; + } + filterObj.free(); + return secHdlr; +} + +SecurityHandler::SecurityHandler(PDFDoc *docA) { + doc = docA; +} + +SecurityHandler::~SecurityHandler() { +} + +GBool SecurityHandler::checkEncryption(GString *ownerPassword, + GString *userPassword) { + void *authData; + GBool ok; + int i; + + if (ownerPassword || userPassword) { + authData = makeAuthData(ownerPassword, userPassword); + } else { + authData = NULL; + } + ok = authorize(authData); + if (authData) { + freeAuthData(authData); + } + for (i = 0; !ok && i < 3; ++i) { + if (!(authData = getAuthData())) { + break; + } + ok = authorize(authData); + if (authData) { + freeAuthData(authData); + } + } + if (!ok) { + error(-1, "Incorrect password"); + } + return ok; +} + +//------------------------------------------------------------------------ +// StandardSecurityHandler +//------------------------------------------------------------------------ + +class StandardAuthData { +public: + + StandardAuthData(GString *ownerPasswordA, GString *userPasswordA) { + ownerPassword = ownerPasswordA; + userPassword = userPasswordA; + } + + ~StandardAuthData() { + if (ownerPassword) { + delete ownerPassword; + } + if (userPassword) { + delete userPassword; + } + } + + GString *ownerPassword; + GString *userPassword; +}; + +StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA, + Object *encryptDictA): + SecurityHandler(docA) +{ + Object versionObj, revisionObj, lengthObj; + Object ownerKeyObj, userKeyObj, permObj, fileIDObj; + Object fileIDObj1; + Object cryptFiltersObj, streamFilterObj, stringFilterObj; + Object cryptFilterObj, cfmObj, cfLengthObj; + Object encryptMetadataObj; + + ok = gFalse; + fileID = NULL; + ownerKey = NULL; + userKey = NULL; + + encryptDictA->dictLookup("V", &versionObj); + encryptDictA->dictLookup("R", &revisionObj); + encryptDictA->dictLookup("Length", &lengthObj); + encryptDictA->dictLookup("O", &ownerKeyObj); + encryptDictA->dictLookup("U", &userKeyObj); + encryptDictA->dictLookup("P", &permObj); + doc->getXRef()->getTrailerDict()->dictLookup("ID", &fileIDObj); + if (versionObj.isInt() && + revisionObj.isInt() && + ownerKeyObj.isString() && ownerKeyObj.getString()->getLength() == 32 && + userKeyObj.isString() && userKeyObj.getString()->getLength() == 32 && + permObj.isInt()) { + encVersion = versionObj.getInt(); + encRevision = revisionObj.getInt(); + encAlgorithm = cryptRC4; + // revision 2 forces a 40-bit key - some buggy PDF generators + // set the Length value incorrectly + if (encRevision == 2 || !lengthObj.isInt()) { + fileKeyLength = 5; + } else { + fileKeyLength = lengthObj.getInt() / 8; + } + encryptMetadata = gTrue; + //~ this currently only handles a subset of crypt filter functionality + if (encVersion == 4 && encRevision == 4) { + encryptDictA->dictLookup("CF", &cryptFiltersObj); + encryptDictA->dictLookup("StmF", &streamFilterObj); + encryptDictA->dictLookup("StrF", &stringFilterObj); + if (cryptFiltersObj.isDict() && + streamFilterObj.isName() && + stringFilterObj.isName() && + !strcmp(streamFilterObj.getName(), stringFilterObj.getName())) { + if (cryptFiltersObj.dictLookup(streamFilterObj.getName(), + &cryptFilterObj)->isDict()) { + cryptFilterObj.dictLookup("CFM", &cfmObj); + if (cfmObj.isName("V2")) { + encVersion = 2; + encRevision = 3; + if (cryptFilterObj.dictLookup("Length", &cfLengthObj)->isInt()) { + //~ according to the spec, this should be cfLengthObj / 8 + fileKeyLength = cfLengthObj.getInt(); + } + cfLengthObj.free(); + } else if (cfmObj.isName("AESV2")) { + encVersion = 2; + encRevision = 3; + encAlgorithm = cryptAES; + if (cryptFilterObj.dictLookup("Length", &cfLengthObj)->isInt()) { + //~ according to the spec, this should be cfLengthObj / 8 + fileKeyLength = cfLengthObj.getInt(); + } + cfLengthObj.free(); + } + cfmObj.free(); + } + cryptFilterObj.free(); + } + stringFilterObj.free(); + streamFilterObj.free(); + cryptFiltersObj.free(); + if (encryptDictA->dictLookup("EncryptMetadata", + &encryptMetadataObj)->isBool()) { + encryptMetadata = encryptMetadataObj.getBool(); + } + encryptMetadataObj.free(); + } + permFlags = permObj.getInt(); + ownerKey = ownerKeyObj.getString()->copy(); + userKey = userKeyObj.getString()->copy(); + if (encVersion >= 1 && encVersion <= 2 && + encRevision >= 2 && encRevision <= 3) { + if (fileIDObj.isArray()) { + if (fileIDObj.arrayGet(0, &fileIDObj1)->isString()) { + fileID = fileIDObj1.getString()->copy(); + } else { + fileID = new GString(); + } + fileIDObj1.free(); + } else { + fileID = new GString(); + } + ok = gTrue; + } else { + error(-1, "Unsupported version/revision (%d/%d) of Standard security handler", + encVersion, encRevision); + } + } else { + error(-1, "Weird encryption info"); + } + if (fileKeyLength > 16) { + fileKeyLength = 16; + } + fileIDObj.free(); + permObj.free(); + userKeyObj.free(); + ownerKeyObj.free(); + lengthObj.free(); + revisionObj.free(); + versionObj.free(); +} + +StandardSecurityHandler::~StandardSecurityHandler() { + if (fileID) { + delete fileID; + } + if (ownerKey) { + delete ownerKey; + } + if (userKey) { + delete userKey; + } +} + +void *StandardSecurityHandler::makeAuthData(GString *ownerPassword, + GString *userPassword) { + return new StandardAuthData(ownerPassword ? ownerPassword->copy() + : (GString *)NULL, + userPassword ? userPassword->copy() + : (GString *)NULL); +} + +void *StandardSecurityHandler::getAuthData() { +#if HAVE_XPDFCORE + XPDFCore *core; + GString *password; + + if (!(core = (XPDFCore *)doc->getGUIData()) || + !(password = core->getPassword())) { + return NULL; + } + return new StandardAuthData(password, password->copy()); +#elif HAVE_WINPDFCORE + WinPDFCore *core; + GString *password; + + if (!(core = (WinPDFCore *)doc->getGUIData()) || + !(password = core->getPassword())) { + return NULL; + } + return new StandardAuthData(password, password->copy()); +#else + return NULL; +#endif +} + +void StandardSecurityHandler::freeAuthData(void *authData) { + delete (StandardAuthData *)authData; +} + +GBool StandardSecurityHandler::authorize(void *authData) { + GString *ownerPassword, *userPassword; + + if (!ok) { + return gFalse; + } + if (authData) { + ownerPassword = ((StandardAuthData *)authData)->ownerPassword; + userPassword = ((StandardAuthData *)authData)->userPassword; + } else { + ownerPassword = NULL; + userPassword = NULL; + } + if (!Decrypt::makeFileKey(encVersion, encRevision, fileKeyLength, + ownerKey, userKey, permFlags, fileID, + ownerPassword, userPassword, fileKey, + encryptMetadata, &ownerPasswordOk)) { + return gFalse; + } + return gTrue; +} + +#ifdef ENABLE_PLUGINS + +//------------------------------------------------------------------------ +// ExternalSecurityHandler +//------------------------------------------------------------------------ + +ExternalSecurityHandler::ExternalSecurityHandler(PDFDoc *docA, + Object *encryptDictA, + XpdfSecurityHandler *xshA): + SecurityHandler(docA) +{ + encryptDictA->copy(&encryptDict); + xsh = xshA; + encAlgorithm = cryptRC4; //~ this should be obtained via getKey + ok = gFalse; + + if (!(*xsh->newDoc)(xsh->handlerData, (XpdfDoc)docA, + (XpdfObject)encryptDictA, &docData)) { + return; + } + + ok = gTrue; +} + +ExternalSecurityHandler::~ExternalSecurityHandler() { + (*xsh->freeDoc)(xsh->handlerData, docData); + encryptDict.free(); +} + +void *ExternalSecurityHandler::makeAuthData(GString *ownerPassword, + GString *userPassword) { + char *opw, *upw; + void *authData; + + opw = ownerPassword ? ownerPassword->getCString() : (char *)NULL; + upw = userPassword ? userPassword->getCString() : (char *)NULL; + if (!(*xsh->makeAuthData)(xsh->handlerData, docData, opw, upw, &authData)) { + return NULL; + } + return authData; +} + +void *ExternalSecurityHandler::getAuthData() { + void *authData; + + if (!(*xsh->getAuthData)(xsh->handlerData, docData, &authData)) { + return NULL; + } + return authData; +} + +void ExternalSecurityHandler::freeAuthData(void *authData) { + (*xsh->freeAuthData)(xsh->handlerData, docData, authData); +} + +GBool ExternalSecurityHandler::authorize(void *authData) { + char *key; + int length; + + if (!ok) { + return gFalse; + } + permFlags = (*xsh->authorize)(xsh->handlerData, docData, authData); + if (!(permFlags & xpdfPermissionOpen)) { + return gFalse; + } + if (!(*xsh->getKey)(xsh->handlerData, docData, &key, &length, &encVersion)) { + return gFalse; + } + if ((fileKeyLength = length) > 16) { + fileKeyLength = 16; + } + memcpy(fileKey, key, fileKeyLength); + (*xsh->freeKey)(xsh->handlerData, docData, key, length); + return gTrue; +} + +#endif // ENABLE_PLUGINS diff --git a/kpdf/xpdf/xpdf/SecurityHandler.h b/kpdf/xpdf/xpdf/SecurityHandler.h new file mode 100644 index 00000000..a27868c2 --- /dev/null +++ b/kpdf/xpdf/xpdf/SecurityHandler.h @@ -0,0 +1,160 @@ +//======================================================================== +// +// SecurityHandler.h +// +// Copyright 2004 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SECURITYHANDLER_H +#define SECURITYHANDLER_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "Object.h" + +class GString; +class PDFDoc; +struct XpdfSecurityHandler; + +//------------------------------------------------------------------------ +// SecurityHandler +//------------------------------------------------------------------------ + +class SecurityHandler { +public: + + static SecurityHandler *make(PDFDoc *docA, Object *encryptDictA); + + SecurityHandler(PDFDoc *docA); + virtual ~SecurityHandler(); + + // Check the document's encryption. If the document is encrypted, + // this will first try and (in + // "batch" mode), and if those fail, it will attempt to request a + // password from the user. This is the high-level function that + // calls the lower level functions for the specific security handler + // (requesting a password three times, etc.). Returns true if the + // document can be opened (if it's unencrypted, or if a correct + // password is obtained); false otherwise (encrypted and no correct + // password). + GBool checkEncryption(GString *ownerPassword, + GString *userPassword); + + // Create authorization data for the specified owner and user + // passwords. If the security handler doesn't support "batch" mode, + // this function should return NULL. + virtual void *makeAuthData(GString *ownerPassword, + GString *userPassword) = 0; + + // Construct authorization data, typically by prompting the user for + // a password. Returns an authorization data object, or NULL to + // cancel. + virtual void *getAuthData() = 0; + + // Free the authorization data returned by makeAuthData or + // getAuthData. + virtual void freeAuthData(void *authData) = 0; + + // Attempt to authorize the document, using the supplied + // authorization data (which may be NULL). Returns true if + // successful (i.e., if at least the right to open the document was + // granted). + virtual GBool authorize(void *authData) = 0; + + // Return the various authorization parameters. These are only + // valid after authorize has returned true. + virtual int getPermissionFlags() = 0; + virtual GBool getOwnerPasswordOk() = 0; + virtual Guchar *getFileKey() = 0; + virtual int getFileKeyLength() = 0; + virtual int getEncVersion() = 0; + virtual CryptAlgorithm getEncAlgorithm() = 0; + +protected: + + PDFDoc *doc; +}; + +//------------------------------------------------------------------------ +// StandardSecurityHandler +//------------------------------------------------------------------------ + +class StandardSecurityHandler: public SecurityHandler { +public: + + StandardSecurityHandler(PDFDoc *docA, Object *encryptDictA); + virtual ~StandardSecurityHandler(); + + virtual void *makeAuthData(GString *ownerPassword, + GString *userPassword); + virtual void *getAuthData(); + virtual void freeAuthData(void *authData); + virtual GBool authorize(void *authData); + virtual int getPermissionFlags() { return permFlags; } + virtual GBool getOwnerPasswordOk() { return ownerPasswordOk; } + virtual Guchar *getFileKey() { return fileKey; } + virtual int getFileKeyLength() { return fileKeyLength; } + virtual int getEncVersion() { return encVersion; } + virtual CryptAlgorithm getEncAlgorithm() { return encAlgorithm; } + +private: + + int permFlags; + GBool ownerPasswordOk; + Guchar fileKey[16]; + int fileKeyLength; + int encVersion; + int encRevision; + CryptAlgorithm encAlgorithm; + GBool encryptMetadata; + + GString *ownerKey, *userKey; + GString *fileID; + GBool ok; +}; + +#ifdef ENABLE_PLUGINS +//------------------------------------------------------------------------ +// ExternalSecurityHandler +//------------------------------------------------------------------------ + +class ExternalSecurityHandler: public SecurityHandler { +public: + + ExternalSecurityHandler(PDFDoc *docA, Object *encryptDictA, + XpdfSecurityHandler *xshA); + virtual ~ExternalSecurityHandler(); + + virtual void *makeAuthData(GString *ownerPassword, + GString *userPassword); + virtual void *getAuthData(); + virtual void freeAuthData(void *authData); + virtual GBool authorize(void *authData); + virtual int getPermissionFlags() { return permFlags; } + virtual GBool getOwnerPasswordOk() { return gFalse; } + virtual Guchar *getFileKey() { return fileKey; } + virtual int getFileKeyLength() { return fileKeyLength; } + virtual int getEncVersion() { return encVersion; } + virtual CryptAlgorithm getEncAlgorithm() { return encAlgorithm; } + +private: + + Object encryptDict; + XpdfSecurityHandler *xsh; + void *docData; + int permFlags; + Guchar fileKey[16]; + int fileKeyLength; + int encVersion; + CryptAlgorithm encAlgorithm; + GBool ok; +}; +#endif // ENABLE_PLUGINS + +#endif diff --git a/kpdf/xpdf/xpdf/SplashOutputDev.cc b/kpdf/xpdf/xpdf/SplashOutputDev.cc new file mode 100644 index 00000000..fe235fb8 --- /dev/null +++ b/kpdf/xpdf/xpdf/SplashOutputDev.cc @@ -0,0 +1,2851 @@ +//======================================================================== +// +// SplashOutputDev.cc +// +// Copyright 2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gfile.h" +#include "GlobalParams.h" +#include "Error.h" +#include "Object.h" +#include "GfxFont.h" +#include "Link.h" +#include "CharCodeToUnicode.h" +#include "FontEncodingTables.h" +#include "FoFiTrueType.h" +#include "SplashBitmap.h" +#include "SplashGlyphBitmap.h" +#include "SplashPattern.h" +#include "SplashScreen.h" +#include "SplashPath.h" +#include "SplashState.h" +#include "SplashErrorCodes.h" +#include "SplashFontEngine.h" +#include "SplashFont.h" +#include "SplashFontFile.h" +#include "SplashFontFileID.h" +#include "Splash.h" +#include "SplashOutputDev.h" + +#ifdef VMS +#if (__VMS_VER < 70000000) +extern "C" int unlink(char *filename); +#endif +#endif + +//------------------------------------------------------------------------ + +// Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result. +static inline Guchar div255(int x) { + return (Guchar)((x + (x >> 8) + 0x80) >> 8); +} + +//------------------------------------------------------------------------ +// Blend functions +//------------------------------------------------------------------------ + +static void splashOutBlendMultiply(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = (dest[i] * src[i]) / 255; + } +} + +static void splashOutBlendScreen(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = dest[i] + src[i] - (dest[i] * src[i]) / 255; + } +} + +static void splashOutBlendOverlay(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = dest[i] < 0x80 + ? (src[i] * 2 * dest[i]) / 255 + : 255 - 2 * ((255 - src[i]) * (255 - dest[i])) / 255; + } +} + +static void splashOutBlendDarken(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = dest[i] < src[i] ? dest[i] : src[i]; + } +} + +static void splashOutBlendLighten(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = dest[i] > src[i] ? dest[i] : src[i]; + } +} + +static void splashOutBlendColorDodge(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, + SplashColorMode cm) { + int i, x; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + if (src[i] == 255) { + blend[i] = 255; + } else { + x = (dest[i] * 255) / (255 - src[i]); + blend[i] = x <= 255 ? x : 255; + } + } +} + +static void splashOutBlendColorBurn(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i, x; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + if (src[i] == 0) { + blend[i] = 0; + } else { + x = ((255 - dest[i]) * 255) / src[i]; + blend[i] = x <= 255 ? 255 - x : 0; + } + } +} + +static void splashOutBlendHardLight(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = src[i] < 0x80 + ? (dest[i] * 2 * src[i]) / 255 + : 255 - 2 * ((255 - dest[i]) * (255 - src[i])) / 255; + } +} + +static void splashOutBlendSoftLight(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i, x; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + if (src[i] < 0x80) { + blend[i] = dest[i] - (255 - 2 * src[i]) * dest[i] * (255 - dest[i]) / + (255 * 255); + } else { + if (dest[i] < 0x40) { + x = (((((16 * dest[i] - 12 * 255) * dest[i]) / 255) + + 4 * 255) * dest[i]) / 255; + } else { + x = (int)sqrt(255.0 * dest[i]); + } + blend[i] = dest[i] + (2 * src[i] - 255) * (x - dest[i]) / 255; + } + } +} + +static void splashOutBlendDifference(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, + SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = dest[i] < src[i] ? src[i] - dest[i] : dest[i] - src[i]; + } +} + +static void splashOutBlendExclusion(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = dest[i] + src[i] - (2 * dest[i] * src[i]) / 255; + } +} + +static void cvtRGBToHSV(Guchar r, Guchar g, Guchar b, int *h, int *s, int *v) { + int cmax, cmid, cmin, x; + + if (r >= g) { + if (g >= b) { x = 0; cmax = r; cmid = g; cmin = b; } + else if (b >= r) { x = 4; cmax = b; cmid = r; cmin = g; } + else { x = 5; cmax = r; cmid = b; cmin = g; } + } else { + if (r >= b) { x = 1; cmax = g; cmid = r; cmin = b; } + else if (g >= b) { x = 2; cmax = g; cmid = b; cmin = r; } + else { x = 3; cmax = b; cmid = g; cmin = r; } + } + if (cmax == cmin) { + *h = *s = 0; + } else { + *h = x * 60; + if (x & 1) { + *h += ((cmax - cmid) * 60) / (cmax - cmin); + } else { + *h += ((cmid - cmin) * 60) / (cmax - cmin); + } + *s = (255 * (cmax - cmin)) / cmax; + } + *v = cmax; +} + +static void cvtHSVToRGB(int h, int s, int v, Guchar *r, Guchar *g, Guchar *b) { + int x, f, cmax, cmid, cmin; + + if (s == 0) { + *r = *g = *b = v; + } else { + x = h / 60; + f = h % 60; + cmax = v; + if (x & 1) { + cmid = div255(v * 255 - ((s * f) / 60)); + } else { + cmid = div255(v * (255 - ((s * (60 - f)) / 60))); + } + cmin = div255(v * (255 - s)); + switch (x) { + case 0: *r = cmax; *g = cmid; *b = cmin; break; + case 1: *g = cmax; *r = cmid; *b = cmin; break; + case 2: *g = cmax; *b = cmid; *r = cmin; break; + case 3: *b = cmax; *g = cmid; *r = cmin; break; + case 4: *b = cmax; *r = cmid; *g = cmin; break; + case 5: *r = cmax; *b = cmid; *g = cmin; break; + } + } +} + +static void splashOutBlendHue(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int hs, ss, vs, hd, sd, vd; +#if SPLASH_CMYK + Guchar r, g, b; +#endif + + switch (cm) { + case splashModeMono1: + case splashModeMono8: + blend[0] = dest[0]; + break; + case splashModeRGB8: + case splashModeBGR8: + cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs); + cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd); + cvtHSVToRGB(hs, sd, vd, &blend[0], &blend[1], &blend[2]); + break; +#if SPLASH_CMYK + case splashModeCMYK8: + //~ (0xff - ...) should be clipped + cvtRGBToHSV(0xff - (src[0] + src[3]), + 0xff - (src[1] + src[3]), + 0xff - (src[2] + src[3]), &hs, &ss, &vs); + cvtRGBToHSV(0xff - (dest[0] + dest[3]), + 0xff - (dest[1] + dest[3]), + 0xff - (dest[2] + dest[3]), &hd, &sd, &vd); + cvtHSVToRGB(hs, sd, vd, &r, &g, &b); + //~ should do black generation + blend[0] = 0xff - r; + blend[1] = 0xff - g; + blend[2] = 0xff - b; + blend[3] = 0; + break; +#endif + } +} + +static void splashOutBlendSaturation(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, + SplashColorMode cm) { + int hs, ss, vs, hd, sd, vd; +#if SPLASH_CMYK + Guchar r, g, b; +#endif + + switch (cm) { + case splashModeMono1: + case splashModeMono8: + blend[0] = dest[0]; + break; + case splashModeRGB8: + case splashModeBGR8: + cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs); + cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd); + cvtHSVToRGB(hd, ss, vd, &blend[0], &blend[1], &blend[2]); + break; +#if SPLASH_CMYK + case splashModeCMYK8: + //~ (0xff - ...) should be clipped + cvtRGBToHSV(0xff - (src[0] + src[3]), + 0xff - (src[1] + src[3]), + 0xff - (src[2] + src[3]), &hs, &ss, &vs); + cvtRGBToHSV(0xff - (dest[0] + dest[3]), + 0xff - (dest[1] + dest[3]), + 0xff - (dest[2] + dest[3]), &hd, &sd, &vd); + cvtHSVToRGB(hd, ss, vd, &r, &g, &b); + //~ should do black generation + blend[0] = 0xff - r; + blend[1] = 0xff - g; + blend[2] = 0xff - b; + blend[3] = 0; + break; +#endif + } +} + +static void splashOutBlendColor(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int hs, ss, vs, hd, sd, vd; +#if SPLASH_CMYK + Guchar r, g, b; +#endif + + switch (cm) { + case splashModeMono1: + case splashModeMono8: + blend[0] = dest[0]; + break; + case splashModeRGB8: + case splashModeBGR8: + cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs); + cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd); + cvtHSVToRGB(hs, ss, vd, &blend[0], &blend[1], &blend[2]); + break; +#if SPLASH_CMYK + case splashModeCMYK8: + //~ (0xff - ...) should be clipped + cvtRGBToHSV(0xff - (src[0] + src[3]), + 0xff - (src[1] + src[3]), + 0xff - (src[2] + src[3]), &hs, &ss, &vs); + cvtRGBToHSV(0xff - (dest[0] + dest[3]), + 0xff - (dest[1] + dest[3]), + 0xff - (dest[2] + dest[3]), &hd, &sd, &vd); + cvtHSVToRGB(hs, ss, vd, &r, &g, &b); + //~ should do black generation + blend[0] = 0xff - r; + blend[1] = 0xff - g; + blend[2] = 0xff - b; + blend[3] = 0; + break; +#endif + } +} + +static void splashOutBlendLuminosity(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, + SplashColorMode cm) { + int hs, ss, vs, hd, sd, vd; +#if SPLASH_CMYK + Guchar r, g, b; +#endif + + switch (cm) { + case splashModeMono1: + case splashModeMono8: + blend[0] = dest[0]; + break; + case splashModeRGB8: + case splashModeBGR8: + cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs); + cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd); + cvtHSVToRGB(hd, sd, vs, &blend[0], &blend[1], &blend[2]); + break; +#if SPLASH_CMYK + case splashModeCMYK8: + //~ (0xff - ...) should be clipped + cvtRGBToHSV(0xff - (src[0] + src[3]), + 0xff - (src[1] + src[3]), + 0xff - (src[2] + src[3]), &hs, &ss, &vs); + cvtRGBToHSV(0xff - (dest[0] + dest[3]), + 0xff - (dest[1] + dest[3]), + 0xff - (dest[2] + dest[3]), &hd, &sd, &vd); + cvtHSVToRGB(hd, sd, vs, &r, &g, &b); + //~ should do black generation + blend[0] = 0xff - r; + blend[1] = 0xff - g; + blend[2] = 0xff - b; + blend[3] = 0; + break; +#endif + } +} + +// NB: This must match the GfxBlendMode enum defined in GfxState.h. +SplashBlendFunc splashOutBlendFuncs[] = { + NULL, + &splashOutBlendMultiply, + &splashOutBlendScreen, + &splashOutBlendOverlay, + &splashOutBlendDarken, + &splashOutBlendLighten, + &splashOutBlendColorDodge, + &splashOutBlendColorBurn, + &splashOutBlendHardLight, + &splashOutBlendSoftLight, + &splashOutBlendDifference, + &splashOutBlendExclusion, + &splashOutBlendHue, + &splashOutBlendSaturation, + &splashOutBlendColor, + &splashOutBlendLuminosity +}; + +//------------------------------------------------------------------------ +// Font substitutions +//------------------------------------------------------------------------ + +struct SplashOutFontSubst { + char *name; + double mWidth; +}; + +// index: {symbolic:12, fixed:8, serif:4, sans-serif:0} + bold*2 + italic +static SplashOutFontSubst splashOutSubstFonts[16] = { + {"Helvetica", 0.833}, + {"Helvetica-Oblique", 0.833}, + {"Helvetica-Bold", 0.889}, + {"Helvetica-BoldOblique", 0.889}, + {"Times-Roman", 0.788}, + {"Times-Italic", 0.722}, + {"Times-Bold", 0.833}, + {"Times-BoldItalic", 0.778}, + {"Courier", 0.600}, + {"Courier-Oblique", 0.600}, + {"Courier-Bold", 0.600}, + {"Courier-BoldOblique", 0.600}, + {"Symbol", 0.576}, + {"Symbol", 0.576}, + {"Symbol", 0.576}, + {"Symbol", 0.576} +}; + +//------------------------------------------------------------------------ +// SplashOutFontFileID +//------------------------------------------------------------------------ + +class SplashOutFontFileID: public SplashFontFileID { +public: + + SplashOutFontFileID(Ref *rA) { r = *rA; substIdx = -1; } + + ~SplashOutFontFileID() {} + + GBool matches(SplashFontFileID *id) { + return ((SplashOutFontFileID *)id)->r.num == r.num && + ((SplashOutFontFileID *)id)->r.gen == r.gen; + } + + void setSubstIdx(int substIdxA) { substIdx = substIdxA; } + int getSubstIdx() { return substIdx; } + +private: + + Ref r; + int substIdx; +}; + +//------------------------------------------------------------------------ +// T3FontCache +//------------------------------------------------------------------------ + +struct T3FontCacheTag { + Gushort code; + Gushort mru; // valid bit (0x8000) and MRU index +}; + +class T3FontCache { +public: + + T3FontCache(Ref *fontID, double m11A, double m12A, + double m21A, double m22A, + int glyphXA, int glyphYA, int glyphWA, int glyphHA, + GBool aa, GBool validBBoxA); + ~T3FontCache(); + GBool matches(Ref *idA, double m11A, double m12A, + double m21A, double m22A) + { return fontID.num == idA->num && fontID.gen == idA->gen && + m11 == m11A && m12 == m12A && m21 == m21A && m22 == m22A; } + + Ref fontID; // PDF font ID + double m11, m12, m21, m22; // transform matrix + int glyphX, glyphY; // pixel offset of glyph bitmaps + int glyphW, glyphH; // size of glyph bitmaps, in pixels + GBool validBBox; // false if the bbox was [0 0 0 0] + int glyphSize; // size of glyph bitmaps, in bytes + int cacheSets; // number of sets in cache + int cacheAssoc; // cache associativity (glyphs per set) + Guchar *cacheData; // glyph pixmap cache + T3FontCacheTag *cacheTags; // cache tags, i.e., char codes +}; + +T3FontCache::T3FontCache(Ref *fontIDA, double m11A, double m12A, + double m21A, double m22A, + int glyphXA, int glyphYA, int glyphWA, int glyphHA, + GBool validBBoxA, GBool aa) { + int i; + + fontID = *fontIDA; + m11 = m11A; + m12 = m12A; + m21 = m21A; + m22 = m22A; + glyphX = glyphXA; + glyphY = glyphYA; + glyphW = glyphWA; + glyphH = glyphHA; + validBBox = validBBoxA; + if (aa) { + glyphSize = glyphW * glyphH; + } else { + glyphSize = ((glyphW + 7) >> 3) * glyphH; + } + cacheAssoc = 8; + if (glyphSize <= 256) { + cacheSets = 8; + } else if (glyphSize <= 512) { + cacheSets = 4; + } else if (glyphSize <= 1024) { + cacheSets = 2; + } else { + cacheSets = 1; + } + cacheData = (Guchar *)gmallocn_checkoverflow(cacheSets * cacheAssoc, glyphSize); + if (cacheData != NULL) + { + cacheTags = (T3FontCacheTag *)gmallocn(cacheSets * cacheAssoc, + sizeof(T3FontCacheTag)); + for (i = 0; i < cacheSets * cacheAssoc; ++i) { + cacheTags[i].mru = i & (cacheAssoc - 1); + } + } + else + { + cacheTags = NULL; + } +} + +T3FontCache::~T3FontCache() { + gfree(cacheData); + gfree(cacheTags); +} + +struct T3GlyphStack { + Gushort code; // character code + + //----- cache info + T3FontCache *cache; // font cache for the current font + T3FontCacheTag *cacheTag; // pointer to cache tag for the glyph + Guchar *cacheData; // pointer to cache data for the glyph + + //----- saved state + SplashBitmap *origBitmap; + Splash *origSplash; + double origCTM4, origCTM5; + + T3GlyphStack *next; // next object on stack +}; + +//------------------------------------------------------------------------ +// SplashTransparencyGroup +//------------------------------------------------------------------------ + +struct SplashTransparencyGroup { + int tx, ty; // translation coordinates + SplashBitmap *tBitmap; // bitmap for transparency group + GfxColorSpace *blendingColorSpace; + GBool isolated; + + //----- saved state + SplashBitmap *origBitmap; + Splash *origSplash; + + SplashTransparencyGroup *next; +}; + +//------------------------------------------------------------------------ +// SplashOutputDev +//------------------------------------------------------------------------ + +SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA, + int bitmapRowPadA, + GBool reverseVideoA, + SplashColorPtr paperColorA, + GBool bitmapTopDownA, + GBool allowAntialiasA) { + colorMode = colorModeA; + bitmapRowPad = bitmapRowPadA; + bitmapTopDown = bitmapTopDownA; + allowAntialias = allowAntialiasA; + vectorAntialias = allowAntialias && + globalParams->getVectorAntialias() && + colorMode != splashModeMono1; + setupScreenParams(72.0, 72.0); + reverseVideo = reverseVideoA; + splashColorCopy(paperColor, paperColorA); + + xref = NULL; + + bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode, + colorMode != splashModeMono1, bitmapTopDown); + splash = new Splash(bitmap, vectorAntialias, &screenParams); + splash->clear(paperColor, 0); + + fontEngine = NULL; + + nT3Fonts = 0; + t3GlyphStack = NULL; + + font = NULL; + needFontUpdate = gFalse; + textClipPath = NULL; + + transpGroupStack = NULL; +} + +void SplashOutputDev::setupScreenParams(double hDPI, double vDPI) { + screenParams.size = globalParams->getScreenSize(); + screenParams.dotRadius = globalParams->getScreenDotRadius(); + screenParams.gamma = (SplashCoord)globalParams->getScreenGamma(); + screenParams.blackThreshold = + (SplashCoord)globalParams->getScreenBlackThreshold(); + screenParams.whiteThreshold = + (SplashCoord)globalParams->getScreenWhiteThreshold(); + switch (globalParams->getScreenType()) { + case screenDispersed: + screenParams.type = splashScreenDispersed; + if (screenParams.size < 0) { + screenParams.size = 4; + } + break; + case screenClustered: + screenParams.type = splashScreenClustered; + if (screenParams.size < 0) { + screenParams.size = 10; + } + break; + case screenStochasticClustered: + screenParams.type = splashScreenStochasticClustered; + if (screenParams.size < 0) { + screenParams.size = 100; + } + if (screenParams.dotRadius < 0) { + screenParams.dotRadius = 2; + } + break; + case screenUnset: + default: + // use clustered dithering for resolution >= 300 dpi + // (compare to 299.9 to avoid floating point issues) + if (hDPI > 299.9 && vDPI > 299.9) { + screenParams.type = splashScreenStochasticClustered; + if (screenParams.size < 0) { + screenParams.size = 100; + } + if (screenParams.dotRadius < 0) { + screenParams.dotRadius = 2; + } + } else { + screenParams.type = splashScreenDispersed; + if (screenParams.size < 0) { + screenParams.size = 4; + } + } + } +} + +SplashOutputDev::~SplashOutputDev() { + int i; + + for (i = 0; i < nT3Fonts; ++i) { + delete t3FontCache[i]; + } + if (fontEngine) { + delete fontEngine; + } + if (splash) { + delete splash; + } + if (bitmap) { + delete bitmap; + } +} + +void SplashOutputDev::startDoc(XRef *xrefA) { + int i; + + xref = xrefA; + if (fontEngine) { + delete fontEngine; + } + fontEngine = new SplashFontEngine( +#if HAVE_T1LIB_H + globalParams->getEnableT1lib(), +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + globalParams->getEnableFreeType(), +#endif + allowAntialias && + globalParams->getAntialias() && + colorMode != splashModeMono1); + for (i = 0; i < nT3Fonts; ++i) { + delete t3FontCache[i]; + } + nT3Fonts = 0; +} + +void SplashOutputDev::startPage(int /*pageNum*/, GfxState *state) { + int w, h; + double *ctm; + SplashCoord mat[6]; + SplashColor color; + + if (state) { + setupScreenParams(state->getHDPI(), state->getVDPI()); + w = (int)(state->getPageWidth() + 0.5); + if (w <= 0) { + w = 1; + } + h = (int)(state->getPageHeight() + 0.5); + if (h <= 0) { + h = 1; + } + } else { + w = h = 1; + } + if (splash) { + delete splash; + } + if (!bitmap || w != bitmap->getWidth() || h != bitmap->getHeight()) { + if (bitmap) { + delete bitmap; + } + bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, + colorMode != splashModeMono1, bitmapTopDown); + } + splash = new Splash(bitmap, vectorAntialias, &screenParams); + if (state) { + ctm = state->getCTM(); + mat[0] = (SplashCoord)ctm[0]; + mat[1] = (SplashCoord)ctm[1]; + mat[2] = (SplashCoord)ctm[2]; + mat[3] = (SplashCoord)ctm[3]; + mat[4] = (SplashCoord)ctm[4]; + mat[5] = (SplashCoord)ctm[5]; + splash->setMatrix(mat); + } + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + color[0] = 0; + break; + case splashModeRGB8: + case splashModeBGR8: + color[0] = color[1] = color[2] = 0; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + color[0] = color[1] = color[2] = color[3] = 0; + break; +#endif + } + splash->setStrokePattern(new SplashSolidColor(color)); + splash->setFillPattern(new SplashSolidColor(color)); + splash->setLineCap(splashLineCapButt); + splash->setLineJoin(splashLineJoinMiter); + splash->setLineDash(NULL, 0, 0); + splash->setMiterLimit(10); + splash->setFlatness(1); + // the SA parameter supposedly defaults to false, but Acrobat + // apparently hardwires it to true + splash->setStrokeAdjust(globalParams->getStrokeAdjust()); + splash->clear(paperColor, 0); +} + +void SplashOutputDev::endPage() { + if (colorMode != splashModeMono1) { + splash->compositeBackground(paperColor); + } +} + +void SplashOutputDev::saveState(GfxState * /*state*/) { + splash->saveState(); +} + +void SplashOutputDev::restoreState(GfxState * /*state*/) { + splash->restoreState(); + needFontUpdate = gTrue; +} + +void SplashOutputDev::updateAll(GfxState *state) { + updateLineDash(state); + updateLineJoin(state); + updateLineCap(state); + updateLineWidth(state); + updateFlatness(state); + updateMiterLimit(state); + updateStrokeAdjust(state); + updateFillColor(state); + updateStrokeColor(state); + needFontUpdate = gTrue; +} + +void SplashOutputDev::updateCTM(GfxState *state, double /*m11*/, double /*m12*/, + double /*m21*/, double /*m22*/, + double /*m31*/, double /*m32*/) { + double *ctm; + SplashCoord mat[6]; + + ctm = state->getCTM(); + mat[0] = (SplashCoord)ctm[0]; + mat[1] = (SplashCoord)ctm[1]; + mat[2] = (SplashCoord)ctm[2]; + mat[3] = (SplashCoord)ctm[3]; + mat[4] = (SplashCoord)ctm[4]; + mat[5] = (SplashCoord)ctm[5]; + splash->setMatrix(mat); +} + +void SplashOutputDev::updateLineDash(GfxState *state) { + double *dashPattern; + int dashLength; + double dashStart; + SplashCoord dash[20]; + int i; + + state->getLineDash(&dashPattern, &dashLength, &dashStart); + if (dashLength > 20) { + dashLength = 20; + } + for (i = 0; i < dashLength; ++i) { + dash[i] = (SplashCoord)dashPattern[i]; + if (dash[i] < 0) { + dash[i] = 0; + } + } + splash->setLineDash(dash, dashLength, (SplashCoord)dashStart); +} + +void SplashOutputDev::updateFlatness(GfxState *state) { + splash->setFlatness(state->getFlatness()); +} + +void SplashOutputDev::updateLineJoin(GfxState *state) { + splash->setLineJoin(state->getLineJoin()); +} + +void SplashOutputDev::updateLineCap(GfxState *state) { + splash->setLineCap(state->getLineCap()); +} + +void SplashOutputDev::updateMiterLimit(GfxState *state) { + splash->setMiterLimit(state->getMiterLimit()); +} + +void SplashOutputDev::updateLineWidth(GfxState *state) { + splash->setLineWidth(state->getLineWidth()); +} + +void SplashOutputDev::updateStrokeAdjust(GfxState * /*state*/) { +#if 0 // the SA parameter supposedly defaults to false, but Acrobat + // apparently hardwires it to true + splash->setStrokeAdjust(state->getStrokeAdjust()); +#endif +} + +void SplashOutputDev::updateFillColor(GfxState *state) { + GfxGray gray; + GfxRGB rgb; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + + state->getFillGray(&gray); + state->getFillRGB(&rgb); +#if SPLASH_CMYK + state->getFillCMYK(&cmyk); + splash->setFillPattern(getColor(gray, &rgb, &cmyk)); +#else + splash->setFillPattern(getColor(gray, &rgb)); +#endif +} + +void SplashOutputDev::updateStrokeColor(GfxState *state) { + GfxGray gray; + GfxRGB rgb; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + + state->getStrokeGray(&gray); + state->getStrokeRGB(&rgb); +#if SPLASH_CMYK + state->getStrokeCMYK(&cmyk); + splash->setStrokePattern(getColor(gray, &rgb, &cmyk)); +#else + splash->setStrokePattern(getColor(gray, &rgb)); +#endif +} + +#if SPLASH_CMYK +SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb, + GfxCMYK *cmyk) { +#else +SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb) { +#endif + SplashPattern *pattern; + SplashColor color; + GfxColorComp r, g, b; + + if (reverseVideo) { + gray = gfxColorComp1 - gray; + r = gfxColorComp1 - rgb->r; + g = gfxColorComp1 - rgb->g; + b = gfxColorComp1 - rgb->b; + } else { + r = rgb->r; + g = rgb->g; + b = rgb->b; + } + + pattern = NULL; // make gcc happy + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + color[0] = colToByte(gray); + pattern = new SplashSolidColor(color); + break; + case splashModeRGB8: + case splashModeBGR8: + color[0] = colToByte(r); + color[1] = colToByte(g); + color[2] = colToByte(b); + pattern = new SplashSolidColor(color); + break; +#if SPLASH_CMYK + case splashModeCMYK8: + color[0] = colToByte(cmyk->c); + color[1] = colToByte(cmyk->m); + color[2] = colToByte(cmyk->y); + color[3] = colToByte(cmyk->k); + pattern = new SplashSolidColor(color); + break; +#endif + } + + return pattern; +} + +void SplashOutputDev::updateBlendMode(GfxState *state) { + splash->setBlendFunc(splashOutBlendFuncs[state->getBlendMode()]); +} + +void SplashOutputDev::updateFillOpacity(GfxState *state) { + splash->setFillAlpha((SplashCoord)state->getFillOpacity()); +} + +void SplashOutputDev::updateStrokeOpacity(GfxState *state) { + splash->setStrokeAlpha((SplashCoord)state->getStrokeOpacity()); +} + +void SplashOutputDev::updateFont(GfxState * /*state*/) { + needFontUpdate = gTrue; +} + +void SplashOutputDev::doUpdateFont(GfxState *state) { + GfxFont *gfxFont; + GfxFontType fontType; + SplashOutFontFileID *id; + SplashFontFile *fontFile; + SplashFontSrc *fontsrc = NULL; + FoFiTrueType *ff; + Ref embRef; + Object refObj, strObj; + GString *fileName, *substName; + char *tmpBuf; + int tmpBufLen; + Gushort *codeToGID; + DisplayFontParam *dfp; + CharCodeToUnicode *ctu; + double *textMat; + double m11, m12, m21, m22, w1, w2, fontSize; + SplashCoord mat[4]; + char *name; + Unicode uBuf[8]; + int substIdx, n, code, cmap; + int faceIndex = 0; + + needFontUpdate = gFalse; + font = NULL; + fileName = NULL; + tmpBuf = NULL; + substIdx = -1; + dfp = NULL; + + if (!(gfxFont = state->getFont())) { + goto err1; + } + fontType = gfxFont->getType(); + if (fontType == fontType3) { + goto err1; + } + + // check the font file cache + id = new SplashOutFontFileID(gfxFont->getID()); + if ((fontFile = fontEngine->getFontFile(id))) { + delete id; + + } else { + + // if there is an embedded font, write it to disk + if (gfxFont->getEmbeddedFontID(&embRef)) { + tmpBuf = gfxFont->readEmbFontFile(xref, &tmpBufLen); + if (! tmpBuf) + goto err2; + + // if there is an external font file, use it + } else if (!(fileName = gfxFont->getExtFontFile())) { + + // look for a display font mapping or a substitute font + if (gfxFont->isCIDFont()) { + if (((GfxCIDFont *)gfxFont)->getCollection()) { + dfp = globalParams-> + getDisplayCIDFont(gfxFont->getName(), + ((GfxCIDFont *)gfxFont)->getCollection()); + } + } else { + if (gfxFont->getName()) { + dfp = globalParams->getDisplayFont(gfxFont->getName()); + } + if (!dfp) { + // 8-bit font substitution + if (gfxFont->isFixedWidth()) { + substIdx = 8; + } else if (gfxFont->isSerif()) { + substIdx = 4; + } else { + substIdx = 0; + } + if (gfxFont->isBold()) { + substIdx += 2; + } + if (gfxFont->isItalic()) { + substIdx += 1; + } + substName = new GString(splashOutSubstFonts[substIdx].name); + dfp = globalParams->getDisplayFont(substName); + delete substName; + id->setSubstIdx(substIdx); + } + } + if (!dfp) { + error(-1, "Couldn't find a font for '%s'", + gfxFont->getName() ? gfxFont->getName()->getCString() + : "(unnamed)"); + goto err2; + } + switch (dfp->kind) { + case displayFontT1: + fileName = dfp->t1.fileName; + fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1; + break; + case displayFontTT: + fileName = dfp->tt.fileName; + fontType = gfxFont->isCIDFont() ? fontCIDType2 : fontTrueType; + faceIndex = dfp->tt.faceIndex; + break; + } + } + + fontsrc = new SplashFontSrc; + if (fileName) + fontsrc->setFile(fileName, gFalse); + else + fontsrc->setBuf(tmpBuf, tmpBufLen, gTrue); + + // load the font file + switch (fontType) { + case fontType1: + if (!(fontFile = fontEngine->loadType1Font( + id, + fontsrc, + ((Gfx8BitFont *)gfxFont)->getEncoding()))) { + error(-1, "Couldn't create a font for '%s'", + gfxFont->getName() ? gfxFont->getName()->getCString() + : "(unnamed)"); + goto err2; + } + break; + case fontType1C: + if (!(fontFile = fontEngine->loadType1CFont( + id, + fontsrc, + ((Gfx8BitFont *)gfxFont)->getEncoding()))) { + error(-1, "Couldn't create a font for '%s'", + gfxFont->getName() ? gfxFont->getName()->getCString() + : "(unnamed)"); + goto err2; + } + break; + case fontType1COT: + if (!(fontFile = fontEngine->loadOpenTypeT1CFont( + id, + fontsrc, + ((Gfx8BitFont *)gfxFont)->getEncoding()))) { + error(-1, "Couldn't create a font for '%s'", + gfxFont->getName() ? gfxFont->getName()->getCString() + : "(unnamed)"); + goto err2; + } + break; + case fontTrueType: + case fontTrueTypeOT: + if (fileName) + ff = FoFiTrueType::load(fileName->getCString()); + else + ff = FoFiTrueType::make(tmpBuf, tmpBufLen); + if (ff) { + codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff); + n = 256; + delete ff; + } else { + codeToGID = NULL; + n = 0; + } + if (!(fontFile = fontEngine->loadTrueTypeFont( + id, + fontsrc, + codeToGID, n))) { + error(-1, "Couldn't create a font for '%s'", + gfxFont->getName() ? gfxFont->getName()->getCString() + : "(unnamed)"); + goto err2; + } + break; + case fontCIDType0: + case fontCIDType0C: + if (!(fontFile = fontEngine->loadCIDFont( + id, + fontsrc))) { + error(-1, "Couldn't create a font for '%s'", + gfxFont->getName() ? gfxFont->getName()->getCString() + : "(unnamed)"); + goto err2; + } + break; + case fontCIDType0COT: + if (!(fontFile = fontEngine->loadOpenTypeCFFFont( + id, + fontsrc))) { + error(-1, "Couldn't create a font for '%s'", + gfxFont->getName() ? gfxFont->getName()->getCString() + : "(unnamed)"); + goto err2; + } + break; + case fontCIDType2: + case fontCIDType2OT: + codeToGID = NULL; + n = 0; + if (dfp) { + // create a CID-to-GID mapping, via Unicode + if ((ctu = ((GfxCIDFont *)gfxFont)->getToUnicode())) { + if (fileName) + ff = FoFiTrueType::load(fileName->getCString()); + else + ff = FoFiTrueType::make(tmpBuf, tmpBufLen); + if (ff) { + // look for a Unicode cmap + for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) { + if ((ff->getCmapPlatform(cmap) == 3 && + ff->getCmapEncoding(cmap) == 1) || + ff->getCmapPlatform(cmap) == 0) { + break; + } + } + if (cmap < ff->getNumCmaps()) { + // map CID -> Unicode -> GID + n = ctu->getLength(); + codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort)); + for (code = 0; code < n; ++code) { + if (ctu->mapToUnicode(code, uBuf, 8) > 0) { + codeToGID[code] = ff->mapCodeToGID(cmap, uBuf[0]); + } else { + codeToGID[code] = 0; + } + } + } + delete ff; + } + ctu->decRefCnt(); + } else { + error(-1, "Couldn't find a mapping to Unicode for font '%s'", + gfxFont->getName() ? gfxFont->getName()->getCString() + : "(unnamed)"); + } + } else { + if (((GfxCIDFont *)gfxFont)->getCIDToGID()) { + n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(); + codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort)); + memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), + n * sizeof(Gushort)); + } + } + if (!(fontFile = fontEngine->loadTrueTypeFont( + id, + fontsrc, + codeToGID, n, faceIndex))) { + error(-1, "Couldn't create a font for '%s'", + gfxFont->getName() ? gfxFont->getName()->getCString() + : "(unnamed)"); + goto err2; + } + break; + default: + // this shouldn't happen + goto err2; + } + } + + // get the font matrix + textMat = state->getTextMat(); + fontSize = state->getFontSize(); + m11 = textMat[0] * fontSize * state->getHorizScaling(); + m12 = textMat[1] * fontSize * state->getHorizScaling(); + m21 = textMat[2] * fontSize; + m22 = textMat[3] * fontSize; + + // for substituted fonts: adjust the font matrix -- compare the + // width of 'm' in the original font and the substituted font + substIdx = ((SplashOutFontFileID *)fontFile->getID())->getSubstIdx(); + if (substIdx >= 0) { + for (code = 0; code < 256; ++code) { + if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) && + name[0] == 'm' && name[1] == '\0') { + break; + } + } + if (code < 256) { + w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code); + w2 = splashOutSubstFonts[substIdx].mWidth; + if (!gfxFont->isSymbolic()) { + // if real font is substantially narrower than substituted + // font, reduce the font size accordingly + if (w1 > 0.01 && w1 < 0.9 * w2) { + w1 /= w2; + m11 *= w1; + m21 *= w1; + } + } + } + } + + // create the scaled font + mat[0] = m11; mat[1] = m12; + mat[2] = m21; mat[3] = m22; + font = fontEngine->getFont(fontFile, mat, splash->getMatrix()); + + if (fontsrc && !fontsrc->isFile) + fontsrc->unref(); + + return; + + err2: + delete id; + err1: + if (fontsrc && !fontsrc->isFile) + fontsrc->unref(); + return; +} + +void SplashOutputDev::stroke(GfxState *state) { + SplashPath *path; + + if (state->getStrokeColorSpace()->isNonMarking()) { + return; + } + path = convertPath(state, state->getPath()); + splash->stroke(path); + delete path; +} + +void SplashOutputDev::fill(GfxState *state) { + SplashPath *path; + + if (state->getFillColorSpace()->isNonMarking()) { + return; + } + path = convertPath(state, state->getPath()); + splash->fill(path, gFalse); + delete path; +} + +void SplashOutputDev::eoFill(GfxState *state) { + SplashPath *path; + + if (state->getFillColorSpace()->isNonMarking()) { + return; + } + path = convertPath(state, state->getPath()); + splash->fill(path, gTrue); + delete path; +} + +void SplashOutputDev::clip(GfxState *state) { + SplashPath *path; + + path = convertPath(state, state->getPath()); + splash->clipToPath(path, gFalse); + delete path; +} + +void SplashOutputDev::eoClip(GfxState *state) { + SplashPath *path; + + path = convertPath(state, state->getPath()); + splash->clipToPath(path, gTrue); + delete path; +} + +void SplashOutputDev::clipToStrokePath(GfxState *state) { + SplashPath *path, *path2; + + path = convertPath(state, state->getPath()); + path2 = splash->makeStrokePath(path); + delete path; + splash->clipToPath(path2, gFalse); + delete path2; +} + +SplashPath *SplashOutputDev::convertPath(GfxState * /*state*/, GfxPath *path) { + SplashPath *sPath; + GfxSubpath *subpath; + int i, j; + + sPath = new SplashPath(); + for (i = 0; i < path->getNumSubpaths(); ++i) { + subpath = path->getSubpath(i); + if (subpath->getNumPoints() > 0) { + sPath->moveTo((SplashCoord)subpath->getX(0), + (SplashCoord)subpath->getY(0)); + j = 1; + while (j < subpath->getNumPoints()) { + if (subpath->getCurve(j)) { + sPath->curveTo((SplashCoord)subpath->getX(j), + (SplashCoord)subpath->getY(j), + (SplashCoord)subpath->getX(j+1), + (SplashCoord)subpath->getY(j+1), + (SplashCoord)subpath->getX(j+2), + (SplashCoord)subpath->getY(j+2)); + j += 3; + } else { + sPath->lineTo((SplashCoord)subpath->getX(j), + (SplashCoord)subpath->getY(j)); + ++j; + } + } + if (subpath->isClosed()) { + sPath->close(); + } + } + } + return sPath; +} + +void SplashOutputDev::drawChar(GfxState *state, double x, double y, + double /*dx*/, double /*dy*/, + double originX, double originY, + CharCode code, int /*nBytes*/, + Unicode * /*u*/, int /*uLen*/) { + SplashPath *path; + int render; + + // check for invisible text -- this is used by Acrobat Capture + render = state->getRender(); + if (render == 3) { + return; + } + + if (needFontUpdate) { + doUpdateFont(state); + } + if (!font) { + return; + } + + x -= originX; + y -= originY; + + // fill + if (!(render & 1)) { + if (!state->getFillColorSpace()->isNonMarking()) { + splash->fillChar((SplashCoord)x, (SplashCoord)y, code, font); + } + } + + // stroke + if ((render & 3) == 1 || (render & 3) == 2) { + if (!state->getStrokeColorSpace()->isNonMarking()) { + if ((path = font->getGlyphPath(code))) { + path->offset((SplashCoord)x, (SplashCoord)y); + splash->stroke(path); + delete path; + } + } + } + + // clip + if (render & 4) { + if ((path = font->getGlyphPath(code))) { + path->offset((SplashCoord)x, (SplashCoord)y); + if (textClipPath) { + textClipPath->append(path); + delete path; + } else { + textClipPath = path; + } + } + } +} + +GBool SplashOutputDev::beginType3Char(GfxState *state, double /*x*/, double /*y*/, + double /*dx*/, double /*dy*/, + CharCode code, Unicode * /*u*/, int /*uLen*/) { + GfxFont *gfxFont; + Ref *fontID; + double *ctm, *bbox; + T3FontCache *t3Font; + T3GlyphStack *t3gs; + GBool validBBox; + double x1, y1, xMin, yMin, xMax, yMax, xt, yt; + int i, j; + + if (!(gfxFont = state->getFont())) { + return gFalse; + } + fontID = gfxFont->getID(); + ctm = state->getCTM(); + state->transform(0, 0, &xt, &yt); + + // is it the first (MRU) font in the cache? + if (!(nT3Fonts > 0 && + t3FontCache[0]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3]))) { + + // is the font elsewhere in the cache? + for (i = 1; i < nT3Fonts; ++i) { + if (t3FontCache[i]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3])) { + t3Font = t3FontCache[i]; + for (j = i; j > 0; --j) { + t3FontCache[j] = t3FontCache[j - 1]; + } + t3FontCache[0] = t3Font; + break; + } + } + if (i >= nT3Fonts) { + + // create new entry in the font cache + if (nT3Fonts == splashOutT3FontCacheSize) { + delete t3FontCache[nT3Fonts - 1]; + --nT3Fonts; + } + for (j = nT3Fonts; j > 0; --j) { + t3FontCache[j] = t3FontCache[j - 1]; + } + ++nT3Fonts; + bbox = gfxFont->getFontBBox(); + if (bbox[0] == 0 && bbox[1] == 0 && bbox[2] == 0 && bbox[3] == 0) { + // unspecified bounding box -- just take a guess + xMin = xt - 5; + xMax = xMin + 30; + yMax = yt + 15; + yMin = yMax - 45; + validBBox = gFalse; + } else { + state->transform(bbox[0], bbox[1], &x1, &y1); + xMin = xMax = x1; + yMin = yMax = y1; + state->transform(bbox[0], bbox[3], &x1, &y1); + if (x1 < xMin) { + xMin = x1; + } else if (x1 > xMax) { + xMax = x1; + } + if (y1 < yMin) { + yMin = y1; + } else if (y1 > yMax) { + yMax = y1; + } + state->transform(bbox[2], bbox[1], &x1, &y1); + if (x1 < xMin) { + xMin = x1; + } else if (x1 > xMax) { + xMax = x1; + } + if (y1 < yMin) { + yMin = y1; + } else if (y1 > yMax) { + yMax = y1; + } + state->transform(bbox[2], bbox[3], &x1, &y1); + if (x1 < xMin) { + xMin = x1; + } else if (x1 > xMax) { + xMax = x1; + } + if (y1 < yMin) { + yMin = y1; + } else if (y1 > yMax) { + yMax = y1; + } + validBBox = gTrue; + } + t3FontCache[0] = new T3FontCache(fontID, ctm[0], ctm[1], ctm[2], ctm[3], + (int)floor(xMin - xt), + (int)floor(yMin - yt), + (int)ceil(xMax) - (int)floor(xMin) + 3, + (int)ceil(yMax) - (int)floor(yMin) + 3, + validBBox, + colorMode != splashModeMono1); + } + } + t3Font = t3FontCache[0]; + + // is the glyph in the cache? + i = (code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc; + for (j = 0; j < t3Font->cacheAssoc; ++j) { + if (t3Font->cacheTags != NULL) { + if ((t3Font->cacheTags[i+j].mru & 0x8000) && + t3Font->cacheTags[i+j].code == code) { + drawType3Glyph(t3Font, &t3Font->cacheTags[i+j], + t3Font->cacheData + (i+j) * t3Font->glyphSize); + return gTrue; + } + } + } + + // push a new Type 3 glyph record + t3gs = new T3GlyphStack(); + t3gs->next = t3GlyphStack; + t3GlyphStack = t3gs; + t3GlyphStack->code = code; + t3GlyphStack->cache = t3Font; + t3GlyphStack->cacheTag = NULL; + t3GlyphStack->cacheData = NULL; + + return gFalse; +} + +void SplashOutputDev::endType3Char(GfxState *state) { + T3GlyphStack *t3gs; + double *ctm; + + if (t3GlyphStack->cacheTag) { + memcpy(t3GlyphStack->cacheData, bitmap->getDataPtr(), + t3GlyphStack->cache->glyphSize); + delete bitmap; + delete splash; + bitmap = t3GlyphStack->origBitmap; + splash = t3GlyphStack->origSplash; + ctm = state->getCTM(); + state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3], + t3GlyphStack->origCTM4, t3GlyphStack->origCTM5); + updateCTM(state, 0, 0, 0, 0, 0, 0); + drawType3Glyph(t3GlyphStack->cache, + t3GlyphStack->cacheTag, t3GlyphStack->cacheData); + } + t3gs = t3GlyphStack; + t3GlyphStack = t3gs->next; + delete t3gs; +} + +void SplashOutputDev::type3D0(GfxState * /*state*/, double /*wx*/, double /*wy*/) { +} + +void SplashOutputDev::type3D1(GfxState *state, double /*wx*/, double /*wy*/, + double llx, double lly, double urx, double ury) { + double *ctm; + T3FontCache *t3Font; + SplashColor color; + double xt, yt, xMin, xMax, yMin, yMax, x1, y1; + int i, j; + + t3Font = t3GlyphStack->cache; + + // check for a valid bbox + state->transform(0, 0, &xt, &yt); + state->transform(llx, lly, &x1, &y1); + xMin = xMax = x1; + yMin = yMax = y1; + state->transform(llx, ury, &x1, &y1); + if (x1 < xMin) { + xMin = x1; + } else if (x1 > xMax) { + xMax = x1; + } + if (y1 < yMin) { + yMin = y1; + } else if (y1 > yMax) { + yMax = y1; + } + state->transform(urx, lly, &x1, &y1); + if (x1 < xMin) { + xMin = x1; + } else if (x1 > xMax) { + xMax = x1; + } + if (y1 < yMin) { + yMin = y1; + } else if (y1 > yMax) { + yMax = y1; + } + state->transform(urx, ury, &x1, &y1); + if (x1 < xMin) { + xMin = x1; + } else if (x1 > xMax) { + xMax = x1; + } + if (y1 < yMin) { + yMin = y1; + } else if (y1 > yMax) { + yMax = y1; + } + if (xMin - xt < t3Font->glyphX || + yMin - yt < t3Font->glyphY || + xMax - xt > t3Font->glyphX + t3Font->glyphW || + yMax - yt > t3Font->glyphY + t3Font->glyphH) { + if (t3Font->validBBox) { + error(-1, "Bad bounding box in Type 3 glyph"); + } + return; + } + + // allocate a cache entry + i = (t3GlyphStack->code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc; + for (j = 0; j < t3Font->cacheAssoc; ++j) { + if ((t3Font->cacheTags[i+j].mru & 0x7fff) == t3Font->cacheAssoc - 1) { + t3Font->cacheTags[i+j].mru = 0x8000; + t3Font->cacheTags[i+j].code = t3GlyphStack->code; + t3GlyphStack->cacheTag = &t3Font->cacheTags[i+j]; + t3GlyphStack->cacheData = t3Font->cacheData + (i+j) * t3Font->glyphSize; + } else { + ++t3Font->cacheTags[i+j].mru; + } + } + + // save state + t3GlyphStack->origBitmap = bitmap; + t3GlyphStack->origSplash = splash; + ctm = state->getCTM(); + t3GlyphStack->origCTM4 = ctm[4]; + t3GlyphStack->origCTM5 = ctm[5]; + + // create the temporary bitmap + if (colorMode == splashModeMono1) { + bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1, + splashModeMono1, gFalse); + splash = new Splash(bitmap, gFalse, + t3GlyphStack->origSplash->getScreen()); + color[0] = 0; + splash->clear(color); + color[0] = 1; + } else { + bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1, + splashModeMono8, gFalse); + splash = new Splash(bitmap, vectorAntialias, + t3GlyphStack->origSplash->getScreen()); + color[0] = 0x00; + splash->clear(color); + color[0] = 0xff; + } + splash->setFillPattern(new SplashSolidColor(color)); + splash->setStrokePattern(new SplashSolidColor(color)); + //~ this should copy other state from t3GlyphStack->origSplash? + state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3], + -t3Font->glyphX, -t3Font->glyphY); + updateCTM(state, 0, 0, 0, 0, 0, 0); +} + +void SplashOutputDev::drawType3Glyph(T3FontCache *t3Font, + T3FontCacheTag * /*tag*/, Guchar *data) { + SplashGlyphBitmap glyph; + + glyph.x = -t3Font->glyphX; + glyph.y = -t3Font->glyphY; + glyph.w = t3Font->glyphW; + glyph.h = t3Font->glyphH; + glyph.aa = colorMode != splashModeMono1; + glyph.data = data; + glyph.freeData = gFalse; + splash->fillGlyph(0, 0, &glyph); +} + +void SplashOutputDev::endTextObject(GfxState * /*state*/) { + if (textClipPath) { + splash->clipToPath(textClipPath, gFalse); + delete textClipPath; + textClipPath = NULL; + } +} + +struct SplashOutImageMaskData { + ImageStream *imgStr; + GBool invert; + int width, height, y; +}; + +GBool SplashOutputDev::imageMaskSrc(void *data, SplashColorPtr line) { + SplashOutImageMaskData *imgMaskData = (SplashOutImageMaskData *)data; + Guchar *p; + SplashColorPtr q; + int x; + + if (imgMaskData->y == imgMaskData->height) { + return gFalse; + } + for (x = 0, p = imgMaskData->imgStr->getLine(), q = line; + x < imgMaskData->width; + ++x) { + *q++ = *p++ ^ imgMaskData->invert; + } + ++imgMaskData->y; + return gTrue; +} + +void SplashOutputDev::drawImageMask(GfxState *state, Object * /*ref*/, Stream *str, + int width, int height, GBool invert, + GBool inlineImg) { + double *ctm; + SplashCoord mat[6]; + SplashOutImageMaskData imgMaskData; + + if (state->getFillColorSpace()->isNonMarking()) { + return; + } + + ctm = state->getCTM(); + mat[0] = ctm[0]; + mat[1] = ctm[1]; + mat[2] = -ctm[2]; + mat[3] = -ctm[3]; + mat[4] = ctm[2] + ctm[4]; + mat[5] = ctm[3] + ctm[5]; + + imgMaskData.imgStr = new ImageStream(str, width, 1, 1); + imgMaskData.imgStr->reset(); + imgMaskData.invert = invert ? 0 : 1; + imgMaskData.width = width; + imgMaskData.height = height; + imgMaskData.y = 0; + + splash->fillImageMask(&imageMaskSrc, &imgMaskData, width, height, mat, + t3GlyphStack != NULL); + if (inlineImg) { + while (imgMaskData.y < height) { + imgMaskData.imgStr->getLine(); + ++imgMaskData.y; + } + } + + delete imgMaskData.imgStr; + str->close(); +} + +struct SplashOutImageData { + ImageStream *imgStr; + GfxImageColorMap *colorMap; + SplashColorPtr lookup; + int *maskColors; + SplashColorMode colorMode; + int width, height, y; +}; + +GBool SplashOutputDev::imageSrc(void *data, SplashColorPtr colorLine, + Guchar * /*alphaLine*/) { + SplashOutImageData *imgData = (SplashOutImageData *)data; + Guchar *p; + SplashColorPtr q, col; + GfxRGB rgb; + GfxGray gray; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + int nComps, x; + + if (imgData->y == imgData->height) { + return gFalse; + } + + nComps = imgData->colorMap->getNumPixelComps(); + + if (imgData->lookup) { + switch (imgData->colorMode) { + case splashModeMono1: + case splashModeMono8: + for (x = 0, p = imgData->imgStr->getLine(), q = colorLine; + x < imgData->width; + ++x, ++p) { + *q++ = imgData->lookup[*p]; + } + break; + case splashModeRGB8: + case splashModeBGR8: + for (x = 0, p = imgData->imgStr->getLine(), q = colorLine; + x < imgData->width; + ++x, ++p) { + col = &imgData->lookup[3 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + for (x = 0, p = imgData->imgStr->getLine(), q = colorLine; + x < imgData->width; + ++x, ++p) { + col = &imgData->lookup[4 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + *q++ = col[3]; + } + break; +#endif + } + } else { + switch (imgData->colorMode) { + case splashModeMono1: + case splashModeMono8: + for (x = 0, p = imgData->imgStr->getLine(), q = colorLine; + x < imgData->width; + ++x, p += nComps) { + imgData->colorMap->getGray(p, &gray); + *q++ = colToByte(gray); + } + break; + case splashModeRGB8: + case splashModeBGR8: + for (x = 0, p = imgData->imgStr->getLine(), q = colorLine; + x < imgData->width; + ++x, p += nComps) { + imgData->colorMap->getRGB(p, &rgb); + *q++ = colToByte(rgb.r); + *q++ = colToByte(rgb.g); + *q++ = colToByte(rgb.b); + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + for (x = 0, p = imgData->imgStr->getLine(), q = colorLine; + x < imgData->width; + ++x, p += nComps) { + imgData->colorMap->getCMYK(p, &cmyk); + *q++ = colToByte(cmyk.c); + *q++ = colToByte(cmyk.m); + *q++ = colToByte(cmyk.y); + *q++ = colToByte(cmyk.k); + } + break; +#endif + } + } + + ++imgData->y; + return gTrue; +} + +GBool SplashOutputDev::alphaImageSrc(void *data, SplashColorPtr colorLine, + Guchar *alphaLine) { + SplashOutImageData *imgData = (SplashOutImageData *)data; + Guchar *p, *aq; + SplashColorPtr q, col; + GfxRGB rgb; + GfxGray gray; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + Guchar alpha; + int nComps, x, i; + + if (imgData->y == imgData->height) { + return gFalse; + } + + nComps = imgData->colorMap->getNumPixelComps(); + + for (x = 0, p = imgData->imgStr->getLine(), q = colorLine, aq = alphaLine; + x < imgData->width; + ++x, p += nComps) { + alpha = 0; + for (i = 0; i < nComps; ++i) { + if (p[i] < imgData->maskColors[2*i] || + p[i] > imgData->maskColors[2*i+1]) { + alpha = 0xff; + break; + } + } + if (imgData->lookup) { + switch (imgData->colorMode) { + case splashModeMono1: + case splashModeMono8: + *q++ = imgData->lookup[*p]; + *aq++ = alpha; + break; + case splashModeRGB8: + case splashModeBGR8: + col = &imgData->lookup[3 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + *aq++ = alpha; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + col = &imgData->lookup[4 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + *q++ = col[3]; + *aq++ = alpha; + break; +#endif + } + } else { + switch (imgData->colorMode) { + case splashModeMono1: + case splashModeMono8: + imgData->colorMap->getGray(p, &gray); + *q++ = colToByte(gray); + *aq++ = alpha; + break; + case splashModeRGB8: + case splashModeBGR8: + imgData->colorMap->getRGB(p, &rgb); + *q++ = colToByte(rgb.r); + *q++ = colToByte(rgb.g); + *q++ = colToByte(rgb.b); + *aq++ = alpha; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + imgData->colorMap->getCMYK(p, &cmyk); + *q++ = colToByte(cmyk.c); + *q++ = colToByte(cmyk.m); + *q++ = colToByte(cmyk.y); + *q++ = colToByte(cmyk.k); + *aq++ = alpha; + break; +#endif + } + } + } + + ++imgData->y; + return gTrue; +} + +void SplashOutputDev::drawImage(GfxState *state, Object * /*ref*/, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + int *maskColors, GBool inlineImg) { + double *ctm; + SplashCoord mat[6]; + SplashOutImageData imgData; + SplashColorMode srcMode; + SplashImageSource src; + GfxGray gray; + GfxRGB rgb; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + Guchar pix; + int n, i; + + ctm = state->getCTM(); + mat[0] = ctm[0]; + mat[1] = ctm[1]; + mat[2] = -ctm[2]; + mat[3] = -ctm[3]; + mat[4] = ctm[2] + ctm[4]; + mat[5] = ctm[3] + ctm[5]; + + imgData.imgStr = new ImageStream(str, width, + colorMap->getNumPixelComps(), + colorMap->getBits()); + imgData.imgStr->reset(); + imgData.colorMap = colorMap; + imgData.maskColors = maskColors; + imgData.colorMode = colorMode; + imgData.width = width; + imgData.height = height; + imgData.y = 0; + + // special case for one-channel (monochrome/gray/separation) images: + // build a lookup table here + imgData.lookup = NULL; + if (colorMap->getNumPixelComps() == 1) { + n = 1 << colorMap->getBits(); + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + imgData.lookup = (SplashColorPtr)gmalloc(n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getGray(&pix, &gray); + imgData.lookup[i] = colToByte(gray); + } + break; + case splashModeRGB8: + case splashModeBGR8: + imgData.lookup = (SplashColorPtr)gmalloc(3 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getRGB(&pix, &rgb); + imgData.lookup[3*i] = colToByte(rgb.r); + imgData.lookup[3*i+1] = colToByte(rgb.g); + imgData.lookup[3*i+2] = colToByte(rgb.b); + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + imgData.lookup = (SplashColorPtr)gmalloc(4 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getCMYK(&pix, &cmyk); + imgData.lookup[4*i] = colToByte(cmyk.c); + imgData.lookup[4*i+1] = colToByte(cmyk.m); + imgData.lookup[4*i+2] = colToByte(cmyk.y); + imgData.lookup[4*i+3] = colToByte(cmyk.k); + } + break; +#endif + break; + } + } + + if (colorMode == splashModeMono1) { + srcMode = splashModeMono8; + } else { + srcMode = colorMode; + } + src = maskColors ? &alphaImageSrc : &imageSrc; + splash->drawImage(src, &imgData, srcMode, maskColors ? gTrue : gFalse, + width, height, mat); + if (inlineImg) { + while (imgData.y < height) { + imgData.imgStr->getLine(); + ++imgData.y; + } + } + + gfree(imgData.lookup); + delete imgData.imgStr; + str->close(); +} + +struct SplashOutMaskedImageData { + ImageStream *imgStr; + GfxImageColorMap *colorMap; + SplashBitmap *mask; + SplashColorPtr lookup; + SplashColorMode colorMode; + int width, height, y; +}; + +GBool SplashOutputDev::maskedImageSrc(void *data, SplashColorPtr colorLine, + Guchar *alphaLine) { + SplashOutMaskedImageData *imgData = (SplashOutMaskedImageData *)data; + Guchar *p, *aq; + SplashColor maskColor; + SplashColorPtr q, col; + GfxRGB rgb; + GfxGray gray; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + Guchar alpha; + int nComps, x; + + if (imgData->y == imgData->height) { + return gFalse; + } + + nComps = imgData->colorMap->getNumPixelComps(); + + for (x = 0, p = imgData->imgStr->getLine(), q = colorLine, aq = alphaLine; + x < imgData->width; + ++x, p += nComps) { + imgData->mask->getPixel(x, imgData->y, maskColor); + alpha = maskColor[0] ? 0xff : 0x00; + if (imgData->lookup) { + switch (imgData->colorMode) { + case splashModeMono1: + case splashModeMono8: + *q++ = imgData->lookup[*p]; + *aq++ = alpha; + break; + case splashModeRGB8: + case splashModeBGR8: + col = &imgData->lookup[3 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + *aq++ = alpha; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + col = &imgData->lookup[4 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + *q++ = col[3]; + *aq++ = alpha; + break; +#endif + } + } else { + switch (imgData->colorMode) { + case splashModeMono1: + case splashModeMono8: + imgData->colorMap->getGray(p, &gray); + *q++ = colToByte(gray); + *aq++ = alpha; + break; + case splashModeRGB8: + case splashModeBGR8: + imgData->colorMap->getRGB(p, &rgb); + *q++ = colToByte(rgb.r); + *q++ = colToByte(rgb.g); + *q++ = colToByte(rgb.b); + *aq++ = alpha; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + imgData->colorMap->getCMYK(p, &cmyk); + *q++ = colToByte(cmyk.c); + *q++ = colToByte(cmyk.m); + *q++ = colToByte(cmyk.y); + *q++ = colToByte(cmyk.k); + *aq++ = alpha; + break; +#endif + } + } + } + + ++imgData->y; + return gTrue; +} + +void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref, + Stream *str, int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, int maskWidth, + int maskHeight, GBool maskInvert) { + GfxImageColorMap *maskColorMap; + Object maskDecode, decodeLow, decodeHigh; + double *ctm; + SplashCoord mat[6]; + SplashOutMaskedImageData imgData; + SplashOutImageMaskData imgMaskData; + SplashColorMode srcMode; + SplashBitmap *maskBitmap; + Splash *maskSplash; + SplashColor maskColor; + GfxGray gray; + GfxRGB rgb; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + Guchar pix; + int n, i; + + // If the mask is higher resolution than the image, use + // drawSoftMaskedImage() instead. + if (maskWidth > width || maskHeight > height) { + decodeLow.initInt(maskInvert ? 0 : 1); + decodeHigh.initInt(maskInvert ? 1 : 0); + maskDecode.initArray(xref); + maskDecode.arrayAdd(&decodeLow); + maskDecode.arrayAdd(&decodeHigh); + maskColorMap = new GfxImageColorMap(1, &maskDecode, + new GfxDeviceGrayColorSpace()); + maskDecode.free(); + drawSoftMaskedImage(state, ref, str, width, height, colorMap, + maskStr, maskWidth, maskHeight, maskColorMap); + delete maskColorMap; + + } else { + + //----- scale the mask image to the same size as the source image + + mat[0] = (SplashCoord)width; + mat[1] = 0; + mat[2] = 0; + mat[3] = (SplashCoord)height; + mat[4] = 0; + mat[5] = 0; + imgMaskData.imgStr = new ImageStream(maskStr, maskWidth, 1, 1); + imgMaskData.imgStr->reset(); + imgMaskData.invert = maskInvert ? 0 : 1; + imgMaskData.width = maskWidth; + imgMaskData.height = maskHeight; + imgMaskData.y = 0; + maskBitmap = new SplashBitmap(width, height, 1, splashModeMono1, gFalse); + maskSplash = new Splash(maskBitmap, gFalse); + maskColor[0] = 0; + maskSplash->clear(maskColor); + maskColor[0] = 0xff; + maskSplash->setFillPattern(new SplashSolidColor(maskColor)); + maskSplash->fillImageMask(&imageMaskSrc, &imgMaskData, + maskWidth, maskHeight, mat, gFalse); + delete imgMaskData.imgStr; + maskStr->close(); + delete maskSplash; + + //----- draw the source image + + ctm = state->getCTM(); + mat[0] = ctm[0]; + mat[1] = ctm[1]; + mat[2] = -ctm[2]; + mat[3] = -ctm[3]; + mat[4] = ctm[2] + ctm[4]; + mat[5] = ctm[3] + ctm[5]; + + imgData.imgStr = new ImageStream(str, width, + colorMap->getNumPixelComps(), + colorMap->getBits()); + imgData.imgStr->reset(); + imgData.colorMap = colorMap; + imgData.mask = maskBitmap; + imgData.colorMode = colorMode; + imgData.width = width; + imgData.height = height; + imgData.y = 0; + + // special case for one-channel (monochrome/gray/separation) images: + // build a lookup table here + imgData.lookup = NULL; + if (colorMap->getNumPixelComps() == 1) { + n = 1 << colorMap->getBits(); + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + imgData.lookup = (SplashColorPtr)gmalloc(n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getGray(&pix, &gray); + imgData.lookup[i] = colToByte(gray); + } + break; + case splashModeRGB8: + case splashModeBGR8: + imgData.lookup = (SplashColorPtr)gmalloc(3 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getRGB(&pix, &rgb); + imgData.lookup[3*i] = colToByte(rgb.r); + imgData.lookup[3*i+1] = colToByte(rgb.g); + imgData.lookup[3*i+2] = colToByte(rgb.b); + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + imgData.lookup = (SplashColorPtr)gmalloc(4 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getCMYK(&pix, &cmyk); + imgData.lookup[4*i] = colToByte(cmyk.c); + imgData.lookup[4*i+1] = colToByte(cmyk.m); + imgData.lookup[4*i+2] = colToByte(cmyk.y); + imgData.lookup[4*i+3] = colToByte(cmyk.k); + } + break; +#endif + } + } + + if (colorMode == splashModeMono1) { + srcMode = splashModeMono8; + } else { + srcMode = colorMode; + } + splash->drawImage(&maskedImageSrc, &imgData, srcMode, gTrue, + width, height, mat); + + delete maskBitmap; + gfree(imgData.lookup); + delete imgData.imgStr; + str->close(); + } +} + +void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object * /*ref*/, + Stream *str, int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GfxImageColorMap *maskColorMap) { + double *ctm; + SplashCoord mat[6]; + SplashOutImageData imgData; + SplashOutImageData imgMaskData; + SplashColorMode srcMode; + SplashBitmap *maskBitmap; + Splash *maskSplash; + SplashColor maskColor; + GfxGray gray; + GfxRGB rgb; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + Guchar pix; + int n, i; + + ctm = state->getCTM(); + mat[0] = ctm[0]; + mat[1] = ctm[1]; + mat[2] = -ctm[2]; + mat[3] = -ctm[3]; + mat[4] = ctm[2] + ctm[4]; + mat[5] = ctm[3] + ctm[5]; + + //----- set up the soft mask + + imgMaskData.imgStr = new ImageStream(maskStr, maskWidth, + maskColorMap->getNumPixelComps(), + maskColorMap->getBits()); + imgMaskData.imgStr->reset(); + imgMaskData.colorMap = maskColorMap; + imgMaskData.maskColors = NULL; + imgMaskData.colorMode = splashModeMono8; + imgMaskData.width = maskWidth; + imgMaskData.height = maskHeight; + imgMaskData.y = 0; + n = 1 << maskColorMap->getBits(); + imgMaskData.lookup = (SplashColorPtr)gmalloc(n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + maskColorMap->getGray(&pix, &gray); + imgMaskData.lookup[i] = colToByte(gray); + } + maskBitmap = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(), + 1, splashModeMono8, gFalse); + maskSplash = new Splash(maskBitmap, vectorAntialias); + maskColor[0] = 0; + maskSplash->clear(maskColor); + maskSplash->drawImage(&imageSrc, &imgMaskData, splashModeMono8, gFalse, + maskWidth, maskHeight, mat); + delete imgMaskData.imgStr; + maskStr->close(); + gfree(imgMaskData.lookup); + delete maskSplash; + splash->setSoftMask(maskBitmap); + + //----- draw the source image + + imgData.imgStr = new ImageStream(str, width, + colorMap->getNumPixelComps(), + colorMap->getBits()); + imgData.imgStr->reset(); + imgData.colorMap = colorMap; + imgData.maskColors = NULL; + imgData.colorMode = colorMode; + imgData.width = width; + imgData.height = height; + imgData.y = 0; + + // special case for one-channel (monochrome/gray/separation) images: + // build a lookup table here + imgData.lookup = NULL; + if (colorMap->getNumPixelComps() == 1) { + n = 1 << colorMap->getBits(); + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + imgData.lookup = (SplashColorPtr)gmalloc(n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getGray(&pix, &gray); + imgData.lookup[i] = colToByte(gray); + } + break; + case splashModeRGB8: + case splashModeBGR8: + imgData.lookup = (SplashColorPtr)gmalloc(3 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getRGB(&pix, &rgb); + imgData.lookup[3*i] = colToByte(rgb.r); + imgData.lookup[3*i+1] = colToByte(rgb.g); + imgData.lookup[3*i+2] = colToByte(rgb.b); + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + imgData.lookup = (SplashColorPtr)gmalloc(4 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getCMYK(&pix, &cmyk); + imgData.lookup[4*i] = colToByte(cmyk.c); + imgData.lookup[4*i+1] = colToByte(cmyk.m); + imgData.lookup[4*i+2] = colToByte(cmyk.y); + imgData.lookup[4*i+3] = colToByte(cmyk.k); + } + break; +#endif + } + } + + if (colorMode == splashModeMono1) { + srcMode = splashModeMono8; + } else { + srcMode = colorMode; + } + splash->drawImage(&imageSrc, &imgData, srcMode, gFalse, width, height, mat); + + splash->setSoftMask(NULL); + gfree(imgData.lookup); + delete imgData.imgStr; + str->close(); +} + +void SplashOutputDev::beginTransparencyGroup(GfxState *state, double *bbox, + GfxColorSpace *blendingColorSpace, + GBool isolated, GBool /*knockout*/, + GBool /*forSoftMask*/) { + SplashTransparencyGroup *transpGroup; + SplashColor color; + double xMin, yMin, xMax, yMax, x, y; + int tx, ty, w, h; + + // transform the bbox + state->transform(bbox[0], bbox[1], &x, &y); + xMin = xMax = x; + yMin = yMax = y; + state->transform(bbox[0], bbox[3], &x, &y); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + state->transform(bbox[2], bbox[1], &x, &y); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + state->transform(bbox[2], bbox[3], &x, &y); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + tx = (int)floor(xMin); + if (tx < 0) { + tx = 0; + } else if (tx > bitmap->getWidth()) { + tx = bitmap->getWidth(); + } + ty = (int)floor(yMin); + if (ty < 0) { + ty = 0; + } else if (ty > bitmap->getHeight()) { + ty = bitmap->getHeight(); + } + w = (int)ceil(xMax) - tx + 1; + if (tx + w > bitmap->getWidth()) { + w = bitmap->getWidth() - tx; + } + if (w < 1) { + w = 1; + } + h = (int)ceil(yMax) - ty + 1; + if (ty + h > bitmap->getHeight()) { + h = bitmap->getHeight() - ty; + } + if (h < 1) { + h = 1; + } + + // push a new stack entry + transpGroup = new SplashTransparencyGroup(); + transpGroup->tx = tx; + transpGroup->ty = ty; + transpGroup->blendingColorSpace = blendingColorSpace; + transpGroup->isolated = isolated; + transpGroup->next = transpGroupStack; + transpGroupStack = transpGroup; + + // save state + transpGroup->origBitmap = bitmap; + transpGroup->origSplash = splash; + + //~ this ignores the blendingColorSpace arg + + // create the temporary bitmap + bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, gTrue, + bitmapTopDown); + splash = new Splash(bitmap, vectorAntialias, + transpGroup->origSplash->getScreen()); + if (isolated) { + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + color[0] = 0; + break; + case splashModeRGB8: + case splashModeBGR8: + color[0] = color[1] = color[2] = 0; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + color[0] = color[1] = color[2] = color[3] = 0; + break; +#endif + default: + // make gcc happy + break; + } + splash->clear(color, 0); + } else { + splash->blitTransparent(transpGroup->origBitmap, tx, ty, 0, 0, w, h); + splash->setInNonIsolatedGroup(transpGroup->origBitmap, tx, ty); + } + transpGroup->tBitmap = bitmap; + state->shiftCTM(-tx, -ty); + updateCTM(state, 0, 0, 0, 0, 0, 0); +} + +void SplashOutputDev::endTransparencyGroup(GfxState *state) { + double *ctm; + + // restore state + delete splash; + bitmap = transpGroupStack->origBitmap; + splash = transpGroupStack->origSplash; + ctm = state->getCTM(); + state->shiftCTM(transpGroupStack->tx, transpGroupStack->ty); + updateCTM(state, 0, 0, 0, 0, 0, 0); +} + +void SplashOutputDev::paintTransparencyGroup(GfxState * /*state*/, double * /*bbox*/) { + SplashBitmap *tBitmap; + SplashTransparencyGroup *transpGroup; + GBool isolated; + int tx, ty; + + tx = transpGroupStack->tx; + ty = transpGroupStack->ty; + tBitmap = transpGroupStack->tBitmap; + isolated = transpGroupStack->isolated; + + // paint the transparency group onto the parent bitmap + // - the clip path was set in the parent's state) + splash->composite(tBitmap, 0, 0, tx, ty, + tBitmap->getWidth(), tBitmap->getHeight(), + gFalse, !isolated); + + // pop the stack + transpGroup = transpGroupStack; + transpGroupStack = transpGroup->next; + delete transpGroup; + + delete tBitmap; +} + +void SplashOutputDev::setSoftMask(GfxState * /*state*/, double * /*bbox*/, + GBool alpha, Function *transferFunc, + GfxColor *backdropColor) { + SplashBitmap *softMask, *tBitmap; + Splash *tSplash; + SplashTransparencyGroup *transpGroup; + SplashColor color; + SplashColorPtr p; + GfxGray gray; + GfxRGB rgb; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + double lum, lum2; + int tx, ty, x, y; + + tx = transpGroupStack->tx; + ty = transpGroupStack->ty; + tBitmap = transpGroupStack->tBitmap; + + // composite with backdrop color + if (!alpha && colorMode != splashModeMono1) { + //~ need to correctly handle the case where no blending color + //~ space is given + tSplash = new Splash(tBitmap, vectorAntialias, + transpGroupStack->origSplash->getScreen()); + if (transpGroupStack->blendingColorSpace) { + switch (colorMode) { + case splashModeMono1: + // transparency is not supported in mono1 mode + break; + case splashModeMono8: + transpGroupStack->blendingColorSpace->getGray(backdropColor, &gray); + color[0] = colToByte(gray); + tSplash->compositeBackground(color); + break; + case splashModeRGB8: + case splashModeBGR8: + transpGroupStack->blendingColorSpace->getRGB(backdropColor, &rgb); + color[0] = colToByte(rgb.r); + color[1] = colToByte(rgb.g); + color[2] = colToByte(rgb.b); + tSplash->compositeBackground(color); + break; +#if SPLASH_CMYK + case splashModeCMYK8: + transpGroupStack->blendingColorSpace->getCMYK(backdropColor, &cmyk); + color[0] = colToByte(cmyk.c); + color[1] = colToByte(cmyk.m); + color[2] = colToByte(cmyk.y); + color[3] = colToByte(cmyk.k); + tSplash->compositeBackground(color); + break; +#endif + } + delete tSplash; + } + } + + softMask = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(), + 1, splashModeMono8, gFalse); + memset(softMask->getDataPtr(), 0, + softMask->getRowSize() * softMask->getHeight()); + p = softMask->getDataPtr() + ty * softMask->getRowSize() + tx; + int xMax = tBitmap->getWidth(); + int yMax = tBitmap->getHeight(); + if (xMax + tx > bitmap->getWidth()) xMax = bitmap->getWidth() - tx; + if (yMax + ty > bitmap->getHeight()) yMax = bitmap->getHeight() - ty; + for (y = 0; y < yMax; ++y) { + for (x = 0; x < xMax; ++x) { + tBitmap->getPixel(x, y, color); + if (alpha) { + //~ unimplemented + } else { + // convert to luminosity + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + lum = color[0] / 255.0; + break; + case splashModeRGB8: + case splashModeBGR8: + lum = (0.3 / 255.0) * color[0] + + (0.59 / 255.0) * color[1] + + (0.11 / 255.0) * color[2]; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + lum = (1 - color[3] / 255.0) + - (0.3 / 255.0) * color[0] + - (0.59 / 255.0) * color[1] + - (0.11 / 255.0) * color[2]; + if (lum < 0) { + lum = 0; + } + break; +#endif + } + if (transferFunc) { + transferFunc->transform(&lum, &lum2); + } else { + lum2 = lum; + } + p[x] = (int)(lum2 * 255.0 + 0.5); + } + } + p += softMask->getRowSize(); + } + splash->setSoftMask(softMask); + + // pop the stack + transpGroup = transpGroupStack; + transpGroupStack = transpGroup->next; + delete transpGroup; + + delete tBitmap; +} + +void SplashOutputDev::clearSoftMask(GfxState * /*state*/) { + splash->setSoftMask(NULL); +} + +void SplashOutputDev::setPaperColor(SplashColorPtr paperColorA) { + splashColorCopy(paperColor, paperColorA); +} + +int SplashOutputDev::getBitmapWidth() { + return bitmap->getWidth(); +} + +int SplashOutputDev::getBitmapHeight() { + return bitmap->getHeight(); +} + +SplashBitmap *SplashOutputDev::takeBitmap() { + SplashBitmap *ret; + + ret = bitmap; + bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode, + colorMode != splashModeMono1, bitmapTopDown); + return ret; +} + +void SplashOutputDev::getModRegion(int *xMin, int *yMin, + int *xMax, int *yMax) { + splash->getModRegion(xMin, yMin, xMax, yMax); +} + +void SplashOutputDev::clearModRegion() { + splash->clearModRegion(); +} + +void SplashOutputDev::setFillColor(int r, int g, int b) { + GfxRGB rgb; + GfxGray gray; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + + rgb.r = byteToCol(r); + rgb.g = byteToCol(g); + rgb.b = byteToCol(b); + gray = (GfxColorComp)(0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b + 0.5); + if (gray > gfxColorComp1) { + gray = gfxColorComp1; + } +#if SPLASH_CMYK + cmyk.c = gfxColorComp1 - rgb.r; + cmyk.m = gfxColorComp1 - rgb.g; + cmyk.y = gfxColorComp1 - rgb.b; + cmyk.k = 0; + splash->setFillPattern(getColor(gray, &rgb, &cmyk)); +#else + splash->setFillPattern(getColor(gray, &rgb)); +#endif +} + +SplashFont *SplashOutputDev::getFont(GString *name, double *textMatA) { + DisplayFontParam *dfp; + Ref ref; + SplashOutFontFileID *id; + SplashFontFile *fontFile; + SplashFont *fontObj; + FoFiTrueType *ff; + Gushort *codeToGID; + Unicode u; + SplashCoord textMat[4]; + int cmap, i; + + for (i = 0; i < 16; ++i) { + if (!name->cmp(splashOutSubstFonts[i].name)) { + break; + } + } + if (i == 16) { + return NULL; + } + ref.num = i; + ref.gen = -1; + id = new SplashOutFontFileID(&ref); + + // check the font file cache + if ((fontFile = fontEngine->getFontFile(id))) { + delete id; + + // load the font file + } else { + dfp = globalParams->getDisplayFont(name); + if (dfp && dfp->kind == displayFontT1) { + SplashFontSrc *fontsrc = new SplashFontSrc; + fontsrc->setFile(dfp->t1.fileName, gFalse); + fontFile = fontEngine->loadType1Font(id, fontsrc, winAnsiEncoding); + } else if (dfp && dfp->kind == displayFontTT) { + if (!(ff = FoFiTrueType::load(dfp->tt.fileName->getCString()))) { + return NULL; + } + for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) { + if ((ff->getCmapPlatform(cmap) == 3 && + ff->getCmapEncoding(cmap) == 1) || + ff->getCmapPlatform(cmap) == 0) { + break; + } + } + if (cmap == ff->getNumCmaps()) { + delete ff; + return NULL; + } + codeToGID = (Gushort *)gmallocn(256, sizeof(Gushort)); + for (i = 0; i < 256; ++i) { + codeToGID[i] = 0; + if (winAnsiEncoding[i] && + (u = globalParams->mapNameToUnicode(winAnsiEncoding[i]))) { + codeToGID[i] = ff->mapCodeToGID(cmap, u); + } + } + delete ff; + SplashFontSrc *fontsrc = new SplashFontSrc; + fontsrc->setFile(dfp->tt.fileName->getCString(), gFalse); + fontFile = fontEngine->loadTrueTypeFont(id, fontsrc, codeToGID, 256); + } else { + return NULL; + } + } + + // create the scaled font + textMat[0] = (SplashCoord)textMatA[0]; + textMat[1] = (SplashCoord)textMatA[1]; + textMat[2] = (SplashCoord)textMatA[2]; + textMat[3] = (SplashCoord)textMatA[3]; + fontObj = fontEngine->getFont(fontFile, textMat, splash->getMatrix()); + + return fontObj; +} + +#if 1 //~tmp: turn off anti-aliasing temporarily +GBool SplashOutputDev::getVectorAntialias() { + return splash->getVectorAntialias(); +} + +void SplashOutputDev::setVectorAntialias(GBool vaa) { + splash->setVectorAntialias(vaa); +} +#endif diff --git a/kpdf/xpdf/xpdf/SplashOutputDev.h b/kpdf/xpdf/xpdf/SplashOutputDev.h new file mode 100644 index 00000000..96f270ab --- /dev/null +++ b/kpdf/xpdf/xpdf/SplashOutputDev.h @@ -0,0 +1,247 @@ +//======================================================================== +// +// SplashOutputDev.h +// +// Copyright 2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHOUTPUTDEV_H +#define SPLASHOUTPUTDEV_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "SplashTypes.h" +#include "config.h" +#include "OutputDev.h" +#include "GfxState.h" + +class Gfx8BitFont; +class SplashBitmap; +class Splash; +class SplashPath; +class SplashPattern; +class SplashFontEngine; +class SplashFont; +class T3FontCache; +struct T3FontCacheTag; +struct T3GlyphStack; +struct SplashTransparencyGroup; + +//------------------------------------------------------------------------ + +// number of Type 3 fonts to cache +#define splashOutT3FontCacheSize 8 + +//------------------------------------------------------------------------ +// SplashOutputDev +//------------------------------------------------------------------------ + +class SplashOutputDev: public OutputDev { +public: + + // Constructor. + SplashOutputDev(SplashColorMode colorModeA, int bitmapRowPadA, + GBool reverseVideoA, SplashColorPtr paperColorA, + GBool bitmapTopDownA = gTrue, + GBool allowAntialiasA = gTrue); + + // Destructor. + virtual ~SplashOutputDev(); + + //----- get info about output device + + // Does this device use upside-down coordinates? + // (Upside-down means (0,0) is the top left corner of the page.) + virtual GBool upsideDown() { return gTrue; } + + // Does this device use drawChar() or drawString()? + virtual GBool useDrawChar() { return gTrue; } + + // Does this device use beginType3Char/endType3Char? Otherwise, + // text in Type 3 fonts will be drawn with drawChar/drawString. + virtual GBool interpretType3Chars() { return gTrue; } + + //----- initialization and control + + // Start a page. + virtual void startPage(int pageNum, GfxState *state); + + // End a page. + virtual void endPage(); + + //----- save/restore graphics state + virtual void saveState(GfxState *state); + virtual void restoreState(GfxState *state); + + //----- update graphics state + virtual void updateAll(GfxState *state); + virtual void updateCTM(GfxState *state, double m11, double m12, + double m21, double m22, double m31, double m32); + virtual void updateLineDash(GfxState *state); + virtual void updateFlatness(GfxState *state); + virtual void updateLineJoin(GfxState *state); + virtual void updateLineCap(GfxState *state); + virtual void updateMiterLimit(GfxState *state); + virtual void updateLineWidth(GfxState *state); + virtual void updateStrokeAdjust(GfxState *state); + virtual void updateFillColor(GfxState *state); + virtual void updateStrokeColor(GfxState *state); + virtual void updateBlendMode(GfxState *state); + virtual void updateFillOpacity(GfxState *state); + virtual void updateStrokeOpacity(GfxState *state); + + //----- update text state + virtual void updateFont(GfxState *state); + + //----- path painting + virtual void stroke(GfxState *state); + virtual void fill(GfxState *state); + virtual void eoFill(GfxState *state); + + //----- path clipping + virtual void clip(GfxState *state); + virtual void eoClip(GfxState *state); + virtual void clipToStrokePath(GfxState *state); + + //----- text drawing + virtual void drawChar(GfxState *state, double x, double y, + double dx, double dy, + double originX, double originY, + CharCode code, int nBytes, Unicode *u, int uLen); + virtual GBool beginType3Char(GfxState *state, double x, double y, + double dx, double dy, + CharCode code, Unicode *u, int uLen); + virtual void endType3Char(GfxState *state); + virtual void endTextObject(GfxState *state); + + //----- image drawing + virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, + int width, int height, GBool invert, + GBool inlineImg); + virtual void drawImage(GfxState *state, Object *ref, Stream *str, + int width, int height, GfxImageColorMap *colorMap, + int *maskColors, GBool inlineImg); + virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, int maskWidth, int maskHeight, + GBool maskInvert); + virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GfxImageColorMap *maskColorMap); + + //----- Type 3 font operators + virtual void type3D0(GfxState *state, double wx, double wy); + virtual void type3D1(GfxState *state, double wx, double wy, + double llx, double lly, double urx, double ury); + + //----- transparency groups and soft masks + virtual void beginTransparencyGroup(GfxState *state, double *bbox, + GfxColorSpace *blendingColorSpace, + GBool isolated, GBool knockout, + GBool forSoftMask); + virtual void endTransparencyGroup(GfxState *state); + virtual void paintTransparencyGroup(GfxState *state, double *bbox); + virtual void setSoftMask(GfxState *state, double *bbox, GBool alpha, + Function *transferFunc, GfxColor *backdropColor); + virtual void clearSoftMask(GfxState *state); + + //----- special access + + // Called to indicate that a new PDF document has been loaded. + void startDoc(XRef *xrefA); + + void setPaperColor(SplashColorPtr paperColorA); + + GBool isReverseVideo() { return reverseVideo; } + void setReverseVideo(GBool reverseVideoA) { reverseVideo = reverseVideoA; } + + // Get the bitmap and its size. + SplashBitmap *getBitmap() { return bitmap; } + int getBitmapWidth(); + int getBitmapHeight(); + + // Returns the last rasterized bitmap, transferring ownership to the + // caller. + SplashBitmap *takeBitmap(); + + // Get the Splash object. + Splash *getSplash() { return splash; } + + // Get the modified region. + void getModRegion(int *xMin, int *yMin, int *xMax, int *yMax); + + // Clear the modified region. + void clearModRegion(); + + // Set the Splash fill color. + void setFillColor(int r, int g, int b); + + // Get a font object for a Base-14 font, using the Latin-1 encoding. + SplashFont *getFont(GString *name, double *textMatA); + + SplashFont *getCurrentFont() { return font; } + +#if 1 //~tmp: turn off anti-aliasing temporarily + virtual GBool getVectorAntialias(); + virtual void setVectorAntialias(GBool vaa); +#endif + +private: + + void setupScreenParams(double hDPI, double vDPI); +#if SPLASH_CMYK + SplashPattern *getColor(GfxGray gray, GfxRGB *rgb, GfxCMYK *cmyk); +#else + SplashPattern *getColor(GfxGray gray, GfxRGB *rgb); +#endif + SplashPath *convertPath(GfxState *state, GfxPath *path); + void doUpdateFont(GfxState *state); + void drawType3Glyph(T3FontCache *t3Font, + T3FontCacheTag *tag, Guchar *data); + static GBool imageMaskSrc(void *data, SplashColorPtr line); + static GBool imageSrc(void *data, SplashColorPtr colorLine, + Guchar *alphaLine); + static GBool alphaImageSrc(void *data, SplashColorPtr line, + Guchar *alphaLine); + static GBool maskedImageSrc(void *data, SplashColorPtr line, + Guchar *alphaLine); + + SplashColorMode colorMode; + int bitmapRowPad; + GBool bitmapTopDown; + GBool allowAntialias; + GBool vectorAntialias; + GBool reverseVideo; // reverse video mode + SplashColor paperColor; // paper color + SplashScreenParams screenParams; + + XRef *xref; // xref table for current document + + SplashBitmap *bitmap; + Splash *splash; + SplashFontEngine *fontEngine; + + T3FontCache * // Type 3 font cache + t3FontCache[splashOutT3FontCacheSize]; + int nT3Fonts; // number of valid entries in t3FontCache + T3GlyphStack *t3GlyphStack; // Type 3 glyph context stack + + SplashFont *font; // current font + GBool needFontUpdate; // set when the font needs to be updated + SplashPath *textClipPath; // clipping path built with text object + + SplashTransparencyGroup * // transparency group stack + transpGroupStack; +}; + +#endif diff --git a/kpdf/xpdf/xpdf/Stream-CCITT.h b/kpdf/xpdf/xpdf/Stream-CCITT.h new file mode 100644 index 00000000..a9b1d1ed --- /dev/null +++ b/kpdf/xpdf/xpdf/Stream-CCITT.h @@ -0,0 +1,462 @@ +#ifndef STREAM_CCITT_H +#define STREAM_CCITT_H +//======================================================================== +// +// Stream-CCITT.h +// +// Tables for CCITT Fax decoding. +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +struct CCITTCode { + short bits; + short n; +}; + +#define ccittEOL -2 + +//------------------------------------------------------------------------ +// 2D codes +//------------------------------------------------------------------------ + +#define twoDimPass 0 +#define twoDimHoriz 1 +#define twoDimVert0 2 +#define twoDimVertR1 3 +#define twoDimVertL1 4 +#define twoDimVertR2 5 +#define twoDimVertL2 6 +#define twoDimVertR3 7 +#define twoDimVertL3 8 + +// 1-7 bit codes +static CCITTCode twoDimTab1[128] = { + {-1, -1}, {-1, -1}, // 000000x + {7, twoDimVertL3}, // 0000010 + {7, twoDimVertR3}, // 0000011 + {6, twoDimVertL2}, {6, twoDimVertL2}, // 000010x + {6, twoDimVertR2}, {6, twoDimVertR2}, // 000011x + {4, twoDimPass}, {4, twoDimPass}, // 0001xxx + {4, twoDimPass}, {4, twoDimPass}, + {4, twoDimPass}, {4, twoDimPass}, + {4, twoDimPass}, {4, twoDimPass}, + {3, twoDimHoriz}, {3, twoDimHoriz}, // 001xxxx + {3, twoDimHoriz}, {3, twoDimHoriz}, + {3, twoDimHoriz}, {3, twoDimHoriz}, + {3, twoDimHoriz}, {3, twoDimHoriz}, + {3, twoDimHoriz}, {3, twoDimHoriz}, + {3, twoDimHoriz}, {3, twoDimHoriz}, + {3, twoDimHoriz}, {3, twoDimHoriz}, + {3, twoDimHoriz}, {3, twoDimHoriz}, + {3, twoDimVertL1}, {3, twoDimVertL1}, // 010xxxx + {3, twoDimVertL1}, {3, twoDimVertL1}, + {3, twoDimVertL1}, {3, twoDimVertL1}, + {3, twoDimVertL1}, {3, twoDimVertL1}, + {3, twoDimVertL1}, {3, twoDimVertL1}, + {3, twoDimVertL1}, {3, twoDimVertL1}, + {3, twoDimVertL1}, {3, twoDimVertL1}, + {3, twoDimVertL1}, {3, twoDimVertL1}, + {3, twoDimVertR1}, {3, twoDimVertR1}, // 011xxxx + {3, twoDimVertR1}, {3, twoDimVertR1}, + {3, twoDimVertR1}, {3, twoDimVertR1}, + {3, twoDimVertR1}, {3, twoDimVertR1}, + {3, twoDimVertR1}, {3, twoDimVertR1}, + {3, twoDimVertR1}, {3, twoDimVertR1}, + {3, twoDimVertR1}, {3, twoDimVertR1}, + {3, twoDimVertR1}, {3, twoDimVertR1}, + {1, twoDimVert0}, {1, twoDimVert0}, // 1xxxxxx + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0}, + {1, twoDimVert0}, {1, twoDimVert0} +}; + +//------------------------------------------------------------------------ +// white run lengths +//------------------------------------------------------------------------ + +// 11-12 bit codes (upper 7 bits are 0) +static CCITTCode whiteTab1[32] = { + {-1, -1}, // 00000 + {12, ccittEOL}, // 00001 + {-1, -1}, {-1, -1}, // 0001x + {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 001xx + {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 010xx + {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 011xx + {11, 1792}, {11, 1792}, // 1000x + {12, 1984}, // 10010 + {12, 2048}, // 10011 + {12, 2112}, // 10100 + {12, 2176}, // 10101 + {12, 2240}, // 10110 + {12, 2304}, // 10111 + {11, 1856}, {11, 1856}, // 1100x + {11, 1920}, {11, 1920}, // 1101x + {12, 2368}, // 11100 + {12, 2432}, // 11101 + {12, 2496}, // 11110 + {12, 2560} // 11111 +}; + +// 1-9 bit codes +static CCITTCode whiteTab2[512] = { + {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 0000000xx + {8, 29}, {8, 29}, // 00000010x + {8, 30}, {8, 30}, // 00000011x + {8, 45}, {8, 45}, // 00000100x + {8, 46}, {8, 46}, // 00000101x + {7, 22}, {7, 22}, {7, 22}, {7, 22}, // 0000011xx + {7, 23}, {7, 23}, {7, 23}, {7, 23}, // 0000100xx + {8, 47}, {8, 47}, // 00001010x + {8, 48}, {8, 48}, // 00001011x + {6, 13}, {6, 13}, {6, 13}, {6, 13}, // 000011xxx + {6, 13}, {6, 13}, {6, 13}, {6, 13}, + {7, 20}, {7, 20}, {7, 20}, {7, 20}, // 0001000xx + {8, 33}, {8, 33}, // 00010010x + {8, 34}, {8, 34}, // 00010011x + {8, 35}, {8, 35}, // 00010100x + {8, 36}, {8, 36}, // 00010101x + {8, 37}, {8, 37}, // 00010110x + {8, 38}, {8, 38}, // 00010111x + {7, 19}, {7, 19}, {7, 19}, {7, 19}, // 0001100xx + {8, 31}, {8, 31}, // 00011010x + {8, 32}, {8, 32}, // 00011011x + {6, 1}, {6, 1}, {6, 1}, {6, 1}, // 000111xxx + {6, 1}, {6, 1}, {6, 1}, {6, 1}, + {6, 12}, {6, 12}, {6, 12}, {6, 12}, // 001000xxx + {6, 12}, {6, 12}, {6, 12}, {6, 12}, + {8, 53}, {8, 53}, // 00100100x + {8, 54}, {8, 54}, // 00100101x + {7, 26}, {7, 26}, {7, 26}, {7, 26}, // 0010011xx + {8, 39}, {8, 39}, // 00101000x + {8, 40}, {8, 40}, // 00101001x + {8, 41}, {8, 41}, // 00101010x + {8, 42}, {8, 42}, // 00101011x + {8, 43}, {8, 43}, // 00101100x + {8, 44}, {8, 44}, // 00101101x + {7, 21}, {7, 21}, {7, 21}, {7, 21}, // 0010111xx + {7, 28}, {7, 28}, {7, 28}, {7, 28}, // 0011000xx + {8, 61}, {8, 61}, // 00110010x + {8, 62}, {8, 62}, // 00110011x + {8, 63}, {8, 63}, // 00110100x + {8, 0}, {8, 0}, // 00110101x + {8, 320}, {8, 320}, // 00110110x + {8, 384}, {8, 384}, // 00110111x + {5, 10}, {5, 10}, {5, 10}, {5, 10}, // 00111xxxx + {5, 10}, {5, 10}, {5, 10}, {5, 10}, + {5, 10}, {5, 10}, {5, 10}, {5, 10}, + {5, 10}, {5, 10}, {5, 10}, {5, 10}, + {5, 11}, {5, 11}, {5, 11}, {5, 11}, // 01000xxxx + {5, 11}, {5, 11}, {5, 11}, {5, 11}, + {5, 11}, {5, 11}, {5, 11}, {5, 11}, + {5, 11}, {5, 11}, {5, 11}, {5, 11}, + {7, 27}, {7, 27}, {7, 27}, {7, 27}, // 0100100xx + {8, 59}, {8, 59}, // 01001010x + {8, 60}, {8, 60}, // 01001011x + {9, 1472}, // 010011000 + {9, 1536}, // 010011001 + {9, 1600}, // 010011010 + {9, 1728}, // 010011011 + {7, 18}, {7, 18}, {7, 18}, {7, 18}, // 0100111xx + {7, 24}, {7, 24}, {7, 24}, {7, 24}, // 0101000xx + {8, 49}, {8, 49}, // 01010010x + {8, 50}, {8, 50}, // 01010011x + {8, 51}, {8, 51}, // 01010100x + {8, 52}, {8, 52}, // 01010101x + {7, 25}, {7, 25}, {7, 25}, {7, 25}, // 0101011xx + {8, 55}, {8, 55}, // 01011000x + {8, 56}, {8, 56}, // 01011001x + {8, 57}, {8, 57}, // 01011010x + {8, 58}, {8, 58}, // 01011011x + {6, 192}, {6, 192}, {6, 192}, {6, 192}, // 010111xxx + {6, 192}, {6, 192}, {6, 192}, {6, 192}, + {6, 1664}, {6, 1664}, {6, 1664}, {6, 1664}, // 011000xxx + {6, 1664}, {6, 1664}, {6, 1664}, {6, 1664}, + {8, 448}, {8, 448}, // 01100100x + {8, 512}, {8, 512}, // 01100101x + {9, 704}, // 011001100 + {9, 768}, // 011001101 + {8, 640}, {8, 640}, // 01100111x + {8, 576}, {8, 576}, // 01101000x + {9, 832}, // 011010010 + {9, 896}, // 011010011 + {9, 960}, // 011010100 + {9, 1024}, // 011010101 + {9, 1088}, // 011010110 + {9, 1152}, // 011010111 + {9, 1216}, // 011011000 + {9, 1280}, // 011011001 + {9, 1344}, // 011011010 + {9, 1408}, // 011011011 + {7, 256}, {7, 256}, {7, 256}, {7, 256}, // 0110111xx + {4, 2}, {4, 2}, {4, 2}, {4, 2}, // 0111xxxxx + {4, 2}, {4, 2}, {4, 2}, {4, 2}, + {4, 2}, {4, 2}, {4, 2}, {4, 2}, + {4, 2}, {4, 2}, {4, 2}, {4, 2}, + {4, 2}, {4, 2}, {4, 2}, {4, 2}, + {4, 2}, {4, 2}, {4, 2}, {4, 2}, + {4, 2}, {4, 2}, {4, 2}, {4, 2}, + {4, 2}, {4, 2}, {4, 2}, {4, 2}, + {4, 3}, {4, 3}, {4, 3}, {4, 3}, // 1000xxxxx + {4, 3}, {4, 3}, {4, 3}, {4, 3}, + {4, 3}, {4, 3}, {4, 3}, {4, 3}, + {4, 3}, {4, 3}, {4, 3}, {4, 3}, + {4, 3}, {4, 3}, {4, 3}, {4, 3}, + {4, 3}, {4, 3}, {4, 3}, {4, 3}, + {4, 3}, {4, 3}, {4, 3}, {4, 3}, + {4, 3}, {4, 3}, {4, 3}, {4, 3}, + {5, 128}, {5, 128}, {5, 128}, {5, 128}, // 10010xxxx + {5, 128}, {5, 128}, {5, 128}, {5, 128}, + {5, 128}, {5, 128}, {5, 128}, {5, 128}, + {5, 128}, {5, 128}, {5, 128}, {5, 128}, + {5, 8}, {5, 8}, {5, 8}, {5, 8}, // 10011xxxx + {5, 8}, {5, 8}, {5, 8}, {5, 8}, + {5, 8}, {5, 8}, {5, 8}, {5, 8}, + {5, 8}, {5, 8}, {5, 8}, {5, 8}, + {5, 9}, {5, 9}, {5, 9}, {5, 9}, // 10100xxxx + {5, 9}, {5, 9}, {5, 9}, {5, 9}, + {5, 9}, {5, 9}, {5, 9}, {5, 9}, + {5, 9}, {5, 9}, {5, 9}, {5, 9}, + {6, 16}, {6, 16}, {6, 16}, {6, 16}, // 101010xxx + {6, 16}, {6, 16}, {6, 16}, {6, 16}, + {6, 17}, {6, 17}, {6, 17}, {6, 17}, // 101011xxx + {6, 17}, {6, 17}, {6, 17}, {6, 17}, + {4, 4}, {4, 4}, {4, 4}, {4, 4}, // 1011xxxxx + {4, 4}, {4, 4}, {4, 4}, {4, 4}, + {4, 4}, {4, 4}, {4, 4}, {4, 4}, + {4, 4}, {4, 4}, {4, 4}, {4, 4}, + {4, 4}, {4, 4}, {4, 4}, {4, 4}, + {4, 4}, {4, 4}, {4, 4}, {4, 4}, + {4, 4}, {4, 4}, {4, 4}, {4, 4}, + {4, 4}, {4, 4}, {4, 4}, {4, 4}, + {4, 5}, {4, 5}, {4, 5}, {4, 5}, // 1100xxxxx + {4, 5}, {4, 5}, {4, 5}, {4, 5}, + {4, 5}, {4, 5}, {4, 5}, {4, 5}, + {4, 5}, {4, 5}, {4, 5}, {4, 5}, + {4, 5}, {4, 5}, {4, 5}, {4, 5}, + {4, 5}, {4, 5}, {4, 5}, {4, 5}, + {4, 5}, {4, 5}, {4, 5}, {4, 5}, + {4, 5}, {4, 5}, {4, 5}, {4, 5}, + {6, 14}, {6, 14}, {6, 14}, {6, 14}, // 110100xxx + {6, 14}, {6, 14}, {6, 14}, {6, 14}, + {6, 15}, {6, 15}, {6, 15}, {6, 15}, // 110101xxx + {6, 15}, {6, 15}, {6, 15}, {6, 15}, + {5, 64}, {5, 64}, {5, 64}, {5, 64}, // 11011xxxx + {5, 64}, {5, 64}, {5, 64}, {5, 64}, + {5, 64}, {5, 64}, {5, 64}, {5, 64}, + {5, 64}, {5, 64}, {5, 64}, {5, 64}, + {4, 6}, {4, 6}, {4, 6}, {4, 6}, // 1110xxxxx + {4, 6}, {4, 6}, {4, 6}, {4, 6}, + {4, 6}, {4, 6}, {4, 6}, {4, 6}, + {4, 6}, {4, 6}, {4, 6}, {4, 6}, + {4, 6}, {4, 6}, {4, 6}, {4, 6}, + {4, 6}, {4, 6}, {4, 6}, {4, 6}, + {4, 6}, {4, 6}, {4, 6}, {4, 6}, + {4, 6}, {4, 6}, {4, 6}, {4, 6}, + {4, 7}, {4, 7}, {4, 7}, {4, 7}, // 1111xxxxx + {4, 7}, {4, 7}, {4, 7}, {4, 7}, + {4, 7}, {4, 7}, {4, 7}, {4, 7}, + {4, 7}, {4, 7}, {4, 7}, {4, 7}, + {4, 7}, {4, 7}, {4, 7}, {4, 7}, + {4, 7}, {4, 7}, {4, 7}, {4, 7}, + {4, 7}, {4, 7}, {4, 7}, {4, 7}, + {4, 7}, {4, 7}, {4, 7}, {4, 7} +}; + +//------------------------------------------------------------------------ +// black run lengths +//------------------------------------------------------------------------ + +// 10-13 bit codes (upper 6 bits are 0) +static CCITTCode blackTab1[128] = { + {-1, -1}, {-1, -1}, // 000000000000x + {12, ccittEOL}, {12, ccittEOL}, // 000000000001x + {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000001xx + {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000010xx + {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000011xx + {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000100xx + {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000101xx + {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000110xx + {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000111xx + {11, 1792}, {11, 1792}, {11, 1792}, {11, 1792}, // 00000001000xx + {12, 1984}, {12, 1984}, // 000000010010x + {12, 2048}, {12, 2048}, // 000000010011x + {12, 2112}, {12, 2112}, // 000000010100x + {12, 2176}, {12, 2176}, // 000000010101x + {12, 2240}, {12, 2240}, // 000000010110x + {12, 2304}, {12, 2304}, // 000000010111x + {11, 1856}, {11, 1856}, {11, 1856}, {11, 1856}, // 00000001100xx + {11, 1920}, {11, 1920}, {11, 1920}, {11, 1920}, // 00000001101xx + {12, 2368}, {12, 2368}, // 000000011100x + {12, 2432}, {12, 2432}, // 000000011101x + {12, 2496}, {12, 2496}, // 000000011110x + {12, 2560}, {12, 2560}, // 000000011111x + {10, 18}, {10, 18}, {10, 18}, {10, 18}, // 0000001000xxx + {10, 18}, {10, 18}, {10, 18}, {10, 18}, + {12, 52}, {12, 52}, // 000000100100x + {13, 640}, // 0000001001010 + {13, 704}, // 0000001001011 + {13, 768}, // 0000001001100 + {13, 832}, // 0000001001101 + {12, 55}, {12, 55}, // 000000100111x + {12, 56}, {12, 56}, // 000000101000x + {13, 1280}, // 0000001010010 + {13, 1344}, // 0000001010011 + {13, 1408}, // 0000001010100 + {13, 1472}, // 0000001010101 + {12, 59}, {12, 59}, // 000000101011x + {12, 60}, {12, 60}, // 000000101100x + {13, 1536}, // 0000001011010 + {13, 1600}, // 0000001011011 + {11, 24}, {11, 24}, {11, 24}, {11, 24}, // 00000010111xx + {11, 25}, {11, 25}, {11, 25}, {11, 25}, // 00000011000xx + {13, 1664}, // 0000001100100 + {13, 1728}, // 0000001100101 + {12, 320}, {12, 320}, // 000000110011x + {12, 384}, {12, 384}, // 000000110100x + {12, 448}, {12, 448}, // 000000110101x + {13, 512}, // 0000001101100 + {13, 576}, // 0000001101101 + {12, 53}, {12, 53}, // 000000110111x + {12, 54}, {12, 54}, // 000000111000x + {13, 896}, // 0000001110010 + {13, 960}, // 0000001110011 + {13, 1024}, // 0000001110100 + {13, 1088}, // 0000001110101 + {13, 1152}, // 0000001110110 + {13, 1216}, // 0000001110111 + {10, 64}, {10, 64}, {10, 64}, {10, 64}, // 0000001111xxx + {10, 64}, {10, 64}, {10, 64}, {10, 64} +}; + +// 7-12 bit codes (upper 4 bits are 0) +static CCITTCode blackTab2[192] = { + {8, 13}, {8, 13}, {8, 13}, {8, 13}, // 00000100xxxx + {8, 13}, {8, 13}, {8, 13}, {8, 13}, + {8, 13}, {8, 13}, {8, 13}, {8, 13}, + {8, 13}, {8, 13}, {8, 13}, {8, 13}, + {11, 23}, {11, 23}, // 00000101000x + {12, 50}, // 000001010010 + {12, 51}, // 000001010011 + {12, 44}, // 000001010100 + {12, 45}, // 000001010101 + {12, 46}, // 000001010110 + {12, 47}, // 000001010111 + {12, 57}, // 000001011000 + {12, 58}, // 000001011001 + {12, 61}, // 000001011010 + {12, 256}, // 000001011011 + {10, 16}, {10, 16}, {10, 16}, {10, 16}, // 0000010111xx + {10, 17}, {10, 17}, {10, 17}, {10, 17}, // 0000011000xx + {12, 48}, // 000001100100 + {12, 49}, // 000001100101 + {12, 62}, // 000001100110 + {12, 63}, // 000001100111 + {12, 30}, // 000001101000 + {12, 31}, // 000001101001 + {12, 32}, // 000001101010 + {12, 33}, // 000001101011 + {12, 40}, // 000001101100 + {12, 41}, // 000001101101 + {11, 22}, {11, 22}, // 00000110111x + {8, 14}, {8, 14}, {8, 14}, {8, 14}, // 00000111xxxx + {8, 14}, {8, 14}, {8, 14}, {8, 14}, + {8, 14}, {8, 14}, {8, 14}, {8, 14}, + {8, 14}, {8, 14}, {8, 14}, {8, 14}, + {7, 10}, {7, 10}, {7, 10}, {7, 10}, // 0000100xxxxx + {7, 10}, {7, 10}, {7, 10}, {7, 10}, + {7, 10}, {7, 10}, {7, 10}, {7, 10}, + {7, 10}, {7, 10}, {7, 10}, {7, 10}, + {7, 10}, {7, 10}, {7, 10}, {7, 10}, + {7, 10}, {7, 10}, {7, 10}, {7, 10}, + {7, 10}, {7, 10}, {7, 10}, {7, 10}, + {7, 10}, {7, 10}, {7, 10}, {7, 10}, + {7, 11}, {7, 11}, {7, 11}, {7, 11}, // 0000101xxxxx + {7, 11}, {7, 11}, {7, 11}, {7, 11}, + {7, 11}, {7, 11}, {7, 11}, {7, 11}, + {7, 11}, {7, 11}, {7, 11}, {7, 11}, + {7, 11}, {7, 11}, {7, 11}, {7, 11}, + {7, 11}, {7, 11}, {7, 11}, {7, 11}, + {7, 11}, {7, 11}, {7, 11}, {7, 11}, + {7, 11}, {7, 11}, {7, 11}, {7, 11}, + {9, 15}, {9, 15}, {9, 15}, {9, 15}, // 000011000xxx + {9, 15}, {9, 15}, {9, 15}, {9, 15}, + {12, 128}, // 000011001000 + {12, 192}, // 000011001001 + {12, 26}, // 000011001010 + {12, 27}, // 000011001011 + {12, 28}, // 000011001100 + {12, 29}, // 000011001101 + {11, 19}, {11, 19}, // 00001100111x + {11, 20}, {11, 20}, // 00001101000x + {12, 34}, // 000011010010 + {12, 35}, // 000011010011 + {12, 36}, // 000011010100 + {12, 37}, // 000011010101 + {12, 38}, // 000011010110 + {12, 39}, // 000011010111 + {11, 21}, {11, 21}, // 00001101100x + {12, 42}, // 000011011010 + {12, 43}, // 000011011011 + {10, 0}, {10, 0}, {10, 0}, {10, 0}, // 0000110111xx + {7, 12}, {7, 12}, {7, 12}, {7, 12}, // 0000111xxxxx + {7, 12}, {7, 12}, {7, 12}, {7, 12}, + {7, 12}, {7, 12}, {7, 12}, {7, 12}, + {7, 12}, {7, 12}, {7, 12}, {7, 12}, + {7, 12}, {7, 12}, {7, 12}, {7, 12}, + {7, 12}, {7, 12}, {7, 12}, {7, 12}, + {7, 12}, {7, 12}, {7, 12}, {7, 12}, + {7, 12}, {7, 12}, {7, 12}, {7, 12} +}; + +// 2-6 bit codes +static CCITTCode blackTab3[64] = { + {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 0000xx + {6, 9}, // 000100 + {6, 8}, // 000101 + {5, 7}, {5, 7}, // 00011x + {4, 6}, {4, 6}, {4, 6}, {4, 6}, // 0010xx + {4, 5}, {4, 5}, {4, 5}, {4, 5}, // 0011xx + {3, 1}, {3, 1}, {3, 1}, {3, 1}, // 010xxx + {3, 1}, {3, 1}, {3, 1}, {3, 1}, + {3, 4}, {3, 4}, {3, 4}, {3, 4}, // 011xxx + {3, 4}, {3, 4}, {3, 4}, {3, 4}, + {2, 3}, {2, 3}, {2, 3}, {2, 3}, // 10xxxx + {2, 3}, {2, 3}, {2, 3}, {2, 3}, + {2, 3}, {2, 3}, {2, 3}, {2, 3}, + {2, 3}, {2, 3}, {2, 3}, {2, 3}, + {2, 2}, {2, 2}, {2, 2}, {2, 2}, // 11xxxx + {2, 2}, {2, 2}, {2, 2}, {2, 2}, + {2, 2}, {2, 2}, {2, 2}, {2, 2}, + {2, 2}, {2, 2}, {2, 2}, {2, 2} +}; +#endif diff --git a/kpdf/xpdf/xpdf/Stream.cc b/kpdf/xpdf/xpdf/Stream.cc new file mode 100644 index 00000000..ab630241 --- /dev/null +++ b/kpdf/xpdf/xpdf/Stream.cc @@ -0,0 +1,4697 @@ +//======================================================================== +// +// Stream.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include +#ifndef WIN32 +#include +#endif +#include +#include +#include "gmem.h" +#include "gfile.h" +#include "config.h" +#include "Error.h" +#include "Object.h" +#include "Lexer.h" +#include "GfxState.h" +#include "Stream.h" +#include "JBIG2Stream.h" +#include "JPXStream.h" +#include "Stream-CCITT.h" + +#ifdef __DJGPP__ +static GBool setDJSYSFLAGS = gFalse; +#endif + +#ifdef VMS +#ifdef __GNUC__ +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#endif +#endif + +//------------------------------------------------------------------------ +// Stream (base class) +//------------------------------------------------------------------------ + +Stream::Stream() { + ref = 1; +} + +Stream::~Stream() { +} + +void Stream::close() { +} + +int Stream::getRawChar() { + error(-1, "Internal: called getRawChar() on non-predictor stream"); + return EOF; +} + +char *Stream::getLine(char *buf, int size) { + int i; + int c; + + if (lookChar() == EOF) + return NULL; + for (i = 0; i < size - 1; ++i) { + c = getChar(); + if (c == EOF || c == '\n') + break; + if (c == '\r') { + if ((c = lookChar()) == '\n') + getChar(); + break; + } + buf[i] = c; + } + buf[i] = '\0'; + return buf; +} + +GString *Stream::getPSFilter(int /*psLevel*/, char * /*indent*/) { + return new GString(); +} + +Stream *Stream::addFilters(Object *dict) { + Object obj, obj2; + Object params, params2; + Stream *str; + int i; + + str = this; + dict->dictLookup("Filter", &obj); + if (obj.isNull()) { + obj.free(); + dict->dictLookup("F", &obj); + } + dict->dictLookup("DecodeParms", ¶ms); + if (params.isNull()) { + params.free(); + dict->dictLookup("DP", ¶ms); + } + if (obj.isName()) { + str = makeFilter(obj.getName(), str, ¶ms); + } else if (obj.isArray()) { + for (i = 0; i < obj.arrayGetLength(); ++i) { + obj.arrayGet(i, &obj2); + if (params.isArray()) + params.arrayGet(i, ¶ms2); + else + params2.initNull(); + if (obj2.isName()) { + str = makeFilter(obj2.getName(), str, ¶ms2); + } else { + error(getPos(), "Bad filter name"); + str = new EOFStream(str); + } + obj2.free(); + params2.free(); + } + } else if (!obj.isNull()) { + error(getPos(), "Bad 'Filter' attribute in stream"); + } + obj.free(); + params.free(); + + return str; +} + +Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { + int pred; // parameters + int colors; + int bits; + int early; + int encoding; + GBool endOfLine, byteAlign, endOfBlock, black; + int columns, rows; + int colorXform; + Object globals, obj; + + if (!strcmp(name, "ASCIIHexDecode") || !strcmp(name, "AHx")) { + str = new ASCIIHexStream(str); + } else if (!strcmp(name, "ASCII85Decode") || !strcmp(name, "A85")) { + str = new ASCII85Stream(str); + } else if (!strcmp(name, "LZWDecode") || !strcmp(name, "LZW")) { + pred = 1; + columns = 1; + colors = 1; + bits = 8; + early = 1; + if (params->isDict()) { + params->dictLookup("Predictor", &obj); + if (obj.isInt()) + pred = obj.getInt(); + obj.free(); + params->dictLookup("Columns", &obj); + if (obj.isInt()) + columns = obj.getInt(); + obj.free(); + params->dictLookup("Colors", &obj); + if (obj.isInt()) + colors = obj.getInt(); + obj.free(); + params->dictLookup("BitsPerComponent", &obj); + if (obj.isInt()) + bits = obj.getInt(); + obj.free(); + params->dictLookup("EarlyChange", &obj); + if (obj.isInt()) + early = obj.getInt(); + obj.free(); + } + str = new LZWStream(str, pred, columns, colors, bits, early); + } else if (!strcmp(name, "RunLengthDecode") || !strcmp(name, "RL")) { + str = new RunLengthStream(str); + } else if (!strcmp(name, "CCITTFaxDecode") || !strcmp(name, "CCF")) { + encoding = 0; + endOfLine = gFalse; + byteAlign = gFalse; + columns = 1728; + rows = 0; + endOfBlock = gTrue; + black = gFalse; + if (params->isDict()) { + params->dictLookup("K", &obj); + if (obj.isInt()) { + encoding = obj.getInt(); + } + obj.free(); + params->dictLookup("EndOfLine", &obj); + if (obj.isBool()) { + endOfLine = obj.getBool(); + } + obj.free(); + params->dictLookup("EncodedByteAlign", &obj); + if (obj.isBool()) { + byteAlign = obj.getBool(); + } + obj.free(); + params->dictLookup("Columns", &obj); + if (obj.isInt()) { + columns = obj.getInt(); + } + obj.free(); + params->dictLookup("Rows", &obj); + if (obj.isInt()) { + rows = obj.getInt(); + } + obj.free(); + params->dictLookup("EndOfBlock", &obj); + if (obj.isBool()) { + endOfBlock = obj.getBool(); + } + obj.free(); + params->dictLookup("BlackIs1", &obj); + if (obj.isBool()) { + black = obj.getBool(); + } + obj.free(); + } + str = new CCITTFaxStream(str, encoding, endOfLine, byteAlign, + columns, rows, endOfBlock, black); + } else if (!strcmp(name, "DCTDecode") || !strcmp(name, "DCT")) { + colorXform = -1; + if (params->isDict()) { + if (params->dictLookup("ColorTransform", &obj)->isInt()) { + colorXform = obj.getInt(); + } + obj.free(); + } + str = new DCTStream(str, colorXform); + } else if (!strcmp(name, "FlateDecode") || !strcmp(name, "Fl")) { + pred = 1; + columns = 1; + colors = 1; + bits = 8; + if (params->isDict()) { + params->dictLookup("Predictor", &obj); + if (obj.isInt()) + pred = obj.getInt(); + obj.free(); + params->dictLookup("Columns", &obj); + if (obj.isInt()) + columns = obj.getInt(); + obj.free(); + params->dictLookup("Colors", &obj); + if (obj.isInt()) + colors = obj.getInt(); + obj.free(); + params->dictLookup("BitsPerComponent", &obj); + if (obj.isInt()) + bits = obj.getInt(); + obj.free(); + } + str = new FlateStream(str, pred, columns, colors, bits); + } else if (!strcmp(name, "JBIG2Decode")) { + if (params->isDict()) { + params->dictLookup("JBIG2Globals", &globals); + } + str = new JBIG2Stream(str, &globals); + globals.free(); + } else if (!strcmp(name, "JPXDecode")) { + str = new JPXStream(str); + } else { + error(getPos(), "Unknown filter '%s'", name); + str = new EOFStream(str); + } + return str; +} + +//------------------------------------------------------------------------ +// BaseStream +//------------------------------------------------------------------------ + +BaseStream::BaseStream(Object *dictA) { + dict = *dictA; +} + +BaseStream::~BaseStream() { + dict.free(); +} + +//------------------------------------------------------------------------ +// FilterStream +//------------------------------------------------------------------------ + +FilterStream::FilterStream(Stream *strA) { + str = strA; +} + +FilterStream::~FilterStream() { +} + +void FilterStream::close() { + str->close(); +} + +void FilterStream::setPos(Guint /*pos*/, int /*dir*/) { + error(-1, "Internal: called setPos() on FilterStream"); +} + +//------------------------------------------------------------------------ +// ImageStream +//------------------------------------------------------------------------ + +ImageStream::ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA) { + int imgLineSize; + + str = strA; + width = widthA; + nComps = nCompsA; + nBits = nBitsA; + + nVals = width * nComps; + if (nBits == 1) { + imgLineSize = (nVals + 7) & ~7; + } else { + imgLineSize = nVals; + } + imgLine = (Guchar *)gmallocn(imgLineSize, sizeof(Guchar)); + imgIdx = nVals; +} + +ImageStream::~ImageStream() { + gfree(imgLine); +} + +void ImageStream::reset() { + str->reset(); +} + +GBool ImageStream::getPixel(Guchar *pix) { + int i; + + if (imgIdx >= nVals) { + getLine(); + imgIdx = 0; + } + for (i = 0; i < nComps; ++i) { + pix[i] = imgLine[imgIdx++]; + } + return gTrue; +} + +Guchar *ImageStream::getLine() { + Gulong buf, bitMask; + int bits; + int c; + int i; + + if (nBits == 1) { + for (i = 0; i < nVals; i += 8) { + c = str->getChar(); + imgLine[i+0] = (Guchar)((c >> 7) & 1); + imgLine[i+1] = (Guchar)((c >> 6) & 1); + imgLine[i+2] = (Guchar)((c >> 5) & 1); + imgLine[i+3] = (Guchar)((c >> 4) & 1); + imgLine[i+4] = (Guchar)((c >> 3) & 1); + imgLine[i+5] = (Guchar)((c >> 2) & 1); + imgLine[i+6] = (Guchar)((c >> 1) & 1); + imgLine[i+7] = (Guchar)(c & 1); + } + } else if (nBits == 8) { + for (i = 0; i < nVals; ++i) { + imgLine[i] = str->getChar(); + } + } else { + bitMask = (1 << nBits) - 1; + buf = 0; + bits = 0; + for (i = 0; i < nVals; ++i) { + if (bits < nBits) { + buf = (buf << 8) | (str->getChar() & 0xff); + bits += 8; + } + imgLine[i] = (Guchar)((buf >> (bits - nBits)) & bitMask); + bits -= nBits; + } + } + return imgLine; +} + +void ImageStream::skipLine() { + int n, i; + + n = (nVals * nBits + 7) >> 3; + for (i = 0; i < n; ++i) { + str->getChar(); + } +} + +//------------------------------------------------------------------------ +// StreamPredictor +//------------------------------------------------------------------------ + +StreamPredictor::StreamPredictor(Stream *strA, int predictorA, + int widthA, int nCompsA, int nBitsA) { + str = strA; + predictor = predictorA; + width = widthA; + nComps = nCompsA; + nBits = nBitsA; + predLine = NULL; + ok = gFalse; + + nVals = width * nComps; + if (width <= 0 || nComps <= 0 || nBits <= 0 || + nComps > gfxColorMaxComps || nBits > 16 || + width >= INT_MAX / nComps || + nVals >= (INT_MAX - 7) / nBits) { + return; + } + pixBytes = (nComps * nBits + 7) >> 3; + rowBytes = ((nVals * nBits + 7) >> 3) + pixBytes; + if (rowBytes <= 0) { + return; + } + predLine = (Guchar *)gmalloc(rowBytes); + memset(predLine, 0, rowBytes); + predIdx = rowBytes; + + ok = gTrue; +} + +StreamPredictor::~StreamPredictor() { + gfree(predLine); +} + +int StreamPredictor::lookChar() { + if (predIdx >= rowBytes) { + if (!getNextLine()) { + return EOF; + } + } + return predLine[predIdx]; +} + +int StreamPredictor::getChar() { + if (predIdx >= rowBytes) { + if (!getNextLine()) { + return EOF; + } + } + return predLine[predIdx++]; +} + +GBool StreamPredictor::getNextLine() { + int curPred; + Guchar upLeftBuf[gfxColorMaxComps * 2 + 1]; + int left, up, upLeft, p, pa, pb, pc; + int c; + Gulong inBuf, outBuf, bitMask; + int inBits, outBits; + int i, j, k, kk; + + // get PNG optimum predictor number + if (predictor >= 10) { + if ((curPred = str->getRawChar()) == EOF) { + return gFalse; + } + curPred += 10; + } else { + curPred = predictor; + } + + // read the raw line, apply PNG (byte) predictor + memset(upLeftBuf, 0, pixBytes + 1); + for (i = pixBytes; i < rowBytes; ++i) { + for (j = pixBytes; j > 0; --j) { + upLeftBuf[j] = upLeftBuf[j-1]; + } + upLeftBuf[0] = predLine[i]; + if ((c = str->getRawChar()) == EOF) { + if (i > pixBytes) { + // this ought to return false, but some (broken) PDF files + // contain truncated image data, and Adobe apparently reads the + // last partial line + break; + } + return gFalse; + } + switch (curPred) { + case 11: // PNG sub + predLine[i] = predLine[i - pixBytes] + (Guchar)c; + break; + case 12: // PNG up + predLine[i] = predLine[i] + (Guchar)c; + break; + case 13: // PNG average + predLine[i] = ((predLine[i - pixBytes] + predLine[i]) >> 1) + + (Guchar)c; + break; + case 14: // PNG Paeth + left = predLine[i - pixBytes]; + up = predLine[i]; + upLeft = upLeftBuf[pixBytes]; + p = left + up - upLeft; + if ((pa = p - left) < 0) + pa = -pa; + if ((pb = p - up) < 0) + pb = -pb; + if ((pc = p - upLeft) < 0) + pc = -pc; + if (pa <= pb && pa <= pc) + predLine[i] = left + (Guchar)c; + else if (pb <= pc) + predLine[i] = up + (Guchar)c; + else + predLine[i] = upLeft + (Guchar)c; + break; + case 10: // PNG none + default: // no predictor or TIFF predictor + predLine[i] = (Guchar)c; + break; + } + } + + // apply TIFF (component) predictor + if (predictor == 2) { + if (nBits == 1) { + inBuf = predLine[pixBytes - 1]; + for (i = pixBytes; i < rowBytes; i += 8) { + // 1-bit add is just xor + inBuf = (inBuf << 8) | predLine[i]; + predLine[i] ^= inBuf >> nComps; + } + } else if (nBits == 8) { + for (i = pixBytes; i < rowBytes; ++i) { + predLine[i] += predLine[i - nComps]; + } + } else { + memset(upLeftBuf, 0, nComps + 1); + bitMask = (1 << nBits) - 1; + inBuf = outBuf = 0; + inBits = outBits = 0; + j = k = pixBytes; + for (i = 0; i < width; ++i) { + for (kk = 0; kk < nComps; ++kk) { + if (inBits < nBits) { + inBuf = (inBuf << 8) | (predLine[j++] & 0xff); + inBits += 8; + } + upLeftBuf[kk] = (Guchar)((upLeftBuf[kk] + + (inBuf >> (inBits - nBits))) & bitMask); + inBits -= nBits; + outBuf = (outBuf << nBits) | upLeftBuf[kk]; + outBits += nBits; + if (outBits >= 8) { + predLine[k++] = (Guchar)(outBuf >> (outBits - 8)); + outBits -= 8; + } + } + } + if (outBits > 0) { + predLine[k++] = (Guchar)((outBuf << (8 - outBits)) + + (inBuf & ((1 << (8 - outBits)) - 1))); + } + } + } + + // reset to start of line + predIdx = pixBytes; + + return gTrue; +} + +//------------------------------------------------------------------------ +// FileStream +//------------------------------------------------------------------------ + +FileStream::FileStream(FILE *fA, Guint startA, GBool limitedA, + Guint lengthA, Object *dictA): + BaseStream(dictA) { + f = fA; + start = startA; + limited = limitedA; + length = lengthA; + bufPtr = bufEnd = buf; + bufPos = start; + savePos = 0; + saved = gFalse; +} + +FileStream::~FileStream() { + close(); +} + +Stream *FileStream::makeSubStream(Guint startA, GBool limitedA, + Guint lengthA, Object *dictA) { + return new FileStream(f, startA, limitedA, lengthA, dictA); +} + +void FileStream::reset() { +#if HAVE_FSEEKO + savePos = (Guint)ftello(f); + fseeko(f, start, SEEK_SET); +#elif HAVE_FSEEK64 + savePos = (Guint)ftell64(f); + fseek64(f, start, SEEK_SET); +#else + savePos = (Guint)ftell(f); + fseek(f, start, SEEK_SET); +#endif + saved = gTrue; + bufPtr = bufEnd = buf; + bufPos = start; +} + +void FileStream::close() { + if (saved) { +#if HAVE_FSEEKO + fseeko(f, savePos, SEEK_SET); +#elif HAVE_FSEEK64 + fseek64(f, savePos, SEEK_SET); +#else + fseek(f, savePos, SEEK_SET); +#endif + saved = gFalse; + } +} + +GBool FileStream::fillBuf() { + int n; + + bufPos += bufEnd - buf; + bufPtr = bufEnd = buf; + if (limited && bufPos >= start + length) { + return gFalse; + } + if (limited && bufPos + fileStreamBufSize > start + length) { + n = start + length - bufPos; + } else { + n = fileStreamBufSize; + } + n = fread(buf, 1, n, f); + bufEnd = buf + n; + if (bufPtr >= bufEnd) { + return gFalse; + } + return gTrue; +} + +void FileStream::setPos(Guint pos, int dir) { + Guint size; + + if (dir >= 0) { +#if HAVE_FSEEKO + fseeko(f, pos, SEEK_SET); +#elif HAVE_FSEEK64 + fseek64(f, pos, SEEK_SET); +#else + fseek(f, pos, SEEK_SET); +#endif + bufPos = pos; + } else { +#if HAVE_FSEEKO + fseeko(f, 0, SEEK_END); + size = (Guint)ftello(f); +#elif HAVE_FSEEK64 + fseek64(f, 0, SEEK_END); + size = (Guint)ftell64(f); +#else + fseek(f, 0, SEEK_END); + size = (Guint)ftell(f); +#endif + if (pos > size) + pos = (Guint)size; +#ifdef __CYGWIN32__ + //~ work around a bug in cygwin's implementation of fseek + rewind(f); +#endif +#if HAVE_FSEEKO + fseeko(f, -(int)pos, SEEK_END); + bufPos = (Guint)ftello(f); +#elif HAVE_FSEEK64 + fseek64(f, -(int)pos, SEEK_END); + bufPos = (Guint)ftell64(f); +#else + fseek(f, -(int)pos, SEEK_END); + bufPos = (Guint)ftell(f); +#endif + } + bufPtr = bufEnd = buf; +} + +void FileStream::moveStart(int delta) { + start += delta; + bufPtr = bufEnd = buf; + bufPos = start; +} + +//------------------------------------------------------------------------ +// MemStream +//------------------------------------------------------------------------ + +MemStream::MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA): + BaseStream(dictA) { + buf = bufA; + start = startA; + length = lengthA; + bufEnd = buf + start + length; + bufPtr = buf + start; + needFree = gFalse; +} + +MemStream::~MemStream() { + if (needFree) { + gfree(buf); + } +} + +Stream *MemStream::makeSubStream(Guint startA, GBool limited, + Guint lengthA, Object *dictA) { + MemStream *subStr; + Guint newLength; + + if (!limited || startA + lengthA > start + length) { + newLength = start + length - startA; + } else { + newLength = lengthA; + } + subStr = new MemStream(buf, startA, newLength, dictA); + return subStr; +} + +void MemStream::reset() { + bufPtr = buf + start; +} + +void MemStream::close() { +} + +void MemStream::setPos(Guint pos, int dir) { + Guint i; + + if (dir >= 0) { + i = pos; + } else { + i = start + length - pos; + } + if (i < start) { + i = start; + } else if (i > start + length) { + i = start + length; + } + bufPtr = buf + i; +} + +void MemStream::moveStart(int delta) { + start += delta; + length -= delta; + bufPtr = buf + start; +} + +//------------------------------------------------------------------------ +// EmbedStream +//------------------------------------------------------------------------ + +EmbedStream::EmbedStream(Stream *strA, Object *dictA, + GBool limitedA, Guint lengthA): + BaseStream(dictA) { + str = strA; + limited = limitedA; + length = lengthA; +} + +EmbedStream::~EmbedStream() { +} + +Stream *EmbedStream::makeSubStream(Guint /*start*/, GBool /*limitedA*/, + Guint /*lengthA*/, Object * /*dictA*/) { + error(-1, "Internal: called makeSubStream() on EmbedStream"); + return NULL; +} + +int EmbedStream::getChar() { + if (limited && !length) { + return EOF; + } + --length; + return str->getChar(); +} + +int EmbedStream::lookChar() { + if (limited && !length) { + return EOF; + } + return str->lookChar(); +} + +void EmbedStream::setPos(Guint /*pos*/, int /*dir*/) { + error(-1, "Internal: called setPos() on EmbedStream"); +} + +Guint EmbedStream::getStart() { + error(-1, "Internal: called getStart() on EmbedStream"); + return 0; +} + +void EmbedStream::moveStart(int /*delta*/) { + error(-1, "Internal: called moveStart() on EmbedStream"); +} + +//------------------------------------------------------------------------ +// ASCIIHexStream +//------------------------------------------------------------------------ + +ASCIIHexStream::ASCIIHexStream(Stream *strA): + FilterStream(strA) { + buf = EOF; + eof = gFalse; +} + +ASCIIHexStream::~ASCIIHexStream() { + delete str; +} + +void ASCIIHexStream::reset() { + str->reset(); + buf = EOF; + eof = gFalse; +} + +int ASCIIHexStream::lookChar() { + int c1, c2, x; + + if (buf != EOF) + return buf; + if (eof) { + buf = EOF; + return EOF; + } + do { + c1 = str->getChar(); + } while (isspace(c1)); + if (c1 == '>') { + eof = gTrue; + buf = EOF; + return buf; + } + do { + c2 = str->getChar(); + } while (isspace(c2)); + if (c2 == '>') { + eof = gTrue; + c2 = '0'; + } + if (c1 >= '0' && c1 <= '9') { + x = (c1 - '0') << 4; + } else if (c1 >= 'A' && c1 <= 'F') { + x = (c1 - 'A' + 10) << 4; + } else if (c1 >= 'a' && c1 <= 'f') { + x = (c1 - 'a' + 10) << 4; + } else if (c1 == EOF) { + eof = gTrue; + x = 0; + } else { + error(getPos(), "Illegal character <%02x> in ASCIIHex stream", c1); + x = 0; + } + if (c2 >= '0' && c2 <= '9') { + x += c2 - '0'; + } else if (c2 >= 'A' && c2 <= 'F') { + x += c2 - 'A' + 10; + } else if (c2 >= 'a' && c2 <= 'f') { + x += c2 - 'a' + 10; + } else if (c2 == EOF) { + eof = gTrue; + x = 0; + } else { + error(getPos(), "Illegal character <%02x> in ASCIIHex stream", c2); + } + buf = x & 0xff; + return buf; +} + +GString *ASCIIHexStream::getPSFilter(int psLevel, char *indent) { + GString *s; + + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { + return NULL; + } + s->append(indent)->append("/ASCIIHexDecode filter\n"); + return s; +} + +GBool ASCIIHexStream::isBinary(GBool /*last*/) { + return str->isBinary(gFalse); +} + +//------------------------------------------------------------------------ +// ASCII85Stream +//------------------------------------------------------------------------ + +ASCII85Stream::ASCII85Stream(Stream *strA): + FilterStream(strA) { + index = n = 0; + eof = gFalse; +} + +ASCII85Stream::~ASCII85Stream() { + delete str; +} + +void ASCII85Stream::reset() { + str->reset(); + index = n = 0; + eof = gFalse; +} + +int ASCII85Stream::lookChar() { + int k; + Gulong t; + + if (index >= n) { + if (eof) + return EOF; + index = 0; + do { + c[0] = str->getChar(); + } while (Lexer::isSpace(c[0])); + if (c[0] == '~' || c[0] == EOF) { + eof = gTrue; + n = 0; + return EOF; + } else if (c[0] == 'z') { + b[0] = b[1] = b[2] = b[3] = 0; + n = 4; + } else { + for (k = 1; k < 5; ++k) { + do { + c[k] = str->getChar(); + } while (Lexer::isSpace(c[k])); + if (c[k] == '~' || c[k] == EOF) + break; + } + n = k - 1; + if (k < 5 && (c[k] == '~' || c[k] == EOF)) { + for (++k; k < 5; ++k) + c[k] = 0x21 + 84; + eof = gTrue; + } + t = 0; + for (k = 0; k < 5; ++k) + t = t * 85 + (c[k] - 0x21); + for (k = 3; k >= 0; --k) { + b[k] = (int)(t & 0xff); + t >>= 8; + } + } + } + return b[index]; +} + +GString *ASCII85Stream::getPSFilter(int psLevel, char *indent) { + GString *s; + + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { + return NULL; + } + s->append(indent)->append("/ASCII85Decode filter\n"); + return s; +} + +GBool ASCII85Stream::isBinary(GBool /*last*/) { + return str->isBinary(gFalse); +} + +//------------------------------------------------------------------------ +// LZWStream +//------------------------------------------------------------------------ + +LZWStream::LZWStream(Stream *strA, int predictor, int columns, int colors, + int bits, int earlyA): + FilterStream(strA) { + if (predictor != 1) { + pred = new StreamPredictor(this, predictor, columns, colors, bits); + if (!pred->isOk()) { + delete pred; + pred = NULL; + } + } else { + pred = NULL; + } + early = earlyA; + eof = gFalse; + inputBits = 0; + clearTable(); +} + +LZWStream::~LZWStream() { + if (pred) { + delete pred; + } + delete str; +} + +int LZWStream::getChar() { + if (pred) { + return pred->getChar(); + } + if (eof) { + return EOF; + } + if (seqIndex >= seqLength) { + if (!processNextCode()) { + return EOF; + } + } + return seqBuf[seqIndex++]; +} + +int LZWStream::lookChar() { + if (pred) { + return pred->lookChar(); + } + if (eof) { + return EOF; + } + if (seqIndex >= seqLength) { + if (!processNextCode()) { + return EOF; + } + } + return seqBuf[seqIndex]; +} + +int LZWStream::getRawChar() { + if (eof) { + return EOF; + } + if (seqIndex >= seqLength) { + if (!processNextCode()) { + return EOF; + } + } + return seqBuf[seqIndex++]; +} + +void LZWStream::reset() { + str->reset(); + eof = gFalse; + inputBits = 0; + clearTable(); +} + +GBool LZWStream::processNextCode() { + int code; + int nextLength; + int i, j; + + // check for EOF + if (eof) { + return gFalse; + } + + // check for eod and clear-table codes + start: + code = getCode(); + if (code == EOF || code == 257) { + eof = gTrue; + return gFalse; + } + if (code == 256) { + clearTable(); + goto start; + } + if (nextCode >= 4097) { + error(getPos(), "Bad LZW stream - expected clear-table code"); + clearTable(); + } + + // process the next code + nextLength = seqLength + 1; + if (code < 256) { + seqBuf[0] = code; + seqLength = 1; + } else if (code < nextCode) { + seqLength = table[code].length; + for (i = seqLength - 1, j = code; i > 0; --i) { + seqBuf[i] = table[j].tail; + j = table[j].head; + } + seqBuf[0] = j; + } else if (code == nextCode) { + seqBuf[seqLength] = newChar; + ++seqLength; + } else { + error(getPos(), "Bad LZW stream - unexpected code"); + eof = gTrue; + return gFalse; + } + newChar = seqBuf[0]; + if (first) { + first = gFalse; + } else { + table[nextCode].length = nextLength; + table[nextCode].head = prevCode; + table[nextCode].tail = newChar; + ++nextCode; + if (nextCode + early == 512) + nextBits = 10; + else if (nextCode + early == 1024) + nextBits = 11; + else if (nextCode + early == 2048) + nextBits = 12; + } + prevCode = code; + + // reset buffer + seqIndex = 0; + + return gTrue; +} + +void LZWStream::clearTable() { + nextCode = 258; + nextBits = 9; + seqIndex = seqLength = 0; + first = gTrue; +} + +int LZWStream::getCode() { + int c; + int code; + + while (inputBits < nextBits) { + if ((c = str->getChar()) == EOF) + return EOF; + inputBuf = (inputBuf << 8) | (c & 0xff); + inputBits += 8; + } + code = (inputBuf >> (inputBits - nextBits)) & ((1 << nextBits) - 1); + inputBits -= nextBits; + return code; +} + +GString *LZWStream::getPSFilter(int psLevel, char *indent) { + GString *s; + + if (psLevel < 2 || pred) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { + return NULL; + } + s->append(indent)->append("<< "); + if (!early) { + s->append("/EarlyChange 0 "); + } + s->append(">> /LZWDecode filter\n"); + return s; +} + +GBool LZWStream::isBinary(GBool /*last*/) { + return str->isBinary(gTrue); +} + +//------------------------------------------------------------------------ +// RunLengthStream +//------------------------------------------------------------------------ + +RunLengthStream::RunLengthStream(Stream *strA): + FilterStream(strA) { + bufPtr = bufEnd = buf; + eof = gFalse; +} + +RunLengthStream::~RunLengthStream() { + delete str; +} + +void RunLengthStream::reset() { + str->reset(); + bufPtr = bufEnd = buf; + eof = gFalse; +} + +GString *RunLengthStream::getPSFilter(int psLevel, char *indent) { + GString *s; + + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { + return NULL; + } + s->append(indent)->append("/RunLengthDecode filter\n"); + return s; +} + +GBool RunLengthStream::isBinary(GBool /*last*/) { + return str->isBinary(gTrue); +} + +GBool RunLengthStream::fillBuf() { + int c; + int n, i; + + if (eof) + return gFalse; + c = str->getChar(); + if (c == 0x80 || c == EOF) { + eof = gTrue; + return gFalse; + } + if (c < 0x80) { + n = c + 1; + for (i = 0; i < n; ++i) + buf[i] = (char)str->getChar(); + } else { + n = 0x101 - c; + c = str->getChar(); + for (i = 0; i < n; ++i) + buf[i] = (char)c; + } + bufPtr = buf; + bufEnd = buf + n; + return gTrue; +} + +//------------------------------------------------------------------------ +// CCITTFaxStream +//------------------------------------------------------------------------ + +CCITTFaxStream::CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA, + GBool byteAlignA, int columnsA, int rowsA, + GBool endOfBlockA, GBool blackA): + FilterStream(strA) { + encoding = encodingA; + endOfLine = endOfLineA; + byteAlign = byteAlignA; + columns = columnsA; + if (columns < 1) { + columns = 1; + } else if (columns > INT_MAX - 2) { + columns = INT_MAX - 2; + } + rows = rowsA; + endOfBlock = endOfBlockA; + black = blackA; + // 0 <= codingLine[0] < codingLine[1] < ... < codingLine[n] = columns + // ---> max codingLine size = columns + 1 + // refLine has one extra guard entry at the end + // ---> max refLine size = columns + 2 + codingLine = (int *)gmallocn_checkoverflow(columns + 1, sizeof(int)); + refLine = (int *)gmallocn_checkoverflow(columns + 2, sizeof(int)); + + if (codingLine != NULL && refLine != NULL) { + eof = gFalse; + codingLine[0] = columns; + } else { + eof = gTrue; + } + row = 0; + nextLine2D = encoding < 0; + inputBits = 0; + a0i = 0; + outputBits = 0; + + buf = EOF; +} + +CCITTFaxStream::~CCITTFaxStream() { + delete str; + gfree(refLine); + gfree(codingLine); +} + +void CCITTFaxStream::reset() { + short code1; + + str->reset(); + + if (codingLine != NULL && refLine != NULL) { + eof = gFalse; + codingLine[0] = columns; + } else { + eof = gTrue; + } + row = 0; + nextLine2D = encoding < 0; + inputBits = 0; + a0i = 0; + outputBits = 0; + buf = EOF; + + // skip any initial zero bits and end-of-line marker, and get the 2D + // encoding tag + while ((code1 = lookBits(12)) == 0) { + eatBits(1); + } + if (code1 == 0x001) { + eatBits(12); + } + if (encoding > 0) { + nextLine2D = !lookBits(1); + eatBits(1); + } +} + +inline void CCITTFaxStream::addPixels(int a1, int blackPixels) { + if (a1 > codingLine[a0i]) { + if (a1 > columns) { + error(getPos(), "CCITTFax row is wrong length (%d)", a1); + err = gTrue; + a1 = columns; + } + if ((a0i & 1) ^ blackPixels) { + ++a0i; + } + codingLine[a0i] = a1; + } +} + +inline void CCITTFaxStream::addPixelsNeg(int a1, int blackPixels) { + if (a1 > codingLine[a0i]) { + if (a1 > columns) { + error(getPos(), "CCITTFax row is wrong length (%d)", a1); + err = gTrue; + a1 = columns; + } + if ((a0i & 1) ^ blackPixels) { + ++a0i; + } + codingLine[a0i] = a1; + } else if (a1 < codingLine[a0i]) { + if (a1 < 0) { + error(getPos(), "Invalid CCITTFax code"); + err = gTrue; + a1 = 0; + } + while (a0i > 0 && a1 <= codingLine[a0i - 1]) { + --a0i; + } + codingLine[a0i] = a1; + } +} + +int CCITTFaxStream::lookChar() { + short code1, code2, code3; + int b1i, blackPixels, i, bits; + GBool gotEOL; + + if (buf != EOF) { + return buf; + } + + // read the next row + if (outputBits == 0) { + + // if at eof just return EOF + if (eof) { + return EOF; + } + + err = gFalse; + + // 2-D encoding + if (nextLine2D) { + for (i = 0; codingLine[i] < columns; ++i) { + refLine[i] = codingLine[i]; + } + refLine[i++] = columns; + refLine[i] = columns; + codingLine[0] = 0; + a0i = 0; + b1i = 0; + blackPixels = 0; + // invariant: + // refLine[b1i-1] <= codingLine[a0i] < refLine[b1i] < refLine[b1i+1] + // <= columns + // exception at left edge: + // codingLine[a0i = 0] = refLine[b1i = 0] = 0 is possible + // exception at right edge: + // refLine[b1i] = refLine[b1i+1] = columns is possible + while (codingLine[a0i] < columns) { + code1 = getTwoDimCode(); + switch (code1) { + case twoDimPass: + addPixels(refLine[b1i + 1], blackPixels); + if (refLine[b1i + 1] < columns) { + b1i += 2; + } + break; + case twoDimHoriz: + code1 = code2 = 0; + if (blackPixels) { + do { + code1 += code3 = getBlackCode(); + } while (code3 >= 64); + do { + code2 += code3 = getWhiteCode(); + } while (code3 >= 64); + } else { + do { + code1 += code3 = getWhiteCode(); + } while (code3 >= 64); + do { + code2 += code3 = getBlackCode(); + } while (code3 >= 64); + } + addPixels(codingLine[a0i] + code1, blackPixels); + if (codingLine[a0i] < columns) { + addPixels(codingLine[a0i] + code2, blackPixels ^ 1); + } + while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { + b1i += 2; + } + break; + case twoDimVertR3: + addPixels(refLine[b1i] + 3, blackPixels); + blackPixels ^= 1; + if (codingLine[a0i] < columns) { + ++b1i; + while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { + b1i += 2; + } + } + break; + case twoDimVertR2: + addPixels(refLine[b1i] + 2, blackPixels); + blackPixels ^= 1; + if (codingLine[a0i] < columns) { + ++b1i; + while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { + b1i += 2; + } + } + break; + case twoDimVertR1: + addPixels(refLine[b1i] + 1, blackPixels); + blackPixels ^= 1; + if (codingLine[a0i] < columns) { + ++b1i; + while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { + b1i += 2; + } + } + break; + case twoDimVert0: + addPixels(refLine[b1i], blackPixels); + blackPixels ^= 1; + if (codingLine[a0i] < columns) { + ++b1i; + while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { + b1i += 2; + } + } + break; + case twoDimVertL3: + addPixelsNeg(refLine[b1i] - 3, blackPixels); + blackPixels ^= 1; + if (codingLine[a0i] < columns) { + if (b1i > 0) { + --b1i; + } else { + ++b1i; + } + while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { + b1i += 2; + } + } + break; + case twoDimVertL2: + addPixelsNeg(refLine[b1i] - 2, blackPixels); + blackPixels ^= 1; + if (codingLine[a0i] < columns) { + if (b1i > 0) { + --b1i; + } else { + ++b1i; + } + while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { + b1i += 2; + } + } + break; + case twoDimVertL1: + addPixelsNeg(refLine[b1i] - 1, blackPixels); + blackPixels ^= 1; + if (codingLine[a0i] < columns) { + if (b1i > 0) { + --b1i; + } else { + ++b1i; + } + while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { + b1i += 2; + } + } + break; + case EOF: + addPixels(columns, 0); + eof = gTrue; + break; + default: + error(getPos(), "Bad 2D code %04x in CCITTFax stream", code1); + addPixels(columns, 0); + err = gTrue; + break; + } + } + + // 1-D encoding + } else { + codingLine[0] = 0; + a0i = 0; + blackPixels = 0; + while (codingLine[a0i] < columns) { + code1 = 0; + if (blackPixels) { + do { + code1 += code3 = getBlackCode(); + } while (code3 >= 64); + } else { + do { + code1 += code3 = getWhiteCode(); + } while (code3 >= 64); + } + addPixels(codingLine[a0i] + code1, blackPixels); + blackPixels ^= 1; + } + } + + // byte-align the row + if (byteAlign) { + inputBits &= ~7; + } + + // check for end-of-line marker, skipping over any extra zero bits + gotEOL = gFalse; + if (!endOfBlock && row == rows - 1) { + eof = gTrue; + } else { + code1 = lookBits(12); + while (code1 == 0) { + eatBits(1); + code1 = lookBits(12); + } + if (code1 == 0x001) { + eatBits(12); + gotEOL = gTrue; + } else if (code1 == EOF) { + eof = gTrue; + } + } + + // get 2D encoding tag + if (!eof && encoding > 0) { + nextLine2D = !lookBits(1); + eatBits(1); + } + + // check for end-of-block marker + if (endOfBlock && gotEOL) { + code1 = lookBits(12); + if (code1 == 0x001) { + eatBits(12); + if (encoding > 0) { + lookBits(1); + eatBits(1); + } + if (encoding >= 0) { + for (i = 0; i < 4; ++i) { + code1 = lookBits(12); + if (code1 != 0x001) { + error(getPos(), "Bad RTC code in CCITTFax stream"); + } + eatBits(12); + if (encoding > 0) { + lookBits(1); + eatBits(1); + } + } + } + eof = gTrue; + } + + // look for an end-of-line marker after an error -- we only do + // this if we know the stream contains end-of-line markers because + // the "just plow on" technique tends to work better otherwise + } else if (err && endOfLine) { + while (1) { + code1 = lookBits(13); + if (code1 == EOF) { + eof = gTrue; + return EOF; + } + if ((code1 >> 1) == 0x001) { + break; + } + eatBits(1); + } + eatBits(12); + if (encoding > 0) { + eatBits(1); + nextLine2D = !(code1 & 1); + } + } + + // set up for output + if (codingLine[0] > 0) { + outputBits = codingLine[a0i = 0]; + } else { + outputBits = codingLine[a0i = 1]; + } + + ++row; + } + + // get a byte + if (outputBits >= 8) { + buf = (a0i & 1) ? 0x00 : 0xff; + outputBits -= 8; + if (outputBits == 0 && codingLine[a0i] < columns) { + ++a0i; + outputBits = codingLine[a0i] - codingLine[a0i - 1]; + } + } else { + bits = 8; + buf = 0; + do { + if (outputBits > bits) { + buf <<= bits; + if (!(a0i & 1)) { + buf |= 0xff >> (8 - bits); + } + outputBits -= bits; + bits = 0; + } else { + buf <<= outputBits; + if (!(a0i & 1)) { + buf |= 0xff >> (8 - outputBits); + } + bits -= outputBits; + outputBits = 0; + if (codingLine[a0i] < columns) { + ++a0i; + outputBits = codingLine[a0i] - codingLine[a0i - 1]; + } else if (bits > 0) { + buf <<= bits; + bits = 0; + } + } + } while (bits); + } + if (black) { + buf ^= 0xff; + } + return buf; +} + +short CCITTFaxStream::getTwoDimCode() { + short code; + CCITTCode *p; + int n; + + code = 0; // make gcc happy + if (endOfBlock) { + code = lookBits(7); + p = &twoDimTab1[code]; + if (p->bits > 0) { + eatBits(p->bits); + return p->n; + } + } else { + for (n = 1; n <= 7; ++n) { + code = lookBits(n); + if (n < 7) { + code <<= 7 - n; + } + p = &twoDimTab1[code]; + if (p->bits == n) { + eatBits(n); + return p->n; + } + } + } + error(getPos(), "Bad two dim code (%04x) in CCITTFax stream", code); + return EOF; +} + +short CCITTFaxStream::getWhiteCode() { + short code; + CCITTCode *p; + int n; + + code = 0; // make gcc happy + if (endOfBlock) { + code = lookBits(12); + if (code == EOF) { + return 1; + } + if ((code >> 5) == 0) { + p = &whiteTab1[code]; + } else { + p = &whiteTab2[code >> 3]; + } + if (p->bits > 0) { + eatBits(p->bits); + return p->n; + } + } else { + for (n = 1; n <= 9; ++n) { + code = lookBits(n); + if (code == EOF) { + return 1; + } + if (n < 9) { + code <<= 9 - n; + } + p = &whiteTab2[code]; + if (p->bits == n) { + eatBits(n); + return p->n; + } + } + for (n = 11; n <= 12; ++n) { + code = lookBits(n); + if (code == EOF) { + return 1; + } + if (n < 12) { + code <<= 12 - n; + } + p = &whiteTab1[code]; + if (p->bits == n) { + eatBits(n); + return p->n; + } + } + } + error(getPos(), "Bad white code (%04x) in CCITTFax stream", code); + // eat a bit and return a positive number so that the caller doesn't + // go into an infinite loop + eatBits(1); + return 1; +} + +short CCITTFaxStream::getBlackCode() { + short code; + CCITTCode *p; + int n; + + code = 0; // make gcc happy + if (endOfBlock) { + code = lookBits(13); + if (code == EOF) { + return 1; + } + if ((code >> 7) == 0) { + p = &blackTab1[code]; + } else if ((code >> 9) == 0 && (code >> 7) != 0) { + p = &blackTab2[(code >> 1) - 64]; + } else { + p = &blackTab3[code >> 7]; + } + if (p->bits > 0) { + eatBits(p->bits); + return p->n; + } + } else { + for (n = 2; n <= 6; ++n) { + code = lookBits(n); + if (code == EOF) { + return 1; + } + if (n < 6) { + code <<= 6 - n; + } + p = &blackTab3[code]; + if (p->bits == n) { + eatBits(n); + return p->n; + } + } + for (n = 7; n <= 12; ++n) { + code = lookBits(n); + if (code == EOF) { + return 1; + } + if (n < 12) { + code <<= 12 - n; + } + if (code >= 64) { + p = &blackTab2[code - 64]; + if (p->bits == n) { + eatBits(n); + return p->n; + } + } + } + for (n = 10; n <= 13; ++n) { + code = lookBits(n); + if (code == EOF) { + return 1; + } + if (n < 13) { + code <<= 13 - n; + } + p = &blackTab1[code]; + if (p->bits == n) { + eatBits(n); + return p->n; + } + } + } + error(getPos(), "Bad black code (%04x) in CCITTFax stream", code); + // eat a bit and return a positive number so that the caller doesn't + // go into an infinite loop + eatBits(1); + return 1; +} + +short CCITTFaxStream::lookBits(int n) { + int c; + + while (inputBits < n) { + if ((c = str->getChar()) == EOF) { + if (inputBits == 0) { + return EOF; + } + // near the end of the stream, the caller may ask for more bits + // than are available, but there may still be a valid code in + // however many bits are available -- we need to return correct + // data in this case + return (inputBuf << (n - inputBits)) & (0xffff >> (16 - n)); + } + inputBuf = (inputBuf << 8) + c; + inputBits += 8; + } + return (inputBuf >> (inputBits - n)) & (0xffff >> (16 - n)); +} + +GString *CCITTFaxStream::getPSFilter(int psLevel, char *indent) { + GString *s; + char s1[50]; + + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { + return NULL; + } + s->append(indent)->append("<< "); + if (encoding != 0) { + sprintf(s1, "/K %d ", encoding); + s->append(s1); + } + if (endOfLine) { + s->append("/EndOfLine true "); + } + if (byteAlign) { + s->append("/EncodedByteAlign true "); + } + sprintf(s1, "/Columns %d ", columns); + s->append(s1); + if (rows != 0) { + sprintf(s1, "/Rows %d ", rows); + s->append(s1); + } + if (!endOfBlock) { + s->append("/EndOfBlock false "); + } + if (black) { + s->append("/BlackIs1 true "); + } + s->append(">> /CCITTFaxDecode filter\n"); + return s; +} + +GBool CCITTFaxStream::isBinary(GBool /*last*/) { + return str->isBinary(gTrue); +} + +//------------------------------------------------------------------------ +// DCTStream +//------------------------------------------------------------------------ + +// IDCT constants (20.12 fixed point format) +#define dctCos1 4017 // cos(pi/16) +#define dctSin1 799 // sin(pi/16) +#define dctCos3 3406 // cos(3*pi/16) +#define dctSin3 2276 // sin(3*pi/16) +#define dctCos6 1567 // cos(6*pi/16) +#define dctSin6 3784 // sin(6*pi/16) +#define dctSqrt2 5793 // sqrt(2) +#define dctSqrt1d2 2896 // sqrt(2) / 2 + +// color conversion parameters (16.16 fixed point format) +#define dctCrToR 91881 // 1.4020 +#define dctCbToG -22553 // -0.3441363 +#define dctCrToG -46802 // -0.71413636 +#define dctCbToB 116130 // 1.772 + +// clip [-256,511] --> [0,255] +#define dctClipOffset 256 +static Guchar dctClip[768]; +static int dctClipInit = 0; + +// zig zag decode map +static int dctZigZag[64] = { + 0, + 1, 8, + 16, 9, 2, + 3, 10, 17, 24, + 32, 25, 18, 11, 4, + 5, 12, 19, 26, 33, 40, + 48, 41, 34, 27, 20, 13, 6, + 7, 14, 21, 28, 35, 42, 49, 56, + 57, 50, 43, 36, 29, 22, 15, + 23, 30, 37, 44, 51, 58, + 59, 52, 45, 38, 31, + 39, 46, 53, 60, + 61, 54, 47, + 55, 62, + 63 +}; + +DCTStream::DCTStream(Stream *strA, GBool colorXformA): + FilterStream(strA) { + int i, j; + + colorXform = colorXformA; + progressive = interleaved = gFalse; + width = height = 0; + mcuWidth = mcuHeight = 0; + numComps = 0; + comp = 0; + x = y = dy = 0; + for (i = 0; i < 4; ++i) { + for (j = 0; j < 32; ++j) { + rowBuf[i][j] = NULL; + } + frameBuf[i] = NULL; + } + + if (!dctClipInit) { + for (i = -256; i < 0; ++i) + dctClip[dctClipOffset + i] = 0; + for (i = 0; i < 256; ++i) + dctClip[dctClipOffset + i] = i; + for (i = 256; i < 512; ++i) + dctClip[dctClipOffset + i] = 255; + dctClipInit = 1; + } +} + +DCTStream::~DCTStream() { + close(); + delete str; +} + +void DCTStream::reset() { + int i, j; + + str->reset(); + + progressive = interleaved = gFalse; + width = height = 0; + numComps = 0; + numQuantTables = 0; + numDCHuffTables = 0; + numACHuffTables = 0; + gotJFIFMarker = gFalse; + gotAdobeMarker = gFalse; + restartInterval = 0; + + if (!readHeader()) { + y = height; + return; + } + + // compute MCU size + if (numComps == 1) { + compInfo[0].hSample = compInfo[0].vSample = 1; + } + mcuWidth = compInfo[0].hSample; + mcuHeight = compInfo[0].vSample; + for (i = 1; i < numComps; ++i) { + if (compInfo[i].hSample > mcuWidth) { + mcuWidth = compInfo[i].hSample; + } + if (compInfo[i].vSample > mcuHeight) { + mcuHeight = compInfo[i].vSample; + } + } + mcuWidth *= 8; + mcuHeight *= 8; + + // figure out color transform + if (colorXform == -1) { + if (numComps == 3) { + if (gotJFIFMarker) { + colorXform = 1; + } else if (compInfo[0].id == 82 && compInfo[1].id == 71 && + compInfo[2].id == 66) { // ASCII "RGB" + colorXform = 0; + } else { + colorXform = 1; + } + } else { + colorXform = 0; + } + } + + if (progressive || !interleaved) { + + // allocate a buffer for the whole image + bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; + bufHeight = ((height + mcuHeight - 1) / mcuHeight) * mcuHeight; + if (bufWidth <= 0 || bufHeight <= 0 || + bufWidth > INT_MAX / bufWidth / (int)sizeof(int)) { + error(getPos(), "Invalid image size in DCT stream"); + y = height; + return; + } + for (i = 0; i < numComps; ++i) { + frameBuf[i] = (int *)gmallocn(bufWidth * bufHeight, sizeof(int)); + memset(frameBuf[i], 0, bufWidth * bufHeight * sizeof(int)); + } + + // read the image data + do { + restartMarker = 0xd0; + restart(); + readScan(); + } while (readHeader()); + + // decode + decodeImage(); + + // initialize counters + comp = 0; + x = 0; + y = 0; + + } else { + + // allocate a buffer for one row of MCUs + bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; + for (i = 0; i < numComps; ++i) { + for (j = 0; j < mcuHeight; ++j) { + rowBuf[i][j] = (Guchar *)gmallocn(bufWidth, sizeof(Guchar)); + } + } + + // initialize counters + comp = 0; + x = 0; + y = 0; + dy = mcuHeight; + + restartMarker = 0xd0; + restart(); + } +} + +void DCTStream::close() { + int i, j; + + for (i = 0; i < 4; ++i) { + for (j = 0; j < 32; ++j) { + gfree(rowBuf[i][j]); + rowBuf[i][j] = NULL; + } + gfree(frameBuf[i]); + frameBuf[i] = NULL; + } + FilterStream::close(); +} + +int DCTStream::getChar() { + int c; + + if (y >= height) { + return EOF; + } + if (progressive || !interleaved) { + c = frameBuf[comp][y * bufWidth + x]; + if (++comp == numComps) { + comp = 0; + if (++x == width) { + x = 0; + ++y; + } + } + } else { + if (dy >= mcuHeight) { + if (!readMCURow()) { + y = height; + return EOF; + } + comp = 0; + x = 0; + dy = 0; + } + c = rowBuf[comp][dy][x]; + if (++comp == numComps) { + comp = 0; + if (++x == width) { + x = 0; + ++y; + ++dy; + if (y == height) { + readTrailer(); + } + } + } + } + return c; +} + +int DCTStream::lookChar() { + if (y >= height) { + return EOF; + } + if (progressive || !interleaved) { + return frameBuf[comp][y * bufWidth + x]; + } else { + if (dy >= mcuHeight) { + if (!readMCURow()) { + y = height; + return EOF; + } + comp = 0; + x = 0; + dy = 0; + } + return rowBuf[comp][dy][x]; + } +} + +void DCTStream::restart() { + int i; + + inputBits = 0; + restartCtr = restartInterval; + for (i = 0; i < numComps; ++i) { + compInfo[i].prevDC = 0; + } + eobRun = 0; +} + +// Read one row of MCUs from a sequential JPEG stream. +GBool DCTStream::readMCURow() { + int data1[64]; + Guchar data2[64]; + Guchar *p1, *p2; + int pY, pCb, pCr, pR, pG, pB; + int h, v, horiz, vert, hSub, vSub; + int x1, x2, y2, x3, y3, x4, y4, x5, y5, cc, i; + int c; + + for (x1 = 0; x1 < width; x1 += mcuWidth) { + + // deal with restart marker + if (restartInterval > 0 && restartCtr == 0) { + c = readMarker(); + if (c != restartMarker) { + error(getPos(), "Bad DCT data: incorrect restart marker"); + return gFalse; + } + if (++restartMarker == 0xd8) + restartMarker = 0xd0; + restart(); + } + + // read one MCU + for (cc = 0; cc < numComps; ++cc) { + h = compInfo[cc].hSample; + v = compInfo[cc].vSample; + horiz = mcuWidth / h; + vert = mcuHeight / v; + hSub = horiz / 8; + vSub = vert / 8; + for (y2 = 0; y2 < mcuHeight; y2 += vert) { + for (x2 = 0; x2 < mcuWidth; x2 += horiz) { + if (!readDataUnit(&dcHuffTables[scanInfo.dcHuffTable[cc]], + &acHuffTables[scanInfo.acHuffTable[cc]], + &compInfo[cc].prevDC, + data1)) { + return gFalse; + } + transformDataUnit(quantTables[compInfo[cc].quantTable], + data1, data2); + if (hSub == 1 && vSub == 1) { + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + p1 = &rowBuf[cc][y2+y3][x1+x2]; + p1[0] = data2[i]; + p1[1] = data2[i+1]; + p1[2] = data2[i+2]; + p1[3] = data2[i+3]; + p1[4] = data2[i+4]; + p1[5] = data2[i+5]; + p1[6] = data2[i+6]; + p1[7] = data2[i+7]; + } + } else if (hSub == 2 && vSub == 2) { + for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) { + p1 = &rowBuf[cc][y2+y3][x1+x2]; + p2 = &rowBuf[cc][y2+y3+1][x1+x2]; + p1[0] = p1[1] = p2[0] = p2[1] = data2[i]; + p1[2] = p1[3] = p2[2] = p2[3] = data2[i+1]; + p1[4] = p1[5] = p2[4] = p2[5] = data2[i+2]; + p1[6] = p1[7] = p2[6] = p2[7] = data2[i+3]; + p1[8] = p1[9] = p2[8] = p2[9] = data2[i+4]; + p1[10] = p1[11] = p2[10] = p2[11] = data2[i+5]; + p1[12] = p1[13] = p2[12] = p2[13] = data2[i+6]; + p1[14] = p1[15] = p2[14] = p2[15] = data2[i+7]; + } + } else { + i = 0; + for (y3 = 0, y4 = 0; y3 < 8; ++y3, y4 += vSub) { + for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) { + for (y5 = 0; y5 < vSub; ++y5) + for (x5 = 0; x5 < hSub; ++x5) + rowBuf[cc][y2+y4+y5][x1+x2+x4+x5] = data2[i]; + ++i; + } + } + } + } + } + } + --restartCtr; + + // color space conversion + if (colorXform) { + // convert YCbCr to RGB + if (numComps == 3) { + for (y2 = 0; y2 < mcuHeight; ++y2) { + for (x2 = 0; x2 < mcuWidth; ++x2) { + pY = rowBuf[0][y2][x1+x2]; + pCb = rowBuf[1][y2][x1+x2] - 128; + pCr = rowBuf[2][y2][x1+x2] - 128; + pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; + rowBuf[0][y2][x1+x2] = dctClip[dctClipOffset + pR]; + pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32768) >> 16; + rowBuf[1][y2][x1+x2] = dctClip[dctClipOffset + pG]; + pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; + rowBuf[2][y2][x1+x2] = dctClip[dctClipOffset + pB]; + } + } + // convert YCbCrK to CMYK (K is passed through unchanged) + } else if (numComps == 4) { + for (y2 = 0; y2 < mcuHeight; ++y2) { + for (x2 = 0; x2 < mcuWidth; ++x2) { + pY = rowBuf[0][y2][x1+x2]; + pCb = rowBuf[1][y2][x1+x2] - 128; + pCr = rowBuf[2][y2][x1+x2] - 128; + pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; + rowBuf[0][y2][x1+x2] = 255 - dctClip[dctClipOffset + pR]; + pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32768) >> 16; + rowBuf[1][y2][x1+x2] = 255 - dctClip[dctClipOffset + pG]; + pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; + rowBuf[2][y2][x1+x2] = 255 - dctClip[dctClipOffset + pB]; + } + } + } + } + } + return gTrue; +} + +// Read one scan from a progressive or non-interleaved JPEG stream. +void DCTStream::readScan() { + int data[64]; + int x1, y1, dx1, dy1, x2, y2, y3, cc, i; + int h, v, horiz, vert, vSub; + int *p1; + int c; + + if (scanInfo.numComps == 1) { + for (cc = 0; cc < numComps; ++cc) { + if (scanInfo.comp[cc]) { + break; + } + } + dx1 = mcuWidth / compInfo[cc].hSample; + dy1 = mcuHeight / compInfo[cc].vSample; + } else { + dx1 = mcuWidth; + dy1 = mcuHeight; + } + + for (y1 = 0; y1 < height; y1 += dy1) { + for (x1 = 0; x1 < width; x1 += dx1) { + + // deal with restart marker + if (restartInterval > 0 && restartCtr == 0) { + c = readMarker(); + if (c != restartMarker) { + error(getPos(), "Bad DCT data: incorrect restart marker"); + return; + } + if (++restartMarker == 0xd8) { + restartMarker = 0xd0; + } + restart(); + } + + // read one MCU + for (cc = 0; cc < numComps; ++cc) { + if (!scanInfo.comp[cc]) { + continue; + } + + h = compInfo[cc].hSample; + v = compInfo[cc].vSample; + horiz = mcuWidth / h; + vert = mcuHeight / v; + vSub = vert / 8; + for (y2 = 0; y2 < dy1; y2 += vert) { + for (x2 = 0; x2 < dx1; x2 += horiz) { + + // pull out the current values + p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + data[i] = p1[0]; + data[i+1] = p1[1]; + data[i+2] = p1[2]; + data[i+3] = p1[3]; + data[i+4] = p1[4]; + data[i+5] = p1[5]; + data[i+6] = p1[6]; + data[i+7] = p1[7]; + p1 += bufWidth * vSub; + } + + // read one data unit + if (progressive) { + if (!readProgressiveDataUnit( + &dcHuffTables[scanInfo.dcHuffTable[cc]], + &acHuffTables[scanInfo.acHuffTable[cc]], + &compInfo[cc].prevDC, + data)) { + return; + } + } else { + if (!readDataUnit(&dcHuffTables[scanInfo.dcHuffTable[cc]], + &acHuffTables[scanInfo.acHuffTable[cc]], + &compInfo[cc].prevDC, + data)) { + return; + } + } + + // add the data unit into frameBuf + p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + p1[0] = data[i]; + p1[1] = data[i+1]; + p1[2] = data[i+2]; + p1[3] = data[i+3]; + p1[4] = data[i+4]; + p1[5] = data[i+5]; + p1[6] = data[i+6]; + p1[7] = data[i+7]; + p1 += bufWidth * vSub; + } + } + } + } + --restartCtr; + } + } +} + +// Read one data unit from a sequential JPEG stream. +GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable, + DCTHuffTable *acHuffTable, + int *prevDC, int data[64]) { + int run, size, amp; + int c; + int i, j; + + if ((size = readHuffSym(dcHuffTable)) == 9999) { + return gFalse; + } + if (size > 0) { + if ((amp = readAmp(size)) == 9999) { + return gFalse; + } + } else { + amp = 0; + } + data[0] = *prevDC += amp; + for (i = 1; i < 64; ++i) { + data[i] = 0; + } + i = 1; + while (i < 64) { + run = 0; + while ((c = readHuffSym(acHuffTable)) == 0xf0 && run < 0x30) { + run += 0x10; + } + if (c == 9999) { + return gFalse; + } + if (c == 0x00) { + break; + } else { + run += (c >> 4) & 0x0f; + size = c & 0x0f; + amp = readAmp(size); + if (amp == 9999) { + return gFalse; + } + i += run; + if (i < 64) { + j = dctZigZag[i++]; + data[j] = amp; + } + } + } + return gTrue; +} + +// Read one data unit from a sequential JPEG stream. +GBool DCTStream::readProgressiveDataUnit(DCTHuffTable *dcHuffTable, + DCTHuffTable *acHuffTable, + int *prevDC, int data[64]) { + int run, size, amp, bit, c; + int i, j, k; + + // get the DC coefficient + i = scanInfo.firstCoeff; + if (i == 0) { + if (scanInfo.ah == 0) { + if ((size = readHuffSym(dcHuffTable)) == 9999) { + return gFalse; + } + if (size > 0) { + if ((amp = readAmp(size)) == 9999) { + return gFalse; + } + } else { + amp = 0; + } + data[0] += (*prevDC += amp) << scanInfo.al; + } else { + if ((bit = readBit()) == 9999) { + return gFalse; + } + data[0] += bit << scanInfo.al; + } + ++i; + } + if (scanInfo.lastCoeff == 0) { + return gTrue; + } + + // check for an EOB run + if (eobRun > 0) { + while (i <= scanInfo.lastCoeff) { + j = dctZigZag[i++]; + if (data[j] != 0) { + if ((bit = readBit()) == EOF) { + return gFalse; + } + if (bit) { + data[j] += 1 << scanInfo.al; + } + } + } + --eobRun; + return gTrue; + } + + // read the AC coefficients + while (i <= scanInfo.lastCoeff) { + if ((c = readHuffSym(acHuffTable)) == 9999) { + return gFalse; + } + + // ZRL + if (c == 0xf0) { + k = 0; + while (k < 16) { + j = dctZigZag[i++]; + if (data[j] == 0) { + ++k; + } else { + if ((bit = readBit()) == EOF) { + return gFalse; + } + if (bit) { + data[j] += 1 << scanInfo.al; + } + } + } + + // EOB run + } else if ((c & 0x0f) == 0x00) { + j = c >> 4; + eobRun = 0; + for (k = 0; k < j; ++k) { + if ((bit = readBit()) == EOF) { + return gFalse; + } + eobRun = (eobRun << 1) | bit; + } + eobRun += 1 << j; + while (i <= scanInfo.lastCoeff) { + j = dctZigZag[i++]; + if (data[j] != 0) { + if ((bit = readBit()) == EOF) { + return gFalse; + } + if (bit) { + data[j] += 1 << scanInfo.al; + } + } + } + --eobRun; + break; + + // zero run and one AC coefficient + } else { + run = (c >> 4) & 0x0f; + size = c & 0x0f; + if ((amp = readAmp(size)) == 9999) { + return gFalse; + } + k = 0; + do { + j = dctZigZag[i++]; + while (data[j] != 0) { + if ((bit = readBit()) == EOF) { + return gFalse; + } + if (bit) { + data[j] += 1 << scanInfo.al; + } + j = dctZigZag[i++]; + } + ++k; + } while (k <= run); + data[j] = amp << scanInfo.al; + } + } + + return gTrue; +} + +// Decode a progressive JPEG image. +void DCTStream::decodeImage() { + int dataIn[64]; + Guchar dataOut[64]; + Gushort *quantTable; + int pY, pCb, pCr, pR, pG, pB; + int x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, cc, i; + int h, v, horiz, vert, hSub, vSub; + int *p0, *p1, *p2; + + for (y1 = 0; y1 < bufHeight; y1 += mcuHeight) { + for (x1 = 0; x1 < bufWidth; x1 += mcuWidth) { + for (cc = 0; cc < numComps; ++cc) { + quantTable = quantTables[compInfo[cc].quantTable]; + h = compInfo[cc].hSample; + v = compInfo[cc].vSample; + horiz = mcuWidth / h; + vert = mcuHeight / v; + hSub = horiz / 8; + vSub = vert / 8; + for (y2 = 0; y2 < mcuHeight; y2 += vert) { + for (x2 = 0; x2 < mcuWidth; x2 += horiz) { + + // pull out the coded data unit + p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + dataIn[i] = p1[0]; + dataIn[i+1] = p1[1]; + dataIn[i+2] = p1[2]; + dataIn[i+3] = p1[3]; + dataIn[i+4] = p1[4]; + dataIn[i+5] = p1[5]; + dataIn[i+6] = p1[6]; + dataIn[i+7] = p1[7]; + p1 += bufWidth * vSub; + } + + // transform + transformDataUnit(quantTable, dataIn, dataOut); + + // store back into frameBuf, doing replication for + // subsampled components + p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; + if (hSub == 1 && vSub == 1) { + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + p1[0] = dataOut[i] & 0xff; + p1[1] = dataOut[i+1] & 0xff; + p1[2] = dataOut[i+2] & 0xff; + p1[3] = dataOut[i+3] & 0xff; + p1[4] = dataOut[i+4] & 0xff; + p1[5] = dataOut[i+5] & 0xff; + p1[6] = dataOut[i+6] & 0xff; + p1[7] = dataOut[i+7] & 0xff; + p1 += bufWidth; + } + } else if (hSub == 2 && vSub == 2) { + p2 = p1 + bufWidth; + for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) { + p1[0] = p1[1] = p2[0] = p2[1] = dataOut[i] & 0xff; + p1[2] = p1[3] = p2[2] = p2[3] = dataOut[i+1] & 0xff; + p1[4] = p1[5] = p2[4] = p2[5] = dataOut[i+2] & 0xff; + p1[6] = p1[7] = p2[6] = p2[7] = dataOut[i+3] & 0xff; + p1[8] = p1[9] = p2[8] = p2[9] = dataOut[i+4] & 0xff; + p1[10] = p1[11] = p2[10] = p2[11] = dataOut[i+5] & 0xff; + p1[12] = p1[13] = p2[12] = p2[13] = dataOut[i+6] & 0xff; + p1[14] = p1[15] = p2[14] = p2[15] = dataOut[i+7] & 0xff; + p1 += bufWidth * 2; + p2 += bufWidth * 2; + } + } else { + i = 0; + for (y3 = 0, y4 = 0; y3 < 8; ++y3, y4 += vSub) { + for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) { + p2 = p1 + x4; + for (y5 = 0; y5 < vSub; ++y5) { + for (x5 = 0; x5 < hSub; ++x5) { + p2[x5] = dataOut[i] & 0xff; + } + p2 += bufWidth; + } + ++i; + } + p1 += bufWidth * vSub; + } + } + } + } + } + + // color space conversion + if (colorXform) { + // convert YCbCr to RGB + if (numComps == 3) { + for (y2 = 0; y2 < mcuHeight; ++y2) { + p0 = &frameBuf[0][(y1+y2) * bufWidth + x1]; + p1 = &frameBuf[1][(y1+y2) * bufWidth + x1]; + p2 = &frameBuf[2][(y1+y2) * bufWidth + x1]; + for (x2 = 0; x2 < mcuWidth; ++x2) { + pY = *p0; + pCb = *p1 - 128; + pCr = *p2 - 128; + pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; + *p0++ = dctClip[dctClipOffset + pR]; + pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + + 32768) >> 16; + *p1++ = dctClip[dctClipOffset + pG]; + pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; + *p2++ = dctClip[dctClipOffset + pB]; + } + } + // convert YCbCrK to CMYK (K is passed through unchanged) + } else if (numComps == 4) { + for (y2 = 0; y2 < mcuHeight; ++y2) { + p0 = &frameBuf[0][(y1+y2) * bufWidth + x1]; + p1 = &frameBuf[1][(y1+y2) * bufWidth + x1]; + p2 = &frameBuf[2][(y1+y2) * bufWidth + x1]; + for (x2 = 0; x2 < mcuWidth; ++x2) { + pY = *p0; + pCb = *p1 - 128; + pCr = *p2 - 128; + pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; + *p0++ = 255 - dctClip[dctClipOffset + pR]; + pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + + 32768) >> 16; + *p1++ = 255 - dctClip[dctClipOffset + pG]; + pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; + *p2++ = 255 - dctClip[dctClipOffset + pB]; + } + } + } + } + } + } +} + +// Transform one data unit -- this performs the dequantization and +// IDCT steps. This IDCT algorithm is taken from: +// Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz, +// "Practical Fast 1-D DCT Algorithms with 11 Multiplications", +// IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989, +// 988-991. +// The stage numbers mentioned in the comments refer to Figure 1 in this +// paper. +void DCTStream::transformDataUnit(Gushort *quantTable, + int dataIn[64], Guchar dataOut[64]) { + int v0, v1, v2, v3, v4, v5, v6, v7, t; + int *p; + int i; + + // dequant + for (i = 0; i < 64; ++i) { + dataIn[i] *= quantTable[i]; + } + + // inverse DCT on rows + for (i = 0; i < 64; i += 8) { + p = dataIn + i; + + // check for all-zero AC coefficients + if (p[1] == 0 && p[2] == 0 && p[3] == 0 && + p[4] == 0 && p[5] == 0 && p[6] == 0 && p[7] == 0) { + t = (dctSqrt2 * p[0] + 512) >> 10; + p[0] = t; + p[1] = t; + p[2] = t; + p[3] = t; + p[4] = t; + p[5] = t; + p[6] = t; + p[7] = t; + continue; + } + + // stage 4 + v0 = (dctSqrt2 * p[0] + 128) >> 8; + v1 = (dctSqrt2 * p[4] + 128) >> 8; + v2 = p[2]; + v3 = p[6]; + v4 = (dctSqrt1d2 * (p[1] - p[7]) + 128) >> 8; + v7 = (dctSqrt1d2 * (p[1] + p[7]) + 128) >> 8; + v5 = p[3] << 4; + v6 = p[5] << 4; + + // stage 3 + t = (v0 - v1+ 1) >> 1; + v0 = (v0 + v1 + 1) >> 1; + v1 = t; + t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8; + v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8; + v3 = t; + t = (v4 - v6 + 1) >> 1; + v4 = (v4 + v6 + 1) >> 1; + v6 = t; + t = (v7 + v5 + 1) >> 1; + v5 = (v7 - v5 + 1) >> 1; + v7 = t; + + // stage 2 + t = (v0 - v3 + 1) >> 1; + v0 = (v0 + v3 + 1) >> 1; + v3 = t; + t = (v1 - v2 + 1) >> 1; + v1 = (v1 + v2 + 1) >> 1; + v2 = t; + t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12; + v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12; + v7 = t; + t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12; + v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12; + v6 = t; + + // stage 1 + p[0] = v0 + v7; + p[7] = v0 - v7; + p[1] = v1 + v6; + p[6] = v1 - v6; + p[2] = v2 + v5; + p[5] = v2 - v5; + p[3] = v3 + v4; + p[4] = v3 - v4; + } + + // inverse DCT on columns + for (i = 0; i < 8; ++i) { + p = dataIn + i; + + // check for all-zero AC coefficients + if (p[1*8] == 0 && p[2*8] == 0 && p[3*8] == 0 && + p[4*8] == 0 && p[5*8] == 0 && p[6*8] == 0 && p[7*8] == 0) { + t = (dctSqrt2 * dataIn[i+0] + 8192) >> 14; + p[0*8] = t; + p[1*8] = t; + p[2*8] = t; + p[3*8] = t; + p[4*8] = t; + p[5*8] = t; + p[6*8] = t; + p[7*8] = t; + continue; + } + + // stage 4 + v0 = (dctSqrt2 * p[0*8] + 2048) >> 12; + v1 = (dctSqrt2 * p[4*8] + 2048) >> 12; + v2 = p[2*8]; + v3 = p[6*8]; + v4 = (dctSqrt1d2 * (p[1*8] - p[7*8]) + 2048) >> 12; + v7 = (dctSqrt1d2 * (p[1*8] + p[7*8]) + 2048) >> 12; + v5 = p[3*8]; + v6 = p[5*8]; + + // stage 3 + t = (v0 - v1 + 1) >> 1; + v0 = (v0 + v1 + 1) >> 1; + v1 = t; + t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12; + v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12; + v3 = t; + t = (v4 - v6 + 1) >> 1; + v4 = (v4 + v6 + 1) >> 1; + v6 = t; + t = (v7 + v5 + 1) >> 1; + v5 = (v7 - v5 + 1) >> 1; + v7 = t; + + // stage 2 + t = (v0 - v3 + 1) >> 1; + v0 = (v0 + v3 + 1) >> 1; + v3 = t; + t = (v1 - v2 + 1) >> 1; + v1 = (v1 + v2 + 1) >> 1; + v2 = t; + t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12; + v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12; + v7 = t; + t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12; + v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12; + v6 = t; + + // stage 1 + p[0*8] = v0 + v7; + p[7*8] = v0 - v7; + p[1*8] = v1 + v6; + p[6*8] = v1 - v6; + p[2*8] = v2 + v5; + p[5*8] = v2 - v5; + p[3*8] = v3 + v4; + p[4*8] = v3 - v4; + } + + // convert to 8-bit integers + for (i = 0; i < 64; ++i) { + dataOut[i] = dctClip[dctClipOffset + 128 + ((dataIn[i] + 8) >> 4)]; + } +} + +int DCTStream::readHuffSym(DCTHuffTable *table) { + Gushort code; + int bit; + int codeBits; + + code = 0; + codeBits = 0; + do { + // add a bit to the code + if ((bit = readBit()) == EOF) + return 9999; + code = (code << 1) + bit; + ++codeBits; + + // look up code + if (code - table->firstCode[codeBits] < table->numCodes[codeBits]) { + code -= table->firstCode[codeBits]; + return table->sym[table->firstSym[codeBits] + code]; + } + } while (codeBits < 16); + + error(getPos(), "Bad Huffman code in DCT stream"); + return 9999; +} + +int DCTStream::readAmp(int size) { + int amp, bit; + int bits; + + amp = 0; + for (bits = 0; bits < size; ++bits) { + if ((bit = readBit()) == EOF) + return 9999; + amp = (amp << 1) + bit; + } + if (amp < (1 << (size - 1))) + amp -= (1 << size) - 1; + return amp; +} + +int DCTStream::readBit() { + int bit; + int c, c2; + + if (inputBits == 0) { + if ((c = str->getChar()) == EOF) + return EOF; + if (c == 0xff) { + do { + c2 = str->getChar(); + } while (c2 == 0xff); + if (c2 != 0x00) { + error(getPos(), "Bad DCT data: missing 00 after ff"); + return EOF; + } + } + inputBuf = c; + inputBits = 8; + } + bit = (inputBuf >> (inputBits - 1)) & 1; + --inputBits; + return bit; +} + +GBool DCTStream::readHeader() { + GBool doScan; + int n; + int c = 0; + int i; + + // read headers + doScan = gFalse; + while (!doScan) { + c = readMarker(); + switch (c) { + case 0xc0: // SOF0 (sequential) + case 0xc1: // SOF1 (extended sequential) + if (!readBaselineSOF()) { + return gFalse; + } + break; + case 0xc2: // SOF2 (progressive) + if (!readProgressiveSOF()) { + return gFalse; + } + break; + case 0xc4: // DHT + if (!readHuffmanTables()) { + return gFalse; + } + break; + case 0xd8: // SOI + break; + case 0xd9: // EOI + return gFalse; + case 0xda: // SOS + if (!readScanInfo()) { + return gFalse; + } + doScan = gTrue; + break; + case 0xdb: // DQT + if (!readQuantTables()) { + return gFalse; + } + break; + case 0xdd: // DRI + if (!readRestartInterval()) { + return gFalse; + } + break; + case 0xe0: // APP0 + if (!readJFIFMarker()) { + return gFalse; + } + break; + case 0xee: // APP14 + if (!readAdobeMarker()) { + return gFalse; + } + break; + case EOF: + error(getPos(), "Bad DCT header"); + return gFalse; + default: + // skip APPn / COM / etc. + if (c >= 0xe0) { + n = read16() - 2; + for (i = 0; i < n; ++i) { + str->getChar(); + } + } else { + error(getPos(), "Unknown DCT marker <%02x>", c); + return gFalse; + } + break; + } + } + + return gTrue; +} + +GBool DCTStream::readBaselineSOF() { + int length; + int prec; + int i; + int c; + + length = read16(); + prec = str->getChar(); + height = read16(); + width = read16(); + numComps = str->getChar(); + if (numComps <= 0 || numComps > 4) { + error(getPos(), "Bad number of components in DCT stream"); + numComps = 0; + return gFalse; + } + if (prec != 8) { + error(getPos(), "Bad DCT precision %d", prec); + return gFalse; + } + for (i = 0; i < numComps; ++i) { + compInfo[i].id = str->getChar(); + c = str->getChar(); + compInfo[i].hSample = (c >> 4) & 0x0f; + compInfo[i].vSample = c & 0x0f; + compInfo[i].quantTable = str->getChar(); + } + progressive = gFalse; + return gTrue; +} + +GBool DCTStream::readProgressiveSOF() { + int length; + int prec; + int i; + int c; + + length = read16(); + prec = str->getChar(); + height = read16(); + width = read16(); + numComps = str->getChar(); + if (numComps <= 0 || numComps > 4) { + error(getPos(), "Bad number of components in DCT stream"); + numComps = 0; + return gFalse; + } + if (prec != 8) { + error(getPos(), "Bad DCT precision %d", prec); + return gFalse; + } + for (i = 0; i < numComps; ++i) { + compInfo[i].id = str->getChar(); + c = str->getChar(); + compInfo[i].hSample = (c >> 4) & 0x0f; + compInfo[i].vSample = c & 0x0f; + compInfo[i].quantTable = str->getChar(); + } + progressive = gTrue; + return gTrue; +} + +GBool DCTStream::readScanInfo() { + int length; + int id, c; + int i, j; + + length = read16() - 2; + scanInfo.numComps = str->getChar(); + if (scanInfo.numComps <= 0 || scanInfo.numComps > 4) { + error(getPos(), "Bad number of components in DCT stream"); + scanInfo.numComps = 0; + return gFalse; + } + --length; + if (length != 2 * scanInfo.numComps + 3) { + error(getPos(), "Bad DCT scan info block"); + return gFalse; + } + interleaved = scanInfo.numComps == numComps; + for (j = 0; j < numComps; ++j) { + scanInfo.comp[j] = gFalse; + } + for (i = 0; i < scanInfo.numComps; ++i) { + id = str->getChar(); + // some (broken) DCT streams reuse ID numbers, but at least they + // keep the components in order, so we check compInfo[i] first to + // work around the problem + if (id == compInfo[i].id) { + j = i; + } else { + for (j = 0; j < numComps; ++j) { + if (id == compInfo[j].id) { + break; + } + } + if (j == numComps) { + error(getPos(), "Bad DCT component ID in scan info block"); + return gFalse; + } + } + scanInfo.comp[j] = gTrue; + c = str->getChar(); + scanInfo.dcHuffTable[j] = (c >> 4) & 0x0f; + scanInfo.acHuffTable[j] = c & 0x0f; + } + scanInfo.firstCoeff = str->getChar(); + scanInfo.lastCoeff = str->getChar(); + if (scanInfo.firstCoeff < 0 || scanInfo.lastCoeff > 63 || + scanInfo.firstCoeff > scanInfo.lastCoeff) { + error(getPos(), "Bad DCT coefficient numbers in scan info block"); + return gFalse; + } + c = str->getChar(); + scanInfo.ah = (c >> 4) & 0x0f; + scanInfo.al = c & 0x0f; + return gTrue; +} + +GBool DCTStream::readQuantTables() { + int length, prec, i, index; + + length = read16() - 2; + while (length > 0) { + index = str->getChar(); + prec = (index >> 4) & 0x0f; + index &= 0x0f; + if (prec > 1 || index >= 4) { + error(getPos(), "Bad DCT quantization table"); + return gFalse; + } + if (index == numQuantTables) { + numQuantTables = index + 1; + } + for (i = 0; i < 64; ++i) { + if (prec) { + quantTables[index][dctZigZag[i]] = read16(); + } else { + quantTables[index][dctZigZag[i]] = str->getChar(); + } + } + if (prec) { + length -= 129; + } else { + length -= 65; + } + } + return gTrue; +} + +GBool DCTStream::readHuffmanTables() { + DCTHuffTable *tbl; + int length; + int index; + Gushort code; + Guchar sym; + int i; + int c; + + length = read16() - 2; + while (length > 0) { + index = str->getChar(); + --length; + if ((index & 0x0f) >= 4) { + error(getPos(), "Bad DCT Huffman table"); + return gFalse; + } + if (index & 0x10) { + index &= 0x0f; + if (index >= numACHuffTables) + numACHuffTables = index+1; + tbl = &acHuffTables[index]; + } else { + index &= 0x0f; + if (index >= numDCHuffTables) + numDCHuffTables = index+1; + tbl = &dcHuffTables[index]; + } + sym = 0; + code = 0; + for (i = 1; i <= 16; ++i) { + c = str->getChar(); + tbl->firstSym[i] = sym; + tbl->firstCode[i] = code; + tbl->numCodes[i] = c; + sym += c; + code = (code + c) << 1; + } + length -= 16; + for (i = 0; i < sym; ++i) + tbl->sym[i] = str->getChar(); + length -= sym; + } + return gTrue; +} + +GBool DCTStream::readRestartInterval() { + int length; + + length = read16(); + if (length != 4) { + error(getPos(), "Bad DCT restart interval"); + return gFalse; + } + restartInterval = read16(); + return gTrue; +} + +GBool DCTStream::readJFIFMarker() { + int length, i; + char buf[5]; + int c; + + length = read16(); + length -= 2; + if (length >= 5) { + for (i = 0; i < 5; ++i) { + if ((c = str->getChar()) == EOF) { + error(getPos(), "Bad DCT APP0 marker"); + return gFalse; + } + buf[i] = c; + } + length -= 5; + if (!memcmp(buf, "JFIF\0", 5)) { + gotJFIFMarker = gTrue; + } + } + while (length > 0) { + if (str->getChar() == EOF) { + error(getPos(), "Bad DCT APP0 marker"); + return gFalse; + } + --length; + } + return gTrue; +} + +GBool DCTStream::readAdobeMarker() { + int length, i; + char buf[12]; + int c; + + length = read16(); + if (length < 14) { + goto err; + } + for (i = 0; i < 12; ++i) { + if ((c = str->getChar()) == EOF) { + goto err; + } + buf[i] = c; + } + if (strncmp(buf, "Adobe", 5)) { + goto err; + } + colorXform = buf[11]; + gotAdobeMarker = gTrue; + for (i = 14; i < length; ++i) { + if (str->getChar() == EOF) { + goto err; + } + } + return gTrue; + + err: + error(getPos(), "Bad DCT Adobe APP14 marker"); + return gFalse; +} + +GBool DCTStream::readTrailer() { + int c; + + c = readMarker(); + if (c != 0xd9) { // EOI + error(getPos(), "Bad DCT trailer"); + return gFalse; + } + return gTrue; +} + +int DCTStream::readMarker() { + int c; + + do { + do { + c = str->getChar(); + } while (c != 0xff && c != EOF); + do { + c = str->getChar(); + } while (c == 0xff); + } while (c == 0x00); + return c; +} + +int DCTStream::read16() { + int c1, c2; + + if ((c1 = str->getChar()) == EOF) + return EOF; + if ((c2 = str->getChar()) == EOF) + return EOF; + return (c1 << 8) + c2; +} + +GString *DCTStream::getPSFilter(int psLevel, char *indent) { + GString *s; + + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { + return NULL; + } + s->append(indent)->append("<< >> /DCTDecode filter\n"); + return s; +} + +GBool DCTStream::isBinary(GBool /*last*/) { + return str->isBinary(gTrue); +} + +//------------------------------------------------------------------------ +// FlateStream +//------------------------------------------------------------------------ + +int FlateStream::codeLenCodeMap[flateMaxCodeLenCodes] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 +}; + +FlateDecode FlateStream::lengthDecode[flateMaxLitCodes-257] = { + {0, 3}, + {0, 4}, + {0, 5}, + {0, 6}, + {0, 7}, + {0, 8}, + {0, 9}, + {0, 10}, + {1, 11}, + {1, 13}, + {1, 15}, + {1, 17}, + {2, 19}, + {2, 23}, + {2, 27}, + {2, 31}, + {3, 35}, + {3, 43}, + {3, 51}, + {3, 59}, + {4, 67}, + {4, 83}, + {4, 99}, + {4, 115}, + {5, 131}, + {5, 163}, + {5, 195}, + {5, 227}, + {0, 258}, + {0, 258}, + {0, 258} +}; + +FlateDecode FlateStream::distDecode[flateMaxDistCodes] = { + { 0, 1}, + { 0, 2}, + { 0, 3}, + { 0, 4}, + { 1, 5}, + { 1, 7}, + { 2, 9}, + { 2, 13}, + { 3, 17}, + { 3, 25}, + { 4, 33}, + { 4, 49}, + { 5, 65}, + { 5, 97}, + { 6, 129}, + { 6, 193}, + { 7, 257}, + { 7, 385}, + { 8, 513}, + { 8, 769}, + { 9, 1025}, + { 9, 1537}, + {10, 2049}, + {10, 3073}, + {11, 4097}, + {11, 6145}, + {12, 8193}, + {12, 12289}, + {13, 16385}, + {13, 24577} +}; + +static FlateCode flateFixedLitCodeTabCodes[512] = { + {7, 0x0100}, + {8, 0x0050}, + {8, 0x0010}, + {8, 0x0118}, + {7, 0x0110}, + {8, 0x0070}, + {8, 0x0030}, + {9, 0x00c0}, + {7, 0x0108}, + {8, 0x0060}, + {8, 0x0020}, + {9, 0x00a0}, + {8, 0x0000}, + {8, 0x0080}, + {8, 0x0040}, + {9, 0x00e0}, + {7, 0x0104}, + {8, 0x0058}, + {8, 0x0018}, + {9, 0x0090}, + {7, 0x0114}, + {8, 0x0078}, + {8, 0x0038}, + {9, 0x00d0}, + {7, 0x010c}, + {8, 0x0068}, + {8, 0x0028}, + {9, 0x00b0}, + {8, 0x0008}, + {8, 0x0088}, + {8, 0x0048}, + {9, 0x00f0}, + {7, 0x0102}, + {8, 0x0054}, + {8, 0x0014}, + {8, 0x011c}, + {7, 0x0112}, + {8, 0x0074}, + {8, 0x0034}, + {9, 0x00c8}, + {7, 0x010a}, + {8, 0x0064}, + {8, 0x0024}, + {9, 0x00a8}, + {8, 0x0004}, + {8, 0x0084}, + {8, 0x0044}, + {9, 0x00e8}, + {7, 0x0106}, + {8, 0x005c}, + {8, 0x001c}, + {9, 0x0098}, + {7, 0x0116}, + {8, 0x007c}, + {8, 0x003c}, + {9, 0x00d8}, + {7, 0x010e}, + {8, 0x006c}, + {8, 0x002c}, + {9, 0x00b8}, + {8, 0x000c}, + {8, 0x008c}, + {8, 0x004c}, + {9, 0x00f8}, + {7, 0x0101}, + {8, 0x0052}, + {8, 0x0012}, + {8, 0x011a}, + {7, 0x0111}, + {8, 0x0072}, + {8, 0x0032}, + {9, 0x00c4}, + {7, 0x0109}, + {8, 0x0062}, + {8, 0x0022}, + {9, 0x00a4}, + {8, 0x0002}, + {8, 0x0082}, + {8, 0x0042}, + {9, 0x00e4}, + {7, 0x0105}, + {8, 0x005a}, + {8, 0x001a}, + {9, 0x0094}, + {7, 0x0115}, + {8, 0x007a}, + {8, 0x003a}, + {9, 0x00d4}, + {7, 0x010d}, + {8, 0x006a}, + {8, 0x002a}, + {9, 0x00b4}, + {8, 0x000a}, + {8, 0x008a}, + {8, 0x004a}, + {9, 0x00f4}, + {7, 0x0103}, + {8, 0x0056}, + {8, 0x0016}, + {8, 0x011e}, + {7, 0x0113}, + {8, 0x0076}, + {8, 0x0036}, + {9, 0x00cc}, + {7, 0x010b}, + {8, 0x0066}, + {8, 0x0026}, + {9, 0x00ac}, + {8, 0x0006}, + {8, 0x0086}, + {8, 0x0046}, + {9, 0x00ec}, + {7, 0x0107}, + {8, 0x005e}, + {8, 0x001e}, + {9, 0x009c}, + {7, 0x0117}, + {8, 0x007e}, + {8, 0x003e}, + {9, 0x00dc}, + {7, 0x010f}, + {8, 0x006e}, + {8, 0x002e}, + {9, 0x00bc}, + {8, 0x000e}, + {8, 0x008e}, + {8, 0x004e}, + {9, 0x00fc}, + {7, 0x0100}, + {8, 0x0051}, + {8, 0x0011}, + {8, 0x0119}, + {7, 0x0110}, + {8, 0x0071}, + {8, 0x0031}, + {9, 0x00c2}, + {7, 0x0108}, + {8, 0x0061}, + {8, 0x0021}, + {9, 0x00a2}, + {8, 0x0001}, + {8, 0x0081}, + {8, 0x0041}, + {9, 0x00e2}, + {7, 0x0104}, + {8, 0x0059}, + {8, 0x0019}, + {9, 0x0092}, + {7, 0x0114}, + {8, 0x0079}, + {8, 0x0039}, + {9, 0x00d2}, + {7, 0x010c}, + {8, 0x0069}, + {8, 0x0029}, + {9, 0x00b2}, + {8, 0x0009}, + {8, 0x0089}, + {8, 0x0049}, + {9, 0x00f2}, + {7, 0x0102}, + {8, 0x0055}, + {8, 0x0015}, + {8, 0x011d}, + {7, 0x0112}, + {8, 0x0075}, + {8, 0x0035}, + {9, 0x00ca}, + {7, 0x010a}, + {8, 0x0065}, + {8, 0x0025}, + {9, 0x00aa}, + {8, 0x0005}, + {8, 0x0085}, + {8, 0x0045}, + {9, 0x00ea}, + {7, 0x0106}, + {8, 0x005d}, + {8, 0x001d}, + {9, 0x009a}, + {7, 0x0116}, + {8, 0x007d}, + {8, 0x003d}, + {9, 0x00da}, + {7, 0x010e}, + {8, 0x006d}, + {8, 0x002d}, + {9, 0x00ba}, + {8, 0x000d}, + {8, 0x008d}, + {8, 0x004d}, + {9, 0x00fa}, + {7, 0x0101}, + {8, 0x0053}, + {8, 0x0013}, + {8, 0x011b}, + {7, 0x0111}, + {8, 0x0073}, + {8, 0x0033}, + {9, 0x00c6}, + {7, 0x0109}, + {8, 0x0063}, + {8, 0x0023}, + {9, 0x00a6}, + {8, 0x0003}, + {8, 0x0083}, + {8, 0x0043}, + {9, 0x00e6}, + {7, 0x0105}, + {8, 0x005b}, + {8, 0x001b}, + {9, 0x0096}, + {7, 0x0115}, + {8, 0x007b}, + {8, 0x003b}, + {9, 0x00d6}, + {7, 0x010d}, + {8, 0x006b}, + {8, 0x002b}, + {9, 0x00b6}, + {8, 0x000b}, + {8, 0x008b}, + {8, 0x004b}, + {9, 0x00f6}, + {7, 0x0103}, + {8, 0x0057}, + {8, 0x0017}, + {8, 0x011f}, + {7, 0x0113}, + {8, 0x0077}, + {8, 0x0037}, + {9, 0x00ce}, + {7, 0x010b}, + {8, 0x0067}, + {8, 0x0027}, + {9, 0x00ae}, + {8, 0x0007}, + {8, 0x0087}, + {8, 0x0047}, + {9, 0x00ee}, + {7, 0x0107}, + {8, 0x005f}, + {8, 0x001f}, + {9, 0x009e}, + {7, 0x0117}, + {8, 0x007f}, + {8, 0x003f}, + {9, 0x00de}, + {7, 0x010f}, + {8, 0x006f}, + {8, 0x002f}, + {9, 0x00be}, + {8, 0x000f}, + {8, 0x008f}, + {8, 0x004f}, + {9, 0x00fe}, + {7, 0x0100}, + {8, 0x0050}, + {8, 0x0010}, + {8, 0x0118}, + {7, 0x0110}, + {8, 0x0070}, + {8, 0x0030}, + {9, 0x00c1}, + {7, 0x0108}, + {8, 0x0060}, + {8, 0x0020}, + {9, 0x00a1}, + {8, 0x0000}, + {8, 0x0080}, + {8, 0x0040}, + {9, 0x00e1}, + {7, 0x0104}, + {8, 0x0058}, + {8, 0x0018}, + {9, 0x0091}, + {7, 0x0114}, + {8, 0x0078}, + {8, 0x0038}, + {9, 0x00d1}, + {7, 0x010c}, + {8, 0x0068}, + {8, 0x0028}, + {9, 0x00b1}, + {8, 0x0008}, + {8, 0x0088}, + {8, 0x0048}, + {9, 0x00f1}, + {7, 0x0102}, + {8, 0x0054}, + {8, 0x0014}, + {8, 0x011c}, + {7, 0x0112}, + {8, 0x0074}, + {8, 0x0034}, + {9, 0x00c9}, + {7, 0x010a}, + {8, 0x0064}, + {8, 0x0024}, + {9, 0x00a9}, + {8, 0x0004}, + {8, 0x0084}, + {8, 0x0044}, + {9, 0x00e9}, + {7, 0x0106}, + {8, 0x005c}, + {8, 0x001c}, + {9, 0x0099}, + {7, 0x0116}, + {8, 0x007c}, + {8, 0x003c}, + {9, 0x00d9}, + {7, 0x010e}, + {8, 0x006c}, + {8, 0x002c}, + {9, 0x00b9}, + {8, 0x000c}, + {8, 0x008c}, + {8, 0x004c}, + {9, 0x00f9}, + {7, 0x0101}, + {8, 0x0052}, + {8, 0x0012}, + {8, 0x011a}, + {7, 0x0111}, + {8, 0x0072}, + {8, 0x0032}, + {9, 0x00c5}, + {7, 0x0109}, + {8, 0x0062}, + {8, 0x0022}, + {9, 0x00a5}, + {8, 0x0002}, + {8, 0x0082}, + {8, 0x0042}, + {9, 0x00e5}, + {7, 0x0105}, + {8, 0x005a}, + {8, 0x001a}, + {9, 0x0095}, + {7, 0x0115}, + {8, 0x007a}, + {8, 0x003a}, + {9, 0x00d5}, + {7, 0x010d}, + {8, 0x006a}, + {8, 0x002a}, + {9, 0x00b5}, + {8, 0x000a}, + {8, 0x008a}, + {8, 0x004a}, + {9, 0x00f5}, + {7, 0x0103}, + {8, 0x0056}, + {8, 0x0016}, + {8, 0x011e}, + {7, 0x0113}, + {8, 0x0076}, + {8, 0x0036}, + {9, 0x00cd}, + {7, 0x010b}, + {8, 0x0066}, + {8, 0x0026}, + {9, 0x00ad}, + {8, 0x0006}, + {8, 0x0086}, + {8, 0x0046}, + {9, 0x00ed}, + {7, 0x0107}, + {8, 0x005e}, + {8, 0x001e}, + {9, 0x009d}, + {7, 0x0117}, + {8, 0x007e}, + {8, 0x003e}, + {9, 0x00dd}, + {7, 0x010f}, + {8, 0x006e}, + {8, 0x002e}, + {9, 0x00bd}, + {8, 0x000e}, + {8, 0x008e}, + {8, 0x004e}, + {9, 0x00fd}, + {7, 0x0100}, + {8, 0x0051}, + {8, 0x0011}, + {8, 0x0119}, + {7, 0x0110}, + {8, 0x0071}, + {8, 0x0031}, + {9, 0x00c3}, + {7, 0x0108}, + {8, 0x0061}, + {8, 0x0021}, + {9, 0x00a3}, + {8, 0x0001}, + {8, 0x0081}, + {8, 0x0041}, + {9, 0x00e3}, + {7, 0x0104}, + {8, 0x0059}, + {8, 0x0019}, + {9, 0x0093}, + {7, 0x0114}, + {8, 0x0079}, + {8, 0x0039}, + {9, 0x00d3}, + {7, 0x010c}, + {8, 0x0069}, + {8, 0x0029}, + {9, 0x00b3}, + {8, 0x0009}, + {8, 0x0089}, + {8, 0x0049}, + {9, 0x00f3}, + {7, 0x0102}, + {8, 0x0055}, + {8, 0x0015}, + {8, 0x011d}, + {7, 0x0112}, + {8, 0x0075}, + {8, 0x0035}, + {9, 0x00cb}, + {7, 0x010a}, + {8, 0x0065}, + {8, 0x0025}, + {9, 0x00ab}, + {8, 0x0005}, + {8, 0x0085}, + {8, 0x0045}, + {9, 0x00eb}, + {7, 0x0106}, + {8, 0x005d}, + {8, 0x001d}, + {9, 0x009b}, + {7, 0x0116}, + {8, 0x007d}, + {8, 0x003d}, + {9, 0x00db}, + {7, 0x010e}, + {8, 0x006d}, + {8, 0x002d}, + {9, 0x00bb}, + {8, 0x000d}, + {8, 0x008d}, + {8, 0x004d}, + {9, 0x00fb}, + {7, 0x0101}, + {8, 0x0053}, + {8, 0x0013}, + {8, 0x011b}, + {7, 0x0111}, + {8, 0x0073}, + {8, 0x0033}, + {9, 0x00c7}, + {7, 0x0109}, + {8, 0x0063}, + {8, 0x0023}, + {9, 0x00a7}, + {8, 0x0003}, + {8, 0x0083}, + {8, 0x0043}, + {9, 0x00e7}, + {7, 0x0105}, + {8, 0x005b}, + {8, 0x001b}, + {9, 0x0097}, + {7, 0x0115}, + {8, 0x007b}, + {8, 0x003b}, + {9, 0x00d7}, + {7, 0x010d}, + {8, 0x006b}, + {8, 0x002b}, + {9, 0x00b7}, + {8, 0x000b}, + {8, 0x008b}, + {8, 0x004b}, + {9, 0x00f7}, + {7, 0x0103}, + {8, 0x0057}, + {8, 0x0017}, + {8, 0x011f}, + {7, 0x0113}, + {8, 0x0077}, + {8, 0x0037}, + {9, 0x00cf}, + {7, 0x010b}, + {8, 0x0067}, + {8, 0x0027}, + {9, 0x00af}, + {8, 0x0007}, + {8, 0x0087}, + {8, 0x0047}, + {9, 0x00ef}, + {7, 0x0107}, + {8, 0x005f}, + {8, 0x001f}, + {9, 0x009f}, + {7, 0x0117}, + {8, 0x007f}, + {8, 0x003f}, + {9, 0x00df}, + {7, 0x010f}, + {8, 0x006f}, + {8, 0x002f}, + {9, 0x00bf}, + {8, 0x000f}, + {8, 0x008f}, + {8, 0x004f}, + {9, 0x00ff} +}; + +FlateHuffmanTab FlateStream::fixedLitCodeTab = { + flateFixedLitCodeTabCodes, 9 +}; + +static FlateCode flateFixedDistCodeTabCodes[32] = { + {5, 0x0000}, + {5, 0x0010}, + {5, 0x0008}, + {5, 0x0018}, + {5, 0x0004}, + {5, 0x0014}, + {5, 0x000c}, + {5, 0x001c}, + {5, 0x0002}, + {5, 0x0012}, + {5, 0x000a}, + {5, 0x001a}, + {5, 0x0006}, + {5, 0x0016}, + {5, 0x000e}, + {0, 0x0000}, + {5, 0x0001}, + {5, 0x0011}, + {5, 0x0009}, + {5, 0x0019}, + {5, 0x0005}, + {5, 0x0015}, + {5, 0x000d}, + {5, 0x001d}, + {5, 0x0003}, + {5, 0x0013}, + {5, 0x000b}, + {5, 0x001b}, + {5, 0x0007}, + {5, 0x0017}, + {5, 0x000f}, + {0, 0x0000} +}; + +FlateHuffmanTab FlateStream::fixedDistCodeTab = { + flateFixedDistCodeTabCodes, 5 +}; + +FlateStream::FlateStream(Stream *strA, int predictor, int columns, + int colors, int bits): + FilterStream(strA) { + if (predictor != 1) { + pred = new StreamPredictor(this, predictor, columns, colors, bits); + if (!pred->isOk()) { + delete pred; + pred = NULL; + } + } else { + pred = NULL; + } + litCodeTab.codes = NULL; + distCodeTab.codes = NULL; + memset(buf, 0, flateWindow); +} + +FlateStream::~FlateStream() { + if (litCodeTab.codes != fixedLitCodeTab.codes) { + gfree(litCodeTab.codes); + } + if (distCodeTab.codes != fixedDistCodeTab.codes) { + gfree(distCodeTab.codes); + } + if (pred) { + delete pred; + } + delete str; +} + +void FlateStream::reset() { + int cmf, flg; + + index = 0; + remain = 0; + codeBuf = 0; + codeSize = 0; + compressedBlock = gFalse; + endOfBlock = gTrue; + eof = gTrue; + + str->reset(); + + // read header + //~ need to look at window size? + endOfBlock = eof = gTrue; + cmf = str->getChar(); + flg = str->getChar(); + if (cmf == EOF || flg == EOF) + return; + if ((cmf & 0x0f) != 0x08) { + error(getPos(), "Unknown compression method in flate stream"); + return; + } + if ((((cmf << 8) + flg) % 31) != 0) { + error(getPos(), "Bad FCHECK in flate stream"); + return; + } + if (flg & 0x20) { + error(getPos(), "FDICT bit set in flate stream"); + return; + } + + eof = gFalse; +} + +int FlateStream::getChar() { + int c; + + if (pred) { + return pred->getChar(); + } + while (remain == 0) { + if (endOfBlock && eof) + return EOF; + readSome(); + } + c = buf[index]; + index = (index + 1) & flateMask; + --remain; + return c; +} + +int FlateStream::lookChar() { + int c; + + if (pred) { + return pred->lookChar(); + } + while (remain == 0) { + if (endOfBlock && eof) + return EOF; + readSome(); + } + c = buf[index]; + return c; +} + +int FlateStream::getRawChar() { + int c; + + while (remain == 0) { + if (endOfBlock && eof) + return EOF; + readSome(); + } + c = buf[index]; + index = (index + 1) & flateMask; + --remain; + return c; +} + +GString *FlateStream::getPSFilter(int psLevel, char *indent) { + GString *s; + + if (psLevel < 3 || pred) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { + return NULL; + } + s->append(indent)->append("<< >> /FlateDecode filter\n"); + return s; +} + +GBool FlateStream::isBinary(GBool /*last*/) { + return str->isBinary(gTrue); +} + +void FlateStream::readSome() { + int code1, code2; + int len, dist; + int i, j, k; + int c; + + if (endOfBlock) { + if (!startBlock()) + return; + } + + if (compressedBlock) { + if ((code1 = getHuffmanCodeWord(&litCodeTab)) == EOF) + goto err; + if (code1 < 256) { + buf[index] = code1; + remain = 1; + } else if (code1 == 256) { + endOfBlock = gTrue; + remain = 0; + } else { + code1 -= 257; + code2 = lengthDecode[code1].bits; + if (code2 > 0 && (code2 = getCodeWord(code2)) == EOF) + goto err; + len = lengthDecode[code1].first + code2; + if ((code1 = getHuffmanCodeWord(&distCodeTab)) == EOF) + goto err; + code2 = distDecode[code1].bits; + if (code2 > 0 && (code2 = getCodeWord(code2)) == EOF) + goto err; + dist = distDecode[code1].first + code2; + i = index; + j = (index - dist) & flateMask; + for (k = 0; k < len; ++k) { + buf[i] = buf[j]; + i = (i + 1) & flateMask; + j = (j + 1) & flateMask; + } + remain = len; + } + + } else { + len = (blockLen < flateWindow) ? blockLen : flateWindow; + for (i = 0, j = index; i < len; ++i, j = (j + 1) & flateMask) { + if ((c = str->getChar()) == EOF) { + endOfBlock = eof = gTrue; + break; + } + buf[j] = c & 0xff; + } + remain = i; + blockLen -= len; + if (blockLen == 0) + endOfBlock = gTrue; + } + + return; + +err: + error(getPos(), "Unexpected end of file in flate stream"); + endOfBlock = eof = gTrue; + remain = 0; +} + +GBool FlateStream::startBlock() { + int blockHdr; + int c; + int check; + + // free the code tables from the previous block + if (litCodeTab.codes != fixedLitCodeTab.codes) { + gfree(litCodeTab.codes); + } + litCodeTab.codes = NULL; + if (distCodeTab.codes != fixedDistCodeTab.codes) { + gfree(distCodeTab.codes); + } + distCodeTab.codes = NULL; + + // read block header + blockHdr = getCodeWord(3); + if (blockHdr & 1) + eof = gTrue; + blockHdr >>= 1; + + // uncompressed block + if (blockHdr == 0) { + compressedBlock = gFalse; + if ((c = str->getChar()) == EOF) + goto err; + blockLen = c & 0xff; + if ((c = str->getChar()) == EOF) + goto err; + blockLen |= (c & 0xff) << 8; + if ((c = str->getChar()) == EOF) + goto err; + check = c & 0xff; + if ((c = str->getChar()) == EOF) + goto err; + check |= (c & 0xff) << 8; + if (check != (~blockLen & 0xffff)) + error(getPos(), "Bad uncompressed block length in flate stream"); + codeBuf = 0; + codeSize = 0; + + // compressed block with fixed codes + } else if (blockHdr == 1) { + compressedBlock = gTrue; + loadFixedCodes(); + + // compressed block with dynamic codes + } else if (blockHdr == 2) { + compressedBlock = gTrue; + if (!readDynamicCodes()) { + goto err; + } + + // unknown block type + } else { + goto err; + } + + endOfBlock = gFalse; + return gTrue; + +err: + error(getPos(), "Bad block header in flate stream"); + endOfBlock = eof = gTrue; + return gFalse; +} + +void FlateStream::loadFixedCodes() { + litCodeTab.codes = fixedLitCodeTab.codes; + litCodeTab.maxLen = fixedLitCodeTab.maxLen; + distCodeTab.codes = fixedDistCodeTab.codes; + distCodeTab.maxLen = fixedDistCodeTab.maxLen; +} + +GBool FlateStream::readDynamicCodes() { + int numCodeLenCodes; + int numLitCodes; + int numDistCodes; + int codeLenCodeLengths[flateMaxCodeLenCodes]; + FlateHuffmanTab codeLenCodeTab; + int len, repeat, code; + int i; + + codeLenCodeTab.codes = NULL; + + // read lengths + if ((numLitCodes = getCodeWord(5)) == EOF) { + goto err; + } + numLitCodes += 257; + if ((numDistCodes = getCodeWord(5)) == EOF) { + goto err; + } + numDistCodes += 1; + if ((numCodeLenCodes = getCodeWord(4)) == EOF) { + goto err; + } + numCodeLenCodes += 4; + if (numLitCodes > flateMaxLitCodes || + numDistCodes > flateMaxDistCodes || + numCodeLenCodes > flateMaxCodeLenCodes) { + goto err; + } + + // build the code length code table + for (i = 0; i < flateMaxCodeLenCodes; ++i) { + codeLenCodeLengths[i] = 0; + } + for (i = 0; i < numCodeLenCodes; ++i) { + if ((codeLenCodeLengths[codeLenCodeMap[i]] = getCodeWord(3)) == -1) { + goto err; + } + } + compHuffmanCodes(codeLenCodeLengths, flateMaxCodeLenCodes, &codeLenCodeTab); + + // build the literal and distance code tables + len = 0; + repeat = 0; + i = 0; + while (i < numLitCodes + numDistCodes) { + if ((code = getHuffmanCodeWord(&codeLenCodeTab)) == EOF) { + goto err; + } + if (code == 16) { + if ((repeat = getCodeWord(2)) == EOF) { + goto err; + } + repeat += 3; + if (i + repeat > numLitCodes + numDistCodes) { + goto err; + } + for (; repeat > 0; --repeat) { + codeLengths[i++] = len; + } + } else if (code == 17) { + if ((repeat = getCodeWord(3)) == EOF) { + goto err; + } + repeat += 3; + if (i + repeat > numLitCodes + numDistCodes) { + goto err; + } + len = 0; + for (; repeat > 0; --repeat) { + codeLengths[i++] = 0; + } + } else if (code == 18) { + if ((repeat = getCodeWord(7)) == EOF) { + goto err; + } + repeat += 11; + if (i + repeat > numLitCodes + numDistCodes) { + goto err; + } + len = 0; + for (; repeat > 0; --repeat) { + codeLengths[i++] = 0; + } + } else { + codeLengths[i++] = len = code; + } + } + compHuffmanCodes(codeLengths, numLitCodes, &litCodeTab); + compHuffmanCodes(codeLengths + numLitCodes, numDistCodes, &distCodeTab); + + gfree(codeLenCodeTab.codes); + return gTrue; + +err: + error(getPos(), "Bad dynamic code table in flate stream"); + gfree(codeLenCodeTab.codes); + return gFalse; +} + +// Convert an array of lengths, in value order, into a +// Huffman code lookup table. +void FlateStream::compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab) { + int tabSize, len, code, code2, skip, val, i, t; + + // find max code length + tab->maxLen = 0; + for (val = 0; val < n; ++val) { + if (lengths[val] > tab->maxLen) { + tab->maxLen = lengths[val]; + } + } + + // allocate the table + tabSize = 1 << tab->maxLen; + tab->codes = (FlateCode *)gmallocn(tabSize, sizeof(FlateCode)); + + // clear the table + for (i = 0; i < tabSize; ++i) { + tab->codes[i].len = 0; + tab->codes[i].val = 0; + } + + // build the table + for (len = 1, code = 0, skip = 2; + len <= tab->maxLen; + ++len, code <<= 1, skip <<= 1) { + for (val = 0; val < n; ++val) { + if (lengths[val] == len) { + + // bit-reverse the code + code2 = 0; + t = code; + for (i = 0; i < len; ++i) { + code2 = (code2 << 1) | (t & 1); + t >>= 1; + } + + // fill in the table entries + for (i = code2; i < tabSize; i += skip) { + tab->codes[i].len = (Gushort)len; + tab->codes[i].val = (Gushort)val; + } + + ++code; + } + } + } +} + +int FlateStream::getHuffmanCodeWord(FlateHuffmanTab *tab) { + FlateCode *code; + int c; + + while (codeSize < tab->maxLen) { + if ((c = str->getChar()) == EOF) { + break; + } + codeBuf |= (c & 0xff) << codeSize; + codeSize += 8; + } + code = &tab->codes[codeBuf & ((1 << tab->maxLen) - 1)]; + if (codeSize == 0 || codeSize < code->len || code->len == 0) { + return EOF; + } + codeBuf >>= code->len; + codeSize -= code->len; + return (int)code->val; +} + +int FlateStream::getCodeWord(int bits) { + int c; + + while (codeSize < bits) { + if ((c = str->getChar()) == EOF) + return EOF; + codeBuf |= (c & 0xff) << codeSize; + codeSize += 8; + } + c = codeBuf & ((1 << bits) - 1); + codeBuf >>= bits; + codeSize -= bits; + return c; +} + +//------------------------------------------------------------------------ +// EOFStream +//------------------------------------------------------------------------ + +EOFStream::EOFStream(Stream *strA): + FilterStream(strA) { +} + +EOFStream::~EOFStream() { + delete str; +} + +//------------------------------------------------------------------------ +// FixedLengthEncoder +//------------------------------------------------------------------------ + +FixedLengthEncoder::FixedLengthEncoder(Stream *strA, int lengthA): + FilterStream(strA) { + length = lengthA; + count = 0; +} + +FixedLengthEncoder::~FixedLengthEncoder() { + if (str->isEncoder()) + delete str; +} + +void FixedLengthEncoder::reset() { + str->reset(); + count = 0; +} + +int FixedLengthEncoder::getChar() { + if (length >= 0 && count >= length) + return EOF; + ++count; + return str->getChar(); +} + +int FixedLengthEncoder::lookChar() { + if (length >= 0 && count >= length) + return EOF; + return str->getChar(); +} + +GBool FixedLengthEncoder::isBinary(GBool /*last*/) { + return str->isBinary(gTrue); +} + +//------------------------------------------------------------------------ +// ASCIIHexEncoder +//------------------------------------------------------------------------ + +ASCIIHexEncoder::ASCIIHexEncoder(Stream *strA): + FilterStream(strA) { + bufPtr = bufEnd = buf; + lineLen = 0; + eof = gFalse; +} + +ASCIIHexEncoder::~ASCIIHexEncoder() { + if (str->isEncoder()) { + delete str; + } +} + +void ASCIIHexEncoder::reset() { + str->reset(); + bufPtr = bufEnd = buf; + lineLen = 0; + eof = gFalse; +} + +GBool ASCIIHexEncoder::fillBuf() { + static char *hex = "0123456789abcdef"; + int c; + + if (eof) { + return gFalse; + } + bufPtr = bufEnd = buf; + if ((c = str->getChar()) == EOF) { + *bufEnd++ = '>'; + eof = gTrue; + } else { + if (lineLen >= 64) { + *bufEnd++ = '\n'; + lineLen = 0; + } + *bufEnd++ = hex[(c >> 4) & 0x0f]; + *bufEnd++ = hex[c & 0x0f]; + lineLen += 2; + } + return gTrue; +} + +//------------------------------------------------------------------------ +// ASCII85Encoder +//------------------------------------------------------------------------ + +ASCII85Encoder::ASCII85Encoder(Stream *strA): + FilterStream(strA) { + bufPtr = bufEnd = buf; + lineLen = 0; + eof = gFalse; +} + +ASCII85Encoder::~ASCII85Encoder() { + if (str->isEncoder()) + delete str; +} + +void ASCII85Encoder::reset() { + str->reset(); + bufPtr = bufEnd = buf; + lineLen = 0; + eof = gFalse; +} + +GBool ASCII85Encoder::fillBuf() { + Guint t; + char buf1[5]; + int c0, c1, c2, c3; + int n, i; + + if (eof) { + return gFalse; + } + c0 = str->getChar(); + c1 = str->getChar(); + c2 = str->getChar(); + c3 = str->getChar(); + bufPtr = bufEnd = buf; + if (c3 == EOF) { + if (c0 == EOF) { + n = 0; + t = 0; + } else { + if (c1 == EOF) { + n = 1; + t = c0 << 24; + } else if (c2 == EOF) { + n = 2; + t = (c0 << 24) | (c1 << 16); + } else { + n = 3; + t = (c0 << 24) | (c1 << 16) | (c2 << 8); + } + for (i = 4; i >= 0; --i) { + buf1[i] = (char)(t % 85 + 0x21); + t /= 85; + } + for (i = 0; i <= n; ++i) { + *bufEnd++ = buf1[i]; + if (++lineLen == 65) { + *bufEnd++ = '\n'; + lineLen = 0; + } + } + } + *bufEnd++ = '~'; + *bufEnd++ = '>'; + eof = gTrue; + } else { + t = (c0 << 24) | (c1 << 16) | (c2 << 8) | c3; + if (t == 0) { + *bufEnd++ = 'z'; + if (++lineLen == 65) { + *bufEnd++ = '\n'; + lineLen = 0; + } + } else { + for (i = 4; i >= 0; --i) { + buf1[i] = (char)(t % 85 + 0x21); + t /= 85; + } + for (i = 0; i <= 4; ++i) { + *bufEnd++ = buf1[i]; + if (++lineLen == 65) { + *bufEnd++ = '\n'; + lineLen = 0; + } + } + } + } + return gTrue; +} + +//------------------------------------------------------------------------ +// RunLengthEncoder +//------------------------------------------------------------------------ + +RunLengthEncoder::RunLengthEncoder(Stream *strA): + FilterStream(strA) { + bufPtr = bufEnd = nextEnd = buf; + eof = gFalse; +} + +RunLengthEncoder::~RunLengthEncoder() { + if (str->isEncoder()) + delete str; +} + +void RunLengthEncoder::reset() { + str->reset(); + bufPtr = bufEnd = nextEnd = buf; + eof = gFalse; +} + +// +// When fillBuf finishes, buf[] looks like this: +// +-----+--------------+-----------------+-- +// + tag | ... data ... | next 0, 1, or 2 | +// +-----+--------------+-----------------+-- +// ^ ^ ^ +// bufPtr bufEnd nextEnd +// +GBool RunLengthEncoder::fillBuf() { + int c, c1, c2; + int n; + + // already hit EOF? + if (eof) + return gFalse; + + // grab two bytes + if (nextEnd < bufEnd + 1) { + if ((c1 = str->getChar()) == EOF) { + eof = gTrue; + return gFalse; + } + } else { + c1 = bufEnd[0] & 0xff; + } + if (nextEnd < bufEnd + 2) { + if ((c2 = str->getChar()) == EOF) { + eof = gTrue; + buf[0] = 0; + buf[1] = c1; + bufPtr = buf; + bufEnd = &buf[2]; + return gTrue; + } + } else { + c2 = bufEnd[1] & 0xff; + } + + // check for repeat + c = 0; // make gcc happy + if (c1 == c2) { + n = 2; + while (n < 128 && (c = str->getChar()) == c1) + ++n; + buf[0] = (char)(257 - n); + buf[1] = c1; + bufEnd = &buf[2]; + if (c == EOF) { + eof = gTrue; + } else if (n < 128) { + buf[2] = c; + nextEnd = &buf[3]; + } else { + nextEnd = bufEnd; + } + + // get up to 128 chars + } else { + buf[1] = c1; + buf[2] = c2; + n = 2; + while (n < 128) { + if ((c = str->getChar()) == EOF) { + eof = gTrue; + break; + } + ++n; + buf[n] = c; + if (buf[n] == buf[n-1]) + break; + } + if (buf[n] == buf[n-1]) { + buf[0] = (char)(n-2-1); + bufEnd = &buf[n-1]; + nextEnd = &buf[n+1]; + } else { + buf[0] = (char)(n-1); + bufEnd = nextEnd = &buf[n+1]; + } + } + bufPtr = buf; + return gTrue; +} diff --git a/kpdf/xpdf/xpdf/Stream.h b/kpdf/xpdf/xpdf/Stream.h new file mode 100644 index 00000000..b2f71de7 --- /dev/null +++ b/kpdf/xpdf/xpdf/Stream.h @@ -0,0 +1,860 @@ +//======================================================================== +// +// Stream.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef STREAM_H +#define STREAM_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include +#include "gtypes.h" +#include "Object.h" + +class BaseStream; + +//------------------------------------------------------------------------ + +enum StreamKind { + strFile, + strASCIIHex, + strASCII85, + strLZW, + strRunLength, + strCCITTFax, + strDCT, + strFlate, + strJBIG2, + strJPX, + strWeird // internal-use stream types +}; + +enum StreamColorSpaceMode { + streamCSNone, + streamCSDeviceGray, + streamCSDeviceRGB, + streamCSDeviceCMYK +}; + +//------------------------------------------------------------------------ + +// This is in Stream.h instead of Decrypt.h to avoid really annoying +// include file dependency loops. +enum CryptAlgorithm { + cryptRC4, + cryptAES +}; + +//------------------------------------------------------------------------ +// Stream (base class) +//------------------------------------------------------------------------ + +class Stream { +public: + + // Constructor. + Stream(); + + // Destructor. + virtual ~Stream(); + + // Reference counting. + int incRef() { return ++ref; } + int decRef() { return --ref; } + + // Get kind of stream. + virtual StreamKind getKind() = 0; + + // Reset stream to beginning. + virtual void reset() = 0; + + // Close down the stream. + virtual void close(); + + // Get next char from stream. + virtual int getChar() = 0; + + // Peek at next char in stream. + virtual int lookChar() = 0; + + // Get next char from stream without using the predictor. + // This is only used by StreamPredictor. + virtual int getRawChar(); + + // Get next line from stream. + virtual char *getLine(char *buf, int size); + + // Get current position in file. + virtual int getPos() = 0; + + // Go to a position in the stream. If

is negative, the + // position is from the end of the file; otherwise the position is + // from the start of the file. + virtual void setPos(Guint pos, int dir = 0) = 0; + + // Get PostScript command for the filter(s). + virtual GString *getPSFilter(int psLevel, char *indent); + + // Does this stream type potentially contain non-printable chars? + virtual GBool isBinary(GBool last = gTrue) = 0; + + // Get the BaseStream of this stream. + virtual BaseStream *getBaseStream() = 0; + + // Get the stream after the last decoder (this may be a BaseStream + // or a DecryptStream). + virtual Stream *getUndecodedStream() = 0; + + // Get the dictionary associated with this stream. + virtual Dict *getDict() = 0; + + // Is this an encoding filter? + virtual GBool isEncoder() { return gFalse; } + + // Get image parameters which are defined by the stream contents. + virtual void getImageParams(int * /*bitsPerComponent*/, + StreamColorSpaceMode * /*csMode*/) {} + + // Return the next stream in the "stack". + virtual Stream *getNextStream() { return NULL; } + + // Add filters to this stream according to the parameters in . + // Returns the new stream. + Stream *addFilters(Object *dict); + +private: + + Stream *makeFilter(char *name, Stream *str, Object *params); + + int ref; // reference count +}; + +//------------------------------------------------------------------------ +// BaseStream +// +// This is the base class for all streams that read directly from a file. +//------------------------------------------------------------------------ + +class BaseStream: public Stream { +public: + + BaseStream(Object *dictA); + virtual ~BaseStream(); + virtual Stream *makeSubStream(Guint start, GBool limited, + Guint length, Object *dict) = 0; + virtual void setPos(Guint pos, int dir = 0) = 0; + virtual GBool isBinary(GBool last = gTrue) { return last; } + virtual BaseStream *getBaseStream() { return this; } + virtual Stream *getUndecodedStream() { return this; } + virtual Dict *getDict() { return dict.getDict(); } + virtual GString *getFileName() { return NULL; } + + // Get/set position of first byte of stream within the file. + virtual Guint getStart() = 0; + virtual void moveStart(int delta) = 0; + +private: + + Object dict; +}; + +//------------------------------------------------------------------------ +// FilterStream +// +// This is the base class for all streams that filter another stream. +//------------------------------------------------------------------------ + +class FilterStream: public Stream { +public: + + FilterStream(Stream *strA); + virtual ~FilterStream(); + virtual void close(); + virtual int getPos() { return str->getPos(); } + virtual void setPos(Guint pos, int dir = 0); + virtual BaseStream *getBaseStream() { return str->getBaseStream(); } + virtual Stream *getUndecodedStream() { return str->getUndecodedStream(); } + virtual Dict *getDict() { return str->getDict(); } + virtual Stream *getNextStream() { return str; } + +protected: + + Stream *str; +}; + +//------------------------------------------------------------------------ +// ImageStream +//------------------------------------------------------------------------ + +class ImageStream { +public: + + // Create an image stream object for an image with the specified + // parameters. Note that these are the actual image parameters, + // which may be different from the predictor parameters. + ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA); + + ~ImageStream(); + + // Reset the stream. + void reset(); + + // Gets the next pixel from the stream. should be able to hold + // at least nComps elements. Returns false at end of file. + GBool getPixel(Guchar *pix); + + // Returns a pointer to the next line of pixels. Returns NULL at + // end of file. + Guchar *getLine(); + + // Skip an entire line from the image. + void skipLine(); + +private: + + Stream *str; // base stream + int width; // pixels per line + int nComps; // components per pixel + int nBits; // bits per component + int nVals; // components per line + Guchar *imgLine; // line buffer + int imgIdx; // current index in imgLine +}; + +//------------------------------------------------------------------------ +// StreamPredictor +//------------------------------------------------------------------------ + +class StreamPredictor { +public: + + // Create a predictor object. Note that the parameters are for the + // predictor, and may not match the actual image parameters. + StreamPredictor(Stream *strA, int predictorA, + int widthA, int nCompsA, int nBitsA); + + ~StreamPredictor(); + + GBool isOk() { return ok; } + + int lookChar(); + int getChar(); + +private: + + GBool getNextLine(); + + Stream *str; // base stream + int predictor; // predictor + int width; // pixels per line + int nComps; // components per pixel + int nBits; // bits per component + int nVals; // components per line + int pixBytes; // bytes per pixel + int rowBytes; // bytes per line + Guchar *predLine; // line buffer + int predIdx; // current index in predLine + GBool ok; +}; + +//------------------------------------------------------------------------ +// FileStream +//------------------------------------------------------------------------ + +#define fileStreamBufSize 256 + +class FileStream: public BaseStream { +public: + + FileStream(FILE *fA, Guint startA, GBool limitedA, + Guint lengthA, Object *dictA); + virtual ~FileStream(); + virtual Stream *makeSubStream(Guint startA, GBool limitedA, + Guint lengthA, Object *dictA); + virtual StreamKind getKind() { return strFile; } + virtual void reset(); + virtual void close(); + virtual int getChar() + { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } + virtual int lookChar() + { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } + virtual int getPos() { return bufPos + (bufPtr - buf); } + virtual void setPos(Guint pos, int dir = 0); + virtual Guint getStart() { return start; } + virtual void moveStart(int delta); + +private: + + GBool fillBuf(); + + FILE *f; + Guint start; + GBool limited; + Guint length; + char buf[fileStreamBufSize]; + char *bufPtr; + char *bufEnd; + Guint bufPos; + int savePos; + GBool saved; +}; + +//------------------------------------------------------------------------ +// MemStream +//------------------------------------------------------------------------ + +class MemStream: public BaseStream { +public: + + MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA); + virtual ~MemStream(); + virtual Stream *makeSubStream(Guint start, GBool limited, + Guint lengthA, Object *dictA); + virtual StreamKind getKind() { return strWeird; } + virtual void reset(); + virtual void close(); + virtual int getChar() + { return (bufPtr < bufEnd) ? (*bufPtr++ & 0xff) : EOF; } + virtual int lookChar() + { return (bufPtr < bufEnd) ? (*bufPtr & 0xff) : EOF; } + virtual int getPos() { return (int)(bufPtr - buf); } + virtual void setPos(Guint pos, int dir = 0); + virtual Guint getStart() { return start; } + virtual void moveStart(int delta); + +private: + + char *buf; + Guint start; + Guint length; + char *bufEnd; + char *bufPtr; + GBool needFree; +}; + +//------------------------------------------------------------------------ +// EmbedStream +// +// This is a special stream type used for embedded streams (inline +// images). It reads directly from the base stream -- after the +// EmbedStream is deleted, reads from the base stream will proceed where +// the BaseStream left off. Note that this is very different behavior +// that creating a new FileStream (using makeSubStream). +//------------------------------------------------------------------------ + +class EmbedStream: public BaseStream { +public: + + EmbedStream(Stream *strA, Object *dictA, GBool limitedA, Guint lengthA); + virtual ~EmbedStream(); + virtual Stream *makeSubStream(Guint start, GBool limitedA, + Guint lengthA, Object *dictA); + virtual StreamKind getKind() { return str->getKind(); } + virtual void reset() {} + virtual int getChar(); + virtual int lookChar(); + virtual int getPos() { return str->getPos(); } + virtual void setPos(Guint pos, int dir = 0); + virtual Guint getStart(); + virtual void moveStart(int delta); + +private: + + Stream *str; + GBool limited; + Guint length; +}; + +//------------------------------------------------------------------------ +// ASCIIHexStream +//------------------------------------------------------------------------ + +class ASCIIHexStream: public FilterStream { +public: + + ASCIIHexStream(Stream *strA); + virtual ~ASCIIHexStream(); + virtual StreamKind getKind() { return strASCIIHex; } + virtual void reset(); + virtual int getChar() + { int c = lookChar(); buf = EOF; return c; } + virtual int lookChar(); + virtual GString *getPSFilter(int psLevel, char *indent); + virtual GBool isBinary(GBool last = gTrue); + +private: + + int buf; + GBool eof; +}; + +//------------------------------------------------------------------------ +// ASCII85Stream +//------------------------------------------------------------------------ + +class ASCII85Stream: public FilterStream { +public: + + ASCII85Stream(Stream *strA); + virtual ~ASCII85Stream(); + virtual StreamKind getKind() { return strASCII85; } + virtual void reset(); + virtual int getChar() + { int ch = lookChar(); ++index; return ch; } + virtual int lookChar(); + virtual GString *getPSFilter(int psLevel, char *indent); + virtual GBool isBinary(GBool last = gTrue); + +private: + + int c[5]; + int b[4]; + int index, n; + GBool eof; +}; + +//------------------------------------------------------------------------ +// LZWStream +//------------------------------------------------------------------------ + +class LZWStream: public FilterStream { +public: + + LZWStream(Stream *strA, int predictor, int columns, int colors, + int bits, int earlyA); + virtual ~LZWStream(); + virtual StreamKind getKind() { return strLZW; } + virtual void reset(); + virtual int getChar(); + virtual int lookChar(); + virtual int getRawChar(); + virtual GString *getPSFilter(int psLevel, char *indent); + virtual GBool isBinary(GBool last = gTrue); + +private: + + StreamPredictor *pred; // predictor + int early; // early parameter + GBool eof; // true if at eof + int inputBuf; // input buffer + int inputBits; // number of bits in input buffer + struct { // decoding table + int length; + int head; + Guchar tail; + } table[4097]; + int nextCode; // next code to be used + int nextBits; // number of bits in next code word + int prevCode; // previous code used in stream + int newChar; // next char to be added to table + Guchar seqBuf[4097]; // buffer for current sequence + int seqLength; // length of current sequence + int seqIndex; // index into current sequence + GBool first; // first code after a table clear + + GBool processNextCode(); + void clearTable(); + int getCode(); +}; + +//------------------------------------------------------------------------ +// RunLengthStream +//------------------------------------------------------------------------ + +class RunLengthStream: public FilterStream { +public: + + RunLengthStream(Stream *strA); + virtual ~RunLengthStream(); + virtual StreamKind getKind() { return strRunLength; } + virtual void reset(); + virtual int getChar() + { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } + virtual int lookChar() + { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } + virtual GString *getPSFilter(int psLevel, char *indent); + virtual GBool isBinary(GBool last = gTrue); + +private: + + char buf[128]; // buffer + char *bufPtr; // next char to read + char *bufEnd; // end of buffer + GBool eof; + + GBool fillBuf(); +}; + +//------------------------------------------------------------------------ +// CCITTFaxStream +//------------------------------------------------------------------------ + +struct CCITTCodeTable; + +class CCITTFaxStream: public FilterStream { +public: + + CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA, + GBool byteAlignA, int columnsA, int rowsA, + GBool endOfBlockA, GBool blackA); + virtual ~CCITTFaxStream(); + virtual StreamKind getKind() { return strCCITTFax; } + virtual void reset(); + virtual int getChar() + { int c = lookChar(); buf = EOF; return c; } + virtual int lookChar(); + virtual GString *getPSFilter(int psLevel, char *indent); + virtual GBool isBinary(GBool last = gTrue); + +private: + + int encoding; // 'K' parameter + GBool endOfLine; // 'EndOfLine' parameter + GBool byteAlign; // 'EncodedByteAlign' parameter + int columns; // 'Columns' parameter + int rows; // 'Rows' parameter + GBool endOfBlock; // 'EndOfBlock' parameter + GBool black; // 'BlackIs1' parameter + GBool eof; // true if at eof + GBool nextLine2D; // true if next line uses 2D encoding + int row; // current row + int inputBuf; // input buffer + int inputBits; // number of bits in input buffer + int *codingLine; // coding line changing elements + int *refLine; // reference line changing elements + int a0i; // index into codingLine + GBool err; // error on current line + int outputBits; // remaining ouput bits + int buf; // character buffer + + void addPixels(int a1, int black); + void addPixelsNeg(int a1, int black); + short getTwoDimCode(); + short getWhiteCode(); + short getBlackCode(); + short lookBits(int n); + void eatBits(int n) { if ((inputBits -= n) < 0) inputBits = 0; } +}; + +//------------------------------------------------------------------------ +// DCTStream +//------------------------------------------------------------------------ + +// DCT component info +struct DCTCompInfo { + int id; // component ID + int hSample, vSample; // horiz/vert sampling resolutions + int quantTable; // quantization table number + int prevDC; // DC coefficient accumulator +}; + +struct DCTScanInfo { + GBool comp[4]; // comp[i] is set if component i is + // included in this scan + int numComps; // number of components in the scan + int dcHuffTable[4]; // DC Huffman table numbers + int acHuffTable[4]; // AC Huffman table numbers + int firstCoeff, lastCoeff; // first and last DCT coefficient + int ah, al; // successive approximation parameters +}; + +// DCT Huffman decoding table +struct DCTHuffTable { + Guchar firstSym[17]; // first symbol for this bit length + Gushort firstCode[17]; // first code for this bit length + Gushort numCodes[17]; // number of codes of this bit length + Guchar sym[256]; // symbols +}; + +class DCTStream: public FilterStream { +public: + + DCTStream(Stream *strA, int colorXformA); + virtual ~DCTStream(); + virtual StreamKind getKind() { return strDCT; } + virtual void reset(); + virtual void close(); + virtual int getChar(); + virtual int lookChar(); + virtual GString *getPSFilter(int psLevel, char *indent); + virtual GBool isBinary(GBool last = gTrue); + Stream *getRawStream() { return str; } + +private: + + GBool progressive; // set if in progressive mode + GBool interleaved; // set if in interleaved mode + int width, height; // image size + int mcuWidth, mcuHeight; // size of min coding unit, in data units + int bufWidth, bufHeight; // frameBuf size + DCTCompInfo compInfo[4]; // info for each component + DCTScanInfo scanInfo; // info for the current scan + int numComps; // number of components in image + int colorXform; // color transform: -1 = unspecified + // 0 = none + // 1 = YUV/YUVK -> RGB/CMYK + GBool gotJFIFMarker; // set if APP0 JFIF marker was present + GBool gotAdobeMarker; // set if APP14 Adobe marker was present + int restartInterval; // restart interval, in MCUs + Gushort quantTables[4][64]; // quantization tables + int numQuantTables; // number of quantization tables + DCTHuffTable dcHuffTables[4]; // DC Huffman tables + DCTHuffTable acHuffTables[4]; // AC Huffman tables + int numDCHuffTables; // number of DC Huffman tables + int numACHuffTables; // number of AC Huffman tables + Guchar *rowBuf[4][32]; // buffer for one MCU (non-progressive mode) + int *frameBuf[4]; // buffer for frame (progressive mode) + int comp, x, y, dy; // current position within image/MCU + int restartCtr; // MCUs left until restart + int restartMarker; // next restart marker + int eobRun; // number of EOBs left in the current run + int inputBuf; // input buffer for variable length codes + int inputBits; // number of valid bits in input buffer + + void restart(); + GBool readMCURow(); + void readScan(); + GBool readDataUnit(DCTHuffTable *dcHuffTable, + DCTHuffTable *acHuffTable, + int *prevDC, int data[64]); + GBool readProgressiveDataUnit(DCTHuffTable *dcHuffTable, + DCTHuffTable *acHuffTable, + int *prevDC, int data[64]); + void decodeImage(); + void transformDataUnit(Gushort *quantTable, + int dataIn[64], Guchar dataOut[64]); + int readHuffSym(DCTHuffTable *table); + int readAmp(int size); + int readBit(); + GBool readHeader(); + GBool readBaselineSOF(); + GBool readProgressiveSOF(); + GBool readScanInfo(); + GBool readQuantTables(); + GBool readHuffmanTables(); + GBool readRestartInterval(); + GBool readJFIFMarker(); + GBool readAdobeMarker(); + GBool readTrailer(); + int readMarker(); + int read16(); +}; + +//------------------------------------------------------------------------ +// FlateStream +//------------------------------------------------------------------------ + +#define flateWindow 32768 // buffer size +#define flateMask (flateWindow-1) +#define flateMaxHuffman 15 // max Huffman code length +#define flateMaxCodeLenCodes 19 // max # code length codes +#define flateMaxLitCodes 288 // max # literal codes +#define flateMaxDistCodes 30 // max # distance codes + +// Huffman code table entry +struct FlateCode { + Gushort len; // code length, in bits + Gushort val; // value represented by this code +}; + +struct FlateHuffmanTab { + FlateCode *codes; + int maxLen; +}; + +// Decoding info for length and distance code words +struct FlateDecode { + int bits; // # extra bits + int first; // first length/distance +}; + +class FlateStream: public FilterStream { +public: + + FlateStream(Stream *strA, int predictor, int columns, + int colors, int bits); + virtual ~FlateStream(); + virtual StreamKind getKind() { return strFlate; } + virtual void reset(); + virtual int getChar(); + virtual int lookChar(); + virtual int getRawChar(); + virtual GString *getPSFilter(int psLevel, char *indent); + virtual GBool isBinary(GBool last = gTrue); + +private: + + StreamPredictor *pred; // predictor + Guchar buf[flateWindow]; // output data buffer + int index; // current index into output buffer + int remain; // number valid bytes in output buffer + int codeBuf; // input buffer + int codeSize; // number of bits in input buffer + int // literal and distance code lengths + codeLengths[flateMaxLitCodes + flateMaxDistCodes]; + FlateHuffmanTab litCodeTab; // literal code table + FlateHuffmanTab distCodeTab; // distance code table + GBool compressedBlock; // set if reading a compressed block + int blockLen; // remaining length of uncompressed block + GBool endOfBlock; // set when end of block is reached + GBool eof; // set when end of stream is reached + + static int // code length code reordering + codeLenCodeMap[flateMaxCodeLenCodes]; + static FlateDecode // length decoding info + lengthDecode[flateMaxLitCodes-257]; + static FlateDecode // distance decoding info + distDecode[flateMaxDistCodes]; + static FlateHuffmanTab // fixed literal code table + fixedLitCodeTab; + static FlateHuffmanTab // fixed distance code table + fixedDistCodeTab; + + void readSome(); + GBool startBlock(); + void loadFixedCodes(); + GBool readDynamicCodes(); + void compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab); + int getHuffmanCodeWord(FlateHuffmanTab *tab); + int getCodeWord(int bits); +}; + +//------------------------------------------------------------------------ +// EOFStream +//------------------------------------------------------------------------ + +class EOFStream: public FilterStream { +public: + + EOFStream(Stream *strA); + virtual ~EOFStream(); + virtual StreamKind getKind() { return strWeird; } + virtual void reset() {} + virtual int getChar() { return EOF; } + virtual int lookChar() { return EOF; } + virtual GString *getPSFilter(int /*psLevel*/, char * /*indent*/) { return NULL; } + virtual GBool isBinary(GBool /*last*/ = gTrue) { return gFalse; } +}; + +//------------------------------------------------------------------------ +// FixedLengthEncoder +//------------------------------------------------------------------------ + +class FixedLengthEncoder: public FilterStream { +public: + + FixedLengthEncoder(Stream *strA, int lengthA); + ~FixedLengthEncoder(); + virtual StreamKind getKind() { return strWeird; } + virtual void reset(); + virtual int getChar(); + virtual int lookChar(); + virtual GString *getPSFilter(int /*psLevel*/, char * /*indent*/) { return NULL; } + virtual GBool isBinary(GBool last = gTrue); + virtual GBool isEncoder() { return gTrue; } + +private: + + int length; + int count; +}; + +//------------------------------------------------------------------------ +// ASCIIHexEncoder +//------------------------------------------------------------------------ + +class ASCIIHexEncoder: public FilterStream { +public: + + ASCIIHexEncoder(Stream *strA); + virtual ~ASCIIHexEncoder(); + virtual StreamKind getKind() { return strWeird; } + virtual void reset(); + virtual int getChar() + { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } + virtual int lookChar() + { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } + virtual GString *getPSFilter(int /*psLevel*/, char * /*indent*/) { return NULL; } + virtual GBool isBinary(GBool /*last*/ = gTrue) { return gFalse; } + virtual GBool isEncoder() { return gTrue; } + +private: + + char buf[4]; + char *bufPtr; + char *bufEnd; + int lineLen; + GBool eof; + + GBool fillBuf(); +}; + +//------------------------------------------------------------------------ +// ASCII85Encoder +//------------------------------------------------------------------------ + +class ASCII85Encoder: public FilterStream { +public: + + ASCII85Encoder(Stream *strA); + virtual ~ASCII85Encoder(); + virtual StreamKind getKind() { return strWeird; } + virtual void reset(); + virtual int getChar() + { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } + virtual int lookChar() + { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } + virtual GString *getPSFilter(int /*psLevel*/, char * /*indent*/) { return NULL; } + virtual GBool isBinary(GBool /*last*/ = gTrue) { return gFalse; } + virtual GBool isEncoder() { return gTrue; } + +private: + + char buf[8]; + char *bufPtr; + char *bufEnd; + int lineLen; + GBool eof; + + GBool fillBuf(); +}; + +//------------------------------------------------------------------------ +// RunLengthEncoder +//------------------------------------------------------------------------ + +class RunLengthEncoder: public FilterStream { +public: + + RunLengthEncoder(Stream *strA); + virtual ~RunLengthEncoder(); + virtual StreamKind getKind() { return strWeird; } + virtual void reset(); + virtual int getChar() + { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } + virtual int lookChar() + { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } + virtual GString *getPSFilter(int /*psLevel*/, char * /*indent*/) { return NULL; } + virtual GBool isBinary(GBool /*last*/ = gTrue) { return gTrue; } + virtual GBool isEncoder() { return gTrue; } + +private: + + char buf[131]; + char *bufPtr; + char *bufEnd; + char *nextEnd; + GBool eof; + + GBool fillBuf(); +}; + +#endif diff --git a/kpdf/xpdf/xpdf/TextOutputDev.cc b/kpdf/xpdf/xpdf/TextOutputDev.cc new file mode 100644 index 00000000..d2bfaf63 --- /dev/null +++ b/kpdf/xpdf/xpdf/TextOutputDev.cc @@ -0,0 +1,4090 @@ +//======================================================================== +// +// TextOutputDev.cc +// +// Copyright 1997-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include +#include +#ifdef WIN32 +#include // for O_BINARY +#include // for setmode +#endif +#include "gmem.h" +#include "GString.h" +#include "GList.h" +#include "config.h" +#include "Error.h" +#include "GlobalParams.h" +#include "UnicodeMap.h" +#include "UnicodeTypeTable.h" +#include "GfxState.h" +#include "Link.h" +#include "TextOutputDev.h" + +#ifdef MACOS +// needed for setting type/creator of MacOS files +#include "ICSupport.h" +#endif + +//------------------------------------------------------------------------ +// parameters +//------------------------------------------------------------------------ + +// Each bucket in a text pool includes baselines within a range of +// this many points. +#define textPoolStep 4 + +// Inter-character space width which will cause addChar to start a new +// word. +#define minWordBreakSpace 0.1 + +// Negative inter-character space width, i.e., overlap, which will +// cause addChar to start a new word. +#define minDupBreakOverlap 0.2 + +// Max distance between baselines of two lines within a block, as a +// fraction of the font size. +#define maxLineSpacingDelta 1.5 + +// Max difference in primary font sizes on two lines in the same +// block. Delta1 is used when examining new lines above and below the +// current block; delta2 is used when examining text that overlaps the +// current block; delta3 is used when examining text to the left and +// right of the current block. +#define maxBlockFontSizeDelta1 0.05 +#define maxBlockFontSizeDelta2 0.6 +#define maxBlockFontSizeDelta3 0.2 + +// Max difference in font sizes inside a word. +#define maxWordFontSizeDelta 0.05 + +// Maximum distance between baselines of two words on the same line, +// e.g., distance between subscript or superscript and the primary +// baseline, as a fraction of the font size. +#define maxIntraLineDelta 0.5 + +// Minimum inter-word spacing, as a fraction of the font size. (Only +// used for raw ordering.) +#define minWordSpacing 0.15 + +// Maximum inter-word spacing, as a fraction of the font size. +#define maxWordSpacing 1.5 + +// Maximum horizontal spacing which will allow a word to be pulled +// into a block. +#define minColSpacing1 0.3 + +// Minimum spacing between columns, as a fraction of the font size. +#define minColSpacing2 1.0 + +// Maximum vertical spacing between blocks within a flow, as a +// multiple of the font size. +#define maxBlockSpacing 2.5 + +// Minimum spacing between characters within a word, as a fraction of +// the font size. +#define minCharSpacing -0.2 + +// Maximum spacing between characters within a word, as a fraction of +// the font size, when there is no obvious extra-wide character +// spacing. +#define maxCharSpacing 0.03 + +// When extra-wide character spacing is detected, the inter-character +// space threshold is set to the minimum inter-character space +// multiplied by this constant. +#define maxWideCharSpacingMul 1.3 + +// Upper limit on spacing between characters in a word. +#define maxWideCharSpacing 0.4 + +// Max difference in primary,secondary coordinates (as a fraction of +// the font size) allowed for duplicated text (fake boldface, drop +// shadows) which is to be discarded. +#define dupMaxPriDelta 0.1 +#define dupMaxSecDelta 0.2 + +// Max width of underlines (in points). +#define maxUnderlineWidth 3 + +// Min distance between baseline and underline (in points). +//~ this should be font-size-dependent +#define minUnderlineGap -2 + +// Max distance between baseline and underline (in points). +//~ this should be font-size-dependent +#define maxUnderlineGap 4 + +// Max horizontal distance between edge of word and start of underline +// (in points). +//~ this should be font-size-dependent +#define underlineSlack 1 + +// Max distance between edge of text and edge of link border +#define hyperlinkSlack 2 + +//------------------------------------------------------------------------ +// TextUnderline +//------------------------------------------------------------------------ + +class TextUnderline { +public: + + TextUnderline(double x0A, double y0A, double x1A, double y1A) + { x0 = x0A; y0 = y0A; x1 = x1A; y1 = y1A; horiz = y0 == y1; } + ~TextUnderline() {} + + double x0, y0, x1, y1; + GBool horiz; +}; + +//------------------------------------------------------------------------ +// TextLink +//------------------------------------------------------------------------ + +class TextLink { +public: + + TextLink(int xMinA, int yMinA, int xMaxA, int yMaxA, Link *linkA) + { xMin = xMinA; yMin = yMinA; xMax = xMaxA; yMax = yMaxA; link = linkA; } + ~TextLink() {} + + int xMin, yMin, xMax, yMax; + Link *link; +}; + +//------------------------------------------------------------------------ +// TextFontInfo +//------------------------------------------------------------------------ + +TextFontInfo::TextFontInfo(GfxState *state) { + gfxFont = state->getFont(); +#if TEXTOUT_WORD_LIST + fontName = (gfxFont && gfxFont->getOrigName()) + ? gfxFont->getOrigName()->copy() + : (GString *)NULL; + flags = gfxFont ? gfxFont->getFlags() : 0; +#endif +} + +TextFontInfo::~TextFontInfo() { +#if TEXTOUT_WORD_LIST + if (fontName) { + delete fontName; + } +#endif +} + +GBool TextFontInfo::matches(GfxState *state) { + return state->getFont() == gfxFont; +} + +//------------------------------------------------------------------------ +// TextWord +//------------------------------------------------------------------------ + +TextWord::TextWord(GfxState *state, int rotA, double x0, double y0, + int charPosA, TextFontInfo *fontA, double fontSizeA) { + GfxFont *gfxFont; + double x, y, ascent, descent; + + rot = rotA; + charPos = charPosA; + charLen = 0; + font = fontA; + fontSize = fontSizeA; + state->transform(x0, y0, &x, &y); + if ((gfxFont = font->gfxFont)) { + ascent = gfxFont->getAscent() * fontSize; + descent = gfxFont->getDescent() * fontSize; + } else { + // this means that the PDF file draws text without a current font, + // which should never happen + ascent = 0.95 * fontSize; + descent = -0.35 * fontSize; + } + switch (rot) { + case 0: + yMin = y - ascent; + yMax = y - descent; + if (yMin == yMax) { + // this is a sanity check for a case that shouldn't happen -- but + // if it does happen, we want to avoid dividing by zero later + yMin = y; + yMax = y + 1; + } + base = y; + break; + case 1: + xMin = x + descent; + xMax = x + ascent; + if (xMin == xMax) { + // this is a sanity check for a case that shouldn't happen -- but + // if it does happen, we want to avoid dividing by zero later + xMin = x; + xMax = x + 1; + } + base = x; + break; + case 2: + yMin = y + descent; + yMax = y + ascent; + if (yMin == yMax) { + // this is a sanity check for a case that shouldn't happen -- but + // if it does happen, we want to avoid dividing by zero later + yMin = y; + yMax = y + 1; + } + base = y; + break; + case 3: + xMin = x - ascent; + xMax = x - descent; + if (xMin == xMax) { + // this is a sanity check for a case that shouldn't happen -- but + // if it does happen, we want to avoid dividing by zero later + xMin = x; + xMax = x + 1; + } + base = x; + break; + } + text = NULL; + edge = NULL; + len = size = 0; + spaceAfter = gFalse; + next = NULL; + +#if TEXTOUT_WORD_LIST + GfxRGB rgb; + + if ((state->getRender() & 3) == 1) { + state->getStrokeRGB(&rgb); + } else { + state->getFillRGB(&rgb); + } + colorR = colToDbl(rgb.r); + colorG = colToDbl(rgb.g); + colorB = colToDbl(rgb.b); +#endif + + underlined = gFalse; + link = NULL; +} + +TextWord::~TextWord() { + gfree(text); + gfree(edge); +} + +void TextWord::addChar(GfxState * /*state*/, double x, double y, + double dx, double dy, Unicode u) { + if (len == size) { + size += 16; + text = (Unicode *)greallocn(text, size, sizeof(Unicode)); + edge = (double *)greallocn(edge, size + 1, sizeof(double)); + } + text[len] = u; + switch (rot) { + case 0: + if (len == 0) { + xMin = x; + } + edge[len] = x; + xMax = edge[len+1] = x + dx; + break; + case 1: + if (len == 0) { + yMin = y; + } + edge[len] = y; + yMax = edge[len+1] = y + dy; + break; + case 2: + if (len == 0) { + xMax = x; + } + edge[len] = x; + xMin = edge[len+1] = x + dx; + break; + case 3: + if (len == 0) { + yMax = y; + } + edge[len] = y; + yMin = edge[len+1] = y + dy; + break; + } + ++len; +} + +void TextWord::merge(TextWord *word) { + int i; + + if (word->xMin < xMin) { + xMin = word->xMin; + } + if (word->yMin < yMin) { + yMin = word->yMin; + } + if (word->xMax > xMax) { + xMax = word->xMax; + } + if (word->yMax > yMax) { + yMax = word->yMax; + } + if (len + word->len > size) { + size = len + word->len; + text = (Unicode *)greallocn(text, size, sizeof(Unicode)); + edge = (double *)greallocn(edge, size + 1, sizeof(double)); + } + for (i = 0; i < word->len; ++i) { + text[len + i] = word->text[i]; + edge[len + i] = word->edge[i]; + } + edge[len + word->len] = word->edge[word->len]; + len += word->len; + charLen += word->charLen; +} + +inline int TextWord::primaryCmp(TextWord *word) { + double cmp; + + cmp = 0; // make gcc happy + switch (rot) { + case 0: + cmp = xMin - word->xMin; + break; + case 1: + cmp = yMin - word->yMin; + break; + case 2: + cmp = word->xMax - xMax; + break; + case 3: + cmp = word->yMax - yMax; + break; + } + return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; +} + +double TextWord::primaryDelta(TextWord *word) { + double delta; + + delta = 0; // make gcc happy + switch (rot) { + case 0: + delta = word->xMin - xMax; + break; + case 1: + delta = word->yMin - yMax; + break; + case 2: + delta = xMin - word->xMax; + break; + case 3: + delta = yMin - word->yMax; + break; + } + return delta; +} + +int TextWord::cmpYX(const void *p1, const void *p2) { + TextWord *word1 = *(TextWord **)p1; + TextWord *word2 = *(TextWord **)p2; + double cmp; + + cmp = word1->yMin - word2->yMin; + if (cmp == 0) { + cmp = word1->xMin - word2->xMin; + } + return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; +} + +#if TEXTOUT_WORD_LIST + +GString *TextWord::getText() { + GString *s; + UnicodeMap *uMap; + char buf[8]; + int n, i; + + s = new GString(); + if (!(uMap = globalParams->getTextEncoding())) { + return s; + } + for (i = 0; i < len; ++i) { + n = uMap->mapUnicode(text[i], buf, sizeof(buf)); + s->append(buf, n); + } + uMap->decRefCnt(); + return s; +} + +void TextWord::getCharBBox(int charIdx, double *xMinA, double *yMinA, + double *xMaxA, double *yMaxA) { + if (charIdx < 0 || charIdx >= len) { + return; + } + switch (rot) { + case 0: + *xMinA = edge[charIdx]; + *xMaxA = edge[charIdx + 1]; + *yMinA = yMin; + *yMaxA = yMax; + break; + case 1: + *xMinA = xMin; + *xMaxA = xMax; + *yMinA = edge[charIdx]; + *yMaxA = edge[charIdx + 1]; + break; + case 2: + *xMinA = edge[charIdx + 1]; + *xMaxA = edge[charIdx]; + *yMinA = yMin; + *yMaxA = yMax; + break; + case 3: + *xMinA = xMin; + *xMaxA = xMax; + *yMinA = edge[charIdx + 1]; + *yMaxA = edge[charIdx]; + break; + } +} + +#endif // TEXTOUT_WORD_LIST + +//------------------------------------------------------------------------ +// TextPool +//------------------------------------------------------------------------ + +TextPool::TextPool() { + minBaseIdx = 0; + maxBaseIdx = -1; + pool = NULL; + cursor = NULL; + cursorBaseIdx = -1; +} + +TextPool::~TextPool() { + int baseIdx; + TextWord *word, *word2; + + for (baseIdx = minBaseIdx; baseIdx <= maxBaseIdx; ++baseIdx) { + for (word = pool[baseIdx - minBaseIdx]; word; word = word2) { + word2 = word->next; + delete word; + } + } + gfree(pool); +} + +int TextPool::getBaseIdx(double base) { + int baseIdx; + + baseIdx = (int)(base / textPoolStep); + if (baseIdx < minBaseIdx) { + return minBaseIdx; + } + if (baseIdx > maxBaseIdx) { + return maxBaseIdx; + } + return baseIdx; +} + +void TextPool::addWord(TextWord *word) { + TextWord **newPool; + int wordBaseIdx, newMinBaseIdx, newMaxBaseIdx, baseIdx; + TextWord *w0, *w1; + + // expand the array if needed + wordBaseIdx = (int)(word->base / textPoolStep); + if (minBaseIdx > maxBaseIdx) { + minBaseIdx = wordBaseIdx - 128; + maxBaseIdx = wordBaseIdx + 128; + pool = (TextWord **)gmallocn(maxBaseIdx - minBaseIdx + 1, + sizeof(TextWord *)); + for (baseIdx = minBaseIdx; baseIdx <= maxBaseIdx; ++baseIdx) { + pool[baseIdx - minBaseIdx] = NULL; + } + } else if (wordBaseIdx < minBaseIdx) { + newMinBaseIdx = wordBaseIdx - 128; + newPool = (TextWord **)gmallocn(maxBaseIdx - newMinBaseIdx + 1, + sizeof(TextWord *)); + for (baseIdx = newMinBaseIdx; baseIdx < minBaseIdx; ++baseIdx) { + newPool[baseIdx - newMinBaseIdx] = NULL; + } + memcpy(&newPool[minBaseIdx - newMinBaseIdx], pool, + (maxBaseIdx - minBaseIdx + 1) * sizeof(TextWord *)); + gfree(pool); + pool = newPool; + minBaseIdx = newMinBaseIdx; + } else if (wordBaseIdx > maxBaseIdx) { + newMaxBaseIdx = wordBaseIdx + 128; + pool = (TextWord **)greallocn(pool, newMaxBaseIdx - minBaseIdx + 1, + sizeof(TextWord *)); + for (baseIdx = maxBaseIdx + 1; baseIdx <= newMaxBaseIdx; ++baseIdx) { + pool[baseIdx - minBaseIdx] = NULL; + } + maxBaseIdx = newMaxBaseIdx; + } + + // insert the new word + if (cursor && wordBaseIdx == cursorBaseIdx && + word->primaryCmp(cursor) > 0) { + w0 = cursor; + w1 = cursor->next; + } else { + w0 = NULL; + w1 = pool[wordBaseIdx - minBaseIdx]; + } + for (; w1 && word->primaryCmp(w1) > 0; w0 = w1, w1 = w1->next) ; + word->next = w1; + if (w0) { + w0->next = word; + } else { + pool[wordBaseIdx - minBaseIdx] = word; + } + cursor = word; + cursorBaseIdx = wordBaseIdx; +} + +//------------------------------------------------------------------------ +// TextLine +//------------------------------------------------------------------------ + +TextLine::TextLine(TextBlock *blkA, int rotA, double baseA) { + blk = blkA; + rot = rotA; + xMin = yMin = 0; + xMax = yMax = -1; + base = baseA; + words = lastWord = NULL; + text = NULL; + edge = NULL; + col = NULL; + len = 0; + convertedLen = 0; + hyphenated = gFalse; + next = NULL; +} + +TextLine::~TextLine() { + TextWord *word; + + while (words) { + word = words; + words = words->next; + delete word; + } + gfree(text); + gfree(edge); + gfree(col); +} + +void TextLine::addWord(TextWord *word) { + if (lastWord) { + lastWord->next = word; + } else { + words = word; + } + lastWord = word; + + if (xMin > xMax) { + xMin = word->xMin; + xMax = word->xMax; + yMin = word->yMin; + yMax = word->yMax; + } else { + if (word->xMin < xMin) { + xMin = word->xMin; + } + if (word->xMax > xMax) { + xMax = word->xMax; + } + if (word->yMin < yMin) { + yMin = word->yMin; + } + if (word->yMax > yMax) { + yMax = word->yMax; + } + } +} + +double TextLine::primaryDelta(TextLine *line) { + double delta; + + delta = 0; // make gcc happy + switch (rot) { + case 0: + delta = line->xMin - xMax; + break; + case 1: + delta = line->yMin - yMax; + break; + case 2: + delta = xMin - line->xMax; + break; + case 3: + delta = yMin - line->yMax; + break; + } + return delta; +} + +int TextLine::primaryCmp(TextLine *line) { + double cmp; + + cmp = 0; // make gcc happy + switch (rot) { + case 0: + cmp = xMin - line->xMin; + break; + case 1: + cmp = yMin - line->yMin; + break; + case 2: + cmp = line->xMax - xMax; + break; + case 3: + cmp = line->yMax - yMax; + break; + } + return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; +} + +int TextLine::secondaryCmp(TextLine *line) { + double cmp; + + cmp = (rot == 0 || rot == 3) ? base - line->base : line->base - base; + return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; +} + +int TextLine::cmpYX(TextLine *line) { + int cmp; + + if ((cmp = secondaryCmp(line))) { + return cmp; + } + return primaryCmp(line); +} + +int TextLine::cmpXY(const void *p1, const void *p2) { + TextLine *line1 = *(TextLine **)p1; + TextLine *line2 = *(TextLine **)p2; + int cmp; + + if ((cmp = line1->primaryCmp(line2))) { + return cmp; + } + return line1->secondaryCmp(line2); +} + +void TextLine::coalesce(UnicodeMap *uMap) { + TextWord *word0, *word1; + double space, delta, minSpace; + GBool isUnicode; + char buf[8]; + int i, j; + + if (words->next) { + + // compute the inter-word space threshold + if (words->len > 1 || words->next->len > 1) { + minSpace = 0; + } else { + minSpace = words->primaryDelta(words->next); + for (word0 = words->next, word1 = word0->next; + word1 && minSpace > 0; + word0 = word1, word1 = word0->next) { + if (word1->len > 1) { + minSpace = 0; + } + delta = word0->primaryDelta(word1); + if (delta < minSpace) { + minSpace = delta; + } + } + } + if (minSpace <= 0) { + space = maxCharSpacing * words->fontSize; + } else { + space = maxWideCharSpacingMul * minSpace; + if (space > maxWideCharSpacing * words->fontSize) { + space = maxWideCharSpacing * words->fontSize; + } + } + + // merge words + word0 = words; + word1 = words->next; + while (word1) { + if (word0->primaryDelta(word1) >= space) { + word0->spaceAfter = gTrue; + word0 = word1; + word1 = word1->next; + } else if (word0->font == word1->font && + word0->underlined == word1->underlined && + fabs(word0->fontSize - word1->fontSize) < + maxWordFontSizeDelta * words->fontSize && + word1->charPos == word0->charPos + word0->charLen) { + word0->merge(word1); + word0->next = word1->next; + delete word1; + word1 = word0->next; + } else { + word0 = word1; + word1 = word1->next; + } + } + } + + // build the line text + isUnicode = uMap ? uMap->isUnicode() : gFalse; + len = 0; + for (word1 = words; word1; word1 = word1->next) { + len += word1->len; + if (word1->spaceAfter) { + ++len; + } + } + text = (Unicode *)gmallocn(len, sizeof(Unicode)); + edge = (double *)gmallocn(len + 1, sizeof(double)); + i = 0; + for (word1 = words; word1; word1 = word1->next) { + for (j = 0; j < word1->len; ++j) { + text[i] = word1->text[j]; + edge[i] = word1->edge[j]; + ++i; + } + edge[i] = word1->edge[word1->len]; + if (word1->spaceAfter) { + text[i] = (Unicode)0x0020; + ++i; + } + } + + // compute convertedLen and set up the col array + col = (int *)gmallocn(len + 1, sizeof(int)); + convertedLen = 0; + for (i = 0; i < len; ++i) { + col[i] = convertedLen; + if (isUnicode) { + ++convertedLen; + } else if (uMap) { + convertedLen += uMap->mapUnicode(text[i], buf, sizeof(buf)); + } + } + col[len] = convertedLen; + + // check for hyphen at end of line + //~ need to check for other chars used as hyphens + hyphenated = text[len - 1] == (Unicode)'-'; +} + +//------------------------------------------------------------------------ +// TextLineFrag +//------------------------------------------------------------------------ + +class TextLineFrag { +public: + + TextLine *line; // the line object + int start, len; // offset and length of this fragment + // (in Unicode chars) + double xMin, xMax; // bounding box coordinates + double yMin, yMax; + double base; // baseline virtual coordinate + int col; // first column + + void init(TextLine *lineA, int startA, int lenA); + void computeCoords(GBool oneRot); + + static int cmpYXPrimaryRot(const void *p1, const void *p2); + static int cmpYXLineRot(const void *p1, const void *p2); + static int cmpXYLineRot(const void *p1, const void *p2); + static int cmpXYColumnPrimaryRot(const void *p1, const void *p2); + static int cmpXYColumnLineRot(const void *p1, const void *p2); +}; + +void TextLineFrag::init(TextLine *lineA, int startA, int lenA) { + line = lineA; + start = startA; + len = lenA; + col = line->col[start]; +} + +void TextLineFrag::computeCoords(GBool oneRot) { + TextBlock *blk; + double d0, d1, d2, d3, d4; + + if (oneRot) { + + switch (line->rot) { + case 0: + xMin = line->edge[start]; + xMax = line->edge[start + len]; + yMin = line->yMin; + yMax = line->yMax; + break; + case 1: + xMin = line->xMin; + xMax = line->xMax; + yMin = line->edge[start]; + yMax = line->edge[start + len]; + break; + case 2: + xMin = line->edge[start + len]; + xMax = line->edge[start]; + yMin = line->yMin; + yMax = line->yMax; + break; + case 3: + xMin = line->xMin; + xMax = line->xMax; + yMin = line->edge[start + len]; + yMax = line->edge[start]; + break; + } + base = line->base; + + } else { + + if (line->rot == 0 && line->blk->page->primaryRot == 0) { + + xMin = line->edge[start]; + xMax = line->edge[start + len]; + yMin = line->yMin; + yMax = line->yMax; + base = line->base; + + } else { + + blk = line->blk; + d0 = line->edge[start]; + d1 = line->edge[start + len]; + d2 = d3 = d4 = 0; // make gcc happy + + switch (line->rot) { + case 0: + d2 = line->yMin; + d3 = line->yMax; + d4 = line->base; + d0 = (d0 - blk->xMin) / (blk->xMax - blk->xMin); + d1 = (d1 - blk->xMin) / (blk->xMax - blk->xMin); + d2 = (d2 - blk->yMin) / (blk->yMax - blk->yMin); + d3 = (d3 - blk->yMin) / (blk->yMax - blk->yMin); + d4 = (d4 - blk->yMin) / (blk->yMax - blk->yMin); + break; + case 1: + d2 = line->xMax; + d3 = line->xMin; + d4 = line->base; + d0 = (d0 - blk->yMin) / (blk->yMax - blk->yMin); + d1 = (d1 - blk->yMin) / (blk->yMax - blk->yMin); + d2 = (blk->xMax - d2) / (blk->xMax - blk->xMin); + d3 = (blk->xMax - d3) / (blk->xMax - blk->xMin); + d4 = (blk->xMax - d4) / (blk->xMax - blk->xMin); + break; + case 2: + d2 = line->yMax; + d3 = line->yMin; + d4 = line->base; + d0 = (blk->xMax - d0) / (blk->xMax - blk->xMin); + d1 = (blk->xMax - d1) / (blk->xMax - blk->xMin); + d2 = (blk->yMax - d2) / (blk->yMax - blk->yMin); + d3 = (blk->yMax - d3) / (blk->yMax - blk->yMin); + d4 = (blk->yMax - d4) / (blk->yMax - blk->yMin); + break; + case 3: + d2 = line->xMin; + d3 = line->xMax; + d4 = line->base; + d0 = (blk->yMax - d0) / (blk->yMax - blk->yMin); + d1 = (blk->yMax - d1) / (blk->yMax - blk->yMin); + d2 = (d2 - blk->xMin) / (blk->xMax - blk->xMin); + d3 = (d3 - blk->xMin) / (blk->xMax - blk->xMin); + d4 = (d4 - blk->xMin) / (blk->xMax - blk->xMin); + break; + } + + switch (line->blk->page->primaryRot) { + case 0: + xMin = blk->xMin + d0 * (blk->xMax - blk->xMin); + xMax = blk->xMin + d1 * (blk->xMax - blk->xMin); + yMin = blk->yMin + d2 * (blk->yMax - blk->yMin); + yMax = blk->yMin + d3 * (blk->yMax - blk->yMin); + base = blk->yMin + base * (blk->yMax - blk->yMin); + break; + case 1: + xMin = blk->xMax - d3 * (blk->xMax - blk->xMin); + xMax = blk->xMax - d2 * (blk->xMax - blk->xMin); + yMin = blk->yMin + d0 * (blk->yMax - blk->yMin); + yMax = blk->yMin + d1 * (blk->yMax - blk->yMin); + base = blk->xMax - d4 * (blk->xMax - blk->xMin); + break; + case 2: + xMin = blk->xMax - d1 * (blk->xMax - blk->xMin); + xMax = blk->xMax - d0 * (blk->xMax - blk->xMin); + yMin = blk->yMax - d3 * (blk->yMax - blk->yMin); + yMax = blk->yMax - d2 * (blk->yMax - blk->yMin); + base = blk->yMax - d4 * (blk->yMax - blk->yMin); + break; + case 3: + xMin = blk->xMin + d2 * (blk->xMax - blk->xMin); + xMax = blk->xMin + d3 * (blk->xMax - blk->xMin); + yMin = blk->yMax - d1 * (blk->yMax - blk->yMin); + yMax = blk->yMax - d0 * (blk->yMax - blk->yMin); + base = blk->xMin + d4 * (blk->xMax - blk->xMin); + break; + } + + } + } +} + +int TextLineFrag::cmpYXPrimaryRot(const void *p1, const void *p2) { + TextLineFrag *frag1 = (TextLineFrag *)p1; + TextLineFrag *frag2 = (TextLineFrag *)p2; + double cmp; + + cmp = 0; // make gcc happy + switch (frag1->line->blk->page->primaryRot) { + case 0: + if (fabs(cmp = frag1->yMin - frag2->yMin) < 0.01) { + cmp = frag1->xMin - frag2->xMin; + } + break; + case 1: + if (fabs(cmp = frag2->xMax - frag1->xMax) < 0.01) { + cmp = frag1->yMin - frag2->yMin; + } + break; + case 2: + if (fabs(cmp = frag2->yMin - frag1->yMin) < 0.01) { + cmp = frag2->xMax - frag1->xMax; + } + break; + case 3: + if (fabs(cmp = frag1->xMax - frag2->xMax) < 0.01) { + cmp = frag2->yMax - frag1->yMax; + } + break; + } + return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; +} + +int TextLineFrag::cmpYXLineRot(const void *p1, const void *p2) { + TextLineFrag *frag1 = (TextLineFrag *)p1; + TextLineFrag *frag2 = (TextLineFrag *)p2; + double cmp; + + cmp = 0; // make gcc happy + switch (frag1->line->rot) { + case 0: + if ((cmp = frag1->yMin - frag2->yMin) == 0) { + cmp = frag1->xMin - frag2->xMin; + } + break; + case 1: + if ((cmp = frag2->xMax - frag1->xMax) == 0) { + cmp = frag1->yMin - frag2->yMin; + } + break; + case 2: + if ((cmp = frag2->yMin - frag1->yMin) == 0) { + cmp = frag2->xMax - frag1->xMax; + } + break; + case 3: + if ((cmp = frag1->xMax - frag2->xMax) == 0) { + cmp = frag2->yMax - frag1->yMax; + } + break; + } + return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; +} + +int TextLineFrag::cmpXYLineRot(const void *p1, const void *p2) { + TextLineFrag *frag1 = (TextLineFrag *)p1; + TextLineFrag *frag2 = (TextLineFrag *)p2; + double cmp; + + cmp = 0; // make gcc happy + switch (frag1->line->rot) { + case 0: + if ((cmp = frag1->xMin - frag2->xMin) == 0) { + cmp = frag1->yMin - frag2->yMin; + } + break; + case 1: + if ((cmp = frag1->yMin - frag2->yMin) == 0) { + cmp = frag2->xMax - frag1->xMax; + } + break; + case 2: + if ((cmp = frag2->xMax - frag1->xMax) == 0) { + cmp = frag2->yMin - frag1->yMin; + } + break; + case 3: + if ((cmp = frag2->yMax - frag1->yMax) == 0) { + cmp = frag1->xMax - frag2->xMax; + } + break; + } + return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; +} + +int TextLineFrag::cmpXYColumnPrimaryRot(const void *p1, const void *p2) { + TextLineFrag *frag1 = (TextLineFrag *)p1; + TextLineFrag *frag2 = (TextLineFrag *)p2; + double cmp; + + // if columns overlap, compare y values + if (frag1->col < frag2->col + (frag2->line->col[frag2->start + frag2->len] - + frag2->line->col[frag2->start]) && + frag2->col < frag1->col + (frag1->line->col[frag1->start + frag1->len] - + frag1->line->col[frag1->start])) { + cmp = 0; // make gcc happy + switch (frag1->line->blk->page->primaryRot) { + case 0: cmp = frag1->yMin - frag2->yMin; break; + case 1: cmp = frag2->xMax - frag1->xMax; break; + case 2: cmp = frag2->yMin - frag1->yMin; break; + case 3: cmp = frag1->xMax - frag2->xMax; break; + } + return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; + } + + // otherwise, compare starting column + return frag1->col - frag2->col; +} + +int TextLineFrag::cmpXYColumnLineRot(const void *p1, const void *p2) { + TextLineFrag *frag1 = (TextLineFrag *)p1; + TextLineFrag *frag2 = (TextLineFrag *)p2; + double cmp; + + // if columns overlap, compare y values + if (frag1->col < frag2->col + (frag2->line->col[frag2->start + frag2->len] - + frag2->line->col[frag2->start]) && + frag2->col < frag1->col + (frag1->line->col[frag1->start + frag1->len] - + frag1->line->col[frag1->start])) { + cmp = 0; // make gcc happy + switch (frag1->line->rot) { + case 0: cmp = frag1->yMin - frag2->yMin; break; + case 1: cmp = frag2->xMax - frag1->xMax; break; + case 2: cmp = frag2->yMin - frag1->yMin; break; + case 3: cmp = frag1->xMax - frag2->xMax; break; + } + return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; + } + + // otherwise, compare starting column + return frag1->col - frag2->col; +} + +//------------------------------------------------------------------------ +// TextBlock +//------------------------------------------------------------------------ + +TextBlock::TextBlock(TextPage *pageA, int rotA) { + page = pageA; + rot = rotA; + xMin = yMin = 0; + xMax = yMax = -1; + priMin = 0; + priMax = page->pageWidth; + pool = new TextPool(); + lines = NULL; + curLine = NULL; + next = NULL; + stackNext = NULL; +} + +TextBlock::~TextBlock() { + TextLine *line; + + delete pool; + while (lines) { + line = lines; + lines = lines->next; + delete line; + } +} + +void TextBlock::addWord(TextWord *word) { + pool->addWord(word); + if (xMin > xMax) { + xMin = word->xMin; + xMax = word->xMax; + yMin = word->yMin; + yMax = word->yMax; + } else { + if (word->xMin < xMin) { + xMin = word->xMin; + } + if (word->xMax > xMax) { + xMax = word->xMax; + } + if (word->yMin < yMin) { + yMin = word->yMin; + } + if (word->yMax > yMax) { + yMax = word->yMax; + } + } +} + +void TextBlock::coalesce(UnicodeMap *uMap) { + TextWord *word0, *word1, *word2, *bestWord0, *bestWord1, *lastWord; + TextLine *line, *line0, *line1; + int poolMinBaseIdx, startBaseIdx, minBaseIdx, maxBaseIdx; + int baseIdx, bestWordBaseIdx, idx0, idx1; + double minBase, maxBase; + double fontSize, delta, priDelta, secDelta; + TextLine **lineArray; + GBool found; + int col1, col2; + int i, j, k; + + // discard duplicated text (fake boldface, drop shadows) + for (idx0 = pool->minBaseIdx; idx0 <= pool->maxBaseIdx; ++idx0) { + word0 = pool->getPool(idx0); + while (word0) { + priDelta = dupMaxPriDelta * word0->fontSize; + secDelta = dupMaxSecDelta * word0->fontSize; + if (rot == 0 || rot == 3) { + maxBaseIdx = pool->getBaseIdx(word0->base + secDelta); + } else { + maxBaseIdx = pool->getBaseIdx(word0->base - secDelta); + } + found = gFalse; + word1 = word2 = NULL; // make gcc happy + for (idx1 = idx0; idx1 <= maxBaseIdx; ++idx1) { + if (idx1 == idx0) { + word1 = word0; + word2 = word0->next; + } else { + word1 = NULL; + word2 = pool->getPool(idx1); + } + for (; word2; word1 = word2, word2 = word2->next) { + if (word2->len == word0->len && + !memcmp(word2->text, word0->text, + word0->len * sizeof(Unicode))) { + switch (rot) { + case 0: + case 2: + found = fabs(word0->xMin - word2->xMin) < priDelta && + fabs(word0->xMax - word2->xMax) < priDelta && + fabs(word0->yMin - word2->yMin) < secDelta && + fabs(word0->yMax - word2->yMax) < secDelta; + break; + case 1: + case 3: + found = fabs(word0->xMin - word2->xMin) < secDelta && + fabs(word0->xMax - word2->xMax) < secDelta && + fabs(word0->yMin - word2->yMin) < priDelta && + fabs(word0->yMax - word2->yMax) < priDelta; + break; + } + } + if (found) { + break; + } + } + if (found) { + break; + } + } + if (found) { + if (word1) { + word1->next = word2->next; + } else { + pool->setPool(idx1, word2->next); + } + delete word2; + } else { + word0 = word0->next; + } + } + } + + // build the lines + curLine = NULL; + poolMinBaseIdx = pool->minBaseIdx; + charCount = 0; + nLines = 0; + while (1) { + + // find the first non-empty line in the pool + for (; + poolMinBaseIdx <= pool->maxBaseIdx && !pool->getPool(poolMinBaseIdx); + ++poolMinBaseIdx) ; + if (poolMinBaseIdx > pool->maxBaseIdx) { + break; + } + + // look for the left-most word in the first four lines of the + // pool -- this avoids starting with a superscript word + startBaseIdx = poolMinBaseIdx; + for (baseIdx = poolMinBaseIdx + 1; + baseIdx < poolMinBaseIdx + 4 && baseIdx <= pool->maxBaseIdx; + ++baseIdx) { + if (!pool->getPool(baseIdx)) { + continue; + } + if (pool->getPool(baseIdx)->primaryCmp(pool->getPool(startBaseIdx)) + < 0) { + startBaseIdx = baseIdx; + } + } + + // create a new line + word0 = pool->getPool(startBaseIdx); + pool->setPool(startBaseIdx, word0->next); + word0->next = NULL; + line = new TextLine(this, word0->rot, word0->base); + line->addWord(word0); + lastWord = word0; + + // compute the search range + fontSize = word0->fontSize; + minBase = word0->base - maxIntraLineDelta * fontSize; + maxBase = word0->base + maxIntraLineDelta * fontSize; + minBaseIdx = pool->getBaseIdx(minBase); + maxBaseIdx = pool->getBaseIdx(maxBase); + + // find the rest of the words in this line + while (1) { + + // find the left-most word whose baseline is in the range for + // this line + bestWordBaseIdx = 0; + bestWord0 = bestWord1 = NULL; + for (baseIdx = minBaseIdx; baseIdx <= maxBaseIdx; ++baseIdx) { + for (word0 = NULL, word1 = pool->getPool(baseIdx); + word1; + word0 = word1, word1 = word1->next) { + if (word1->base >= minBase && + word1->base <= maxBase && + (delta = lastWord->primaryDelta(word1)) >= + minCharSpacing * fontSize) { + if (delta < maxWordSpacing * fontSize && + (!bestWord1 || word1->primaryCmp(bestWord1) < 0)) { + bestWordBaseIdx = baseIdx; + bestWord0 = word0; + bestWord1 = word1; + } + break; + } + } + } + if (!bestWord1) { + break; + } + + // remove it from the pool, and add it to the line + if (bestWord0) { + bestWord0->next = bestWord1->next; + } else { + pool->setPool(bestWordBaseIdx, bestWord1->next); + } + bestWord1->next = NULL; + line->addWord(bestWord1); + lastWord = bestWord1; + } + + // add the line + if (curLine && line->cmpYX(curLine) > 0) { + line0 = curLine; + line1 = curLine->next; + } else { + line0 = NULL; + line1 = lines; + } + for (; + line1 && line->cmpYX(line1) > 0; + line0 = line1, line1 = line1->next) ; + if (line0) { + line0->next = line; + } else { + lines = line; + } + line->next = line1; + curLine = line; + line->coalesce(uMap); + charCount += line->len; + ++nLines; + } + + // sort lines into xy order for column assignment + lineArray = (TextLine **)gmallocn(nLines, sizeof(TextLine *)); + for (line = lines, i = 0; line; line = line->next, ++i) { + lineArray[i] = line; + } + qsort(lineArray, nLines, sizeof(TextLine *), &TextLine::cmpXY); + + // column assignment + nColumns = 0; + for (i = 0; i < nLines; ++i) { + line0 = lineArray[i]; + col1 = 0; + for (j = 0; j < i; ++j) { + line1 = lineArray[j]; + if (line1->primaryDelta(line0) >= 0) { + col2 = line1->col[line1->len] + 1; + } else { + k = 0; // make gcc happy + switch (rot) { + case 0: + for (k = 0; + k < line1->len && + line0->xMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]); + ++k) ; + break; + case 1: + for (k = 0; + k < line1->len && + line0->yMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]); + ++k) ; + break; + case 2: + for (k = 0; + k < line1->len && + line0->xMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]); + ++k) ; + break; + case 3: + for (k = 0; + k < line1->len && + line0->yMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]); + ++k) ; + break; + } + col2 = line1->col[k]; + } + if (col2 > col1) { + col1 = col2; + } + } + for (k = 0; k <= line0->len; ++k) { + line0->col[k] += col1; + } + if (line0->col[line0->len] > nColumns) { + nColumns = line0->col[line0->len]; + } + } + gfree(lineArray); +} + +void TextBlock::updatePriMinMax(TextBlock *blk) { + double newPriMin, newPriMax; + GBool gotPriMin, gotPriMax; + + gotPriMin = gotPriMax = gFalse; + newPriMin = newPriMax = 0; // make gcc happy + switch (page->primaryRot) { + case 0: + case 2: + if (blk->yMin < yMax && blk->yMax > yMin) { + if (blk->xMin < xMin) { + newPriMin = blk->xMax; + gotPriMin = gTrue; + } + if (blk->xMax > xMax) { + newPriMax = blk->xMin; + gotPriMax = gTrue; + } + } + break; + case 1: + case 3: + if (blk->xMin < xMax && blk->xMax > xMin) { + if (blk->yMin < yMin) { + newPriMin = blk->yMax; + gotPriMin = gTrue; + } + if (blk->yMax > yMax) { + newPriMax = blk->yMin; + gotPriMax = gTrue; + } + } + break; + } + if (gotPriMin) { + if (newPriMin > xMin) { + newPriMin = xMin; + } + if (newPriMin > priMin) { + priMin = newPriMin; + } + } + if (gotPriMax) { + if (newPriMax < xMax) { + newPriMax = xMax; + } + if (newPriMax < priMax) { + priMax = newPriMax; + } + } +} + +int TextBlock::cmpXYPrimaryRot(const void *p1, const void *p2) { + TextBlock *blk1 = *(TextBlock **)p1; + TextBlock *blk2 = *(TextBlock **)p2; + double cmp; + + cmp = 0; // make gcc happy + switch (blk1->page->primaryRot) { + case 0: + if ((cmp = blk1->xMin - blk2->xMin) == 0) { + cmp = blk1->yMin - blk2->yMin; + } + break; + case 1: + if ((cmp = blk1->yMin - blk2->yMin) == 0) { + cmp = blk2->xMax - blk1->xMax; + } + break; + case 2: + if ((cmp = blk2->xMax - blk1->xMax) == 0) { + cmp = blk2->yMin - blk1->yMin; + } + break; + case 3: + if ((cmp = blk2->yMax - blk1->yMax) == 0) { + cmp = blk1->xMax - blk2->xMax; + } + break; + } + return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; +} + +int TextBlock::cmpYXPrimaryRot(const void *p1, const void *p2) { + TextBlock *blk1 = *(TextBlock **)p1; + TextBlock *blk2 = *(TextBlock **)p2; + double cmp; + + cmp = 0; // make gcc happy + switch (blk1->page->primaryRot) { + case 0: + if ((cmp = blk1->yMin - blk2->yMin) == 0) { + cmp = blk1->xMin - blk2->xMin; + } + break; + case 1: + if ((cmp = blk2->xMax - blk1->xMax) == 0) { + cmp = blk1->yMin - blk2->yMin; + } + break; + case 2: + if ((cmp = blk2->yMin - blk1->yMin) == 0) { + cmp = blk2->xMax - blk1->xMax; + } + break; + case 3: + if ((cmp = blk1->xMax - blk2->xMax) == 0) { + cmp = blk2->yMax - blk1->yMax; + } + break; + } + return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; +} + +int TextBlock::primaryCmp(TextBlock *blk) { + double cmp; + + cmp = 0; // make gcc happy + switch (rot) { + case 0: + cmp = xMin - blk->xMin; + break; + case 1: + cmp = yMin - blk->yMin; + break; + case 2: + cmp = blk->xMax - xMax; + break; + case 3: + cmp = blk->yMax - yMax; + break; + } + return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; +} + +double TextBlock::secondaryDelta(TextBlock *blk) { + double delta; + + delta = 0; // make gcc happy + switch (rot) { + case 0: + delta = blk->yMin - yMax; + break; + case 1: + delta = xMin - blk->xMax; + break; + case 2: + delta = yMin - blk->yMax; + break; + case 3: + delta = blk->xMin - xMax; + break; + } + return delta; +} + +GBool TextBlock::isBelow(TextBlock *blk) { + GBool below; + + below = gFalse; // make gcc happy + switch (page->primaryRot) { + case 0: + below = xMin >= blk->priMin && xMax <= blk->priMax && + yMin > blk->yMin; + break; + case 1: + below = yMin >= blk->priMin && yMax <= blk->priMax && + xMax < blk->xMax; + break; + case 2: + below = xMin >= blk->priMin && xMax <= blk->priMax && + yMax < blk->yMax; + break; + case 3: + below = yMin >= blk->priMin && yMax <= blk->priMax && + xMin > blk->xMin; + break; + } + + return below; +} + +//------------------------------------------------------------------------ +// TextFlow +//------------------------------------------------------------------------ + +TextFlow::TextFlow(TextPage *pageA, TextBlock *blk) { + page = pageA; + xMin = blk->xMin; + xMax = blk->xMax; + yMin = blk->yMin; + yMax = blk->yMax; + priMin = blk->priMin; + priMax = blk->priMax; + blocks = lastBlk = blk; + next = NULL; +} + +TextFlow::~TextFlow() { + TextBlock *blk; + + while (blocks) { + blk = blocks; + blocks = blocks->next; + delete blk; + } +} + +void TextFlow::addBlock(TextBlock *blk) { + if (lastBlk) { + lastBlk->next = blk; + } else { + blocks = blk; + } + lastBlk = blk; + if (blk->xMin < xMin) { + xMin = blk->xMin; + } + if (blk->xMax > xMax) { + xMax = blk->xMax; + } + if (blk->yMin < yMin) { + yMin = blk->yMin; + } + if (blk->yMax > yMax) { + yMax = blk->yMax; + } +} + +GBool TextFlow::blockFits(TextBlock *blk, TextBlock * /*prevBlk*/) { + GBool fits; + + // lower blocks must use smaller fonts + if (blk->lines->words->fontSize > lastBlk->lines->words->fontSize) { + return gFalse; + } + + fits = gFalse; // make gcc happy + switch (page->primaryRot) { + case 0: + fits = blk->xMin >= priMin && blk->xMax <= priMax; + break; + case 1: + fits = blk->yMin >= priMin && blk->yMax <= priMax; + break; + case 2: + fits = blk->xMin >= priMin && blk->xMax <= priMax; + break; + case 3: + fits = blk->yMin >= priMin && blk->yMax <= priMax; + break; + } + return fits; +} + +#if TEXTOUT_WORD_LIST + +//------------------------------------------------------------------------ +// TextWordList +//------------------------------------------------------------------------ + +TextWordList::TextWordList(TextPage *text, GBool physLayout) { + TextFlow *flow; + TextBlock *blk; + TextLine *line; + TextWord *word; + TextWord **wordArray; + int nWords, i; + + words = new GList(); + + if (text->rawOrder) { + for (word = text->rawWords; word; word = word->next) { + words->append(word); + } + + } else if (physLayout) { + // this is inefficient, but it's also the least useful of these + // three cases + nWords = 0; + for (flow = text->flows; flow; flow = flow->next) { + for (blk = flow->blocks; blk; blk = blk->next) { + for (line = blk->lines; line; line = line->next) { + for (word = line->words; word; word = word->next) { + ++nWords; + } + } + } + } + wordArray = (TextWord **)gmallocn(nWords, sizeof(TextWord *)); + i = 0; + for (flow = text->flows; flow; flow = flow->next) { + for (blk = flow->blocks; blk; blk = blk->next) { + for (line = blk->lines; line; line = line->next) { + for (word = line->words; word; word = word->next) { + wordArray[i++] = word; + } + } + } + } + qsort(wordArray, nWords, sizeof(TextWord *), &TextWord::cmpYX); + for (i = 0; i < nWords; ++i) { + words->append(wordArray[i]); + } + gfree(wordArray); + + } else { + for (flow = text->flows; flow; flow = flow->next) { + for (blk = flow->blocks; blk; blk = blk->next) { + for (line = blk->lines; line; line = line->next) { + for (word = line->words; word; word = word->next) { + words->append(word); + } + } + } + } + } +} + +TextWordList::~TextWordList() { + delete words; +} + +int TextWordList::getLength() { + return words->getLength(); +} + +TextWord *TextWordList::get(int idx) { + if (idx < 0 || idx >= words->getLength()) { + return NULL; + } + return (TextWord *)words->get(idx); +} + +#endif // TEXTOUT_WORD_LIST + +//------------------------------------------------------------------------ +// TextPage +//------------------------------------------------------------------------ + +TextPage::TextPage(GBool rawOrderA) { + int rot; + + rawOrder = rawOrderA; + curWord = NULL; + charPos = 0; + curFont = NULL; + curFontSize = 0; + nest = 0; + nTinyChars = 0; + lastCharOverlap = gFalse; + if (!rawOrder) { + for (rot = 0; rot < 4; ++rot) { + pools[rot] = new TextPool(); + } + } + flows = NULL; + blocks = NULL; + rawWords = NULL; + rawLastWord = NULL; + fonts = new GList(); + lastFindXMin = lastFindYMin = 0; + haveLastFind = gFalse; + underlines = new GList(); + links = new GList(); +} + +TextPage::~TextPage() { + int rot; + + clear(); + if (!rawOrder) { + for (rot = 0; rot < 4; ++rot) { + delete pools[rot]; + } + } + delete fonts; + deleteGList(underlines, TextUnderline); + deleteGList(links, TextLink); +} + +void TextPage::startPage(GfxState *state) { + clear(); + if (state) { + pageWidth = state->getPageWidth(); + pageHeight = state->getPageHeight(); + } else { + pageWidth = pageHeight = 0; + } +} + +void TextPage::endPage() { + if (curWord) { + endWord(); + } +} + +void TextPage::clear() { + int rot; + TextFlow *flow; + TextWord *word; + + if (curWord) { + delete curWord; + curWord = NULL; + } + if (rawOrder) { + while (rawWords) { + word = rawWords; + rawWords = rawWords->next; + delete word; + } + } else { + for (rot = 0; rot < 4; ++rot) { + delete pools[rot]; + } + while (flows) { + flow = flows; + flows = flows->next; + delete flow; + } + gfree(blocks); + } + deleteGList(fonts, TextFontInfo); + + curWord = NULL; + charPos = 0; + curFont = NULL; + curFontSize = 0; + nest = 0; + nTinyChars = 0; + if (!rawOrder) { + for (rot = 0; rot < 4; ++rot) { + pools[rot] = new TextPool(); + } + } + flows = NULL; + blocks = NULL; + rawWords = NULL; + rawLastWord = NULL; + fonts = new GList(); +} + +void TextPage::updateFont(GfxState *state) { + GfxFont *gfxFont; + double *fm; + char *name; + int code, mCode, letterCode, anyCode; + double w; + int i; + + // get the font info object + curFont = NULL; + for (i = 0; i < fonts->getLength(); ++i) { + curFont = (TextFontInfo *)fonts->get(i); + if (curFont->matches(state)) { + break; + } + curFont = NULL; + } + if (!curFont) { + curFont = new TextFontInfo(state); + fonts->append(curFont); + } + + // adjust the font size + gfxFont = state->getFont(); + curFontSize = state->getTransformedFontSize(); + if (gfxFont && gfxFont->getType() == fontType3) { + // This is a hack which makes it possible to deal with some Type 3 + // fonts. The problem is that it's impossible to know what the + // base coordinate system used in the font is without actually + // rendering the font. This code tries to guess by looking at the + // width of the character 'm' (which breaks if the font is a + // subset that doesn't contain 'm'). + mCode = letterCode = anyCode = -1; + for (code = 0; code < 256; ++code) { + name = ((Gfx8BitFont *)gfxFont)->getCharName(code); + if (name && name[0] == 'm' && name[1] == '\0') { + mCode = code; + } + if (letterCode < 0 && name && name[1] == '\0' && + ((name[0] >= 'A' && name[0] <= 'Z') || + (name[0] >= 'a' && name[0] <= 'z'))) { + letterCode = code; + } + if (anyCode < 0 && name && + ((Gfx8BitFont *)gfxFont)->getWidth(code) > 0) { + anyCode = code; + } + } + if (mCode >= 0 && + (w = ((Gfx8BitFont *)gfxFont)->getWidth(mCode)) > 0) { + // 0.6 is a generic average 'm' width -- yes, this is a hack + curFontSize *= w / 0.6; + } else if (letterCode >= 0 && + (w = ((Gfx8BitFont *)gfxFont)->getWidth(letterCode)) > 0) { + // even more of a hack: 0.5 is a generic letter width + curFontSize *= w / 0.5; + } else if (anyCode >= 0 && + (w = ((Gfx8BitFont *)gfxFont)->getWidth(anyCode)) > 0) { + // better than nothing: 0.5 is a generic character width + curFontSize *= w / 0.5; + } + fm = gfxFont->getFontMatrix(); + if (fm[0] != 0) { + curFontSize *= fabs(fm[3] / fm[0]); + } + } +} + +void TextPage::beginWord(GfxState *state, double x0, double y0) { + double *fontm; + double m[4], m2[4]; + int rot; + + // This check is needed because Type 3 characters can contain + // text-drawing operations (when TextPage is being used via + // {X,Win}SplashOutputDev rather than TextOutputDev). + if (curWord) { + ++nest; + return; + } + + // compute the rotation + state->getFontTransMat(&m[0], &m[1], &m[2], &m[3]); + if (state->getFont()->getType() == fontType3) { + fontm = state->getFont()->getFontMatrix(); + m2[0] = fontm[0] * m[0] + fontm[1] * m[2]; + m2[1] = fontm[0] * m[1] + fontm[1] * m[3]; + m2[2] = fontm[2] * m[0] + fontm[3] * m[2]; + m2[3] = fontm[2] * m[1] + fontm[3] * m[3]; + m[0] = m2[0]; + m[1] = m2[1]; + m[2] = m2[2]; + m[3] = m2[3]; + } + if (fabs(m[0] * m[3]) > fabs(m[1] * m[2])) { + rot = (m[3] < 0) ? 0 : 2; + } else { + rot = (m[2] > 0) ? 1 : 3; + } + + curWord = new TextWord(state, rot, x0, y0, charPos, curFont, curFontSize); +} + +void TextPage::addChar(GfxState *state, double x, double y, + double dx, double dy, + CharCode c, int nBytes, Unicode *u, int uLen) { + double x1, y1, w1, h1, dx2, dy2, base, sp, delta; + GBool overlap; + int i; + + // subtract char and word spacing from the dx,dy values + sp = state->getCharSpace(); + if (c == (CharCode)0x20) { + sp += state->getWordSpace(); + } + state->textTransformDelta(sp * state->getHorizScaling(), 0, &dx2, &dy2); + dx -= dx2; + dy -= dy2; + state->transformDelta(dx, dy, &w1, &h1); + + // throw away chars that aren't inside the page bounds + // (and also do a sanity check on the character size) + state->transform(x, y, &x1, &y1); + if (x1 + w1 < 0 || x1 > pageWidth || + y1 + h1 < 0 || y1 > pageHeight || + w1 > pageWidth || h1 > pageHeight) { + charPos += nBytes; + return; + } + + // check the tiny chars limit + if (!globalParams->getTextKeepTinyChars() && + fabs(w1) < 3 && fabs(h1) < 3) { + if (++nTinyChars > 50000) { + charPos += nBytes; + return; + } + } + + // break words at space character + if (uLen == 1 && u[0] == (Unicode)0x20) { + if (curWord) { + ++curWord->charLen; + } + charPos += nBytes; + endWord(); + return; + } + + // start a new word if: + // (1) this character doesn't fall in the right place relative to + // the end of the previous word (this places upper and lower + // constraints on the position deltas along both the primary + // and secondary axes), or + // (2) this character overlaps the previous one (duplicated text), or + // (3) the previous character was an overlap (we want each duplicated + // character to be in a word by itself at this stage), + // (4) the font size has changed + if (curWord && curWord->len > 0) { + base = sp = delta = 0; // make gcc happy + switch (curWord->rot) { + case 0: + base = y1; + sp = x1 - curWord->xMax; + delta = x1 - curWord->edge[curWord->len - 1]; + break; + case 1: + base = x1; + sp = y1 - curWord->yMax; + delta = y1 - curWord->edge[curWord->len - 1]; + break; + case 2: + base = y1; + sp = curWord->xMin - x1; + delta = curWord->edge[curWord->len - 1] - x1; + break; + case 3: + base = x1; + sp = curWord->yMin - y1; + delta = curWord->edge[curWord->len - 1] - y1; + break; + } + overlap = fabs(delta) < dupMaxPriDelta * curWord->fontSize && + fabs(base - curWord->base) < dupMaxSecDelta * curWord->fontSize; + if (overlap || lastCharOverlap || + sp < -minDupBreakOverlap * curWord->fontSize || + sp > minWordBreakSpace * curWord->fontSize || + fabs(base - curWord->base) > 0.5 || + curFontSize != curWord->fontSize) { + endWord(); + } + lastCharOverlap = overlap; + } else { + lastCharOverlap = gFalse; + } + + if (uLen != 0) { + // start a new word if needed + if (!curWord) { + beginWord(state, x, y); + } + + // page rotation and/or transform matrices can cause text to be + // drawn in reverse order -- in this case, swap the begin/end + // coordinates and break text into individual chars + if ((curWord->rot == 0 && w1 < 0) || + (curWord->rot == 1 && h1 < 0) || + (curWord->rot == 2 && w1 > 0) || + (curWord->rot == 3 && h1 > 0)) { + endWord(); + beginWord(state, x + dx, y + dy); + x1 += w1; + y1 += h1; + w1 = -w1; + h1 = -h1; + } + + // add the characters to the current word + w1 /= uLen; + h1 /= uLen; + for (i = 0; i < uLen; ++i) { + curWord->addChar(state, x1 + i*w1, y1 + i*h1, w1, h1, u[i]); + } + } + if (curWord) { + curWord->charLen += nBytes; + } + charPos += nBytes; +} + +void TextPage::endWord() { + // This check is needed because Type 3 characters can contain + // text-drawing operations (when TextPage is being used via + // {X,Win}SplashOutputDev rather than TextOutputDev). + if (nest > 0) { + --nest; + return; + } + + if (curWord) { + addWord(curWord); + curWord = NULL; + } +} + +void TextPage::addWord(TextWord *word) { + // throw away zero-length words -- they don't have valid xMin/xMax + // values, and they're useless anyway + if (word->len == 0) { + delete word; + return; + } + + if (rawOrder) { + if (rawLastWord) { + rawLastWord->next = word; + } else { + rawWords = word; + } + rawLastWord = word; + } else { + pools[word->rot]->addWord(word); + } +} + +void TextPage::addUnderline(double x0, double y0, double x1, double y1) { + underlines->append(new TextUnderline(x0, y0, x1, y1)); +} + +void TextPage::addLink(int xMin, int yMin, int xMax, int yMax, Link *link) { + links->append(new TextLink(xMin, yMin, xMax, yMax, link)); +} + +void TextPage::coalesce(GBool /*physLayout*/, GBool doHTML) { + UnicodeMap *uMap; + TextPool *pool; + TextWord *word0, *word1, *word2; + TextLine *line; + TextBlock *blkList, *blkStack, *blk, *lastBlk, *blk0, *blk1; + TextBlock **blkArray; + TextFlow *flow, *lastFlow; + TextUnderline *underline; + TextLink *link; + int rot, poolMinBaseIdx, baseIdx, startBaseIdx, endBaseIdx; + double minBase, maxBase, newMinBase, newMaxBase; + double fontSize, colSpace1, colSpace2, lineSpace, intraLineSpace, blkSpace; + GBool found; + int count[4]; + int lrCount; + int firstBlkIdx, nBlocksLeft; + int col1, col2; + int i, j, n; + + if (rawOrder) { + primaryRot = 0; + primaryLR = gTrue; + return; + } + + uMap = globalParams->getTextEncoding(); + blkList = NULL; + lastBlk = NULL; + nBlocks = 0; + primaryRot = -1; + +#if 0 // for debugging + printf("*** initial words ***\n"); + for (rot = 0; rot < 4; ++rot) { + pool = pools[rot]; + for (baseIdx = pool->minBaseIdx; baseIdx <= pool->maxBaseIdx; ++baseIdx) { + for (word0 = pool->getPool(baseIdx); word0; word0 = word0->next) { + printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f rot=%d link=%p '", + word0->xMin, word0->xMax, word0->yMin, word0->yMax, + word0->base, word0->fontSize, rot*90, word0->link); + for (i = 0; i < word0->len; ++i) { + fputc(word0->text[i] & 0xff, stdout); + } + printf("'\n"); + } + } + } + printf("\n"); +#endif + +#if 0 //~ for debugging + for (i = 0; i < underlines->getLength(); ++i) { + underline = (TextUnderline *)underlines->get(i); + printf("underline: x=%g..%g y=%g..%g horiz=%d\n", + underline->x0, underline->x1, underline->y0, underline->y1, + underline->horiz); + } +#endif + + if (doHTML) { + + //----- handle underlining + for (i = 0; i < underlines->getLength(); ++i) { + underline = (TextUnderline *)underlines->get(i); + if (underline->horiz) { + // rot = 0 + if (pools[0]->minBaseIdx <= pools[0]->maxBaseIdx) { + startBaseIdx = pools[0]->getBaseIdx(underline->y0 + minUnderlineGap); + endBaseIdx = pools[0]->getBaseIdx(underline->y0 + maxUnderlineGap); + for (j = startBaseIdx; j <= endBaseIdx; ++j) { + for (word0 = pools[0]->getPool(j); word0; word0 = word0->next) { + //~ need to check the y value against the word baseline + if (underline->x0 < word0->xMin + underlineSlack && + word0->xMax - underlineSlack < underline->x1) { + word0->underlined = gTrue; + } + } + } + } + + // rot = 2 + if (pools[2]->minBaseIdx <= pools[2]->maxBaseIdx) { + startBaseIdx = pools[2]->getBaseIdx(underline->y0 - maxUnderlineGap); + endBaseIdx = pools[2]->getBaseIdx(underline->y0 - minUnderlineGap); + for (j = startBaseIdx; j <= endBaseIdx; ++j) { + for (word0 = pools[2]->getPool(j); word0; word0 = word0->next) { + if (underline->x0 < word0->xMin + underlineSlack && + word0->xMax - underlineSlack < underline->x1) { + word0->underlined = gTrue; + } + } + } + } + } else { + // rot = 1 + if (pools[1]->minBaseIdx <= pools[1]->maxBaseIdx) { + startBaseIdx = pools[1]->getBaseIdx(underline->x0 - maxUnderlineGap); + endBaseIdx = pools[1]->getBaseIdx(underline->x0 - minUnderlineGap); + for (j = startBaseIdx; j <= endBaseIdx; ++j) { + for (word0 = pools[1]->getPool(j); word0; word0 = word0->next) { + if (underline->y0 < word0->yMin + underlineSlack && + word0->yMax - underlineSlack < underline->y1) { + word0->underlined = gTrue; + } + } + } + } + + // rot = 3 + if (pools[3]->minBaseIdx <= pools[3]->maxBaseIdx) { + startBaseIdx = pools[3]->getBaseIdx(underline->x0 + minUnderlineGap); + endBaseIdx = pools[3]->getBaseIdx(underline->x0 + maxUnderlineGap); + for (j = startBaseIdx; j <= endBaseIdx; ++j) { + for (word0 = pools[3]->getPool(j); word0; word0 = word0->next) { + if (underline->y0 < word0->yMin + underlineSlack && + word0->yMax - underlineSlack < underline->y1) { + word0->underlined = gTrue; + } + } + } + } + } + } + + //----- handle links + for (i = 0; i < links->getLength(); ++i) { + link = (TextLink *)links->get(i); + + // rot = 0 + if (pools[0]->minBaseIdx <= pools[0]->maxBaseIdx) { + startBaseIdx = pools[0]->getBaseIdx(link->yMin); + endBaseIdx = pools[0]->getBaseIdx(link->yMax); + for (j = startBaseIdx; j <= endBaseIdx; ++j) { + for (word0 = pools[0]->getPool(j); word0; word0 = word0->next) { + if (link->xMin < word0->xMin + hyperlinkSlack && + word0->xMax - hyperlinkSlack < link->xMax && + link->yMin < word0->yMin + hyperlinkSlack && + word0->yMax - hyperlinkSlack < link->yMax) { + word0->link = link->link; + } + } + } + } + + // rot = 2 + if (pools[2]->minBaseIdx <= pools[2]->maxBaseIdx) { + startBaseIdx = pools[2]->getBaseIdx(link->yMin); + endBaseIdx = pools[2]->getBaseIdx(link->yMax); + for (j = startBaseIdx; j <= endBaseIdx; ++j) { + for (word0 = pools[2]->getPool(j); word0; word0 = word0->next) { + if (link->xMin < word0->xMin + hyperlinkSlack && + word0->xMax - hyperlinkSlack < link->xMax && + link->yMin < word0->yMin + hyperlinkSlack && + word0->yMax - hyperlinkSlack < link->yMax) { + word0->link = link->link; + } + } + } + } + + // rot = 1 + if (pools[1]->minBaseIdx <= pools[1]->maxBaseIdx) { + startBaseIdx = pools[1]->getBaseIdx(link->xMin); + endBaseIdx = pools[1]->getBaseIdx(link->xMax); + for (j = startBaseIdx; j <= endBaseIdx; ++j) { + for (word0 = pools[1]->getPool(j); word0; word0 = word0->next) { + if (link->yMin < word0->yMin + hyperlinkSlack && + word0->yMax - hyperlinkSlack < link->yMax && + link->xMin < word0->xMin + hyperlinkSlack && + word0->xMax - hyperlinkSlack < link->xMax) { + word0->link = link->link; + } + } + } + } + + // rot = 3 + if (pools[3]->minBaseIdx <= pools[3]->maxBaseIdx) { + startBaseIdx = pools[3]->getBaseIdx(link->xMin); + endBaseIdx = pools[3]->getBaseIdx(link->xMax); + for (j = startBaseIdx; j <= endBaseIdx; ++j) { + for (word0 = pools[3]->getPool(j); word0; word0 = word0->next) { + if (link->yMin < word0->yMin + hyperlinkSlack && + word0->yMax - hyperlinkSlack < link->yMax && + link->xMin < word0->xMin + hyperlinkSlack && + word0->xMax - hyperlinkSlack < link->xMax) { + word0->link = link->link; + } + } + } + } + } + } + + //----- assemble the blocks + + //~ add an outer loop for writing mode (vertical text) + + // build blocks for each rotation value + for (rot = 0; rot < 4; ++rot) { + pool = pools[rot]; + poolMinBaseIdx = pool->minBaseIdx; + count[rot] = 0; + + // add blocks until no more words are left + while (1) { + + // find the first non-empty line in the pool + for (; + poolMinBaseIdx <= pool->maxBaseIdx && + !pool->getPool(poolMinBaseIdx); + ++poolMinBaseIdx) ; + if (poolMinBaseIdx > pool->maxBaseIdx) { + break; + } + + // look for the left-most word in the first four lines of the + // pool -- this avoids starting with a superscript word + startBaseIdx = poolMinBaseIdx; + for (baseIdx = poolMinBaseIdx + 1; + baseIdx < poolMinBaseIdx + 4 && baseIdx <= pool->maxBaseIdx; + ++baseIdx) { + if (!pool->getPool(baseIdx)) { + continue; + } + if (pool->getPool(baseIdx)->primaryCmp(pool->getPool(startBaseIdx)) + < 0) { + startBaseIdx = baseIdx; + } + } + + // create a new block + word0 = pool->getPool(startBaseIdx); + pool->setPool(startBaseIdx, word0->next); + word0->next = NULL; + blk = new TextBlock(this, rot); + blk->addWord(word0); + + fontSize = word0->fontSize; + minBase = maxBase = word0->base; + colSpace1 = minColSpacing1 * fontSize; + colSpace2 = minColSpacing2 * fontSize; + lineSpace = maxLineSpacingDelta * fontSize; + intraLineSpace = maxIntraLineDelta * fontSize; + + // add words to the block + do { + found = gFalse; + + // look for words on the line above the current top edge of + // the block + newMinBase = minBase; + for (baseIdx = pool->getBaseIdx(minBase); + baseIdx >= pool->getBaseIdx(minBase - lineSpace); + --baseIdx) { + word0 = NULL; + word1 = pool->getPool(baseIdx); + while (word1) { + if (word1->base < minBase && + word1->base >= minBase - lineSpace && + ((rot == 0 || rot == 2) + ? (word1->xMin < blk->xMax && word1->xMax > blk->xMin) + : (word1->yMin < blk->yMax && word1->yMax > blk->yMin)) && + fabs(word1->fontSize - fontSize) < + maxBlockFontSizeDelta1 * fontSize) { + word2 = word1; + if (word0) { + word0->next = word1->next; + } else { + pool->setPool(baseIdx, word1->next); + } + word1 = word1->next; + word2->next = NULL; + blk->addWord(word2); + found = gTrue; + newMinBase = word2->base; + } else { + word0 = word1; + word1 = word1->next; + } + } + } + minBase = newMinBase; + + // look for words on the line below the current bottom edge of + // the block + newMaxBase = maxBase; + for (baseIdx = pool->getBaseIdx(maxBase); + baseIdx <= pool->getBaseIdx(maxBase + lineSpace); + ++baseIdx) { + word0 = NULL; + word1 = pool->getPool(baseIdx); + while (word1) { + if (word1->base > maxBase && + word1->base <= maxBase + lineSpace && + ((rot == 0 || rot == 2) + ? (word1->xMin < blk->xMax && word1->xMax > blk->xMin) + : (word1->yMin < blk->yMax && word1->yMax > blk->yMin)) && + fabs(word1->fontSize - fontSize) < + maxBlockFontSizeDelta1 * fontSize) { + word2 = word1; + if (word0) { + word0->next = word1->next; + } else { + pool->setPool(baseIdx, word1->next); + } + word1 = word1->next; + word2->next = NULL; + blk->addWord(word2); + found = gTrue; + newMaxBase = word2->base; + } else { + word0 = word1; + word1 = word1->next; + } + } + } + maxBase = newMaxBase; + + // look for words that are on lines already in the block, and + // that overlap the block horizontally + for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace); + baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace); + ++baseIdx) { + word0 = NULL; + word1 = pool->getPool(baseIdx); + while (word1) { + if (word1->base >= minBase - intraLineSpace && + word1->base <= maxBase + intraLineSpace && + ((rot == 0 || rot == 2) + ? (word1->xMin < blk->xMax + colSpace1 && + word1->xMax > blk->xMin - colSpace1) + : (word1->yMin < blk->yMax + colSpace1 && + word1->yMax > blk->yMin - colSpace1)) && + fabs(word1->fontSize - fontSize) < + maxBlockFontSizeDelta2 * fontSize) { + word2 = word1; + if (word0) { + word0->next = word1->next; + } else { + pool->setPool(baseIdx, word1->next); + } + word1 = word1->next; + word2->next = NULL; + blk->addWord(word2); + found = gTrue; + } else { + word0 = word1; + word1 = word1->next; + } + } + } + + // only check for outlying words (the next two chunks of code) + // if we didn't find anything else + if (found) { + continue; + } + + // scan down the left side of the block, looking for words + // that are near (but not overlapping) the block; if there are + // three or fewer, add them to the block + n = 0; + for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace); + baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace); + ++baseIdx) { + word1 = pool->getPool(baseIdx); + while (word1) { + if (word1->base >= minBase - intraLineSpace && + word1->base <= maxBase + intraLineSpace && + ((rot == 0 || rot == 2) + ? (word1->xMax <= blk->xMin && + word1->xMax > blk->xMin - colSpace2) + : (word1->yMax <= blk->yMin && + word1->yMax > blk->yMin - colSpace2)) && + fabs(word1->fontSize - fontSize) < + maxBlockFontSizeDelta3 * fontSize) { + ++n; + break; + } + word1 = word1->next; + } + } + if (n > 0 && n <= 3) { + for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace); + baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace); + ++baseIdx) { + word0 = NULL; + word1 = pool->getPool(baseIdx); + while (word1) { + if (word1->base >= minBase - intraLineSpace && + word1->base <= maxBase + intraLineSpace && + ((rot == 0 || rot == 2) + ? (word1->xMax <= blk->xMin && + word1->xMax > blk->xMin - colSpace2) + : (word1->yMax <= blk->yMin && + word1->yMax > blk->yMin - colSpace2)) && + fabs(word1->fontSize - fontSize) < + maxBlockFontSizeDelta3 * fontSize) { + word2 = word1; + if (word0) { + word0->next = word1->next; + } else { + pool->setPool(baseIdx, word1->next); + } + word1 = word1->next; + word2->next = NULL; + blk->addWord(word2); + if (word2->base < minBase) { + minBase = word2->base; + } else if (word2->base > maxBase) { + maxBase = word2->base; + } + found = gTrue; + break; + } else { + word0 = word1; + word1 = word1->next; + } + } + } + } + + // scan down the right side of the block, looking for words + // that are near (but not overlapping) the block; if there are + // three or fewer, add them to the block + n = 0; + for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace); + baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace); + ++baseIdx) { + word1 = pool->getPool(baseIdx); + while (word1) { + if (word1->base >= minBase - intraLineSpace && + word1->base <= maxBase + intraLineSpace && + ((rot == 0 || rot == 2) + ? (word1->xMin >= blk->xMax && + word1->xMin < blk->xMax + colSpace2) + : (word1->yMin >= blk->yMax && + word1->yMin < blk->yMax + colSpace2)) && + fabs(word1->fontSize - fontSize) < + maxBlockFontSizeDelta3 * fontSize) { + ++n; + break; + } + word1 = word1->next; + } + } + if (n > 0 && n <= 3) { + for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace); + baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace); + ++baseIdx) { + word0 = NULL; + word1 = pool->getPool(baseIdx); + while (word1) { + if (word1->base >= minBase - intraLineSpace && + word1->base <= maxBase + intraLineSpace && + ((rot == 0 || rot == 2) + ? (word1->xMin >= blk->xMax && + word1->xMin < blk->xMax + colSpace2) + : (word1->yMin >= blk->yMax && + word1->yMin < blk->yMax + colSpace2)) && + fabs(word1->fontSize - fontSize) < + maxBlockFontSizeDelta3 * fontSize) { + word2 = word1; + if (word0) { + word0->next = word1->next; + } else { + pool->setPool(baseIdx, word1->next); + } + word1 = word1->next; + word2->next = NULL; + blk->addWord(word2); + if (word2->base < minBase) { + minBase = word2->base; + } else if (word2->base > maxBase) { + maxBase = word2->base; + } + found = gTrue; + break; + } else { + word0 = word1; + word1 = word1->next; + } + } + } + } + + } while (found); + + //~ need to compute the primary writing mode (horiz/vert) in + //~ addition to primary rotation + + // coalesce the block, and add it to the list + blk->coalesce(uMap); + if (lastBlk) { + lastBlk->next = blk; + } else { + blkList = blk; + } + lastBlk = blk; + count[rot] += blk->charCount; + if (primaryRot < 0 || count[rot] > count[primaryRot]) { + primaryRot = rot; + } + ++nBlocks; + } + } + +#if 0 // for debugging + printf("*** rotation ***\n"); + for (rot = 0; rot < 4; ++rot) { + printf(" %d: %6d\n", rot, count[rot]); + } + printf(" primary rot = %d\n", primaryRot); + printf("\n"); +#endif + +#if 0 // for debugging + printf("*** blocks ***\n"); + for (blk = blkList; blk; blk = blk->next) { + printf("block: rot=%d x=%.2f..%.2f y=%.2f..%.2f\n", + blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax); + for (line = blk->lines; line; line = line->next) { + printf(" line: x=%.2f..%.2f y=%.2f..%.2f base=%.2f\n", + line->xMin, line->xMax, line->yMin, line->yMax, line->base); + for (word0 = line->words; word0; word0 = word0->next) { + printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '", + word0->xMin, word0->xMax, word0->yMin, word0->yMax, + word0->base, word0->fontSize, word0->spaceAfter); + for (i = 0; i < word0->len; ++i) { + fputc(word0->text[i] & 0xff, stdout); + } + printf("'\n"); + } + } + } + printf("\n"); +#endif + + // determine the primary direction + lrCount = 0; + for (blk = blkList; blk; blk = blk->next) { + for (line = blk->lines; line; line = line->next) { + for (word0 = line->words; word0; word0 = word0->next) { + for (i = 0; i < word0->len; ++i) { + if (unicodeTypeL(word0->text[i])) { + ++lrCount; + } else if (unicodeTypeR(word0->text[i])) { + --lrCount; + } + } + } + } + } + primaryLR = lrCount >= 0; + +#if 0 // for debugging + printf("*** direction ***\n"); + printf("lrCount = %d\n", lrCount); + printf("primaryLR = %d\n", primaryLR); +#endif + + //----- column assignment + + // sort blocks into xy order for column assignment + blocks = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *)); + for (blk = blkList, i = 0; blk; blk = blk->next, ++i) { + blocks[i] = blk; + } + qsort(blocks, nBlocks, sizeof(TextBlock *), &TextBlock::cmpXYPrimaryRot); + + // column assignment + for (i = 0; i < nBlocks; ++i) { + blk0 = blocks[i]; + col1 = 0; + for (j = 0; j < i; ++j) { + blk1 = blocks[j]; + col2 = 0; // make gcc happy + switch (primaryRot) { + case 0: + if (blk0->xMin > blk1->xMax) { + col2 = blk1->col + blk1->nColumns + 3; + } else if (blk1->xMax == blk1->xMin) { + col2 = blk1->col; + } else { + col2 = blk1->col + (int)(((blk0->xMin - blk1->xMin) / + (blk1->xMax - blk1->xMin)) * + blk1->nColumns); + } + break; + case 1: + if (blk0->yMin > blk1->yMax) { + col2 = blk1->col + blk1->nColumns + 3; + } else if (blk1->yMax == blk1->yMin) { + col2 = blk1->col; + } else { + col2 = blk1->col + (int)(((blk0->yMin - blk1->yMin) / + (blk1->yMax - blk1->yMin)) * + blk1->nColumns); + } + break; + case 2: + if (blk0->xMax < blk1->xMin) { + col2 = blk1->col + blk1->nColumns + 3; + } else if (blk1->xMin == blk1->xMax) { + col2 = blk1->col; + } else { + col2 = blk1->col + (int)(((blk0->xMax - blk1->xMax) / + (blk1->xMin - blk1->xMax)) * + blk1->nColumns); + } + break; + case 3: + if (blk0->yMax < blk1->yMin) { + col2 = blk1->col + blk1->nColumns + 3; + } else if (blk1->yMin == blk1->yMax) { + col2 = blk1->col; + } else { + col2 = blk1->col + (int)(((blk0->yMax - blk1->yMax) / + (blk1->yMin - blk1->yMax)) * + blk1->nColumns); + } + break; + } + if (col2 > col1) { + col1 = col2; + } + } + blk0->col = col1; + for (line = blk0->lines; line; line = line->next) { + for (j = 0; j <= line->len; ++j) { + line->col[j] += col1; + } + } + } + +#if 0 // for debugging + printf("*** blocks, after column assignment ***\n"); + for (blk = blkList; blk; blk = blk->next) { + printf("block: rot=%d x=%.2f..%.2f y=%.2f..%.2f col=%d nCols=%d\n", + blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax, blk->col, + blk->nColumns); + for (line = blk->lines; line; line = line->next) { + printf(" line:\n"); + for (word0 = line->words; word0; word0 = word0->next) { + printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '", + word0->xMin, word0->xMax, word0->yMin, word0->yMax, + word0->base, word0->fontSize, word0->spaceAfter); + for (i = 0; i < word0->len; ++i) { + fputc(word0->text[i] & 0xff, stdout); + } + printf("'\n"); + } + } + } + printf("\n"); +#endif + + //----- reading order sort + + // sort blocks into yx order (in preparation for reading order sort) + qsort(blocks, nBlocks, sizeof(TextBlock *), &TextBlock::cmpYXPrimaryRot); + + // compute space on left and right sides of each block + for (i = 0; i < nBlocks; ++i) { + blk0 = blocks[i]; + for (j = 0; j < nBlocks; ++j) { + blk1 = blocks[j]; + if (blk1 != blk0) { + blk0->updatePriMinMax(blk1); + } + } + } + +#if 0 // for debugging + printf("*** blocks, after yx sort ***\n"); + for (i = 0; i < nBlocks; ++i) { + blk = blocks[i]; + printf("block: rot=%d x=%.2f..%.2f y=%.2f..%.2f space=%.2f..%.2f\n", + blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax, + blk->priMin, blk->priMax); + for (line = blk->lines; line; line = line->next) { + printf(" line:\n"); + for (word0 = line->words; word0; word0 = word0->next) { + printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '", + word0->xMin, word0->xMax, word0->yMin, word0->yMax, + word0->base, word0->fontSize, word0->spaceAfter); + for (j = 0; j < word0->len; ++j) { + fputc(word0->text[j] & 0xff, stdout); + } + printf("'\n"); + } + } + } + printf("\n"); +#endif + + // build the flows + //~ this needs to be adjusted for writing mode (vertical text) + //~ this also needs to account for right-to-left column ordering + blkArray = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *)); + memcpy(blkArray, blocks, nBlocks * sizeof(TextBlock *)); + flows = lastFlow = NULL; + firstBlkIdx = 0; + nBlocksLeft = nBlocks; + while (nBlocksLeft > 0) { + + // find the upper-left-most block + for (; !blkArray[firstBlkIdx]; ++firstBlkIdx) ; + i = firstBlkIdx; + blk = blkArray[i]; + for (j = firstBlkIdx + 1; j < nBlocks; ++j) { + blk1 = blkArray[j]; + if (blk1) { + if (blk && blk->secondaryDelta(blk1) > 0) { + break; + } + if (blk1->primaryCmp(blk) < 0) { + i = j; + blk = blk1; + } + } + } + blkArray[i] = NULL; + --nBlocksLeft; + blk->next = NULL; + + // create a new flow, starting with the upper-left-most block + flow = new TextFlow(this, blk); + if (lastFlow) { + lastFlow->next = flow; + } else { + flows = flow; + } + lastFlow = flow; + fontSize = blk->lines->words->fontSize; + + // push the upper-left-most block on the stack + blk->stackNext = NULL; + blkStack = blk; + + // find the other blocks in this flow + while (blkStack) { + + // find the upper-left-most block under (but within + // maxBlockSpacing of) the top block on the stack + blkSpace = maxBlockSpacing * blkStack->lines->words->fontSize; + blk = NULL; + i = -1; + for (j = firstBlkIdx; j < nBlocks; ++j) { + blk1 = blkArray[j]; + if (blk1) { + if (blkStack->secondaryDelta(blk1) > blkSpace) { + break; + } + if (blk && blk->secondaryDelta(blk1) > 0) { + break; + } + if (blk1->isBelow(blkStack) && + (!blk || blk1->primaryCmp(blk) < 0)) { + i = j; + blk = blk1; + } + } + } + + // if a suitable block was found, add it to the flow and push it + // onto the stack + if (blk && flow->blockFits(blk, blkStack)) { + blkArray[i] = NULL; + --nBlocksLeft; + blk->next = NULL; + flow->addBlock(blk); + fontSize = blk->lines->words->fontSize; + blk->stackNext = blkStack; + blkStack = blk; + + // otherwise (if there is no block under the top block or the + // block is not suitable), pop the stack + } else { + blkStack = blkStack->stackNext; + } + } + } + gfree(blkArray); + +#if 0 // for debugging + printf("*** flows ***\n"); + for (flow = flows; flow; flow = flow->next) { + printf("flow: x=%.2f..%.2f y=%.2f..%.2f pri:%.2f..%.2f\n", + flow->xMin, flow->xMax, flow->yMin, flow->yMax, + flow->priMin, flow->priMax); + for (blk = flow->blocks; blk; blk = blk->next) { + printf(" block: rot=%d x=%.2f..%.2f y=%.2f..%.2f pri=%.2f..%.2f\n", + blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax, + blk->priMin, blk->priMax); + for (line = blk->lines; line; line = line->next) { + printf(" line:\n"); + for (word0 = line->words; word0; word0 = word0->next) { + printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '", + word0->xMin, word0->xMax, word0->yMin, word0->yMax, + word0->base, word0->fontSize, word0->spaceAfter); + for (i = 0; i < word0->len; ++i) { + fputc(word0->text[i] & 0xff, stdout); + } + printf("'\n"); + } + } + } + } + printf("\n"); +#endif + + if (uMap) { + uMap->decRefCnt(); + } +} + +GBool TextPage::findText(Unicode *s, int len, + GBool startAtTop, GBool stopAtBottom, + GBool startAtLast, GBool stopAtLast, + GBool caseSensitive, GBool backward, + double *xMin, double *yMin, + double *xMax, double *yMax) { + TextBlock *blk; + TextLine *line; + Unicode *s2, *txt; + Unicode *p; + int txtSize, m, i, j, k; + double xStart, yStart, xStop, yStop; + double xMin0, yMin0, xMax0, yMax0; + double xMin1, yMin1, xMax1, yMax1; + GBool found; + + //~ needs to handle right-to-left text + + if (rawOrder) { + return gFalse; + } + + // convert the search string to uppercase + if (!caseSensitive) { + s2 = (Unicode *)gmallocn(len, sizeof(Unicode)); + for (i = 0; i < len; ++i) { + s2[i] = unicodeToUpper(s[i]); + } + } else { + s2 = s; + } + + txt = NULL; + txtSize = 0; + + xStart = yStart = xStop = yStop = 0; + if (startAtLast && haveLastFind) { + xStart = lastFindXMin; + yStart = lastFindYMin; + } else if (!startAtTop) { + xStart = *xMin; + yStart = *yMin; + } + if (stopAtLast && haveLastFind) { + xStop = lastFindXMin; + yStop = lastFindYMin; + } else if (!stopAtBottom) { + xStop = *xMax; + yStop = *yMax; + } + + found = gFalse; + xMin0 = xMax0 = yMin0 = yMax0 = 0; // make gcc happy + xMin1 = xMax1 = yMin1 = yMax1 = 0; // make gcc happy + + for (i = backward ? nBlocks - 1 : 0; + backward ? i >= 0 : i < nBlocks; + i += backward ? -1 : 1) { + blk = blocks[i]; + + // check: is the block above the top limit? + if (!startAtTop && (backward ? blk->yMin > yStart : blk->yMax < yStart)) { + continue; + } + + // check: is the block below the bottom limit? + if (!stopAtBottom && (backward ? blk->yMax < yStop : blk->yMin > yStop)) { + break; + } + + for (line = blk->lines; line; line = line->next) { + + // check: is the line above the top limit? + if (!startAtTop && + (backward ? line->yMin > yStart : line->yMin < yStart)) { + continue; + } + + // check: is the line below the bottom limit? + if (!stopAtBottom && + (backward ? line->yMin < yStop : line->yMin > yStop)) { + continue; + } + + // convert the line to uppercase + m = line->len; + if (!caseSensitive) { + if (m > txtSize) { + txt = (Unicode *)greallocn(txt, m, sizeof(Unicode)); + txtSize = m; + } + for (k = 0; k < m; ++k) { + txt[k] = unicodeToUpper(line->text[k]); + } + } else { + txt = line->text; + } + + // search each position in this line + j = backward ? m - len : 0; + p = txt + j; + while (backward ? j >= 0 : j <= m - len) { + + // compare the strings + for (k = 0; k < len; ++k) { + if (p[k] != s2[k]) { + break; + } + } + + // found it + if (k == len) { + switch (line->rot) { + case 0: + xMin1 = line->edge[j]; + xMax1 = line->edge[j + len]; + yMin1 = line->yMin; + yMax1 = line->yMax; + break; + case 1: + xMin1 = line->xMin; + xMax1 = line->xMax; + yMin1 = line->edge[j]; + yMax1 = line->edge[j + len]; + break; + case 2: + xMin1 = line->edge[j + len]; + xMax1 = line->edge[j]; + yMin1 = line->yMin; + yMax1 = line->yMax; + break; + case 3: + xMin1 = line->xMin; + xMax1 = line->xMax; + yMin1 = line->edge[j + len]; + yMax1 = line->edge[j]; + break; + } + if (backward) { + if ((startAtTop || + yMin1 < yStart || (yMin1 == yStart && xMin1 < xStart)) && + (stopAtBottom || + yMin1 > yStop || (yMin1 == yStop && xMin1 > xStop))) { + if (!found || + yMin1 > yMin0 || (yMin1 == yMin0 && xMin1 > xMin0)) { + xMin0 = xMin1; + xMax0 = xMax1; + yMin0 = yMin1; + yMax0 = yMax1; + found = gTrue; + } + } + } else { + if ((startAtTop || + yMin1 > yStart || (yMin1 == yStart && xMin1 > xStart)) && + (stopAtBottom || + yMin1 < yStop || (yMin1 == yStop && xMin1 < xStop))) { + if (!found || + yMin1 < yMin0 || (yMin1 == yMin0 && xMin1 < xMin0)) { + xMin0 = xMin1; + xMax0 = xMax1; + yMin0 = yMin1; + yMax0 = yMax1; + found = gTrue; + } + } + } + } + if (backward) { + --j; + --p; + } else { + ++j; + ++p; + } + } + } + } + + if (!caseSensitive) { + gfree(s2); + gfree(txt); + } + + if (found) { + *xMin = xMin0; + *xMax = xMax0; + *yMin = yMin0; + *yMax = yMax0; + lastFindXMin = xMin0; + lastFindYMin = yMin0; + haveLastFind = gTrue; + return gTrue; + } + + return gFalse; +} + +GString *TextPage::getText(double xMin, double yMin, + double xMax, double yMax) { + GString *s; + UnicodeMap *uMap; + GBool isUnicode; + TextBlock *blk; + TextLine *line; + TextLineFrag *frags; + int nFrags, fragsSize; + TextLineFrag *frag; + char space[8], eol[16]; + int spaceLen, eolLen; + int lastRot; + double x, y, delta; + int col, idx0, idx1, i, j; + GBool multiLine, oneRot; + + s = new GString(); + + if (rawOrder) { + return s; + } + + // get the output encoding + if (!(uMap = globalParams->getTextEncoding())) { + return s; + } + isUnicode = uMap->isUnicode(); + spaceLen = uMap->mapUnicode(0x20, space, sizeof(space)); + eolLen = 0; // make gcc happy + switch (globalParams->getTextEOL()) { + case eolUnix: + eolLen = uMap->mapUnicode(0x0a, eol, sizeof(eol)); + break; + case eolDOS: + eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol)); + eolLen += uMap->mapUnicode(0x0a, eol + eolLen, sizeof(eol) - eolLen); + break; + case eolMac: + eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol)); + break; + } + + //~ writing mode (horiz/vert) + + // collect the line fragments that are in the rectangle + fragsSize = 256; + frags = (TextLineFrag *)gmallocn(fragsSize, sizeof(TextLineFrag)); + nFrags = 0; + lastRot = -1; + oneRot = gTrue; + for (i = 0; i < nBlocks; ++i) { + blk = blocks[i]; + if (xMin < blk->xMax && blk->xMin < xMax && + yMin < blk->yMax && blk->yMin < yMax) { + for (line = blk->lines; line; line = line->next) { + if (xMin < line->xMax && line->xMin < xMax && + yMin < line->yMax && line->yMin < yMax) { + idx0 = idx1 = -1; + switch (line->rot) { + case 0: + y = 0.5 * (line->yMin + line->yMax); + if (yMin < y && y < yMax) { + j = 0; + while (j < line->len) { + if (0.5 * (line->edge[j] + line->edge[j+1]) > xMin) { + idx0 = j; + break; + } + ++j; + } + j = line->len - 1; + while (j >= 0) { + if (0.5 * (line->edge[j] + line->edge[j+1]) < xMax) { + idx1 = j; + break; + } + --j; + } + } + break; + case 1: + x = 0.5 * (line->xMin + line->xMax); + if (xMin < x && x < xMax) { + j = 0; + while (j < line->len) { + if (0.5 * (line->edge[j] + line->edge[j+1]) > yMin) { + idx0 = j; + break; + } + ++j; + } + j = line->len - 1; + while (j >= 0) { + if (0.5 * (line->edge[j] + line->edge[j+1]) < yMax) { + idx1 = j; + break; + } + --j; + } + } + break; + case 2: + y = 0.5 * (line->yMin + line->yMax); + if (yMin < y && y < yMax) { + j = 0; + while (j < line->len) { + if (0.5 * (line->edge[j] + line->edge[j+1]) < xMax) { + idx0 = j; + break; + } + ++j; + } + j = line->len - 1; + while (j >= 0) { + if (0.5 * (line->edge[j] + line->edge[j+1]) > xMin) { + idx1 = j; + break; + } + --j; + } + } + break; + case 3: + x = 0.5 * (line->xMin + line->xMax); + if (xMin < x && x < xMax) { + j = 0; + while (j < line->len) { + if (0.5 * (line->edge[j] + line->edge[j+1]) < yMax) { + idx0 = j; + break; + } + ++j; + } + j = line->len - 1; + while (j >= 0) { + if (0.5 * (line->edge[j] + line->edge[j+1]) > yMin) { + idx1 = j; + break; + } + --j; + } + } + break; + } + if (idx0 >= 0 && idx1 >= 0) { + if (nFrags == fragsSize) { + fragsSize *= 2; + frags = (TextLineFrag *) + greallocn(frags, fragsSize, sizeof(TextLineFrag)); + } + frags[nFrags].init(line, idx0, idx1 - idx0 + 1); + ++nFrags; + if (lastRot >= 0 && line->rot != lastRot) { + oneRot = gFalse; + } + lastRot = line->rot; + } + } + } + } + } + + // sort the fragments and generate the string + if (nFrags > 0) { + + for (i = 0; i < nFrags; ++i) { + frags[i].computeCoords(oneRot); + } + assignColumns(frags, nFrags, oneRot); + + // if all lines in the region have the same rotation, use it; + // otherwise, use the page's primary rotation + if (oneRot) { + qsort(frags, nFrags, sizeof(TextLineFrag), + &TextLineFrag::cmpYXLineRot); + } else { + qsort(frags, nFrags, sizeof(TextLineFrag), + &TextLineFrag::cmpYXPrimaryRot); + } + i = 0; + while (i < nFrags) { + delta = maxIntraLineDelta * frags[i].line->words->fontSize; + for (j = i+1; + j < nFrags && fabs(frags[j].base - frags[i].base) < delta; + ++j) ; + qsort(frags + i, j - i, sizeof(TextLineFrag), + oneRot ? &TextLineFrag::cmpXYColumnLineRot + : &TextLineFrag::cmpXYColumnPrimaryRot); + i = j; + } + + col = 0; + multiLine = gFalse; + for (i = 0; i < nFrags; ++i) { + frag = &frags[i]; + + // insert a return + if (frag->col < col || + (i > 0 && fabs(frag->base - frags[i-1].base) > + maxIntraLineDelta * frags[i-1].line->words->fontSize)) { + s->append(eol, eolLen); + col = 0; + multiLine = gTrue; + } + + // column alignment + for (; col < frag->col; ++col) { + s->append(space, spaceLen); + } + + // get the fragment text + col += dumpFragment(frag->line->text + frag->start, frag->len, uMap, s); + } + + if (multiLine) { + s->append(eol, eolLen); + } + } + + gfree(frags); + uMap->decRefCnt(); + + return s; +} + +GBool TextPage::findCharRange(int pos, int length, + double *xMin, double *yMin, + double *xMax, double *yMax) { + TextBlock *blk; + TextLine *line; + TextWord *word; + double xMin0, xMax0, yMin0, yMax0; + double xMin1, xMax1, yMin1, yMax1; + GBool first; + int i, j0, j1; + + if (rawOrder) { + return gFalse; + } + + //~ this doesn't correctly handle: + //~ - ranges split across multiple lines (the highlighted region + //~ is the bounding box of all the parts of the range) + //~ - cases where characters don't convert one-to-one into Unicode + first = gTrue; + xMin0 = xMax0 = yMin0 = yMax0 = 0; // make gcc happy + xMin1 = xMax1 = yMin1 = yMax1 = 0; // make gcc happy + for (i = 0; i < nBlocks; ++i) { + blk = blocks[i]; + for (line = blk->lines; line; line = line->next) { + for (word = line->words; word; word = word->next) { + if (pos < word->charPos + word->charLen && + word->charPos < pos + length) { + j0 = pos - word->charPos; + if (j0 < 0) { + j0 = 0; + } + j1 = pos + length - 1 - word->charPos; + if (j1 >= word->len) { + j1 = word->len - 1; + } + switch (line->rot) { + case 0: + xMin1 = word->edge[j0]; + xMax1 = word->edge[j1 + 1]; + yMin1 = word->yMin; + yMax1 = word->yMax; + break; + case 1: + xMin1 = word->xMin; + xMax1 = word->xMax; + yMin1 = word->edge[j0]; + yMax1 = word->edge[j1 + 1]; + break; + case 2: + xMin1 = word->edge[j1 + 1]; + xMax1 = word->edge[j0]; + yMin1 = word->yMin; + yMax1 = word->yMax; + break; + case 3: + xMin1 = word->xMin; + xMax1 = word->xMax; + yMin1 = word->edge[j1 + 1]; + yMax1 = word->edge[j0]; + break; + } + if (first || xMin1 < xMin0) { + xMin0 = xMin1; + } + if (first || xMax1 > xMax0) { + xMax0 = xMax1; + } + if (first || yMin1 < yMin0) { + yMin0 = yMin1; + } + if (first || yMax1 > yMax0) { + yMax0 = yMax1; + } + first = gFalse; + } + } + } + } + if (!first) { + *xMin = xMin0; + *xMax = xMax0; + *yMin = yMin0; + *yMax = yMax0; + return gTrue; + } + return gFalse; +} + +void TextPage::dump(void *outputStream, TextOutputFunc outputFunc, + GBool physLayout) { + UnicodeMap *uMap; + TextFlow *flow; + TextBlock *blk; + TextLine *line; + TextLineFrag *frags; + TextWord *word; + int nFrags, fragsSize; + TextLineFrag *frag; + char space[8], eol[16], eop[8]; + int spaceLen, eolLen, eopLen; + GBool pageBreaks; + GString *s; + double delta; + int col, i, j, d, n; + + // get the output encoding + if (!(uMap = globalParams->getTextEncoding())) { + return; + } + spaceLen = uMap->mapUnicode(0x20, space, sizeof(space)); + eolLen = 0; // make gcc happy + switch (globalParams->getTextEOL()) { + case eolUnix: + eolLen = uMap->mapUnicode(0x0a, eol, sizeof(eol)); + break; + case eolDOS: + eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol)); + eolLen += uMap->mapUnicode(0x0a, eol + eolLen, sizeof(eol) - eolLen); + break; + case eolMac: + eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol)); + break; + } + eopLen = uMap->mapUnicode(0x0c, eop, sizeof(eop)); + pageBreaks = globalParams->getTextPageBreaks(); + + //~ writing mode (horiz/vert) + + // output the page in raw (content stream) order + if (rawOrder) { + + for (word = rawWords; word; word = word->next) { + s = new GString(); + dumpFragment(word->text, word->len, uMap, s); + (*outputFunc)(outputStream, s->getCString(), s->getLength()); + delete s; + if (word->next && + fabs(word->next->base - word->base) < + maxIntraLineDelta * word->fontSize) { + if (word->next->xMin > word->xMax + minWordSpacing * word->fontSize) { + (*outputFunc)(outputStream, space, spaceLen); + } + } else { + (*outputFunc)(outputStream, eol, eolLen); + } + } + + // output the page, maintaining the original physical layout + } else if (physLayout) { + + // collect the line fragments for the page and sort them + fragsSize = 256; + frags = (TextLineFrag *)gmallocn(fragsSize, sizeof(TextLineFrag)); + nFrags = 0; + for (i = 0; i < nBlocks; ++i) { + blk = blocks[i]; + for (line = blk->lines; line; line = line->next) { + if (nFrags == fragsSize) { + fragsSize *= 2; + frags = (TextLineFrag *)greallocn(frags, + fragsSize, sizeof(TextLineFrag)); + } + frags[nFrags].init(line, 0, line->len); + frags[nFrags].computeCoords(gTrue); + ++nFrags; + } + } + qsort(frags, nFrags, sizeof(TextLineFrag), &TextLineFrag::cmpYXPrimaryRot); + i = 0; + while (i < nFrags) { + delta = maxIntraLineDelta * frags[i].line->words->fontSize; + for (j = i+1; + j < nFrags && fabs(frags[j].base - frags[i].base) < delta; + ++j) ; + qsort(frags + i, j - i, sizeof(TextLineFrag), + &TextLineFrag::cmpXYColumnPrimaryRot); + i = j; + } + +#if 0 // for debugging + printf("*** line fragments ***\n"); + for (i = 0; i < nFrags; ++i) { + frag = &frags[i]; + printf("frag: x=%.2f..%.2f y=%.2f..%.2f base=%.2f '", + frag->xMin, frag->xMax, frag->yMin, frag->yMax, frag->base); + for (n = 0; n < frag->len; ++n) { + fputc(frag->line->text[frag->start + n] & 0xff, stdout); + } + printf("'\n"); + } + printf("\n"); +#endif + + // generate output + col = 0; + for (i = 0; i < nFrags; ++i) { + frag = &frags[i]; + + // column alignment + for (; col < frag->col; ++col) { + (*outputFunc)(outputStream, space, spaceLen); + } + + // print the line + s = new GString(); + col += dumpFragment(frag->line->text + frag->start, frag->len, uMap, s); + (*outputFunc)(outputStream, s->getCString(), s->getLength()); + delete s; + + // print one or more returns if necessary + if (i == nFrags - 1 || + frags[i+1].col < col || + fabs(frags[i+1].base - frag->base) > + maxIntraLineDelta * frag->line->words->fontSize) { + if (i < nFrags - 1) { + d = (int)((frags[i+1].base - frag->base) / + frag->line->words->fontSize); + if (d < 1) { + d = 1; + } else if (d > 5) { + d = 5; + } + } else { + d = 1; + } + for (; d > 0; --d) { + (*outputFunc)(outputStream, eol, eolLen); + } + col = 0; + } + } + + gfree(frags); + + // output the page, "undoing" the layout + } else { + for (flow = flows; flow; flow = flow->next) { + for (blk = flow->blocks; blk; blk = blk->next) { + for (line = blk->lines; line; line = line->next) { + n = line->len; + if (line->hyphenated && (line->next || blk->next)) { + --n; + } + s = new GString(); + dumpFragment(line->text, n, uMap, s); + (*outputFunc)(outputStream, s->getCString(), s->getLength()); + delete s; + if (!line->hyphenated) { + if (line->next) { + (*outputFunc)(outputStream, space, spaceLen); + } else if (blk->next) { + //~ this is a bit of a kludge - we should really do a more + //~ intelligent determination of paragraphs + if (blk->next->lines->words->fontSize == + blk->lines->words->fontSize) { + (*outputFunc)(outputStream, space, spaceLen); + } else { + (*outputFunc)(outputStream, eol, eolLen); + } + } + } + } + } + (*outputFunc)(outputStream, eol, eolLen); + (*outputFunc)(outputStream, eol, eolLen); + } + } + + // end of page + if (pageBreaks) { + (*outputFunc)(outputStream, eop, eopLen); + } + + uMap->decRefCnt(); +} + +void TextPage::assignColumns(TextLineFrag *frags, int nFrags, GBool oneRot) { + TextLineFrag *frag0, *frag1; + int rot, col1, col2, i, j, k; + + // all text in the region has the same rotation -- recompute the + // column numbers based only on the text in the region + if (oneRot) { + qsort(frags, nFrags, sizeof(TextLineFrag), &TextLineFrag::cmpXYLineRot); + rot = frags[0].line->rot; + for (i = 0; i < nFrags; ++i) { + frag0 = &frags[i]; + col1 = 0; + for (j = 0; j < i; ++j) { + frag1 = &frags[j]; + col2 = 0; // make gcc happy + switch (rot) { + case 0: + if (frag0->xMin >= frag1->xMax) { + col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] - + frag1->line->col[frag1->start]) + 1; + } else { + for (k = frag1->start; + k < frag1->start + frag1->len && + frag0->xMin >= 0.5 * (frag1->line->edge[k] + + frag1->line->edge[k+1]); + ++k) ; + col2 = frag1->col + + frag1->line->col[k] - frag1->line->col[frag1->start]; + } + break; + case 1: + if (frag0->yMin >= frag1->yMax) { + col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] - + frag1->line->col[frag1->start]) + 1; + } else { + for (k = frag1->start; + k < frag1->start + frag1->len && + frag0->yMin >= 0.5 * (frag1->line->edge[k] + + frag1->line->edge[k+1]); + ++k) ; + col2 = frag1->col + + frag1->line->col[k] - frag1->line->col[frag1->start]; + } + break; + case 2: + if (frag0->xMax <= frag1->xMin) { + col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] - + frag1->line->col[frag1->start]) + 1; + } else { + for (k = frag1->start; + k < frag1->start + frag1->len && + frag0->xMax <= 0.5 * (frag1->line->edge[k] + + frag1->line->edge[k+1]); + ++k) ; + col2 = frag1->col + + frag1->line->col[k] - frag1->line->col[frag1->start]; + } + break; + case 3: + if (frag0->yMax <= frag1->yMin) { + col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] - + frag1->line->col[frag1->start]) + 1; + } else { + for (k = frag1->start; + k < frag1->start + frag1->len && + frag0->yMax <= 0.5 * (frag1->line->edge[k] + + frag1->line->edge[k+1]); + ++k) ; + col2 = frag1->col + + frag1->line->col[k] - frag1->line->col[frag1->start]; + } + break; + } + if (col2 > col1) { + col1 = col2; + } + } + frag0->col = col1; + } + + // the region includes text at different rotations -- use the + // globally assigned column numbers, offset by the minimum column + // number (i.e., shift everything over to column 0) + } else { + col1 = frags[0].col; + for (i = 1; i < nFrags; ++i) { + if (frags[i].col < col1) { + col1 = frags[i].col; + } + } + for (i = 0; i < nFrags; ++i) { + frags[i].col -= col1; + } + } +} + +int TextPage::dumpFragment(Unicode *text, int len, UnicodeMap *uMap, + GString *s) { + char lre[8], rle[8], popdf[8], buf[8]; + int lreLen, rleLen, popdfLen, n; + int nCols, i, j, k; + + nCols = 0; + + if (uMap->isUnicode()) { + + lreLen = uMap->mapUnicode(0x202a, lre, sizeof(lre)); + rleLen = uMap->mapUnicode(0x202b, rle, sizeof(rle)); + popdfLen = uMap->mapUnicode(0x202c, popdf, sizeof(popdf)); + + if (primaryLR) { + + i = 0; + while (i < len) { + // output a left-to-right section + for (j = i; j < len && !unicodeTypeR(text[j]); ++j) ; + for (k = i; k < j; ++k) { + n = uMap->mapUnicode(text[k], buf, sizeof(buf)); + s->append(buf, n); + ++nCols; + } + i = j; + // output a right-to-left section + for (j = i; j < len && !unicodeTypeL(text[j]); ++j) ; + if (j > i) { + s->append(rle, rleLen); + for (k = j - 1; k >= i; --k) { + n = uMap->mapUnicode(text[k], buf, sizeof(buf)); + s->append(buf, n); + ++nCols; + } + s->append(popdf, popdfLen); + i = j; + } + } + + } else { + + s->append(rle, rleLen); + i = len - 1; + while (i >= 0) { + // output a right-to-left section + for (j = i; j >= 0 && !unicodeTypeL(text[j]); --j) ; + for (k = i; k > j; --k) { + n = uMap->mapUnicode(text[k], buf, sizeof(buf)); + s->append(buf, n); + ++nCols; + } + i = j; + // output a left-to-right section + for (j = i; j >= 0 && !unicodeTypeR(text[j]); --j) ; + if (j < i) { + s->append(lre, lreLen); + for (k = j + 1; k <= i; ++k) { + n = uMap->mapUnicode(text[k], buf, sizeof(buf)); + s->append(buf, n); + ++nCols; + } + s->append(popdf, popdfLen); + i = j; + } + } + s->append(popdf, popdfLen); + + } + + } else { + for (i = 0; i < len; ++i) { + n = uMap->mapUnicode(text[i], buf, sizeof(buf)); + s->append(buf, n); + nCols += n; + } + } + + return nCols; +} + +#if TEXTOUT_WORD_LIST +TextWordList *TextPage::makeWordList(GBool physLayout) { + return new TextWordList(this, physLayout); +} +#endif + +//------------------------------------------------------------------------ +// TextOutputDev +//------------------------------------------------------------------------ + +static void TextOutputDev_outputToFile(void *stream, char *text, int len) { + fwrite(text, 1, len, (FILE *)stream); +} + +TextOutputDev::TextOutputDev(char *fileName, GBool physLayoutA, + GBool rawOrderA, GBool append) { + text = NULL; + physLayout = physLayoutA; + rawOrder = rawOrderA; + doHTML = gFalse; + ok = gTrue; + + // open file + needClose = gFalse; + if (fileName) { + if (!strcmp(fileName, "-")) { + outputStream = stdout; +#ifdef WIN32 + // keep DOS from munging the end-of-line characters + setmode(fileno(stdout), O_BINARY); +#endif + } else if ((outputStream = fopen(fileName, append ? "ab" : "wb"))) { + needClose = gTrue; + } else { + error(-1, "Couldn't open text file '%s'", fileName); + ok = gFalse; + return; + } + outputFunc = &TextOutputDev_outputToFile; + } else { + outputStream = NULL; + } + + // set up text object + text = new TextPage(rawOrderA); +} + +TextOutputDev::TextOutputDev(TextOutputFunc func, void *stream, + GBool physLayoutA, GBool rawOrderA) { + outputFunc = func; + outputStream = stream; + needClose = gFalse; + physLayout = physLayoutA; + rawOrder = rawOrderA; + doHTML = gFalse; + text = new TextPage(rawOrderA); + ok = gTrue; +} + +TextOutputDev::~TextOutputDev() { + if (needClose) { +#ifdef MACOS + ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle); +#endif + fclose((FILE *)outputStream); + } + if (text) { + delete text; + } +} + +void TextOutputDev::startPage(int /*pageNum*/, GfxState *state) { + text->startPage(state); +} + +void TextOutputDev::endPage() { + text->endPage(); + text->coalesce(physLayout, doHTML); + if (outputStream) { + text->dump(outputStream, outputFunc, physLayout); + } +} + +void TextOutputDev::updateFont(GfxState *state) { + text->updateFont(state); +} + +void TextOutputDev::beginString(GfxState * /*state*/, GString * /*s*/) { +} + +void TextOutputDev::endString(GfxState * /*state*/) { +} + +void TextOutputDev::drawChar(GfxState *state, double x, double y, + double dx, double dy, + double /*originX*/, double /*originY*/, + CharCode c, int nBytes, Unicode *u, int uLen) { + text->addChar(state, x, y, dx, dy, c, nBytes, u, uLen); +} + +void TextOutputDev::stroke(GfxState *state) { + GfxPath *path; + GfxSubpath *subpath; + double x[2], y[2]; + + if (!doHTML) { + return; + } + path = state->getPath(); + if (path->getNumSubpaths() != 1) { + return; + } + subpath = path->getSubpath(0); + if (subpath->getNumPoints() != 2) { + return; + } + state->transform(subpath->getX(0), subpath->getY(0), &x[0], &y[0]); + state->transform(subpath->getX(1), subpath->getY(1), &x[1], &y[1]); + + // look for a vertical or horizontal line + if (x[0] == x[1] || y[0] == y[1]) { + text->addUnderline(x[0], y[0], x[1], y[1]); + } +} + +void TextOutputDev::fill(GfxState *state) { + GfxPath *path; + GfxSubpath *subpath; + double x[5], y[5]; + double rx0, ry0, rx1, ry1, t; + int i; + + if (!doHTML) { + return; + } + path = state->getPath(); + if (path->getNumSubpaths() != 1) { + return; + } + subpath = path->getSubpath(0); + if (subpath->getNumPoints() != 5) { + return; + } + for (i = 0; i < 5; ++i) { + if (subpath->getCurve(i)) { + return; + } + state->transform(subpath->getX(i), subpath->getY(i), &x[i], &y[i]); + } + + // look for a rectangle + if (x[0] == x[1] && y[1] == y[2] && x[2] == x[3] && y[3] == y[4] && + x[0] == x[4] && y[0] == y[4]) { + rx0 = x[0]; + ry0 = y[0]; + rx1 = x[2]; + ry1 = y[1]; + } else if (y[0] == y[1] && x[1] == x[2] && y[2] == y[3] && x[3] == x[4] && + x[0] == x[4] && y[0] == y[4]) { + rx0 = x[0]; + ry0 = y[0]; + rx1 = x[1]; + ry1 = y[2]; + } else { + return; + } + if (rx1 < rx0) { + t = rx0; + rx0 = rx1; + rx1 = t; + } + if (ry1 < ry0) { + t = ry0; + ry0 = ry1; + ry1 = t; + } + + // skinny horizontal rectangle + if (ry1 - ry0 < rx1 - rx0) { + if (ry1 - ry0 < maxUnderlineWidth) { + ry0 = 0.5 * (ry0 + ry1); + text->addUnderline(rx0, ry0, rx1, ry0); + } + + // skinny vertical rectangle + } else { + if (rx1 - rx0 < maxUnderlineWidth) { + rx0 = 0.5 * (rx0 + rx1); + text->addUnderline(rx0, ry0, rx0, ry1); + } + } +} + +void TextOutputDev::eoFill(GfxState *state) { + if (!doHTML) { + return; + } + fill(state); +} + +void TextOutputDev::processLink(Link *link, Catalog * /*catalog*/) { + double x1, y1, x2, y2; + int xMin, yMin, xMax, yMax, x, y; + + if (!doHTML) { + return; + } + link->getRect(&x1, &y1, &x2, &y2); + cvtUserToDev(x1, y1, &x, &y); + xMin = xMax = x; + yMin = yMax = y; + cvtUserToDev(x1, y2, &x, &y); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + cvtUserToDev(x2, y1, &x, &y); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + cvtUserToDev(x2, y2, &x, &y); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + text->addLink(xMin, yMin, xMax, yMax, link); +} + +GBool TextOutputDev::findText(Unicode *s, int len, + GBool startAtTop, GBool stopAtBottom, + GBool startAtLast, GBool stopAtLast, + GBool caseSensitive, GBool backward, + double *xMin, double *yMin, + double *xMax, double *yMax) { + return text->findText(s, len, startAtTop, stopAtBottom, + startAtLast, stopAtLast, caseSensitive, backward, + xMin, yMin, xMax, yMax); +} + +GString *TextOutputDev::getText(double xMin, double yMin, + double xMax, double yMax) { + return text->getText(xMin, yMin, xMax, yMax); +} + +GBool TextOutputDev::findCharRange(int pos, int length, + double *xMin, double *yMin, + double *xMax, double *yMax) { + return text->findCharRange(pos, length, xMin, yMin, xMax, yMax); +} + +#if TEXTOUT_WORD_LIST +TextWordList *TextOutputDev::makeWordList() { + return text->makeWordList(physLayout); +} +#endif + +TextPage *TextOutputDev::takeText() { + TextPage *ret; + + ret = text; + text = new TextPage(rawOrder); + return ret; +} diff --git a/kpdf/xpdf/xpdf/TextOutputDev.h b/kpdf/xpdf/xpdf/TextOutputDev.h new file mode 100644 index 00000000..3a424bb1 --- /dev/null +++ b/kpdf/xpdf/xpdf/TextOutputDev.h @@ -0,0 +1,661 @@ +//======================================================================== +// +// TextOutputDev.h +// +// Copyright 1997-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef TEXTOUTPUTDEV_H +#define TEXTOUTPUTDEV_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include +#include "gtypes.h" +#include "GfxFont.h" +#include "OutputDev.h" + +class GString; +class GList; +class GfxFont; +class GfxState; +class UnicodeMap; +class Link; + +class TextWord; +class TextPool; +class TextLine; +class TextLineFrag; +class TextBlock; +class TextFlow; +class TextWordList; +class TextPage; + +//------------------------------------------------------------------------ + +typedef void (*TextOutputFunc)(void *stream, char *text, int len); + +//------------------------------------------------------------------------ +// TextFontInfo +//------------------------------------------------------------------------ + +class TextFontInfo { +public: + + TextFontInfo(GfxState *state); + ~TextFontInfo(); + + GBool matches(GfxState *state); + +#if TEXTOUT_WORD_LIST + // Get the font name (which may be NULL). + GString *getFontName() { return fontName; } + + // Get font descriptor flags. + GBool isFixedWidth() { return flags & fontFixedWidth; } + GBool isSerif() { return flags & fontSerif; } + GBool isSymbolic() { return flags & fontSymbolic; } + GBool isItalic() { return flags & fontItalic; } + GBool isBold() { return flags & fontBold; } +#endif + +private: + + GfxFont *gfxFont; +#if TEXTOUT_WORD_LIST + GString *fontName; + int flags; +#endif + + friend class TextWord; + friend class TextPage; +}; + +//------------------------------------------------------------------------ +// TextWord +//------------------------------------------------------------------------ + +class TextWord { +public: + + // Constructor. + TextWord(GfxState *state, int rotA, double x0, double y0, + int charPosA, TextFontInfo *fontA, double fontSize); + + // Destructor. + ~TextWord(); + + // Add a character to the word. + void addChar(GfxState *state, double x, double y, + double dx, double dy, Unicode u); + + // Merge onto the end of . + void merge(TextWord *word); + + // Compares to , returning -1 (<), 0 (=), or +1 (>), + // based on a primary-axis comparison, e.g., x ordering if rot=0. + int primaryCmp(TextWord *word); + + // Return the distance along the primary axis between and + // . + double primaryDelta(TextWord *word); + + static int cmpYX(const void *p1, const void *p2); + + // Get the TextFontInfo object associated with this word. + TextFontInfo *getFontInfo() { return font; } + + // Get the next TextWord on the linked list. + TextWord *getNext() { return next; } + +#if TEXTOUT_WORD_LIST + int getLength() { return len; } + Unicode getChar(int idx) { return text[idx]; } + GString *getText(); + GString *getFontName() { return font->fontName; } + void getColor(double *r, double *g, double *b) + { *r = colorR; *g = colorG; *b = colorB; } + void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA) + { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } + void getCharBBox(int charIdx, double *xMinA, double *yMinA, + double *xMaxA, double *yMaxA); + double getFontSize() { return fontSize; } + int getRotation() { return rot; } + int getCharPos() { return charPos; } + int getCharLen() { return charLen; } + GBool getSpaceAfter() { return spaceAfter; } +#endif + + GBool isUnderlined() { return underlined; } + Link *getLink() { return link; } + +private: + + int rot; // rotation, multiple of 90 degrees + // (0, 1, 2, or 3) + double xMin, xMax; // bounding box x coordinates + double yMin, yMax; // bounding box y coordinates + double base; // baseline x or y coordinate + Unicode *text; // the text + double *edge; // "near" edge x or y coord of each char + // (plus one extra entry for the last char) + int len; // length of text and edge arrays + int size; // size of text and edge arrays + int charPos; // character position (within content stream) + int charLen; // number of content stream characters in + // this word + TextFontInfo *font; // font information + double fontSize; // font size + GBool spaceAfter; // set if there is a space between this + // word and the next word on the line + TextWord *next; // next word in line + +#if TEXTOUT_WORD_LIST + double colorR, // word color + colorG, + colorB; +#endif + + GBool underlined; + Link *link; + + friend class TextPool; + friend class TextLine; + friend class TextBlock; + friend class TextFlow; + friend class TextWordList; + friend class TextPage; +}; + +//------------------------------------------------------------------------ +// TextPool +//------------------------------------------------------------------------ + +class TextPool { +public: + + TextPool(); + ~TextPool(); + + TextWord *getPool(int baseIdx) { return pool[baseIdx - minBaseIdx]; } + void setPool(int baseIdx, TextWord *p) { pool[baseIdx - minBaseIdx] = p; } + + int getBaseIdx(double base); + + void addWord(TextWord *word); + +private: + + int minBaseIdx; // min baseline bucket index + int maxBaseIdx; // max baseline bucket index + TextWord **pool; // array of linked lists, one for each + // baseline value (multiple of 4 pts) + TextWord *cursor; // pointer to last-accessed word + int cursorBaseIdx; // baseline bucket index of last-accessed word + + friend class TextBlock; + friend class TextPage; +}; + +//------------------------------------------------------------------------ +// TextLine +//------------------------------------------------------------------------ + +class TextLine { +public: + + TextLine(TextBlock *blkA, int rotA, double baseA); + ~TextLine(); + + void addWord(TextWord *word); + + // Return the distance along the primary axis between and + // . + double primaryDelta(TextLine *line); + + // Compares to , returning -1 (<), 0 (=), or +1 (>), + // based on a primary-axis comparison, e.g., x ordering if rot=0. + int primaryCmp(TextLine *line); + + // Compares to , returning -1 (<), 0 (=), or +1 (>), + // based on a secondary-axis comparison of the baselines, e.g., y + // ordering if rot=0. + int secondaryCmp(TextLine *line); + + int cmpYX(TextLine *line); + + static int cmpXY(const void *p1, const void *p2); + + void coalesce(UnicodeMap *uMap); + + // Get the head of the linked list of TextWords. + TextWord *getWords() { return words; } + + // Get the next TextLine on the linked list. + TextLine *getNext() { return next; } + + // Returns true if the last char of the line is a hyphen. + GBool isHyphenated() { return hyphenated; } + +private: + + TextBlock *blk; // parent block + int rot; // text rotation + double xMin, xMax; // bounding box x coordinates + double yMin, yMax; // bounding box y coordinates + double base; // baseline x or y coordinate + TextWord *words; // words in this line + TextWord *lastWord; // last word in this line + Unicode *text; // Unicode text of the line, including + // spaces between words + double *edge; // "near" edge x or y coord of each char + // (plus one extra entry for the last char) + int *col; // starting column number of each Unicode char + int len; // number of Unicode chars + int convertedLen; // total number of converted characters + GBool hyphenated; // set if last char is a hyphen + TextLine *next; // next line in block + + friend class TextLineFrag; + friend class TextBlock; + friend class TextFlow; + friend class TextWordList; + friend class TextPage; +}; + +//------------------------------------------------------------------------ +// TextBlock +//------------------------------------------------------------------------ + +class TextBlock { +public: + + TextBlock(TextPage *pageA, int rotA); + ~TextBlock(); + + void addWord(TextWord *word); + + void coalesce(UnicodeMap *uMap); + + // Update this block's priMin and priMax values, looking at . + void updatePriMinMax(TextBlock *blk); + + static int cmpXYPrimaryRot(const void *p1, const void *p2); + + static int cmpYXPrimaryRot(const void *p1, const void *p2); + + int primaryCmp(TextBlock *blk); + + double secondaryDelta(TextBlock *blk); + + // Returns true if is below , relative to the page's + // primary rotation. + GBool isBelow(TextBlock *blk); + + // Get the head of the linked list of TextLines. + TextLine *getLines() { return lines; } + + // Get the next TextBlock on the linked list. + TextBlock *getNext() { return next; } + +private: + + TextPage *page; // the parent page + int rot; // text rotation + double xMin, xMax; // bounding box x coordinates + double yMin, yMax; // bounding box y coordinates + double priMin, priMax; // whitespace bounding box along primary axis + + TextPool *pool; // pool of words (used only until lines + // are built) + TextLine *lines; // linked list of lines + TextLine *curLine; // most recently added line + int nLines; // number of lines + int charCount; // number of characters in the block + int col; // starting column + int nColumns; // number of columns in the block + + TextBlock *next; + TextBlock *stackNext; + + friend class TextLine; + friend class TextLineFrag; + friend class TextFlow; + friend class TextWordList; + friend class TextPage; +}; + +//------------------------------------------------------------------------ +// TextFlow +//------------------------------------------------------------------------ + +class TextFlow { +public: + + TextFlow(TextPage *pageA, TextBlock *blk); + ~TextFlow(); + + // Add a block to the end of this flow. + void addBlock(TextBlock *blk); + + // Returns true if fits below in the flow, i.e., (1) + // it uses a font no larger than the last block added to the flow, + // and (2) it fits within the flow's [priMin, priMax] along the + // primary axis. + GBool blockFits(TextBlock *blk, TextBlock *prevBlk); + + // Get the head of the linked list of TextBlocks. + TextBlock *getBlocks() { return blocks; } + + // Get the next TextFlow on the linked list. + TextFlow *getNext() { return next; } + +private: + + TextPage *page; // the parent page + double xMin, xMax; // bounding box x coordinates + double yMin, yMax; // bounding box y coordinates + double priMin, priMax; // whitespace bounding box along primary axis + TextBlock *blocks; // blocks in flow + TextBlock *lastBlk; // last block in this flow + TextFlow *next; + + friend class TextWordList; + friend class TextPage; +}; + +#if TEXTOUT_WORD_LIST + +//------------------------------------------------------------------------ +// TextWordList +//------------------------------------------------------------------------ + +class TextWordList { +public: + + // Build a flat word list, in content stream order (if + // text->rawOrder is true), physical layout order (if + // is true and text->rawOrder is false), or reading order (if both + // flags are false). + TextWordList(TextPage *text, GBool physLayout); + + ~TextWordList(); + + // Return the number of words on the list. + int getLength(); + + // Return the th word from the list. + TextWord *get(int idx); + +private: + + GList *words; // [TextWord] +}; + +#endif // TEXTOUT_WORD_LIST + +//------------------------------------------------------------------------ +// TextPage +//------------------------------------------------------------------------ + +class TextPage { +public: + + // Constructor. + TextPage(GBool rawOrderA); + + // Destructor. + ~TextPage(); + + // Start a new page. + void startPage(GfxState *state); + + // End the current page. + void endPage(); + + // Update the current font. + void updateFont(GfxState *state); + + // Begin a new word. + void beginWord(GfxState *state, double x0, double y0); + + // Add a character to the current word. + void addChar(GfxState *state, double x, double y, + double dx, double dy, + CharCode c, int nBytes, Unicode *u, int uLen); + + // End the current word, sorting it into the list of words. + void endWord(); + + // Add a word, sorting it into the list of words. + void addWord(TextWord *word); + + // Add a (potential) underline. + void addUnderline(double x0, double y0, double x1, double y1); + + // Add a hyperlink. + void addLink(int xMin, int yMin, int xMax, int yMax, Link *link); + + // Coalesce strings that look like parts of the same line. + void coalesce(GBool physLayout, GBool doHTML); + + // Find a string. If is true, starts looking at the + // top of the page; else if is true, starts looking + // immediately after the last find result; else starts looking at + // ,. If is true, stops looking at the + // bottom of the page; else if is true, stops looking + // just before the last find result; else stops looking at + // ,. + GBool findText(Unicode *s, int len, + GBool startAtTop, GBool stopAtBottom, + GBool startAtLast, GBool stopAtLast, + GBool caseSensitive, GBool backward, + double *xMin, double *yMin, + double *xMax, double *yMax); + + // Get the text which is inside the specified rectangle. + GString *getText(double xMin, double yMin, + double xMax, double yMax); + + // Find a string by character position and length. If found, sets + // the text bounding rectangle and returns true; otherwise returns + // false. + GBool findCharRange(int pos, int length, + double *xMin, double *yMin, + double *xMax, double *yMax); + + // Dump contents of page to a file. + void dump(void *outputStream, TextOutputFunc outputFunc, + GBool physLayout); + + // Get the head of the linked list of TextFlows. + TextFlow *getFlows() { return flows; } + +#if TEXTOUT_WORD_LIST + // Build a flat word list, in content stream order (if + // this->rawOrder is true), physical layout order (if + // is true and this->rawOrder is false), or reading order (if both + // flags are false). + TextWordList *makeWordList(GBool physLayout); +#endif + +private: + + void clear(); + void assignColumns(TextLineFrag *frags, int nFrags, int rot); + int dumpFragment(Unicode *text, int len, UnicodeMap *uMap, GString *s); + + GBool rawOrder; // keep text in content stream order + + double pageWidth, pageHeight; // width and height of current page + TextWord *curWord; // currently active string + int charPos; // next character position (within content + // stream) + TextFontInfo *curFont; // current font + double curFontSize; // current font size + int nest; // current nesting level (for Type 3 fonts) + int nTinyChars; // number of "tiny" chars seen so far + GBool lastCharOverlap; // set if the last added char overlapped the + // previous char + + TextPool *pools[4]; // a "pool" of TextWords for each rotation + TextFlow *flows; // linked list of flows + TextBlock **blocks; // array of blocks, in yx order + int nBlocks; // number of blocks + int primaryRot; // primary rotation + GBool primaryLR; // primary direction (true means L-to-R, + // false means R-to-L) + TextWord *rawWords; // list of words, in raw order (only if + // rawOrder is set) + TextWord *rawLastWord; // last word on rawWords list + + GList *fonts; // all font info objects used on this + // page [TextFontInfo] + + double lastFindXMin, // coordinates of the last "find" result + lastFindYMin; + GBool haveLastFind; + + GList *underlines; // [TextUnderline] + GList *links; // [TextLink] + + friend class TextLine; + friend class TextLineFrag; + friend class TextBlock; + friend class TextFlow; + friend class TextWordList; +}; + +//------------------------------------------------------------------------ +// TextOutputDev +//------------------------------------------------------------------------ + +class TextOutputDev: public OutputDev { +public: + + // Open a text output file. If is NULL, no file is + // written (this is useful, e.g., for searching text). If + // is true, the original physical layout of the text + // is maintained. If is true, the text is kept in + // content stream order. + TextOutputDev(char *fileName, GBool physLayoutA, + GBool rawOrderA, GBool append); + + // Create a TextOutputDev which will write to a generic stream. If + // is true, the original physical layout of the text + // is maintained. If is true, the text is kept in + // content stream order. + TextOutputDev(TextOutputFunc func, void *stream, + GBool physLayoutA, GBool rawOrderA); + + // Destructor. + virtual ~TextOutputDev(); + + // Check if file was successfully created. + virtual GBool isOk() { return ok; } + + //---- get info about output device + + // Does this device use upside-down coordinates? + // (Upside-down means (0,0) is the top left corner of the page.) + virtual GBool upsideDown() { return gTrue; } + + // Does this device use drawChar() or drawString()? + virtual GBool useDrawChar() { return gTrue; } + + // Does this device use beginType3Char/endType3Char? Otherwise, + // text in Type 3 fonts will be drawn with drawChar/drawString. + virtual GBool interpretType3Chars() { return gFalse; } + + // Does this device need non-text content? + virtual GBool needNonText() { return gFalse; } + + //----- initialization and control + + // Start a page. + virtual void startPage(int pageNum, GfxState *state); + + // End a page. + virtual void endPage(); + + //----- update text state + virtual void updateFont(GfxState *state); + + //----- text drawing + virtual void beginString(GfxState *state, GString *s); + virtual void endString(GfxState *state); + virtual void drawChar(GfxState *state, double x, double y, + double dx, double dy, + double originX, double originY, + CharCode c, int nBytes, Unicode *u, int uLen); + + //----- path painting + virtual void stroke(GfxState *state); + virtual void fill(GfxState *state); + virtual void eoFill(GfxState *state); + + //----- link borders + virtual void processLink(Link *link, Catalog *catalog); + + //----- special access + + // Find a string. If is true, starts looking at the + // top of the page; else if is true, starts looking + // immediately after the last find result; else starts looking at + // ,. If is true, stops looking at the + // bottom of the page; else if is true, stops looking + // just before the last find result; else stops looking at + // ,. + GBool findText(Unicode *s, int len, + GBool startAtTop, GBool stopAtBottom, + GBool startAtLast, GBool stopAtLast, + GBool caseSensitive, GBool backward, + double *xMin, double *yMin, + double *xMax, double *yMax); + + // Get the text which is inside the specified rectangle. + GString *getText(double xMin, double yMin, + double xMax, double yMax); + + // Find a string by character position and length. If found, sets + // the text bounding rectangle and returns true; otherwise returns + // false. + GBool findCharRange(int pos, int length, + double *xMin, double *yMin, + double *xMax, double *yMax); + +#if TEXTOUT_WORD_LIST + // Build a flat word list, in content stream order (if + // this->rawOrder is true), physical layout order (if + // this->physLayout is true and this->rawOrder is false), or reading + // order (if both flags are false). + TextWordList *makeWordList(); +#endif + + // Returns the TextPage object for the last rasterized page, + // transferring ownership to the caller. + TextPage *takeText(); + + // Turn extra processing for HTML conversion on or off. + void enableHTMLExtras(GBool doHTMLA) { doHTML = doHTMLA; } + +private: + + TextOutputFunc outputFunc; // output function + void *outputStream; // output stream + GBool needClose; // need to close the output file? + // (only if outputStream is a FILE*) + TextPage *text; // text for the current page + GBool physLayout; // maintain original physical layout when + // dumping text + GBool rawOrder; // keep text in content stream order + GBool doHTML; // extra processing for HTML conversion + GBool ok; // set up ok? +}; + +#endif diff --git a/kpdf/xpdf/xpdf/UTF8.h b/kpdf/xpdf/xpdf/UTF8.h new file mode 100644 index 00000000..8536dbf9 --- /dev/null +++ b/kpdf/xpdf/xpdf/UTF8.h @@ -0,0 +1,56 @@ +//======================================================================== +// +// UTF8.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +static int mapUTF8(Unicode u, char *buf, int bufSize) { + if (u <= 0x0000007f) { + if (bufSize < 1) { + return 0; + } + buf[0] = (char)u; + return 1; + } else if (u <= 0x000007ff) { + if (bufSize < 2) { + return 0; + } + buf[0] = (char)(0xc0 + (u >> 6)); + buf[1] = (char)(0x80 + (u & 0x3f)); + return 2; + } else if (u <= 0x0000ffff) { + if (bufSize < 3) { + return 0; + } + buf[0] = (char)(0xe0 + (u >> 12)); + buf[1] = (char)(0x80 + ((u >> 6) & 0x3f)); + buf[2] = (char)(0x80 + (u & 0x3f)); + return 3; + } else if (u <= 0x0010ffff) { + if (bufSize < 4) { + return 0; + } + buf[0] = (char)(0xf0 + (u >> 18)); + buf[1] = (char)(0x80 + ((u >> 12) & 0x3f)); + buf[2] = (char)(0x80 + ((u >> 6) & 0x3f)); + buf[3] = (char)(0x80 + (u & 0x3f)); + return 4; + } else { + return 0; + } +} + +static int mapUCS2(Unicode u, char *buf, int bufSize) { + if (u <= 0xffff) { + if (bufSize < 2) { + return 0; + } + buf[0] = (char)((u >> 8) & 0xff); + buf[1] = (char)(u & 0xff); + return 2; + } else { + return 0; + } +} diff --git a/kpdf/xpdf/xpdf/UnicodeMap.cc b/kpdf/xpdf/xpdf/UnicodeMap.cc new file mode 100644 index 00000000..2b8cb1f7 --- /dev/null +++ b/kpdf/xpdf/xpdf/UnicodeMap.cc @@ -0,0 +1,293 @@ +//======================================================================== +// +// UnicodeMap.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "gfile.h" +#include "GString.h" +#include "GList.h" +#include "Error.h" +#include "GlobalParams.h" +#include "UnicodeMap.h" + +//------------------------------------------------------------------------ + +#define maxExtCode 16 + +struct UnicodeMapExt { + Unicode u; // Unicode char + char code[maxExtCode]; + Guint nBytes; +}; + +//------------------------------------------------------------------------ + +UnicodeMap *UnicodeMap::parse(GString *encodingNameA) { + FILE *f; + UnicodeMap *map; + UnicodeMapRange *range; + UnicodeMapExt *eMap; + int size, eMapsSize; + char buf[256]; + int line, nBytes, i, x; + char *tok1, *tok2, *tok3; + + if (!(f = globalParams->getUnicodeMapFile(encodingNameA))) { + error(-1, "Couldn't find unicodeMap file for the '%s' encoding", + encodingNameA->getCString()); + return NULL; + } + + map = new UnicodeMap(encodingNameA->copy()); + + size = 8; + map->ranges = (UnicodeMapRange *)gmallocn(size, sizeof(UnicodeMapRange)); + eMapsSize = 0; + + line = 1; + while (getLine(buf, sizeof(buf), f)) { + if ((tok1 = strtok(buf, " \t\r\n")) && + (tok2 = strtok(NULL, " \t\r\n"))) { + if (!(tok3 = strtok(NULL, " \t\r\n"))) { + tok3 = tok2; + tok2 = tok1; + } + nBytes = strlen(tok3) / 2; + if (nBytes <= 4) { + if (map->len == size) { + size *= 2; + map->ranges = (UnicodeMapRange *) + greallocn(map->ranges, size, sizeof(UnicodeMapRange)); + } + range = &map->ranges[map->len]; + sscanf(tok1, "%x", &range->start); + sscanf(tok2, "%x", &range->end); + sscanf(tok3, "%x", &range->code); + range->nBytes = nBytes; + ++map->len; + } else if (tok2 == tok1) { + if (map->eMapsLen == eMapsSize) { + eMapsSize += 16; + map->eMaps = (UnicodeMapExt *) + greallocn(map->eMaps, eMapsSize, sizeof(UnicodeMapExt)); + } + eMap = &map->eMaps[map->eMapsLen]; + sscanf(tok1, "%x", &eMap->u); + for (i = 0; i < nBytes; ++i) { + sscanf(tok3 + i*2, "%2x", &x); + eMap->code[i] = (char)x; + } + eMap->nBytes = nBytes; + ++map->eMapsLen; + } else { + error(-1, "Bad line (%d) in unicodeMap file for the '%s' encoding", + line, encodingNameA->getCString()); + } + } else { + error(-1, "Bad line (%d) in unicodeMap file for the '%s' encoding", + line, encodingNameA->getCString()); + } + ++line; + } + + fclose(f); + + return map; +} + +UnicodeMap::UnicodeMap(GString *encodingNameA) { + encodingName = encodingNameA; + unicodeOut = gFalse; + kind = unicodeMapUser; + ranges = NULL; + len = 0; + eMaps = NULL; + eMapsLen = 0; + refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif +} + +UnicodeMap::UnicodeMap(char *encodingNameA, GBool unicodeOutA, + UnicodeMapRange *rangesA, int lenA) { + encodingName = new GString(encodingNameA); + unicodeOut = unicodeOutA; + kind = unicodeMapResident; + ranges = rangesA; + len = lenA; + eMaps = NULL; + eMapsLen = 0; + refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif +} + +UnicodeMap::UnicodeMap(char *encodingNameA, GBool unicodeOutA, + UnicodeMapFunc funcA) { + encodingName = new GString(encodingNameA); + unicodeOut = unicodeOutA; + kind = unicodeMapFunc; + func = funcA; + eMaps = NULL; + eMapsLen = 0; + refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif +} + +UnicodeMap::~UnicodeMap() { + delete encodingName; + if (kind == unicodeMapUser && ranges) { + gfree(ranges); + } + if (eMaps) { + gfree(eMaps); + } +#if MULTITHREADED + gDestroyMutex(&mutex); +#endif +} + +void UnicodeMap::incRefCnt() { +#if MULTITHREADED + gLockMutex(&mutex); +#endif + ++refCnt; +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif +} + +void UnicodeMap::decRefCnt() { + GBool done; + +#if MULTITHREADED + gLockMutex(&mutex); +#endif + done = --refCnt == 0; +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif + if (done) { + delete this; + } +} + +GBool UnicodeMap::match(GString *encodingNameA) { + return !encodingName->cmp(encodingNameA); +} + +int UnicodeMap::mapUnicode(Unicode u, char *buf, int bufSize) { + int a, b, m, n, i, j; + Guint code; + + if (kind == unicodeMapFunc) { + return (*func)(u, buf, bufSize); + } + + a = 0; + b = len; + if (u >= ranges[a].start) { + // invariant: ranges[a].start <= u < ranges[b].start + while (b - a > 1) { + m = (a + b) / 2; + if (u >= ranges[m].start) { + a = m; + } else if (u < ranges[m].start) { + b = m; + } + } + if (u <= ranges[a].end) { + n = ranges[a].nBytes; + if (n > bufSize) { + return 0; + } + code = ranges[a].code + (u - ranges[a].start); + for (i = n - 1; i >= 0; --i) { + buf[i] = (char)(code & 0xff); + code >>= 8; + } + return n; + } + } + + for (i = 0; i < eMapsLen; ++i) { + if (eMaps[i].u == u) { + n = eMaps[i].nBytes; + for (j = 0; j < n; ++j) { + buf[j] = eMaps[i].code[j]; + } + return n; + } + } + + return 0; +} + +//------------------------------------------------------------------------ + +UnicodeMapCache::UnicodeMapCache() { + int i; + + for (i = 0; i < unicodeMapCacheSize; ++i) { + cache[i] = NULL; + } +} + +UnicodeMapCache::~UnicodeMapCache() { + int i; + + for (i = 0; i < unicodeMapCacheSize; ++i) { + if (cache[i]) { + cache[i]->decRefCnt(); + } + } +} + +UnicodeMap *UnicodeMapCache::getUnicodeMap(GString *encodingName) { + UnicodeMap *map; + int i, j; + + if (cache[0] && cache[0]->match(encodingName)) { + cache[0]->incRefCnt(); + return cache[0]; + } + for (i = 1; i < unicodeMapCacheSize; ++i) { + if (cache[i] && cache[i]->match(encodingName)) { + map = cache[i]; + for (j = i; j >= 1; --j) { + cache[j] = cache[j - 1]; + } + cache[0] = map; + map->incRefCnt(); + return map; + } + } + if ((map = UnicodeMap::parse(encodingName))) { + if (cache[unicodeMapCacheSize - 1]) { + cache[unicodeMapCacheSize - 1]->decRefCnt(); + } + for (j = unicodeMapCacheSize - 1; j >= 1; --j) { + cache[j] = cache[j - 1]; + } + cache[0] = map; + map->incRefCnt(); + return map; + } + return NULL; +} diff --git a/kpdf/xpdf/xpdf/UnicodeMap.h b/kpdf/xpdf/xpdf/UnicodeMap.h new file mode 100644 index 00000000..0f86101e --- /dev/null +++ b/kpdf/xpdf/xpdf/UnicodeMap.h @@ -0,0 +1,123 @@ +//======================================================================== +// +// UnicodeMap.h +// +// Mapping from Unicode to an encoding. +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef UNICODEMAP_H +#define UNICODEMAP_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "CharTypes.h" + +#if MULTITHREADED +#include "GMutex.h" +#endif + +class GString; + +//------------------------------------------------------------------------ + +enum UnicodeMapKind { + unicodeMapUser, // read from a file + unicodeMapResident, // static list of ranges + unicodeMapFunc // function pointer +}; + +typedef int (*UnicodeMapFunc)(Unicode u, char *buf, int bufSize); + +struct UnicodeMapRange { + Unicode start, end; // range of Unicode chars + Guint code, nBytes; // first output code +}; + +struct UnicodeMapExt; + +//------------------------------------------------------------------------ + +class UnicodeMap { +public: + + // Create the UnicodeMap specified by . Sets the + // initial reference count to 1. Returns NULL on failure. + static UnicodeMap *parse(GString *encodingNameA); + + // Create a resident UnicodeMap. + UnicodeMap(char *encodingNameA, GBool unicodeOutA, + UnicodeMapRange *rangesA, int lenA); + + // Create a resident UnicodeMap that uses a function instead of a + // list of ranges. + UnicodeMap(char *encodingNameA, GBool unicodeOutA, + UnicodeMapFunc funcA); + + ~UnicodeMap(); + + void incRefCnt(); + void decRefCnt(); + + GString *getEncodingName() { return encodingName; } + + GBool isUnicode() { return unicodeOut; } + + // Return true if this UnicodeMap matches the specified + // . + GBool match(GString *encodingNameA); + + // Map Unicode to the target encoding. Fills in with the + // output and returns the number of bytes used. Output will be + // truncated at bytes. No string terminator is written. + // Returns 0 if no mapping is found. + int mapUnicode(Unicode u, char *buf, int bufSize); + +private: + + UnicodeMap(GString *encodingNameA); + + GString *encodingName; + UnicodeMapKind kind; + GBool unicodeOut; + union { + UnicodeMapRange *ranges; // (user, resident) + UnicodeMapFunc func; // (func) + }; + int len; // (user, resident) + UnicodeMapExt *eMaps; // (user) + int eMapsLen; // (user) + int refCnt; +#if MULTITHREADED + GMutex mutex; +#endif +}; + +//------------------------------------------------------------------------ + +#define unicodeMapCacheSize 4 + +class UnicodeMapCache { +public: + + UnicodeMapCache(); + ~UnicodeMapCache(); + + // Get the UnicodeMap for . Increments its reference + // count; there will be one reference for the cache plus one for the + // caller of this function. Returns NULL on failure. + UnicodeMap *getUnicodeMap(GString *encodingName); + +private: + + UnicodeMap *cache[unicodeMapCacheSize]; +}; + +#endif diff --git a/kpdf/xpdf/xpdf/UnicodeMapTables.h b/kpdf/xpdf/xpdf/UnicodeMapTables.h new file mode 100644 index 00000000..9c510346 --- /dev/null +++ b/kpdf/xpdf/xpdf/UnicodeMapTables.h @@ -0,0 +1,361 @@ +//======================================================================== +// +// UnicodeMapTables.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +static UnicodeMapRange latin1UnicodeMapRanges[] = { + { 0x000a, 0x000a, 0x0a, 1 }, + { 0x000c, 0x000d, 0x0c, 1 }, + { 0x0020, 0x007e, 0x20, 1 }, + { 0x00a0, 0x00a0, 0x20, 1 }, + { 0x00a1, 0x00ac, 0xa1, 1 }, + { 0x00ae, 0x00ff, 0xae, 1 }, + { 0x010c, 0x010c, 0x43, 1 }, + { 0x010d, 0x010d, 0x63, 1 }, + { 0x0131, 0x0131, 0x69, 1 }, + { 0x0141, 0x0141, 0x4c, 1 }, + { 0x0142, 0x0142, 0x6c, 1 }, + { 0x0152, 0x0152, 0x4f45, 2 }, + { 0x0153, 0x0153, 0x6f65, 2 }, + { 0x0160, 0x0160, 0x53, 1 }, + { 0x0161, 0x0161, 0x73, 1 }, + { 0x0178, 0x0178, 0x59, 1 }, + { 0x017d, 0x017d, 0x5a, 1 }, + { 0x017e, 0x017e, 0x7a, 1 }, + { 0x02c6, 0x02c6, 0x5e, 1 }, + { 0x02da, 0x02da, 0xb0, 1 }, + { 0x02dc, 0x02dc, 0x7e, 1 }, + { 0x2013, 0x2013, 0xad, 1 }, + { 0x2014, 0x2014, 0x2d2d, 2 }, + { 0x2018, 0x2018, 0x60, 1 }, + { 0x2019, 0x2019, 0x27, 1 }, + { 0x201a, 0x201a, 0x2c, 1 }, + { 0x201c, 0x201c, 0x22, 1 }, + { 0x201d, 0x201d, 0x22, 1 }, + { 0x201e, 0x201e, 0x2c2c, 2 }, + { 0x2022, 0x2022, 0xb7, 1 }, + { 0x2026, 0x2026, 0x2e2e2e, 3 }, + { 0x2039, 0x2039, 0x3c, 1 }, + { 0x203a, 0x203a, 0x3e, 1 }, + { 0x2044, 0x2044, 0x2f, 1 }, + { 0x2122, 0x2122, 0x544d, 2 }, + { 0x2212, 0x2212, 0x2d, 1 }, + { 0xf6f9, 0xf6f9, 0x4c, 1 }, + { 0xf6fa, 0xf6fa, 0x4f45, 2 }, + { 0xf6fc, 0xf6fc, 0xb0, 1 }, + { 0xf6fd, 0xf6fd, 0x53, 1 }, + { 0xf6fe, 0xf6fe, 0x7e, 1 }, + { 0xf6ff, 0xf6ff, 0x5a, 1 }, + { 0xf721, 0xf721, 0x21, 1 }, + { 0xf724, 0xf724, 0x24, 1 }, + { 0xf726, 0xf726, 0x26, 1 }, + { 0xf730, 0xf739, 0x30, 1 }, + { 0xf73f, 0xf73f, 0x3f, 1 }, + { 0xf761, 0xf77a, 0x41, 1 }, + { 0xf7a1, 0xf7a2, 0xa1, 1 }, + { 0xf7bf, 0xf7bf, 0xbf, 1 }, + { 0xf7e0, 0xf7f6, 0xc0, 1 }, + { 0xf7f8, 0xf7fe, 0xd8, 1 }, + { 0xf7ff, 0xf7ff, 0x59, 1 }, + { 0xfb00, 0xfb00, 0x6666, 2 }, + { 0xfb01, 0xfb01, 0x6669, 2 }, + { 0xfb02, 0xfb02, 0x666c, 2 }, + { 0xfb03, 0xfb03, 0x666669, 3 }, + { 0xfb04, 0xfb04, 0x66666c, 3 } +}; +#define latin1UnicodeMapLen (sizeof(latin1UnicodeMapRanges) / sizeof(UnicodeMapRange)) + +static UnicodeMapRange ascii7UnicodeMapRanges[] = { + { 0x000a, 0x000a, 0x0a, 1 }, + { 0x000c, 0x000d, 0x0c, 1 }, + { 0x0020, 0x005f, 0x20, 1 }, + { 0x0061, 0x007e, 0x61, 1 }, + { 0x00a6, 0x00a6, 0x7c, 1 }, + { 0x00a9, 0x00a9, 0x286329, 3 }, + { 0x00ae, 0x00ae, 0x285229, 3 }, + { 0x00b7, 0x00b7, 0x2a, 1 }, + { 0x00bc, 0x00bc, 0x312f34, 3 }, + { 0x00bd, 0x00bd, 0x312f32, 3 }, + { 0x00be, 0x00be, 0x332f34, 3 }, + { 0x00c0, 0x00c0, 0x41, 1 }, + { 0x00c1, 0x00c1, 0x41, 1 }, + { 0x00c2, 0x00c2, 0x41, 1 }, + { 0x00c3, 0x00c3, 0x41, 1 }, + { 0x00c4, 0x00c4, 0x41, 1 }, + { 0x00c5, 0x00c5, 0x41, 1 }, + { 0x00c6, 0x00c6, 0x4145, 2 }, + { 0x00c7, 0x00c7, 0x43, 1 }, + { 0x00c8, 0x00c8, 0x45, 1 }, + { 0x00c9, 0x00c9, 0x45, 1 }, + { 0x00ca, 0x00ca, 0x45, 1 }, + { 0x00cb, 0x00cb, 0x45, 1 }, + { 0x00cc, 0x00cc, 0x49, 1 }, + { 0x00cd, 0x00cd, 0x49, 1 }, + { 0x00ce, 0x00ce, 0x49, 1 }, + { 0x00cf, 0x00cf, 0x49, 1 }, + { 0x00d1, 0x00d2, 0x4e, 1 }, + { 0x00d3, 0x00d3, 0x4f, 1 }, + { 0x00d4, 0x00d4, 0x4f, 1 }, + { 0x00d5, 0x00d5, 0x4f, 1 }, + { 0x00d6, 0x00d6, 0x4f, 1 }, + { 0x00d7, 0x00d7, 0x78, 1 }, + { 0x00d8, 0x00d8, 0x4f, 1 }, + { 0x00d9, 0x00d9, 0x55, 1 }, + { 0x00da, 0x00da, 0x55, 1 }, + { 0x00db, 0x00db, 0x55, 1 }, + { 0x00dc, 0x00dc, 0x55, 1 }, + { 0x00dd, 0x00dd, 0x59, 1 }, + { 0x00e0, 0x00e0, 0x61, 1 }, + { 0x00e1, 0x00e1, 0x61, 1 }, + { 0x00e2, 0x00e2, 0x61, 1 }, + { 0x00e3, 0x00e3, 0x61, 1 }, + { 0x00e4, 0x00e4, 0x61, 1 }, + { 0x00e5, 0x00e5, 0x61, 1 }, + { 0x00e6, 0x00e6, 0x6165, 2 }, + { 0x00e7, 0x00e7, 0x63, 1 }, + { 0x00e8, 0x00e8, 0x65, 1 }, + { 0x00e9, 0x00e9, 0x65, 1 }, + { 0x00ea, 0x00ea, 0x65, 1 }, + { 0x00eb, 0x00eb, 0x65, 1 }, + { 0x00ec, 0x00ec, 0x69, 1 }, + { 0x00ed, 0x00ed, 0x69, 1 }, + { 0x00ee, 0x00ee, 0x69, 1 }, + { 0x00ef, 0x00ef, 0x69, 1 }, + { 0x00f1, 0x00f2, 0x6e, 1 }, + { 0x00f3, 0x00f3, 0x6f, 1 }, + { 0x00f4, 0x00f4, 0x6f, 1 }, + { 0x00f5, 0x00f5, 0x6f, 1 }, + { 0x00f6, 0x00f6, 0x6f, 1 }, + { 0x00f7, 0x00f7, 0x2f, 1 }, + { 0x00f8, 0x00f8, 0x6f, 1 }, + { 0x00f9, 0x00f9, 0x75, 1 }, + { 0x00fa, 0x00fa, 0x75, 1 }, + { 0x00fb, 0x00fb, 0x75, 1 }, + { 0x00fc, 0x00fc, 0x75, 1 }, + { 0x00fd, 0x00fd, 0x79, 1 }, + { 0x00ff, 0x00ff, 0x79, 1 }, + { 0x0131, 0x0131, 0x69, 1 }, + { 0x0141, 0x0141, 0x4c, 1 }, + { 0x0152, 0x0152, 0x4f45, 2 }, + { 0x0153, 0x0153, 0x6f65, 2 }, + { 0x0160, 0x0160, 0x53, 1 }, + { 0x0178, 0x0178, 0x59, 1 }, + { 0x017d, 0x017d, 0x5a, 1 }, + { 0x2013, 0x2013, 0x2d, 1 }, + { 0x2014, 0x2014, 0x2d2d, 2 }, + { 0x2018, 0x2018, 0x60, 1 }, + { 0x2019, 0x2019, 0x27, 1 }, + { 0x201c, 0x201c, 0x22, 1 }, + { 0x201d, 0x201d, 0x22, 1 }, + { 0x2022, 0x2022, 0x2a, 1 }, + { 0x2026, 0x2026, 0x2e2e2e, 3 }, + { 0x2122, 0x2122, 0x544d, 2 }, + { 0x2212, 0x2212, 0x2d, 1 }, + { 0xf6f9, 0xf6f9, 0x4c, 1 }, + { 0xf6fa, 0xf6fa, 0x4f45, 2 }, + { 0xf6fd, 0xf6fd, 0x53, 1 }, + { 0xf6fe, 0xf6fe, 0x7e, 1 }, + { 0xf6ff, 0xf6ff, 0x5a, 1 }, + { 0xf721, 0xf721, 0x21, 1 }, + { 0xf724, 0xf724, 0x24, 1 }, + { 0xf726, 0xf726, 0x26, 1 }, + { 0xf730, 0xf739, 0x30, 1 }, + { 0xf73f, 0xf73f, 0x3f, 1 }, + { 0xf761, 0xf77a, 0x41, 1 }, + { 0xf7e0, 0xf7e0, 0x41, 1 }, + { 0xf7e1, 0xf7e1, 0x41, 1 }, + { 0xf7e2, 0xf7e2, 0x41, 1 }, + { 0xf7e3, 0xf7e3, 0x41, 1 }, + { 0xf7e4, 0xf7e4, 0x41, 1 }, + { 0xf7e5, 0xf7e5, 0x41, 1 }, + { 0xf7e6, 0xf7e6, 0x4145, 2 }, + { 0xf7e7, 0xf7e7, 0x43, 1 }, + { 0xf7e8, 0xf7e8, 0x45, 1 }, + { 0xf7e9, 0xf7e9, 0x45, 1 }, + { 0xf7ea, 0xf7ea, 0x45, 1 }, + { 0xf7eb, 0xf7eb, 0x45, 1 }, + { 0xf7ec, 0xf7ec, 0x49, 1 }, + { 0xf7ed, 0xf7ed, 0x49, 1 }, + { 0xf7ee, 0xf7ee, 0x49, 1 }, + { 0xf7ef, 0xf7ef, 0x49, 1 }, + { 0xf7f1, 0xf7f2, 0x4e, 1 }, + { 0xf7f3, 0xf7f3, 0x4f, 1 }, + { 0xf7f4, 0xf7f4, 0x4f, 1 }, + { 0xf7f5, 0xf7f5, 0x4f, 1 }, + { 0xf7f6, 0xf7f6, 0x4f, 1 }, + { 0xf7f8, 0xf7f8, 0x4f, 1 }, + { 0xf7f9, 0xf7f9, 0x55, 1 }, + { 0xf7fa, 0xf7fa, 0x55, 1 }, + { 0xf7fb, 0xf7fb, 0x55, 1 }, + { 0xf7fc, 0xf7fc, 0x55, 1 }, + { 0xf7fd, 0xf7fd, 0x59, 1 }, + { 0xf7ff, 0xf7ff, 0x59, 1 }, + { 0xfb00, 0xfb00, 0x6666, 2 }, + { 0xfb01, 0xfb01, 0x6669, 2 }, + { 0xfb02, 0xfb02, 0x666c, 2 }, + { 0xfb03, 0xfb03, 0x666669, 3 }, + { 0xfb04, 0xfb04, 0x66666c, 3 } +}; +#define ascii7UnicodeMapLen (sizeof(ascii7UnicodeMapRanges) / sizeof(UnicodeMapRange)) + +static UnicodeMapRange symbolUnicodeMapRanges[] = { + { 0x0020, 0x0021, 0x20, 1 }, + { 0x0023, 0x0023, 0x23, 1 }, + { 0x0025, 0x0026, 0x25, 1 }, + { 0x0028, 0x0029, 0x28, 1 }, + { 0x002b, 0x002c, 0x2b, 1 }, + { 0x002e, 0x003f, 0x2e, 1 }, + { 0x005b, 0x005b, 0x5b, 1 }, + { 0x005d, 0x005d, 0x5d, 1 }, + { 0x005f, 0x005f, 0x5f, 1 }, + { 0x007b, 0x007d, 0x7b, 1 }, + { 0x00ac, 0x00ac, 0xd8, 1 }, + { 0x00b0, 0x00b1, 0xb0, 1 }, + { 0x00b5, 0x00b5, 0x6d, 1 }, + { 0x00d7, 0x00d7, 0xb4, 1 }, + { 0x00f7, 0x00f7, 0xb8, 1 }, + { 0x0192, 0x0192, 0xa6, 1 }, + { 0x0391, 0x0392, 0x41, 1 }, + { 0x0393, 0x0393, 0x47, 1 }, + { 0x0395, 0x0395, 0x45, 1 }, + { 0x0396, 0x0396, 0x5a, 1 }, + { 0x0397, 0x0397, 0x48, 1 }, + { 0x0398, 0x0398, 0x51, 1 }, + { 0x0399, 0x0399, 0x49, 1 }, + { 0x039a, 0x039d, 0x4b, 1 }, + { 0x039e, 0x039e, 0x58, 1 }, + { 0x039f, 0x03a0, 0x4f, 1 }, + { 0x03a1, 0x03a1, 0x52, 1 }, + { 0x03a3, 0x03a5, 0x53, 1 }, + { 0x03a6, 0x03a6, 0x46, 1 }, + { 0x03a7, 0x03a7, 0x43, 1 }, + { 0x03a8, 0x03a8, 0x59, 1 }, + { 0x03b1, 0x03b2, 0x61, 1 }, + { 0x03b3, 0x03b3, 0x67, 1 }, + { 0x03b4, 0x03b5, 0x64, 1 }, + { 0x03b6, 0x03b6, 0x7a, 1 }, + { 0x03b7, 0x03b7, 0x68, 1 }, + { 0x03b8, 0x03b8, 0x71, 1 }, + { 0x03b9, 0x03b9, 0x69, 1 }, + { 0x03ba, 0x03bb, 0x6b, 1 }, + { 0x03bd, 0x03bd, 0x6e, 1 }, + { 0x03be, 0x03be, 0x78, 1 }, + { 0x03bf, 0x03c0, 0x6f, 1 }, + { 0x03c1, 0x03c1, 0x72, 1 }, + { 0x03c2, 0x03c2, 0x56, 1 }, + { 0x03c3, 0x03c5, 0x73, 1 }, + { 0x03c6, 0x03c6, 0x66, 1 }, + { 0x03c7, 0x03c7, 0x63, 1 }, + { 0x03c8, 0x03c8, 0x79, 1 }, + { 0x03c9, 0x03c9, 0x77, 1 }, + { 0x03d1, 0x03d1, 0x4a, 1 }, + { 0x03d2, 0x03d2, 0xa1, 1 }, + { 0x03d5, 0x03d5, 0x6a, 1 }, + { 0x03d6, 0x03d6, 0x76, 1 }, + { 0x2022, 0x2022, 0xb7, 1 }, + { 0x2026, 0x2026, 0xbc, 1 }, + { 0x2032, 0x2032, 0xa2, 1 }, + { 0x2033, 0x2033, 0xb2, 1 }, + { 0x2044, 0x2044, 0xa4, 1 }, + { 0x2111, 0x2111, 0xc1, 1 }, + { 0x2118, 0x2118, 0xc3, 1 }, + { 0x211c, 0x211c, 0xc2, 1 }, + { 0x2126, 0x2126, 0x57, 1 }, + { 0x2135, 0x2135, 0xc0, 1 }, + { 0x2190, 0x2193, 0xac, 1 }, + { 0x2194, 0x2194, 0xab, 1 }, + { 0x21b5, 0x21b5, 0xbf, 1 }, + { 0x21d0, 0x21d3, 0xdc, 1 }, + { 0x21d4, 0x21d4, 0xdb, 1 }, + { 0x2200, 0x2200, 0x22, 1 }, + { 0x2202, 0x2202, 0xb6, 1 }, + { 0x2203, 0x2203, 0x24, 1 }, + { 0x2205, 0x2205, 0xc6, 1 }, + { 0x2206, 0x2206, 0x44, 1 }, + { 0x2207, 0x2207, 0xd1, 1 }, + { 0x2208, 0x2209, 0xce, 1 }, + { 0x220b, 0x220b, 0x27, 1 }, + { 0x220f, 0x220f, 0xd5, 1 }, + { 0x2211, 0x2211, 0xe5, 1 }, + { 0x2212, 0x2212, 0x2d, 1 }, + { 0x2217, 0x2217, 0x2a, 1 }, + { 0x221a, 0x221a, 0xd6, 1 }, + { 0x221d, 0x221d, 0xb5, 1 }, + { 0x221e, 0x221e, 0xa5, 1 }, + { 0x2220, 0x2220, 0xd0, 1 }, + { 0x2227, 0x2228, 0xd9, 1 }, + { 0x2229, 0x222a, 0xc7, 1 }, + { 0x222b, 0x222b, 0xf2, 1 }, + { 0x2234, 0x2234, 0x5c, 1 }, + { 0x223c, 0x223c, 0x7e, 1 }, + { 0x2245, 0x2245, 0x40, 1 }, + { 0x2248, 0x2248, 0xbb, 1 }, + { 0x2260, 0x2261, 0xb9, 1 }, + { 0x2264, 0x2264, 0xa3, 1 }, + { 0x2265, 0x2265, 0xb3, 1 }, + { 0x2282, 0x2282, 0xcc, 1 }, + { 0x2283, 0x2283, 0xc9, 1 }, + { 0x2284, 0x2284, 0xcb, 1 }, + { 0x2286, 0x2286, 0xcd, 1 }, + { 0x2287, 0x2287, 0xca, 1 }, + { 0x2295, 0x2295, 0xc5, 1 }, + { 0x2297, 0x2297, 0xc4, 1 }, + { 0x22a5, 0x22a5, 0x5e, 1 }, + { 0x22c5, 0x22c5, 0xd7, 1 }, + { 0x2320, 0x2320, 0xf3, 1 }, + { 0x2321, 0x2321, 0xf5, 1 }, + { 0x2329, 0x2329, 0xe1, 1 }, + { 0x232a, 0x232a, 0xf1, 1 }, + { 0x25ca, 0x25ca, 0xe0, 1 }, + { 0x2660, 0x2660, 0xaa, 1 }, + { 0x2663, 0x2663, 0xa7, 1 }, + { 0x2665, 0x2665, 0xa9, 1 }, + { 0x2666, 0x2666, 0xa8, 1 }, + { 0xf6d9, 0xf6d9, 0xd3, 1 }, + { 0xf6da, 0xf6da, 0xd2, 1 }, + { 0xf6db, 0xf6db, 0xd4, 1 }, + { 0xf8e5, 0xf8e5, 0x60, 1 }, + { 0xf8e6, 0xf8e7, 0xbd, 1 }, + { 0xf8e8, 0xf8ea, 0xe2, 1 }, + { 0xf8eb, 0xf8f4, 0xe6, 1 }, + { 0xf8f5, 0xf8f5, 0xf4, 1 }, + { 0xf8f6, 0xf8fe, 0xf6, 1 } +}; +#define symbolUnicodeMapLen (sizeof(symbolUnicodeMapRanges) / sizeof(UnicodeMapRange)) + +static UnicodeMapRange zapfDingbatsUnicodeMapRanges[] = { + { 0x0020, 0x0020, 0x20, 1 }, + { 0x2192, 0x2192, 0xd5, 1 }, + { 0x2194, 0x2195, 0xd6, 1 }, + { 0x2460, 0x2469, 0xac, 1 }, + { 0x25a0, 0x25a0, 0x6e, 1 }, + { 0x25b2, 0x25b2, 0x73, 1 }, + { 0x25bc, 0x25bc, 0x74, 1 }, + { 0x25c6, 0x25c6, 0x75, 1 }, + { 0x25cf, 0x25cf, 0x6c, 1 }, + { 0x25d7, 0x25d7, 0x77, 1 }, + { 0x2605, 0x2605, 0x48, 1 }, + { 0x260e, 0x260e, 0x25, 1 }, + { 0x261b, 0x261b, 0x2a, 1 }, + { 0x261e, 0x261e, 0x2b, 1 }, + { 0x2660, 0x2660, 0xab, 1 }, + { 0x2663, 0x2663, 0xa8, 1 }, + { 0x2665, 0x2665, 0xaa, 1 }, + { 0x2666, 0x2666, 0xa9, 1 }, + { 0x2701, 0x2704, 0x21, 1 }, + { 0x2706, 0x2709, 0x26, 1 }, + { 0x270c, 0x2727, 0x2c, 1 }, + { 0x2729, 0x274b, 0x49, 1 }, + { 0x274d, 0x274d, 0x6d, 1 }, + { 0x274f, 0x2752, 0x6f, 1 }, + { 0x2756, 0x2756, 0x76, 1 }, + { 0x2758, 0x275e, 0x78, 1 }, + { 0x2761, 0x2767, 0xa1, 1 }, + { 0x2776, 0x2794, 0xb6, 1 }, + { 0x2798, 0x27af, 0xd8, 1 }, + { 0x27b1, 0x27be, 0xf1, 1 } +}; +#define zapfDingbatsUnicodeMapLen (sizeof(zapfDingbatsUnicodeMapRanges) / sizeof(UnicodeMapRange)) diff --git a/kpdf/xpdf/xpdf/UnicodeTypeTable.cc b/kpdf/xpdf/xpdf/UnicodeTypeTable.cc new file mode 100644 index 00000000..b8960403 --- /dev/null +++ b/kpdf/xpdf/xpdf/UnicodeTypeTable.cc @@ -0,0 +1,949 @@ +//======================================================================== +// +// UnicodeTypeTable.cc +// +// Copyright 2004 Glyph & Cog, LLC +// +//======================================================================== + +#include +#include "CharTypes.h" +#include "UnicodeTypeTable.h" + +struct UnicodeMapTableEntry { + char *vector; + char type; +}; + +struct UnicodeCaseTableVector { + Unicode codes[256]; +}; + +static UnicodeMapTableEntry typeTable[256] = { + { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLNNNNNNNNNNLNNNNLNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLL", 'X' }, + { NULL, 'L' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLNNNNNNNNNNNNNNLLNNNNNNNNNNNNNNLLLLLNNNNNNNNNLNNNNNNNNNNNNNNNNN", 'X' }, + { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLNNNNNNNNNNNLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNRNRNNRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR", 'X' }, + { "RRRRNNNNNNNNNRNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNRRRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNRNNNNNNNRRNNNNNNNRRNNNNNNNNNNRRRRRR", 'X' }, + { "RRRRRRRRRRRRRRNNRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNNNNNNNNNNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, + { NULL, 'N' }, + { "NNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNLLLLNLLLNNNNLLLLLLLLLLLLLNNLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNLLLLLLLLNLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLNNLLLLLLLNNNNN", 'X' }, + { "NNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNLLLLNLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLNNNNNNNNNNNNNNNN", 'X' }, + { "NNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLNLNNNLLLLLLLLLNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNLLLLLLLNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLNNNNNNNNNNNNLLLLLLLNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLNNNNNNNNNLLLLLLLLLLNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLNLNLNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNLNNNNNLNNLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNLNNNNNNLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLLLLLNLLNNNNNNNNNNNLLLLLLLNLNLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNN", 'X' }, + { "NNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLNNNNNLLLLLLNLLLLLLNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLNNNLLLLLLLLLLLNNNLLLLLLLLLLLLNNNNLLLLLLLLLLLLLNNNLLLLLLLLLLLLLNNN", 'X' }, + { "NNNNNNNNNNNNNNLRNNNNNNNNNNNNNNNNNNNNNNNNNNLRNLRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLNNNNNNNNNNNNNLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, + { "NNLNNNNLNNLLLLLLLLLLNLNNNLLLLLNNNNNNLNLNLNLLLLNLLLNLLLLLLLNNLLLLNNNNNLLLLLNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, + { NULL, 'N' }, + { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, + { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNN", 'X' }, + { NULL, 'N' }, + { NULL, 'N' }, + { NULL, 'N' }, + { NULL, 'L' }, + { NULL, 'N' }, + { NULL, 'N' }, + { NULL, 'N' }, + { NULL, 'N' }, + { NULL, 'N' }, + { NULL, 'N' }, + { NULL, 'N' }, + { "NNNNNLLLNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLNNNNNNNLLLLLNNLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLL", 'X' }, + { NULL, 'L' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNLLLLLLLLLLLLNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN", 'X' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLRRRRRRNRRRRRRRRRRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR", 'X' }, + { NULL, 'R' }, + { "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNN", 'X' }, + { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNN", 'X' }, + { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLL", 'X' } +}; + +static UnicodeCaseTableVector caseTable00 = {{ + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, + 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, + 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x03bc, 0x00b6, 0x00b7, + 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, + 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, + 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, + 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00d7, + 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00df, + 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, + 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, + 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, + 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff +}}; +static UnicodeCaseTableVector caseTable01 = {{ + 0x0101, 0x0101, 0x0103, 0x0103, 0x0105, 0x0105, 0x0107, 0x0107, + 0x0109, 0x0109, 0x010b, 0x010b, 0x010d, 0x010d, 0x010f, 0x010f, + 0x0111, 0x0111, 0x0113, 0x0113, 0x0115, 0x0115, 0x0117, 0x0117, + 0x0119, 0x0119, 0x011b, 0x011b, 0x011d, 0x011d, 0x011f, 0x011f, + 0x0121, 0x0121, 0x0123, 0x0123, 0x0125, 0x0125, 0x0127, 0x0127, + 0x0129, 0x0129, 0x012b, 0x012b, 0x012d, 0x012d, 0x012f, 0x012f, + 0x0130, 0x0131, 0x0133, 0x0133, 0x0135, 0x0135, 0x0137, 0x0137, + 0x0138, 0x013a, 0x013a, 0x013c, 0x013c, 0x013e, 0x013e, 0x0140, + 0x0140, 0x0142, 0x0142, 0x0144, 0x0144, 0x0146, 0x0146, 0x0148, + 0x0148, 0x0149, 0x014b, 0x014b, 0x014d, 0x014d, 0x014f, 0x014f, + 0x0151, 0x0151, 0x0153, 0x0153, 0x0155, 0x0155, 0x0157, 0x0157, + 0x0159, 0x0159, 0x015b, 0x015b, 0x015d, 0x015d, 0x015f, 0x015f, + 0x0161, 0x0161, 0x0163, 0x0163, 0x0165, 0x0165, 0x0167, 0x0167, + 0x0169, 0x0169, 0x016b, 0x016b, 0x016d, 0x016d, 0x016f, 0x016f, + 0x0171, 0x0171, 0x0173, 0x0173, 0x0175, 0x0175, 0x0177, 0x0177, + 0x00ff, 0x017a, 0x017a, 0x017c, 0x017c, 0x017e, 0x017e, 0x0073, + 0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188, + 0x0188, 0x0256, 0x0257, 0x018c, 0x018c, 0x018d, 0x01dd, 0x0259, + 0x025b, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268, + 0x0199, 0x0199, 0x019a, 0x019b, 0x026f, 0x0272, 0x019e, 0x0275, + 0x01a1, 0x01a1, 0x01a3, 0x01a3, 0x01a5, 0x01a5, 0x0280, 0x01a8, + 0x01a8, 0x0283, 0x01aa, 0x01ab, 0x01ad, 0x01ad, 0x0288, 0x01b0, + 0x01b0, 0x028a, 0x028b, 0x01b4, 0x01b4, 0x01b6, 0x01b6, 0x0292, + 0x01b9, 0x01b9, 0x01ba, 0x01bb, 0x01bd, 0x01bd, 0x01be, 0x01bf, + 0x01c0, 0x01c1, 0x01c2, 0x01c3, 0x01c6, 0x01c6, 0x01c6, 0x01c9, + 0x01c9, 0x01c9, 0x01cc, 0x01cc, 0x01cc, 0x01ce, 0x01ce, 0x01d0, + 0x01d0, 0x01d2, 0x01d2, 0x01d4, 0x01d4, 0x01d6, 0x01d6, 0x01d8, + 0x01d8, 0x01da, 0x01da, 0x01dc, 0x01dc, 0x01dd, 0x01df, 0x01df, + 0x01e1, 0x01e1, 0x01e3, 0x01e3, 0x01e5, 0x01e5, 0x01e7, 0x01e7, + 0x01e9, 0x01e9, 0x01eb, 0x01eb, 0x01ed, 0x01ed, 0x01ef, 0x01ef, + 0x01f0, 0x01f3, 0x01f3, 0x01f3, 0x01f5, 0x01f5, 0x0195, 0x01bf, + 0x01f9, 0x01f9, 0x01fb, 0x01fb, 0x01fd, 0x01fd, 0x01ff, 0x01ff +}}; +static UnicodeCaseTableVector caseTable02 = {{ + 0x0201, 0x0201, 0x0203, 0x0203, 0x0205, 0x0205, 0x0207, 0x0207, + 0x0209, 0x0209, 0x020b, 0x020b, 0x020d, 0x020d, 0x020f, 0x020f, + 0x0211, 0x0211, 0x0213, 0x0213, 0x0215, 0x0215, 0x0217, 0x0217, + 0x0219, 0x0219, 0x021b, 0x021b, 0x021d, 0x021d, 0x021f, 0x021f, + 0x019e, 0x0221, 0x0223, 0x0223, 0x0225, 0x0225, 0x0227, 0x0227, + 0x0229, 0x0229, 0x022b, 0x022b, 0x022d, 0x022d, 0x022f, 0x022f, + 0x0231, 0x0231, 0x0233, 0x0233, 0x0234, 0x0235, 0x0236, 0x0237, + 0x0238, 0x0239, 0x023a, 0x023b, 0x023c, 0x023d, 0x023e, 0x023f, + 0x0240, 0x0241, 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247, + 0x0248, 0x0249, 0x024a, 0x024b, 0x024c, 0x024d, 0x024e, 0x024f, + 0x0250, 0x0251, 0x0252, 0x0253, 0x0254, 0x0255, 0x0256, 0x0257, + 0x0258, 0x0259, 0x025a, 0x025b, 0x025c, 0x025d, 0x025e, 0x025f, + 0x0260, 0x0261, 0x0262, 0x0263, 0x0264, 0x0265, 0x0266, 0x0267, + 0x0268, 0x0269, 0x026a, 0x026b, 0x026c, 0x026d, 0x026e, 0x026f, + 0x0270, 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277, + 0x0278, 0x0279, 0x027a, 0x027b, 0x027c, 0x027d, 0x027e, 0x027f, + 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0286, 0x0287, + 0x0288, 0x0289, 0x028a, 0x028b, 0x028c, 0x028d, 0x028e, 0x028f, + 0x0290, 0x0291, 0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297, + 0x0298, 0x0299, 0x029a, 0x029b, 0x029c, 0x029d, 0x029e, 0x029f, + 0x02a0, 0x02a1, 0x02a2, 0x02a3, 0x02a4, 0x02a5, 0x02a6, 0x02a7, + 0x02a8, 0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ad, 0x02ae, 0x02af, + 0x02b0, 0x02b1, 0x02b2, 0x02b3, 0x02b4, 0x02b5, 0x02b6, 0x02b7, + 0x02b8, 0x02b9, 0x02ba, 0x02bb, 0x02bc, 0x02bd, 0x02be, 0x02bf, + 0x02c0, 0x02c1, 0x02c2, 0x02c3, 0x02c4, 0x02c5, 0x02c6, 0x02c7, + 0x02c8, 0x02c9, 0x02ca, 0x02cb, 0x02cc, 0x02cd, 0x02ce, 0x02cf, + 0x02d0, 0x02d1, 0x02d2, 0x02d3, 0x02d4, 0x02d5, 0x02d6, 0x02d7, + 0x02d8, 0x02d9, 0x02da, 0x02db, 0x02dc, 0x02dd, 0x02de, 0x02df, + 0x02e0, 0x02e1, 0x02e2, 0x02e3, 0x02e4, 0x02e5, 0x02e6, 0x02e7, + 0x02e8, 0x02e9, 0x02ea, 0x02eb, 0x02ec, 0x02ed, 0x02ee, 0x02ef, + 0x02f0, 0x02f1, 0x02f2, 0x02f3, 0x02f4, 0x02f5, 0x02f6, 0x02f7, + 0x02f8, 0x02f9, 0x02fa, 0x02fb, 0x02fc, 0x02fd, 0x02fe, 0x02ff +}}; +static UnicodeCaseTableVector caseTable03 = {{ + 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, + 0x0308, 0x0309, 0x030a, 0x030b, 0x030c, 0x030d, 0x030e, 0x030f, + 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, + 0x0318, 0x0319, 0x031a, 0x031b, 0x031c, 0x031d, 0x031e, 0x031f, + 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, + 0x0328, 0x0329, 0x032a, 0x032b, 0x032c, 0x032d, 0x032e, 0x032f, + 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, + 0x0338, 0x0339, 0x033a, 0x033b, 0x033c, 0x033d, 0x033e, 0x033f, + 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x03b9, 0x0346, 0x0347, + 0x0348, 0x0349, 0x034a, 0x034b, 0x034c, 0x034d, 0x034e, 0x034f, + 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, + 0x0358, 0x0359, 0x035a, 0x035b, 0x035c, 0x035d, 0x035e, 0x035f, + 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, + 0x0368, 0x0369, 0x036a, 0x036b, 0x036c, 0x036d, 0x036e, 0x036f, + 0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377, + 0x0378, 0x0379, 0x037a, 0x037b, 0x037c, 0x037d, 0x037e, 0x037f, + 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x03ac, 0x0387, + 0x03ad, 0x03ae, 0x03af, 0x038b, 0x03cc, 0x038d, 0x03cd, 0x03ce, + 0x0390, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, + 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, + 0x03c0, 0x03c1, 0x03a2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, + 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03ac, 0x03ad, 0x03ae, 0x03af, + 0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, + 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, + 0x03c0, 0x03c1, 0x03c3, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, + 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce, 0x03cf, + 0x03b2, 0x03b8, 0x03d2, 0x03d3, 0x03d4, 0x03c6, 0x03c0, 0x03d7, + 0x03d9, 0x03d9, 0x03db, 0x03db, 0x03dd, 0x03dd, 0x03df, 0x03df, + 0x03e1, 0x03e1, 0x03e3, 0x03e3, 0x03e5, 0x03e5, 0x03e7, 0x03e7, + 0x03e9, 0x03e9, 0x03eb, 0x03eb, 0x03ed, 0x03ed, 0x03ef, 0x03ef, + 0x03ba, 0x03c1, 0x03f2, 0x03f3, 0x03b8, 0x03b5, 0x03f6, 0x03f8, + 0x03f8, 0x03f2, 0x03fb, 0x03fb, 0x03fc, 0x03fd, 0x03fe, 0x03ff +}}; +static UnicodeCaseTableVector caseTable04 = {{ + 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, + 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x045d, 0x045e, 0x045f, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, + 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, + 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x045d, 0x045e, 0x045f, + 0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467, + 0x0469, 0x0469, 0x046b, 0x046b, 0x046d, 0x046d, 0x046f, 0x046f, + 0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0477, 0x0477, + 0x0479, 0x0479, 0x047b, 0x047b, 0x047d, 0x047d, 0x047f, 0x047f, + 0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, + 0x0488, 0x0489, 0x048b, 0x048b, 0x048d, 0x048d, 0x048f, 0x048f, + 0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497, + 0x0499, 0x0499, 0x049b, 0x049b, 0x049d, 0x049d, 0x049f, 0x049f, + 0x04a1, 0x04a1, 0x04a3, 0x04a3, 0x04a5, 0x04a5, 0x04a7, 0x04a7, + 0x04a9, 0x04a9, 0x04ab, 0x04ab, 0x04ad, 0x04ad, 0x04af, 0x04af, + 0x04b1, 0x04b1, 0x04b3, 0x04b3, 0x04b5, 0x04b5, 0x04b7, 0x04b7, + 0x04b9, 0x04b9, 0x04bb, 0x04bb, 0x04bd, 0x04bd, 0x04bf, 0x04bf, + 0x04c0, 0x04c2, 0x04c2, 0x04c4, 0x04c4, 0x04c6, 0x04c6, 0x04c8, + 0x04c8, 0x04ca, 0x04ca, 0x04cc, 0x04cc, 0x04ce, 0x04ce, 0x04cf, + 0x04d1, 0x04d1, 0x04d3, 0x04d3, 0x04d5, 0x04d5, 0x04d7, 0x04d7, + 0x04d9, 0x04d9, 0x04db, 0x04db, 0x04dd, 0x04dd, 0x04df, 0x04df, + 0x04e1, 0x04e1, 0x04e3, 0x04e3, 0x04e5, 0x04e5, 0x04e7, 0x04e7, + 0x04e9, 0x04e9, 0x04eb, 0x04eb, 0x04ed, 0x04ed, 0x04ef, 0x04ef, + 0x04f1, 0x04f1, 0x04f3, 0x04f3, 0x04f5, 0x04f5, 0x04f6, 0x04f7, + 0x04f9, 0x04f9, 0x04fa, 0x04fb, 0x04fc, 0x04fd, 0x04fe, 0x04ff +}}; +static UnicodeCaseTableVector caseTable05 = {{ + 0x0501, 0x0501, 0x0503, 0x0503, 0x0505, 0x0505, 0x0507, 0x0507, + 0x0509, 0x0509, 0x050b, 0x050b, 0x050d, 0x050d, 0x050f, 0x050f, + 0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517, + 0x0518, 0x0519, 0x051a, 0x051b, 0x051c, 0x051d, 0x051e, 0x051f, + 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527, + 0x0528, 0x0529, 0x052a, 0x052b, 0x052c, 0x052d, 0x052e, 0x052f, + 0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, + 0x0568, 0x0569, 0x056a, 0x056b, 0x056c, 0x056d, 0x056e, 0x056f, + 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, + 0x0578, 0x0579, 0x057a, 0x057b, 0x057c, 0x057d, 0x057e, 0x057f, + 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557, + 0x0558, 0x0559, 0x055a, 0x055b, 0x055c, 0x055d, 0x055e, 0x055f, + 0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, + 0x0568, 0x0569, 0x056a, 0x056b, 0x056c, 0x056d, 0x056e, 0x056f, + 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, + 0x0578, 0x0579, 0x057a, 0x057b, 0x057c, 0x057d, 0x057e, 0x057f, + 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587, + 0x0588, 0x0589, 0x058a, 0x058b, 0x058c, 0x058d, 0x058e, 0x058f, + 0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597, + 0x0598, 0x0599, 0x059a, 0x059b, 0x059c, 0x059d, 0x059e, 0x059f, + 0x05a0, 0x05a1, 0x05a2, 0x05a3, 0x05a4, 0x05a5, 0x05a6, 0x05a7, + 0x05a8, 0x05a9, 0x05aa, 0x05ab, 0x05ac, 0x05ad, 0x05ae, 0x05af, + 0x05b0, 0x05b1, 0x05b2, 0x05b3, 0x05b4, 0x05b5, 0x05b6, 0x05b7, + 0x05b8, 0x05b9, 0x05ba, 0x05bb, 0x05bc, 0x05bd, 0x05be, 0x05bf, + 0x05c0, 0x05c1, 0x05c2, 0x05c3, 0x05c4, 0x05c5, 0x05c6, 0x05c7, + 0x05c8, 0x05c9, 0x05ca, 0x05cb, 0x05cc, 0x05cd, 0x05ce, 0x05cf, + 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, + 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, + 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, + 0x05e8, 0x05e9, 0x05ea, 0x05eb, 0x05ec, 0x05ed, 0x05ee, 0x05ef, + 0x05f0, 0x05f1, 0x05f2, 0x05f3, 0x05f4, 0x05f5, 0x05f6, 0x05f7, + 0x05f8, 0x05f9, 0x05fa, 0x05fb, 0x05fc, 0x05fd, 0x05fe, 0x05ff +}}; +static UnicodeCaseTableVector caseTable1e = {{ + 0x1e01, 0x1e01, 0x1e03, 0x1e03, 0x1e05, 0x1e05, 0x1e07, 0x1e07, + 0x1e09, 0x1e09, 0x1e0b, 0x1e0b, 0x1e0d, 0x1e0d, 0x1e0f, 0x1e0f, + 0x1e11, 0x1e11, 0x1e13, 0x1e13, 0x1e15, 0x1e15, 0x1e17, 0x1e17, + 0x1e19, 0x1e19, 0x1e1b, 0x1e1b, 0x1e1d, 0x1e1d, 0x1e1f, 0x1e1f, + 0x1e21, 0x1e21, 0x1e23, 0x1e23, 0x1e25, 0x1e25, 0x1e27, 0x1e27, + 0x1e29, 0x1e29, 0x1e2b, 0x1e2b, 0x1e2d, 0x1e2d, 0x1e2f, 0x1e2f, + 0x1e31, 0x1e31, 0x1e33, 0x1e33, 0x1e35, 0x1e35, 0x1e37, 0x1e37, + 0x1e39, 0x1e39, 0x1e3b, 0x1e3b, 0x1e3d, 0x1e3d, 0x1e3f, 0x1e3f, + 0x1e41, 0x1e41, 0x1e43, 0x1e43, 0x1e45, 0x1e45, 0x1e47, 0x1e47, + 0x1e49, 0x1e49, 0x1e4b, 0x1e4b, 0x1e4d, 0x1e4d, 0x1e4f, 0x1e4f, + 0x1e51, 0x1e51, 0x1e53, 0x1e53, 0x1e55, 0x1e55, 0x1e57, 0x1e57, + 0x1e59, 0x1e59, 0x1e5b, 0x1e5b, 0x1e5d, 0x1e5d, 0x1e5f, 0x1e5f, + 0x1e61, 0x1e61, 0x1e63, 0x1e63, 0x1e65, 0x1e65, 0x1e67, 0x1e67, + 0x1e69, 0x1e69, 0x1e6b, 0x1e6b, 0x1e6d, 0x1e6d, 0x1e6f, 0x1e6f, + 0x1e71, 0x1e71, 0x1e73, 0x1e73, 0x1e75, 0x1e75, 0x1e77, 0x1e77, + 0x1e79, 0x1e79, 0x1e7b, 0x1e7b, 0x1e7d, 0x1e7d, 0x1e7f, 0x1e7f, + 0x1e81, 0x1e81, 0x1e83, 0x1e83, 0x1e85, 0x1e85, 0x1e87, 0x1e87, + 0x1e89, 0x1e89, 0x1e8b, 0x1e8b, 0x1e8d, 0x1e8d, 0x1e8f, 0x1e8f, + 0x1e91, 0x1e91, 0x1e93, 0x1e93, 0x1e95, 0x1e95, 0x1e96, 0x1e97, + 0x1e98, 0x1e99, 0x1e9a, 0x1e61, 0x1e9c, 0x1e9d, 0x1e9e, 0x1e9f, + 0x1ea1, 0x1ea1, 0x1ea3, 0x1ea3, 0x1ea5, 0x1ea5, 0x1ea7, 0x1ea7, + 0x1ea9, 0x1ea9, 0x1eab, 0x1eab, 0x1ead, 0x1ead, 0x1eaf, 0x1eaf, + 0x1eb1, 0x1eb1, 0x1eb3, 0x1eb3, 0x1eb5, 0x1eb5, 0x1eb7, 0x1eb7, + 0x1eb9, 0x1eb9, 0x1ebb, 0x1ebb, 0x1ebd, 0x1ebd, 0x1ebf, 0x1ebf, + 0x1ec1, 0x1ec1, 0x1ec3, 0x1ec3, 0x1ec5, 0x1ec5, 0x1ec7, 0x1ec7, + 0x1ec9, 0x1ec9, 0x1ecb, 0x1ecb, 0x1ecd, 0x1ecd, 0x1ecf, 0x1ecf, + 0x1ed1, 0x1ed1, 0x1ed3, 0x1ed3, 0x1ed5, 0x1ed5, 0x1ed7, 0x1ed7, + 0x1ed9, 0x1ed9, 0x1edb, 0x1edb, 0x1edd, 0x1edd, 0x1edf, 0x1edf, + 0x1ee1, 0x1ee1, 0x1ee3, 0x1ee3, 0x1ee5, 0x1ee5, 0x1ee7, 0x1ee7, + 0x1ee9, 0x1ee9, 0x1eeb, 0x1eeb, 0x1eed, 0x1eed, 0x1eef, 0x1eef, + 0x1ef1, 0x1ef1, 0x1ef3, 0x1ef3, 0x1ef5, 0x1ef5, 0x1ef7, 0x1ef7, + 0x1ef9, 0x1ef9, 0x1efa, 0x1efb, 0x1efc, 0x1efd, 0x1efe, 0x1eff +}}; +static UnicodeCaseTableVector caseTable1f = {{ + 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07, + 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07, + 0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0x1f16, 0x1f17, + 0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0x1f1e, 0x1f1f, + 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27, + 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27, + 0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37, + 0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37, + 0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0x1f46, 0x1f47, + 0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0x1f4e, 0x1f4f, + 0x1f50, 0x1f51, 0x1f52, 0x1f53, 0x1f54, 0x1f55, 0x1f56, 0x1f57, + 0x1f58, 0x1f51, 0x1f5a, 0x1f53, 0x1f5c, 0x1f55, 0x1f5e, 0x1f57, + 0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67, + 0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67, + 0x1f70, 0x1f71, 0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1f76, 0x1f77, + 0x1f78, 0x1f79, 0x1f7a, 0x1f7b, 0x1f7c, 0x1f7d, 0x1f7e, 0x1f7f, + 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87, + 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87, + 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97, + 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97, + 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7, + 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7, + 0x1fb0, 0x1fb1, 0x1fb2, 0x1fb3, 0x1fb4, 0x1fb5, 0x1fb6, 0x1fb7, + 0x1fb0, 0x1fb1, 0x1f70, 0x1f71, 0x1fb3, 0x1fbd, 0x03b9, 0x1fbf, + 0x1fc0, 0x1fc1, 0x1fc2, 0x1fc3, 0x1fc4, 0x1fc5, 0x1fc6, 0x1fc7, + 0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1fc3, 0x1fcd, 0x1fce, 0x1fcf, + 0x1fd0, 0x1fd1, 0x1fd2, 0x1fd3, 0x1fd4, 0x1fd5, 0x1fd6, 0x1fd7, + 0x1fd0, 0x1fd1, 0x1f76, 0x1f77, 0x1fdc, 0x1fdd, 0x1fde, 0x1fdf, + 0x1fe0, 0x1fe1, 0x1fe2, 0x1fe3, 0x1fe4, 0x1fe5, 0x1fe6, 0x1fe7, + 0x1fe0, 0x1fe1, 0x1f7a, 0x1f7b, 0x1fe5, 0x1fed, 0x1fee, 0x1fef, + 0x1ff0, 0x1ff1, 0x1ff2, 0x1ff3, 0x1ff4, 0x1ff5, 0x1ff6, 0x1ff7, + 0x1f78, 0x1f79, 0x1f7c, 0x1f7d, 0x1ff3, 0x1ffd, 0x1ffe, 0x1fff +}}; +static UnicodeCaseTableVector caseTable21 = {{ + 0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107, + 0x2108, 0x2109, 0x210a, 0x210b, 0x210c, 0x210d, 0x210e, 0x210f, + 0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117, + 0x2118, 0x2119, 0x211a, 0x211b, 0x211c, 0x211d, 0x211e, 0x211f, + 0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x03c9, 0x2127, + 0x2128, 0x2129, 0x006b, 0x00e5, 0x212c, 0x212d, 0x212e, 0x212f, + 0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137, + 0x2138, 0x2139, 0x213a, 0x213b, 0x213c, 0x213d, 0x213e, 0x213f, + 0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147, + 0x2148, 0x2149, 0x214a, 0x214b, 0x214c, 0x214d, 0x214e, 0x214f, + 0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, + 0x2158, 0x2159, 0x215a, 0x215b, 0x215c, 0x215d, 0x215e, 0x215f, + 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, + 0x2178, 0x2179, 0x217a, 0x217b, 0x217c, 0x217d, 0x217e, 0x217f, + 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, + 0x2178, 0x2179, 0x217a, 0x217b, 0x217c, 0x217d, 0x217e, 0x217f, + 0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187, + 0x2188, 0x2189, 0x218a, 0x218b, 0x218c, 0x218d, 0x218e, 0x218f, + 0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197, + 0x2198, 0x2199, 0x219a, 0x219b, 0x219c, 0x219d, 0x219e, 0x219f, + 0x21a0, 0x21a1, 0x21a2, 0x21a3, 0x21a4, 0x21a5, 0x21a6, 0x21a7, + 0x21a8, 0x21a9, 0x21aa, 0x21ab, 0x21ac, 0x21ad, 0x21ae, 0x21af, + 0x21b0, 0x21b1, 0x21b2, 0x21b3, 0x21b4, 0x21b5, 0x21b6, 0x21b7, + 0x21b8, 0x21b9, 0x21ba, 0x21bb, 0x21bc, 0x21bd, 0x21be, 0x21bf, + 0x21c0, 0x21c1, 0x21c2, 0x21c3, 0x21c4, 0x21c5, 0x21c6, 0x21c7, + 0x21c8, 0x21c9, 0x21ca, 0x21cb, 0x21cc, 0x21cd, 0x21ce, 0x21cf, + 0x21d0, 0x21d1, 0x21d2, 0x21d3, 0x21d4, 0x21d5, 0x21d6, 0x21d7, + 0x21d8, 0x21d9, 0x21da, 0x21db, 0x21dc, 0x21dd, 0x21de, 0x21df, + 0x21e0, 0x21e1, 0x21e2, 0x21e3, 0x21e4, 0x21e5, 0x21e6, 0x21e7, + 0x21e8, 0x21e9, 0x21ea, 0x21eb, 0x21ec, 0x21ed, 0x21ee, 0x21ef, + 0x21f0, 0x21f1, 0x21f2, 0x21f3, 0x21f4, 0x21f5, 0x21f6, 0x21f7, + 0x21f8, 0x21f9, 0x21fa, 0x21fb, 0x21fc, 0x21fd, 0x21fe, 0x21ff +}}; +static UnicodeCaseTableVector caseTable24 = {{ + 0x2400, 0x2401, 0x2402, 0x2403, 0x2404, 0x2405, 0x2406, 0x2407, + 0x2408, 0x2409, 0x240a, 0x240b, 0x240c, 0x240d, 0x240e, 0x240f, + 0x2410, 0x2411, 0x2412, 0x2413, 0x2414, 0x2415, 0x2416, 0x2417, + 0x2418, 0x2419, 0x241a, 0x241b, 0x241c, 0x241d, 0x241e, 0x241f, + 0x2420, 0x2421, 0x2422, 0x2423, 0x2424, 0x2425, 0x2426, 0x2427, + 0x2428, 0x2429, 0x242a, 0x242b, 0x242c, 0x242d, 0x242e, 0x242f, + 0x2430, 0x2431, 0x2432, 0x2433, 0x2434, 0x2435, 0x2436, 0x2437, + 0x2438, 0x2439, 0x243a, 0x243b, 0x243c, 0x243d, 0x243e, 0x243f, + 0x2440, 0x2441, 0x2442, 0x2443, 0x2444, 0x2445, 0x2446, 0x2447, + 0x2448, 0x2449, 0x244a, 0x244b, 0x244c, 0x244d, 0x244e, 0x244f, + 0x2450, 0x2451, 0x2452, 0x2453, 0x2454, 0x2455, 0x2456, 0x2457, + 0x2458, 0x2459, 0x245a, 0x245b, 0x245c, 0x245d, 0x245e, 0x245f, + 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467, + 0x2468, 0x2469, 0x246a, 0x246b, 0x246c, 0x246d, 0x246e, 0x246f, + 0x2470, 0x2471, 0x2472, 0x2473, 0x2474, 0x2475, 0x2476, 0x2477, + 0x2478, 0x2479, 0x247a, 0x247b, 0x247c, 0x247d, 0x247e, 0x247f, + 0x2480, 0x2481, 0x2482, 0x2483, 0x2484, 0x2485, 0x2486, 0x2487, + 0x2488, 0x2489, 0x248a, 0x248b, 0x248c, 0x248d, 0x248e, 0x248f, + 0x2490, 0x2491, 0x2492, 0x2493, 0x2494, 0x2495, 0x2496, 0x2497, + 0x2498, 0x2499, 0x249a, 0x249b, 0x249c, 0x249d, 0x249e, 0x249f, + 0x24a0, 0x24a1, 0x24a2, 0x24a3, 0x24a4, 0x24a5, 0x24a6, 0x24a7, + 0x24a8, 0x24a9, 0x24aa, 0x24ab, 0x24ac, 0x24ad, 0x24ae, 0x24af, + 0x24b0, 0x24b1, 0x24b2, 0x24b3, 0x24b4, 0x24b5, 0x24d0, 0x24d1, + 0x24d2, 0x24d3, 0x24d4, 0x24d5, 0x24d6, 0x24d7, 0x24d8, 0x24d9, + 0x24da, 0x24db, 0x24dc, 0x24dd, 0x24de, 0x24df, 0x24e0, 0x24e1, + 0x24e2, 0x24e3, 0x24e4, 0x24e5, 0x24e6, 0x24e7, 0x24e8, 0x24e9, + 0x24d0, 0x24d1, 0x24d2, 0x24d3, 0x24d4, 0x24d5, 0x24d6, 0x24d7, + 0x24d8, 0x24d9, 0x24da, 0x24db, 0x24dc, 0x24dd, 0x24de, 0x24df, + 0x24e0, 0x24e1, 0x24e2, 0x24e3, 0x24e4, 0x24e5, 0x24e6, 0x24e7, + 0x24e8, 0x24e9, 0x24ea, 0x24eb, 0x24ec, 0x24ed, 0x24ee, 0x24ef, + 0x24f0, 0x24f1, 0x24f2, 0x24f3, 0x24f4, 0x24f5, 0x24f6, 0x24f7, + 0x24f8, 0x24f9, 0x24fa, 0x24fb, 0x24fc, 0x24fd, 0x24fe, 0x24ff +}}; +static UnicodeCaseTableVector caseTableff = {{ + 0xff00, 0xff01, 0xff02, 0xff03, 0xff04, 0xff05, 0xff06, 0xff07, + 0xff08, 0xff09, 0xff0a, 0xff0b, 0xff0c, 0xff0d, 0xff0e, 0xff0f, + 0xff10, 0xff11, 0xff12, 0xff13, 0xff14, 0xff15, 0xff16, 0xff17, + 0xff18, 0xff19, 0xff1a, 0xff1b, 0xff1c, 0xff1d, 0xff1e, 0xff1f, + 0xff20, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47, + 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f, + 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57, + 0xff58, 0xff59, 0xff5a, 0xff3b, 0xff3c, 0xff3d, 0xff3e, 0xff3f, + 0xff40, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47, + 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f, + 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57, + 0xff58, 0xff59, 0xff5a, 0xff5b, 0xff5c, 0xff5d, 0xff5e, 0xff5f, + 0xff60, 0xff61, 0xff62, 0xff63, 0xff64, 0xff65, 0xff66, 0xff67, + 0xff68, 0xff69, 0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f, + 0xff70, 0xff71, 0xff72, 0xff73, 0xff74, 0xff75, 0xff76, 0xff77, + 0xff78, 0xff79, 0xff7a, 0xff7b, 0xff7c, 0xff7d, 0xff7e, 0xff7f, + 0xff80, 0xff81, 0xff82, 0xff83, 0xff84, 0xff85, 0xff86, 0xff87, + 0xff88, 0xff89, 0xff8a, 0xff8b, 0xff8c, 0xff8d, 0xff8e, 0xff8f, + 0xff90, 0xff91, 0xff92, 0xff93, 0xff94, 0xff95, 0xff96, 0xff97, + 0xff98, 0xff99, 0xff9a, 0xff9b, 0xff9c, 0xff9d, 0xff9e, 0xff9f, + 0xffa0, 0xffa1, 0xffa2, 0xffa3, 0xffa4, 0xffa5, 0xffa6, 0xffa7, + 0xffa8, 0xffa9, 0xffaa, 0xffab, 0xffac, 0xffad, 0xffae, 0xffaf, + 0xffb0, 0xffb1, 0xffb2, 0xffb3, 0xffb4, 0xffb5, 0xffb6, 0xffb7, + 0xffb8, 0xffb9, 0xffba, 0xffbb, 0xffbc, 0xffbd, 0xffbe, 0xffbf, + 0xffc0, 0xffc1, 0xffc2, 0xffc3, 0xffc4, 0xffc5, 0xffc6, 0xffc7, + 0xffc8, 0xffc9, 0xffca, 0xffcb, 0xffcc, 0xffcd, 0xffce, 0xffcf, + 0xffd0, 0xffd1, 0xffd2, 0xffd3, 0xffd4, 0xffd5, 0xffd6, 0xffd7, + 0xffd8, 0xffd9, 0xffda, 0xffdb, 0xffdc, 0xffdd, 0xffde, 0xffdf, + 0xffe0, 0xffe1, 0xffe2, 0xffe3, 0xffe4, 0xffe5, 0xffe6, 0xffe7, + 0xffe8, 0xffe9, 0xffea, 0xffeb, 0xffec, 0xffed, 0xffee, 0xffef, + 0xfff0, 0xfff1, 0xfff2, 0xfff3, 0xfff4, 0xfff5, 0xfff6, 0xfff7, + 0xfff8, 0xfff9, 0xfffa, 0xfffb, 0xfffc, 0xfffd, 0xfffe, 0xffff +}}; +static UnicodeCaseTableVector *caseTable[256] = { + &caseTable00, + &caseTable01, + &caseTable02, + &caseTable03, + &caseTable04, + &caseTable05, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &caseTable1e, + &caseTable1f, + NULL, + &caseTable21, + NULL, + NULL, + &caseTable24, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &caseTableff +}; + +static inline char getType(Unicode c) { + int i; + char type; + + if (c > 0xffff) { + type = 'X'; + } else { + i = (c >> 8) & 0xff; + if ((type = typeTable[i].type) == 'X') { + type = typeTable[i].vector[c & 0xff]; + } + } + return type; +} + +GBool unicodeTypeL(Unicode c) { + return getType(c) == 'L'; +} + +GBool unicodeTypeR(Unicode c) { + return getType(c) == 'R'; +} + +Unicode unicodeToUpper(Unicode c) { + int i; + + if (c > 0xffff) { + return c; + } + i = (c >> 8) & 0xff; + if (caseTable[i]) { + return caseTable[i]->codes[c & 0xff]; + } + return c; +} + diff --git a/kpdf/xpdf/xpdf/UnicodeTypeTable.h b/kpdf/xpdf/xpdf/UnicodeTypeTable.h new file mode 100644 index 00000000..7103dbdd --- /dev/null +++ b/kpdf/xpdf/xpdf/UnicodeTypeTable.h @@ -0,0 +1,20 @@ +//======================================================================== +// +// UnicodeTypeTable.h +// +// Copyright 2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef UNICODETYPETABLE_H +#define UNICODETYPETABLE_H + +#include "gtypes.h" + +extern GBool unicodeTypeL(Unicode c); + +extern GBool unicodeTypeR(Unicode c); + +extern Unicode unicodeToUpper(Unicode c); + +#endif diff --git a/kpdf/xpdf/xpdf/XRef.cc b/kpdf/xpdf/xpdf/XRef.cc new file mode 100644 index 00000000..d12d812f --- /dev/null +++ b/kpdf/xpdf/xpdf/XRef.cc @@ -0,0 +1,917 @@ +//======================================================================== +// +// XRef.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include +#include "gmem.h" +#include "Object.h" +#include "Stream.h" +#include "Lexer.h" +#include "Parser.h" +#include "Dict.h" +#include "Error.h" +#include "ErrorCodes.h" +#include "XRef.h" + +//------------------------------------------------------------------------ + +#define xrefSearchSize 1024 // read this many bytes at end of file + // to look for 'startxref' + +//------------------------------------------------------------------------ +// Permission bits +//------------------------------------------------------------------------ + +#define permPrint (1<<2) +#define permChange (1<<3) +#define permCopy (1<<4) +#define permNotes (1<<5) +#define defPermFlags 0xfffc + +//------------------------------------------------------------------------ +// ObjectStream +//------------------------------------------------------------------------ + +class ObjectStream { +public: + + // Create an object stream, using object number , + // generation 0. + ObjectStream(XRef *xref, int objStrNumA); + + ~ObjectStream(); + + // Return the object number of this object stream. + int getObjStrNum() { return objStrNum; } + + // Get the th object from this stream, which should be + // object number , generation 0. + Object *getObject(int objIdx, int objNum, Object *obj); + +private: + + int objStrNum; // object number of the object stream + int nObjects; // number of objects in the stream + Object *objs; // the objects (length = nObjects) + int *objNums; // the object numbers (length = nObjects) +}; + +ObjectStream::ObjectStream(XRef *xref, int objStrNumA) { + Stream *str; + Parser *parser; + int *offsets; + Object objStr, obj1, obj2; + int first, i; + + objStrNum = objStrNumA; + nObjects = 0; + objs = NULL; + objNums = NULL; + + if (!xref->fetch(objStrNum, 0, &objStr)->isStream()) { + goto err1; + } + + if (!objStr.streamGetDict()->lookup("N", &obj1)->isInt()) { + obj1.free(); + goto err1; + } + nObjects = obj1.getInt(); + obj1.free(); + if (nObjects <= 0) { + goto err1; + } + + if (!objStr.streamGetDict()->lookup("First", &obj1)->isInt()) { + obj1.free(); + goto err1; + } + first = obj1.getInt(); + obj1.free(); + if (first < 0) { + goto err1; + } + + objs = new Object[nObjects]; + objNums = (int *)gmallocn(nObjects, sizeof(int)); + offsets = (int *)gmallocn(nObjects, sizeof(int)); + + // parse the header: object numbers and offsets + objStr.streamReset(); + obj1.initNull(); + str = new EmbedStream(objStr.getStream(), &obj1, gTrue, first); + parser = new Parser(xref, new Lexer(xref, str), gFalse); + for (i = 0; i < nObjects; ++i) { + parser->getObj(&obj1); + parser->getObj(&obj2); + if (!obj1.isInt() || !obj2.isInt()) { + obj1.free(); + obj2.free(); + delete parser; + gfree(offsets); + goto err1; + } + objNums[i] = obj1.getInt(); + offsets[i] = obj2.getInt(); + obj1.free(); + obj2.free(); + if (objNums[i] < 0 || offsets[i] < 0 || + (i > 0 && offsets[i] < offsets[i-1])) { + delete parser; + gfree(offsets); + goto err1; + } + } + while (str->getChar() != EOF) ; + delete parser; + + // skip to the first object - this shouldn't be necessary because + // the First key is supposed to be equal to offsets[0], but just in + // case... + for (i = first; i < offsets[0]; ++i) { + objStr.getStream()->getChar(); + } + + // parse the objects + for (i = 0; i < nObjects; ++i) { + obj1.initNull(); + if (i == nObjects - 1) { + str = new EmbedStream(objStr.getStream(), &obj1, gFalse, 0); + } else { + str = new EmbedStream(objStr.getStream(), &obj1, gTrue, + offsets[i+1] - offsets[i]); + } + parser = new Parser(xref, new Lexer(xref, str), gFalse); + parser->getObj(&objs[i]); + while (str->getChar() != EOF) ; + delete parser; + } + + gfree(offsets); + + err1: + objStr.free(); + return; +} + +ObjectStream::~ObjectStream() { + int i; + + if (objs) { + for (i = 0; i < nObjects; ++i) { + objs[i].free(); + } + delete[] objs; + } + gfree(objNums); +} + +Object *ObjectStream::getObject(int objIdx, int objNum, Object *obj) { + if (objIdx < 0 || objIdx >= nObjects || objNum != objNums[objIdx]) { + return obj->initNull(); + } + return objs[objIdx].copy(obj); +} + +//------------------------------------------------------------------------ +// XRef +//------------------------------------------------------------------------ + +XRef::XRef(BaseStream *strA) { + Guint pos; + Object obj; + + ok = gTrue; + errCode = errNone; + size = 0; + entries = NULL; + streamEnds = NULL; + streamEndsLen = 0; + objStr = NULL; + + encrypted = gFalse; + permFlags = defPermFlags; + ownerPasswordOk = gFalse; + + // read the trailer + str = strA; + start = str->getStart(); + pos = getStartXref(); + + // if there was a problem with the 'startxref' position, try to + // reconstruct the xref table + if (pos == 0) { + if (!(ok = constructXRef())) { + errCode = errDamaged; + return; + } + + // read the xref table + } else { + while (readXRef(&pos)) ; + + // if there was a problem with the xref table, + // try to reconstruct it + if (!ok) { + if (!(ok = constructXRef())) { + errCode = errDamaged; + return; + } + } + } + + // get the root dictionary (catalog) object + trailerDict.dictLookupNF("Root", &obj); + if (obj.isRef()) { + rootNum = obj.getRefNum(); + rootGen = obj.getRefGen(); + obj.free(); + } else { + obj.free(); + if (!(ok = constructXRef())) { + errCode = errDamaged; + return; + } + } + + // now set the trailer dictionary's xref pointer so we can fetch + // indirect objects from it + trailerDict.getDict()->setXRef(this); +} + +XRef::~XRef() { + gfree(entries); + trailerDict.free(); + if (streamEnds) { + gfree(streamEnds); + } + if (objStr) { + delete objStr; + } +} + +// Read the 'startxref' position. +Guint XRef::getStartXref() { + char buf[xrefSearchSize+1]; + char *p; + int c, n, i; + + // read last xrefSearchSize bytes + str->setPos(xrefSearchSize, -1); + for (n = 0; n < xrefSearchSize; ++n) { + if ((c = str->getChar()) == EOF) { + break; + } + buf[n] = c; + } + buf[n] = '\0'; + + // find startxref + for (i = n - 9; i >= 0; --i) { + if (!strncmp(&buf[i], "startxref", 9)) { + break; + } + } + if (i < 0) { + return 0; + } + for (p = &buf[i+9]; isspace(*p); ++p) ; + lastXRefPos = strToUnsigned(p); + + return lastXRefPos; +} + +// Read one xref table section. Also reads the associated trailer +// dictionary, and returns the prev pointer (if any). +GBool XRef::readXRef(Guint *pos) { + Parser *parser; + Object obj; + GBool more; + + // start up a parser, parse one token + obj.initNull(); + parser = new Parser(NULL, + new Lexer(NULL, + str->makeSubStream(start + *pos, gFalse, 0, &obj)), + gTrue); + parser->getObj(&obj); + + // parse an old-style xref table + if (obj.isCmd("xref")) { + obj.free(); + more = readXRefTable(parser, pos); + + // parse an xref stream + } else if (obj.isInt()) { + obj.free(); + if (!parser->getObj(&obj)->isInt()) { + goto err1; + } + obj.free(); + if (!parser->getObj(&obj)->isCmd("obj")) { + goto err1; + } + obj.free(); + if (!parser->getObj(&obj)->isStream()) { + goto err1; + } + more = readXRefStream(obj.getStream(), pos); + obj.free(); + + } else { + goto err1; + } + + delete parser; + return more; + + err1: + obj.free(); + delete parser; + ok = gFalse; + return gFalse; +} + +GBool XRef::readXRefTable(Parser *parser, Guint *pos) { + XRefEntry entry; + GBool more; + Object obj, obj2; + Guint pos2; + int first, n, newSize, i; + + while (1) { + parser->getObj(&obj); + if (obj.isCmd("trailer")) { + obj.free(); + break; + } + if (!obj.isInt()) { + goto err1; + } + first = obj.getInt(); + obj.free(); + if (!parser->getObj(&obj)->isInt()) { + goto err1; + } + n = obj.getInt(); + obj.free(); + if (first < 0 || n < 0 || first + n < 0) { + goto err1; + } + if (first + n > size) { + for (newSize = size ? 2 * size : 1024; + first + n > newSize && newSize > 0; + newSize <<= 1) ; + if (newSize < 0) { + goto err1; + } + entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry)); + for (i = size; i < newSize; ++i) { + entries[i].offset = 0xffffffff; + entries[i].type = xrefEntryFree; + } + size = newSize; + } + for (i = first; i < first + n; ++i) { + if (!parser->getObj(&obj)->isInt()) { + goto err1; + } + entry.offset = (Guint)obj.getInt(); + obj.free(); + if (!parser->getObj(&obj)->isInt()) { + goto err1; + } + entry.gen = obj.getInt(); + obj.free(); + parser->getObj(&obj); + if (obj.isCmd("n")) { + entry.type = xrefEntryUncompressed; + } else if (obj.isCmd("f")) { + entry.type = xrefEntryFree; + } else { + goto err1; + } + obj.free(); + if (entries[i].offset == 0xffffffff) { + entries[i] = entry; + // PDF files of patents from the IBM Intellectual Property + // Network have a bug: the xref table claims to start at 1 + // instead of 0. + if (i == 1 && first == 1 && + entries[1].offset == 0 && entries[1].gen == 65535 && + entries[1].type == xrefEntryFree) { + i = first = 0; + entries[0] = entries[1]; + entries[1].offset = 0xffffffff; + } + } + } + } + + // read the trailer dictionary + if (!parser->getObj(&obj)->isDict()) { + goto err1; + } + + // get the 'Prev' pointer + obj.getDict()->lookupNF("Prev", &obj2); + if (obj2.isInt()) { + *pos = (Guint)obj2.getInt(); + more = gTrue; + } else if (obj2.isRef()) { + // certain buggy PDF generators generate "/Prev NNN 0 R" instead + // of "/Prev NNN" + *pos = (Guint)obj2.getRefNum(); + more = gTrue; + } else { + more = gFalse; + } + obj2.free(); + + // save the first trailer dictionary + if (trailerDict.isNone()) { + obj.copy(&trailerDict); + } + + // check for an 'XRefStm' key + if (obj.getDict()->lookup("XRefStm", &obj2)->isInt()) { + pos2 = (Guint)obj2.getInt(); + readXRef(&pos2); + if (!ok) { + obj2.free(); + goto err1; + } + } + obj2.free(); + + obj.free(); + return more; + + err1: + obj.free(); + ok = gFalse; + return gFalse; +} + +GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) { + Dict *dict; + int w[3]; + GBool more; + Object obj, obj2, idx; + int newSize, first, n, i; + + dict = xrefStr->getDict(); + + if (!dict->lookupNF("Size", &obj)->isInt()) { + goto err1; + } + newSize = obj.getInt(); + obj.free(); + if (newSize < 0) { + goto err1; + } + if (newSize > size) { + entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry)); + for (i = size; i < newSize; ++i) { + entries[i].offset = 0xffffffff; + entries[i].type = xrefEntryFree; + } + size = newSize; + } + + if (!dict->lookupNF("W", &obj)->isArray() || + obj.arrayGetLength() < 3) { + goto err1; + } + for (i = 0; i < 3; ++i) { + if (!obj.arrayGet(i, &obj2)->isInt()) { + obj2.free(); + goto err1; + } + w[i] = obj2.getInt(); + obj2.free(); + if (w[i] < 0 || w[i] > 4) { + goto err1; + } + } + obj.free(); + + xrefStr->reset(); + dict->lookupNF("Index", &idx); + if (idx.isArray()) { + for (i = 0; i+1 < idx.arrayGetLength(); i += 2) { + if (!idx.arrayGet(i, &obj)->isInt()) { + idx.free(); + goto err1; + } + first = obj.getInt(); + obj.free(); + if (!idx.arrayGet(i+1, &obj)->isInt()) { + idx.free(); + goto err1; + } + n = obj.getInt(); + obj.free(); + if (first < 0 || n < 0 || + !readXRefStreamSection(xrefStr, w, first, n)) { + idx.free(); + goto err0; + } + } + } else { + if (!readXRefStreamSection(xrefStr, w, 0, newSize)) { + idx.free(); + goto err0; + } + } + idx.free(); + + dict->lookupNF("Prev", &obj); + if (obj.isInt()) { + *pos = (Guint)obj.getInt(); + more = gTrue; + } else { + more = gFalse; + } + obj.free(); + if (trailerDict.isNone()) { + trailerDict.initDict(dict); + } + + return more; + + err1: + obj.free(); + err0: + ok = gFalse; + return gFalse; +} + +GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) { + Guint offset; + int type, gen, c, newSize, i, j; + + if (first + n < 0) { + return gFalse; + } + if (first + n > size) { + for (newSize = size ? 2 * size : 1024; + first + n > newSize && newSize > 0; + newSize <<= 1) ; + if (newSize < 0) { + return gFalse; + } + entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry)); + for (i = size; i < newSize; ++i) { + entries[i].offset = 0xffffffff; + entries[i].type = xrefEntryFree; + } + size = newSize; + } + for (i = first; i < first + n; ++i) { + if (w[0] == 0) { + type = 1; + } else { + for (type = 0, j = 0; j < w[0]; ++j) { + if ((c = xrefStr->getChar()) == EOF) { + return gFalse; + } + type = (type << 8) + c; + } + } + for (offset = 0, j = 0; j < w[1]; ++j) { + if ((c = xrefStr->getChar()) == EOF) { + return gFalse; + } + offset = (offset << 8) + c; + } + for (gen = 0, j = 0; j < w[2]; ++j) { + if ((c = xrefStr->getChar()) == EOF) { + return gFalse; + } + gen = (gen << 8) + c; + } + if (entries[i].offset == 0xffffffff) { + switch (type) { + case 0: + entries[i].offset = offset; + entries[i].gen = gen; + entries[i].type = xrefEntryFree; + break; + case 1: + entries[i].offset = offset; + entries[i].gen = gen; + entries[i].type = xrefEntryUncompressed; + break; + case 2: + entries[i].offset = offset; + entries[i].gen = gen; + entries[i].type = xrefEntryCompressed; + break; + default: + return gFalse; + } + } + } + + return gTrue; +} + +// Attempt to construct an xref table for a damaged file. +GBool XRef::constructXRef() { + Parser *parser; + Object newTrailerDict, obj; + char buf[256]; + Guint pos; + int num, gen; + int newSize; + int streamEndsSize; + char *p; + int i; + GBool gotRoot; + + gfree(entries); + size = 0; + entries = NULL; + + error(-1, "PDF file is damaged - attempting to reconstruct xref table..."); + gotRoot = gFalse; + streamEndsLen = streamEndsSize = 0; + + str->reset(); + while (1) { + pos = str->getPos(); + if (!str->getLine(buf, 256)) { + break; + } + p = buf; + + // skip whitespace + while (*p && Lexer::isSpace(*p & 0xff)) ++p; + + // got trailer dictionary + if (!strncmp(p, "trailer", 7)) { + obj.initNull(); + parser = new Parser(NULL, + new Lexer(NULL, + str->makeSubStream(pos + 7, gFalse, 0, &obj)), + gFalse); + parser->getObj(&newTrailerDict); + if (newTrailerDict.isDict()) { + newTrailerDict.dictLookupNF("Root", &obj); + if (obj.isRef()) { + rootNum = obj.getRefNum(); + rootGen = obj.getRefGen(); + if (!trailerDict.isNone()) { + trailerDict.free(); + } + newTrailerDict.copy(&trailerDict); + gotRoot = gTrue; + } + obj.free(); + } + newTrailerDict.free(); + delete parser; + + // look for object + } else if (isdigit(*p)) { + num = atoi(p); + if (num > 0) { + do { + ++p; + } while (*p && isdigit(*p)); + if (isspace(*p)) { + do { + ++p; + } while (*p && isspace(*p)); + if (isdigit(*p)) { + gen = atoi(p); + do { + ++p; + } while (*p && isdigit(*p)); + if (isspace(*p)) { + do { + ++p; + } while (*p && isspace(*p)); + if (!strncmp(p, "obj", 3)) { + if (num >= size) { + newSize = (num + 1 + 255) & ~255; + if (newSize < 0) { + error(-1, "Bad object number"); + return gFalse; + } + entries = (XRefEntry *) + greallocn(entries, newSize, sizeof(XRefEntry)); + for (i = size; i < newSize; ++i) { + entries[i].offset = 0xffffffff; + entries[i].type = xrefEntryFree; + } + size = newSize; + } + if (entries[num].type == xrefEntryFree || + gen >= entries[num].gen) { + entries[num].offset = pos - start; + entries[num].gen = gen; + entries[num].type = xrefEntryUncompressed; + } + } + } + } + } + } + + } else if (!strncmp(p, "endstream", 9)) { + if (streamEndsLen == streamEndsSize) { + streamEndsSize += 64; + streamEnds = (Guint *)greallocn(streamEnds, + streamEndsSize, sizeof(int)); + } + streamEnds[streamEndsLen++] = pos; + } + } + + if (gotRoot) + return gTrue; + + error(-1, "Couldn't find trailer dictionary"); + return gFalse; +} + +void XRef::setEncryption(int permFlagsA, GBool ownerPasswordOkA, + Guchar *fileKeyA, int keyLengthA, int encVersionA, + CryptAlgorithm encAlgorithmA) { + int i; + + encrypted = gTrue; + permFlags = permFlagsA; + ownerPasswordOk = ownerPasswordOkA; + if (keyLengthA <= 16) { + keyLength = keyLengthA; + } else { + keyLength = 16; + } + for (i = 0; i < keyLength; ++i) { + fileKey[i] = fileKeyA[i]; + } + encVersion = encVersionA; + encAlgorithm = encAlgorithmA; +} + +GBool XRef::okToPrint(GBool ignoreOwnerPW) { + return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permPrint); +} + +GBool XRef::okToChange(GBool ignoreOwnerPW) { + return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permChange); +} + +GBool XRef::okToCopy(GBool ignoreOwnerPW) { + return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permCopy); +} + +GBool XRef::okToAddNotes(GBool ignoreOwnerPW) { + return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permNotes); +} + +Object *XRef::fetch(int num, int gen, Object *obj) { + XRefEntry *e; + Parser *parser; + Object obj1, obj2, obj3; + + // check for bogus ref - this can happen in corrupted PDF files + if (num < 0 || num >= size) { + goto err; + } + + e = &entries[num]; + switch (e->type) { + + case xrefEntryUncompressed: + if (e->gen != gen) { + goto err; + } + obj1.initNull(); + parser = new Parser(this, + new Lexer(this, + str->makeSubStream(start + e->offset, gFalse, 0, &obj1)), + gTrue); + parser->getObj(&obj1); + parser->getObj(&obj2); + parser->getObj(&obj3); + if (!obj1.isInt() || obj1.getInt() != num || + !obj2.isInt() || obj2.getInt() != gen || + !obj3.isCmd("obj")) { + obj1.free(); + obj2.free(); + obj3.free(); + delete parser; + goto err; + } + parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, + encAlgorithm, keyLength, num, gen); + obj1.free(); + obj2.free(); + obj3.free(); + delete parser; + break; + + case xrefEntryCompressed: + if (gen != 0) { + goto err; + } + if (!objStr || objStr->getObjStrNum() != (int)e->offset) { + if (objStr) { + delete objStr; + } + objStr = new ObjectStream(this, e->offset); + } + objStr->getObject(e->gen, num, obj); + break; + + default: + goto err; + } + + return obj; + + err: + return obj->initNull(); +} + +Object *XRef::getDocInfo(Object *obj) { + return trailerDict.dictLookup("Info", obj); +} + +// Added for the pdftex project. +Object *XRef::getDocInfoNF(Object *obj) { + return trailerDict.dictLookupNF("Info", obj); +} + +GBool XRef::getStreamEnd(Guint streamStart, Guint *streamEnd) { + int a, b, m; + + if (streamEndsLen == 0 || + streamStart > streamEnds[streamEndsLen - 1]) { + return gFalse; + } + + a = -1; + b = streamEndsLen - 1; + // invariant: streamEnds[a] < streamStart <= streamEnds[b] + while (b - a > 1) { + m = (a + b) / 2; + if (streamStart <= streamEnds[m]) { + b = m; + } else { + a = m; + } + } + *streamEnd = streamEnds[b]; + return gTrue; +} + +int XRef::getNumEntry(Guint offset) const +{ + if (size > 0) + { + int res = 0; + Guint resOffset = entries[0].offset; + XRefEntry e; + for (int i = 1; i < size; ++i) + { + e = entries[i]; + if (e.offset < offset && e.offset >= resOffset) + { + res = i; + resOffset = e.offset; + } + } + return res; + } + else return -1; +} + +Guint XRef::strToUnsigned(char *s) { + Guint x; + char *p; + int i; + + x = 0; + for (p = s, i = 0; *p && isdigit(*p) && i < 10; ++p, ++i) { + x = 10 * x + (*p - '0'); + } + return x; +} diff --git a/kpdf/xpdf/xpdf/XRef.h b/kpdf/xpdf/xpdf/XRef.h new file mode 100644 index 00000000..68a0e9c5 --- /dev/null +++ b/kpdf/xpdf/xpdf/XRef.h @@ -0,0 +1,136 @@ +//======================================================================== +// +// XRef.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef XREF_H +#define XREF_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "Object.h" + +class Dict; +class Stream; +class Parser; +class ObjectStream; + +//------------------------------------------------------------------------ +// XRef +//------------------------------------------------------------------------ + +enum XRefEntryType { + xrefEntryFree, + xrefEntryUncompressed, + xrefEntryCompressed +}; + +struct XRefEntry { + Guint offset; + int gen; + XRefEntryType type; +}; + +class XRef { +public: + + // Constructor. Read xref table from stream. + XRef(BaseStream *strA); + + // Destructor. + ~XRef(); + + // Is xref table valid? + GBool isOk() { return ok; } + + // Get the error code (if isOk() returns false). + int getErrorCode() { return errCode; } + + // Set the encryption parameters. + void setEncryption(int permFlagsA, GBool ownerPasswordOkA, + Guchar *fileKeyA, int keyLengthA, int encVersionA, + CryptAlgorithm encAlgorithmA); + + // Is the file encrypted? + GBool isEncrypted() { return encrypted; } + + // Check various permissions. + GBool okToPrint(GBool ignoreOwnerPW = gFalse); + GBool okToChange(GBool ignoreOwnerPW = gFalse); + GBool okToCopy(GBool ignoreOwnerPW = gFalse); + GBool okToAddNotes(GBool ignoreOwnerPW = gFalse); + + // Get catalog object. + Object *getCatalog(Object *obj) { return fetch(rootNum, rootGen, obj); } + + // Fetch an indirect reference. + Object *fetch(int num, int gen, Object *obj); + + // Return the document's Info dictionary (if any). + Object *getDocInfo(Object *obj); + Object *getDocInfoNF(Object *obj); + + // Return the number of objects in the xref table. + int getNumObjects() { return size; } + + // Return the offset of the last xref table. + Guint getLastXRefPos() { return lastXRefPos; } + + // Return the catalog object reference. + int getRootNum() { return rootNum; } + int getRootGen() { return rootGen; } + + // Get end position for a stream in a damaged file. + // Returns false if unknown or file is not damaged. + GBool getStreamEnd(Guint streamStart, Guint *streamEnd); + + // Retuns the entry that belongs to the offset + int getNumEntry(Guint offset) const; + + // Direct access. + int getSize() { return size; } + XRefEntry *getEntry(int i) { return &entries[i]; } + Object *getTrailerDict() { return &trailerDict; } + +private: + + BaseStream *str; // input stream + Guint start; // offset in file (to allow for garbage + // at beginning of file) + XRefEntry *entries; // xref entries + int size; // size of array + int rootNum, rootGen; // catalog dict + GBool ok; // true if xref table is valid + int errCode; // error code (if is false) + Object trailerDict; // trailer dictionary + Guint lastXRefPos; // offset of last xref table + Guint *streamEnds; // 'endstream' positions - only used in + // damaged files + int streamEndsLen; // number of valid entries in streamEnds + ObjectStream *objStr; // cached object stream + GBool encrypted; // true if file is encrypted + int permFlags; // permission bits + GBool ownerPasswordOk; // true if owner password is correct + Guchar fileKey[16]; // file decryption key + int keyLength; // length of key, in bytes + int encVersion; // encryption version + CryptAlgorithm encAlgorithm; // encryption algorithm + + Guint getStartXref(); + GBool readXRef(Guint *pos); + GBool readXRefTable(Parser *parser, Guint *pos); + GBool readXRefStreamSection(Stream *xrefStr, int *w, int first, int n); + GBool readXRefStream(Stream *xrefStr, Guint *pos); + GBool constructXRef(); + Guint strToUnsigned(char *s); +}; + +#endif diff --git a/kpdf/xpdf/xpdf/xpdf_config.h b/kpdf/xpdf/xpdf/xpdf_config.h new file mode 100644 index 00000000..81d4dd07 --- /dev/null +++ b/kpdf/xpdf/xpdf/xpdf_config.h @@ -0,0 +1,112 @@ +//======================================================================== +// +// config.h +// +// Copyright 1996-2007 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef CONFIG_H +#define CONFIG_H + +//------------------------------------------------------------------------ +// version +//------------------------------------------------------------------------ + +// xpdf version +#define xpdfVersion "3.02" +#define xpdfVersionNum 3.02 +#define xpdfMajorVersion 3 +#define xpdfMinorVersion 2 +#define xpdfUpdateVersion 0 +#define xpdfMajorVersionStr "3" +#define xpdfMinorVersionStr "2" +#define xpdfUpdateVersionStr "0" + +// supported PDF version +#define supportedPDFVersionStr "1.7" +#define supportedPDFVersionNum 1.7 + +// copyright notice +#define xpdfCopyright "Copyright 1996-2007 Glyph & Cog, LLC" + +// Windows resource file stuff +#define winxpdfVersion "WinXpdf 3.02" +#define xpdfCopyrightAmp "Copyright 1996-2007 Glyph && Cog, LLC" + +//------------------------------------------------------------------------ +// paper size +//------------------------------------------------------------------------ + +// default paper size (in points) for PostScript output +#ifdef A4_PAPER +#define defPaperWidth 595 // ISO A4 (210x297 mm) +#define defPaperHeight 842 +#else +#define defPaperWidth 612 // American letter (8.5x11") +#define defPaperHeight 792 +#endif + +//------------------------------------------------------------------------ +// config file (xpdfrc) path +//------------------------------------------------------------------------ + +// user config file name, relative to the user's home directory +#if defined(VMS) || (defined(WIN32) && !defined(__CYGWIN32__)) +#define xpdfUserConfigFile "xpdfrc" +#else +#define xpdfUserConfigFile ".xpdfrc" +#endif + +// system config file name (set via the configure script) +#ifdef SYSTEM_XPDFRC +#define xpdfSysConfigFile SYSTEM_XPDFRC +#else +// under Windows, we get the directory with the executable and then +// append this file name +#define xpdfSysConfigFile "xpdfrc" +#endif + +//------------------------------------------------------------------------ +// X-related constants +//------------------------------------------------------------------------ + +// default maximum size of color cube to allocate +#define defaultRGBCube 5 + +// number of fonts (combined t1lib, FreeType, X server) to cache +#define xOutFontCacheSize 64 + +// number of Type 3 fonts to cache +#define xOutT3FontCacheSize 8 + +//------------------------------------------------------------------------ +// popen +//------------------------------------------------------------------------ + +#if defined(_MSC_VER) || defined(__BORLANDC__) +#define popen _popen +#define pclose _pclose +#endif + +#if defined(VMS) || defined(VMCMS) || defined(DOS) || defined(OS2) || defined(__EMX__) || defined(WIN32) || defined(__DJGPP__) || defined(MACOS) +#define POPEN_READ_MODE "rb" +#else +#define POPEN_READ_MODE "r" +#endif + +//------------------------------------------------------------------------ +// Win32 stuff +//------------------------------------------------------------------------ + +#ifdef CDECL +#undef CDECL +#endif + +#if defined(_MSC_VER) || defined(__BORLANDC__) +#define CDECL __cdecl +#else +#define CDECL +#endif + +#endif diff --git a/kpovmodeler/AUTHORS b/kpovmodeler/AUTHORS new file mode 100644 index 00000000..5afc7760 --- /dev/null +++ b/kpovmodeler/AUTHORS @@ -0,0 +1,13 @@ +Maintainer, framework, everything: +Andreas Zehender + +Textures: +Luis Passos Carvalho + +Povray 3.5 Objects: +Leon Pennington + +Some graphical objects: +Philippe Van Hecke +Leonardo Skorianez + diff --git a/kpovmodeler/BUGS b/kpovmodeler/BUGS new file mode 100644 index 00000000..7cecd8b3 --- /dev/null +++ b/kpovmodeler/BUGS @@ -0,0 +1,5 @@ +Known bugs in kpovmodeler in version 0.2 +-------- + +None at the moment + diff --git a/kpovmodeler/COPYING b/kpovmodeler/COPYING new file mode 100644 index 00000000..54754ab4 --- /dev/null +++ b/kpovmodeler/COPYING @@ -0,0 +1,341 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +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 give any other recipients of the Program a copy of this License +along with the Program. + +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 Program or any portion +of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +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 Program, 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 Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) 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; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, 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 executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or 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 counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program 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. + + 5. 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 Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. 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 Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program 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 Program. + +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. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program 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. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 Program +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 Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, 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 + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/kpovmodeler/ChangeLog b/kpovmodeler/ChangeLog new file mode 100644 index 00000000..9ad06f1f --- /dev/null +++ b/kpovmodeler/ChangeLog @@ -0,0 +1,83 @@ +Version 0.0.1: + - Development release + - Framework is finished + - Some basic objects and textures + +Version 0.1 + - First release for the public + - Most textures are supported + - All simple objects are supported + - Rendering the scene with povray inside the program + - Textures can be previewed inside the dialog view + - The camera supports now focal blur and all complex projections + - The camera view can render all projections except the omnimax projection + +Version 0.1.1 + - Bugfix release + - Fixed bugs: + - A bug that causes the program to crash during rendering + - A bug that causes the program to hang during auto scroll + - "Revert file" now works + +Version 0.2 + - Ported to Qt 3.0 / KDE 3.0, moved to the kdegraphics package + - Dock widgets + - Qt OpenGL extension removed + - Key navigation in the tree view + - Compressed document format + - Fixed bugs: + - Validation check for the depth edit in the pattern edit + - Texture preview didn't serialize all needed declares + - "File close" follows the style guide + +Version 1.0 + - View layouts + - User documentation + +Version 1.1 + - Plugin framework (work in progress) + - Object and texture library (work in progress) + - new --no-dri command line option and configuration dialog to + disable direct rendering + - First characters of comments are used as description in the tree view + - The user is asked if pending changes should be saved before rendering + - Nicer render speed values + - Empty line before comments in povray output + - Control point selection in the properties view for bicubic patch, + sor, lathe and prism + - Export flag for graphical objects and the camera + - Removed the glut dependency + - Added Heightfield Viewstructure + - Light object gained, parallel, circular and orient options + - Dispersion options added to interior + - Added Noise generator options to global settings and patterns + - New warp types added + - Added accuracy setting to normals + - Added new finish options + - New objects: + - Isosurface + - Sphere sweep + - Projected through + - Radiosity + - Global photons + - Photons + - Light groups + - Interior textures + - Mesh + +Version 1.1.1 + - Added graphical editing to Mesh object + - Updated Media too handle new methods and options + - Added new patterns cells, additional crackle options, julia, + additional mandel options, and slope + - Added keywords no_image, no_reflection, and double_illuminate to + graphical objects + - Added uv mapping and uv vectors + +Version 1.1.2 + - Added local and global detail levels too: + Sphere, Cylinder, Cone, Torus, Disc, Blob Sphere, Blob Cylinder, Lathe, + SOR, Prism, SQE, Sphere sweep and Heightfield. + +Version 1.2 + - The user is asked if pending changes should be saved before saving or exporting diff --git a/kpovmodeler/INSTALL b/kpovmodeler/INSTALL new file mode 100644 index 00000000..02a4a074 --- /dev/null +++ b/kpovmodeler/INSTALL @@ -0,0 +1,167 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes a while. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Type `make install' to install the programs and any data files and + documentation. + + 4. You can remove the program binaries and object files from the + source code directory by typing `make clean'. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + diff --git a/kpovmodeler/Makefile.am b/kpovmodeler/Makefile.am new file mode 100644 index 00000000..4e1f3ef9 --- /dev/null +++ b/kpovmodeler/Makefile.am @@ -0,0 +1,251 @@ + +INCLUDES = $(LIBFREETYPE_CFLAGS) $(all_includes) + +SUBDIRS = pics examples + +KDE_OPTIONS = nofinal + +#### +# common lib + +lib_LTLIBRARIES = libkpovmodeler.la +libkpovmodeler_la_SOURCES = pmpart.cpp pmfactory.cpp \ + pmview.cpp pmshell.cpp pmobjectdrag.cpp \ + pmtreeview.cpp pmmessage.cpp pmtreeviewitem.cpp \ + pmerrordialog.cpp pminsertpopup.cpp pminserterrordialog.cpp \ + pmglview.cpp pmrendermanager.cpp pmobjectselect.cpp \ + pmrendermodesdialog.cpp pmpovrayrenderwidget.cpp pmpovraywidget.cpp \ + pmpovrayoutputwidget.cpp pmsettingsdialog.cpp \ + pmcolorsettings.cpp pmgridsettings.cpp pmlayoutsettings.cpp \ + pmobjectlibrarysettings.cpp pmobjectsettings.cpp pmpluginsettings.cpp \ + pmpovraysettings.cpp pmpreviewsettings.cpp pmopenglsettings.cpp \ + pmdockwidget.cpp pmdockwidget_private.cpp pmviewlayoutmanager.cpp \ + pmviewbase.cpp pmviewfactory.cpp pmunknownview.cpp pmdragwidget.cpp \ + \ + pmprototypemanager.cpp \ + pmobject.cpp pmcompositeobject.cpp \ + pmgraphicalobject.cpp pmsolidobject.cpp \ + pmscene.cpp pmglobalsettings.cpp pmskysphere.cpp pmrainbow.cpp \ + pmfog.cpp pmbox.cpp pmsphere.cpp pmblob.cpp pmblobsphere.cpp \ + pmblobcylinder.cpp pmtext.cpp pmjuliafractal.cpp \ + pmcylinder.cpp pmcone.cpp pmtorus.cpp pmplane.cpp pmpolynom.cpp \ + pmdisc.cpp pmbicubicpatch.cpp pmtriangle.cpp \ + pmlathe.cpp pmprism.cpp pmsor.cpp pmsqe.cpp pmheightfield.cpp \ + pmheightfieldroam.cpp pmcomment.cpp pmraw.cpp pmnamedobject.cpp \ + pmtranslate.cpp pmscale.cpp pmrotate.cpp pmpovraymatrix.cpp \ + pmcsg.cpp pmcamera.cpp pmboundedby.cpp pmclippedby.cpp \ + pmlight.cpp pmlookslike.cpp pmprojectedthrough.cpp\ + pmtexturebase.cpp pmtexture.cpp pmpigment.cpp \ + pmsolidcolor.cpp pmlistpattern.cpp pmquickcolor.cpp \ + pmpattern.cpp pmblendmapmodifiers.cpp pmtexturemap.cpp \ + pmnormal.cpp pmslope.cpp pmwarp.cpp pmfinish.cpp \ + pminterior.cpp pmmedia.cpp pmmaterial.cpp pmmaterialmap.cpp \ + pmdensity.cpp pmimagemap.cpp pmbumpmap.cpp \ + \ + pmisosurface.cpp pmradiosity.cpp pmglobalphotons.cpp \ + pmphotons.cpp pmlightgroup.cpp pminteriortexture.cpp \ + pmspheresweep.cpp pmmesh.cpp pmdetailobject.cpp \ + \ + pmdeclare.cpp pmobjectlink.cpp \ + pmrecursiveobjectiterator.cpp \ + \ + pmaddcommand.cpp pmcommandmanager.cpp pmdatachangecommand.cpp \ + pmdeletecommand.cpp pmmovecommand.cpp \ + \ + pmdialogview.cpp pmdialogeditbase.cpp pmgraphicalobjectedit.cpp \ + pmnamedobjectedit.cpp pmsolidobjectedit.cpp pmskysphereedit.cpp \ + pmglobalsettingsedit.cpp pmrainbowedit.cpp pmfogedit.cpp \ + pmboxedit.cpp pmsphereedit.cpp pmblobedit.cpp pmblobsphereedit.cpp \ + pmblobcylinderedit.cpp pmtextedit.cpp pmjuliafractaledit.cpp \ + pmcylinderedit.cpp pmconeedit.cpp pmtorusedit.cpp pmplaneedit.cpp \ + pmpolynomedit.cpp pmheightfieldedit.cpp \ + pmlatheedit.cpp pmprismedit.cpp pmsoredit.cpp pmsqeedit.cpp \ + pmdiscedit.cpp pmbicubicpatchedit.cpp pmtriangleedit.cpp \ + pmcommentedit.cpp pmrawedit.cpp \ + pmrotateedit.cpp pmscaleedit.cpp pmtranslateedit.cpp \ + pmpovraymatrixedit.cpp \ + pmcsgedit.cpp pmcameraedit.cpp pmlightedit.cpp pmboundedbyedit.cpp \ + pmclippedbyedit.cpp \ + pmlineedits.cpp pmvectorlistedit.cpp pmcoloredit.cpp pmlinkedit.cpp \ + pmvectoredit.cpp pmpalettevalueedit.cpp pmformulalabel.cpp \ + pmtexturebaseedit.cpp pmtextureedit.cpp pmpigmentedit.cpp \ + pmsolidcoloredit.cpp pmlistpatternedit.cpp pmquickcoloredit.cpp \ + pmpatternedit.cpp pmblendmapmodifiersedit.cpp pmimagemapedit.cpp \ + pmtexturemapedit.cpp pmbumpmapedit.cpp pmmaterialmapedit.cpp \ + pmnormaledit.cpp pmslopeedit.cpp pmfinishedit.cpp pmwarpedit.cpp \ + pminterioredit.cpp pmmediaedit.cpp pmmaterialedit.cpp \ + pmdensityedit.cpp pmdeclareedit.cpp pmobjectlinkedit.cpp \ + \ + pmisosurfaceedit.cpp pmradiosityedit.cpp pmglobalphotonsedit.cpp \ + pmphotonsedit.cpp pmlightgroupedit.cpp pminteriortextureedit.cpp \ + pmspheresweepedit.cpp pmmeshedit.cpp pmdetailobjectedit.cpp \ + \ + pmcontrolpoint.cpp pm3dcontrolpoint.cpp pm2dcontrolpoint.cpp \ + pmsorcontrolpoint.cpp pmtranslatecontrolpoint.cpp \ + pmrotatecontrolpoint.cpp pmscalecontrolpoint.cpp \ + pmvectorcontrolpoint.cpp pmdistancecontrolpoint.cpp \ + pmplanenormalcontrolpoint.cpp \ + \ + pmmemento.cpp pmmapmemento.cpp pmsplinememento.cpp pmprismmemento.cpp \ + pmpalettevaluememento.cpp \ + \ + pmiomanager.cpp pmpovrayformat.cpp pmpovray31format.cpp pmpovray35format.cpp \ + pmpovray31serialization.cpp pmpovray35serialization.cpp \ + pmscanner.cpp pmparser.cpp pmxmlparser.cpp pmpovrayparser.cpp \ + pmserializer.cpp pmoutputdevice.cpp pmxmlhelper.cpp \ + pmfiledialog.cpp \ + \ + pmpalettevalue.cpp \ + pmvector.cpp pmmath.cpp pmmatrix.cpp pmviewstructure.cpp pmline.cpp \ + pmcolor.cpp pmpoint.cpp pmsymboltable.cpp pmactions.cpp \ + pmsplinesegment.cpp pmsorsegment.cpp pmpolynomexponents.cpp \ + pmvariant.cpp pmmetaobject.cpp pmenumproperty.cpp pmface.cpp \ + \ + pmrendermode.cpp pmresourcelocator.cpp pmtruetypecache.cpp \ + pmdocumentationmap.cpp pminsertrulesystem.cpp pmlibrarymanager.cpp \ + pmlibraryhandle.cpp pmlibraryhandleedit.cpp pmlibraryobject.cpp \ + pmlibraryentrypreview.cpp\ + pmlibrarybrowser.cpp pmlibraryiconview.cpp pmlibraryobjectsearch.cpp \ + pmpluginmanager.cpp \ + pmpartiface.skel + +libkpovmodeler_la_LDFLAGS = $(all_libraries) -version-info 0:0:0 -no-undefined $(LIBFREETYPE_RPATH) +libkpovmodeler_la_LIBADD = $(LIBFREETYPE_LIBS) $(LIB_KPARTS) $(GLLIB) -lXmu -lXi +METASOURCES = AUTO + +noinst_HEADERS = pmpart.h pmfactory.h pmview.h pmshell.h pmobjectdrag.h \ + pmtreeview.h pmtreeviewitem.h pmmessage.h \ + pmerrordialog.h pminsertpopup.h pminserterrordialog.h \ + pmglview.h pmrendermanager.h pmobjectselect.h \ + pmrendermodesdialog.h pmpovrayrenderwidget.h pmpovraywidget.h \ + pmpovrayoutputwidget.h pmsettingsdialog.h \ + pmcolorsettings.h pmgridsettings.h pmlayoutsettings.h \ + pmobjectlibrarysettings.h pmobjectsettings.h pmpluginsettings.h \ + pmpovraysettings.h pmpreviewsettings.h pmopenglsettings.h \ + pmdockwidget.h pmdockwidget_private.h pmviewlayoutmanager.h \ + pmviewbase.h pmviewfactory.h pmunknownview.h pmdragwidget.h \ + \ + pmprototypemanager.h pmallobjects.h \ + pmobject.h pmcompositeobject.h \ + pmgraphicalobject.h pmsolidobject.h \ + pmscene.h pmglobalsettings.h pmskysphere.h pmrainbow.h \ + pmfog.h pmbox.h pmsphere.h pmblob.h pmblobsphere.h \ + pmblobcylinder.h pmtext.h pmjuliafractal.h \ + pmcylinder.h pmcone.h pmtorus.h pmplane.h pmpolynom.h \ + pmdisc.h pmbicubicpatch.h pmtriangle.h \ + pmlathe.h pmprism.h pmsor.h pmsqe.h pmheightfield.h \ + pmheightfieldroam.h pmcomment.h pmraw.h pmnamedobject.h \ + pmtranslate.h pmscale.h pmrotate.h pmpovraymatrix.h \ + pmcsg.h pmcamera.h pmboundedby.h pmclippedby.h \ + pmlight.h pmlookslike.h pmprojectedthrough.h\ + pmtexturebase.h pmtexture.h pmpigment.h \ + pmsolidcolor.h pmlistpattern.h pmquickcolor.h pmmaterialmap.h \ + pmpattern.h pmblendmapmodifiers.h pmtexturemap.h pmnormal.h \ + pmslope.h pmfinish.h pmwarp.h pminterior.h pmmedia.h pmmaterial.h \ + pmdensity.h pmimagemap.h pmbumpmap.h pmdeclare.h pmobjectlink.h \ + pmrecursiveobjectiterator.h \ + \ + pmisosurface.h pmradiosity.h pmglobalphotons.h \ + pmphotons.h pmlightgroup.h pminteriortexture.h \ + pmspheresweep.h pmmesh.h pmdetailobject.h \ + \ + pmcommand.h pmaddcommand.h pmcommandmanager.h pmdatachangecommand.h \ + pmallcommands.h pmdeletecommand.h pmmovecommand.h \ + \ + pmdialogview.h pmdialogeditbase.h pmgraphicalobjectedit.h \ + pmnamedobjectedit.h pmsolidobjectedit.h pmskysphereedit.h \ + pmglobalsettingsedit.h pmrainbowedit.h pmfogedit.h \ + pmboxedit.h pmsphereedit.h pmblobedit.h pmblobsphereedit.h \ + pmblobcylinderedit.h pmtextedit.h pmjuliafractaledit.h \ + pmcylinderedit.h pmconeedit.h pmtorusedit.h pmplaneedit.h \ + pmpolynomedit.h pmheightfieldedit.h \ + pmdiscedit.h pmbicubicpatchedit.h pmtriangleedit.h \ + pmlatheedit.h pmprismedit.h pmsoredit.h pmsqeedit.h \ + pmcommentedit.h pmrawedit.h \ + pmrotateedit.h pmscaleedit.h pmtranslateedit.h \ + pmpovraymatrixedit.h \ + pmcsgedit.h pmcameraedit.h pmlightedit.h pmboundedbyedit.h \ + pmclippedbyedit.h \ + pmlineedits.h pmvectorlistedit.h pmcoloredit.h pmlinkedit.h \ + pmvectoredit.h pmpalettevalueedit.h pmformulalabel.h \ + pmtexturebaseedit.h pmtextureedit.h pmpigmentedit.h \ + pmsolidcoloredit.h pmlistpatternedit.h pmquickcoloredit.h \ + pmpatternedit.h pmblendmapmodifiersedit.h pmimagemapedit.h \ + pmtexturemapedit.h pmbumpmapedit.h pmmaterialmapedit.h \ + pmnormaledit.h pmslopeedit.h pmfinishedit.h pmwarpedit.h \ + pminterioredit.h pmmediaedit.h pmmaterialedit.h pmdensityedit.h \ + pmdeclareedit.h pmobjectlinkedit.h \ + \ + pmisosurfaceedit.h pmradiosityedit.h pmglobalphotonsedit.h \ + pmphotonsedit.h pmlightgroupedit.h pminteriortextureedit.h \ + pmspheresweepedit.h pmmeshedit.h pmdetailobjectedit.h \ + \ + pmcontrolpoint.h pm3dcontrolpoint.h pm2dcontrolpoint.h \ + pmsorcontrolpoint.h pmtranslatecontrolpoint.h \ + pmrotatecontrolpoint.h pmscalecontrolpoint.h \ + pmvectorcontrolpoint.h pmdistancecontrolpoint.h \ + pmplanenormalcontrolpoint.h \ + \ + pmmemento.h pmmapmemento.h pmsplinememento.h pmprismmemento.h \ + pmpalettevaluememento.h \ + \ + pmiomanager.h pmpovrayformat.h pmpovray31format.h pmpovray35format.h \ + pmpovray31serialization.h pmpovray35serialization.h \ + pmtokens.h pmscanner.h \ + pmparser.h pmxmlparser.h pmpovrayparser.h \ + pmserializer.h pmoutputdevice.h pmxmlhelper.h \ + pmfiledialog.h \ + \ + pmerrorflags.h pmpalettevalue.h \ + pmvector.h pmmath.h pmmatrix.h pmviewstructure.h pmline.h \ + pmcolor.h pmpoint.h pmvalue.h pmsymboltable.h pmactions.h \ + pmobjectaction.h pmsplinesegment.h pmsorsegment.h pmpolynomexponents.h \ + pmface.h \ + \ + pmrendermode.h pmglobals.h pmdefaults.h pmresourcelocator.h \ + pmtruetypecache.h pmdocumentationmap.h pminsertrulesystem.h \ + pmlibrarymanager.h pmlibraryhandle.h pmlibraryhandleedit.h \ + pmlibraryobject.h pmlibrarybrowser.h pmlibraryiconview.h \ + pmlibraryentrypreview.h\ + pmlibraryobjectsearch.h \ + pmpluginmanager.h \ + \ + version.h pmdocumentformat.h pmdebug.h pmpartiface.h + +#### +# the part + +kde_module_LTLIBRARIES = libkpovmodelerpart.la + +libkpovmodelerpart_la_SOURCES = dummy.cpp +libkpovmodelerpart_la_LIBADD = libkpovmodeler.la +libkpovmodelerpart_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +#### +# the executable + +bin_PROGRAMS = kpovmodeler + +kpovmodeler_SOURCES = main.cpp +kpovmodeler_LDFLAGS = $(all_libraries) $(KDE_RPATH) +kpovmodeler_LDADD = libkpovmodeler.la + +dummy.cpp: + echo > dummy.cpp + +rcdir = $(kde_datadir)/kpovmodeler +rc_DATA = kpovmodelershell.rc kpovmodelerui.rc kpovmodelerbrowser.rc \ + povraydocmap.xml baseinsertrules.xml questionmark.png + + +EXTRA_DIST = kpovmodeler.desktop + + +# make messages.po. Move this one to ../po/ and "make merge" in po +# the -x is for skipping messages already translated in kdelibs +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/kpovmodeler.pot + +KDE_ICON = kpovmodeler_doc kpovmodeler + +xdg_apps_DATA = kpovmodeler.desktop diff --git a/kpovmodeler/README b/kpovmodeler/README new file mode 100644 index 00000000..209fde03 --- /dev/null +++ b/kpovmodeler/README @@ -0,0 +1,3 @@ +KPovModeler: A graphical editor for povray scenes + +See http://www.kpovmodeler.org diff --git a/kpovmodeler/REQUIREMENTS b/kpovmodeler/REQUIREMENTS new file mode 100644 index 00000000..17987faa --- /dev/null +++ b/kpovmodeler/REQUIREMENTS @@ -0,0 +1,19 @@ +Requirements for KPovModeler 1.0 +-------------------------------- + +The program requires: + +- KDE-3.0 with header files + +- Qt-3.0.2 with header files + +- Freetype2 (Text view structures will be disabled otherwise) + +- OpenGL, glut, glu, glx libraries and header files + +- The Qt OpenGL extension is _NOT_ required any more! + +If you still have problems compiling the application, +visit http://www.kpovmodeler.org/install.html +or contact the KPovModeler developers +http://www.kpovmodeler.org/contact.html diff --git a/kpovmodeler/StyleConvention b/kpovmodeler/StyleConvention new file mode 100644 index 00000000..eddc404f --- /dev/null +++ b/kpovmodeler/StyleConvention @@ -0,0 +1,225 @@ + Coding Style Convention + ------------------------- + +This document describes the coding style convention +used in KPovModeler. + +Author: Andreas Zehender +Date: 16 June 2001 + +If you edit existing files or create new ones, please follow this convention. +This ensures that the code is consistent and clear. + +1) Indentation +-------------- + +- Use 3 spaces as basic offset. Do not use tabs for indentation. +- Do not indent access keywords (public, protected, private) as + well as signal/slot keywords. +- Do not indent braces. +- Put braces in separate lines. +- Indent case statements. + +Example: +class abcd +{ +public: + void someMethod( ); +}; + +void abcd::someMethod( ) +{ + if( 1 == 2 ) + { + } + else + { + switch( x ) + { + case 1: + y = 2; + break; + default: + y = -2; + } + } +} + + +2) Spacing +---------- + +Use many spaces. +Use it +- before and after brackets +- before and after operators +- after commas + +Examples: + +a = someMethod( ); // Notice the space between the brackets! +b = anotherMethod( ( a + b ) / 2, 3 ) || 23456; +if( ( a == 2 ) && !b ) + + +3) Type Modifiers (Pointers and References) +------------------------------------------- + +Put type modifiers behind the type, not before the variable name. + +Example: + +const QString& type; +PMObject* obj; + + +4) Names +-------- + +Variables: +---------- +Member variables begin with "m_". +Static variables begin with "s_". +Member pointers begin with "m_p". + +All variables begin with a lower case (member variables after the "m_"). +Use upper case character to separate different words. + +Examples: + +class abcd +{ + int m_firstMember; + char* m_pFirstMember; + static const char* s_pAStaticPointerToConstCharThatMeansItIsAString; +}; + +void abcd::efgh( ) +{ + int aLocalVariable; +} + +Classes: +-------- +All classes start with "PM" and a upper case character. + +Methods: +-------- +All methods start with a lower case character. + +Set methods begin with "set". +Get methods do NOT begin with "get". + +Examples: + +int PMSPhere::centre( ) const; +void PMSphere::setCentre( ); + +5) KDoc Comments +---------------- + +Use KDoc comments to document classes. + +Don't add a description if you just overload a virtual function +that doesn't add some functionality. + +Example: + +/** Returns the internal object name (not i18n'ed) */ +virtual PMObject::className( ) const; + +/** */ +virtual PMSphere::className( ) const; + +KDoc will then generate the following output: + + +PMObject* newObject ( ) + +[const virtual] + +Reimplemented from PMObject. + + + +6) Long Lines +-------------- +Try to use only 80 characters per line. + + +7) Sample .emacs File +--------------------- + +Here is a sample .emacs file. It is a mix of several files, so some +things are set multiple times. But it works :-) + +<.emacs> +(defconst my-c-style + '((c-tab-always-indent . t) + (c-comment-only-line-offset . 0) + (c-hanging-braces-alist . ((substatement-open after) + (brace-list-open))) + (c-hanging-colons-alist . ((member-init-intro before) + (inher-intro) + (case-label after) + (label after) + (access-label after))) + (c-cleanup-list . (scope-operator + empty-defun-braces + defun-close-semi)) + (c-offsets-alist . ((arglist-close . c-lineup-arglist) + (substatement-open . 0) + (case-label . +) + (block-open . 0) + (knr-argdecl-intro . -) + (inline-open . 0))) + (c-echo-syntactic-information-p . t) + ) + "My C Programming Style") + +;; Customizations for all of c-mode, c++-mode, and objc-mode +(defun my-c-mode-common-hook () + ;; add my personal style and set it for the current buffer + (c-add-style "PERSONAL" my-c-style t) + ;; offset customizations not in my-c-style + (c-set-offset 'member-init-intro '++) + ;; other customizations + (setq tab-width 8 + ;; this will make sure spaces are used instead of tabs + indent-tabs-mode nil) + (setq c-basic-offset 3) + ;; we like auto-newline and hungry-delete + (c-toggle-hungry-state 1) + ;; keybindings for C, C++, and Objective-C. We can put these in + ;; c-mode-map because c++-mode-map and objc-mode-map inherit it + (define-key c-mode-map [f9] 'compile) + (define-key c-mode-map [return] 'newline-and-indent) + (define-key c++-mode-map [f9] 'compile) + (define-key c++-mode-map [return] 'newline-and-indent) + (define-key java-mode-map [f9] 'compile) + (define-key java-mode-map [return] 'newline-and-indent) + (load-library "vc") + + ;;for QT + (setq c-C++-access-key "\\<\\(signals\\|public\\|protected\\|private + \\|public slots\\|protected slots\\|private slots\\)\\>[ \t]*:") + ;; modify the colour of slots to match public, private, etc ... + (font-lock-add-keywords 'c++-mode + '(("\\<\\(slots\\|signals\\)\\>" . font-lock-type-face))) + ;; make new font for rest of qt keywords + (make-face 'qt-keywords-face) + (set-face-foreground 'qt-keywords-face "green") + ;; qt keywords + (font-lock-add-keywords 'c++-mode + '(("\\" . 'qt-keywords-face))) + (font-lock-add-keywords 'c++-mode + '(("\\" . 'qt-keywords-face))) + (font-lock-add-keywords 'c++-mode + '(("\\ + diff --git a/kpovmodeler/TODO b/kpovmodeler/TODO new file mode 100644 index 00000000..565d19d1 --- /dev/null +++ b/kpovmodeler/TODO @@ -0,0 +1,52 @@ +TODO/Wishlist for kpovmodeler +----------------------------- + +Tree View +--------- +- Leave insert errors at their original position +- Add an option to the configuration whether transformations and maybe + a simple pigment should be added to new graphical objects + +Object Properties View +---------------------- + +Graphical View +-------------- +- Zoom to object short cut +- Invert mouse wheel option +- Remove GLUT dependency +- Do hidden views use CPU time? +- Heightfield wire frame + +Povray Render Window +-------------------- + +Includes +-------- +- Finish the library + * Maintain the object index in PMLibraryHandle and library_index.html + * Eliminate crashes when modifying a library object + * Implement delete in the library object preview tree +- Build an example objects library + +Povray Export +------------- + +General +------- +- All not implemented objects +- New POV-Ray 3.5 objects and textures +- BREP modeling with the patch object (triangles and polygons, extrusion etc.) +- Umlauts in the truetype text object +- Scene templates +- Add some basic render modes to a new scenes +- Sync the recent files list between multiple windows +- Multiplication of objects with simple transformations + +Long Term +--------- +- Support for animations +- Shaded views, csg results +- The whole povray syntax (macros, includes, ...) +- Support for povray variants (megapov, pvmpov) +- Support for more renderers diff --git a/kpovmodeler/baseinsertrules.xml b/kpovmodeler/baseinsertrules.xml new file mode 100644 index 00000000..24aa7dd5 --- /dev/null +++ b/kpovmodeler/baseinsertrules.xml @@ -0,0 +1,1039 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kpovmodeler/configure.in.bot b/kpovmodeler/configure.in.bot new file mode 100644 index 00000000..da816798 --- /dev/null +++ b/kpovmodeler/configure.in.bot @@ -0,0 +1,37 @@ +if test "$KPOVMODELER_OPENGL" = "no"; then + if test "$have_gl_headers" = "no"; then + echo "" + echo "You are missing" + if test "$ac_cv_header_GL_gl_h" = "no"; then + echo " - OpenGL (mesa)" + fi + if test "$ac_cv_header_GL_glu_h" = "no"; then + echo " - GLU" + fi + if test "$ac_cv_header_GL_glx_h" = "no"; then + echo " - GLX" + fi + echo "KPovModeler will not be compiled." + echo "You can download them from" + echo "http://mesa3d.sf.net" + echo "" + else + echo "" + echo "Your system fails at linking a small OpenGL application!" + echo "KPovModeler will not be compiled." + echo "Check, if OpenGL and GLU are installed correctly on your system." + echo "For more details about this problem, look at config.log after" + echo "the line \"checking for GL\"." + echo "" + fi + all_tests=bad +fi + +if test -z "$LIBFREETYPE_LIBS"; then + echo "" + echo "You're missing freetype2. KPovModeler will not display true type texts." + echo "You can download it from" + echo "http://www.freetype.org" + echo "" + all_tests=bad +fi diff --git a/kpovmodeler/configure.in.in b/kpovmodeler/configure.in.in new file mode 100644 index 00000000..34ae508f --- /dev/null +++ b/kpovmodeler/configure.in.in @@ -0,0 +1,60 @@ +have_gl_headers=yes +can_link_gl=yes +KPOVMODELER_OPENGL=yes; + +KDE_CHECK_HEADERS(GL/gl.h GL/glu.h GL/glx.h) +if test "$ac_cv_header_GL_gl_h" = "no"; then + have_gl_headers=no; +fi +if test "$ac_cv_header_GL_glu_h" = "no"; then + have_gl_headers=no; +fi +if test "$ac_cv_header_GL_glx_h" = "no"; then + have_gl_headers=no; +fi + +if test "$have_gl_headers" = "yes"; then + AC_HAVE_GL( can_link_gl=yes, can_link_gl=no ) +fi + +if test "$have_gl_headers" = "no"; then + KPOVMODELER_OPENGL=no; +fi +if test "$can_link_gl" = "no"; then + KPOVMODELER_OPENGL=no; +fi + +if test "$KPOVMODELER_OPENGL" = "no"; then + DO_NOT_COMPILE="$DO_NOT_COMPILE kpovmodeler" +fi + + +KDE_FIND_PATH(freetype-config, FREETYPE_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin]) + +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`" + + AC_DEFINE_UNQUOTED(HAVE_FREETYPE, 1, [Defines if your system has the libfreetype library]) + AC_MSG_RESULT([libraries $LIBFREETYPE_LIBS, headers $LIBFREETYPE_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) diff --git a/kpovmodeler/cr16-mime-kpovmodeler_doc.png b/kpovmodeler/cr16-mime-kpovmodeler_doc.png new file mode 100644 index 00000000..7ece4cce Binary files /dev/null and b/kpovmodeler/cr16-mime-kpovmodeler_doc.png differ diff --git a/kpovmodeler/cr32-mime-kpovmodeler_doc.png b/kpovmodeler/cr32-mime-kpovmodeler_doc.png new file mode 100644 index 00000000..32f0d2a5 Binary files /dev/null and b/kpovmodeler/cr32-mime-kpovmodeler_doc.png differ diff --git a/kpovmodeler/cr48-mime-kpovmodeler_doc.png b/kpovmodeler/cr48-mime-kpovmodeler_doc.png new file mode 100644 index 00000000..ec8bf13e Binary files /dev/null and b/kpovmodeler/cr48-mime-kpovmodeler_doc.png differ diff --git a/kpovmodeler/examples/Makefile.am b/kpovmodeler/examples/Makefile.am new file mode 100644 index 00000000..4ad27f9a --- /dev/null +++ b/kpovmodeler/examples/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = scenes includes \ No newline at end of file diff --git a/kpovmodeler/examples/includes/Makefile.am b/kpovmodeler/examples/includes/Makefile.am new file mode 100644 index 00000000..9d7b21f2 --- /dev/null +++ b/kpovmodeler/examples/includes/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = inlined original \ No newline at end of file diff --git a/kpovmodeler/examples/includes/inlined/Makefile.am b/kpovmodeler/examples/includes/inlined/Makefile.am new file mode 100644 index 00000000..f798eb8b --- /dev/null +++ b/kpovmodeler/examples/includes/inlined/Makefile.am @@ -0,0 +1,4 @@ +exdir = $(kde_datadir)/kpovmodeler/examples/includes/inlined +ex_DATA = chars.kpm finish.kpm glass.kpm golds.kpm metals.kpm shapes.kpm \ + shapes2.kpm shapesq.kpm skies.kpm stars.kpm stones1.kpm stones2.kpm \ + textures.kpm woods.kpm \ No newline at end of file diff --git a/kpovmodeler/examples/includes/inlined/chars.kpm b/kpovmodeler/examples/includes/inlined/chars.kpm new file mode 100644 index 00000000..606e7db0 Binary files /dev/null and b/kpovmodeler/examples/includes/inlined/chars.kpm differ diff --git a/kpovmodeler/examples/includes/inlined/finish.kpm b/kpovmodeler/examples/includes/inlined/finish.kpm new file mode 100644 index 00000000..d7131c4d Binary files /dev/null and b/kpovmodeler/examples/includes/inlined/finish.kpm differ diff --git a/kpovmodeler/examples/includes/inlined/glass.kpm b/kpovmodeler/examples/includes/inlined/glass.kpm new file mode 100644 index 00000000..329b68e1 --- /dev/null +++ b/kpovmodeler/examples/includes/inlined/glass.kpm @@ -0,0 +1,141 @@ + + + + + + +Persistence of Vision Raytracer Version 3.1 +Glass finishes and textures + + Changes in ver. 3.1 moved refraction and ior to the interior statment. +Use I_Glass in conjunction with each of the finish statments below. + Glass Interior + + + + Glass Finishes + + + + + + + + + + + + + Glass Textures + Simple clear glass + + + + + + + + + More like an acrylic plastic + + + + + + + + + An excellent lead crystal glass! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A few color variations on Norm's glass +Ruby glass + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Orange/Amber glass + + + + + + + + + Vicks bottle, glass + + + + + + + + + diff --git a/kpovmodeler/examples/includes/inlined/golds.kpm b/kpovmodeler/examples/includes/inlined/golds.kpm new file mode 100644 index 00000000..91feeca0 Binary files /dev/null and b/kpovmodeler/examples/includes/inlined/golds.kpm differ diff --git a/kpovmodeler/examples/includes/inlined/metals.kpm b/kpovmodeler/examples/includes/inlined/metals.kpm new file mode 100644 index 00000000..80f7f432 Binary files /dev/null and b/kpovmodeler/examples/includes/inlined/metals.kpm differ diff --git a/kpovmodeler/examples/includes/inlined/shapes.kpm b/kpovmodeler/examples/includes/inlined/shapes.kpm new file mode 100644 index 00000000..0390613d Binary files /dev/null and b/kpovmodeler/examples/includes/inlined/shapes.kpm differ diff --git a/kpovmodeler/examples/includes/inlined/shapes2.kpm b/kpovmodeler/examples/includes/inlined/shapes2.kpm new file mode 100644 index 00000000..72421aef Binary files /dev/null and b/kpovmodeler/examples/includes/inlined/shapes2.kpm differ diff --git a/kpovmodeler/examples/includes/inlined/shapesq.kpm b/kpovmodeler/examples/includes/inlined/shapesq.kpm new file mode 100644 index 00000000..3aa691b6 Binary files /dev/null and b/kpovmodeler/examples/includes/inlined/shapesq.kpm differ diff --git a/kpovmodeler/examples/includes/inlined/skies.kpm b/kpovmodeler/examples/includes/inlined/skies.kpm new file mode 100644 index 00000000..9c4ff952 Binary files /dev/null and b/kpovmodeler/examples/includes/inlined/skies.kpm differ diff --git a/kpovmodeler/examples/includes/inlined/stars.kpm b/kpovmodeler/examples/includes/inlined/stars.kpm new file mode 100644 index 00000000..9ec844a6 Binary files /dev/null and b/kpovmodeler/examples/includes/inlined/stars.kpm differ diff --git a/kpovmodeler/examples/includes/inlined/stones1.kpm b/kpovmodeler/examples/includes/inlined/stones1.kpm new file mode 100644 index 00000000..67ddadfe Binary files /dev/null and b/kpovmodeler/examples/includes/inlined/stones1.kpm differ diff --git a/kpovmodeler/examples/includes/inlined/stones2.kpm b/kpovmodeler/examples/includes/inlined/stones2.kpm new file mode 100644 index 00000000..955052e5 Binary files /dev/null and b/kpovmodeler/examples/includes/inlined/stones2.kpm differ diff --git a/kpovmodeler/examples/includes/inlined/textures.kpm b/kpovmodeler/examples/includes/inlined/textures.kpm new file mode 100644 index 00000000..4f5d3dc9 Binary files /dev/null and b/kpovmodeler/examples/includes/inlined/textures.kpm differ diff --git a/kpovmodeler/examples/includes/inlined/woods.kpm b/kpovmodeler/examples/includes/inlined/woods.kpm new file mode 100644 index 00000000..f5b12879 Binary files /dev/null and b/kpovmodeler/examples/includes/inlined/woods.kpm differ diff --git a/kpovmodeler/examples/includes/original/Makefile.am b/kpovmodeler/examples/includes/original/Makefile.am new file mode 100644 index 00000000..544ecd09 --- /dev/null +++ b/kpovmodeler/examples/includes/original/Makefile.am @@ -0,0 +1,4 @@ +exdir = $(kde_datadir)/kpovmodeler/examples/includes/original +ex_DATA = chars.kpm finish.kpm glass.kpm golds.kpm metals.kpm shapes.kpm \ + shapes2.kpm shapesq.kpm skies.kpm stars.kpm stones1.kpm stones2.kpm \ + textures.kpm woods.kpm \ No newline at end of file diff --git a/kpovmodeler/examples/includes/original/chars.kpm b/kpovmodeler/examples/includes/original/chars.kpm new file mode 100644 index 00000000..1f16af27 Binary files /dev/null and b/kpovmodeler/examples/includes/original/chars.kpm differ diff --git a/kpovmodeler/examples/includes/original/finish.kpm b/kpovmodeler/examples/includes/original/finish.kpm new file mode 100644 index 00000000..57964af6 Binary files /dev/null and b/kpovmodeler/examples/includes/original/finish.kpm differ diff --git a/kpovmodeler/examples/includes/original/glass.kpm b/kpovmodeler/examples/includes/original/glass.kpm new file mode 100644 index 00000000..9750c57a Binary files /dev/null and b/kpovmodeler/examples/includes/original/glass.kpm differ diff --git a/kpovmodeler/examples/includes/original/golds.kpm b/kpovmodeler/examples/includes/original/golds.kpm new file mode 100644 index 00000000..d11b632b Binary files /dev/null and b/kpovmodeler/examples/includes/original/golds.kpm differ diff --git a/kpovmodeler/examples/includes/original/metals.kpm b/kpovmodeler/examples/includes/original/metals.kpm new file mode 100644 index 00000000..c5634789 Binary files /dev/null and b/kpovmodeler/examples/includes/original/metals.kpm differ diff --git a/kpovmodeler/examples/includes/original/shapes.kpm b/kpovmodeler/examples/includes/original/shapes.kpm new file mode 100644 index 00000000..e587d44b Binary files /dev/null and b/kpovmodeler/examples/includes/original/shapes.kpm differ diff --git a/kpovmodeler/examples/includes/original/shapes2.kpm b/kpovmodeler/examples/includes/original/shapes2.kpm new file mode 100644 index 00000000..206f375a Binary files /dev/null and b/kpovmodeler/examples/includes/original/shapes2.kpm differ diff --git a/kpovmodeler/examples/includes/original/shapesq.kpm b/kpovmodeler/examples/includes/original/shapesq.kpm new file mode 100644 index 00000000..416d190e Binary files /dev/null and b/kpovmodeler/examples/includes/original/shapesq.kpm differ diff --git a/kpovmodeler/examples/includes/original/skies.kpm b/kpovmodeler/examples/includes/original/skies.kpm new file mode 100644 index 00000000..e5c65c04 Binary files /dev/null and b/kpovmodeler/examples/includes/original/skies.kpm differ diff --git a/kpovmodeler/examples/includes/original/stars.kpm b/kpovmodeler/examples/includes/original/stars.kpm new file mode 100644 index 00000000..b17cb306 Binary files /dev/null and b/kpovmodeler/examples/includes/original/stars.kpm differ diff --git a/kpovmodeler/examples/includes/original/stones1.kpm b/kpovmodeler/examples/includes/original/stones1.kpm new file mode 100644 index 00000000..0753b49e Binary files /dev/null and b/kpovmodeler/examples/includes/original/stones1.kpm differ diff --git a/kpovmodeler/examples/includes/original/stones2.kpm b/kpovmodeler/examples/includes/original/stones2.kpm new file mode 100644 index 00000000..16438514 Binary files /dev/null and b/kpovmodeler/examples/includes/original/stones2.kpm differ diff --git a/kpovmodeler/examples/includes/original/textures.kpm b/kpovmodeler/examples/includes/original/textures.kpm new file mode 100644 index 00000000..ae6cca1f Binary files /dev/null and b/kpovmodeler/examples/includes/original/textures.kpm differ diff --git a/kpovmodeler/examples/includes/original/woods.kpm b/kpovmodeler/examples/includes/original/woods.kpm new file mode 100644 index 00000000..4cdca2ec Binary files /dev/null and b/kpovmodeler/examples/includes/original/woods.kpm differ diff --git a/kpovmodeler/examples/scenes/Makefile.am b/kpovmodeler/examples/scenes/Makefile.am new file mode 100644 index 00000000..090e2230 --- /dev/null +++ b/kpovmodeler/examples/scenes/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = advanced csg interior lights objects \ No newline at end of file diff --git a/kpovmodeler/examples/scenes/advanced/Makefile.am b/kpovmodeler/examples/scenes/advanced/Makefile.am new file mode 100644 index 00000000..42f8c53c --- /dev/null +++ b/kpovmodeler/examples/scenes/advanced/Makefile.am @@ -0,0 +1,2 @@ +exdir = $(kde_datadir)/kpovmodeler/examples/scenes/advanced +ex_DATA = ants.kpm bee.kpm ink.kpm table.kpm \ No newline at end of file diff --git a/kpovmodeler/examples/scenes/advanced/ants.kpm b/kpovmodeler/examples/scenes/advanced/ants.kpm new file mode 100644 index 00000000..c84bd68d Binary files /dev/null and b/kpovmodeler/examples/scenes/advanced/ants.kpm differ diff --git a/kpovmodeler/examples/scenes/advanced/bee.kpm b/kpovmodeler/examples/scenes/advanced/bee.kpm new file mode 100644 index 00000000..9f594df3 Binary files /dev/null and b/kpovmodeler/examples/scenes/advanced/bee.kpm differ diff --git a/kpovmodeler/examples/scenes/advanced/ink.kpm b/kpovmodeler/examples/scenes/advanced/ink.kpm new file mode 100644 index 00000000..036ef168 Binary files /dev/null and b/kpovmodeler/examples/scenes/advanced/ink.kpm differ diff --git a/kpovmodeler/examples/scenes/advanced/table.kpm b/kpovmodeler/examples/scenes/advanced/table.kpm new file mode 100644 index 00000000..1fdddccd Binary files /dev/null and b/kpovmodeler/examples/scenes/advanced/table.kpm differ diff --git a/kpovmodeler/examples/scenes/csg/Makefile.am b/kpovmodeler/examples/scenes/csg/Makefile.am new file mode 100644 index 00000000..c63d4ae8 --- /dev/null +++ b/kpovmodeler/examples/scenes/csg/Makefile.am @@ -0,0 +1,2 @@ +exdir = $(kde_datadir)/kpovmodeler/examples/scenes/csg +ex_DATA = cheese.kpm emptybox.kpm heightfield.kpm \ No newline at end of file diff --git a/kpovmodeler/examples/scenes/csg/cheese.kpm b/kpovmodeler/examples/scenes/csg/cheese.kpm new file mode 100644 index 00000000..215ec50d Binary files /dev/null and b/kpovmodeler/examples/scenes/csg/cheese.kpm differ diff --git a/kpovmodeler/examples/scenes/csg/emptybox.kpm b/kpovmodeler/examples/scenes/csg/emptybox.kpm new file mode 100644 index 00000000..e917ba21 Binary files /dev/null and b/kpovmodeler/examples/scenes/csg/emptybox.kpm differ diff --git a/kpovmodeler/examples/scenes/csg/heightfield.kpm b/kpovmodeler/examples/scenes/csg/heightfield.kpm new file mode 100644 index 00000000..051b25ea Binary files /dev/null and b/kpovmodeler/examples/scenes/csg/heightfield.kpm differ diff --git a/kpovmodeler/examples/scenes/interior/Makefile.am b/kpovmodeler/examples/scenes/interior/Makefile.am new file mode 100644 index 00000000..7d8e4e22 --- /dev/null +++ b/kpovmodeler/examples/scenes/interior/Makefile.am @@ -0,0 +1,2 @@ +exdir = $(kde_datadir)/kpovmodeler/examples/scenes/interior +ex_DATA = cubes.kpm media1.kpm media2.kpm media3.kpm spheres.kpm \ No newline at end of file diff --git a/kpovmodeler/examples/scenes/interior/cubes.kpm b/kpovmodeler/examples/scenes/interior/cubes.kpm new file mode 100644 index 00000000..30f516c9 Binary files /dev/null and b/kpovmodeler/examples/scenes/interior/cubes.kpm differ diff --git a/kpovmodeler/examples/scenes/interior/media1.kpm b/kpovmodeler/examples/scenes/interior/media1.kpm new file mode 100644 index 00000000..94938e69 Binary files /dev/null and b/kpovmodeler/examples/scenes/interior/media1.kpm differ diff --git a/kpovmodeler/examples/scenes/interior/media2.kpm b/kpovmodeler/examples/scenes/interior/media2.kpm new file mode 100644 index 00000000..bae2c746 Binary files /dev/null and b/kpovmodeler/examples/scenes/interior/media2.kpm differ diff --git a/kpovmodeler/examples/scenes/interior/media3.kpm b/kpovmodeler/examples/scenes/interior/media3.kpm new file mode 100644 index 00000000..b9215dfa Binary files /dev/null and b/kpovmodeler/examples/scenes/interior/media3.kpm differ diff --git a/kpovmodeler/examples/scenes/interior/spheres.kpm b/kpovmodeler/examples/scenes/interior/spheres.kpm new file mode 100644 index 00000000..059bee3b Binary files /dev/null and b/kpovmodeler/examples/scenes/interior/spheres.kpm differ diff --git a/kpovmodeler/examples/scenes/lights/Makefile.am b/kpovmodeler/examples/scenes/lights/Makefile.am new file mode 100644 index 00000000..9b1f5ad5 --- /dev/null +++ b/kpovmodeler/examples/scenes/lights/Makefile.am @@ -0,0 +1,2 @@ +exdir = $(kde_datadir)/kpovmodeler/examples/scenes/lights +ex_DATA = arealight.kpm arealight2.kpm spotlight.kpm \ No newline at end of file diff --git a/kpovmodeler/examples/scenes/lights/arealight.kpm b/kpovmodeler/examples/scenes/lights/arealight.kpm new file mode 100644 index 00000000..d02a893d Binary files /dev/null and b/kpovmodeler/examples/scenes/lights/arealight.kpm differ diff --git a/kpovmodeler/examples/scenes/lights/arealight2.kpm b/kpovmodeler/examples/scenes/lights/arealight2.kpm new file mode 100644 index 00000000..21d2e772 Binary files /dev/null and b/kpovmodeler/examples/scenes/lights/arealight2.kpm differ diff --git a/kpovmodeler/examples/scenes/lights/spotlight.kpm b/kpovmodeler/examples/scenes/lights/spotlight.kpm new file mode 100644 index 00000000..925fb7c3 Binary files /dev/null and b/kpovmodeler/examples/scenes/lights/spotlight.kpm differ diff --git a/kpovmodeler/examples/scenes/objects/Makefile.am b/kpovmodeler/examples/scenes/objects/Makefile.am new file mode 100644 index 00000000..bfa14dce --- /dev/null +++ b/kpovmodeler/examples/scenes/objects/Makefile.am @@ -0,0 +1,3 @@ +exdir = $(kde_datadir)/kpovmodeler/examples/scenes/objects +ex_DATA = allobjects.kpm fractals.kpm lathe.kpm prism.kpm sor.kpm \ + superellipsoid.kpm text.kpm \ No newline at end of file diff --git a/kpovmodeler/examples/scenes/objects/allobjects.kpm b/kpovmodeler/examples/scenes/objects/allobjects.kpm new file mode 100644 index 00000000..10136a71 Binary files /dev/null and b/kpovmodeler/examples/scenes/objects/allobjects.kpm differ diff --git a/kpovmodeler/examples/scenes/objects/fractals.kpm b/kpovmodeler/examples/scenes/objects/fractals.kpm new file mode 100644 index 00000000..a0e83171 Binary files /dev/null and b/kpovmodeler/examples/scenes/objects/fractals.kpm differ diff --git a/kpovmodeler/examples/scenes/objects/lathe.kpm b/kpovmodeler/examples/scenes/objects/lathe.kpm new file mode 100644 index 00000000..64e8691a Binary files /dev/null and b/kpovmodeler/examples/scenes/objects/lathe.kpm differ diff --git a/kpovmodeler/examples/scenes/objects/prism.kpm b/kpovmodeler/examples/scenes/objects/prism.kpm new file mode 100644 index 00000000..c6b5cd19 Binary files /dev/null and b/kpovmodeler/examples/scenes/objects/prism.kpm differ diff --git a/kpovmodeler/examples/scenes/objects/sor.kpm b/kpovmodeler/examples/scenes/objects/sor.kpm new file mode 100644 index 00000000..cddea81e Binary files /dev/null and b/kpovmodeler/examples/scenes/objects/sor.kpm differ diff --git a/kpovmodeler/examples/scenes/objects/superellipsoid.kpm b/kpovmodeler/examples/scenes/objects/superellipsoid.kpm new file mode 100644 index 00000000..35810e6e Binary files /dev/null and b/kpovmodeler/examples/scenes/objects/superellipsoid.kpm differ diff --git a/kpovmodeler/examples/scenes/objects/text.kpm b/kpovmodeler/examples/scenes/objects/text.kpm new file mode 100644 index 00000000..f7c84beb Binary files /dev/null and b/kpovmodeler/examples/scenes/objects/text.kpm differ diff --git a/kpovmodeler/hi16-app-kpovmodeler.png b/kpovmodeler/hi16-app-kpovmodeler.png new file mode 100644 index 00000000..a6f1b945 Binary files /dev/null and b/kpovmodeler/hi16-app-kpovmodeler.png differ diff --git a/kpovmodeler/hi22-app-kpovmodeler.png b/kpovmodeler/hi22-app-kpovmodeler.png new file mode 100644 index 00000000..218417bd Binary files /dev/null and b/kpovmodeler/hi22-app-kpovmodeler.png differ diff --git a/kpovmodeler/hi32-app-kpovmodeler.png b/kpovmodeler/hi32-app-kpovmodeler.png new file mode 100644 index 00000000..07ffa8bb Binary files /dev/null and b/kpovmodeler/hi32-app-kpovmodeler.png differ diff --git a/kpovmodeler/hi48-app-kpovmodeler.png b/kpovmodeler/hi48-app-kpovmodeler.png new file mode 100644 index 00000000..904a39cf Binary files /dev/null and b/kpovmodeler/hi48-app-kpovmodeler.png differ diff --git a/kpovmodeler/kdoc.rules b/kpovmodeler/kdoc.rules new file mode 100644 index 00000000..6b5d40a6 --- /dev/null +++ b/kpovmodeler/kdoc.rules @@ -0,0 +1,10 @@ +# These are the rules used by makekdedoc to generate the kpovmodeler +# documentation with KDOC. +# +# $Id$ + +kde_MODULES = kpovmodeler + +kpovmodeler_FILES = *.h +kpovmodeler_LIBS = -lkdeui -lkparts -lkdecore -ldcop -lkfile -lkio -lqt -p +kpovmodeler_PATH = . \ No newline at end of file diff --git a/kpovmodeler/kpovmodeler.desktop b/kpovmodeler/kpovmodeler.desktop new file mode 100644 index 00000000..49e0844c --- /dev/null +++ b/kpovmodeler/kpovmodeler.desktop @@ -0,0 +1,59 @@ +[Desktop Entry] +DocPath=kpovmodeler/index.html +Exec=kpovmodeler -caption "%c" %i %m %f +Icon=kpovmodeler +MimeType=application/x-kpovmodeler; +Name=KPovModeler +Name[eo]=KPovModelilo +Name[es]=Modelador Povray +Name[he]=מעצב Povray +Name[nb]=KPov-modellerer +Name[ne]=केडीई पोभ मोडेलर +Name[nn]=KPov-modellering +Name[sv]=Kpovmodeler +GenericName=Povray Modeler +GenericName[ca]=Modelador Povray +GenericName[cs]=Modelář Povray +GenericName[cy]=Modelydd Povray +GenericName[da]=Povray-modellering +GenericName[de]=Povray-Modellierer +GenericName[en_GB]=Povray Modeller +GenericName[eo]=Povray-modelilo +GenericName[es]=Modelador Povray +GenericName[et]=Povray modelleerija +GenericName[eu]=Povray modelatzailea +GenericName[fa]=سازندۀ مدل Povray +GenericName[fi]=Povray-mallintaja +GenericName[fr]=Modeleur Povray +GenericName[gl]=Modelador Povray +GenericName[he]=מעצב Povray +GenericName[hu]=Povray-modellező +GenericName[is]=Povray hönnuður +GenericName[it]=Modellatore per Povray +GenericName[ja]=Povray モデラー +GenericName[kk]=Povray үлгілеу +GenericName[km]=កម្មវិធី​ធ្វើ​ម៉ូដែល Povray +GenericName[ms]=Pemodel Povray +GenericName[nb]=Povray-modellerer +GenericName[nds]=Povray-Modellmaker +GenericName[ne]=पोभ्रे मोडेलर +GenericName[nn]=Povray-modellering +GenericName[pl]=Modeler Povray +GenericName[pt]=Modelador de Povray +GenericName[pt_BR]=Modelador Povray +GenericName[ro]=Modelator Povray +GenericName[ru]=Редактор Povray +GenericName[sl]=Modelirnik Povray +GenericName[sr]=Моделар за Povray +GenericName[sr@Latn]=Modelar za Povray +GenericName[sv]=Modellering med Povray +GenericName[ta]=பாவ்ரே மாடுல்லர் +GenericName[tr]=Povray Modelleyici +GenericName[zh_CN]=Povray 建模器 +GenericName[zh_HK]=Povray 建模器 +Path= +ServiceTypes=KParts/ReadOnlyPart,KParts/ReadWritePart,Browser/View,KPovModeler/Document +Terminal=false +Type=Application +X-KDE-Library=libkpovmodelerpart +Categories=Qt;KDE;Graphics; diff --git a/kpovmodeler/kpovmodelerbrowser.rc b/kpovmodeler/kpovmodelerbrowser.rc new file mode 100644 index 00000000..9640121f --- /dev/null +++ b/kpovmodeler/kpovmodelerbrowser.rc @@ -0,0 +1,21 @@ + + + + &Edit + + + + + + + + + + + + + + + + + diff --git a/kpovmodeler/kpovmodelershell.rc b/kpovmodeler/kpovmodelershell.rc new file mode 100644 index 00000000..cea9e017 --- /dev/null +++ b/kpovmodeler/kpovmodelershell.rc @@ -0,0 +1,58 @@ + + + + &File + + + + &Edit + + + &Insert + + + &View + + + + + + + + + + + + + + + + + + + &Settings + + + + + +Main Toolbar + + + + + + + + + + +Library Toolbar + + + + + + + + diff --git a/kpovmodeler/kpovmodelerui.rc b/kpovmodeler/kpovmodelerui.rc new file mode 100644 index 00000000..007257b6 --- /dev/null +++ b/kpovmodeler/kpovmodelerui.rc @@ -0,0 +1,303 @@ + + + + + &File + + + + &Edit + + + + + + + + + &Insert + + + + + + + + + + + + + + + + + + + Finite Solid Primitives + + + + + + + + + + + + + + + + + + + + + + + Finite Patch Primitives + + + + + + Infinite Solid Primitives + + + + Constructive Solid Geometry + + + + + + + Material + + + Interior + + + + + + + Textures + + + + + + + + + + + + + + + + + + + + + + + + + + + Photons + + + Atmospheric Effects + + + + + + Transformations + + + + + + + &View + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Main Toolbar + + + + + + + + + +Finite Solid Primitives + + + + + + + + + + + + + + + + + + + + + + + +Constructive Solid Geometry + + + + + + +Infinite and Patch Primitives + + + + + + + + + +Atmospheric Effects + + + + + +Misc Objects + + + + + + + + + + + + + + + + + + + + +Transformations + + + + + + +Textures + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Povray Rendering + + + + + +Graphical View + + + + + + + + diff --git a/kpovmodeler/main.cpp b/kpovmodeler/main.cpp new file mode 100644 index 00000000..8bdabf8e --- /dev/null +++ b/kpovmodeler/main.cpp @@ -0,0 +1,69 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include +#include +#include +#include + +#include "pmshell.h" +#include "pmfactory.h" +#include "pmrendermanager.h" +#include "version.h" + + +static KCmdLineOptions options[] = +{ + { "+[file]", I18N_NOOP( "File to open" ), 0 }, + { "no-opengl", I18N_NOOP( "Disables OpenGL rendering" ), 0 }, + { "no-dri", I18N_NOOP( "Disables direct rendering" ), 0 }, + KCmdLineLastOption +}; + +int main( int argc, char* argv[] ) +{ + PMShell* shell = 0; + + KCmdLineArgs::init( argc, argv, PMFactory::aboutData( ) ); + KCmdLineArgs::addCmdLineOptions( options ); + + KApplication app; + + KCmdLineArgs* args = KCmdLineArgs::parsedArgs( ); + + if( !args->isSet( "-opengl" ) ) + PMRenderManager::disableOpenGL( ); + if( !args->isSet( "-dri" ) ) + PMGLView::enableDirectRendering( false ); + + if( args->count( ) > 0 ) + { + for( int i = 0 ; i < args->count( ) ; i++ ) + { + shell = new PMShell( args->url( i ) ); + shell->show( ); + } + } + else + { + shell = new PMShell; + shell->show( ); + } + args->clear(); + return app.exec( ); +} diff --git a/kpovmodeler/pics/Makefile.am b/kpovmodeler/pics/Makefile.am new file mode 100644 index 00000000..ff33151e --- /dev/null +++ b/kpovmodeler/pics/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = locolor crystalsvg diff --git a/kpovmodeler/pics/crystalsvg/Makefile.am b/kpovmodeler/pics/crystalsvg/Makefile.am new file mode 100644 index 00000000..66481ab6 --- /dev/null +++ b/kpovmodeler/pics/crystalsvg/Makefile.am @@ -0,0 +1,2 @@ +pmtoolbardir = $(kde_datadir)/kpovmodeler/icons +pmtoolbar_ICON = AUTO diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmaddpoint.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmaddpoint.png new file mode 100644 index 00000000..b3c7cab4 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmaddpoint.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmaddpointabove.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmaddpointabove.png new file mode 100644 index 00000000..4310c761 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmaddpointabove.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmaddsubprism.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmaddsubprism.png new file mode 100644 index 00000000..ff5bca2b Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmaddsubprism.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmbicubicpatch.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmbicubicpatch.png new file mode 100644 index 00000000..3b7baaa0 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmbicubicpatch.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmblendmapmodifiers.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmblendmapmodifiers.png new file mode 100644 index 00000000..334867dc Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmblendmapmodifiers.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmblob.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmblob.png new file mode 100644 index 00000000..28c7f9c4 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmblob.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmblobcylinder.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmblobcylinder.png new file mode 100644 index 00000000..3b788ebf Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmblobcylinder.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmblobsphere.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmblobsphere.png new file mode 100644 index 00000000..9e9e9c04 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmblobsphere.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmboundedby.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmboundedby.png new file mode 100644 index 00000000..288769d8 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmboundedby.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmbox.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmbox.png new file mode 100644 index 00000000..48a81471 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmbox.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmbumpmap.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmbumpmap.png new file mode 100644 index 00000000..5221c2a9 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmbumpmap.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmcamera.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmcamera.png new file mode 100644 index 00000000..264a4e9f Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmcamera.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmclippedby.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmclippedby.png new file mode 100644 index 00000000..b281ac84 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmclippedby.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmcolorlist.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmcolorlist.png new file mode 100644 index 00000000..cc3e406d Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmcolorlist.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmcolormap.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmcolormap.png new file mode 100644 index 00000000..ed68e5e5 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmcolormap.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmcolormapdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmcolormapdeclare.png new file mode 100644 index 00000000..3371c27a Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmcolormapdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmcomment.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmcomment.png new file mode 100644 index 00000000..78b0a3f0 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmcomment.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmcone.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmcone.png new file mode 100644 index 00000000..0dd88efd Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmcone.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmcylinder.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmcylinder.png new file mode 100644 index 00000000..753453b2 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmcylinder.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmdeclare.png new file mode 100644 index 00000000..36c277d5 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmdensity.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmdensity.png new file mode 100644 index 00000000..98b91daa Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmdensity.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitydeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitydeclare.png new file mode 100644 index 00000000..87f96d9e Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitydeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitylist.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitylist.png new file mode 100644 index 00000000..a783751e Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitylist.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitymap.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitymap.png new file mode 100644 index 00000000..dc277d2c Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitymap.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitymapdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitymapdeclare.png new file mode 100644 index 00000000..f22f525e Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitymapdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmdialogview.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmdialogview.png new file mode 100644 index 00000000..e48cb253 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmdialogview.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmdifference.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmdifference.png new file mode 100644 index 00000000..d2551828 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmdifference.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmdisc.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmdisc.png new file mode 100644 index 00000000..c39115c4 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmdisc.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmdrag.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmdrag.png new file mode 100644 index 00000000..65aba8ba Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmdrag.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmfinish.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmfinish.png new file mode 100644 index 00000000..d014f144 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmfinish.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmfinishdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmfinishdeclare.png new file mode 100644 index 00000000..b0e77f59 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmfinishdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmfog.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmfog.png new file mode 100644 index 00000000..5d7acae0 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmfog.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmfogdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmfogdeclare.png new file mode 100644 index 00000000..0db954dc Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmfogdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmglobalphotons.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmglobalphotons.png new file mode 100644 index 00000000..1e6d4144 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmglobalphotons.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmglobalsettings.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmglobalsettings.png new file mode 100644 index 00000000..9732e0ba Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmglobalsettings.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmglview.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmglview.png new file mode 100644 index 00000000..7b69cea1 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmglview.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmheightfield.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmheightfield.png new file mode 100644 index 00000000..f40f3f50 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmheightfield.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmimagemap.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmimagemap.png new file mode 100644 index 00000000..01d8d9da Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmimagemap.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pminserterrors.png b/kpovmodeler/pics/crystalsvg/cr16-action-pminserterrors.png new file mode 100644 index 00000000..a8edc396 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pminserterrors.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pminsertfirstchild.png b/kpovmodeler/pics/crystalsvg/cr16-action-pminsertfirstchild.png new file mode 100644 index 00000000..5ee47f17 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pminsertfirstchild.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pminsertlastchild.png b/kpovmodeler/pics/crystalsvg/cr16-action-pminsertlastchild.png new file mode 100644 index 00000000..cc7193f7 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pminsertlastchild.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pminsertsibling.png b/kpovmodeler/pics/crystalsvg/cr16-action-pminsertsibling.png new file mode 100644 index 00000000..a0bca16f Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pminsertsibling.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pminterior.png b/kpovmodeler/pics/crystalsvg/cr16-action-pminterior.png new file mode 100644 index 00000000..76a003df Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pminterior.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pminteriordeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pminteriordeclare.png new file mode 100644 index 00000000..18781544 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pminteriordeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pminteriortexture.png b/kpovmodeler/pics/crystalsvg/cr16-action-pminteriortexture.png new file mode 100644 index 00000000..0de1c19b Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pminteriortexture.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pminteriortexturedeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pminteriortexturedeclare.png new file mode 100644 index 00000000..801ecda9 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pminteriortexturedeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmintersection.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmintersection.png new file mode 100644 index 00000000..954eae50 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmintersection.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmisosurface.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmisosurface.png new file mode 100644 index 00000000..59dbdc05 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmisosurface.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmjuliafractal.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmjuliafractal.png new file mode 100644 index 00000000..66b6cad0 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmjuliafractal.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmlathe.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmlathe.png new file mode 100644 index 00000000..bd316870 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmlathe.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmlight.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmlight.png new file mode 100644 index 00000000..e6e0d098 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmlight.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmlightgroup.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmlightgroup.png new file mode 100644 index 00000000..105ca083 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmlightgroup.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmlistpattern.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmlistpattern.png new file mode 100644 index 00000000..cd68aa2a Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmlistpattern.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmlookslike.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmlookslike.png new file mode 100644 index 00000000..3b511673 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmlookslike.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmmaterial.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmmaterial.png new file mode 100644 index 00000000..af492025 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmmaterial.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmmaterialdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmmaterialdeclare.png new file mode 100644 index 00000000..aa9ba10b Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmmaterialdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmmaterialmap.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmmaterialmap.png new file mode 100644 index 00000000..f46a9fb2 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmmaterialmap.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmmatrix.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmmatrix.png new file mode 100644 index 00000000..32f4f298 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmmatrix.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmmedia.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmmedia.png new file mode 100644 index 00000000..4b72046c Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmmedia.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmmediadeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmmediadeclare.png new file mode 100644 index 00000000..e43b3948 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmmediadeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmmerge.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmmerge.png new file mode 100644 index 00000000..04e71ed2 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmmerge.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmmesh.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmmesh.png new file mode 100644 index 00000000..3ab5de1a Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmmesh.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmnormal.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmnormal.png new file mode 100644 index 00000000..99979725 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmnormal.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmnormaldeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmnormaldeclare.png new file mode 100644 index 00000000..e148abc3 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmnormaldeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmnormallist.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmnormallist.png new file mode 100644 index 00000000..4f4fea88 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmnormallist.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmnormalmap.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmnormalmap.png new file mode 100644 index 00000000..6d12407b Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmnormalmap.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmnormalmapdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmnormalmapdeclare.png new file mode 100644 index 00000000..09c6d28e Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmnormalmapdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmobjectdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmobjectdeclare.png new file mode 100644 index 00000000..cd562250 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmobjectdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmobjectlink.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmobjectlink.png new file mode 100644 index 00000000..479664f6 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmobjectlink.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmpattern.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmpattern.png new file mode 100644 index 00000000..5032bb8d Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmpattern.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmphotons.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmphotons.png new file mode 100644 index 00000000..b2f64977 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmphotons.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmpigment.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmpigment.png new file mode 100644 index 00000000..e1c49853 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmpigment.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentdeclare.png new file mode 100644 index 00000000..15af344d Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentlist.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentlist.png new file mode 100644 index 00000000..26aa2908 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentlist.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentmap.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentmap.png new file mode 100644 index 00000000..32e1c4e6 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentmap.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentmapdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentmapdeclare.png new file mode 100644 index 00000000..2ff2d59d Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentmapdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmplane.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmplane.png new file mode 100644 index 00000000..8e6590b0 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmplane.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmpolynom.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmpolynom.png new file mode 100644 index 00000000..fcaf1a15 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmpolynom.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmprism.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmprism.png new file mode 100644 index 00000000..b58f5aa8 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmprism.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmprojectedthrough.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmprojectedthrough.png new file mode 100644 index 00000000..94b4aa4e Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmprojectedthrough.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmquickcolor.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmquickcolor.png new file mode 100644 index 00000000..41afd2a3 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmquickcolor.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmradiosity.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmradiosity.png new file mode 100644 index 00000000..0428f202 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmradiosity.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmrainbow.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmrainbow.png new file mode 100644 index 00000000..271405db Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmrainbow.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmrainbowdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmrainbowdeclare.png new file mode 100644 index 00000000..9232255c Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmrainbowdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmraw.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmraw.png new file mode 100644 index 00000000..cb0ce235 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmraw.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmremovepoint.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmremovepoint.png new file mode 100644 index 00000000..0be182fb Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmremovepoint.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmrender.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmrender.png new file mode 100644 index 00000000..901a283d Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmrender.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmrenderpreview.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmrenderpreview.png new file mode 100644 index 00000000..c14b2c38 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmrenderpreview.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmrendersettings.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmrendersettings.png new file mode 100644 index 00000000..9a63e1a2 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmrendersettings.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmrotate.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmrotate.png new file mode 100644 index 00000000..744f927c Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmrotate.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmscale.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmscale.png new file mode 100644 index 00000000..ca553a0f Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmscale.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmscene.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmscene.png new file mode 100644 index 00000000..8a4c4bd1 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmscene.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmskysphere.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmskysphere.png new file mode 100644 index 00000000..bbfd050a Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmskysphere.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmskyspheredeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmskyspheredeclare.png new file mode 100644 index 00000000..16cd5bb3 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmskyspheredeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmslope.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmslope.png new file mode 100644 index 00000000..e665a1bd Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmslope.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmslopemap.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmslopemap.png new file mode 100644 index 00000000..a757fc90 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmslopemap.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmslopemapdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmslopemapdeclare.png new file mode 100644 index 00000000..fe7e9969 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmslopemapdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmsolidcolor.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmsolidcolor.png new file mode 100644 index 00000000..b2f4eda7 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmsolidcolor.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmsor.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmsor.png new file mode 100644 index 00000000..8a652ed7 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmsor.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmsphere.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmsphere.png new file mode 100644 index 00000000..a8a38679 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmsphere.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmspheresweep.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmspheresweep.png new file mode 100644 index 00000000..19cced4c Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmspheresweep.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmsqe.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmsqe.png new file mode 100644 index 00000000..ea2e2a14 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmsqe.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmtext.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmtext.png new file mode 100644 index 00000000..4b339926 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmtext.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmtexture.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmtexture.png new file mode 100644 index 00000000..c90031ca Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmtexture.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturedeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturedeclare.png new file mode 100644 index 00000000..75a77847 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturedeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturelist.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturelist.png new file mode 100644 index 00000000..85881a7d Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturelist.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturemap.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturemap.png new file mode 100644 index 00000000..171bf68d Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturemap.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturemapdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturemapdeclare.png new file mode 100644 index 00000000..ab2edae6 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturemapdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmtorus.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmtorus.png new file mode 100644 index 00000000..82f78511 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmtorus.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmtranslate.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmtranslate.png new file mode 100644 index 00000000..2d16dea2 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmtranslate.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmtreeview.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmtreeview.png new file mode 100644 index 00000000..b78f646d Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmtreeview.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmtriangle.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmtriangle.png new file mode 100644 index 00000000..9592e253 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmtriangle.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmunion.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmunion.png new file mode 100644 index 00000000..1407fe3a Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmunion.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmwarp.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmwarp.png new file mode 100644 index 00000000..c0f294cd Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr16-action-pmwarp.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmbicubicpatch.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmbicubicpatch.png new file mode 100644 index 00000000..4dedf979 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmbicubicpatch.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmblendmapmodifiers.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmblendmapmodifiers.png new file mode 100644 index 00000000..15fc5700 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmblendmapmodifiers.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmblob.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmblob.png new file mode 100644 index 00000000..a165af80 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmblob.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmblobcylinder.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmblobcylinder.png new file mode 100644 index 00000000..5dc230f9 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmblobcylinder.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmblobsphere.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmblobsphere.png new file mode 100644 index 00000000..a43cf351 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmblobsphere.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmboundedby.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmboundedby.png new file mode 100644 index 00000000..a8748990 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmboundedby.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmbox.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmbox.png new file mode 100644 index 00000000..1bbdac7c Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmbox.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmbumpmap.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmbumpmap.png new file mode 100644 index 00000000..2371d104 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmbumpmap.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmcamera.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmcamera.png new file mode 100644 index 00000000..51e3079a Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmcamera.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmclippedby.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmclippedby.png new file mode 100644 index 00000000..e7653cb1 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmclippedby.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmcolorlist.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmcolorlist.png new file mode 100644 index 00000000..b94946d3 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmcolorlist.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmcolormap.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmcolormap.png new file mode 100644 index 00000000..775db294 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmcolormap.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmcolormapdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmcolormapdeclare.png new file mode 100644 index 00000000..d4033601 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmcolormapdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmcomment.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmcomment.png new file mode 100644 index 00000000..348ed6fa Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmcomment.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmcone.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmcone.png new file mode 100644 index 00000000..8cb55a7a Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmcone.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigurecolors.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigurecolors.png new file mode 100644 index 00000000..5775bb49 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigurecolors.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguredialogview.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguredialogview.png new file mode 100644 index 00000000..5951a63b Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguredialogview.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguregraphicalview.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguregraphicalview.png new file mode 100644 index 00000000..87ce6705 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguregraphicalview.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguregrid.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguregrid.png new file mode 100644 index 00000000..f378b405 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguregrid.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureobjectlibrary.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureobjectlibrary.png new file mode 100644 index 00000000..83a72f37 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureobjectlibrary.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureobjects.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureobjects.png new file mode 100644 index 00000000..16fc0bdf Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureobjects.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureopengl.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureopengl.png new file mode 100644 index 00000000..03c1efca Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureopengl.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigurepovray.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigurepovray.png new file mode 100644 index 00000000..de26c9ca Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigurepovray.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguretexturepreview.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguretexturepreview.png new file mode 100644 index 00000000..6cd4ee02 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguretexturepreview.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureviewlayout.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureviewlayout.png new file mode 100644 index 00000000..502eb876 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureviewlayout.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmcylinder.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmcylinder.png new file mode 100644 index 00000000..7fe73163 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmcylinder.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmdeclare.png new file mode 100644 index 00000000..840d56eb Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmdensity.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmdensity.png new file mode 100644 index 00000000..057210fb Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmdensity.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitydeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitydeclare.png new file mode 100644 index 00000000..c38fe00c Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitydeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitylist.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitylist.png new file mode 100644 index 00000000..3c260d9e Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitylist.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitymap.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitymap.png new file mode 100644 index 00000000..3aabb850 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitymap.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitymapdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitymapdeclare.png new file mode 100644 index 00000000..2fc8e38b Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitymapdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmdifference.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmdifference.png new file mode 100644 index 00000000..0ac4238e Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmdifference.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmdisc.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmdisc.png new file mode 100644 index 00000000..536cc8a0 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmdisc.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmdrag.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmdrag.png new file mode 100644 index 00000000..5a5c703d Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmdrag.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmfinish.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmfinish.png new file mode 100644 index 00000000..070f16d1 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmfinish.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmfinishdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmfinishdeclare.png new file mode 100644 index 00000000..8d8359c5 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmfinishdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmfog.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmfog.png new file mode 100644 index 00000000..23a5e5ee Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmfog.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmfogdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmfogdeclare.png new file mode 100644 index 00000000..df4460d1 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmfogdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmglobalphotons.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmglobalphotons.png new file mode 100644 index 00000000..b97c1337 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmglobalphotons.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmglobalsettings.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmglobalsettings.png new file mode 100644 index 00000000..c87764bc Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmglobalsettings.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmheightfield.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmheightfield.png new file mode 100644 index 00000000..64b767b4 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmheightfield.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmimagemap.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmimagemap.png new file mode 100644 index 00000000..a93604e5 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmimagemap.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pminserterrors.png b/kpovmodeler/pics/crystalsvg/cr22-action-pminserterrors.png new file mode 100644 index 00000000..fab5a4eb Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pminserterrors.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pminterior.png b/kpovmodeler/pics/crystalsvg/cr22-action-pminterior.png new file mode 100644 index 00000000..d3c3a66f Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pminterior.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pminteriordeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pminteriordeclare.png new file mode 100644 index 00000000..20c5880e Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pminteriordeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pminteriortexture.png b/kpovmodeler/pics/crystalsvg/cr22-action-pminteriortexture.png new file mode 100644 index 00000000..bf6b6d00 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pminteriortexture.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pminteriortexturedeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pminteriortexturedeclare.png new file mode 100644 index 00000000..2566437f Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pminteriortexturedeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmintersection.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmintersection.png new file mode 100644 index 00000000..edc287ff Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmintersection.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmisosurface.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmisosurface.png new file mode 100644 index 00000000..cbbad58f Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmisosurface.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmjuliafractal.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmjuliafractal.png new file mode 100644 index 00000000..ce90ba06 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmjuliafractal.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmlathe.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmlathe.png new file mode 100644 index 00000000..572ca904 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmlathe.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmlight.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmlight.png new file mode 100644 index 00000000..ebb36242 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmlight.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmlightgroup.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmlightgroup.png new file mode 100644 index 00000000..49e1aee6 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmlightgroup.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmlistpattern.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmlistpattern.png new file mode 100644 index 00000000..76fa8d8b Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmlistpattern.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmlookslike.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmlookslike.png new file mode 100644 index 00000000..d70ce958 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmlookslike.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmmaterial.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmmaterial.png new file mode 100644 index 00000000..9cb8498d Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmmaterial.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmmaterialdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmmaterialdeclare.png new file mode 100644 index 00000000..317b793b Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmmaterialdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmmaterialmap.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmmaterialmap.png new file mode 100644 index 00000000..d352f4c1 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmmaterialmap.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmmatrix.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmmatrix.png new file mode 100644 index 00000000..3b9524e5 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmmatrix.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmmedia.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmmedia.png new file mode 100644 index 00000000..dcb93a22 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmmedia.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmmediadeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmmediadeclare.png new file mode 100644 index 00000000..e09b71c9 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmmediadeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmmerge.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmmerge.png new file mode 100644 index 00000000..ce93f989 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmmerge.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmmesh.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmmesh.png new file mode 100644 index 00000000..74ffa376 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmmesh.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmnormal.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmnormal.png new file mode 100644 index 00000000..c2838b98 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmnormal.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmnormaldeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmnormaldeclare.png new file mode 100644 index 00000000..ce3841d8 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmnormaldeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmnormallist.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmnormallist.png new file mode 100644 index 00000000..ec5d3695 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmnormallist.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmnormalmap.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmnormalmap.png new file mode 100644 index 00000000..435b0b74 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmnormalmap.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmnormalmapdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmnormalmapdeclare.png new file mode 100644 index 00000000..2cabff95 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmnormalmapdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmobjectdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmobjectdeclare.png new file mode 100644 index 00000000..b1d2947f Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmobjectdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmobjectlink.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmobjectlink.png new file mode 100644 index 00000000..f6e2a32f Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmobjectlink.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmpattern.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmpattern.png new file mode 100644 index 00000000..f2620041 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmpattern.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmphotons.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmphotons.png new file mode 100644 index 00000000..4e2f161e Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmphotons.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmpigment.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmpigment.png new file mode 100644 index 00000000..6a2103d0 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmpigment.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentdeclare.png new file mode 100644 index 00000000..5b0e22e7 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentlist.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentlist.png new file mode 100644 index 00000000..568beead Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentlist.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentmap.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentmap.png new file mode 100644 index 00000000..36466942 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentmap.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentmapdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentmapdeclare.png new file mode 100644 index 00000000..8bbee2e9 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentmapdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmplane.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmplane.png new file mode 100644 index 00000000..f5430a72 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmplane.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmpolynom.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmpolynom.png new file mode 100644 index 00000000..67e4b46c Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmpolynom.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmprism.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmprism.png new file mode 100644 index 00000000..ca3dd0b5 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmprism.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmprojectedthrough.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmprojectedthrough.png new file mode 100644 index 00000000..4f7712e6 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmprojectedthrough.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmquickcolor.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmquickcolor.png new file mode 100644 index 00000000..4a2c7c25 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmquickcolor.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmradiosity.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmradiosity.png new file mode 100644 index 00000000..59f923cf Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmradiosity.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmrainbow.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmrainbow.png new file mode 100644 index 00000000..3e0b1021 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmrainbow.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmrainbowdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmrainbowdeclare.png new file mode 100644 index 00000000..f92ab03e Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmrainbowdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmraw.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmraw.png new file mode 100644 index 00000000..d8270f7c Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmraw.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmrender.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmrender.png new file mode 100644 index 00000000..6aa2b69f Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmrender.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmrenderpreview.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmrenderpreview.png new file mode 100644 index 00000000..0227ab0c Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmrenderpreview.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmrendersettings.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmrendersettings.png new file mode 100644 index 00000000..cb6b2e9a Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmrendersettings.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmrotate.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmrotate.png new file mode 100644 index 00000000..22a5af44 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmrotate.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmscale.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmscale.png new file mode 100644 index 00000000..e7820f60 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmscale.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmscene.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmscene.png new file mode 100644 index 00000000..47c9dc56 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmscene.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmskysphere.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmskysphere.png new file mode 100644 index 00000000..cad5cdf5 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmskysphere.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmskyspheredeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmskyspheredeclare.png new file mode 100644 index 00000000..4aaafa28 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmskyspheredeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmslope.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmslope.png new file mode 100644 index 00000000..42abb1b4 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmslope.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmslopemap.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmslopemap.png new file mode 100644 index 00000000..4efbb6ef Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmslopemap.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmslopemapdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmslopemapdeclare.png new file mode 100644 index 00000000..19307196 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmslopemapdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmsolidcolor.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmsolidcolor.png new file mode 100644 index 00000000..e8cbfc51 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmsolidcolor.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmsor.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmsor.png new file mode 100644 index 00000000..1a9bdf7a Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmsor.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmsphere.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmsphere.png new file mode 100644 index 00000000..bb9b6f2d Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmsphere.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmspheresweep.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmspheresweep.png new file mode 100644 index 00000000..fe94fb83 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmspheresweep.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmsqe.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmsqe.png new file mode 100644 index 00000000..a3d9152d Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmsqe.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmtext.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmtext.png new file mode 100644 index 00000000..25fc94c3 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmtext.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmtexture.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmtexture.png new file mode 100644 index 00000000..a2f13e15 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmtexture.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturedeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturedeclare.png new file mode 100644 index 00000000..e40843f0 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturedeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturelist.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturelist.png new file mode 100644 index 00000000..e497f164 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturelist.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturemap.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturemap.png new file mode 100644 index 00000000..282acdf6 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturemap.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturemapdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturemapdeclare.png new file mode 100644 index 00000000..2f046f10 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturemapdeclare.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmtorus.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmtorus.png new file mode 100644 index 00000000..ab187e64 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmtorus.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmtranslate.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmtranslate.png new file mode 100644 index 00000000..3234c8fe Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmtranslate.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmtriangle.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmtriangle.png new file mode 100644 index 00000000..4cae6980 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmtriangle.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmunion.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmunion.png new file mode 100644 index 00000000..aacb8776 Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmunion.png differ diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmwarp.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmwarp.png new file mode 100644 index 00000000..e98e139c Binary files /dev/null and b/kpovmodeler/pics/crystalsvg/cr22-action-pmwarp.png differ diff --git a/kpovmodeler/pics/locolor/Makefile.am b/kpovmodeler/pics/locolor/Makefile.am new file mode 100644 index 00000000..66481ab6 --- /dev/null +++ b/kpovmodeler/pics/locolor/Makefile.am @@ -0,0 +1,2 @@ +pmtoolbardir = $(kde_datadir)/kpovmodeler/icons +pmtoolbar_ICON = AUTO diff --git a/kpovmodeler/pics/locolor/lo16-action-pmaddpoint.png b/kpovmodeler/pics/locolor/lo16-action-pmaddpoint.png new file mode 100644 index 00000000..b3c7cab4 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmaddpoint.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmaddpointabove.png b/kpovmodeler/pics/locolor/lo16-action-pmaddpointabove.png new file mode 100644 index 00000000..4310c761 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmaddpointabove.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmaddsubprism.png b/kpovmodeler/pics/locolor/lo16-action-pmaddsubprism.png new file mode 100644 index 00000000..c292daab Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmaddsubprism.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmbicubicpatch.png b/kpovmodeler/pics/locolor/lo16-action-pmbicubicpatch.png new file mode 100644 index 00000000..dd3752c9 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmbicubicpatch.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmblendmapmodifiers.png b/kpovmodeler/pics/locolor/lo16-action-pmblendmapmodifiers.png new file mode 100644 index 00000000..c95808c9 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmblendmapmodifiers.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmblob.png b/kpovmodeler/pics/locolor/lo16-action-pmblob.png new file mode 100644 index 00000000..f5dfe034 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmblob.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmblobcylinder.png b/kpovmodeler/pics/locolor/lo16-action-pmblobcylinder.png new file mode 100644 index 00000000..a320ec3a Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmblobcylinder.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmblobsphere.png b/kpovmodeler/pics/locolor/lo16-action-pmblobsphere.png new file mode 100644 index 00000000..f45f5433 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmblobsphere.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmboundedby.png b/kpovmodeler/pics/locolor/lo16-action-pmboundedby.png new file mode 100644 index 00000000..4d167b4d Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmboundedby.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmbox.png b/kpovmodeler/pics/locolor/lo16-action-pmbox.png new file mode 100644 index 00000000..6e8665d4 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmbox.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmbumpmap.png b/kpovmodeler/pics/locolor/lo16-action-pmbumpmap.png new file mode 100644 index 00000000..17df5809 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmbumpmap.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmcamera.png b/kpovmodeler/pics/locolor/lo16-action-pmcamera.png new file mode 100644 index 00000000..264a4e9f Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmcamera.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmclippedby.png b/kpovmodeler/pics/locolor/lo16-action-pmclippedby.png new file mode 100644 index 00000000..98394ece Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmclippedby.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmcomment.png b/kpovmodeler/pics/locolor/lo16-action-pmcomment.png new file mode 100644 index 00000000..78b0a3f0 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmcomment.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmcone.png b/kpovmodeler/pics/locolor/lo16-action-pmcone.png new file mode 100644 index 00000000..dc369725 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmcone.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmcylinder.png b/kpovmodeler/pics/locolor/lo16-action-pmcylinder.png new file mode 100644 index 00000000..7147b4ca Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmcylinder.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmdeclare.png b/kpovmodeler/pics/locolor/lo16-action-pmdeclare.png new file mode 100644 index 00000000..e56be4e9 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmdeclare.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmdensity.png b/kpovmodeler/pics/locolor/lo16-action-pmdensity.png new file mode 100644 index 00000000..58fe3d6f Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmdensity.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmdensitydeclare.png b/kpovmodeler/pics/locolor/lo16-action-pmdensitydeclare.png new file mode 100644 index 00000000..9b826d4a Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmdensitydeclare.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmdensitylist.png b/kpovmodeler/pics/locolor/lo16-action-pmdensitylist.png new file mode 100644 index 00000000..d4d9170b Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmdensitylist.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmdensitymap.png b/kpovmodeler/pics/locolor/lo16-action-pmdensitymap.png new file mode 100644 index 00000000..69f9fda7 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmdensitymap.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmdensitymapdeclare.png b/kpovmodeler/pics/locolor/lo16-action-pmdensitymapdeclare.png new file mode 100644 index 00000000..0b26c273 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmdensitymapdeclare.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmdifference.png b/kpovmodeler/pics/locolor/lo16-action-pmdifference.png new file mode 100644 index 00000000..d2551828 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmdifference.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmdisc.png b/kpovmodeler/pics/locolor/lo16-action-pmdisc.png new file mode 100644 index 00000000..095adf32 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmdisc.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmdrag.png b/kpovmodeler/pics/locolor/lo16-action-pmdrag.png new file mode 100644 index 00000000..65aba8ba Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmdrag.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmfog.png b/kpovmodeler/pics/locolor/lo16-action-pmfog.png new file mode 100644 index 00000000..89346120 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmfog.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmfogdeclare.png b/kpovmodeler/pics/locolor/lo16-action-pmfogdeclare.png new file mode 100644 index 00000000..944720cb Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmfogdeclare.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmglobalsettings.png b/kpovmodeler/pics/locolor/lo16-action-pmglobalsettings.png new file mode 100644 index 00000000..b8951994 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmglobalsettings.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmheightfield.png b/kpovmodeler/pics/locolor/lo16-action-pmheightfield.png new file mode 100644 index 00000000..5f4b7871 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmheightfield.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmimagemap.png b/kpovmodeler/pics/locolor/lo16-action-pmimagemap.png new file mode 100644 index 00000000..2ece117d Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmimagemap.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pminserterrors.png b/kpovmodeler/pics/locolor/lo16-action-pminserterrors.png new file mode 100644 index 00000000..a8edc396 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pminserterrors.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pminsertfirstchild.png b/kpovmodeler/pics/locolor/lo16-action-pminsertfirstchild.png new file mode 100644 index 00000000..5ee47f17 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pminsertfirstchild.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pminsertlastchild.png b/kpovmodeler/pics/locolor/lo16-action-pminsertlastchild.png new file mode 100644 index 00000000..cc7193f7 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pminsertlastchild.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pminsertsibling.png b/kpovmodeler/pics/locolor/lo16-action-pminsertsibling.png new file mode 100644 index 00000000..a0bca16f Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pminsertsibling.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmintersection.png b/kpovmodeler/pics/locolor/lo16-action-pmintersection.png new file mode 100644 index 00000000..954eae50 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmintersection.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmjuliafractal.png b/kpovmodeler/pics/locolor/lo16-action-pmjuliafractal.png new file mode 100644 index 00000000..4b88db07 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmjuliafractal.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmlathe.png b/kpovmodeler/pics/locolor/lo16-action-pmlathe.png new file mode 100644 index 00000000..181e4446 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmlathe.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmlight.png b/kpovmodeler/pics/locolor/lo16-action-pmlight.png new file mode 100644 index 00000000..ec9c456d Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmlight.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmlistpattern.png b/kpovmodeler/pics/locolor/lo16-action-pmlistpattern.png new file mode 100644 index 00000000..6a85bc72 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmlistpattern.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmlookslike.png b/kpovmodeler/pics/locolor/lo16-action-pmlookslike.png new file mode 100644 index 00000000..6f7a439f Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmlookslike.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmmaterialmap.png b/kpovmodeler/pics/locolor/lo16-action-pmmaterialmap.png new file mode 100644 index 00000000..c964f8a4 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmmaterialmap.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmmatrix.png b/kpovmodeler/pics/locolor/lo16-action-pmmatrix.png new file mode 100644 index 00000000..096bad00 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmmatrix.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmmerge.png b/kpovmodeler/pics/locolor/lo16-action-pmmerge.png new file mode 100644 index 00000000..04e71ed2 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmmerge.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmobjectdeclare.png b/kpovmodeler/pics/locolor/lo16-action-pmobjectdeclare.png new file mode 100644 index 00000000..cd562250 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmobjectdeclare.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmobjectlink.png b/kpovmodeler/pics/locolor/lo16-action-pmobjectlink.png new file mode 100644 index 00000000..479664f6 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmobjectlink.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmpigment.png b/kpovmodeler/pics/locolor/lo16-action-pmpigment.png new file mode 100644 index 00000000..0f59413c Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmpigment.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmpigmentdeclare.png b/kpovmodeler/pics/locolor/lo16-action-pmpigmentdeclare.png new file mode 100644 index 00000000..efdada03 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmpigmentdeclare.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmplane.png b/kpovmodeler/pics/locolor/lo16-action-pmplane.png new file mode 100644 index 00000000..7b2029d9 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmplane.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmpolynom.png b/kpovmodeler/pics/locolor/lo16-action-pmpolynom.png new file mode 100644 index 00000000..d2858866 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmpolynom.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmprism.png b/kpovmodeler/pics/locolor/lo16-action-pmprism.png new file mode 100644 index 00000000..ce96f3e5 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmprism.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmquickcolor.png b/kpovmodeler/pics/locolor/lo16-action-pmquickcolor.png new file mode 100644 index 00000000..109131d8 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmquickcolor.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmrainbow.png b/kpovmodeler/pics/locolor/lo16-action-pmrainbow.png new file mode 100644 index 00000000..ddd11480 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmrainbow.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmrainbowdeclare.png b/kpovmodeler/pics/locolor/lo16-action-pmrainbowdeclare.png new file mode 100644 index 00000000..47906a3a Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmrainbowdeclare.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmraw.png b/kpovmodeler/pics/locolor/lo16-action-pmraw.png new file mode 100644 index 00000000..cb0ce235 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmraw.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmremovepoint.png b/kpovmodeler/pics/locolor/lo16-action-pmremovepoint.png new file mode 100644 index 00000000..0be182fb Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmremovepoint.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmrender.png b/kpovmodeler/pics/locolor/lo16-action-pmrender.png new file mode 100644 index 00000000..a2fc7d79 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmrender.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmrenderpreview.png b/kpovmodeler/pics/locolor/lo16-action-pmrenderpreview.png new file mode 100644 index 00000000..feb2f7b1 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmrenderpreview.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmrendersettings.png b/kpovmodeler/pics/locolor/lo16-action-pmrendersettings.png new file mode 100644 index 00000000..f19b0eea Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmrendersettings.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmrotate.png b/kpovmodeler/pics/locolor/lo16-action-pmrotate.png new file mode 100644 index 00000000..744f927c Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmrotate.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmscale.png b/kpovmodeler/pics/locolor/lo16-action-pmscale.png new file mode 100644 index 00000000..ca553a0f Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmscale.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmscene.png b/kpovmodeler/pics/locolor/lo16-action-pmscene.png new file mode 100644 index 00000000..61dfa78a Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmscene.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmskysphere.png b/kpovmodeler/pics/locolor/lo16-action-pmskysphere.png new file mode 100644 index 00000000..aaf0f47a Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmskysphere.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmskyspheredeclare.png b/kpovmodeler/pics/locolor/lo16-action-pmskyspheredeclare.png new file mode 100644 index 00000000..b9d719ff Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmskyspheredeclare.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmsolidcolor.png b/kpovmodeler/pics/locolor/lo16-action-pmsolidcolor.png new file mode 100644 index 00000000..38840359 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmsolidcolor.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmsor.png b/kpovmodeler/pics/locolor/lo16-action-pmsor.png new file mode 100644 index 00000000..c38eb6ae Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmsor.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmsphere.png b/kpovmodeler/pics/locolor/lo16-action-pmsphere.png new file mode 100644 index 00000000..a7ea2461 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmsphere.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmsqr.png b/kpovmodeler/pics/locolor/lo16-action-pmsqr.png new file mode 100644 index 00000000..cfaa5aff Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmsqr.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmtext.png b/kpovmodeler/pics/locolor/lo16-action-pmtext.png new file mode 100644 index 00000000..04987349 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmtext.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmtexture.png b/kpovmodeler/pics/locolor/lo16-action-pmtexture.png new file mode 100644 index 00000000..d84fcd66 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmtexture.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmtexturedeclare.png b/kpovmodeler/pics/locolor/lo16-action-pmtexturedeclare.png new file mode 100644 index 00000000..8984df92 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmtexturedeclare.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmtorus.png b/kpovmodeler/pics/locolor/lo16-action-pmtorus.png new file mode 100644 index 00000000..a09660ab Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmtorus.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmtranslate.png b/kpovmodeler/pics/locolor/lo16-action-pmtranslate.png new file mode 100644 index 00000000..2d16dea2 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmtranslate.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmtriangle.png b/kpovmodeler/pics/locolor/lo16-action-pmtriangle.png new file mode 100644 index 00000000..dfe6ed44 Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmtriangle.png differ diff --git a/kpovmodeler/pics/locolor/lo16-action-pmunion.png b/kpovmodeler/pics/locolor/lo16-action-pmunion.png new file mode 100644 index 00000000..1407fe3a Binary files /dev/null and b/kpovmodeler/pics/locolor/lo16-action-pmunion.png differ diff --git a/kpovmodeler/pm2dcontrolpoint.cpp b/kpovmodeler/pm2dcontrolpoint.cpp new file mode 100644 index 00000000..66e7a85a --- /dev/null +++ b/kpovmodeler/pm2dcontrolpoint.cpp @@ -0,0 +1,207 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pm2dcontrolpoint.h" +#include "pmmath.h" +#include + +PM2DControlPoint::PM2DControlPoint( const PMVector& point, + PM2DControlPoint::CPType type, int id, + const QString& description ) + : PMControlPoint( id, description ) +{ + m_point = point; + m_type = type; + m_thirdCoordinate = 0; + m_scale = 1.0; + m_pBasePoint = 0; + m_pLatheLink = 0; +} + +void PM2DControlPoint::graphicalChangeStarted( ) +{ + QPtrListIterator it( m_linkedPoints ); + for( ; *it; ++it ) + if( !( *it )->selected( ) ) + ( *it )->graphicalChangeStarted( ); + + m_original2DPoint = m_point; + m_originalPoint = to3D( m_point ); +} + +void PM2DControlPoint::graphicalChange( const PMVector& startPoint, + const PMVector& /*viewNormal*/, + const PMVector& endPoint ) +{ + if( m_pBasePoint && m_pBasePoint->selected( ) ) + return; + + m_point = to2D( m_originalPoint + endPoint - startPoint ); + + if( m_pLatheLink && m_pLatheLink->selected( ) ) + { + PM2DControlPoint* ll = m_pLatheLink; + PMVector op = ll->to2D( ll->m_originalPoint + endPoint - startPoint ); + + m_point = to2D( m_originalPoint + endPoint - startPoint ); + if( ( m_point - m_original2DPoint ).abs( ) < + ( op - ll->m_original2DPoint ).abs( ) ) + m_point = op; + } + + QPtrListIterator it( m_linkedPoints ); + for( ; *it; ++it ) + { + ( *it )->m_point = m_point + ( *it )->m_original2DPoint + - m_original2DPoint; + ( *it )->setChanged( ); + } +} + +void PM2DControlPoint::setBasePoint( PM2DControlPoint* p ) +{ + if( p != m_pBasePoint ) + { + if( m_pBasePoint ) + m_pBasePoint->removeLinkedPoint( this ); + m_pBasePoint = p; + if( m_pBasePoint ) + m_pBasePoint->addLinkedPoint( this ); + } +} + +void PM2DControlPoint::snapToGrid( ) +{ + int i; + double d = moveGrid( ); + bool diff = false; + PMVector change( 2 ); + + if( m_pBasePoint && m_pBasePoint->selected( ) ) + { + m_point -= m_pBasePoint->m_point; + diff = true; + } + + if( !approxZero( d ) ) + { + for( i = 0; i < 2; i++ ) + { + change[i] = -m_point[i]; + m_point[i] = rint( m_point[i] / d ) * d; + change[i] += m_point[i]; + } + } + + if( diff ) + m_point += m_pBasePoint->m_point; + + QPtrListIterator it( m_linkedPoints ); + for( ; *it; ++it ) + { + ( *it )->m_point += change; + ( *it )->setChanged( ); + } + + setChanged( ); +} + +PMVector PM2DControlPoint::to2D( const PMVector& v ) const +{ + PMVector result( 2 ); + switch( m_type ) + { + case PM2DXY: + result[0] = v[0]; + result[1] = v[1]; + break; + case PM2DXZ: + result[0] = v[0]; + result[1] = v[2]; + break; + case PM2DYZ: + result[0] = v[1]; + result[1] = v[2]; + break; + case PM2DYX: + result[0] = v[1]; + result[1] = v[0]; + break; + case PM2DZX: + result[0] = v[2]; + result[1] = v[0]; + break; + case PM2DZY: + result[0] = v[2]; + result[1] = v[1]; + break; + } + if( !approxZero( m_scale ) ) + result /= m_scale; + return result; +} + +PMVector PM2DControlPoint::to3D( const PMVector& v ) const +{ + PMVector vec( v * m_scale ); + PMVector result( 3 ); + switch( m_type ) + { + case PM2DXY: + result[0] = vec[0]; + result[1] = vec[1]; + result[2] = m_thirdCoordinate; + break; + case PM2DXZ: + result[0] = vec[0]; + result[1] = m_thirdCoordinate; + result[2] = vec[1]; + break; + case PM2DYZ: + result[0] = m_thirdCoordinate; + result[1] = vec[0]; + result[2] = vec[1]; + break; + case PM2DYX: + result[1] = vec[0]; + result[0] = vec[1]; + result[2] = m_thirdCoordinate; + break; + case PM2DZX: + result[2] = vec[0]; + result[0] = vec[1]; + result[1] = m_thirdCoordinate; + break; + case PM2DZY: + result[2] = vec[0]; + result[1] = vec[1]; + result[0] = m_thirdCoordinate; + break; + } + return result; +} + +void PM2DControlPoint::addLinkedPoint( PM2DControlPoint* p ) +{ + if( !m_linkedPoints.containsRef( p ) ) + m_linkedPoints.append( p ); +} + +void PM2DControlPoint::removeLinkedPoint( PM2DControlPoint* p ) +{ + m_linkedPoints.removeRef( p ); +} diff --git a/kpovmodeler/pm2dcontrolpoint.h b/kpovmodeler/pm2dcontrolpoint.h new file mode 100644 index 00000000..f949570b --- /dev/null +++ b/kpovmodeler/pm2dcontrolpoint.h @@ -0,0 +1,135 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PM2DCONTROLPOINT_H +#define PM2DCONTROLPOINT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + + +#include "pmcontrolpoint.h" +#include + +/** + * Class for free moveable control points + */ +class PM2DControlPoint : public PMControlPoint +{ +public: + /** + * Type enum + */ + enum CPType { PM2DXY, PM2DYX, PM2DXZ, PM2DZX, PM2DYZ, PM2DZY }; + /** + * Creates a PM2DControlPoint with id. Point has to be a 2D vector. + */ + PM2DControlPoint( const PMVector& point, CPType type, + int id, const QString& description ); + /** + * Deletes the PM2DControlPoint + */ + virtual ~PM2DControlPoint( ) { }; + + /** */ + virtual PMVector position( ) const { return to3D( m_point ); } + /** + * Sets the 2d coordinates of the control point + */ + void setPoint( const PMVector& newPoint ) { m_point = newPoint; } + /** + * 2d coordinates of the control point + */ + PMVector point( ) const { return m_point; } + /** */ + virtual void snapToGrid( ); + /** + * Returns the third coordinate + */ + double thirdCoordinate( ) const { return m_thirdCoordinate; } + /** + * Sets the third coordinate + */ + void setThirdCoordinate( double d ) { m_thirdCoordinate = d; } + /** + * Returns the 2d scale + */ + double scale( ) const { return m_scale; } + /** + * Sets the scale + */ + void setScale( double s ) { m_scale = s; } + + /** + * Sets the base point. + * + * If a base point is set, an extra line is shown between + * the base point and this control point. + */ + void setBasePoint( PM2DControlPoint* p ); + /** + * Returns the base point + */ + PM2DControlPoint* basePoint( ) const { return m_pBasePoint; } + /** + * This method is used by the lathe object to link + * the control points in the xy and xz plane. These points are + * synchronized if both are selected. + */ + void setLatheLink( PM2DControlPoint* p ) { m_pLatheLink = p; } + /** + * Returns the linked control point for lathe points + */ + PM2DControlPoint* latheLink( ) const { return m_pLatheLink; } + + /** */ + virtual bool hasExtraLine( ) const { return m_pBasePoint; } + /** */ + virtual PMVector extraLineStart( ) const { return position( ); } + /** */ + virtual PMVector extraLineEnd( ) const + { + if( m_pBasePoint ) + return m_pBasePoint->position( ); + return PMVector( 0, 0, 0 ); + } + +protected: + /** */ + virtual void graphicalChangeStarted( ); + /** */ + virtual void graphicalChange( const PMVector& startPoint, + const PMVector& viewNormal, + const PMVector& endPoint ); +private: + PMVector to2D( const PMVector& v ) const; + PMVector to3D( const PMVector& v ) const; + void addLinkedPoint( PM2DControlPoint* p ); + void removeLinkedPoint( PM2DControlPoint* p ); + + PMVector m_point, m_originalPoint, m_original2DPoint; + CPType m_type; + double m_thirdCoordinate; + double m_scale; + PM2DControlPoint* m_pBasePoint; + QPtrList m_linkedPoints; + PM2DControlPoint* m_pLatheLink; +}; + +#endif diff --git a/kpovmodeler/pm3dcontrolpoint.cpp b/kpovmodeler/pm3dcontrolpoint.cpp new file mode 100644 index 00000000..7bd4e10e --- /dev/null +++ b/kpovmodeler/pm3dcontrolpoint.cpp @@ -0,0 +1,49 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pm3dcontrolpoint.h" +#include "pmmath.h" +#include + +PM3DControlPoint::PM3DControlPoint( const PMVector& point, int id, + const QString& description ) + : PMControlPoint( id, description ) +{ + m_point = point; +} + +void PM3DControlPoint::graphicalChangeStarted( ) +{ + m_originalPoint = m_point; +} + +void PM3DControlPoint::graphicalChange( const PMVector& startPoint, + const PMVector& /*viewNormal*/, + const PMVector& endPoint ) +{ + m_point = m_originalPoint + endPoint - startPoint; +} + +void PM3DControlPoint::snapToGrid( ) +{ + int i; + double d = moveGrid( ); + if( !approxZero( d ) ) + for( i = 0; i < 3; i++ ) + m_point[i] = rint( m_point[i] / d ) * d; + setChanged( ); +} diff --git a/kpovmodeler/pm3dcontrolpoint.h b/kpovmodeler/pm3dcontrolpoint.h new file mode 100644 index 00000000..765c4e43 --- /dev/null +++ b/kpovmodeler/pm3dcontrolpoint.h @@ -0,0 +1,68 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PM3DCONTROLPOINT_H +#define PM3DCONTROLPOINT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + + +#include "pmcontrolpoint.h" + +/** + * Class for free moveable control points + */ +class PM3DControlPoint : public PMControlPoint +{ +public: + /** + * Creates a PM3DControlPoint with id. + */ + PM3DControlPoint( const PMVector& point, int id, const QString& description ); + /** + * Deletes the PM3DControlPoint + */ + virtual ~PM3DControlPoint( ) { }; + + /** */ + virtual PMVector position( ) const { return m_point; } + /** + * Sets the 3d coordinates of the control point + */ + void setPoint( const PMVector& newPoint ) { m_point = newPoint; } + /** + * 3d coordinates of the control point + */ + PMVector point( ) const { return m_point; } + /** */ + virtual void snapToGrid( ); + +protected: + /** */ + virtual void graphicalChangeStarted( ); + /** */ + virtual void graphicalChange( const PMVector& startPoint, + const PMVector& viewNormal, + const PMVector& endPoint ); +private: + PMVector m_point, m_originalPoint; +}; + +#endif diff --git a/kpovmodeler/pmactions.cpp b/kpovmodeler/pmactions.cpp new file mode 100644 index 00000000..b84e42da --- /dev/null +++ b/kpovmodeler/pmactions.cpp @@ -0,0 +1,254 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmactions.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pmdebug.h" + +// Fixed widths are calculated wrong in a toolbar. +// Fixed sizeHint for the combo box to return +// at least the minimum size +class PMComboBox : public QComboBox +{ +public: + PMComboBox( QWidget* parent, const char* name = 0 ) + : QComboBox( parent, name ) + { + } + + virtual QSize minimumSizeHint( ) const + { + QSize s = QComboBox::minimumSizeHint( ); + return s.expandedTo( minimumSize( ) ); + } + virtual QSize sizeHint( ) const + { + QSize s = QComboBox::sizeHint( ); + return s.expandedTo( minimumSize( ) ); + } +}; + +PMComboAction::PMComboAction( const QString& text, int accel, const QObject* receiver, const char* member, + QObject* parent, const char* name ) + : KAction( text, accel, parent, name ) +{ + m_receiver = receiver; + m_member = member; + m_minWidth = 0; + m_maxWidth = 0; +} + +PMComboAction::~PMComboAction( ) +{ +} + +int PMComboAction::plug( QWidget* w, int index ) +{ + if( !w->inherits( "KToolBar" ) ) + return -1; + + KToolBar* toolBar = ( KToolBar* ) w; + + int id = KAction::getToolButtonID( ); + + QComboBox* comboBox = new PMComboBox( toolBar ); + if( m_minWidth > 0 ) + comboBox->setMinimumWidth( m_minWidth ); + if( m_maxWidth > 0 ) + comboBox->setMaximumWidth( m_maxWidth ); + + toolBar->insertWidget( id, m_minWidth > 0 ? m_minWidth : 300, + comboBox, index ); + connect( comboBox, SIGNAL( activated( int ) ), m_receiver, m_member ); + + addContainer( toolBar, id ); + + connect( toolBar, SIGNAL( destroyed( ) ), this, SLOT( slotDestroyed( ) ) ); + + //toolBar->setItemAutoSized( id, true ); + + m_combo = comboBox; + + emit plugged( ); + + QWhatsThis::add( comboBox, whatsThis( ) ); + + return containerCount( ) - 1; +} + +void PMComboAction::unplug( QWidget *w ) +{ + if( !w->inherits( "KToolBar" ) ) + return; + + KToolBar *toolBar = ( KToolBar* ) w; + + int idx = findContainer( w ); + + toolBar->removeItem( itemId( idx ) ); + + removeContainer( idx ); + m_combo = 0L; +} + + +// Use a toolbutton instead of a label so it is styled correctly. +// copied from konq_actions.cc +class PMToolBarLabel : public QToolButton +{ +public: + PMToolBarLabel( const QString& text, QWidget* parent = 0, const char* name = 0 ) + : QToolButton( parent, name ) + { + setText( text ); + } +protected: + QSize sizeHint( ) const + { + int w = fontMetrics( ).width( text( ) ); + int h = fontMetrics( ).height( ); + return QSize( w, h ); + } + void drawButton( QPainter* p ) + { +#if ( QT_VERSION >= 300 ) + // Draw the background + style( ).drawComplexControl( QStyle::CC_ToolButton, p, this, rect( ), colorGroup( ), + QStyle::Style_Enabled, QStyle::SC_ToolButton ); + // Draw the label + style( ).drawControl( QStyle::CE_ToolButtonLabel, p, this, rect( ), colorGroup( ), + QStyle::Style_Enabled ); +#else + p->drawText( rect( ), Qt::AlignVCenter | Qt::AlignLeft, text( ) ); +#endif + } +}; + +PMLabelAction::PMLabelAction( const QString &text, QObject *parent, const char *name ) + : KAction( text, 0, parent, name ) +{ + m_button = 0; +} + +int PMLabelAction::plug( QWidget *widget, int index ) +{ + //do not call the previous implementation here + + if( widget->inherits( "KToolBar" ) ) + { + KToolBar* tb = ( KToolBar* ) widget; + + int id = KAction::getToolButtonID( ); + + m_button = new PMToolBarLabel( text( ), widget ); + tb->insertWidget( id, m_button->width( ), m_button, index ); + + addContainer( tb, id ); + + connect( tb, SIGNAL( destroyed( ) ), this, SLOT( slotDestroyed( ) ) ); + + return containerCount( ) - 1; + } + + return -1; +} + +void PMLabelAction::unplug( QWidget *widget ) +{ + if( widget->inherits( "KToolBar" ) ) + { + KToolBar* bar = ( KToolBar* ) widget; + + int idx = findContainer( bar ); + + if( idx != -1 ) + { + bar->removeItem( itemId( idx ) ); + removeContainer( idx ); + } + + m_button = 0; + return; + } +} + + +PMSpinBoxAction::PMSpinBoxAction( const QString& text, int accel, const QObject* receiver, const char* member, + QObject* parent, const char* name ) + : KAction( text, accel, parent, name ) +{ + m_receiver = receiver; + m_member = member; +} + +PMSpinBoxAction::~PMSpinBoxAction( ) +{ +} + +int PMSpinBoxAction::plug( QWidget* w, int index ) +{ + if( !w->inherits( "KToolBar" ) ) + return -1; + + KToolBar* toolBar = ( KToolBar* ) w; + + int id = KAction::getToolButtonID( ); + + QSpinBox* spinBox = new QSpinBox( -1000, 1000, 1, w ); + toolBar->insertWidget( id, 70, spinBox, index ); + + connect( spinBox, SIGNAL( valueChanged( int ) ), m_receiver, m_member ); + + addContainer( toolBar, id ); + + connect( toolBar, SIGNAL( destroyed( ) ), this, SLOT( slotDestroyed( ) ) ); + //toolBar->setItemAutoSized( id, false ); + + m_spinBox = spinBox; + + emit plugged( ); + + QWhatsThis::add( spinBox, whatsThis( ) ); + + return containerCount( ) - 1; +} + +void PMSpinBoxAction::unplug( QWidget *w ) +{ + if( !w->inherits( "KToolBar" ) ) + return; + + KToolBar *toolBar = (KToolBar *)w; + + int idx = findContainer( w ); + + toolBar->removeItem( itemId( idx ) ); + + removeContainer( idx ); + m_spinBox = 0L; +} + +#include "pmactions.moc" diff --git a/kpovmodeler/pmactions.h b/kpovmodeler/pmactions.h new file mode 100644 index 00000000..f4f8e9e4 --- /dev/null +++ b/kpovmodeler/pmactions.h @@ -0,0 +1,106 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMACTIONS_H +#define PMACTIONS_H + +#include +#include + +class QComboBox; +class QSpinBox; +class QLabel; +class QToolButton; + +/** + * Combobox action for the toolbar. + * + * Copied from konq_actions.h, author: Simon Hausmann + */ +class PMComboAction : public KAction +{ + Q_OBJECT +public: + PMComboAction( const QString& text, int accel, const QObject* receiver, const char* member, QObject* parent, const char* name ); + ~PMComboAction( ); + + virtual int plug( QWidget* w, int index = -1 ); + + virtual void unplug( QWidget* w ); + + QGuardedPtr combo( ) { return m_combo; } + + void setMaximumWidth( int w ) { m_maxWidth = w; } + void setMinimumWidth( int w ) { m_minWidth = w; } + +signals: + void plugged( ); + +private: + QGuardedPtr m_combo; + const QObject* m_receiver; + const char* m_member; + int m_minWidth, m_maxWidth; +}; + +/** + * Label action for the toolbar. + * + * Copied from konq_actions.h, author: Simon Hausmann + */ +class PMLabelAction : public KAction +{ + Q_OBJECT +public: + PMLabelAction( const QString &text, QObject *parent = 0, const char *name = 0 ); + + virtual int plug( QWidget *widget, int index = -1 ); + virtual void unplug( QWidget *widget ); + QToolButton* button( ) { return m_button; } + +private: + QToolButton* m_button; +}; + +/** + * Spinbox action for the toolbar. + */ +class PMSpinBoxAction : public KAction +{ + Q_OBJECT +public: + PMSpinBoxAction( const QString& text, int accel, const QObject* receiver, const char* member, QObject* parent, const char* name ); + ~PMSpinBoxAction( ); + + virtual int plug( QWidget* w, int index = -1 ); + virtual void unplug( QWidget* w ); + + QGuardedPtr spinBox( ) { return m_spinBox; } + +signals: + void plugged( ); + +private: + QGuardedPtr m_spinBox; + const QObject* m_receiver; + const char* m_member; +}; + + +#endif diff --git a/kpovmodeler/pmaddcommand.cpp b/kpovmodeler/pmaddcommand.cpp new file mode 100644 index 00000000..b8d4ea49 --- /dev/null +++ b/kpovmodeler/pmaddcommand.cpp @@ -0,0 +1,233 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmaddcommand.h" +#include "pmcommandmanager.h" +#include "pmpart.h" +#include "pmdeclare.h" +#include "pmerrorflags.h" +#include "pmrecursiveobjectiterator.h" +#include "pmmemento.h" + +#include + +PMAddCommand::PMAddCommand( PMObject* obj, PMObject* parent, PMObject* after ) + : PMCommand( i18n( "Add New %1" ).arg( obj->description( ) ) ) +{ + m_objects.append( obj ); + m_pParent = parent; + m_pAfter = after; + m_executed = false; + m_firstExecution = true; + m_linksCreated = false; + m_pParentChangeMemento = 0; +} + +PMAddCommand::PMAddCommand( const PMObjectList& list, PMObject* parent, + PMObject* after ) + : PMCommand( i18n( "Add Objects" ) ) +{ + m_objects = list; + m_pParent = parent; + m_pAfter = after; + m_executed = false; + m_firstExecution = true; + m_linksCreated = false; + m_pParentChangeMemento = 0; +} + +PMAddCommand::~PMAddCommand( ) +{ + if( !m_executed ) + { + m_objects.setAutoDelete( true ); + m_objects.clear( ); + } + + m_insertErrors.setAutoDelete( true ); + m_insertErrors.clear( ); +} + +void PMAddCommand::execute( PMCommandManager* theManager ) +{ + if( !m_executed ) + { + PMObjectListIterator it( m_objects ); + PMObject* prev = m_pAfter; + PMObjectList errors; + PMObject* current; + bool error = false; + + if( m_firstExecution ) + if( m_pParent->dataChangeOnInsertRemove( ) ) + m_pParent->createMemento( ); + + for( ; it.current( ); ++it ) + { + current = it.current( ); + if( !prev ) + { + if( m_pParent->canInsert( current, 0 ) ) + { + m_pParent->insertChild( current, 0 ); + prev = current; + theManager->cmdObjectChanged( current, PMCAdd ); + } + else + error = true; + } + else + { + if( m_pParent->canInsert( current, prev ) ) + { + m_pParent->insertChildAfter( current, prev ); + prev = current; + theManager->cmdObjectChanged( current, PMCAdd ); + } + else + error = true; + } + + if( error ) + { + errors.append( current ); + theManager->cmdObjectChanged( current, PMCAdd | PMCInsertError ); + if( current->isA( "Declare" ) ) + { + // the object, that couldn't be inserted was a declare, + // remove all links + PMObjectListIterator links = + ( ( PMDeclare* ) current )->linkedObjects( ); + for( ; links.current( ); ++links ) + { + PMObject* l = links.current( ); + if( l->parent( ) ) + l->parent( )->takeChild( l ); + else + m_objects.removeRef( l ); + m_insertErrors.append( l ); + } + } + if( current->linkedObject( ) ) + current->linkedObject( )->removeLinkedObject( current ); + error = false; + } + } + + if( m_pParent->mementoCreated( ) ) + m_pParentChangeMemento = m_pParent->takeMemento( ); + + if( m_pParentChangeMemento ) + { + PMObjectChangeListIterator c = m_pParentChangeMemento->changedObjects( ); + for( ; c.current( ); ++c ) + theManager->cmdObjectChanged( c.current( )->object( ), + c.current( )->mode( ) ); + } + + if( m_linksCreated ) + { + PMObjectListIterator rit( m_links ); + for( ; rit.current( ); ++rit ) + rit.current( )->linkedObject( )->addLinkedObject( rit.current( ) ); + PMObjectListIterator dit( m_linkedDeclares ); + for( ; dit.current( ); ++dit ) + theManager->cmdObjectChanged( dit.current( ), PMCData ); + } + + PMObjectListIterator errorit( errors ); + for( ; errorit.current( ); ++errorit ) + { + m_objects.removeRef( errorit.current( ) ); + m_insertErrors.append( errorit.current( ) ); + + PMRecursiveObjectIterator lit( errorit.current( ) ); + for( ; lit.current( ); ++lit ) + if( lit.current( )->linkedObject( ) ) + lit.current( )->linkedObject( )->removeLinkedObject( lit.current( ) ); + } + + m_executed = true; + m_firstExecution = false; + } +} + +void PMAddCommand::undo( PMCommandManager* theManager ) +{ + if( m_executed ) + { + PMObjectListIterator it( m_objects ); + PMObject* obj; + PMDeclare* decl; + + if( !m_linksCreated ) + { + for( ; it.current( ); ++it ) + { + PMRecursiveObjectIterator lit( it.current( ) ); + for( ; lit.current( ); ++lit ) + { + decl = lit.current( )->linkedObject( ); + if( decl ) + { + m_links.append( lit.current( ) ); + if( !m_linkedDeclares.containsRef( decl ) ) + m_linkedDeclares.append( decl ); + } + } + } + m_linksCreated = true; + } + + PMObjectListIterator rit( m_links ); + for( ; rit.current( ); ++rit ) + rit.current( )->linkedObject( )->removeLinkedObject( rit.current( ) ); + + for( it.toLast( ) ; it.current( ); --it ) + { + obj = it.current( ); + // signal has to be emitted before the item is removed + theManager->cmdObjectChanged( obj, PMCRemove ); + + if( obj->parent( ) ) + obj->parent( )->takeChild( obj ); + } + + if( m_pParentChangeMemento ) + { + m_pParent->restoreMemento( m_pParentChangeMemento ); + PMObjectChangeListIterator c = m_pParentChangeMemento->changedObjects( ); + for( ; c.current( ); ++c ) + { + theManager->cmdObjectChanged( c.current( )->object( ), + c.current( )->mode( ) ); + } + } + + PMObjectListIterator dit( m_linkedDeclares ); + for( ; dit.current( ); ++dit ) + theManager->cmdObjectChanged( dit.current( ), PMCData ); + + m_executed = false; + } +} + +int PMAddCommand::errorFlags( PMPart* ) +{ + return PMENone; +} diff --git a/kpovmodeler/pmaddcommand.h b/kpovmodeler/pmaddcommand.h new file mode 100644 index 00000000..97793d03 --- /dev/null +++ b/kpovmodeler/pmaddcommand.h @@ -0,0 +1,87 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMADDCOMMAND_H +#define PMADDCOMMAND_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmcommand.h" +#include "pmobject.h" + +class PMMemento; + +/** + * Command class for adding a new PMObject + */ +class PMAddCommand : public PMCommand +{ +public: + /** + * Command that adds a new PMObject. + * + * The object obj will be inserted as child of parent after + * the object after. + * + * If after is 0, the object becomes the first child. + */ + PMAddCommand( PMObject* obj, PMObject* parent, PMObject* after ); + + /** + * Command that adds a list of new PMObjects. + * + * The object in the list will be inserted as children of parent after + * the object after. + * + * If after is 0, the objects will be inserted as first children. + */ + PMAddCommand( const PMObjectList& list, PMObject* parent, PMObject* after ); + /** + * Deletes the command. The inserted object will be deleted, if + the command was not executed (or undo-ed) */ + virtual ~PMAddCommand( ); + + /** */ + virtual int errorFlags( PMPart* ); + +protected: + /** + * Executes the command and stores undo information + */ + virtual void execute( PMCommandManager* theManager ); + /** + * Undo the command + */ + virtual void undo( PMCommandManager* theManager ); + +private: + PMObject* m_pParent; + PMObjectList m_objects; + PMObject* m_pAfter; + bool m_executed, m_firstExecution; + PMObjectList m_insertErrors; + PMObjectList m_links; + PMObjectList m_linkedDeclares; + bool m_linksCreated; + PMMemento* m_pParentChangeMemento; +}; + +#endif diff --git a/kpovmodeler/pmallcommands.h b/kpovmodeler/pmallcommands.h new file mode 100644 index 00000000..014b5a04 --- /dev/null +++ b/kpovmodeler/pmallcommands.h @@ -0,0 +1,27 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMALLCOMMANDS_H +#define PMALLCOMMANDS_H + +#include "pmaddcommand.h" +#include "pmdeletecommand.h" +#include "pmmovecommand.h" + +#endif diff --git a/kpovmodeler/pmalledits.h b/kpovmodeler/pmalledits.h new file mode 100644 index 00000000..e1ee4a5a --- /dev/null +++ b/kpovmodeler/pmalledits.h @@ -0,0 +1,25 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMALLEDITS_H +#define PMALLEDITS_H + +#include "pmboxedit.h" + +#endif diff --git a/kpovmodeler/pmallobjects.h b/kpovmodeler/pmallobjects.h new file mode 100644 index 00000000..3a02107c --- /dev/null +++ b/kpovmodeler/pmallobjects.h @@ -0,0 +1,106 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMALLOBJECTS_H +#define PMALLOBJECTS_H + +#include "pmscene.h" +#include "pmglobalsettings.h" + +#include "pmbox.h" +#include "pmsphere.h" +#include "pmcylinder.h" +#include "pmcone.h" +#include "pmtorus.h" +#include "pmlathe.h" +#include "pmprism.h" +#include "pmsor.h" +#include "pmsqe.h" +#include "pmheightfield.h" +#include "pmtext.h" +#include "pmjuliafractal.h" + +#include "pmblob.h" +#include "pmblobsphere.h" +#include "pmblobcylinder.h" + +#include "pmplane.h" +#include "pmpolynom.h" + +#include "pmdeclare.h" +#include "pmobjectlink.h" + +#include "pmcsg.h" + +#include "pmdisc.h" +#include "pmbicubicpatch.h" +#include "pmtriangle.h" + +#include "pmboundedby.h" +#include "pmclippedby.h" + +#include "pmcamera.h" + +#include "pmtranslate.h" +#include "pmscale.h" +#include "pmrotate.h" +#include "pmpovraymatrix.h" + +#include "pmlight.h" +#include "pmlookslike.h" +#include "pmprojectedthrough.h" + +#include "pmtexture.h" +#include "pmpigment.h" +#include "pmsolidcolor.h" +#include "pmlistpattern.h" +#include "pmquickcolor.h" +#include "pmnormal.h" +#include "pmfinish.h" +#include "pmpattern.h" +#include "pmblendmapmodifiers.h" +#include "pmimagemap.h" +#include "pmbumpmap.h" +#include "pmtexturemap.h" +#include "pmmaterialmap.h" +#include "pmwarp.h" +#include "pmslope.h" +#include "pmdensity.h" + +#include "pmskysphere.h" +#include "pmrainbow.h" +#include "pmfog.h" +#include "pminterior.h" +#include "pmmedia.h" +#include "pmmaterial.h" + +#include "pmcomment.h" +#include "pmraw.h" + +// POV-Ray 3.5 objects +#include "pmisosurface.h" +#include "pmradiosity.h" +#include "pmglobalphotons.h" +#include "pmphotons.h" +#include "pmlightgroup.h" +#include "pminteriortexture.h" +#include "pmspheresweep.h" +#include "pmmesh.h" + +#endif diff --git a/kpovmodeler/pmbicubicpatch.cpp b/kpovmodeler/pmbicubicpatch.cpp new file mode 100644 index 00000000..cbc633a9 --- /dev/null +++ b/kpovmodeler/pmbicubicpatch.cpp @@ -0,0 +1,544 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmbicubicpatch.h" + +#include "pmxmlhelper.h" +#include "pmbicubicpatchedit.h" +#include "pmmemento.h" +#include "pmviewstructure.h" +#include "pm3dcontrolpoint.h" +#include "pmmath.h" + +#include + +const double c_defaultPatchSize = 6.0; +const int c_defaultPatchType = 0; +const int c_defaultPatchUSteps = 3; +const int c_defaultPatchVSteps = 3; +const double c_defaultPatchFlatness = 0; +const PMVector c_defaultUVVector0 = PMVector( 0.0, 0.0 ); +const PMVector c_defaultUVVector1 = PMVector( 1.0, 0.0 ); +const PMVector c_defaultUVVector2 = PMVector( 1.0, 1.0 ); +const PMVector c_defaultUVVector3 = PMVector( 0.0, 1.0 ); + +PMDefinePropertyClass( PMBicubicPatch, PMBicubicPatchProperty ); + +class PMPointProperty : public PMPropertyBase +{ +public: + PMPointProperty( ) + : PMPropertyBase( "controlPoints", PMVariant::Vector ) + { + m_index = 0; + } + virtual int dimensions( ) const { return 1; } + virtual void setIndex( int /*dimension*/, int index ) + { + if( index < 0 || index > 15 ) + kdError( PMArea ) << "Illegal index in PMBicubicPatch::PointProperty::setIndex" << endl; + else + m_index = index; + } + virtual int size( PMObject* /*object*/, int /*dimension*/ ) const + { + return 16; + } +protected: + virtual bool setProtected( PMObject* obj, const PMVariant& v ) + { + PMBicubicPatch* p = ( PMBicubicPatch* ) obj; + p->setControlPoint( m_index, v.vectorData( ) ); + return true; + } + virtual PMVariant getProtected( const PMObject* obj ) + { + const PMBicubicPatch* p = ( const PMBicubicPatch* ) obj; + return PMVariant( p->controlPoint( m_index ) ); + } + +private: + int m_index; +}; + +class PMUVVectorProperty : public PMPropertyBase +{ +public: + PMUVVectorProperty( ) + : PMPropertyBase( "uvVectors", PMVariant::Vector ) + { + m_index = 0; + } + virtual int dimensions( ) const { return 1; } + virtual void setIndex( int /*dimension*/, int index ) + { + if( index < 0 || index > 3 ) + kdError( PMArea ) << "Illegal index in PMBicubicPatch::UVVectorProperty::setIndex" << endl; + else + m_index = index; + } + virtual int size( PMObject* /*object*/, int /*dimension*/ ) const + { + return 3; + } +protected: + virtual bool setProtected( PMObject* obj, const PMVariant& v ) + { + PMBicubicPatch* p = ( PMBicubicPatch* ) obj; + p->setUVVector( m_index, v.vectorData( ) ); + return true; + } + virtual PMVariant getProtected( const PMObject* obj ) + { + const PMBicubicPatch* p = ( const PMBicubicPatch* ) obj; + return PMVariant( p->uvVector( m_index ) ); + } + +private: + int m_index; +}; + +PMMetaObject* PMBicubicPatch::s_pMetaObject = 0; +PMObject* createNewBicubicPatch( PMPart* part ) +{ + return new PMBicubicPatch( part ); +} + +PMBicubicPatch::PMBicubicPatch( PMPart* part ) + : Base( part ) +{ + int x, z; + double o = -c_defaultPatchSize / 2.0, s = c_defaultPatchSize / 3.0; + m_patchType = c_defaultPatchType; + m_numUSteps = c_defaultPatchUSteps; + m_numVSteps = c_defaultPatchVSteps; + m_flatness = c_defaultPatchFlatness; + for( x = 0; x < 4; x++ ) + for( z = 0; z < 4; z++ ) + m_point[x+z*4] = PMVector( o + s * x, 0, o + s * z ); + m_vsUSteps = 0; + m_vsVSteps = 0; + m_uvEnabled = false; + m_uvVectors[0] = c_defaultUVVector0; + m_uvVectors[1] = c_defaultUVVector1; + m_uvVectors[2] = c_defaultUVVector2; + m_uvVectors[3] = c_defaultUVVector3; +} + +PMBicubicPatch::PMBicubicPatch( const PMBicubicPatch& p ) + : Base( p ) +{ + int i; + m_patchType = p.m_patchType; + m_numUSteps = p.m_numUSteps; + m_numVSteps = p.m_numVSteps; + m_flatness = p.m_flatness; + for( i = 0; i < 16; i++ ) + m_point[i] = p.m_point[i]; + m_vsUSteps = 0; + m_vsVSteps = 0; + m_uvEnabled = p.m_uvEnabled; + for( i = 0; i < 4; ++i ) + m_uvVectors[i] = p.m_uvVectors[i]; +} + +PMBicubicPatch::~PMBicubicPatch( ) +{ +} + +QString PMBicubicPatch::description( ) const +{ + return i18n( "bicubic patch" ); +} + +void PMBicubicPatch::serialize( QDomElement& e, QDomDocument& doc ) const +{ + int i; + + e.setAttribute( "type", m_patchType ); + e.setAttribute( "flatness", m_flatness ); + e.setAttribute( "uSteps", m_numUSteps ); + e.setAttribute( "vSteps", m_numVSteps ); + e.setAttribute( "uvEnabled", m_uvEnabled ); + + for( i = 0; i < 16; i++ ) + e.setAttribute( QString( "cp%1" ).arg( i ), m_point[i].serializeXML( ) ); + + for( i = 0; i < 4; ++i ) + e.setAttribute( QString( "uv%1" ).arg( i ), m_uvVectors[i].serializeXML( ) ); + + Base::serialize( e, doc ); +} + +void PMBicubicPatch::readAttributes( const PMXMLHelper& h ) +{ + int u, v; + double o = -c_defaultPatchSize / 2.0, s = c_defaultPatchSize / 3.0; + + m_patchType = h.intAttribute( "type", c_defaultPatchType ); + m_flatness = h.doubleAttribute( "flatness", c_defaultPatchFlatness ); + m_numUSteps = h.intAttribute( "uSteps", c_defaultPatchUSteps ); + m_numVSteps = h.intAttribute( "vSteps", c_defaultPatchVSteps ); + m_uvEnabled = h.boolAttribute( "uvEnabled", m_uvEnabled ); + + for( v = 0; v < 4; v++ ) + for( u = 0; u < 4; u++ ) + m_point[u+v*4] = h.vectorAttribute( QString( "cp%1" ).arg( u+v*4 ), + PMVector( o + s * u, 0, o + s * v ) ); + + m_uvVectors[0] = h.vectorAttribute( "uv0", c_defaultUVVector0 ); + m_uvVectors[1] = h.vectorAttribute( "uv1", c_defaultUVVector1 ); + m_uvVectors[2] = h.vectorAttribute( "uv2", c_defaultUVVector2 ); + m_uvVectors[3] = h.vectorAttribute( "uv3", c_defaultUVVector3 ); + + Base::readAttributes( h ); +} + +PMMetaObject* PMBicubicPatch::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "BicubicPatch", Base::metaObject( ), + createNewBicubicPatch ); + s_pMetaObject->addProperty( + new PMBicubicPatchProperty( "patchType", &PMBicubicPatch::setPatchType, + &PMBicubicPatch::patchType ) ); + s_pMetaObject->addProperty( + new PMBicubicPatchProperty( "uSteps", &PMBicubicPatch::setUSteps, + &PMBicubicPatch::uSteps ) ); + s_pMetaObject->addProperty( + new PMBicubicPatchProperty( "vSteps", &PMBicubicPatch::setVSteps, + &PMBicubicPatch::vSteps ) ); + s_pMetaObject->addProperty( + new PMBicubicPatchProperty( "flatness", &PMBicubicPatch::setFlatness, + &PMBicubicPatch::flatness ) ); + s_pMetaObject->addProperty( + new PMBicubicPatchProperty( "uvEnabled", &PMBicubicPatch::enableUV, + &PMBicubicPatch::isUVEnabled ) ); + s_pMetaObject->addProperty( new PMPointProperty( ) ); + s_pMetaObject->addProperty( new PMUVVectorProperty( ) ); + } + return s_pMetaObject; +} + +void PMBicubicPatch::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMBicubicPatch::setPatchType( int patchType ) +{ + if( ( patchType == 0 ) || ( patchType == 1 ) ) + { + if( patchType != m_patchType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMTypeID, m_patchType ); + m_patchType = patchType; + } + } + else + kdError( PMArea ) << "Wrong type in PMBicubicPatch::setPatchType( )\n"; +} + +void PMBicubicPatch::setFlatness( double flatness ) +{ + if( flatness >= 0.0 ) + { + if( flatness != m_flatness ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFlatnessID, m_flatness ); + m_flatness = flatness; + } + } + else + kdError( PMArea ) << "Flatness has to be >= 0 in PMBicubicPatch::setFlatness( )\n"; +} + +void PMBicubicPatch::setUSteps( int steps ) +{ + if( steps >= 0 ) + { + if( steps != m_numUSteps ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMUStepsID, m_numUSteps ); + m_numUSteps = steps; + setViewStructureChanged( ); + } + } + else + kdError( PMArea ) << "uSteps has to be >= 0 in PMBicubicPatch::setUSteps( )\n"; +} + +void PMBicubicPatch::setVSteps( int steps ) +{ + if( steps >= 0 ) + { + if( steps != m_numVSteps ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMVStepsID, m_numVSteps ); + m_numVSteps = steps; + setViewStructureChanged( ); + } + } + else + kdError( PMArea ) << "vSteps has to be >= 0 in PMBicubicPatch::setVSteps( )\n"; +} + +void PMBicubicPatch::setControlPoint( int i, const PMVector& p ) +{ + if( ( i >= 0 ) && ( i <= 15 ) ) + { + if( p != m_point[i] ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCP0ID + i, m_point[i] ); + m_point[i] = p; + setViewStructureChanged( ); + } + } + else + kdError( PMArea ) << "Wrong index in PMBicubicPatch::setControlPoint( )\n"; +} + +PMVector PMBicubicPatch::controlPoint( int i ) const +{ + if( ( i >= 0 ) && ( i <= 15 ) ) + return m_point[i]; + else + kdError( PMArea ) << "Wrong index in PMBicubicPatch::controlPoint( )\n"; + return PMVector( 0, 0, 0 ); +} + +void PMBicubicPatch::enableUV( bool yes ) +{ + if( yes != m_uvEnabled ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMUVEnabledID, m_uvEnabled ); + m_uvEnabled = yes; + } +} + +void PMBicubicPatch::setUVVector( int i, const PMVector& v ) +{ + if ( i >= 0 && i < 4 ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMUV0ID + i, m_uvVectors[i] ); + m_uvVectors[i] = v; + m_uvVectors[i].resize( 2 ); + } + else + kdError( PMArea ) << "Wrong index in PMBicubicPatch::setUVVector\n"; +} + +PMVector PMBicubicPatch::uvVector( int i ) const +{ + if( i >= 0 && i < 4 ) + return m_uvVectors[i]; + else + kdError( PMArea ) << "Wrong index in PMBicubicPatch::uvVector\n"; + return PMVector( 0.0, 0.0 ); +} + +PMDialogEditBase* PMBicubicPatch::editWidget( QWidget* parent ) const +{ + return new PMBicubicPatchEdit( parent ); +} + +void PMBicubicPatch::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMTypeID: + setPatchType( data->intData( ) ); + break; + case PMFlatnessID: + setFlatness( data->doubleData( ) ); + break; + case PMUStepsID: + setUSteps( data->intData( ) ); + break; + case PMVStepsID: + setVSteps( data->intData( ) ); + break; + case PMUVEnabledID: + enableUV( data->boolData( ) ); + break; + default: + if( ( data->valueID( ) >= PMCP0ID ) && ( data->valueID( ) <= PMCP15ID ) ) + setControlPoint( data->valueID( ) - PMCP0ID, data->vectorData( ) ); + else if ( data->valueID( ) >= PMUV0ID && data->valueID( ) <= PMUV3ID ) + setUVVector( data->valueID( ) - PMUV0ID, data->vectorData( ) ); + else + kdError( PMArea ) << "Wrong ID in PMBicubicPatch::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + +void PMBicubicPatch::createViewStructure( ) +{ + int u, v, i, j; + int uSteps = m_numUSteps, vSteps = m_numVSteps; + if( uSteps > 5 ) uSteps = 5; + if( vSteps > 5 ) vSteps = 5; + if( uSteps < 0 ) uSteps = 0; + if( vSteps < 0 ) vSteps = 0; + + // bugfix: Swap u and v + int segmentsU = pmpot( 2, vSteps ); + int segmentsV = pmpot( 2, uSteps ); + + int np = ( segmentsU + 1 ) * ( segmentsV + 1 ); + int nl = segmentsU * ( segmentsV + 1 ) + ( segmentsU + 1 ) * segmentsV; + + int offset = 0; + + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( np, nl ); + m_vsUSteps = uSteps + 1; + } + else + { + if( m_pViewStructure->points( ).size( ) != ( unsigned ) np ) + m_pViewStructure->points( ).resize( np ); + if( m_pViewStructure->lines( ).size( ) != ( unsigned ) nl ) + m_pViewStructure->lines( ).resize( nl ); + } + + if( ( m_vsUSteps != uSteps ) || ( m_vsVSteps != vSteps ) ) + { + PMLineArray& lines = m_pViewStructure->lines( ); + int poffset = 0; + for( v = 0; v < ( segmentsV + 1 ); v++ ) + { + for( u = 0; u < segmentsU; u++ ) + { + lines[offset + u] = PMLine( poffset, poffset + 1 ); + poffset++; + } + poffset++; + offset += segmentsU; + } + poffset = 0; + for( v = 0; v < segmentsV; v++ ) + { + for( u = 0; u < ( segmentsU + 1 ); u++ ) + { + lines[offset + u] = PMLine( poffset, poffset + segmentsU + 1 ); + poffset++; + } + offset += segmentsU + 1; + } + m_vsUSteps = uSteps; + m_vsVSteps = vSteps; + } + + PMPointArray& points = m_pViewStructure->points( ); + + offset = 0; + double incU = 1.0 / segmentsU; + double incV = 1.0 / segmentsV; + + PMVector* hp[4]; + for( v = 0; v < 4; v++ ) + hp[v] = new PMVector[segmentsU+1]; + + PMVector tp[4]; + + double cu, cv; + + // points in u direction + for( v = 0; v < 4; v++ ) + { + for( u = 1; u < segmentsU; u++ ) + { + cu = u * incU; + + for( i = 0; i < 4; i++ ) + tp[i] = m_point[v*4+i]; + for( i = 3; i > 0; i-- ) + for( j = 0; j < i; j++ ) + tp[j] = tp[j] * ( 1 - cu ) + tp[j+1] * cu; + hp[v][u] = tp[0]; + } + hp[v][0] = m_point[v*4]; + hp[v][segmentsU] = m_point[v*4+3]; + } + + for( v = 0; v <= segmentsV; v++ ) + { + cv = v * incV; + for( u = 0; u <= segmentsU; u++ ) + { + for( i = 0; i < 4; i++ ) + tp[i] = hp[i][u]; + for( i = 3; i > 0; i-- ) + for( j = 0; j < i; j++ ) + tp[j] = tp[j] * ( 1 - cv ) + tp[j+1] * cv; + points[offset] = tp[0]; + offset++; + } + } + + for( v = 0; v < 4; v++ ) + delete[] hp[v]; +} + +void PMBicubicPatch::controlPoints( PMControlPointList& list ) +{ + int u, v; + for( v = 0; v < 4; v++ ) + for( u = 0; u < 4; u++ ) + list.append( new PM3DControlPoint( m_point[u+v*4], u+v*4, + i18n( "Point (%1, %2)" ).arg( u ).arg( v ) ) ); +} + +void PMBicubicPatch::controlPointsChanged( PMControlPointList& list ) +{ + PMControlPoint* p; + + for( p = list.first( ); p; p = list.next( ) ) + { + if( p->changed( ) ) + { + setControlPoint( p->id( ), p->position( ) ); + } + } +} diff --git a/kpovmodeler/pmbicubicpatch.h b/kpovmodeler/pmbicubicpatch.h new file mode 100644 index 00000000..c7ca6b3b --- /dev/null +++ b/kpovmodeler/pmbicubicpatch.h @@ -0,0 +1,188 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMBICUBICPATCH_H +#define PMBICUBICPATCH_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmgraphicalobject.h" +#include "pmvector.h" + +class PMViewStructure; + +/** + * Class for povray bicubic patches (bezier patches). + */ + +class PMBicubicPatch : public PMGraphicalObject +{ + typedef PMGraphicalObject Base; +public: + /** + * Creates an empty PMBicubicPatch + */ + PMBicubicPatch( PMPart* part ); + /** + * Copy constructor + */ + PMBicubicPatch( const PMBicubicPatch& p ); + /** + * deletes the PMBicubicPatch + */ + virtual ~PMBicubicPatch( ); + + /** */ + virtual PMObject* copy( ) const { return new PMBicubicPatch( *this ); } + /** */ + virtual QString description( ) const; + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMBicubicPatchEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmbicubicpatch" ); } + + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual void controlPoints( PMControlPointList& list ); + /** */ + virtual void controlPointsChanged( PMControlPointList& list ); + /** */ + virtual bool multipleSelectControlPoints( ) const { return true; } + + /** + * Sets the type. Type must be 0 or 1 + */ + void setPatchType( int type ); + /** + * Returns the type + */ + int patchType( ) const { return m_patchType; } + /** + * Sets the number of u steps + */ + void setUSteps( int steps ); + /** + * Returns the number of u steps + */ + int uSteps( ) const { return m_numUSteps; } + /** + * Sets the number of v steps + */ + void setVSteps( int steps ); + /** + * Returns the number of v steps + */ + int vSteps( ) const { return m_numVSteps; } + /** + * Sets the flatness + */ + void setFlatness( double f ); + /** + * Returns the flatness + */ + double flatness( ) const { return m_flatness; } + + /** + * Sets the ith patch control point + */ + void setControlPoint( int i, const PMVector& p ); + /** + * Returns the ith patch control point + */ + PMVector controlPoint( int i ) const; + + /** + * Sets the uv vectors flag + */ + void enableUV( bool yes ); + /** + * Returns the uv vectors flag + */ + bool isUVEnabled( ) const { return m_uvEnabled; } + /** + * Sets the ith uv vector + */ + void setUVVector( int i, const PMVector& v ); + /** + * Returns the ith uv vector + */ + PMVector uvVector( int i ) const; + +protected: + /** */ + virtual bool isDefault( ) { return false; } + /** */ + virtual void createViewStructure( ); + /** */ + virtual PMViewStructure* defaultViewStructure( ) const { return 0; } + +private: + /** + * IDs for @ref PMMementoData + */ + enum PMBicubicPatchMementoID { PMTypeID, PMFlatnessID, PMUStepsID, + PMVStepsID, + PMCP0ID, PMCP1ID, PMCP2ID, PMCP3ID, + PMCP4ID, PMCP5ID, PMCP6ID, PMCP7ID, + PMCP8ID, PMCP9ID, PMCP10ID, PMCP11ID, + PMCP12ID, PMCP13ID, PMCP14ID, PMCP15ID, + PMUVEnabledID, + PMUV0ID, PMUV1ID, PMUV2ID, PMUV3ID }; + + /** + * The patch type + */ + int m_patchType; + /** + * Number of subdivisions + */ + int m_numUSteps, m_numVSteps; + /** + * Flatness of the patch + */ + double m_flatness; + /** + * The control points + */ + PMVector m_point[16]; + int m_vsUSteps, m_vsVSteps; + bool m_uvEnabled; + PMVector m_uvVectors[4]; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmbicubicpatchedit.cpp b/kpovmodeler/pmbicubicpatchedit.cpp new file mode 100644 index 00000000..6ead96ae --- /dev/null +++ b/kpovmodeler/pmbicubicpatchedit.cpp @@ -0,0 +1,218 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmbicubicpatchedit.h" +#include "pmbicubicpatch.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" +#include "pmvectorlistedit.h" +#include "pmpart.h" + +#include +#include +#include +#include +#include + +PMBicubicPatchEdit::PMBicubicPatchEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMBicubicPatchEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* layout; + + m_pType = new QComboBox( false, this ); + m_pType->insertItem( i18n( "Normal (type 0)" ) ); + m_pType->insertItem( i18n( "Preprocessed (type 1)" ) ); + layout = new QHBoxLayout( topLayout( ) ); + layout->addWidget( new QLabel( i18n( "Type:" ), this ) ); + layout->addWidget( m_pType ); + layout->addStretch( 1 ); + + m_pUSteps = new PMIntEdit( this ); + m_pUSteps->setValidation( true, 0, false, 0 ); + layout = new QHBoxLayout( topLayout( ) ); + layout->addWidget( new QLabel( i18n( "Steps:" ) + " u", this ) ); + layout->addWidget( m_pUSteps ); + m_pVSteps = new PMIntEdit( this ); + m_pVSteps->setValidation( true, 0, false, 0 ); + layout->addWidget( new QLabel( "v", this ) ); + layout->addWidget( m_pVSteps ); + + m_pFlatness = new PMFloatEdit( this ); + m_pFlatness->setValidation( true, 0.0, false, 0.0 ); + layout = new QHBoxLayout( topLayout( ) ); + layout->addWidget( new QLabel( i18n( "Flatness:" ), this ) ); + layout->addWidget( m_pFlatness ); + layout->addStretch( 1 ); + + topLayout( )->addWidget( new QLabel( i18n( "Points:" ), this ) ); + + m_pPoints = new PMVectorListEdit( "x", "y", "z", this ); + m_pPoints->setSize( 16 ); + topLayout( )->addWidget( m_pPoints ); + + m_pUVEnabled = new QCheckBox( i18n( "UV vectors" ), this ); + topLayout( )->addWidget( m_pUVEnabled ); + m_pUVVectors = new PMVectorListEdit( "u", "v", this ); + m_pUVVectors->setSize( 4 ); + topLayout( )->addWidget( m_pUVVectors ); + + connect( m_pType, SIGNAL( highlighted( int ) ), SLOT( slotTypeSelected( int ) ) ); + connect( m_pUSteps, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pVSteps, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pFlatness, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pPoints, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pPoints, SIGNAL( selectionChanged( ) ), + SLOT( slotSelectionChanged( ) ) ); + connect( m_pUVEnabled, SIGNAL( clicked( ) ), SLOT( slotUVEnabledClicked( ) ) ); + connect( m_pUVVectors, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMBicubicPatchEdit::displayObject( PMObject* o ) +{ + int i; + if( o->isA( "BicubicPatch" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMBicubicPatch* ) o; + + m_pType->setCurrentItem( m_pDisplayedObject->patchType( ) ); + m_pType->setEnabled( !readOnly ); + m_pUSteps->setValue( m_pDisplayedObject->uSteps( ) ); + m_pUSteps->setReadOnly( readOnly ); + m_pVSteps->setValue( m_pDisplayedObject->vSteps( ) ); + m_pVSteps->setReadOnly( readOnly ); + m_pFlatness->setValue( m_pDisplayedObject->flatness( ) ); + m_pFlatness->setReadOnly( readOnly ); + + for( i = 0; i < 16; i++ ) + m_pPoints->setVector( i, m_pDisplayedObject->controlPoint( i ) ); + m_pPoints->setReadOnly( readOnly ); + updateControlPointSelection( ); + + m_pUVEnabled->setChecked( m_pDisplayedObject->isUVEnabled( ) ); + m_pUVEnabled->setEnabled( !readOnly ); + for( i = 0; i < 4; ++i ) + m_pUVVectors->setVector( i, m_pDisplayedObject->uvVector( i ) ); + m_pUVVectors->setReadOnly( readOnly ); + slotUVEnabledClicked( ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMBicubicPatchEdit: Can't display object\n"; +} + +void PMBicubicPatchEdit::updateControlPointSelection( ) +{ + PMControlPointList cp = part( )->activeControlPoints( ); + PMControlPointListIterator it( cp ); + int s = 0, e = 0; + + m_pPoints->blockSelectionUpdates( true ); + bool sb = m_pPoints->signalsBlocked( ); + m_pPoints->blockSignals( true ); + + m_pPoints->clearSelection( ); + while( s < 16 ) + { + if( ( *it )->selected( ) ) + { + for( e = s; e < 16 && ( *it )->selected( ); e++ ) + ++it; + m_pPoints->select( s, e - 1 ); + s = e; + } + else + { + s++; + ++it; + } + } + + m_pPoints->blockSignals( sb ); + m_pPoints->blockSelectionUpdates( false ); +} + +void PMBicubicPatchEdit::saveContents( ) +{ + int i; + + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setPatchType( m_pType->currentItem( ) ); + m_pDisplayedObject->setUSteps( m_pUSteps->value( ) ); + m_pDisplayedObject->setVSteps( m_pVSteps->value( ) ); + m_pDisplayedObject->setFlatness( m_pFlatness->value( ) ); + for( i = 0; i < 16; i++ ) + m_pDisplayedObject->setControlPoint( i, m_pPoints->vector( i ) ); + m_pDisplayedObject->enableUV( m_pUVEnabled->isChecked( ) ); + for( i = 0; i < 4; ++i ) + m_pDisplayedObject->setUVVector( i, m_pUVVectors->vector( i ) ); + } +} + +bool PMBicubicPatchEdit::isDataValid( ) +{ + bool ok = false; + if( m_pUSteps->isDataValid( ) ) + if( m_pVSteps->isDataValid( ) ) + if( m_pFlatness->isDataValid( ) ) + ok = true; + if( ok ) + ok = m_pPoints->isDataValid( ); + if( ok && m_pUVEnabled->isChecked( ) ) + ok = m_pUVVectors->isDataValid( ); + if( ok ) + return Base::isDataValid( ); + return false; +} + +void PMBicubicPatchEdit::slotTypeSelected( int ) +{ + emit dataChanged( ); +} + +void PMBicubicPatchEdit::slotSelectionChanged( ) +{ + PMControlPointList cp = part( )->activeControlPoints( ); + PMControlPointListIterator it( cp ); + int i; + for( i = 0; i < 16; i++, ++it ) + ( *it )->setSelected( m_pPoints->isSelected( i ) ); + emit controlPointSelectionChanged( ); +} + +void PMBicubicPatchEdit::slotUVEnabledClicked( ) +{ + if( m_pUVEnabled->isChecked( ) ) + m_pUVVectors->show( ); + else + m_pUVVectors->hide( ); + emit dataChanged( ); + emit sizeChanged( ); +} + +#include "pmbicubicpatchedit.moc" diff --git a/kpovmodeler/pmbicubicpatchedit.h b/kpovmodeler/pmbicubicpatchedit.h new file mode 100644 index 00000000..41d173c1 --- /dev/null +++ b/kpovmodeler/pmbicubicpatchedit.h @@ -0,0 +1,80 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMBICUBICPATCHEDIT_H +#define PMBICUBICPATCHEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmgraphicalobjectedit.h" + +class PMBicubicPatch; +class PMIntEdit; +class PMFloatEdit; +class PMVectorListEdit; +class QComboBox; +class QCheckBox; + +/** + * Dialog edit class for @ref PMBicubicPatch + */ +class PMBicubicPatchEdit : public PMGraphicalObjectEdit +{ + Q_OBJECT + typedef PMGraphicalObjectEdit Base; +public: + /** + * Creates a PMBicubicPatchEdit with parent and name + */ + PMBicubicPatchEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + /** */ + virtual void updateControlPointSelection( ); + + /** */ + virtual bool isDataValid( ); + +protected slots: + void slotTypeSelected( int i ); + void slotSelectionChanged( ); + void slotUVEnabledClicked( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + QComboBox* m_pType; + PMIntEdit* m_pUSteps; + PMIntEdit* m_pVSteps; + PMFloatEdit* m_pFlatness; + PMVectorListEdit* m_pPoints; + QCheckBox* m_pUVEnabled; + PMVectorListEdit* m_pUVVectors; + + PMBicubicPatch* m_pDisplayedObject; +}; + + +#endif diff --git a/kpovmodeler/pmblendmapmodifiers.cpp b/kpovmodeler/pmblendmapmodifiers.cpp new file mode 100644 index 00000000..0259fb90 --- /dev/null +++ b/kpovmodeler/pmblendmapmodifiers.cpp @@ -0,0 +1,284 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#include "pmblendmapmodifiers.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmblendmapmodifiersedit.h" +#include "pmvector.h" +#include "pmenumproperty.h" + +#include + +PMDefinePropertyClass( PMBlendMapModifiers, PMBlendMapModifiersProperty ); +PMDefineEnumPropertyClass( PMBlendMapModifiers, + PMBlendMapModifiers::PMWaveFormType, + PMWaveFormProperty ); + +PMMetaObject* PMBlendMapModifiers::s_pMetaObject = 0; +PMObject* createBlendMapModifiers( PMPart* part ) +{ + return new PMBlendMapModifiers( part ); +} + +const double frequencyDefault = 1.0; +const double phaseDefault = 0.0; +const PMBlendMapModifiers::PMWaveFormType waveFormTypeDefault = PMBlendMapModifiers::RampWave; +const double waveFormExponentDefault = 1.0; + + +PMBlendMapModifiers::PMBlendMapModifiers( PMPart* part ) + : Base( part ) +{ + m_enableFrequency = false; + m_frequency = frequencyDefault; + m_enablePhase = false; + m_phase = phaseDefault; + m_enableWaveForm = false; + m_waveFormType = waveFormTypeDefault; + m_waveFormExponent = waveFormExponentDefault; +} + +PMBlendMapModifiers::~PMBlendMapModifiers( ) +{ +} + +PMMetaObject* PMBlendMapModifiers::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "BlendMapModifiers", Base::metaObject( ), + createBlendMapModifiers ); + s_pMetaObject->addProperty( + new PMBlendMapModifiersProperty( "frequencyEnabled", &PMBlendMapModifiers::enableFrequency, + &PMBlendMapModifiers::isFrequencyEnabled ) ); + s_pMetaObject->addProperty( + new PMBlendMapModifiersProperty( "frequency", &PMBlendMapModifiers::setFrequency, + &PMBlendMapModifiers::frequency ) ); + s_pMetaObject->addProperty( + new PMBlendMapModifiersProperty( "phaseEnabled", &PMBlendMapModifiers::enablePhase, + &PMBlendMapModifiers::isPhaseEnabled ) ); + s_pMetaObject->addProperty( + new PMBlendMapModifiersProperty( "phase", &PMBlendMapModifiers::setPhase, + &PMBlendMapModifiers::phase ) ); + s_pMetaObject->addProperty( + new PMBlendMapModifiersProperty( "waveFormEnabled", &PMBlendMapModifiers::enableWaveForm, + &PMBlendMapModifiers::isWaveFormEnabled ) ); + s_pMetaObject->addProperty( + new PMBlendMapModifiersProperty( "waveFormExponent", &PMBlendMapModifiers::setWaveFormExponent, + &PMBlendMapModifiers::waveFormExponent ) ); + + PMWaveFormProperty* p = new PMWaveFormProperty( + "waveForm", &PMBlendMapModifiers::setWaveFormType, + &PMBlendMapModifiers::waveFormType ); + p->addEnumValue( QString( "RampWave" ), RampWave ); + p->addEnumValue( QString( "TriangleWave" ), TriangleWave ); + p->addEnumValue( QString( "SineWave" ), SineWave ); + p->addEnumValue( QString( "ScallopWave" ), ScallopWave ); + p->addEnumValue( QString( "CubicWave" ), CubicWave ); + p->addEnumValue( QString( "PolyWave" ), PolyWave ); + s_pMetaObject->addProperty( p ); + } + return s_pMetaObject; +} + +void PMBlendMapModifiers::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMBlendMapModifiers::description( ) const +{ + return i18n( "blend map modifiers" ); +} + +void PMBlendMapModifiers::serialize( QDomElement& e, QDomDocument& ) const +{ + e.setAttribute( "frequency", m_frequency ); + e.setAttribute( "phase", m_phase ); + e.setAttribute( "enable_frequency", m_enableFrequency ); + e.setAttribute( "enable_phase", m_enablePhase ); + e.setAttribute( "wave_exponent", m_waveFormExponent ); + e.setAttribute( "enable_wave", m_enableWaveForm ); + switch( m_waveFormType ) + { + case RampWave: + e.setAttribute( "waveform_type", "ramp" ); + break; + case TriangleWave: + e.setAttribute( "waveform_type", "triangle" ); + break; + case SineWave: + e.setAttribute( "waveform_type", "sine" ); + break; + case ScallopWave: + e.setAttribute( "waveform_type", "scallop" ); + break; + case CubicWave: + e.setAttribute( "waveform_type", "cubic" ); + break; + case PolyWave: + e.setAttribute( "waveform_type", "poly" ); + break; + } +} + +void PMBlendMapModifiers::readAttributes( const PMXMLHelper& h ) +{ + QString str = h.stringAttribute( "waveform_type", "ramp" ); + + if( str == "ramp" ) + m_waveFormType = RampWave; + else if( str == "triangle" ) + m_waveFormType = TriangleWave; + else if( str == "sine" ) + m_waveFormType = SineWave; + else if( str == "scallop" ) + m_waveFormType = ScallopWave; + else if( str == "cubic" ) + m_waveFormType = CubicWave; + else if( str == "poly" ) + m_waveFormType = PolyWave; + m_frequency = h.doubleAttribute( "frequency", frequencyDefault ); + m_enableFrequency = h.boolAttribute( "enable_frequency", false ); + m_phase = h.doubleAttribute( "phase", phaseDefault ); + m_enablePhase = h.boolAttribute( "enable_phase", false ); + m_enableWaveForm = h.boolAttribute( "enable_wave", false ); + m_waveFormExponent = h.doubleAttribute( "wave_exponent", waveFormExponentDefault ); +} + +void PMBlendMapModifiers::setFrequency( double c ) +{ + if( c != m_frequency ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFrequencyID, m_frequency ); + m_frequency = c; + } +} + +void PMBlendMapModifiers::enableFrequency( bool c ) +{ + if( c != m_enableFrequency ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableFrequencyID, m_enableFrequency ); + m_enableFrequency = c; + } +} + +void PMBlendMapModifiers::setPhase( double c ) +{ + if( c != m_phase ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMPhaseID, m_phase ); + m_phase = c; + } +} + +void PMBlendMapModifiers::enablePhase( bool c ) +{ + if( c != m_enablePhase ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnablePhaseID, m_enablePhase ); + m_enablePhase = c; + } +} + +void PMBlendMapModifiers::enableWaveForm( bool c ) +{ + if( c != m_enableWaveForm ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableWaveFormID, m_enableWaveForm ); + m_enableWaveForm = c; + } +} + +void PMBlendMapModifiers::setWaveFormExponent( double c ) +{ + if( c != m_waveFormExponent ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMWaveFormExponentID, m_waveFormExponent ); + m_waveFormExponent = c; + } +} + +void PMBlendMapModifiers::setWaveFormType( PMWaveFormType c ) +{ + if( c != m_waveFormType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMWaveFormTypeID, m_waveFormType ); + m_waveFormType = c; + } +} + +PMDialogEditBase* PMBlendMapModifiers::editWidget( QWidget* parent ) const +{ + return new PMBlendMapModifiersEdit( parent ); +} + +void PMBlendMapModifiers::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMFrequencyID: + setFrequency( data->doubleData( ) ); + break; + case PMEnableFrequencyID: + enableFrequency( data->boolData( ) ); + break; + case PMPhaseID: + setPhase( data->doubleData( ) ); + break; + case PMEnablePhaseID: + enablePhase( data->boolData( ) ); + break; + case PMWaveFormTypeID: + setWaveFormType( ( PMWaveFormType )data->intData( ) ); + break; + case PMEnableWaveFormID: + enableWaveForm( data->boolData( ) ); + break; + case PMWaveFormExponentID: + setWaveFormExponent( data->doubleData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMBlendMapModifiers::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmblendmapmodifiers.h b/kpovmodeler/pmblendmapmodifiers.h new file mode 100644 index 00000000..1fa45528 --- /dev/null +++ b/kpovmodeler/pmblendmapmodifiers.h @@ -0,0 +1,129 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMBLENDMAPMODIFIERS_H +#define PMBLENDMAPMODIFIERS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebase.h" +#include "pmcolor.h" +#include "pmvector.h" + +/** + * Class for povray blendmapmodifierss + */ +class PMBlendMapModifiers : public PMObject +{ + typedef PMObject Base; +public: + /** + * The type of the wave form + */ + enum PMWaveFormType { RampWave, TriangleWave, SineWave, ScallopWave, + CubicWave, PolyWave }; + + /** + * Creates an PMBlendMapModifiers + */ + PMBlendMapModifiers( PMPart* part ); + /** + * Deletes the object + */ + virtual ~PMBlendMapModifiers( ); + + /** */ + virtual PMObject* copy( ) const { return new PMBlendMapModifiers( *this ); } + + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMBlendMapModifiersEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pmblendmapmodifiers" ); } + + /** */ + virtual void restoreMemento( PMMemento* s ); + + /** */ + bool isFrequencyEnabled( ) const { return m_enableFrequency; } + /** */ + double frequency( ) const { return m_frequency; } + /** */ + bool isPhaseEnabled( ) const { return m_enablePhase; } + /** */ + double phase( ) const { return m_phase; } + /** */ + bool isWaveFormEnabled( ) const { return m_enableWaveForm; } + /** */ + PMWaveFormType waveFormType( ) const { return m_waveFormType; } + /** */ + double waveFormExponent( ) const { return m_waveFormExponent; } + + /** */ + void enableFrequency( bool c ); + /** */ + void setFrequency( double c ); + /** */ + void enablePhase( bool c ); + /** */ + void setPhase( double c ); + /** */ + void enableWaveForm( bool c ); + /** */ + void setWaveFormType( PMWaveFormType c ); + /** */ + void setWaveFormExponent( double c ); + +private: + /** + * IDs for @ref PMMementoData + */ + enum PMBlendMapModifiersMementoID { PMEnableFrequencyID, PMFrequencyID, + PMEnablePhaseID, PMPhaseID, PMEnableWaveFormID, + PMWaveFormTypeID, PMWaveFormExponentID }; + + bool m_enableFrequency; + double m_frequency; + bool m_enablePhase; + double m_phase; + bool m_enableWaveForm; + PMWaveFormType m_waveFormType; + double m_waveFormExponent; + + static PMMetaObject* s_pMetaObject; +}; + + +#endif diff --git a/kpovmodeler/pmblendmapmodifiersedit.cpp b/kpovmodeler/pmblendmapmodifiersedit.cpp new file mode 100644 index 00000000..8e8ff150 --- /dev/null +++ b/kpovmodeler/pmblendmapmodifiersedit.cpp @@ -0,0 +1,261 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmblendmapmodifiersedit.h" +#include "pmblendmapmodifiers.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" +#include "pmvector.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +PMBlendMapModifiersEdit::PMBlendMapModifiersEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMBlendMapModifiersEdit::createTopWidgets( ) +{ + QHBoxLayout* hl; + + Base::createTopWidgets( ); + + hl = new QHBoxLayout( topLayout( ) ); + m_pEnableFrequencyEdit = new QCheckBox( i18n( "Frequency:" ), this ); + m_pFrequencyEdit = new PMFloatEdit( this ); + hl->addWidget( m_pEnableFrequencyEdit ); + hl->addWidget( m_pFrequencyEdit ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + m_pEnablePhaseEdit = new QCheckBox( i18n( "Phase:" ), this ); + m_pPhaseEdit = new PMFloatEdit( this ); + hl->addWidget( m_pEnablePhaseEdit ); + hl->addWidget( m_pPhaseEdit ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + m_pEnableWaveFormEdit = new QCheckBox( i18n( "Wave form:" ), this ); + m_pWaveTypeCombo = new QComboBox( this ); + m_pWaveTypeCombo->insertItem( i18n( "Ramp" ) ); + m_pWaveTypeCombo->insertItem( i18n( "Triangle" ) ); + m_pWaveTypeCombo->insertItem( i18n( "Sine" ) ); + m_pWaveTypeCombo->insertItem( i18n( "Scallop" ) ); + m_pWaveTypeCombo->insertItem( i18n( "Cubic" ) ); + m_pWaveTypeCombo->insertItem( i18n( "Poly" ) ); + hl->addWidget( m_pEnableWaveFormEdit ); + hl->addWidget( m_pWaveTypeCombo ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + m_pWaveExponentLabel = new QLabel( i18n( "Exponent:" ), this ); + m_pWaveExponentEdit = new PMFloatEdit( this ); + hl->addWidget( m_pWaveExponentLabel ); + hl->addWidget( m_pWaveExponentEdit ); + hl->addStretch( 1 ); + + connect( m_pEnableFrequencyEdit, SIGNAL( clicked( ) ), SLOT( slotFrequencyClicked( ) ) ); + connect( m_pFrequencyEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pEnablePhaseEdit, SIGNAL( clicked( ) ), SLOT( slotPhaseClicked( ) ) ); + connect( m_pPhaseEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pEnableWaveFormEdit, SIGNAL( clicked( ) ), SLOT( slotWaveFormClicked( ) ) ); + connect( m_pWaveExponentEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pWaveTypeCombo, SIGNAL( activated( int ) ), SLOT( slotTypeComboChanged( int ) ) ); +} + +void PMBlendMapModifiersEdit::displayObject( PMObject* o ) +{ + QString str; + + if( o->isA( "BlendMapModifiers" ) ) + { + m_pDisplayedObject = ( PMBlendMapModifiers* ) o; + + m_pEnableFrequencyEdit->setChecked( m_pDisplayedObject->isFrequencyEnabled( ) ); + m_pEnablePhaseEdit->setChecked( m_pDisplayedObject->isPhaseEnabled( ) ); + m_pEnableWaveFormEdit->setChecked( m_pDisplayedObject->isWaveFormEnabled( ) ); + + m_pFrequencyEdit->setValue( m_pDisplayedObject->frequency( ) ); + m_pPhaseEdit->setValue( m_pDisplayedObject->phase( ) ); + m_pWaveExponentEdit->setValue( m_pDisplayedObject->waveFormExponent( ) ); + + switch( m_pDisplayedObject->waveFormType( ) ) + { + case PMBlendMapModifiers::RampWave: + m_pWaveTypeCombo->setCurrentItem( 0 ); + break; + case PMBlendMapModifiers::TriangleWave: + m_pWaveTypeCombo->setCurrentItem( 1 ); + break; + case PMBlendMapModifiers::SineWave: + m_pWaveTypeCombo->setCurrentItem( 2 ); + break; + case PMBlendMapModifiers::ScallopWave: + m_pWaveTypeCombo->setCurrentItem( 3 ); + break; + case PMBlendMapModifiers::CubicWave: + m_pWaveTypeCombo->setCurrentItem( 4 ); + break; + case PMBlendMapModifiers::PolyWave: + m_pWaveTypeCombo->setCurrentItem( 5 ); + break; + } + + slotFrequencyClicked( ); + slotPhaseClicked( ); + slotWaveFormClicked( ); + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMBlendMapModifiersEdit: Can't display object\n"; +} + +void PMBlendMapModifiersEdit::setBlendMapModifiersType( int i ) +{ + m_pWaveTypeCombo->setCurrentItem( i ); + slotTypeComboChanged( i ); +} + +void PMBlendMapModifiersEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + + m_pDisplayedObject->enableFrequency( m_pEnableFrequencyEdit->isChecked( ) ); + m_pDisplayedObject->enablePhase( m_pEnablePhaseEdit->isChecked( ) ); + m_pDisplayedObject->enableWaveForm( m_pEnableWaveFormEdit->isChecked( ) ); + + if( m_pEnableFrequencyEdit->isChecked( ) ) + m_pDisplayedObject->setFrequency( m_pFrequencyEdit->value( ) ); + + if( m_pEnablePhaseEdit->isChecked( ) ) + m_pDisplayedObject->setPhase( m_pPhaseEdit->value( ) ); + + if( m_pEnableWaveFormEdit->isChecked( ) ) + { + switch( m_pWaveTypeCombo->currentItem( ) ) + { + case 0: /* Ramp Wave */ + m_pDisplayedObject->setWaveFormType( PMBlendMapModifiers::RampWave ); + break; + case 1: /* Triangle Wave */ + m_pDisplayedObject->setWaveFormType( PMBlendMapModifiers::TriangleWave ); + break; + case 2: /* Sine Wave */ + m_pDisplayedObject->setWaveFormType( PMBlendMapModifiers::SineWave ); + break; + case 3: /* Scallop Wave */ + m_pDisplayedObject->setWaveFormType( PMBlendMapModifiers::ScallopWave ); + break; + case 4: /* Cubic Wave */ + m_pDisplayedObject->setWaveFormType( PMBlendMapModifiers::CubicWave ); + break; + case 5: /* Poly Wave */ + m_pDisplayedObject->setWaveFormType( PMBlendMapModifiers::PolyWave ); + m_pDisplayedObject->setWaveFormExponent( m_pWaveExponentEdit->value( ) ); + break; + } + } + } +} + +bool PMBlendMapModifiersEdit::isDataValid( ) +{ + if( !m_pFrequencyEdit->isDataValid( ) ) return false; + if( !m_pPhaseEdit->isDataValid( ) ) return false; + + switch( m_pWaveTypeCombo->currentItem( ) ) + { + case 5: /* Poly Wave */ + if( !m_pWaveExponentEdit->isDataValid( ) ) return false; + break; + } + + return Base::isDataValid( ); +} + +void PMBlendMapModifiersEdit::slotTypeComboChanged( int c ) +{ + switch( c ) + { + case 5: /* Poly Wave */ + m_pWaveExponentLabel->show( ); + m_pWaveExponentEdit->show( ); + break; + default: + m_pWaveExponentLabel->hide( ); + m_pWaveExponentEdit->hide( ); + break; + } + emit dataChanged( ); + emit sizeChanged( ); +} + +void PMBlendMapModifiersEdit::slotFrequencyClicked( ) +{ + if( m_pEnableFrequencyEdit->isChecked( ) ) + m_pFrequencyEdit->setEnabled( true ); + else + m_pFrequencyEdit->setEnabled( false ); + emit dataChanged( ); + emit sizeChanged( ); +} + +void PMBlendMapModifiersEdit::slotPhaseClicked( ) +{ + if(m_pEnablePhaseEdit->isChecked( ) ) + m_pPhaseEdit->setEnabled( true ); + else + m_pPhaseEdit->setEnabled( false ); + emit dataChanged( ); + emit sizeChanged( ); +} + +void PMBlendMapModifiersEdit::slotWaveFormClicked( ) +{ + if(m_pEnableWaveFormEdit->isChecked( ) ) + { + m_pWaveTypeCombo->setEnabled( true ); + slotTypeComboChanged( m_pWaveTypeCombo->currentItem( ) ); + } + else + { + m_pWaveTypeCombo->setEnabled( false ); + m_pWaveExponentLabel->hide( ); + m_pWaveExponentEdit->hide( ); + } + emit dataChanged( ); + emit sizeChanged( ); +} + +#include "pmblendmapmodifiersedit.moc" diff --git a/kpovmodeler/pmblendmapmodifiersedit.h b/kpovmodeler/pmblendmapmodifiersedit.h new file mode 100644 index 00000000..eb4e40b5 --- /dev/null +++ b/kpovmodeler/pmblendmapmodifiersedit.h @@ -0,0 +1,100 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMBLENDMAPMODIFIERSEDIT_H +#define PMBLENDMAPMODIFIERSEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMBlendMapModifiers; +class PMVectorEdit; +class QComboBox; +class PMFloatEdit; +class PMIntEdit; +class QLabel; +class QCheckBox; +class QWidget; +class QLineEdit; +class QPushButton; + +/** + * Dialog edit class for @ref PMBlendMapModifiers. + */ +class PMBlendMapModifiersEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMBlendMapModifiersEdit with parent and name + */ + PMBlendMapModifiersEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + /** + * Slot called whenever a new Wave Form type is selected. + */ + void slotTypeComboChanged( int c ); + /** + * Slot called when frequency is activated/deactivated. + */ + void slotFrequencyClicked( ); + /** + * Slot called when phase is activated/deactivated. + */ + void slotPhaseClicked( ); + /** + * Slot called when wave form is activated/deactivated. + */ + void slotWaveFormClicked( ); + +private: + /** + * Set's the combo box and enables/disables widgets. + */ + void setBlendMapModifiersType( int i ); + PMBlendMapModifiers* m_pDisplayedObject; + + QComboBox* m_pWaveTypeCombo; + PMFloatEdit* m_pFrequencyEdit; + PMFloatEdit* m_pPhaseEdit; + PMFloatEdit* m_pWaveExponentEdit; + QLabel* m_pWaveExponentLabel; + QCheckBox* m_pEnableFrequencyEdit; + QCheckBox* m_pEnablePhaseEdit; + QCheckBox* m_pEnableWaveFormEdit; +}; + + +#endif diff --git a/kpovmodeler/pmblob.cpp b/kpovmodeler/pmblob.cpp new file mode 100644 index 00000000..800c3b5a --- /dev/null +++ b/kpovmodeler/pmblob.cpp @@ -0,0 +1,175 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmblob.h" + +#include "pmxmlhelper.h" +#include "pmblobedit.h" +#include "pmmemento.h" + +#include + +const double c_defaultThreshold = 0.5; +bool c_defaultSturm = false; +bool c_defaultHierarchy = false; + +PMDefinePropertyClass( PMBlob, PMBlobProperty ); + +PMMetaObject* PMBlob::s_pMetaObject = 0; +PMObject* createNewBlob( PMPart* part ) +{ + return new PMBlob( part ); +} + +PMBlob::PMBlob( PMPart* part ) + : Base( part ) +{ + m_threshold = c_defaultThreshold; + m_sturm = c_defaultSturm; + m_hierarchy = c_defaultHierarchy; +} + +PMBlob::PMBlob( const PMBlob& b ) + : Base( b ) +{ + m_threshold = b.m_threshold; + m_sturm = b.m_sturm; + m_hierarchy = b.m_hierarchy; +} + +PMBlob::~PMBlob( ) +{ +} + +QString PMBlob::description( ) const +{ + return i18n( "blob" ); +} + +void PMBlob::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "threshold", m_threshold ); + e.setAttribute( "sturm", m_sturm ); + e.setAttribute( "hierarchy", m_hierarchy ); + Base::serialize( e, doc ); +} + +void PMBlob::readAttributes( const PMXMLHelper& h ) +{ + m_threshold = h.doubleAttribute( "threshold", c_defaultThreshold ); + m_sturm = h.boolAttribute( "sturm", c_defaultSturm ); + m_hierarchy = h.boolAttribute( "hierarchy", c_defaultHierarchy ); + Base::readAttributes( h ); +} + +PMMetaObject* PMBlob::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Blob", Base::metaObject( ), + createNewBlob ); + s_pMetaObject->addProperty( + new PMBlobProperty( "threshold", &PMBlob::setThreshold, &PMBlob::threshold ) ); + s_pMetaObject->addProperty( + new PMBlobProperty( "hierarchy", &PMBlob::setHierarchy, &PMBlob::hierarchy ) ); + s_pMetaObject->addProperty( + new PMBlobProperty( "sturm", &PMBlob::setSturm, &PMBlob::sturm ) ); + } + return s_pMetaObject; +} + +void PMBlob::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMBlob::setThreshold( double t ) +{ + if( t <= 0.0 ) + { + kdError( PMArea ) << "Threshold is not positive in PMBlob::setThreshold\n"; + t = 1.0; + } + + if( t != m_threshold ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMThresholdID, m_threshold ); + m_threshold = t; + } +} + +void PMBlob::setSturm( bool s ) +{ + if( s != m_sturm ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSturmID, m_sturm ); + m_sturm = s; + } +} + +void PMBlob::setHierarchy( bool h ) +{ + if( h != m_hierarchy ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMHierarchyID, m_hierarchy ); + m_hierarchy = h; + } +} + +PMDialogEditBase* PMBlob::editWidget( QWidget* parent ) const +{ + return new PMBlobEdit( parent ); +} + +void PMBlob::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMThresholdID: + setThreshold( data->doubleData( ) ); + break; + case PMSturmID: + setSturm( data->boolData( ) ); + break; + case PMHierarchyID: + setHierarchy( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMBlob::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmblob.h b/kpovmodeler/pmblob.h new file mode 100644 index 00000000..986cec8c --- /dev/null +++ b/kpovmodeler/pmblob.h @@ -0,0 +1,113 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMBLOB_H +#define PMBLOB_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" + +/** + * Class for povray blobs. + */ + +class PMBlob : public PMSolidObject +{ + typedef PMSolidObject Base; +public: + /** + * Creates an empty PMBlob + */ + PMBlob( PMPart* part ); + /** + * Copy constructor + */ + PMBlob( const PMBlob& b ); + /** + * deletes the PMBlob + */ + virtual ~PMBlob( ); + + /** */ + virtual PMObject* copy( ) const { return new PMBlob( *this ); } + /** */ + virtual QString description( ) const; + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMBlobEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmblob" ); } + + /** + * Returns the threshold + */ + double threshold( ) const { return m_threshold; } + /** + * Sets the threshold + */ + void setThreshold( double t ); + /** + * Returns the hierarchy flag + */ + bool hierarchy( ) const { return m_hierarchy; } + /** + * Sets the hierarchy flag + */ + void setHierarchy( bool h ); + /** + * Returns the sturm flag + */ + bool sturm( ) const { return m_sturm; } + /** + * Sets the sturm flag + */ + void setSturm( bool s ); + + /** */ + virtual void restoreMemento( PMMemento* s ); + +private: + /** + * IDs for @ref PMMementoData + */ + enum PMBlobMementoID { PMThresholdID, PMHierarchyID, PMSturmID }; + double m_threshold; + bool m_hierarchy; + bool m_sturm; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmblobcylinder.cpp b/kpovmodeler/pmblobcylinder.cpp new file mode 100644 index 00000000..687ce132 --- /dev/null +++ b/kpovmodeler/pmblobcylinder.cpp @@ -0,0 +1,468 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmblobcylinder.h" + +#include "pmxmlhelper.h" +#include "pmboxedit.h" +#include "pmmemento.h" +#include "pm3dcontrolpoint.h" +#include "pmdefaults.h" +#include "pmdistancecontrolpoint.h" +#include "pmblobcylinderedit.h" + +#include + +PMDefinePropertyClass( PMBlobCylinder, PMBlobCylinderProperty ); + +PMMetaObject* PMBlobCylinder::s_pMetaObject = 0; +PMObject* createNewBlobCylinder( PMPart* part ) +{ + return new PMBlobCylinder( part ); +} + +const double c_defaultRadius = 0.5; +const PMVector c_defaultEnd1 = PMVector ( 0, 0.5, 0 ); +const PMVector c_defaultEnd2 = PMVector ( 0, -0.5, 0 ); +const double c_defaultStrength = 1.0; + +/** default cylinder structure */ +PMViewStructure* PMBlobCylinder::s_pDefaultViewStructure = 0; +int PMBlobCylinder::s_vStep = c_defaultBlobCylinderVSteps; +int PMBlobCylinder::s_uStep = c_defaultBlobCylinderUSteps; +int PMBlobCylinder::s_parameterKey = 0; + + +PMBlobCylinder::PMBlobCylinder( PMPart* part ) + : Base( part ) +{ + m_end1 = c_defaultEnd1; + m_end2 = c_defaultEnd2; + m_radius = c_defaultRadius; + m_strength = c_defaultStrength; +} + +PMBlobCylinder::PMBlobCylinder( const PMBlobCylinder& c ) + : Base( c ) +{ + m_end1 = c.m_end1; + m_end2 = c.m_end2; + m_radius = c.m_radius; + m_strength = c.m_strength; +} + +PMBlobCylinder::~PMBlobCylinder( ) +{ +} + +QString PMBlobCylinder::description( ) const +{ + return i18n( "blob cylinder" ); +} + +void PMBlobCylinder::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "end_a", m_end1.serializeXML( ) ); + e.setAttribute( "end_b", m_end2.serializeXML( ) ); + e.setAttribute( "radius", m_radius ); + e.setAttribute( "strength", m_strength ); + Base::serialize( e, doc ); +} + +void PMBlobCylinder::readAttributes( const PMXMLHelper& h ) +{ + m_end1 = h.vectorAttribute( "end_a", c_defaultEnd1 ); + m_end2 = h.vectorAttribute( "end_b", c_defaultEnd2 ); + m_radius = h.doubleAttribute( "radius", c_defaultRadius ); + m_strength = h.doubleAttribute( "strength", c_defaultStrength ); + Base::readAttributes( h ); +} + +PMMetaObject* PMBlobCylinder::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "BlobCylinder", Base::metaObject( ), + createNewBlobCylinder ); + s_pMetaObject->addProperty( + new PMBlobCylinderProperty( "end1", &PMBlobCylinder::setEnd1, + &PMBlobCylinder::end1 ) ); + s_pMetaObject->addProperty( + new PMBlobCylinderProperty( "end2", &PMBlobCylinder::setEnd2, + &PMBlobCylinder::end2 ) ); + s_pMetaObject->addProperty( + new PMBlobCylinderProperty( "radius", &PMBlobCylinder::setRadius, + &PMBlobCylinder::radius ) ); + s_pMetaObject->addProperty( + new PMBlobCylinderProperty( "strength", &PMBlobCylinder::setStrength, + &PMBlobCylinder::strength ) ); + } + return s_pMetaObject; +} + +void PMBlobCylinder::setEnd1( const PMVector& p ) +{ + if( p != m_end1 ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnd1ID, m_end1 ); + m_end1 = p; + m_end1.resize( 3 ); + setViewStructureChanged( ); + } +} + +void PMBlobCylinder::setEnd2( const PMVector& p ) +{ + if( p != m_end2 ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnd2ID, m_end2 ); + m_end2 = p; + m_end2.resize( 3 ); + setViewStructureChanged( ); + } +} + +void PMBlobCylinder::setRadius( double radius ) +{ + if( m_radius != radius ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRadiusID, m_radius ); + m_radius = radius; + setViewStructureChanged( ); + } +} + +void PMBlobCylinder::setStrength( double s ) +{ + if( s != m_strength ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMStrengthID, m_strength ); + m_strength = s; + } +} + +PMDialogEditBase* PMBlobCylinder::editWidget( QWidget* parent ) const +{ + return new PMBlobCylinderEdit( parent ); +} + +void PMBlobCylinder::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMEnd1ID: + setEnd1( data->vectorData( ) ); + break; + case PMEnd2ID: + setEnd2( data->vectorData( ) ); + break; + case PMRadiusID: + setRadius( data->doubleData( ) ); + break; + case PMStrengthID: + setStrength( data->doubleData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMBlobCylinder::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + +bool PMBlobCylinder::isDefault( ) +{ + if( ( m_end1 == c_defaultEnd1 ) && ( m_end2 == c_defaultEnd2 ) + && ( m_radius == c_defaultRadius ) + && globalDetail( ) ) + return true; + return false; +} + +void PMBlobCylinder::createViewStructure( ) +{ + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultViewStructure ( ) ); + m_pViewStructure->points( ).detach( ); + } + + int uStep = (int)( ( (float)s_uStep / 2 ) * ( displayDetail( ) + 1 ) ); + int vStep = (int)( ( (float)s_vStep / 2 ) * ( displayDetail( ) + 1 ) ); + unsigned ptsSize = vStep * uStep * 2 + 2; + unsigned lineSize = vStep * uStep * 4 + vStep; + + if( ptsSize != m_pViewStructure->points( ).size( ) ) + m_pViewStructure->points( ).resize( ptsSize ); + + createPoints( m_pViewStructure->points( ), m_end1, m_end2, m_radius, uStep, vStep ); + + if( lineSize != m_pViewStructure->lines( ).size( ) ) + { + m_pViewStructure->lines( ).detach( ); + m_pViewStructure->lines( ).resize( lineSize ); + createLines( m_pViewStructure->lines( ), uStep, vStep ); + } +} + +PMViewStructure* PMBlobCylinder::defaultViewStructure( ) const +{ + if( !s_pDefaultViewStructure || s_pDefaultViewStructure->parameterKey( ) != viewStructureParameterKey( ) ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + int uStep = (int)( ( (float)s_uStep / 2 ) * ( displayDetail( ) + 1 ) ); + int vStep = (int)( ( (float)s_vStep / 2 ) * ( displayDetail( ) + 1 ) ); + + s_pDefaultViewStructure = + new PMViewStructure( vStep * uStep * 2 + 2, + vStep * uStep * 4 + vStep ); + + createPoints( s_pDefaultViewStructure->points( ), c_defaultEnd1, + c_defaultEnd2, c_defaultRadius, uStep, vStep ); + + createLines( s_pDefaultViewStructure->lines( ), uStep, vStep ); + } + return s_pDefaultViewStructure; +} + +void PMBlobCylinder::createLines( PMLineArray& lines, int uStep, int vStep ) +{ + int u, v; + int offset = 0; + + // horizontal lines + for( u = 0; u < ( uStep * 2 ); u++ ) + { + for( v = 0; v < ( vStep - 1 ); v++ ) + lines[offset + v] = + PMLine( u * vStep + v + 1, u * vStep + v + 2 ); + lines[offset + vStep - 1] = + PMLine( u * vStep + 1, u * vStep + vStep ); + + offset += vStep; + } + + // vertical lines + // lines at the "north pole" + for( v = 0; v < vStep; v++ ) + lines[offset + v] = PMLine( 0, v + 1 ); + offset += vStep; + + for( v = 0; v < vStep; v++ ) + { + for( u = 0; u < ( 2 * uStep - 1 ); u++ ) + { + lines[offset + u] = + PMLine( u * vStep + v + 1, ( u + 1 ) * vStep + v + 1 ); + } + offset += ( 2 * uStep - 1 ); + } + // lines at the "south pole" + for( v = 0; v < vStep; v++ ) + lines[offset + v] = PMLine( ( 2 * uStep - 1 ) * vStep + v + 1, + 2 * uStep * vStep + 1 ); + // offset += vStep; +} + +void PMBlobCylinder::createPoints( PMPointArray& points, const PMVector& end1, + const PMVector& end2, double radius, int uStep, int vStep ) +{ + double uRadStep = M_PI / uStep / 2.0; + double vRadStep = 2 * M_PI / vStep; + double du = uRadStep; + + if( radius < 0 ) + radius = -radius; + + PMVector pointAt = end2 - end1; + double pl = pointAt.abs( ); + if( approxZero( pl ) ) + pointAt = PMVector( 0.0, 0.0, 1.0 ); + else + pointAt /= pl; + + PMMatrix rotation = PMMatrix::rotation( pointAt, vRadStep ); + PMVector ortho = pointAt.orthogonal( ); + ortho /= ortho.abs( ); + + points[0] = PMPoint( end1 - pointAt * radius ); + points[vStep * uStep * 2 + 1] = PMPoint( end2 + pointAt * radius ); + + int u, v; + for( u = 0; u < uStep; u++ ) + { + PMVector end = ortho * radius * sin( du ); + PMVector pv = pointAt * radius * cos( du ); + PMVector e1 = end1 - pv; + PMVector e2 = end2 + pv; + + for( v = 0; v < vStep; v++ ) + { + points[u * vStep + v + 1] = PMPoint( e1 + end ); + points[vStep * uStep * 2 - ( u + 1 ) * vStep + v + 1] + = PMPoint( e2 + end ); + end = rotation * end; + } + du += uRadStep; + } +} + +void PMBlobCylinder::controlPoints( PMControlPointList & list ) +{ + PMVector center, angle1, angle2; + center = m_end1 - m_end2; + double pl = center.abs( ); + if( approxZero( pl ) ) + center = PMVector( 0.0, 1.0, 0.0 ); + else + center /= pl; + + angle1 = center.orthogonal( ); + angle2 = PMVector::cross( center, angle1 ); + + PM3DControlPoint* pb = new PM3DControlPoint( m_end1, PMEnd1ID, i18n( "End 1" ) ); + list.append( pb ); + list.append( new PM3DControlPoint( m_end2, PMEnd2ID, i18n( "End 2" ) ) ); + list.append( new PMDistanceControlPoint( pb, angle1, m_radius, PMRadiusID, i18n( "Radius (1)" ) ) ); + list.append( new PMDistanceControlPoint( pb, angle2, m_radius, PMRadiusID, i18n( "Radius (2)" ) ) ); +} + + +void PMBlobCylinder::controlPointsChanged( PMControlPointList & list ) +{ + PMControlPoint* p; + bool pointChanged = false; + bool radiusChanged = false; + + for( p = list.first( ); p; p = list.next( ) ) + { + if( p->changed( ) ) + { + switch( p->id( ) ) + { + case PMEnd1ID: + setEnd1( ( ( PM3DControlPoint *) p)->point( ) ); + pointChanged = true; + break; + case PMEnd2ID: + setEnd2( ( ( PM3DControlPoint *) p)->point( ) ); + pointChanged = true; + break; + case PMRadiusID: + setRadius( ( ( PMDistanceControlPoint *) p)->distance( ) ); + radiusChanged = true; + break; + default: + kdError( PMArea ) << "Wrong ID in PMBlobCylinder::controlPointsChanged\n"; + break; + } + } + } + + if( pointChanged ) + { + PMVector center, angle1, angle2; + bool firstPoint = true; + + center = m_end1 - m_end2; + double pl = center.abs( ); + if( approxZero( pl ) ) + center = PMVector( 0.0, 1.0, 0.0 ); + else + center /= pl; + + angle1 = center.orthogonal( ); + angle2 = PMVector::cross( center, angle1 ); + + for( p = list.first( ); p; p = list.next( ) ) + if( p->id( ) == PMRadiusID ) + { + if( firstPoint ) + { + ( ( PMDistanceControlPoint *) p)->setDirection( angle1 ); + firstPoint = false; + } + else + ( ( PMDistanceControlPoint *) p)->setDirection( angle2 ); + } + } + + if( radiusChanged ) + for( p = list.first( ); p; p = list.next( ) ) + if( p->id( ) == PMRadiusID ) + ( ( PMDistanceControlPoint *) p)->setDistance( m_radius ); +} + +void PMBlobCylinder::setUSteps( int u ) +{ + if( u >= 2 ) + { + s_uStep = u; + if( s_pDefaultViewStructure ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + } + } + else + kdDebug( PMArea ) << "PMBlobCylinder::setUSteps: U must be greater than 1\n"; + s_parameterKey++; +} + +void PMBlobCylinder::setVSteps( int v ) +{ + if( v >= 4 ) + { + s_vStep = v; + if( s_pDefaultViewStructure ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + } + } + else + kdDebug( PMArea ) << "PMBlobCylinder::setVSteps: V must be greater than 3\n"; + s_parameterKey++; +} + +void PMBlobCylinder::cleanUp( ) const +{ + if( s_pDefaultViewStructure ) + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} diff --git a/kpovmodeler/pmblobcylinder.h b/kpovmodeler/pmblobcylinder.h new file mode 100644 index 00000000..80986cfe --- /dev/null +++ b/kpovmodeler/pmblobcylinder.h @@ -0,0 +1,181 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMBLOBCYLINDER_H +#define PMBLOBCYLINDER_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdetailobject.h" +#include "pmvector.h" +#include "pmviewstructure.h" + +/** + * Class for povray blob cylinder + */ + +class PMBlobCylinder : public PMDetailObject +{ + typedef PMDetailObject Base; +public: + /** + * Creates a cylinder + */ + PMBlobCylinder( PMPart* part ); + /** + * Copy constructor + */ + PMBlobCylinder( const PMBlobCylinder& c ); + + /** + * Deletes the cylinder + */ + virtual ~PMBlobCylinder( ); + + /** */ + virtual PMObject* copy( ) const { return new PMBlobCylinder( *this ); } + + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMBlobCylinderEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmblobcylinder" ); } + + /** + * Return the end_1 + */ + PMVector end1( ) const { return m_end1; } + /** + * Sets end_1 + */ + void setEnd1( const PMVector& p ); + /** + * Return the end_2 + */ + PMVector end2( ) const { return m_end2; } + /** + * Sets end_2 + */ + void setEnd2( const PMVector& p ); + /** + * return the radius of the cylinder + */ + double radius( ) const { return m_radius; } + /** + * Sets the radius of the cylinder + */ + void setRadius( double radius ); + /** + * Returns the strength + */ + double strength( ) const { return m_strength; } + /** + * Sets the strength + */ + void setStrength( double s ); + + /** + * Sets the number of latitutes + */ + static void setUSteps( int u ); + /** + * Sets the number of longitudes + */ + static void setVSteps( int v ); + /** + * Returns the number or latitutes + */ + static int uSteps( ) { return s_uStep; } + /** + * Returns the number or longitudes + */ + static int vSteps( ) { return s_vStep; } + + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual void controlPoints( PMControlPointList& list ); + /** */ + virtual void controlPointsChanged( PMControlPointList& list ); + /** */ + virtual bool hasDisplayDetail( ) const { return true; } + /** */ + virtual void cleanUp( ) const; + +protected: + /** */ + virtual bool isDefault( ); + /** */ + virtual void createViewStructure( ); + /** */ + virtual PMViewStructure *defaultViewStructure( ) const; + /** */ + virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey(); } + +private: + /** + * Creates the lines for the view structure + */ + static void createLines( PMLineArray& lines, int uStep, int vStep ); + /** + * Creates the points for the view structure + */ + static void createPoints( PMPointArray& points, const PMVector& end1, + const PMVector& end2, double radius, int uStep, int vStep ); + + /** + * IDs for @ref PMMementoData + */ + enum PMBlobCylinderMementoID { PMEnd1ID, PMEnd2ID, PMRadiusID, PMStrengthID }; + /** + * ends of cylinder + */ + PMVector m_end1, m_end2; + /** + * radius of cylinder + */ + double m_radius; + double m_strength; + /** + * The default view structure. It can be shared between cylinders + */ + static PMViewStructure* s_pDefaultViewStructure; + static int s_vStep; + static int s_uStep; + static int s_parameterKey; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmblobcylinderedit.cpp b/kpovmodeler/pmblobcylinderedit.cpp new file mode 100644 index 00000000..9313b8af --- /dev/null +++ b/kpovmodeler/pmblobcylinderedit.cpp @@ -0,0 +1,114 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmblobcylinderedit.h" +#include "pmblobcylinder.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" + +#include +#include +#include +#include + +PMBlobCylinderEdit::PMBlobCylinderEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMBlobCylinderEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* layout; + QGridLayout* gl; + + m_pEnd1 = new PMVectorEdit( "x", "y", "z", this ); + m_pEnd2 = new PMVectorEdit( "x", "y", "z", this ); + m_pRadius = new PMFloatEdit( this ); + m_pStrength = new PMFloatEdit( this ); + + gl = new QGridLayout( topLayout( ), 2, 2 ); + gl->addWidget( new QLabel( i18n( "End 1:" ), this ), 0, 0 ); + gl->addWidget( m_pEnd1, 0, 1 ); + gl->addWidget( new QLabel( i18n( "End 2:" ), this ), 1, 0 ); + gl->addWidget( m_pEnd2, 1, 1 ); + + layout = new QHBoxLayout( topLayout( ) ); + gl = new QGridLayout( layout, 2, 2 ); + gl->addWidget( new QLabel( i18n( "Radius:" ), this ), 0, 0 ); + gl->addWidget( m_pRadius, 0, 1 ); + gl->addWidget( new QLabel( i18n( "Strength:" ), this ), 1, 0 ); + gl->addWidget( m_pStrength, 1, 1 ); + layout->addStretch( 1 ); + + connect( m_pEnd1, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pEnd2, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pRadius, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pStrength, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMBlobCylinderEdit::displayObject( PMObject* o ) +{ + if( o->isA( "BlobCylinder" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMBlobCylinder* ) o; + + m_pEnd1->setVector( m_pDisplayedObject->end1( ) ); + m_pEnd2->setVector( m_pDisplayedObject->end2( ) ); + m_pRadius->setValue( m_pDisplayedObject->radius( ) ); + m_pStrength->setValue( m_pDisplayedObject->strength( ) ); + + m_pEnd1->setReadOnly( readOnly ); + m_pEnd2->setReadOnly( readOnly ); + m_pRadius->setReadOnly( readOnly ); + m_pStrength->setReadOnly( readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMBlobCylinderEdit: Can't display object\n"; +} + +void PMBlobCylinderEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setEnd1( m_pEnd1->vector( ) ); + m_pDisplayedObject->setEnd2( m_pEnd2->vector( ) ); + m_pDisplayedObject->setRadius( m_pRadius->value( ) ); + m_pDisplayedObject->setStrength( m_pStrength->value( ) ); + } +} + +bool PMBlobCylinderEdit::isDataValid( ) +{ + if( m_pEnd1->isDataValid( ) ) + if( m_pEnd2->isDataValid( ) ) + if( m_pRadius->isDataValid( ) ) + if( m_pStrength->isDataValid( ) ) + return Base::isDataValid( ); + return false; +} + +#include "pmblobcylinderedit.moc" + + diff --git a/kpovmodeler/pmblobcylinderedit.h b/kpovmodeler/pmblobcylinderedit.h new file mode 100644 index 00000000..d156e412 --- /dev/null +++ b/kpovmodeler/pmblobcylinderedit.h @@ -0,0 +1,61 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMBLOBCYLINDEREDIT_H +#define PMBLOBCYLINDEREDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdetailobjectedit.h" + +class PMVectorEdit; +class PMFloatEdit; +class PMBlobCylinder; + +class PMBlobCylinderEdit : public PMDetailObjectEdit +{ + Q_OBJECT + typedef PMDetailObjectEdit Base; +public: + /** + * Creates a PMBlobCylinderEdit with parent and name + */ + PMBlobCylinderEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMBlobCylinder* m_pDisplayedObject; + PMVectorEdit* m_pEnd1; + PMVectorEdit* m_pEnd2; + PMFloatEdit* m_pRadius; + PMFloatEdit* m_pStrength; +}; +#endif diff --git a/kpovmodeler/pmblobedit.cpp b/kpovmodeler/pmblobedit.cpp new file mode 100644 index 00000000..80ebd510 --- /dev/null +++ b/kpovmodeler/pmblobedit.cpp @@ -0,0 +1,96 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmblobedit.h" +#include "pmblob.h" +#include "pmlineedits.h" + +#include +#include +#include +#include + +PMBlobEdit::PMBlobEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMBlobEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Threshold:" ), this ) ); + m_pThreshold = new PMFloatEdit( this ); + hl->addWidget( m_pThreshold ); + m_pThreshold->setValidation( true, 0.0, false, 0 ); + m_pThreshold->setValidationOperator( PMFloatEdit::OpGreater, + PMFloatEdit::OpLess ); + hl->addStretch( 1 ); + + m_pSturm = new QCheckBox( i18n( "Sturm" ), this ); + topLayout( )->addWidget( m_pSturm ); + m_pHierarchy = new QCheckBox( i18n( "Hierarchy" ), this ); + topLayout( )->addWidget( m_pHierarchy ); + + connect( m_pThreshold, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pHierarchy, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pSturm, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMBlobEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Blob" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMBlob* ) o; + + m_pThreshold->setValue( m_pDisplayedObject->threshold( ) ); + m_pSturm->setChecked( m_pDisplayedObject->sturm( ) ); + m_pHierarchy->setChecked( m_pDisplayedObject->hierarchy( ) ); + + m_pThreshold->setReadOnly( readOnly ); + m_pSturm->setEnabled( !readOnly ); + m_pHierarchy->setEnabled( !readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMBlobEdit: Can't display object\n"; +} + +void PMBlobEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setThreshold( m_pThreshold->value( ) ); + m_pDisplayedObject->setSturm( m_pSturm->isChecked( ) ); + m_pDisplayedObject->setHierarchy( m_pHierarchy->isChecked( ) ); + } +} + +bool PMBlobEdit::isDataValid( ) +{ + if( m_pThreshold->isDataValid( ) ) + return Base::isDataValid( ); + return false; +} + +#include "pmblobedit.moc" diff --git a/kpovmodeler/pmblobedit.h b/kpovmodeler/pmblobedit.h new file mode 100644 index 00000000..df07ba30 --- /dev/null +++ b/kpovmodeler/pmblobedit.h @@ -0,0 +1,65 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMBLOBEDIT_H +#define PMBLOBEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" + +class PMBlob; +class PMFloatEdit; +class QCheckBox; + +/** + * Dialog edit class for @ref PMBlob + */ +class PMBlobEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMBlobEdit with parent and name + */ + PMBlobEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMBlob* m_pDisplayedObject; + PMFloatEdit* m_pThreshold; + QCheckBox* m_pSturm; + QCheckBox* m_pHierarchy; +}; + + +#endif diff --git a/kpovmodeler/pmblobsphere.cpp b/kpovmodeler/pmblobsphere.cpp new file mode 100644 index 00000000..6ca96769 --- /dev/null +++ b/kpovmodeler/pmblobsphere.cpp @@ -0,0 +1,391 @@ +/* +************************************************************************** + description + ------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmblobsphere.h" + +#include "pmxmlhelper.h" +#include "pmblobsphereedit.h" +#include "pmmemento.h" +#include "pm3dcontrolpoint.h" +#include "pmdistancecontrolpoint.h" +#include "pmdefaults.h" + +#include + +PMDefinePropertyClass( PMBlobSphere, PMBlobSphereProperty ); + +PMMetaObject* PMBlobSphere::s_pMetaObject = 0; +PMObject* createNewBlobSphere( PMPart* part ) +{ + return new PMBlobSphere( part ); +} + +/** default param for the sphere */ +const double c_defaultRadius = 0.5; +const PMVector c_defaultCentre = PMVector( 0, 0, 0 ); +const double c_defaultStrength = 1.0; + +/** default sphere structure */ +PMViewStructure* PMBlobSphere::s_pDefaultViewStructure = 0; + +int PMBlobSphere::s_vStep = c_defaultBlobSphereVSteps; +int PMBlobSphere::s_uStep = c_defaultBlobSphereUSteps; +int PMBlobSphere::s_parameterKey = 0; + +PMBlobSphere::PMBlobSphere( PMPart* part ) + : Base( part ) +{ + m_radius = c_defaultRadius; + m_centre = c_defaultCentre; + m_strength = c_defaultStrength; +} + +PMBlobSphere::PMBlobSphere( const PMBlobSphere& s ) + : Base( s ) +{ + m_radius = s.m_radius; + m_centre = s.m_centre; + m_strength = s.m_strength; +} + +PMBlobSphere::~PMBlobSphere( ) +{ +} + + +QString PMBlobSphere::description( ) const +{ + return i18n( "blob sphere" ); +} + +PMMetaObject* PMBlobSphere::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "BlobSphere", Base::metaObject( ), + createNewBlobSphere ); + s_pMetaObject->addProperty( + new PMBlobSphereProperty( "center", &PMBlobSphere::setCentre, + &PMBlobSphere::centre ) ); + s_pMetaObject->addProperty( + new PMBlobSphereProperty( "radius", &PMBlobSphere::setRadius, + &PMBlobSphere::radius ) ); + s_pMetaObject->addProperty( + new PMBlobSphereProperty( "strength", &PMBlobSphere::setStrength, + &PMBlobSphere::strength ) ); + } + return s_pMetaObject; +} + +void PMBlobSphere::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "centre", m_centre.serializeXML( ) ); + e.setAttribute( "radius", m_radius ); + e.setAttribute( "strength", m_strength ); + Base::serialize( e, doc ); +} + +void PMBlobSphere::readAttributes( const PMXMLHelper& h ) +{ + m_centre = h.vectorAttribute( "centre", c_defaultCentre ); + m_radius = h.doubleAttribute( "radius", c_defaultRadius ); + m_strength = h.doubleAttribute( "strength", c_defaultStrength ); + Base::readAttributes( h ); +} + +PMDialogEditBase* PMBlobSphere::editWidget( QWidget* parent ) const +{ + return new PMBlobSphereEdit( parent ); +} + +void PMBlobSphere::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMRadiusID: + setRadius( data->doubleData( ) ); + break; + case PMCentreID: + setCentre( data->vectorData( ) ); + break; + case PMStrengthID: + setStrength( data->doubleData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PBlobSphere::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); + +} + +void PMBlobSphere::controlPoints( PMControlPointList& list ) +{ + PM3DControlPoint* p = new PM3DControlPoint( m_centre, PMCentreID, + i18n( "Center" ) ); + list.append( p ); + list.append( new PMDistanceControlPoint( p, PMVector( 1.0, 0.0, 0.0 ), + m_radius, PMRadiusID, + i18n( "Radius (x)" ) ) ); + list.append( new PMDistanceControlPoint( p, PMVector( 0.0, 1.0, 0.0 ), + m_radius, PMRadiusID, + i18n( "Radius (y)" ) ) ); + list.append( new PMDistanceControlPoint( p, PMVector( 0.0, 0.0, 1.0 ), + m_radius, PMRadiusID, + i18n( "Radius (z)" ) ) ); +} + +void PMBlobSphere::controlPointsChanged( PMControlPointList& list ) +{ + PMControlPoint* p; + bool radiusChanged = false; + + for( p = list.first( ); p; p = list.next( ) ) + { + if( p->changed( ) ) + { + switch( p->id( ) ) + { + case PMCentreID: + setCentre( ( ( PM3DControlPoint* ) p )->point( ) ); + break; + case PMRadiusID: + setRadius( ( ( PMDistanceControlPoint* ) p )->distance( ) ); + radiusChanged = true; + break; + default: + kdError( PMArea ) << "Wrong ID in PMBlobSphere::controlPointsChanged\n"; + break; + } + } + } + + if( radiusChanged ) + for( p = list.first( ); p; p = list.next( ) ) + if( p->id( ) == PMRadiusID ) + ( ( PMDistanceControlPoint* ) p )->setDistance( m_radius ); +} + +bool PMBlobSphere::isDefault( ) +{ + if( ( m_radius == c_defaultRadius ) && ( m_centre == c_defaultCentre ) && globalDetail( ) ) + return true; + return false; +} + +void PMBlobSphere::createViewStructure( ) +{ + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultViewStructure( ) ); + m_pViewStructure->points( ).detach( ); + } + + int uStep = (int)( ( (float)s_uStep / 2 ) * ( displayDetail( ) + 1 ) ); + int vStep = (int)( ( (float)s_vStep / 2 ) * ( displayDetail( ) + 1 ) ); + unsigned ptsSize = vStep * ( uStep - 1 ) + 2; + unsigned lineSize = vStep * ( uStep - 1 ) * 2 + vStep; + + if( ptsSize != m_pViewStructure->points( ).size( ) ) + m_pViewStructure->points( ).resize( ptsSize ); + + createPoints( m_pViewStructure->points( ), m_centre, m_radius, uStep, vStep ); + + if( lineSize != m_pViewStructure->lines( ).size( ) ) + { + m_pViewStructure->lines( ).detach( ); + m_pViewStructure->lines( ).resize( lineSize ); + createLines( m_pViewStructure->lines( ), uStep, vStep ); + } +} + +PMViewStructure* PMBlobSphere::defaultViewStructure( ) const +{ + if( !s_pDefaultViewStructure || s_pDefaultViewStructure->parameterKey( ) != viewStructureParameterKey( ) ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + int uStep = (int)( ( (float)s_uStep / 2 ) * ( globalDetailLevel( ) + 1 ) ); + int vStep = (int)( ( (float)s_vStep / 2 ) * ( globalDetailLevel( ) + 1 ) ); + + s_pDefaultViewStructure = + new PMViewStructure( vStep * ( uStep - 1 ) + 2, + vStep * ( uStep - 1 ) * 2 + vStep ); + + createPoints( s_pDefaultViewStructure->points( ), c_defaultCentre, + c_defaultRadius, uStep, vStep ); + + createLines( s_pDefaultViewStructure->lines( ), uStep, vStep ); + } + return s_pDefaultViewStructure; +} + +void PMBlobSphere::createLines( PMLineArray& lines, int uStep, int vStep ) +{ + int u, v; + int offset = 0; + + // horizontal lines + for( u = 0; u < ( uStep - 1 ); u++ ) + { + for( v = 0; v < ( vStep - 1 ); v++ ) + lines[offset + v] = + PMLine( u * vStep + v + 1, u * vStep + v + 2 ); + lines[offset + vStep - 1] = + PMLine( u * vStep + 1, u * vStep + vStep ); + + offset += vStep; + } + + // vertical lines + // lines at the "north pole" + for( v = 0; v < vStep; v++ ) + lines[offset + v] = PMLine( 0, v + 1 ); + offset += vStep; + + for( v = 0; v < vStep; v++ ) + { + for( u = 0; u < ( uStep - 2 ); u++ ) + { + lines[offset + u] = + PMLine( u * vStep + v + 1, ( u + 1 ) * vStep + v + 1 ); + } + offset += ( uStep - 2 ); + } + // lines at the "south pole" + for( v = 0; v < vStep; v++ ) + lines[offset + v] = PMLine( ( uStep - 2 ) * vStep + v + 1, + ( uStep - 1 ) * vStep + 1 ); + // offset += vStep; +} + +void PMBlobSphere::createPoints( PMPointArray& points, const PMVector& centre, + double radius, int uStep, int vStep ) +{ + double l_UradStep = M_PI / uStep; + double l_VradStep = ( 2.0 * M_PI ) / vStep; + double l_u = l_UradStep; + int u, v; + + points[0] = PMPoint( centre + PMVector( 0, radius, 0 ) ); + points[vStep * ( uStep - 1 ) + 1] = + PMPoint( centre - PMVector( 0, radius, 0 ) ); + + for( u = 0; u < ( uStep - 1 ); u++ ) + { + double l_v = 0.0; + double l_rcosu = radius * sin( l_u ); + double y = ( radius * cos( l_u ) ) + centre[1]; + for( v = 0; v < vStep ; v++ ) + { + + double x = ( l_rcosu * cos( l_v ) ) + centre[0]; + double z = ( l_rcosu * sin( l_v ) ) + centre[2]; + + points[u * vStep + v + 1] = PMPoint( x, y, z ); + l_v = l_v + l_VradStep; + } + l_u = l_u + l_UradStep; + } +} + +void PMBlobSphere::setRadius( double radius ) +{ + if( m_radius != radius ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRadiusID, m_radius ); + m_radius = radius; + setViewStructureChanged( ); + } +} + +void PMBlobSphere::setCentre( const PMVector& centre ) +{ + if( m_centre != centre ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCentreID, m_centre ); + m_centre = centre; + setViewStructureChanged( ); + } +} + +void PMBlobSphere::setStrength( double s ) +{ + if( m_strength != s ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMStrengthID, m_strength ); + m_strength = s; + } +} + +void PMBlobSphere::setUSteps( int u ) +{ + if( u >= 2 ) + { + s_uStep = u; + if( s_pDefaultViewStructure ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + } + } + else + kdDebug( PMArea ) << "PMBlobSphere::setUSteps: U must be greater than 1\n"; + s_parameterKey++; +} + +void PMBlobSphere::setVSteps( int v ) +{ + if( v >= 4 ) + { + s_vStep = v; + if( s_pDefaultViewStructure ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + } + } + else + kdDebug( PMArea ) << "PMBlobSphere::setVSteps: V must be greater than 3\n"; + s_parameterKey++; +} + +void PMBlobSphere::cleanUp( ) const +{ + if( s_pDefaultViewStructure ) + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} diff --git a/kpovmodeler/pmblobsphere.h b/kpovmodeler/pmblobsphere.h new file mode 100644 index 00000000..bb75b856 --- /dev/null +++ b/kpovmodeler/pmblobsphere.h @@ -0,0 +1,168 @@ +//-*-C++-*- +/* +************************************************************************** + description + ------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMBLOBSPHERE_H +#define PMBLOBSPHERE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdetailobject.h" +#include "pmvector.h" +#include "pmviewstructure.h" + +/** + * Class for povray sphere. + */ +class PMBlobSphere : public PMDetailObject +{ + typedef PMDetailObject Base; + +public: + /** + * Create an empty BlobSphere + */ + PMBlobSphere( PMPart* part ); + /** + * Copy constructor + */ + PMBlobSphere( const PMBlobSphere& s ); + /** + * Delete the PMBlobSphere + */ + virtual ~PMBlobSphere( ); + + /** */ + virtual PMObject* copy( ) const { return new PMBlobSphere( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMBlobSphereEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmblobsphere" ); } + + /** + * Returns the centre of the sphere + */ + PMVector centre( ) const { return m_centre; } + /** + * Set the centre of the sphere + */ + void setCentre( const PMVector& centre ); + /** + * returns the radius of the sphere + */ + double radius( ) const { return m_radius; } + /** + * Sets the radius of the sphere + */ + void setRadius( double radius ); + /** + * Returns the components strength + */ + double strength( ) const { return m_strength; } + /** + * Sets the strength + */ + void setStrength( double s ); + + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual void controlPoints( PMControlPointList& list ); + /** */ + virtual void controlPointsChanged( PMControlPointList& list ); + /** */ + virtual bool hasDisplayDetail( ) const { return true; } + + /** + * Sets the number of latitutes + */ + static void setUSteps( int u ); + /** + * Sets the number of longitudes + */ + static void setVSteps( int v ); + /** + * Returns the number or latitutes + */ + static int uSteps( ) { return s_uStep; } + /** + * Returns the number or longitudes + */ + static int vSteps( ) { return s_vStep; } + /** */ + virtual void cleanUp( ) const; + +protected: + /** */ + virtual bool isDefault( ); + /** */ + virtual void createViewStructure( ); + /** */ + virtual PMViewStructure* defaultViewStructure( ) const; + /** */ + virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey(); } + +private: + /** + * Creates the lines for the view structure + */ + static void createLines( PMLineArray& lines, int uStep, int vStep ); + /** + * Creates the points for the view structure + */ + static void createPoints( PMPointArray& points, const PMVector& centre, + double radius, int uStep, int vStep ); + + enum PMBlobSphereMementoID { PMRadiusID, PMCentreID, PMStrengthID }; + /** + * Radius of the sphere + */ + double m_radius; + /** + * centre of the sphere + */ + PMVector m_centre; + double m_strength; + + static PMViewStructure* s_pDefaultViewStructure; + static int s_vStep; + static int s_uStep; + static int s_parameterKey; + + static PMMetaObject* s_pMetaObject; +}; + + +#endif diff --git a/kpovmodeler/pmblobsphereedit.cpp b/kpovmodeler/pmblobsphereedit.cpp new file mode 100644 index 00000000..26291248 --- /dev/null +++ b/kpovmodeler/pmblobsphereedit.cpp @@ -0,0 +1,102 @@ +/* +************************************************************************** + description + ------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmblobsphereedit.h" +#include "pmblobsphere.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" + +#include +#include +#include + +PMBlobSphereEdit::PMBlobSphereEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMBlobSphereEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* layout; + + m_pCentre = new PMVectorEdit( "x", "y", "z", this ); + m_pRadius = new PMFloatEdit( this ); + m_pStrength = new PMFloatEdit( this ); + + layout = new QHBoxLayout( topLayout( ) ); + layout->addWidget( new QLabel( i18n( "Center:" ), this ) ); + layout->addWidget( m_pCentre ); + + layout = new QHBoxLayout( topLayout( ) ); + QGridLayout* gl = new QGridLayout( layout, 2, 2 ); + gl->addWidget( new QLabel( i18n( "Radius:" ), this ), 0, 0 ); + gl->addWidget( m_pRadius, 0, 1 ); + gl->addWidget( new QLabel( i18n( "Strength:" ), this ), 1, 0 ); + gl->addWidget( m_pStrength, 1, 1 ); + layout->addStretch( 1 ); + + connect( m_pCentre, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pRadius, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pStrength, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMBlobSphereEdit::displayObject( PMObject* o ) +{ + if( o->isA( "BlobSphere" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMBlobSphere* ) o; + + m_pCentre->setVector( m_pDisplayedObject->centre( ) ); + m_pRadius->setValue( m_pDisplayedObject->radius( ) ); + m_pStrength->setValue( m_pDisplayedObject->strength( ) ); + + m_pCentre->setReadOnly( readOnly ); + m_pRadius->setReadOnly( readOnly ); + m_pStrength->setReadOnly( readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMBlobSphereEdit: Can't display object\n"; +} + +void PMBlobSphereEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setCentre( m_pCentre->vector( ) ); + m_pDisplayedObject->setRadius( m_pRadius->value( ) ); + m_pDisplayedObject->setStrength( m_pStrength->value( ) ); + } +} + +bool PMBlobSphereEdit::isDataValid( ) +{ + if( m_pCentre->isDataValid( ) ) + if( m_pRadius->isDataValid( ) ) + if( m_pStrength->isDataValid( ) ) + return Base::isDataValid( ); + return false; +} + + +#include "pmblobsphereedit.moc" diff --git a/kpovmodeler/pmblobsphereedit.h b/kpovmodeler/pmblobsphereedit.h new file mode 100644 index 00000000..08f0f1d4 --- /dev/null +++ b/kpovmodeler/pmblobsphereedit.h @@ -0,0 +1,63 @@ +/* +************************************************************************** + description + ------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMBLOBSPHEREEDIT_H +#define PMBLOBSPHEREEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdetailobjectedit.h" + +class PMBlobSphere; +class PMVectorEdit; +class PMFloatEdit ; + +/** + * Dialog edit class for @ref PMBlobSphere + */ +class PMBlobSphereEdit : public PMDetailObjectEdit +{ + Q_OBJECT + typedef PMDetailObjectEdit Base; +public: + /** + * Creates a PMBlobSphereEdit with parent and name + */ + PMBlobSphereEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMBlobSphere* m_pDisplayedObject; + PMVectorEdit* m_pCentre; + PMFloatEdit* m_pRadius; + PMFloatEdit* m_pStrength; +}; + + +#endif diff --git a/kpovmodeler/pmboundedby.cpp b/kpovmodeler/pmboundedby.cpp new file mode 100644 index 00000000..127a05f8 --- /dev/null +++ b/kpovmodeler/pmboundedby.cpp @@ -0,0 +1,114 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmboundedby.h" +#include "pmboundedbyedit.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" + +#include + +PMDefinePropertyClass( PMBoundedBy, PMBoundedByProperty ); + +PMMetaObject* PMBoundedBy::s_pMetaObject = 0; +PMObject* createNewBoundedBy( PMPart* part ) +{ + return new PMBoundedBy( part ); +} + +PMBoundedBy::PMBoundedBy( PMPart* part ) + : Base( part ) +{ +} + +PMBoundedBy::~PMBoundedBy( ) +{ +} + +PMMetaObject* PMBoundedBy::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "BoundedBy", Base::metaObject( ), + createNewBoundedBy ); + s_pMetaObject->addProperty( + new PMBoundedByProperty( "clippedBy", 0, &PMBoundedBy::clippedBy ) ); + } + return s_pMetaObject; +} + +void PMBoundedBy::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMBoundedBy::description( ) const +{ + return i18n( "bounded by" ); +} + +bool PMBoundedBy::clippedBy( ) const +{ + bool cb = true; + PMObject* o = firstChild( ); + + for( ; o && cb; o = o->nextSibling( ) ) + if( o->type( ) != "Comment" ) + cb = false; + + return cb; +} + +void PMBoundedBy::serialize( QDomElement& e, QDomDocument& doc ) const +{ + // no extra data at the moment + Base::serialize( e, doc ); +} + +void PMBoundedBy::readAttributes( const PMXMLHelper& h ) +{ + // no extra data at the moment + Base::readAttributes( h ); +} + +PMDialogEditBase* PMBoundedBy::editWidget( QWidget* parent ) const +{ + return new PMBoundedByEdit( parent ); +} + +void PMBoundedBy::childRemoved( PMObject* o ) +{ + Base::childRemoved( o ); + + // add a dummy change + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMClippedByID, true ); +} + +void PMBoundedBy::childAdded( PMObject* o ) +{ + Base::childAdded( o ); + + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMClippedByID, true ); +} diff --git a/kpovmodeler/pmboundedby.h b/kpovmodeler/pmboundedby.h new file mode 100644 index 00000000..22ac3fb4 --- /dev/null +++ b/kpovmodeler/pmboundedby.h @@ -0,0 +1,89 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMBOUNDEDBY_H +#define PMBOUNDEDBY_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmcompositeobject.h" + +/** + * class for bounded_by povray statements + */ + +class PMBoundedBy : public PMCompositeObject +{ + typedef PMCompositeObject Base; +public: + /** + * Creates an empty PMBoundedBy + */ + PMBoundedBy( PMPart* part ); + /** + * Deletes the object + */ + ~PMBoundedBy( ); + + /** */ + virtual PMObject* copy( ) const { return new PMBoundedBy( *this ); } + + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual bool dataChangeOnInsertRemove( ) const { return true; } + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMBoundedByEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmboundedby" ); } + + /** */ + virtual void childRemoved( PMObject* ); + /** */ + virtual void childAdded( PMObject* ); + + /** + * Returns true if the object contains no child objects (exmbumcept comments) + */ + bool clippedBy( ) const; + +private: + enum PMBoundedByMementoID { PMClippedByID }; + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmboundedbyedit.cpp b/kpovmodeler/pmboundedbyedit.cpp new file mode 100644 index 00000000..2bf1409e --- /dev/null +++ b/kpovmodeler/pmboundedbyedit.cpp @@ -0,0 +1,65 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmboundedbyedit.h" +#include "pmboundedby.h" + +#include +#include +#include + +PMBoundedByEdit::PMBoundedByEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMBoundedByEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + m_pChildLabel = new QLabel( i18n( "No child objects" ), this ); + topLayout( )->addWidget( m_pChildLabel ); + m_pClippedByLabel = new QLabel( i18n( "(= clipped by)" ), this ); + topLayout( )->addWidget( m_pClippedByLabel ); +} + +void PMBoundedByEdit::displayObject( PMObject* o ) +{ + if( o->isA( "BoundedBy" ) ) + { + m_pDisplayedObject = ( PMBoundedBy* ) o; + + if( m_pDisplayedObject->clippedBy( ) ) + { + m_pChildLabel->show( ); + m_pClippedByLabel->show( ); + } + else + { + m_pChildLabel->hide( ); + m_pClippedByLabel->hide( ); + } + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMBoundedByEdit: Can't display object\n"; +} + +#include "pmboundedbyedit.moc" diff --git a/kpovmodeler/pmboundedbyedit.h b/kpovmodeler/pmboundedbyedit.h new file mode 100644 index 00000000..f4d24a41 --- /dev/null +++ b/kpovmodeler/pmboundedbyedit.h @@ -0,0 +1,59 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMBOUNDEDBYEDIT_H +#define PMBOUNDEDBYEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMBoundedBy; +class QLabel; + +/** + * Dialog edit class for @ref PMBoundedBy + */ +class PMBoundedByEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMBoundedByEdit with parent and name + */ + PMBoundedByEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + +protected: + /** */ + virtual void createTopWidgets( ); + +private: + PMBoundedBy* m_pDisplayedObject; + QLabel* m_pChildLabel; + QLabel* m_pClippedByLabel; +}; + + +#endif diff --git a/kpovmodeler/pmbox.cpp b/kpovmodeler/pmbox.cpp new file mode 100644 index 00000000..045389bb --- /dev/null +++ b/kpovmodeler/pmbox.cpp @@ -0,0 +1,276 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmbox.h" + +#include "pmxmlhelper.h" +#include "pmboxedit.h" +#include "pmmemento.h" +#include "pmviewstructure.h" +#include "pm3dcontrolpoint.h" + +#include + +const double defaultBoxSize = 0.5; +const PMVector corner1Default = PMVector( -defaultBoxSize, -defaultBoxSize, -defaultBoxSize ); +const PMVector corner2Default = PMVector( defaultBoxSize, defaultBoxSize, defaultBoxSize ); + +PMDefinePropertyClass( PMBox, PMBoxProperty ); + +PMViewStructure* PMBox::s_pDefaultViewStructure = 0; +PMMetaObject* PMBox::s_pMetaObject = 0; +PMObject* createNewBox( PMPart* part ) +{ + return new PMBox( part ); +} + +PMBox::PMBox( PMPart* part ) + : Base( part ) +{ + m_corner1 = corner1Default; + m_corner2 = corner2Default; +} + +PMBox::PMBox( const PMBox& b ) + : Base( b ) +{ + m_corner1 = b.m_corner1; + m_corner2 = b.m_corner2; +} + +PMBox::~PMBox( ) +{ +} + +QString PMBox::description( ) const +{ + return i18n( "box" ); +} + +void PMBox::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "corner_a", m_corner1.serializeXML( ) ); + e.setAttribute( "corner_b", m_corner2.serializeXML( ) ); + Base::serialize( e, doc ); +} + +void PMBox::readAttributes( const PMXMLHelper& h ) +{ + m_corner1 = h.vectorAttribute( "corner_a", corner1Default ); + m_corner2 = h.vectorAttribute( "corner_b", corner2Default ); + Base::readAttributes( h ); +} + +PMMetaObject* PMBox::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Box", Base::metaObject( ), + createNewBox ); + s_pMetaObject->addProperty( + new PMBoxProperty( "corner1", &PMBox::setCorner1, &PMBox::corner1 ) ); + s_pMetaObject->addProperty( + new PMBoxProperty( "corner2", &PMBox::setCorner2, &PMBox::corner2 ) ); + } + return s_pMetaObject; +} + +void PMBox::setCorner1( const PMVector& p ) +{ + if( p != m_corner1 ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCorner1ID, m_corner1 ); + m_corner1 = p; + m_corner1.resize( 3 ); + setViewStructureChanged( ); + } +} + +void PMBox::setCorner2( const PMVector& p ) +{ + if( p != m_corner2 ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCorner2ID, m_corner2 ); + m_corner2 = p; + m_corner2.resize( 3 ); + setViewStructureChanged( ); + } +} + +PMDialogEditBase* PMBox::editWidget( QWidget* parent ) const +{ + return new PMBoxEdit( parent ); +} + +void PMBox::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMCorner1ID: + setCorner1( data->vectorData( ) ); + break; + case PMCorner2ID: + setCorner2( data->vectorData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMBox::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + + +bool PMBox::isDefault( ) +{ + if( ( m_corner1 == corner1Default ) && ( m_corner2 == corner2Default ) ) + return true; + return false; +} + +void PMBox::createViewStructure( ) +{ + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultViewStructure( ) ); + m_pViewStructure->points( ).detach( ); + } + + PMPointArray& points = m_pViewStructure->points( ); + + points[0][0] = m_corner1[0]; + points[0][1] = m_corner1[1]; + points[0][2] = m_corner1[2]; + + points[1][0] = m_corner2[0]; + points[1][1] = m_corner1[1]; + points[1][2] = m_corner1[2]; + + points[2][0] = m_corner2[0]; + points[2][1] = m_corner1[1]; + points[2][2] = m_corner2[2]; + + points[3][0] = m_corner1[0]; + points[3][1] = m_corner1[1]; + points[3][2] = m_corner2[2]; + + points[4][0] = m_corner1[0]; + points[4][1] = m_corner2[1]; + points[4][2] = m_corner1[2]; + + points[5][0] = m_corner2[0]; + points[5][1] = m_corner2[1]; + points[5][2] = m_corner1[2]; + + points[6][0] = m_corner2[0]; + points[6][1] = m_corner2[1]; + points[6][2] = m_corner2[2]; + + points[7][0] = m_corner1[0]; + points[7][1] = m_corner2[1]; + points[7][2] = m_corner2[2]; +} + +PMViewStructure* PMBox::defaultViewStructure( ) const +{ + if( !s_pDefaultViewStructure ) + { + s_pDefaultViewStructure = new PMViewStructure( 8, 12 ); + PMPointArray& points = s_pDefaultViewStructure->points( ); + PMLineArray& lines = s_pDefaultViewStructure->lines( ); + + points[0] = PMPoint( -defaultBoxSize, -defaultBoxSize, -defaultBoxSize ); + points[1] = PMPoint( defaultBoxSize, -defaultBoxSize, -defaultBoxSize ); + points[2] = PMPoint( defaultBoxSize, -defaultBoxSize, defaultBoxSize ); + points[3] = PMPoint( -defaultBoxSize, -defaultBoxSize, defaultBoxSize ); + points[4] = PMPoint( -defaultBoxSize, defaultBoxSize, -defaultBoxSize ); + points[5] = PMPoint( defaultBoxSize, defaultBoxSize, -defaultBoxSize ); + points[6] = PMPoint( defaultBoxSize, defaultBoxSize, defaultBoxSize ); + points[7] = PMPoint( -defaultBoxSize, defaultBoxSize, defaultBoxSize ); + + lines[ 0] = PMLine( 0, 1 ); + lines[ 1] = PMLine( 0, 3 ); + lines[ 2] = PMLine( 0, 4 ); + lines[ 3] = PMLine( 1, 2 ); + lines[ 4] = PMLine( 1, 5 ); + lines[ 5] = PMLine( 2, 3 ); + lines[ 6] = PMLine( 2, 6 ); + lines[ 7] = PMLine( 3, 7 ); + lines[ 8] = PMLine( 4, 5 ); + lines[ 9] = PMLine( 4, 7 ); + lines[10] = PMLine( 5, 6 ); + lines[11] = PMLine( 6, 7 ); + } + return s_pDefaultViewStructure; +} + +void PMBox::controlPoints( PMControlPointList& list ) +{ + list.append( new PM3DControlPoint( m_corner1, PMCorner1ID, + i18n( "Corner 1" ) ) ); + list.append( new PM3DControlPoint( m_corner2, PMCorner2ID, + i18n( "Corner 2" ) ) ); +} + +void PMBox::controlPointsChanged( PMControlPointList& list ) +{ + PMControlPoint* p; + + for( p = list.first( ); p; p = list.next( ) ) + { + if( p->changed( ) ) + { + switch( p->id( ) ) + { + case PMCorner1ID: + setCorner1( ( ( PM3DControlPoint* ) p )->point( ) ); + break; + case PMCorner2ID: + setCorner2( ( ( PM3DControlPoint* ) p )->point( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMBox::controlPointsChanged\n"; + break; + } + } + } +} + +void PMBox::cleanUp( ) const +{ + if( s_pDefaultViewStructure ) + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} diff --git a/kpovmodeler/pmbox.h b/kpovmodeler/pmbox.h new file mode 100644 index 00000000..d6627ffe --- /dev/null +++ b/kpovmodeler/pmbox.h @@ -0,0 +1,123 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMBOX_H +#define PMBOX_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" +#include "pmvector.h" + +class PMViewStructure; + +/** + * Class for povray boxes. + */ + +class PMBox : public PMSolidObject +{ + typedef PMSolidObject Base; +public: + /** + * Creates an empty PMBox + */ + PMBox( PMPart* part ); + /** + * Copy constructor + */ + PMBox( const PMBox& b ); + /** + * deletes the PMBox + */ + virtual ~PMBox( ); + + /** */ + virtual PMObject* copy( ) const { return new PMBox( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMBoxEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmbox" ); } + + /** + * Returns Corner_1 + */ + PMVector corner1( ) const { return m_corner1; } + /** + * Sets Corner_1 + */ + void setCorner1( const PMVector& p ); + /** + * Returns Corner_2 + */ + PMVector corner2( ) const { return m_corner2; } + /** + * Sets Corner_2 + */ + void setCorner2( const PMVector& p ); + + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual void controlPoints( PMControlPointList& list ); + /** */ + virtual void controlPointsChanged( PMControlPointList& list ); + /** */ + virtual void cleanUp( ) const; + +protected: + /** */ + virtual bool isDefault( ); + /** */ + virtual void createViewStructure( ); + /** */ + virtual PMViewStructure* defaultViewStructure( ) const; + +private: + /** + * IDs for @ref PMMementoData + */ + enum PMBoxMementoID { PMCorner1ID, PMCorner2ID }; + PMVector m_corner1, m_corner2; + + /** + * The default view structure. It can be shared between boxes + */ + static PMViewStructure* s_pDefaultViewStructure; + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmboxedit.cpp b/kpovmodeler/pmboxedit.cpp new file mode 100644 index 00000000..2db1eb79 --- /dev/null +++ b/kpovmodeler/pmboxedit.cpp @@ -0,0 +1,86 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmboxedit.h" +#include "pmbox.h" +#include "pmvectoredit.h" + +#include +#include +#include + +PMBoxEdit::PMBoxEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMBoxEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + m_pCorner1 = new PMVectorEdit( "x", "y", "z", this ); + m_pCorner2 = new PMVectorEdit( "x", "y", "z", this ); + + QGridLayout* gl = new QGridLayout( topLayout( ), 2, 2 ); + gl->addWidget( new QLabel( i18n( "Corner 1:" ), this ), 0, 0 ); + gl->addWidget( m_pCorner1, 0, 1 ); + gl->addWidget( new QLabel( i18n( "Corner 2:" ), this ), 1, 0 ); + gl->addWidget( m_pCorner2, 1, 1 ); + + connect( m_pCorner1, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pCorner2, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMBoxEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Box" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMBox* ) o; + + m_pCorner1->setVector( m_pDisplayedObject->corner1( ) ); + m_pCorner2->setVector( m_pDisplayedObject->corner2( ) ); + + m_pCorner1->setReadOnly( readOnly ); + m_pCorner2->setReadOnly( readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMBoxEdit: Can't display object\n"; +} + +void PMBoxEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setCorner1( m_pCorner1->vector( ) ); + m_pDisplayedObject->setCorner2( m_pCorner2->vector( ) ); + } +} + +bool PMBoxEdit::isDataValid( ) +{ + if( m_pCorner1->isDataValid( ) ) + if( m_pCorner2->isDataValid( ) ) + return Base::isDataValid( ); + return false; +} +#include "pmboxedit.moc" diff --git a/kpovmodeler/pmboxedit.h b/kpovmodeler/pmboxedit.h new file mode 100644 index 00000000..4f87ceac --- /dev/null +++ b/kpovmodeler/pmboxedit.h @@ -0,0 +1,63 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMBOXEDIT_H +#define PMBOXEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" + +class PMBox; +class PMVectorEdit; + +/** + * Dialog edit class for @ref PMBox + */ +class PMBoxEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMBoxEdit with parent and name + */ + PMBoxEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMBox* m_pDisplayedObject; + PMVectorEdit* m_pCorner1; + PMVectorEdit* m_pCorner2; +}; + + +#endif diff --git a/kpovmodeler/pmbumpmap.cpp b/kpovmodeler/pmbumpmap.cpp new file mode 100644 index 00000000..e9549bd9 --- /dev/null +++ b/kpovmodeler/pmbumpmap.cpp @@ -0,0 +1,384 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Passos Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmbumpmapedit.h" +#include "pmbumpmap.h" +#include "pmpalettevalue.h" +#include "pmpalettevaluememento.h" + +#include "pmxmlhelper.h" +#include "pmcompositeobject.h" +#include "pmmemento.h" +#include "pmenumproperty.h" + +#include + +const PMBumpMap::PMBitmapType bitmapTypeDefault = PMBumpMap::BitmapSys; +const char *const bitmapFileDefault = 0; +const bool enableFilterAllDefault = false; +const bool enableTransmitAllDefault = false; +const double filterAllDefault = 0.0; +const double transmitAllDefault = 0.0; +const bool onceDefault = false; +const PMBumpMap::PMMapType mapTypeDefault = PMBumpMap::MapPlanar; +const PMBumpMap::PMInterpolateType interpolateTypeDefault = PMBumpMap::InterpolateNone; +const bool useIndexDefault = false; +const double bumpSizeDefault = 0.0; + +PMDefinePropertyClass( PMBumpMap, PMBumpMapProperty ); +PMDefineEnumPropertyClass( PMBumpMap, PMBumpMap::PMBitmapType, + PMBitmapTypeProperty ); +PMDefineEnumPropertyClass( PMBumpMap, PMBumpMap::PMInterpolateType, + PMInterpolateTypeProperty ); +PMDefineEnumPropertyClass( PMBumpMap, PMBumpMap::PMMapType, + PMMapTypeProperty ); + +PMMetaObject* PMBumpMap::s_pMetaObject = 0; +PMObject* createNewBumpMap( PMPart* part ) +{ + return new PMBumpMap( part ); +} + +PMBumpMap::PMBumpMap( PMPart* part ) + : Base( part ) +{ + m_bitmapType = bitmapTypeDefault; + m_bitmapFile = bitmapFileDefault; + m_once = onceDefault; + m_mapType = mapTypeDefault; + m_interpolateType = interpolateTypeDefault; + m_useIndex = useIndexDefault; + m_bumpSize = bumpSizeDefault; +} + +PMBumpMap::PMBumpMap( const PMBumpMap& m ) + : Base( m ) +{ + m_bitmapType = m.m_bitmapType; + m_bitmapFile = m.m_bitmapFile; + m_once = m.m_once; + m_mapType = m.m_mapType; + m_interpolateType = m.m_interpolateType; + m_useIndex = m.m_useIndex; + m_bumpSize = m.m_bumpSize; +} + +PMBumpMap::~PMBumpMap( ) +{ +} + +void PMBumpMap::serialize( QDomElement& e, QDomDocument& doc ) const +{ + switch( m_bitmapType ) + { + case BitmapGif: + e.setAttribute( "bitmap_type", "gif" ); + break; + case BitmapTga: + e.setAttribute( "bitmap_type", "tga" ); + break; + case BitmapIff: + e.setAttribute( "bitmap_type", "iff" ); + break; + case BitmapPpm: + e.setAttribute( "bitmap_type", "ppm" ); + break; + case BitmapPgm: + e.setAttribute( "bitmap_type", "pgm" ); + break; + case BitmapPng: + e.setAttribute( "bitmap_type", "png" ); + break; + case BitmapJpeg: + e.setAttribute( "bitmap_type", "jpeg" ); + break; + case BitmapTiff: + e.setAttribute( "bitmap_type", "tiff" ); + break; + case BitmapSys: + e.setAttribute( "bitmap_type", "sys" ); + break; + } + e.setAttribute( "file_name", m_bitmapFile ); + e.setAttribute( "once", m_once ); + switch( m_mapType ) + { + case MapPlanar: + e.setAttribute( "map_type", "planar" ); + break; + case MapSpherical: + e.setAttribute( "map_type", "spherical" ); + break; + case MapCylindrical: + e.setAttribute( "map_type", "cylindrical" ); + break; + case MapToroidal: + e.setAttribute( "map_type", "toroidal" ); + break; + } + switch( m_interpolateType ) + { + case InterpolateNone: + e.setAttribute( "interpolate", "none" ); + break; + case InterpolateBilinear: + e.setAttribute( "interpolate", "bilinear" ); + break; + case InterpolateNormalized: + e.setAttribute( "interpolate", "normalized" ); + break; + } + e.setAttribute( "use_index", m_useIndex ); + e.setAttribute( "bump_size", m_bumpSize ); + + Base::serialize( e, doc ); +} + +void PMBumpMap::readAttributes( const PMXMLHelper& h ) +{ + QString str; + + str = h.stringAttribute( "bitmap_type", "sys" ); + if( str == "gif" ) + m_bitmapType = BitmapGif; + else if( str == "tga" ) + m_bitmapType = BitmapTga; + else if( str == "iff" ) + m_bitmapType = BitmapIff; + else if( str == "ppm" ) + m_bitmapType = BitmapPpm; + else if( str == "pgm" ) + m_bitmapType = BitmapPgm; + else if( str == "png" ) + m_bitmapType = BitmapPng; + else if( str == "jpeg" ) + m_bitmapType = BitmapJpeg; + else if( str == "tiff" ) + m_bitmapType = BitmapTiff; + else if( str == "sys" ) + m_bitmapType = BitmapSys; + + m_bitmapFile = h.stringAttribute( "file_name", bitmapFileDefault ); + m_once = h.boolAttribute( "once", onceDefault ); + + str = h.stringAttribute( "map_type", "planar" ); + if( str == "planar" ) + m_mapType = MapPlanar; + else if( str == "spherical" ) + m_mapType = MapSpherical; + else if( str == "cylindrical" ) + m_mapType = MapCylindrical; + else if( str == "toroidal" ) + m_mapType = MapToroidal; + + str = h.stringAttribute( "interpolate", "none" ); + if( str == "none" ) + m_interpolateType = InterpolateNone; + else if( str == "bilinear" ) + m_interpolateType = InterpolateBilinear; + else if( str == "normalized" ) + m_interpolateType = InterpolateNormalized; + + m_useIndex = h.boolAttribute( "use_index", useIndexDefault ); + m_bumpSize = h.doubleAttribute( "bump_size", bumpSizeDefault ); + + Base::readAttributes( h ); +} + +PMMetaObject* PMBumpMap::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "BumpMap", Base::metaObject( ), + createNewBumpMap ); + + PMBitmapTypeProperty* bp = new PMBitmapTypeProperty( + "bitmapType", &PMBumpMap::setBitmapType, + &PMBumpMap::bitmapType ); + bp->addEnumValue( "Gif", BitmapGif ); + bp->addEnumValue( "Tga", BitmapTga ); + bp->addEnumValue( "Iff", BitmapIff ); + bp->addEnumValue( "Ppm", BitmapPpm ); + bp->addEnumValue( "Pgm", BitmapPgm ); + bp->addEnumValue( "Png", BitmapPng ); + bp->addEnumValue( "Jpeg", BitmapJpeg ); + bp->addEnumValue( "Tiff", BitmapTiff ); + bp->addEnumValue( "Sys", BitmapSys ); + s_pMetaObject->addProperty( bp ); + + PMInterpolateTypeProperty* ip = new PMInterpolateTypeProperty( + "interpolateType", &PMBumpMap::setInterpolateType, + &PMBumpMap::interpolateType ); + ip->addEnumValue( "None", InterpolateNone ); + ip->addEnumValue( "Bilinear", InterpolateBilinear ); + ip->addEnumValue( "Normalized", InterpolateNormalized ); + s_pMetaObject->addProperty( ip ); + + PMMapTypeProperty* mp = new PMMapTypeProperty( + "mapType", &PMBumpMap::setMapType, &PMBumpMap::mapType ); + mp->addEnumValue( "Planar", MapPlanar ); + mp->addEnumValue( "Spherical", MapSpherical ); + mp->addEnumValue( "Cylindrical", MapCylindrical ); + mp->addEnumValue( "Toroidal", MapToroidal ); + s_pMetaObject->addProperty( mp ); + + s_pMetaObject->addProperty( + new PMBumpMapProperty( "bitmapFile", &PMBumpMap::setBitmapFileName, + &PMBumpMap::bitmapFile ) ); + s_pMetaObject->addProperty( + new PMBumpMapProperty( "useIndex", &PMBumpMap::enableUseIndex, + &PMBumpMap::isUseIndexEnabled ) ); + s_pMetaObject->addProperty( + new PMBumpMapProperty( "once", &PMBumpMap::enableOnce, + &PMBumpMap::isOnceEnabled ) ); + } + return s_pMetaObject; +} + +void PMBumpMap::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + + +QString PMBumpMap::description( ) const +{ + return i18n( "bump map" ); +} + +void PMBumpMap::setBitmapType( PMBitmapType c ) +{ + if( c != m_bitmapType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMBitmapTypeID, m_bitmapType ); + m_bitmapType = c; + } +} + +void PMBumpMap::setBitmapFileName( const QString& c ) +{ + if( c != m_bitmapFile ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMBitmapFileID, m_bitmapFile ); + m_bitmapFile = c; + } +} + +void PMBumpMap::enableUseIndex( bool c ) +{ + if( c != m_useIndex ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMUseIndexID, m_useIndex ); + m_useIndex = c; + } +} + +void PMBumpMap::setMapType( PMMapType c ) +{ + if( c != m_mapType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMMapTypeID, m_mapType ); + m_mapType = c; + } +} + +void PMBumpMap::setInterpolateType( PMInterpolateType c ) +{ + if( c != m_interpolateType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMInterpolateID, m_interpolateType ); + m_interpolateType = c; + } +} + +void PMBumpMap::enableOnce( bool c ) +{ + if( c != m_once ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMOnceID, m_once ); + m_once = c; + } +} + +void PMBumpMap::setBumpSize( double c ) +{ + if( c != m_bumpSize ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMBumpSizeID, m_bumpSize ); + m_bumpSize = c; + } +} + +PMDialogEditBase* PMBumpMap::editWidget( QWidget* parent ) const +{ + return new PMBumpMapEdit( parent ); +} + +void PMBumpMap::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMBitmapTypeID: + setBitmapType( ( PMBitmapType )data->intData( ) ); + break; + case PMBitmapFileID: + setBitmapFileName( data->stringData( ) ); + break; + case PMOnceID: + enableOnce( data->boolData( ) ); + break; + case PMMapTypeID: + setMapType( ( PMMapType )data->intData( ) ); + break; + case PMInterpolateID: + setInterpolateType( ( PMInterpolateType )data->intData( ) ); + break; + case PMUseIndexID: + enableUseIndex( data->boolData( ) ); + break; + case PMBumpSizeID: + setBumpSize( data->doubleData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMBumpMap::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmbumpmap.h b/kpovmodeler/pmbumpmap.h new file mode 100644 index 00000000..69bf53a3 --- /dev/null +++ b/kpovmodeler/pmbumpmap.h @@ -0,0 +1,172 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Passos Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMBUMPMAP_H +#define PMBUMPMAP_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmnamedobject.h" +#include "pmpalettevalue.h" + +/** + * Class for povray bumpmaps. + */ + +class PMBumpMap : public PMNamedObject +{ + typedef PMNamedObject Base; +public: + /** + * The bitmap type + */ + enum PMBitmapType { BitmapGif, BitmapTga, BitmapIff, BitmapPpm, + BitmapPgm, BitmapPng, BitmapJpeg, BitmapTiff, + BitmapSys }; + /** + * The interpolate method + */ + enum PMInterpolateType { InterpolateNone, InterpolateBilinear, + InterpolateNormalized }; + /** + * The mapping method + */ + enum PMMapType { MapPlanar, MapSpherical, MapCylindrical, + MapToroidal }; + + + /** + * Creates a PMBumpMap + */ + PMBumpMap( PMPart* part ); + /** + * Copy constructor + */ + PMBumpMap( const PMBumpMap& m ); + /** + * deletes the PMBumpMap + */ + virtual ~PMBumpMap( ); + + /** */ + virtual PMObject* copy( ) const { return new PMBumpMap( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual QString pixmap( ) const { return QString( "pmbumpmap" ); } + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMBumpMapEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + + /** + * Gets the bitmap type + */ + PMBitmapType bitmapType( ) const { return m_bitmapType; } + /** + * Gets the bitmap file name + */ + QString bitmapFile( ) const { return m_bitmapFile; } + /** + * Returns true if use_index is enabled + */ + bool isUseIndexEnabled( ) const { return m_useIndex; } + /** + * Returns the bump size + */ + double bumpSize( ) const { return m_bumpSize; } + /** + * Returns true if once is enabled + */ + bool isOnceEnabled( ) const { return m_once; } + /** + * Gets the bitmap file type + */ + PMMapType mapType( ) const { return m_mapType; } + /** + * Gets the interpolate method type + */ + PMInterpolateType interpolateType( ) const { return m_interpolateType; } + + + /** + * Sets the bumpmap type + */ + void setBitmapType( PMBitmapType c ); + /** + * Sets the bitmap file name*/ + void setBitmapFileName( const QString& c ); + /** + * Sets if use_index is enabled + */ + void enableUseIndex( bool c ); + /** + * Set the bump size + */ + void setBumpSize( double c ); + /** + * Sets if the bitmap should be mapped once + */ + void enableOnce( bool c ); + /** + * Sets the mapping method + */ + void setMapType( const PMMapType c ); + /** + * Sets the interpolating method + */ + void setInterpolateType( PMInterpolateType c ); + /** */ + virtual void restoreMemento( PMMemento* s ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMBumpMapMementoID { PMBitmapTypeID, PMBitmapFileID, + PMOnceID, PMMapTypeID, PMInterpolateID, + PMUseIndexID, PMBumpSizeID }; + /** + * BumpMap type + */ + PMBitmapType m_bitmapType; + QString m_bitmapFile; + bool m_once; + PMMapType m_mapType; + PMInterpolateType m_interpolateType; + bool m_useIndex; + double m_bumpSize; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmbumpmapedit.cpp b/kpovmodeler/pmbumpmapedit.cpp new file mode 100644 index 00000000..d792cec2 --- /dev/null +++ b/kpovmodeler/pmbumpmapedit.cpp @@ -0,0 +1,319 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Passos Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmbumpmapedit.h" +#include "pmbumpmap.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" +#include "pmpalettevalueedit.h" +#include "pmvector.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +PMBumpMapEdit::PMBumpMapEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMBumpMapEdit::createTopWidgets( ) +{ + QLabel* lbl; + QHBoxLayout* hl; + + Base::createTopWidgets( ); + + hl = new QHBoxLayout( topLayout( ) ); + lbl = new QLabel( i18n( "File type:" ), this ); + m_pImageFileTypeEdit = new QComboBox( this ); + m_pImageFileTypeEdit->insertItem( "gif" ); + m_pImageFileTypeEdit->insertItem( "tga" ); + m_pImageFileTypeEdit->insertItem( "iff" ); + m_pImageFileTypeEdit->insertItem( "ppm" ); + m_pImageFileTypeEdit->insertItem( "pgm" ); + m_pImageFileTypeEdit->insertItem( "png" ); + m_pImageFileTypeEdit->insertItem( "jpeg" ); + m_pImageFileTypeEdit->insertItem( "tiff" ); + m_pImageFileTypeEdit->insertItem( "sys" ); + hl->addWidget( lbl ); + hl->addWidget( m_pImageFileTypeEdit ); + + hl = new QHBoxLayout( topLayout( ) ); + lbl = new QLabel( i18n( "File name:" ), this ); + m_pImageFileNameEdit = new QLineEdit( this ); + m_pImageFileNameBrowse = new QPushButton( this ); + m_pImageFileNameBrowse->setPixmap( SmallIcon( "fileopen" ) ); + hl->addWidget( lbl ); + hl->addWidget( m_pImageFileNameEdit ); + hl->addWidget( m_pImageFileNameBrowse ); + hl->addStretch( 1 ); + + m_pOnceEdit = new QCheckBox( i18n( "Once" ), this ); + topLayout( )->addWidget( m_pOnceEdit ); + + hl = new QHBoxLayout( topLayout( ) ); + lbl = new QLabel( i18n( "Interpolate:" ), this ); + m_pInterpolateTypeEdit = new QComboBox( this ); + m_pInterpolateTypeEdit->insertItem( i18n( "None" ) ); + m_pInterpolateTypeEdit->insertItem( i18n( "Bilinear" ) ); + m_pInterpolateTypeEdit->insertItem( i18n( "Normalized" ) ); + hl->addWidget( lbl ); + hl->addWidget( m_pInterpolateTypeEdit ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + lbl = new QLabel( i18n( "Map type:" ), this ); + m_pMapTypeEdit = new QComboBox( this ); + m_pMapTypeEdit->insertItem( i18n( "Planar" ) ); + m_pMapTypeEdit->insertItem( i18n( "Spherical" ) ); + m_pMapTypeEdit->insertItem( i18n( "Cylindrical" ) ); + m_pMapTypeEdit->insertItem( i18n( "Toroidal" ) ); + hl->addWidget( lbl ); + hl->addWidget( m_pMapTypeEdit ); + hl->addStretch( 1 ); + + m_pUseIndexEdit = new QCheckBox( i18n( "Use index" ), this ); + topLayout( )->addWidget( m_pUseIndexEdit ); + + hl = new QHBoxLayout( topLayout( ) ); + lbl = new QLabel( i18n( "Bump size:" ), this ); + m_pBumpSizeEdit = new PMFloatEdit( this ); + hl->addWidget( lbl ); + hl->addWidget( m_pBumpSizeEdit ); + hl->addStretch( 1 ); + + connect( m_pImageFileTypeEdit, SIGNAL( activated( int ) ), SLOT( slotImageFileTypeChanged( int ) ) ); + connect( m_pMapTypeEdit, SIGNAL( activated( int ) ), SLOT( slotMapTypeChanged( int ) ) ); + connect( m_pInterpolateTypeEdit, SIGNAL( activated( int ) ), SLOT( slotInterpolateTypeChanged( int ) ) ); + connect( m_pImageFileNameBrowse, SIGNAL( clicked( ) ), SLOT( slotImageFileBrowseClicked( ) ) ); + connect( m_pImageFileNameEdit, SIGNAL( textChanged( const QString& ) ), SLOT( slotImageFileNameChanged( const QString& ) ) ); + connect( m_pOnceEdit, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pUseIndexEdit, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pBumpSizeEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMBumpMapEdit::displayObject( PMObject* o ) +{ + bool readOnly; + + if( o->isA( "BumpMap" ) ) + { + m_pDisplayedObject = ( PMBumpMap* ) o; + readOnly = m_pDisplayedObject->isReadOnly( ); + + switch( m_pDisplayedObject->bitmapType( ) ) + { + case PMBumpMap::BitmapGif: + m_pImageFileTypeEdit->setCurrentItem( 0 ); + break; + case PMBumpMap::BitmapTga: + m_pImageFileTypeEdit->setCurrentItem( 1 ); + break; + case PMBumpMap::BitmapIff: + m_pImageFileTypeEdit->setCurrentItem( 2 ); + break; + case PMBumpMap::BitmapPpm: + m_pImageFileTypeEdit->setCurrentItem( 3 ); + break; + case PMBumpMap::BitmapPgm: + m_pImageFileTypeEdit->setCurrentItem( 4 ); + break; + case PMBumpMap::BitmapPng: + m_pImageFileTypeEdit->setCurrentItem( 5 ); + break; + case PMBumpMap::BitmapJpeg: + m_pImageFileTypeEdit->setCurrentItem( 6 ); + break; + case PMBumpMap::BitmapTiff: + m_pImageFileTypeEdit->setCurrentItem( 7 ); + break; + case PMBumpMap::BitmapSys: + m_pImageFileTypeEdit->setCurrentItem( 8 ); + break; + } + m_pImageFileTypeEdit->setEnabled( !readOnly ); + + switch( m_pDisplayedObject->interpolateType( ) ) + { + case PMBumpMap::InterpolateNone: + m_pInterpolateTypeEdit->setCurrentItem( 0 ); + break; + case PMBumpMap::InterpolateBilinear: + m_pInterpolateTypeEdit->setCurrentItem( 1); + break; + case PMBumpMap::InterpolateNormalized: + m_pInterpolateTypeEdit->setCurrentItem( 2 ); + break; + } + m_pInterpolateTypeEdit->setEnabled( !readOnly ); + + switch( m_pDisplayedObject->mapType( ) ) + { + case PMBumpMap::MapPlanar: + m_pMapTypeEdit->setCurrentItem( 0 ); + break; + case PMBumpMap::MapSpherical: + m_pMapTypeEdit->setCurrentItem( 1 ); + break; + case PMBumpMap::MapCylindrical: + m_pMapTypeEdit->setCurrentItem( 2 ); + break; + case PMBumpMap::MapToroidal: + m_pMapTypeEdit->setCurrentItem( 3 ); + break; + } + m_pMapTypeEdit->setEnabled( !readOnly ); + + m_pImageFileNameEdit->setText( m_pDisplayedObject->bitmapFile( ) ); + m_pImageFileNameEdit->setEnabled( !readOnly ); + m_pOnceEdit->setChecked( m_pDisplayedObject->isOnceEnabled( ) ); + m_pOnceEdit->setEnabled( !readOnly ); + m_pUseIndexEdit->setChecked( m_pDisplayedObject->isUseIndexEnabled( ) ); + m_pUseIndexEdit->setEnabled( !readOnly ); + m_pBumpSizeEdit->setValue( m_pDisplayedObject->bumpSize( ) ); + m_pBumpSizeEdit->setReadOnly( readOnly ); + + Base::displayObject( o ); + } + +} + +void PMBumpMapEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + switch( m_pImageFileTypeEdit->currentItem( ) ) + { + case 0: + m_pDisplayedObject->setBitmapType( PMBumpMap::BitmapGif ); + break; + case 1: + m_pDisplayedObject->setBitmapType( PMBumpMap::BitmapTga ); + break; + case 2: + m_pDisplayedObject->setBitmapType( PMBumpMap::BitmapIff ); + break; + case 3: + m_pDisplayedObject->setBitmapType( PMBumpMap::BitmapPpm ); + break; + case 4: + m_pDisplayedObject->setBitmapType( PMBumpMap::BitmapPgm ); + break; + case 5: + m_pDisplayedObject->setBitmapType( PMBumpMap::BitmapPng ); + break; + case 6: + m_pDisplayedObject->setBitmapType( PMBumpMap::BitmapJpeg ); + break; + case 7: + m_pDisplayedObject->setBitmapType( PMBumpMap::BitmapTiff ); + break; + case 8: + m_pDisplayedObject->setBitmapType( PMBumpMap::BitmapSys ); + break; + } + + switch( m_pInterpolateTypeEdit->currentItem( ) ) + { + case 0: + m_pDisplayedObject->setInterpolateType( PMBumpMap::InterpolateNone ); + break; + case 1: + m_pDisplayedObject->setInterpolateType( PMBumpMap::InterpolateBilinear ); + break; + case 2: + m_pDisplayedObject->setInterpolateType( PMBumpMap::InterpolateNormalized ); + break; + } + + switch( m_pMapTypeEdit->currentItem( ) ) + { + case 0: + m_pDisplayedObject->setMapType( PMBumpMap::MapPlanar ); + break; + case 1: + m_pDisplayedObject->setMapType( PMBumpMap::MapSpherical ); + break; + case 2: + m_pDisplayedObject->setMapType( PMBumpMap::MapCylindrical ); + break; + case 3: + m_pDisplayedObject->setMapType( PMBumpMap::MapToroidal ); + break; + } + + m_pDisplayedObject->setBitmapFileName( m_pImageFileNameEdit->text( ) ); + m_pDisplayedObject->enableOnce( m_pOnceEdit->isChecked( ) ); + m_pDisplayedObject->enableUseIndex( m_pUseIndexEdit->isChecked( ) ); + m_pDisplayedObject->setBumpSize( m_pBumpSizeEdit->value( ) ); + } +} + +bool PMBumpMapEdit::isDataValid( ) +{ + if( !m_pBumpSizeEdit->isDataValid( ) ) return false; + + return Base::isDataValid( ); +} + +void PMBumpMapEdit::slotInterpolateTypeChanged( const int /*a*/ ) +{ + emit dataChanged( ); +} + +void PMBumpMapEdit::slotImageFileTypeChanged( const int /*a*/ ) +{ + emit dataChanged( ); +} + +void PMBumpMapEdit::slotMapTypeChanged( const int /*a*/ ) +{ + emit dataChanged( ); +} + +void PMBumpMapEdit::slotImageFileNameChanged( const QString& /*a*/ ) +{ + emit dataChanged( ); +} + +void PMBumpMapEdit::slotImageFileBrowseClicked( ) +{ + QString str = KFileDialog::getOpenFileName( QString::null, QString::null ); + + if( !str.isEmpty() ) + { + m_pImageFileNameEdit->setText( str ); + emit dataChanged( ); + } +} + +#include "pmbumpmapedit.moc" diff --git a/kpovmodeler/pmbumpmapedit.h b/kpovmodeler/pmbumpmapedit.h new file mode 100644 index 00000000..cceb2b84 --- /dev/null +++ b/kpovmodeler/pmbumpmapedit.h @@ -0,0 +1,86 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Passos Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMBUMPMAPEDIT_H +#define PMBUMPMAPEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmpalettevalueedit.h" +#include "pmdialogeditbase.h" + +class PMBumpMap; +class PMPaletteValue; +class PMVectorEdit; +class QComboBox; +class PMFloatEdit; +class PMIntEdit; +class QLabel; +class QCheckBox; +class QWidget; +class QLineEdit; +class QPushButton; + +/** + * Dialog edit class for @ref PMBumpMap. + */ +class PMBumpMapEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMBumpMapEdit with parent and name + */ + PMBumpMapEdit( QWidget* parent, const char* name = 0 ); + /** */ + virtual void displayObject( PMObject* o ); + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); +private slots: + /** */ + void slotImageFileTypeChanged( int a ); + /** */ + void slotMapTypeChanged( int a ); + /** */ + void slotInterpolateTypeChanged( int a ); + /** */ + void slotImageFileNameChanged( const QString& a ); + /** */ + void slotImageFileBrowseClicked( ); +private: + PMBumpMap* m_pDisplayedObject; + QComboBox* m_pImageFileTypeEdit; + QLineEdit* m_pImageFileNameEdit; + QPushButton* m_pImageFileNameBrowse; + QCheckBox* m_pOnceEdit; + QComboBox* m_pMapTypeEdit; + QComboBox* m_pInterpolateTypeEdit; + QCheckBox* m_pUseIndexEdit; + PMFloatEdit* m_pBumpSizeEdit; +}; + +#endif diff --git a/kpovmodeler/pmcamera.cpp b/kpovmodeler/pmcamera.cpp new file mode 100644 index 00000000..b224f340 --- /dev/null +++ b/kpovmodeler/pmcamera.cpp @@ -0,0 +1,769 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmcamera.h" + +#include "pmxmlhelper.h" +#include "pmcameraedit.h" +#include "pmmemento.h" +#include "pmviewstructure.h" +#include "pm3dcontrolpoint.h" +#include "pmvectorcontrolpoint.h" +#include "pmenumproperty.h" + +#include + +PMDefinePropertyClass( PMCamera, PMCameraProperty ); +PMDefineEnumPropertyClass( PMCamera, PMCamera::CameraType, + PMCameraTypeProperty ); + +PMViewStructure* PMCamera::s_pDefaultViewStructure = 0; +PMMetaObject* PMCamera::s_pMetaObject = 0; +PMObject* createNewCamera( PMPart* part ) +{ + return new PMCamera( part ); +} + +const PMVector locationDefault = PMVector( 0.0, 0.0, 0.0 ); +const PMVector lookAtDefault = PMVector( 0.0, 0.0, 1.0 ); +const PMVector directionDefault = PMVector( 0.0, 0.0, 1.0 ); +const PMVector upDefault = PMVector( 0.0, 1.0, 0.0 ); +const PMVector rightDefault = PMVector( 4.0/3.0, 0.0, 0.0 ); +const PMVector skyDefault = PMVector( 0.0, 1.0, 0.0 ); +//const double aspectDefault = 1.0; +const bool angleEnabledDefault = false; +const double angleDefault = 90.0; +const PMCamera::CameraType cameraTypeDefault = PMCamera::Perspective; +const int cylinderTypeDefault = 1; +const bool focalBlurDefault = false; +const double apertureDefault = 0.4; +const int blurSamplesDefault = 10; +const PMVector focalPointDefault = PMVector( 0.0, 0.0, 0.0 ); +const double confidenceDefault = 0.9; +const double varianceDefault = 0.008; +const bool c_defaultExport = true; + +PMCamera::PMCamera( PMPart* part ) + : Base( part ) +{ + m_location = locationDefault; + m_lookAt = lookAtDefault; + m_direction = directionDefault; + + m_up = upDefault; + m_right = rightDefault; + + m_sky = skyDefault; + m_angle = angleDefault; + m_angleEnabled = angleEnabledDefault; + + m_cameraType = cameraTypeDefault; + m_cylinderType = cylinderTypeDefault; + + m_focalBlurEnabled = focalBlurDefault; + m_aperture = apertureDefault; + m_blurSamples = blurSamplesDefault; + m_focalPoint = focalPointDefault; + m_confidence = confidenceDefault; + m_variance = varianceDefault; + m_export = c_defaultExport; +} + +PMCamera::PMCamera( const PMCamera& c ) + : Base( c ) +{ + m_location = c.m_location; + m_lookAt = c.m_lookAt; + m_direction = c.m_direction; + + m_up = c.m_up; + m_right = c.m_right; + + m_sky = c.m_sky; + m_angle = c.m_angle; + m_angleEnabled = c.m_angleEnabled; + + m_cameraType = c.m_cameraType; + m_cylinderType = c.m_cylinderType; + + m_focalBlurEnabled = c.m_focalBlurEnabled; + m_aperture = c.m_aperture; + m_blurSamples = c.m_blurSamples; + m_focalPoint = c.m_focalPoint; + m_confidence = c.m_confidence; + m_variance = c.m_variance; + m_export = c.m_export; +} + +PMCamera::~PMCamera( ) +{ +} + +QString PMCamera::description( ) const +{ + return i18n( "camera" ); +} + +void PMCamera::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "camera_type", cameraTypeToString( m_cameraType ) ); + e.setAttribute( "cylinder_type", m_cylinderType ); + e.setAttribute( "location", m_location.serializeXML( ) ); + e.setAttribute( "sky", m_sky.serializeXML( ) ); + e.setAttribute( "direction", m_direction.serializeXML( ) ); + e.setAttribute( "right", m_right.serializeXML( ) ); + e.setAttribute( "up", m_up.serializeXML( ) ); + e.setAttribute( "look_at", m_lookAt.serializeXML( ) ); + e.setAttribute( "angle_enabled", m_angleEnabled ); + e.setAttribute( "angle", m_angle ); + e.setAttribute( "focal_blur", m_focalBlurEnabled ); + e.setAttribute( "aperture", m_aperture ); + e.setAttribute( "blur_samples", m_blurSamples ); + e.setAttribute( "focal_point", m_focalPoint.serializeXML( ) ); + e.setAttribute( "confidence", m_confidence ); + e.setAttribute( "variance", m_variance ); + e.setAttribute( "export", m_export ); + + Base::serialize( e, doc ); +} + +void PMCamera::readAttributes( const PMXMLHelper& h ) +{ + m_cameraType = stringToCameraType( h.stringAttribute( "camera_type", + "perspective" ) ); + m_cylinderType = h.intAttribute( "cylinder_type", cylinderTypeDefault ); + m_location = h.vectorAttribute( "location", locationDefault ); + m_sky = h.vectorAttribute( "sky", skyDefault ); + m_direction = h.vectorAttribute( "direction", directionDefault ); + m_right = h.vectorAttribute( "right", rightDefault ); + m_up = h.vectorAttribute( "up", upDefault ); + m_lookAt = h.vectorAttribute( "look_at", lookAtDefault ); + m_angleEnabled = h.boolAttribute( "angle_enabled", angleEnabledDefault ); + m_angle = h.doubleAttribute( "angle", angleDefault ); + m_focalBlurEnabled = h.boolAttribute( "focal_blur", focalBlurDefault ); + m_aperture = h.doubleAttribute( "aperture", apertureDefault ); + m_blurSamples = h.intAttribute( "blur_samples", blurSamplesDefault ); + m_focalPoint = h.vectorAttribute( "focal_point", focalPointDefault ); + m_confidence = h.doubleAttribute( "confidence", confidenceDefault ); + m_variance = h.doubleAttribute( "variance", varianceDefault ); + m_export = h.boolAttribute( "export", c_defaultExport ); + Base::readAttributes( h ); +} + +PMMetaObject* PMCamera::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Camera", Base::metaObject( ), + createNewCamera ); + s_pMetaObject->addProperty( + new PMCameraProperty( "location", &PMCamera::setLocation, + &PMCamera::location ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "lookAt", &PMCamera::setLookAt, + &PMCamera::lookAt ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "up", &PMCamera::setUp, + &PMCamera::up ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "right", &PMCamera::setRight, + &PMCamera::right ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "direction", &PMCamera::setDirection, + &PMCamera::direction ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "sky", &PMCamera::setSky, + &PMCamera::sky ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "aspect", 0, &PMCamera::aspect ) ); + + s_pMetaObject->addProperty( + new PMCameraProperty( "angleEnabled", &PMCamera::enableAngle, + &PMCamera::isAngleEnabled ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "angle", &PMCamera::setAngle, + &PMCamera::angle ) ); + + PMCameraTypeProperty* p = new PMCameraTypeProperty( + "cameraType", &PMCamera::setCameraType, + &PMCamera::cameraType ); + p->addEnumValue( "Perspective", Perspective ); + p->addEnumValue( "Orthographic", Orthographic ); + p->addEnumValue( "FishEye", FishEye ); + p->addEnumValue( "UltraWideAngle", UltraWideAngle ); + p->addEnumValue( "Omnimax", Omnimax ); + p->addEnumValue( "Panoramic", Panoramic ); + p->addEnumValue( "Cylinder", Cylinder ); + s_pMetaObject->addProperty( p ); + + s_pMetaObject->addProperty( + new PMCameraProperty( "cylinderType", &PMCamera::setCylinderType, + &PMCamera::cylinderType ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "focalBlurEnabled", &PMCamera::enableFocalBlur, + &PMCamera::isFocalBlurEnabled ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "aperture", &PMCamera::setAperture, + &PMCamera::aperture ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "blurSamples", &PMCamera::setBlurSamples, + &PMCamera::blurSamples ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "focalPoint", &PMCamera::setFocalPoint, + &PMCamera::focalPoint ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "confidence", &PMCamera::setConfidence, + &PMCamera::confidence ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "variance", &PMCamera::setVariance, + &PMCamera::variance ) ); + s_pMetaObject->addProperty( + new PMCameraProperty( "export", &PMCamera::setExportPovray, + &PMCamera::exportPovray ) ); + } + return s_pMetaObject; +} + +void PMCamera::setLocation( const PMVector& p ) +{ + if( p != m_location ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMLocationID, m_location ); + m_location = p; + m_location.resize( 3 ); + setViewStructureChanged( ); + } +} + +void PMCamera::setLookAt( const PMVector& p ) +{ + if( p != m_lookAt ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMLookAtID, m_lookAt ); + m_lookAt = p; + m_lookAt.resize( 3 ); + setViewStructureChanged( ); + } +} + +void PMCamera::setUp( const PMVector& v ) +{ + if( v != m_up ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMUpID, m_up ); + m_up = v; + m_up.resize( 3 ); + setViewStructureChanged( ); + } +} + +void PMCamera::setRight( const PMVector& v ) +{ + if( v != m_right ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRightID, m_right ); + m_right = v; + m_right.resize( 3 ); + setViewStructureChanged( ); + } +} + +void PMCamera::setDirection( const PMVector& v ) +{ + if( v != m_direction ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMDirectionID, m_direction ); + m_direction = v; + m_direction.resize( 3 ); + setViewStructureChanged( ); + } +} + +void PMCamera::setSky( const PMVector& v ) +{ + if( v != m_sky ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSkyID, m_sky ); + m_sky = v; + m_sky.resize( 3 ); + setViewStructureChanged( ); + } +} + +double PMCamera::aspect( ) const +{ + double d = m_up.abs( ); + if( approxZero( d ) ) + return 1.0; + return m_right.abs( ) / d; +} + +void PMCamera::enableAngle( bool yes ) +{ + if( yes != m_angleEnabled ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAngleEnabledID, m_angleEnabled ); + m_angleEnabled = yes; + setViewStructureChanged( ); + } +} + +void PMCamera::setAngle( double a ) +{ + if( a != m_angle ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAngleID, m_angle ); + m_angle = a; + setViewStructureChanged( ); + } +} + +void PMCamera::setCameraType( PMCamera::CameraType t ) +{ + if( t != m_cameraType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCameraTypeID, m_cameraType ); + m_cameraType = t; + setViewStructureChanged( ); + } +} + +void PMCamera::setCylinderType( int t ) +{ + if( ( t < 1 ) || ( t > 4 ) ) + kdError( PMArea ) << "Invalid type in PMCylinder::setCylinderType\n"; + else if( t != m_cylinderType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCylinderTypeID, m_cylinderType ); + m_cylinderType = t; + setViewStructureChanged( ); + } +} + +void PMCamera::enableFocalBlur( bool yes ) +{ + if( yes != m_focalBlurEnabled ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFocalBlurID, m_focalBlurEnabled ); + m_focalBlurEnabled = yes; + } +} + +void PMCamera::setAperture( double a ) +{ + if( a < 0 ) + kdError( PMArea ) << "Aperture < 0 in PMCylinder::setAperture\n"; + else if( a != m_aperture ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMApertureID, m_aperture ); + m_aperture = a; + } +} + +void PMCamera::setBlurSamples( int s ) +{ + if( s < 0 ) + kdError( PMArea ) << "Samples < 0 in PMCylinder::setBlutSamples\n"; + else if( s != m_blurSamples ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMBlurSamplesID, m_blurSamples ); + m_blurSamples = s; + } +} + +void PMCamera::setFocalPoint( const PMVector& v ) +{ + if( v != m_focalPoint ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFocalPointID, m_focalPoint ); + m_focalPoint = v; + } +} + +void PMCamera::setConfidence( double c ) +{ + if( ( c < 0.0 ) || ( c > 1.0 ) ) + kdError( PMArea ) << "Confidence not in [0.0 1.0] in PMCylinder::setConfidence\n"; + else if( c != m_confidence ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMConfidenceID, m_confidence ); + m_confidence = c; + } +} + +void PMCamera::setVariance( double v ) +{ + if( v < 0 ) + kdError( PMArea ) << "Variance < 0 in PMCylinder::setVariance\n"; + else if( v != m_variance ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMVarianceID, m_variance ); + m_variance = v; + } +} + +void PMCamera::setExportPovray( bool ex ) +{ + if( m_export != ex ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMExportID, m_export ); + m_export = ex; + } +} + +PMDialogEditBase* PMCamera::editWidget( QWidget* parent ) const +{ + return new PMCameraEdit( parent ); +} + +void PMCamera::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMLocationID: + setLocation( data->vectorData( ) ); + break; + case PMLookAtID: + setLookAt( data->vectorData( ) ); + break; + case PMUpID: + setUp( data->vectorData( ) ); + break; + case PMRightID: + setRight( data->vectorData( ) ); + break; + case PMDirectionID: + setDirection( data->vectorData( ) ); + break; + case PMSkyID: + setSky( data->vectorData( ) ); + break; + case PMAngleEnabledID: + enableAngle( data->boolData( ) ); + break; + case PMAngleID: + setAngle( data->doubleData( ) ); + break; + case PMCameraTypeID: + setCameraType( ( CameraType ) data->intData( ) ); + break; + case PMCylinderTypeID: + setCylinderType( data->intData( ) ); + break; + case PMFocalBlurID: + enableFocalBlur( data->boolData( ) ); + break; + case PMBlurSamplesID: + setBlurSamples( data->intData( ) ); + break; + case PMFocalPointID: + setFocalPoint( data->vectorData( ) ); + break; + case PMConfidenceID: + setConfidence( data->doubleData( ) ); + break; + case PMVarianceID: + setVariance( data->doubleData( ) ); + break; + case PMApertureID: + setAperture( data->doubleData( ) ); + break; + case PMExportID: + setExportPovray( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMCamera::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + +void PMCamera::createViewStructure( ) +{ + PMVector newUp, newRight, newDirection, tmp; + double upLen, rightLen; + + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultViewStructure( ) ); + m_pViewStructure->points( ).detach( ); + } + + PMPointArray& points = m_pViewStructure->points( ); + calculateLookAtAngle( newRight, newUp, newDirection ); + + points[0] = m_lookAt; + points[1] = m_location; + + upLen = newUp.abs( ); + rightLen = newRight.abs( ); + if( rightLen > upLen ) + { + newUp /= rightLen; + newRight /= rightLen; + newDirection /= rightLen; + } + else + { + newUp /= upLen; + newRight /= upLen; + newDirection /= upLen; + } + + newRight /= 2.0; + newUp /= 2.0; + tmp = m_location + newDirection; + points[2] = tmp - newRight + newUp; + points[3] = tmp - newRight - newUp; + points[4] = tmp + newRight - newUp; + points[5] = tmp + newRight + newUp; +// points[6] = m_location + m_sky; +} + +PMViewStructure* PMCamera::defaultViewStructure( ) const +{ + if( !s_pDefaultViewStructure ) + { + s_pDefaultViewStructure = new PMViewStructure( 6, 9 ); + PMLineArray& lines = s_pDefaultViewStructure->lines( ); + + lines[0] = PMLine( 0, 1 ); + lines[1] = PMLine( 1, 2 ); + lines[2] = PMLine( 1, 3 ); + lines[3] = PMLine( 1, 4 ); + lines[4] = PMLine( 1, 5 ); + lines[5] = PMLine( 2, 3 ); + lines[6] = PMLine( 2, 5 ); + lines[7] = PMLine( 3, 4 ); + lines[8] = PMLine( 4, 5 ); +// lines[9] = PMLine( 1, 6 ); + } + return s_pDefaultViewStructure; +} + +void PMCamera::controlPoints( PMControlPointList& list ) +{ + PMControlPoint* p; + p = new PM3DControlPoint( m_location, PMLocationID, i18n( "Location" ) ); + list.append( p ); + list.append( new PM3DControlPoint( m_lookAt, PMLookAtID, i18n( "Look at" ) ) ); +} + +void PMCamera::controlPointsChanged( PMControlPointList& list ) +{ + PMControlPoint* p; + + for( p = list.first( ); p; p = list.next( ) ) + { + if( p->changed( ) ) + { + switch( p->id( ) ) + { + case PMLocationID: + setLocation( ( ( PM3DControlPoint* ) p )->point( ) ); + break; + case PMLookAtID: + setLookAt( ( ( PM3DControlPoint* ) p )->point( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMCamera::controlPointsChanged\n"; + break; + } + } + } +} + +void PMCamera::calculateLookAtAngle( PMVector& right, PMVector& up, PMVector& direction ) +{ + PMVector tmpVector; + double directionLen, upLen, rightLen, handedness, angle; + + angle = m_angle; + if( m_cameraType == Perspective ) + { + if( angle < 0.0 ) + angle = angleDefault; + if( angle >= 180.0 ) + angle = angleDefault; + } + else + angle = 90.0; + + directionLen = m_direction.abs( ); + upLen = m_up.abs( ); + rightLen = m_right.abs( ); + + // for safety: if vector is null vector, use the default one + if( approxZero( directionLen ) ) + { + direction = directionDefault; + directionLen = direction.abs( ); + } + else + direction = m_direction; + + if( approxZero( upLen ) ) + { + up = upDefault; + upLen = up.abs( ); + } + else + up = m_up; + + if( approxZero( rightLen ) ) + { + right = rightDefault; + rightLen = right.abs( ); + } + else + right = m_right; + + if( m_angleEnabled ) + { + // calculate angle + direction /= directionLen; + directionLen = 0.5 * rightLen / tan( angle * M_PI / 360.0 ); + direction *= directionLen; + } + + // calculate handedness + tmpVector = PMVector::cross( up, direction ); + handedness = PMVector::dot( tmpVector, right ); + + direction = m_lookAt - m_location; + if( approxZero( direction.abs( ) ) ) + { + // Camera location and look_at point are the same + direction = directionDefault; + } + + // normalize new direction + direction /= direction.abs( ); + + tmpVector = right; + right = PMVector::cross( m_sky, direction ); + + if( approxZero( right.abs( ) ) ) + right = tmpVector; + + right /= right.abs( ); + up = PMVector::cross( direction, right ); + direction *= directionLen; + + if( handedness > 0.0 ) + right *= rightLen; + else + right *= -rightLen; + up *= upLen; +} + +QString PMCamera::cameraTypeToString( PMCamera::CameraType t ) +{ + QString str( "perspective" ); + switch( t ) + { + case Perspective: + break; + case Orthographic: + str = "orthographic"; + break; + case FishEye: + str = "fisheye"; + break; + case UltraWideAngle: + str = "ultra_wide_angle"; + break; + case Omnimax: + str = "omnimax"; + break; + case Panoramic: + str = "panoramic"; + break; + case Cylinder: + str = "cylinder"; + break; + } + return str; +} + +PMCamera::CameraType PMCamera::stringToCameraType( const QString& str ) +{ + CameraType t = Perspective; + + if( str == "perspective" ) + t = Perspective; + else if( str == "orthographic" ) + t = Orthographic; + else if( str == "fisheye" ) + t = FishEye; + else if( str == "ultra_wide_angle" ) + t = UltraWideAngle; + else if( str == "omnimax" ) + t = Omnimax; + else if( str == "panoramic" ) + t = Panoramic; + else if( str == "cylinder" ) + t = Cylinder; + else + kdDebug( PMArea ) << "Unknown camera type\n"; + + return t; +} + +void PMCamera::cleanUp( ) const +{ + if( s_pDefaultViewStructure ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + } + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + + Base::cleanUp( ); +} diff --git a/kpovmodeler/pmcamera.h b/kpovmodeler/pmcamera.h new file mode 100644 index 00000000..9f09ee58 --- /dev/null +++ b/kpovmodeler/pmcamera.h @@ -0,0 +1,292 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMCAMERA_H +#define PMCAMERA_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmnamedobject.h" +#include "pmvector.h" + +class PMViewStructure; + +/** + * Class for povray cameras + */ + +class PMCamera : public PMNamedObject +{ + typedef PMNamedObject Base; +public: + /** + * Type of the camera + */ + enum CameraType { Perspective, Orthographic, FishEye, UltraWideAngle, + Omnimax, Panoramic, Cylinder }; + /** + * Creates a default povray camera + */ + PMCamera( PMPart* part ); + /** + * Copy constructor + */ + PMCamera( const PMCamera& c ); + /** + * deletes the camera + */ + virtual ~PMCamera( ); + + /** */ + virtual PMObject* copy( ) const { return new PMCamera( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMCameraEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pmcamera" ); } + + /** + * Returns the location + */ + PMVector location( ) const { return m_location; } + /** + * Sets the location + */ + void setLocation( const PMVector& p ); + + /** + * Returns the look_at point + */ + PMVector lookAt( ) const { return m_lookAt; } + /** + * Sets the look_at point + */ + void setLookAt( const PMVector& p ); + + /** + * Returns the up vector + */ + PMVector up( ) const { return m_up; } + /** + * Sets the up vector + */ + void setUp( const PMVector& v ); + + /** + * Returns the right vector + */ + PMVector right( ) const { return m_right; } + /** + * Sets the right vector + */ + void setRight( const PMVector& v ); + + /** + * Returns the direction vector + */ + PMVector direction( ) const { return m_direction; } + /** + * Sets the direction vector + */ + void setDirection( const PMVector& v ); + + /** + * Returns the sky vector + */ + PMVector sky( ) const { return m_sky; } + /** + * Sets the sky vector + */ + void setSky( const PMVector& v ); + + /** + * Returns the aspect ratio + */ + double aspect( ) const; + + /** + * Returns true if angle is enabled + */ + bool isAngleEnabled( ) const { return m_angleEnabled; } + /** + * Enables/Disables the use of angle + */ + void enableAngle( bool yes ); + + /** + * Returns the angle + */ + double angle( ) const { return m_angle; } + /** + * Sets the angle + */ + void setAngle( double a ); + + /** + * Returns the camera type + */ + CameraType cameraType( ) const { return m_cameraType; } + /** + * Sets the camera type + */ + void setCameraType( CameraType t ); + + /** + * Returns the cylinder type + */ + int cylinderType( ) const { return m_cylinderType; } + /** + * Sets the cylinder type. Valid values are 1-4 + */ + void setCylinderType( int t ); + + /** + * Returns true if focal blur is enabled + */ + bool isFocalBlurEnabled( ) const { return m_focalBlurEnabled; } + /** + * Enables/Disables the focal blur + */ + void enableFocalBlur( bool yes ); + /** + * Returns the aperture + */ + double aperture( ) const { return m_aperture; } + /** + * Sets the aperture. Has to be greater or equal 0 + */ + void setAperture( double d ); + /** + * Returns the number of blur samples + */ + int blurSamples( ) const { return m_blurSamples; } + /** + * Sets the number of blur samples + */ + void setBlurSamples( int s ); + /** + * Returns the focal point + */ + PMVector focalPoint( ) const { return m_focalPoint; } + /** + * Sets the focal point + */ + void setFocalPoint( const PMVector& v ); + /** + * Returns the confidence + */ + double confidence( ) const { return m_confidence;} + /** + * Sets the confidence + */ + void setConfidence( double c ); + /** + * Returns the variance + */ + double variance( ) const { return m_variance; } + /** + * Sets the variance + */ + void setVariance( double v ); + + /** + * Returns the export flag + */ + virtual bool exportPovray( ) const { return m_export; } + /** + * Sets the export flag + */ + void setExportPovray( bool ex ); + + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual void controlPoints( PMControlPointList& list ); + /** */ + virtual void controlPointsChanged( PMControlPointList& list ); + + /** + * Calculates the new right, up and direction vector with the + * look_at vector. + */ + void calculateLookAtAngle( PMVector& right, PMVector& up, PMVector& direction ); + + /** + * Converts the camera type to a string + */ + static QString cameraTypeToString( CameraType t ); + /** + * Converts a string to the camera type + */ + static CameraType stringToCameraType( const QString& s ); + /** */ + virtual void cleanUp( ) const; + +protected: + /** */ + virtual bool isDefault( ) { return false; } + /** */ + virtual void createViewStructure( ); + /** */ + virtual PMViewStructure* defaultViewStructure( ) const; + +private: + /** + * IDs for @ref PMMementoData + */ + enum PMCameraMementoID { PMLocationID, PMLookAtID, PMDirectionID, + PMUpID, PMRightID, PMAngleID, PMSkyID, + PMCameraTypeID, PMCylinderTypeID, + PMFocalBlurID, PMBlurSamplesID, PMFocalPointID, + PMConfidenceID, PMVarianceID, PMApertureID, + PMAngleEnabledID, PMExportID }; + PMVector m_location, m_lookAt, m_up, m_right, m_direction, m_sky; + bool m_angleEnabled; + double m_angle; + CameraType m_cameraType; + int m_cylinderType; + bool m_focalBlurEnabled; + double m_aperture; + int m_blurSamples; + PMVector m_focalPoint; + double m_confidence, m_variance; + bool m_export; + + /** + * The default view structure. It can be shared between cameras + */ + static PMViewStructure* s_pDefaultViewStructure; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmcameraedit.cpp b/kpovmodeler/pmcameraedit.cpp new file mode 100644 index 00000000..676c9f8b --- /dev/null +++ b/kpovmodeler/pmcameraedit.cpp @@ -0,0 +1,439 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmcameraedit.h" +#include "pmcamera.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" + +#include +#include +#include +#include + +#include +#include + + +PMCameraEdit::PMCameraEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMCameraEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QGridLayout* layout; + QLabel* label; + + m_pCameraType = new QComboBox( false, this ); + m_pCameraType->insertItem( i18n( "Perspective" ) ); + m_pCameraType->insertItem( i18n( "Orthographic" ) ); + m_pCameraType->insertItem( i18n( "Fish Eye" ) ); + m_pCameraType->insertItem( i18n( "Ultra Wide Angle" ) ); + m_pCameraType->insertItem( i18n( "Omnimax" ) ); + m_pCameraType->insertItem( i18n( "Panoramic" ) ); + m_pCameraType->insertItem( i18n( "Cylinder" ) ); + + m_pCylinderType = new QComboBox( false, this ); + m_pCylinderType->insertItem( i18n( "1: Vertical, Fixed Viewpoint" ) ); + m_pCylinderType->insertItem( i18n( "2: Horizontal, Fixed Viewpoint" ) ); + m_pCylinderType->insertItem( i18n( "3: Vertical, Variable Viewpoint" ) ); + m_pCylinderType->insertItem( i18n( "4: Horizontal, Variable Viewpoint" ) ); + + m_pLocation = new PMVectorEdit( "x", "y", "z", this ); + m_pSky = new PMVectorEdit( "x", "y", "z", this ); + m_pDirection = new PMVectorEdit( "x", "y", "z", this ); + m_pRight = new PMVectorEdit( "x", "y", "z", this ); + m_pUp = new PMVectorEdit( "x", "y", "z", this ); + m_pLookAt = new PMVectorEdit( "x", "y", "z", this ); + m_pAngle = new PMFloatEdit( this ); + m_pAngle->setValidation( true, 0.0, true, 360.0 ); + + QHBoxLayout* hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Camera type:" ), this ) ); + hl->addWidget( m_pCameraType ); + hl = new QHBoxLayout( topLayout( ) ); + m_pCylinderTypeLabel = new QLabel( i18n( "Cylinder type:" ), this ); + hl->addWidget( m_pCylinderTypeLabel ); + hl->addWidget( m_pCylinderType ); + + layout = new QGridLayout( topLayout( ), 7, 2 ); + layout->addWidget( new QLabel( i18n( "Location:" ), this ), 0, 0 ); + layout->addWidget( m_pLocation, 0, 1 ); + + layout->addWidget( new QLabel( i18n( "Sky:" ), this ), 1, 0 ); + layout->addWidget( m_pSky, 1, 1 ); + + layout->addWidget( new QLabel( i18n( "Direction:" ), this ), 2, 0 ); + layout->addWidget( m_pDirection, 2, 1 ); + + layout->addWidget( new QLabel( i18n( "Right:" ), this ), 3, 0 ); + layout->addWidget( m_pRight, 3, 1 ); + + layout->addWidget( new QLabel( i18n( "Up:" ), this ), 4, 0 ); + layout->addWidget( m_pUp, 4, 1 ); + + layout->addWidget( new QLabel( i18n( "Look at:" ), this ), 5, 0 ); + layout->addWidget( m_pLookAt, 5, 1 ); + + m_pEnableAngle = new QCheckBox( i18n( "Angle:" ), this ); + layout->addWidget( m_pEnableAngle, 6, 0 ); + layout->addWidget( m_pAngle, 6, 1, AlignLeft ); + + m_pFocalBlur = new QCheckBox( i18n( "Focal blur" ), this ); + topLayout( )->addWidget( m_pFocalBlur ); + + m_pAperture = new PMFloatEdit( this ); + m_pAperture->setValidation( true, 0, false, 0 ); + m_focalWidgets.append( m_pAperture ); + m_pBlurSamples = new PMIntEdit( this ); + m_pBlurSamples->setValidation( true, 0, false, 0 ); + m_focalWidgets.append( m_pBlurSamples ); + m_pFocalPoint = new PMVectorEdit( "x", "y", "z", this ); + m_focalWidgets.append( m_pFocalPoint ); + m_pConfidence = new PMFloatEdit( this ); + m_pConfidence->setValidation( true, 0, true, 1 ); + m_focalWidgets.append( m_pConfidence ); + m_pVariance = new PMFloatEdit( this ); + m_pVariance->setValidation( true, 0, false, 0 ); + m_focalWidgets.append( m_pVariance ); + + layout = new QGridLayout( topLayout( ), 5, 2 ); + label = new QLabel( i18n( "Aperture:" ), this ); + m_focalWidgets.append( label ); + layout->addWidget( label, 0, 0 ); + layout->addWidget( m_pAperture, 0, 1 ); + label = new QLabel( i18n( "Blur samples:" ), this ); + m_focalWidgets.append( label ); + layout->addWidget( label, 1, 0 ); + layout->addWidget( m_pBlurSamples, 1, 1 ); + label = new QLabel( i18n( "Focal point:" ), this ); + m_focalWidgets.append( label ); + layout->addWidget( label, 2, 0 ); + layout->addWidget( m_pFocalPoint, 2, 1 ); + label = new QLabel( i18n( "Confidence:" ), this ); + m_focalWidgets.append( label ); + layout->addWidget( label, 3, 0 ); + layout->addWidget( m_pConfidence, 3, 1 ); + label = new QLabel( i18n( "Variance:" ), this ); + m_focalWidgets.append( label ); + layout->addWidget( label, 4, 0 ); + layout->addWidget( m_pVariance, 4, 1 ); + + m_pExport = new QCheckBox( i18n( "Export to renderer" ), this ); + topLayout( )->addWidget( m_pExport ); + + connect( m_pLocation, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pDirection, SIGNAL( dataChanged( ) ), SLOT( slotDirectionChanged( ) ) ); + connect( m_pRight, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pRight, SIGNAL( dataChanged( ) ), SLOT( slotRightChanged( ) ) ); + connect( m_pUp, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pSky, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pLookAt, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pEnableAngle, SIGNAL( toggled( bool ) ), + SLOT( slotAngleToggled( bool ) ) ); + connect( m_pAngle, SIGNAL( dataChanged( ) ), SLOT( slotAngleChanged( ) ) ); + connect( m_pCameraType, SIGNAL( activated( int ) ), + SLOT( slotCameraTypeActivated( int ) ) ); + connect( m_pCylinderType, SIGNAL( activated( int ) ), + SLOT( slotCylinderTypeActivated( int ) ) ); + + connect( m_pFocalBlur, SIGNAL( toggled( bool ) ), + SLOT( slotFocalBlurToggled( bool ) ) ); + connect( m_pAperture, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pBlurSamples, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pFocalPoint, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pVariance, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pConfidence, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pExport, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMCameraEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Camera" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMCamera* ) o; + + m_pCameraType->setCurrentItem( m_pDisplayedObject->cameraType( ) ); + m_pCameraType->setEnabled( !readOnly ); + slotCameraTypeActivated( m_pDisplayedObject->cameraType( ) ); + m_pCylinderType->setCurrentItem( m_pDisplayedObject->cylinderType( ) - 1 ); + m_pCylinderType->setEnabled( !readOnly ); + m_pLocation->setVector( m_pDisplayedObject->location( ) ); + m_pLocation->setReadOnly( readOnly ); + m_pSky->setVector( m_pDisplayedObject->sky( ) ); + m_pSky->setReadOnly( readOnly ); + m_pDirection->setVector( m_pDisplayedObject->direction( ) ); + m_pDirection->setReadOnly( readOnly ); + m_pRight->setVector( m_pDisplayedObject->right( ) ); + m_pRight->setReadOnly( readOnly ); + m_pUp->setVector( m_pDisplayedObject->up( ) ); + m_pUp->setReadOnly( readOnly ); + m_pLookAt->setVector( m_pDisplayedObject->lookAt( ) ); + m_pLookAt->setReadOnly( readOnly ); + + m_pEnableAngle->setChecked( m_pDisplayedObject->isAngleEnabled( ) ); + m_pEnableAngle->setEnabled( !readOnly ); + m_pAngle->setValue( m_pDisplayedObject->angle( ) ); + m_pAngle->setReadOnly( readOnly ); + slotAngleToggled( m_pDisplayedObject->isAngleEnabled( ) ); + slotRightChanged( ); + m_pFocalBlur->setChecked( m_pDisplayedObject->isFocalBlurEnabled( ) ); + slotFocalBlurToggled( m_pDisplayedObject->isFocalBlurEnabled( ) ); + m_pFocalBlur->setEnabled( !readOnly ); + + m_pAperture->setValue( m_pDisplayedObject->aperture( ) ); + m_pAperture->setReadOnly( readOnly ); + m_pBlurSamples->setValue( m_pDisplayedObject->blurSamples( ) ); + m_pBlurSamples->setReadOnly( readOnly ); + m_pFocalPoint->setVector( m_pDisplayedObject->focalPoint( ) ); + m_pFocalPoint->setReadOnly( readOnly ); + m_pConfidence->setValue( m_pDisplayedObject->confidence( ) ); + m_pConfidence->setReadOnly( readOnly ); + m_pVariance->setValue( m_pDisplayedObject->variance( ) ); + m_pVariance->setReadOnly( readOnly ); + + m_pExport->setChecked( m_pDisplayedObject->exportPovray( ) ); + m_pExport->setEnabled( !readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMCameraEdit: Can't display object\n"; +} + +void PMCameraEdit::saveContents( ) +{ + int index; + if( m_pDisplayedObject ) + { + Base::saveContents( ); + index = m_pCameraType->currentItem( ); + m_pDisplayedObject->setCameraType( ( PMCamera::CameraType ) index ); + if( index == 6 ) + m_pDisplayedObject->setCylinderType( m_pCylinderType->currentItem( ) + 1 ); + m_pDisplayedObject->setLocation( m_pLocation->vector( ) ); + m_pDisplayedObject->setDirection( m_pDirection->vector( ) ); + m_pDisplayedObject->setRight( m_pRight->vector( ) ); + m_pDisplayedObject->setUp( m_pUp->vector( ) ); + m_pDisplayedObject->setSky( m_pSky->vector( ) ); + m_pDisplayedObject->setLookAt( m_pLookAt->vector( ) ); + m_pDisplayedObject->enableAngle( m_pEnableAngle->isChecked( ) ); + if( m_pEnableAngle->isChecked( ) ) + m_pDisplayedObject->setAngle( m_pAngle->value( ) ); + + m_pDisplayedObject->enableFocalBlur( m_pFocalBlur->isChecked( ) ); + if( m_pFocalBlur->isChecked( ) ) + { + m_pDisplayedObject->setAperture( m_pAperture->value( ) ); + m_pDisplayedObject->setBlurSamples( m_pBlurSamples->value( ) ); + m_pDisplayedObject->setFocalPoint( m_pFocalPoint->vector( ) ); + m_pDisplayedObject->setConfidence( m_pConfidence->value( ) ); + m_pDisplayedObject->setVariance( m_pVariance->value( ) ); + } + m_pDisplayedObject->setExportPovray( m_pExport->isChecked( ) ); + } +} + +bool PMCameraEdit::isDataValid( ) +{ + if( !m_pLocation->isDataValid( ) ) + return false; + if( !m_pSky->isDataValid( ) ) + return false; + if( approxZero( m_pSky->vector( ).abs( ) ) ) + { + KMessageBox::error( this, i18n( "The sky vector may not be a null vector." ), + i18n( "Error" ) ); + m_pSky->setFocus( ); + return false; + } + if( !m_pDirection->isDataValid( ) ) + return false; + if( approxZero( m_pDirection->vector( ).abs( ) ) ) + { + KMessageBox::error( this, i18n( "The direction vector may not be a null vector." ), + i18n( "Error" ) ); + m_pDirection->setFocus( ); + return false; + } + if( !m_pRight->isDataValid( ) ) + return false; + if( approxZero( m_pRight->vector( ).abs( ) ) ) + { + KMessageBox::error( this, i18n( "The right vector may not be a null vector." ), + i18n( "Error" ) ); + m_pRight->setFocus( ); + return false; + } + if( !m_pUp->isDataValid( ) ) + return false; + if( approxZero( m_pUp->vector( ).abs( ) ) ) + { + KMessageBox::error( this, i18n( "The up vector may not be a null vector." ), + i18n( "Error" ) ); + m_pDirection->setFocus( ); + return false; + } + if( !m_pLookAt->isDataValid( ) ) + return false; + if( m_pEnableAngle->isChecked( ) && !m_pAngle->isDataValid( ) ) + return false; + + if( ( m_pCameraType->currentItem( ) == 0 ) && m_pEnableAngle->isChecked( ) ) + { + double angle = m_pAngle->value( ); + if( angle >= 180.0 ) + { + KMessageBox::error( this, i18n( "Angle has to be smaller than 180" + " degrees for that camera type." ), + i18n( "Error" ) ); + m_pAngle->setFocus( ); + return false; + } + } + + if( m_pFocalBlur->isChecked( ) ) + { + if( !m_pAperture->isDataValid( ) ) + return false; + if( !m_pBlurSamples->isDataValid( ) ) + return false; + if( !m_pFocalPoint->isDataValid( ) ) + return false; + if( !m_pConfidence->isDataValid( ) ) + return false; + if( !m_pVariance->isDataValid( ) ) + return false; + } + + return Base::isDataValid( ); +} + +void PMCameraEdit::slotCameraTypeActivated( int index ) +{ + if( index == 6 ) + { + m_pCylinderType->show( ); + m_pCylinderTypeLabel->show( ); + } + else + { + m_pCylinderType->hide( ); + m_pCylinderTypeLabel->hide( ); + } + + if( ( index == 1 ) || ( index == 4 ) || ( index == 5 ) ) + { + m_pAngle->hide( ); + m_pEnableAngle->hide( ); + } + else + { + m_pAngle->show( ); + m_pEnableAngle->show( ); + } + + if( index == 0 ) + m_pFocalBlur->show( ); + else + m_pFocalBlur->hide( ); + enableFocalWidgets( m_pFocalBlur->isChecked( ) && ( index == 0 ) ); + emit sizeChanged( ); + emit dataChanged( ); +} + +void PMCameraEdit::slotCylinderTypeActivated( int ) +{ + emit dataChanged( ); +} + +void PMCameraEdit::slotFocalBlurToggled( bool on ) +{ + enableFocalWidgets( on && ( m_pCameraType->currentItem( ) == 0 ) ); + emit dataChanged( ); +} + +void PMCameraEdit::slotAngleToggled( bool on ) +{ + m_pAngle->setEnabled( on ); + emit dataChanged( ); +} + +void PMCameraEdit::slotAngleChanged( ) +{ + /* + if( ( m_pCameraType->currentItem( ) == 0 ) && m_pEnableAngle->isChecked( ) ) + { + // Only change direction's value in perspective and with an enabled angle + disconnect( m_pDirection, SIGNAL( dataChanged( ) ), 0, 0 ); + m_pDirection->setVector( 0.5 * m_pRight->vector( ) / tan( 2 * deg2Rad( m_pAngle->value( ) ) ) ); + connect( m_pDirection, SIGNAL( dataChanged( ) ), SLOT( slotDirectionChanged( ) ) ); + } + */ + emit dataChanged( ); +} + +void PMCameraEdit::slotDirectionChanged( ) +{ + calculateCameraAngle( ); + emit dataChanged( ); +} + +void PMCameraEdit::slotRightChanged( ) +{ + calculateCameraAngle( ); + emit dataChanged( ); +} + +void PMCameraEdit::calculateCameraAngle( ) +{ + if( ( m_pCameraType->currentItem( ) == 0 ) && !m_pEnableAngle->isChecked( ) ) + { + // Only change angle's value in perspective and with a disabled angle + double rl = m_pRight->vector( ).abs( ); + double dl = m_pDirection->vector( ).abs( ); + if( ( rl > 0 ) && ( dl > 0 ) ) + { + bool sb = m_pAngle->signalsBlocked( ); + m_pAngle->blockSignals( true ); + m_pAngle->setValue( rad2Deg( 2 * atan2( 0.5 * rl, dl ) ) ); + m_pAngle->blockSignals( sb ); + } + } +} + +void PMCameraEdit::enableFocalWidgets( bool on ) +{ + QPtrListIterator it( m_focalWidgets ); + + for( ; it.current( ); ++it ) + { + if( on ) + it.current( )->show( ); + else + it.current( )->hide( ); + } + emit sizeChanged( ); +} + +#include "pmcameraedit.moc" diff --git a/kpovmodeler/pmcameraedit.h b/kpovmodeler/pmcameraedit.h new file mode 100644 index 00000000..7b787683 --- /dev/null +++ b/kpovmodeler/pmcameraedit.h @@ -0,0 +1,99 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMCAMERAEDIT_H +#define PMCAMERAEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmnamedobjectedit.h" +#include + +class PMCamera; +class PMVectorEdit; +class PMFloatEdit; +class PMIntEdit; +class QComboBox; +class QLabel; +class QCheckBox; + +/** + * Dialog edit class for @ref PMCamera + */ +class PMCameraEdit : public PMNamedObjectEdit +{ + Q_OBJECT + typedef PMNamedObjectEdit Base; +public: + /** + * Creates a PMCameraEdit with parent and name + */ + PMCameraEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); + +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + void slotCameraTypeActivated( int index ); + void slotCylinderTypeActivated( int index ); + void slotFocalBlurToggled( bool on ); + void slotAngleToggled( bool on ); + void slotAngleChanged( ); + void slotDirectionChanged( ); + void slotRightChanged( ); + +private: + void enableFocalWidgets( bool yes ); + void calculateCameraAngle( ); + + PMCamera* m_pDisplayedObject; + PMVectorEdit* m_pLocation; + PMVectorEdit* m_pDirection; + PMVectorEdit* m_pRight; + PMVectorEdit* m_pUp; + PMVectorEdit* m_pSky; + PMVectorEdit* m_pLookAt; + QCheckBox* m_pEnableAngle; + PMFloatEdit* m_pAngle; + QComboBox* m_pCameraType; + QComboBox* m_pCylinderType; + QLabel* m_pCylinderTypeLabel; + QCheckBox* m_pFocalBlur; + PMFloatEdit* m_pAperture; + PMIntEdit* m_pBlurSamples; + PMVectorEdit* m_pFocalPoint; + PMFloatEdit* m_pConfidence; + PMFloatEdit* m_pVariance; + QPtrList m_focalWidgets; + QCheckBox* m_pExport; +}; + + +#endif diff --git a/kpovmodeler/pmclippedby.cpp b/kpovmodeler/pmclippedby.cpp new file mode 100644 index 00000000..fc00bc51 --- /dev/null +++ b/kpovmodeler/pmclippedby.cpp @@ -0,0 +1,114 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmclippedby.h" +#include "pmclippedbyedit.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" + +#include + +PMDefinePropertyClass( PMClippedBy, PMClippedByProperty ); + +PMMetaObject* PMClippedBy::s_pMetaObject = 0; +PMObject* createNewClippedBy( PMPart* part ) +{ + return new PMClippedBy( part ); +} + +PMClippedBy::PMClippedBy( PMPart* part ) + : Base( part ) +{ +} + +PMClippedBy::~PMClippedBy( ) +{ +} + +PMMetaObject* PMClippedBy::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "ClippedBy", Base::metaObject( ), + createNewClippedBy ); + s_pMetaObject->addProperty( + new PMClippedByProperty( "boundedBy", 0, &PMClippedBy::boundedBy ) ); + } + return s_pMetaObject; +} + +void PMClippedBy::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMClippedBy::description( ) const +{ + return i18n( "clipped by" ); +} + +bool PMClippedBy::boundedBy( ) const +{ + bool cb = true; + PMObject* o = firstChild( ); + + for( ; o && cb; o = o->nextSibling( ) ) + if( o->type( ) != "Comment" ) + cb = false; + + return cb; +} + +void PMClippedBy::serialize( QDomElement& e, QDomDocument& doc ) const +{ + // no extra data at the moment + Base::serialize( e, doc ); +} + +void PMClippedBy::readAttributes( const PMXMLHelper& h ) +{ + // no extra data at the moment + Base::readAttributes( h ); +} + +PMDialogEditBase* PMClippedBy::editWidget( QWidget* parent ) const +{ + return new PMClippedByEdit( parent ); +} + +void PMClippedBy::childRemoved( PMObject* o ) +{ + Base::childRemoved( o ); + + // add a dummy change + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMBoundedByID, true ); +} + +void PMClippedBy::childAdded( PMObject* o ) +{ + Base::childAdded( o ); + + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMBoundedByID, true ); +} diff --git a/kpovmodeler/pmclippedby.h b/kpovmodeler/pmclippedby.h new file mode 100644 index 00000000..39c5081a --- /dev/null +++ b/kpovmodeler/pmclippedby.h @@ -0,0 +1,88 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMCLIPPEDBY_H +#define PMCLIPPEDBY_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmcompositeobject.h" + +/** + * class for clipped_by povray statements + */ + +class PMClippedBy : public PMCompositeObject +{ + typedef PMCompositeObject Base; +public: + /** + * Creates an empty PMClippedBy + */ + PMClippedBy( PMPart* part ); + /** + * Deletes the object + */ + ~PMClippedBy( ); + + /** */ + virtual PMObject* copy( ) const { return new PMClippedBy( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual bool dataChangeOnInsertRemove( ) const { return true; } + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMClippedByEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmclippedby" ); } + + /** */ + virtual void childRemoved( PMObject* ); + /** */ + virtual void childAdded( PMObject* ); + + /** + * Returns true if the object contains no child objects (except comments) + */ + bool boundedBy( ) const; + +private: + enum PMClippedByMementoID { PMBoundedByID }; + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmclippedbyedit.cpp b/kpovmodeler/pmclippedbyedit.cpp new file mode 100644 index 00000000..18a9d4db --- /dev/null +++ b/kpovmodeler/pmclippedbyedit.cpp @@ -0,0 +1,65 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmclippedbyedit.h" +#include "pmclippedby.h" + +#include +#include +#include + +PMClippedByEdit::PMClippedByEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMClippedByEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + m_pChildLabel = new QLabel( i18n( "No child objects" ), this ); + topLayout( )->addWidget( m_pChildLabel ); + m_pBoundedByLabel = new QLabel( i18n( "(= bounded by)" ), this ); + topLayout( )->addWidget( m_pBoundedByLabel ); +} + +void PMClippedByEdit::displayObject( PMObject* o ) +{ + if( o->isA( "ClippedBy" ) ) + { + m_pDisplayedObject = ( PMClippedBy* ) o; + + if( m_pDisplayedObject->boundedBy( ) ) + { + m_pChildLabel->show( ); + m_pBoundedByLabel->show( ); + } + else + { + m_pChildLabel->hide( ); + m_pBoundedByLabel->hide( ); + } + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMClippedByEdit: Can't display object\n"; +} + +#include "pmclippedbyedit.moc" diff --git a/kpovmodeler/pmclippedbyedit.h b/kpovmodeler/pmclippedbyedit.h new file mode 100644 index 00000000..3dc0c38f --- /dev/null +++ b/kpovmodeler/pmclippedbyedit.h @@ -0,0 +1,59 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMCLIPPEDBYEDIT_H +#define PMCLIPPEDBYEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMClippedBy; +class QLabel; + +/** + * Dialog edit class for @ref PMClippedBy + */ +class PMClippedByEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMClippedByEdit with parent and name + */ + PMClippedByEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + +protected: + /** */ + virtual void createTopWidgets( ); + +private: + PMClippedBy* m_pDisplayedObject; + QLabel* m_pChildLabel; + QLabel* m_pBoundedByLabel; +}; + + +#endif diff --git a/kpovmodeler/pmcolor.cpp b/kpovmodeler/pmcolor.cpp new file mode 100644 index 00000000..0eb38b79 --- /dev/null +++ b/kpovmodeler/pmcolor.cpp @@ -0,0 +1,196 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmcolor.h" +#include "pmvector.h" +#include "pmmath.h" + +#include "pmdebug.h" + +#include +#include + +PMColor::PMColor( ) +{ + int i; + for( i = 0; i < 5; i++ ) + m_colorValue[i] = 0; +} + +PMColor::PMColor( const double red, const double green, const double blue, + const double filter, const double transmit ) +{ + m_colorValue[0] = red; + m_colorValue[1] = green; + m_colorValue[2] = blue; + m_colorValue[3] = filter; + m_colorValue[4] = transmit; +} + +PMColor::PMColor( const double red, const double green, const double blue ) +{ + m_colorValue[0] = red; + m_colorValue[1] = green; + m_colorValue[2] = blue; + m_colorValue[3] = 0; + m_colorValue[4] = 0; +} + +PMColor::PMColor( const PMVector& v ) +{ + int i; + if( v.size( ) != 5 ) + { + kdError( PMArea ) << "Vector has wrong size in PMColor::PMColor( const PMVector& v )\n"; + for( i = 0; i < 5; i++ ) + m_colorValue[i] = 0; + } + else + { + for( i = 0; i < 5; i++ ) + m_colorValue[i] = v[i]; + } +} + +PMColor::PMColor( const QColor& c ) +{ + m_colorValue[0] = c.red( ) / 255.0; + m_colorValue[1] = c.green( ) / 255.0; + m_colorValue[2] = c.blue( ) / 255.0; + m_colorValue[3] = 0.0; + m_colorValue[4] = 0.0; +} + +QColor PMColor::toQColor( ) const +{ + double r, g, b, max = 0; + r = red( ); + g = green( ); + b = blue( ); + + if( r < 0 ) r = 0; + if( g < 0 ) g = 0; + if( b < 0 ) b = 0; + + if( r > max ) + max = r; + if( g > max ) + max = g; + if( b > max ) + max = b; + if( max > 1 ) + { + r /= max; + g /= max; + b /= max; + } + return QColor( ( int ) ( r * 255 + 0.5 ), ( int ) ( g * 255 + 0.5 ), + ( int ) ( b * 255 + 0.5 ) ); +} + +QString PMColor::serialize( bool addColorKeyword ) const +{ + QString result; + QTextStream str( &result, IO_WriteOnly ); + + if( addColorKeyword ) + str << "color "; + + if( approxZero( m_colorValue[4] ) ) + { + if( approxZero( m_colorValue[3] ) ) + { + // rgb + str << "rgb <" << m_colorValue[0] << ", " << m_colorValue[1] << ", " + << m_colorValue[2] << '>'; + } + else + { + // rgbf + str << "rgbf <" << m_colorValue[0] << ", " << m_colorValue[1] << ", " + << m_colorValue[2] << ", " << m_colorValue[3] << '>'; + } + } + else + { + if( approxZero( m_colorValue[3] ) ) + { + // rgbt + str << "rgbt <" << m_colorValue[0] << ", " << m_colorValue[1] << ", " + << m_colorValue[2] << ", " << m_colorValue[4] << '>'; + } + else + { + // rgbft + str << "rgbft <" << m_colorValue[0] << ", " << m_colorValue[1] << ", " + << m_colorValue[2] << ", " << m_colorValue[3] + << ", " << m_colorValue[4] << '>'; + } + } + + return result; +} + +QString PMColor::serializeXML( ) const +{ + QString result; + QTextStream str( &result, IO_WriteOnly ); + int i; + + for( i = 0; i < 5; i++ ) + { + if( i != 0 ) + str << ' '; + str << m_colorValue[i]; + } + + return result; +} + +bool PMColor::operator!= ( const PMColor& c ) const +{ + return !( *this == c ); +} + +bool PMColor::operator== ( const PMColor& c ) const +{ + unsigned int i; + + for( i = 0; i < 5; i++ ) + if( c.m_colorValue[i] != m_colorValue[i] ) + return false; + return true; +} + +bool PMColor::loadXML( const QString& str ) +{ + QString tmp( str ); + QTextStream s( &tmp, IO_ReadOnly ); + QString val; + bool ok; + int i; + + for( i = 0; i < 5; i++ ) + { + s >> val; + m_colorValue[i] = val.toDouble( &ok ); + if( !ok ) + return false; + } + return true; +} diff --git a/kpovmodeler/pmcolor.h b/kpovmodeler/pmcolor.h new file mode 100644 index 00000000..7ae0eeab --- /dev/null +++ b/kpovmodeler/pmcolor.h @@ -0,0 +1,130 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMCOLOR_H +#define PMCOLOR_H + +#include +#include + +class PMVector; + +/** + * Class for povray colors (red, green, blue, filter and transmit amount) + */ +class PMColor +{ +public: + /** + * Creates a color with all values set to 0.0 + */ + PMColor( ); + /** + * Creates a color + */ + PMColor( const double red, const double green, const double blue, + const double filter, const double transmit ); + /** + * Creates a color with filter and transmit set to 0 + */ + PMColor( const double red, const double green, const double blue ); + /** + * Creates a color from a @ref PMVector. The vector has to be of size 5 + */ + PMColor( const PMVector& v ); + /** + * Creates a color from a @ref QColor object. + * filter and transmit are set to 0 + */ + PMColor( const QColor& c ); + + /** + * Sets the red value + */ + void setRed( double d ) { m_colorValue[0] = d; } + /** + * Returns the red value + */ + double red( ) const { return m_colorValue[0]; } + /** + * Sets the green value + */ + void setGreen( double d ) { m_colorValue[1] = d; } + /** + * Returns the green value + */ + double green( ) const { return m_colorValue[1]; } + /** + * Sets the blue value + */ + void setBlue( double d ) { m_colorValue[2] = d; } + /** + * Returns the red value + */ + double blue( ) const { return m_colorValue[2]; } + /** + * Sets the filter value + */ + void setFilter( double d ) { m_colorValue[3] = d; } + /** + * Returns the filter value + */ + double filter( ) const { return m_colorValue[3]; } + /** + * Sets the transmit value + */ + void setTransmit( double d ) { m_colorValue[4] = d; } + /** + * Returns the transmit value + */ + double transmit( ) const { return m_colorValue[4]; } + + /** + * Returns the rgb value as QColor + */ + QColor toQColor( ) const; + + /** + * Returns a string for serialization + */ + QString serialize( bool addColorKeyword = false ) const; + /** + * Returns a string for xml output + */ + QString serializeXML( ) const; + /** + * loads the color data from the xml string + */ + bool loadXML( const QString& str ); + + /** + * Returns true if the colors are equal*/ + bool operator== ( const PMColor& p ) const; + /** + * Returns false if the colors are equal + */ + bool operator!= ( const PMColor& p ) const; +private: + /** + * The color values. Index 0 is red, 1 green, 2 blue, 3 filter, 4 transmit + */ + double m_colorValue[5]; + +}; + +#endif diff --git a/kpovmodeler/pmcoloredit.cpp b/kpovmodeler/pmcoloredit.cpp new file mode 100644 index 00000000..06ac4d0f --- /dev/null +++ b/kpovmodeler/pmcoloredit.cpp @@ -0,0 +1,201 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmcoloredit.h" +#include "pmlineedits.h" +#include +#include +#include +#include +#include +#include + +PMColorEdit::PMColorEdit( bool filterAndTransmit, QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + m_bFilterAndTransmit = filterAndTransmit; + + m_edits[0] = new PMFloatEdit( this ); + m_edits[1] = new PMFloatEdit( this ); + m_edits[2] = new PMFloatEdit( this ); + if( filterAndTransmit ) + { + m_edits[3] = new PMFloatEdit( this ); + m_edits[4] = new PMFloatEdit( this ); + } + else + { + m_edits[3] = 0; + m_edits[4] = 0; + } + m_pButton = new KColorButton( this ); + + QVBoxLayout* topLayout = new QVBoxLayout( this, 0, KDialog::spacingHint( ) ); + QHBoxLayout* l = new QHBoxLayout( topLayout ); + l->addWidget( m_pButton ); + l = new QHBoxLayout( topLayout ); + l->addWidget( new QLabel( i18n( "red:" ), this ) ); + l->addWidget( m_edits[0] ); + l->addWidget( new QLabel( i18n( "green:" ), this ) ); + l->addWidget( m_edits[1] ); + l->addWidget( new QLabel( i18n( "blue:" ), this ) ); + l->addWidget( m_edits[2] ); + if( filterAndTransmit ) + { + l = new QHBoxLayout( topLayout ); + l->addWidget( new QLabel( i18n( "filter" ), this ) ); + l->addWidget( m_edits[3] ); + l->addWidget( new QLabel( i18n( "transmit" ), this ) ); + l->addWidget( m_edits[4] ); + } + + connect( m_edits[0], SIGNAL( dataChanged( ) ), SLOT( slotEditChanged( ) ) ); + connect( m_edits[1], SIGNAL( dataChanged( ) ), SLOT( slotEditChanged( ) ) ); + connect( m_edits[2], SIGNAL( dataChanged( ) ), SLOT( slotEditChanged( ) ) ); + if( filterAndTransmit ) + { + connect( m_edits[3], SIGNAL( dataChanged( ) ), SLOT( slotEditChanged( ) ) ); + connect( m_edits[4], SIGNAL( dataChanged( ) ), SLOT( slotEditChanged( ) ) ); + } + connect( m_pButton, SIGNAL( changed( const QColor& ) ), + SLOT( slotColorChanged( const QColor& ) ) ); +} + +void PMColorEdit::setColor( const PMColor& c ) +{ + bool blocked[5]; + int i; + int num = m_bFilterAndTransmit ? 5 : 3; + + for( i = 0; i < num; i++ ) + { + blocked[i] = m_edits[i]->signalsBlocked( ); + m_edits[i]->blockSignals( true ); + } + + m_color = c; + m_edits[0]->setValue( c.red( ) ); + m_edits[1]->setValue( c.green( ) ); + m_edits[2]->setValue( c.blue( ) ); + if( m_bFilterAndTransmit ) + { + m_edits[3]->setValue( c.filter( ) ); + m_edits[4]->setValue( c.transmit( ) ); + } + updateButton( ); + + for( i = 0; i < num; i++ ) + m_edits[i]->blockSignals( blocked[i] ); +} + +void PMColorEdit::updateButton( ) +{ + bool b = m_pButton->signalsBlocked( ); + m_pButton->blockSignals( true ); + m_pButton->setColor( m_color.toQColor( ) ); + m_pButton->blockSignals( b ); +} + +bool PMColorEdit::isDataValid( ) +{ + if( !m_edits[0]->isDataValid( ) ) + return false; + if( !m_edits[1]->isDataValid( ) ) + return false; + if( !m_edits[2]->isDataValid( ) ) + return false; + if( m_bFilterAndTransmit ) + { + if( !m_edits[3]->isDataValid( ) ) + return false; + if( !m_edits[4]->isDataValid( ) ) + return false; + } + return true; +} + +void PMColorEdit::setReadOnly( bool yes ) +{ + m_edits[0]->setReadOnly( yes ); + m_edits[1]->setReadOnly( yes ); + m_edits[2]->setReadOnly( yes ); + if( m_bFilterAndTransmit ) + { + m_edits[3]->setReadOnly( yes ); + m_edits[4]->setReadOnly( yes ); + } + m_pButton->setEnabled( !yes ); +} + +void PMColorEdit::slotColorChanged( const QColor& c ) +{ + int i; + bool blocked[3]; + + for( i = 0; i < 3; i++ ) + { + blocked[i] = m_edits[i]->signalsBlocked( ); + m_edits[i]->blockSignals( true ); + } + + m_color.setRed( c.red( ) / 255.0 ); + m_color.setGreen( c.green( ) / 255.0 ); + m_color.setBlue( c.blue( ) / 255.0 ); + + m_edits[0]->setValue( m_color.red( ) ); + m_edits[1]->setValue( m_color.green( ) ); + m_edits[2]->setValue( m_color.blue( ) ); + + for( i = 0; i < 3; i++ ) + m_edits[i]->blockSignals( blocked[i] ); + + emit dataChanged( ); +} + +void PMColorEdit::slotEditChanged( ) +{ + bool ok; + + m_edits[0]->text( ).toDouble( &ok ); + if( ok ) + m_edits[1]->text( ).toDouble( &ok ); + if( ok ) + m_edits[2]->text( ).toDouble( &ok ); + if( m_bFilterAndTransmit ) + { + if( ok ) + m_edits[3]->text( ).toDouble( &ok ); + if( ok ) + m_edits[4]->text( ).toDouble( &ok ); + } + + if( ok ) + { + m_color.setRed( m_edits[0]->value( ) ); + m_color.setGreen( m_edits[1]->value( ) ); + m_color.setBlue( m_edits[2]->value( ) ); + if( m_bFilterAndTransmit ) + { + m_color.setFilter( m_edits[3]->value( ) ); + m_color.setTransmit( m_edits[4]->value( ) ); + } + updateButton( ); + } + emit dataChanged( ); +} + +#include "pmcoloredit.moc" diff --git a/kpovmodeler/pmcoloredit.h b/kpovmodeler/pmcoloredit.h new file mode 100644 index 00000000..4b581a0f --- /dev/null +++ b/kpovmodeler/pmcoloredit.h @@ -0,0 +1,83 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMCOLOREDIT_H +#define PMCOLOREDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include "pmcolor.h" + +class KColorButton; +class PMFloatEdit; +class QColor; + +/** + * Edit widget for @ref PMColor + */ +class PMColorEdit : public QWidget +{ + Q_OBJECT +public: + /** + * Creates an edit widget for rgbft colors. + */ + PMColorEdit( bool filterAndTransmit, QWidget* parent, const char* name = 0 ); + + /** + * Sets the displayed color + */ + void setColor( const PMColor& c ); + /** + * Returns the color + */ + PMColor color( ) const { return m_color; } + + /** + * Returns true if the input is a valid + * color value. Otherwise an error message is shown. + */ + bool isDataValid( ); + + /** + * Enables or disables read only mode + */ + void setReadOnly( bool yes = true ); +signals: + /** + * Emitted when the color is changed + */ + void dataChanged( ); + +protected slots: + void slotColorChanged( const QColor& c ); + void slotEditChanged( ); +private: + void updateButton( ); +private: + PMFloatEdit* m_edits[5]; + KColorButton* m_pButton; + bool m_bFilterAndTransmit; + PMColor m_color; +}; + +#endif diff --git a/kpovmodeler/pmcolorsettings.cpp b/kpovmodeler/pmcolorsettings.cpp new file mode 100644 index 00000000..d5924d4b --- /dev/null +++ b/kpovmodeler/pmcolorsettings.cpp @@ -0,0 +1,163 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmcolorsettings.h" + +#include "pmrendermanager.h" +#include "pmdefaults.h" + +#include +#include +#include +#include + +PMColorSettings::PMColorSettings( QWidget* parent, const char* name ) + : PMSettingsDialogPage( parent, name ) +{ + QHBoxLayout* hlayout; + QVBoxLayout* vlayout; + QGridLayout* grid; + + vlayout = new QVBoxLayout( this, 0, KDialog::spacingHint( ) ); + grid = new QGridLayout( vlayout, 6, 3 ); + + grid->addWidget( new QLabel( i18n( "Background:" ), this ), 0, 0 ); + hlayout = new QHBoxLayout( ); + grid->addLayout( hlayout, 0, 2 ); + m_pBackgroundColor = new KColorButton( this ); + hlayout->addWidget( m_pBackgroundColor ); + hlayout->addStretch( 1 ); + + grid->addWidget( new QLabel( i18n( "Wire frame:" ), this ), 1, 0 ); + hlayout = new QHBoxLayout( ); + grid->addLayout( hlayout, 1, 2 ); + m_pGraphicalObjectsColor[0] = new KColorButton( this ); + hlayout->addWidget( m_pGraphicalObjectsColor[0] ); + hlayout->addWidget( new QLabel( i18n( "Selected:" ), this ) ); + m_pGraphicalObjectsColor[1] = new KColorButton( this ); + hlayout->addWidget( m_pGraphicalObjectsColor[1] ); + hlayout->addStretch( 1 ); + + grid->addWidget( new QLabel( i18n( "Control points:" ), this ), 2, 0 ); + hlayout = new QHBoxLayout( ); + grid->addLayout( hlayout, 2, 2 ); + m_pControlPointsColor[0] = new KColorButton( this ); + hlayout->addWidget( m_pControlPointsColor[0] ); + hlayout->addWidget( new QLabel( i18n( "Selected:" ), this ) ); + m_pControlPointsColor[1] = new KColorButton( this ); + hlayout->addWidget( m_pControlPointsColor[1] ); + hlayout->addStretch( 1 ); + + grid->addWidget( new QLabel( i18n( "Axes:" ), this ), 3, 0 ); + hlayout = new QHBoxLayout( ); + grid->addLayout( hlayout, 3, 2 ); + grid->addWidget( new QLabel( "x", this ), 3, 1 ); + m_pAxesColor[0] = new KColorButton( this ); + hlayout->addWidget( m_pAxesColor[0] ); + hlayout->addWidget( new QLabel( "y", this ) ); + m_pAxesColor[1] = new KColorButton( this ); + hlayout->addWidget( m_pAxesColor[1] ); + hlayout->addWidget( new QLabel( "z", this ) ); + m_pAxesColor[2] = new KColorButton( this ); + hlayout->addWidget( m_pAxesColor[2] ); + hlayout->addStretch( 1 ); + + grid->addWidget( new QLabel( i18n( "Field of view:" ), this ), 4, 0 ); + hlayout = new QHBoxLayout( ); + grid->addLayout( hlayout, 4, 2 ); + m_pFieldOfViewColor = new KColorButton( this ); + hlayout->addWidget( m_pFieldOfViewColor ); + hlayout->addStretch( 1 ); +} + +void PMColorSettings::displaySettings( ) +{ + PMRenderManager* rm = PMRenderManager::theManager( ); + m_pBackgroundColor->setColor( rm->backgroundColor( ) ); + m_pGraphicalObjectsColor[0]->setColor( rm->graphicalObjectColor( 0 ) ); + m_pGraphicalObjectsColor[1]->setColor( rm->graphicalObjectColor( 1 ) ); + m_pControlPointsColor[0]->setColor( rm->controlPointColor( 0 ) ); + m_pControlPointsColor[1]->setColor( rm->controlPointColor( 1 ) ); + m_pAxesColor[0]->setColor( rm->axesColor( 0 ) ); + m_pAxesColor[1]->setColor( rm->axesColor( 1 ) ); + m_pAxesColor[2]->setColor( rm->axesColor( 2 ) ); + m_pFieldOfViewColor->setColor( rm->fieldOfViewColor( ) ); +} + +void PMColorSettings::displayDefaults( ) +{ + m_pBackgroundColor->setColor( c_defaultBackgroundColor ); + m_pGraphicalObjectsColor[0]->setColor( c_defaultGraphicalObjectColor0 ); + m_pGraphicalObjectsColor[1]->setColor( c_defaultGraphicalObjectColor1 ); + m_pControlPointsColor[0]->setColor( c_defaultControlPointColor0 ); + m_pControlPointsColor[1]->setColor( c_defaultControlPointColor1 ); + m_pAxesColor[0]->setColor( c_defaultAxesColorX ); + m_pAxesColor[1]->setColor( c_defaultAxesColorY ); + m_pAxesColor[2]->setColor( c_defaultAxesColorZ ); + m_pFieldOfViewColor->setColor( c_defaultFieldOfViewColor ); +} + +bool PMColorSettings::validateData( ) +{ + return true; +} + +void PMColorSettings::applySettings( ) +{ + bool repaint = false; + int i; + + PMRenderManager* rm = PMRenderManager::theManager( ); + if( rm->backgroundColor( ) != m_pBackgroundColor->color( ) ) + { + rm->setBackgroundColor( m_pBackgroundColor->color( ) ); + repaint = true; + } + for( i = 0; i < 2; i++ ) + { + if( rm->graphicalObjectColor( i ) != m_pGraphicalObjectsColor[i]->color( ) ) + { + rm->setGraphicalObjectColor( i, m_pGraphicalObjectsColor[i]->color( ) ); + repaint = true; + } + } + for( i = 0; i < 2; i++ ) + { + if( rm->controlPointColor( i ) != m_pControlPointsColor[i]->color( ) ) + { + rm->setControlPointColor( i, m_pControlPointsColor[i]->color( ) ); + repaint = true; + } + } + for( i = 0; i < 3; i++ ) + { + if( rm->axesColor( i ) != m_pAxesColor[i]->color( ) ) + { + rm->setAxesColor( i, m_pAxesColor[i]->color( ) ); + repaint = true; + } + } + if( rm->fieldOfViewColor( ) != m_pFieldOfViewColor->color( ) ) + { + rm->setFieldOfViewColor( m_pFieldOfViewColor->color( ) ); + repaint = true; + } + if( repaint ) + emit repaintViews( ); +} + +#include "pmcolorsettings.moc" diff --git a/kpovmodeler/pmcolorsettings.h b/kpovmodeler/pmcolorsettings.h new file mode 100644 index 00000000..9ad628e0 --- /dev/null +++ b/kpovmodeler/pmcolorsettings.h @@ -0,0 +1,58 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMCOLORSETTINGS_H +#define PMCOLORSETTINGS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsettingsdialog.h" + +class KColorButton; + +/** + * Colors configuration dialog page + */ +class PMColorSettings : public PMSettingsDialogPage +{ + Q_OBJECT +public: + /** + * Default constructor + */ + PMColorSettings( QWidget* parent, const char* name = 0 ); + /** */ + virtual void displaySettings( ); + /** */ + virtual bool validateData( ); + /** */ + virtual void applySettings( ); + /** */ + virtual void displayDefaults( ); + +private: + KColorButton* m_pBackgroundColor; + KColorButton* m_pGraphicalObjectsColor[2]; + KColorButton* m_pControlPointsColor[2]; + KColorButton* m_pAxesColor[3]; + KColorButton* m_pFieldOfViewColor; +}; + + +#endif diff --git a/kpovmodeler/pmcommand.h b/kpovmodeler/pmcommand.h new file mode 100644 index 00000000..9bdca16f --- /dev/null +++ b/kpovmodeler/pmcommand.h @@ -0,0 +1,146 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMCOMMAND_H +#define PMCOMMAND_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "pmmessage.h" +#include "pmerrorflags.h" + +class PMCommandManager; +class PMObject; +class PMPart; + +/** + * Constants for object changes + * + * PMCAdd: An object was added + * + * PMCRemove: An object was removed. A signal with this constant has + * to be emitted _before_ the object is removed. + * + * PMCChildren: Some children are added or removed. Do not use. Use PMCAdd and + * PMCRemove for all childrens. + * + * PMCData: Data (for dialog views) is changed + * + * PMCDescription: The name or pixmap of the object has changed. Always + * together with PMCData. + * + * PMCViewStructure: The rendering has changed + * + * PMCNewSelection: The object was selected and all other deleselected. + * If the changed object is 0, all objects are deselected! + * + * PMCSelected: The object was selected. + * + * PMCDeselected: The object was deselected. + * + * PMCNewControlPoints: The list of control points has changed. + * + * PMCControlPointSelection: The control point selection has changed. + * + * PMCInsertError: The added object couldn't be inserted and was appended + * to the insert errors. Always together with PMCAdd. + * + * PMCNothing: Nothing was changed + */ +enum PMChange +{ + PMCNothing = 0, PMCAdd = 1, PMCRemove = 2, PMCChildren = 4, + PMCData = 8, PMCDescription = 16, PMCViewStructure = 32, + PMCGraphicalChange = 64, + PMCNewSelection = 128, PMCSelected = 256, + PMCDeselected = 512, + PMCNewControlPoints = 1024, PMCControlPointSelection = 2048, + PMCInsertError = 4096 +}; + +/** + * Base class for all commands, that support undo/redo. + */ +class PMCommand +{ + friend class PMCommandManager; // only PMCommandManager can execute commands +public: + /** + * Creates an empty command object. + */ + PMCommand( ) { } + /** + * Creates a command with command text text + */ + PMCommand( const QString &text ) + { m_text = text; } + /** + * Deletes the command. + */ + virtual ~PMCommand( ) { } + + /** + * Command text shown in the undo/redo menues + */ + QString text( ) const { return m_text; } + /** + * Sets the command text + */ + void setText( const QString& s ) { m_text = s; } + + /** + * Checks if the command is valid and sets the error message + * + * Returns a bitwise combination of @ref PMErrorFlags flags + */ + virtual int errorFlags( PMPart* ) { return PMENone; } + /** + * Returns the error message + */ + PMMessageList messages( ) { return m_errors; } + +protected: + /** + * Executes the command and stores undo information. + */ + virtual void execute( PMCommandManager* theManager ) = 0; + /** + * Undoes the command + */ + virtual void undo( PMCommandManager* theManager ) = 0; + /** + * The error messages + */ + PMMessageList m_errors; + +private: + /** + * The command text. + */ + QString m_text; +}; + +typedef QPtrList PMCommandList; + +#endif diff --git a/kpovmodeler/pmcommandmanager.cpp b/kpovmodeler/pmcommandmanager.cpp new file mode 100644 index 00000000..333468e3 --- /dev/null +++ b/kpovmodeler/pmcommandmanager.cpp @@ -0,0 +1,99 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmcommandmanager.h" +#include "pmpart.h" + +PMCommandManager::PMCommandManager( PMPart* thePart ) +{ + m_commands.setAutoDelete( true ); + m_redoCommands.setAutoDelete( true ); + m_maxUndoRedo = 50; + m_pPart = thePart; +} + +PMCommandManager::~PMCommandManager( ) +{ + m_commands.clear( ); + m_redoCommands.clear( ); +} + +void PMCommandManager::execute( PMCommand* cmd ) +{ + // some commands (like control point commands) can be executed + // multiple times. + cmd->execute( this ); + + if( m_commands.last( ) != cmd ) + m_commands.append( cmd ); + while( m_commands.count( ) > m_maxUndoRedo ) + m_commands.removeFirst( ); + m_redoCommands.clear( ); + + emit updateUndoRedo( cmd->text( ), QString::null ); +} + +void PMCommandManager::undo( ) +{ + if( !m_commands.isEmpty( ) ) + { + PMCommand* last = m_commands.last( ); + last->undo( this ); + + m_redoCommands.append( m_commands.take( ) ); + + if( m_commands.isEmpty( ) ) + emit updateUndoRedo( QString::null, last->text( ) ); + else + emit updateUndoRedo( m_commands.last( )->text( ), last->text( ) ); + } +} + +void PMCommandManager::redo( ) +{ + if( !m_redoCommands.isEmpty( ) ) + { + PMCommand* last = m_redoCommands.last( ); + last->execute( this ); + + m_commands.append( m_redoCommands.take( ) ); + + if( m_redoCommands.isEmpty( ) ) + emit updateUndoRedo( last->text( ), QString::null ); + else + emit updateUndoRedo( last->text( ), m_redoCommands.last( )->text( ) ); + } +} + +void PMCommandManager::clear( ) +{ + m_redoCommands.clear( ); + m_commands.clear( ); + emit updateUndoRedo( QString::null, QString::null ); +} + +void PMCommandManager::cmdObjectChanged( PMObject* obj, const int mode ) +{ + emit objectChanged( obj, mode, this ); +} + +void PMCommandManager::cmdIDChanged( PMObject* obj, const QString& oldID ) +{ + emit idChanged( obj, oldID ); +} +#include "pmcommandmanager.moc" diff --git a/kpovmodeler/pmcommandmanager.h b/kpovmodeler/pmcommandmanager.h new file mode 100644 index 00000000..2ef2fbbc --- /dev/null +++ b/kpovmodeler/pmcommandmanager.h @@ -0,0 +1,118 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMCOMMANDMANAGER_H +#define PMCOMMANDMANAGER_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmcommand.h" +#include +#include + +class PMPart; + +/** + * Manager for PMCommand objects. + * + * The class PMCommandManager stores stacks of commands for undo/redo + * operations. + */ +class PMCommandManager : public QObject +{ + Q_OBJECT +public: + /** + * Creates a new PMCommandManager + */ + PMCommandManager( PMPart* thepart ); + /** + * Deletes the command manager. All commands are deleted as well. + */ + ~PMCommandManager( ); + /** + * Adds the @ref PMCommand to the command stack. + * All commands in the m_redoCommands stack are deleted. + */ + void execute( PMCommand* cmd ); + /** + * Moves the last command to the m_redoCommands stack. + */ + void undo( ); + /** + * Moves the last redo command to the command stack. + */ + void redo( ); + /** + * Deletes the commands + */ + void clear( ); + /** + * Returns the maximal number of items that can be undone/redone. + */ + unsigned int maxUndoRedo( ) const { return m_maxUndoRedo; } + /** + * Sets the maximal number of items that can be undone/redone. + */ + void setMaxUndoRedo( unsigned int n ) { m_maxUndoRedo = n; } + /** + * Called by an executed command. Will emit objectChanged( ) + */ + void cmdObjectChanged( PMObject* obj, const int mode ); + /** + * Called by an executed command. Will emit idChanged( ) + */ + void cmdIDChanged( PMObject* obj, const QString& oldID ); + /** + * Returns a pointer to the part. For commands that need to access the + * part directly. + */ + PMPart* part( ) const { return m_pPart; } +signals: + /** + * emmited, when the undo and redo command texts change + */ + void updateUndoRedo( const QString& undo, const QString& redo ); + /** + * Signal that is emitted when an object is changed. + * Mode is a bit combination of @ref PMChange constants. + */ + void objectChanged( PMObject* obj, const int mode, QObject* sender ); + /** + * Signal that is emitted when the id of the object is changed + */ + void idChanged( PMObject* obj, const QString& oldID ); +private: + /** + * The executed commands. + */ + PMCommandList m_commands; + /** + * The undone commands. + */ + PMCommandList m_redoCommands; + // the maximal number of items that can be undone/redone. + unsigned int m_maxUndoRedo; + PMObject* m_pLastChangedObject; + PMPart* m_pPart; +}; + +#endif diff --git a/kpovmodeler/pmcomment.cpp b/kpovmodeler/pmcomment.cpp new file mode 100644 index 00000000..e4783ae5 --- /dev/null +++ b/kpovmodeler/pmcomment.cpp @@ -0,0 +1,174 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmcomment.h" +#include "pmxmlhelper.h" + +#include "pmcommentedit.h" +#include "pmmemento.h" + +#include +#include + +PMDefinePropertyClass( PMComment, PMCommentProperty ); + +PMMetaObject* PMComment::s_pMetaObject = 0; +PMObject* createNewComment( PMPart* part ) +{ + return new PMComment( part ); +} + +const unsigned int c_maxDescriptionLength = 25; + +PMComment::PMComment( PMPart* part ) + : Base( part ) +{ +} + +PMComment::PMComment( PMPart* part, const QString& t ) + : Base( part ) +{ + m_text = t; +} + +PMComment::PMComment( const PMComment& c ) + : Base( c ) +{ + m_text = c.m_text; +} + +PMComment::~PMComment( ) +{ +} + +QString PMComment::description( ) const +{ + if( !m_text.isEmpty( ) ) + { + QString copy = m_text; + QTextStream str( ©, IO_ReadOnly ); + QString tmp, desc; + bool stop = false; + bool truncated = false; + + while( !str.atEnd( ) && !stop ) + { + str >> tmp; + if( desc.length( ) + tmp.length( ) + 1 <= c_maxDescriptionLength ) + { + if( !desc.isEmpty( ) ) + desc += " "; + desc += tmp; + } + else + { + if( desc.isEmpty( ) ) + { + desc = tmp.left( c_maxDescriptionLength ); + if( tmp.length( ) > c_maxDescriptionLength ) + truncated = true; + } + else + truncated = true; + stop = true; + } + } + if( truncated ) + desc += "..."; + return desc; + } + return i18n( "comment" ); +} + +void PMComment::setText( const QString& text ) +{ + if( text != m_text ) + { + if( m_pMemento ) + { + m_pMemento->addData( s_pMetaObject, PMTextID, m_text ); + m_pMemento->setDescriptionChanged( ); + } + m_text = text; + } +} + +PMMetaObject* PMComment::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Comment", Base::metaObject( ), + createNewComment ); + s_pMetaObject->addProperty( + new PMCommentProperty( "text", &PMComment::setText, &PMComment::text ) ); + } + return s_pMetaObject; +} + +void PMComment::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMComment::serialize( QDomElement& e, QDomDocument& doc ) const +{ + QDomText t = doc.createTextNode( m_text ); + e.appendChild( t ); +} + +void PMComment::readAttributes( const PMXMLHelper& h ) +{ + QDomNode e = h.element( ).firstChild( ); + if( e.isText( ) ) + m_text = e.toText( ).data( ); +} + +PMDialogEditBase* PMComment::editWidget( QWidget* parent ) const +{ + return new PMCommentEdit( parent ); +} + +void PMComment::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMTextID: + setText( data->stringData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMComment::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + diff --git a/kpovmodeler/pmcomment.h b/kpovmodeler/pmcomment.h new file mode 100644 index 00000000..82c62fa8 --- /dev/null +++ b/kpovmodeler/pmcomment.h @@ -0,0 +1,92 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMCOMMENT_H +#define PMCOMMENT_H + +#include "pmobject.h" +#include + + +/** + * Class for povray comments + */ + +class PMComment : public PMObject +{ + typedef PMObject Base; +public: + /** + * Creates an enpty comment + */ + PMComment( PMPart* part ); + /** + * Creates a comment with text t + */ + PMComment( PMPart* part, const QString& t ); + /** + * Copy constructor + */ + PMComment( const PMComment& c ); + /** + * Deletes the comment + */ + ~PMComment( ); + + /** + * Sets the comment text + */ + void setText( const QString& text ); + /** + * Returns the comment text + */ + QString text( ) const { return m_text; } + + /** */ + virtual PMObject* copy( ) const { return new PMComment( *this ); } + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual QString description( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pmcomment" ); } + /** */ + virtual void restoreMemento( PMMemento* s ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMCommentMementoID { PMTextID }; + QString m_text; + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmcommentedit.cpp b/kpovmodeler/pmcommentedit.cpp new file mode 100644 index 00000000..6fa5ba9e --- /dev/null +++ b/kpovmodeler/pmcommentedit.cpp @@ -0,0 +1,75 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmcommentedit.h" +#include "pmcomment.h" + +#include +#include +#include + +PMCommentEdit::PMCommentEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMCommentEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + m_pEdit = new QMultiLineEdit( this ); +#if ( QT_VERSION >= 300 ) + m_pEdit->setTextFormat( Qt::PlainText ); + m_pEdit->setWordWrap( QTextEdit::NoWrap ); +#endif + m_pEdit->setFont( KGlobalSettings::fixedFont( ) ); + topLayout( )->addWidget( m_pEdit, 2 ); + + connect( m_pEdit, SIGNAL( textChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMCommentEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Comment" ) ) + { + m_pDisplayedObject = ( PMComment* ) o; + m_pEdit->setText( m_pDisplayedObject->text( ) ); + + m_pEdit->setReadOnly( o->isReadOnly( ) ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMCommentEdit: Can't display object\n"; +} + +void PMCommentEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setText( m_pEdit->text( ) ); + } +} + +bool PMCommentEdit::isDataValid( ) +{ + return Base::isDataValid( ); +} +#include "pmcommentedit.moc" diff --git a/kpovmodeler/pmcommentedit.h b/kpovmodeler/pmcommentedit.h new file mode 100644 index 00000000..b3dc1d25 --- /dev/null +++ b/kpovmodeler/pmcommentedit.h @@ -0,0 +1,62 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMCOMMENTEDIT_H +#define PMCOMMENTEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMComment; +class QMultiLineEdit; + +/** + * Dialog edit class for @ref PMComment. + */ +class PMCommentEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMCommentEdit with parent and name + */ + PMCommentEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMComment* m_pDisplayedObject; + QMultiLineEdit* m_pEdit; +}; + + +#endif diff --git a/kpovmodeler/pmcompositeobject.cpp b/kpovmodeler/pmcompositeobject.cpp new file mode 100644 index 00000000..c1ab704d --- /dev/null +++ b/kpovmodeler/pmcompositeobject.cpp @@ -0,0 +1,396 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmcompositeobject.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmviewstructure.h" + +#include + +PMMetaObject* PMCompositeObject::s_pMetaObject = 0; + +PMCompositeObject::PMCompositeObject( PMPart* part ) + : Base( part ) +{ + m_pFirstChild = 0; + m_pLastChild = 0; + m_selectedChildren = 0; + m_bViewStructureChanged = true; + m_pViewStructure = 0; +} + +PMCompositeObject::PMCompositeObject( const PMCompositeObject& c ) + : Base( c ) +{ + m_pFirstChild = 0; + m_pLastChild = 0; + m_selectedChildren = 0; + m_bViewStructureChanged = true; + m_pViewStructure = 0; + + PMObject* o = c.m_pFirstChild; + for( ; o; o = o->nextSibling( ) ) + appendChild( o->copy( ) ); +} + +PMCompositeObject::~PMCompositeObject( ) +{ + PMObject* tmp; + PMObject* next; + + tmp = m_pFirstChild; + + while( tmp ) + { + next = tmp->m_pNextSibling; + delete tmp; + tmp = next; + } + + if( m_pViewStructure ) + delete m_pViewStructure; +} + +PMMetaObject* PMCompositeObject::metaObject( ) const +{ + if( !s_pMetaObject ) + s_pMetaObject = new PMMetaObject( "CompositeObject", Base::metaObject( ) ); + return s_pMetaObject; +} + +void PMCompositeObject::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +PMObject* PMCompositeObject::childAt( uint index ) const +{ + PMObject* tmp; + uint i = 0; + + for( tmp = m_pFirstChild; tmp && ( i < index ); tmp = tmp->nextSibling( ) ) + i++; + return tmp; +} + +int PMCompositeObject::findChild( PMObject* o ) +{ + if( o->parent( ) != this ) + return -1; + + PMObject* tmp; + int index = 0; + + for( tmp = m_pFirstChild; tmp; tmp = tmp->nextSibling( ) ) + { + if( tmp == o ) + return index; + else + index++; + } + return -1; +} + +bool PMCompositeObject::insertChild( PMObject* o, int i ) +{ + if( i < 0 ) + return appendChild( o ); + else + { + if( i == 0 ) + { + if( canInsert( o, 0 ) ) + { + o->m_pNextSibling = m_pFirstChild; + o->m_pPrevSibling = 0; + if( m_pFirstChild ) + m_pFirstChild->m_pPrevSibling = o; + m_pFirstChild = o; + if( !m_pLastChild ) + m_pLastChild = o; + o->m_pParent = this; + } + else + return false; + } + else + { + PMObject* tmp = childAt( ( uint ) ( i - 1 ) ); + if( !tmp ) + { + kdError( PMArea ) << "Index too big" << "\n"; + return false; + } + + if( canInsert( o, tmp ) ) + { + o->m_pPrevSibling = tmp; + o->m_pNextSibling = tmp->m_pNextSibling; + if( tmp->m_pNextSibling ) + tmp->m_pNextSibling->m_pPrevSibling = o; + else + m_pLastChild = o; + tmp->m_pNextSibling = o; + o->m_pParent = this; + } + else + return false; + } + childAdded( o ); + return true; + } + return false; +} + +bool PMCompositeObject::appendChild( PMObject* o ) +{ + if( canInsert( o, m_pLastChild ) ) + { + o->m_pParent = this; + o->m_pPrevSibling = m_pLastChild; + o->m_pNextSibling = 0; + if( m_pLastChild ) + m_pLastChild->m_pNextSibling = o; + else + m_pFirstChild = o; + m_pLastChild = o; + + childAdded( o ); + return true; + } + return false; +} + +bool PMCompositeObject::insertChildAfter( PMObject* obj, PMObject* after ) +{ + if( canInsert( obj, after ) ) + { + if( after->m_pParent == this ) + { + obj->m_pParent = this; + obj->m_pPrevSibling = after; + obj->m_pNextSibling = after->m_pNextSibling; + if( after->m_pNextSibling ) + after->m_pNextSibling->m_pPrevSibling = obj; + else + m_pLastChild = obj; + after->m_pNextSibling = obj; + + childAdded( obj ); + return true; + } + else + { + kdError( PMArea ) << "Object after is no child" << "\n"; + return false; + } + } + return false; +} + +bool PMCompositeObject::insertChildBefore( PMObject* obj, PMObject* before ) +{ + if( before ) + { + if( canInsert( obj, before->m_pPrevSibling ) ) + { + if( before->m_pParent == this ) + { + obj->m_pParent = this; + obj->m_pPrevSibling = before->m_pPrevSibling; + obj->m_pNextSibling = before; + if( before->m_pPrevSibling ) + before->m_pPrevSibling->m_pNextSibling = obj; + else + m_pFirstChild = obj; + before->m_pPrevSibling = obj; + + childAdded( obj ); + return true; + } + else + { + kdError( PMArea ) << "Object before is no child" << "\n"; + return false; + } + } + } + return false; +} + +bool PMCompositeObject::takeChild( PMObject* o ) +{ + if( ( PMObject* ) this == o->m_pParent ) + { + // deselect the object and all child objects of o + if( o->isSelected( ) ) + o->setSelected( false ); + else if( o->selectedChildren( ) > 0 ) + o->deselectChildren( ); + + // remove it, but do NOT delete it. + if( o->m_pPrevSibling ) + o->m_pPrevSibling->m_pNextSibling = o->m_pNextSibling; + else + m_pFirstChild = o->m_pNextSibling; + if( o->m_pNextSibling ) + o->m_pNextSibling->m_pPrevSibling = o->m_pPrevSibling; + else + m_pLastChild = o->m_pPrevSibling; + + o->m_pParent = 0; + o->m_pPrevSibling = 0; + o->m_pNextSibling = 0; + + childRemoved( o ); + return true; + } + kdError( PMArea ) << "o is no child" << "\n"; + return false; +} + +bool PMCompositeObject::takeChild( uint i ) +{ + PMObject* tmp = childAt( i ); + if( tmp ) + return takeChild( tmp ); + kdError( PMArea ) << "Index too big"; + return false; +} + +void PMCompositeObject::serialize( QDomElement& e, QDomDocument& doc ) const +{ + PMObject* tmp; + + for( tmp = m_pFirstChild; tmp; tmp = tmp->m_pNextSibling ) + e.appendChild( tmp->serialize( doc ) ); +} + +int PMCompositeObject::countChildren( ) const +{ + int num = 0; + PMObject* tmp; + + for( tmp = m_pFirstChild; tmp; tmp = tmp->m_pNextSibling ) + num++; + return num; +} + +void PMCompositeObject::adjustSelectedChildren( int num ) +{ + m_selectedChildren += num; + if( m_selectedChildren < 0 ) + { + kdError( PMArea ) << "num too big in PMCompositeObject::adjustSelectedChildren( )\n"; + m_selectedChildren = 0; + } + if( m_pParent ) + m_pParent->adjustSelectedChildren( num ); +} + +void PMCompositeObject::deselectChildren( ) +{ + PMObject* tmp; + if( m_selectedChildren > 0 ) + { + tmp = m_pFirstChild; + while( tmp && ( m_selectedChildren > 0 ) ) + { + if( tmp->isSelected( ) ) + tmp->setSelected( false ); + else if( tmp->selectedChildren( ) > 0 ) + tmp->deselectChildren( ); + + tmp = tmp->m_pNextSibling; + } + } +} + + +PMViewStructure* PMCompositeObject::viewStructure( ) +{ + if( m_pViewStructure ) + { + if( m_pViewStructure->parameterKey( ) != viewStructureParameterKey( ) ) + { + // the default view structure or the parameters (detail level) + // have changed + m_bViewStructureChanged = true; + delete m_pViewStructure; + m_pViewStructure = 0; + } + } + + if( m_bViewStructureChanged ) + { + PMViewStructure* dvs = defaultViewStructure( ); + if( dvs ) + if( dvs->parameterKey( ) == -1 ) // newly created view structure + dvs->setParameterKey( viewStructureParameterKey( ) ); + + if( isDefault( ) ) + { + if( dvs ) + { + if( m_pViewStructure ) + { + if( *m_pViewStructure != *dvs ) + { + delete m_pViewStructure; + m_pViewStructure = new PMViewStructure( dvs ); + } + } + else + m_pViewStructure = new PMViewStructure( dvs ); + } + + if( !m_pViewStructure ) + kdError( PMArea ) << "isDefault( ) returned true, but no default view structure is provided\n"; + } + else + { + if( dvs ) + { + if( m_pViewStructure && ( *m_pViewStructure == *dvs ) ) + { + delete m_pViewStructure; + m_pViewStructure = 0; + } + } + createViewStructure( ); + if( m_pViewStructure ) + m_pViewStructure->setParameterKey( viewStructureParameterKey( ) ); + } + m_bViewStructureChanged = false; + } + return m_pViewStructure; +} + +void PMCompositeObject::setViewStructureChanged( ) +{ + m_bViewStructureChanged = true; + if( m_pMemento ) + m_pMemento->setViewStructureChanged( ); +} + diff --git a/kpovmodeler/pmcompositeobject.h b/kpovmodeler/pmcompositeobject.h new file mode 100644 index 00000000..c2e2da58 --- /dev/null +++ b/kpovmodeler/pmcompositeobject.h @@ -0,0 +1,198 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMCOMPOBJECT_H +#define PMCOMPOBJECT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmobject.h" + +/** + * Base class for all povray objects that can have child objects. + * + * Used pattern: Composite + */ +class PMCompositeObject : public PMObject +{ + typedef PMObject Base; +public: + /** + * Creates an empty PMCompositeObject + */ + PMCompositeObject( PMPart* part ); + /** + * Copy constructor + */ + PMCompositeObject( const PMCompositeObject& o ); + /** + * Deletes the object and all children. + */ + virtual ~PMCompositeObject( ); + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** + * Returns a pointer to the first child. + */ + virtual PMObject* firstChild( ) const { return m_pFirstChild; } + /** + * Returns a pointer to the last child. + */ + virtual PMObject* lastChild( ) const { return m_pLastChild; } + /** + * Returns a pointer to the child object at position index, + * or null if the index is out of range. + */ + virtual PMObject* childAt( uint index ) const; + + /** + * Returns true if the object contains the child object o + */ + virtual bool containsChild( PMObject* o ) const + { return ( ( PMObject* )this == o->parent( ) ); } + /** + * Returns the index of the object or -1 if not found + */ + virtual int findChild( PMObject* o ); + + /** + * Inserts the object as child at index i. + * If i is -1, the object is appended. + * Returns true if successful. + */ + virtual bool insertChild( PMObject* o, int i ); + /** + * Inserts the object as child after the child object after + */ + virtual bool insertChildAfter( PMObject* object, PMObject* after ); + /** + * Inserts the object as child before the child object before + */ + virtual bool insertChildBefore( PMObject* object, PMObject* before ); + /** + * Appends the object as child. Returns true if successful. + */ + virtual bool appendChild( PMObject* ); + /** + * Returns the number of children. + */ + virtual int countChildren( ) const; + /** + * Removes a child object. Does not delete it! + * Returns true if successful.*/ + virtual bool takeChild( PMObject* o ); + /** + * Removes a child object at index i. Does not delete it! + */ + virtual bool takeChild( uint i ); + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + + /** + * Returns the number of selected child items. All selected items in + * any depth are counted + */ + virtual int selectedChildren( ) const { return m_selectedChildren; } + /** + * Deselects recursively all child objects + */ + virtual void deselectChildren( ); + + /** + * Returns the view structure of the object. + * + * If the view structure has changed since the last call, the + * structure is created or updated, or the default view structure + * is used. + * + * If the default view structure can't be used, this function calls + * createViewStructure, which has to create a non default view structure. + */ + virtual PMViewStructure* viewStructure( ); +protected: + /** + * Adds num to the number of selected objects in this object and all + * parent objects. num can be negative. + */ + virtual void adjustSelectedChildren( int num ); + + /** + * Returns the default view structure for the object. This view + * structure can be shared between all objects of this type. + * + * Only the data can be shared, NOT the pointer!!! + * + * The default view structure has to be created when this function + * is called first. + */ + virtual PMViewStructure* defaultViewStructure( ) const { return 0; } + /** + * Returns a key that represents the view structure parameter. + * + * Each time a view structure parameter is changed (=detail level), + * this key has to be incremented. + */ + virtual int viewStructureParameterKey( ) const { return 0; } + + /** + * Returns true if the objects attributes are default and the default + * view structure can be used + */ + virtual bool isDefault( ) { return false; } + /** + * The object has to create or update a non default view structure + */ + virtual void createViewStructure( ) { }; + /** + * Calls setViewStructureChanged( ) for the memento (if one has been created) + * and marks the current view structure as outdated. + */ + void setViewStructureChanged( ); + /** + * The view structure. + */ + PMViewStructure* m_pViewStructure; +private: + /** + * Pointer to the first child + */ + PMObject* m_pFirstChild; + /** + * Pointer to the last child + */ + PMObject* m_pLastChild; + /** + * number of selected child items. + */ + int m_selectedChildren; + /** + * The modify flag for the view structure + */ + bool m_bViewStructureChanged; + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmcone.cpp b/kpovmodeler/pmcone.cpp new file mode 100644 index 00000000..2772eda5 --- /dev/null +++ b/kpovmodeler/pmcone.cpp @@ -0,0 +1,451 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Leonardo Skorianez + email : lsk@if.ufrj.br + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmcone.h" + +#include "pmxmlhelper.h" +#include "pmboxedit.h" +#include "pmmemento.h" +#include "pm3dcontrolpoint.h" +#include "pmdefaults.h" +#include "pmdistancecontrolpoint.h" +#include "pmconeedit.h" + +#include + + +const double defaultConeRadius1 = 0.0; +const double defaultConeRadius2 = 0.5; +const double defaultHalfConeSize = 0.5; +const PMVector defaultEnd1 = PMVector ( 0, defaultHalfConeSize, 0 ); +const PMVector defaultEnd2 = PMVector ( 0, -defaultHalfConeSize, 0 ); +const bool defaultOpen = false; + +/** default cone structure */ +PMViewStructure* PMCone::s_pDefaultViewStructure = 0; +int PMCone::s_numSteps = c_defaultConeSteps; +int PMCone::s_parameterKey = 0; + +PMDefinePropertyClass( PMCone, PMConeProperty ); + +PMMetaObject* PMCone::s_pMetaObject = 0; +PMObject* createNewCone( PMPart* part ) +{ + return new PMCone( part ); +} + +PMCone::PMCone( PMPart* part ) + :Base( part ) +{ + m_end1 = defaultEnd1; + m_end2 = defaultEnd2; + m_radius1 = defaultConeRadius1; + m_radius2 = defaultConeRadius2; + m_open = defaultOpen; +} + +PMCone::PMCone( const PMCone& c ) + : Base( c ) +{ + m_end1 = c.m_end1; + m_end2 = c.m_end2; + m_radius1 = c.m_radius1; + m_radius2 = c.m_radius2; + m_open = c.m_open; +} + +PMCone::~PMCone( ) +{ +} + +QString PMCone::description( ) const +{ + return i18n( "cone" ); +} + +void PMCone::serialize( QDomElement & e, QDomDocument & doc ) const +{ + e.setAttribute( "end_a", m_end1.serializeXML( ) ); + e.setAttribute( "end_b", m_end2.serializeXML( ) ); + e.setAttribute( "radius_a", m_radius1 ); + e.setAttribute( "radius_b", m_radius2 ); + e.setAttribute( "open", m_open ); + Base::serialize( e, doc ); +} + +void PMCone::readAttributes( const PMXMLHelper & h ) +{ + m_end1 = h.vectorAttribute( "end_a", defaultEnd1 ); + m_end2 = h.vectorAttribute( "end_b", defaultEnd2 ); + m_radius1 = h.doubleAttribute( "radius_a", defaultConeRadius1 ); + m_radius2 = h.doubleAttribute( "radius_b", defaultConeRadius2 ); + m_open = h.boolAttribute( "open", defaultOpen ); + Base::readAttributes( h ); +} + +PMMetaObject* PMCone::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Cone", Base::metaObject( ), + createNewCone ); + s_pMetaObject->addProperty( + new PMConeProperty( "end1", &PMCone::setEnd1, &PMCone::end1 ) ); + s_pMetaObject->addProperty( + new PMConeProperty( "end2", &PMCone::setEnd2, &PMCone::end2 ) ); + s_pMetaObject->addProperty( + new PMConeProperty( "radius1", &PMCone::setRadius1, &PMCone::radius1 ) ); + s_pMetaObject->addProperty( + new PMConeProperty( "radius2", &PMCone::setRadius2, &PMCone::radius2 ) ); + s_pMetaObject->addProperty( + new PMConeProperty( "open", &PMCone::setOpen, &PMCone::open ) ); + } + return s_pMetaObject; +} + +void PMCone::setEnd1( const PMVector & p ) +{ + if( p != m_end1 ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnd1ID, m_end1 ); + m_end1 = p; + m_end1.resize( 3 ); + setViewStructureChanged( ); + } +} + +void PMCone::setEnd2( const PMVector & p ) +{ + if( p != m_end2 ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnd2ID, m_end2 ); + m_end2 = p; + m_end2.resize( 3 ); + setViewStructureChanged( ); + } +} + +void PMCone::setRadius1( double radius ) +{ + if( m_radius1 != radius ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRadius1ID, m_radius1 ); + m_radius1 = radius; + setViewStructureChanged( ); + } +} + +void PMCone::setRadius2( double radius ) +{ + if( m_radius2 != radius ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRadius2ID, m_radius2 ); + m_radius2 = radius; + setViewStructureChanged( ); + } +} + +void PMCone::setOpen( bool op ) +{ + if( op != m_open ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMOpenID, m_open ); + m_open = op; + } +} + +PMDialogEditBase* PMCone::editWidget( QWidget * parent ) const +{ + return new PMConeEdit( parent ); +} + +void PMCone::restoreMemento( PMMemento * s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMEnd1ID: + setEnd1( data->vectorData( ) ); + break; + case PMEnd2ID: + setEnd2( data->vectorData( ) ); + break; + case PMRadius1ID: + setRadius1( data->doubleData( ) ); + break; + case PMRadius2ID: + setRadius2( data->doubleData( ) ); + break; + case PMOpenID: + setOpen( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMCone::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento (s); +} + +bool PMCone::isDefault( ) +{ + if( ( m_end1 == defaultEnd1 ) && ( m_radius1 == defaultConeRadius1 ) + && ( m_end2 == defaultEnd2 ) && ( m_radius2 == defaultConeRadius2 ) && ( m_open == defaultOpen ) + && globalDetail( ) ) + return true; + return false; +} + +void PMCone::createViewStructure( ) +{ + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure(defaultViewStructure ( ) ); + m_pViewStructure->points( ).detach( ); + } + + int steps = (int)( ( (float)s_numSteps / 2 ) * ( displayDetail( ) + 1 ) ); + unsigned ptsSize = steps * 2; + unsigned lineSize = steps * 3; + + if( ptsSize != m_pViewStructure->points( ).size( ) ) + m_pViewStructure->points( ).resize( ptsSize ); + + createPoints( m_pViewStructure->points( ), m_end1, m_end2, m_radius1, m_radius2, steps ); + + if( lineSize != m_pViewStructure->lines( ).size( ) ) + { + m_pViewStructure->lines( ).detach( ); + m_pViewStructure->lines( ).resize( lineSize ); + createLines( m_pViewStructure->lines( ), steps ); + } +} + +PMViewStructure* PMCone::defaultViewStructure( ) const +{ + if( !s_pDefaultViewStructure || s_pDefaultViewStructure->parameterKey( ) != viewStructureParameterKey( ) ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + int steps = (int)( ( (float)s_numSteps / 2 ) * ( globalDetailLevel( ) + 1 ) ); + s_pDefaultViewStructure = new PMViewStructure( steps * 2, steps * 3 ); + + createPoints( s_pDefaultViewStructure->points( ), defaultEnd1, + defaultEnd2,defaultConeRadius1,defaultConeRadius2, steps ); + + createLines( s_pDefaultViewStructure->lines( ), steps ); + } + return s_pDefaultViewStructure; +} + +void PMCone::createLines( PMLineArray& lines, int steps ) +{ + int i; + for( i = 0; i < ( steps - 1 ); i++ ) + { + lines[i] = PMLine( i, i + 1 ); + lines[i + steps] = PMLine( i + steps, i + steps+ 1 ); + } + lines[steps - 1] = PMLine( steps - 1, 0 ); + lines[steps * 2 - 1] = PMLine( steps * 2 - 1, steps ); + + for( i = 0; i < steps; i++ ) + { + lines[i + 2 * steps] = PMLine( i, i + steps ); + } +} + +void PMCone::createPoints( PMPointArray& points, const PMVector& end1, + const PMVector& end2, double radius1, double radius2, int steps ) +{ + + double angle = ( 2.0 * M_PI ) / (double) steps; + + PMVector pointAt = end2 - end1; + double pl = pointAt.abs( ); + if( approxZero( pl ) ) + pointAt = PMVector( 0.0, 1.0, 0.0 ); + else + pointAt /= pl; + + PMMatrix rotation = PMMatrix::rotation( pointAt, angle ); + PMVector endPoint1 = pointAt.orthogonal( ); + endPoint1 *= radius1; + PMVector endPoint2 = pointAt.orthogonal( ); + endPoint2 *= radius2; + + int i; + for( i = 0; i < steps; i++ ) + { + points[i] = PMPoint( endPoint1 + end1 ); + points[i + steps] = PMPoint( endPoint2 + end2 ); + endPoint1 = rotation * endPoint1; + endPoint2 = rotation * endPoint2; + } +} + +void PMCone::controlPoints( PMControlPointList & list ) +{ + PMVector center, angle1, angle2; + center = m_end1 - m_end2; + double pl = center.abs( ); + if( approxZero( pl ) ) + center = PMVector( 0.0, 1.0, 0.0 ); + else + center /= pl; + + angle1 = center.orthogonal( ); + angle2 = PMVector::cross( center, angle1 ); + + PM3DControlPoint* pb1 = new PM3DControlPoint( m_end1, PMEnd1ID, i18n( "End 1" ) ); + list.append( pb1 ); + PM3DControlPoint* pb2 = new PM3DControlPoint( m_end2, PMEnd2ID, i18n( "End 2" ) ); + list.append( pb2 ); + + list.append( new PMDistanceControlPoint( pb1, angle1, m_radius1, PMRadius1ID, i18n( "Radius 1 (1)" ) ) ); + list.append( new PMDistanceControlPoint( pb1, angle2, m_radius1, PMRadius1ID, i18n( "Radius 1 (2)" ) ) ); + list.append( new PMDistanceControlPoint( pb2, angle1, m_radius2, PMRadius2ID, i18n( "Radius 2 (1)" ) ) ); + list.append( new PMDistanceControlPoint( pb2, angle2, m_radius2, PMRadius2ID, i18n( "Radius 2 (2)" ) ) ); +} + +void PMCone::controlPointsChanged( PMControlPointList & list ) +{ + PMControlPoint* p; + bool pointChanged = false; + bool radiusChanged = false; + + for( p = list.first( ); p; p = list.next( ) ) + { + if( p->changed( ) ) + { + switch( p->id( ) ) + { + case PMEnd1ID: + setEnd1( ( ( PM3DControlPoint *) p)->point( ) ); + pointChanged = true; + break; + case PMEnd2ID: + setEnd2( ( ( PM3DControlPoint *) p)->point( ) ); + pointChanged = true; + break; + case PMRadius1ID: + setRadius1( ( ( PMDistanceControlPoint *) p)->distance( ) ); + radiusChanged = true; + break; + case PMRadius2ID: + setRadius2( ( ( PMDistanceControlPoint *) p)->distance( ) ); + radiusChanged = true; + break; + default: + kdError (PMArea) << "Wrong ID in PMCone::controlPointsChanged\n"; + break; + } + } + } + + if( pointChanged ) + { + PMVector center, angle1, angle2; + bool firstPoint1 = true; + bool firstPoint2 = true; + + center = m_end1 - m_end2; + double pl = center.abs( ); + if( approxZero( pl ) ) + center = PMVector( 0.0, 1.0, 0.0 ); + else + center /= pl; + + angle1 = center.orthogonal( ); + angle2 = PMVector::cross( center, angle1 ); + + for( p = list.first( ); p; p = list.next( ) ) + { + if( p->id( ) == PMRadius1ID ) + { + if( firstPoint1 ) + { + ( ( PMDistanceControlPoint *) p)->setDirection( angle1 ); + firstPoint1 = false; + } + else + ( ( PMDistanceControlPoint *) p)->setDirection( angle2 ); + }else if( p->id( ) == PMRadius2ID ) + { + if( firstPoint2 ) + { + ( ( PMDistanceControlPoint *) p)->setDirection( angle1 ); + firstPoint2 = false; + } + else + ( ( PMDistanceControlPoint *) p)->setDirection( angle2 ); + } + } + } + + if( radiusChanged ) + for( p = list.first( ); p; p = list.next( ) ) + if( p->id( ) == PMRadius1ID ) + ( ( PMDistanceControlPoint *) p)->setDistance( m_radius1 ); + else if( p->id( ) == PMRadius2ID ) + ( ( PMDistanceControlPoint *) p)->setDistance( m_radius2 ); +} + +void PMCone::setSteps( int s ) +{ + if( s >= 4 ) + { + s_numSteps = s; + if( s_pDefaultViewStructure ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + } + } + else + kdDebug( PMArea ) << "PMCone::setSteps: S must be greater than 4\n"; + s_parameterKey++; +} + +void PMCone::cleanUp( ) const +{ + if( s_pDefaultViewStructure ) + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} diff --git a/kpovmodeler/pmcone.h b/kpovmodeler/pmcone.h new file mode 100644 index 00000000..445846f3 --- /dev/null +++ b/kpovmodeler/pmcone.h @@ -0,0 +1,188 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Leonardo Skorianez + email : lsk@if.ufrj.br + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMCONE_H +#define PMCONE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" +#include "pmvector.h" +#include "pmviewstructure.h" + +class PMViewStructure; + +/** + * Class for Povray Cone + * + */ + +class PMCone : public PMSolidObject +{ + typedef PMSolidObject Base; +public: + /** + * Create a Cone + */ + PMCone( PMPart* part ); + /** + * Copy constructor + */ + PMCone( const PMCone& c ); + + /** + * delete the Cone + */ + virtual ~PMCone( ); + + /** */ + virtual PMObject* copy( ) const { return new PMCone( *this ); } + + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMConeEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmcone" ); } + + /** + * Return the end_1 + */ + PMVector end1( ) const { return m_end1; } + /** + * Sets end_1 + */ + void setEnd1( const PMVector & p ); + /** + * Return the end_2 + */ + PMVector end2( ) const { return m_end2; } + /** + * Sets end_2 + */ + void setEnd2( const PMVector & p ); + /** + * return the first radius of the cone + */ + double radius1( ) const { return m_radius1; } + /** + * Sets the first radius of the cone + */ + void setRadius1( double radius ); + /** + * return the second radius of the cone + */ + double radius2( ) const { return m_radius2; } + /** + * Sets the second radius of the cone + */ + void setRadius2( double radius ); + /** + * Return open = 1 or close = 0 + */ + bool open( ) const { return m_open; } + /** + * Sets open cylinder + */ + void setOpen( bool op ); + + /** + * Returns the number of lines for rendering + */ + static int steps( ) { return s_numSteps; } + /** + * Sets the number of lines for rendering + */ + static void setSteps( int s ); + + /** */ + virtual void restoreMemento( PMMemento * s ); + /** */ + virtual void controlPoints( PMControlPointList & list ); + /** */ + virtual void controlPointsChanged( PMControlPointList & list ); + /** */ + virtual bool hasDisplayDetail( ) const { return true; } + /** */ + virtual void cleanUp( ) const; + +protected: + /** */ + virtual bool isDefault( ); + /** */ + virtual void createViewStructure( ); + /** */ + virtual PMViewStructure* defaultViewStructure( ) const; + /** */ + virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey(); } + +private: + /** + * Creates the lines for the view structure + */ + static void createLines( PMLineArray& lines, int steps ); + /** + * Creates the points for the view structure + */ + static void createPoints( PMPointArray& points, const PMVector& end1, + const PMVector& end2, double radius1, double radius2, int steps ); + + /** + * IDs for @ref PMMementoData + */ + enum PMConeMementoID { PMEnd1ID, PMEnd2ID, PMRadius1ID, PMRadius2ID, PMOpenID }; + /** + * ends of cone + */ + PMVector m_end1, m_end2; + /** + * radius of cone + */ + double m_radius1,m_radius2; + /** + * open + */ + bool m_open; + /** + * The default view structure. It can be shared between cones + */ + static PMViewStructure* s_pDefaultViewStructure; + static int s_numSteps; + static int s_parameterKey; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmconeedit.cpp b/kpovmodeler/pmconeedit.cpp new file mode 100644 index 00000000..2dbcfc7c --- /dev/null +++ b/kpovmodeler/pmconeedit.cpp @@ -0,0 +1,119 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Leonardo Skorianez + email : lsk@if.ufrj.br +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmconeedit.h" +#include "pmcone.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" + +#include +#include +#include +#include + +PMConeEdit::PMConeEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMConeEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* layout; + QGridLayout* gl; + + m_pEnd1 = new PMVectorEdit( "x", "y", "z", this ); + m_pEnd2 = new PMVectorEdit( "x", "y", "z", this ); + m_pRadius1 = new PMFloatEdit( this ); + m_pRadius2 = new PMFloatEdit( this ); + m_pOpen = new QCheckBox( i18n( "type of the object", "Open" ), this ); + + gl = new QGridLayout( topLayout( ), 2, 2 ); + gl->addWidget( new QLabel( i18n( "End 1:" ), this ), 0, 0 ); + gl->addWidget( m_pEnd1, 0, 1 ); + gl->addWidget( new QLabel( i18n( "End 2:" ), this ), 1, 0 ); + gl->addWidget( m_pEnd2, 1, 1 ); + + layout = new QHBoxLayout( topLayout( ) ); + gl = new QGridLayout( layout, 2, 2 ); + gl->addWidget( new QLabel( i18n( "Radius 1:" ), this ), 0, 0 ); + gl->addWidget( m_pRadius1, 0, 1 ); + gl->addWidget( new QLabel( i18n( "Radius 2:" ), this ), 1, 0 ); + gl->addWidget( m_pRadius2, 1, 1 ); + layout->addStretch( 1 ); + + topLayout( )->addWidget( m_pOpen ); + + connect( m_pEnd1, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pEnd2, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pRadius1, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pRadius2, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pOpen, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMConeEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Cone" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMCone* ) o; + + m_pEnd1->setVector( m_pDisplayedObject->end1( ) ); + m_pEnd2->setVector( m_pDisplayedObject->end2( ) ); + m_pRadius1->setValue( m_pDisplayedObject->radius1( ) ); + m_pRadius2->setValue( m_pDisplayedObject->radius2( ) ); + m_pOpen->setChecked( m_pDisplayedObject->open( ) ); + + m_pEnd1->setReadOnly( readOnly ); + m_pEnd2->setReadOnly( readOnly ); + m_pRadius1->setReadOnly( readOnly ); + m_pRadius2->setReadOnly( readOnly ); + m_pOpen->setEnabled( !readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMConeEdit: Can't display object\n"; +} + +void PMConeEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setEnd1( m_pEnd1->vector( ) ); + m_pDisplayedObject->setEnd2( m_pEnd2->vector( ) ); + m_pDisplayedObject->setRadius1( m_pRadius1->value( ) ); + m_pDisplayedObject->setRadius2( m_pRadius2->value( ) ); + m_pDisplayedObject->setOpen( m_pOpen->isChecked( ) ); + } +} + +bool PMConeEdit::isDataValid( ) +{ + if( m_pEnd1->isDataValid( ) ) + if( m_pEnd2->isDataValid( ) ) + if( m_pRadius1->isDataValid( ) ) + if( m_pRadius2->isDataValid( ) ) + return Base::isDataValid( ); + return false; +} + +#include "pmconeedit.moc" diff --git a/kpovmodeler/pmconeedit.h b/kpovmodeler/pmconeedit.h new file mode 100644 index 00000000..f39f95c6 --- /dev/null +++ b/kpovmodeler/pmconeedit.h @@ -0,0 +1,64 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Leonardo Skorinaez + email : lsk@if.ufrj.br +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMCONEEDIT_H +#define PMCONEEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" + +class QCheckBox; + +class PMVectorEdit; +class PMFloatEdit; +class PMCone; + +class PMConeEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMConeEdit with parent and name + */ + PMConeEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMCone* m_pDisplayedObject; + PMVectorEdit* m_pEnd1; + PMVectorEdit* m_pEnd2; + PMFloatEdit* m_pRadius1; + PMFloatEdit* m_pRadius2; + QCheckBox* m_pOpen; +}; +#endif diff --git a/kpovmodeler/pmcontrolpoint.cpp b/kpovmodeler/pmcontrolpoint.cpp new file mode 100644 index 00000000..8617ae27 --- /dev/null +++ b/kpovmodeler/pmcontrolpoint.cpp @@ -0,0 +1,99 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmcontrolpoint.h" +#include "pmdefaults.h" +#include "pmdebug.h" + +#include + +double PMControlPoint::s_moveGrid = c_defaultMoveGrid; +double PMControlPoint::s_scaleGrid = c_defaultScaleGrid; +double PMControlPoint::s_rotateGrid = c_defaultRotateGrid; + +PMControlPoint::PMControlPoint( int id, const QString& description ) +{ + m_id = id; + m_bChanged = false; + m_description = description; + m_bSelected = false; +} + +PMControlPoint::~PMControlPoint( ) +{ +} + +void PMControlPoint::startChange( const PMVector& s, const PMVector& n ) +{ + m_startPoint = s; + m_normalVector = n; + graphicalChangeStarted( ); +} + +void PMControlPoint::change( const PMVector& endPoint ) +{ + m_bChanged = true; + graphicalChange( m_startPoint, m_normalVector, endPoint ); +} + +bool PMControlPoint::changed( ) +{ + bool h = m_bChanged; + m_bChanged = false; + + return h; +} + +void PMControlPoint::setMoveGrid( double d ) +{ + if( d > 0 ) + s_moveGrid = d; + else + kdError( PMArea ) << "Grid has to be greater than 0\n"; +} + +void PMControlPoint::setScaleGrid( double d ) +{ + if( d > 0 ) + s_scaleGrid = d; + else + kdError( PMArea ) << "Grid has to be greater than 0\n"; +} + +void PMControlPoint::setRotateGrid( double d ) +{ + if( d > 0 ) + s_rotateGrid = d; + else + kdError( PMArea ) << "Grid has to be greater than 0\n"; +} + +void PMControlPoint::saveConfig( KConfig* cfg ) +{ + cfg->setGroup( "Grid" ); + cfg->writeEntry( "MoveGrid", s_moveGrid ); + cfg->writeEntry( "RotateGrid", s_rotateGrid ); + cfg->writeEntry( "ScaleGrid", s_scaleGrid ); +} + +void PMControlPoint::restoreConfig( KConfig* cfg ) +{ + cfg->setGroup( "Grid" ); + s_moveGrid = cfg->readDoubleNumEntry( "MoveGrid", c_defaultMoveGrid ); + s_rotateGrid = cfg->readDoubleNumEntry( "RotateGrid", c_defaultRotateGrid ); + s_scaleGrid = cfg->readDoubleNumEntry( "ScaleGrid", c_defaultScaleGrid ); +} diff --git a/kpovmodeler/pmcontrolpoint.h b/kpovmodeler/pmcontrolpoint.h new file mode 100644 index 00000000..8d3e9e66 --- /dev/null +++ b/kpovmodeler/pmcontrolpoint.h @@ -0,0 +1,190 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMCONTROLPOINT_H +#define PMCONTROLPOINT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmvector.h" +#include +#include + +class KConfig; + +/** + * Interface between the graphical views and the PMObject. + * + * PMControlPoint is the interface between graphical view and PMObjects that + * can be changed graphically with the mouse. A @ref PMObject has a + * PMControlPoint for each changeable attribute. + * + * There is one subclass for each change behavior like 3dpoint, normal vector, + * radius, rotation ... + * + * Each control point has an id to be indentified by the PMObject. The id has + * to be unique within a PMObject. + */ + +class PMControlPoint +{ +public: + /** + * Creates a PMControlPoint with an id and a description. + */ + PMControlPoint( int id, const QString& description ); + /** + * Deletes the PMControlPoint + */ + virtual ~PMControlPoint( ); + + /** + * Starts a graphical change at 3d cursor position startPoint. viewNormal + * is the normal vector of the view + */ + void startChange( const PMVector& startPoint, const PMVector& viewNormal ); + /** + * Graphical change with 3d end cursor position endPoint + */ + void change( const PMVector& endPoint ); + /** + * Snaps the control point to the grid + */ + virtual void snapToGrid( ) = 0; + + /** + * 3d coordinates of the control point for rendering*/ + virtual PMVector position( ) const { return PMVector( ); } + /** + * Returns true if the point should be displayed (rendered) + */ + virtual bool display( ) const { return true; } + /** + * Returns the id of the control point + */ + int id( ) const { return m_id; } + /** + * Type of the control point + * + * CPPoint: The control point is displayed as point, the mouse cursor + * has to be over the control point to be active (e.g. 3DControlPoint) + * + * CPCross: The control point is displayed as cross, the control point + * can be changed with the mouse in the whole view (e.g. Translation) + */ + enum PMCPDisplayType { CPPoint = 0, CPCross = 1 }; + /** + * Returns the type of the control point (see @ref PMCPDisplayType) + */ + virtual PMCPDisplayType displayType( ) const { return CPPoint; }; + /** + * Returns the description + */ + QString description( ) const { return m_description; } + /** + * Selects/deselects the control point + */ + void setSelected( bool yes ) { m_bSelected = yes; } + /** + * Returns true if the control point is selected + */ + bool selected( ) const { return m_bSelected; } + + /** + * Returns true, if the control point was changed and sets the + * changed flag to false. + */ + bool changed( ); + + /** + * Returns true if an extra line should be displayed in addition to + * the view structure + */ + virtual bool hasExtraLine( ) const { return false; } + /** + * Returns the start point of the extra line + */ + virtual PMVector extraLineStart( ) const { return PMVector( 0, 0, 0 ); } + /** + * Returns the end point of the extra line + */ + virtual PMVector extraLineEnd( ) const { return PMVector( 0, 0, 0 ); } + + /** + * Returns the grid distance for 3d points, vectors and movements + */ + static double moveGrid( ) { return s_moveGrid; } + /** + * Sets the grid distance + */ + static void setMoveGrid( double d ); + /** + * Returns the grid distance rotations + */ + static double rotateGrid( ) { return s_rotateGrid; } + /** + * Sets the grid distance + */ + static void setRotateGrid( double d ); + /** + * Returns the grid distance for scales + */ + static double scaleGrid( ) { return s_scaleGrid; } + /** + * Sets the grid distance + */ + static void setScaleGrid( double d ); + + static void saveConfig( KConfig* cfg ); + static void restoreConfig( KConfig* cfg ); + +protected: + /** + * Called when a graphical change was started + */ + virtual void graphicalChangeStarted( ) = 0; + /** + * Called when the control point was changed + */ + virtual void graphicalChange( const PMVector& startPoint, + const PMVector& viewNormal, + const PMVector& endPoint ) = 0; + /** + * Sets the changed flag + */ + void setChanged( ) { m_bChanged = true; } +private: + int m_id; + PMVector m_startPoint; + PMVector m_normalVector; + bool m_bChanged; + bool m_bSelected; + QString m_description; + + static double s_moveGrid; + static double s_rotateGrid; + static double s_scaleGrid; +}; + +typedef QPtrList PMControlPointList; +typedef QPtrListIterator PMControlPointListIterator; + +#endif diff --git a/kpovmodeler/pmcsg.cpp b/kpovmodeler/pmcsg.cpp new file mode 100644 index 00000000..3af76740 --- /dev/null +++ b/kpovmodeler/pmcsg.cpp @@ -0,0 +1,200 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmcsg.h" + +#include +#include "pmxmlhelper.h" +#include "pmcsgedit.h" +#include "pmmemento.h" +#include "pmenumproperty.h" + +PMDefineEnumPropertyClass( PMCSG, PMCSG::PMCSGType, PMCSGTypeProperty ); + +PMMetaObject* PMCSG::s_pMetaObject = 0; +PMObject* createNewCSG( PMPart* part ) +{ + return new PMCSG( part ); +} + +PMCSG::PMCSG( PMPart* part ) + : Base( part ) +{ + m_type = CSGUnion; +} + +PMCSG::PMCSG( PMPart* part, const PMCSGType t ) + : Base( part ) +{ + m_type = t; +} + +PMCSG::PMCSG( const PMCSG& c ) + : Base( c ) +{ + m_type = c.m_type; +} + +PMCSG::~PMCSG( ) +{ +} + +QString PMCSG::description( ) const +{ + switch( m_type ) + { + case CSGUnion: + return i18n( "union" ); + break; + case CSGIntersection: + return i18n( "intersection" ); + break; + case CSGDifference: + return i18n( "difference" ); + break; + case CSGMerge: + return i18n( "merge" ); + break; + } + return QString( "" ); +} + +QString PMCSG::pixmap( ) const +{ + switch( m_type ) + { + case CSGUnion: + return QString( "pmunion" ); + break; + case CSGIntersection: + return QString( "pmintersection" ); + break; + case CSGDifference: + return QString( "pmdifference" ); + break; + case CSGMerge: + return QString( "pmmerge" ); + break; + } + return QString( "" ); +} + +void PMCSG::serialize( QDomElement& e, QDomDocument& doc ) const +{ + switch( m_type ) + { + case CSGUnion: + e.setAttribute( "csgtype", "union" ); + break; + case CSGIntersection: + e.setAttribute( "csgtype", "intersection" ); + break; + case CSGDifference: + e.setAttribute( "csgtype", "difference" ); + break; + case CSGMerge: + e.setAttribute( "csgtype", "merge" ); + break; + } + + Base::serialize( e, doc ); +} + +void PMCSG::readAttributes( const PMXMLHelper& h ) +{ + QString str = h.stringAttribute( "csgtype", "union" ); + if( str == "union" ) + m_type = CSGUnion; + else if( str == "intersection" ) + m_type = CSGIntersection; + else if( str == "difference" ) + m_type = CSGDifference; + else + m_type = CSGMerge; + + Base::readAttributes( h ); +} + +PMMetaObject* PMCSG::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "CSG", Base::metaObject( ), + createNewCSG ); + PMCSGTypeProperty* p = new PMCSGTypeProperty( "csgType", &PMCSG::setCSGType, &PMCSG::csgType ); + p->addEnumValue( "union", CSGUnion ); + p->addEnumValue( "intersection", CSGIntersection ); + p->addEnumValue( "difference", CSGDifference ); + p->addEnumValue( "merge", CSGMerge ); + s_pMetaObject->addProperty( p ); + } + return s_pMetaObject; +} + +void PMCSG::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMCSG::setCSGType( const PMCSGType t ) +{ + if( t != m_type ) + { + if( m_pMemento ) + { + m_pMemento->addData( s_pMetaObject, PMTypeID, ( int ) m_type ); + m_pMemento->setDescriptionChanged( ); + } + m_type = t; + } +} + +PMDialogEditBase* PMCSG::editWidget( QWidget* parent ) const +{ + return new PMCSGEdit( parent ); +} + +void PMCSG::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMTypeID: + setCSGType( ( PMCSGType ) data->intData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMCSG::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + diff --git a/kpovmodeler/pmcsg.h b/kpovmodeler/pmcsg.h new file mode 100644 index 00000000..e8ce741e --- /dev/null +++ b/kpovmodeler/pmcsg.h @@ -0,0 +1,105 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMCSG_H +#define PMCSG_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" + +/** + * Class for povray csg objects. + */ + +class PMCSG : public PMSolidObject +{ + typedef PMSolidObject Base; +public: + /** + * The type of the csg object + */ + enum PMCSGType { CSGUnion, CSGIntersection, CSGDifference, CSGMerge }; + /** + * Creates an empty PMCSG union + */ + PMCSG( PMPart* part ); + /** + * Creates an empty PMCSG object with type t + */ + PMCSG( PMPart* part, const PMCSGType t ); + /** + * Copy constructor + */ + PMCSG( const PMCSG& c ); + + /** + * deletes the PMCSG object + */ + virtual ~PMCSG( ); + + /** */ + virtual PMObject* copy( ) const { return new PMCSG( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMCSGEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const; + + /** + * Returns the type of the csg + */ + PMCSGType csgType( ) const { return m_type; } + /** + * Sets the type of the csg + */ + void setCSGType( const PMCSGType t ); + + /** */ + virtual void restoreMemento( PMMemento* s ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMCSGMementoID { PMTypeID }; + PMCSGType m_type; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmcsgedit.cpp b/kpovmodeler/pmcsgedit.cpp new file mode 100644 index 00000000..9a6e0a39 --- /dev/null +++ b/kpovmodeler/pmcsgedit.cpp @@ -0,0 +1,118 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmcsgedit.h" +#include "pmcsg.h" + +#include +#include +#include +#include + +PMCSGEdit::PMCSGEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMCSGEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* layout; + m_pTypeCombo = new QComboBox( false, this ); + m_pTypeCombo->insertItem( i18n( "Union" ) ); + m_pTypeCombo->insertItem( i18n( "Intersection" ) ); + m_pTypeCombo->insertItem( i18n( "Difference" ) ); + m_pTypeCombo->insertItem( i18n( "Merge" ) ); + + layout = new QHBoxLayout( topLayout( ) ); + layout->addWidget( new QLabel( i18n( "Type:" ), this ) ); + layout->addWidget( m_pTypeCombo ); + layout->addStretch( 1 ); + + connect( m_pTypeCombo, SIGNAL( activated( int ) ), SLOT( slotTypeSelected( int ) ) ); +} + +void PMCSGEdit::displayObject( PMObject* o ) +{ + if( o->isA( "CSG" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMCSG* ) o; + + switch( m_pDisplayedObject->csgType( ) ) + { + case PMCSG::CSGUnion: + m_pTypeCombo->setCurrentItem( 0 ); + break; + case PMCSG::CSGIntersection: + m_pTypeCombo->setCurrentItem( 1 ); + break; + case PMCSG::CSGDifference: + m_pTypeCombo->setCurrentItem( 2 ); + break; + case PMCSG::CSGMerge: + m_pTypeCombo->setCurrentItem( 3 ); + break; + } + + m_pTypeCombo->setEnabled( !readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMCSGEdit: Can't display object\n"; +} + +void PMCSGEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + switch( m_pTypeCombo->currentItem( ) ) + { + case 0: + m_pDisplayedObject->setCSGType( PMCSG::CSGUnion ); + break; + case 1: + m_pDisplayedObject->setCSGType( PMCSG::CSGIntersection ); + break; + case 2: + m_pDisplayedObject->setCSGType( PMCSG::CSGDifference ); + break; + case 3: + m_pDisplayedObject->setCSGType( PMCSG::CSGMerge ); + break; + default: + m_pDisplayedObject->setCSGType( PMCSG::CSGUnion ); + break; + } + } +} + +bool PMCSGEdit::isDataValid( ) +{ + return Base::isDataValid( ); +} + +void PMCSGEdit::slotTypeSelected( int ) +{ + emit dataChanged( ); +} +#include "pmcsgedit.moc" diff --git a/kpovmodeler/pmcsgedit.h b/kpovmodeler/pmcsgedit.h new file mode 100644 index 00000000..8aeaddc6 --- /dev/null +++ b/kpovmodeler/pmcsgedit.h @@ -0,0 +1,63 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMCSGEDIT_H +#define PMCSGEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" + +class PMCSG; +class QComboBox; + +/** + * Dialog edit class for @ref PMCSG + */ +class PMCSGEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMCSGEdit with parent and name + */ + PMCSGEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); +protected slots: + void slotTypeSelected( int index ); +private: + PMCSG* m_pDisplayedObject; + QComboBox* m_pTypeCombo; +}; + + +#endif diff --git a/kpovmodeler/pmcylinder.cpp b/kpovmodeler/pmcylinder.cpp new file mode 100644 index 00000000..1a119004 --- /dev/null +++ b/kpovmodeler/pmcylinder.cpp @@ -0,0 +1,407 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Leonardo Skorianez + email : lsk@if.ufrj.br + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmcylinder.h" + +#include "pmxmlhelper.h" +#include "pmboxedit.h" +#include "pmmemento.h" +#include "pm3dcontrolpoint.h" +#include "pmdefaults.h" + +#include + +#include "pmdistancecontrolpoint.h" + +#include "pmcylinderedit.h" + +const double defaultCylRadius = 0.5; +const double defaultHalfCylSize = 0.5; +const PMVector defaultEnd1 = PMVector ( 0, defaultHalfCylSize, 0 ); +const PMVector defaultEnd2 = PMVector ( 0, -defaultHalfCylSize, 0 ); +const bool defaultOpen = false; + +/** default cylinder structure */ +PMViewStructure* PMCylinder::s_pDefaultViewStructure = 0; +int PMCylinder::s_numSteps = c_defaultCylinderSteps; +int PMCylinder::s_parameterKey = 0; + +PMDefinePropertyClass( PMCylinder, PMCylinderProperty ); + +PMMetaObject* PMCylinder::s_pMetaObject = 0; +PMObject* createNewCylinder( PMPart* part ) +{ + return new PMCylinder( part ); +} + + +PMCylinder::PMCylinder( PMPart* part ) + : Base( part ) +{ + m_end1 = defaultEnd1; + m_end2 = defaultEnd2; + m_radius = defaultCylRadius; + m_open = defaultOpen; +} + +PMCylinder::PMCylinder( const PMCylinder& c ) + : Base( c ) +{ + m_end1 = c.m_end1; + m_end2 = c.m_end2; + m_radius = c.m_radius; + m_open = c.m_open; +} + +PMCylinder::~PMCylinder( ) +{ +} + +QString PMCylinder::description( ) const +{ + return i18n( "cylinder" ); +} + +void PMCylinder::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "end_a", m_end1.serializeXML( ) ); + e.setAttribute( "end_b", m_end2.serializeXML( ) ); + e.setAttribute( "radius", m_radius ); + e.setAttribute( "open", m_open ); + Base::serialize( e, doc ); +} + +void PMCylinder::readAttributes( const PMXMLHelper& h ) +{ + m_end1 = h.vectorAttribute( "end_a", defaultEnd1 ); + m_end2 = h.vectorAttribute( "end_b", defaultEnd2 ); + m_radius = h.doubleAttribute( "radius", defaultCylRadius ); + m_open = h.boolAttribute( "open", defaultOpen ); + Base::readAttributes( h ); +} + +PMMetaObject* PMCylinder::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Cylinder", Base::metaObject( ), + createNewCylinder ); + s_pMetaObject->addProperty( + new PMCylinderProperty( "end1", &PMCylinder::setEnd1, &PMCylinder::end1 ) ); + s_pMetaObject->addProperty( + new PMCylinderProperty( "end2", &PMCylinder::setEnd2, &PMCylinder::end2 ) ); + s_pMetaObject->addProperty( + new PMCylinderProperty( "radius", &PMCylinder::setRadius, &PMCylinder::radius ) ); + s_pMetaObject->addProperty( + new PMCylinderProperty( "open", &PMCylinder::setOpen, &PMCylinder::open ) ); + } + return s_pMetaObject; +} + +void PMCylinder::setEnd1( const PMVector& p ) +{ + if( p != m_end1 ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnd1ID, m_end1 ); + m_end1 = p; + m_end1.resize( 3 ); + setViewStructureChanged( ); + } +} + +void PMCylinder::setEnd2( const PMVector& p ) +{ + if( p != m_end2 ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnd2ID, m_end2 ); + m_end2 = p; + m_end2.resize( 3 ); + setViewStructureChanged( ); + } +} + +void PMCylinder::setRadius( double radius ) +{ + if( m_radius != radius ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRadiusID, m_radius ); + m_radius = radius; + setViewStructureChanged( ); + } +} + +void PMCylinder::setOpen( bool op ) +{ + if( op != m_open ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMOpenID, m_open ); + m_open = op; + } +} + +PMDialogEditBase* PMCylinder::editWidget( QWidget* parent ) const +{ + return new PMCylinderEdit( parent ); +} + +void PMCylinder::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMEnd1ID: + setEnd1( data->vectorData( ) ); + break; + case PMEnd2ID: + setEnd2( data->vectorData( ) ); + break; + case PMRadiusID: + setRadius( data->doubleData( ) ); + break; + case PMOpenID: + setOpen( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMCylinder::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + +bool PMCylinder::isDefault( ) +{ + if( ( m_end1 == defaultEnd1 ) && ( m_end2 == defaultEnd2 ) + && ( m_radius == defaultCylRadius ) && ( m_open == defaultOpen ) + && globalDetail( ) ) + return true; + return false; +} + +void PMCylinder::createViewStructure( ) +{ + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultViewStructure ( ) ); + m_pViewStructure->points( ).detach( ); + } + + int steps = (int)( ( (float)s_numSteps / 2 ) * ( displayDetail( ) + 1 ) ); + unsigned ptsSize = steps * 2; + unsigned lineSize = steps * 3; + + if( ptsSize != m_pViewStructure->points( ).size( ) ) + m_pViewStructure->points( ).resize( ptsSize ); + + createPoints( m_pViewStructure->points( ), m_end1, m_end2, m_radius, steps ); + + if( ( lineSize ) != m_pViewStructure->lines( ).size( ) ) + { + m_pViewStructure->lines( ).detach( ); + m_pViewStructure->lines( ).resize( lineSize ); + createLines( m_pViewStructure->lines( ), steps ); + } +} + +PMViewStructure* PMCylinder::defaultViewStructure( ) const +{ + if( !s_pDefaultViewStructure || s_pDefaultViewStructure->parameterKey( ) != viewStructureParameterKey( ) ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + int steps = (int)( ( (float)s_numSteps / 2 ) * ( globalDetailLevel( ) + 1 ) ); + s_pDefaultViewStructure = new PMViewStructure( steps * 2, steps * 3 ); + + createPoints( s_pDefaultViewStructure->points( ), defaultEnd1, + defaultEnd2, defaultCylRadius, steps ); + + createLines( s_pDefaultViewStructure->lines( ), steps ); + } + return s_pDefaultViewStructure; +} + +void PMCylinder::createLines( PMLineArray& lines, int steps ) +{ + int i; + for( i = 0; i < ( steps - 1 ); i++ ) + { + lines[i] = PMLine( i, i + 1 ); + lines[i + steps] = PMLine( i + steps, i + steps + 1 ); + } + lines[steps - 1] = PMLine( steps - 1, 0 ); + lines[steps * 2 - 1] = PMLine( steps * 2 - 1, steps ); + + for( i = 0; i < steps; i++ ) + { + lines[i + 2 * steps] = PMLine( i, i + steps ); + } +} + +void PMCylinder::createPoints( PMPointArray& points, const PMVector& end1, + const PMVector& end2, double radius, int steps ) +{ + double angle = ( 2.0 * M_PI ) / ( double ) steps; + + PMVector pointAt = end2 - end1; + double pl = pointAt.abs( ); + if( approxZero( pl ) ) + pointAt = PMVector( 0.0, 0.0, 1.0 ); + else + pointAt /= pl; + + PMMatrix rotation = PMMatrix::rotation( pointAt, angle ); + PMVector endPoint = pointAt.orthogonal( ); + endPoint *= radius; + + int i; + for( i = 0; i < steps; i++ ) + { + points[i] = PMPoint( endPoint + end1 ); + points[i + steps] = PMPoint( endPoint + end2 ); + endPoint = rotation * endPoint; + } +} + +void PMCylinder::controlPoints( PMControlPointList & list ) +{ + PMVector center, angle1, angle2; + center = m_end1 - m_end2; + double pl = center.abs( ); + if( approxZero( pl ) ) + center = PMVector( 0.0, 1.0, 0.0 ); + else + center /= pl; + + angle1 = center.orthogonal( ); + angle2 = PMVector::cross( center, angle1 ); + + PM3DControlPoint* pb = new PM3DControlPoint( m_end1, PMEnd1ID, i18n( "End 1" ) ); + list.append( pb ); + list.append( new PM3DControlPoint( m_end2, PMEnd2ID, i18n( "End 2" ) ) ); + list.append( new PMDistanceControlPoint( pb, angle1, m_radius, PMRadiusID, i18n( "Radius (1)" ) ) ); + list.append( new PMDistanceControlPoint( pb, angle2, m_radius, PMRadiusID, i18n( "Radius (2)" ) ) ); +} + + +void PMCylinder::controlPointsChanged( PMControlPointList & list ) +{ + PMControlPoint* p; + bool pointChanged = false; + bool radiusChanged = false; + + for( p = list.first( ); p; p = list.next( ) ) + { + if( p->changed( ) ) + { + switch( p->id( ) ) + { + case PMEnd1ID: + setEnd1( ( ( PM3DControlPoint *) p)->point( ) ); + pointChanged = true; + break; + case PMEnd2ID: + setEnd2( ( ( PM3DControlPoint *) p)->point( ) ); + pointChanged = true; + break; + case PMRadiusID: + setRadius( ( ( PMDistanceControlPoint *) p)->distance( ) ); + radiusChanged = true; + break; + default: + kdError( PMArea ) << "Wrong ID in PMCylinder::controlPointsChanged\n"; + break; + } + } + } + + if( pointChanged ) + { + PMVector center, angle1, angle2; + bool firstPoint = true; + + center = m_end1 - m_end2; + double pl = center.abs( ); + if( approxZero( pl ) ) + center = PMVector( 0.0, 1.0, 0.0 ); + else + center /= pl; + + angle1 = center.orthogonal( ); + angle2 = PMVector::cross( center, angle1 ); + + for( p = list.first( ); p; p = list.next( ) ) + if( p->id( ) == PMRadiusID ) + { + if( firstPoint ) + { + ( ( PMDistanceControlPoint *) p)->setDirection( angle1 ); + firstPoint = false; + } + else + ( ( PMDistanceControlPoint *) p)->setDirection( angle2 ); + } + } + + if( radiusChanged ) + for( p = list.first( ); p; p = list.next( ) ) + if( p->id( ) == PMRadiusID ) + ( ( PMDistanceControlPoint *) p)->setDistance( m_radius ); +} + +void PMCylinder::setSteps( int s ) +{ + if( s >= 4 ) + { + s_numSteps = s; + if( s_pDefaultViewStructure ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + } + } + else + kdDebug( PMArea ) << "PMCylinder::setSteps: S must be greater than 3\n"; + s_parameterKey++; +} + +void PMCylinder::cleanUp( ) const +{ + if( s_pDefaultViewStructure ) + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} diff --git a/kpovmodeler/pmcylinder.h b/kpovmodeler/pmcylinder.h new file mode 100644 index 00000000..ba98ae40 --- /dev/null +++ b/kpovmodeler/pmcylinder.h @@ -0,0 +1,176 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Leonardo Skorianez + email : lsk@if.ufrj.br + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMCYLINDER_H +#define PMCYLINDER_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" +#include "pmvector.h" +#include "pmviewstructure.h" + +/** + * Class for povray cylinder + */ + +class PMCylinder : public PMSolidObject +{ + typedef PMSolidObject Base; +public: + /** + * Creates a cylinder + */ + PMCylinder( PMPart* part ); + /** + * Copy constructor + */ + PMCylinder( const PMCylinder& c ); + + /** + * Deletes the cylinder + */ + virtual ~PMCylinder( ); + + /** */ + virtual PMObject* copy( ) const { return new PMCylinder( *this ); } + + /** */ + virtual QString description( ) const; + /** */ + virtual PMMetaObject* metaObject( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMCylinderEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmcylinder" ); } + + /** + * Return the end_1 + */ + PMVector end1( ) const { return m_end1; } + /** + * Sets end_1 + */ + void setEnd1( const PMVector& p ); + /** + * Return the end_2 + */ + PMVector end2( ) const { return m_end2; } + /** + * Sets end_2 + */ + void setEnd2( const PMVector& p ); + /** + * return the radius of the cylinder + */ + double radius( ) const { return m_radius; } + /** + * Sets the radius of the cylinder + */ + void setRadius( double radius ); + /** + * Return open = 1 or close = 0 + */ + bool open( ) const { return m_open; } + /** + * Sets open cylinder + */ + void setOpen( bool op ); + + /** + * Returns the number of lines for rendering + */ + static int steps( ) { return s_numSteps; } + /** + * Sets the number of lines for rendering + */ + static void setSteps( int s ); + + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual void controlPoints( PMControlPointList& list ); + /** */ + virtual void controlPointsChanged( PMControlPointList& list ); + /** */ + virtual bool hasDisplayDetail( ) const { return true; } + /** */ + virtual void cleanUp( ) const; + +protected: + /** */ + virtual bool isDefault( ); + /** */ + virtual void createViewStructure( ); + /** */ + virtual PMViewStructure* defaultViewStructure( ) const; + /** */ + virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey(); } + +private: + /** + * Creates the lines for the view structure + */ + static void createLines( PMLineArray& lines, int steps ); + /** + * Creates the points for the view structure + */ + static void createPoints( PMPointArray& points, const PMVector& end1, + const PMVector& end2, double radius, int steps ); + + /** + * IDs for @ref PMMementoData + */ + enum PMCylinderMementoID { PMEnd1ID, PMEnd2ID, PMRadiusID, PMOpenID }; + /** + * ends of cylinder + */ + PMVector m_end1, m_end2; + /** + * radius of cylinder + */ + double m_radius; + /** + * open + */ + bool m_open; + /** + * The default view structure. It can be shared between cylinders + */ + static PMViewStructure* s_pDefaultViewStructure; + static int s_numSteps; + static int s_parameterKey; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmcylinderedit.cpp b/kpovmodeler/pmcylinderedit.cpp new file mode 100644 index 00000000..623b2b4f --- /dev/null +++ b/kpovmodeler/pmcylinderedit.cpp @@ -0,0 +1,113 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Leonardo Skorianez + email : skoriane@nce.ufrj.br +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmcylinderedit.h" +#include "pmcylinder.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" + +#include +#include +#include +#include + +PMCylinderEdit::PMCylinderEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMCylinderEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* layout; + QGridLayout* gl; + + m_pEnd1 = new PMVectorEdit( "x", "y", "z", this ); + m_pEnd2 = new PMVectorEdit( "x", "y", "z", this ); + m_pRadius = new PMFloatEdit( this ); + m_pOpen = new QCheckBox( i18n( "type of the object", "Open" ), this ); + + gl = new QGridLayout( topLayout( ), 2, 2 ); + gl->addWidget( new QLabel( i18n( "End 1:" ), this ), 0, 0 ); + gl->addWidget( m_pEnd1, 0, 1 ); + gl->addWidget( new QLabel( i18n( "End 2:" ), this ), 1, 0 ); + gl->addWidget( m_pEnd2, 1, 1 ); + + layout = new QHBoxLayout( topLayout( ) ); + layout->addWidget( new QLabel( i18n( "Radius:" ), this ) ); + layout->addWidget( m_pRadius ); + layout->addStretch( 1 ); + + layout = new QHBoxLayout( topLayout( ) ); + layout->addWidget( m_pOpen ); + + connect( m_pEnd1, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pEnd2, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pRadius, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pOpen, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMCylinderEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Cylinder" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMCylinder* ) o; + + m_pEnd1->setVector( m_pDisplayedObject->end1( ) ); + m_pEnd2->setVector( m_pDisplayedObject->end2( ) ); + m_pRadius->setValue( m_pDisplayedObject->radius( ) ); + m_pOpen->setChecked( m_pDisplayedObject->open( ) ); + + m_pEnd1->setReadOnly( readOnly ); + m_pEnd2->setReadOnly( readOnly ); + m_pRadius->setReadOnly( readOnly ); + m_pOpen->setEnabled( !readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMCylinderEdit: Can't display object\n"; +} + +void PMCylinderEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setEnd1( m_pEnd1->vector( ) ); + m_pDisplayedObject->setEnd2( m_pEnd2->vector( ) ); + m_pDisplayedObject->setRadius( m_pRadius->value( ) ); + m_pDisplayedObject->setOpen( m_pOpen->isChecked( ) ); + } +} + +bool PMCylinderEdit::isDataValid( ) +{ + if( m_pEnd1->isDataValid( ) ) + if( m_pEnd2->isDataValid( ) ) + if( m_pRadius->isDataValid( ) ) + return Base::isDataValid( ); + return false; +} + +#include "pmcylinderedit.moc" + + diff --git a/kpovmodeler/pmcylinderedit.h b/kpovmodeler/pmcylinderedit.h new file mode 100644 index 00000000..aec05df5 --- /dev/null +++ b/kpovmodeler/pmcylinderedit.h @@ -0,0 +1,63 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Leonardo Skorinaez + email : skoriane@nce.ufrj.br +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMCYLINDEREDIT_H +#define PMCYLINDEREDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" + +class PMVectorEdit; +class PMFloatEdit; +class PMCylinder; +class QCheckBox; + +class PMCylinderEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMCylinderEdit with parent and name + */ + PMCylinderEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMCylinder* m_pDisplayedObject; + PMVectorEdit* m_pEnd1; + PMVectorEdit* m_pEnd2; + PMFloatEdit* m_pRadius; + QCheckBox* m_pOpen; + +}; +#endif diff --git a/kpovmodeler/pmdatachangecommand.cpp b/kpovmodeler/pmdatachangecommand.cpp new file mode 100644 index 00000000..0793986e --- /dev/null +++ b/kpovmodeler/pmdatachangecommand.cpp @@ -0,0 +1,111 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmdatachangecommand.h" +#include "pmcommandmanager.h" +#include "pmmemento.h" +#include "pmobject.h" +#include + +PMDataChangeCommand::PMDataChangeCommand( PMMemento* memento ) + : PMCommand( ) +{ + QString text = memento->originator( )->name( ); + if( text.isEmpty( ) ) + text = memento->originator( )->description( ); + setText( i18n( "Change %1" ).arg( text ) ); + + // the data is already changed when the command is created + m_executed = true; + m_unexecuted = false; + m_pOldState = memento; + m_pNewState = 0; +} + +PMDataChangeCommand::~PMDataChangeCommand( ) +{ + if( m_pOldState ) + delete m_pOldState; + if( m_pNewState ) + delete m_pNewState; +} + +void PMDataChangeCommand::execute( PMCommandManager* theManager ) +{ + PMObject* obj = m_pOldState->originator( ); + if( !m_executed ) + { + // if the command is not executed + // restore the memento + if( m_pNewState ) + { + if( m_pNewState->containsChanges( ) ) + { + obj->restoreMemento( m_pNewState ); + + if( m_pOldState->idChanged( ) ) + theManager->cmdIDChanged( obj, m_pOldState->oldID( ) ); + signalChanges( theManager, m_pNewState ); + } + } + m_executed = true; + } + else if( !m_unexecuted ) + { + // the data can be changed multiple times + // if the command was never unexecuted, emit the signal + // ( the data was already changed, so this is not necessary here ) + if( m_pOldState->idChanged( ) ) + theManager->cmdIDChanged( obj, m_pOldState->oldID( ) ); + signalChanges( theManager, m_pOldState ); + } +} + +void PMDataChangeCommand::undo( PMCommandManager* theManager ) +{ + if( m_executed ) + { + if( m_pOldState->containsChanges( ) ) + { + PMObject* obj = m_pOldState->originator( ); + if( !m_pNewState ) + obj->createMemento( ); + + obj->restoreMemento( m_pOldState ); + + if( !m_pNewState ) + m_pNewState = obj->takeMemento( ); + + if( m_pNewState->idChanged( ) ) + theManager->cmdIDChanged( obj, m_pNewState->oldID( ) ); + signalChanges( theManager, m_pOldState ); + } + m_executed = false; + m_unexecuted = true; + } +} + +void PMDataChangeCommand::signalChanges( PMCommandManager* theManager, + PMMemento* memento ) +{ + PMObjectChangeListIterator it( memento->changedObjects( ) ); + + for( ; it.current( ); ++it ) + theManager->cmdObjectChanged( it.current( )->object( ), + it.current( )->mode( ) ); +} diff --git a/kpovmodeler/pmdatachangecommand.h b/kpovmodeler/pmdatachangecommand.h new file mode 100644 index 00000000..878e0f4f --- /dev/null +++ b/kpovmodeler/pmdatachangecommand.h @@ -0,0 +1,68 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMDATACHANGECOMMAND_H +#define PMDATACHANGECOMMAND_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmcommand.h" + +class PMMemento; + +/** + * Command that stores undo information for object changes + * + * Let an object create a @ref PMMemento, change the objects data, take the + * memento and create a PMDataChangeCommand with this memento. + * + * Then execute the command. The object will not be changed again! + */ +class PMDataChangeCommand : public PMCommand +{ +public: + /** + * Creates a PMDataChangeCommand for the memento + */ + PMDataChangeCommand( PMMemento* memento ); + /** + * Deletes the command. The memento will be deleted. + */ + virtual ~PMDataChangeCommand( ); +protected: + /** + * Executes the command + */ + virtual void execute( PMCommandManager* theManager ); + /** + * Undo the command + */ + virtual void undo( PMCommandManager* theManager ); + +private: + void signalChanges( PMCommandManager* theManager, PMMemento* memento ); + PMMemento* m_pNewState; + PMMemento* m_pOldState; + bool m_executed; + bool m_unexecuted; +}; + +#endif diff --git a/kpovmodeler/pmdebug.h b/kpovmodeler/pmdebug.h new file mode 100644 index 00000000..692bcd60 --- /dev/null +++ b/kpovmodeler/pmdebug.h @@ -0,0 +1,26 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMDEBUG_H +#define PMDEBUG_H + +#define PMArea 0 // no area for debug messages yet + +#include + +#endif diff --git a/kpovmodeler/pmdeclare.cpp b/kpovmodeler/pmdeclare.cpp new file mode 100644 index 00000000..2b698f0e --- /dev/null +++ b/kpovmodeler/pmdeclare.cpp @@ -0,0 +1,238 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmdeclare.h" +#include "pmdeclareedit.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmprototypemanager.h" +#include "pmpart.h" + +#include +#include + +PMDefinePropertyClass( PMDeclare, PMDeclareProperty ); + +PMMetaObject* PMDeclare::s_pMetaObject; +PMObject* createNewDeclare( PMPart* part ) +{ + return new PMDeclare( part ); +} + +PMDeclare::PMDeclare( PMPart* part ) + : Base( part ) +{ + m_pDeclareType = 0; +} + +PMDeclare::PMDeclare( const PMDeclare& d ) + : Base( d ) +{ + m_id = d.m_id; // CAUTION! Duplication of the id which has to be unique + m_pDeclareType = 0; // will be set automatically in the + // base constuctor when the children are copied +} + +PMMetaObject* PMDeclare::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Declare", Base::metaObject( ), + createNewDeclare ); + s_pMetaObject->addProperty( + new PMDeclareProperty( "id", &PMDeclare::setID, &PMDeclare::id ) ); + } + return s_pMetaObject; +} + +void PMDeclare::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +PMDeclare::~PMDeclare( ) +{ +} + +QString PMDeclare::description( ) const +{ + PMPart* pPart = part( ); + QString d = i18n( "declaration" ); + + if( m_pDeclareType && pPart ) + { + const QValueList& descriptions + = pPart->prototypeManager( )->declarationTypes( ); + QValueList::const_iterator it; + bool found = false; + for( it = descriptions.begin( ); it != descriptions.end( ) && !found; ++it ) + { + if( ( *it ).type == m_pDeclareType ) + { + d = ( *it ).description; + found = true; + } + } + } + return d; +} + +QString PMDeclare::pixmap( ) const +{ + PMPart* pPart = part( ); + QString d = "pmdeclare"; + + if( m_pDeclareType && pPart ) + { + const QValueList& descriptions + = pPart->prototypeManager( )->declarationTypes( ); + QValueList::const_iterator it; + bool found = false; + for( it = descriptions.begin( ); it != descriptions.end( ) && !found; ++it ) + { + if( ( *it ).type == m_pDeclareType ) + { + d = ( *it ).pixmap; + found = true; + } + } + } + return d; +} + +void PMDeclare::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "id", m_id ); + Base::serialize( e, doc ); +} + +void PMDeclare::readAttributes( const PMXMLHelper& h ) +{ + m_id = h.stringAttribute( "id", "object" ); + Base::readAttributes( h ); +} + +PMDialogEditBase* PMDeclare::editWidget( QWidget* parent ) const +{ + return new PMDeclareEdit( parent ); +} + +void PMDeclare::setID( const QString& newID ) +{ + if( newID != m_id ) + { + if( m_pMemento ) + { + m_pMemento->addIDChange( s_pMetaObject, PMIDID, m_id ); + m_pMemento->setDescriptionChanged( ); + } + + m_id = newID; + } +} + +QString PMDeclare::declareType( ) const +{ + if( !m_pDeclareType ) + return QString( "None" ); + return m_pDeclareType->className( ); +} + +void PMDeclare::setDeclareType( PMMetaObject* t ) +{ + if( m_pDeclareType != t ) + { + if( m_pMemento ) + m_pMemento->setDescriptionChanged( ); + + m_pDeclareType = t; + } +} + +void PMDeclare::updateDeclareType( ) +{ + PMPart* pPart = part( ); + if( !pPart ) + return; + + PMMetaObject* type = 0; + PMObject* o = firstChild( ); + PMPrototypeManager* m = pPart->prototypeManager( ); + if( o ) + { + if( o->isA( "GraphicalObject" ) ) + type = m->metaObject( "GraphicalObject" ); + else + type = o->metaObject( ); + } + setDeclareType( type ); +} + +void PMDeclare::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMIDID: + setID( data->stringData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMDeclare::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + +void PMDeclare::addLinkedObject( PMObject* o ) +{ + m_linkedObjects.append( o ); +} + +void PMDeclare::removeLinkedObject( PMObject* o ) +{ + m_linkedObjects.removeRef( o ); +} + +void PMDeclare::childAdded( PMObject* o ) +{ + if( !m_pDeclareType ) + updateDeclareType( ); + + Base::childAdded( o ); +} + +void PMDeclare::childRemoved( PMObject* o ) +{ + if( !firstChild( ) ) + setDeclareType( 0 ); + + Base::childRemoved( o ); +} diff --git a/kpovmodeler/pmdeclare.h b/kpovmodeler/pmdeclare.h new file mode 100644 index 00000000..d466e60e --- /dev/null +++ b/kpovmodeler/pmdeclare.h @@ -0,0 +1,147 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMDECLARE_H +#define PMDECLARE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmcompositeobject.h" +#include "pmsymboltable.h" + +/** + * Class for all povray declares + */ +class PMDeclare : public PMCompositeObject +{ + typedef PMCompositeObject Base; +public: + /** + * Constructor + */ + PMDeclare( PMPart* part ); + /** + * Copy constructor + */ + PMDeclare( const PMDeclare& d ); + /** + * Deletes the object + */ + ~PMDeclare( ); + + /** */ + virtual PMObject* copy( ) const { return new PMDeclare( *this ); } + + /** */ + virtual QString description( ) const; + /** */ + virtual QString pixmap( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual bool dataChangeOnInsertRemove( ) const { return true; } + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMDeclareEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the id of the declare + */ + virtual QString name( ) const { return m_id; } + /** + * Returns the id of the declare + */ + QString id( ) const { return m_id; } + /** + * Returns the declare type + */ + QString declareType( ) const; + + /** + * Sets the id of the object. + */ + void setID( const QString& id ); + /** */ + virtual bool canHaveName( ) const { return true; } + + /** */ + virtual void restoreMemento( PMMemento* s ); + /** + * Returns an iterator to the list of objects, that are linked to that + * declare + */ + PMObjectListIterator linkedObjects( ) const + { + return PMObjectListIterator( m_linkedObjects ); + } + /** + * Adds the object to the list of linked objects + */ + void addLinkedObject( PMObject* o ); + /** + * Removes the object from the list of linked objects + */ + void removeLinkedObject( PMObject* o ); + + /** */ + virtual void childAdded( PMObject* o ); + /** */ + virtual void childRemoved( PMObject* o ); + +private: + /** + * Sets the declare type + */ + void setDeclareType( PMMetaObject* o ); + /** + * Recalculates the declaration type + */ + void updateDeclareType( ); + /** + * IDs for @ref PMMementoData + */ + enum PMDeclareMementoID { PMIDID }; + + /** + * id of the declare + */ + QString m_id; + /** + * The linked objects + */ + PMObjectList m_linkedObjects; + /** + * The declare type + */ + PMMetaObject* m_pDeclareType; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmdeclareedit.cpp b/kpovmodeler/pmdeclareedit.cpp new file mode 100644 index 00000000..5f9e9c67 --- /dev/null +++ b/kpovmodeler/pmdeclareedit.cpp @@ -0,0 +1,206 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmdeclareedit.h" +#include "pmdeclare.h" +#include "pmpart.h" +#include "pmsymboltable.h" +#include "pmscanner.h" +#include "pmobjectselect.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +PMDeclareEdit::PMDeclareEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; + m_pSelectedObject = 0; +} + +void PMDeclareEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* layout = new QHBoxLayout( topLayout( ) ); + m_pNameEdit = new QLineEdit( this ); + m_pNameEdit->setMaxLength( 40 ); + QLabel* label = new QLabel( i18n( "Identifier:" ), this ); + + layout->addWidget( label ); + layout->addWidget( m_pNameEdit ); + + connect( m_pNameEdit, SIGNAL( textChanged( const QString& ) ), + SLOT( slotNameChanged( const QString& ) ) ); +} + +void PMDeclareEdit::createBottomWidgets( ) +{ + QLabel* l = new QLabel( i18n( "Linked objects:" ), this ); + topLayout( )->addWidget( l ); + + m_pLinkedObjects = new QListBox( this ); + m_pLinkedObjects->setMinimumHeight( 100 ); + connect( m_pLinkedObjects, SIGNAL( highlighted( QListBoxItem* ) ), + SLOT( slotItemSelected( QListBoxItem* ) ) ); + topLayout( )->addWidget( m_pLinkedObjects, 1 ); + + QHBoxLayout* layout = new QHBoxLayout( topLayout( ) ); + m_pSelectButton = new QPushButton( i18n( "Select..." ), this ); + m_pSelectButton->setEnabled( false ); + + connect( m_pSelectButton, SIGNAL( clicked( ) ), SLOT( slotSelect( ) ) ); + layout->addStretch( ); + layout->addWidget( m_pSelectButton ); + + Base::createBottomWidgets( ); +} + +void PMDeclareEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Declare" ) ) + { + m_pDisplayedObject = ( PMDeclare* ) o; + m_pNameEdit->setText( QString( m_pDisplayedObject->id( ) ) ); + + m_pNameEdit->setReadOnly( m_pDisplayedObject->isReadOnly( ) ); + + PMObjectListIterator it( m_pDisplayedObject->linkedObjects( ) ); + m_pLinkedObjects->clear( ); + + for( ; it.current( ); ++it ) + m_pLinkedObjects->insertItem( + new PMListBoxObject( it.current( ) ) ); + + m_pSelectButton->setEnabled( false ); + m_pSelectedObject = 0; + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMDeclareEdit: Can't display object\n"; +} + +void PMDeclareEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setID( m_pNameEdit->text( ) ); + } +} + +bool PMDeclareEdit::isDataValid( ) +{ + if( !Base::isDataValid( ) ) + return false; + + QString text = m_pNameEdit->text( ); + if( text.length( ) == 0 ) + { + KMessageBox::error( this, i18n( "Please enter an identifier!" ), + i18n( "Error" ) ); + return false; + } + + if( text == m_pDisplayedObject->id( ) ) + return true; + + QTextStream str( &text, IO_ReadOnly ); + QChar c; + int ac; + bool ok = true; + int i = 0; + while( !str.atEnd( ) && ok ) + { + str >> c; + ac = c.latin1( ); + // QChar::category can't be used because umlauts are not allowed + if( i == 0 ) + ok = ( ( ( ac >= 'a' ) && ( ac <= 'z' ) ) || + ( ( ac >= 'A' ) && ( ac <= 'Z' ) ) || + ( ac == '_' ) ); + else + ok = ( ( ( ac >= 'a' ) && ( ac <= 'z' ) ) || + ( ( ac >= 'A' ) && ( ac <= 'Z' ) ) || + ( ( ac >= '0' ) && ( ac <= '9' ) ) || + ( ac == '_' ) ); + i++; + } + if( !ok ) + { + KMessageBox::error( this, i18n( "An identifier may consist of letters," + " digits and the underscore character" + " ('_').\n" + "The first character must be a letter" + " or the underscore character!" ), + i18n( "Error" ) ); + return false; + } + // valid identifer! + + PMReservedWordDict* dict = PMScanner::reservedWords( ); + if( dict->find( text.latin1( ) ) != -1 ) + { + KMessageBox::error( this, i18n( "You can't use a povray reserved word" + " as an identifier!" ), i18n( "Error" ) ); + return false; + } + dict = PMScanner::directives( ); + if( dict->find( text.latin1( ) ) != -1 ) + { + KMessageBox::error( this, i18n( "You can't use a povray directive" + " as an identifier!" ), i18n( "Error" ) ); + return false; + } + + // no reserved word + PMSymbolTable* st = part( )->symbolTable( ); + if( st->find( text ) ) + { + KMessageBox::error( this, i18n( "Please enter a unique identifier!" ), + i18n( "Error" ) ); + return false; + } + return true; +} + +void PMDeclareEdit::slotNameChanged( const QString& ) +{ + emit dataChanged( ); +} + +void PMDeclareEdit::slotItemSelected( QListBoxItem* item ) +{ + m_pSelectedObject = ( ( PMListBoxObject* ) item )->object( ); + m_pSelectButton->setEnabled( true ); +} + +void PMDeclareEdit::slotSelect( ) +{ + if( m_pSelectedObject ) + part( )->slotObjectChanged( m_pSelectedObject, PMCNewSelection, this ); +} +#include "pmdeclareedit.moc" diff --git a/kpovmodeler/pmdeclareedit.h b/kpovmodeler/pmdeclareedit.h new file mode 100644 index 00000000..9ee2fc83 --- /dev/null +++ b/kpovmodeler/pmdeclareedit.h @@ -0,0 +1,74 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMDECLAREEDIT_H +#define PMDECLAREEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMDeclare; +class QLineEdit; +class QListBox; +class QPushButton; +class QListBoxItem; + +/** + * Dialog edit class for @ref PMDeclare. + */ +class PMDeclareEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMDeclareEdit with parent and name + */ + PMDeclareEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void createBottomWidgets( ); + /** */ + virtual void saveContents( ); + +private slots: + void slotNameChanged( const QString& ); + void slotItemSelected( QListBoxItem* ); + void slotSelect( ); +private: + PMDeclare* m_pDisplayedObject; + QLineEdit* m_pNameEdit; + QListBox* m_pLinkedObjects; + QPushButton* m_pSelectButton; + PMObject* m_pSelectedObject; +}; + + +#endif diff --git a/kpovmodeler/pmdefaults.h b/kpovmodeler/pmdefaults.h new file mode 100644 index 00000000..32c9675c --- /dev/null +++ b/kpovmodeler/pmdefaults.h @@ -0,0 +1,131 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMDEFAULTS_H +#define PMDEFAULTS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +// PMRenderManager +const QColor c_defaultGraphicalObjectColor0 = QColor( 148, 148, 148 ); +const QColor c_defaultGraphicalObjectColor1 = QColor( 255, 255, 128 ); +const QColor c_defaultTextureColor0 = QColor( 64, 192, 64 ); +const QColor c_defaultTextureColor1 = QColor( 192, 255, 128 ); +const QColor c_defaultAxesColorX = QColor( 255, 0, 0 ); +const QColor c_defaultAxesColorY = QColor( 0, 255, 0 ); +const QColor c_defaultAxesColorZ = QColor( 0, 0, 255 ); +const QColor c_defaultControlPointColor0 = QColor( 255, 255, 148 ); +const QColor c_defaultControlPointColor1 = QColor( 92, 255, 92 ); +const QColor c_defaultBackgroundColor = QColor( 0, 0, 0 ); +const QColor c_defaultFieldOfViewColor = QColor( 128, 128, 255 ); +const bool c_defaultHighDetailCameraView = true; + +// PMGLView +const int c_defaultGridDistance = 50; +const QColor c_defaultGridColor = QColor( 40, 120, 40 ); + +// PovrayRenderWidget +const QString c_defaultPovrayCommand = QString( "povray" ); + +// PMDetailObject +const int c_defaultDetailObjectGlobalDetailLevel = 1; + +// PMSphere +const int c_defaultSphereUSteps = 8; +const int c_defaultSphereVSteps = 16; + +// PMBlobSphere +const int c_defaultBlobSphereUSteps = 8; +const int c_defaultBlobSphereVSteps = 16; + +// PMBlobCylinder +const int c_defaultBlobCylinderUSteps = 4; +const int c_defaultBlobCylinderVSteps = 16; + +// PMCylinder +const int c_defaultCylinderSteps = 16; + +// PMCone +const int c_defaultConeSteps = 16; + +// PMTorus +const int c_defaultTorusVSteps = 16; +const int c_defaultTorusUSteps = 9; + +// PMPlane +const double c_defaultPlaneSize = 2.0; + +// PMDisc +const int c_defaultDiscSteps = 16; + +// PMText +const int c_defaultTextSteps = 3; + +// PMLathe +const int c_defaultLatheRSteps = 16; +const int c_defaultLatheSSteps = 4; + +// PMPrism +const int c_defaultPrismSSteps = 4; + +// PMSurfaceOfRevolution +const int c_defaultSurfaceOfRevolutionRSteps = 16; +const int c_defaultSurfaceOfRevolutionSSteps = 4; + +// PMSuperquadricEllipsoid +const int c_defaultSuperquadricEllipsoidUSteps = 3; +const int c_defaultSuperquadricEllipsoidVSteps = 3; + +// PMSphereSweep +const int c_defaultSphereSweepRSteps = 8; +const int c_defaultSphereSweepSSteps = 4; + +// PMHeightField +const int c_defaultHeightFieldVariance = 16; + +// PMDialogEditBase, texture preview +const int c_defaultTPSize = 160; +const bool c_defaultTPShowSphere = true; +const bool c_defaultTPShowCylinder = false; +const bool c_defaultTPShowBox = true; +const bool c_defaultTPAA = false; +const int c_defaultTPAADepth = 2; +const double c_defaultTPAAThreshold = 0.3; +const bool c_defaultTPShowFloor = true; +const bool c_defaultTPShowWall = true; +const QColor c_defaultTPWallColor1 = QColor( 255, 255, 255 ); +const QColor c_defaultTPWallColor2 = QColor( 0, 0, 0 ); +const QColor c_defaultTPFloorColor1 = QColor( 192, 0, 0 ); +const QColor c_defaultTPFloorColor2 = QColor( 255, 255, 255 ); +const double c_defaultTPGamma = 1.5; + +// PM3DControlPoint +const double c_defaultMoveGrid = 0.1; +const double c_defaultScaleGrid = 0.1; +const double c_defaultRotateGrid = 1.0; + +// PMShell +const bool c_defaultTreeViewTabbed = false; +const bool c_defaultTreeViewRight = false; +const bool c_defaultTreeViewBelow = false; + +#endif diff --git a/kpovmodeler/pmdeletecommand.cpp b/kpovmodeler/pmdeletecommand.cpp new file mode 100644 index 00000000..fa5ff47b --- /dev/null +++ b/kpovmodeler/pmdeletecommand.cpp @@ -0,0 +1,281 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmdeletecommand.h" +#include "pmcommandmanager.h" +#include "pmdeclare.h" +#include "pmrecursiveobjectiterator.h" +#include "pmmemento.h" + +#include +#include +#include + +PMDeleteCommand::PMDeleteCommand( PMObject* obj ) + : PMCommand( i18n( "Delete %1" ).arg( obj->name( ) ) ) +{ + // the scene can not be deleted! + if( obj->parent( ) ) + m_infoList.append( new PMDeleteInfo( obj ) ); + else + { + // object has no parent! + // top level objects can't be moved, move all child items + PMObject* tmp; + for( tmp = obj->firstChild( ); tmp; tmp = tmp->nextSibling( ) ) + m_infoList.append( new PMDeleteInfo( tmp ) ); + } + m_executed = false; + m_firstExecution = true; + m_linksCreated = false; +} + +PMDeleteCommand::PMDeleteCommand( const PMObjectList& list ) + : PMCommand( i18n( "Delete Objects" ) ) +{ + PMObjectListIterator it( list ); + PMObject* obj; + + for( ; it.current( ); ++it ) + { + obj = it.current( ); + + if( obj->parent( ) ) + m_infoList.append( new PMDeleteInfo( obj ) ); + else + { + // object has no parent! + // top level objects can't be moved, move all child items + PMObject* tmp; + for( tmp = obj->firstChild( ); tmp; tmp = tmp->nextSibling( ) ) + m_infoList.append( new PMDeleteInfo( tmp ) ); + } + } + + m_infoList.setAutoDelete( true ); + m_executed = false; + m_firstExecution = true; + m_linksCreated = false; +} + +PMDeleteCommand::~PMDeleteCommand( ) +{ + if( m_executed ) + { + PMDeleteInfoListIterator it( m_infoList ); + for( ; it.current( ); ++it ) + delete ( it.current( )->deletedObject( ) ); + } + + m_infoList.clear( ); +} + +void PMDeleteCommand::execute( PMCommandManager* theManager ) +{ + if( !m_executed ) + { + PMDeleteInfoListIterator it( m_infoList ); + PMDeleteInfo* info = 0; + PMObject* parent; + + if( !m_linksCreated ) + { + PMDeclare* decl; + for( ; it.current( ); ++it ) + { + PMRecursiveObjectIterator oit( it.current( )->deletedObject( ) ); + for( ; oit.current( ); ++oit ) + { + decl = oit.current( )->linkedObject( ); + if( decl ) + { + m_links.append( oit.current( ) ); + if( !m_linkedDeclares.containsRef( decl ) ) + m_linkedDeclares.append( decl ); + } + } + } + m_linksCreated = true; + } + + PMObjectListIterator lit( m_links ); + for( ; lit.current( ); ++lit ) + lit.current( )->linkedObject( )->removeLinkedObject( lit.current( ) ); + + for( it.toLast( ); it.current( ); --it ) + { + info = it.current( ); + parent = info->parent( ); + // signal has to be emitted before the item is removed + theManager->cmdObjectChanged( info->deletedObject( ), PMCRemove ); + if( m_firstExecution ) + if( parent->dataChangeOnInsertRemove( ) + && !parent->mementoCreated( ) ) + parent->createMemento( ); + parent->takeChild( info->deletedObject( ) ); + } + + if( m_firstExecution ) + { + for( it.toLast( ); it.current( ); --it ) + { + parent = it.current( )->parent( ); + if( parent->mementoCreated( ) ) + m_dataChanges.append( parent->takeMemento( ) ); + } + } + + QPtrListIterator mit( m_dataChanges ); + for( ; mit.current( ); ++mit ) + { + PMObjectChangeListIterator change = mit.current( )->changedObjects( ); + for( ; change.current( ); ++change ) + theManager->cmdObjectChanged( change.current( )->object( ), + change.current( )->mode( ) ); + } + + PMObjectListIterator dit( m_linkedDeclares ); + for( ; dit.current( ); ++dit ) + theManager->cmdObjectChanged( dit.current( ), PMCData ); + + m_executed = true; + m_firstExecution = false; + } +} + +void PMDeleteCommand::undo( PMCommandManager* theManager ) +{ + if( m_executed ) + { + PMDeleteInfoListIterator it( m_infoList ); + for( ; it.current( ); ++it ) + { + if( it.current( )->prevSibling( ) ) + it.current( )->parent( ) + ->insertChildAfter( it.current( )->deletedObject( ), + it.current( )->prevSibling( ) ); + else + it.current( )->parent( ) + ->insertChild( it.current( )->deletedObject( ), 0 ); + theManager->cmdObjectChanged( it.current( )->deletedObject( ), PMCAdd ); + } + + PMObjectListIterator lit( m_links ); + for( ; lit.current( ); ++lit ) + lit.current( )->linkedObject( )->addLinkedObject( lit.current( ) ); + PMObjectListIterator dit( m_linkedDeclares ); + for( ; dit.current( ); ++dit ) + theManager->cmdObjectChanged( dit.current( ), PMCData ); + + QPtrListIterator mit( m_dataChanges ); + for( ; mit.current( ); ++mit ) + { + mit.current( )->originator( )->restoreMemento( mit.current( ) ); + PMObjectChangeListIterator change = mit.current( )->changedObjects( ); + for( ; change.current( ); ++change ) + theManager->cmdObjectChanged( change.current( )->object( ), + change.current( )->mode( ) ); + } + + m_executed = false; + } +} + +int PMDeleteCommand::errorFlags( PMPart* ) +{ + PMDeleteInfo* info; + PMDeclare* decl = 0; + PMObject* obj; + bool insideSelection; + bool ok = true; + bool error = false; + + // dictionary of deleted objects + QPtrDict m_deletedObjects( 1009 ); + m_deletedObjects.setAutoDelete( true ); + PMDeleteInfoListIterator it( m_infoList ); + for( ; it.current( ); ++it ) + m_deletedObjects.insert( it.current( )->deletedObject( ), + new bool( true ) ); + + // declares can only be deleted, if all linked + // objects are deleted as well + + info = m_infoList.last( ); + + while( info ) + { + ok = true; + if( info->deletedObject( )->isA( "Declare" ) ) + { + decl = ( PMDeclare* ) ( info->deletedObject( ) ); + PMObjectListIterator links = decl->linkedObjects( ); + + for( ; links.current( ) && ok; ++links ) + { + insideSelection = false; + for( obj = links.current( ); obj && !insideSelection; + obj = obj->parent( ) ) + { + if( m_deletedObjects.find( obj ) ) + insideSelection = true; + } + + if( insideSelection ) + { + bool stop = false; + for( obj = links.current( ); obj && !stop; obj = obj->parent( ) ) + { + if( m_deletedObjects.find( obj ) ) + stop = true; + else + m_deletedObjects.insert( obj, new bool( true ) ); + } + } + else + ok = false; + } + } + + if( !ok ) + { + m_errors.prepend( i18n( "The declare \"%1\" can't be removed " + "because of some remaining links." ) + .arg( decl->id( ) ) ); + + PMDeleteInfo* tmp = info; + info = m_infoList.prev( ); + m_deletedObjects.remove( decl ); + m_infoList.removeRef( tmp ); + + error = true; + } + else + info = m_infoList.prev( ); + } + + if( error ) + { + if( m_infoList.count( ) == 0 ) + return PMEError | PMEFatal; + else + return PMEError; + } + + return PMENone; +} diff --git a/kpovmodeler/pmdeletecommand.h b/kpovmodeler/pmdeletecommand.h new file mode 100644 index 00000000..ff67c0bc --- /dev/null +++ b/kpovmodeler/pmdeletecommand.h @@ -0,0 +1,126 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMDELETECOMMAND_H +#define PMDELETECOMMAND_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmcommand.h" +#include + +#include "pmobject.h" + +class PMMemento; + +/** + * Class that stores undo information for the @ref PMDeleteCommand + */ +class PMDeleteInfo +{ +public: + /** + * Creates undo information for the object deletedObject. + * The object has to have a parent! + */ + PMDeleteInfo( PMObject* deletedObject ) + { + m_pDeletedObject = deletedObject; + m_pParent = deletedObject->parent( ); + m_pPrevSibling = deletedObject->prevSibling( ); + m_insertError = false; + } + /** + * Deletes the object. The object deletedObject will not be deleted! + */ + ~PMDeleteInfo( ) { }; + /** + * Returns a pointer to the deleted object + */ + PMObject* deletedObject( ) const { return m_pDeletedObject; } + /** + * Returns a pointer to the parent of the deleted object + */ + PMObject* parent( ) const { return m_pParent; } + /** + * Returns the previous sibling of the deleted object + */ + PMObject* prevSibling( ) const { return m_pPrevSibling; } + /** + * Returns true if this object could not be inserted in a move command + */ + bool insertError( ) const { return m_insertError; } + /** + * Sets the insert error flag + */ + void setInsertError( ) { m_insertError = true; } +private: + PMObject* m_pDeletedObject; + PMObject* m_pParent; + PMObject* m_pPrevSibling; + bool m_insertError; +}; + +typedef QPtrList PMDeleteInfoList; +typedef QPtrListIterator PMDeleteInfoListIterator; + +/** + * Command class for removing PMObjects + */ +class PMDeleteCommand : public PMCommand +{ +public: + /** + * Delete Command that removes the object obj. + */ + PMDeleteCommand( PMObject* obj ); + /** + * Command that deletes a list of PMObjects. The list has to be sorted! + */ + PMDeleteCommand( const PMObjectList& list ); + /** + * Deletes the command. The deleted object will be deleted, if removed + */ + virtual ~PMDeleteCommand( ); + + /** */ + virtual int errorFlags( PMPart* ); + +protected: + /** + * Executes the command and stores undo information + */ + virtual void execute( PMCommandManager* theManager ); + /** + * Undo the command + */ + virtual void undo( PMCommandManager* theManager ); + +private: + PMDeleteInfoList m_infoList; + bool m_executed, m_firstExecution; + PMObjectList m_links; + PMObjectList m_linkedDeclares; + bool m_linksCreated; + QPtrList m_dataChanges; +}; + +#endif diff --git a/kpovmodeler/pmdensity.cpp b/kpovmodeler/pmdensity.cpp new file mode 100644 index 00000000..1cc1d638 --- /dev/null +++ b/kpovmodeler/pmdensity.cpp @@ -0,0 +1,76 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.tp +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmdensity.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmdensityedit.h" + +#include + +PMMetaObject* PMDensity::s_pMetaObject = 0; +PMObject* createNewDensity( PMPart* part ) +{ + return new PMDensity( part ); +} + +PMDensity::PMDensity( PMPart* part ) + : Base( part ) +{ +} + +PMDensity::PMDensity( const PMDensity& d ) + : Base( d ) +{ +} + +PMDensity::~PMDensity( ) +{ +} + +PMMetaObject* PMDensity::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Density", Base::metaObject( ), + createNewDensity ); + } + return s_pMetaObject; +} + +void PMDensity::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMDensity::description( ) const +{ + return i18n( "density" ); +} + + +PMDialogEditBase* PMDensity::editWidget( QWidget* parent ) const +{ + return new PMDensityEdit( parent ); +} + diff --git a/kpovmodeler/pmdensity.h b/kpovmodeler/pmdensity.h new file mode 100644 index 00000000..72a76bb7 --- /dev/null +++ b/kpovmodeler/pmdensity.h @@ -0,0 +1,76 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMDENSITY_H +#define PMDENSITY_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebase.h" + +/** + * Class for povray densities + */ +class PMDensity : public PMTextureBase +{ + typedef PMTextureBase Base; +public: + /** + * Creates an PMDensity + */ + PMDensity( PMPart* part ); + /** + * Copy constructor + */ + PMDensity( const PMDensity& d ); + /** + * Deletes the object + */ + virtual ~PMDensity( ); + + /** */ + virtual PMObject* copy( ) const { return new PMDensity( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** + * Returns a new @ref PMDensityEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pmdensity" ); } + +private: + /** + * IDs for @ref PMMementoData + */ +// enum PMDensityMementoID { }; + + static PMMetaObject* s_pMetaObject; +}; + + +#endif diff --git a/kpovmodeler/pmdensityedit.cpp b/kpovmodeler/pmdensityedit.cpp new file mode 100644 index 00000000..9c7ff732 --- /dev/null +++ b/kpovmodeler/pmdensityedit.cpp @@ -0,0 +1,44 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmdensityedit.h" +#include "pmdensity.h" +#include "pmlinkedit.h" + +#include +#include +#include + + +PMDensityEdit::PMDensityEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMDensityEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Density" ) ) + { + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMDensityEdit: Can't display object\n"; +} + +#include "pmdensityedit.moc" diff --git a/kpovmodeler/pmdensityedit.h b/kpovmodeler/pmdensityedit.h new file mode 100644 index 00000000..093a750c --- /dev/null +++ b/kpovmodeler/pmdensityedit.h @@ -0,0 +1,58 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMDENSITYEDIT_H +#define PMDENSITYEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebaseedit.h" + +class PMDensity; + +/** + * Dialog edit class for @ref PMDensity + */ +class PMDensityEdit : public PMTextureBaseEdit +{ + Q_OBJECT + typedef PMTextureBaseEdit Base; +public: + /** + * Creates a PMDensityEdit with parent and name + */ + PMDensityEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + +protected: + /** */ +// virtual void createTopWidgets( ); + /** */ +// virtual void saveContents( ); + +private: + PMDensity* m_pDisplayedObject; +}; + + +#endif diff --git a/kpovmodeler/pmdetailobject.cpp b/kpovmodeler/pmdetailobject.cpp new file mode 100644 index 00000000..eae526cb --- /dev/null +++ b/kpovmodeler/pmdetailobject.cpp @@ -0,0 +1,151 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2004 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ +#include "pmdetailobject.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmdefaults.h" + +/** Default local detail value*/ +const bool c_defaulGlobalDetail = true; +const int c_defaultLocalDetailLevel = 1; + +/** Static global detail */ +int PMDetailObject::s_globalDetailLevel = c_defaultDetailObjectGlobalDetailLevel; +int PMDetailObject::s_globalDetailKey = 0; + +PMMetaObject* PMDetailObject::s_pMetaObject = 0; + +PMDefinePropertyClass( PMDetailObject, PMDetailObjectProperty ); + +PMDetailObject::PMDetailObject( PMPart *part ) : Base( part ) +{ + m_globalDetail = c_defaulGlobalDetail; + m_localDetailLevel = c_defaultLocalDetailLevel; +} + +PMDetailObject::PMDetailObject( const PMDetailObject& o ) : Base( o ) +{ + m_globalDetail = o.m_globalDetail; + m_localDetailLevel = o.m_localDetailLevel; +} + +PMDetailObject::~PMDetailObject() +{ +} + +PMMetaObject* PMDetailObject::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "DetailObject", Base::metaObject( ) ); + s_pMetaObject->addProperty( + new PMDetailObjectProperty( "globalDetail", &PMDetailObject::setGlobalDetail, &PMDetailObject::globalDetail ) ); + s_pMetaObject->addProperty( + new PMDetailObjectProperty( "localDetailLevel", &PMDetailObject::setLocalDetailLevel, &PMDetailObject::localDetailLevel ) ); + } + return s_pMetaObject; +} + +void PMDetailObject::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMDetailObject::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "global_detail", m_globalDetail ); + e.setAttribute( "local_detail_level", m_localDetailLevel ); + Base::serialize( e, doc ); +} + +void PMDetailObject::readAttributes( const PMXMLHelper& h ) +{ + m_globalDetail = h.boolAttribute( "global_detail", c_defaulGlobalDetail ); + m_localDetailLevel = h.intAttribute( "local_detail_level", c_defaultLocalDetailLevel ); + Base::readAttributes( h ); +} + +int PMDetailObject::displayDetail( ) const +{ + if( m_globalDetail ) + return s_globalDetailLevel; + else + return m_localDetailLevel; +} + +void PMDetailObject::setGlobalDetail( bool yes ) +{ + if( m_globalDetail != yes ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMGlobalDetailID, m_globalDetail ); + m_globalDetail = yes; + setViewStructureChanged( ); + } +} + +void PMDetailObject::setLocalDetailLevel( int level ) +{ + if( m_localDetailLevel != level ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMLocalDetailLevelID, m_localDetailLevel ); + m_localDetailLevel = level; + setViewStructureChanged( ); + } +} + +void PMDetailObject::setGlobalDetailLevel( int level ) +{ + if( s_globalDetailLevel != level ) + { + ++s_globalDetailKey; + s_globalDetailLevel = level; + } +} + +void PMDetailObject::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMGlobalDetailID: + setGlobalDetail( data->boolData( ) ); + break; + case PMLocalDetailLevelID: + setLocalDetailLevel( data->intData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMDetailObject::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmdetailobject.h b/kpovmodeler/pmdetailobject.h new file mode 100644 index 00000000..7994cdff --- /dev/null +++ b/kpovmodeler/pmdetailobject.h @@ -0,0 +1,115 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2004 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#ifndef PMDETAILOBJECT_H +#define PMDETAILOBJECT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmnamedobject.h" + +class PMDetailObject : public PMNamedObject +{ + typedef PMNamedObject Base; +public: + /** + * Creates an empty PMDetailObject + */ + PMDetailObject( PMPart* part ); + /** + * Copy constrctor + */ + PMDetailObject( const PMDetailObject& o ); + /** + * Deletes the object + */ + virtual ~PMDetailObject(); + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns true if the object has detail settings + */ + virtual bool hasDisplayDetail( ) const { return false; } + + /** + * Returns the current display detail + */ + int displayDetail( ) const; + + /** + * Sets the global detail flag + */ + void setGlobalDetail( bool yes ); + /** + * Returns the global detail flag + */ + bool globalDetail( ) const { return m_globalDetail; } + + /** + * Sets the local detail level + */ + void setLocalDetailLevel( int level ); + /** + * Returns the local detail level + */ + int localDetailLevel( ) const { return m_localDetailLevel; } + + /** + * Sets the global detail level + */ + static void setGlobalDetailLevel( int level ); + /** + * Returns the global detail level + */ + static int globalDetailLevel( ) { return s_globalDetailLevel; } + + /** */ + virtual void restoreMemento( PMMemento* s ); + +protected: + /** + * Global parameter key + */ + static int globalDetailKey( ) { return s_globalDetailKey; } + +private: + /** + * IDs for @ref PMMementoData + */ + enum PMNamedObjectMementoID { PMGlobalDetailID, PMLocalDetailLevelID }; + + bool m_globalDetail; + int m_localDetailLevel; + + static int s_globalDetailKey; + static int s_globalDetailLevel; + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmdetailobjectedit.cpp b/kpovmodeler/pmdetailobjectedit.cpp new file mode 100644 index 00000000..d42c668c --- /dev/null +++ b/kpovmodeler/pmdetailobjectedit.cpp @@ -0,0 +1,122 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2004 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ +#include "pmdetailobjectedit.h" +#include "pmdetailobject.h" + +#include +#include +#include +#include +#include + +PMDetailObjectEdit::PMDetailObjectEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMDetailObjectEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* layout = new QHBoxLayout( topLayout( ) ); + m_pGlobalDetail = new QCheckBox( i18n( "Global detail" ), this ); + m_pLocalDetailLevelLabel = new QLabel( i18n( "Detail level:" ), this ); + m_pLocalDetailLevel = new QComboBox( this ); + m_pLocalDetailLevel->insertItem( i18n( "Very Low" ) ); + m_pLocalDetailLevel->insertItem( i18n( "Low" ) ); + m_pLocalDetailLevel->insertItem( i18n( "Medium" ) ); + m_pLocalDetailLevel->insertItem( i18n( "High" ) ); + m_pLocalDetailLevel->insertItem( i18n( "Very High" ) ); + + layout->addWidget( m_pGlobalDetail ); + layout->addWidget( m_pLocalDetailLevelLabel ); + layout->addWidget( m_pLocalDetailLevel ); + layout->addStretch( ); + + connect( m_pGlobalDetail, SIGNAL( clicked( ) ), SLOT( slotGlobalDetailClicked( ) ) ); + connect( m_pLocalDetailLevel, SIGNAL( activated( int ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMDetailObjectEdit::displayObject( PMObject* o ) +{ + if( o->isA( "DetailObject" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMDetailObject* ) o; + + if( !m_pDisplayedObject->hasDisplayDetail( ) ) + { + m_pGlobalDetail->hide( ); + m_pLocalDetailLevelLabel->hide( ); + m_pLocalDetailLevel->hide( ); + } + + if( m_pDisplayedObject->globalDetail( ) ) + { + m_pGlobalDetail->setChecked( true ); + m_pLocalDetailLevelLabel->setEnabled( false ); + m_pLocalDetailLevel->setEnabled( false ); + } + else + { + m_pGlobalDetail->setChecked( false ); + m_pLocalDetailLevelLabel->setEnabled( !readOnly ); + m_pLocalDetailLevel->setEnabled( !readOnly ); + } + m_pGlobalDetail->setEnabled( !readOnly ); + + m_pLocalDetailLevel->setCurrentItem( m_pDisplayedObject->localDetailLevel( ) - 1 ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMNamedObjectEdit: Can't display object\n"; +} + +void PMDetailObjectEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setGlobalDetail( m_pGlobalDetail->isChecked( ) ); + m_pDisplayedObject->setLocalDetailLevel( m_pLocalDetailLevel->currentItem( ) + 1 ); + } +} + +bool PMDetailObjectEdit::isDataValid( ) +{ + return Base::isDataValid( ); +} + +void PMDetailObjectEdit::slotGlobalDetailClicked( ) +{ + if( m_pGlobalDetail->isChecked( ) ) + { + m_pLocalDetailLevelLabel->setEnabled( false ); + m_pLocalDetailLevel->setEnabled( false ); + } + else + { + bool readOnly = m_pDisplayedObject->isReadOnly( ); + m_pLocalDetailLevelLabel->setEnabled( !readOnly ); + m_pLocalDetailLevel->setEnabled( !readOnly ); + } + emit dataChanged( ); +} + +#include "pmdetailobjectedit.moc" diff --git a/kpovmodeler/pmdetailobjectedit.h b/kpovmodeler/pmdetailobjectedit.h new file mode 100644 index 00000000..7a585034 --- /dev/null +++ b/kpovmodeler/pmdetailobjectedit.h @@ -0,0 +1,68 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2004 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ +#ifndef PMDETAILOBJECTEDIT_H +#define PMDETAILOBJECTEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmnamedobjectedit.h" + +class PMDetailObject; +class QCheckBox; +class QLabel; +class QComboBox; + +/** + * Dialog edit class for @ref PMNamedObject. + */ +class PMDetailObjectEdit : public PMNamedObjectEdit +{ + Q_OBJECT + typedef PMNamedObjectEdit Base; +public: + /** + * Creates a PMNamedObjectEdit with parent and name + */ + PMDetailObjectEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); + +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private slots: + void slotGlobalDetailClicked( ); + +private: + PMDetailObject* m_pDisplayedObject; + QCheckBox* m_pGlobalDetail; + QLabel* m_pLocalDetailLevelLabel; + QComboBox* m_pLocalDetailLevel; +}; + + +#endif diff --git a/kpovmodeler/pmdialogeditbase.cpp b/kpovmodeler/pmdialogeditbase.cpp new file mode 100644 index 00000000..9defd762 --- /dev/null +++ b/kpovmodeler/pmdialogeditbase.cpp @@ -0,0 +1,558 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmdialogeditbase.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pmpart.h" +#include "pmdefaults.h" +#include "pmpovrayrenderwidget.h" +#include "pmpovrayoutputwidget.h" +#include "pmpovray31format.h" +#include "pmserializer.h" +#include "pmcolor.h" +#include "pmrecursiveobjectiterator.h" +#include "pmdeclare.h" + +#include "pmdebug.h" + +int PMDialogEditBase::s_previewSize = c_defaultTPSize; +bool PMDialogEditBase::s_showSphere = c_defaultTPShowSphere; +bool PMDialogEditBase::s_showCylinder = c_defaultTPShowCylinder; +bool PMDialogEditBase::s_showBox = c_defaultTPShowBox; +bool PMDialogEditBase::s_previewAA = c_defaultTPAA; +int PMDialogEditBase::s_previewAADepth = c_defaultTPAADepth; +double PMDialogEditBase::s_previewAAThreshold = c_defaultTPAAThreshold; +bool PMDialogEditBase::s_showFloor = c_defaultTPShowFloor; +bool PMDialogEditBase::s_showWall = c_defaultTPShowWall; +QColor PMDialogEditBase::s_wallColor1 = c_defaultTPWallColor1; +QColor PMDialogEditBase::s_wallColor2 = c_defaultTPWallColor2; +QColor PMDialogEditBase::s_floorColor1 = c_defaultTPFloorColor1; +QColor PMDialogEditBase::s_floorColor2 = c_defaultTPFloorColor2; +bool PMDialogEditBase::s_previewLocal = false; +double PMDialogEditBase::s_previewGamma = c_defaultTPGamma; + + +/** Constants for texture preview */ +const QString c_wallCode = QString( + "plane { <0, 0, -1>, -2\n" + " pigment { checker %1 %2\n" + " scale <0.5, 0.5, 0.5>\n" + " translate <0.5, 0, 0>\n" + " }\n" + "}\n" ); +const QString c_floorCode = QString( + "plane { <0, 1, 0>, 0\n" + " pigment { checker %1 %2\n" + " scale <0.5, 0.5, 0.5>\n" + " }\n" + "}\n" ); +const QString c_lightCode = QString( + "light_source { <-2.5, 3, -1.5>, rgb <1, 1, 1> }\n" + "light_source { <3, 3, -3>, rgb <0.6, 0.6, 0.6> shadowless }\n" ); + + +const QString c_cameraCode[3] = { + QString( "camera { location <-1, 1.25, -2> right <1, 0, 0>\n" + " look_at <0.0, 0.5, 0> angle 45 }\n" ), + QString( "camera { location <-1, 2, -3> right <1, 0, 0>\n" + " look_at <0.0, 1, 0> angle 45 }\n" ), + QString( "camera { location <-2, 2.5, -4> right <1, 0, 0>\n" + " look_at <0.0, 1.5, 0> angle 45 }\n" ) +}; +const QString c_sphereCode = QString( + "sphere { <0, 0.5, 0>, 0.5 translate <0, %1, 0> }\n" ); +const QString c_cylinderCode = QString( + "cylinder { <0, 0, 0>, <0, 1, 0>, 0.5 translate <0, %1, 0> }\n" ); +const QString c_boxCode = QString( + "box { <-0.5, 0, -0.5>, <0.5, 1, 0.5> translate <0, %1, 0> }\n" ); +const QString c_globalSettingsCode = QString( + "global_settings { assumed_gamma %1 }\n" ); + +PMDialogEditBase::PMDialogEditBase( QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + m_pDisplayedObject = 0; + m_pPart = 0; + + m_pTexturePreviewWidget = 0; + m_pOutputWidget = 0; + m_pRenderWidget = 0; + m_pRenderFrame = 0; + m_pPreviewLocalBox = 0; + m_pPreviewButton = 0; + m_pOutputButton = 0; +} + +PMDialogEditBase::~PMDialogEditBase( ) +{ + if( m_pOutputWidget ) + delete m_pOutputWidget; +} + +void PMDialogEditBase::createWidgets( ) +{ + m_pTopLayout = new QBoxLayout( this, QBoxLayout::TopToBottom, + KDialog::spacingHint( ) ); + + createTopWidgets( ); + createBottomWidgets( ); + + m_pTopLayout->addStretch( ); + m_pTopLayout->activate( ); +} + +void PMDialogEditBase::createBottomWidgets( ) +{ + m_pTexturePreviewWidget = new QWidget( this ); + m_pTexturePreviewWidget->hide( ); + m_pTopLayout->addWidget( m_pTexturePreviewWidget ); +} + +bool PMDialogEditBase::saveData( ) +{ + if( isDataValid( ) ) + { + saveContents( ); + return true; + } + return false; +} + +void PMDialogEditBase::saveContents( ) +{ +} + +void PMDialogEditBase::displayObject( PMObject* o ) +{ + bool newObject = ( m_pDisplayedObject != o ); + m_pDisplayedObject = o; + PMObject* global; + PMObject* local; + + // Is object a full texture or inside a full texture + findTextures( global, local ); + if( global ) + { + // is the preview widget created? + if( !m_pRenderWidget ) + { + QVBoxLayout* vl = new QVBoxLayout( m_pTexturePreviewWidget, 0, + KDialog::spacingHint( ) ); + vl->addSpacing( 10 ); + QFrame* hline = new QFrame( m_pTexturePreviewWidget ); + hline->setFrameStyle( QFrame::HLine | QFrame::Plain ); + hline->setLineWidth( 1 ); + vl->addWidget( hline ); + vl->addWidget( new QLabel( i18n( "Texture preview:" ), m_pTexturePreviewWidget ) ); + m_pRenderFrame = new QVBox( m_pTexturePreviewWidget ); + m_pRenderFrame->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken ); + m_pRenderFrame->setLineWidth( 2 ); + m_pRenderFrame->hide( ); + vl->addWidget( m_pRenderFrame ); + + m_pRenderWidget = new PMPovrayRenderWidget( m_pRenderFrame ); + connect( m_pRenderWidget, SIGNAL( finished( int ) ), + SLOT( slotPreviewFinished( int ) ) ); + m_pPreviewLocalBox = new QCheckBox( i18n( "local" ), m_pTexturePreviewWidget ); + m_pPreviewLocalBox->setChecked( s_previewLocal ); + connect( m_pPreviewLocalBox, SIGNAL( toggled( bool ) ), + SLOT( slotPreviewLocal( bool ) ) ); + vl->addWidget( m_pPreviewLocalBox ); + + QHBoxLayout* hl = new QHBoxLayout( vl ); + m_pPreviewButton = new QPushButton( i18n( "&Preview" ), m_pTexturePreviewWidget ); + hl->addWidget( m_pPreviewButton ); + connect( m_pPreviewButton, SIGNAL( clicked( ) ), + SLOT( slotTexturePreview( ) ) ); + m_pOutputButton = new QPushButton( i18n( "Povray Output" ), m_pTexturePreviewWidget ); + hl->addWidget( m_pOutputButton ); + connect( m_pOutputButton, SIGNAL( clicked( ) ), + SLOT( slotPovrayOutput( ) ) ); + hl->addStretch( 1 ); + + m_pOutputWidget = new PMPovrayOutputWidget( ); + connect( m_pRenderWidget, SIGNAL( povrayMessage( const QString& ) ), + m_pOutputWidget, SLOT( slotText( const QString& ) ) ); + } + + m_pTexturePreviewWidget->show( ); + if( newObject ) + m_pRenderFrame->hide( ); + m_pPreviewLocalBox->setEnabled( local != global ); + m_pPreviewButton->setEnabled( true ); + } + else + { + // is the preview widget created? + if( m_pPreviewButton ) + m_pPreviewButton->setEnabled( false ); + m_pTexturePreviewWidget->hide( ); + } +} + +void PMDialogEditBase::setHelp( const QString& anchor ) +{ + m_helpTopic = anchor; +} + +void PMDialogEditBase::redisplay( ) +{ + if( m_pDisplayedObject ) + displayObject( m_pDisplayedObject ); +} + +void PMDialogEditBase::setCheckBox( QCheckBox* box, PMThreeState state ) +{ + switch( state ) + { + case PMTrue: + box->setChecked( true ); + break; + case PMFalse: + box->setChecked( false ); + break; + case PMUnspecified: + box->setNoChange( ); + break; + } +} + +PMThreeState PMDialogEditBase::checkBoxState( QCheckBox* box ) +{ + PMThreeState st = PMTrue; + switch( box->state( ) ) + { + case QCheckBox::On: + st = PMTrue; + break; + case QCheckBox::Off: + st = PMFalse; + break; + case QCheckBox::NoChange: + st = PMUnspecified; + break; + } + return st; +} + +void PMDialogEditBase::setPreviewSize( int size ) +{ + if( ( size >= 10 ) && ( size <= 400 ) ) + s_previewSize = size; +} + +void PMDialogEditBase::setPreviewAADepth( int d ) +{ + if( ( d >= 1 ) && ( d <= 9 ) ) + s_previewAADepth = d; +} + +void PMDialogEditBase::saveConfig( KConfig* cfg ) +{ + cfg->setGroup( "TexturePreview" ); + cfg->writeEntry( "Size", s_previewSize ); + cfg->writeEntry( "showSphere", s_showSphere ); + cfg->writeEntry( "showCylinder", s_showCylinder ); + cfg->writeEntry( "showBox", s_showBox ); + cfg->writeEntry( "AA", s_previewAA ); + cfg->writeEntry( "AADepth", s_previewAADepth ); + cfg->writeEntry( "AAThreshold", s_previewAAThreshold ); + cfg->writeEntry( "showWall", s_showWall ); + cfg->writeEntry( "showFloor", s_showFloor ); + cfg->writeEntry( "WallColor1", s_wallColor1 ); + cfg->writeEntry( "WallColor2", s_wallColor2 ); + cfg->writeEntry( "FloorColor1", s_floorColor1 ); + cfg->writeEntry( "FloorColor2", s_floorColor2 ); + cfg->writeEntry( "Gamma", s_previewGamma ); +} + +void PMDialogEditBase::restoreConfig( KConfig* cfg ) +{ + cfg->setGroup( "TexturePreview" ); + setPreviewSize( cfg->readNumEntry( "Size", s_previewSize ) ); + s_showSphere = cfg->readBoolEntry( "showSphere", s_showSphere ); + s_showCylinder = cfg->readBoolEntry( "showCylinder", s_showCylinder ); + s_showBox = cfg->readBoolEntry( "showBox", s_showBox ); + s_previewAA = cfg->readBoolEntry( "AA", s_previewAA ); + setPreviewAADepth( cfg->readNumEntry( "AADepth", s_previewAADepth ) ); + s_previewAAThreshold = cfg->readDoubleNumEntry( "AAThreshold", s_previewAAThreshold ); + s_showWall = cfg->readBoolEntry( "showWall", s_showWall ); + s_showFloor = cfg->readBoolEntry( "showFloor", s_showFloor ); + s_wallColor1 = cfg->readColorEntry( "WallColor1", &s_wallColor1 ); + s_wallColor2 = cfg->readColorEntry( "WallColor2", &s_wallColor2 ); + s_floorColor1 = cfg->readColorEntry( "FloorColor1", &s_floorColor1 ); + s_floorColor2 = cfg->readColorEntry( "FloorColor2", &s_floorColor2 ); + s_previewGamma = cfg->readDoubleNumEntry( "Gamma", s_previewGamma ); +} + +void PMDialogEditBase::findTextures( PMObject*& global, PMObject*& local ) const +{ + PMObject* o; + global = 0; + local = 0; + + for( o = m_pDisplayedObject; o; o = o->parent( ) ) + { + if( o->type( ) == "Material" || o->type( ) == "Interior" || + o->type( ) == "Texture" || o->type( ) == "Pigment" || + o->type( ) == "InteriorTexture" ) + { + if( !local ) + local = o; + global = o; + } + else if( o->type( ) == "Declare" ) + { + PMDeclare* d = ( PMDeclare* ) o; + if( d->declareType( ) == "Interior" || + d->declareType( ) == "Pigment" || + d->declareType( ) == "Material" ) + { + if( !local || ( local == global ) ) + local = o; + global = o; + } + else if( d->declareType( ) == "Texture" || + d->declareType( ) == "InteriorTexture" ) + { + if( o->countChildren( ) > 1 ) + { + if( !local ) + local = o; + } + else + if( !local || ( local == global ) ) + local = o; + global = o; + } + } + } +} + +void PMDialogEditBase::slotTexturePreview( ) +{ + PMObject* o; + PMObject* local = 0; + PMObject* global = 0; + + if( !m_pRenderWidget ) + return; + + findTextures( global, local ); + if( local ) + { + emit aboutToRender( ); + + if( global == local ) + o = global; + else + { + if( m_pPreviewLocalBox->isChecked( ) ) + o = local; + else + o = global; + } + + // ensure at least one object will be rendered. + if( !( s_showSphere || s_showCylinder || s_showBox ) ) + s_showSphere = true; + + int numObjects = 0; + QByteArray scene; + QBuffer buffer( scene ); + buffer.open( IO_WriteOnly ); + QTextStream str( &buffer ); + PMPovray31Format format; + PMSerializer* dev = format.newSerializer( &buffer ); + PMRenderMode mode; + PMObjectList neededDeclares, objectsToCheck; + QPtrDict objectsToSerialize( 101 ); + PMObject* link; + + // find needed declares + objectsToCheck.append( o ); + do + { + PMObjectListIterator it( objectsToCheck ); + for( ; it.current( ); ++it ) + { + PMRecursiveObjectIterator rit( it.current( ) ); + for( ; rit.current( ); ++rit ) + { + link = rit.current( )->linkedObject( ); + if( link ) + if( !neededDeclares.containsRef( link ) ) + if( !objectsToSerialize.find( link ) ) + neededDeclares.append( link ); + } + objectsToSerialize.insert( it.current( ), it.current( ) ); + } + + objectsToCheck = neededDeclares; + neededDeclares.clear( ); + } + while( objectsToCheck.count( ) > 0 ); + + // serialize all needed declares in the right order + int numDeclares = objectsToSerialize.count( ); + if( numDeclares > 0 ) + { + PMObject* otr = o; + + // find the scene + while( otr->parent( ) ) otr = otr->parent( ); + + for( otr = otr->firstChild( ); otr && ( numDeclares > 0 ); + otr = otr->nextSibling( ) ) + { + if( otr->type( ) == "Declare" ) + { + if( objectsToSerialize.find( otr ) ) + { + dev->serialize( otr ); + numDeclares--; + } + } + } + str << "\n\n"; + } + // if the previewed texture is a declare, serialize it + if( o->type( ) == "Declare" ) + dev->serialize( o ); + + // build the preview scene + str << "union {\n"; + if( s_showBox ) + { + str << c_boxCode.arg( numObjects ); + numObjects++; + } + if( s_showCylinder ) + { + str << c_cylinderCode.arg( numObjects ); + numObjects++; + } + if( s_showSphere ) + { + str << c_sphereCode.arg( numObjects ); + numObjects++; + } + + // serialize the texture + if( o->type( ) == "Declare" ) + { + PMDeclare* dec = ( PMDeclare* ) o; + if( dec->declareType( ) == "Interior" ) + str << "interior { "; + else if( dec->declareType( ) == "Texture" ) + str << "texture { "; + else if( dec->declareType( ) == "Pigment" ) + str << "pigment { "; + else if( dec->declareType( ) == "InteriorTexture" ) + str << "interior_texture { "; + else if( dec->declareType( ) == "Material" ) + str << "material { "; + else + kdError( PMArea ) << "Unhandled declare type in " + "PMDialogEditBase::slotTexturePreview\n"; + + str << dec->id( ); + str << " }\n"; + } + else + dev->serialize( o ); + str << "}\n"; + + PMColor c1, c2; + if( s_showWall ) + { + c1 = PMColor( s_wallColor1 ); + c2 = PMColor( s_wallColor2 ); + str << c_wallCode.arg( c1.serialize( true ) ).arg( c2.serialize( true ) ); + } + if( s_showFloor ) + { + c1 = PMColor( s_floorColor1 ); + c2 = PMColor( s_floorColor2 ); + str << c_floorCode.arg( c1.serialize( true ) ).arg( c2.serialize( true ) ); + } + + str << c_lightCode; + str << c_cameraCode[numObjects-1]; + str << c_globalSettingsCode.arg( s_previewGamma ); + + // Set the render mode + mode.setHeight( s_previewSize ); + mode.setWidth( s_previewSize ); + mode.setAntialiasing( s_previewAA ); + mode.setAntialiasingThreshold( s_previewAAThreshold ); + mode.setAntialiasingDepth( s_previewAADepth ); + + m_pRenderFrame->show( ); + m_pRenderFrame->setFixedSize( s_previewSize + m_pRenderFrame->frameWidth( ) * 2, + s_previewSize + m_pRenderFrame->frameWidth( ) * 2 ); + m_pRenderFrame->updateGeometry( ); + m_pTexturePreviewWidget->layout( )->activate( ); + emit sizeChanged( ); + m_pOutputWidget->slotClear( ); + m_pRenderWidget->render( scene, mode, m_pPart->url( ) ); + + delete dev; + } +} + +void PMDialogEditBase::slotPreviewLocal( bool on ) +{ + s_previewLocal = on; +} + +void PMDialogEditBase::slotPreviewFinished( int exitStatus ) +{ + if( exitStatus != 0 ) + { + KMessageBox::error( this, i18n( "Povray exited abnormally with " + "exit code %1.\n" + "See the povray output for details." ) + .arg( exitStatus ) ); + } + else if( m_pRenderWidget->povrayOutput( ).contains( "ERROR" ) ) + { + KMessageBox::error( this, i18n( "There were errors while rendering.\n" + "See the povray output for details." ) ); + } +} + +void PMDialogEditBase::slotPovrayOutput( ) +{ + if( m_pOutputWidget ) + m_pOutputWidget->show( ); +} + +#include "pmdialogeditbase.moc" diff --git a/kpovmodeler/pmdialogeditbase.h b/kpovmodeler/pmdialogeditbase.h new file mode 100644 index 00000000..547946f5 --- /dev/null +++ b/kpovmodeler/pmdialogeditbase.h @@ -0,0 +1,356 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMDIALOGEDITBASE_H +#define PMDIALOGEDITBASE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "pmobject.h" + +class QBoxLayout; +class QCheckBox; +class QLayout; +class QPushButton; +class QVBox; +class KConfig; +class PMPart; +class PMPovrayRenderWidget; +class PMPovrayOutputWidget; + +/** + * Base class for all widgets for editing object attributes. + * + * Ensures a consistent layout for all widgets. Widgets should not + * created within the constructor, but with the functions @ref createTopWidgets + * and @ref createBottomWidgets. + * + * Each subclass uses the functionality of the base class. For example all + * widgets for solid objects have the same base class that shows attributes + * of solid objects. Subclasses like the widget for the box object add their + * object specific controls. + */ +class PMDialogEditBase : public QWidget +{ + Q_OBJECT +public: + /** + * Creates a new PMDialogEditBase widget objectType is + * @ref PMObject->description( ). + * + * No widgets are created within the constructor! You have to call + * @ref createWidgets after creating a new edit widget. + */ + PMDialogEditBase( QWidget* parent, const char* name = 0 ); + /** + * Destructor + */ + virtual ~PMDialogEditBase( ); + + /** + * Creates child widgets. + * + * This function is necessary because virtual functions do not work + * properly inside the constructor. + * + * Calls @ref createTopWidgets and @ref createBottomWidgets + */ + void createWidgets( ); + + /** + * Displays the object o. + * Always call displayObject( ) of the base class after displaying the + * objects data + */ + virtual void displayObject( PMObject* o ); + + /** + * returns a pointer to the displayed object + */ + PMObject* displayedObject( ) const { return m_pDisplayedObject; } + + /** + * Function that is called, when the "Apply" button is pressed. + * + * Returns true if successful + */ + bool saveData( ); + + /** + * Called, when the contents have to be checked. + * + * Display an error message and return false, if the data is invalid. + * Otherwise return isDataValid( ) of the base class. + */ + virtual bool isDataValid( ) { return true; } + + /** + * Returns the help topic + */ + const QString& helpTopic( ) { return m_helpTopic; } + + /** + * Discards changes and redisplays the object + */ + void redisplay( ); + + /** + * Called when the control point selection has changed + */ + virtual void updateControlPointSelection( ) { }; + + /** + * Sets the check box to state s + */ + static void setCheckBox( QCheckBox* box, PMThreeState s ); + /** + * Gets the state of the checkbox + */ + static PMThreeState checkBoxState( QCheckBox* box ); + + /** + * Sets the part + */ + void setPart( PMPart* p ) { m_pPart = p; } + /** + * Returns the part + */ + PMPart* part( ) const { return m_pPart; } + + /** + * Returns the size of the texture preview widget + */ + static int previewSize( ) { return s_previewSize; } + /** + * Sets the texture preview size + */ + static void setPreviewSize( int size ); + /** + * Returns true if a sphere should be renderend + */ + static bool previewShowSphere( ) { return s_showSphere; } + /** + * Enable/disable the sphere in the texture preview widget + */ + static void previewShowSphere( bool show ) { s_showSphere = show; } + /** + * Returns true if a cylinder should be renderend + */ + static bool previewShowCylinder( ) { return s_showCylinder; } + /** + * Enable/disable the cylinder in the texture preview widget + */ + static void previewShowCylinder( bool show ) { s_showCylinder = show; } + /** + * Returns true if a box should be renderend + */ + static bool previewShowBox( ) { return s_showBox; } + /** + * Enable/disable the box in the texture preview widget + */ + static void previewShowBox( bool show ) { s_showBox = show; } + + /** + * Returns true if AA is enabled + */ + static bool isPreviewAAEnabled( ) { return s_previewAA; } + /** + * Enables/disables AA + */ + static void setPreviewAAEnabled( bool enable ) { s_previewAA = enable; } + /** + * Returns the AA depth + */ + static int previewAADepth( ) { return s_previewAADepth; } + /** + * Sets the AA depth + */ + static void setPreviewAADepth( int d ); + /** + * Returns the AA threshold + */ + static double previewAAThreshold( ) { return s_previewAAThreshold; } + /** + * Sets the AA threshold + */ + static void setPreviewAAThreshold( double t ) { s_previewAAThreshold = t; } + + /** + * Returns true if the floor should be rendered + */ + static bool previewShowFloor( ) { return s_showFloor; } + /** + * Enables/disables the floor + */ + static void previewShowFloor( bool show ) { s_showFloor = show; } + /** + * Returns true if the wall should be rendered + */ + static bool previewShowWall( ) { return s_showWall; } + /** + * Enables/disables the wall + */ + static void previewShowWall( bool show ) { s_showWall = show; } + /** + * Returns the first wall color + */ + static QColor previewWallColor1( ) { return s_wallColor1; } + /** + * Sets the first wall color + */ + static void setPreviewWallColor1( const QColor& c ) { s_wallColor1 = c; } + /** + * Returns the second wall color + */ + static QColor previewWallColor2( ) { return s_wallColor2; } + /** + * Sets the second wall color + */ + static void setPreviewWallColor2( const QColor& c ) { s_wallColor2 = c; } + /** + * Returns the first floor color + */ + static QColor previewFloorColor1( ) { return s_floorColor1; } + /** + * Sets the first floor color + */ + static void setPreviewFloorColor1( const QColor& c ) { s_floorColor1 = c; } + /** + * Returns the second floor color + */ + static QColor previewFloorColor2( ) { return s_floorColor2; } + /** + * Sets the second floor color + */ + static void setPreviewFloorColor2( const QColor& c ) { s_floorColor2 = c; } + /** + * Returns the local flag for texture preview + */ + static bool previewLocal( ) { return s_previewLocal; } + /** + * Sets the local flag + */ + static void setPreviewLocal( bool l ) { s_previewLocal = l; } + /** + * Returns the gamma value for the texture preview + */ + static double previewGamma( ) { return s_previewGamma; } + /** + * Sets the gamma value for the texture preview + */ + static void setPreviewGamma( double g ) { s_previewGamma = g; } + + static void saveConfig( KConfig* cfg ); + static void restoreConfig( KConfig* cfg ); +protected: + /** + * Sets the help topic + * @param anchor Defined anchor in your docbook sources + */ + void setHelp( const QString& anchor ); + + /** + * Create widgets here, that should be placed on top of the widgets + * of the sub class. + * + * First call the function of the base class, then create and append + * the widgets to the top layout. + */ + virtual void createTopWidgets( ) { }; + + /** + * Create widgets here, that should be placed under the widgets + * of the sub class. + * + * First create and append the widgets to the top layout, then + * call the function of the base class + */ + virtual void createBottomWidgets( ); + + /** + * Save here the class specific data and call saveContents( ) + * of the base class + */ + virtual void saveContents( ); + + /** + * Returns a pointer to the top layout + */ + QBoxLayout* topLayout( ) const { return m_pTopLayout; } + +protected slots: + void slotTexturePreview( ); + void slotPreviewLocal( bool on ); + void slotPreviewFinished( int exitStatus ); + void slotPovrayOutput( ); + +signals: + /** + * Emit this, if data has changed + */ + void dataChanged( ); + /** + * Emit this, if the size of the widget has changed + */ + void sizeChanged( ); + /** + * Emit this, if the control point selection has changed + */ + void controlPointSelectionChanged( ); + /** + * Emit this signal, before the displayed object or texture is rendered + */ + void aboutToRender( ); +private: + void findTextures( PMObject*& global, PMObject*& local ) const; + + PMObject* m_pDisplayedObject; + QBoxLayout* m_pTopLayout; + QString m_helpTopic; + PMPart* m_pPart; + QWidget* m_pTexturePreviewWidget; + PMPovrayRenderWidget* m_pRenderWidget; + PMPovrayOutputWidget* m_pOutputWidget; + QVBox* m_pRenderFrame; + QCheckBox* m_pPreviewLocalBox; + QPushButton* m_pPreviewButton; + QPushButton* m_pOutputButton; + + static int s_previewSize; + static bool s_showSphere; + static bool s_showCylinder; + static bool s_showBox; + static bool s_previewAA; + static int s_previewAADepth; + static double s_previewAAThreshold; + static bool s_showFloor; + static bool s_showWall; + static QColor s_wallColor1, s_wallColor2; + static QColor s_floorColor1, s_floorColor2; + static bool s_previewLocal; + static double s_previewGamma; +}; + + +#endif diff --git a/kpovmodeler/pmdialogview.cpp b/kpovmodeler/pmdialogview.cpp new file mode 100644 index 00000000..f88a0272 --- /dev/null +++ b/kpovmodeler/pmdialogview.cpp @@ -0,0 +1,441 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmdialogview.h" +#include "pmdialogeditbase.h" +#include "pmallobjects.h" +#include "pmdebug.h" +#include "pmfactory.h" +#include "pmdatachangecommand.h" +#include "pmpart.h" +#include "pmdocumentationmap.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +PMDialogEditContent::PMDialogEditContent( QWidget* parent, const char* name ) + : QScrollView( parent, name ) +{ + m_pContents = 0; + setVScrollBarMode( AlwaysOff ); + setHScrollBarMode( AlwaysOff ); + setFrameStyle( Panel | Sunken ); + setLineWidth( 1 ); + setResizePolicy( Manual ); +} + +void PMDialogEditContent::setContents( QWidget* wid ) +{ + if( m_pContents ) + removeChild( m_pContents ); + + m_pContents = wid; + + if( m_pContents ) + { + addChild( m_pContents ); + calculateSize( ); + } +} + +void PMDialogEditContent::calculateSize( ) +{ + int fw = lineWidth( ) * 2; + if( m_pContents ) + { + QSize newSize = m_pContents->minimumSizeHint( ); + + setVScrollBarMode( AlwaysOff ); + setHScrollBarMode( AlwaysOff ); + setMargins( 0, 0, 0, 0 ); + + if( width( ) - fw < newSize.width( ) ) + { + setHScrollBarMode( AlwaysOn ); + + if( ( height( ) - horizontalScrollBar( )->height( ) - fw ) + < newSize.height( ) ) + setVScrollBarMode( AlwaysOn ); + else + newSize.setHeight( height( ) - horizontalScrollBar( )->height( ) - 2 ); + } + else if( height( ) - fw < newSize.height( ) ) + { + setVScrollBarMode( AlwaysOn ); + + if( ( width( ) - verticalScrollBar( )->width( ) - fw ) + < newSize.width( ) ) + setHScrollBarMode( AlwaysOn ); + else + newSize.setWidth( width( ) - verticalScrollBar( )->width( ) - fw ); + } + else + { + newSize.setWidth( width( ) - fw ); + newSize.setHeight( height( ) - fw ); + } + + resizeContents( newSize.width( ), newSize.height( ) ); + m_pContents->resize( newSize ); + } +} + +void PMDialogEditContent::resizeEvent( QResizeEvent* /* ev */ ) +{ + calculateSize( ); +} + +PMDialogView::PMDialogView( PMPart* part, QWidget* parent, const char* name ) + : PMViewBase( parent, name ) +{ + m_pDisplayedWidget = 0; + m_unsavedData = false; + m_pHelper = new PMDialogEditContent( this ); + m_pHelper->show( ); + m_pPart = part; + + m_pLayout = new QVBoxLayout( this, KDialog::marginHint( ), + KDialog::spacingHint( ) ); + + QHBoxLayout* labelLayout = new QHBoxLayout( m_pLayout ); + m_pPixmapLabel = new QLabel( this ); + m_pObjectTypeLabel = new QLabel( this ); + labelLayout->addWidget( m_pPixmapLabel ); + labelLayout->addWidget( m_pObjectTypeLabel ); + labelLayout->addStretch( ); + + m_pLayout->addWidget( m_pHelper, 2 ); + m_pLayout->addStretch( ); + + QHBoxLayout* buttonLayout = new QHBoxLayout( m_pLayout ); + m_pHelpButton = new KPushButton( KStdGuiItem::help(), this ); + buttonLayout->addWidget( m_pHelpButton ); + connect( m_pHelpButton, SIGNAL( clicked( ) ), this, SLOT( slotHelp( ) ) ); + m_pHelpButton->setEnabled( false ); + + m_pApplyButton = new KPushButton( KStdGuiItem::apply(), this ); + buttonLayout->addWidget( m_pApplyButton ); + connect( m_pApplyButton, SIGNAL( clicked( ) ), this, SLOT( slotApply( ) ) ); + m_pApplyButton->setEnabled( false ); + + buttonLayout->addStretch( ); + + m_pCancelButton = new KPushButton( KStdGuiItem::cancel(), this ); + buttonLayout->addWidget( m_pCancelButton ); + connect( m_pCancelButton, SIGNAL( clicked( ) ), this, SLOT( slotCancel( ) ) ); + m_pCancelButton->setEnabled( false ); + + m_pLayout->activate( ); + + connect( part, SIGNAL( refresh( ) ), SLOT( slotRefresh( ) ) ); + connect( part, SIGNAL( objectChanged( PMObject*, const int, QObject* ) ), + SLOT( slotObjectChanged( PMObject*, const int, QObject* ) ) ); + connect( part, SIGNAL( clear( ) ), SLOT( slotClear( ) ) ); + connect( part, SIGNAL( aboutToRender( ) ), SLOT( slotAboutToRender( ) ) ); + connect( part, SIGNAL( aboutToSave( ) ), SLOT( slotAboutToRender( ) ) ); + connect( this, SIGNAL( objectChanged( PMObject*, const int, QObject* ) ), + part, SLOT( slotObjectChanged( PMObject*, const int, QObject* ) ) ); + + displayObject( m_pPart->activeObject( ) ); +} + + + +PMDialogView::~PMDialogView( ) +{ + emit destroyed( this ); +} + +void PMDialogView::slotObjectChanged( PMObject* obj, const int mode, QObject* sender ) +{ + if( sender == this ) + return; + if( mode & PMCNewSelection ) + { + if( m_pDisplayedWidget ) + if( m_pDisplayedWidget->displayedObject( ) ) + if( m_unsavedData ) + if( shouldSaveData( ) ) + slotApply( ); + + displayObject( obj ); + } + if( mode & ( PMCSelected | PMCDeselected ) ) + { + if( m_pDisplayedWidget ) + if( m_pDisplayedWidget->displayedObject( ) ) + if( m_unsavedData ) + if( shouldSaveData( ) ) + slotApply( ); + + displayObject( 0 ); + } + if( mode & PMCRemove ) + { + if( m_pDisplayedWidget ) + { + if( m_pDisplayedWidget->displayedObject( ) == obj ) + { + displayObject( 0 ); + } + } + } + if( mode & ( PMCData | PMCDescription ) ) + { + if( m_pDisplayedWidget ) + { + if( m_pDisplayedWidget->displayedObject( ) ) + { + if( m_pDisplayedWidget->displayedObject( ) == obj ) + { + displayObject( obj, mode & PMCDescription ); + m_unsavedData = false; + m_pApplyButton->setEnabled( false ); + m_pCancelButton->setEnabled( false ); + } + } + } + } + if( mode & PMCControlPointSelection ) + { + if( m_pDisplayedWidget ) + m_pDisplayedWidget->updateControlPointSelection( ); + } +} + +bool PMDialogView::shouldSaveData( ) +{ + return ( KMessageBox::questionYesNo( + this, i18n( "This object was modified.\n\nSave changes?" ), + i18n( "Unsaved Changes" ), KStdGuiItem::save(), KStdGuiItem::discard() ) == KMessageBox::Yes ); +} + +void PMDialogView::slotRefresh( ) +{ + if( m_pDisplayedWidget ) + m_pDisplayedWidget->redisplay( ); +} + +void PMDialogView::slotClear( ) +{ + displayObject( 0 ); +} + +void PMDialogView::slotApply( ) +{ + if( m_pDisplayedWidget ) + { + PMObject* obj = m_pDisplayedWidget->displayedObject( ); + if( obj ) + { + if( m_pDisplayedWidget->isDataValid( ) ) + { + PMDataChangeCommand* cmd; + + obj->createMemento( ); + m_pDisplayedWidget->saveData( ); + cmd = new PMDataChangeCommand( obj->takeMemento( ) ); + m_pPart->executeCommand( cmd ); + + m_pApplyButton->setEnabled( false ); + m_pCancelButton->setEnabled( false ); + m_unsavedData = false; + } + } + } +} + +void PMDialogView::slotHelp( ) +{ + if( m_pDisplayedWidget && m_pDisplayedWidget->displayedObject( ) ) + { + QString url = PMDocumentationMap::theMap( )->documentation( + m_pDisplayedWidget->displayedObject( )->className( ) ); + if( !url.isEmpty( ) ) + { + // Instead of calling invokeBrowser run konqueror directly. + // invokeBrowser was ignoring html anchors. + url = "konqueror " + KProcess::quote(url); + KRun::runCommand( url ); + } + } +} + +void PMDialogView::slotCancel( ) +{ + m_pCancelButton->setEnabled( false ); + m_pApplyButton->setEnabled( false ); + m_unsavedData = false; + + if( m_pDisplayedWidget ) + { + bool b = m_pDisplayedWidget->signalsBlocked( ); + m_pDisplayedWidget->blockSignals( true ); + m_pDisplayedWidget->redisplay( ); + m_pDisplayedWidget->blockSignals( b ); + slotSizeChanged( ); + } +} + +void PMDialogView::slotDataChanged( ) +{ +// kdDebug( PMArea ) << "PMDialogView::slotDataChanged\n"; + m_pApplyButton->setEnabled( true ) ; + m_pCancelButton->setEnabled( true ); + + m_unsavedData = true; +} + +void PMDialogView::slotSizeChanged( ) +{ + // force recalculating of the layout + if( m_pDisplayedWidget ) + if( m_pDisplayedWidget->layout( ) ) + m_pDisplayedWidget->layout( )->activate( ); + m_pHelper->calculateSize( ); +} + +void PMDialogView::slotControlPointSelectionChanged( ) +{ + if( m_pDisplayedWidget && m_pDisplayedWidget->displayedObject( ) ) + emit objectChanged( m_pDisplayedWidget->displayedObject( ), + PMCControlPointSelection, this ); +} + +void PMDialogView::displayObject( PMObject* obj, bool updateDescription ) +{ + PMDialogEditBase* old = 0; + + if( !obj ) + { + if( m_pDisplayedWidget ) + old = m_pDisplayedWidget; + + m_pDisplayedWidget = new PMDialogEditBase( m_pHelper->viewport( ) ); + m_pDisplayedWidget->createWidgets( ); + m_pHelper->setContents( m_pDisplayedWidget ); + m_pPixmapLabel->setText( "" ); + m_pObjectTypeLabel->setText( "" ); + } + else + { + bool newWidget = true; + if( m_pDisplayedWidget ) + { + if( m_pDisplayedWidget->displayedObject( ) ) + { + if( obj->type( ) == m_pDisplayedWidget->displayedObject( )->type( ) ) + { + // current widget displays object of the same type + // reuse the widget + newWidget = false; + } + } + } + + if( newWidget ) + { + // first create the new widget, then delete the old one. + if( m_pDisplayedWidget ) + old = m_pDisplayedWidget; + m_pDisplayedWidget = obj->editWidget( m_pHelper->viewport( ) ); + m_pDisplayedWidget->setPart( m_pPart ); + m_pDisplayedWidget->createWidgets( ); + m_pHelper->setContents( m_pDisplayedWidget ); + + if( m_pDisplayedWidget ) + { + connect( m_pDisplayedWidget, SIGNAL( dataChanged( ) ), + this, SLOT( slotDataChanged( ) ) ); + connect( m_pDisplayedWidget, SIGNAL( sizeChanged( ) ), + this, SLOT( slotSizeChanged( ) ) ); + connect( m_pDisplayedWidget, SIGNAL( aboutToRender( ) ), + this, SLOT( slotAboutToRender( ) ) ); + connect( m_pDisplayedWidget, + SIGNAL( controlPointSelectionChanged( ) ), + SLOT( slotControlPointSelectionChanged( ) ) ); + + } + } + } + + if( m_pDisplayedWidget ) + { + bool b = m_pDisplayedWidget->signalsBlocked( ); + m_pDisplayedWidget->blockSignals( true ); + m_pDisplayedWidget->displayObject( obj ); + m_pDisplayedWidget->blockSignals( b ); + + m_pHelpButton->setEnabled( !m_pDisplayedWidget->helpTopic( ).isNull() ); + + if( !m_pDisplayedWidget->isVisible( ) ) + m_pDisplayedWidget->show( ); + if( obj && updateDescription ) + { + m_pPixmapLabel->setPixmap( SmallIcon( obj->pixmap( ), PMFactory::instance( ) ) ); + m_pObjectTypeLabel->setText( obj->description( ) ); + } + slotSizeChanged( ); + } + + if( old ) + delete old; + + m_pApplyButton->setEnabled( false ); + m_pCancelButton->setEnabled( false ); + m_pHelpButton->setEnabled( !PMDocumentationMap::theMap( ) + ->povrayDocumentationPath( ).isEmpty( ) ); + + m_unsavedData = false; +} + +void PMDialogView::keyPressEvent( QKeyEvent* ev ) +{ + if( ( ev->key( ) == Key_Return ) || ( ev->key( ) == Key_Enter ) ) + slotApply( ); +} + +void PMDialogView::slotAboutToRender( ) +{ + if( m_unsavedData ) + if( shouldSaveData( ) ) + slotApply( ); +} + +QString PMDialogView::description( ) const +{ + return i18n( "Object Properties" ); +} + +QString PMDialogViewFactory::description( ) const +{ + return i18n( "Object Properties" ); +} + +#include "pmdialogview.moc" diff --git a/kpovmodeler/pmdialogview.h b/kpovmodeler/pmdialogview.h new file mode 100644 index 00000000..aef224eb --- /dev/null +++ b/kpovmodeler/pmdialogview.h @@ -0,0 +1,163 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMDIALOGEDITVIEW_H +#define PMDIALOGEDITVIEW_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "pmviewbase.h" +#include "pmviewfactory.h" + +class PMDialogEditBase; +class PMObject; +class PMPart; +class QGroupBox; +class QBoxLayout; +class QLabel; + +/** + * Helper class for @ref PMDialogView + */ +class PMDialogEditContent : public QScrollView +{ + Q_OBJECT +public: + PMDialogEditContent( QWidget* parent, const char* name = 0 ); + void setContents( QWidget* wid ); + void calculateSize( ); +protected: + void resizeEvent( QResizeEvent* ); +private: + QWidget* m_pContents; +}; + +/** + * View to display and modify attributes of objects. + * + * This class creates the corresponding widget + * (subclass of @ref PMDialogEditBase) for the active object and + * displays it. + */ +class PMDialogView : public PMViewBase +{ + Q_OBJECT +public: + /** + * Creates a new PMDialogView widget + */ + PMDialogView( PMPart* part, QWidget* parent, const char* name = 0 ); + /** + * Deletes the widget + */ + ~PMDialogView( ); + + /** */ + virtual QString viewType( ) const { return QString( "dialogview" ); } + /** */ + virtual QString description( ) const; + +public slots: + /** + * Called when an object is changed. + * Mode is a bit combination of @ref PMChange constants + */ + void slotObjectChanged( PMObject* obj, const int mode, QObject* sender ); + /** + * Called before the scene is rendered + */ + void slotAboutToRender( ); + /** + * Called when the whole documents contents have changed + */ + void slotRefresh( ); + /** + * Clears all data + */ + void slotClear( ); +signals: + /** + * Signal that is emitted when an object is changed. + * Mode is a bit combination of @ref PMChange constants. + */ + void objectChanged( PMObject* obj, const int mode, QObject* sender ); + /** + * Emitted in the destructor + */ + void destroyed( PMDialogView* v ); + +protected: + virtual void keyPressEvent( QKeyEvent* ); + +private slots: + void slotApply( ); + void slotHelp( ); + void slotCancel( ); + void slotDataChanged( ); + void slotSizeChanged( ); + void slotControlPointSelectionChanged( ); + +private: + /** + * Asks the user to save unsaved data in the displayed widget + */ + bool shouldSaveData( ); + /** + * Displays the object + */ + void displayObject( PMObject* obj, bool updateDescription = true ); + + PMDialogEditBase* m_pDisplayedWidget; + QBoxLayout* m_pLayout; + + KPushButton* m_pApplyButton; + KPushButton* m_pCancelButton; + KPushButton* m_pHelpButton; + + QLabel* m_pPixmapLabel; + QLabel* m_pObjectTypeLabel; + + PMDialogEditContent* m_pHelper; + + bool m_unsavedData; + PMPart* m_pPart; +}; + +/** + * Factory class for dialog views + */ +class PMDialogViewFactory : public PMViewTypeFactory +{ +public: + PMDialogViewFactory( ) { } + virtual QString viewType( ) const { return QString( "dialogview" ); } + virtual QString description( ) const; + virtual QString iconName( ) const { return QString( "pmdialogview" ); } + virtual PMViewBase* newInstance( QWidget* parent, PMPart* part ) const + { + return new PMDialogView( part, parent ); + } +}; + +#endif diff --git a/kpovmodeler/pmdisc.cpp b/kpovmodeler/pmdisc.cpp new file mode 100644 index 00000000..d276e541 --- /dev/null +++ b/kpovmodeler/pmdisc.cpp @@ -0,0 +1,440 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Leonardo Skorianez + email : lsk@if.ufrj.br + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmdisc.h" + +#include "pmxmlhelper.h" +#include "pmboxedit.h" +#include "pmmemento.h" +#include "pmdistancecontrolpoint.h" +#include "pmvectorcontrolpoint.h" +#include "pm3dcontrolpoint.h" +#include "pmdefaults.h" + +#include + +#include "pmdiscedit.h" + +const double defaultDiscRadius = 1.0; +const double defaultDiscHoleRadius = 0.0; +const PMVector defaultDiscCenter = PMVector ( 0.0, 0.0, 0.0 ); +const PMVector defaultDiscNormal = PMVector ( 0.0, 1.0, 0.0 ); + +/** default disc structure */ +PMViewStructure* PMDisc::s_pDefaultViewStructure = 0; +int PMDisc::s_numSteps = c_defaultDiscSteps; +int PMDisc::s_parameterKey = 0; + +PMDefinePropertyClass( PMDisc, PMDiscProperty ); + +PMMetaObject* PMDisc::s_pMetaObject = 0; +PMObject* createNewDisc( PMPart* part ) +{ + return new PMDisc( part ); +} + +PMDisc::PMDisc( PMPart* part ) + : Base( part ) +{ + m_center = defaultDiscCenter; + m_normal = defaultDiscNormal; + m_radius = defaultDiscRadius; + m_hradius = defaultDiscHoleRadius; +} + +PMDisc::PMDisc( const PMDisc& d ) + : Base( d ) +{ + m_center = d.m_center; + m_normal = d.m_normal; + m_radius = d.m_radius; + m_hradius = d.m_hradius; +} + + +PMDisc::~PMDisc( ) +{ +} + +QString PMDisc::description( ) const +{ + return i18n( "disc" ); +} + +void PMDisc::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "center", m_center.serializeXML( ) ); + e.setAttribute( "normal", m_normal.serializeXML( ) ); + e.setAttribute( "radius", m_radius ); + e.setAttribute( "hole_radius", m_hradius ); + Base::serialize( e, doc ); +} + +void PMDisc::readAttributes( const PMXMLHelper& h ) +{ + m_center = h.vectorAttribute( "center", defaultDiscCenter ); + m_normal = h.vectorAttribute( "normal", defaultDiscNormal ); + m_radius = h.doubleAttribute( "radius", defaultDiscRadius ); + m_hradius = h.doubleAttribute( "hole_radius", defaultDiscHoleRadius ); + Base::readAttributes( h ); +} + +PMMetaObject* PMDisc::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Disc", Base::metaObject( ), + createNewDisc ); + s_pMetaObject->addProperty( + new PMDiscProperty( "center", &PMDisc::setCenter, &PMDisc::center ) ); + s_pMetaObject->addProperty( + new PMDiscProperty( "normal", &PMDisc::setNormal, &PMDisc::normal ) ); + s_pMetaObject->addProperty( + new PMDiscProperty( "radius", &PMDisc::setRadius, &PMDisc::radius ) ); + s_pMetaObject->addProperty( + new PMDiscProperty( "holeRadius", &PMDisc::setHoleRadius, &PMDisc::holeRadius ) ); + } + return s_pMetaObject; +} + +void PMDisc::setCenter( const PMVector& c ) +{ + if( c != m_center ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCenterID, m_center ); + + m_center = c; + m_center.resize( 3 ); + + setViewStructureChanged( ); + } +} + +void PMDisc::setNormal( const PMVector& p ) +{ + if( p != m_normal ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMNormalID, m_normal ); + + m_normal = p; + m_normal.resize( 3 ); + + setViewStructureChanged( ); + } +} + +void PMDisc::setRadius( double radius ) +{ + if( m_radius != radius ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRadiusID, m_radius ); + + if( radius <= m_hradius ) + m_radius = m_hradius; + else + m_radius = radius; + + setViewStructureChanged( ); + } +} + +void PMDisc::setHoleRadius( double hradius ) +{ + if( m_hradius != hradius ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMHRadiusID, m_hradius ); + + if( hradius >= m_radius ) + m_hradius = m_radius; + else if( hradius <= 0.0 ) + m_hradius = 0.0; + else + m_hradius = hradius; + + setViewStructureChanged( ); + } +} + +PMDialogEditBase* PMDisc::editWidget( QWidget* parent ) const +{ + return new PMDiscEdit( parent ); +} + +void PMDisc::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMCenterID: + setCenter( data->vectorData( ) ); + break; + case PMNormalID: + setNormal( data->vectorData( ) ); + break; + case PMRadiusID: + setRadius( data->doubleData( ) ); + break; + case PMHRadiusID: + setHoleRadius( data->doubleData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMDisc::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + +bool PMDisc::isDefault( ) +{ + if( ( m_center == defaultDiscCenter ) && ( m_normal == defaultDiscNormal ) + && ( m_radius == defaultDiscRadius ) && ( m_hradius == defaultDiscHoleRadius ) + && globalDetail( ) ) + return true; + return false; +} + +void PMDisc::createViewStructure( ) +{ + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultViewStructure ( ) ); + m_pViewStructure->points( ).detach( ); + } + + int steps = (int)( ( (float)s_numSteps / 2 ) * ( displayDetail( ) + 1 ) ); + unsigned size = steps * 2; + + if( size != m_pViewStructure->points( ).size( ) ) + { + m_pViewStructure->points( ).resize( size ); + m_pViewStructure->lines( ).detach( ); + m_pViewStructure->lines( ).resize( size ); + createLines( m_pViewStructure->lines( ), steps ); + } + createPoints( m_pViewStructure->points( ), m_center, m_normal, m_radius, m_hradius, steps ); +} + +PMViewStructure* PMDisc::defaultViewStructure( ) const +{ + if( !s_pDefaultViewStructure || s_pDefaultViewStructure->parameterKey( ) != viewStructureParameterKey( ) ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + int steps = (int)( ( (float)s_numSteps / 2 ) * ( globalDetailLevel( ) + 1 ) ); + s_pDefaultViewStructure = new PMViewStructure( steps * 2 , steps * 2 ); + + createPoints( s_pDefaultViewStructure->points( ), defaultDiscCenter, defaultDiscNormal, + defaultDiscRadius, defaultDiscHoleRadius, steps ); + + createLines( s_pDefaultViewStructure->lines( ), steps ); + } + return s_pDefaultViewStructure; +} + +void PMDisc::createLines( PMLineArray& lines, int steps ) +{ + int i; + for( i = 0; i < ( steps - 1) ; i++ ) + { + lines[ i ] = PMLine( i, i + 1 ); + lines[ i + steps ] = PMLine( i + steps, i + steps + 1 ); + } + lines[ i ] = PMLine( i , 0 ); + lines[i + steps] = PMLine( i + steps, steps ); +} + +void PMDisc::createPoints( PMPointArray& points, const PMVector& center, + const PMVector& normal, double radius , double hradius, int steps ) +{ + PMVector pv = normal; + double pl = pv.abs( ); + if( approxZero( pl ) ) + pv = PMVector( 0.0 , 1.0 , 0.0 ); + else + pv /= pl; + + double angle = ( 2.0 * M_PI ) / ( double ) steps; + PMMatrix rotation = PMMatrix::rotation( pv , angle ); + PMVector endP = pv.orthogonal( ); + + for( int i = 0 ; i < steps ; i++ ) + { + points[ i ] = PMPoint( ( endP * radius ) + center ); + points[ i + steps ] = PMPoint( ( endP * hradius ) + center ); + endP = rotation * endP; + } +} + +void setVectorBase( PMVector pn , PMVector& vn , PMVector& v1, PMVector& v2 ) +{ + double pl = pn.abs( ); + if( approxZero( pl ) ) + vn = PMVector( 0.0 , 1.0 , 0.0 ); + else + vn = ( pn / pl ); + + v1 = vn.orthogonal( ); + v2 = PMVector::cross( vn, v1 ); +} + +void PMDisc::controlPoints( PMControlPointList & list ) +{ + PMVector vetN , vet1 , vet2 ; + setVectorBase( m_normal , vetN , vet1 , vet2 ); + + PM3DControlPoint* pb = new PM3DControlPoint( m_center, PMCenterID, i18n( "Center" ) ); + list.append( pb ); + + PMDistanceControlPoint* d; + d = new PMDistanceControlPoint( pb , vet1, m_radius, PMRadiusID, i18n( "Radius (1)" ) ); + list.append( d ); + d = new PMDistanceControlPoint( pb , vet2, m_radius, PMRadiusID, i18n( "Radius (2)" ) ); + list.append( d ); + d = new PMDistanceControlPoint( pb , vet1, m_hradius, PMHRadiusID, i18n( "Hole Radius (1)" ) ); + list.append( d ); + d = new PMDistanceControlPoint( pb , vet2, m_hradius, PMHRadiusID, i18n( "Hole Radius (2)" ) ); + list.append( d ); + + list.append( new PMVectorControlPoint( pb, m_normal, PMNormalID, i18n( "Normal" ) ) ); +} + +void PMDisc::controlPointsChanged( PMControlPointList & list ) +{ + PMControlPoint* p; + bool radius1Changed = false; + bool radius2Changed = false; + bool pointChanged = false; + PMVector pt; + + for( p = list.first( ); p; p = list.next( ) ) + { + if( p->changed( ) ) + { + switch( p->id( ) ) + { + case PMCenterID: + pt =( (PM3DControlPoint* ) p)->point( ) ; + setCenter( pt ); + pointChanged = true; + break; + case PMNormalID: + setNormal( ( ( (PM3DControlPoint* ) p)->point( ) ) ); + pointChanged = true; + break; + case PMRadiusID: + setRadius( ( ( PMDistanceControlPoint *) p )->distance( ) ); + radius1Changed = true; + break; + case PMHRadiusID: + setHoleRadius( ( ( PMDistanceControlPoint *) p )->distance( ) ); + radius2Changed = true; + break; + default: + kdError( PMArea ) << "Wrong ID in PMDisc::controlPointsChanged\n"; + break; + } + } + } + + if( radius1Changed ) + for( p = list.first( ); p; p = list.next( ) ) + if( p->id( ) == PMRadiusID ) + ( ( PMDistanceControlPoint *) p)->setDistance( m_radius ); + + if( radius2Changed ) + for( p = list.first( ); p; p = list.next( ) ) + if( p->id( ) == PMHRadiusID ) + ( ( PMDistanceControlPoint *) p)->setDistance( m_hradius ); + + if( pointChanged ) + { + PMVector vetN, vet1, vet2; + setVectorBase( m_normal , vetN, vet1, vet2 ); + + bool firstPoint1 = true; + bool firstPoint2 = true; + + for( p = list.first( ); p; p = list.next( ) ) + { + if( p->id( ) == PMRadiusID ) + { + if( firstPoint1 ) + { + ( ( PMDistanceControlPoint *) p)->setDirection( vet1 ); + firstPoint1 = false; + } + else + ( ( PMDistanceControlPoint *) p)->setDirection( vet2 ); + } + if( p->id( ) == PMHRadiusID ) + { + if( firstPoint2 ) + { + ( ( PMDistanceControlPoint *) p)->setDirection( vet1 ); + firstPoint2 = false; + } + else + ( ( PMDistanceControlPoint *) p)->setDirection( vet2 ); + } + } + } +} + +void PMDisc::setSteps( int s ) +{ + if( s >= 4 ) + { + s_numSteps = s; + if( s_pDefaultViewStructure ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + } + } + else + kdDebug( PMArea ) << "PMDisc::setSteps: S must be greater than 3\n"; + s_parameterKey++; +} + +void PMDisc::cleanUp( ) const +{ + if( s_pDefaultViewStructure ) + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} diff --git a/kpovmodeler/pmdisc.h b/kpovmodeler/pmdisc.h new file mode 100644 index 00000000..35cb0081 --- /dev/null +++ b/kpovmodeler/pmdisc.h @@ -0,0 +1,180 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Leonardo Skorianez + email : lsk@if.ufrj.br + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMDISC_H +#define PMDISC_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmgraphicalobject.h" +#include "pmvector.h" +#include "pmviewstructure.h" + +/** + * Class for povray disc + */ + +class PMDisc : public PMGraphicalObject +{ + typedef PMGraphicalObject Base; +public: + /** + * Creates a disc + */ + PMDisc( PMPart* part ); + /** + * Copy constructor + */ + PMDisc( const PMDisc& d ); + + /** + * Deletes the disc + */ + virtual ~PMDisc( ); + + /** */ + virtual PMObject* copy( ) const { return new PMDisc( *this ); } + + /** */ + virtual QString description( ) const; + /** */ + virtual PMMetaObject* metaObject( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMDiscEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmdisc" ); } + + /** + * Return the center + */ + PMVector center( ) const { return m_center; } + /** + * Sets center + */ + void setCenter( const PMVector& c ); + /** + * Return the normal + */ + PMVector normal( ) const { return m_normal; } + /** + * Sets normal + */ + void setNormal( const PMVector& p ); + /** + * Return the radius + */ + double radius( ) const { return m_radius; } + /** + * Sets the radius + */ + void setRadius( double radius ); + /** + * Return the hole radius + */ + double holeRadius( ) const { return m_hradius; } + /** + * Sets the hole radius + */ + void setHoleRadius( double hradius ); + + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual void controlPoints( PMControlPointList& list ); + /** */ + virtual void controlPointsChanged( PMControlPointList& list ); + /** */ + virtual bool hasDisplayDetail( ) const { return true; } + + /** + * Returns the number of lines for rendering + */ + static int steps( ) { return s_numSteps; } + /** + * Sets the number of lines for rendering + */ + static void setSteps( int s ); + /** */ + virtual void cleanUp( ) const; + +protected: + /** */ + virtual bool isDefault( ); + /** */ + virtual void createViewStructure( ); + /** */ + virtual PMViewStructure* defaultViewStructure( ) const; + /** */ + virtual int viewStructureParameterKey( ) const { return s_parameterKey+ globalDetailKey(); } + +private: + /** + * Creates the lines for the view structure + */ + static void createLines( PMLineArray& lines, int steps ); + /** + * Creates the points for the view structure + */ + static void createPoints( PMPointArray& points, const PMVector& center, + const PMVector& normal, double radius , double hradius, int steps ); + + /** + * IDs for @ref PMMementoData + */ + enum PMPlaneMementoID { PMCenterID, PMNormalID, PMRadiusID, PMHRadiusID }; + /** + * center of disc + */ + PMVector m_center; + /** + * normal of disc + */ + PMVector m_normal; + /** + * radius of disc + */ + double m_radius; + /** + * hole radius of disc + */ + double m_hradius; + /** + * The default view structure. It can be shared between planes + */ + static PMViewStructure* s_pDefaultViewStructure; + static int s_numSteps; + static int s_parameterKey; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmdiscedit.cpp b/kpovmodeler/pmdiscedit.cpp new file mode 100644 index 00000000..109c3d66 --- /dev/null +++ b/kpovmodeler/pmdiscedit.cpp @@ -0,0 +1,147 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Leonardo Skorianez + email : lsk@if.ufrj.br +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmdiscedit.h" +#include "pmdisc.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" + +#include +#include +#include +#include +#include + +PMDiscEdit::PMDiscEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMDiscEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* layout; + QGridLayout* gl; + + m_pCenter = new PMVectorEdit( "x", "y", "z", this ); + m_pNormal = new PMVectorEdit( "x", "y", "z", this ); + m_pHRadius = new PMFloatEdit( this ); + m_pHRadius->setValidation( true, 0.0, false, 0.0 ); + m_pRadius = new PMFloatEdit( this ); + m_pRadius->setValidation( true, 0.0, false, 0.0 ); + + gl = new QGridLayout( topLayout( ), 2, 2 ); + gl->addWidget( new QLabel( i18n( "Center:" ), this ), 0, 0 ); + gl->addWidget( m_pCenter, 0, 1 ); + gl->addWidget( new QLabel( i18n( "Normal:" ), this ), 1, 0 ); + gl->addWidget( m_pNormal, 1, 1 ); + + layout = new QHBoxLayout( topLayout( ) ); + gl = new QGridLayout( layout, 2, 2 ); + gl->addWidget( new QLabel( i18n( "Radius:" ), this ), 0, 0 ); + gl->addWidget( m_pRadius, 0, 1 ); + gl->addWidget( new QLabel( i18n( "Hole radius:" ), this ), 1, 0 ); + gl->addWidget( m_pHRadius, 1, 1 ); + layout->addStretch( 1 ); + + QPushButton* nb = new QPushButton( i18n( "Normalize" ), this ); + layout = new QHBoxLayout( topLayout( ) ); + layout->addWidget( nb ); + layout->addStretch( 1 ); + + connect( m_pCenter, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pNormal, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pRadius, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pHRadius, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( nb, SIGNAL( clicked( ) ), SLOT( slotNormalize( ) ) ); +} + +void PMDiscEdit::slotNormalize( ) +{ + PMVector normal = m_pNormal->vector( ); + double l = normal.abs( ); + if( !approxZero( l ) ) + m_pNormal->setVector( normal / l ); +} + + +void PMDiscEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Disc" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMDisc* ) o; + + m_pCenter->setVector( m_pDisplayedObject->center( ) ); + m_pNormal->setVector( m_pDisplayedObject->normal( ) ); + m_pRadius->setValue( m_pDisplayedObject->radius( ) ); + m_pHRadius->setValue( m_pDisplayedObject->holeRadius( ) ); + + m_pCenter->setReadOnly( readOnly ); + m_pNormal->setReadOnly( readOnly ); + m_pRadius->setReadOnly( readOnly ); + m_pHRadius->setReadOnly( readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMDiscEdit: Can't display object\n"; +} + +void PMDiscEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setCenter( m_pCenter->vector( ) ); + m_pDisplayedObject->setNormal( m_pNormal->vector( ) ); + m_pDisplayedObject->setRadius( m_pRadius->value( ) ); + m_pDisplayedObject->setHoleRadius( m_pHRadius->value( ) ); + } +} + +bool PMDiscEdit::isDataValid( ) +{ + if( m_pNormal->isDataValid( ) ) + { + if( approxZero( m_pNormal->vector( ).abs( ) ) ) + { + KMessageBox::error( this, i18n( "The normal vector may not be a " + "null vector." ), + i18n( "Error" ) ); + return false; + } + if( m_pCenter->isDataValid( ) ) + if( m_pRadius->isDataValid( ) ) + if( m_pHRadius->isDataValid( ) ) + if( m_pRadius->value( ) >= m_pHRadius->value( ) ) + return Base::isDataValid( ); + else + { + KMessageBox::error( this, i18n( "The radius may not be smaller " + "than the hole radius." ), + i18n( "Error" ) ); + m_pRadius->setFocus( ); + } + } + return false; +} + +#include "pmdiscedit.moc" diff --git a/kpovmodeler/pmdiscedit.h b/kpovmodeler/pmdiscedit.h new file mode 100644 index 00000000..bc603ddc --- /dev/null +++ b/kpovmodeler/pmdiscedit.h @@ -0,0 +1,67 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Leonardo Skorinaez + email : lsk@if.ufrj.br +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMDISCEDIT_H +#define PMDISCEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmgraphicalobjectedit.h" + +class PMVectorEdit; +class PMFloatEdit; +class PMDisc; + +class PMDiscEdit : public PMGraphicalObjectEdit +{ + Q_OBJECT + typedef PMGraphicalObjectEdit Base; +public: + /** + * Creates a PMPlaneEdit with parent and name + */ + PMDiscEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + /** + * Normalizes the vector + */ + void slotNormalize( ); + +private: + PMDisc* m_pDisplayedObject; + PMVectorEdit* m_pCenter; + PMVectorEdit* m_pNormal; + PMFloatEdit* m_pRadius; + PMFloatEdit* m_pHRadius; +}; +#endif diff --git a/kpovmodeler/pmdistancecontrolpoint.cpp b/kpovmodeler/pmdistancecontrolpoint.cpp new file mode 100644 index 00000000..dbd8b881 --- /dev/null +++ b/kpovmodeler/pmdistancecontrolpoint.cpp @@ -0,0 +1,92 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmdistancecontrolpoint.h" +#include "pmmath.h" +#include "pmdebug.h" +#include + + +PMDistanceControlPoint::PMDistanceControlPoint( PMControlPoint* base, + const PMVector& direction, double distance, + int id, const QString& description, + bool showExtraLine ) + : PMControlPoint( id, description ) +{ + m_distance = distance; + m_pBasePoint = base; + m_direction = direction; + m_directionLength = direction.abs( ); + m_extraLine = showExtraLine; +} + +PMDistanceControlPoint::PMDistanceControlPoint( const PMVector& base, + const PMVector& direction, double distance, + int id, const QString& description, + bool showExtraLine ) + : PMControlPoint( id, description ) +{ + m_distance = distance; + m_constBasePoint = base; + m_pBasePoint = 0; + m_direction = direction; + m_directionLength = direction.abs( ); + m_extraLine = showExtraLine; +} + +PMVector PMDistanceControlPoint::position( ) const +{ + if( m_pBasePoint ) + return m_pBasePoint->position( ) + m_direction * m_distance; + return m_constBasePoint + m_direction * m_distance; +} + +PMVector PMDistanceControlPoint::basePoint( ) const +{ + if( m_pBasePoint ) + return m_pBasePoint->position( ); + return m_constBasePoint; +} + +void PMDistanceControlPoint::setDirection( const PMVector& direction ) +{ + m_direction = direction; + m_directionLength = direction.abs( ); +} + +void PMDistanceControlPoint::graphicalChangeStarted( ) +{ + m_originalDistance = m_distance; +} + +void PMDistanceControlPoint::graphicalChange( const PMVector& startPoint, + const PMVector& /*viewNormal*/, + const PMVector& endPoint ) +{ + if( !approxZero( m_directionLength ) ) + m_distance = m_originalDistance + + PMVector::dot( endPoint - startPoint, m_direction ) + / ( m_directionLength * m_directionLength ); +} + +void PMDistanceControlPoint::snapToGrid( ) +{ + double d = moveGrid( ); + if( !approxZero( d ) ) + m_distance = rint( m_distance / d ) * d; + setChanged( ); +} diff --git a/kpovmodeler/pmdistancecontrolpoint.h b/kpovmodeler/pmdistancecontrolpoint.h new file mode 100644 index 00000000..f5e28fff --- /dev/null +++ b/kpovmodeler/pmdistancecontrolpoint.h @@ -0,0 +1,110 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMDISTANCECONTROLPOINT_H +#define PMDISTANCECONTROLPOINT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + + +#include "pmcontrolpoint.h" + +/** + * Class for distance control points + */ +class PMDistanceControlPoint : public PMControlPoint +{ +public: + /** + * Creates a PMDistanceControlPoint with id. + * + * The base point of the vector is given by the control point location. + */ + PMDistanceControlPoint( PMControlPoint* location, const PMVector& direction, + double distance, int id, const QString& description, + bool extraLine = false ); + /** + * Creates a PMDistanceControlPoint with id. + * + * The base point of the vector is given by the vector p. + */ + PMDistanceControlPoint( const PMVector& location, const PMVector& direction, + double distance, int id, const QString& description, + bool extraLine = false ); + + /** + * Deletes the PMDistanceControlPoint + */ + virtual ~PMDistanceControlPoint( ) { }; + + /** */ + virtual PMVector position( ) const; + + /** + * Sets the distance + */ + void setDistance( double distance ) { m_distance = distance; } + /** + * returns the distance + */ + double distance( ) const { return m_distance; } + /** + * Sets the direction + */ + void setDirection( const PMVector& d ); + /** + * Returns the direction + */ + PMVector direction( ) const { return m_direction; } + /** + * Returns the base point + */ + PMVector basePoint( ) const; + + /** */ + virtual bool hasExtraLine( ) const { return m_extraLine; } + /** + * Returns the start point of the extra line + */ + virtual PMVector extraLineStart( ) const { return basePoint( ); } + /** + * Returns the end point of the extra line + */ + virtual PMVector extraLineEnd( ) const { return position( ); } + + /** */ + virtual void snapToGrid( ); +protected: + /** */ + virtual void graphicalChangeStarted( ); + /** */ + virtual void graphicalChange( const PMVector& startPoint, + const PMVector& viewNormal, + const PMVector& endPoint ); +private: + double m_distance, m_originalDistance; + PMControlPoint* m_pBasePoint; + PMVector m_constBasePoint; + PMVector m_direction; + double m_directionLength; + bool m_extraLine; +}; + +#endif diff --git a/kpovmodeler/pmdockwidget.cpp b/kpovmodeler/pmdockwidget.cpp new file mode 100644 index 00000000..625ea6bc --- /dev/null +++ b/kpovmodeler/pmdockwidget.cpp @@ -0,0 +1,2549 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 Max Judin + Modified 2002 Andreas Zehender + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "pmdockwidget.h" +#include "pmdockwidget_private.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef NO_KDE2 +#include +#include +#include +#include +#include +#include +#ifdef Q_WS_X11 +#include +#include +#endif +#else +#include +#include +#include +#endif + +#include "pmdebug.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DOCK_CONFIG_VERSION "0.0.5" + +static const char* const close_xpm[]={ +"7 7 2 1", +"# c black", +". c None", +".......", +"##..##.", +".####..", +"..##...", +".####..", +"##..##.", +"......."}; + +static const char* const todesktop_xpm[]={ +"5 5 2 1", +"# c black", +". c None", +"####.", +"##...", +"#.#..", +"#..#.", +"....#"}; + +static const char* const dockback_xpm[]={ +"5 5 2 1", +"# c black", +". c None", +"#....", +".#..#", +"..#.#", +"...##", +".####"}; + +static const char* const not_close_xpm[]={ +"5 5 2 1", +"# c black", +". c None", +"#####", +"#...#", +"#...#", +"#...#", +"#####"}; + +class PMDockMainWindowPrivate +{ +public: + PMDockMainWindowPrivate() + { + m_activePart = 0; + m_bShellGUIActivated = false; + m_helpMenu = 0; + } + ~PMDockMainWindowPrivate() + { + } + + QGuardedPtr m_activePart; + bool m_bShellGUIActivated; + KHelpMenu *m_helpMenu; +}; + + +/** + * A special kind of KMainWindow that is able to have dockwidget child widgets. + * + * The main widget should be a dockwidget where other dockwidgets can be docked to + * the left, right, top, bottom or to the middle. + * Furthermore, the PMDockMainWindow has got the KDocManager and some data about the dock states. + * + * @author Max Judin. +*/ +PMDockMainWindow::PMDockMainWindow( QWidget* parent, const char *name, WFlags f) +:KMainWindow( parent, name, f ) +{ + QString new_name = QString(name) + QString("_DockManager"); + dockManager = new PMDockManager( this, new_name.latin1() ); + mainDockWidget = 0L; + + d = new PMDockMainWindowPrivate( ); + PartBase::setPartObject( this ); +} + +PMDockMainWindow::~PMDockMainWindow() +{ + delete dockManager; + delete d; +} + +// kparts/dockmainwindow stuff +void PMDockMainWindow::createGUI( Part * part ) +{ + kdDebug(1000) << QString("DockMainWindow::createGUI for %1").arg(part?part->name():"0L") << endl; + + KXMLGUIFactory *factory = guiFactory(); + + setUpdatesEnabled( false ); + + QPtrList plugins; + + if ( d->m_activePart ) + { + kdDebug(1000) << QString("deactivating GUI for %1").arg(d->m_activePart->name()) << endl; + + GUIActivateEvent ev( false ); + QApplication::sendEvent( d->m_activePart, &ev ); + + factory->removeClient( d->m_activePart ); + + disconnect( d->m_activePart, SIGNAL( setWindowCaption( const QString & ) ), + this, SLOT( setCaption( const QString & ) ) ); + disconnect( d->m_activePart, SIGNAL( setStatusBarText( const QString & ) ), + this, SLOT( slotSetStatusBarText( const QString & ) ) ); + } + + if( !d->m_bShellGUIActivated ) + { + loadPlugins( this, this, KGlobal::instance() ); + createShellGUI(); + d->m_bShellGUIActivated = true; + } + + if ( part ) + { + // do this before sending the activate event + connect( part, SIGNAL( setWindowCaption( const QString & ) ), + this, SLOT( setCaption( const QString & ) ) ); + connect( part, SIGNAL( setStatusBarText( const QString & ) ), + this, SLOT( slotSetStatusBarText( const QString & ) ) ); + + factory->addClient( part ); + + GUIActivateEvent ev( true ); + QApplication::sendEvent( part, &ev ); + + } + + setUpdatesEnabled( true ); + + d->m_activePart = part; +} + +void PMDockMainWindow::slotSetStatusBarText( const QString & text ) +{ + statusBar()->message( text ); +} + +void PMDockMainWindow::createShellGUI( bool create ) +{ + bool bAccelAutoUpdate = accel()->setAutoUpdate( false ); + assert( d->m_bShellGUIActivated != create ); + d->m_bShellGUIActivated = create; + + if ( create ) + { + if ( isHelpMenuEnabled() && !d->m_helpMenu ) + d->m_helpMenu = new KHelpMenu( this, instance()->aboutData(), true, actionCollection() ); + + QString f = xmlFile(); + setXMLFile( locate( "config", "ui/ui_standards.rc", instance() ) ); + if ( !f.isEmpty() ) + setXMLFile( f, true ); + else + { + QString auto_file( instance()->instanceName() + "ui.rc" ); + setXMLFile( auto_file, true ); + } + + GUIActivateEvent ev( true ); + QApplication::sendEvent( this, &ev ); + + guiFactory()->addClient( this ); + + } + else + { + GUIActivateEvent ev( false ); + QApplication::sendEvent( this, &ev ); + + guiFactory()->removeClient( this ); + } + accel()->setAutoUpdate( bAccelAutoUpdate ); +} +// end kparts/dockmainwindow + +void PMDockMainWindow::setMainDockWidget( PMDockWidget* mdw ) +{ + if ( mainDockWidget == mdw ) return; + mainDockWidget = mdw; +} + +void PMDockMainWindow::setView( QWidget *view ) +{ + if ( view->isA("PMDockWidget") ){ + if ( view->parent() != this ) ((PMDockWidget*)view)->applyToWidget( this ); + } + +#ifndef NO_KDE2 + KMainWindow::setCentralWidget(view); +#else + QMainWindow::setCentralWidget(view); +#endif +} + +PMDockWidget* PMDockMainWindow::createDockWidget( const QString& name, const QPixmap &pixmap, QWidget* parent, const QString& strCaption, const QString& strTabPageLabel) +{ + return new PMDockWidget( dockManager, name.latin1(), pixmap, parent, strCaption, strTabPageLabel ); +} + +void PMDockMainWindow::makeDockVisible( PMDockWidget* dock ) +{ + if ( dock != 0L) + dock->makeDockVisible(); +} + +void PMDockMainWindow::makeDockInvisible( PMDockWidget* dock ) +{ + if ( dock != 0L) + dock->undock(); +} + +void PMDockMainWindow::makeWidgetDockVisible( QWidget* widget ) +{ + makeDockVisible( dockManager->findWidgetParentDock(widget) ); +} + +void PMDockMainWindow::writeDockConfig(QDomElement &base) +{ + dockManager->writeConfig(base); +} + +void PMDockMainWindow::readDockConfig(QDomElement &base) +{ + dockManager->readConfig(base); +} + +#ifndef NO_KDE2 +void PMDockMainWindow::writeDockConfig( KConfig* c, QString group ) +{ + dockManager->writeConfig( c, group ); +} + +void PMDockMainWindow::readDockConfig( KConfig* c, QString group ) +{ + dockManager->readConfig( c, group ); +} +#endif + +void PMDockMainWindow::slotDockWidgetUndocked() +{ + QObject* pSender = (QObject*) sender(); + if (!pSender->inherits("PMDockWidget")) return; + PMDockWidget* pDW = (PMDockWidget*) pSender; + emit dockWidgetHasUndocked( pDW); +} + +/*************************************************************************/ +PMDockWidgetAbstractHeaderDrag::PMDockWidgetAbstractHeaderDrag( PMDockWidgetAbstractHeader* parent, PMDockWidget* dock, const char* name ) +:QFrame( parent, name ) +{ + dw = dock; + installEventFilter( dock->dockManager() ); +} +/*************************************************************************/ +PMDockWidgetHeaderDrag::PMDockWidgetHeaderDrag( PMDockWidgetAbstractHeader* parent, PMDockWidget* dock, const char* name ) +:PMDockWidgetAbstractHeaderDrag( parent, dock, name ) +{ +} + +void PMDockWidgetHeaderDrag::paintEvent( QPaintEvent* ) +{ + QPainter paint; + + paint.begin( this ); + + style().drawPrimitive (QStyle::PE_DockWindowHandle, &paint, QRect(0,0,width(), height()), colorGroup()); + + paint.end(); +} +/*************************************************************************/ +PMDockWidgetAbstractHeader::PMDockWidgetAbstractHeader( PMDockWidget* parent, const char* name ) +:QFrame( parent, name ) +{ +} +/*************************************************************************/ +PMDockWidgetHeader::PMDockWidgetHeader( PMDockWidget* parent, const char* name ) +:PMDockWidgetAbstractHeader( parent, name ) +{ + layout = new QHBoxLayout( this ); + layout->setResizeMode( QLayout::Minimum ); + + drag = new PMDockWidgetHeaderDrag( this, parent ); + + closeButton = new PMDockButton_Private( this, "DockCloseButton" ); + closeButton->setPixmap( const_cast< const char** >(close_xpm) ); + int buttonWidth = 9, buttonHeight = 9; + closeButton->setFixedSize(buttonWidth,buttonHeight); + connect( closeButton, SIGNAL(clicked()), parent, SIGNAL(headerCloseButtonClicked())); + // MODIFICATION (zehender) + // The shell will delete the widget + // undock is unnecessary + // connect( closeButton, SIGNAL(clicked()), parent, SLOT(undock())); + + stayButton = new PMDockButton_Private( this, "DockStayButton" ); + stayButton->setToggleButton( true ); + stayButton->setPixmap( const_cast< const char** >(not_close_xpm) ); + stayButton->setFixedSize(buttonWidth,buttonHeight); + connect( stayButton, SIGNAL(clicked()), this, SLOT(slotStayClicked())); + stayButton->hide( ); + + dockbackButton = new PMDockButton_Private( this, "DockbackButton" ); + dockbackButton->setPixmap( const_cast< const char** >(dockback_xpm)); + dockbackButton->setFixedSize(buttonWidth,buttonHeight); + connect( dockbackButton, SIGNAL(clicked()), parent, SIGNAL(headerDockbackButtonClicked())); + connect( dockbackButton, SIGNAL(clicked()), parent, SLOT(dockBack())); + + // MODIFICATION (zehender) + // Add a button to undock the widget and dock it as top level + // widget to the desktop + toDesktopButton = new PMDockButton_Private( this, "ToDesktopButton" ); + toDesktopButton->setPixmap( const_cast< const char** >(todesktop_xpm)); + toDesktopButton->setFixedSize(buttonWidth,buttonHeight); + connect( toDesktopButton, SIGNAL(clicked()), parent, SLOT(toDesktop())); + + layout->addWidget( drag ); + layout->addWidget( dockbackButton ); + layout->addWidget( toDesktopButton ); + layout->addWidget( stayButton ); + layout->addWidget( closeButton ); + layout->activate(); + drag->setFixedHeight( layout->minimumSize().height() ); +} + +void PMDockWidgetHeader::setTopLevel( bool isTopLevel ) +{ + if ( isTopLevel ){ + PMDockWidget* par = (PMDockWidget*)parent(); + if( par) { + if( par->isDockBackPossible()) + dockbackButton->show(); + else + dockbackButton->hide(); + } + stayButton->hide(); + closeButton->hide(); + toDesktopButton->hide(); + drag->setEnabled( true ); + } else { + dockbackButton->hide(); + stayButton->hide(); + closeButton->show(); + toDesktopButton->show(); + } + layout->activate(); + updateGeometry(); +} + +void PMDockWidgetHeader::setDragPanel( PMDockWidgetHeaderDrag* nd ) +{ + if ( !nd ) return; + + delete layout; + layout = new QHBoxLayout( this ); + layout->setResizeMode( QLayout::Minimum ); + + delete drag; + drag = nd; + + layout->addWidget( drag ); + layout->addWidget( dockbackButton ); + layout->addWidget( toDesktopButton ); + layout->addWidget( stayButton ); + layout->addWidget( closeButton ); + layout->activate(); + drag->setFixedHeight( layout->minimumSize().height() ); +} + +void PMDockWidgetHeader::slotStayClicked() +{ + setDragEnabled(!stayButton->isOn()); +} + +bool PMDockWidgetHeader::dragEnabled() const +{ + return drag->isEnabled(); +} + +void PMDockWidgetHeader::setDragEnabled(bool b) +{ + stayButton->setOn(!b); + closeButton->setEnabled(b); + drag->setEnabled(b); +} + +#ifndef NO_KDE2 +void PMDockWidgetHeader::saveConfig( KConfig* c ) +{ + c->writeEntry( QString("%1%2").arg(parent()->name()).arg(":stayButton"), stayButton->isOn() ); +} + +void PMDockWidgetHeader::loadConfig( KConfig* c ) +{ + setDragEnabled( !c->readBoolEntry( QString("%1%2").arg(parent()->name()).arg(":stayButton"), false ) ); +} +#endif + +/*************************************************************************/ +PMDockWidget::PMDockWidget( PMDockManager* dockManager, const char* name, const QPixmap &pixmap, QWidget* parent, const QString& strCaption, const QString& strTabPageLabel, WFlags f) +: QWidget( parent, name, f ) + ,formerBrotherDockWidget(0L) + ,currentDockPos(DockNone) + ,formerDockPos(DockNone) + ,pix(new QPixmap(pixmap)) + ,prevSideDockPosBeforeDrag(DockNone) +{ + d = new PMDockWidgetPrivate(); // create private data + + d->_parent = parent; + + layout = new QVBoxLayout( this ); + layout->setResizeMode( QLayout::Minimum ); + + manager = dockManager; + manager->childDock->append( this ); + installEventFilter( manager ); + + header = 0L; + setHeader( new PMDockWidgetHeader( this, "AutoCreatedDockHeader" ) ); + if( strCaption == 0L) + setCaption( name ); + else + setCaption( strCaption); + + if( strTabPageLabel == " ") + setTabPageLabel( caption()); + else + setTabPageLabel( strTabPageLabel); + + eDocking = DockFullDocking; + sDocking = DockFullSite; + + isGroup = false; + isTabGroup = false; + + setIcon( pixmap); + widget = 0L; + + QObject::connect(this, SIGNAL(hasUndocked()), manager->main, SLOT(slotDockWidgetUndocked()) ); + applyToWidget( parent, QPoint(0,0) ); +} + +void PMDockWidget::slotSetCaption( const QString& str ) +{ + setTabPageLabel( str ); + setCaption( str ); +} + +PMDockWidget::~PMDockWidget() +{ + if ( !manager->undockProcess ){ + d->blockHasUndockedSignal = true; + undock(); + d->blockHasUndockedSignal = false; + } + emit iMBeingClosed(); + manager->childDock->remove( this ); + delete pix; + delete d; // destroy private data +} + +void PMDockWidget::setHeader( PMDockWidgetAbstractHeader* h ) +{ + if ( !h ) return; + + if ( header ){ + delete header; + delete layout; + header = h; + layout = new QVBoxLayout( this ); + layout->setResizeMode( QLayout::Minimum ); + layout->addWidget( header ); + setWidget( widget ); + } else { + header = h; + layout->addWidget( header ); + } +} + +void PMDockWidget::setEnableDocking( int pos ) +{ + eDocking = pos; + updateHeader(); +} + +void PMDockWidget::updateHeader() +{ + if ( parent() ){ + if ( (parent() == manager->main) || isGroup || (eDocking == PMDockWidget::DockNone) ){ + header->hide(); + } else { + header->setTopLevel( false ); + header->show(); + } + } else { + header->setTopLevel( true ); + header->show(); + } +} + +void PMDockWidget::applyToWidget( QWidget* s, const QPoint& p ) +{ + if ( parent() != s ) + { + hide(); + reparent(s, 0, QPoint(0,0), false); + } + + if ( s && s->inherits("PMDockMainWindow") ){ + ((PMDockMainWindow*)s)->setView( this ); + } + + if ( s == manager->main ){ + setGeometry( QRect(QPoint(0,0), manager->main->geometry().size()) ); + } + + if ( !s ) + { + move(p); + +#ifndef NO_KDE2 +#ifdef Q_WS_X11 + if (d->transient && d->_parent) + XSetTransientForHint( qt_xdisplay(), winId(), d->_parent->winId() ); + + KWin::setType( winId(), d->windowType ); +#endif +#endif + + } + updateHeader(); + + setIcon(*pix); +} + +void PMDockWidget::show() +{ + if ( parent() || manager->main->isVisible() ) + if ( !parent() ){ + emit manager->setDockDefaultPos( this ); + emit setDockDefaultPos(); + if ( parent() ){ + makeDockVisible(); + } else { + QWidget::show(); + } + } else { + QWidget::show(); + } +} + +#ifndef NO_KDE2 + +void PMDockWidget::setDockWindowType (NET::WindowType windowType) +{ + d->windowType = windowType; + applyToWidget( parentWidget(), QPoint(0,0) ); +} + +#endif + +void PMDockWidget::setDockWindowTransient (QWidget *parent, bool transientEnabled) +{ + d->_parent = parent; + d->transient = transientEnabled; + applyToWidget( parentWidget(), QPoint(0,0) ); +} + +bool PMDockWidget::event( QEvent* pevent ) +{ + switch ( pevent->type() ) + { + #undef FocusIn + case QEvent::FocusIn: + if (widget && !d->pendingFocusInEvent) { + d->pendingFocusInEvent = true; + widget->setFocus(); + } + d->pendingFocusInEvent = false; + break; + case QEvent::ChildRemoved: + if ( widget == ((QChildEvent*)pevent)->child() ) widget = 0L; + break; + case QEvent::Show: + if ( widget ) widget->show(); + emit manager->change(); + break; + case QEvent::Hide: + if ( widget ) widget->hide(); + emit manager->change(); + break; + case QEvent::CaptionChange: + if ( parentWidget() ){ + if ( parent()->inherits("PMDockSplitter") ){ + ((PMDockSplitter*)(parent()))->updateName(); + } + if ( parentDockTabGroup() ){ + setDockTabName( parentDockTabGroup() ); + parentDockTabGroup()->setTabLabel( this, tabPageLabel() ); + } + } + break; + case QEvent::Close: + // MODIFICATION (zehender) + // Top level widget is closed + // emit same signal as if the widget is docked and closed with + // the header button + emit headerCloseButtonClicked( ); + // emit iMBeingClosed(); + break; + default: + break; + } + #undef KeyPress + bool processed = QWidget::event( pevent ); + if( pevent->type( ) == QEvent::AccelOverride && !processed && !parent( ) ){ + // MODIFICATION (zehender) + // floating widget, post event to main window + processed = qApp->sendEvent( manager->dockMainWidget( ), pevent ); + } + return processed; +} + +PMDockWidget* PMDockWidget::manualDock( PMDockWidget* target, DockPosition dockPos, int spliPos, QPoint pos, bool check, int tabIndex ) +{ + if (this == target) + return 0L; // docking to itself not possible + + bool succes = true; // tested flag + + // do not dock into a floating widget + if( target && !target->parent( ) ) + target = 0; + + // check allowed this dock submit this operations + if ( !(eDocking & (int)dockPos) ){ + succes = false; + } + + // check allowed target submit this operations + if ( target && !(target->dockSite( ) & (int)dockPos) ){ + succes = false; + } + + if ( parent() && !parent()->inherits("PMDockSplitter") && !parentDockTabGroup() ){ + succes = false; + } + + // if docking to a tab group, and position is not center + // dock to the parent of the tab group + if( target && ( dockPos != PMDockWidget::DockCenter ) + && ( dockPos != PMDockWidget::DockNone ) ) + { + QWidget* pdt = target->parentDockTabGroup( ); + if( pdt ) + return manualDock( ( PMDockWidget* ) ( pdt->parent( ) ), + dockPos, spliPos, pos, check, tabIndex ); + } + + if ( !succes ){ + // try to make another manualDock + PMDockWidget* dock_result = 0L; + if ( target && !check ){ + PMDockWidget::DockPosition another__dockPos = PMDockWidget::DockNone; + switch ( dockPos ){ + case PMDockWidget::DockLeft : another__dockPos = PMDockWidget::DockRight ; break; + case PMDockWidget::DockRight : another__dockPos = PMDockWidget::DockLeft ; break; + case PMDockWidget::DockTop : another__dockPos = PMDockWidget::DockBottom; break; + case PMDockWidget::DockBottom: another__dockPos = PMDockWidget::DockTop ; break; + default: break; + } + dock_result = target->manualDock( this, another__dockPos, spliPos, pos, true, tabIndex ); + } + return dock_result; + } + // end check block + + d->blockHasUndockedSignal = true; + undock(); + d->blockHasUndockedSignal = false; + + if ( !target ){ + move( pos ); + show(); + emit manager->change(); + return this; + } + + PMDockTabGroup* parentTab = target->parentDockTabGroup(); + if ( parentTab ){ + // add to existing TabGroup + applyToWidget( parentTab ); + parentTab->insertTab( this, icon() ? *icon() : QPixmap(), + tabPageLabel(), tabIndex ); + setDockTabName( parentTab ); + if( !toolTipStr.isEmpty()) + parentTab->setTabToolTip( this, toolTipStr); + + currentDockPos = PMDockWidget::DockCenter; + emit manager->change(); + return (PMDockWidget*)parentTab->parent(); + } + + // MODIFICATION (Zehender): + // If DockPosition is DockLeft or DockRight, add the widget + // left or right of the target, so that a new vertical splitter + // (a splitter with horizontal widget layout :-) is created + // that spawns the full height of the main view + + if( ( dockPos == PMDockWidget::DockLeft ) || + ( dockPos == PMDockWidget::DockRight ) ) + { + PMDockWidget* newTarget = target; + bool found = false; + QWidget* wtarget = target; + while( wtarget && !found ) + { + if( wtarget->inherits( "PMDockWidget" ) ) + { + PMDockWidget* dw = ( PMDockWidget* ) wtarget; + newTarget = dw; + QWidget* pw = wtarget->parentWidget( ); + if( pw ) + { + if( pw->inherits( "PMDockSplitter" ) ) + { + PMDockSplitter* ds = ( PMDockSplitter* ) pw; + if( ds->splitterOrientation( ) == Vertical ) + found = true; + } + } + } + wtarget = wtarget->parentWidget( ); + } + + if( newTarget != target ) + return manualDock( newTarget, dockPos, spliPos, pos, check, tabIndex ); + } + + // END MODIFICATION + + // create a new dockwidget that will contain the target and this + QWidget* parentDock = target->parentWidget(); + PMDockWidget* newDock = new PMDockWidget( manager, "tempName", QPixmap(""), parentDock ); + newDock->currentDockPos = target->currentDockPos; + + if ( dockPos == PMDockWidget::DockCenter ){ + newDock->isTabGroup = true; + } else { + newDock->isGroup = true; + } + newDock->eDocking = (target->eDocking & eDocking) & (~(int)PMDockWidget::DockCenter); + + newDock->applyToWidget( parentDock ); + + if ( !parentDock ){ + // dock to a toplevel dockwidget means newDock is toplevel now + newDock->move( target->frameGeometry().topLeft() ); + newDock->resize( target->geometry().size() ); + if ( target->isVisibleToTLW() ) newDock->show(); + } + + // redirect the dockback button to the new dockwidget + if( target->formerBrotherDockWidget != 0L) { + newDock->formerBrotherDockWidget = target->formerBrotherDockWidget; + if( formerBrotherDockWidget != 0L) + QObject::connect( newDock->formerBrotherDockWidget, SIGNAL(iMBeingClosed()), + newDock, SLOT(loseFormerBrotherDockWidget()) ); + target->loseFormerBrotherDockWidget(); + } + newDock->formerDockPos = target->formerDockPos; + + if ( dockPos == PMDockWidget::DockCenter ) + { + PMDockTabGroup* tab = new PMDockTabGroup( newDock, "_dock_tab"); + QObject::connect(tab, SIGNAL(currentChanged(QWidget*)), d, SLOT(slotFocusEmbeddedWidget(QWidget*))); + newDock->setWidget( tab ); + + target->applyToWidget( tab ); + applyToWidget( tab ); + + + tab->insertTab( target, target->icon() ? *(target->icon()) : QPixmap(), + target->tabPageLabel() ); + if( !target->toolTipString().isEmpty()) + tab->setTabToolTip( target, target->toolTipString()); + + tab->insertTab( this, icon() ? *icon() : QPixmap(), + tabPageLabel(), tabIndex ); + if( !toolTipString().isEmpty()) + tab->setTabToolTip( this, toolTipString()); + + setDockTabName( tab ); + tab->show(); + + currentDockPos = DockCenter; + target->formerDockPos = target->currentDockPos; + target->currentDockPos = DockCenter; + } + else { + // if to dock not to the center of the target dockwidget, + // dock to newDock + PMDockSplitter* panner = 0L; + if ( dockPos == PMDockWidget::DockTop || dockPos == PMDockWidget::DockBottom ) panner = new PMDockSplitter( newDock, "_dock_split_", Horizontal, spliPos, manager->splitterHighResolution() ); + if ( dockPos == PMDockWidget::DockLeft || dockPos == PMDockWidget::DockRight ) panner = new PMDockSplitter( newDock, "_dock_split_", Vertical , spliPos, manager->splitterHighResolution() ); + newDock->setWidget( panner ); + + panner->setOpaqueResize(manager->splitterOpaqueResize()); + panner->setKeepSize(manager->splitterKeepSize()); + panner->setFocusPolicy( NoFocus ); + target->applyToWidget( panner ); + applyToWidget( panner ); + target->formerDockPos = target->currentDockPos; + if ( dockPos == PMDockWidget::DockRight) { + panner->activate( target, this ); + currentDockPos = PMDockWidget::DockRight; + target->currentDockPos = PMDockWidget::DockLeft; + } + else if( dockPos == PMDockWidget::DockBottom) { + panner->activate( target, this ); + currentDockPos = PMDockWidget::DockBottom; + target->currentDockPos = PMDockWidget::DockTop; + } + else if( dockPos == PMDockWidget::DockTop) { + panner->activate( this, target ); + currentDockPos = PMDockWidget::DockTop; + target->currentDockPos = PMDockWidget::DockBottom; + } + else if( dockPos == PMDockWidget::DockLeft) { + panner->activate( this, target ); + currentDockPos = PMDockWidget::DockLeft; + target->currentDockPos = PMDockWidget::DockRight; + } + target->show(); + show(); + panner->show(); + } + + if ( parentDock ){ + if ( parentDock->inherits("PMDockSplitter") ){ + PMDockSplitter* sp = (PMDockSplitter*)parentDock; + sp->deactivate(); + if ( sp->getFirst() == target ) + sp->activate( newDock, 0L ); + else + sp->activate( 0L, newDock ); + } + } + + newDock->show(); + emit target->docking( this, dockPos ); + emit manager->replaceDock( target, newDock ); + emit manager->change(); + + return newDock; +} + +PMDockTabGroup* PMDockWidget::parentDockTabGroup() const +{ + if ( !parent() ) return 0L; + QWidget* candidate = parentWidget()->parentWidget(); + if ( candidate && candidate->inherits("PMDockTabGroup") ) return (PMDockTabGroup*)candidate; + return 0L; +} + +void PMDockWidget::toDesktop() +{ + QPoint p = mapToGlobal( QPoint( -30, -30 ) ); + if( p.x( ) < 0 ) + p.setX( 0 ); + if( p.y( ) < 0 ) + p.setY( 0 ); + manualDock( 0, DockDesktop, 50, p ); +} + +void PMDockWidget::undock() +{ + QWidget* parentW = parentWidget(); + if ( !parentW ){ + hide(); + if (!d->blockHasUndockedSignal) + emit hasUndocked(); + return; + } + + formerDockPos = currentDockPos; + currentDockPos = PMDockWidget::DockDesktop; + + manager->blockSignals(true); + manager->undockProcess = true; + + bool isV = parentW->isVisibleToTLW(); + + PMDockTabGroup* parentTab = parentDockTabGroup(); + if ( parentTab ){ + d->index = parentTab->indexOf( this); // memorize the page position in the tab widget + parentTab->removePage( this ); + formerBrotherDockWidget = (PMDockWidget*)parentTab->page(0); + QObject::connect( formerBrotherDockWidget, SIGNAL(iMBeingClosed()), + this, SLOT(loseFormerBrotherDockWidget()) ); + applyToWidget( 0L ); + if ( parentTab->count() == 1 ){ + + // last subdock widget in the tab control + PMDockWidget* lastTab = (PMDockWidget*)parentTab->page(0); + parentTab->removePage( lastTab ); + lastTab->applyToWidget( 0L ); + lastTab->move( parentTab->mapToGlobal(parentTab->frameGeometry().topLeft()) ); + + // PMDockTabGroup always have a parent that is a PMDockWidget + PMDockWidget* parentOfTab = (PMDockWidget*)parentTab->parent(); + delete parentTab; // PMDockTabGroup + + QWidget* parentOfDockWidget = parentOfTab->parentWidget(); + if ( parentOfDockWidget == 0L ){ + if ( isV ) lastTab->show(); + } else { + if ( parentOfDockWidget->inherits("PMDockSplitter") ){ + PMDockSplitter* split = (PMDockSplitter*)parentOfDockWidget; + lastTab->applyToWidget( split ); + split->deactivate(); + if ( split->getFirst() == parentOfTab ){ + split->activate( lastTab ); + if ( ((PMDockWidget*)split->parent())->splitterOrientation == Vertical ) + emit ((PMDockWidget*)split->getAnother(parentOfTab))->docking( parentOfTab, PMDockWidget::DockLeft ); + else + emit ((PMDockWidget*)split->getAnother(parentOfTab))->docking( parentOfTab, PMDockWidget::DockTop ); + } else { + split->activate( 0L, lastTab ); + if ( ((PMDockWidget*)split->parent())->splitterOrientation == Vertical ) + emit ((PMDockWidget*)split->getAnother(parentOfTab))->docking( parentOfTab, PMDockWidget::DockRight ); + else + emit ((PMDockWidget*)split->getAnother(parentOfTab))->docking( parentOfTab, PMDockWidget::DockBottom ); + } + split->show(); + } else { + lastTab->applyToWidget( parentOfDockWidget ); + } + lastTab->show(); + } + manager->blockSignals(false); + emit manager->replaceDock( parentOfTab, lastTab ); + lastTab->currentDockPos = parentOfTab->currentDockPos; + emit parentOfTab->iMBeingClosed(); + manager->blockSignals(true); + delete parentOfTab; + + } else { + setDockTabName( parentTab ); + } + } else { +/*********************************************************************************************/ + if ( parentW->inherits("PMDockSplitter") ){ + PMDockSplitter* parentSplitterOfDockWidget = (PMDockSplitter*)parentW; + d->splitPosInPercent = parentSplitterOfDockWidget->separatorPos(); + + PMDockWidget* secondWidget = (PMDockWidget*)parentSplitterOfDockWidget->getAnother( this ); + PMDockWidget* group = (PMDockWidget*)parentSplitterOfDockWidget->parentWidget(); + formerBrotherDockWidget = secondWidget; + applyToWidget( 0L ); + group->hide(); + + if( formerBrotherDockWidget != 0L) + QObject::connect( formerBrotherDockWidget, SIGNAL(iMBeingClosed()), + this, SLOT(loseFormerBrotherDockWidget()) ); + + if ( !group->parentWidget() ){ + secondWidget->applyToWidget( 0L, group->frameGeometry().topLeft() ); + secondWidget->resize( group->width(), group->height() ); + } else { + QWidget* obj = group->parentWidget(); + secondWidget->applyToWidget( obj ); + if ( obj->inherits("PMDockSplitter") ){ + PMDockSplitter* parentOfGroup = (PMDockSplitter*)obj; + parentOfGroup->deactivate(); + + if ( parentOfGroup->getFirst() == group ) + parentOfGroup->activate( secondWidget ); + else + parentOfGroup->activate( 0L, secondWidget ); + } + } + secondWidget->currentDockPos = group->currentDockPos; + secondWidget->formerDockPos = group->formerDockPos; + delete parentSplitterOfDockWidget; + manager->blockSignals(false); + emit manager->replaceDock( group, secondWidget ); + emit group->iMBeingClosed(); + manager->blockSignals(true); + delete group; + + if ( isV ) secondWidget->show(); + } else { + applyToWidget( 0L ); + } +/*********************************************************************************************/ + } + manager->blockSignals(false); + if (!d->blockHasUndockedSignal) + emit manager->change(); + manager->undockProcess = false; + + if (!d->blockHasUndockedSignal) + emit hasUndocked(); +} + +void PMDockWidget::setWidget( QWidget* mw ) +{ + if ( !mw ) return; + + if ( mw->parent() != this ){ + mw->reparent(this, 0, QPoint(0,0), false); + } + + widget = mw; + delete layout; + + layout = new QVBoxLayout( this ); + layout->setResizeMode( QLayout::Minimum ); + + layout->addWidget( header ); + layout->addWidget( widget,1 ); +} + +void PMDockWidget::setDockTabName( PMDockTabGroup* tab ) +{ + QString listOfName; + QString listOfCaption; + for ( int i = 0; i < tab->count(); ++i ) { + QWidget *w = tab->page( i ); + listOfCaption.append( w->caption() ).append(","); + listOfName.append( w->name() ).append(","); + } + listOfCaption.remove( listOfCaption.length()-1, 1 ); + listOfName.remove( listOfName.length()-1, 1 ); + + tab->parentWidget()->setName( listOfName.utf8() ); + tab->parentWidget()->setCaption( listOfCaption ); + + tab->parentWidget()->repaint( false ); // PMDockWidget->repaint + if ( tab->parentWidget()->parent() ) + if ( tab->parentWidget()->parent()->inherits("PMDockSplitter") ) + ((PMDockSplitter*)(tab->parentWidget()->parent()))->updateName(); +} + +bool PMDockWidget::mayBeHide() const +{ + bool f = (parent() != manager->main); + return ( !isGroup && !isTabGroup && f && isVisible() && ( eDocking != (int)PMDockWidget::DockNone ) ); +} + +bool PMDockWidget::mayBeShow() const +{ + bool f = (parent() != manager->main); + return ( !isGroup && !isTabGroup && f && !isVisible() ); +} + +void PMDockWidget::changeHideShowState() +{ + if ( mayBeHide() ){ + undock(); + return; + } + + if ( mayBeShow() ){ + if ( manager->main->inherits("PMDockMainWindow") ){ + ((PMDockMainWindow*)manager->main)->makeDockVisible(this); + } else { + makeDockVisible(); + } + } +} + +void PMDockWidget::makeDockVisible() +{ + if ( parentDockTabGroup() ){ + parentDockTabGroup()->showPage( this ); + } + if ( isVisible() ) return; + + QWidget* p = parentWidget(); + while ( p ){ + if ( !p->isVisible() ) + p->show(); + p = p->parentWidget(); + } + if( parent() == 0L) // is undocked + dockBack(); + show(); +} + +void PMDockWidget::loseFormerBrotherDockWidget() +{ + if( formerBrotherDockWidget != 0L) + QObject::disconnect( formerBrotherDockWidget, SIGNAL(iMBeingClosed()), + this, SLOT(loseFormerBrotherDockWidget()) ); + formerBrotherDockWidget = 0L; + repaint(); +} + +void PMDockWidget::dockBack() +{ + if( formerBrotherDockWidget) { + // search all children if it tries to dock back to a child + bool found = false; + QObjectList* cl = queryList("PMDockWidget"); + QObjectListIt it( *cl ); + QObject * obj; + while ( !found && (obj=it.current()) != 0 ) { + ++it; + QWidget* widg = (QWidget*)obj; + if( widg == formerBrotherDockWidget) + found = true; + } + delete cl; + + if( !found) { + // can dock back to the former brother dockwidget + manualDock( formerBrotherDockWidget, formerDockPos, d->splitPosInPercent, QPoint(0,0), false, d->index); + formerBrotherDockWidget = 0L; + makeDockVisible(); + return; + } + } + + // else dockback to the dockmainwindow (default behaviour) + manualDock( ((PMDockMainWindow*)manager->main)->getMainDockWidget(), formerDockPos, d->splitPosInPercent, QPoint(0,0), false, d->index); + formerBrotherDockWidget = 0L; + if (parent()) + makeDockVisible(); +} + +bool PMDockWidget::isDockBackPossible() const +{ + if( (formerBrotherDockWidget == 0L) || !(formerBrotherDockWidget->dockSite() & formerDockPos)) + return false; + else + return true; +} + +/**************************************************************************************/ + +class PMDockManager::PMDockManagerPrivate +{ +public: + /** + * This rectangle is used to highlight the current dockposition. It stores global screen coordinates. + */ + QRect dragRect; + + /** + * This rectangle is used to erase the previously highlighted dockposition. It stores global screen coordinates. + */ + QRect oldDragRect; + + /** + * This flag stores the information if dragging is ready to start. Used between mousePress and mouseMove event. + */ + bool readyToDrag; + + /** + * This variable stores the offset of the mouse cursor to the upper left edge of the current drag widget. + */ + QPoint dragOffset; + + /** + * These flags store information about the splitter behaviour + */ + bool splitterOpaqueResize; + bool splitterKeepSize; + bool splitterHighResolution; +}; + +PMDockManager::PMDockManager( QWidget* mainWindow , const char* name ) +:QObject( mainWindow, name ) + ,main(mainWindow) + ,currentDragWidget(0L) + ,currentMoveWidget(0L) + ,childDockWidgetList(0L) + ,autoCreateDock(0L) + ,storeW(0) + ,storeH(0) + ,draging(false) + ,undockProcess(false) + ,dropCancel(true) +{ + d = new PMDockManagerPrivate; + d->splitterOpaqueResize = false; + d->splitterKeepSize = false; + d->splitterHighResolution = false; + + main->installEventFilter( this ); + + undockProcess = false; + + menuData = new QPtrList; + menuData->setAutoDelete( true ); + menuData->setAutoDelete( true ); + +#ifndef NO_KDE2 + menu = new KPopupMenu(); +#else + menu = new QPopupMenu(); +#endif + + connect( menu, SIGNAL(aboutToShow()), SLOT(slotMenuPopup()) ); + connect( menu, SIGNAL(activated(int)), SLOT(slotMenuActivated(int)) ); + + childDock = new QObjectList(); + childDock->setAutoDelete( false ); +} + +PMDockManager::~PMDockManager() +{ + delete menuData; + delete menu; + + QObjectListIt it( *childDock ); + PMDockWidget * obj; + + while ( (obj=(PMDockWidget*)it.current()) ) { + delete obj; + } + delete childDock; + delete d; +} + +void PMDockManager::activate() +{ + QObjectListIt it( *childDock ); + PMDockWidget * obj; + + while ( (obj=(PMDockWidget*)it.current()) ) { + ++it; + if ( obj->widget ) obj->widget->show(); + if ( !obj->parentDockTabGroup() ){ + obj->show(); + } + } + if ( !main->inherits("QDialog") ) main->show(); +} + +bool PMDockManager::eventFilter( QObject *obj, QEvent *event ) +{ +/* This doesn't seem to fullfill any sense, other than breaking + QMainWindow's layout all over the place + The first child of the mainwindow is not necessarily a meaningful + content widget but in Qt3's QMainWindow it can easily be a QToolBar. + In short: QMainWindow knows how to layout its children, no need to + mess that up. + + >>>>>I need this in the PMDockArea at the moment (JoWenn) + + if ( obj == main && event->type() == QEvent::Resize && dynamic_cast(main) && main->children() ){ +#ifndef NO_KDE2 + kdDebug()<<"PMDockManager::eventFilter(): main is a PMDockArea and there are children"<children()->getFirst(); + if ( fc ) + fc->setGeometry( QRect(QPoint(0,0), main->geometry().size()) ); + } +*/ + + if ( obj->inherits("PMDockWidgetAbstractHeaderDrag") ){ + PMDockWidget* pDockWdgAtCursor = 0L; + PMDockWidget* curdw = ((PMDockWidgetAbstractHeaderDrag*)obj)->dockWidget(); + switch ( event->type() ){ + case QEvent::MouseButtonDblClick: + if (curdw->currentDockPos == PMDockWidget::DockDesktop) curdw->dockBack(); + else curdw->toDesktop( ); + break; + case QEvent::MouseButtonPress: + if ( ((QMouseEvent*)event)->button() == LeftButton ){ + if ( curdw->eDocking != (int)PMDockWidget::DockNone ){ + dropCancel = true; + curdw->setFocus(); + qApp->processOneEvent(); + + currentDragWidget = curdw; + currentMoveWidget = 0L; + childDockWidgetList = new QWidgetList(); + childDockWidgetList->append( curdw ); + findChildDockWidget( curdw, *childDockWidgetList ); + + d->oldDragRect = QRect(); + d->dragRect = QRect(curdw->geometry()); + QPoint p = curdw->mapToGlobal(QPoint(0,0)); + d->dragRect.moveTopLeft(p); + drawDragRectangle(); + d->readyToDrag = true; + + d->dragOffset = QCursor::pos()-currentDragWidget->mapToGlobal(QPoint(0,0)); + } + } + break; + case QEvent::MouseButtonRelease: + if ( ((QMouseEvent*)event)->button() == LeftButton ){ + if ( draging ){ + if ( !dropCancel ) + drop(); + else + cancelDrop(); + } + if (d->readyToDrag) { + d->readyToDrag = false; + d->oldDragRect = QRect(); + d->dragRect = QRect(curdw->geometry()); + QPoint p = curdw->mapToGlobal(QPoint(0,0)); + d->dragRect.moveTopLeft(p); + drawDragRectangle(); + currentDragWidget = 0L; + delete childDockWidgetList; + childDockWidgetList = 0L; + } + draging = false; + dropCancel = true; + } + break; + case QEvent::MouseMove: + if ( draging ) { + pDockWdgAtCursor = findDockWidgetAt( QCursor::pos() ); + PMDockWidget* oldMoveWidget = currentMoveWidget; + if ( currentMoveWidget && pDockWdgAtCursor == currentMoveWidget ) { //move + dragMove( currentMoveWidget, currentMoveWidget->mapFromGlobal( QCursor::pos() ) ); + break; + } else { + if (dropCancel && curdw) { + d->dragRect = QRect(curdw->geometry()); + QPoint p = curdw->mapToGlobal(QPoint(0,0)); + d->dragRect.moveTopLeft(p); + }else + d->dragRect = QRect(); + + drawDragRectangle(); + } + + if ( !pDockWdgAtCursor && (curdw->eDocking & (int)PMDockWidget::DockDesktop) == 0 ){ + // just moving at the desktop + currentMoveWidget = pDockWdgAtCursor; + curPos = PMDockWidget::DockDesktop; + } else { + if ( oldMoveWidget && pDockWdgAtCursor != currentMoveWidget ) { //leave + currentMoveWidget = pDockWdgAtCursor; + curPos = PMDockWidget::DockDesktop; + } + } + + if ( oldMoveWidget != pDockWdgAtCursor && pDockWdgAtCursor ) { //enter pDockWdgAtCursor + currentMoveWidget = pDockWdgAtCursor; + curPos = PMDockWidget::DockDesktop; + } + } else { + if (d->readyToDrag) { + d->readyToDrag = false; + } + if ( (((QMouseEvent*)event)->state() == LeftButton) && + (curdw->eDocking != (int)PMDockWidget::DockNone) ) { + startDrag( curdw); + } + } + break; + default: + break; + } + } + return QObject::eventFilter( obj, event ); +} + +PMDockWidget* PMDockManager::findDockWidgetAt( const QPoint& pos ) +{ + dropCancel = true; + + if (!currentDragWidget) + return 0L; // pointer access safety + + if (currentDragWidget->eDocking == (int)PMDockWidget::DockNone ) return 0L; + + QWidget* p = QApplication::widgetAt( pos ); + if ( !p ) { + dropCancel = false; + return 0L; + } +#if defined(_OS_WIN32_) || defined(Q_OS_WIN32) + p = p->topLevelWidget(); +#endif + QWidget* w = 0L; + findChildDockWidget( w, p, p->mapFromGlobal(pos) ); + if ( !w ){ + if ( !p->inherits("PMDockWidget") ) { + return 0L; + } + w = p; + } + if ( qt_find_obj_child( w, "PMDockSplitter", "_dock_split_" ) ) return 0L; + if ( qt_find_obj_child( w, "PMDockTabGroup", "_dock_tab" ) ) return 0L; + if (!childDockWidgetList) return 0L; + if ( childDockWidgetList->find(w) != -1 ) return 0L; + if ( currentDragWidget->isGroup && ((PMDockWidget*)w)->parentDockTabGroup() ) return 0L; + + PMDockWidget* www = (PMDockWidget*)w; + if ( www->dockSite( ) == (int)PMDockWidget::DockNone ) return 0L; + + PMDockWidget::DockPosition curPos = PMDockWidget::DockDesktop; + QPoint cpos = www->mapFromGlobal( pos ); + + int ww = www->widget->width() / 3; + int hh = www->widget->height() / 3; + + if ( cpos.y() <= hh ){ + curPos = PMDockWidget::DockTop; + } else + if ( cpos.y() >= 2*hh ){ + curPos = PMDockWidget::DockBottom; + } else + if ( cpos.x() <= ww ){ + curPos = PMDockWidget::DockLeft; + } else + if ( cpos.x() >= 2*ww ){ + curPos = PMDockWidget::DockRight; + } else + curPos = PMDockWidget::DockCenter; + + if ( !(www->dockSite( ) & (int)curPos) ) return 0L; + if ( !(currentDragWidget->eDocking & (int)curPos) ) return 0L; + if ( www->manager != this ) return 0L; + + dropCancel = false; + return www; +} + +void PMDockManager::findChildDockWidget( QWidget*& ww, const QWidget* p, const QPoint& pos ) +{ + if ( p->children() ) { + QWidget *w; + QObjectListIt it( *p->children() ); + it.toLast(); + while ( it.current() ) { + if ( it.current()->isWidgetType() ) { + w = (QWidget*)it.current(); + if ( w->isVisible() && w->geometry().contains(pos) ) { + if ( w->inherits("PMDockWidget") ) ww = w; + findChildDockWidget( ww, w, w->mapFromParent(pos) ); + return; + } + } + --it; + } + } + return; +} + +void PMDockManager::findChildDockWidget( const QWidget* p, QWidgetList& list ) +{ + if ( p->children() ) { + QWidget *w; + QObjectListIt it( *p->children() ); + it.toLast(); + while ( it.current() ) { + if ( it.current()->isWidgetType() ) { + w = (QWidget*)it.current(); + if ( w->isVisible() ) { + if ( w->inherits("PMDockWidget") ) list.append( w ); + findChildDockWidget( w, list ); + } + } + --it; + } + } + return; +} + +void PMDockManager::findFloatingWidgets( QPtrList& l ) +{ + QObjectListIt it( *childDock ); + for( ; it.current( ); ++it ) + if( it.current( )->inherits( "PMDockWidget" ) && + !it.current( )->parent( ) ) + l.append( ( PMDockWidget* ) it.current( ) ); +} + +void PMDockManager::startDrag( PMDockWidget* w ) +{ + if(( w->currentDockPos == PMDockWidget::DockLeft) || ( w->currentDockPos == PMDockWidget::DockRight) + || ( w->currentDockPos == PMDockWidget::DockTop) || ( w->currentDockPos == PMDockWidget::DockBottom)) { + w->prevSideDockPosBeforeDrag = w->currentDockPos; + + if ( w->parentWidget()->inherits("PMDockSplitter") ){ + PMDockSplitter* parentSplitterOfDockWidget = (PMDockSplitter*)(w->parentWidget()); + w->d->splitPosInPercent = parentSplitterOfDockWidget->separatorPos(); + } + } + + curPos = PMDockWidget::DockDesktop; + draging = true; + + QApplication::setOverrideCursor(QCursor(sizeAllCursor)); +} + +void PMDockManager::dragMove( PMDockWidget* dw, QPoint pos ) +{ + QPoint p = dw->mapToGlobal( dw->widget->pos() ); + PMDockWidget::DockPosition oldPos = curPos; + + QSize r = dw->widget->size(); + if ( dw->parentDockTabGroup() ){ + curPos = PMDockWidget::DockCenter; + if ( oldPos != curPos ) { + d->dragRect.setRect( p.x()+2, p.y()+2, r.width()-4, r.height()-4 ); + } + return; + } + + int w = r.width() / 3; + int h = r.height() / 3; + + PMDockMainWindow* mw = ( PMDockMainWindow* ) parent( ); + QWidget* cw = mw->centralWidget( ); + QPoint cwp = cw->mapToGlobal( QPoint( 0, 0 ) ); + int cwh = cw->height( ); + + if ( pos.y() <= h ) + { + curPos = PMDockWidget::DockTop; + w = r.width(); + } + else if ( pos.y() >= 2*h ) + { + curPos = PMDockWidget::DockBottom; + p.setY( p.y() + 2*h ); + w = r.width(); + } + else if ( pos.x() <= w ) + { + curPos = PMDockWidget::DockLeft; + h = r.height(); + p.setY( cwp.y( ) ); + h = cwh; + } + else if ( pos.x() >= 2*w ) + { + curPos = PMDockWidget::DockRight; + p.setX( p.x() + 2*w ); + p.setY( cwp.y( ) ); + h = cwh; + } + else + { + curPos = PMDockWidget::DockCenter; + p.setX( p.x() + w ); + p.setY( p.y() + h ); + } + + if ( oldPos != curPos ) { + d->dragRect.setRect( p.x(), p.y(), w, h ); + drawDragRectangle(); + } +} + + +void PMDockManager::cancelDrop() +{ + QApplication::restoreOverrideCursor(); + + delete childDockWidgetList; + childDockWidgetList = 0L; + + d->dragRect = QRect(); // cancel drawing + drawDragRectangle(); // only the old rect will be deleted +} + + +void PMDockManager::drop() +{ + d->dragRect = QRect(); // cancel drawing + drawDragRectangle(); // only the old rect will be deleted + + QApplication::restoreOverrideCursor(); + + delete childDockWidgetList; + childDockWidgetList = 0L; + + if ( dropCancel ) return; + if ( !currentMoveWidget && ((currentDragWidget->eDocking & (int)PMDockWidget::DockDesktop) == 0) ) { + d->dragRect = QRect(); // cancel drawing + drawDragRectangle(); // only the old rect will be deleted + return; + } + if ( !currentMoveWidget && !currentDragWidget->parent() ) { + currentDragWidget->move( QCursor::pos() - d->dragOffset ); + } + else { + int splitPos = currentDragWidget->d->splitPosInPercent; + // do we have to calculate 100%-splitPosInPercent? + if( (curPos != currentDragWidget->prevSideDockPosBeforeDrag) && (curPos != PMDockWidget::DockCenter) && (curPos != PMDockWidget::DockDesktop)) { + switch( currentDragWidget->prevSideDockPosBeforeDrag) { + case PMDockWidget::DockLeft: if(curPos != PMDockWidget::DockTop) splitPos = 100-splitPos; break; + case PMDockWidget::DockRight: if(curPos != PMDockWidget::DockBottom) splitPos = 100-splitPos; break; + case PMDockWidget::DockTop: if(curPos != PMDockWidget::DockLeft) splitPos = 100-splitPos; break; + case PMDockWidget::DockBottom: if(curPos != PMDockWidget::DockRight) splitPos = 100-splitPos; break; + default: break; + } + } + currentDragWidget->manualDock( currentMoveWidget, curPos , splitPos, QCursor::pos() - d->dragOffset ); + currentDragWidget->makeDockVisible(); + } +} + + +static QDomElement createStringEntry(QDomDocument &doc, const QString &tagName, const QString &str) +{ + QDomElement el = doc.createElement(tagName); + + el.appendChild(doc.createTextNode(str)); + return el; +} + + +static QDomElement createBoolEntry(QDomDocument &doc, const QString &tagName, bool b) +{ + return createStringEntry(doc, tagName, QString::fromLatin1(b? "true" : "false")); +} + + +static QDomElement createNumberEntry(QDomDocument &doc, const QString &tagName, int n) +{ + return createStringEntry(doc, tagName, QString::number(n)); +} + + +static QDomElement createRectEntry(QDomDocument &doc, const QString &tagName, const QRect &rect) +{ + QDomElement el = doc.createElement(tagName); + + QDomElement xel = doc.createElement("x"); + xel.appendChild(doc.createTextNode(QString::number(rect.x()))); + el.appendChild(xel); + QDomElement yel = doc.createElement("y"); + yel.appendChild(doc.createTextNode(QString::number(rect.y()))); + el.appendChild(yel); + QDomElement wel = doc.createElement("width"); + wel.appendChild(doc.createTextNode(QString::number(rect.width()))); + el.appendChild(wel); + QDomElement hel = doc.createElement("height"); + hel.appendChild(doc.createTextNode(QString::number(rect.height()))); + el.appendChild(hel); + + return el; +} + + +static QDomElement createListEntry(QDomDocument &doc, const QString &tagName, + const QString &subTagName, const QStrList &list) +{ + QDomElement el = doc.createElement(tagName); + + QStrListIterator it(list); + for (; it.current(); ++it) { + QDomElement subel = doc.createElement(subTagName); + subel.appendChild(doc.createTextNode(QString::fromLatin1(it.current()))); + el.appendChild(subel); + } + + return el; +} + + +static QString stringEntry(QDomElement &base, const QString &tagName) +{ + return base.namedItem(tagName).firstChild().toText().data(); +} + + +static bool boolEntry(QDomElement &base, const QString &tagName) +{ + return base.namedItem(tagName).firstChild().toText().data() == "true"; +} + + +static int numberEntry(QDomElement &base, const QString &tagName) +{ + return stringEntry(base, tagName).toInt(); +} + + +static QRect rectEntry(QDomElement &base, const QString &tagName) +{ + QDomElement el = base.namedItem(tagName).toElement(); + + int x = numberEntry(el, "x"); + int y = numberEntry(el, "y"); + int width = numberEntry(el, "width"); + int height = numberEntry(el, "height"); + + return QRect(x, y, width, height); +} + + +static QStrList listEntry(QDomElement &base, const QString &tagName, const QString &subTagName) +{ + QStrList list; + + QDomElement subel = base.namedItem(tagName).firstChild().toElement(); + while (!subel.isNull()) { + if (subel.tagName() == subTagName) + list.append(subel.firstChild().toText().data().latin1()); + subel = subel.nextSibling().toElement(); + } + + return list; +} + + +void PMDockManager::writeConfig(QDomElement &base) +{ + // First of all, clear the tree under base + while (!base.firstChild().isNull()) + base.removeChild(base.firstChild()); + QDomDocument doc = base.ownerDocument(); + + QStrList nameList; + QString mainWidgetStr; + + // collect widget names + QStrList nList; + QObjectListIt it(*childDock); + PMDockWidget *obj1; + while ( (obj1=(PMDockWidget*)it.current()) ) { + if ( obj1->parent() == main ) + mainWidgetStr = QString::fromLatin1(obj1->name()); + nList.append(obj1->name()); + ++it; + } + + nList.first(); + while ( nList.current() ) { + PMDockWidget *obj = getDockWidgetFromName( nList.current() ); + if (obj->isGroup && (nameList.find( obj->firstName.latin1() ) == -1 + || nameList.find(obj->lastName.latin1()) == -1)) { + // Skip until children are saved (why?) + nList.next(); + if ( !nList.current() ) nList.first(); + continue; + } + + QDomElement groupEl; + + if (obj->isGroup) { + //// Save a group + groupEl = doc.createElement("splitGroup"); + + groupEl.appendChild(createStringEntry(doc, "firstName", obj->firstName)); + groupEl.appendChild(createStringEntry(doc, "secondName", obj->lastName)); + groupEl.appendChild(createNumberEntry(doc, "orientation", (int)obj->splitterOrientation)); + groupEl.appendChild(createNumberEntry(doc, "separatorPos", ((PMDockSplitter*)obj->widget)->separatorPos())); + } else if (obj->isTabGroup) { + //// Save a tab group + groupEl = doc.createElement("tabGroup"); + + QStrList list; + for ( int i = 0; i < ((PMDockTabGroup*)obj->widget)->count(); ++i ) + list.append( ((PMDockTabGroup*)obj->widget)->page( i )->name() ); + groupEl.appendChild(createListEntry(doc, "tabs", "tab", list)); + groupEl.appendChild(createNumberEntry(doc, "currentTab", ((PMDockTabGroup*)obj->widget)->currentPageIndex())); + } else { + //// Save an ordinary dock widget + groupEl = doc.createElement("dock"); + } + + groupEl.appendChild(createStringEntry(doc, "name", QString::fromLatin1(obj->name()))); + groupEl.appendChild(createBoolEntry(doc, "hasParent", obj->parent())); + if ( !obj->parent() ) { + groupEl.appendChild(createRectEntry(doc, "geometry", QRect(main->frameGeometry().topLeft(), main->size()))); + groupEl.appendChild(createBoolEntry(doc, "visible", obj->isVisible())); + } + if (obj->header && obj->header->inherits("PMDockWidgetHeader")) { + PMDockWidgetHeader *h = static_cast(obj->header); + groupEl.appendChild(createBoolEntry(doc, "dragEnabled", h->dragEnabled())); + } + + base.appendChild(groupEl); + nameList.append(obj->name()); + nList.remove(); + nList.first(); + } + + if (main->inherits("PMDockMainWindow")) { + PMDockMainWindow *dmain = (PMDockMainWindow*)main; + QString centralWidgetStr = QString(dmain->centralWidget()? dmain->centralWidget()->name() : ""); + base.appendChild(createStringEntry(doc, "centralWidget", centralWidgetStr)); + QString mainDockWidgetStr = QString(dmain->getMainDockWidget()? dmain->getMainDockWidget()->name() : ""); + base.appendChild(createStringEntry(doc, "mainDockWidget", mainDockWidgetStr)); + } else { + base.appendChild(createStringEntry(doc, "mainWidget", mainWidgetStr)); + } + + base.appendChild(createRectEntry(doc, "geometry", QRect(main->frameGeometry().topLeft(), main->size()))); +} + + +void PMDockManager::readConfig(QDomElement &base) +{ + if (base.namedItem("group").isNull() + && base.namedItem("tabgroup").isNull() + && base.namedItem("dock").isNull()) { + activate(); + return; + } + + autoCreateDock = new QObjectList(); + autoCreateDock->setAutoDelete( true ); + + bool isMainVisible = main->isVisible(); + main->hide(); + + QObjectListIt it(*childDock); + PMDockWidget *obj1; + while ( (obj1=(PMDockWidget*)it.current()) ) { + if ( !obj1->isGroup && !obj1->isTabGroup ) { + if ( obj1->parent() ) + obj1->undock(); + else + obj1->hide(); + } + ++it; + } + + QDomElement childEl = base.firstChild().toElement(); + while (!childEl.isNull() ) { + PMDockWidget *obj = 0; + + if (childEl.tagName() == "splitGroup") { + // Read a group + QString name = stringEntry(childEl, "name"); + QString firstName = stringEntry(childEl, "firstName"); + QString secondName = stringEntry(childEl, "secondName"); + int orientation = numberEntry(childEl, "orientation"); + int separatorPos = numberEntry(childEl, "separatorPos"); + + PMDockWidget *first = getDockWidgetFromName(firstName); + PMDockWidget *second = getDockWidgetFromName(secondName); + if (first && second) { + obj = first->manualDock(second, + (orientation == (int)Vertical)? PMDockWidget::DockLeft : PMDockWidget::DockTop, + separatorPos); + if (obj) + obj->setName(name.latin1()); + } + } else if (childEl.tagName() == "tabGroup") { + // Read a tab group + QString name = stringEntry(childEl, "name"); + QStrList list = listEntry(childEl, "tabs", "tab"); + + PMDockWidget *d1 = getDockWidgetFromName( list.first() ); + list.next(); + PMDockWidget *d2 = getDockWidgetFromName( list.current() ); + + PMDockWidget *obj = d2->manualDock( d1, PMDockWidget::DockCenter ); + if (obj) { + PMDockTabGroup *tab = (PMDockTabGroup*)obj->widget; + list.next(); + while (list.current() && obj) { + PMDockWidget *tabDock = getDockWidgetFromName(list.current()); + obj = tabDock->manualDock(d1, PMDockWidget::DockCenter); + list.next(); + } + if (obj) { + obj->setName(name.latin1()); + tab->showPage(tab->page(numberEntry(childEl, "currentTab"))); + } + } + } else if (childEl.tagName() == "dock") { + // Read an ordinary dock widget + obj = getDockWidgetFromName(stringEntry(childEl, "name")); + } + + if (!boolEntry(childEl, "hasParent")) { + QRect r = rectEntry(childEl, "geometry"); + obj = getDockWidgetFromName(stringEntry(childEl, "name")); + obj->applyToWidget(0); + obj->setGeometry(r); + if (boolEntry(childEl, "visible")) + obj->QWidget::show(); + } + + if (obj && obj->header && obj->header->inherits("PMDockWidgetHeader")) { + PMDockWidgetHeader *h = static_cast(obj->header); + h->setDragEnabled(boolEntry(childEl, "dragEnabled")); + } + + childEl = childEl.nextSibling().toElement(); + } + + if (main->inherits("PMDockMainWindow")) { + PMDockMainWindow *dmain = (PMDockMainWindow*)main; + + QString mv = stringEntry(base, "centralWidget"); + if (!mv.isEmpty() && getDockWidgetFromName(mv) ) { + PMDockWidget *mvd = getDockWidgetFromName(mv); + mvd->applyToWidget(dmain); + mvd->show(); + dmain->setCentralWidget(mvd); + } + QString md = stringEntry(base, "mainDockWidget"); + if (!md.isEmpty() && getDockWidgetFromName(md)) { + PMDockWidget *mvd = getDockWidgetFromName(md); + dmain->setMainDockWidget(mvd); + } + } else { + QString mv = stringEntry(base, "mainWidget"); + if (!mv.isEmpty() && getDockWidgetFromName(mv)) { + PMDockWidget *mvd = getDockWidgetFromName(mv); + mvd->applyToWidget(main); + mvd->show(); + } + } + + QRect mr = rectEntry(base, "geometry"); + main->setGeometry(mr); + if (isMainVisible) + main->show(); + + delete autoCreateDock; + autoCreateDock = 0; +} + + +#ifndef NO_KDE2 +void PMDockManager::writeConfig( KConfig* c, QString group ) +{ + //debug("BEGIN Write Config"); + if ( !c ) c = KGlobal::config(); + if ( group.isEmpty() ) group = "dock_setting_default"; + + c->setGroup( group ); + c->writeEntry( "Version", DOCK_CONFIG_VERSION ); + + QStrList nameList; + QStrList findList; + QObjectListIt it( *childDock ); + PMDockWidget * obj; + + // collect PMDockWidget's name + QStrList nList; + while ( (obj=(PMDockWidget*)it.current()) ) { + ++it; + //debug(" +Add subdock %s", obj->name()); + nList.append( obj->name() ); + if ( obj->parent() == main ) + c->writeEntry( "Main:view", obj->name() ); + } + + nList.first(); + while ( nList.current() ){ + //debug(" -Try to save %s", nList.current()); + obj = getDockWidgetFromName( nList.current() ); + QString cname = obj->name(); + if ( obj->header ){ + obj->header->saveConfig( c ); + } +/*************************************************************************************************/ + if ( obj->isGroup ){ + if ( findList.find( obj->firstName.latin1() ) != -1 && findList.find( obj->lastName.latin1() ) != -1 ){ + + c->writeEntry( cname+":type", "GROUP"); + if ( !obj->parent() ){ + c->writeEntry( cname+":parent", "___null___"); + c->writeEntry( cname+":geometry", QRect(obj->frameGeometry().topLeft(), obj->size()) ); + c->writeEntry( cname+":visible", obj->isVisible()); + } else { + c->writeEntry( cname+":parent", "yes"); + } + c->writeEntry( cname+":first_name", obj->firstName ); + c->writeEntry( cname+":last_name", obj->lastName ); + c->writeEntry( cname+":orientation", (int)obj->splitterOrientation ); + c->writeEntry( cname+":sepPos", ((PMDockSplitter*)obj->widget)->separatorPos() ); + + nameList.append( obj->name() ); + findList.append( obj->name() ); + //debug(" Save %s", nList.current()); + nList.remove(); + nList.first(); + } else { +/*************************************************************************************************/ + //debug(" Skip %s", nList.current()); + //if ( findList.find( obj->firstName ) == -1 ) + // debug(" ? Not found %s", obj->firstName); + //if ( findList.find( obj->lastName ) == -1 ) + // debug(" ? Not found %s", obj->lastName); + nList.next(); + if ( !nList.current() ) nList.first(); + } + } else { +/*************************************************************************************************/ + if ( obj->isTabGroup){ + c->writeEntry( cname+":type", "TAB_GROUP"); + if ( !obj->parent() ){ + c->writeEntry( cname+":parent", "___null___"); + c->writeEntry( cname+":geometry", QRect(obj->frameGeometry().topLeft(), obj->size()) ); + c->writeEntry( cname+":visible", obj->isVisible()); + } else { + c->writeEntry( cname+":parent", "yes"); + } + QStrList list; + for ( int i = 0; i < ((PMDockTabGroup*)obj->widget)->count(); ++i ) + list.append( ((PMDockTabGroup*)obj->widget)->page( i )->name() ); + c->writeEntry( cname+":tabNames", list ); + c->writeEntry( cname+":curTab", ((PMDockTabGroup*)obj->widget)->currentPageIndex() ); + + nameList.append( obj->name() ); + findList.append( obj->name() ); // not really need !!! + //debug(" Save %s", nList.current()); + nList.remove(); + nList.first(); + } else { +/*************************************************************************************************/ + if ( !obj->parent() ){ + c->writeEntry( cname+":type", "NULL_DOCK"); + c->writeEntry( cname+":geometry", QRect(obj->frameGeometry().topLeft(), obj->size()) ); + c->writeEntry( cname+":visible", obj->isVisible()); + } else { + c->writeEntry( cname+":type", "DOCK"); + } + nameList.append( cname.latin1() ); + //debug(" Save %s", nList.current()); + findList.append( obj->name() ); + nList.remove(); + nList.first(); + } + } + } + c->writeEntry( "NameList", nameList ); + + c->writeEntry( "Main:Geometry", QRect(main->frameGeometry().topLeft(), main->size()) ); + c->writeEntry( "Main:visible", main->isVisible()); // curently nou use + + if ( main->inherits("PMDockMainWindow") ){ + PMDockMainWindow* dmain = (PMDockMainWindow*)main; + // for PMDockMainWindow->setView() in readConfig() + c->writeEntry( "Main:view", dmain->centralWidget() ? dmain->centralWidget()->name():"" ); + c->writeEntry( "Main:dock", dmain->getMainDockWidget() ? dmain->getMainDockWidget()->name() :"" ); + } + + c->sync(); + //debug("END Write Config"); +} +#include +void PMDockManager::readConfig( KConfig* c, QString group ) +{ + if ( !c ) c = KGlobal::config(); + if ( group.isEmpty() ) group = "dock_setting_default"; + + c->setGroup( group ); + QStrList nameList; + c->readListEntry( "NameList", nameList ); + QString ver = c->readEntry( "Version", "0.0.1" ); + nameList.first(); + if ( !nameList.current() || ver != DOCK_CONFIG_VERSION ){ + activate(); + return; + } + + autoCreateDock = new QObjectList(); + autoCreateDock->setAutoDelete( true ); + + bool isMainVisible = main->isVisible(); + // if (isMainVisible) // CCC + //QMessageBox::information(0,"","hallo"); +//COMMENTED4TESTING main->hide(); + + QObjectListIt it( *childDock ); + PMDockWidget * obj; + + while ( (obj=(PMDockWidget*)it.current()) ){ + ++it; + if ( !obj->isGroup && !obj->isTabGroup ) + { + if ( obj->parent() ) obj->undock(); else obj->hide(); + } + } + + nameList.first(); + while ( nameList.current() ){ + QString oname = nameList.current(); + c->setGroup( group ); + QString type = c->readEntry( oname + ":type" ); + obj = 0L; + + if ( type == "GROUP" ){ + PMDockWidget* first = getDockWidgetFromName( c->readEntry( oname + ":first_name" ) ); + PMDockWidget* last = getDockWidgetFromName( c->readEntry( oname + ":last_name" ) ); + int sepPos = c->readNumEntry( oname + ":sepPos" ); + + Orientation p = (Orientation)c->readNumEntry( oname + ":orientation" ); + if ( first && last ){ + obj = first->manualDock( last, ( p == Vertical ) ? PMDockWidget::DockLeft : PMDockWidget::DockTop, sepPos ); + if (obj){ + obj->setName( oname.latin1() ); + } + } + } + + if ( type == "TAB_GROUP" ){ + QStrList list; + PMDockWidget* tabDockGroup = 0L; + c->readListEntry( oname+":tabNames", list ); + PMDockWidget* d1 = getDockWidgetFromName( list.first() ); + list.next(); + PMDockWidget* d2 = getDockWidgetFromName( list.current() ); + tabDockGroup = d2->manualDock( d1, PMDockWidget::DockCenter ); + if ( tabDockGroup ){ + PMDockTabGroup* tab = (PMDockTabGroup*)tabDockGroup->widget; + list.next(); + while ( list.current() && tabDockGroup ){ + PMDockWidget* tabDock = getDockWidgetFromName( list.current() ); + tabDockGroup = tabDock->manualDock( d1, PMDockWidget::DockCenter ); + list.next(); + } + if ( tabDockGroup ){ + tabDockGroup->setName( oname.latin1() ); + c->setGroup( group ); + tab->showPage( tab->page( c->readNumEntry( oname+":curTab" ) ) ); + } + } + obj = tabDockGroup; + } + + if ( type == "NULL_DOCK" || c->readEntry( oname + ":parent") == "___null___" ){ + QRect r = c->readRectEntry( oname + ":geometry" ); + obj = getDockWidgetFromName( oname ); + obj->applyToWidget( 0L ); + obj->setGeometry(r); + + c->setGroup( group ); + if ( c->readBoolEntry( oname + ":visible" ) ){ + obj->QWidget::show(); + } + } + + if ( type == "DOCK" ){ + obj = getDockWidgetFromName( oname ); + } + + if ( obj && obj->header){ + obj->header->loadConfig( c ); + } + nameList.next(); + } + + if ( main->inherits("PMDockMainWindow") ){ + PMDockMainWindow* dmain = (PMDockMainWindow*)main; + + c->setGroup( group ); + QString mv = c->readEntry( "Main:view" ); + if ( !mv.isEmpty() && getDockWidgetFromName( mv ) ){ + PMDockWidget* mvd = getDockWidgetFromName( mv ); + mvd->applyToWidget( dmain ); + mvd->show(); + dmain->setView( mvd ); + } + c->setGroup( group ); + QString md = c->readEntry( "Main:dock" ); + if ( !md.isEmpty() && getDockWidgetFromName( md ) ){ + PMDockWidget* mvd = getDockWidgetFromName( md ); + dmain->setMainDockWidget( mvd ); + } + } else { + c->setGroup( group ); + QString mv = c->readEntry( "Main:view" ); + if ( !mv.isEmpty() && getDockWidgetFromName( mv ) ){ + PMDockWidget* mvd = getDockWidgetFromName( mv ); + mvd->applyToWidget( main ); + mvd->show(); + } + + } + // delete all autocreate dock + delete autoCreateDock; + autoCreateDock = 0L; + + c->setGroup( group ); + QRect mr = c->readRectEntry("Main:Geometry"); + main->setGeometry(mr); + if ( isMainVisible ) main->show(); +} +#endif + +PMDockWidget* PMDockManager::getDockWidgetFromName( const QString& dockName ) +{ + QObjectListIt it( *childDock ); + PMDockWidget * obj; + while ( (obj=(PMDockWidget*)it.current()) ) { + ++it; + if ( QString(obj->name()) == dockName ) return obj; + } + + PMDockWidget* autoCreate = 0L; + if ( autoCreateDock ){ + autoCreate = new PMDockWidget( this, dockName.latin1(), QPixmap("") ); + autoCreateDock->append( autoCreate ); + } + return autoCreate; +} +void PMDockManager::setSplitterOpaqueResize(bool b) +{ + d->splitterOpaqueResize = b; +} + +bool PMDockManager::splitterOpaqueResize() const +{ + return d->splitterOpaqueResize; +} + +void PMDockManager::setSplitterKeepSize(bool b) +{ + d->splitterKeepSize = b; +} + +bool PMDockManager::splitterKeepSize() const +{ + return d->splitterKeepSize; +} + +void PMDockManager::setSplitterHighResolution(bool b) +{ + d->splitterHighResolution = b; +} + +bool PMDockManager::splitterHighResolution() const +{ + return d->splitterHighResolution; +} + +void PMDockManager::slotMenuPopup() +{ + menu->clear(); + menuData->clear(); + + QObjectListIt it( *childDock ); + PMDockWidget * obj; + int numerator = 0; + while ( (obj=(PMDockWidget*)it.current()) ) { + ++it; + if ( obj->mayBeHide() ) + { + menu->insertItem( obj->icon() ? *(obj->icon()) : QPixmap(), QString("Hide ") + obj->caption(), numerator++ ); + menuData->append( new MenuDockData( obj, true ) ); + } + + if ( obj->mayBeShow() ) + { + menu->insertItem( obj->icon() ? *(obj->icon()) : QPixmap(), QString("Show ") + obj->caption(), numerator++ ); + menuData->append( new MenuDockData( obj, false ) ); + } + } +} + +void PMDockManager::slotMenuActivated( int id ) +{ + MenuDockData* data = menuData->at( id ); + data->dock->changeHideShowState(); +} + +PMDockWidget* PMDockManager::findWidgetParentDock( QWidget* w ) const +{ + QObjectListIt it( *childDock ); + PMDockWidget * dock; + PMDockWidget * found = 0L; + + while ( (dock=(PMDockWidget*)it.current()) ) { + ++it; + if ( dock->widget == w ){ found = dock; break; } + } + return found; +} + +void PMDockManager::drawDragRectangle() +{ + if (d->oldDragRect == d->dragRect) + return; + + int i; + QRect oldAndNewDragRect[2]; + oldAndNewDragRect[0] = d->oldDragRect; + oldAndNewDragRect[1] = d->dragRect; + + // 2 calls, one for the old and one for the new drag rectangle + for (i = 0; i <= 1; i++) { + if (oldAndNewDragRect[i].isEmpty()) + continue; + + PMDockWidget* pDockWdgAtRect = (PMDockWidget*) QApplication::widgetAt( oldAndNewDragRect[i].topLeft(), true ); + if (!pDockWdgAtRect) + continue; + + bool isOverMainWdg = false; + bool unclipped; + PMDockMainWindow* pMain = 0L; + PMDockWidget* pTLDockWdg = 0L; + QWidget* topWdg; + if (pDockWdgAtRect->topLevelWidget() == main) { + isOverMainWdg = true; + topWdg = pMain = (PMDockMainWindow*) main; + unclipped = pMain->testWFlags( WPaintUnclipped ); + pMain->setWFlags( WPaintUnclipped ); + } + else { + topWdg = pTLDockWdg = (PMDockWidget*) pDockWdgAtRect->topLevelWidget(); + unclipped = pTLDockWdg->testWFlags( WPaintUnclipped ); + pTLDockWdg->setWFlags( WPaintUnclipped ); + } + + // draw the rectangle unclipped over the main dock window + QPainter p; + p.begin( topWdg ); + if ( !unclipped ) { + if (isOverMainWdg) + pMain->clearWFlags(WPaintUnclipped); + else + pTLDockWdg->clearWFlags(WPaintUnclipped); + } + // draw the rectangle + p.setRasterOp(Qt::NotXorROP); + QRect r = oldAndNewDragRect[i]; + r.moveTopLeft( r.topLeft() - topWdg->mapToGlobal(QPoint(0,0)) ); + p.drawRect(r.x(), r.y(), r.width(), r.height()); + p.end(); + } + + // memorize the current rectangle for later removing + d->oldDragRect = d->dragRect; +} + + +#ifdef _JOWENN_EXPERIMENTAL_ + +PMDockArea::PMDockArea( QWidget* parent, const char *name) +:QWidget( parent, name) +{ + QString new_name = QString(name) + QString("_DockManager"); + dockManager = new PMDockManager( this, new_name.latin1() ); + mainDockWidget = 0L; +} + +PMDockArea::~PMDockArea() +{ + delete dockManager; +} + +PMDockWidget* PMDockArea::createDockWidget( const QString& name, const QPixmap &pixmap, QWidget* parent, const QString& strCaption, const QString& strTabPageLabel) +{ + return new PMDockWidget( dockManager, name.latin1(), pixmap, parent, strCaption, strTabPageLabel ); +} + +void PMDockArea::makeDockVisible( PMDockWidget* dock ) +{ + if ( dock != 0L) + dock->makeDockVisible(); +} + +void PMDockArea::makeDockInvisible( PMDockWidget* dock ) +{ + if ( dock != 0L) + dock->undock(); +} + +void PMDockArea::makeWidgetDockVisible( QWidget* widget ) +{ + makeDockVisible( dockManager->findWidgetParentDock(widget) ); +} + +void PMDockArea::writeDockConfig(QDomElement &base) +{ + dockManager->writeConfig(base); +} + +void PMDockArea::readDockConfig(QDomElement &base) +{ + dockManager->readConfig(base); +} + +void PMDockArea::slotDockWidgetUndocked() +{ + QObject* pSender = (QObject*) sender(); + if (!pSender->inherits("PMDockWidget")) return; + PMDockWidget* pDW = (PMDockWidget*) pSender; + emit dockWidgetHasUndocked( pDW); +} + +void PMDockArea::resizeEvent(QResizeEvent *rsize) +{ + QWidget::resizeEvent(rsize); + if (children()){ +#ifndef NO_KDE2 + kdDebug()<<"PMDockArea::resize"<setGeometry(QRect(QPoint(0,0),size())); + break; + } + delete list; +#if 0 + PMDockSplitter *split; +// for (unsigned int i=0;icount();i++) + { +// QPtrList list(children()); +// QObject *obj=((QPtrList)children())->at(i); + QObject *obj=children()->getFirst(); + if (split=dynamic_cast(obj)) + { + split->setGeometry( QRect(QPoint(0,0), size() )); +// break; + } + } +#endif + } +} + +#ifndef NO_KDE2 +void PMDockArea::writeDockConfig( KConfig* c, QString group ) +{ + dockManager->writeConfig( c, group ); +} + +void PMDockArea::readDockConfig( KConfig* c, QString group ) +{ + dockManager->readConfig( c, group ); +} + +void PMDockArea::setMainDockWidget( PMDockWidget* mdw ) +{ + if ( mainDockWidget == mdw ) return; + mainDockWidget = mdw; + mdw->applyToWidget(this); +} +#endif + + +#endif + +void PMDockWidgetAbstractHeader::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +void PMDockWidgetAbstractHeaderDrag::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +void PMDockWidgetHeaderDrag::virtual_hook( int id, void* data ) +{ PMDockWidgetAbstractHeaderDrag::virtual_hook( id, data ); } + +void PMDockWidgetHeader::virtual_hook( int id, void* data ) +{ PMDockWidgetAbstractHeader::virtual_hook( id, data ); } + +void PMDockTabGroup::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +void PMDockWidget::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +void PMDockManager::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +void PMDockMainWindow::virtual_hook( int id, void* data ) +{ KMainWindow::virtual_hook( id, data ); } + +void PMDockArea::virtual_hook( int, void* ) +{ /*KMainWindow::virtual_hook( id, data );*/ } + + +#ifndef NO_INCLUDE_MOCFILES // for Qt-only projects, because tmake doesn't take this name +#include "pmdockwidget.moc" +#endif diff --git a/kpovmodeler/pmdockwidget.h b/kpovmodeler/pmdockwidget.h new file mode 100644 index 00000000..29f6c34f --- /dev/null +++ b/kpovmodeler/pmdockwidget.h @@ -0,0 +1,1478 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 Max Judin + Copyright (C) 2000 Falk Brettschneider + Modified 2002 Andreas Zehender + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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. +*/ + +/* + activities: + ----------- + 03/2002 : Copied from kdelibs. Slightly different docking + ; behavior by Andreas Zehender + 05/2001 - : useful patches, bugfixes by Christoph Cullmann , + Joseph Wenninger and Falk Brettschneider + 03/2001 - 05/2001 : maintained and enhanced by Falk Brettschneider + 03/2000 : class documentation added by Falk Brettschneider + 10/1999 - 03/2000 : programmed by Max Judin + + C++ classes in this file: + ------------------------- + - PMDockWidgetAbstractHeader - minor helper class + - PMDockWidgetAbstractHeaderDrag - minor helper class + - PMDockWidgetHeaderDrag - drag panel in a dockwidget title bar + - PMDockWidgetHeader - dockwidget title bar containing the drag panel + - PMDockTabGroup - minor helper class + - PMDockWidget - IMPORTANT CLASS: the one and only dockwidget class + - PMDockManager - helper class + - PMDockMainWindow - IMPORTANT CLASS: a special KMainWindow that can have dockwidgets + - PMDockArea - like PMDockMainWindow but inherits just QWidget + + IMPORTANT Note: This file compiles also in Qt-only mode by using the NO_KDE2 precompiler definition! +*/ + +/* + MODIFICATIONS (zehender) + Added kparts ability from kparts/dockmainwindow +*/ + +#define _JOWENN_EXPERIMENTAL_ + + +#ifndef KDOCKWIDGET_H +#define KDOCKWIDGET_H + +#define _KDOCKWIDGET_2_2_ + +#include +#include +#include +#include +#include + +#ifndef NO_KDE2 +#include +#include +#undef EXPORT_DOCKCLASS +#define EXPORT_DOCKCLASS +#else +#include +#include "exportdockclass.h" +#include "dummykmainwindow.h" +#endif + +#include +using namespace KParts; + +class PMDockSplitter; +class PMDockManager; +class PMDockMoveManager; +class PMDockWidget; +class PMDockButton_Private; +class PMDockWidgetPrivate; +class PMDockArea; +class PMDockMainWindowPrivate; + +class QObjectList; +class QPopupMenu; +class QVBoxLayout; +class QHBoxLayout; +class QPixmap; + +#ifndef NO_KDE2 +class KToolBar; +class KConfig; +#else +class QToolBar; +#endif + +/** + * An abstract base clase for all dockwidget headers (and member of the dockwidget class set). + * See the class description of @ref PMDockWidgetHeader! + * More or less a minor helper class for the dockwidget class set. + * + * @author Max Judin (documentation: Falk Brettschneider). + */ +class PMDockWidgetAbstractHeader : public QFrame +{ + Q_OBJECT +public: + + /** + * Constructs this. + * + * @param parent the parent widget (usually a dockwidget) + * @param name the object instance name + */ + PMDockWidgetAbstractHeader( PMDockWidget* parent, const char* name = 0L ); + + /** + * Destructs this. + */ + virtual ~PMDockWidgetAbstractHeader(){}; + + /** + * Provides things concerning to switching to toplevel mode. Must be overridden by an inheriting class. + */ + virtual void setTopLevel( bool ){}; + +#ifndef NO_KDE2 + /** + * Provides saving the current configuration. Must be overridden by an inheriting class. + */ + virtual void saveConfig( KConfig* ){}; + + /** + * Provides loading the current configuration. Must be overridden by an inheriting class + */ + virtual void loadConfig( KConfig* ){}; +#endif + +protected: + virtual void virtual_hook( int id, void* data ); +private: + class PMDockWidgetAbstractHeaderPrivate; + PMDockWidgetAbstractHeaderPrivate *d; +}; + +/** + * An abstract class for all dockwidget drag-panels of a dockwidgets (and member of the dockwidget class set). + * See the class description of @ref PMDockWidgetHeaderDrag! + * More or less a minor helper class for the dockwidget class set. + * + * @author Max Judin (documentation: Falk Brettschneider). + */ +class PMDockWidgetAbstractHeaderDrag : public QFrame +{ + Q_OBJECT +public: + + /** + * Constructs this. + * + * @param parent the parent widget (usually a dockwidget header) + * @param dock the dockwidget where it belongs to + * @param name the object instance name + */ + PMDockWidgetAbstractHeaderDrag( PMDockWidgetAbstractHeader* parent, + PMDockWidget* dock, const char* name = 0L ); + + /** + * Destructs this. + */ + virtual ~PMDockWidgetAbstractHeaderDrag(){}; + + /** + * @return the dockwidget where this belongs to + */ + PMDockWidget* dockWidget() const { return dw; } + +private: + /** + * the dockwidget where this belongs to + */ + PMDockWidget* dw; +protected: + virtual void virtual_hook( int id, void* data ); +private: + class PMDockWidgetAbstractHeaderDragPrivate; + PMDockWidgetAbstractHeaderDragPrivate *d; +}; + +/** + * This special widget is the panel one can grip with the mouses (and member of the dockwidget class set). + * The widget for dragging, so to speak. + * Usually it is located in the @ref PMDockWidgetHeader. + * More or less a minor helper class for the dockwidget class set. + * + * @author Max Judin (documentation: Falk Brettschneider). + */ +class PMDockWidgetHeaderDrag : public PMDockWidgetAbstractHeaderDrag +{ + Q_OBJECT +public: + + /** + * Constructs this. + * + * @param parent the parent widget (usually a dockwidget header) + * @param dock the dockwidget where it belongs to + * @param name the object instance name + */ + PMDockWidgetHeaderDrag( PMDockWidgetAbstractHeader* parent, PMDockWidget* dock, + const char* name = 0L ); + + /** + * Destructs this. + */ + virtual ~PMDockWidgetHeaderDrag(){}; + +protected: + + /** + * Draws the drag panel (a double line) + */ + virtual void paintEvent( QPaintEvent* ); + +protected: + virtual void virtual_hook( int id, void* data ); +private: + class PMDockWidgetHeaderDragPrivate; + PMDockWidgetHeaderDragPrivate *d; +}; + +/** + * The header (additional bar) for a @ref PMDockWidget s (and member of the dockwidget class set). + * It have got the buttons located there. And it is for recording and reading the button states. + * More or less a minor helper class for the dockwidget class set. + * + * @author Max Judin (documentation: Falk Brettschneider). + */ +class PMDockWidgetHeader : public PMDockWidgetAbstractHeader +{ + Q_OBJECT +public: + + /** + * Constructs this. + * + * @param parent the parent widget (usually a dockwidget) + * @param name the object instance name + */ + PMDockWidgetHeader( PMDockWidget* parent, const char* name = 0L ); + + /** + * Destructs this. + */ + virtual ~PMDockWidgetHeader(){}; + + /** + * Hides the close button and stay button when switching to toplevel or vice versa shows them. + * + * @param t toplevel or not + */ + virtual void setTopLevel( bool t); + + /** + * Sets the drag panel of this header. + * + * @param nd A pointer to the new drag panel + */ + void setDragPanel( PMDockWidgetHeaderDrag* nd ); + + bool dragEnabled() const; + void setDragEnabled(bool b); + +#ifndef NO_KDE2 + /** + * Saves the current button state to a KDE config container object. + * + * @param c the configuration safe + */ + virtual void saveConfig( KConfig* c); + + /** + * Loads the current button state from a KDE config container object. + * + * @param c the configuration safe + */ + virtual void loadConfig( KConfig* ); +#endif + +protected slots: + /** + * Sets dragging the dockwidget off when the stay button is pressed down and vice versa. + */ + void slotStayClicked(); + +protected: + + /** + * A layout manager for placing the embedded buttons (close and stay) + */ + QHBoxLayout* layout; + + /** + * a little button for closing (undocking and hiding) the dockwidget + */ + PMDockButton_Private* closeButton; + + /** + * a little button for undocking the dockwidget and add it as + * level widget + */ + PMDockButton_Private* toDesktopButton; + + /** + * a little button for enabling/disabling dragging the dockwidget with the mouse + */ + PMDockButton_Private* stayButton; + + /** + * a little button for dock back the dockwidget to it's previous dockwidget + */ + PMDockButton_Private* dockbackButton; + + /** + * the drag panel (double line) + */ + PMDockWidgetHeaderDrag* drag; + +protected: + virtual void virtual_hook( int id, void* data ); +private: + class PMDockWidgetHeaderPrivate; + PMDockWidgetHeaderPrivate *d; +}; + +/** + * It just hides the special implementation of a dockwidget tab groups (and is member of the dockwidget class set). + * An abstraction what it is currently. + * In general it is like @ref QTabWidget but is more useful for the dockwidget class set. + * More or less a minor helper class for the dockwidget class set. + * + * @author Max Judin (documentation: Falk Brettschneider). + */ +class EXPORT_DOCKCLASS PMDockTabGroup : public QTabWidget +{ + Q_OBJECT +public: + /** + * Constructs this. It just calls the method of the base class. + */ + PMDockTabGroup( QWidget *parent = 0, const char *name = 0 ) + :QTabWidget( parent, name ){}; + + /** + * Destructs a PMDockTabGroup. + */ + virtual ~PMDockTabGroup(){}; + +protected: + virtual void virtual_hook( int id, void* data ); +private: + class PMDockTabGroupPrivate; + PMDockTabGroupPrivate *d; +}; + +/** + * Floatable widget that can be dragged around with the mouse and + * encapsulate the actual widgets (and member of the dockwidget class + * set). + * + * You just grip the double-lined panel, tear it off its parent + * widget, drag it somewhere and let it loose. Depending on the + * position where you leave it, the dockwidget becomes a toplevel + * window on the desktop (floating mode) or docks to a new widget + * (dock mode). Note: A PMDockWidget can only be docked to a + * PMDockWidget. + * + * If you want to use this kind of widget, your main application + * window has to be a @ref PMDockMainWindow. That is because it has + * got several additional dock management features, for instance a + * @ref PMDockManager that has an overview over all dockwidgets and and + * a dockmovemanager (internal class) that handles the dock process. + * + * Usually you create an PMDockWidget that covers the actual widget in this way: + *
+ * ...
+ * PMDockMainWindow* mainWidget;
+ * ...
+ * PMDockWidget* dock = 0L;
+ * dock = mainWidget->createDockWidget( "Any window caption", nicePixmap, 0L, i18n("window caption")); // 0L==no parent
+ * QWidget* actualWidget = new QWidget( dock);
+ * dock->setWidget( actualWidget); // embed it
+ * dock->setToolTipString(i18n("That's me")); // available when appearing as tab page
+ * ...
+ * 
+ * + * See @ref PMDockMainWindow how a dockwidget is docked in. + * + * + * @author Max Judin (documentation: Falk Brettschneider). + */ +class EXPORT_DOCKCLASS PMDockWidget: public QWidget +{ + Q_OBJECT +friend class PMDockManager; +friend class PMDockSplitter; +friend class PMDockMainWindow; +friend class PMDockArea; + +public: + /** + * Construct a dockwidget. + * + * Initially, docking to another and docking to this is allowed for + * every @p DockPosition. It is supposed to be no (tab) group. It will + * taken under control of its dockmanager. + * + * @param dockManager The responsible manager (dock helper) + * @param name Object instance name + * @param pixmap An icon (for instance shown when docked centered) + * @param parent Parent widget + * @param strCaption Title of the dockwidget window (shown when toplevel) + * @param strTabPageLabel The title of the tab page (shown when in tab page mode), if it is "", only the icon will be shown, if it is 0L, the label is set to strCaption + */ + PMDockWidget( PMDockManager* dockManager, const char* name, + const QPixmap &pixmap, QWidget* parent = 0L, const QString& strCaption = 0L, + const QString& strTabPageLabel = " ", WFlags f = 0); + + /** + * Destructs a dockwidget. + */ + virtual ~PMDockWidget(); + + /** + * The possible positions where a dockwidget can dock to another dockwidget + */ + enum DockPosition + { + DockNone = 0, + DockTop = 0x0001, + DockLeft = 0x0002, + DockRight = 0x0004, + DockBottom = 0x0008, + DockCenter = 0x0010, + DockDesktop= 0x0020, + + DockCorner = DockTop | DockLeft | DockRight | DockBottom, + DockFullSite = DockCorner | DockCenter, + DockFullDocking = DockFullSite | DockDesktop + }; + + /** + * This is a key method of this class! Use it to dock dockwidgets to + * another dockwidget at the right position within its + * @ref PMDockMainWindow or a toplevel dockwidget. + * + * + * If the target is null, it will become a toplevel dockwidget at position pos; + * Note: Docking to another dockwidget means exactly: + * A new parent dockwidget will be created, that replaces the target dockwidget and contains another single helper widget (tab widget or panner) + * which contains both dockwidgets, this and the target dockwidget. So consider parent<->child relationships change completely during such actions. + * + * @param target The dockwidget to dock to + * @param dockPos One of the DockPositions this is going to dock to + * @param spliPos The split relation (in percent, or percent*100 in high resolution) between both dockwidgets, target and this + * @param pos The dock position, mainly of interest for docking to the desktop (as toplevel dockwidget) + * @param check Only for internal use; + * @param tabIndex The position index of the tab widget (when in tab page mode), -1 (default) means append + * @return result The group dockwidget that replaces the target dockwidget and will be grandparent of target and @p this. + */ + PMDockWidget* manualDock( PMDockWidget* target, DockPosition dockPos, int spliPos = 50, QPoint pos = QPoint(0,0), bool check = false, int tabIndex = -1); + + /** + * Specify where it is either possible or impossible for this to dock to another dockwidget. + * + * @param pos An OR'ed set of @p DockPositions + */ + void setEnableDocking( int pos ); + + /** + * @return Where it is either possible or impossible for this to dock to another dockwidget (an OR'ed set of DockPositions). + */ + int enableDocking() const { return eDocking; } + + /** + * Specify where it is either possible or impossible for another dockwidget to dock to this. + * + * @param pos An OR'ed set of @p DockPositions + */ + void setDockSite( int pos ){ sDocking = pos;} + + /** + * @return There it is either possible or impossible for another dockwidget to dock to this (an OR'ed set of @p DockPositions). + */ + int dockSite() const + { + // no docking if a floating dock widget + if( !parent( ) ) + return 0; + return sDocking; + } + + /** + * Sets the embedded widget. + * + * A QLayout takes care about proper resizing, automatically. + * + * @param w The pointer to the dockwidget's child widget. + */ + void setWidget( QWidget* w); + + /** + * Get the embedded widget. + * + * @return The pointer to the dockwidget's child widget, 0L if there's no such child. + */ + QWidget* getWidget() const { return widget; }; + + /** + * Sets the header of this dockwidget. + * + * A @ref QLayout takes care about proper resizing, automatically. + * The header contains the drag panel, the close button and the stay button. + * + * @param ah A base class pointer to the dockwidget header + */ + void setHeader( PMDockWidgetAbstractHeader* ah); + + /** + * Normally it simply shows the dockwidget. + * + * But additionally, if it is docked to a tab widget (@p DockCenter), it is set as the active (visible) tab page. + */ + void makeDockVisible(); + + /** + * @return If it may be possible to hide this. + * + * There are reasons that it's impossible: + * @li It is a (tab) group. + * @li It is already invisible ;-) + * @li The parent of this is the @ref PMDockMainWindow. + * @li It isn't able to dock to another widget. + */ + bool mayBeHide() const; + + /** + * @return If it may be possible to show this. + * There are reasons that it's impossible: + * @li It is a (tab) group. + * @li It is already visible ;-) + * @li The parent of this is the @p PMDockMainWindow. + */ + bool mayBeShow() const; + + /** + * @return The dockmanager that is responsible for this. + */ + PMDockManager* dockManager() const { return manager; } + + /** + * Stores a string for a tooltip. + * + * That tooltip string has only a meaning when this dockwidget is shown as tab page. + * In this case the tooltip is shown when one holds the mouse cursor on the tab page header. + * Such tooltip will for instance be useful, if you use only icons there. + * Note: Setting an empty string switches the tooltip off. + * + * @param ttStr A string for the tooltip on the tab. + */ + void setToolTipString(const QString& ttStr) { toolTipStr = ttStr; }; + + /** + * @return The tooltip string being shown on the appropriate tab page header when in dock-centered mode. + */ + const QString& toolTipString() const { return toolTipStr; }; + + /** + * @return result @p true, if a dockback is possible, otherwise @p false. + */ + bool isDockBackPossible() const; + + /** + * Sets a string that is used for the label of the tab page when in tab page mode + * @param label The new tab page label. + */ + void setTabPageLabel( const QString& label) { tabPageTitle = label; }; + + /** + * @return A string that is used for the label of the tab page when in tab page mode. + */ + const QString& tabPageLabel() const { return tabPageTitle; }; + + /** + * Catches and processes some @ref QWidget events that are interesting for dockwidgets. + */ + virtual bool event( QEvent * ); + + /** + * Add dockwidget management actions to @ref QWidget::show. + */ + virtual void show(); + /** + * @return the parent widget of this if it inherits class PMDockTabGroup + */ + PMDockTabGroup* parentDockTabGroup() const; + +#ifndef NO_KDE2 + + /** + * Sets the type of the dock window + * + * @param windowType is type of dock window + */ + void setDockWindowType (NET::WindowType windowType); + +#endif + + /** + * Sets the type of the dock window + * + * @param windowType is type of dock window + */ + void setDockWindowTransient (QWidget *parent, bool transientEnabled); + + // MODIFICATION (lpassos) + /** + * + * Return the current dock position of the widget + */ + DockPosition getDockPosition( ) const { return currentDockPos; } +public slots: + /** + * Docks a dockwidget back to the dockwidget that was the neighbor + widget before the current dock position. + */ + void dockBack(); + + /** + * Toggles the visibility state of the dockwidget if it is able to be shown or to be hidden. + */ + void changeHideShowState(); + + /** + * Undocks this. It means it becomes a toplevel widget framed by the system window manager. + * A small panel at the top of this undocked widget gives the possibility to drag it into + * another dockwidget by mouse (docking). + */ + void undock(); + + // MODIFICATION (zehender) + /** + * Docks the widget to the desktop (as a toplevel widget) + */ + void toDesktop( ); + + /** + * Sets the caption and tab label + */ + void slotSetCaption( const QString& ); + +protected: + + /** + * Checks some conditions and shows or hides the dockwidget header (drag panel). + * The header is hidden if: + * @li the parent widget is the PMDockMainWindow + * @li this is a (tab) group dockwidget + * @li it is not able to dock to another dockwidget + */ + void updateHeader(); + +signals: + /** + * Emitted when another dock widget is docking to this. + * + * @param dw the dockwidget that is docking to this + * @param dp the DockPosition where it wants to dock to + */ + void docking( PMDockWidget* dw, PMDockWidget::DockPosition dp); + + /** + * Signals that the dock default position is set. + */ + void setDockDefaultPos(); + + /** + * Emitted when the close button of the panel (@ref PMDockWidgetHeader) has been clicked. + */ + void headerCloseButtonClicked(); + + /** + * Emitted when the dockback button of the panel (@ref PMDockWidgetHeader) has been clicked. + */ + void headerDockbackButtonClicked(); + + /** + * Emitted when the widget processes a close event. + */ + void iMBeingClosed(); + /** + * Emitted when the widget has undocked. + */ + void hasUndocked(); + +protected slots: + + /** + * Does several things here when it has noticed that the former brother widget (closest neighbor) gets lost. + * The former brother widget is needed for a possible dockback action, to speak with the Beatles: + * "To get back to where you once belonged" ;-) + */ + void loseFormerBrotherDockWidget(); + +protected: + /** + * earlier closest neighbor widget, so it's possible to dock back to it. + */ + PMDockWidget* formerBrotherDockWidget; + /** + * the current dock position. + */ + DockPosition currentDockPos; + /** + * the former dock position when it really was at another position before. + */ + DockPosition formerDockPos; + /** + * a string used as tooltip for the tab page header when in dock-centered mode. + */ + QString toolTipStr; + /** + * a string used as title of the tab page when in tab page mode + */ + QString tabPageTitle; + +private: + /** + * Sets the caption (window title) of the given tab widget. + * + * @param g the group (tab) widget + */ + void setDockTabName( PMDockTabGroup* g); + + /** + * Reparent to s or set this to the PMDockMainWindow's view if s is that dockmainwindow. + * If s is O, simply move the widget. + * + * @param s the target widget to reparent to + * @param p the point to move to (if it doesn't reparent) + */ + void applyToWidget( QWidget* s, const QPoint& p = QPoint(0,0) ); + + /** + * A base class pointer to the header of this dockwidget + */ + PMDockWidgetAbstractHeader* header; + + /** + * the embedded widget + */ + QWidget* widget; + + /** + * the layout manager that takes care about proper resizing and moving the embedded widget and the header + */ + QVBoxLayout* layout; + + /** + * the responsible dockmanager + */ + PMDockManager* manager; + + /** + * an icon for the tab widget header + */ + QPixmap* pix; + + /** + * Information about the ability for docking to another dockwidget. + */ + int eDocking; + + /** + * Information which site of this dockwidget is free for docking of other dockwidgets. + */ + int sDocking; + + /** + * Previous side (left,right,top,bottom) where this dockwidget was before a dragging action, none if it wasn't dragged before. + */ + PMDockWidget::DockPosition prevSideDockPosBeforeDrag; + + // GROUP data + QString firstName; + QString lastName; + Orientation splitterOrientation; + bool isGroup; + bool isTabGroup; + +protected: + virtual void virtual_hook( int id, void* data ); +private: + PMDockWidgetPrivate *d; +}; + +/** + * The manager that knows all dockwidgets and handles the dock process (and member of the dockwidget class set). + * More or less a helper class for the PMDockWidget class set but of interest for some functionality + * that can be called within a @ref PMDockMainWindow or a @ref PMDockWidget . + * + * An important feature is the ability to read or save the current state of all things concerning to + * dockwidgets to @ref KConfig . + * + * The dockmanager is also often used when a certain dockwidget or a child of such dockwidget must be found. + * + * @author Max Judin (documentation: Falk Brettschneider). + */ +class EXPORT_DOCKCLASS PMDockManager: public QObject +{ + Q_OBJECT +friend class PMDockWidget; +friend class PMDockMainWindow; + +public: + /** + * Constructs a dockmanager. Some initialization happen: + * @li It installs an event filter for the main window, + * @li a control list for dock objects + * @li a control list for menu items concerning to menus provided by the dockmanager + * @li Some state variables are set + * + * @param mainWindow the main window controlled by this + * @param name the internal QOject name + */ + PMDockManager( QWidget* mainWindow, const char* name = 0L ); + + /** + * Destructs a dockmanager. + */ + virtual ~PMDockManager(); + +#ifndef NO_KDE2 + /** + * Saves the current state of the dockmanager and of all controlled widgets. + * State means here to save the geometry, visibility, parents, internal object names, orientation, + * separator positions, dockwidget-group information, tab widget states (if it is a tab group) and + * last but not least some necessary things for recovering the dockmainwindow state. + * + * @param c the KDE configuration saver + * @param group the name of the section in KConfig + */ + void writeConfig( KConfig* c = 0L, QString group = QString::null ); + + /** + * Like writeConfig but reads the whole stuff in. + * + * In order to restore a window configuration + * from a config file, it looks up widgets by name + * (QObject::name) in the childDock variable of + * PMDockManager. This list in turn contains all + * PMDockWidgets (according to the PMDockWidget constructor). + * So in principle, in order to restore a window layout, + * one must first construct all widgets, put each of them in a + * PMDockWidget and then call readConfig(). And for all that + * to work, each widget must have a unique name. + * + * @param c the KDE configuration saver + * @param group the name of the section in KConfig + */ + void readConfig ( KConfig* c = 0L, QString group = QString::null ); +#endif + + /** + * Saves the current dock window layout into a DOM tree below the given element. + */ + void writeConfig(QDomElement &base); + /** + * Reads the current dock window layout from a DOM tree below the given element. + */ + void readConfig(QDomElement &base); + + /** + * Shows all encapsulated widgets of all controlled dockwidgets and shows all dockwidgets which are + * parent of a dockwidget tab group. + */ + void activate(); + + /** + * It's more or less a method that catches several events which are interesting for the dockmanager. + * Mainly mouse events during the drag process of a dockwidgets are of interest here. + * + * @param _ the object that sends the event + * @param _ the event + * @return the return value of the method call of the base class method + */ + virtual bool eventFilter( QObject *, QEvent * ); + + /** + * This method finds out what a widgets' dockwidget is. That means the dockmanager has a look at all + * dockwidgets it knows and tells you when one of those dockwidgets covers the given widget. + * + * @param w any widget that is supposed to be encapsulated by one of the controlled dockwidgets + * @return the dockwidget that encapsulates that widget, otherwise 0 + */ + PMDockWidget* findWidgetParentDock( QWidget* w) const; + + /** + * Works like makeDockVisible() but can be called for widgets that covered by a dockwidget. + * + * @param w the widget that is encapsulated by a dockwidget that turns to visible. + */ + void makeWidgetDockVisible( QWidget* w ){ findWidgetParentDock(w)->makeDockVisible(); } + + /** + * @return the popupmenu for showing/hiding dockwidgets + */ + QPopupMenu* dockHideShowMenu() const { return menu; } + + /** + * @param dockName an internal QObject name + * @return the dockwidget that has got that internal QObject name + */ + PMDockWidget* getDockWidgetFromName( const QString& dockName ); + + /** + * Enables opaque resizing. Opaque resizing is initially turned off. + * Call this method before you create any dock widgets! + */ + void setSplitterOpaqueResize(bool b=true); + + /** + * Returns TRUE if opaque resizing is enabled, FALSE otherwise. + */ + bool splitterOpaqueResize() const; + + /** + * Try to preserve the widget's size. Works like KeepSize resize mode + * of QSplitter. Off by default. + * Call this method before you create any dock widgets! + */ + void setSplitterKeepSize(bool b=true); + + /** + * Returns TRUE if the KeepSize is enabled, FALSE otherwise. + */ + bool splitterKeepSize() const; + + /** + * Operate the splitter with a higher resolution. Off by default. + * Call this method before you create any dock widgets! + * If high resolution is used all splitter position parameters + * are percent*100 instead of percent. + */ + void setSplitterHighResolution(bool b=true); + + /** + * Returns TRUE if the splitter uses the high resolution, FALSE otherwise. + */ + bool splitterHighResolution() const; + + /** + * Returns the main dock widget + */ + QWidget* dockMainWidget( ) const { return main; } + +signals: + + /** + * Signals changes of the docking state of a dockwidget. Usually the dock-toolbar will be updated then. + */ + void change(); + + /** + * Signals a dockwidget is replaced with another one. + */ + void replaceDock( PMDockWidget* oldDock, PMDockWidget* newDock ); + + /** + * Signals a dockwidget without parent (toplevel) is shown. + */ + void setDockDefaultPos( PMDockWidget* ); + +private slots: + + /** + * Clears the popupmenu for showing/hiding dockwidgets and fills it with the current states of all controlled dockwidgets. + */ + void slotMenuPopup(); + + /** + * This method assumes a menuitem of the popupmenu for showing/hiding dockwidgets is selected and toggles that state. + * + * @param id the popupmenu id of the selected menuitem + */ + void slotMenuActivated( int id); + + /* clears the old drawn drag rectangle (oldDragRect) from screen and + * draws the new current drag rectangle (dragRect) depending on the current mouse position. + * This highlights the dockwidget which is the currently chosen target during a dock action. + */ + void drawDragRectangle(); + +private: + + /** + * A data structure containing data about every dockwidget that is under control. + */ + struct MenuDockData + { + MenuDockData( PMDockWidget* _dock, bool _hide ) + { + dock = _dock; + hide = _hide; + }; + ~MenuDockData(){}; + + PMDockWidget* dock; + bool hide; + }; + + /** + * Finds the PMDockWidget at the position given as parameter + * + * @param pos global (desktop) position of the wanted dockwidget + * @return the dockwidget at that position + */ + PMDockWidget* findDockWidgetAt( const QPoint& pos ); + + /** + * Finds the QWidget recursively at the position given as parameter + * + * @param w a variable where the method puts the QWidget at that position (instead of a return value) + * @param p the parent widget where the recursive search should start from + * @param pos global (desktop) position of the wanted dockwidget + */ + void findChildDockWidget( QWidget*& w, const QWidget* p, const QPoint& pos ); + // MODIFICATION (lpassos) + // Made findChildDockWidget public +public: + /** + * Finds all dockwidgets which are child, grandchild and so on of p. + * + * @param p the parent widget where the recursive search starts from + * @param l the widget list that contains the search result after the return of this method + */ + void findChildDockWidget( const QWidget* p, QWidgetList& l); + /** + * Returns all floating dock widgets + */ + void findFloatingWidgets( QPtrList& l ); + +private: + /** + * Sets a dockwidget in drag mode. + */ + void startDrag( PMDockWidget* ); + + /** + * Moves a dockwidget that is in drag mode. + * + * @param d the dockwidget which is dragged + * @param pos the new position of the dragged dockwidget + */ + void dragMove( PMDockWidget* d, QPoint pos ); + + /** + * Aborts the drag mode. Restores the cursor and hides the drag indicator. + */ + void cancelDrop(); + + /** + * Finishes the drag mode. If the user let it drop on an other dockwidget, it will possibly be docked (if allowed), + * if the user drops it outside of the application window it becomes toplevel. + */ + void drop(); + +// class members + + /** + * Usually the PMDockMainWindow but not necessarily. + */ + QWidget* main; + + /** + * The dockwidget that is being dragged at the moment + */ + PMDockWidget* currentDragWidget; + + /** + * The target dockwidget where the currentDragWidget is dropped + */ + PMDockWidget* currentMoveWidget; // widget where mouse moving + + /** + * It is of interest during the dock process. Then it contains all child dockwidgets. + */ + QWidgetList* childDockWidgetList; + + /** + * The dockposition where the dockwidget would be docked to, if we dropped it here. + */ + PMDockWidget::DockPosition curPos; + + /** + * A QList of all objects that are important for docking. + * Some serve as group widgets of dockwidgets, others encapsulate normal widgets. + */ + QObjectList* childDock; + + /** + * Contains dockwidgets that are created automatically by the dockmanager. For internal use. + */ + QObjectList* autoCreateDock; + + /** + * For storing the width during the dragging of a dockwidget. + */ + int storeW; + + /** + * For storing the height during the dragging of a dockwidget. + */ + int storeH; + + /** + * State variable if there is a drag process active. + */ + bool draging; + + /** + * State variable if there is an undock process active + */ + bool undockProcess; + + /** + * The dockmanager sets it to true if the user cancels the drag by moving the cursor + * on a invalid drop place + */ + bool dropCancel; + + /** + * A popup menu that contains one menuitem for each dockwidget that shows the current visibility state and + * to show or hide the appropriate dockwidget. + */ + QPopupMenu* menu; + + /** + * An internal list containing data for the menuitems for the visibility popup menu. + */ + QPtrList *menuData; + +protected: + virtual void virtual_hook( int id, void* data ); +private: + class PMDockManagerPrivate; + PMDockManagerPrivate *d; +}; + +/** + * A special kind of @ref KMainWindow that is able to have dockwidget child widgets (and member of the dockwidget class set). + * + * The main widget should be a @ref PMDockWidget where other @ref PMDockWidget can be docked to + * the left, right, top, bottom or to the middle. + * Note: dock to the middle means to drop on a dockwidget and to unite them to a new widget, a tab control. + * + * Furthermore, the PMDockMainWindow has got the @ref PMDockManager and some data about the dock states. + * + * If you've got some dockwidgets, you can dock them to the dockmainwindow to initialize a start scene: + * Here an example: + *
+ * DockApplication::DockApplication( const char* name) : PMDockMainWindow( name)
+ * {
+ *   ...
+ *   PMDockWidget* mainDock;
+ *   mainDock = createDockWidget( "Falk's MainDockWidget", mainPixmap, 0L, "main_dock_widget");
+ *   AnyContentsWidget* cw = new AnyContentsWidget( mainDock);
+ *   mainDock->setWidget( cw);
+ *   // allow others to dock to the 4 sides
+ *   mainDock->setDockSite(PMDockWidget::DockCorner);
+ *   // forbit docking abilities of mainDock itself
+ *   mainDock->setEnableDocking(PMDockWidget::DockNone);
+ *   setView( mainDock); // central widget in a KDE mainwindow
+ *   setMainDockWidget( mainDock); // master dockwidget
+ *   ...
+ *   PMDockWidget* dockLeft;
+ *   dockLeft = createDockWidget( "Intially left one", anyOtherPixmap, 0L, i18n("The left dockwidget"));
+ *   AnotherWidget* aw = new AnotherWidget( dockLeft);
+ *   dockLeft->setWidget( aw);
+ *   dockLeft->manualDock( mainDock,              // dock target
+ *                         PMDockWidget::DockLeft, // dock site
+ *                         20 );                  // relation target/this (in percent)
+ *   ...
+ * 
+ * + * Docking is fully dynamical at runtime. That means you can always move dockwidgets via drag and drop. + * + * And last but not least you can use the popupmenu for showing or hiding any controlled dockwidget + * of this class and insert it to your main menu bar or anywhere else. + * + * @author Max Judin (documentation: Falk Brettschneider). + */ +class EXPORT_DOCKCLASS PMDockMainWindow : public KMainWindow, virtual public PartBase +{ + Q_OBJECT + +friend class PMDockManager; + +public: + + /** + * Constructs a dockmainwindow. It calls its base class constructor and does additional things concerning + * to the dock stuff: + * @li information about the dock state of this' children gets initialized + * @li a dockmanager is created... + * @li ...and gets initialized + * @li the main dockwidget is set to 0 + * + * @param name object name + */ + PMDockMainWindow( QWidget* parent = 0L, const char *name = 0L, WFlags f = WType_TopLevel | WDestructiveClose ); + + /** + * Destructs a dockmainwindow. + */ + virtual ~PMDockMainWindow(); + + /** + * Returns the dockmanager of this. (see @ref PMDockManager) + * @return pointer to the wanted dockmanager + */ + PMDockManager* manager() const { return dockManager; } + + /** + * Sets a new main dockwidget. + * Additionally, the toolbar is re-initialized. + * + * @param _ dockwidget that become the new main dockwidget + */ + void setMainDockWidget( PMDockWidget* ); + + /** + * Returns the main dockwidget. + * + * @return pointer to the main dockwidget + */ + PMDockWidget* getMainDockWidget() const { return mainDockWidget; } + + /** + * This is one of the most important methods! + * The PMDockMainWindow creates a new dockwidget object here that usually should encapsulate the user's widget. + * The new dockwidget is automatically taken under control by the dockmanager of the dockmainwindow. + * + * @param name QObject name (default dockwidget caption) + * @param pixmap window icon (for instance shown when docked as tabwidget entry) + * @param parent parent widget for the new dockwidget + * @param strCaption window title (shown when toplevel) + * @param strTabPageLabel title of the tab page (visible when in tab page mode), if it is "", only the icon will be shown; if it is 0L, the label is set to strCaption + * @return a pointer to the new created dockwidget + */ + PMDockWidget* createDockWidget( const QString& name, const QPixmap &pixmap, QWidget* parent = 0L, const QString& strCaption = 0L, const QString& strTabPageLabel = " "); + + /** + * Saves the current dock window layout into a DOM tree below the given element. + */ + void writeDockConfig(QDomElement &base); + /** + * Reads the current dock window layout from a DOM tree below the given element. + */ + void readDockConfig(QDomElement &base); + +#ifndef NO_KDE2 + /** + * It writes the current dock state in the given section of KConfig. + * + * @param c KDE class for saving configurations + * @param group name of section to write to + */ + void writeDockConfig( KConfig* c = 0L, QString group = QString::null ); + + /** + * It reads the current dock state from the given section of KConfig. + * + * @param c KDE class for saving configurations + * @param group name of section to read from + */ + void readDockConfig ( KConfig* c = 0L, QString group = QString::null ); +#endif + + /** + * It runs through all dockwidgets which are under control of the dockmanager and calls show() for every + * encapsulated widget and show() for the dockwidget itself if it is not in tab mode. + * Additionally, if the main dockwidget is not a QDialog, it will be shown. + */ + void activateDock(){ dockManager->activate(); } + + /** + * Returns a popup menu that contains entries for all controlled dockwidgets making hiding and showing + * them possible. + * + * @return the wanted popup menu + */ + QPopupMenu* dockHideShowMenu() const { return dockManager->dockHideShowMenu(); } + + /** + * This method shows the given dockwidget. + * The clue is that it also considers the dockwidget could be a tab page + * and must set to be the activate one. + * + * @param dock the dockwidget that is to be shown + */ + void makeDockVisible( PMDockWidget* dock ); + + /** + * This method hides the given dockwidget. + * + * @param dock the dockwidget that is to be shown + */ + void makeDockInvisible( PMDockWidget* dock ); + + /** + * This is an overloaded member function, provided for convenience. + * It differs from the above function only in what argument(s) it accepts. + */ + void makeWidgetDockVisible( QWidget* widget ); + + /** + * This method calls the base class method. + * If the given widget inherits PMDockWidget, applyToWidget(this) is called. + * + * @param _ any widget that should become the main view + */ + void setView( QWidget* ); + +signals: + /** + * Signals a certain dockwidget is undocked now. + */ + void dockWidgetHasUndocked(PMDockWidget*); + +protected: + + /** + * A pointer to the main dockwidget (where one can manualDock() to + */ + PMDockWidget* mainDockWidget; + + /** + * A pointer to the manager for the dock process + */ + PMDockManager* dockManager; + +protected slots: + /** + * Called whenever one of the dockwidgets of this has been undocked. + */ + void slotDockWidgetUndocked(); + + // kparts/dockmainwindow stuff +protected slots: + + /** + * Create the GUI (by merging the host's and the active part's) + * + * Called on startup and whenever the active part changes + * For this you need to connect this slot to the + * @ref KPartManager::activePartChanged() signal + * @param part The active part (set to 0L if no part). + */ + void createGUI( KParts::Part * part ); + + /** + * Called when the active part wants to change the statusbar message + * Reimplement if your dock-mainwindow has a complex statusbar + * (with several items) + */ + virtual void slotSetStatusBarText( const QString & ); + +protected: + virtual void createShellGUI( bool create = true ); + // end kparts/dockmainwindow stuff + +protected: + virtual void virtual_hook( int id, void* data ); +private: + PMDockMainWindowPrivate *d; +}; + + + + + + + + + + + + + + + +#ifdef _JOWENN_EXPERIMENTAL_ +/* Joseph Wenninger jowenn@kde.org Experimental (Just all KMainWindow references changed to QWidget, otherwise nearly exactly the +same as PMDockMainWindow*/ + +class EXPORT_DOCKCLASS PMDockArea : public QWidget +{ + Q_OBJECT + +friend class PMDockManager; + +public: + + + PMDockArea( QWidget* parent = 0L, const char *name = 0L); + + virtual ~PMDockArea(); + + PMDockManager* manager(){ return dockManager; } + + + void setMainDockWidget( PMDockWidget* ); + PMDockWidget* getMainDockWidget(){ return mainDockWidget; } + + PMDockWidget* createDockWidget( const QString& name, const QPixmap &pixmap, QWidget* parent = 0L, const QString& strCaption = 0L, const QString& strTabPageLabel = " "); + + void writeDockConfig(QDomElement &base); + void readDockConfig(QDomElement &base); + +#ifndef NO_KDE2 + void writeDockConfig( KConfig* c = 0L, QString group = QString::null ); + void readDockConfig ( KConfig* c = 0L, QString group = QString::null ); +#endif + + + + void activateDock(){ dockManager->activate(); } + QPopupMenu* dockHideShowMenu(){ return dockManager->dockHideShowMenu(); } + void makeDockVisible( PMDockWidget* dock ); + void makeDockInvisible( PMDockWidget* dock ); + void makeWidgetDockVisible( QWidget* widget ); + //void setView( QWidget* ); + +signals: + /** + * Signals a certain dockwidget is undocked now. + */ + void dockWidgetHasUndocked(PMDockWidget*); + +protected: + + PMDockWidget* mainDockWidget; + PMDockManager* dockManager; + +protected slots: + void slotDockWidgetUndocked(); + +public: + virtual void resizeEvent(QResizeEvent *); + +protected: + virtual void virtual_hook( int id, void* data ); +private: + class PMDockMainWindowPrivate; + PMDockMainWindowPrivate *d; +}; + +#endif + +#endif + + diff --git a/kpovmodeler/pmdockwidget_private.cpp b/kpovmodeler/pmdockwidget_private.cpp new file mode 100644 index 00000000..cdf21930 --- /dev/null +++ b/kpovmodeler/pmdockwidget_private.cpp @@ -0,0 +1,372 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 Max Judin + Modified 2002 Andreas Zehender + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "pmdockwidget.h" +#include "pmdockwidget_private.h" + +#include +#include + +PMDockSplitter::PMDockSplitter(QWidget *parent, const char *name, Orientation orient, int pos, bool highResolution) +: QWidget(parent, name) +{ + divider = 0L; + child0 = 0L; + child1 = 0L; + orientation = orient; + mOpaqueResize = false; + mKeepSize = false; + mHighResolution = highResolution; + setSeparatorPos( pos, false ); + initialised = false; +} + +void PMDockSplitter::activate(QWidget *c0, QWidget *c1) +{ + if ( c0 ) child0 = c0; + if ( c1 ) child1 = c1; + + setupMinMaxSize(); + + if (divider) delete divider; + divider = new QFrame(this, "pannerdivider"); + divider->setFrameStyle(QFrame::Panel | QFrame::Raised); + divider->setLineWidth(1); + divider->raise(); + + if (orientation == Horizontal) + divider->setCursor(QCursor(sizeVerCursor)); + else + divider->setCursor(QCursor(sizeHorCursor)); + + divider->installEventFilter(this); + + initialised= true; + + updateName(); + + divider->show(); + resizeEvent(0); +} + +void PMDockSplitter::setupMinMaxSize() +{ + // Set the minimum and maximum sizes + int minx, maxx, miny, maxy; + if (orientation == Horizontal) { + miny = child0->minimumSize().height() + child1->minimumSize().height()+4; + maxy = child0->maximumSize().height() + child1->maximumSize().height()+4; + minx = (child0->minimumSize().width() > child1->minimumSize().width()) ? child0->minimumSize().width() : child1->minimumSize().width(); + maxx = (child0->maximumSize().width() > child1->maximumSize().width()) ? child0->maximumSize().width() : child1->maximumSize().width(); + + miny = (miny > 4) ? miny : 4; + maxy = (maxy < 32000) ? maxy : 32000; + minx = (minx > 2) ? minx : 2; + maxx = (maxx < 32000) ? maxx : 32000; + } else { + minx = child0->minimumSize().width() + child1->minimumSize().width()+4; + maxx = child0->maximumSize().width() + child1->maximumSize().width()+4; + miny = (child0->minimumSize().height() > child1->minimumSize().height()) ? child0->minimumSize().height() : child1->minimumSize().height(); + maxy = (child0->maximumSize().height() > child1->maximumSize().height()) ? child0->maximumSize().height() : child1->maximumSize().height(); + + minx = (minx > 4) ? minx : 4; + maxx = (maxx < 32000) ? maxx : 32000; + miny = (miny > 2) ? miny : 2; + maxy = (maxy < 32000) ? maxy : 32000; + } + setMinimumSize(minx, miny); + setMaximumSize(maxx, maxy); +} + +void PMDockSplitter::deactivate() +{ + if (divider) delete divider; + divider = 0L; + initialised= false; +} + +void PMDockSplitter::setSeparatorPos(int pos, bool do_resize) +{ + xpos = pos; + if (do_resize) + resizeEvent(0); +} + +int PMDockSplitter::separatorPos() const +{ + return xpos; +} + +void PMDockSplitter::resizeEvent(QResizeEvent *ev) +{ + if (initialised){ + int factor = (mHighResolution)? 10000:100; + // real resize event, recalculate xpos + if (ev && mKeepSize && isVisible()) { + if (orientation == Horizontal) { + if (ev->oldSize().height() != ev->size().height()) + xpos = factor * checkValue( child0->height()+1 ) / height(); + } else { + if (ev->oldSize().width() != ev->size().width()) + xpos = factor * checkValue( child0->width()+1 ) / width(); + } + } + int position = checkValue( (orientation == Vertical ? width() : height()) * xpos/factor ); + if (orientation == Horizontal){ + child0->setGeometry(0, 0, width(), position); + child1->setGeometry(0, position+4, width(), height()-position-4); + divider->setGeometry(0, position, width(), 4); + } else { + child0->setGeometry(0, 0, position, height()); + child1->setGeometry(position+4, 0, width()-position-4, height()); + divider->setGeometry(position, 0, 4, height()); + } + } +} + +int PMDockSplitter::checkValue( int position ) const +{ + if (initialised){ + if (orientation == Vertical){ + if (position < (child0->minimumSize().width())) + position = child0->minimumSize().width(); + if ((width()-4-position) < (child1->minimumSize().width())) + position = width() - (child1->minimumSize().width()) -4; + } else { + if (position < (child0->minimumSize().height())) + position = (child0->minimumSize().height()); + if ((height()-4-position) < (child1->minimumSize().height())) + position = height() - (child1->minimumSize().height()) -4; + } + } + + if (position < 0) position = 0; + + if ((orientation == Vertical) && (position > width())) + position = width(); + if ((orientation == Horizontal) && (position > height())) + position = height(); + + return position; +} + +bool PMDockSplitter::eventFilter(QObject *o, QEvent *e) +{ + QMouseEvent *mev; + bool handled = false; + int factor = (mHighResolution)? 10000:100; + + switch (e->type()) { + case QEvent::MouseMove: + mev= (QMouseEvent*)e; + child0->setUpdatesEnabled(mOpaqueResize); + child1->setUpdatesEnabled(mOpaqueResize); + if (orientation == Horizontal) { + if (!mOpaqueResize) { + int position = checkValue( mapFromGlobal(mev->globalPos()).y() ); + divider->move( 0, position ); + } else { + xpos = factor * checkValue( mapFromGlobal(mev->globalPos()).y() ) / height(); + resizeEvent(0); + divider->repaint(true); + } + } else { + if (!mOpaqueResize) { + int position = checkValue( mapFromGlobal(QCursor::pos()).x() ); + divider->move( position, 0 ); + } else { + xpos = factor * checkValue( mapFromGlobal( mev->globalPos()).x() ) / width(); + resizeEvent(0); + divider->repaint(true); + } + } + handled= true; + break; + case QEvent::MouseButtonRelease: + child0->setUpdatesEnabled(true); + child1->setUpdatesEnabled(true); + mev= (QMouseEvent*)e; + if (orientation == Horizontal){ + xpos = factor* checkValue( mapFromGlobal(mev->globalPos()).y() ) / height(); + resizeEvent(0); + divider->repaint(true); + } else { + xpos = factor* checkValue( mapFromGlobal(mev->globalPos()).x() ) / width(); + resizeEvent(0); + divider->repaint(true); + } + handled= true; + break; + default: + break; + } + return (handled) ? true : QWidget::eventFilter( o, e ); +} + +bool PMDockSplitter::event( QEvent* e ) +{ + if ( e->type() == QEvent::LayoutHint ){ + // change children min/max size + setupMinMaxSize(); + setSeparatorPos(xpos); + } + return QWidget::event(e); +} + +QWidget* PMDockSplitter::getAnother( QWidget* w ) const +{ + return ( w == child0 ) ? child1 : child0; +} + +void PMDockSplitter::updateName() +{ + if ( !initialised ) return; + + QString new_name = QString( child0->name() ) + "," + child1->name(); + parentWidget()->setName( new_name.latin1() ); + parentWidget()->setCaption( child0->caption() + "," + child1->caption() ); + parentWidget()->repaint( false ); + + ((PMDockWidget*)parentWidget())->firstName = child0->name(); + ((PMDockWidget*)parentWidget())->lastName = child1->name(); + ((PMDockWidget*)parentWidget())->splitterOrientation = orientation; + + QWidget* p = parentWidget()->parentWidget(); + if ( p != 0L && p->inherits("PMDockSplitter" ) ) + ((PMDockSplitter*)p)->updateName(); +} + +void PMDockSplitter::setOpaqueResize(bool b) +{ + mOpaqueResize = b; +} + +bool PMDockSplitter::opaqueResize() const +{ + return mOpaqueResize; +} + +void PMDockSplitter::setKeepSize(bool b) +{ + mKeepSize = b; +} + +bool PMDockSplitter::keepSize() const +{ + return mKeepSize; +} + +void PMDockSplitter::setHighResolution(bool b) +{ + if (mHighResolution) { + if (!b) xpos = xpos/100; + } else { + if (b) xpos = xpos*100; + } + mHighResolution = b; +} + +bool PMDockSplitter::highResolution() const +{ + return mHighResolution; +} + + +/*************************************************************************/ +PMDockButton_Private::PMDockButton_Private( QWidget *parent, const char * name ) +:QPushButton( parent, name ) +{ + moveMouse = false; + setFocusPolicy( NoFocus ); +} + +PMDockButton_Private::~PMDockButton_Private() +{ +} + +void PMDockButton_Private::drawButton( QPainter* p ) +{ + p->fillRect( 0,0, width(), height(), QBrush(colorGroup().brush(QColorGroup::Background)) ); + p->drawPixmap( (width() - pixmap()->width()) / 2, (height() - pixmap()->height()) / 2, *pixmap() ); + if ( moveMouse && !isDown() ){ + p->setPen( white ); + p->moveTo( 0, height() - 1 ); + p->lineTo( 0, 0 ); + p->lineTo( width() - 1, 0 ); + + p->setPen( colorGroup().dark() ); + p->lineTo( width() - 1, height() - 1 ); + p->lineTo( 0, height() - 1 ); + } + if ( isOn() || isDown() ){ + p->setPen( colorGroup().dark() ); + p->moveTo( 0, height() - 1 ); + p->lineTo( 0, 0 ); + p->lineTo( width() - 1, 0 ); + + p->setPen( white ); + p->lineTo( width() - 1, height() - 1 ); + p->lineTo( 0, height() - 1 ); + } +} + +void PMDockButton_Private::enterEvent( QEvent * ) +{ + moveMouse = true; + repaint(); +} + +void PMDockButton_Private::leaveEvent( QEvent * ) +{ + moveMouse = false; + repaint(); +} + +/*************************************************************************/ +PMDockWidgetPrivate::PMDockWidgetPrivate() + : QObject() + ,index(-1) + ,splitPosInPercent(50) + ,pendingFocusInEvent(false) + ,blockHasUndockedSignal(false) +{ +#ifndef NO_KDE2 + windowType = NET::Normal; +#endif + + _parent = 0L; + transient = false; +} + +PMDockWidgetPrivate::~PMDockWidgetPrivate() +{ +} + +void PMDockWidgetPrivate::slotFocusEmbeddedWidget(QWidget* w) +{ + if (w) { + QWidget* embeddedWdg = ((PMDockWidget*)w)->getWidget(); + if (embeddedWdg && ((embeddedWdg->focusPolicy() == QWidget::ClickFocus) || (embeddedWdg->focusPolicy() == QWidget::StrongFocus))) { + embeddedWdg->setFocus(); + } + } +} + +#ifndef NO_INCLUDE_MOCFILES // for Qt-only projects, because tmake doesn't take this name +#include "pmdockwidget_private.moc" +#endif diff --git a/kpovmodeler/pmdockwidget_private.h b/kpovmodeler/pmdockwidget_private.h new file mode 100644 index 00000000..353eb390 --- /dev/null +++ b/kpovmodeler/pmdockwidget_private.h @@ -0,0 +1,142 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 Max Judin + Modified 2002 Andreas Zehender + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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. +*/ + +/* + IMPORTANT Note: This file compiles also in Qt-only mode by using the NO_KDE2 precompiler definition +*/ + +#ifndef KDOCKWIDGET_PRIVATE_H +#define KDOCKWIDGET_PRIVATE_H + +#include +#include + +#ifndef NO_KDE2 +#include +#endif + +class QFrame; + +/** + * Like QSplitter but specially designed for dockwidgets stuff. + * @internal + * + * @author Max Judin. +*/ +class PMDockSplitter : public QWidget +{ + Q_OBJECT +public: + PMDockSplitter(QWidget *parent= 0, const char *name= 0, Orientation orient= Vertical, int pos= 50, bool highResolution=false); + virtual ~PMDockSplitter(){}; + + void activate(QWidget *c0, QWidget *c1 = 0L); + void deactivate(); + + int separatorPos() const; + void setSeparatorPos(int pos, bool do_resize = true); + + virtual bool eventFilter(QObject *, QEvent *); + virtual bool event( QEvent * ); + + QWidget* getFirst() const { return child0; } + QWidget* getLast() const { return child1; } + QWidget* getAnother( QWidget* ) const; + void updateName(); + + void setOpaqueResize(bool b=true); + bool opaqueResize() const; + + void setKeepSize(bool b=true); + bool keepSize() const; + + void setHighResolution(bool b=true); + bool highResolution() const; + + // MODIFICATION (Zehender) + Orientation splitterOrientation( ) const { return orientation; } + +protected: + int checkValue( int ) const; + virtual void resizeEvent(QResizeEvent *); + +private: + void setupMinMaxSize(); + + QWidget *child0, *child1; + Orientation orientation; + bool initialised; + QFrame* divider; + int xpos; + bool mOpaqueResize, mKeepSize, mHighResolution; +}; + +/** + * A mini-button usually placed in the dockpanel. + * @internal + * + * @author Max Judin. +*/ +class PMDockButton_Private : public QPushButton +{ + Q_OBJECT +public: + PMDockButton_Private( QWidget *parent=0, const char *name=0 ); + ~PMDockButton_Private(); + +protected: + virtual void drawButton( QPainter * ); + virtual void enterEvent( QEvent * ); + virtual void leaveEvent( QEvent * ); + +private: + bool moveMouse; +}; + +/** + * additional PMDockWidget stuff (private) +*/ +class PMDockWidgetPrivate : public QObject +{ + Q_OBJECT +public: + PMDockWidgetPrivate(); + ~PMDockWidgetPrivate(); + +public slots: + /** + * Especially used for Tab page docking. Switching the pages requires additional setFocus() for the embedded widget. + */ + void slotFocusEmbeddedWidget(QWidget* w = 0L); + +public: + int index; + int splitPosInPercent; + bool pendingFocusInEvent; + bool blockHasUndockedSignal; + +#ifndef NO_KDE2 + NET::WindowType windowType; +#endif + + QWidget *_parent; + bool transient; +}; + +#endif diff --git a/kpovmodeler/pmdocumentationmap.cpp b/kpovmodeler/pmdocumentationmap.cpp new file mode 100644 index 00000000..9c898c4c --- /dev/null +++ b/kpovmodeler/pmdocumentationmap.cpp @@ -0,0 +1,193 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmdocumentationmap.h" + +#include +#include + +#include +#include + +#include "pmdebug.h" + +PMDocumentationMap* PMDocumentationMap::s_pInstance = 0; +KStaticDeleter PMDocumentationMap::s_staticDeleter; + +QString PMDocumentationVersion::documentation( const QString& className ) const +{ + if( m_map.contains( className ) ) + return m_map[className]; + return m_index; +} + +void PMDocumentationVersion::loadData( QDomElement& e ) +{ + QString className; + QString target; + + m_version = e.attribute( "number", "3.1" ); + m_index = e.attribute( "index", "index.htm" ); + + QDomNode m = e.firstChild( ); + while( !m.isNull( ) ) + { + if( m.isElement( ) ) + { + QDomElement me = m.toElement( ); + className = me.attribute( "className", "" ); + target = me.attribute( "target", "" ); + if( !className.isEmpty( ) && !target.isEmpty( ) ) + m_map.insert( className, target ); + } + m = m.nextSibling( ); + } +} + +PMDocumentationMap::PMDocumentationMap( ) +{ + m_pCurrentVersion = 0; + m_mapLoaded = false; +} + +PMDocumentationMap::~PMDocumentationMap( ) +{ + m_maps.setAutoDelete( true ); + m_maps.clear( ); +} + +void PMDocumentationMap::saveConfig( KConfig* cfg ) +{ + cfg->setGroup( "Povray" ); + cfg->writePathEntry( "DocumentationPath", m_documentationPath ); + cfg->writeEntry( "DocumentationVersion", m_currentVersion ); +} + +void PMDocumentationMap::restoreConfig( KConfig* cfg ) +{ + cfg->setGroup( "Povray" ); + m_documentationPath = cfg->readPathEntry( "DocumentationPath" ); + m_currentVersion = cfg->readEntry( "DocumentationVersion", "3.1" ); +} + +void PMDocumentationMap::setDocumentationVersion( const QString& v ) +{ + m_currentVersion = v; + if( m_mapLoaded ) + findVersion( ); +} + +QValueList PMDocumentationMap::availableVersions( ) +{ + if( !m_mapLoaded ) + loadMap( ); + + QValueList result; + QPtrListIterator it( m_maps ); + + for( ; it.current( ); ++it ) + result.push_back( it.current( )->version( ) ); + + return result; +} + +QString PMDocumentationMap::documentation( const QString& objectName ) +{ + if( !m_mapLoaded ) + loadMap( ); + + QString url; + + if( !m_documentationPath.isEmpty( ) ) + if( !m_documentationPath.endsWith( QString( "/" ) ) ) + m_documentationPath += "/"; + + if( !m_documentationPath.isEmpty( ) && m_pCurrentVersion ) + url = m_documentationPath + + m_pCurrentVersion->documentation( objectName ); + + return url; +} + +void PMDocumentationMap::loadMap( ) +{ + if( !m_mapLoaded ) + { + m_mapLoaded = true; + + QString fileName = locate( "data", "kpovmodeler/povraydocmap.xml" ); + if( fileName.isEmpty( ) ) + { + kdError( PMArea ) << "Povray documentation map not found" << endl; + return; + } + + QFile file( fileName ); + if( !file.open( IO_ReadOnly ) ) + { + kdError( PMArea ) << "Could not open the povray documentation map file" + << endl; + return; + } + + QDomDocument doc( "DOCMAP" ); + doc.setContent( &file ); + + QDomElement e = doc.documentElement( ); + QDomNode c = e.firstChild( ); + + QString str; + + while( !c.isNull( ) ) + { + if( c.isElement( ) ) + { + QDomElement ce = c.toElement( ); + PMDocumentationVersion* v = new PMDocumentationVersion( ); + m_maps.append( v ); + v->loadData( ce ); + } + c = c.nextSibling( ); + } + + findVersion( ); + } +} + +void PMDocumentationMap::findVersion( ) +{ + QPtrListIterator< PMDocumentationVersion > it( m_maps ); + bool found = false; + + m_pCurrentVersion = 0; + + for( ; it.current( ) && !found; ++it ) + { + if( it.current( )->version( ) == m_currentVersion ) + { + found = true; + m_pCurrentVersion = it.current( ); + } + } +} + +PMDocumentationMap* PMDocumentationMap::theMap( ) +{ + if( !s_pInstance ) + s_staticDeleter.setObject( s_pInstance, new PMDocumentationMap( ) ); + return s_pInstance; +} diff --git a/kpovmodeler/pmdocumentationmap.h b/kpovmodeler/pmdocumentationmap.h new file mode 100644 index 00000000..3027095c --- /dev/null +++ b/kpovmodeler/pmdocumentationmap.h @@ -0,0 +1,138 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMDOCUMENTATIONMAP_H +#define PMDOCUMENTATIONMAP_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +class KConfig; +class QDomElement; + +/** + * Class used internally by @ref PMDocumentationMap + */ +class PMDocumentationVersion +{ +public: + /** + * Constructor + */ + PMDocumentationVersion( ) { } + /** + * Destructor + */ + ~PMDocumentationVersion( ) { } + + QString version( ) const { return m_version; } + void setVersion( const QString& str ) { m_version = str; } + QString index( ) const { return m_index; } + void setIndex( const QString& str ) { m_index = str; } + + QString documentation( const QString& className ) const; + + void loadData( QDomElement& e ); + +private: + QString m_version; + QString m_index; + QMap< QString, QString > m_map; +}; + +/** + * Class that maps the class name to the corresponding povray + * user documentation file + */ +class PMDocumentationMap +{ +public: + /** + * Destructor + */ + ~PMDocumentationMap( ); + /** + * Returns the map instance (singleton) + */ + static PMDocumentationMap* theMap( ); + + /** + * Sets the path to the povray user documentation + */ + void setPovrayDocumentationPath( const QString& s ) + { + m_documentationPath = s; + } + /** + * Returns the path to the povray user documentation + */ + QString povrayDocumentationPath( ) + { + return m_documentationPath; + } + + /** + * Sets the povray documentation version + */ + void setDocumentationVersion( const QString& str ); + /** + * Returns the povray documentation version + */ + QString documentationVersion( ) const { return m_currentVersion; } + + /** + * Returns the list of available documentation versions + */ + QValueList availableVersions( ); + + /** + * Returns the povray documentation file for the + * given object type + */ + QString documentation( const QString& objectName ); + + void saveConfig( KConfig* cfg ); + void restoreConfig( KConfig* cfg ); + +private: + + /** + * Constructor + */ + PMDocumentationMap( ); + void loadMap( ); + void findVersion( ); + + QString m_documentationPath; + bool m_mapLoaded; + QPtrList< PMDocumentationVersion > m_maps; + PMDocumentationVersion* m_pCurrentVersion; + QString m_currentVersion; + + static PMDocumentationMap* s_pInstance; + static KStaticDeleter s_staticDeleter; +}; + +#endif diff --git a/kpovmodeler/pmdocumentformat.h b/kpovmodeler/pmdocumentformat.h new file mode 100644 index 00000000..1551f9e4 --- /dev/null +++ b/kpovmodeler/pmdocumentformat.h @@ -0,0 +1,26 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMDOCUMENTFORMAT_H +#define PMDOCUMENTFORMAT_H + +// the current document format number +// (1.0) +const int c_majorDocumentFormat = 1; +const int c_minorDocumentFormat = 0; + +#endif diff --git a/kpovmodeler/pmdragwidget.cpp b/kpovmodeler/pmdragwidget.cpp new file mode 100644 index 00000000..7b63baf5 --- /dev/null +++ b/kpovmodeler/pmdragwidget.cpp @@ -0,0 +1,49 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2004 by Luis Carvalho + email : lpassos@oninetspeed.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#include "pmdragwidget.h" + +PMDragWidget::PMDragWidget( QWidget* parent, const char* name, WFlags f ) + : QWidget( parent, name, f ) +{ + dragging = false; +} + +void PMDragWidget::mousePressEvent( QMouseEvent* ) +{ + dragging = true; +} + +void PMDragWidget::mouseReleaseEvent( QMouseEvent* ) +{ + dragging = false; +} + +void PMDragWidget::mouseMoveEvent( QMouseEvent* ) +{ + if( dragging ) + { + startDrag( ); + dragging = false; + } +} + +void PMDragWidget::startDrag( ) +{ +} + +#include "pmdragwidget.moc" diff --git a/kpovmodeler/pmdragwidget.h b/kpovmodeler/pmdragwidget.h new file mode 100644 index 00000000..30b15045 --- /dev/null +++ b/kpovmodeler/pmdragwidget.h @@ -0,0 +1,51 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2004 by Luis Carvalho + email : lpassos@oninetspeed.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#ifndef PMDRAGWIDGET_H +#define PMDRAGWIDGET_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +/** + * This class implements a widget that exposes a signal for drag + * and drop. + * + * It will emit startDrag when it's time to start a drag. + */ +class PMDragWidget : public QWidget +{ + Q_OBJECT +public: + PMDragWidget( QWidget* parent = 0, const char* name = 0, WFlags f = 0 ); + + virtual void startDrag( ); + +protected: + void mousePressEvent( QMouseEvent* ); + void mouseReleaseEvent( QMouseEvent* ); + void mouseMoveEvent( QMouseEvent* ); + +private: + bool dragging; +}; + +#endif diff --git a/kpovmodeler/pmenumproperty.cpp b/kpovmodeler/pmenumproperty.cpp new file mode 100644 index 00000000..72a03788 --- /dev/null +++ b/kpovmodeler/pmenumproperty.cpp @@ -0,0 +1,57 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmenumproperty.h" + +PMEnumProperty::PMEnumProperty( const char* name, bool readOnly, + bool writeOnly ) + : PMPropertyBase( name, PMVariant::String, readOnly, writeOnly ) +{ +} + +void PMEnumProperty::addEnumValue( const QString& str, int value ) +{ + m_valueMap[value] = str; + m_stringMap[str] = value; +} + +QStringList PMEnumProperty::enumValues( ) const +{ + QStringList l; + PMEnumStringValueMap::const_iterator it; + for( it = m_stringMap.begin( ); it != m_stringMap.end( ); ++it ) + l.append( it.key( ) ); + return l; +} + +bool PMEnumProperty::setProtected( PMObject* obj, const PMVariant& v ) +{ + PMEnumStringValueMap::iterator it = m_stringMap.find( v.stringData( ) ); + if( it == m_stringMap.end( ) ) + return false; + setEnum( obj, it.data( ) ); + return true; +} + +PMVariant PMEnumProperty::getProtected( const PMObject* obj ) +{ + int v = getEnum( obj ); + PMEnumValueStringMap::const_iterator it = m_valueMap.find( v ); + if( it == m_valueMap.end( ) ) + return PMVariant( QString::null ); + return it.data( ); +} diff --git a/kpovmodeler/pmenumproperty.h b/kpovmodeler/pmenumproperty.h new file mode 100644 index 00000000..a8d6085e --- /dev/null +++ b/kpovmodeler/pmenumproperty.h @@ -0,0 +1,110 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMENUMPROPERTY_H +#define PMENUMPROPERTY_H + +#include "pmmetaobject.h" +#include + +typedef QMap PMEnumValueStringMap; +typedef QMap PMEnumStringValueMap; + +/** + * Base class for enum properties + */ +class PMEnumProperty : public PMPropertyBase +{ +public: + /** + * Default constructor + */ + PMEnumProperty( const char* name, bool readOnly = false, + bool writeOnly = false ); + + /** + * Adds the string to the list of enum values and sets the enum flag + * to true + */ + void addEnumValue( const QString& str, int value ); + + /** + * Returns true if the property is an enum + */ + virtual bool isEnum( ) const { return true; } + /** + * Returns the list of enum values + */ + virtual QStringList enumValues( ) const; + +protected: + /** + * Do not reimplement this method in a sub class + */ + virtual bool setProtected( PMObject* obj, const PMVariant& v ); + /** + * Do not reimplement this method in a sub class + */ + virtual PMVariant getProtected( const PMObject* obj ); + + /** + * Reimplement this method in sub classes. You can safetly + * cast the integer to the enum type + */ + virtual void setEnum( PMObject* obj, int value ) = 0; + /** + * Reimplement this method in sub classes. + */ + virtual int getEnum( const PMObject* obj ) = 0; + +private: + PMEnumValueStringMap m_valueMap; + PMEnumStringValueMap m_stringMap; +}; + +#define PMDefineEnumPropertyClass( ObjectClass, EnumType, PropertyClass ) \ +class PropertyClass : public PMEnumProperty \ +{ \ +public: \ + typedef void ( ObjectClass::*SetPtr ) ( EnumType ); \ + typedef EnumType ( ObjectClass::*GetPtr ) ( void ) const; \ + \ + PropertyClass( const char* name, SetPtr setFktn, GetPtr getFktn ) \ + : PMEnumProperty( name, setFktn == 0, getFktn == 0 ) \ + { \ + m_setFunktion = setFktn; \ + m_getFunktion = getFktn; \ + } \ +protected: \ + virtual void setEnum( PMObject* obj, int value ) \ + { \ + ObjectClass* o = ( ObjectClass* ) obj; \ + ( o->*m_setFunktion )( ( EnumType ) value ); \ + } \ + virtual int getEnum( const PMObject* obj ) \ + { \ + const ObjectClass* o = ( const ObjectClass* ) obj; \ + return ( o->*m_getFunktion )( ); \ + } \ +private: \ + SetPtr m_setFunktion; \ + GetPtr m_getFunktion; \ +} +// no semicolon, put a semicolon after the macro! + +#endif diff --git a/kpovmodeler/pmerrordialog.cpp b/kpovmodeler/pmerrordialog.cpp new file mode 100644 index 00000000..721cd302 --- /dev/null +++ b/kpovmodeler/pmerrordialog.cpp @@ -0,0 +1,136 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmerrordialog.h" +#include "pmerrorflags.h" + +#include +#include +#include + +#include + + +QSize PMErrorDialog::s_size = QSize( 150, 200 ); + +PMErrorDialog::PMErrorDialog( const PMMessageList& messages, int errorFlags, + QWidget* parent, const char* name ) + : KDialogBase( parent, name, true, i18n( "Messages" ), + Ok | Cancel, Cancel ) +{ + QVBox* page = makeVBoxMainWidget( ); + QLabel* text = new QLabel( QString( "" ), ( QWidget* )page ); + + + m_pTextView = new QTextEdit( ( QWidget* )page ); + m_pTextView->setReadOnly( true ); + + m_messageDict.setAutoDelete( true ); + m_messages.setAutoDelete( true ); + + PMMessageList::ConstIterator it; + for( it = messages.begin( ); it != messages.end( ); ++it ) + m_messages.append( new PMMessage( *it ) ); + + QPtrListIterator pit( m_messages ); + for( ; pit.current( ); ++pit ) + { + PMObject* obj = pit.current( )->linkedObject( ); + for( ; obj; obj = obj->parent( ) ) + { + QPtrList* pList = m_messageDict.find( obj ); + if( !pList ) + { + pList = new QPtrList; + m_messageDict.insert( obj, pList ); + } + pList->append( pit.current( ) ); + if( !obj->parent( ) ) + { + if( obj->type( ) != "scene" ) + { + kdError( PMArea ) << "A message contains an object that is not inserted in the scene" << endl; + pit.current( )->setLinkedObject( 0 ); + } + } + } + } + + displayMessages( ); + + if( errorFlags & PMEWarning ) + { + if( ( errorFlags & PMEError ) || ( errorFlags & PMEFatal ) ) + text->setText( i18n( "There were warnings and errors:" ) ); + else + text->setText( i18n( "There were warnings:" ) ); + } + else + text->setText( i18n( "There were errors:" ) ); + + setButtonOKText( KStdGuiItem::ok().text(), + i18n( "Proceed" ), + i18n( "When clicking Proceed, the program\n" + "will try to proceed with the current action." ) ); + setButtonCancelText( KStdGuiItem::cancel().text(), + i18n( "&Cancel" ), + i18n( "When clicking Cancel, the program\n" + "will cancel the current action." ) ); + + if( errorFlags & PMEFatal ) + showButtonOK( false ); + else + new QLabel( i18n( "Still try to proceed?" ), ( QWidget* )page ); + + resize( s_size ); +} + +void PMErrorDialog::displayMessages( ) +{ + QPtrListIterator pit( m_messages ); + QString text; + + text = "\n"; + + for( ; pit.current( ); ++pit ) + text += "

" + pit.current( )->text( ) + "

\n"; + + text += "
"; + + m_pTextView->setText( text ); +} + +void PMErrorDialog::saveConfig( KConfig* cfg ) +{ + cfg->setGroup( "Appearance" ); + cfg->writeEntry( "ErrorDialogSize", s_size ); +} + +void PMErrorDialog::restoreConfig( KConfig* cfg ) +{ + cfg->setGroup( "Appearance" ); + + QSize defaultSize( 150, 200 ); + s_size = cfg->readSizeEntry( "ErrorDialogSize", &defaultSize ); +} + +void PMErrorDialog::resizeEvent( QResizeEvent* ev ) +{ + s_size = ev->size( ); +} +#include "pmerrordialog.moc" diff --git a/kpovmodeler/pmerrordialog.h b/kpovmodeler/pmerrordialog.h new file mode 100644 index 00000000..972d55ab --- /dev/null +++ b/kpovmodeler/pmerrordialog.h @@ -0,0 +1,73 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMERRORDIALOG_H +#define PMERRORDIALOG_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +class KConfig; +class QTextEdit; +class PMObject; + +#include "pmmessage.h" + +/** + * Dialog that is shown if some errors or warnings occurred during + * parsing or execution of commands. + */ +class PMErrorDialog : public KDialogBase +{ + Q_OBJECT +public: + /** + * Creates a modal PMErrorDialog with parent and name. + * + * messages is the message list. If the list contains a message of type + * FatalError, the 'Proceed" button will not be shown. + * + * PMErrorDialog::exec( ) returns QDialog::Accepted if the command + * should be continued. + */ + PMErrorDialog( const PMMessageList& messages, int errorFlags, + QWidget* parent = 0, const char* name = 0 ); + + static void saveConfig( KConfig* cfg ); + static void restoreConfig( KConfig* cfg ); + +protected: + virtual void resizeEvent( QResizeEvent* ev ); + +private: + void displayMessages( ); + + static QSize s_size; + QTextEdit* m_pTextView; + QPtrDict< QPtrList > m_messageDict; + QPtrList m_messages; +}; + +#endif diff --git a/kpovmodeler/pmerrorflags.h b/kpovmodeler/pmerrorflags.h new file mode 100644 index 00000000..ce604c9b --- /dev/null +++ b/kpovmodeler/pmerrorflags.h @@ -0,0 +1,31 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMERRORFLAGS_H +#define PMERRORFLAGS_H + +/** + * Error flags + * + * These flags are returnd by @ref PMParser::errorFlags( ) + * and PMCommand::errorFlags( ) + */ + +enum PMErrorFlags { PMENone = 0, PMEWarning = 1, PMEError = 2, PMEFatal = 4 }; + +#endif diff --git a/kpovmodeler/pmface.cpp b/kpovmodeler/pmface.cpp new file mode 100644 index 00000000..654a31b0 --- /dev/null +++ b/kpovmodeler/pmface.cpp @@ -0,0 +1,119 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2004 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ +#include +#include "pmface.h" + +GLuint PMFace::s_dummy = 0; + +PMFace::PMFace( const PMFace& face ) +{ + m_points = new( std::nothrow ) GLuint[ face.m_size ]; + for( unsigned i = 0; i < face.m_size; ++i ) + m_points[ i ] = face.m_points[ i ]; + m_size = face.m_size; + m_normal = face.m_normal; +} + +PMFace::PMFace( const GLuint pt1, const GLuint pt2, const GLuint pt3, const PMVector& normal ) +{ + m_points = new( std::nothrow ) GLuint[ 3 ]; + m_points[ 0 ] = pt1; + m_points[ 1 ] = pt2; + m_points[ 2 ] = pt3; + m_size = 3; + m_normal = normal; +} + +PMFace::PMFace( const GLuint pt1, const GLuint pt2, const GLuint pt3, const GLuint pt4, const PMVector& normal ) +{ + m_points = new( std::nothrow ) GLuint[ 4 ]; + m_points[ 0 ] = pt1; + m_points[ 1 ] = pt2; + m_points[ 2 ] = pt3; + m_points[ 3 ] = pt4; + m_size = 4; + m_normal = normal; +} + +PMFace& PMFace::operator=( const PMFace& face ) +{ + delete m_points; + m_points = new( std::nothrow ) GLuint[ face.m_size ]; + for( unsigned i = 0; i < face.m_size; ++i ) + m_points[ i ] = face.m_points[ i ]; + m_size = face.m_size; + m_normal = face.m_normal; + return *this; +} + +bool PMFace::operator==( const PMFace& face ) const +{ + if( m_size == face.m_size && m_normal == face.m_normal ) + { + for( unsigned i = 0; i < m_size; ++i ) + { + if( m_points[i] != face.m_points[i] ) + return false; + } + return true; + } + else + return false; +} + +bool PMFace::operator!=( const PMFace& face ) const +{ + return !( *this == face ); +} + +bool PMFace::resize( const unsigned int size ) +{ + if( size != m_size ) + { + GLuint* temp = new( std::nothrow ) GLuint[ size ]; + if( temp ) + { + for( unsigned i = 0; i < m_size && i < size; ++i ) + temp[i] = m_points[i]; + + for( unsigned i = m_size; i < size; ++i ) + temp[i] = 0; + + delete [] m_points; + m_points = temp; + } + else + return false; + } + return true; +} + +GLuint& PMFace::operator[] ( int index ) +{ + if( ( index >= 0 ) && ( index < ( signed ) m_size ) ) + return m_points[index]; + kdError( PMArea ) << "Bad index in PMFace operator []\n"; + return s_dummy; +} + +const GLuint& PMFace::operator[] ( int index ) const +{ + if( ( index >= 0 ) && ( index < ( signed ) m_size ) ) + return m_points[index]; + kdError( PMArea ) << "Bad index in PMFace operator []\n"; + return s_dummy; +} diff --git a/kpovmodeler/pmface.h b/kpovmodeler/pmface.h new file mode 100644 index 00000000..46da64bb --- /dev/null +++ b/kpovmodeler/pmface.h @@ -0,0 +1,130 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2004 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ +#ifndef PMFACE_H +#define PMFACE_H + +#include +#include +#include +#include "pmdebug.h" +#include "pmvector.h" + +/** + * face to display with index of points. Points must be in clockwise order. + * + * Face of a @ref PMViewStructure. Only the indices in a @ref PMPointArray + * are stored. + * + * Optimized for OpenGL + */ +class PMFace +{ +public: + /** + * Default constructor + */ + PMFace( ) + { + m_points = 0; + m_size = 0; + } + /** + * Copy Constructor + */ + PMFace( const PMFace& face ); + /** + * Destructor + */ + ~PMFace( ) { delete m_points; } + /** + * Creates a face with three points. + */ + PMFace( const GLuint pt1, const GLuint pt2, const GLuint pt3, const PMVector& normal = PMVector() ); + /** + * Creates a face with four points. + */ + PMFace( const GLuint pt1, const GLuint pt2, const GLuint pt3, const GLuint pt4, const PMVector& normal = PMVector() ); + + /** + * Operator assignment + */ + PMFace& operator=( const PMFace& face ); + /** + * Operator equals + */ + bool operator==( const PMFace& face ) const; + /** + * Operator unequals + */ + bool operator!=( const PMFace& face ) const; + + /** + * Resizes the number of points in the face. + * @return True if successful + */ + bool resize( const unsigned int size ); + /** + * @return The number of points in the face. + */ + unsigned int size( ) const { return m_size; } + + /** + * Returns a reference to a point in the face + */ + GLuint& operator[] ( int index ); + /** + * Returns a const reference to a point in the face + */ + const GLuint& operator[] ( int index ) const; + + /** + * Calculates the normal for the face + */ + void setNormal( const PMVector& normal ) { m_normal = normal; } + /** + * Returns the normal for the face + */ + PMVector normal( ) const { return m_normal; } + +private: + /** + * The face points (indices!) + */ + GLuint* m_points; + /** + * The number of points in the face + */ + unsigned int m_size; + /** + * The normal of the face, calculated automatically + */ + PMVector m_normal; + static GLuint s_dummy; +}; + +typedef QPtrListIterator PMFaceListIterator; + +/** + * A list of @ref PMFace objects. + * + * This class stores all faces of a @ref PMViewStructure. Only the indices + * in a @ref PMPointArray are stored. + */ +typedef QValueVector PMFaceArray; + +#endif diff --git a/kpovmodeler/pmfactory.cpp b/kpovmodeler/pmfactory.cpp new file mode 100644 index 00000000..4a3631ae --- /dev/null +++ b/kpovmodeler/pmfactory.cpp @@ -0,0 +1,102 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include +#include +#include + +#include "pmfactory.h" +#include "pmpart.h" +#include "pmdebug.h" +#include "version.h" + +extern "C" +{ + void* init_libkpovmodelerpart( ) + { + return new PMFactory( ); + } +} + +static const char description[] = I18N_NOOP( "Modeler for POV-Ray Scenes" ); + +KInstance* PMFactory::s_instance = 0L; +KAboutData* PMFactory::s_aboutData = 0L; + +PMFactory::PMFactory( ) +{ + kdDebug( ) << "PMFactory::PMFactory( )\n"; +} + +PMFactory::~PMFactory( ) +{ + if( s_instance ) + delete s_instance; + if( s_aboutData ) + delete s_aboutData; + + s_instance = 0L; + s_aboutData = 0L; +} + +KParts::Part* PMFactory::createPartObject( QWidget* parentWidget, + const char* widgetName, + QObject* parent, const char* name, + const char* classname, + const QStringList& /*args*/ ) +{ + kdDebug( ) << "PMFactory: Created new part\n"; + + bool readwrite = !( ( strcmp( classname, "Browser/View" ) == 0 ) + || ( strcmp( classname, "KParts::ReadOnlyPart" ) == 0 ) ); + + KParts::ReadWritePart *part = new PMPart( parentWidget, widgetName, + parent, name, readwrite ); + + return part; +} + +KInstance* PMFactory::instance( ) +{ + if( !s_instance ) + s_instance = new KInstance( aboutData( ) ); + return s_instance; +} + +const KAboutData* PMFactory::aboutData( ) +{ + if( !s_aboutData ) + { + s_aboutData = + new KAboutData( "kpovmodeler", I18N_NOOP( "KPovModeler" ), + KPOVMODELER_VERSION, description, + KAboutData::License_GPL, "(c) 2001-2006, Andreas Zehender" ); + s_aboutData->addAuthor( "Andreas Zehender", 0, + "zehender@kde.org", "http://www.azweb.de" ); + s_aboutData->addAuthor( "Luis Passos Carvalho", I18N_NOOP( "Textures" ), + "lpassos@mail.telepac.pt" ); + s_aboutData->addAuthor( "Leon Pennington", I18N_NOOP( "POV-Ray 3.5 objects" ), + "leon@leonscape.co.uk" ); + s_aboutData->addAuthor( "Philippe Van Hecke", I18N_NOOP( "Some graphical objects" ), + "lephiloux@tiscalinet.be" ); + s_aboutData->addAuthor( "Leonardo Skorianez", I18N_NOOP( "Some graphical objects" ), + "skorianez@bol.com.br" ); + } + return s_aboutData; +} +#include "pmfactory.moc" diff --git a/kpovmodeler/pmfactory.h b/kpovmodeler/pmfactory.h new file mode 100644 index 00000000..b44c6bd3 --- /dev/null +++ b/kpovmodeler/pmfactory.h @@ -0,0 +1,48 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMFACTORY_H +#define PMFACTORY_H + +#include + +class KAboutData; +class KInstance; + +class PMFactory : public KParts::Factory +{ + Q_OBJECT +public: + PMFactory( ); + virtual ~PMFactory( ); + + virtual KParts::Part* createPartObject( QWidget* parentWidget, + const char* widgetName, + QObject* parent, const char* name, + const char* classname, + const QStringList& args ); + + static KInstance* instance( ); + static const KAboutData* aboutData( ); +private: + static KInstance* s_instance; + static KAboutData* s_aboutData; +}; + +#endif diff --git a/kpovmodeler/pmfiledialog.cpp b/kpovmodeler/pmfiledialog.cpp new file mode 100644 index 00000000..68030f8c --- /dev/null +++ b/kpovmodeler/pmfiledialog.cpp @@ -0,0 +1,104 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmfiledialog.h" +#include "pmpart.h" + +#include + + +PMFileDialog::PMFileDialog( const QString& startDir, const QString& filter, QWidget* parent, const char* name, bool modal ) + : KFileDialog( startDir, filter, parent, name, modal ) +{ + +} + +QString PMFileDialog::getImportFileName( QWidget* parent, PMPart* part, + PMIOFormat*& format ) +{ + PMIOManager* manager = part->ioManager( ); + QString filter; + QPtrListIterator it( manager->formats( ) ); + QPtrList formats; + + for( ; it.current( ); ++it ) + { + if( it.current( )->services( ) & PMIOFormat::Import ) + { + QStringList patterns = it.current( )->importPatterns( ); + QStringList::Iterator pit; + for( pit = patterns.begin( ); pit != patterns.end( ); ++pit ) + { + if( !filter.isEmpty( ) ) + filter += "\n"; + filter += *pit; + formats.append( it.current( ) ); + } + } + } + + PMFileDialog dlg( QString::null, filter, parent, "import file dialog", true ); + dlg.setOperationMode( Opening ); + dlg.setMode( KFile::File | KFile::LocalOnly ); + dlg.setCaption( i18n( "Import" ) ); + dlg.filterWidget->setEditable( false ); + dlg.exec( ); + + format = formats.at( dlg.filterWidget->currentItem( ) ); + + return dlg.selectedFile( ); +} + +QString PMFileDialog::getExportFileName( QWidget* parent, PMPart* part, + PMIOFormat*& format, QString& selectedFilter ) +{ + PMIOManager* manager = part->ioManager( ); + QString filter; + QPtrListIterator it( manager->formats( ) ); + QPtrList formats; + + for( ; it.current( ); ++it ) + { + if( it.current( )->services( ) & PMIOFormat::Export ) + { + QStringList patterns = it.current( )->exportPatterns( ); + QStringList::Iterator pit; + for( pit = patterns.begin( ); pit != patterns.end( ); ++pit ) + { + if( !filter.isEmpty( ) ) + filter += "\n"; + filter += *pit; + formats.append( it.current( ) ); + } + } + } + + PMFileDialog dlg( QString::null, filter, parent, "export file dialog", true ); + dlg.setOperationMode( Saving ); + dlg.setMode( KFile::File | KFile::LocalOnly ); + dlg.setCaption( i18n( "Export" ) ); + dlg.filterWidget->setEditable( false ); + dlg.exec( ); + + format = formats.at( dlg.filterWidget->currentItem( ) ); + selectedFilter = dlg.currentFilter( ); + + return dlg.selectedFile( ); +} + +#include "pmfiledialog.moc" diff --git a/kpovmodeler/pmfiledialog.h b/kpovmodeler/pmfiledialog.h new file mode 100644 index 00000000..e98a84ab --- /dev/null +++ b/kpovmodeler/pmfiledialog.h @@ -0,0 +1,60 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMFILEDIALOG_H +#define PMFILEDIALOG_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmiomanager.h" +#include + +class PMPart; + +/** + * File dialog used for the import and export action. + * + * The filters will be set automatically dependent on the + * supported file formats + * @see PMIOManager + */ +class PMFileDialog : public KFileDialog +{ + Q_OBJECT +public: + /** + * Default constructor, use the static methods + * @ref getImportFileName or @ref getExportFileName instead + */ + PMFileDialog( const QString& startDir, const QString& filter, QWidget* parent, const char* name, bool modal ); + /** + * Opens a modal file dialog and returns a selected file and the chosen + * file format. + */ + static QString getImportFileName( QWidget* parent, PMPart* part, PMIOFormat*& format ); + /** + * Opens a modal file dialog and returns a selected file and the chosen + * file format and filter. + */ + static QString getExportFileName( QWidget* parent, PMPart* part, + PMIOFormat*& format, QString& filter ); +}; + +#endif diff --git a/kpovmodeler/pmfinish.cpp b/kpovmodeler/pmfinish.cpp new file mode 100644 index 00000000..a98b9a2c --- /dev/null +++ b/kpovmodeler/pmfinish.cpp @@ -0,0 +1,765 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmfinish.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmfinishedit.h" + +#include + +const PMColor ambientColorDefault = PMColor( 0.0, 0.0, 0.0, 0.0, 0.0 ); +const double diffuseDefault = 0.6; +const double brillianceDefault = 1.0; +const double crandDefault = 0.0; +const double phongDefault = 0.0; +const double phongSizeDefault = 40.0; +const double metallicDefault = 1.0; +const double specularDefault = 0.0; +const double roughnessDefault = 0.05; +const double iridAmountDefault = 0.0; +const double iridThicknessDefault = 0.0; +const double iridTurbulenceDefault = 0.0; +const PMColor reflectionColorDefault = PMColor( 0.0, 0.0, 0.0, 0.0, 0.0 ); +const double reflectionFalloffDefault = 0.0; +const double reflectionExponentDefault = 1.0; +const double reflectionMetallicDefault = 1.0; + +PMDefinePropertyClass( PMFinish, PMFinishProperty ); + +PMMetaObject* PMFinish::s_pMetaObject = 0; +PMObject* createNewFinish( PMPart* part ) +{ + return new PMFinish( part ); +} + +PMFinish::PMFinish( PMPart* part ) + : Base( part ) +{ + m_ambientColor = ambientColorDefault; + m_diffuse = diffuseDefault; + m_brilliance = brillianceDefault; + m_crand = crandDefault; + m_conserveEnergy = false; + m_phong = phongDefault; + m_phongSize = phongSizeDefault; + m_metallic = metallicDefault; + m_specular = specularDefault; + m_roughness = roughnessDefault; + m_iridAmount = iridAmountDefault; + m_iridThickness = iridThicknessDefault; + m_iridTurbulence = iridTurbulenceDefault; + m_reflectionColor = reflectionColorDefault; + m_reflectionMinColor = reflectionColorDefault; + m_reflectionFresnel = false; + m_reflectionFalloff = reflectionFalloffDefault; + m_reflectionExponent = reflectionExponentDefault; + m_reflectionMetallic = reflectionMetallicDefault; + m_enableAmbient = false; + m_enableDiffuse = false; + m_enableBrilliance = false; + m_enableCrand = false; + m_enablePhong = false; + m_enablePhongSize = false; + m_enableMetallic = false; + m_enableSpecular = false; + m_enableRoughness = false; + m_enableReflection = false; + m_enableReflectionMin = false; + m_enableRefFalloff = false; + m_enableRefExponent = false; + m_enableRefMetallic = false; + m_irid = false; +} + +PMFinish::PMFinish( const PMFinish& f ) + : Base( f ) +{ + m_ambientColor = f.m_ambientColor; + m_diffuse = f.m_diffuse; + m_brilliance = f.m_brilliance; + m_crand = f.m_crand; + m_conserveEnergy = f.m_conserveEnergy; + m_phong = f.m_phong; + m_phongSize = f.m_phongSize; + m_metallic = f.m_metallic; + m_specular = f.m_specular; + m_roughness = f.m_roughness; + m_iridAmount = f.m_iridAmount; + m_iridThickness = f.m_iridThickness; + m_iridTurbulence = f.m_iridTurbulence; + m_reflectionColor = f.m_reflectionColor; + m_reflectionMinColor = f.m_reflectionMinColor; + m_reflectionFresnel = f.m_reflectionFresnel; + m_reflectionFalloff = f.m_reflectionFalloff; + m_reflectionExponent = f.m_reflectionExponent; + m_reflectionMetallic = f.m_reflectionMetallic; + m_enableAmbient = f.m_enableAmbient; + m_enableDiffuse = f.m_enableDiffuse; + m_enableBrilliance = f.m_enableBrilliance; + m_enableCrand = f.m_enableCrand; + m_enablePhong = f.m_enablePhong; + m_enablePhongSize = f.m_enablePhongSize; + m_enableMetallic = f.m_enableMetallic; + m_enableSpecular = f.m_enableSpecular; + m_enableRoughness = f.m_enableRoughness; + m_enableReflection = f.m_enableReflection; + m_enableReflectionMin = f.m_enableReflectionMin; + m_enableRefFalloff = f.m_enableRefFalloff; + m_enableRefExponent = f.m_enableRefExponent; + m_enableRefMetallic = f.m_enableRefMetallic; + m_irid = f.m_irid; +} + +PMFinish::~PMFinish( ) +{ +} + +PMMetaObject* PMFinish::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Finish", Base::metaObject( ), + createNewFinish ); + s_pMetaObject->addProperty( + new PMFinishProperty( "ambientColor", &PMFinish::setAmbientColor, &PMFinish::ambientColor ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "phong", &PMFinish::setPhong, &PMFinish::phong ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "diffuse", &PMFinish::setDiffuse, &PMFinish::diffuse ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "brilliance", &PMFinish::setBrilliance, &PMFinish::brilliance ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "crand", &PMFinish::setCrand, &PMFinish::crand ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "conserveEnergy", &PMFinish::setConserveEnergy, &PMFinish::conserveEnergy ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "specular", &PMFinish::setSpecular, &PMFinish::specular ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "roughness", &PMFinish::setRoughness, &PMFinish::roughness ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "metallic", &PMFinish::setMetallic, &PMFinish::metallic ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "irid", &PMFinish::setIrid, &PMFinish::irid ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "iridAmount", &PMFinish::setIridAmount, &PMFinish::iridAmount ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "iridThickness", &PMFinish::setIridThickness, &PMFinish::iridThickness ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "reflectionColor", &PMFinish::setReflectionColor, &PMFinish::reflectionColor ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "reflectionMinColor", &PMFinish::setReflectionMinColor, &PMFinish::reflectionMinColor ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "reflectionFresnel", &PMFinish::setReflectionFresnel, &PMFinish::reflectionFresnel ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "reflectionFalloff", &PMFinish::setReflectionFalloff, &PMFinish::reflectionFalloff ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "reflectionExponent", &PMFinish::setReflectionExponent, &PMFinish::reflectionExponent ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "reflectionMetallic", &PMFinish::setReflectionMetallic, &PMFinish::reflectionMetallic ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "ambientEnabled", &PMFinish::enableAmbient, &PMFinish::isAmbientEnabled ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "phongEnabled", &PMFinish::enablePhong, &PMFinish::isPhongEnabled ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "phongSizeEnabled", &PMFinish::enablePhongSize, &PMFinish::isPhongSizeEnabled ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "diffuseEnabled", &PMFinish::enableDiffuse, &PMFinish::isDiffuseEnabled ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "brillianceEnabled", &PMFinish::enableBrilliance, &PMFinish::isBrillianceEnabled ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "crandEnabled", &PMFinish::enableCrand, &PMFinish::isCrandEnabled ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "specularEnabled", &PMFinish::enableSpecular, &PMFinish::isSpecularEnabled ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "roughnessEnabled", &PMFinish::enableRoughness, &PMFinish::isRoughnessEnabled ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "metallicEnabled", &PMFinish::enableMetallic, &PMFinish::isMetallicEnabled ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "reflectionEnabled", &PMFinish::enableReflection, &PMFinish::isReflectionEnabled ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "reflectionMinEnabled", &PMFinish::enableReflectionMin, &PMFinish::isReflectionMinEnabled ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "refFalloffEnabled", &PMFinish::enableRefFalloff, &PMFinish::isRefFalloffEnabled ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "refExponentEnabled", &PMFinish::enableRefExponent, &PMFinish::isRefExponentEnabled ) ); + s_pMetaObject->addProperty( + new PMFinishProperty( "refMetallicEnabled", &PMFinish::enableRefMetallic, &PMFinish::isRefMetallicEnabled ) ); + } + return s_pMetaObject; +} + +void PMFinish::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMFinish::description( ) const +{ + return i18n( "finish" ); +} + +void PMFinish::serialize( QDomElement& e, QDomDocument& doc ) const +{ + Base::serialize( e, doc ); + e.setAttribute( "enable_ambient", m_enableAmbient ); + e.setAttribute( "enable_diffuse", m_enableDiffuse ); + e.setAttribute( "enable_brilliance", m_enableBrilliance ); + e.setAttribute( "enable_crand", m_enableCrand ); + e.setAttribute( "enable_phong", m_enablePhong ); + e.setAttribute( "enable_phong_size", m_enablePhongSize ); + e.setAttribute( "enable_metallic", m_enableMetallic ); + e.setAttribute( "enable_specular", m_enableSpecular ); + e.setAttribute( "enable_roughness", m_enableRoughness ); + e.setAttribute( "enable_reflection", m_enableReflection ); + e.setAttribute( "enable_reflection_min", m_enableReflectionMin ); + e.setAttribute( "enable_reflection_falloff", m_enableRefFalloff ); + e.setAttribute( "enable_reflection_exponent", m_enableRefExponent ); + e.setAttribute( "enable_reflection_metallic", m_enableRefMetallic ); + e.setAttribute( "ambient", m_ambientColor.serializeXML( ) ); + e.setAttribute( "diffuse", m_diffuse ); + e.setAttribute( "brilliance", m_brilliance ); + e.setAttribute( "crand", m_crand ); + e.setAttribute( "conserve_energy", m_conserveEnergy ); + e.setAttribute( "phong", m_phong ); + e.setAttribute( "phongsize", m_phongSize ); + e.setAttribute( "metallic", m_metallic ); + e.setAttribute( "specular", m_specular ); + e.setAttribute( "roughness", m_roughness ); + e.setAttribute( "irid", m_irid ); + e.setAttribute( "irid_amount", m_iridAmount ); + e.setAttribute( "irid_thickness", m_iridThickness ); + e.setAttribute( "irid_turbulence", m_iridTurbulence ); + e.setAttribute( "reflection", m_reflectionColor.serializeXML( ) ); + e.setAttribute( "reflection_min", m_reflectionMinColor.serializeXML( ) ); + e.setAttribute( "reflection_fresnel", m_reflectionFresnel ); + e.setAttribute( "reflection_falloff", m_reflectionFalloff ); + e.setAttribute( "reflection_exponent", m_reflectionExponent ); + e.setAttribute( "reflection_metallic", m_reflectionMetallic ); +} + +void PMFinish::readAttributes( const PMXMLHelper& h ) +{ + Base::readAttributes( h ); + m_enableAmbient = h.boolAttribute( "enable_ambient", false ); + m_enableDiffuse = h.boolAttribute( "enable_diffuse", false ); + m_enableBrilliance = h.boolAttribute( "enable_brilliance", false ); + m_enableCrand = h.boolAttribute( "enable_crand", false ); + m_enablePhong = h.boolAttribute( "enable_phong", false ); + m_enablePhongSize = h.boolAttribute( "enable_phong_size", false ); + m_enableMetallic = h.boolAttribute( "enable_metallic", false ); + m_enableSpecular = h.boolAttribute( "enable_specular", false ); + m_enableRoughness = h.boolAttribute( "enable_roughness", false ); + m_enableReflection = h.boolAttribute( "enable_reflection", false ); + m_enableReflectionMin = h.boolAttribute( "enable_reflection_min", false ); + m_enableRefFalloff = h.boolAttribute( "enable_reflection_falloff", false ); + m_enableRefExponent = h.boolAttribute( "enable_reflection_exponent", false ); + m_enableRefMetallic = h.boolAttribute( "enable_reflection_metallic", false ); + m_irid = h.boolAttribute( "irid", false ); + m_ambientColor = h.colorAttribute( "ambient", ambientColorDefault ); + m_diffuse = h.doubleAttribute( "diffuse", diffuseDefault ); + m_brilliance = h.doubleAttribute( "brilliance", crandDefault ); + m_crand = h.doubleAttribute( "crand", crandDefault ); + m_conserveEnergy = h.boolAttribute( "conserve_energy", false ); + m_phong = h.doubleAttribute( "phong", phongDefault ); + m_phongSize = h.doubleAttribute( "phongsize", phongSizeDefault ); + m_metallic = h.doubleAttribute( "metallic", metallicDefault ); + m_specular = h.doubleAttribute( "specular", specularDefault ); + m_roughness = h.doubleAttribute( "roughness", roughnessDefault ); + m_iridAmount = h.doubleAttribute( "irid_amount", iridAmountDefault ); + m_iridThickness = h.doubleAttribute( "irid_thickness", iridThicknessDefault ); + m_iridTurbulence = h.doubleAttribute( "irid_turbulence", iridTurbulenceDefault ); + m_reflectionColor = h.colorAttribute( "reflection", reflectionColorDefault ); + m_reflectionMinColor = h.colorAttribute( "reflection_min", reflectionColorDefault ); + m_reflectionFresnel = h.boolAttribute( "reflection_fresnel", false ); + m_reflectionFalloff = h.doubleAttribute( "reflection_falloff", reflectionFalloffDefault ); + m_reflectionExponent = h.doubleAttribute( "reflection_exponent", reflectionExponentDefault ); + m_reflectionMetallic = h.doubleAttribute( "reflection_metallic", reflectionMetallicDefault ); +} + +void PMFinish::setPhong( double c ) +{ + if( c != m_phong ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMPhongID, m_phong ); + m_phong = c; + } +} + +void PMFinish::setPhongSize( double c ) +{ + if( c != m_phongSize ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMPhongSizeID, m_phongSize ); + m_phongSize = c; + } +} + +void PMFinish::setMetallic( double c ) +{ + if( c != m_metallic ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMMetallicID, m_metallic ); + m_metallic = c; + } +} + +void PMFinish::setAmbientColor( const PMColor& c ) +{ + if( c != m_ambientColor ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAmbientColorID, m_ambientColor ); + m_ambientColor = c; + } +} + +void PMFinish::setDiffuse( double c ) +{ + if( c != m_diffuse ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMDiffuseID, m_diffuse ); + m_diffuse = c; + } +} + +void PMFinish::setBrilliance( double c ) +{ + if( c != m_brilliance ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMBrillianceID, m_brilliance ); + m_brilliance = c; + } +} + +void PMFinish::setCrand( double c ) +{ + if( c != m_crand ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCrandID, m_crand ); + m_crand = c; + } +} + +void PMFinish::setConserveEnergy( bool c ) +{ + if( c != m_conserveEnergy ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMConserveEnergyID, m_conserveEnergy ); + m_conserveEnergy = c; + } +} + +void PMFinish::setSpecular( double c ) +{ + if( c != m_specular ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSpecularID, m_specular ); + m_specular = c; + } +} + +void PMFinish::setRoughness( double c ) +{ + if( c != m_roughness ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRoughnessID, m_roughness ); + m_roughness = c; + } +} + +void PMFinish::setIrid( bool c ) +{ + if( c != m_irid ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMIridID, m_irid ); + m_irid = c; + } +} + +void PMFinish::setReflectionColor( const PMColor& c ) +{ + if( c != m_reflectionColor ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMReflectionColorID, m_reflectionColor ); + m_reflectionColor = c; + } +} + +void PMFinish::setReflectionMinColor( const PMColor& c ) +{ + if( c != m_reflectionMinColor ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMReflectionMinColorID, m_reflectionMinColor ); + m_reflectionMinColor = c; + } +} + +void PMFinish::setReflectionFresnel( bool c ) +{ + if( c != m_reflectionFresnel ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMReflectionFresnelID, m_reflectionFresnel ); + m_reflectionFresnel = c; + } +} + +void PMFinish::setReflectionFalloff( double c ) +{ + if( c != m_reflectionFalloff ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMReflectionFalloffID, m_reflectionFalloff ); + m_reflectionFalloff = c; + } +} + +void PMFinish::setReflectionExponent( double c ) +{ + if( c != m_reflectionExponent ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMReflectionExponentID, m_reflectionExponent ); + m_reflectionExponent = c; + } +} + +void PMFinish::setReflectionMetallic( double c ) +{ + if( c != m_reflectionMetallic ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMReflectionMetallicID, m_reflectionMetallic ); + m_reflectionMetallic = c; + } +} + +void PMFinish::enableAmbient( bool c ) +{ + if( c != m_enableAmbient ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableAmbientID, m_enableAmbient ); + m_enableAmbient = c; + } +} + +void PMFinish::enableDiffuse( bool c ) +{ + if( c != m_enableDiffuse ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableDiffuseID, m_enableDiffuse ); + m_enableDiffuse = c; + } +} + +void PMFinish::enablePhong( bool c ) +{ + if( c != m_enablePhong ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnablePhongID, m_enablePhong ); + m_enablePhong = c; + } +} + +void PMFinish::enablePhongSize( bool c ) +{ + if( c != m_enablePhongSize ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnablePhongSizeID, m_enablePhongSize ); + m_enablePhongSize = c; + } +} + +void PMFinish::enableBrilliance( bool c ) +{ + if( c != m_enableBrilliance ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableBrillianceID, m_enableBrilliance ); + m_enableBrilliance = c; + } +} + +void PMFinish::enableCrand( bool c ) +{ + if( c != m_enableCrand ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableCrandID, m_enableCrand ); + m_enableCrand = c; + } +} + +void PMFinish::enableSpecular( bool c ) +{ + if( c != m_enableSpecular ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableSpecularID, m_enableSpecular ); + m_enableSpecular = c; + } +} + +void PMFinish::enableRoughness( bool c ) +{ + if( c != m_enableRoughness ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableRoughnessID, m_enableRoughness ); + m_enableRoughness = c; + } +} + +void PMFinish::enableMetallic( bool c ) +{ + if( c != m_enableMetallic ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableMetallicID, m_enableMetallic ); + m_enableMetallic = c; + } +} + +void PMFinish::enableReflection( bool c ) +{ + if( c != m_enableReflection ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableReflectionID, m_enableReflection ); + m_enableReflection = c; + } +} + +void PMFinish::enableReflectionMin( bool c ) +{ + if( c != m_enableReflectionMin ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableReflectionMinID, m_enableReflectionMin ); + m_enableReflectionMin = c; + } +} + +void PMFinish::enableRefFalloff( bool c ) +{ + if( c != m_enableRefFalloff ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableRefFalloffID, m_enableRefFalloff ); + m_enableRefFalloff = c; + } +} + +void PMFinish::enableRefExponent( bool c ) +{ + if( c != m_enableRefExponent ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableRefExponentID, m_enableRefExponent ); + m_enableRefExponent = c; + } +} + +void PMFinish::enableRefMetallic( bool c ) +{ + if( c != m_enableRefMetallic ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableRefMetallicID, m_enableRefMetallic ); + m_enableRefMetallic = c; + } +} + +void PMFinish::setIridAmount( double c ) +{ + if( c != m_iridAmount ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMIridAmountID, m_iridAmount ); + m_iridAmount = c; + } +} + +void PMFinish::setIridThickness( double c ) +{ + if( c != m_iridThickness ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMIridThicknessID, m_iridThickness ); + m_iridThickness = c; + } +} + +void PMFinish::setIridTurbulence( double c ) +{ + if( c != m_iridTurbulence ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMIridTurbulenceID, m_iridTurbulence ); + m_iridTurbulence = c; + } +} + +PMDialogEditBase* PMFinish::editWidget( QWidget* parent ) const +{ + return new PMFinishEdit( parent ); +} + +void PMFinish::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMAmbientColorID: + setAmbientColor( data->colorData( ) ); + break; + case PMDiffuseID: + setDiffuse( data->doubleData( ) ); + break; + case PMBrillianceID: + setBrilliance( data->doubleData( ) ); + break; + case PMCrandID: + setCrand( data->doubleData( ) ); + break; + case PMConserveEnergyID: + setConserveEnergy( data->boolData( ) ); + case PMPhongID: + setPhong( data->doubleData( ) ); + break; + case PMPhongSizeID: + setPhongSize( data->doubleData( ) ); + break; + case PMMetallicID: + setMetallic( data->doubleData( ) ); + break; + case PMSpecularID: + setSpecular( data->doubleData( ) ); + break; + case PMRoughnessID: + setRoughness( data->doubleData( ) ); + break; + case PMIridID: + setIrid( data->boolData( ) ); + break; + case PMIridAmountID: + setIridAmount( data->doubleData( ) ); + break; + case PMIridThicknessID: + setIridThickness( data->doubleData( ) ); + break; + case PMIridTurbulenceID: + setIridTurbulence( data->doubleData( ) ); + break; + case PMReflectionColorID: + setReflectionColor( data->colorData( ) ); + break; + case PMReflectionMinColorID: + setReflectionMinColor( data->colorData( ) ); + break; + case PMReflectionFresnelID: + setReflectionFresnel( data->boolData( ) ); + break; + case PMReflectionFalloffID: + setReflectionFalloff( data->doubleData( ) ); + break; + case PMReflectionExponentID: + setReflectionExponent( data->doubleData( ) ); + break; + case PMReflectionMetallicID: + setReflectionMetallic( data->doubleData( ) ); + break; + case PMEnableAmbientID: + enableAmbient( data->boolData( ) ); + break; + case PMEnablePhongID: + enablePhong( data->boolData( ) ); + break; + case PMEnablePhongSizeID: + enablePhongSize( data->boolData( ) ); + break; + case PMEnableDiffuseID: + enableDiffuse( data->boolData( ) ); + break; + case PMEnableBrillianceID: + enableBrilliance( data->boolData( ) ); + break; + case PMEnableCrandID: + enableCrand( data->boolData( ) ); + break; + case PMEnableSpecularID: + enableSpecular( data->boolData( ) ); + break; + case PMEnableRoughnessID: + enableRoughness( data->boolData( ) ); + break; + case PMEnableMetallicID: + enableMetallic( data->boolData( ) ); + break; + case PMEnableReflectionID: + enableReflection( data->boolData( ) ); + break; + case PMEnableReflectionMinID: + enableReflectionMin( data->boolData( ) ); + break; + case PMEnableRefFalloffID: + enableRefFalloff( data->boolData( ) ); + break; + case PMEnableRefExponentID: + enableRefExponent( data->boolData( ) ); + break; + case PMEnableRefMetallicID: + enableRefMetallic( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMFinish::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmfinish.h b/kpovmodeler/pmfinish.h new file mode 100644 index 00000000..072a0f7c --- /dev/null +++ b/kpovmodeler/pmfinish.h @@ -0,0 +1,208 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMFINISH_H +#define PMFINISH_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebase.h" +#include "pmcolor.h" + +/** + * Class for povray finishs + */ +class PMFinish : public PMTextureBase +{ + typedef PMTextureBase Base; +public: + /** + * Creates an PMFinish + */ + PMFinish( PMPart* part ); + /** + * Copy constructor + */ + PMFinish( const PMFinish& f ); + /** + * Deletes the object + */ + virtual ~PMFinish( ); + + /** */ + virtual PMObject* copy( ) const { return new PMFinish( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMFinishEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pmfinish" ); } + + /** */ + virtual void restoreMemento( PMMemento* s ); + + PMColor ambientColor( ) const { return m_ambientColor; } + double phong( ) const { return m_phong; } + double phongSize( ) const { return m_phongSize; } + double diffuse( ) const { return m_diffuse; } + double brilliance( ) const { return m_brilliance; } + double crand( ) const { return m_crand; } + bool conserveEnergy( ) const { return m_conserveEnergy; } + double specular( ) const { return m_specular; } + double roughness( ) const { return m_roughness; } + double metallic( ) const { return m_metallic; } + bool irid( ) const { return m_irid; } + double iridAmount( ) const { return m_iridAmount; } + double iridThickness( ) const { return m_iridThickness; } + double iridTurbulence( ) const { return m_iridTurbulence; } + PMColor reflectionColor( ) const { return m_reflectionColor; } + PMColor reflectionMinColor( ) const { return m_reflectionMinColor;} + bool reflectionFresnel( ) const { return m_reflectionFresnel; } + double reflectionFalloff( ) const { return m_reflectionFalloff; } + double reflectionExponent( ) const { return m_reflectionExponent; } + double reflectionMetallic( ) const { return m_reflectionMetallic; } + bool isAmbientEnabled( ) const { return m_enableAmbient; } + bool isPhongEnabled( ) const { return m_enablePhong; } + bool isPhongSizeEnabled( ) const { return m_enablePhongSize; } + bool isDiffuseEnabled( ) const { return m_enableDiffuse; } + bool isBrillianceEnabled( ) const { return m_enableBrilliance; } + bool isCrandEnabled( ) const { return m_enableCrand; } + bool isSpecularEnabled( ) const { return m_enableSpecular; } + bool isRoughnessEnabled( ) const { return m_enableRoughness; } + bool isMetallicEnabled( ) const { return m_enableMetallic; } + bool isReflectionEnabled( ) const { return m_enableReflection; } + bool isReflectionMinEnabled( ) const { return m_enableReflectionMin; } + bool isRefFalloffEnabled( ) const { return m_enableRefFalloff; } + bool isRefExponentEnabled( ) const { return m_enableRefExponent; } + bool isRefMetallicEnabled( ) const { return m_enableRefMetallic; } + + //This is here for povrat31serialization (It won't compile otherwise) + bool isExponentEnabled( ) const { return m_enableRefExponent; } + + void setAmbientColor( const PMColor& c ); + void setPhong( double c ); + void setPhongSize( double c ); + void setDiffuse( double c ); + void setBrilliance( double c ); + void setCrand( double c ); + void setConserveEnergy( bool c ); + void setSpecular( double c ); + void setRoughness( double c ); + void setMetallic( double c ); + void setIrid( bool c ); + void setIridAmount( double c ); + void setIridThickness( double c ); + void setIridTurbulence( double c ); + void setReflectionColor( const PMColor& c ); + void setReflectionMinColor( const PMColor& c ); + void setReflectionFresnel( bool c ); + void setReflectionFalloff( double c ); + void setReflectionExponent( double c ); + void setReflectionMetallic( double c ); + void enableAmbient( bool c ); + void enablePhong( bool c ); + void enablePhongSize( bool c ); + void enableDiffuse( bool c ); + void enableBrilliance( bool c ); + void enableCrand( bool c ); + void enableSpecular( bool c ); + void enableRoughness( bool c ); + void enableMetallic( bool c ); + void enableReflection( bool c ); + void enableReflectionMin( bool c ); + void enableRefFalloff( bool c ); + void enableRefExponent( bool c ); + void enableRefMetallic( bool c ); + +private: + /** + * IDs for @ref PMMementoData + */ + enum PMFinishMementoID { PMAmbientColorID, PMPhongID, PMPhongSizeID, + PMMetallicID, PMDiffuseID, PMBrillianceID, + PMCrandID, PMConserveEnergyID, PMSpecularID, + PMRoughnessID, + PMIridID, PMIridAmountID, PMIridThicknessID, + PMReflectionColorID, PMReflectionMinColorID, + PMReflectionFresnelID, PMReflectionFalloffID, + PMReflectionExponentID, PMReflectionMetallicID, + PMIridTurbulenceID, PMEnableAmbientID, + PMEnablePhongID, PMEnablePhongSizeID, + PMEnableMetallicID, + PMEnableDiffuseID, PMEnableBrillianceID, + PMEnableCrandID, PMEnableSpecularID, + PMEnableRoughnessID, PMEnableReflectionID, + PMEnableReflectionMinID, PMEnableRefFalloffID, + PMEnableRefExponentID, PMEnableRefMetallicID }; + + PMColor m_ambientColor; + double m_phong; + double m_phongSize; + double m_diffuse; + double m_brilliance; + double m_crand; + bool m_conserveEnergy; + double m_specular; + double m_roughness; + double m_metallic; + bool m_irid; + double m_iridAmount; + double m_iridThickness; + double m_iridTurbulence; + PMColor m_reflectionColor; + PMColor m_reflectionMinColor; + bool m_reflectionFresnel; + double m_reflectionFalloff; + double m_reflectionExponent; + double m_reflectionMetallic; + + bool m_enableAmbient; + bool m_enableDiffuse; + bool m_enableBrilliance; + bool m_enableCrand; + bool m_enablePhong; + bool m_enablePhongSize; + bool m_enableMetallic; + bool m_enableSpecular; + bool m_enableRoughness; + bool m_enableReflection; + bool m_enableReflectionMin; + bool m_enableRefFalloff; + bool m_enableRefExponent; + bool m_enableRefMetallic; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmfinishedit.cpp b/kpovmodeler/pmfinishedit.cpp new file mode 100644 index 00000000..809cbd66 --- /dev/null +++ b/kpovmodeler/pmfinishedit.cpp @@ -0,0 +1,474 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmfinishedit.h" +#include "pmfinish.h" +#include "pmlineedits.h" +#include "pmcoloredit.h" + +#include +#include +#include +#include +#include +#include + + +PMFinishEdit::PMFinishEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMFinishEdit::createTopWidgets( ) +{ + QHBoxLayout* hl; + + Base::createTopWidgets( ); + + hl = new QHBoxLayout( topLayout( ) ); + QGridLayout* layout = new QGridLayout( hl, 2, 2 ); + m_pEnableAmbientEdit = new QCheckBox( i18n( "Ambient color" ), this ); + m_pAmbientColorLabel = new QLabel( i18n( "Color:" ), this ); + m_pAmbientColorEdit = new PMColorEdit( true, this ); + layout->addMultiCellWidget( m_pEnableAmbientEdit, 0, 0, 0, 1 ); + layout->addWidget( m_pAmbientColorLabel, 1, 0, AlignTop ); + layout->addWidget( m_pAmbientColorEdit, 1, 1 ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + layout = new QGridLayout( hl, 4, 2 ); + m_pEnableDiffuseEdit = new QCheckBox( i18n( "Diffuse:" ), this ); + m_pDiffuseEdit = new PMFloatEdit( this ); + layout->addWidget( m_pEnableDiffuseEdit, 0, 0 ); + layout->addWidget( m_pDiffuseEdit, 0, 1 ); + m_pEnableBrillianceEdit = new QCheckBox( i18n( "Brilliance:" ), this ); + m_pBrillianceEdit = new PMFloatEdit( this ); + layout->addWidget( m_pEnableBrillianceEdit, 1, 0 ); + layout->addWidget( m_pBrillianceEdit, 1, 1 ); + m_pEnableCrandEdit = new QCheckBox( i18n( "Crand:" ), this ); + m_pCrandEdit = new PMFloatEdit( this ); + layout->addWidget( m_pEnableCrandEdit, 2, 0 ); + layout->addWidget( m_pCrandEdit, 2, 1 ); + m_pConserveEnergyEdit = new QCheckBox( + i18n( "Conserve energy for reflection" ), this ); + layout->addMultiCellWidget( m_pConserveEnergyEdit, 3, 3, 0, 1 ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + layout = new QGridLayout( hl, 2, 2 ); + m_pEnablePhongEdit = new QCheckBox( i18n( "Phong:" ), this ); + m_pPhongEdit = new PMFloatEdit( this ); + m_pEnablePhongSizeEdit = new QCheckBox( i18n( "Phong size:" ), this ); + m_pPhongSizeEdit = new PMFloatEdit( this ); + layout->addWidget( m_pEnablePhongEdit, 0, 0 ); + layout->addWidget( m_pPhongEdit, 0, 1 ); + layout->addWidget( m_pEnablePhongSizeEdit, 1, 0 ); + layout->addWidget( m_pPhongSizeEdit, 1, 1 ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + layout = new QGridLayout( hl, 3, 2 ); + m_pEnableSpecularEdit = new QCheckBox( i18n( "Specular:" ), this ); + m_pSpecularEdit = new PMFloatEdit( this ); + layout->addWidget( m_pEnableSpecularEdit, 0, 0 ); + layout->addWidget( m_pSpecularEdit, 0, 1 ); + m_pEnableRoughnessEdit = new QCheckBox( i18n( "Roughness:" ), this ); + m_pRoughnessEdit = new PMFloatEdit( this ); + layout->addWidget( m_pEnableRoughnessEdit, 1, 0 ); + layout->addWidget( m_pRoughnessEdit, 1, 1 ); + m_pEnableMetallicEdit = new QCheckBox( i18n( "Metallic:" ), this ); + m_pMetallicEdit = new PMFloatEdit( this ); + layout->addWidget( m_pEnableMetallicEdit, 2, 0 ); + layout->addWidget( m_pMetallicEdit, 2, 1 ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + layout = new QGridLayout( hl, 6, 2 ); + m_pIridEdit = new QCheckBox( i18n( "Iridiscence" ), this ); + layout->addMultiCellWidget( m_pIridEdit, 0, 0, 0, 1 ); + m_pIridAmountLabel = new QLabel( i18n( "Amount:" ), this ); + m_pIridAmountEdit = new PMFloatEdit( this ); + layout->addWidget( m_pIridAmountLabel, 1, 0 ); + layout->addWidget( m_pIridAmountEdit, 1, 1 ); + m_pIridThicknessLabel = new QLabel( i18n( "Thickness:" ), this ); + m_pIridThicknessEdit = new PMFloatEdit( this ); + layout->addWidget( m_pIridThicknessLabel, 2, 0 ); + layout->addWidget( m_pIridThicknessEdit, 2, 1 ); + m_pIridTurbulenceEdit = new PMFloatEdit( this ); + m_pIridTurbulenceLabel = new QLabel( i18n( "Turbulence:" ), this ); + layout->addWidget( m_pIridTurbulenceLabel, 3, 0 ); + layout->addWidget( m_pIridTurbulenceEdit, 3, 1 ); + m_pEnableReflectionEdit = new QCheckBox( i18n( "Reflection" ), this ); + layout->addMultiCellWidget( m_pEnableReflectionEdit, 4, 4, 0, 1 ); + hl->addStretch( 1 ); + + m_pReflectionWidget = new QWidget( this ); + QVBoxLayout* vl = new QVBoxLayout( m_pReflectionWidget, 0, KDialog::spacingHint( ) ); + QGridLayout* gl = new QGridLayout( vl, 2, 2 ); + m_pEnableReflectionMinEdit = new QCheckBox( i18n( "Minimum:" ), + m_pReflectionWidget ); + m_pReflectionMinColorEdit = new PMColorEdit( false, m_pReflectionWidget ); + gl->addWidget( m_pEnableReflectionMinEdit, 0, 0, AlignTop ); + gl->addWidget( m_pReflectionMinColorEdit, 0, 1 ); + QLabel* label = new QLabel( i18n( "Maximum:" ), m_pReflectionWidget ); + m_pReflectionColorEdit = new PMColorEdit( false, m_pReflectionWidget ); + gl->addWidget( label, 1, 0, AlignTop ); + gl->addWidget( m_pReflectionColorEdit, 1, 1 ); + + gl = new QGridLayout( vl, 4, 2 ); + m_pReflectionFresnelEdit = new QCheckBox( i18n( "Fresnel reflectivity" ), + m_pReflectionWidget ); + gl->addMultiCellWidget( m_pReflectionFresnelEdit, 0, 0, 0, 1 ); + m_pEnableRefFalloffEdit = new QCheckBox( i18n( "Falloff:" ), + m_pReflectionWidget ); + m_pReflectionFalloffEdit = new PMFloatEdit( m_pReflectionWidget ); + gl->addWidget( m_pEnableRefFalloffEdit, 1, 0 ); + gl->addWidget( m_pReflectionFalloffEdit, 1, 1 ); + m_pEnableRefExponentEdit = new QCheckBox( i18n( "Exponent:" ), + m_pReflectionWidget ); + m_pReflectionExponentEdit = new PMFloatEdit( m_pReflectionWidget ); + gl->addWidget( m_pEnableRefExponentEdit, 2, 0 ); + gl->addWidget( m_pReflectionExponentEdit, 2, 1 ); + m_pEnableRefMetallicEdit = new QCheckBox( i18n( "Metallic:" ), + m_pReflectionWidget ); + m_pReflectionMetallicEdit = new PMFloatEdit( m_pReflectionWidget ); + gl->addWidget( m_pEnableRefMetallicEdit, 3, 0 ); + gl->addWidget( m_pReflectionMetallicEdit, 3, 1 ); + vl->addStretch( 1 ); + layout->addMultiCellWidget( m_pReflectionWidget, 5, 5, 0, 1 ); + + + connect( m_pAmbientColorEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pDiffuseEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pBrillianceEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pCrandEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pConserveEnergyEdit, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pPhongEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pPhongSizeEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pMetallicEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pSpecularEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pRoughnessEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pIridAmountEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pIridThicknessEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pIridTurbulenceEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pIridEdit, SIGNAL( clicked( ) ), SLOT( slotIridClicked( ) ) ); + connect( m_pReflectionColorEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pReflectionMinColorEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pReflectionFresnelEdit, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pReflectionFalloffEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pReflectionExponentEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pReflectionMetallicEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + + connect( m_pEnableAmbientEdit, SIGNAL( clicked( ) ), SLOT( slotAmbientClicked( ) ) ); + connect( m_pEnablePhongEdit, SIGNAL( clicked( ) ), SLOT( slotPhongClicked( ) ) ); + connect( m_pEnablePhongSizeEdit, SIGNAL( clicked( ) ), SLOT( slotPhongSizeClicked( ) ) ); + connect( m_pEnableDiffuseEdit, SIGNAL( clicked( ) ), SLOT( slotDiffuseClicked( ) ) ); + connect( m_pEnableBrillianceEdit, SIGNAL( clicked( ) ), SLOT( slotBrillianceClicked( ) ) ); + connect( m_pEnableCrandEdit, SIGNAL( clicked( ) ), SLOT( slotCrandClicked( ) ) ); + connect( m_pEnableSpecularEdit, SIGNAL( clicked( ) ), SLOT( slotSpecularClicked( ) ) ); + connect( m_pEnableRoughnessEdit, SIGNAL( clicked( ) ), SLOT( slotRoughnessClicked( ) ) ); + connect( m_pEnableMetallicEdit, SIGNAL( clicked( ) ), SLOT( slotMetallicClicked( ) ) ); + connect( m_pEnableReflectionEdit, SIGNAL( clicked( ) ), SLOT( slotReflectionClicked( ) ) ); + connect( m_pEnableReflectionMinEdit, SIGNAL( clicked( ) ), SLOT( slotReflectionMinClicked( ) ) ); + connect( m_pEnableRefFalloffEdit, SIGNAL( clicked( ) ), SLOT( slotRefFalloffClicked( ) ) ); + connect( m_pEnableRefExponentEdit, SIGNAL( clicked( ) ), SLOT( slotRefExponentClicked( ) ) ); + connect( m_pEnableRefMetallicEdit, SIGNAL( clicked( ) ), SLOT( slotRefMetallicClicked( ) ) ); +} + +void PMFinishEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Finish" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMFinish* ) o; + + m_pAmbientColorEdit->setColor( m_pDisplayedObject->ambientColor( ) ); + m_pAmbientColorEdit->setReadOnly( readOnly ); + m_pDiffuseEdit->setValue( m_pDisplayedObject->diffuse( ) ); + m_pDiffuseEdit->setReadOnly( readOnly ); + m_pBrillianceEdit->setValue( m_pDisplayedObject->brilliance( ) ); + m_pBrillianceEdit->setReadOnly( readOnly ); + m_pCrandEdit->setValue( m_pDisplayedObject->crand( ) ); + m_pCrandEdit->setReadOnly( readOnly ); + m_pConserveEnergyEdit->setChecked( m_pDisplayedObject->conserveEnergy( ) ); + m_pConserveEnergyEdit->setEnabled( !readOnly ); + m_pPhongEdit->setValue( m_pDisplayedObject->phong( ) ); + m_pPhongEdit->setReadOnly( readOnly ); + m_pPhongSizeEdit->setValue( m_pDisplayedObject->phongSize( ) ); + m_pPhongSizeEdit->setReadOnly( readOnly ); + m_pMetallicEdit->setValue( m_pDisplayedObject->metallic( ) ); + m_pMetallicEdit->setReadOnly( readOnly ); + m_pSpecularEdit->setValue( m_pDisplayedObject->specular( ) ); + m_pSpecularEdit->setReadOnly( readOnly ); + m_pRoughnessEdit->setValue( m_pDisplayedObject->roughness( ) ); + m_pRoughnessEdit->setReadOnly( readOnly ); + m_pIridEdit->setChecked( m_pDisplayedObject->irid( ) ); + m_pIridEdit->setEnabled( !readOnly ); + m_pIridAmountEdit->setValue( m_pDisplayedObject->iridAmount( ) ); + m_pIridAmountEdit->setReadOnly( readOnly ); + m_pIridThicknessEdit->setValue( m_pDisplayedObject->iridThickness( ) ); + m_pIridThicknessEdit->setReadOnly( readOnly ); + m_pIridTurbulenceEdit->setValue( m_pDisplayedObject->iridTurbulence( ) ); + m_pIridTurbulenceEdit->setReadOnly( readOnly ); + m_pReflectionColorEdit->setColor( m_pDisplayedObject->reflectionColor( ) ); + m_pReflectionColorEdit->setReadOnly( readOnly ); + m_pReflectionMinColorEdit->setColor( m_pDisplayedObject->reflectionMinColor( ) ); + m_pReflectionMinColorEdit->setReadOnly( readOnly ); + m_pReflectionFresnelEdit->setChecked( m_pDisplayedObject->reflectionFresnel( ) ); + m_pReflectionFresnelEdit->setEnabled( !readOnly ); + m_pReflectionFalloffEdit->setValue( m_pDisplayedObject->reflectionFalloff( ) ); + m_pReflectionFalloffEdit->setReadOnly( readOnly ); + m_pReflectionExponentEdit->setValue( m_pDisplayedObject->reflectionExponent( ) ); + m_pReflectionExponentEdit->setReadOnly( readOnly ); + m_pReflectionMetallicEdit->setValue( m_pDisplayedObject->reflectionMetallic( ) ); + m_pReflectionMetallicEdit->setReadOnly( readOnly ); + m_pEnableAmbientEdit->setChecked( m_pDisplayedObject->isAmbientEnabled( ) ); + m_pEnableAmbientEdit->setEnabled( !readOnly ); + m_pEnablePhongEdit->setChecked( m_pDisplayedObject->isPhongEnabled( ) ); + m_pEnablePhongEdit->setEnabled( !readOnly ); + m_pEnablePhongSizeEdit->setChecked( m_pDisplayedObject->isPhongSizeEnabled( ) ); + m_pEnablePhongSizeEdit->setEnabled( !readOnly ); + m_pEnableDiffuseEdit->setChecked( m_pDisplayedObject->isDiffuseEnabled( ) ); + m_pEnableDiffuseEdit->setEnabled( !readOnly ); + m_pEnableBrillianceEdit->setChecked( m_pDisplayedObject->isBrillianceEnabled( ) ); + m_pEnableBrillianceEdit->setEnabled( !readOnly ); + m_pEnableCrandEdit->setChecked( m_pDisplayedObject->isCrandEnabled( ) ); + m_pEnableCrandEdit->setEnabled( !readOnly ); + m_pEnableMetallicEdit->setChecked( m_pDisplayedObject->isMetallicEnabled( ) ); + m_pEnableMetallicEdit->setEnabled( !readOnly ); + m_pEnableSpecularEdit->setChecked( m_pDisplayedObject->isSpecularEnabled( ) ); + m_pEnableSpecularEdit->setEnabled( !readOnly ); + m_pEnableRoughnessEdit->setChecked( m_pDisplayedObject->isRoughnessEnabled( ) ); + m_pEnableRoughnessEdit->setEnabled( !readOnly ); + m_pEnableReflectionEdit->setChecked( m_pDisplayedObject->isReflectionEnabled( ) ); + m_pEnableReflectionEdit->setEnabled( !readOnly ); + m_pEnableReflectionMinEdit->setChecked( m_pDisplayedObject->isReflectionMinEnabled( ) ); + m_pEnableReflectionMinEdit->setEnabled( !readOnly ); + m_pEnableRefFalloffEdit->setChecked( m_pDisplayedObject->isRefFalloffEnabled( ) ); + m_pEnableRefFalloffEdit->setEnabled( !readOnly ); + m_pEnableRefExponentEdit->setChecked( m_pDisplayedObject->isRefExponentEnabled( ) ); + m_pEnableRefExponentEdit->setEnabled( !readOnly ); + m_pEnableRefMetallicEdit->setChecked( m_pDisplayedObject->isRefMetallicEnabled( ) ); + m_pEnableRefMetallicEdit->setEnabled( !readOnly ); + slotIridClicked( ); + slotAmbientClicked( ); + slotPhongClicked( ); + slotPhongSizeClicked( ); + slotBrillianceClicked( ); + slotDiffuseClicked( ); + slotMetallicClicked( ); + slotCrandClicked( ); + slotSpecularClicked( ); + slotRoughnessClicked( ); + slotReflectionClicked( ); + slotReflectionMinClicked( ); + slotRefFalloffClicked( ); + slotRefExponentClicked( ); + slotRefMetallicClicked( ); + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMFinishEdit: Can't display object\n"; +} + +void PMFinishEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setAmbientColor( m_pAmbientColorEdit->color( ) ); + m_pDisplayedObject->setDiffuse( m_pDiffuseEdit->value( ) ); + m_pDisplayedObject->setBrilliance( m_pBrillianceEdit->value( ) ); + m_pDisplayedObject->setCrand( m_pCrandEdit->value( ) ); + m_pDisplayedObject->setConserveEnergy( m_pConserveEnergyEdit->isChecked( ) ); + m_pDisplayedObject->setPhong( m_pPhongEdit->value( ) ); + m_pDisplayedObject->setPhongSize( m_pPhongSizeEdit->value( ) ); + m_pDisplayedObject->setMetallic( m_pMetallicEdit->value( ) ); + m_pDisplayedObject->setSpecular( m_pSpecularEdit->value( ) ); + m_pDisplayedObject->setRoughness( m_pRoughnessEdit->value( ) ); + m_pDisplayedObject->setIrid( m_pIridEdit->isChecked( ) ); + m_pDisplayedObject->setIridAmount( m_pIridAmountEdit->value( ) ); + m_pDisplayedObject->setIridThickness( m_pIridThicknessEdit->value( ) ); + m_pDisplayedObject->setIridTurbulence( m_pIridTurbulenceEdit->value( ) ); + m_pDisplayedObject->setReflectionColor( m_pReflectionColorEdit->color( ) ); + m_pDisplayedObject->setReflectionMinColor( m_pReflectionMinColorEdit->color( ) ); + m_pDisplayedObject->setReflectionFresnel( m_pReflectionFresnelEdit->isChecked( ) ); + m_pDisplayedObject->setReflectionFalloff( m_pReflectionFalloffEdit->value( ) ); + m_pDisplayedObject->setReflectionExponent( m_pReflectionExponentEdit->value( ) ); + m_pDisplayedObject->setReflectionMetallic( m_pReflectionMetallicEdit->value( ) ); + m_pDisplayedObject->enableAmbient( m_pEnableAmbientEdit->isChecked( ) ); + m_pDisplayedObject->enablePhong( m_pEnablePhongEdit->isChecked( ) ); + m_pDisplayedObject->enablePhongSize( m_pEnablePhongSizeEdit->isChecked( ) ); + m_pDisplayedObject->enableBrilliance( m_pEnableBrillianceEdit->isChecked( ) ); + m_pDisplayedObject->enableDiffuse( m_pEnableDiffuseEdit->isChecked( ) ); + m_pDisplayedObject->enableCrand( m_pEnableCrandEdit->isChecked( ) ); + m_pDisplayedObject->enableMetallic( m_pEnableMetallicEdit->isChecked( ) ); + m_pDisplayedObject->enableRoughness( m_pEnableRoughnessEdit->isChecked( ) ); + m_pDisplayedObject->enableSpecular( m_pEnableSpecularEdit->isChecked( ) ); + m_pDisplayedObject->enableReflection( m_pEnableReflectionEdit->isChecked( ) ); + m_pDisplayedObject->enableReflectionMin( m_pEnableReflectionMinEdit->isChecked( ) ); + m_pDisplayedObject->enableRefFalloff( m_pEnableRefFalloffEdit->isChecked( ) ); + m_pDisplayedObject->enableRefExponent( m_pEnableRefExponentEdit->isChecked( ) ); + m_pDisplayedObject->enableRefMetallic( m_pEnableRefMetallicEdit->isChecked( ) ); + } +} + +bool PMFinishEdit::isDataValid( ) +{ + if( !m_pDiffuseEdit->isDataValid( ) ) return false; + if( !m_pBrillianceEdit->isDataValid( ) ) return false; + if( !m_pCrandEdit->isDataValid( ) ) return false; + if( !m_pPhongEdit->isDataValid( ) ) return false; + if( !m_pPhongSizeEdit->isDataValid( ) ) return false; + if( !m_pMetallicEdit->isDataValid( ) ) return false; + if( !m_pSpecularEdit->isDataValid( ) ) return false; + if( !m_pRoughnessEdit->isDataValid( ) ) return false; + if( !m_pIridAmountEdit->isDataValid( ) ) return false; + if( !m_pIridThicknessEdit->isDataValid( ) ) return false; + if( !m_pIridTurbulenceEdit->isDataValid( ) ) return false; + if( !m_pReflectionFalloffEdit->isDataValid( ) ) return false; + if( !m_pReflectionExponentEdit->isDataValid( ) ) return false; + if( !m_pReflectionMetallicEdit->isDataValid( ) ) return false; + return Base::isDataValid( ); +} + +void PMFinishEdit::slotIridClicked( ) +{ + if( m_pIridEdit->isChecked( ) ) + { + m_pIridAmountLabel->show( ); + m_pIridAmountEdit->show( ); + m_pIridThicknessLabel->show( ); + m_pIridThicknessEdit->show( ); + m_pIridTurbulenceEdit->show( ); + m_pIridTurbulenceLabel->show( ); + } + else + { + m_pIridAmountLabel->hide( ); + m_pIridAmountEdit->hide( ); + m_pIridThicknessLabel->hide( ); + m_pIridThicknessEdit->hide( ); + m_pIridTurbulenceEdit->hide( ); + m_pIridTurbulenceLabel->hide( ); + } + emit dataChanged( ); + emit sizeChanged( ); +} + +void PMFinishEdit::slotAmbientClicked( ) +{ + if( m_pEnableAmbientEdit->isChecked( ) ) + { + m_pAmbientColorEdit->show( ); + m_pAmbientColorLabel->show( ); + } + else + { + m_pAmbientColorEdit->hide( ); + m_pAmbientColorLabel->hide( ); + } + emit dataChanged( ); + emit sizeChanged( ); +} + +void PMFinishEdit::slotPhongClicked( ) +{ + m_pPhongEdit->setEnabled( m_pEnablePhongEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMFinishEdit::slotPhongSizeClicked( ) +{ + m_pPhongSizeEdit->setEnabled( m_pEnablePhongSizeEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMFinishEdit::slotBrillianceClicked( ) +{ + m_pBrillianceEdit->setEnabled( m_pEnableBrillianceEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMFinishEdit::slotDiffuseClicked( ) +{ + m_pDiffuseEdit->setEnabled( m_pEnableDiffuseEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMFinishEdit::slotMetallicClicked( ) +{ + m_pMetallicEdit->setEnabled( m_pEnableMetallicEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMFinishEdit::slotCrandClicked( ) +{ + m_pCrandEdit->setEnabled( m_pEnableCrandEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMFinishEdit::slotSpecularClicked( ) +{ + m_pSpecularEdit->setEnabled( m_pEnableSpecularEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMFinishEdit::slotRoughnessClicked( ) +{ + m_pRoughnessEdit->setEnabled( m_pEnableRoughnessEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMFinishEdit::slotReflectionClicked( ) +{ + if( m_pEnableReflectionEdit->isChecked( ) ) + m_pReflectionWidget->show( ); + else + m_pReflectionWidget->hide( ); + + emit dataChanged( ); + emit sizeChanged( ); +} + +void PMFinishEdit::slotReflectionMinClicked( ) +{ + m_pReflectionMinColorEdit->setEnabled( m_pEnableReflectionMinEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMFinishEdit::slotRefFalloffClicked( ) +{ + m_pReflectionFalloffEdit->setEnabled( m_pEnableRefFalloffEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMFinishEdit::slotRefExponentClicked( ) +{ + m_pReflectionExponentEdit->setEnabled( m_pEnableRefExponentEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMFinishEdit::slotRefMetallicClicked( ) +{ + m_pReflectionMetallicEdit->setEnabled( m_pEnableRefMetallicEdit->isChecked( ) ); + emit dataChanged( ); +} + +#include "pmfinishedit.moc" diff --git a/kpovmodeler/pmfinishedit.h b/kpovmodeler/pmfinishedit.h new file mode 100644 index 00000000..313b35dc --- /dev/null +++ b/kpovmodeler/pmfinishedit.h @@ -0,0 +1,122 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMFINISHEDIT_H +#define PMFINISHEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebaseedit.h" + +class PMFinish; +class PMFloatEdit; +class PMColorEdit; +class QCheckBox; +class QLabel; +class QWidget; + +/** + * Dialog edit class for @ref PMFinish + */ +class PMFinishEdit : public PMTextureBaseEdit +{ + Q_OBJECT + typedef PMTextureBaseEdit Base; +public: + /** + * Creates a PMFinishEdit with parent and name + */ + PMFinishEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + void slotIridClicked( ); + void slotAmbientClicked( ); + void slotPhongClicked( ); + void slotPhongSizeClicked( ); + void slotBrillianceClicked( ); + void slotDiffuseClicked( ); + void slotMetallicClicked( ); + void slotCrandClicked( ); + void slotSpecularClicked( ); + void slotRoughnessClicked( ); + void slotReflectionClicked( ); + void slotReflectionMinClicked( ); + void slotRefFalloffClicked( ); + void slotRefExponentClicked( ); + void slotRefMetallicClicked( ); + +private: + PMFinish* m_pDisplayedObject; + PMColorEdit* m_pAmbientColorEdit; + QLabel* m_pAmbientColorLabel; + PMFloatEdit* m_pDiffuseEdit; + PMFloatEdit* m_pBrillianceEdit; + PMFloatEdit* m_pCrandEdit; + QCheckBox* m_pConserveEnergyEdit; + PMFloatEdit* m_pPhongEdit; + PMFloatEdit* m_pPhongSizeEdit; + PMFloatEdit* m_pMetallicEdit; + PMFloatEdit* m_pSpecularEdit; + PMFloatEdit* m_pRoughnessEdit; + QCheckBox* m_pIridEdit; + PMFloatEdit* m_pIridAmountEdit; + PMFloatEdit* m_pIridThicknessEdit; + PMFloatEdit* m_pIridTurbulenceEdit; + QLabel* m_pIridAmountLabel; + QLabel* m_pIridThicknessLabel; + QLabel* m_pIridTurbulenceLabel; + QCheckBox* m_pEnableAmbientEdit; + QCheckBox* m_pEnablePhongEdit; + QCheckBox* m_pEnablePhongSizeEdit; + QCheckBox* m_pEnableDiffuseEdit; + QCheckBox* m_pEnableBrillianceEdit; + QCheckBox* m_pEnableCrandEdit; + QCheckBox* m_pEnableSpecularEdit; + QCheckBox* m_pEnableRoughnessEdit; + QCheckBox* m_pEnableMetallicEdit; + + QWidget* m_pReflectionWidget; + PMColorEdit* m_pReflectionColorEdit; + PMColorEdit* m_pReflectionMinColorEdit; + QCheckBox* m_pReflectionFresnelEdit; + PMFloatEdit* m_pReflectionFalloffEdit; + PMFloatEdit* m_pReflectionExponentEdit; + PMFloatEdit* m_pReflectionMetallicEdit; + QCheckBox* m_pEnableReflectionEdit; + QCheckBox* m_pEnableReflectionMinEdit; + QCheckBox* m_pEnableRefFalloffEdit; + QCheckBox* m_pEnableRefExponentEdit; + QCheckBox* m_pEnableRefMetallicEdit; +}; + + +#endif diff --git a/kpovmodeler/pmfog.cpp b/kpovmodeler/pmfog.cpp new file mode 100644 index 00000000..5f2f1581 --- /dev/null +++ b/kpovmodeler/pmfog.cpp @@ -0,0 +1,347 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#include "pmfog.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmfogedit.h" +#include "pmvector.h" + +#include + +const int fogTypeDefault = 1; +const double distanceDefault = 0.0; +const PMColor colorDefault = PMColor( 0.0, 0.0, 0.0 ); +const double lambdaDefault = 2.0; +const double fogOffsetDefault = 0.0; +const double fogAltDefault = 0.0; +const PMVector turbulenceDefault = PMVector( 0.0, 0.0, 0.0 ); +const int octavesDefault = 6; +const double omegaDefault = 0.5; +const double turbDepthDefault = 0.5; +const PMVector upDefault = PMVector( 0.0, 1.0, 0.0 ); + +PMDefinePropertyClass( PMFog, PMFogProperty ); + +PMMetaObject* PMFog::s_pMetaObject = 0; +PMObject* createNewFog( PMPart* part ) +{ + return new PMFog( part ); +} + +PMFog::PMFog( PMPart* part ) + : Base( part ) +{ + m_fogType = fogTypeDefault; + m_distance = distanceDefault; + m_color = colorDefault; + m_enableTurbulence = false; + m_valueVector = turbulenceDefault; + m_octaves = octavesDefault; + m_omega = omegaDefault; + m_depth = turbDepthDefault; + m_fogOffset = fogOffsetDefault; + m_fogAlt = fogAltDefault; + m_up = upDefault; + m_lambda = 0; +} + +PMFog::PMFog( const PMFog& f ) + : Base( f ) +{ + m_fogType = f.m_fogType; + m_distance = f.m_distance; + m_color = f.m_color; + m_enableTurbulence = f.m_enableTurbulence; + m_valueVector = f.m_valueVector; + m_octaves = f.m_octaves; + m_omega = f.m_omega; + m_depth = f.m_depth; + m_fogOffset = f.m_fogOffset; + m_fogAlt = f.m_fogAlt; + m_up = f.m_up; + m_lambda = f.m_lambda; +} + +PMFog::~PMFog( ) +{ +} + +PMMetaObject* PMFog::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Fog", Base::metaObject( ), + createNewFog ); + s_pMetaObject->addProperty( + new PMFogProperty( "fogType", &PMFog::setFogType, &PMFog::fogType ) ); + s_pMetaObject->addProperty( + new PMFogProperty( "distance", &PMFog::setDistance, &PMFog::distance ) ); + s_pMetaObject->addProperty( + new PMFogProperty( "color", &PMFog::setColor, &PMFog::color ) ); + s_pMetaObject->addProperty( + new PMFogProperty( "turbulenceEnabled", &PMFog::enableTurbulence, &PMFog::isTurbulenceEnabled ) ); + s_pMetaObject->addProperty( + new PMFogProperty( "turbulence", &PMFog::setValueVector, &PMFog::valueVector ) ); + s_pMetaObject->addProperty( + new PMFogProperty( "octaves", &PMFog::setOctaves, &PMFog::octaves ) ); + s_pMetaObject->addProperty( + new PMFogProperty( "omega", &PMFog::setOmega, &PMFog::omega ) ); + s_pMetaObject->addProperty( + new PMFogProperty( "lambda", &PMFog::setLambda, &PMFog::lambda ) ); + s_pMetaObject->addProperty( + new PMFogProperty( "depth", &PMFog::setDepth, &PMFog::depth ) ); + s_pMetaObject->addProperty( + new PMFogProperty( "offset", &PMFog::setFogOffset, &PMFog::fogOffset ) ); + s_pMetaObject->addProperty( + new PMFogProperty( "altitude", &PMFog::setFogAlt, &PMFog::fogAlt ) ); + s_pMetaObject->addProperty( + new PMFogProperty( "up", &PMFog::setUp, &PMFog::up ) ); + } + return s_pMetaObject; +} + +void PMFog::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMFog::description( ) const +{ + return i18n( "fog" ); +} + +void PMFog::serialize( QDomElement& e, QDomDocument& doc ) const +{ + Base::serialize( e, doc ); + e.setAttribute( "fog_type", m_fogType ); + e.setAttribute( "distance", m_distance ); + e.setAttribute( "color", m_color.serializeXML( ) ); + e.setAttribute( "enable_turbulence", m_enableTurbulence ); + e.setAttribute( "value_vector", m_valueVector.serializeXML( ) ); + e.setAttribute( "octaves", m_octaves ); + e.setAttribute( "omega", m_omega ); + e.setAttribute( "lambda", m_lambda ); + e.setAttribute( "depth", m_depth ); + e.setAttribute( "fog_offset", m_fogOffset ); + e.setAttribute( "fog_alt", m_fogAlt ); + e.setAttribute( "up", m_up.serializeXML( ) ); +} + +void PMFog::readAttributes( const PMXMLHelper& h ) +{ + Base::readAttributes( h ); + m_fogType = h.intAttribute( "fog_type", fogTypeDefault ); + m_distance = h.doubleAttribute( "distance", distanceDefault ); + m_color = h.colorAttribute( "color", colorDefault ); + m_enableTurbulence = h.boolAttribute( "enable_turbulence", false ); + m_valueVector = h.vectorAttribute( "value_vector", turbulenceDefault ); + m_octaves = h.intAttribute( "octaves", octavesDefault ); + m_omega = h.doubleAttribute( "omega", omegaDefault ); + m_lambda = h.doubleAttribute( "lambda", lambdaDefault ); + m_depth = h.doubleAttribute( "depth", turbDepthDefault ); + m_fogOffset = h.doubleAttribute( "fog_offset", fogOffsetDefault ); + m_fogAlt = h.doubleAttribute( "fog_alt", fogAltDefault ); + m_up = h.vectorAttribute( "up", upDefault ); +} + +void PMFog::setFogType( int c ) +{ + if( c != m_fogType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFogTypeID, m_fogType ); + m_fogType = c; + } +} + +void PMFog::setDistance( double c ) +{ + if( c != m_distance ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMDistanceID, m_distance ); + m_distance = c; + } +} + +void PMFog::setColor( const PMColor& c ) +{ + if( c != m_color ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMColorID, m_color ); + m_color = c; + } +} + +void PMFog::enableTurbulence( bool c ) +{ + if( c != m_enableTurbulence ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableTurbulenceID, m_enableTurbulence ); + m_enableTurbulence = c; + } +} + +void PMFog::setValueVector( const PMVector& c ) +{ + if( c != m_valueVector ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMValueVectorID, m_valueVector ); + m_valueVector = c; + } +} + +void PMFog::setOctaves( int c ) +{ + if( c != m_octaves ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMOctavesID, m_octaves ); + m_octaves = c; + } +} + +void PMFog::setOmega( double c ) +{ + if( c != m_omega ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMOmegaID, m_omega ); + m_omega = c; + } +} + +void PMFog::setLambda( double c ) +{ + if( c != m_lambda ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMLambdaID, m_lambda ); + m_lambda = c; + } +} + +void PMFog::setDepth( double c ) +{ + if( c != m_depth ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMDepthID, m_depth ); + m_depth = c; + } +} + +void PMFog::setFogOffset( double c ) +{ + if( c != m_fogOffset ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFogOffsetID, m_fogOffset ); + m_fogOffset = c; + } +} + +void PMFog::setFogAlt( double c ) +{ + if( c != m_fogAlt ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFogAltID, m_fogAlt ); + m_fogAlt = c; + } +} + +void PMFog::setUp( const PMVector& c ) +{ + if( c != m_up ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMUpID, m_up ); + m_up = c; + } +} + +PMDialogEditBase* PMFog::editWidget( QWidget* parent ) const +{ + return new PMFogEdit( parent ); +} + +void PMFog::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMFogTypeID: + setFogType( data->intData( ) ); + break; + case PMDistanceID: + setDistance( data->doubleData( ) ); + break; + case PMColorID: + setColor( data->colorData( ) ); + break; + case PMEnableTurbulenceID: + enableTurbulence( data->boolData( ) ); + break; + case PMValueVectorID: + setValueVector( data->vectorData( ) ); + break; + case PMOctavesID: + setOctaves( data->intData( ) ); + break; + case PMOmegaID: + setOmega( data->doubleData( ) ); + break; + case PMLambdaID: + setLambda( data->doubleData( ) ); + break; + case PMDepthID: + setDepth( data->doubleData( ) ); + break; + case PMFogOffsetID: + setFogOffset( data->doubleData( ) ); + break; + case PMFogAltID: + setFogAlt( data->doubleData( ) ); + break; + case PMUpID: + setUp( data->vectorData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMFog::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmfog.h b/kpovmodeler/pmfog.h new file mode 100644 index 00000000..444fa54a --- /dev/null +++ b/kpovmodeler/pmfog.h @@ -0,0 +1,129 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMFOG_H +#define PMFOG_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebase.h" +#include "pmcolor.h" +#include "pmvector.h" + +/** + * Class for povray fogs + */ +class PMFog : public PMTextureBase +{ + typedef PMTextureBase Base; +public: + /** + * Creates an PMFog + */ + PMFog( PMPart* part ); + /** + * Copy constructor + */ + PMFog( const PMFog& f ); + /** + * Deletes the object + */ + virtual ~PMFog( ); + + /** */ + virtual PMObject* copy( ) const { return new PMFog( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMFogEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pmfog" ); } + + /** */ + virtual void restoreMemento( PMMemento* s ); + + int fogType( ) const { return m_fogType; } + double distance( ) const { return m_distance; } + PMColor color( ) const { return m_color; } + bool isTurbulenceEnabled( ) const { return m_enableTurbulence; } + PMVector valueVector( ) const { return m_valueVector; } + int octaves( ) const { return m_octaves; } + double omega( ) const { return m_omega; } + double lambda( ) const { return m_lambda; } + double depth( ) const { return m_depth; } + double fogOffset( ) const { return m_fogOffset; } + double fogAlt( ) const { return m_fogAlt; } + PMVector up( ) const { return m_up; } + + void setFogType( int c ); + void setDistance( double c ); + void setColor( const PMColor& c ); + void enableTurbulence( bool c ); + void setValueVector( const PMVector& v ); + void setOctaves( int c ); + void setOmega( double c ); + void setLambda( double c ); + void setDepth( double c ); + void setFogOffset( double c ); + void setFogAlt( double c ); + void setUp( const PMVector& v ); + +private: + /** + * IDs for @ref PMMementoData + */ + enum PMFogMementoID { PMFogTypeID, PMDistanceID, PMColorID, + PMEnableTurbulenceID, PMValueVectorID, + PMOctavesID, PMOmegaID, PMLambdaID, + PMDepthID, PMFogOffsetID, PMFogAltID, + PMUpID }; + + int m_fogType; + double m_distance; + PMColor m_color; + bool m_enableTurbulence; + PMVector m_valueVector; + int m_octaves; + double m_omega; + double m_lambda; + double m_depth; + double m_fogOffset; + double m_fogAlt; + PMVector m_up; + + static PMMetaObject* s_pMetaObject; +}; + + +#endif diff --git a/kpovmodeler/pmfogedit.cpp b/kpovmodeler/pmfogedit.cpp new file mode 100644 index 00000000..64cb915e --- /dev/null +++ b/kpovmodeler/pmfogedit.cpp @@ -0,0 +1,240 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmfogedit.h" +#include "pmfog.h" +#include "pmlineedits.h" +#include "pmvectoredit.h" +#include "pmcoloredit.h" + +#include +#include +#include +#include +#include +#include +#include + +PMFogEdit::PMFogEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMFogEdit::createTopWidgets( ) +{ + QHBoxLayout* hl; + QVBoxLayout* vl; + QGridLayout* gl; + QLabel* lbl; + + Base::createTopWidgets( ); + + lbl = new QLabel( i18n( "Fog type:" ), this ); + m_pFogTypeEdit = new QComboBox( this ); + m_pFogTypeEdit->insertItem( i18n( "Constant" ) ); + m_pFogTypeEdit->insertItem( i18n( "Ground" ) ); + hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( lbl ); + hl->addWidget( m_pFogTypeEdit ); + hl->addStretch( 1 ); + + lbl = new QLabel( i18n( "Distance:" ), this ); + m_pDistance = new PMFloatEdit( this ); + hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( lbl ); + hl->addWidget( m_pDistance ); + hl->addStretch( 1 ); + + lbl = new QLabel( i18n( "Color:" ), this ); + m_pColor = new PMColorEdit( false, this ); + hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( lbl ); + hl->addWidget( m_pColor ); + hl->addStretch( 1 ); + + m_pTurbulenceCheck = new QCheckBox( i18n( "Turbulence" ), this ); + topLayout( )->addWidget( m_pTurbulenceCheck ); + + m_pTurbulenceWidget = new QWidget( this ); + vl = new QVBoxLayout( m_pTurbulenceWidget, 0, KDialog::spacingHint( ) ); + hl = new QHBoxLayout( vl ); + lbl = new QLabel( i18n( "Value: " ), m_pTurbulenceWidget ); + m_pTurbulenceVector = new PMVectorEdit( "x", "y", "z", m_pTurbulenceWidget); + hl->addWidget( lbl ); + hl->addWidget( m_pTurbulenceVector ); + hl->addStretch( 1 ); + hl = new QHBoxLayout( vl ); + gl = new QGridLayout( hl, 4, 2 ); + lbl = new QLabel( i18n( "Octaves:" ), m_pTurbulenceWidget ); + m_pOctaves = new PMIntEdit( m_pTurbulenceWidget ); + gl->addWidget( lbl, 0, 0 ); + gl->addWidget( m_pOctaves, 0, 1 ); + lbl = new QLabel( i18n( "Omega:" ), m_pTurbulenceWidget ); + m_pOmega = new PMFloatEdit( m_pTurbulenceWidget ); + gl->addWidget( lbl, 1, 0 ); + gl->addWidget( m_pOmega, 1, 1 ); + lbl = new QLabel( i18n( "Lambda:" ), m_pTurbulenceWidget ); + m_pLambda = new PMFloatEdit( m_pTurbulenceWidget ); + gl->addWidget( lbl, 2, 0 ); + gl->addWidget( m_pLambda, 2, 1 ); + lbl = new QLabel( i18n( "Depth:" ), m_pTurbulenceWidget ); + m_pDepth = new PMFloatEdit( m_pTurbulenceWidget ); + gl->addWidget( lbl, 3, 0 ); + gl->addWidget( m_pDepth, 3, 1 ); + hl->addStretch( 1 ); + topLayout( )->addWidget( m_pTurbulenceWidget ); + + hl = new QHBoxLayout( topLayout( ) ); + gl = new QGridLayout( hl, 2, 2 ); + m_pFogOffsetLabel = new QLabel( i18n( "Offset: " ), this ); + m_pFogOffset = new PMFloatEdit( this ); + m_pFogAltLabel = new QLabel( i18n( "Altitude: " ), this ); + m_pFogAlt = new PMFloatEdit( this ); + gl->addWidget( m_pFogOffsetLabel, 0, 0 ); + gl->addWidget( m_pFogOffset, 0, 1 ); + gl->addWidget( m_pFogAltLabel, 1, 0 ); + gl->addWidget( m_pFogAlt, 1, 1 ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + m_pUpLabel = new QLabel( i18n( "Up: " ), this ); + m_pUp = new PMVectorEdit( "x", "y", "z", this ); + hl->addWidget( m_pUpLabel ); + hl->addWidget( m_pUp ); + + connect( m_pFogTypeEdit, SIGNAL( activated( int ) ), SLOT( slotFogTypeChanged( int ) ) ); + connect( m_pDistance, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pColor, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pTurbulenceCheck, SIGNAL( clicked( ) ), SLOT( slotTurbulenceClicked( ) ) ); + connect( m_pTurbulenceVector, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pOctaves, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pOmega, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pLambda, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pDepth, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pFogOffset, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pFogAlt, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pUp, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMFogEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Fog" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMFog* ) o; + + m_pFogTypeEdit->setCurrentItem( m_pDisplayedObject->fogType( ) - 1 ); + m_pFogTypeEdit->setEnabled( !readOnly ); + m_pDistance->setValue( m_pDisplayedObject->distance( ) ); + m_pDistance->setReadOnly( readOnly ); + m_pColor->setColor( m_pDisplayedObject->color( ) ); + m_pColor->setReadOnly( readOnly ); + m_pTurbulenceCheck->setChecked( m_pDisplayedObject->isTurbulenceEnabled( ) ); + m_pTurbulenceCheck->setEnabled( !readOnly ); + m_pTurbulenceVector->setVector( m_pDisplayedObject->valueVector( ) ); + m_pTurbulenceVector->setReadOnly( readOnly ); + m_pOctaves->setValue( m_pDisplayedObject->octaves( ) ); + m_pOctaves->setReadOnly( readOnly ); + m_pOmega->setValue( m_pDisplayedObject->omega( ) ); + m_pOmega->setReadOnly( readOnly ); + m_pLambda->setValue( m_pDisplayedObject->lambda( ) ); + m_pLambda->setReadOnly( readOnly ); + m_pDepth->setValue( m_pDisplayedObject->depth( ) ); + m_pDepth->setReadOnly( readOnly ); + m_pFogOffset->setValue( m_pDisplayedObject->fogOffset( ) ); + m_pFogOffset->setReadOnly( readOnly ); + m_pFogAlt->setValue( m_pDisplayedObject->fogAlt( ) ); + m_pFogAlt->setReadOnly( readOnly ); + m_pUp->setVector( m_pDisplayedObject->up( ) ); + m_pUp->setReadOnly( readOnly ); + + slotTurbulenceClicked( ); + slotFogTypeChanged( m_pFogTypeEdit->currentItem( ) ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMFogEdit: Can't display object\n"; +} + +void PMFogEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + m_pDisplayedObject->setFogType( m_pFogTypeEdit->currentItem( ) + 1 ); + m_pDisplayedObject->setDistance( m_pDistance->value( ) ); + m_pDisplayedObject->setColor( m_pColor->color( ) ); + m_pDisplayedObject->enableTurbulence( m_pTurbulenceCheck->isChecked( ) ); + m_pDisplayedObject->setValueVector( m_pTurbulenceVector->vector( ) ); + m_pDisplayedObject->setOctaves( m_pOctaves->value( ) ); + m_pDisplayedObject->setOmega( m_pOmega->value( ) ); + m_pDisplayedObject->setLambda( m_pLambda->value( ) ); + m_pDisplayedObject->setDepth( m_pDepth->value( ) ); + m_pDisplayedObject->setFogOffset( m_pFogOffset->value( ) ); + m_pDisplayedObject->setFogAlt( m_pFogAlt->value( ) ); + m_pDisplayedObject->setUp( m_pUp->vector( ) ); + Base::saveContents( ); + } +} + +bool PMFogEdit::isDataValid( ) +{ + return Base::isDataValid( ); +} + +void PMFogEdit::slotTurbulenceClicked( ) +{ + if( m_pTurbulenceCheck->isChecked( ) ) + m_pTurbulenceWidget->show( ); + else + m_pTurbulenceWidget->hide( ); + + emit dataChanged( ); + emit sizeChanged( ); +} + +void PMFogEdit::slotFogTypeChanged( int val ) +{ + switch( val ) + { + case 0: // Constant Fog + m_pFogOffsetLabel->hide( ); + m_pFogOffset->hide( ); + m_pFogAltLabel->hide( ); + m_pFogAlt->hide( ); + m_pUpLabel->hide( ); + m_pUp->hide( ); + break; + case 1: // Ground Fog + m_pFogOffsetLabel->show( ); + m_pFogOffset->show( ); + m_pFogAltLabel->show( ); + m_pFogAlt->show( ); + m_pUpLabel->show( ); + m_pUp->show( ); + break; + default: + break; + } + + emit dataChanged( ); + emit sizeChanged( ); +} + +#include "pmfogedit.moc" diff --git a/kpovmodeler/pmfogedit.h b/kpovmodeler/pmfogedit.h new file mode 100644 index 00000000..880b578c --- /dev/null +++ b/kpovmodeler/pmfogedit.h @@ -0,0 +1,95 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMFOGEDIT_H +#define PMFOGEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebaseedit.h" + +class PMFog; +class PMVectorEdit; +class PMFloatEdit; +class PMIntEdit; +class PMColorEdit; +class QCheckBox; +class QComboBox; +class QWidget; +class QLabel; + +/** + * Dialog edit class for @ref PMFog + */ +class PMFogEdit : public PMTextureBaseEdit +{ + Q_OBJECT + typedef PMTextureBaseEdit Base; +public: + /** + * Creates a PMFogEdit with parent and name + */ + PMFogEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + /** + * Slot called whenever turbulence is activated/deactivated + */ + void slotTurbulenceClicked( ); + /** + * Slot called whenever a new fog type is selected + */ + void slotFogTypeChanged( int val ); + +private: + PMFog* m_pDisplayedObject; + + QComboBox* m_pFogTypeEdit; + PMFloatEdit* m_pDistance; + PMColorEdit* m_pColor; + QCheckBox* m_pTurbulenceCheck; + QWidget* m_pTurbulenceWidget; + PMVectorEdit* m_pTurbulenceVector; + PMIntEdit* m_pOctaves; + PMFloatEdit* m_pOmega; + PMFloatEdit* m_pLambda; + PMFloatEdit* m_pDepth; + QLabel* m_pFogOffsetLabel; + PMFloatEdit* m_pFogOffset; + QLabel* m_pFogAltLabel; + PMFloatEdit* m_pFogAlt; + QLabel* m_pUpLabel; + PMVectorEdit* m_pUp; +}; + + +#endif diff --git a/kpovmodeler/pmformulalabel.cpp b/kpovmodeler/pmformulalabel.cpp new file mode 100644 index 00000000..ac2e98d3 --- /dev/null +++ b/kpovmodeler/pmformulalabel.cpp @@ -0,0 +1,190 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmformulalabel.h" +#include "pmpolynomexponents.h" + +#include +#include +#include + +const int c_indent = 3; +const int c_dotSize = 3; + +QString PMFormulaLabel::s_xyz[3] = +{ + QString( "x" ), QString( "y" ), QString( "z" ) +}; + +QString PMFormulaLabel::s_digit[10] = +{ + QString( "0" ), + QString( "1" ), + QString( "2" ), + QString( "3" ), + QString( "4" ), + QString( "5" ), + QString( "6" ), + QString( "7" ), + QString( "8" ), + QString( "9" ) +}; + +QString PMFormulaLabel::s_nullString = QString( "= 0" ); + +PMFormulaLabel::PMFormulaLabel( const PMPolynomExponents& exp, QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + m_exponents[0] = exp.exponent( 0 ); + m_exponents[1] = exp.exponent( 1 ); + m_exponents[2] = exp.exponent( 2 ); + + calculateSizeHint( ); +} + +PMFormulaLabel::PMFormulaLabel( int x, int y, int z, QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + m_exponents[0] = x; + m_exponents[1] = y; + m_exponents[2] = z; + + calculateSizeHint( ); +} + +PMFormulaLabel::~PMFormulaLabel( ) +{ +} + +void PMFormulaLabel::drawContents( QPainter* p ) +{ + QRect cr = rect( ); + int i; + cr.setLeft( cr.left( ) + c_indent ); + + int sum = m_exponents[0] + m_exponents[1] + m_exponents[2]; + if( sum == 0 ) + p->drawText( cr, Qt::AlignVCenter | Qt::AlignLeft, s_nullString ); + else + { + // draw dot + int center = ( cr.top( ) + cr.bottom( ) ) / 2; + int rad = c_dotSize / 2; + p->setBrush( QBrush( colorGroup( ).text( ) ) ); + p->drawEllipse( cr.left( ), center - rad, c_dotSize, c_dotSize ); + cr.setLeft( cr.left( ) + c_dotSize + c_indent ); + + QFontMetrics m1( font( ) ); + QFont f2 = exponentFont( ); + QFontMetrics m2( f2 ); + int up = m1.height( ) / 2; + + for( i = 0; i < 3; i++ ) + { + + if( m_exponents[i] > 0 ) + { + p->drawText( cr, Qt::AlignVCenter | Qt::AlignLeft, s_xyz[i] ); + cr.setLeft( cr.left( ) + m1.width( s_xyz[i] ) ); + if( m_exponents[i] > 1 ) + { + cr.setBottom( cr.bottom( ) - up ); + p->setFont( f2 ); + p->drawText( cr, Qt::AlignVCenter | Qt::AlignLeft, + s_digit[m_exponents[i]] ); + cr.setLeft( cr.left( ) + m2.width( s_digit[m_exponents[i]] ) + 1 ); + cr.setBottom( cr.bottom( ) + up ); + p->setFont( font( ) ); + } + } + } + } +} + +void PMFormulaLabel::paintEvent( QPaintEvent* ev ) +{ + QPainter paint( this ); + if( ev->rect( ).intersects( rect( ) ) ) + { + paint.setClipRegion( ev->region( ).intersect( rect( ) ) ); + drawContents( &paint ); + } +} + +void PMFormulaLabel::calculateSizeHint( ) +{ + int sum = m_exponents[0] + m_exponents[1] + m_exponents[2]; + + QFontMetrics m1( font( ) ); + if( sum == 0 ) + m_sizeHint.setWidth( m1.width( s_nullString ) ); + else + { + QFontMetrics m2( exponentFont( ) ); + int width = c_indent * 3 + c_dotSize; + int i; + for( i = 0; i < 3; i++ ) + { + if( m_exponents[i] > 0 ) + { + width += m1.width( s_xyz[i] ); + if( m_exponents[i] > 1 ) + width += m2.width( s_digit[m_exponents[i]] ) + 1; + } + } + m_sizeHint.setWidth( width ); + } + m_sizeHint.setHeight( m1.height( ) + 7 ); +} + +QSize PMFormulaLabel::sizeHint( ) const +{ + return minimumSizeHint( ); +} + +QSize PMFormulaLabel::minimumSizeHint( ) const +{ + return m_sizeHint; +} + +void PMFormulaLabel::fontChange( const QFont& ) +{ + calculateSizeHint( ); +} + + +QFont PMFormulaLabel::exponentFont( ) const +{ + QFont small = font( ); + int fs = small.pointSize( ); + if( fs > 0 ) + { + fs = fs * 2 / 3; + if( fs == 0 ) + fs = 1; + small.setPointSize( fs ); + } + else + { + fs = small.pixelSize( ); + fs = fs * 2 / 3; + if( fs == 0 ) + fs = 1; + small.setPixelSize( fs ); + } + return small; +} diff --git a/kpovmodeler/pmformulalabel.h b/kpovmodeler/pmformulalabel.h new file mode 100644 index 00000000..329ba639 --- /dev/null +++ b/kpovmodeler/pmformulalabel.h @@ -0,0 +1,69 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMFORMULALABEL_H +#define PMFORMULALABEL_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +class PMPolynomExponents; + +/** + * QLabel with a rich text to display a polynom for the quadric, + * cubic, quartic and polynom objects. + */ +class PMFormulaLabel : public QWidget +{ +public: + /** + * Displays the exponents of the @ref PMPolynomExponents + */ + PMFormulaLabel( const PMPolynomExponents& exp, QWidget* parent, const char* name = 0 ); + /** + * Displays the given exponents + */ + PMFormulaLabel( int x, int y, int z, QWidget* parent, const char* name = 0 ); + /** + * Destructor + */ + ~PMFormulaLabel( ); + virtual QSize sizeHint( ) const; + virtual QSize minimumSizeHint( ) const; + +protected: + virtual void drawContents( QPainter* p ); + virtual void paintEvent( QPaintEvent* e ); + virtual void fontChange( const QFont& oldFont ); + +private: + QFont exponentFont( ) const; + void calculateSizeHint( ); + + QSize m_sizeHint; + int m_exponents[3]; + + static QString s_xyz[3]; + static QString s_digit[10]; + static QString s_nullString; +}; + +#endif diff --git a/kpovmodeler/pmglobalphotons.cpp b/kpovmodeler/pmglobalphotons.cpp new file mode 100644 index 00000000..4a24855f --- /dev/null +++ b/kpovmodeler/pmglobalphotons.cpp @@ -0,0 +1,521 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmglobalphotons.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmenumproperty.h" +#include "pmglobalphotonsedit.h" + +#include + +const double spacingDefault = 0.01; +const int countDefault = 20000; +const int gatherMinDefault = 20; +const int gatherMaxDefault = 100; +const int mediaMaxStepsDefault = 0; +const double mediaFactorDefault = 1.0; +const double jitterDefault = 0.4; +const int maxTraceLevelDefault = 0; +const double adcBailoutDefault = 0.01; +const double autostopDefault = 0.0; +const double expandIncreaseDefault = 0.2; +const int expandMinDefault = 40; +const double radiusGatherDefault = 0.0; +const double radiusGatherMultiDefault = 1.0; +const double radiusMediaDefault = 0.0; +const double radiusMediaMultiDefault = 1.0; + +PMDefinePropertyClass( PMGlobalPhotons, PMGlobalPhotonsProperty ); +PMDefineEnumPropertyClass( PMGlobalPhotons, PMGlobalPhotons::PMNumberType, PMNumberProperty ); + +PMMetaObject* PMGlobalPhotons::s_pMetaObject = 0; +PMObject* createNewGlobalPhotons( PMPart* part ) +{ + return new PMGlobalPhotons( part ); +} + +PMGlobalPhotons::PMGlobalPhotons( PMPart* part ) : Base( part ) +{ + m_numberType = Spacing; + m_spacing = spacingDefault; + m_count = countDefault; + m_gatherMin = gatherMinDefault; + m_gatherMax = gatherMaxDefault; + m_mediaMaxSteps = mediaMaxStepsDefault; + m_mediaFactor = mediaFactorDefault; + m_jitter = jitterDefault; + m_maxTraceLevelGlobal = true; + m_maxTraceLevel = maxTraceLevelDefault; + m_adcBailoutGlobal = true; + m_adcBailout = adcBailoutDefault; + m_autostop = autostopDefault; + m_expandIncrease = expandIncreaseDefault; + m_expandMin = expandMinDefault; + m_radiusGather = radiusGatherDefault; + m_radiusGatherMulti = radiusGatherMultiDefault; + m_radiusMedia = radiusMediaDefault; + m_radiusMediaMulti = radiusMediaMultiDefault; +} + +PMGlobalPhotons::PMGlobalPhotons( const PMGlobalPhotons& p ) + : Base( p ) +{ + m_numberType = p.m_numberType; + m_spacing = p.m_spacing; + m_count = p.m_count; + m_gatherMin = p.m_gatherMin; + m_gatherMax = p.m_gatherMax; + m_mediaMaxSteps = p.m_mediaMaxSteps; + m_mediaFactor = p.m_mediaFactor; + m_jitter = p.m_jitter; + m_maxTraceLevelGlobal = p.m_maxTraceLevelGlobal; + m_maxTraceLevel = p.m_maxTraceLevel; + m_adcBailoutGlobal = p.m_adcBailoutGlobal; + m_adcBailout = p.m_adcBailout; + m_autostop = p.m_autostop; + m_expandIncrease = p.m_expandIncrease; + m_expandMin = p.m_expandMin; + m_radiusGather = p.m_radiusGather; + m_radiusGatherMulti = p.m_radiusGatherMulti; + m_radiusMedia = p.m_radiusMedia; + m_radiusMediaMulti = p.m_radiusMediaMulti; +} + +PMGlobalPhotons::~PMGlobalPhotons( ) +{ +} + +PMMetaObject* PMGlobalPhotons::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "GlobalPhotons", Base::metaObject( ), + createNewGlobalPhotons ); + + PMNumberProperty* p1 = new PMNumberProperty( "numberType", + &PMGlobalPhotons::setNumberType, &PMGlobalPhotons::numberType ); + p1->addEnumValue( "Spacing", Spacing ); + p1->addEnumValue( "Count", Count ); + s_pMetaObject->addProperty( p1 ); + + s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "spacing", + &PMGlobalPhotons::setSpacing, &PMGlobalPhotons::spacing ) ); + s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "count", + &PMGlobalPhotons::setCount, &PMGlobalPhotons::count ) ); + s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "gatherMin", + &PMGlobalPhotons::setGatherMin, &PMGlobalPhotons::gatherMin ) ); + s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "gatherMax", + &PMGlobalPhotons::setGatherMax, &PMGlobalPhotons::gatherMax ) ); + s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "mediaMaxSteps", + &PMGlobalPhotons::setMediaMaxSteps, &PMGlobalPhotons::mediaMaxSteps ) ); + s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "mediaFactor", + &PMGlobalPhotons::setMediaFactor, &PMGlobalPhotons::mediaFactor ) ); + s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "jitter", + &PMGlobalPhotons::setJitter, &PMGlobalPhotons::jitter ) ); + s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "maxTraceLevelGlobal", + &PMGlobalPhotons::setMaxTraceLevelGlobal, &PMGlobalPhotons::maxTraceLevelGlobal ) ); + s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "maxTraceLevel", + &PMGlobalPhotons::setMaxTraceLevel, &PMGlobalPhotons::maxTraceLevel ) ); + s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "adcBailoutGlobal", + &PMGlobalPhotons::setAdcBailoutGlobal, &PMGlobalPhotons::adcBailoutGlobal ) ); + s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "adcBailout", + &PMGlobalPhotons::setAdcBailout, &PMGlobalPhotons::adcBailout ) ); + s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "autostop", + &PMGlobalPhotons::setAutostop, &PMGlobalPhotons::autostop ) ); + s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "expandIncrease", + &PMGlobalPhotons::setExpandIncrease, &PMGlobalPhotons::expandIncrease ) ); + s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "expandMin", + &PMGlobalPhotons::setExpandMin, &PMGlobalPhotons::expandMin ) ); + s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "radiusGather", + &PMGlobalPhotons::setRadiusGather, &PMGlobalPhotons::radiusGather ) ); + s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "radiusGatherMulti", + &PMGlobalPhotons::setRadiusGatherMulti, &PMGlobalPhotons::radiusGatherMulti ) ); + s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "radiusMedia", + &PMGlobalPhotons::setRadiusMedia, &PMGlobalPhotons::radiusMedia ) ); + s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "radiusMediaMulti", + &PMGlobalPhotons::setRadiusMediaMulti, &PMGlobalPhotons::radiusMediaMulti ) ); + } + return s_pMetaObject; +} + +void PMGlobalPhotons::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMGlobalPhotons::description( ) const +{ + return i18n( "global photons" ); +} + +void PMGlobalPhotons::serialize( QDomElement& e, QDomDocument& ) const +{ + if( m_numberType == Spacing ) + { + e.setAttribute( "number_type", "spacing" ); + e.setAttribute( "spacing", m_spacing ); + } + else + { + e.setAttribute( "number_type", "count" ); + e.setAttribute( "count", m_count ); + } + + e.setAttribute( "gather_min", m_gatherMin ); + e.setAttribute( "gather_max", m_gatherMax ); + e.setAttribute( "media_max_steps", m_mediaMaxSteps ); + e.setAttribute( "media_factor", m_mediaFactor ); + e.setAttribute( "jitter", m_jitter ); + e.setAttribute( "max_trace_level_global", m_maxTraceLevelGlobal ); + e.setAttribute( "max_trace_level", m_maxTraceLevel ); + e.setAttribute( "adc_bailout_global", m_adcBailoutGlobal ); + e.setAttribute( "adc_bailout", m_adcBailout ); + e.setAttribute( "autostop", m_autostop ); + e.setAttribute( "expand_increase", m_expandIncrease ); + e.setAttribute( "expand_min", m_expandMin ); + e.setAttribute( "radius_gather", m_radiusGather ); + e.setAttribute( "radius_gather_multi", m_radiusGatherMulti ); + e.setAttribute( "radius_media", m_radiusMedia ); + e.setAttribute( "radius_media_multi", m_radiusMediaMulti ); +} + +void PMGlobalPhotons::readAttributes( const PMXMLHelper& h ) +{ + QString str; + + str = h.stringAttribute( "number_type", "spacing" ); + if( str == "count" ) + m_numberType = Count; + else + m_numberType = Spacing; + + m_spacing = h.doubleAttribute( "spacing", spacingDefault ); + m_count = h.intAttribute( "count", countDefault ); + m_gatherMin = h.intAttribute( "gather_min", gatherMinDefault ); + m_gatherMax = h.intAttribute( "gather_max", gatherMaxDefault ); + m_mediaMaxSteps = h.intAttribute( "media_max_steps", mediaMaxStepsDefault ); + m_mediaFactor = h.doubleAttribute( "media_factor", mediaFactorDefault ); + m_jitter = h.doubleAttribute( "jitter", jitterDefault ); + m_maxTraceLevelGlobal = h.boolAttribute( "max_trace_level_global", true ); + m_maxTraceLevel = h.intAttribute( "max_trace_level", maxTraceLevelDefault ); + m_adcBailoutGlobal = h.boolAttribute( "adc_bailout_global", true ); + m_adcBailout = h.doubleAttribute( "adc_bailout", adcBailoutDefault ); + m_autostop = h.doubleAttribute( "autostop", autostopDefault ); + m_expandIncrease = h.doubleAttribute( "expand_increase", expandIncreaseDefault ); + m_expandMin = h.intAttribute( "expand_min", expandMinDefault ); + m_radiusGather = h.doubleAttribute( "radius_gather", radiusGatherDefault ); + m_radiusGatherMulti = h.doubleAttribute( "radius_gather_multi", + radiusGatherMultiDefault ); + + m_radiusMedia = h.doubleAttribute( "radius_media", radiusMediaDefault ); + m_radiusMediaMulti = h.doubleAttribute( "radius_media_multi", + radiusMediaMultiDefault ); +} + +void PMGlobalPhotons::setNumberType( PMNumberType nt ) +{ + if( nt != m_numberType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMNumberTypeID, m_numberType ); + m_numberType = nt; + } +} + +void PMGlobalPhotons::setSpacing( double s ) +{ + if( s != m_spacing ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSpacingID, m_spacing ); + m_spacing = s; + } +} + +void PMGlobalPhotons::setCount( int c ) +{ + if( c != m_count ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCountID, m_count ); + m_count = c; + } +} + +void PMGlobalPhotons::setGatherMin( int gm ) +{ + if( gm > m_gatherMax ) + { + kdError( PMArea ) << "Gather Minimum > Gather Maximum in PMGlobalPhotons::setGatherMin\n"; + gm = m_gatherMax; + } + + if( gm != m_gatherMin ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMGatherMinID, m_gatherMin ); + m_gatherMin = gm; + } +} + +void PMGlobalPhotons::setGatherMax( int gm ) +{ + if( gm < m_gatherMin ) + { + kdError( PMArea ) << "Gather Maximum < Gather Minimum in PMGlobalPhotons::setGatherMax\n"; + gm = m_gatherMin; + } + + if( gm != m_gatherMax ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMGatherMaxID, m_gatherMax ); + m_gatherMax = gm; + } +} + +void PMGlobalPhotons::setMediaMaxSteps( int mms ) +{ + if( mms != m_mediaMaxSteps ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMMediaMaxStepsID, m_mediaMaxSteps ); + m_mediaMaxSteps = mms; + } +} + +void PMGlobalPhotons::setMediaFactor( double mf ) +{ + if( mf != m_mediaFactor ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMMediaFactorID, m_mediaFactor ); + m_mediaFactor = mf; + } +} + +void PMGlobalPhotons::setJitter( double j ) +{ + if( j != m_jitter ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMJitterID, m_jitter ); + m_jitter = j; + } +} + +void PMGlobalPhotons::setMaxTraceLevelGlobal( bool mtlg ) +{ + if( mtlg != m_maxTraceLevelGlobal ) + { + if( m_pMemento ) + m_pMemento->addData( + s_pMetaObject, PMMaxTraceLevelGlobalID, m_maxTraceLevelGlobal ); + m_maxTraceLevelGlobal = mtlg; + } +} + +void PMGlobalPhotons::setMaxTraceLevel( int mtl ) +{ + if( mtl != m_maxTraceLevel ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMMaxTraceLevelID, m_maxTraceLevel ); + m_maxTraceLevel = mtl; + } +} + +void PMGlobalPhotons::setAdcBailoutGlobal( bool abg ) +{ + if( abg != m_adcBailoutGlobal ) + { + if( m_pMemento ) + m_pMemento->addData( + s_pMetaObject, PMAdcBailoutGlobalID, m_adcBailoutGlobal ); + m_adcBailoutGlobal = abg; + } +} + +void PMGlobalPhotons::setAdcBailout( double ab ) +{ + if( ab != m_adcBailout ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAdcBailoutID, m_adcBailout ); + m_adcBailout = ab; + } +} + +void PMGlobalPhotons::setAutostop( double a ) +{ + if( a != m_autostop ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAutostopID, m_autostop ); + m_autostop = a; + } +} + +void PMGlobalPhotons::setExpandIncrease( double ei ) +{ + if( ei != m_expandIncrease ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMExpandIncreaseID, m_expandIncrease ); + m_expandIncrease = ei; + } +} + +void PMGlobalPhotons::setExpandMin( int em ) +{ + if(em != m_expandMin ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMExpandMinID, m_expandMin ); + m_expandMin = em; + } +} + +void PMGlobalPhotons::setRadiusGather( double rg ) +{ + if ( rg != m_radiusGather ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRadiusGatherID, m_radiusGather ); + m_radiusGather = rg; + } +} + +void PMGlobalPhotons::setRadiusGatherMulti( double rgm ) +{ + if ( rgm != m_radiusGatherMulti ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRadiusGatherID, m_radiusGatherMulti ); + m_radiusGatherMulti = rgm; + } +} + +void PMGlobalPhotons::setRadiusMedia( double rm ) +{ + if ( rm != m_radiusMedia ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRadiusGatherID, m_radiusMedia ); + m_radiusMedia = rm; + } +} + +void PMGlobalPhotons::setRadiusMediaMulti( double rmm ) +{ + if ( rmm != m_radiusMediaMulti ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRadiusGatherID, m_radiusMediaMulti ); + m_radiusMediaMulti = rmm; + } +} + +PMDialogEditBase* PMGlobalPhotons::editWidget( QWidget* parent ) const +{ + return new PMGlobalPhotonsEdit( parent ); +} + +void PMGlobalPhotons::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMNumberTypeID: + setNumberType( ( PMNumberType ) ( data->intData( ) ) ); + break; + case PMSpacingID: + setSpacing( data->doubleData( ) ); + break; + case PMCountID: + setCount( data->intData( ) ); + break; + case PMGatherMinID: + setGatherMin( data->intData( ) ); + break; + case PMGatherMaxID: + setGatherMax( data->intData( ) ); + break; + case PMMediaMaxStepsID: + setMediaMaxSteps( data->intData( ) ); + break; + case PMMediaFactorID: + setMediaFactor( data->doubleData( ) ); + break; + case PMJitterID: + setJitter( data->doubleData( ) ); + break; + case PMMaxTraceLevelGlobalID: + setMaxTraceLevelGlobal( data->boolData( ) ); + break; + case PMMaxTraceLevelID: + setMaxTraceLevel( data->intData( ) ); + break; + case PMAdcBailoutGlobalID: + setAdcBailoutGlobal( data->boolData( ) ); + break; + case PMAdcBailoutID: + setAdcBailout( data->doubleData( ) ); + break; + case PMAutostopID: + setAutostop( data->doubleData( ) ); + break; + case PMExpandIncreaseID: + setExpandIncrease( data->doubleData( ) ); + break; + case PMExpandMinID: + setExpandMin( data->intData( ) ); + break; + case PMRadiusGatherID: + setRadiusGather( data->doubleData( ) ); + break; + case PMRadiusGatherMultiID: + setRadiusGatherMulti( data->doubleData( ) ); + break; + case PMRadiusMediaID: + setRadiusMedia( data->doubleData( ) ); + break; + case PMRadiusMediaMultiID: + setRadiusMediaMulti( data->doubleData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMRadiosity::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmglobalphotons.h b/kpovmodeler/pmglobalphotons.h new file mode 100644 index 00000000..b56cc6b1 --- /dev/null +++ b/kpovmodeler/pmglobalphotons.h @@ -0,0 +1,284 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMGLOBALPHOTONS_H +#define PMGLOBALPHOTONS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmobject.h" + +/** + * Class for GlobalPhotons settings. + */ + +class PMGlobalPhotons : public PMObject +{ + typedef PMObject Base; +public: + enum PMNumberType { Spacing=0, Count=1 }; + + /** + * Creates a PMGlobalPhotons + */ + PMGlobalPhotons( PMPart* part ); + /** + * Copy constructor + */ + PMGlobalPhotons( const PMGlobalPhotons& p ); + /** + * deletes the PMGlobalPhotons + */ + virtual ~PMGlobalPhotons( ); + + /** */ + virtual PMObject* copy( ) const { return new PMGlobalPhotons( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMGlobalPhotonsEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmglobalphotons" ); } + + /** + * Returns the number type + */ + PMNumberType numberType( ) const { return m_numberType; } + /** + * Sets the number type + */ + void setNumberType( PMNumberType nt ); + + /** + * Returns the photons spacing value + */ + double spacing( ) const { return m_spacing; } + /** + * Sets the photons spacing value + */ + void setSpacing( double s ); + + /** + * Returns the number of photons to shoot + */ + int count( ) const { return m_count; } + /** + * Sets the number of photons to shoot + */ + void setCount( int c ); + + /** + * Returns the minimum gather + */ + int gatherMin( ) const { return m_gatherMin; } + /** + * Sets the minimum gather + */ + void setGatherMin( int gm ); + + /** + * Returns the maximum gather + */ + int gatherMax( ) const { return m_gatherMax; } + /** + * Sets the maximum gather + */ + void setGatherMax( int gm ); + + /** + * Returns the media maximum steps + */ + int mediaMaxSteps( ) const { return m_mediaMaxSteps; } + /** + * Sets the media maximum steps + */ + void setMediaMaxSteps( int mms ); + + /** + * Returns the media factor + */ + double mediaFactor( ) const { return m_mediaFactor; } + /** + * Sets the media factor + */ + void setMediaFactor( double mf ); + + /** + * Returns jitter amount + */ + double jitter( ) const { return m_jitter; } + /** + * Sets the jitter amount + */ + void setJitter( double j ); + + /** + * Returns the maximum trace level global flag + */ + bool maxTraceLevelGlobal( ) const { return m_maxTraceLevelGlobal; } + /** + * Sets the maximum trace level global flag + */ + void setMaxTraceLevelGlobal( bool mtlg ); + + /** + * Returns the maximum trace level + */ + int maxTraceLevel( ) const { return m_maxTraceLevel; } + /** + * Sets the maximum trace level + */ + void setMaxTraceLevel( int mtl ); + + /** + * Returns the adc bailout global flag + */ + bool adcBailoutGlobal( ) const { return m_adcBailoutGlobal; } + /** + * Sets the adc bailout global flag + */ + void setAdcBailoutGlobal( bool abg ); + + /** + * Returns the adc bailout + */ + double adcBailout( ) const { return m_adcBailout; } + /** + * Sets the adc bailout + */ + void setAdcBailout( double ab ); + + /** + * Returns the autostop fraction + */ + double autostop( ) const { return m_autostop; } + /** + * Sets the autostop fraction + */ + void setAutostop( double a ); + + /** + * Returns the expand threshold percent increase + */ + double expandIncrease( ) const { return m_expandIncrease; } + /** + * Sets the expand threshold percent increase + */ + void setExpandIncrease( double ei ); + + /** + * Returns the expand threshold minimum + */ + int expandMin( ) const { return m_expandMin; } + /** + * Sets the expand threshold minimum + */ + void setExpandMin( int em ); + + /** + * Retuens the gather radius + */ + double radiusGather( ) const { return m_radiusGather; } + /** + * Sets the gather radius + */ + void setRadiusGather( double rg ); + + /** + * Returns the gather radius multiplier + */ + double radiusGatherMulti( ) const { return m_radiusGatherMulti; } + /** + * Sets the radius gather multiplier + */ + void setRadiusGatherMulti( double rgm ); + + /** + * Returns the media gather radius + */ + double radiusMedia( ) const { return m_radiusMedia; } + /** + * Sets the media gather radius + */ + void setRadiusMedia( double rm ); + + /** + * Returns the media gather radius multiplier + */ + double radiusMediaMulti( ) const { return m_radiusMediaMulti; } + /** + * Sets the media gather radius multiplier + */ + void setRadiusMediaMulti( double rmm ); + + /** */ + virtual void restoreMemento( PMMemento* s ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMGlobalPhotonsMementoID + { PMNumberTypeID, PMSpacingID, PMCountID, PMGatherMinID, PMGatherMaxID, + PMMediaMaxStepsID, PMMediaFactorID, PMJitterID, PMMaxTraceLevelGlobalID, + PMMaxTraceLevelID, PMAdcBailoutGlobalID, PMAdcBailoutID, PMAutostopID, + PMExpandIncreaseID, PMExpandMinID, PMRadiusGatherID, PMRadiusGatherMultiID, + PMRadiusMediaID, PMRadiusMediaMultiID }; + + PMNumberType m_numberType; + double m_spacing; + int m_count; + int m_gatherMin; + int m_gatherMax; + int m_mediaMaxSteps; + double m_mediaFactor; + double m_jitter; + bool m_maxTraceLevelGlobal; + int m_maxTraceLevel; + bool m_adcBailoutGlobal; + double m_adcBailout; + double m_autostop; + double m_expandIncrease; + int m_expandMin; + double m_radiusGather; + double m_radiusGatherMulti; + double m_radiusMedia; + double m_radiusMediaMulti; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmglobalphotonsedit.cpp b/kpovmodeler/pmglobalphotonsedit.cpp new file mode 100644 index 00000000..e241f597 --- /dev/null +++ b/kpovmodeler/pmglobalphotonsedit.cpp @@ -0,0 +1,328 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmglobalphotonsedit.h" +#include "pmglobalphotons.h" +#include "pmlineedits.h" + +#include +#include +#include +#include +#include +#include +#include + + +PMGlobalPhotonsEdit::PMGlobalPhotonsEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMGlobalPhotonsEdit::createTopWidgets( ) +{ + QHBoxLayout* hl; + QGridLayout* gl; + QLabel* lbl; + + Base::createTopWidgets( ); + + hl = new QHBoxLayout( topLayout( ) ); + lbl = new QLabel( i18n( "Photon numbers" ), this ); + m_pNumberType = new QComboBox( false, this ); + m_pNumberType->insertItem( i18n( "Spacing" ) ); + m_pNumberType->insertItem( i18n( "Count" ) ); + m_pSpacing = new PMFloatEdit( this ); + m_pSpacing->setValidation( true, 0, false, 0 ); + m_pCount = new PMIntEdit( this ); + m_pCount->setValidation( true, 0, false, 0 ); + hl->addWidget( lbl ); + hl->addWidget( m_pNumberType ); + hl->addWidget( m_pSpacing ); + hl->addWidget( m_pCount ); + hl->addStretch( 1 ); + + gl = new QGridLayout( topLayout( ), 2, 5 ); + lbl = new QLabel( i18n( "Gather" ), this ); + gl->addWidget( lbl, 0, 0 ); + lbl = new QLabel( i18n( "Min:" ), this ); + gl->addWidget( lbl, 0, 1 ); + m_pGatherMin = new PMIntEdit( this ); + m_pGatherMin->setValidation( true, 0, false, 0 ); + gl->addWidget( m_pGatherMin, 0, 2 ); + lbl = new QLabel( i18n( "Max:" ), this ); + gl->addWidget( lbl, 0, 3 ); + m_pGatherMax = new PMIntEdit( this ); + m_pGatherMax->setValidation( true, 0, false, 0 ); + gl->addWidget( m_pGatherMax, 0, 4 ); + + lbl = new QLabel( i18n( "Media" ), this ); + gl->addWidget( lbl, 1, 0 ); + lbl = new QLabel( i18n( "Max stop:" ), this ); + gl->addWidget( lbl, 1, 1 ); + m_pMediaMaxSteps = new PMIntEdit( this ); + m_pMediaMaxSteps->setValidation( true, 0, false, 0 ); + gl->addWidget( m_pMediaMaxSteps, 1, 2 ); + lbl = new QLabel( i18n( "Factor:" ), this ); + gl->addWidget( lbl,1, 3 ); + m_pMediaFactor = new PMFloatEdit( this ); + m_pMediaFactor->setValidation( true, 0, false, 0 ); + gl->addWidget( m_pMediaFactor, 1, 4 ); + + hl = new QHBoxLayout( topLayout( ) ); + lbl = new QLabel( i18n( "Jitter:" ), this ); + m_pJitter = new PMFloatEdit( this ); + m_pJitter->setValidation ( true, 0, false, 0 ); + hl->addWidget( lbl ); + hl->addWidget( m_pJitter ); + hl->addStretch( 1 ); + + gl = new QGridLayout( topLayout( ), 2, 3 ); + lbl = new QLabel( i18n( "Max trace level:" ), this ); + m_pMaxTraceLevel = new PMIntEdit ( this ); + m_pMaxTraceLevel->setValidation( true, 0, false, 0 ); + m_pMaxTraceLevelGlobal = new QCheckBox( i18n( "Use global" ), this ); + gl->addWidget( lbl, 0, 0 ); + gl->addWidget( m_pMaxTraceLevel, 0, 1 ); + gl->addWidget( m_pMaxTraceLevelGlobal, 0, 2 ); + + lbl = new QLabel( i18n( "Adc bailout:" ), this ); + m_pAdcBailout = new PMFloatEdit ( this ); + m_pAdcBailout->setValidation( true, 0, true, 1 ); + m_pAdcBailoutGlobal = new QCheckBox( i18n( "Use global" ), this ); + gl->addWidget( lbl, 1, 0 ); + gl->addWidget( m_pAdcBailout, 1, 1 ); + gl->addWidget( m_pAdcBailoutGlobal, 1, 2 ); + + hl = new QHBoxLayout( topLayout( ) ); + lbl = new QLabel( i18n( "Autostop:" ), this ); + m_pAutostop = new PMFloatEdit ( this ); + m_pAutostop->setValidation( true, 0, true, 1 ); + hl->addWidget( lbl ); + hl->addWidget( m_pAutostop ); + hl->addStretch( 1 ); + + gl = new QGridLayout( topLayout( ), 3, 5 ); + lbl = new QLabel( i18n( "Expand" ), this ); + gl->addWidget( lbl, 0, 0 ); + lbl = new QLabel( i18n( "Increase:" ), this ); + gl->addWidget( lbl, 0, 1 ); + m_pExpandIncrease = new PMFloatEdit( this ); + m_pExpandIncrease->setValidation( true, 0, true, 1 ); + gl->addWidget( m_pExpandIncrease, 0, 2 ); + lbl = new QLabel( i18n( "Minimum:" ), this ); + gl->addWidget( lbl, 0, 3 ); + m_pExpandMin = new PMIntEdit( this ); + m_pExpandMin->setValidation( true, 0, false, 0 ); + gl->addWidget( m_pExpandMin, 0, 4 ); + + lbl = new QLabel( i18n( "Gather" ), this ); + gl->addWidget( lbl, 1, 0 ); + lbl = new QLabel( i18n( "Radius:" ), this ); + gl->addWidget( lbl, 1, 1 ); + m_pRadiusGather = new PMFloatEdit( this ); + m_pRadiusGather->setValidation( true, 0, false, 0 ); + gl->addWidget( m_pRadiusGather, 1, 2 ); + lbl = new QLabel( i18n( "Multiplier:" ), this ); + gl->addWidget( lbl, 1, 3 ); + m_pRadiusGatherMulti = new PMFloatEdit( this ); + m_pRadiusGatherMulti->setValidation( true, 0, false, 0 ); + gl->addWidget( m_pRadiusGatherMulti, 1, 4 ); + + lbl = new QLabel( i18n( "Media" ), this ); + gl->addWidget( lbl, 2, 0 ); + lbl = new QLabel( i18n( "Radius:" ), this ); + gl->addWidget( lbl, 2, 1 ); + m_pRadiusMedia = new PMFloatEdit( this ); + m_pRadiusMedia->setValidation( true, 0, false, 0 ); + gl->addWidget( m_pRadiusMedia, 2, 2 ); + lbl = new QLabel( i18n( "Multiplier:" ), this ); + gl->addWidget( lbl, 2, 3 ); + m_pRadiusMediaMulti = new PMFloatEdit( this ); + m_pRadiusMediaMulti->setValidation( true, 0, false, 0 ); + gl->addWidget( m_pRadiusMediaMulti, 2, 4 ); + + connect( m_pNumberType, SIGNAL( activated( int ) ), + SLOT( slotNumberTypeActivated( int ) ) ); + connect( m_pSpacing, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pCount, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pGatherMin, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pGatherMax, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pMediaMaxSteps, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pMediaFactor, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pJitter, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pMaxTraceLevelGlobal, SIGNAL( clicked( ) ), + SLOT( slotMaxTraceLevelGlobalClicked( ) ) ); + connect( m_pMaxTraceLevel, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pAdcBailoutGlobal, SIGNAL( clicked( ) ), + SLOT( slotAdcBailoutGlobalClicked( ) ) ); + connect( m_pAdcBailout, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pAutostop, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pExpandIncrease, SIGNAL( dataChanged( ) ), SIGNAL ( dataChanged( ) ) ); + connect( m_pExpandMin, SIGNAL( dataChanged( ) ), SIGNAL ( dataChanged( ) ) ); + connect( m_pRadiusGather, SIGNAL( dataChanged( ) ), SIGNAL ( dataChanged( ) ) ); + connect( m_pRadiusGatherMulti, SIGNAL( dataChanged( ) ), SIGNAL ( dataChanged( ) ) ); + connect( m_pRadiusMedia, SIGNAL( dataChanged( ) ), SIGNAL ( dataChanged( ) ) ); + connect( m_pRadiusMediaMulti, SIGNAL( dataChanged( ) ), SIGNAL ( dataChanged( ) ) ); +} + +void PMGlobalPhotonsEdit::displayObject( PMObject* o ) +{ + if( o->isA( "GlobalPhotons" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMGlobalPhotons* ) o; + + m_pNumberType->setCurrentItem( m_pDisplayedObject->numberType( ) ); + m_pNumberType->setEnabled( !readOnly ); + m_pSpacing->setValue( m_pDisplayedObject->spacing( ) ); + m_pSpacing->setReadOnly( readOnly ); + m_pCount->setValue( m_pDisplayedObject->count( ) ); + m_pCount->setReadOnly( readOnly ); + m_pGatherMin->setValue( m_pDisplayedObject->gatherMin( ) ); + m_pGatherMin->setReadOnly( readOnly ); + m_pGatherMax->setValue( m_pDisplayedObject->gatherMax( ) ); + m_pGatherMax->setReadOnly( readOnly ); + m_pMediaMaxSteps->setValue( m_pDisplayedObject->mediaMaxSteps( ) ); + m_pMediaMaxSteps->setReadOnly( readOnly ); + m_pMediaFactor->setValue( m_pDisplayedObject->mediaFactor( ) ); + m_pMediaFactor->setReadOnly( readOnly ); + m_pJitter->setValue( m_pDisplayedObject->jitter( ) ); + m_pJitter->setReadOnly( readOnly ); + m_pMaxTraceLevelGlobal->setChecked( m_pDisplayedObject->maxTraceLevelGlobal( ) ); + m_pMaxTraceLevelGlobal->setEnabled( !readOnly ); + m_pMaxTraceLevel->setValue( m_pDisplayedObject->maxTraceLevel( ) ); + m_pMaxTraceLevel->setReadOnly( readOnly ); + m_pAdcBailoutGlobal->setChecked( m_pDisplayedObject->adcBailoutGlobal( ) ); + m_pAdcBailoutGlobal->setEnabled( !readOnly ); + m_pAdcBailout->setValue( m_pDisplayedObject->adcBailout( ) ); + m_pAdcBailout->setReadOnly( readOnly ); + m_pAutostop->setValue( m_pDisplayedObject->autostop( ) ); + m_pAutostop->setReadOnly( readOnly ); + m_pExpandIncrease->setValue( m_pDisplayedObject->expandIncrease( ) ); + m_pExpandIncrease->setReadOnly( readOnly ); + m_pExpandMin->setValue( m_pDisplayedObject->expandMin( ) ); + m_pExpandMin->setReadOnly( readOnly ); + m_pRadiusGather->setValue( m_pDisplayedObject->radiusGather( ) ); + m_pRadiusGather->setReadOnly( readOnly ); + m_pRadiusGatherMulti->setValue( m_pDisplayedObject->radiusGatherMulti( ) ); + m_pRadiusGatherMulti->setReadOnly( readOnly ); + m_pRadiusMedia->setValue( m_pDisplayedObject->radiusMedia( ) ); + m_pRadiusMedia->setReadOnly( readOnly ); + m_pRadiusMediaMulti->setValue( m_pDisplayedObject->radiusMediaMulti( ) ); + m_pRadiusMediaMulti->setReadOnly( readOnly ); + + slotNumberTypeActivated( m_pDisplayedObject->numberType( ) ); + slotMaxTraceLevelGlobalClicked( ); + slotAdcBailoutGlobalClicked( ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMGlobalPhotonsEdit: Can't display object\n"; +} + +void PMGlobalPhotonsEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setNumberType( + ( PMGlobalPhotons::PMNumberType ) m_pNumberType->currentItem( ) ); + m_pDisplayedObject->setSpacing( m_pSpacing->value( ) ); + m_pDisplayedObject->setCount( m_pCount->value( ) ); + m_pDisplayedObject->setGatherMin( m_pGatherMin->value( ) ); + m_pDisplayedObject->setGatherMax( m_pGatherMax->value( ) ); + m_pDisplayedObject->setMediaMaxSteps( m_pMediaMaxSteps->value( ) ); + m_pDisplayedObject->setMediaFactor( m_pMediaFactor->value( ) ); + m_pDisplayedObject->setJitter( m_pJitter->value( ) ); + m_pDisplayedObject->setMaxTraceLevelGlobal( + m_pMaxTraceLevelGlobal->isChecked( ) ); + m_pDisplayedObject->setMaxTraceLevel( m_pMaxTraceLevel->value( ) ); + m_pDisplayedObject->setAdcBailoutGlobal( + m_pAdcBailoutGlobal->isChecked( ) ); + m_pDisplayedObject->setAdcBailout( m_pAdcBailout->value( ) ); + m_pDisplayedObject->setAutostop( m_pAutostop->value( ) ); + m_pDisplayedObject->setExpandIncrease( m_pExpandIncrease->value( ) ); + m_pDisplayedObject->setExpandMin( m_pExpandMin->value( ) ); + m_pDisplayedObject->setRadiusGather( m_pRadiusGather->value( ) ); + m_pDisplayedObject->setRadiusGatherMulti( m_pRadiusGatherMulti->value( ) ); + m_pDisplayedObject->setRadiusMedia( m_pRadiusMedia->value( ) ); + m_pDisplayedObject->setRadiusMediaMulti( m_pRadiusMediaMulti->value( ) ); + } +} + +bool PMGlobalPhotonsEdit::isDataValid( ) +{ + if( !m_pSpacing->isDataValid( ) ) return false; + if( !m_pCount->isDataValid( ) ) return false; + if( !m_pGatherMin->isDataValid( ) ) return false; + if( !m_pGatherMax->isDataValid( ) ) return false; + if( !m_pMediaMaxSteps->isDataValid( ) ) return false; + if( !m_pMediaFactor->isDataValid( ) ) return false; + if( !m_pJitter->isDataValid( ) ) return false; + if( !m_pMaxTraceLevel->isDataValid( ) ) return false; + if( !m_pAdcBailout->isDataValid( ) ) return false; + if( !m_pAutostop->isDataValid( ) ) return false; + if( !m_pExpandIncrease->isDataValid( ) ) return false; + if( !m_pExpandMin->isDataValid( ) ) return false; + if( !m_pRadiusGather->isDataValid( ) ) return false; + if( !m_pRadiusGatherMulti->isDataValid( ) ) return false; + if( !m_pRadiusMedia->isDataValid( ) ) return false; + if( !m_pRadiusMediaMulti->isDataValid( ) ) return false; + + return Base::isDataValid( ); +} + +void PMGlobalPhotonsEdit::slotNumberTypeActivated( int index ) +{ + if( index == 0 ) + { + m_pSpacing->show( ); + m_pCount->hide( ); + } + else + { + m_pSpacing->hide( ); + m_pCount->show( ); + } + emit dataChanged( ); +} + +void PMGlobalPhotonsEdit::slotMaxTraceLevelGlobalClicked( ) +{ + if( m_pMaxTraceLevelGlobal->isChecked( ) ) + m_pMaxTraceLevel->setEnabled( false ); + else if ( m_pMaxTraceLevelGlobal->isEnabled( ) ) + m_pMaxTraceLevel->setEnabled( true ); + emit dataChanged( ); + emit sizeChanged( ); +} + +void PMGlobalPhotonsEdit::slotAdcBailoutGlobalClicked( ) +{ + if( m_pAdcBailoutGlobal->isChecked( ) ) + m_pAdcBailout->setEnabled( false ); + else if ( m_pAdcBailoutGlobal->isEnabled( ) ) + m_pAdcBailout->setEnabled( true ); + emit dataChanged( ); + emit sizeChanged( ); +} + +#include "pmglobalphotonsedit.moc" diff --git a/kpovmodeler/pmglobalphotonsedit.h b/kpovmodeler/pmglobalphotonsedit.h new file mode 100644 index 00000000..ec06f749 --- /dev/null +++ b/kpovmodeler/pmglobalphotonsedit.h @@ -0,0 +1,98 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMGLOBALPHOTONSEDIT_H +#define PMGLOBALPHOTONSEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMGlobalPhotons; +class PMFloatEdit; +class PMIntEdit; +class QComboBox; +class QCheckBox; + +/** + * Dialog edit class for @ref PMGlobalPhotons. + */ +class PMGlobalPhotonsEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMGlobalPhotonsEdit with parent and name + */ + PMGlobalPhotonsEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + /** + * Slot Called whenever NumberType is altered + */ + void slotNumberTypeActivated( int index ); + /** + * slot Called whenever MaxTraceLevelGlobal is Clicked + */ + void slotMaxTraceLevelGlobalClicked( ); + /** + * slot Called whenever AdcBailoutGlobal is Clicked + */ + void slotAdcBailoutGlobalClicked( ); + +private: + PMGlobalPhotons* m_pDisplayedObject; + + QComboBox* m_pNumberType; + PMFloatEdit* m_pSpacing; + PMIntEdit* m_pCount; + PMIntEdit* m_pGatherMin; + PMIntEdit* m_pGatherMax; + PMIntEdit* m_pMediaMaxSteps; + PMFloatEdit* m_pMediaFactor; + PMFloatEdit* m_pJitter; + QCheckBox* m_pMaxTraceLevelGlobal; + PMIntEdit* m_pMaxTraceLevel; + QCheckBox* m_pAdcBailoutGlobal; + PMFloatEdit* m_pAdcBailout; + PMFloatEdit* m_pAutostop; + PMFloatEdit* m_pExpandIncrease; + PMIntEdit* m_pExpandMin; + PMFloatEdit* m_pRadiusGather; + PMFloatEdit* m_pRadiusGatherMulti; + PMFloatEdit* m_pRadiusMedia; + PMFloatEdit* m_pRadiusMediaMulti; +}; + + +#endif diff --git a/kpovmodeler/pmglobals.h b/kpovmodeler/pmglobals.h new file mode 100644 index 00000000..0a50b2b6 --- /dev/null +++ b/kpovmodeler/pmglobals.h @@ -0,0 +1,29 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMGLOBALS_H +#define PMGLOBALS_H + +#ifdef PMEnableSimpleProfiling +#include +extern QTime PMDebugTime; +#endif + +#define PMArea 0 // no area for debug messages yet + + +#endif diff --git a/kpovmodeler/pmglobalsettings.cpp b/kpovmodeler/pmglobalsettings.cpp new file mode 100644 index 00000000..a4740378 --- /dev/null +++ b/kpovmodeler/pmglobalsettings.cpp @@ -0,0 +1,516 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmglobalsettings.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmglobalsettingsedit.h" +#include "pmenumproperty.h" + +#include + +const double adcBailoutDefault = 1.0 / 255.0; +const PMColor ambientLightDefault = PMColor( 1.0, 1.0, 1.0, 0.0, 0.0 ); +const double assumedGammaDefault = 0.0; +const bool hfGray16Default = false; +const PMColor iridWaveLengthDefault = PMColor( 0.25, 0.18, 0.14, 0.0, 0.0 ); +const int maxIntersectionsDefault = 0; // ??? +const int maxTraceLevelDefault = 0; // ??? +const int numberWavesDefault = 10; +const bool radiosityDefault = false; +const double brightnessDefault = 1.0; +const int countDefault = 35; +const double distanceMaximumDefault = 0; // ??? +const double errorBoundDefault = 1.8; +const double grayThresholdDefault = 0.0; +const double lowErrorFactorDefault = 0.5; +const double minimumReuseDefault = 0.015; +const int nearestCountDefault = 5; +const int recursionLimitDefault = 2; + +PMDefinePropertyClass( PMGlobalSettings, PMGlobalSettingsProperty ); +PMDefineEnumPropertyClass( PMGlobalSettings, PMGlobalSettings::PMNoiseType, PMNoiseProperty ); + +PMMetaObject* PMGlobalSettings::s_pMetaObject = 0; +PMObject* createNewGlobalSettings( PMPart* part ) +{ + return new PMGlobalSettings( part ); +} + +PMGlobalSettings::PMGlobalSettings( PMPart* part ) + : Base( part ) +{ + m_adcBailout = adcBailoutDefault; + m_ambientLight = ambientLightDefault; + m_assumedGamma = assumedGammaDefault; + m_hfGray16 = hfGray16Default; + m_iridWaveLength = iridWaveLengthDefault; + m_maxIntersections = maxIntersectionsDefault; + m_maxTraceLevel = maxTraceLevelDefault; + m_numberWaves = numberWavesDefault; + m_noiseGenerator = RangeCorrected; + m_radiosityEnabled = radiosityDefault; + m_brightness = brightnessDefault; + m_count = countDefault; + m_distanceMaximum = distanceMaximumDefault; + m_errorBound = errorBoundDefault; + m_grayThreshold = grayThresholdDefault; + m_lowErrorFactor = lowErrorFactorDefault; + m_minimumReuse = minimumReuseDefault; + m_nearestCount = nearestCountDefault; + m_recursionLimit = recursionLimitDefault; +} + +PMGlobalSettings::PMGlobalSettings( const PMGlobalSettings& s ) + : Base( s ) +{ + m_adcBailout = s.m_adcBailout; + m_ambientLight = s.m_ambientLight; + m_assumedGamma = s.m_assumedGamma; + m_hfGray16 = s.m_hfGray16; + m_iridWaveLength = s.m_iridWaveLength; + m_maxIntersections = s.m_maxIntersections; + m_maxTraceLevel = s.m_maxTraceLevel; + m_numberWaves = s.m_numberWaves; + m_noiseGenerator = s.m_noiseGenerator; + m_radiosityEnabled = s.m_radiosityEnabled; + m_brightness = s.m_brightness; + m_count = s.m_count; + m_distanceMaximum = s.m_distanceMaximum; + m_errorBound = s.m_errorBound; + m_grayThreshold = s.m_grayThreshold; + m_lowErrorFactor = s.m_lowErrorFactor; + m_minimumReuse = s.m_minimumReuse; + m_nearestCount = s.m_nearestCount; + m_recursionLimit = s.m_recursionLimit; +} + +PMGlobalSettings::~PMGlobalSettings( ) +{ +} + +PMMetaObject* PMGlobalSettings::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "GlobalSettings", Base::metaObject( ), + createNewGlobalSettings ); + s_pMetaObject->addProperty( + new PMGlobalSettingsProperty( "adcBailout", &PMGlobalSettings::setAdcBailout, &PMGlobalSettings::adcBailout ) ); + s_pMetaObject->addProperty( + new PMGlobalSettingsProperty( "ambientLight", &PMGlobalSettings::setAmbientLight, &PMGlobalSettings::ambientLight ) ); + s_pMetaObject->addProperty( + new PMGlobalSettingsProperty( "assumedGamma", &PMGlobalSettings::setAssumedGamma, &PMGlobalSettings::assumedGamma ) ); + s_pMetaObject->addProperty( + new PMGlobalSettingsProperty( "hfGray16", &PMGlobalSettings::setHfGray16, &PMGlobalSettings::hfGray16 ) ); + s_pMetaObject->addProperty( + new PMGlobalSettingsProperty( "iridWaveLength", &PMGlobalSettings::setIridWaveLength, &PMGlobalSettings::iridWaveLength ) ); + s_pMetaObject->addProperty( + new PMGlobalSettingsProperty( "maxIntersections", &PMGlobalSettings::setMaxIntersections, &PMGlobalSettings::maxIntersections ) ); + s_pMetaObject->addProperty( + new PMGlobalSettingsProperty( "maxTraceLevel", &PMGlobalSettings::setMaxTraceLevel, &PMGlobalSettings::maxTraceLevel ) ); + s_pMetaObject->addProperty( + new PMGlobalSettingsProperty( "numberWaves", &PMGlobalSettings::setNumberWaves, &PMGlobalSettings::numberWaves ) ); + + PMNoiseProperty* p = new PMNoiseProperty( "noiseGenerator", &PMGlobalSettings::setNoiseGenerator, + &PMGlobalSettings::noiseGenerator ); + p->addEnumValue( "Original", Original ); + p->addEnumValue( "RangeCorrected", RangeCorrected ); + p->addEnumValue( "Perlin", Perlin ); + s_pMetaObject->addProperty( p ); + + s_pMetaObject->addProperty( + new PMGlobalSettingsProperty( "radiosity", &PMGlobalSettings::enableRadiosity, &PMGlobalSettings::isRadiosityEnabled ) ); + s_pMetaObject->addProperty( + new PMGlobalSettingsProperty( "brightness", &PMGlobalSettings::setBrightness, &PMGlobalSettings::brightness ) ); + s_pMetaObject->addProperty( + new PMGlobalSettingsProperty( "count", &PMGlobalSettings::setCount, &PMGlobalSettings::count ) ); + s_pMetaObject->addProperty( + new PMGlobalSettingsProperty( "distanceMaximum", &PMGlobalSettings::setDistanceMaximum, &PMGlobalSettings::distanceMaximum ) ); + s_pMetaObject->addProperty( + new PMGlobalSettingsProperty( "errorBound", &PMGlobalSettings::setErrorBound, &PMGlobalSettings::errorBound ) ); + s_pMetaObject->addProperty( + new PMGlobalSettingsProperty( "grayThreshold", &PMGlobalSettings::setGrayThreshold, &PMGlobalSettings::grayThreshold ) ); + s_pMetaObject->addProperty( + new PMGlobalSettingsProperty( "lowErrorFactor", &PMGlobalSettings::setLowErrorFactor, &PMGlobalSettings::lowErrorFactor ) ); + s_pMetaObject->addProperty( + new PMGlobalSettingsProperty( "minimumReuse", &PMGlobalSettings::setMinimumReuse, &PMGlobalSettings::minimumReuse ) ); + s_pMetaObject->addProperty( + new PMGlobalSettingsProperty( "nearestCount", &PMGlobalSettings::setNearestCount, &PMGlobalSettings::nearestCount ) ); + s_pMetaObject->addProperty( + new PMGlobalSettingsProperty( "recursionLimit", &PMGlobalSettings::setRecursionLimit, &PMGlobalSettings::recursionLimit ) ); + } + return s_pMetaObject; +} + +void PMGlobalSettings::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMGlobalSettings::description( ) const +{ + return i18n( "global settings" ); +} + +void PMGlobalSettings::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "adc_bailout", m_adcBailout ); + e.setAttribute( "ambient_light", m_ambientLight.serializeXML( ) ); + e.setAttribute( "assumed_gamma", m_assumedGamma ); + e.setAttribute( "hf_gray_16", m_hfGray16 ); + e.setAttribute( "irid_wavelength", m_iridWaveLength.serializeXML( ) ); + e.setAttribute( "max_intersections", m_maxIntersections ); + e.setAttribute( "max_trace_level", m_maxTraceLevel ); + e.setAttribute( "number_of_waves", m_numberWaves ); + e.setAttribute( "radiosity", m_radiosityEnabled ); + switch ( m_noiseGenerator ) + { + case Original: + e.setAttribute( "noise_generator", "original" ); + break; + case RangeCorrected: + e.setAttribute( "noise_generator", "range_corrected" ); + break; + case Perlin: + e.setAttribute( "noise_generator", "perlin" ); + break; + } + e.setAttribute( "brightness", m_brightness ); + e.setAttribute( "count", m_count ); + e.setAttribute( "distance_maximum", m_distanceMaximum ); + e.setAttribute( "error_bound", m_errorBound ); + e.setAttribute( "gray_threshold", m_grayThreshold ); + e.setAttribute( "low_error_factor", m_lowErrorFactor ); + e.setAttribute( "minimum_reuse", m_minimumReuse ); + e.setAttribute( "nearest_count", m_nearestCount ); + e.setAttribute( "recursion_limit", m_recursionLimit ); + + Base::serialize( e, doc ); +} + +void PMGlobalSettings::readAttributes( const PMXMLHelper& h ) +{ + QString str; + + m_adcBailout = h.doubleAttribute( "adc_bailout", adcBailoutDefault ); + m_ambientLight = h.colorAttribute( "ambient_light", ambientLightDefault ); + m_assumedGamma = h.doubleAttribute( "assumed_gamma", assumedGammaDefault ); + m_hfGray16 = h.boolAttribute( "hf_gray_16", hfGray16Default ); + m_iridWaveLength = h.colorAttribute( "irid_wavelength", iridWaveLengthDefault ); + m_maxIntersections = h.intAttribute( "max_intersections", maxIntersectionsDefault ); + m_maxTraceLevel = h.intAttribute( "max_trace_level", maxTraceLevelDefault ); + m_numberWaves = h.intAttribute( "number_of_waves", numberWavesDefault ); + str = h.stringAttribute( "noise_generator", "range_corrected" ); + if ( str == "original" ) + m_noiseGenerator = Original; + else if ( str == "perlin" ) + m_noiseGenerator = Perlin; + else + m_noiseGenerator = RangeCorrected; + m_radiosityEnabled = h.boolAttribute( "radiosity", radiosityDefault ); + m_brightness = h.doubleAttribute( "brightness", brightnessDefault ); + m_count = h.intAttribute( "count", countDefault ); + m_distanceMaximum = h.doubleAttribute( "distance_maximum", distanceMaximumDefault ); + m_errorBound = h.doubleAttribute( "error_bound", errorBoundDefault ); + m_grayThreshold = h.doubleAttribute( "gray_threshold", grayThresholdDefault ); + m_lowErrorFactor = h.doubleAttribute( "low_error_factor", lowErrorFactorDefault ); + m_minimumReuse = h.doubleAttribute( "minimum_reuse", minimumReuseDefault ); + m_nearestCount = h.intAttribute( "nearest_count", nearestCountDefault ); + m_recursionLimit = h.intAttribute( "recursion_limit", recursionLimitDefault ); + + Base::readAttributes( h ); +} + +void PMGlobalSettings::setAdcBailout( double c ) +{ + if( c != m_adcBailout ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAdcBailoutID, m_adcBailout ); + m_adcBailout = c; + } +} + +void PMGlobalSettings::setAmbientLight( const PMColor& c ) +{ + if( c != m_ambientLight ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAmbientLightID, m_ambientLight ); + m_ambientLight = c; + } +} + +void PMGlobalSettings::setAssumedGamma( double c ) +{ + if( c != m_assumedGamma ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAssumedGammaID, m_assumedGamma ); + m_assumedGamma = c; + } +} + +void PMGlobalSettings::setIridWaveLength( const PMColor& c ) +{ + if( c != m_iridWaveLength ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMIridWaveLengthID, m_iridWaveLength ); + m_iridWaveLength = c; + } +} + +void PMGlobalSettings::setHfGray16( bool c ) +{ + if( c != m_hfGray16 ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMHfGray16ID, m_hfGray16 ); + m_hfGray16 = c; + } +} + +void PMGlobalSettings::setMaxIntersections( int c ) +{ + if( c != m_maxIntersections ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMMaxIntersectionsID, m_maxIntersections ); + m_maxIntersections = c; + } +} + +void PMGlobalSettings::setMaxTraceLevel( int c ) +{ + if( c != m_maxTraceLevel ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMMaxTraceLevelID, m_maxTraceLevel ); + m_maxTraceLevel = c; + } +} + +void PMGlobalSettings::setNumberWaves( int c ) +{ + if( c != m_numberWaves ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMNumberWavesID, m_numberWaves ); + m_numberWaves = c; + } +} + +void PMGlobalSettings::setNoiseGenerator( PMNoiseType c ) +{ + if( c != m_noiseGenerator ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMNoiseGeneratorID, m_noiseGenerator ); + m_noiseGenerator = c; + } +} + +void PMGlobalSettings::enableRadiosity( bool c ) +{ + if( c != m_radiosityEnabled ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRadiosityEnabledID, m_radiosityEnabled ); + m_radiosityEnabled = c; + } +} + +void PMGlobalSettings::setBrightness( double c ) +{ + if( c != m_brightness ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMBrightnessID, m_brightness ); + m_brightness = c; + } +} + +void PMGlobalSettings::setCount( int c ) +{ + if( c != m_count ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCountID, m_count ); + m_count = c; + } +} + +void PMGlobalSettings::setDistanceMaximum( double c ) +{ + if( c != m_distanceMaximum ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMDistanceMaximumID, m_distanceMaximum ); + m_distanceMaximum = c; + } +} + +void PMGlobalSettings::setErrorBound( double c ) +{ + if( c != m_errorBound ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMErrorBoundID, m_errorBound ); + m_errorBound = c; + } +} + +void PMGlobalSettings::setGrayThreshold( double c ) +{ + if( c != m_grayThreshold ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMGrayThresholdID, m_grayThreshold ); + m_grayThreshold = c; + } +} + +void PMGlobalSettings::setLowErrorFactor( double c ) +{ + if( c != m_lowErrorFactor ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMLowErrorFactorID, m_lowErrorFactor ); + m_lowErrorFactor = c; + } +} + +void PMGlobalSettings::setMinimumReuse( double c ) +{ + if( c != m_minimumReuse ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMMinimumReuseID, m_minimumReuse ); + m_minimumReuse = c; + } +} + +void PMGlobalSettings::setNearestCount( int c ) +{ + if( c != m_nearestCount ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMNearestCountID, m_nearestCount ); + m_nearestCount = c; + } +} + +void PMGlobalSettings::setRecursionLimit( int c ) +{ + if( c != m_recursionLimit ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRecursionLimitID, m_recursionLimit ); + m_recursionLimit = c; + } +} + +PMDialogEditBase* PMGlobalSettings::editWidget( QWidget* parent ) const +{ + return new PMGlobalSettingsEdit( parent ); +} + +void PMGlobalSettings::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMAdcBailoutID: + setAdcBailout( data->doubleData( ) ); + break; + case PMAmbientLightID: + setAmbientLight( data->colorData( ) ); + break; + case PMAssumedGammaID: + setAssumedGamma( data->doubleData( ) ); + break; + case PMHfGray16ID: + setHfGray16( data->boolData( ) ); + break; + case PMIridWaveLengthID: + setIridWaveLength( data->colorData( ) ); + break; + case PMMaxIntersectionsID: + setMaxIntersections( data->intData( ) ); + break; + case PMMaxTraceLevelID: + setMaxTraceLevel( data->intData( ) ); + break; + case PMNumberWavesID: + setNumberWaves( data->intData( ) ); + break; + case PMNoiseGeneratorID: + setNoiseGenerator( ( PMNoiseType ) ( data->intData( ) ) ); + break; + case PMRadiosityEnabledID: + enableRadiosity( data->boolData( ) ); + break; + case PMBrightnessID: + setBrightness( data->doubleData( ) ); + break; + case PMCountID: + setCount( data->intData( ) ); + break; + case PMDistanceMaximumID: + setDistanceMaximum( data->doubleData( ) ); + break; + case PMErrorBoundID: + setErrorBound( data->doubleData( ) ); + break; + case PMGrayThresholdID: + setGrayThreshold( data->doubleData( ) ); + break; + case PMLowErrorFactorID: + setLowErrorFactor( data->doubleData( ) ); + break; + case PMMinimumReuseID: + setMinimumReuse( data->doubleData( ) ); + break; + case PMNearestCountID: + setNearestCount( data->intData( ) ); + break; + case PMRecursionLimitID: + setRecursionLimit( data->intData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMGlobalSettings::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmglobalsettings.h b/kpovmodeler/pmglobalsettings.h new file mode 100644 index 00000000..e552293e --- /dev/null +++ b/kpovmodeler/pmglobalsettings.h @@ -0,0 +1,268 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMGLOBALSETTINGS_H +#define PMGLOBALSETTINGS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmcompositeobject.h" +#include "pmcolor.h" + +/** + * Class for global settings. + */ + +class PMGlobalSettings : public PMCompositeObject +{ + typedef PMCompositeObject Base; +public: + enum PMNoiseType { Original = 0, RangeCorrected = 1, Perlin = 2 }; + + /** + * Creates a PMGlobalSettings + */ + PMGlobalSettings( PMPart* part ); + /** + * Copy constructor + */ + PMGlobalSettings( const PMGlobalSettings& s ); + /** + * deletes the PMGlobalSettings + */ + virtual ~PMGlobalSettings( ); + + /** */ + virtual PMObject* copy( ) const { return new PMGlobalSettings( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMGlobalSettingsEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmglobalsettings" ); } + + /** + * Returns the adc bailout + */ + double adcBailout( ) const { return m_adcBailout; } + /** + * Sets the adc bailout + */ + void setAdcBailout( double c ); + /** + * Returns the ambient color + */ + PMColor ambientLight( ) const { return m_ambientLight; } + /** + * Sets the ambient color + */ + void setAmbientLight( const PMColor& c ); + /** + * Returns the assumed gamma + */ + double assumedGamma( ) const { return m_assumedGamma; } + /** + * Sets the assumed gamma + */ + void setAssumedGamma( double c ); + /** + * Returns the hf gray 16 + */ + bool hfGray16( ) const { return m_hfGray16; } + /** + * Sets the hf gray 16 + */ + void setHfGray16( bool c ); + /** + * Returns the iridiscence wavelength + */ + PMColor iridWaveLength( ) const { return m_iridWaveLength; } + /** + * Sets the iridiscence wavelength + */ + void setIridWaveLength( const PMColor& c ); + /** + * Returns the maximum number of intersections + */ + int maxIntersections( ) const { return m_maxIntersections; } + /** + * Sets the maximum number of intersections + */ + void setMaxIntersections( int c ); + /** + * Returns the maximum trace level + */ + int maxTraceLevel( ) const { return m_maxTraceLevel; } + /** + * Sets the maximum trace level + */ + void setMaxTraceLevel( int c ); + /** + * Returns the number of waves + */ + int numberWaves( ) const { return m_numberWaves; } + /** + * Sets the number of waves + */ + void setNumberWaves( int c ); + /** + * Returns the current noise generator + */ + PMNoiseType noiseGenerator( ) const { return m_noiseGenerator; } + /** + * Sets the noise generator + */ + void setNoiseGenerator( PMNoiseType c ); + /** + * Returns true if radiosity is enabled + */ + bool isRadiosityEnabled( ) const { return m_radiosityEnabled; } + /** + * Enables/Disables radiosity + */ + void enableRadiosity( bool c ); + /** + * Returns brightness + */ + double brightness( ) const { return m_brightness; } + /** + * Sets the brightness + */ + void setBrightness( double c ); + /** + * Returns count + */ + int count( ) const { return m_count; } + /** + * Sets the count + */ + void setCount( int c ); + /** + * Returns maximum distance + */ + double distanceMaximum( ) const { return m_distanceMaximum; } + /** + * Sets the maximum distance + */ + void setDistanceMaximum( double c ); + /** + * Returns error boundary + */ + double errorBound( ) const { return m_errorBound; } + /** + * Sets the error boundary + */ + void setErrorBound( double c ); + /** + * Returns gray threshold + */ + double grayThreshold( ) const { return m_grayThreshold; } + /** + * Sets the gray threshold + */ + void setGrayThreshold( double c ); + /** + * Returns low error factor + */ + double lowErrorFactor( ) const { return m_lowErrorFactor; } + /** + * Sets the low error factor + */ + void setLowErrorFactor( double c ); + /** + * Returns minimum reuse + */ + double minimumReuse( ) const { return m_minimumReuse; } + /** + * Sets the minimum reuse + */ + void setMinimumReuse( double c ); + /** + * Returns nearest count + */ + int nearestCount( ) const { return m_nearestCount; } + /** + * Sets the nearest count + */ + void setNearestCount( int c ); + /** + * Returns recursion limit + */ + int recursionLimit( ) const { return m_recursionLimit; } + /** + * Sets the recursion limit + */ + void setRecursionLimit( int c ); + + /** */ + virtual void restoreMemento( PMMemento* s ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMGlobalSettingsMementoID { PMAdcBailoutID, PMAmbientLightID, PMAssumedGammaID, + PMHfGray16ID, PMIridWaveLengthID, PMMaxIntersectionsID, + PMMaxTraceLevelID, PMNumberWavesID, PMNoiseGeneratorID, + PMRadiosityEnabledID, PMBrightnessID, PMCountID, + PMDistanceMaximumID, PMErrorBoundID, PMGrayThresholdID, + PMLowErrorFactorID, PMMinimumReuseID, PMNearestCountID, + PMRecursionLimitID }; + + double m_adcBailout; + PMColor m_ambientLight; + double m_assumedGamma; + bool m_hfGray16; + PMColor m_iridWaveLength; + int m_maxIntersections; + int m_maxTraceLevel; + int m_numberWaves; + PMNoiseType m_noiseGenerator; + bool m_radiosityEnabled; + double m_brightness; + int m_count; + double m_distanceMaximum; + double m_errorBound; + double m_grayThreshold; + double m_lowErrorFactor; + double m_minimumReuse; + int m_nearestCount; + int m_recursionLimit; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmglobalsettingsedit.cpp b/kpovmodeler/pmglobalsettingsedit.cpp new file mode 100644 index 00000000..8a297738 --- /dev/null +++ b/kpovmodeler/pmglobalsettingsedit.cpp @@ -0,0 +1,317 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmglobalsettingsedit.h" +#include "pmglobalsettings.h" +#include "pmlineedits.h" +#include "pmcoloredit.h" + +#include +#include +#include +#include +#include +#include +#include + +PMGlobalSettingsEdit::PMGlobalSettingsEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMGlobalSettingsEdit::createTopWidgets( ) +{ + QHBoxLayout* hl; + QLabel* lbl; + + Base::createTopWidgets( ); + + hl = new QHBoxLayout( topLayout( ) ); + lbl = new QLabel( i18n( "Adc bailout:" ), this ); + m_pAdcBailoutEdit = new PMFloatEdit( this ); + hl->addWidget( lbl ); + hl->addWidget( m_pAdcBailoutEdit ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + lbl = new QLabel( i18n( "Ambient light:" ), this ); + m_pAmbientLightEdit = new PMColorEdit( false, this ); + topLayout( )->addWidget( lbl ); + topLayout( )->addWidget( m_pAmbientLightEdit ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + lbl = new QLabel( i18n( "Assumed gamma:" ), this ); + m_pAssumedGammaEdit = new PMFloatEdit( this ); + hl->addWidget( lbl ); + hl->addWidget( m_pAssumedGammaEdit ); + hl->addStretch( 1 ); + + m_pHfGray16Edit = new QCheckBox( i18n( "Hf gray 16" ), this ); + topLayout( )->addWidget( m_pHfGray16Edit ); + + hl = new QHBoxLayout( topLayout( ) ); + lbl = new QLabel( i18n( "Iridiscence wave length:" ), this ); + m_pIridWaveLengthEdit = new PMColorEdit( false, this ); + topLayout( )->addWidget( lbl ); + topLayout( )->addWidget( m_pIridWaveLengthEdit ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + QGridLayout* layout = new QGridLayout( hl, 4, 2 ); + lbl = new QLabel( i18n( "Maximum intersections:" ), this ); + m_pMaxIntersectionsEdit = new PMIntEdit( this ); + layout->addWidget( lbl, 0, 0 ); + layout->addWidget( m_pMaxIntersectionsEdit, 0, 1 ); + lbl = new QLabel( i18n( "Maximum trace level:" ), this ); + m_pMaxTraceLevelEdit = new PMIntEdit( this ); + layout->addWidget( lbl, 1, 0 ); + layout->addWidget( m_pMaxTraceLevelEdit, 1, 1 ); + lbl = new QLabel( i18n( "Number of waves:" ), this ); + m_pNumberWavesEdit = new PMIntEdit( this ); + layout->addWidget( lbl, 2, 0 ); + layout->addWidget( m_pNumberWavesEdit, 2, 1 ); + lbl = new QLabel( i18n( "Noise generator:" ), this ); + m_pNoiseGeneratorEdit = new QComboBox( false, this ); + m_pNoiseGeneratorEdit->insertItem( i18n( "Original" ) ); + m_pNoiseGeneratorEdit->insertItem( i18n( "Range Corrected" ) ); + m_pNoiseGeneratorEdit->insertItem( i18n( "Perlin" ) ); + layout->addWidget( lbl, 3, 0 ); + layout->addWidget( m_pNoiseGeneratorEdit, 3, 1 ); + hl->addStretch( 1 ); + + m_pRadiosityEdit = new QCheckBox( i18n( "Radiosity (Povray 3.1)" ), this ); + topLayout( )->addWidget( m_pRadiosityEdit ); + + m_pRadiosityWidget = new QWidget( this ); + hl = new QHBoxLayout( m_pRadiosityWidget, 0, KDialog::spacingHint( ) ); + layout = new QGridLayout( hl, 7, 2 ); + lbl = new QLabel( i18n( "Brightness:" ), m_pRadiosityWidget ); + m_pBrightnessEdit = new PMFloatEdit( m_pRadiosityWidget ); + layout->addWidget( lbl, 0, 0 ); + layout->addWidget( m_pBrightnessEdit, 0, 1 ); + lbl = new QLabel( i18n( "Count:" ), m_pRadiosityWidget ); + m_pCountEdit = new PMIntEdit( m_pRadiosityWidget ); + layout->addWidget( lbl, 1, 0 ); + layout->addWidget( m_pCountEdit, 1, 1 ); + lbl = new QLabel( i18n( "Maximum distance:" ), m_pRadiosityWidget ); + m_pDistanceMaximumEdit = new PMFloatEdit( m_pRadiosityWidget ); + layout->addWidget( lbl, 2, 0 ); + layout->addWidget( m_pDistanceMaximumEdit, 2, 1 ); + lbl = new QLabel( i18n( "Error boundary:" ), m_pRadiosityWidget ); + m_pErrorBoundEdit = new PMFloatEdit( m_pRadiosityWidget ); + layout->addWidget( lbl, 3, 0 ); + layout->addWidget( m_pErrorBoundEdit, 3, 1 ); + lbl = new QLabel( i18n( "Gray threshold:" ), m_pRadiosityWidget ); + m_pGrayThresholdEdit = new PMFloatEdit( m_pRadiosityWidget ); + layout->addWidget( lbl, 4, 0 ); + layout->addWidget( m_pGrayThresholdEdit, 4, 1 ); + lbl = new QLabel( i18n( "Low error factor:" ), m_pRadiosityWidget ); + m_pLowErrorFactorEdit = new PMFloatEdit( m_pRadiosityWidget ); + layout->addWidget( lbl, 5, 0 ); + layout->addWidget( m_pLowErrorFactorEdit, 5, 1 ); + lbl = new QLabel( i18n( "Minimum reuse:" ), m_pRadiosityWidget ); + m_pMinimumReuseEdit = new PMFloatEdit( m_pRadiosityWidget ); + layout->addWidget( lbl, 6, 0 ); + layout->addWidget( m_pMinimumReuseEdit, 6, 1 ); + lbl = new QLabel( i18n( "Nearest count:" ), m_pRadiosityWidget ); + m_pNearestCountEdit = new PMIntEdit( m_pRadiosityWidget ); + layout->addWidget( lbl, 7, 0 ); + layout->addWidget( m_pNearestCountEdit, 7, 1 ); + lbl = new QLabel( i18n( "Recursion limit:" ), m_pRadiosityWidget ); + m_pRecursionLimitEdit = new PMIntEdit( m_pRadiosityWidget ); + layout->addWidget( lbl, 8, 0 ); + layout->addWidget( m_pRecursionLimitEdit, 8, 1 ); + hl->addStretch( 1 ); + + topLayout( )->addWidget( m_pRadiosityWidget ); + + connect( m_pAdcBailoutEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pAmbientLightEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pAssumedGammaEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pHfGray16Edit, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pIridWaveLengthEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pMaxIntersectionsEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pMaxTraceLevelEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pNumberWavesEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pNoiseGeneratorEdit, SIGNAL( activated( int ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pRadiosityEdit, SIGNAL( clicked( ) ), SLOT( slotRadiosityClicked( ) ) ); + connect( m_pBrightnessEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pCountEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pDistanceMaximumEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pErrorBoundEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pGrayThresholdEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pLowErrorFactorEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pMinimumReuseEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pNearestCountEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pRecursionLimitEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMGlobalSettingsEdit::displayObject( PMObject* o ) +{ + if( o->isA( "GlobalSettings" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMGlobalSettings* ) o; + + m_pAdcBailoutEdit->setValue( m_pDisplayedObject->adcBailout( ) ); + m_pAdcBailoutEdit->setReadOnly( readOnly ); + m_pAmbientLightEdit->setColor( m_pDisplayedObject->ambientLight( ) ); + m_pAmbientLightEdit->setReadOnly( readOnly ); + m_pAssumedGammaEdit->setValue( m_pDisplayedObject->assumedGamma( ) ); + m_pAssumedGammaEdit->setReadOnly( readOnly ); + m_pHfGray16Edit->setChecked( m_pDisplayedObject->hfGray16( ) ); + m_pHfGray16Edit->setEnabled( !readOnly ); + m_pIridWaveLengthEdit->setColor( m_pDisplayedObject->iridWaveLength( ) ); + m_pIridWaveLengthEdit->setReadOnly( readOnly ); + m_pMaxIntersectionsEdit->setValue( m_pDisplayedObject->maxIntersections( ) ); + m_pMaxIntersectionsEdit->setReadOnly( readOnly ); + m_pMaxTraceLevelEdit->setValue( m_pDisplayedObject->maxTraceLevel( ) ); + m_pMaxTraceLevelEdit->setReadOnly( readOnly ); + m_pNumberWavesEdit->setValue( m_pDisplayedObject->numberWaves( ) ); + m_pNumberWavesEdit->setReadOnly( readOnly ); + m_pNoiseGeneratorEdit->setCurrentItem( m_pDisplayedObject->noiseGenerator( ) ); + m_pNoiseGeneratorEdit->setEnabled( !readOnly ); + m_pRadiosityEdit->setChecked( m_pDisplayedObject->isRadiosityEnabled( ) ); + m_pRadiosityEdit->setEnabled( !readOnly ); + m_pBrightnessEdit->setValue( m_pDisplayedObject->brightness( ) ); + m_pBrightnessEdit->setReadOnly( readOnly ); + m_pCountEdit->setValue( m_pDisplayedObject->count( ) ); + m_pCountEdit->setReadOnly( readOnly ); + m_pDistanceMaximumEdit->setValue( m_pDisplayedObject->distanceMaximum( ) ); + m_pDistanceMaximumEdit->setReadOnly( readOnly ); + m_pErrorBoundEdit->setValue( m_pDisplayedObject->errorBound( ) ); + m_pErrorBoundEdit->setReadOnly( readOnly ); + m_pGrayThresholdEdit->setValue( m_pDisplayedObject->grayThreshold( ) ); + m_pGrayThresholdEdit->setReadOnly( readOnly ); + m_pLowErrorFactorEdit->setValue( m_pDisplayedObject->lowErrorFactor( ) ); + m_pLowErrorFactorEdit->setReadOnly( readOnly ); + m_pMinimumReuseEdit->setValue( m_pDisplayedObject->minimumReuse( ) ); + m_pMinimumReuseEdit->setReadOnly( readOnly ); + m_pNearestCountEdit->setValue( m_pDisplayedObject->nearestCount( ) ); + m_pNearestCountEdit->setReadOnly( readOnly ); + m_pRecursionLimitEdit->setValue( m_pDisplayedObject->recursionLimit( ) ); + m_pRecursionLimitEdit->setReadOnly( readOnly ); + slotRadiosityClicked( ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMGlobalSettingsEdit: Can't display object\n"; +} + +void PMGlobalSettingsEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setAdcBailout( m_pAdcBailoutEdit->value( ) ); + m_pDisplayedObject->setAmbientLight( m_pAmbientLightEdit->color( ) ); + m_pDisplayedObject->setAssumedGamma( m_pAssumedGammaEdit->value( ) ); + m_pDisplayedObject->setHfGray16( m_pHfGray16Edit->isChecked( ) ); + m_pDisplayedObject->setIridWaveLength( m_pIridWaveLengthEdit->color( ) ); + m_pDisplayedObject->setMaxIntersections( m_pMaxIntersectionsEdit->value( ) ); + m_pDisplayedObject->setMaxTraceLevel( m_pMaxTraceLevelEdit->value( ) ); + m_pDisplayedObject->setNumberWaves( m_pNumberWavesEdit->value( ) ); + m_pDisplayedObject->setNoiseGenerator( + ( PMGlobalSettings::PMNoiseType ) ( m_pNoiseGeneratorEdit->currentItem( ) ) ); + m_pDisplayedObject->enableRadiosity( m_pRadiosityEdit->isChecked( ) ); + m_pDisplayedObject->setBrightness( m_pBrightnessEdit->value( ) ); + m_pDisplayedObject->setCount( m_pCountEdit->value( ) ); + m_pDisplayedObject->setDistanceMaximum( m_pDistanceMaximumEdit->value( ) ); + m_pDisplayedObject->setErrorBound( m_pErrorBoundEdit->value( ) ); + m_pDisplayedObject->setGrayThreshold( m_pGrayThresholdEdit->value( ) ); + m_pDisplayedObject->setLowErrorFactor( m_pLowErrorFactorEdit->value( ) ); + m_pDisplayedObject->setMinimumReuse( m_pMinimumReuseEdit->value( ) ); + m_pDisplayedObject->setNearestCount( m_pNearestCountEdit->value( ) ); + m_pDisplayedObject->setRecursionLimit( m_pRecursionLimitEdit->value( ) ); + } +} + +bool PMGlobalSettingsEdit::isDataValid( ) +{ + if( !m_pAdcBailoutEdit->isDataValid( ) ) return false; + if( !m_pAmbientLightEdit->isDataValid( ) ) return false; + if( !m_pAssumedGammaEdit->isDataValid( ) ) return false; + if( !m_pIridWaveLengthEdit->isDataValid( ) ) return false; + if( !m_pMaxIntersectionsEdit->isDataValid( ) ) return false; + if( !m_pMaxTraceLevelEdit->isDataValid( ) ) return false; + if( !m_pNumberWavesEdit->isDataValid( ) ) return false; + if( !m_pBrightnessEdit->isDataValid( ) ) return false; + if( !m_pCountEdit->isDataValid( ) ) return false; + if( !m_pDistanceMaximumEdit->isDataValid( ) ) return false; + if( !m_pErrorBoundEdit->isDataValid( ) ) return false; + if( !m_pGrayThresholdEdit->isDataValid( ) ) return false; + if( !m_pLowErrorFactorEdit->isDataValid( ) ) return false; + if( !m_pMinimumReuseEdit->isDataValid( ) ) return false; + if( !m_pNearestCountEdit->isDataValid( ) ) return false; + if( !m_pRecursionLimitEdit->isDataValid( ) ) return false; + + if( m_pMaxIntersectionsEdit->value( ) < 0 ) + { + KMessageBox::error( this, i18n( "Maximum intersections must be a positive value." ), + i18n( "Error" ) ); + m_pMaxIntersectionsEdit->setFocus( ); + return false; + } + if( m_pMaxTraceLevelEdit->value( ) < 0 ) + { + KMessageBox::error( this, i18n( "Maximum trace level must be a positive value." ), + i18n( "Error" ) ); + m_pMaxTraceLevelEdit->setFocus( ); + return false; + } + if( m_pNumberWavesEdit->value( ) < 0 ) + { + KMessageBox::error( this, i18n( "Number of waves must be a positive value." ), + i18n( "Error" ) ); + m_pNumberWavesEdit->setFocus( ); + return false; + } + if( m_pNearestCountEdit->value( ) < 1 || m_pNearestCountEdit->value( ) > 10 ) + { + KMessageBox::error( this, i18n( "Nearest count must be between 1 and 10." ), + i18n( "Error" ) ); + m_pNearestCountEdit->setFocus( ); + return false; + } + + if( m_pRecursionLimitEdit->value( ) < 1 || m_pRecursionLimitEdit->value( ) > 2 ) + { + KMessageBox::error( this, i18n( "Recursion limit must be 1 or 2." ), + i18n( "Error" ) ); + m_pRecursionLimitEdit->setFocus( ); + return false; + } + + return Base::isDataValid( ); +} + +void PMGlobalSettingsEdit::slotRadiosityClicked( ) +{ + if( m_pRadiosityEdit->isChecked( ) ) + m_pRadiosityWidget->show( ); + else + m_pRadiosityWidget->hide( ); + + emit dataChanged( ); + emit sizeChanged( ); +} + +#include "pmglobalsettingsedit.moc" diff --git a/kpovmodeler/pmglobalsettingsedit.h b/kpovmodeler/pmglobalsettingsedit.h new file mode 100644 index 00000000..2a439617 --- /dev/null +++ b/kpovmodeler/pmglobalsettingsedit.h @@ -0,0 +1,93 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMGLOBALSETTINGSEDIT_H +#define PMGLOBALSETTINGSEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMGlobalSettings; +class PMColorEdit; +class PMFloatEdit; +class PMIntEdit; +class QCheckBox; +class QComboBox; + +/** + * Dialog edit class for @ref PMGlobalSettings. + */ +class PMGlobalSettingsEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMGlobalSettingsEdit with parent and name + */ + PMGlobalSettingsEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); + +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + /** + * Slot called whenever Radiosity is toggled + */ + void slotRadiosityClicked( ); + +private: + PMGlobalSettings* m_pDisplayedObject; + + PMFloatEdit* m_pAdcBailoutEdit; + PMColorEdit* m_pAmbientLightEdit; + PMFloatEdit* m_pAssumedGammaEdit; + QCheckBox* m_pHfGray16Edit; + PMColorEdit* m_pIridWaveLengthEdit; + PMIntEdit* m_pMaxIntersectionsEdit; + PMIntEdit* m_pMaxTraceLevelEdit; + PMIntEdit* m_pNumberWavesEdit; + QComboBox* m_pNoiseGeneratorEdit; + QCheckBox* m_pRadiosityEdit; + QWidget* m_pRadiosityWidget; + PMFloatEdit* m_pBrightnessEdit; + PMIntEdit* m_pCountEdit; + PMFloatEdit* m_pDistanceMaximumEdit; + PMFloatEdit* m_pErrorBoundEdit; + PMFloatEdit* m_pGrayThresholdEdit; + PMFloatEdit* m_pLowErrorFactorEdit; + PMFloatEdit* m_pMinimumReuseEdit; + PMIntEdit* m_pNearestCountEdit; + PMIntEdit* m_pRecursionLimitEdit; +}; + + +#endif diff --git a/kpovmodeler/pmglview.cpp b/kpovmodeler/pmglview.cpp new file mode 100644 index 00000000..43102de9 --- /dev/null +++ b/kpovmodeler/pmglview.cpp @@ -0,0 +1,1853 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmglview.h" +#include "pmpart.h" +#include "pmrendermanager.h" +#include "pmcamera.h" +#include "pmscene.h" +#include "pmdatachangecommand.h" +#include "pmdebug.h" +#include "pmdefaults.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +const double c_sizeFactor = log( 2.0 ) / 100.0; +const int c_mouseChangeDelayPixel = 3; +const int c_mouseChangeDelayMs = 300; +const int c_multipleSelectDelayPixel = 3; +const double c_defaultAutoScrollSpeed = 200; // pixels per second +const int c_minAutoScrollUpdateTime = 30; //ms + +const double keyMoveSpeed = 40.0; +const double keyScaleFactor = 1.4; + +static int glxAttributeList[] = { GLX_LEVEL, 0, + GLX_DOUBLEBUFFER, + GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + //GLX_ALPHA_SIZE, 1, + GLX_DEPTH_SIZE, 1, + None }; + +class PMGLViewStatic +{ +public: + PMGLViewStatic( ) + { + m_colormap = 0; + m_context = NULL; + m_colormapAllocated = false; + m_display = 0; + m_visualInfo = 0; + } + ~PMGLViewStatic( ) + { + if( m_colormapAllocated ) + XFreeColormap( m_display, m_colormap ); + if( m_context != NULL ) + glXDestroyContext( m_display, m_context ); + if( m_visualInfo ) + XFree( m_visualInfo ); + } + + Colormap m_colormap; + GLXContext m_context; + bool m_colormapAllocated; + Display* m_display; + XVisualInfo* m_visualInfo; +}; + +static PMGLViewStatic* s_pSharedData = 0; +static KStaticDeleter s_staticDeleter; +bool PMGLView::s_bDirect = true; + + +PMGLView::PMGLView( PMPart* part, PMViewType t, + QWidget* parent, const char* name, WFlags f ) + : PMViewBase( parent, name, f | Qt::WWinOwnDC | Qt::WRepaintNoErase ) +{ + m_pPart = part; + m_type = t; + m_bScaleMode = false; + m_scaleIntX = 0.0; + m_scaleIntY = 0.0; + m_bTranslateMode = false; + m_bGraphicalChangeMode = false; + m_bMousePressed = false; + m_bMidMousePressed = false; + m_dTransX = 0.0; + m_dTransY = 0.0; + m_dScale = 30.0; + m_bInverseValid = false; + m_pActiveObject = part->activeObject( ); + m_bMementoCreated = false; + m_bSelectUnderMouse = false; + m_bDeselectUnderMouse = false; + m_bMultipleSelectionMode = false; + m_bSelectionStarted = false; + m_bAutoScroll = false; + m_autoScrollSpeed = c_defaultAutoScrollSpeed; + m_bAboutToUpdate = false; + m_projectionUpToDate = false; + m_contextClickPosition = PMVector( 0.0, 0.0 ); + m_objectActions.setAutoDelete( true ); + + m_controlPointsPosition.setAutoDelete( true ); + m_pUnderMouse = 0; + + setCamera( m_pPart->firstCamera( ) ); + + initializeGL( ); + + setMouseTracking( true ); + setFocusPolicy( WheelFocus ); + + PMRenderManager* rm = PMRenderManager::theManager( ); + rm->viewCreated( ); + + setMinimumSize( 50, 50 ); + + connect( part, SIGNAL( refresh( ) ), SLOT( slotRefresh( ) ) ); + connect( part, SIGNAL( clear( ) ), SLOT( slotClear( ) ) ); + + connect( this, SIGNAL( objectChanged( PMObject*, const int, QObject* ) ), + part, SLOT( slotObjectChanged( PMObject*, const int, QObject* ) ) ); + connect( part, SIGNAL( objectChanged( PMObject*, const int, QObject* ) ), + SLOT( slotObjectChanged( PMObject*, const int, QObject* ) ) ); + + connect( part, SIGNAL( activeRenderModeChanged( ) ), + SLOT( slotActiveRenderModeChanged( ) ) ); + + connect( &m_startTimer, SIGNAL( timeout( ) ), + SLOT( slotMouseChangeTimer( ) ) ); + connect( &m_autoScrollTimer, SIGNAL( timeout( ) ), + SLOT( slotAutoScroll( ) ) ); + + connect( rm, SIGNAL( renderingStarted( PMGLView* ) ), + SLOT( slotRenderingStarted( PMGLView* ) ) ); + connect( rm, SIGNAL( aboutToUpdate( PMGLView* ) ), + SLOT( slotAboutToUpdate( PMGLView* ) ) ); + connect( rm, SIGNAL( renderingFinished( PMGLView* ) ), + SLOT( slotRenderingFinished( PMGLView* ) ) ); + connect( rm, SIGNAL( renderingSettingsChanged( ) ), + SLOT( slotRefresh( ) ) ); + + connect( this, SIGNAL( controlPointMessage( const QString& ) ), + m_pPart, SIGNAL( controlPointMessage( const QString& ) ) ); + + updateControlPoints( ); +} + +void PMGLView::initializeGL( ) +{ + Display* display = x11Display( ); + int screen = x11Screen( ); + int i; + + if( !s_pSharedData ) + { + s_staticDeleter.setObject( s_pSharedData, new PMGLViewStatic ); + s_pSharedData->m_display = display; + + if( PMRenderManager::hasOpenGL( ) ) + { + // get an appropriate visual + XVisualInfo* vi = glXChooseVisual( display, screen, glxAttributeList ); + s_pSharedData->m_visualInfo = vi; + + if( vi ) + { + kdDebug( PMArea ) << "PMGLView: XVisual found\n"; + + // create a color map (from qgl_x11.cpp) + // check if we can use the global colormap + // should be the default ? + if( vi->visualid == + XVisualIDFromVisual( ( Visual* ) QPaintDevice::x11AppVisual( ) ) ) + { + kdDebug( PMArea ) << "PMGLView: Default colormap used\n"; + s_pSharedData->m_colormap = QPaintDevice::x11AppColormap(); + s_pSharedData->m_colormapAllocated = false; + } + + if( !s_pSharedData->m_colormap ) + { + const char* v = glXQueryServerString( display, vi->screen, + GLX_VERSION ); + bool mesa_gl = false; + if( v ) + mesa_gl = strstr( v, "Mesa" ) != 0; + if( mesa_gl ) + { + XStandardColormap* c; + int n; + Atom hp_cmaps = XInternAtom( display, "_HP_RGB_SMOOTH_MAP_LIST", + TRUE ); + + if( hp_cmaps && ( vi->visual->c_class == TrueColor ) + && ( vi->depth == 8 ) ) + { + if( XGetRGBColormaps( display, RootWindow( display,vi->screen ), + &c, &n, hp_cmaps ) ) + { + i = 0; + while( ( i < n ) && ( s_pSharedData->m_colormap == 0 ) ) + { + if( c[i].visualid == vi->visual->visualid ) + { + s_pSharedData->m_colormap = c[i].colormap; + kdDebug( PMArea ) << "PMGLView: HP_RGB scmap used\n"; + } + i++; + } + XFree( ( char* ) c ); + } + } + } + } + +#if !defined(Q_OS_SOLARIS) + if( !s_pSharedData->m_colormap ) + { + XStandardColormap* c; + int n; + + if( XmuLookupStandardColormap( display, vi->screen, vi->visualid, + vi->depth, XA_RGB_DEFAULT_MAP, + FALSE, TRUE ) ) + { + if( XGetRGBColormaps( display, RootWindow( display, vi->screen ), + &c, &n, XA_RGB_DEFAULT_MAP ) ) + { + i = 0; + while( ( i < n ) && ( s_pSharedData->m_colormap == 0 ) ) + { + if( c[i].visualid == vi->visualid ) + { + s_pSharedData->m_colormap = c[i].colormap; + kdDebug( PMArea ) << "PMGLView: RGB_DEFAULT scmap used\n"; + } + i++; + } + XFree( ( char* ) c ); + } + } + } +#endif + + if( !s_pSharedData->m_colormap ) + { + // create a new colormap otherwise + kdDebug( PMArea ) << "PMGLView: New colormap created\n"; + s_pSharedData->m_colormap = + XCreateColormap( display, + RootWindow( display, vi->screen ), + vi->visual, AllocNone ); + s_pSharedData->m_colormapAllocated = true; + } + + // create the context + // this context is shared between all gl views! + s_pSharedData->m_context = glXCreateContext( display, vi, 0, s_bDirect ); + + if( s_pSharedData->m_context != NULL ) + kdDebug( PMArea ) << "PMGLView: glx context created\n"; + + } + } + } + + if( s_pSharedData->m_context != NULL ) + { + XVisualInfo* vi = s_pSharedData->m_visualInfo; + + // create the window + XSetWindowAttributes swa; + swa.colormap = s_pSharedData->m_colormap; + swa.border_pixel = 0; + swa.background_pixel = 0; + + Window p; + p = RootWindow( display, vi->screen ); + QWidget* pw = parentWidget( ); + if( pw ) + p = pw->winId( ); + + Window w = XCreateWindow( display, p, x( ), y( ), width( ), + height( ), 0, vi->depth, InputOutput, + vi->visual, + CWColormap | CWBorderPixel | CWBackPixel, + &swa ); + + // tell the windowmanager to use the colormap + Window* colorMapWindows = 0; + Window* newWindows = 0; + int num; + if( XGetWMColormapWindows( display, topLevelWidget( )->winId( ), + &colorMapWindows, &num ) ) + { + // create a new list and append the new window + bool replaced = false; + newWindows = new Window[num+1]; + + for( i = 0; i < num; i++ ) + { + newWindows[i] = colorMapWindows[i]; + if( newWindows[i] == winId( ) ) // old window + { + newWindows[i] = w; + replaced = true; + } + } + if( !replaced ) + { + newWindows[num] = w; + num++; + } + } + else + { + num = 1; + newWindows = new Window[1]; + newWindows[0] = w; + } + // tell Qt to use this window + create( w ); + + XSetWMColormapWindows( display, topLevelWidget( )->winId( ), + newWindows, num ); + delete[] newWindows; + + XFlush( x11Display( ) ); + } + else + { + QVBoxLayout* topLayout = new QVBoxLayout( this ); + QLabel* label = new QLabel( i18n( "No OpenGL support" ), this ); + label->setAlignment( Qt::AlignCenter ); + topLayout->addWidget( label ); + } + + //setProjection( ); +} + +PMGLView::~PMGLView( ) +{ + PMRenderManager* rm = PMRenderManager::theManager( ); + rm->removeView( this ); + rm->viewDeleted( ); + emit destroyed( this ); +} + +bool PMGLView::isValid( ) const +{ + if( s_pSharedData && ( s_pSharedData->m_context != NULL ) ) + return true; + return false; +} + +void PMGLView::makeCurrent( ) +{ + if( isValid( ) ) + glXMakeCurrent( x11Display( ), winId( ), s_pSharedData->m_context ); +} + +void PMGLView::swapBuffers( ) +{ + if( isValid( ) ) + glXSwapBuffers( x11Display( ), winId( ) ); +} + +void PMGLView::setScale( double scale ) +{ + if( m_dScale > 0 ) + { + m_dScale = scale; + invalidateProjection( ); + } + else + kdError( PMArea ) << "Scale <= 0 in PMGLView::setScale\n"; +} + +void PMGLView::setTranslationX( double d ) +{ + m_dTransX = d; + invalidateProjection( ); +} + +void PMGLView::setTranslationY( double d ) +{ + m_dTransY = d; + invalidateProjection( ); +} + +void PMGLView::resizeEvent( QResizeEvent* ) +{ + invalidateProjection( ); +} + +void PMGLView::paintEvent( QPaintEvent* ) +{ + repaint( ); +} + +void PMGLView::invalidateProjection( bool graphicalChange /*= true*/ ) +{ + m_viewTransformation = PMMatrix::identity( ); + + + if( m_type != PMViewCamera ) + { + m_viewTransformation = m_viewTransformation * PMMatrix::scale( m_dScale, m_dScale, m_dScale ); + m_viewTransformation = m_viewTransformation * PMMatrix::translation( m_dTransX, m_dTransY, 0 ); + + switch( m_type ) + { + case PMViewPosZ: + m_normal = PMVector( 0.0, 0.0, 1.0 ); + break; + case PMViewNegZ: + m_viewTransformation = m_viewTransformation * PMMatrix::rotation( 0.0, M_PI, 0.0 ); + m_normal = PMVector( 0.0, 0.0, -1.0 ); + break; + case PMViewNegY: + m_viewTransformation = m_viewTransformation * PMMatrix::rotation( M_PI_2, 0.0, 0.0 ); + m_normal = PMVector( 0.0, -1.0, 0.0 ); + break; + case PMViewPosY: + m_normal = PMVector( 0.0, 1.0, 0.0 ); + m_viewTransformation = m_viewTransformation * PMMatrix::rotation( -M_PI_2, 0.0, 0.0 ); + break; + case PMViewPosX: + m_viewTransformation = m_viewTransformation * PMMatrix::rotation( 0.0, M_PI_2, 0.0 ); + m_normal = PMVector( 1.0, 0.0, 0.0 ); + break; + case PMViewNegX: + m_viewTransformation = m_viewTransformation * PMMatrix::rotation( 0.0, -M_PI_2, 0.0 ); + m_normal = PMVector( -1.0, 0.0, 0.0 ); + break; + default: + break; + } + + m_viewTransformation = m_viewTransformation * PMMatrix::scale( 1.0, 1.0, -1.0 ); + + if( m_controlPoints.count( ) > 0 ) + recalculateTransformations( ); + recalculateControlPointPosition( ); + } + m_projectionUpToDate = false; + repaint( graphicalChange ); +} + +void PMGLView::enableTranslateMode( bool yes ) +{ + if( m_type != PMViewCamera ) + { + m_bScaleMode = false; + m_bTranslateMode = yes; + setCursor( yes ? crossCursor : arrowCursor ); + } +} + +void PMGLView::enableScaleMode( bool yes ) +{ + if( m_type != PMViewCamera ) + { + m_bScaleMode = yes; + m_bTranslateMode = false; + setCursor( yes ? crossCursor : arrowCursor ); + } +} + +void PMGLView::mousePressEvent( QMouseEvent* e ) +{ + if( m_bScaleMode || m_bTranslateMode ) + { + if( ( e->button( ) & LeftButton ) && ( e->state( ) == 0 ) ) + { + m_bMousePressed = true; + m_mousePos = e->pos( ); + m_scaleIntX = screenToInternalX( e->x( ) ); + m_scaleIntY = screenToInternalY( e->y( ) ); + } + } + else if( m_type != PMViewCamera ) + { + if( ( e->button( ) & LeftButton ) && m_bInverseValid + && m_pActiveObject ) + { + if( m_pUnderMouse ) + { + // check the control point selection + if( m_pActiveObject->multipleSelectControlPoints( ) ) + { + if( m_pUnderMouse->selected( ) ) + { + if( e->state( ) & ControlButton ) + m_bDeselectUnderMouse = true; + else + m_bSelectUnderMouse = true; + } + else + { + if( e->state( ) & ControlButton ) + selectControlPoint( m_pUnderMouse, + !m_pUnderMouse->selected( ), false ); + else + selectControlPoint( m_pUnderMouse, true ); + } + } + else + selectControlPoint( m_pUnderMouse, true ); + + // start the graphical change + if( !m_bGraphicalChangeMode ) + { + m_bGraphicalChangeMode = true; + m_bMementoCreated = false; + m_changeStartPos = e->pos( ); + m_changeStartTime = QTime::currentTime( ); + m_currentMousePos = m_changeStartPos; + m_startTimer.start( c_mouseChangeDelayMs, true ); + } + } + else + { + if( m_pActiveObject->multipleSelectControlPoints( ) ) + { + // multiple selection mode + // start only when the view is rendered + if( !PMRenderManager::theManager( )->containsTask( this ) ) + { + m_bMultipleSelectionMode = true; + m_bSelectionStarted = false; + m_selectionStart = e->pos( ); + m_selectionEnd = m_selectionStart; + } + } + else + selectControlPoint( 0, false ); + } + } + } + + + if( !( m_bGraphicalChangeMode || m_bMousePressed ) ) + { + if( ( e->button( ) == RightButton ) && ( e->state( ) == 0 ) ) + { + m_contextClickPosition = PMVector( screenToInternalX( e->x( ) ), + screenToInternalY( e->y( ) ) ); + + if( m_pUnderMouse ) + { + // check the control point selection + if( m_pActiveObject->multipleSelectControlPoints( ) ) + { + if( !m_pUnderMouse->selected( ) ) + selectControlPoint( m_pUnderMouse, true ); + } + else + selectControlPoint( m_pUnderMouse, true ); + } + + contextMenu( ); + } + } + + if( e->button( ) == MidButton ) + { + m_bMidMousePressed = true; + m_mousePos = e->pos( ); + } +} + +void PMGLView::mouseReleaseEvent( QMouseEvent* e ) +{ + m_bMousePressed = false; + if( m_bGraphicalChangeMode ) + { + m_startTimer.stop( ); + + if( m_bMementoCreated ) + { + PMDataChangeCommand* cmd; + cmd = new PMDataChangeCommand( m_pActiveObject->takeMemento( ) ); + m_pPart->executeCommand( cmd ); + + checkUnderMouse( ( int ) screenToInternalX( e->x( ) ), + ( int ) screenToInternalY( e->y( ) ) ); + } + else + { + if( m_pUnderMouse ) + { + if( m_bSelectUnderMouse ) + selectControlPoint( m_pUnderMouse, true ); + else if( m_bDeselectUnderMouse ) + selectControlPoint( m_pUnderMouse, false, false ); + } + } + m_bGraphicalChangeMode = false; + } + else if( m_bMultipleSelectionMode ) + { + if( m_bSelectionStarted ) + { + int sx, sy, ex, ey, w, h; + double isx, isy, iex, iey; + QPtrListIterator pit( m_controlPointsPosition ); + PMControlPointListIterator cit( m_controlPoints ); + PMVector p; + + calculateSelectionBox( sx, sy, ex, ey, w, h ); + isx = screenToInternalX( sx ); + iex = screenToInternalX( ex ); + isy = screenToInternalY( ey ); + iey = screenToInternalY( sy ); + restoreSelectionBox( ); + + while( pit.current( ) && cit.current( ) ) + { + p = *( pit.current( ) ); + + if( ( isx <= p[0] ) && ( iex >= p[0] ) + && ( isy <= p[1] ) && ( iey >= p[1] ) ) + selectControlPoint( cit.current( ), true, false ); + else if( !( e->state( ) & ControlButton ) ) + selectControlPoint( cit.current( ), false, false ); + + ++cit; + ++pit; + } + } + else + selectControlPoint( 0, false ); + + m_bMultipleSelectionMode = false; + } + + if( m_bAutoScroll ) + { + m_bAutoScroll = false; + m_autoScrollTimer.stop( ); + } + + if( e->button( ) & QEvent::MidButton ) + m_bMidMousePressed = false; + + m_bSelectUnderMouse = false; + m_bDeselectUnderMouse = false; +} + +void PMGLView::mouseMoveEvent( QMouseEvent* e ) +{ + if( m_bMousePressed ) + { + if( m_bScaleMode ) + { + int d = e->x( ) - m_mousePos.x( ); + if( d != 0 ) + { + double s = exp( d * c_sizeFactor ); + double c = 1.0 / ( m_dScale * s ) - 1.0 / m_dScale; + m_dTransX += m_scaleIntX * c; + m_dTransY += m_scaleIntY * c; + m_dScale *= s; + invalidateProjection( ); + } + } + else if( m_bTranslateMode ) + { + m_dTransX += ( e->x( ) - m_mousePos.x( ) ) / m_dScale; + m_dTransY -= ( e->y( ) - m_mousePos.y( ) ) / m_dScale; + invalidateProjection( ); + } + m_mousePos = e->pos( ); + } + else if( m_bMidMousePressed ) + { + m_dTransX += ( e->x( ) - m_mousePos.x( ) ) / m_dScale; + m_dTransY -= ( e->y( ) - m_mousePos.y( ) ) / m_dScale; + invalidateProjection( ); + + m_mousePos = e->pos( ); + } + else if( m_bGraphicalChangeMode ) + { + m_currentMousePos = e->pos( ); + if( !m_bMementoCreated ) + { + QPoint movement = e->pos( ) - m_changeStartPos; + if( ( m_changeStartTime.msecsTo( QTime::currentTime( ) ) > c_mouseChangeDelayMs ) + || ( movement.manhattanLength( ) > c_mouseChangeDelayPixel ) ) + { + m_startTimer.stop( ); + startChange( m_changeStartPos ); + } + } + + if( m_bMementoCreated ) + graphicalChange( e->pos( ) ); + } + else if( m_bMultipleSelectionMode ) + { + if( !m_bSelectionStarted ) + { + m_selectionEnd = e->pos( ); + startSelection( ); + } + else + { + restoreSelectionBox( ); + m_selectionEnd = e->pos( ); + saveSelectionBox( ); + paintSelectionBox( ); + } + } + else if( !( m_bScaleMode || m_bTranslateMode ) ) + { + checkUnderMouse( ( int ) screenToInternalX( e->x( ) ), + ( int ) screenToInternalY( e->y( ) ) ); + } + + if( m_bMultipleSelectionMode || m_bGraphicalChangeMode ) + { + bool as = m_bAutoScroll; + + if( e->x( ) < 0 ) + m_autoScrollDirectionX = 1; + else if( e->x( ) >= width( ) ) + m_autoScrollDirectionX = -1; + else + m_autoScrollDirectionX = 0; + + if( e->y( ) < 0 ) + m_autoScrollDirectionY = 1; + else if( e->y( ) >= height( ) ) + m_autoScrollDirectionY = -1; + else + m_autoScrollDirectionY = 0; + + if( ( m_autoScrollDirectionX != 0 ) || ( m_autoScrollDirectionY != 0 ) ) + m_bAutoScroll = true; + else + m_bAutoScroll = false; + + if( m_bAutoScroll && !as ) + { + m_lastAutoScrollUpdate = QTime::currentTime( ); + m_autoScrollTimer.start( c_minAutoScrollUpdateTime, true ); + } + if( !m_bAutoScroll && as ) + m_autoScrollTimer.stop( ); + } +} + +void PMGLView::wheelEvent( QWheelEvent* e ) +{ + if( m_type != PMViewCamera ) + { + double s = exp( e->delta( ) / 4 * c_sizeFactor ); + double deltaX = screenToInternalX( e->x( ) ); + double deltaY = screenToInternalY( e->y( ) ); + double c = 1.0 / ( m_dScale * s ) - 1.0 / m_dScale; + m_dTransX += deltaX * c; + m_dTransY += deltaY * c; + m_dScale *= s; + invalidateProjection( ); + } +} + +void PMGLView::keyPressEvent( QKeyEvent* e ) +{ + bool accept = true; + + if( e->state( ) == 0 ) + { + if( m_type != PMViewCamera ) + { + if( m_dScale > 0 ) + { + switch( e->key( ) ) + { + case Key_Left: + m_dTransX -= keyMoveSpeed / m_dScale; + break; + case Key_Right: + m_dTransX += keyMoveSpeed / m_dScale; + break; + case Key_Up: + m_dTransY += keyMoveSpeed / m_dScale; + break; + case Key_Down: + m_dTransY -= keyMoveSpeed / m_dScale; + break; + default: + accept = false; + } + } + else + kdError( PMArea ) << "scale <= 0 in PMGLView::keyPressEvent\n"; + } + } + else if( e->state( ) == ControlButton ) + { + if( m_type != PMViewCamera ) + { + switch( e->key( ) ) + { + case Key_Left: + case Key_Down: + m_dScale /= keyScaleFactor; + break; + case Key_Right: + case Key_Up: + m_dScale *= keyScaleFactor; + break; + default: + accept = false; + } + } + } + else + accept = false; + + if( accept ) + invalidateProjection( ); + else + e->ignore( ); +} + +void PMGLView::slotAutoScroll( ) +{ + if( m_bAutoScroll ) + { + QTime now = QTime::currentTime( ); + int msecs = m_lastAutoScrollUpdate.msecsTo( now ); + int pixels = ( int ) ( m_autoScrollSpeed * msecs / 1000.0 ); + + if( pixels < 1 ) + pixels = 1; + if( pixels > ( width( ) * 3 / 4 ) ) + pixels = width( ) * 3 / 4; + if( pixels > ( height( ) * 3 / 4 ) ) + pixels = height( ) * 3 / 4; + + if( m_bGraphicalChangeMode && !m_bMementoCreated ) + startChange( m_changeStartPos ); + if( m_bMultipleSelectionMode ) + restoreSelectionBox( ); + + m_dTransX += pixels * m_autoScrollDirectionX / m_dScale; + m_dTransY -= pixels * m_autoScrollDirectionY / m_dScale; + invalidateProjection( ); + + if( m_bGraphicalChangeMode ) + if( m_bMultipleSelectionMode ) + { + m_selectionStart += QPoint( pixels * m_autoScrollDirectionX, + pixels * m_autoScrollDirectionY ); + + saveSelectionBox( ); + paintSelectionBox( ); + } + + if( m_bGraphicalChangeMode ) + graphicalChange( mapFromGlobal( QCursor::pos( ) ) ); + else + repaint( ); + + m_lastAutoScrollUpdate = now; + } +} + +void PMGLView::slotMouseChangeTimer( ) +{ + if( !m_bMementoCreated ) + { + if( m_currentMousePos != m_changeStartPos ) + { + startChange( m_changeStartPos ); + graphicalChange( m_currentMousePos ); + } + } +} + +void PMGLView::startChange( const QPoint& mousePos ) +{ + m_pActiveObject->createMemento( ); + m_bMementoCreated = true; + + PMVector p = mousePosition( m_pUnderMouse, mousePos.x( ), mousePos.y( ) ); + p.transform( m_inversePointsTransformation ); + + if( m_pActiveObject->multipleSelectControlPoints( ) ) + { + PMControlPointListIterator it( m_controlPoints ); + for( ; it.current( ); ++it ) + if( it.current( )->selected( ) ) + it.current( )->startChange( p, m_normal ); + } + else + m_pUnderMouse->startChange( p, m_normal ); +} + +void PMGLView::graphicalChange( const QPoint& mousePos ) +{ + PMVector p = mousePosition( m_pUnderMouse, mousePos.x( ), mousePos.y( ) ); + p.transform( m_inversePointsTransformation ); + if( m_pActiveObject->multipleSelectControlPoints( ) ) + { + PMControlPointListIterator it( m_controlPoints ); + for( ; it.current( ); ++it ) + if( it.current( )->selected( ) ) + it.current( )->change( p ); + } + else + m_pUnderMouse->change( p ); + + PMObjectList changedObjects; + m_pActiveObject->controlPointsChangedList( m_controlPoints, changedObjects ); + + if( changedObjects.isEmpty( ) ) + emit objectChanged( m_pActiveObject, PMCGraphicalChange, this ); + else + { + PMObjectListIterator it( changedObjects ); + for( ; it.current( ); ++it ) + emit objectChanged( it.current( ), PMCGraphicalChange, this ); + } +} + +void PMGLView::checkUnderMouse( int x, int y ) +{ + // is cursor over a control point? + // double z; + PMVector* v; + PMControlPoint* p; + PMControlPoint* old = m_pUnderMouse; + + if( m_bInverseValid && ( m_type != PMViewCamera ) ) + { + m_pUnderMouse = 0; +// z = -1e10; + + v = m_controlPointsPosition.first( ); + p = m_controlPoints.first( ); + + while( p ) + { + if( p->displayType( ) == PMControlPoint::CPCross ) + { + if( !m_pUnderMouse ) + m_pUnderMouse = p; + } + else + { + if( ( fabs( x - (*v)[0] ) < ( controlPointSize / 2.0 + 0.1 ) ) + && ( fabs( y - (*v)[1] ) < ( controlPointSize / 2.0 + 0.1 ) ) ) + { + if( m_pUnderMouse ) + { + if( p->selected( ) && !m_pUnderMouse->selected( ) ) + m_pUnderMouse = p; + } + else + m_pUnderMouse = p; + } + } + + p = m_controlPoints.next( ); + v = m_controlPointsPosition.next( ); + } + } + else + m_pUnderMouse = 0; + + setCursor( m_pUnderMouse ? crossCursor : arrowCursor ); + if( m_pUnderMouse != old ) + { + if( m_pUnderMouse ) + emit controlPointMessage( m_pUnderMouse->description( ) ); + else + emit controlPointMessage( "" ); + } +} + +void PMGLView::updateControlPoints( ) +{ + m_controlPoints.clear( ); + m_controlPoints = m_pPart->activeControlPoints( ); + + if( ( m_controlPoints.count( ) > 0 ) && m_pActiveObject ) + { + m_objectsTransformation = m_pActiveObject->transformedWith( ); + recalculateTransformations( ); + } + + if( m_bGraphicalChangeMode ) + m_bGraphicalChangeMode = false; + + recalculateControlPointPosition( ); +} + +void PMGLView::recalculateControlPointPosition( ) +{ + PMControlPointListIterator it( m_controlPoints ); + m_controlPointsPosition.clear( ); + PMVector* v; + + for( ; it.current( ); ++it ) + { + v = new PMVector( m_controlPointsTransformation * it.current( )->position( ) ); + m_controlPointsPosition.append( v ); + } + if( !m_bGraphicalChangeMode ) + { + m_pUnderMouse = 0; + emit controlPointMessage( "" ); + } +} + +PMVector PMGLView::mousePosition( PMControlPoint* cp, int x, int y ) +{ + PMVector result; + int index; + PMVector* p; + + result[0] = screenToInternalX( x ); + result[1] = screenToInternalY( y ); + if( cp ) + { + index = m_controlPoints.findRef( cp ); + if( index >= 0 ) + { + p = m_controlPointsPosition.at( ( uint ) index ); + if( p ) + result[2] = p->z( ); + } + } + return result; +} + +void PMGLView::recalculateTransformations( ) +{ + int r, c; + + m_controlPointsTransformation = m_viewTransformation * m_objectsTransformation; + + if( m_controlPointsTransformation.canBuildInverse( ) ) + { + m_inversePointsTransformation = m_controlPointsTransformation.inverse( ); + + for( c = 0; c < 4; c++ ) + for( r = 0; r < 4; r++ ) + if( fabs( m_inversePointsTransformation[c][r] ) < 1e-8 ) + m_inversePointsTransformation[c][r] = 0.0; + + m_bInverseValid = true; + } + else + m_bInverseValid = false; +} + +void PMGLView::setType( PMViewType t ) +{ + if( m_type != t ) + m_viewTransformation = PMMatrix::identity( ); + m_type = t; + invalidateProjection( ); + + emit viewTypeChanged( viewTypeAsString( t ) ); +} + +void PMGLView::setCamera( PMCamera* c ) +{ + m_pCamera = c; + invalidateProjection( ); +} + +void PMGLView::slotRefresh( ) +{ + if( m_type == PMViewCamera ) + if( !m_pCamera ) + setCamera( m_pPart->firstCamera( ) ); + + repaint( ); +} + +void PMGLView::slotClear( ) +{ + m_controlPointsPosition.clear( ); + m_controlPoints.clear( ); + m_pUnderMouse = 0; + m_pCamera = 0; + m_pActiveObject = 0; + + slotStopRendering( ); +} + +void PMGLView::slotActiveRenderModeChanged( ) +{ + if( ( m_type == PMViewCamera ) && m_pCamera ) + invalidateProjection( ); +} + +void PMGLView::slotStopRendering( ) +{ + PMRenderManager* rm = PMRenderManager::theManager( ); + rm->removeView( this ); +} + +void PMGLView::slotObjectChanged( PMObject* obj, const int mode, + QObject* sender ) +{ + bool redraw = false; + + if( mode & PMCNewSelection ) + { + if( obj ) + { + if( obj != m_pActiveObject ) + { + m_pActiveObject = obj; + redraw = true; + } + } + else + { + m_pActiveObject = 0; + redraw = true; + } + } + if( mode & ( PMCSelected | PMCDeselected ) ) + { + m_pActiveObject = 0; + redraw = true; + } + if( mode & ( PMCViewStructure | PMCGraphicalChange ) ) + { + if( m_type == PMGLView::PMViewCamera ) + { + if( obj->type( ) == "Camera" ) + if( m_pCamera == ( PMCamera* ) obj ) + invalidateProjection( ); + + if( obj->parent( ) ) + if( obj->parent( )->type( ) == "Camera" ) + if( m_pCamera == ( PMCamera* ) obj->parent( ) ) + if( obj->hasTransformationMatrix( ) ) + invalidateProjection( ); + } + + redraw = true; + } + if( mode & PMCNewControlPoints ) + { + updateControlPoints( ); + m_pActiveObject = m_pPart->activeObject( ); + redraw = true; + } + if( mode & PMCControlPointSelection ) + { + redraw = true; + } + if( mode & PMCDescription ) + { + if( m_type == PMGLView::PMViewCamera && obj && obj == m_pCamera ) + redraw = true; + } + if( mode & PMCAdd ) + { + if( m_type == PMGLView::PMViewCamera ) + { + if( obj->type( ) == "Camera" ) + if( !m_pCamera ) + setCamera( ( PMCamera* ) obj ); + if( obj->parent( ) ) + if( obj->parent( )->type( ) == "Camera" ) + if( m_pCamera == ( PMCamera* ) obj->parent( ) ) + if( obj->hasTransformationMatrix( ) ) + invalidateProjection( ); + } + redraw = true; + } + + if( mode & PMCRemove ) + { + if( obj->type( ) == "Camera" ) + if( m_pCamera == ( PMCamera* ) obj ) + setCamera( 0 ); + + if( m_type == PMGLView::PMViewCamera ) + if( obj->parent( ) ) + if( obj->parent( )->type( ) == "Camera" ) + if( m_pCamera == ( PMCamera* ) obj->parent( ) ) + if( obj->hasTransformationMatrix( ) ) + invalidateProjection( ); + + redraw = true; + } + + if( mode & PMCChildren ) + redraw = true; + + if( redraw ) + repaint( sender == this ); +} + +void PMGLView::repaint( bool graphicalChange ) +{ + if( isValid( ) ) + { + PMObject* obj = m_pActiveObject; + + if( obj ) + obj = topLevelRenderingObject( obj ); + else + { + const PMObjectList& selected = m_pPart->selectedObjects( ); + PMObjectListIterator it( selected ); + if( it.current( ) ) + obj = topLevelRenderingObject( it.current( ) ); + + if( obj && ( obj->type( ) != "Scene" ) ) + for( ++it; it.current( ) && obj; ++it ) + if( topLevelRenderingObject( it.current( ) ) != obj ) + obj = 0; + } + + if( !obj ) + obj = m_pPart->scene( ); + + if( obj ) + { + double aspectRatio = 1.0; + PMRenderMode* mode = m_pPart->scene( )->renderModes( )->current( ); + if( mode ) + if( mode->height( ) != 0 ) + aspectRatio = ( double ) mode->width( ) + / ( double ) mode->height( ); + + PMRenderManager* rm = PMRenderManager::theManager( ); + rm->addView( this, m_pActiveObject, obj, + &m_controlPoints, aspectRatio, + m_pPart->scene( )->visibilityLevel( ), graphicalChange ); + } + } +} + +PMObject* PMGLView::topLevelRenderingObject( PMObject* o ) const +{ + PMObject* obj = o; + bool stop = false; + + if( obj ) + { + do + { + if( !obj ) + stop = true; + else if( obj->isA( "Scene" ) || obj->isA( "Declare" ) ) + stop = true; + else + obj = obj->parent( ); + } + while( !stop ); + } + else + obj = m_pPart->scene( ); + + return obj; +} + +void PMGLView::selectControlPoint( PMControlPoint* cp, bool select, bool deselectOthers ) +{ + bool selectionChanged = false; + + if( cp ) + { + if( deselectOthers ) + { + PMControlPointListIterator it( m_controlPoints ); + for( ; it.current( ); ++it ) + { + bool s; + if( it.current( ) == cp ) + s = select; + else + s = false; + + if( s != it.current( )->selected( ) ) + { + selectionChanged = true; + it.current( )->setSelected( s ); + } + } + } + else + { + if( select != cp->selected( ) ) + { + selectionChanged = true; + cp->setSelected( select ); + } + } + } + else + { + PMControlPointListIterator it( m_controlPoints ); + for( ; it.current( ); ++it ) + { + if( select != it.current( )->selected( ) ) + { + selectionChanged = true; + it.current( )->setSelected( select ); + } + } + } + + if( selectionChanged ) + emit objectChanged( m_pActiveObject, PMCControlPointSelection, this ); +} + +void PMGLView::startSelection( ) +{ + if( !m_bSelectionStarted ) + { + saveSelectionBox( ); + paintSelectionBox( ); + + m_bSelectionStarted = true; + } +} + +void PMGLView::restoreSelectionBox( ) +{ + if( !m_bAboutToUpdate ) + { + int sx, sy, ex, ey, w, h; + calculateSelectionBox( sx, sy, ex, ey, w, h ); + + if( !m_selectionPixmap[0].isNull( ) ) + bitBlt( this, sx, sy, &( m_selectionPixmap[0] ), 0, 0, w, 1, CopyROP ); + if( !m_selectionPixmap[1].isNull( ) ) + bitBlt( this, sx, ey, &( m_selectionPixmap[1] ), 0, 0, w, 1, CopyROP ); + if( !m_selectionPixmap[2].isNull( ) ) + bitBlt( this, sx, sy+1, &( m_selectionPixmap[2] ), 0, 0, 1, h-2, CopyROP ); + if( !m_selectionPixmap[3].isNull( ) ) + bitBlt( this, ex, sy+1, &( m_selectionPixmap[3] ), 0, 0, 1, h-2, CopyROP ); + } +} + +void PMGLView::saveSelectionBox( ) +{ + if( !m_bAboutToUpdate ) + { + int sx, sy, ex, ey, w, h; + calculateSelectionBox( sx, sy, ex, ey, w, h ); + + m_selectionPixmap[0].resize( w, 1 ); + if( !m_selectionPixmap[0].isNull( ) ) + bitBlt( &( m_selectionPixmap[0] ), 0, 0, this, sx, sy, w, 1, CopyROP ); + m_selectionPixmap[1].resize( w, 1 ); + if( !m_selectionPixmap[1].isNull( ) ) + bitBlt( &( m_selectionPixmap[1] ), 0, 0, this, sx, ey, w, 1, CopyROP ); + + m_selectionPixmap[2].resize( 1, h-2 ); + if( !m_selectionPixmap[2].isNull( ) ) + bitBlt( &( m_selectionPixmap[2] ), 0, 0, this, sx, sy+1, 1, h-2, CopyROP ); + m_selectionPixmap[3].resize( 1, h-2 ); + if( !m_selectionPixmap[3].isNull( ) ) + bitBlt( &( m_selectionPixmap[3] ), 0, 0, this, ex, sy+1, 1, h-2, CopyROP ); + } +} + +void PMGLView::paintSelectionBox( ) +{ + if( !m_bAboutToUpdate ) + { + int sx, sy, ex, ey, w, h; + calculateSelectionBox( sx, sy, ex, ey, w, h ); + QPainter p; + p.begin( this ); + p.setPen( PMRenderManager::theManager( )->controlPointColor( 1 ) ); + p.drawRect( sx, sy, w, h ); + p.end( ); + } +} + +void PMGLView::calculateSelectionBox( int& sx, int& sy, int& ex, int& ey, + int& w, int& h ) +{ + if( m_selectionStart.x( ) < m_selectionEnd.x( ) ) + { + sx = m_selectionStart.x( ); + ex = m_selectionEnd.x( ); + } + else + { + ex = m_selectionStart.x( ); + sx = m_selectionEnd.x( ); + } + + if( m_selectionStart.y( ) < m_selectionEnd.y( ) ) + { + sy = m_selectionStart.y( ); + ey = m_selectionEnd.y( ); + } + else + { + ey = m_selectionStart.y( ); + sy = m_selectionEnd.y( ); + } + + w = ex - sx + 1; + h = ey - sy + 1; +} + +double PMGLView::screenToInternalX( int x ) const +{ + return rint( x - width( ) / 2.0 + 0.1 ); +} + +double PMGLView::screenToInternalY( int y ) const +{ + return rint( height( ) / 2.0 - y - 0.1 ); +} + +void PMGLView::slotRenderingStarted( PMGLView* ) +{ +} + +void PMGLView::slotAboutToUpdate( PMGLView* view ) +{ + if( view == this ) + m_bAboutToUpdate = true; +} + +void PMGLView::slotRenderingFinished( PMGLView* view ) +{ + if( view == this ) + { + m_bAboutToUpdate = false; + if( m_bMultipleSelectionMode ) + { + saveSelectionBox( ); + paintSelectionBox( ); + } + + if( m_bAutoScroll ) + { + QTime now = QTime::currentTime( ); + int msecs = m_lastAutoScrollUpdate.msecsTo( now ); + + if( msecs < c_minAutoScrollUpdateTime ) + m_autoScrollTimer.start( c_minAutoScrollUpdateTime - msecs, true ); + else + m_autoScrollTimer.start( 0, true ); + } + } +} + +QString PMGLView::viewTypeAsString( PMViewType t ) +{ + QString str; + + switch( t ) + { + case PMViewPosX: + str = i18n( "Left" ); + break; + case PMViewNegX: + str = i18n( "Right" ); + break; + case PMViewPosY: + str = i18n( "Bottom" ); + break; + case PMViewNegY: + str = i18n( "Top" ); + break; + case PMViewPosZ: + str = i18n( "Front" ); + break; + case PMViewNegZ: + str = i18n( "Back" ); + break; + case PMViewCamera: + str = i18n( "Camera" ); + break; + } + return str; +} + +void PMGLView::saveConfig( KConfig* /*cfg*/ ) +{ +} + +void PMGLView::restoreConfig( KConfig* /*cfg*/ ) +{ +} + +void PMGLView::contextMenu( ) +{ + QPopupMenu* m = new QPopupMenu( ); + m->insertItem( i18n( "Left View" ), this, SLOT( slotSetTypePosX( ) ) ); + m->insertItem( i18n( "Right View" ), this, SLOT( slotSetTypeNegX( ) ) ); + m->insertItem( i18n( "Top View" ), this, SLOT( slotSetTypeNegY( ) ) ); + m->insertItem( i18n( "Bottom View" ), this, SLOT( slotSetTypePosY( ) ) ); + m->insertItem( i18n( "Front View" ), this, SLOT( slotSetTypePosZ( ) ) ); + m->insertItem( i18n( "Back View" ), this, SLOT( slotSetTypeNegZ( ) ) ); + + QPopupMenu* cm = new QPopupMenu( m ); + QPtrListIterator it = m_pPart->cameras( ); + QString name; + if( !it.current( ) ) + cm->insertItem( i18n( "No Cameras" ) ); + else + { + int cnr = 0; + for( ; it.current( ); ++it, ++cnr ) + { + name = it.current( )->name( ); + if( name.isEmpty( ) ) + name = i18n( "(unnamed)" ); + cm->insertItem( name, cnr ); + } + } + connect( cm, SIGNAL( activated( int ) ), SLOT( slotCameraView( int ) ) ); + + m->insertItem( SmallIconSet( "pmcamera" ), i18n( "Camera" ), cm ); + + m->insertSeparator( ); + + m->insertItem( i18n( "Snap to Grid" ), this, SLOT( slotSnapToGrid( ) ) ); + m_objectActions.clear( ); + if( m_pActiveObject ) + { + m_pActiveObject->addObjectActions( m_controlPoints, m_objectActions ); + if( !m_objectActions.isEmpty( ) ) + { + PMObjectAction* oa = 0; + QPtrListIterator ait( m_objectActions ); + + for( ; ait.current( ); ++ait ) + { + oa = ait.current( ); + oa->setMenuID( m->insertItem( oa->description( ) ) ); + } + } + } + connect( m, SIGNAL( activated( int ) ), SLOT( slotObjectAction( int ) ) ); + + m->insertSeparator( ); + + QPopupMenu* menu = new QPopupMenu( m ); + PMControlPointListIterator pit( m_controlPoints ); + + if( !pit.current( ) ) + menu->insertItem( i18n( "No Control Points" ) ); + else + { + int cnr = 0; + for( ; pit.current( ); ++pit, ++cnr ) + menu->insertItem( pit.current( )->description( ), cnr ); + } + connect( menu, SIGNAL( activated( int ) ), SLOT( slotControlPoint( int ) ) ); + + m->insertItem( i18n( "Control Points" ), menu ); + + m->exec( QCursor::pos( ) ); + delete m; +} + +void PMGLView::slotCameraView( int id ) +{ + int i; + QPtrListIterator it = m_pPart->cameras( ); + + for( i = 0; i < id; i++ ) + ++it; + if( it.current( ) ) + { + setCamera( it.current( ) ); + setType( PMGLView::PMViewCamera ); + } +} + +void PMGLView::slotObjectAction( int id ) +{ + QPtrListIterator it( m_objectActions ); + PMObjectAction* oa = 0; + + for( ; it.current( ) && !oa; ++it ) + if( it.current( )->menuID( ) == id ) + oa = it.current( ); + + if( oa && m_pActiveObject ) + { + // otherwise no object action was selected in the context menu + + m_pActiveObject->createMemento( ); + m_pActiveObject->objectActionCalled( oa, m_controlPoints, + m_controlPointsPosition, + m_contextClickPosition ); + PMDataChangeCommand* cmd; + cmd = new PMDataChangeCommand( m_pActiveObject->takeMemento( ) ); + cmd->setText( oa->description( ) ); + m_pPart->executeCommand( cmd ); + } +} + +void PMGLView::slotControlPoint( int id ) +{ + PMControlPoint* p = m_controlPoints.at( id ); + if( p ) + { + PMControlPointListIterator cit( m_controlPoints ); + for( ; cit.current( ); ++cit ) + cit.current( )->setSelected( p == cit.current( ) ); + emit objectChanged( m_pActiveObject, PMCControlPointSelection, this ); + } +} + +void PMGLView::slotSnapToGrid( ) +{ + if( m_pActiveObject ) + { + if( !m_pActiveObject->mementoCreated( ) ) + m_pActiveObject->createMemento( ); + + PMControlPointListIterator it( m_controlPoints ); + for( ; it.current( ); ++it ) + if( it.current( )->selected( ) ) + it.current( )->snapToGrid( ); + + m_pActiveObject->controlPointsChanged( m_controlPoints ); + + PMDataChangeCommand* cmd; + cmd = new PMDataChangeCommand( m_pActiveObject->takeMemento( ) ); + cmd->setText( i18n( "Snap to Grid" ) ); + m_pPart->executeCommand( cmd ); + } +} + +QString PMGLView::description( ) const +{ + return viewTypeAsString( m_type ); +} + +void PMGLView::restoreViewConfig( PMViewOptions* vo ) +{ + if( vo && vo->viewType( ) == "glview" ) + { + PMGLViewOptions* o = ( PMGLViewOptions* ) vo; + m_type = o->glViewType( ); + } +} + +void PMGLView::saveViewConfig( PMViewOptions* vo ) const +{ + if( vo && vo->viewType( ) == "glview" ) + { + PMGLViewOptions* o = ( PMGLViewOptions* ) vo; + o->setGLViewType( m_type ); + } +} + +void PMGLViewOptions::loadData( QDomElement& e ) +{ + QString s = e.attribute( "type", "Camera" ); + if( s == "Camera" ) m_glViewType = PMGLView::PMViewCamera; + else if( s == "X" ) m_glViewType = PMGLView::PMViewPosX; + else if( s == "Y" ) m_glViewType = PMGLView::PMViewPosY; + else if( s == "Z" ) m_glViewType = PMGLView::PMViewPosZ; + else if( s == "NegX" ) m_glViewType = PMGLView::PMViewNegX; + else if( s == "NegY" ) m_glViewType = PMGLView::PMViewNegY; + else if( s == "NegZ" ) m_glViewType = PMGLView::PMViewNegZ; +} + +void PMGLViewOptions::saveData( QDomElement& e ) +{ + switch( m_glViewType ) + { + case PMGLView::PMViewCamera: + e.setAttribute( "type", "Camera" ); + break; + case PMGLView::PMViewPosX: + e.setAttribute( "type", "X" ); + break; + case PMGLView::PMViewPosY: + e.setAttribute( "type", "Y" ); + break; + case PMGLView::PMViewPosZ: + e.setAttribute( "type", "Z" ); + break; + case PMGLView::PMViewNegX: + e.setAttribute( "type", "NegX" ); + break; + case PMGLView::PMViewNegY: + e.setAttribute( "type", "NegY" ); + break; + case PMGLView::PMViewNegZ: + e.setAttribute( "type", "NegZ" ); + break; + default: + kdError( PMArea ) << i18n( "Unknown GL view type." ) + << endl; + break; + } +} + +QString PMGLViewFactory::description( ) const +{ + return i18n( "3D View" ); +} + +QString PMGLViewFactory::description( PMViewOptions* vo ) const +{ + if( vo && vo->viewType( ) == "glview" ) + { + PMGLViewOptions* o = ( PMGLViewOptions* ) vo; + return i18n( "3D View (%1)" ).arg( + PMGLView::viewTypeAsString( o->glViewType( ) ) ); + } + return description( ); +} + +PMViewOptionsWidget* PMGLViewFactory::newOptionsWidget( QWidget* parent, + PMViewOptions* o ) +{ + return new PMGLViewOptionsWidget( parent, o ); +} + +PMViewOptions* PMGLViewFactory::newOptionsInstance( ) const +{ + PMGLViewOptions* o = new PMGLViewOptions( ); + return o; +} + +PMGLViewOptionsWidget::PMGLViewOptionsWidget( QWidget* parent, + PMViewOptions* o ) + : PMViewOptionsWidget( parent ) +{ + m_pOptions = ( PMGLViewOptions* ) o; + + QHBoxLayout* hl = new QHBoxLayout( this, 0, KDialog::spacingHint( ) ); + QLabel* l = new QLabel( i18n( "3D view type:" ), this ); + hl->addWidget( l ); + + m_pGLViewType = new QComboBox( false, this ); + m_pGLViewType->insertItem( i18n( "Top" ) ); + m_pGLViewType->insertItem( i18n( "Bottom" ) ); + m_pGLViewType->insertItem( i18n( "Left" ) ); + m_pGLViewType->insertItem( i18n( "Right" ) ); + m_pGLViewType->insertItem( i18n( "Front" ) ); + m_pGLViewType->insertItem( i18n( "Back" ) ); + m_pGLViewType->insertItem( i18n( "Camera" ) ); + + switch( m_pOptions->glViewType( ) ) + { + case PMGLView::PMViewNegY: + m_pGLViewType->setCurrentItem( 0 ); + break; + case PMGLView::PMViewPosY: + m_pGLViewType->setCurrentItem( 1 ); + break; + case PMGLView::PMViewPosX: + m_pGLViewType->setCurrentItem( 2 ); + break; + case PMGLView::PMViewNegX: + m_pGLViewType->setCurrentItem( 3 ); + break; + case PMGLView::PMViewPosZ: + m_pGLViewType->setCurrentItem( 4 ); + break; + case PMGLView::PMViewNegZ: + m_pGLViewType->setCurrentItem( 5 ); + break; + case PMGLView::PMViewCamera: + m_pGLViewType->setCurrentItem( 6 ); + break; + } + + connect( m_pGLViewType, SIGNAL( activated( int ) ), + SLOT( slotGLViewTypeChanged( int ) ) ); + hl->addWidget( m_pGLViewType ); +} + +void PMGLViewOptionsWidget::slotGLViewTypeChanged( int index ) +{ + switch( index ) + { + case 0: + m_pOptions->setGLViewType( PMGLView::PMViewNegY ); + break; + case 1: + m_pOptions->setGLViewType( PMGLView::PMViewPosY ); + break; + case 2: + m_pOptions->setGLViewType( PMGLView::PMViewPosX ); + break; + case 3: + m_pOptions->setGLViewType( PMGLView::PMViewNegX ); + break; + case 4: + m_pOptions->setGLViewType( PMGLView::PMViewPosZ ); + break; + case 5: + m_pOptions->setGLViewType( PMGLView::PMViewNegZ ); + break; + case 6: + m_pOptions->setGLViewType( PMGLView::PMViewCamera ); + break; + } + emit viewTypeDescriptionChanged( ); +} + +#include "pmglview.moc" diff --git a/kpovmodeler/pmglview.h b/kpovmodeler/pmglview.h new file mode 100644 index 00000000..b33eeb2b --- /dev/null +++ b/kpovmodeler/pmglview.h @@ -0,0 +1,589 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMGLVIEW_H +#define PMGLVIEW_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "pmviewbase.h" +#include "pmviewfactory.h" +#include "pmcontrolpoint.h" +#include "pmvector.h" +#include "pmmatrix.h" +#include "pmobjectaction.h" + +const int controlPointSize = 7; + +class PMObject; +class PMPart; +class PMCamera; +class KConfig; +class QComboBox; + +/** + * Widget for rendering the scene with OpenGL + */ +class PMGLView : public PMViewBase +{ + Q_OBJECT +public: + /** + * Type of the view + */ + enum PMViewType { PMViewPosX, PMViewNegX, PMViewPosY, PMViewNegY, + PMViewPosZ, PMViewNegZ, PMViewCamera }; + /** + * Constructor + */ + PMGLView( PMPart* part, PMViewType t, + QWidget* parent = 0, const char* name = 0, WFlags f = 0 ); + /** + * Destructor + */ + ~PMGLView( ); + + /** */ + virtual QString viewType( ) const { return QString( "glview" ); } + /** */ + virtual QString description( ) const; + /** */ + virtual void restoreViewConfig( PMViewOptions* ); + /** */ + virtual void saveViewConfig( PMViewOptions* ) const; + + /** + * Enables/disables translating the view with the mouse + */ + void enableTranslateMode( bool yes = true ); + /** + * Enables/disables scaling the view with the mouse + */ + void enableScaleMode( bool yes = true ); + + /** + * Returns true if the opengl projection is up to date + */ + bool isProjectionUpToDate( ) const { return m_projectionUpToDate; } + /** + * Sets the projection up to date flag + */ + void setProjectionUpToDate( bool yes ) { m_projectionUpToDate = yes; } + + /** + * Sets the scale + */ + void setScale( double scale ); + /** + * Returns the scale + */ + double scale( ) const { return m_dScale; } + /** + * Sets the views translation in x direction + */ + void setTranslationX( double d ); + /** + * Returns the views translation in x direction + */ + double translationX( ) const { return m_dTransX; } + /** + * Sets the views translation in y direction + */ + void setTranslationY( double d ); + /** + * Returns the views translation in y direction + */ + double translationY( ) const { return m_dTransY; } + + /** + * Returns the 2D control points position in the view + */ + const QPtrList& controlPointsPosition( ) const + { + return m_controlPointsPosition; + } + /** + * Returns the last right mouse click position + */ + PMVector contextClickPosition( ) const { return m_contextClickPosition; } + + /** + * Returns the view type + */ + PMViewType type( ) const { return m_type; } + /** + * Sets the view type + */ + void setType( PMViewType t ); + /** + * Sets the camera + */ + void setCamera( PMCamera* c ); + /** + * Returns the camera + */ + PMCamera* camera( ) const { return m_pCamera; } + + /** + * Saves the configuration + */ + static void saveConfig( KConfig* cfg ); + /** + * Restores the configuration + */ + static void restoreConfig( KConfig* cfg ); + + /** + * Returns true if the glx stuff was initialized successfully + */ + bool isValid( ) const; + /** + * Sets this view as the current rendering view + */ + void makeCurrent( ); + /** + * Swaps the opengl buffers + */ + void swapBuffers( ); + + /** + * Returns the view type as string + */ + static QString viewTypeAsString( PMViewType t ); + /** + * Sets the direct rendering flag + */ + static void enableDirectRendering( bool yes ) { s_bDirect = yes; } + /** + * Returns the direct rendering flag + */ + static bool isDirectRenderingEnabled( ) { return s_bDirect; } +public slots: + /** + * Sets the view normal vector to the positive x-axes + */ + void slotSetTypePosX( ) { setType( PMViewPosX ); } + /** + * Sets the view normal vector to the negative x-axes + */ + void slotSetTypeNegX( ) { setType( PMViewNegX ); } + /** + * Sets the view normal vector to the positive y-axes + */ + void slotSetTypePosY( ) { setType( PMViewPosY ); } + /** + * Sets the view normal vector to the negative y-axes + */ + void slotSetTypeNegY( ) { setType( PMViewNegY ); } + /** + * Sets the view normal vector to the positive z-axes + */ + void slotSetTypePosZ( ) { setType( PMViewPosZ ); } + /** + * Sets the view normal vector to the negative z-axes + */ + void slotSetTypeNegZ( ) { setType( PMViewNegZ ); } + + /** + * Called when an object is changed. + * @see PMPart::objectChanged( ) + */ + void slotObjectChanged( PMObject* obj, const int mode, QObject* sender ); + /** + * Restarts rendering + */ + void slotRefresh( ); + /** + * Clears all data + */ + void slotClear( ); + /** + * Stops rendering + */ + void slotStopRendering( ); + /** + * Repaints the view if it is a camera view + */ + void slotActiveRenderModeChanged( ); + + /** + * Connected to the render manager + */ + void slotRenderingStarted( PMGLView* view ); + /** + * Connected to the render manager + */ + void slotAboutToUpdate( PMGLView* view ); + /** + * Connected to the render manager + */ + void slotRenderingFinished( PMGLView* view ); + +protected slots: + /** + * Sets the view type to camera view + */ + void slotCameraView( int id ); + /** + * Called when an object action was selected in the context menu + */ + void slotObjectAction( int id ); + /** + * Called when a control point was selected in the context menu + */ + void slotControlPoint( int id ); + /** + * Aligns the selected control points to the grid + */ + void slotSnapToGrid( ); + + void slotMouseChangeTimer( ); + void slotAutoScroll( ); + +signals: + /** + * Emitted when rendering has to be restarted + */ + void refresh( PMGLView* w ); + /** + * Emitted when an object is changed + */ + void objectChanged( PMObject* obj, const int mode, QObject* sender ); + /** + * Emitted when the mouse is over a control point + */ + void controlPointMessage( const QString& msg ); + /** + * Emitted in the destructor + */ + void destroyed( PMGLView* v ); + /** + * Emitted when the view type changes + */ + void viewTypeChanged( const QString& str ); + +protected: + /** + * Initializes the glx stuff + */ + virtual void initializeGL( ); + /** */ + virtual void resizeEvent( QResizeEvent* e ); + /** */ + virtual void paintEvent( QPaintEvent* e ); + /** */ + virtual void mousePressEvent( QMouseEvent* e ); + /** */ + virtual void mouseReleaseEvent( QMouseEvent* e ); + /** */ + virtual void mouseMoveEvent( QMouseEvent* e ); + /** */ + virtual void keyPressEvent( QKeyEvent* e ); + /** + * Event to zoom in / zoom out the viewport by mouse wheel + */ + virtual void wheelEvent( QWheelEvent* e ); + +private: + /** + * Updates the control points + */ + void updateControlPoints( ); + /** + * Recalculates the position of the control points on the screen + */ + void recalculateControlPointPosition( ); + /** + * Recalculates m_controlPointsTransformation and + * m_inversePointsTransformation + */ + void recalculateTransformations( ); + /** + * Returns the mouse 3D position, when the control point cp is selected + * + * x and y are the screen coordinates of the mouse. + */ + PMVector mousePosition( PMControlPoint* cp, int x, int y ); + /** + * Checks if a control point is under the mouse + */ + void checkUnderMouse( int x, int y ); + /** + * Repaints the view + */ + void repaint( bool graphicalChange = false ); + /** + * Starts a graphical change + */ + void startChange( const QPoint& mousePos ); + /** + * Graphical Change + */ + void graphicalChange( const QPoint& mousePos ); + /** + * Selects/deselecs the control point. If cp is 0, all control points are + * selected/deselected. + */ + void selectControlPoint( PMControlPoint* cp, bool select, bool deselectOthers = true ); + /** + * Invalidates the projection and repaints the view + */ + void invalidateProjection( bool graphicaChange = false ); + + /** + * Starts multiple selection mode + */ + void startSelection( ); + /** + * Restores the widget under the selection rect + */ + void restoreSelectionBox( ); + /** + * Saves the widget under the selection rect + */ + void saveSelectionBox( ); + /** + * Paints the selection box + */ + void paintSelectionBox( ); + /** + * Calculates the selection box + */ + void calculateSelectionBox( int& sx, int& sy, int& ex, int& ey, int& w, int& h ); + + double screenToInternalX( int x ) const; + double screenToInternalY( int y ) const; + + /** + * Returns the top level object for rendering (a declaration or the scene) + */ + PMObject* topLevelRenderingObject( PMObject* obj ) const; + /** + * Displays the context menu + */ + void contextMenu( ); + + /** + * Type of the view (camera, xy, ... ) + */ + PMViewType m_type; + /** + * Pointer to the part + */ + PMPart* m_pPart; + /** + * True if "scale view" is active + */ + bool m_bScaleMode; + double m_scaleIntX, m_scaleIntY; + /** + * true if "translate view" is active + */ + bool m_bTranslateMode; + /** + * True if "scale view" or "translate view" is active and the left + * mouse button is pressed. + */ + bool m_bMousePressed; + /** + * MidButton pressed + */ + bool m_bMidMousePressed; + /** + * True if a graphical change is active + */ + bool m_bGraphicalChangeMode; + bool m_bMementoCreated; + /** + * The old mouse position + */ + QPoint m_mousePos; + QPoint m_changeStartPos; + QPoint m_currentMousePos; + QTimer m_startTimer; + QTime m_changeStartTime; + bool m_bDeselectUnderMouse; + bool m_bSelectUnderMouse; + + /** + * Member variables for multiple selection mode + */ + QPixmap m_selectionPixmap[4]; + QPoint m_selectionStart, m_selectionEnd; + bool m_bMultipleSelectionMode; + bool m_bSelectionStarted; + + /** + * Member variables for autoscroll + */ + bool m_bAutoScroll; + double m_autoScrollSpeed; + QTimer m_autoScrollTimer; + QTime m_lastAutoScrollUpdate; + int m_autoScrollDirectionX, m_autoScrollDirectionY; + /** + * Rendering + */ + bool m_bAboutToUpdate; + + /** + * Scale of the view + */ + double m_dScale; + /** + * X-translation of the view + */ + double m_dTransX; + /** + * Y-translation of the view + */ + double m_dTransY; + + /** + * Control points of the active object + */ + PMControlPointList m_controlPoints; + /** + * Control point under the mouse + */ + PMControlPoint* m_pUnderMouse; + /** + * Position of the control points on the screen + */ + QPtrList m_controlPointsPosition; + /** + * Position of the last right mouse click + */ + PMVector m_contextClickPosition; + /** + * Transformation of the control points + * + * Always m_viewTransformation * m_objectsTransformation. + */ + PMMatrix m_controlPointsTransformation; + /** + * Inverse of m_controlPointsTransformation + */ + PMMatrix m_inversePointsTransformation; + /** + * True if m_inversePointsTransformation is valid + */ + bool m_bInverseValid; + /** + * Normal vector of the view + */ + PMVector m_normal; + /** + * Transformation of the view (scale and translation) + */ + PMMatrix m_viewTransformation; + /** + * Transformation of the active object + */ + PMMatrix m_objectsTransformation; + /** + * The camera + */ + PMCamera* m_pCamera; + PMObject* m_pActiveObject; + /** + * true if the opengl projection is up to date + */ + bool m_projectionUpToDate; + int m_visibilityLevel; + /** + * The current object actions + */ + QPtrList m_objectActions; + static bool s_bDirect; +}; + +/** + * Options class for the opengl view + */ +class PMGLViewOptions : public PMViewOptions +{ +public: + PMGLViewOptions( ) + { + m_glViewType = PMGLView::PMViewPosX; + } + PMGLViewOptions( PMGLView::PMViewType t ) + { + m_glViewType = t; + } + virtual PMViewOptions* copy( ) const { return new PMGLViewOptions( *this ); } + virtual QString viewType( ) const { return QString( "glview" ); } + PMGLView::PMViewType glViewType( ) const { return m_glViewType; } + void setGLViewType( PMGLView::PMViewType t ) { m_glViewType = t; } + virtual void loadData( QDomElement& e ); + virtual void saveData( QDomElement& e ); + +private: + PMGLView::PMViewType m_glViewType; +}; + +/** + * Factory class for 3d views + */ +class PMGLViewFactory : public PMViewTypeFactory +{ +public: + PMGLViewFactory( ) { } + virtual QString viewType( ) const { return QString( "glview" ); } + virtual QString description( ) const; + virtual QString description( PMViewOptions* ) const; + virtual QString iconName( ) const { return QString( "pmglview" ); } + virtual PMViewBase* newInstance( QWidget* parent, PMPart* part ) const + { + return new PMGLView( part, PMGLView::PMViewPosX, parent ); + } + virtual PMViewOptions* newOptionsInstance( ) const; + virtual PMViewOptionsWidget* newOptionsWidget( QWidget*, PMViewOptions* ); +}; + +/** + * Configuration widget for the view layout settings dialog + */ +class PMGLViewOptionsWidget : public PMViewOptionsWidget +{ + Q_OBJECT +public: + /** + * Default constructor + */ + PMGLViewOptionsWidget( QWidget* parent, PMViewOptions* o ); + +protected slots: + void slotGLViewTypeChanged( int ); + +private: + PMGLViewOptions* m_pOptions; + QComboBox* m_pGLViewType; +}; + +#endif diff --git a/kpovmodeler/pmgraphicalobject.cpp b/kpovmodeler/pmgraphicalobject.cpp new file mode 100644 index 00000000..85f4ad22 --- /dev/null +++ b/kpovmodeler/pmgraphicalobject.cpp @@ -0,0 +1,248 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmgraphicalobject.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" + +const bool c_defaultNoShadow = false; +const bool c_defaultNoImage = false; +const bool c_defaultNoReflection = false; +const bool c_defaultDoubleIlluminate = false; +const int c_defaultVisibilityLevel = 0; +const bool c_defaultRelativeVisibility = true; +const bool c_defaultExport = true; + +PMDefinePropertyClass( PMGraphicalObject, PMGraphicalObjectProperty ); + +PMMetaObject* PMGraphicalObject::s_pMetaObject = 0; + +PMGraphicalObject::PMGraphicalObject( PMPart* part ) + : Base( part ) +{ + m_noShadow = c_defaultNoShadow; + m_noImage = c_defaultNoImage; + m_noReflection = c_defaultNoReflection; + m_doubleIlluminate = c_defaultDoubleIlluminate; + m_visibilityLevel = c_defaultVisibilityLevel; + m_relativeVisibility = c_defaultRelativeVisibility; + m_export = c_defaultExport; +} + +PMGraphicalObject::PMGraphicalObject( const PMGraphicalObject& o ) + : Base( o ) +{ + m_noShadow = o.m_noShadow; + m_noImage = o.m_noImage; + m_noReflection = o.m_noReflection; + m_doubleIlluminate = o.m_doubleIlluminate; + m_visibilityLevel = o.m_visibilityLevel; + m_relativeVisibility = o.m_relativeVisibility; + m_export = o.m_export; +} + +PMGraphicalObject::~PMGraphicalObject( ) +{ +} + +PMMetaObject* PMGraphicalObject::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "GraphicalObject", Base::metaObject( ) ); + s_pMetaObject->addProperty( + new PMGraphicalObjectProperty( "noShadow", &PMGraphicalObject::setNoShadow, + &PMGraphicalObject::noShadow ) ); + s_pMetaObject->addProperty( + new PMGraphicalObjectProperty( "noImage", &PMGraphicalObject::setNoImage, + &PMGraphicalObject::noImage ) ); + s_pMetaObject->addProperty( + new PMGraphicalObjectProperty( "noReflection", &PMGraphicalObject::setNoReflection, + &PMGraphicalObject::noReflection ) ); + s_pMetaObject->addProperty( + new PMGraphicalObjectProperty( "doubleIlluminate", &PMGraphicalObject::setDoubleIlluminate, + &PMGraphicalObject::doubleIlluminate ) ); + s_pMetaObject->addProperty( + new PMGraphicalObjectProperty( "visibilityLevel", &PMGraphicalObject::setVisibilityLevel, + &PMGraphicalObject::visibilityLevel ) ); + s_pMetaObject->addProperty( + new PMGraphicalObjectProperty( "relativeVisibilityLevel", &PMGraphicalObject::setVisibilityLevelRelative, + &PMGraphicalObject::isVisibilityLevelRelative ) ); + s_pMetaObject->addProperty( + new PMGraphicalObjectProperty( "export", &PMGraphicalObject::setExportPovray, + &PMGraphicalObject::exportPovray ) ); + } + return s_pMetaObject; +} + +void PMGraphicalObject::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMGraphicalObject::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "no_shadow", m_noShadow ); + e.setAttribute( "no_image", m_noImage ); + e.setAttribute( "no_reflection", m_noReflection ); + e.setAttribute( "double_illuminate", m_doubleIlluminate ); + e.setAttribute( "visibility_level", m_visibilityLevel ); + e.setAttribute( "relative_visibility", m_relativeVisibility ); + e.setAttribute( "export", m_export ); + Base::serialize( e, doc ); +} + +void PMGraphicalObject::readAttributes( const PMXMLHelper& h ) +{ + m_noShadow = h.boolAttribute( "no_shadow", c_defaultNoShadow ); + m_noImage = h.boolAttribute( "no_image", c_defaultNoImage ); + m_noReflection = h.boolAttribute( "no_reflection", c_defaultNoReflection ); + m_doubleIlluminate = h.boolAttribute( "double_illuminate", + c_defaultDoubleIlluminate ); + m_visibilityLevel = h.intAttribute( "visibility_level", + c_defaultVisibilityLevel ); + m_relativeVisibility = h.boolAttribute( "relative_visibility", + c_defaultRelativeVisibility ); + m_export = h.boolAttribute( "export", c_defaultExport ); + Base::readAttributes( h ); +} + +void PMGraphicalObject::setNoShadow( bool yes ) +{ + if( m_noShadow != yes ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMNoShadowID, m_noShadow ); + m_noShadow = yes; + } +} + +void PMGraphicalObject::setNoImage( bool yes ) +{ + if( m_noImage != yes ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMNoImageID, m_noImage ); + m_noImage = yes; + } +} + +void PMGraphicalObject::setNoReflection( bool yes ) +{ + if ( m_noReflection != yes ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMNoReflectionID, m_noReflection ); + m_noReflection = yes; + } +} + +void PMGraphicalObject::setDoubleIlluminate( bool yes ) +{ + if( m_doubleIlluminate != yes ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMDoubleIlluminateID, m_doubleIlluminate ); + m_doubleIlluminate = yes; + } +} + +void PMGraphicalObject::setVisibilityLevel( int level ) +{ + if( m_visibilityLevel != level ) + { + if( m_pMemento ) + { + m_pMemento->addData( s_pMetaObject, PMVisibilityID, + m_visibilityLevel ); + // do not call PMCompositeObject::setViewStructureChanged because + // the view structure has not really changed. + // Only the scene has to be rendered. + m_pMemento->setViewStructureChanged( ); + } + m_visibilityLevel = level; + } +} + +void PMGraphicalObject::setVisibilityLevelRelative( bool relative ) +{ + if( m_relativeVisibility != relative ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRelativeVisibilityID, + m_relativeVisibility ); + m_relativeVisibility = relative; + } +} + +void PMGraphicalObject::setExportPovray( bool ex ) +{ + if( m_export != ex ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMExportID, m_export ); + m_export = ex; + } +} + +void PMGraphicalObject::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMNoShadowID: + setNoShadow( data->boolData( ) ); + break; + case PMNoImageID: + setNoImage( data->boolData( ) ); + break; + case PMNoReflectionID: + setNoReflection( data->boolData( ) ); + break; + case PMDoubleIlluminateID: + setDoubleIlluminate( data->boolData( ) ); + break; + case PMVisibilityID: + setVisibilityLevel( data->intData( ) ); + break; + case PMRelativeVisibilityID: + setVisibilityLevelRelative( data->boolData( ) ); + break; + case PMExportID: + setExportPovray( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMGraphicalObject::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmgraphicalobject.h b/kpovmodeler/pmgraphicalobject.h new file mode 100644 index 00000000..f07ac46f --- /dev/null +++ b/kpovmodeler/pmgraphicalobject.h @@ -0,0 +1,141 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMGRAPHICALOBJECT_H +#define PMGRAPHICALOBJECT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdetailobject.h" + + +/** + * Class for povray graphical objects + * + * Objects in povray can be: + * Finite Solid Primitives, Finite Patch Primitives, Infinite Solid Primitives and Constructive Solid Geometry + */ +class PMGraphicalObject : public PMDetailObject +{ + typedef PMDetailObject Base; +public: + /** + * Creates an empty PMGraphicalObject + */ + PMGraphicalObject( PMPart* part ); + /** + * Copy constructor + */ + PMGraphicalObject( const PMGraphicalObject& o ); + /** + * Deletes the object and all children + */ + virtual ~PMGraphicalObject( ); + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns the state of the no_shadow flag. + */ + bool noShadow( ) const { return m_noShadow; } + /** + * Sets the no_shadow flag + */ + void setNoShadow( bool yes ); + /** + * Returns the state of the no_image flag. + */ + bool noImage( ) const { return m_noImage; } + /** + * Sets the no_image flag + */ + void setNoImage( bool yes ); + /** + * Returns the state of the no_reflection flag + */ + bool noReflection( ) const { return m_noReflection; } + /** + * Sets the no_reflection flag + */ + void setNoReflection( bool yes ); + /** + * Returns the state of the double_illuminate flag + */ + bool doubleIlluminate( ) const { return m_doubleIlluminate; } + /** + * Sets the double_illuminate flag + */ + void setDoubleIlluminate( bool yes ); + /** + * Returns the visibility level + */ + int visibilityLevel( ) const { return m_visibilityLevel; } + /** + * Sets the visibility level + */ + void setVisibilityLevel( int level ); + /** + * Returns true if the visibility level is relative to the objects parent + */ + bool isVisibilityLevelRelative( ) const { return m_relativeVisibility; } + /** + * Sets the visibility level absolute or relative + */ + void setVisibilityLevelRelative( bool relative ); + /** + * Returns the export flag + */ + virtual bool exportPovray( ) const { return m_export; } + /** + * Sets the export flag + */ + void setExportPovray( bool ex ); + + /** */ + virtual void restoreMemento( PMMemento* s ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMGraphicalObjectMementoID { PMNoShadowID, PMNoImageID, PMNoReflectionID, + PMDoubleIlluminateID, PMVisibilityID, + PMRelativeVisibilityID, PMExportID }; + + bool m_noShadow; + bool m_noImage; + bool m_noReflection; + bool m_doubleIlluminate; + int m_visibilityLevel; + bool m_relativeVisibility; + bool m_export; + static PMMetaObject* s_pMetaObject; +}; + + +#endif diff --git a/kpovmodeler/pmgraphicalobjectedit.cpp b/kpovmodeler/pmgraphicalobjectedit.cpp new file mode 100644 index 00000000..2a06485c --- /dev/null +++ b/kpovmodeler/pmgraphicalobjectedit.cpp @@ -0,0 +1,168 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmgraphicalobjectedit.h" +#include "pmgraphicalobject.h" + +#include +#include +#include +#include +#include + +const int c_minValue = -1000; +const int c_maxValue = 1000; + +PMGraphicalObjectEdit::PMGraphicalObjectEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMGraphicalObjectEdit::createBottomWidgets( ) +{ + QGridLayout* gl = new QGridLayout( topLayout( ), 2, 2 ); + m_pNoShadowButton = new QCheckBox( i18n( "No shadow" ), this ); + gl->addWidget( m_pNoShadowButton, 0, 0 ); + m_pNoImageButton = new QCheckBox( i18n( "No image" ), this ); + gl->addWidget( m_pNoImageButton, 0, 1 ); + m_pNoReflectionButton = new QCheckBox( i18n( "No reflection" ), this ); + gl->addWidget( m_pNoReflectionButton, 1, 0 ); + m_pDoubleIlluminateButton = new QCheckBox( i18n( "Double illuminate" ), this ); + gl->addWidget( m_pDoubleIlluminateButton, 1, 1 ); + m_pExport = new QCheckBox( i18n( "Export to renderer" ), this ); + topLayout( )->addWidget( m_pExport ); + + QHBoxLayout* hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Visibility level: " ), this ) ); + m_pVisibilityLevel = new QSpinBox( c_minValue, c_maxValue, 1, this ); + hl->addWidget( m_pVisibilityLevel ); + m_pResultingVisibility = new QLabel( QString( "( )" ), this ); + hl->addWidget( m_pResultingVisibility ); + hl->addSpacing( 10 ); + m_pRelativeVisibility = new QCheckBox( i18n( "Relative" ), this ); + hl->addWidget( m_pRelativeVisibility ); + hl->addStretch( 1 ); + + connect( m_pNoShadowButton, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pNoImageButton, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pNoReflectionButton, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pDoubleIlluminateButton, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pRelativeVisibility, SIGNAL( clicked( ) ), + SLOT( slotRelativeChanged( ) ) ); + connect( m_pVisibilityLevel, SIGNAL( valueChanged( int ) ), + SLOT( slotLevelChanged( int ) ) ); + connect( m_pExport, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + + + Base::createBottomWidgets( ); +} + +void PMGraphicalObjectEdit::displayObject( PMObject* o ) +{ + if( o->isA( "GraphicalObject" ) ) + { + bool readOnly = o->isReadOnly( ); + + m_pDisplayedObject = ( PMGraphicalObject* ) o; + m_pNoShadowButton->setChecked( m_pDisplayedObject->noShadow( ) ); + m_pNoShadowButton->setEnabled( !readOnly ); + m_pNoImageButton->setChecked( m_pDisplayedObject->noImage( ) ); + m_pNoImageButton->setEnabled( !readOnly ); + m_pNoReflectionButton->setChecked( m_pDisplayedObject->noReflection( ) ); + m_pNoReflectionButton->setEnabled( !readOnly ); + m_pDoubleIlluminateButton->setChecked( m_pDisplayedObject->doubleIlluminate( ) ); + m_pDoubleIlluminateButton->setEnabled( !readOnly ); + bool sb = m_pVisibilityLevel->signalsBlocked( ); + m_pVisibilityLevel->blockSignals( true ); + m_pVisibilityLevel->setValue( m_pDisplayedObject->visibilityLevel( ) ); + m_pVisibilityLevel->setEnabled( !readOnly ); + m_pVisibilityLevel->blockSignals( sb ); + sb = m_pRelativeVisibility->signalsBlocked( ); + m_pRelativeVisibility->blockSignals( true ); + m_pRelativeVisibility->setChecked( m_pDisplayedObject->isVisibilityLevelRelative( ) ); + m_pRelativeVisibility->setEnabled( !readOnly ); + m_pRelativeVisibility->blockSignals( sb ); + m_pExport->setChecked( m_pDisplayedObject->exportPovray( ) ); + m_pExport->setEnabled( !readOnly ); + + recalculateResultingVisibility( ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMGraphicalObjectEdit: Can't display object\n"; +} + +void PMGraphicalObjectEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + m_pDisplayedObject->setNoShadow( m_pNoShadowButton->isChecked( ) ); + m_pDisplayedObject->setNoImage( m_pNoImageButton->isChecked( ) ); + m_pDisplayedObject->setNoReflection( m_pNoReflectionButton->isChecked( ) ); + m_pDisplayedObject->setDoubleIlluminate( m_pDoubleIlluminateButton->isChecked( ) ); + m_pDisplayedObject->setVisibilityLevel( m_pVisibilityLevel->value( ) ); + m_pDisplayedObject->setVisibilityLevelRelative( m_pRelativeVisibility->isChecked( ) ); + m_pDisplayedObject->setExportPovray( m_pExport->isChecked( ) ); + Base::saveContents( ); + } +} + +bool PMGraphicalObjectEdit::isDataValid( ) +{ + return Base::isDataValid( ); +} + +void PMGraphicalObjectEdit::slotRelativeChanged( ) +{ + recalculateResultingVisibility( ); + emit dataChanged( ); +} + +void PMGraphicalObjectEdit::slotLevelChanged( int ) +{ + recalculateResultingVisibility( ); + emit dataChanged( ); +} + +void PMGraphicalObjectEdit::recalculateResultingVisibility( ) +{ + PMObject* o = m_pDisplayedObject->parent( ); + PMGraphicalObject* go = 0; + int level = 0; + bool absoluteFound = false; + + level = m_pVisibilityLevel->value( ); + if( !m_pRelativeVisibility->isChecked( ) ) + absoluteFound = true; + + for( ; o && !absoluteFound; o = o->parent( ) ) + { + if( o->isA( "GraphicalObject" ) ) + { + go = ( PMGraphicalObject* ) o; + level += go->visibilityLevel( ); + if( !go->isVisibilityLevelRelative( ) ) + absoluteFound = true; + } + } + m_pResultingVisibility->setText( QString( "(%1)" ).arg( level ) ); +} + +#include "pmgraphicalobjectedit.moc" diff --git a/kpovmodeler/pmgraphicalobjectedit.h b/kpovmodeler/pmgraphicalobjectedit.h new file mode 100644 index 00000000..3b31a794 --- /dev/null +++ b/kpovmodeler/pmgraphicalobjectedit.h @@ -0,0 +1,78 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMGRAPHICALOBJECTEDIT_H +#define PMGRAPHICALOBJECTEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdetailobjectedit.h" + +class PMGraphicalObject; +class QCheckBox; +class QSpinBox; +class QLabel; + +/** + * Dialog edit class for @ref PMGraphicalObject. + */ +class PMGraphicalObjectEdit : public PMDetailObjectEdit +{ + Q_OBJECT + typedef PMDetailObjectEdit Base; +public: + /** + * Creates a PMGraphicalObjectEdit with parent and name + */ + PMGraphicalObjectEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createBottomWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + void slotRelativeChanged( ); + void slotLevelChanged( int ); + +private: + void recalculateResultingVisibility( ); + +private: + PMGraphicalObject* m_pDisplayedObject; + QCheckBox* m_pNoShadowButton; + QCheckBox* m_pNoImageButton; + QCheckBox* m_pNoReflectionButton; + QCheckBox* m_pDoubleIlluminateButton; + QSpinBox* m_pVisibilityLevel; + QCheckBox* m_pRelativeVisibility; + QLabel* m_pResultingVisibility; + QCheckBox* m_pExport; +}; + + +#endif diff --git a/kpovmodeler/pmgridsettings.cpp b/kpovmodeler/pmgridsettings.cpp new file mode 100644 index 00000000..20973935 --- /dev/null +++ b/kpovmodeler/pmgridsettings.cpp @@ -0,0 +1,155 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmgridsettings.h" + +#include "pmlineedits.h" +#include "pmrendermanager.h" +#include "pmcontrolpoint.h" +#include "pmdefaults.h" + +#include +#include +#include +#include +#include + +PMGridSettings::PMGridSettings( QWidget* parent, const char* name ) + : PMSettingsDialogPage( parent, name ) +{ + QHBoxLayout* hlayout; + QVBoxLayout* vlayout; + QVBoxLayout* gvl; + QGridLayout* grid; + QGroupBox* gb; + + vlayout = new QVBoxLayout( this, 0, KDialog::spacingHint( ) ); + gb = new QGroupBox( i18n( "Displayed Grid" ), this ); + vlayout->addWidget( gb ); + gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) ); + gvl->addSpacing( 10 ); + + hlayout = new QHBoxLayout( gvl ); + hlayout->addWidget( new QLabel( i18n( "Color:" ), gb ) ); + m_pGridColor = new KColorButton( gb ); + hlayout->addWidget( m_pGridColor ); + hlayout->addStretch( 1 ); + + hlayout = new QHBoxLayout( gvl ); + hlayout->addWidget( new QLabel( i18n( "Distance:" ), gb ) ); + m_pGridDistance = new PMIntEdit( gb ); + m_pGridDistance->setValidation( true, 20, false, 0 ); + hlayout->addWidget( m_pGridDistance ); + hlayout->addStretch( 1 ); + + gb = new QGroupBox( i18n( "Control Point Grid" ), this ); + vlayout->addWidget( gb ); + gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) ); + gvl->addSpacing( 10 ); + + hlayout = new QHBoxLayout( gvl ); + grid = new QGridLayout( hlayout, 3, 2 ); + grid->addWidget( new QLabel( i18n( "2D/3D movement:" ), gb ), 0, 0 ); + m_pMoveGrid = new PMFloatEdit( gb ); + m_pMoveGrid->setValidation( true, 0.001, true, 100 ); + grid->addWidget( m_pMoveGrid, 0, 1 ); + + grid->addWidget( new QLabel( i18n( "Scale:" ), gb ), 1, 0 ); + m_pScaleGrid = new PMFloatEdit( gb ); + m_pScaleGrid->setValidation( true, 0.001, true, 100 ); + grid->addWidget( m_pScaleGrid, 1, 1 ); + + grid->addWidget( new QLabel( i18n( "Rotation:" ), gb ), 2, 0 ); + m_pRotateGrid = new PMFloatEdit( gb ); + m_pRotateGrid->setValidation( true, 0.001, true, 180 ); + grid->addWidget( m_pRotateGrid, 2, 1 ); + + hlayout->addStretch( 1 ); + + vlayout->addStretch( 1 ); +} + +void PMGridSettings::displaySettings( ) +{ + PMRenderManager* rm = PMRenderManager::theManager( ); + m_pGridColor->setColor( rm->gridColor( ) ); + m_pGridDistance->setValue( rm->gridDistance( ) ); + m_pMoveGrid->setValue( PMControlPoint::moveGrid( ) ); + m_pScaleGrid->setValue( PMControlPoint::scaleGrid( ) ); + m_pRotateGrid->setValue( PMControlPoint::rotateGrid( ) ); +} + +void PMGridSettings::displayDefaults( ) +{ + m_pGridColor->setColor( c_defaultGridColor ); + m_pGridDistance->setValue( c_defaultGridDistance ); + m_pMoveGrid->setValue( c_defaultMoveGrid ); + m_pScaleGrid->setValue( c_defaultScaleGrid ); + m_pRotateGrid->setValue( c_defaultRotateGrid ); +} + +bool PMGridSettings::validateData( ) +{ + if( !m_pGridDistance->isDataValid( ) ) + { + emit showMe( ); + m_pGridDistance->setFocus( ); + return false; + } + if( !m_pMoveGrid->isDataValid( ) ) + { + emit showMe( ); + m_pMoveGrid->setFocus( ); + return false; + } + if( !m_pScaleGrid->isDataValid( ) ) + { + emit showMe( ); + m_pScaleGrid->setFocus( ); + return false; + } + if( !m_pRotateGrid->isDataValid( ) ) + { + emit showMe( ); + m_pRotateGrid->setFocus( ); + return false; + } + return true; +} + +void PMGridSettings::applySettings( ) +{ + bool repaint = false; + PMRenderManager* rm = PMRenderManager::theManager( ); + if( rm->gridColor( ) != m_pGridColor->color( ) ) + { + rm->setGridColor( m_pGridColor->color( ) ); + repaint = true; + } + if( rm->gridDistance( ) != m_pGridDistance->value( ) ) + { + rm->setGridDistance( m_pGridDistance->value( ) ); + repaint = true; + } + PMControlPoint::setMoveGrid( m_pMoveGrid->value( ) ); + PMControlPoint::setScaleGrid( m_pScaleGrid->value( ) ); + PMControlPoint::setRotateGrid( m_pRotateGrid->value( ) ); + if( repaint ) + emit repaintViews( ); +} + +#include "pmgridsettings.moc" diff --git a/kpovmodeler/pmgridsettings.h b/kpovmodeler/pmgridsettings.h new file mode 100644 index 00000000..724ade35 --- /dev/null +++ b/kpovmodeler/pmgridsettings.h @@ -0,0 +1,60 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMGRIDSETTINGS_H +#define PMGRIDSETTINGS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsettingsdialog.h" + +class KColorButton; +class PMIntEdit; +class PMFloatEdit; + +/** + * Grid configuration dialog page + */ +class PMGridSettings : public PMSettingsDialogPage +{ + Q_OBJECT +public: + /** + * Default constructor + */ + PMGridSettings( QWidget* parent, const char* name = 0 ); + /** */ + virtual void displaySettings( ); + /** */ + virtual bool validateData( ); + /** */ + virtual void applySettings( ); + /** */ + virtual void displayDefaults( ); + +private: + PMIntEdit* m_pGridDistance; + KColorButton* m_pGridColor; + PMFloatEdit* m_pMoveGrid; + PMFloatEdit* m_pScaleGrid; + PMFloatEdit* m_pRotateGrid; +}; + + +#endif diff --git a/kpovmodeler/pmheightfield.cpp b/kpovmodeler/pmheightfield.cpp new file mode 100644 index 00000000..e729282a --- /dev/null +++ b/kpovmodeler/pmheightfield.cpp @@ -0,0 +1,469 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmheightfield.h" + +#include "pmxmlhelper.h" +#include "pmheightfieldedit.h" +#include "pmheightfieldroam.h" +#include "pmmemento.h" +#include "pmviewstructure.h" +#include "pmenumproperty.h" +#include "pmdefaults.h" + +#include + +const PMHeightField::HeightFieldType c_defaultType = PMHeightField::HFgif; +const QString c_defaultTypeText = QString( "gif" ); +const QString c_defaultFileName = QString( "" ); +const bool c_defaultHierarchy = true; +const bool c_defaultSmooth = false; +const double c_defaultWaterLevel = 0.0; + +PMDefinePropertyClass( PMHeightField, PMHeightFieldProperty ); +PMDefineEnumPropertyClass( PMHeightField, PMHeightField::HeightFieldType, + PMHeightFieldTypeProperty ); + + +int PMHeightField::s_variance = c_defaultHeightFieldVariance; +int PMHeightField::s_parameterKey = 0; + +PMViewStructure* PMHeightField::s_pDefaultViewStructure = 0; +PMMetaObject* PMHeightField::s_pMetaObject = 0; + +PMObject* createNewHeightField( PMPart* part ) +{ + return new PMHeightField( part ); +} + +PMHeightField::PMHeightField( PMPart* part ) + : Base( part ) +{ + m_hfType = c_defaultType; + m_fileName = c_defaultFileName; + m_hierarchy = c_defaultHierarchy; + m_smooth = c_defaultSmooth; + m_waterLevel = c_defaultWaterLevel; + + m_modMap = true; + m_pROAM = 0; +} + +PMHeightField::PMHeightField( const PMHeightField& f ) + : Base( f ) +{ + m_hfType = f.m_hfType; + m_fileName = f.m_fileName; + m_hierarchy = f.m_hierarchy; + m_smooth = f.m_smooth; + m_waterLevel = f.m_waterLevel; + + m_modMap = true; + m_pROAM = 0; +} + +PMHeightField::~PMHeightField( ) +{ + delete m_pROAM; +} + +QString PMHeightField::description( ) const +{ + return i18n( "height field" ); +} + +void PMHeightField::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "hf_type", typeToString( m_hfType ) ); + e.setAttribute( "file_name", m_fileName ); + e.setAttribute( "hierarchy", m_hierarchy ); + e.setAttribute( "smooth", m_smooth ); + e.setAttribute( "water_level", m_waterLevel ); + Base::serialize( e, doc ); +} + +void PMHeightField::readAttributes( const PMXMLHelper& h ) +{ + m_hfType = stringToType( h.stringAttribute( "hf_type", c_defaultTypeText ) ); + m_fileName = h.stringAttribute( "file_name", c_defaultFileName ); + m_hierarchy = h.boolAttribute( "hierarchy", c_defaultHierarchy ); + m_smooth = h.boolAttribute( "smooth", c_defaultSmooth ); + m_waterLevel = h.doubleAttribute( "water_level", c_defaultWaterLevel ); + Base::readAttributes( h ); +} + +PMMetaObject* PMHeightField::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "HeightField", Base::metaObject( ), + createNewHeightField ); + s_pMetaObject->addProperty( + new PMHeightFieldProperty( "fileName", &PMHeightField::setFileName, &PMHeightField::fileName ) ); + s_pMetaObject->addProperty( + new PMHeightFieldProperty( "hierarchy", &PMHeightField::setHierarchy, &PMHeightField::hierarchy ) ); + s_pMetaObject->addProperty( + new PMHeightFieldProperty( "smooth", &PMHeightField::setSmooth, &PMHeightField::smooth ) ); + s_pMetaObject->addProperty( + new PMHeightFieldProperty( "waterLevel", &PMHeightField::setWaterLevel, &PMHeightField::waterLevel ) ); + PMHeightFieldTypeProperty* p = + new PMHeightFieldTypeProperty( "heightFieldType", &PMHeightField::setHeightFieldType, + &PMHeightField::heightFieldType ); + p->addEnumValue( "Gif", HFgif ); + p->addEnumValue( "Tga", HFtga ); + p->addEnumValue( "Pot", HFpot ); + p->addEnumValue( "Png", HFpng ); + p->addEnumValue( "Pgm", HFpgm ); + p->addEnumValue( "Ppm", HFppm ); + p->addEnumValue( "Sys", HFsys ); + s_pMetaObject->addProperty( p ); + } + return s_pMetaObject; +} + +void PMHeightField::setHeightFieldType( PMHeightField::HeightFieldType t ) +{ + if( t != m_hfType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMHeightFieldTypeID, m_hfType ); + m_hfType = t; + } +} + +void PMHeightField::setFileName( const QString& f ) +{ + if( f != m_fileName ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFileNameID, m_fileName ); + m_fileName = f; + m_modMap = true; + setViewStructureChanged( ); + } +} + +void PMHeightField::setHierarchy( bool h ) +{ + if( h != m_hierarchy ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMHierarchyID, m_hierarchy ); + m_hierarchy = h; + } +} + +void PMHeightField::setSmooth( bool s ) +{ + if( s != m_smooth ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSmoothID, m_smooth ); + m_smooth = s; + } +} + +void PMHeightField::setWaterLevel( double wl ) +{ + if( wl < 0.0 ) + { + kdError( PMArea ) << "Water level < 0.0 in PMHeightField::setWaterLevel\n"; + wl = 0.0; + } + if( wl > 1.0 ) + { + kdError( PMArea ) << "Water level > 1.0 in PMHeightField::setWaterLevel\n"; + wl = 1.0; + } + + if( wl != m_waterLevel ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMWaterLevelID, m_waterLevel ); + m_waterLevel = wl; + setViewStructureChanged( ); + } +} + +PMDialogEditBase* PMHeightField::editWidget( QWidget* parent ) const +{ + return new PMHeightFieldEdit( parent ); +} + +void PMHeightField::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMHeightFieldTypeID: + m_hfType = ( HeightFieldType ) data->intData( ); + break; + case PMFileNameID: + m_fileName = data->stringData( ); + break; + case PMHierarchyID: + m_hierarchy = data->boolData( ); + break; + case PMSmoothID: + m_smooth = data->boolData( ); + break; + case PMWaterLevelID: + m_waterLevel = data->doubleData( ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMHeightField::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + + +bool PMHeightField::isDefault( ) +{ + return ( m_waterLevel == c_defaultWaterLevel && m_fileName.isEmpty( ) ); +} + +void PMHeightField::createViewStructure( ) +{ + int detail = 65200 - ( ( s_variance * 163 ) * ( displayDetail( ) * displayDetail( ) ) ); + if ( m_modMap ) + { + m_modMap = false; + + if ( m_pROAM ) + { + delete m_pROAM; + m_pROAM = 0; + } + + if ( !m_fileName.isEmpty( ) ) + { + m_pROAM = new PMHeightFieldROAM( m_fileName ); + + if ( m_pROAM->isFailed( ) ) + { + delete m_pROAM; + m_pROAM = 0; + } + } + } + + if ( m_pROAM ) + { + m_pROAM->setDisplayDetail( detail ); + m_pROAM->setWaterLevel( m_waterLevel ); + m_pROAM->updateModel( ); + roamViewStructure( ); + return; + } + + if ( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultViewStructure( ) ); + m_pViewStructure->points( ).detach( ); + m_pViewStructure->lines( ).detach( ); + } + else + { + m_pViewStructure->points( ).resize( + defaultViewStructure( )->points( ).size( ) ); + m_pViewStructure->lines( ).resize( + defaultViewStructure( )->lines( ).size( ) ); + } + + PMPointArray& points = m_pViewStructure->points( ); + + points[4][1] = m_waterLevel; + points[5][1] = m_waterLevel; + points[6][1] = m_waterLevel; + points[7][1] = m_waterLevel; +} + +void PMHeightField::roamViewStructure( ) +{ + if ( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultViewStructure( ) ); + m_pViewStructure->points( ).detach( ); + m_pViewStructure->lines( ).detach( ); + } + + int x, z, i, pts; + int size = m_pROAM->size( ); + int currentLine = defaultViewStructure( )->lines( ).size( ); + int defPointsNum = defaultViewStructure( )->points( ).size( ); + double dx, dy, dz; + double sizeM1 = size - 1.0; + + m_pViewStructure->points( ).resize( m_pROAM->usedPoints( ) + defPointsNum ); + m_pViewStructure->lines( ).resize( m_pROAM->numLines( ) + currentLine ); + + PMPointArray& points = m_pViewStructure->points( ); + PMLineArray& lines = m_pViewStructure->lines( ); + + points[4][1] = m_waterLevel; + points[5][1] = m_waterLevel; + points[6][1] = m_waterLevel; + points[7][1] = m_waterLevel; + + for ( x = 0; x < size; ++x ) + { + dx = x / sizeM1; + for ( z = 0; z < size; ++z ) + { + dz = z / sizeM1; + if ( m_pROAM->usedPoint( x, z ) ) + { + pts = m_pROAM->posPoint( x, z ) + defPointsNum; + dy = m_pROAM->height( x, z, true ) / 65535.0; + points[ pts ] = PMPoint( dx, dy, dz ); + + for ( i = 0; m_pROAM->lineExist( x, z, i ) && i < 8; ++i ) + { + lines[ currentLine++ ] = + PMLine( pts, m_pROAM->endPoint( x, z, i ) + defPointsNum ); + } + } + } + } +} + +PMViewStructure* PMHeightField::defaultViewStructure( ) const +{ + if( !s_pDefaultViewStructure ) + { + s_pDefaultViewStructure = new PMViewStructure( 12, 16 ); + PMPointArray& points = s_pDefaultViewStructure->points( ); + PMLineArray& lines = s_pDefaultViewStructure->lines( ); + + points[ 0] = PMPoint( 0.0, 0.0, 0.0 ); + points[ 1] = PMPoint( 1.0, 0.0, 0.0 ); + points[ 2] = PMPoint( 1.0, 0.0, 1.0 ); + points[ 3] = PMPoint( 0.0, 0.0, 1.0 ); + points[ 4] = PMPoint( 0.0, c_defaultWaterLevel, 0.0 ); + points[ 5] = PMPoint( 1.0, c_defaultWaterLevel, 0.0 ); + points[ 6] = PMPoint( 1.0, c_defaultWaterLevel, 1.0 ); + points[ 7] = PMPoint( 0.0, c_defaultWaterLevel, 1.0 ); + points[ 8] = PMPoint( 0.0, 1.0, 0.0 ); + points[ 9] = PMPoint( 1.0, 1.0, 0.0 ); + points[10] = PMPoint( 1.0, 1.0, 1.0 ); + points[11] = PMPoint( 0.0, 1.0, 1.0 ); + + lines[ 0] = PMLine( 0, 1 ); + lines[ 1] = PMLine( 1, 2 ); + lines[ 2] = PMLine( 2, 3 ); + lines[ 3] = PMLine( 0, 3 ); + + lines[ 4] = PMLine( 0, 8 ); + lines[ 5] = PMLine( 1, 9 ); + lines[ 6] = PMLine( 2, 10 ); + lines[ 7] = PMLine( 3, 11 ); + + lines[ 8] = PMLine( 4, 5 ); + lines[ 9] = PMLine( 5, 6 ); + lines[10] = PMLine( 6, 7 ); + lines[11] = PMLine( 4, 7 ); + + lines[12] = PMLine( 8, 9 ); + lines[13] = PMLine( 9, 10 ); + lines[14] = PMLine( 10, 11 ); + lines[15] = PMLine( 8, 11 ); + } + return s_pDefaultViewStructure; +} + +QString PMHeightField::typeToString( PMHeightField::HeightFieldType t ) +{ + QString s; + switch( t ) + { + case HFgif: + s = QString( "gif" ); + break; + case HFtga: + s = QString( "tga" ); + break; + case HFpot: + s = QString( "pot" ); + break; + case HFpng: + s = QString( "png" ); + break; + case HFpgm: + s = QString( "pgm" ); + break; + case HFppm: + s = QString( "ppm" ); + break; + case HFsys: + s = QString( "sys" ); + break; + } + return s; +} + +PMHeightField::HeightFieldType PMHeightField::stringToType( const QString &str ) +{ + HeightFieldType t = HFgif; + if( str == "gif" ) + t = HFgif; + else if( str == "tga" ) + t = HFtga; + else if( str == "pot" ) + t = HFpot; + else if( str == "png" ) + t = HFpng; + else if( str == "pgm" ) + t = HFpgm; + else if( str == "ppm" ) + t = HFppm; + else if( str == "sys" ) + t = HFsys; + return t; +} + +void PMHeightField::setVariance( int v ) +{ + if( v < 52 && v > 0 ) + s_variance = v; + else + kdDebug( PMArea ) << "PMHeightField::setVariance: V must be less than 52 & greater than 0\n"; + s_parameterKey++; +} + +void PMHeightField::cleanUp( ) const +{ + if( s_pDefaultViewStructure ) + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} diff --git a/kpovmodeler/pmheightfield.h b/kpovmodeler/pmheightfield.h new file mode 100644 index 00000000..4ab961c8 --- /dev/null +++ b/kpovmodeler/pmheightfield.h @@ -0,0 +1,180 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMHEIGHTFIELD_H +#define PMHEIGHTFIELD_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" + +class PMViewStructure; +class PMHeightFieldROAM; + +/** + * Class for povray height fields. + */ + +class PMHeightField : public PMSolidObject +{ + typedef PMSolidObject Base; +public: + /** + * Height field type + */ + enum HeightFieldType { HFgif, HFtga, HFpot, HFpng, HFpgm, HFppm, HFsys }; + /** + * Creates an empty PMHeightField + */ + PMHeightField( PMPart* part ); + /** + * Copy constructor + */ + PMHeightField( const PMHeightField& f ); + /** + * deletes the PMHeightField + */ + virtual ~PMHeightField( ); + + /** */ + virtual PMObject* copy( ) const { return new PMHeightField( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMHeightFieldEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmheightfield" ); } + + /** + * Returns the height field type + */ + HeightFieldType heightFieldType( ) const { return m_hfType; } + /** + * Sets the height field type + */ + void setHeightFieldType( HeightFieldType t ); + /** + * Returns the file name + */ + QString fileName( ) const { return m_fileName; } + /** + * Sets the file name + */ + void setFileName( const QString& name ); + /** + * Returns the hierarchy flag + */ + bool hierarchy( ) const { return m_hierarchy; } + /** + * Sets the hierarchy flag + */ + void setHierarchy( bool h ); + /** + * Returns the smooth flag + */ + bool smooth( ) const { return m_smooth; } + /** + * Sets the smooth flag + */ + void setSmooth( bool s ); + /** + * Returns the water level + */ + double waterLevel( ) const { return m_waterLevel; } + /** + * Sets the water level + */ + void setWaterLevel( double wl ); + + /** + * Sets the heightfield variance + */ + static void setVariance( int v ); + /** + * Returns the heightfield variance + */ + static int variance( ) { return s_variance; } + + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual bool hasDisplayDetail( ) const { return true; } + /** */ + virtual void cleanUp( ) const; + + static QString typeToString( HeightFieldType t ); + static HeightFieldType stringToType( const QString &str ); + +protected: + /** */ + virtual bool isDefault( ); + /** */ + virtual void createViewStructure( ); + /** */ + virtual PMViewStructure* defaultViewStructure( ) const; + /** */ + virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey(); } + +private: + /** + * Creates the ROAM view structure + */ + void roamViewStructure( ); + + /** + * IDs for @ref PMMementoData + */ + enum PMHeightFieldMementoID { PMHeightFieldTypeID, PMFileNameID, + PMHierarchyID, PMSmoothID, PMWaterLevelID }; + + HeightFieldType m_hfType; + QString m_fileName; + bool m_hierarchy; + bool m_smooth; + double m_waterLevel; + + bool m_modMap; + PMHeightFieldROAM* m_pROAM; + + /** + * The default view structure. It can be shared between height fields + */ + static PMViewStructure* s_pDefaultViewStructure; + static int s_variance; + static int s_parameterKey; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmheightfieldedit.cpp b/kpovmodeler/pmheightfieldedit.cpp new file mode 100644 index 00000000..c5a65998 --- /dev/null +++ b/kpovmodeler/pmheightfieldedit.cpp @@ -0,0 +1,201 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmheightfieldedit.h" +#include "pmheightfield.h" +#include "pmlineedits.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +PMHeightFieldEdit::PMHeightFieldEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMHeightFieldEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Type:" ), this ) ); + m_pHeightFieldType = new QComboBox( false, this ); + hl->addWidget( m_pHeightFieldType ); + hl->addStretch( 0 ); + m_pHeightFieldType->insertItem( "gif" ); + m_pHeightFieldType->insertItem( "tga" ); + m_pHeightFieldType->insertItem( "pot" ); + m_pHeightFieldType->insertItem( "png" ); + m_pHeightFieldType->insertItem( "pgm" ); + m_pHeightFieldType->insertItem( "ppm" ); + m_pHeightFieldType->insertItem( "sys" ); + + hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "File name:" ), this ) ); + m_pFileName = new QLineEdit( this ); + hl->addWidget( m_pFileName ); + m_pChooseFileName = new QPushButton( this ); + m_pChooseFileName->setPixmap( SmallIcon( "fileopen" ) ); + hl->addWidget( m_pChooseFileName ); + + hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Water level:" ), this ) ); + m_pWaterLevel = new PMFloatEdit( this ); + m_pWaterLevel->setValidation( true, 0.0, true, 1.0 ); + hl->addWidget( m_pWaterLevel ); + hl->addStretch( 1 ); + + m_pHierarchy = new QCheckBox( i18n( "Hierarchy" ), this ); + topLayout( )->addWidget( m_pHierarchy ); + + m_pSmooth = new QCheckBox( i18n( "Smooth" ), this ); + topLayout( )->addWidget( m_pSmooth ); + + connect( m_pHeightFieldType, SIGNAL( activated( int ) ), + SLOT( slotTypeChanged( int ) ) ); + connect( m_pFileName, SIGNAL( textChanged( const QString& ) ), + SLOT( slotFileNameChanged( const QString& ) ) ); + connect( m_pChooseFileName, SIGNAL( clicked( ) ), + SLOT( slotFileNameClicked( ) ) ); + connect( m_pWaterLevel, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pHierarchy, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pSmooth, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMHeightFieldEdit::displayObject( PMObject* o ) +{ + if( o->isA( "HeightField" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMHeightField* ) o; + + switch( m_pDisplayedObject->heightFieldType( ) ) + { + case PMHeightField::HFgif: + m_pHeightFieldType->setCurrentItem( 0 ); + break; + case PMHeightField::HFtga: + m_pHeightFieldType->setCurrentItem( 1 ); + break; + case PMHeightField::HFpot: + m_pHeightFieldType->setCurrentItem( 2 ); + break; + case PMHeightField::HFpng: + m_pHeightFieldType->setCurrentItem( 3 ); + break; + case PMHeightField::HFpgm: + m_pHeightFieldType->setCurrentItem( 4 ); + break; + case PMHeightField::HFppm: + m_pHeightFieldType->setCurrentItem( 5 ); + break; + case PMHeightField::HFsys: + m_pHeightFieldType->setCurrentItem( 6 ); + break; + } + m_pFileName->setText( m_pDisplayedObject->fileName( ) ); + m_pWaterLevel->setValue( m_pDisplayedObject->waterLevel( ) ); + m_pHierarchy->setChecked( m_pDisplayedObject->hierarchy( ) ); + m_pSmooth->setChecked( m_pDisplayedObject->smooth( ) ); + + m_pHeightFieldType->setEnabled( !readOnly ); + m_pFileName->setReadOnly( readOnly ); + m_pChooseFileName->setEnabled( !readOnly ); + m_pHierarchy->setEnabled( !readOnly ); + m_pSmooth->setEnabled( !readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMHeightFieldEdit: Can't display object\n"; +} + +void PMHeightFieldEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + switch( m_pHeightFieldType->currentItem( ) ) + { + case 0: + m_pDisplayedObject->setHeightFieldType( PMHeightField::HFgif ); + break; + case 1: + m_pDisplayedObject->setHeightFieldType( PMHeightField::HFtga ); + break; + case 2: + m_pDisplayedObject->setHeightFieldType( PMHeightField::HFpot ); + break; + case 3: + m_pDisplayedObject->setHeightFieldType( PMHeightField::HFpng ); + break; + case 4: + m_pDisplayedObject->setHeightFieldType( PMHeightField::HFpgm ); + break; + case 5: + m_pDisplayedObject->setHeightFieldType( PMHeightField::HFppm ); + break; + case 6: + m_pDisplayedObject->setHeightFieldType( PMHeightField::HFsys ); + break; + } + m_pDisplayedObject->setFileName( m_pFileName->text( ) ); + m_pDisplayedObject->setWaterLevel( m_pWaterLevel->value( ) ); + m_pDisplayedObject->setHierarchy( m_pHierarchy->isChecked( ) ); + m_pDisplayedObject->setSmooth( m_pSmooth->isChecked( ) ); + } +} + +bool PMHeightFieldEdit::isDataValid( ) +{ + if( m_pWaterLevel->isDataValid( ) ) + return Base::isDataValid( ); + return false; +} + +void PMHeightFieldEdit::slotTypeChanged( int ) +{ + emit dataChanged( ); +} + +void PMHeightFieldEdit::slotFileNameChanged( const QString& ) +{ + emit dataChanged( ); +} + +void PMHeightFieldEdit::slotFileNameClicked( ) +{ + QString str = KFileDialog::getOpenFileName( QString::null, QString::null ); + + if( !str.isEmpty() ) + { + m_pFileName->setText( str ); + emit dataChanged( ); + } +} + +#include "pmheightfieldedit.moc" diff --git a/kpovmodeler/pmheightfieldedit.h b/kpovmodeler/pmheightfieldedit.h new file mode 100644 index 00000000..24ea2e6e --- /dev/null +++ b/kpovmodeler/pmheightfieldedit.h @@ -0,0 +1,87 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMHEIGHTFIELDEDIT_H +#define PMHEIGHTFIELDEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" + +class PMHeightField; +class PMFloatEdit; +class QCheckBox; +class QComboBox; +class QLineEdit; +class QPushButton; + +/** + * Dialog edit class for @ref PMHeightField + */ +class PMHeightFieldEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMHeightFieldEdit with parent and name + */ + PMHeightFieldEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); + +protected slots: + /** + * Slot called when the height field type is changed + */ + void slotTypeChanged( int t ); + /** + * Slot called when the file name is changed + */ + void slotFileNameChanged( const QString& s ); + /** + * Slot called when the choose file button is pressed + */ + void slotFileNameClicked( ); + +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMHeightField* m_pDisplayedObject; + QComboBox* m_pHeightFieldType; + QLineEdit* m_pFileName; + QPushButton* m_pChooseFileName; + QCheckBox* m_pSmooth; + QCheckBox* m_pHierarchy; + PMFloatEdit* m_pWaterLevel; + +}; + + +#endif diff --git a/kpovmodeler/pmheightfieldroam.cpp b/kpovmodeler/pmheightfieldroam.cpp new file mode 100644 index 00000000..eb2790a5 --- /dev/null +++ b/kpovmodeler/pmheightfieldroam.cpp @@ -0,0 +1,422 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ +#include "pmheightfieldroam.h" + +#include +#include + +#include +#include +#include + +#include + +PMHeightFieldROAM::PMHeightFieldROAM( const QString &fileName ) +{ + m_size = 0; + m_numLines = m_usedPoints = 0; + m_waterLevel = m_displayDetail = 0; + m_mapMod = m_levelMod = true; + m_fail = false; + m_pPoints = 0; + m_pTree = 0; + + if ( !imageToData( fileName ) ) + { + if ( m_pPoints ) + delete [] m_pPoints; + if ( m_pTree ) + delete [] m_pTree; + m_pPoints = 0; + m_pTree = 0; + m_pNextNode = 0; + m_size = m_numPoints = m_numNodes = 0; + m_fail = true; + return; + } + + calcLevel( ); +} + +PMHeightFieldROAM::~PMHeightFieldROAM( ) +{ + delete [] m_pPoints; + delete [] m_pTree; +} + +void PMHeightFieldROAM::updateModel( ) +{ + if ( m_fail ) + return; + int z = m_size - 1; + if ( m_mapMod ) + { + m_mapMod = false; + m_levelMod = false; + clearPoints( ); + clearNodes( true ); + + m_pNextNode = m_pTree + 1; + m_pNextNode->base = m_pTree; + m_pTree->base = m_pNextNode++; + + varNode(m_pTree, z, 0, 0, 0, 0, z, 0); + varNode(m_pTree + 1, 0, z, z, z, z, 0, 0); + + sptNode(m_pTree, 0); + sptNode(m_pTree + 1, 0); + + pntNode(m_pTree, z, 0, 0, 0, 0, z); + pntNode(m_pTree + 1, 0, z, z, z, z, 0); + } + else if ( m_levelMod ) + { + m_levelMod = false; + clearPoints( ); + clearNodes( ); + + sptNode( m_pTree, 0 ); + sptNode( m_pTree + 1, 0 ); + + pntNode( m_pTree, z, 0, 0, 0, 0, z ); + pntNode( m_pTree + 1, 0, z, z, z, z, 0 ); + } +} + +void PMHeightFieldROAM::setDisplayDetail( int detail ) +{ + if ( detail != m_displayDetail ) + { + m_displayDetail = detail; + m_levelMod = true; + } +} + +void PMHeightFieldROAM::setWaterLevel( double waterLevel ) +{ + int waterConv = (int)( waterLevel * 65535 ); + if ( waterConv != m_waterLevel ) + { + m_waterLevel = waterConv; + m_levelMod = true; + } +} + +double PMHeightFieldROAM::waterLevel( ) const +{ + double waterConv = m_waterLevel / 65535.0; + return waterConv; +} + +unsigned short PMHeightFieldROAM::height( int x, int y, bool waterLevel ) const +{ + unsigned short hgt = m_pPoints[ x + ( y * m_size ) ].hgt; + if ( waterLevel ) + { + if ( hgt <= m_waterLevel ) + return m_waterLevel; + else + return hgt; + } + else + return hgt; +} + +bool PMHeightFieldROAM::lineExist( int x, int y, int line ) const +{ + if ( m_pPoints[ x + ( y * m_size ) ].lines[ line ] ) return true; + else return false; +} + +bool PMHeightFieldROAM::imageToData(const QString &fileName) +{ + QImage scaledMap; + QImage mapFile( fileName ); + + if ( mapFile.isNull( ) ) + return false; + + if ( mapFile.width( ) > 192 || mapFile.height( ) > 192 ) + { + scaledMap = mapFile.scale( 257, 257 ); + } + else if ( mapFile.width( ) > 96 || mapFile.height( ) > 96 ) + { + scaledMap = mapFile.scale( 129, 129 ); + } + else if ( mapFile.width( ) > 48 || mapFile.height( ) > 48) + { + scaledMap = mapFile.scale( 65, 65 ); + } + else + { + scaledMap = mapFile.scale( 33, 33 ); + } + + if ( scaledMap.isNull( ) ) + return false; + + m_size = scaledMap.width( ); + if ( !createPoints( ) || !createNodes( ) ) + return false; + + bool colourIndex; + + if ( mapFile.depth( ) > 8 ) + colourIndex = false; + else + { + scaledMap = scaledMap.convertDepthWithPalette( 8, mapFile.colorTable( ), 256 ); + colourIndex = true; + } + + for ( int y = 0, y2 = ( m_size - 1 ) ; y < m_size ; ++y, --y2 ) + { + for ( int x = 0 ; x < m_size ; ++x ) + { + if ( colourIndex ) + setHeight( x, y2, scaledMap.pixelIndex( x, y ) * 256 ); + else + setHeight( x, y2, ( 256 * qRed( scaledMap.pixel( x, y ) ) ) + + qGreen( scaledMap.pixel( x, y ) ) ); + } + } + + return true; +} + +void PMHeightFieldROAM::calcLevel( ) +{ + int i = 0; + int j = m_size; + + while( j != 1) + { + j /= 2; + i++; + } + m_maxLevel = i * 2; +} + +void PMHeightFieldROAM::varNode ( triNodeStructure* current, + int x1, int y1, + int x2, int y2, + int x3, int y3, + int level ) +{ + int xm = (x1 + x3) >> 1; + int ym = (y1 + y3) >> 1; + + if ( level >= m_maxLevel ) + { + unsigned short z1 = height( x1, y1 ); + unsigned short z3 = height( x3, y3 ); + + unsigned short zm = ( ( z3 - z1 ) / 2 ) + z1; + unsigned short hgt = height( xm, ym ); + + current->vari = abs( zm - hgt ); + return; + } + + current->lchd = m_pNextNode++; + current->rchd = m_pNextNode++; + + varNode(current->lchd, x3, y3, xm, ym, x2, y2, level + 1); + varNode(current->rchd, x2, y2, xm, ym, x1, y1, level + 1); + + current->vari = current->lchd->vari + current->rchd->vari; +} + +void PMHeightFieldROAM::sptNode ( triNodeStructure* current, int level ) +{ + if ( !current->split ) + { + if ( level >= m_maxLevel ) return; + + if (current->vari > m_displayDetail) split(current); + else return; + } + + sptNode(current->lchd, level + 1); + sptNode(current->rchd, level + 1); +} + +void PMHeightFieldROAM::split( triNodeStructure* current ) +{ + current->split = true; + + if ( current->base ) + { + if ( current->base->base != current ) split( current->base ); + } + + triNodeStructure* child; + + //left child + child = current->lchd; + child->base = current->lnbr; + if ( current->lnbr ) + { + if ( current->lnbr->rnbr == current ) current->lnbr->rnbr = child; + else current->lnbr->base = child; + } + child->lnbr = current->rchd; + + //rightchild + child = current->rchd; + child->base = current->rnbr; + if ( current->rnbr ) + { + if ( current->rnbr->lnbr == current ) current->rnbr->lnbr = child; + else current->rnbr->base = child; + } + child->rnbr = current->lchd; + + if ( current->base ) + { + if ( !current->base->split ) split( current->base ); + current->lchd->rnbr = current->base->rchd; + current->rchd->lnbr = current->base->lchd; + } +} + +void PMHeightFieldROAM::pntNode( triNodeStructure* current, + int x1, int y1, + int x2, int y2, + int x3, int y3 ) +{ + if (current->split) + { + int xm = (x1 + x3) >> 1; + int ym = (y1 + y3) >> 1; + pntNode( current->lchd, x3, y3, xm, ym, x2, y2 ); + pntNode( current->rchd, x2, y2, xm, ym, x1, y1 ); + } + else + { + pointStructure* pts[3]; + pts[0] = &m_pPoints[ x1 + ( y1 * m_size ) ]; + pts[1] = &m_pPoints[ x2 + ( y2 * m_size ) ]; + pts[2] = &m_pPoints[ x3 + ( y3 * m_size ) ]; + + if ( m_waterLevel != 0 ) + { + if ( pts[0]->hgt <= m_waterLevel && + pts[1]->hgt <= m_waterLevel && + pts[2]->hgt <= m_waterLevel ) + return; + } + + for ( int i = 0 ; i < 3 ; ++i ) + { + if ( !pts[i]->used ) + { + pts[i]->pos = m_usedPoints++; + pts[i]->used = true; + } + } + + addLine( pts[0], pts[1] ); + addLine( pts[1], pts[2] ); + addLine( pts[2], pts[0] ); + } +} + +void PMHeightFieldROAM::addLine( pointStructure* pts1, pointStructure* pts2 ) +{ + for ( int i = 0 ; i < 8 ; ++i ) + { + if ( pts1->lines[i] ) + { + if ( pts1->lines[i] == pts2 ) return; + } + else + { + for ( int j = 0 ; pts2->lines[j] ; ++j ) + { + if ( pts2->lines[j] == pts1 ) return; + } + pts1->lines[i] = pts2; + m_numLines++; + return; + } + } +} + +bool PMHeightFieldROAM::createPoints( ) +{ + m_numPoints = m_size * m_size; + m_pPoints = new( std::nothrow ) pointStructure[ m_numPoints ]; + if ( !m_pPoints ) + return false; + else + { + clearPoints( true ); + return true; + } +} + +void PMHeightFieldROAM::clearPoints( bool all ) +{ + int i, j; + for ( i = 0 ; i < m_numPoints ; ++i ) + { + if ( all ) + { + m_pPoints[i].hgt = 0; + m_pPoints[i].pos = 0; + } + for ( j = 0 ; j < 8 ; ++j ) + m_pPoints[i].lines[j] = 0; + m_pPoints[i].used = false; + } + + m_usedPoints = m_numLines = 0; +} + +bool PMHeightFieldROAM::createNodes( ) +{ + m_numNodes = ( ( m_size - 1 ) * ( 4 * ( m_size - 1 ) ) ) - 2; + m_pTree = new( std::nothrow ) triNodeStructure[ m_numNodes ]; + if ( !m_pTree ) + return false; + else + { + clearNodes( true ); + return true; + } +} + +void PMHeightFieldROAM::clearNodes( bool all ) +{ + m_pNextNode = m_pTree; + for ( int i = 0; i < m_numNodes; ++i ) + { + if ( all ) + { + m_pNextNode->lchd = 0; + m_pNextNode->rchd = 0; + m_pNextNode->base = 0; + m_pNextNode->lnbr = 0; + m_pNextNode->rnbr = 0; + m_pNextNode->vari = 0; + } + m_pNextNode->split = false; + m_pNextNode++; + } +} diff --git a/kpovmodeler/pmheightfieldroam.h b/kpovmodeler/pmheightfieldroam.h new file mode 100644 index 00000000..e2802c6b --- /dev/null +++ b/kpovmodeler/pmheightfieldroam.h @@ -0,0 +1,283 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ +#ifndef PMHEIGHTFIELDROAM_H +#define PMHEIGHTFIELDROAM_H + +class QString; + +/** + * ROAM display class for @ref PMHeightField +*/ +class PMHeightFieldROAM +{ + int m_size; + int m_numPoints; + int m_usedPoints; + int m_numLines; + int m_numNodes; + bool m_fail; + int m_maxLevel; + int m_displayDetail; + int m_waterLevel; + bool m_mapMod; + bool m_levelMod; + + /** + * Point Structure holds most of the info + */ + struct pointStructure + { + unsigned short hgt; + pointStructure* lines[ 8 ]; + int pos; + bool used; + }; + /** + * The points array + */ + pointStructure* m_pPoints; + + /** + * The Triangle Node structure used in the ROAM algorithm + */ + struct triNodeStructure + { + triNodeStructure* lchd; + triNodeStructure* rchd; + triNodeStructure* base; + triNodeStructure* lnbr; + triNodeStructure* rnbr; + int vari; + bool split; + }; + /** + * Tree Root node + */ + triNodeStructure* m_pTree; + /** + * Next available node + */ + triNodeStructure* m_pNextNode; + + /** + * Loads and formats the image to the correct size, creates the points + * array. Then fills the points array with the heights and zero's the + * rest of the info + * @param filename The name of the file to load + * @return true if succesful false it it fails + */ + bool imageToData( const QString &fileName ); + + /** + * Sets the Maximum Level of the tree. + */ + void calcLevel( ); + + /** + * Generates the Variance for each node. + * @param current The current node + * @param x1-y1 The position of the first corner + * @param x2-y2 The position of the second corner + * @param x3-y3 The position of the third corner + * @param level The current level within a tree + */ + void varNode( triNodeStructure* current, + int x1, int y1, + int x2, int y2, + int x3, int y3, + int level ); + + /** + * Generates the Split for the Tree. + * @param current The current node + * @param level The current level within a tree + */ + void sptNode( triNodeStructure* current, int level ); + + /** + * Request the splitting of a node, checks too see if it can be + * Split or if its base neighbour requires splitting. + * @param current node to split + */ + void split( triNodeStructure* current ); + + /** + * Counts up the lines and points in a model, and sets the points + * structure ready for returning + * @param current The current node + * @param x1-y1 The position of the first corner + * @param x2-y2 The position of the second corner + * @param x3-y3 The position of the third corner + */ + void pntNode( triNodeStructure* current, + int x1, int y1, + int x2, int y2, + int x3, int y3 ); + + /** + * Adds a line makes sure that this line does not already exist + * @param pts1 The start point in the line + * @param pts2 The end point of the line + */ + void addLine( pointStructure* pts1, pointStructure* pts2 ); + + /** + * creates the points array and clears it + * @return true if succesful + */ + bool createPoints( ); + /** + * Clears some of the points data for recalculation or all + * of it for initialization + * @param all true if all the data is to be cleared + */ + void clearPoints( bool all = false ); + + /** + * creates the nodes array and clears it + * @return true if succesful + */ + bool createNodes( ); + /** + * Clears nodes for reuse in splitting recalculation or + * all of the data for initialization and variance + * @param all true if all the data is to be cleared + */ + void clearNodes( bool all = false ); + + /** + * Sets the height of a point + * @param x the position of the point in X + * @param y the position of the point in Y + * @param hgt the new height + */ + void setHeight( int x, int y, unsigned short hgt ) const + { m_pPoints[ x + ( y * m_size ) ].hgt = hgt; } + +public: + /** + * Constructor for class + * @param fileName Source file for the map + */ + PMHeightFieldROAM( const QString &fileName ); + /** + * Class Destructor relases all the memory + */ + ~PMHeightFieldROAM( ); + + /** + * Returns true if there has been a problem + */ + bool isFailed( ) { return m_fail; } + + /** + * Creates the model based on the current map + * display detail and water level + */ + void updateModel( ); + + /** + * Sets the display detail for the model + * @param detail The new level of detail + */ + void setDisplayDetail( int detail ); + /** + * Returns the current display detail + */ + int displayDetail( ) const { return m_displayDetail; } + + /** + * Sets the water level + * @param waterLevel the water level + */ + void setWaterLevel( double m_waterLevel ); + /** + * Returns the current water level + */ + double waterLevel( ) const; + + /** + * Return The size of the map in either direction + */ + int size( ) const { return m_size; } + /** + * Return The total number of points in the model + */ + int numPoints( ) const { return m_numPoints; } + /** + * Return The number of used points + */ + int usedPoints( ) const { return m_usedPoints; } + /** + * Return The number of lines + */ + int numLines( ) const { return m_numLines; } + /** + * Return the number of nodes + */ + int numNodes( ) const { return m_numNodes; } + + /** + * Returns a height of a point + * @param x the position of the point in X + * @param y the position of the point in Y + * @param waterLevel whether to return a point offset by water level + * @return the height of the point + */ + unsigned short height( int x, int y, bool waterLevel = false ) const; + + /** + * Determines if the point is used + * @param x The position of the point on the x axis. + * @param y The position of the point on the y axis. + * @return true if the point is used else false + */ + bool usedPoint( int x, int y ) const + { return m_pPoints[ x + ( y * m_size ) ].used; } + + /** + * Gets the used postion of a point + * @param x The position of the point on the x axis. + * @param y The position of the point on the y axis. + * @return the used position + */ + int posPoint( int x, int y ) const + { return m_pPoints[ x + ( y * m_size ) ].pos; } + + /** + * Returns the used position of a point at the end point of a line. + * @param x The position of the start point on the x axis. + * @param y The position of the start point on the y axis. + * @param line The Line Index + * @return The used positon of the end point + */ + int endPoint( int x, int y, int line ) const + { return m_pPoints[ x + ( y * m_size ) ].lines[ line ]->pos; } + + /** + * Returns whether this line exists + * @param x The position of the start point on the x axis. + * @param y The position of the start point on the y axis. + * @param line The Line Index + * @return Whether the line exists + */ + bool lineExist( int x, int y, int line ) const; + +}; + +#endif diff --git a/kpovmodeler/pmimagemap.cpp b/kpovmodeler/pmimagemap.cpp new file mode 100644 index 00000000..7fcaeb64 --- /dev/null +++ b/kpovmodeler/pmimagemap.cpp @@ -0,0 +1,522 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Passos Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmimagemapedit.h" +#include "pmimagemap.h" +#include "pmpalettevalue.h" +#include "pmpalettevaluememento.h" + +#include "pmxmlhelper.h" +#include "pmcompositeobject.h" +#include "pmmemento.h" +#include "pmenumproperty.h" + +#include + +const PMImageMap::PMBitmapType bitmapTypeDefault = PMImageMap::BitmapSys; +const char *const bitmapFileDefault = 0; +const bool enableFilterAllDefault = false; +const bool enableTransmitAllDefault = false; +const double filterAllDefault = 0.0; +const double transmitAllDefault = 0.0; +const bool onceDefault = false; +const PMImageMap::PMMapType mapTypeDefault = PMImageMap::MapPlanar; +const PMImageMap::PMInterpolateType interpolateTypeDefault = PMImageMap::InterpolateNone; + +PMDefinePropertyClass( PMImageMap, PMImageMapProperty ); +PMDefineEnumPropertyClass( PMImageMap, PMImageMap::PMBitmapType, + PMBitmapTypeProperty ); +PMDefineEnumPropertyClass( PMImageMap, PMImageMap::PMInterpolateType, + PMInterpolateTypeProperty ); +PMDefineEnumPropertyClass( PMImageMap, PMImageMap::PMMapType, + PMMapTypeProperty ); + +PMMetaObject* PMImageMap::s_pMetaObject = 0; +PMObject* createNewImageMap( PMPart* part ) +{ + return new PMImageMap( part ); +} + +PMImageMap::PMImageMap( PMPart* part ) + : Base( part ) +{ + m_bitmapType = bitmapTypeDefault; + m_bitmapFile = bitmapFileDefault; + m_enableFilterAll = enableFilterAllDefault; + m_filterAll = filterAllDefault; + m_enableTransmitAll = enableTransmitAllDefault; + m_transmitAll = transmitAllDefault; + m_once = onceDefault; + m_mapType = mapTypeDefault; + m_interpolateType = interpolateTypeDefault; +} + +PMImageMap::PMImageMap( const PMImageMap& m ) + : Base( m ) +{ + m_bitmapType = m.m_bitmapType; + m_bitmapFile = m.m_bitmapFile; + m_enableFilterAll = m.m_enableFilterAll; + m_filterAll = m.m_filterAll; + m_enableTransmitAll = m.m_enableTransmitAll; + m_transmitAll = m.m_transmitAll; + m_once = m.m_once; + m_mapType = m.m_mapType; + m_interpolateType = m.m_interpolateType; + m_filters = m.m_filters; + m_transmits = m.m_transmits; +} + +PMImageMap::~PMImageMap( ) +{ +} + +void PMImageMap::serialize( QDomElement& e, QDomDocument& doc ) const +{ + switch( m_bitmapType ) + { + case BitmapGif: + e.setAttribute( "bitmap_type", "gif" ); + break; + case BitmapTga: + e.setAttribute( "bitmap_type", "tga" ); + break; + case BitmapIff: + e.setAttribute( "bitmap_type", "iff" ); + break; + case BitmapPpm: + e.setAttribute( "bitmap_type", "ppm" ); + break; + case BitmapPgm: + e.setAttribute( "bitmap_type", "pgm" ); + break; + case BitmapPng: + e.setAttribute( "bitmap_type", "png" ); + break; + case BitmapJpeg: + e.setAttribute( "bitmap_type", "jpeg" ); + break; + case BitmapTiff: + e.setAttribute( "bitmap_type", "tiff" ); + break; + case BitmapSys: + e.setAttribute( "bitmap_type", "sys" ); + break; + } + e.setAttribute( "file_name", m_bitmapFile ); + e.setAttribute( "enable_filter_all", m_enableFilterAll ); + e.setAttribute( "filter_all", m_filterAll ); + e.setAttribute( "enable_transmit_all", m_enableTransmitAll ); + e.setAttribute( "transmit_all", m_transmitAll ); + e.setAttribute( "once", m_once ); + + QDomElement extra_data = doc.createElement( "extra_data" ); + + QDomElement data = doc.createElement( "indexed_filters" ); + QDomElement p; + + QValueList::ConstIterator it; + for( it = m_filters.begin( ); it != m_filters.end( ); ++it ) + { + p = doc.createElement( "index_filter" ); + ( *it ).serialize( p, doc ); + data.appendChild( p ); + } + extra_data.appendChild( data ); + + data = doc.createElement( "indexed_transmits" ); + for( it = m_transmits.begin( ); it != m_transmits.end( ); ++it ) + { + p = doc.createElement( "index_transmit" ); + ( *it ).serialize( p, doc ); + data.appendChild( p ); + } + extra_data.appendChild( data ); + + e.appendChild( extra_data ); + + switch( m_mapType ) + { + case MapPlanar: + e.setAttribute( "map_type", "planar" ); + break; + case MapSpherical: + e.setAttribute( "map_type", "spherical" ); + break; + case MapCylindrical: + e.setAttribute( "map_type", "cylindrical" ); + break; + case MapToroidal: + e.setAttribute( "map_type", "toroidal" ); + break; + } + switch( m_interpolateType ) + { + case InterpolateNone: + e.setAttribute( "interpolate", "none" ); + break; + case InterpolateBilinear: + e.setAttribute( "interpolate", "bilinear" ); + break; + case InterpolateNormalized: + e.setAttribute( "interpolate", "normalized" ); + break; + } + Base::serialize( e, doc ); +} + +void PMImageMap::readAttributes( const PMXMLHelper& h ) +{ + QString str; + + str = h.stringAttribute( "bitmap_type", "sys" ); + if( str == "gif" ) + m_bitmapType = BitmapGif; + else if( str == "tga" ) + m_bitmapType = BitmapTga; + else if( str == "iff" ) + m_bitmapType = BitmapIff; + else if( str == "ppm" ) + m_bitmapType = BitmapPpm; + else if( str == "pgm" ) + m_bitmapType = BitmapPgm; + else if( str == "png" ) + m_bitmapType = BitmapPng; + else if( str == "jpeg" ) + m_bitmapType = BitmapJpeg; + else if( str == "tiff" ) + m_bitmapType = BitmapTiff; + else if( str == "sys" ) + m_bitmapType = BitmapSys; + + m_bitmapFile = h.stringAttribute( "file_name", bitmapFileDefault ); + m_enableFilterAll = h.boolAttribute( "enable_filter_all", enableFilterAllDefault ); + m_filterAll = h.doubleAttribute( "filter_all", filterAllDefault ); + m_enableTransmitAll = h.boolAttribute( "enable_transmit_all", enableTransmitAllDefault ); + m_transmitAll = h.doubleAttribute( "transmit_all", transmitAllDefault ); + m_once = h.boolAttribute( "once", onceDefault ); + + QDomElement e = h.extraData( ); + if( !e.isNull( ) ) + { + QDomNode c = e.firstChild( ); + while( !c.isNull( ) ) + { + if( c.isElement( ) ) + { + QDomElement ce = c.toElement( ); + if( ce.tagName( ) == "indexed_filters" ) + { + m_filters.clear( ); + QDomNode cd = ce.firstChild( ); + while( !cd.isNull( ) ) + { + if( cd.isElement( ) ) + { + PMPaletteValue pv; + pv.readAttributes( cd.toElement( ) ); + m_filters.append( pv ); + } + cd = cd.nextSibling( ); + } + } + if( ce.tagName( ) == "indexed_transmits" ) + { + m_transmits.clear( ); + QDomNode cd = ce.firstChild( ); + while( !cd.isNull( ) ) + { + if( cd.isElement( ) ) + { + PMPaletteValue pv; + pv.readAttributes( cd.toElement( ) ); + m_transmits.append( pv ); + } + cd = cd.nextSibling( ); + } + } + } + c = c.nextSibling( ); + } + } + + str = h.stringAttribute( "map_type", "planar" ); + if( str == "planar" ) + m_mapType = MapPlanar; + else if( str == "spherical" ) + m_mapType = MapSpherical; + else if( str == "cylindrical" ) + m_mapType = MapCylindrical; + else if( str == "toroidal" ) + m_mapType = MapToroidal; + + str = h.stringAttribute( "interpolate", "none" ); + if( str == "none" ) + m_interpolateType = InterpolateNone; + else if( str == "bilinear" ) + m_interpolateType = InterpolateBilinear; + else if( str == "normalized" ) + m_interpolateType = InterpolateNormalized; + Base::readAttributes( h ); +} + +PMMetaObject* PMImageMap::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "ImageMap", Base::metaObject( ), + createNewImageMap ); + + PMBitmapTypeProperty* bp = new PMBitmapTypeProperty( + "bitmapType", &PMImageMap::setBitmapType, &PMImageMap::bitmapType ); + bp->addEnumValue( "Gif", BitmapGif ); + bp->addEnumValue( "Tga", BitmapTga ); + bp->addEnumValue( "Iff", BitmapIff ); + bp->addEnumValue( "Ppm", BitmapPpm ); + bp->addEnumValue( "Pgm", BitmapPgm ); + bp->addEnumValue( "Png", BitmapPng ); + bp->addEnumValue( "Jpeg", BitmapJpeg ); + bp->addEnumValue( "Tiff", BitmapTiff ); + bp->addEnumValue( "Sys", BitmapSys ); + s_pMetaObject->addProperty( bp ); + + PMInterpolateTypeProperty* ip = new PMInterpolateTypeProperty( + "interpolateType", &PMImageMap::setInterpolateType, + &PMImageMap::interpolateType ); + ip->addEnumValue( "None", InterpolateNone ); + ip->addEnumValue( "Bilinear", InterpolateBilinear ); + ip->addEnumValue( "Normalized", InterpolateNormalized ); + s_pMetaObject->addProperty( ip ); + + PMMapTypeProperty* mp = new PMMapTypeProperty( + "mapType", &PMImageMap::setMapType, &PMImageMap::mapType ); + mp->addEnumValue( "Planar", MapPlanar ); + mp->addEnumValue( "Spherical", MapSpherical ); + mp->addEnumValue( "Cylindrical", MapCylindrical ); + mp->addEnumValue( "Toroidal", MapToroidal ); + s_pMetaObject->addProperty( mp ); + + s_pMetaObject->addProperty( + new PMImageMapProperty( "bitmapFile", &PMImageMap::setBitmapFileName, + &PMImageMap::bitmapFile ) ); + s_pMetaObject->addProperty( + new PMImageMapProperty( "filterAllEnabled", &PMImageMap::enableFilterAll, + &PMImageMap::isFilterAllEnabled ) ); + s_pMetaObject->addProperty( + new PMImageMapProperty( "filterAll", &PMImageMap::setFilterAll, + &PMImageMap::filterAll ) ); + s_pMetaObject->addProperty( + new PMImageMapProperty( "transmitAllEnabled", &PMImageMap::enableTransmitAll, + &PMImageMap::isTransmitAllEnabled ) ); + s_pMetaObject->addProperty( + new PMImageMapProperty( "transmitAll", &PMImageMap::setTransmitAll, + &PMImageMap::transmitAll ) ); + s_pMetaObject->addProperty( + new PMImageMapProperty( "once", &PMImageMap::enableOnce, &PMImageMap::isOnceEnabled ) ); + + // TODO: filters and transmits properties + } + return s_pMetaObject; +} + +void PMImageMap::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMImageMap::description( ) const +{ + return i18n( "imagemap" ); +} + +void PMImageMap::setBitmapType( PMBitmapType c ) +{ + if( c != m_bitmapType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMBitmapTypeID, m_bitmapType ); + m_bitmapType = c; + } +} + +void PMImageMap::setBitmapFileName( const QString& c ) +{ + if( c != m_bitmapFile ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMBitmapFileID, m_bitmapFile ); + m_bitmapFile = c; + } +} + +void PMImageMap::enableFilterAll( bool c ) +{ + if( c != m_enableFilterAll ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableFilterAllID, m_enableFilterAll ); + m_enableFilterAll = c; + } +} + +void PMImageMap::enableTransmitAll( bool c ) +{ + if( c != m_enableTransmitAll ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableTransmitAllID, m_enableTransmitAll ); + m_enableTransmitAll = c; + } +} + +void PMImageMap::setFilterAll( double c ) +{ + if( c != m_filterAll ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFilterAllID, m_filterAll ); + m_filterAll = c; + } +} + +void PMImageMap::setTransmitAll( double c ) +{ + if( c != m_transmitAll ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFilterAllID, m_transmitAll ); + m_transmitAll = c; + } +} + +void PMImageMap::enableOnce( bool c ) +{ + if( c != m_once ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMOnceID, m_once ); + m_once = c; + } +} + +void PMImageMap::setMapType( PMMapType c ) +{ + if( c != m_mapType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMMapTypeID, m_mapType ); + m_mapType = c; + } +} + +void PMImageMap::setInterpolateType( PMInterpolateType c ) +{ + if( c != m_interpolateType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMInterpolateID, m_interpolateType ); + m_interpolateType = c; + } +} + +void PMImageMap::setFilters( const QValueList& c ) +{ + if( m_filters != c ) + { + if( m_pMemento ) + ( ( PMPaletteValueMemento* ) m_pMemento )->setFilterPaletteValues( m_filters ); + m_filters = c; + } +} + +void PMImageMap::setTransmits( const QValueList& c ) +{ + if( m_transmits != c ) + { + if( m_pMemento ) + ( ( PMPaletteValueMemento* ) m_pMemento )->setTransmitPaletteValues( m_transmits ); + m_transmits = c; + } +} + +PMDialogEditBase* PMImageMap::editWidget( QWidget* parent ) const +{ + return new PMImageMapEdit( parent ); +} + +void PMImageMap::restoreMemento( PMMemento* s ) +{ + PMPaletteValueMemento* m = ( PMPaletteValueMemento* ) s; + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMBitmapTypeID: + setBitmapType( ( PMBitmapType )data->intData( ) ); + break; + case PMBitmapFileID: + setBitmapFileName( data->stringData( ) ); + break; + case PMEnableFilterAllID: + enableFilterAll( data->boolData( ) ); + break; + case PMEnableTransmitAllID: + enableTransmitAll( data->boolData( ) ); + break; + case PMFilterAllID: + setFilterAll( data->doubleData( ) ); + break; + case PMTransmitAllID: + setTransmitAll( data->doubleData( ) ); + break; + case PMOnceID: + enableOnce( data->boolData( ) ); + break; + case PMMapTypeID: + setMapType( ( PMMapType )data->intData( ) ); + break; + case PMInterpolateID: + setInterpolateType( ( PMInterpolateType )data->intData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMImageMap::restoreMemento\n"; + break; + } + } + } + + if( m->filterPaletteValuesSaved( ) ) + setFilters( m->filterPaletteValues( ) ); + + if( m->transmitPaletteValuesSaved( ) ) + setTransmits( m->transmitPaletteValues( ) ); + + Base::restoreMemento( s ); +} + diff --git a/kpovmodeler/pmimagemap.h b/kpovmodeler/pmimagemap.h new file mode 100644 index 00000000..3291994d --- /dev/null +++ b/kpovmodeler/pmimagemap.h @@ -0,0 +1,209 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Passos Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMIMAGEMAP_H +#define PMIMAGEMAP_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmnamedobject.h" +#include "pmpalettevalue.h" + +/** + * Class for povray imagemaps. + */ + +class PMImageMap : public PMNamedObject +{ + typedef PMNamedObject Base; +public: + /** + * The bitmap type + */ + enum PMBitmapType { BitmapGif, BitmapTga, BitmapIff, BitmapPpm, + BitmapPgm, BitmapPng, BitmapJpeg, BitmapTiff, + BitmapSys }; + /** + * The interpolate method + */ + enum PMInterpolateType { InterpolateNone, InterpolateBilinear, + InterpolateNormalized }; + /** + * The mapping method + */ + enum PMMapType { MapPlanar, MapSpherical, MapCylindrical, + MapToroidal }; + + /** + * Creates a PMImageMap + */ + PMImageMap( PMPart* part ); + /** + * Copy constructor + */ + PMImageMap( const PMImageMap& im ); + /** + * deletes the PMImageMap + */ + virtual ~PMImageMap( ); + + /** */ + virtual PMObject* copy( ) const { return new PMImageMap( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual QString pixmap( ) const { return QString( "pmimagemap" ); } + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMImageMapEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + + /** + * Gets the bitmap type + */ + PMBitmapType bitmapType( ) const { return m_bitmapType; } + /** + * Gets the bitmap file name + */ + QString bitmapFile( ) const { return m_bitmapFile; } + /** + * Returns true if filter all is enabled + */ + bool isFilterAllEnabled( ) const { return m_enableFilterAll; } + /** + * Gets the value of filter for all colors + */ + double filterAll( ) const { return m_filterAll; } + /** + * Returns true if transmit all is enabled + */ + bool isTransmitAllEnabled( ) const { return m_enableTransmitAll; } + /** + * Gets the value of transmit all for all colors + */ + double transmitAll( ) const { return m_transmitAll; } + /** + * Returns true if once is enabled + */ + bool isOnceEnabled( ) const { return m_once; } + /** + * Gets the bitmap file type + */ + PMMapType mapType( ) const { return m_mapType; } + /** + * Gets the interpolate method type + */ + PMInterpolateType interpolateType( ) const { return m_interpolateType; } + /** + * Gets the list of indexed filters + */ + QValueList filters( ) const { return m_filters; } + /** + * Gets the list of indexed transmits + */ + QValueList transmits( ) const { return m_transmits; } + + /** + * Sets the imagemap type + */ + void setBitmapType( PMBitmapType c ); + /** + * Sets the bitmap file name*/ + void setBitmapFileName( const QString& c ); + /** + * Enables/Disables Filter All + */ + void enableFilterAll( bool c ); + /** + * Sets the filter all value + */ + void setFilterAll( double c ); + /** + * Enables/Disables Transmit All + */ + void enableTransmitAll( bool c ); + /** + * Sets the transmit all value + */ + void setTransmitAll( double c ); + /** + * Sets if the bitmap should be mapped once + */ + void enableOnce( bool c ); + /** + * Sets the mapping method + */ + void setMapType( const PMMapType c ); + /** + * Sets the interpolating method + */ + void setInterpolateType( PMInterpolateType c ); + /** + * Set the list of indexed filters + */ + void setFilters( const QValueList& filters ); + /** + * Set the list of indexed transmits + */ + void setTransmits( const QValueList& transmits ); + /** */ + virtual void restoreMemento( PMMemento* s ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMImageMapMementoID { PMBitmapTypeID, PMBitmapFileID, + PMEnableFilterAllID, + PMEnableTransmitAllID, + PMFilterAllID, PMTransmitAllID, + PMOnceID, PMMapTypeID, + PMInterpolateID }; + /** + * ImageMap type + */ + PMBitmapType m_bitmapType; + QString m_bitmapFile; + bool m_enableFilterAll; + float m_filterAll; + bool m_enableTransmitAll; + float m_transmitAll; + bool m_once; + PMMapType m_mapType; + PMInterpolateType m_interpolateType; + QValueList m_filters; + QValueList m_transmits; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmimagemapedit.cpp b/kpovmodeler/pmimagemapedit.cpp new file mode 100644 index 00000000..c43443df --- /dev/null +++ b/kpovmodeler/pmimagemapedit.cpp @@ -0,0 +1,625 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Passos Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmimagemapedit.h" +#include "pmimagemap.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" +#include "pmpalettevalueedit.h" +#include "pmvector.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +PMImageMapEdit::PMImageMapEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMImageMapEdit::createTopWidgets( ) +{ + QLabel* lbl; + QHBoxLayout* hl; + + Base::createTopWidgets( ); + + hl = new QHBoxLayout( topLayout( ) ); + lbl = new QLabel( i18n( "File type:" ), this ); + m_pImageFileTypeEdit = new QComboBox( this ); + m_pImageFileTypeEdit->insertItem( "gif" ); + m_pImageFileTypeEdit->insertItem( "tga" ); + m_pImageFileTypeEdit->insertItem( "iff" ); + m_pImageFileTypeEdit->insertItem( "ppm" ); + m_pImageFileTypeEdit->insertItem( "pgm" ); + m_pImageFileTypeEdit->insertItem( "png" ); + m_pImageFileTypeEdit->insertItem( "jpeg" ); + m_pImageFileTypeEdit->insertItem( "tiff" ); + m_pImageFileTypeEdit->insertItem( "sys" ); + hl->addWidget( lbl ); + hl->addWidget( m_pImageFileTypeEdit ); + + hl = new QHBoxLayout( topLayout( ) ); + lbl = new QLabel( i18n( "File name:" ), this ); + m_pImageFileNameEdit = new QLineEdit( this ); + m_pImageFileNameBrowse = new QPushButton( this ); + m_pImageFileNameBrowse->setPixmap( SmallIcon( "fileopen" ) ); + hl->addWidget( lbl ); + hl->addWidget( m_pImageFileNameEdit ); + hl->addWidget( m_pImageFileNameBrowse ); + + hl = new QHBoxLayout( topLayout( ) ); + m_pEnableFilterAllEdit = new QCheckBox( i18n( "Filter all" ), this ); + m_pFilterAllEdit = new PMFloatEdit( this ); + hl->addWidget( m_pEnableFilterAllEdit ); + hl->addWidget( m_pFilterAllEdit ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + m_pEnableTransmitAllEdit = new QCheckBox( i18n( "Transmit all" ), this ); + m_pTransmitAllEdit = new PMFloatEdit( this ); + hl->addWidget( m_pEnableTransmitAllEdit ); + hl->addWidget( m_pTransmitAllEdit ); + hl->addStretch( 1 ); + + m_pOnceEdit = new QCheckBox( i18n( "Once" ), this ); + topLayout( )->addWidget( m_pOnceEdit ); + + hl = new QHBoxLayout( topLayout( ) ); + lbl = new QLabel( i18n( "Interpolate:" ), this ); + m_pInterpolateTypeEdit = new QComboBox( this ); + m_pInterpolateTypeEdit->insertItem( i18n( "None" ) ); + m_pInterpolateTypeEdit->insertItem( i18n( "Bilinear" ) ); + m_pInterpolateTypeEdit->insertItem( i18n( "Normalized" ) ); + hl->addWidget( lbl ); + hl->addWidget( m_pInterpolateTypeEdit ); + + hl = new QHBoxLayout( topLayout( ) ); + lbl = new QLabel( i18n( "Map type:" ), this ); + m_pMapTypeEdit = new QComboBox( this ); + m_pMapTypeEdit->insertItem( i18n( "Planar" ) ); + m_pMapTypeEdit->insertItem( i18n( "Spherical" ) ); + m_pMapTypeEdit->insertItem( i18n( "Cylindrical" ) ); + m_pMapTypeEdit->insertItem( i18n( "Toroidal" ) ); + hl->addWidget( lbl ); + hl->addWidget( m_pMapTypeEdit ); + + connect( m_pImageFileTypeEdit, SIGNAL( activated( int ) ), SLOT( slotImageFileTypeChanged( int ) ) ); + connect( m_pMapTypeEdit, SIGNAL( activated( int ) ), SLOT( slotMapTypeChanged( int ) ) ); + connect( m_pInterpolateTypeEdit, SIGNAL( activated( int ) ), SLOT( slotInterpolateTypeChanged( int ) ) ); + connect( m_pImageFileNameBrowse, SIGNAL( clicked( ) ), SLOT( slotImageFileBrowseClicked( ) ) ); + connect( m_pImageFileNameEdit, SIGNAL( textChanged( const QString& ) ), SLOT( slotImageFileNameChanged( const QString& ) ) ); + connect( m_pEnableFilterAllEdit, SIGNAL( clicked( ) ), SLOT( slotFilterAllClicked( ) ) ); + connect( m_pEnableTransmitAllEdit, SIGNAL( clicked( ) ), SLOT( slotTransmitAllClicked( ) ) ); + connect( m_pFilterAllEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pTransmitAllEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pOnceEdit, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMImageMapEdit::createBottomWidgets( ) +{ + topLayout( )->addWidget( new QLabel( i18n( "Indexed filters" ), this ) ); + m_pFiltersWidget = new QWidget( this ); + topLayout( )->addWidget( m_pFiltersWidget ); + topLayout( )->addWidget( new QLabel( i18n( "Indexed transmits" ), this ) ); + m_pTransmitsWidget = new QWidget( this ); + topLayout( )->addWidget( m_pTransmitsWidget ); + + + Base::createBottomWidgets( ); +} + +void PMImageMapEdit::displayObject( PMObject* o ) +{ + bool readOnly; + + if( o->isA( "ImageMap" ) ) + { + m_pDisplayedObject = ( PMImageMap* ) o; + readOnly = m_pDisplayedObject->isReadOnly( ); + + switch( m_pDisplayedObject->bitmapType( ) ) + { + case PMImageMap::BitmapGif: + m_pImageFileTypeEdit->setCurrentItem( 0 ); + break; + case PMImageMap::BitmapTga: + m_pImageFileTypeEdit->setCurrentItem( 1 ); + break; + case PMImageMap::BitmapIff: + m_pImageFileTypeEdit->setCurrentItem( 2 ); + break; + case PMImageMap::BitmapPpm: + m_pImageFileTypeEdit->setCurrentItem( 3 ); + break; + case PMImageMap::BitmapPgm: + m_pImageFileTypeEdit->setCurrentItem( 4 ); + break; + case PMImageMap::BitmapPng: + m_pImageFileTypeEdit->setCurrentItem( 5 ); + break; + case PMImageMap::BitmapJpeg: + m_pImageFileTypeEdit->setCurrentItem( 6 ); + break; + case PMImageMap::BitmapTiff: + m_pImageFileTypeEdit->setCurrentItem( 7 ); + break; + case PMImageMap::BitmapSys: + m_pImageFileTypeEdit->setCurrentItem( 8 ); + break; + } + m_pImageFileTypeEdit->setEnabled( !readOnly ); + + switch( m_pDisplayedObject->interpolateType( ) ) + { + case PMImageMap::InterpolateNone: + m_pInterpolateTypeEdit->setCurrentItem( 0 ); + break; + case PMImageMap::InterpolateBilinear: + m_pInterpolateTypeEdit->setCurrentItem( 1); + break; + case PMImageMap::InterpolateNormalized: + m_pInterpolateTypeEdit->setCurrentItem( 2 ); + break; + } + m_pInterpolateTypeEdit->setEnabled( !readOnly ); + + switch( m_pDisplayedObject->mapType( ) ) + { + case PMImageMap::MapPlanar: + m_pMapTypeEdit->setCurrentItem( 0 ); + break; + case PMImageMap::MapSpherical: + m_pMapTypeEdit->setCurrentItem( 1 ); + break; + case PMImageMap::MapCylindrical: + m_pMapTypeEdit->setCurrentItem( 2 ); + break; + case PMImageMap::MapToroidal: + m_pMapTypeEdit->setCurrentItem( 3 ); + break; + } + m_pMapTypeEdit->setEnabled( !readOnly ); + + m_pImageFileNameEdit->setText( m_pDisplayedObject->bitmapFile( ) ); + m_pImageFileNameEdit->setEnabled( !readOnly ); + m_pOnceEdit->setChecked( m_pDisplayedObject->isOnceEnabled( ) ); + m_pOnceEdit->setEnabled( !readOnly ); + m_pEnableFilterAllEdit->setChecked( m_pDisplayedObject->isFilterAllEnabled( ) ); + m_pEnableFilterAllEdit->setEnabled( !readOnly ); + m_pFilterAllEdit->setValue( m_pDisplayedObject->filterAll( ) ); + m_pFilterAllEdit->setReadOnly( readOnly ); + m_pEnableTransmitAllEdit->setChecked( m_pDisplayedObject->isTransmitAllEnabled( ) ); + m_pEnableTransmitAllEdit->setEnabled( !readOnly ); + m_pTransmitAllEdit->setValue( m_pDisplayedObject->transmitAll( ) ); + m_pTransmitAllEdit->setReadOnly( readOnly ); + + displayPaletteEntries( m_pDisplayedObject->filters( ), m_pDisplayedObject->transmits( ) ); + + slotFilterAllClicked( ); + slotTransmitAllClicked( ); + + Base::displayObject( o ); + } + +} + +void PMImageMapEdit::displayPaletteEntries( const QValueList& filters, + const QValueList& transmits ) +{ + bool readOnly = m_pDisplayedObject->isReadOnly( ); + + int nfilters = ( int ) filters.count( ); + int ntransmits = ( int ) transmits.count( ); + + int i; + PMPaletteValueEdit* edit; + QPushButton* button; + QGridLayout* gl; + QPixmap addButtonPixmap = SmallIcon( "pmaddpoint" ); + QPixmap removeButtonPixmap = SmallIcon( "pmremovepoint" ); + + // First let's deal with the filter entries... + if( m_pFiltersWidget->layout( ) ) + delete m_pFiltersWidget->layout( ); + + m_filterEntries.setAutoDelete( true ); + m_filterAddButtons.setAutoDelete( true ); + m_filterRemoveButtons.setAutoDelete( true ); + m_filterEntries.clear( ); + m_filterAddButtons.clear( ); + m_filterRemoveButtons.clear( ); + m_filterEntries.setAutoDelete( false ); + m_filterAddButtons.setAutoDelete( false ); + m_filterRemoveButtons.setAutoDelete( false ); + + gl = new QGridLayout( m_pFiltersWidget, nfilters + 1, 3, 0, KDialog::spacingHint( ) ); + + button = new QPushButton( m_pFiltersWidget ); + button->setPixmap( addButtonPixmap ); + m_filterAddButtons.append( button ); + connect( button, SIGNAL( clicked( ) ), SLOT( slotAddFilterEntry( ) ) ); + gl->addWidget( button, 0, 1 ); + button->show( ); + button->setEnabled( !readOnly ); + QToolTip::add( button, i18n( "Add new filter" ) ); + + for( i = 0; i < nfilters; i ++ ) + { + edit = new PMPaletteValueEdit( m_pFiltersWidget ); + m_filterEntries.append( edit ); + connect( edit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + gl->addWidget( edit, i+1, 0 ); + edit->setIndex( filters[ i ].index( ) ); + edit->setValue( filters[ i ].value( ) ); + edit->show( ); + edit->setReadOnly( readOnly ); + + button = new QPushButton( m_pFiltersWidget ); + button->setPixmap( addButtonPixmap ); + m_filterAddButtons.append( button ); + connect( button, SIGNAL( clicked( ) ), SLOT( slotAddFilterEntry( ) ) ); + gl->addWidget( button, i+1, 1 ); + button->show( ); + button->setEnabled( !readOnly ); + QToolTip::add( button, i18n( "Add new filter" ) ); + + button = new QPushButton( m_pFiltersWidget ); + button->setPixmap( removeButtonPixmap ); + m_filterRemoveButtons.append( button ); + connect( button, SIGNAL( clicked( ) ), SLOT( slotRemoveFilterEntry( ) ) ); + gl->addWidget( button, i+1, 2 ); + button->show( ); + button->setEnabled( !readOnly ); + QToolTip::add( button, i18n( "Remove filter" ) ); + } + + // ...next the transmit entries + m_transmitEntries.setAutoDelete( true ); + m_transmitAddButtons.setAutoDelete( true ); + m_transmitRemoveButtons.setAutoDelete( true ); + m_transmitEntries.clear( ); + m_transmitAddButtons.clear( ); + m_transmitRemoveButtons.clear( ); + m_transmitEntries.setAutoDelete( false ); + m_transmitAddButtons.setAutoDelete( false ); + m_transmitRemoveButtons.setAutoDelete( false ); + + // recreate the entry edits + if( m_pTransmitsWidget->layout( ) ) + delete m_pTransmitsWidget->layout( ); + + gl = new QGridLayout( m_pTransmitsWidget, ntransmits + 1, 3, 0, KDialog::spacingHint( ) ); + + button = new QPushButton( m_pTransmitsWidget ); + button->setPixmap( addButtonPixmap ); + m_transmitAddButtons.append( button ); + connect( button, SIGNAL( clicked( ) ), SLOT( slotAddTransmitEntry( ) ) ); + gl->addWidget( button, 0, 1 ); + button->show( ); + button->setEnabled( !readOnly ); + QToolTip::add( button, i18n( "Add new transmit" ) ); + + for( i = 0; i < ntransmits; i ++ ) + { + edit = new PMPaletteValueEdit( m_pTransmitsWidget ); + m_transmitEntries.append( edit ); + connect( edit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + gl->addWidget( edit, i+1, 0 ); + edit->setIndex( transmits[ i ].index( ) ); + edit->setValue( transmits[ i ].value( ) ); + edit->show( ); + edit->setReadOnly( readOnly ); + + button = new QPushButton( m_pTransmitsWidget ); + button->setPixmap( addButtonPixmap ); + m_transmitAddButtons.append( button ); + connect( button, SIGNAL( clicked( ) ), SLOT( slotAddTransmitEntry( ) ) ); + gl->addWidget( button, i+1, 1 ); + button->show( ); + button->setEnabled( !readOnly ); + QToolTip::add( button, i18n( "Add new transmit" ) ); + + button = new QPushButton( m_pTransmitsWidget ); + button->setPixmap( removeButtonPixmap ); + m_transmitRemoveButtons.append( button ); + connect( button, SIGNAL( clicked( ) ), SLOT( slotRemoveTransmitEntry( ) ) ); + gl->addWidget( button, i+1, 2 ); + button->show( ); + button->setEnabled( !readOnly ); + QToolTip::add( button, i18n( "Remove transmit" ) ); + } +} + +void PMImageMapEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + switch( m_pImageFileTypeEdit->currentItem( ) ) + { + case 0: + m_pDisplayedObject->setBitmapType( PMImageMap::BitmapGif ); + break; + case 1: + m_pDisplayedObject->setBitmapType( PMImageMap::BitmapTga ); + break; + case 2: + m_pDisplayedObject->setBitmapType( PMImageMap::BitmapIff ); + break; + case 3: + m_pDisplayedObject->setBitmapType( PMImageMap::BitmapPpm ); + break; + case 4: + m_pDisplayedObject->setBitmapType( PMImageMap::BitmapPgm ); + break; + case 5: + m_pDisplayedObject->setBitmapType( PMImageMap::BitmapPng ); + break; + case 6: + m_pDisplayedObject->setBitmapType( PMImageMap::BitmapJpeg ); + break; + case 7: + m_pDisplayedObject->setBitmapType( PMImageMap::BitmapTiff ); + break; + case 8: + m_pDisplayedObject->setBitmapType( PMImageMap::BitmapSys ); + break; + } + + switch( m_pInterpolateTypeEdit->currentItem( ) ) + { + case 0: + m_pDisplayedObject->setInterpolateType( PMImageMap::InterpolateNone ); + break; + case 1: + m_pDisplayedObject->setInterpolateType( PMImageMap::InterpolateBilinear ); + break; + case 2: + m_pDisplayedObject->setInterpolateType( PMImageMap::InterpolateNormalized ); + break; + } + + switch( m_pMapTypeEdit->currentItem( ) ) + { + case 0: + m_pDisplayedObject->setMapType( PMImageMap::MapPlanar ); + break; + case 1: + m_pDisplayedObject->setMapType( PMImageMap::MapSpherical ); + break; + case 2: + m_pDisplayedObject->setMapType( PMImageMap::MapCylindrical ); + break; + case 3: + m_pDisplayedObject->setMapType( PMImageMap::MapToroidal ); + break; + } + + m_pDisplayedObject->setFilters( filters( ) ); + m_pDisplayedObject->setTransmits( transmits( ) ); + + m_pDisplayedObject->setBitmapFileName( m_pImageFileNameEdit->text( ) ); + m_pDisplayedObject->enableFilterAll( m_pEnableFilterAllEdit->isChecked( ) ); + m_pDisplayedObject->setFilterAll( m_pFilterAllEdit->value( ) ); + m_pDisplayedObject->enableTransmitAll( m_pEnableTransmitAllEdit->isChecked( ) ); + m_pDisplayedObject->setTransmitAll( m_pTransmitAllEdit->value( ) ); + m_pDisplayedObject->enableOnce( m_pOnceEdit->isChecked( ) ); + } +} + +bool PMImageMapEdit::isDataValid( ) +{ + if( !m_pFilterAllEdit->isDataValid( ) ) return false; + if( !m_pTransmitAllEdit->isDataValid( ) ) return false; + + QPtrListIterator it_filters( m_filterEntries ); + for( ; it_filters.current( ); ++it_filters ) + if( !( it_filters.current( )->isDataValid( ) ) ) + return false; + + QPtrListIterator it_transmits( m_transmitEntries ); + for( ; it_transmits.current( ); ++it_transmits ) + if( !( it_transmits.current( )->isDataValid( ) ) ) + return false; + + return Base::isDataValid( ); +} + +void PMImageMapEdit::slotInterpolateTypeChanged( const int /*a*/ ) +{ + emit dataChanged( ); +} + +void PMImageMapEdit::slotImageFileTypeChanged( const int /*a*/ ) +{ + emit dataChanged( ); +} + +void PMImageMapEdit::slotMapTypeChanged( const int /*a*/ ) +{ + emit dataChanged( ); +} + +void PMImageMapEdit::slotImageFileNameChanged( const QString& /*a*/ ) +{ + emit dataChanged( ); +} + +void PMImageMapEdit::slotImageFileBrowseClicked( ) +{ + QString str = KFileDialog::getOpenFileName( QString::null, QString::null ); + + if( !str.isEmpty() ) + { + m_pImageFileNameEdit->setText( str ); + emit dataChanged( ); + } +} + +void PMImageMapEdit::slotFilterAllClicked( ) +{ + if( m_pEnableFilterAllEdit->isChecked( ) ) + m_pFilterAllEdit->setEnabled( true ); + else + m_pFilterAllEdit->setEnabled( false ); + emit sizeChanged( ); + emit dataChanged( ); +} + +void PMImageMapEdit::slotTransmitAllClicked( ) +{ + if( m_pEnableTransmitAllEdit->isChecked( ) ) + m_pTransmitAllEdit->setEnabled( true ); + else + m_pTransmitAllEdit->setEnabled( false ); + emit sizeChanged( ); + emit dataChanged( ); +} + +QValueList PMImageMapEdit::filters( ) +{ + QValueList entries; + QPtrListIterator it( m_filterEntries ); + + for( ; it.current( ); ++it ) + entries.append( PMPaletteValue( it.current( )->index( ), it.current( )->value( ) ) ); + + return entries; +} + +QValueList PMImageMapEdit::transmits( ) +{ + QValueList entries; + QPtrListIterator it( m_transmitEntries ); + + for( ; it.current( ); ++it ) + entries.append( PMPaletteValue( it.current( )->index( ), it.current( )->value( ) ) ); + + return entries; +} + +void PMImageMapEdit::slotAddFilterEntry( ) +{ + QValueList entriesFilters; + QValueListIterator it; + PMPaletteValue newEntry; + QPushButton* button = ( QPushButton* ) sender( ); + + if( button ) + { + int index = m_filterAddButtons.findRef( button ); + if( index >= 0 ) + { + entriesFilters = filters( ); + if( index == 0 ) + entriesFilters.prepend( newEntry ); + else + { + it = entriesFilters.at( index ); + entriesFilters.insert( it, newEntry ); + } + displayPaletteEntries( entriesFilters, transmits( ) ); + emit sizeChanged( ); + emit dataChanged( ); + } + } +} + +void PMImageMapEdit::slotRemoveFilterEntry( ) +{ + QValueList entriesFilters; + QValueListIterator it; + QPushButton* button = ( QPushButton* ) sender( ); + + if( button ) + { + int index = m_filterRemoveButtons.findRef( button ); + if( index >= 0 ) + { + entriesFilters = filters( ); + it = entriesFilters.at( index ); + entriesFilters.remove( it ); + displayPaletteEntries( entriesFilters, transmits( ) ); + emit sizeChanged( ); + emit dataChanged( ); + } + } +} + +void PMImageMapEdit::slotAddTransmitEntry( ) +{ + QValueList entriesTransmits; + QValueListIterator it; + PMPaletteValue newEntry; + QPushButton* button = ( QPushButton* ) sender( ); + + if( button ) + { + int index = m_transmitAddButtons.findRef( button ); + if( index >= 0 ) + { + entriesTransmits = transmits( ); + if( index == 0 ) + entriesTransmits.prepend( newEntry ); + else + { + it = entriesTransmits.at( index ); + entriesTransmits.insert( it, newEntry ); + } + displayPaletteEntries( filters( ), entriesTransmits ); + emit sizeChanged( ); + emit dataChanged( ); + } + } +} + +void PMImageMapEdit::slotRemoveTransmitEntry( ) +{ + QValueList entriesTransmits; + QValueListIterator it; + QPushButton* button = ( QPushButton* ) sender( ); + + if( button ) + { + int index = m_transmitRemoveButtons.findRef( button ); + if( index >= 0 ) + { + entriesTransmits = transmits( ); + it = entriesTransmits.at( index ); + entriesTransmits.remove( it ); + displayPaletteEntries( filters( ), entriesTransmits ); + emit sizeChanged( ); + emit dataChanged( ); + } + } +} + +#include "pmimagemapedit.moc" diff --git a/kpovmodeler/pmimagemapedit.h b/kpovmodeler/pmimagemapedit.h new file mode 100644 index 00000000..86055ea2 --- /dev/null +++ b/kpovmodeler/pmimagemapedit.h @@ -0,0 +1,121 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Passos Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMIMAGEMAPEDIT_H +#define PMIMAGEMAPEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmpalettevalueedit.h" +#include "pmdialogeditbase.h" + +class PMImageMap; +class PMPaletteValue; +class PMVectorEdit; +class QComboBox; +class PMFloatEdit; +class PMIntEdit; +class QLabel; +class QCheckBox; +class QWidget; +class QLineEdit; +class QPushButton; + +/** + * Dialog edit class for @ref PMImageMap. + */ +class PMImageMapEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMImageMapEdit with parent and name + */ + PMImageMapEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void createBottomWidgets( ); + /** */ + virtual void saveContents( ); + /** */ + QValueList filters( ); + /** */ + QValueList transmits( ); + /** */ + void displayPaletteEntries( const QValueList& filters, + const QValueList& transmits ); + +private slots: + /** */ + void slotImageFileTypeChanged( int a ); + /** */ + void slotMapTypeChanged( int a ); + /** */ + void slotInterpolateTypeChanged( int a ); + /** */ + void slotImageFileNameChanged( const QString& a ); + /** */ + void slotImageFileBrowseClicked( ); + /** */ + void slotFilterAllClicked( ); + /** */ + void slotTransmitAllClicked( ); + /** */ + void slotAddFilterEntry( ); + /** */ + void slotRemoveFilterEntry( ); + /** */ + void slotAddTransmitEntry( ); + /** */ + void slotRemoveTransmitEntry( ); +private: + PMImageMap* m_pDisplayedObject; + QComboBox* m_pImageFileTypeEdit; + QLineEdit* m_pImageFileNameEdit; + QPushButton* m_pImageFileNameBrowse; + QCheckBox* m_pOnceEdit; + QComboBox* m_pMapTypeEdit; + QComboBox* m_pInterpolateTypeEdit; + QCheckBox* m_pEnableFilterAllEdit; + QCheckBox* m_pEnableTransmitAllEdit; + PMFloatEdit* m_pFilterAllEdit; + PMFloatEdit* m_pTransmitAllEdit; + QWidget* m_pFiltersWidget; + QWidget* m_pTransmitsWidget; + + QPtrList m_filterEntries; + QPtrList m_filterAddButtons; + QPtrList m_filterRemoveButtons; + QPtrList m_transmitEntries; + QPtrList m_transmitAddButtons; + QPtrList m_transmitRemoveButtons; +}; + +#endif diff --git a/kpovmodeler/pminserterrordialog.cpp b/kpovmodeler/pminserterrordialog.cpp new file mode 100644 index 00000000..766db20a --- /dev/null +++ b/kpovmodeler/pminserterrordialog.cpp @@ -0,0 +1,51 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pminserterrordialog.h" +#include +#include +#include +#include + +PMInsertErrorDialog::PMInsertErrorDialog( + int numObj, int numErrors, + const QStringList& details, + QWidget* parent /*= 0*/, const char* name /*= 0*/ ) + : KDialogBase( parent, name, true, i18n( "Insert Errors" ), + Help | Ok | User1, Ok, false, i18n( "Details" ) ) +{ + QVBox* page = makeVBoxMainWidget( ); + new QLabel( i18n( "%1 of %2 objects couldn't be inserted." ) + .arg( numErrors ).arg( numObj ), page ); + + m_pDetailsLabel = new QLabel( i18n( "Objects not inserted:" ), page ); + m_pDetailsLabel->hide( ); + + m_pDetails = new QListBox( page ); + m_pDetails->insertStringList( details, 0 ); + m_pDetails->setMinimumHeight( 150 ); + m_pDetails->hide( ); + +} + +void PMInsertErrorDialog::slotUser1( ) +{ + m_pDetailsLabel->show( ); + m_pDetails->show( ); +} +#include "pminserterrordialog.moc" diff --git a/kpovmodeler/pminserterrordialog.h b/kpovmodeler/pminserterrordialog.h new file mode 100644 index 00000000..d94be0f6 --- /dev/null +++ b/kpovmodeler/pminserterrordialog.h @@ -0,0 +1,54 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMINSERTERRORDIALOG_H +#define PMINSERTERRORDIALOG_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +class QListBox; +class QLabel; + +/** + * Dialog that is shown if not all objects could be inserted + during the execution of a command */ +class PMInsertErrorDialog : public KDialogBase +{ + Q_OBJECT +public: + /** + * Creates a modal PMInsertErrorDialog with parent and name. + */ + PMInsertErrorDialog( int NumberOfObjects, int NumberOfInsertErrors, + const QStringList& details, + QWidget* parent = 0, const char* name = 0 ); +protected slots: + void slotUser1( ); + +private: + QListBox* m_pDetails; + QLabel* m_pDetailsLabel; +}; + +#endif diff --git a/kpovmodeler/pminsertpopup.cpp b/kpovmodeler/pminsertpopup.cpp new file mode 100644 index 00000000..be6a527d --- /dev/null +++ b/kpovmodeler/pminsertpopup.cpp @@ -0,0 +1,90 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pminsertpopup.h" +#include +#include +#include + +PMInsertPopup::PMInsertPopup( QWidget* parent, bool multipleObjects, + int items, bool canInsertAllAsFirstChildren, + bool canInsertAllAsLastChildren, + bool canInsertAllAsSiblings, const char* name ) + : KPopupMenu( parent, name ) +{ + QString itemText; + if( multipleObjects ) + { + insertTitle( i18n( "Insert Objects As" ) ); + if( ( items & PMIFirstChild ) == PMIFirstChild ) + { + itemText = i18n( "First Children" ); + if( !canInsertAllAsFirstChildren ) + itemText += " (" + i18n( "some" ) + ")"; + insertItem( SmallIcon( "pminsertfirstchild" ), + itemText, PMIFirstChild ); + } + if( ( items & PMILastChild ) == PMILastChild ) + { + itemText = i18n( "Last Children" ); + if( !canInsertAllAsLastChildren ) + itemText += " (" + i18n( "some" ) + ")"; + insertItem( SmallIcon( "pminsertlastchild" ), + itemText, PMILastChild ); + } + if( ( items & PMISibling ) == PMISibling ) + { + itemText = i18n( "Siblings" ); + if( !canInsertAllAsSiblings ) + itemText += " (" + i18n( "some" ) + ")"; + insertItem( SmallIcon( "pminsertsibling" ), + itemText, PMISibling ); + } + } + else + { + insertTitle( i18n( "Insert Object As" ) ); + if( ( items & PMIFirstChild ) == PMIFirstChild ) + insertItem( SmallIcon( "pminsertfirstchild" ), + i18n( "First Child" ), PMIFirstChild ); + if( ( items & PMILastChild ) == PMILastChild ) + insertItem( SmallIcon( "pminsertlastchild" ), + i18n( "Last Child" ), PMILastChild ); + if( ( items & PMISibling ) == PMISibling ) + insertItem( SmallIcon( "pminsertsibling" ), + i18n( "Sibling" ), PMISibling ); + } +} + +int PMInsertPopup::choosePlace( QWidget* parent, bool multipleObjects, + int items, bool canInsertAllAsFirstChildren, + bool canInsertAllAsLastChildren, + bool canInsertAllAsSiblings ) +{ + int result; + PMInsertPopup* popup = new PMInsertPopup( parent, multipleObjects, items, + canInsertAllAsFirstChildren, + canInsertAllAsLastChildren, + canInsertAllAsSiblings ); + result = popup->exec( QCursor::pos( ) ); + if( result < 0 ) + result = 0; + delete popup; + + return result; +} diff --git a/kpovmodeler/pminsertpopup.h b/kpovmodeler/pminsertpopup.h new file mode 100644 index 00000000..c5e99dac --- /dev/null +++ b/kpovmodeler/pminsertpopup.h @@ -0,0 +1,81 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMINSERTPOPUP_H +#define PMINSERTPOPUP_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +/** + * Popup menu. Ask the user where to insert new objects + */ +class PMInsertPopup : public KPopupMenu +{ +public: + /** + * Places where a new object can be inserted + */ + enum { PMIFirstChild = 1, PMILastChild = 2, PMISibling = 4 }; + /** + * Creates a popup menu + * + * @param parent The parent widget + * @param multipleObjects True if more than one object will be inserted + * @param items Which items to display. Can be a bitwise combination + * of PMIFirstChild, PMILastChild, PMISibling. + * @param name Internal name of the popup menu + */ + PMInsertPopup( QWidget* parent, bool multipleObjects, + int items = PMIFirstChild | PMILastChild | PMISibling, + bool canInsertAllAsFirstChildren = true, + bool canInsertAllAsLastChildren = true, + bool canInsertAllAsSiblings = true, + const char* name = 0 ); + /** + * Deletes the popup menu + */ + ~PMInsertPopup( ) { }; + + /** + * Popups a PMInsertPopup menu + * + * @param parent The parent widget + * @param multipleObjects True if more than one object will be inserted + * @param items Which items to display. Can be a bitwise combination + * of PMIFirstChild, PMILastChild, PMISibling. + * @param canInsertAllAsChildren If false the text "(some)" will appear + * behind the "first Children" and "last Children" items + * @param canInsertAllAsSiblings If false the text "(some)" will appear + * behind the "Siblings" items + * + * Returns the selected item or 0 if no item was selected. + */ + static int choosePlace( QWidget* parent, bool multipleObjects, + int items = PMIFirstChild | PMILastChild + | PMISibling, + bool canInsertAllAsFirstChildren = true, + bool canInsertAllAsLastChildren = true, + bool canInsertAllAsSiblings = true ); +}; + +#endif diff --git a/kpovmodeler/pminsertrules.dtd b/kpovmodeler/pminsertrules.dtd new file mode 100644 index 00000000..a3c2128c --- /dev/null +++ b/kpovmodeler/pminsertrules.dtd @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kpovmodeler/pminsertrulesystem.cpp b/kpovmodeler/pminsertrulesystem.cpp new file mode 100644 index 00000000..0e7b7be2 --- /dev/null +++ b/kpovmodeler/pminsertrulesystem.cpp @@ -0,0 +1,1061 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pminsertrulesystem.h" +#include "pmprototypemanager.h" +#include "pmpart.h" +#include "pmvariant.h" +#include "pmdebug.h" + +#include +#include + +bool isCategory( QDomElement& e ) +{ + return( e.tagName( ) == "class" || e.tagName( ) == "group" ); +} + +PMRuleCategory* newCategory( QDomElement& e, + QPtrList& globalGroups, + QPtrList& localGroups ) +{ + if( e.tagName( ) == "class" ) + return new PMRuleClass( e ); + if( e.tagName( ) == "group" ) + return new PMRuleGroup( e, globalGroups, localGroups ); + return 0; +} + +PMPrototypeManager* PMRuleClass::s_pPrototypeManager = 0; + +PMRuleClass::PMRuleClass( QDomElement& e ) + : PMRuleCategory( ) +{ + m_pPrototypeManager = s_pPrototypeManager; + m_className = e.attribute( "name" ); + if( m_className.isEmpty( ) ) + kdError( PMArea ) << "RuleSystem: Invalid class name" << endl; + if( !m_pPrototypeManager->existsClass( m_className ) ) + kdError( PMArea ) << "RuleSystem: Unknown class: " + << m_className << endl; +} + +bool PMRuleClass::matches( const QString& className ) +{ + return m_pPrototypeManager->isA( className, m_className ); +} + +PMRuleGroup::PMRuleGroup( QDomElement& e, + QPtrList& globalGroups, + QPtrList& localGroups ) + : PMRuleCategory( ) +{ + m_pGroup = 0; + QString groupName = e.attribute( "name" ); + if( groupName.isEmpty( ) ) + kdError( PMArea ) << "RuleSystem: Invalid group name" << endl; + // find group + QPtrListIterator lit( localGroups ); + for( ; lit.current( ) && !m_pGroup; ++lit ) + if( lit.current( )->name( ) == groupName ) + m_pGroup = lit.current( ); + QPtrListIterator git( globalGroups ); + for( ; git.current( ) && !m_pGroup; ++git ) + if( git.current( )->name( ) == groupName ) + m_pGroup = git.current( ); + if( !m_pGroup ) + kdError( PMArea ) << "RuleSystem: Group not defined: " + << groupName << endl; +} + +bool PMRuleGroup::matches( const QString& className ) +{ + if( m_pGroup ) + return m_pGroup->matches( className ); + return false; +} + +PMRuleDefineGroup::PMRuleDefineGroup( QDomElement& e, + QPtrList& globalGroups, + QPtrList& localGroups ) +{ + m_name = e.attribute( "name" ); + if( m_name.isEmpty( ) ) + kdError( PMArea ) << "RuleSystem: Invalid group name" << endl; + + QDomNode m = e.firstChild( ); + while( !m.isNull( ) ) + { + if( m.isElement( ) ) + { + QDomElement me = m.toElement( ); + if( isCategory( me ) ) + m_categories.append( newCategory( me, globalGroups, localGroups ) ); + } + m = m.nextSibling( ); + } +} + +PMRuleDefineGroup::~PMRuleDefineGroup( ) +{ + m_categories.setAutoDelete( true ); + m_categories.clear( ); +} + +bool PMRuleDefineGroup::matches( const QString& className ) +{ + bool m = false; + QPtrListIterator it( m_categories ); + for( ; it.current( ) && !m; ++it ) + m = it.current( )->matches( className ); + return m; +} + + +bool isValue( QDomElement& e ) +{ + return( e.tagName( ) == "property" || e.tagName( ) == "const" || + e.tagName( ) == "count" ); +} + +bool isCondition( QDomElement& e ) +{ + return( e.tagName( ) == "not" || e.tagName( ) == "and" || + e.tagName( ) == "or" || e.tagName( ) == "before" || + e.tagName( ) == "after" || e.tagName( ) == "contains" || + e.tagName( ) == "greater" || e.tagName( ) == "less" || + e.tagName( ) == "equal" ); +} + +PMRuleValue* newValue( QDomElement& e, + QPtrList& globalGroups, + QPtrList& localGroups ) +{ + if( e.tagName( ) == "property" ) + return new PMRuleProperty( e ); + if( e.tagName( ) == "const" ) + return new PMRuleConstant( e ); + if( e.tagName( ) == "count" ) + return new PMRuleCount( e, globalGroups, localGroups ); + return 0; +} + +PMRuleCondition* newCondition( QDomElement& e, + QPtrList& globalGroups, + QPtrList& localGroups ) +{ + if( e.tagName( ) == "not" ) + return new PMRuleNot( e, globalGroups, localGroups ); + if( e.tagName( ) == "and" ) + return new PMRuleAnd( e, globalGroups, localGroups ); + if( e.tagName( ) == "or" ) + return new PMRuleOr( e, globalGroups, localGroups ); + if( e.tagName( ) == "before" ) + return new PMRuleBefore( e, globalGroups, localGroups ); + if( e.tagName( ) == "after" ) + return new PMRuleAfter( e, globalGroups, localGroups ); + if( e.tagName( ) == "contains" ) + return new PMRuleContains( e, globalGroups, localGroups ); + if( e.tagName( ) == "greater" ) + return new PMRuleGreater( e, globalGroups, localGroups ); + if( e.tagName( ) == "less" ) + return new PMRuleLess( e, globalGroups, localGroups ); + if( e.tagName( ) == "equal" ) + return new PMRuleEqual( e, globalGroups, localGroups ); + return 0; +} + +PMRuleBase::~PMRuleBase( ) +{ + m_children.setAutoDelete( true ); + m_children.clear( ); +} + +void PMRuleBase::countChild( const QString& className, bool afterInsertPoint ) +{ + countChildProtected( className, afterInsertPoint ); + + QPtrListIterator it( m_children ); + for( ; it.current( ); ++it ) + it.current( )->countChild( className, afterInsertPoint ); +} + +void PMRuleBase::reset( ) +{ + resetProtected( ); + + QPtrListIterator it( m_children ); + for( ; it.current( ); ++it ) + it.current( )->reset( ); +} + +PMRuleProperty::PMRuleProperty( QDomElement& e ) + : PMRuleValue( ) +{ + m_property = e.attribute( "name" ); + if( m_property.isNull( ) ) + kdError( PMArea ) << "RuleSystem: Invalid property name" << endl; +} + +PMVariant PMRuleProperty::evaluate( const PMObject* o ) +{ + PMVariant v = o->property( m_property ); + if( v.isNull( ) ) + kdError( PMArea ) << "RuleSystem: Invalid property name: " + << m_property << endl; + return v; +} + + +PMRuleConstant::PMRuleConstant( QDomElement& e ) + : PMRuleValue( ) +{ + QString v = e.attribute( "value" ); + if( v.isNull( ) ) + kdError( PMArea ) << "RuleSystem: Invalid value" << endl; + + m_value = PMVariant( v ); +} + +PMVariant PMRuleConstant::evaluate( const PMObject* ) +{ + return m_value; +} + +bool PMRuleConstant::convertTo( PMVariant::PMVariantDataType type ) +{ + return m_value.convertTo( type ); +} + + +PMRuleCount::PMRuleCount( QDomElement& e, + QPtrList& globalGroups, + QPtrList& localGroups ) + : PMRuleValue( ) +{ + m_number = 0; + QDomNode m = e.firstChild( ); + while( !m.isNull( ) ) + { + if( m.isElement( ) ) + { + QDomElement me = m.toElement( ); + if( isCategory( me ) ) + m_categories.append( newCategory( me, globalGroups, localGroups ) ); + } + m = m.nextSibling( ); + } +} + +PMRuleCount::~PMRuleCount( ) +{ + m_categories.setAutoDelete( true ); + m_categories.clear( ); +} + +PMVariant PMRuleCount::evaluate( const PMObject* ) +{ + return PMVariant( m_number ); +} + +void PMRuleCount::countChildProtected( const QString& className, bool ) +{ + bool m = false; + QPtrListIterator it( m_categories ); + for( ; it.current( ) && !m; ++it ) + m = it.current( )->matches( className ); + if( m ) + m_number++; +} + +void PMRuleCount::resetProtected( ) +{ + m_number = 0; +} + +PMRuleNot::PMRuleNot( QDomElement& e, + QPtrList& globalGroups, + QPtrList& localGroups ) + : PMRuleCondition( ) +{ + m_pChild = 0; + QDomNode m = e.firstChild( ); + while( !m.isNull( ) && !m_pChild ) + { + if( m.isElement( ) ) + { + QDomElement me = m.toElement( ); + if( isCondition( me ) ) + { + m_pChild = newCondition( me, globalGroups, localGroups ); + m_children.append( m_pChild ); + } + } + m = m.nextSibling( ); + } +} + +bool PMRuleNot::evaluate( const PMObject* object ) +{ + if( m_pChild ) + return !m_pChild->evaluate( object ); + return true; +} + +PMRuleAnd::PMRuleAnd( QDomElement& e, + QPtrList& globalGroups, + QPtrList& localGroups ) + : PMRuleCondition( ) +{ + QDomNode m = e.firstChild( ); + while( !m.isNull( ) ) + { + if( m.isElement( ) ) + { + QDomElement me = m.toElement( ); + if( isCondition( me ) ) + { + PMRuleCondition* c = newCondition( me, globalGroups, localGroups ); + m_children.append( c ); + m_conditions.append( c ); + } + } + m = m.nextSibling( ); + } +} + +bool PMRuleAnd::evaluate( const PMObject* object ) +{ + bool b = true; + QPtrListIterator it( m_conditions ); + for( ; it.current( ) && b; ++it ) + b = it.current( )->evaluate( object ); + return b; +} + +PMRuleOr::PMRuleOr( QDomElement& e, + QPtrList& globalGroups, + QPtrList& localGroups ) + : PMRuleCondition( ) +{ + QDomNode m = e.firstChild( ); + while( !m.isNull( ) ) + { + if( m.isElement( ) ) + { + QDomElement me = m.toElement( ); + if( isCondition( me ) ) + { + PMRuleCondition* c = newCondition( me, globalGroups, localGroups ); + m_children.append( c ); + m_conditions.append( c ); + } + } + m = m.nextSibling( ); + } +} + +bool PMRuleOr::evaluate( const PMObject* object ) +{ + bool b = false; + QPtrListIterator it( m_conditions ); + for( ; it.current( ) && !b; ++it ) + b = it.current( )->evaluate( object ); + return b; +} + +PMRuleBefore::PMRuleBefore( QDomElement& e, + QPtrList& globalGroups, + QPtrList& localGroups ) + : PMRuleCondition( ) +{ + m_contains = false; + QDomNode m = e.firstChild( ); + while( !m.isNull( ) ) + { + if( m.isElement( ) ) + { + QDomElement me = m.toElement( ); + if( isCategory( me ) ) + m_categories.append( newCategory( me, globalGroups, localGroups ) ); + } + m = m.nextSibling( ); + } +} + +PMRuleBefore::~PMRuleBefore( ) +{ + m_categories.setAutoDelete( true ); + m_categories.clear( ); +} + +bool PMRuleBefore::evaluate( const PMObject* ) +{ + return m_contains; +} + +void PMRuleBefore::countChildProtected( const QString& className, + bool afterInsertPoint ) +{ + if( afterInsertPoint && !m_contains ) + { + QPtrListIterator it( m_categories ); + for( ; it.current( ) && !m_contains; ++it ) + m_contains = it.current( )->matches( className ); + } +} + +void PMRuleBefore::resetProtected( ) +{ + m_contains = false; +} + +PMRuleAfter::PMRuleAfter( QDomElement& e, + QPtrList& globalGroups, + QPtrList& localGroups ) + : PMRuleCondition( ) +{ + m_contains = false; + QDomNode m = e.firstChild( ); + while( !m.isNull( ) ) + { + if( m.isElement( ) ) + { + QDomElement me = m.toElement( ); + if( isCategory( me ) ) + m_categories.append( newCategory( me, globalGroups, localGroups ) ); + } + m = m.nextSibling( ); + } +} + +PMRuleAfter::~PMRuleAfter( ) +{ + m_categories.setAutoDelete( true ); + m_categories.clear( ); +} + +bool PMRuleAfter::evaluate( const PMObject* ) +{ + return m_contains; +} + +void PMRuleAfter::countChildProtected( const QString& className, + bool afterInsertPoint ) +{ + if( !afterInsertPoint && !m_contains ) + { + QPtrListIterator it( m_categories ); + for( ; it.current( ) && !m_contains; ++it ) + m_contains = it.current( )->matches( className ); + } +} + +void PMRuleAfter::resetProtected( ) +{ + m_contains = false; +} + +PMRuleContains::PMRuleContains( QDomElement& e, + QPtrList& globalGroups, + QPtrList& localGroups ) + : PMRuleCondition( ) +{ + m_contains = false; + QDomNode m = e.firstChild( ); + while( !m.isNull( ) ) + { + if( m.isElement( ) ) + { + QDomElement me = m.toElement( ); + if( isCategory( me ) ) + m_categories.append( newCategory( me, globalGroups, localGroups ) ); + } + m = m.nextSibling( ); + } +} + +PMRuleContains::~PMRuleContains( ) +{ + m_categories.setAutoDelete( true ); + m_categories.clear( ); +} + +bool PMRuleContains::evaluate( const PMObject* ) +{ + return m_contains; +} + +void PMRuleContains::countChildProtected( const QString& className, bool ) +{ + if( !m_contains ) + { + QPtrListIterator it( m_categories ); + for( ; it.current( ) && !m_contains; ++it ) + m_contains = it.current( )->matches( className ); + } +} + +void PMRuleContains::resetProtected( ) +{ + m_contains = false; +} + +PMRuleCompare::PMRuleCompare( QDomElement& e, + QPtrList& globalGroups, + QPtrList& localGroups ) + : PMRuleCondition( ) +{ + m_pValue[0] = 0; + m_pValue[1] = 0; + + int i = 0; + QDomNode m = e.firstChild( ); + while( !m.isNull( ) && !m_pValue[1] ) + { + if( m.isElement( ) ) + { + QDomElement me = m.toElement( ); + if( isValue( me ) ) + { + m_pValue[i] = newValue( me, globalGroups, localGroups ); + m_children.append( m_pValue[i] ); + i++; + } + } + m = m.nextSibling( ); + } + if( !m_pValue[1] ) + kdError( PMArea ) << "RuleSystem: Comparison needs two values" << endl; +} + +bool PMRuleCompare::evaluate( const PMObject* object ) +{ + if( !m_pValue[1] ) + return false; + + PMVariant v[2]; + v[0] = m_pValue[0]->evaluate( object ); + v[1] = m_pValue[1]->evaluate( object ); + + if( v[0].isNull( ) || v[1].isNull( ) ) + return false; + + bool convertError = false; + + if( v[0].dataType( ) != v[1].dataType( ) ) + { + if( m_pValue[1]->type( ) == "Constant" ) + { + if( v[1].convertTo( v[0].dataType( ) ) ) + ( ( PMRuleConstant* ) m_pValue[1] )->convertTo( v[0].dataType( ) ); + else + convertError = true; + } + else if( m_pValue[0]->type( ) == "Constant" ) + { + if( v[0].convertTo( v[1].dataType( ) ) ) + ( ( PMRuleConstant* ) m_pValue[0] )->convertTo( v[1].dataType( ) ); + else + convertError = true; + } + else + convertError = true; + } + if( convertError ) + { + kdError( PMArea ) << "RuleSystem: Types in comparison must match" << endl; + return false; + } + + return compare( v[0], v[1] ); +} + +PMRuleLess::PMRuleLess( QDomElement& e, + QPtrList& globalGroups, + QPtrList& localGroups ) + : PMRuleCompare( e, globalGroups, localGroups ) +{ +} + +bool PMRuleLess::compare( const PMVariant& v1, const PMVariant& v2 ) +{ + bool c = false; + + switch( v1.dataType( ) ) + { + case PMVariant::Integer: + c = v1.intData( ) < v2.intData( ); + break; + case PMVariant::Unsigned: + c = v1.unsignedData( ) < v2.unsignedData( ); + break; + case PMVariant::Double: + c = v1.doubleData( ) < v2.doubleData( ); + break; + case PMVariant::String: + c = v1.stringData( ) < v2.stringData( ); + break; + case PMVariant::Bool: + kdError( PMArea ) << "RuleSystem: Less: Can't compare booleans" << endl; + break; + case PMVariant::ThreeState: + kdError( PMArea ) << "RuleSystem: Less: Can't compare ThreeStates" << endl; + break; + case PMVariant::Vector: + kdError( PMArea ) << "RuleSystem: Less: Can't compare vectors" << endl; + break; + case PMVariant::Color: + kdError( PMArea ) << "RuleSystem: Less: Can't compare colors" << endl; + break; + case PMVariant::ObjectPointer: + kdError( PMArea ) << "RuleSystem: Less: Can't compare object pointers" << endl; + break; + case PMVariant::None: + kdError( PMArea ) << "RuleSystem: Less: Value has type none" << endl; + break; + } + return c; +} + +PMRuleGreater::PMRuleGreater( QDomElement& e, + QPtrList& globalGroups, + QPtrList& localGroups ) + : PMRuleCompare( e, globalGroups, localGroups ) +{ +} + +bool PMRuleGreater::compare( const PMVariant& v1, const PMVariant& v2 ) +{ + bool c = false; + + switch( v1.dataType( ) ) + { + case PMVariant::Integer: + c = v1.intData( ) > v2.intData( ); + break; + case PMVariant::Unsigned: + c = v1.unsignedData( ) > v2.unsignedData( ); + break; + case PMVariant::Double: + c = v1.doubleData( ) > v2.doubleData( ); + break; + case PMVariant::String: + c = v1.stringData( ) > v2.stringData( ); + break; + case PMVariant::Bool: + kdError( PMArea ) << "RuleSystem: Greater: Can't compare booleans" << endl; + break; + case PMVariant::ThreeState: + kdError( PMArea ) << "RuleSystem: Greater: Can't compare ThreeStates" << endl; + break; + case PMVariant::Vector: + kdError( PMArea ) << "RuleSystem: Greater: Can't compare vectors" << endl; + break; + case PMVariant::Color: + kdError( PMArea ) << "RuleSystem: Greater: Can't compare colors" << endl; + break; + case PMVariant::ObjectPointer: + kdError( PMArea ) << "RuleSystem: Greater: Can't compare object pointers" << endl; + break; + case PMVariant::None: + kdError( PMArea ) << "RuleSystem: Greater: Value has type none" << endl; + break; + } + return c; +} + +PMRuleEqual::PMRuleEqual( QDomElement& e, + QPtrList& globalGroups, + QPtrList& localGroups ) + : PMRuleCompare( e, globalGroups, localGroups ) +{ +} + +bool PMRuleEqual::compare( const PMVariant& v1, const PMVariant& v2 ) +{ + bool c = false; + + switch( v1.dataType( ) ) + { + case PMVariant::Integer: + c = v1.intData( ) == v2.intData( ); + break; + case PMVariant::Unsigned: + c = v1.unsignedData( ) == v2.unsignedData( ); + break; + case PMVariant::Double: + c = v1.doubleData( ) == v2.doubleData( ); + break; + case PMVariant::String: + c = v1.stringData( ) == v2.stringData( ); + break; + case PMVariant::Bool: + c = v1.boolData( ) == v2.boolData( ); + break; + case PMVariant::ThreeState: + c = v1.threeStateData( ) == v2.threeStateData( ); + break; + case PMVariant::Vector: + kdError( PMArea ) << "RuleSystem: Equal: Can't compare vectors" << endl; + break; + case PMVariant::Color: + kdError( PMArea ) << "RuleSystem: Equal: Can't compare colors" << endl; + break; + case PMVariant::ObjectPointer: + kdError( PMArea ) << "RuleSystem: Equal: Can't compare object pointers" << endl; + break; + case PMVariant::None: + kdError( PMArea ) << "RuleSystem: Equal: Value has type none" << endl; + break; + } + return c; +} + + +PMRule::PMRule( QDomElement& e, + QPtrList& globalGroups, + QPtrList& localGroups ) + : PMRuleBase( ) +{ + m_pCondition = 0; + + QDomNode m = e.firstChild( ); + while( !m.isNull( ) && !m_pCondition ) + { + if( m.isElement( ) ) + { + QDomElement me = m.toElement( ); + if( isCategory( me ) ) + m_categories.append( newCategory( me, globalGroups, localGroups ) ); + else if( isCondition( me ) ) + { + m_pCondition = newCondition( me, globalGroups, localGroups ); + m_children.append( m_pCondition ); + } + } + m = m.nextSibling( ); + } +} + +PMRule::~PMRule( ) +{ + m_categories.setAutoDelete( true ); + m_categories.clear( ); +} + +bool PMRule::matches( const QString& className ) +{ + bool m = false; + QPtrListIterator it( m_categories ); + for( ; it.current( ) && !m; ++it ) + m = it.current( )->matches( className ); + return m; +} + +bool PMRule::evaluate( const PMObject* parent ) +{ + if( !m_pCondition ) + return true; + else + return m_pCondition->evaluate( parent ); +} + +PMRuleTargetClass::PMRuleTargetClass( QDomElement& e, + QPtrList& globalGroups ) +{ + m_class = e.attribute( "name" ); + if( m_class.isEmpty( ) ) + kdError( PMArea ) << "RuleSystem: Invalid class name" << endl; + + appendRules( e, globalGroups ); +} + +void PMRuleTargetClass::appendRules( QDomElement& e, + QPtrList& globalGroups ) +{ + QDomNode m = e.firstChild( ); + while( !m.isNull( ) ) + { + if( m.isElement( ) ) + { + QDomElement me = m.toElement( ); + if( me.tagName( ) == "definegroup" ) + m_groups.append( new PMRuleDefineGroup( me, globalGroups, m_groups ) ); + if( me.tagName( ) == "rule" ) + m_rules.append( new PMRule( me, globalGroups, m_groups ) ); + if( me.tagName( ) == "exception" ) + m_exceptions.append( me.attribute( "class" ) ); + } + m = m.nextSibling( ); + } +} + +PMRuleTargetClass::~PMRuleTargetClass( ) +{ + m_groups.setAutoDelete( true ); + m_groups.clear( ); + m_rules.setAutoDelete( true ); + m_rules.clear( ); +} + +PMInsertRuleSystem::PMInsertRuleSystem( PMPart* part ) +{ + m_pPart = part; +} + +PMInsertRuleSystem::~PMInsertRuleSystem( ) +{ + m_groups.setAutoDelete( true ); + m_groups.clear( ); + m_classRules.setAutoDelete( true ); + m_classRules.clear( ); +} + +void PMInsertRuleSystem::loadRules( const QString& fileName ) +{ + PMRuleClass::s_pPrototypeManager = m_pPart->prototypeManager( ); + if( m_loadedFiles.find( fileName ) != m_loadedFiles.end( ) ) + return; + m_loadedFiles.push_back( fileName ); + + + QString ruleFile = locate( "data", QString( "kpovmodeler/" + fileName ) ); + if( ruleFile.isEmpty( ) ) + { + kdError( PMArea ) << "Rule file 'kpovmodeler/" << fileName + << "' not found." << endl; + return; + } + + QFile file( ruleFile ); + if( !file.open( IO_ReadOnly ) ) + { + kdError( PMArea ) << "Could not open rule file 'kpovmodeler/" << fileName + << "'" << endl; + return; + } + + QDomDocument doc( "insertrules" ); + doc.setContent( &file ); + + QDomElement e = doc.documentElement( ); + if( e.attribute( "format" ) != "1.0" ) + kdError( PMArea ) << "Rule format " << e.attribute( "format" ) + << " not supported." << endl; + else + { + QDomNode c = e.firstChild( ); + QPtrList dummyLocalGroups; + + while( !c.isNull( ) ) + { + if( c.isElement( ) ) + { + QDomElement ce = c.toElement( ); + if( ce.tagName( ) == "definegroup" ) + m_groups.append( new PMRuleDefineGroup( ce, m_groups, + dummyLocalGroups ) ); + else if( ce.tagName( ) == "targetclass" ) + { + QString className = ce.attribute( "name" ); + // find a target class with the same name + PMRuleTargetClass* target = 0; + + if( !m_rulesDict.isEmpty( ) ) + target = m_rulesDict.find( className ); + + if( target ) + target->appendRules( ce, m_groups ); + else + { + target = new PMRuleTargetClass( ce, m_groups ); + m_rulesDict.insert( className, target ); + m_classRules.append( target ); + } + } + } + c = c.nextSibling( ); + } + } + file.close( ); + + PMRuleClass::s_pPrototypeManager = 0; +} + +bool PMInsertRuleSystem::canInsert( const PMObject* parentObject, + const QString& className, + const PMObject* after, + const PMObjectList* objectsBetween ) +{ + bool possible = false; + + // find rules for target class + PMMetaObject* meta = parentObject->metaObject( ); + for( ; meta && !possible; meta = meta->superClass( ) ) + { + PMRuleTargetClass* tc = m_rulesDict.find( meta->className( ) ); + if( tc ) + { + // check the exception list + QStringList exceptions = tc->exceptions( ); + bool exceptionFound = false; + QStringList::ConstIterator it; + for( it = exceptions.begin( ); + it != exceptions.end( ) && !exceptionFound; ++it ) + if( parentObject->isA( *it ) ) + exceptionFound = true; + + if( !exceptionFound ) + { + QPtrListIterator rit = tc->rules( ); + // find matching rules for class name + for( ; rit.current( ) && !possible; ++rit ) + { + PMRule* rule = rit.current( ); + if( rule->matches( className ) ) + { + // matching rule found + // reset the rule + rit.current( )->reset( ); + + // count already inserted child objects + bool afterInsertPoint = false; + PMObject* o = parentObject->firstChild( ); + if( !after ) + afterInsertPoint = true; + for( ; o; o = o->nextSibling( ) ) + { + rule->countChild( o->className( ), afterInsertPoint ); + if( o == after ) + afterInsertPoint = true; + } + if( objectsBetween ) + { + PMObjectListIterator it( *objectsBetween ); + for( ; it.current( ); ++it ) + rule->countChild( it.current( )->type( ), false ); + } + + // evaluate condition value + possible = rule->evaluate( parentObject ); + } + } + } + } + } + + return possible; +} + +bool PMInsertRuleSystem::canInsert( const PMObject* parentObject, + const PMObject* object, + const PMObject* after, + const PMObjectList* objectsBetween ) +{ + return canInsert( parentObject, object->type( ), after, objectsBetween ); +} + +int PMInsertRuleSystem::canInsert( const PMObject* parentObject, + const PMObjectList& list, + const PMObject* after ) +{ + PMObjectListIterator it( list ); + QStringList classes; + for( ; it.current( ); ++it ) + classes.append( it.current( )->type( ) ); + return canInsert( parentObject, classes, after ); +} + +int PMInsertRuleSystem::canInsert( const PMObject* parentObject, + const QStringList& list, + const PMObject* after ) +{ + if( list.size( ) == 1 ) + { + // more efficient + if( canInsert( parentObject, list.first( ), after ) ) + return 1; + else + return 0; + } + + // find rules for target class + QPtrList targetClassList; + PMMetaObject* meta = parentObject->metaObject( ); + for( ; meta; meta = meta->superClass( ) ) + { + PMRuleTargetClass* tc = m_rulesDict.find( meta->className( ) ); + if( tc ) + targetClassList.append( tc ); + } + if( targetClassList.isEmpty( ) ) + return 0; // not rules found + + // count already inserted children + QPtrListIterator tit( targetClassList ); + for( ; tit.current( ); ++tit ) // ... for all target classes + { + QPtrListIterator rit = tit.current( )->rules( ); + for( ; rit.current( ); ++rit ) // ... and all rules + { + rit.current( )->reset( ); + bool afterInsertPoint = false; + PMObject* o = parentObject->firstChild( ); + if( !after ) + afterInsertPoint = true; + for( ; o; o = o->nextSibling( ) ) + { + rit.current( )->countChild( o->className( ), afterInsertPoint ); + if( o == after ) + afterInsertPoint = true; + } + } + } + + int number = 0; + QStringList::const_iterator oit; + + for( oit = list.begin( ); oit != list.end( ); ++oit ) + { + bool possible = false; + for( tit.toFirst( ); tit.current( ) && !possible; ++tit ) + { + QPtrListIterator rit = tit.current( )->rules( ); + + for( ; rit.current( ) && !possible; ++rit ) + { + PMRule* rule = rit.current( ); + if( rule->matches( *oit ) ) + possible = rule->evaluate( parentObject ); + } + } + if( possible ) + { + // object can be inserted, count it + for( ; tit.current( ); ++tit ) + { + QPtrListIterator rit = tit.current( )->rules( ); + for( ; rit.current( ); ++rit ) + rit.current( )->countChild( *oit, false ); + } + number++; + } + } + + return number; +} diff --git a/kpovmodeler/pminsertrulesystem.h b/kpovmodeler/pminsertrulesystem.h new file mode 100644 index 00000000..499cbc8e --- /dev/null +++ b/kpovmodeler/pminsertrulesystem.h @@ -0,0 +1,678 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMINSERTRULESYSTEM_H +#define PMINSERTRULESYSTEM_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmobject.h" + +#include +#include +#include +#include + +class PMInsertRuleSystem; +class PMPrototypeManager; + +/** + * Base class for all object categories (class and group) + * for the insert rule system + */ +class PMRuleCategory +{ +public: + /** + * Default constructor + */ + PMRuleCategory( ) { } + /** + * Destructor + */ + virtual ~PMRuleCategory( ) { } + /** + * Returns true if the given class types matches the category. + */ + virtual bool matches( const QString& className ) = 0; +}; + +/** + * Represents a class for the insert rule system + */ +class PMRuleClass : public PMRuleCategory +{ +public: + /** + * Workaround to tell a created instance which + * prototype manager to use. + */ + static PMPrototypeManager* s_pPrototypeManager; + /** + * Reads the data from the QDomElement. + */ + PMRuleClass( QDomElement& e ); + /** */ + virtual bool matches( const QString& className ); +private: + QString m_className; + PMPrototypeManager* m_pPrototypeManager; +}; + +/** + * Groups together multiple classes or groups to form a new + * category for the insert rule system. + */ +class PMRuleDefineGroup +{ +public: + /** + * Reads the data from the QDomElement. + */ + PMRuleDefineGroup( QDomElement& e, QPtrList& globalGroups, + QPtrList& localGroups ); + /** + * Destructor + */ + virtual ~PMRuleDefineGroup( ); + /** + * Returns true if the given class types matches the category. + */ + virtual bool matches( const QString& className ); + /** + * Returns the group's name + */ + QString name( ) const { return m_name; } +private: + QPtrList m_categories; + QString m_name; +}; + +/** + * Represents a group for the insert rule system + */ +class PMRuleGroup : public PMRuleCategory +{ +public: + /** + * Reads the data from the QDomElement. + */ + PMRuleGroup( QDomElement& e, QPtrList& globalGroups, + QPtrList& localGroups ); + /** */ + bool matches( const QString& className ); +private: + PMRuleDefineGroup* m_pGroup; +}; + + +/** + * Base class for all nodes for the insert rule system + */ +class PMRuleBase +{ +public: + /** + * Default constructor. + */ + PMRuleBase( ) { } + /** + * Destructor + */ + virtual ~PMRuleBase( ); + /** + * Returns the node type. + */ + virtual QString type( ) const = 0; + /** + * Calls countChildProtected for this node and all child nodes + */ + void countChild( const QString& className, bool afterInsertPoint ); + /** + * Calls resetProtected for this node and all child nodes + */ + void reset( ); + /** + * Returns an iterator to all child nodes + */ + QPtrListIterator childIterator( ) const + { + return QPtrListIterator( m_children ); + } +protected: + /** + * Reimplement this method if the nodes value depends + * on already inserted child objects. + */ + virtual void countChildProtected( const QString&, bool ) { } + /** + * Reset all cached data (like counted child objects) here. + */ + virtual void resetProtected( ) { } + + /** + * Add all child nodes to this list. + */ + QPtrList m_children; +}; + +/** + * Base class for values used by the rule system + */ +class PMRuleValue : public PMRuleBase +{ +public: + /** + * Default constructor + */ + PMRuleValue( ) : PMRuleBase( ) { } + /** + * Returns the node's value as variant. + * + * Reimplement this method in sub classes. + */ + virtual PMVariant evaluate( const PMObject* o ) = 0; +}; + + +/** + * Value node for object properties + */ +class PMRuleProperty : public PMRuleValue +{ +public: + /** + * Reads the data from the QDomElement. + */ + PMRuleProperty( QDomElement& e ); + /** */ + virtual QString type( ) const { return QString( "Property" ); } + /** */ + virtual PMVariant evaluate( const PMObject* o ); +private: + QString m_property; +}; + + +/** + * Simple constant + */ +class PMRuleConstant : public PMRuleValue +{ +public: + /** + * Reads the data from the QDomElement. + */ + PMRuleConstant( QDomElement& e ); + /** */ + virtual QString type( ) const { return QString( "Constant" ); } + /** */ + virtual PMVariant evaluate( const PMObject* ); + /** + * Converts the constant to the given type and returns true if + * successful. + */ + bool convertTo( PMVariant::PMVariantDataType type ); +private: + PMVariant m_value; +}; + +/** + * Rule that counts child objects of certaint types + */ +class PMRuleCount : public PMRuleValue +{ +public: + /** + * Reads the data from the QDomElement. + */ + PMRuleCount( QDomElement& e, QPtrList& globalGroups, + QPtrList& localGroups ); + /** + * Destructor + */ + virtual ~PMRuleCount( ); + /** */ + virtual QString type( ) const { return QString( "Count" ); } + /** */ + virtual PMVariant evaluate( const PMObject* ); +protected: + /** */ + virtual void countChildProtected( const QString& className, + bool afterInsertPoint ); + /** + * Reset all cached data (like counted child objects) here. + */ + virtual void resetProtected( ); +private: + QPtrList m_categories; + int m_number; +}; + +/** + * Base class for conditions + */ +class PMRuleCondition : public PMRuleBase +{ +public: + /** + * Default constructor + */ + PMRuleCondition( ) : PMRuleBase( ) { } + /** + * Returns the condition's value. + * + * Reimplement this method in sub classes. + */ + virtual bool evaluate( const PMObject* object ) = 0; +}; + + +/** + * Logical negation + */ +class PMRuleNot : public PMRuleCondition +{ +public: + /** + * Reads the data from the QDomElement. + */ + PMRuleNot( QDomElement& e, QPtrList& globalGroups, + QPtrList& localGroups ); + /** */ + virtual QString type( ) const { return QString( "Not" ); } + /** */ + virtual bool evaluate( const PMObject* object ); +private: + PMRuleCondition* m_pChild; +}; + + +/** + * Logical and + */ +class PMRuleAnd : public PMRuleCondition +{ +public: + /** + * Reads the data from the QDomElement. + */ + PMRuleAnd( QDomElement& e, QPtrList& globalGroups, + QPtrList& localGroups ); + /** */ + virtual QString type( ) const { return QString( "And" ); } + /** */ + virtual bool evaluate( const PMObject* object ); +private: + QPtrList m_conditions; +}; + +/** + * Logical or + */ +class PMRuleOr : public PMRuleCondition +{ +public: + /** + * Reads the data from the QDomElement. + */ + PMRuleOr( QDomElement& e, QPtrList& globalGroups, + QPtrList& localGroups ); + /** */ + virtual QString type( ) const { return QString( "Or" ); } + /** */ + virtual bool evaluate( const PMObject* object ); +private: + QPtrList m_conditions; +}; + +/** + * Condition. Value is true if the object already contains + * objects of certaint classes before the insert point. + */ +class PMRuleBefore : public PMRuleCondition +{ +public: + /** + * Reads the data from the QDomElement. + */ + PMRuleBefore( QDomElement& e, QPtrList& globalGroups, + QPtrList& localGroups ); + /** + * Destructor + */ + virtual ~PMRuleBefore( ); + /** */ + virtual QString type( ) const { return QString( "Before" ); } + /** */ + virtual bool evaluate( const PMObject* object ); +protected: + /** */ + virtual void countChildProtected( const QString& className, + bool afterInsertPoint ); + /** */ + virtual void resetProtected( ); +private: + QPtrList m_categories; + bool m_contains; +}; + +/** + * Condition. Value is true if the object already contains + * objects of certaint classes after the insert point. + */ +class PMRuleAfter : public PMRuleCondition +{ +public: + /** + * Reads the data from the QDomElement. + */ + PMRuleAfter( QDomElement& e, QPtrList& globalGroups, + QPtrList& localGroups ); + /** + * Destructor + */ + virtual ~PMRuleAfter( ); + /** */ + virtual QString type( ) const { return QString( "After" ); } + /** */ + virtual bool evaluate( const PMObject* object ); +protected: + /** */ + virtual void countChildProtected( const QString& className, + bool afterInsertPoint ); + /** */ + virtual void resetProtected( ); +private: + QPtrList m_categories; + bool m_contains; +}; + +/** + * Condition. Value is true if the object already contains + * objects of certaint classes. + */ +class PMRuleContains : public PMRuleCondition +{ +public: + /** + * Reads the data from the QDomElement. + */ + PMRuleContains( QDomElement& e, QPtrList& globalGroups, + QPtrList& localGroups ); + /** + * Destructor + */ + virtual ~PMRuleContains( ); + /** */ + virtual QString type( ) const { return QString( "Contains" ); } + /** */ + virtual bool evaluate( const PMObject* object ); +protected: + /** */ + virtual void countChildProtected( const QString& className, + bool afterInsertPoint ); + /** */ + virtual void resetProtected( ); +private: + QPtrList m_categories; + bool m_contains; +}; + +/** + * Base class for comparisons + */ +class PMRuleCompare : public PMRuleCondition +{ +public: + /** + * Reads the data from the QDomElement. + */ + PMRuleCompare( QDomElement& e, QPtrList& globalGroups, + QPtrList& localGroups ); + /** */ + virtual bool evaluate( const PMObject* object ); +protected: + /** + * Compares the two variants. The variants have the same type. + * + * Reimplement this method in sub classes. + */ + virtual bool compare( const PMVariant& v1, const PMVariant& v2 ) = 0; +private: + PMRuleValue* m_pValue[2]; +}; + +/** + * Less than comparison + */ +class PMRuleLess : public PMRuleCompare +{ +public: + /** + * Reads the data from the QDomElement. + */ + PMRuleLess( QDomElement& e, QPtrList& globalGroups, + QPtrList& localGroups ); + /** */ + virtual QString type( ) const { return QString( "Less" ); } +protected: + /** */ + virtual bool compare( const PMVariant& v1, const PMVariant& v2 ); +}; + +/** + * Greater than comparison + */ +class PMRuleGreater : public PMRuleCompare +{ +public: + /** + * Reads the data from the QDomElement. + */ + PMRuleGreater( QDomElement& e, QPtrList& globalGroups, + QPtrList& localGroups ); + /** */ + virtual QString type( ) const { return QString( "Greater" ); } +protected: + /** */ + virtual bool compare( const PMVariant& v1, const PMVariant& v2 ); +}; + +/** + * Equal comparison + */ +class PMRuleEqual : public PMRuleCompare +{ +public: + /** + * Reads the data from the QDomElement. + */ + PMRuleEqual( QDomElement& e, QPtrList& globalGroups, + QPtrList& localGroups ); + /** */ + virtual QString type( ) const { return QString( "Equal" ); } +protected: + /** */ + virtual bool compare( const PMVariant& v1, const PMVariant& v2 ); +}; + +class PMRule : public PMRuleBase +{ +public: + /** + * Reads the data from the QDomElement. + */ + PMRule( QDomElement& e, QPtrList& globalGroups, + QPtrList& localGroups ); + /** + * Destructor + */ + virtual ~PMRule( ); + /** */ + virtual QString type( ) const { return QString( "Rule" ); } + /** + * Returns true if this rule matches for the given class. + */ + bool matches( const QString& className ); + /** + * Returns the conditions value. + */ + bool evaluate( const PMObject* parent ); + +private: + QPtrList m_categories; + PMRuleCondition* m_pCondition; +}; + +/** + * Class used internally by the insert rule system + * + * Stores all rules for one class. + */ +class PMRuleTargetClass +{ +public: + /** + * Reads the data from the QDomElement. + */ + PMRuleTargetClass( QDomElement& e, + QPtrList& globalGroups ); + /** + * Destructor + */ + ~PMRuleTargetClass( ); + + /** + * Reads rules and groups from the QDomELement and appends + * them to the local ones. + */ + void appendRules( QDomElement& e, QPtrList& globalGroups ); + /** + * Returns an iterator to the rules + */ + QPtrListIterator rules( ) const + { + return QPtrListIterator( m_rules ); + } + /** + * Returns the class name + */ + QString name( ) const { return m_class; } + /** + * Returns a list of exceptions for this rule. + */ + QStringList exceptions( ) const { return m_exceptions; } +private: + QPtrList m_groups; + QPtrList m_rules; + QString m_class; + QStringList m_exceptions; +}; + +/** + * Rule based system that checks which objects can be inserted as child + * into another object. + * + * The rules are defined in the file "pmbaseinsertrules.xml". + * The file "pminsertrules.dtd" is a DTD file that can be used + * to validate rule files. + * + * Plugins can add additional rules to the system. + */ +class PMInsertRuleSystem +{ +public: + /** + * Constructor + */ + PMInsertRuleSystem( PMPart* part ); + /** + * Destructor + */ + ~PMInsertRuleSystem( ); + + /** + * Tells the system to load the rules from a file. + * + * Rules are never loaded twice for the same file. It is save + * to call this method twice for the same file. + */ + void loadRules( const QString& fileName ); + + /** + * Returns true if an object of the given class can be inserted as child + * after the object after. + * + * The parser uses the third parameter for top level objects. These objects + * have to be treated as if they are inserted after the object after. + */ + bool canInsert( const PMObject* parentObject, const QString& className, + const PMObject* after, const PMObjectList* objectsBetween = 0 ); + + /** + * Returns true if the object can be inserted as child + * after the object after. + * + * The parser uses the third parameter for top level objects. These objects + * have to be treated as if they are inserted after the object after. + * + * Same as canInsert( parentObject, object->class( ), after, objectsBetween ) + */ + bool canInsert( const PMObject* parentObject, const PMObject* object, + const PMObject* after, const PMObjectList* objectsBetween = 0 ); + + /** + * Returns the number of objects that can be inserted at that position + */ + int canInsert( const PMObject* parentObject, const PMObjectList& list, + const PMObject* after ); + /** + * Returns the number of objects that can be inserted at that position + */ + int canInsert( const PMObject* parentObject, const QStringList& listOfClasses, + const PMObject* after ); + /** + * Returns a pointer to the part + */ + PMPart* part( ) const { return m_pPart; } + +private: + /** + * List of all rules. + */ + QPtrList m_classRules; + /** + * List of global groups + */ + QPtrList m_groups; + /** + * Dictionary that maps from the class name + * to a list of rules that match. + */ + QDict m_rulesDict; + /** + * List of already loaded files + */ + QStringList m_loadedFiles; + PMPart* m_pPart; +}; + +#endif diff --git a/kpovmodeler/pminterior.cpp b/kpovmodeler/pminterior.cpp new file mode 100644 index 00000000..31d7bf5d --- /dev/null +++ b/kpovmodeler/pminterior.cpp @@ -0,0 +1,343 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pminterior.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pminterioredit.h" + +#include + +const double iorDefault = 1.0; +const double causticsDefault = 0.0; +const double dispersionDefault = 1.0; +const int dispSamplesDefault = 7; +const double fadeDistanceDefault = 0.0; +const double fadePowerDefault = 0.0; + +PMDefinePropertyClass( PMInterior, PMInteriorProperty ); + +PMMetaObject* PMInterior::s_pMetaObject = 0; +PMObject* createNewInterior( PMPart* part ) +{ + return new PMInterior( part ); +} + +PMInterior::PMInterior( PMPart* part ) + : Base( part ) +{ + m_ior = iorDefault; + m_caustics = causticsDefault; + m_dispersion = dispersionDefault; + m_dispSamples = dispSamplesDefault; + m_fadeDistance = fadeDistanceDefault; + m_fadePower = fadePowerDefault; + m_enableIor = false; + m_enableCaustics = false; + m_enableDispersion = false; + m_enableDispSamples = false; + m_enableFadeDistance = false; + m_enableFadePower = false; +} + +PMInterior::PMInterior( const PMInterior& i ) + : Base( i ) +{ + m_ior = i.m_ior; + m_caustics = i.m_caustics; + m_dispersion = i.m_dispersion; + m_dispSamples = i.m_dispSamples; + m_fadeDistance = i.m_fadeDistance; + m_fadePower = i.m_fadePower; + m_enableIor = i.m_enableIor; + m_enableCaustics = i.m_enableCaustics; + m_enableDispersion = i.m_enableDispersion; + m_enableDispSamples = i.m_enableDispSamples; + m_enableFadeDistance = i.m_enableFadeDistance; + m_enableFadePower = i.m_enableFadePower; +} + +PMInterior::~PMInterior( ) +{ +} + +PMMetaObject* PMInterior::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Interior", Base::metaObject( ), + createNewInterior ); + s_pMetaObject->addProperty( + new PMInteriorProperty( "ior", &PMInterior::setIor, &PMInterior::ior ) ); + s_pMetaObject->addProperty( + new PMInteriorProperty( "caustics", &PMInterior::setCaustics, &PMInterior::caustics ) ); + s_pMetaObject->addProperty( + new PMInteriorProperty( "dispersion", &PMInterior::setDispersion, &PMInterior::dispersion ) ); + s_pMetaObject->addProperty( + new PMInteriorProperty( "dispSamples", &PMInterior::setDispSamples, &PMInterior::dispSamples ) ); + s_pMetaObject->addProperty( + new PMInteriorProperty( "fadeDistance", &PMInterior::setFadeDistance, &PMInterior::fadeDistance ) ); + s_pMetaObject->addProperty( + new PMInteriorProperty( "fadePower", &PMInterior::setFadePower, &PMInterior::fadePower ) ); + s_pMetaObject->addProperty( + new PMInteriorProperty( "iorEnabled", &PMInterior::enableIor, &PMInterior::isIorEnabled ) ); + s_pMetaObject->addProperty( + new PMInteriorProperty( "causticsEnabled", &PMInterior::enableCaustics, &PMInterior::isCausticsEnabled ) ); + s_pMetaObject->addProperty( + new PMInteriorProperty( "dispersionEnabled", &PMInterior::enableDispersion, &PMInterior::isDispersionEnabled ) ); + s_pMetaObject->addProperty( + new PMInteriorProperty( "dispSamplesEnabled", &PMInterior::enableDispSamples, &PMInterior::isDispSamplesEnabled ) ); + s_pMetaObject->addProperty( + new PMInteriorProperty( "fadeDistanceEnabled", &PMInterior::enableFadeDistance, &PMInterior::isFadeDistanceEnabled ) ); + s_pMetaObject->addProperty( + new PMInteriorProperty( "fadePowerEnabled", &PMInterior::enableFadePower, &PMInterior::isFadePowerEnabled ) ); + } + return s_pMetaObject; +} + +void PMInterior::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMInterior::description( ) const +{ + return i18n( "interior" ); +} + +void PMInterior::serialize( QDomElement& e, QDomDocument& doc ) const +{ + Base::serialize( e, doc ); + e.setAttribute( "enable_ior", m_enableIor ); + e.setAttribute( "enable_caustics", m_enableCaustics ); + e.setAttribute( "enable_dispersion", m_enableDispersion ); + e.setAttribute( "enable_disp_samples", m_enableDispSamples ); + e.setAttribute( "enable_fade_distance", m_enableFadeDistance ); + e.setAttribute( "enable_fade_power", m_enableFadePower ); + e.setAttribute( "ior", m_ior ); + e.setAttribute( "caustics", m_caustics ); + e.setAttribute( "dispersion", m_dispersion ); + e.setAttribute( "disp_samples", m_dispSamples ); + e.setAttribute( "fade_distance", m_fadeDistance ); + e.setAttribute( "fade_power", m_fadePower ); +} + +void PMInterior::readAttributes( const PMXMLHelper& h ) +{ + Base::readAttributes( h ); + m_enableIor = h.boolAttribute( "enable_ior", false ); + m_enableCaustics = h.boolAttribute( "enable_caustics", false ); + m_enableDispersion = h.boolAttribute( "enable_dispersion", false ); + m_enableDispSamples = h.boolAttribute( "enable_disp_samples", false ); + m_enableFadeDistance = h.boolAttribute( "enable_fade_distance", false ); + m_enableFadePower = h.boolAttribute( "enable_fade_power", false ); + m_ior = h.doubleAttribute( "ior", iorDefault ); + m_caustics = h.doubleAttribute( "caustics", causticsDefault ); + m_dispersion = h.doubleAttribute( "dispersion", dispersionDefault ); + m_dispSamples = h.intAttribute( "disp_samples", dispSamplesDefault ); + m_fadeDistance = h.doubleAttribute( "fade_distance", fadeDistanceDefault ); + m_fadePower = h.doubleAttribute( "fade_power", fadePowerDefault ); +} + +void PMInterior::setIor( double c ) +{ + if( c != m_ior ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMIorID, m_ior ); + m_ior = c; + } +} + +void PMInterior::setCaustics( double c ) +{ + if( c != m_caustics ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCausticsID, m_caustics ); + m_caustics = c; + } +} + +void PMInterior::setDispersion( double c ) +{ + if ( c != m_dispersion ) + { + if ( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMDispersionID, m_dispersion ); + m_dispersion = c; + } +} + +void PMInterior::setDispSamples( int c ) +{ + if ( c != m_dispSamples ) + { + if ( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMDispSamplesID, m_dispSamples ); + m_dispSamples = c; + } +} + +void PMInterior::setFadeDistance( double c ) +{ + if( c != m_fadeDistance ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFadeDistanceID, m_fadeDistance ); + m_fadeDistance = c; + } +} + +void PMInterior::setFadePower( double c ) +{ + if( c != m_fadePower ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFadePowerID, m_fadePower ); + m_fadePower = c; + } +} + +void PMInterior::enableIor( bool c ) +{ + if( c != m_enableIor ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableIorID, m_enableIor ); + m_enableIor = c; + } +} + +void PMInterior::enableCaustics( bool c ) +{ + if( c != m_enableCaustics ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableCausticsID, m_enableCaustics ); + m_enableCaustics = c; + } +} + +void PMInterior::enableDispersion( bool c ) +{ + if( c != m_enableDispersion ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableDispersionID, m_enableDispersion ); + m_enableDispersion = c; + } +} + +void PMInterior::enableDispSamples( bool c ) +{ + if( c != m_enableDispSamples ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableDispSamplesID, m_enableDispSamples ); + m_enableDispSamples = c; + } +} + +void PMInterior::enableFadeDistance( bool c ) +{ + if( c != m_enableFadeDistance ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableFadeDistanceID, + m_enableFadeDistance ); + m_enableFadeDistance = c; + } +} + +void PMInterior::enableFadePower( bool c ) +{ + if( c != m_enableFadePower ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableFadePowerID, + m_enableFadePower ); + m_enableFadePower = c; + } +} + +PMDialogEditBase* PMInterior::editWidget( QWidget* parent ) const +{ + return new PMInteriorEdit( parent ); +} + +void PMInterior::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMIorID: + setIor( data->doubleData( ) ); + break; + case PMCausticsID: + setCaustics( data->doubleData( ) ); + break; + case PMDispersionID: + setDispersion( data->doubleData( ) ); + break; + case PMDispSamplesID: + setDispSamples( data->intData( ) ); + break; + case PMFadeDistanceID: + setFadeDistance( data->doubleData( ) ); + break; + case PMFadePowerID: + setFadePower( data->doubleData( ) ); + break; + case PMEnableIorID: + enableIor( data->boolData( ) ); + break; + case PMEnableCausticsID: + enableCaustics( data->boolData( ) ); + break; + case PMEnableDispersionID: + enableDispersion( data->boolData( ) ); + break; + case PMEnableDispSamplesID: + enableDispSamples( data->boolData( ) ); + case PMEnableFadeDistanceID: + enableFadeDistance( data->boolData( ) ); + break; + case PMEnableFadePowerID: + enableFadePower( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMInterior::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pminterior.h b/kpovmodeler/pminterior.h new file mode 100644 index 00000000..159b6b64 --- /dev/null +++ b/kpovmodeler/pminterior.h @@ -0,0 +1,128 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMINTERIOR_H +#define PMINTERIOR_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebase.h" +#include "pmcolor.h" + +/** + * Class for povray interiors + */ +class PMInterior : public PMTextureBase +{ + typedef PMTextureBase Base; +public: + /** + * Creates an PMInterior + */ + PMInterior( PMPart* part ); + /** + * Copy constructor + */ + PMInterior( const PMInterior& i ); + /** + * Deletes the object + */ + virtual ~PMInterior( ); + + /** */ + virtual PMObject* copy( ) const { return new PMInterior( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMInteriorEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pminterior" ); } + + /** */ + virtual void restoreMemento( PMMemento* s ); + + double ior( ) const { return m_ior; } + double caustics( ) const { return m_caustics; } + double dispersion( ) const { return m_dispersion; } + int dispSamples( ) const { return m_dispSamples; } + double fadeDistance( ) const { return m_fadeDistance; } + double fadePower( ) const { return m_fadePower; } + bool isIorEnabled( ) const { return m_enableIor; } + bool isCausticsEnabled( ) const { return m_enableCaustics; } + bool isDispersionEnabled( ) const { return m_enableDispersion; } + bool isDispSamplesEnabled( ) const { return m_enableDispSamples; } + bool isFadeDistanceEnabled( ) const { return m_enableFadeDistance; } + bool isFadePowerEnabled( ) const { return m_enableFadePower; } + + void setIor( double c ); + void setCaustics( double c ); + void setDispersion ( double c ); + void setDispSamples ( int c ); + void setFadeDistance( double c ); + void setFadePower( double c ); + void enableIor( bool c ); + void enableCaustics( bool c ); + void enableDispersion( bool c ); + void enableDispSamples( bool c ); + void enableFadeDistance( bool c ); + void enableFadePower( bool c ); + +private: + /** + * IDs for @ref PMMementoData + */ + enum PMInteriorMementoID { PMIorID, PMCausticsID, PMDispersionID, + PMDispSamplesID, PMFadeDistanceID, PMFadePowerID, + PMEnableIorID, PMEnableCausticsID, + PMEnableDispersionID, PMEnableDispSamplesID, + PMEnableFadeDistanceID, PMEnableFadePowerID }; + double m_ior; + double m_caustics; + double m_dispersion; + int m_dispSamples; + double m_fadeDistance; + double m_fadePower; + + bool m_enableIor; + bool m_enableCaustics; + bool m_enableDispersion; + bool m_enableDispSamples; + bool m_enableFadeDistance; + bool m_enableFadePower; + + static PMMetaObject* s_pMetaObject; +}; + + +#endif diff --git a/kpovmodeler/pminterioredit.cpp b/kpovmodeler/pminterioredit.cpp new file mode 100644 index 00000000..b5df1825 --- /dev/null +++ b/kpovmodeler/pminterioredit.cpp @@ -0,0 +1,212 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pminterioredit.h" +#include "pminterior.h" +#include "pmlineedits.h" +#include "pmcoloredit.h" + +#include +#include +#include +#include + + +PMInteriorEdit::PMInteriorEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMInteriorEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* hl = new QHBoxLayout( topLayout( ) ); + QGridLayout* layout = new QGridLayout( hl ,17 ,6); + m_pEnableIorEdit = new QCheckBox( i18n( "Refraction:" ), this ); + m_pIorEdit = new PMFloatEdit( this ); + layout->addWidget( m_pEnableIorEdit, 0, 0 ); + layout->addWidget( m_pIorEdit, 0, 1 ); + m_pEnableCausticsEdit = new QCheckBox( i18n( "Caustics:" ), this ); + m_pCausticsEdit = new PMFloatEdit( this ); + layout->addWidget( m_pEnableCausticsEdit, 1, 0 ); + layout->addWidget( m_pCausticsEdit, 1, 1 ); + m_pEnableDispersionEdit = new QCheckBox( i18n( "Dispersion:" ), this ); + m_pDispersionEdit = new PMFloatEdit( this ); + m_pDispersionEdit->setValidation( true, 0, false, 0 ); + layout->addWidget( m_pEnableDispersionEdit, 2, 0 ); + layout->addWidget( m_pDispersionEdit, 2, 1 ); + m_pEnableDispSamplesEdit = new QCheckBox( i18n( "Dispersion samples:" ), this ); + m_pDispSamplesEdit = new PMIntEdit( this ); + m_pDispSamplesEdit->setValidation( true, 2, false, 0 ); + layout->addWidget( m_pEnableDispSamplesEdit, 3, 0 ); + layout->addWidget( m_pDispSamplesEdit, 3, 1 ); + m_pEnableFadeDistanceEdit = new QCheckBox( i18n( "Fade distance:" ), this ); + m_pFadeDistanceEdit = new PMFloatEdit( this ); + layout->addWidget( m_pEnableFadeDistanceEdit, 4, 0 ); + layout->addWidget( m_pFadeDistanceEdit, 4, 1 ); + m_pEnableFadePowerEdit = new QCheckBox( i18n( "Fade power:" ), this ); + m_pFadePowerEdit = new PMFloatEdit( this ); + layout->addWidget( m_pEnableFadePowerEdit, 5, 0 ); + layout->addWidget( m_pFadePowerEdit, 5, 1 ); + hl->addStretch( 1 ); + + connect( m_pIorEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pCausticsEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pDispersionEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pDispSamplesEdit, SIGNAL( dataChanged( ) ), SIGNAL ( dataChanged( ) ) ); + connect( m_pFadeDistanceEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pFadePowerEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pEnableIorEdit, SIGNAL( clicked( ) ), SLOT( slotIorClicked( ) ) ); + connect( m_pEnableCausticsEdit, SIGNAL( clicked( ) ), SLOT( slotCausticsClicked( ) ) ); + connect( m_pEnableDispersionEdit, SIGNAL( clicked( ) ), SLOT( slotDispersionClicked( ) ) ); + connect( m_pEnableDispSamplesEdit, SIGNAL( clicked( ) ), SLOT( slotDispSamplesClicked( ) ) ); + connect( m_pEnableFadeDistanceEdit, SIGNAL( clicked( ) ), SLOT( slotFadeDistanceClicked( ) ) ); + connect( m_pEnableFadePowerEdit, SIGNAL( clicked( ) ), SLOT( slotFadePowerClicked( ) ) ); +} + +void PMInteriorEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Interior" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMInterior* ) o; + + m_pIorEdit->setValue( m_pDisplayedObject->ior( ) ); + m_pIorEdit->setReadOnly( readOnly ); + m_pCausticsEdit->setValue( m_pDisplayedObject->caustics( ) ); + m_pCausticsEdit->setReadOnly( readOnly ); + m_pDispersionEdit->setValue( m_pDisplayedObject->dispersion( ) ); + m_pDispersionEdit->setReadOnly( readOnly ); + m_pDispSamplesEdit->setValue( m_pDisplayedObject->dispSamples( ) ); + m_pDispSamplesEdit->setReadOnly( readOnly ); + m_pFadeDistanceEdit->setValue( m_pDisplayedObject->fadeDistance( ) ); + m_pFadeDistanceEdit->setReadOnly( readOnly ); + m_pFadePowerEdit->setValue( m_pDisplayedObject->fadePower( ) ); + m_pFadePowerEdit->setReadOnly( readOnly ); + m_pEnableIorEdit->setChecked( m_pDisplayedObject->isIorEnabled( ) ); + m_pEnableIorEdit->setEnabled( !readOnly ); + m_pEnableCausticsEdit->setChecked( m_pDisplayedObject->isCausticsEnabled( ) ); + m_pEnableCausticsEdit->setEnabled( !readOnly ); + m_pEnableDispersionEdit->setChecked( m_pDisplayedObject->isDispersionEnabled( ) ); + m_pEnableDispersionEdit->setEnabled( !readOnly ); + m_pEnableDispSamplesEdit->setChecked( m_pDisplayedObject->isDispSamplesEnabled( ) ); + m_pEnableDispSamplesEdit->setEnabled( !readOnly ); + m_pEnableFadeDistanceEdit->setChecked( m_pDisplayedObject->isFadeDistanceEnabled( ) ); + m_pEnableFadeDistanceEdit->setEnabled( !readOnly ); + m_pEnableFadePowerEdit->setChecked( m_pDisplayedObject->isFadePowerEnabled( ) ); + m_pEnableFadePowerEdit->setEnabled( !readOnly ); + slotIorClicked( ); + slotCausticsClicked( ); + slotDispersionClicked( ); + slotDispSamplesClicked( ); + slotFadeDistanceClicked( ); + slotFadePowerClicked( ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMInteriorEdit: Can't display object\n"; +} + +void PMInteriorEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setIor( m_pIorEdit->value( ) ); + m_pDisplayedObject->setCaustics( m_pCausticsEdit->value( ) ); + m_pDisplayedObject->setDispersion( m_pDispersionEdit->value( ) ); + m_pDisplayedObject->setDispSamples( m_pDispSamplesEdit->value( ) ); + m_pDisplayedObject->setFadeDistance( m_pFadeDistanceEdit->value( ) ); + m_pDisplayedObject->setFadePower( m_pFadePowerEdit->value( ) ); + m_pDisplayedObject->enableIor( m_pEnableIorEdit->isChecked( ) ); + m_pDisplayedObject->enableCaustics( m_pEnableCausticsEdit->isChecked( ) ); + m_pDisplayedObject->enableDispersion( m_pEnableDispersionEdit->isChecked( ) ); + m_pDisplayedObject->enableDispSamples( m_pEnableDispSamplesEdit->isChecked( ) ); + m_pDisplayedObject->enableFadeDistance( m_pEnableFadeDistanceEdit->isChecked( ) ); + m_pDisplayedObject->enableFadePower( m_pEnableFadePowerEdit->isChecked( ) ); + } +} + +bool PMInteriorEdit::isDataValid( ) +{ + if( !m_pIorEdit->isDataValid( ) ) return false; + if( !m_pCausticsEdit->isDataValid( ) ) return false; + if( !m_pDispersionEdit->isDataValid( ) ) return false; + if( !m_pDispSamplesEdit->isDataValid( ) ) return false; + if( !m_pFadeDistanceEdit->isDataValid( ) ) return false; + if( !m_pFadePowerEdit->isDataValid( ) ) return false; + if( !m_pFadeDistanceEdit->isDataValid( ) ) return false; + + return Base::isDataValid( ); +} + +void PMInteriorEdit::slotIorClicked( ) +{ + if( m_pEnableIorEdit->isChecked( ) ) + { + m_pIorEdit->setEnabled( true ); + m_pEnableDispersionEdit->setEnabled( true ); + m_pEnableDispSamplesEdit->setEnabled( true ); + } + else + { + m_pIorEdit->setEnabled( false ); + m_pEnableDispersionEdit->setEnabled( false ); + m_pEnableDispSamplesEdit->setEnabled( false ); + m_pEnableDispersionEdit->setChecked( false ); + m_pEnableDispSamplesEdit->setChecked( false ); + slotDispersionClicked( ); + slotDispSamplesClicked( ); + } + emit dataChanged( ); +} + +void PMInteriorEdit::slotCausticsClicked( ) +{ + m_pCausticsEdit->setEnabled( m_pEnableCausticsEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMInteriorEdit::slotDispersionClicked( ) +{ + m_pDispersionEdit->setEnabled( m_pEnableDispersionEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMInteriorEdit::slotDispSamplesClicked( ) +{ + m_pDispSamplesEdit->setEnabled( m_pEnableDispSamplesEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMInteriorEdit::slotFadeDistanceClicked( ) +{ + m_pFadeDistanceEdit->setEnabled( m_pEnableFadeDistanceEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMInteriorEdit::slotFadePowerClicked( ) +{ + m_pFadePowerEdit->setEnabled( m_pEnableFadePowerEdit->isChecked( ) ); + emit dataChanged( ); +} + +#include "pminterioredit.moc" diff --git a/kpovmodeler/pminterioredit.h b/kpovmodeler/pminterioredit.h new file mode 100644 index 00000000..93564bcb --- /dev/null +++ b/kpovmodeler/pminterioredit.h @@ -0,0 +1,85 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMINTERIOREDIT_H +#define PMINTERIOREDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebaseedit.h" + +class PMInterior; +class PMIntEdit; +class PMFloatEdit; +class PMColorEdit; +class QCheckBox; +class QLabel; + +/** + * Dialog edit class for @ref PMInterior + */ +class PMInteriorEdit : public PMTextureBaseEdit +{ + Q_OBJECT + typedef PMTextureBaseEdit Base; +public: + /** + * Creates a PMInteriorEdit with parent and name + */ + PMInteriorEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + void slotIorClicked( ); + void slotCausticsClicked( ); + void slotDispersionClicked( ); + void slotDispSamplesClicked( ); + void slotFadePowerClicked( ); + void slotFadeDistanceClicked( ); + +private: + PMInterior* m_pDisplayedObject; + PMFloatEdit* m_pIorEdit; + PMFloatEdit* m_pCausticsEdit; + PMFloatEdit* m_pDispersionEdit; + PMIntEdit* m_pDispSamplesEdit; + PMFloatEdit* m_pFadeDistanceEdit; + PMFloatEdit* m_pFadePowerEdit; + QCheckBox* m_pEnableIorEdit; + QCheckBox* m_pEnableCausticsEdit; + QCheckBox* m_pEnableDispersionEdit; + QCheckBox* m_pEnableDispSamplesEdit; + QCheckBox* m_pEnableFadeDistanceEdit; + QCheckBox* m_pEnableFadePowerEdit; +}; + + +#endif diff --git a/kpovmodeler/pminteriortexture.cpp b/kpovmodeler/pminteriortexture.cpp new file mode 100644 index 00000000..f379e4b6 --- /dev/null +++ b/kpovmodeler/pminteriortexture.cpp @@ -0,0 +1,75 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pminteriortexture.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pminteriortextureedit.h" + +#include + +PMMetaObject* PMInteriorTexture::s_pMetaObject = 0; +PMObject* createNewInteriorTexture( PMPart* part ) +{ + return new PMInteriorTexture( part ); +} + +PMInteriorTexture::PMInteriorTexture( PMPart* part ) + : Base( part ) +{ +} + +PMInteriorTexture::PMInteriorTexture( const PMInteriorTexture& t ) + : Base( t ) +{ +} + +PMInteriorTexture::~PMInteriorTexture( ) +{ +} + +PMMetaObject* PMInteriorTexture::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "InteriorTexture", Base::metaObject( ), + createNewInteriorTexture ); + } + return s_pMetaObject; +} + +void PMInteriorTexture::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMInteriorTexture::description( ) const +{ + return i18n( "interior texture" ); +} + +PMDialogEditBase* PMInteriorTexture::editWidget( QWidget* parent ) const +{ + return new PMInteriorTextureEdit( parent ); +} + diff --git a/kpovmodeler/pminteriortexture.h b/kpovmodeler/pminteriortexture.h new file mode 100644 index 00000000..8682e69d --- /dev/null +++ b/kpovmodeler/pminteriortexture.h @@ -0,0 +1,71 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMINTERIORTEXTURE_H +#define PMINTERIORTEXTURE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebase.h" + +/** + * Class for povray interior textures + */ +class PMInteriorTexture : public PMTextureBase +{ + typedef PMTextureBase Base; +public: + /** + * Creates an PMInteriorTexture + */ + PMInteriorTexture( PMPart* part ); + /** + * Copy constructor + */ + PMInteriorTexture( const PMInteriorTexture& t ); + /** + * Deletes the object + */ + virtual ~PMInteriorTexture( ); + + /** */ + virtual PMObject* copy( ) const { return new PMInteriorTexture( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** + * Returns a new @ref PMTextureEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pminteriortexture" ); } + +private: + static PMMetaObject* s_pMetaObject; +}; + + +#endif diff --git a/kpovmodeler/pminteriortextureedit.cpp b/kpovmodeler/pminteriortextureedit.cpp new file mode 100644 index 00000000..47fe6f38 --- /dev/null +++ b/kpovmodeler/pminteriortextureedit.cpp @@ -0,0 +1,44 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pminteriortextureedit.h" +#include "pminteriortexture.h" +#include "pmlinkedit.h" + +#include +#include +#include + + +PMInteriorTextureEdit::PMInteriorTextureEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMInteriorTextureEdit::displayObject( PMObject* o ) +{ + if( o->isA( "InteriorTexture" ) ) + { + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMInteriorTextureEdit: Can't display object\n"; +} + +#include "pminteriortextureedit.moc" diff --git a/kpovmodeler/pminteriortextureedit.h b/kpovmodeler/pminteriortextureedit.h new file mode 100644 index 00000000..1594ef6e --- /dev/null +++ b/kpovmodeler/pminteriortextureedit.h @@ -0,0 +1,58 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMINTERIORTEXTUREEDIT_H +#define PMINTERIORTEXTUREEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebaseedit.h" + +class PMInteriorTexture; + +/** + * Dialog edit class for @ref PMTexture + */ +class PMInteriorTextureEdit : public PMTextureBaseEdit +{ + Q_OBJECT + typedef PMTextureBaseEdit Base; +public: + /** + * Creates a PMTextureEdit with parent and name + */ + PMInteriorTextureEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + +protected: + /** */ +// virtual void createTopWidgets( ); + /** */ +// virtual void saveContents( ); + +private: + PMInteriorTexture* m_pDisplayedObject; +}; + + +#endif diff --git a/kpovmodeler/pmiomanager.cpp b/kpovmodeler/pmiomanager.cpp new file mode 100644 index 00000000..72a081d2 --- /dev/null +++ b/kpovmodeler/pmiomanager.cpp @@ -0,0 +1,96 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmiomanager.h" +#include "pmdebug.h" +#include "pmpovray31format.h" +#include "pmpovray35format.h" + +PMIOFormat::PMIOFormat( ) +{ +} + +PMIOFormat::~PMIOFormat( ) +{ + +} + +PMIOManager::PMIOManager( PMPart* part ) +{ + m_pPart = part; + m_formats.setAutoDelete( true ); + + addFormat( new PMPovray35Format( ) ); + //addFormat( new PMPovray31Format( ) ); +} + +PMIOManager::~PMIOManager( ) +{ + +} + +void PMIOManager::addFormat( PMIOFormat* format ) +{ + if( !format ) + return; + if( !m_formats.containsRef( format ) ) + { + if( !m_dict.find( format->name( ) ) ) + { + m_formats.append( format ); + m_dict.insert( format->name( ), format ); + } + else + kdError( PMArea ) << "Format " << format->name( ) << "already registered" << endl; + } + else + kdError( PMArea ) << "Format " << format->name( ) << "already registered" << endl; +} + +void PMIOManager::removeFormat( const QString& name ) +{ + PMIOFormat* pFormat = format( name ); + if( pFormat ) + { + m_dict.remove( name ); + m_formats.removeRef( pFormat ); + } +} + +PMIOFormat* PMIOManager::format( const QString& name ) const +{ + return m_dict.find( name ); +} + +PMIOFormat* PMIOManager::formatForMimeType( const QString& mime ) const +{ + QPtrListIterator it( m_formats ); + bool found = false; + PMIOFormat* pFormat = 0; + + while( it.current( ) && !found ) + { + pFormat = it.current( ); + if( pFormat->mimeType( ) == mime ) + found = true; + else + ++it; + } + if( found ) + return pFormat; + return 0; +} diff --git a/kpovmodeler/pmiomanager.h b/kpovmodeler/pmiomanager.h new file mode 100644 index 00000000..ac3b78eb --- /dev/null +++ b/kpovmodeler/pmiomanager.h @@ -0,0 +1,184 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMIOMANAGER +#define PMIOMANAGER + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +class PMParser; +class PMSerializer; +class PMRenderer; +class PMPart; + +class QIODevice; + +/** + * Description class for input and output formats. + * + * A format may provide the following services: + * + * Import: The class can provide a parser to load and import data + * + * Export: The class can provide a output device to export and save data + * + * Renderer: A renderer exists to render the exported data + * + * The class @ref PMIOManager stores a list of instances + * of this class + */ +class PMIOFormat +{ +public: + /** + * Format type enum + */ + enum Services { Import = 1, Export = 2, Renderer = 4, + AllServices = Import | Export | Renderer }; + /** + * Default constructor + */ + PMIOFormat( ); + /** + * Destructor + */ + virtual ~PMIOFormat( ); + + /** + * Returns an unique name of this format. + */ + virtual QString name( ) const = 0; + /** + * Returns a translated description of this format + */ + virtual QString description( ) const = 0; + /** + * Returns the supported services + * (a bitwise combination of the Services enum values) + */ + virtual int services( ) const = 0; + /** + * Returns a parser to parse the io device. + * + * The caller is responsible to delete the returned parser. + */ + virtual PMParser* newParser( PMPart*, QIODevice* ) const + { + return 0; + }; + /** + * Returns a parser to parse the byte array. + * + * The caller is responsible to delete the returned parser. + */ + virtual PMParser* newParser( PMPart*, const QByteArray& ) const + { + return 0; + }; + /** + * Returns an output device to export objects or the complete + * scene to the given io device. + * + * The caller is responsible to delete the returned device + */ + virtual PMSerializer* newSerializer( QIODevice* ) + { + return 0; + } + /** + * Returns a new renderer + */ + virtual PMRenderer* newRenderer( PMPart* ) const + { + return 0; + } + /** + * Returns the mime type for this format + */ + virtual QString mimeType( ) const + { + return QString::null; + } + /** + * Returns a list of patterns for the import file dialog + */ + virtual QStringList importPatterns( ) const + { + return QStringList( ); + } + /** + * Returns a list of patterns for the export file dialog + */ + virtual QStringList exportPatterns( ) const + { + return QStringList( ); + } +}; + +/** + * Manager class that handles all available input and output formats + * as well as renderers for one part + */ +class PMIOManager +{ +public: + /** + * Creates an io manager for the part + */ + PMIOManager( PMPart* part ); + /** + * Deletes the io manager + */ + ~PMIOManager( ); + + /** + * Adds a new format + */ + void addFormat( PMIOFormat* format ); + /** + * Removes a format by name + */ + void removeFormat( const QString& name ); + + /** + * Returns the list of registered io formats + */ + const QPtrList& formats( ) const { return m_formats; } + /** + * Returns a view type by name + */ + PMIOFormat* format( const QString& name ) const; + /** + * Returns the first io format that can handle the mime type + * or 0 if there is none + */ + PMIOFormat* formatForMimeType( const QString& mime ) const; + +private: + QPtrList m_formats; + QDict m_dict; + PMPart* m_pPart; +}; + +#endif diff --git a/kpovmodeler/pmisosurface.cpp b/kpovmodeler/pmisosurface.cpp new file mode 100644 index 00000000..16e5e247 --- /dev/null +++ b/kpovmodeler/pmisosurface.cpp @@ -0,0 +1,419 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmisosurface.h" + +#include "pmxmlhelper.h" +#include "pmisosurfaceedit.h" +#include "pmmemento.h" +#include "pmviewstructure.h" + +#include + +const PMIsoSurface::ContainedByType c_defaultContainedBy = PMIsoSurface::Box; +const PMVector c_defaultCorner1 = PMVector( -1, -1, -1 ); +const PMVector c_defaultCorner2 = PMVector( 1, 1, 1 ); +const PMVector c_defaultCenter = PMVector( 0, 0, 0 ); +const double c_defaultRadius = 1; + +const double c_defaultThreshold = 0.0; +const double c_defaultAccuracy = 0.001; +const double c_defaultMaxGradient = 1.1; +const bool c_defaultEvaluate = false; +const double c_defaultEvaluate0 = 5; +const double c_defaultEvaluate1 = 1.2; +const double c_defaultEvaluate2 = 0.95; +const double c_defaultOpen = false; +const int c_defaultMaxTrace = 1; +const bool c_defaultAllIntersections = false; + +PMDefinePropertyClass( PMIsoSurface, PMIsoSurfaceProperty ); + +PMViewStructure* PMIsoSurface::s_pDefaultViewStructure = 0; +PMMetaObject* PMIsoSurface::s_pMetaObject = 0; +PMObject* createNewIsoSurface( PMPart* part ) +{ + return new PMIsoSurface( part ); +} + +PMIsoSurface::PMIsoSurface( PMPart* part ) + : Base( part ) +{ + m_containedBy = c_defaultContainedBy; + m_corner1 = c_defaultCorner1; + m_corner2 = c_defaultCorner2; + m_center = c_defaultCenter; + m_radius = c_defaultRadius; + m_threshold = c_defaultThreshold; + m_accuracy = c_defaultAccuracy; + m_maxGradient = c_defaultMaxGradient; + m_bEvaluate = c_defaultEvaluate; + m_evaluate[0] = c_defaultEvaluate0; + m_evaluate[1] = c_defaultEvaluate1; + m_evaluate[2] = c_defaultEvaluate2; + m_bOpen = c_defaultOpen; + m_maxTrace = c_defaultMaxTrace; + m_bAllIntersections = c_defaultAllIntersections; +} + +PMIsoSurface::PMIsoSurface( const PMIsoSurface& b ) + : Base( b ) +{ + m_function = b.m_function; + m_containedBy = b.m_containedBy; + m_corner1 = b.m_corner1; + m_corner2 = b.m_corner2; + m_center = b.m_center; + m_radius = b.m_radius; + m_threshold = b.m_threshold; + m_accuracy = b.m_accuracy; + m_maxGradient = m_maxGradient; + m_bEvaluate = b.m_bEvaluate; + m_evaluate[0] = b.m_evaluate[0]; + m_evaluate[1] = b.m_evaluate[1]; + m_evaluate[2] = b.m_evaluate[2]; + m_bOpen = b.m_bOpen; + m_maxTrace = b.m_maxTrace; + m_bAllIntersections = b.m_bAllIntersections; +} + +PMIsoSurface::~PMIsoSurface( ) +{ +} + +QString PMIsoSurface::description( ) const +{ + return i18n( "isosurface" ); +} + +void PMIsoSurface::serialize( QDomElement& e, QDomDocument& doc ) const +{ + QDomText t = doc.createTextNode( m_function ); + e.appendChild( t ); + + if( m_containedBy == Box ) + e.setAttribute( "contained_by", "box" ); + else + e.setAttribute( "contained_by", "sphere" ); + e.setAttribute( "corner_a", m_corner1.serializeXML( ) ); + e.setAttribute( "corner_b", m_corner2.serializeXML( ) ); + e.setAttribute( "center", m_center.serializeXML( ) ); + e.setAttribute( "radius", m_radius ); + e.setAttribute( "threshold", m_threshold ); + e.setAttribute( "accuracy", m_accuracy ); + e.setAttribute( "max_gradient", m_maxGradient ); + e.setAttribute( "evaluate", m_bEvaluate ); + e.setAttribute( "e0", m_evaluate[0] ); + e.setAttribute( "e1", m_evaluate[1] ); + e.setAttribute( "e2", m_evaluate[2] ); + e.setAttribute( "open", m_bOpen ); + e.setAttribute( "max_trace", m_maxTrace ); + e.setAttribute( "all_intersections", m_bAllIntersections ); + Base::serialize( e, doc ); +} + +void PMIsoSurface::readAttributes( const PMXMLHelper& h ) +{ + QDomNode e = h.element( ).firstChild( ); + if( e.isText( ) ) + m_function = e.toText( ).data( ); + + QString str = h.stringAttribute( "contained_by", "" ); + if( str == "sphere" ) + m_containedBy = Sphere; + else + m_containedBy = Box; + + m_corner1 = h.vectorAttribute( "corner_a", c_defaultCorner1 ); + m_corner2 = h.vectorAttribute( "corner_b", c_defaultCorner1 ); + m_center = h.vectorAttribute( "center", c_defaultCenter ); + m_radius = h.doubleAttribute( "radius", c_defaultRadius ); + m_threshold = h.doubleAttribute( "threshold", c_defaultThreshold ); + m_accuracy = h.doubleAttribute( "accuracy", c_defaultAccuracy ); + m_maxGradient = h.doubleAttribute( "max_gradient", c_defaultMaxGradient ); + m_bEvaluate = h.boolAttribute( "evaluate", c_defaultEvaluate ); + m_evaluate[0] = h.doubleAttribute( "e0", c_defaultEvaluate0 ); + m_evaluate[1] = h.doubleAttribute( "e1", c_defaultEvaluate1 ); + m_evaluate[2] = h.doubleAttribute( "e2", c_defaultEvaluate2 ); + m_bOpen = h.boolAttribute( "open", c_defaultOpen ); + m_maxTrace = h.intAttribute( "max_trace", c_defaultMaxTrace ); + m_bAllIntersections = h.boolAttribute( "all_intersections", c_defaultAllIntersections ); + + Base::readAttributes( h ); +} + +PMMetaObject* PMIsoSurface::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "IsoSurface", Base::metaObject( ), + createNewIsoSurface ); + // TODO + /* + s_pMetaObject->addProperty( + new PMIsoSurfaceProperty( "corner1", &PMIsoSurface::setCorner1, &PMIsoSurface::corner1 ) ); + s_pMetaObject->addProperty( + new PMIsoSurfaceProperty( "corner2", &PMIsoSurface::setCorner2, &PMIsoSurface::corner2 ) ); + */ + } + return s_pMetaObject; +} + +void PMIsoSurface::setFunction( const QString& f ) +{ + if( f != m_function ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, FunctionID, m_function ); + m_function = f; + } +} + +void PMIsoSurface::setContainedBy( ContainedByType type ) +{ + if( type != m_containedBy ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, ContainedByID, m_containedBy ); + m_containedBy = type; + } +} + +void PMIsoSurface::setCorner1( const PMVector& p ) +{ + if( p != m_corner1 ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, Corner1ID, m_corner1 ); + m_corner1 = p; + m_corner1.resize( 3 ); + //setViewStructureChanged( ); + } +} + +void PMIsoSurface::setCorner2( const PMVector& p ) +{ + if( p != m_corner2 ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, Corner2ID, m_corner2 ); + m_corner2 = p; + m_corner2.resize( 3 ); + //setViewStructureChanged( ); + } +} + +void PMIsoSurface::setCenter( const PMVector& v ) +{ + if( v != m_center ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, CenterID, m_center ); + m_center = v; + } +} + +void PMIsoSurface::setRadius( double r ) +{ + if( r != m_radius ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, RadiusID, m_radius ); + m_radius = r; + } +} +void PMIsoSurface::setThreshold( double d ) +{ + if( d != m_threshold ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, ThresholdID, m_threshold ); + m_threshold = d; + } +} + +void PMIsoSurface::setAccuracy( double d ) +{ + if( d != m_accuracy ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, AccuracyID, m_accuracy ); + m_accuracy = d; + } +} + +void PMIsoSurface::setMaxGradient( double d ) +{ + if( d != m_maxGradient ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, MaxGradientID, m_maxGradient ); + m_maxGradient = d; + } +} +void PMIsoSurface::setEvaluate( bool yes ) +{ + if( yes != m_bEvaluate ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, EvaluateID, m_evaluate ); + m_bEvaluate = yes; + } +} + +void PMIsoSurface::setEvaluateValue( int index, double v ) +{ + if( index < 0 || index > 2 ) + { + kdError( PMArea ) << "Illegal index in PMIsoSurface::setEvaluateValue" << endl; + return; + } + + if( v != m_evaluate[index] ) + { + if( m_pMemento ) + { + int id = Evaluate0ID; + switch( index ) + { + case 0: id = Evaluate0ID; break; + case 1: id = Evaluate1ID; break; + case 2: id = Evaluate2ID; break; + default: break; + } + + m_pMemento->addData( s_pMetaObject, id, m_evaluate[index] ); + } + m_evaluate[index] = v; + } +} + +void PMIsoSurface::setOpen( bool yes ) +{ + if( yes != m_bOpen ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, OpenID, m_bOpen ); + m_bOpen = yes; + } +} + +void PMIsoSurface::setMaxTrace( int i ) +{ + if( i != m_maxTrace ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, MaxTraceID, m_maxTrace ); + m_maxTrace = i; + } +} + +void PMIsoSurface::setAllIntersections( bool yes ) +{ + if( yes != m_bAllIntersections ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, AllIntersectionsID, m_bAllIntersections ); + m_bAllIntersections = yes; + } +} + +PMDialogEditBase* PMIsoSurface::editWidget( QWidget* parent ) const +{ + return new PMIsoSurfaceEdit( parent ); +} + +void PMIsoSurface::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case FunctionID: + setFunction( data->stringData( ) ); + break; + case ContainedByID: + setContainedBy( ( ContainedByType ) data->intData( ) ); + break; + case Corner1ID: + setCorner1( data->vectorData( ) ); + break; + case Corner2ID: + setCorner2( data->vectorData( ) ); + break; + case CenterID: + setCenter( data->vectorData( ) ); + break; + case RadiusID: + setRadius( data->doubleData( ) ); + break; + case ThresholdID: + setThreshold( data->doubleData( ) ); + break; + case AccuracyID: + setAccuracy( data->doubleData( ) ); + break; + case MaxGradientID: + setMaxGradient( data->doubleData( ) ); + break; + case EvaluateID: + setEvaluate( data->boolData( ) ); + break; + case Evaluate0ID: + setEvaluateValue( 0, data->doubleData( ) ); + break; + case Evaluate1ID: + setEvaluateValue( 1, data->doubleData( ) ); + break; + case Evaluate2ID: + setEvaluateValue( 2, data->doubleData( ) ); + break; + case OpenID: + setOpen( data->boolData( ) ); + break; + case MaxTraceID: + setMaxTrace( data->intData( ) ); + break; + case AllIntersectionsID: + setAllIntersections( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMIsoSurface::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + + +void PMIsoSurface::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} diff --git a/kpovmodeler/pmisosurface.h b/kpovmodeler/pmisosurface.h new file mode 100644 index 00000000..0646aff3 --- /dev/null +++ b/kpovmodeler/pmisosurface.h @@ -0,0 +1,234 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMISOSURFACE_H +#define PMISOSURFACE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" +#include "pmvector.h" + +class PMViewStructure; + +/** + * Class for povray boxes. + */ + +class PMIsoSurface : public PMSolidObject +{ + typedef PMSolidObject Base; +public: + /** + * Enum for the "contained_by" statement + */ + enum ContainedByType { Box, Sphere }; + /** + * Creates an empty PMIsoSurface + */ + PMIsoSurface( PMPart* part ); + /** + * Copy constructor + */ + PMIsoSurface( const PMIsoSurface& b ); + /** + * deletes the PMIsoSurface + */ + virtual ~PMIsoSurface( ); + + /** */ + virtual PMObject* copy( ) const { return new PMIsoSurface( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMIsoSurfaceEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmisosurface" ); } + + + /** + * Sets the isosurface function + */ + void setFunction( const QString& f ); + /** + * Returns the isosurface function + */ + QString function( ) const { return m_function; } + /** + * Sets the type of the contained_by object + */ + void setContainedBy( ContainedByType type ); + /** + * Returns the type of the contained_by object + */ + ContainedByType containedBy( ) const { return m_containedBy; } + /** + * Sets the first corner of a contained_by box + */ + void setCorner1( const PMVector& v ); + /** + * Returns the first corner of a contained_by box + */ + PMVector corner1( ) const { return m_corner1; } + /** + * Sets the second corner of a contained_by box + */ + void setCorner2( const PMVector& v ); + /** + * Returns the second corner of a contained_by box + */ + PMVector corner2( ) const { return m_corner2; } + /** + * Sets the center of a contained_by sphere + */ + void setCenter( const PMVector& v ); + /** + * Returns the center of a contained_by sphere + */ + PMVector center( ) const { return m_center; } + /** + * Sets the radius of a contained_by sphere + */ + void setRadius( double r ); + /** + * Returns the radius of a contained_by sphere + */ + double radius( ) const { return m_radius; } + /** + * Sets the threshold + */ + void setThreshold( double d ); + /** + * Returns the Threshold + */ + double threshold( ) const { return m_threshold; } + /** + * Sets the accuracy + */ + void setAccuracy( double d ); + /** + * Returns the accuracy + */ + double accuracy( ) const { return m_accuracy; } + /** + * Sets the maximal gradient + */ + void setMaxGradient( double d ); + /** + * Returns the maximal Gradient + */ + double maxGradient( ) const { return m_maxGradient; } + /** + * Enables/disables the evaluate statement + */ + void setEvaluate( bool yes ); + /** + * Returns the evaluate flag + */ + bool evaluate( ) const { return m_bEvaluate; } + /** + * Sets the i-th evaluate value, index is in [0..2] + */ + void setEvaluateValue( int index, double v ); + /** + * Returns the i-th evaluate value + */ + double evaluateValue( int index ) const { return m_evaluate[index]; } + /** + * Sets the open flag + */ + void setOpen( bool yes ); + /** + * Returns the open flag + */ + bool open( ) const { return m_bOpen; } + /** + * Sets the maximal number of intersections + */ + void setMaxTrace( int i ); + /** + * Returns the maximal number of intersections + */ + int maxTrace( ) const { return m_maxTrace; } + /** + * Sets the all intersections flag + */ + void setAllIntersections( bool yes ); + /** + * Returns the all intersections flag + */ + bool allIntersections( ) const { return m_bAllIntersections; } + + + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual void cleanUp( ) const; + +protected: + /** */ + //virtual bool isDefault( ); + /** */ + //virtual void createViewStructure( ); + /** */ + //virtual PMViewStructure* defaultViewStructure( ) const; + +private: + /** + * IDs for @ref PMMementoData + */ + enum PMIsoSurfaceMementoID { FunctionID, ContainedByID, Corner1ID, Corner2ID, + CenterID, RadiusID, ThresholdID, AccuracyID, + MaxGradientID, EvaluateID, + Evaluate0ID, Evaluate1ID, Evaluate2ID, + OpenID, MaxTraceID, AllIntersectionsID }; + + QString m_function; + ContainedByType m_containedBy; + PMVector m_corner1, m_corner2, m_center; + double m_radius, m_threshold, m_accuracy, m_maxGradient; + bool m_bEvaluate; + double m_evaluate[3]; + bool m_bOpen; + int m_maxTrace; + bool m_bAllIntersections; + + /** + * The default view structure. It can be shared between boxes + */ + static PMViewStructure* s_pDefaultViewStructure; + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmisosurfaceedit.cpp b/kpovmodeler/pmisosurfaceedit.cpp new file mode 100644 index 00000000..b4eb0216 --- /dev/null +++ b/kpovmodeler/pmisosurfaceedit.cpp @@ -0,0 +1,326 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmisosurfaceedit.h" +#include "pmisosurface.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" + +#include +#include +#include +#include +#include +#include + +PMIsoSurfaceEdit::PMIsoSurfaceEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMIsoSurfaceEdit::createTopWidgets( ) +{ + int i; + QGridLayout* gl; + QHBoxLayout* hl; + + Base::createTopWidgets( ); + + m_pFunction = new QLineEdit( this ); + m_pContainedBy = new QComboBox( false, this ); + m_pContainedBy->insertItem( i18n( "Box" ) ); + m_pContainedBy->insertItem( i18n( "Sphere" ) ); + + m_pCorner1 = new PMVectorEdit( "x", "y", "z", this ); + m_pCorner2 = new PMVectorEdit( "x", "y", "z", this ); + m_pCenter = new PMVectorEdit( "x", "y", "z", this ); + m_pRadius = new PMFloatEdit( this ); + m_pCorner1Label = new QLabel( i18n( "Corner1:" ), this ); + m_pCorner2Label = new QLabel( i18n( "Corner2:" ), this ); + m_pCenterLabel = new QLabel( i18n( "Center:" ), this ); + m_pRadiusLabel = new QLabel( i18n( "Radius:" ), this ); + + m_pThreshold = new PMFloatEdit( this ); + m_pAccuracy = new PMFloatEdit( this ); + m_pAccuracy->setValidation( true, 1e-8, false, 0 ); + m_pMaxGradient = new PMFloatEdit( this ); + m_pMaxGradient->setValidation( true, 1e-8, false, 0 ); + m_pEvaluate = new QCheckBox( i18n( "Adapt maximum gradient" ), this ); + for( i = 0; i < 3; i++ ) + m_pEvaluateValue[i] = new PMFloatEdit( this ); + m_pMaxTrace = new PMIntEdit( this ); + m_pMaxTrace->setValidation( true, 1, false, 0 ); + m_pAllIntersections = new QCheckBox( i18n( "All intersections" ), this ); + m_pOpen = new QCheckBox( i18n( "type of the object", "Open" ), this ); + + gl = new QGridLayout( topLayout( ), 8, 2 ); + gl->addWidget( new QLabel( i18n( "Function:" ), this ), 0, 0 ); + gl->addWidget( m_pFunction, 0, 1 ); + gl->addWidget( new QLabel( i18n( "Container:" ), this ), 1, 0 ); + gl->addWidget( m_pContainedBy, 1, 1 ); + gl->addWidget( m_pCorner1Label, 2, 0 ); + gl->addWidget( m_pCorner1, 2, 1 ); + gl->addWidget( m_pCorner2Label, 3, 0 ); + gl->addWidget( m_pCorner2, 3, 1 ); + gl->addWidget( m_pCenterLabel, 4, 0 ); + gl->addWidget( m_pCenter, 4, 1 ); + gl->addWidget( m_pRadiusLabel, 5, 0 ); + gl->addWidget( m_pRadius, 5, 1 ); + gl->addWidget( new QLabel( i18n( "Threshold:" ), this ), 6, 0 ); + gl->addWidget( m_pThreshold, 6, 1 ); + gl->addWidget( new QLabel( i18n( "Accuracy:" ), this ), 7, 0 ); + gl->addWidget( m_pAccuracy, 7, 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Maximum gradient:" ), this ) ); + hl->addWidget( m_pMaxGradient ); + + topLayout( )->addWidget( m_pEvaluate ); + hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Values:" ), this ) ); + for( i = 0; i < 3; i++ ) + { + hl->addWidget( new QLabel( QString( "P%1" ).arg( i ), this ) ); + hl->addWidget( m_pEvaluateValue[i] ); + } + + hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Maximum traces:" ), this ) ); + hl->addWidget( m_pMaxTrace ); + topLayout( )->addWidget( m_pAllIntersections ); + topLayout( )->addWidget( m_pOpen ); + + connect( m_pFunction, SIGNAL( textChanged( const QString& ) ), + SLOT( textChanged( const QString& ) ) ); + connect( m_pContainedBy, SIGNAL( activated( int ) ), + SLOT( currentChanged( int ) ) ); + connect( m_pCorner1, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pCorner2, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pCenter, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pRadius, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pThreshold, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pAccuracy, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pMaxGradient, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pEvaluate, SIGNAL( toggled( bool ) ), + SLOT( evaluateToggled( bool ) ) ); + connect( m_pMaxTrace, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + for( i = 0; i < 3; i++ ) + connect( m_pEvaluateValue[i], SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pOpen, SIGNAL( toggled( bool ) ), SLOT( toggled( bool ) ) ); + connect( m_pAllIntersections, SIGNAL( toggled( bool ) ), + SLOT( allToggled( bool ) ) ); +} + +void PMIsoSurfaceEdit::displayObject( PMObject* o ) +{ + int i; + + if( o->isA( "IsoSurface" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMIsoSurface* ) o; + + m_pFunction->setText( m_pDisplayedObject->function( ) ); + if( m_pDisplayedObject->containedBy( ) == PMIsoSurface::Box ) + { + m_pContainedBy->setCurrentItem( 0 ); + m_pCorner1Label->show( ); + m_pCorner2Label->show( ); + m_pCorner1->show( ); + m_pCorner2->show( ); + m_pCenterLabel->hide( ); + m_pCenter->hide( ); + m_pRadiusLabel->hide( ); + m_pRadius->hide( ); + } + else + { + m_pContainedBy->setCurrentItem( 1 ); + m_pCorner1Label->hide( ); + m_pCorner2Label->hide( ); + m_pCorner1->hide( ); + m_pCorner2->hide( ); + m_pCenterLabel->show( ); + m_pCenter->show( ); + m_pRadiusLabel->show( ); + m_pRadius->show( ); + } + + m_pCorner1->setVector( m_pDisplayedObject->corner1( ) ); + m_pCorner2->setVector( m_pDisplayedObject->corner2( ) ); + m_pCenter->setVector( m_pDisplayedObject->center( ) ); + m_pRadius->setValue( m_pDisplayedObject->radius( ) ); + m_pThreshold->setValue( m_pDisplayedObject->threshold( ) ); + m_pAccuracy->setValue( m_pDisplayedObject->accuracy( ) ); + m_pMaxGradient->setValue( m_pDisplayedObject->maxGradient( ) ); + bool ev = m_pDisplayedObject->evaluate( ); + m_pEvaluate->setChecked( ev ); + + for( i = 0; i < 3; i++ ) + { + m_pEvaluateValue[i]->setValue( m_pDisplayedObject->evaluateValue( i ) ); + m_pEvaluateValue[i]->setEnabled( ev ); + } + + m_pOpen->setChecked( m_pDisplayedObject->open( ) ); + m_pMaxTrace->setValue( m_pDisplayedObject->maxTrace( ) ); + bool all = m_pDisplayedObject->allIntersections( ); + m_pAllIntersections->setChecked( all ); + m_pMaxTrace->setEnabled( !all ); + + m_pFunction->setReadOnly( readOnly ); + m_pContainedBy->setEnabled( !readOnly ); + m_pCorner1->setReadOnly( readOnly ); + m_pCorner2->setReadOnly( readOnly ); + m_pCenter->setReadOnly( readOnly ); + m_pRadius->setReadOnly( readOnly ); + m_pThreshold->setReadOnly( readOnly ); + m_pAccuracy->setReadOnly( readOnly ); + m_pMaxGradient->setReadOnly( readOnly ); + m_pEvaluate->setEnabled( !readOnly ); + for( i = 0; i < 3; i++ ) + m_pEvaluateValue[i]->setReadOnly( readOnly ); + m_pOpen->setEnabled( !readOnly ); + m_pMaxTrace->setReadOnly( readOnly ); + m_pAllIntersections->setEnabled( !readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMIsoSurfaceEdit: Can't display object\n"; +} + +void PMIsoSurfaceEdit::saveContents( ) +{ + int i; + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setFunction( m_pFunction->text( ) ); + if( m_pContainedBy->currentItem( ) == 0 ) + { + m_pDisplayedObject->setContainedBy( PMIsoSurface::Box ); + m_pDisplayedObject->setCorner1( m_pCorner1->vector( ) ); + m_pDisplayedObject->setCorner2( m_pCorner2->vector( ) ); + } + else + { + m_pDisplayedObject->setContainedBy( PMIsoSurface::Sphere ); + m_pDisplayedObject->setCenter( m_pCenter->vector( ) ); + m_pDisplayedObject->setRadius( m_pRadius->value( ) ); + } + m_pDisplayedObject->setThreshold( m_pThreshold->value( ) ); + m_pDisplayedObject->setAccuracy( m_pAccuracy->value( ) ); + m_pDisplayedObject->setMaxGradient( m_pMaxGradient->value( ) ); + m_pDisplayedObject->setEvaluate( m_pEvaluate->isChecked( ) ); + if( m_pEvaluate->isChecked( ) ) + for( i = 0; i < 3; i++ ) + m_pDisplayedObject->setEvaluateValue( i, m_pEvaluateValue[i]->value( ) ); + m_pDisplayedObject->setOpen( m_pOpen->isChecked( ) ); + m_pDisplayedObject->setAllIntersections( m_pAllIntersections->isChecked( ) ); + if( !m_pAllIntersections->isChecked( ) ) + m_pDisplayedObject->setMaxTrace( m_pMaxTrace->value( ) ); + } +} + +bool PMIsoSurfaceEdit::isDataValid( ) +{ + int i; + + if( m_pContainedBy->currentItem( ) == 0 ) + { + if( !m_pCorner1->isDataValid( ) ) + return false; + if( !m_pCorner2->isDataValid( ) ) + return false; + } + else + { + if( !m_pCenter->isDataValid( ) ) + return false; + if( !m_pRadius->isDataValid( ) ) + return false; + } + if( !m_pThreshold->isDataValid( ) ) + return false; + if( !m_pAccuracy->isDataValid( ) ) + return false; + if( !m_pMaxGradient->isDataValid( ) ) + return false; + if( m_pEvaluate->isChecked( ) ) + for( i = 0; i < 3; i++ ) + if( !m_pEvaluateValue[i]->isDataValid( ) ) + return false; + if( !m_pAllIntersections->isChecked( ) && !m_pMaxTrace->isDataValid( ) ) + return false; + return Base::isDataValid( ); +} + +void PMIsoSurfaceEdit::textChanged( const QString& ) +{ + emit dataChanged( ); +} + +void PMIsoSurfaceEdit::currentChanged( int i ) +{ + if( i == 0 ) + { + m_pCorner1Label->show( ); + m_pCorner2Label->show( ); + m_pCorner1->show( ); + m_pCorner2->show( ); + m_pCenterLabel->hide( ); + m_pCenter->hide( ); + m_pRadiusLabel->hide( ); + m_pRadius->hide( ); + } + else + { + m_pCorner1Label->hide( ); + m_pCorner2Label->hide( ); + m_pCorner1->hide( ); + m_pCorner2->hide( ); + m_pCenterLabel->show( ); + m_pCenter->show( ); + m_pRadiusLabel->show( ); + m_pRadius->show( ); + } + emit dataChanged( ); +} + +void PMIsoSurfaceEdit::evaluateToggled( bool yes ) +{ + int i; + for( i = 0; i < 3; i++ ) + m_pEvaluateValue[i]->setEnabled( yes ); + emit dataChanged( ); +} + +void PMIsoSurfaceEdit::allToggled( bool yes ) +{ + m_pMaxTrace->setEnabled( !yes ); + emit dataChanged( ); +} + +void PMIsoSurfaceEdit::toggled( bool ) +{ + emit dataChanged( ); +} + +#include "pmisosurfaceedit.moc" diff --git a/kpovmodeler/pmisosurfaceedit.h b/kpovmodeler/pmisosurfaceedit.h new file mode 100644 index 00000000..9ee6e872 --- /dev/null +++ b/kpovmodeler/pmisosurfaceedit.h @@ -0,0 +1,92 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMISOSURFACEEDIT_H +#define PMISOSURFACEEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" + +class PMIsoSurface; +class PMVectorEdit; +class PMFloatEdit; +class PMIntEdit; +class QCheckBox; +class QComboBox; +class QLabel; +class QLineEdit; + +/** + * Dialog edit class for @ref PMIsoSurface + */ +class PMIsoSurfaceEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMIsoSurfaceEdit with parent and name + */ + PMIsoSurfaceEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private slots: + void textChanged( const QString& ); + void currentChanged( int i ); + void evaluateToggled( bool ); + void allToggled( bool ); + void toggled( bool ); + +private: + PMIsoSurface* m_pDisplayedObject; + QLineEdit* m_pFunction; + QComboBox* m_pContainedBy; + PMVectorEdit* m_pCorner1; + PMVectorEdit* m_pCorner2; + PMVectorEdit* m_pCenter; + PMFloatEdit* m_pRadius; + QLabel* m_pCorner1Label; + QLabel* m_pCorner2Label; + QLabel* m_pCenterLabel; + QLabel* m_pRadiusLabel; + PMFloatEdit* m_pThreshold; + PMFloatEdit* m_pAccuracy; + PMFloatEdit* m_pMaxGradient; + QCheckBox* m_pEvaluate; + PMFloatEdit* m_pEvaluateValue[3]; + QCheckBox* m_pOpen; + PMIntEdit* m_pMaxTrace; + QCheckBox* m_pAllIntersections; +}; + + +#endif diff --git a/kpovmodeler/pmjuliafractal.cpp b/kpovmodeler/pmjuliafractal.cpp new file mode 100644 index 00000000..49ca9de5 --- /dev/null +++ b/kpovmodeler/pmjuliafractal.cpp @@ -0,0 +1,449 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmjuliafractal.h" + +#include "pmxmlhelper.h" +#include "pmjuliafractaledit.h" +#include "pmmemento.h" +#include "pmviewstructure.h" +#include "pm3dcontrolpoint.h" +#include "pmenumproperty.h" + +#include + +const PMVector c_defaultJuliaParameter = PMVector( -0.083, 0.0, -0.83, -0.025 ); +const PMVector c_defaultSliceNormal = PMVector( 0.0, 0.0, 0.0, 1.0 ); +const double c_defaultSliceDistance = 0.0; +const int c_defaultMaxIterations = 20; +const PMJuliaFractal::AlgebraType c_defaultAlgebraType = PMJuliaFractal::Quaternion; +const QString c_defaultAlgebraString = "quaternion"; +const PMJuliaFractal::FunctionType c_defaultFunctionType = PMJuliaFractal::FTsqr; +const QString c_defaultFunctionString = "sqr"; +const PMVector c_defaultExponent = PMVector( 0.0, 0.0 ); +const double c_defaultPrecision = 20.0; + + +PMDefinePropertyClass( PMJuliaFractal, PMJuliaFractalProperty ); +PMDefineEnumPropertyClass( PMJuliaFractal, PMJuliaFractal::AlgebraType, + PMAlgebraTypeProperty ); +PMDefineEnumPropertyClass( PMJuliaFractal, PMJuliaFractal::FunctionType, + PMFunctionTypeProperty ); + +PMMetaObject* PMJuliaFractal::s_pMetaObject = 0; +PMObject* createNewJuliaFractal( PMPart* part ) +{ + return new PMJuliaFractal( part ); +} + +PMJuliaFractal::PMJuliaFractal( PMPart* part ) + : Base( part ) +{ + m_juliaParameter = c_defaultJuliaParameter; + m_algebraType = c_defaultAlgebraType; + m_functionType = c_defaultFunctionType; + m_maxIterations = c_defaultMaxIterations; + m_precision = c_defaultPrecision; + m_sliceNormal = c_defaultSliceNormal; + m_sliceDistance = c_defaultSliceDistance; + m_exponent = c_defaultExponent; +} + +PMJuliaFractal::PMJuliaFractal( const PMJuliaFractal& f ) + : Base( f ) +{ + m_juliaParameter = f.m_juliaParameter; + m_algebraType = f.m_algebraType; + m_functionType = f.m_functionType; + m_maxIterations = f.m_maxIterations; + m_precision = f.m_precision; + m_sliceNormal = f.m_sliceNormal; + m_sliceDistance = f.m_sliceDistance; + m_exponent = f.m_exponent; +} + +PMJuliaFractal::~PMJuliaFractal( ) +{ +} + +QString PMJuliaFractal::description( ) const +{ + return i18n( "julia fractal" ); +} + +void PMJuliaFractal::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "julia_parameter", m_juliaParameter.serializeXML( ) ); + e.setAttribute( "algebra_type", algebraTypeToString( m_algebraType ) ); + e.setAttribute( "function_type", functionTypeToString( m_functionType ) ); + e.setAttribute( "max_iterations", m_maxIterations ); + e.setAttribute( "precision", m_precision ); + e.setAttribute( "slice_normal", m_sliceNormal.serializeXML( ) ); + e.setAttribute( "slice_distance", m_sliceDistance ); + e.setAttribute( "exponent", m_exponent.serializeXML( ) ); + Base::serialize( e, doc ); +} + +void PMJuliaFractal::readAttributes( const PMXMLHelper& h ) +{ + m_juliaParameter = h.vectorAttribute( "julia_parameter", c_defaultJuliaParameter ); + m_algebraType = stringToAlgebraType( h.stringAttribute( "algebra_type", c_defaultAlgebraString ) ); + m_functionType = stringToFunctionType( h.stringAttribute( "function_type", c_defaultFunctionString ) ); + m_maxIterations = h.intAttribute( "max_iterations", c_defaultMaxIterations ); + m_precision = h.doubleAttribute( "precision", c_defaultPrecision ); + m_sliceNormal = h.vectorAttribute( "slice_normal", c_defaultSliceNormal ); + m_sliceDistance = h.doubleAttribute( "slice_distance", c_defaultSliceDistance ); + m_exponent = h.vectorAttribute( "exponent", c_defaultExponent ); + Base::readAttributes( h ); +} + +PMMetaObject* PMJuliaFractal::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "JuliaFractal", Base::metaObject( ), + createNewJuliaFractal ); + s_pMetaObject->addProperty( + new PMJuliaFractalProperty( "juliaParameter", &PMJuliaFractal::setJuliaParameter, + &PMJuliaFractal::juliaParameter ) ); + s_pMetaObject->addProperty( + new PMJuliaFractalProperty( "maximumIterations", &PMJuliaFractal::setMaximumIterations, + &PMJuliaFractal::maximumIterations ) ); + s_pMetaObject->addProperty( + new PMJuliaFractalProperty( "precision", &PMJuliaFractal::setPrecision, + &PMJuliaFractal::precision ) ); + s_pMetaObject->addProperty( + new PMJuliaFractalProperty( "sliceNormal", &PMJuliaFractal::setSliceNormal, + &PMJuliaFractal::sliceNormal ) ); + s_pMetaObject->addProperty( + new PMJuliaFractalProperty( "sliceDistance", &PMJuliaFractal::setSliceDistance, + &PMJuliaFractal::sliceDistance ) ); + s_pMetaObject->addProperty( + new PMJuliaFractalProperty( "exponent", &PMJuliaFractal::setExponent, + &PMJuliaFractal::exponent ) ); + + PMAlgebraTypeProperty* ap = new PMAlgebraTypeProperty( + "algebraType", &PMJuliaFractal::setAlgebraType, &PMJuliaFractal::algebraType ); + ap->addEnumValue( "Quaternion", Quaternion ); + ap->addEnumValue( "Hypercomplex", Hypercomplex ); + s_pMetaObject->addProperty( ap ); + + PMFunctionTypeProperty* fp = new PMFunctionTypeProperty( + "functionType", &PMJuliaFractal::setFunctionType, &PMJuliaFractal::functionType ); + fp->addEnumValue( "sqr", FTsqr ); + fp->addEnumValue( "cube", FTcube ); + fp->addEnumValue( "exp", FTexp ); + fp->addEnumValue( "reciprocal", FTreciprocal ); + fp->addEnumValue( "sin", FTsin ); + fp->addEnumValue( "asin", FTasin ); + fp->addEnumValue( "sinh", FTsinh ); + fp->addEnumValue( "asinh", FTasinh ); + fp->addEnumValue( "cos", FTcos ); + fp->addEnumValue( "acos", FTacos ); + fp->addEnumValue( "cosh", FTcosh ); + fp->addEnumValue( "acosh", FTacosh ); + fp->addEnumValue( "tan", FTtan ); + fp->addEnumValue( "atan", FTatan ); + fp->addEnumValue( "tanh", FTtanh ); + fp->addEnumValue( "atanh", FTatanh ); + fp->addEnumValue( "log", FTlog ); + fp->addEnumValue( "pwr", FTpwr ); + s_pMetaObject->addProperty( fp ); + } + return s_pMetaObject; +} + +void PMJuliaFractal::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMJuliaFractal::setJuliaParameter( const PMVector& p ) +{ + if( p != m_juliaParameter ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMJuliaParameterID, m_juliaParameter ); + m_juliaParameter = p; + m_juliaParameter.resize( 4 ); + } +} + +void PMJuliaFractal::setAlgebraType( PMJuliaFractal::AlgebraType t ) +{ + if( m_algebraType != t ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAlgebraTypeID, m_algebraType ); + m_algebraType = t; + } +} + +void PMJuliaFractal::setFunctionType( PMJuliaFractal::FunctionType t ) +{ + if( m_functionType != t ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFunctionTypeID, m_functionType ); + m_functionType = t; + } +} + +void PMJuliaFractal::setMaximumIterations( int max ) +{ + if( max <= 0 ) + { + kdError( PMArea ) << "max <= 0 in PMJuliaFractal::setMaximumIterations\n"; + max = 20; + } + if( m_maxIterations != max ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMMaxIterationsID, m_maxIterations ); + m_maxIterations = max; + } +} + +void PMJuliaFractal::setPrecision( double p ) +{ + if( p < 1.0 ) + { + kdError( PMArea ) << "p < 1.0 in PMJuliaFractal::setPrecision\n"; + p = 1.0; + } + + if( m_precision != p ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMPrecisionID, m_precision ); + m_precision = p; + } +} + +void PMJuliaFractal::setSliceNormal( const PMVector& n ) +{ + if( m_sliceNormal != n ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSliceNormalID, m_sliceNormal ); + m_sliceNormal = n; + m_sliceNormal.resize( 4 ); + } +} + +void PMJuliaFractal::setSliceDistance( double d ) +{ + if( m_sliceDistance != d ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSliceDistanceID, m_sliceDistance ); + m_sliceDistance = d; + } +} + +void PMJuliaFractal::setExponent( const PMVector& e ) +{ + if( m_exponent != e ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMExponentID, m_exponent ); + m_exponent = e; + m_exponent.resize( 2 ); + } +} + +PMDialogEditBase* PMJuliaFractal::editWidget( QWidget* parent ) const +{ + return new PMJuliaFractalEdit( parent ); +} + +void PMJuliaFractal::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMJuliaParameterID: + setJuliaParameter( data->vectorData( ) ); + break; + case PMAlgebraTypeID: + setAlgebraType( ( AlgebraType ) data->intData( ) ); + break; + case PMFunctionTypeID: + setFunctionType( ( FunctionType ) data->intData( ) ); + break; + case PMMaxIterationsID: + setMaximumIterations( data->intData( ) ); + break; + case PMPrecisionID: + setPrecision( data->doubleData( ) ); + break; + case PMSliceNormalID: + setSliceNormal( data->vectorData( ) ); + break; + case PMSliceDistanceID: + setSliceDistance( data->doubleData( ) ); + break; + case PMExponentID: + setExponent( data->vectorData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMJuliaFractal::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + +QString PMJuliaFractal::functionTypeToString( PMJuliaFractal::FunctionType t ) +{ + QString result = "sqr"; + switch( t ) + { + case FTsqr: + result = "sqr"; + break; + case FTcube: + result = "cube"; + break; + case FTexp: + result = "exp"; + break; + case FTreciprocal: + result = "reciprocal"; + break; + case FTsin: + result = "sin"; + break; + case FTasin: + result = "asin"; + break; + case FTsinh: + result = "sinh"; + break; + case FTasinh: + result = "asinh"; + break; + case FTcos: + result = "cos"; + break; + case FTacos: + result = "acos"; + break; + case FTcosh: + result = "cosh"; + break; + case FTacosh: + result = "acosh"; + break; + case FTtan: + result = "tan"; + break; + case FTatan: + result = "atan"; + break; + case FTtanh: + result = "tanh"; + break; + case FTatanh: + result = "atanh"; + break; + case FTlog: + result = "log"; + break; + case FTpwr: + result = "pwr"; + break; + } + return result; +} + +PMJuliaFractal::FunctionType PMJuliaFractal::stringToFunctionType( const QString& str ) +{ + FunctionType t = c_defaultFunctionType; + + if( str == "sqr" ) + t = FTsqr; + else if( str == "cube" ) + t = FTcube; + else if( str == "exp" ) + t = FTexp; + else if( str == "reciprocal" ) + t = FTreciprocal; + else if( str == "sin" ) + t = FTsin; + else if( str == "asin" ) + t = FTasin; + else if( str == "sinh" ) + t = FTsinh; + else if( str == "asinh" ) + t = FTasinh; + else if( str == "cos" ) + t = FTcos; + else if( str == "acos" ) + t = FTacos; + else if( str == "cosh" ) + t = FTcosh; + else if( str == "acosh" ) + t = FTacosh; + else if( str == "tan" ) + t = FTtan; + else if( str == "atan" ) + t = FTatan; + else if( str == "tanh" ) + t = FTtanh; + else if( str == "atanh" ) + t = FTatanh; + else if( str == "log" ) + t = FTlog; + else if( str == "pwr" ) + t = FTpwr; + return t; +} + +QString PMJuliaFractal::algebraTypeToString( PMJuliaFractal::AlgebraType t ) +{ + QString result; + if( t == Quaternion ) + result = "quaternion"; + else + result = "hypercomplex"; + return result; +} + +PMJuliaFractal::AlgebraType PMJuliaFractal::stringToAlgebraType( const QString& str ) +{ + AlgebraType t = c_defaultAlgebraType; + if( str == "quaternion" ) + t = Quaternion; + else if( str == "hypercomplex" ) + t = Hypercomplex; + return t; +} diff --git a/kpovmodeler/pmjuliafractal.h b/kpovmodeler/pmjuliafractal.h new file mode 100644 index 00000000..1e93a46c --- /dev/null +++ b/kpovmodeler/pmjuliafractal.h @@ -0,0 +1,174 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMJULIAFRACTAL_H +#define PMJULIAFRACTAL_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" +#include "pmvector.h" + +class PMViewStructure; + +/** + * Class for povray julia fractals. + */ + +class PMJuliaFractal : public PMSolidObject +{ + typedef PMSolidObject Base; +public: + enum AlgebraType { Quaternion, Hypercomplex }; + enum FunctionType { FTsqr, FTcube, FTexp, FTreciprocal, FTsin, FTasin, + FTsinh, FTasinh, FTcos, FTacos, FTcosh, FTacosh, + FTtan, FTatan, FTtanh, FTatanh, FTlog, FTpwr }; + + /** + * Creates an empty PMJuliaFractal + */ + PMJuliaFractal( PMPart* part ); + /** + * Copy constructor + */ + PMJuliaFractal( const PMJuliaFractal& f ); + /** + * deletes the PMJuliaFractal + */ + virtual ~PMJuliaFractal( ); + + /** */ + virtual PMObject* copy( ) const { return new PMJuliaFractal( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMJuliaFractalEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmjuliafractal" ); } + /** */ + virtual void restoreMemento( PMMemento* s ); + + /** + * Returns the 4d julia parameter vector + */ + PMVector juliaParameter( ) const { return m_juliaParameter; } + /** + * Sets the julia parameter vector + */ + void setJuliaParameter( const PMVector& p ); + /** + * Returns the algebra type + */ + AlgebraType algebraType( ) const { return m_algebraType; } + /** + * Sets the algebra type + */ + void setAlgebraType( AlgebraType t ); + /** + * Returns the function type + */ + FunctionType functionType( ) const { return m_functionType; } + /** + * Sets the function type + */ + void setFunctionType( FunctionType t ); + /** + * Returns the maximum number of iterations + */ + int maximumIterations( ) const { return m_maxIterations; } + /** + * Sets the maximum number of iterations + */ + void setMaximumIterations( int m ); + /** + * Returns the precision + */ + double precision( ) const { return m_precision; } + /** + * Sets the precision + */ + void setPrecision( double p ); + /** + * Returns the slice normal (4D vector) + */ + PMVector sliceNormal( ) const { return m_sliceNormal; } + /** + * Sets the slice normal (4D vector) + */ + void setSliceNormal( const PMVector& v ); + /** + * Returns the slice distance + */ + double sliceDistance( ) const { return m_sliceDistance; } + /** + * Sets the slice distance + */ + void setSliceDistance( double d ); + /** + * Returns the exponent for the pow function type (2D vector) + */ + PMVector exponent( ) const { return m_exponent; } + /** + * Sets the exponent for the pow function type (2D Vector) + */ + void setExponent( const PMVector& p ); + + static QString functionTypeToString( FunctionType t ); + static FunctionType stringToFunctionType( const QString& str ); + static QString algebraTypeToString( AlgebraType t ); + static AlgebraType stringToAlgebraType( const QString& str ); +private: + + /** + * IDs for @ref PMMementoData + */ + enum PMJuliaFractalMementoID { PMJuliaParameterID, PMAlgebraTypeID, + PMFunctionTypeID, PMMaxIterationsID, + PMPrecisionID, PMSliceNormalID, + PMSliceDistanceID, PMExponentID }; + PMVector m_juliaParameter; + AlgebraType m_algebraType; + FunctionType m_functionType; + int m_maxIterations; + double m_precision; + PMVector m_sliceNormal; + double m_sliceDistance; + PMVector m_exponent; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmjuliafractaledit.cpp b/kpovmodeler/pmjuliafractaledit.cpp new file mode 100644 index 00000000..43f351c5 --- /dev/null +++ b/kpovmodeler/pmjuliafractaledit.cpp @@ -0,0 +1,380 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmjuliafractaledit.h" +#include "pmjuliafractal.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" + +#include +#include +#include +#include +#include + +PMJuliaFractalEdit::PMJuliaFractalEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMJuliaFractalEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* hl; + QGridLayout* gl; + + topLayout( )->addWidget( new QLabel( i18n( "Julia parameter:" ), this ) ); + m_pJuliaParameter = new PMVectorEdit( "", "i", "j", "k", this ); + topLayout( )->addWidget( m_pJuliaParameter ); + + hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Algebra type:" ), this ) ); + m_pAlgebraType = new QComboBox( false, this ); + m_pAlgebraType->insertItem( i18n( "Quaternion" ) ); + m_pAlgebraType->insertItem( i18n( "Hypercomplex" ) ); + hl->addWidget( m_pAlgebraType ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Function type:" ), this ) ); + m_pFunctionType = new QComboBox( false, this ); + m_pFunctionType->insertItem( "sqr" ); + m_pFunctionType->insertItem( "cube" ); + m_pFunctionType->insertItem( "exp" ); + m_pFunctionType->insertItem( "reciprocal" ); + m_pFunctionType->insertItem( "sin" ); + m_pFunctionType->insertItem( "asin" ); + m_pFunctionType->insertItem( "sinh" ); + m_pFunctionType->insertItem( "asinh" ); + m_pFunctionType->insertItem( "cos" ); + m_pFunctionType->insertItem( "acos" ); + m_pFunctionType->insertItem( "cosh" ); + m_pFunctionType->insertItem( "acosh" ); + m_pFunctionType->insertItem( "tan" ); + m_pFunctionType->insertItem( "atan" ); + m_pFunctionType->insertItem( "tanh" ); + m_pFunctionType->insertItem( "atanh" ); + m_pFunctionType->insertItem( "log" ); + m_pFunctionType->insertItem( "pwr" ); + hl->addWidget( m_pFunctionType ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + m_pExponentsLabel = new QLabel( i18n( "Exponent:" ), this ); + hl->addWidget( m_pExponentsLabel ); + m_pExponents = new PMVectorEdit( "", "i", this ); + hl->addWidget( m_pExponents ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + gl = new QGridLayout( hl, 2, 2 ); + gl->addWidget( new QLabel( i18n( "Maximum iterations:" ), this ), 0, 0 ); + m_pMaxIterations = new PMIntEdit( this ); + m_pMaxIterations->setValidation( true, 1, false, 0 ); + gl->addWidget( m_pMaxIterations, 0, 1 ); + gl->addWidget( new QLabel( i18n( "Precision:" ), this ), 1, 0 ); + m_pPrecision = new PMFloatEdit( this ); + m_pPrecision->setValidation( true, 1.0, false, 0.0 ); + gl->addWidget( m_pPrecision, 1, 1 ); + hl->addStretch( 1 ); + + topLayout( )->addWidget( new QLabel( i18n( "Slice normal:" ), this ) ); + m_pSliceNormal = new PMVectorEdit( "", "i", "j", "k", this ); + topLayout( )->addWidget( m_pSliceNormal ); + + hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Slice distance:" ), this ) ); + m_pSliceDistance = new PMFloatEdit( this ); + hl->addWidget( m_pSliceDistance ); + hl->addStretch( 1 ); + + connect( m_pJuliaParameter, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pAlgebraType, SIGNAL( activated( int ) ), + SLOT( slotAlgebraTypeSelected( int ) ) ); + connect( m_pFunctionType, SIGNAL( activated( int ) ), + SLOT( slotFunctionTypeSelected( int ) ) ); + connect( m_pExponents, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pMaxIterations, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pPrecision, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pSliceNormal, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pSliceDistance, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMJuliaFractalEdit::displayObject( PMObject* o ) +{ + if( o->isA( "JuliaFractal" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMJuliaFractal* ) o; + + m_pJuliaParameter->setVector( m_pDisplayedObject->juliaParameter( ) ); + switch( m_pDisplayedObject->algebraType( ) ) + { + case PMJuliaFractal::Quaternion: + m_pAlgebraType->setCurrentItem( 0 ); + break; + case PMJuliaFractal::Hypercomplex: + m_pAlgebraType->setCurrentItem( 1 ); + break; + } + switch( m_pDisplayedObject->functionType( ) ) + { + case PMJuliaFractal::FTsqr: + m_pFunctionType->setCurrentItem( 0 ); + break; + case PMJuliaFractal::FTcube: + m_pFunctionType->setCurrentItem( 1 ); + break; + case PMJuliaFractal::FTexp: + m_pFunctionType->setCurrentItem( 2 ); + break; + case PMJuliaFractal::FTreciprocal: + m_pFunctionType->setCurrentItem( 3 ); + break; + case PMJuliaFractal::FTsin: + m_pFunctionType->setCurrentItem( 4 ); + break; + case PMJuliaFractal::FTasin: + m_pFunctionType->setCurrentItem( 5 ); + break; + case PMJuliaFractal::FTsinh: + m_pFunctionType->setCurrentItem( 6 ); + break; + case PMJuliaFractal::FTasinh: + m_pFunctionType->setCurrentItem( 7 ); + break; + case PMJuliaFractal::FTcos: + m_pFunctionType->setCurrentItem( 8 ); + break; + case PMJuliaFractal::FTacos: + m_pFunctionType->setCurrentItem( 9 ); + break; + case PMJuliaFractal::FTcosh: + m_pFunctionType->setCurrentItem( 10 ); + break; + case PMJuliaFractal::FTacosh: + m_pFunctionType->setCurrentItem( 11 ); + break; + case PMJuliaFractal::FTtan: + m_pFunctionType->setCurrentItem( 12 ); + break; + case PMJuliaFractal::FTatan: + m_pFunctionType->setCurrentItem( 13 ); + break; + case PMJuliaFractal::FTtanh: + m_pFunctionType->setCurrentItem( 14 ); + break; + case PMJuliaFractal::FTatanh: + m_pFunctionType->setCurrentItem( 15 ); + break; + case PMJuliaFractal::FTlog: + m_pFunctionType->setCurrentItem( 16 ); + break; + case PMJuliaFractal::FTpwr: + m_pFunctionType->setCurrentItem( 17 ); + break; + } + m_pExponents->setVector( m_pDisplayedObject->exponent( ) ); + if( m_pDisplayedObject->functionType( ) == PMJuliaFractal::FTpwr ) + { + m_pExponents->show( ); + m_pExponentsLabel->show( ); + } + else + { + m_pExponents->hide( ); + m_pExponentsLabel->hide( ); + } + + m_pMaxIterations->setValue( m_pDisplayedObject->maximumIterations( ) ); + m_pPrecision->setValue( m_pDisplayedObject->precision( ) ); + m_pSliceNormal->setVector( m_pDisplayedObject->sliceNormal( ) ); + m_pSliceDistance->setValue( m_pDisplayedObject->sliceDistance( ) ); + + m_pJuliaParameter->setReadOnly( readOnly ); + m_pAlgebraType->setEnabled( !readOnly ); + m_pFunctionType->setEnabled( !readOnly ); + m_pExponents->setReadOnly( readOnly ); + m_pMaxIterations->setReadOnly( readOnly ); + m_pPrecision->setReadOnly( readOnly ); + m_pSliceNormal->setReadOnly( readOnly ); + m_pSliceDistance->setReadOnly( readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMJuliaFractalEdit: Can't display object\n"; +} + +void PMJuliaFractalEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + PMVector p( 4 ); + + m_pDisplayedObject->setJuliaParameter( m_pJuliaParameter->vector( ) ); + switch( m_pAlgebraType->currentItem( ) ) + { + case 0: + m_pDisplayedObject->setAlgebraType( PMJuliaFractal::Quaternion ); + break; + case 1: + m_pDisplayedObject->setAlgebraType( PMJuliaFractal::Hypercomplex ); + break; + default: + m_pDisplayedObject->setAlgebraType( PMJuliaFractal::Quaternion ); + break; + } + switch( m_pFunctionType->currentItem( ) ) + { + case 0: + m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTsqr ); + break; + case 1: + m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTcube ); + break; + case 2: + m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTexp ); + break; + case 3: + m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTreciprocal ); + break; + case 4: + m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTsin ); + break; + case 5: + m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTasin ); + break; + case 6: + m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTsinh ); + break; + case 7: + m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTasinh ); + break; + case 8: + m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTcos ); + break; + case 9: + m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTacos ); + break; + case 10: + m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTcosh ); + break; + case 11: + m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTacosh ); + break; + case 12: + m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTtan ); + break; + case 13: + m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTatan ); + break; + case 14: + m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTtanh ); + break; + case 15: + m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTatanh ); + break; + case 16: + m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTlog ); + break; + case 17: + m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTpwr ); + break; + default: + m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTsqr ); + break; + } + if( m_pExponents->isVisible( ) ) + m_pDisplayedObject->setExponent( m_pExponents->vector( ) ); + m_pDisplayedObject->setMaximumIterations( m_pMaxIterations->value( ) ); + m_pDisplayedObject->setPrecision( m_pPrecision->value( ) ); + m_pDisplayedObject->setSliceNormal( m_pSliceNormal->vector( ) ); + m_pDisplayedObject->setSliceDistance( m_pSliceDistance->value( ) ); + } +} + +bool PMJuliaFractalEdit::isDataValid( ) +{ + if( !m_pJuliaParameter->isDataValid( ) ) + return false; + if( m_pExponents->isVisible( ) ) + if( !m_pExponents->isDataValid( ) ) + return false; + if( !m_pMaxIterations->isDataValid( ) ) + return false; + if( !m_pPrecision->isDataValid( ) ) + return false; + if( !m_pSliceNormal->isDataValid( ) ) + return false; + PMVector v = m_pSliceNormal->vector( ); + if( approxZero( v.abs( ) ) ) + { + KMessageBox::error( this, i18n( "The slice normal vector may not be a null vector." ), + i18n( "Error" ) ); + return false; + } + if( approxZero( v[3] ) ) + { + KMessageBox::error( this, i18n( "The 'k' component of the slice normal vector may not be zero." ), + i18n( "Error" ) ); + return false; + } + + if( !m_pSliceDistance->isDataValid( ) ) + return false; + + if( m_pAlgebraType->currentItem( ) == 0 ) + { + if( m_pFunctionType->currentItem( ) > 1 ) + { + KMessageBox::error( this, i18n( "Only the functions 'sqr' and 'cube' " + "are defined in the quaternion algebra." ), + i18n( "Error" ) ); + return false; + } + } + + + return Base::isDataValid( ); +} + +void PMJuliaFractalEdit::slotAlgebraTypeSelected( int ) +{ + emit dataChanged( ); +} + +void PMJuliaFractalEdit::slotFunctionTypeSelected( int index ) +{ + if( index == 17 ) + { + m_pExponents->show( ); + m_pExponentsLabel->show( ); + } + else + { + m_pExponents->hide( ); + m_pExponentsLabel->hide( ); + } + emit dataChanged( ); +} + +#include "pmjuliafractaledit.moc" diff --git a/kpovmodeler/pmjuliafractaledit.h b/kpovmodeler/pmjuliafractaledit.h new file mode 100644 index 00000000..598ea144 --- /dev/null +++ b/kpovmodeler/pmjuliafractaledit.h @@ -0,0 +1,79 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMJULIAFRACTALEDIT_H +#define PMJULIAFRACTALEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" + +class PMJuliaFractal; +class PMVectorEdit; +class PMIntEdit; +class PMFloatEdit; +class QComboBox; +class QLabel; + +/** + * Dialog edit class for @ref PMJuliaFractal + */ +class PMJuliaFractalEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMJuliaFractalEdit with parent and name + */ + PMJuliaFractalEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); + +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + void slotAlgebraTypeSelected( int ); + void slotFunctionTypeSelected( int ); + +private: + PMJuliaFractal* m_pDisplayedObject; + PMVectorEdit* m_pJuliaParameter; + QComboBox* m_pAlgebraType; + QComboBox* m_pFunctionType; + PMVectorEdit* m_pExponents; + QLabel* m_pExponentsLabel; + PMIntEdit* m_pMaxIterations; + PMFloatEdit* m_pPrecision; + PMVectorEdit* m_pSliceNormal; + PMFloatEdit* m_pSliceDistance; +}; + + +#endif diff --git a/kpovmodeler/pmlathe.cpp b/kpovmodeler/pmlathe.cpp new file mode 100644 index 00000000..f6c3c3c3 --- /dev/null +++ b/kpovmodeler/pmlathe.cpp @@ -0,0 +1,948 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmlathe.h" + +#include "pmxmlhelper.h" +#include "pmlatheedit.h" +#include "pmmemento.h" +#include "pmviewstructure.h" +#include "pm2dcontrolpoint.h" +#include "pmsplinememento.h" +#include "pmsplinesegment.h" +#include "pmdefaults.h" +#include "pmenumproperty.h" +#include "pmobjectaction.h" + +#include + +const int defaultNumberOfPoints = 4; +const PMVector defaultPoint[defaultNumberOfPoints] = +{ + PMVector( 0.0, 1.0 ), + PMVector( 0.5, 0.7 ), + PMVector( 0.5, 0.3 ), + PMVector( 0.0, 0.0 ) +}; + +const bool defaultSturm = false; +const PMLathe::SplineType defaultSplineType = PMLathe::LinearSpline; + +PMDefinePropertyClass( PMLathe, PMLatheProperty ); +PMDefineEnumPropertyClass( PMLathe, PMLathe::SplineType, PMSplineTypeProperty ); + +PMMetaObject* PMLathe::s_pMetaObject = 0; +PMObject* createNewLathe( PMPart* part ) +{ + return new PMLathe( part ); +} + +class PMPointProperty : public PMPropertyBase +{ +public: + PMPointProperty( ) + : PMPropertyBase( "splinePoints", PMVariant::Vector ) + { + m_index = 0; + } + virtual int dimensions( ) const { return 1; } + virtual void setIndex( int /*dimension*/, int index ) + { + m_index = index; + } + virtual int size( PMObject* object, int /*dimension*/ ) const + { + return ( ( PMLathe* ) object )->numberOfPoints( ); + } +protected: + virtual bool setProtected( PMObject* obj, const PMVariant& var ) + { + PMLathe* p = ( PMLathe* ) obj; + QValueList list = p->points( ); + QValueList::Iterator it = list.begin( ); + int i; + PMVector v = var.vectorData( ); + v.resize( 2 ); + + for( i = 0; i < m_index && it != list.end( ); ++i ) + ++it; + // expand the list if necessary + for( ; i < m_index; ++i ) + list.insert( it, v ); + if( it == list.end( ) ) + it = list.insert( it, v ); + else + *it = v; + + p->setPoints( list ); + return true; + } + virtual PMVariant getProtected( const PMObject* obj ) + { + PMLathe* p = ( PMLathe* ) obj; + QValueList list = p->points( ); + QValueList::ConstIterator it = list.at( m_index ); + + if( it == list.end( ) ) + { + kdError( PMArea ) << "Range error in PMLathe::PointProperty::get" << endl; + return PMVariant( ); + } + + return PMVariant( *it ); + } + +private: + int m_index; +}; + + +int PMLathe::s_rSteps = c_defaultLatheRSteps; +int PMLathe::s_sSteps = c_defaultLatheSSteps; +int PMLathe::s_parameterKey = 0; + +PMLathe::PMLathe( PMPart* part ) + : Base( part ) +{ + int i; + + for( i = 0; i < defaultNumberOfPoints; ++i ) + m_points.append( defaultPoint[i] ); + m_splineType = defaultSplineType; + m_sturm = defaultSturm; +} + +PMLathe::PMLathe( const PMLathe& l ) + : Base( l ) +{ + m_points = l.m_points; + m_splineType = l.m_splineType; + m_sturm = l.m_sturm; +} + +PMLathe::~PMLathe( ) +{ +} + +QString PMLathe::description( ) const +{ + return i18n( "lathe" ); +} + +void PMLathe::serialize( QDomElement& e, QDomDocument& doc ) const +{ + QDomElement data = doc.createElement( "extra_data" ); + QDomElement p; + + e.setAttribute( "spline_type", m_splineType ); + e.setAttribute( "sturm", m_sturm ); + + QValueList::ConstIterator it; + for( it = m_points.begin( ); it != m_points.end( ); ++it ) + { + p = doc.createElement( "point" ); + p.setAttribute( "vector", ( *it ).serializeXML( ) ); + data.appendChild( p ); + } + + e.appendChild( data ); + Base::serialize( e, doc ); +} + +void PMLathe::readAttributes( const PMXMLHelper& h ) +{ + m_splineType = ( SplineType ) h.intAttribute( "spline_type", defaultSplineType ); + m_sturm = h.boolAttribute( "sturm", defaultSturm ); + + m_points.clear( ); + PMVector v( 2 ); + + QDomElement e = h.extraData( ); + if( !e.isNull( ) ) + { + QDomNode c = e.firstChild( ); + while( !c.isNull( ) ) + { + if( c.isElement( ) ) + { + QDomElement ce = c.toElement( ); + if( ce.tagName( ) == "point" ) + { + QString str = ce.attribute( "vector" ); + if( !str.isNull( ) ) + { + v.loadXML( str ); + m_points.append( v ); + } + } + } + c = c.nextSibling( ); + } + } + + Base::readAttributes( h ); +} + +PMMetaObject* PMLathe::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Lathe", Base::metaObject( ), + createNewLathe ); + s_pMetaObject->addProperty( + new PMLatheProperty( "sturm", &PMLathe::setSturm, &PMLathe::sturm ) ); + PMSplineTypeProperty* p = new PMSplineTypeProperty( + "splineType", &PMLathe::setSplineType, &PMLathe::splineType ); + p->addEnumValue( "LinearSpline", LinearSpline ); + p->addEnumValue( "QuadraticSpline", QuadraticSpline ); + p->addEnumValue( "CubicSpline", CubicSpline ); + p->addEnumValue( "BezierSpline", BezierSpline ); + s_pMetaObject->addProperty( p ); + s_pMetaObject->addProperty( new PMPointProperty( ) ); + } + return s_pMetaObject; +} + +void PMLathe::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMLathe::setSplineType( PMLathe::SplineType t ) +{ + if( m_splineType != t ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSplineTypeID, ( int ) m_splineType ); + setViewStructureChanged( ); + m_splineType = t; + } +} + +void PMLathe::setSturm( bool s ) +{ + if( m_sturm != s ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSturmID, m_sturm ); + m_sturm = s; + } +} + +void PMLathe::setPoints( const QValueList& points ) +{ + if( m_points != points ) + { + if( m_pMemento ) + ( ( PMSplineMemento* ) m_pMemento )->setSplinePoints( m_points ); + + setViewStructureChanged( ); + m_points = points; + } +} + +PMDialogEditBase* PMLathe::editWidget( QWidget* parent ) const +{ + return new PMLatheEdit( parent ); +} + +void PMLathe::createMemento( ) +{ + if( m_pMemento ) + delete m_pMemento; + m_pMemento = new PMSplineMemento( this ); +} + +void PMLathe::restoreMemento( PMMemento* s ) +{ + PMSplineMemento* m = ( PMSplineMemento* ) s; + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMSplineTypeID: + setSplineType( ( SplineType ) data->intData( ) ); + break; + case PMSturmID: + setSturm( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMLathe::restoreMemento\n"; + break; + } + } + } + if( m->splinePointsSaved( ) ) + setPoints( m->splinePoints( ) ); + + Base::restoreMemento( s ); +} + + +void PMLathe::createViewStructure( ) +{ + if( s_sSteps == 0 ) + s_sSteps = c_defaultLatheSSteps; + if( s_rSteps == 0 ) + s_rSteps = c_defaultLatheRSteps; + + int rSteps = (int)( ( (float)s_rSteps / 2 ) * ( displayDetail( ) + 1 ) ); + int sSteps = (int)( ( (float)s_sSteps / 2 ) * ( displayDetail( ) + 1 ) ); + + int np = m_points.count( ); + int ns = 0; + int i, j, r, si; + + // calculate number of segments + switch( m_splineType ) + { + case LinearSpline: + ns = np - 1; + break; + case QuadraticSpline: + ns = np - 2; + break; + case CubicSpline: + ns = np - 3; + break; + case BezierSpline: + ns = np / 4; + break; + } + + // calculate number of points and lines of the view structure + int vsp = 0; + if( m_splineType != BezierSpline ) + vsp = ns * sSteps + 1; + else + vsp = ns * ( sSteps + 1 ); + + int vsl = 0; + if( m_splineType != BezierSpline ) + vsl = ( 2 * vsp - 1 ) * rSteps; + else + vsl = ns * ( ( 2 * sSteps + 1 ) * rSteps ); + + vsp *= rSteps; + + if( m_pViewStructure ) + { + if( m_pViewStructure->points( ).size( ) != ( unsigned ) vsp ) + m_pViewStructure->points( ).resize( vsp ); + if( m_pViewStructure->lines( ).size( ) != ( unsigned ) vsl ) + m_pViewStructure->lines( ).resize( vsl ); + } + else + m_pViewStructure = new PMViewStructure( vsp, vsl ); + + + // calculate the spline segments + QValueList segments; + QValueList::Iterator it1, it2, it3, it4; + it1 = m_points.begin( ); + it2 = it1; ++it2; + it3 = it2; ++it3; + it4 = it3; ++it4; + PMSplineSegment s; + + for( i = 0; i < ns; ++i ) + { + switch( m_splineType ) + { + case LinearSpline: + s.calculateLinear( *it1, *it2 ); + ++it1; + ++it2; + break; + case QuadraticSpline: + s.calculateQuadratic( *it1, *it2, *it3 ); + ++it1; + ++it2; + ++it3; + break; + case CubicSpline: + s.calculateCubic( *it1, *it2, *it3, *it4 ); + ++it1; + ++it2; + ++it3; + ++it4; + break; + case BezierSpline: + s.calculateBezier( *it1, *it2, *it3, *it4 ); + for( j = 0; j < 4; ++j ) + { + ++it1; + ++it2; + ++it3; + ++it4; + } + break; + } + segments.append( s ); + } + + // create the line array + if( m_splineType != BezierSpline ) + { + PMLineArray& lines = m_pViewStructure->lines( ); + int vl = ns * sSteps; + int lb = 0; + for( i = 0; i < vl + 1; ++i ) + { + for( j = 0; j < rSteps - 1; ++j ) + lines[lb+j] = PMLine( lb + j, lb + j + 1 ); + lines[lb+rSteps-1] = PMLine( lb, lb + rSteps - 1 ); + lb += rSteps; + } + int pi = 0; + for( i = 0; i < vl; ++i ) + { + for( j = 0; j < rSteps; ++j ) + { + lines[lb] = PMLine( pi, pi + rSteps ); + ++pi; + ++lb; + } + } + } + else + { + PMLineArray& lines = m_pViewStructure->lines( ); + int lb = 0; + int pi = 0; + + for( si = 0; si < ns; ++si ) + { + for( i = 0; i < sSteps + 1; ++i ) + { + for( j = 0; j < rSteps - 1; ++j ) + lines[lb+j] = PMLine( lb + j, lb + j + 1 ); + lines[lb+rSteps-1] = PMLine( lb, lb + rSteps - 1 ); + lb += rSteps; + } + } + for( si = 0; si < ns; ++si ) + { + for( i = 0; i < sSteps; ++i ) + { + for( j = 0; j < rSteps; ++j ) + { + lines[lb] = PMLine( pi, pi + rSteps ); + ++pi; + ++lb; + } + } + pi += rSteps; + } + } + // calculate the points + PMVector point2, point3; + QValueList::Iterator sit = segments.begin( ); + int pi = 0; + + double poffset = 1.0 / sSteps; + PMMatrix rot = PMMatrix::rotation( 0.0, M_PI * 2.0 / rSteps, 0.0 ); + PMPointArray& points = m_pViewStructure->points( ); + + if( m_splineType != BezierSpline ) + { + for( i = 0; i < ns; ++i, ++sit ) + { + for( j = 0; j < sSteps; ++j ) + { + point2 = ( *sit ).point( poffset * j ); + point3[0] = point2[0]; + point3[1] = point2[1]; + point3[2] = 0.0; + + for( r = 0; r < rSteps; ++r ) + { + points[pi] = PMPoint( point3 ); + if( r != rSteps - 1 ) + point3.transform( rot ); + ++pi; + } + } + if( i == ns - 1 ) + { + point2 = ( *sit ).point( 1.0 ); + point3[0] = point2[0]; + point3[1] = point2[1]; + point3[2] = 0.0; + + for( r = 0; r < rSteps; ++r ) + { + points[pi] = PMPoint( point3 ); + if( r != rSteps - 1 ) + point3.transform( rot ); + ++pi; + } + } + } + } + else + { + for( i = 0; i < ns; ++i, ++sit ) + { + for( j = 0; j < sSteps + 1; ++j ) + { + point2 = ( *sit ).point( poffset * j ); + point3[0] = point2[0]; + point3[1] = point2[1]; + point3[2] = 0.0; + + for( r = 0; r < rSteps; ++r ) + { + points[pi] = PMPoint( point3 ); + if( r != rSteps - 1 ) + point3.transform( rot ); + ++pi; + } + } + } + } +} + +void PMLathe::controlPoints( PMControlPointList& list ) +{ + QValueList::Iterator it; + int i, d; + + PM2DControlPoint* cp = 0; + QPtrList tmp[2]; + + for( d = 0; d < 2; ++d ) + { + if( m_splineType != BezierSpline ) + { + PM2DControlPoint* firstPoint = 0; + PM2DControlPoint* lastPoint = 0; + + for( it = m_points.begin( ), i = 0; it != m_points.end( ); ++it, ++i ) + { + lastPoint = cp; + if( d == 0 ) + cp = new PM2DControlPoint( *it, PM2DControlPoint::PM2DXY, i, + i18n( "Point %1 (xy)" ).arg( i + 1 ) ); + else + cp = new PM2DControlPoint( *it, PM2DControlPoint::PM2DZY, i, + i18n( "Point %1 (xy)" ).arg( i + 1 ) ); + + if( i == 0 ) + firstPoint = cp; + if( ( i == 1 ) && ( m_splineType != LinearSpline ) ) + firstPoint->setBasePoint( cp ); + + tmp[d].append( cp ); + } + if( m_splineType == CubicSpline ) + cp->setBasePoint( lastPoint ); + } + else + { + PM2DControlPoint* helpPoint = 0; + + for( it = m_points.begin( ), i = 0; it != m_points.end( ); ++it, ++i ) + { + int imod4 = i % 4; + if( d == 0 ) + cp = new PM2DControlPoint( *it, PM2DControlPoint::PM2DXY, i, + i18n( "Point %1 (xy)" ).arg( i + 1 ) ); + else + cp = new PM2DControlPoint( *it, PM2DControlPoint::PM2DZY, i, + i18n( "Point %1 (xy)" ).arg( i + 1 ) ); + switch( imod4 ) + { + case 0: + helpPoint = cp; + break; + case 1: + cp->setBasePoint( helpPoint ); + break; + case 2: + helpPoint = cp; + break; + case 3: + helpPoint->setBasePoint( cp ); + break; + default: + break; + } + + tmp[d].append( cp ); + } + } + } + + QPtrListIterator cit1( tmp[0] ), cit2( tmp[1] ); + + for( ; cit1.current( ) && cit2.current( ); ++cit1, ++cit2 ) + { + ( *cit1 )->setLatheLink( *cit2 ); + ( *cit2 )->setLatheLink( *cit1 ); + } + for( cit1.toFirst( ); cit1.current( ); ++cit1 ) + list.append( *cit1 ); + for( cit2.toFirst( ); cit2.current( ); ++cit2 ) + list.append( *cit2 ); +} + +void PMLathe::controlPointsChanged( PMControlPointList& list ) +{ + PMControlPointListIterator it1( list ), it2( list ); + QValueList::Iterator pit = m_points.begin( ); + PM2DControlPoint* p1; + PM2DControlPoint* p2; + bool firstChange = true; + + for( it2 += list.count( ) / 2; it2.current( ); ++it1, ++it2, ++pit ) + { + p1 = ( PM2DControlPoint* ) it1.current( ); + p2 = ( PM2DControlPoint* ) it2.current( ); + + if( p1->changed( ) ) + { + if( firstChange ) + { + if( m_pMemento ) + { + PMSplineMemento* m = ( PMSplineMemento* ) m_pMemento; + if( !m->splinePointsSaved( ) ) + m->setSplinePoints( m_points ); + } + firstChange = false; + setViewStructureChanged( ); + } + p2->setPoint( p1->point( ) ); + ( *pit ) = p1->point( ); + } + else if( p2->changed( ) ) + { + if( firstChange ) + { + if( m_pMemento ) + { + PMSplineMemento* m = ( PMSplineMemento* ) m_pMemento; + if( !m->splinePointsSaved( ) ) + m->setSplinePoints( m_points ); + } + firstChange = false; + setViewStructureChanged( ); + } + p1->setPoint( p2->point( ) ); + ( *pit ) = p2->point( ); + } + } +} + +void PMLathe::addObjectActions( const PMControlPointList& /*cp*/, + QPtrList& actions ) +{ + PMObjectAction* a; + + a = new PMObjectAction( s_pMetaObject, PMSplitSegmentID, + i18n( "Add Point" ) ); + actions.append( a ); + + a = new PMObjectAction( s_pMetaObject, PMJoinSegmentsID, + i18n( "Remove Point" ) ); + int np = m_points.count( ); + int minp = 3; + switch( m_splineType ) + { + case LinearSpline: + minp = 3; + break; + case QuadraticSpline: + minp = 4; + break; + case CubicSpline: + minp = 5; + break; + case BezierSpline: + minp = 8; + break; + } + + if( np < minp ) + a->setEnabled( false ); + actions.append( a ); +} + +void PMLathe::objectActionCalled( const PMObjectAction* action, + const PMControlPointList& cp, + const QPtrList& cpViewPosition, + const PMVector& clickPosition ) +{ + if( action->objectType( ) == s_pMetaObject ) + { + switch( action->actionID( ) ) + { + case PMSplitSegmentID: + splitSegment( cp, cpViewPosition, clickPosition ); + break; + case PMJoinSegmentsID: + joinSegments( cp, cpViewPosition, clickPosition ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMLathe::objectActionCalled\n"; + break; + } + } + else + Base::objectActionCalled( action, cp, cpViewPosition, clickPosition ); +} + +void PMLathe::splitSegment( const PMControlPointList& /*cp*/, + const QPtrList& cpViewPosition, + const PMVector& clickPosition ) +{ + // find nearest segment + int nump = cpViewPosition.count( ) / 2 - 1; + double abs = 0.0, minabs = 1e10; + int ns = -1; + int i, j; + PMVector mid( 3 ), dist( 2 ); + + QPtrListIterator it1( cpViewPosition ); + QPtrListIterator it2( cpViewPosition ); + ++it2; + + for( j = 0; j < 2; ++j ) + { + for( i = 0; i < nump; ++i ) + { + bool skip = false; + switch( m_splineType ) + { + case LinearSpline: + case BezierSpline: + break; + case QuadraticSpline: + if( i == 0 ) + skip = true; + break; + case CubicSpline: + if( ( i == 0 ) || ( i == ( nump - 1 ) ) ) + skip = true; + break; + } + + if( !skip ) + { + mid = ( **it1 + **it2 ) / 2.0; + dist[0] = mid[0]; + dist[1] = mid[1]; + dist -= clickPosition; + abs = dist.abs( ); + + if( ( minabs > abs ) || ( ns < 0 ) ) + { + minabs = abs; + ns = i; + } + } + ++it1; + ++it2; + } + ++it1; + ++it2; + } + + // add a new segment + QValueList newPoints = m_points; + + if( m_splineType == BezierSpline ) + { + ns /= 4; + ns *= 4; + } + QValueList::Iterator it = newPoints.at( ( unsigned ) ns ); + PMVector p[4]; + QValueList::Iterator hit = it; + + // calculate the spline segment + PMSplineSegment segment; + switch( m_splineType ) + { + case LinearSpline: + for( i = 0; i < 2; ++i, ++hit ) + p[i] = *hit; + segment.calculateLinear( p[0], p[1] ); + break; + case QuadraticSpline: + --hit; + for( i = 0; i < 3; ++i, ++hit ) + p[i] = *hit; + segment.calculateQuadratic( p[0], p[1], p[2] ); + break; + case CubicSpline: + --hit; + for( i = 0; i < 4; ++i, ++hit ) + p[i] = *hit; + segment.calculateCubic( p[0], p[1], p[2], p[3] ); + break; + case BezierSpline: + for( i = 0; i < 4; ++i, ++hit ) + p[i] = *hit; + segment.calculateBezier( p[0], p[1], p[2], p[3] ); + break; + } + + mid = segment.point( 0.5 ); + if( m_splineType != BezierSpline ) + { + ++it; + newPoints.insert( it, mid ); + } + else + { + PMVector end = *it; + ++it; + *it = end + ( *it - end ) / 2.0; + ++it; + + PMVector grad = segment.gradient( 0.5 ) / 4.0; + + newPoints.insert( it, mid - grad ); + newPoints.insert( it, mid ); + newPoints.insert( it, mid ); + newPoints.insert( it, mid + grad ); + + ++it; + end = *it; + --it; + *it = end + ( *it - end ) / 2.0; + } + setPoints( newPoints ); +} + +void PMLathe::joinSegments( const PMControlPointList& /*cp*/, + const QPtrList& cpViewPosition, + const PMVector& clickPosition ) +{ + // find nearest point + int nump = cpViewPosition.count( ) / 2; + int minp = 0; + + switch( m_splineType ) + { + case LinearSpline: + minp = 3; + break; + case QuadraticSpline: + minp = 4; + break; + case CubicSpline: + minp = 5; + break; + case BezierSpline: + minp = 8; + break; + } + + if( nump < minp ) + { + kdError( PMArea ) << "Not enough points in PMLathe::joinSegments\n"; + return; + } + + double abs = 0.0, minabs = 1e10; + int ns = -1; + int i, j; + PMVector* p; + PMVector dist( 2 ); + + QPtrListIterator it1( cpViewPosition ); + + for( j = 0; j < 2; ++j ) + { + for( i = 0; i < nump; ++i ) + { + p = *it1; + dist[0] = (*p)[0]; + dist[1] = (*p)[1]; + dist -= clickPosition; + abs = dist.abs( ); + + if( ( minabs > abs ) || ( ns < 0 ) ) + { + minabs = abs; + ns = i; + } + ++it1; + } + } + + // join two segments + QValueList newPoints = m_points; + QValueList::Iterator it; + + if( m_splineType != BezierSpline ) + { + // never remove the first or last point + if( ns == 0 ) + ++ns; + if( ns == ( nump - 1 ) ) + --ns; + it = newPoints.at( ns ); + newPoints.remove( it ); + } + else + { + ns = ( ns - 2 ) / 4; + if( ns < 0 ) + ns = 0; + if( ns >= ( nump / 4 - 1 ) ) + ns = nump / 4 - 2; + + it = newPoints.at( ns * 4 + 2 ); + for( i = 0; i < 4; ++i ) + it = newPoints.remove( it ); + } + setPoints( newPoints ); +} + +void PMLathe::setRSteps( int r ) +{ + if( r >= 4 ) + s_rSteps = r; + else + kdDebug( PMArea ) << "PMLathe::setRSteps: R must be greater than 3\n"; + ++s_parameterKey; +} + +void PMLathe::setSSteps( int s ) +{ + if( s >= 1 ) + s_sSteps = s; + else + kdDebug( PMArea ) << "PMLathe::setSSteps: S must be greater than 0\n"; + ++s_parameterKey; +} diff --git a/kpovmodeler/pmlathe.h b/kpovmodeler/pmlathe.h new file mode 100644 index 00000000..99986a6f --- /dev/null +++ b/kpovmodeler/pmlathe.h @@ -0,0 +1,193 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMLATHE_H +#define PMLATHE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" +#include "pmvector.h" +#include +#include +#include + +class PMViewStructure; + +/** + * Class for povray lathe objects. + */ + +class PMLathe : public PMSolidObject +{ + typedef PMSolidObject Base; +public: + /** + * The spline type + */ + enum SplineType { LinearSpline, QuadraticSpline, CubicSpline, BezierSpline }; + /** + * Creates an empty PMLathe + */ + PMLathe( PMPart* part ); + /** + * Copy constructor + */ + PMLathe( const PMLathe& l ); + /** + * deletes the PMLathe + */ + virtual ~PMLathe( ); + + /** */ + virtual PMObject* copy( ) const { return new PMLathe( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMLatheEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmlathe" ); } + + /** */ + virtual void createMemento( ); + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual void controlPoints( PMControlPointList& list ); + /** */ + virtual void controlPointsChanged( PMControlPointList& list ); + /** */ + virtual bool hasDisplayDetail( ) const { return true; } + /** */ + virtual bool multipleSelectControlPoints( ) const { return true; } + /** */ + virtual void addObjectActions( const PMControlPointList&, + QPtrList& ); + /** */ + virtual void objectActionCalled( const PMObjectAction*, + const PMControlPointList&, + const QPtrList&, + const PMVector& ); + + /** + * Returns the spline points + */ + QValueList points( ) const { return m_points; } + /** + * Sets the spline points + */ + void setPoints( const QValueList& points ); + /** + * Returns the number of spline points + */ + int numberOfPoints( ) const { return m_points.size( ); } + /** + * Returns the spline type + */ + SplineType splineType( ) const { return m_splineType; } + /** + * Sets the spline type + */ + void setSplineType( SplineType t ); + /** + * Returns the sturm flag + */ + bool sturm( ) const { return m_sturm; } + /** + * Sets the sturm flag + */ + void setSturm( bool s ); + + /** + * Sets the number of steps around the y axis + */ + static void setRSteps( int r ); + /** + * Sets the number of subdivisions of one spline segment + */ + static void setSSteps( int v ); + /** + * Returns the number of steps around the y axis + */ + static int rSteps( ) { return s_rSteps; } + /** + * Returns the number of subdivisions of one spline segment + */ + static int sSteps( ) { return s_sSteps; } + +protected: + /** */ + virtual void createViewStructure( ); + /** */ + virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey( ); } + +private: + /** + * Object action. Adds a spline point + */ + void splitSegment( const PMControlPointList& cp, + const QPtrList& cpViewPosition, + const PMVector& clickPosition ); + /** + * Object action. Removes a spline point + */ + void joinSegments( const PMControlPointList& cp, + const QPtrList& cpViewPosition, + const PMVector& clickPosition ); + + void stringToValues( const QString& str ); + QString valuesToString( ) const; + + /** + * IDs for @ref PMMementoData + */ + enum PMLatheMementoID { PMSplineTypeID, PMSturmID }; + /** + * IDs for the object actions + */ + enum PMLatheActionID { PMSplitSegmentID, PMJoinSegmentsID }; + SplineType m_splineType; + QValueList m_points; + bool m_sturm; + + static int s_rSteps; + static int s_sSteps; + static int s_parameterKey; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmlatheedit.cpp b/kpovmodeler/pmlatheedit.cpp new file mode 100644 index 00000000..970cc2f5 --- /dev/null +++ b/kpovmodeler/pmlatheedit.cpp @@ -0,0 +1,333 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmlatheedit.h" +#include "pmlathe.h" +#include "pmvectoredit.h" +#include "pmvectorlistedit.h" +#include "pmpart.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +PMLatheEdit::PMLatheEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMLatheEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Spline type:" ), this ) ); + m_pSplineType = new QComboBox( false, this ); + m_pSplineType->insertItem( i18n( "Linear Spline" ) ); + m_pSplineType->insertItem( i18n( "Quadratic Spline" ) ); + m_pSplineType->insertItem( i18n( "Cubic Spline" ) ); + m_pSplineType->insertItem( i18n( "Bezier Spline" ) ); + hl->addWidget( m_pSplineType ); + hl->addStretch( 1 ); + + connect( m_pSplineType, SIGNAL( activated( int ) ), + SLOT( slotTypeChanged( int ) ) ); +} + +void PMLatheEdit::createBottomWidgets( ) +{ + topLayout( )->addWidget( new QLabel( i18n( "Spline points:" ), this ) ); + + m_pPoints = new PMVectorListEdit( "u", "v", this ); + connect( m_pPoints, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pPoints, SIGNAL( selectionChanged( ) ), + SLOT( slotSelectionChanged( ) ) ); + QHBoxLayout* hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( m_pPoints, 2 ); + + m_pAddAbove = new QPushButton( this ); + m_pAddAbove->setPixmap( SmallIcon( "pmaddpointabove" ) ); + m_pAddBelow = new QPushButton( this ); + m_pAddBelow->setPixmap( SmallIcon( "pmaddpoint" ) ); + m_pRemove = new QPushButton( this ); + m_pRemove->setPixmap( SmallIcon( "pmremovepoint" ) ); + connect( m_pAddAbove, SIGNAL( clicked( ) ), SLOT( slotAddPointAbove( ) ) ); + connect( m_pAddBelow, SIGNAL( clicked( ) ), SLOT( slotAddPointBelow( ) ) ); + connect( m_pRemove, SIGNAL( clicked( ) ), SLOT( slotRemovePoint( ) ) ); + + QVBoxLayout* bl = new QVBoxLayout( hl ); + bl->addWidget( m_pAddAbove ); + bl->addWidget( m_pAddBelow ); + bl->addWidget( m_pRemove ); + bl->addStretch( 1 ); + + m_pSturm = new QCheckBox( i18n( "Sturm" ), this ); + topLayout( )->addWidget( m_pSturm ); + connect( m_pSturm, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + + Base::createBottomWidgets( ); +} + +void PMLatheEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Lathe" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMLathe* ) o; + + switch( m_pDisplayedObject->splineType( ) ) + { + case PMLathe::LinearSpline: + m_pSplineType->setCurrentItem( 0 ); + break; + case PMLathe::QuadraticSpline: + m_pSplineType->setCurrentItem( 1 ); + break; + case PMLathe::CubicSpline: + m_pSplineType->setCurrentItem( 2 ); + break; + case PMLathe::BezierSpline: + m_pSplineType->setCurrentItem( 3 ); + break; + } + m_pSplineType->setEnabled( !readOnly ); + m_pSturm->setChecked( m_pDisplayedObject->sturm( ) ); + m_pSturm->setEnabled( !readOnly ); + m_pPoints->setReadOnly( readOnly ); + m_pPoints->setVectors( m_pDisplayedObject->points( ), true ); + updateControlPointSelection( ); + updatePointButtons( ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMLatheEdit: Can't display object\n"; +} + +void PMLatheEdit::updateControlPointSelection( ) +{ + PMControlPointList cp = part( )->activeControlPoints( ); + PMControlPointListIterator it( cp ); + int i; + int np = cp.count( ) / 2; + + if( np == m_pPoints->size( ) ) + { + m_pPoints->blockSelectionUpdates( true ); + bool sb = m_pPoints->signalsBlocked( ); + m_pPoints->blockSignals( true ); + + m_pPoints->clearSelection( ); + for( i = 0; i < np; i++, ++it ) + if( ( *it )->selected( ) ) + m_pPoints->select( i ); + for( i = 0; i < np; i++, ++it ) + if( ( *it )->selected( ) ) + m_pPoints->select( i ); + + m_pPoints->blockSignals( sb ); + m_pPoints->blockSelectionUpdates( false ); + } +} + +void PMLatheEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + m_pDisplayedObject->setPoints( m_pPoints->vectors( ) ); + + switch( m_pSplineType->currentItem( ) ) + { + case 0: + m_pDisplayedObject->setSplineType( PMLathe::LinearSpline ); + break; + case 1: + m_pDisplayedObject->setSplineType( PMLathe::QuadraticSpline ); + break; + case 2: + m_pDisplayedObject->setSplineType( PMLathe::CubicSpline ); + break; + case 3: + m_pDisplayedObject->setSplineType( PMLathe::BezierSpline ); + break; + } + m_pDisplayedObject->setSturm( m_pSturm->isChecked( ) ); + Base::saveContents( ); + } +} + +bool PMLatheEdit::isDataValid( ) +{ + if( !m_pPoints->isDataValid( ) ) + return false; + + int np = m_pPoints->size( ); + switch( m_pSplineType->currentItem( ) ) + { + case 0: + if( np < 2 ) + { + KMessageBox::error( this, i18n( "Linear splines need at least 2 points." ), + i18n( "Error" ) ); + return false; + } + break; + case 1: + if( np < 3 ) + { + KMessageBox::error( this, i18n( "Quadratic splines need at least 3 points." ), + i18n( "Error" ) ); + return false; + } + break; + case 2: + if( np < 4 ) + { + KMessageBox::error( this, i18n( "Cubic splines need at least 4 points." ), + i18n( "Error" ) ); + return false; + } + break; + case 3: + if( ( np < 4 ) || ( ( np % 4 ) != 0 ) ) + { + KMessageBox::error( this, i18n( "Bezier splines need 4 points for each segment." ), + i18n( "Error" ) ); + return false; + } + break; + } + + return Base::isDataValid( ); +} + +void PMLatheEdit::slotTypeChanged( int ) +{ + emit dataChanged( ); +} + +void PMLatheEdit::slotAddPointAbove( ) +{ + int index = m_pPoints->currentRow( ); + if( index >= 0 ) + { + QValueList points = m_pPoints->vectors( ); + QValueListIterator it = points.at( index ); + + if( it != points.end( ) ) + { + QValueListIterator it2 = it; + it2--; + PMVector v; + if( it2 == points.end( ) ) + v = *it; + else + v = ( *it + *it2 ) / 2; + + points.insert( it, v ); + m_pPoints->setVectors( points, true ); + updatePointButtons( ); + emit dataChanged( ); + emit sizeChanged( ); + } + } +} + +void PMLatheEdit::slotAddPointBelow( ) +{ + int index = m_pPoints->currentRow( ); + if( index >= 0 ) + { + QValueList points = m_pPoints->vectors( ); + QValueListIterator it = points.at( index ); + + if( it != points.end( ) ) + { + QValueListIterator it2 = it; + it2++; + PMVector v; + if( it2 == points.end( ) ) + v = *it; + else + v = ( *it + *it2 ) / 2; + + points.insert( it2, v ); + m_pPoints->setVectors( points, true ); + m_pPoints->setCurrentCell( index + 1, m_pPoints->currentColumn( ) ); + updatePointButtons( ); + emit dataChanged( ); + emit sizeChanged( ); + } + } +} + +void PMLatheEdit::slotRemovePoint( ) +{ + int row = m_pPoints->currentRow( ); + + if( row >= 0 ) + { + QValueList points = m_pPoints->vectors( ); + QValueListIterator it = points.at( row ); + + if( it != points.end( ) && points.size( ) > 1 ) + { + points.remove( it ); + m_pPoints->setVectors( points, true ); + updatePointButtons( ); + emit dataChanged( ); + emit sizeChanged( ); + } + } +} + +void PMLatheEdit::slotSelectionChanged( ) +{ + PMControlPointList cp = part( )->activeControlPoints( ); + PMControlPointListIterator it( cp ); + int np = cp.count( ) / 2; + int i; + + if( np == m_pPoints->size( ) ) + { + for( i = 0; i < np; i++, ++it ) + ( *it )->setSelected( m_pPoints->isSelected( i ) ); + for( i = 0; i < np; i++, ++it ) + ( *it )->setSelected( m_pPoints->isSelected( i ) ); + emit controlPointSelectionChanged( ); + } + updatePointButtons( ); +} + +void PMLatheEdit::updatePointButtons( ) +{ + int row = m_pPoints->currentRow( ); + m_pAddAbove->setEnabled( row >= 0 ); + m_pAddBelow->setEnabled( row >= 0 ); + m_pRemove->setEnabled( row >= 0 && m_pPoints->size( ) > 2 ); +} + +#include "pmlatheedit.moc" diff --git a/kpovmodeler/pmlatheedit.h b/kpovmodeler/pmlatheedit.h new file mode 100644 index 00000000..ad8cf835 --- /dev/null +++ b/kpovmodeler/pmlatheedit.h @@ -0,0 +1,89 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMLATHEEDIT_H +#define PMLATHEEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" +#include "pmvectoredit.h" +#include +#include + +class PMLathe; +class PMVectorListEdit; +class QVBoxLayout; +class QComboBox; +class QCheckBox; +class QPushButton; +class QLabel; + +/** + * Dialog edit class for @ref PMLathe + */ +class PMLatheEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMLatheEdit with parent and name + */ + PMLatheEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + /** */ + virtual void updateControlPointSelection( ); + + /** */ + virtual bool isDataValid( ); + +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void createBottomWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + void slotTypeChanged( int ); + void slotAddPointAbove( ); + void slotAddPointBelow( ); + void slotRemovePoint( ); + void slotSelectionChanged( ); + +private: + void updatePointButtons( ); + + PMLathe* m_pDisplayedObject; + QComboBox* m_pSplineType; + QCheckBox* m_pSturm; + PMVectorListEdit* m_pPoints; + QPushButton* m_pAddAbove; + QPushButton* m_pAddBelow; + QPushButton* m_pRemove; +}; + + +#endif diff --git a/kpovmodeler/pmlayoutsettings.cpp b/kpovmodeler/pmlayoutsettings.cpp new file mode 100644 index 00000000..398e5354 --- /dev/null +++ b/kpovmodeler/pmlayoutsettings.cpp @@ -0,0 +1,774 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmlayoutsettings.h" + +#include "pmlineedits.h" +#include "pmviewfactory.h" +#include "pmdebug.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +PMLayoutSettings::PMLayoutSettings( QWidget* parent, const char* name ) + : PMSettingsDialogPage( parent, name ) +{ + QHBoxLayout* hlayout; + QVBoxLayout* vlayout; + QVBoxLayout* gvl; + QGridLayout* grid; + QGroupBox* gb; + QGroupBox* gbe; + QHBoxLayout* ghe; + QVBoxLayout* gvle; + + vlayout = new QVBoxLayout( this, 0, KDialog::spacingHint( ) ); + + hlayout = new QHBoxLayout( vlayout ); + hlayout->addWidget( new QLabel( i18n( "Default view layout:" ), this ) ); + m_pDefaultLayout = new QComboBox( this ); + hlayout->addWidget( m_pDefaultLayout, 1 ); + hlayout->addStretch( 1 ); + + gb = new QGroupBox( i18n( "Available View Layouts" ), this ); + vlayout->addWidget( gb ); + gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) ); + gvl->addSpacing( 10 ); + + grid = new QGridLayout( gvl, 3, 2 ); + m_pViewLayouts = new QListBox( gb ); + connect( m_pViewLayouts, SIGNAL( highlighted( int ) ), + SLOT( slotLayoutSelected( int ) ) ); + grid->addMultiCellWidget( m_pViewLayouts, 0, 2, 0, 0 ); + m_pAddLayout = new QPushButton( i18n( "Add" ), gb ); + connect( m_pAddLayout, SIGNAL( clicked( ) ), SLOT( slotAddLayout( ) ) ); + grid->addWidget( m_pAddLayout, 0, 1 ); + m_pRemoveLayout = new QPushButton( i18n( "Remove" ), gb ); + connect( m_pRemoveLayout, SIGNAL( clicked( ) ), SLOT( slotRemoveLayout( ) ) ); + grid->addWidget( m_pRemoveLayout, 1, 1 ); + grid->setRowStretch( 2, 1 ); + + gbe = new QGroupBox( i18n( "View Layout" ), gb ); + gvl->addWidget( gbe ); + gvle = new QVBoxLayout( gbe, KDialog::marginHint( ), KDialog::spacingHint( ) ); + gvle->addSpacing( 10 ); + ghe = new QHBoxLayout( gvle ); + ghe->addWidget( new QLabel( i18n( "Name:" ), gbe ) ); + m_pViewLayoutName = new QLineEdit( gbe ); + connect( m_pViewLayoutName, SIGNAL( textChanged( const QString& ) ), + SLOT( slotLayoutNameChanged( const QString& ) ) ); + ghe->addWidget( m_pViewLayoutName ); + grid = new QGridLayout( gvle, 4, 2 ); + m_pViewEntries = new QListView( gbe ); + m_pViewEntries->setAllColumnsShowFocus( true ); + m_pViewEntries->addColumn( " " ); // This column is for the view entry number + m_pViewEntries->addColumn( i18n( "Type" ) ); + m_pViewEntries->addColumn( i18n( "Position" ) ); + m_pViewEntries->setSorting( -1 ); + m_pViewEntries->setMaximumHeight( 150 ); + connect( m_pViewEntries, SIGNAL( selectionChanged( QListViewItem* ) ), + SLOT( slotViewEntrySelected( QListViewItem* ) ) ); + grid->addMultiCellWidget( m_pViewEntries, 0, 3, 0, 0 ); + m_pAddEntry = new QPushButton( i18n( "Add" ), gbe ); + connect( m_pAddEntry, SIGNAL( clicked( ) ), SLOT( slotAddViewEntryClicked( ) ) ); + grid->addWidget( m_pAddEntry, 0, 1 ); + m_pRemoveEntry = new QPushButton( i18n( "Remove" ), gbe ); + connect( m_pRemoveEntry, SIGNAL( clicked( ) ), SLOT( slotRemoveViewEntryClicked( ) ) ); + grid->addWidget( m_pRemoveEntry, 1, 1 ); + /* //TODO + m_pMoveUpEntry = new QPushButton( i18n( "Move Up" ), gbe ); + connect( m_pMoveUpEntry, SIGNAL( clicked( ) ), SLOT( slotMoveUpViewEntryClicked( ) ) ); + grid->addWidget( m_pMoveUpEntry, 2, 1 ); + m_pMoveDownEntry = new QPushButton( i18n( "Move Down" ), gbe ); + connect( m_pMoveDownEntry, SIGNAL( clicked( ) ), SLOT( slotMoveDownViewEntryClicked( ) ) ); + grid->addWidget( m_pMoveDownEntry, 3, 1 ); + */ + + QHBoxLayout* ghl = new QHBoxLayout( gvle ); + grid = new QGridLayout( ghl, 7, 4 ); + grid->addWidget( new QLabel( i18n( "Type:" ), gbe ), 0, 0 ); + grid->addWidget( new QLabel( i18n( "Dock position:" ), gbe ), 2, 0 ); + m_pColumnWidthLabel = new QLabel( i18n( "Column width:" ), gbe ); + grid->addWidget( m_pColumnWidthLabel, 3, 0 ); + m_pViewHeightLabel = new QLabel( i18n( "View height:" ), gbe ); + grid->addWidget( m_pViewHeightLabel, 4, 0 ); + m_pViewTypeEdit = new QComboBox( gbe ); + + // insert all view types + const QPtrList& types = + PMViewFactory::theFactory( )->viewTypes( ); + QPtrListIterator it( types ); + for( ; *it; ++it ) + m_pViewTypeEdit->insertItem( ( *it )->description( ) ); + + connect( m_pViewTypeEdit, SIGNAL( activated( int ) ), + SLOT( slotViewTypeChanged( int ) ) ); + grid->addWidget( m_pViewTypeEdit, 0, 1 ); + m_pDockPositionEdit = new QComboBox( gbe ); + m_pDockPositionEdit->insertItem( i18n( "New Column" ) ); + m_pDockPositionEdit->insertItem( i18n( "Below" ) ); + m_pDockPositionEdit->insertItem( i18n( "Tabbed" ) ); + m_pDockPositionEdit->insertItem( i18n( "Floating" ) ); + connect( m_pDockPositionEdit, SIGNAL( activated( int ) ), + SLOT( slotDockPositionChanged( int ) ) ); + grid->addWidget( m_pDockPositionEdit, 2, 1 ); + + m_pColumnWidthEdit = new PMIntEdit( gbe ); + connect( m_pColumnWidthEdit, SIGNAL( textChanged( const QString& ) ), + SLOT( slotColumnWidthChanged( const QString& ) ) ); + grid->addWidget( m_pColumnWidthEdit, 3, 1 ); + + m_pViewHeightEdit = new PMIntEdit( gbe ); + connect( m_pViewHeightEdit, SIGNAL( textChanged( const QString& ) ), + SLOT( slotViewHeightChanged( const QString& ) ) ); + grid->addWidget( m_pViewHeightEdit, 4, 1 ); + + m_pFloatingWidthLabel = new QLabel( i18n( "Width:" ), gbe ); + m_pFloatingHeightLabel = new QLabel( i18n( "Height:" ), gbe ); + m_pFloatingPosXLabel = new QLabel( i18n( "Position x:" ), gbe ); + m_pFloatingPosYLabel = new QLabel( QString( "y:" ), gbe ); + grid->addWidget( m_pFloatingWidthLabel, 5, 0 ); + grid->addWidget( m_pFloatingHeightLabel, 5, 2 ); + grid->addWidget( m_pFloatingPosXLabel, 6, 0 ); + grid->addWidget( m_pFloatingPosYLabel, 6, 2 ); + + m_pFloatingWidth = new PMIntEdit( gbe ); + connect( m_pFloatingWidth, SIGNAL( textChanged( const QString& ) ), + SLOT( slotFloatingWidthChanged( const QString& ) ) ); + m_pFloatingHeight = new PMIntEdit( gbe ); + connect( m_pFloatingHeight, SIGNAL( textChanged( const QString& ) ), + SLOT( slotFloatingHeightChanged( const QString& ) ) ); + m_pFloatingPosX = new PMIntEdit( gbe ); + connect( m_pFloatingPosX, SIGNAL( textChanged( const QString& ) ), + SLOT( slotFloatingPosXChanged( const QString& ) ) ); + m_pFloatingPosY = new PMIntEdit( gbe ); + connect( m_pFloatingPosY, SIGNAL( textChanged( const QString& ) ), + SLOT( slotFloatingPosYChanged( const QString& ) ) ); + grid->addWidget( m_pFloatingWidth, 5, 1 ); + grid->addWidget( m_pFloatingHeight, 5, 3 ); + grid->addWidget( m_pFloatingPosX, 6, 1 ); + grid->addWidget( m_pFloatingPosY, 6, 3 ); + + // create a holder widget for custom options widgets + m_pCustomOptionsWidget = 0; + m_pCustomOptionsHolder = new QWidget( gbe ); + + QVBoxLayout* covl = new QVBoxLayout( ghl ); + covl->addWidget( m_pCustomOptionsHolder ); + covl->addStretch( 1 ); + + ghl->addStretch( 1 ); + + vlayout->addStretch( 1 ); +} + +void PMLayoutSettings::displaySettings( ) +{ + PMViewLayoutManager* m = PMViewLayoutManager::theManager( ); + m_viewLayouts = m->layouts( ); + m_currentViewLayout = m_viewLayouts.begin( ); + m_defaultViewLayout = m_viewLayouts.begin( ); + for( ; ( m_defaultViewLayout != m_viewLayouts.end( ) ) && + ( *m_defaultViewLayout ).name( ) != m->defaultLayout( ); + ++m_defaultViewLayout ); + displayLayoutList( ); + m_pViewLayouts->setCurrentItem( 0 ); + if( m_pViewLayouts->numRows( ) == 1 ) + m_pRemoveLayout->setEnabled( false ); +} + +void PMLayoutSettings::displayDefaults( ) +{ +} + +bool PMLayoutSettings::validateData( ) +{ + QValueListIterator lit; + for( lit = m_viewLayouts.begin( ); lit != m_viewLayouts.end( ); ++lit ) + { + if( ( *lit ).name( ).isEmpty( ) ) + { + emit showMe( ); + KMessageBox::error( this, i18n( "View layouts may not have empty names." ), + i18n( "Error" ) ); + return false; + } + QValueListIterator eit = ( *lit ).begin( ); + if( eit != ( *lit ).end( ) ) + { + if( ( *eit ).dockPosition( ) != PMDockWidget::DockRight ) + { + emit showMe( ); + KMessageBox::error( this, i18n( "The docking position of the first view layout entry has to be 'New Column'." ), + i18n( "Error" ) ); + return false; + } + } + } + return true; +} + +void PMLayoutSettings::applySettings( ) +{ + QValueListIterator lit; + for( lit = m_viewLayouts.begin( ); lit != m_viewLayouts.end( ); ++lit ) + ( *lit ).normalize( ); + PMViewLayoutManager::theManager( )->setDefaultLayout( m_pDefaultLayout->currentText( ) ); + PMViewLayoutManager::theManager( )->setLayouts( m_viewLayouts ); + PMViewLayoutManager::theManager( )->saveData( ); +} + +void PMLayoutSettings::displayLayoutList( ) +{ + QValueListIterator it; + + m_pViewLayouts->clear( ); + m_pDefaultLayout->clear( ); + for( it = m_viewLayouts.begin( ); it != m_viewLayouts.end( ); ++it ) + { + m_pViewLayouts->insertItem( ( *it ).name( ) ); + m_pDefaultLayout->insertItem( ( *it ).name( ) ); + if( it == m_defaultViewLayout ) + m_pDefaultLayout->setCurrentText( ( *it ).name( ) ); + } +} + +void PMLayoutSettings::slotAddLayout( ) +{ + QString new_name; + int i = 1; + QString str; + + new_name = i18n( "Unnamed" ); + str.setNum( i ); + while( m_pViewLayouts->findItem( new_name, Qt::ExactMatch ) ) + { + new_name = i18n( "Unnamed" ) + str; + i++; + str.setNum( i ); + } + + PMViewLayout l; + l.setName( new_name ); + + m_currentViewLayout++; + m_viewLayouts.insert( m_currentViewLayout, l ); + displayLayoutList( ); + m_pViewLayouts->setCurrentItem( m_pViewLayouts->findItem( new_name, Qt::ExactMatch ) ); + m_pRemoveLayout->setEnabled( true ); +} + +void PMLayoutSettings::slotRemoveLayout( ) +{ + if( m_currentViewLayout == m_defaultViewLayout ) + { + m_defaultViewLayout--; + if( m_defaultViewLayout == m_viewLayouts.end( ) ) + { + m_defaultViewLayout++; + m_defaultViewLayout++; + } + } + m_viewLayouts.remove( m_currentViewLayout ); + displayLayoutList( ); + m_pViewLayouts->setCurrentItem( m_pViewLayouts->firstItem( ) ); + + if( m_pViewLayouts->numRows( ) == 1 ) + m_pRemoveLayout->setEnabled( false ); +} + +void PMLayoutSettings::slotLayoutSelected( int index ) +{ + int i; + QString str; + bool sb; + + m_currentViewLayout = m_viewLayouts.at( index ); + m_currentViewEntry = ( *m_currentViewLayout ).begin( ); + + sb = m_pViewLayoutName->signalsBlocked( ); + m_pViewLayoutName->blockSignals( true ); + m_pViewLayoutName->setText( ( *m_currentViewLayout ).name( ) ); + m_pViewLayoutName->blockSignals( sb ); + + PMViewLayout::iterator it; + QListViewItem* previous = NULL; + m_pViewEntries->clear( ); + i = 0; + for( it = ( *m_currentViewLayout ).begin( ); + it != ( *m_currentViewLayout ).end( ); ++it ) + { + i++; str.setNum( i ); + previous = new QListViewItem( m_pViewEntries, previous, str, + ( *it ).viewTypeAsString( ), + ( *it ).dockPositionAsString( ) ); + if( i == 1 ) + m_pViewEntries->setSelected( previous, true ); + } + if( i == 0 ) + slotViewEntrySelected( 0 ); +} + +void PMLayoutSettings::slotLayoutNameChanged( const QString& text ) +{ + int n_item = m_pViewLayouts->currentItem( ); + bool sb = m_pViewLayouts->signalsBlocked( ); + m_pViewLayouts->blockSignals( true ); + m_pViewLayouts->removeItem( n_item ); + m_pViewLayouts->insertItem( text, n_item ); + m_pViewLayouts->setCurrentItem( n_item ); + m_pViewLayouts->blockSignals( sb ); + + ( *m_currentViewLayout ).setName( text ); + + QValueListIterator it; + m_pDefaultLayout->clear( ); + for( it = m_viewLayouts.begin( ); it != m_viewLayouts.end( ); ++it ) + { + m_pDefaultLayout->insertItem( ( *it ).name( ) ); + if( it == m_defaultViewLayout ) + m_pDefaultLayout->setCurrentText( ( *it ).name( ) ); + } +} + +void PMLayoutSettings::slotViewEntrySelected( QListViewItem *item ) +{ + if( item ) + { + m_pViewTypeEdit->setEnabled( true ); + m_pDockPositionEdit->setEnabled( true ); + + int n_item = item->text( 0 ).toInt( ) - 1; + + m_currentViewEntry = ( *m_currentViewLayout ).at( n_item ); + QString vt = ( *m_currentViewEntry ).viewType( ); + + // find the view type + int index = 0; + bool found = false; + const QPtrList& types = + PMViewFactory::theFactory( )->viewTypes( ); + QPtrListIterator it( types ); + + for( ; *it && !found; ++it ) + { + if( ( *it )->viewType( ) == vt ) + found = true; + else + index++; + } + + if( !found ) + { + kdError( PMArea ) << "Unknown view type in PMLayoutSettings::slotViewEntrySelected" << endl; + m_pViewTypeEdit->setCurrentItem( 0 ); + } + else + m_pViewTypeEdit->setCurrentItem( index ); + + /* + switch( ( *m_currentViewEntry ).glViewType( ) ) + { + case PMGLView::PMViewNegY: + m_pGLViewTypeEdit->setCurrentItem( 0 ); + break; + case PMGLView::PMViewPosY: + m_pGLViewTypeEdit->setCurrentItem( 1 ); + break; + case PMGLView::PMViewPosX: + m_pGLViewTypeEdit->setCurrentItem( 2 ); + break; + case PMGLView::PMViewNegX: + m_pGLViewTypeEdit->setCurrentItem( 3 ); + break; + case PMGLView::PMViewPosZ: + m_pGLViewTypeEdit->setCurrentItem( 4 ); + break; + case PMGLView::PMViewNegZ: + m_pGLViewTypeEdit->setCurrentItem( 5 ); + break; + case PMGLView::PMViewCamera: + m_pGLViewTypeEdit->setCurrentItem( 6 ); + break; + } + */ + switch( ( *m_currentViewEntry ).dockPosition( ) ) + { + case PMDockWidget::DockRight: + m_pDockPositionEdit->setCurrentItem( 0 ); + m_pColumnWidthLabel->show( ); + m_pColumnWidthEdit->show( ); + m_pViewHeightEdit->show( ); + m_pViewHeightLabel->show( ); + m_pFloatingWidth->hide( ); + m_pFloatingHeight->hide( ); + m_pFloatingPosX->hide( ); + m_pFloatingPosY->hide( ); + m_pFloatingWidthLabel->hide( ); + m_pFloatingHeightLabel->hide( ); + m_pFloatingPosXLabel->hide( ); + m_pFloatingPosYLabel->hide( ); + break; + case PMDockWidget::DockBottom: + m_pDockPositionEdit->setCurrentItem( 1 ); + m_pColumnWidthLabel->hide( ); + m_pColumnWidthEdit->hide( ); + m_pViewHeightEdit->show( ); + m_pViewHeightLabel->show( ); + m_pFloatingWidth->hide( ); + m_pFloatingHeight->hide( ); + m_pFloatingPosX->hide( ); + m_pFloatingPosY->hide( ); + m_pFloatingWidthLabel->hide( ); + m_pFloatingHeightLabel->hide( ); + m_pFloatingPosXLabel->hide( ); + m_pFloatingPosYLabel->hide( ); + break; + case PMDockWidget::DockCenter: + m_pDockPositionEdit->setCurrentItem( 2 ); + m_pColumnWidthLabel->hide( ); + m_pColumnWidthEdit->hide( ); + m_pViewHeightEdit->hide( ); + m_pViewHeightLabel->hide( ); + m_pFloatingWidth->hide( ); + m_pFloatingHeight->hide( ); + m_pFloatingPosX->hide( ); + m_pFloatingPosY->hide( ); + m_pFloatingWidthLabel->hide( ); + m_pFloatingHeightLabel->hide( ); + m_pFloatingPosXLabel->hide( ); + m_pFloatingPosYLabel->hide( ); + break; + default: + m_pDockPositionEdit->setCurrentItem( 3 ); + m_pColumnWidthLabel->hide( ); + m_pColumnWidthEdit->hide( ); + m_pViewHeightEdit->hide( ); + m_pViewHeightLabel->hide( ); + m_pFloatingWidth->show( ); + m_pFloatingHeight->show( ); + m_pFloatingPosX->show( ); + m_pFloatingPosY->show( ); + m_pFloatingWidthLabel->show( ); + m_pFloatingHeightLabel->show( ); + m_pFloatingPosXLabel->show( ); + m_pFloatingPosYLabel->show( ); + break; + } + m_pColumnWidthEdit->setValue( ( *m_currentViewEntry ).columnWidth( ) ); + m_pViewHeightEdit->setValue( ( *m_currentViewEntry ).height( ) ); + m_pFloatingWidth->setValue( ( *m_currentViewEntry ).floatingWidth( ) ); + m_pFloatingHeight->setValue( ( *m_currentViewEntry ).floatingHeight( ) ); + m_pFloatingPosX->setValue( ( *m_currentViewEntry ).floatingPositionX( ) ); + m_pFloatingPosY->setValue( ( *m_currentViewEntry ).floatingPositionY( ) ); + m_pViewEntries->triggerUpdate( ); + displayCustomOptions( ); + } + else + { + m_pViewTypeEdit->setEnabled( false ); + m_pDockPositionEdit->setEnabled( false ); + m_pColumnWidthLabel->hide( ); + m_pColumnWidthEdit->hide( ); + m_pViewHeightEdit->hide( ); + m_pViewHeightLabel->hide( ); + m_pFloatingWidth->hide( ); + m_pFloatingHeight->hide( ); + m_pFloatingPosX->hide( ); + m_pFloatingPosY->hide( ); + m_pFloatingWidthLabel->hide( ); + m_pFloatingHeightLabel->hide( ); + m_pFloatingPosXLabel->hide( ); + m_pFloatingPosYLabel->hide( ); + } +} + +void PMLayoutSettings::slotViewTypeChanged( int index ) +{ + const QPtrList& types = + PMViewFactory::theFactory( )->viewTypes( ); + QPtrListIterator it( types ); + it += index; + const PMViewTypeFactory* factory = *it; + PMViewLayoutEntry& ve = ( *m_currentViewEntry ); + + if( factory && factory->viewType( ) != ve.viewType( ) ) + { + ve.setViewType( factory->viewType( ) ); + ve.setCustomOptions( factory->newOptionsInstance( ) ); + + QListViewItem* item = m_pViewEntries->currentItem( ); + if( item ) + { + if( ve.customOptions( ) ) + item->setText( 1, factory->description( ve.customOptions( ) ) ); + else + item->setText( 1, factory->description( ) ); + displayCustomOptions( ); + } + } +} + +void PMLayoutSettings::slotDockPositionChanged( int index ) +{ + switch( index ) + { + case 0: + ( *m_currentViewEntry ).setDockPosition( PMDockWidget::DockRight ); + m_pColumnWidthLabel->show( ); + m_pColumnWidthEdit->show( ); + m_pViewHeightEdit->show( ); + m_pViewHeightLabel->show( ); + m_pFloatingWidth->hide( ); + m_pFloatingHeight->hide( ); + m_pFloatingPosX->hide( ); + m_pFloatingPosY->hide( ); + m_pFloatingWidthLabel->hide( ); + m_pFloatingHeightLabel->hide( ); + m_pFloatingPosXLabel->hide( ); + m_pFloatingPosYLabel->hide( ); + break; + case 1: + ( *m_currentViewEntry ).setDockPosition( PMDockWidget::DockBottom ); + m_pColumnWidthLabel->hide( ); + m_pColumnWidthEdit->hide( ); + m_pViewHeightEdit->show( ); + m_pViewHeightLabel->show( ); + m_pFloatingWidth->hide( ); + m_pFloatingHeight->hide( ); + m_pFloatingPosX->hide( ); + m_pFloatingPosY->hide( ); + m_pFloatingWidthLabel->hide( ); + m_pFloatingHeightLabel->hide( ); + m_pFloatingPosXLabel->hide( ); + m_pFloatingPosYLabel->hide( ); + break; + case 2: + ( *m_currentViewEntry ).setDockPosition( PMDockWidget::DockCenter ); + m_pColumnWidthLabel->hide( ); + m_pColumnWidthEdit->hide( ); + m_pViewHeightEdit->hide( ); + m_pViewHeightLabel->hide( ); + m_pFloatingWidth->hide( ); + m_pFloatingHeight->hide( ); + m_pFloatingPosX->hide( ); + m_pFloatingPosY->hide( ); + m_pFloatingWidthLabel->hide( ); + m_pFloatingHeightLabel->hide( ); + m_pFloatingPosXLabel->hide( ); + m_pFloatingPosYLabel->hide( ); + break; + case 3: + ( *m_currentViewEntry ).setDockPosition( PMDockWidget::DockNone ); + m_pColumnWidthLabel->hide( ); + m_pColumnWidthEdit->hide( ); + m_pViewHeightEdit->hide( ); + m_pViewHeightLabel->hide( ); + m_pFloatingWidth->show( ); + m_pFloatingHeight->show( ); + m_pFloatingPosX->show( ); + m_pFloatingPosY->show( ); + m_pFloatingWidthLabel->show( ); + m_pFloatingHeightLabel->show( ); + m_pFloatingPosXLabel->show( ); + m_pFloatingPosYLabel->show( ); + break; + } + QListViewItem* item = m_pViewEntries->currentItem( ); + if( item ) + item->setText( 2, ( *m_currentViewEntry ).dockPositionAsString( ) ); +} + +void PMLayoutSettings::slotViewHeightChanged( const QString& text ) +{ + ( *m_currentViewEntry ).setHeight( text.toInt( ) ); +} + +void PMLayoutSettings::slotColumnWidthChanged( const QString& text ) +{ + ( *m_currentViewEntry ).setColumnWidth( text.toInt( ) ); +} + +void PMLayoutSettings::slotFloatingWidthChanged( const QString& text ) +{ + ( *m_currentViewEntry ).setFloatingWidth( text.toInt( ) ); +} + +void PMLayoutSettings::slotFloatingHeightChanged( const QString& text ) +{ + ( *m_currentViewEntry ).setFloatingHeight( text.toInt( ) ); +} + +void PMLayoutSettings::slotFloatingPosXChanged( const QString& text ) +{ + ( *m_currentViewEntry ).setFloatingPositionX( text.toInt( ) ); +} + +void PMLayoutSettings::slotFloatingPosYChanged( const QString& text ) +{ + ( *m_currentViewEntry ).setFloatingPositionY( text.toInt( ) ); +} + +void PMLayoutSettings::slotAddViewEntryClicked( ) +{ + PMViewLayoutEntry p; + QString str; + QListViewItem* temp; + + temp = m_pViewEntries->currentItem( ); + if( temp ) + { + int n_item = temp->text( 0 ).toInt( ); + ( *m_currentViewLayout ).addEntry( p, n_item ); + n_item++; + str.setNum( n_item ); + QListViewItem* a = new QListViewItem( m_pViewEntries, temp, + str, p.viewTypeAsString( ), + p.dockPositionAsString( ) ); + m_pViewEntries->setSelected( a, true ); + temp = a->nextSibling( ); + while( temp ) + { + n_item++; + str.setNum( n_item ); + temp->setText( 0, str ); + temp = temp->nextSibling( ); + } + } + else + { + // If there is no selected the list must be empty + ( *m_currentViewLayout ).addEntry( p ); + str.setNum( 1 ); + QListViewItem* a = new QListViewItem( m_pViewEntries, NULL, + str, p.viewTypeAsString( ), + p.dockPositionAsString( ) ); + m_pViewEntries->setSelected( a, true ); + } +} + +void PMLayoutSettings::slotRemoveViewEntryClicked( ) +{ + QListViewItem* temp; + QString str; + + QListViewItem* current = m_pViewEntries->currentItem( ); + if( current ) + { + int n_item = current->text( 0 ).toInt( ) - 1; + ( *m_currentViewLayout ).removeEntry( n_item ); + + // Save the next selected item in temp, since the current item will + // be removed. + temp = current->nextSibling( ); + if( !temp ) + temp = current->itemAbove( ); + else + n_item++; + + delete current; + + if( temp ) + { + str.setNum( n_item ); + temp->setText( 0, str ); + m_pViewEntries->setSelected( temp, true ); + n_item++; + temp = temp->nextSibling( ); + } + else + slotViewEntrySelected( 0 ); + while( temp ) + { + str.setNum( n_item ); + temp->setText( 0, str ); + n_item++; + temp = temp->nextSibling( ); + } + } +} + +void PMLayoutSettings::slotMoveUpViewEntryClicked( ) +{ +} + +void PMLayoutSettings::slotMoveDownViewEntryClicked( ) +{ +} + +void PMLayoutSettings::displayCustomOptions( ) +{ + // delete an old widget + if( m_pCustomOptionsHolder->layout( ) ) + delete m_pCustomOptionsHolder->layout( ); + if( m_pCustomOptionsWidget ) + { + delete m_pCustomOptionsWidget; + m_pCustomOptionsWidget = 0; + } + + if( m_currentViewLayout != m_viewLayouts.end( ) && + m_currentViewEntry != ( *m_currentViewLayout ).end( ) && + ( *m_currentViewEntry ).customOptions( ) ) + { + PMViewTypeFactory* vf = PMViewFactory::theFactory( )->viewFactory( + ( *m_currentViewEntry ).viewType( ) ); + if( vf ) + { + m_pCustomOptionsWidget = + vf->newOptionsWidget( m_pCustomOptionsHolder, + ( *m_currentViewEntry ).customOptions( ) ); + if( m_pCustomOptionsWidget ) + { + connect( m_pCustomOptionsWidget, SIGNAL( viewTypeDescriptionChanged( ) ), + SLOT( slotViewTypeDescriptionChanged( ) ) ); + QHBoxLayout* hl = new QHBoxLayout( m_pCustomOptionsHolder, + 0, KDialog::spacingHint( ) ); + hl->addWidget( m_pCustomOptionsWidget ); + m_pCustomOptionsWidget->show( ); + } + } + } +} + +void PMLayoutSettings::slotViewTypeDescriptionChanged( ) +{ + PMViewLayoutEntry& ve = *m_currentViewEntry; + const PMViewTypeFactory* factory = + PMViewFactory::theFactory( )->viewFactory( ve.viewType( ) ); + + if( factory ) + { + QListViewItem* item = m_pViewEntries->currentItem( ); + if( item ) + { + if( ve.customOptions( ) ) + item->setText( 1, factory->description( ve.customOptions( ) ) ); + else + item->setText( 1, factory->description( ) ); + } + } +} + +#include "pmlayoutsettings.moc" diff --git a/kpovmodeler/pmlayoutsettings.h b/kpovmodeler/pmlayoutsettings.h new file mode 100644 index 00000000..4bca52e3 --- /dev/null +++ b/kpovmodeler/pmlayoutsettings.h @@ -0,0 +1,174 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMLAYOUTSETTINGS_H +#define PMLAYOUTSETTINGS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsettingsdialog.h" +#include "pmviewlayoutmanager.h" + +#include + +class PMIntEdit; +class PMViewOptionsWidget; +class QComboBox; +class QListBox; +class QPushButton; +class QLabel; + +/** + * View layout configuration dialog page + */ +class PMLayoutSettings : public PMSettingsDialogPage +{ + Q_OBJECT +public: + /** + * Default constructor + */ + PMLayoutSettings( QWidget* parent, const char* name = 0 ); + /** */ + virtual void displaySettings( ); + /** */ + virtual bool validateData( ); + /** */ + virtual void applySettings( ); + /** */ + virtual void displayDefaults( ); + +protected slots: + /** + * Called when the browse add layout button is clicked + */ + void slotAddLayout( ); + /** + * Called when the remove layout button is clicked + */ + void slotRemoveLayout( ); + /** + * Called when the selected layout changes + */ + void slotLayoutSelected( int i ); + /** + * Called when the layout name changes + */ + void slotLayoutNameChanged( const QString& text ); + /** + * Called when the selected view entry changes + */ + void slotViewEntrySelected( QListViewItem* text ); + /** + * Called when the view type field changes value + */ + void slotViewTypeChanged( int index ); + /** + * Called when the gl view type field changes value + */ + //void slotGLViewTypeChanged( int index ); + /** + * Called when the dock position field changes value + */ + void slotDockPositionChanged( int index ); + /** + * Called when the view height field changes value + */ + void slotViewHeightChanged( const QString& text ); + /** + * Called when the column width field changes value + */ + void slotColumnWidthChanged( const QString& text ); + /** + * Called when the floating height changes value + */ + void slotFloatingHeightChanged( const QString& text ); + /** + * Called when the floating width changes value + */ + void slotFloatingWidthChanged( const QString& text ); + /** + * Called when the floating position x changes value + */ + void slotFloatingPosXChanged( const QString& text ); + /** + * Called when the floating position y changes value + */ + void slotFloatingPosYChanged( const QString& text ); + /** + * Called when the add view entry button is clicked + */ + void slotAddViewEntryClicked( ); + /** + * Called when the remove view entry button is clicked + */ + void slotRemoveViewEntryClicked( ); + /** + * Called when the move up view entry button is clicked + */ + void slotMoveUpViewEntryClicked( ); + /** + * Called when the move down view entry button is clicked + */ + void slotMoveDownViewEntryClicked( ); + /** + * Called when the view type description has changed + */ + void slotViewTypeDescriptionChanged( ); + +private: + void displayLayoutList( ); + void displayCustomOptions( ); + + QComboBox* m_pDefaultLayout; + QListBox* m_pViewLayouts; + QPushButton* m_pAddLayout; + QPushButton* m_pRemoveLayout; + QLineEdit* m_pViewLayoutName; + QListView* m_pViewEntries; + QPushButton* m_pAddEntry; + QPushButton* m_pRemoveEntry; + QPushButton* m_pMoveUpEntry; + QPushButton* m_pMoveDownEntry; + QComboBox* m_pViewTypeEdit; + QComboBox* m_pDockPositionEdit; + PMIntEdit* m_pColumnWidthEdit; + QLabel* m_pColumnWidthLabel; + PMIntEdit* m_pViewHeightEdit; + QLabel* m_pViewHeightLabel; + + PMIntEdit* m_pFloatingHeight; + PMIntEdit* m_pFloatingWidth; + QLabel* m_pFloatingHeightLabel; + QLabel* m_pFloatingWidthLabel; + PMIntEdit* m_pFloatingPosX; + PMIntEdit* m_pFloatingPosY; + QLabel* m_pFloatingPosXLabel; + QLabel* m_pFloatingPosYLabel; + + PMViewOptionsWidget* m_pCustomOptionsWidget; + QWidget* m_pCustomOptionsHolder; + + QValueList m_viewLayouts; + QValueListIterator m_currentViewLayout; + QValueListIterator m_defaultViewLayout; + QValueListIterator m_currentViewEntry; +}; + +#endif diff --git a/kpovmodeler/pmlibrarybrowser.cpp b/kpovmodeler/pmlibrarybrowser.cpp new file mode 100644 index 00000000..e133f08c --- /dev/null +++ b/kpovmodeler/pmlibrarybrowser.cpp @@ -0,0 +1,304 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmlibrarybrowser.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "pmlineedits.h" +#include "pmdialogeditbase.h" +#include "pmlibrarymanager.h" +#include "pmlibraryhandle.h" +#include "pmlibraryobject.h" +#include "pmlibraryiconview.h" +#include "pmlibraryentrypreview.h" + +// ************** PMLibraryBrowser ************************** + +PMLibraryBrowserView::PMLibraryBrowserView( PMPart* /*part*/, QWidget* parent /*= 0*/, + const char* name /*=0*/ ) + : PMViewBase( parent, name ) +{ + QHBoxLayout* hl = new QHBoxLayout( this ); + PMLibraryBrowserViewWidget* tv = new PMLibraryBrowserViewWidget( this ); + hl->addWidget( tv ); +} + +QString PMLibraryBrowserView::description( ) const +{ + return i18n( "Library View" ); +} + +PMLibraryBrowserViewWidget::PMLibraryBrowserViewWidget( QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + setCaption( i18n( "Library Objects" ) ); + + QVBoxLayout* vl = new QVBoxLayout( this, KDialog::spacingHint( ) ); + + QHBoxLayout* hl = new QHBoxLayout( vl ); + + m_pUpButton = new QPushButton( this ); + m_pUpButton->setPixmap( SmallIcon( "up" ) ); + m_pNewSubLibraryButton = new QPushButton( this ); + m_pNewSubLibraryButton->setPixmap( SmallIcon( "folder_new" ) ); + m_pNewObjectButton = new QPushButton( this ); + m_pNewObjectButton->setPixmap( SmallIcon( "filenew" ) ); + m_pDeleteObjectButton = new QPushButton( this ); + m_pDeleteObjectButton->setPixmap( SmallIcon( "editdelete" ) ); + QLabel* lbl = new QLabel( i18n( "Library: " ), this ); + m_pLibraryComboBox = new QComboBox( this ); + m_pLibraryComboBox->insertStringList( PMLibraryManager::theManager( )->availableLibraries( ) ); + m_pLibraryComboBox->setDuplicatesEnabled( false ); + m_pLibraryComboBox->setCurrentItem( 0 ); + hl->addWidget( m_pUpButton ); + hl->addWidget( m_pNewSubLibraryButton ); + hl->addWidget( m_pNewObjectButton ); + hl->addWidget( m_pDeleteObjectButton ); + hl->addWidget( lbl ); + hl->addWidget( m_pLibraryComboBox ); + hl->addStretch( 1 ); + + QSplitter *splitv = new QSplitter( this ); + m_pLibraryIconView = new PMLibraryIconView( splitv ); + m_pLibraryIconView->setMinimumSize( PMDialogEditBase::previewSize( )+20, PMDialogEditBase::previewSize( ) ); + m_pLibraryEntryPreview = new PMLibraryEntryPreview( splitv ); + vl->addWidget( splitv, 99 ); + + // Connect all the objects + connect( m_pUpButton, SIGNAL( clicked( ) ), SLOT( slotUpButtonClicked( ) ) ); + connect( m_pNewSubLibraryButton, SIGNAL( clicked( ) ), SLOT( slotNewSubLibraryClicked( ) ) ); + connect( m_pNewObjectButton, SIGNAL( clicked( ) ), SLOT( slotNewObjectClicked( ) ) ); + connect( m_pDeleteObjectButton, SIGNAL( clicked( ) ), SLOT( slotDeleteClicked( ) ) ); + connect( m_pLibraryComboBox, SIGNAL( highlighted( const QString& ) ), + SLOT( slotPathSelected( const QString& ) ) ); + connect( m_pLibraryIconView, SIGNAL( selectionChanged( QIconViewItem* ) ), + SLOT( slotSelectionChanged( QIconViewItem* ) ) ); + connect( m_pLibraryIconView, SIGNAL( executed( QIconViewItem* ) ), + SLOT( slotSelectionExecuted( QIconViewItem* ) ) ); + connect( m_pLibraryEntryPreview, SIGNAL( objectChanged( ) ), SLOT( slotIconViewRefresh( ) ) ); + + // Set the selected library + slotPathSelected( m_pLibraryComboBox->currentText( ) ); +} + +void PMLibraryBrowserViewWidget::resizeEvent( QResizeEvent* /*ev*/ ) +{ +} + +void PMLibraryBrowserViewWidget::slotPathSelected( const QString& str ) +{ + PMLibraryHandle* h = PMLibraryManager::theManager( )->getLibraryHandle( str ); + if( h ) + { + m_pLibraryIconView->setLibrary( h ); + m_pCurrentLibrary = h; + // This can never be a sub library + m_pUpButton->setEnabled( false ); + // If the top library is read-only so is everthing below it + m_topLibraryReadOnly = m_pCurrentLibrary->isReadOnly( ); + m_pNewSubLibraryButton->setEnabled( !m_topLibraryReadOnly ); + m_pNewObjectButton->setEnabled( !m_topLibraryReadOnly ); + m_pDeleteObjectButton->setEnabled( !m_topLibraryReadOnly ); + } + else + { + m_pUpButton->setEnabled( false ); + m_pNewSubLibraryButton->setEnabled( false ); + m_pNewObjectButton->setEnabled( false ); + m_pDeleteObjectButton->setEnabled( false ); + } +} + +void PMLibraryBrowserViewWidget::slotIconViewRefresh( ) +{ + m_pLibraryIconView->refresh( ); +} + +void PMLibraryBrowserViewWidget::slotIconViewSetLibrary( ) +{ + m_pLibraryIconView->setLibrary( m_pFutureLibrary ); + m_pCurrentLibrary = m_pFutureLibrary; + m_pFutureLibrary = NULL; +} + +void PMLibraryBrowserViewWidget::slotSelectionChanged( QIconViewItem* item ) +{ + PMLibraryIconViewItem* sel = static_cast( item ); + m_pLibraryIconView->setCurrentItem( sel ); + if( sel->isSubLibrary( ) ) + { + if( m_pLibraryEntryPreview->saveIfNeeded( ) ) + QTimer::singleShot( 100, this, SLOT( slotIconViewRefresh( ) ) ); + else + m_pLibraryEntryPreview->showPreview( sel->path( ), m_topLibraryReadOnly, true ); + } + else + { + if( m_pLibraryEntryPreview->saveIfNeeded( ) ) + QTimer::singleShot( 100, this, SLOT( slotIconViewRefresh( ) ) ); + else + m_pLibraryEntryPreview->showPreview( sel->path( ), m_topLibraryReadOnly, false ); + } + m_pLibraryIconView->setFocus(); +} + +void PMLibraryBrowserViewWidget::slotSelectionExecuted( QIconViewItem* item ) +{ + PMLibraryIconViewItem* sel = static_cast( item ); + m_pLibraryIconView->setCurrentItem( sel ); + if( sel->isSubLibrary( ) ) + { + // It's a sub library + m_pFutureLibrary = new PMLibraryHandle( sel->path( ) ); + m_pLibraryEntryPreview->clearPreview( ); + QTimer::singleShot( 100, this, SLOT( slotIconViewSetLibrary( ) ) ); + m_pUpButton->setEnabled( true ); + } + else + { + // It's an object + if( m_pLibraryEntryPreview->saveIfNeeded( ) ) + QTimer::singleShot( 100, this, SLOT( slotIconViewRefresh( ) ) ); + else + m_pLibraryEntryPreview->showPreview( sel->path( ), m_topLibraryReadOnly, false ); + } + m_pLibraryIconView->setFocus(); +} + +void PMLibraryBrowserViewWidget::slotUpButtonClicked( ) +{ + QDir pathManipulator( m_pCurrentLibrary->path( ) ); + + pathManipulator.cdUp( ); + m_pFutureLibrary = new PMLibraryHandle( pathManipulator.path( ) ); + if( !m_pFutureLibrary->isSubLibrary( ) ) + m_pUpButton->setEnabled( false ); + QTimer::singleShot( 100, this, SLOT( slotIconViewSetLibrary( ) ) ); + + // Release the current Library + delete m_pCurrentLibrary; +} + +void PMLibraryBrowserViewWidget::slotDeleteClicked( ) +{ + PMLibraryIconViewItem* sel = static_cast( m_pLibraryIconView->currentItem( ) ); + PMLibraryHandle::PMResult rst; + if( !sel ) + return; + else if( sel->isSubLibrary( ) ) + rst = m_pCurrentLibrary->deleteSubLibrary( sel->path( ) ); + else + rst = m_pCurrentLibrary->deleteObject( sel->path( ) ); + + switch( rst ) + { + case PMLibraryHandle::Ok: + { + KIO::Job *job = KIO::del( sel->path() ); + connect( job, SIGNAL( result( KIO::Job * ) ), SLOT( slotJobResult( KIO::Job * ) ) ); + } + break; + case PMLibraryHandle::ReadOnlyLib: + KMessageBox::error( this, i18n( "This library is read only." ), i18n( "Error" ) ); + break; + case PMLibraryHandle::NotInLib: + KMessageBox::error( this, i18n( "The current library does not contain that item." ), i18n( "Error" ) ); + break; + default: + KMessageBox::error( this, i18n( "Could not remove item." ), i18n( "Error" ) ); + break; + } +} + +void PMLibraryBrowserViewWidget::slotNewObjectClicked( ) +{ + m_pLibraryEntryPreview->saveIfNeeded( ); + + switch( m_pCurrentLibrary->createNewObject( ) ) + { + case PMLibraryHandle::Ok: + QTimer::singleShot( 100, this, SLOT( slotIconViewRefresh( ) ) ); + break; + case PMLibraryHandle::ReadOnlyLib: + KMessageBox::error( this, i18n( "This library is read only." ), i18n( "Error" ) ); + break; + default: + KMessageBox::error( this, i18n( "Could not create a new object." ), i18n( "Error" ) ); + } +} + +void PMLibraryBrowserViewWidget::slotNewSubLibraryClicked( ) +{ + bool result = false; + + m_pLibraryEntryPreview->saveIfNeeded( ); + QString subLibraryName = KInputDialog::getText( i18n( "Create Sub-Library" ), + i18n( "Enter the sub-library name: " ), + i18n( "Unknown" ), + &result ); + + if( result ) + { + switch( m_pCurrentLibrary->createNewSubLibrary( subLibraryName ) ) + { + case PMLibraryHandle::Ok: + m_pLibraryIconView->refresh( ); + break; + case PMLibraryHandle::ExistingDir: + KMessageBox::error( this, i18n( "That library already exists." ), i18n( "Error" ) ); + break; + case PMLibraryHandle::ReadOnlyLib: + KMessageBox::error( this, i18n( "This library is read only." ), i18n( "Error" ) ); + break; + default: + KMessageBox::error( this, i18n( "Could not create a new sub library." ), i18n( "Error" ) ); + } + } +} + +void PMLibraryBrowserViewWidget::slotJobResult( KIO::Job * job ) +{ + if( job->error( ) ) + job->showErrorDialog( this ); + QTimer::singleShot( 100, this, SLOT( slotIconViewRefresh( ) ) ); +} + +QString PMLibraryBrowserViewFactory::description( ) const +{ + return i18n( "Library View" ); +} + +#include "pmlibrarybrowser.moc" diff --git a/kpovmodeler/pmlibrarybrowser.h b/kpovmodeler/pmlibrarybrowser.h new file mode 100644 index 00000000..3d5af6ff --- /dev/null +++ b/kpovmodeler/pmlibrarybrowser.h @@ -0,0 +1,119 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#ifndef PMLIBRARYBROWSER_H +#define PMLIBRARYBROWSER_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "pmviewbase.h" +#include "pmviewfactory.h" + +class QComboBox; +class QIconViewItem; +class QPushButton; +class KConfig; +class KDirOperator; +class PMLibraryIconView; +class PMLibraryEntryPreview; +class PMLibraryHandle; +class PMPart; +namespace KIO{ class Job; } + +typedef QDict QStringDict; + +/** + * Wrapper class for the treeview/dock widget + */ +class PMLibraryBrowserView : public PMViewBase +{ + Q_OBJECT +public: + /** + * Default constructor + */ + PMLibraryBrowserView( PMPart* part, QWidget* parent, const char* name = 0 ); + + /** */ + virtual QString viewType( ) const { return QString( "librarybrowserview" ); } + /** */ + virtual QString description( ) const; +}; + +/** + * This class provides a non-modal dialog to browse the available libraries. + */ +class PMLibraryBrowserViewWidget: public QWidget +{ + Q_OBJECT +public: + PMLibraryBrowserViewWidget( QWidget *parent, const char* name = NULL ); + +private slots: + void resizeEvent( QResizeEvent* ev ); + void slotPathSelected( const QString& str ); + void slotSelectionChanged( QIconViewItem* item ); + void slotSelectionExecuted( QIconViewItem* item ); + void slotUpButtonClicked( ); + void slotDeleteClicked( ); + void slotNewObjectClicked( ); + void slotNewSubLibraryClicked( ); + + void slotJobResult( KIO::Job * ); + + // These slots provide delayed activity on the IconView + void slotIconViewRefresh( ); + void slotIconViewSetLibrary( ); + +private: + + + QPushButton* m_pUpButton; + QPushButton* m_pNewSubLibraryButton; + QPushButton* m_pNewObjectButton; + QPushButton* m_pDeleteObjectButton; + QComboBox* m_pLibraryComboBox; + PMLibraryIconView* m_pLibraryIconView; + PMLibraryEntryPreview* m_pLibraryEntryPreview; + PMLibraryHandle* m_pCurrentLibrary; + PMLibraryHandle* m_pFutureLibrary; + bool m_topLibraryReadOnly; +}; + +/** + * Factory class for the tree view + */ +class PMLibraryBrowserViewFactory : public PMViewTypeFactory +{ +public: + PMLibraryBrowserViewFactory( ) { } + virtual QString viewType( ) const { return QString( "librarybrowserview" ); } + virtual QString description( ) const; + virtual QString iconName( ) const { return QString( "pmlibrarybrowserview" ); } + virtual PMViewBase* newInstance( QWidget* parent, PMPart* part ) const + { + return new PMLibraryBrowserView( part, parent ); + } +}; + +#endif diff --git a/kpovmodeler/pmlibraryentrypreview.cpp b/kpovmodeler/pmlibraryentrypreview.cpp new file mode 100644 index 00000000..b7232cdd --- /dev/null +++ b/kpovmodeler/pmlibraryentrypreview.cpp @@ -0,0 +1,344 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmlibraryobject.h" +#include "pmlibraryhandle.h" +#include "pmlibraryentrypreview.h" +#include "pmdialogeditbase.h" +#include "pmpart.h" +#include "pmtreeview.h" +#include "pmxmlparser.h" +#include "pmscene.h" +#include "pmobjectdrag.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +PMLibraryEntryPreview::PMLibraryEntryPreview( QWidget* parent ) : + QWidget( parent ) +{ + setAcceptDrops( true ); + m_pPart = new PMPart( this, "treeview", NULL, "part", false, true ); + m_pPart->setReadWrite( false ); + m_readOnly = true; + m_modified = false; + m_subLib = false; + + setMaximumSize( 1000, 1000 ); + QVBoxLayout* vl = new QVBoxLayout( this, KDialog::spacingHint( ) ); + + QHBoxLayout* hl = new QHBoxLayout( vl ); + hl->addStretch( 1 ); + + QGridLayout* gl = new QGridLayout( vl, 4, 2 ); + gl->setColStretch( 1, 1 ); + QLabel* lbl = new QLabel( i18n( "Name: " ), this ); + m_pName = new QLineEdit( this ); + m_pName->setAlignment( Qt::AlignLeft ); + m_pName->setReadOnly( true ); + gl->addWidget( lbl, 0, 0 ); + gl->addWidget( m_pName, 0, 1 ); + + lbl = new QLabel( i18n( "Description:" ), this ); + lbl->setAlignment( Qt::AlignTop ); + m_pDescription = new QMultiLineEdit( this ); + m_pDescription->setAlignment( Qt::AlignTop | Qt::AlignLeft | + Qt::WordBreak | Qt::DontClip ); + m_pDescription->setReadOnly( true ); + gl->addWidget( lbl, 1, 0 ); + gl->addWidget( m_pDescription, 1, 1 ); + + m_pKeywordsLabel = new QLabel( i18n( "Keywords:" ), this ); + m_pKeywordsLabel->setAlignment( Qt::AlignTop ); + m_pKeywords = new QMultiLineEdit( this ); + m_pKeywords->setAlignment( Qt::AlignTop | Qt::AlignLeft | + Qt::WordBreak | Qt::DontClip ); + m_pKeywords->setReadOnly( true ); + gl->addWidget( m_pKeywordsLabel, 2, 0 ); + gl->addWidget( m_pKeywords, 2, 1 ); + + m_pContentsLabel = new QLabel( i18n( "Contents:" ), this ); + m_pContentsPreview = new PMTreeView( m_pPart, this ); + gl->addMultiCellWidget( m_pContentsLabel, 3, 3, 0, 1 ); + gl->addMultiCellWidget( m_pContentsPreview, 4, 4, 0, 1 ); + gl->setRowStretch(4, 1); + + hl = new QHBoxLayout( vl ); + hl->addStretch( 1 ); + m_pSetPreviewImageButton = new QPushButton( i18n( "Change Preview Image" ), this ); + m_pSetPreviewImageButton->setEnabled( false ); + hl->addWidget( m_pSetPreviewImageButton ); + + hl = new QHBoxLayout( vl ); + hl->addStretch( 1 ); + m_pApplyChanges = new QPushButton( i18n( "&Apply" ), this ); + m_pApplyChanges->setEnabled( false ); + hl->addWidget( m_pApplyChanges ); + m_pCancelChanges = new QPushButton( i18n( "&Cancel" ), this ); + m_pCancelChanges->setEnabled( false ); + hl->addWidget( m_pCancelChanges ); + + connect( m_pName, SIGNAL( textChanged( const QString& ) ), + SLOT( slotTextChanged( const QString& ) ) ); + connect( m_pDescription, SIGNAL( textChanged( ) ), + SLOT( slotTextChanged( ) ) ); + connect( m_pKeywords, SIGNAL( textChanged( ) ), + SLOT( slotTextChanged( ) ) ); + connect( m_pSetPreviewImageButton, SIGNAL( clicked( ) ), + SLOT( slotPreviewClicked( ) ) ); + connect( m_pPart, SIGNAL( modified( ) ), + SLOT( slotTextChanged( ) ) ); + connect( m_pApplyChanges, SIGNAL( clicked( ) ), SLOT( slotApplyClicked( ) ) ); + connect( m_pCancelChanges, SIGNAL( clicked( ) ), SLOT( slotCancelClicked( ) ) ); + vl->addStretch( 1 ); +} + +PMLibraryEntryPreview::~PMLibraryEntryPreview( ) +{ +// delete m_pPart; +} + +bool PMLibraryEntryPreview::showPreview( KURL u, bool readOnly, bool subLib ) +{ + bool result = false; + + if( u.isLocalFile( ) ) + { + result = saveIfNeeded( ); + + m_image.reset( ); + + m_subLib = subLib; + if( subLib ) + { + // Load the new subLib to preview + PMLibraryHandle lib( u.path( ) ); + m_pName->setText( lib.name( ) ); + m_pDescription->setText( lib.description( ) ); + m_pKeywords->setText( "" ); + m_pPart->setReadWrite( true ); + m_pPart->setScene( new PMScene( m_pPart ) ); + m_pContentsPreview->slotRefresh( ); + m_pPart->setReadWrite( false ); + } + else + { + // Load the new object to preview + PMLibraryObject aux( u ); + + m_pName->setText( aux.name( ) ); + m_pDescription->setText( aux.description( ) ); + m_pKeywords->setText( aux.keywords( ) ); + if( aux.preview( ) ) + { + m_image = aux.preview( )->copy( ); + } + loadObjects( aux.objects( ) ); + // Save the preview location + } + m_pKeywordsLabel->setEnabled( !subLib ); + m_pKeywords->setEnabled( !subLib ); + m_pContentsLabel->setEnabled( !subLib ); + m_pContentsPreview->setEnabled( !subLib ); + setReadOnly( readOnly ); + setModified( false ); + m_currentURL = u; + } + return result; +} + +void PMLibraryEntryPreview::loadObjects( QByteArray* obj ) +{ + + m_pPart->setReadWrite( true ); + m_pPart->setScene( new PMScene( m_pPart ) ); + if( obj ) + { + PMXMLParser parser( m_pPart, *obj ); + m_pPart->insertFromParser( i18n( "Object Load" ), &parser, m_pPart->scene( ) ); + } + m_pPart->setReadWrite( false ); + m_pContentsPreview->slotRefresh( ); +} + +void PMLibraryEntryPreview::clearPreview( ) +{ + saveIfNeeded( ); + m_pName->setText( "" ); + m_pDescription->setText( "" ); + m_pKeywords->setText( "" ); + m_image.reset( ); + m_pPart->setReadWrite( true ); + m_pPart->setScene( new PMScene( m_pPart ) ); + m_pContentsPreview->slotRefresh( ); + m_pPart->setReadWrite( false ); + setReadOnly( true ); + setModified( false ); +} + +void PMLibraryEntryPreview::setReadOnly( bool b ) +{ + m_readOnly = b; + if( b ) + { + m_pName->setReadOnly( true ); + m_pDescription->setReadOnly( true ); + m_pKeywords->setReadOnly( true ); + m_pSetPreviewImageButton->setEnabled( false ); + m_pPart->setReadWrite( false ); + } + else + { + m_pName->setReadOnly( false ); + m_pDescription->setReadOnly( false ); + if( m_subLib ) + { + m_pKeywords->setReadOnly( true ); + m_pSetPreviewImageButton->setEnabled( false ); + m_pPart->setReadWrite( false ); + } + else + { + m_pKeywords->setReadOnly( false ); + m_pSetPreviewImageButton->setEnabled( true ); + m_pPart->setReadWrite( true ); + } + } +} + +void PMLibraryEntryPreview::slotTextChanged( ) +{ + setModified( true ); +} + +void PMLibraryEntryPreview::slotTextChanged( const QString& /* s */) +{ + setModified( true ); +} + +void PMLibraryEntryPreview::slotPreviewClicked( ) +{ + KFileDialog dlg( QString::null, "", NULL, "", false ); + + dlg.setFilter( "image/jpeg image/gif image/tiff image/png image/x-bmp" ); + if( dlg.exec( ) == QDialog::Accepted ) + { + m_image.load( dlg.selectedFile( ) ); + setModified( true ); + } +} + +void PMLibraryEntryPreview::slotApplyClicked( ) +{ + saveIfNeeded( true ); + emit objectChanged( ); +} + +void PMLibraryEntryPreview::slotCancelClicked( ) +{ + setModified( false ); + showPreview( m_currentURL, m_readOnly, m_subLib ); +} + +bool PMLibraryEntryPreview::saveIfNeeded( bool forceSave ) +{ + if ( m_modified ) + { + // ask if we must save the changes + if( forceSave || KMessageBox::questionYesNo( this, + i18n( "The object has been modified and not saved.\nDo you wish to save?" ), + i18n( "Warning" ), KStdGuiItem::save(), KStdGuiItem::discard() ) == KMessageBox::Yes ) + { + if( m_subLib ) + { + PMLibraryHandle lib( m_currentURL.path( ) ); + lib.setName( m_pName->text( ) ); + lib.setDescription( m_pDescription->text( ) ); + lib.saveLibraryInfo( ); + } + else + { + PMLibraryObject objToSave; + PMObjectList sortedList; + PMObject* tmp; + + // First save the text parameters. + objToSave.setName( m_pName->text( ) ); + objToSave.setDescription( m_pDescription->text( ) ); + objToSave.setKeywords( m_pKeywords->text( ) ); + + // Gather the contents of the part. + tmp = m_pPart->scene( )->firstChild( ); + while( tmp ) + { + sortedList.append( tmp ); + tmp = tmp->nextSibling(); + } + + // Add them to the object to save. + PMObjectDrag drag( m_pPart, sortedList ); + objToSave.setObjects( drag.encodedData( "application/x-kpovmodeler" ) ); + + // Add the preview image + objToSave.setPreview( m_image.copy( ) ); + + // Finally save the object to a file. + kdDebug( 0 ) << m_currentURL.path( ) << "\n"; + objToSave.save( m_currentURL.path( ) ); + } + setModified( false ); + return true; + } + setModified( false ); + } + return false; +} + +void PMLibraryEntryPreview::dragEnterEvent( QDragEnterEvent* event ) +{ + event->accept( !m_readOnly && QImageDrag::canDecode( event ) ); +} + +void PMLibraryEntryPreview::dropEvent( QDropEvent* event ) +{ + QImage img; + if( QImageDrag::decode( event, img ) ) + { + m_image = img; + setModified( true ); + } +} + +void PMLibraryEntryPreview::setModified( bool modified ) +{ + m_modified = modified; + m_pApplyChanges->setEnabled( modified ); + m_pCancelChanges->setEnabled( modified ); +} + +#include "pmlibraryentrypreview.moc" diff --git a/kpovmodeler/pmlibraryentrypreview.h b/kpovmodeler/pmlibraryentrypreview.h new file mode 100644 index 00000000..95077299 --- /dev/null +++ b/kpovmodeler/pmlibraryentrypreview.h @@ -0,0 +1,119 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#ifndef PMLIBRARYOBJECTPREVIEW_H +#define PMLIBRARYOBJECTPREVIEW_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +class QLabel; +class QLineEdit; +class QMultiLineEdit; +class QPushButton; +class QFrame; +class PMPart; +class PMTreeView; + +/** + * Preview widget for Library Objects and sub Libs. + */ +class PMLibraryEntryPreview: public QWidget +{ + Q_OBJECT +public: + /** Constructor */ + PMLibraryEntryPreview( QWidget *parent ); + /** Destructor */ + ~PMLibraryEntryPreview( ); + + /** + * Called to show the file preview. + * @param url The path to the file + * @param readOnly Whether the top library is read only + * @param subLib Whether this is a sub library to preview + * @Return true if the previous file was saved to disk. + */ + bool showPreview( KURL url, bool readOnly, bool subLib ); + /** + * Clears the preview + */ + virtual void clearPreview( ); + + /** + * Save the object, if needed. + * @param forceSave If true don't ask about changes just save them + * @Return true if a save was performed. + */ + bool saveIfNeeded( bool forceSave = false ); + +signals: + /** Emitted when the object name has been changed */ + void objectChanged( ); + +protected: + virtual void dragEnterEvent( QDragEnterEvent* event ); + + virtual void dropEvent( QDropEvent* event ); + +private slots: + /** Called when description or keywords are changed */ + void slotTextChanged( ); + /** Called when the name is changed */ + void slotTextChanged( const QString& s ); + /** Called when the set preview button is clicked */ + void slotPreviewClicked( ); + /** Called when the apply button is clicked */ + void slotApplyClicked( ); + /** Called when the cancel button is clicked */ + void slotCancelClicked( ); + +private: + /** Called to load the object tree. */ + void loadObjects( QByteArray* obj ); + /** Sets whether the object is read only or not */ + void setReadOnly( bool b ); + /** Sets whether the object is modified or not */ + void setModified( bool modified ); + + PMPart* m_pPart; + QLineEdit* m_pName; + QMultiLineEdit* m_pDescription; + QLabel* m_pKeywordsLabel; + QMultiLineEdit* m_pKeywords; + QLabel* m_pContentsLabel; + PMTreeView* m_pContentsPreview; + QPushButton* m_pSetPreviewImageButton; + QPushButton* m_pApplyChanges; + QPushButton* m_pCancelChanges; + + QImage m_image; + KURL m_currentURL; + + bool m_modified; + bool m_readOnly; + bool m_subLib; +}; + +#endif diff --git a/kpovmodeler/pmlibraryhandle.cpp b/kpovmodeler/pmlibraryhandle.cpp new file mode 100644 index 00000000..7902f789 --- /dev/null +++ b/kpovmodeler/pmlibraryhandle.cpp @@ -0,0 +1,395 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Luis Carvalho + email : lpassos@oninetspeed.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#include "pmlibraryhandle.h" +#include "pmlibraryobject.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "pmdebug.h" + +PMLibraryHandle::PMLibraryHandle( ) +{ + setPath( "" ); + setAuthor( i18n( "Unknown" ) ); + setName( i18n( "Unknown" ) ); + m_readOnly = false; + m_objects.setAutoDelete( true ); + m_libraries.setAutoDelete( true ); +} + +PMLibraryHandle::PMLibraryHandle( const QString& path ) +{ + setPath( path ); + setAuthor( i18n( "Unknown" ) ); + setName( i18n( "Unknown" ) ); + m_objects.setAutoDelete( true ); + m_libraries.setAutoDelete( true ); + loadLibraryInfo( ); +} + +PMLibraryHandle::~PMLibraryHandle( ) +{ +} + +void PMLibraryHandle::setName( const QString& name ) +{ + m_name = name; +} + +void PMLibraryHandle::setPath( const QString& path ) +{ + m_objects.clear( ); + m_path = path; +} + +void PMLibraryHandle::setAuthor( const QString& author ) +{ + m_author = author; +} + +void PMLibraryHandle::setDescription( const QString& description ) +{ + m_description = description; +} + +void PMLibraryHandle::setReadOnly( const bool rdOnly ) +{ + m_readOnly = rdOnly; +} + +void PMLibraryHandle::loadLibraryInfo( ) +{ + // 1. Open the information file (library_index.xml) + QFile file( m_path + "/library_index.xml" ); + + if( !file.open( IO_ReadOnly ) ) + { + kdError( PMArea ) << "Could not find the library index." << endl; + return; + } + + // 2. Read the information + QDomDocument doc( "KPOVLIBINDEX" ); + doc.setContent( &file ); + + QDomElement e = doc.documentElement( ); + + if( e.tagName( ) != "library" ) + { + kdError( PMArea ) << "This doesn't appear to be a library index." << endl; + return; + } + + // 3. The library entry + setName( e.attribute( "name", i18n( "Unknown" ) ) ); + setAuthor( e.attribute( "author", i18n( "Unknown" ) ) ); + setDescription( e.attribute( "description", "" ) ); + if( e.attribute( "readonly", "false" ) == "false" ) + m_readOnly = false; + else + m_readOnly = true; + + if( e.attribute( "sublibrary", "false" ) == "false" ) + m_subLibrary = false; + else + m_subLibrary = true; + + // 4. The object entries + QDomNode n = e.firstChild( ); + if( !n.isNull( ) ) + { + if( n.isElement( ) ) + { + QDomElement c = n.toElement( ); + if( c.tagName( ) == "object_list" ) + { + n = n.firstChild( ); + while( !n.isNull( ) ) + { + c = n.toElement( ); + if( c.tagName( ) == "object_entry" ) + { + m_objects.insert( c.attribute( "name", i18n( "Unknown" ) ), + new QString( c.attribute( "file", "" ) ) ); + } + else if( c.tagName( ) == "library_entry" ) + { + m_libraries.insert( c.attribute( "name", i18n( "Unknown" ) ), + new QString( c.attribute( "file", "" ) ) ); + } + n = n.nextSibling( ); + } + } + } + } +} + +PMLibraryHandle::PMResult PMLibraryHandle::createLibrary( ) +{ + // Test if the library exists. + QDir d( m_path ); + + if( !d.exists( ) ) + { + // If it doesn't, create it + if( !d.mkdir( m_path ) ) + { + return PMLibraryHandle::CouldNotCreateDir; + } + } + else + { + return PMLibraryHandle::ExistingDir; + } + + return saveLibraryInfo( ); +} + +PMLibraryHandle::PMResult PMLibraryHandle::saveLibraryInfo( ) +{ + // Save the information to the index + QFile file( m_path + "/library_index.xml" ); + if( !file.open( IO_WriteOnly ) ) + { + return PMLibraryHandle::CouldNotCreateInfo; + } + + // Create the XML DOM tree + QDomDocument doc( "KPOVLIBINDEX" ); + QDomElement e = doc.createElement( "library" ); + e.setAttribute( "name", name( ) ); + e.setAttribute( "author", author( ) ); + e.setAttribute( "description", description( ) ); + if( m_readOnly ) + e.setAttribute( "readonly", "true" ); + else + e.setAttribute( "readonly", "false" ); + + if( m_subLibrary ) + e.setAttribute( "sublibrary", "true" ); + else + e.setAttribute( "sublibrary", "false" ); + + // Add the object list to the tree + QDomElement l = doc.createElement( "object_list" ); + for(QDictIterator it( m_objects ); it.current( ); ++it ) + { + QDomElement n = doc.createElement( "object_entry" ); + n.setAttribute( "name", it.currentKey( ) ); + n.setAttribute( "file", *( it.current( ) ) ); + l.appendChild( n ); + } + for(QDictIterator it( m_libraries ); it.current( ); ++it ) + { + QDomElement n = doc.createElement( "library_entry" ); + n.setAttribute( "name", it.currentKey( ) ); + n.setAttribute( "file", *( it.current( ) ) ); + l.appendChild( n ); + } + e.appendChild( l ); + doc.appendChild( e ); + + // Save to the file + QTextStream str( &file ); + str.setEncoding( QTextStream::UnicodeUTF8 ); + str << doc.toString( ); + file.close( ); + + return PMLibraryHandle::Ok; +} + +PMLibraryHandle::PMResult PMLibraryHandle::createNewObject( ) +{ + /// @todo Need to replace mkdtemp and mkstemps before enabling libs + return PMLibraryHandle::CouldNotCreateFile; + /* + PMLibraryObject aux; + QCString s = m_path.latin1( ); + QString unknownIcon = locate( "data" , "kpovmodeler/questionmark.png" ); + QImage img; + int fh; + + if( m_readOnly ) + return PMLibraryHandle::ReadOnlyLib; + + aux.setName( i18n( "Empty" ) ); + aux.setObjects( QByteArray( ) ); + img.load( unknownIcon, "PNG" ); + aux.setPreview( img ); + + s = s + "/objXXXXXX.kpml"; + if( ( fh = mkstemps( s.data( ), 5 ) ) < 0 ) + { + // Ooops! Error creating the file. + return PMLibraryHandle::CouldNotCreateFile; + } + + // Success creating the file + close( fh ); + m_objects.insert( i18n( "Empty" ), new QString( s ) ); + aux.save( s ); + saveLibraryInfo( ); + return PMLibraryHandle::Ok; + */ +} + +PMLibraryHandle::PMResult PMLibraryHandle::addObject( const QString& path, const QString& name ) +{ + if( m_readOnly ) + return PMLibraryHandle::ReadOnlyLib; + + m_objects.insert( name, new QString( path ) ); + saveLibraryInfo( ); + return PMLibraryHandle::Ok; +} + +PMLibraryHandle::PMResult PMLibraryHandle::deleteObject( const QString& objectName ) +{ + if( m_readOnly ) + return PMLibraryHandle::ReadOnlyLib; + + if( !m_objects.remove( objectName ) ) + { + PMLibraryHandle::EntryIterator itr( m_objects ); + for( ; itr.current( ); ++itr ) + { + if( *(itr.current( )) == objectName ) + { + m_objects.remove( itr.currentKey( ) ); + saveLibraryInfo( ); + return PMLibraryHandle::Ok; + } + } + } + return PMLibraryHandle::NotInLib; +} + +PMLibraryHandle::PMResult PMLibraryHandle::createNewSubLibrary( const QString /*subLibName*/ ) +{ + /// @todo Need to replace mkdtemp and mkstemps before enabling libs + return PMLibraryHandle::CouldNotCreateFile; + /* + char* dirname; + QCString s = m_path.latin1( ); + PMLibraryHandle aux; + + if( m_readOnly ) + return PMLibraryHandle::ReadOnlyLib; + + if( m_libraries.find( subLibName ) ) + return PMLibraryHandle::ExistingDir; + + s = s+ "/libXXXXXX"; + if ( !( dirname = mkdtemp( s.data( ) ) ) ) + { + // Ooops! Error creating the file. + return PMLibraryHandle::CouldNotCreateFile; + } + + aux.setName( subLibName ); + aux.setAuthor( author( ) ); + aux.setPath( dirname ); + aux.saveLibraryInfo( ); + m_libraries.insert( subLibName, new QString( dirname ) ); + saveLibraryInfo( ); + return PMLibraryHandle::Ok; + */ +} + +PMLibraryHandle::PMResult PMLibraryHandle::addSubLibrary( const QString& path, const QString& subLibName ) +{ + if( m_readOnly ) + return PMLibraryHandle::ReadOnlyLib; + + m_libraries.insert( subLibName, new QString( path ) ); + saveLibraryInfo( ); + return PMLibraryHandle::Ok; +} + +PMLibraryHandle::PMResult PMLibraryHandle::deleteSubLibrary( const QString& subLibName ) +{ + if( m_readOnly ) + return PMLibraryHandle::ReadOnlyLib; + + if( !m_libraries.remove( subLibName ) ) + { + PMLibraryHandle::EntryIterator itr( m_libraries ); + for( ; itr.current( ); ++itr ) + { + if( *(itr.current( )) == subLibName ) + { + m_libraries.remove( itr.currentKey( ) ); + saveLibraryInfo( ); + return PMLibraryHandle::Ok; + } + } + } + return PMLibraryHandle::NotInLib; +} + +PMLibraryHandle::PMResult PMLibraryHandle::changeParentLibrary( const QString& parentPath ) +{ + if( m_readOnly ) + return PMLibraryHandle::ReadOnlyLib; + + QString newPath = parentPath + "/" + m_path.section( '/', -1 ); + PMLibraryHandle::EntryIterator itr( m_libraries ); + for( ; itr.current( ); ++itr ) + { + PMLibraryHandle lib = PMLibraryHandle( *itr.current( ) ); + lib.changeParentLibrary( newPath ); + m_libraries.replace( itr.currentKey( ), new QString( newPath + "/" + lib.path( ) ) ); + } + + PMLibraryHandle::EntryIterator objItr( m_objects ); + for( ; objItr.current( ); ++objItr ) + { + QString test = newPath + "/" + objItr.current( )->section( '/', -1 ); + m_objects.replace( objItr.currentKey( ), new QString( newPath + "/" + objItr.current( )->section( '/', -1 ) ) ); + } + + saveLibraryInfo( ); + m_path = newPath; + return PMLibraryHandle::Ok; +} + +PMLibraryHandle::EntryIterator* PMLibraryHandle::createObjectIterator( ) +{ + return new EntryIterator( m_objects ); +} + +PMLibraryHandle::EntryIterator* PMLibraryHandle::createSubLibraryIterator( ) +{ + return new EntryIterator( m_libraries ); +} + +void PMLibraryHandle::setSubLibrary( bool isSubLibrary ) +{ + m_subLibrary = isSubLibrary; +} diff --git a/kpovmodeler/pmlibraryhandle.h b/kpovmodeler/pmlibraryhandle.h new file mode 100644 index 00000000..e906fd11 --- /dev/null +++ b/kpovmodeler/pmlibraryhandle.h @@ -0,0 +1,210 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Luis Carvalho + email : lpassos@oninetspeed.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#ifndef PMLIBRARYHANDLE_H +#define PMLIBRARYHANDLE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +class QDomElement; + +/** + * Class that holds all the information about a specific library. + * The class can also create the library if it doesn't exists. + * + * A library is nothing more than a directory in the file system, and + * an index file stored in XML format. + * + * One library can have one or more sub-libraries. Sub-libraries can + * only contain the entries of object files and more sub-libraries. + * + */ +class PMLibraryHandle +{ +public: + enum PMResult { Ok, CouldNotCreateDir, ExistingDir, + CouldNotCreateInfo, ReadOnlyLib, + CouldNotCreateFile, NotInLib }; + + /** + * Iterator for the objects in the library + */ + typedef QDictIterator EntryIterator; + + /** + * Constructor for an empty library + */ + PMLibraryHandle( ); + + /** + * Constructor for a given directory. + */ + PMLibraryHandle( const QString& path ); + + /** + * Destructor + */ + ~PMLibraryHandle( ); + /** + * Returns the library's name + */ + QString name( ) const { return m_name; } + + /** + * Returns the library's path + */ + QString path( ) const { return m_path; } + + /** + * Returns the library's author + */ + QString author( ) const { return m_author; } + + /** + * Returns the library's description + */ + QString description( ) const { return m_description; } + + /** + * Sets the library's name + */ + void setName( const QString& name ); + + /** + * Sets the library's path + */ + void setPath( const QString& path ); + + /** + * Sets the library's author + */ + void setAuthor( const QString& author ); + + /** + * Sets the library's description + */ + void setDescription( const QString& description ); + + /** + * Sets the library's erad only status + */ + void setReadOnly( const bool rdonly = true ); + + /** + * Save the library's information file. + */ + PMLibraryHandle::PMResult saveLibraryInfo( ); + + /** + * Create the library's information file. + */ + PMLibraryHandle::PMResult createLibrary( ); + + /** + * Append a new object to the library. + * Returns PMLibraryHandle::Ok if successful or the reason of failure. + */ + PMLibraryHandle::PMResult createNewObject( ); + /** + * Adds an already existing object to the library + * @param path The path for the object + * @param name The name of the object + * @return PMLibraryHandle::Ok if successful or the reason of failure + */ + PMLibraryHandle::PMResult addObject( const QString& path, const QString& name ); + /** + * Deletes an object out of the library. Only removes the entry from the library + * doesn't delete the objects file + * @param objectName The name of the object ( or objects path ) to delete + * @return PMLibraryHandle::Ok if successul or the reason of failure + */ + PMLibraryHandle::PMResult deleteObject( const QString& objectName ); + + /** + * Create a new sub library. + */ + PMLibraryHandle::PMResult createNewSubLibrary( const QString subLibName ); + /** + * Adds an already existing sub-library to the library + * @param path The path for the sub library + * @param subLibName The name of the sub library + * @return PMLibraryHandle::Ok if successful or the reason of failure + */ + PMLibraryHandle::PMResult addSubLibrary( const QString& path, const QString& name ); + /** + * Deletes a sub library. Only removes the entry from the library + * doesn't delete the objects file + * @param subLibName The name of the sub library ( or sub libraries path ) to delete + * @return PMLibraryHandle::Ok if successul or the reason of failure + */ + PMLibraryHandle::PMResult deleteSubLibrary( const QString& subLibName ); + + /** + * Returns true if the library is set read-only + */ + bool isReadOnly( ) const { return m_readOnly; } + + /** + * Returns an object iterator. It has to be deleted afterwards. + */ + PMLibraryHandle::EntryIterator* createObjectIterator( ); + + /** + * Returns a sub-library iterator. It has to be deleted afterwards. + */ + PMLibraryHandle::EntryIterator* createSubLibraryIterator( ); + + /** + * Returns true if the library is a sub library. + */ + bool isSubLibrary( ) const { return m_subLibrary; } + + /** + * Changes the parent library if this is a sub library + * @param parentPath The new parent path for this library + * @return PMLibraryHandle::Ok if successful or the reason for failure + */ + PMLibraryHandle::PMResult changeParentLibrary( const QString& parentPath ); + +private: + + /** + * Makes the library a sub library. + */ + void setSubLibrary( bool isSubLibrary ); + + + void loadLibraryInfo( ); + + QString m_name; + QString m_path; + QString m_author; + QString m_description; + bool m_readOnly; + bool m_subLibrary; + + QDict m_objects; + QDict m_libraries; +}; + +#endif diff --git a/kpovmodeler/pmlibraryhandleedit.cpp b/kpovmodeler/pmlibraryhandleedit.cpp new file mode 100644 index 00000000..8c26682d --- /dev/null +++ b/kpovmodeler/pmlibraryhandleedit.cpp @@ -0,0 +1,131 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Luis Carvalho + email : lpassos@oninetspeed.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#include "pmlibraryhandleedit.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "pmlineedits.h" +#include "pmdialogeditbase.h" +#include "pmlibraryhandle.h" + +QSize PMLibraryHandleEdit::s_size = QSize( 600, 400 ); + +PMLibraryHandleEdit::PMLibraryHandleEdit( PMLibraryHandle* lib, QWidget* parent, const char* name ) + : KDialogBase( parent, name, true, i18n( "Create Library" ), + Ok | Cancel, Ok ) +{ + m_pLibrary = lib; + + resize( s_size ); + QWidget* page = new QWidget( this ); + setMainWidget( page ); + QVBoxLayout* vl = new QVBoxLayout( page, KDialog::spacingHint( ) ); + + QGridLayout* grid = new QGridLayout( vl, 5, 2 ); + QLabel* lbl = new QLabel( i18n( "Name: " ), page ); + m_pNameEdit = new QLineEdit( page ); + grid->addWidget( lbl, 0, 0 ); + grid->addWidget( m_pNameEdit, 0, 1 ); + + lbl = new QLabel( i18n( "Author: " ), page ); + m_pAuthorEdit = new QLineEdit( page ); + grid->addWidget( lbl, 1, 0 ); + grid->addWidget( m_pAuthorEdit, 1, 1 ); + + lbl = new QLabel( i18n( "Description: " ), page ); + m_pDescriptionEdit = new QTextEdit( page ); + m_pDescriptionEdit->setMaximumHeight( 120 ); + grid->addWidget( lbl, 2, 0 ); + grid->addMultiCellWidget( m_pDescriptionEdit, 2, 3, 1, 1 ); + grid->setRowStretch( 3, 1 ); + + m_pReadOnlyEdit = new QCheckBox( i18n( "Allow changes to the library?" ), page ); + grid->addMultiCellWidget( m_pReadOnlyEdit, 4, 4, 0, 1 ); + + // Load the fields with values + m_pNameEdit->setText( lib->name( ) ); + m_pDescriptionEdit->setText( lib->description( ) ); + m_pAuthorEdit->setText( lib->author( ) ); + m_pReadOnlyEdit->setChecked( !lib->isReadOnly( ) ); + + // Setup the signals + connect( m_pNameEdit, SIGNAL( textChanged( const QString& ) ), SLOT( slotEditsChanged( const QString& ) ) ); + connect( m_pAuthorEdit, SIGNAL( textChanged( const QString& ) ), SLOT( slotEditsChanged( const QString& ) ) ); + connect( m_pDescriptionEdit, SIGNAL( textChanged( ) ), SLOT( slotDescriptionChanged( ) ) ); + connect( m_pReadOnlyEdit, SIGNAL( clicked( ) ), SLOT( slotReadOnlyChanged( ) ) ); + + // On startup you can only cancel + enableButtonOK( false ); +} + +void PMLibraryHandleEdit::slotReadOnlyChanged( ) +{ + enableButtonOK( true ); +} + +void PMLibraryHandleEdit::slotEditsChanged( const QString& /*str*/ ) +{ + enableButtonOK( true ); +} + +void PMLibraryHandleEdit::slotDescriptionChanged( ) +{ + enableButtonOK( true ); +} + +void PMLibraryHandleEdit::saveConfig( KConfig* cfg ) +{ + cfg->setGroup( "Appearance" ); + cfg->writeEntry( "LibraryHandleEditSize", s_size ); +} + +void PMLibraryHandleEdit::restoreConfig( KConfig* cfg ) +{ + cfg->setGroup( "Appearance" ); + + QSize defaultSize( 300, 200 ); + s_size = cfg->readSizeEntry( "LibraryHandleEditSize", &defaultSize ); +} + +void PMLibraryHandleEdit::resizeEvent( QResizeEvent* ev ) +{ + s_size = ev->size( ); +} + +void PMLibraryHandleEdit::slotOk( ) +{ + m_pLibrary->setName( m_pNameEdit->text( ) ); + m_pLibrary->setAuthor( m_pAuthorEdit->text( ) ); + m_pLibrary->setDescription( m_pDescriptionEdit->text( ) ); + m_pLibrary->setReadOnly( !m_pReadOnlyEdit->isChecked( ) ); + + accept( ); +} + +#include "pmlibraryhandleedit.moc" diff --git a/kpovmodeler/pmlibraryhandleedit.h b/kpovmodeler/pmlibraryhandleedit.h new file mode 100644 index 00000000..d0f53bb2 --- /dev/null +++ b/kpovmodeler/pmlibraryhandleedit.h @@ -0,0 +1,66 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Luis Carvalho + email : lpassos@oninetspeed.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#ifndef PMLIBRARYHANDLEEDIT_H +#define PMLIBRARYHANDLEEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +class QLineEdit; +class QTextEdit; +class QListBox; +class QCheckBox; +class PMLibraryHandle; + +/** + * This class provides a dialog to edit the definitions of a library. + */ +class PMLibraryHandleEdit: public KDialogBase +{ + Q_OBJECT +public: + /** + * Construct a dialog to edit the properties of lib. The library will be + * modified only if Ok is pressed. + */ + PMLibraryHandleEdit( PMLibraryHandle* lib, QWidget *parent = NULL, const char* name = NULL ); + + static void saveConfig( KConfig* cfg ); + static void restoreConfig( KConfig* cfg ); + static QSize s_size; + +private slots: + void slotOk( ); + void slotEditsChanged( const QString& ); + void slotDescriptionChanged( ); + void slotReadOnlyChanged( ); + void resizeEvent( QResizeEvent *ev ); + +private: + PMLibraryHandle* m_pLibrary; + QLineEdit* m_pNameEdit; + QLineEdit* m_pAuthorEdit; + QTextEdit* m_pDescriptionEdit; + QCheckBox* m_pReadOnlyEdit; +}; + +#endif diff --git a/kpovmodeler/pmlibraryiconview.cpp b/kpovmodeler/pmlibraryiconview.cpp new file mode 100644 index 00000000..9a59fcda --- /dev/null +++ b/kpovmodeler/pmlibraryiconview.cpp @@ -0,0 +1,328 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Luis Carvalho + email : lpassos@oninetspeed.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#include "pmlibraryiconview.h" + +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include "pmlibraryhandle.h" +#include "pmlibraryobject.h" +#include "pmdebug.h" + +const char* PMLibraryIconDrag::format( int i ) const +{ + switch( i ) + { + case 0: + return "application/x-qiconlist"; + break; + case 1: + return "text/sublib-list"; + break; + default: + return 0; + break; + } +} + +QByteArray PMLibraryIconDrag::encodedData( const char* mime ) const +{ + QByteArray a; + if ( QString( mime ) == "application/x-qiconlist" ) + a = QIconDrag::encodedData( mime ); + else if ( QString( mime ) == "text/sublib-list" ) + { + QString s , l; + for( unsigned i = 0; i < m_paths.count( ); ++i ) + { + if( m_subLibs[i] ) + l = "true"; + else + l = "false"; + s += m_paths[i] + "\r" + l + "\n"; + } + a.resize( s.length( ) ); + memcpy( a.data( ), s.latin1( ), s.length( ) ); + } + return a; +} + +bool PMLibraryIconDrag::canDecode( QMimeSource* e ) +{ + return e->provides( "application/x-qiconlist" ) || + e->provides( "text/sublib-list" ); +} + +bool PMLibraryIconDrag::decode( QMimeSource* e, QStringList& strList, QValueList& subLibList ) +{ + QByteArray a = e->encodedData( "text/sublib-list" ); + if( a.isEmpty( ) ) + return false; + + QStringList list = QStringList::split( "\n", QString( a ) ); + for( unsigned i = 0; i < list.count( ); ++i ) + { + strList.append( list[i].section( "\r", 0, 0 ) ); + if( list[i].section( "\r", 1, 1 ) == "true" ) + subLibList.append( true ); + else + subLibList.append( false ); + } + return true; +} + +void PMLibraryIconDrag::append( const QIconDragItem &item, const QRect &pr, + const QRect &tr, const QString &path, bool isSubLibrary ) +{ + QIconDrag::append( item, pr, tr ); + m_paths << path; + m_subLibs.append( isSubLibrary ); +} + +PMLibraryIconView::PMLibraryIconView( QWidget* parent, const char* name ) + : KIconView( parent, name ) +{ + m_pLibrary = NULL; + m_pCurrentLibrary = NULL; + setSelectionMode( Single ); + setMode( Execute ); +} + +void PMLibraryIconView::setLibrary( PMLibraryHandle* h ) +{ + m_pLibrary = h; + refresh( ); +} + +void PMLibraryIconView::refresh( ) +{ + // Clear all the icons + clear( ); + + PMLibraryHandle::EntryIterator* it; + + // Scan all the library objects and load them into the view + // First let's add the libraries + it = m_pLibrary->createSubLibraryIterator( ); + for( ; it->current( ); ++(*it) ) + { + QString f_name = *( it->current( ) ); + PMLibraryHandle h( f_name ); + + new PMLibraryIconViewItem( this, h.name( ), f_name, true ); + } + delete it; + + // Then the objects + it = m_pLibrary->createObjectIterator( ); + for( ; it->current( ); ++(*it) ) + { + QString f_name = *( it->current( ) ); + PMLibraryObject obj( f_name ); + + if( obj.preview( ) ) + new PMLibraryIconViewItem( this, obj.name( ), obj.preview( )->copy( ), f_name, false ); + else + new PMLibraryIconViewItem( this, obj.name( ), f_name, false ); + } + delete it; +} + +void PMLibraryIconView::slotDropped( QDropEvent *e, const QValueList & ) +{ + e->ignore( ); +} + +QDragObject* PMLibraryIconView::dragObject( ) +{ + if ( !currentItem( ) ) + return 0; + + QPoint orig = viewportToContents( viewport( )->mapFromGlobal( QCursor::pos( ) ) ); + PMLibraryIconDrag *drag = new PMLibraryIconDrag( viewport( ) ); + drag->setPixmap( *currentItem( )->pixmap( ), + QPoint( currentItem( )->pixmapRect( ).width( ) / 2, + currentItem( )->pixmapRect( ).height( ) / 2 ) ); + + for ( PMLibraryIconViewItem *item = (PMLibraryIconViewItem*)firstItem( ); + item; item = ( PMLibraryIconViewItem* )item->nextItem( ) ) + { + if ( item->isSelected( ) ) + { + QIconDragItem id; + id.setData( QCString( item->path( ).latin1( ) ) ); + drag->append( id, + QRect( item->pixmapRect( FALSE ).x( ) - orig.x( ), + item->pixmapRect( FALSE ).y( ) - orig.y( ), + item->pixmapRect( ).width( ), + item->pixmapRect( ).height( ) ), + QRect( item->textRect( FALSE ).x( ) - orig.x( ), + item->textRect( FALSE ).y( ) - orig.y( ), + item->textRect().width( ), + item->textRect( ).height( ) ), + item->path( ), + item->isSubLibrary( ) ); + } + } + return drag; +} + +PMLibraryIconViewItem::PMLibraryIconViewItem( QIconView *parent, const QString &text, const QString& path, bool isSubLibrary ) + : KIconViewItem( parent, text ) +{ + m_path = path; + m_isSubLibrary = isSubLibrary; +} + +PMLibraryIconViewItem::PMLibraryIconViewItem( QIconView *parent, const QString &text, const QImage& image, const QString& path, bool isSubLibrary ) + : KIconViewItem( parent, text, image ) +{ + m_path = path; + m_isSubLibrary = isSubLibrary; +} + +bool PMLibraryIconViewItem::acceptDrop( const QMimeSource *e ) const +{ + if ( m_isSubLibrary && e->provides( "text/sublib-list" ) ) + return true; + + return false; +} + +void PMLibraryIconViewItem::dropped( QDropEvent *e, const QValueList & ) +{ + QStringList pathList; + QValueList subLibList; + if( m_isSubLibrary && PMLibraryIconDrag::decode( e, pathList, subLibList ) ) + { + PMLibraryIconView* source = static_cast( e->source( )->parentWidget( ) ); + PMLibraryHandle* parentLib = source->library( ); + PMLibraryHandle newParentLib = PMLibraryHandle( m_path ); + if ( parentLib->isReadOnly() || newParentLib.isReadOnly() ) + { + e->ignore(); + return; + } + + for( unsigned i = 0; i < pathList.count( ); ++i ) + { + bool success = true; + QString path = pathList[i]; + if( path != ( m_path +"/" + path.section( '/', -1 ) ) ) + { + if( subLibList[i] ) + { + QString newpath = newPath( path, true ); + if( parentLib->deleteSubLibrary( path ) == PMLibraryHandle::Ok ) + { + PMLibraryHandle lib = PMLibraryHandle( path ); + if( newParentLib.addSubLibrary( newpath, lib.name() ) == PMLibraryHandle::Ok ) + { + lib.changeParentLibrary( m_path ); + KIO::move( path, newpath ); + } + else + { + success = false; + parentLib->addSubLibrary( path, lib.name( ) ); + } + } + else + success = false; + } + else + { + QString newpath = newPath( path, false ); + if( parentLib->deleteObject( path ) == PMLibraryHandle::Ok ) + { + PMLibraryObject obj = PMLibraryObject( path ); + if( newParentLib.addObject( newpath, obj.name() ) == PMLibraryHandle::Ok ) + { + KIO::move( path, newpath ); + } + else + { + success = false; + parentLib->addObject( path, obj.name( ) ); + } + } + else + success = false; + } + + if( !success ) + { + KMessageBox::error( 0, i18n( "Error moving \"%1\" to \"%2\"" ).arg( path ).arg( m_path ) ); + e->ignore( ); + return; + } + } + } + e->acceptAction( ); + source->refresh( ); + } + else + { + e->ignore( ); + } +} + +QString PMLibraryIconViewItem::newPath( const QString oldPath, bool /*subLib*/ ) +{ + /// @todo Need to replace mkdtemp and mkstemps before enabling libs + return oldPath; + /* + QString path = m_path + "/" + oldPath.section( '/', -1 ); + if( subLib ) + { + QString test = path + "/library_index.xml"; + if( QFile::exists( test ) ) + { + QCString s = m_path.latin1(); + s+= "/libXXXXXX"; + char* dirname = mkdtemp( s.data() ); + rmdir( dirname ); + path = dirname; + } + } + else if( QFile::exists( path ) ) + { + // we need to rename it. + QCString s = m_path.latin1(); + s += "/objXXXXXX.kpml"; + int fh = mkstemps( s.data( ), 5 ); + close( fh ); + unlink( s.data() ); + path = s; + } + + return path; + */ +} + +#include "pmlibraryiconview.moc" diff --git a/kpovmodeler/pmlibraryiconview.h b/kpovmodeler/pmlibraryiconview.h new file mode 100644 index 00000000..a30ef529 --- /dev/null +++ b/kpovmodeler/pmlibraryiconview.h @@ -0,0 +1,123 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Luis Carvalho + email : lpassos@oninetspeed.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#ifndef PMLIBRARYICONVIEW_H +#define PMLIBRARYICONVIEW_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +class PMLibraryHandle; + +/** + * This class is the drag and drop object for the icon view + */ +class PMLibraryIconDrag : public QIconDrag +{ + Q_OBJECT +public: + /** Constructor */ + PMLibraryIconDrag( QWidget * dragSource, const char* name = 0 ) : QIconDrag( dragSource, name ) {} + + /** @return The ith format, or NULL. */ + const char* format( int i ) const; + /** @return The encoded payload of this object, in the specified MIME format. */ + QByteArray encodedData( const char* mime ) const; + /** @return True if the information in e can be decoded */ + static bool canDecode( QMimeSource* e ); + /** + * Attempts to decode the data in e + * @return True if successful otherwise returns false + */ + static bool decode( QMimeSource* e, QStringList& StrList, QValueList& subLibList ); + /** Adds a item to the object */ + void append( const QIconDragItem &item, const QRect &pr, const QRect &tr, const QString &path, bool subLib ); + +private: + QStringList m_paths; + QValueList m_subLibs; +}; + +/** + * This class provides a view to browse objects, showing their previews. + */ +class PMLibraryIconView: public KIconView +{ + Q_OBJECT +public: + PMLibraryIconView( QWidget *parent, const char* name = NULL ); + + /** + * Set the library base path + */ + void setLibrary( PMLibraryHandle* h ); + /** + * Returns the library in view + */ + PMLibraryHandle* library( ) const { return m_pLibrary; } + +public slots: + /** + * refresh the icon view + */ + void refresh( ); + + /** called when an Item is dropped onto the view */ + void slotDropped( QDropEvent *e, const QValueList& ); + +protected: + /** @return a QDragObject for drag and drop */ + virtual QDragObject* dragObject( ); + +private: + PMLibraryHandle *m_pLibrary; + PMLibraryHandle *m_pCurrentLibrary; +}; + +/** + * This class holds a library object's icon. It also remembers the path + * where the file is. + */ +class PMLibraryIconViewItem: public KIconViewItem +{ +public: + PMLibraryIconViewItem( QIconView *parent, const QString& text, const QString& path, bool isSubLibrary ); + PMLibraryIconViewItem( QIconView *parent, const QString& text, const QImage& image, const QString& path, bool isSubLibrary ); + + /** Get the path of the entry */ + QString path( ) const { return m_path; } + /** Is the entry a sublib library? */ + bool isSubLibrary( ) const { return m_isSubLibrary; } + /** Reimplement accept drop to take items */ + virtual bool acceptDrop( const QMimeSource *mime ) const; + +protected: + /** Tokes a dropped item */ + void dropped( QDropEvent *evt, const QValueList& ); + /** Checks for the existance of oldpath and generates a new path as required */ + QString newPath( const QString oldPath, bool subLib ); + +private: + QString m_path; + bool m_isSubLibrary; +}; + +#endif diff --git a/kpovmodeler/pmlibrarymanager.cpp b/kpovmodeler/pmlibrarymanager.cpp new file mode 100644 index 00000000..2caeb6e3 --- /dev/null +++ b/kpovmodeler/pmlibrarymanager.cpp @@ -0,0 +1,121 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Luis Carvalho + email : lpassos@oninetspeed.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#include "pmlibrarymanager.h" + +#include +#include +#include + +#include +#include + +#include "pmdebug.h" + +PMLibraryManager* PMLibraryManager::s_pInstance = 0; +KStaticDeleter PMLibraryManager::s_staticDeleter; + +PMLibraryHandle* PMLibraryManager::getLibraryHandle( const QString& libraryName ) +{ + QPtrListIterator it( m_libraries ); + + for( ; it.current( ); ++it ) + if( it.current( )->name( ) == libraryName ) + return it.current( ); + + return NULL; +} + +PMLibraryManager::PMLibraryManager( ) +{ + m_libraries.setAutoDelete( true ); + scanLibraries( ); +} + +PMLibraryManager::~PMLibraryManager( ) +{ + m_libraries.clear( ); +} + +void PMLibraryManager::saveConfig( KConfig* /*cfg*/ ) +{ +} + +void PMLibraryManager::restoreConfig( KConfig* /*cfg*/ ) +{ +} + +QValueList PMLibraryManager::availableLibraries( ) +{ + QValueList result; + QPtrListIterator it( m_libraries ); + + for( ; it.current( ); ++it ) + result.push_back( it.current( )->name( ) ); + + return result; +} + +PMLibraryManager* PMLibraryManager::theManager( ) +{ + if( !s_pInstance ) + s_staticDeleter.setObject( s_pInstance, new PMLibraryManager( ) ); + return s_pInstance; +} + +void PMLibraryManager::scanLibraries( ) +{ + QStringList libraryDirectories; + + // Search for sub directories in /usr/share/kpovmodeler/library + libraryDirectories = KGlobal::dirs( )->findDirs( "data", "kpovmodeler/library" ); + + for( QStringList::Iterator i = libraryDirectories.begin( ); i != libraryDirectories.end( ); ++i ) + { + QDir curDir( *i ); + curDir.setFilter( QDir::Dirs ); + QFileInfoListIterator it( *( curDir.entryInfoList( ) ) ); + + // For each sub directory + QFileInfo* fi; + for( ; ( fi = it.current( ) ) != NULL; ++it ) + { + // check for the existance of library_index.xml + // If it's there it's a library + if( QFile::exists( fi->absFilePath( ) + "/library_index.xml" ) ) + { + // Create the corresponding PMLibraryHandle + PMLibraryHandle* h; + + h = new PMLibraryHandle( fi->absFilePath( ) ); + if( !getLibraryHandle( h->name( ) ) ) + m_libraries.append( h ); + else + // a library with that name already exists + delete h; + } + } + } +} + +void PMLibraryManager::refresh( ) +{ + // TODO: Manage the list incrementaly so that previouly handed out + // PMLibraryHandle pointers are kept valid + m_libraries.clear( ); + scanLibraries( ); +} diff --git a/kpovmodeler/pmlibrarymanager.h b/kpovmodeler/pmlibrarymanager.h new file mode 100644 index 00000000..8221ba19 --- /dev/null +++ b/kpovmodeler/pmlibrarymanager.h @@ -0,0 +1,97 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Luis Carvalho + email : lpassos@oninetspeed.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#ifndef PMLIBRARYMANAGER_H +#define PMLIBRARYMANAGER_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "pmlibraryhandle.h" + +class KConfig; +class QDomElement; + +/** + * Class that maintains the list of available libraries for kpovmodeler + * + * This class is a singleton, wich means all libraries will be known to + * all instances of the application. + * + * When the class is initialized, the following steps are taken: + * 1. The global kpovmodeler library path is scanned for libraries + * 2. The users' kpovmodeler library path is also scanned for libraries + * + * If more than one library has the same name, only the last one will be + * accessible. + */ +class PMLibraryManager +{ + +public: + /** + * Destructor + */ + ~PMLibraryManager( ); + /** + * Returns the manager instance (singleton) + */ + static PMLibraryManager* theManager( ); + + /** + * Returns the list of available libraries + */ + QValueList availableLibraries( ); + + /** + * Returns the handle for the indicated library + */ + PMLibraryHandle* getLibraryHandle( const QString& libraryName ); + + /** + * Refreshes the list of libraries. + * WARNING: This function invalidates all previously given PMLibraryHandle pointers + */ + void refresh( ); + + void saveConfig( KConfig* cfg ); + void restoreConfig( KConfig* cfg ); + +private: + + /** + * Constructor + */ + PMLibraryManager( ); + + void scanLibraries( ); + + QPtrList< PMLibraryHandle > m_libraries; + + static PMLibraryManager* s_pInstance; + static KStaticDeleter s_staticDeleter; +}; + +#endif diff --git a/kpovmodeler/pmlibraryobject.cpp b/kpovmodeler/pmlibraryobject.cpp new file mode 100644 index 00000000..e84ba9e1 --- /dev/null +++ b/kpovmodeler/pmlibraryobject.cpp @@ -0,0 +1,331 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#include "pmlibraryobject.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "pmdebug.h" + +PMLibraryObject::PMLibraryObject( ) +{ + m_previewLoaded = false; + m_objectsLoaded = false; + m_preview = NULL; + m_objects = NULL; + m_data = NULL; + m_name = QString::null; + m_description = QString::null; + m_keywords = QString::null; +} + +PMLibraryObject::PMLibraryObject( KURL u ) +{ + m_previewLoaded = false; + m_objectsLoaded = false; + m_preview = NULL; + m_objects = NULL; + m_data = new KTar( u.path( ), "application/x-gzip" ); + loadLibraryInfo( ); +} + +PMLibraryObject::~PMLibraryObject( ) +{ + delete m_data; + if( m_previewLoaded ) + delete m_preview; + if( m_objectsLoaded ) + delete m_objects; +} + +void PMLibraryObject::loadLibraryInfo( ) +{ + if( m_data ) + { + m_data->open( IO_ReadOnly ); + // Position in the root of the file + const KArchiveDirectory* root = m_data->directory( ); + if( !root ) + return; + + // Find the object info + const KArchiveEntry* entry = root->entry( "objectinfo.xml" ); + if( entry && entry->isFile( ) ) + { + QBuffer buffer( ( ( KArchiveFile* )entry )->data( ) ); + buffer.open( IO_ReadOnly ); + + QDomDocument doc( "OBJECTINFO" ); + doc.setContent( &buffer ); + + QDomElement e = doc.documentElement( ); + m_name = e.attribute( "name", "empty" ); + + QDomNode c = e.firstChild( ); + while( !c.isNull( ) ) + { + if( c.isElement( ) ) + { + QDomElement ce = c.toElement( ); + // Description information + if( ce.tagName( ) == "description" ) + { + QDomText te = ce.firstChild( ).toText( ); + m_description = te.nodeValue( ); + } + // Keywords information + else if( ce.tagName( ) == "keywords" ) + { + QDomText te = ce.firstChild( ).toText( ); + m_keywords = te.nodeValue( ); + } + // Extra files list + else if( ce.tagName( ) == "file_entries" ) + { + QDomNode entry = ce.firstChild( ); + while( !entry.isNull( ) ) + { + QDomElement entryElement = entry.toElement( ); + if( entryElement.tagName( ) == "file" ) + m_extraFiles.append( entryElement.attribute( "name", "" ) ); + entry = entry.nextSibling( ); + } + } + } + c = c.nextSibling( ); + } + } + m_data->close( ); + } +} + +QImage* PMLibraryObject::preview( ) +{ + if( !m_previewLoaded ) + { + if( m_data ) + { + m_data->open( IO_ReadOnly ); + // Position in the root of the file + const KArchiveDirectory* root = m_data->directory( ); + if( !root ) + return NULL; + + // Find the object preview + const KArchiveEntry* entry = root->entry( "preview.png" ); + if( entry && entry->isFile( ) ) + { + QBuffer buffer( ( ( KArchiveFile* )entry )->data( ) ); + buffer.open( IO_ReadOnly ); + m_preview = new QImage( buffer.readAll( ) ); + m_previewLoaded = true; + } + + m_data->close( ); + } + } + return m_preview; +} + +QByteArray* PMLibraryObject::objects( ) +{ + if( !m_objectsLoaded ) + { + if( m_data ) + { + m_data->open( IO_ReadOnly ); + // Position in the root of the file + const KArchiveDirectory* root = m_data->directory( ); + if( !root ) + return NULL; + + // Find the object info + const KArchiveEntry* entry = root->entry( "objectdata.kpm" ); + if( entry && entry->isFile( ) ) + { + // Transfer the file contents to a QByteArray. + // TODO Maybe there is a smarter way of doing this. + char buf[256]; + int nbytes; + QIODevice* aux_in = ( ( KArchiveFile* )entry )->device( ); + + m_objects = new QByteArray( ); + QBuffer aux_out( *m_objects ); + + aux_in->open( IO_ReadOnly ); + aux_out.open( IO_WriteOnly ); + while( !aux_in->atEnd( ) ) + { + nbytes = aux_in->readBlock( buf, 256 ); + aux_out.writeBlock( buf, nbytes ); + } + delete aux_in; + if( m_objects->size( ) != 0 ) + m_objectsLoaded = true; + else + { + delete m_objects; + m_objects = NULL; + } + } + } + } + return m_objects; +} + +void PMLibraryObject::setName( const QString& str ) +{ + m_name = str; +} + +void PMLibraryObject::setDescription( const QString& str ) +{ + m_description = str; +} + +void PMLibraryObject::setKeywords( const QString& str ) +{ + m_keywords = str; +} + +void PMLibraryObject::setPreview( const QImage& img ) +{ + if( m_previewLoaded ) + delete m_preview; + + m_preview = new QImage( img ); + m_previewLoaded = true; +} + +void PMLibraryObject::setObjects( const QByteArray& obj ) +{ + if( m_objectsLoaded ) + delete m_objects; + + m_objects = new QByteArray( obj ); + m_objects->detach( ); + m_objectsLoaded = true; +} + +void PMLibraryObject::save( const QString& fileName ) +{ + // create the library file + m_data = new KTar( fileName, "application/x-gzip" ); + m_data->open( IO_WriteOnly ); + // save object info + saveLibraryInfo( ); + // save preview + savePreview( ); + // save library objects + saveObjects( ); + m_data->close( ); +} + +void PMLibraryObject::saveLibraryInfo( ) +{ + // Pre-condition for the execution of this method. + if( !m_data || !m_data->isOpened( ) ) + { + kdError( PMArea ) << "Trying to save to an unopened data file." << endl; + exit( 1 ); + } + + QBuffer buf; + + // Document type + QDomDocument doc( "OBJECTINFO" ); + + // The root element for the document has one attribute: name + QDomElement root = doc.createElement( "object" ); + doc.appendChild( root ); + root.setAttribute( "name", m_name ); + + // Inside the root element we add the description node ... + QDomElement description = doc.createElement( "description" ); + root.appendChild( description ); + description.appendChild( doc.createTextNode( m_description ) ); + + // ... and the keywords node ... + QDomElement keywords = doc.createElement( "keywords" ); + root.appendChild( keywords ); + keywords.appendChild( doc.createTextNode( m_keywords ) ); + + // ... and finally the extra files information + QDomElement file_list = doc.createElement( "file_list" ); + root.appendChild( file_list ); + QStringList::Iterator it = m_extraFiles.begin( ); + for( ; it != m_extraFiles.end( ); ++it ) + { + QDomElement entry = doc.createElement( "file" ); + entry.setAttribute( "name", *it ); + file_list.appendChild( entry ); + } + + // Write the document to the buffer + QByteArray array; + QTextStream str( array, IO_WriteOnly ); + str.setEncoding( QTextStream::UnicodeUTF8 ); + str << doc.toString( ); + m_data->writeFile( "objectinfo.xml", "user", "group", array.size( ), array.data( ) ); +} + +void PMLibraryObject::savePreview( ) +{ + // Pre-condition for the execution of this method. + if( !m_data || !m_data->isOpened( ) ) + { + kdError( PMArea ) << "Trying to save to an unopened data file." << endl; + exit( 1 ); + } + + QByteArray array; + QBuffer iods( array ); + QImageIO img_io( &iods, "PNG" ); + + if( m_previewLoaded ) + { + img_io.setImage( *m_preview ); + iods.open( IO_WriteOnly ); + img_io.write( ); + m_data->writeFile( "preview.png", "user", "group", array.size( ), array.data( ) ); + } +} + +void PMLibraryObject::saveObjects( ) +{ + // Pre-condition for the execution of this method. + if( !m_data || !m_data->isOpened( ) ) + { + kdError( PMArea ) << "Trying to save to an unopened data file." << endl; + exit( 1 ); + } + + if( m_objectsLoaded ) + m_data->writeFile( "objectdata.kpm", "user", "group", m_objects->size( ), m_objects->data( ) ); +} diff --git a/kpovmodeler/pmlibraryobject.h b/kpovmodeler/pmlibraryobject.h new file mode 100644 index 00000000..e3699c8f --- /dev/null +++ b/kpovmodeler/pmlibraryobject.h @@ -0,0 +1,136 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#ifndef PMLIBRARYOBJECT_H +#define PMLIBRARYOBJECT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +class KURL; +class KArchive; +class KTar; +class QImage; + +/** + * This class implements a library object. + * + * A library object has a name, a textual description, a graphical + * preview and the object data, of course. It also contains a collection of + * keywords. + * + * When an instance of PMLibraryObject is created, the objects description is + * loaded. + * + * The graphical preview and the objects data are loaded only if needed. + * + */ +class PMLibraryObject +{ +public: + /** + * Constructor for the library object. Creates an empty library object. + */ + PMLibraryObject( ); + /** + * Constructor for the library object. + * Loads the object data from the specified library object file. + */ + PMLibraryObject( KURL u ); + /** + * Destructor + */ + ~PMLibraryObject( ); + + /** + * Name of the library object. + */ + QString name( ) const { return m_name; } + /** + * Textual description of the library object. + */ + QString description( ) const { return m_description; } + /** + * List of keywords for search of the library object. + */ + QString keywords( ) const { return m_keywords; } + /** + * Graphical Preview. + */ + QImage* preview( ); + /** + * True is the preview has been loaded. + */ + bool isPreviewLoaded( ) const { return m_previewLoaded; } + /** + * Objects for the scene + */ + QByteArray* objects( ); + bool areObjectsLoaded( ) const { return m_objectsLoaded; } + + /** + * Set the library object name + */ + void setName( const QString& str ); + /** + * Set the library object description + */ + void setDescription( const QString& str ); + /** + * Set the library object keywords + */ + void setKeywords( const QString& str ); + /** + * Set the preview image + */ + void setPreview( const QImage& img ); + /** + * Set the object data + */ + void setObjects( const QByteArray& obj ); + + /** + * Save the library object to a file + */ + void save( const QString& fileName ); + +private: + void loadLibraryInfo( ); + void saveLibraryInfo( ); + void savePreview( ); + void saveObjects( ); + + bool m_previewLoaded; + bool m_objectsLoaded; + QString m_name; + QString m_description; + QString m_keywords; + KTar* m_data; + QImage* m_preview; + QByteArray* m_objects; + QStringList m_extraFiles; +}; + +#endif diff --git a/kpovmodeler/pmlibraryobjectsearch.cpp b/kpovmodeler/pmlibraryobjectsearch.cpp new file mode 100644 index 00000000..428da887 --- /dev/null +++ b/kpovmodeler/pmlibraryobjectsearch.cpp @@ -0,0 +1,86 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmlibraryobject.h" +#include "pmlibraryentrypreview.h" +#include "pmlibraryobjectsearch.h" +#include "pmdialogeditbase.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +PMLibraryObjectSearch::PMLibraryObjectSearch( QWidget* parent ) : + QWidget( parent, "" ) +{ + setMinimumSize( 780, 300 ); + setMaximumSize( 800, 400 ); + QVBoxLayout* vl = new QVBoxLayout( this, KDialog::spacingHint( ) ); + + // Search parameters + QFrame* frame = new QFrame( this ); + QHBoxLayout* fhl = new QHBoxLayout( frame, KDialog::spacingHint( ) ); + QGridLayout* grid = new QGridLayout( fhl, 3, 2 ); + QLabel *lbl = new QLabel( i18n( "Search for:" ), frame ); + m_pSearch = new QLineEdit( frame ); + grid->addWidget( lbl, 0, 0 ); + grid->addWidget( m_pSearch, 0, 1 ); + + QVBoxLayout* fvl = new QVBoxLayout( fhl ); + m_pSearchButton = new QPushButton( i18n( "&Search" ), frame ); + fvl->addWidget( m_pSearchButton ); + fvl->addStretch( 1 ); + + vl->addWidget( frame ); + + // Search results + frame = new QFrame( this ); + QHBoxLayout* hl = new QHBoxLayout( frame, KDialog::spacingHint( ) ); + m_pFileList = new KListView( frame ); + m_pFileList->addColumn( i18n( "File" ) ); + m_pFileList->addColumn( i18n( "Path" ) ); + m_pFileList->setFullWidth( true ); + m_pPreview = new PMLibraryEntryPreview( frame ); + hl->addWidget( m_pFileList, 1 ); + hl->addWidget( m_pPreview ); + vl->addWidget( frame ); + + // Connect signals and slots + connect( m_pSearchButton, SIGNAL( clicked( ) ), SLOT( slotSearchButtonPressed( ) ) ); +} + +void PMLibraryObjectSearch::slotSearchButtonPressed( ) +{ +// QStringList::Iterator it( s_libraryPath ); + // For each of the defined libraries + // + // Open recursively each library file + // Check if any of the strings contains the search words + // If it does add to the list +} + +#include "pmlibraryobjectsearch.moc" diff --git a/kpovmodeler/pmlibraryobjectsearch.h b/kpovmodeler/pmlibraryobjectsearch.h new file mode 100644 index 00000000..2ef5b07a --- /dev/null +++ b/kpovmodeler/pmlibraryobjectsearch.h @@ -0,0 +1,55 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#ifndef PMLIBRARYOBJECTSEARCH_H +#define PMLIBRARYOBJECTSEARCH_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +class QLineEdit; +class QListBox; +class QPushButton; +class PMLibraryEntryPreview; +class KListView; + +/** + * Search widget for Library Objects. + * It also provides drag. If the user doesn't have a clear idea + * where the objects he wants are, this is the dialog to use. + */ +class PMLibraryObjectSearch: public QWidget +{ + Q_OBJECT +public: + PMLibraryObjectSearch( QWidget *parent ); + +private slots: + void slotSearchButtonPressed( ); + +private: + QLineEdit* m_pSearch; + QPushButton* m_pSearchButton; + KListView* m_pFileList; + PMLibraryEntryPreview* m_pPreview; +}; + +#endif diff --git a/kpovmodeler/pmlight.cpp b/kpovmodeler/pmlight.cpp new file mode 100644 index 00000000..b715c7ee --- /dev/null +++ b/kpovmodeler/pmlight.cpp @@ -0,0 +1,1064 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmlight.h" + +#include "pmxmlhelper.h" +#include "pmlightedit.h" +#include "pmmemento.h" +#include "pmviewstructure.h" +#include "pm3dcontrolpoint.h" +#include "pmmath.h" +#include "pmmatrix.h" +#include "pmenumproperty.h" + +#include + +const PMVector locationDefault = PMVector( 0, 0, 0 ); +const PMColor colorDefault = PMColor( 1.0, 1.0, 1.0 ); +const double radiusDefault = 70.0; +const double falloffDefault = 70.0; +const double tightnessDefault = 10; +const PMVector pointAtDefault = PMVector( 0, 0, 1 ); +const bool parallelDefault = false; +const PMVector areaAxis1Default = PMVector( 1, 0, 0 ); +const PMVector areaAxis2Default = PMVector( 0, 1, 0 ); +const int areaSize1Default = 3; +const int areaSize2Default = 3; +const int adaptiveDefault = 0; +const bool orientDefault = false; +const bool jitterDefault = false; +const int fadePowerDefault = 1; +const double fadeDistanceDefault = 10.0; + +PMViewStructure* PMLight::s_pDefaultPointStructure = 0; +PMViewStructure* PMLight::s_pDefaultSpotStructure = 0; +PMViewStructure* PMLight::s_pDefaultCylindricalStructure = 0; +double PMLight::s_pointLightSize = 0.25; +int PMLight::s_nCylinderLines = 8; +int PMLight::s_nSpotLines = 8; +double PMLight::s_length = 1.0; + +PMDefinePropertyClass( PMLight, PMLightProperty ); +PMDefineEnumPropertyClass( PMLight, PMLight::PMLightType, PMTypeProperty ); +PMDefineEnumPropertyClass( PMLight, PMLight::PMAreaType, PMAreaProperty ); + +PMMetaObject* PMLight::s_pMetaObject = 0; +PMObject* createNewLight( PMPart* part ) +{ + return new PMLight( part ); +} + +PMLight::PMLight( PMPart* part ) + : Base( part ) +{ + m_location = locationDefault; + m_color = colorDefault; + m_type = PointLight; + m_radius = radiusDefault; + m_falloff = falloffDefault; + m_tightness = tightnessDefault; + m_pointAt = pointAtDefault; + m_parallel = parallelDefault; + m_bAreaLight = false; + m_areaType = Rectangular; + m_areaAxis1 = areaAxis1Default; + m_areaAxis2 = areaAxis2Default; + m_areaSize1 = areaSize1Default; + m_areaSize2 = areaSize2Default; + m_adaptive = adaptiveDefault; + m_orient = orientDefault; + m_jitter = jitterDefault; + m_bFading = false; + m_fadeDistance = fadeDistanceDefault; + m_fadePower = fadePowerDefault; + m_bMediaInteraction = true; + m_bMediaAttenuation = true; +} + +PMLight::PMLight( const PMLight& l ) + : Base( l ) +{ + m_location = l.m_location; + m_color = l.m_color; + m_type = l.m_type; + m_radius = l.m_radius; + m_falloff = l.m_falloff; + m_tightness = l.m_tightness; + m_pointAt = l.m_pointAt; + m_parallel = l.m_parallel; + m_bAreaLight = l.m_bAreaLight; + m_areaType = l.m_areaType; + m_areaAxis1 = l.m_areaAxis1; + m_areaAxis2 = l.m_areaAxis2; + m_areaSize1 = l.m_areaSize1; + m_areaSize2 = l.m_areaSize2; + m_adaptive = l.m_adaptive; + m_orient = l.m_orient; + m_jitter = l.m_jitter; + m_bFading = l.m_bFading; + m_fadeDistance = l.m_fadeDistance; + m_fadePower = l.m_fadePower; + m_bMediaInteraction = l.m_bMediaInteraction; + m_bMediaAttenuation = l.m_bMediaAttenuation; +} + +PMLight::~PMLight( ) +{ +} + +QString PMLight::description( ) const +{ + return i18n( "light" ); +} + +void PMLight::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "location", m_location.serializeXML( ) ); + e.setAttribute( "color", m_color.serializeXML( ) ); + + switch( m_type ) + { + case SpotLight: + e.setAttribute( "lighttype", "spotlight" ); + break; + case CylinderLight: + e.setAttribute( "lighttype", "cylinder" ); + break; + case ShadowlessLight: + e.setAttribute( "lighttype", "shadowless" ); + break; + case PointLight: + e.setAttribute( "lighttype", "point" ); + break; + } + + if( ( m_type == SpotLight ) || ( m_type == CylinderLight ) ) + { + e.setAttribute( "radius", m_radius ); + e.setAttribute( "falloff", m_falloff ); + e.setAttribute( "tightness", m_tightness ); + e.setAttribute( "point_at", m_pointAt.serializeXML( ) ); + } + + if ( m_parallel ) + e.setAttribute( "parallel", "1" ); + else + e.setAttribute( "parallel", "0" ); + + if( m_bAreaLight ) + { + if ( m_areaType == Rectangular ) + e.setAttribute( "areatype", "rectangular" ); + else + e.setAttribute( "areatype", "circular" ); + + e.setAttribute( "area_light", "1" ); + e.setAttribute( "area_light_a", m_areaAxis1.serializeXML( ) ); + e.setAttribute( "area_light_b", m_areaAxis2.serializeXML( ) ); + e.setAttribute( "area_size_a", m_areaSize1 ); + e.setAttribute( "area_size_b", m_areaSize2 ); + e.setAttribute( "adaptive", m_adaptive ); + + if( m_orient ) + e.setAttribute( "orient", "1" ); + else + e.setAttribute( "orient", "0" ); + + if( m_jitter ) + e.setAttribute( "jitter", "1" ); + else + e.setAttribute( "jitter", "0" ); + } + else + e.setAttribute( "area_light", "0" ); + + if( m_bFading ) + { + e.setAttribute( "fading", "1" ); + e.setAttribute( "fade_distance" , m_fadeDistance ); + e.setAttribute( "fade_power", m_fadePower ); + } + else + e.setAttribute( "fading", "0" ); + + if( m_bMediaInteraction ) + e.setAttribute( "media_interaction", "1" ); + else + e.setAttribute( "media_interaction", "0" ); + + if( m_bMediaAttenuation ) + e.setAttribute( "media_attenuation", "1" ); + else + e.setAttribute( "media_attenuation", "0" ); + + Base::serialize( e, doc ); +} + +void PMLight::readAttributes( const PMXMLHelper& h ) +{ + QString str; + + m_location = h.vectorAttribute( "location", locationDefault ); + m_color = h.colorAttribute( "color", colorDefault ); + + str = h.stringAttribute( "lighttype", "point" ); + if( str == "point" ) + m_type = PointLight; + else if( str == "spotlight" ) + m_type = SpotLight; + else if( str == "cylinder" ) + m_type = CylinderLight; + else if( str == "shadowless" ) + m_type = ShadowlessLight; + else + m_type = PointLight; + + if( ( m_type == SpotLight ) || ( m_type == CylinderLight ) ) + { + m_radius = h.doubleAttribute( "radius", radiusDefault ); + m_falloff = h.doubleAttribute( "falloff", falloffDefault ); + m_tightness = h.doubleAttribute( "tightness", tightnessDefault ); + m_pointAt = h.vectorAttribute( "point_at", pointAtDefault ); + } + + m_parallel = h.boolAttribute( "parallel", parallelDefault ); + + m_bAreaLight = h.boolAttribute( "area_light", false ); + if( m_bAreaLight ) + { + str = h.stringAttribute( "areatype", "rectangular" ); + if ( str == "circular" ) + m_areaType = Circular; + else + m_areaType = Rectangular; + + m_areaAxis1 = h.vectorAttribute( "area_light_a", areaAxis1Default ); + m_areaAxis2 = h.vectorAttribute( "area_light_b", areaAxis2Default ); + m_areaSize1 = h.intAttribute( "area_size_a", areaSize1Default ); + m_areaSize2 = h.intAttribute( "area_size_b", areaSize2Default ); + m_adaptive = h.intAttribute( "adaptive", adaptiveDefault ); + m_orient = h.boolAttribute( "orient", orientDefault ); + m_jitter = h.boolAttribute( "jitter", jitterDefault ); + } + m_bFading = h.boolAttribute( "fading", false ); + if( m_bFading ) + { + m_fadeDistance = h.doubleAttribute( "fade_distance", fadeDistanceDefault ); + m_fadePower = h.intAttribute( "fade_power", m_fadePower ); + } + m_bMediaInteraction = h.boolAttribute( "media_interaction", true ); + m_bMediaAttenuation = h.boolAttribute( "media_attenuation", true ); + + Base::readAttributes( h ); +} + +PMMetaObject* PMLight::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Light", Base::metaObject( ), + createNewLight ); + PMTypeProperty* p = new PMTypeProperty( "lightType", &PMLight::setLightType, + &PMLight::lightType ); + p->addEnumValue( "PointLight", PointLight ); + p->addEnumValue( "SpotLight", SpotLight ); + p->addEnumValue( "CylinderLight", CylinderLight ); + p->addEnumValue( "ShadowlessLight", ShadowlessLight ); + s_pMetaObject->addProperty( p ); + + s_pMetaObject->addProperty( + new PMLightProperty( "location", &PMLight::setLocation, &PMLight::location ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "color", &PMLight::setColor, &PMLight::color ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "radius", &PMLight::setRadius, &PMLight::radius ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "falloff", &PMLight::setFalloff, &PMLight::falloff ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "tightness", &PMLight::setTightness, &PMLight::tightness ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "pointAt", &PMLight::setPointAt, &PMLight::pointAt ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "parallel", &PMLight::setParallel, &PMLight::parallel ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "areaLight", &PMLight::setAreaLight, &PMLight::isAreaLight ) ); + + PMAreaProperty* p2 = new PMAreaProperty( "areaType", &PMLight::setAreaType, + &PMLight::areaType ); + p2->addEnumValue( "Rectangular", Rectangular ); + p2->addEnumValue( "Circular", Circular ); + s_pMetaObject->addProperty( p2 ); + + s_pMetaObject->addProperty( + new PMLightProperty( "axis1", &PMLight::setAxis1, &PMLight::axis1 ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "axis2", &PMLight::setAxis2, &PMLight::axis2 ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "adaptive", &PMLight::setAdaptive, &PMLight::adaptive ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "orient", &PMLight::setOrient, &PMLight::orient ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "jitter", &PMLight::setJitter, &PMLight::jitter ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "fading", &PMLight::setFading, &PMLight::fading ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "fadeDistance", &PMLight::setFadeDistance, &PMLight::fadeDistance ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "fadePower", &PMLight::setFadePower, &PMLight::fadePower ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "mediaInteraction", &PMLight::setMediaInteraction, + &PMLight::mediaInteraction ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "mediaAttenuation", &PMLight::setMediaAttenuation, + &PMLight::mediaAttenuation ) ); + } + return s_pMetaObject; +} + +void PMLight::setLocation( const PMVector& p ) +{ + if( p != m_location ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMLocationID, m_location ); + m_location = p; + m_location.resize( 3 ); + setViewStructureChanged( ); + } +} + +void PMLight::setColor( const PMColor& c ) +{ + if( c != m_color ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMColorID, m_color ); + m_color = c; + } +} + +void PMLight::setLightType( PMLightType t ) +{ + if( t != m_type ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMTypeID, m_type ); + m_type = t; + setViewStructureChanged( ); + } +} + +void PMLight::setRadius( double r ) +{ + if( !approx( r, m_radius ) ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRadiusID, m_radius ); + m_radius = r; + setViewStructureChanged( ); + } +} + +void PMLight::setFalloff( double f ) +{ + if( !approx( f, m_falloff ) ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFalloffID, m_falloff ); + m_falloff = f; + setViewStructureChanged( ); + } +} + +void PMLight::setTightness( double t ) +{ + if( !approx( t, m_tightness ) ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMTightnessID, m_tightness ); + m_tightness = t; + } +} + +void PMLight::setPointAt( const PMVector& v ) +{ + if( !m_pointAt.approxEqual( v ) ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMPointAtID, m_pointAt ); + m_pointAt = v; + setViewStructureChanged( ); + } +} + +void PMLight::setParallel( bool p ) +{ + if ( p != m_parallel ) + { + if ( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMParallelID, m_parallel ); + m_parallel = p; + } +} + +void PMLight::setAreaLight( bool yes ) +{ + if( yes != m_bAreaLight ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAreaLightID, m_bAreaLight ); + m_bAreaLight = yes; + setViewStructureChanged( ); + } +} + +void PMLight::setAreaType( PMAreaType at ) +{ + if ( at != m_areaType ) + { + if ( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAreaTypeID, m_areaType ); + m_areaType = at; + setViewStructureChanged( ); + } +} + +void PMLight::setAxis1( const PMVector& v ) +{ + if( !m_areaAxis1.approxEqual( v ) ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAreaAxis1ID, m_areaAxis1 ); + m_areaAxis1 = v; + setViewStructureChanged( ); + } +} + +void PMLight::setAxis2( const PMVector& v ) +{ + if( !m_areaAxis2.approxEqual( v ) ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAreaAxis2ID, m_areaAxis2 ); + m_areaAxis2 = v; + setViewStructureChanged( ); + } +} + +void PMLight::setSize1( int s ) +{ + if( s != m_areaSize1 ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAreaSize1ID, m_areaSize1 ); + m_areaSize1 = s; + setViewStructureChanged( ); + } +} + +void PMLight::setSize2( int s ) +{ + if( s != m_areaSize2 ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAreaSize2ID, m_areaSize2 ); + m_areaSize2 = s; + setViewStructureChanged( ); + } +} + +void PMLight::setAdaptive( int a ) +{ + if( a != m_adaptive ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAdaptiveID, m_adaptive ); + m_adaptive = a; + } +} + +void PMLight::setOrient( bool o ) +{ + if( o != m_orient ) + { + if ( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMOrientID, m_orient ); + m_orient = o; + setViewStructureChanged( ); + } +} + +void PMLight::setJitter( bool j ) +{ + if( j != m_jitter ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMJitterID, m_jitter ); + m_jitter = j; + } +} + +void PMLight::setFading( bool y ) +{ + if( y != m_bFading ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFadingID, m_bFading ); + m_bFading = y; + } +} + +void PMLight::setFadeDistance( double d ) +{ + if( !approx( d, m_fadeDistance ) ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFadeDistanceID, m_fadeDistance ); + m_fadeDistance = d; + } +} + +void PMLight::setFadePower( int p ) +{ + if( p != m_fadePower ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFadePowerID, m_fadePower ); + m_fadePower = p; + } +} + +void PMLight::setMediaInteraction( bool y ) +{ + if( y != m_bMediaInteraction ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMInteractionID, m_bMediaInteraction ); + m_bMediaInteraction = y; + } +} + +void PMLight::setMediaAttenuation( bool y ) +{ + if( y != m_bMediaAttenuation ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAttenuationID, m_bMediaAttenuation ); + m_bMediaAttenuation = y; + } +} + +PMDialogEditBase* PMLight::editWidget( QWidget* parent ) const +{ + return new PMLightEdit( parent ); +} + +void PMLight::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMLocationID: + setLocation( data->vectorData( ) ); + break; + case PMColorID: + setColor( data->colorData( ) ); + break; + case PMTypeID: + setLightType( ( PMLightType ) ( data->intData( ) ) ); + break; + case PMRadiusID: + setRadius( data->doubleData( ) ); + break; + case PMFalloffID: + setFalloff( data->doubleData( ) ); + break; + case PMTightnessID: + setTightness( data->doubleData( ) ); + break; + case PMPointAtID: + setPointAt( data->vectorData( ) ); + break; + case PMParallelID: + setParallel( data->boolData( ) ); + break; + case PMAreaLightID: + setAreaLight( data->boolData( ) ); + break; + case PMAreaTypeID: + setAreaType( ( PMAreaType ) ( data->intData( ) ) ); + break; + case PMAreaAxis1ID: + setAxis1( data->vectorData( ) ); + break; + case PMAreaAxis2ID: + setAxis2( data->vectorData( ) ); + break; + case PMAreaSize1ID: + setSize1( data->intData( ) ); + break; + case PMAreaSize2ID: + setSize2( data->intData( ) ); + break; + case PMAdaptiveID: + setAdaptive( data->intData( ) ); + break; + case PMOrientID: + setOrient( data->boolData( ) ); + break; + case PMJitterID: + setJitter( data->boolData( ) ); + break; + case PMFadingID: + setFading( data->boolData( ) ); + break; + case PMFadeDistanceID: + setFadeDistance( data->doubleData( ) ); + break; + case PMFadePowerID: + setFadePower( data->intData( ) ); + break; + case PMInteractionID: + setMediaInteraction( data->boolData( ) ); + break; + case PMAttenuationID: + setMediaAttenuation( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMLight::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + +void PMLight::createViewStructure( ) +{ + if( ( m_type == PointLight ) || ( m_type == ShadowlessLight ) ) + { + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultPointStructure( ) ); + m_pViewStructure->points( ).detach( ); + } + else + { + m_pViewStructure->points( ).resize( + defaultPointStructure( )->points( ).size( ) ); + m_pViewStructure->lines( ) = defaultPointStructure( )->lines( ); + } + + PMPointArray& points = m_pViewStructure->points( ); + + int i; + double c = s_pointLightSize / sqrt( 3.0 ); + for( i = 0; i < 14; i++ ) + points[i] = PMPoint( m_location ); + + points[0][0] += s_pointLightSize; + points[1][0] -= s_pointLightSize; + points[2][1] += s_pointLightSize; + points[3][1] -= s_pointLightSize; + points[4][2] += s_pointLightSize; + points[5][2] -= s_pointLightSize; + + for( i = 0; i < 4; i++ ) + { + points[6+2*i][0] += c; + points[6+2*i][1] += ( i & 1 ? c : -c ); + points[6+2*i][2] += ( i & 2 ? c : -c ); + points[7+2*i][0] -= c; + points[7+2*i][1] -= ( i & 1 ? c : -c ); + points[7+2*i][2] -= ( i & 2 ? c : -c ); + } + } + else if( m_type == SpotLight ) + { + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultSpotStructure( ) ); + m_pViewStructure->points( ).detach( ); + } + else + { + m_pViewStructure->points( ).resize( + defaultSpotStructure( )->points( ).size( ) ); + m_pViewStructure->lines( ) = defaultSpotStructure( )->lines( ); + } + + PMPointArray& points = m_pViewStructure->points( ); + + points[0] = PMPoint( m_location ); + + PMVector pointAtVector = m_pointAt - m_location; + double pl = pointAtVector.abs( ); + if( approxZero( pl ) ) + pointAtVector = PMVector( 0.0, 0.0, 1.0 ); + else + pointAtVector /= pl; + PMVector endPoint = pointAtVector.orthogonal( ); + PMMatrix rotation = PMMatrix::rotation( pointAtVector, + 2 * M_PI / s_nSpotLines ); + double length, r1, r2, a1, a2; + length = s_length; + a1 = m_radius; + a2 = m_falloff; + if( a1 < 0 ) a1 = 0; + if( a2 < 0 ) a2 = 0; + if( a1 > a2 ) a1 = a2; + if( a1 >= 89.9 ) a1 = 89.9; + if( a2 >= 89.9 ) a2 = 89.9; + a1 *= M_PI / 180; + a2 *= M_PI / 180; + r1 = tan( a1 ) * length; + r2 = tan( a2 ) * length; + + if( r2 > length ) + { + double d = length / r2; + r1 *= d; + r2 *= d; + length *= d; + } + + endPoint *= r2; + double r; + if( approxZero( r2 ) ) + r = 1; + else + r = r1 / r2; + + PMVector circleCenter = m_location + length * pointAtVector; + points[1] = PMPoint( circleCenter + endPoint ); + points[s_nSpotLines + 1] = PMPoint( circleCenter + endPoint * r ); + + int i; + for( i = 2; i < ( s_nSpotLines + 1 ); i++ ) + { + endPoint = rotation * endPoint; + points[i] = PMPoint( circleCenter + endPoint ); + points[s_nSpotLines + i] = PMPoint( circleCenter + endPoint * r ); + } + points[s_nSpotLines*2+1] = m_pointAt; + } + else if( m_type == CylinderLight ) + { + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultCylindricalStructure( ) ); + m_pViewStructure->points( ).detach( ); + } + else + { + m_pViewStructure->points( ).resize( + defaultCylindricalStructure( )->points( ).size( ) ); + m_pViewStructure->lines( ) = defaultCylindricalStructure( )->lines( ); + } + + PMPointArray& points = m_pViewStructure->points( ); + + points[s_nCylinderLines*4] = PMPoint( m_location ); + points[s_nCylinderLines*4+1] = PMPoint( m_pointAt ); + + PMVector pointAtVector = m_pointAt - m_location; + double pl = pointAtVector.abs( ); + if( approxZero( pl ) ) + pointAtVector = PMVector( 0.0, 0.0, 1.0 ); + else + pointAtVector /= pl; + PMVector endPoint = pointAtVector.orthogonal( ); + PMMatrix rotation = PMMatrix::rotation( pointAtVector, + 2 * M_PI / s_nCylinderLines ); + double r1, r2; + r1 = m_radius / 100; + r2 = m_falloff / 100; + if( r1 < 0 ) r1 = 0; + if( r2 < 0 ) r2 = 0; + if( r1 > r2 ) r1 = r2; + + endPoint *= r2; + double r; + if( approxZero( r2 ) ) + r = 1; + else + r = r1 / r2; + + PMVector circleCenter = m_location + s_length * pointAtVector; + points[0] = PMPoint( circleCenter + endPoint ); + points[s_nCylinderLines] = PMPoint( m_location + endPoint ); + points[2*s_nCylinderLines] = PMPoint( circleCenter + endPoint * r ); + points[3*s_nCylinderLines] = PMPoint( m_location + endPoint * r ); + + int i; + for( i = 1; i < s_nCylinderLines; i++ ) + { + endPoint = rotation * endPoint; + points[i] = PMPoint( circleCenter + endPoint ); + points[s_nCylinderLines + i] = PMPoint( m_location + endPoint ); + points[2*s_nCylinderLines + i] = PMPoint( circleCenter + endPoint * r ); + points[3*s_nCylinderLines + i] = PMPoint( m_location + endPoint * r ); + } + } + + if( m_bAreaLight ) + { + int s1, s2; + + s1 = m_areaSize1; + s2 = m_areaSize2; + if( s1 < 1 ) s1 = 1; + if( s2 < 1 ) s2 = 1; + + if( ( s1 > 1 ) || ( s2 > 1 ) ) + { + int x, y, h; + int ps, ls; + PMVector bp; + + PMPointArray& points = m_pViewStructure->points( ); + PMLineArray& lines = m_pViewStructure->lines( ); + points.detach( ); + lines.detach( ); + + ps = points.size( ); + ls = lines.size( ); + points.resize( ps + s1*s2 ); + lines.resize( ls + s1*(s2-1) + s2*(s1-1) ); + + if( s1 == 1 ) + { + bp = m_location - m_areaAxis2/2; + for( y = 0; y < s2; y++ ) + points[ps + y] = PMPoint( bp + m_areaAxis2 + * ( (double)y/(double)(s2-1) ) ); + for( y = 0; y < ( s2-1 ); y++ ) + lines[ls+y] = PMLine( ps + y, ps + y+1 ); + } + else if( s2 == 1 ) + { + bp = m_location - m_areaAxis1/2; + for( x = 0; x < s1; x++ ) + points[ps + x] = PMPoint( bp + m_areaAxis1 + * ( (double)x/(double)(s1-1) ) ); + for( x = 0; x < ( s1-1 ); x++ ) + lines[ls+x] = PMLine( ps + x, ps + x+1 ); + } + else + { + bp = m_location - m_areaAxis1/2 - m_areaAxis2/2; + + if ( m_areaType == Rectangular || s1 < 2 || s2 < 2 ) + { + for( x = 0; x < s1; x++ ) + for( y = 0; y < s2; y++ ) + points[ps + y*s1 + x] = + PMPoint( bp + m_areaAxis1 * ( (double)x/(double)(s1-1) ) + + m_areaAxis2 * ( (double)y/(double)(s2-1) ) ); + } + else + { + double stepX = ( 2.0 / (double)(s1-1) ); + double stepY = ( 2.0 / (double)(s2-1) ); + double doubleX, doubleY, xSqr, scaleFactor; + + for ( x = 0; x < s1; ++x ) + { + doubleX = ( (double)x * stepX ) - 1.0; + xSqr = doubleX * doubleX; + for ( y = 0; y < s2; ++y ) + { + doubleY = ( (double)y * stepY ) - 1.0; + + if ( doubleX == 0.0 && doubleY == 0.0 ) + scaleFactor = 1.0; + else + { + if ( fabs( doubleX ) > fabs( doubleY ) ) + scaleFactor = fabs( doubleX ); + else + scaleFactor = fabs( doubleY ); + scaleFactor /= sqrt( xSqr + doubleY * doubleY ); + } + + points[ps + y*s1 + x] = + PMPoint( bp + m_areaAxis1 * + ( ( ( doubleX * scaleFactor ) / 2.0 ) + 0.5 ) + + m_areaAxis2 * + ( ( ( doubleY * scaleFactor ) / 2.0 ) + 0.5 ) ); + } + } + } + + for( x = 0; x < s1; x++ ) + { + for( y = 0; y < (s2-1); y++ ) + { + h = ps + x + s1*y; + lines[ls + x*(s2-1) + y] = PMLine( h, h+s1 ); + } + } + + ls += s1*(s2-1); + for( y = 0; y < s2; y++ ) + { + for( x = 0; x < (s1-1); x++ ) + { + h = ps + x + s1*y; + lines[ls + y*(s1-1) + x] = PMLine( h, h+1 ); + } + } + } + } + } +} + +PMViewStructure* PMLight::defaultPointStructure( ) const +{ + if( !s_pDefaultPointStructure ) + { + s_pDefaultPointStructure = new PMViewStructure( 14, 7 ); +// PMPointArray& points = s_pDefaultPointStructure->points( ); + PMLineArray& lines = s_pDefaultPointStructure->lines( ); + + lines[0] = PMLine( 0, 1 ); + lines[1] = PMLine( 2, 3 ); + lines[2] = PMLine( 4, 5 ); + lines[3] = PMLine( 6, 7 ); + lines[4] = PMLine( 8, 9 ); + lines[5] = PMLine( 10, 11 ); + lines[6] = PMLine( 12, 13 ); + } + return s_pDefaultPointStructure; +} + +PMViewStructure* PMLight::defaultSpotStructure( ) const +{ + if( !s_pDefaultSpotStructure ) + { + s_pDefaultSpotStructure = new PMViewStructure( s_nSpotLines * 2 + 2, s_nSpotLines * 3 + 1 ); +// PMPointArray& points = s_pDefaultSpotStructure->points( ); + PMLineArray& lines = s_pDefaultSpotStructure->lines( ); + + int i; + for( i = 0; i < s_nSpotLines; i++ ) + { + lines[i] = PMLine( 0, i+1 ); + lines[s_nSpotLines + i] = PMLine( i+1, i+2 ); + lines[2*s_nSpotLines + i] = PMLine( s_nSpotLines + i+1, + s_nSpotLines + i+2 ); + } + // fix for the last line + lines[2*s_nSpotLines - 1] = PMLine( 1, s_nSpotLines ); + lines[3*s_nSpotLines - 1] = PMLine( s_nSpotLines + 1, s_nSpotLines*2 ); + lines[3*s_nSpotLines] = PMLine( 0, s_nSpotLines*2 + 1 ); + } + return s_pDefaultSpotStructure; +} + +PMViewStructure* PMLight::defaultCylindricalStructure( ) const +{ + if( !s_pDefaultCylindricalStructure ) + { + s_pDefaultCylindricalStructure = new PMViewStructure( s_nCylinderLines * 4 + 2, s_nCylinderLines * 5 + 1 ); +// PMPointArray& points = s_pDefaultCylindricalStructure->points( ); + PMLineArray& lines = s_pDefaultCylindricalStructure->lines( ); + + int i; + for( i = 0; i < s_nCylinderLines; i++ ) + { + lines[i] = PMLine( i, i+1 ); + lines[s_nCylinderLines + i] = PMLine( i + s_nCylinderLines, + i + s_nCylinderLines + 1 ); + lines[2*s_nCylinderLines + i] = PMLine( i + 2*s_nCylinderLines, + i + 2*s_nCylinderLines + 1 ); + lines[3*s_nCylinderLines + i] = PMLine( i + 3*s_nCylinderLines, + i + 3*s_nCylinderLines + 1 ); + lines[4*s_nCylinderLines + i] = PMLine( i, i + s_nCylinderLines ); + } + // fix for some lines + lines[s_nCylinderLines-1] = PMLine( 0, s_nCylinderLines - 1 ); + lines[2*s_nCylinderLines-1] = PMLine( s_nCylinderLines, + 2*s_nCylinderLines - 1 ); + lines[3*s_nCylinderLines-1] = PMLine( 2*s_nCylinderLines, + 3*s_nCylinderLines - 1 ); + lines[4*s_nCylinderLines-1] = PMLine( 3*s_nCylinderLines, + 4*s_nCylinderLines - 1 ); + lines[5*s_nCylinderLines] = PMLine( 4*s_nCylinderLines, + 4*s_nCylinderLines + 1 ); + } + return s_pDefaultCylindricalStructure; +} + +void PMLight::controlPoints( PMControlPointList& list ) +{ + list.append( new PM3DControlPoint( m_location, PMLocationID, i18n( "Location" ) ) ); + if( ( m_type == SpotLight ) || ( m_type == CylinderLight ) ) + list.append( new PM3DControlPoint( m_pointAt, PMPointAtID, i18n( "Point at" ) ) ); +} + +void PMLight::controlPointsChanged( PMControlPointList& list ) +{ + PMControlPoint* p; + + for( p = list.first( ); p; p = list.next( ) ) + { + if( p->changed( ) ) + { + switch( p->id( ) ) + { + case PMLocationID: + setLocation( ( ( PM3DControlPoint* ) p )->point( ) ); + break; + case PMPointAtID: + setPointAt( ( ( PM3DControlPoint* ) p )->point( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMLight::controlPointsChanged\n"; + break; + } + } + } +} + +void PMLight::cleanUp( ) const +{ + if( s_pDefaultPointStructure ) + delete s_pDefaultPointStructure; + s_pDefaultPointStructure = 0; + if( s_pDefaultSpotStructure ) + delete s_pDefaultSpotStructure; + s_pDefaultSpotStructure = 0; + if( s_pDefaultCylindricalStructure ) + delete s_pDefaultCylindricalStructure; + s_pDefaultCylindricalStructure = 0; + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} diff --git a/kpovmodeler/pmlight.h b/kpovmodeler/pmlight.h new file mode 100644 index 00000000..df40ec0a --- /dev/null +++ b/kpovmodeler/pmlight.h @@ -0,0 +1,372 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMLIGHT_H +#define PMLIGHT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmnamedobject.h" +#include "pmvector.h" +#include "pmcolor.h" + +class PMViewStructure; + +/** + * Class for povray light sources. + */ + +class PMLight : public PMNamedObject +{ + typedef PMNamedObject Base; +public: + enum PMLightType { PointLight=0, SpotLight=1, CylinderLight=2, ShadowlessLight=3 }; + enum PMAreaType { Rectangular=0, Circular=1 }; + /** + * Creates an empty PMLight + */ + PMLight( PMPart* part ); + /** + * Copy constructor + */ + PMLight( const PMLight& l ); + /** + * deletes the PMLight + */ + virtual ~PMLight( ); + + /** */ + virtual PMObject* copy( ) const { return new PMLight( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMLightEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmlight" ); } + + /** + * Returns the type + */ + PMLightType lightType( ) const { return m_type; } + /** + * Sets the type + */ + void setLightType( PMLightType t ); + + /** + * Returns the location + */ + PMVector location( ) const { return m_location; } + /** + * Sets the location + */ + void setLocation( const PMVector& p ); + + /** + * Returns the color + */ + PMColor color( ) const { return m_color; } + /** + * Sets the color + */ + void setColor( const PMColor& c ); + + /** + * Returns the radius for cylinder and spot lights + */ + double radius( ) const { return m_radius; } + /** + * Sets the radius for cylinder and spot lights + */ + void setRadius( double r ); + + /** + * Returns the falloff for cylinder and spot lights + */ + double falloff( ) const { return m_falloff; } + /** + * Sets the falloff for cylinder and spot lights + */ + void setFalloff( double f ); + + /** + * Returns the tightness for cylinder and spot lights + */ + double tightness( ) const { return m_tightness; } + /** + * Sets the tightness for cylinder and spot lights + */ + void setTightness( double r ); + + /** + * Returns the pointAt point for cylinder and spot lights + */ + PMVector pointAt( ) const { return m_pointAt; } + /** + * Sets the pointAt for cylinder and spot lights + */ + void setPointAt( const PMVector& p ); + + /** + * Return true if the light is a parallel light + */ + bool parallel( ) const { return m_parallel; } + /** + * Sets the parallel light flag + */ + void setParallel( bool p ); + + /** + * Returns true if the light is a area light + */ + bool isAreaLight( ) const { return m_bAreaLight; } + /** + * Sets the area light flag + */ + void setAreaLight( bool yes ); + + /** + * Returns the area light type + */ + PMAreaType areaType( ) const { return m_areaType; } + /** + * Sets the area light type + */ + void setAreaType( PMAreaType at ); + + /** + * Returns the axis1 for area lights + */ + PMVector axis1( ) const { return m_areaAxis1; } + /** + * Sets the axis1 for area lights + */ + void setAxis1( const PMVector& v ); + + /** + * Returns the axis2 for area lights + */ + PMVector axis2( ) const { return m_areaAxis2; } + /** + * Sets the axis2 for area lights + */ + void setAxis2( const PMVector& v ); + + /** + * Returns the size1 for area lights + */ + int size1( ) const { return m_areaSize1; } + /** + * Sets the size1 for area lights + */ + void setSize1( int s ); + + /** + * Returns the size2 for area lights + */ + int size2( ) const { return m_areaSize2; } + /** + * Sets the size2 for area lights + */ + void setSize2( int s ); + + /** + * Returns the adaptive parameter for area lights + */ + int adaptive( ) const { return m_adaptive; } + /** + * Sets the adaptive parameter for area lights + */ + void setAdaptive( int s ); + + /** + * Returns if the area light is orientated + */ + bool orient( ) const { return m_orient; } + /** + * Sets the orient flag + */ + void setOrient( bool o ); + + /** + * Returns the jitter parameter for area lights + */ + bool jitter( ) const { return m_jitter; } + /** + * Sets the jitter parameter for area lights + */ + void setJitter( bool j ); + + /** + * Returns true if light fading is enabled + */ + bool fading( ) const { return m_bFading; } + /** + * Enables/Disables light fading + */ + void setFading( bool yes ); + + /** + * Returns the fading distance + */ + double fadeDistance( ) const { return m_fadeDistance; } + /** + * Sets the fading distance + */ + void setFadeDistance( double d ); + + /** + * Returns the fading power + */ + int fadePower( ) const { return m_fadePower; } + /** + * Sets the fading power + */ + void setFadePower( int p ); + + /** + * Returns the media interaction flag + */ + bool mediaInteraction( ) const { return m_bMediaInteraction; } + /** + * Sets the media interaction flag + */ + void setMediaInteraction( bool yes ); + + /** + * Returns the media attenuation flag + */ + bool mediaAttenuation( ) const { return m_bMediaAttenuation; } + /** + * Sets the media attenuation flag + */ + void setMediaAttenuation( bool yes ); + + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual void controlPoints( PMControlPointList& list ); + /** */ + virtual void controlPointsChanged( PMControlPointList& list ); + /** */ + virtual void cleanUp( ) const; + +protected: + /** */ + virtual bool isDefault( ) { return false; } + /** */ + virtual void createViewStructure( ); + /** */ + virtual PMViewStructure* defaultViewStructure( ) const { return 0; } + +private: + /** + * Creates and returns the default view structure for point lights + */ + PMViewStructure* defaultPointStructure( ) const; + /** + * Creates and returns the default view structure for spot lights + */ + PMViewStructure* defaultSpotStructure( ) const; + /** + * Creates and returns the default view structure for cylindrical lights + */ + PMViewStructure* defaultCylindricalStructure( ) const; + + /** + * IDs for @ref PMMementoData + */ + enum PMLightMementoID + { PMLocationID, PMColorID, PMRadiusID, PMFalloffID, PMTightnessID, + PMPointAtID, PMParallelID, PMAreaLightID, PMAreaTypeID, PMAreaAxis1ID, + PMAreaAxis2ID, PMAreaSize1ID, PMAreaSize2ID, PMAdaptiveID, PMOrientID, + PMJitterID, PMTypeID, PMFadingID, PMFadeDistanceID, PMFadePowerID, + PMInteractionID, PMAttenuationID }; + + PMLightType m_type; + PMVector m_location; + PMColor m_color; + double m_radius; + double m_falloff; + double m_tightness; + PMVector m_pointAt; + bool m_parallel; + bool m_bAreaLight; + PMAreaType m_areaType; + PMVector m_areaAxis1, m_areaAxis2; + int m_areaSize1, m_areaSize2; + int m_adaptive; + bool m_orient; + bool m_jitter; + bool m_bFading; + double m_fadeDistance; + int m_fadePower; + bool m_bMediaInteraction; + bool m_bMediaAttenuation; + + /** + * The default view structure for point lights + */ + static PMViewStructure* s_pDefaultPointStructure; + /** + * The default view structure for spot lights + */ + static PMViewStructure* s_pDefaultSpotStructure; + /** + * The default view structure for cylindrical lights + */ + static PMViewStructure* s_pDefaultCylindricalStructure; + + /** + * The size of the point light for 3d views + */ + static double s_pointLightSize; + /** + * Number of lines around the cylinder + */ + static int s_nCylinderLines; + /** + * Number of lines around the spot + */ + static int s_nSpotLines; + /** + * Length of the spot and cylinder + */ + static double s_length; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmlightedit.cpp b/kpovmodeler/pmlightedit.cpp new file mode 100644 index 00000000..23f5aa9d --- /dev/null +++ b/kpovmodeler/pmlightedit.cpp @@ -0,0 +1,450 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmlightedit.h" +#include "pmlight.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" +#include "pmcoloredit.h" + +#include +#include +#include +#include + +#include + +PMLightEdit::PMLightEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMLightEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + m_pLocation = new PMVectorEdit( "x", "y", "z", this ); + m_pColor = new PMColorEdit( false, this ); + m_pType = new QComboBox( false, this ); + m_pType->insertItem( i18n( "Point Light" ) ); + m_pType->insertItem( i18n( "Spot Light" ) ); + m_pType->insertItem( i18n( "Cylindrical Light" ) ); + m_pType->insertItem( i18n( "Shadowless Light" ) ); + + m_pRadius = new PMFloatEdit( this ); + m_pRadius->setValidation( false, 0, true, 90 ); + m_pRadiusLabel = new QLabel( i18n( "Radius:" ), this ); + + m_pFalloff = new PMFloatEdit( this ); + m_pFalloff->setValidation( false, 0, true, 90 ); + m_pFalloffLabel = new QLabel( i18n( "Falloff:" ), this ); + + m_pTightness = new PMFloatEdit( this ); + m_pTightness->setValidation( false, 0, true, 90 ); + m_pTightnessLabel = new QLabel( i18n( "Tightness:" ), this ); + + m_pPointAt = new PMVectorEdit( "x", "y", "z", this ); + m_pPointAtLabel = new QLabel( i18n( "Point at:" ), this ); + + m_pParallel = new QCheckBox( i18n( "Parallel" ), this ); + + m_pAreaLight = new QCheckBox( i18n( "Area light" ), this ); + + m_pAreaTypeLabel = new QLabel( i18n ( "Area type:" ), this ); + m_pAreaType = new QComboBox( false, this ); + m_pAreaType->insertItem( i18n( "Rectangular" ) ); + m_pAreaType->insertItem( i18n( "Circular" ) ); + + m_pAxis1 = new PMVectorEdit( "x", "y", "z", this ); + m_pAxis1Label = new QLabel( i18n( "Axis 1:" ), this ); + m_pAxis2 = new PMVectorEdit( "x", "y", "z", this ); + m_pAxis2Label = new QLabel( i18n( "Axis 2:" ), this ); + + m_pSize1 = new PMIntEdit( this ); + m_pSize1->setValidation( true, 1, true, 50 ); + m_pSize1Label = new QLabel( i18n( "Size 1:" ), this ); + m_pSize2 = new PMIntEdit( this ); + m_pSize2->setValidation( true, 1, true, 50 ); + m_pSize2Label = new QLabel( i18n( "Size 2:" ), this ); + + m_pAdaptive = new PMIntEdit( this ); + m_pAdaptive->setValidation( true, 0, false, 0 ); + m_pAdaptiveLabel = new QLabel( i18n( "Adaptive:" ), this ); + m_pOrient = new QCheckBox( i18n( "Orient" ), this ); + m_pJitter = new QCheckBox( i18n( "Jitter" ), this ); + + m_pFading = new QCheckBox( i18n( "Fading" ), this ); + + m_pFadeDistance = new PMFloatEdit( this ); + m_pFadeDistance->setValidation( true, 0, false, 0 ); + m_pFadeDistanceLabel = new QLabel( i18n( "Fade distance:" ), this ); + + m_pFadePower = new PMIntEdit( this ); + m_pFadePower->setValidation( true, 0, false, 0 ); + m_pFadePowerLabel = new QLabel( i18n( "Fade power:" ), this ); + + m_pMediaInteraction = new QCheckBox( i18n( "Media interaction" ), this ); + m_pMediaAttenuation = new QCheckBox( i18n( "Media attenuation" ), this ); + + QHBoxLayout* hl; + QGridLayout* gl; + + gl = new QGridLayout( topLayout( ), 3, 2 ); + gl->addWidget( new QLabel( i18n( "Location:" ), this ), 0, 0 ); + gl->addWidget( m_pLocation, 0, 1 ); + gl->addWidget( new QLabel( i18n( "Color:" ), this ), 1, 0, AlignTop ); + gl->addWidget( m_pColor, 1, 1 ); + gl->addWidget( new QLabel( i18n( "Type:" ), this ), 2, 0 ); + hl = new QHBoxLayout( ); + gl->addLayout( hl, 2, 1 ); + hl->addWidget( m_pType ); + hl->addStretch( 1 ); + + gl = new QGridLayout( topLayout( ), 4, 2 ); + gl->addWidget( m_pRadiusLabel, 0, 0 ); + gl->addWidget( m_pRadius, 0, 1, AlignLeft ); + gl->addWidget( m_pFalloffLabel, 1, 0 ); + gl->addWidget( m_pFalloff, 1, 1, AlignLeft ); + gl->addWidget( m_pTightnessLabel, 2, 0 ); + gl->addWidget( m_pTightness, 2, 1, AlignLeft ); + gl->addWidget( m_pPointAtLabel, 3, 0 ); + gl->addWidget( m_pPointAt, 3, 1 ); + + topLayout( )->addWidget( m_pParallel ); + + hl = new QHBoxLayout( topLayout( ) ); + gl = new QGridLayout( hl, 7, 2 ); + gl->addMultiCellWidget( m_pAreaLight, 0, 0, 0, 1 ); + gl->addWidget( m_pAreaTypeLabel, 1, 0 ); + gl->addWidget( m_pAreaType, 1, 1 ); + gl->addWidget( m_pAxis1Label, 2, 0 ); + gl->addWidget( m_pAxis1, 2, 1 ); + gl->addWidget( m_pAxis2Label, 3, 0 ); + gl->addWidget( m_pAxis2, 3, 1 ); + gl->addWidget( m_pSize1Label, 4, 0 ); + gl->addWidget( m_pSize1, 4, 1, AlignLeft ); + gl->addWidget( m_pSize2Label, 5, 0 ); + gl->addWidget( m_pSize2, 5, 1, AlignLeft ); + gl->addWidget( m_pAdaptiveLabel, 6, 0 ); + gl->addWidget( m_pAdaptive, 6, 1, AlignLeft ); + hl->addStretch( 1 ); + + topLayout( )->addWidget( m_pOrient ); + topLayout( )->addWidget( m_pJitter ); + + hl = new QHBoxLayout( topLayout( ) ); + gl = new QGridLayout( hl, 3, 2 ); + gl->addMultiCellWidget( m_pFading, 0, 0, 0, 1 ); + gl->addWidget( m_pFadeDistanceLabel, 1, 0 ); + gl->addWidget( m_pFadeDistance, 1, 1 ); + gl->addWidget( m_pFadePowerLabel, 2, 0 ); + gl->addWidget( m_pFadePower, 2, 1 ); + hl->addStretch( 1 ); + + topLayout( )->addWidget( m_pMediaInteraction ); + topLayout( )->addWidget( m_pMediaAttenuation ); + + connect( m_pLocation, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pColor, SIGNAL( dataChanged( ) ), + SIGNAL( dataChanged( ) ) ); + connect( m_pType, SIGNAL( activated( int ) ), + SLOT( slotTypeActivated( int ) ) ); + connect( m_pRadius, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pFalloff, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pTightness, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pPointAt, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pParallel, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pAreaLight, SIGNAL( clicked( ) ), SLOT( slotAreaClicked( ) ) ); + connect( m_pAreaType, SIGNAL( activated ( int ) ), SLOT( slotOrientCheck( ) ) ); + connect( m_pAxis1, SIGNAL( dataChanged( ) ), SLOT( slotOrientCheck( ) ) ); + connect( m_pAxis2, SIGNAL( dataChanged( ) ), SLOT( slotOrientCheck( ) ) ); + connect( m_pSize1, SIGNAL( dataChanged( ) ), SLOT( slotOrientCheck( ) ) ); + connect( m_pSize2, SIGNAL( dataChanged( ) ), SLOT( slotOrientCheck( ) ) ); + connect( m_pAdaptive, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pOrient, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pJitter, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pFading, SIGNAL( clicked( ) ), SLOT( slotFadingClicked( ) ) ); + connect( m_pFadeDistance, SIGNAL( dataChanged( ) ), + SIGNAL( dataChanged( ) ) ); + connect( m_pFadePower, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pMediaInteraction, SIGNAL( clicked( ) ), + SIGNAL( dataChanged( ) ) ); + connect( m_pMediaAttenuation, SIGNAL( clicked( ) ), + SIGNAL( dataChanged( ) ) ); +} + +void PMLightEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Light" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMLight* ) o; + + m_pLocation->setVector( m_pDisplayedObject->location( ) ); + m_pLocation->setReadOnly( readOnly ); + m_pColor->setColor( m_pDisplayedObject->color( ) ); + m_pColor->setReadOnly( readOnly ); + m_pType->setCurrentItem( m_pDisplayedObject->lightType( ) ); + m_pType->setEnabled( !readOnly ); + slotTypeActivated( m_pDisplayedObject->lightType( ) ); + m_pRadius->setValue( m_pDisplayedObject->radius( ) ); + m_pRadius->setReadOnly( readOnly ); + m_pFalloff->setValue( m_pDisplayedObject->falloff( ) ); + m_pFalloff->setReadOnly( readOnly ); + m_pTightness->setValue( m_pDisplayedObject->tightness( ) ); + m_pTightness->setReadOnly( readOnly ); + m_pPointAt->setVector( m_pDisplayedObject->pointAt( ) ); + m_pPointAt->setReadOnly( readOnly ); + m_pParallel->setChecked( m_pDisplayedObject->parallel( ) ); + m_pParallel->setEnabled( !readOnly ); + m_pAreaLight->setChecked( m_pDisplayedObject->isAreaLight( ) ); + m_pAreaLight->setEnabled( !readOnly ); + m_pAreaType->setCurrentItem( m_pDisplayedObject->areaType( ) ); + m_pAreaType->setEnabled( !readOnly ); + m_pAxis1->setVector( m_pDisplayedObject->axis1( ) ); + m_pAxis1->setReadOnly( readOnly ); + m_pAxis2->setVector( m_pDisplayedObject->axis2( ) ); + m_pAxis2->setReadOnly( readOnly ); + m_pSize1->setValue( m_pDisplayedObject->size1( ) ); + m_pSize1->setReadOnly( readOnly ); + m_pSize2->setValue( m_pDisplayedObject->size2( ) ); + m_pSize2->setReadOnly( readOnly ); + m_pAdaptive->setValue( m_pDisplayedObject->adaptive( ) ); + m_pAdaptive->setReadOnly( readOnly ); + m_pOrient->setChecked( m_pDisplayedObject->orient( ) ); + m_pOrient->setEnabled( orientEnabled( readOnly ) ); + m_pJitter->setChecked( m_pDisplayedObject->jitter( ) ); + m_pJitter->setEnabled( !readOnly ); + slotAreaClicked( ); + m_pFading->setChecked( m_pDisplayedObject->fading( ) ); + m_pFading->setEnabled( !readOnly ); + m_pFadeDistance->setValue( m_pDisplayedObject->fadeDistance( ) ); + m_pFadeDistance->setReadOnly( readOnly ); + m_pFadePower->setValue( m_pDisplayedObject->fadePower( ) ); + m_pFadePower->setReadOnly( readOnly ); + slotFadingClicked( ); + m_pMediaInteraction->setChecked( m_pDisplayedObject->mediaInteraction( ) ); + m_pMediaInteraction->setEnabled( !readOnly ); + m_pMediaAttenuation->setChecked( m_pDisplayedObject->mediaAttenuation( ) ); + m_pMediaAttenuation->setEnabled( !readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMLightEdit: Can't display object\n"; +} + +void PMLightEdit::saveContents( ) +{ + int index; + + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setLocation( m_pLocation->vector( ) ); + m_pDisplayedObject->setColor( m_pColor->color( ) ); + + index = m_pType->currentItem( ); + if( ( index == 1 ) || ( index == 2 ) ) + { + m_pDisplayedObject->setRadius( m_pRadius->value( ) ); + m_pDisplayedObject->setFalloff( m_pFalloff->value( ) ); + m_pDisplayedObject->setTightness( m_pTightness->value( ) ); + m_pDisplayedObject->setPointAt( m_pPointAt->vector( ) ); + } + m_pDisplayedObject->setLightType( ( PMLight::PMLightType ) index ); + + m_pDisplayedObject->setParallel( m_pParallel->isChecked( ) ); + + if( m_pAreaLight->isChecked( ) ) + { + m_pDisplayedObject->setAreaType( + ( PMLight::PMAreaType ) m_pAreaType->currentItem( ) ); + m_pDisplayedObject->setAxis1( m_pAxis1->vector( ) ); + m_pDisplayedObject->setAxis2( m_pAxis2->vector( ) ); + m_pDisplayedObject->setSize1( m_pSize1->value( ) ); + m_pDisplayedObject->setSize2( m_pSize2->value( ) ); + m_pDisplayedObject->setAdaptive( m_pAdaptive->value( ) ); + m_pDisplayedObject->setOrient( m_pOrient->isChecked( ) ); + m_pDisplayedObject->setJitter( m_pJitter->isChecked( ) ); + } + m_pDisplayedObject->setAreaLight( m_pAreaLight->isChecked( ) ); + + if( m_pFading->isChecked( ) ) + { + m_pDisplayedObject->setFadePower( m_pFadePower->value( ) ); + m_pDisplayedObject->setFadeDistance( m_pFadeDistance->value( ) ); + } + m_pDisplayedObject->setFading( m_pFading->isChecked( ) ); + + m_pDisplayedObject->setMediaInteraction( m_pMediaInteraction->isChecked( ) ); + m_pDisplayedObject->setMediaAttenuation( m_pMediaAttenuation->isChecked( ) ); + } +} + +bool PMLightEdit::isDataValid( ) +{ + int index; + if( !m_pLocation->isDataValid( ) ) return false; + if( !m_pColor->isDataValid( ) ) return false; + + index = m_pType->currentItem( ); + if( ( index == 1 ) || ( index == 2 ) ) + { + if( !m_pRadius->isDataValid( ) ) return false; + if( !m_pFalloff->isDataValid( ) ) return false; + if( !m_pTightness->isDataValid( ) ) return false; + if( !m_pPointAt->isDataValid( ) ) return false; + } + if( m_pAreaLight->isChecked( ) ) + { + if( !m_pAxis1->isDataValid( ) ) return false; + if( !m_pAxis2->isDataValid( ) ) return false; + if( !m_pSize1->isDataValid( ) ) return false; + if( !m_pSize2->isDataValid( ) ) return false; + if( !m_pAdaptive->isDataValid( ) ) return false; + } + if( m_pFading->isChecked( ) ) + { + if( !m_pFadeDistance->isDataValid( ) ) return false; + if( !m_pFadePower->isDataValid( ) ) return false; + } + + return Base::isDataValid( ); +} + +void PMLightEdit::slotTypeActivated( int index ) +{ + if( ( index == 1 ) || ( index == 2 ) ) + { + m_pRadius->show( ); + m_pRadiusLabel->show( ); + m_pFalloff->show( ); + m_pFalloffLabel->show( ); + m_pTightness->show( ); + m_pTightnessLabel->show( ); + m_pPointAt->show( ); + m_pPointAtLabel->show( ); + } + else + { + m_pRadius->hide( ); + m_pRadiusLabel->hide( ); + m_pFalloff->hide( ); + m_pFalloffLabel->hide( ); + m_pTightness->hide( ); + m_pTightnessLabel->hide( ); + m_pPointAt->hide( ); + m_pPointAtLabel->hide( ); + } + emit dataChanged( ); + emit sizeChanged( ); +} + +void PMLightEdit::slotAreaClicked( ) +{ + if( m_pAreaLight->isChecked( ) ) + { + m_pAreaTypeLabel->show( ); + m_pAreaType->show( ); + m_pAxis1->show( ); + m_pAxis1Label->show( ); + m_pAxis2->show( ); + m_pAxis2Label->show( ); + m_pSize1->show( ); + m_pSize1Label->show( ); + m_pSize2->show( ); + m_pSize2Label->show( ); + m_pAdaptive->show( ); + m_pAdaptiveLabel->show( ); + m_pOrient->show( ); + m_pOrient->setEnabled( orientEnabled( !m_pJitter->isEnabled( ) ) ); + m_pJitter->show( ); + } + else + { + m_pAreaTypeLabel->hide( ); + m_pAreaType->hide( ); + m_pAxis1->hide( ); + m_pAxis1Label->hide( ); + m_pAxis2->hide( ); + m_pAxis2Label->hide( ); + m_pSize1->hide( ); + m_pSize1Label->hide( ); + m_pSize2->hide( ); + m_pSize2Label->hide( ); + m_pAdaptive->hide( ); + m_pAdaptiveLabel->hide( ); + m_pOrient->hide( ); + m_pJitter->hide( ); + } + + emit dataChanged( ); + emit sizeChanged( ); +} + +void PMLightEdit::slotOrientCheck( ) +{ + m_pOrient->setEnabled( orientEnabled( !m_pJitter->isEnabled( ) ) ); + emit dataChanged( ); +} + +void PMLightEdit::slotFadingClicked( ) +{ + if( m_pFading->isChecked( ) ) + { + m_pFadeDistance->show( ); + m_pFadeDistanceLabel->show( ); + m_pFadePower->show( ); + m_pFadePowerLabel->show( ); + } + else + { + m_pFadeDistance->hide( ); + m_pFadeDistanceLabel->hide( ); + m_pFadePower->hide( ); + m_pFadePowerLabel->hide( ); + } + emit dataChanged( ); + emit sizeChanged( ); +} + +bool PMLightEdit::orientEnabled( bool readOnly ) +{ + if ( readOnly ) + return false; + + if ( m_pAreaLight ) + { + if ( m_pAreaType->currentItem( ) == 1 ) + { + int size1 = m_pSize1->value( ); + int size2 = m_pSize2->value( ); + if ( size1 > 1 && size2 > 1 && size1 == size2 ) + { + if ( m_pAxis1->vector( ).abs( ) == m_pAxis2->vector( ).abs( ) ) + return true; + } + } + } + m_pOrient->setChecked( false ); + return false; +} + +#include "pmlightedit.moc" diff --git a/kpovmodeler/pmlightedit.h b/kpovmodeler/pmlightedit.h new file mode 100644 index 00000000..0b9b5ffb --- /dev/null +++ b/kpovmodeler/pmlightedit.h @@ -0,0 +1,115 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMLIGHTEDIT_H +#define PMLIGHTEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmnamedobjectedit.h" + +class PMLight; +class PMVectorEdit; +class PMColorEdit; +class QComboBox; +class PMFloatEdit; +class PMIntEdit; +class QLabel; +class QCheckBox; + +/** + * Dialog edit class for @ref PMLight + */ +class PMLightEdit : public PMNamedObjectEdit +{ + Q_OBJECT + typedef PMNamedObjectEdit Base; +public: + /** + * Creates a PMLightEdit with parent and name + */ + PMLightEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +public slots: + void slotTypeActivated( int index ); + void slotAreaClicked( ); + void slotOrientCheck( ); + void slotFadingClicked( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + /** + * Returns true if orient should be enabled + */ + bool orientEnabled( bool readOnly ); + + PMLight* m_pDisplayedObject; + PMVectorEdit* m_pLocation; + PMColorEdit* m_pColor; + QComboBox* m_pType; + + PMFloatEdit* m_pRadius; + QLabel* m_pRadiusLabel; + PMFloatEdit* m_pFalloff; + QLabel* m_pFalloffLabel; + PMFloatEdit* m_pTightness; + QLabel* m_pTightnessLabel; + + PMVectorEdit* m_pPointAt; + QLabel* m_pPointAtLabel; + QCheckBox* m_pParallel; + + QCheckBox* m_pAreaLight; + QLabel* m_pAreaTypeLabel; + QComboBox* m_pAreaType; + PMVectorEdit* m_pAxis1; + PMIntEdit* m_pSize1; + PMVectorEdit* m_pAxis2; + PMIntEdit* m_pSize2; + QLabel* m_pAxis1Label; + QLabel* m_pAxis2Label; + QLabel* m_pSize1Label; + QLabel* m_pSize2Label; + PMIntEdit* m_pAdaptive; + QLabel* m_pAdaptiveLabel; + QCheckBox* m_pOrient; + QCheckBox* m_pJitter; + + QCheckBox* m_pFading; + PMFloatEdit* m_pFadeDistance; + QLabel* m_pFadeDistanceLabel; + PMIntEdit* m_pFadePower; + QLabel* m_pFadePowerLabel; + QCheckBox* m_pMediaInteraction; + QCheckBox* m_pMediaAttenuation; +}; + + +#endif diff --git a/kpovmodeler/pmlightgroup.cpp b/kpovmodeler/pmlightgroup.cpp new file mode 100644 index 00000000..e53e0e3b --- /dev/null +++ b/kpovmodeler/pmlightgroup.cpp @@ -0,0 +1,134 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmlightgroup.h" + +#include +#include "pmxmlhelper.h" +#include "pmlightgroupedit.h" +#include "pmmemento.h" + +PMDefinePropertyClass( PMLightGroup, PMLightGroupProperty ); + +PMMetaObject* PMLightGroup::s_pMetaObject = 0; +PMObject* createNewLightGroup( PMPart* part ) +{ + return new PMLightGroup( part ); +} + +PMLightGroup::PMLightGroup( PMPart* part ) + : Base( part ) +{ + m_globalLights = false; +} + +PMLightGroup::PMLightGroup( const PMLightGroup& lg ) + : Base( lg ) +{ + m_globalLights = lg.m_globalLights; +} + +PMLightGroup::~PMLightGroup( ) +{ +} + +QString PMLightGroup::description( ) const +{ + return QString( i18n( "light group" ) ); +} + +void PMLightGroup::serialize( QDomElement& e, QDomDocument& doc ) const +{ + if( m_globalLights ) + e.setAttribute( "global_lights", "1" ); + else + e.setAttribute( "global_lights", "0" ); + + Base::serialize( e, doc ); +} + +void PMLightGroup::readAttributes( const PMXMLHelper& h ) +{ + m_globalLights = h.boolAttribute( "global_lights", false ); + + Base::readAttributes( h ); +} + +PMMetaObject* PMLightGroup::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "LightGroup", Base::metaObject( ), + createNewLightGroup ); + + s_pMetaObject->addProperty( new PMLightGroupProperty( "globalLights", + &PMLightGroup::setGlobalLights, &PMLightGroup::globalLights ) ); + + } + return s_pMetaObject; +} + +void PMLightGroup::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMLightGroup::setGlobalLights( bool gl ) +{ + if( gl != m_globalLights ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMGlobalLightsID, m_globalLights ); + m_globalLights = gl; + } +} + +PMDialogEditBase* PMLightGroup::editWidget( QWidget* parent ) const +{ + return new PMLightGroupEdit( parent ); +} + +void PMLightGroup::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMGlobalLightsID: + setGlobalLights( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMCSG::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + diff --git a/kpovmodeler/pmlightgroup.h b/kpovmodeler/pmlightgroup.h new file mode 100644 index 00000000..f488eaf2 --- /dev/null +++ b/kpovmodeler/pmlightgroup.h @@ -0,0 +1,98 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMLIGHTGROUP_H +#define PMLIGHTGROUP_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" + +/** + * Class for povray light group objects. + */ + +class PMLightGroup : public PMSolidObject +{ + typedef PMSolidObject Base; +public: + /** + * Creates an empty PMLightGroup object + */ + PMLightGroup( PMPart* part ); + /** + * Copy constructor + */ + PMLightGroup( const PMLightGroup& lg ); + + /** + * deletes the PMLightGroup object + */ + virtual ~PMLightGroup( ); + + /** */ + virtual PMObject* copy( ) const { return new PMLightGroup( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMLightGroupEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmlightgroup" ); } + + /** + * Returns the global lights flag + */ + bool globalLights( ) const { return m_globalLights; } + /** + * Sets the global lights flag + */ + void setGlobalLights( bool gl ); + + /** */ + virtual void restoreMemento( PMMemento* s ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMGlobalLightsMementoID { PMGlobalLightsID }; + + bool m_globalLights; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmlightgroupedit.cpp b/kpovmodeler/pmlightgroupedit.cpp new file mode 100644 index 00000000..18feffbe --- /dev/null +++ b/kpovmodeler/pmlightgroupedit.cpp @@ -0,0 +1,78 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmlightgroupedit.h" +#include "pmlightgroup.h" + +#include +#include +#include +#include + +PMLightGroupEdit::PMLightGroupEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMLightGroupEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* layout; + m_pGlobalLights = new QCheckBox( i18n( "Global lights" ), this ); + + layout = new QHBoxLayout( topLayout( ) ); + layout->addWidget( m_pGlobalLights ); + layout->addStretch( 1 ); + + connect( m_pGlobalLights, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMLightGroupEdit::displayObject( PMObject* o ) +{ + if( o->isA( "LightGroup" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMLightGroup* ) o; + + m_pGlobalLights->setChecked( m_pDisplayedObject->globalLights( ) ); + m_pGlobalLights->setEnabled( !readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMLightGroupEdit: Can't display object\n"; +} + +void PMLightGroupEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + + m_pDisplayedObject->setGlobalLights( m_pGlobalLights->isChecked( ) ); + } +} + +bool PMLightGroupEdit::isDataValid( ) +{ + return Base::isDataValid( ); +} + +#include "pmlightgroupedit.moc" diff --git a/kpovmodeler/pmlightgroupedit.h b/kpovmodeler/pmlightgroupedit.h new file mode 100644 index 00000000..2701d681 --- /dev/null +++ b/kpovmodeler/pmlightgroupedit.h @@ -0,0 +1,64 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMLIGHTGROUPEDIT_H +#define PMLIGHTGROUPEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" + +class PMLightGroup; +class QCheckBox; + +/** + * Dialog edit class for @ref PMLightGroup + */ +class PMLightGroupEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMLightGroupEdit with parent and name + */ + PMLightGroupEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); +protected slots: + +private: + PMLightGroup* m_pDisplayedObject; + + QCheckBox* m_pGlobalLights; +}; + + +#endif diff --git a/kpovmodeler/pmline.cpp b/kpovmodeler/pmline.cpp new file mode 100644 index 00000000..27ff752d --- /dev/null +++ b/kpovmodeler/pmline.cpp @@ -0,0 +1,22 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmline.h" + + +// nothing to be done here at the moment diff --git a/kpovmodeler/pmline.h b/kpovmodeler/pmline.h new file mode 100644 index 00000000..399555ea --- /dev/null +++ b/kpovmodeler/pmline.h @@ -0,0 +1,102 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMLINES_H +#define PMLINES_H + +#include +#include +#include "pmdebug.h" + +/** + * Line to display with index of start and end point. + * + * Line of a @ref PMViewStructure. Only the indices in a @ref PMPointArray + * are stored. + * + * Optimized for OpenGL + */ +class PMLine +{ +public: + /** + * Default constructor + */ + PMLine( ) + { + m_start = 0; + m_end = 0; + } + /** + * Creates a line with start point si and end point ei. If si is greater + * than ei, si and ei are swapped. + */ + PMLine( const GLuint si, const GLuint ei ) + { m_start = si; m_end = ei; checkPoints( ); } + + /** + * Sets the start point. + */ + void setStartPoint( GLuint si ) { m_start = si; checkPoints( ); } + /** + * Sets the end point. + */ + void setEndPoint( GLuint ei ) { m_end = ei; checkPoints( ); } + /** + * Returns the start point. + */ + GLuint startPoint( ) const { return m_start; } + /** + * Returns the end point. + */ + GLuint endPoint( ) const { return m_end; } + +private: + /** + * Swaps the two points. + */ + void swapPoints( ) { GLuint help = m_start; m_start = m_end; m_end = help; } + /** + * Checks, if si < ei and swaps the two points if necessary + */ + void checkPoints( ) + { + if( m_start == m_end ) kdError( PMArea ) << "Start index = end index in PMLine" << "\n"; + if( m_start > m_end ) swapPoints( ); + } + /** + * The start and end points (indices!) + * + * THESE MEMBERS HAVE TO BE THE ONLY ONE (for rendering with OpenGl) + */ + GLuint m_start, m_end; +}; + +typedef QPtrListIterator PMLineListIterator; + +/** + * A list of @ref PMLine objects. + * + * This class stores all lines of a @ref PMViewStructure. A line is + * described by a start and end point. Only the indices in a @ref PMPointArray + * are stored. + */ +typedef QMemArray PMLineArray; + +#endif diff --git a/kpovmodeler/pmlineedits.cpp b/kpovmodeler/pmlineedits.cpp new file mode 100644 index 00000000..05124d75 --- /dev/null +++ b/kpovmodeler/pmlineedits.cpp @@ -0,0 +1,229 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmlineedits.h" +#include +#include + +PMFloatEdit::PMFloatEdit( QWidget* parent, const char* name /*= 0*/ ) + : QLineEdit( parent, name ) +{ + m_bCheckLower = false; + m_bCheckUpper = false; + m_lowerValue = 0; + m_upperValue = 0; + m_lowerOp = OpGreaterEqual; + m_upperOp = OpLessEqual; + + connect( this, SIGNAL( textChanged( const QString& ) ), + SLOT( slotEditTextChanged( const QString& ) ) ); +} + +void PMFloatEdit::setValidation( bool checkLower, double lowerValue, + bool checkUpper, double upperValue ) +{ + m_bCheckLower = checkLower; + m_bCheckUpper = checkUpper; + m_lowerValue = lowerValue; + m_upperValue = upperValue; +} + +void PMFloatEdit::setValidationOperator( ValidationOp l, ValidationOp u ) +{ + m_lowerOp = l; + m_upperOp = u; +} + +bool PMFloatEdit::isDataValid( ) +{ + bool ok = true; + double d; + d = text( ).toDouble( &ok ); + + if( ok ) + { + if( m_bCheckLower ) + ok = ok && ( m_lowerOp == OpGreaterEqual ? + d >= m_lowerValue : d > m_lowerValue ); + if( m_bCheckUpper ) + ok = ok && ( m_upperOp == OpLessEqual ? + d <= m_upperValue : d < m_upperValue ); + if( !ok ) + { + if( m_bCheckLower && m_bCheckUpper ) + KMessageBox::error( this, i18n( "Please enter a float value " + "between %1 and %2" ) + .arg( m_lowerValue ).arg( m_upperValue ), + i18n( "Error" ) ); + else if( m_bCheckLower ) + { + if( m_lowerOp == OpGreaterEqual ) + KMessageBox::error( this, i18n( "Please enter a float value " + ">= %1" ).arg( m_lowerValue ), + i18n( "Error" ) ); + else + KMessageBox::error( this, i18n( "Please enter a float value " + "> %1" ).arg( m_lowerValue ), + i18n( "Error" ) ); + } + else + { + if( m_upperOp == OpLessEqual ) + KMessageBox::error( this, i18n( "Please enter a float value " + "<= %1" ).arg( m_upperValue ), + i18n( "Error" ) ); + else + KMessageBox::error( this, i18n( "Please enter a float value " + "< %1" ).arg( m_upperValue ), + i18n( "Error" ) ); + } + } + } + else + { + KMessageBox::error( this, i18n( "Please enter a valid float value!" ), + i18n( "Error" ) ); + } + + if( !ok ) + { + setFocus( ); + selectAll( ); + } + return ok; +} + +double PMFloatEdit::value( ) const +{ + return text( ).toDouble( ); +} + +void PMFloatEdit::setValue( double d, int precision ) +{ + QString str; + + str.setNum( d, 'g', precision ); + setText( str ); +} + +void PMFloatEdit::slotEditTextChanged( const QString& /*t*/ ) +{ + emit dataChanged( ); +} + + + + + +PMIntEdit::PMIntEdit( QWidget* parent, const char* name /*= 0*/ ) + : QLineEdit( parent, name ) +{ + m_bCheckLower = false; + m_bCheckUpper = false; + m_lowerValue = 0; + m_upperValue = 0; + + connect( this, SIGNAL( textChanged( const QString& ) ), + SLOT( slotEditTextChanged( const QString& ) ) ); +} + +void PMIntEdit::setValidation( bool checkLower, int lowerValue, + bool checkUpper, int upperValue ) +{ + m_bCheckLower = checkLower; + m_bCheckUpper = checkUpper; + m_lowerValue = lowerValue; + m_upperValue = upperValue; +} + +bool PMIntEdit::isDataValid( ) +{ + bool ok = true; + int i; + double d; + + i = text( ).toInt( &ok ); + if( !ok ) + { + d = text( ).toDouble( &ok ); + if( ok ) + { + i = ( int ) d; + QString str; + bool b = signalsBlocked( ); + blockSignals( true ); + str.setNum( i ); + setText( str ); + blockSignals( b ); + } + } + + if( ok ) + { + if( m_bCheckLower ) + ok = ok && ( i >= m_lowerValue ); + if( m_bCheckUpper ) + ok = ok && ( i <= m_upperValue ); + if( !ok ) + { + if( m_bCheckLower && m_bCheckUpper ) + KMessageBox::error( this, i18n( "Please enter an integer value " + "between %1 and %2" ) + .arg( m_lowerValue ).arg( m_upperValue ), + i18n( "Error" ) ); + else if( m_bCheckLower ) + KMessageBox::error( this, i18n( "Please enter an integer value " + ">= %1" ).arg( m_lowerValue ), + i18n( "Error" ) ); + else + KMessageBox::error( this, i18n( "Please enter an integer value " + "<= %1" ).arg( m_upperValue ), + i18n( "Error" ) ); + } + } + else + { + KMessageBox::error( this, i18n( "Please enter a valid integer value!" ), + i18n( "Error" ) ); + } + + if( !ok ) + { + setFocus( ); + selectAll( ); + } + return ok; +} + +int PMIntEdit::value( ) const +{ + return text( ).toInt( ); +} + +void PMIntEdit::setValue( int i ) +{ + QString str; + + str.setNum( i ); + setText( str ); +} + +void PMIntEdit::slotEditTextChanged( const QString& /*t*/ ) +{ + emit dataChanged( ); +} +#include "pmlineedits.moc" diff --git a/kpovmodeler/pmlineedits.h b/kpovmodeler/pmlineedits.h new file mode 100644 index 00000000..9a12c384 --- /dev/null +++ b/kpovmodeler/pmlineedits.h @@ -0,0 +1,133 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PM_LINEEDITS_H +#define PM_LINEEDITS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +/** + * Lineedit for float input + */ + +class PMFloatEdit : public QLineEdit +{ + Q_OBJECT +public: + enum ValidationOp { OpGreater, OpGreaterEqual, + OpLess, OpLessEqual }; + /** + * Simple constructor + */ + PMFloatEdit( QWidget* parent, const char* name = 0 ); + /** + * Sets the validation for the lineedit. + * + * If checkLower is true, the value has to be >= the lowerValue. + * + * If checkUpper is true, the value has to be <= the upperValue. + * + * By default no range check is made. + */ + void setValidation( bool checkLower, double lowerValue, + bool checkUpper, double upperValue ); + /** + * Sets the validation operators for the lower and upper value. + * + * Valid values for lower are OpGreater and OpGreaterEqual, + * valid values for upper are OpLess and OpLessEqual. + */ + void setValidationOperator( ValidationOp lower, ValidationOp upper ); + /** + * Returns true, if the text is a valid float in the valid range + */ + bool isDataValid( ); + /** + * Returns the float value + */ + double value( ) const; + /** + * Sets the value + */ + void setValue( double d, int precision = 5 ); +signals: + /** + * emitted if the text is changed + */ + void dataChanged( ); +public slots: + void slotEditTextChanged( const QString& t ); +private: + bool m_bCheckLower, m_bCheckUpper; + double m_lowerValue, m_upperValue; + ValidationOp m_lowerOp, m_upperOp; +}; + + +/** + * Lineedit for int input + */ + +class PMIntEdit : public QLineEdit +{ + Q_OBJECT +public: + /** + * Simple constructor + */ + PMIntEdit( QWidget* parent, const char* name = 0 ); + /** + * Sets the validation for the lineedit. + * + * If checkLower is true, the value has to be >= the lowerValue. + * + * If checkUpper is true, the value has to be <= the upperValue. + * + * By default no range check is made. + */ + void setValidation( bool checkLower, int lowerValue, + bool checkUpper, int upperValue ); + /** + * Returns true, if the text is a valid integer in the valid range + */ + bool isDataValid( ); + /** + * Returns the integer value + */ + int value( ) const; + /** + * Sets the value + */ + void setValue( int i ); +signals: + /** + * emitted if the text is changed + */ + void dataChanged( ); +public slots: + void slotEditTextChanged( const QString& t ); +private: + bool m_bCheckLower, m_bCheckUpper; + int m_lowerValue, m_upperValue; +}; + +#endif diff --git a/kpovmodeler/pmlinkedit.cpp b/kpovmodeler/pmlinkedit.cpp new file mode 100644 index 00000000..a878e02e --- /dev/null +++ b/kpovmodeler/pmlinkedit.cpp @@ -0,0 +1,146 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmlinkedit.h" +#include +#include +#include +#include +#include +#include +#include + +#include "pmdeclare.h" +#include "pmobjectselect.h" + +PMLinkEdit::PMLinkEdit( const QString& declareType, + QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + m_declareTypes.append( declareType ); + init( ); +} + +PMLinkEdit::PMLinkEdit( const QStringList& declareTypes, + QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + m_declareTypes = declareTypes; + init( ); +} + +PMLinkEdit::PMLinkEdit( QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + init( ); +} + +void PMLinkEdit::init( ) +{ + m_pDeclare = 0; + m_pDisplayedObject = 0; + m_bReadOnly = false; + + QGridLayout* grid = new QGridLayout( this, 2, 2, 0, KDialog::spacingHint( ) ); + + grid->addWidget( new QLabel( i18n( "Prototype:" ), this ), 0, 0 ); + grid->setColStretch( 0, 0 ); + grid->setColStretch( 1, 1 ); + m_pIDEdit = new QLineEdit( this ); + m_pIDEdit->setReadOnly( true ); + grid->addWidget( m_pIDEdit, 0, 1 ); + + QHBoxLayout* layout = new QHBoxLayout( ); + grid->addLayout( layout, 1, 1 ); + m_pSelectButton = new QPushButton( i18n( "Select..." ), this ); + layout->addWidget( m_pSelectButton ); + m_pClearButton = new KPushButton( KStdGuiItem::clear(), this ); + layout->addWidget( m_pClearButton ); + + connect( m_pSelectButton, SIGNAL( clicked( ) ), SLOT( slotSelectClicked( ) ) ); + connect( m_pClearButton, SIGNAL( clicked( ) ), SLOT( slotClearClicked( ) ) ); +} + +void PMLinkEdit::setDisplayedObject( PMObject* obj ) +{ + m_pDisplayedObject = obj; + m_pDeclare = obj->linkedObject( ); + if( m_pDeclare ) + { + m_pIDEdit->setText( m_pDeclare->id( ) ); + if( !m_bReadOnly ) + m_pClearButton->setEnabled( true ); + } + else + { + m_pIDEdit->clear( ); + if( !m_bReadOnly ) + m_pClearButton->setEnabled( false ); + } +} + +void PMLinkEdit::setLinkPossibility( const QString& t ) +{ + m_declareTypes.clear( ); + m_declareTypes.append( t ); +} + + +void PMLinkEdit::setLinkPossibilities( const QStringList& t ) +{ + m_declareTypes = t; +} + +void PMLinkEdit::setReadOnly( bool yes ) +{ + m_bReadOnly = yes; + m_pClearButton->setEnabled( !m_bReadOnly && m_pDeclare ); + m_pSelectButton->setEnabled( !m_bReadOnly ); +} + +void PMLinkEdit::slotSelectClicked( ) +{ + if( m_pDisplayedObject ) + { + PMObject* obj = 0; + int result; + + if( m_declareTypes.count( ) == 1 ) + result = PMObjectSelect::selectDeclare( + m_pDisplayedObject, m_declareTypes.first( ), obj, this ); + else + result = PMObjectSelect::selectDeclare( + m_pDisplayedObject, m_declareTypes, obj, this ); + + if( ( result == QDialog::Accepted ) && obj ) + { + m_pDeclare = ( PMDeclare* ) obj; + m_pIDEdit->setText( m_pDeclare->id( ) ); + m_pClearButton->setEnabled( true ); + emit dataChanged( ); + } + } +} + +void PMLinkEdit::slotClearClicked( ) +{ + m_pDeclare = 0; + m_pIDEdit->clear( ); + emit dataChanged( ); +} + +#include "pmlinkedit.moc" diff --git a/kpovmodeler/pmlinkedit.h b/kpovmodeler/pmlinkedit.h new file mode 100644 index 00000000..f5abe182 --- /dev/null +++ b/kpovmodeler/pmlinkedit.h @@ -0,0 +1,105 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMLINKEDIT_H +#define PMLINKEDIT_H + +#include +#include "pmobject.h" +#include "pmdeclare.h" + +#include + +class QString; +class QLineEdit; +class QPushButton; + +/** + * Edit widget for links with a QLineEdit, a select and a clear button. + */ +class PMLinkEdit : public QWidget +{ + Q_OBJECT +public: + /** + * Creates a link edit widget with parent and name. + * + * Allows the selection of declares of type declareType. + */ + PMLinkEdit( const QString& declareType, QWidget* parent, const char* name = 0 ); + /** + * Creates a link edit widget with parent and name. + * + * Allows the selection of declares of type declares. + */ + PMLinkEdit( const QStringList& declares, QWidget* parent, const char* name = 0 ); + /** + * Creates a link edit widget with parent and name. + */ + PMLinkEdit( QWidget* parent, const char* name = 0 ); + + /** + * Sets the displayed object and displays the link + */ + void setDisplayedObject( PMObject* obj ); + /** + * Returns the selected link + */ + PMDeclare* link( ) const { return m_pDeclare; } + + /** + * Sets the selection possibilities + */ + void setLinkPossibility( const QString& t ); + /** + * Sets the selection possibilities + */ + void setLinkPossibilities( const QStringList& t ); + + /** + * Enables or disables read only mode + */ + void setReadOnly( bool yes = true ); +signals: + /** + * Emitted when the link is changed + */ + void dataChanged( ); + +public slots: + /** + * Called when the select button is clicked + */ + void slotSelectClicked( ); + /** + * Called when the clear button is clicked + */ + void slotClearClicked( ); + +private: + void init( ); + PMDeclare* m_pDeclare; + PMObject* m_pDisplayedObject; + QStringList m_declareTypes; + + QLineEdit* m_pIDEdit; + QPushButton* m_pSelectButton; + QPushButton* m_pClearButton; + bool m_bReadOnly; +}; + +#endif diff --git a/kpovmodeler/pmlistpattern.cpp b/kpovmodeler/pmlistpattern.cpp new file mode 100644 index 00000000..299ab4fb --- /dev/null +++ b/kpovmodeler/pmlistpattern.cpp @@ -0,0 +1,469 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmlistpattern.h" + +#include "pmxmlhelper.h" +#include "pmlistpatternedit.h" +#include "pmcompositeobject.h" +#include "pmmemento.h" +#include "pmenumproperty.h" + +#include + +PMDefinePropertyClass( PMListPattern, PMListPatternProperty ); +PMDefineEnumPropertyClass( PMListPattern, PMListPattern::PMListType, + PMListTypeProperty ); + +const PMVector brickSizeDefault = PMVector( 8, 6, 4.5 ); +const double mortarDefault = 0.5; +const double depthDefault = 0; + +PMMetaObject* PMListPattern::s_pMetaObject = 0; +PMMetaObject* PMColorList::s_pMetaObject = 0; +PMObject* createNewColorList( PMPart* part ) +{ + return new PMColorList( part ); +} +PMMetaObject* PMDensityList::s_pMetaObject = 0; +PMObject* createNewDensityList( PMPart* part ) +{ + return new PMDensityList( part ); +} +PMMetaObject* PMNormalList::s_pMetaObject = 0; +PMObject* createNewNormalList( PMPart* part ) +{ + return new PMNormalList( part ); +} +PMMetaObject* PMPigmentList::s_pMetaObject = 0; +PMObject* createNewPigmentList( PMPart* part ) +{ + return new PMPigmentList( part ); +} +PMMetaObject* PMTextureList::s_pMetaObject = 0; +PMObject* createNewTextureList( PMPart* part ) +{ + return new PMTextureList( part ); +} + +PMListPattern::PMListPattern( PMPart* part ) + : Base( part ) +{ + m_listType = ListPatternChecker; + m_brickSize = brickSizeDefault; + m_mortar = mortarDefault; +} + +PMListPattern::PMListPattern( const PMListPattern& p ) + : Base( p ) +{ + m_listType = p.m_listType; + m_brickSize = p.m_brickSize; + m_mortar = p.m_mortar; +} + +PMListPattern::~PMListPattern( ) +{ +} + +void PMListPattern::serialize( QDomElement& e, QDomDocument& doc ) const +{ + switch( m_listType ) + { + case ListPatternBrick: + e.setAttribute( "listtype", "brick" ); + break; + case ListPatternChecker: + e.setAttribute( "listtype", "checker" ); + break; + case ListPatternHexagon: + e.setAttribute( "listtype", "hexagon" ); + break; + }; + e.setAttribute( "bricksize", m_brickSize.serializeXML( ) ); + e.setAttribute( "mortar", m_mortar ); + Base::serialize( e, doc ); +} + +void PMListPattern::readAttributes( const PMXMLHelper& h ) +{ + QString str = h.stringAttribute( "listtype", "checker" ); + if( str == "checker" ) + m_listType = ListPatternChecker; + else if( str == "brick" ) + m_listType = ListPatternBrick; + else + m_listType = ListPatternHexagon; + m_brickSize = h.vectorAttribute( "bricksize", brickSizeDefault ); + m_mortar = h.doubleAttribute( "mortar", mortarDefault ); + Base::readAttributes( h ); +} + +PMMetaObject* PMListPattern::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "ListPattern", Base::metaObject( ) ); + + PMListTypeProperty* p = new PMListTypeProperty( + "listType", &PMListPattern::setListType, + &PMListPattern::listType ); + p->addEnumValue( QString( "Checker" ), ListPatternChecker ); + p->addEnumValue( QString( "Brick" ), ListPatternBrick ); + p->addEnumValue( QString( "Hexagon" ), ListPatternHexagon ); + s_pMetaObject->addProperty( p ); + + s_pMetaObject->addProperty( + new PMListPatternProperty( "brickSize", &PMListPattern::setBrickSize, + &PMListPattern::brickSize ) ); + s_pMetaObject->addProperty( + new PMListPatternProperty( "mortar", &PMListPattern::setMortar, + &PMListPattern::mortar ) ); + } + return s_pMetaObject; +} + +void PMListPattern::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMListPattern::setListType( PMListType l ) +{ + if( l != m_listType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMListTypeID, m_listType ); + m_listType = l; + } +} + +void PMListPattern::setBrickSize( const PMVector& n ) +{ + if( n != m_brickSize ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMBrickSizeID, m_brickSize ); + m_brickSize = n; + } +} + +void PMListPattern::setMortar( double n ) +{ + if( n != m_mortar ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMMortarID, m_mortar ); + m_mortar = n; + } +} + +PMDialogEditBase* PMListPattern::editWidget( QWidget* parent ) const +{ + return new PMListPatternEdit( parent ); +} + +void PMListPattern::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMListTypeID: + setListType( ( PMListType ) data->intData( ) ); + break; + case PMBrickSizeID: + setBrickSize( data->vectorData( ) ); + break; + case PMMortarID: + setMortar( data->doubleData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMListPattern::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + + +PMTextureList::PMTextureList( PMPart* part ) + : Base( part ) +{ +} + +PMTextureList::PMTextureList( const PMTextureList& l ) + : Base( l ) +{ +} + +PMTextureList::~PMTextureList( ) +{ +} + +PMMetaObject* PMTextureList::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "TextureList", Base::metaObject( ), + createNewTextureList ); + } + return s_pMetaObject; +} + +void PMTextureList::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMTextureList::description( ) const +{ + return i18n( "texture list" ); +} + +PMPigmentList::PMPigmentList( PMPart* part ) + : Base( part ) +{ +} + +PMPigmentList::PMPigmentList( const PMPigmentList& l ) + : Base( l ) +{ +} + +PMPigmentList::~PMPigmentList( ) +{ +} + +PMMetaObject* PMPigmentList::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "PigmentList", Base::metaObject( ), + createNewPigmentList ); + } + return s_pMetaObject; +} + +void PMPigmentList::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMPigmentList::description( ) const +{ + return i18n( "pigment list" ); +} + +PMColorList::PMColorList( PMPart* part ) + : Base( part ) +{ +} + +PMColorList::PMColorList( const PMColorList& l ) + : Base( l ) +{ +} + +PMColorList::~PMColorList( ) +{ +} + +PMMetaObject* PMColorList::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "ColorList", Base::metaObject( ), + createNewColorList ); + } + return s_pMetaObject; +} + +void PMColorList::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMColorList::description( ) const +{ + return i18n( "color list" ); +} + +PMDensityList::PMDensityList( PMPart* part ) + : Base( part ) +{ +} + +PMDensityList::PMDensityList( const PMDensityList& l ) + : Base( l ) +{ +} + +PMDensityList::~PMDensityList( ) +{ +} + +PMMetaObject* PMDensityList::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "DensityList", Base::metaObject( ), + createNewDensityList ); + } + return s_pMetaObject; +} + +void PMDensityList::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMDensityList::description( ) const +{ + return i18n( "density list" ); +} + +PMDefinePropertyClass( PMNormalList, PMNormalListProperty ); + +PMNormalList::PMNormalList( PMPart* part ) + : Base( part ) +{ + m_depth = depthDefault; +} + +PMNormalList::PMNormalList( const PMNormalList& l ) + : Base( l ) +{ + m_depth = depthDefault; +} + +PMNormalList::~PMNormalList( ) +{ +} + +PMMetaObject* PMNormalList::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "NormalList", Base::metaObject( ), + createNewNormalList ); + s_pMetaObject->addProperty( + new PMNormalListProperty( "depth", &PMNormalList::setDepth, + &PMNormalList::depth ) ); + } + return s_pMetaObject; +} + +void PMNormalList::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMNormalList::description( ) const +{ + return i18n( "normal list" ); +} + +void PMNormalList::setDepth( double d ) +{ + if( d != m_depth ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMDepthID, m_depth ); + m_depth = d; + } +} + +void PMNormalList::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMDepthID: + setDepth( data->doubleData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMNormalList::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + +void PMNormalList::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "depth", m_depth ); + Base::serialize( e, doc ); +} + +void PMNormalList::readAttributes( const PMXMLHelper& h ) +{ + m_depth = h.doubleAttribute( "depth", depthDefault ); + Base::readAttributes( h ); +} + +PMDialogEditBase* PMNormalList::editWidget( QWidget* parent ) const +{ + return new PMListPatternEdit( parent ); +} + diff --git a/kpovmodeler/pmlistpattern.h b/kpovmodeler/pmlistpattern.h new file mode 100644 index 00000000..f646d8ab --- /dev/null +++ b/kpovmodeler/pmlistpattern.h @@ -0,0 +1,351 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMLISTPATTERN_H +#define PMLISTPATTERN_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmcompositeobject.h" +#include "pmvector.h" + +/** + * Base class for povray lists. + */ + +class PMListPattern : public PMCompositeObject +{ + typedef PMCompositeObject Base; +public: + /** + * The type of the pigment list + */ + enum PMListType { ListPatternChecker, ListPatternBrick, ListPatternHexagon }; + /** + * Creates a PMListPattern + */ + PMListPattern( PMPart* part ); + /** + * Copy constructor + */ + PMListPattern( const PMListPattern& p ); + /** + * deletes the PMListPattern + */ + virtual ~PMListPattern( ); + + /** + * Returns the list pattern object type + */ + virtual QString listObjectType( ) const = 0; + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMListPatternEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + + /** + * Returns the color list type + */ + PMListType listType( ) const { return m_listType; } + /** + * Returns the brick size + */ + PMVector brickSize( ) const { return m_brickSize; } + /** + * Returns the mortar size + */ + double mortar( ) const { return m_mortar; } + + /** + * Sets the list type + */ + void setListType( PMListType l ); + /** + * Sets the brick size + */ + void setBrickSize( const PMVector& n ); + /** + * Sets the mortar size + */ + void setMortar( double n ); + + /** */ + virtual void restoreMemento( PMMemento* s ); + +private: + /** + * IDs for @ref PMMementoData + */ + enum PMListPatternMementoID { PMListTypeID, PMBrickSizeID, PMMortarID }; + /** + * List type + */ + PMListType m_listType; + /** + * Brick Size + */ + PMVector m_brickSize; + /** + * Mortar Size + */ + double m_mortar; + + static PMMetaObject* s_pMetaObject; +}; + +/** + * Class for texture lists + */ + +class PMTextureList : public PMListPattern +{ +public: + typedef PMListPattern Base; + /** + * Creates a texture list + */ + PMTextureList( PMPart* part ); + /** + * Copy constructor + */ + PMTextureList( const PMTextureList& l ); + /** + * Deletes the texture list + */ + virtual ~PMTextureList( ); + + /** */ + virtual PMObject* copy( ) const { return new PMTextureList( *this ); } + /** */ + virtual QString description( ) const; + /** */ + virtual QString listObjectType( ) const { return QString( "Texture" ); } + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual QString pixmap( ) const { return QString( "pmtexturelist" ); } + + static PMMetaObject* s_pMetaObject; +}; + +/** + * Class for pigment lists + */ + +class PMPigmentList : public PMListPattern +{ +public: + typedef PMListPattern Base; + /** + * Creates a pigment list + */ + PMPigmentList( PMPart* part ); + /** + * Copy constructor + */ + PMPigmentList( const PMPigmentList& l ); + /** + * Deletes the pigment list + */ + virtual ~PMPigmentList( ); + + /** */ + virtual PMObject* copy( ) const { return new PMPigmentList( *this ); } + /** */ + virtual QString description( ) const; + /** */ + virtual QString listObjectType( ) const { return QString( "Pigment" ); } + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual QString pixmap( ) const { return QString( "pmpigmentlist" ); } + + static PMMetaObject* s_pMetaObject; +}; + +/** + * Class for color lists + */ + +class PMColorList : public PMListPattern +{ +public: + typedef PMListPattern Base; + /** + * Creates a color list + */ + PMColorList( PMPart* part ); + /** + * Copy constructor + */ + PMColorList( const PMColorList& l ); + /** + * Deletes the color list + */ + virtual ~PMColorList( ); + + /** */ + virtual PMObject* copy( ) const { return new PMColorList( *this ); } + /** */ + virtual QString description( ) const; + /** */ + virtual QString listObjectType( ) const { return QString( "SolidColor" ); } + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual QString pixmap( ) const { return QString( "pmcolorlist" ); } + + static PMMetaObject* s_pMetaObject; +}; + +/** + * Class for density lists + */ + +class PMDensityList : public PMListPattern +{ +public: + typedef PMListPattern Base; + /** + * Creates a density list + */ + PMDensityList( PMPart* part ); + /** + * Copy constructor + */ + PMDensityList( const PMDensityList& l ); + /** + * Deletes the density list + */ + virtual ~PMDensityList( ); + + /** */ + virtual PMObject* copy( ) const { return new PMDensityList( *this ); } + /** */ + virtual QString description( ) const; + /** */ + virtual QString listObjectType( ) const { return QString( "Density" ); } + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual QString pixmap( ) const { return QString( "pmdensitylist" ); } + + static PMMetaObject* s_pMetaObject; +}; + +/** + * Class for normal lists + */ + +class PMNormalList : public PMListPattern +{ +public: + typedef PMListPattern Base; + /** + * Creates a normal list + */ + PMNormalList( PMPart* part ); + /** + * Copy constructor + */ + PMNormalList( const PMNormalList& l ); + /** + * Deletes the normal list + */ + virtual ~PMNormalList( ); + + /** */ + virtual PMObject* copy( ) const { return new PMNormalList( *this ); } + /** */ + virtual QString description( ) const; + /** */ + virtual QString listObjectType( ) const { return QString( "Normal" ); } + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** + * Returns a new @ref PMListPatternEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + + /** */ + virtual QString pixmap( ) const { return QString( "pmnormallist" ); } + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** */ + virtual void restoreMemento( PMMemento* s ); + + /** + * Returns the normal's depth + */ + double depth( ) const { return m_depth; } + /** + * Sets the normal's depth + */ + void setDepth( double d ); + +private: + /** + * IDs for @ref PMMementoData + */ + enum PMNormalListMementoID { PMDepthID }; + /** + * Normal Depth + */ + double m_depth; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmlistpatternedit.cpp b/kpovmodeler/pmlistpatternedit.cpp new file mode 100644 index 00000000..f9eb3cf7 --- /dev/null +++ b/kpovmodeler/pmlistpatternedit.cpp @@ -0,0 +1,225 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmlistpatternedit.h" +#include "pmlistpattern.h" +#include "pmvectoredit.h" +#include "pmvector.h" + +#include +#include +#include +#include +#include "pmlineedits.h" +#include +#include +#include + + +PMListPatternEdit::PMListPatternEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMListPatternEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QVBoxLayout* vlayout = new QVBoxLayout( topLayout( ) ); + + /* Field for Pattern List type */ + QHBoxLayout* layout = new QHBoxLayout( vlayout ); + QLabel* label = new QLabel( i18n( "Type:" ), this ); + m_pTypeCombo = new QComboBox( false, this ); + m_pTypeCombo->insertItem( i18n( "Checkers" ) ); + m_pTypeCombo->insertItem( i18n( "Brick" ) ); + m_pTypeCombo->insertItem( i18n( "Hexagon" ) ); + layout->addWidget( label, 0, AlignTop ); + layout->addWidget( m_pTypeCombo ); + layout->addStretch( 1 ); + + /* The depth field */ + layout = new QHBoxLayout( vlayout ); + m_pDepthLabel = new QLabel( i18n( "Depth:" ), this ); + m_pDepth = new PMFloatEdit( this ); + layout->addWidget( m_pDepthLabel ); + layout->addWidget( m_pDepth ); + layout->addStretch( 1 ); + + /* The brick information */ + QHBoxLayout* bricklayout = new QHBoxLayout( vlayout ); + m_pBrickSizeLabel = new QLabel( i18n( "Brick size:" ), this ); + m_pBrickSize = new PMVectorEdit( "x", "y", "z", this ); + bricklayout->addWidget( m_pBrickSizeLabel ); + bricklayout->addWidget( m_pBrickSize ); + layout = new QHBoxLayout( vlayout ); + m_pMortarLabel = new QLabel( i18n( "Mortar:" ), this ); + m_pMortar = new PMFloatEdit( this ); + layout->addWidget( m_pMortarLabel ); + layout->addWidget( m_pMortar ); + layout->addStretch( 1 ); + + /* connect all signals to slots/signals */ + connect( m_pBrickSize, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pTypeCombo, SIGNAL( activated( int ) ), SLOT( slotComboChanged( int ) ) ); + connect( m_pMortar, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pDepth, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMListPatternEdit::displayObject( PMObject* o ) +{ + QString str; + + if( o->isA( "ListPattern" ) ) + { + m_pDisplayedObject = ( PMListPattern* ) o; + + switch( m_pDisplayedObject->listType( ) ) + { + case PMListPattern::ListPatternChecker: + m_pTypeCombo->setCurrentItem( 0 ); + m_pBrickSizeLabel->hide( ); + m_pBrickSize->hide( ); + m_pMortarLabel->hide( ); + m_pMortar->hide( ); + break; + case PMListPattern::ListPatternBrick: + m_pTypeCombo->setCurrentItem( 1 ); + m_pBrickSizeLabel->show( ); + m_pBrickSize->show( ); + m_pMortarLabel->show( ); + m_pMortar->show( ); + break; + case PMListPattern::ListPatternHexagon: + m_pTypeCombo->setCurrentItem( 2 ); + m_pBrickSizeLabel->hide( ); + m_pBrickSize->hide( ); + m_pMortarLabel->hide( ); + m_pMortar->hide( ); + break; + } + m_pMortar->setValue( m_pDisplayedObject->mortar( ) ); + m_pBrickSize->setVector( m_pDisplayedObject->brickSize( ) ); + if( o->type( ) == "NormalList" ) + { + m_pDepth->setValue( ( ( PMNormalList* )o )->depth( ) ); + m_pDepth->show( ); + m_pDepthLabel->show( ); + emit sizeChanged( ); + } + else + { + m_pDepth->hide( ); + m_pDepthLabel->hide( ); + emit sizeChanged( ); + } + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMListPatternEdit: Can't display object\n"; +} + +void PMListPatternEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + switch( m_pTypeCombo->currentItem( ) ) + { + case 0: + m_pDisplayedObject->setListType( PMListPattern::ListPatternChecker ); + break; + case 1: + m_pDisplayedObject->setListType( PMListPattern::ListPatternBrick ); + m_pDisplayedObject->setMortar( m_pMortar->value( ) ); + m_pDisplayedObject->setBrickSize( m_pBrickSize->vector( ) ); + break; + case 2: + m_pDisplayedObject->setListType( PMListPattern::ListPatternHexagon ); + break; + } + if( m_pDisplayedObject->type( ) == "NormalList" ) + ( ( PMNormalList* )m_pDisplayedObject )->setDepth( m_pDepth->value( ) ); + } +} + +bool PMListPatternEdit::isDataValid( ) +{ + int children = 0; + PMObject* o; + + if( !m_pBrickSize->isDataValid( ) ) + return false; + if( !m_pMortar->isDataValid( ) ) + return false; + + // count child objects + for( o = m_pDisplayedObject->firstChild( ); o; o = o->nextSibling( ) ) + if( o->type( ) == m_pDisplayedObject->listObjectType( ) ) + children++; + + switch( m_pTypeCombo->currentItem( ) ) + { + case 0: + case 1: + if( children > 2 ) + { + KMessageBox::error( this, i18n( "You can have at most two child" + " items for that list type!" ), + i18n( "Error" ) ); + return false; + } + break; + default: + break; + } + + return Base::isDataValid( ); +} + +void PMListPatternEdit::slotComboChanged( int c ) +{ + switch( c ) + { + case 0: + m_pBrickSizeLabel->hide( ); + m_pBrickSize->hide( ); + m_pMortarLabel->hide( ); + m_pMortar->hide( ); + break; + case 1: + m_pBrickSizeLabel->show( ); + m_pBrickSize->show( ); + m_pMortarLabel->show( ); + m_pMortar->show( ); + break; + case 2: + m_pBrickSizeLabel->hide( ); + m_pBrickSize->hide( ); + m_pMortarLabel->hide( ); + m_pMortar->hide( ); + break; + default: + break; + } + emit sizeChanged( ); + emit dataChanged( ); +} + +#include "pmlistpatternedit.moc" diff --git a/kpovmodeler/pmlistpatternedit.h b/kpovmodeler/pmlistpatternedit.h new file mode 100644 index 00000000..8ebd5e5b --- /dev/null +++ b/kpovmodeler/pmlistpatternedit.h @@ -0,0 +1,78 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMLISTPATTERNEDIT_H +#define PMLISTPATTERNEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMListPattern; +class PMVectorEdit; +class QComboBox; +class PMFloatEdit; +class QLabel; + +/** + * Dialog edit class for @ref PMListPattern. + */ +class PMListPatternEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMListPatternEdit with parent and name + */ + PMListPatternEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + /** + * This slot is called when the list type is changed + */ + void slotComboChanged( int c ); + +private: + PMListPattern* m_pDisplayedObject; + QComboBox* m_pTypeCombo; + PMFloatEdit* m_pMortar; + PMVectorEdit* m_pBrickSize; + QLabel* m_pBrickSizeLabel; + QLabel* m_pMortarLabel; + + QLabel* m_pDepthLabel; + PMFloatEdit* m_pDepth; +}; + + +#endif diff --git a/kpovmodeler/pmlookslike.cpp b/kpovmodeler/pmlookslike.cpp new file mode 100644 index 00000000..7e810605 --- /dev/null +++ b/kpovmodeler/pmlookslike.cpp @@ -0,0 +1,92 @@ +/* +************************************************************************** + description + ------------------- + and : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmlookslike.h" + +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmnamedobjectedit.h" + +#include + +PMMetaObject* PMLooksLike::s_pMetaObject = 0; +PMObject* createNewLooksLike( PMPart* part ) +{ + return new PMLooksLike( part ); +} + +PMLooksLike::PMLooksLike( PMPart* part ) + : Base( part ) +{ +} + +PMLooksLike::PMLooksLike( const PMLooksLike& l ) + : Base( l ) +{ +} + +PMLooksLike::~PMLooksLike( ) +{ +} + + +QString PMLooksLike::description( ) const +{ + return i18n( "looks like" ); +} + +PMMetaObject* PMLooksLike::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "LooksLike", Base::metaObject( ), + createNewLooksLike ); + // no properties + } + return s_pMetaObject; +} + +void PMLooksLike::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMLooksLike::serialize( QDomElement& e, QDomDocument& doc ) const +{ + Base::serialize( e, doc ); +} + +void PMLooksLike::readAttributes( const PMXMLHelper& h ) +{ + Base::readAttributes( h ); +} + +PMDialogEditBase* PMLooksLike::editWidget( QWidget* parent ) const +{ + return new PMNamedObjectEdit( parent ); +} + +void PMLooksLike::restoreMemento( PMMemento* s ) +{ + Base::restoreMemento( s ); +} + diff --git a/kpovmodeler/pmlookslike.h b/kpovmodeler/pmlookslike.h new file mode 100644 index 00000000..971519e0 --- /dev/null +++ b/kpovmodeler/pmlookslike.h @@ -0,0 +1,82 @@ +//-*-C++-*- +/* +************************************************************************** + description + ------------------- + and : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMLOOKSLIKE_H +#define PMLOOKSLIKE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmnamedobject.h" + +/** + * Class for povray looks_like statements. + */ +class PMLooksLike : public PMNamedObject +{ + typedef PMNamedObject Base; + +public: + /** + * Constructor + */ + PMLooksLike( PMPart* part ); + /** + * Copy constructor + */ + PMLooksLike( const PMLooksLike& l ); + /** + * Deletes the PMLooksLike + */ + virtual ~PMLooksLike( ); + + /** */ + virtual PMObject* copy( ) const { return new PMLooksLike( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMLooksLikeEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmlookslike" ); } + + /** */ + virtual void restoreMemento( PMMemento* s ); + +private: + static PMMetaObject* s_pMetaObject; +}; + + +#endif diff --git a/kpovmodeler/pmmapmemento.cpp b/kpovmodeler/pmmapmemento.cpp new file mode 100644 index 00000000..5b4e9aaa --- /dev/null +++ b/kpovmodeler/pmmapmemento.cpp @@ -0,0 +1,51 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmmapmemento.h" + +PMMapMemento::PMMapMemento( PMObject* originator ) + : PMMemento( originator ) +{ + m_bMapValuesSaved = false; + m_bRemovedValuesSaved = false; +} + +PMMapMemento::~PMMapMemento( ) +{ +} + +void PMMapMemento::setMapValues( const QValueList& v ) +{ + if( !m_bMapValuesSaved ) + { + m_mapValues = v; + m_bMapValuesSaved = true; + addChange( PMCData ); + } +} + +void PMMapMemento::setRemovedValues( const QValueList& v ) +{ + if( !m_bRemovedValuesSaved ) + { + m_removedValues = v; + m_bRemovedValuesSaved = true; + addChange( PMCData ); + } +} + + diff --git a/kpovmodeler/pmmapmemento.h b/kpovmodeler/pmmapmemento.h new file mode 100644 index 00000000..e2f1fa0a --- /dev/null +++ b/kpovmodeler/pmmapmemento.h @@ -0,0 +1,81 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMMAPMEMENTO_H +#define PMMAPMEMENTO_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmmemento.h" +#include + + +/** + * Memento for @ref PMTextureMapBase + */ +class PMMapMemento : public PMMemento +{ +public: + /** + * Creates a memento for the object originator + */ + PMMapMemento( PMObject* originator ); + /** + * Deletes the memento + */ + virtual ~PMMapMemento( ); + + /** + * Saves the map values + */ + void setMapValues( const QValueList& v ); + /** + * Returns the map values + */ + QValueList mapValues( ) const { return m_mapValues; } + /** + * Returns true if the map values were saved + */ + bool mapValuesSaved( ) const { return m_bMapValuesSaved; } + + /** + * Saves the removed values + */ + void setRemovedValues( const QValueList& v ); + /** + * Returns the removed values + */ + QValueList removedValues( ) const { return m_removedValues; } + /** + * Returns true if the removed values were saved + */ + bool removedValuesSaved( ) const { return m_bRemovedValuesSaved; } + +private: + /** + * The stored values + */ + QValueList m_mapValues; + QValueList m_removedValues; + bool m_bMapValuesSaved, m_bRemovedValuesSaved; +}; + +#endif diff --git a/kpovmodeler/pmmaterial.cpp b/kpovmodeler/pmmaterial.cpp new file mode 100644 index 00000000..d50f0ed1 --- /dev/null +++ b/kpovmodeler/pmmaterial.cpp @@ -0,0 +1,75 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmmaterial.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmmaterialedit.h" + +#include + +PMMetaObject* PMMaterial::s_pMetaObject = 0; +PMObject* createNewMaterial( PMPart* part ) +{ + return new PMMaterial( part ); +} + +PMMaterial::PMMaterial( PMPart* part ) + : Base( part ) +{ +} + +PMMaterial::PMMaterial( const PMMaterial& m ) + : Base( m ) +{ +} + +PMMaterial::~PMMaterial( ) +{ +} + +PMMetaObject* PMMaterial::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Material", Base::metaObject( ), + createNewMaterial ); + } + return s_pMetaObject; +} + +void PMMaterial::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMMaterial::description( ) const +{ + return i18n( "material" ); +} + +PMDialogEditBase* PMMaterial::editWidget( QWidget* parent ) const +{ + return new PMMaterialEdit( parent ); +} + diff --git a/kpovmodeler/pmmaterial.h b/kpovmodeler/pmmaterial.h new file mode 100644 index 00000000..40891f1e --- /dev/null +++ b/kpovmodeler/pmmaterial.h @@ -0,0 +1,75 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMMATERIAL_H +#define PMMATERIAL_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebase.h" + +/** + * Class for povray materials + */ +class PMMaterial : public PMTextureBase +{ + typedef PMTextureBase Base; +public: + /** + * Creates an PMMaterial + */ + PMMaterial( PMPart* part ); + /** + * Copy constructor + */ + PMMaterial( const PMMaterial& m ); + /** + * Deletes the object + */ + virtual ~PMMaterial( ); + + /** */ + virtual PMObject* copy( ) const { return new PMMaterial( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** + * Returns a new @ref PMMaterialEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pmmaterial" ); } + +private: + /** + * IDs for @ref PMMementoData + */ +// enum PMMaterialMementoID { }; + static PMMetaObject* s_pMetaObject; +}; + + +#endif diff --git a/kpovmodeler/pmmaterialedit.cpp b/kpovmodeler/pmmaterialedit.cpp new file mode 100644 index 00000000..ba63f579 --- /dev/null +++ b/kpovmodeler/pmmaterialedit.cpp @@ -0,0 +1,44 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmmaterialedit.h" +#include "pmmaterial.h" +#include "pmlinkedit.h" + +#include +#include +#include + + +PMMaterialEdit::PMMaterialEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMMaterialEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Material" ) ) + { + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMMaterialEdit: Can't display object\n"; +} + +#include "pmmaterialedit.moc" diff --git a/kpovmodeler/pmmaterialedit.h b/kpovmodeler/pmmaterialedit.h new file mode 100644 index 00000000..d273a72e --- /dev/null +++ b/kpovmodeler/pmmaterialedit.h @@ -0,0 +1,58 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMMATERIALEDIT_H +#define PMMATERIALEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebaseedit.h" + +class PMMaterial; + +/** + * Dialog edit class for @ref PMMaterial + */ +class PMMaterialEdit : public PMTextureBaseEdit +{ + Q_OBJECT + typedef PMTextureBaseEdit Base; +public: + /** + * Creates a PMMaterialEdit with parent and name + */ + PMMaterialEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + +protected: + /** */ +// virtual void createTopWidgets( ); + /** */ +// virtual void saveContents( ); + +private: + PMMaterial* m_pDisplayedObject; +}; + + +#endif diff --git a/kpovmodeler/pmmaterialmap.cpp b/kpovmodeler/pmmaterialmap.cpp new file mode 100644 index 00000000..c70d85c9 --- /dev/null +++ b/kpovmodeler/pmmaterialmap.cpp @@ -0,0 +1,338 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Passos Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmmaterialmapedit.h" +#include "pmmaterialmap.h" + +#include "pmxmlhelper.h" +#include "pmcompositeobject.h" +#include "pmmemento.h" +#include "pmenumproperty.h" + +#include + +const PMMaterialMap::PMBitmapType bitmapTypeDefault = PMMaterialMap::BitmapSys; +const char *const bitmapFileDefault = 0; +const bool enableFilterAllDefault = false; +const bool enableTransmitAllDefault = false; +const double filterAllDefault = 0.0; +const double transmitAllDefault = 0.0; +const bool onceDefault = false; +const PMMaterialMap::PMMapType mapTypeDefault = PMMaterialMap::MapPlanar; +const PMMaterialMap::PMInterpolateType interpolateTypeDefault = PMMaterialMap::InterpolateNone; + +PMDefinePropertyClass( PMMaterialMap, PMMaterialMapProperty ); +PMDefineEnumPropertyClass( PMMaterialMap, PMMaterialMap::PMBitmapType, + PMBitmapTypeProperty ); +PMDefineEnumPropertyClass( PMMaterialMap, PMMaterialMap::PMInterpolateType, + PMInterpolateTypeProperty ); +PMDefineEnumPropertyClass( PMMaterialMap, PMMaterialMap::PMMapType, + PMMapTypeProperty ); + +PMMetaObject* PMMaterialMap::s_pMetaObject = 0; +PMObject* createNewMaterialMap( PMPart* part ) +{ + return new PMMaterialMap( part ); +} + +PMMaterialMap::PMMaterialMap( PMPart* part ) + : Base( part ) +{ + m_bitmapType = bitmapTypeDefault; + m_bitmapFile = bitmapFileDefault; + m_once = onceDefault; + m_mapType = mapTypeDefault; + m_interpolateType = interpolateTypeDefault; +} + +PMMaterialMap::PMMaterialMap( const PMMaterialMap& m ) + : Base( m ) +{ + m_bitmapType = m.m_bitmapType; + m_bitmapFile = m.m_bitmapFile; + m_once = m.m_once; + m_mapType = m.m_mapType; + m_interpolateType = m.m_interpolateType; +} + +PMMaterialMap::~PMMaterialMap( ) +{ +} + +void PMMaterialMap::serialize( QDomElement& e, QDomDocument& doc ) const +{ + switch( m_bitmapType ) + { + case BitmapGif: + e.setAttribute( "bitmap_type", "gif" ); + break; + case BitmapTga: + e.setAttribute( "bitmap_type", "tga" ); + break; + case BitmapIff: + e.setAttribute( "bitmap_type", "iff" ); + break; + case BitmapPpm: + e.setAttribute( "bitmap_type", "ppm" ); + break; + case BitmapPgm: + e.setAttribute( "bitmap_type", "pgm" ); + break; + case BitmapPng: + e.setAttribute( "bitmap_type", "png" ); + break; + case BitmapJpeg: + e.setAttribute( "bitmap_type", "jpeg" ); + break; + case BitmapTiff: + e.setAttribute( "bitmap_type", "tiff" ); + break; + case BitmapSys: + e.setAttribute( "bitmap_type", "sys" ); + break; + } + e.setAttribute( "file_name", m_bitmapFile ); + e.setAttribute( "once", m_once ); + switch( m_mapType ) + { + case MapPlanar: + e.setAttribute( "map_type", "planar" ); + break; + case MapSpherical: + e.setAttribute( "map_type", "spherical" ); + break; + case MapCylindrical: + e.setAttribute( "map_type", "cylindrical" ); + break; + case MapToroidal: + e.setAttribute( "map_type", "toroidal" ); + break; + } + switch( m_interpolateType ) + { + case InterpolateNone: + e.setAttribute( "interpolate", "none" ); + break; + case InterpolateBilinear: + e.setAttribute( "interpolate", "bilinear" ); + break; + case InterpolateNormalized: + e.setAttribute( "interpolate", "normalized" ); + break; + } + Base::serialize( e, doc ); +} + +void PMMaterialMap::readAttributes( const PMXMLHelper& h ) +{ + QString str; + + str = h.stringAttribute( "bitmap_type", "sys" ); + if( str == "gif" ) + m_bitmapType = BitmapGif; + else if( str == "tga" ) + m_bitmapType = BitmapTga; + else if( str == "iff" ) + m_bitmapType = BitmapIff; + else if( str == "ppm" ) + m_bitmapType = BitmapPpm; + else if( str == "pgm" ) + m_bitmapType = BitmapPgm; + else if( str == "png" ) + m_bitmapType = BitmapPng; + else if( str == "jpeg" ) + m_bitmapType = BitmapJpeg; + else if( str == "tiff" ) + m_bitmapType = BitmapTiff; + else if( str == "sys" ) + m_bitmapType = BitmapSys; + + m_bitmapFile = h.stringAttribute( "file_name", bitmapFileDefault ); + m_once = h.boolAttribute( "once", onceDefault ); + + str = h.stringAttribute( "map_type", "planar" ); + if( str == "planar" ) + m_mapType = MapPlanar; + else if( str == "spherical" ) + m_mapType = MapSpherical; + else if( str == "cylindrical" ) + m_mapType = MapCylindrical; + else if( str == "toroidal" ) + m_mapType = MapToroidal; + + str = h.stringAttribute( "interpolate", "none" ); + if( str == "none" ) + m_interpolateType = InterpolateNone; + else if( str == "bilinear" ) + m_interpolateType = InterpolateBilinear; + else if( str == "normalized" ) + m_interpolateType = InterpolateNormalized; + + Base::readAttributes( h ); +} + +PMMetaObject* PMMaterialMap::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "MaterialMap", Base::metaObject( ), + createNewMaterialMap ); + + PMBitmapTypeProperty* bp = new PMBitmapTypeProperty( + "bitmapType", &PMMaterialMap::setBitmapType, &PMMaterialMap::bitmapType ); + bp->addEnumValue( "Gif", BitmapGif ); + bp->addEnumValue( "Tga", BitmapTga ); + bp->addEnumValue( "Iff", BitmapIff ); + bp->addEnumValue( "Ppm", BitmapPpm ); + bp->addEnumValue( "Pgm", BitmapPgm ); + bp->addEnumValue( "Png", BitmapPng ); + bp->addEnumValue( "Jpeg", BitmapJpeg ); + bp->addEnumValue( "Tiff", BitmapTiff ); + bp->addEnumValue( "Sys", BitmapSys ); + s_pMetaObject->addProperty( bp ); + + PMInterpolateTypeProperty* ip = new PMInterpolateTypeProperty( + "interpolateType", &PMMaterialMap::setInterpolateType, + &PMMaterialMap::interpolateType ); + ip->addEnumValue( "None", InterpolateNone ); + ip->addEnumValue( "Bilinear", InterpolateBilinear ); + ip->addEnumValue( "Normalized", InterpolateNormalized ); + s_pMetaObject->addProperty( ip ); + + PMMapTypeProperty* mp = new PMMapTypeProperty( + "mapType", &PMMaterialMap::setMapType, &PMMaterialMap::mapType ); + mp->addEnumValue( "Planar", MapPlanar ); + mp->addEnumValue( "Spherical", MapSpherical ); + mp->addEnumValue( "Cylindrical", MapCylindrical ); + mp->addEnumValue( "Toroidal", MapToroidal ); + s_pMetaObject->addProperty( mp ); + + s_pMetaObject->addProperty( + new PMMaterialMapProperty( "bitmapFile", &PMMaterialMap::setBitmapFileName, + &PMMaterialMap::bitmapFile ) ); + s_pMetaObject->addProperty( + new PMMaterialMapProperty( "once", &PMMaterialMap::enableOnce, &PMMaterialMap::isOnceEnabled ) ); + } + return s_pMetaObject; +} + +void PMMaterialMap::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMMaterialMap::description( ) const +{ + return i18n( "material map" ); +} + +void PMMaterialMap::setBitmapType( PMBitmapType c ) +{ + if( c != m_bitmapType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMBitmapTypeID, m_bitmapType ); + m_bitmapType = c; + } +} + +void PMMaterialMap::setBitmapFileName( const QString& c ) +{ + if( c != m_bitmapFile ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMBitmapFileID, m_bitmapFile ); + m_bitmapFile = c; + } +} + +void PMMaterialMap::setMapType( PMMapType c ) +{ + if( c != m_mapType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMMapTypeID, m_mapType ); + m_mapType = c; + } +} + +void PMMaterialMap::setInterpolateType( PMInterpolateType c ) +{ + if( c != m_interpolateType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMInterpolateID, m_interpolateType ); + m_interpolateType = c; + } +} + +void PMMaterialMap::enableOnce( bool c ) +{ + if( c != m_once ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMOnceID, m_once ); + m_once = c; + } +} + +PMDialogEditBase* PMMaterialMap::editWidget( QWidget* parent ) const +{ + return new PMMaterialMapEdit( parent ); +} + +void PMMaterialMap::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMBitmapTypeID: + setBitmapType( ( PMBitmapType )data->intData( ) ); + break; + case PMBitmapFileID: + setBitmapFileName( data->stringData( ) ); + break; + case PMOnceID: + enableOnce( data->boolData( ) ); + break; + case PMMapTypeID: + setMapType( ( PMMapType )data->intData( ) ); + break; + case PMInterpolateID: + setInterpolateType( ( PMInterpolateType )data->intData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMMaterialMap::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmmaterialmap.h b/kpovmodeler/pmmaterialmap.h new file mode 100644 index 00000000..c6713e9f --- /dev/null +++ b/kpovmodeler/pmmaterialmap.h @@ -0,0 +1,153 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Passos Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMMATERIALMAP_H +#define PMMATERIALMAP_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmnamedobject.h" +#include "pmpalettevalue.h" + +/** + * Class for povray material maps. + */ + +class PMMaterialMap : public PMNamedObject +{ + typedef PMNamedObject Base; +public: + /** + * The bitmap type + */ + enum PMBitmapType { BitmapGif, BitmapTga, BitmapIff, BitmapPpm, + BitmapPgm, BitmapPng, BitmapJpeg, BitmapTiff, + BitmapSys }; + /** + * The interpolate method + */ + enum PMInterpolateType { InterpolateNone, InterpolateBilinear, + InterpolateNormalized }; + /** + * The mapping method + */ + enum PMMapType { MapPlanar, MapSpherical, MapCylindrical, + MapToroidal }; + + + /** + * Creates a PMMaterialMap + */ + PMMaterialMap( PMPart* part ); + /** + * Copy constructor + */ + PMMaterialMap( const PMMaterialMap& m ); + /** + * deletes the PMMaterialMap + */ + virtual ~PMMaterialMap( ); + + /** */ + virtual PMObject* copy( ) const { return new PMMaterialMap( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual QString pixmap( ) const { return QString( "pmmaterialmap" ); } + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMMaterialMapEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + + /** + * Gets the bitmap type + */ + PMBitmapType bitmapType( ) const { return m_bitmapType; } + /** + * Gets the bitmap file name + */ + QString bitmapFile( ) const { return m_bitmapFile; } + /** + * Returns true if once is enabled + */ + bool isOnceEnabled( ) const { return m_once; } + /** + * Gets the bitmap file type + */ + PMMapType mapType( ) const { return m_mapType; } + /** + * Gets the interpolate method type + */ + PMInterpolateType interpolateType( ) const { return m_interpolateType; } + + + /** + * Sets the bumpmap type + */ + void setBitmapType( PMBitmapType c ); + /** + * Sets the bitmap file name*/ + void setBitmapFileName( const QString& c ); + /** + * Sets if the bitmap should be mapped once + */ + void enableOnce( bool c ); + /** + * Sets the mapping method + */ + void setMapType( const PMMapType c ); + /** + * Sets the interpolating method + */ + void setInterpolateType( PMInterpolateType c ); + /** */ + virtual void restoreMemento( PMMemento* s ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMMaterialMapMementoID { PMBitmapTypeID, PMBitmapFileID, + PMOnceID, PMMapTypeID, PMInterpolateID }; + /** + * MaterialMap type + */ + PMBitmapType m_bitmapType; + QString m_bitmapFile; + bool m_once; + PMMapType m_mapType; + PMInterpolateType m_interpolateType; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmmaterialmapedit.cpp b/kpovmodeler/pmmaterialmapedit.cpp new file mode 100644 index 00000000..d50e3d7b --- /dev/null +++ b/kpovmodeler/pmmaterialmapedit.cpp @@ -0,0 +1,299 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Passos Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmmaterialmapedit.h" +#include "pmmaterialmap.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" +#include "pmpalettevalueedit.h" +#include "pmvector.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +PMMaterialMapEdit::PMMaterialMapEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMMaterialMapEdit::createTopWidgets( ) +{ + QLabel* lbl; + QHBoxLayout* hl; + + Base::createTopWidgets( ); + + hl = new QHBoxLayout( topLayout( ) ); + lbl = new QLabel( i18n( "File type:" ), this ); + m_pImageFileTypeEdit = new QComboBox( this ); + m_pImageFileTypeEdit->insertItem( "gif" ); + m_pImageFileTypeEdit->insertItem( "tga" ); + m_pImageFileTypeEdit->insertItem( "iff" ); + m_pImageFileTypeEdit->insertItem( "ppm" ); + m_pImageFileTypeEdit->insertItem( "pgm" ); + m_pImageFileTypeEdit->insertItem( "png" ); + m_pImageFileTypeEdit->insertItem( "jpeg" ); + m_pImageFileTypeEdit->insertItem( "tiff" ); + m_pImageFileTypeEdit->insertItem( "sys" ); + hl->addWidget( lbl ); + hl->addWidget( m_pImageFileTypeEdit ); + + hl = new QHBoxLayout( topLayout( ) ); + lbl = new QLabel( i18n( "File name:" ), this ); + m_pImageFileNameEdit = new QLineEdit( this ); + m_pImageFileNameBrowse = new QPushButton( this ); + m_pImageFileNameBrowse->setPixmap( SmallIcon( "fileopen" ) ); + hl->addWidget( lbl ); + hl->addWidget( m_pImageFileNameEdit ); + hl->addWidget( m_pImageFileNameBrowse ); + hl->addStretch( 1 ); + + m_pOnceEdit = new QCheckBox( i18n( "Once" ), this ); + topLayout( )->addWidget( m_pOnceEdit ); + + hl = new QHBoxLayout( topLayout( ) ); + lbl = new QLabel( i18n( "Interpolate:" ), this ); + m_pInterpolateTypeEdit = new QComboBox( this ); + m_pInterpolateTypeEdit->insertItem( i18n( "None" ) ); + m_pInterpolateTypeEdit->insertItem( i18n( "Bilinear" ) ); + m_pInterpolateTypeEdit->insertItem( i18n( "Normalized" ) ); + hl->addWidget( lbl ); + hl->addWidget( m_pInterpolateTypeEdit ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + lbl = new QLabel( i18n( "Map type:" ), this ); + m_pMapTypeEdit = new QComboBox( this ); + m_pMapTypeEdit->insertItem( i18n( "Planar" ) ); + m_pMapTypeEdit->insertItem( i18n( "Spherical" ) ); + m_pMapTypeEdit->insertItem( i18n( "Cylindrical" ) ); + m_pMapTypeEdit->insertItem( i18n( "Toroidal" ) ); + hl->addWidget( lbl ); + hl->addWidget( m_pMapTypeEdit ); + hl->addStretch( 1 ); + + connect( m_pImageFileTypeEdit, SIGNAL( activated( int ) ), SLOT( slotImageFileTypeChanged( int ) ) ); + connect( m_pMapTypeEdit, SIGNAL( activated( int ) ), SLOT( slotMapTypeChanged( int ) ) ); + connect( m_pInterpolateTypeEdit, SIGNAL( activated( int ) ), SLOT( slotInterpolateTypeChanged( int ) ) ); + connect( m_pImageFileNameBrowse, SIGNAL( clicked( ) ), SLOT( slotImageFileBrowseClicked( ) ) ); + connect( m_pImageFileNameEdit, SIGNAL( textChanged( const QString& ) ), SLOT( slotImageFileNameChanged( const QString& ) ) ); + connect( m_pOnceEdit, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMMaterialMapEdit::displayObject( PMObject* o ) +{ + bool readOnly; + + if( o->isA( "MaterialMap" ) ) + { + m_pDisplayedObject = ( PMMaterialMap* ) o; + readOnly = m_pDisplayedObject->isReadOnly( ); + + switch( m_pDisplayedObject->bitmapType( ) ) + { + case PMMaterialMap::BitmapGif: + m_pImageFileTypeEdit->setCurrentItem( 0 ); + break; + case PMMaterialMap::BitmapTga: + m_pImageFileTypeEdit->setCurrentItem( 1 ); + break; + case PMMaterialMap::BitmapIff: + m_pImageFileTypeEdit->setCurrentItem( 2 ); + break; + case PMMaterialMap::BitmapPpm: + m_pImageFileTypeEdit->setCurrentItem( 3 ); + break; + case PMMaterialMap::BitmapPgm: + m_pImageFileTypeEdit->setCurrentItem( 4 ); + break; + case PMMaterialMap::BitmapPng: + m_pImageFileTypeEdit->setCurrentItem( 5 ); + break; + case PMMaterialMap::BitmapJpeg: + m_pImageFileTypeEdit->setCurrentItem( 6 ); + break; + case PMMaterialMap::BitmapTiff: + m_pImageFileTypeEdit->setCurrentItem( 7 ); + break; + case PMMaterialMap::BitmapSys: + m_pImageFileTypeEdit->setCurrentItem( 8 ); + break; + } + m_pImageFileTypeEdit->setEnabled( !readOnly ); + + switch( m_pDisplayedObject->interpolateType( ) ) + { + case PMMaterialMap::InterpolateNone: + m_pInterpolateTypeEdit->setCurrentItem( 0 ); + break; + case PMMaterialMap::InterpolateBilinear: + m_pInterpolateTypeEdit->setCurrentItem( 1); + break; + case PMMaterialMap::InterpolateNormalized: + m_pInterpolateTypeEdit->setCurrentItem( 2 ); + break; + } + m_pInterpolateTypeEdit->setEnabled( !readOnly ); + + switch( m_pDisplayedObject->mapType( ) ) + { + case PMMaterialMap::MapPlanar: + m_pMapTypeEdit->setCurrentItem( 0 ); + break; + case PMMaterialMap::MapSpherical: + m_pMapTypeEdit->setCurrentItem( 1 ); + break; + case PMMaterialMap::MapCylindrical: + m_pMapTypeEdit->setCurrentItem( 2 ); + break; + case PMMaterialMap::MapToroidal: + m_pMapTypeEdit->setCurrentItem( 3 ); + break; + } + m_pMapTypeEdit->setEnabled( !readOnly ); + + m_pImageFileNameEdit->setText( m_pDisplayedObject->bitmapFile( ) ); + m_pImageFileNameEdit->setEnabled( !readOnly ); + m_pOnceEdit->setChecked( m_pDisplayedObject->isOnceEnabled( ) ); + m_pOnceEdit->setEnabled( !readOnly ); + + Base::displayObject( o ); + } + +} + +void PMMaterialMapEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + switch( m_pImageFileTypeEdit->currentItem( ) ) + { + case 0: + m_pDisplayedObject->setBitmapType( PMMaterialMap::BitmapGif ); + break; + case 1: + m_pDisplayedObject->setBitmapType( PMMaterialMap::BitmapTga ); + break; + case 2: + m_pDisplayedObject->setBitmapType( PMMaterialMap::BitmapIff ); + break; + case 3: + m_pDisplayedObject->setBitmapType( PMMaterialMap::BitmapPpm ); + break; + case 4: + m_pDisplayedObject->setBitmapType( PMMaterialMap::BitmapPgm ); + break; + case 5: + m_pDisplayedObject->setBitmapType( PMMaterialMap::BitmapPng ); + break; + case 6: + m_pDisplayedObject->setBitmapType( PMMaterialMap::BitmapJpeg ); + break; + case 7: + m_pDisplayedObject->setBitmapType( PMMaterialMap::BitmapTiff ); + break; + case 8: + m_pDisplayedObject->setBitmapType( PMMaterialMap::BitmapSys ); + break; + } + + switch( m_pInterpolateTypeEdit->currentItem( ) ) + { + case 0: + m_pDisplayedObject->setInterpolateType( PMMaterialMap::InterpolateNone ); + break; + case 1: + m_pDisplayedObject->setInterpolateType( PMMaterialMap::InterpolateBilinear ); + break; + case 2: + m_pDisplayedObject->setInterpolateType( PMMaterialMap::InterpolateNormalized ); + break; + } + + switch( m_pMapTypeEdit->currentItem( ) ) + { + case 0: + m_pDisplayedObject->setMapType( PMMaterialMap::MapPlanar ); + break; + case 1: + m_pDisplayedObject->setMapType( PMMaterialMap::MapSpherical ); + break; + case 2: + m_pDisplayedObject->setMapType( PMMaterialMap::MapCylindrical ); + break; + case 3: + m_pDisplayedObject->setMapType( PMMaterialMap::MapToroidal ); + break; + } + + m_pDisplayedObject->setBitmapFileName( m_pImageFileNameEdit->text( ) ); + m_pDisplayedObject->enableOnce( m_pOnceEdit->isChecked( ) ); + } +} + +bool PMMaterialMapEdit::isDataValid( ) +{ + return Base::isDataValid( ); +} + +void PMMaterialMapEdit::slotInterpolateTypeChanged( const int /*a*/ ) +{ + emit dataChanged( ); +} + +void PMMaterialMapEdit::slotImageFileTypeChanged( const int /*a*/ ) +{ + emit dataChanged( ); +} + +void PMMaterialMapEdit::slotMapTypeChanged( const int /*a*/ ) +{ + emit dataChanged( ); +} + +void PMMaterialMapEdit::slotImageFileNameChanged( const QString& /*a*/ ) +{ + emit dataChanged( ); +} + +void PMMaterialMapEdit::slotImageFileBrowseClicked( ) +{ + QString str = KFileDialog::getOpenFileName( QString::null, QString::null ); + + if( !str.isEmpty() ) + { + m_pImageFileNameEdit->setText( str ); + emit dataChanged( ); + } +} + +#include "pmmaterialmapedit.moc" diff --git a/kpovmodeler/pmmaterialmapedit.h b/kpovmodeler/pmmaterialmapedit.h new file mode 100644 index 00000000..f6ffa7f0 --- /dev/null +++ b/kpovmodeler/pmmaterialmapedit.h @@ -0,0 +1,81 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Passos Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMMATERIALMAPEDIT_H +#define PMMATERIALMAPEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMMaterialMap; +class QComboBox; +class PMFloatEdit; +class PMIntEdit; +class QLabel; +class QCheckBox; +class QWidget; +class QLineEdit; +class QPushButton; + +/** + * Dialog edit class for @ref PMMaterialMap. + */ +class PMMaterialMapEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMMaterialMapEdit with parent and name + */ + PMMaterialMapEdit( QWidget* parent, const char* name = 0 ); + /** */ + virtual void displayObject( PMObject* o ); + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); +private slots: + /** */ + void slotImageFileTypeChanged( int a ); + /** */ + void slotMapTypeChanged( int a ); + /** */ + void slotInterpolateTypeChanged( int a ); + /** */ + void slotImageFileNameChanged( const QString& a ); + /** */ + void slotImageFileBrowseClicked( ); +private: + PMMaterialMap* m_pDisplayedObject; + QComboBox* m_pImageFileTypeEdit; + QLineEdit* m_pImageFileNameEdit; + QPushButton* m_pImageFileNameBrowse; + QCheckBox* m_pOnceEdit; + QComboBox* m_pMapTypeEdit; + QComboBox* m_pInterpolateTypeEdit; +}; + +#endif diff --git a/kpovmodeler/pmmath.cpp b/kpovmodeler/pmmath.cpp new file mode 100644 index 00000000..8aedab76 --- /dev/null +++ b/kpovmodeler/pmmath.cpp @@ -0,0 +1,67 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +// some helper functions + +#include "pmmath.h" +#include + +bool approx( double v1, double v2, double epsilon ) +{ + return fabs( v1 - v2 ) < epsilon; +} + +bool approxZero( double v, double epsilon ) +{ + return fabs( v ) < epsilon; +} + +double rad2Deg( double rad ) +{ + return rad / M_PI * 180.0; +} + +double deg2Rad( double deg ) +{ + return deg * M_PI / 180.0; +} + +double pmatan( double s, double c ) +{ + double a; + if( approxZero( c ) ) + { + if( s > 0 ) + a = M_PI_2; + else + a = -M_PI_2; + } + else + a = atan2( s, c ); + + return a; +} + +int pmpot( int x, int y ) +{ + int i; + int result = 1; + for( i = 0; i < y; i++ ) + result *= x; + return result; +} diff --git a/kpovmodeler/pmmath.h b/kpovmodeler/pmmath.h new file mode 100644 index 00000000..520b8b6d --- /dev/null +++ b/kpovmodeler/pmmath.h @@ -0,0 +1,48 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMMATH_H +#define PMMATH_H + +/** + * Same as ( fabs( v1 - v2 ) < epsilon ) + */ +bool approx( double v1, double v2, double epsilon = 1e-6 ); +/** + * Same as ( fabs( v ) < epsilon ) + */ +bool approxZero( double v, double epsilon = 1e-6 ); +/** + * Converts rad to deg + */ +double rad2Deg( double rad ); +/** + * Converts deg to rad + */ +double deg2Rad( double deg ); +/** + * Returns the atan( s / c ) with all special cases + */ +double pmatan( double s, double c ); +/** + * Returns x^y. y has to be >= 0 + */ +int pmpot( int x, int y ); + +#endif diff --git a/kpovmodeler/pmmatrix.cpp b/kpovmodeler/pmmatrix.cpp new file mode 100644 index 00000000..217672e5 --- /dev/null +++ b/kpovmodeler/pmmatrix.cpp @@ -0,0 +1,442 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include + +#include "pmmatrix.h" +#include "pmvector.h" +#include "pmdebug.h" + +#include + +PMMatrix::PMMatrix( ) +{ + int i; + + for( i = 0; i < 16; i++ ) + m_elements[i] = 0; +} + +PMMatrix::~PMMatrix( ) +{ +} + +PMMatrix& PMMatrix::operator= ( const PMMatrix& m ) +{ + int i; + for( i=0; i<16; i++ ) + m_elements[i] = m.m_elements[i]; + + return *this; +} + +PMMatrix PMMatrix::identity( ) +{ + PMMatrix newMatrix; + int i; + + for( i=0; i<4; i++ ) + newMatrix[i][i] = 1.0; + + return newMatrix; +} + +PMMatrix PMMatrix::translation( double x, double y, double z ) +{ + PMMatrix newMatrix; + newMatrix[3][0] = x; + newMatrix[3][1] = y; + newMatrix[3][2] = z; + newMatrix[0][0] = 1; + newMatrix[1][1] = 1; + newMatrix[2][2] = 1; + newMatrix[3][3] = 1; + + return newMatrix; +} + +PMMatrix PMMatrix::scale( double x, double y, double z ) +{ + PMMatrix newMatrix; + newMatrix[0][0] = x; + newMatrix[1][1] = y; + newMatrix[2][2] = z; + newMatrix[3][3] = 1; + + return newMatrix; +} + +PMMatrix PMMatrix::rotation( double x, double y, double z ) +{ + PMMatrix newMatrix; + double sinx, siny, sinz, cosx, cosy, cosz; + sinx = sin( x ); + siny = sin( y ); + sinz = sin( z ); + cosx = cos( x ); + cosy = cos( y ); + cosz = cos( z ); + + newMatrix[0][0] = cosz*cosy; + newMatrix[1][0] = -sinz*cosx + cosz*siny*sinx; + newMatrix[2][0] = sinz*sinx + cosz*siny*cosx; + newMatrix[0][1] = sinz*cosy; + newMatrix[1][1] = cosz*cosx + sinz*siny*sinx; + newMatrix[2][1] = -cosz*sinx + sinz*siny*cosx; + newMatrix[0][2] = -siny; + newMatrix[1][2] = cosy*sinx; + newMatrix[2][2] = cosy*cosx; + newMatrix[3][3] = 1; + + return newMatrix; +} + +PMMatrix PMMatrix::rotation( const PMVector& n, double a ) +{ + PMMatrix result( PMMatrix::identity( ) ); + double rx, ry; + + if( n.size( ) == 3 ) + { + rx = pmatan( n.y( ), n.z( ) ); + ry = - pmatan( n.x( ), sqrt( n.y( ) * n.y( ) + n.z( ) * n.z( ) ) ); + + result = rotation( -rx, 0.0, 0.0 ) * rotation( 0.0, -ry, 0.0 ) + * rotation( rx, ry, a ); + + } + else + kdError( PMArea ) << "Wrong size in PMMatrix::rotation( )\n"; + + return result; +} + +PMMatrix PMMatrix::viewTransformation( const PMVector& eye, + const PMVector& lookAt, + const PMVector& up ) +{ + PMMatrix result; + PMVector x, y, z; + GLdouble len; + int i; + + // create rotation matrix + z = eye - lookAt; + len = z.abs( ); + if( !approxZero( len ) ) + z /= len; + + y = up; + x = PMVector::cross( y, z ); + y = PMVector::cross( z, x ); + + // normalize vectors + len = x.abs( ); + if( !approxZero( len ) ) + x /= len; + + len = y.abs( ); + if( !approxZero( len ) ) + y /= len; + + for( i = 0; i < 3; i++ ) + { + result[i][0] = x[i]; + result[i][1] = y[i]; + result[i][2] = z[i]; + result[3][i] = 0.0; + result[i][3] = 0.0; + } + result[3][3] = 1.0; + + // Translate eye to origin + return result * translation( -eye[0], -eye[1], -eye[2] ); +} + +void PMMatrix::toRotation( double* x, double* y, double* z ) +{ + PMMatrix& m = *this; + + if( !approx( fabs( m[0][2] ), 1.0 ) ) + { + double cosy; + // | m[0][2] | != 1 + // sin(y) != 1.0, cos(y) != 0.0 + *y = asin( - m[0][2] ); + cosy = cos( *y ); + + // sign of cosy is important! + *x = pmatan( m[1][2] / cosy, m[2][2] / cosy ); + *z = pmatan( m[0][1] / cosy, m[0][0] / cosy ); + } + else if( m[0][2] < 0 ) + { + // m[0][2] == -1 + // sin(y) == 1, cos(y) == 0 + // z and x are dependent of each other, assume z = 0 + + double zminusx = pmatan( m[2][1], m[1][1] ); + + *y = M_PI_2; + *z = 0.0; + *x = - zminusx; + } + else + { + // m[0][2] == 1 + // sin(y) == -1, cos(y) == 0 + // z and x are dependent of each other, assume z = 0 + + double zplusx = pmatan( -m[2][1], m[1][1] ); + + *y = -M_PI_2; + *z = 0.0; + *x = zplusx; + } +} + +PMMatrix PMMatrix::modelviewMatrix( ) +{ + PMMatrix result; + glGetDoublev( GL_MODELVIEW_MATRIX, result.m_elements ); + return result; +} + +double PMMatrix::det( ) const +{ + PMMatrix tmp( *this ); + double result = 1.0, help; + int i, k, e, row; + + // make a upper triangular matrix + for( i=0; i<4; i++ ) + { + row = tmp.notNullElementRow( i ); + if( row == -1 ) + return 0; + if( row != i ) + { + tmp.exchangeRows( i, row ); + result = -result; + } + + result *= tmp[i][i]; + for( k=i+1; k<4; k++ ) + { + help = tmp[i][k]; + for( e=0; e<4; e++ ) + tmp[e][k] -= tmp[e][i] * help/tmp[i][i]; + } + } + return result; +} + +PMMatrix PMMatrix::inverse( ) const +{ + PMMatrix result( identity( ) ); + PMMatrix tmp( *this ); + int i, k, e, row; + double a; + + // uses the Gauss algorithm + // row operations to make tmp a identity matrix + // result matrix is then the inverse + for( i=0; i<4; i++ ) + { + row = tmp.notNullElementRow( i ); + if( row == -1 ) + return identity( ); + if( row != i ) + { + tmp.exchangeRows( i, row ); + result.exchangeRows( i, row ); + } + // tmp[i][i] != 0 + + a = tmp[i][i]; + for( e=0; e<4; e++ ) + { + result[e][i] /= a; + tmp[e][i] /= a; + } + // tmp[i][i] == 1 + + for( k=0; k<4; k++ ) + { + if( k != i ) + { + a = tmp[i][k]; + for( e=0; e<4; e++ ) + { + result[e][k] -= result[e][i] * a; + tmp[e][k] -= tmp[e][i] * a; + } + } + } + // tmp[!=i][i] == 0.0 + } + return result; +} + +void PMMatrix::exchangeRows( int r1, int r2 ) +{ + GLdouble help; + int i; + + for( i=0; i<4; i++ ) + { + help = (*this)[i][r1]; + (*this)[i][r1] = (*this)[i][r2]; + (*this)[i][r2] = help; + } +} + +int PMMatrix::notNullElementRow( const int index ) const +{ + int i, result = -1; + GLdouble max = 0.0, v; + + // choose the row with abs( ) = max + for( i=index; i<4; i++ ) + { + v = fabs((*this)[index][i]); + if( v > max ) + { + result = i; + max = v; + } + } + return result; +} + +PMMatrix& PMMatrix::operator*= ( const double d ) +{ + int i; + for( i=0; i<16; i++ ) + m_elements[i] *= d; + return *this; +} + +PMMatrix& PMMatrix::operator/= ( const double d ) +{ + int i; + if( approxZero( 0 ) ) + kdError( PMArea ) << "Division by zero in PMMatrix::operator/=" << "\n"; + else + for( i=0; i<16; i++ ) + m_elements[i] /= d; + return *this; +} + +PMMatrix& PMMatrix::operator*= ( const PMMatrix& m ) +{ + *this = *this * m; + return *this; +} + +PMMatrix operator- ( const PMMatrix& m ) +{ + PMMatrix result; + int r,c; + + for( r=0; r<4; r++ ) + for( c=0; c<4; c++ ) + result[c][r] = -m[c][r]; + return result; +} + +PMMatrix operator* ( const PMMatrix& m1, const PMMatrix& m2 ) +{ + PMMatrix result; + int r, c, i; + + for( r=0; r<4; r++ ) + for( c=0; c<4; c++ ) + for( i=0; i<4; i++ ) + result[c][r] += m1[i][r] * m2[c][i]; + return result; +} + +PMMatrix operator* ( const PMMatrix& m1, const double d ) +{ + PMMatrix result( m1 ); + result *= d; + return result; +} + +PMMatrix operator/ ( const PMMatrix& m1, const double d ) +{ + PMMatrix result( m1 ); + result /= d ; + return result; +} + +PMMatrix operator* ( const double d, const PMMatrix& m1 ) +{ + PMMatrix result( m1 ); + result *= d; + return result; +} + +#include +void PMMatrix::testOutput( ) +{ + int r, c; + + printf( "\n" ); + for( r=0; r<4; r++ ) + { + for( c=0; c<4; c++ ) + printf( "% 20.18f ", (*this)[c][r] ); + printf( "\n" ); + } +} + +QString PMMatrix::serializeXML( ) const +{ + QString result; + QTextStream str( &result, IO_WriteOnly ); + int i; + + for( i = 0; i < 16; i++ ) + { + if( i > 0 ) + str << ' '; + str << m_elements[i]; + } + + return result; +} + +bool PMMatrix::loadXML( const QString& str ) +{ + int i; + QString tmp( str ); + QTextStream s( &tmp, IO_ReadOnly ); + QString val; + bool ok; + + for( i = 0; i < 16; i++ ) + { + s >> val; + m_elements[i] = val.toDouble( &ok ); + if( !ok ) + return false; + } + return true; +} diff --git a/kpovmodeler/pmmatrix.h b/kpovmodeler/pmmatrix.h new file mode 100644 index 00000000..62747aea --- /dev/null +++ b/kpovmodeler/pmmatrix.h @@ -0,0 +1,188 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMMATRIX_H +#define PMMATRIX_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmmath.h" +#include "math.h" + +#include + +#include + +class PMVector; + +/** + * 4x4 matrix for transformations with homogenous coordinates + * + * Optimized for OpenGL. + */ +class PMMatrix +{ +public: + /** + * Creates a zero matrix + */ + PMMatrix( ); + /** + * Deletes the matrix + */ + ~PMMatrix( ); + /** + * Assigns m to the matrix + */ + PMMatrix& operator= ( const PMMatrix& m ); + /** + * Creates an identity matrix + */ + static PMMatrix identity( ); + /** + * Creates a matrix for translation. + */ + static PMMatrix translation( double x, double y, double z ); + /** + * Creates a matrix for rotations. Rotation first around the x, then y + * and then around the z axis. + * + * x, y and z in rad + */ + static PMMatrix rotation( double x, double y, double z ); + /** + * Creates a matrix for rotation around the direction n with angle a. + * + * a in rad. + */ + static PMMatrix rotation( const PMVector& n, double a ); + /** + * Creates a viewing matrix. + * + * The viewpoint is specified by the parameter eye. The parameter + * lookAt specifies any point along the line of sight. The up vector + * indicate which direction is up. + */ + static PMMatrix viewTransformation( const PMVector& eye, + const PMVector& lookAt, + const PMVector& up ); + /** + * Backwards calculate the rotations from the matrix + */ + void toRotation( double* x, double* y, double* z ); + + /** + * Creates a matrix for scale. + */ + static PMMatrix scale( double x, double y, double z ); + /** + * Returns the current gl modelview matrix + */ + static PMMatrix modelviewMatrix( ); + + /** + * Returns a pointer to the column (!) at position index. + * That means matrix[i][j] is the element at column i and row j*/ + GLdouble* operator[] ( int index ) { return &( m_elements[index*4] ); } + /** + * Returns a pointer to the column (!) at position index. + * That means matrix[i][j] is the element at column i and row j*/ + const GLdouble* operator[] ( int index ) const + { return &(m_elements[index*4]); } + /** + * Returns true if an inverse matrix can be calculated + */ + bool canBuildInverse( ) const { return ! approxZero( det( ) ); } + /** + * Returns the inverse matrix if possible, otherwise a identity matrix + */ + PMMatrix inverse( ) const; + /** + * Returns the determinant of the matrix + */ + double det( ) const; + /** + * Multiplies m to the matrix from the right side + */ + PMMatrix& operator*= ( const PMMatrix& m ); + /** + * Multiplies each element with d + */ + PMMatrix& operator*= ( const double d ); + /** + * Divides each element by d + */ + PMMatrix& operator/= ( const double d ); + + /** + * Returns a matrix with negated elements + */ + friend PMMatrix operator- ( const PMMatrix& m ); + /** + * Multiplies m2 with m1 from the right side (m1*m2)*/ + friend PMMatrix operator* ( const PMMatrix& m1, const PMMatrix& m2 ); + /** + * Multiplies d to all elements + */ + friend PMMatrix operator* ( const PMMatrix& m, const double d ); + /** + * Multiplies d to all elements + */ + friend PMMatrix operator* ( const GLdouble d, const PMMatrix& m ); + /** + * Divides all elements by d + */ + friend PMMatrix operator/ ( const PMMatrix& m, const double d ); + + /** + * Only for tests + */ + void testOutput( ); + /** + * Returns a pointer to the data. Can be used in glMultMatrixd + */ + const GLdouble* data( ) const { return m_elements; } + + /** + * Returns a string for xml output + */ + QString serializeXML( ) const; + /** + * loads the vector data from the xml string + */ + bool loadXML( const QString& str ); +private: + /** + * Exchanges two rows + */ + void exchangeRows( int r1, int r2 ); + /** + * Finds a row with not zero element in column index. Begins to + * search in row at position index. Used for det() and inverse() + * + * Returns -1 if all rows are zero in that column + */ + int notNullElementRow( const int index ) const; + + GLdouble m_elements[16]; +}; + +#endif diff --git a/kpovmodeler/pmmedia.cpp b/kpovmodeler/pmmedia.cpp new file mode 100644 index 00000000..e5229d47 --- /dev/null +++ b/kpovmodeler/pmmedia.cpp @@ -0,0 +1,480 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmmedia.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmmediaedit.h" +#include "pmcolor.h" + +#include + +const int methodDefault = 1; +const int intervalsDefault = 10; +const int samplesMinDefault = 1; +const int samplesMaxDefault = 1; +const double confidenceDefault = 0.9; +const double varianceDefault = 0.0078125; +const double ratioDefault = 0.9; +const int aaLevelDefault = 4; +const double aaThresholdDefault = 0.1; +const PMColor absorptionDefault = PMColor( 0.0, 0.0, 0.0 ); +const PMColor emissionDefault = PMColor( 0.0, 0.0, 0.0 ); +const int scatteringTypeDefault = 0; +const PMColor scatteringColorDefault = PMColor( 0.0, 0.0, 0.0 ); +const double scatteringEccentricityDefault = 0; +const double scatteringExtinctionDefault = 1.0; + +PMDefinePropertyClass( PMMedia, PMMediaProperty ); +PMMetaObject* PMMedia::s_pMetaObject = 0; +PMObject* createNewMedia( PMPart* part ) +{ + return new PMMedia( part ); +} + +PMMedia::PMMedia( PMPart* part ) + : Base( part ) +{ + m_method = methodDefault; + m_intervals = intervalsDefault; + m_samplesMin = samplesMinDefault; + m_samplesMax = samplesMaxDefault; + m_confidence = confidenceDefault; + m_variance = varianceDefault; + m_ratio = ratioDefault; + m_aaLevel = aaLevelDefault; + m_aaThreshold = aaThresholdDefault; + m_absorption = absorptionDefault; + m_emission = emissionDefault; + m_scatteringType = scatteringTypeDefault; + m_scatteringColor = scatteringColorDefault; + m_scatteringEccentricity = scatteringEccentricityDefault; + m_scatteringExtinction = scatteringExtinctionDefault; + m_enableAbsorption = false; + m_enableEmission = false; + m_enableScattering = false; +} + +PMMedia::PMMedia( const PMMedia& m ) + : Base( m ) +{ + m_method = m.m_method; + m_intervals = m.m_intervals; + m_samplesMin = m.m_samplesMin; + m_samplesMax = m.m_samplesMax; + m_aaLevel = m.m_aaLevel; + m_confidence = m.m_confidence; + m_variance = m.m_variance; + m_ratio = m.m_ratio; + m_aaThreshold = m.m_aaThreshold; + m_absorption = m.m_absorption; + m_emission = m.m_emission; + m_scatteringType = m.m_scatteringType; + m_scatteringColor = m.m_scatteringColor; + m_scatteringEccentricity = m.m_scatteringEccentricity; + m_scatteringExtinction = m.m_scatteringExtinction; + m_enableAbsorption = m.m_enableAbsorption; + m_enableEmission = m.m_enableEmission; + m_enableScattering = m.m_enableScattering; +} + +PMMedia::~PMMedia( ) +{ +} + +PMMetaObject* PMMedia::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Media", Base::metaObject( ), + createNewMedia ); + s_pMetaObject->addProperty( + new PMMediaProperty( "method", &PMMedia::setMethod, &PMMedia::method ) ); + s_pMetaObject->addProperty( + new PMMediaProperty( "intervals", &PMMedia::setIntervals, &PMMedia::intervals ) ); + s_pMetaObject->addProperty( + new PMMediaProperty( "samplesMin", &PMMedia::setSamplesMin, &PMMedia::samplesMin ) ); + s_pMetaObject->addProperty( + new PMMediaProperty( "samplesMax", &PMMedia::setSamplesMax, &PMMedia::samplesMax ) ); + s_pMetaObject->addProperty( + new PMMediaProperty( "aaLevel", &PMMedia::setAALevel, &PMMedia::aaLevel ) ); + s_pMetaObject->addProperty( + new PMMediaProperty( "confidence", &PMMedia::setConfidence, &PMMedia::confidence ) ); + s_pMetaObject->addProperty( + new PMMediaProperty( "variance", &PMMedia::setVariance, &PMMedia::variance ) ); + s_pMetaObject->addProperty( + new PMMediaProperty( "ratio", &PMMedia::setRatio, &PMMedia::ratio ) ); + s_pMetaObject->addProperty( + new PMMediaProperty( "aaThreshold", &PMMedia::setAAThreshold, &PMMedia::aaThreshold ) ); + s_pMetaObject->addProperty( + new PMMediaProperty( "absorption", &PMMedia::setAbsorption, &PMMedia::absorption ) ); + s_pMetaObject->addProperty( + new PMMediaProperty( "emission", &PMMedia::setEmission, &PMMedia::emission ) ); + s_pMetaObject->addProperty( + new PMMediaProperty( "scatteringType", &PMMedia::setScatteringType, &PMMedia::scatteringType ) ); + s_pMetaObject->addProperty( + new PMMediaProperty( "scatteringColor", &PMMedia::setScatteringColor, &PMMedia::scatteringColor ) ); + s_pMetaObject->addProperty( + new PMMediaProperty( "scatteringExtinction", &PMMedia::setScatteringExtinction, &PMMedia::scatteringExtinction ) ); + s_pMetaObject->addProperty( + new PMMediaProperty( "scatteringEccentricity", &PMMedia::setScatteringEccentricity, &PMMedia::scatteringEccentricity ) ); + + s_pMetaObject->addProperty( + new PMMediaProperty( "absorptionEnabled", &PMMedia::enableAbsorption, &PMMedia::isAbsorptionEnabled ) ); + s_pMetaObject->addProperty( + new PMMediaProperty( "emissionEnabled", &PMMedia::enableEmission, &PMMedia::isEmissionEnabled ) ); + s_pMetaObject->addProperty( + new PMMediaProperty( "scatteringEnabled", &PMMedia::enableScattering, &PMMedia::isScatteringEnabled ) ); + } + return s_pMetaObject; +} + +void PMMedia::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMMedia::description( ) const +{ + return i18n( "media" ); +} + +void PMMedia::serialize( QDomElement& e, QDomDocument& doc ) const +{ + Base::serialize( e, doc ); + e.setAttribute( "enable_absorption", m_enableAbsorption ); + e.setAttribute( "enable_emission", m_enableEmission ); + e.setAttribute( "enable_scattering", m_enableScattering ); + e.setAttribute( "method", m_method ); + e.setAttribute( "intervals", m_intervals ); + e.setAttribute( "samples_min", m_samplesMin ); + e.setAttribute( "samples_max", m_samplesMax ); + e.setAttribute( "aa_level", m_aaLevel ); + e.setAttribute( "confidence", m_confidence ); + e.setAttribute( "variance", m_variance ); + e.setAttribute( "ratio", m_ratio ); + e.setAttribute( "aa_threshold", m_aaThreshold ); + e.setAttribute( "absorption", m_absorption.serializeXML( ) ); + e.setAttribute( "emission", m_emission.serializeXML( ) ); + e.setAttribute( "scattering_type", m_scatteringType ); + e.setAttribute( "scattering_color", m_scatteringColor.serializeXML( ) ); + e.setAttribute( "scattering_eccentricity", m_scatteringEccentricity ); + e.setAttribute( "scattering_extinction", m_scatteringExtinction ); +} + +void PMMedia::readAttributes( const PMXMLHelper& h ) +{ + Base::readAttributes( h ); + m_enableAbsorption = h.boolAttribute( "enable_absorption", false ); + m_enableEmission = h.boolAttribute( "enable_emission", false ); + m_enableScattering = h.boolAttribute( "enable_scattering", false ); + m_method = h.intAttribute( "method", methodDefault ); + m_intervals = h.intAttribute( "intervals", intervalsDefault ); + m_samplesMin = h.intAttribute( "samples_min", samplesMinDefault ); + m_samplesMax = h.intAttribute( "samples_max", samplesMaxDefault ); + m_aaLevel = h.intAttribute( "aa_level", aaLevelDefault ); + m_confidence = h.doubleAttribute( "confidence", confidenceDefault ); + m_variance = h.doubleAttribute( "variance", varianceDefault ); + m_ratio = h.doubleAttribute( "ratio", ratioDefault ); + m_aaThreshold = h.doubleAttribute( "aa_threshold", aaThresholdDefault ); + m_absorption = h.colorAttribute( "absorption", absorptionDefault ); + m_emission = h.colorAttribute( "emission", emissionDefault ); + m_scatteringType = h.intAttribute( "scattering_type", scatteringTypeDefault ); + m_scatteringColor = h.colorAttribute( "scattering_color", scatteringColorDefault ); + m_scatteringEccentricity = h.doubleAttribute( "scattering_eccentricity", + scatteringEccentricityDefault ); + m_scatteringExtinction = h.doubleAttribute( "scattering_extinction", + scatteringExtinctionDefault ); +} + +void PMMedia::setMethod( int c ) +{ + if ( c < 1 ) + { + kdError( PMArea ) << "method is < 1 in PMMedia::setMethod\n"; + c = 1; + } + + if ( c > 3 ) + { + kdError( PMArea ) << "method is > 3 in PMMedia::setMethod\n"; + c = 3; + } + + if ( c != m_method ) + { + if ( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMMethodID, m_method ); + m_method = c; + } +} + +void PMMedia::setIntervals( int c ) +{ + if( c != m_intervals ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMIntervalsID, m_intervals ); + m_intervals = c; + } +} + +void PMMedia::setSamplesMin( int c ) +{ + if( c != m_samplesMin ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSamplesMinID, m_samplesMin ); + m_samplesMin = c; + } +} + +void PMMedia::setSamplesMax( int c ) +{ + if( c != m_samplesMax ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSamplesMaxID, m_samplesMax ); + m_samplesMax = c; + } +} + +void PMMedia::setAALevel( int c ) +{ + if ( c != m_aaLevel ) + { + if ( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAALevelID, m_aaLevel ); + m_aaLevel = c; + } +} + +void PMMedia::setConfidence( double c ) +{ + if( c != m_confidence ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMConfidenceID, m_confidence ); + m_confidence = c; + } +} + +void PMMedia::setVariance( double c ) +{ + if( c != m_variance ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMVarianceID, m_variance ); + m_variance = c; + } +} + +void PMMedia::setRatio( double c ) +{ + if( c != m_ratio ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRatioID, m_ratio ); + m_ratio = c; + } +} + +void PMMedia::setAAThreshold( double c ) +{ + if ( c != m_aaThreshold ) + { + if ( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAAThresholdID, m_aaThreshold ); + m_aaThreshold = c; + } +} + +void PMMedia::setAbsorption( const PMColor& c ) +{ + if( c != m_absorption ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAbsorptionID, m_absorption ); + m_absorption = c; + } +} + +void PMMedia::setEmission( const PMColor& c ) +{ + if( c != m_emission ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEmissionID, m_emission ); + m_emission = c; + } +} + +void PMMedia::setScatteringType( int c ) +{ + if( c != m_scatteringType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMScatteringTypeID, m_scatteringType ); + m_scatteringType = c; + } +} + +void PMMedia::setScatteringColor( const PMColor& c ) +{ + if( c != m_scatteringColor ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMScatteringColorID, m_scatteringColor ); + m_scatteringColor = c; + } +} + +void PMMedia::setScatteringEccentricity( double c ) +{ + if( c != m_scatteringEccentricity ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMScatteringEccentricityID, m_scatteringEccentricity ); + m_scatteringEccentricity = c; + } +} + +void PMMedia::setScatteringExtinction( double c ) +{ + if( c != m_scatteringExtinction ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMScatteringExtinctionID, m_scatteringExtinction ); + m_scatteringExtinction = c; + } +} + +void PMMedia::enableAbsorption( bool c ) +{ + if( c != m_enableAbsorption ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableAbsorptionID, m_enableAbsorption ); + m_enableAbsorption = c; + } +} + +void PMMedia::enableEmission( bool c ) +{ + if( c != m_enableEmission ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableEmissionID, m_enableEmission ); + m_enableEmission = c; + } +} + +void PMMedia::enableScattering( bool c ) +{ + if( c != m_enableScattering ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableScatteringID, m_enableScattering ); + m_enableScattering = c; + } +} + +PMDialogEditBase* PMMedia::editWidget( QWidget* parent ) const +{ + return new PMMediaEdit( parent ); +} + +void PMMedia::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMEnableAbsorptionID: + enableAbsorption( data->boolData( ) ); + break; + case PMEnableEmissionID: + enableEmission( data->boolData( ) ); + break; + case PMEnableScatteringID: + enableScattering( data->boolData( ) ); + break; + case PMMethodID: + setMethod( data->intData( ) ); + break; + case PMIntervalsID: + setIntervals( data->intData( ) ); + break; + case PMSamplesMinID: + setSamplesMin( data->intData( ) ); + break; + case PMSamplesMaxID: + setSamplesMax( data->intData( ) ); + break; + case PMAALevelID: + setAALevel( data->intData( ) ); + break; + case PMConfidenceID: + setConfidence( data->doubleData( ) ); + break; + case PMVarianceID: + setVariance( data->doubleData( ) ); + break; + case PMRatioID: + setRatio( data->doubleData( ) ); + break; + case PMAAThresholdID: + setAAThreshold( data->doubleData( ) ); + break; + case PMAbsorptionID: + setAbsorption( data->colorData( ) ); + break; + case PMEmissionID: + setEmission( data->colorData( ) ); + break; + case PMScatteringTypeID: + setScatteringType( data->intData( ) ); + break; + case PMScatteringColorID: + setScatteringColor( data->colorData( ) ); + break; + case PMScatteringEccentricityID: + setScatteringEccentricity( data->doubleData( ) ); + break; + case PMScatteringExtinctionID: + setScatteringExtinction( data->doubleData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMMedia::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmmedia.h b/kpovmodeler/pmmedia.h new file mode 100644 index 00000000..3bf6705b --- /dev/null +++ b/kpovmodeler/pmmedia.h @@ -0,0 +1,149 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMMEDIA_H +#define PMMEDIA_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebase.h" +#include "pmcolor.h" + +/** + * Class for povray medias + */ +class PMMedia : public PMTextureBase +{ + typedef PMTextureBase Base; +public: + /** + * Creates an PMMedia + */ + PMMedia( PMPart* part ); + /** + * Copy constructor + */ + PMMedia( const PMMedia& m ); + /** + * Deletes the object + */ + virtual ~PMMedia( ); + + /** */ + virtual PMObject* copy( ) const { return new PMMedia( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMMediaEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pmmedia" ); } + + /** */ + virtual void restoreMemento( PMMemento* s ); + + int method( ) const { return m_method; } + int intervals( ) const { return m_intervals; } + int samplesMin( ) const { return m_samplesMin; } + int samplesMax( ) const { return m_samplesMax; } + double confidence( ) const { return m_confidence; } + double variance( ) const { return m_variance; } + double ratio( ) const { return m_ratio; } + int aaLevel( ) const { return m_aaLevel; } + double aaThreshold( ) const { return m_aaThreshold; } + PMColor absorption( ) const { return m_absorption; } + PMColor emission( ) const { return m_emission; } + int scatteringType( ) const { return m_scatteringType; } + PMColor scatteringColor( ) const { return m_scatteringColor; } + double scatteringEccentricity( ) const { return m_scatteringEccentricity; } + double scatteringExtinction( ) const { return m_scatteringExtinction; } + bool isAbsorptionEnabled( ) const { return m_enableAbsorption; } + bool isEmissionEnabled( ) const { return m_enableEmission; } + bool isScatteringEnabled( ) const { return m_enableScattering; } + + void setMethod( int c ); + void setIntervals( int c ); + void setSamplesMin( int c ); + void setSamplesMax( int c ); + void setAALevel( int c ); + void setConfidence( double c ); + void setVariance( double c ); + void setRatio( double c ); + void setAAThreshold( double c ); + void setAbsorption( const PMColor& c ); + void setEmission( const PMColor& c ); + void setScatteringType( int c ); + void setScatteringColor( const PMColor& c ); + void setScatteringEccentricity( double c ); + void setScatteringExtinction( double c ); + void enableAbsorption( bool c ); + void enableEmission( bool c ); + void enableScattering( bool c ); + +private: + /** + * IDs for @ref PMMementoData + */ + enum PMMediaMementoID { PMMethodID, PMIntervalsID, PMSamplesMinID, PMSamplesMaxID, + PMConfidenceID, PMVarianceID, PMRatioID, + PMAALevelID, PMAAThresholdID, PMAbsorptionID, PMEmissionID, + PMScatteringTypeID, PMScatteringColorID, + PMScatteringEccentricityID, PMScatteringExtinctionID, + PMEnableAbsorptionID, PMEnableEmissionID, + PMEnableScatteringID }; + + int m_method; + int m_intervals; + int m_samplesMin; + int m_samplesMax; + double m_confidence; + double m_variance; + double m_ratio; + int m_aaLevel; + double m_aaThreshold; + PMColor m_absorption; + PMColor m_emission; + int m_scatteringType; + PMColor m_scatteringColor; + double m_scatteringEccentricity; + double m_scatteringExtinction; + + bool m_enableAbsorption; + bool m_enableEmission; + bool m_enableScattering; + + static PMMetaObject* s_pMetaObject; +}; + + +#endif diff --git a/kpovmodeler/pmmediaedit.cpp b/kpovmodeler/pmmediaedit.cpp new file mode 100644 index 00000000..2806eff8 --- /dev/null +++ b/kpovmodeler/pmmediaedit.cpp @@ -0,0 +1,370 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmmediaedit.h" +#include "pmmedia.h" +#include "pmlineedits.h" +#include "pmcoloredit.h" + +#include +#include +#include +#include +#include +#include +#include + +PMMediaEdit::PMMediaEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMMediaEdit::createTopWidgets( ) +{ + QHBoxLayout* hl; + QGridLayout* gl; + + Base::createTopWidgets( ); + + hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Method:" ), this ) ); + m_pMethodEdit = new QComboBox( this ); + m_pMethodEdit->insertItem( i18n( "1 (Monte Carlo)" ) ); + m_pMethodEdit->insertItem( i18n( "2 (Smooth)" ) ); + m_pMethodEdit->insertItem( i18n( "3 (Adaptive sampling)" ) ); + hl->addWidget( m_pMethodEdit ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Intervals:" ), this ) ); + m_pIntervalsEdit = new PMIntEdit( this ); + m_pIntervalsEdit->setValidation( true, 1, false, 0 ); + hl->addWidget( m_pIntervalsEdit ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Samples" ), this ) ); + hl->addWidget( new QLabel( i18n( "Min:" ), this ) ); + m_pSamplesMinEdit = new PMIntEdit( this ); + m_pSamplesMinEdit->setValidation( true, 1, false, 0 ); + hl->addWidget( m_pSamplesMinEdit ); + m_pSamplesMaxLabel = new QLabel( i18n( "Max:" ), this ); + hl->addWidget( m_pSamplesMaxLabel ); + m_pSamplesMaxEdit = new PMIntEdit( this ); + hl->addWidget( m_pSamplesMaxEdit ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + gl = new QGridLayout( hl, 3, 2 ); + gl->addWidget( new QLabel( i18n( "Confidence:" ), this ), 0, 0 ); + m_pConfidenceEdit = new PMFloatEdit( this ); + m_pConfidenceEdit->setValidation( true, 0, true, 1 ); + gl->addWidget( m_pConfidenceEdit, 0, 1 ); + gl->addWidget( new QLabel( i18n( "Variance:" ), this ), 1, 0 ); + m_pVarianceEdit = new PMFloatEdit( this ); + gl->addWidget( m_pVarianceEdit, 1, 1 ); + gl->addWidget( new QLabel( i18n( "Ratio:" ), this ), 2, 0 ); + m_pRatioEdit = new PMFloatEdit( this ); + gl->addWidget( m_pRatioEdit, 2, 1 ); + hl->addStretch( 1 ); + + m_pAAWidget = new QWidget( this ); + hl = new QHBoxLayout( m_pAAWidget, KDialog::spacingHint( ) ); + hl->addWidget( new QLabel( i18n( "Anti-aliasing" ), m_pAAWidget ) ); + hl->addWidget( new QLabel( i18n( "Level:" ), m_pAAWidget ) ); + m_pAALevelEdit = new PMIntEdit( m_pAAWidget ); + m_pAALevelEdit->setValidation( true, 1, false, 0 ); + hl->addWidget( m_pAALevelEdit ); + hl->addWidget( new QLabel( i18n( "Threshold:" ), m_pAAWidget ) ); + m_pAAThresholdEdit = new PMFloatEdit( m_pAAWidget ); + m_pAAThresholdEdit->setValidation( true, 0.0, false, 0.0 ); + hl->addWidget( m_pAAThresholdEdit ); + hl->addStretch( 1 ); + topLayout( )->addWidget( m_pAAWidget ); + + hl = new QHBoxLayout( topLayout( ) ); + gl = new QGridLayout( hl, 2, 2 ); + m_pEnableAbsorptionEdit = new QCheckBox( i18n( "Absorption" ), this ); + gl->addMultiCellWidget( m_pEnableAbsorptionEdit, 0, 0, 0, 1 ); + m_pAbsorptionEdit = new PMColorEdit( false, this ); + m_pAbsorptionLabel = new QLabel( i18n( "Color:" ), this ); + gl->addWidget( m_pAbsorptionLabel, 1, 0, AlignTop ); + gl->addWidget( m_pAbsorptionEdit, 1, 1 ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + gl = new QGridLayout( hl, 2, 2 ); + m_pEnableEmissionEdit = new QCheckBox( i18n( "Emission" ), this ); + gl->addMultiCellWidget( m_pEnableEmissionEdit, 0, 0, 0, 1 ); + m_pEmissionEdit = new PMColorEdit( false, this ); + m_pEmissionLabel = new QLabel( i18n( "Color:" ), this ); + gl->addWidget( m_pEmissionLabel, 1, 0, AlignTop ); + gl->addWidget( m_pEmissionEdit, 1, 1 ); + hl->addStretch( 1 ); + + m_pEnableScatteringEdit = new QCheckBox( i18n( "Scattering" ), this ); + topLayout( )->addWidget( m_pEnableScatteringEdit ); + m_pScatteringWidget = new QWidget( this ); + QVBoxLayout* vl = new QVBoxLayout( m_pScatteringWidget, KDialog::spacingHint( ) ); + hl = new QHBoxLayout( vl ); + hl->addWidget( new QLabel( i18n( "Type:" ), m_pScatteringWidget ) ); + m_pScatteringTypeEdit = new QComboBox( m_pScatteringWidget ); + m_pScatteringTypeEdit->insertItem( i18n( "Isotropic" ) ); + m_pScatteringTypeEdit->insertItem( i18n( "Mie Haze" ) ); + m_pScatteringTypeEdit->insertItem( i18n( "Mie Murky" ) ); + m_pScatteringTypeEdit->insertItem( i18n( "Rayleigh" ) ); + m_pScatteringTypeEdit->insertItem( i18n( "Henyey-Greenstein" ) ); + hl->addWidget( m_pScatteringTypeEdit ); + hl->addStretch( 1 ); + hl = new QHBoxLayout( vl ); + hl->addWidget( new QLabel( i18n( "Color:" ), m_pScatteringWidget ), 0, AlignTop ); + m_pScatteringColorEdit = new PMColorEdit( false, m_pScatteringWidget ); + hl->addWidget( m_pScatteringColorEdit ); + hl = new QHBoxLayout( vl ); + gl = new QGridLayout( hl, 2, 2 ); + m_pScatteringEccentricityLabel = new QLabel( i18n( "Eccentricity:" ), m_pScatteringWidget ); + gl->addWidget( m_pScatteringEccentricityLabel, 0, 0 ); + m_pScatteringEccentricityEdit = new PMFloatEdit( m_pScatteringWidget ); + gl->addWidget( m_pScatteringEccentricityEdit, 0, 1 ); + gl->addWidget( new QLabel( i18n( "Extinction:" ), m_pScatteringWidget ), 1, 0 ); + m_pScatteringExtinctionEdit = new PMFloatEdit( m_pScatteringWidget ); + gl->addWidget( m_pScatteringExtinctionEdit, 1, 1 ); + hl->addStretch( 1 ); + topLayout( )->addWidget( m_pScatteringWidget ); + + connect( m_pMethodEdit, SIGNAL( activated( int ) ), SLOT( slotMethodChanged( int ) ) ); + connect( m_pIntervalsEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pSamplesMinEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pSamplesMaxEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pConfidenceEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pVarianceEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pRatioEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pAALevelEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pAAThresholdEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pAbsorptionEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pEmissionEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pEnableAbsorptionEdit, SIGNAL( clicked( ) ), SLOT( slotAbsorptionClicked( ) ) ); + connect( m_pEnableEmissionEdit, SIGNAL( clicked( ) ), SLOT( slotEmissionClicked( ) ) ); + connect( m_pEnableScatteringEdit, SIGNAL( clicked( ) ), SLOT( slotScatteringClicked( ) ) ); + connect( m_pScatteringTypeEdit, SIGNAL( activated( int ) ), SLOT( slotScatteringTypeChanged( int ) ) ); + connect( m_pScatteringColorEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pScatteringEccentricityEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pScatteringExtinctionEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMMediaEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Media" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMMedia* ) o; + + m_pMethodEdit->setCurrentItem( m_pDisplayedObject->method( ) - 1 ); + m_pMethodEdit->setEnabled( !readOnly ); + m_pIntervalsEdit->setValue( m_pDisplayedObject->intervals( ) ); + m_pIntervalsEdit->setReadOnly( readOnly ); + m_pSamplesMinEdit->setValue( m_pDisplayedObject->samplesMin( ) ); + m_pSamplesMinEdit->setReadOnly( readOnly ); + m_pSamplesMaxEdit->setValue( m_pDisplayedObject->samplesMax( ) ); + m_pSamplesMaxEdit->setReadOnly( readOnly ); + m_pConfidenceEdit->setValue( m_pDisplayedObject->confidence( ) ); + m_pConfidenceEdit->setReadOnly( readOnly ); + m_pVarianceEdit->setValue( m_pDisplayedObject->variance( ) ); + m_pVarianceEdit->setReadOnly( readOnly ); + m_pRatioEdit->setValue( m_pDisplayedObject->ratio( ) ); + m_pRatioEdit->setReadOnly( readOnly ); + m_pAALevelEdit->setValue( m_pDisplayedObject->aaLevel( ) ); + m_pAALevelEdit->setReadOnly( readOnly ); + m_pAAThresholdEdit->setValue( m_pDisplayedObject->aaThreshold( ) ); + m_pAAThresholdEdit->setReadOnly( readOnly ); + m_pAbsorptionEdit->setColor( m_pDisplayedObject->absorption( ) ); + m_pAbsorptionEdit->setReadOnly( readOnly ); + m_pEmissionEdit->setColor( m_pDisplayedObject->emission( ) ); + m_pEmissionEdit->setReadOnly( readOnly ); + m_pEnableAbsorptionEdit->setChecked( m_pDisplayedObject->isAbsorptionEnabled( ) ); + m_pEnableAbsorptionEdit->setEnabled( !readOnly ); + m_pEnableEmissionEdit->setChecked( m_pDisplayedObject->isEmissionEnabled( ) ); + m_pEnableEmissionEdit->setEnabled( !readOnly ); + m_pEnableScatteringEdit->setChecked( m_pDisplayedObject->isScatteringEnabled( ) ); + m_pEnableScatteringEdit->setEnabled( !readOnly ); + m_pScatteringTypeEdit->setCurrentItem( m_pDisplayedObject->scatteringType( ) - 1 ); + m_pScatteringTypeEdit->setEnabled( !readOnly ); + m_pScatteringColorEdit->setColor( m_pDisplayedObject->scatteringColor( ) ); + m_pScatteringColorEdit->setReadOnly( readOnly ); + m_pScatteringEccentricityEdit->setValue( m_pDisplayedObject->scatteringEccentricity( ) ); + m_pScatteringEccentricityEdit->setReadOnly( readOnly ); + m_pScatteringExtinctionEdit->setValue( m_pDisplayedObject->scatteringExtinction( ) ); + m_pScatteringExtinctionEdit->setReadOnly( readOnly ); + + slotMethodChanged( m_pMethodEdit->currentItem( ) ); + slotAbsorptionClicked( ); + slotEmissionClicked( ); + slotScatteringClicked( ); + slotScatteringTypeChanged( m_pScatteringTypeEdit->currentItem( ) ); + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMMediaEdit: Can't display object\n"; +} + +void PMMediaEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setMethod( m_pMethodEdit->currentItem( ) + 1 ); + m_pDisplayedObject->setIntervals( m_pIntervalsEdit->value( ) ); + m_pDisplayedObject->setSamplesMin( m_pSamplesMinEdit->value( ) ); + m_pDisplayedObject->setSamplesMax( m_pSamplesMaxEdit->value( ) ); + m_pDisplayedObject->setConfidence( m_pConfidenceEdit->value( ) ); + m_pDisplayedObject->setVariance( m_pVarianceEdit->value( ) ); + m_pDisplayedObject->setRatio( m_pRatioEdit->value( ) ); + m_pDisplayedObject->setAALevel( m_pAALevelEdit->value( ) ); + m_pDisplayedObject->setAAThreshold( m_pAAThresholdEdit->value( ) ); + m_pDisplayedObject->setAbsorption( m_pAbsorptionEdit->color( ) ); + m_pDisplayedObject->setEmission( m_pEmissionEdit->color( ) ); + m_pDisplayedObject->setScatteringType( m_pScatteringTypeEdit->currentItem( ) + 1 ); + m_pDisplayedObject->setScatteringColor( m_pScatteringColorEdit->color( ) ); + m_pDisplayedObject->setScatteringEccentricity( m_pScatteringEccentricityEdit->value( ) ); + m_pDisplayedObject->setScatteringExtinction( m_pScatteringExtinctionEdit->value( ) ); + m_pDisplayedObject->enableAbsorption( m_pEnableAbsorptionEdit->isChecked( ) ); + m_pDisplayedObject->enableEmission( m_pEnableEmissionEdit->isChecked( ) ); + m_pDisplayedObject->enableScattering( m_pEnableScatteringEdit->isChecked( ) ); + } +} + +bool PMMediaEdit::isDataValid( ) +{ + if( !m_pIntervalsEdit->isDataValid( ) ) return false; + if( !m_pSamplesMinEdit->isDataValid( ) ) return false; + if( !m_pSamplesMaxEdit->isDataValid( ) ) return false; + if( !m_pConfidenceEdit->isDataValid( ) ) return false; + if( !m_pVarianceEdit->isDataValid( ) ) return false; + if( !m_pRatioEdit->isDataValid( ) ) return false; + if( !m_pAALevelEdit->isDataValid( ) ) return false; + if( !m_pAAThresholdEdit->isDataValid( ) ) return false; + if( !m_pAbsorptionEdit->isDataValid( ) ) return false; + if( !m_pEmissionEdit->isDataValid( ) ) return false; + if( !m_pScatteringColorEdit->isDataValid( ) ) return false; + if( !m_pScatteringEccentricityEdit->isDataValid( ) ) return false; + if( !m_pScatteringExtinctionEdit->isDataValid( ) ) return false; + if( m_pMethodEdit->currentItem( ) < 2 && + m_pSamplesMaxEdit->value( ) < m_pSamplesMinEdit->value( ) ) + { + KMessageBox::error( this, i18n( "Maximum number of samples lower than minimum number." ), + i18n( "Error" ) ); + return false; + } + + return Base::isDataValid( ); +} + +void PMMediaEdit::slotMethodChanged( int c ) +{ + if ( c == 2 ) + { + m_pAAWidget->show( ); + m_pSamplesMaxLabel->hide( ); + m_pSamplesMaxEdit->hide( ); + } + else + { + m_pAAWidget->hide( ); + m_pSamplesMaxLabel->show( ); + m_pSamplesMaxEdit->show( ); + if ( m_pSamplesMaxEdit->value( ) < m_pSamplesMinEdit->value( ) ) + m_pSamplesMaxEdit->setValue( m_pSamplesMinEdit->value( ) ); + } + emit dataChanged( ); + emit sizeChanged( ); +} + +void PMMediaEdit::slotAbsorptionClicked( ) +{ + if( m_pEnableAbsorptionEdit->isChecked( ) ) + { + m_pAbsorptionEdit->show( ); + m_pAbsorptionLabel->show( ); + } + else + { + m_pAbsorptionEdit->hide( ); + m_pAbsorptionLabel->hide( ); + } + emit dataChanged( ); + emit sizeChanged( ); +} + +void PMMediaEdit::slotEmissionClicked( ) +{ + if( m_pEnableEmissionEdit->isChecked( ) ) + { + m_pEmissionEdit->show( ); + m_pEmissionLabel->show( ); + } + else + { + m_pEmissionEdit->hide( ); + m_pEmissionLabel->hide( ); + } + emit dataChanged( ); + emit sizeChanged( ); +} + +void PMMediaEdit::slotScatteringClicked( ) +{ + if( m_pEnableScatteringEdit->isChecked( ) ) + { + m_pScatteringWidget->show( ); + if( m_pScatteringTypeEdit->currentItem( ) == 4 ) + { + m_pScatteringEccentricityLabel->show( ); + m_pScatteringEccentricityEdit->show( ); + } + else + { + m_pScatteringEccentricityLabel->hide( ); + m_pScatteringEccentricityEdit->hide( ); + } + } + else + m_pScatteringWidget->hide( ); + + emit dataChanged( ); + emit sizeChanged( ); +} + +void PMMediaEdit::slotScatteringTypeChanged( int c ) +{ + if( c == 4 ) + { + m_pScatteringEccentricityLabel->show( ); + m_pScatteringEccentricityEdit->show( ); + } + else + { + m_pScatteringEccentricityLabel->hide( ); + m_pScatteringEccentricityEdit->hide( ); + } + m_pScatteringWidget->adjustSize( ); + emit dataChanged( ); + emit sizeChanged( ); +} + +#include "pmmediaedit.moc" diff --git a/kpovmodeler/pmmediaedit.h b/kpovmodeler/pmmediaedit.h new file mode 100644 index 00000000..866e706d --- /dev/null +++ b/kpovmodeler/pmmediaedit.h @@ -0,0 +1,102 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMMEDIAEDIT_H +#define PMMEDIAEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebaseedit.h" + +class PMMedia; +class PMIntEdit; +class PMFloatEdit; +class PMColorEdit; +class QCheckBox; +class QLabel; +class QComboBox; + +/** + * Dialog edit class for @ref PMMedia + */ +class PMMediaEdit : public PMTextureBaseEdit +{ + Q_OBJECT + typedef PMTextureBaseEdit Base; +public: + /** + * Creates a PMMediaEdit with parent and name + */ + PMMediaEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + void slotMethodChanged( int c ); + void slotAbsorptionClicked( ); + void slotEmissionClicked( ); + void slotScatteringClicked( ); + void slotScatteringTypeChanged( int c ); + +private: + PMMedia* m_pDisplayedObject; + + QComboBox* m_pMethodEdit; + PMIntEdit* m_pIntervalsEdit; + PMIntEdit* m_pSamplesMinEdit; + QLabel* m_pSamplesMaxLabel; + PMIntEdit* m_pSamplesMaxEdit; + PMFloatEdit* m_pConfidenceEdit; + PMFloatEdit* m_pVarianceEdit; + PMFloatEdit* m_pRatioEdit; + + QWidget* m_pAAWidget; + PMIntEdit* m_pAALevelEdit; + PMFloatEdit* m_pAAThresholdEdit; + + QCheckBox* m_pEnableAbsorptionEdit; + PMColorEdit* m_pAbsorptionEdit; + QLabel* m_pAbsorptionLabel; + + QCheckBox* m_pEnableEmissionEdit; + PMColorEdit* m_pEmissionEdit; + QLabel* m_pEmissionLabel; + + QCheckBox* m_pEnableScatteringEdit; + QWidget* m_pScatteringWidget; + QComboBox* m_pScatteringTypeEdit; + PMColorEdit* m_pScatteringColorEdit; + QLabel* m_pScatteringEccentricityLabel; + PMFloatEdit* m_pScatteringEccentricityEdit; + PMFloatEdit* m_pScatteringExtinctionEdit; +}; + + +#endif diff --git a/kpovmodeler/pmmemento.cpp b/kpovmodeler/pmmemento.cpp new file mode 100644 index 00000000..84f52a6e --- /dev/null +++ b/kpovmodeler/pmmemento.cpp @@ -0,0 +1,220 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmmemento.h" +#include "pmdebug.h" + + +PMMementoData::PMMementoData( PMMetaObject* classType, int vID, int data ) + : PMVariant( data ) +{ + m_objectType = classType; + m_valueID = vID; +} + +PMMementoData::PMMementoData( PMMetaObject* classType, int vID, unsigned int data ) + : PMVariant( data ) +{ + m_objectType = classType; + m_valueID = vID; +} + +PMMementoData::PMMementoData( PMMetaObject* classType, int vID, double data ) + : PMVariant( data ) +{ + m_objectType = classType; + m_valueID = vID; +} + + +PMMementoData::PMMementoData( PMMetaObject* classType, int vID, bool data ) + : PMVariant( data ) +{ + m_objectType = classType; + m_valueID = vID; +} + +PMMementoData::PMMementoData( PMMetaObject* classType, int vID, PMThreeState data ) + : PMVariant( data ) +{ + m_objectType = classType; + m_valueID = vID; +} + + +PMMementoData::PMMementoData( PMMetaObject* classType, int vID, const QString& data ) + : PMVariant( data ) +{ + m_objectType = classType; + m_valueID = vID; +} + +PMMementoData::PMMementoData( PMMetaObject* classType, int vID, const PMVector& data ) + : PMVariant( data ) +{ + m_objectType = classType; + m_valueID = vID; +} + +PMMementoData::PMMementoData( PMMetaObject* classType, int vID, const PMColor& data ) + : PMVariant( data ) +{ + m_objectType = classType; + m_valueID = vID; +} + +PMMementoData::PMMementoData( PMMetaObject* classType, int vID, PMObject* obj ) + : PMVariant( obj ) +{ + m_objectType = classType; + m_valueID = vID; +} + +PMMemento::PMMemento( PMObject* originator ) +{ + m_data.setAutoDelete( true ); + m_changedObjects.setAutoDelete( true ); + m_pIDData = 0; + m_pOriginatorChange = 0; + m_pOriginator = originator; +} + +PMMemento::~PMMemento( ) +{ + m_data.clear( ); + m_changedObjects.clear( ); + // m_pOriginatorChange is in m_changedObjects and is already deleted! +} + +PMMementoData* PMMemento::findData( PMMetaObject* classType, int vID ) const +{ + PMMementoDataIterator it( m_data ); + + for( ; it.current( ); ++it ) + { + if( ( it.current( )->objectType( ) == classType ) && + ( it.current( )->valueID( ) == vID ) ) + return it.current( ); + } + return 0; +} + +void PMMemento::addData( PMMementoData* data ) +{ + m_data.append( data ); + addChange( PMCData ); +} + +void PMMemento::addData( PMMetaObject* classType, int vID, const int data ) +{ + if( !findData( classType, vID ) ) + addData( new PMMementoData( classType, vID, data ) ); +} + +void PMMemento::addData( PMMetaObject* classType, int vID, const unsigned int data ) +{ + if( !findData( classType, vID ) ) + addData( new PMMementoData( classType, vID, data ) ); +} + +void PMMemento::addData( PMMetaObject* classType, int vID, const double data ) +{ + if( !findData( classType, vID ) ) + addData( new PMMementoData( classType, vID, data ) ); +} + +void PMMemento::addData( PMMetaObject* classType, int vID, const bool data ) +{ + if( !findData( classType, vID ) ) + addData( new PMMementoData( classType, vID, data ) ); +} + +void PMMemento::addData( PMMetaObject* classType, int vID, const PMThreeState data ) +{ + if( !findData( classType, vID ) ) + addData( new PMMementoData( classType, vID, data ) ); +} + +void PMMemento::addData( PMMetaObject* classType, int vID, const QString& data ) +{ + if( !findData( classType, vID ) ) + addData( new PMMementoData( classType, vID, data ) ); +} + +void PMMemento::addIDChange( PMMetaObject* classType, int vID, const QString& data ) +{ + if( !findData( classType, vID ) ) + { + PMMementoData* d = new PMMementoData( classType, vID, data ); + addData( d ); + m_pIDData = d; + } +} + +void PMMemento::addData( PMMetaObject* classType, int vID, const PMVector& data ) +{ + if( !findData( classType, vID ) ) + addData( new PMMementoData( classType, vID, data ) ); +} + +void PMMemento::addData( PMMetaObject* classType, int vID, const PMColor& data ) +{ + if( !findData( classType, vID ) ) + addData( new PMMementoData( classType, vID, data ) ); +} + +void PMMemento::addData( PMMetaObject* classType, int vID, PMObject* obj ) +{ + if( !findData( classType, vID ) ) + addData( new PMMementoData( classType, vID, obj ) ); +} + +QString PMMemento::oldID( ) const +{ + if( m_pIDData ) + return m_pIDData->stringData( ); + return QString::null; +} + +void PMMemento::addChangedObject( PMObject* obj, int mode ) +{ + PMObjectChangeListIterator it( m_changedObjects ); + PMObjectChange* change = 0; + + while( it.current( ) && !change ) + { + if( it.current( )->object( ) == obj ) + change = it.current( ); + else + ++it; + } + + if( change ) + change->addMode( mode ); + else + m_changedObjects.append( new PMObjectChange( obj, mode ) ); +} + +void PMMemento::addChange( int mode ) +{ + if( !m_pOriginatorChange ) + { + m_pOriginatorChange = new PMObjectChange( m_pOriginator, PMCData ); + m_changedObjects.append( m_pOriginatorChange ); + } + m_pOriginatorChange->addMode( mode ); +} diff --git a/kpovmodeler/pmmemento.h b/kpovmodeler/pmmemento.h new file mode 100644 index 00000000..a3ea9c98 --- /dev/null +++ b/kpovmodeler/pmmemento.h @@ -0,0 +1,318 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMOBJECTMEMENTO_H +#define PMOBJECTMEMENTO_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmvariant.h" +#include "pmcommand.h" +#include "pmmetaobject.h" +#include +#include + +/** + * Class used by @ref PMObjectMemento to store one value. + * + * Each piece of data has two IDs: The type of the povray class that stored + * the data and a unique ID within this class. + * + * @see PMMementoDataIterator + */ + +class PMMementoData : public PMVariant +{ +public: + /** + * Stores an integer + */ + PMMementoData( PMMetaObject* classType, int vID, int data ); + /** + * Stores an unsigned integer + */ + PMMementoData( PMMetaObject* classType, int vID, unsigned int data ); + /** + * Stores double + */ + PMMementoData( PMMetaObject* classType, int vID, double data ); + /** + * Stores a boolean + */ + PMMementoData( PMMetaObject* classType, int vID, bool data ); + /** + * Stores a @ref PMThreeState + */ + PMMementoData( PMMetaObject* classType, int vID, PMThreeState data ); + /** + * Stores a string + */ + PMMementoData( PMMetaObject* classType, int vID, const QString& data ); + /** + * Stores a @ref PMVector + */ + PMMementoData( PMMetaObject* classType, int vID, const PMVector& data ); + /** + * Stores a @ref PMColor + */ + PMMementoData( PMMetaObject* classType, int vID, const PMColor& data ); + /** + * Stores a pointer to a PMObject + */ + PMMementoData( PMMetaObject* classType, int vID, PMObject* obj ); + + /** + * Returns the object type of the povray class that stored the data + */ + PMMetaObject* objectType( ) const { return m_objectType; } + /** + * Returns the ID of the stored value + */ + int valueID( ) const { return m_valueID; } + +private: + /** + * Class that stored the information + */ + PMMetaObject* m_objectType; + /** + * The unique ID within the m_objectType + */ + int m_valueID; +}; + +typedef QPtrList PMMementoDataList; + + +/** + * Helper class to store information about changed objects in @ref PMMemento + */ +class PMObjectChange +{ +public: + /** + * Creates change information for the object obj. + * + * mode is a bitwise combination of @ref PMChange constants. + */ + PMObjectChange( PMObject* obj, int mode ) + { + m_pObject = obj; + m_mode = mode; + } + PMObject* object( ) const { return m_pObject; } + int mode( ) const { return m_mode; } + void addMode( int mode ) { m_mode |= mode; } +private: + PMObject* m_pObject; + int m_mode; +}; + +typedef QPtrList PMObjectChangeList; +typedef QPtrListIterator PMObjectChangeListIterator; + +/** + * Class that stores the data of povray objects for undo/redo information + * + * This class should provide enough functionality for most objects. If not, + * subclass this class. + * + * All objects have to use the memento class of its base class or an inherited + * one. + * + * Only the changed attributes of an object are saved. + * + * See class @ref PMMementoData to see how values are stored. + */ +class PMMemento +{ + friend class PMMementoDataIterator; +public: + /** + * Creates a memento for the object originator + */ + PMMemento( PMObject* originator ); + /** + * Deletes the memento + */ + virtual ~PMMemento( ); + + /** + * Returns a pointer to the originator + */ + PMObject* originator( ) const { return m_pOriginator; } + /** + * Returns a pointer to the memento data or 0 if this value is not + * stored + */ + PMMementoData* findData( PMMetaObject* classType, int vID ) const; + /** + * Adds the data object to the list of stored data. The menento may not + * contain this information (objType and vID). + * + * The memento becomes the owner of this object.*/ + void addData( PMMementoData* data ); + + /** + * Adds an integer data object. Will be ignored if the memento + * already contains this data + */ + void addData( PMMetaObject* classType, int vID, const int data ); + + /** + * Adds an unsigned data object. Will be ignored if the memento + * already contains this data + */ + void addData( PMMetaObject* classType, int vID, const unsigned int data ); + + /** + * Adds an double data object. Will be ignored if the memento + * already contains this data + */ + void addData( PMMetaObject* classType, int vID, const double data ); + + /** + * Adds an bool data object. Will be ignored if the memento + * already contains this data + */ + void addData( PMMetaObject* classType, int vID, const bool data ); + + /** + * Adds an @ref PMThreeState data object. Will be ignored if the memento + * already contains this data + */ + void addData( PMMetaObject* classType, int vID, const PMThreeState data ); + + /** + * Adds an @ref QString data object. Will be ignored if the memento + * already contains this data + */ + void addData( PMMetaObject* classType, int vID, const QString& data ); + + /** + * Adds an @ref PMVector data object. Will be ignored if the memento + * already contains this data + */ + void addData( PMMetaObject* classType, int vID, const PMVector& data ); + + /** + * Adds an @ref PMColor data object. Will be ignored if the memento + * already contains this data + */ + void addData( PMMetaObject* classType, int vID, const PMColor& data ); + + /** + * Adds an PMObject pointer data object. Will be ignored if the memento + * already contains this data + */ + void addData( PMMetaObject* classType, int vID, PMObject* obj ); + + /** + * Call this to store an id change + */ + void addIDChange( PMMetaObject* classType, int vID, const QString& data ); + + /** + * Returns true if the memento contains changed data + */ + bool containsChanges( ) const { return ( m_changedObjects.count( ) > 0 ); } + + /** + * Call this function, if you stored some data that changed + * the view structure of the originator + */ + void setViewStructureChanged( ) { addChange( PMCViewStructure ); } + /** + * Call this function, if you stored some data that changed + * the name or pixmap of the originator + */ + void setDescriptionChanged( ) { addChange( PMCDescription ); } + + /** + * Returns true if the id of a @ref PMDeclare was changed + */ + bool idChanged( ) const { return m_pIDData != 0; } + /** + * Returns the old id + */ + QString oldID( ) const; + /** + * If one object is changed, other objects can be changed as well. + * + * For example, if the linked declare of an object link is changed, + * the old and new declare are changed as well (Remove the old link, + * add the new link). + * + * This function returns an iterator to the list of all changed objects. + * The first object is the originator. + */ + PMObjectChangeListIterator changedObjects( ) + { return PMObjectChangeListIterator( m_changedObjects ); } + /** + * Adds the object to the list of changed objects. + * Note that the originator is added automatically + */ + void addChangedObject( PMObject* obj, int mode ); +protected: + /** + * Adds the change to the originator change object + */ + void addChange( int mode ); +private: + /** + * The stored values + */ + PMMementoDataList m_data; + /** + * Additional pointer to the memento data for id changes of + * @ref PMDeclare objects + */ + PMMementoData* m_pIDData; + /** + * List of changes + */ + QPtrList m_changedObjects; + PMObjectChange* m_pOriginatorChange; + PMObject* m_pOriginator; +}; + + +/** + * Iterator for memento data + */ +class PMMementoDataIterator : public QPtrListIterator +{ +public: + PMMementoDataIterator( const PMMemento& m ) + : QPtrListIterator( m.m_data ) + { + } + PMMementoDataIterator( const PMMemento* m ) + : QPtrListIterator( m->m_data ) + { + } + PMMementoDataIterator( const PMMementoDataList& l ) + : QPtrListIterator( l ) + { + } +}; + +#endif diff --git a/kpovmodeler/pmmesh.cpp b/kpovmodeler/pmmesh.cpp new file mode 100644 index 00000000..571170a9 --- /dev/null +++ b/kpovmodeler/pmmesh.cpp @@ -0,0 +1,557 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmmesh.h" + +#include +#include "pmxmlhelper.h" +#include "pmmeshedit.h" +#include "pmmemento.h" +#include "pmtriangle.h" +#include "pm3dcontrolpoint.h" +#include "pmvectorcontrolpoint.h" + +const PMVector insideVectorDefault = PMVector( 0.0, 0.0, 0.0 ); + +PMDefinePropertyClass( PMMesh, PMMeshProperty ); + +class PMMeshMemento : public PMMemento +{ +public: + /** + * Creates a memento for the object originator + */ + PMMeshMemento( PMObject* originator ) : PMMemento( originator ) + { + m_bTriangleMementosSaved = false; + m_triangleMementos.setAutoDelete( true ); + } + /** + * Deletes the memento + */ + virtual ~PMMeshMemento( ) + { + m_triangleMementos.clear( ); + } + + /** + * Saves the triangles memento data + */ + void setTriangleMementos( const QPtrList& list ) + { + if ( !m_bTriangleMementosSaved ) + { + QPtrListIterator Itr( list ); + PMMemento* m; + while( ( m = Itr.current( ) ) != 0 ) + { + m_triangleMementos.append( m ); + ++Itr; + } + + m_bTriangleMementosSaved = true; + addChange( PMCData ); + } + } + /** + * Returns the triangles memento data + */ + QPtrList triangleMementos( ) const + { + if ( !m_bTriangleMementosSaved ) + kdError( PMArea ) << "Triangles mementos not saved in PMMeshMemento::triangleMementos\n"; + return m_triangleMementos; + } + /** + * Returns true if the triangle mementos have been saved + */ + bool triangleMementosSaved( ) const { return m_bTriangleMementosSaved; } +private: + QPtrList m_triangleMementos; + bool m_bTriangleMementosSaved; +}; + +PMMetaObject* PMMesh::s_pMetaObject = 0; +PMObject* createNewMesh( PMPart* part ) +{ + return new PMMesh( part ); +} + +PMMesh::PMMesh( PMPart* part ) + : Base( part ) +{ + m_hierarchy = true; + m_enableInsideVector = false; + m_insideVector = insideVectorDefault; +} + +PMMesh::PMMesh( const PMMesh& m ) + : Base( m ) +{ + m_hierarchy = m.m_hierarchy; + m_enableInsideVector = m.m_enableInsideVector; + m_insideVector = m.m_insideVector; +} + +PMMesh::~PMMesh( ) +{ +} + +QString PMMesh::description( ) const +{ + return i18n( "mesh" ); +} + +void PMMesh::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "hierarchy", m_hierarchy ); + e.setAttribute( "enable_inside_vector", m_enableInsideVector ); + e.setAttribute( "inside_vector", m_insideVector.serializeXML( ) ); + Base::serialize( e, doc ); +} + +void PMMesh::readAttributes( const PMXMLHelper& h ) +{ + m_hierarchy = h.boolAttribute( "hierarchy", true ); + m_enableInsideVector = h.boolAttribute( "enable_inside_vector", false ); + m_insideVector = h.vectorAttribute( "inside_vector", insideVectorDefault ); + Base::readAttributes( h ); +} + +PMMetaObject* PMMesh::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Mesh", Base::metaObject( ), createNewMesh ); + + s_pMetaObject->addProperty( + new PMMeshProperty( "hierarchy", &PMMesh::setHierarchy, &PMMesh::hierarchy ) ); + s_pMetaObject->addProperty( + new PMMeshProperty( "insideVectorEnabled", &PMMesh::enableInsideVector, &PMMesh::isInsideVectorEnabled ) ); + s_pMetaObject->addProperty( + new PMMeshProperty( "insideVector", &PMMesh::setInsideVector, &PMMesh::insideVector ) ); + } + return s_pMetaObject; +} + +void PMMesh::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMMesh::setHierarchy( bool h ) +{ + if( h != m_hierarchy ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMHierarchyID, m_hierarchy ); + m_hierarchy = h; + } +} + +void PMMesh::enableInsideVector( bool eiv ) +{ + if( eiv != m_enableInsideVector ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableInsideVectorID, m_enableInsideVector ); + m_enableInsideVector = eiv; + } +} + +void PMMesh::setInsideVector( const PMVector& iv ) +{ + if( iv != m_insideVector ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMInsideVectorID, m_insideVector ); + m_insideVector = iv; + } +} + +PMDialogEditBase* PMMesh::editWidget( QWidget* parent ) const +{ + return new PMMeshEdit( parent ); +} + +void PMMesh::createMemento( ) +{ + delete m_pMemento; + m_pMemento = new PMMeshMemento( this ); +} + +void PMMesh::restoreMemento( PMMemento* s ) +{ + PMMeshMemento* m = ( PMMeshMemento * ) s; + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMHierarchyID: + setHierarchy( data->boolData( ) ); + break; + case PMEnableInsideVectorID: + enableInsideVector( data->boolData( ) ); + break; + case PMInsideVectorID: + setInsideVector( data->vectorData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMMesh::restoreMemento\n"; + break; + } + } + } + + if ( m->triangleMementosSaved( ) ) + { + int numChildren = countChildren( ); + PMMemento* tm; + QPtrList list = m->triangleMementos( ); + QPtrListIterator Itr( list ); + for ( int i = 0; i < numChildren && ( tm = Itr.current( ) ) != 0; ++i, ++Itr ) + childAt( i )->restoreMemento( tm ); + } + + Base::restoreMemento( s ); +} + +void PMMesh::controlPoints( PMControlPointList& list ) +{ + unsigned numChildren = countChildren(); + PMTriangle *obj; + pointToPoint ptp; + bool found; + PMVector point, normal; + PMControlPoint* listP; + PM3DControlPoint* cp; + PMVectorControlPoint* vp; + int currentPoint = 0; + int firstNormal = numChildren * 3; + int currentNormal = firstNormal; + + m_pointToPointList.clear( ); + for ( unsigned i = 0; i < numChildren; ++i ) + { + if ( childAt( i )->isA( "Triangle" ) ) + { + + obj = ( PMTriangle * ) childAt( i ); + ptp.object = obj; + for ( unsigned j = 0; j < 3; ++j ) + { + found = false; + ptp.pointID = j; + point = obj->point( j ); + + for( listP = list.first( ); listP; listP = list.next( ) ) + { + if ( listP->id( ) < firstNormal && point == listP->position( ) ) + { + found = true; + ptp.listID = listP->id( ); + break; + } + } + + if ( !found ) + { + cp = new PM3DControlPoint( point, currentPoint, + i18n( "Mesh Point " + currentPoint ) ); + list.append( cp ); + ptp.listID = currentPoint++; + } + + m_pointToPointList.append( ptp ); + + if ( obj->isSmoothTriangle( ) ) + { + found = false; + ptp.pointID = j + 3; + normal = obj->normal( j ); + + for ( listP = list.first( ); listP; listP = list.next( ) ) + { + if ( listP->id( ) >= firstNormal ) + { + vp = ( PMVectorControlPoint* ) listP; + if ( vp->basePoint( ) == point && + vp->vector( ) == normal ) + { + found = true; + ptp.listID = listP->id( ); + break; + } + } + } + + if ( !found ) + { + vp = new PMVectorControlPoint( point, normal, currentNormal, + i18n( "Mesh Normal " + currentNormal ) ); + list.append( vp ); + ptp.listID = currentNormal++; + } + + m_pointToPointList.append( ptp ); + } + + } + } + } +} + +void PMMesh::controlPointsChangedList( PMControlPointList& list, PMObjectList& objList ) +{ + int numChildren = countChildren( ); + PMControlPoint* p; + QValueList::ConstIterator ptpItr = m_pointToPointList.begin( ); + QPtrList mementoList; + PMTriangle *obj; + PMVector p0, p1, p2; + PM3DControlPoint* cp0, * cp1, * cp2; + bool bp0, bp1, bp2; + PMVector n0, n1, n2; + PMVectorControlPoint* cn0, * cn1, * cn2; + bool bn0, bn1, bn2; + PMVector triangleNormal; + double d, normalDirection = 1.0; + bool found, validNormal, validTriangles = true; + int listID, pointID, numCP; + + // have to cache changed values because checking once changes them to false + QMemArray changed( list.count( ) ); + p = list.first( ); + for ( int i = 0; p; ++i, p = list.next( ) ) + changed[i] = p->changed( ); + + for ( int i = 0; i < numChildren && validTriangles; ++i ) + { + if ( childAt( i )->isA( "Triangle" ) ) + { + obj = ( PMTriangle* )childAt( i ); + obj->createMemento( ); + objList.append( obj ); + validNormal = false; + + if ( obj->isSmoothTriangle( ) ) + numCP = 6; + else + numCP = 3; + + cp0 = cp1 = cp2 = 0; + cn0 = cn1 = cn2 = 0; + + bp0 = bp1 = bp2 = bn0 = bn1 = bn2 = false; + + for ( int j = 0; j < numCP; ++j, ++ptpItr ) + { + + listID = (*ptpItr).listID; + pointID = (*ptpItr).pointID; + found = false; + p = list.first( ); + for ( int k = 0; p && !found; p = list.next( ), ++k ) + { + if( listID == p->id( ) ) + { + switch( pointID ) + { + case 0: + cp0 = ( PM3DControlPoint* ) p; + p0 = cp0->point( ); + bp0 = changed[ k ]; + break; + case 1: + cp1 = ( PM3DControlPoint* ) p; + p1 = cp1->point( ); + bp1 = changed[ k ]; + break; + case 2: + cp2 = ( PM3DControlPoint* ) p; + p2 = cp2->point( ); + bp2 = changed[ k ]; + break; + case 3: + cn0 = ( PMVectorControlPoint* ) p; + n0 = cn0->vector( ); + bn0 = changed[ k ]; + break; + case 4: + cn1 = ( PMVectorControlPoint* ) p; + n1 = cn1->vector( ); + bn1 = changed[ k ]; + break; + case 5: + cn2 = ( PMVectorControlPoint* ) p; + n2 = cn2->vector( ); + bn2 = changed[ k ]; + break; + default: + break; + } + found = true; + } + } + } + + if ( obj->isSmoothTriangle( ) ) + { + triangleNormal = PMVector::cross( obj->point( 1 ) - obj->point( 0 ), + obj->point( 2 ) - obj->point( 0 ) ); + normalDirection = PMVector::dot( triangleNormal, obj->normal( 0 ) ); + if( approxZero( normalDirection ) ) + normalDirection = PMVector::dot( triangleNormal, obj->normal( 1 ) ); + if( approxZero( normalDirection ) ) + normalDirection = PMVector::dot( triangleNormal, obj->normal( 2 ) ); + if( normalDirection < 0 ) + triangleNormal = -triangleNormal; + if( !approxZero( triangleNormal.abs( ) ) ) + { + validNormal = true; + triangleNormal /= triangleNormal.abs( ); + } + } + + if ( bp0 ) + { + if ( !( p0.approxEqual( p1 ) || p0.approxEqual( p2 ) ) ) + obj->setPoint( 0, p0 ); + else + { + validTriangles = false; + cp0->setPoint( obj->point( 0 ) ); + break; + } + } + + if ( bp1 ) + { + if ( !( p1.approxEqual( p0 ) || p1.approxEqual( p2 ) ) ) + obj->setPoint( 1, p1 ); + else + { + validTriangles = false; + cp1->setPoint( obj->point( 1 ) ); + break; + } + } + + if ( bp2 ) + { + if ( !( p2.approxEqual( p0 ) || p2.approxEqual( p1 ) ) ) + obj->setPoint( 2, p2 ); + else + { + validTriangles = false; + cp2->setPoint( obj->point( 2 ) ); + break; + } + } + + if ( obj->isSmoothTriangle( ) ) + { + if ( bn0 ) + { + if( validNormal ) + { + d = PMVector::dot( triangleNormal, n0 ); + if( d > 0 ) + obj->setNormal( 0, n0 ); + else + { + obj->setNormal( 0, n0 - ( d - 1e-5 ) * triangleNormal ); + cn0->setVector( obj->normal( 0 ) ); + } + } + else + cn0->setVector( obj->normal( 0 ) ); + } + + if ( bn1 ) + { + if( validNormal ) + { + d = PMVector::dot( triangleNormal, n1 ); + if( d > 0 ) + obj->setNormal( 1, n1 ); + else + { + obj->setNormal( 1, n1 - ( d - 1e-5 ) * triangleNormal ); + cn1->setVector( obj->normal( 1 ) ); + } + } + else + cn1->setVector( obj->normal( 1 ) ); + } + + if ( bn2 ) + { + if( validNormal ) + { + d = PMVector::dot( triangleNormal, n2 ); + if( d > 0 ) + obj->setNormal( 2, n2 ); + else + { + obj->setNormal( 2, n2 - ( d - 1e-5 ) * triangleNormal ); + cn2->setVector( obj->normal( 2 ) ); + } + } + else + cn2->setVector( obj->normal( 2 ) ); + } + } + + mementoList.append( obj->takeMemento( ) ); + + if ( !validTriangles ) + { + PMMemento *tm; + for ( int j = i; j >= 0; --j ) + { + if ( ( tm = mementoList.getLast( ) ) ) + { + childAt( j )->restoreMemento( tm ); + delete tm; + mementoList.removeLast( ); + } + } + } + } + } + + if ( validTriangles ) + { + if ( m_pMemento ) + ( ( PMMeshMemento * ) m_pMemento )->setTriangleMementos( mementoList ); + objList.append( this ); + setViewStructureChanged( ); + } +} diff --git a/kpovmodeler/pmmesh.h b/kpovmodeler/pmmesh.h new file mode 100644 index 00000000..4045d3ab --- /dev/null +++ b/kpovmodeler/pmmesh.h @@ -0,0 +1,142 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMMESH_H +#define PMMESH_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" +#include "pmvector.h" + +class PMTriangle; + +/** + * Class for povray mesh objects. + */ +class PMMesh : public PMSolidObject +{ + typedef PMSolidObject Base; +public: + /** + * Creates an empty PMMesh object + */ + PMMesh( PMPart* part ); + /** + * Copy constructor + */ + PMMesh( const PMMesh& m ); + + /** + * deletes the PMMesh object + */ + virtual ~PMMesh( ); + + /** */ + virtual PMObject* copy( ) const { return new PMMesh( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMMeshEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmmesh" ); } + + /** + * Returns the hierarchy flag + */ + bool hierarchy( ) const { return m_hierarchy; } + /** + * Sets the type of the csg + */ + void setHierarchy( bool h ); + + /** + * Returns true if the inside vector is enabled + */ + bool isInsideVectorEnabled( ) const { return m_enableInsideVector; } + /** + * Sets the inside vector flag + */ + void enableInsideVector( bool eiv ); + + /** + * Returns the inside vector + */ + PMVector insideVector( ) const { return m_insideVector; } + /** + * Sets the inside vector + */ + void setInsideVector( const PMVector& iv ); + + /** */ + virtual void createMemento( ); + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual void controlPoints( PMControlPointList& list ); + /** */ + virtual void controlPointsChangedList( PMControlPointList& list, PMObjectList& objList ); + +private: + /** + * IDs for @ref PMMementoData + */ + enum PMMeshMementoID { PMHierarchyID, PMEnableInsideVectorID, + PMInsideVectorID }; + + bool m_hierarchy; + bool m_enableInsideVector; + PMVector m_insideVector; + + static PMMetaObject* s_pMetaObject; + + /** + * Point to point structure for changes with control points + */ + struct pointToPoint { + PMTriangle *object; + int pointID; + int listID; + }; + + /** + * List of point to point structures + */ + QValueList m_pointToPointList; +}; + +#endif diff --git a/kpovmodeler/pmmeshedit.cpp b/kpovmodeler/pmmeshedit.cpp new file mode 100644 index 00000000..0b0e2269 --- /dev/null +++ b/kpovmodeler/pmmeshedit.cpp @@ -0,0 +1,100 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmmeshedit.h" +#include "pmmesh.h" +#include "pmvectoredit.h" + +#include +#include + +#include + +PMMeshEdit::PMMeshEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMMeshEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* layout; + m_pHierarchy = new QCheckBox( i18n( "Hierarchy" ), this ); + m_pEnableInsideVector = new QCheckBox( i18n( "Inside vector:" ), this ); + m_pInsideVector = new PMVectorEdit( "x", "y", "z", this ); + layout = new QHBoxLayout( topLayout( ) ); + layout->addWidget( m_pHierarchy ); + layout->addStretch( 1 ); + layout = new QHBoxLayout( topLayout( ) ); + layout->addWidget( m_pEnableInsideVector ); + layout->addWidget( m_pInsideVector ); + layout->addStretch( 1 ); + + connect( m_pHierarchy, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pEnableInsideVector, SIGNAL( clicked( ) ), SLOT( slotInsideVectorClicked( ) ) ); + connect( m_pInsideVector, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMMeshEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Mesh" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMMesh* ) o; + + m_pHierarchy->setChecked( m_pDisplayedObject->hierarchy( ) ); + m_pHierarchy->setEnabled( !readOnly ); + m_pEnableInsideVector->setChecked( m_pDisplayedObject->isInsideVectorEnabled( ) ); + m_pEnableInsideVector->setEnabled( !readOnly ); + m_pInsideVector->setVector( m_pDisplayedObject->insideVector( ) ); + m_pInsideVector->setReadOnly( readOnly ); + slotInsideVectorClicked( ); + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMMeshEdit: Can't display object\n"; +} + +void PMMeshEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setHierarchy( m_pHierarchy->isChecked( ) ); + m_pDisplayedObject->enableInsideVector( m_pEnableInsideVector->isChecked( ) ); + m_pDisplayedObject->setInsideVector( m_pInsideVector->vector( ) ); + } +} + +bool PMMeshEdit::isDataValid( ) +{ + return Base::isDataValid( ); +} + +void PMMeshEdit::slotInsideVectorClicked( ) +{ + if( m_pEnableInsideVector->isChecked( ) ) + m_pInsideVector->setEnabled( true ); + else + m_pInsideVector->setEnabled( false ); + emit dataChanged( ); +} + +#include "pmmeshedit.moc" diff --git a/kpovmodeler/pmmeshedit.h b/kpovmodeler/pmmeshedit.h new file mode 100644 index 00000000..1a778ac8 --- /dev/null +++ b/kpovmodeler/pmmeshedit.h @@ -0,0 +1,67 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMMESHEDIT_H +#define PMMESHEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" + +class PMMesh; +class QCheckBox; +class PMVectorEdit; + +/** + * Dialog edit class for @ref PMMesh + */ +class PMMeshEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMMeshEdit with parent and name + */ + PMMeshEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); +protected slots: + void slotInsideVectorClicked( ); +private: + PMMesh* m_pDisplayedObject; + + QCheckBox* m_pHierarchy; + QCheckBox* m_pEnableInsideVector; + PMVectorEdit* m_pInsideVector; +}; + + +#endif diff --git a/kpovmodeler/pmmessage.cpp b/kpovmodeler/pmmessage.cpp new file mode 100644 index 00000000..5587181f --- /dev/null +++ b/kpovmodeler/pmmessage.cpp @@ -0,0 +1,43 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmmessage.h" + +PMMessage::PMMessage( ) +{ + m_pObject = 0; +} + +PMMessage::PMMessage( const QString& text, PMObject* object ) +{ + m_sText = text; + m_pObject = object; +} + +PMMessage::PMMessage( const PMMessage& m ) +{ + m_sText = m.m_sText; + m_pObject = m.m_pObject; +} + +PMMessage& PMMessage::operator=( const PMMessage& m ) +{ + m_sText = m.m_sText; + m_pObject = m.m_pObject; + return *this; +} + diff --git a/kpovmodeler/pmmessage.h b/kpovmodeler/pmmessage.h new file mode 100644 index 00000000..1247ccb0 --- /dev/null +++ b/kpovmodeler/pmmessage.h @@ -0,0 +1,79 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMMESSAGE_H +#define PMMESSAGE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmobject.h" + +#include +#include + +/** + * Class for messages in the @ref PMErrorDialog + */ +class PMMessage +{ +public: + /** + * Default constructor + */ + PMMessage( ); + /** + * Creates a message with a text and optionally with + * a link to an object + */ + PMMessage( const QString& text, PMObject* object = 0 ); + /** + * Copy constructor + */ + PMMessage( const PMMessage& m ); + /** + * Assignment operator + */ + PMMessage& operator=( const PMMessage& m ); + + /** + * Returns the message text + */ + QString text( ) const { return m_sText; } + /** + * Sets the message text + */ + void setText( const QString& text ) { m_sText = text; } + /** + * Returns the linked object or 0 + */ + PMObject* linkedObject( ) const { return m_pObject; } + /** + * Sets the linked object + */ + void setLinkedObject( PMObject* o ) { m_pObject = o; } + +private: + QString m_sText; + PMObject* m_pObject; +}; + +typedef QValueList PMMessageList; + +#endif diff --git a/kpovmodeler/pmmetaobject.cpp b/kpovmodeler/pmmetaobject.cpp new file mode 100644 index 00000000..a7e98b9b --- /dev/null +++ b/kpovmodeler/pmmetaobject.cpp @@ -0,0 +1,95 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmmetaobject.h" + +PMPropertyBase::PMPropertyBase( const QString& name, + PMVariant::PMVariantDataType t, + bool readOnly, bool writeOnly ) +{ + m_name = name; + m_type = t; + m_pEnumList = 0; + m_readOnly = readOnly; + m_writeOnly = writeOnly; +} + +PMPropertyBase::PMPropertyBase( const PMPropertyBase& p ) +{ + m_name = p.m_name; + m_type = p.m_type; + m_readOnly = p.m_readOnly; + m_writeOnly = p.m_writeOnly; + + if( p.m_pEnumList ) + m_pEnumList = new QStringList( *( p.m_pEnumList ) ); + else + m_pEnumList = 0; +} + +PMPropertyBase::~PMPropertyBase( ) +{ + delete m_pEnumList; +} + +bool PMPropertyBase::setProperty( PMObject* obj, const PMVariant& v ) +{ + if( m_readOnly ) + return false; + PMVariant cp = v; + if( cp.convertTo( m_type ) ) + return setProtected( obj, cp ); + return false; +} + +PMVariant PMPropertyBase::getProperty( const PMObject* obj ) +{ + if( m_writeOnly ) + return PMVariant( ); + return getProtected( obj ); +} + +PMMetaObject::PMMetaObject( const QString& className, PMMetaObject* superClass, + PMObjectFactoryMethod factory ) +{ + m_className = className; + m_pSuperClass = superClass; + m_factory = factory; + + // add the properties of the super class to the dictionary + if( m_pSuperClass ) + m_propertiesDict = superClass->m_propertiesDict; +} + +PMMetaObject::~PMMetaObject( ) +{ + m_properties.setAutoDelete( true ); + m_properties.clear( ); +} + +void PMMetaObject::addProperty( PMPropertyBase* p ) +{ + m_properties.append( p ); + m_propertiesDict.insert( p->name( ), p ); +} + +PMObject* PMMetaObject::newObject( PMPart* part ) const +{ + if( m_factory ) + return m_factory( part ); + return 0; +} diff --git a/kpovmodeler/pmmetaobject.h b/kpovmodeler/pmmetaobject.h new file mode 100644 index 00000000..f8daf2eb --- /dev/null +++ b/kpovmodeler/pmmetaobject.h @@ -0,0 +1,416 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMMETAOBJECT_H +#define PMMETAOBJECT_H + +#include +#include +#include +#include +#include "pmvariant.h" + +class PMPart; + +/** + * Base class for all properties + */ +class PMPropertyBase +{ +public: + /** + * Default constructor + */ + PMPropertyBase( const QString& name, PMVariant::PMVariantDataType t, + bool readOnly = false, bool writeOnly = false ); + /** + * Copy constructor + */ + PMPropertyBase( const PMPropertyBase& p ); + /** + * Destructor + */ + virtual ~PMPropertyBase( ); + + /** + * Returns the properties name + */ + QString name( ) const { return m_name; } + /** + * Returns the data type + */ + PMVariant::PMVariantDataType type( ) const { return m_type; } + + /** + * Sets the property. + * + * Returns true if successful. + * + * Makes a type check and calls @ref setProtected on success. + */ + bool setProperty( PMObject* obj, const PMVariant& ); + + /** + * Returns the property value + */ + PMVariant getProperty( const PMObject* obj ); + + /** + * Returns the number of dimensions for array properties + * or 0 otherwise + */ + virtual int dimensions( ) const { return 0; } + /** + * Has to be reimplemented for array properties. + * + * The first parameter is the dimension, the second the index. + */ + virtual void setIndex( int /*dimension*/, int /*index*/ ) { }; + /** + * Has to be reimplemented for array properties. + * + * Returns the current size for the object and dimension. + */ + virtual int size( PMObject*, int /*dimension*/ ) const { return 0; } + + /** + * Returns true if the property is an enum + */ + virtual bool isEnum( ) const { return false; } + /** + * Returns the list of enum values + */ + virtual QStringList enumValues( ) const { return QStringList( ); } + + /** + * Returns true if the property is read-only. False by default + */ + bool isReadOnly( ) const { return m_readOnly; } + /** + * Returns true if the property is write-only. False by default + */ + bool isWriteOnly( ) const { return m_writeOnly; } + +protected: + /** + * Reimplement this function to call the correct object method. + * + * The variant is already converted to the correct type. + */ + virtual bool setProtected( PMObject* obj, const PMVariant& ) = 0; + + /** + * Reimplement this function to call the correct object method. + */ + virtual PMVariant getProtected( const PMObject* obj ) = 0; + +private: + PMVariant::PMVariantDataType m_type; + QString m_name; + QStringList* m_pEnumList; + bool m_readOnly; + bool m_writeOnly; +}; + +typedef QPtrList PMPropertyList; +typedef QDict PMPropertyDict; +typedef QDictIterator PMPropertyIterator; + +/** + * Macro that defines a property class for a PMObject class + * + * Example: PMDefinePropertyClass( PMBox, PMProperty ); defines + * a class PMProperty that can store pointer to member functions + * for PMBox objects. + * + * Use only in .cpp files. + */ + +#define PMDefinePropertyClass( ObjectClass, PropertyClass ) \ +class PropertyClass : public PMPropertyBase \ +{ \ +public: \ + typedef void ( ObjectClass::*SetIntPtr ) ( int ); \ + typedef void ( ObjectClass::*SetUnsignedPtr ) ( unsigned ); \ + typedef void ( ObjectClass::*SetDoublePtr ) ( double ); \ + typedef void ( ObjectClass::*SetBoolPtr ) ( bool ); \ + typedef void ( ObjectClass::*SetThreeStatePtr )( PMThreeState ); \ + typedef void ( ObjectClass::*SetStringPtr ) ( const QString& ); \ + typedef void ( ObjectClass::*SetVectorPtr ) ( const PMVector& ); \ + typedef void ( ObjectClass::*SetColorPtr ) ( const PMColor& ); \ + typedef void ( ObjectClass::*SetObjectPtr ) ( PMObject* ); \ + \ + typedef int ( ObjectClass::*GetIntPtr ) ( void ) const; \ + typedef unsigned ( ObjectClass::*GetUnsignedPtr ) ( void ) const; \ + typedef double ( ObjectClass::*GetDoublePtr ) ( void ) const; \ + typedef bool ( ObjectClass::*GetBoolPtr ) ( void ) const; \ + typedef PMThreeState ( ObjectClass::*GetThreeStatePtr ) ( void ) const; \ + typedef QString ( ObjectClass::*GetStringPtr ) ( void ) const; \ + typedef PMVector ( ObjectClass::*GetVectorPtr ) ( void ) const; \ + typedef PMColor ( ObjectClass::*GetColorPtr ) ( void ) const; \ + typedef PMObject* ( ObjectClass::*GetObjectPtr ) ( void ) const; \ + \ + PropertyClass( const QString& name, SetIntPtr setFktn, GetIntPtr getFktn ) \ + : PMPropertyBase( name, PMVariant::Integer, \ + setFktn == 0, getFktn == 0 ) \ + { \ + m_setFunction.setInt = setFktn; \ + m_getFunction.getInt = getFktn; \ + } \ + PropertyClass( const QString& name, SetUnsignedPtr setFktn, GetUnsignedPtr getFktn ) \ + : PMPropertyBase( name, PMVariant::Unsigned, \ + setFktn == 0, getFktn == 0 ) \ + { \ + m_setFunction.setUnsigned = setFktn; \ + m_getFunction.getUnsigned = getFktn; \ + } \ + PropertyClass( const QString& name, SetDoublePtr setFktn, GetDoublePtr getFktn ) \ + : PMPropertyBase( name, PMVariant::Double, \ + setFktn == 0, getFktn == 0 ) \ + { \ + m_setFunction.setDouble = setFktn; \ + m_getFunction.getDouble = getFktn; \ + } \ + PropertyClass( const QString& name, SetBoolPtr setFktn, GetBoolPtr getFktn ) \ + : PMPropertyBase( name, PMVariant::Bool, \ + setFktn == 0, getFktn == 0 ) \ + { \ + m_setFunction.setBool = setFktn; \ + m_getFunction.getBool = getFktn; \ + } \ + PropertyClass( const QString& name, SetThreeStatePtr setFktn, GetThreeStatePtr getFktn ) \ + : PMPropertyBase( name, PMVariant::ThreeState, \ + setFktn == 0, getFktn == 0 ) \ + { \ + m_setFunction.setThreeState = setFktn; \ + m_getFunction.getThreeState = getFktn; \ + } \ + PropertyClass( const QString& name, SetStringPtr setFktn, GetStringPtr getFktn ) \ + : PMPropertyBase( name, PMVariant::String, \ + setFktn == 0, getFktn == 0 ) \ + { \ + m_setFunction.setString = setFktn; \ + m_getFunction.getString = getFktn; \ + } \ + PropertyClass( const QString& name, SetVectorPtr setFktn, GetVectorPtr getFktn ) \ + : PMPropertyBase( name, PMVariant::Vector, \ + setFktn == 0, getFktn == 0 ) \ + { \ + m_setFunction.setVector = setFktn; \ + m_getFunction.getVector = getFktn; \ + } \ + PropertyClass( const QString& name, SetColorPtr setFktn, GetColorPtr getFktn ) \ + : PMPropertyBase( name, PMVariant::Color, \ + setFktn == 0, getFktn == 0 ) \ + { \ + m_setFunction.setColor = setFktn; \ + m_getFunction.getColor = getFktn; \ + } \ + PropertyClass( const QString& name, SetObjectPtr setFktn, GetObjectPtr getFktn ) \ + : PMPropertyBase( name, PMVariant::ObjectPointer, \ + setFktn == 0, getFktn == 0 ) \ + { \ + m_setFunction.setObject = setFktn; \ + m_getFunction.getObject = getFktn; \ + } \ + \ +protected: \ + bool setProtected( PMObject* obj, const PMVariant& v ) \ + { \ + ObjectClass* o = ( ObjectClass* ) obj; \ + switch( type( ) ) \ + { \ + case PMVariant::Integer: \ + ( o->*( m_setFunction.setInt ) )( v.intData( ) ); \ + break; \ + case PMVariant::Unsigned: \ + ( o->*( m_setFunction.setUnsigned ) )( v.unsignedData( ) ); \ + break; \ + case PMVariant::Double: \ + ( o->*( m_setFunction.setDouble ) )( v.doubleData( ) ); \ + break; \ + case PMVariant::Bool: \ + ( o->*( m_setFunction.setBool ) )( v.boolData( ) ); \ + break; \ + case PMVariant::ThreeState: \ + ( o->*( m_setFunction.setThreeState ) )( v.threeStateData( ) ); \ + break; \ + case PMVariant::String: \ + ( o->*( m_setFunction.setString ) )( v.stringData( ) ); \ + break; \ + case PMVariant::Vector: \ + ( o->*( m_setFunction.setVector ) )( v.vectorData( ) ); \ + break; \ + case PMVariant::Color: \ + ( o->*( m_setFunction.setColor ) )( v.colorData( ) ); \ + break; \ + case PMVariant::ObjectPointer: \ + ( o->*( m_setFunction.setObject ) )( v.objectData( ) ); \ + break; \ + case PMVariant::None: \ + break; \ + } \ + return true; \ + } \ + \ + PMVariant getProtected( const PMObject* obj ) \ + { \ + const ObjectClass* o = ( const ObjectClass* ) obj; \ + PMVariant result; \ + \ + switch( type( ) ) \ + { \ + case PMVariant::Integer: \ + result.setInt( ( o->*( m_getFunction.getInt ) )( ) ); \ + break; \ + case PMVariant::Unsigned: \ + result.setUnsigned( ( o->*( m_getFunction.getUnsigned ) )( ) ); \ + break; \ + case PMVariant::Double: \ + result.setDouble( ( o->*( m_getFunction.getDouble ) )( ) ); \ + break; \ + case PMVariant::Bool: \ + result.setBool( ( o->*( m_getFunction.getBool ) )( ) ); \ + break; \ + case PMVariant::ThreeState: \ + result.setThreeState( ( o->*( m_getFunction.getThreeState ) )( ) ); \ + break; \ + case PMVariant::String: \ + result.setString( ( o->*( m_getFunction.getString ) )( ) ); \ + break; \ + case PMVariant::Vector: \ + result.setVector( ( o->*( m_getFunction.getVector ) )( ) ); \ + break; \ + case PMVariant::Color: \ + result.setColor( ( o->*( m_getFunction.getColor ) )( ) ); \ + break; \ + case PMVariant::ObjectPointer: \ + result.setObject( ( o->*( m_getFunction.getObject ) )( ) ); \ + break; \ + case PMVariant::None: \ + break; \ + } \ + return result; \ + } \ + \ +private: \ + union \ + { \ + SetIntPtr setInt; \ + SetUnsignedPtr setUnsigned; \ + SetDoublePtr setDouble; \ + SetBoolPtr setBool; \ + SetThreeStatePtr setThreeState; \ + SetStringPtr setString; \ + SetVectorPtr setVector; \ + SetColorPtr setColor; \ + SetObjectPtr setObject; \ + } m_setFunction; \ + \ + union \ + { \ + GetIntPtr getInt; \ + GetUnsignedPtr getUnsigned; \ + GetDoublePtr getDouble; \ + GetBoolPtr getBool; \ + GetThreeStatePtr getThreeState; \ + GetStringPtr getString; \ + GetVectorPtr getVector; \ + GetColorPtr getColor; \ + GetObjectPtr getObject; \ + } m_getFunction; \ +} +// no semicolon, put a semicolon after the macro! + + +typedef PMObject* ( *PMObjectFactoryMethod ) ( PMPart* ); + +/** + * Meta information object for the @ref PMObject class. + * + * Stores information (class name, inheritance hierarchy, + * object properties) for each class. + */ +class PMMetaObject +{ +public: + /** + * Creates a PMMetaObject. The class name has to be the class name + * without the PM prefix. + * + * factoryMethod is a function pointer to a factory method + * with signature PMObject* theMethod( PMPart* ) that returns + * a new object of that type. factoryMethod may be 0 for + * abstract classes. + */ + PMMetaObject( const QString& className, PMMetaObject* superClass = 0, + PMObjectFactoryMethod factoryMethod = 0 ); + /** + * Destructor + */ + ~PMMetaObject( ); + + /** + * Returns the class name + */ + QString className( ) const { return m_className; } + /** + * Returns the meta object of the super class + */ + PMMetaObject* superClass( ) const { return m_pSuperClass; } + /** + * Returns a new object instance + */ + PMObject* newObject( PMPart* part ) const; + /** + * Returns true if the class is an abstract class + * (if no factory method was set in the constructor) + */ + bool isAbstract( ) const { return m_factory == 0; } + + /** + * Adds a property. + * + * The meta object becomes the owner of the property object + */ + void addProperty( PMPropertyBase* p ); + /** + * Returns an iterator to the properties + */ + PMPropertyIterator properties( ) const + { + return PMPropertyIterator( m_propertiesDict ); + } + /** + * Returns a property by name or 0 if a property with the name + * doesn't exist. + */ + PMPropertyBase* property( const QString& name ) const + { + return m_propertiesDict.find( name ); + } + +private: + QString m_className; + PMMetaObject* m_pSuperClass; + PMPropertyList m_properties; + PMPropertyDict m_propertiesDict; + PMObjectFactoryMethod m_factory; +}; + +#endif diff --git a/kpovmodeler/pmmovecommand.cpp b/kpovmodeler/pmmovecommand.cpp new file mode 100644 index 00000000..1d70f3e0 --- /dev/null +++ b/kpovmodeler/pmmovecommand.cpp @@ -0,0 +1,478 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmmovecommand.h" +#include "pmobject.h" +#include "pmpart.h" +#include "pmcommandmanager.h" +#include "pmdeclare.h" +#include "pmerrorflags.h" +#include "pmrecursiveobjectiterator.h" +#include "pmmemento.h" +#include "pmdebug.h" + +#include +#include + +PMMoveCommand::PMMoveCommand( PMObject* obj, PMObject* parent, PMObject* after ) + : PMCommand( i18n( "Move %1" ).arg( obj->description( ) ) ) +{ + m_pParent = parent; + m_pAfter = after; + + if( obj->parent( ) ) + { + m_infoList.append( new PMDeleteInfo( obj ) ); + } + else + { + // object has no parent! + // top level objects can't be moved, move all child items + PMObject* tmp; + for( tmp = obj->firstChild( ); tmp; tmp = tmp->nextSibling( ) ) + m_infoList.append( new PMDeleteInfo( tmp ) ); + } + + m_executed = false; + m_firstExecution = true; +} + +PMMoveCommand::PMMoveCommand( const PMObjectList& list, PMObject* parent, + PMObject* after ) + : PMCommand( i18n( "Move Objects" ) ) +{ + PMObjectListIterator it( list ); + + for( ; it.current( ); ++it ) + { + if( it.current( )->parent( ) ) + m_infoList.append( new PMDeleteInfo( it.current( ) ) ); + else + { + // object has no parent! + // top level objects can't be moved, move all child items + PMObject* tmp; + for( tmp = it.current( )->firstChild( ); tmp; tmp = tmp->nextSibling( ) ) + m_infoList.append( new PMDeleteInfo( tmp ) ); + } + } + + m_pParent = parent; + m_pAfter = after; + m_executed = false; + m_firstExecution = true; +} + +PMMoveCommand::~PMMoveCommand( ) +{ + if( m_executed ) + { + m_insertErrors.setAutoDelete( true ); + m_insertErrors.clear( ); + } +} + +void PMMoveCommand::execute( PMCommandManager* theManager ) +{ + if( !m_executed ) + { + // remove objects + PMDeleteInfoListIterator it( m_infoList ); + PMObject* prev = m_pAfter; + PMObject* obj; + bool error = false; + PMDeleteInfo* info = 0; + PMObject* parent; + + for( it.toLast( ); it.current( ); --it ) + { + info = it.current( ); + parent = info->parent( ); + // signal has to be emitted before the item is removed + theManager->cmdObjectChanged( info->deletedObject( ), PMCRemove ); + if( m_firstExecution ) + if( parent->dataChangeOnInsertRemove( ) + && !parent->mementoCreated( ) ) + parent->createMemento( ); + parent->takeChild( info->deletedObject( ) ); + } + + // insert at new position + if( m_firstExecution ) + if( m_pParent->dataChangeOnInsertRemove( ) + && !m_pParent->mementoCreated( ) ) + m_pParent->createMemento( ); + + for( it.toFirst( ); it.current( ); ++it ) + { + if( !it.current( )->insertError( ) ) + { + obj = it.current( )->deletedObject( ); + + if( !prev ) + { + if( m_pParent->canInsert( obj, 0 ) ) + { + m_pParent->insertChild( obj, 0 ); + prev = obj; + theManager->cmdObjectChanged( obj, PMCAdd ); + } + else + error = true; + } + else + { + if( m_pParent->canInsert( obj, prev ) ) + { + m_pParent->insertChildAfter( obj, prev ); + prev = obj; + theManager->cmdObjectChanged( obj, PMCAdd ); + } + else + error = true; + } + + if( error ) + { + m_insertErrors.append( it.current( )->deletedObject( ) ); + it.current( )->setInsertError( ); + theManager->cmdObjectChanged( obj, PMCAdd | PMCInsertError ); + error = false; + } + } + } + + if( m_firstExecution ) + { + if( m_pParent->mementoCreated( ) ) + m_dataChanges.append( m_pParent->takeMemento( ) ); + + for( it.toLast( ); it.current( ); --it ) + { + info = it.current( ); + parent = info->parent( ); + + if( parent->mementoCreated( ) ) + m_dataChanges.append( parent->takeMemento( ) ); + } + } + + QPtrListIterator mit( m_dataChanges ); + for( ; mit.current( ); ++mit ) + { + PMObjectChangeListIterator change = mit.current( )->changedObjects( ); + for( ; change.current( ); ++change ) + theManager->cmdObjectChanged( change.current( )->object( ), + change.current( )->mode( ) ); + } + + m_executed = true; + m_firstExecution = true; + } +} + +void PMMoveCommand::undo( PMCommandManager* theManager ) +{ + if( m_executed ) + { + PMDeleteInfoListIterator it( m_infoList ); + PMObject* obj; + for( it.toLast( ) ; it.current( ); --it ) + { + // signal has to be emitted before the item is removed + obj = it.current( )->deletedObject( ); + theManager->cmdObjectChanged( obj, PMCRemove ); + if( obj->parent( ) ) + obj->parent( )->takeChild( obj ); + } + + for( it.toFirst( ); it.current( ); ++it ) + { + obj = it.current( )->deletedObject( ); + if( it.current( )->prevSibling( ) ) + it.current( )->parent( ) + ->insertChildAfter( obj, it.current( )->prevSibling( ) ); + else + it.current( )->parent( )->insertChild( obj, 0 ); + theManager->cmdObjectChanged( obj, PMCAdd ); + } + + QPtrListIterator mit( m_dataChanges ); + for( ; mit.current( ); ++mit ) + { + mit.current( )->originator( )->restoreMemento( mit.current( ) ); + PMObjectChangeListIterator change = mit.current( )->changedObjects( ); + for( ; change.current( ); ++change ) + theManager->cmdObjectChanged( change.current( )->object( ), + change.current( )->mode( ) ); + } + + m_executed = false; + } +} + +int PMMoveCommand::errorFlags( PMPart* ) +{ + PMDeleteInfo* info; + PMDeclare* decl = 0; + PMObject* obj; + bool insideSelection; + bool ok = true; + bool declareInsertError = false; + bool error = false; + bool stop; + + // dictionary of deleted objects + QPtrDict deletedObjects( 1009 ); + deletedObjects.setAutoDelete( true ); + QPtrDict objectsAfterInsertPosition( 1009 ); + objectsAfterInsertPosition.setAutoDelete( true ); + QPtrDict declaresBeforeInsertPosition( 199 ); + declaresBeforeInsertPosition.setAutoDelete( true ); + + + PMDeleteInfoListIterator it( m_infoList ); + for( ; it.current( ); ++it ) + deletedObjects.insert( it.current( )->deletedObject( ), + new bool( true ) ); + + // declares can only be moved, if all linked + // objects are moved as well or the insert position is before the first + // linked object and all declares can be inserted + + info = m_infoList.last( ); + + while( info ) + { + ok = true; + declareInsertError = false; + + if( info->deletedObject( )->isA( "Declare" ) ) + { + decl = ( PMDeclare* ) ( info->deletedObject( ) ); + + if( !m_pParent->canInsert( decl, m_pAfter ) ) + { + declareInsertError = true; + ok = false; + } + else + { + PMObjectListIterator links = decl->linkedObjects( ); + + for( ; links.current( ) && ok; ++links ) + { + insideSelection = false; + for( obj = links.current( ); obj && !insideSelection; + obj = obj->parent( ) ) + { + if( deletedObjects.find( obj ) ) + insideSelection = true; + } + + if( insideSelection ) + { + bool stop = false; + for( obj = links.current( ); obj && !stop; obj = obj->parent( ) ) + { + if( deletedObjects.find( obj ) ) + stop = true; + else + deletedObjects.insert( obj, new bool( true ) ); + } + } + else + { + // link will not be moved + // check, if after insert position + // declares can only be inserted as childs of the scene + + if( m_pAfter ) + { + // insert point is not the first item + // find the top level parent item + stop = false; + obj = links.current( ); + do + { + if( obj->parent( ) ) + { + if( obj->parent( )->type( ) == "Scene" ) + stop = true; + else + obj = obj->parent( ); + } + else + stop = true; // error + } + while( !stop ); + + PMObject* topParent = obj; + + // check if insert point is before the top level + // parent object + + if( !objectsAfterInsertPosition.find( obj ) ) + { + stop = false; + obj = obj->prevSibling( ); + while( obj && !stop ) + { + if( obj == m_pAfter ) + stop = true; + else if( objectsAfterInsertPosition.find( obj ) ) + stop = true; + else + obj = obj->prevSibling( ); + } + + if( stop ) + objectsAfterInsertPosition.insert( topParent, new bool( true ) ); + else + ok = false; + } + } + } + } + } + } + + if( !ok ) + { + if( declareInsertError ) + m_errors.prepend( i18n( "Can't insert the declare \"%1\" at that point." ) + .arg( decl->id( ) ) ); + else + m_errors.prepend( i18n( "The declare \"%1\" can't be moved behind linked objects." ) + .arg( decl->id( ) ) ); + + PMDeleteInfo* tmp = info; + info = m_infoList.prev( ); + deletedObjects.remove( tmp->deletedObject( ) ); + m_infoList.removeRef( tmp ); + + error = true; + } + else + info = m_infoList.prev( ); + } + + // check if links are moved before the declare object + + // find all declares bevore the insert position + if( m_pParent->type( ) == "Scene" ) + obj = m_pAfter; + else + { + stop = false; + obj = m_pParent; + do + { + if( obj->parent( ) ) + { + if( obj->parent( )->type( ) == "Scene" ) + stop = true; + else + obj = obj->parent( ); + } + else + stop = true; // error + } + while( !stop ); + + if( obj ) + obj = obj->prevSibling( ); + } + + while( obj ) + { + if( obj->isA( "Declare" ) ) + declaresBeforeInsertPosition.insert( obj, new bool( true ) ); + obj = obj->prevSibling( ); + } + + info = m_infoList.first( ); + while( info ) + { + ok = true; + PMRecursiveObjectIterator it( info->deletedObject( ) ); + PMObject* linked = 0; + + while( it.current( ) && ok ) + { + linked = it.current( )->linkedObject( ); + + if( linked ) + { + if( !deletedObjects.find( linked ) ) + { + // Object is linked to a declare and the declare + // will not be moved. + // Check, if the insert point is after the declare + + if( !declaresBeforeInsertPosition.find( linked ) ) + ok = false; + } + } + + if( ok ) + ++it; + } + + if( ok ) + info = m_infoList.next( ); + else + { + if( linked ) + { + obj = info->deletedObject( ); + QString name = obj->name( ); + decl = ( PMDeclare* ) linked; + + if( name.isEmpty( ) ) + name = i18n( "(unnamed)" ); + m_errors.append( i18n( "The %1 \"%2\" can't be moved because it " + "contains a link to the declare \"%3\" " + "and the insert point is not after " + "the declare." ) + .arg( obj->description( ) ).arg( name ) + .arg( decl->id( ) ) ); + } + else + kdError( PMArea ) << "linked is 0 in PMMoveCommand::errorFlags\n"; + + + PMDeleteInfo* tmp = info; + info = m_infoList.next( ); + deletedObjects.remove( tmp->deletedObject( ) ); + m_infoList.removeRef( tmp ); + + error = true; + } + } + + if( error ) + { + if( m_infoList.count( ) == 0 ) + return PMEError | PMEFatal; + else + return PMEError; + } + + return PMENone; +} diff --git a/kpovmodeler/pmmovecommand.h b/kpovmodeler/pmmovecommand.h new file mode 100644 index 00000000..75250fd2 --- /dev/null +++ b/kpovmodeler/pmmovecommand.h @@ -0,0 +1,88 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMMOVECOMMAND_H +#define PMMOVECOMMAND_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmcommand.h" +#include "pmdeletecommand.h" + +class PMObject; +class PMMemento; + +/** + * Command class for moving objects + */ +class PMMoveCommand : public PMCommand +{ +public: + /** + * Command that moves one PMObject. + * + * The object obj will be inserted as child of parent after + * the object after. + * + * If after is 0, the object becomes the first child. + */ + PMMoveCommand( PMObject* obj, PMObject* parent, PMObject* after ); + + /** + * Command that moves a list of new PMObjects. + * The objects don't have to be siblings of each other. + * + * The object in the list will be inserted as children of parent after + * the object after. + * + * If after is 0, the objects will be inserted as first children. + */ + PMMoveCommand( const PMObjectList& list, PMObject* parent, PMObject* after ); + /** + * Deletes the command. + */ + virtual ~PMMoveCommand( ); + + /** */ + virtual int errorFlags( PMPart* ); + +protected: + /** + * Executes the command and stores undo information + */ + virtual void execute( PMCommandManager* theManager ); + /** + * Undo the command + */ + virtual void undo( PMCommandManager* theManager ); + +private: + PMObject* m_pParent; + PMObject* m_pAfter; + + PMDeleteInfoList m_infoList; + PMObjectList m_insertErrors; + bool m_executed; + bool m_firstExecution; + QPtrList m_dataChanges; +}; + +#endif diff --git a/kpovmodeler/pmnamedobject.cpp b/kpovmodeler/pmnamedobject.cpp new file mode 100644 index 00000000..d6d6ab09 --- /dev/null +++ b/kpovmodeler/pmnamedobject.cpp @@ -0,0 +1,111 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmnamedobject.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" + +PMDefinePropertyClass( PMNamedObject, PMNamedObjectProperty ); + +PMMetaObject* PMNamedObject::s_pMetaObject = 0; + +PMNamedObject::PMNamedObject( PMPart* part ) + : Base( part ) +{ +} + +PMNamedObject::PMNamedObject( const PMNamedObject& o ) + : Base( o ) +{ + m_name = o.m_name; +} + +PMNamedObject::~PMNamedObject( ) +{ +} + +PMMetaObject* PMNamedObject::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "NamedObject", Base::metaObject( ) ); + s_pMetaObject->addProperty( + new PMNamedObjectProperty( "name", &PMNamedObject::setName, &PMNamedObject::name ) ); + } + return s_pMetaObject; +} + +void PMNamedObject::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMNamedObject::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "name", m_name ); + Base::serialize( e, doc ); +} + +void PMNamedObject::readAttributes( const PMXMLHelper& h ) +{ + m_name = h.stringAttribute( "name", "" ); + Base::readAttributes( h ); +} + +void PMNamedObject::setName( const QString& newName ) +{ + if( newName != m_name ) + { + if( m_pMemento ) + { + m_pMemento->addData( s_pMetaObject, PMNameID, m_name ); + m_pMemento->setDescriptionChanged( ); + } + + m_name = newName; + } +} + +void PMNamedObject::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMNameID: + setName( data->stringData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMNamedObject::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmnamedobject.h b/kpovmodeler/pmnamedobject.h new file mode 100644 index 00000000..d4cdee2c --- /dev/null +++ b/kpovmodeler/pmnamedobject.h @@ -0,0 +1,89 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMNAMEDOBJECT_H +#define PMNAMEDOBJECT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmcompositeobject.h" + +/** + * class for all objects with free choose-able names (all objects except + * include files, the scene and declares) + */ + +class PMNamedObject : public PMCompositeObject +{ + typedef PMCompositeObject Base; +public: + /** + * Creates an empty PMNamedObject + */ + PMNamedObject( PMPart* part ); + /** + * Copy constructor + */ + PMNamedObject( const PMNamedObject& o ); + /** + * Deletes the object + */ + ~PMNamedObject( ); + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns the name of the object. This is the name that helps + * the user to identify a object (like "south_wall", "floor" ...) */ + virtual QString name( ) const { return m_name; } + /** + * Sets the name of the object. + */ + virtual void setName( const QString& newName ); + /** + * Returns true if the object can have a name + */ + virtual bool canHaveName( ) const { return true; } + + /** */ + virtual void restoreMemento( PMMemento* s ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMNamedObjectMementoID { PMNameID }; + + /** + * Name of the object + */ + QString m_name; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmnamedobjectedit.cpp b/kpovmodeler/pmnamedobjectedit.cpp new file mode 100644 index 00000000..35a6c96c --- /dev/null +++ b/kpovmodeler/pmnamedobjectedit.cpp @@ -0,0 +1,81 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmnamedobjectedit.h" +#include "pmnamedobject.h" + +#include +#include +#include +#include + +PMNamedObjectEdit::PMNamedObjectEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMNamedObjectEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* layout = new QHBoxLayout( topLayout( ) ); + m_pNameEdit = new QLineEdit( this ); + QLabel* label = new QLabel( i18n( "Name:" ), this ); + + layout->addWidget( label ); + layout->addWidget( m_pNameEdit ); + + connect( m_pNameEdit, SIGNAL( textChanged( const QString& ) ), + SLOT( slotNameChanged( const QString& ) ) ); +} + +void PMNamedObjectEdit::displayObject( PMObject* o ) +{ + if( o->isA( "NamedObject" ) ) + { + m_pDisplayedObject = ( PMNamedObject* ) o; + m_pNameEdit->setText( m_pDisplayedObject->name( ) ); + + m_pNameEdit->setReadOnly( m_pDisplayedObject->isReadOnly( ) ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMNamedObjectEdit: Can't display object\n"; +} + +void PMNamedObjectEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setName( m_pNameEdit->text( ) ); + } +} + +bool PMNamedObjectEdit::isDataValid( ) +{ + return Base::isDataValid( ); +} + +void PMNamedObjectEdit::slotNameChanged( const QString& ) +{ + emit dataChanged( ); +} +#include "pmnamedobjectedit.moc" diff --git a/kpovmodeler/pmnamedobjectedit.h b/kpovmodeler/pmnamedobjectedit.h new file mode 100644 index 00000000..8d9dff40 --- /dev/null +++ b/kpovmodeler/pmnamedobjectedit.h @@ -0,0 +1,64 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMNAMEDOBJECTEDIT_H +#define PMNAMEDOBJECTEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMNamedObject; +class QLineEdit; + +/** + * Dialog edit class for @ref PMNamedObject. + */ +class PMNamedObjectEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMNamedObjectEdit with parent and name + */ + PMNamedObjectEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private slots: + void slotNameChanged( const QString& ); +private: + PMNamedObject* m_pDisplayedObject; + QLineEdit* m_pNameEdit; +}; + + +#endif diff --git a/kpovmodeler/pmnormal.cpp b/kpovmodeler/pmnormal.cpp new file mode 100644 index 00000000..77fdddd1 --- /dev/null +++ b/kpovmodeler/pmnormal.cpp @@ -0,0 +1,189 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmnormal.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmnormaledit.h" +#include "pmlistpattern.h" +#include "pmpattern.h" + +#include + +const double bumpSizeDefault = 0.0; +const double accuracyDefault = 0.02; + +PMDefinePropertyClass( PMNormal, PMNormProperty ); + +PMMetaObject* PMNormal::s_pMetaObject = 0; +PMObject* createNewNormal( PMPart* part ) +{ + return new PMNormal( part ); +} + +PMNormal::PMNormal( PMPart* part ) + : Base( part ) +{ + m_enableBumpSize = false; + m_bumpSize = bumpSizeDefault; + m_accuracy = accuracyDefault; + m_uvMapping = false; +} + +PMNormal::PMNormal( const PMNormal& n ) + : Base( n ) +{ + m_enableBumpSize = n.m_enableBumpSize; + m_bumpSize = n.m_bumpSize; + m_accuracy = n.m_accuracy; + m_uvMapping = n.m_uvMapping; +} + +PMNormal::~PMNormal( ) +{ +} + +PMMetaObject* PMNormal::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Normal", Base::metaObject( ), + createNewNormal ); + s_pMetaObject->addProperty( + new PMNormProperty( "bumpSize", &PMNormal::setBumpSize, &PMNormal::bumpSize ) ); + s_pMetaObject->addProperty( + new PMNormProperty( "bumpSizeEnabled", &PMNormal::enableBumpSize, &PMNormal::isBumpSizeEnabled ) ); + s_pMetaObject->addProperty( + new PMNormProperty( "accuracy", &PMNormal::setAccuracy, &PMNormal::accuracy ) ); + s_pMetaObject->addProperty( + new PMNormProperty( "uvMapping", &PMNormal::setUVMapping, &PMNormal::uvMapping ) ); + } + return s_pMetaObject; +} + +void PMNormal::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMNormal::description( ) const +{ + return i18n( "normal" ); +} + +void PMNormal::serialize( QDomElement& e, QDomDocument& doc ) const +{ + Base::serialize( e, doc ); + e.setAttribute( "enable_bump_size", m_enableBumpSize ); + e.setAttribute( "bump_size", m_bumpSize ); + e.setAttribute( "accuracy", m_accuracy ); + e.setAttribute( "uv_mapping", m_uvMapping ); +} + +void PMNormal::readAttributes( const PMXMLHelper& h ) +{ + Base::readAttributes( h ); + m_enableBumpSize = h.boolAttribute( "enable_bump_size", false ); + m_bumpSize = h.doubleAttribute( "bump_size", bumpSizeDefault ); + m_accuracy = h.doubleAttribute( "accuracy", accuracyDefault ); + m_uvMapping = h.boolAttribute( "uv_mapping", false ); +} + +PMDialogEditBase* PMNormal::editWidget( QWidget* parent ) const +{ + return new PMNormalEdit( parent ); +} + +void PMNormal::enableBumpSize( bool c ) +{ + if( c != m_enableBumpSize ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableBumpSizeID, m_enableBumpSize ); + m_enableBumpSize = c; + } +} + +void PMNormal::setBumpSize( double c ) +{ + if( c != m_bumpSize ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMBumpSizeID, m_bumpSize ); + m_bumpSize = c; + } +} + +void PMNormal::setAccuracy( double c ) +{ + if( c!= m_accuracy ) + { + if ( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAccuracyID, m_accuracy ); + m_accuracy = c; + } +} + +void PMNormal::setUVMapping( bool m ) +{ + if( m != m_uvMapping ) + { + if ( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMUVMappingID, m_uvMapping ); + m_uvMapping = m; + } +} + +void PMNormal::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMEnableBumpSizeID: + enableBumpSize( data->boolData( ) ); + break; + case PMBumpSizeID: + setBumpSize( data->doubleData( ) ); + break; + case PMAccuracyID: + setAccuracy( data->doubleData( ) ); + break; + case PMUVMappingID: + setUVMapping( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMNormal::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + diff --git a/kpovmodeler/pmnormal.h b/kpovmodeler/pmnormal.h new file mode 100644 index 00000000..81ec0547 --- /dev/null +++ b/kpovmodeler/pmnormal.h @@ -0,0 +1,122 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMNORMAL_H +#define PMNORMAL_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebase.h" + +/** + * Class for povray normals + */ +class PMNormal : public PMTextureBase +{ + typedef PMTextureBase Base; +public: + /** + * Creates an PMNormal + */ + PMNormal( PMPart* part ); + /** + * Copy constructor + */ + PMNormal( const PMNormal& n ); + /** + * Deletes the object + */ + virtual ~PMNormal( ); + + /** */ + virtual PMObject* copy( ) const { return new PMNormal( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMNormalEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pmnormal" ); } + + /** */ + virtual void restoreMemento( PMMemento* s ); + + /** + * Returns true if bump_size is enabled + */ + bool isBumpSizeEnabled( ) const { return m_enableBumpSize; } + /** + * enables/disables bump_size + */ + void enableBumpSize( bool c ); + /** + * Returns the normal's bump size + */ + double bumpSize( ) const { return m_bumpSize; } + /** + * Sets the normal's bump size + */ + void setBumpSize( double c ); + /** + * Returns the normal's accuracy + */ + double accuracy( ) const { return m_accuracy; } + /** + * Sets the normal's accuracy + */ + void setAccuracy( double c ); + /** + * Returns the uv mapping flag + */ + bool uvMapping( ) const { return m_uvMapping; } + /** + * Sets the uv mapping flag + */ + void setUVMapping( bool m ); + +private: + /** + * IDs for @ref PMMementoData + */ + enum PMNormalMementoID { PMEnableBumpSizeID, PMBumpSizeID, PMAccuracyID, PMUVMappingID }; + + bool m_enableBumpSize; + double m_bumpSize; + double m_accuracy; + bool m_uvMapping; + + static PMMetaObject* s_pMetaObject; +}; + + +#endif diff --git a/kpovmodeler/pmnormaledit.cpp b/kpovmodeler/pmnormaledit.cpp new file mode 100644 index 00000000..161f2b0b --- /dev/null +++ b/kpovmodeler/pmnormaledit.cpp @@ -0,0 +1,118 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmnormaledit.h" +#include "pmnormal.h" +#include "pmlinkedit.h" +#include "pmlineedits.h" + +#include +#include +#include +#include + + +PMNormalEdit::PMNormalEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMNormalEdit::createTopWidgets( ) +{ + QHBoxLayout* hl; + + Base::createTopWidgets( ); + + hl = new QHBoxLayout( topLayout( ) ); + m_pBumpSizeCheck = new QCheckBox( i18n( "Bump size" ), this ); + m_pBumpSizeEdit = new PMFloatEdit( this ); + hl->addWidget( m_pBumpSizeCheck ); + hl->addWidget( m_pBumpSizeEdit ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + QLabel* lbl = new QLabel( i18n( "Accuracy" ), this ); + m_pAccuracy = new PMFloatEdit( this ); + hl->addWidget( lbl ); + hl->addWidget( m_pAccuracy ); + hl->addStretch( 1 ); + + m_pUVMapping = new QCheckBox( i18n( "UV mapping" ), this ); + topLayout( )->addWidget( m_pUVMapping ); + + connect( m_pBumpSizeCheck, SIGNAL( clicked( ) ), SLOT( slotBumpSizeClicked( )) ); + connect( m_pBumpSizeEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( )) ); + connect( m_pAccuracy, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pUVMapping, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMNormalEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Normal" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMNormal* )o; + + m_pBumpSizeCheck->setChecked( m_pDisplayedObject->isBumpSizeEnabled( ) ); + m_pBumpSizeCheck->setEnabled( !readOnly ); + m_pBumpSizeEdit->setValue( m_pDisplayedObject->bumpSize( ) ); + m_pBumpSizeEdit->setReadOnly( readOnly ); + slotBumpSizeClicked( ); + m_pAccuracy->setValue( m_pDisplayedObject->accuracy( ) ); + m_pAccuracy->setReadOnly( readOnly ); + m_pUVMapping->setChecked( m_pDisplayedObject->uvMapping() ); + m_pUVMapping->setEnabled( !readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMNormalEdit: Can't display object\n"; +} + +void PMNormalEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->enableBumpSize( m_pBumpSizeCheck->isChecked( ) ); + m_pDisplayedObject->setBumpSize( m_pBumpSizeEdit->value( ) ); + m_pDisplayedObject->setAccuracy( m_pAccuracy->value( ) ); + m_pDisplayedObject->setUVMapping( m_pUVMapping->isChecked() ); + } +} + +bool PMNormalEdit::isDataValid( ) +{ + if( !m_pBumpSizeEdit->isDataValid( ) ) return false; + if( !m_pAccuracy->isDataValid( ) ) return false; + + return Base::isDataValid( ); +} + +void PMNormalEdit::slotBumpSizeClicked( ) +{ + if( m_pBumpSizeCheck->isChecked( ) ) + m_pBumpSizeEdit->show( ); + else + m_pBumpSizeEdit->hide( ); + emit sizeChanged( ); + emit dataChanged( ); +} + +#include "pmnormaledit.moc" diff --git a/kpovmodeler/pmnormaledit.h b/kpovmodeler/pmnormaledit.h new file mode 100644 index 00000000..631db778 --- /dev/null +++ b/kpovmodeler/pmnormaledit.h @@ -0,0 +1,70 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMNORMALEDIT_H +#define PMNORMALEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebaseedit.h" + +class PMNormal; +class QCheckBox; +class PMFloatEdit; + +/** + * Dialog edit class for @ref PMNormal + */ +class PMNormalEdit : public PMTextureBaseEdit +{ + Q_OBJECT + typedef PMTextureBaseEdit Base; +public: + /** + * Creates a PMNormalEdit with parent and name + */ + PMNormalEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + /** */ + virtual bool isDataValid( ); + +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + void slotBumpSizeClicked( ); + +private: + PMNormal* m_pDisplayedObject; + + QCheckBox* m_pBumpSizeCheck; + PMFloatEdit* m_pBumpSizeEdit; + PMFloatEdit* m_pAccuracy; + QCheckBox* m_pUVMapping; +}; + + +#endif diff --git a/kpovmodeler/pmobject.cpp b/kpovmodeler/pmobject.cpp new file mode 100644 index 00000000..d6bb94b3 --- /dev/null +++ b/kpovmodeler/pmobject.cpp @@ -0,0 +1,283 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmobject.h" +#include "pmcontrolpoint.h" +#include "pmdialogeditbase.h" +#include "pmmemento.h" +#include "pmprototypemanager.h" +#include "pminsertrulesystem.h" +#include "pmpart.h" + +PMDefinePropertyClass( PMObject, PMObjectProperty ); + +PMMetaObject* PMObject::s_pMetaObject = 0; + +PMObject::PMObject( PMPart* part ) +{ + m_pParent = 0; + m_selected = false; + m_pPrevSibling = 0; + m_pNextSibling = 0; + m_pMemento = 0; + m_readOnly = false; + m_pPart = part; + + if( !m_pPart ) + kdError( PMArea ) << "PMObject::PMObject: The part may not be null" << endl; +} + +PMObject::PMObject( const PMObject& o ) +{ + m_pParent = 0; + m_selected = false; + m_pPrevSibling = 0; + m_pNextSibling = 0; + m_pMemento = 0; + m_readOnly = false; + m_pPart = o.m_pPart; +} + +PMObject::~PMObject( ) +{ +} + +PMMetaObject* PMObject::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Object", 0 ); + s_pMetaObject->addProperty( + new PMObjectProperty( "readOnly", &PMObject::setReadOnly, &PMObject::isReadOnly ) ); + s_pMetaObject->addProperty( + new PMObjectProperty( "numberOfChildren", 0, &PMObject::countChildren ) ); + } + return s_pMetaObject; +} + +PMObject* PMObject::newObject( ) const +{ + return metaObject( )->newObject( m_pPart ); +} + +bool PMObject::insertChildAfter( PMObject*, PMObject* ) +{ + kdError( PMArea ) << "Tried to insert object into a non composite object" << "\n"; + return false; +} + +bool PMObject::insertChildBefore( PMObject*, PMObject* ) +{ + kdError( PMArea ) << "Tried to insert object into a non composite object" << "\n"; + return false; +} + +void PMObject::setSelected( bool s ) +{ + if( m_selected != s ) + { + if( s ) + { + if( isSelectable( ) ) + { + m_selected = true; + if( m_pParent ) + m_pParent->adjustSelectedChildren( 1 ); + } + } + else + { + m_selected = false; + if( m_pParent ) + m_pParent->adjustSelectedChildren( -1 ); + } + } +} + +bool PMObject::isSelectable( ) +{ + bool is = true; + PMObject* o; + + for( o = m_pParent; o && is; o = o->m_pParent ) + if( o->isSelected( ) ) + is = false; + + return is; +} + +bool PMObject::isReadOnly( ) const +{ + if( m_readOnly ) + return true; + if( m_pParent ) + return m_pParent->isReadOnly( ); + return false; +} + +bool PMObject::takeChild( PMObject* ) +{ + kdError( PMArea ) << "Tried to remove object out of a non composite object" << "\n"; + return false; +} + +bool PMObject::takeChild( uint ) +{ + kdError( PMArea ) << "Tried to remove object out of a non composite object" << "\n"; + return false; +} + +PMDialogEditBase* PMObject::editWidget( QWidget* parent ) const +{ + return new PMDialogEditBase( parent ); +// return 0; +} + +void PMObject::createMemento( ) +{ + if( m_pMemento ) + delete m_pMemento; + m_pMemento = new PMMemento( this ); +} + +PMMemento* PMObject::takeMemento( ) +{ + PMMemento* tmp = m_pMemento; + m_pMemento = 0; + return tmp; +} + +void PMObject::restoreMemento( PMMemento* /* s */ ) +{ + // nothing to be done at the moment +} + +PMMatrix PMObject::transformedWith( ) const +{ + PMMatrix result = PMMatrix::identity( ); + const PMObject* o = this; + + if( o->firstChild( ) ) + o = o->firstChild( ); + else if( o->nextSibling( ) ) + o = o->nextSibling( ); + else + o = o->parent( ); + + while( o ) + { + if( o->hasTransformationMatrix( ) ) + result = o->transformationMatrix( ) * result; + + if( o->nextSibling( ) ) + o = o->nextSibling( ); + else + o = o->parent( ); + } + + return result; +} + +QDomElement PMObject::serialize( QDomDocument& doc ) const +{ + QDomElement e = doc.createElement( className( ).lower( ) ); + serialize( e, doc ); + return e; +} + +void PMObject::readAttributes( const PMXMLHelper& ) +{ +} + +void PMObject::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } +} + +bool PMObject::setProperty( const QString& name, const PMVariant& v ) +{ + PMPropertyBase* p = metaObject( )->property( name ); + if( !p ) + return false; + return p->setProperty( this, v ); +} + +QStringList PMObject::properties( ) const +{ + QStringList lst; + PMPropertyIterator it = metaObject( )->properties( ); + + for( ; it.current( ); ++it ) + lst.append( it.current( )->name( ) ); + + return lst; +} + +PMVariant PMObject::property( const QString& name ) const +{ + PMPropertyBase* p = metaObject( )->property( name ); + if( !p ) + return PMVariant( ); + return p->getProperty( this ); +} + +bool PMObject::isA( const QString& className ) const +{ + if( !m_pPart ) + return false; + return m_pPart->prototypeManager( )->isA( metaObject( ), className ); +} + +QString PMObject::type( ) const +{ + return metaObject( )->className( ); +} + +bool PMObject::canInsert( const QString& className, const PMObject* after, + const PMObjectList* objectsBetween ) const +{ + if( !m_pPart ) + return false; + return m_pPart->insertRuleSystem( )->canInsert( this, className, after, objectsBetween ); +} + +bool PMObject::canInsert( const PMObject* o, const PMObject* after, + const PMObjectList* objectsBetween ) const +{ + if( !m_pPart ) + return false; + return m_pPart->insertRuleSystem( )->canInsert( this, o, after, objectsBetween ); +} + +int PMObject::canInsert( const PMObjectList& list, const PMObject* after ) const +{ + if( !m_pPart ) + return false; + return m_pPart->insertRuleSystem( )->canInsert( this, list, after ); +} + +int PMObject::canInsert( const QStringList& classes, const PMObject* after ) const +{ + if( !m_pPart ) + return false; + return m_pPart->insertRuleSystem( )->canInsert( this, classes, after ); +} diff --git a/kpovmodeler/pmobject.h b/kpovmodeler/pmobject.h new file mode 100644 index 00000000..0c11008b --- /dev/null +++ b/kpovmodeler/pmobject.h @@ -0,0 +1,511 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMOBJECT_H +#define PMOBJECT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "pmmatrix.h" +#include "pmcontrolpoint.h" +#include "pmmetaobject.h" +#include "pmdebug.h" + +class PMDialogEditBase; +class PMMemento; +class PMViewStructure; +class PMXMLHelper; +class PMDeclare; +class PMObjectAction; +class PMPart; + +class PMObject; +typedef QPtrList PMObjectList; +typedef QPtrListIterator PMObjectListIterator; + +/** + * Base class for all povray objects + * + * Used pattern: Composite + * + * All list/child functionality is disabled in this class. Objects that + * can have children has to be inherited from @ref PMCompositeObject. + */ +class PMObject +{ + friend class PMCompositeObject; +public: + /** + * Creates an empty PMObject without parent. + */ + PMObject( PMPart* part ); + /** + * Copy constructor. All object pointers (parent, siblings) are set to 0! + */ + PMObject( const PMObject& o ); + /** + * Deletes the object and all children. + */ + virtual ~PMObject( ); + + /** + * Returns a new object of that type + */ + PMObject* newObject( ) const; + /** + * Returns a deep copy of the object + */ + virtual PMObject* copy( ) const = 0; + + /** + * Returns the meta object for the class + */ + virtual PMMetaObject* metaObject( ) const; + + /** + * Returns true if the object is of type t or inherits the object + * class with type t + */ + bool isA( const QString& className ) const; + + /** + * Returns the class name (not i18n'ed, without the PM prefix) + */ + QString type( ) const; + /** + * same as @ref type( ) + */ + QString className( ) const { return type( ); } + /** + * Returns the class name of the object (povray name). + * This is the name that is showed in dialogs and menus. + */ + virtual QString description( ) const = 0; + /** + * Returns the name of the object. This is the name that helps + * the user to identify a object (like "south wall", "floor" ...) + */ + virtual QString name( ) const { return QString::null; } + /** + * Returns true if the object can have a name + */ + virtual bool canHaveName( ) const { return false; } + /** + * Returns true if the object should be exported for rendering + */ + virtual bool exportPovray( ) const { return true; } + + /** + * Returns a pointer to the parent object. + */ + PMObject* parent( ) const { return m_pParent; } + /** + * Returns a pointer to the corresponding part + */ + PMPart* part( ) const { return m_pPart; } + + /** + * Returns true if an object with type className can be inserted + * as child after the object after. + * + * The parser uses the third parameter for top level objects. These objects + * have to be treated as if they are inserted after the object after. + */ + bool canInsert( const QString& className, const PMObject* after, + const PMObjectList* objectsBetween = 0 ) const; + /** + * Returns true if the object o can be inserted as child after the object + * after. + * + * The parser uses the third parameter for top level objects. These objects + * have to be treated as if they are inserted after the object after. + */ + bool canInsert( const PMObject* o, const PMObject* after, + const PMObjectList* objectsBetween = 0 ) const; + /** + * Returns the number of objects that can be inserted at that position + */ + int canInsert( const PMObjectList& list, const PMObject* after ) const; + /** + * Returns the number of objects that can be inserted at that position + */ + int canInsert( const QStringList& classes, const PMObject* after ) const; + + /** + * Returns true if an insert or remove operation of children will + * change data inside this class + */ + virtual bool dataChangeOnInsertRemove( ) const { return false; } + + /** + * Returns a pointer to the first child. Null for this class + */ + virtual PMObject* firstChild( ) const { return 0; } + /** + * Returns a pointer to the last child. Null for this class + */ + virtual PMObject* lastChild( ) const { return 0; } + /** + * Returns a pointer to the child object at position index, + * or null if the index is out of range. + */ + virtual PMObject* childAt( uint ) const { return 0; } + /** + * Returns the next sibling of that item + */ + PMObject* nextSibling( ) const { return m_pNextSibling; } + /** + * Returns the previous sibling of that item + */ + PMObject* prevSibling( ) const { return m_pPrevSibling; } + + /** + * Returns true if the object contains the child object o + */ + virtual bool containsChild( PMObject* ) const { return false; } + /** + * Returns the index of the child or -1 if not found + */ + virtual int findChild( PMObject* ) { return -1; } + /** + * Inserts the object as child at index index. + * If i is -1, the object is appended. + * Returns true if successful + */ + virtual bool insertChild( PMObject*, int ) + { + kdError( PMArea ) << "Tried to insert object into a non composite object" << "\n"; + return false; + } + /** + * Inserts the object as child after the child object after + */ + virtual bool insertChildAfter( PMObject* object, PMObject* after ); + /** + * Inserts the object as child before the child object before + */ + virtual bool insertChildBefore( PMObject* object, PMObject* before ); + /** + * Appends the object as last child. Returns true if successful + */ + virtual bool appendChild( PMObject* ) + { + kdError( PMArea ) << "Tried to insert object into a non composite object" << "\n"; + return false; + } + /** + * Returns the number of children. 0 in this class + */ + virtual int countChildren( ) const { return 0; } + /** + * Removes a child object. Does not delete it! + * Returns true if successful + */ + virtual bool takeChild( PMObject* ); + /** + * Removes a child object at index i. Does not delete it! + * Returns true if successful + */ + virtual bool takeChild( uint ); + + /** + * Called when a child was removed. For classes that have to be informed + * when children are removed + */ + virtual void childRemoved( PMObject* ) { }; + /** + * Called when a child was added. For classes that have to be informed + * when children are added + */ + virtual void childAdded( PMObject* ) { }; + + /** + * Returns true if the object needs auxiliary files. + */ + virtual bool needsAuxiliaryFiles( ) const { return false; } + /** + * Returns a list of auxiliary files + */ + virtual QStringList auxiliaryFiles( ) const { return QStringList( ); } + + /** + * Returns true if the object has a (povray) transformation matrix. + * True for transformation objects. + */ + virtual bool hasTransformationMatrix( ) const { return false; } + /** + * Returns the (povray) transformation of the object, if it has one, + * otherwise an identity matrix + */ + virtual PMMatrix transformationMatrix( ) const + { + kdError( PMArea ) << "This object has no transformation matrix" << "\n"; + return PMMatrix::identity( ); + } + /** + * Returns the matrix, the object is transformed with + */ + PMMatrix transformedWith( ) const; + + /** + * Returns the view structure ( see @ref PMViewStructure ) of the object + * or 0, if it has none. + * + * The view structure will be created or updated if necessary. + */ + virtual PMViewStructure* viewStructure( ) { return 0; } + + /** + * Creates the control points and appends them to the list. + * + * The caller becomes the owner of the control points and has + * to delete them. + * + * Control points are the interface between the graphical views and the + * PMObject for graphical changes. + */ + virtual void controlPoints( PMControlPointList& ) { } + /** + * Tells the object that the control points have changed + */ + virtual void controlPointsChanged( PMControlPointList& ) { } + /** + * Tells the object that the control points have changed + * + * The object can add objects to the second parameter, if + * additional objects were changed during the graphical change, + * not only this object. + * + * If you leave the list empty, only this object was changed. + * If you add children or other objects to the list, add this object + * to the list, too, if it was changed! + * + * IMPORTANT: When you change additional objects, make sure that + * a memento is created for these objects (@ref mementoCreated, + * @ref createMemento) before changing data. + * + * Calls @ref controlPointsChanged by default. + */ + virtual void controlPointsChangedList( PMControlPointList& list, + PMObjectList& /*changedObjects*/ ) + { + controlPointsChanged( list ); + } + /** + * Returns true if multiple control points can be selected + */ + virtual bool multipleSelectControlPoints( ) const { return false; } + + /** + * Each object can add actions to the context menu of the @ref PMGLView. + * + * Each time the user opens the context menu, this function is called. + * Add all supported actions to this list and call the base class. + * + * The default implementation adds no action. + * + * @see PMObjectAction + */ + virtual void addObjectActions( const PMControlPointList&, + QPtrList& ) { } + + /** + * This member is called when the user selects an object action + * in the context menu. + * + * The arguments are the selected action, the list of control points, + * the 3D (!) positions of the control points (screen-x, screen-y and depth) + * in the active opengl view and the 2D mouse position. + */ + virtual void objectActionCalled( const PMObjectAction*, + const PMControlPointList&, + const QPtrList&, + const PMVector& ) { }; + + /** + * Saves the object as kpovmodeler xml code. + */ + QDomElement serialize( QDomDocument& doc ) const; + /** + * Adds the objects attributes and child objects to the element + */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const = 0; + /** + * Reads the attributes from the QDomElement + */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns the list of known properties + */ + QStringList properties( ) const; + + /** + * Sets a property and returns true if successful + */ + bool setProperty( const QString&, const PMVariant& v ); + /** + * Returns a property + */ + PMVariant property( const QString& ) const; + + /** + * Returns true if the object is selected + */ + bool isSelected( ) { return m_selected; } + /** + * Sets this object to be selected if s is true and to not be selected + if s is false + */ + void setSelected( bool s ); + /** + * Returns true if this item can be selected. An item cannot be selected + * if a parent object is selected + */ + bool isSelectable( ); + /** + * Returns the number of selected child items. All selected items in + * any depth are counted + */ + virtual int selectedChildren( ) const { return 0; } + /** + * Deselects recursively all child objects + */ + virtual void deselectChildren( ) { }; + /** + * Returns true if this object is read only + */ + bool isReadOnly( ) const; + /** + * Makes this object read only, if yes == true. All children will + * be read only, too + */ + void setReadOnly( bool yes = true ) { m_readOnly = yes; } + + /** + * Creates a new edit widget that can display this object and + * returns a pointer to it. + * + * The widget will be created as a child of parent. + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const = 0; + /** + * Returns a pointer to the @ref PMDeclare object, that is linked to + * that object, or 0, if this object contains no link + */ + virtual PMDeclare* linkedObject( ) const { return 0; } + + /** + * Tells the object to create a memento object. + * + * By default a simple @ref PMMemento will be created. + * If the memento doesn't provide enough functionality, subclass the memento + * and reimplement this function. + * + * NOTE: The new memento has to inherit the memento used in the base class! + * + * If a memento was created, the object saves all changes its + * state. The memento is then used for undo/redo. + * + * First call this function, change attributes and then take the mementos + * with @ref takeMemento + * + * If you want to restore the old state, call @ref restoreMemento with + * the memento. + */ + virtual void createMemento( ); + /** + * Returns true if a memento was created + */ + bool mementoCreated( ) const { return m_pMemento != 0; } + /** + * Takes the memento. The caller is responsible to delete the memento + */ + PMMemento* takeMemento( ); + /** + * Restores the state s + */ + virtual void restoreMemento( PMMemento* s ); + + /** + * This function is called before the part is unloaded. + * + * Delete static pointer variables to clean up the memory. + * + * This method can be called multiple times when there are subclasses. + * Set the pointer to 0 after deleting an object! + */ + virtual void cleanUp( ) const; + +protected: + /** + * Adds num to the number of selected objects in this object and all + * parent objects. num can be negative. + */ + virtual void adjustSelectedChildren( int /*num*/ ) { }; + /** + * The memento where the old status of the object should be stored + */ + PMMemento* m_pMemento; +private: + /** + * Pointer to the parent object. 0 if the object has no parent. + */ + PMObject* m_pParent; + /** + * Pointer to the prev sibling. 0 if the object has no prev sibling. + */ + PMObject* m_pPrevSibling; + /** + * Pointer to the next sibling. 0 if the object has no next sibling. + */ + PMObject* m_pNextSibling; + /** + * true if this object is selected + */ + bool m_selected; + /** + * true if this object is read only. All children will be read only, too + */ + bool m_readOnly; + /** + * The meta object + */ + static PMMetaObject* s_pMetaObject; + /** + * The corresponding part + */ + PMPart* m_pPart; +}; + +#endif diff --git a/kpovmodeler/pmobjectaction.h b/kpovmodeler/pmobjectaction.h new file mode 100644 index 00000000..e9a843ce --- /dev/null +++ b/kpovmodeler/pmobjectaction.h @@ -0,0 +1,100 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMOBJECTACTION_H +#define PMOBJECTACTION_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmvector.h" +#include "pmcontrolpoint.h" +#include "pmmetaobject.h" +#include +#include + +class KAction; + +/** + * Helper class for object action functions. + * + * Each object can define actions that are inserted into the context + * menu. This class stores informations of one action. + * + * The actionID has to be unique for each class. + * + * The member m_action is set later by the framework. + */ +class PMObjectAction +{ +public: + /** + * Constructor + */ + PMObjectAction( PMMetaObject* objectType, int actionID, + const QString& description, bool enabled = true ) + { + m_class = objectType; + m_actionID = actionID; + m_description = description; + m_enabled = enabled; + m_menuID = -1; + } + + /** + * Returns the class type for the action + */ + PMMetaObject* objectType( ) const { return m_class; } + /** + * Returns the action ID + */ + int actionID( ) const { return m_actionID; } + /** + * Returns the description + */ + QString description( ) const { return m_description; } + + /** + * Returns the enabled flag + */ + bool isEnabled( ) const { return m_enabled; } + /** + * Sets the enabled flag + */ + void setEnabled( bool enable ) { m_enabled = enable; } + + /** + * Returns the menu id + */ + int menuID( ) const { return m_menuID; } + /** + * Sets the menu id + */ + void setMenuID( int id ) { m_menuID = id; } + +private: + PMMetaObject* m_class; + int m_actionID; + QString m_description; + bool m_enabled; + int m_menuID; +}; + +#endif diff --git a/kpovmodeler/pmobjectdrag.cpp b/kpovmodeler/pmobjectdrag.cpp new file mode 100644 index 00000000..6bebfc8e --- /dev/null +++ b/kpovmodeler/pmobjectdrag.cpp @@ -0,0 +1,230 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmobjectdrag.h" +#include "pmobject.h" +#include "pmpart.h" +#include "pmpovrayparser.h" +#include "pmxmlparser.h" +#include "pmxmlhelper.h" +#include "pmdocumentformat.h" +#include "pmiomanager.h" +#include "pmserializer.h" + +#include +#include + +const char* const c_kpmDocumentMimeFormat = "application/x-kpovmodeler"; + +PMObjectDrag::PMObjectDrag( PMPart* part, PMObject* object, QWidget* dragSource, + const char* name ) + : QDragObject( dragSource, name ) +{ + QByteArray modelerData; + + QTextStream s2( modelerData, IO_WriteOnly ); + QDomDocument doc( "KPOVMODELER" ); + QDomElement top = doc.createElement( "objects" ); + doc.appendChild( top ); + top.setAttribute( "majorFormat", c_majorDocumentFormat ); + top.setAttribute( "minorFormat", c_minorDocumentFormat ); + + if( object->type( ) == "Scene" ) + { + PMObject* o = object->firstChild( ); + for( ; o; o = o->nextSibling( ) ) + { + QDomElement e = o->serialize( doc ); + top.appendChild( e ); + } + } + else + { + QDomElement e = object->serialize( doc ); + top.appendChild( e ); + } + s2 << doc; + + m_data.push_back( modelerData ); + m_mimeTypes.push_back( c_kpmDocumentMimeFormat ); + + const QPtrList& formats = part->ioManager( )->formats( ); + QPtrListIterator it( formats ); + for( ; it.current( ); ++it ) + { + if( it.current( )->services( ) & PMIOFormat::Export ) + { + QByteArray data; + QBuffer buffer( data ); + buffer.open( IO_WriteOnly ); + + PMSerializer* ser = it.current( )->newSerializer( &buffer ); + + if( ser ) + { + ser->serialize( object ); + ser->close( ); + delete ser; + buffer.close( ); + + m_data.push_back( data ); + m_mimeTypes.push_back( it.current( )->mimeType( ) ); + + kdDebug( PMArea ) << "Added mime type " << it.current( )->mimeType( ) + << " " << data.size( ) << " bytes" << endl; + } + else + kdError( PMArea ) << "Format claims to support exporting, but doesn't provide a serializer" << endl; + + buffer.close( ); + } + } +} + +PMObjectDrag::PMObjectDrag( PMPart* part, const PMObjectList& objList, QWidget* dragSource, + const char* name ) + : QDragObject( dragSource, name ) +{ + QByteArray modelerData; + + QTextStream s2( modelerData, IO_WriteOnly ); + QDomDocument doc( "KPOVMODELER" ); + QDomElement top = doc.createElement( "objects" ); + doc.appendChild( top ); + top.setAttribute( "majorFormat", c_majorDocumentFormat ); + top.setAttribute( "minorFormat", c_minorDocumentFormat ); + + PMObjectListIterator it( objList ); + for( ; it.current( ); ++it ) + { + if( it.current( )->type( ) == "Scene" ) + { + PMObject* o = it.current( )->firstChild( ); + for( ; o; o = o->nextSibling( ) ) + { + QDomElement e = o->serialize( doc ); + top.appendChild( e ); + } + } + else + { + QDomElement e = it.current( )->serialize( doc ); + top.appendChild( e ); + } + } + + s2 << doc; + + m_data.push_back( modelerData ); + m_mimeTypes.push_back( c_kpmDocumentMimeFormat ); + + const QPtrList& formats = part->ioManager( )->formats( ); + QPtrListIterator fit( formats ); + for( ; fit.current( ); ++fit ) + { + if( fit.current( )->services( ) & PMIOFormat::Export ) + { + QByteArray data; + QBuffer buffer( data ); + buffer.open( IO_WriteOnly ); + + PMSerializer* ser = fit.current( )->newSerializer( &buffer ); + + if( ser ) + { + ser->serializeList( objList ); + ser->close( ); + delete ser; + buffer.close( ); + + m_data.push_back( data ); + m_mimeTypes.push_back( fit.current( )->mimeType( ) ); + + kdDebug( PMArea ) << "Added mime type " << fit.current( )->mimeType( ) + << " " << data.size( ) << " bytes" << endl; + } + else + kdError( PMArea ) << "Format claims to support exporting, but doesn't provide a serializer" << endl; + + buffer.close( ); + } + } +} + +PMObjectDrag::~PMObjectDrag( ) +{ +} + +QByteArray PMObjectDrag::encodedData( const char* format ) const +{ + QValueList::ConstIterator dit; + QStringList::ConstIterator sit; + + for( dit = m_data.begin( ), sit = m_mimeTypes.begin( ); + dit != m_data.end( ) && sit != m_mimeTypes.end( ); ++dit, ++sit ) + { + if( *sit == format ) + return *dit; + } + + QByteArray empty; + return empty; +} + +const char* PMObjectDrag::format( int i /*=0*/ ) const +{ + if( i >= 0 && i < ( signed ) m_mimeTypes.size( ) ) + return ( *m_mimeTypes.at( i ) ).latin1( ); + return 0; +} + +bool PMObjectDrag::canDecode( const QMimeSource* e, PMPart* part ) +{ + if( e->provides( c_kpmDocumentMimeFormat ) ) + return true; + + const QPtrList& formats = part->ioManager( )->formats( ); + QPtrListIterator fit( formats ); + for( ; fit.current( ); ++fit ) + if( fit.current( )->services( ) & PMIOFormat::Import && + e->provides( fit.current( )->mimeType( ).latin1( ) ) ) + return true; + + return false; +} + +PMParser* PMObjectDrag::newParser( const QMimeSource* e, PMPart* part ) +{ + if( e->provides( c_kpmDocumentMimeFormat ) ) + return new PMXMLParser( part, e->encodedData( c_kpmDocumentMimeFormat ) ); + + const QPtrList& formats = part->ioManager( )->formats( ); + QPtrListIterator fit( formats ); + for( ; fit.current( ); ++fit ) + { + PMIOFormat* f = fit.current( ); + QString str = f->mimeType( ); + const char* lat = str.latin1( ); + if( f->services( ) & PMIOFormat::Import && e->provides( lat ) ) + return f->newParser( part, e->encodedData( lat ) ); + } + + return 0; +} + + diff --git a/kpovmodeler/pmobjectdrag.h b/kpovmodeler/pmobjectdrag.h new file mode 100644 index 00000000..a8f4daf3 --- /dev/null +++ b/kpovmodeler/pmobjectdrag.h @@ -0,0 +1,81 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMOBJECTDRAG_H +#define PMOBJECTDRAG_H + +#include +#include + +#include "pmobject.h" +class PMParser; +class PMPart; + +/** + * Supports drag/drop and copy/paste of kpovmodeler objects + */ + +class PMObjectDrag : public QDragObject +{ +public: + /** + * Creates a drag object for one object + * + * The object drag will contain all formats that are supported + * by the part. + * @see PMIOManager + */ + PMObjectDrag( PMPart* part, PMObject* object, QWidget* dragSource = 0, + const char* name = 0 ); + /** + * Creates a drag object for all objects in objList + */ + PMObjectDrag( PMPart* part, const PMObjectList& objList, QWidget* dragSource = 0, + const char* name = 0 ); + /** + * Deletes the drag object + */ + ~PMObjectDrag( ); + /** + * Returns the encoded payload of this object, in the + * specified MIME format. + */ + virtual QByteArray encodedData( const char* ) const; + /** + * Returns the ith format, or NULL. + */ + virtual const char* format( int i = 0 ) const; + /** + * Returns true if the information in e can be decoded + */ + static bool canDecode( const QMimeSource* e, PMPart* part ); + /** + * Returns a pointer to a parser for this drag object or 0, if the data + * can't be decoded. + * + * The caller is responsible to delete the parser. + */ + static PMParser* newParser( const QMimeSource* e, PMPart* part ); + +private: + QValueList m_data; + QStringList m_mimeTypes; +}; + +#endif diff --git a/kpovmodeler/pmobjectlibrarysettings.cpp b/kpovmodeler/pmobjectlibrarysettings.cpp new file mode 100644 index 00000000..ce80f77c --- /dev/null +++ b/kpovmodeler/pmobjectlibrarysettings.cpp @@ -0,0 +1,189 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.org + copyright : (C) 2003 by Luis Carvalho + email : lpassos@oninetspeed.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#include "pmobjectlibrarysettings.h" + +#include "pmlibrarymanager.h" +#include "pmlibraryhandle.h" +#include "pmlibraryhandleedit.h" +#include "pmdebug.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +PMObjectLibrarySettings::PMObjectLibrarySettings( QWidget* parent, const char* name ) + : PMSettingsDialogPage( parent, name ) +{ + QVBoxLayout* vlayout = new QVBoxLayout( this, 0, KDialog::spacingHint( ) ); + + QGroupBox* gb = new QGroupBox( i18n( "Libraries" ), this ); + vlayout->addWidget( gb ); + + QHBoxLayout* hlayout = new QHBoxLayout( gb, KDialog::marginHint( ) + 5, KDialog::spacingHint( ) ); + m_pObjectLibraries = new QListBox( gb ); + connect( m_pObjectLibraries, SIGNAL( selectionChanged( ) ), SLOT( slotObjectLibraryChanged( ) ) ); + hlayout->addWidget( m_pObjectLibraries ); + QVBoxLayout* gvl = new QVBoxLayout( hlayout ); + m_pCreateObjectLibrary = new QPushButton( i18n( "Create..." ), gb ); + connect( m_pCreateObjectLibrary, SIGNAL( clicked( ) ), SLOT( slotCreateObjectLibrary( ) ) ); + gvl->addWidget( m_pCreateObjectLibrary ); + m_pRemoveObjectLibrary = new QPushButton( i18n( "Remove" ), gb ); + connect( m_pRemoveObjectLibrary, SIGNAL( clicked( ) ), SLOT( slotRemoveObjectLibrary( ) ) ); + gvl->addWidget( m_pRemoveObjectLibrary ); + m_pImportObjectLibrary = new QPushButton( i18n( "Import" ), gb ); + connect( m_pImportObjectLibrary, SIGNAL( clicked( ) ), SLOT( slotImportObjectLibrary( ) ) ); + gvl->addWidget( m_pImportObjectLibrary ); + m_pModifyObjectLibrary = new QPushButton( i18n( "Properties" ), gb ); + connect( m_pModifyObjectLibrary, SIGNAL( clicked( ) ), SLOT( slotModifyObjectLibrary( ) ) ); + gvl->addWidget( m_pModifyObjectLibrary ); + gvl->addStretch( 1 ); + + gb = new QGroupBox( i18n( "Library Details" ), this ); + QGridLayout* grid = new QGridLayout( gb, 4, 2, KDialog::marginHint( ) + 5, KDialog::spacingHint( ) ); + QLabel* lbl = new QLabel( i18n( "Path" ), gb ); + grid->addWidget( lbl, 0, 0 ); + lbl = new QLabel( i18n( "Author" ), gb ); + grid->addWidget( lbl, 1, 0 ); + lbl = new QLabel( i18n( "Description" ), gb ); + grid->addWidget( lbl, 2, 0 ); + m_pLibraryPath = new QLabel( "", gb ); + m_pLibraryAuthor = new QLabel( "", gb ); + m_pLibraryDescription = new QLabel( "", gb ); + m_pReadOnlyText = new QLabel( "", gb ); + grid->addWidget( m_pLibraryPath, 0, 1 ); + grid->addWidget( m_pLibraryAuthor, 1, 1 ); + grid->addWidget( m_pLibraryDescription, 2, 1 ); + grid->addMultiCellWidget( m_pReadOnlyText, 3, 3, 0, 1 ); + grid->setColStretch( 1, 1 ); + vlayout->addWidget( gb ); + + vlayout->addStretch( 1 ); +} + +void PMObjectLibrarySettings::displaySettings( ) +{ + m_pObjectLibraries->clear( ); + m_pObjectLibraries->insertStringList( PMLibraryManager::theManager( )->availableLibraries( ) ); +} + +void PMObjectLibrarySettings::applySettings( ) +{ +} + +bool PMObjectLibrarySettings::validateData( ) +{ + return true; +} + +void PMObjectLibrarySettings::displayDefaults( ) +{ +} + +void PMObjectLibrarySettings::slotImportObjectLibrary( ) +{ + // TODO +} + +void PMObjectLibrarySettings::slotModifyObjectLibrary( ) +{ + PMLibraryHandle* h = PMLibraryManager::theManager( )->getLibraryHandle( m_pObjectLibraries->currentText( ) ); + if( h ) + { + PMLibraryHandleEdit h_dlg( h, this ); + + if( h_dlg.exec( ) == QDialog::Accepted ) + { + h->saveLibraryInfo( ); + displaySettings( ); + for( unsigned i = 0; i < m_pObjectLibraries->count( ); ++i ) + { + if( m_pObjectLibraries->text( i ) == h->name( ) ) + { + m_pObjectLibraries->setSelected( i, true ); + break; + } + } + slotObjectLibraryChanged( ); + } + } +} + +void PMObjectLibrarySettings::slotRemoveObjectLibrary( ) +{ + m_pObjectLibraries->removeItem( m_pObjectLibraries->currentItem( ) ); +} + +void PMObjectLibrarySettings::slotCreateObjectLibrary( ) +{ + PMLibraryHandle h; + PMLibraryHandleEdit h_dlg( &h, this ); + QString libfilename; + + if( h_dlg.exec( ) == QDialog::Accepted ) + { + libfilename = h.name( ); + h.setPath( locateLocal( "appdata", "library/" ) + libfilename.stripWhiteSpace( ) + "/" ); + // Create the new library + switch( h.createLibrary( ) ) + { + case PMLibraryHandle::Ok: + PMLibraryManager::theManager( )->refresh( ); + displaySettings( ); + break; + case PMLibraryHandle::ExistingDir: + KMessageBox::error( this, i18n( "The folder already exists." ) ); + break; + case PMLibraryHandle::CouldNotCreateDir: + KMessageBox::error( this, i18n( "Could not create the folder." ) ); + break; + default: + kdError( PMArea ) << "Unexpected error in slotCreateObjectLibrary." << endl; + } + } +} + +void PMObjectLibrarySettings::slotObjectLibraryChanged( ) +{ + PMLibraryHandle* h = PMLibraryManager::theManager( )->getLibraryHandle( m_pObjectLibraries->currentText( ) ); + if( h ) + { + m_pLibraryPath->setText( h->path( ) ); + m_pLibraryAuthor->setText( h->author( ) ); + m_pLibraryDescription->setText( h->description( ) ); + if( h->isReadOnly( ) ) + m_pReadOnlyText->setText( i18n( "This library is not modifiable." ) ); + else + m_pReadOnlyText->setText( i18n( "This library is modifiable." ) ); + } + else + { + m_pLibraryPath->setText( "" ); + m_pLibraryAuthor->setText( "" ); + m_pLibraryDescription->setText( "" ); + m_pReadOnlyText->setText( "" ); + } +} + +#include "pmobjectlibrarysettings.moc" diff --git a/kpovmodeler/pmobjectlibrarysettings.h b/kpovmodeler/pmobjectlibrarysettings.h new file mode 100644 index 00000000..1c4c9ab9 --- /dev/null +++ b/kpovmodeler/pmobjectlibrarysettings.h @@ -0,0 +1,78 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.org + copyright : (C) 2003 by Luis Carvalho + email : lpassos@oninetspeed.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#ifndef PMOBJECTLIBRARYSETTINGS_H +#define PMOBJECTLIBRARYSETTINGS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsettingsdialog.h" + +class QPushButton; +class QListBox; + +/** + * Object library configuration dialog page + */ +class PMObjectLibrarySettings : public PMSettingsDialogPage +{ + Q_OBJECT +public: + /** + * Default constructor + */ + PMObjectLibrarySettings( QWidget* parent, const char* name = 0 ); + /** */ + virtual void displaySettings( ); + /** */ + virtual void applySettings( ); + /** */ + virtual bool validateData( ); + /** */ + virtual void displayDefaults( ); +protected slots: + /** Called when the object library create button is clicked */ + void slotCreateObjectLibrary( ); + /** Called when the object library properties button is clicked */ + void slotModifyObjectLibrary( ); + /** Called when the object library remove button is clicked */ + void slotRemoveObjectLibrary( ); + /** Called when the object library import button is clicked */ + void slotImportObjectLibrary( ); + /** Called when the selected library is changed */ + void slotObjectLibraryChanged( ); +private: + int m_objectLibraryIndex; + int m_selectionIndex; + QListBox* m_pObjectLibraries; + QPushButton* m_pCreateObjectLibrary; + QPushButton* m_pModifyObjectLibrary; + QPushButton* m_pRemoveObjectLibrary; + QPushButton* m_pImportObjectLibrary; + + QLabel* m_pLibraryPath; + QLabel* m_pLibraryAuthor; + QLabel* m_pLibraryDescription; + QLabel* m_pReadOnlyText; +}; + + +#endif diff --git a/kpovmodeler/pmobjectlink.cpp b/kpovmodeler/pmobjectlink.cpp new file mode 100644 index 00000000..6596471d --- /dev/null +++ b/kpovmodeler/pmobjectlink.cpp @@ -0,0 +1,197 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmobjectlink.h" +#include "pmdeclare.h" +#include "pmpart.h" +#include "pmsymboltable.h" +#include "pmobjectlinkedit.h" +#include "pmparser.h" + +#include "pmmemento.h" +#include "pmxmlhelper.h" + +#include + +PMDefinePropertyClass( PMObjectLink, PMObjectLinkProperty ); + +PMMetaObject* PMObjectLink::s_pMetaObject = 0; +PMObject* createNewObjectLink( PMPart* part ) +{ + return new PMObjectLink( part ); +} + +PMObjectLink::PMObjectLink( PMPart* part ) + : Base( part ) +{ + m_pLinkedObject = 0; +} + +PMObjectLink::PMObjectLink( const PMObjectLink& o ) + : Base( o ) +{ + m_pLinkedObject = 0; + setLinkedObject( o.m_pLinkedObject ); +} + +PMObjectLink::~PMObjectLink( ) +{ +} + +QString PMObjectLink::description( ) const +{ + return i18n( "object link" ); +} + +PMMetaObject* PMObjectLink::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "ObjectLink", Base::metaObject( ), + createNewObjectLink ); + s_pMetaObject->addProperty( + new PMObjectLinkProperty( "linkedObject", &PMObjectLink::setLinkedObjectProperty, + &PMObjectLink::linkedObjectProperty ) ); + } + return s_pMetaObject; +} + +void PMObjectLink::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +bool PMObjectLink::setLinkedObject( PMDeclare* obj ) +{ + if( obj ) + { + if( obj->declareType( ) == "GraphicalObject" || + obj->declareType( ) == "Light" ) + { + if( m_pLinkedObject != obj ) + { + if( m_pMemento ) + { + m_pMemento->addData( s_pMetaObject, PMLinkedObjectID, + m_pLinkedObject ); + m_pMemento->setViewStructureChanged( ); + } + + if( m_pLinkedObject ) + { + m_pLinkedObject->removeLinkedObject( this ); + if( m_pMemento ) + m_pMemento->addChangedObject( m_pLinkedObject, PMCData ); + } + m_pLinkedObject = obj; + m_pLinkedObject->addLinkedObject( this ); + if( m_pMemento ) + m_pMemento->addChangedObject( m_pLinkedObject, PMCData ); + } + return true; + } + else + return false; + } + else + { + if( m_pLinkedObject != 0 ) + { + if( m_pMemento ) + { + m_pMemento->addData( s_pMetaObject, PMLinkedObjectID, + m_pLinkedObject ); + m_pMemento->addChangedObject( m_pLinkedObject, PMCData ); + } + m_pLinkedObject->removeLinkedObject( this ); + m_pLinkedObject = 0; + } + return true; + } + return false; +} + +void PMObjectLink::setLinkedObjectProperty( PMObject* o ) +{ + if( o == 0 ) + setLinkedObject( 0 ); + else if( o->isA( "Declare" ) ) + setLinkedObject( ( PMDeclare* ) o ); +} + +void PMObjectLink::serialize( QDomElement& e, QDomDocument& doc ) const +{ + if( m_pLinkedObject ) + e.setAttribute( "prototype", m_pLinkedObject->id( ) ); + Base::serialize( e, doc ); +} + +void PMObjectLink::readAttributes( const PMXMLHelper& h ) +{ + QString id = h.stringAttribute( "prototype", "" ); + if( !id.isEmpty( ) ) + { + PMDeclare* link = h.parser( )->checkLink( id ); + if( link ) + { + if( link->type( ) == "Declare" ) + { + m_pLinkedObject = ( PMDeclare* ) link; + m_pLinkedObject->addLinkedObject( this ); + } + else + h.parser( )->printError( i18n( "Declare \"%1\" has wrong type." ) + .arg( id ) ); + } + } + Base::readAttributes( h ); +} + +PMDialogEditBase* PMObjectLink::editWidget( QWidget* parent ) const +{ + return new PMObjectLinkEdit( parent ); +} + +void PMObjectLink::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMLinkedObjectID: + setLinkedObject( ( PMDeclare* ) data->objectData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMObjectLink::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmobjectlink.h b/kpovmodeler/pmobjectlink.h new file mode 100644 index 00000000..54eb4833 --- /dev/null +++ b/kpovmodeler/pmobjectlink.h @@ -0,0 +1,99 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMOBJECTLINK_H +#define PMOBJECTLINK_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" +#include "pmdeclare.h" + +/** + * Class for links of graphical objects. + */ +class PMObjectLink : public PMSolidObject +{ + typedef PMSolidObject Base; +public: + /** + * Creates an empty PMObjectLink + */ + PMObjectLink( PMPart* part ); + /** + * Copy constructor + */ + PMObjectLink( const PMObjectLink& ol ); + /** + * deletes the PMObjectLink + */ + virtual ~PMObjectLink( ); + + /** */ + virtual PMObject* copy( ) const { return new PMObjectLink( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual PMDeclare* linkedObject( ) const { return m_pLinkedObject; } + /** + * Sets the linked object. Returns true if successful + */ + bool setLinkedObject( PMDeclare* o ); + + /** + * Method used by the properties framework + */ + PMObject* linkedObjectProperty( ) const { return m_pLinkedObject; } + /** + * Method used by the properties framework + */ + void setLinkedObjectProperty( PMObject* o ); + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMObjectLinkEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pmobjectlink" ); } + + /** */ + virtual void restoreMemento( PMMemento* s ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMObjectLinkMementoID { PMLinkedObjectID }; + PMDeclare* m_pLinkedObject; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmobjectlinkedit.cpp b/kpovmodeler/pmobjectlinkedit.cpp new file mode 100644 index 00000000..935f8714 --- /dev/null +++ b/kpovmodeler/pmobjectlinkedit.cpp @@ -0,0 +1,74 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmobjectlinkedit.h" +#include "pmobjectlink.h" +#include "pmdeclare.h" +#include "pmobjectselect.h" +#include "pmlinkedit.h" + +#include + +PMObjectLinkEdit::PMObjectLinkEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMObjectLinkEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + m_pLinkEdit = new PMLinkEdit( this ); + QStringList l; + l.append( "GraphicalObject" ); + l.append( "Light" ); + m_pLinkEdit->setLinkPossibilities( l ); + topLayout( )->addWidget( m_pLinkEdit ); + connect( m_pLinkEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMObjectLinkEdit::displayObject( PMObject* o ) +{ + if( o->isA( "ObjectLink" ) ) + { + m_pDisplayedObject = ( PMObjectLink* ) o; + m_pLinkEdit->setDisplayedObject( m_pDisplayedObject ); + m_pLinkEdit->setReadOnly( m_pDisplayedObject->isReadOnly( ) ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMObjectLinkEdit: Can't display object\n"; +} + +void PMObjectLinkEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setLinkedObject( m_pLinkEdit->link( ) ); + } +} + +bool PMObjectLinkEdit::isDataValid( ) +{ + return Base::isDataValid( ); +} + +#include "pmobjectlinkedit.moc" diff --git a/kpovmodeler/pmobjectlinkedit.h b/kpovmodeler/pmobjectlinkedit.h new file mode 100644 index 00000000..2f517951 --- /dev/null +++ b/kpovmodeler/pmobjectlinkedit.h @@ -0,0 +1,62 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMOBJECTLINKEDIT_H +#define PMOBJECTLINKEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" + +class PMObjectLink; +class PMLinkEdit; + +/** + * Dialog edit class for @ref PMObjectLink. + */ +class PMObjectLinkEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMObjectLinkEdit with parent and name + */ + PMObjectLinkEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMObjectLink* m_pDisplayedObject; + PMLinkEdit* m_pLinkEdit; +}; + + +#endif diff --git a/kpovmodeler/pmobjectselect.cpp b/kpovmodeler/pmobjectselect.cpp new file mode 100644 index 00000000..fb9fa0ce --- /dev/null +++ b/kpovmodeler/pmobjectselect.cpp @@ -0,0 +1,361 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmobjectselect.h" +#include "pmfactory.h" +#include +#include + +PMListBoxObject::PMListBoxObject( QListBox* listbox, PMObject* obj, + QListBoxItem* after ) + : QListBoxPixmap( listbox, + SmallIcon( obj->pixmap( ), PMFactory::instance( ) ), + checkName( obj->name( ) ), after ) +{ + m_pObject = obj; +} + +PMListBoxObject::PMListBoxObject( QListBox* listbox, PMObject* obj ) + : QListBoxPixmap( listbox, + SmallIcon( obj->pixmap( ), PMFactory::instance( ) ), + checkName( obj->name( ) ) ) +{ + m_pObject = obj; +} + +PMListBoxObject::PMListBoxObject( PMObject* obj ) + : QListBoxPixmap( SmallIcon( obj->pixmap( ), PMFactory::instance( ) ), + checkName( obj->name( ) ) ) +{ + m_pObject = obj; +} + +PMListBoxObject::PMListBoxObject( QListBox* listbox, PMObject* obj, + const QString& text, QListBoxItem* after ) + : QListBoxPixmap( listbox, + SmallIcon( obj->pixmap( ), PMFactory::instance( ) ), + text, after ) +{ + m_pObject = obj; +} + +PMListBoxObject::PMListBoxObject( QListBox* listbox, PMObject* obj, + const QString& text ) + : QListBoxPixmap( listbox, + SmallIcon( obj->pixmap( ), PMFactory::instance( ) ), + text ) +{ + m_pObject = obj; +} + +PMListBoxObject::PMListBoxObject( PMObject* obj, const QString& text ) + : QListBoxPixmap( SmallIcon( obj->pixmap( ), PMFactory::instance( ) ), + text ) +{ + m_pObject = obj; +} + +QString PMListBoxObject::checkName( const QString& text ) +{ + if( text.isEmpty( ) ) + return i18n( "(unnamed)" ); + return text; +} + +PMListBoxObject::~PMListBoxObject( ) +{ +} + + +QSize PMObjectSelect::s_size = QSize( 200, 300 ); + + +PMObjectSelect::PMObjectSelect( QWidget* parent, const char* name, bool modal ) + : KDialogBase( parent, name, modal, i18n( "Choose Object" ), Ok | Cancel ) +{ + m_pSelectedObject = 0; + m_pListBox = new QListBox( this ); + setMainWidget( m_pListBox ); + setInitialSize( s_size ); + + connect( m_pListBox, SIGNAL( highlighted( QListBoxItem* ) ), + SLOT( slotHighlighted( QListBoxItem* ) ) ); + connect( m_pListBox, SIGNAL( selected( QListBoxItem* ) ), + SLOT( slotSelected( QListBoxItem* ) ) ); + enableButtonOK( false ); +} + +PMObjectSelect::~PMObjectSelect( ) +{ + s_size = size( ); +} + +void PMObjectSelect::addObject( PMObject* obj ) +{ + m_pListBox->insertItem( new PMListBoxObject( obj ) ); +} + +int PMObjectSelect::selectObject( PMObject* link, const QString& t, + PMObject* & obj, QWidget* parent ) +{ + PMObject* last = link; + PMObject* scene; + bool stop = false; + bool found = false; + + do + { + scene = last->parent( ); + if( scene ) + { + if( scene->type( ) == "Scene" ) + { + last = last->prevSibling( ); + stop = true; + found = true; + } + else + last = last->parent( ); + } + else + stop = true; + } + while( !stop ); + + if( found ) + { + PMObjectSelect s( parent ); + + PMObject* o = scene->firstChild( ); + bool l = false; + + while( o && !l && last ) + { + if( o->type( ) == t ) + s.m_pListBox->insertItem( new PMListBoxObject( o ) ); + + if( o == last ) + l = true; + else + o = o->nextSibling( ); + } + + int result = s.exec( ); + if( result == Accepted ) + obj = s.selectedObject( ); + + return result; + } + else + kdError( PMArea ) << "PMObjectSelect: Link does not seem to be correctly inserted in the scene.\n"; + return Rejected; +} + +int PMObjectSelect::selectObject( PMObject* link, + const QStringList& t, + PMObject* & obj, QWidget* parent ) +{ + PMObject* last = link; + PMObject* scene; + bool stop = false; + bool found = false; + + do + { + scene = last->parent( ); + if( scene ) + { + if( scene->type( ) == "Scene" ) + { + last = last->prevSibling( ); + stop = true; + found = true; + } + else + last = last->parent( ); + } + else + stop = true; + } + while( !stop ); + + if( found ) + { + PMObjectSelect s( parent ); + + PMObject* o = scene->firstChild( ); + bool l = false; + + while( o && !l && last ) + { + if( t.findIndex( o->type( ) ) >= 0 ) + s.m_pListBox->insertItem( new PMListBoxObject( o ) ); + + if( o == last ) + l = true; + else + o = o->nextSibling( ); + } + + int result = s.exec( ); + if( result == Accepted ) + obj = s.selectedObject( ); + + return result; + } + else + kdError( PMArea ) << "PMObjectSelect: Link does not seem to be correctly inserted in the scene.\n"; + return Rejected; +} + +int PMObjectSelect::selectDeclare( PMObject* link, const QString& declareType, + PMObject* & obj, QWidget* parent ) +{ + PMObject* last = link; + PMObject* scene; + bool stop = false; + bool found = false; + + do + { + scene = last->parent( ); + if( scene ) + { + if( scene->type( ) == "Scene" ) + { + last = last->prevSibling( ); + stop = true; + found = true; + } + else + last = last->parent( ); + } + else + stop = true; + } + while( !stop ); + + if( found ) + { + PMObjectSelect s( parent ); + + PMObject* o = scene->firstChild( ); + PMDeclare* decl; + + bool l = false; + + while( o && !l && last ) + { + if( o->type( ) == "Declare" ) + { + decl = ( PMDeclare* ) o; + if( decl->declareType( ) == declareType ) + s.m_pListBox->insertItem( new PMListBoxObject( o ) ); + } + + if( o == last ) + l = true; + else + o = o->nextSibling( ); + } + + int result = s.exec( ); + if( result == Accepted ) + obj = s.selectedObject( ); + + return result; + } + else + kdError( PMArea ) << "PMObjectSelect: Link does not seem to be correctly inserted in the scene.\n"; + return Rejected; +} + +int PMObjectSelect::selectDeclare( PMObject* link, const QStringList& declareTypes, + PMObject* & obj, QWidget* parent ) +{ + PMObject* last = link; + PMObject* scene; + bool stop = false; + bool found = false; + + do + { + scene = last->parent( ); + if( scene ) + { + if( scene->type( ) == "Scene" ) + { + last = last->prevSibling( ); + stop = true; + found = true; + } + else + last = last->parent( ); + } + else + stop = true; + } + while( !stop ); + + if( found ) + { + PMObjectSelect s( parent ); + + PMObject* o = scene->firstChild( ); + PMDeclare* decl; + + bool l = false; + + while( o && !l && last ) + { + if( o->type( ) == "Declare" ) + { + decl = ( PMDeclare* ) o; + if( declareTypes.findIndex( decl->declareType( ) ) >= 0 ) + s.m_pListBox->insertItem( new PMListBoxObject( o ) ); + } + + if( o == last ) + l = true; + else + o = o->nextSibling( ); + } + + int result = s.exec( ); + if( result == Accepted ) + obj = s.selectedObject( ); + + return result; + } + else + kdError( PMArea ) << "PMObjectSelect: Link does not seem to be correctly inserted in the scene.\n"; + return Rejected; +} + +void PMObjectSelect::slotHighlighted( QListBoxItem* lbi ) +{ + m_pSelectedObject = ( ( PMListBoxObject* ) lbi )->object( ); + enableButtonOK( true ); +} + +void PMObjectSelect::slotSelected( QListBoxItem* lbi ) +{ + m_pSelectedObject = ( ( PMListBoxObject* ) lbi )->object( ); + enableButtonOK( true ); + accept( ); +} +#include "pmobjectselect.moc" diff --git a/kpovmodeler/pmobjectselect.h b/kpovmodeler/pmobjectselect.h new file mode 100644 index 00000000..c69af315 --- /dev/null +++ b/kpovmodeler/pmobjectselect.h @@ -0,0 +1,132 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMOBJECTSELECT_H +#define PMOBJECTSELECT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include "pmobject.h" +#include "pmdeclare.h" + +/** + * QListBoxItem for @ref PMObject + */ +class PMListBoxObject : public QListBoxPixmap +{ +public: + /** + * Constructs a list box item in listbox listbox showing the + * object obj. The item gets inserted after the item after + */ + PMListBoxObject( QListBox* listbox, PMObject* obj, QListBoxItem* after ); + /** + * Constructs a list box item in listbox listbox showing the object obj + */ + PMListBoxObject( QListBox* listbox, PMObject* obj ); + /** + * Constructs a list box item showing the object obj + */ + PMListBoxObject( PMObject* obj ); + /** + * Constructs a list box item in listbox listbox showing the + * text text. The item gets inserted after the item after + */ + PMListBoxObject( QListBox* listbox, PMObject* obj, const QString& text, + QListBoxItem* after ); + /** + * Constructs a list box item in listbox listbox showing the text text + */ + PMListBoxObject( QListBox* listbox, PMObject* obj, const QString& text ); + /** + * Constructs a list box item showing the text text + */ + PMListBoxObject( PMObject* obj, const QString& text ); + /** + * Deletes the item + */ + ~PMListBoxObject( ); + + /** + * Returns a pointer to the object + */ + PMObject* object( ) const { return m_pObject; } +private: + static QString checkName( const QString& text ); + PMObject* m_pObject; +}; + +/** + * A PMObject selection widget + */ +class PMObjectSelect : public KDialogBase +{ + Q_OBJECT +public: + /** + * Creates a selection widget with parent and name + */ + PMObjectSelect( QWidget* parent = 0, const char* name = 0, + bool modal = true ); + /** + * Deletes the dialog + */ + ~PMObjectSelect( ); + + /** + * Appends the object to the list of choosable objects + */ + void addObject( PMObject* obj ); + + /** + * Returns the currently selected object + */ + PMObject* selectedObject( ) const { return m_pSelectedObject; } + + /** + * Create a modal dialog and let the user choose an declare object + * of type t. + * + * Only objects above the object link are listed. + */ + static int selectObject( PMObject* link, const QString& t, PMObject* & obj, + QWidget* parent = 0 ); + static int selectObject( PMObject* link, const QStringList& t, + PMObject* & obj, QWidget* parent = 0 ); + static int selectDeclare( PMObject* link, const QString& declareType, + PMObject* & obj, QWidget* parent = 0 ); + static int selectDeclare( PMObject* link, const QStringList& dt, + PMObject* & obj, QWidget* parent = 0 ); + +protected slots: + void slotHighlighted( QListBoxItem* lbi ); + void slotSelected( QListBoxItem* lbi ); +private: + QListBox* m_pListBox; + PMObject* m_pSelectedObject; + static QSize s_size; +}; + +#endif diff --git a/kpovmodeler/pmobjectsettings.cpp b/kpovmodeler/pmobjectsettings.cpp new file mode 100644 index 00000000..06aae64e --- /dev/null +++ b/kpovmodeler/pmobjectsettings.cpp @@ -0,0 +1,550 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmobjectsettings.h" + +#include "pmlineedits.h" +#include "pmrendermanager.h" +#include "pmdefaults.h" + +#include "pmsphere.h" +#include "pmcone.h" +#include "pmcylinder.h" +#include "pmtorus.h" +#include "pmplane.h" +#include "pmdisc.h" +#include "pmblobsphere.h" +#include "pmblobcylinder.h" +#include "pmlathe.h" +#include "pmsor.h" +#include "pmprism.h" +#include "pmsqe.h" +#include "pmspheresweep.h" +#include "pmheightfield.h" +#include "pmtext.h" + +#include +#include +#include +#include +#include + + +PMObjectSettings::PMObjectSettings( QWidget* parent, const char* name ) + : PMSettingsDialogPage( parent, name ) +{ + QHBoxLayout* hlayout; + QVBoxLayout* vlayout; + QVBoxLayout* gvl; + QGridLayout* grid; + QGroupBox* gb; + + vlayout = new QVBoxLayout( this, 0, KDialog::spacingHint( ) ); + + gb = new QGroupBox( i18n( "Subdivisions" ), this ); + vlayout->addWidget( gb ); + gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) ); + gvl->addSpacing( 10 ); + grid = new QGridLayout( gvl, 13, 3 ); + + grid->addWidget( new QLabel( i18n( "Sphere:" ), gb ), 0, 0 ); + hlayout = new QHBoxLayout( ); + grid->addLayout( hlayout, 0, 2 ); + grid->addWidget( new QLabel( "u", gb ), 0, 1 ); + m_pSphereUSteps = new PMIntEdit( gb ); + hlayout->addWidget( m_pSphereUSteps ); + m_pSphereUSteps->setValidation( true, 2, true, 32 ); + hlayout->addWidget( new QLabel( "v", gb ) ); + m_pSphereVSteps = new PMIntEdit( gb ); + hlayout->addWidget( m_pSphereVSteps ); + m_pSphereVSteps->setValidation( true, 4, true, 64 ); + hlayout->addStretch( 1 ); + + grid->addWidget( new QLabel( i18n( "Cylinder:" ), gb ), 1, 0 ); + hlayout = new QHBoxLayout( ); + grid->addLayout( hlayout, 1, 2 ); + m_pCylinderSteps = new PMIntEdit( gb ); + hlayout->addWidget( m_pCylinderSteps ); + m_pCylinderSteps->setValidation( true, 4, true, 64 ); + hlayout->addStretch( 1 ); + + grid->addWidget( new QLabel( i18n( "Cone:" ), gb ), 2, 0 ); + hlayout = new QHBoxLayout( ); + grid->addLayout( hlayout, 2, 2 ); + m_pConeSteps = new PMIntEdit( gb ); + hlayout->addWidget( m_pConeSteps ); + m_pConeSteps->setValidation( true, 4, true, 64 ); + hlayout->addStretch( 1 ); + + grid->addWidget( new QLabel( i18n( "Torus:" ), gb ), 3, 0 ); + hlayout = new QHBoxLayout( ); + grid->addLayout( hlayout, 3, 2 ); + grid->addWidget( new QLabel( "u", gb ), 3, 1 ); + m_pTorusUSteps = new PMIntEdit( gb ); + hlayout->addWidget( m_pTorusUSteps ); + m_pTorusUSteps->setValidation( true, 2, true, 16 ); + hlayout->addWidget( new QLabel( "v", gb ) ); + m_pTorusVSteps = new PMIntEdit( gb ); + hlayout->addWidget( m_pTorusVSteps ); + m_pTorusVSteps->setValidation( true, 4, true, 64 ); + hlayout->addStretch( 1 ); + + grid->addWidget( new QLabel( i18n( "Disc:" ), gb ), 4, 0 ); + hlayout = new QHBoxLayout( ); + grid->addLayout( hlayout, 4, 2 ); + m_pDiscSteps = new PMIntEdit( gb ); + hlayout->addWidget( m_pDiscSteps ); + m_pDiscSteps->setValidation( true, 4, true, 64 ); + hlayout->addStretch( 1 ); + + grid->addWidget( new QLabel( i18n( "Blob sphere:" ), gb ), 5, 0 ); + hlayout = new QHBoxLayout( ); + grid->addLayout( hlayout, 5, 2 ); + grid->addWidget( new QLabel( "u", gb ), 5, 1 ); + m_pBlobSphereUSteps = new PMIntEdit( gb ); + hlayout->addWidget( m_pBlobSphereUSteps ); + m_pBlobSphereUSteps->setValidation( true, 2, true, 32 ); + hlayout->addWidget( new QLabel( "v", gb ) ); + m_pBlobSphereVSteps = new PMIntEdit( gb ); + hlayout->addWidget( m_pBlobSphereVSteps ); + m_pBlobSphereVSteps->setValidation( true, 4, true, 64 ); + hlayout->addStretch( 1 ); + + grid->addWidget( new QLabel( i18n( "Blob cylinder:" ), gb ), 6, 0 ); + hlayout = new QHBoxLayout( ); + grid->addLayout( hlayout, 6, 2 ); + grid->addWidget( new QLabel( "u", gb ), 6, 1 ); + m_pBlobCylinderUSteps = new PMIntEdit( gb ); + hlayout->addWidget( m_pBlobCylinderUSteps ); + m_pBlobCylinderUSteps->setValidation( true, 2, true, 32 ); + hlayout->addWidget( new QLabel( "v", gb ) ); + m_pBlobCylinderVSteps = new PMIntEdit( gb ); + hlayout->addWidget( m_pBlobCylinderVSteps ); + m_pBlobCylinderVSteps->setValidation( true, 4, true, 64 ); + hlayout->addStretch( 1 ); + + grid->addWidget( new QLabel( i18n( "Lathe:" ), gb ), 7, 0 ); + hlayout = new QHBoxLayout( ); + grid->addLayout( hlayout, 7, 2 ); + grid->addWidget( new QLabel( "u", gb ), 7, 1 ); + m_pLatheUSteps = new PMIntEdit( gb ); + hlayout->addWidget( m_pLatheUSteps ); + m_pLatheUSteps->setValidation( true, 1, true, 16 ); + hlayout->addWidget( new QLabel( "v", gb ) ); + m_pLatheRSteps = new PMIntEdit( gb ); + hlayout->addWidget( m_pLatheRSteps ); + m_pLatheRSteps->setValidation( true, 4, true, 64 ); + hlayout->addStretch( 1 ); + + grid->addWidget( new QLabel( i18n( "Surface of revolution:" ), gb ), 8, 0 ); + hlayout = new QHBoxLayout( ); + grid->addLayout( hlayout, 8, 2 ); + grid->addWidget( new QLabel( "u", gb ), 8, 1 ); + m_pSorUSteps = new PMIntEdit( gb ); + hlayout->addWidget( m_pSorUSteps ); + m_pSorUSteps->setValidation( true, 1, true, 16 ); + hlayout->addWidget( new QLabel( "v", gb ) ); + m_pSorRSteps = new PMIntEdit( gb ); + hlayout->addWidget( m_pSorRSteps ); + m_pSorRSteps->setValidation( true, 4, true, 64 ); + hlayout->addStretch( 1 ); + + grid->addWidget( new QLabel( i18n( "Prism:" ), gb ), 9, 0 ); + hlayout = new QHBoxLayout( ); + grid->addLayout( hlayout, 9, 2 ); + m_pPrismSteps = new PMIntEdit( gb ); + hlayout->addWidget( m_pPrismSteps ); + m_pPrismSteps->setValidation( true, 1, true, 16 ); + hlayout->addStretch( 1 ); + + grid->addWidget( new QLabel( i18n( "Superquadric ellipsoid:" ), gb ), 10, 0 ); + hlayout = new QHBoxLayout( ); + grid->addLayout( hlayout, 10, 2 ); + grid->addWidget( new QLabel( "u", gb ), 10, 1 ); + m_pSqeUSteps = new PMIntEdit( gb ); + hlayout->addWidget( m_pSqeUSteps ); + m_pSqeUSteps->setValidation( true, 2, true, 8 ); + hlayout->addWidget( new QLabel( "v", gb ) ); + m_pSqeVSteps = new PMIntEdit( gb ); + hlayout->addWidget( m_pSqeVSteps ); + m_pSqeVSteps->setValidation( true, 2, true, 8 ); + hlayout->addStretch( 1 ); + + grid->addWidget( new QLabel( i18n( "Sphere sweep:" ), gb ), 11, 0 ); + hlayout = new QHBoxLayout( ); + grid->addLayout( hlayout, 11, 2 ); + grid->addWidget( new QLabel( "r", gb ), 11, 1 ); + m_pSphereSweepRSteps = new PMIntEdit( gb ); + hlayout->addWidget( m_pSphereSweepRSteps ); + m_pSphereSweepRSteps->setValidation( true, 4, true, 64 ); + hlayout->addWidget( new QLabel( "s", gb ) ); + m_pSphereSweepSSteps = new PMIntEdit( gb ); + hlayout->addWidget( m_pSphereSweepSSteps ); + m_pSphereSweepSSteps->setValidation( true, 1, true, 16 ); + hlayout->addStretch( 1 ); + + grid->addWidget( new QLabel( i18n( "Heightfield:" ), gb ), 12, 0 ); + hlayout = new QHBoxLayout( ); + grid->addLayout( hlayout, 12, 2 ); + m_pHeightFieldVariance = new PMIntEdit( gb ); + hlayout->addWidget( m_pHeightFieldVariance ); + m_pHeightFieldVariance->setValidation( true, 1, true, 16 ); + hlayout->addStretch( 1 ); + + gb = new QGroupBox( i18n( "Sizes" ), this ); + vlayout->addWidget( gb ); + gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) ); + gvl->addSpacing( 10 ); + + grid = new QGridLayout( gvl, 1, 2 ); + + grid->addWidget( new QLabel( i18n( "Plane:" ), gb ), 0, 0 ); + hlayout = new QHBoxLayout( ); + grid->addLayout( hlayout, 0, 1 ); + m_pPlaneSize = new PMFloatEdit( gb ); + hlayout->addWidget( m_pPlaneSize ); + m_pPlaneSize->setValidation( true, 0.1, false, 0.0 ); + hlayout->addStretch( 1 ); + + gb = new QGroupBox( i18n( "Camera Views" ), this ); + vlayout->addWidget( gb ); + gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) ); + gvl->addSpacing( 10 ); + + m_pHighDetailCameraViews = new QCheckBox( i18n( "High detail for enhanced projections" ), gb ); + gvl->addWidget( m_pHighDetailCameraViews ); + + vlayout->addStretch( 1 ); +} + +void PMObjectSettings::displaySettings( ) +{ + m_pSphereUSteps->setValue( PMSphere::uSteps( ) ); + m_pSphereVSteps->setValue( PMSphere::vSteps( ) ); + m_pCylinderSteps->setValue( PMCylinder::steps( ) ); + m_pConeSteps->setValue( PMCone::steps( ) ); + m_pTorusUSteps->setValue( PMTorus::uSteps( ) ); + m_pTorusVSteps->setValue( PMTorus::vSteps( ) ); + m_pDiscSteps->setValue( PMDisc::steps( ) ); + m_pBlobSphereUSteps->setValue( PMBlobSphere::uSteps( ) ); + m_pBlobSphereVSteps->setValue( PMBlobSphere::vSteps( ) ); + m_pBlobCylinderUSteps->setValue( PMBlobCylinder::uSteps( ) ); + m_pBlobCylinderVSteps->setValue( PMBlobCylinder::vSteps( ) ); + m_pPlaneSize->setValue( PMPlane::planeSize( ) ); + m_pLatheUSteps->setValue( PMLathe::sSteps( ) ); + m_pLatheRSteps->setValue( PMLathe::rSteps( ) ); + m_pSorUSteps->setValue( PMSurfaceOfRevolution::sSteps( ) ); + m_pSorRSteps->setValue( PMSurfaceOfRevolution::rSteps( ) ); + m_pPrismSteps->setValue( PMPrism::sSteps( ) ); + m_pSqeUSteps->setValue( PMSuperquadricEllipsoid::uSteps( ) ); + m_pSqeVSteps->setValue( PMSuperquadricEllipsoid::vSteps( ) ); + m_pSphereSweepRSteps->setValue( PMSphereSweep::rSteps( ) ); + m_pSphereSweepSSteps->setValue( PMSphereSweep::sSteps( ) ); + m_pHeightFieldVariance->setValue( PMHeightField::variance( ) ); + PMRenderManager* rm = PMRenderManager::theManager( ); + m_pHighDetailCameraViews->setChecked( rm->highDetailCameraViews( ) ); +} + +void PMObjectSettings::displayDefaults( ) +{ + m_pSphereUSteps->setValue( c_defaultSphereUSteps ); + m_pSphereVSteps->setValue( c_defaultSphereVSteps ); + m_pCylinderSteps->setValue( c_defaultCylinderSteps ); + m_pConeSteps->setValue( c_defaultConeSteps ); + m_pTorusUSteps->setValue( c_defaultTorusUSteps ); + m_pTorusVSteps->setValue( c_defaultTorusVSteps ); + m_pDiscSteps->setValue( c_defaultDiscSteps ); + m_pBlobSphereUSteps->setValue( c_defaultBlobSphereUSteps ); + m_pBlobSphereVSteps->setValue( c_defaultBlobSphereVSteps ); + m_pBlobCylinderUSteps->setValue( c_defaultBlobCylinderUSteps ); + m_pBlobCylinderVSteps->setValue( c_defaultBlobCylinderVSteps ); + m_pLatheUSteps->setValue( c_defaultLatheSSteps ); + m_pLatheRSteps->setValue( c_defaultLatheRSteps ); + m_pSorUSteps->setValue( c_defaultSurfaceOfRevolutionSSteps ); + m_pSorRSteps->setValue( c_defaultSurfaceOfRevolutionRSteps ); + m_pPrismSteps->setValue( c_defaultPrismSSteps ); + m_pSqeUSteps->setValue( c_defaultSuperquadricEllipsoidUSteps ); + m_pSqeVSteps->setValue( c_defaultSuperquadricEllipsoidVSteps ); + m_pSphereSweepRSteps->setValue( c_defaultSphereSweepRSteps ); + m_pSphereSweepSSteps->setValue( c_defaultSphereSweepSSteps ); + m_pHeightFieldVariance->setValue( c_defaultHeightFieldVariance ); + m_pPlaneSize->setValue( c_defaultPlaneSize ); + m_pHighDetailCameraViews->setChecked( c_defaultHighDetailCameraView ); +} + +bool PMObjectSettings::validateData( ) +{ + if( !m_pSphereUSteps->isDataValid( ) ) + { + emit showMe( ); + m_pSphereUSteps->setFocus( ); + return false; + } + if( !m_pSphereVSteps->isDataValid( ) ) + { + emit showMe( ); + m_pSphereVSteps->setFocus( ); + return false; + } + if( !m_pCylinderSteps->isDataValid( ) ) + { + emit showMe( ); + m_pCylinderSteps->setFocus( ); + return false; + } + if( !m_pConeSteps->isDataValid( ) ) + { + emit showMe( ); + m_pConeSteps->setFocus( ); + return false; + } + if( !m_pTorusUSteps->isDataValid( ) ) + { + emit showMe( ); + m_pTorusUSteps->setFocus( ); + return false; + } + if( !m_pTorusVSteps->isDataValid( ) ) + { + emit showMe( ); + m_pTorusVSteps->setFocus( ); + return false; + } + if( !m_pDiscSteps->isDataValid( ) ) + { + emit showMe( ); + m_pDiscSteps->setFocus( ); + return false; + } + if( !m_pBlobSphereUSteps->isDataValid( ) ) + { + emit showMe( ); + m_pBlobSphereUSteps->setFocus( ); + return false; + } + if( !m_pBlobSphereVSteps->isDataValid( ) ) + { + emit showMe( ); + m_pBlobSphereVSteps->setFocus( ); + return false; + } + if( !m_pBlobCylinderUSteps->isDataValid( ) ) + { + emit showMe( ); + m_pBlobCylinderUSteps->setFocus( ); + return false; + } + if( !m_pBlobCylinderVSteps->isDataValid( ) ) + { + emit showMe( ); + m_pBlobCylinderVSteps->setFocus( ); + return false; + } + if( !m_pLatheUSteps->isDataValid( ) ) + { + emit showMe( ); + m_pLatheUSteps->setFocus( ); + return false; + } + if( !m_pLatheRSteps->isDataValid( ) ) + { + emit showMe( ); + m_pLatheRSteps->setFocus( ); + return false; + } + if( !m_pSorUSteps->isDataValid( ) ) + { + emit showMe( ); + m_pSorUSteps->setFocus( ); + return false; + } + if( !m_pSorRSteps->isDataValid( ) ) + { + emit showMe( ); + m_pSorRSteps->setFocus( ); + return false; + } + if( !m_pPrismSteps->isDataValid( ) ) + { + emit showMe( ); + m_pPrismSteps->setFocus( ); + return false; + } + if( !m_pSqeUSteps->isDataValid( ) ) + { + emit showMe( ); + m_pSqeUSteps->setFocus( ); + return false; + } + if( !m_pSqeVSteps->isDataValid( ) ) + { + emit showMe( ); + m_pSqeVSteps->setFocus( ); + return false; + } + if( !m_pSphereSweepRSteps->isDataValid( ) ) + { + emit showMe( ); + m_pSphereSweepRSteps->setFocus( ); + return false; + } + if( !m_pSphereSweepSSteps->isDataValid( ) ) + { + emit showMe( ); + m_pSphereSweepSSteps->setFocus( ); + return false; + } + if( !m_pHeightFieldVariance->isDataValid( ) ) + { + emit showMe( ); + m_pHeightFieldVariance->setFocus( ); + return false; + } + if( !m_pPlaneSize->isDataValid( ) ) + { + emit showMe( ); + m_pPlaneSize->setFocus( ); + return false; + } + return true; +} + +void PMObjectSettings::applySettings( ) +{ + bool repaint = false; + + PMRenderManager* rm = PMRenderManager::theManager( ); + if( rm->highDetailCameraViews( ) != m_pHighDetailCameraViews->isChecked( ) ) + { + rm->setHighDetailCameraViews( m_pHighDetailCameraViews->isChecked( ) ); + repaint = true; + } + if( PMSphere::uSteps( ) != m_pSphereUSteps->value( ) ) + { + PMSphere::setUSteps( m_pSphereUSteps->value( ) ); + repaint = true; + } + if( PMSphere::vSteps( ) != m_pSphereVSteps->value( ) ) + { + PMSphere::setVSteps( m_pSphereVSteps->value( ) ); + repaint = true; + } + if( PMCylinder::steps( ) != m_pCylinderSteps->value( ) ) + { + PMCylinder::setSteps( m_pCylinderSteps->value( ) ); + repaint = true; + } + if( PMCone::steps( ) != m_pConeSteps->value( ) ) + { + PMCone::setSteps( m_pConeSteps->value( ) ); + repaint = true; + } + if( PMTorus::uSteps( ) != m_pTorusUSteps->value( ) ) + { + PMTorus::setUSteps( m_pTorusUSteps->value( ) ); + repaint = true; + } + if( PMTorus::vSteps( ) != m_pTorusVSteps->value( ) ) + { + PMTorus::setVSteps( m_pTorusVSteps->value( ) ); + repaint = true; + } + if( PMDisc::steps( ) != m_pDiscSteps->value( ) ) + { + PMDisc::setSteps( m_pDiscSteps->value( ) ); + repaint = true; + } + if( PMBlobSphere::uSteps( ) != m_pBlobSphereUSteps->value( ) ) + { + PMBlobSphere::setUSteps( m_pBlobSphereUSteps->value( ) ); + repaint = true; + } + if( PMBlobSphere::vSteps( ) != m_pBlobSphereVSteps->value( ) ) + { + PMBlobSphere::setVSteps( m_pBlobSphereVSteps->value( ) ); + repaint = true; + } + if( PMBlobCylinder::uSteps( ) != m_pBlobCylinderUSteps->value( ) ) + { + PMBlobCylinder::setUSteps( m_pBlobCylinderUSteps->value( ) ); + repaint = true; + } + if( PMBlobCylinder::vSteps( ) != m_pBlobCylinderVSteps->value( ) ) + { + PMBlobCylinder::setVSteps( m_pBlobCylinderVSteps->value( ) ); + repaint = true; + } + if( PMPlane::planeSize( ) != m_pPlaneSize->value( ) ) + { + PMPlane::setPlaneSize( m_pPlaneSize->value( ) ); + repaint = true; + } + if( PMLathe::sSteps( ) != m_pLatheUSteps->value( ) ) + { + PMLathe::setSSteps( m_pLatheUSteps->value( ) ); + repaint = true; + } + if( PMLathe::rSteps( ) != m_pLatheRSteps->value( ) ) + { + PMLathe::setRSteps( m_pLatheRSteps->value( ) ); + repaint = true; + } + if( PMSurfaceOfRevolution::sSteps( ) != m_pSorUSteps->value( ) ) + { + PMSurfaceOfRevolution::setSSteps( m_pSorUSteps->value( ) ); + repaint = true; + } + if( PMSurfaceOfRevolution::rSteps( ) != m_pSorRSteps->value( ) ) + { + PMSurfaceOfRevolution::setRSteps( m_pSorRSteps->value( ) ); + repaint = true; + } + if( PMPrism::sSteps( ) != m_pPrismSteps->value( ) ) + { + PMPrism::setSSteps( m_pPrismSteps->value( ) ); + repaint = true; + } + if( PMSuperquadricEllipsoid::uSteps( ) != m_pSqeUSteps->value( ) ) + { + PMSuperquadricEllipsoid::setUSteps( m_pSqeUSteps->value( ) ); + repaint = true; + } + if( PMSuperquadricEllipsoid::vSteps( ) != m_pSqeVSteps->value( ) ) + { + PMSuperquadricEllipsoid::setVSteps( m_pSqeVSteps->value( ) ); + repaint = true; + } + if( PMSphereSweep::rSteps( ) != m_pSphereSweepRSteps->value( ) ) + { + PMSphereSweep::setRSteps( m_pSphereSweepRSteps->value( ) ); + repaint = true; + } + if( PMSphereSweep::sSteps( ) != m_pSphereSweepSSteps->value( ) ) + { + PMSphereSweep::setSSteps( m_pSphereSweepSSteps->value( ) ); + repaint = true; + } + if( PMHeightField::variance( ) != m_pHeightFieldVariance->value( ) ) + { + PMHeightField::setVariance( m_pHeightFieldVariance->value( ) ); + repaint = true; + } + if( repaint ) + emit repaintViews( ); +} + +#include "pmobjectsettings.moc" diff --git a/kpovmodeler/pmobjectsettings.h b/kpovmodeler/pmobjectsettings.h new file mode 100644 index 00000000..716631c0 --- /dev/null +++ b/kpovmodeler/pmobjectsettings.h @@ -0,0 +1,78 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMOBJECTSETTINGS_H +#define PMOBJECTSETTINGS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsettingsdialog.h" + +class PMIntEdit; +class PMFloatEdit; +class QCheckBox; + +/** + * Object details configuration dialog page + */ +class PMObjectSettings : public PMSettingsDialogPage +{ + Q_OBJECT +public: + /** + * Default constructor + */ + PMObjectSettings( QWidget* parent, const char* name = 0 ); + /** */ + virtual void displaySettings( ); + /** */ + virtual bool validateData( ); + /** */ + virtual void applySettings( ); + /** */ + virtual void displayDefaults( ); + +private: + PMIntEdit* m_pSphereUSteps; + PMIntEdit* m_pSphereVSteps; + PMIntEdit* m_pCylinderSteps; + PMIntEdit* m_pConeSteps; + PMIntEdit* m_pTorusUSteps; + PMIntEdit* m_pTorusVSteps; + PMFloatEdit* m_pPlaneSize; + PMIntEdit* m_pDiscSteps; + PMIntEdit* m_pBlobSphereUSteps; + PMIntEdit* m_pBlobSphereVSteps; + PMIntEdit* m_pBlobCylinderUSteps; + PMIntEdit* m_pBlobCylinderVSteps; + PMIntEdit* m_pLatheUSteps; + PMIntEdit* m_pLatheRSteps; + PMIntEdit* m_pSorUSteps; + PMIntEdit* m_pSorRSteps; + PMIntEdit* m_pPrismSteps; + PMIntEdit* m_pSqeUSteps; + PMIntEdit* m_pSqeVSteps; + PMIntEdit* m_pSphereSweepRSteps; + PMIntEdit* m_pSphereSweepSSteps; + PMIntEdit* m_pHeightFieldVariance; + QCheckBox* m_pHighDetailCameraViews; +}; + + +#endif diff --git a/kpovmodeler/pmopenglsettings.cpp b/kpovmodeler/pmopenglsettings.cpp new file mode 100644 index 00000000..64f3ac9c --- /dev/null +++ b/kpovmodeler/pmopenglsettings.cpp @@ -0,0 +1,59 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmopenglsettings.h" + +#include "pmglview.h" +#include "pmdefaults.h" + +#include +#include +#include +#include + +PMOpenGLSettings::PMOpenGLSettings( QWidget* parent, const char* name ) + : PMSettingsDialogPage( parent, name ) +{ + QVBoxLayout* vlayout = new QVBoxLayout( this, 0, KDialog::spacingHint( ) ); + + m_pDirect = new QCheckBox( i18n( "Direct rendering" ), this ); + vlayout->addWidget( new QLabel( i18n( "Changes take only effect after a restart!" ), this ) ); + vlayout->addWidget( m_pDirect ); + vlayout->addStretch( 1 ); +} + +void PMOpenGLSettings::displaySettings( ) +{ + m_pDirect->setChecked( PMGLView::isDirectRenderingEnabled( ) ); +} + +void PMOpenGLSettings::displayDefaults( ) +{ + m_pDirect->setChecked( true ); +} + +bool PMOpenGLSettings::validateData( ) +{ + return true; +} + +void PMOpenGLSettings::applySettings( ) +{ + PMGLView::enableDirectRendering( m_pDirect->isChecked( ) ); +} + +#include "pmopenglsettings.moc" diff --git a/kpovmodeler/pmopenglsettings.h b/kpovmodeler/pmopenglsettings.h new file mode 100644 index 00000000..d893a6b0 --- /dev/null +++ b/kpovmodeler/pmopenglsettings.h @@ -0,0 +1,54 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMOPENGLSETTINGS_H +#define PMOPENGLSETTINGS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsettingsdialog.h" + +class QCheckBox; + +/** + * OpenGL configuration dialog page + */ +class PMOpenGLSettings : public PMSettingsDialogPage +{ + Q_OBJECT +public: + /** + * Default constructor + */ + PMOpenGLSettings( QWidget* parent, const char* name = 0 ); + /** */ + virtual void displaySettings( ); + /** */ + virtual bool validateData( ); + /** */ + virtual void applySettings( ); + /** */ + virtual void displayDefaults( ); + +private: + QCheckBox* m_pDirect; +}; + + +#endif diff --git a/kpovmodeler/pmoutputdevice.cpp b/kpovmodeler/pmoutputdevice.cpp new file mode 100644 index 00000000..5feb8ec2 --- /dev/null +++ b/kpovmodeler/pmoutputdevice.cpp @@ -0,0 +1,203 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmoutputdevice.h" +#include "pmpovrayformat.h" +#include +#include + +unsigned int PMOutputDevice::s_indentOffset = 3; +bool PMOutputDevice::s_bracketBehindType = true; + +PMOutputDevice::PMOutputDevice( QIODevice* dev, PMPovrayFormat* format ) + : PMSerializer( dev ), m_stream( dev ) +{ + m_pFormat = format; + m_indentation = 0; + m_lastWasComment = false; + m_pendingNewLine = false; + m_objectSeparation = false; +} + +PMOutputDevice::~PMOutputDevice( ) +{ +} + +QString PMOutputDevice::description( ) const +{ + return QString( "POV-Ray" ); +} + +void PMOutputDevice::callSerialization( const PMObject* o, const PMMetaObject* mo ) +{ + if( !mo ) + return; + + const PMPovraySerializeMethodInfo* info = + m_pFormat->serializationMethod( mo->className( ) ); + + if( info ) + info->call( o, mo, this ); + else + { + if( mo == o->metaObject( ) ) + { + printError( i18n( "The object \"%1\" doesn't support %2." ) + .arg( o->description( ) ).arg( description( ) ) ); + } + else + { + printError( i18n( "The class \"%1\" doesn't support %2." ) + .arg( o->description( ) ).arg( mo->className( ) ) ); + } + } +} + +void PMOutputDevice::serialize( PMObject* o ) +{ + callSerialization( o, o->metaObject( ) ); +} + +void PMOutputDevice::close( ) +{ +// m_stream << ( char ) 0; +} + +void PMOutputDevice::objectBegin( const QString& type ) +{ + if( m_pendingNewLine ) + newLine( ); + if( m_objectSeparation ) + newLine( ); + m_stream << type; + if( s_bracketBehindType ) + m_stream << " "; + else + newLine( ); + + m_stream << "{"; + m_indentation++; + m_indentString.fill( ' ', s_indentOffset * m_indentation ); + m_pendingNewLine = true; + m_objectSeparation = false; +} + +void PMOutputDevice::declareBegin( const QString& id ) +{ + if( m_pendingNewLine ) + newLine( ); + if( m_objectSeparation ) + newLine( ); + m_stream << "#declare " << id << " = "; + + m_objectSeparation = false; +} + +void PMOutputDevice::objectEnd( ) +{ + m_indentation--; + m_indentString.fill( ' ', s_indentOffset * m_indentation ); + newLine( ); + m_stream << "}"; + m_pendingNewLine = true; + m_objectSeparation = true; +} + +void PMOutputDevice::writeLine( const QString& str ) +{ + if( m_pendingNewLine ) + newLine( ); + m_stream << str; + m_pendingNewLine = true; + m_objectSeparation = true; +} + +void PMOutputDevice::write( const QString& str ) +{ + if( m_pendingNewLine ) + newLine( ); + m_stream << str; + m_objectSeparation = false; +} + +void PMOutputDevice::newLine( ) +{ + m_lastWasComment = false; + m_pendingNewLine = false; + m_stream << '\n' << m_indentString; +} + +void PMOutputDevice::writeComment( const QString& text ) +{ + QString s( text ); + QTextStream str( &s, IO_ReadOnly ); + + bool lwc = m_lastWasComment; + if( m_pendingNewLine ) + newLine( ); + if( lwc ) + newLine( ); + if( m_objectSeparation ) + newLine( ); + if( str.atEnd( ) ) + writeLine( "//" ); + else + while( !str.atEnd( ) ) + writeLine( QString( "// " ) + str.readLine( ) ); + m_lastWasComment = true; + m_objectSeparation = false; +} + +void PMOutputDevice::writeSemicolon( ) +{ + // does not change m_pendingNewLine! + m_stream << ';'; +} + +void PMOutputDevice::writeName( const QString& name ) +{ + if( !name.isEmpty( ) ) + writeLine( QString( "//*PMName " ) + name ); +} + +QString PMOutputDevice::escapeAndQuoteString( const QString& s ) +{ + QString result = "\""; + QString tmp = s; + QTextStream stream( &tmp, IO_ReadOnly ); + QChar current, last; + + while( !stream.atEnd( ) ) + { + stream >> current ; + // not escaped quotation mark + if( ( current == '"' ) && ( last != '\\' ) ) + result += '\\'; + result += current; + // correctly quoted backslash + if( ( last == '\\' ) && ( current == '\\' ) ) + current = QChar( 0 ); // clear the last char + last = current; + } + // backslash at the end + if( last == '\\' ) + result += '\\'; + result += '"'; + + return result; +} diff --git a/kpovmodeler/pmoutputdevice.h b/kpovmodeler/pmoutputdevice.h new file mode 100644 index 00000000..25b3c58b --- /dev/null +++ b/kpovmodeler/pmoutputdevice.h @@ -0,0 +1,159 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMOUTPUTDEVICE_H +#define PMOUTPUTDEVICE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmserializer.h" + +#include + +class QTextStream; +class PMPovrayFormat; + +/** + * Output class for povray code. + * + * The class @ref PMPovrayFormat or a base class has factory methods + * to create an instance of this class. The output device uses the + * registered serialization methods of this povray format to serialize + * objects. + * + * This class handles the indentation and position of brackets + */ + +class PMOutputDevice : public PMSerializer +{ +public: + /** + * Creates an PMOutputDevice that serializes the povray code + * to the device + */ + PMOutputDevice( QIODevice* dev, PMPovrayFormat* format ); + /** */ + virtual ~PMOutputDevice( ); + + /** */ + virtual QString description( ) const; + /** */ + virtual void serialize( PMObject* o ); + /** */ + virtual void close( ); + + /** + * Writes the povray object type, an open bracket to the text stream + * and indents the next lines + */ + void objectBegin( const QString& type ); + /** + * Begins a declare with the identifier id + */ + void declareBegin( const QString& id ); + /** + * Writes an closing bracket to the text stream + * and decreases the indentation + */ + void objectEnd( ); + /** + * Writes a single line to the text stream. Don't include + * newlines in the string or indentation will not work properly. + * + * Adds a newline before the string. + */ + void writeLine( const QString& str ); + /** + * Writes the string to the text stream + */ + void write( const QString& str ); + /** + * Writes a new line to the text stream and indents the next line. + */ + void newLine( ); + /** + * Writes a comment string to the text stream + */ + void writeComment( const QString& text ); + /** + * Writes a semicolon after a call to objectEnd( ) + */ + void writeSemicolon( ); + /** + * Writes a special name comment to the text stream, if the + * name is not empty + */ + void writeName( const QString& name ); + + /** + * Returns the basic indentation offset + */ + static unsigned int indentationOffset( ) { return s_indentOffset; } + /** + * Sets the basic indentation offset + */ + static void setIndentationOffset( unsigned int offset ) + { s_indentOffset = offset; } + + /** + * If set to true, the open bracket after an object begin will be + * written behind the object type, otherwise in a new line. + */ + static void setBracketBehindType( bool yes ) { s_bracketBehindType = yes; } + /** + * Returns true if the open bracket after an object begin will be + * written behind the object type + */ + static bool bracketBehindType( ) { return s_bracketBehindType; } + + /** + * Correctly escapes the string and puts quotation marks at the begin + * and end of the string. + * + * Escapes only not escaped characters. "\"" and "\\" in the string + * are not escaped. + */ + static QString escapeAndQuoteString( const QString& s ); + + /** + * Calls the serialization method for the object o and class + * given by the meta object. + * + * If no method for this class was registered in the corresponding + * @ref PMPovrayFormat, an error is added the message list. + */ + void callSerialization( const PMObject* o, const PMMetaObject* mo ); + +private: + static unsigned int s_indentOffset; + static bool s_bracketBehindType; + + PMPovrayFormat* m_pFormat; + unsigned int m_indentation; + QString m_indentString; + QTextStream m_stream; + bool m_lastWasComment; + bool m_pendingNewLine; + bool m_objectSeparation; +}; + + +#endif diff --git a/kpovmodeler/pmpalettevalue.cpp b/kpovmodeler/pmpalettevalue.cpp new file mode 100644 index 00000000..f2b26fff --- /dev/null +++ b/kpovmodeler/pmpalettevalue.cpp @@ -0,0 +1,81 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmpalettevalue.h" + +PMPaletteValue::PMPaletteValue( ) +{ + m_index = 0; + m_value = 0.0; +} + +PMPaletteValue::PMPaletteValue( int idx, double value ) +{ + m_index = idx; + m_value = value; +} + +void PMPaletteValue::setIndex( int idx ) +{ + m_index = idx; +} + +void PMPaletteValue::setValue( double value ) +{ + m_value = value; +} + +void PMPaletteValue::serialize( QDomElement& e, QDomDocument& /* doc */ ) const +{ + e.setAttribute( "index", m_index ); + e.setAttribute( "value", m_value ); +} + +void PMPaletteValue::readAttributes( const QDomElement& h ) +{ + QString str; + bool ok; + + str = h.attribute( "index" ); + if( str.isNull( ) ) + m_index = 0; + else + { + m_index = str.toInt( &ok ); + if( !ok ) m_index = 0; + } + + str = h.attribute( "value" ); + if( str.isNull( ) ) + m_value = 0; + else + { + m_value = str.toDouble( &ok ); + if( !ok ) m_value = 0; + } +} + +bool PMPaletteValue::operator==( const PMPaletteValue& p ) const +{ + return ( m_index == p.m_index && m_value == p.m_value ); +} + +bool PMPaletteValue::operator!=( const PMPaletteValue& p ) const +{ + return ( m_index != p.m_index || m_value != p.m_value ); +} diff --git a/kpovmodeler/pmpalettevalue.h b/kpovmodeler/pmpalettevalue.h new file mode 100644 index 00000000..05f9712a --- /dev/null +++ b/kpovmodeler/pmpalettevalue.h @@ -0,0 +1,78 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMPALETTEVALUE_H +#define PMPALETTEVALUE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmnamedobject.h" + +/** + * Class for pallete values used for filter and transmit in image maps. + */ +class PMPaletteValue +{ +public: + /** */ + PMPaletteValue(); + /** */ + PMPaletteValue( int idx, double value ); + /** + * Returns the index of the palette entry. + */ + int index( ) const { return m_index; } + /** + * Returns the value of the palette entry. + */ + double value( ) const { return m_value; } + /** + * Sets the index of the palette entry. + */ + void setIndex( int idx ); + /** + * Sets the value of the palette entry. + */ + void setValue( double val ); + /** + * Serializes the palette entry into a XML document. + */ + void serialize( QDomElement& e, QDomDocument& doc ) const; + /** + * Reads the palette entry from a XML document. + */ + void readAttributes( const QDomElement& h ); + + /** + * Returns true if both values have the same index and value + */ + bool operator== ( const PMPaletteValue& p) const; + /** + * Returns false if both values have the same index and value + */ + bool operator!= ( const PMPaletteValue& p) const; + +private: + int m_index; + double m_value; +}; + +#endif diff --git a/kpovmodeler/pmpalettevalueedit.cpp b/kpovmodeler/pmpalettevalueedit.cpp new file mode 100644 index 00000000..ae6ea653 --- /dev/null +++ b/kpovmodeler/pmpalettevalueedit.cpp @@ -0,0 +1,99 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Passos Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmpalettevalueedit.h" +#include "pmpalettevalue.h" +#include "pmlineedits.h" +#include "pmdebug.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +PMPaletteValueEdit::PMPaletteValueEdit( QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + QLabel* lbl; + QHBoxLayout* layout; + + m_pIndexEdit = new PMIntEdit( this ); + m_pValueEdit = new PMFloatEdit( this ); + + layout = new QHBoxLayout( this ); + lbl = new QLabel( i18n( "Index" ), this ); + layout->addWidget( lbl ); + layout->addSpacing( KDialog::spacingHint( ) ); + layout->addWidget( m_pIndexEdit ); + layout->addSpacing( KDialog::spacingHint( ) ); + lbl = new QLabel( i18n( "Value" ), this ); + layout->addWidget( lbl ); + layout->addSpacing( KDialog::spacingHint( ) ); + layout->addWidget( m_pValueEdit ); + + connect( m_pIndexEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pValueEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMPaletteValueEdit::setIndex( int idx ) +{ + m_pIndexEdit->setValue( idx ); +} + +void PMPaletteValueEdit::setValue( double val ) +{ + m_pValueEdit->setValue( val ); +} + +int PMPaletteValueEdit::index( ) +{ + return m_pIndexEdit->value( ); +} + +double PMPaletteValueEdit::value( ) +{ + return m_pValueEdit->value( ); +} + +void PMPaletteValueEdit::setReadOnly( bool yes ) +{ + m_pIndexEdit->setReadOnly( yes ); + m_pValueEdit->setReadOnly( yes ); +} + +void PMPaletteValueEdit::setEnabled( bool yes ) +{ + m_pIndexEdit->setEnabled( yes ); + m_pValueEdit->setEnabled( yes ); +} + +bool PMPaletteValueEdit::isDataValid( ) +{ + return ( m_pIndexEdit->isDataValid( ) && m_pValueEdit->isDataValid( ) ); +} + +#include "pmpalettevalueedit.moc" diff --git a/kpovmodeler/pmpalettevalueedit.h b/kpovmodeler/pmpalettevalueedit.h new file mode 100644 index 00000000..c5795cd9 --- /dev/null +++ b/kpovmodeler/pmpalettevalueedit.h @@ -0,0 +1,67 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Passos Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMPALETTEVALUEEDIT_H +#define PMPALETTEVALUEEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMFloatEdit; +class PMIntEdit; + +/** + * Dialog edit class for @ref PMPaletteValue. + */ +class PMPaletteValueEdit: public QWidget +{ + Q_OBJECT +public: + /** */ + PMPaletteValueEdit( QWidget* parent, const char* name = 0 ); + /** */ + void setIndex( int idx ); + /** */ + int index( ); + /** */ + void setValue( double val ); + /** */ + double value( ); + /** + * Returns true is both fields are valid numbers + */ + bool isDataValid( ); + /** */ + void setReadOnly( bool yes = true ); + /** */ + virtual void setEnabled( bool yes ); + +signals: + /** */ + void dataChanged( ); + +private: + PMIntEdit* m_pIndexEdit; + PMFloatEdit* m_pValueEdit; +}; + +#endif diff --git a/kpovmodeler/pmpalettevaluememento.cpp b/kpovmodeler/pmpalettevaluememento.cpp new file mode 100644 index 00000000..6db9b922 --- /dev/null +++ b/kpovmodeler/pmpalettevaluememento.cpp @@ -0,0 +1,84 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Passos Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#include "pmpalettevaluememento.h" +#include "pmdebug.h" + +PMPaletteValueMemento::PMPaletteValueMemento( PMObject* originator ) + : PMMemento( originator ) +{ + m_bFilterPaletteValuesSaved = false; + m_bTransmitPaletteValuesSaved = false; +} + +PMPaletteValueMemento::~PMPaletteValueMemento( ) +{ +} + +void PMPaletteValueMemento::setFilterPaletteValues( const QValueList& v ) +{ + if( !m_bFilterPaletteValuesSaved ) + { + // Direct assignment does not work with Qt 2.3.x + // The list will be changed later in a graphical + // change because QValueList::detach( ) is called + // too late! + // Copy the list by hand. + + QValueList::ConstIterator it = v.begin( ); + for( ; it != v.end( ); ++it ) + m_filterPaletteValues.append( *it ); + + m_bFilterPaletteValuesSaved = true; + addChange( PMCData ); + } +} + +QValueList PMPaletteValueMemento::filterPaletteValues( ) const +{ + if( !m_bFilterPaletteValuesSaved ) + kdError( PMArea ) << "Filter palette values not saved in PMPaletteValueMemento::filterPaletteValues\n"; + + return m_filterPaletteValues; +} + +void PMPaletteValueMemento::setTransmitPaletteValues( const QValueList& v ) +{ + if( !m_bTransmitPaletteValuesSaved ) + { + // Direct assignment does not work with Qt 2.3.x + // The list will be changed later in a graphical + // change because QValueList::detach( ) is called + // too late! + // Copy the list by hand. + + QValueList::ConstIterator it = v.begin( ); + for( ; it != v.end( ); ++it ) + m_transmitPaletteValues.append( *it ); + + m_bTransmitPaletteValuesSaved = true; + addChange( PMCData ); + } +} + +QValueList PMPaletteValueMemento::transmitPaletteValues( ) const +{ + if( !m_bTransmitPaletteValuesSaved ) + kdError( PMArea ) << "Transmit palette values not saved in PMPaletteValueMemento::transmitPaletteValues\n"; + + return m_transmitPaletteValues; +} diff --git a/kpovmodeler/pmpalettevaluememento.h b/kpovmodeler/pmpalettevaluememento.h new file mode 100644 index 00000000..0ac1242e --- /dev/null +++ b/kpovmodeler/pmpalettevaluememento.h @@ -0,0 +1,85 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Passos Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMPALETTEVALUEMEMENTO_H +#define PMPALETTEVALUEMEMENTO_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmmemento.h" +#include "pmpalettevalue.h" +#include + + +/** + * Memento for @ref PMImageMap + */ +class PMPaletteValueMemento : public PMMemento +{ +public: + /** + * Creates a memento for the object originator + */ + PMPaletteValueMemento( PMObject* originator ); + /** + * Deletes the memento + */ + virtual ~PMPaletteValueMemento( ); + + /** + * Saves the filter palette values + */ + void setFilterPaletteValues( const QValueList& v ); + /** + * Returns the filter palette values + */ + QValueList filterPaletteValues( ) const; + /** + * Returns true if the filter palette values were saved + */ + bool filterPaletteValuesSaved( ) const { return m_bFilterPaletteValuesSaved; } + /** + * Saves the transmit palette values + */ + void setTransmitPaletteValues( const QValueList& v ); + /** + * Returns the transmit palette values + */ + QValueList transmitPaletteValues( ) const; + /** + * Returns true if the transmit palette values were saved + */ + bool transmitPaletteValuesSaved( ) const { return m_bTransmitPaletteValuesSaved; } + +private: + /** + * The stored values for filter + */ + QValueList m_filterPaletteValues; + bool m_bFilterPaletteValuesSaved; + /** + * The stored values for transmit + */ + QValueList m_transmitPaletteValues; + bool m_bTransmitPaletteValuesSaved; +}; + +#endif diff --git a/kpovmodeler/pmparser.cpp b/kpovmodeler/pmparser.cpp new file mode 100644 index 00000000..7a252c88 --- /dev/null +++ b/kpovmodeler/pmparser.cpp @@ -0,0 +1,433 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmparser.h" + +#include +#include +#include + +#include "pmpart.h" +#include "pmdeclare.h" +#include "pmerrorflags.h" +#include "pmrecursiveobjectiterator.h" +#include "pmdebug.h" + +unsigned int PMParser::s_maxErrors = 30; +unsigned int PMParser::s_maxWarnings = 50; + + +PMParser::PMParser( PMPart* part, QIODevice* dev ) + : m_okDeclares( 101 ) +{ + m_pPart = part; + m_pDevice = dev; + m_bDeviceCreated = false; + + init( ); +} + +PMParser::PMParser( PMPart* part, const QByteArray& array ) + : m_okDeclares( 101 ) +{ + m_pPart = part; + QBuffer* buffer = new QBuffer( array ); + buffer->open( IO_ReadOnly ); + m_pDevice = buffer; + m_bDeviceCreated = true; + + init( ); +} + +void PMParser::init( ) +{ + m_okDeclares.setAutoDelete( true ); + m_pLocalST.setAutoDelete( true ); + + m_lineNum = -1; + m_pResultList = 0; + m_errors = 0; + m_warnings = 0; + m_bFatalError = false; + m_shownMessages = 0; + m_messages.clear( ); + + m_pTopParent = 0; + m_renamedObjectSymbols.clear( ); + m_okDeclares.clear( ); + m_pNextCheckDeclare = 0; +} + +PMParser::~PMParser( ) +{ + if( m_bDeviceCreated ) + delete m_pDevice; +} + +void PMParser::printMessage( const PMPMessage messageNum ) +{ + if( !( m_shownMessages & messageNum ) ) + { + m_shownMessages |= messageNum; + + switch( messageNum ) + { + case PMMClockDefault: + printWarning( i18n( "Using the default value of 0.0 for clock" ) ); + break; + case PMMClockDeltaDefault: + printWarning( i18n( "Using the default value of 1.0 for clock_delta" ) ); + break; + case PMMSpecialRawComment: + m_messages += PMMessage( i18n( "Note: The full povray syntax is not supported yet. " + "If you want to add unsupported povray code to the " + "scene, you can put this code between the two " + "special comments \"//*PMRawBegin\" and " + "\"//*PMRawEnd\"." ) ); + break; + } + } +} + +void PMParser::printMessage( const QString& type, const QString& msg ) +{ + if( m_lineNum >= 0 ) + m_messages += PMMessage( i18n( "Line %1: " ).arg( m_lineNum ) + type + ": " + msg ); + else + m_messages += PMMessage( type + ": " + msg ); +} + +void PMParser::printError( const QString& msg ) +{ + if( m_errors < s_maxErrors ) + { + printMessage( i18n( "Error" ), msg ); + m_errors++; + } + else if( m_errors == s_maxErrors ) + { + m_messages += PMMessage( i18n( "Maximum of %1 errors reached." ) + .arg( s_maxErrors ) ); + m_errors++; + } +} + +void PMParser::printWarning( const QString& msg ) +{ + if( m_warnings < s_maxWarnings ) + { + printMessage( i18n( "Warning" ), msg ); + m_warnings++; + } + else if( m_warnings == s_maxWarnings ) + { + m_messages += PMMessage( i18n( "Maximum of %1 warnings reached." ) + .arg( s_maxWarnings ) ); + m_warnings++; + } +} + +void PMParser::printExpected( const char c, const char* sValue ) +{ + printError( i18n( "'%1' expected, found token '%2' instead." ) + .arg( c ).arg( sValue ) ); +} + +void PMParser::printExpected( const QString& str, const char* sValue ) +{ + printError( i18n( "'%1' expected, found token '%2' instead." ) + .arg( str ).arg( sValue ) ); +} + +void PMParser::printUnexpected( const QString& str ) +{ + printError( i18n( "Unexpected token '%1'." ).arg( str ) ); +} + +void PMParser::printInfo( const QString& msg ) +{ + printMessage( i18n( "Info" ), msg ); +} + +int PMParser::errorFlags( ) const +{ + int result = 0; + if( errors( ) ) + result |= PMEError; + if( warnings( ) ) + result |= PMEWarning; + if( fatal( ) ) + result |= PMEFatal; + return result; +} + + +void PMParser::parse( PMObjectList* list, PMObject* parent, + PMObject* after ) +{ + m_pResultList = list; + m_pTopParent = parent; + m_pAfter = after; + + // find first item, that can be a declare and can be used as link + // for parsed objects. + if( parent ) + { + if( parent->type( ) == "Scene" ) + { + if( after ) + m_pNextCheckDeclare = after; + else + m_pNextCheckDeclare = 0; + } + else + { + PMObject* obj = parent; + bool stop = false; + + // go to parents, until the parent is the scene + // (declares can only be inserted as top level objects) + do + { + if( obj->parent( ) ) + { + if( obj->parent( )->type( ) == "Scene" ) + stop = true; + else + obj = obj->parent( ); + } + else + { + obj = 0; + stop = true; + } + } + while( obj && !stop ); + + // now obj is the top level parent of the object, where parsed objects + // will be inserted + if( obj ) + m_pNextCheckDeclare = obj->prevSibling( ); + else + m_pNextCheckDeclare = 0; + } + } + + topParse( ); + + QPtrListIterator it( m_renamedObjectSymbols ); + for( ; it.current( ); ++it ) + it.current( )->setRenamedSymbol( 0 ); + m_renamedObjectSymbols.clear( ); + m_pLocalST.clear( ); + + if( ( errors( ) || warnings( ) ) && m_pResultList->isEmpty( ) ) + setFatalError( ); +} + +bool PMParser::insertChild( PMObject* child, PMObject* parent ) +{ + bool inserted = false; + + if( parent ) + { + if( parent->canInsert( child, parent->lastChild( ) ) ) + { + parent->appendChild( child ); + inserted = true; + } + else + { + printError( i18n( "Can't insert %1 into %2." ) + .arg( child->description( ) ) + .arg( parent->description( ) ) ); + } + } + else + { + if( m_pTopParent ) + { + if( m_pTopParent->canInsert( child, m_pAfter, m_pResultList ) ) + { + m_pResultList->append( child ); + inserted = true; + } + else + { + printError( i18n( "Can't insert %1 into %2." ) + .arg( child->description( ) ) + .arg( m_pTopParent->description( ) ) ); + } + } + else + { + // these lines should not be executed + // m_pTopParent may not be null + m_pResultList->append( child ); + inserted = true; + } + } + + if( !inserted ) + { + // insert error + // remove all links + PMRecursiveObjectIterator rit( child ); + PMDeclare* decl = 0; + + for( ; rit.current( ); ++rit ) + { + decl = rit.current( )->linkedObject( ); + if( decl ) + decl->removeLinkedObject( rit.current( ) ); + } + } + + return inserted; +} + +void PMParser::checkID( PMDeclare* decl ) +{ + PMSymbolTable* st = m_pPart->symbolTable( ); + PMSymbol* s = m_pLocalST.find( decl->id( ) ); + if( !s ) + s = st->find( decl->id( ) ); + + if( s ) + { + PMSymbol* newSym = st->findNewID( s->id( ) + "_", decl ); + s->setRenamedSymbol( newSym ); + // Symbol can be inserted multiple times + // Faster than searching for s and inserting s + // if the list does not contain it. + m_renamedObjectSymbols.append( s ); + + if( m_pTopParent ) + m_pLocalST.insert( decl->id( ), newSym ); // paste/drop + else + st->insert( decl->id( ), newSym ); // load file + } + else + { + s = new PMSymbol( decl->id( ), decl ); + if( m_pTopParent ) + m_pLocalST.insert( decl->id( ), s ); // paste/drop + else + st->insert( decl->id( ), s ); // load file + m_okDeclares.insert( decl->id( ), new bool( true ) ); + } +} + +void PMParser::checkID( const QString& id, const PMValue& v ) +{ + PMSymbolTable* st = m_pPart->symbolTable( ); + PMSymbol* s = m_pLocalST.find( id ); + + if( s ) + { + PMSymbol* newSym = new PMSymbol( st->findNewID( id + "_" ), v ); + s->setRenamedSymbol( newSym ); + // Symbol can be inserted multiple times + // Faster than searching for s and inserting s + // if the list does not contain it. + m_renamedObjectSymbols.append( s ); + + if( m_pTopParent ) + m_pLocalST.insert( id, newSym ); // paste/drop + + // values are never inserted into the parts symbol table + // else + // st->insert( decl->id( ), newSym ); // load file + } + else + { + s = new PMSymbol( id, v ); + if( m_pTopParent ) + m_pLocalST.insert( id, s ); // paste/drop + + // values are never inserted into the parts symbol table + // else + // st->insert( decl->id( ), s ); // load file + + m_okDeclares.insert( id, new bool( true ) ); + } +} + +PMDeclare* PMParser::checkLink( const QString& id ) +{ + PMSymbolTable* t = m_pPart->symbolTable( ); + bool ok = false; + + // is object declared? + PMSymbol* s = m_pLocalST.find( id ); + if( !s ) + s = t->find( id ); + + if( !s ) + printError( i18n( "Undefined object \"%1\"." ).arg( id ) ); + else if( s->type( ) != PMSymbol::Object ) + printError( i18n( "Undefined object \"%1\"." ).arg( id ) ); + else + { + // the object is declared + // is the id already in m_okDeclares + bool* lok = m_okDeclares.find( id ); + if( lok ) + ok = true; + else + { + // the id is not in m_okDeclares + PMObject* obj = s->object( ); + while( m_pNextCheckDeclare && !ok ) + { + if( m_pNextCheckDeclare->isA( "Declare" ) ) + { + PMDeclare* decl = ( PMDeclare* ) m_pNextCheckDeclare; + m_okDeclares.insert( decl->id( ), new bool( true ) ); + } + if( m_pNextCheckDeclare == obj ) + ok = true; + + m_pNextCheckDeclare = m_pNextCheckDeclare->prevSibling( ); + } + } + + if( !ok ) + printError( i18n( "Object \"%1\" is undefined at that point." ) + .arg( id ) ); + } + + if( ok ) + { + while( s->renamedSymbol( ) ) + s = s->renamedSymbol( ); + + return s->object( ); + } + + return 0; +} + +PMSymbol* PMParser::getSymbol( const QString& id ) const +{ + PMSymbol* s = m_pLocalST.find( id ); + if( !s ) + s = m_pPart->symbolTable( )->find( id ); + return s; +} + diff --git a/kpovmodeler/pmparser.h b/kpovmodeler/pmparser.h new file mode 100644 index 00000000..48250798 --- /dev/null +++ b/kpovmodeler/pmparser.h @@ -0,0 +1,299 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMPARSER_H +#define PMPARSER_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "pmobject.h" +#include "pmsymboltable.h" +#include "pmvalue.h" +#include "pmerrordialog.h" + +class QTextStream; +class QIODevice; + +class PMScanner; +class PMPart; +class PMSymbolTable; + +enum PMPMessage { PMMClockDefault = 1, PMMClockDeltaDefault = 2, + PMMSpecialRawComment = 4 }; + +/** + * Base class for kpovmodeler parsers. + */ +class PMParser +{ +public: + /** + * Parser that parses the device + */ + PMParser( PMPart* part, QIODevice* device ); + /** + * Parser that parses the byte array + */ + PMParser( PMPart* part, const QByteArray& array ); + /** + * Deletes the parser + */ + virtual ~PMParser( ); + + /** + * Quickly scans the top level objects. Appends all top level object + * types to the list. + */ + virtual void quickParse( QStringList& /*list*/ ) { }; + /** + * Returns true, if the parser can quickly scan the top level objects. + */ + virtual bool canQuickParse( ) const { return false; } + + /** + * Parses the device. + * + * Appends all parsed objects to the list. + * + * parent is the object where the parsed objects will be inserted as + * children behind the object after. These parameters are used to check + * the consistency of declares and links. + * + * Set parent and after to 0 if and only if a document is parsed/opened. + */ + void parse( PMObjectList* list, PMObject* parent, + PMObject* after ); + + /** + * Returns the messages of the parser + */ + PMMessageList messages( ) const { return m_messages; } + /** + * Returns true if there were errors during parsing + */ + bool errors( ) const { return m_errors > 0; } + /** + * Returns true if there were warnings during parsing + */ + bool warnings( ) const { return m_warnings > 0; } + /** + * Returns true, if a fatal error occurred or no object could be + * successfully parsed and it doesn't make sense to continue + */ + bool fatal( ) const { return m_bFatalError; } + /** + * Returns a bitwise combination of @ref PMErrorFlags constants + */ + int errorFlags( ) const; + + /** + * returns the maximum number of errors + */ + static unsigned maxErrors( ) { return s_maxErrors; } + /** + * sets the maximum number of errors to m + */ + static void setMaxErrors( unsigned m ) { s_maxErrors = m; } + /** + * returns the maximum number of warnings + */ + static unsigned maxWarnings( ) { return s_maxWarnings; } + /** + * sets the maximum number of warnings to m + */ + static void setMaxWarnings( unsigned m ) { s_maxWarnings = m; } + + /** + * Adds an error to the message string + */ + void printError( const QString& msg ); + /** + * Adds the error "'' expected, found instead" to the message string + */ + void printExpected( const QString& str, const char* token ); + /** + * Adds the error "'' expected" to the message string + */ + void printExpected( const char c, const char* token ); + /** + * Adds the error "Unexpected token '', found instead" to the message string + */ + void printUnexpected( const QString& str ); + /** + * Adds a warning to the message string + */ + void printWarning( const QString& msg ); + /** + * Adds an info to the message string + */ + void printInfo( const QString& msg ); + /** + * Adds the message to the message string. Type is "error", "warning", + * "info" or "scanner error" + */ + void printMessage( const QString& type, const QString& msg ); + /** + * Prints a messages that should only reported once + */ + void printMessage( const PMPMessage messageNum ); + + /** + * Sets the fatal error flag + */ + void setFatalError( ) { m_bFatalError = true; } + + /** + * Sets the current line number + */ + void setCurrentLine( int lineNumber ) { m_lineNum = lineNumber; } + + /** + * Returns the declare object with id, if it exists and is declared at + * the current parse position, otherwise 0 + */ + PMDeclare* checkLink( const QString& id ); + /** + * Checks the id of the declare. If there is already a declare with + * the same id, the id of the object is renamed. + * + * Inserts the object into the symbol table.*/ + void checkID( PMDeclare* obj ); + /** + * Checks the id of the value declare (constant, vector or color). + * If there is already a declare with + * the same id, the id of the value is renamed. + * + * Inserts the object into the symbol table.*/ + void checkID( const QString& id, const PMValue& v ); + /** + * Returns the symbol with id id or 0 if the id is undeclared + */ + PMSymbol* getSymbol( const QString& id ) const; + /** + * Tries to insert obj as child of parent. If parent is 0, the object + * will be inserted in the list of top level objects. + * + * Returns true if the object could be inserted. + */ + bool insertChild( PMObject* obj, PMObject* parent ); + +protected: + /** + * Top level parse function. + * + * Overwrite this function in a specific parser. + */ + virtual void topParse( ) = 0; + +protected: + /** + * Pointer to the part + */ + PMPart* m_pPart; + /** + * parent object where the parsed top level objects + * will be inserted _later_ (not from the parser) as children + */ + const PMObject* m_pTopParent; + const PMObject* m_pAfter; + /** + * The list where the parsed objects are stored + */ + PMObjectList* m_pResultList; + /** + * The QIODevice + */ + QIODevice* m_pDevice; + /** + * True, if the device was created by the parser + */ + bool m_bDeviceCreated; + +private: + /** + * Initializes the parser + */ + void init( ); + + /** + * The parser output (errors, warnings...) + */ + PMMessageList m_messages; + /** + * A dictionary object -> message + */ + QPtrDict< QPtrList > m_messageDict; + /** + * Number of warnings during parsing + */ + unsigned int m_warnings; + /** + * Number of errors during parsing + */ + unsigned int m_errors; + /** + * Flag for fatal errors + */ + bool m_bFatalError; + + /** + * maximum number of errors + */ + static unsigned int s_maxErrors; + /** + * maximum number of warnings + */ + static unsigned int s_maxWarnings; + /** + * Already shown warnings or errors, that are reported only once + */ + int m_shownMessages; + /** + * The current line number + */ + int m_lineNum; + /** + * List of renamed declares + */ + QPtrList m_renamedObjectSymbols; + /** + * Dictionary of symbol names, that can be linked + */ + QDict m_okDeclares; + PMObject* m_pNextCheckDeclare; + /** + * Symbol table used during parsing. The symbol table of the part + * will not be changed. + */ + PMSymbolTable m_pLocalST; +}; + + + +#endif diff --git a/kpovmodeler/pmpart.cpp b/kpovmodeler/pmpart.cpp new file mode 100644 index 00000000..c87f4719 --- /dev/null +++ b/kpovmodeler/pmpart.cpp @@ -0,0 +1,2884 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +// include files for QT +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// include files for KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// application specific includes +#include "pmpart.h" +#include "pmshell.h" +#include "pmview.h" +#include "pmglview.h" +#include "pmallcommands.h" +#include "pmpovraywidget.h" +#include "pmpovrayrenderwidget.h" + +#include "pmallobjects.h" +#include "pmcommandmanager.h" +#include "pmobjectdrag.h" +#include "pmxmlparser.h" +#include "pmpovrayparser.h" +#include "pmerrordialog.h" +#include "pmsettingsdialog.h" +#include "pminserterrordialog.h" +#include "pminsertpopup.h" + +#include "pmpovray35format.h" +#include "pmserializer.h" + +#include "pmfactory.h" +#include "pmdefaults.h" +#include "pmsymboltable.h" + +#include "pmrendermodesdialog.h" +#include "pmrendermode.h" +#include "pmpovrayoutputwidget.h" +#include "pmrendermanager.h" +#include "pmdialogeditbase.h" +#include "pmdocumentationmap.h" +#include "pmlibrarymanager.h" +#include "pmlibraryhandleedit.h" +#include "pmlibraryobject.h" +#include "pmlibrarybrowser.h" +#include "pmlibraryobjectsearch.h" +#include "pmscene.h" + +#include "pmpluginmanager.h" +#include "pminsertrulesystem.h" +#include "pmprototypemanager.h" +#include "pmiomanager.h" + +#include "pmactions.h" +#include "pmrecursiveobjectiterator.h" + +#include "pmerrorflags.h" + +#include "pmfiledialog.h" + +#ifdef PMEnableSimpleProfiling +QTime PMDebugTime; +#endif + +//#define KPM_WITH_OBJECT_LIBRARY + +PMPart::PMPart( QWidget* parentWidget, const char* widgetName, + QObject* parent, const char* name, bool readwrite, + PMShell* shell ) + : DCOPObject( "PMPartIface" ), + KParts::ReadWritePart( parent, name ), + m_commandManager( this ) +{ + setPluginLoadingMode( LoadPlugins ); + setInstance( PMFactory::instance( ), false ); + m_pExtension = new PMBrowserExtension( this ); + + m_pActiveObject = 0; + m_canDecode = false; + m_pScene = 0; + m_pNewSelection = 0; + m_sortedListUpToDate = false; + m_numAddedObjects = 0; + m_numInsertErrors = 0; + m_pSymbolTable = 0; + m_bCameraListUpToDate = true; + m_updateNewObjectActions = false; + m_pPovrayWidget = 0; + m_pView = 0; + m_pShell = shell; + m_controlPoints.setAutoDelete( true ); + m_onlyCopyPaste = true; + + // call inits to invoke all other construction parts + setReadWrite( readwrite ); + + if( isReadWrite( ) ) + setXMLFile( "kpovmodelerui.rc" ); + else + setXMLFile( "kpovmodelerbrowser.rc" ); + + m_pPrototypeManager = new PMPrototypeManager( this ); + m_pInsertRuleSystem = new PMInsertRuleSystem( this ); + m_pIOManager = new PMIOManager( this ); + m_pInsertRuleSystem->loadRules( "baseinsertrules.xml" ); + + initActions( ); + initDocument( ); + initView( parentWidget, widgetName ); + + restoreConfig( instance( )->config( ) ); + + connect( qApp->clipboard( ), SIGNAL( dataChanged( ) ), + SLOT( slotClipboardDataChanged( ) ) ); + slotClipboardDataChanged( ); + connect( &m_commandManager, SIGNAL( updateUndoRedo( const QString&, const QString& ) ), + SLOT( slotUpdateUndoRedo( const QString&, const QString& ) ) ); + connect( &m_commandManager, SIGNAL( objectChanged( PMObject*, const int, QObject* ) ), + SLOT( slotObjectChanged( PMObject*, const int, QObject* ) ) ); + connect( &m_commandManager, SIGNAL( idChanged( PMObject*, const QString& ) ), + SLOT( slotIDChanged( PMObject*, const QString& ) ) ); + + PMPluginManager::theManager( )->registerPart( this ); + + emit refresh( ); + slotObjectChanged( m_pScene, PMCNewSelection, this ); +} + +PMPart::PMPart( QWidget* /*parentWidget*/, const char* /*widgetName*/, + QObject* parent, const char* name, bool readwrite, + bool /*onlyCutPaste*/, PMShell* shell ) + : DCOPObject( "LibraryBrowserIface" ), + KParts::ReadWritePart( parent, name ), + m_commandManager( this ) +{ + setPluginLoadingMode( LoadPlugins ); + setInstance( PMFactory::instance( ), false ); + + m_pActiveObject = 0; + m_canDecode = false; + m_pNewSelection = 0; + m_sortedListUpToDate = false; + m_numAddedObjects = 0; + m_numInsertErrors = 0; + m_pSymbolTable = 0; + m_bCameraListUpToDate = true; + m_updateNewObjectActions = false; + m_pPovrayWidget = 0; + m_pView = 0; + m_pShell = shell; + m_pScene = new PMScene( this ); + m_onlyCopyPaste = true; + + // call inits to invoke all other construction parts + setReadWrite( readwrite ); + + if( isReadWrite( ) ) + setXMLFile( "kpovmodelerui.rc" ); + else + setXMLFile( "kpovmodelerbrowser.rc" ); + + m_pPrototypeManager = new PMPrototypeManager( this ); + m_pInsertRuleSystem = new PMInsertRuleSystem( this ); + m_pIOManager = new PMIOManager( this ); + m_pInsertRuleSystem->loadRules( "baseinsertrules.xml" ); + m_pSymbolTable = new PMSymbolTable( ); + + initCopyPasteActions( ); + + connect( &m_commandManager, SIGNAL( objectChanged( PMObject*, const int, QObject* ) ), + SLOT( slotObjectChanged( PMObject*, const int, QObject* ) ) ); + + PMPluginManager::theManager( )->registerPart( this ); + + emit refresh( ); +} + +PMPart::~PMPart( ) +{ + delete m_pExtension; + deleteContents( ); + delete m_pSymbolTable; + delete m_pPovrayWidget; + PMPluginManager::theManager( )->removePart( this ); +} + +void PMPart::initCopyPasteActions( ) +{ + // setup edit menu + m_pCutAction = KStdAction::cut( this, SLOT( slotEditCut( ) ), actionCollection( ) ); + m_pCopyAction = KStdAction::copy( this, SLOT( slotEditCopy( ) ), actionCollection( ) ); + m_pPasteAction = KStdAction::paste( this, SLOT( slotEditPaste( ) ), actionCollection( ) ); + + m_pDeleteAction = + new KAction( i18n( "Delete" ), "edittrash", Qt::Key_Delete, + this, SLOT( slotEditDelete( ) ), + actionCollection( ), "edit_delete" ); + + m_pCutAction->setEnabled( false ); + m_pCopyAction->setEnabled( false ); + m_pPasteAction->setEnabled( false ); + m_pDeleteAction->setEnabled( false ); + +} + +void PMPart::initActions( ) +{ + // file menu + m_pImportAction = new KAction( i18n( "Import..." ), 0, this, + SLOT( slotFileImport( ) ), actionCollection( ), + "file_import" ); + m_pExportAction = new KAction( i18n( "&Export..." ), 0, this, + SLOT( slotFileExport( ) ), actionCollection( ), + "file_export" ); + + initCopyPasteActions( ); + m_onlyCopyPaste = false; + + m_pRenderComboAction = new PMComboAction( i18n( "Render Modes" ), 0, this, SLOT( slotRenderMode( int ) ), + actionCollection( ), "view_render_combo" ); + m_pRenderComboAction->setMinimumWidth( 250 ); + connect( m_pRenderComboAction, SIGNAL( plugged( ) ), + SLOT( slotRenderModeActionPlugged( ) ) ); + m_pRenderAction = new KAction( i18n( "Render" ), "pmrender", 0, this, SLOT( slotRender( ) ), + actionCollection( ), "view_render" ); + m_pRenderSettingsAction = new KAction( i18n( "Render Modes..." ), "pmrendersettings", 0, this, SLOT( slotRenderSettings( ) ), + actionCollection( ), "view_render_settings" ); + m_pViewRenderWindowAction = new KAction( i18n( "Render Window" ), 0, this, SLOT( slotViewRenderWindow( ) ), + actionCollection( ), "view_render_window" ); + m_pVisibilityLabelAction = new PMLabelAction( i18n( "Visibility level:" ) + QString( " " ), actionCollection( ), "view_visibility_label" ); + m_pVisibilityLevelAction = new PMSpinBoxAction( i18n( "Visibility Level" ), + 0, this, SLOT( slotVisibilityLevelChanged( int ) ), + actionCollection( ), "view_visibility_level" ); + connect( m_pVisibilityLevelAction, SIGNAL( plugged( ) ), + SLOT( slotVisibilityActionPlugged( ) ) ); + + m_pGlobalDetailLabelAction = new PMLabelAction( i18n( "Global detail:" ) + QString( " " ), actionCollection( ), "global_detail_label" ); + m_pGlobalDetailAction = new KSelectAction( i18n("Global Detail Level"), KShortcut(), actionCollection(), "global_detail_level" ); + QStringList strList; + strList.append( i18n( "Very Low" ) ); + strList.append( i18n( "Low" ) ); + strList.append( i18n( "Medium" ) ); + strList.append( i18n( "High" ) ); + strList.append( i18n( "Very High" ) ); + m_pGlobalDetailAction->setItems( strList ); + connect( m_pGlobalDetailAction, SIGNAL( activated( int ) ), SLOT( slotGlobalDetailLevelChanged( int ) ) ); + + // new objects + if( isReadWrite( ) ) + { + m_pNewGlobalSettingsAction = new KAction( i18n( "Global Settings" ), "pmglobalsettings", 0, this, SLOT( slotNewGlobalSettings( ) ), + actionCollection( ), "new_globalsettings" ); + m_readWriteActions.append( m_pNewGlobalSettingsAction ); + m_pNewSkySphereAction = new KAction( i18n( "Sky Sphere" ), "pmskysphere", 0, this, SLOT( slotNewSkySphere( ) ), + actionCollection( ), "new_skysphere" ); + m_readWriteActions.append( m_pNewSkySphereAction ); + m_pNewRainbowAction = new KAction( i18n( "Rainbow" ), "pmrainbow", 0, this, SLOT( slotNewRainbow( ) ), + actionCollection( ), "new_rainbow" ); + m_readWriteActions.append( m_pNewRainbowAction ); + m_pNewFogAction = new KAction( i18n( "Fog" ), "pmfog", 0, this, SLOT( slotNewFog( ) ), + actionCollection( ), "new_fog" ); + m_readWriteActions.append( m_pNewFogAction ); + m_pNewInteriorAction = new KAction( i18n( "Interior" ), "pminterior", 0, this, SLOT( slotNewInterior( ) ), + actionCollection( ), "new_interior" ); + m_readWriteActions.append( m_pNewInteriorAction ); + m_pNewMediaAction = new KAction( i18n( "Media" ), "pmmedia", 0, this, SLOT( slotNewMedia( ) ), + actionCollection( ), "new_media" ); + m_readWriteActions.append( m_pNewMediaAction ); + m_pNewDensityAction = new KAction( i18n( "Density" ), "pmdensity", 0, this, SLOT( slotNewDensity( ) ), + actionCollection( ), "new_density" ); + m_readWriteActions.append( m_pNewDensityAction ); + m_pNewMaterialAction = new KAction( i18n( "Material" ), "pmmaterial", 0, this, SLOT( slotNewMaterial( ) ), + actionCollection( ), "new_material" ); + m_readWriteActions.append( m_pNewMaterialAction ); + m_pNewBoxAction = new KAction( i18n( "Box" ), "pmbox", 0, this, SLOT( slotNewBox( ) ), + actionCollection( ), "new_box" ); + m_readWriteActions.append( m_pNewBoxAction ); + m_pNewSphereAction = new KAction( i18n( "Sphere" ), "pmsphere", 0, this, SLOT( slotNewSphere( ) ), + actionCollection( ), "new_sphere" ); + m_readWriteActions.append( m_pNewSphereAction ); + m_pNewCylinderAction = new KAction( i18n( "Cylinder" ), "pmcylinder", 0, this, SLOT( slotNewCylinder( ) ), + actionCollection( ), "new_cylinder" ); + m_readWriteActions.append( m_pNewCylinderAction ); + m_pNewConeAction = new KAction( i18n( "Cone" ), "pmcone", 0, this, SLOT( slotNewCone( ) ), + actionCollection( ), "new_cone" ); + m_readWriteActions.append( m_pNewConeAction ); + m_pNewTorusAction = new KAction( i18n( "Torus" ), "pmtorus", 0, this, SLOT( slotNewTorus( ) ), + actionCollection( ), "new_torus" ); + m_readWriteActions.append( m_pNewTorusAction ); + + m_pNewLatheAction = new KAction( i18n( "Lathe" ), "pmlathe", 0, this, SLOT( slotNewLathe( ) ), + actionCollection( ), "new_lathe" ); + m_readWriteActions.append( m_pNewLatheAction ); + m_pNewPrismAction = new KAction( i18n( "Prism" ), "pmprism", 0, this, SLOT( slotNewPrism( ) ), + actionCollection( ), "new_prism" ); + m_readWriteActions.append( m_pNewPrismAction ); + m_pNewSurfaceOfRevolutionAction = new KAction( i18n( "Surface of Revolution" ), "pmsor", 0, this, SLOT( slotNewSurfaceOfRevolution( ) ), + actionCollection( ), "new_surfaceofrevolution" ); + m_readWriteActions.append( m_pNewSurfaceOfRevolutionAction ); + m_pNewSuperquadricEllipsoidAction = new KAction( i18n( "Superquadric Ellipsoid" ), "pmsqe", 0, this, SLOT( slotNewSuperquadricEllipsoid( ) ), + actionCollection( ), "new_superquadricellipsoid" ); + m_readWriteActions.append( m_pNewSuperquadricEllipsoidAction ); + + m_pNewJuliaFractalAction = new KAction( i18n( "Julia Fractal" ), "pmjuliafractal", 0, this, SLOT( slotNewJuliaFractal( ) ), + actionCollection( ), "new_juliafractal" ); + m_readWriteActions.append( m_pNewJuliaFractalAction ); + m_pNewHeightFieldAction = new KAction( i18n( "Height Field" ), "pmheightfield", 0, this, SLOT( slotNewHeightField( ) ), + actionCollection( ), "new_heightfield" ); + m_readWriteActions.append( m_pNewHeightFieldAction ); + m_pNewTextAction = new KAction( i18n( "Text" ), "pmtext", 0, this, SLOT( slotNewText( ) ), + actionCollection( ), "new_text" ); + m_readWriteActions.append( m_pNewTextAction ); + + m_pNewBlobAction = new KAction( i18n( "Blob" ), "pmblob", 0, this, SLOT( slotNewBlob( ) ), + actionCollection( ), "new_blob" ); + m_readWriteActions.append( m_pNewBlobAction ); + m_pNewBlobSphereAction = new KAction( i18n( "Blob Sphere" ), "pmblobsphere", 0, this, SLOT( slotNewBlobSphere( ) ), + actionCollection( ), "new_blobsphere" ); + m_readWriteActions.append( m_pNewBlobSphereAction ); + m_pNewBlobCylinderAction = new KAction( i18n( "Blob Cylinder" ), "pmblobcylinder", 0, this, SLOT( slotNewBlobCylinder( ) ), + actionCollection( ), "new_blobcylinder" ); + m_readWriteActions.append( m_pNewBlobCylinderAction ); + + m_pNewPlaneAction = new KAction( i18n( "Plane" ), "pmplane", 0, this, SLOT( slotNewPlane( ) ), + actionCollection( ), "new_plane" ); + m_readWriteActions.append( m_pNewPlaneAction ); + m_pNewPolynomAction = new KAction( i18n( "Polynom" ), "pmpolynom", 0, this, SLOT( slotNewPolynom( ) ), + actionCollection( ), "new_polynom" ); + m_readWriteActions.append( m_pNewPolynomAction ); + + m_pNewDeclareAction = new KAction( i18n( "Declaration" ), "pmdeclare", 0, this, SLOT( slotNewDeclare( ) ), + actionCollection( ), "new_declare" ); + m_readWriteActions.append( m_pNewDeclareAction ); + m_pNewObjectLinkAction = new KAction( i18n( "Object Link" ), "pmobjectlink", 0, this, SLOT( slotNewObjectLink( ) ), + actionCollection( ), "new_objectlink" ); + m_readWriteActions.append( m_pNewObjectLinkAction ); + + m_pNewUnionAction = new KAction( i18n( "Union" ), "pmunion", 0, this, SLOT( slotNewUnion( ) ), + actionCollection( ), "new_union" ); + m_readWriteActions.append( m_pNewUnionAction ); + m_pNewIntersectionAction = new KAction( i18n( "Intersection" ), "pmintersection", 0, this, SLOT( slotNewIntersection( ) ), + actionCollection( ), "new_intersection" ); + m_readWriteActions.append( m_pNewIntersectionAction ); + m_pNewDifferenceAction = new KAction( i18n( "Difference" ), "pmdifference", 0, this, SLOT( slotNewDifference( ) ), + actionCollection( ), "new_difference" ); + m_readWriteActions.append( m_pNewDifferenceAction ); + m_pNewMergeAction = new KAction( i18n( "Merge" ), "pmmerge", 0, this, SLOT( slotNewMerge( ) ), + actionCollection( ), "new_merge" ); + m_readWriteActions.append( m_pNewMergeAction ); + + m_pNewBoundedByAction = new KAction( i18n( "Bounded By" ), "pmboundedby", 0, this, SLOT( slotNewBoundedBy( ) ), + actionCollection( ), "new_boundedby" ); + m_readWriteActions.append( m_pNewBoundedByAction ); + m_pNewClippedByAction = new KAction( i18n( "Clipped By" ), "pmclippedby", 0, this, SLOT( slotNewClippedBy( ) ), + actionCollection( ), "new_clippedby" ); + m_readWriteActions.append( m_pNewClippedByAction ); + + m_pNewLightAction = new KAction( i18n( "Light" ), "pmlight", 0, this, SLOT( slotNewLight( ) ), + actionCollection( ), "new_light" ); + m_readWriteActions.append( m_pNewLightAction ); + m_pNewLooksLikeAction = new KAction( i18n( "Looks Like" ), "pmlookslike", 0, this, SLOT( slotNewLooksLike( ) ), + actionCollection( ), "new_lookslike" ); + m_readWriteActions.append( m_pNewLooksLikeAction ); + m_pNewProjectedThroughAction = new KAction( i18n( "Projected Through" ), "pmprojectedthrough", 0, this, SLOT( slotNewProjectedThrough( ) ), + actionCollection( ), "new_projectedthrough" ); + m_readWriteActions.append( m_pNewProjectedThroughAction ); + + m_pNewBicubicPatchAction = new KAction( i18n( "Bicubic Patch" ), "pmbicubicpatch", 0, this, SLOT( slotNewBicubicPatch( ) ), + actionCollection( ), "new_bicubicpatch" ); + m_readWriteActions.append( m_pNewBicubicPatchAction ); + m_pNewDiscAction = new KAction( i18n( "Disc" ), "pmdisc", 0, this, SLOT( slotNewDisc( ) ), + actionCollection( ), "new_disc" ); + m_readWriteActions.append( m_pNewDiscAction ); + m_pNewTriangleAction = new KAction( i18n( "Triangle" ), "pmtriangle", 0, this, SLOT( slotNewTriangle( ) ), + actionCollection( ), "new_triangle" ); + m_readWriteActions.append( m_pNewTriangleAction ); + + + m_pNewCameraAction = new KAction( i18n( "Camera" ), "pmcamera", 0, this, SLOT( slotNewCamera( ) ), + actionCollection( ), "new_camera" ); + m_readWriteActions.append( m_pNewCameraAction ); + + m_pNewTextureAction = new KAction( i18n( "Texture" ), "pmtexture", 0, this, SLOT( slotNewTexture( ) ), + actionCollection( ), "new_texture" ); + m_readWriteActions.append( m_pNewTextureAction ); + + m_pNewPigmentAction = new KAction( i18n( "Pigment" ), "pmpigment", 0, this, SLOT( slotNewPigment( ) ), + actionCollection( ), "new_pigment" ); + m_readWriteActions.append( m_pNewPigmentAction ); + m_pNewNormalAction = new KAction( i18n( "Normal" ), "pmnormal", 0, this, SLOT( slotNewNormal( ) ), + actionCollection( ), "new_normal" ); + m_readWriteActions.append( m_pNewNormalAction ); + m_pNewSolidColorAction = new KAction( i18n( "Solid Color" ), "pmsolidcolor", 0, this, SLOT( slotNewSolidColor( ) ), + actionCollection( ), "new_solidcolor" ); + m_readWriteActions.append( m_pNewSolidColorAction ); + + m_pNewTextureListAction = new KAction( i18n( "Texture List" ), "pmtexturelist", 0, this, SLOT( slotNewTextureList( ) ), + actionCollection( ), "new_texturelist" ); + m_readWriteActions.append( m_pNewTextureListAction ); + m_pNewColorListAction = new KAction( i18n( "Color List" ), "pmcolorlist", 0, this, SLOT( slotNewColorList( ) ), + actionCollection( ), "new_colorlist" ); + m_readWriteActions.append( m_pNewColorListAction ); + m_pNewPigmentListAction = new KAction( i18n( "Pigment List" ), "pmpigmentlist", 0, this, SLOT( slotNewPigmentList( ) ), + actionCollection( ), "new_pigmentlist" ); + m_readWriteActions.append( m_pNewPigmentListAction ); + m_pNewNormalListAction = new KAction( i18n( "Normal List" ), "pmnormallist", 0, this, SLOT( slotNewNormalList( ) ), + actionCollection( ), "new_normallist" ); + m_readWriteActions.append( m_pNewNormalListAction ); + m_pNewDensityListAction = new KAction( i18n( "Density List" ), "pmdensitylist", 0, this, SLOT( slotNewDensityList( ) ), + actionCollection( ), "new_densitylist" ); + m_readWriteActions.append( m_pNewDensityListAction ); + + m_pNewFinishAction = new KAction( i18n( "Finish" ), "pmfinish", 0, this, SLOT( slotNewFinish( ) ), + actionCollection( ), "new_finish" ); + m_readWriteActions.append( m_pNewFinishAction ); + + m_pNewPatternAction = new KAction( i18n( "Pattern" ), "pmpattern", 0, this, SLOT( slotNewPattern( ) ), + actionCollection( ), "new_pattern" ); + m_readWriteActions.append( m_pNewPatternAction ); + m_pNewBlendMapModifiersAction = new KAction( i18n( "Blend Map Modifiers" ), "pmblendmapmodifiers", 0, this, SLOT( slotNewBlendMapModifiers( ) ), + actionCollection( ), "new_blendmapmodifiers" ); + m_readWriteActions.append( m_pNewBlendMapModifiersAction ); + m_pNewTextureMapAction = new KAction( i18n( "Texture Map" ), "pmtexturemap", 0, this, SLOT( slotNewTextureMap( ) ), + actionCollection( ), "new_texturemap" ); + m_readWriteActions.append( m_pNewTextureMapAction ); + m_pNewMaterialMapAction = new KAction( i18n( "Material Map" ), "pmmaterialmap", 0, this, SLOT( slotNewMaterialMap( ) ), + actionCollection( ), "new_materialmap" ); + m_readWriteActions.append( m_pNewMaterialMapAction ); + m_pNewPigmentMapAction = new KAction( i18n( "Pigment Map" ), "pmpigmentmap", 0, this, SLOT( slotNewPigmentMap( ) ), + actionCollection( ), "new_pigmentmap" ); + m_readWriteActions.append( m_pNewPigmentMapAction ); + m_pNewColorMapAction = new KAction( i18n( "Color Map" ), "pmcolormap", 0, this, SLOT( slotNewColorMap( ) ), + actionCollection( ), "new_colormap" ); + m_readWriteActions.append( m_pNewColorMapAction ); + m_pNewNormalMapAction = new KAction( i18n( "Normal Map" ), "pmnormalmap", 0, this, SLOT( slotNewNormalMap( ) ), + actionCollection( ), "new_normalmap" ); + m_readWriteActions.append( m_pNewNormalMapAction ); + m_pNewBumpMapAction = new KAction( i18n( "Bump Map" ), "pmbumpmap", 0, this, SLOT( slotNewBumpMap( ) ), + actionCollection( ), "new_bumpmap" ); + m_readWriteActions.append( m_pNewBumpMapAction ); + m_pNewSlopeMapAction = new KAction( i18n( "Slope Map" ), "pmslopemap", 0, this, SLOT( slotNewSlopeMap( ) ), + actionCollection( ), "new_slopemap" ); + m_readWriteActions.append( m_pNewSlopeMapAction ); + m_pNewDensityMapAction = new KAction( i18n( "Density Map" ), "pmdensitymap", 0, this, SLOT( slotNewDensityMap( ) ), + actionCollection( ), "new_densitymap" ); + m_readWriteActions.append( m_pNewDensityMapAction ); + m_pNewSlopeAction = new KAction( i18n( "Slope" ), "pmslope", 0, this, SLOT( slotNewSlope( ) ), + actionCollection( ), "new_slope" ); + m_readWriteActions.append( m_pNewSlopeAction ); + + m_pNewWarpAction = new KAction( i18n( "Warp" ), "pmwarp", 0, this, SLOT( slotNewWarp( ) ), + actionCollection( ), "new_warp" ); + m_readWriteActions.append( m_pNewWarpAction ); + m_pNewImageMapAction = new KAction( i18n( "Image Map" ), "pmimagemap", 0, this, SLOT( slotNewImageMap( ) ), + actionCollection( ), "new_imagemap" ); + m_readWriteActions.append( m_pNewImageMapAction ); + m_pNewQuickColorAction = new KAction( i18n( "QuickColor" ), "pmquickcolor", 0, this, SLOT( slotNewQuickColor( ) ), + actionCollection( ), "new_quickcolor" ); + m_readWriteActions.append( m_pNewQuickColorAction ); + + m_pNewTranslateAction = new KAction( i18n( "Translate" ), "pmtranslate", 0, this, SLOT( slotNewTranslate( ) ), + actionCollection( ), "new_translate" ); + m_readWriteActions.append( m_pNewTranslateAction ); + m_pNewScaleAction = new KAction( i18n( "Scale" ), "pmscale", 0, this, SLOT( slotNewScale( ) ), + actionCollection( ), "new_scale" ); + m_readWriteActions.append( m_pNewScaleAction ); + m_pNewRotateAction = new KAction( i18n( "Rotate" ), "pmrotate", 0, this, SLOT( slotNewRotate( ) ), + actionCollection( ), "new_rotate" ); + m_readWriteActions.append( m_pNewRotateAction ); + m_pNewMatrixAction = new KAction( i18n( "Matrix" ), "pmmatrix", 0, this, SLOT( slotNewMatrix( ) ), + actionCollection( ), "new_povraymatrix" ); + m_readWriteActions.append( m_pNewMatrixAction ); + + m_pNewCommentAction = new KAction( i18n( "Comment" ), "pmcomment", 0, this, SLOT( slotNewComment( ) ), + actionCollection( ), "new_comment" ); + m_readWriteActions.append( m_pNewCommentAction ); + m_pNewRawAction = new KAction( i18n( "Raw Povray" ), "pmraw", 0, this, SLOT( slotNewRaw( ) ), + actionCollection( ), "new_raw" ); + m_readWriteActions.append( m_pNewRawAction ); + + // POV-Ray 3.5 objects + m_pNewIsoSurfaceAction = new KAction( i18n( "Iso Surface" ), "pmisosurface", 0, this, SLOT( slotNewIsoSurface( ) ), + actionCollection( ), "new_isosurface" ); + m_readWriteActions.append( m_pNewIsoSurfaceAction ); + m_pNewRadiosityAction = new KAction( i18n( "Radiosity" ), "pmradiosity", 0, this, SLOT( slotNewRadiosity( ) ), + actionCollection( ), "new_radiosity" ); + m_readWriteActions.append( m_pNewRadiosityAction ); + m_pNewGlobalPhotonsAction = new KAction( i18n( "Global Photons" ), "pmglobalphotons", 0, this, SLOT( slotNewGlobalPhotons( ) ), + actionCollection( ), "new_globalphotons" ); + m_readWriteActions.append( m_pNewGlobalPhotonsAction ); + m_pNewPhotonsAction = new KAction( i18n( "Photons" ), "pmphotons", 0, this, SLOT( slotNewPhotons( ) ), + actionCollection( ), "new_photons" ); + m_readWriteActions.append( m_pNewPhotonsAction ); + m_pNewLightGroupAction = new KAction( i18n( "Light Group" ), "pmlightgroup", 0, this, SLOT( slotNewLightGroup( ) ), + actionCollection( ), "new_lightgroup" ); + m_readWriteActions.append( m_pNewLightGroupAction ); + m_pNewInteriorTextureAction = new KAction( i18n( "Interior Texture" ), "pminteriortexture", 0, this, SLOT( slotNewInteriorTexture( ) ), + actionCollection( ), "new_interiortexture" ); + m_readWriteActions.append( m_pNewInteriorTextureAction ); + m_pNewSphereSweepAction = new KAction( i18n( "Sphere Sweep" ), "pmspheresweep", 0, this, SLOT( slotNewSphereSweep( ) ), + actionCollection( ), "new_spheresweep" ); + m_readWriteActions.append( m_pNewSphereSweepAction ); + m_pNewMeshAction = new KAction( i18n( "Mesh" ), "pmmesh", 0, this, SLOT( slotNewMesh( ) ), + actionCollection( ), "new_mesh" ); + m_readWriteActions.append( m_pNewMeshAction ); + +#ifdef KPM_WITH_OBJECT_LIBRARY + m_pSearchLibraryObjectAction = new KAction( i18n( "Search Object" ), "pmsearchlibrary", 0, this, SLOT( slotSearchLibraryObject( ) ), + actionCollection( ), "search_library_object" ); + m_readWriteActions.append( m_pSearchLibraryObjectAction ); +#endif + + m_pUndoAction = KStdAction::undo( this, SLOT( slotEditUndo( ) ), actionCollection( ) ); + m_pRedoAction = KStdAction::redo( this, SLOT( slotEditRedo( ) ), actionCollection( ) ); + m_pUndoAction->setEnabled( false ); + m_pRedoAction->setEnabled( false ); + } + else + { + m_pNewGlobalSettingsAction = 0; + m_pNewSkySphereAction = 0; + m_pNewRainbowAction = 0; + m_pNewFogAction = 0; + + m_pNewInteriorAction = 0; + m_pNewMediaAction = 0; + m_pNewDensityAction = 0; + m_pNewMaterialAction = 0; + m_pNewBoxAction = 0; + m_pNewSphereAction = 0; + m_pNewCylinderAction = 0; + m_pNewConeAction = 0; + m_pNewTorusAction = 0; + m_pNewLatheAction = 0; + m_pNewPrismAction = 0; + m_pNewSurfaceOfRevolutionAction = 0; + m_pNewSuperquadricEllipsoidAction = 0; + m_pNewJuliaFractalAction = 0; + m_pNewHeightFieldAction = 0; + m_pNewTextAction = 0; + + m_pNewBlobAction = 0; + m_pNewBlobSphereAction = 0; + m_pNewBlobCylinderAction = 0; + + m_pNewPlaneAction = 0; + m_pNewPolynomAction = 0; + + m_pNewDeclareAction = 0; + m_pNewObjectLinkAction = 0; + + m_pNewDiscAction = 0; + m_pNewBicubicPatchAction = 0; + m_pNewTriangleAction = 0; + + m_pNewUnionAction = 0; + m_pNewDifferenceAction = 0; + m_pNewIntersectionAction = 0; + m_pNewMergeAction = 0; + + m_pNewBoundedByAction = 0; + m_pNewClippedByAction = 0; + + m_pNewLightAction = 0; + m_pNewLooksLikeAction = 0; + m_pNewProjectedThroughAction = 0; + + m_pNewCameraAction = 0; + + m_pNewTextureAction = 0; + m_pNewPigmentAction = 0; + m_pNewNormalAction = 0; + m_pNewSolidColorAction = 0; + m_pNewFinishAction = 0; + m_pNewTextureListAction = 0; + m_pNewColorListAction = 0; + m_pNewPigmentListAction = 0; + m_pNewNormalListAction = 0; + m_pNewDensityListAction = 0; + + m_pNewPatternAction = 0; + m_pNewBlendMapModifiersAction = 0; + m_pNewTextureMapAction = 0; + m_pNewMaterialMapAction = 0; + m_pNewPigmentMapAction = 0; + m_pNewColorMapAction = 0; + m_pNewNormalMapAction = 0; + m_pNewBumpMapAction = 0; + m_pNewSlopeMapAction = 0; + m_pNewDensityMapAction = 0; + + m_pNewWarpAction = 0; + m_pNewImageMapAction = 0; + m_pNewSlopeAction = 0; + + m_pNewTranslateAction = 0; + m_pNewScaleAction = 0; + m_pNewRotateAction = 0; + m_pNewMatrixAction = 0; + m_pNewCommentAction = 0; + m_pNewRawAction = 0; + + m_pNewIsoSurfaceAction = 0; + m_pNewRadiosityAction = 0; + m_pNewGlobalPhotonsAction = 0; + m_pNewPhotonsAction = 0; + m_pNewLightGroupAction = 0; + m_pNewInteriorTextureAction = 0; + m_pNewSphereSweepAction = 0; + m_pNewMeshAction = 0; + + // POV-Ray + + m_pUndoAction = 0; + m_pRedoAction = 0; + } +} + +void PMPart::updateNewObjectActions( ) +{ + if( isReadWrite( ) && !m_onlyCopyPaste ) + { + QPtrListIterator it = + m_pPrototypeManager->prototypeIterator( ); + KAction* action; + bool enable; + bool readWriteParent = false; + + if( m_pActiveObject ) + if( m_pActiveObject->parent( ) ) + if( !m_pActiveObject->parent( )->isReadOnly( ) ) + readWriteParent = true; + + for( ; it.current( ); ++it ) + { + // get the action object for that type of PMObject + // action names are "new_" + povray name + // (like new_box, new_sphere ...) + + QString actionName = "new_" + it.current( )->className( ).lower( ); + action = actionCollection( )->action( actionName.latin1( ) ); + if( action ) + { + if( m_pActiveObject ) + { + QString insertName = it.current( )->className( ); + enable = m_pActiveObject->canInsert( insertName, 0 ); + if( !enable ) + if( m_pActiveObject->lastChild( ) ) + enable = m_pActiveObject->canInsert( insertName, m_pActiveObject->lastChild( ) ); + if( !enable ) + if( readWriteParent ) + enable |= m_pActiveObject->parent( )->canInsert( insertName, m_pActiveObject ); + } + else + enable = false; + action->setEnabled( enable ); + } + } + // special treatment for csg actions + if( m_pActiveObject ) + { + enable = m_pActiveObject->canInsert( QString( "CSG" ), 0 ); + if( !enable ) + if( m_pActiveObject->lastChild( ) ) + enable = m_pActiveObject->canInsert( QString( "CSG" ), m_pActiveObject->lastChild( ) ); + if( !enable ) + if( readWriteParent ) + enable = m_pActiveObject->parent( )->canInsert( QString( "CSG" ), m_pActiveObject ); + } + else + enable = false; + m_pNewUnionAction->setEnabled( enable ); + m_pNewIntersectionAction->setEnabled( enable ); + m_pNewDifferenceAction->setEnabled( enable ); + m_pNewMergeAction->setEnabled( enable ); + } + m_updateNewObjectActions = false; +} + +void PMPart::disableReadWriteActions( ) +{ + QPtrListIterator it( m_readWriteActions); + for( ; it.current( ); ++it ) + it.current( )->setEnabled( false ); +} + +void PMPart::initDocument( ) +{ + newDocument( ); +} + +void PMPart::initView( QWidget* parent, const char* name ) +{ + if( !m_pShell ) + { + // a part inside konqueror + // simple layout + m_pView = new PMView( this, parent, name ); + m_pView->show( ); + setWidget( m_pView ); + } + else + { + // inside a PMShell + // the shell will create the view + } +} + +void PMPart::saveConfig( KConfig* cfg ) +{ + if( m_pView ) + m_pView->saveConfig( cfg ); + PMErrorDialog::saveConfig( cfg ); + PMRenderModesDialog::saveConfig( cfg ); + PMRenderModeDialog::saveConfig( cfg ); + PMPovrayOutputWidget::saveConfig( cfg ); + PMRenderManager::theManager( )->saveConfig( cfg ); + PMGLView::saveConfig( cfg ); + PMDialogEditBase::saveConfig( cfg ); + PMControlPoint::saveConfig( cfg ); + PMPovrayRenderWidget::saveConfig( cfg ); + PMSettingsDialog::saveConfig( cfg ); + PMLibraryHandleEdit::saveConfig( cfg ); + PMDocumentationMap::theMap( )->saveConfig( cfg ); + PMLibraryManager::theManager( )->saveConfig(cfg ); + + cfg->setGroup( "Rendering" ); + cfg->writeEntry( "SphereUSteps", PMSphere::uSteps( ) ); + cfg->writeEntry( "SphereVSteps", PMSphere::vSteps( ) ); + cfg->writeEntry( "CylinderSteps", PMCylinder::steps( ) ); + cfg->writeEntry( "ConeSteps", PMCone::steps( ) ); + cfg->writeEntry( "DiscSteps", PMDisc::steps( ) ); + cfg->writeEntry( "BlobSphereUSteps", PMBlobSphere::uSteps( ) ); + cfg->writeEntry( "BlobSphereVSteps", PMBlobSphere::vSteps( ) ); + cfg->writeEntry( "BlobCylinderUSteps", PMBlobCylinder::uSteps( ) ); + cfg->writeEntry( "BlobCylinderVSteps", PMBlobCylinder::vSteps( ) ); + cfg->writeEntry( "TorusUSteps", PMTorus::uSteps( ) ); + cfg->writeEntry( "TorusVSteps", PMTorus::vSteps( ) ); + cfg->writeEntry( "LatheSSteps", PMLathe::sSteps( ) ); + cfg->writeEntry( "LatheRSteps", PMLathe::rSteps( ) ); + cfg->writeEntry( "SorSSteps", PMSurfaceOfRevolution::sSteps( ) ); + cfg->writeEntry( "SorRSteps", PMSurfaceOfRevolution::rSteps( ) ); + cfg->writeEntry( "PrismSSteps", PMPrism::sSteps( ) ); + cfg->writeEntry( "PlaneSize", PMPlane::planeSize( ) ); + cfg->writeEntry( "SqeUSteps", PMSuperquadricEllipsoid::uSteps( ) ); + cfg->writeEntry( "SqeVSteps", PMSuperquadricEllipsoid::vSteps( ) ); + cfg->writeEntry( "SphereSweepRSteps", PMSphereSweep::rSteps( ) ); + cfg->writeEntry( "SphereSweepSSteps", PMSphereSweep::sSteps( ) ); + cfg->writeEntry( "HeightFieldVariance", PMHeightField::variance( ) ); + cfg->writeEntry( "GlobalDetailLevel", PMDetailObject::globalDetailLevel( ) ); + + cfg->writeEntry( "DirectRendering", PMGLView::isDirectRenderingEnabled( ) ); +} + +void PMPart::restoreConfig( KConfig* cfg ) +{ + if( m_pView ) + m_pView->restoreConfig( cfg ); + PMErrorDialog::restoreConfig( cfg ); + PMRenderModesDialog::restoreConfig( cfg ); + PMRenderModeDialog::restoreConfig( cfg ); + PMPovrayOutputWidget::restoreConfig( cfg ); + PMRenderManager::theManager( )->restoreConfig( cfg ); + PMGLView::restoreConfig( cfg ); + PMDialogEditBase::restoreConfig( cfg ); + PMControlPoint::restoreConfig( cfg ); + PMPovrayRenderWidget::restoreConfig( cfg ); + PMSettingsDialog::restoreConfig( cfg ); + PMLibraryHandleEdit::restoreConfig( cfg ); + PMDocumentationMap::theMap( )->restoreConfig( cfg ); + PMLibraryManager::theManager( )->restoreConfig(cfg ); + + cfg->setGroup( "Rendering" ); + PMSphere::setUSteps( cfg->readNumEntry( "SphereUSteps", c_defaultSphereUSteps ) ); + PMSphere::setVSteps( cfg->readNumEntry( "SphereVSteps", c_defaultSphereVSteps ) ); + PMCylinder::setSteps( cfg->readNumEntry( "CylinderSteps", c_defaultCylinderSteps ) ); + PMCone::setSteps( cfg->readNumEntry( "ConeSteps", c_defaultConeSteps ) ); + PMTorus::setUSteps( cfg->readNumEntry( "TorusUSteps", c_defaultTorusUSteps ) ); + PMTorus::setVSteps( cfg->readNumEntry( "TorusVSteps", c_defaultTorusVSteps ) ); + PMLathe::setSSteps( cfg->readNumEntry( "LatheSSteps", c_defaultLatheSSteps ) ); + PMLathe::setRSteps( cfg->readNumEntry( "LatheRSteps", c_defaultLatheRSteps ) ); + PMSurfaceOfRevolution::setSSteps( cfg->readNumEntry( "SorSSteps", c_defaultSurfaceOfRevolutionSSteps ) ); + PMSurfaceOfRevolution::setRSteps( cfg->readNumEntry( "SorRSteps", c_defaultSurfaceOfRevolutionRSteps ) ); + PMPrism::setSSteps( cfg->readNumEntry( "PrismSSteps", c_defaultPrismSSteps ) ); + PMPlane::setPlaneSize( cfg->readDoubleNumEntry( "PlaneSize", c_defaultPlaneSize ) ); + PMDisc::setSteps( cfg->readNumEntry( "DiscSteps", c_defaultDiscSteps ) ); + PMBlobSphere::setUSteps( cfg->readNumEntry( "BlobSphereUSteps", c_defaultBlobSphereUSteps ) ); + PMBlobSphere::setVSteps( cfg->readNumEntry( "BlobSphereVSteps", c_defaultBlobSphereVSteps ) ); + PMBlobCylinder::setUSteps( cfg->readNumEntry( "BlobCylinderUSteps", c_defaultBlobCylinderUSteps ) ); + PMBlobCylinder::setVSteps( cfg->readNumEntry( "BlobCylinderVSteps", c_defaultBlobCylinderVSteps ) ); + PMSuperquadricEllipsoid::setUSteps( cfg->readNumEntry( "SqeUSteps", c_defaultSuperquadricEllipsoidUSteps ) ); + PMSuperquadricEllipsoid::setVSteps( cfg->readNumEntry( "SqeVSteps", c_defaultSuperquadricEllipsoidVSteps ) ); + PMSphereSweep::setRSteps( cfg->readNumEntry( "SphereSweepRSteps", c_defaultSphereSweepRSteps ) ); + PMSphereSweep::setSSteps( cfg->readNumEntry( "SphereSweepSSteps", c_defaultSphereSweepSSteps ) ); + PMHeightField::setVariance( cfg->readNumEntry( "HeightFieldVariance", c_defaultHeightFieldVariance ) ); + PMDetailObject::setGlobalDetailLevel( cfg->readNumEntry( "GlobalDetailLevel", c_defaultDetailObjectGlobalDetailLevel ) ); + m_pGlobalDetailAction->setCurrentItem( PMDetailObject::globalDetailLevel( ) - 1 ); + + if( PMGLView::isDirectRenderingEnabled( ) ) // otherwise it was disabled with a command line switch + PMGLView::enableDirectRendering( cfg->readBoolEntry( "DirectRendering", true ) ); +} + +bool PMPart::openFile( ) +{ + QIODevice* dev = KFilterDev::deviceForFile( m_file, "application/x-gzip" ); + bool success = true; + PMObjectList list; + + deleteContents( ); + + setModified( false ); + + if( dev && dev->open( IO_ReadOnly ) ) + { + PMXMLParser parser( this, dev ); + + parser.parse( &list, 0, 0 ); + + if( parser.errors( ) || parser.warnings( ) ) + { + PMErrorDialog dlg( parser.messages( ), parser.errorFlags( ) ); + // still try to insert the correct parsed objects? + success = ( dlg.exec( ) == QDialog::Accepted ); + } + if( success ) + { + PMObject* obj = list.first( ); + if( obj ) + { + if( obj->type( ) == "Scene" ) + m_pScene = ( PMScene* ) obj; + else + success = false; + } + else + success = false; + } + } + else + success = false; + + if( !success ) + { + m_url = KURL( ); + newDocument( ); + } + + m_pScene->setReadOnly( !isReadWrite( ) ); + if( !isReadWrite( ) ) + disableReadWriteActions( ); + m_bCameraListUpToDate = false; + + emit refresh( ); + updateRenderModes( ); + updateVisibilityLevel( ); + slotObjectChanged( m_pScene, PMCNewSelection, this ); + + if( dev ) + delete dev; + + return success; +} + +bool PMPart::saveFile( ) +{ + bool success = false; + + QIODevice* dev = KFilterDev::deviceForFile( m_file, "application/x-gzip" ); + if( dev && dev->open( IO_WriteOnly ) ) + { + QDomDocument doc( "KPOVMODELER" ); + QDomElement e = ( ( PMObject* )m_pScene)->serialize( doc ); + doc.appendChild( e ); + + QTextStream str( dev ); + str << doc; + dev->close( ); + setModified( false ); + success = true; + } + + if( dev ) + delete dev; + + return success; +} + +bool PMPart::exportPovray( const KURL& url ) +{ + KTempFile* tempFile = 0; + QFile* file = 0; + bool ok = true; + + if( !url.isValid( ) ) + return false; + + if( url.isLocalFile( ) ) + { + // Local file + file = new QFile( url.path( ) ); + if( !file->open( IO_WriteOnly ) ) + ok = false; + } + else + { + // Remote file + // provide a temp file + tempFile = new KTempFile( ); + if( tempFile->status( ) != 0 ) + ok = false; + else + file = tempFile->file( ); + } + + if( ok ) + { + PMPovray35Format format; + PMSerializer* dev = format.newSerializer( file ); + dev->serialize( m_pScene ); + delete dev; + + if( tempFile ) + { + tempFile->close( ); + ok = KIO::NetAccess::upload( tempFile->name( ), url, (QWidget*) 0 ); + tempFile->unlink( ); + file = 0; + } + else + file->close( ); + } + + delete file; + delete tempFile; + + return ok; +} + +QString PMPart::activeObjectName( ) +{ + QString result = ""; + PMObject* tmpObj; + PMObject* testSib; + int idx = 0; + + tmpObj = activeObject( ); + while( tmpObj != m_pScene && tmpObj ) + { + // count previous siblings of the same type (for array like entries) + testSib = tmpObj; + while( ( testSib = testSib->prevSibling( ) ) ) + if( testSib->type( ) == tmpObj->type( ) ) + idx++; + + // prepend to result + if( idx != 0 ) + result = tmpObj->type( ) + "[" + QString::number( idx ) + "]/" + result; + else + result = tmpObj->type( ) + "/" + result; + + // go up in the scene + tmpObj = tmpObj->parent( ); + idx = 0; + } + + // Make the object name an absolute name + result = "/" + result; + + return result; +} + +bool PMPart::setActiveObject( const QString& name ) +{ + PMObject* tmpObj; + PMObject* tmpSibling; + int pos, siblingIndex, objIndex, firstBracket, lastBracket; + QString objPath; + QString pathElem; + + // check if it's a absolute object name + if( name[0] == '/' ) + { + tmpObj = m_pScene; + objPath = name.mid( 1 ); // clear that first character + } + else + tmpObj = activeObject( ); + + // get the first element + pos = objPath.find( '/' ); + if( pos != -1 ) + { + pathElem = objPath.mid( 0, pos ); + objPath = objPath.mid( pos + 1 ); + } + else + { + pathElem = objPath; + objPath = QString::null; + } + + while( !pathElem.isNull( ) ) + { + if( !pathElem.isEmpty( ) ) + { + // Special treatment for brackets + firstBracket = pathElem.find( '[' ); + if( firstBracket != -1 ) + { + lastBracket = pathElem.findRev( ']' ); + objIndex = pathElem.mid( firstBracket + 1, lastBracket - firstBracket - 1).toInt( ); + pathElem = pathElem.left( firstBracket ); + } + else + objIndex = 0; + + // Iterate the children for this element. We stop when there are no more siblings + // or the object is of the correct type and it's index count is also correct + siblingIndex = 0; + tmpSibling = tmpObj->firstChild( ); + for( ; tmpSibling && ( tmpSibling->type( ) != pathElem || siblingIndex != objIndex ); + tmpSibling = tmpSibling->nextSibling( ) ) + { + // Found an object of the type we are looking for + if( tmpSibling->type( ) == pathElem ) + siblingIndex++; + } + if( tmpSibling ) + tmpObj = tmpSibling; + else + // No correct sibling + return false; + + } + + // Get the next element + pos = objPath.find( '/' ); + if( pos != -1 ) + { + pathElem = objPath.mid( 0, pos ); + objPath = objPath.mid( pos + 1 ); + } + else + { + pathElem = objPath; + objPath = QString::null; + } + } + if( tmpObj ) + { + slotObjectChanged( tmpObj, PMCNewSelection, this ); + return true; + } + else + return false; +} + +QStringList PMPart::getProperties( ) +{ + PMObject* curObj = activeObject( ); + + // Ensure that there is an active object + if( !curObj ) + return QStringList( ); + + return curObj->properties( ); +} + +bool PMPart::setProperty( const QString& name, const PMVariant& value ) +{ + PMObject* curObj = activeObject( ); + + // Ensure that there is an active object + if( !curObj ) + return false; + + curObj->setProperty( name, value ); + slotObjectChanged( curObj, PMCNewSelection, this ); + return true; +} + +bool PMPart::setProperty( const QString& name, const QString& value ) +{ + PMObject* curObj = activeObject( ); + PMVariant variant; + + // Ensure that there is an active object + if( !curObj ) + return false; + + variant.fromString( curObj->property( name ).dataType( ), value ); + curObj->setProperty( name, variant ); + slotObjectChanged( curObj, PMCNewSelection, this ); + return true; +} + +const PMVariant PMPart::getProperty( const QString& name ) +{ + PMObject* curObj = activeObject( ); + + // Ensure that there is an active object + if( !curObj ) + return PMVariant( ); + + return curObj->property( name ); +} + +const QString PMPart::getPropertyStr( const QString& name ) +{ + PMObject* curObj = activeObject( ); + + // Ensure that there is an active object + if( !curObj ) + return PMVariant( ).asString( ); + + return curObj->property( name ).asString( ); +} + +const PMObjectList& PMPart::selectedObjects( ) +{ + uint numObjects = m_selectedObjects.count( ); + uint numOrdered = 0; + bool stop = false; + + PMObject* tmp; + QPtrStack stack; + + if( !m_sortedListUpToDate ) + { + m_sortedSelectedObjects.clear( ); + + if( numObjects == 1 ) + m_sortedSelectedObjects.append( m_selectedObjects.first( ) ); + else if( numObjects > 1 ) + { + tmp = m_pScene; + do + { + if( !tmp ) + { + if( !stack.isEmpty( ) ) + { + tmp = stack.pop( ); + if( tmp == m_pScene ) + stop = true; + else + tmp = tmp->nextSibling( ); + } + else + stop = true; + } + else if( tmp->isSelected( ) ) + { + m_sortedSelectedObjects.append( tmp ); + numOrdered++; + tmp = tmp->nextSibling( ); + } + else if( tmp->selectedChildren( ) > 0 ) + { + stack.push( tmp ); + tmp = tmp->firstChild( ); + } + else + { + tmp = tmp->nextSibling( ); + } + } + while( !stop && ( numOrdered < numObjects ) ); + } + m_sortedListUpToDate = true; + } + + return m_sortedSelectedObjects; +} + +int PMPart::whereToInsert( PMObject* obj, const PMObjectList& list ) +{ + // if you change this function, change + // whereToInsert( PMObject* obj, const QStringList& ), too + + int canInsertAsFirstChild = 0; + int canInsertAsLastChild = 0; + int canInsertAsSibling = 0; + + int insertAs = 0; + int insertPossibilities = 0; + + if( !obj->isReadOnly( ) ) + { + canInsertAsFirstChild = obj->canInsert( list, 0 ); + if( obj->lastChild( ) ) + canInsertAsLastChild = obj->canInsert( list, obj->lastChild( ) ); + + if( canInsertAsFirstChild > 0 ) + { + // some objects can be inserted as child + insertAs |= PMInsertPopup::PMIFirstChild; + insertPossibilities++; + } + if( canInsertAsLastChild > 0 ) + { + insertAs |= PMInsertPopup::PMILastChild; + insertPossibilities++; + } + } + + if( obj->parent( ) ) + { + PMObject* p = obj->parent( ); + if( !p->isReadOnly( ) ) + { + canInsertAsSibling = p->canInsert( list, obj ); + if( canInsertAsSibling > 0 ) + { + // some objects can be inserted as siblings + insertAs |= PMInsertPopup::PMISibling; + insertPossibilities++; + } + } + } + + if( insertPossibilities > 1 ) + { + int count = ( int ) list.count( ); + // more than one possibilities, ask user + insertAs = PMInsertPopup::choosePlace( + widget( ), count > 1, insertAs, + canInsertAsFirstChild == count, + canInsertAsLastChild == count, + canInsertAsSibling == count ); + } + else if( insertPossibilities == 0 ) + insertAs = PMInsertPopup::PMIFirstChild; + return insertAs; +} + +int PMPart::whereToInsert( PMObject* obj, const QStringList& list ) +{ + // if you change this function, change + // whereToInsert( PMObject* obj, const PMObjectList ), too + + int canInsertAsFirstChild = 0; + int canInsertAsLastChild = 0; + int canInsertAsSibling = 0; + + int insertAs = 0; + int insertPossibilities = 0; + + if( !obj->isReadOnly( ) ) + { + canInsertAsFirstChild = obj->canInsert( list, 0 ); + if( obj->lastChild( ) ) + canInsertAsLastChild = obj->canInsert( list, obj->lastChild( ) ); + + if( canInsertAsFirstChild > 0 ) + { + // some objects can be inserted as child + insertAs |= PMInsertPopup::PMIFirstChild; + insertPossibilities++; + } + if( canInsertAsLastChild > 0 ) + { + insertAs |= PMInsertPopup::PMILastChild; + insertPossibilities++; + } + } + + if( obj->parent( ) ) + { + PMObject* p = obj->parent( ); + if( !p->isReadOnly( ) ) + { + canInsertAsSibling = p->canInsert( list, obj ); + if( canInsertAsSibling > 0 ) + { + // some objects can be inserted as siblings + insertAs |= PMInsertPopup::PMISibling; + insertPossibilities++; + } + } + } + + if( insertPossibilities > 1 ) + { + int count = ( int ) list.count( ); + // more than one possibilities, ask user + insertAs = PMInsertPopup::choosePlace( + widget( ), count > 1, insertAs, + canInsertAsFirstChild == count, + canInsertAsLastChild == count, + canInsertAsSibling == count ); + } + else if( insertPossibilities == 0 ) + insertAs = PMInsertPopup::PMIFirstChild; + return insertAs; +} + +int PMPart::whereToInsert( PMObject* obj ) +{ + int insertAs = 0; + int insertPossibilities = 0; + + if( obj->parent( ) ) + { + insertAs |= PMInsertPopup::PMISibling; + insertPossibilities++; + } + if( obj->isA( "CompositeObject" ) ) + { + insertAs |= PMInsertPopup::PMIFirstChild; + insertPossibilities++; + if( obj->firstChild( ) ) + { + insertAs |= PMInsertPopup::PMILastChild; + insertPossibilities++; + } + } + if( insertAs && ( insertPossibilities > 1 ) ) + insertAs = PMInsertPopup::choosePlace( widget( ), true, insertAs ); + + return insertAs; +} + +void PMPart::slotFileImport( ) +{ + QString fileName; + PMIOFormat* selectedFormat = 0; + + fileName = PMFileDialog::getImportFileName( 0, this, selectedFormat ); + + if( !fileName.isEmpty( ) && selectedFormat ) + { + QFile file( fileName ); + if( file.open( IO_ReadOnly ) ) + { + PMParser* newParser = selectedFormat->newParser( this, &file ); + if( newParser ) + { + if( m_pActiveObject ) + insertFromParser( i18n( "Import %1" ).arg( selectedFormat->description( ) ), + newParser, m_pActiveObject ); + else + insertFromParser( i18n( "Import %1" ).arg( selectedFormat->description( ) ), + newParser, m_pScene ); + delete newParser; + } + } + else + { + KMessageBox::error( 0, tr( "Couldn't open the selected file\n" + "Permission denied!" ) ); + } + } +} + +void PMPart::slotFileExport( ) +{ + emit aboutToSave( ); + + QString fileName, filter; + PMIOFormat* selectedFormat = 0; + + fileName = PMFileDialog::getExportFileName( 0, this, selectedFormat, filter ); + + if( !fileName.isEmpty( ) && selectedFormat ) + { + QByteArray baData; + QBuffer buffer( baData ); + buffer.open( IO_WriteOnly ); + + PMSerializer* newSer = selectedFormat->newSerializer( &buffer ); + if( newSer ) + { + newSer->serialize( m_pScene ); + newSer->close( ); + bool success = !( newSer->warnings( ) || newSer->errors( ) ); + + if( !success ) + { + // there were errors, display them + PMErrorDialog dlg( newSer->messages( ), newSer->errorFlags( ) ); + // still try to export? + success = ( dlg.exec( ) == QDialog::Accepted ); + } + if( success ) + { + QFileInfo info( fileName ); + if( info.extension( ).isEmpty( ) ) + fileName += filter.right( filter.length( ) - 1 ); // remove '*' + + QFile file( fileName ); + if( file.open( IO_WriteOnly ) ) + { + file.writeBlock( baData ); + file.close( ); + } + else + { + KMessageBox::error( 0, tr( "Couldn't export to the selected file\n" + "Permission denied!" ) ); + } + } + + delete newSer; + } + } +} + +void PMPart::slotEditCut( ) +{ + emit setStatusBarText( i18n( "Cutting selection..." ) ); + + const PMObjectList& sortedList = selectedObjects( ); + + if( sortedList.count( ) > 0 ) + { + QApplication::clipboard( )->setData( new PMObjectDrag( this, sortedList ) ); + removeSelection( i18n( "Cut" ) ); + } + + emit setStatusBarText( "" ); +} + +void PMPart::slotEditDelete( ) +{ + emit setStatusBarText( i18n( "Deleting selection..." ) ); + + removeSelection( i18n( "Delete" ) ); + + emit setStatusBarText( "" ); +} + +void PMPart::slotEditCopy( ) +{ + emit setStatusBarText( i18n( "Copying selection to clipboard..." ) ); + const PMObjectList& sortedList = selectedObjects( ); + + if( sortedList.count( ) > 0 ) + QApplication::clipboard( )->setData( new PMObjectDrag( this, sortedList ) ); + + emit setStatusBarText( "" ); +} + +bool PMPart::dragMoveSelectionTo( PMObject* obj ) +{ + if( obj == 0 ) + { + return removeSelection( i18n( "Drag" ) ); + } + else + { + const PMObjectList& sortedList = selectedObjects( ); + PMMoveCommand* command = 0; + int insertAs = whereToInsert( obj, sortedList ); + + if( insertAs > 0 ) + { + PMObject* hlp; + bool stop; + + switch( insertAs ) + { + case PMInsertPopup::PMIFirstChild: + command = new PMMoveCommand( sortedList, obj, 0 ); + break; + case PMInsertPopup::PMILastChild: + hlp = obj->lastChild( ); + stop = false; + + while( hlp && !stop ) + { + if( hlp->isSelected( ) ) + hlp = hlp->prevSibling( ); + else + stop = true; + } + command = new PMMoveCommand( sortedList, obj, hlp ); + break; + case PMInsertPopup::PMISibling: + command = new PMMoveCommand( sortedList, obj->parent( ), obj ); + break; + } + } + if( command ) + { + command->setText( i18n( "Drag" ) ); + return executeCommand( command ); + } + } + return false; +} + +bool PMPart::removeSelection( const QString& type ) +{ + PMDeleteCommand* cmd = 0; + const PMObjectList& sortedList = selectedObjects( ); + + if( sortedList.count( ) > 0 ) + { + cmd = new PMDeleteCommand( sortedList ); + cmd->setText( type ); + return executeCommand( cmd ); + } + return false; +} + +bool PMPart::drop( PMObject* obj, QMimeSource* mime ) +{ + return pasteOrDrop( i18n( "Drop" ), mime, obj ); +} + +void PMPart::slotEditPaste( ) +{ + emit setStatusBarText( i18n( "Inserting clipboard contents..." ) ); + + pasteOrDrop( i18n( "Paste" ), qApp->clipboard( )->data( ), + m_pActiveObject ); + + emit setStatusBarText( "" ); +} + +bool PMPart::pasteOrDrop( const QString& type, QMimeSource* mime, PMObject* obj ) +{ + bool success = false; + + if( mime && obj) + { + PMParser* parser = PMObjectDrag::newParser( mime, this ); + + if( parser ) + success = insertFromParser( type, parser, obj ); + } + return success; +} + +bool PMPart::insertFromParser( const QString& type, PMParser* parser, + PMObject* obj ) +{ + PMObjectList list; + bool success = true; + int insertAs = 0; + PMAddCommand* command = 0; + + // try to parse + if( parser->canQuickParse( ) ) + { + QStringList types; + parser->quickParse( types ); + + success = !( parser->warnings( ) || parser->errors( ) ); + + if( !success ) + { + // there were errors, display them + PMErrorDialog dlg( parser->messages( ), parser->errorFlags( ) ); + // still try to insert the correct parsed objects? + success = ( dlg.exec( ) == QDialog::Accepted ); + } + if( success && ( types.count( ) > 0 ) ) + insertAs = whereToInsert( obj, types ); + } + else + insertAs = whereToInsert( obj ); + + if( success && insertAs ) + { + PMObject* parent = 0; + PMObject* after = 0; + + switch( insertAs ) + { + case PMInsertPopup::PMIFirstChild: + parent = obj; + after = 0; + break; + case PMInsertPopup::PMILastChild: + parent = obj; + after = obj->lastChild( ); + break; + case PMInsertPopup::PMISibling: + parent = obj->parent( ); + after = obj; + break; + default: + parent = obj; + after = 0; + break; + } + + parser->parse( &list, parent, after ); + success = !( parser->warnings( ) || parser->errors( ) ); + + if( !success ) + { + // there were errors, display them + PMErrorDialog dlg( parser->messages( ), parser->errorFlags( ) ); + // still try to insert the correct parsed objects? + success = ( dlg.exec( ) == QDialog::Accepted ); + } + + if( list.count( ) > 0 ) + { + if( success ) + { + // parsing was successful + command = new PMAddCommand( list, parent, after ); + + command->setText( type ); + success = executeCommand( command ); + } + else + { + // parsed objects will not be inserted + // remove all links + PMObjectListIterator it( list ); + PMDeclare* decl = 0; + + for( ; it.current( ); ++it ) + { + PMRecursiveObjectIterator rit( it.current( ) ); + for( ; rit.current( ); ++rit ) + { + decl = rit.current( )->linkedObject( ); + if( decl ) + decl->removeLinkedObject( rit.current( ) ); + } + } + } + } + } + if( !command ) + { + // delete all parsed objects + list.setAutoDelete( true ); + list.clear( ); + } + + return success && insertAs; +} + +void PMPart::slotEditUndo( ) +{ + emit setStatusBarText( i18n( "Undo last change..." ) ); + m_pNewSelection = 0; + m_updateNewObjectActions = false; + + m_commandManager.undo( ); + + if( m_pNewSelection ) + slotObjectChanged( m_pNewSelection, PMCNewSelection, this ); + if( !isModified( ) ) + setModified( true ); + if( m_updateNewObjectActions ) + updateNewObjectActions( ); + + emit setStatusBarText( "" ); +} + +void PMPart::slotEditRedo( ) +{ + emit setStatusBarText( i18n( "Redo last change..." ) ); + m_pNewSelection = 0; + m_updateNewObjectActions = false; + + m_commandManager.redo( ); + if( m_pNewSelection ) + slotObjectChanged( m_pNewSelection, PMCNewSelection, this ); + if( !isModified( ) ) + setModified( true ); + if( m_updateNewObjectActions ) + updateNewObjectActions( ); + + emit setStatusBarText( "" ); +} + +bool PMPart::executeCommand( PMCommand* cmd ) +{ + m_pNewSelection = 0; + m_numAddedObjects = 0; + m_numInsertErrors = 0; + m_insertErrorDetails.clear( ); + m_updateNewObjectActions = false; + + if( isReadWrite( ) && cmd ) + { + bool execute = true; + int flags = cmd->errorFlags( this ); + + if( flags ) + { + PMErrorDialog dlg( cmd->messages( ), flags ); + execute = ( dlg.exec( ) == QDialog::Accepted ); + } + + if( execute ) + { + m_commandManager.execute( cmd ); + if( m_pNewSelection ) + slotObjectChanged( m_pNewSelection, PMCNewSelection, this ); + if( !isModified( ) ) + setModified( true ); + + if( m_numInsertErrors > 0 ) + { + m_insertErrorDetails.sort( ); + PMInsertErrorDialog dlg( m_numAddedObjects, m_numInsertErrors, + m_insertErrorDetails ); + dlg.exec( ); + } + if( m_updateNewObjectActions ) + updateNewObjectActions( ); + + return true; + } + } + + delete cmd; + return false; +} + +void PMPart::slotObjectChanged( PMObject* obj, const int m, + QObject* sender ) +{ + int mode = m; + bool selectionChanged = false; + bool changeControlPoints = false; + PMObject* oldActive = m_pActiveObject; + + if( mode & PMCNewSelection ) + { + if( !obj ) + { + clearSelection( ); + selectionChanged = true; + m_pActiveObject = 0; + } + else + { + clearSelection( ); + obj->setSelected( true ); + m_selectedObjects.append( obj ); + selectionChanged = true; + m_pActiveObject = obj; + } + } + else if( ( mode & PMCSelected ) && !obj->isSelected( ) ) + { + if( obj->isSelectable( ) ) + { + if( obj->selectedChildren( ) > 0 ) + { + QPtrStack stack; + PMObject* tmp = obj->firstChild( ); + bool stop = false; + + do + { + if( !tmp ) + { + if( !stack.isEmpty( ) ) + { + tmp = stack.pop( ); + if( tmp == obj ) + stop = true; + else + tmp = tmp->nextSibling( ); + } + else + stop = true; + } + else if( tmp->isSelected( ) ) + { + tmp->setSelected( false ); + m_selectedObjects.removeRef( tmp ); + emit objectChanged( tmp, PMCDeselected, this ); + tmp = tmp->nextSibling( ); + } + else if( tmp->selectedChildren( ) > 0 ) + { + stack.push( tmp ); + tmp = tmp->firstChild( ); + } + else + { + tmp = tmp->nextSibling( ); + } + } + while( !stop ); + } + + obj->setSelected( true ); + m_selectedObjects.append( obj ); + selectionChanged = true; + m_sortedListUpToDate = false; + m_sortedSelectedObjects.clear( ); + m_pActiveObject = 0; + } + else + { + kdError( PMArea ) << "(PMPart::slotObjectChanged) object is not selectable!" << "\n"; + mode = mode & ( ~( PMCSelected | PMCNewSelection ) ); + } + } + else if( mode & PMCDeselected ) + { + // no problems here + m_selectedObjects.removeRef( obj ); + obj->setSelected( false ); + m_sortedListUpToDate = false; + m_sortedSelectedObjects.clear( ); + selectionChanged = true; + m_pActiveObject = 0; + } + + if( mode & PMCRemove ) + { + if( obj->parent( ) ) + if( obj->parent( ) == m_pActiveObject ) + m_updateNewObjectActions = true; + if( m_pNewSelection == obj ) + { + if( obj->nextSibling( ) ) + m_pNewSelection = obj->nextSibling( ); + else if( obj->prevSibling( ) ) + m_pNewSelection = obj->nextSibling( ); + else if( obj->parent( ) ) + m_pNewSelection = obj->parent( ); + else + m_pNewSelection = 0; + } + if( m_selectedObjects.containsRef( obj ) ) + { + m_selectedObjects.removeRef( obj ); + if( m_selectedObjects.isEmpty( ) ) + { + if( obj->nextSibling( ) ) + m_pNewSelection = obj->nextSibling( ); + else if( obj->prevSibling( ) ) + m_pNewSelection = obj->prevSibling( ); + else if( obj->parent( ) ) + m_pNewSelection = obj->parent( ); + else + m_pNewSelection = 0; + } + m_sortedListUpToDate = false; + m_sortedSelectedObjects.clear( ); + selectionChanged = true; + } + if( m_pActiveObject == obj ) + m_pActiveObject = 0; + + if( obj->isA( "Declare" ) ) + { + PMDeclare* decl = ( PMDeclare* ) obj; + m_pSymbolTable->remove( decl->id( ) ); + } + + if( obj->type( ) == "Camera" ) + m_cameras.removeRef( ( PMCamera* ) obj ); + } + + if( mode & PMCAdd ) + { + if( !( mode & PMCInsertError ) ) + { + m_pNewSelection = obj; + if( obj->isA( "Declare" ) ) + { + PMDeclare* decl = ( PMDeclare* ) obj; + PMSymbol* s = m_pSymbolTable->find( decl->id( ) ); + if( !s ) + m_pSymbolTable->insert( decl->id( ), + new PMSymbol( decl->id( ), decl ) ); + } + if( obj->type( ) == "Camera" ) + m_bCameraListUpToDate = false; + } + if( obj->parent( ) ) + if( obj->parent( ) == m_pActiveObject ) + m_updateNewObjectActions = true; + m_numAddedObjects++; + } + + if( mode & PMCData ) + { + m_updateNewObjectActions = true; + } + + if( mode & PMCViewStructure ) + { + changeControlPoints = true; + } + + if( mode & PMCInsertError ) + { + m_numInsertErrors++; + QString detail; + detail = obj->description( ) + QString( " " ) + obj->name( ); + m_insertErrorDetails.append( detail ); + + if( obj->isA( "Declare" ) ) + { + PMDeclare* decl = ( PMDeclare* ) obj; + m_pSymbolTable->remove( decl->id( ) ); + } + } + + if( selectionChanged ) + { + m_sortedListUpToDate = false; + m_sortedSelectedObjects.clear( ); + + int c = m_selectedObjects.count( ); + + if( m_pScene->isSelected( ) ) + c = m_pScene->countChildren( ); + + m_pCopyAction->setEnabled( c > 0 ); + + if( isReadWrite( ) ) + { + m_pCutAction->setEnabled( c > 0 ); + m_pDeleteAction->setEnabled( c > 0 ); + m_pPasteAction->setEnabled( m_pActiveObject && m_canDecode ); + updateNewObjectActions( ); + } + } + + if( ( oldActive != m_pActiveObject ) || changeControlPoints ) + { + updateControlPoints( oldActive ); + emit objectChanged( m_pActiveObject, PMCNewControlPoints, this ); + mode |= ( PMCNewControlPoints | PMCControlPointSelection ); + } + + emit objectChanged( obj, mode, sender ); +} + +void PMPart::slotIDChanged( PMObject* obj, const QString& oldID ) +{ + if( obj->isA( "Declare" ) ) + { + PMDeclare* d = ( PMDeclare* ) obj; + PMSymbol* s = m_pSymbolTable->find( oldID ); + if( s ) + { + if( s->type( ) == PMSymbol::Object ) + { + if( s->object( ) == obj ) + { + m_pSymbolTable->take( oldID ); + s->setId( d->id( ) ); + m_pSymbolTable->insert( s->id( ), s ); + } + else + kdError( PMArea ) << "PMPart::slotIDChanged: Symbol " + << oldID << " points to wrong object.\n"; + } + else + kdError( PMArea ) << "PMPart::slotIDChanged: Symbol " + << oldID << " has wrong type.\n"; + } + else + kdError( PMArea ) << "PMPart::slotIDChanged: Symbol " + << oldID << " not found.\n"; + } +} + +void PMPart::slotNewObject( PMObject* newObject, int insertAs ) +{ + PMObjectList list; + list.append( newObject ); + PMCommand* command = 0; + + if( m_pActiveObject ) + { + // If no position was specified ask the user + if( insertAs <= 0 ) + insertAs = whereToInsert( m_pActiveObject, list ); + // If either through a parameter or by user action a position was selected + if( insertAs > 0 ) + { + // insert the object in the position indicated + switch( insertAs ) + { + case PMInsertPopup::PMIFirstChild: + command = new PMAddCommand( list, m_pActiveObject, 0 ); + break; + case PMInsertPopup::PMILastChild: + command = new PMAddCommand( list, m_pActiveObject, + m_pActiveObject->lastChild( ) ); + break; + case PMInsertPopup::PMISibling: + command = new PMAddCommand( list, + m_pActiveObject->parent( ), + m_pActiveObject ); + break; + default: + command = new PMAddCommand( list, m_pActiveObject, 0 ); + break; + } + executeCommand( command ); + } + else + { + list.clear( ); + delete newObject; + } + } + else + { + list.clear( ); + delete newObject; + } +} + +void PMPart::slotNewObject( const QString& type ) +{ + PMObject* newObject = m_pPrototypeManager->newObject( type ); + if( newObject ) + slotNewObject( newObject ); +} + +void PMPart::slotNewObject( const QString& type, const QString& pos ) +{ + PMObject* newObject = m_pPrototypeManager->newObject( type ); + if( newObject ) + { + if( pos == "FirstChild" ) + slotNewObject( newObject, PMInsertPopup::PMIFirstChild ); + else if( pos == "LastChild" ) + slotNewObject( newObject, PMInsertPopup::PMILastChild ); + else if( pos == "Sibling" ) + slotNewObject( newObject, PMInsertPopup::PMISibling ); + else + slotNewObject( newObject ); + } +} + +QStringList PMPart::getObjectTypes( ) +{ + QStringList result; + QPtrListIterator it = m_pPrototypeManager->prototypeIterator( ); + + for( ; it.current( ); ++it ) + { + result.append( it.current( )->className( ) ); + } + return result; +} + +void PMPart::slotNewTransformedObject( PMObject* o ) +{ + if( o ) + { + if( o->canInsert( QString( "Scale" ), o->lastChild( ) ) ) + o->appendChild( new PMScale( this ) ); + if( o->canInsert( QString( "Rotate" ), o->lastChild( ) ) ) + o->appendChild( new PMRotate( this ) ); + if( o->canInsert( QString( "Translate" ), o->lastChild( ) ) ) + o->appendChild( new PMTranslate( this ) ); + slotNewObject( o ); + } +} + +void PMPart::slotNewGlobalSettings( ) +{ + slotNewObject( new PMGlobalSettings( this ) ); +} + +void PMPart::slotNewSkySphere( ) +{ + slotNewObject( new PMSkySphere( this ) ); +} + +void PMPart::slotNewRainbow( ) +{ + slotNewObject( new PMRainbow( this ) ); +} + +void PMPart::slotNewFog( ) +{ + slotNewObject( new PMFog( this ) ); +} + +void PMPart::slotNewInterior( ) +{ + slotNewObject( new PMInterior( this ) ); +} + +void PMPart::slotNewMedia( ) +{ + slotNewObject( new PMMedia( this ) ); +} + +void PMPart::slotNewDensity( ) +{ + slotNewObject( new PMDensity( this ) ); +} + +void PMPart::slotNewMaterial( ) +{ + slotNewObject( new PMMaterial( this ) ); +} + +void PMPart::slotNewBox( ) +{ + slotNewTransformedObject( new PMBox( this ) ); +} + +void PMPart::slotNewSphere( ) +{ + slotNewTransformedObject( new PMSphere( this ) ); +} + +void PMPart::slotNewCylinder( ) +{ + slotNewTransformedObject( new PMCylinder( this ) ); +} + +void PMPart::slotNewPlane( ) +{ + slotNewTransformedObject( new PMPlane( this ) ); +} + +void PMPart::slotNewPolynom( ) +{ + slotNewTransformedObject( new PMPolynom( this ) ); +} + +void PMPart::slotNewCone( ) +{ + slotNewTransformedObject( new PMCone( this ) ); +} + +void PMPart::slotNewTorus( ) +{ + slotNewTransformedObject( new PMTorus( this ) ); +} + +void PMPart::slotNewLathe( ) +{ + slotNewTransformedObject( new PMLathe( this ) ); +} + +void PMPart::slotNewPrism( ) +{ + slotNewTransformedObject( new PMPrism( this ) ); +} + +void PMPart::slotNewSurfaceOfRevolution( ) +{ + slotNewTransformedObject( new PMSurfaceOfRevolution( this ) ); +} + +void PMPart::slotNewSuperquadricEllipsoid( ) +{ + slotNewTransformedObject( new PMSuperquadricEllipsoid( this ) ); +} + +void PMPart::slotNewJuliaFractal( ) +{ + slotNewTransformedObject( new PMJuliaFractal( this ) ); +} + +void PMPart::slotNewHeightField( ) +{ + slotNewTransformedObject( new PMHeightField( this ) ); +} + +void PMPart::slotNewText( ) +{ + slotNewTransformedObject( new PMText( this ) ); +} + +void PMPart::slotNewBlob( ) +{ + slotNewTransformedObject( new PMBlob( this ) ); +} + +void PMPart::slotNewBlobSphere( ) +{ + slotNewObject( new PMBlobSphere( this ) ); +} + +void PMPart::slotNewBlobCylinder( ) +{ + slotNewObject( new PMBlobCylinder( this ) ); +} + +void PMPart::slotNewDeclare( ) +{ + PMDeclare* obj = new PMDeclare( this ); + m_pSymbolTable->findNewID( i18n( "Declare" ), obj ); + slotNewObject( obj ); +} + +void PMPart::slotNewObjectLink( ) +{ + slotNewTransformedObject( new PMObjectLink( this ) ); +} + +void PMPart::slotNewUnion( ) +{ + slotNewObject( new PMCSG( this, PMCSG::CSGUnion ) ); +} + +void PMPart::slotNewDifference( ) +{ + slotNewObject( new PMCSG( this, PMCSG::CSGDifference ) ); +} + +void PMPart::slotNewIntersection( ) +{ + slotNewObject( new PMCSG( this, PMCSG::CSGIntersection ) ); +} + +void PMPart::slotNewMerge( ) +{ + slotNewObject( new PMCSG( this, PMCSG::CSGMerge ) ); +} + +void PMPart::slotNewBoundedBy( ) +{ + slotNewObject( new PMBoundedBy( this ) ); +} + +void PMPart::slotNewClippedBy( ) +{ + slotNewObject( new PMClippedBy( this ) ); +} + +void PMPart::slotNewLight( ) +{ + slotNewObject( new PMLight( this ) ); +} + +void PMPart::slotNewLooksLike( ) +{ + slotNewObject( new PMLooksLike( this ) ); +} + +void PMPart::slotNewProjectedThrough( ) +{ + slotNewObject( new PMProjectedThrough( this ) ); +} + +void PMPart::slotNewDisc( ) +{ + slotNewTransformedObject( new PMDisc( this ) ); +} + +void PMPart::slotNewBicubicPatch( ) +{ + slotNewTransformedObject( new PMBicubicPatch( this ) ); +} + +void PMPart::slotNewTriangle( ) +{ + slotNewObject( new PMTriangle( this ) ); +} + +void PMPart::slotNewCamera( ) +{ + PMCamera* c = new PMCamera( this ); + c->setAngle( 45.0 ); + c->setLocation( PMVector( 5.0, 5.0, -5.0 ) ); + c->setLookAt( PMVector( 0.0, 0.0, 0.0 ) ); + + slotNewObject( c ); +} + +void PMPart::slotNewTexture( ) +{ + slotNewObject( new PMTexture( this ) ); +} + +void PMPart::slotNewPigment( ) +{ + slotNewObject( new PMPigment( this ) ); +} + +void PMPart::slotNewNormal( ) +{ + slotNewObject( new PMNormal( this ) ); +} + +void PMPart::slotNewSolidColor( ) +{ + slotNewObject( new PMSolidColor( this ) ); +} + +void PMPart::slotNewTextureList( ) +{ + slotNewObject( new PMTextureList( this ) ); +} + +void PMPart::slotNewColorList( ) +{ + slotNewObject( new PMColorList( this ) ); +} + +void PMPart::slotNewPigmentList( ) +{ + slotNewObject( new PMPigmentList( this ) ); +} + +void PMPart::slotNewNormalList( ) +{ + slotNewObject( new PMNormalList( this ) ); +} + +void PMPart::slotNewDensityList( ) +{ + slotNewObject( new PMDensityList( this ) ); +} + +void PMPart::slotNewFinish( ) +{ + slotNewObject( new PMFinish( this ) ); +} + +void PMPart::slotNewWarp( ) +{ + slotNewObject( new PMWarp( this ) ); +} + +void PMPart::slotNewImageMap( ) +{ + slotNewObject( new PMImageMap( this ) ); +} + +void PMPart::slotNewPattern( ) +{ + slotNewObject( new PMPattern( this ) ); +} + +void PMPart::slotNewBlendMapModifiers( ) +{ + slotNewObject( new PMBlendMapModifiers( this ) ); +} + +void PMPart::slotNewTextureMap( ) +{ + slotNewObject( new PMTextureMap( this ) ); +} + +void PMPart::slotNewMaterialMap( ) +{ + slotNewObject( new PMMaterialMap( this ) ); +} + +void PMPart::slotNewColorMap( ) +{ + slotNewObject( new PMColorMap( this ) ); +} + +void PMPart::slotNewPigmentMap( ) +{ + slotNewObject( new PMPigmentMap( this ) ); +} + +void PMPart::slotNewNormalMap( ) +{ + slotNewObject( new PMNormalMap( this ) ); +} + +void PMPart::slotNewBumpMap( ) +{ + slotNewObject( new PMBumpMap( this ) ); +} + +void PMPart::slotNewSlopeMap( ) +{ + slotNewObject( new PMSlopeMap( this ) ); +} + +void PMPart::slotNewDensityMap( ) +{ + slotNewObject( new PMDensityMap( this ) ); +} + +void PMPart::slotNewSlope( ) +{ + slotNewObject( new PMSlope( this ) ); +} + +void PMPart::slotNewQuickColor( ) +{ + slotNewObject( new PMQuickColor( this ) ); +} + +void PMPart::slotNewTranslate( ) +{ + slotNewObject( new PMTranslate( this ) ); +} + +void PMPart::slotNewScale( ) +{ + slotNewObject( new PMScale( this ) ); +} + +void PMPart::slotNewRotate( ) +{ + slotNewObject( new PMRotate( this ) ); +} + +void PMPart::slotNewMatrix( ) +{ + slotNewObject( new PMPovrayMatrix( this ) ); +} + +void PMPart::slotNewComment( ) +{ + slotNewObject( new PMComment( this ) ); +} + +void PMPart::slotNewRaw( ) +{ + slotNewObject( new PMRaw( this ) ); +} + +// POV-Ray 3.5 objects + +void PMPart::slotNewIsoSurface( ) +{ + slotNewObject( new PMIsoSurface( this ) ); +} + +void PMPart::slotNewRadiosity( ) +{ + slotNewObject( new PMRadiosity( this ) ); +} + +void PMPart::slotNewGlobalPhotons( ) +{ + slotNewObject( new PMGlobalPhotons( this ) ); +} + +void PMPart::slotNewPhotons( ) +{ + slotNewObject( new PMPhotons( this ) ); +} + +void PMPart::slotNewLightGroup( ) +{ + slotNewObject( new PMLightGroup( this ) ); +} + +void PMPart::slotNewInteriorTexture( ) +{ + slotNewObject( new PMInteriorTexture( this ) ); +} + +void PMPart::slotNewSphereSweep( ) +{ + slotNewObject( new PMSphereSweep( this ) ); +} + +void PMPart::slotNewMesh( ) +{ + slotNewObject( new PMMesh( this ) ); +} + +void PMPart::slotSearchLibraryObject( ) +{ + PMLibraryObjectSearch* aux = new PMLibraryObjectSearch( NULL ); + aux->show( ); +} + +void PMPart::slotClipboardDataChanged( ) +{ + if( isReadWrite( ) ) + { + m_canDecode = PMObjectDrag::canDecode( qApp->clipboard( )->data( ), this ); + m_pPasteAction->setEnabled( m_canDecode && m_pActiveObject ); + } + else + m_pPasteAction->setEnabled( false ); +} + +void PMPart::clearSelection( ) +{ + PMObjectListIterator it( m_selectedObjects ); + + if( it.current( ) ) + { + if( it.current( )->nextSibling( ) ) + m_pNewSelection = it.current( )->nextSibling( ); + else if( it.current( )->prevSibling( ) ) + m_pNewSelection = it.current( )->prevSibling( ); + else if( it.current( )->parent( ) ) + m_pNewSelection = it.current( )->parent( ); + + for( ; it.current( ); ++it ) + { + it.current( )->setSelected( false ); + if( m_pNewSelection == it.current( ) ) + { + if( it.current( )->nextSibling( ) ) + m_pNewSelection = it.current( )->nextSibling( ); + else if( it.current( )->prevSibling( ) ) + m_pNewSelection = it.current( )->prevSibling( ); + else if( it.current( )->parent( ) ) + m_pNewSelection = it.current( )->parent( ); + } + } + } + + m_selectedObjects.clear( ); + m_sortedListUpToDate = true; +} + +bool PMPart::newDocument( ) +{ + deleteContents( ); + setModified( false ); + + m_pScene = new PMScene( this ); + + PMGlobalSettings* gs = new PMGlobalSettings( this ); + gs->setAssumedGamma( 1.5 ); + m_pScene->appendChild( gs ); + + PMBox* b = new PMBox( this ); + m_pScene->appendChild( b ); + PMPigment* p = new PMPigment( this ); + b->appendChild( p ); + PMSolidColor* c = new PMSolidColor( this ); + c->setColor( PMColor( 0.3, 1.0, 0.3 ) ); + p->appendChild( c ); + PMScale* s = new PMScale( this ); + b->appendChild( s ); + PMRotate* r = new PMRotate( this ); + b->appendChild( r ); + PMTranslate* t = new PMTranslate( this ); + t->setTranslation( PMVector( 0, 0.5, 0 ) ); + b->appendChild( t ); + + PMLight* l = new PMLight( this ); + l->setLocation( PMVector( 4.0, 5.0, -5.0 ) ); + m_pScene->appendChild( l ); + PMCamera* ca = new PMCamera( this ); + ca->setAngle( 45.0 ); + ca->setLocation( PMVector( 5.0, 5.0, -5.0 ) ); + ca->setLookAt( PMVector( 0.0, 0.0, 0.0 ) ); + m_pScene->appendChild( ca ); + m_bCameraListUpToDate = false; + + m_pScene->setReadOnly( !isReadWrite( ) ); + PMRenderMode* mode = new PMRenderMode( ); + mode->setDescription( i18n( "Default" ) ); + m_pScene->renderModes( )->append( mode ); + + emit refresh( ); + updateRenderModes( ); + updateVisibilityLevel( ); + slotObjectChanged( m_pScene, PMCNewSelection, this ); + + return true; +} + +void PMPart::closeDocument( ) +{ + m_url = KURL( ); +} + +void PMPart::deleteContents( ) +{ + emit clear( ); + if( isReadWrite( ) ) + m_commandManager.clear( ); + m_selectedObjects.clear( ); + m_sortedSelectedObjects.clear( ); + m_sortedListUpToDate = true; + m_pActiveObject = 0; + m_pNewSelection = 0; + + if( m_pScene ) + { + delete m_pScene; + m_pScene = 0; + } + if( m_pSymbolTable ) + delete m_pSymbolTable; + + m_pSymbolTable = new PMSymbolTable( ); + m_cameras.clear( ); + m_bCameraListUpToDate = true; +} + +void PMPart::slotUpdateUndoRedo( const QString& undo, const QString& redo ) +{ + if( isReadWrite( ) ) + { + if( m_pUndoAction ) + { + if( undo.isNull( ) ) + { + m_pUndoAction->setText( i18n( "Undo" ) ); + m_pUndoAction->setEnabled( false ); + } + else + { + m_pUndoAction->setText( i18n( "Undo" ) + " " + undo ); + m_pUndoAction->setEnabled( true ); + } + } + if( m_pRedoAction ) + { + if( redo.isNull( ) ) + { + m_pRedoAction->setText( i18n( "Redo" ) ); + m_pRedoAction->setEnabled( false ); + } + else + { + m_pRedoAction->setText( i18n( "Redo" ) + " " + redo ); + m_pRedoAction->setEnabled( true ); + } + } + } +} + +void PMPart::setScene( PMScene* scene ) +{ + deleteContents( ); + m_pScene = scene; + emit refresh( ); + slotObjectChanged( m_pScene, PMCNewSelection, this ); +} + +void PMPart::setModified( ) +{ + KParts::ReadWritePart::setModified( ); + emit modified( ); +} + +void PMPart::setModified( bool m ) +{ + KParts::ReadWritePart::setModified( m ); + emit modified( ); +} + +PMCamera* PMPart::firstCamera( ) +{ + if( !m_bCameraListUpToDate ) + updateCameraList( ); + return m_cameras.first( ); +} + +QPtrListIterator PMPart::cameras( ) +{ + if( !m_bCameraListUpToDate ) + updateCameraList( ); + return QPtrListIterator( m_cameras ); +} + +void PMPart::updateCameraList( ) +{ + m_cameras.clear( ); + PMObject* obj; + for( obj = m_pScene->firstChild( ); obj; obj = obj->nextSibling( ) ) + if( obj->type( ) == "Camera" ) + m_cameras.append( ( PMCamera* ) obj ); + m_bCameraListUpToDate = true; +} + +void PMPart::slotRender( ) +{ + PMRenderMode* m = m_pScene->renderModes( )->current( ); + if( m ) + { + emit aboutToRender( ); + + QByteArray a; + QBuffer buffer( a ); + buffer.open( IO_WriteOnly ); + PMPovray35Format format; + PMSerializer* dev = format.newSerializer( &buffer ); + dev->serialize( m_pScene ); + delete dev; + + if( !m_pPovrayWidget ) + m_pPovrayWidget = new PMPovrayWidget( ); + if( m_pPovrayWidget->render( a, *m, url( ) ) ) + { + m_pPovrayWidget->show( ); + m_pPovrayWidget->raise( ); + } + } +} + +void PMPart::slotRenderSettings( ) +{ + PMRenderModesDialog dlg( m_pScene->renderModes( ), widget( ) ); + int result = dlg.exec( ); + + if( result == QDialog::Accepted ) + { + if( isReadWrite( ) ) + setModified( true ); + updateRenderModes( ); + } +} + +void PMPart::slotViewRenderWindow( ) +{ + if( !m_pPovrayWidget ) + m_pPovrayWidget = new PMPovrayWidget( ); + m_pPovrayWidget->show( ); + m_pPovrayWidget->raise( ); +} + +void PMPart::slotRenderMode( int index ) +{ + PMRenderModeList* list = m_pScene->renderModes( ); + list->at( index ); + emit activeRenderModeChanged( ); +} + +void PMPart::updateRenderModes( ) +{ + if( m_pScene ) + { + PMRenderModeList* list = m_pScene->renderModes( ); + PMRenderModeListIterator it( *list ); + + QComboBox* box = m_pRenderComboAction->combo( ); + if( box ) + { + bool b = box->signalsBlocked( ); + box->blockSignals( true ); + box->clear( ); + + for( ; it.current( ); ++it ) + box->insertItem( it.current( )->description( ) ); + box->setCurrentItem( list->at( ) ); + box->updateGeometry( ); + + box->blockSignals( b ); + } + emit activeRenderModeChanged( ); + } +} + +void PMPart::slotRenderModeActionPlugged( ) +{ + updateRenderModes( ); +// connect( m_pRenderComboAction->combo( ), SIGNAL( activated( int ) ), +// SLOT( slotRenderMode( int ) ) ); +} + +void PMPart::slotVisibilityLevelChanged( int l ) +{ + if( m_pScene->visibilityLevel( ) != l ) + { + m_pScene->setVisibilityLevel( l ); + if( isReadWrite( ) ) + setModified( true ); + emit objectChanged( m_pScene, PMCViewStructure, this ); + } +} + +void PMPart::slotVisibilityActionPlugged( ) +{ + if( m_pVisibilityLevelAction ) + { + QSpinBox* box = m_pVisibilityLevelAction->spinBox( ); + if( box ) + { + box->setMinValue( -1000 ); + box->setMaxValue( 1000 ); + updateVisibilityLevel( ); + } + } +} + +void PMPart::updateVisibilityLevel( ) +{ + if( m_pVisibilityLevelAction ) + { + QSpinBox* box = m_pVisibilityLevelAction->spinBox( ); + if( box && m_pScene ) + { + bool sb = box->signalsBlocked( ); + box->blockSignals( true ); + box->setValue( m_pScene->visibilityLevel( ) ); + box->blockSignals( sb ); + } + } +} + +void PMPart::slotGlobalDetailLevelChanged( int level ) +{ + PMDetailObject::setGlobalDetailLevel( level + 1 ); + emit objectChanged( m_pScene, PMCViewStructure, this ); +} + +void PMPart::updateControlPoints( PMObject* oldActive ) +{ + PMControlPointList newCPs; + + if( m_pActiveObject ) + { + m_pActiveObject->controlPoints( newCPs ); + + if( m_pActiveObject == oldActive ) + { + // check if the control points are the same + bool same = true; + PMControlPointListIterator oit( m_controlPoints ); + PMControlPointListIterator nit( newCPs ); + while( same && oit.current( ) && nit.current( ) ) + { + if( oit.current( )->id( ) != nit.current( )->id( ) ) + same = false; + ++oit; + ++nit; + } + if( oit.current( ) || nit.current( ) ) + same = false; + if( same ) + { + // set the old selection + oit.toFirst( ); + nit.toFirst( ); + while( oit.current( ) && nit.current( ) ) + { + nit.current( )->setSelected( oit.current( )->selected( ) ); + ++oit; + ++nit; + } + } + } + } + + m_controlPoints.clear( ); + m_controlPoints = newCPs; + +} + +void PMPart::slotAboutToSave( ) +{ + emit aboutToSave( ); +} + +#include "pmpart.moc" diff --git a/kpovmodeler/pmpart.h b/kpovmodeler/pmpart.h new file mode 100644 index 00000000..e0ebcd06 --- /dev/null +++ b/kpovmodeler/pmpart.h @@ -0,0 +1,1041 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMPART_H +#define PMPART_H + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pmobject.h" +#include "pmcommandmanager.h" +#include "pmpartiface.h" + +class PMView; +class PMShell; +class PMObjectDrag; +class PMScene; +class PMCamera; +class PMPovrayWidget; +class PMParser; + +class PMBrowserExtension; +class PMSymbolTable; +class PMDeclare; + +class PMPrototypeManager; +class PMInsertRuleSystem; +class PMIOManager; + +class QMimeSource; +class KAction; +class KSelectAction; +class PMComboAction; +class PMSpinBoxAction; +class PMLabelAction; +class KProcess; + +/** + * The part for kpovmodeler (povray document) + */ +class PMPart : public KParts::ReadWritePart, virtual public PMPartIface +{ + Q_OBJECT +public: + /** + * construtor of PMPart, calls all init functions to create the + * application. + */ + PMPart( QWidget* parentWidget, const char* widgetName, + QObject* parent, const char* name, bool readWrite, + PMShell* shell = 0 ); + + /** + * construtor of PMPart, calls all init functions to create the + * application. It does not create the main widget. + */ + PMPart( QWidget* parentWidget, const char* widgetName, + QObject* parent, const char* name, bool readWrite, + bool onlyCutPaste, PMShell* shell = 0 ); + + /** + * Destructor + */ + ~PMPart( ); + /** + * deletes the document's contents + */ + void deleteContents( ); + /** + * initializes the document generally + */ + bool newDocument( ); + /** + * closes the actual document + */ + void closeDocument( ); + /** + * Exports the scene as povray code + */ + bool exportPovray( const KURL& url ); + + /** + * returns the toplevel object + */ + PMScene* scene( ) const { return m_pScene; } + /** + * Returns a pointer to the shell if there is one + */ + PMShell* shell( ) const { return m_pShell; } + /** + * saves settings + */ + void saveConfig( KConfig* cfg ); + /** + * loads settings + */ + void restoreConfig( KConfig* cfg ); + + /** + * Updates the sorted list of selected objects if necessary and + * returns a reference to the list. + */ + const PMObjectList& selectedObjects( ); + + /** + * Executes the command cmd. + * + * All changes to the document have to be made + * with @ref PMCommand objects for undo/redo. Each slot that changes the + * document creates a PMCommand object and calls this function. + * + * If this function returns false, the command was not executed + * and the command object was deleted. + */ + bool executeCommand( PMCommand* cmd ); + /** + * Checks, where the objects in list can be inserted, as child + * or as sibling of obj and asks the user if there is more than one + * possibility + * + * Returns PMIFirstChild, PMILastChild, PMISibling or 0, if the objects + * should not be inserted.*/ + int whereToInsert( PMObject* obj, const PMObjectList& list ); + /** + * Checks, where the objects in list can be inserted, as child + * or as sibling of obj and asks the user if there is more than one + * possibility + * + * Returns PMIFirstChild, PMILastChild, PMISibling or 0, if the objects + * should not be inserted.*/ + int whereToInsert( PMObject* obj, const QStringList& list ); + /** + * Asks the user, where to insert new objects. + * + * Returns PMIFirstChild, PMILastChild, PMISibling or 0, if the objects + * should not be inserted.*/ + int whereToInsert( PMObject* obj ); + + /** + * Returns the symbol table of this document + */ + PMSymbolTable* symbolTable( ) const { return m_pSymbolTable; } + /** + * Returns the first camera + */ + PMCamera* firstCamera( ); + /** + * Returns an iterator to the list of cameras + */ + QPtrListIterator cameras( ); + /** + * The active object + */ + PMObject* activeObject( ) const { return m_pActiveObject; } + /** + * The active object's name + */ + virtual QString activeObjectName( ); + /** + * Set the active object + */ + virtual bool setActiveObject( const QString& name ); + /** + * Get the valid properties of the currently active object + */ + virtual QStringList getProperties( ); + /** + * set a property on the active object + */ + virtual bool setProperty( const QString& name, const PMVariant& value ); + /** + * set a property on the active object + */ + virtual bool setProperty( const QString& name, const QString& value ); + /** + * get a property on the active object + */ + virtual const PMVariant getProperty( const QString& name ); + /** + * get a property on the active object + */ + virtual const QString getPropertyStr( const QString& name ); + /** + * List of control points of the active object + */ + PMControlPointList activeControlPoints( ) const { return m_controlPoints; } + + /** + * Called when the user moves some objects in the tree view. + * If obj is 0, the user moved the objects to another document (remove) + * + * Returns true if successful. + */ + bool dragMoveSelectionTo( PMObject* obj ); + /** + * Called when the user drags some objects onto the tree view + * + * Returns true if successful. + */ + bool drop( PMObject* obj, QMimeSource* e ); + /** + * Tries to parse the data and insert the parsed objects + * as child or siblings of object obj + * + * Type is the actions description for the undo/redo menu. + */ + bool insertFromParser( const QString& type, PMParser* parser, PMObject* obj ); + + /** + * Returns a pointer to the prototype manager + */ + PMPrototypeManager* prototypeManager( ) const { return m_pPrototypeManager; } + /** + * Returns a pointer to the insert rules system + */ + PMInsertRuleSystem* insertRuleSystem( ) const { return m_pInsertRuleSystem; } + /** + * Returns a pointer to the IO formats manager for this part + */ + PMIOManager* ioManager( ) const { return m_pIOManager; } + +public slots: + /** + * Opens the import file dialog + */ + void slotFileImport( ); + /** + * Opens the export file dialog + */ + void slotFileExport( ); + + /** + * puts the marked text/object into the clipboard and removes the objects + */ + void slotEditCut( ); + /** + * removes the selected object + */ + void slotEditDelete( ); + /** + * puts the marked text/object into the clipboard + */ + void slotEditCopy( ); + /** + * paste the clipboard into the document + */ + void slotEditPaste( ); + /** + * undoes the last change + */ + void slotEditUndo( ); + /** + * redoes the last undone command + */ + void slotEditRedo( ); + + /** + * Called when an object is changed. + * Mode is a bit combination of @ref PMChange constants + */ + void slotObjectChanged( PMObject* obj, const int mode, QObject* sender ); + /** + * Called when an id is changed + */ + void slotIDChanged( PMObject* obj, const QString& oldID ); + + /** + * Inserts a new PMObject of type type + */ + void slotNewObject( const QString& type ); + /** + * Inserts a new PMObject of type type at position pos. + * pos can be one of: + * FirstChild + * LastChild + * Sibling + */ + void slotNewObject( const QString& type, const QString& pos ); + /** + * Inserts the new PMObject. The object will be deleted if it can't be + * inserted or the user aborts the action + */ + void slotNewObject( PMObject* newObject, int insertAs = 0 ); + + /** + * List the known object types + */ + virtual QStringList getObjectTypes( ); + + /** + * Adds transformations to the object and calls slotNewObject + * for it + */ + void slotNewTransformedObject( PMObject* o ); + + /** + * Inserts a new PMGlobalSettings + */ + void slotNewGlobalSettings( ); + /** + * Inserts a new PMSkySphere + */ + void slotNewSkySphere( ); + /** + * Inserts a new PMRainbow + */ + void slotNewRainbow( ); + /** + * Inserts a new PMFog + */ + void slotNewFog( ); + /** + * Inserts a new PMInterior + */ + void slotNewInterior( ); + /** + * Inserts a new PMMedia + */ + void slotNewMedia( ); + /** + * Inserts a new PMDensity + */ + void slotNewDensity( ); + /** + * Inserts a new PMMaterial + */ + void slotNewMaterial( ); + /** + * Inserts a new PMBox + */ + void slotNewBox( ); + /** + * Inserts a new PMSphere + */ + void slotNewSphere( ); + /** + * Inserts a new PMCylinder + */ + void slotNewCylinder( ); + /** + * Inserts a new PMCone + */ + void slotNewCone( ); + /** + * Inserts a new PMTorus + */ + void slotNewTorus( ); + /** + * Inserts a new PMLathe + */ + void slotNewLathe( ); + /** + * Inserts a new PMPrism + */ + void slotNewPrism( ); + /** + * Inserts a new PMSurfaceOfRevolution + */ + void slotNewSurfaceOfRevolution( ); + /** + * Inserts a new PMSuperquadricEllipsoid + */ + void slotNewSuperquadricEllipsoid( ); + /** + * Inserts a new PMJuliaFractal + */ + void slotNewJuliaFractal( ); + /** + * Inserts a new PMHeightField + */ + void slotNewHeightField( ); + /** + * Inserts a new text object + */ + void slotNewText( ); + + /** + * Inserts a new PMBlob + */ + void slotNewBlob( ); + /** + * Inserts a new PMBlobSphere + */ + void slotNewBlobSphere( ); + /** + * Inserts a new PMBlobCylinder + */ + void slotNewBlobCylinder( ); + + /** + * Inserts a new PMPlane + */ + void slotNewPlane( ); + /** + * Inserts a new PMPolynom + */ + void slotNewPolynom( ); + /** + * Inserts a new PMDeclare + */ + void slotNewDeclare( ); + /** + * Inserts a new PMObjectLink + */ + void slotNewObjectLink( ); + + /** + * Inserts a new PMCSG ( union ) + */ + void slotNewUnion( ); + /** + * Inserts a new PMCSG ( intersection ) + */ + void slotNewIntersection( ); + /** + * Inserts a new PMCSG ( difference ) + */ + void slotNewDifference( ); + /** + * Inserts a new PMCSG ( merge ) + */ + void slotNewMerge( ); + + /** + * Inserts a new PMDisc + */ + void slotNewDisc( ); + /** + * Inserts a new PMBicubicPatch + */ + void slotNewBicubicPatch( ); + /** + * Inserts a new PMTriangle + */ + void slotNewTriangle( ); + + /** + * Inserts a new PMBoundedBy + */ + void slotNewBoundedBy( ); + /** + * Inserts a new PMClippedBy + */ + void slotNewClippedBy( ); + + /** + * Inserts a new PMLight object + */ + void slotNewLight( ); + /** + * Inserts a new PMLooksLike object + */ + void slotNewLooksLike( ); + /** + * Inserts a new PMProjectedThrough object + */ + void slotNewProjectedThrough( ); + + /** + * Inserts a new PMCamera + */ + void slotNewCamera( ); + + /** + * Inserts a new PMTexture + */ + void slotNewTexture( ); + /** + * Inserts a new PMPigment + */ + void slotNewPigment( ); + /** + * Inserts a new PMNormal + */ + void slotNewNormal( ); + /** + * Inserts a new PMSolidColor + */ + void slotNewSolidColor( ); + /** + * Inserts a new PMTextureList + */ + void slotNewTextureList( ); + /** + * Inserts a new PMColorList + */ + void slotNewColorList( ); + /** + * Inserts a new PMPigmentList + */ + void slotNewPigmentList( ); + /** + * Inserts a new PMNormalList + */ + void slotNewNormalList( ); + /** + * Inserts a new PMDensityList + */ + void slotNewDensityList( ); + /** + * Inserts a new PMFinish + */ + void slotNewFinish( ); + /** + * Inserts a new PMPattern + */ + void slotNewPattern( ); + /** + * Inserts a new PMBlendMapModifiers + */ + void slotNewBlendMapModifiers( ); + /** + * Inserts a new PMTextureMap + */ + void slotNewTextureMap( ); + /** + * Inserts a new PMMaterialMap + */ + void slotNewMaterialMap( ); + /** + * Inserts a new PMColorMap + */ + void slotNewColorMap( ); + /** + * Inserts a new PMPigmentMap + */ + void slotNewPigmentMap( ); + /** + * Inserts a new PMNormalMap + */ + void slotNewNormalMap( ); + /** + * Inserts a new PMBumpMap + */ + void slotNewBumpMap( ); + /** + * Inserts a new PMSlopeMap + */ + void slotNewSlopeMap( ); + /** + * Inserts a new PMDensityMap + */ + void slotNewDensityMap( ); + /** + * Inserts a new PMSlope + */ + void slotNewSlope( ); + /** + * Inserts a new PMWarp + */ + void slotNewWarp( ); + /** + * Inserts a new PMImageMap + */ + void slotNewImageMap( ); + /** + * Inserts a new PMQuickColor + */ + void slotNewQuickColor( ); + + /** + * Inserts a new PMTranslate + */ + void slotNewTranslate( ); + /** + * Inserts a new PMRotate + */ + void slotNewRotate( ); + /** + * Inserts a new PMScale + */ + void slotNewScale( ); + /** + * Inserts a new PMPovrayMatrix + */ + void slotNewMatrix( ); + /** + * Inserts a new PMComment + */ + void slotNewComment( ); + /** + * Inserts a new PMRaw + */ + void slotNewRaw( ); + + // POV-Ray 3.5 objects + /** + * Inserts a new PMIsoSurfate + */ + void slotNewIsoSurface( ); + /** + * Inserts a new PMRadiosity + */ + void slotNewRadiosity( ); + /** + * Inserts a new PMGlobalPhotons + */ + void slotNewGlobalPhotons( ); + /** + * Inserts a new PMPhotons + */ + void slotNewPhotons( ); + /** + * Inserts a new PMLightGroup + */ + void slotNewLightGroup( ); + /** + * Inserts a new PMInteriorTexture + */ + void slotNewInteriorTexture( ); + /** + * Inserts a new PMSphereSweep + */ + void slotNewSphereSweep( ); + /** + * Inserts a new PMMesh + */ + void slotNewMesh( ); + + + /** + * Called when the clipboard contents changed + */ + void slotClipboardDataChanged( ); + /** + * updates the undo/redo menu items + */ + void slotUpdateUndoRedo( const QString& undo, const QString& redo ); + + /** + * Starts rendering with povray + */ + virtual void slotRender( ); + /** + * Opens the render settings + */ + void slotRenderSettings( ); + /** + * Called when a render mode is selected + */ + void slotRenderMode( int index ); + /** + * Called when the render modes combo action is plugged into the toolbar + */ + void slotRenderModeActionPlugged( ); + /** + * Shows the render window + */ + void slotViewRenderWindow( ); + /** + * Called when the visibility level has changed + */ + void slotVisibilityLevelChanged( int ); + /** + * Called when the visibility level action is plugged into the toolbar + */ + void slotVisibilityActionPlugged( ); + /** + * Called when the global detail level has changed + */ + void slotGlobalDetailLevelChanged( int level ); + + /** + * Opens the search library object dialog + */ + void slotSearchLibraryObject( ); + + /** */ + virtual void setModified( ); + /** */ + virtual void setModified( bool modified ); + + /** Set the scene object. Must be used with extreme care. */ + void setScene( PMScene* scene ); + + /** + * Emits the aboutToSave signal + */ + void slotAboutToSave( ); + +signals: + /** + * Signal that is emitted when an object is changed. + * Mode is a bit combination of @ref PMChange constants. + */ + void objectChanged( PMObject* obj, const int mode, QObject* sender ); + /** + * Signal that is emitted when the views have to be refreshed. + * Usually on newDocument or openDocument + */ + void refresh( ); + /** + * Emitted when all views should delete all data + */ + void clear( ); + /** + * Emitted, when the modified flag changes + */ + void modified( ); + /** + * Emitted when the mouse is over a control point + */ + void controlPointMessage( const QString& msg ); + /** + * Emitted when the active render mode has changed + */ + void activeRenderModeChanged( ); + /** + * Emitted before the scene is rendered. + * + * Views should ask the user to save pending changes. + */ + void aboutToRender( ); + /** + * Emitted before the scene is saved or exported + * + * Views should ask the user to save pending changes. + */ + void aboutToSave( ); + +protected: + /** + * reimplemented from @ref KParts::ReadOnlyPart + */ + virtual bool openFile( ); + /** + * reimplemented from @ref KParts::ReadOnlyPart + */ + virtual bool saveFile( ); + /** + * Inits all actions + */ + void initActions( ); + /** + * Inits only actions related to copy&paste. + * Required by the library browser. + */ + void initCopyPasteActions( ); + + /** + * creates the widget of the part instance and sets + * it as the view + */ + void initView( QWidget* parent, const char* name ); + /** + * initializes the documents contents + */ + void initDocument( ); + /** + * clears the selection + */ + void clearSelection( ); + +private: + /** + * Disables all actions, that modify the part + */ + void disableReadWriteActions( ); + /** + * Updates all "new object" actions + */ + void updateNewObjectActions( ); + /** + * Finds a free id of the format . + * + * Adds the object to the symbol table. + * + * Returns the number. + */ + unsigned int findNewID( const QString& prefix, unsigned int firstNumber, + PMDeclare* obj ); + /** + * Updates the list of cameras + */ + void updateCameraList( ); + + /** + * Generic drop/paste function + */ + bool pasteOrDrop( const QString& type, QMimeSource* mime, PMObject* obj ); + /** + * Generic cut/delete/remove function + */ + bool removeSelection( const QString& type ); + /** + * Updates the render mode combo action + */ + void updateRenderModes( ); + /** + * Updates the visibility level action + */ + void updateVisibilityLevel( ); + /** + * Updates the control point list + */ + void updateControlPoints( PMObject* oldActive ); + + PMView* m_pView; + PMShell* m_pShell; + PMBrowserExtension* m_pExtension; + + /** + * the selected objects, unsorted! + */ + PMObjectList m_selectedObjects; + /** + * the selected objects, sorted. This list is only created if necessary. + */ + PMObjectList m_sortedSelectedObjects; + /** + * true if the list m_sortedSelectedObjects is up to date + */ + bool m_sortedListUpToDate; + /** + * the active object + */ + PMObject* m_pActiveObject; + /** + * the new selection after a command was executed + */ + PMObject* m_pNewSelection; + /** + * List of all cameras + */ + QPtrList m_cameras; + /** + * true if the m_cameras list is up to date + */ + bool m_bCameraListUpToDate; + /** + * true if the clipboard data can be decoded + */ + bool m_canDecode; + /** + * Commands stack for undo and redo + */ + PMCommandManager m_commandManager; + /** + * The povray scene, top level object + */ + PMScene* m_pScene; + /** + * Number of added objects during the last executed command + */ + unsigned int m_numAddedObjects; + /** + * Number of insert errors during the last executed command + */ + unsigned int m_numInsertErrors; + /** + * Details of insert errors + */ + QStringList m_insertErrorDetails; + /** + * The symbol table for this document + */ + PMSymbolTable* m_pSymbolTable; + /** + * The povray render window + */ + PMPovrayWidget* m_pPovrayWidget; + /** + * true if the new object actions have to be updated + */ + bool m_updateNewObjectActions; + /** + * Control points of the active object + */ + PMControlPointList m_controlPoints; + /** + * true if only copy'n'paste actions are available + */ + bool m_onlyCopyPaste; + + // the actions + KAction* m_pImportAction; + KAction* m_pExportAction; + + KAction* m_pCutAction; + KAction* m_pCopyAction; + KAction* m_pPasteAction; + KAction* m_pUndoAction; + KAction* m_pRedoAction; + KAction* m_pDeleteAction; + + KAction* m_pNewGlobalSettingsAction; + KAction* m_pNewSkySphereAction; + KAction* m_pNewRainbowAction; + KAction* m_pNewFogAction; + KAction* m_pNewInteriorAction; + KAction* m_pNewMediaAction; + KAction* m_pNewDensityAction; + KAction* m_pNewMaterialAction; + KAction* m_pNewBoxAction; + KAction* m_pNewSphereAction; + KAction* m_pNewCylinderAction; + KAction* m_pNewConeAction; + KAction* m_pNewTorusAction; + KAction* m_pNewLatheAction; + KAction* m_pNewPrismAction; + KAction* m_pNewSurfaceOfRevolutionAction; + KAction* m_pNewSuperquadricEllipsoidAction; + KAction* m_pNewJuliaFractalAction; + KAction* m_pNewHeightFieldAction; + KAction* m_pNewTextAction; + + KAction* m_pNewBlobAction; + KAction* m_pNewBlobSphereAction; + KAction* m_pNewBlobCylinderAction; + + KAction* m_pNewPlaneAction; + KAction* m_pNewPolynomAction; + + KAction* m_pNewDeclareAction; + KAction* m_pNewObjectLinkAction; + + KAction* m_pNewUnionAction; + KAction* m_pNewDifferenceAction; + KAction* m_pNewIntersectionAction; + KAction* m_pNewMergeAction; + + KAction* m_pNewBoundedByAction; + KAction* m_pNewClippedByAction; + + KAction* m_pNewBicubicPatchAction; + KAction* m_pNewDiscAction; + KAction* m_pNewTriangleAction; + + KAction* m_pNewLightAction; + KAction* m_pNewLooksLikeAction; + KAction* m_pNewProjectedThroughAction; + + KAction* m_pNewCameraAction; + + KAction* m_pNewTextureAction; + KAction* m_pNewPigmentAction; + KAction* m_pNewNormalAction; + KAction* m_pNewSolidColorAction; + KAction* m_pNewTextureListAction; + KAction* m_pNewColorListAction; + KAction* m_pNewPigmentListAction; + KAction* m_pNewNormalListAction; + KAction* m_pNewDensityListAction; + KAction* m_pNewFinishAction; + KAction* m_pNewPatternAction; + KAction* m_pNewBlendMapModifiersAction; + KAction* m_pNewTextureMapAction; + KAction* m_pNewMaterialMapAction; + KAction* m_pNewPigmentMapAction; + KAction* m_pNewColorMapAction; + KAction* m_pNewNormalMapAction; + KAction* m_pNewBumpMapAction; + KAction* m_pNewSlopeMapAction; + KAction* m_pNewDensityMapAction; + KAction* m_pNewSlopeAction; + KAction* m_pNewWarpAction; + KAction* m_pNewImageMapAction; + KAction* m_pNewQuickColorAction; + + KAction* m_pNewTranslateAction; + KAction* m_pNewScaleAction; + KAction* m_pNewRotateAction; + KAction* m_pNewMatrixAction; + + KAction* m_pNewCommentAction; + KAction* m_pNewRawAction; + + // POV-Ray 3.5 objects + KAction* m_pNewIsoSurfaceAction; + KAction* m_pNewRadiosityAction; + KAction* m_pNewGlobalPhotonsAction; + KAction* m_pNewPhotonsAction; + KAction* m_pNewLightGroupAction; + KAction* m_pNewInteriorTextureAction; + KAction* m_pNewSphereSweepAction; + KAction* m_pNewMeshAction; + + KAction* m_pSearchLibraryObjectAction; + + PMComboAction* m_pRenderComboAction; + KAction* m_pRenderSettingsAction; + KAction* m_pViewRenderWindowAction; + KAction* m_pRenderAction; + PMSpinBoxAction* m_pVisibilityLevelAction; + PMLabelAction* m_pVisibilityLabelAction; + KSelectAction* m_pGlobalDetailAction; + PMLabelAction* m_pGlobalDetailLabelAction; + + QPtrList m_readWriteActions; + + PMPrototypeManager* m_pPrototypeManager; + PMInsertRuleSystem* m_pInsertRuleSystem; + PMIOManager* m_pIOManager; +}; + +class PMBrowserExtension : public KParts::BrowserExtension +{ + Q_OBJECT + friend class PMPart; +public: + PMBrowserExtension( PMPart* parent ) + : KParts::BrowserExtension( parent, "PMBrowserExtension" ) + { + KGlobal::locale()->insertCatalogue("kpovmodeler"); + } + + virtual ~PMBrowserExtension( ) + { + } +}; + +#endif diff --git a/kpovmodeler/pmpartiface.h b/kpovmodeler/pmpartiface.h new file mode 100644 index 00000000..a1fe495e --- /dev/null +++ b/kpovmodeler/pmpartiface.h @@ -0,0 +1,119 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2004 by Luis Carvalho + email : lpassos@oninetspeed.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMPARTIFACE_H +#define PMPARTIFACE_H + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "pmvariant.h" + +/** + * DCOP Interface for kpovmodeler + */ +class PMPartIface : virtual public DCOPObject +{ + K_DCOP + +k_dcop: + /** + * deletes the document's contents + */ + virtual void deleteContents( ) = 0; + /** + * initializes the document generally + */ + virtual bool newDocument( ) = 0; + /** + * closes the actual document + */ + virtual void closeDocument( ) = 0; + /** + * Inserts a new PMObject of type type + */ + virtual void slotNewObject( const QString& type, const QString& pos ) = 0; + /** + * initializes the documents contents + */ + virtual void initDocument( ) = 0; + /** + * clears the selection + */ + virtual void clearSelection( ) = 0; + /** + * puts the marked text/object into the clipboard and removes the objects + */ + virtual void slotEditCut( ) = 0; + /** + * removes the selected object + */ + virtual void slotEditDelete( ) = 0; + /** + * puts the marked text/object into the clipboard + */ + virtual void slotEditCopy( ) = 0; + /** + * paste the clipboard into the document + */ + virtual void slotEditPaste( ) = 0; + /** + * render the current scene + */ + virtual void slotRender( ) = 0; + /** + * returns the currently selected object + */ + virtual QString activeObjectName( ) = 0; + /** + * set the current selected object. + * returns true if successful or false otherwise + */ + virtual bool setActiveObject( const QString& name ) = 0; + /** + * Get known properties of the currently active object + */ + virtual QStringList getProperties( ) = 0; + /** + * set a property on the currently active object + */ + virtual bool setProperty( const QString& property, const PMVariant& value ) = 0; + /** + * set a property on the currently active object + */ + virtual bool setProperty( const QString& property, const QString& value ) = 0; + /** + * Get the value of the given property + */ + virtual const PMVariant getProperty( const QString& property ) = 0; + /** + * Get the value of the given property + */ + virtual const QString getPropertyStr( const QString& property ) = 0; + /** + * Get a list of known object types. + */ + virtual QStringList getObjectTypes( ) = 0; +}; + +#endif diff --git a/kpovmodeler/pmpattern.cpp b/kpovmodeler/pmpattern.cpp new file mode 100644 index 00000000..c9377f84 --- /dev/null +++ b/kpovmodeler/pmpattern.cpp @@ -0,0 +1,1126 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmpatternedit.h" +#include "pmpattern.h" + +#include "pmxmlhelper.h" +#include "pmlistpatternedit.h" +#include "pmcompositeobject.h" +#include "pmmemento.h" +#include "pmenumproperty.h" + +#include + +const PMPattern::PMPatternType patternTypeDefault = PMPattern::PatternAgate; +const double agateTurbulenceDefault = 0.5; +const PMVector crackleFormDefault = PMVector( -1.0, 1.0, 0.0 ); +const int crackleMetricDefault = 2; +const double crackleOffsetDefault = 0.0; +const bool crackleSolidDefault = false; +const QString densityFileDefault = QString( "" ); +const int densityInterpolateDefault = 0; +const PMVector gradientDefault = PMVector( 1.0, 1.0, 1.0 ); +const PMVector juliaComplexDefault = PMVector( 0.353, 0.288 ); +const bool fractalMagnetDefault = false; +const int fractalMagnetTypeDefault = 1; +const int maxIterationsDefault = 10; +const int fractalExponentDefault = 2; +const int fractalExtTypeDefault = 1; +const double fractalExtFactorDefault = 1.0; +const int fractalIntTypeDefault = 0; +const double fractalIntFactorDefault = 1.0; +const double quiltControl0Default = 1.0; +const double quiltControl1Default = 1.0; +const PMVector slopeDirectionDefault = PMVector( 0.0, -1.0, 0.0 ); +const double slopeLoSlopeDefault = 0.0; +const double slopeHiSlopeDefault = 1.0; +const bool slopeAltFlagDefault = false; +const PMVector slopeAltitudeDefault = PMVector( 0.0, 1.0, 0.0 ); +const double slopeLoAltDefault = 0.0; +const double slopeHiAltDefault = 1.0; +const int spiralNumberArmsDefault = 0; +const PMPattern::PMNoiseType noiseGeneratorDefault = PMPattern::GlobalSetting; +const QString noiseGeneratorDefaultText = QString( "global_setting" ); +const bool turbulenceDefault = false; +const PMVector valueVectorDefault = PMVector( 0.0, 0.0, 0.0 ); +const int octavesDefault = 6; +const double omegaDefault = 0.5; +const double lambdaDefault = 2.0; +const double depthDefault = 0.0; + +PMDefinePropertyClass( PMPattern, PMPatternProperty ); +PMDefineEnumPropertyClass( PMPattern, PMPattern::PMPatternType, + PMPatternTypeProperty ); +PMDefineEnumPropertyClass( PMPattern, PMPattern::PMNoiseType, + PMNoiseProperty ); + +PMMetaObject* PMPattern::s_pMetaObject = 0; +PMObject* createNewPattern( PMPart* part ) +{ + return new PMPattern( part ); +} + +PMPattern::PMPattern( PMPart* part ) + : Base( part ) +{ + m_patternType = patternTypeDefault; + + m_agateTurbulence = agateTurbulenceDefault; + + m_crackleForm = crackleFormDefault; + m_crackleMetric = crackleMetricDefault; + m_crackleOffset = crackleOffsetDefault; + m_crackleSolid = crackleSolidDefault; + + m_densityFile = densityFileDefault; + m_densityInterpolate = densityInterpolateDefault; + + m_gradient = gradientDefault; + + m_juliaComplex = juliaComplexDefault; + m_fractalMagnet = fractalMagnetDefault; + m_fractalMagnetType = fractalMagnetTypeDefault; + m_maxIterations = maxIterationsDefault; + m_fractalExponent = fractalExponentDefault; + m_fractalExtType = fractalExtTypeDefault; + m_fractalExtFactor = fractalExtFactorDefault; + m_fractalIntType = fractalIntTypeDefault; + m_fractalIntFactor = fractalIntFactorDefault; + + m_quiltControl0 = quiltControl0Default; + m_quiltControl1 = quiltControl1Default; + + m_slopeDirection = slopeDirectionDefault; + m_slopeLoSlope = slopeLoSlopeDefault; + m_slopeHiSlope = slopeHiSlopeDefault; + m_slopeAltFlag = slopeAltFlagDefault; + m_slopeAltitude = slopeAltitudeDefault; + m_slopeLoAlt = slopeLoAltDefault; + m_slopeHiAlt = slopeHiAltDefault; + + m_spiralNumberArms = spiralNumberArmsDefault; + + m_noiseGenerator = noiseGeneratorDefault; + + m_enableTurbulence = turbulenceDefault; + m_valueVector = valueVectorDefault; + m_octaves = octavesDefault; + m_omega = omegaDefault; + m_lambda = lambdaDefault; + + m_depth = depthDefault; +} + +PMPattern::PMPattern( const PMPattern& p ) + : Base( p ) +{ + m_patternType = p.m_patternType; + + m_agateTurbulence = p.m_agateTurbulence; + + m_crackleForm = p.m_crackleForm; + m_crackleMetric = p.m_crackleMetric; + m_crackleOffset = p.m_crackleOffset; + m_crackleSolid = p.m_crackleSolid; + + m_densityFile = p.m_densityFile; + m_densityInterpolate = p.m_densityInterpolate; + + m_gradient = p.m_gradient; + + m_juliaComplex = p.m_juliaComplex; + m_fractalMagnet = p.m_fractalMagnet; + m_fractalMagnetType = p.m_fractalMagnetType; + m_maxIterations = p.m_maxIterations; + m_fractalExponent = p.m_fractalExponent; + m_fractalExtType = p.m_fractalExtType; + m_fractalExtFactor = p.m_fractalExtFactor; + m_fractalIntType = p.m_fractalIntType; + m_fractalIntFactor = p.m_fractalIntFactor; + + m_quiltControl0 = p.m_quiltControl0; + m_quiltControl1 = p.m_quiltControl1; + + m_slopeDirection = p.m_slopeDirection; + m_slopeLoSlope = p.m_slopeLoSlope; + m_slopeHiSlope = p.m_slopeHiSlope; + m_slopeAltFlag = p.m_slopeAltFlag; + m_slopeAltitude = p.m_slopeAltitude; + m_slopeLoAlt = p.m_slopeLoAlt; + m_slopeHiAlt = p.m_slopeHiAlt; + + m_spiralNumberArms = p.m_spiralNumberArms; + + m_noiseGenerator = p.m_noiseGenerator; + + m_enableTurbulence = p.m_enableTurbulence; + m_valueVector = p.m_valueVector; + m_octaves = p.m_octaves; + m_omega = p.m_omega; + m_lambda = p.m_lambda; + + m_depth = p.m_depth; +} + +PMPattern::~PMPattern( ) +{ +} + +void PMPattern::serialize( QDomElement& e, QDomDocument& ) const +{ + switch( m_patternType ) + { + case PatternAgate: + e.setAttribute( "patterntype", "agate" ); + break; + case PatternAverage: + e.setAttribute( "patterntype", "average" ); + break; + case PatternBoxed: + e.setAttribute( "patterntype", "boxed" ); + break; + case PatternBozo: + e.setAttribute( "patterntype", "bozo" ); + break; + case PatternBumps: + e.setAttribute( "patterntype", "bumps" ); + break; + case PatternCells: + e.setAttribute( "patterntype", "cells" ); + break; + case PatternCrackle: + e.setAttribute( "patterntype", "crackle" ); + break; + case PatternCylindrical: + e.setAttribute( "patterntype", "cylindrical" ); + break; + case PatternDensity: + e.setAttribute( "patterntype", "density" ); + break; + case PatternDents: + e.setAttribute( "patterntype", "dents" ); + break; + case PatternGradient: + e.setAttribute( "patterntype", "gradient" ); + break; + case PatternGranite: + e.setAttribute( "patterntype", "granite" ); + break; + case PatternJulia: + e.setAttribute( "patterntype", "julia" ); + break; + case PatternLeopard: + e.setAttribute( "patterntype", "leopard" ); + break; + case PatternMandel: + e.setAttribute( "patterntype", "mandel" ); + break; + case PatternMarble: + e.setAttribute( "patterntype", "marble" ); + break; + case PatternOnion: + e.setAttribute( "patterntype", "onion" ); + break; + case PatternPlanar: + e.setAttribute( "patterntype", "planar" ); + break; + case PatternQuilted: + e.setAttribute( "patterntype", "quilted" ); + break; + case PatternRadial: + e.setAttribute( "patterntype", "radial" ); + break; + case PatternRipples: + e.setAttribute( "patterntype", "ripples" ); + break; + case PatternSlope: + e.setAttribute( "patterntype", "slope" ); + break; + case PatternSpherical: + e.setAttribute( "patterntype", "spherical" ); + break; + case PatternSpiral1: + e.setAttribute( "patterntype", "spiral1" ); + break; + case PatternSpiral2: + e.setAttribute( "patterntype", "spiral2" ); + break; + case PatternSpotted: + e.setAttribute( "patterntype", "spotted" ); + break; + case PatternWaves: + e.setAttribute( "patterntype", "waves" ); + break; + case PatternWood: + e.setAttribute( "patterntype", "wood" ); + break; + case PatternWrinkles: + e.setAttribute( "patterntype", "wrinkles" ); + break; + } + + e.setAttribute( "agateturbulence", m_agateTurbulence ); + + e.setAttribute( "crackleform", m_crackleForm.serializeXML( ) ); + e.setAttribute( "cracklemetric", m_crackleMetric ); + e.setAttribute( "crackleoffset", m_crackleOffset ); + e.setAttribute( "cracklesolid", m_crackleSolid ); + + e.setAttribute( "densityinterpolate", m_densityInterpolate ); + e.setAttribute( "densityfile", m_densityFile ); + + e.setAttribute( "gradient", m_gradient.serializeXML( ) ); + + e.setAttribute( "juliacomplex", m_juliaComplex.serializeXML( ) ); + e.setAttribute( "fractalmagnet", m_fractalMagnet ); + e.setAttribute( "fractalmagnettype", m_fractalMagnetType ); + e.setAttribute( "maxiterations", m_maxIterations ); + e.setAttribute( "fractalexponent", m_fractalExponent ); + e.setAttribute( "fractalexttype", m_fractalExtType ); + e.setAttribute( "fractalextfactor", m_fractalExtFactor ); + e.setAttribute( "fractalinttype", m_fractalIntType ); + e.setAttribute( "fractalintfactor", m_fractalIntFactor ); + + e.setAttribute( "quiltcontrol0", m_quiltControl0 ); + e.setAttribute( "quiltcontrol1", m_quiltControl1 ); + + e.setAttribute( "slopedirection", m_slopeDirection.serializeXML( ) ); + e.setAttribute( "slopeloslope", m_slopeLoSlope ); + e.setAttribute( "slopehislope", m_slopeHiSlope ); + e.setAttribute( "slopealtflag", m_slopeAltFlag ); + e.setAttribute( "slopealtitude", m_slopeAltitude.serializeXML( ) ); + e.setAttribute( "slopeloalt", m_slopeLoAlt ); + e.setAttribute( "slopehialt", m_slopeHiAlt ); + + e.setAttribute( "spiralnumberarms", m_spiralNumberArms ); + switch ( m_noiseGenerator ) + { + case GlobalSetting: + e.setAttribute( "noise_generator", "global_setting" ); + break; + case Original: + e.setAttribute( "noise_generator", "original" ); + break; + case RangeCorrected: + e.setAttribute( "noise_generator", "range_corrected" ); + break; + case Perlin: + e.setAttribute( "noise_generator", "perlin" ); + break; + } + + e.setAttribute( "enable_turbulence", m_enableTurbulence ); + e.setAttribute( "turbulence", m_valueVector.serializeXML( ) ); + e.setAttribute( "octaves", m_octaves ); + e.setAttribute( "omega", m_omega ); + e.setAttribute( "lambda", m_lambda ); + + e.setAttribute( "depth", m_depth ); +} + +void PMPattern::readAttributes( const PMXMLHelper& h ) +{ + QString str = h.stringAttribute( "patterntype", "agate" ); + + if( str == "agate" ) + m_patternType = PatternAgate; + else if( str == "average" ) + m_patternType = PatternAverage; + else if( str == "boxed" ) + m_patternType = PatternBoxed; + else if( str == "bozo" ) + m_patternType = PatternBozo; + else if( str == "bumps" ) + m_patternType = PatternBumps; + else if( str == "cells" ) + m_patternType = PatternCells; + else if( str == "crackle" ) + m_patternType = PatternCrackle; + else if( str == "cylindrical" ) + m_patternType = PatternCylindrical; + else if( str == "density" ) + m_patternType = PatternDensity; + else if( str == "dents" ) + m_patternType = PatternDents; + else if( str == "gradient" ) + m_patternType = PatternGradient; + else if( str == "granite" ) + m_patternType = PatternGranite; + else if( str == "julia" ) + m_patternType = PatternJulia; + else if( str == "leopard" ) + m_patternType = PatternLeopard; + else if( str == "mandel" ) + m_patternType = PatternMandel; + else if( str == "marble" ) + m_patternType = PatternMarble; + else if( str == "onion" ) + m_patternType = PatternOnion; + else if( str == "planar" ) + m_patternType = PatternPlanar; + else if( str == "quilted" ) + m_patternType = PatternQuilted; + else if( str == "radial" ) + m_patternType = PatternRadial; + else if( str == "ripples" ) + m_patternType = PatternRipples; + else if( str == "slope" ) + m_patternType = PatternSlope; + else if( str == "spherical" ) + m_patternType = PatternSpherical; + else if( str == "spiral1" ) + m_patternType = PatternSpiral1; + else if( str == "spiral2" ) + m_patternType = PatternSpiral2; + else if( str == "spotted" ) + m_patternType = PatternSpotted; + else if( str == "waves" ) + m_patternType = PatternWaves; + else if( str == "wood" ) + m_patternType = PatternWood; + else if( str == "wrinkles" ) + m_patternType = PatternWrinkles; + + m_agateTurbulence = h.doubleAttribute( "agateturbulence", agateTurbulenceDefault ); + + m_crackleForm = h.vectorAttribute( "crackleform", crackleFormDefault ); + m_crackleMetric = h.intAttribute( "cracklemetric", crackleMetricDefault ); + m_crackleOffset = h.doubleAttribute( "crackleoffset", crackleOffsetDefault ); + m_crackleSolid = h.boolAttribute( "cracklesolid", crackleSolidDefault ); + + m_densityInterpolate = h.intAttribute( "densityinterpolate", densityInterpolateDefault ); + m_densityFile = h.stringAttribute( "densityfile", densityFileDefault ); + + m_gradient = h.vectorAttribute( "gradient", gradientDefault ); + + m_juliaComplex = h.vectorAttribute( "juliacomplex", juliaComplexDefault ); + m_fractalMagnet = h.boolAttribute( "fractalmagnet", fractalMagnetDefault ); + m_fractalMagnetType = h.intAttribute( "fractalmagnettype", fractalMagnetTypeDefault ); + m_maxIterations = h.intAttribute( "maxiterations", maxIterationsDefault ); + m_fractalExponent = h.intAttribute( "fractalexponent", fractalExponentDefault ); + m_fractalExtType = h.intAttribute( "fractalexttype", fractalExtTypeDefault ); + m_fractalExtFactor = h.doubleAttribute( "fractalextfactor", fractalExtFactorDefault ); + m_fractalIntType = h.intAttribute( "fractalinttype", fractalIntTypeDefault ); + m_fractalIntFactor = h.doubleAttribute( "fractalintfactor", fractalIntFactorDefault ); + + m_quiltControl0 = h.doubleAttribute( "quiltcontrol0", quiltControl0Default ); + m_quiltControl1 = h.doubleAttribute( "quiltcontrol1", quiltControl1Default ); + + m_slopeDirection = h.vectorAttribute( "slopedirection", slopeDirectionDefault ); + m_slopeLoSlope = h.doubleAttribute( "slopeloslope", slopeLoSlopeDefault ); + m_slopeHiSlope = h.doubleAttribute( "slopehislope", slopeHiSlopeDefault ); + m_slopeAltFlag = h.boolAttribute( "slopealtflag", slopeAltFlagDefault ); + m_slopeAltitude = h.vectorAttribute( "slopealtitude", slopeAltitudeDefault ); + m_slopeLoAlt = h.doubleAttribute( "slopeloalt", slopeLoAltDefault ); + m_slopeHiAlt = h.doubleAttribute( "slopehialt", slopeHiAltDefault ); + + m_spiralNumberArms = h.intAttribute( "spiralnumberarms", spiralNumberArmsDefault ); + + str = h.stringAttribute( "noise_generator", noiseGeneratorDefaultText ); + if ( str == "original" ) + m_noiseGenerator = Original; + else if ( str == "range_corrected" ) + m_noiseGenerator = RangeCorrected; + else if ( str == "perlin" ) + m_noiseGenerator = Perlin; + else + m_noiseGenerator = GlobalSetting; + + m_enableTurbulence = h.boolAttribute( "enable_turbulence" , false ); + m_valueVector = h.vectorAttribute( "turbulence", valueVectorDefault ); + m_octaves = h.intAttribute( "octaves", octavesDefault ); + m_omega = h.doubleAttribute( "omega", omegaDefault ); + m_lambda = h.doubleAttribute( "lambda", lambdaDefault ); + + m_depth = h.doubleAttribute( "depth", depthDefault ); + + Base::readAttributes( h ); +} + +PMMetaObject* PMPattern::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Pattern", Base::metaObject( ), + createNewPattern ); + s_pMetaObject->addProperty( + new PMPatternProperty( "agateTurbulence", &PMPattern::setAgateTurbulence, &PMPattern::agateTurbulence ) ); + + s_pMetaObject->addProperty( + new PMPatternProperty( "densityFile", &PMPattern::setDensityFile, &PMPattern::densityFile ) ); + s_pMetaObject->addProperty( + new PMPatternProperty( "densityInterpolate", &PMPattern::setDensityInterpolate, &PMPattern::densityInterpolate ) ); + + s_pMetaObject->addProperty( + new PMPatternProperty( "gradient", &PMPattern::setGradient, &PMPattern::gradient ) ); + + s_pMetaObject->addProperty( + new PMPatternProperty( "maxIterations", &PMPattern::setMaxIterations, &PMPattern::maxIterations ) ); + + s_pMetaObject->addProperty( + new PMPatternProperty( "quiltControl0", &PMPattern::setQuiltControl0, &PMPattern::quiltControl0 ) ); + s_pMetaObject->addProperty( + new PMPatternProperty( "quiltControl1", &PMPattern::setQuiltControl1, &PMPattern::quiltControl1 ) ); + + s_pMetaObject->addProperty( + new PMPatternProperty( "spiralNumberArms", &PMPattern::setSpiralNumberArms, &PMPattern::spiralNumberArms ) ); + + s_pMetaObject->addProperty( + new PMPatternProperty( "turbulence", &PMPattern::enableTurbulence, &PMPattern::isTurbulenceEnabled ) ); + s_pMetaObject->addProperty( + new PMPatternProperty( "valueVector", &PMPattern::setValueVector, &PMPattern::valueVector ) ); + s_pMetaObject->addProperty( + new PMPatternProperty( "octaves", &PMPattern::setOctaves, &PMPattern::octaves ) ); + s_pMetaObject->addProperty( + new PMPatternProperty( "omega", &PMPattern::setOmega, &PMPattern::omega ) ); + s_pMetaObject->addProperty( + new PMPatternProperty( "lambda", &PMPattern::setLambda, &PMPattern::lambda ) ); + + s_pMetaObject->addProperty( + new PMPatternProperty( "depth", &PMPattern::setDepth, &PMPattern::depth ) ); + + PMPatternTypeProperty* p = new PMPatternTypeProperty( + "patternType", &PMPattern::setPatternType, &PMPattern::patternType ); + p->addEnumValue( "Agate", PatternAgate ); + p->addEnumValue( "Average", PatternAverage ); + p->addEnumValue( "Boxed", PatternBoxed ); + p->addEnumValue( "Bozo", PatternBozo ); + p->addEnumValue( "Bumps", PatternBumps ); + p->addEnumValue( "Cells", PatternCells ); + p->addEnumValue( "Crackle", PatternCrackle ); + p->addEnumValue( "Cylindrical", PatternCylindrical ); + p->addEnumValue( "Density", PatternDensity ); + p->addEnumValue( "Dents", PatternDents ); + p->addEnumValue( "Gradient", PatternGradient ); + p->addEnumValue( "Granite", PatternGranite ); + p->addEnumValue( "Julia", PatternJulia ); + p->addEnumValue( "Leopard", PatternLeopard ); + p->addEnumValue( "Mandel", PatternMandel ); + p->addEnumValue( "Marble", PatternMarble ); + p->addEnumValue( "Onion", PatternOnion ); + p->addEnumValue( "Planar", PatternPlanar ); + p->addEnumValue( "Quilted", PatternQuilted ); + p->addEnumValue( "Radial", PatternRadial ); + p->addEnumValue( "Ripples", PatternRipples ); + p->addEnumValue( "Slope", PatternSlope ); + p->addEnumValue( "Spherical", PatternSpherical ); + p->addEnumValue( "Spiral1", PatternSpiral1 ); + p->addEnumValue( "Spiral2", PatternSpiral2 ); + p->addEnumValue( "Spotted", PatternSpotted ); + p->addEnumValue( "Waves", PatternWaves ); + p->addEnumValue( "Wood", PatternWood ); + p->addEnumValue( "Wrinkles", PatternWrinkles ); + s_pMetaObject->addProperty( p ); + + PMNoiseProperty* p2 = new PMNoiseProperty( + "noiseGenerator", &PMPattern::setNoiseGenerator, &PMPattern::noiseGenerator ); + p2->addEnumValue( "GlobalSetting", GlobalSetting ); + p2->addEnumValue( "Original", Original ); + p2->addEnumValue( "RangeCorrected", RangeCorrected ); + p2->addEnumValue( "Perlin", Perlin ); + s_pMetaObject->addProperty( p2 ); + } + return s_pMetaObject; +} + +void PMPattern::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMPattern::description( ) const +{ + return i18n( "pattern" ); +} + +void PMPattern::setPatternType( PMPatternType c ) +{ + if( c != m_patternType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMPatternTypeID, m_patternType ); + m_patternType = c; + } +} + +void PMPattern::setAgateTurbulence( double c ) +{ + if( c != m_agateTurbulence ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAgateTurbulenceID, m_agateTurbulence ); + m_agateTurbulence = c; + } +} + +void PMPattern::setCrackleForm( const PMVector& v ) +{ + if ( v != m_crackleForm ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCrackleFormID, m_crackleForm ); + m_crackleForm = v; + } +} + +void PMPattern::setCrackleMetric( int c ) +{ + if ( c < 1 ) + { + kdError( PMArea ) << "new metric is < 1 in PMPattern::setCrackleMetric\n"; + c = 1; + } + + if ( c != m_crackleMetric ) + { + if ( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCrackleMetricID, m_crackleMetric ); + m_crackleMetric = c; + } +} + +void PMPattern::setCrackleOffset( double c ) +{ + if ( c != m_crackleOffset ) + { + if ( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCrackleOffsetID, m_crackleOffset ); + m_crackleOffset = c; + } +} + +void PMPattern::setCrackleSolid( bool c ) +{ + if ( c != m_crackleSolid ) + { + if ( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCrackleSolidID, m_crackleSolid ); + m_crackleSolid = c; + } +} + +void PMPattern::setDensityInterpolate( int c ) +{ + if( c != m_densityInterpolate ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMDensityInterpolateID, m_densityInterpolate ); + m_densityInterpolate = c; + } +} + +void PMPattern::setDensityFile( const QString& s ) +{ + if( s != m_densityFile ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMDensityFileID, m_densityFile ); + m_densityFile = s; + } +} + +void PMPattern::setGradient( const PMVector& v ) +{ + if( v != m_gradient ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMGradientID, m_gradient ); + m_gradient = v; + } +} + +void PMPattern::setJuliaComplex( const PMVector& v ) +{ + if ( v != m_juliaComplex ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMJuliaComplexID, m_juliaComplex ); + m_juliaComplex = v; + } +} + +void PMPattern::setFractalMagnet( bool c ) +{ + if ( c != m_fractalMagnet ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFractalMagnetID, m_fractalMagnet ); + m_fractalMagnet = c; + } +} + +void PMPattern::setFractalMagnetType( int c ) +{ + if ( c < 1 ) + { + kdError( PMArea ) << "Magnet type < 1 in PMPattern::setFractalMagnetType\n"; + c = 1; + } + + if ( c > 2 ) + { + kdError( PMArea ) << "Magnet type > 2 in PMPattern::setFractalMagnetType\n"; + c = 2; + } + + if ( c != m_fractalMagnetType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFractalMagnetTypeID, m_fractalMagnetType ); + m_fractalMagnetType = c; + } +} + +void PMPattern::setMaxIterations( int c ) +{ + if( c != m_maxIterations ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMMaxIterationsID, m_maxIterations ); + m_maxIterations = c; + } +} + +void PMPattern::setFractalExponent( int c ) +{ + if ( c < 2 ) + { + kdError( PMArea ) << "Exponent < 2 in PMPattern::setFractalExponent\n"; + c = 2; + } + + if ( c > 33 ) + { + kdError( PMArea ) << "Exponent > 33 in PMPattern::setFractalExponent\n"; + c = 33; + } + + if ( c != m_fractalExponent ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFractalExponentID, m_fractalExponent ); + m_fractalExponent = c; + } +} + +void PMPattern::setFractalExtType( int c ) +{ + if ( c < 0 ) + { + kdError( PMArea ) << "Exterior Type < 0 in PMPattern::setFractalExtType\n"; + c = 0; + } + + if ( c > 6 ) + { + kdError( PMArea ) << "Exterior Type > 6 in PMPattern::setFractalExtType\n"; + c = 6; + } + + if ( c != m_fractalExtType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFractalExtTypeID, m_fractalExtType ); + m_fractalExtType = c; + } +} + +void PMPattern::setFractalExtFactor( double c ) +{ + if ( c != m_fractalExtFactor ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFractalExtFactorID, m_fractalExtFactor ); + m_fractalExtFactor = c; + } +} + +void PMPattern::setFractalIntType( int c ) +{ + if ( c < 0 ) + { + kdError( PMArea ) << "Interior Type < 0 in PMPattern::setFractalIntType\n"; + c = 0; + } + + if ( c > 6 ) + { + kdError( PMArea ) << "Interior Type > 6 in PMPattern::setFractalIntType\n"; + c = 6; + } + + if ( c != m_fractalIntType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFractalIntTypeID, m_fractalIntType ); + m_fractalIntType = c; + } +} + +void PMPattern::setFractalIntFactor( double c ) +{ + if ( c != m_fractalIntFactor ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFractalIntFactorID, m_fractalIntFactor ); + m_fractalIntFactor = c; + } +} + +void PMPattern::setQuiltControl0( double c ) +{ + if( c != m_quiltControl0 ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMQuiltControl0ID, m_quiltControl0 ); + m_quiltControl0 = c; + } +} + +void PMPattern::setQuiltControl1( double c ) +{ + if( c != m_quiltControl1 ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMQuiltControl1ID, m_quiltControl1 ); + m_quiltControl1 = c; + } +} + +void PMPattern::setSlopeDirection( const PMVector& v ) +{ + if ( v != m_slopeDirection ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSlopeDirectionID, m_slopeDirection ); + m_slopeDirection = v; + } +} + +void PMPattern::setSlopeLoSlope( double c ) +{ + if ( c < 0.0 ) + { + kdError( PMArea ) << "Low slope < 0.0 in PMPattern::setSlopeLoSlope\n"; + c = 0.0; + } + + if ( c > 1.0 ) + { + kdError( PMArea ) << "Low slope > 1.0 in PMPattern::setSlopeLoSlope\n"; + c = 1.0; + } + + if ( c != m_slopeLoSlope ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSlopeLoSlopeID, m_slopeLoSlope ); + m_slopeLoSlope = c; + } +} + +void PMPattern::setSlopeHiSlope( double c ) +{ + if ( c < 0.0 ) + { + kdError( PMArea ) << "High slope < 0.0 in PMPattern::setSlopeHiSlope\n"; + c = 0.0; + } + + if ( c > 1.0 ) + { + kdError( PMArea ) << "High slope > 1.0 in PMPattern::setSlopeHiSlope\n"; + c = 1.0; + } + + if ( c != m_slopeHiSlope ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSlopeHiSlopeID, m_slopeHiSlope ); + m_slopeHiSlope = c; + } +} + +void PMPattern::setSlopeAltFlag( bool c ) +{ + if ( c != m_slopeAltFlag ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSlopeAltFlagID, m_slopeAltFlag ); + m_slopeAltFlag = c; + } +} + +void PMPattern::setSlopeAltitude( const PMVector& v ) +{ + if ( v != m_slopeAltitude ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSlopeAltitudeID, m_slopeAltitude ); + m_slopeAltitude = v; + } +} + +void PMPattern::setSlopeLoAlt( double c ) +{ + if ( c != m_slopeLoAlt ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSlopeLoAltID, m_slopeLoAlt ); + m_slopeLoAlt = c; + } +} + +void PMPattern::setSlopeHiAlt( double c ) +{ + if ( c != m_slopeHiAlt ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSlopeHiAltID, m_slopeHiAlt ); + m_slopeHiAlt = c; + } +} + +void PMPattern::setSpiralNumberArms( int c ) +{ + if( c != m_spiralNumberArms ) + { + if(m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSpiralNumberArmsID, m_spiralNumberArms ); + m_spiralNumberArms = c; + } +} + +void PMPattern::setNoiseGenerator( PMNoiseType c ) +{ + if( c != m_noiseGenerator ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMNoiseGeneratorID, m_noiseGenerator ); + m_noiseGenerator = c; + } +} + +void PMPattern::enableTurbulence( bool c ) +{ + if( c != m_enableTurbulence ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableTurbulenceID, m_enableTurbulence ); + m_enableTurbulence = c; + } +} + +void PMPattern::setValueVector( const PMVector& c ) +{ + if( c != m_valueVector ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMValueVectorID, m_valueVector ); + m_valueVector = c; + } +} + +void PMPattern::setOctaves( const int c ) +{ + if( c != m_octaves ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMOctavesID, m_octaves ); + m_octaves = c; + } +} + +void PMPattern::setOmega( const double c ) +{ + if( c != m_omega ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMOmegaID, m_omega ); + m_omega = c; + } +} + +void PMPattern::setLambda( const double c ) +{ + if( c != m_lambda ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMLambdaID, m_lambda ); + m_lambda = c; + } +} + +void PMPattern::setDepth( const double c ) +{ + if( c != m_depth ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMDepthID, m_depth ); + m_depth = c; + } +} + +PMDialogEditBase* PMPattern::editWidget( QWidget* parent ) const +{ + return new PMPatternEdit( parent ); +} + +void PMPattern::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMPatternTypeID: + setPatternType( ( PMPatternType )data->intData( ) ); + break; + + case PMAgateTurbulenceID: + setAgateTurbulence( data->doubleData( ) ); + break; + + case PMCrackleFormID: + setCrackleForm( data->vectorData( ) ); + break; + case PMCrackleMetricID: + setCrackleMetric( data->intData( ) ); + break; + case PMCrackleOffsetID: + setCrackleOffset( data->doubleData( ) ); + break; + case PMCrackleSolidID: + setCrackleSolid( data->boolData( ) ); + break; + + case PMDensityInterpolateID: + setDensityInterpolate( data->intData( ) ); + break; + case PMDensityFileID: + setDensityFile( data->stringData( ) ); + break; + + case PMGradientID: + setGradient( data->vectorData( ) ); + break; + + case PMJuliaComplexID: + setJuliaComplex( data->vectorData( ) ); + break; + case PMFractalMagnetID: + setFractalMagnet( data->boolData( ) ); + break; + case PMFractalMagnetTypeID: + setFractalMagnetType( data->intData( ) ); + break; + case PMMaxIterationsID: + setMaxIterations( data->intData( ) ); + break; + case PMFractalExponentID: + setFractalExponent( data->intData( ) ); + break; + case PMFractalExtTypeID: + setFractalExtType( data->intData( ) ); + break; + case PMFractalExtFactorID: + setFractalExtFactor( data->doubleData( ) ); + break; + case PMFractalIntTypeID: + setFractalIntType( data->intData( ) ); + break; + case PMFractalIntFactorID: + setFractalIntFactor( data->doubleData( ) ); + break; + + case PMQuiltControl0ID: + setQuiltControl0( data->doubleData( ) ); + break; + case PMQuiltControl1ID: + setQuiltControl1( data->doubleData( ) ); + break; + + case PMSlopeDirectionID: + setSlopeDirection( data->vectorData( ) ); + break; + case PMSlopeLoSlopeID: + setSlopeLoSlope( data->doubleData( ) ); + break; + case PMSlopeHiSlopeID: + setSlopeHiSlope( data->doubleData( ) ); + break; + case PMSlopeAltFlagID: + setSlopeAltFlag( data->boolData( ) ); + break; + case PMSlopeAltitudeID: + setSlopeAltitude( data->boolData( ) ); + break; + case PMSlopeLoAltID: + setSlopeLoAlt( data->intData( ) ); + break; + case PMSlopeHiAltID: + setSlopeHiAlt( data->intData( ) ); + break; + + case PMSpiralNumberArmsID: + setSpiralNumberArms( data->intData( ) ); + break; + + case PMNoiseGeneratorID: + setNoiseGenerator( ( PMNoiseType ) ( data->intData( ) ) ); + break; + + case PMEnableTurbulenceID: + enableTurbulence( data->boolData( ) ); + break; + case PMValueVectorID: + setValueVector( data->vectorData( ) ); + break; + case PMOctavesID: + setOctaves( data->intData( ) ); + break; + case PMOmegaID: + setOmega( data->doubleData( ) ); + break; + case PMLambdaID: + setLambda( data->doubleData( ) ); + break; + + case PMDepthID: + setDepth( data->doubleData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMPattern::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + diff --git a/kpovmodeler/pmpattern.h b/kpovmodeler/pmpattern.h new file mode 100644 index 00000000..69001a41 --- /dev/null +++ b/kpovmodeler/pmpattern.h @@ -0,0 +1,449 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMPATTERN_H +#define PMPATTERN_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmobject.h" +#include "pmvector.h" +#include "pmcolor.h" + +#include +#include + +/** + * Class for povray patterns. + */ +class PMPattern : public PMObject +{ + typedef PMObject Base; +public: + /** + * The type of the pattern + */ + enum PMPatternType { PatternAgate, PatternAverage, PatternBoxed, + PatternBozo, PatternBumps, PatternCells, + PatternCrackle, PatternCylindrical, PatternDensity, + PatternDents, PatternGradient, PatternGranite, + PatternJulia, PatternLeopard, PatternMandel, + PatternMarble, PatternOnion, PatternPlanar, + PatternQuilted, PatternRadial, PatternRipples, + PatternSlope, PatternSpherical, PatternSpiral1, + PatternSpiral2, PatternSpotted, PatternWaves, + PatternWood, PatternWrinkles }; + /** + * The noise generators + */ + enum PMNoiseType { GlobalSetting, Original, RangeCorrected, Perlin }; + /** + * Creates a PMPattern + */ + PMPattern( PMPart* part ); + /** + * Copy constructor + */ + PMPattern( const PMPattern& p ); + /** + * deletes the PMPattern + */ + virtual ~PMPattern( ); + + /** */ + virtual PMObject* copy( ) const { return new PMPattern( *this ); } + /** */ + virtual QString description( ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pmpattern" ); } + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMPatternEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + + /** + * Gets the pattern type + */ + PMPatternType patternType( ) const { return m_patternType; } + /** + * Gets the agate Turbulence*/ + double agateTurbulence( ) const { return m_agateTurbulence; } + /** + * Gets the crackle form + */ + PMVector crackleForm( ) const { return m_crackleForm; } + /** + * Gets the crackle metric + */ + int crackleMetric( ) const { return m_crackleMetric; } + /** + * Gets the crackle offset + */ + double crackleOffset( ) const { return m_crackleOffset; } + /** + * Gets the crackle solid flag + */ + bool crackleSolid( ) const { return m_crackleSolid; } + /** + * Gets the desity file name + */ + QString densityFile( ) const { return m_densityFile; } + /** + * Gets the density interpolation + */ + int densityInterpolate( ) const { return m_densityInterpolate; } + /** + * Gets the gradint vector + */ + PMVector gradient( ) const { return m_gradient; } + /** + * Returns the Complex number for Julia Fractals + */ + PMVector juliaComplex( ) const { return m_juliaComplex; } + /** + * Returns true if where using tha magnet types of fractals + */ + bool fractalMagnet( ) const { return m_fractalMagnet; } + /** + * Returns the magnet type of a fractal + */ + int fractalMagnetType( ) const { return m_fractalMagnetType; } + /** + * Gets the number of Iterations for fractals + */ + int maxIterations( ) const { return m_maxIterations; } + /** + * Returns the exponent of a fractal + */ + int fractalExponent( ) const { return m_fractalExponent; } + /** + * Returns the exterior type of a fractal + */ + int fractalExtType( ) const { return m_fractalExtType; } + /** + * Return the exterior factor of a fractal + */ + double fractalExtFactor( ) const { return m_fractalExtFactor; } + /** + * Returns the interior type of a fractal + */ + int fractalIntType( ) const { return m_fractalIntType; } + /** + * Returns the interior factor of a fractal + */ + double fractalIntFactor( ) const { return m_fractalIntFactor; } + /** + * Gets control0 for Quilt + */ + double quiltControl0( ) const { return m_quiltControl0; } + /** + * Gets control1 for Quilt + */ + double quiltControl1( ) const { return m_quiltControl1; } + /** + * Returns the slope direction + */ + PMVector slopeDirection( ) const { return m_slopeDirection; } + /** + * Returns the low slope value + */ + double slopeLoSlope( ) const { return m_slopeLoSlope; } + /** + * Returns the high slope value + */ + double slopeHiSlope( ) const { return m_slopeHiSlope; } + /** + * Returns the slopes altitude flag + */ + bool slopeAltFlag( ) const { return m_slopeAltFlag; } + /** + * Returns the altitude for the slope + */ + PMVector slopeAltitude( ) const { return m_slopeAltitude; } + /** + * Returns the low altitude for slope + */ + double slopeLoAltitude( ) const { return m_slopeLoAlt; } + /** + * Returns the high altitude for slope + */ + double slopeHiAltitude( ) const { return m_slopeHiAlt; } + /** + * Gets the number of arms in spiral types 1 and 2 + */ + int spiralNumberArms( ) const { return m_spiralNumberArms; } + /** + * Returns the noise generator + */ + PMNoiseType noiseGenerator( ) const { return m_noiseGenerator; }; + /** + * Returns whether turbulence is enabled + */ + bool isTurbulenceEnabled( ) const { return m_enableTurbulence; } + /** + * Gets the Turbulence vector + */ + PMVector valueVector( ) const { return m_valueVector; } + /** + * Gets the turbulence octaves + */ + int octaves( ) const { return m_octaves; } + /** + * Gets the turbulence omega + */ + double omega( ) const { return m_omega; } + /** + * Gets the turbulence lambda + */ + double lambda( ) const { return m_lambda; } + /** + * Returns depth (only has meaning inside a normal) + */ + double depth( ) const { return m_depth; } + + /** + * Sets the pattern type + */ + void setPatternType( PMPatternType l ); + /** + * Sets agate turbulence + */ + void setAgateTurbulence( double c ); + /** + * Sets the crackle form + */ + void setCrackleForm( const PMVector& v ); + /** + * Sets the crackle metric + */ + void setCrackleMetric( int c ); + /** + * Sets the crackle offset + */ + void setCrackleOffset( double c ); + /** + * Sets the crackle solid flag + */ + void setCrackleSolid( bool c ); + /** + * Sets the Density File Name + */ + void setDensityFile( const QString& v ); + /** + * Sets the density interpolation + */ + void setDensityInterpolate( int c ); + /** + * sets gradient vector + */ + void setGradient( const PMVector& v ); + /** + * Sets the complex number for Julia + */ + void setJuliaComplex( const PMVector& v ); + /** + * Sets if where using magnet types of fractals + */ + void setFractalMagnet( bool c ); + /** + * Sets the magnet type of a fractal + */ + void setFractalMagnetType( int c ); + /** + * Sets the maximum iterations for fractals + */ + void setMaxIterations( int c ); + /** + * Sets the exponent for fractals + */ + void setFractalExponent( int c ); + /** + * Sets the exterior type of fractals + */ + void setFractalExtType( int c ); + /** + * Sets the exterior factor of fractals + */ + void setFractalExtFactor( double c ); + /** + * Sets the interior type of fractals + */ + void setFractalIntType( int c ); + /** + * Sets the interior factor of fractals + */ + void setFractalIntFactor( double c ); + /** + * Sets quilt control 0 + */ + void setQuiltControl0( double c ); + /** + * Sets quite control 1 + */ + void setQuiltControl1( double c ); + /** + * Sets the slope direction + */ + void setSlopeDirection( const PMVector& v ); + /** + * Sets the low slope value + */ + void setSlopeLoSlope( double c ); + /** + * Sets the high slope value + */ + void setSlopeHiSlope( double c ); + /** + * Sets the slopes altitude flag + */ + void setSlopeAltFlag( bool c ); + /** + * Sets the slopes alititude direction + */ + void setSlopeAltitude( const PMVector& v ); + /** + * Sets the slopes low altitude + */ + void setSlopeLoAlt( double c ); + /** + * Sets the slopes high altitude + */ + void setSlopeHiAlt( double c ); + /** + * Sets the number of spiral arms + */ + void setSpiralNumberArms( int c ); + /** + * Sets noise generator + */ + void setNoiseGenerator( PMNoiseType c ); + /** + * Enables turbulence + */ + void enableTurbulence( bool c ); + /** + * sets the turbulence vector + */ + void setValueVector( const PMVector& v ); + /** + * Sets the turbulence octaves + */ + void setOctaves( int c ); + /** + * Sets the turblence omega + */ + void setOmega( double c ); + /** + * Sets the turbulence Lambda + */ + void setLambda( double c ); + /** + * Sets the depth value (only inside normals) + */ + void setDepth( double c ); + + /** */ + virtual void restoreMemento( PMMemento* s ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMPatternMementoID { PMPatternTypeID, PMAgateTurbulenceID, PMCrackleFormID, + PMCrackleMetricID, PMCrackleOffsetID, PMCrackleSolidID, + PMDensityFileID, PMDensityInterpolateID, PMGradientID, + PMJuliaComplexID, PMFractalMagnetID, PMFractalMagnetTypeID, + PMMaxIterationsID, PMFractalExponentID, PMFractalExtTypeID, + PMFractalExtFactorID, PMFractalIntTypeID, PMFractalIntFactorID, + PMQuiltControl0ID, PMQuiltControl1ID, PMSlopeDirectionID, + PMSlopeLoSlopeID, PMSlopeHiSlopeID, PMSlopeAltFlagID, + PMSlopeAltitudeID, PMSlopeLoAltID, PMSlopeHiAltID, + PMSpiralNumberArmsID, PMNoiseGeneratorID, PMEnableTurbulenceID, + PMValueVectorID, PMOctavesID, PMOmegaID, PMLambdaID, PMDepthID }; + /** + * Pattern type + */ + PMPatternType m_patternType; + + // Extra values for Individual Patterns + // Agate + double m_agateTurbulence; + // crackle + PMVector m_crackleForm; + int m_crackleMetric; + double m_crackleOffset; + bool m_crackleSolid; + // density + QString m_densityFile; + int m_densityInterpolate; + // gradient + PMVector m_gradient; + // Julia + PMVector m_juliaComplex; + // Fractal patterns Mandel and Julia + bool m_fractalMagnet; + int m_fractalMagnetType; + int m_maxIterations; + int m_fractalExponent; + int m_fractalExtType; + double m_fractalExtFactor; + int m_fractalIntType; + double m_fractalIntFactor; + // quilt + double m_quiltControl0; + double m_quiltControl1; + // slope + PMVector m_slopeDirection; + double m_slopeLoSlope; + double m_slopeHiSlope; + bool m_slopeAltFlag; + PMVector m_slopeAltitude; + double m_slopeLoAlt; + double m_slopeHiAlt; + // Spiral + int m_spiralNumberArms; + + // noise generator type for Bozo, Bumps, Granite and Wrinkles. + PMNoiseType m_noiseGenerator; + + // Turbulence available for all patterns + bool m_enableTurbulence; + PMVector m_valueVector; + int m_octaves; + double m_omega; + double m_lambda; + // depth when used with Normal + double m_depth; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmpatternedit.cpp b/kpovmodeler/pmpatternedit.cpp new file mode 100644 index 00000000..1f9647c2 --- /dev/null +++ b/kpovmodeler/pmpatternedit.cpp @@ -0,0 +1,1073 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmpatternedit.h" +#include "pmpattern.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" +#include "pmvector.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +PMPatternEdit::PMPatternEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMPatternEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QGridLayout* layout; + QHBoxLayout* hl; + QVBoxLayout* vl; + QGridLayout* gl; + + layout = new QGridLayout( topLayout( ), 12, 2 ); + hl = new QHBoxLayout( KDialog::spacingHint( ) ); + hl->addWidget( new QLabel( i18n( "Type:" ), this ) ); + m_pTypeCombo = new QComboBox( false, this ); + m_pTypeCombo->insertItem( i18n( "Agate" ) ); + m_pTypeCombo->insertItem( i18n( "Average" ) ); + m_pTypeCombo->insertItem( i18n( "Boxed" ) ); + m_pTypeCombo->insertItem( i18n( "Bozo" ) ); + m_pTypeCombo->insertItem( i18n( "Bumps" ) ); + m_pTypeCombo->insertItem( i18n( "Cells" ) ); + m_pTypeCombo->insertItem( i18n( "Crackle" ) ); + m_pTypeCombo->insertItem( i18n( "Cylindrical" ) ); + m_pTypeCombo->insertItem( i18n( "Density File" ) ); + m_pTypeCombo->insertItem( i18n( "Dents" ) ); + m_pTypeCombo->insertItem( i18n( "Gradient" ) ); + m_pTypeCombo->insertItem( i18n( "Granite" ) ); + m_pTypeCombo->insertItem( i18n( "Julia" ) ); + m_pTypeCombo->insertItem( i18n( "Leopard" ) ); + m_pTypeCombo->insertItem( i18n( "Mandel" ) ); + m_pTypeCombo->insertItem( i18n( "Marble" ) ); + m_pTypeCombo->insertItem( i18n( "Onion" ) ); + m_pTypeCombo->insertItem( i18n( "Planar" ) ); + m_pTypeCombo->insertItem( i18n( "Quilt" ) ); + m_pTypeCombo->insertItem( i18n( "Radial" ) ); + m_pTypeCombo->insertItem( i18n( "Ripples" ) ); + m_pTypeCombo->insertItem( i18n( "Slope" ) ); + m_pTypeCombo->insertItem( i18n( "Spherical" ) ); + m_pTypeCombo->insertItem( i18n( "Spiral1" ) ); + m_pTypeCombo->insertItem( i18n( "Spiral2" ) ); + m_pTypeCombo->insertItem( i18n( "Spotted" ) ); + m_pTypeCombo->insertItem( i18n( "Waves" ) ); + m_pTypeCombo->insertItem( i18n( "Wood" ) ); + m_pTypeCombo->insertItem( i18n( "Wrinkles" ) ); + hl->addWidget( m_pTypeCombo ); + hl->addStretch( 1 ); + layout->addMultiCellLayout( hl, 0, 0, 0, 1 ); + + m_pAgateTurbulenceLabel = new QLabel( i18n( "Turbulence:" ), this ); + layout->addWidget( m_pAgateTurbulenceLabel, 1, 0 ); + m_pAgateTurbulenceEdit = new PMFloatEdit( this ); + layout->addWidget( m_pAgateTurbulenceEdit, 1, 1, AlignLeft ); + + m_pCrackleWidget = new QWidget( this ); + vl = new QVBoxLayout( m_pCrackleWidget, 0, KDialog::spacingHint( ) ); + hl = new QHBoxLayout( vl ); + hl->addWidget( new QLabel( i18n( "Form:" ), m_pCrackleWidget ) ); + m_pCrackleForm = new PMVectorEdit( "x", "y", "z", m_pCrackleWidget ); + hl->addWidget( m_pCrackleForm ); + hl->addStretch( 1 ); + hl = new QHBoxLayout( vl ); + gl = new QGridLayout( hl, 3, 2 ); + gl->addWidget( new QLabel( i18n( "Metric:" ), m_pCrackleWidget ), 0, 0 ); + m_pCrackleMetric = new PMIntEdit( m_pCrackleWidget ); + m_pCrackleMetric->setValidation( true, 1, false, 0 ); + gl->addWidget( m_pCrackleMetric, 0, 1 ); + gl->addWidget( new QLabel( i18n( "Offset:" ), m_pCrackleWidget ), 1, 0 ); + m_pCrackleOffset = new PMFloatEdit( m_pCrackleWidget ); + gl->addWidget( m_pCrackleOffset, 1, 1 ); + m_pCrackleSolid = new QCheckBox( i18n( "Solid:" ), m_pCrackleWidget ); + gl->addMultiCellWidget( m_pCrackleSolid, 2, 2, 0, 1 ); + hl->addStretch( 1 ); + layout->addMultiCellWidget( m_pCrackleWidget, 2, 2, 0, 1 ); + + m_pDensityWidget = new QWidget( this ); + vl = new QVBoxLayout( m_pDensityWidget, 0, KDialog::spacingHint( ) ); + hl = new QHBoxLayout( vl ); + hl->addWidget( new QLabel( i18n( "File:" ), m_pDensityWidget ) ); + m_pDensityFile = new QLineEdit( m_pDensityWidget ); + hl->addWidget( m_pDensityFile, 1 ); + m_pDensityFileBrowse = new QPushButton( m_pDensityWidget ); + m_pDensityFileBrowse->setPixmap( SmallIcon( "fileopen" ) ); + hl->addWidget( m_pDensityFileBrowse ); + hl = new QHBoxLayout( vl ); + hl->addWidget( new QLabel( i18n( "Interpolation:" ), m_pDensityWidget ) ); + m_pDensityInterpolate = new QComboBox( false, m_pDensityWidget ); + m_pDensityInterpolate->insertItem( i18n( "None" ) ); + m_pDensityInterpolate->insertItem( i18n( "Trilinear" ) ); + hl->addWidget( m_pDensityInterpolate ); + hl->addStretch( 1 ); + layout->addMultiCellWidget( m_pDensityWidget, 3, 3, 0, 1 ); + + m_pGradientLabel = new QLabel( i18n( "Gradient:" ), this ); + layout->addWidget( m_pGradientLabel, 4, 0 ); + m_pGradientEdit = new PMVectorEdit( "x", "y", "z", this ); + layout->addWidget( m_pGradientEdit, 4, 1 ); + + m_pJuliaComplexLabel = new QLabel( i18n( "Complex number:" ), this ); + layout->addWidget( m_pJuliaComplexLabel, 5, 0 ); + m_pJuliaComplex = new PMVectorEdit( "Real", "Imaginary", this ); + layout->addWidget( m_pJuliaComplex, 5, 1 ); + + m_pFractalWidget = new QWidget( this ); + vl = new QVBoxLayout( m_pFractalWidget, 0, KDialog::spacingHint( ) ); + hl = new QHBoxLayout( vl ); + m_pFractalMagnet = new QCheckBox( i18n( "Magnet" ), m_pFractalWidget ); + hl->addWidget( m_pFractalMagnet ); + m_pFractalMagnetType = new QComboBox( false, m_pFractalWidget ); + m_pFractalMagnetType->insertItem( i18n( "Type 1" ) ); + m_pFractalMagnetType->insertItem( i18n( "Type 2" ) ); + hl->addWidget( m_pFractalMagnetType ); + hl->addStretch( 1 ); + hl = new QHBoxLayout( vl ); + gl = new QGridLayout( hl, 2, 2 ); + gl->addWidget( new QLabel( i18n( "Maximum iterations:" ), m_pFractalWidget ), 0, 0 ); + m_pMaxIterationsEdit = new PMIntEdit( m_pFractalWidget ); + m_pMaxIterationsEdit->setValidation( true, 1, false, 0 ); + gl->addWidget( m_pMaxIterationsEdit, 0, 1 ); + m_pFractalExponentLabel = new QLabel( i18n( "Exponent:" ), m_pFractalWidget ); + gl->addWidget( m_pFractalExponentLabel, 1, 0 ); + m_pFractalExponent = new PMIntEdit( m_pFractalWidget ); + m_pFractalExponent->setValidation( true, 2, true, 33 ); + gl->addWidget( m_pFractalExponent, 1, 1 ); + hl->addStretch( 1 ); + hl = new QHBoxLayout( vl ); + gl = new QGridLayout( hl, 2, 4 ); + gl->addWidget( new QLabel( i18n( "Exterior type:" ), m_pFractalWidget ), 0, 0 ); + m_pFractalExtType = new QComboBox( false, m_pFractalWidget ); + m_pFractalExtType->insertItem( i18n( "0: Returns Just 1" ) ); + m_pFractalExtType->insertItem( i18n( "1: Iterations Until Bailout" ) ); + m_pFractalExtType->insertItem( i18n( "2: Real Part" ) ); + m_pFractalExtType->insertItem( i18n( "3: Imaginary Part" ) ); + m_pFractalExtType->insertItem( i18n( "4: Squared Real Part" ) ); + m_pFractalExtType->insertItem( i18n( "5: Squared Imaginary Part" ) ); + m_pFractalExtType->insertItem( i18n( "6: Absolute Value" ) ); + gl->addWidget( m_pFractalExtType, 0, 1 ); + gl->addWidget( new QLabel( i18n( "Factor:" ), m_pFractalWidget ), 0, 2 ); + m_pFractalExtFactor = new PMFloatEdit( m_pFractalWidget ); + gl->addWidget( m_pFractalExtFactor, 0, 3 ); + gl->addWidget( new QLabel( i18n( "Interior type:" ), m_pFractalWidget ), 1, 0 ); + m_pFractalIntType = new QComboBox( false, m_pFractalWidget ); + m_pFractalIntType->insertItem( i18n( "0: Returns Just 1" ) ); + m_pFractalIntType->insertItem( i18n( "1: Absolute Value Smallest" ) ); + m_pFractalIntType->insertItem( i18n( "2: Real Part" ) ); + m_pFractalIntType->insertItem( i18n( "3: Imaginary Part" ) ); + m_pFractalIntType->insertItem( i18n( "4: Squared Real Part" ) ); + m_pFractalIntType->insertItem( i18n( "5: Squared Imaginary Part" ) ); + m_pFractalIntType->insertItem( i18n( "6: Absolute Value Last" ) ); + gl->addWidget( m_pFractalIntType, 1, 1 ); + gl->addWidget( new QLabel( i18n( "Factor:" ), m_pFractalWidget ), 1, 2 ); + m_pFractalIntFactor = new PMFloatEdit( m_pFractalWidget ); + gl->addWidget( m_pFractalIntFactor, 1, 3 ); + hl->addStretch( 1 ); + layout->addMultiCellWidget( m_pFractalWidget, 6, 6, 0, 1 ); + + m_pQuiltControlsLabel = new QLabel( i18n( "Quilt controls:" ), this ); + m_pQuiltControl0Edit = new PMFloatEdit( this ); + m_pQuiltControl1Edit = new PMFloatEdit( this ); + hl = new QHBoxLayout( ); + hl->addWidget( m_pQuiltControl0Edit ); + hl->addWidget( m_pQuiltControl1Edit ); + hl->addStretch( 1 ); + layout->addWidget( m_pQuiltControlsLabel, 7, 0 ); + layout->addLayout( hl, 7, 1 ); + + m_pSlopeWidget = new QWidget( this ); + vl = new QVBoxLayout( m_pSlopeWidget, 0, KDialog::spacingHint( ) ); + hl = new QHBoxLayout( vl ); + hl->addWidget( new QLabel( i18n( "Direction:" ), m_pSlopeWidget ) ); + m_pSlopeDirection = new PMVectorEdit( "x", "y", "z", m_pSlopeWidget ); + hl->addWidget( m_pSlopeDirection ); + hl = new QHBoxLayout( vl ); + gl = new QGridLayout( hl, 2, 2 ); + gl->addWidget( new QLabel( i18n( "Low slope:" ), m_pSlopeWidget ), 0, 0 ); + m_pSlopeLoSlope = new PMFloatEdit( m_pSlopeWidget ); + m_pSlopeLoSlope->setValidation( true, 0.0, true, 1.0 ); + gl->addWidget( m_pSlopeLoSlope, 0, 1 ); + gl->addWidget( new QLabel( i18n( "High slope:" ), m_pSlopeWidget ), 1, 0 ); + m_pSlopeHiSlope = new PMFloatEdit( m_pSlopeWidget ); + m_pSlopeHiSlope->setValidation( true, 0.0, true, 1.0 ); + gl->addWidget( m_pSlopeHiSlope, 1, 1 ); + hl->addStretch( 1 ); + hl = new QHBoxLayout( vl ); + m_pSlopeAltFlag = new QCheckBox( i18n( "Altitiude" ), m_pSlopeWidget ); + hl->addWidget( m_pSlopeAltFlag ); + m_pSlopeAltitude = new PMVectorEdit( "x", "y", "z", m_pSlopeWidget ); + hl->addWidget( m_pSlopeAltitude ); + hl = new QHBoxLayout( vl ); + gl = new QGridLayout( hl, 2, 2 ); + m_pSlopeLoAltLabel = new QLabel( i18n( "Low altitude:" ), m_pSlopeWidget ); + gl->addWidget( m_pSlopeLoAltLabel, 0, 0 ); + m_pSlopeLoAlt = new PMFloatEdit( m_pSlopeWidget ); + gl->addWidget( m_pSlopeLoAlt, 0, 1 ); + m_pSlopeHiAltLabel = new QLabel( i18n( "High altitude:" ), m_pSlopeWidget ); + gl->addWidget( m_pSlopeHiAltLabel, 1, 0 ); + m_pSlopeHiAlt = new PMFloatEdit( m_pSlopeWidget ); + gl->addWidget( m_pSlopeHiAlt, 1, 1 ); + hl->addStretch( 1 ); + layout->addMultiCellWidget( m_pSlopeWidget, 8, 8, 0, 1 ); + + m_pSpiralNumberLabel = new QLabel( i18n( "Spiral number:" ), this ); + m_pSpiralNumberEdit = new PMIntEdit( this ); + layout->addWidget( m_pSpiralNumberLabel, 9, 0 ); + layout->addWidget( m_pSpiralNumberEdit, 9, 1, AlignLeft ); + + m_pDepthLabel = new QLabel( i18n( "Depth:" ), this ); + m_pDepthEdit = new PMFloatEdit( this ); + layout->addWidget( m_pDepthLabel, 10, 0 ); + layout->addWidget( m_pDepthEdit, 10, 1, AlignLeft ); + + m_pNoiseGeneratorLabel = new QLabel( i18n( "Noise generator:" ), this ); + m_pNoiseGenerator = new QComboBox( false, this ); + m_pNoiseGenerator->insertItem( i18n( "Use Global Setting" ) ); + m_pNoiseGenerator->insertItem( i18n( "Original" ) ); + m_pNoiseGenerator->insertItem( i18n( "Range Corrected" ) ); + m_pNoiseGenerator->insertItem( i18n( "Perlin" ) ); + layout->addWidget( m_pNoiseGeneratorLabel, 11, 0 ); + layout->addWidget( m_pNoiseGenerator, 11, 1 ); + + m_pEnableTurbulenceEdit = new QCheckBox( i18n( "Turbulence" ), this ); + topLayout( )->addWidget( m_pEnableTurbulenceEdit ); + m_pTurbulenceWidget = new QWidget( this ); + vl = new QVBoxLayout( m_pTurbulenceWidget, 0, KDialog::spacingHint( ) ); + hl = new QHBoxLayout( vl ); + hl->addWidget( new QLabel( i18n( "Value:" ), m_pTurbulenceWidget ) ); + m_pValueVectorEdit = new PMVectorEdit( "x", "y", "z", m_pTurbulenceWidget ); + hl->addWidget( m_pValueVectorEdit ); + hl = new QHBoxLayout( vl ); + gl = new QGridLayout( hl, 3, 2 ); + gl->addWidget( new QLabel( i18n( "Octaves:" ), m_pTurbulenceWidget ), 0, 0 ); + m_pOctavesEdit = new PMIntEdit( m_pTurbulenceWidget ); + gl->addWidget( m_pOctavesEdit, 0, 1 ); + gl->addWidget( new QLabel( i18n( "Omega:" ), m_pTurbulenceWidget ), 1, 0 ); + m_pOmegaEdit = new PMFloatEdit( m_pTurbulenceWidget ); + gl->addWidget( m_pOmegaEdit, 1, 1 ); + gl->addWidget( new QLabel( i18n( "Lambda:" ), m_pTurbulenceWidget ), 2, 0 ); + m_pLambdaEdit = new PMFloatEdit( m_pTurbulenceWidget ); + gl->addWidget( m_pLambdaEdit, 2, 1 ); + hl->addStretch( 1 ); + topLayout( )->addWidget( m_pTurbulenceWidget ); + + /* connect all signals to slots/signals */ + connect( m_pTypeCombo, SIGNAL( activated( int ) ), SLOT( slotComboChanged( int ) ) ); + + connect( m_pAgateTurbulenceEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + + connect( m_pCrackleForm, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pCrackleMetric, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pCrackleOffset, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pCrackleSolid, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + + connect( m_pDensityInterpolate, SIGNAL( activated( int ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pDensityFile, SIGNAL( textChanged( const QString& ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pDensityFileBrowse, SIGNAL( clicked( ) ), SLOT( slotDensityFileBrowseClicked( ) ) ); + + connect( m_pGradientEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + + connect( m_pJuliaComplex, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pFractalMagnet, SIGNAL( clicked( ) ), SLOT( slotFractalMagnetClicked( ) ) ); + connect( m_pFractalMagnetType, SIGNAL( activated( int ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pMaxIterationsEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pFractalExponent, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pFractalExtType, SIGNAL( activated( int ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pFractalExtFactor, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pFractalIntType, SIGNAL( activated( int ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pFractalIntFactor, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + + connect( m_pQuiltControl0Edit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pQuiltControl1Edit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + + connect( m_pSlopeDirection, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pSlopeLoSlope, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pSlopeHiSlope, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pSlopeAltFlag, SIGNAL( clicked( ) ), SLOT( slotSlopeAltFlagClicked( ) ) ); + connect( m_pSlopeAltitude, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pSlopeLoAlt, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pSlopeHiAlt, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + + connect( m_pSpiralNumberEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + + connect( m_pNoiseGenerator, SIGNAL( activated( int ) ), SIGNAL( dataChanged( ) ) ); + + connect( m_pEnableTurbulenceEdit, SIGNAL( clicked( ) ), SLOT( slotTurbulenceClicked( ) ) ); + connect( m_pValueVectorEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pOctavesEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pOmegaEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pLambdaEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pDepthEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMPatternEdit::displayObject( PMObject* o ) +{ + QString str; + bool readOnly; + + if( o->isA( "Pattern" ) ) + { + m_pDisplayedObject = ( PMPattern* ) o; + readOnly = m_pDisplayedObject->isReadOnly( ); + + switch( m_pDisplayedObject->patternType( ) ) + { + case PMPattern::PatternAgate: + setPatternType( 0 ); + break; + case PMPattern::PatternAverage: + setPatternType( 1 ); + break; + case PMPattern::PatternBoxed: + setPatternType( 2 ); + break; + case PMPattern::PatternBozo: + setPatternType( 3 ); + break; + case PMPattern::PatternBumps: + setPatternType( 4 ); + break; + case PMPattern::PatternCells: + setPatternType( 5 ); + break; + case PMPattern::PatternCrackle: + setPatternType( 6 ); + break; + case PMPattern::PatternCylindrical: + setPatternType( 7 ); + break; + case PMPattern::PatternDensity: + setPatternType( 8 ); + break; + case PMPattern::PatternDents: + setPatternType( 9 ); + break; + case PMPattern::PatternGradient: + setPatternType( 10 ); + break; + case PMPattern::PatternGranite: + setPatternType( 11 ); + break; + case PMPattern::PatternJulia: + setPatternType( 12 ); + break; + case PMPattern::PatternLeopard: + setPatternType( 13 ); + break; + case PMPattern::PatternMandel: + setPatternType( 14 ); + break; + case PMPattern::PatternMarble: + setPatternType( 15 ); + break; + case PMPattern::PatternOnion: + setPatternType( 16 ); + break; + case PMPattern::PatternPlanar: + setPatternType( 17 ); + break; + case PMPattern::PatternQuilted: + setPatternType( 18 ); + break; + case PMPattern::PatternRadial: + setPatternType( 19 ); + break; + case PMPattern::PatternRipples: + setPatternType( 20 ); + break; + case PMPattern::PatternSlope: + setPatternType( 21 ); + break; + case PMPattern::PatternSpherical: + setPatternType( 22 ); + break; + case PMPattern::PatternSpiral1: + setPatternType( 23 ); + break; + case PMPattern::PatternSpiral2: + setPatternType( 24 ); + break; + case PMPattern::PatternSpotted: + setPatternType( 25 ); + break; + case PMPattern::PatternWaves: + setPatternType( 26 ); + break; + case PMPattern::PatternWood: + setPatternType( 27 ); + break; + case PMPattern::PatternWrinkles: + setPatternType( 28 ); + break; + } + m_pTypeCombo->setEnabled( !readOnly ); + + m_pAgateTurbulenceEdit->setValue( m_pDisplayedObject->agateTurbulence( ) ); + m_pAgateTurbulenceEdit->setReadOnly( readOnly ); + + m_pCrackleForm->setVector( m_pDisplayedObject->crackleForm( ) ); + m_pCrackleForm->setReadOnly( readOnly ); + m_pCrackleMetric->setValue( m_pDisplayedObject->crackleMetric( ) ); + m_pCrackleMetric->setReadOnly( readOnly ); + m_pCrackleOffset->setValue( m_pDisplayedObject->crackleOffset( ) ); + m_pCrackleOffset->setReadOnly( readOnly ); + m_pCrackleSolid->setChecked( m_pDisplayedObject->crackleSolid( ) ); + m_pCrackleSolid->setEnabled( !readOnly ); + + m_pDensityFile->setText( m_pDisplayedObject->densityFile( ) ); + m_pDensityFile->setEnabled( !readOnly ); + m_pDensityInterpolate->setCurrentItem( m_pDisplayedObject->densityInterpolate( ) ); + m_pDensityInterpolate->setEnabled( !readOnly ); + + m_pGradientEdit->setVector( m_pDisplayedObject->gradient( ) ); + m_pGradientEdit->setReadOnly( readOnly ); + + m_pJuliaComplex->setVector( m_pDisplayedObject->juliaComplex( ) ); + m_pJuliaComplex->setReadOnly( readOnly ); + m_pFractalMagnet->setChecked( m_pDisplayedObject->fractalMagnet( ) ); + m_pFractalMagnet->setEnabled( !readOnly ); + m_pFractalMagnetType->setCurrentItem( m_pDisplayedObject->fractalMagnetType( ) - 1 ); + m_pFractalMagnetType->setEnabled( !readOnly ); + m_pMaxIterationsEdit->setValue( m_pDisplayedObject->maxIterations( ) ); + m_pMaxIterationsEdit->setReadOnly( readOnly ); + m_pFractalExponent->setValue( m_pDisplayedObject->fractalExponent( ) ); + m_pFractalExponent->setReadOnly( readOnly ); + m_pFractalExtType->setCurrentItem( m_pDisplayedObject->fractalExtType( ) ); + m_pFractalExtType->setEnabled( !readOnly ); + m_pFractalExtFactor->setValue( m_pDisplayedObject->fractalExtFactor( ) ); + m_pFractalExtFactor->setReadOnly( readOnly ); + m_pFractalIntType->setCurrentItem( m_pDisplayedObject->fractalIntType( ) ); + m_pFractalIntType->setEnabled( !readOnly ); + m_pFractalIntFactor->setValue( m_pDisplayedObject->fractalIntFactor( ) ); + m_pFractalIntFactor->setReadOnly( readOnly ); + + m_pQuiltControl0Edit->setValue( m_pDisplayedObject->quiltControl0( ) ); + m_pQuiltControl0Edit->setReadOnly( readOnly ); + m_pQuiltControl1Edit->setValue( m_pDisplayedObject->quiltControl1( ) ); + m_pQuiltControl1Edit->setReadOnly( readOnly ); + + m_pSlopeDirection->setVector( m_pDisplayedObject->slopeDirection( ) ); + m_pSlopeDirection->setReadOnly( readOnly ); + m_pSlopeLoSlope->setValue( m_pDisplayedObject->slopeLoSlope( ) ); + m_pSlopeLoSlope->setReadOnly( readOnly ); + m_pSlopeHiSlope->setValue( m_pDisplayedObject->slopeHiSlope( ) ); + m_pSlopeHiSlope->setReadOnly( readOnly ); + m_pSlopeAltFlag->setChecked( m_pDisplayedObject->slopeAltFlag( ) ); + m_pSlopeAltFlag->setEnabled( !readOnly ); + m_pSlopeAltitude->setVector( m_pDisplayedObject->slopeAltitude( ) ); + m_pSlopeAltitude->setReadOnly( readOnly ); + m_pSlopeLoAlt->setValue( m_pDisplayedObject->slopeLoAltitude( ) ); + m_pSlopeLoAlt->setReadOnly( readOnly ); + m_pSlopeHiAlt->setValue( m_pDisplayedObject->slopeHiAltitude( ) ); + m_pSlopeHiAlt->setReadOnly( readOnly ); + + m_pSpiralNumberEdit->setValue( m_pDisplayedObject->spiralNumberArms( ) ); + m_pSpiralNumberEdit->setReadOnly( readOnly ); + + m_pNoiseGenerator->setCurrentItem( m_pDisplayedObject->noiseGenerator( ) ); + m_pNoiseGenerator->setEnabled( !readOnly ); + + m_pEnableTurbulenceEdit->setChecked( m_pDisplayedObject->isTurbulenceEnabled( ) ); + m_pEnableTurbulenceEdit->setEnabled( !readOnly ); + m_pValueVectorEdit->setVector( m_pDisplayedObject->valueVector( ) ); + m_pValueVectorEdit->setReadOnly( readOnly ); + m_pOctavesEdit->setValue( m_pDisplayedObject->octaves( ) ); + m_pOctavesEdit->setReadOnly( readOnly ); + m_pOmegaEdit->setValue( m_pDisplayedObject->omega( ) ); + m_pOmegaEdit->setReadOnly( readOnly ); + m_pLambdaEdit->setValue( m_pDisplayedObject->lambda( ) ); + m_pLambdaEdit->setReadOnly( readOnly ); + + if( o->parent( ) && ( o->parent( )->type( ) == "Normal" ) ) + { + m_pDepthEdit->setValue( m_pDisplayedObject->depth( ) ); + m_pDepthEdit->setReadOnly( readOnly ); + m_pDepthEdit->show( ); + m_pDepthLabel->show( ); + emit sizeChanged( ); + } + else + { + m_pDepthEdit->hide( ); + m_pDepthLabel->hide( ); + emit sizeChanged( ); + } + + slotFractalMagnetClicked( ); + slotSlopeAltFlagClicked( ); + slotTurbulenceClicked( ); + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMPatternEdit: Can't display object\n"; +} + +void PMPatternEdit::setPatternType( int i ) +{ + m_pTypeCombo->setCurrentItem( i ); + slotComboChanged( i ); +} + +void PMPatternEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + switch( m_pTypeCombo->currentItem( ) ) + { + case 0: + m_pDisplayedObject->setPatternType( PMPattern::PatternAgate ); + m_pDisplayedObject->setAgateTurbulence( m_pAgateTurbulenceEdit->value( ) ); + break; + case 1: + m_pDisplayedObject->setPatternType( PMPattern::PatternAverage ); + break; + case 2: + m_pDisplayedObject->setPatternType( PMPattern::PatternBoxed ); + break; + case 3: + m_pDisplayedObject->setPatternType( PMPattern::PatternBozo ); + m_pDisplayedObject->setNoiseGenerator( + ( PMPattern::PMNoiseType ) m_pNoiseGenerator->currentItem( ) ); + break; + case 4: + m_pDisplayedObject->setPatternType( PMPattern::PatternBumps ); + m_pDisplayedObject->setNoiseGenerator( + ( PMPattern::PMNoiseType ) m_pNoiseGenerator->currentItem( ) ); + break; + case 5: + m_pDisplayedObject->setPatternType( PMPattern::PatternCells ); + break; + case 6: + m_pDisplayedObject->setPatternType( PMPattern::PatternCrackle ); + m_pDisplayedObject->setCrackleForm( m_pCrackleForm->vector( ) ); + m_pDisplayedObject->setCrackleMetric( m_pCrackleMetric->value( ) ); + m_pDisplayedObject->setCrackleOffset( m_pCrackleOffset->value( ) ); + m_pDisplayedObject->setCrackleSolid( m_pCrackleSolid->isChecked( ) ); + break; + case 7: + m_pDisplayedObject->setPatternType( PMPattern::PatternCylindrical ); + break; + case 8: + m_pDisplayedObject->setPatternType( PMPattern::PatternDensity ); + m_pDisplayedObject->setDensityFile( m_pDensityFile->text( ) ); + m_pDisplayedObject->setDensityInterpolate( m_pDensityInterpolate->currentItem( ) ); + break; + case 9: + m_pDisplayedObject->setPatternType( PMPattern::PatternDents ); + break; + case 10: + m_pDisplayedObject->setPatternType( PMPattern::PatternGradient ); + m_pDisplayedObject->setGradient( m_pGradientEdit->vector( ) ); + break; + case 11: + m_pDisplayedObject->setPatternType( PMPattern::PatternGranite ); + m_pDisplayedObject->setNoiseGenerator( + ( PMPattern::PMNoiseType ) m_pNoiseGenerator->currentItem( ) ); + break; + case 12: + m_pDisplayedObject->setPatternType( PMPattern::PatternJulia ); + m_pDisplayedObject->setJuliaComplex( m_pJuliaComplex->vector( ) ); + m_pDisplayedObject->setFractalMagnet( m_pFractalMagnet->isChecked( ) ); + m_pDisplayedObject->setFractalMagnetType( m_pFractalMagnetType->currentItem( ) + 1 ); + m_pDisplayedObject->setMaxIterations( m_pMaxIterationsEdit->value( ) ); + m_pDisplayedObject->setFractalExponent( m_pFractalExponent->value( ) ); + m_pDisplayedObject->setFractalExtType( m_pFractalExtType->currentItem( ) ); + m_pDisplayedObject->setFractalExtFactor( m_pFractalExtFactor->value( ) ); + m_pDisplayedObject->setFractalIntType( m_pFractalIntType->currentItem( ) ); + m_pDisplayedObject->setFractalIntFactor( m_pFractalIntFactor->value( ) ); + break; + case 13: + m_pDisplayedObject->setPatternType( PMPattern::PatternLeopard ); + break; + case 14: + m_pDisplayedObject->setPatternType( PMPattern::PatternMandel ); + m_pDisplayedObject->setFractalMagnet( m_pFractalMagnet->isChecked( ) ); + m_pDisplayedObject->setFractalMagnetType( m_pFractalMagnetType->currentItem( ) + 1 ); + m_pDisplayedObject->setMaxIterations( m_pMaxIterationsEdit->value( ) ); + m_pDisplayedObject->setFractalExponent( m_pFractalExponent->value( ) ); + m_pDisplayedObject->setFractalExtType( m_pFractalExtType->currentItem( ) ); + m_pDisplayedObject->setFractalExtFactor( m_pFractalExtFactor->value( ) ); + m_pDisplayedObject->setFractalIntType( m_pFractalIntType->currentItem( ) ); + m_pDisplayedObject->setFractalIntFactor( m_pFractalIntFactor->value( ) ); + break; + case 15: + m_pDisplayedObject->setPatternType( PMPattern::PatternMarble ); + break; + case 16: + m_pDisplayedObject->setPatternType( PMPattern::PatternOnion ); + break; + case 17: + m_pDisplayedObject->setPatternType( PMPattern::PatternPlanar ); + break; + case 18: + m_pDisplayedObject->setPatternType( PMPattern::PatternQuilted ); + m_pDisplayedObject->setQuiltControl0( m_pQuiltControl0Edit->value( ) ); + m_pDisplayedObject->setQuiltControl1( m_pQuiltControl1Edit->value( ) ); + break; + case 19: + m_pDisplayedObject->setPatternType( PMPattern::PatternRadial ); + break; + case 20: + m_pDisplayedObject->setPatternType( PMPattern::PatternRipples ); + break; + case 21: + m_pDisplayedObject->setPatternType( PMPattern::PatternSlope ); + m_pDisplayedObject->setSlopeDirection( m_pSlopeDirection->vector( ) ); + m_pDisplayedObject->setSlopeLoSlope( m_pSlopeLoSlope->value( ) ); + m_pDisplayedObject->setSlopeHiSlope( m_pSlopeHiSlope->value( ) ); + m_pDisplayedObject->setSlopeAltFlag( m_pSlopeAltFlag->isChecked( ) ); + m_pDisplayedObject->setSlopeAltitude( m_pSlopeAltitude->vector( ) ); + m_pDisplayedObject->setSlopeLoAlt( m_pSlopeLoAlt->value( ) ); + m_pDisplayedObject->setSlopeHiAlt( m_pSlopeHiAlt->value( ) ); + break; + case 22: + m_pDisplayedObject->setPatternType( PMPattern::PatternSpherical ); + break; + case 23: + m_pDisplayedObject->setPatternType( PMPattern::PatternSpiral1 ); + m_pDisplayedObject->setSpiralNumberArms( m_pSpiralNumberEdit->value( ) ); + break; + case 24: + m_pDisplayedObject->setPatternType( PMPattern::PatternSpiral2 ); + m_pDisplayedObject->setSpiralNumberArms( m_pSpiralNumberEdit->value( ) ); + break; + case 25: + m_pDisplayedObject->setPatternType( PMPattern::PatternSpotted ); + break; + case 26: + m_pDisplayedObject->setPatternType( PMPattern::PatternWaves ); + break; + case 27: + m_pDisplayedObject->setPatternType( PMPattern::PatternWood ); + break; + case 28: + m_pDisplayedObject->setPatternType( PMPattern::PatternWrinkles ); + m_pDisplayedObject->setNoiseGenerator( + ( PMPattern::PMNoiseType ) m_pNoiseGenerator->currentItem( ) ); + break; + } + m_pDisplayedObject->enableTurbulence( m_pEnableTurbulenceEdit->isChecked( ) ); + m_pDisplayedObject->setValueVector( m_pValueVectorEdit->vector( ) ); + m_pDisplayedObject->setOctaves( m_pOctavesEdit->value( ) ); + m_pDisplayedObject->setOmega( m_pOmegaEdit->value( ) ); + m_pDisplayedObject->setLambda( m_pLambdaEdit->value( ) ); + + if( m_pDisplayedObject->parent( ) && + ( m_pDisplayedObject->parent( )->type( ) == "Normal" ) ) + m_pDisplayedObject->setDepth( m_pDepthEdit->value( ) ); + } +} + +bool PMPatternEdit::isDataValid( ) +{ + switch( m_pTypeCombo->currentItem( ) ) + { + case 0: // Agate + if( !m_pAgateTurbulenceEdit->isDataValid( ) ) + return false; + break; + case 6: // Crackle + if ( !m_pCrackleMetric->isDataValid( ) ) + return false; + break; + case 10: // Gradient + if( !m_pGradientEdit->isDataValid( ) ) + return false; + break; + case 12: // Julia + case 14: // Mandel + if ( !m_pMaxIterationsEdit->isDataValid( ) ) + return false; + if ( !m_pFractalExponent->isDataValid( ) ) + return false; + break; + case 18: // Quilt + if( !m_pQuiltControl0Edit->isDataValid( ) ) + return false; + if( !m_pQuiltControl1Edit->isDataValid( ) ) + return false; + break; + case 21: // Slope + if( !m_pSlopeLoSlope->isDataValid( ) ) + return false; + if( !m_pSlopeHiSlope->isDataValid( ) ) + return false; + break; + case 23: // Spiral1 + case 24: // Spiral2 + if( !m_pSpiralNumberEdit->isDataValid( ) ) + return false; + break; + default: + break; + } + if( m_pEnableTurbulenceEdit->isChecked( ) ) { + if( !m_pValueVectorEdit->isDataValid( ) ) return false; + if( !m_pOctavesEdit->isDataValid( ) ) return false; + if( !m_pOmegaEdit->isDataValid( ) ) return false; + if( !m_pLambdaEdit->isDataValid( ) ) return false; + } + if( m_pDisplayedObject->parent( ) && + m_pDisplayedObject->parent( )->type( ) == "Normal" && + !m_pDepthEdit->isDataValid( ) ) + return false; + + return Base::isDataValid( ); +} + +void PMPatternEdit::slotComboChanged( int c ) +{ + switch( c ) + { + case 0: /* Agate */ + m_pAgateTurbulenceEdit->show( ); + m_pAgateTurbulenceLabel->show( ); + m_pCrackleWidget->hide( ); + m_pDensityWidget->hide( ); + m_pGradientEdit->hide( ); + m_pGradientLabel->hide( ); + m_pJuliaComplexLabel->hide( ); + m_pJuliaComplex->hide( ); + m_pFractalWidget->hide( ); + m_pQuiltControlsLabel->hide( ); + m_pQuiltControl0Edit->hide( ); + m_pQuiltControl1Edit->hide( ); + m_pSlopeWidget->hide( ); + m_pSpiralNumberEdit->hide( ); + m_pSpiralNumberLabel->hide( ); + m_pNoiseGeneratorLabel->hide( ); + m_pNoiseGenerator->hide( ); + break; + case 3: /* Bozo */ + case 4: /* Bumps */ + m_pAgateTurbulenceEdit->hide( ); + m_pAgateTurbulenceLabel->hide( ); + m_pCrackleWidget->hide( ); + m_pDensityWidget->hide( ); + m_pGradientEdit->hide( ); + m_pGradientLabel->hide( ); + m_pJuliaComplexLabel->hide( ); + m_pJuliaComplex->hide( ); + m_pFractalWidget->hide( ); + m_pQuiltControlsLabel->hide( ); + m_pQuiltControl0Edit->hide( ); + m_pQuiltControl1Edit->hide( ); + m_pSlopeWidget->hide( ); + m_pSpiralNumberEdit->hide( ); + m_pSpiralNumberLabel->hide( ); + m_pNoiseGeneratorLabel->show( ); + m_pNoiseGenerator->show( ); + break; + case 6: /* Crackle */ + m_pAgateTurbulenceEdit->hide( ); + m_pAgateTurbulenceLabel->hide( ); + m_pCrackleWidget->show( ); + m_pDensityWidget->hide( ); + m_pGradientEdit->hide( ); + m_pGradientLabel->hide( ); + m_pJuliaComplexLabel->hide( ); + m_pJuliaComplex->hide( ); + m_pFractalWidget->hide( ); + m_pQuiltControlsLabel->hide( ); + m_pQuiltControl0Edit->hide( ); + m_pQuiltControl1Edit->hide( ); + m_pSlopeWidget->hide( ); + m_pSpiralNumberEdit->hide( ); + m_pSpiralNumberLabel->hide( ); + m_pNoiseGeneratorLabel->hide( ); + m_pNoiseGenerator->hide( ); + break; + case 8: /* Density File */ + m_pAgateTurbulenceEdit->hide( ); + m_pAgateTurbulenceLabel->hide( ); + m_pCrackleWidget->hide( ); + m_pDensityWidget->show( ); + m_pGradientEdit->hide( ); + m_pGradientLabel->hide( ); + m_pJuliaComplexLabel->hide( ); + m_pJuliaComplex->hide( ); + m_pFractalWidget->hide( ); + m_pQuiltControlsLabel->hide( ); + m_pQuiltControl0Edit->hide( ); + m_pQuiltControl1Edit->hide( ); + m_pSlopeWidget->hide( ); + m_pSpiralNumberEdit->hide( ); + m_pSpiralNumberLabel->hide( ); + m_pNoiseGeneratorLabel->hide( ); + m_pNoiseGenerator->hide( ); + break; + case 10: /* Gradient */ + m_pAgateTurbulenceEdit->hide( ); + m_pAgateTurbulenceLabel->hide( ); + m_pCrackleWidget->hide( ); + m_pDensityWidget->hide( ); + m_pGradientEdit->show( ); + m_pGradientLabel->show( ); + m_pJuliaComplexLabel->hide( ); + m_pJuliaComplex->hide( ); + m_pFractalWidget->hide( ); + m_pQuiltControlsLabel->hide( ); + m_pQuiltControl0Edit->hide( ); + m_pQuiltControl1Edit->hide( ); + m_pSlopeWidget->hide( ); + m_pSpiralNumberEdit->hide( ); + m_pSpiralNumberLabel->hide( ); + m_pNoiseGeneratorLabel->hide( ); + m_pNoiseGenerator->hide( ); + break; + case 11: /* Granite */ + m_pAgateTurbulenceEdit->hide( ); + m_pAgateTurbulenceLabel->hide( ); + m_pCrackleWidget->hide( ); + m_pDensityWidget->hide( ); + m_pGradientEdit->hide( ); + m_pGradientLabel->hide( ); + m_pJuliaComplexLabel->hide( ); + m_pJuliaComplex->hide( ); + m_pFractalWidget->hide( ); + m_pQuiltControlsLabel->hide( ); + m_pQuiltControl0Edit->hide( ); + m_pQuiltControl1Edit->hide( ); + m_pSlopeWidget->hide( ); + m_pSpiralNumberEdit->hide( ); + m_pSpiralNumberLabel->hide( ); + m_pNoiseGeneratorLabel->show( ); + m_pNoiseGenerator->show( ); + break; + case 12: /* Julia */ + m_pAgateTurbulenceEdit->hide( ); + m_pAgateTurbulenceLabel->hide( ); + m_pCrackleWidget->hide( ); + m_pDensityWidget->hide( ); + m_pGradientEdit->hide( ); + m_pGradientLabel->hide( ); + m_pJuliaComplexLabel->show( ); + m_pJuliaComplex->show( ); + m_pFractalWidget->show( ); + m_pQuiltControlsLabel->hide( ); + m_pQuiltControl0Edit->hide( ); + m_pQuiltControl1Edit->hide( ); + m_pSlopeWidget->hide( ); + m_pSpiralNumberEdit->hide( ); + m_pSpiralNumberLabel->hide( ); + m_pNoiseGeneratorLabel->hide( ); + m_pNoiseGenerator->hide( ); + break; + case 14: /* Mandel */ + m_pAgateTurbulenceEdit->hide( ); + m_pAgateTurbulenceLabel->hide( ); + m_pCrackleWidget->hide( ); + m_pDensityWidget->hide( ); + m_pGradientEdit->hide( ); + m_pGradientLabel->hide( ); + m_pJuliaComplexLabel->hide( ); + m_pJuliaComplex->hide( ); + m_pFractalWidget->show( ); + m_pQuiltControlsLabel->hide( ); + m_pQuiltControl0Edit->hide( ); + m_pQuiltControl1Edit->hide( ); + m_pSlopeWidget->hide( ); + m_pSpiralNumberEdit->hide( ); + m_pSpiralNumberLabel->hide( ); + m_pNoiseGeneratorLabel->hide( ); + m_pNoiseGenerator->hide( ); + break; + case 18: /* Quilted */ + m_pAgateTurbulenceEdit->hide( ); + m_pAgateTurbulenceLabel->hide( ); + m_pCrackleWidget->hide( ); + m_pDensityWidget->hide( ); + m_pGradientEdit->hide( ); + m_pGradientLabel->hide( ); + m_pJuliaComplexLabel->hide( ); + m_pJuliaComplex->hide( ); + m_pFractalWidget->hide( ); + m_pQuiltControlsLabel->show( ); + m_pQuiltControl0Edit->show( ); + m_pQuiltControl1Edit->show( ); + m_pSlopeWidget->hide( ); + m_pSpiralNumberEdit->hide( ); + m_pSpiralNumberLabel->hide( ); + m_pNoiseGeneratorLabel->hide( ); + m_pNoiseGenerator->hide( ); + break; + case 21: /* Slope */ + m_pAgateTurbulenceEdit->hide( ); + m_pAgateTurbulenceLabel->hide( ); + m_pCrackleWidget->hide( ); + m_pDensityWidget->hide( ); + m_pGradientEdit->hide( ); + m_pGradientLabel->hide( ); + m_pJuliaComplexLabel->hide( ); + m_pJuliaComplex->hide( ); + m_pFractalWidget->hide( ); + m_pQuiltControlsLabel->hide( ); + m_pQuiltControl0Edit->hide( ); + m_pQuiltControl1Edit->hide( ); + m_pSlopeWidget->show( ); + m_pSpiralNumberEdit->hide( ); + m_pSpiralNumberLabel->hide( ); + m_pNoiseGeneratorLabel->hide( ); + m_pNoiseGenerator->hide( ); + break; + case 23: /* Spiral1 */ + case 24: /* Spiral2 */ + m_pAgateTurbulenceEdit->hide( ); + m_pAgateTurbulenceLabel->hide( ); + m_pCrackleWidget->hide( ); + m_pDensityWidget->hide( ); + m_pGradientEdit->hide( ); + m_pGradientLabel->hide( ); + m_pJuliaComplexLabel->hide( ); + m_pJuliaComplex->hide( ); + m_pFractalWidget->hide( ); + m_pQuiltControlsLabel->hide( ); + m_pQuiltControl0Edit->hide( ); + m_pQuiltControl1Edit->hide( ); + m_pSlopeWidget->hide( ); + m_pSpiralNumberEdit->show( ); + m_pSpiralNumberLabel->show( ); + m_pNoiseGeneratorLabel->hide( ); + m_pNoiseGenerator->hide( ); + break; + case 28: /* Wrinkles */ + m_pAgateTurbulenceEdit->hide( ); + m_pAgateTurbulenceLabel->hide( ); + m_pCrackleWidget->hide( ); + m_pDensityWidget->hide( ); + m_pGradientEdit->hide( ); + m_pGradientLabel->hide( ); + m_pJuliaComplexLabel->hide( ); + m_pJuliaComplex->hide( ); + m_pFractalWidget->hide( ); + m_pQuiltControlsLabel->hide( ); + m_pQuiltControl0Edit->hide( ); + m_pQuiltControl1Edit->hide( ); + m_pSlopeWidget->hide( ); + m_pSpiralNumberEdit->hide( ); + m_pSpiralNumberLabel->hide( ); + m_pNoiseGeneratorLabel->show( ); + m_pNoiseGenerator->show( ); + break; + default: + m_pAgateTurbulenceEdit->hide( ); + m_pAgateTurbulenceLabel->hide( ); + m_pCrackleWidget->hide( ); + m_pDensityWidget->hide( ); + m_pGradientEdit->hide( ); + m_pGradientLabel->hide( ); + m_pJuliaComplexLabel->hide( ); + m_pJuliaComplex->hide( ); + m_pFractalWidget->hide( ); + m_pQuiltControlsLabel->hide( ); + m_pQuiltControl0Edit->hide( ); + m_pQuiltControl1Edit->hide( ); + m_pSlopeWidget->hide( ); + m_pSpiralNumberEdit->hide( ); + m_pSpiralNumberLabel->hide( ); + m_pNoiseGeneratorLabel->hide( ); + m_pNoiseGenerator->hide( ); + break; + } + emit dataChanged( ); + emit sizeChanged( ); +} + +void PMPatternEdit::slotDensityFileBrowseClicked( ) +{ + QString str = KFileDialog::getOpenFileName( QString::null, QString::null ); + + if( !str.isEmpty() ) + { + m_pDensityFile->setText( str ); + emit dataChanged( ); + } +} + +void PMPatternEdit::slotFractalMagnetClicked( ) +{ + if ( m_pFractalMagnet->isChecked( ) ) + { + m_pFractalMagnetType->show( ); + m_pFractalExponentLabel->hide( ); + m_pFractalExponent->hide( ); + } + else + { + m_pFractalMagnetType->hide( ); + m_pFractalExponentLabel->show( ); + m_pFractalExponent->show( ); + } + m_pFractalWidget->adjustSize( ); + emit dataChanged( ); + emit sizeChanged( ); +} + +void PMPatternEdit::slotSlopeAltFlagClicked( ) +{ + if ( m_pSlopeAltFlag->isChecked( ) ) + { + m_pSlopeAltitude->show( ); + m_pSlopeLoAltLabel->show( ); + m_pSlopeLoAlt->show( ); + m_pSlopeHiAltLabel->show( ); + m_pSlopeHiAlt->show( ); + } + else + { + m_pSlopeAltitude->hide( ); + m_pSlopeLoAltLabel->hide( ); + m_pSlopeLoAlt->hide( ); + m_pSlopeHiAltLabel->hide( ); + m_pSlopeHiAlt->hide( ); + } + m_pSlopeWidget->adjustSize( ); + emit dataChanged( ); + emit sizeChanged( ); +} + +void PMPatternEdit::slotTurbulenceClicked( ) +{ + if(m_pEnableTurbulenceEdit->isChecked( ) ) + m_pTurbulenceWidget->show( ); + else + m_pTurbulenceWidget->hide( ); + + emit dataChanged( ); + emit sizeChanged( ); +} + +#include "pmpatternedit.moc" diff --git a/kpovmodeler/pmpatternedit.h b/kpovmodeler/pmpatternedit.h new file mode 100644 index 00000000..9f36ccf4 --- /dev/null +++ b/kpovmodeler/pmpatternedit.h @@ -0,0 +1,164 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMPATTERNEDIT_H +#define PMPATTERNEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMPattern; +class PMVectorEdit; +class QComboBox; +class PMFloatEdit; +class PMIntEdit; +class QLabel; +class QCheckBox; +class QWidget; +class QLineEdit; +class QPushButton; + +/** + * Dialog edit class for @ref PMPattern. + */ +class PMPatternEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMPatternEdit with parent and name + */ + PMPatternEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + /** + * Slot called whenever a new pattern type is selected. + */ + void slotComboChanged( int c ); + /** + * Slot called when the browse button is pressed for selection of the + * density file + */ + void slotDensityFileBrowseClicked( ); + /** + * Slot called when fractal magnet clicked + */ + void slotFractalMagnetClicked( ); + /** + * Slot called when the slope altitude flag is clicked + */ + void slotSlopeAltFlagClicked( ); + /** + * Slot called when turbulence is activated/deactivated. + */ + void slotTurbulenceClicked( ); + +private: + /** + * Set's the combo box and enables/disables widgets. + */ + void setPatternType( int i ); + /** + * m_noDepth is false is the editor must show the depth field + */ + bool m_noDepth; + PMPattern* m_pDisplayedObject; + QComboBox* m_pTypeCombo; + + QLabel* m_pAgateTurbulenceLabel; + PMFloatEdit* m_pAgateTurbulenceEdit; + + QWidget* m_pCrackleWidget; + PMVectorEdit* m_pCrackleForm; + PMIntEdit* m_pCrackleMetric; + PMFloatEdit* m_pCrackleOffset; + QCheckBox* m_pCrackleSolid; + + QWidget* m_pDensityWidget; + QComboBox* m_pDensityInterpolate; + QLineEdit* m_pDensityFile; + QPushButton* m_pDensityFileBrowse; + + QLabel* m_pGradientLabel; + PMVectorEdit* m_pGradientEdit; + + QLabel* m_pJuliaComplexLabel; + PMVectorEdit* m_pJuliaComplex; + QWidget* m_pFractalWidget; + QCheckBox* m_pFractalMagnet; + QComboBox* m_pFractalMagnetType; + PMIntEdit* m_pMaxIterationsEdit; + QLabel* m_pFractalExponentLabel; + PMIntEdit* m_pFractalExponent; + QComboBox* m_pFractalExtType; + PMFloatEdit* m_pFractalExtFactor; + QComboBox* m_pFractalIntType; + PMFloatEdit* m_pFractalIntFactor; + + QLabel* m_pQuiltControlsLabel; + PMFloatEdit* m_pQuiltControl0Edit; + PMFloatEdit* m_pQuiltControl1Edit; + + QWidget* m_pSlopeWidget; + PMVectorEdit* m_pSlopeDirection; + PMFloatEdit* m_pSlopeLoSlope; + PMFloatEdit* m_pSlopeHiSlope; + QCheckBox* m_pSlopeAltFlag; + PMVectorEdit* m_pSlopeAltitude; + QLabel* m_pSlopeLoAltLabel; + PMFloatEdit* m_pSlopeLoAlt; + QLabel* m_pSlopeHiAltLabel; + PMFloatEdit* m_pSlopeHiAlt; + + QLabel* m_pSpiralNumberLabel; + PMIntEdit* m_pSpiralNumberEdit; + + QLabel* m_pNoiseGeneratorLabel; + QComboBox* m_pNoiseGenerator; + + QCheckBox* m_pEnableTurbulenceEdit; + QWidget* m_pTurbulenceWidget; + PMVectorEdit* m_pValueVectorEdit; + PMIntEdit* m_pOctavesEdit; + PMFloatEdit* m_pOmegaEdit; + PMFloatEdit* m_pLambdaEdit; + + QLabel* m_pDepthLabel; + PMFloatEdit* m_pDepthEdit; +}; + + +#endif diff --git a/kpovmodeler/pmphotons.cpp b/kpovmodeler/pmphotons.cpp new file mode 100644 index 00000000..8297e3be --- /dev/null +++ b/kpovmodeler/pmphotons.cpp @@ -0,0 +1,240 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmphotons.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmphotonsedit.h" + +#include + +const double spacingMultiDefault = 1.0; + +PMDefinePropertyClass( PMPhotons, PMPhotonsProperty ); + +PMMetaObject* PMPhotons::s_pMetaObject = 0; +PMObject* createNewPhotons( PMPart* part ) +{ + return new PMPhotons( part ); +} + +PMPhotons::PMPhotons( PMPart* part ) : Base( part ) +{ + m_target = true; + m_spacingMulti = spacingMultiDefault; + m_refraction = false; + m_reflection = false; + m_collect = true; + m_passThrough = false; + m_areaLight = false; +} + +PMPhotons::PMPhotons( const PMPhotons& p ) + : Base( p ) +{ + m_target = p.m_target; + m_spacingMulti = p.m_spacingMulti; + m_refraction = p.m_refraction; + m_reflection = p.m_reflection; + m_collect = p.m_collect; + m_passThrough = p.m_passThrough; + m_areaLight = p.m_areaLight; +} + +PMPhotons::~PMPhotons( ) +{ +} + +PMMetaObject* PMPhotons::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Photons", Base::metaObject( ), + createNewPhotons ); + + s_pMetaObject->addProperty( new PMPhotonsProperty( "target", + &PMPhotons::setTarget, &PMPhotons::target ) ); + s_pMetaObject->addProperty( new PMPhotonsProperty( "spacingMulti", + &PMPhotons::setSpacingMulti, &PMPhotons::spacingMulti ) ); + s_pMetaObject->addProperty( new PMPhotonsProperty( "refraction", + &PMPhotons::setRefraction, &PMPhotons::refraction ) ); + s_pMetaObject->addProperty( new PMPhotonsProperty( "reflection", + &PMPhotons::setReflection, &PMPhotons::reflection ) ); + s_pMetaObject->addProperty( new PMPhotonsProperty( "collect", + &PMPhotons::setCollect, &PMPhotons::collect ) ); + s_pMetaObject->addProperty( new PMPhotonsProperty( "passThrough", + &PMPhotons::setPassThrough, &PMPhotons::passThrough ) ); + s_pMetaObject->addProperty( new PMPhotonsProperty( "areaLight", + &PMPhotons::setAreaLight, &PMPhotons::areaLight ) ); + } + return s_pMetaObject; +} + +void PMPhotons::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMPhotons::description( ) const +{ + return i18n( "photons" ); +} + +void PMPhotons::serialize( QDomElement& e, QDomDocument& ) const +{ + e.setAttribute( "target", m_target ); + e.setAttribute( "spacing_multi", m_spacingMulti ); + e.setAttribute( "refraction", m_refraction ); + e.setAttribute( "reflection", m_reflection ); + e.setAttribute( "collect", m_collect ); + e.setAttribute( "pass_through", m_passThrough ); + e.setAttribute( "area_light", m_areaLight ); +} + +void PMPhotons::readAttributes( const PMXMLHelper& h ) +{ + m_target = h.boolAttribute( "target", true ); + m_spacingMulti = h.doubleAttribute( "spacing_multi", spacingMultiDefault ); + m_refraction = h.boolAttribute( "refraction", false ); + m_reflection = h.boolAttribute( "reflection", false ); + m_collect = h.boolAttribute( "collect", true ); + m_passThrough = h.boolAttribute( "pass_through", false ); + m_areaLight = h.boolAttribute( "area_light", false ); +} + +void PMPhotons::setTarget( bool t ) +{ + if( t != m_target ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMTargetID, m_target ); + m_target = t; + } +} + +void PMPhotons::setSpacingMulti( double sm ) +{ + if ( sm != m_spacingMulti ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSpacingMultiID, m_spacingMulti ); + m_spacingMulti = sm; + } +} + +void PMPhotons::setRefraction( bool r ) +{ + if ( r != m_refraction ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRefractionID, m_refraction ); + m_refraction = r; + } +} + +void PMPhotons::setReflection( bool r ) +{ + if ( r != m_reflection ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMReflectionID, m_reflection); + m_reflection = r; + } +} + +void PMPhotons::setCollect( bool c ) +{ + if ( c != m_collect ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCollectID, m_collect ); + m_collect = c; + } +} + +void PMPhotons::setPassThrough( bool pt ) +{ + if ( pt != m_passThrough ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMPassThroughID, m_passThrough ); + m_passThrough = pt; + } +} + +void PMPhotons::setAreaLight( bool al ) +{ + if ( al != m_areaLight ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAreaLightID, m_areaLight ); + m_areaLight = al; + } +} + +PMDialogEditBase* PMPhotons::editWidget( QWidget* parent ) const +{ + return new PMPhotonsEdit( parent ); +} + +void PMPhotons::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMTargetID: + setTarget( data->boolData( ) ); + break; + case PMSpacingMultiID: + setSpacingMulti( data->doubleData( ) ); + break; + case PMRefractionID: + setRefraction( data->boolData( ) ); + break; + case PMReflectionID: + setReflection( data->boolData( ) ); + break; + case PMCollectID: + setCollect( data->boolData( ) ); + break; + case PMPassThroughID: + setPassThrough( data->boolData( ) ); + break; + case PMAreaLightID: + setAreaLight( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMRadiosity::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmphotons.h b/kpovmodeler/pmphotons.h new file mode 100644 index 00000000..14ce9f6f --- /dev/null +++ b/kpovmodeler/pmphotons.h @@ -0,0 +1,160 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMPHOTONS_H +#define PMPHOTONS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmobject.h" + +/** + * Class for Photons settings. + */ + +class PMPhotons : public PMObject +{ + typedef PMObject Base; +public: + /** + * Creates a PMPhotons + */ + PMPhotons( PMPart* part ); + /** + * Copy constructor + */ + PMPhotons( const PMPhotons& p ); + /** + * deletes the PMPhotons + */ + virtual ~PMPhotons( ); + + /** */ + virtual PMObject* copy( ) const { return new PMPhotons( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMPhotonsEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmphotons" ); } + + /** + * Returns the target flag + */ + bool target( ) const { return m_target; } + /** + * Sets the target flag + */ + void setTarget( bool t ); + + /** + * Returns the spacing multiplier + */ + double spacingMulti( ) const { return m_spacingMulti; } + /** + * Sets the spacing multipler + */ + void setSpacingMulti( double sm ); + + /** + * Returns the refraction flag + */ + bool refraction( ) const { return m_refraction; } + /** + * Sets the refraction flag + */ + void setRefraction( bool r ); + + /** + * Returns the reflection flag + */ + bool reflection( ) const { return m_reflection; } + /** + * Sets the reflection flag + */ + void setReflection( bool r ); + + /** + * Returns the collect flag + */ + bool collect( ) const { return m_collect; } + /** + * Sets the collect flag + */ + void setCollect( bool c ); + + /** + * Returns the pass through flag + */ + bool passThrough( ) const { return m_passThrough; } + /** + * Sets the pass through flag + */ + void setPassThrough( bool pt ); + + /** + * Returns the area light flag + */ + bool areaLight( ) const { return m_areaLight; } + /** + * Sets the area light flag + */ + void setAreaLight( bool al ); + + /** */ + virtual void restoreMemento( PMMemento* s ); + +private: + /** + * IDs for @ref PMMementoData + */ + enum PMPhotonsMementoID{ PMTargetID, PMSpacingMultiID, PMRefractionID, + PMReflectionID, PMCollectID, PMPassThroughID, + PMAreaLightID }; + + bool m_target; + double m_spacingMulti; + bool m_refraction; + bool m_reflection; + bool m_collect; + bool m_passThrough; + bool m_areaLight; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmphotonsedit.cpp b/kpovmodeler/pmphotonsedit.cpp new file mode 100644 index 00000000..21f5d106 --- /dev/null +++ b/kpovmodeler/pmphotonsedit.cpp @@ -0,0 +1,160 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmphotonsedit.h" +#include "pmphotons.h" +#include "pmlineedits.h" + +#include +#include +#include +#include +#include +#include + + +PMPhotonsEdit::PMPhotonsEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMPhotonsEdit::createTopWidgets( ) +{ + QGridLayout* gl; + QHBoxLayout* hl; + + Base::createTopWidgets( ); + + m_pLayoutWidget = new QWidget( this ); + m_pTarget = new QCheckBox( i18n( "Target" ), m_pLayoutWidget ); + m_pSpacingMultiLabel = new QLabel( i18n( "Spacing multiplier:" ), m_pLayoutWidget ); + m_pSpacingMulti = new PMFloatEdit( m_pLayoutWidget ); + m_pSpacingMulti->setValidation( true, 0, false, 0 ); + + m_pRefraction = new QCheckBox( i18n( "Refraction" ), this ); + m_pReflection = new QCheckBox( i18n( "Reflection" ), this ); + m_pCollect = new QCheckBox( i18n( "Collect" ), this ); + m_pPassThrough = new QCheckBox( i18n( "Pass through" ), this ); + m_pAreaLight = new QCheckBox( i18n( "Area light" ), this ); + + hl = new QHBoxLayout( m_pLayoutWidget, 0, KDialog::spacingHint( ) ); + gl = new QGridLayout( hl, 2, 2 ); + gl->addMultiCellWidget( m_pTarget, 0, 0, 0, 1 ); + gl->addWidget( m_pSpacingMultiLabel, 1, 0 ); + gl->addWidget( m_pSpacingMulti, 1, 1 ); + hl->addStretch( 1 ); + topLayout( )->addWidget( m_pLayoutWidget ); + + gl = new QGridLayout( topLayout( ), 2, 2 ); + gl->addWidget( m_pRefraction, 0, 0 ); + gl->addWidget( m_pReflection, 0, 1 ); + gl->addWidget( m_pCollect, 1, 0 ); + gl->addWidget( m_pPassThrough, 1, 1 ); + gl->addWidget( m_pAreaLight, 1, 0 ); + + connect( m_pTarget, SIGNAL( clicked( ) ), SLOT( slotTargetClicked( ) ) ); + connect( m_pSpacingMulti, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pRefraction, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pReflection, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pCollect, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pPassThrough, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pAreaLight, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMPhotonsEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Photons" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMPhotons* ) o; + + if ( o->parent( ) && ( o->parent( )->isA( "Light" ) ) ) + { + m_pLayoutWidget->hide( ); + m_pCollect->hide( ); + m_pPassThrough->hide( ); + m_pAreaLight->show( ); + } + else + { + m_pLayoutWidget->show( ); + m_pCollect->show( ); + m_pPassThrough->show( ); + m_pAreaLight->hide( ); + } + + m_pTarget->setChecked( m_pDisplayedObject->target( ) ); + m_pTarget->setEnabled( !readOnly ); + m_pSpacingMulti->setValue( m_pDisplayedObject->spacingMulti( ) ); + m_pSpacingMulti->setReadOnly( readOnly ); + m_pRefraction->setChecked( m_pDisplayedObject->refraction( ) ); + m_pRefraction->setEnabled( !readOnly ); + m_pReflection->setChecked( m_pDisplayedObject->reflection( ) ); + m_pReflection->setEnabled( !readOnly ); + m_pCollect->setChecked( m_pDisplayedObject->collect( ) ); + m_pCollect->setEnabled( !readOnly ); + m_pPassThrough->setChecked( m_pDisplayedObject->passThrough( ) ); + m_pPassThrough->setEnabled( !readOnly ); + m_pAreaLight->setChecked( m_pDisplayedObject->areaLight( ) ); + m_pAreaLight->setEnabled( !readOnly ); + + slotTargetClicked( ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMPhotonsEdit: Can't display object\n"; +} + +void PMPhotonsEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setTarget( m_pTarget->isChecked( ) ); + m_pDisplayedObject->setSpacingMulti( m_pSpacingMulti->value( ) ); + m_pDisplayedObject->setRefraction( m_pRefraction->isChecked( ) ); + m_pDisplayedObject->setReflection( m_pReflection->isChecked( ) ); + m_pDisplayedObject->setCollect( m_pCollect->isChecked( ) ); + m_pDisplayedObject->setPassThrough( m_pPassThrough->isChecked( ) ); + m_pDisplayedObject->setAreaLight( m_pAreaLight->isChecked( ) ); + } +} + +bool PMPhotonsEdit::isDataValid( ) +{ + if( !m_pSpacingMulti->isDataValid( ) ) return false; + + return Base::isDataValid( ); +} + +void PMPhotonsEdit::slotTargetClicked( ) +{ + if ( m_pTarget->isChecked( ) && m_pTarget->isEnabled( ) ) + { + m_pSpacingMulti->setEnabled( true ); + } + else + { + m_pSpacingMulti->setEnabled( false ); + } + emit dataChanged( ); +} + +#include "pmphotonsedit.moc" diff --git a/kpovmodeler/pmphotonsedit.h b/kpovmodeler/pmphotonsedit.h new file mode 100644 index 00000000..d40e84cf --- /dev/null +++ b/kpovmodeler/pmphotonsedit.h @@ -0,0 +1,79 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMPHOTONSEDIT_H +#define PMPHOTONSEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMPhotons; +class PMFloatEdit; +class QCheckBox; +class QLabel; + +/** + * Dialog edit class for @ref PMPhotons. + */ +class PMPhotonsEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMPhotonsEdit with parent and name + */ + PMPhotonsEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + /** + * Slot Called whenever target is clicked + */ + void slotTargetClicked( ); + +private: + PMPhotons* m_pDisplayedObject; + + QWidget* m_pLayoutWidget; + QCheckBox* m_pTarget; + PMFloatEdit* m_pSpacingMulti; + QLabel* m_pSpacingMultiLabel; + QCheckBox* m_pRefraction; + QCheckBox* m_pReflection; + QCheckBox* m_pCollect; + QCheckBox* m_pPassThrough; + QCheckBox* m_pAreaLight; +}; + + +#endif diff --git a/kpovmodeler/pmpigment.cpp b/kpovmodeler/pmpigment.cpp new file mode 100644 index 00000000..39e5a4e3 --- /dev/null +++ b/kpovmodeler/pmpigment.cpp @@ -0,0 +1,124 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmpigment.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmpigmentedit.h" + +#include + +PMDefinePropertyClass( PMPigment, PMPigmentProperty ); + +PMMetaObject* PMPigment::s_pMetaObject = 0; +PMObject* createNewPigment( PMPart* part ) +{ + return new PMPigment( part ); +} + +PMPigment::PMPigment( PMPart* part ) : Base( part ) +{ + m_uvMapping = false; +} + +PMPigment::PMPigment( const PMPigment& p ) : Base( p ) +{ + m_uvMapping = p.m_uvMapping; +} + +PMPigment::~PMPigment( ) +{ +} + +PMMetaObject* PMPigment::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Pigment", Base::metaObject( ), + createNewPigment ); + s_pMetaObject->addProperty( + new PMPigmentProperty( "uvMapping", &PMPigment::setUVMapping, &PMPigment::uvMapping ) ); + } + return s_pMetaObject; +} + +void PMPigment::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMPigment::description( ) const +{ + return i18n( "pigment" ); +} + +PMDialogEditBase* PMPigment::editWidget( QWidget* parent ) const +{ + return new PMPigmentEdit( parent ); +} + +void PMPigment::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "uv_mapping", m_uvMapping ); + Base::serialize( e, doc ); +} + +void PMPigment::readAttributes( const PMXMLHelper& h ) +{ + m_uvMapping = h.boolAttribute( "uv_mapping", false ); + Base::readAttributes( h ); +} + +void PMPigment::setUVMapping( bool m ) +{ + if( m != m_uvMapping ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMUVMappingID, m_uvMapping ); + m_uvMapping = m; + } +} + +void PMPigment::restoreMemento( PMMemento *s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMUVMappingID: + setUVMapping( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMPigment::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmpigment.h b/kpovmodeler/pmpigment.h new file mode 100644 index 00000000..3f465e0e --- /dev/null +++ b/kpovmodeler/pmpigment.h @@ -0,0 +1,95 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMPIGMENT_H +#define PMPIGMENT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebase.h" + +/** + * Class for povray pigments + */ +class PMPigment : public PMTextureBase +{ + typedef PMTextureBase Base; +public: + /** + * Creates an PMPigment + */ + PMPigment( PMPart* part ); + /** + * Copy constructor + */ + PMPigment( const PMPigment& ); + /** + * Deletes the object + */ + virtual ~PMPigment( ); + + /** */ + virtual PMObject* copy( ) const { return new PMPigment( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMPigmentEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pmpigment" ); } + + /** + * Returns the uv mapping flag + */ + bool uvMapping() const { return m_uvMapping; } + /** + * Sets the uv maaping flag + */ + void setUVMapping( bool m ); + + /** */ + virtual void restoreMemento( PMMemento *s ); + +private: + /** + * IDs for @ref PMMementoData + */ + enum PMPigmentMementoID { PMUVMappingID }; + + bool m_uvMapping; + + static PMMetaObject* s_pMetaObject; +}; + + +#endif diff --git a/kpovmodeler/pmpigmentedit.cpp b/kpovmodeler/pmpigmentedit.cpp new file mode 100644 index 00000000..939f18cf --- /dev/null +++ b/kpovmodeler/pmpigmentedit.cpp @@ -0,0 +1,68 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmpigmentedit.h" +#include "pmpigment.h" +#include "pmlinkedit.h" + +#include +#include +#include + + +PMPigmentEdit::PMPigmentEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMPigmentEdit::createTopWidgets() +{ + Base::createTopWidgets(); + m_pUVMapping = new QCheckBox( i18n( "UV mapping" ), this ); + topLayout( )->addWidget( m_pUVMapping ); + + connect( m_pUVMapping, SIGNAL( clicked() ), SIGNAL( dataChanged() ) ); +} + +void PMPigmentEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Pigment" ) ) + { + m_pDisplayedObject = ( PMPigment* ) o; + bool readOnly = m_pDisplayedObject->isReadOnly( ); + + m_pUVMapping->setChecked( m_pDisplayedObject->uvMapping() ); + m_pUVMapping->setEnabled( !readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMPigmentEdit: Can't display object\n"; +} + +void PMPigmentEdit::saveContents() +{ + if( m_pDisplayedObject ) + { + Base::saveContents(); + m_pDisplayedObject->setUVMapping( m_pUVMapping->isChecked() ); + } +} + +#include "pmpigmentedit.moc" diff --git a/kpovmodeler/pmpigmentedit.h b/kpovmodeler/pmpigmentedit.h new file mode 100644 index 00000000..7a3960a2 --- /dev/null +++ b/kpovmodeler/pmpigmentedit.h @@ -0,0 +1,60 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMPIGMENTEDIT_H +#define PMPIGMENTEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebaseedit.h" + +class PMPigment; +class QCheckBox; + +/** + * Dialog edit class for @ref PMPigment + */ +class PMPigmentEdit : public PMTextureBaseEdit +{ + Q_OBJECT + typedef PMTextureBaseEdit Base; +public: + /** + * Creates a PMPigmentEdit with parent and name + */ + PMPigmentEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMPigment* m_pDisplayedObject; + QCheckBox* m_pUVMapping; +}; + + +#endif diff --git a/kpovmodeler/pmplane.cpp b/kpovmodeler/pmplane.cpp new file mode 100644 index 00000000..171df53f --- /dev/null +++ b/kpovmodeler/pmplane.cpp @@ -0,0 +1,276 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Leonardo Skorianez + email : lsk@if.ufrj.br +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmplane.h" + +#include "pmxmlhelper.h" +#include "pmboxedit.h" +#include "pmmemento.h" +#include "pmdistancecontrolpoint.h" +#include "pmplanenormalcontrolpoint.h" +#include "pmdefaults.h" + +#include + +#include "pmplaneedit.h" + +const double defaultPlaneDistance = 0; +const PMVector defaultPlaneNormal = PMVector ( 0.0, 1.0, 0.0 ); + +/** default plane structure */ +PMViewStructure* PMPlane::s_pDefaultViewStructure = 0; +double PMPlane::s_planeSize = c_defaultPlaneSize; +int PMPlane::s_parameterKey = 0; + +PMDefinePropertyClass( PMPlane, PMPlaneProperty ); + +PMMetaObject* PMPlane::s_pMetaObject = 0; +PMObject* createNewPlane( PMPart* part ) +{ + return new PMPlane( part ); +} + +PMPlane::PMPlane( PMPart* part ) + : Base( part ) +{ + m_normal = defaultPlaneNormal; + m_distance = defaultPlaneDistance; +} + +PMPlane::PMPlane( const PMPlane& p ) + : Base( p ) +{ + m_normal = p.m_normal; + m_distance = p.m_distance; +} + +PMPlane::~PMPlane( ) +{ +} + +QString PMPlane::description( ) const +{ + return i18n( "plane" ); +} + +void PMPlane::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "normal", m_normal.serializeXML( ) ); + e.setAttribute( "distance", m_distance ); + Base::serialize( e, doc ); +} + +void PMPlane::readAttributes( const PMXMLHelper& h ) +{ + m_normal = h.vectorAttribute( "normal", defaultPlaneNormal ); + m_distance = h.doubleAttribute( "distance", defaultPlaneDistance ); + Base::readAttributes( h ); +} + +PMMetaObject* PMPlane::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Plane", Base::metaObject( ), + createNewPlane ); + s_pMetaObject->addProperty( + new PMPlaneProperty( "normal", &PMPlane::setNormal, &PMPlane::normal ) ); + s_pMetaObject->addProperty( + new PMPlaneProperty( "distance", &PMPlane::setDistance, &PMPlane::distance ) ); + } + return s_pMetaObject; +} + +void PMPlane::setNormal( const PMVector& p ) +{ + + if( p != m_normal ) + { + if( m_pMemento ) + { + m_pMemento->addData( s_pMetaObject, PMNormalID, m_normal ); + } + m_normal = p; + m_normal.resize( 3 ); + + setViewStructureChanged( ); + } +} + +void PMPlane::setDistance( double distance ) +{ + if( m_distance != distance ) + { + if( m_pMemento ) + { + m_pMemento->addData( s_pMetaObject, PMDistanceID, m_distance ); + } + m_distance = distance; + + setViewStructureChanged( ); + } +} + +PMDialogEditBase* PMPlane::editWidget( QWidget* parent ) const +{ + return new PMPlaneEdit( parent ); +} + +void PMPlane::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMNormalID: + setNormal( data->vectorData( ) ); + break; + case PMDistanceID: + setDistance( data->doubleData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMPlane::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + +bool PMPlane::isDefault( ) +{ + if( ( m_normal == defaultPlaneNormal ) && ( m_distance == defaultPlaneDistance ) ) + return true; + return false; +} + +void PMPlane::createViewStructure( ) +{ + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultViewStructure ( ) ); + m_pViewStructure->points( ).detach( ); + } + createPoints( m_pViewStructure->points( ), m_normal, m_distance ); +} + +PMViewStructure* PMPlane::defaultViewStructure( ) const +{ + if( !s_pDefaultViewStructure ) + { + s_pDefaultViewStructure = new PMViewStructure( 4, 4 ); + PMLineArray& lines = s_pDefaultViewStructure->lines( ); + + createPoints( s_pDefaultViewStructure->points( ), defaultPlaneNormal,defaultPlaneDistance ); + + lines[0] = PMLine( 0 , 1 ); + lines[1] = PMLine( 1 , 2 ); + lines[2] = PMLine( 2 , 3 ); + lines[3] = PMLine( 3 , 0 ); + } + return s_pDefaultViewStructure; +} + +void PMPlane::createPoints( PMPointArray& points, const PMVector& normal, double distance ) +{ + PMVector dir = normal; + if( approxZero( dir.abs( ) ) ) + dir = PMVector( 0.0, 1.0, 0.0 ); + + PMVector base = dir * distance; + PMMatrix rotation = PMMatrix::rotation( dir, M_PI / 4.0 ); + + PMVector endPoint1 = rotation * dir.orthogonal( ) * s_planeSize * sqrt( 2.0 ) * 0.5; + PMVector endPoint2 = rotation * ( rotation * endPoint1 ); + + points[0] = base + endPoint1; + points[1] = base + endPoint2; + points[2] = base - endPoint1; + points[3] = base - endPoint2; +} + +void PMPlane::controlPoints( PMControlPointList & list ) +{ + PMDistanceControlPoint* d; + d = new PMDistanceControlPoint( PMVector( 0, 0, 0 ), m_normal, m_distance, + PMDistanceID, i18n( "Distance" ) ); + list.append( new PMPlaneNormalControlPoint( d, m_normal, PMNormalID, + i18n( "Normal" ) ) ); + list.append( d ); +} + + +void PMPlane::controlPointsChanged( PMControlPointList & list ) +{ + PMControlPoint* p; + + for( p = list.first( ); p; p = list.next( ) ) + { + if( p->changed( ) ) + { + switch( p->id( ) ) + { + case PMNormalID: + setNormal( ( ( PMPlaneNormalControlPoint *) p)->normal( ) ); + setDistance( ( ( PMPlaneNormalControlPoint *) p)->distance( ) ); + break; + case PMDistanceID: + setDistance( ( ( PMDistanceControlPoint *) p )->distance( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMPlane::controlPointsChanged\n"; + break; + } + } + } +} + +void PMPlane::setPlaneSize( double size ) +{ + if( size >= 0.1 ) + { + s_planeSize = size; + if( s_pDefaultViewStructure ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + } + } + else + kdDebug( PMArea ) << "PMPlane::setPlaneSize: Size must be greater than 0.1\n"; + s_parameterKey++; +} + +void PMPlane::cleanUp( ) const +{ + if( s_pDefaultViewStructure ) + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} diff --git a/kpovmodeler/pmplane.h b/kpovmodeler/pmplane.h new file mode 100644 index 00000000..34829ade --- /dev/null +++ b/kpovmodeler/pmplane.h @@ -0,0 +1,148 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Leonardo Skorianez + email : lsk@if.ufrj.br +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMPLANE_H +#define PMPLANE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" +#include "pmvector.h" +#include "pmviewstructure.h" + +/** + * Class for povray plane + */ + +class PMPlane : public PMSolidObject +{ + typedef PMSolidObject Base; +public: + /** + * Creates a plane + */ + PMPlane( PMPart* part ); + /** + * Copy constructor + */ + PMPlane( const PMPlane& p ); + + /** + * Deletes the plane + */ + virtual ~PMPlane( ); + + /** */ + virtual PMObject* copy( ) const { return new PMPlane( *this ); } + + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMPlaneEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmplane" ); } + + /** + * Return the normal + */ + PMVector normal( ) const { return m_normal; } + /** + * Sets normal + */ + void setNormal( const PMVector& p ); + /** + * Return the distance + */ + double distance( ) const { return m_distance; } + /** + * Sets the distance + */ + void setDistance( double distance ); + + /** + * Sets the plane size (view structure) + */ + static void setPlaneSize( double size ); + /** + * Returns the plane size (view structure) + */ + static double planeSize( ) { return s_planeSize; }; + + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual void controlPoints( PMControlPointList& list ); + /** */ + virtual void controlPointsChanged( PMControlPointList& list ); + /** */ + virtual void cleanUp( ) const; + +protected: + /** */ + virtual bool isDefault( ); + /** */ + virtual void createViewStructure( ); + /** */ + virtual PMViewStructure* defaultViewStructure( ) const; + /** */ + virtual int viewStructureParameterKey( ) const { return s_parameterKey; } + +private: + /** + * Creates the points for the view structure + */ + static void createPoints( PMPointArray& points, const PMVector& normal , double distance ); + + /** + * IDs for @ref PMMementoData + */ + enum PMPlaneMementoID { PMNormalID, PMDistanceID }; + /** + * normal of plane + */ + PMVector m_normal; + /** + * distance from origin + */ + double m_distance; + /** + * The default view structure. It can be shared between planes + */ + static PMViewStructure* s_pDefaultViewStructure; + static double s_planeSize; + static int s_parameterKey; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmplaneedit.cpp b/kpovmodeler/pmplaneedit.cpp new file mode 100644 index 00000000..62e7e08e --- /dev/null +++ b/kpovmodeler/pmplaneedit.cpp @@ -0,0 +1,124 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Leonardo Skorianez + email : lsk@if.ufrj.br +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmplaneedit.h" +#include "pmplane.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" + +#include +#include +#include +#include +#include +#include + +PMPlaneEdit::PMPlaneEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMPlaneEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* layout; + + m_pNormal = new PMVectorEdit( "x", "y", "z", this ); + m_pDistance = new PMFloatEdit( this ); + + layout = new QHBoxLayout( topLayout( ) ); + layout->addWidget( new QLabel( i18n( "Normal:" ), this ) ); + layout->addWidget( m_pNormal ); + + layout = new QHBoxLayout( topLayout( ) ); + layout->addWidget( new QLabel( i18n( "Distance:" ), this ) ); + layout->addWidget( m_pDistance ); + layout->addStretch( 1 ); + + QPushButton* nb = new QPushButton( i18n( "Normalize" ), this ); + layout = new QHBoxLayout( topLayout( ) ); + layout->addWidget( nb ); + layout->addStretch( 1 ); + + connect( m_pNormal, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pDistance, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( nb, SIGNAL( clicked( ) ), SLOT( slotNormalize( ) ) ); +} + +void PMPlaneEdit::slotNormalize( ) +{ + PMVector normal = m_pNormal->vector( ); + double distance = m_pDistance->value( ); + double l = normal.abs( ); + if( !approxZero( l ) ) + { + m_pNormal->setVector( normal / l ); + m_pDistance->setValue( distance * l ); + } +} + +void PMPlaneEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Plane" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMPlane* ) o; + + m_pNormal->setVector( m_pDisplayedObject->normal( ) ); + m_pDistance->setValue( m_pDisplayedObject->distance( ) ); + + m_pNormal->setReadOnly( readOnly ); + m_pDistance->setReadOnly( readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMPlaneEdit: Can't display object\n"; +} + +void PMPlaneEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setNormal( m_pNormal->vector( ) ); + m_pDisplayedObject->setDistance( m_pDistance->value( ) ); + } +} + +bool PMPlaneEdit::isDataValid( ) +{ + if( m_pNormal->isDataValid( ) ) + { + if( approxZero( m_pNormal->vector( ).abs( ) ) ) + { + KMessageBox::error( this, i18n( "The normal vector may not be a " + "null vector." ), + i18n( "Error" ) ); + return false; + + } + if( m_pDistance->isDataValid( ) ) + return Base::isDataValid( ); + } + return false; +} + +#include "pmplaneedit.moc" diff --git a/kpovmodeler/pmplaneedit.h b/kpovmodeler/pmplaneedit.h new file mode 100644 index 00000000..97a07467 --- /dev/null +++ b/kpovmodeler/pmplaneedit.h @@ -0,0 +1,66 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Leonardo Skorinaez + email : lsk@if.ufrj.br +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMPLANEEDIT_H +#define PMPLANEEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" + +class PMVectorEdit; +class PMFloatEdit; +class PMPlane; +class QCheckBox; + +class PMPlaneEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMPlaneEdit with parent and name + */ + PMPlaneEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + /** + * Normalizes the vector + */ + void slotNormalize( ); + +private: + PMPlane* m_pDisplayedObject; + PMVectorEdit* m_pNormal; + PMFloatEdit* m_pDistance; +}; +#endif diff --git a/kpovmodeler/pmplanenormalcontrolpoint.cpp b/kpovmodeler/pmplanenormalcontrolpoint.cpp new file mode 100644 index 00000000..f28c035e --- /dev/null +++ b/kpovmodeler/pmplanenormalcontrolpoint.cpp @@ -0,0 +1,93 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmplanenormalcontrolpoint.h" +#include "pmdistancecontrolpoint.h" +#include "pmmath.h" +#include + +PMPlaneNormalControlPoint::PMPlaneNormalControlPoint( PMDistanceControlPoint* d, + const PMVector& normal, int id, + const QString& description ) + : PMControlPoint( id, description ) +{ + m_normal = normal; + m_pDistancePoint = d; +} + +PMVector PMPlaneNormalControlPoint::position( ) const +{ + return m_normal * ( m_pDistancePoint->distance( ) + 1.0 ); +} + +PMVector PMPlaneNormalControlPoint::extraLineStart( ) const +{ + return m_normal * m_pDistancePoint->distance( ); +} + +PMVector PMPlaneNormalControlPoint::extraLineEnd( ) const +{ + return position( ); +} + +void PMPlaneNormalControlPoint::graphicalChangeStarted( ) +{ + m_originalNormal = m_normal; + m_originalDistance = m_pDistancePoint->distance( ); +} + +void PMPlaneNormalControlPoint::graphicalChange( const PMVector& startPoint, + const PMVector& /*viewNormal*/, + const PMVector& endPoint ) +{ + PMVector p = m_originalNormal * ( m_originalDistance + 1 ) + + endPoint - startPoint; + double pabs = p.abs( ); + + if( !approxZero( pabs ) ) + { + PMVector np = p / pabs; + double nd = m_originalNormal.abs( ) * m_originalDistance; + PMVector normal = p - np * fabs( nd ); + double nl = normal.abs( ); + + if( !approxZero( nl ) ) + { + if( ( m_originalDistance * ( pabs - fabs( nd ) ) ) < 0 ) + nd = -nd; + nd /= nl; + m_pDistancePoint->setDistance( nd ); + m_pDistancePoint->setDirection( normal ); + m_normal = normal; + } + } +} + +double PMPlaneNormalControlPoint::distance( ) const +{ + return m_pDistancePoint->distance( ); +} + +void PMPlaneNormalControlPoint::snapToGrid( ) +{ + int i; + double d = moveGrid( ); + if( !approxZero( d ) ) + for( i = 0; i < 3; i++ ) + m_normal[i] = rint( m_normal[i] / d ) * d; + setChanged( ); +} diff --git a/kpovmodeler/pmplanenormalcontrolpoint.h b/kpovmodeler/pmplanenormalcontrolpoint.h new file mode 100644 index 00000000..0faf10b8 --- /dev/null +++ b/kpovmodeler/pmplanenormalcontrolpoint.h @@ -0,0 +1,92 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMPLANENORMALCONTROLPOINT_H +#define PMPLANENORMALCONTROLPOINT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmcontrolpoint.h" + +class PMDistanceControlPoint; + +/** + * Control points for the plane normal + */ +class PMPlaneNormalControlPoint : public PMControlPoint +{ +public: + /** + * Creates a PMPlaneNormalControlPoint with id. + * + * If the control point is change, the distance control point + * is changed, too! + */ + PMPlaneNormalControlPoint( PMDistanceControlPoint* d, const PMVector& normal, + int id, const QString& description ); + /** + * Deletes the PMPlaneNormalControlPoint + */ + virtual ~PMPlaneNormalControlPoint( ) { }; + + /** */ + virtual PMVector position( ) const; + + /** + * Sets the normal vector + */ + void setNormal( PMVector newNormal ) { m_normal = newNormal; } + /** + * Returns the normal vector + */ + PMVector normal( ) const { return m_normal; } + /** + * Returns the distance + */ + double distance( ) const; + + /** */ + virtual bool hasExtraLine( ) const { return true; } + /** + * Returns the start point of the extra line + */ + virtual PMVector extraLineStart( ) const; + /** + * Returns the end point of the extra line + */ + virtual PMVector extraLineEnd( ) const; + + /** */ + virtual void snapToGrid( ); + +protected: + /** */ + virtual void graphicalChangeStarted( ); + /** */ + virtual void graphicalChange( const PMVector& startPoint, + const PMVector& viewNormal, + const PMVector& endPoint ); +private: + PMVector m_normal, m_originalNormal; + double m_originalDistance; + PMDistanceControlPoint* m_pDistancePoint; +}; + +#endif diff --git a/kpovmodeler/pmpluginmanager.cpp b/kpovmodeler/pmpluginmanager.cpp new file mode 100644 index 00000000..0921f79d --- /dev/null +++ b/kpovmodeler/pmpluginmanager.cpp @@ -0,0 +1,115 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmpluginmanager.h" +#include "pmpart.h" +#include "pmshell.h" +#include "pmfactory.h" +#include "pmdebug.h" + +#include +#include + +#include +#include +#include + +PMPluginManager* PMPluginManager::s_pInstance = 0; +KStaticDeleter PMPluginManager::s_staticDeleter; + +using namespace KParts; + +// workaround for protected Plugin::pluginInfos +class PMPluginWorkaround : public Plugin +{ +public: + PMPluginWorkaround( ) : Plugin( 0, 0 ) { }; + static QValueList installedPlugins( const KInstance* instance ) + { + return pluginInfos( instance ); + } +}; + +PMPluginManager::PMPluginManager( ) +{ + // find installed plugins + KConfigGroup cfgGroup( PMFactory::instance( )->config( ), + "KParts Plugins" ); + QValueList plugins + = PMPluginWorkaround::installedPlugins( PMFactory::instance( ) ); + QValueList::ConstIterator pIt = plugins.begin( ); + QValueList::ConstIterator pEnd = plugins.end( ); + + for( ; pIt != pEnd; ++pIt ) + { + QDomElement docElem = ( *pIt ).m_document.documentElement( ); + QString name = docElem.attribute( "name" ); + QString description = docElem.attribute( "description" ); + if( !description.isEmpty( ) ) + description = i18n( description.latin1( ) ); + bool enabled = cfgGroup.readBoolEntry( name + "Enabled", false ); + m_plugins.append( new PMPluginInfo( name, description, enabled ) ); + } +} + +PMPluginManager::~PMPluginManager( ) +{ + m_plugins.setAutoDelete( true ); + m_plugins.clear( ); +} + +PMPluginManager* PMPluginManager::theManager( ) +{ + if( !s_pInstance ) + s_staticDeleter.setObject( s_pInstance, new PMPluginManager( ) ); + return s_pInstance; +} + +void PMPluginManager::registerPart( PMPart* p ) +{ + if( !m_parts.containsRef( p ) ) + { + m_parts.append( p ); + Plugin::loadPlugins( p, p, PMFactory::instance( ), false ); + } +} + +void PMPluginManager::removePart( PMPart* p ) +{ + m_parts.removeRef( p ); +} + +void PMPluginManager::updatePlugins( ) +{ + KConfigGroup cfgGroup( PMFactory::instance( )->config( ), + "KParts Plugins" ); + QPtrListIterator pit( m_plugins ); + for( ; *pit; ++pit ) + cfgGroup.writeEntry( ( *pit )->name( ) + "Enabled", + ( *pit )->enabled( ) ); + cfgGroup.sync( ); + + QPtrListIterator it( m_parts ); + for( ; *it; ++it ) + { + Plugin::loadPlugins( *it, *it, PMFactory::instance( ), false ); + PMShell* shell = ( *it )->shell( ); + if( shell ) + shell->updateGUI( ); + // TODO find a solution to update the gui without using the shell + } +} diff --git a/kpovmodeler/pmpluginmanager.h b/kpovmodeler/pmpluginmanager.h new file mode 100644 index 00000000..9424e014 --- /dev/null +++ b/kpovmodeler/pmpluginmanager.h @@ -0,0 +1,113 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMPLUGINMANAGER_H +#define PMPLUGINMANAGER_H + +#include + +#include +#include + +class PMPart; + +/** + * Plugin info for one plugin + */ +class PMPluginInfo +{ +public: + /** + * Default constructor + */ + PMPluginInfo( const QString& name, const QString& description, + bool enabled ) + { + m_name = name; + m_description = description; + m_enabled = enabled; + } + /** + * Returns the plugin name + */ + QString name( ) const { return m_name; } + /** + * Returns the plugin description (i18n'ed) + */ + QString description( ) const { return m_description; } + /** + * Returns true if the plugin is enabled + */ + bool enabled( ) const { return m_enabled; } + /** + * Enables/disables the plugin + */ + void enable( bool en ) { m_enabled = en; } +private: + QString m_name, m_description; + bool m_enabled; +}; + +/** + * Manager class for plugins. + * + * Stores a list of available plugins and loads and unloads plugins. + */ +class PMPluginManager +{ +public: + /** + * Destructor + */ + ~PMPluginManager( ); + /** + * Returns the instance (singleton) + */ + static PMPluginManager* theManager( ); + + /** + * Registers a part instance and loads the plugins for that part + */ + void registerPart( PMPart* p ); + /** + * Removes a part instance + */ + void removePart( PMPart* p ); + + /** + * Returns a list of available plugins + */ + QPtrList plugins( ) const { return m_plugins; } + /** + * Loads and unloads plugins for all parts when plugins were activated or + * deactivated + */ + void updatePlugins( ); +private: + /** + * Constructor + */ + PMPluginManager( ); + + QPtrList m_plugins; + QPtrList m_parts; + + static PMPluginManager* s_pInstance; + static KStaticDeleter s_staticDeleter; +}; + +#endif diff --git a/kpovmodeler/pmpluginsettings.cpp b/kpovmodeler/pmpluginsettings.cpp new file mode 100644 index 00000000..6b6611f2 --- /dev/null +++ b/kpovmodeler/pmpluginsettings.cpp @@ -0,0 +1,150 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmpluginsettings.h" + +#include "pmpluginmanager.h" + +#include +#include +#include +#include +#include + +class PMPluginListViewItem : public QListViewItem +{ +public: + PMPluginListViewItem( QListView* parent, PMPluginInfo* info ) + : QListViewItem( parent, info->name( ), info->description( ) ) + { + m_info = info; + m_enabled = info->enabled( ); + setStatus( ); + } + void toggleStatus( ) + { + m_enabled = !m_enabled; + setStatus( ); + } + void setStatus( ) + { + if( m_enabled ) + setText( 2, i18n( "loaded" ) ); + else + setText( 2, i18n( "deactivated" ) ); + } + PMPluginInfo* m_info; + bool m_enabled; +}; + +PMPluginSettings::PMPluginSettings( QWidget* parent, const char* name ) + : PMSettingsDialogPage( parent, name ) +{ + QVBoxLayout* vlayout = new QVBoxLayout( this, 0, KDialog::spacingHint( ) ); + + QGroupBox* gb = new QGroupBox( i18n( "Installed Plugins" ), this ); + vlayout->addWidget( gb ); + + QVBoxLayout* gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) ); + gvl->addSpacing( 10 ); + + m_pPluginsList = new QListView( gb ); + connect( m_pPluginsList, SIGNAL( selectionChanged( ) ), + SLOT( slotSelectionChanged( ) ) ); + m_pPluginsList->addColumn( i18n( "Name" ) ); + m_pPluginsList->addColumn( i18n( "Description" ) ); + m_pPluginsList->addColumn( i18n( "Status" ) ); + gvl->addWidget( m_pPluginsList, 1 ); + + QHBoxLayout* hl = new QHBoxLayout( gvl ); + m_pToggle = new QPushButton( i18n( "Load" ), gb ); + m_pToggle->setEnabled( false ); + connect( m_pToggle, SIGNAL( clicked( ) ), SLOT( slotToggle( ) ) ); + hl->addWidget( m_pToggle ); + hl->addStretch( 1 ); + + vlayout->addStretch( 1 ); +} + +void PMPluginSettings::displaySettings( ) +{ + QPtrList plugins = PMPluginManager::theManager( )->plugins( ); + QPtrListIterator it( plugins ); + + m_pPluginsList->clear( ); + for( ; *it; ++it ) + new PMPluginListViewItem( m_pPluginsList, *it ); +} + +void PMPluginSettings::applySettings( ) +{ + bool changes = false; + PMPluginListViewItem* item = + ( PMPluginListViewItem* ) m_pPluginsList->firstChild( ); + for( ; item; item = ( PMPluginListViewItem* ) item->nextSibling( ) ) + { + if( item->m_enabled != item->m_info->enabled( ) ) + { + item->m_info->enable( item->m_enabled ); + changes = true; + } + } + if( changes ) + PMPluginManager::theManager( )->updatePlugins( ); +} + +bool PMPluginSettings::validateData( ) +{ + return true; +} + +void PMPluginSettings::displayDefaults( ) +{ +} + +void PMPluginSettings::slotToggle( ) +{ + PMPluginListViewItem* item = + ( PMPluginListViewItem* ) m_pPluginsList->currentItem( ); + if( item ) + { + item->toggleStatus( ); + + if( item->m_enabled ) + m_pToggle->setText( i18n( "Deactivate" ) ); + else + m_pToggle->setText( i18n( "Load" ) ); + } +} + +void PMPluginSettings::slotSelectionChanged( ) +{ + PMPluginListViewItem* item = + ( PMPluginListViewItem* ) m_pPluginsList->currentItem( ); + if( item ) + { + m_pToggle->setEnabled( true ); + if( item->m_enabled ) + m_pToggle->setText( i18n( "Deactivate" ) ); + else + m_pToggle->setText( i18n( "Load" ) ); + } + else + m_pToggle->setEnabled( false ); +} + +#include "pmpluginsettings.moc" diff --git a/kpovmodeler/pmpluginsettings.h b/kpovmodeler/pmpluginsettings.h new file mode 100644 index 00000000..1ee9191a --- /dev/null +++ b/kpovmodeler/pmpluginsettings.h @@ -0,0 +1,62 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMPLUGINSETTINGS_H +#define PMPLUGINSETTINGS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsettingsdialog.h" + +class QFrame; +class QListView; +class QPushButton; + +/** + * Plugins configuration dialog page + */ +class PMPluginSettings : public PMSettingsDialogPage +{ + Q_OBJECT +public: + /** + * Default constructor + */ + PMPluginSettings( QWidget* parent, const char* name = 0 ); + /** */ + virtual void displaySettings( ); + /** */ + virtual void applySettings( ); + /** */ + virtual bool validateData( ); + /** */ + virtual void displayDefaults( ); + +protected slots: + void slotToggle( ); + void slotSelectionChanged( ); + +private: + QFrame* m_pPluginOptions; + QListView* m_pPluginsList; + QPushButton* m_pToggle; +}; + + +#endif diff --git a/kpovmodeler/pmpoint.cpp b/kpovmodeler/pmpoint.cpp new file mode 100644 index 00000000..2933030e --- /dev/null +++ b/kpovmodeler/pmpoint.cpp @@ -0,0 +1,98 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmpoint.h" +#include "pmvector.h" +#include "pmmatrix.h" +#include "pmmath.h" + + +PMPoint::PMPoint( ) +{ + m_coord[0] = 0; + m_coord[1] = 0; + m_coord[2] = 0; +} + +PMPoint::PMPoint( GLdouble x, GLdouble y, GLdouble z ) +{ + m_coord[0] = x; + m_coord[1] = y; + m_coord[2] = z; +} + +PMPoint::PMPoint( const PMVector& v ) +{ + if( v.size( ) == 3 ) + { + m_coord[0] = v[0]; + m_coord[1] = v[1]; + m_coord[2] = v[2]; + } + else + { + m_coord[0] = 0; + m_coord[1] = 0; + m_coord[2] = 0; + } +} + +PMPoint::PMPoint( const PMPoint& p ) +{ + m_coord[0] = p.m_coord[0]; + m_coord[1] = p.m_coord[1]; + m_coord[2] = p.m_coord[2]; +} + +PMPoint& PMPoint::operator= ( const PMPoint& p ) +{ + m_coord[0] = p.m_coord[0]; + m_coord[1] = p.m_coord[1]; + m_coord[2] = p.m_coord[2]; + + return *this; +} + +void PMPoint::transform( const PMMatrix& m ) +{ + (*this) = m * (*this); +} + +PMPoint operator* ( const PMMatrix& m, const PMPoint& p ) +{ + PMPoint result; + int c, i; + // for homogenous coordinates + double u; + + for( c = 0; c < 3; c++ ) + { + result.m_coord[c] = 0.0; + for( i = 0; i < 4; i++ ) + result.m_coord[c] += m[i][c] * ( i<3 ? p[i] : 1.0 ); + } + + u = 0.0; + for( i = 0; i < 4; i++ ) + u += m[i][3] * ( i<3 ? p[i] : 1.0 ); + if( !approxZero( u ) ) + for( i = 0; i < 3; i++ ) + result.m_coord[i] /= u; + + return result; +} diff --git a/kpovmodeler/pmpoint.h b/kpovmodeler/pmpoint.h new file mode 100644 index 00000000..729d60c0 --- /dev/null +++ b/kpovmodeler/pmpoint.h @@ -0,0 +1,122 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMPOINT_H +#define PMPOINT_H + +#include "GL/gl.h" +#include + +class PMVector; +class PMMatrix; + +/** + * Class for 3d points. + * + * Used in @ref PMViewStructure. + * + * Optimized for rendering with opengl + */ + +class PMPoint +{ +public: + /** + * Creates a point with coordinates [0,0,0] + */ + PMPoint( ); + /** + * Creates a point with coordinates [x,y,z] + */ + PMPoint( GLdouble x, GLdouble y, GLdouble z ); + /** + * Creates a point from a vector. The size of the vector has to be 3 + */ + PMPoint( const PMVector& v ); + /** + * Copy constructor + */ + PMPoint( const PMPoint& p ); + + /** + * Returns a reference to a coordinate, 0:x, 1:y, 2:z + */ + GLdouble& operator[] ( int index ) { return m_coord[index];} + /** + * Returns a reference to a coordinate, 0:x, 1:y, 2:z + */ + const GLdouble& operator[] ( int index ) const { return m_coord[index];} + + /** + * Returns the x coordinate + */ + GLdouble x( ) const { return m_coord[0]; } + /** + * Returns the y coordinate + */ + GLdouble y( ) const { return m_coord[1]; } + /** + * Returns the z coordinate + */ + GLdouble z( ) const { return m_coord[2]; } + + /** + * Sets the x coordinate + */ + void setX( const GLdouble newx ) { m_coord[0] = newx; } + /** + * Sets the y coordinate + */ + void setY( const GLdouble newy ) { m_coord[1] = newy; } + /** + * Sets the z coordinate + */ + void setZ( const GLdouble newz ) { m_coord[2] = newz; } + + /** + * Transforms the point p with the matrix m + * @see transform + */ + friend PMPoint operator* ( const PMMatrix& m, const PMPoint& p ); + /** + * Assigns c to the point + */ + PMPoint& operator= ( const PMPoint& c ); + /** + * Transforms the point with the matrix m. Same as p = m * p + * + * size must be 3! + */ + void transform( const PMMatrix& m ); + +private: + /** + * The coords. THIS MEMBER HAS TO BE THE FIRST AND ONLY ONE + * (for rendering with OpenGL)! + */ + GLdouble m_coord[3]; +}; + +/** + * @ref QMemArray of PMPoints + */ +typedef QMemArray PMPointArray; + + +#endif diff --git a/kpovmodeler/pmpolynom.cpp b/kpovmodeler/pmpolynom.cpp new file mode 100644 index 00000000..93555a58 --- /dev/null +++ b/kpovmodeler/pmpolynom.cpp @@ -0,0 +1,238 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmpolynom.h" +#include "pmpolynomedit.h" + +#include "pmxmlhelper.h" +#include "pmmemento.h" + +#include + +const double c_defaultCoefficients[10] = +{ // Hyperboloid_Y + 1.0, 0.0, 0.0, + 0.0, -1.0, 0.0, + 0.0, 1.0, 0.0, + -1.0 +}; +const int c_defaultOrder = 2; +const bool c_defaultSturm = true; +const int c_polynomSize[8] = { 0, 0, 10, 20, 35, 56, 84, 120 }; + +PMDefinePropertyClass( PMPolynom, PMPolynomProperty ); + +class PMCoefficientProperty : public PMPropertyBase +{ +public: + PMCoefficientProperty( ) + : PMPropertyBase( "coefficients", PMVariant::Double ) + { + m_index = 0; + } + virtual int dimensions( ) const { return 1; } + virtual void setIndex( int /*dimension*/, int index ) + { + m_index = index; + } + virtual int size( PMObject* object, int /*dimension*/ ) const + { + return c_polynomSize[ ( ( PMPolynom* ) object )->polynomOrder( ) ]; + } +protected: + virtual bool setProtected( PMObject* obj, const PMVariant& var ) + { + PMPolynom* p = ( PMPolynom* ) obj; + PMVector v = p->coefficients( ); + v[m_index] = var.doubleData( ); + p->setCoefficients( v ); + + return true; + } + virtual PMVariant getProtected( const PMObject* obj ) + { + PMPolynom* p = ( PMPolynom* ) obj; + return PMVariant( p->coefficients( )[m_index] ); + } + +private: + int m_index; +}; + +PMMetaObject* PMPolynom::s_pMetaObject = 0; +PMObject* createNewPolynom( PMPart* part ) +{ + return new PMPolynom( part ); +} + +PMPolynom::PMPolynom( PMPart* part ) + : Base( part ) +{ + int i; + m_order = c_defaultOrder; + m_coefficients = PMVector( 10 ); + for( i = 0; i < 10; i++ ) + m_coefficients[i] = c_defaultCoefficients[i]; + m_sturm = c_defaultSturm; +} + +PMPolynom::PMPolynom( const PMPolynom& p ) + : Base( p ) +{ + m_order = p.m_order; + m_coefficients = p.m_coefficients; + m_sturm = p.m_sturm; +} + +PMPolynom::~PMPolynom( ) +{ +} + +QString PMPolynom::description( ) const +{ + if( m_order == 2 ) + return i18n( "quadric" ); + else if( m_order == 3 ) + return i18n( "cubic" ); + else if( m_order == 4 ) + return i18n( "quartic" ); + return i18n( "polynom" ); +} + +void PMPolynom::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "order", m_order ); + e.setAttribute( "coefficients", m_coefficients.serializeXML( ) ); + e.setAttribute( "sturm", m_sturm ); + Base::serialize( e, doc ); +} + +void PMPolynom::readAttributes( const PMXMLHelper& h ) +{ + m_order = h.intAttribute( "order", c_defaultOrder ); + m_coefficients = h.vectorAttribute( "coefficients", m_coefficients ); + m_sturm = h.boolAttribute( "sturm", c_defaultSturm ); + Base::readAttributes( h ); +} + +PMMetaObject* PMPolynom::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Polynom", Base::metaObject( ), + createNewPolynom ); + s_pMetaObject->addProperty( + new PMPolynomProperty( "polynomOrder", &PMPolynom::setPolynomOrder, + &PMPolynom::polynomOrder ) ); + s_pMetaObject->addProperty( + new PMPolynomProperty( "sturm", &PMPolynom::setSturm, + &PMPolynom::sturm ) ); + + s_pMetaObject->addProperty( new PMCoefficientProperty( ) ); + } + return s_pMetaObject; +} + +void PMPolynom::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +PMDialogEditBase* PMPolynom::editWidget( QWidget* parent ) const +{ + return new PMPolynomEdit( parent ); +} + +void PMPolynom::setPolynomOrder( int o ) +{ + if( ( o < 2 ) || ( o > 7 ) ) + { + kdError( PMArea ) << "Invalid order in PMPolynom::setPolynomOrder\n"; + o = 2; + } + if( o != m_order ) + { + if( m_pMemento ) + { + m_pMemento->addData( s_pMetaObject, PMOrderID, m_order ); + if( ( o <= 4 ) || ( m_order <= 4 ) ) + m_pMemento->setDescriptionChanged( ); + } + m_order = o; + } +} + +void PMPolynom::setCoefficients( const PMVector& c ) +{ + if( c.size( ) != ( unsigned ) c_polynomSize[m_order] ) + kdError( PMArea ) << "Wrong vector size in PMPolynom::setCoefficients\n"; + + if( c != m_coefficients ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCoefficientsID, m_coefficients ); + m_coefficients = c; + m_coefficients.resize( c_polynomSize[m_order] ); + //setViewStructureChanged( ); + } +} + +void PMPolynom::setSturm( bool s ) +{ + if( m_sturm != s ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSturmID, m_sturm ); + m_sturm = s; + } +} + +void PMPolynom::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMOrderID: + setPolynomOrder( data->intData( ) ); + break; + case PMCoefficientsID: + setCoefficients( data->vectorData( ) ); + break; + case PMSturmID: + setSturm( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMPolynom::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmpolynom.h b/kpovmodeler/pmpolynom.h new file mode 100644 index 00000000..dc59be67 --- /dev/null +++ b/kpovmodeler/pmpolynom.h @@ -0,0 +1,105 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMPOLYNOM_H +#define PMPOLYNOM_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" +#include "pmvector.h" + +/** + * Class for povray polynoms. + */ + +class PMPolynom : public PMSolidObject +{ + typedef PMSolidObject Base; +public: + /** + * Creates an empty PMPolynom + */ + PMPolynom( PMPart* part ); + /** + * Copy constructor + */ + PMPolynom( const PMPolynom& p ); + /** + * deletes the PMPolynom + */ + virtual ~PMPolynom( ); + + /** */ + virtual PMObject* copy( ) const { return new PMPolynom( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** */ + virtual QString pixmap( ) const { return QString( "pmpolynom" ); } + /** + * Returns a new @ref PMPolynomEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual void restoreMemento( PMMemento* s ); + + /** */ + int polynomOrder( ) const { return m_order; } + /** + * Sets the polynom order + */ + void setPolynomOrder( int order ); + /** + * Returns the coefficients. + */ + PMVector coefficients( ) const { return m_coefficients; } + /** + * Sets the coefficients. + */ + void setCoefficients( const PMVector& p ); + /** + * Returns the sturm flag + */ + bool sturm( ) const { return m_sturm; } + /** + * Sets the sturm flag + */ + void setSturm( bool s ); +private: + enum PMPolynomMementoID { PMOrderID, PMCoefficientsID, PMSturmID }; + int m_order; + PMVector m_coefficients; + bool m_sturm; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmpolynomedit.cpp b/kpovmodeler/pmpolynomedit.cpp new file mode 100644 index 00000000..b236a8c6 --- /dev/null +++ b/kpovmodeler/pmpolynomedit.cpp @@ -0,0 +1,255 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmpolynomedit.h" +#include "pmpolynom.h" +#include "pmpolynomexponents.h" +#include "pmlineedits.h" +#include "pmformulalabel.h" + +#include +#include +#include +#include +#include +#include + +PMPolynomEdit::PMPolynomEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; + m_currentOrder = 0; + m_readOnly = false; +} + +void PMPolynomEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Order" ), this ) ); + m_pOrder = new QSpinBox( 2, 7, 1, this ); + hl->addWidget( m_pOrder ); + hl->addStretch( 1 ); + connect( m_pOrder, SIGNAL( valueChanged( int ) ), SLOT( slotOrderChanged( int ) ) ); + + topLayout( )->addWidget( new QLabel( i18n( "Formula:" ), this ) ); + m_pPolyWidget = new QWidget( this ); + topLayout( )->addWidget( m_pPolyWidget ); + m_pSturm = new QCheckBox( i18n( "Sturm" ), this ); + topLayout( )->addWidget( m_pSturm ); + connect( m_pSturm, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMPolynomEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Polynom" ) ) + { + bool readOnly = o->isReadOnly( ); + m_readOnly = readOnly; + m_pDisplayedObject = ( PMPolynom* ) o; + + displayCoefficients( m_pDisplayedObject->coefficients( ), + m_pDisplayedObject->polynomOrder( ), + m_pDisplayedObject->polynomOrder( ) ); + + m_pSturm->setChecked( m_pDisplayedObject->sturm( ) ); + m_pSturm->setEnabled( !readOnly ); + if( m_pDisplayedObject->polynomOrder( ) == 2 ) + m_pSturm->hide( ); + else + m_pSturm->show( ); + + bool sb = m_pOrder->signalsBlocked( ); + m_pOrder->blockSignals( true ); + m_pOrder->setValue( m_pDisplayedObject->polynomOrder( ) ); + m_pOrder->blockSignals( sb ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMPolynomEdit: Can't display object\n"; +} + +void PMPolynomEdit::displayCoefficients( const PMVector& co, int cOrder, + int dOrder ) +{ + QValueList& polynom + = PMPolynomExponents::polynom( dOrder ); + + if( dOrder != m_currentOrder ) + { + if( m_currentOrder > 0 ) + { + if( m_pPolyWidget->layout( ) ) + delete m_pPolyWidget->layout( ); + + m_labels.setAutoDelete( true ); + m_labels.clear( ); + m_labels.setAutoDelete( false ); + m_edits.setAutoDelete( true ); + m_edits.clear( ); + m_edits.setAutoDelete( false ); + } + + int nedit = polynom.count( ); + int nr = ( nedit + 2 ) / 3; + int i; + + QGridLayout* gl = new QGridLayout( m_pPolyWidget, nr * 2 - 1, 9, 0 ); + QLabel* l = 0; + PMFloatEdit* edit; + PMFormulaLabel* fl; + + QValueList::ConstIterator it = polynom.begin( ); + QString text; + int row, col; + QString plus( "+" ); + + for( i = 0; it != polynom.end( ); i++, ++it ) + { + row = ( i / 3 ) * 2; + col = ( i % 3 ) * 3; + + if( i != 0 ) + { + l = new QLabel( plus, m_pPolyWidget ); + m_labels.append( l ); + gl->addWidget( l, row, col ); + l->show( ); + } + + edit = new PMFloatEdit( m_pPolyWidget ); + connect( edit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + m_edits.append( edit ); + gl->addWidget( edit, row, col + 1 ); + edit->show( ); + edit->setReadOnly( m_readOnly ); + + fl = new PMFormulaLabel( *it, m_pPolyWidget ); + + m_labels.append( fl ); + gl->addWidget( fl, row, col + 2 ); + fl->show( ); + } + for( i = 0; i < ( nr - 1 ); i++ ) + gl->addRowSpacing( i * 2 + 1, KDialog::spacingHint( ) ); + + emit sizeChanged( ); + } + m_currentOrder = dOrder; + + + if( dOrder == cOrder ) + { + QPtrListIterator eit( m_edits ); + int i; + for( i = 0; *eit; ++eit, ++i ) + ( *eit )->setValue( co[i] ); + } + else if( dOrder > cOrder ) + { + QValueList::ConstIterator dit = polynom.begin( ); + QValueList& cpoly + = PMPolynomExponents::polynom( cOrder ); + QValueList::ConstIterator cit = cpoly.begin( ); + QPtrListIterator eit( m_edits ); + int i = 0; + + for( ; ( dit != polynom.end( ) ) && ( cit != cpoly.end( ) ); ++dit, ++eit ) + { + if( *dit == *cit ) + { + ( *eit )->setValue( co[i] ); + i++; + cit++; + } + else + ( *eit )->setValue( 0.0 ); + } + if( ( dit != polynom.end( ) ) || ( cit != cpoly.end( ) ) ) + kdError( PMArea ) << "displayExponents is buggy!\n"; + } + else // dOrder < cOrder + { + QValueList::ConstIterator dit = polynom.begin( ); + QValueList& cpoly + = PMPolynomExponents::polynom( cOrder ); + QValueList::ConstIterator cit = cpoly.begin( ); + QPtrListIterator eit( m_edits ); + int i = 0; + + for( ; ( dit != polynom.end( ) ) && ( cit != cpoly.end( ) ); ++cit, ++i ) + { + if( *dit == *cit ) + { + ( *eit )->setValue( co[i] ); + ++eit; + ++dit; + } + } + if( ( dit != polynom.end( ) ) || ( cit != cpoly.end( ) ) ) + kdError( PMArea ) << "displayExponents is buggy!\n"; + } +} + +PMVector PMPolynomEdit::coefficients( ) const +{ + QPtrListIterator eit( m_edits ); + int num = m_edits.count( ); + PMVector v( num ); + int i; + + for( i = 0 ; *eit; ++eit, ++i ) + v[i] = ( *eit )->value( ); + return v; +} + +void PMPolynomEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + m_pDisplayedObject->setPolynomOrder( m_pOrder->value( ) ); + m_pDisplayedObject->setCoefficients( coefficients( ) ); + + Base::saveContents( ); + + m_pDisplayedObject->setSturm( m_pSturm->isChecked( ) ); + } +} + +bool PMPolynomEdit::isDataValid( ) +{ + QPtrListIterator eit( m_edits ); + for( ; *eit; ++eit ) + if( !( *eit )->isDataValid( ) ) + return false; + return Base::isDataValid( ); +} + +void PMPolynomEdit::slotOrderChanged( int order ) +{ + if( order == 2 ) + m_pSturm->hide( ); + else + m_pSturm->show( ); + + displayCoefficients( coefficients( ), m_currentOrder, order ); +} + +#include "pmpolynomedit.moc" diff --git a/kpovmodeler/pmpolynomedit.h b/kpovmodeler/pmpolynomedit.h new file mode 100644 index 00000000..6ffb05b4 --- /dev/null +++ b/kpovmodeler/pmpolynomedit.h @@ -0,0 +1,80 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMPOLYNOMEDIT_H +#define PMPOLYNOMEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" +#include + +class PMPolynom; +class PMFloatEdit; +class PMFormulaLabel; +class QSpinBox; +class QCheckBox; + +/** + * Dialog edit class for @ref PMPolynom + */ +class PMPolynomEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMPolynomEdit with parent and name + */ + PMPolynomEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + void slotOrderChanged( int ); + +private: + void displayCoefficients( const PMVector& co, int cOrder, int dOrder ); + PMVector coefficients( ) const; + + PMPolynom* m_pDisplayedObject; + + int m_currentOrder; + + QWidget* m_pPolyWidget; + QPtrList m_labels; + QPtrList m_edits; + QCheckBox* m_pSturm; + QSpinBox* m_pOrder; + bool m_readOnly; +}; + + +#endif diff --git a/kpovmodeler/pmpolynomexponents.cpp b/kpovmodeler/pmpolynomexponents.cpp new file mode 100644 index 00000000..fdda7bdf --- /dev/null +++ b/kpovmodeler/pmpolynomexponents.cpp @@ -0,0 +1,71 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmpolynomexponents.h" +#include "pmdebug.h" + +bool PMPolynomExponents::m_created[6] = { false, false, false, + false, false, false }; +QValueList PMPolynomExponents::m_lists[6]; + +PMPolynomExponents operator+ ( const PMPolynomExponents& p1, + const PMPolynomExponents& p2 ) +{ + return PMPolynomExponents( p1.m_exponents[0] + p2.m_exponents[0], + p1.m_exponents[1] + p2.m_exponents[1], + p1.m_exponents[2] + p2.m_exponents[2] ); +} + +QValueList& PMPolynomExponents::polynom( int n ) +{ + if( ( n < 2 ) || ( n > 7 ) ) + { + n = 2; + kdError( PMArea ) << "Wrong polynom order in PMPolynomExponents::polynom( )\n"; + } + + if( !m_created[n-2] ) + { + m_lists[n-2] = recPolynom( PMPolynomExponents( 0, 0, 0 ), 0, n, 0 ); + m_created[n-2] = true; +// kdDebug( PMArea ) << "Polynom n: " << n << " size: " << m_lists[n-2].count( ) << endl; + } + + return m_lists[n-2]; +} + +QValueList +PMPolynomExponents::recPolynom( const PMPolynomExponents& base, + int xyz, int n, int rem ) +{ + QValueList res; + + if( n >= 0 ) + { + if( ( ( rem + n ) == 0 ) || ( xyz > 2 ) ) + res.append( base ); + else + { + PMPolynomExponents newBase = base; + newBase.setExponent( xyz, n ); + res += recPolynom( newBase, xyz + 1, rem, 0 ); + res += recPolynom( base, xyz, n - 1, rem + 1 ); + } + } + + return res; +} diff --git a/kpovmodeler/pmpolynomexponents.h b/kpovmodeler/pmpolynomexponents.h new file mode 100644 index 00000000..6f1812ba --- /dev/null +++ b/kpovmodeler/pmpolynomexponents.h @@ -0,0 +1,129 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMPOLYNOMEXPONENTS_H +#define PMPOLYNOMEXPONENTS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +/** + * Helper class for the @ref PMPolynomBaseEdit widget + */ +class PMPolynomExponents +{ +public: + /** + * All exponents are initialized with 0 + */ + PMPolynomExponents( ) + { + m_exponents[0] = m_exponents[1] = m_exponents[2] = 0; + } + /** + * The exponents are initialized with x, y, z + */ + PMPolynomExponents( int x, int y, int z ) + { + m_exponents[0] = x; + m_exponents[1] = y; + m_exponents[2] = z; + } + + /** + * Returns the ith exponent + */ + int exponent( int i ) const { return m_exponents[i]; } + /** + * Sets the ith exponent + */ + void setExponent( int i, int exp ) { m_exponents[i] = exp; } + + /** + * Returns the x exponent + */ + int xExponent( ) const { return m_exponents[0]; } + /** + * Sets the x exponent + */ + void setXExponent( int exp ) { m_exponents[0] = exp; } + /** + * Returns the y exponent + */ + int yExponent( ) const { return m_exponents[1]; } + /** + * Sets the y exponent + */ + void setYExponent( int exp ) { m_exponents[1] = exp; } + /** + * Returns the z exponent + */ + int zExponent( ) const { return m_exponents[2]; } + /** + * Sets the z exponent + */ + void setZExponent( int exp ) { m_exponents[2] = exp; } + + bool operator== ( const PMPolynomExponents& e ) const + { + return ( m_exponents[0] == e.m_exponents[0] ) && + ( m_exponents[1] == e.m_exponents[1] ) && + ( m_exponents[2] == e.m_exponents[2] ); + } + bool operator!= ( const PMPolynomExponents& e ) const + { + return !( *this == e ); + } + PMPolynomExponents& operator= ( const PMPolynomExponents& p ) + { + m_exponents[0] = p.m_exponents[0]; + m_exponents[1] = p.m_exponents[1]; + m_exponents[2] = p.m_exponents[2]; + return *this; + } + friend PMPolynomExponents operator+ ( const PMPolynomExponents& p1, + const PMPolynomExponents& p2 ); + + /** + * Returns the sum of the exponents + */ + int sum( ) const { return m_exponents[0] + m_exponents[1] + m_exponents[2]; } + +private: + int m_exponents[3]; + + // static stuff +public: + /** + * Returns the exponents for a polynom with order n ( 2 <= n <= 7 ) + */ + static QValueList& polynom( int n ); + +private: + static QValueList //... + recPolynom( const PMPolynomExponents& base, int xyz, int n, int rem ); + static bool m_created[6]; + static QValueList m_lists[6]; +}; + +#endif diff --git a/kpovmodeler/pmpovray31format.cpp b/kpovmodeler/pmpovray31format.cpp new file mode 100644 index 00000000..417dd177 --- /dev/null +++ b/kpovmodeler/pmpovray31format.cpp @@ -0,0 +1,153 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmpovray31format.h" +#include "pmpovray31serialization.h" + +#include "pmpovrayparser.h" +#include "pmoutputdevice.h" + +#include + +PMPovray31Format::PMPovray31Format( ) + : PMPovrayFormat( ) +{ + registerMethod( "BicubicPatch", PMPov31SerBicubicPatch ); + registerMethod( "BlendMapModifiers", PMPov31SerBlendMapModifiers ); + registerMethod( "Blob", PMPov31SerBlob ); + registerMethod( "BlobCylinder", PMPov31SerBlobCylinder ); + registerMethod( "BlobSphere", PMPov31SerBlobSphere ); + registerMethod( "BoundedBy", PMPov31SerBoundedBy ); + registerMethod( "Box", PMPov31SerBox ); + registerMethod( "BumpMap", PMPov31SerBumpMap ); + registerMethod( "Camera", PMPov31SerCamera ); + registerMethod( "ClippedBy", PMPov31SerClippedBy ); + registerMethod( "Comment", PMPov31SerComment ); + registerMethod( "CompositeObject", PMPov31SerCompositeObject ); + registerMethod( "Cone", PMPov31SerCone ); + registerMethod( "CSG", PMPov31SerCSG ); + registerMethod( "Cylinder", PMPov31SerCylinder ); + registerMethod( "Declare", PMPov31SerDeclare ); + registerMethod( "Density", PMPov31SerDensity ); + registerMethod( "Disc", PMPov31SerDisc ); + registerMethod( "Finish", PMPov31SerFinish ); + registerMethod( "Fog", PMPov31SerFog ); + registerMethod( "GlobalSettings", PMPov31SerGlobalSettings ); + registerMethod( "GraphicalObject", PMPov31SerGraphicalObject ); + registerMethod( "HeightField", PMPov31SerHeightField ); + registerMethod( "ImageMap", PMPov31SerImageMap ); + registerMethod( "Interior", PMPov31SerInterior ); + registerMethod( "JuliaFractal", PMPov31SerJuliaFractal ); + registerMethod( "Lathe", PMPov31SerLathe ); + registerMethod( "Light", PMPov31SerLight ); + registerMethod( "ListPattern", PMPov31SerListPattern ); + registerMethod( "TextureList", PMPov31SerTextureList ); + registerMethod( "PigmentList", PMPov31SerPigmentList ); + registerMethod( "ColorList", PMPov31SerColorList ); + registerMethod( "DensityList", PMPov31SerDensityList ); + registerMethod( "NormalList", PMPov31SerNormalList ); + registerMethod( "LooksLike", PMPov31SerLooksLike ); + registerMethod( "Material", PMPov31SerMaterial ); + registerMethod( "MaterialMap", PMPov31SerMaterialMap ); + registerMethod( "Media", PMPov31SerMedia ); + registerMethod( "NamedObject", PMPov31SerNamedObject ); + registerMethod( "Normal", PMPov31SerNormal ); + registerMethod( "ObjectLink", PMPov31SerObjectLink ); + registerMethod( "Pattern", PMPov31SerPattern ); + registerMethod( "Pigment", PMPov31SerPigment ); + registerMethod( "Plane", PMPov31SerPlane ); + registerMethod( "Polynom", PMPov31SerPolynom ); + registerMethod( "PovrayMatrix", PMPov31SerPovrayMatrix ); + registerMethod( "Prism", PMPov31SerPrism ); + registerMethod( "QuickColor", PMPov31SerQuickColor ); + registerMethod( "Rainbow", PMPov31SerRainbow ); + registerMethod( "Raw", PMPov31SerRaw ); + registerMethod( "Rotate", PMPov31SerRotate ); + registerMethod( "Scale", PMPov31SerScale ); + registerMethod( "Scene", PMPov31SerScene ); + registerMethod( "SkySphere", PMPov31SerSkySphere ); + registerMethod( "Slope", PMPov31SerSlope ); + registerMethod( "SolidColor", PMPov31SerSolidColor ); + registerMethod( "SolidObject", PMPov31SerSolidObject ); + registerMethod( "SurfaceOfRevolution", PMPov31SerSurfaceOfRevolution ); + registerMethod( "Sphere", PMPov31SerSphere ); + registerMethod( "SuperquadricEllipsoid", PMPov31SerSuperquadricEllipsoid ); + registerMethod( "Text", PMPov31SerText ); + registerMethod( "Texture", PMPov31SerTexture ); + registerMethod( "TextureBase", PMPov31SerTextureBase ); + registerMethod( "TextureMapBase", PMPov31SerTextureMapBase ); + registerMethod( "TextureMap", PMPov31SerTextureMap ); + registerMethod( "PigmentMap", PMPov31SerPigmentMap ); + registerMethod( "ColorMap", PMPov31SerColorMap ); + registerMethod( "NormalMap", PMPov31SerNormalMap ); + registerMethod( "SlopeMap", PMPov31SerSlopeMap ); + registerMethod( "DensityMap", PMPov31SerDensityMap ); + registerMethod( "Torus", PMPov31SerTorus ); + registerMethod( "Translate", PMPov31SerTranslate ); + registerMethod( "Triangle", PMPov31SerTriangle ); + registerMethod( "Warp", PMPov31SerWarp ); + registerMethod( "DetailObject", PMPov31SerDetailObject ); +} + + +PMPovray31Format::~PMPovray31Format( ) +{ + +} + +PMParser* PMPovray31Format::newParser( PMPart* part, QIODevice* dev ) const +{ + return new PMPovrayParser( part, dev ); +} + +PMParser* PMPovray31Format::newParser( PMPart* part, const QByteArray& data ) const +{ + return new PMPovrayParser( part, data ); +} + +PMSerializer* PMPovray31Format::newSerializer( QIODevice* dev ) +{ + return new PMOutputDevice( dev, this ); +} + +PMRenderer* PMPovray31Format::newRenderer( PMPart* ) const +{ + // TODO + return 0; +} + +QString PMPovray31Format::mimeType( ) const +{ + return QString( "text/plain" ); +} + +QStringList PMPovray31Format::importPatterns( ) const +{ + QStringList result; + result.push_back( QString( "*.pov *.inc|" ) + + i18n( "POV-Ray 3.1 Files (*.pov, *.inc)" ) ); + return result; +} + +QStringList PMPovray31Format::exportPatterns( ) const +{ + QStringList result; + result.push_back( QString( "*.pov|" ) + i18n( "POV-Ray 3.1 Files (*.pov)" ) ); + result.push_back( QString( "*.ini|" ) + i18n( "POV-Ray 3.1 Include Files (*.ini)" ) ); + return result; + +} diff --git a/kpovmodeler/pmpovray31format.h b/kpovmodeler/pmpovray31format.h new file mode 100644 index 00000000..a0e3453e --- /dev/null +++ b/kpovmodeler/pmpovray31format.h @@ -0,0 +1,64 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMPOVRAY31_FORMAT_H +#define PMPOVRAY31_FORMAT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmpovrayformat.h" + +/** + * Description class for POV-Ray 3.1 + */ +class PMPovray31Format : public PMPovrayFormat +{ +public: + /** + * Default constructor + */ + PMPovray31Format( ); + /** + * Destructor + */ + virtual ~PMPovray31Format( ); + + /** */ + virtual QString name( ) const { return "povray31"; }; + /** */ + virtual QString description( ) const { return "POV-Ray 3.1"; } + /** */ + virtual int services( ) const { return AllServices; } + /** */ + virtual PMParser* newParser( PMPart*, QIODevice* ) const; + /** */ + virtual PMParser* newParser( PMPart*, const QByteArray& ) const; + /** */ + virtual PMSerializer* newSerializer( QIODevice* ); + /** */ + virtual PMRenderer* newRenderer( PMPart* ) const; + /** */ + virtual QString mimeType( ) const; + /** */ + virtual QStringList importPatterns( ) const; + /** */ + virtual QStringList exportPatterns( ) const; +}; + +#endif diff --git a/kpovmodeler/pmpovray31serialization.cpp b/kpovmodeler/pmpovray31serialization.cpp new file mode 100644 index 00000000..dd4b7603 --- /dev/null +++ b/kpovmodeler/pmpovray31serialization.cpp @@ -0,0 +1,2199 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmpovray31serialization.h" +#include "pmoutputdevice.h" +#include "pmallobjects.h" + +const double c_defaultPatchFlatness = 0; + +void PMPov31SerBicubicPatch( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMBicubicPatch* o = ( PMBicubicPatch* ) object; + + int u, v; + QString str, line; + dev->objectBegin( "bicubic_patch" ); + + dev->writeName( object->name( ) ); + + str.setNum( o->patchType( ) ); + dev->writeLine( "type " + str ); + if( !approx( o->flatness( ), c_defaultPatchFlatness ) ) + { + str.setNum( o->flatness( ) ); + dev->writeLine( "flatness " + str ); + } + str.setNum( o->uSteps( ) ); + dev->writeLine( "u_steps " + str ); + str.setNum( o->vSteps( ) ); + dev->writeLine( "v_steps " + str ); + + for( v = 0; v < 4; v++ ) + { + line = o->controlPoint( v*4 ).serialize( ); + for( u = 1; u < 4; u++ ) + line += QString( ", " ) + o->controlPoint( u+4*v ).serialize( ); + if( v != 3 ) + line += ","; + dev->writeLine( line ); + } + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerBlendMapModifiers( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev ) +{ + PMBlendMapModifiers* o = ( PMBlendMapModifiers* ) object; + + QString str; + + if( o->isFrequencyEnabled( ) ) + { + str.setNum( o->frequency( ) ); + dev->writeLine( "frequency " + str ); + } + + if( o->isPhaseEnabled( ) ) + { + str.setNum( o->phase( ) ); + dev->writeLine( "phase " + str ); + } + + if( o->isWaveFormEnabled( ) ) + { + switch( o->waveFormType( ) ) + { + case PMBlendMapModifiers::RampWave: + dev->writeLine( "ramp_wave" ); + break; + case PMBlendMapModifiers::TriangleWave: + dev->writeLine( "triangle_wave" ); + break; + case PMBlendMapModifiers::SineWave: + dev->writeLine( "sine_wave" ); + break; + case PMBlendMapModifiers::ScallopWave: + dev->writeLine( "scallop_wave" ); + break; + case PMBlendMapModifiers::CubicWave: + dev->writeLine( "cubic_wave" ); + break; + case PMBlendMapModifiers::PolyWave: + str.setNum( o->waveFormExponent( ) ); + dev->writeLine( "poly_wave " + str ); + break; + } + } +} + +void PMPov31SerBlob( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMBlob* o = ( PMBlob* ) object; + + dev->objectBegin( "blob" ); + + dev->writeName( object->name( ) ); + dev->writeLine( QString( "threshold %1" ).arg( o->threshold( ) ) ); + + dev->callSerialization( object, metaObject->superClass( ) ); + + if( o->sturm( ) ) + dev->writeLine( "sturm" ); + if( o->hierarchy( ) ) + dev->writeLine( "hierarchy" ); + + dev->objectEnd( ); +} + +void PMPov31SerBlobCylinder( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMBlobCylinder* o = ( PMBlobCylinder* ) object; + + dev->objectBegin( "cylinder" ); + + dev->writeName( object->name( ) ); + QString str1; + str1.setNum( o->radius( ) ); + dev->writeLine( o->end1( ).serialize( ) + ", " + o->end2( ).serialize( ) + + ", " + str1 + "," ); + dev->writeLine( QString( "strength %1" ).arg( o->strength( ) ) ); + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerBlobSphere( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMBlobSphere* o = ( PMBlobSphere* ) object; + + dev->objectBegin( "sphere" ); + dev->writeName( object->name( ) ); + dev->writeLine( o->centre( ).serialize( ) + QString( ", %1," ).arg( o->radius( ) ) ); + dev->writeLine( QString( "strength %1" ).arg( o->strength( ) ) ); + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerBoundedBy( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMBoundedBy* o = ( PMBoundedBy* ) object; + + dev->objectBegin( "bounded_by" ); + if( o->clippedBy( ) ) + dev->writeLine( "clipped_by" ); + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerBox( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMBox* o = ( PMBox* ) object; + + dev->objectBegin( "box" ); + + dev->writeName( object->name( ) ); + dev->writeLine( o->corner1( ).serialize( ) + ", " + o->corner2( ).serialize( ) ); + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerBumpMap( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev ) +{ + PMBumpMap* o = ( PMBumpMap* ) object; + + QString str1; + + dev->objectBegin( "bump_map" ); + + switch( o->bitmapType( ) ) + { + case PMBumpMap::BitmapGif: + dev->writeLine( "gif" ); + break; + case PMBumpMap::BitmapTga: + dev->writeLine( "tga" ); + break; + case PMBumpMap::BitmapIff: + dev->writeLine( "iff" ); + break; + case PMBumpMap::BitmapPpm: + dev->writeLine( "ppm" ); + break; + case PMBumpMap::BitmapPgm: + dev->writeLine( "pgm" ); + break; + case PMBumpMap::BitmapPng: + dev->writeLine( "png" ); + break; + case PMBumpMap::BitmapJpeg: + dev->writeLine( "jpeg" ); + break; + case PMBumpMap::BitmapTiff: + dev->writeLine( "tiff" ); + break; + case PMBumpMap::BitmapSys: + dev->writeLine( "sys" ); + break; + } + + dev->writeLine( "\"" + o->bitmapFile( ) + "\"" ); + + if( o->isOnceEnabled( ) ) + dev->writeLine( "once" ); + + switch( o->mapType( ) ) + { + case PMBumpMap::MapPlanar: + dev->writeLine( "map_type 0" ); + break; + case PMBumpMap::MapSpherical: + dev->writeLine( "map_type 1" ); + break; + case PMBumpMap::MapCylindrical: + dev->writeLine( "map_type 2" ); + break; + case PMBumpMap::MapToroidal: + dev->writeLine( "map_type 5" ); + break; + } + switch( o->interpolateType( ) ) + { + case PMBumpMap::InterpolateBilinear: + dev->writeLine( "interpolate 2" ); + break; + case PMBumpMap::InterpolateNormalized: + dev->writeLine( "interpolate 4" ); + break; + default: + break; + } + + if( o->isUseIndexEnabled( ) ) + dev->writeLine( "use_index" ); + + if( o->bumpSize( ) ) + { + str1.setNum( o->bumpSize( ) ); + dev->writeLine( "bump_size " + str1 ); + } + + dev->objectEnd( ); +} + +void PMPov31SerCamera( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMCamera* o = ( PMCamera* ) object; + + dev->objectBegin( "camera" ); + QString str; + + dev->writeName( object->name( ) ); + + if( o->cameraType( ) == PMCamera::Cylinder ) + { + str.setNum( o->cylinderType( ) ); + dev->writeLine( "cylinder " + str ); + } + else + dev->writeLine( o->cameraTypeToString( o->cameraType( ) ) ); + + dev->writeLine( "location " + o->location( ).serialize( ) ); + dev->writeLine( "sky " + o->sky( ).serialize( ) ); + dev->writeLine( "direction " + o->direction( ).serialize( ) ); + dev->writeLine( "right " + o->right( ).serialize( ) ); + dev->writeLine( "up " + o->up( ).serialize( ) ); + dev->writeLine( "look_at " + o->lookAt( ).serialize( ) ); + + if( ( o->cameraType( ) != PMCamera::Orthographic ) && + ( o->cameraType( ) != PMCamera::Omnimax ) && + ( o->cameraType( ) != PMCamera::Panoramic ) && o->isAngleEnabled( ) ) + { + str.setNum( o->angle( ) ); + dev->writeLine( "angle " + str ); + } + if( o->isFocalBlurEnabled( ) && ( o->cameraType( ) == PMCamera::Perspective ) ) + { + str.setNum( o->aperture( ) ); + dev->writeLine( "aperture " + str ); + str.setNum( o->blurSamples( ) ); + dev->writeLine( "blur_samples " + str ); + dev->writeLine( "focal_point " + o->focalPoint( ).serialize( ) ); + str.setNum( o->confidence( ) ); + dev->writeLine( "confidence " + str ); + str.setNum( o->variance( ) ); + dev->writeLine( "variance " + str ); + } + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerClippedBy( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMClippedBy* o = ( PMClippedBy* ) object; + + dev->objectBegin( "clipped_by" ); + if( o->boundedBy( ) ) + dev->writeLine( "bounded_by" ); + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerComment( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev ) +{ + PMComment* o = ( PMComment* ) object; + + dev->writeComment( o->text( ) ); +} + +void PMPov31SerCompositeObject( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev ) +{ + PMCompositeObject* o = ( PMCompositeObject* ) object; + + PMObject* tmp; + + for( tmp = o->firstChild( ); tmp; tmp = tmp->nextSibling( ) ) + if( tmp->exportPovray( ) ) + dev->serialize( tmp ); +} + +void PMPov31SerCone( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMCone* o = ( PMCone* ) object; + + dev->objectBegin( "cone" ); + + dev->writeName( object->name( ) ); + QString str1; + str1.setNum( o->radius1( ) ); + dev->writeLine( o->end1( ).serialize( ) + ", " + str1 + "," ); + str1.setNum( o->radius2( ) ); + dev->writeLine( o->end2( ).serialize( ) + ", " + str1 ); + if( o->open( ) ) + dev->writeLine( QString( "open" ) ); + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerCSG( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMCSG* o = ( PMCSG* ) object; + + switch( o->csgType( ) ) + { + case PMCSG::CSGUnion: + dev->objectBegin( "union" ); + break; + case PMCSG::CSGIntersection: + dev->objectBegin( "intersection" ); + break; + case PMCSG::CSGDifference: + dev->objectBegin( "difference" ); + break; + case PMCSG::CSGMerge: + dev->objectBegin( "merge" ); + break; + } + + dev->writeName( object->name( ) ); + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerCylinder( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMCylinder* o = ( PMCylinder* ) object; + + dev->objectBegin( "cylinder" ); + + dev->writeName( object->name( ) ); + QString str1; + str1.setNum( o->radius( ) ); + dev->writeLine( o->end1( ).serialize( ) + ", " + o->end2( ).serialize( ) + + ", " + str1 ); + if( o->open( ) ) + dev->writeLine( QString( "open" ) ); + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerDeclare( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMDeclare* o = ( PMDeclare* ) object; + + if( o->firstChild( ) ) + { + dev->declareBegin( o->id( ) ); + dev->callSerialization( object, metaObject->superClass( ) ); + } +} + +void PMPov31SerDensity( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + bool bObject = true; + if( object->parent( ) ) + if( object->parent( )->type( ) == "DensityMap" ) + bObject = false; + + if( bObject ) + dev->objectBegin( "density" ); + dev->callSerialization( object, metaObject->superClass( ) ); + if( bObject ) + dev->objectEnd( ); +} + +void PMPov31SerDisc( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMDisc* o = ( PMDisc* ) object; + + dev->objectBegin( "disc" ); + + dev->writeName( object->name( ) ); + QString str1, str2; + str1.setNum( o->radius( ) ); + if( o->radius( ) != 0.0 ) + { + str2.setNum( o->holeRadius( ) ); + dev->writeLine( o->center( ).serialize( ) + "," + o->normal( ).serialize( ) + ", " + str1 + "," + str2 ); + } + else + { + dev->writeLine( o->center( ).serialize( ) + "," + o->normal( ).serialize( ) + ", " + str1 ); + } + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerFinish( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMFinish* o = ( PMFinish* ) object; + + QString str1; + + dev->objectBegin( "finish" ); + + dev->callSerialization( object, metaObject->superClass( ) ); + + if( o->isAmbientEnabled( ) ) + dev->writeLine( "ambient " + o->ambientColor( ).serialize( ) ); + if( o->isDiffuseEnabled( ) ) + { + str1.setNum( o->diffuse( ) ); + dev->writeLine( "diffuse " + str1 ); + } + if( o->isBrillianceEnabled( ) ) + { + str1.setNum( o->brilliance( ) ); + dev->writeLine( "brilliance " + str1 ); + } + if( o->isPhongEnabled( ) ) + { + str1.setNum( o->phong( ) ); + dev->writeLine( "phong " + str1 ); + } + if( o->isPhongSizeEnabled( ) ) + { + str1.setNum( o->phongSize( ) ); + dev->writeLine( "phong_size " + str1 ); + } + if( o->isMetallicEnabled( ) ) + { + str1.setNum( o->metallic( ) ); + dev->writeLine( "metallic " + str1 ); + } + if( o->isSpecularEnabled( ) ) + { + str1.setNum( o->specular( ) ); + dev->writeLine( "specular " + str1 ); + } + if( o->isRoughnessEnabled( ) ) + { + str1.setNum( o->roughness( ) ); + dev->writeLine( "roughness " + str1 ); + } + if( o->isReflectionEnabled( ) ) + { + dev->writeLine( "reflection " + o->reflectionColor( ).serialize( ) ); + } + if( o->isExponentEnabled( ) ) + { + str1.setNum( o->reflectionExponent( ) ); + dev->writeLine( "reflection_exponent " + str1 ); + } + if( o->irid( ) ) + { + str1.setNum( o->iridAmount( ) ); + dev->writeLine( "irid { " + str1 ); + str1.setNum( o->iridThickness( ) ); + dev->writeLine( "thickness " + str1 ); + str1.setNum( o->iridTurbulence( ) ); + dev->writeLine( "turbulence " + str1 + " } " ); + } + if( o->isCrandEnabled( ) ) + { + str1.setNum( o->crand( ) ); + dev->writeLine( "crand " + str1 ); + } + dev->objectEnd( ); +} + +const int c_defaultFogOctaves = 6; +const double c_defaultFogLambda = 2.0; +const double c_defaultFogOmega = 0.5; +const double c_defaultFogTurbDepth = 0.5; + +void PMPov31SerFog( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev ) +{ + PMFog* o = ( PMFog* ) object; + + QString str; + + dev->objectBegin( "fog" ); + + // Serialize the name of this object + dev->writeName( object->name( ) ); + + // Serialize a possible link + if( o->linkedObject( ) ) + { + if( o->linkedObject( )->firstChild( ) ) + dev->writeLine( o->linkedObject( )->id( ) ); + else + { + QString text; + text = o->name( ); + if( text.isEmpty( ) ) + text = o->description( ); + + dev->writeComment( QString( "No prototype for %1" ).arg( text ) ); + } + } + + str.setNum( o->fogType( ) ); + dev->writeLine( "fog_type " + str ); + + str.setNum( o->distance( ) ); + dev->writeLine( "distance " + str ); + dev->writeLine( " " + o->color( ).serialize( ) + " " ); + if( o->isTurbulenceEnabled( ) ) + { + dev->writeLine( "turbulence " + o->valueVector( ).serialize( ) ); + if( o->octaves( ) != c_defaultFogOctaves ) + { + str.setNum(o->octaves( )); + dev->writeLine( "octaves " + str ); + } + if( o->omega( ) != c_defaultFogOmega ) + { + str.setNum(o->omega( )); + dev->writeLine( "omega " + str ); + } + if( o->lambda( ) != c_defaultFogLambda ) + { + str.setNum(o->lambda( )); + dev->writeLine( "lambda " + str ); + } + if( o->depth( ) != c_defaultFogTurbDepth ) + { + str.setNum(o->depth( )); + dev->writeLine( "turb_depth " + str ); + } + } + if( o->fogType( ) == 2 ) + { + // Serialize ground fog variables + str.setNum( o->fogOffset( ) ); + dev->writeLine( "fog_offset " + str ); + str.setNum( o->fogAlt( ) ); + dev->writeLine( "fog_alt " + str ); + dev->writeLine( "up " + o->up( ).serialize( ) ); + } + // Serialize the children of this object + dev->callSerialization( object, object->metaObject( )->superClass( )->superClass( ) ); + dev->objectEnd( ); +} + +const double c_defaultGlobalSettingsAdcBailout = 1.0 / 255.0; +const PMColor c_defaultGlobalSettingsAmbientLight = PMColor( 1.0, 1.0, 1.0, 0.0, 0.0 ); +const double c_defaultGlobalSettingsAssumedGamma = 0.0; +const bool c_defaultGlobalSettingsHfGray16 = false; +const PMColor c_defaultGlobalSettingsIridWaveLength = PMColor( 0.25, 0.18, 0.14, 0.0, 0.0 ); +const int c_defaultGlobalSettingsMaxIntersections = 0; // ??? +const int c_defaultGlobalSettingsMaxTraceLevel = 0; // ??? +const int c_defaultGlobalSettingsNumberWaves = 10; +const bool c_defaultGlobalSettingsRadiosity = false; +const double c_defaultGlobalSettingsBrightness = 1.0; +const int c_defaultGlobalSettingsCount = 35; +const double c_defaultGlobalSettingsDistanceMaximum = 0; // ??? +const double c_defaultGlobalSettingsErrorBound = 1.8; +const double c_defaultGlobalSettingsGrayThreshold = 0.0; +const double c_defaultGlobalSettingsLowErrorFactor = 0.5; +const double c_defaultGlobalSettingsMinimumReuse = 0.015; +const int c_defaultGlobalSettingsNearestCount = 5; +const int c_defaultGlobalSettingsRecursionLimit = 2; + +void PMPov31SerGlobalSettings( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev ) +{ + PMGlobalSettings* o = ( PMGlobalSettings* ) object; + + QString str1; + + dev->objectBegin( "global_settings" ); + + if( o->adcBailout( ) != c_defaultGlobalSettingsAdcBailout ) + { + str1.setNum( o->adcBailout( ) ); + dev->writeLine( "adc_bailout " + str1 ); + } + if( o->ambientLight( ) != c_defaultGlobalSettingsAmbientLight ) + dev->writeLine( "ambient_light " + o->ambientLight( ).serialize( ) ); + if( o->assumedGamma( ) != c_defaultGlobalSettingsAssumedGamma ) + { + str1.setNum( o->assumedGamma( ) ); + dev->writeLine( "assumed_gamma " + str1 ); + } + if( o->hfGray16( ) != c_defaultGlobalSettingsHfGray16 ) + { + if( o->hfGray16( ) ) + dev->writeLine( "hf_gray_16 on" ); + else + dev->writeLine( "hf_gray_16 off" ); + } + if( o->iridWaveLength( ) != c_defaultGlobalSettingsIridWaveLength ) + dev->writeLine( "irid_wavelength " + o->iridWaveLength( ).serialize( ) ); + if( o->maxTraceLevel( ) != c_defaultGlobalSettingsMaxTraceLevel ) + { + str1.setNum( o->maxTraceLevel( ) ); + dev->writeLine( "max_trace_level " + str1 ); + } + if( o->maxIntersections( ) != c_defaultGlobalSettingsMaxIntersections ) + { + str1.setNum( o->maxIntersections( ) ); + dev->writeLine( "max_intersections " + str1 ); + } + if( o->numberWaves( ) != c_defaultGlobalSettingsNumberWaves ) + { + str1.setNum( o->numberWaves( ) ); + dev->writeLine( "number_of_waves " + str1 ); + } + if( o->isRadiosityEnabled( ) ) + { + dev->objectBegin( "radiosity" ); + if( o->brightness( ) != c_defaultGlobalSettingsBrightness ) + { + str1.setNum( o->brightness( ) ); + dev->writeLine( "brightness " + str1 ); + } + if( o->count( ) != c_defaultGlobalSettingsCount ) + { + str1.setNum( o->count( ) ); + dev->writeLine( "count " + str1 ); + } + if( o->distanceMaximum( ) != c_defaultGlobalSettingsDistanceMaximum ) + { + str1.setNum( o->distanceMaximum( ) ); + dev->writeLine( "distance_maximum " + str1 ); + } + if( o->errorBound( ) != c_defaultGlobalSettingsErrorBound ) + { + str1.setNum( o->errorBound( ) ); + dev->writeLine( "error_bound " + str1 ); + } + if( o->grayThreshold( ) != c_defaultGlobalSettingsGrayThreshold ) + { + str1.setNum( o->grayThreshold( ) ); + dev->writeLine( "gray_threshold " + str1 ); + } + if( o->lowErrorFactor( ) != c_defaultGlobalSettingsLowErrorFactor ) + { + str1.setNum( o->lowErrorFactor( ) ); + dev->writeLine( "low_error_factor " + str1 ); + } + if( o->minimumReuse( ) != c_defaultGlobalSettingsMinimumReuse ) + { + str1.setNum( o->minimumReuse( ) ); + dev->writeLine( "minimuo->reuse( ) " + str1 ); + } + if( o->nearestCount( ) != c_defaultGlobalSettingsNearestCount ) + { + str1.setNum( o->nearestCount( ) ); + dev->writeLine( "nearest_count " + str1 ); + } + if( o->recursionLimit( ) != c_defaultGlobalSettingsRecursionLimit ) + { + str1.setNum( o->recursionLimit( ) ); + dev->writeLine( "recursion_limit " + str1 ); + } + dev->objectEnd( ); + } + dev->objectEnd( ); +} + +void PMPov31SerGraphicalObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMGraphicalObject* o = ( PMGraphicalObject* ) object; + + dev->callSerialization( object, metaObject->superClass( ) ); + if( o->noShadow( ) ) + dev->writeLine( "no_shadow" ); +} + +void PMPov31SerHeightField( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMHeightField* o = ( PMHeightField* ) object; + + dev->objectBegin( "height_field" ); + + dev->writeName( object->name( ) ); + + dev->writeLine( o->typeToString( o->heightFieldType( ) ) + " \"" + o->fileName( ) + "\"" ); + if( o->waterLevel( ) > 0.0 ) + dev->writeLine( QString( "water_level %1" ).arg( o->waterLevel( ) ) ); + if( !o->hierarchy( ) ) + dev->writeLine( "hierarchy off" ); + if( o->smooth( ) ) + dev->writeLine( "smooth" ); + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerImageMap( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev ) +{ + PMImageMap* o = ( PMImageMap* ) object; + + typedef QValueList PMPaletteValueList; + PMPaletteValueList values; + PMPaletteValueList::ConstIterator tmpPalette; + QString str1, str2; + + dev->objectBegin( "image_map" ); + + switch( o->bitmapType( ) ) + { + case PMImageMap::BitmapGif: + dev->writeLine( "gif" ); + break; + case PMImageMap::BitmapTga: + dev->writeLine( "tga" ); + break; + case PMImageMap::BitmapIff: + dev->writeLine( "iff" ); + break; + case PMImageMap::BitmapPpm: + dev->writeLine( "ppm" ); + break; + case PMImageMap::BitmapPgm: + dev->writeLine( "pgm" ); + break; + case PMImageMap::BitmapPng: + dev->writeLine( "png" ); + break; + case PMImageMap::BitmapJpeg: + dev->writeLine( "jpeg" ); + break; + case PMImageMap::BitmapTiff: + dev->writeLine( "tiff" ); + break; + case PMImageMap::BitmapSys: + dev->writeLine( "sys" ); + break; + } + + dev->writeLine( "\"" + o->bitmapFile( ) + "\"" ); + + values = o->filters( ); + for( tmpPalette = values.begin( ); tmpPalette != values.end( ); ++tmpPalette ) + { + str1.setNum( ( *tmpPalette ).index( ) ); + str2.setNum( ( *tmpPalette ).value( ) ); + dev->writeLine( "filter " + str1 + ", " + str2 ); + } + + values = o->transmits( ); + for( tmpPalette = values.begin( ); tmpPalette != values.end( ); ++tmpPalette ) + { + str1.setNum( ( *tmpPalette ).index( ) ); + str2.setNum( ( *tmpPalette ).value( ) ); + dev->writeLine( "transmit " + str1 + ", " + str2 ); + } + + if( o->isFilterAllEnabled( ) ) + { + str1.setNum( o->filterAll( ) ); + dev->writeLine( "filter all " + str1 ); + } + + if( o->isTransmitAllEnabled( ) ) + { + str1.setNum( o->transmitAll( ) ); + dev->writeLine( "transmit all " + str1 ); + } + + if( o->isOnceEnabled( ) ) + dev->writeLine( "once" ); + + switch( o->mapType( ) ) + { + case PMImageMap::MapPlanar: + dev->writeLine( "map_type 0" ); + break; + case PMImageMap::MapSpherical: + dev->writeLine( "map_type 1" ); + break; + case PMImageMap::MapCylindrical: + dev->writeLine( "map_type 2" ); + break; + case PMImageMap::MapToroidal: + dev->writeLine( "map_type 5" ); + break; + } + switch( o->interpolateType( ) ) + { + case PMImageMap::InterpolateBilinear: + dev->writeLine( "interpolate 2" ); + break; + case PMImageMap::InterpolateNormalized: + dev->writeLine( "interpolate 4" ); + break; + default: + break; + } + + dev->objectEnd( ); +} + +void PMPov31SerInterior( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMInterior* o = ( PMInterior* ) object; + + QString str1; + + dev->objectBegin( "interior" ); + dev->callSerialization( object, metaObject->superClass( ) ); + + if( o->isIorEnabled( ) ) + { + str1.setNum( o->ior( ) ); + dev->writeLine( "ior " + str1 ); + } + if( o->isCausticsEnabled( ) ) + { + str1.setNum( o->caustics( ) ); + dev->writeLine( "caustics " + str1 ); + } + if( o->isFadeDistanceEnabled( ) ) + { + str1.setNum( o->fadeDistance( ) ); + dev->writeLine( "fade_distance " + str1 ); + } + if( o->isFadeDistanceEnabled( ) ) + { + str1.setNum( o->fadeDistance( ) ); + dev->writeLine( "fade_distance " + str1 ); + } + dev->objectEnd( ); +} + +void PMPov31SerJuliaFractal( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMJuliaFractal* o = ( PMJuliaFractal* ) object; + + dev->objectBegin( "julia_fractal" ); + + dev->writeName( object->name( ) ); + dev->writeLine( o->juliaParameter( ).serialize( ) ); + dev->writeLine( o->algebraTypeToString( o->algebraType( ) ) ); + + if( o->functionType( ) == PMJuliaFractal::FTpwr ) + dev->writeLine( QString( "pwr(%1, %2)" ).arg( o->exponent( )[0] ). + arg( o->exponent( )[1] ) ); + else + dev->writeLine( o->functionTypeToString( o->functionType( ) ) ); + + dev->writeLine( QString( "max_iteration %1" ).arg( o->maximumIterations( ) ) ); + dev->writeLine( QString( "precision %1" ).arg( o->precision( ) ) ); + dev->writeLine( QString( "slice %1, %2" ).arg( o->sliceNormal( ).serialize( ) ) + .arg( o->sliceDistance( ) ) ); + + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerLathe( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMLathe* o = ( PMLathe* ) object; + + dev->objectBegin( "lathe" ); + + dev->writeName( object->name( ) ); + + switch( o->splineType( ) ) + { + case PMLathe::LinearSpline: + dev->writeLine( "linear_spline" ); + break; + case PMLathe::QuadraticSpline: + dev->writeLine( "quadratic_spline" ); + break; + case PMLathe::CubicSpline: + dev->writeLine( "cubic_spline" ); + break; + case PMLathe::BezierSpline: + dev->writeLine( "bezier_spline" ); + break; + } + + int num = o->points( ).count( ); + dev->writeLine( QString( "%1," ).arg( num ) ); + + bool first = true; + QValueList points = o->points( ); + QValueList::ConstIterator it = points.begin( ); + for( ; it != points.end( ); ++it ) + { + if( !first ) + dev->write( ", " ); + dev->write( ( *it ).serialize( ) ); + first = false; + } + dev->writeLine( "" ); + + if( o->sturm( ) ) + dev->writeLine( "sturm" ); + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +const double c_defaultLightTightness = 10; +const int c_defaultLightAdaptive = 0; + +void PMPov31SerLight( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMLight* o = ( PMLight* ) object; + + dev->objectBegin( QString( "light_source" ) ); + + dev->writeName( object->name( ) ); + dev->writeLine( o->location( ).serialize( ) + ", " + o->color( ).serialize( ) ); + + if( o->lightType( ) == PMLight::SpotLight ) + dev->writeLine( QString( "spotlight" ) ); + else if( o->lightType( ) == PMLight::CylinderLight ) + dev->writeLine( QString( "cylinder" ) ); + else if( o->lightType( ) == PMLight::ShadowlessLight ) + dev->writeLine( QString( "shadowless" ) ); + + if( ( o->lightType( ) == PMLight::SpotLight ) || + ( o->lightType( ) == PMLight::CylinderLight ) ) + { + dev->writeLine( QString( "radius %1" ).arg( o->radius( ) ) ); + dev->writeLine( QString( "falloff %1" ).arg( o->falloff( ) ) ); + if( o->tightness( ) != c_defaultLightTightness ) + dev->writeLine( QString( "tightness %1" ).arg( o->tightness( ) ) ); + dev->writeLine( QString( "point_at " ) + o->pointAt( ).serialize( ) ); + } + + if( o->isAreaLight( ) ) + { + dev->writeLine( QString( "area_light " ) + o->axis1( ).serialize( ) + + QString( ", " ) + o->axis2( ).serialize( ) + + QString( ", %1, %2" ).arg( o->size1( ) ).arg( o->size2( ) ) ); + if( o->adaptive( ) != c_defaultLightAdaptive ) + dev->writeLine( QString( "adaptive %1" ).arg( o->adaptive( ) ) ); + if( o->jitter( ) ) + dev->writeLine( QString( "jitter" ) ); + } + + if( o->fading( ) ) + { + dev->writeLine( QString( "fade_distance %1" ).arg( o->fadeDistance( ) ) ); + dev->writeLine( QString( "fade_power %1" ).arg( o->fadePower( ) ) ); + } + + if( !o->mediaInteraction( ) ) + dev->writeLine( QString( "media_interaction off" ) ); + if( !o->mediaAttenuation( ) ) + dev->writeLine( QString( "media_attenuation off" ) ); + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerListPattern( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMListPattern* o = ( PMListPattern* ) object; + + QString str1; + + switch( o->listType( ) ) + { + case PMListPattern::ListPatternBrick: + dev->writeLine( "brick" ); + break; + case PMListPattern::ListPatternChecker: + dev->writeLine( "checker " ); + break; + case PMListPattern::ListPatternHexagon: + dev->writeLine( "hexagon " ); + break; + } + + dev->callSerialization( object, metaObject->superClass( ) ); + + if( o->listType( ) == PMListPattern::ListPatternBrick ) + { + dev->writeLine( "brick_size " + + o->brickSize( ).serialize( ) ); + str1.setNum( o->mortar( ) ); + dev->writeLine( "mortar " + str1 ); + } +} + +void PMPov31SerTextureList( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + dev->callSerialization( object, metaObject->superClass( ) ); +} + +void PMPov31SerPigmentList( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + dev->callSerialization( object, metaObject->superClass( ) ); +} + +void PMPov31SerColorList( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + dev->callSerialization( object, metaObject->superClass( ) ); +} + +void PMPov31SerDensityList( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + dev->callSerialization( object, metaObject->superClass( ) ); +} + +void PMPov31SerNormalList( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev ) +{ + PMNormalList* o = ( PMNormalList* ) object; + + QString str1; + + switch( o->listType( ) ) + { + case PMNormalList::ListPatternBrick: + dev->writeLine( "brick " ); + break; + case PMNormalList::ListPatternChecker: + dev->writeLine( "checker " ); + break; + case PMNormalList::ListPatternHexagon: + dev->writeLine( "hexagon " ); + break; + } + if( o->depth( ) ) + { + str1.setNum( o->depth( ) ); + dev->writeLine( str1 ); + } + if( o->listType( ) == PMNormalList::ListPatternBrick ) + { + dev->writeLine( "brick_size " + + o->brickSize( ).serialize( ) ); + str1.setNum( o->mortar( ) ); + dev->writeLine( "mortar " + str1 ); + } +} + +void PMPov31SerLooksLike( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + dev->objectBegin( "looks_like" ); + dev->writeName( object->name( ) ); + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerMaterial( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + dev->objectBegin( "material" ); + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerMaterialMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMMaterialMap* o = ( PMMaterialMap* ) object; + + QString str1; + + dev->objectBegin( "material_map" ); + + switch( o->bitmapType( ) ) + { + case PMMaterialMap::BitmapGif: + dev->writeLine( "gif" ); + break; + case PMMaterialMap::BitmapTga: + dev->writeLine( "tga" ); + break; + case PMMaterialMap::BitmapIff: + dev->writeLine( "iff" ); + break; + case PMMaterialMap::BitmapPpm: + dev->writeLine( "ppm" ); + break; + case PMMaterialMap::BitmapPgm: + dev->writeLine( "pgm" ); + break; + case PMMaterialMap::BitmapPng: + dev->writeLine( "png" ); + break; + case PMMaterialMap::BitmapJpeg: + dev->writeLine( "jpeg" ); + break; + case PMMaterialMap::BitmapTiff: + dev->writeLine( "tiff" ); + break; + case PMMaterialMap::BitmapSys: + dev->writeLine( "sys" ); + break; + } + + dev->writeLine( "\"" + o->bitmapFile( ) + "\"" ); + + if( o->isOnceEnabled( ) ) + dev->writeLine( "once" ); + + switch( o->mapType( ) ) + { + case PMMaterialMap::MapPlanar: + dev->writeLine( "map_type 0" ); + break; + case PMMaterialMap::MapSpherical: + dev->writeLine( "map_type 1" ); + break; + case PMMaterialMap::MapCylindrical: + dev->writeLine( "map_type 2" ); + break; + case PMMaterialMap::MapToroidal: + dev->writeLine( "map_type 5" ); + break; + } + switch( o->interpolateType( ) ) + { + case PMMaterialMap::InterpolateBilinear: + dev->writeLine( "interpolate 2" ); + break; + case PMMaterialMap::InterpolateNormalized: + dev->writeLine( "interpolate 4" ); + break; + default: + break; + } + + dev->callSerialization( object, metaObject->superClass( ) ); + + dev->objectEnd( ); +} + +const int c_defaultMediaIntervals = 10; +const int c_defaultMediaSamplesMin = 1; +const int c_defaultMediaSamplesMax = 1; +const double c_defaultMediaConfidence = 0.9; +const double c_defaultMediaVariance = 0.0078125; +const double c_defaultMediaRatio = 0.9; +const double c_defaultMediaScatteringEccentricity = 0; +const double c_defaultMediaScatteringExtinction = 1.0; + +void PMPov31SerMedia( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMMedia* o = ( PMMedia* ) object; + + QString str1; + QString str2; + + dev->objectBegin( "media" ); + dev->callSerialization( object, metaObject->superClass( ) ); + if( o->intervals( ) != c_defaultMediaIntervals ) + { + str1.setNum( o->intervals( ) ); + dev->writeLine( "intervals " + str1 ); + } + if( o->samplesMin( ) != c_defaultMediaSamplesMin || + o->samplesMax( ) != c_defaultMediaSamplesMax ) + { + str1.setNum( o->samplesMin( ) ); + str2.setNum( o->samplesMax( ) ); + dev->writeLine( "samples " + str1 + "," + str2 ); + } + if( o->confidence( ) != c_defaultMediaConfidence ) + { + str1.setNum( o->confidence( ) ); + dev->writeLine( "confidence " + str1 ); + } + if( o->variance( ) != c_defaultMediaVariance ) + { + str1.setNum( o->variance( ) ); + dev->writeLine( "variance " + str1 ); + } + if( o->ratio( ) != c_defaultMediaRatio ) + { + str1.setNum( o->ratio( ) ); + dev->writeLine( "ratio " + str1 ); + } + if( o->isAbsorptionEnabled( ) ) + { + dev->writeLine( "absorption " + o->absorption( ).serialize( ) ); + } + if( o->isEmissionEnabled( ) ) + { + dev->writeLine( "emission " + o->emission( ).serialize( ) ); + } + if( o->isScatteringEnabled( ) ) + { + dev->objectBegin( "scattering" ); + str1.setNum( o->scatteringType( ) ); + dev->writeLine( str1 + ", " + o->scatteringColor( ).serialize( ) ); + if( o->scatteringType( ) == 5 && o->scatteringEccentricity( ) + != c_defaultMediaScatteringEccentricity ) + { + str1.setNum( o->scatteringEccentricity( ) ); + dev->writeLine( "eccentricity " + str1 ); + } + if( o->scatteringExtinction( ) != c_defaultMediaScatteringExtinction ) + { + str1.setNum( o->scatteringExtinction( ) ); + dev->writeLine( "extinction " + str1 ); + } + dev->objectEnd( ); + } + dev->objectEnd( ); +} + +void PMPov31SerNamedObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + dev->callSerialization( object, metaObject->superClass( ) ); +} + +void PMPov31SerNormal( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMNormal* o = ( PMNormal* ) object; + + QString str1; + bool bObject = true; + + if( o->parent( ) ) + if( o->parent( )->type( ) == "NormalMap" ) + bObject = false; + + if( bObject ) + dev->objectBegin( "normal" ); + dev->callSerialization( object, metaObject->superClass( ) ); + if( o->isBumpSizeEnabled( ) ) + { + str1.setNum( o->bumpSize( ) ); + dev->writeLine( "bump_size " + str1 ); + } + if( bObject ) + dev->objectEnd( ); +} + +void PMPov31SerObjectLink( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMObjectLink* o = ( PMObjectLink* ) object; + + bool writeComment = true; + if( o->linkedObject( ) ) + { + if( o->linkedObject( )->firstChild( ) ) + { + dev->objectBegin( "object" ); + + dev->writeName( object->name( ) ); + dev->writeLine( o->linkedObject( )->id( ) ); + dev->callSerialization( object, metaObject->superClass( ) ); + writeComment = false; + + dev->objectEnd( ); + } + } + if( writeComment ) + { + QString text; + text = o->name( ); + if( text.isEmpty( ) ) + text = o->description( ); + + dev->writeComment( QString( "No prototype for %1" ).arg( text ) ); + } +} + +const int c_defaultPatternOctaves = 6; +const double c_defaultPatternOmega = 0.5; +const double c_defaultPatternLambda = 2.0; + +void PMPov31SerPattern( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev ) +{ + PMPattern* o = ( PMPattern* ) object; + + QString str; + + // pattern type + switch( o->patternType( ) ) + { + case PMPattern::PatternAgate: + dev->writeLine( "agate" ); + break; + case PMPattern::PatternAverage: + dev->writeLine( "average" ); + break; + case PMPattern::PatternBoxed: + dev->writeLine( "boxed" ); + break; + case PMPattern::PatternBozo: + dev->writeLine( "bozo" ); + break; + case PMPattern::PatternBumps: + dev->writeLine( "bumps" ); + break; + case PMPattern::PatternCrackle: + dev->writeLine( "crackle" ); + break; + case PMPattern::PatternCylindrical: + dev->writeLine( "cylindrical" ); + break; + case PMPattern::PatternDensity: + dev->writeLine( "density_file df3 \"" + o->densityFile( ) + "\""); + break; + case PMPattern::PatternDents: + dev->writeLine( "dents" ); + break; + case PMPattern::PatternGradient: + dev->writeLine( "gradient " + o->gradient( ).serialize( ) ); + break; + case PMPattern::PatternGranite: + dev->writeLine( "granite" ); + break; + case PMPattern::PatternLeopard: + dev->writeLine( "leopard" ); + break; + case PMPattern::PatternMandel: + str.setNum( o->maxIterations( ) ); + dev->writeLine( "mandel " + str ); + break; + case PMPattern::PatternMarble: + dev->writeLine( "marble" ); + break; + case PMPattern::PatternOnion: + dev->writeLine( "onion" ); + break; + case PMPattern::PatternPlanar: + dev->writeLine( "planar" ); + break; + case PMPattern::PatternQuilted: + dev->writeLine( "quilted" ); + break; + case PMPattern::PatternRadial: + dev->writeLine( "radial" ); + break; + case PMPattern::PatternRipples: + dev->writeLine( "ripples" ); + break; + case PMPattern::PatternSpherical: + dev->writeLine( "spherical" ); + break; + case PMPattern::PatternSpiral1: + str.setNum( o->spiralNumberArms( ) ); + dev->writeLine( "spiral1 " + str ); + break; + case PMPattern::PatternSpiral2: + str.setNum( o->spiralNumberArms( ) ); + dev->writeLine( "spiral2 " + str ); + break; + case PMPattern::PatternSpotted: + dev->writeLine( "spotted" ); + break; + case PMPattern::PatternWaves: + dev->writeLine( "waves" ); + break; + case PMPattern::PatternWood: + dev->writeLine( "wood" ); + break; + case PMPattern::PatternWrinkles: + dev->writeLine( "wrinkles" ); + break; + default: + break; + } + // depth + if( o->parent( ) ) + { + if( o->depth( ) && o->parent( )->type( ) == "Normal" ) + { + str.setNum( o->depth( ) ); + dev->writeLine( str ); + } + } + // modifiers + switch( o->patternType( ) ) + { + case PMPattern::PatternAgate: + str.setNum( o->agateTurbulence( ) ); + dev->writeLine( "agate_turb " + str ); + break; + case PMPattern::PatternDensity: + str.setNum( o->densityInterpolate( ) ); + dev->writeLine( "interpolate " + str ); + break; + case PMPattern::PatternQuilted: + str.setNum( o->quiltControl0( ) ); + dev->writeLine( "control0 " + str ); + str.setNum( o->quiltControl1( ) ); + dev->writeLine( "control1 " + str ); + break; + default: + break; + } + if( o->isTurbulenceEnabled( ) ) + { + dev->writeLine( "turbulence " + o->valueVector( ).serialize( ) ); + if( o->octaves( ) != c_defaultPatternOctaves ) + { + str.setNum( o->octaves( ) ); + dev->writeLine( "octaves " + str ); + } + if( o->omega( ) != c_defaultPatternOmega ) + { + str.setNum( o->omega( ) ); + dev->writeLine( "omega " + str ); + } + if( o->lambda( ) != c_defaultPatternLambda ) + { + str.setNum( o->lambda( ) ); + dev->writeLine( "lambda " + str ); + } + } +} + +void PMPov31SerPigment( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMPigment* o = ( PMPigment* ) object; + + bool bObject = true; + if( o->parent( ) ) + if( o->parent( )->type( ) == "PigmentMap" ) + bObject = false; + + if( bObject ) + dev->objectBegin( "pigment" ); + dev->callSerialization( object, metaObject->superClass( ) ); + if( bObject ) + dev->objectEnd( ); +} + +void PMPov31SerPlane( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMPlane* o = ( PMPlane* ) object; + + dev->objectBegin( "plane" ); + + dev->writeName( object->name( ) ); + QString str1; + str1.setNum( o->distance( ) ); + dev->writeLine( o->normal( ).serialize( ) + ", " + str1 ); + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerPolynom( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMPolynom* o = ( PMPolynom* ) object; + PMVector coefficients = o->coefficients( ); + + if( o->polynomOrder( ) == 2 ) + dev->objectBegin( "quadric" ); + else if( o->polynomOrder( ) == 3 ) + dev->objectBegin( "cubic" ); + else if( o->polynomOrder( ) == 4 ) + dev->objectBegin( "quartic" ); + else + dev->objectBegin( "poly" ); + + dev->writeName( object->name( ) ); + + if( o->polynomOrder( ) == 2 ) + { + dev->writeLine( QString( "<%1, %2, %3>," ).arg( coefficients[0] ) + .arg( coefficients[4] ).arg( coefficients[7] ) ); + dev->writeLine( QString( "<%1, %2, %3>," ).arg( coefficients[1] ) + .arg( coefficients[2] ).arg( coefficients[5] ) ); + dev->writeLine( QString( "<%1, %2, %3>, %4" ).arg( coefficients[3] ) + .arg( coefficients[6] ).arg( coefficients[8] ) + .arg( coefficients[9] ) ); + } + else + { + if( o->polynomOrder( ) > 4 ) + dev->writeLine( QString( "%1," ).arg( o->polynomOrder( ) ) ); + + int size = coefficients.size( ); + + int i; + QString hlp; + + dev->write( "<" ); + for( i = 0; i < size; i++ ) + { + hlp.setNum( coefficients[i] ); + dev->write( hlp ); + + if( i != ( size - 1 ) ) + { + dev->write( ", " ); + if( ( ( i + 1 ) % 5 ) == 0 ) + dev->writeLine( "" ); + } + } + dev->writeLine( ">" ); + if( o->sturm( ) ) + dev->writeLine( "sturm" ); + } + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerPovrayMatrix( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev ) +{ + PMPovrayMatrix* o = ( PMPovrayMatrix* ) object; + + dev->writeLine( QString( "matrix < %1, %2, %3," ).arg( o->values( )[0] ) + .arg( o->values( )[1] ).arg( o->values( )[2] ) ); + dev->writeLine( QString( " %1, %2, %3," ).arg( o->values( )[3] ) + .arg( o->values( )[4] ).arg( o->values( )[5] ) ); + dev->writeLine( QString( " %1, %2, %3," ).arg( o->values( )[6] ) + .arg( o->values( )[7] ).arg( o->values( )[8] ) ); + dev->writeLine( QString( " %1, %2, %3 >" ).arg( o->values( )[9] ) + .arg( o->values( )[10] ).arg( o->values( )[11] ) ); +} + +void PMPov31SerPrism( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMPrism* o = ( PMPrism* ) object; + + dev->objectBegin( "prism" ); + + dev->writeName( object->name( ) ); + + switch( o->splineType( ) ) + { + case PMPrism::LinearSpline: + dev->writeLine( "linear_spline" ); + break; + case PMPrism::QuadraticSpline: + dev->writeLine( "quadratic_spline" ); + break; + case PMPrism::CubicSpline: + dev->writeLine( "cubic_spline" ); + break; + case PMPrism::BezierSpline: + dev->writeLine( "bezier_spline" ); + break; + } + switch( o->sweepType( ) ) + { + case PMPrism::LinearSweep: + dev->writeLine( "linear_sweep" ); + break; + case PMPrism::ConicSweep: + dev->writeLine( "conic_sweep" ); + break; + } + dev->writeLine( QString( "%1, %2," ).arg( o->height1( ) ).arg( o->height2( ) ) ); + + // count number of points + QValueList< QValueList > points = o->points( ); + QValueList< QValueList >::ConstIterator spit = points.begin( ); + int lines = 0; + for( ; spit != points.end( ); ++spit ) + { + if( o->splineType( ) != PMPrism::BezierSpline ) + lines += ( *spit ).count( ) + 1; + else + lines += ( *spit ).count( ) / 3 * 4; + } + dev->writeLine( QString( "%1," ).arg( lines ) ); + + for( spit = points.begin( ); spit != points.end( ); ++spit ) + { + bool first = true; + + QValueList fullPoints = o->expandedPoints( *spit ); + QValueList::ConstIterator it = fullPoints.begin( ); + + for( ; it != fullPoints.end( ); ++it ) + { + if( !first ) + dev->write( ", " ); + dev->write( ( *it ).serialize( ) ); + first = false; + } + QValueList< QValueList >::ConstIterator spit2 = spit; + spit2++; + if( spit2 != points.end( ) ) + dev->write( "," ); + dev->writeLine( "" ); + } + + if( o->open( ) ) + dev->writeLine( "open" ); + if( o->sturm( ) ) + dev->writeLine( "sturm" ); + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerQuickColor( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev ) +{ + PMQuickColor* o = ( PMQuickColor* ) object; + + dev->writeLine( "quick_color " + o->color( ).serialize( ) ); +} + +void PMPov31SerRainbow( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMRainbow* o = ( PMRainbow* ) object; + + QString str1; + + dev->objectBegin( "rainbow" ); + dev->callSerialization( object, metaObject->superClass( ) ); + + if( o->isDirectionEnabled( ) ) + dev->writeLine( "direction " + o->direction( ).serialize( ) ); + if( o->isAngleEnabled( ) ) + { + str1.setNum( o->angle( ) ); + dev->writeLine( "angle " + str1 ); + } + if( o->isWidthEnabled( ) ) + { + str1.setNum( o->width( ) ); + dev->writeLine( "width " + str1 ); + } + if( o->isDistanceEnabled( ) ) + { + str1.setNum( o->distance( ) ); + dev->writeLine( "distance " + str1 ); + } + if( o->isJitterEnabled( ) ) + { + str1.setNum( o->jitter( ) ); + dev->writeLine( "jitter " + str1 ); + } + if( o->isUpEnabled( ) ) + dev->writeLine( "up " + o->up( ).serialize( ) ); + if( o->isArcAngleEnabled( ) ) + { + str1.setNum( o->arcAngle( ) ); + dev->writeLine( "arc_angle " + str1 ); + } + if( o->isFalloffAngleEnabled( ) ) + { + str1.setNum( o->falloffAngle( ) ); + dev->writeLine( "falloff_angle " + str1 ); + } + dev->objectEnd( ); +} + +void PMPov31SerRaw( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev ) +{ + PMRaw* o = ( PMRaw* ) object; + + dev->writeLine( "//*PMRawBegin" ); + + QString tmp = o->code( ); + QTextStream str( &tmp, IO_ReadOnly ); + while( !str.atEnd( ) ) + dev->writeLine( str.readLine( ) ); + + dev->writeLine( "//*PMRawEnd" ); +} + +void PMPov31SerRotate( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev ) +{ + PMRotate* o = ( PMRotate* ) object; + PMVector rotate = o->rotation( ); + + QString vector; + QTextStream str( &vector, IO_WriteOnly ); + int i; + bool z[3]; + + for( i = 0; i < 3; i++ ) + z[i] = approxZero( rotate[i] ); + if( !z[0] && z[1] && z[2] ) + { + str << "x*"; + i = 0; + } + else if( z[0] && !z[1] && z[2] ) + { + str << "y*"; + i = 1; + } + else if( z[0] && z[1] && !z[2] ) + { + str << "z*"; + i = 2; + } + + if( i < 3 ) + { + if( rotate[i] > 0 ) + str << rotate[i]; + else + str << "(" << rotate[i] << ")"; + } + else + { + str << '<'; + for( i = 0; i < 3; i++ ) + { + if( i > 0 ) + str << ", "; + str << rotate[i]; + } + str << '>'; + } + + dev->writeLine( "rotate " + vector ); +} + +void PMPov31SerScale( const PMObject* object, const PMMetaObject* , PMOutputDevice* dev ) +{ + PMScale* o = ( PMScale* ) object; + PMVector scale = o->scale( ); + + if( approx( scale[0], scale[1] ) && + approx( scale[1], scale[2] ) ) + dev->writeLine( QString( "scale %1" ).arg( scale[0] ) ); + else + dev->writeLine( "scale " + scale.serialize( ) ); +} + +void PMPov31SerScene( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + dev->callSerialization( object, metaObject->superClass( ) ); +} + +void PMPov31SerSkySphere( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + dev->objectBegin( "sky_sphere" ); + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerSlope( const PMObject* object, const PMMetaObject* , PMOutputDevice* dev ) +{ + PMSlope* o = ( PMSlope* ) object; + + QString str1,str2; + + str1.setNum(o->height( )); + str2.setNum(o->slope( )); + + dev->writeLine( "<" + str1 + ", " + str2 + ">" ); +} + +void PMPov31SerSolidColor( const PMObject* object, const PMMetaObject* , PMOutputDevice* dev ) +{ + PMSolidColor* o = ( PMSolidColor* ) object; + + dev->writeLine( o->color( ).serialize( true ) ); +} + +void PMPov31SerSolidObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMSolidObject* o = ( PMSolidObject* ) object; + + dev->callSerialization( object, metaObject->superClass( ) ); + switch( o->hollow( ) ) + { + case PMTrue: + dev->writeLine( "hollow" ); + break; + case PMFalse: + dev->writeLine( "hollow false" ); + break; + case PMUnspecified: + break; + } + if( o->inverse( ) ) + dev->writeLine( "inverse" ); +} + +void PMPov31SerSurfaceOfRevolution( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMSurfaceOfRevolution* o = ( PMSurfaceOfRevolution* ) object; + + dev->objectBegin( "sor" ); + + dev->writeName( object->name( ) ); + + int num = o->points( ).count( ); + dev->writeLine( QString( "%1," ).arg( num ) ); + + bool first = true; + QValueList points = o->points( ); + QValueList::ConstIterator it = points.begin( ); + for( ; it != points.end( ); ++it ) + { + if( !first ) + dev->write( ", " ); + dev->write( ( *it ).serialize( ) ); + first = false; + } + dev->writeLine( "" ); + + if( o->open( ) ) + dev->writeLine( "open" ); + if( o->sturm( ) ) + dev->writeLine( "sturm" ); + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerSphere( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMSphere* o = ( PMSphere* ) object; + + dev->objectBegin( "sphere" ); + dev->writeName( object->name( ) ); + QString str; + str.setNum( o->radius( ) ); + dev->writeLine( o->centre( ).serialize( ) + ", " + str ); + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerSuperquadricEllipsoid( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMSuperquadricEllipsoid* o = ( PMSuperquadricEllipsoid* ) object; + + dev->objectBegin( "superellipsoid" ); + + dev->writeName( object->name( ) ); + dev->writeLine( QString( "<%1, %2>" ).arg( o->eastWestExponent( ) ) + .arg( o->northSouthExponent( ) ) ); + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerText( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMText* o = ( PMText* ) object; + + dev->objectBegin( "text" ); + + dev->writeName( object->name( ) ); + dev->writeLine( QString( "ttf \"" ) + o->font( ) + "\"" ); + dev->writeLine( PMOutputDevice::escapeAndQuoteString( o->text( ) ) ); + dev->writeLine( QString( "%1, " ).arg( o->thickness( ) ) + + o->offset( ).serialize( ) ); + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerTexture( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMTexture* o = ( PMTexture* ) object; + + bool bObject = true; + if( o->parent( ) ) + if( o->parent( )->type( ) == "TextureMap" ) + bObject = false; + + if( bObject ) + dev->objectBegin( "texture" ); + dev->callSerialization( object, metaObject->superClass( ) ); + if( bObject ) + dev->objectEnd( ); +} + +void PMPov31SerTextureBase( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMTextureBase* o = ( PMTextureBase* ) object; + + dev->writeName( object->name( ) ); + + PMDeclare* linkedObject = o->linkedObject( ); + + if( linkedObject) + { + if( linkedObject->firstChild( ) ) + dev->writeLine( linkedObject->id( ) ); + else + { + QString text; + text = o->name( ); + if( text.isEmpty( ) ) + text = o->description( ); + + dev->writeComment( QString( "No prototype for %1" ).arg( text ) ); + } + } + + dev->callSerialization( object, metaObject->superClass( ) ); +} + +void PMPov31SerTextureMapBase( const PMObject* object, const PMMetaObject* , PMOutputDevice* dev ) +{ + PMTextureMapBase* o = ( PMTextureMapBase* ) object; + + QValueList mapValues = o->mapValues( ); + QValueList::ConstIterator it = mapValues.begin( ); + PMObject* c = o->firstChild( ); + double value = 0.0; + + /* Take care of a possible link */ + if( o->linkedObject( ) ) + { + if( o->linkedObject( )->firstChild( ) ) + dev->writeLine( o->linkedObject( )->id( ) ); + else + { + QString text; + text = o->name( ); + if( text.isEmpty( ) ) + text = o->description( ); + + dev->writeComment( QString( "No prototype for %1" ).arg( text ) ); + } + } + + /* Serialize the map */ + for( ; c; c = c->nextSibling( ) ) + { + if( c->type( ) == o->mapType( ) ) + { + value = 1.0; + if( it != mapValues.end( ) ) + value = *it; + dev->write( QString( "[ %1 " ).arg( value ) ); + dev->serialize( c ); + dev->writeLine( "]" ); + ++it; + } + } +} + +void PMPov31SerTextureMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + dev->objectBegin( "texture_map" ); + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerPigmentMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + dev->objectBegin( "pigment_map" ); + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerColorMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + dev->objectBegin( "color_map" ); + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerNormalMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + dev->objectBegin( "normal_map" ); + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerSlopeMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + dev->objectBegin( "slope_map" ); + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerDensityMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + dev->objectBegin( "density_map" ); + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerTorus( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMTorus* o = ( PMTorus* ) object; + + dev->objectBegin( "torus" ); + dev->writeName( object->name( ) ); + QString strMinor; + QString strMajor; + strMinor.setNum( o->minorRadius( ) ); + strMajor.setNum( o->majorRadius( ) ); + + dev->writeLine(strMajor + ", " + strMinor); + if( o->sturm( ) ) + dev->writeLine( QString( "sturm" ) ); + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov31SerTranslate( const PMObject* object, const PMMetaObject* , PMOutputDevice* dev ) +{ + PMTranslate* o = ( PMTranslate* ) object; + + QString vector; + QTextStream str( &vector, IO_WriteOnly ); + int i; + bool z[3]; + PMVector move = o->translation( ); + + for( i = 0; i < 3; i++ ) + z[i] = approxZero( move[i] ); + if( !z[0] && z[1] && z[2] ) + { + str << "x*"; + i = 0; + } + else if( z[0] && !z[1] && z[2] ) + { + str << "y*"; + i = 1; + } + else if( z[0] && z[1] && !z[2] ) + { + str << "z*"; + i = 2; + } + + if( i < 3 ) + { + if( move[i] > 0 ) + str << move[i]; + else + str << "(" << move[i] << ")"; + } + else + { + str << '<'; + for( i = 0; i < 3; i++ ) + { + if( i > 0 ) + str << ", "; + str << move[i]; + } + str << '>'; + } + + dev->writeLine( "translate " + vector ); +} + +void PMPov31SerTriangle( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMTriangle* o = ( PMTriangle* ) object; + + if( o->isSmoothTriangle( ) ) + { + dev->objectBegin( "smooth_triangle" ); + + dev->writeName( object->name( ) ); + dev->writeLine( o->point( 0 ).serialize( ) + ", " + o->normal( 0 ).serialize( ) + "," ); + dev->writeLine( o->point( 1 ).serialize( ) + ", " + o->normal( 1 ).serialize( ) + "," ); + dev->writeLine( o->point( 2 ).serialize( ) + ", " + o->normal( 2 ).serialize( ) ); + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); + } + else + { + dev->objectBegin( "triangle" ); + + dev->writeName( object->name( ) ); + dev->writeLine( o->point( 0 ).serialize( ) + ", " + o->point( 1 ).serialize( ) + + ", " + o->point( 2 ).serialize( ) ); + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); + } +} + + +const PMVector c_warpDirectionDefault = PMVector( 1.0, 0.0, 0.0 ); +const PMVector c_warpOffsetDefault = PMVector( 0.0, 0.0, 0.0 ); +const PMVector c_warpFlipDefault = PMVector( 0.0, 0.0, 0.0 ); +const PMVector c_warpLocationDefault = PMVector( 0.0, 0.0, 0.0 ); +const double c_warpRadiusDefault = 0; +const double c_warpStrengthDefault = 0; +const double c_warpFalloffDefault = 0; +const bool c_warpInverseDefault = false; +const PMVector c_warpRepeatDefault = PMVector( 0.0, 0.0, 0.0 ); +const PMVector c_warpTurbulenceDefault = PMVector( 0.0, 0.0, 0.0 ); +const PMVector c_warpValueVectorDefault = PMVector( 0.0, 0.0, 0.0 ); +const int c_warpOctavesDefault = 6; +const double c_warpOmegaDefault = 0.5; +const double c_warpLambdaDefault = 2.0; + +void PMPov31SerWarp( const PMObject* object, const PMMetaObject* , PMOutputDevice* dev ) +{ + PMWarp* o = ( PMWarp* ) object; + + QString str1; + + dev->objectBegin( "warp" ); + switch( o->warpType( ) ) + { + case PMWarp::Repeat: + dev->writeLine( "repeat" ); + dev->writeLine( o->direction( ).serialize( ) ); + dev->writeLine( "offset " + o->offset( ).serialize( ) ); + dev->writeLine( "flip " + o->flip( ).serialize( ) ); + break; + case PMWarp::BlackHole: + dev->writeLine( "black_hole" ); + dev->writeLine( o->location( ).serialize( ) ); + str1.setNum(o->radius( )); + dev->writeLine( ", " + str1 ); + if( o->strength( ) != c_warpStrengthDefault ) + { + str1.setNum( o->strength( )); + dev->writeLine( "strength " + str1 ); + } + if( o->falloff( ) != c_warpFalloffDefault ) + { + str1.setNum( o->falloff( )); + dev->writeLine( "falloff " + str1 ); + } + if( o->inverse( ) != c_warpInverseDefault ) + { + if( o->inverse( ) ) dev->writeLine( "inverse" ); + } + if( o->repeat( ) != c_warpRepeatDefault ) + { + dev->writeLine( "repeat " + o->repeat( ).serialize( ) ); + } + if( o->turbulence( ) != c_warpTurbulenceDefault ) + { + dev->writeLine( "turbulence " + o->turbulence( ).serialize( ) ); + } + break; + case PMWarp::Turbulence: + dev->writeLine( "turbulence " + o->valueVector( ).serialize( ) ); + if( o->octaves( ) != c_warpOctavesDefault ) + { + str1.setNum(o->octaves( )); + dev->writeLine( "octaves " + str1 ); + } + if( o->omega( ) != c_warpOmegaDefault ) + { + str1.setNum( o->omega( ) ); + dev->writeLine( "omega " + str1 ); + } + if( o->lambda( ) != c_warpLambdaDefault ) + { + str1.setNum( o->lambda( ) ); + dev->writeLine( "lambda " + str1 ); + } + break; + default: + break; + } + dev->objectEnd( ); +} + +void PMPov31SerDetailObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + dev->callSerialization( object, metaObject->superClass( ) ); +} diff --git a/kpovmodeler/pmpovray31serialization.h b/kpovmodeler/pmpovray31serialization.h new file mode 100644 index 00000000..5c48c0cd --- /dev/null +++ b/kpovmodeler/pmpovray31serialization.h @@ -0,0 +1,103 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMPOVRAY31_SERIALIZATION_H +#define PMPOVRAY31_SERIALIZATION_H + +class PMObject; +class PMMetaObject; +class PMOutputDevice; + +// serialization methods for POV-Ray 3.1 + +void PMPov31SerBicubicPatch( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerBlendMapModifiers( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerBlob( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerBlobCylinder( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerBlobSphere( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerBoundedBy( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerBox( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerBumpMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerCamera( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerClippedBy( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerComment( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerCompositeObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerCone( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerCSG( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerCylinder( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerDeclare( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerDensity( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerDisc( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerFinish( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerFog( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerGlobalSettings( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerGraphicalObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerHeightField( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerImageMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerInterior( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerJuliaFractal( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerLathe( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerLight( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerListPattern( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerTextureList( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerPigmentList( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerColorList( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerDensityList( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerNormalList( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerLooksLike( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerMaterial( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerMaterialMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerMedia( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerNamedObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerNormal( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerObjectLink( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerPattern( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerPigment( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerPlane( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerPolynom( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerPovrayMatrix( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerPrism( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerQuickColor( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerRainbow( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerRaw( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerRotate( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerScale( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerScene( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerSkySphere( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerSlope( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerSolidColor( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerSolidObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerSurfaceOfRevolution( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerSphere( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerSuperquadricEllipsoid( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerText( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerTexture( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerTextureBase( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerTextureMapBase( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerTextureMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerPigmentMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerColorMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerNormalMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerSlopeMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerDensityMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerTorus( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerTranslate( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerTriangle( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerWarp( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov31SerDetailObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); + +#endif diff --git a/kpovmodeler/pmpovray35format.cpp b/kpovmodeler/pmpovray35format.cpp new file mode 100644 index 00000000..c00b1d65 --- /dev/null +++ b/kpovmodeler/pmpovray35format.cpp @@ -0,0 +1,100 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmpovray35format.h" +#include "pmpovray35serialization.h" + +#include "pmpovrayparser.h" +#include "pmoutputdevice.h" + +#include + +PMPovray35Format::PMPovray35Format( ) + : PMPovray31Format( ) +{ + registerMethod( "IsoSurface", PMPov35SerIsoSurface ); + registerMethod( "Light", PMPov35SerLight ); + registerMethod( "ProjectedThrough", PMPov35SerProjectedThrough ); + registerMethod( "GlobalSettings", PMPov35SerGlobalSettings ); + registerMethod( "Radiosity", PMPov35SerRadiosity ); + registerMethod( "GlobalPhotons", PMPov35SerGlobalPhotons ); + registerMethod( "Photons", PMPov35SerPhotons ); + registerMethod( "Interior", PMPov35SerInterior ); + registerMethod( "LightGroup", PMPov35SerLightGroup ); + registerMethod( "Pattern", PMPov35SerPattern ); + registerMethod( "Normal", PMPov35SerNormal ); + registerMethod( "InteriorTexture", PMPov35SerInteriorTexture ); + registerMethod( "Warp", PMPov35SerWarp ); + registerMethod( "SphereSweep", PMPov35SerSphereSweep ); + registerMethod( "Finish", PMPov35SerFinish ); + registerMethod( "Mesh", PMPov35SerMesh ); + registerMethod( "Media", PMPov35SerMedia ); + registerMethod( "GraphicalObject", PMPov35SerGraphicalObject ); + registerMethod( "Pigment", PMPov35SerPigment ); + registerMethod( "Texture", PMPov35SerTexture ); + registerMethod( "BicubicPatch", PMPov35SerBicubicPatch ); + registerMethod( "Triangle", PMPov35SerTriangle ); +} + + +PMPovray35Format::~PMPovray35Format( ) +{ + +} + +PMParser* PMPovray35Format::newParser( PMPart* part, QIODevice* dev ) const +{ + return new PMPovrayParser( part, dev ); +} + +PMParser* PMPovray35Format::newParser( PMPart* part, const QByteArray& data ) const +{ + return new PMPovrayParser( part, data ); +} + +PMSerializer* PMPovray35Format::newSerializer( QIODevice* dev ) +{ + return new PMOutputDevice( dev, this ); +} + +PMRenderer* PMPovray35Format::newRenderer( PMPart* ) const +{ + // TODO + return 0; +} + +QString PMPovray35Format::mimeType( ) const +{ + return QString( "text/plain" ); +} + +QStringList PMPovray35Format::importPatterns( ) const +{ + QStringList result; + result.push_back( QString( "*.pov *.inc|" ) + + i18n( "POV-Ray 3.5 Files (*.pov, *.inc)" ) ); + return result; +} + +QStringList PMPovray35Format::exportPatterns( ) const +{ + QStringList result; + result.push_back( QString( "*.pov|" ) + i18n( "POV-Ray 3.5 Files (*.pov)" ) ); + result.push_back( QString( "*.ini|" ) + i18n( "POV-Ray 3.5 Include Files (*.ini)" ) ); + return result; + +} diff --git a/kpovmodeler/pmpovray35format.h b/kpovmodeler/pmpovray35format.h new file mode 100644 index 00000000..117d0375 --- /dev/null +++ b/kpovmodeler/pmpovray35format.h @@ -0,0 +1,64 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMPOVRAY35_FORMAT_H +#define PMPOVRAY35_FORMAT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmpovray31format.h" + +/** + * Description class for POV-Ray 3.5 + */ +class PMPovray35Format : public PMPovray31Format +{ +public: + /** + * Default constructor + */ + PMPovray35Format( ); + /** + * Destructor + */ + virtual ~PMPovray35Format( ); + + /** */ + virtual QString name( ) const { return "povray35"; }; + /** */ + virtual QString description( ) const { return "POV-Ray 3.5"; } + /** */ + virtual int services( ) const { return AllServices; } + /** */ + virtual PMParser* newParser( PMPart*, QIODevice* ) const; + /** */ + virtual PMParser* newParser( PMPart*, const QByteArray& ) const; + /** */ + virtual PMSerializer* newSerializer( QIODevice* ); + /** */ + virtual PMRenderer* newRenderer( PMPart* ) const; + /** */ + virtual QString mimeType( ) const; + /** */ + virtual QStringList importPatterns( ) const; + /** */ + virtual QStringList exportPatterns( ) const; +}; + +#endif diff --git a/kpovmodeler/pmpovray35serialization.cpp b/kpovmodeler/pmpovray35serialization.cpp new file mode 100644 index 00000000..2c3a88e0 --- /dev/null +++ b/kpovmodeler/pmpovray35serialization.cpp @@ -0,0 +1,1471 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmpovray35serialization.h" +#include "pmoutputdevice.h" + +#include "pmisosurface.h" +#include "pmlight.h" +#include "pmprojectedthrough.h" +#include "pmglobalsettings.h" +#include "pmradiosity.h" +#include "pmglobalphotons.h" +#include "pmphotons.h" +#include "pminterior.h" +#include "pmlightgroup.h" +#include "pmpattern.h" +#include "pmnormal.h" +#include "pminteriortexture.h" +#include "pmwarp.h" +#include "pmspheresweep.h" +#include "pmfinish.h" +#include "pmmesh.h" +#include "pmmedia.h" +#include "pmgraphicalobject.h" +#include "pmpigment.h" +#include "pmtexture.h" +#include "pmbicubicpatch.h" +#include "pmtriangle.h" + +const PMIsoSurface::ContainedByType c_defaultIsoContainedBy = PMIsoSurface::Box; +const PMVector c_defaultIsoCorner1 = PMVector( -1, -1, -1 ); +const PMVector c_defaultIsoCorner2 = PMVector( 1, 1, 1 ); +const PMVector c_defaultIsoCenter = PMVector( 0, 0, 0 ); +const double c_defaultIsoRadius = 1; + +const double c_defaultIsoThreshold = 0.0; +const double c_defaultIsoAccuracy = 0.001; +const double c_defaultIsoMaxGradient = 1.1; +const bool c_defaultIsoEvaluate = false; +const double c_defaultIsoEvaluate0 = 5; +const double c_defaultIsoEvaluate1 = 1.2; +const double c_defaultIsoEvaluate2 = 0.95; +const double c_defaultIsoOpen = false; +const int c_defaultIsoMaxTrace = 1; +const bool c_defaultIsoAllIntersections = false; + +void PMPov35SerIsoSurface( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMIsoSurface* o = ( PMIsoSurface* ) object; + QString str; + + dev->objectBegin( "isosurface" ); + dev->writeName( object->name( ) ); + + if( o->containedBy( ) == PMIsoSurface::Box ) + { + dev->writeLine( QString( "function { " ) + o->function( ) + " }" ); + + if( o->corner1( ) != c_defaultIsoCorner1 || + o->corner2( ) != c_defaultIsoCorner2 ) + { + dev->writeLine( QString( "contained_by { box { " ) + + o->corner1( ).serialize( ) + ", " + + o->corner2( ).serialize( ) + " } }" ); + } + } + else + { + str.setNum( o->radius( ) ); + dev->writeLine( QString( "contained_by { sphere { " ) + + o->center( ).serialize( ) + ", " + str + " } }" ); + } + + if( !approx( o->threshold( ), c_defaultIsoThreshold ) ) + { + str.setNum( o->threshold( ) ); + dev->writeLine( "threshold " + str ); + } + if( !approx( o->accuracy( ), c_defaultIsoAccuracy ) ) + { + str.setNum( o->accuracy( ) ); + dev->writeLine( "accuracy " + str ); + } + if( !approx( o->maxGradient( ), c_defaultIsoMaxGradient ) ) + { + str.setNum( o->maxGradient( ) ); + dev->writeLine( "max_gradient " + str ); + } + if( o->evaluate( ) ) + { + str = QString( "%1, %2, %3" ).arg( o->evaluateValue( 0 ) ) + .arg( o->evaluateValue( 1 ) ).arg( o->evaluateValue( 2 ) ); + dev->writeLine( "evaluate " + str ); + } + if( o->allIntersections( ) ) + dev->writeLine( "all_intersections" ); + else + { + str.setNum( o->maxTrace( ) ); + dev->writeLine( "max_trace " + str ); + } + if( o->open( ) ) + dev->writeLine( "open" ); + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +const double c_defaultLightTightness = 10; +const int c_defaultLightAdaptive = 0; + +void PMPov35SerLight( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMLight* o = ( PMLight* ) object; + + dev->objectBegin( QString( "light_source" ) ); + + dev->writeName( object->name( ) ); + dev->writeLine( o->location( ).serialize( ) + ", " + o->color( ).serialize( ) ); + + if( o->lightType( ) == PMLight::SpotLight ) + dev->writeLine( QString( "spotlight" ) ); + else if( o->lightType( ) == PMLight::CylinderLight ) + dev->writeLine( QString( "cylinder" ) ); + else if( o->lightType( ) == PMLight::ShadowlessLight ) + dev->writeLine( QString( "shadowless" ) ); + + if( o->parallel( ) ) + dev->writeLine( QString( "parallel" ) ); + + if( ( o->lightType( ) == PMLight::SpotLight ) || + ( o->lightType( ) == PMLight::CylinderLight ) ) + { + dev->writeLine( QString( "radius %1" ).arg( o->radius( ) ) ); + dev->writeLine( QString( "falloff %1" ).arg( o->falloff( ) ) ); + if( o->tightness( ) != c_defaultLightTightness ) + dev->writeLine( QString( "tightness %1" ).arg( o->tightness( ) ) ); + dev->writeLine( QString( "point_at " ) + o->pointAt( ).serialize( ) ); + } + + if( o->isAreaLight( ) ) + { + dev->writeLine( QString( "area_light " ) + o->axis1( ).serialize( ) + + QString( ", " ) + o->axis2( ).serialize( ) + + QString( ", %1, %2" ).arg( o->size1( ) ).arg( o->size2( ) ) ); + if( o->adaptive( ) != c_defaultLightAdaptive ) + dev->writeLine( QString( "adaptive %1" ).arg( o->adaptive( ) ) ); + if( o->jitter( ) ) + dev->writeLine( QString( "jitter" ) ); + if ( o->areaType( ) == PMLight::Circular ) + dev->writeLine( QString( "circular" ) ); + if ( o->orient( ) ) + dev->writeLine( QString( "orient" ) ); + } + + if( o->fading( ) ) + { + dev->writeLine( QString( "fade_distance %1" ).arg( o->fadeDistance( ) ) ); + dev->writeLine( QString( "fade_power %1" ).arg( o->fadePower( ) ) ); + } + + if( !o->mediaInteraction( ) ) + dev->writeLine( QString( "media_interaction off" ) ); + if( !o->mediaAttenuation( ) ) + dev->writeLine( QString( "media_attenuation off" ) ); + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov35SerProjectedThrough( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + dev->objectBegin( "projected_through" ); + dev->writeName( object->name( ) ); + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +const double c_defaultGlobalSettingsAdcBailout = 1.0 / 255.0; +const PMColor c_defaultGlobalSettingsAmbientLight = PMColor( 1.0, 1.0, 1.0, 0.0, 0.0 ); +const double c_defaultGlobalSettingsAssumedGamma = 0.0; +const bool c_defaultGlobalSettingsHfGray16 = false; +const PMColor c_defaultGlobalSettingsIridWaveLength = PMColor( 0.25, 0.18, 0.14, 0.0, 0.0 ); +const int c_defaultGlobalSettingsMaxIntersections = 0; // ??? +const int c_defaultGlobalSettingsMaxTraceLevel = 0; // ??? +const int c_defaultGlobalSettingsNumberWaves = 10; +const bool c_defaultGlobalSettingsRadiosity = false; +const double c_defaultGlobalSettingsBrightness = 1.0; +const int c_defaultGlobalSettingsCount = 35; +const double c_defaultGlobalSettingsDistanceMaximum = 0; // ??? +const double c_defaultGlobalSettingsErrorBound = 1.8; +const double c_defaultGlobalSettingsGrayThreshold = 0.0; +const double c_defaultGlobalSettingsLowErrorFactor = 0.5; +const double c_defaultGlobalSettingsMinimumReuse = 0.015; +const int c_defaultGlobalSettingsNearestCount = 5; +const int c_defaultGlobalSettingsRecursionLimit = 2; + +void PMPov35SerGlobalSettings( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMGlobalSettings* o = ( PMGlobalSettings* ) object; + + QString str1; + + dev->objectBegin( "global_settings" ); + + if( o->adcBailout( ) != c_defaultGlobalSettingsAdcBailout ) + { + str1.setNum( o->adcBailout( ) ); + dev->writeLine( "adc_bailout " + str1 ); + } + if( o->ambientLight( ) != c_defaultGlobalSettingsAmbientLight ) + dev->writeLine( "ambient_light " + o->ambientLight( ).serialize( ) ); + if( o->assumedGamma( ) != c_defaultGlobalSettingsAssumedGamma ) + { + str1.setNum( o->assumedGamma( ) ); + dev->writeLine( "assumed_gamma " + str1 ); + } + if( o->hfGray16( ) != c_defaultGlobalSettingsHfGray16 ) + { + if( o->hfGray16( ) ) + dev->writeLine( "hf_gray_16 on" ); + else + dev->writeLine( "hf_gray_16 off" ); + } + if( o->iridWaveLength( ) != c_defaultGlobalSettingsIridWaveLength ) + dev->writeLine( "irid_wavelength " + o->iridWaveLength( ).serialize( ) ); + if( o->maxTraceLevel( ) != c_defaultGlobalSettingsMaxTraceLevel ) + { + str1.setNum( o->maxTraceLevel( ) ); + dev->writeLine( "max_trace_level " + str1 ); + } + if( o->maxIntersections( ) != c_defaultGlobalSettingsMaxIntersections ) + { + str1.setNum( o->maxIntersections( ) ); + dev->writeLine( "max_intersections " + str1 ); + } + if( o->numberWaves( ) != c_defaultGlobalSettingsNumberWaves ) + { + str1.setNum( o->numberWaves( ) ); + dev->writeLine( "number_of_waves " + str1 ); + } + if ( o->noiseGenerator( ) == PMGlobalSettings::Original ) + dev->writeLine( QString( "noise_generator 1" ) ); + else if ( o->noiseGenerator( ) == PMGlobalSettings::RangeCorrected ) + dev->writeLine( QString( "noise_generator 2" ) ); + else + dev->writeLine( QString( "noise_generator 3" ) ); + if( o->isRadiosityEnabled( ) ) + { + dev->objectBegin( "radiosity" ); + if( o->brightness( ) != c_defaultGlobalSettingsBrightness ) + { + str1.setNum( o->brightness( ) ); + dev->writeLine( "brightness " + str1 ); + } + if( o->count( ) != c_defaultGlobalSettingsCount ) + { + str1.setNum( o->count( ) ); + dev->writeLine( "count " + str1 ); + } + if( o->distanceMaximum( ) != c_defaultGlobalSettingsDistanceMaximum ) + { + str1.setNum( o->distanceMaximum( ) ); + dev->writeLine( "distance_maximum " + str1 ); + } + if( o->errorBound( ) != c_defaultGlobalSettingsErrorBound ) + { + str1.setNum( o->errorBound( ) ); + dev->writeLine( "error_bound " + str1 ); + } + if( o->grayThreshold( ) != c_defaultGlobalSettingsGrayThreshold ) + { + str1.setNum( o->grayThreshold( ) ); + dev->writeLine( "gray_threshold " + str1 ); + } + if( o->lowErrorFactor( ) != c_defaultGlobalSettingsLowErrorFactor ) + { + str1.setNum( o->lowErrorFactor( ) ); + dev->writeLine( "low_error_factor " + str1 ); + } + if( o->minimumReuse( ) != c_defaultGlobalSettingsMinimumReuse ) + { + str1.setNum( o->minimumReuse( ) ); + dev->writeLine( "minimuo->reuse( ) " + str1 ); + } + if( o->nearestCount( ) != c_defaultGlobalSettingsNearestCount ) + { + str1.setNum( o->nearestCount( ) ); + dev->writeLine( "nearest_count " + str1 ); + } + if( o->recursionLimit( ) != c_defaultGlobalSettingsRecursionLimit ) + { + str1.setNum( o->recursionLimit( ) ); + dev->writeLine( "recursion_limit " + str1 ); + } + dev->objectEnd( ); + } + else + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +const double c_defaultRadiosityAdcBailout = 0.01; +const double c_defaultRadiosityBrightness = 1.0; +const int c_defaultRadiosityCount = 35; +const double c_defaultRadiosityErrorBound = 1.8; +const double c_defaultRadiosityGrayThreshold = 0.0; +const double c_defaultRadiosityLowErrorFactor = 0.5; +const double c_defaultRadiosityMaxSample = -1.0; +const double c_defaultRadiosityMinimumReuse = 0.015; +const int c_defaultRadiosityNearestCount = 5; +const double c_defaultRadiosityPretraceStart = 0.08; +const double c_defaultRadiosityPretraceEnd = 0.04; +const int c_defaultRadiosityRecursionLimit = 2; + +void PMPov35SerRadiosity( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev ) +{ + PMRadiosity* o = ( PMRadiosity* ) object; + + QString str1; + + dev->objectBegin( "radiosity" ); + + if( o->adcBailout( ) != c_defaultRadiosityAdcBailout ) + { + str1.setNum( o->adcBailout( ) ); + dev->writeLine( "adc_bailout " + str1 ); + } + + if( !o->alwaysSample( ) ) + dev->writeLine( "always_sample off" ); + + if( o->brightness( ) != c_defaultRadiosityBrightness ) + { + str1.setNum( o->brightness( ) ); + dev->writeLine( "brightness " + str1 ); + } + + if( o->count( ) != c_defaultRadiosityCount ) + { + str1.setNum( o->count( ) ); + dev->writeLine( "count " + str1 ); + } + + if( o->errorBound( ) != c_defaultRadiosityErrorBound ) + { + str1.setNum( o->errorBound( ) ); + dev->writeLine( "error_bound " + str1 ); + } + + if( o->grayThreshold( ) != c_defaultRadiosityGrayThreshold ) + { + str1.setNum( o->grayThreshold( ) ); + dev->writeLine( "gray_threshold " + str1 ); + } + + if( o->lowErrorFactor( ) != c_defaultRadiosityLowErrorFactor ) + { + str1.setNum( o->lowErrorFactor( ) ); + dev->writeLine( "low_error_factor " + str1 ); + } + + if( o->maxSample( ) != c_defaultRadiosityMaxSample ) + { + str1.setNum( o->maxSample( ) ); + dev->writeLine( "max_sample " + str1 ); + } + + if( o->media( ) ) + dev->writeLine( "media on" ); + + if( o->minimumReuse( ) != c_defaultRadiosityMinimumReuse ) + { + str1.setNum( o->minimumReuse( ) ); + dev->writeLine( "minimum_reuse " + str1 ); + } + if( o->nearestCount( ) != c_defaultRadiosityNearestCount ) + { + str1.setNum( o->nearestCount( ) ); + dev->writeLine( "nearest_count " + str1 ); + } + + if( o->normal( ) ) + dev->writeLine( "normal on" ); + + if( o->pretraceStart( ) != c_defaultRadiosityPretraceStart ) + { + str1.setNum( o->pretraceStart( ) ); + dev->writeLine( "pretrace_start " + str1 ); + } + + if( o->pretraceEnd( ) != c_defaultRadiosityPretraceEnd ) + { + str1.setNum( o->pretraceEnd( ) ); + dev->writeLine( "pretrace_end " + str1 ); + } + + if( o->recursionLimit( ) != c_defaultGlobalSettingsRecursionLimit ) + { + str1.setNum( o->recursionLimit( ) ); + dev->writeLine( "recursion_limit " + str1 ); + } + dev->objectEnd( ); +} + +const int c_defaultGlobalPhotonsGatherMin = 20; +const int c_defaultGlobalPhotonsGatherMax = 100; +const int c_defaultGlobalPhotonsMediaMaxSteps = 0; +const double c_defaultGlobalPhotonsMediaFactor = 1.0; +const double c_defaultGlobalPhotonsJitter = 0.4; +const double c_defaultGlobalPhotonsAutostop = 0.0; +const double c_defaultGlobalPhotonsExpandIncrease = 0.2; +const int c_defaultGlobalPhotonsExpandMin = 40; +const double c_defaultGlobalPhotonsRadiusGather = 0.0; +const double c_defaultGlobalPhotonsRadiusGatherMulti = 1.0; +const double c_defaultGlobalPhotonsRadiusMedia = 0.0; +const double c_defaultGlobalPhotonsRadiusMediaMulti = 1.0; + +void PMPov35SerGlobalPhotons( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev ) +{ + PMGlobalPhotons* o = ( PMGlobalPhotons* ) object; + + QString str1, str2; + + dev->objectBegin( "photons" ); + + if ( o->numberType( ) == PMGlobalPhotons::Spacing ) + { + str1.setNum( o->spacing( ) ); + dev->writeLine( "spacing " + str1 ); + } + else + { + str1.setNum( o->count( ) ); + dev->writeLine( "count " + str1 ); + } + + if ( o->gatherMin( ) != c_defaultGlobalPhotonsGatherMin || + o->gatherMax( ) != c_defaultGlobalPhotonsGatherMax ) + { + str1.setNum( o->gatherMin( ) ); + str2.setNum( o->gatherMax( ) ); + dev->writeLine( "gather " + str1 + ", " + str2 ); + } + + if ( o->mediaMaxSteps( ) != c_defaultGlobalPhotonsMediaMaxSteps ) + { + str1.setNum( o->mediaMaxSteps( ) ); + if ( o->mediaFactor( ) != c_defaultGlobalPhotonsMediaFactor ) + { + str2.setNum( o->mediaFactor( ) ); + dev->writeLine( "media " + str1 + ", " + str2 ); + } + else + dev->writeLine( "media " + str1 ); + } + + if ( o->jitter( ) != c_defaultGlobalPhotonsJitter ) + { + str1.setNum( o->jitter( ) ); + dev->writeLine( "jitter " + str1 ); + } + + if ( !o->maxTraceLevelGlobal( ) ) + { + str1.setNum( o->maxTraceLevel( ) ); + dev->writeLine( "max_trace_level " + str1 ); + } + + if ( !o->adcBailoutGlobal( ) ) + { + str1.setNum( o->adcBailout( ) ); + dev->writeLine( "adc_bailout " + str1 ); + } + + if ( o->autostop( ) != c_defaultGlobalPhotonsAutostop ) + { + str1.setNum( o->autostop( ) ); + dev->writeLine( "autostop " + str1 ); + } + + if ( o->expandIncrease( ) != c_defaultGlobalPhotonsExpandIncrease || + o->expandMin( ) != c_defaultGlobalPhotonsExpandMin ) + { + str1.setNum( o->expandIncrease( ) ); + str2.setNum( o->expandMin( ) ); + dev->writeLine( "expand_thresholds " + str1 + ", " + str2 ); + } + + if ( o->radiusGather( ) != c_defaultGlobalPhotonsRadiusGather || + o->radiusGatherMulti( ) != c_defaultGlobalPhotonsRadiusGatherMulti || + o->radiusMedia( ) != c_defaultGlobalPhotonsRadiusMedia || + o->radiusMediaMulti( ) != c_defaultGlobalPhotonsRadiusMediaMulti ) + { + QString str3, str4; + str1.setNum( o->radiusGather( ) ); + str2.setNum( o->radiusGatherMulti( ) ); + str3.setNum( o->radiusMedia( ) ); + str4.setNum( o->radiusMediaMulti( ) ); + dev->writeLine( "radius " + str1 + ", " + str2 + ", " + str3 + ", " + str4 ); + } + dev->objectEnd( ); +} + +const double c_defaultPhotonsSpacingMulti = 1.0; + +void PMPov35SerPhotons( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev ) +{ + PMPhotons* o = ( PMPhotons* ) object; + + QString str1; + + dev->objectBegin( "photons" ); + + if( o->parent( ) && ( o->parent( )->type( ) == "Light" ) ) + { + if( o->refraction( ) ) + dev->writeLine( QString( "refraction on" ) ); + if( o->reflection( ) ) + dev->writeLine( QString( "reflection on" ) ); + if( o->areaLight( ) ) + dev->writeLine( QString( "area_light" ) ); + } + else + { + if( o->target( ) ) + { + if( o->spacingMulti( ) != c_defaultPhotonsSpacingMulti ) + { + str1.setNum( o->spacingMulti( ) ); + dev->writeLine( "target " + str1 ); + } + else + dev->writeLine( QString( "target" ) ); + } + if( o->refraction( ) ) + dev->writeLine( QString( "refraction on" ) ); + if( o->reflection( ) ) + dev->writeLine( QString( "reflection on" ) ); + if( !o->collect( ) ) + dev->writeLine( QString( "collect off" ) ); + if( o->passThrough( ) ) + dev->writeLine( QString( "pass_through" ) ); + } + dev->objectEnd( ); +} + +void PMPov35SerInterior( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMInterior* o = ( PMInterior* ) object; + + QString str1; + + dev->objectBegin( "interior" ); + dev->callSerialization( object, metaObject->superClass( ) ); + + if( o->isIorEnabled( ) ) + { + str1.setNum( o->ior( ) ); + dev->writeLine( "ior " + str1 ); + } + if( o->isCausticsEnabled( ) ) + { + str1.setNum( o->caustics( ) ); + dev->writeLine( "caustics " + str1 ); + } + if ( o->isDispersionEnabled( ) ) + { + str1.setNum( o->dispersion( ) ); + dev->writeLine( "dispersion " + str1 ); + } + if ( o->isDispSamplesEnabled( ) ) + { + str1.setNum( o->dispSamples( ) ); + dev->writeLine( "dispersion_samples " + str1 ); + } + if( o->isFadeDistanceEnabled( ) ) + { + str1.setNum( o->fadeDistance( ) ); + dev->writeLine( "fade_distance " + str1 ); + } + if( o->isFadePowerEnabled( ) ) + { + str1.setNum( o->fadePower( ) ); + dev->writeLine( "fade_power " + str1 ); + } + dev->objectEnd( ); +} + +void PMPov35SerLightGroup( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMLightGroup* o = ( PMLightGroup* ) object; + + dev->objectBegin( "light_group" ); + + dev->writeName( object->name( ) ); + dev->callSerialization( object, metaObject->superClass( ) ); + + if ( o->globalLights( ) ) + dev->writeLine( "global_lights on" ); + else + dev->writeLine( "global_lights off" ); + + dev->objectEnd( ); +} + +const PMVector c_defaultPatternCrackleForm = PMVector( -1.0, 1.0, 0.0 ); +const int c_defaultPatternCrackleMetric = 2; +const double c_defaultPatternCrackleOffset = 0.0; +const bool c_defaultPatternCrackleSolid = false; +const int c_defaultPatternFractalExponent = 2; +const int c_defaultPatternFractalExtType = 1; +const double c_defaultPatternFractalExtFactor = 1.0; +const int c_defaultPatternFractalIntType = 0; +const double c_defaultPatternFractalIntFactor = 1.0; +const double c_defaultPatternSlopeLoSlope = 0.0; +const double c_defaultPatternSlopeHiSlope = 1.0; +const double c_defaultPatternSlopeLoAlt = 0.0; +const double c_defaultPatternSlopeHiAlt = 1.0; +const int c_defaultPatternOctaves = 6; +const double c_defaultPatternOmega = 0.5; +const double c_defaultPatternLambda = 2.0; + +void PMPov35SerPattern( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev ) +{ + PMPattern* o = ( PMPattern* ) object; + + QString str, str2; + + // pattern type + switch( o->patternType( ) ) + { + case PMPattern::PatternAgate: + dev->writeLine( "agate" ); + break; + case PMPattern::PatternAverage: + dev->writeLine( "average" ); + break; + case PMPattern::PatternBoxed: + dev->writeLine( "boxed" ); + break; + case PMPattern::PatternBozo: + dev->writeLine( "bozo" ); + break; + case PMPattern::PatternBumps: + dev->writeLine( "bumps" ); + break; + case PMPattern::PatternCells: + dev->writeLine( "cells" ); + break; + case PMPattern::PatternCrackle: + dev->writeLine( "crackle" ); + break; + case PMPattern::PatternCylindrical: + dev->writeLine( "cylindrical" ); + break; + case PMPattern::PatternDensity: + dev->writeLine( "density_file df3 \"" + o->densityFile( ) + "\""); + break; + case PMPattern::PatternDents: + dev->writeLine( "dents" ); + break; + case PMPattern::PatternGradient: + dev->writeLine( "gradient " + o->gradient( ).serialize( ) ); + break; + case PMPattern::PatternGranite: + dev->writeLine( "granite" ); + break; + case PMPattern::PatternJulia: + if( o->fractalMagnet( ) ) + { + str.setNum( o->fractalMagnetType( ) ); + str = "magnet " + str + " "; + } + else + str = ""; + + str2.setNum( o->maxIterations( ) ); + str = str + "julia " + o->juliaComplex( ).serialize( ) + ", " + str2; + dev->writeLine( str ); + break; + case PMPattern::PatternLeopard: + dev->writeLine( "leopard" ); + break; + case PMPattern::PatternMandel: + if( o->fractalMagnet( ) ) + { + str.setNum( o->fractalMagnetType( ) ); + str = "magnet " + str + " "; + } + else + str = ""; + + str2.setNum( o->maxIterations( ) ); + dev->writeLine( str + "mandel " + str2 ); + break; + case PMPattern::PatternMarble: + dev->writeLine( "marble" ); + break; + case PMPattern::PatternOnion: + dev->writeLine( "onion" ); + break; + case PMPattern::PatternPlanar: + dev->writeLine( "planar" ); + break; + case PMPattern::PatternQuilted: + dev->writeLine( "quilted" ); + break; + case PMPattern::PatternRadial: + dev->writeLine( "radial" ); + break; + case PMPattern::PatternRipples: + dev->writeLine( "ripples" ); + break; + case PMPattern::PatternSlope: + dev->objectBegin( "slope" ); + dev->write( o->slopeDirection( ).serialize( ) ); + if ( o->slopeLoSlope( ) != c_defaultPatternSlopeLoSlope || + o->slopeHiSlope( ) != c_defaultPatternSlopeHiSlope ) + { + str.setNum( o->slopeLoSlope( ) ); + str2.setNum( o->slopeHiSlope( ) ); + dev->writeLine( ", " + str + ", " + str2 ); + } + else + dev->writeLine( "" ); + + if ( o->slopeAltFlag( ) ) + { + dev->write( "altitude " + o->slopeAltitude( ).serialize( ) ); + if ( o->slopeLoAltitude( ) != c_defaultPatternSlopeLoAlt || + o->slopeHiAltitude( ) != c_defaultPatternSlopeHiAlt ) + { + str.setNum( o->slopeLoAltitude( ) ); + str2.setNum( o->slopeHiAltitude( ) ); + dev->writeLine( ", " + str + ", " + str2 ); + } + else + dev->writeLine( "" ); + } + dev->objectEnd( ); + break; + case PMPattern::PatternSpherical: + dev->writeLine( "spherical" ); + break; + case PMPattern::PatternSpiral1: + str.setNum( o->spiralNumberArms( ) ); + dev->writeLine( "spiral1 " + str ); + break; + case PMPattern::PatternSpiral2: + str.setNum( o->spiralNumberArms( ) ); + dev->writeLine( "spiral2 " + str ); + break; + case PMPattern::PatternSpotted: + dev->writeLine( "spotted" ); + break; + case PMPattern::PatternWaves: + dev->writeLine( "waves" ); + break; + case PMPattern::PatternWood: + dev->writeLine( "wood" ); + break; + case PMPattern::PatternWrinkles: + dev->writeLine( "wrinkles" ); + break; + } + // depth + if( o->parent( ) ) + { + if( o->depth( ) && o->parent( )->type( ) == "Normal" ) + { + str.setNum( o->depth( ) ); + dev->writeLine( str ); + } + } + // modifiers + switch( o->patternType( ) ) + { + case PMPattern::PatternAgate: + str.setNum( o->agateTurbulence( ) ); + dev->writeLine( "agate_turb " + str ); + break; + case PMPattern::PatternCrackle: + if ( o->crackleForm( ) != c_defaultPatternCrackleForm ) + dev->writeLine( "form " + o->crackleForm( ).serialize( ) ); + if ( o->crackleMetric( ) != c_defaultPatternCrackleMetric ) + { + str.setNum( o->crackleMetric( ) ); + dev->writeLine( "metric " + str ); + } + if ( o->crackleOffset( ) != c_defaultPatternCrackleOffset ) + { + str.setNum( o->crackleOffset( ) ); + dev->writeLine( "offset " + str ); + } + if ( o->crackleSolid( ) ) + dev->writeLine( "solid" ); + break; + case PMPattern::PatternDensity: + str.setNum( o->densityInterpolate( ) ); + dev->writeLine( "interpolate " + str ); + break; + case PMPattern::PatternJulia: + case PMPattern::PatternMandel: + if ( !o->fractalMagnet( ) && o->fractalExponent( ) != c_defaultPatternFractalExponent ) + { + str.setNum( o->fractalExponent( ) ); + dev->writeLine( "exponent " + str ); + } + if ( o->fractalExtType( ) != c_defaultPatternFractalExtType || + o->fractalExtFactor( ) != c_defaultPatternFractalExtFactor ) + { + str.setNum( o->fractalExtType( ) ); + str2.setNum( o->fractalExtFactor( ) ); + dev->writeLine( "exterior " + str + ", " + str2 ); + } + if ( o->fractalIntType( ) != c_defaultPatternFractalIntType || + o->fractalIntFactor( ) != c_defaultPatternFractalIntFactor ) + { + str.setNum( o->fractalIntType( ) ); + str2.setNum( o->fractalIntFactor( ) ); + dev->writeLine( "interior " + str + ", " + str2 ); + } + break; + case PMPattern::PatternQuilted: + str.setNum( o->quiltControl0( ) ); + dev->writeLine( "control0 " + str ); + str.setNum( o->quiltControl1( ) ); + dev->writeLine( "control1 " + str ); + break; + case PMPattern::PatternBozo: + case PMPattern::PatternBumps: + case PMPattern::PatternGranite: + case PMPattern::PatternWrinkles: + switch( o->noiseGenerator( ) ) + { + case PMPattern::Original: + dev->writeLine( QString( "noise_generator 1" ) ); + break; + case PMPattern::RangeCorrected: + dev->writeLine( QString( "noise_generator 2" ) ); + break; + case PMPattern::Perlin: + dev->writeLine( QString( "noise_generator 3" ) ); + break; + default: + break; + } + break; + default: + break; + } + if( o->isTurbulenceEnabled( ) ) + { + dev->writeLine( "turbulence " + o->valueVector( ).serialize( ) ); + if( o->octaves( ) != c_defaultPatternOctaves ) + { + str.setNum( o->octaves( ) ); + dev->writeLine( "octaves " + str ); + } + if( o->omega( ) != c_defaultPatternOmega ) + { + str.setNum( o->omega( ) ); + dev->writeLine( "omega " + str ); + } + if( o->lambda( ) != c_defaultPatternLambda ) + { + str.setNum( o->lambda( ) ); + dev->writeLine( "lambda " + str ); + } + } +} + +const double c_defaultNormalAccuracy = 0.02; + +void PMPov35SerNormal( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMNormal* o = ( PMNormal* ) object; + + QString str1; + bool bObject = true; + + if( o->parent( ) ) + { + if( o->parent( )->type( ) == "NormalMap" ) + bObject = false; + } + + if( bObject ) + { + dev->objectBegin( "normal" ); + if ( o->uvMapping() ) + dev->writeLine( "uv_mapping" ); + } + + dev->callSerialization( object, metaObject->superClass( ) ); + + if( o->isBumpSizeEnabled( ) ) + { + str1.setNum( o->bumpSize( ) ); + dev->writeLine( "bump_size " + str1 ); + } + + if( o->accuracy( ) != c_defaultNormalAccuracy ) + { + str1.setNum( o->accuracy( ) ); + dev->writeLine( "accuracy " + str1 ); + } + + if( bObject ) + dev->objectEnd( ); +} + +void PMPov35SerInteriorTexture( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + dev->objectBegin( "interior_texture" ); + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +const PMVector c_warpDirectionDefault = PMVector( 1.0, 0.0, 0.0 ); +const PMVector c_warpOffsetDefault = PMVector( 0.0, 0.0, 0.0 ); +const PMVector c_warpFlipDefault = PMVector( 0.0, 0.0, 0.0 ); +const PMVector c_warpLocationDefault = PMVector( 0.0, 0.0, 0.0 ); +const double c_warpRadiusDefault = 0; +const double c_warpStrengthDefault = 0; +const double c_warpFalloffDefault = 0; +const bool c_warpInverseDefault = false; +const PMVector c_warpRepeatDefault = PMVector( 0.0, 0.0, 0.0 ); +const PMVector c_warpTurbulenceDefault = PMVector( 0.0, 0.0, 0.0 ); +const PMVector c_warpValueVectorDefault = PMVector( 0.0, 0.0, 0.0 ); +const int c_warpOctavesDefault = 6; +const double c_warpOmegaDefault = 0.5; +const double c_warpLambdaDefault = 2.0; +const PMVector c_warpOrientationDefault = PMVector( 0.0, 0.0, 1.0 ); +const double c_warpDistExpDefault = 0.0; +const double c_warpMajorRadiusDefault = 1.0; + +void PMPov35SerWarp( const PMObject* object, const PMMetaObject* , PMOutputDevice* dev ) +{ + PMWarp* o = ( PMWarp* ) object; + + QString str1, str2; + + dev->objectBegin( "warp" ); + switch( o->warpType( ) ) + { + case PMWarp::Repeat: + dev->writeLine( "repeat" ); + dev->writeLine( o->direction( ).serialize( ) ); + dev->writeLine( "offset " + o->offset( ).serialize( ) ); + dev->writeLine( "flip " + o->flip( ).serialize( ) ); + break; + case PMWarp::BlackHole: + dev->writeLine( "black_hole" ); + dev->writeLine( o->location( ).serialize( ) ); + str1.setNum(o->radius( )); + dev->writeLine( ", " + str1 ); + if( o->strength( ) != c_warpStrengthDefault ) + { + str1.setNum( o->strength( )); + dev->writeLine( "strength " + str1 ); + } + if( o->falloff( ) != c_warpFalloffDefault ) + { + str1.setNum( o->falloff( )); + dev->writeLine( "falloff " + str1 ); + } + if( o->inverse( ) != c_warpInverseDefault ) + { + if( o->inverse( ) ) dev->writeLine( "inverse" ); + } + if( o->repeat( ) != c_warpRepeatDefault ) + { + dev->writeLine( "repeat " + o->repeat( ).serialize( ) ); + } + if( o->turbulence( ) != c_warpTurbulenceDefault ) + { + dev->writeLine( "turbulence " + o->turbulence( ).serialize( ) ); + } + break; + case PMWarp::Turbulence: + dev->writeLine( "turbulence " + o->valueVector( ).serialize( ) ); + if( o->octaves( ) != c_warpOctavesDefault ) + { + str1.setNum(o->octaves( )); + dev->writeLine( "octaves " + str1 ); + } + if( o->omega( ) != c_warpOmegaDefault ) + { + str1.setNum( o->omega( ) ); + dev->writeLine( "omega " + str1 ); + } + if( o->lambda( ) != c_warpLambdaDefault ) + { + str1.setNum( o->lambda( ) ); + dev->writeLine( "lambda " + str1 ); + } + break; + case PMWarp::Cylindrical: + dev->writeLine( "cylindrical " + o->orientation( ).serialize( ) ); + if ( o->distExp( ) != c_warpDistExpDefault ) + { + str1.setNum( o->distExp( ) ); + dev->writeLine( "dist_exp " + str1 ); + } + break; + case PMWarp::Spherical: + dev->writeLine( "spherical " + o->orientation( ).serialize( ) ); + if ( o->distExp( ) != c_warpDistExpDefault ) + { + str1.setNum( o->distExp( ) ); + dev->writeLine( "dist_exp " + str1 ); + } + break; + case PMWarp::Toroidal: + dev->writeLine( "torodial " + o->orientation( ).serialize( ) ); + if ( o->distExp( ) != c_warpDistExpDefault ) + { + str1.setNum( o->distExp( ) ); + dev->writeLine( "dist_exp " + str1 ); + } + if ( o->majorRadius( ) != c_warpMajorRadiusDefault ) + { + str1.setNum( o->majorRadius( ) ); + dev->writeLine( "major_radius " + str1 ); + } + break; + case PMWarp::Planar: + str1 = "planar " + o->orientation( ).serialize( ); + if ( o->distExp( ) != c_warpDistExpDefault ) + { + str2.setNum( o->distExp( ) ); + dev->writeLine( str1 + ", " + str2 ); + } + else + dev->writeLine( str1 ); + break; + } + + dev->objectEnd( ); +} + +const double c_sphereSweepToleranceDefault = 1e-6; + +void PMPov35SerSphereSweep( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMSphereSweep* o = ( PMSphereSweep* ) object; + + QString str1; + int numSpheres; + QValueList points; + QValueList radii; + + dev->objectBegin( "sphere_sweep" ); + + switch( o->splineType( ) ) + { + case PMSphereSweep::LinearSpline: + dev->writeLine( QString( "linear_spline," ) ); + break; + case PMSphereSweep::BSpline: + dev->writeLine( QString( "b_spline," ) ); + break; + case PMSphereSweep::CubicSpline: + dev->writeLine( QString( "cubic_spline," ) ); + break; + } + + numSpheres = o->numberOfPoints( ); + str1.setNum( numSpheres ); + dev->writeLine( str1 + "," ); + points = o->points( ); + radii = o->radii( ); + + for ( int i = 0; i < numSpheres; ++i ) + { + str1.setNum( radii[i] ); + dev->writeLine( points[i].serialize( ) + "," + str1 ); + } + + if ( o->tolerance( ) != c_sphereSweepToleranceDefault ) + { + str1.setNum( o->tolerance( ) ); + dev->writeLine( "tolerance " + str1 ); + } + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov35SerFinish( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMFinish* o = ( PMFinish* ) object; + + QString str1; + + dev->objectBegin( "finish" ); + + dev->callSerialization( object, metaObject->superClass( ) ); + + if( o->isAmbientEnabled( ) ) + dev->writeLine( "ambient " + o->ambientColor( ).serialize( ) ); + + if( o->isDiffuseEnabled( ) ) + { + str1.setNum( o->diffuse( ) ); + dev->writeLine( "diffuse " + str1 ); + } + + if( o->isBrillianceEnabled( ) ) + { + str1.setNum( o->brilliance( ) ); + dev->writeLine( "brilliance " + str1 ); + } + + if( o->isPhongEnabled( ) ) + { + str1.setNum( o->phong( ) ); + dev->writeLine( "phong " + str1 ); + } + + if( o->isPhongSizeEnabled( ) ) + { + str1.setNum( o->phongSize( ) ); + dev->writeLine( "phong_size " + str1 ); + } + + if( o->isMetallicEnabled( ) ) + { + str1.setNum( o->metallic( ) ); + dev->writeLine( "metallic " + str1 ); + } + + if( o->isSpecularEnabled( ) ) + { + str1.setNum( o->specular( ) ); + dev->writeLine( "specular " + str1 ); + } + + if( o->isRoughnessEnabled( ) ) + { + str1.setNum( o->roughness( ) ); + dev->writeLine( "roughness " + str1 ); + } + + if( o->isCrandEnabled( ) ) + { + str1.setNum( o->crand( ) ); + dev->writeLine( "crand " + str1 ); + } + + if( o->conserveEnergy( ) ) + dev->writeLine( "conserve_energy" ); + + if( o->irid( ) ) + { + str1.setNum( o->iridAmount( ) ); + dev->writeLine( "irid { " + str1 ); + str1.setNum( o->iridThickness( ) ); + dev->writeLine( "thickness " + str1 ); + str1.setNum( o->iridTurbulence( ) ); + dev->writeLine( "turbulence " + str1 + " } " ); + } + + if( o->isReflectionEnabled( ) ) + { + dev->objectBegin( "reflection" ); + + if ( o->isReflectionMinEnabled( ) ) + { + dev->writeLine( o->reflectionMinColor( ).serialize( ) + ", " + + o->reflectionColor( ).serialize( ) ); + } + else + dev->writeLine( o->reflectionColor( ).serialize( ) ); + + if ( o->reflectionFresnel( ) ) + dev->writeLine( "fresnel" ); + + if ( o->isRefFalloffEnabled( ) ) + { + str1.setNum( o->reflectionFalloff( ) ); + dev->writeLine( "falloff " + str1 ); + } + + if ( o->isRefExponentEnabled( ) ) + { + str1.setNum( o->reflectionExponent( ) ); + dev->writeLine( "exponent " + str1 ); + } + + if ( o->isRefMetallicEnabled( ) ) + { + str1.setNum( o->reflectionMetallic( ) ); + dev->writeLine( "metallic " + str1 ); + } + + dev->objectEnd( ); + } + + dev->objectEnd( ); +} + +void PMPov35SerMesh( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMMesh* o = ( PMMesh* ) object; + + dev->objectBegin( "mesh" ); + + if( o->isInsideVectorEnabled( ) ) + dev->writeLine( "inside_vector " + o->insideVector( ).serialize( ) ); + + dev->callSerialization( object, metaObject->superClass( ) ); + + if( !o->hierarchy( ) ) + dev->writeLine( "hierarchy off" ); + + dev->objectEnd( ); +} + +const int c_defaultMediaMethod = 1; +const int c_defaultMediaIntervals = 10; +const int c_defaultMediaSamplesMin = 1; +const int c_defaultMediaSamplesMax = 1; +const double c_defaultMediaConfidence = 0.9; +const double c_defaultMediaVariance = 0.0078125; +const double c_defaultMediaRatio = 0.9; +const int c_defaultMediaAALevel = 4; +const double c_defaultMediaAAThreshold = 0.1; +const double c_defaultMediaScatteringEccentricity = 0; +const double c_defaultMediaScatteringExtinction = 1.0; + +void PMPov35SerMedia( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMMedia* o = ( PMMedia* ) object; + + QString str1; + QString str2; + + dev->objectBegin( "media" ); + dev->callSerialization( object, metaObject->superClass( ) ); + + if( o->method( ) != c_defaultMediaMethod ) + { + str1.setNum( o->method( ) ); + dev->writeLine( "method " + str1 ); + } + if( o->intervals( ) != c_defaultMediaIntervals ) + { + str1.setNum( o->intervals( ) ); + dev->writeLine( "intervals " + str1 ); + } + if( o->samplesMin( ) != c_defaultMediaSamplesMin || + o->samplesMax( ) != c_defaultMediaSamplesMax ) + { + str1.setNum( o->samplesMin( ) ); + str2.setNum( o->samplesMax( ) ); + if ( o->method( ) < 3 ) + dev->writeLine( "samples " + str1 + "," + str2 ); + else + dev->writeLine( "samples " + str1 ); + } + if( o->confidence( ) != c_defaultMediaConfidence ) + { + str1.setNum( o->confidence( ) ); + dev->writeLine( "confidence " + str1 ); + } + if( o->variance( ) != c_defaultMediaVariance ) + { + str1.setNum( o->variance( ) ); + dev->writeLine( "variance " + str1 ); + } + if( o->ratio( ) != c_defaultMediaRatio ) + { + str1.setNum( o->ratio( ) ); + dev->writeLine( "ratio " + str1 ); + } + if ( o->method( ) == 3 ) + { + if ( o->aaLevel( ) != c_defaultMediaAALevel ) + { + str1.setNum( o->aaLevel( ) ); + dev->writeLine( "aa_level " + str1 ); + } + if ( o->aaThreshold( ) != c_defaultMediaAAThreshold ) + { + str1.setNum( o->aaThreshold( ) ); + dev->writeLine( "aa_threshold " + str1 ); + } + } + if( o->isAbsorptionEnabled( ) ) + { + dev->writeLine( "absorption " + o->absorption( ).serialize( ) ); + } + if( o->isEmissionEnabled( ) ) + { + dev->writeLine( "emission " + o->emission( ).serialize( ) ); + } + if( o->isScatteringEnabled( ) ) + { + dev->objectBegin( "scattering" ); + str1.setNum( o->scatteringType( ) ); + dev->writeLine( str1 + ", " + o->scatteringColor( ).serialize( ) ); + if( o->scatteringType( ) == 5 && o->scatteringEccentricity( ) + != c_defaultMediaScatteringEccentricity ) + { + str1.setNum( o->scatteringEccentricity( ) ); + dev->writeLine( "eccentricity " + str1 ); + } + if( o->scatteringExtinction( ) != c_defaultMediaScatteringExtinction ) + { + str1.setNum( o->scatteringExtinction( ) ); + dev->writeLine( "extinction " + str1 ); + } + dev->objectEnd( ); + } + dev->objectEnd( ); +} + +void PMPov35SerGraphicalObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMGraphicalObject* o = ( PMGraphicalObject* ) object; + + dev->callSerialization( object, metaObject->superClass( ) ); + + if( o->noShadow( ) ) + dev->writeLine( "no_shadow" ); + + if( o->noImage( ) ) + dev->writeLine( "no_image" ); + + if( o->noReflection( ) ) + dev->writeLine( "no_reflection" ); + + if( o->doubleIlluminate( ) ) + dev->writeLine( "double_illuminate" ); +} + +void PMPov35SerPigment( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMPigment* o = ( PMPigment* ) object; + + bool bObject = true; + if( o->parent( ) ) + if( o->parent( )->type( ) == "PigmentMap" ) + bObject = false; + + if( bObject ) + { + dev->objectBegin( "pigment" ); + if ( o->uvMapping() ) + dev->writeLine( "uv_mapping" ); + } + dev->callSerialization( object, metaObject->superClass( ) ); + if( bObject ) + dev->objectEnd( ); +} + +void PMPov35SerTexture( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMTexture* o = ( PMTexture* ) object; + + bool bObject = true; + if( o->parent( ) ) + if( o->parent( )->type( ) == "TextureMap" ) + bObject = false; + + if( bObject ) + { + dev->objectBegin( "texture" ); + if ( o->uvMapping() ) + dev->writeLine( "uv_mapping" ); + } + dev->callSerialization( object, metaObject->superClass( ) ); + if( bObject ) + dev->objectEnd( ); +} + +const double c_defaultPatchFlatness = 0; + +void PMPov35SerBicubicPatch( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMBicubicPatch* o = ( PMBicubicPatch* ) object; + + int u, v; + QString str, line; + dev->objectBegin( "bicubic_patch" ); + + dev->writeName( object->name( ) ); + + str.setNum( o->patchType( ) ); + dev->writeLine( "type " + str ); + if( !approx( o->flatness( ), c_defaultPatchFlatness ) ) + { + str.setNum( o->flatness( ) ); + dev->writeLine( "flatness " + str ); + } + str.setNum( o->uSteps( ) ); + dev->writeLine( "u_steps " + str ); + str.setNum( o->vSteps( ) ); + dev->writeLine( "v_steps " + str ); + + if( o->isUVEnabled( ) ) + { + dev->writeLine( "uv_vectors " + o->uvVector( 0 ).serialize( ) + + " " + o->uvVector( 1 ).serialize( ) + + " " + o->uvVector( 2 ).serialize( ) + + " " + o->uvVector( 3 ).serialize( ) ); + } + + for( v = 0; v < 4; v++ ) + { + line = o->controlPoint( v*4 ).serialize( ); + for( u = 1; u < 4; u++ ) + line += QString( ", " ) + o->controlPoint( u+4*v ).serialize( ); + if( v != 3 ) + line += ","; + dev->writeLine( line ); + } + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} + +void PMPov35SerTriangle( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ) +{ + PMTriangle* o = ( PMTriangle* ) object; + + if( o->isSmoothTriangle( ) ) + { + dev->objectBegin( "smooth_triangle" ); + + dev->writeName( object->name( ) ); + dev->writeLine( o->point( 0 ).serialize( ) + ", " + o->normal( 0 ).serialize( ) + "," ); + dev->writeLine( o->point( 1 ).serialize( ) + ", " + o->normal( 1 ).serialize( ) + "," ); + dev->writeLine( o->point( 2 ).serialize( ) + ", " + o->normal( 2 ).serialize( ) ); + } + else + { + dev->objectBegin( "triangle" ); + + dev->writeName( object->name( ) ); + dev->writeLine( o->point( 0 ).serialize( ) + ", " + o->point( 1 ).serialize( ) + + ", " + o->point( 2 ).serialize( ) ); + } + + if( o->isUVEnabled( ) ) + { + dev->writeLine( "uv_vectors " + o->uvVector( 0 ).serialize( ) + + " " + o->uvVector( 1 ).serialize( ) + + " " + o->uvVector( 2 ).serialize( ) ); + } + + dev->callSerialization( object, metaObject->superClass( ) ); + dev->objectEnd( ); +} diff --git a/kpovmodeler/pmpovray35serialization.h b/kpovmodeler/pmpovray35serialization.h new file mode 100644 index 00000000..4e511d55 --- /dev/null +++ b/kpovmodeler/pmpovray35serialization.h @@ -0,0 +1,49 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMPOVRAY35_SERIALIZATION_H +#define PMPOVRAY35_SERIALIZATION_H + +class PMObject; +class PMMetaObject; +class PMOutputDevice; + +// serialization methods for POV-Ray 3.5 + +void PMPov35SerIsoSurface( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerLight( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerProjectedThrough( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerGlobalSettings( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerRadiosity( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerGlobalPhotons( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerPhotons( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerInterior( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerLightGroup( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerPattern( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerNormal( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerInteriorTexture( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerWarp( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerSphereSweep( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerFinish( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerMesh( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerMedia( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerGraphicalObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerPigment( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerTexture( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerBicubicPatch( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +void PMPov35SerTriangle( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev ); +#endif diff --git a/kpovmodeler/pmpovrayformat.cpp b/kpovmodeler/pmpovrayformat.cpp new file mode 100644 index 00000000..a2c48c80 --- /dev/null +++ b/kpovmodeler/pmpovrayformat.cpp @@ -0,0 +1,52 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmpovrayformat.h" +#include "pmdebug.h" + +PMPovrayFormat::PMPovrayFormat( ) +{ + m_methodDict.setAutoDelete( true ); +} + + +PMPovrayFormat::~PMPovrayFormat( ) +{ + +} + +void PMPovrayFormat::registerMethod( const QString& className, + PMPovraySerializeMethod method ) +{ + PMPovraySerializeMethodInfo* info = m_methodDict.find( className ); + if( info ) + kdWarning( PMArea ) << "Serialization method for " << className + << " shadows old implementation" << endl; + info = new PMPovraySerializeMethodInfo( method ); + m_methodDict.insert( className, info ); +} + +void PMPovrayFormat::removeMethod( const QString& className ) +{ + m_methodDict.remove( className ); +} + +const PMPovraySerializeMethodInfo* PMPovrayFormat::serializationMethod( + const QString& className ) +{ + return m_methodDict.find( className ); +} diff --git a/kpovmodeler/pmpovrayformat.h b/kpovmodeler/pmpovrayformat.h new file mode 100644 index 00000000..398cae42 --- /dev/null +++ b/kpovmodeler/pmpovrayformat.h @@ -0,0 +1,94 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMPOVRAY_FORMAT_H +#define PMPOVRAY_FORMAT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmiomanager.h" +#include "pmoutputdevice.h" + +typedef void ( *PMPovraySerializeMethod ) ( const PMObject*, const PMMetaObject*, + PMOutputDevice* ); +/** + * Helper class for @ref PMOutputDevice and @ref PMPovrayFormatBase + */ +class PMPovraySerializeMethodInfo +{ +public: + PMPovraySerializeMethodInfo( ) + { + m_method = 0; + } + PMPovraySerializeMethodInfo( PMPovraySerializeMethod m ) + { + m_method = m; + } + PMPovraySerializeMethod method( ) const { return m_method; } + void call( const PMObject* o, const PMMetaObject* mo, PMOutputDevice* ser ) const + { + if( m_method ) + m_method( o, mo, ser ); + } +private: + PMPovraySerializeMethod m_method; +}; + +/** + * Base class for all POV-Ray formats which use a PMOutputDevice + * for serialization. + * + * Plugins can register new serialization methods with @ref registerMethod + */ +class PMPovrayFormat : public PMIOFormat +{ +public: + /** + * Default constructor + */ + PMPovrayFormat( ); + /** + * Destructor + */ + virtual ~PMPovrayFormat( ); + + /** + * Registers the serialization method for the class className + */ + void registerMethod( const QString& className, PMPovraySerializeMethod method ); + /** + * Removes a registered serialization method + */ + void removeMethod( const QString& className ); + /** + * Returns the serialization methods info for the given object type + * or 0 if there is none. + */ + const PMPovraySerializeMethodInfo* serializationMethod( + const QString& className ); + +private: + /** + * Dict class name -> serialization method + */ + QDict m_methodDict; +}; + +#endif diff --git a/kpovmodeler/pmpovraymatrix.cpp b/kpovmodeler/pmpovraymatrix.cpp new file mode 100644 index 00000000..4100d46a --- /dev/null +++ b/kpovmodeler/pmpovraymatrix.cpp @@ -0,0 +1,152 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmpovraymatrix.h" +#include "pmpovraymatrixedit.h" + +#include "pmxmlhelper.h" +#include "pmmemento.h" + +#include + +PMDefinePropertyClass( PMPovrayMatrix, PMPovrayMatrixProperty ); + +PMMetaObject* PMPovrayMatrix::s_pMetaObject = 0; +PMObject* createNewPovrayMatrix( PMPart* part ) +{ + return new PMPovrayMatrix( part ); +} + +PMPovrayMatrix::PMPovrayMatrix( PMPart* part ) + : Base( part ) +{ + m_values = PMVector( 12 ); + m_values[0] = 1.0; + m_values[4] = 1.0; + m_values[8] = 1.0; +} + +PMPovrayMatrix::PMPovrayMatrix( const PMPovrayMatrix& m ) + : Base( m ) +{ + m_values = m.m_values; +} + +PMPovrayMatrix::~PMPovrayMatrix( ) +{ +} + +QString PMPovrayMatrix::description( ) const +{ + return i18n( "matrix" ); +} + +void PMPovrayMatrix::serialize( QDomElement& e, QDomDocument& /*doc*/ ) const +{ + e.setAttribute( "value", m_values.serializeXML( ) ); +} + +void PMPovrayMatrix::readAttributes( const PMXMLHelper& h ) +{ + PMVector d = PMVector( 12 ); + d[0] = 1.0; + d[4] = 1.0; + d[8] = 1.0; + + m_values = h.vectorAttribute( "value", d ); + m_values.resize( 12 ); +} + +PMMetaObject* PMPovrayMatrix::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "PovrayMatrix", Base::metaObject( ), + createNewPovrayMatrix ); + s_pMetaObject->addProperty( + new PMPovrayMatrixProperty( "values", &PMPovrayMatrix::setValues, &PMPovrayMatrix::values ) ); + } + return s_pMetaObject; +} + +void PMPovrayMatrix::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMPovrayMatrix::setValues( const PMVector& v ) +{ + if( v != m_values ) + { + if( m_pMemento ) + { + m_pMemento->addData( s_pMetaObject, PMMatrixID, m_values ); + m_pMemento->setViewStructureChanged( ); + } + m_values = v; + m_values.resize( 12 ); + } +} + +PMDialogEditBase* PMPovrayMatrix::editWidget( QWidget* parent ) const +{ + return new PMPovrayMatrixEdit( parent ); +} + +void PMPovrayMatrix::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMMatrixID: + setValues( data->vectorData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMPovrayMatrix::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + +PMMatrix PMPovrayMatrix::transformationMatrix( ) const +{ + PMMatrix m; + int l, c; + + for( l = 0; l < 4; l++ ) + for( c = 0; c < 3; c++ ) + m[l][c] = m_values[l*3+c]; + m[3][3] = 1.0; + + return m; +} + diff --git a/kpovmodeler/pmpovraymatrix.h b/kpovmodeler/pmpovraymatrix.h new file mode 100644 index 00000000..25a1e03b --- /dev/null +++ b/kpovmodeler/pmpovraymatrix.h @@ -0,0 +1,97 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMPOVRAYMATRIX_H +#define PMPOVRAYMATRIX_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmobject.h" + +/** + * Class for povray matrix transformations. + */ + +class PMPovrayMatrix : public PMObject +{ + typedef PMObject Base; +public: + /** + * Creates an identity matrix + */ + PMPovrayMatrix( PMPart* part ); + /** + * Copy constructor + */ + PMPovrayMatrix( const PMPovrayMatrix& m ); + /** + * deletes the object + */ + virtual ~PMPovrayMatrix( ); + + /** */ + virtual PMObject* copy( ) const { return new PMPovrayMatrix( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMPovrayMatrixEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pmmatrix" ); } + + /** + * Returns the matrix values. + */ + PMVector values( ) const { return m_values; } + /** + * Sets the matrix values. Has to be a vector with size 12. + */ + void setValues( const PMVector& v ); + + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual bool hasTransformationMatrix( ) const { return true; } + /** */ + virtual PMMatrix transformationMatrix( ) const; + +private: + /** + * IDs for @ref PMMementoData + */ + enum PMMatrixMementoID { PMMatrixID }; + PMVector m_values; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmpovraymatrixedit.cpp b/kpovmodeler/pmpovraymatrixedit.cpp new file mode 100644 index 00000000..0d78c226 --- /dev/null +++ b/kpovmodeler/pmpovraymatrixedit.cpp @@ -0,0 +1,102 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmpovraymatrixedit.h" +#include "pmpovraymatrix.h" +#include "pmlineedits.h" + +#include +#include +#include + + +PMPovrayMatrixEdit::PMPovrayMatrixEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMPovrayMatrixEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + int i, r, c; + QGridLayout* gl = new QGridLayout( topLayout( ), 4, 4 ); + + for( i = 0; i < 12; i++ ) + { + m_pValue[i] = new PMFloatEdit( this ); + connect( m_pValue[i], SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + } + + for( r = 0; r < 4; r++ ) + for( c = 0; c < 3; c++ ) + gl->addWidget( m_pValue[r*3+c], r, c ); + gl->addWidget( new QLabel( "0.0", this ), 0, 3 ); + gl->addWidget( new QLabel( "0.0", this ), 1, 3 ); + gl->addWidget( new QLabel( "0.0", this ), 2, 3 ); + gl->addWidget( new QLabel( "1.0", this ), 3, 3 ); +} + +void PMPovrayMatrixEdit::displayObject( PMObject* o ) +{ + if( o->isA( "PovrayMatrix" ) ) + { + bool readOnly = o->isReadOnly( ); + int i; + m_pDisplayedObject = ( PMPovrayMatrix* ) o; + PMVector v = m_pDisplayedObject->values( ); + + for( i = 0; i < 12; i++ ) + { + m_pValue[i]->setValue( v[i] ); + m_pValue[i]->setReadOnly( readOnly ); + } + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMPovrayMatrixEdit: Can't display object\n"; +} + +void PMPovrayMatrixEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + PMVector v( 12 ); + int i; + + for( i = 0; i < 12; i++ ) + v[i] = m_pValue[i]->value( ); + m_pDisplayedObject->setValues( v ); + } +} + +bool PMPovrayMatrixEdit::isDataValid( ) +{ + int i; + + for( i = 0; i < 12; i++ ) + if( !m_pValue[i]->isDataValid( ) ) + return false; + + return Base::isDataValid( ); +} + +#include "pmpovraymatrixedit.moc" diff --git a/kpovmodeler/pmpovraymatrixedit.h b/kpovmodeler/pmpovraymatrixedit.h new file mode 100644 index 00000000..2dbd41ae --- /dev/null +++ b/kpovmodeler/pmpovraymatrixedit.h @@ -0,0 +1,62 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMPOVRAYMATRIXEDIT_H +#define PMPOVRAYMATRIXEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMPovrayMatrix; +class PMFloatEdit; + +/** + * Dialog edit class for @ref PMPovrayMatrix + */ +class PMPovrayMatrixEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMPovrayMatrixEdit with parent and name + */ + PMPovrayMatrixEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMPovrayMatrix* m_pDisplayedObject; + PMFloatEdit* m_pValue[12]; +}; + + +#endif diff --git a/kpovmodeler/pmpovrayoutputwidget.cpp b/kpovmodeler/pmpovrayoutputwidget.cpp new file mode 100644 index 00000000..b0d4ca73 --- /dev/null +++ b/kpovmodeler/pmpovrayoutputwidget.cpp @@ -0,0 +1,115 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmpovrayoutputwidget.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include "pmdebug.h" + +QSize PMPovrayOutputWidget::s_size = QSize( 400, 400 ); + +PMPovrayOutputWidget::PMPovrayOutputWidget( QWidget* parent, const char* name ) + : KDialog( parent, name ) +{ + QVBoxLayout* topLayout = new QVBoxLayout( this, KDialog::marginHint( ), KDialog::spacingHint( ) ); + + m_pTextView = new QTextEdit( this ); + topLayout->addWidget( m_pTextView, 1 ); + m_pTextView->setFont( KGlobalSettings::fixedFont( ) ); + m_pTextView->setTextFormat( Qt::PlainText ); + m_pTextView->setReadOnly( true ); + + QHBoxLayout* buttonLayout = new QHBoxLayout( topLayout ); + buttonLayout->addStretch( 1 ); + QPushButton* closeButton = new KPushButton( KStdGuiItem::close(), this ); + buttonLayout->addWidget( closeButton ); + closeButton->setDefault( true ); + connect( closeButton, SIGNAL( clicked( ) ), SLOT( hide( ) ) ); + + setCaption( i18n( "Povray Output" ) ); + resize( s_size ); + + m_startOfLastLine = 0; +} + +PMPovrayOutputWidget::~PMPovrayOutputWidget( ) +{ +} + +void PMPovrayOutputWidget::slotClear( ) +{ + m_output = QString::null; + m_startOfLastLine = 0; + m_pTextView->clear( ); +} + +void PMPovrayOutputWidget::slotText( const QString& output ) +{ + unsigned int i; + + for( i = 0; i < output.length( ); i++ ) + { + QChar c = output[i]; + if( c == '\r' ) + m_output.truncate( m_startOfLastLine ); + else if( c == '\n' ) + { + m_output += c; + m_startOfLastLine = m_output.length( ); + //kdDebug( PMArea ) << m_startOfLastLine << endl; + } + else if( c.isPrint( ) ) + m_output += c; + } + + m_pTextView->setText( m_output ); +} + +void PMPovrayOutputWidget::slotClose( ) +{ + hide( ); +} + + +void PMPovrayOutputWidget::saveConfig( KConfig* cfg ) +{ + cfg->setGroup( "Appearance" ); + cfg->writeEntry( "PovrayOutputWidgetSize", s_size ); +} + +void PMPovrayOutputWidget::restoreConfig( KConfig* cfg ) +{ + cfg->setGroup( "Appearance" ); + + QSize defaultSize( 500, 400 ); + s_size = cfg->readSizeEntry( "PovrayOutputWidgetSize", &defaultSize ); +} + +void PMPovrayOutputWidget::resizeEvent( QResizeEvent* ev ) +{ + s_size = ev->size( ); +} + +#include "pmpovrayoutputwidget.moc" diff --git a/kpovmodeler/pmpovrayoutputwidget.h b/kpovmodeler/pmpovrayoutputwidget.h new file mode 100644 index 00000000..faac7352 --- /dev/null +++ b/kpovmodeler/pmpovrayoutputwidget.h @@ -0,0 +1,77 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMPOVRAYOUTPUTWIDGET_H +#define PMPOVRAYOUTPUTWIDGET_H + +#ifdef HAVE_CONFIG_H +#include +#endif + + +#include +class QTextEdit; +class KConfig; + +/** + * Widget to display the povray text output + */ +class PMPovrayOutputWidget : public KDialog +{ + Q_OBJECT +public: + /** + * Standard constructor + */ + PMPovrayOutputWidget( QWidget* parent = 0, const char* name = 0 ); + /** + * Destructor + */ + ~PMPovrayOutputWidget( ); + + static void saveConfig( KConfig* cfg ); + static void restoreConfig( KConfig* cfg ); + +public slots: + /** + * Clears the text + */ + void slotClear( ); + /** + * Adds the text to the output + */ + void slotText( const QString& output ); + +protected slots: + /** + * Called when the close button is clicked + */ + void slotClose( ); + +protected: + virtual void resizeEvent( QResizeEvent* ev ); + +private: + QTextEdit* m_pTextView; + int m_startOfLastLine; + QString m_output; + static QSize s_size; +}; + + +#endif diff --git a/kpovmodeler/pmpovrayparser.cpp b/kpovmodeler/pmpovrayparser.cpp new file mode 100644 index 00000000..88bd8393 --- /dev/null +++ b/kpovmodeler/pmpovrayparser.cpp @@ -0,0 +1,7213 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmpovrayparser.h" + +#include +#include + +#include "pmpart.h" +#include "pmscanner.h" +#include "pmtokens.h" + +#include "pmcolor.h" +#include "pmallobjects.h" +#include "pmprototypemanager.h" +#include "pmxmlhelper.h" + + +PMPovrayParser::PMPovrayParser( PMPart* part, QIODevice* dev ) + : PMParser( part, dev ) +{ + init( ); +} + +PMPovrayParser::PMPovrayParser( PMPart* part, const QByteArray& array ) + : PMParser( part, array ) +{ + init( ); +} + +PMPovrayParser::~PMPovrayParser( ) +{ + if( m_pScanner ) + delete m_pScanner; +} + +void PMPovrayParser::init( ) +{ + m_pScanner = new PMScanner( m_pDevice ); + m_consumedTokens = 0; + m_skippedComments.setAutoDelete( true ); + m_bLastPMCommentEmpty = true; +} + + +void PMPovrayParser::nextToken( ) +{ + m_token = m_pScanner->nextToken( ); + m_consumedTokens++; + setCurrentLine( m_pScanner->currentLine( ) ); + + if( ( m_token == SCANNER_ERROR_TOK ) || ( m_token == COMMENT_TOK ) + || ( m_token == LINE_COMMENT_TOK ) || ( m_token == PMNAME_TOK ) ) + { + // create the objects (string) only if necessary + PMComment* c; + int lastCommentLine = -2; + QString commentText; + + while( ( m_token == SCANNER_ERROR_TOK ) || ( m_token == COMMENT_TOK ) + || ( m_token == LINE_COMMENT_TOK ) || ( m_token == PMNAME_TOK ) ) + { + switch( m_token ) + { + case SCANNER_ERROR_TOK: + printError( m_pScanner->error( ) ); + lastCommentLine = -2; + break; + case LINE_COMMENT_TOK: + commentText = m_pScanner->sValue( ); + if( lastCommentLine == ( m_pScanner->currentLine( ) - 1 ) ) + { + c = m_skippedComments.last( ); + if( c ) + c->setText( c->text( ) + '\n' + commentText ); + else + { + c = new PMComment( m_pPart, commentText ); + m_skippedComments.append( c ); + } + } + else + { + c = new PMComment( m_pPart, m_pScanner->sValue( ) ); + m_skippedComments.append( c ); + } + lastCommentLine = m_pScanner->currentLine( ); + break; + case COMMENT_TOK: + c = new PMComment( m_pPart, m_pScanner->sValue( ) ); + m_skippedComments.append( c ); + lastCommentLine = -2; + break; + case PMNAME_TOK: + // Special comment + m_lastPMComment = m_pScanner->sValue( ); + m_bLastPMCommentEmpty = false; + lastCommentLine = -2; + break; + default: + lastCommentLine = -2; + break; + } + + m_token = m_pScanner->nextToken( ); + m_consumedTokens++; + } + } +} + +bool PMPovrayParser::isTrue( ) const +{ + if( ( m_token == ON_TOK ) || ( m_token == TRUE_TOK ) || ( m_token == YES_TOK ) ) + return true; + return false; +} + +bool PMPovrayParser::isFalse( ) const +{ + if( ( m_token == OFF_TOK ) || ( m_token == FALSE_TOK ) || ( m_token == NO_TOK ) ) + return true; + return false; +} + +void PMPovrayParser::topParse( ) +{ + nextToken( ); + + do + { + if( !parseChildObjects( 0 ) ) + m_token = EOF_TOK; + if( m_token != EOF_TOK ) + { + printUnexpected( m_pScanner->sValue( ) ); + nextToken( ); + } + } + while( m_token != EOF_TOK ); + + if( errors( ) || warnings( ) ) + printMessage( PMMSpecialRawComment ); +} + +bool PMPovrayParser::parseBool( ) +{ + if( isFalse( ) ) + { + nextToken( ); + return false; + } + if( isTrue( ) ) + { + nextToken( ); + return true; + } + + PMValue v; + + if( parseNumericExpression( v, true ) ) + { + switch( v.type( ) ) + { + case PMVFloat: + return v.floatValue( ) > 0.0; + break; + case PMVVector: + return ( v.vector( ) )[0] > 0.0; + break; + default: + printError( i18n( "Boolean expression expected" ) ); + break; + } + } + + return true; +} + +bool PMPovrayParser::parseChildObjects( PMCompositeObject* parent, + int max /* = -1 */ ) +{ + PMObject* child = 0; + bool finished = false; + bool error = false; + bool noChild = false; + int numParsed = 0; + + do + { + if( !m_bLastPMCommentEmpty && parent ) + { + if( parent->isA( "NamedObject" ) ) + ( ( PMNamedObject* ) parent )->setName( m_lastPMComment ); + m_bLastPMCommentEmpty = true; + } + if( m_skippedComments.count( ) > 0 ) + child = m_skippedComments.take( 0 ); + else + { + child = 0; + noChild = false; + + // some objects + switch( m_token ) + { + case UNION_TOK: + case DIFFERENCE_TOK: + case INTERSECTION_TOK: + case MERGE_TOK: + child = new PMCSG( m_pPart ); + error = !parseCSG( ( PMCSG* ) child ); + break; + case BOX_TOK: + child = new PMBox( m_pPart ); + error = !parseBox( ( PMBox* ) child ); + break; + case SPHERE_TOK: + if( ( parent && ( parent->type( ) == "Blob" ) ) + || ( !parent && m_pTopParent + && ( m_pTopParent->type( ) == "Blob" ) ) ) + { + child = new PMBlobSphere( m_pPart ); + error = !parseBlobSphere( ( PMBlobSphere* ) child ); + } + else + { + child = new PMSphere( m_pPart ); + error = !parseSphere( ( PMSphere* ) child ); + } + break; + case CYLINDER_TOK: + if( ( parent && ( parent->type( ) == "Blob" ) ) + || ( !parent && m_pTopParent + && ( m_pTopParent->type( ) == "Blob" ) ) ) + { + child = new PMBlobCylinder( m_pPart ); + error = !parseBlobCylinder( ( PMBlobCylinder* ) child ); + } + else + { + child = new PMCylinder( m_pPart ); + error = !parseCylinder( ( PMCylinder* ) child ); + } + break; + case CONE_TOK: + child = new PMCone( m_pPart ); + error = !parseCone( ( PMCone* ) child ); + break; + case TORUS_TOK: + child = new PMTorus( m_pPart ); + error = !parseTorus( ( PMTorus* ) child ); + break; + case BLOB_TOK: + child = new PMBlob( m_pPart ); + error = !parseBlob( ( PMBlob* ) child ); + break; + case COMPONENT_TOK: + child = new PMBlobSphere( m_pPart ); + error = !parseBlobComponent( ( PMBlobSphere* ) child ); + break; + case HEIGHT_FIELD_TOK: + child = new PMHeightField( m_pPart ); + error = !parseHeightField( ( PMHeightField* ) child ); + break; + case TEXT_TOK: + child = new PMText( m_pPart ); + error = !parseText( ( PMText* ) child ); + break; + case JULIA_FRACTAL_TOK: + child = new PMJuliaFractal( m_pPart ); + error = !parseJuliaFractal( ( PMJuliaFractal* ) child ); + break; + case PLANE_TOK: + child = new PMPlane( m_pPart ); + error = !parsePlane( ( PMPlane* ) child ); + break; + case QUADRIC_TOK: + case CUBIC_TOK: + case QUARTIC_TOK: + case POLY_TOK: + child = new PMPolynom( m_pPart ); + error = !parsePolynom( ( PMPolynom* ) child ); + break; + case BICUBIC_PATCH_TOK: + child = new PMBicubicPatch( m_pPart ); + error = !parseBicubicPatch( ( PMBicubicPatch* ) child ); + break; + case DISC_TOK: + child = new PMDisc( m_pPart ); + error = !parseDisc( ( PMDisc* ) child ); + break; + case TRIANGLE_TOK: + case SMOOTH_TRIANGLE_TOK: + child = new PMTriangle( m_pPart ); + error = !parseTriangle( ( PMTriangle* ) child ); + break; + case LATHE_TOK: + child = new PMLathe( m_pPart ); + error = !parseLathe( ( PMLathe* ) child ); + break; + case PRISM_TOK: + child = new PMPrism( m_pPart ); + error = !parsePrism( ( PMPrism* ) child ); + break; + case SOR_TOK: + child = new PMSurfaceOfRevolution( m_pPart ); + error = !parseSor( ( PMSurfaceOfRevolution* ) child ); + break; + case SUPERELLIPSOID_TOK: + child = new PMSuperquadricEllipsoid( m_pPart ); + error = !parseSqe( ( PMSuperquadricEllipsoid* ) child ); + break; + case CAMERA_TOK: + child = new PMCamera( m_pPart ); + error = !parseCamera( ( PMCamera* ) child ); + break; + case LIGHT_SOURCE_TOK: + child = new PMLight( m_pPart ); + error = !parseLight( ( PMLight* ) child ); + break; + case LOOKS_LIKE_TOK: + child = new PMLooksLike( m_pPart ); + error = !parseLooksLike( ( PMLooksLike* ) child ); + break; + case PROJECTED_THROUGH_TOK: + child = new PMProjectedThrough( m_pPart ); + error = !parseProjectedThrough( ( PMProjectedThrough* ) child ); + break; + case TEXTURE_TOK: + child = new PMTexture( m_pPart ); + error = !parseTexture( ( PMTexture* ) child ); + break; + case AGATE_TOK: + case AVERAGE_TOK: + case BOXED_TOK: + case BOZO_TOK: + case BUMPS_TOK: + case CELLS_TOK: + case CRACKLE_TOK: + case CYLINDRICAL_TOK: + case DENTS_TOK: + case DENSITY_FILE_TOK: + case GRADIENT_TOK: + case GRANITE_TOK: + case JULIA_TOK: + case LEOPARD_TOK: + case MAGNET_TOK: + case MANDEL_TOK: + case MARBLE_TOK: + case ONION_TOK: + case PLANAR_TOK: + case QUILTED_TOK: + case RADIAL_TOK: + case RIPPLES_TOK: + case SLOPE_TOK: + case SPHERICAL_TOK: + case SPIRAL1_TOK: + case SPIRAL2_TOK: + case SPOTTED_TOK: + case WOOD_TOK: + case WAVES_TOK: + case WRINKLES_TOK: + child = new PMPattern( m_pPart ); + { + bool normal = true; + if( parent && ( parent->type( ) != "Normal" ) ) + normal = false; + error = !parsePattern( ( PMPattern* ) child, normal ); + } + break; + case TURBULENCE_TOK: + // Search for a PMPattern in the object's children + child = parent->firstChild( ); + while( child && !child->isA( "Pattern" ) ) + child = child->nextSibling( ); + if( child ) + { + error = !parsePattern( ( PMPattern* ) child ); + child = 0; + noChild = true; + } + else + { + printError( i18n( "Found turbulence without a pattern." ) ); + error = true; + } + break; + case FREQUENCY_TOK: + case PHASE_TOK: + case RAMP_WAVE_TOK: + case TRIANGLE_WAVE_TOK: + case SINE_WAVE_TOK: + case SCALLOP_WAVE_TOK: + case CUBIC_WAVE_TOK: + case POLY_WAVE_TOK: + // Search for a PMBlendMapModifiers in the object's children + child = parent->firstChild( ); + while( child && !child->isA( "BlendMapModifiers" ) ) + child = child->nextSibling( ); + if( child ) + { + error = !parseBlendMapModifiers( ( PMBlendMapModifiers* ) child ); + child = 0; + noChild = 0; + } + else + { + child = new PMBlendMapModifiers( m_pPart ); + error = !parseBlendMapModifiers( ( PMBlendMapModifiers* ) child ); + } + break; + case WARP_TOK: + child = new PMWarp( m_pPart ); + error = !parseWarp( ( PMWarp* ) child ); + break; + case PIGMENT_TOK: + child = new PMPigment( m_pPart ); + error = !parsePigment( ( PMPigment* ) child ); + break; + case NORMAL_TOK: + child = new PMNormal( m_pPart ); + error = !parseNormal( ( PMNormal* ) child ); + break; + case NORMAL_MAP_TOK: + child = new PMNormalMap( m_pPart ); + error = !parseNormalMap( ( PMNormalMap* ) child ); + break; + case BUMP_MAP_TOK: + child = new PMBumpMap( m_pPart ); + error = !parseBumpMap( ( PMBumpMap* ) child ); + break; + case SLOPE_MAP_TOK: + child = new PMSlopeMap( m_pPart ); + error = !parseSlopeMap( ( PMSlopeMap* ) child ); + break; + case DENSITY_MAP_TOK: + child = new PMDensityMap( m_pPart ); + error = !parseDensityMap( ( PMDensityMap* ) child ); + break; + case TEXTURE_MAP_TOK: + child = new PMTextureMap( m_pPart ); + error = !parseTextureMap( ( PMTextureMap* ) child ); + break; + case MATERIAL_MAP_TOK: + child = new PMMaterialMap( m_pPart ); + error = !parseMaterialMap( ( PMMaterialMap* ) child ); + break; + case PIGMENT_MAP_TOK: + child = new PMPigmentMap( m_pPart ); + error = !parsePigmentMap( ( PMPigmentMap* ) child ); + break; + case COLOR_MAP_TOK: + case COLOUR_MAP_TOK: + child = new PMColorMap( m_pPart ); + error = !parseColorMap( ( PMColorMap* ) child ); + break; + case CHECKER_TOK: + case HEXAGON_TOK: + case BRICK_TOK: + { + bool normal = false; + double depth = 0.0; + int expect = 0; + PMListPattern::PMListType type = PMListPattern::ListPatternChecker; + + if( parent && parent->type( ) == "Normal" ) + normal = true; + else if( m_pTopParent && m_pTopParent->type( ) == "Normal" ) + normal = true; + + switch( m_token ) + { + case CHECKER_TOK: + type = PMListPattern::ListPatternChecker; + expect = 2; + break; + case HEXAGON_TOK: + type = PMListPattern::ListPatternHexagon; + expect = 3; + break; + case BRICK_TOK: + type = PMListPattern::ListPatternBrick; + expect = 2; + break; + } + nextToken( ); + + if( normal ) + { + child = new PMNormalList( m_pPart ); + if( parseFloat( depth, true ) ) + ( ( PMNormalList* ) child )->setDepth( depth ); + + if( m_token == NORMAL_TOK ) + error = !parseNormalList( ( PMNormalList* ) child, expect ); + } + else + { + switch( m_token ) + { + case COLOR_TOK: + case COLOUR_TOK: + case RGB_TOK: + case RGBT_TOK: + case RGBF_TOK: + case RGBFT_TOK: + case RED_TOK: + case GREEN_TOK: + case BLUE_TOK: + case TRANSMIT_TOK: + case FILTER_TOK: + case ID_TOK: + child = new PMColorList( m_pPart ); + error = !parseColorList( ( PMColorList* ) child, expect ); + break; + case PIGMENT_TOK: + child = new PMPigmentList( m_pPart ); + error = !parsePigmentList( ( PMPigmentList* ) child, expect ); + break; + case TEXTURE_TOK: + child = new PMTextureList( m_pPart ); + error = !parseTextureList( ( PMTextureList* ) child, expect ); + break; + case NORMAL_TOK: + child = new PMNormalList( m_pPart ); + error = !parseNormalList( ( PMNormalList* ) child, expect ); + break; + case DENSITY_TOK: + child = new PMDensityList( m_pPart ); + error = !parseDensityList( ( PMDensityList* ) child, expect ); + break; + default: + printError( i18n( "Invalid list member." ) ); + error = true; + } + } + + if( child ) + { + ( ( PMListPattern* ) child )->setListType( type ); + + int oldConsumed; + double num = 0; + PMVector vector; + + do + { + oldConsumed = m_consumedTokens; + switch( m_token ) + { + case MORTAR_TOK: + nextToken( ); + if( !parseFloat( num ) ) + return false; + ( ( PMListPattern* ) child )->setMortar( num ); + break; + case BRICK_SIZE_TOK: + nextToken( ); + if( !parseVector( vector ) ) + return false; + ( ( PMListPattern* ) child )->setBrickSize( vector ); + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + } + break; + } + case IMAGE_MAP_TOK: + child = new PMImageMap( m_pPart ); + error = !parseImageMap( ( PMImageMap* ) child ); + break; + case FINISH_TOK: + child = new PMFinish( m_pPart ); + error = !parseFinish( ( PMFinish* ) child ); + break; + case INTERIOR_TOK: + child = new PMInterior( m_pPart ); + error = !parseInterior( ( PMInterior* ) child ); + break; + case MEDIA_TOK: + child = new PMMedia( m_pPart ); + error = !parseMedia( ( PMMedia* ) child ); + break; + case DENSITY_TOK: + child = new PMDensity( m_pPart ); + error = !parseDensity( ( PMDensity* ) child ); + break; + case MATERIAL_TOK: + child = new PMMaterial( m_pPart ); + error = !parseMaterial( ( PMMaterial* ) child ); + break; + case SKY_SPHERE_TOK: + child = new PMSkySphere( m_pPart ); + error = !parseSkySphere( ( PMSkySphere* ) child ); + break; + case RAINBOW_TOK: + child = new PMRainbow( m_pPart ); + error = !parseRainbow( ( PMRainbow* ) child ); + break; + case FOG_TOK: + child = new PMFog( m_pPart ); + error = !parseFog( ( PMFog* ) child ); + break; + case GLOBAL_SETTINGS_TOK: + child = new PMGlobalSettings( m_pPart ); + error = !parseGlobalSettings( ( PMGlobalSettings* ) child ); + break; + case SCALE_TOK: + child = new PMScale( m_pPart ); + error = !parseScale( ( PMScale* ) child ); + break; + case ROTATE_TOK: + child = new PMRotate( m_pPart ); + error = !parseRotate( ( PMRotate* ) child ); + break; + case TRANSLATE_TOK: + child = new PMTranslate( m_pPart ); + error = !parseTranslate( ( PMTranslate* ) child ); + break; + case MATRIX_TOK: + child = new PMPovrayMatrix( m_pPart ); + error = !parseMatrix( ( PMPovrayMatrix* ) child ); + break; + case BOUNDED_BY_TOK: + if( parent && ( parent->type( ) == "ClippedBy" ) ) + finished = true; + else + { + child = new PMBoundedBy( m_pPart ); + error = !parseBoundedBy( ( PMBoundedBy* ) child ); + } + break; + case CLIPPED_BY_TOK: + if( parent && ( parent->type( ) == "BoundedBy" ) ) + finished = true; + else + { + child = new PMClippedBy( m_pPart ); + error = !parseClippedBy( ( PMClippedBy* ) child ); + } + break; + case ISOSURFACE_TOK: + child = new PMIsoSurface( m_pPart ); + error = !parseIsoSurface( ( PMIsoSurface* ) child ); + break; + case RADIOSITY_TOK: + child = new PMRadiosity( m_pPart ); + error = !parseRadiosity( ( PMRadiosity* ) child ); + break; + case PHOTONS_TOK: + if ( parent && ( parent->type( ) == "GlobalSettings" ) ) + { + child = new PMGlobalPhotons( m_pPart ); + error = !parseGlobalPhotons( ( PMGlobalPhotons* ) child ); + } + else + { + child = new PMPhotons( m_pPart ); + error =!parsePhotons( ( PMPhotons* ) child ); + } + break; + case LIGHT_GROUP_TOK: + child = new PMLightGroup( m_pPart ); + error = !parseLightGroup( ( PMLightGroup* ) child ); + break; + case INTERIOR_TEXTURE_TOK: + child = new PMInteriorTexture( m_pPart ); + error = !parseInteriorTexture( ( PMInteriorTexture* ) child ); + break; + case SPHERE_SWEEP_TOK: + child = new PMSphereSweep( m_pPart ); + error = !parseSphereSweep( ( PMSphereSweep* ) child ); + break; + case MESH_TOK: + child = new PMMesh( m_pPart ); + error = !parseMesh( ( PMMesh* ) child ); + break; + case DECLARE_TOK: + nextToken( ); + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + nextToken( ); + + if( !parseToken( '=' ) ) + error = true; + else + { + PMValue v; + switch( m_token ) + { + case OBJECT_TOK: + // finite solid + case BLOB_TOK: + case BOX_TOK: + case CONE_TOK: + case CYLINDER_TOK: + case HEIGHT_FIELD_TOK: + case JULIA_FRACTAL_TOK: + case LATHE_TOK: + case PRISM_TOK: + case SPHERE_TOK: + case SUPERELLIPSOID_TOK: + case SOR_TOK: + case TEXT_TOK: + case TORUS_TOK: + case ISOSURFACE_TOK: + case SPHERE_SWEEP_TOK: + // finite patch + case BICUBIC_PATCH_TOK: + case DISC_TOK: + case MESH_TOK: + case POLYGON_TOK: + case TRIANGLE_TOK: + case SMOOTH_TRIANGLE_TOK: + // infinite solid + case PLANE_TOK: + case QUADRIC_TOK: + case CUBIC_TOK: + case QUARTIC_TOK: + case POLY_TOK: + // csg + case UNION_TOK: + case INTERSECTION_TOK: + case DIFFERENCE_TOK: + case MERGE_TOK: + // textures + case TEXTURE_TOK: + case INTERIOR_TEXTURE_TOK: + case PIGMENT_TOK: + case NORMAL_TOK: + case FINISH_TOK: + case TEXTURE_MAP_TOK: + case PIGMENT_MAP_TOK: + case COLOR_MAP_TOK: + case COLOUR_MAP_TOK: + case NORMAL_MAP_TOK: + case SLOPE_MAP_TOK: + case DENSITY_MAP_TOK: + case INTERIOR_TOK: + case MEDIA_TOK: + case DENSITY_TOK: + case MATERIAL_TOK: + case SKY_SPHERE_TOK: + case RAINBOW_TOK: + case FOG_TOK: + // misc + case LIGHT_SOURCE_TOK: + case LIGHT_GROUP_TOK: + child = new PMDeclare( m_pPart ); + error = !parseDeclare( ( PMDeclare* ) child ); + break; + default: + // constant, vector or color declare? + if( parseNumericExpression( v ) ) + { + checkID( id, v ); + noChild = true; + } + else + error = true; + break; + } + } + + if( child ) + if( child->isA( "Declare" ) ) + ( ( PMDeclare* ) child )->setID( id ); + if( m_token == ';' ) + nextToken( ); + } + else + printExpected( i18n( "identifier" ), m_pScanner->sValue( ) ); + break; + case OBJECT_TOK: + error = !parseObject( parent ); + noChild = true; + break; + case RAW_POVRAY_TOK: + child = new PMRaw( m_pPart, m_pScanner->sValue( ) ); + error = false; + nextToken( ); + break; + default: + finished = true; + break; + } + } + if( !finished && !child && !noChild ) + error = true; + if( child ) + { + if( !insertChild( child, parent ) ) + { + delete child; + child = 0; + } + else if( child->isA( "Declare" ) ) + checkID( ( PMDeclare* ) child ); + numParsed ++; + if( ( max > 0 ) && ( numParsed >= max ) ) + finished = true; + } + } + while( !finished && !error ); + + return finished; +} + +bool PMPovrayParser::parseToken( int t, const QString& tokenName ) +{ + if( t == ',' ) + { + // do not require commas any more. + if( m_token == ',' ) + nextToken( ); + return true; + } + else if( m_token == t ) + { + nextToken( ); + return true; + } + + if( tokenName.isNull() ) + printExpected( ( char ) t, m_pScanner->sValue( ) ); + else + printExpected( tokenName, m_pScanner->sValue( ) ); + return false; +} + +bool PMPovrayParser::parseNumericItem( PMValue& v, bool checkForBool /*=false*/ ) +{ + bool finishColor = false; + PMVector cv( 0 ); + PMVector vec( 0 ); + PMValue hv; + PMSymbol* s; + int i; + + switch( m_token ) + { + case X_TOK: + v.setVector( PMVector( 1.0, 0.0, 0.0 ) ); + nextToken( ); + break; + case Y_TOK: + v.setVector( PMVector( 0.0, 1.0, 0.0 ) ); + nextToken( ); + break; + case Z_TOK: + v.setVector( PMVector( 0.0, 0.0, 1.0 ) ); + nextToken( ); + break; + case T_TOK: + v.setVector( PMVector( 0.0, 0.0, 0.0, 1.0 ) ); + nextToken( ); + break; + case U_TOK: + v.setVector( PMVector( 1.0, 0.0 ) ); + nextToken( ); + break; + case V_TOK: + v.setVector( PMVector( 0.0, 1.0 ) ); + nextToken( ); + break; + case PI_TOK: + v.setFloat( 3.1415926535897932384626 ); + nextToken( ); + break; + case CLOCK_TOK: + printMessage( PMMClockDefault ); + v.setFloat( 0.0 ); + break; + case CLOCK_DELTA_TOK: + printMessage( PMMClockDeltaDefault ); + v.setFloat( 1.0 ); + break; + case FLOAT_TOK: + v.setFloat( m_pScanner->fValue( ) ); + nextToken( ); + break; + case INTEGER_TOK: + v.setFloat( ( double ) m_pScanner->iValue( ) ); + nextToken( ); + break; + case ON_TOK: + case TRUE_TOK: + case YES_TOK: + v.setFloat( 1.0 ); + nextToken( ); + break; + case OFF_TOK: + case FALSE_TOK: + case NO_TOK: + v.setFloat( 0.0 ); + nextToken( ); + break; + case '(': + nextToken( ); + if( !parseNumericExpression( v ) ) + return false; + if( !parseToken( ')' ) ) + return false; + break; + case '-': + nextToken( ); + if( !parseNumericItem( v ) ) + return false; + if( v.type( ) == PMVFloat ) + v.setFloat( -v.floatValue( ) ); + else + v.setVector( -v.vector( ) ); + break; + case '+': + nextToken( ); + if( !parseNumericItem( v ) ) + return false; + break; + case '<': + if( !parseVectorLiteral( vec ) ) + return false; + v.setVector( vec ); + break; + case COLOR_TOK: + case COLOUR_TOK: + nextToken( ); + case RGB_TOK: + case RGBT_TOK: + case RGBF_TOK: + case RGBFT_TOK: + case RED_TOK: + case GREEN_TOK: + case BLUE_TOK: + case TRANSMIT_TOK: + case FILTER_TOK: + cv.resize( 5 ); + cv = 0.0; + finishColor = true; + break; + case ID_TOK: + s = getSymbol( m_pScanner->sValue( ) ); + if( s ) + { + nextToken( ); + if( s->type( ) == PMSymbol::Value ) + v = s->value( ); + else + { + printError( i18n( "Float, color or vector identifier expected." ) ); + return false; + } + } + else + { + printError( i18n( "Undefined identifier \"%1\"." ) + .arg( m_pScanner->sValue( ) ) ); + nextToken( ); + } + break; + default: + if( !checkForBool ) + printUnexpected( m_pScanner->sValue( ) ); + return false; + break; + } + + if( !finishColor ) + { + if( m_token == '.' ) + { + int index = -1; + nextToken( ); + + switch( m_token ) + { + case X_TOK: + case RED_TOK: + case U_TOK: + index = 0; + break; + case Y_TOK: + case GREEN_TOK: + case V_TOK: + index = 1; + break; + case Z_TOK: + case BLUE_TOK: + index = 2; + break; + case T_TOK: + case FILTER_TOK: + index = 3; + break; + case TRANSMIT_TOK: + index = 4; + break; + default: + break; + } + if( index >= 0 ) + { + nextToken( ); + if( v.type( ) == PMVFloat ) + { + if( index != 0 ) + index = -1; + } + else + { + PMVector vec; + if( v.type( ) == PMVVector ) + vec = v.vector( ); + else + vec = v.color( ); + + if( ( ( unsigned ) index ) < vec.size( ) ) + v.setFloat( vec[index] ); + else + index = -1; + } + } + if( index == -1 ) + { + printError( i18n( "Bad operands for period operator." ) ); + return false; + } + } + } + + while( finishColor ) + { + switch( m_token ) + { + case RGB_TOK: + nextToken( ); + if( !parseNumericExpression( hv ) ) + return false; + switch( hv.type( ) ) + { + case PMVFloat: + cv[0] = hv.floatValue( ); + cv[1] = hv.floatValue( ); + cv[2] = hv.floatValue( ); + break; + case PMVVector: + vec = hv.vector( ); + vec.resize( 3 ); + cv[0] = vec[0]; + cv[1] = vec[1]; + cv[2] = vec[2]; + break; + default: + printError( i18n( "Float or vector expression expected" ) ); + break; + } + break; + case RGBT_TOK: + nextToken( ); + if( !parseNumericExpression( hv ) ) + return false; + switch( hv.type( ) ) + { + case PMVFloat: + cv[0] = hv.floatValue( ); + cv[1] = hv.floatValue( ); + cv[2] = hv.floatValue( ); + cv[4] = hv.floatValue( ); + break; + case PMVVector: + vec = hv.vector( ); + vec.resize( 4 ); + cv[0] = vec[0]; + cv[1] = vec[1]; + cv[2] = vec[2]; + cv[4] = vec[3]; + break; + default: + printError( i18n( "Float or vector expression expected" ) ); + break; + } + break; + case RGBF_TOK: + nextToken( ); + if( !parseNumericExpression( hv ) ) + return false; + switch( hv.type( ) ) + { + case PMVFloat: + cv[0] = hv.floatValue( ); + cv[1] = hv.floatValue( ); + cv[2] = hv.floatValue( ); + cv[3] = hv.floatValue( ); + break; + case PMVVector: + vec = hv.vector( ); + vec.resize( 4 ); + cv[0] = vec[0]; + cv[1] = vec[1]; + cv[2] = vec[2]; + cv[3] = vec[3]; + break; + default: + printError( i18n( "Float or vector expression expected" ) ); + break; + } + break; + case RGBFT_TOK: + nextToken( ); + if( !parseNumericExpression( hv ) ) + return false; + switch( hv.type( ) ) + { + case PMVFloat: + cv = hv.floatValue( ); + break; + case PMVVector: + vec = hv.vector( ); + vec.resize( 5 ); + cv = vec; + break; + default: + printError( i18n( "Float or vector expression expected" ) ); + break; + } + break; + case RED_TOK: + nextToken( ); + parseNumericExpression( hv ); + if( hv.type( ) != PMVFloat ) + { + printError( i18n( "Float expression expected" ) ); + break; + } + cv[0] = hv.floatValue( ); + break; + case GREEN_TOK: + nextToken( ); + parseNumericExpression( hv ); + if( hv.type( ) != PMVFloat ) + { + printError( i18n( "Float expression expected" ) ); + break; + } + cv[1] = hv.floatValue( ); + break; + case BLUE_TOK: + nextToken( ); + parseNumericExpression( hv ); + if( hv.type( ) != PMVFloat ) + { + printError( i18n( "Float expression expected" ) ); + break; + } + cv[2] = hv.floatValue( ); + break; + case FILTER_TOK: + case ALPHA_TOK: + nextToken( ); + parseNumericExpression( hv ); + if( hv.type( ) != PMVFloat ) + { + printError( i18n( "Float expression expected" ) ); + break; + } + cv[3] = hv.floatValue( ); + break; + case TRANSMIT_TOK: + nextToken( ); + parseNumericExpression( hv ); + if( hv.type( ) != PMVFloat ) + { + printError( i18n( "Float expression expected" ) ); + break; + } + cv[4] = hv.floatValue( ); + break; + case ID_TOK: + if( parseNumericItem( hv ) ) + { + if( hv.type( ) == PMVFloat ) + { + for( i = 0; i < 5; i++ ) + cv[i] = hv.floatValue( ); + } + else if( hv.type( ) == PMVVector ) + { + cv = hv.vector( ); + cv.resize( 5 ); + } + else + cv = hv.color( ); + } + break; + default: + finishColor = false; + v.setColor( cv ); + break; + } + } + + return true; +} + +bool PMPovrayParser::parseVectorLiteral( PMVector& p ) +{ + PMValue v; + + if( !parseToken( '<' ) ) + return false; + if( !parseNumericExpression( v ) ) + return false; + + if( v.type( ) != PMVFloat ) + { + printError( i18n( "Float expression expected" ) ); + return false; + } + + p.resize( 1 ); + p[0] = v.floatValue( ); + + while( m_token != '>' ) + { + // many old scenes do not use a comma between values + if( m_token == ',' ) + nextToken( ); + // parseToken( ',' ); + if( !parseNumericExpression( v ) ) + return false; + + if( v.type( ) != PMVFloat ) + { + printError( i18n( "Float expression expected" ) ); + return false; + } + + p.resize( p.size( ) + 1 ); + p[p.size( ) - 1] = v.floatValue( ); + } + + /** old code + while( m_token == ',' ) + { + nextToken( ); + if( !parseNumericExpression( v ) ) + return false; + + if( v.type( ) != PMVFloat ) + { + printError( i18n( "Float expression expected" ) ); + return false; + } + + p.resize( p.size( ) + 1 ); + p[p.size( ) - 1] = v.floatValue( ); + } + */ + + if( !parseToken( '>' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseNumericExpression( PMValue& v, bool checkForBool /*=false*/ ) +{ + bool end = false; + PMValue v2; + PMVector hv( 0 ); + + if( !parseNumericItem( v, checkForBool ) ) + return false; + + do + { + switch( m_token ) + { + case '*': + nextToken( ); + if( !parseNumericItem( v2 ) ) + break; + switch( v.type( ) ) + { + case PMVFloat: + switch( v2.type( ) ) + { + case PMVFloat: + v.setFloat( v.floatValue( ) * v2.floatValue( ) ); + break; + case PMVVector: + v.setVector( v2.vector( ) * v.floatValue( ) ); + break; + case PMVColor: + v.setColor( v2.color( ) * v.floatValue( ) ); + break; + } + break; + case PMVVector: + switch( v2.type( ) ) + { + case PMVFloat: + v.setVector( v.vector( ) * v2.floatValue( ) ); + break; + case PMVVector: + v.setVector( v.vector( ) * v2.vector( ) ); + break; + case PMVColor: + if( v.vector( ).size( ) == 5 ) + v.setColor( v.vector( ) * v2.color( ) ); + else + printError( i18n( "You can't multiply a vector with a color" ) ); + break; + } + break; + case PMVColor: + switch( v2.type( ) ) + { + case PMVFloat: + v.setColor( v.color( ) * v2.floatValue( ) ); + break; + case PMVVector: + if( v2.vector( ).size( ) == 5 ) + v.setColor( v2.vector( ) * v.color( ) ); + else + printError( i18n( "You can't multiply a vector with a color" ) ); + break; + case PMVColor: + v.setColor( v.color( ) * v2.color( ) ); + break; + } + break; + } + break; + case '/': + nextToken( ); + if( !parseNumericItem( v2 ) ) + break; + switch( v.type( ) ) + { + case PMVFloat: + switch( v2.type( ) ) + { + case PMVFloat: + v.setFloat( v.floatValue( ) / v2.floatValue( ) ); + break; + case PMVVector: + hv.resize( v2.vector( ).size( ) ); + hv = v.floatValue( ); + v.setVector( hv / v2.vector( ) ); + break; + case PMVColor: + hv.resize( 5 ); + hv = v.floatValue( ); + v.setColor( hv / v.floatValue( ) ); + break; + } + break; + case PMVVector: + switch( v2.type( ) ) + { + case PMVFloat: + v.setVector( v.vector( ) / v2.floatValue( ) ); + break; + case PMVVector: + v.setVector( v.vector( ) / v2.vector( ) ); + break; + case PMVColor: + if( v.vector( ).size( ) == 5 ) + v.setColor( v.vector( ) / v2.color( ) ); + else + printError( i18n( "You can't divide a vector by a color" ) ); + break; + } + break; + case PMVColor: + switch( v2.type( ) ) + { + case PMVFloat: + v.setColor( v.color( ) / v2.floatValue( ) ); + break; + case PMVVector: + if( v2.vector( ).size( ) == 5 ) + v.setColor( v2.vector( ) / v.color( ) ); + else + printError( i18n( "You can't divide a color by a vector" ) ); + break; + case PMVColor: + v.setColor( v.color( ) / v2.color( ) ); + break; + } + break; + } + break; + case '+': + nextToken( ); + if( !parseNumericExpression( v2 ) ) + break; + switch( v.type( ) ) + { + case PMVFloat: + switch( v2.type( ) ) + { + case PMVFloat: + v.setFloat( v.floatValue( ) + v2.floatValue( ) ); + break; + case PMVVector: + v.setVector( v2.vector( ) + v.floatValue( ) ); + break; + case PMVColor: + v.setColor( v2.color( ) + v.floatValue( ) ); + break; + } + break; + case PMVVector: + switch( v2.type( ) ) + { + case PMVFloat: + v.setVector( v.vector( ) + v2.floatValue( ) ); + break; + case PMVVector: + v.setVector( v.vector( ) + v2.vector( ) ); + break; + case PMVColor: + if( v.vector( ).size( ) == 5 ) + v.setColor( v.vector( ) + v2.color( ) ); + else + printError( i18n( "You can't add a vector and a color" ) ); + break; + } + break; + case PMVColor: + switch( v2.type( ) ) + { + case PMVFloat: + v.setColor( v.color( ) + v2.floatValue( ) ); + break; + case PMVVector: + if( v2.vector( ).size( ) == 5 ) + v.setColor( v2.vector( ) + v.color( ) ); + else + printError( i18n( "You can't add a vector with a color" ) ); + break; + case PMVColor: + v.setColor( v.color( ) + v2.color( ) ); + break; + } + break; + } + break; + case '-': + nextToken( ); + if( !parseNumericExpression( v2 ) ) + break; + switch( v.type( ) ) + { + case PMVFloat: + switch( v2.type( ) ) + { + case PMVFloat: + v.setFloat( v.floatValue( ) - v2.floatValue( ) ); + break; + case PMVVector: + v.setVector( v2.vector( ) - v.floatValue( ) ); + break; + case PMVColor: + v.setColor( v2.color( ) - v.floatValue( ) ); + break; + } + break; + case PMVVector: + switch( v2.type( ) ) + { + case PMVFloat: + v.setVector( v.vector( ) - v2.floatValue( ) ); + break; + case PMVVector: + v.setVector( v.vector( ) - v2.vector( ) ); + break; + case PMVColor: + if( v.vector( ).size( ) == 5 ) + v.setColor( v.vector( ) - v2.color( ) ); + else + printError( i18n( "You can't subtract a vector and a color" ) ); + break; + } + break; + case PMVColor: + switch( v2.type( ) ) + { + case PMVFloat: + v.setColor( v.color( ) - v2.floatValue( ) ); + break; + case PMVVector: + if( v2.vector( ).size( ) == 5 ) + v.setColor( v2.vector( ) - v.color( ) ); + else + printError( i18n( "You can't subtract a vector and a color" ) ); + break; + case PMVColor: + v.setColor( v.color( ) - v2.color( ) ); + break; + } + break; + } + break; + default: + end = true; + break; + } + } + while( !end ); + + return true; +} + +bool PMPovrayParser::parseVector( PMVector& vector, unsigned int size ) +{ + PMValue v; + unsigned int i; + + if( !parseNumericExpression( v ) ) + return false; + + switch( v.type( ) ) + { + case PMVFloat: + vector.resize( size ); + for( i = 0; i < size; i++ ) + vector[i] = v.floatValue( ); + break; + case PMVVector: + vector = v.vector( ); + vector.resize( size ); + break; + default: + printError( i18n( "Float or vector expression expected" ) ); + return false; + } + return true; +} + +bool PMPovrayParser::parseFloat( double& d, bool suppressError ) +{ + PMValue v; + + if( !parseNumericExpression( v, suppressError ) ) + return false; + + switch( v.type( ) ) + { + case PMVFloat: + d = v.floatValue( ); + break; + case PMVVector: + d = ( v.vector( ) )[0]; + break; + default: + printError( i18n( "Float expression expected" ) ); + return false; + } + return true; +} + +bool PMPovrayParser::parseInt( int& i ) +{ + double d; + + if( !parseFloat( d ) ) + return false; + + i = ( int ) ( d + 0.5 ); + return true; +} + +bool PMPovrayParser::parseColor( PMColor& c ) +{ + PMValue v; + + if( !parseNumericExpression( v ) ) + return false; + + if( v.type( ) == PMVColor ) + c = PMColor( v.color( ) ); + else if( v.type( ) == PMVVector ) + { + if( v.vector( ).size( ) == 5 ) + c = PMColor( v.vector( ) ); + else + { + printError( i18n( "Color expression expected" ) ); + return false; + } + } + else if( v.type( ) == PMVFloat ) + { + double d = v.floatValue( ); + c = PMColor( d, d, d, d, d ); + } + else + { + printError( i18n( "Color expression expected" ) ); + return false; + } + + return true; +} + +bool PMPovrayParser::parseObjectModifiers( PMGraphicalObject* o ) +{ + bool finished = false; + + PMSolidObject* so = 0; + if( o->isA( "SolidObject" ) ) + so = ( PMSolidObject* ) o; + + do + { + finished = true; + switch( m_token ) + { + case NO_SHADOW_TOK: + o->setNoShadow( true ); + nextToken( ); + finished = false; + break; + case NO_IMAGE_TOK: + o->setNoImage( true ); + nextToken( ); + finished = false; + break; + case NO_REFLECTION_TOK: + o->setNoReflection( true ); + nextToken( ); + finished = false; + break; + case DOUBLE_ILLUMINATE_TOK: + o->setDoubleIlluminate( true ); + nextToken( ); + finished = false; + break; + default: + break; + } + if( so ) + { + switch( m_token ) + { + case HOLLOW_TOK: + so->setHollow( PMTrue ); + nextToken( ); + if( isTrue( ) ) + nextToken( ); + else if( isFalse( ) ) + { + nextToken( ); + so->setHollow( PMFalse ); + } + finished = false; + break; + case INVERSE_TOK: + so->setInverse( true ); + nextToken( ); + finished = false; + break; + default: + break; + } + } + } + while( !finished ); + return true; +} + +bool PMPovrayParser::parseCSG( PMCSG* pNewCSG ) +{ + int oldConsumed; + + switch( m_token ) + { + case UNION_TOK: + pNewCSG->setCSGType( PMCSG::CSGUnion ); + break; + case INTERSECTION_TOK: + pNewCSG->setCSGType( PMCSG::CSGIntersection ); + break; + case DIFFERENCE_TOK: + pNewCSG->setCSGType( PMCSG::CSGDifference ); + break; + case MERGE_TOK: + pNewCSG->setCSGType( PMCSG::CSGMerge ); + break; + default: + printUnexpected( m_pScanner->sValue( ) ); + return false; + break; + } + nextToken( ); + + if( !parseToken( '{' ) ) + return false; + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewCSG ); + parseObjectModifiers( pNewCSG ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseBox( PMBox* pNewBox ) +{ + PMVector vector; + + int oldConsumed; + + if( !parseToken( BOX_TOK, "box" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewBox->setCorner1( vector ); + + if( !parseToken( ',' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewBox->setCorner2( vector ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewBox ); + parseObjectModifiers( pNewBox ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseSphere( PMSphere* pNewSphere ) +{ + PMVector vector; + double radius; + + int oldConsumed; + + if( !parseToken( SPHERE_TOK, "sphere" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewSphere->setCentre( vector ); + + if( !parseToken( ',' ) ) + return false; + + if( !parseFloat( radius ) ) + return false; + pNewSphere->setRadius( radius ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewSphere ); + parseObjectModifiers( pNewSphere ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseCylinder( PMCylinder* pNewCyl ) +{ + PMVector vector; + double radius; + int oldConsumed; + + if( !parseToken( CYLINDER_TOK, "cylinder" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewCyl->setEnd1( vector ); + + if( !parseToken( ',' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewCyl->setEnd2( vector ); + + if( !parseToken( ',' ) ) + return false; + + if( !parseFloat(radius) ) + return false; + pNewCyl->setRadius( radius ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewCyl ); + parseObjectModifiers( pNewCyl ); + switch( m_token ) + { + case OPEN_TOK: + nextToken( ); + pNewCyl->setOpen( true ); + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseCone( PMCone* pNewCone ) +{ + PMVector vector; + double radius; + int oldConsumed; + + if( !parseToken( CONE_TOK, "cone" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewCone->setEnd1( vector ); + + if( !parseToken( ',' ) ) + return false; + if( !parseFloat( radius ) ) + return false; + pNewCone->setRadius1( radius ); + + if( !parseToken( ',' ) ) + return false; + if( !parseVector( vector ) ) + return false; + pNewCone->setEnd2( vector ); + + if( !parseToken( ',' ) ) + return false; + if( !parseFloat( radius ) ) + return false; + pNewCone->setRadius2( radius ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewCone ); + parseObjectModifiers( pNewCone ); + switch( m_token ) + { + case OPEN_TOK: + nextToken( ); + pNewCone->setOpen( true ); + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; + +} + +bool PMPovrayParser::parseTorus( PMTorus* pNewTorus ) +{ + double radius; + int oldConsumed; + + if( !parseToken( TORUS_TOK, "torus" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseFloat( radius ) ) + return false; + pNewTorus->setMajorRadius( radius ); + if( !parseToken( ',' ) ) + return false; + if( !parseFloat( radius ) ) + return false; + pNewTorus->setMinorRadius( radius ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewTorus ); + parseObjectModifiers( pNewTorus ); + switch( m_token ) + { + case STURM_TOK: + nextToken( ); + pNewTorus->setSturm( true ); + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseBlob( PMBlob* pNewBlob ) +{ + PMVector vector; + double threshold; + int oldConsumed; + + if( !parseToken( BLOB_TOK, "blob" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + pNewBlob->setThreshold( 1.0 ); + + do + { + oldConsumed = m_consumedTokens; + + switch( m_token ) + { + case STURM_TOK: + nextToken( ); + pNewBlob->setSturm( true ); + break; + case HIERARCHY_TOK: + pNewBlob->setHierarchy( true ); + nextToken( ); + if( isTrue( ) ) + nextToken( ); + else if( isFalse( ) ) + { + nextToken( ); + pNewBlob->setHierarchy( false ); + } + break; + case THRESHOLD_TOK: + nextToken( ); + if( parseFloat( threshold ) ) + { + if( threshold <= 0 ) + printError( i18n( "The threshold value has to be positive" ) ); + else + pNewBlob->setThreshold( threshold ); + } + break; + } + + parseChildObjects( pNewBlob ); + parseObjectModifiers( pNewBlob ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseBlobSphere( PMBlobSphere* pNewBlobSphere ) +{ + PMVector vector; + double radius; + double strength; + + int oldConsumed; + + if( !parseToken( SPHERE_TOK, "sphere" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewBlobSphere->setCentre( vector ); + + if( !parseToken( ',' ) ) + return false; + + if( !parseFloat( radius ) ) + return false; + pNewBlobSphere->setRadius( radius ); + + if( !parseToken( ',' ) ) + return false; + + if( m_token == STRENGTH_TOK ) + nextToken( ); + + if( !parseFloat( strength ) ) + return false; + pNewBlobSphere->setStrength( strength ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewBlobSphere ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseBlobComponent( PMBlobSphere* pNewBlobSphere ) +{ + PMVector vector; + double radius; + double strength; + + if( !parseToken( COMPONENT_TOK, "component" ) ) + return false; + + if( !parseFloat( strength ) ) + return false; + pNewBlobSphere->setStrength( strength ); + + if( !parseToken( ',' ) ) + return false; + + if( !parseFloat( radius ) ) + return false; + pNewBlobSphere->setRadius( radius ); + + if( !parseToken( ',' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewBlobSphere->setCentre( vector ); + + return true; +} + +bool PMPovrayParser::parseBlobCylinder( PMBlobCylinder* pNewBlobCylinder ) +{ + PMVector vector; + double radius; + double strength; + int oldConsumed; + + if( !parseToken( CYLINDER_TOK, "cylinder" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewBlobCylinder->setEnd1( vector ); + + if( !parseToken( ',' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewBlobCylinder->setEnd2( vector ); + + if( !parseToken( ',' ) ) + return false; + + if( !parseFloat( radius ) ) + return false; + pNewBlobCylinder->setRadius( radius ); + + if( !parseToken( ',' ) ) + return false; + + if( m_token == STRENGTH_TOK ) + nextToken( ); + + if( !parseFloat( strength ) ) + return false; + pNewBlobCylinder->setStrength( strength ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewBlobCylinder ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseHeightField( PMHeightField* pNewHeightField ) +{ + int oldConsumed; + double wl; + + if( !parseToken( HEIGHT_FIELD_TOK, "height_field" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + switch( m_token ) + { + case GIF_TOK: + pNewHeightField->setHeightFieldType( PMHeightField::HFgif ); + nextToken( ); + break; + case TGA_TOK: + pNewHeightField->setHeightFieldType( PMHeightField::HFtga ); + nextToken( ); + break; + case POT_TOK: + pNewHeightField->setHeightFieldType( PMHeightField::HFpot ); + nextToken( ); + break; + case PNG_TOK: + pNewHeightField->setHeightFieldType( PMHeightField::HFpng ); + nextToken( ); + break; + case PGM_TOK: + pNewHeightField->setHeightFieldType( PMHeightField::HFpgm ); + nextToken( ); + break; + case PPM_TOK: + pNewHeightField->setHeightFieldType( PMHeightField::HFppm ); + nextToken( ); + break; + case SYS_TOK: + pNewHeightField->setHeightFieldType( PMHeightField::HFsys ); + nextToken( ); + break; + default: + printExpected( i18n( "height field type" ), m_pScanner->sValue( ) ); + return false; + } + if( m_token != STRING_TOK ) + { + printExpected( i18n( "height field file" ), m_pScanner->sValue( ) ); + return false; + } + else + { + pNewHeightField->setFileName( m_pScanner->sValue( ) ); + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + + switch( m_token ) + { + case SMOOTH_TOK: + nextToken( ); + pNewHeightField->setSmooth( true ); + if( isTrue( ) ) + nextToken( ); + else if( isFalse( ) ) + { + nextToken( ); + pNewHeightField->setSmooth( false ); + } + break; + case HIERARCHY_TOK: + pNewHeightField->setHierarchy( true ); + nextToken( ); + if( isTrue( ) ) + nextToken( ); + else if( isFalse( ) ) + { + nextToken( ); + pNewHeightField->setHierarchy( false ); + } + break; + case WATER_LEVEL_TOK: + nextToken( ); + if( parseFloat( wl ) ) + { + if( ( wl < 0.0 ) || ( wl > 1.0 ) ) + printError( i18n( "The water level has to be between 0 and 1" ) ); + else + pNewHeightField->setWaterLevel( wl ); + } + break; + } + + parseChildObjects( pNewHeightField ); + parseObjectModifiers( pNewHeightField ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseText( PMText* pNewText ) +{ + int oldConsumed; + double thickness; + PMVector offset; + + if( !parseToken( TEXT_TOK, "text" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseToken( TTF_TOK, "ttf" ) ) + return false; + + if( m_token != STRING_TOK ) + { + printExpected( i18n( "font file name" ), m_pScanner->sValue( ) ); + return false; + } + else + { + pNewText->setFont( m_pScanner->sValue( ) ); + nextToken( ); + } + if( m_token != STRING_TOK ) + { + printExpected( i18n( "string of text" ), m_pScanner->sValue( ) ); + return false; + } + else + { + pNewText->setText( m_pScanner->sValue( ) ); + nextToken( ); + } + + if( !parseFloat( thickness ) ) + return false; + pNewText->setThickness( thickness ); + + parseToken( ',' ); + + if( parseVector( offset, 2 ) ) + pNewText->setOffset( offset ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewText ); + parseObjectModifiers( pNewText ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseJuliaFractal( PMJuliaFractal* pNewFractal ) +{ + int oldConsumed; + double d; + int i; + PMVector v( 4 ), v2( 2 ); + + if( !parseToken( JULIA_FRACTAL_TOK, "julia_fractal" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseVector( v, 4 ) ) + return false; + pNewFractal->setJuliaParameter( v ); + + do + { + oldConsumed = m_consumedTokens; + + switch( m_token ) + { + case QUATERNION_TOK: + pNewFractal->setAlgebraType( PMJuliaFractal::Quaternion ); + nextToken( ); + break; + case HYPERCOMPLEX_TOK: + pNewFractal->setAlgebraType( PMJuliaFractal::Hypercomplex ); + nextToken( ); + break; + case SQR_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTsqr ); + nextToken( ); + break; + case CUBE_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTcube ); + nextToken( ); + break; + case EXP_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTexp ); + nextToken( ); + break; + case RECIPROCAL_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTreciprocal ); + nextToken( ); + break; + case SIN_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTsin ); + nextToken( ); + break; + case ASIN_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTasin ); + nextToken( ); + break; + case SINH_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTsinh ); + nextToken( ); + break; + case ASINH_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTasinh ); + nextToken( ); + break; + case COS_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTcos ); + nextToken( ); + break; + case ACOS_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTacos ); + nextToken( ); + break; + case COSH_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTcosh ); + nextToken( ); + break; + case ACOSH_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTacosh ); + nextToken( ); + break; + case TAN_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTtan ); + nextToken( ); + break; + case ATAN_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTatan ); + nextToken( ); + break; + case TANH_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTtanh ); + nextToken( ); + break; + case ATANH_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTatanh ); + nextToken( ); + break; + case LOG_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTlog ); + nextToken( ); + break; + case PWR_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTpwr ); + nextToken( ); + if( !parseToken( '(' ) ) + return false; + if( !parseFloat( v2[0] ) ) + return false; + parseToken( ',' ); + if( !parseFloat( v2[1] ) ) + return false; + if( !parseToken( ')' ) ) + return false; + pNewFractal->setExponent( v2 ); + break; + case MAX_ITERATION_TOK: + nextToken( ); + if( !parseInt( i ) ) + return false; + if( i <= 0 ) + { + printWarning( i18n( "Maximum iterations are less than 1, fixed" ) ); + i = 1; + } + pNewFractal->setMaximumIterations( i ); + break; + case PRECISION_TOK: + nextToken( ); + if( !parseFloat( d ) ) + return false; + if( d < 1.0 ) + { + printWarning( i18n( "Precision is less than 1.0, fixed" ) ); + d = 1.0; + } + pNewFractal->setPrecision( d ); + break; + case SLICE_TOK: + nextToken( ); + if( !parseVector( v, 4 ) ) + return false; + pNewFractal->setSliceNormal( v ); + parseToken( ',' ); + if( !parseFloat( d ) ) + return false; + pNewFractal->setSliceDistance( d ); + break; + } + + parseChildObjects( pNewFractal ); + parseObjectModifiers( pNewFractal ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parsePlane( PMPlane* pNewPlane ) +{ + double dist; + PMVector vector; + int oldConsumed; + + if( !parseToken( PLANE_TOK, "plane" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewPlane->setNormal( vector ); + + if( !parseToken( ',' ) ) + return false; + if( !parseFloat( dist ) ) + return false; + pNewPlane->setDistance( dist ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewPlane ); + parseObjectModifiers( pNewPlane ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +const int c_polynomSize[8] = { 0, 0, 10, 20, 35, 56, 84, 120 }; + +bool PMPovrayParser::parsePolynom( PMPolynom* pNewPoly ) +{ + PMVector vector; + double d; + PMVector c; + int oldConsumed; + int order = 2; + int type = m_token; + + pNewPoly->setSturm( false ); + + if( ( m_token == QUADRIC_TOK ) || ( m_token == CUBIC_TOK ) || + ( m_token == QUARTIC_TOK ) || ( m_token == POLY_TOK ) ) + { + nextToken( ); + if( !parseToken( '{' ) ) + return false; + } + else + printExpected( "poly", m_pScanner->sValue( ) ); + + if( type == QUADRIC_TOK ) + { + c = PMVector( 10 ); + pNewPoly->setPolynomOrder( 2 ); + + // parse the quadric coefficients + if( !parseVectorLiteral( vector ) ) + return false; + vector.resize( 3 ); + c[0] = vector[0]; + c[4] = vector[1]; + c[7] = vector[2]; + parseToken( ',' ); + + if( !parseVectorLiteral( vector ) ) + return false; + vector.resize( 3 ); + c[1] = vector[0]; + c[2] = vector[1]; + c[5] = vector[2]; + parseToken( ',' ); + + if( !parseVectorLiteral( vector ) ) + return false; + vector.resize( 3 ); + c[3] = vector[0]; + c[6] = vector[1]; + c[8] = vector[2]; + parseToken( ',' ); + + if( !parseFloat( d ) ) + return false; + c[9] = d; + + pNewPoly->setCoefficients( c ); + } + else + { + if( type == CUBIC_TOK ) + order = 3; + else if( type == QUARTIC_TOK ) + order = 4; + else + { + if( !parseInt( order ) ) + return false; + if( ( order < 2 ) || ( order > 7 ) ) + { + printError( i18n( "The polynom order has to be between 2 and 7 inclusive" ) ); + return false; + } + parseToken( ',' ); + } + + pNewPoly->setPolynomOrder( order ); + + if( !parseVectorLiteral( vector ) ) + return false; + + if( vector.size( ) != ( unsigned ) c_polynomSize[order] ) + { + printError( i18n( "%1 coefficients are needed for a polynom with order %2" ) + .arg( c_polynomSize[order] ).arg( order ) ); + vector.resize( c_polynomSize[order] ); + } + pNewPoly->setCoefficients( vector ); + } + + do + { + oldConsumed = m_consumedTokens; + + if( m_token == STURM_TOK ) + { + pNewPoly->setSturm( true ); + nextToken( ); + } + + parseChildObjects( pNewPoly ); + parseObjectModifiers( pNewPoly ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseBicubicPatch( PMBicubicPatch* pNewPatch ) +{ + PMVector vector; + bool stop = false; + int oldConsumed; + int type; + int steps; + double flatness; + int i; + + if( !parseToken( BICUBIC_PATCH_TOK, "bicubic_patch" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + // parse patch items + do + { + switch( m_token ) + { + case TYPE_TOK: + nextToken( ); + if( parseInt( type ) ) + { + if( ( type == 0 ) || ( type == 1 ) ) + pNewPatch->setPatchType( type ); + else + printError( i18n( "Patch type has to be 0 or 1" ) ); + } + break; + case U_STEPS_TOK: + nextToken( ); + if( parseInt( steps ) ) + pNewPatch->setUSteps( steps ); + break; + case V_STEPS_TOK: + nextToken( ); + if( parseInt( steps ) ) + pNewPatch->setVSteps( steps ); + break; + case FLATNESS_TOK: + nextToken( ); + if( parseFloat( flatness ) ) + pNewPatch->setFlatness( flatness ); + break; + case UV_VECTORS_TOK: + pNewPatch->enableUV( true ); + nextToken( ); + for ( i = 0; i < 4; ++i ) + { + if( parseVector( vector ) ) + pNewPatch->setUVVector( i, vector ); + else + return false; + } + break; + case ',': + nextToken( ); + stop = true; + break; + default: + stop = true; + break; + } + } + while( !stop ); + + // parse control points + stop = false; + for( i = 0; ( i < 16 ) && !stop; i++ ) + { + if( parseVector( vector ) ) + { + pNewPatch->setControlPoint( i, vector ); + if( i < 15 ) + if( !parseToken( ',' ) ) + stop = true; + } + else + stop = true; + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewPatch ); + parseObjectModifiers( pNewPatch ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseDisc( PMDisc* pNewDisc ) +{ + double d; + PMVector vector; + int oldConsumed; + + if( !parseToken( DISC_TOK, "disc" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewDisc->setCenter( vector ); + + if( !parseToken( ',' ) ) + return false; + if( !parseVector( vector ) ) + return false; + pNewDisc->setNormal( vector ); + + if( !parseToken( ',' ) ) + return false; + if( !parseFloat( d ) ) + return false; + pNewDisc->setRadius( d ); + + if( m_token == ',' ) + { + nextToken( ); + if( !parseFloat( d ) ) + return false; + pNewDisc->setHoleRadius( d ); + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewDisc ); + parseObjectModifiers( pNewDisc ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseTriangle( PMTriangle* pNewTriangle ) +{ + PMVector vector; + int oldConsumed; + int i; + + if( m_token == SMOOTH_TRIANGLE_TOK ) + pNewTriangle->setSmoothTriangle( true ); + else if( m_token == TRIANGLE_TOK ) + pNewTriangle->setSmoothTriangle( false ); + else + { + printExpected( "triangle", m_pScanner->sValue( ) ); + return false; + } + nextToken( ); + + if( !parseToken( '{' ) ) + return false; + + for( i = 0; i < 3; i++ ) + { + if( i != 0 ) + parseToken( ',' ); + if( !parseVector( vector ) ) + return false; + pNewTriangle->setPoint( i, vector ); + + if( pNewTriangle->isSmoothTriangle( ) ) + { + parseToken( ',' ); + if( !parseVector( vector ) ) + return false; + pNewTriangle->setNormal( i, vector ); + } + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewTriangle ); + parseObjectModifiers( pNewTriangle ); + if( m_token == UV_VECTORS_TOK ) + { + nextToken( ); + pNewTriangle->enableUV( true ); + for ( i = 0; i < 3; ++i ) + { + if( parseVector( vector ) ) + pNewTriangle->setUVVector( i, vector ); + else + return false; + } + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseLathe( PMLathe* pNewLathe ) +{ + PMVector vector; + int oldConsumed; + int i; + bool stop = false; + + if( !parseToken( LATHE_TOK, "lathe" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + int minp = 2; + while( !stop ) + { + switch( m_token ) + { + case LINEAR_SPLINE_TOK: + pNewLathe->setSplineType( PMLathe::LinearSpline ); + nextToken( ); + minp = 2; + break; + case QUADRATIC_SPLINE_TOK: + pNewLathe->setSplineType( PMLathe::QuadraticSpline ); + nextToken( ); + minp = 3; + break; + case CUBIC_SPLINE_TOK: + pNewLathe->setSplineType( PMLathe::CubicSpline ); + nextToken( ); + minp = 4; + break; + case BEZIER_SPLINE_TOK: + pNewLathe->setSplineType( PMLathe::BezierSpline ); + nextToken( ); + minp = 4; + break; + default: + stop = true; + break; + } + } + + int nump; + if( !parseInt( nump ) ) + return false; + + QValueList points; + for( i = 0; i < nump; i++ ) + { + parseToken( ',' ); + if( !parseVector( vector ) ) + return false; + vector.resize( 2 ); + points.append( vector ); + } + + if( nump < minp ) + printError( i18n( "At least %1 points are needed for that spline type" ) + .arg( minp ) ); + else if( ( pNewLathe->splineType( ) == PMLathe::BezierSpline ) && + ( ( nump % 4 ) != 0 ) ) + printError( i18n( "Bezier splines need 4 points for each segment" ) ); + else + pNewLathe->setPoints( points ); + + do + { + oldConsumed = m_consumedTokens; + + if( m_token == STURM_TOK ) + { + pNewLathe->setSturm( true ); + nextToken( ); + } + + parseChildObjects( pNewLathe ); + parseObjectModifiers( pNewLathe ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parsePrism( PMPrism* pNewPrism ) +{ + PMVector vector; + double height; + int oldConsumed; + int i; + bool stop = false; + + if( !parseToken( PRISM_TOK, "prism" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + int minp = 3; + while( !stop ) + { + switch( m_token ) + { + case LINEAR_SPLINE_TOK: + pNewPrism->setSplineType( PMPrism::LinearSpline ); + nextToken( ); + minp = 3; + break; + case QUADRATIC_SPLINE_TOK: + pNewPrism->setSplineType( PMPrism::QuadraticSpline ); + nextToken( ); + minp = 4; + break; + case CUBIC_SPLINE_TOK: + pNewPrism->setSplineType( PMPrism::CubicSpline ); + nextToken( ); + minp = 5; + break; + case BEZIER_SPLINE_TOK: + pNewPrism->setSplineType( PMPrism::BezierSpline ); + nextToken( ); + minp = 4; + break; + case LINEAR_SWEEP_TOK: + pNewPrism->setSweepType( PMPrism::LinearSweep ); + nextToken( ); + break; + case CONIC_SWEEP_TOK: + pNewPrism->setSweepType( PMPrism::ConicSweep ); + nextToken( ); + break; + default: + stop = true; + break; + } + } + + if( !parseFloat( height ) ) + return false; + pNewPrism->setHeight1( height ); + parseToken( ',' ); + if( !parseFloat( height ) ) + return false; + pNewPrism->setHeight2( height ); + parseToken( ',' ); + + int nump; + if( !parseInt( nump ) ) + return false; + + QValueList allPoints; + for( i = 0; i < nump; i++ ) + { + parseToken( ',' ); + if( !parseVector( vector ) ) + return false; + vector.resize( 2 ); + allPoints.append( vector ); + } + + QValueList< QValueList > points; + QValueList subPoints; + QValueList::Iterator it = allPoints.begin( ); + int pnr = 0, pmod4; + PMVector ref( 2 ), ref2( 2 ); + bool error = false; + bool last = false; + + switch( pNewPrism->splineType( ) ) + { + case PMPrism::LinearSpline: + for( ; ( it != allPoints.end( ) ) && !error; ++it, pnr++ ) + { + if( pnr == 0 ) + { + ref = *it; + subPoints.append( *it ); + } + else + { + if( ref.approxEqual( *it ) ) + { + if( pnr < 3 ) + { + printError( i18n( "Linear splines need at least 4 points." ) ); + error = true; + } + else + { + points.append( subPoints ); + subPoints.clear( ); + pnr = -1; + } + } + else + subPoints.append( *it ); + } + } + if( ( pnr != 0 ) && ( !error ) ) + { + printWarning( i18n( "Linear spline not closed" ) ); + if( pnr < 3 ) + { + printError( i18n( "Linear splines need at least 4 points." ) ); + error = true; + } + else + { + points.append( subPoints ); + subPoints.clear( ); + } + } + break; + case PMPrism::QuadraticSpline: + for( ; ( it != allPoints.end( ) ) && !error; ++it, pnr++ ) + { + if( pnr == 0 ) + subPoints.append( *it ); + else if( pnr == 1 ) + { + ref = *it; + subPoints.append( *it ); + } + else + { + if( ref.approxEqual( *it ) ) + { + if( pnr < 4 ) + { + printError( i18n( "Quadratic splines need at least 5 points." ) ); + error = true; + } + else + { + points.append( subPoints ); + subPoints.clear( ); + pnr = -1; + } + } + else + subPoints.append( *it ); + } + } + if( ( pnr != 0 ) && ( !error ) ) + { + printError( i18n( "Quadratic spline not closed" ) ); + error = true; + } + break; + case PMPrism::CubicSpline: + for( ; ( it != allPoints.end( ) ) && !error; ++it, pnr++ ) + { + if( pnr == 0 ) + subPoints.append( *it ); + else if( pnr == 1 ) + { + ref = *it; + subPoints.append( *it ); + } + else if( last ) + { + if( pnr < 5 ) + { + printError( i18n( "Cubic splines need at least 6 points." ) ); + error = true; + } + else + { + subPoints.append( *it ); + points.append( subPoints ); + subPoints.clear( ); + pnr = -1; + last = false; + } + } + else + { + if( ref.approxEqual( *it ) ) + last = true; + else + subPoints.append( *it ); + } + } + if( ( pnr != 0 ) && ( !error ) ) + { + printError( i18n( "Cubic spline not closed" ) ); + error = true; + } + break; + case PMPrism::BezierSpline: + for( ; ( it != allPoints.end( ) ) && !error; ++it, pnr++ ) + { + pmod4 = pnr % 4; + + if( pnr == 0 ) + { + ref = *it; + subPoints.append( *it ); + } + else if( pmod4 == 0 ) + { + if( !ref2.approxEqual( *it ) ) + { + printError( i18n( "Bezier spline not closed" ) ); + error = true; + } + } + else if( pmod4 == 3 ) + { + if( ref.approxEqual( *it ) ) + { + points.append( subPoints ); + subPoints.clear( ); + pnr = -1; + } + else + { + subPoints.append( *it ); + ref2 = *it; + } + } + else + subPoints.append( *it ); + } + if( ( pnr != 0 ) && ( !error ) ) + { + printError( i18n( "Bezier spline not closed" ) ); + error = true; + } + break; + } + + if( !error ) + pNewPrism->setPoints( points ); + + do + { + oldConsumed = m_consumedTokens; + + switch( m_token ) + { + case STURM_TOK: + pNewPrism->setSturm( true ); + nextToken( ); + break; + case OPEN_TOK: + pNewPrism->setOpen( true ); + nextToken( ); + break; + default: + break; + } + + parseChildObjects( pNewPrism ); + parseObjectModifiers( pNewPrism ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseSor( PMSurfaceOfRevolution* pNewSor ) +{ + PMVector vector; + int oldConsumed; + int i; + + if( !parseToken( SOR_TOK, "sor" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + int nump; + if( !parseInt( nump ) ) + return false; + + QValueList points; + for( i = 0; i < nump; i++ ) + { + parseToken( ',' ); + if( !parseVector( vector ) ) + return false; + vector.resize( 2 ); + points.append( vector ); + } + + if( nump < 4 ) + printError( i18n( "At least 4 points are needed for the surface of revolution" ) ); + else + { + QValueList::Iterator it1 = points.begin( ); + QValueList::Iterator it2 = it1; ++it2; + QValueList::Iterator it3 = it2; ++it3; + int pnr = 0; + + for( ; it3 != points.end( ); ++it1, ++it2, ++it3, pnr++ ) + { + if( ( pnr == 0 ) || ( pnr == ( nump - 3 ) ) ) + { + if( approxZero( ( *it1 )[1] - ( *it3 )[1], c_sorTolerance ) ) + { + printError( i18n( "The v coordinate of point %1 and %2 must be different; fixed" ) + .arg( pnr + 1 ).arg( pnr + 3 ) ); + if( pnr == 0 ) + ( *it1 )[1] = ( *it3 )[1] - c_sorTolerance; + else + ( *it3 )[1] = ( *it1 )[1] + c_sorTolerance; + } + } + + if( pnr != 0 ) + { + if( ( ( *it2 )[1] - ( *it1 )[1] ) < c_sorTolerance ) + { + printError( i18n( "The v coordinates must be strictly increasing; fixed" ) ); + ( *it2 )[1] = ( *it1 )[1] + c_sorTolerance; + } + } + } + pNewSor->setPoints( points ); + } + + do + { + oldConsumed = m_consumedTokens; + + switch( m_token ) + { + case STURM_TOK: + pNewSor->setSturm( true ); + nextToken( ); + break; + case OPEN_TOK: + pNewSor->setOpen( true ); + nextToken( ); + break; + default: + break; + } + + parseChildObjects( pNewSor ); + parseObjectModifiers( pNewSor ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseSqe( PMSuperquadricEllipsoid* pNewSqe ) +{ + PMVector vector; + int oldConsumed; + + if( !parseToken( SUPERELLIPSOID_TOK ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + vector.resize( 2 ); + + if( vector[0] < 0.001 ) + { + printError( i18n( "The east-west exponent must be greater than 0.001" ) ); + vector[0] = 0.001; + } + if( vector[1] < 0.001 ) + { + printError( i18n( "The north-south exponent must be greater than 0.001" ) ); + vector[1] = 0.001; + } + + pNewSqe->setEastWestExponent( vector[0] ); + pNewSqe->setNorthSouthExponent( vector[1] ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewSqe ); + parseObjectModifiers( pNewSqe ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseRotate( PMRotate* rotate ) +{ + PMVector v; + + if( !parseToken( ROTATE_TOK, "rotate" ) ) + return false; + if( !parseVector( v ) ) + return false; + + rotate->setRotation( v ); + return true; +} + +bool PMPovrayParser::parseScale( PMScale* scale ) +{ + PMVector v; + + if( !parseToken( SCALE_TOK, "scale" ) ) + return false; + if( !parseVector( v ) ) + return false; + + scale->setScale( v ); + return true; +} + +bool PMPovrayParser::parseTranslate( PMTranslate* translate ) +{ + PMVector v; + + if( !parseToken( TRANSLATE_TOK, "translate" ) ) + return false; + if( !parseVector( v ) ) + return false; + + translate->setTranslation( v ); + return true; +} + +bool PMPovrayParser::parseMatrix( PMPovrayMatrix* matrix ) +{ + PMVector v; + + if( !parseToken( MATRIX_TOK ), "matrix" ) + return false; + if( !parseVectorLiteral( v ) ) + return false; + + if( v.size( ) != 12 ) + { + printError( i18n( "Wrong number of matrix values." ) ); + v.resize( 12 ); + } + matrix->setValues( v ); + return true; +} + +bool PMPovrayParser::parseBoundedBy( PMBoundedBy* bound ) +{ + int oldConsumed; + + if( !parseToken( BOUNDED_BY_TOK, "bounded_by" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + do + { + oldConsumed = m_consumedTokens; + + if( m_token == CLIPPED_BY_TOK ) + nextToken( ); + + parseChildObjects( bound ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseClippedBy( PMClippedBy* clipped ) +{ + int oldConsumed; + + if( !parseToken( CLIPPED_BY_TOK, "clipped_by" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + do + { + oldConsumed = m_consumedTokens; + + if( m_token == BOUNDED_BY_TOK ) + nextToken( ); + + parseChildObjects( clipped ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseCamera( PMCamera* camera ) +{ + PMVector v; + double d; + int i; + + int oldConsumed; + + if( !parseToken( CAMERA_TOK, "camera" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + do + { + oldConsumed = m_consumedTokens; + + do + { + oldConsumed = m_consumedTokens; + + switch( m_token ) + { + case PERSPECTIVE_TOK: + nextToken( ); + camera->setCameraType( PMCamera::Perspective ); + break; + case ORTHOGRAPHIC_TOK: + nextToken( ); + camera->setCameraType( PMCamera::Orthographic ); + break; + case FISHEYE_TOK: + nextToken( ); + camera->setCameraType( PMCamera::FishEye ); + break; + case ULTRA_WIDE_ANGLE_TOK: + nextToken( ); + camera->setCameraType( PMCamera::UltraWideAngle ); + break; + case OMNIMAX_TOK: + nextToken( ); + camera->setCameraType( PMCamera::Omnimax ); + break; + case PANORAMIC_TOK: + nextToken( ); + camera->setCameraType( PMCamera::Panoramic ); + break; + case CYLINDER_TOK: + nextToken( ); + camera->setCameraType( PMCamera::Cylinder ); + if( parseInt( i ) ) + camera->setCylinderType( i ); + break; + case LOCATION_TOK: + nextToken( ); + if( parseVector( v ) ) + camera->setLocation( v ); + break; + case SKY_TOK: + nextToken( ); + if( parseVector( v ) ) + camera->setSky( v ); + break; + case UP_TOK: + nextToken( ); + if( parseVector( v ) ) + camera->setUp( v ); + break; + case RIGHT_TOK: + nextToken( ); + if( parseVector( v ) ) + camera->setRight( v ); + break; + case DIRECTION_TOK: + nextToken( ); + if( parseVector( v ) ) + camera->setDirection( v ); + break; + case LOOK_AT_TOK: + nextToken( ); + if( parseVector( v ) ) + camera->setLookAt( v ); + break; + case ANGLE_TOK: + nextToken( ); + if( parseFloat( d ) ) + { + camera->enableAngle( true ); + camera->setAngle( d ); + } + break; + case BLUR_SAMPLES_TOK: + nextToken( ); + camera->enableFocalBlur( true ); + if( parseInt( i ) ) + camera->setBlurSamples( i ); + break; + case APERTURE_TOK: + nextToken( ); + camera->enableFocalBlur( true ); + if( parseFloat( d ) ) + camera->setAperture( d ); + break; + case FOCAL_POINT_TOK: + nextToken( ); + if( parseVector( v ) ) + camera->setFocalPoint( v ); + break; + case CONFIDENCE_TOK: + nextToken( ); + if( parseFloat( d ) ) + camera->setConfidence( d ); + break; + case VARIANCE_TOK: + nextToken( ); + if( parseFloat( d ) ) + camera->setVariance( d ); + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + parseChildObjects( camera ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseLight( PMLight* light ) +{ + PMVector v; + PMColor c; + double d; + int i; + + int oldConsumed; + + if( !parseToken( LIGHT_SOURCE_TOK, "light_source" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + if( !parseVector( v ) ) + return false; + light->setLocation( v ); + if( m_token == ',' ) + nextToken( ); + if( !parseColor( c ) ) + return false; + light->setColor( c ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( light ); + + switch( m_token ) + { + case SPOTLIGHT_TOK: + nextToken( ); + light->setLightType( PMLight::SpotLight ); + break; + case CYLINDER_TOK: + nextToken( ); + light->setLightType( PMLight::CylinderLight ); + break; + case SHADOWLESS_TOK: + nextToken( ); + light->setLightType( PMLight::ShadowlessLight ); + break; + case RADIUS_TOK: + nextToken( ); + if( parseFloat( d ) ) + light->setRadius( d ); + break; + case FALLOFF_TOK: + nextToken( ); + if( parseFloat( d ) ) + light->setFalloff( d ); + break; + case TIGHTNESS_TOK: + nextToken( ); + if( parseFloat( d ) ) + light->setTightness( d ); + break; + case POINT_AT_TOK: + nextToken( ); + if( parseVector( v ) ) + light->setPointAt( v ); + break; + case PARALLEL_TOK: + nextToken( ); + light->setParallel( parseBool( ) ); + break; + case AREA_LIGHT_TOK: + nextToken( ); + light->setAreaLight( true ); + if( parseVector( v ) ) + light->setAxis1( v ); + parseToken( ',' ); + if( parseVector( v ) ) + light->setAxis2( v ); + parseToken( ',' ); + if( parseInt( i ) ) + light->setSize1( i ); + parseToken( ',' ); + if( parseInt( i ) ) + light->setSize2( i ); + break; + case AREA_CIRCULAR_TOK: + nextToken( ); + light->setAreaType( PMLight::Circular ); + break; + case ADAPTIVE_TOK: + nextToken( ); + if( parseInt( i ) ) + light->setAdaptive( i ); + break; + case ORIENT_TOK: + nextToken( ); + light->setOrient( parseBool( ) ); + break; + case JITTER_TOK: + nextToken( ); + light->setJitter( parseBool( ) ); + break; + case FADE_POWER_TOK: + nextToken( ); + light->setFading( true ); + if( parseInt( i ) ) + light->setFadePower( i ); + break; + case FADE_DISTANCE_TOK: + nextToken( ); + light->setFading( true ); + if( parseFloat( d ) ) + light->setFadeDistance( d ); + break; + case MEDIA_INTERACTION_TOK: + nextToken( ); + light->setMediaInteraction( parseBool( ) ); + break; + case MEDIA_ATTENUATION_TOK: + nextToken( ); + light->setMediaAttenuation( parseBool( ) ); + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseLooksLike( PMLooksLike* ll ) +{ + if( !parseToken( LOOKS_LIKE_TOK, "looks_like" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + parseChildObjects( ll ); + + if( !parseToken( '}' ) ) + return false; + return true; +} + +bool PMPovrayParser::parseProjectedThrough( PMProjectedThrough* ll ) +{ + if( !parseToken( PROJECTED_THROUGH_TOK, "projected_through" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + parseChildObjects( ll ); + + if( !parseToken( '}' ) ) + return false; + return true; +} + +bool PMPovrayParser::parseTexture( PMTexture* texture, bool parseOuter ) +{ + int oldConsumed; + + if( parseOuter ) + { + if( !parseToken( TEXTURE_TOK, "texture" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + } + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !texture->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( texture ); + if( m_token == UV_MAPPING_TOK ) + { + nextToken(); + texture->setUVMapping( parseBool( ) ); + } + } + while( oldConsumed != m_consumedTokens ); + + if( parseOuter ) + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parsePattern( PMPattern* pattern, bool normal ) +{ + PMVector vector; + double f_number; + int i_number; + int oldConsumed; + bool type; + + do + { + oldConsumed = m_consumedTokens; + type = false; + + switch( m_token ) + { + case AGATE_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternAgate ); + type = true; + break; + case AGATE_TURB_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + pattern->setAgateTurbulence( f_number ); + break; + case AVERAGE_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternAverage ); + type = true; + break; + case BOXED_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternBoxed ); + type = true; + break; + case BOZO_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternBozo ); + type = true; + break; + case BUMPS_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternBumps ); + type = true; + break; + case CELLS_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternCells ); + type = true; + break; + case CRACKLE_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternCrackle ); + type = true; + break; + case CYLINDRICAL_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternCylindrical ); + type = true; + break; + case DENTS_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternDents ); + type = true; + break; + case DENSITY_FILE_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternDensity ); + type = true; + if( !parseToken( DF3_TOK, "df3" ) ) + return false; + if( m_token != STRING_TOK ) + { + printError( i18n( "Expecting a file name." ) ); + return false; + } + else + { + pattern->setDensityFile( m_pScanner->sValue( ) ); + nextToken( ); + } + if( parseToken( INTERPOLATE_TOK, "interpolate" ) ) + { + if( !parseInt( i_number ) ) + return false; + else + pattern->setDensityInterpolate( i_number ); + } + break; + case GRADIENT_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternGradient ); + type = true; + if( !parseVector( vector ) ) + return false; + pattern->setGradient( vector ); + break; + case GRANITE_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternGranite ); + type = true; + break; + case JULIA_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternJulia ); + type = true; + if( !parseVector( vector ) ) + return false; + pattern->setJuliaComplex( vector ); + if( !parseInt( i_number ) ) + return false; + pattern->setMaxIterations( i_number ); + break; + case LEOPARD_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternLeopard ); + type = true; + break; + case MANDEL_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternMandel ); + type = true; + if( !parseInt( i_number ) ) + return false; + pattern->setMaxIterations( i_number ); + break; + case MARBLE_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternMarble ); + type = true; + break; + case ONION_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternOnion ); + type = true; + break; + case PLANAR_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternPlanar ); + type = true; + break; + case QUILTED_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternQuilted ); + type = true; + break; + case CONTROL0_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + pattern->setQuiltControl0( f_number ); + break; + case CONTROL1_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + pattern->setQuiltControl1( f_number ); + break; + case RADIAL_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternRadial ); + type = true; + break; + case RIPPLES_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternRipples ); + type = true; + break; + case SLOPE_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternSlope ); + type = true; + if( !parseToken( '{' ) ) + return false; + if( !parseVector( vector ) ) + return false; + pattern->setSlopeDirection( vector ); + if ( parseToken( ',' ) ) + { + if( !parseFloat( f_number ) ) + return false; + pattern->setSlopeLoSlope( f_number ); + if ( parseToken( ',' ) ) + { + if ( !parseFloat( f_number ) ) + return false; + pattern->setSlopeHiSlope( f_number ); + } + } + if( m_token == ALTITUDE_TOK ) + { + pattern->setSlopeAltFlag( true ); + nextToken( ); + if ( !parseVector( vector ) ) + return false; + pattern->setSlopeAltitude( vector ); + if( parseToken( ',' ) ) + { + if ( !parseFloat( f_number ) ) + return false; + pattern->setSlopeLoAlt( f_number ); + if ( parseToken( ',' ) ) + { + if( !parseFloat( f_number ) ) + return false; + pattern->setSlopeHiAlt( f_number ); + } + } + } + if( !parseToken( '}' ) ) + return false; + break; + case SPHERICAL_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternSpherical ); + type = true; + break; + case SPIRAL1_TOK: + case SPIRAL2_TOK: + if( m_token == SPIRAL1_TOK ) + pattern->setPatternType( PMPattern::PatternSpiral1 ); + else + pattern->setPatternType( PMPattern::PatternSpiral2 ); + type = true; + nextToken( ); + if( !parseInt( i_number ) ) + return false; + pattern->setSpiralNumberArms( i_number ); + break; + case SPOTTED_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternSpotted ); + type = true; + break; + case WAVES_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternWaves ); + type = true; + break; + case WOOD_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternWood ); + type = true; + break; + case WRINKLES_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternWrinkles ); + type = true; + break; + + //crackle parameters + case FORM_TOK: + nextToken( ); + if( !parseVector( vector ) ) + return false; + pattern->setCrackleForm( vector ); + break; + case METRIC_TOK: + nextToken( ); + if ( !parseInt( i_number ) ) + return false; + pattern->setCrackleMetric( i_number ); + break; + case OFFSET_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + pattern->setCrackleOffset( f_number ); + break; + case SOLID_TOK: + nextToken( ); + pattern->setCrackleSolid( true ); + break; + + //fractal parameters + case MAGNET_TOK: + nextToken( ); + pattern->setFractalMagnet( true ); + if ( !parseInt( i_number ) ) + return false; + pattern->setFractalMagnetType( i_number ); + break; + case EXPONENT_TOK: + nextToken( ); + if ( !parseInt( i_number ) ) + return false; + pattern->setFractalExponent( i_number ); + break; + case EXTERIOR_TOK: + nextToken( ); + if ( !parseInt( i_number ) ) + return false; + pattern->setFractalExtType( i_number ); + if ( !parseFloat( f_number ) ) + return false; + pattern->setFractalExtFactor( f_number ); + break; + case INTERIOR_TOK: + nextToken( ); + if ( !parseInt( i_number ) ) + return false; + pattern->setFractalIntType( i_number ); + if ( !parseFloat( f_number ) ) + return false; + pattern->setFractalIntFactor( f_number ); + break; + + //turbulence + case TURBULENCE_TOK: + nextToken( ); + pattern->enableTurbulence( true ); + if( !parseVector( vector ) ) + return false; + pattern->setValueVector( vector ); + break; + case OCTAVES_TOK: + nextToken( ); + if( !parseInt( i_number ) ) + return false; + pattern->setOctaves( i_number ); + break; + case OMEGA_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + pattern->setOmega( f_number ); + break; + case LAMBDA_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + pattern->setLambda( f_number ); + break; + + case NOISE_GENERATOR_TOK: + nextToken( ); + if( !parseInt( i_number ) ) + return false; + pattern->setNoiseGenerator( ( PMPattern::PMNoiseType ) ( i_number ) ); + break; + default: + break; + } + + if( type && normal ) + { + // try to parse the normal pattern depth + double depth; + if( parseFloat( depth, true ) ) + pattern->setDepth( depth ); + } + } + while( oldConsumed != m_consumedTokens ); + + return true; +} + +bool PMPovrayParser::parseBlendMapModifiers( PMBlendMapModifiers* blend ) +{ + int oldConsumed; + double f_number; + + do + { + oldConsumed = m_consumedTokens; + switch( m_token ) + { + case FREQUENCY_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + blend->enableFrequency( true ); + blend->setFrequency( f_number ); + break; + case PHASE_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + blend->enablePhase( true ); + blend->setPhase( f_number ); + break; + case RAMP_WAVE_TOK: + nextToken( ); + blend->enableWaveForm( true ); + blend->setWaveFormType( PMBlendMapModifiers::RampWave ); + break; + case TRIANGLE_WAVE_TOK: + nextToken( ); + blend->enableWaveForm( true ); + blend->setWaveFormType( PMBlendMapModifiers::TriangleWave ); + break; + case SINE_WAVE_TOK: + nextToken( ); + blend->enableWaveForm( true ); + blend->setWaveFormType( PMBlendMapModifiers::SineWave ); + break; + case SCALLOP_WAVE_TOK: + nextToken( ); + blend->enableWaveForm( true ); + blend->setWaveFormType( PMBlendMapModifiers::ScallopWave ); + break; + case CUBIC_WAVE_TOK: + nextToken( ); + blend->enableWaveForm( true ); + blend->setWaveFormType( PMBlendMapModifiers::CubicWave ); + break; + case POLY_WAVE_TOK: + nextToken( ); + blend->enableWaveForm( true ); + blend->setWaveFormType( PMBlendMapModifiers::PolyWave ); + if( parseFloat( f_number, true ) ) + blend->setWaveFormExponent( f_number ); + break; + } + } + while( oldConsumed != m_consumedTokens ); + + return true; +} + +bool PMPovrayParser::parseWarp( PMWarp* warp ) +{ + int oldConsumed; + PMVector vector; + double f_number; + int i_number; + bool parsedFirst; + bool mapping; + + if( !parseToken( WARP_TOK, "warp" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + mapping = false; + parsedFirst = false; + do + { + oldConsumed = m_consumedTokens; + if( !parsedFirst && + ( m_token != REPEAT_TOK || + m_token != BLACK_HOLE_TOK || + m_token != TURBULENCE_TOK || + m_token != CYLINDRICAL_TOK || + m_token != SPHERICAL_TOK || + m_token != TOROIDAL_TOK || + m_token != PLANAR_TOK ) ) + { + printError( i18n( "Expecting a warp type" ) ); + return false; + } + switch( m_token ) + { + case REPEAT_TOK: + nextToken( ); + if( !parsedFirst ) + { + warp->setWarpType( PMWarp::Repeat ); + if( !parseVector( vector ) ) + return false; + warp->setDirection( vector ); + parsedFirst = true; + } + else + { + if( !parseVector( vector ) ) + return false; + warp->setRepeat( vector ); + } + break; + case OFFSET_TOK: + nextToken( ); + if( !parseVector( vector ) ) + return false; + warp->setOffset( vector ); + break; + case FLIP_TOK: + nextToken( ); + if( !parseVector( vector ) ) + return false; + warp->setFlip( vector ); + break; + case BLACK_HOLE_TOK: + nextToken( ); + warp->setWarpType( PMWarp::BlackHole ); + if( !parseVector( vector ) ) + return false; + warp->setLocation( vector ); + if( !parseToken( ',' ) ) + return false; + if( !parseFloat( f_number ) ) + return false; + warp->setRadius( f_number ); + parsedFirst = true; + break; + case STRENGTH_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + warp->setStrength( f_number ); + break; + case FALLOFF_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + warp->setFalloff( f_number ); + break; + case INVERSE_TOK: + nextToken( ); + warp->setInverse( true ); + break; + case TURBULENCE_TOK: + if( !parsedFirst ) + { + nextToken( ); + warp->setWarpType( PMWarp::Turbulence ); + if( !parseVector( vector ) ) + return false; + warp->setValueVector( vector ); + parsedFirst = true; + } + else + { + if( !parseVector( vector ) ) + return false; + warp->setTurbulence( vector ); + } + break; + case OCTAVES_TOK: + nextToken( ); + if( !parseInt( i_number ) ) + return false; + warp->setOctaves( i_number ); + break; + case OMEGA_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + warp->setOmega( f_number ); + break; + case LAMBDA_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + warp->setLambda( f_number ); + break; + case CYLINDRICAL_TOK: + warp->setWarpType( PMWarp::Cylindrical ); + mapping = true; + break; + case SPHERICAL_TOK: + warp->setWarpType( PMWarp::Spherical ); + mapping = true; + break; + case TOROIDAL_TOK: + warp->setWarpType( PMWarp::Toroidal ); + mapping = true; + break; + case PLANAR_TOK: + nextToken( ); + warp->setWarpType( PMWarp::Planar ); + if( parseVector( vector ) ) + { + warp->setOrientation( vector ); + if( parseToken( ',' ) ) + { + if( !parseFloat( f_number ) ) + return false; + warp->setDistExp( f_number ); + } + } + parsedFirst = true; + break; + case DIST_EXP_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + warp->setDistExp( f_number ); + break; + case MAJOR_RADIUS_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + warp->setMajorRadius( f_number ); + break; + default: + break; + } + + if( mapping) + { + nextToken( ); + if( !parseVector( vector ) ) + return false; + warp->setOrientation( vector ); + parsedFirst = true; + mapping = false; + } + + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parsePigment( PMPigment* pigment, bool parseOuter ) +{ + PMColor c; + PMSolidColor* sc; + int oldConsumed; + + if( parseOuter ) + { + if( !parseToken( PIGMENT_TOK, "pigment" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + } + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMSymbol* s = getSymbol( id ); + bool skipID = false; + + if( s ) + if( s->type( ) == PMSymbol::Value ) + skipID = true; + + if( !skipID ) + { + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !pigment->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pigment ); + + switch( m_token ) + { + case '<': + case COLOR_TOK: + case COLOUR_TOK: + case RGB_TOK: + case RGBT_TOK: + case RGBF_TOK: + case RGBFT_TOK: + case RED_TOK: + case GREEN_TOK: + case BLUE_TOK: + case TRANSMIT_TOK: + case FILTER_TOK: + case ID_TOK: + if( parseColor( c ) ) + { + sc = new PMSolidColor( m_pPart ); + sc->setColor( c ); + if( !insertChild( sc, pigment ) ) + { + delete sc; + sc = 0; + } + } + break; + case UV_MAPPING_TOK: + nextToken(); + pigment->setUVMapping( parseBool( ) ); + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( parseOuter ) + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseNormal( PMNormal* normal ) +{ + double f_number; + int oldConsumed; + + if( !parseToken( NORMAL_TOK, "normal" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !normal->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( normal ); + switch( m_token ) + { + case BUMP_SIZE_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + normal->enableBumpSize( true ); + normal->setBumpSize( f_number ); + break; + case ACCURACY_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + normal->setAccuracy( f_number ); + break; + case UV_MAPPING_TOK: + nextToken( ); + normal->setUVMapping( parseBool( ) ); + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseTextureMap( PMTextureMap* textureMap ) +{ + int oldConsumed; + double f_number1; + PMTexture* texture; + QValueList mapValues; + + if( !parseToken( TEXTURE_MAP_TOK, "texture_map" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !textureMap->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + + if( m_token == '[' ) + { + nextToken( ); + + if( !parseFloat( f_number1 ) ) + return false; + mapValues.append( f_number1 ); + texture = new PMTexture( m_pPart ); + + parseTexture( texture, false ); + + if( !insertChild( texture, textureMap ) ) + delete texture; + + if( !parseToken( ']' ) ) + return false; + } + } + while( oldConsumed != m_consumedTokens ); + + textureMap->setMapValues( mapValues ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parsePigmentMap( PMPigmentMap* pigmentMap ) +{ + int oldConsumed; + double f_number1; + PMPigment* pigment; + QValueList mapValues; + + if( !parseToken( PIGMENT_MAP_TOK, "pigment_map" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !pigmentMap->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + + if( m_token == '[' ) + { + nextToken( ); + if( !parseFloat( f_number1 ) ) + return false; + mapValues.append( f_number1 ); + pigment = new PMPigment( m_pPart ); + + parsePigment( pigment, false ); + if( !insertChild( pigment, pigmentMap ) ) + delete pigment; + if( !parseToken( ']' ) ) + return false; + } + } + while( oldConsumed != m_consumedTokens ); + + pigmentMap->setMapValues( mapValues ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseNormalMap( PMNormalMap* normalMap ) +{ + int oldConsumed; + double f_number1; + PMNormal* normal; + QValueList mapValues; + + if( !parseToken( NORMAL_MAP_TOK, "normal_map" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !normalMap->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + + // If we find '}' no need to search for an entry + if( m_token != '}' && parseToken( '[' ) ) + { + if( !parseFloat( f_number1 ) ) + return false; + mapValues.append( f_number1 ); + normal = new PMNormal( m_pPart ); + if( !parseNormal( normal ) ) + { + delete normal; + return false; + } + if( !insertChild( normal, normalMap ) ) + delete normal; + if( !parseToken( ']' ) ) + return false; + } + } + while( oldConsumed != m_consumedTokens ); + + normalMap->setMapValues( mapValues ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseBumpMap( PMBumpMap* bumpMap ) +{ + int oldConsumed; + int i_number; + double f_number; + + if( !parseToken( BUMP_MAP_TOK, "bump_map" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + // Parse the bitmap type + if( m_token != STRING_TOK ) + { + switch( m_token ) + { + case GIF_TOK: + bumpMap->setBitmapType( PMBumpMap::BitmapGif ); + nextToken( ); + break; + case TGA_TOK: + bumpMap->setBitmapType( PMBumpMap::BitmapTga ); + nextToken( ); + break; + case IFF_TOK: + bumpMap->setBitmapType( PMBumpMap::BitmapIff ); + nextToken( ); + break; + case PPM_TOK: + bumpMap->setBitmapType( PMBumpMap::BitmapPpm ); + nextToken( ); + break; + case PGM_TOK: + bumpMap->setBitmapType( PMBumpMap::BitmapPgm ); + nextToken( ); + break; + case PNG_TOK: + bumpMap->setBitmapType( PMBumpMap::BitmapPng ); + nextToken( ); + break; + case SYS_TOK: + bumpMap->setBitmapType( PMBumpMap::BitmapSys ); + nextToken( ); + break; + default: + printError( i18n( "Unknown bitmap type" ) ); + return false; + } + } + + // Parse the bitmap file name + if( m_token != STRING_TOK ) + { + printError( i18n( "Expecting a file name." ) ); + return false; + } + else + { + bumpMap->setBitmapFileName( m_pScanner->sValue( ) ); + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + switch( m_token ) + { + case ONCE_TOK: + nextToken( ); + bumpMap->enableOnce( true ); + break; + case MAP_TYPE_TOK: + nextToken( ); + if( !parseInt( i_number ) ) + return false; + switch( i_number ) + { + case 0: + bumpMap->setMapType( PMBumpMap::MapPlanar ); + break; + case 1: + bumpMap->setMapType( PMBumpMap::MapSpherical ); + break; + case 2: + bumpMap->setMapType( PMBumpMap::MapCylindrical ); + break; + case 5: + bumpMap->setMapType( PMBumpMap::MapToroidal ); + break; + } + break; + case INTERPOLATE_TOK: + nextToken( ); + if( !parseInt( i_number ) ) + return false; + switch( i_number ) + { + case 2: + bumpMap->setInterpolateType( PMBumpMap::InterpolateBilinear ); + break; + case 4: + bumpMap->setInterpolateType( PMBumpMap::InterpolateNormalized ); + break; + } + break; + case USE_INDEX_TOK: + nextToken( ); + bumpMap->enableUseIndex( true ); + break; + case BUMP_SIZE_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + bumpMap->setBumpSize( f_number ); + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseMaterialMap( PMMaterialMap* materialMap ) +{ + int oldConsumed; + int i_number; + + if( !parseToken( MATERIAL_MAP_TOK, "material_map" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + // Parse the bitmap type + if( m_token != STRING_TOK ) + { + switch( m_token ) + { + case GIF_TOK: + materialMap->setBitmapType( PMMaterialMap::BitmapGif ); + nextToken( ); + break; + case TGA_TOK: + materialMap->setBitmapType( PMMaterialMap::BitmapTga ); + nextToken( ); + break; + case IFF_TOK: + materialMap->setBitmapType( PMMaterialMap::BitmapIff ); + nextToken( ); + break; + case PPM_TOK: + materialMap->setBitmapType( PMMaterialMap::BitmapPpm ); + nextToken( ); + break; + case PGM_TOK: + materialMap->setBitmapType( PMMaterialMap::BitmapPgm ); + nextToken( ); + break; + case PNG_TOK: + materialMap->setBitmapType( PMMaterialMap::BitmapPng ); + nextToken( ); + break; + case SYS_TOK: + materialMap->setBitmapType( PMMaterialMap::BitmapSys ); + nextToken( ); + break; + default: + printError( i18n( "Unknown bitmap type" ) ); + return false; + } + } + + // Parse the bitmap file name + if( m_token != STRING_TOK ) + { + printError( i18n( "Expecting a file name." ) ); + return false; + } + else + { + materialMap->setBitmapFileName( m_pScanner->sValue( ) ); + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( materialMap ); + switch( m_token ) + { + case ONCE_TOK: + nextToken( ); + materialMap->enableOnce( true ); + break; + case MAP_TYPE_TOK: + nextToken( ); + if( !parseInt( i_number ) ) + return false; + switch( i_number ) + { + case 0: + materialMap->setMapType( PMMaterialMap::MapPlanar ); + break; + case 1: + materialMap->setMapType( PMMaterialMap::MapSpherical ); + break; + case 2: + materialMap->setMapType( PMMaterialMap::MapCylindrical ); + break; + case 5: + materialMap->setMapType( PMMaterialMap::MapToroidal ); + break; + } + break; + case INTERPOLATE_TOK: + nextToken( ); + if( !parseInt( i_number ) ) + return false; + switch( i_number ) + { + case 2: + materialMap->setInterpolateType( PMMaterialMap::InterpolateBilinear ); + break; + case 4: + materialMap->setInterpolateType( PMMaterialMap::InterpolateNormalized ); + break; + } + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseSlopeMap( PMSlopeMap* slopeMap ) +{ + int oldConsumed; + double f_number1; + PMSlope* slope; + QValueList mapValues; + + if( !parseToken( SLOPE_MAP_TOK, "slope_map" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !slopeMap->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + + // If we find '}' no need to search for an entry + if( m_token != '}' && parseToken( '[' ) ) + { + if( !parseFloat( f_number1 ) ) + return false; + mapValues.append( f_number1 ); + slope = new PMSlope( m_pPart ); + if( !parseSlope( slope ) ) + { + delete slope; + return false; + } + if( !insertChild( slope, slopeMap ) ) + delete slope; + if( !parseToken( ']' ) ) + return false; + } + } + while( oldConsumed != m_consumedTokens ); + + slopeMap->setMapValues( mapValues ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseDensityMap( PMDensityMap* densityMap ) +{ + int oldConsumed; + double f_number1; + PMDensity* density; + QValueList mapValues; + + if( !parseToken( DENSITY_MAP_TOK, "density_map" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !densityMap->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + + // If we find '}' no need to search for an entry + if( m_token != '}' && parseToken( '[' ) ) + { + if( !parseFloat( f_number1 ) ) + return false; + mapValues.append( f_number1 ); + density = new PMDensity( m_pPart ); + if( !parseDensity( density ) ) + { + delete density; + return false; + } + if( !insertChild( density, densityMap ) ) + delete density; + if( !parseToken( ']' ) ) + return false; + } + } + while( oldConsumed != m_consumedTokens ); + + densityMap->setMapValues( mapValues ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseImageMap( PMImageMap* imageMap ) +{ + int oldConsumed; + int i_number; + double f_number; + PMPaletteValue newPaletteValue; + QValueList l_valuesFilter; + QValueList l_valuesTransmit; + + if( !parseToken( IMAGE_MAP_TOK, "image_map" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + // Parse the bitmap type + if( m_token != STRING_TOK ) + { + switch( m_token ) + { + case GIF_TOK: + imageMap->setBitmapType( PMImageMap::BitmapGif ); + nextToken( ); + break; + case TGA_TOK: + imageMap->setBitmapType( PMImageMap::BitmapTga ); + nextToken( ); + break; + case IFF_TOK: + imageMap->setBitmapType( PMImageMap::BitmapIff ); + nextToken( ); + break; + case PPM_TOK: + imageMap->setBitmapType( PMImageMap::BitmapPpm ); + nextToken( ); + break; + case PGM_TOK: + imageMap->setBitmapType( PMImageMap::BitmapPgm ); + nextToken( ); + break; + case PNG_TOK: + imageMap->setBitmapType( PMImageMap::BitmapPng ); + nextToken( ); + break; + case SYS_TOK: + imageMap->setBitmapType( PMImageMap::BitmapSys ); + nextToken( ); + break; + default: + printError( i18n( "Unknown bitmap type" ) ); + return false; + } + } + + // Parse the bitmap file name + if( m_token != STRING_TOK ) + { + printError( i18n( "Expecting a file name." ) ); + return false; + } + else + { + imageMap->setBitmapFileName( m_pScanner->sValue( ) ); + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + switch( m_token ) + { + case TRANSMIT_TOK: + nextToken( ); + if( m_token == ALL_TOK ) + { + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + imageMap->enableTransmitAll( true ); + imageMap->setTransmitAll( f_number ); + } + else + { + if( !parseInt( i_number ) ) + return false; + parseToken( ',' ); + if( !parseFloat( f_number ) ) + return false; + newPaletteValue.setIndex( i_number ); + newPaletteValue.setValue( f_number ); + l_valuesTransmit.append( newPaletteValue ); + } + break; + case FILTER_TOK: + nextToken( ); + if( m_token == ALL_TOK ) + { + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + imageMap->enableFilterAll( true ); + imageMap->setFilterAll( f_number ); + } + else + { + if( !parseInt( i_number ) ) + return false; + parseToken( ',' ); + if( !parseFloat( f_number ) ) + return false; + newPaletteValue.setIndex( i_number ); + newPaletteValue.setValue( f_number ); + l_valuesFilter.append( newPaletteValue ); + } + break; + case ONCE_TOK: + nextToken( ); + imageMap->enableOnce( true ); + break; + case MAP_TYPE_TOK: + nextToken( ); + if( !parseInt( i_number ) ) + return false; + switch( i_number ) + { + case 0: + imageMap->setMapType( PMImageMap::MapPlanar ); + break; + case 1: + imageMap->setMapType( PMImageMap::MapSpherical ); + break; + case 2: + imageMap->setMapType( PMImageMap::MapCylindrical ); + break; + case 5: + imageMap->setMapType( PMImageMap::MapToroidal ); + break; + } + break; + case INTERPOLATE_TOK: + nextToken( ); + if( !parseInt( i_number ) ) + return false; + switch( i_number ) + { + case 2: + imageMap->setInterpolateType( PMImageMap::InterpolateBilinear ); + break; + case 4: + imageMap->setInterpolateType( PMImageMap::InterpolateNormalized ); + break; + } + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + imageMap->setFilters( l_valuesFilter ); + imageMap->setTransmits( l_valuesTransmit ); + + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parsePigmentList( PMPigmentList* pigmentList, int expectedItems ) +{ + int oldConsumed; + PMPigment* pigment; + + do + { + oldConsumed = m_consumedTokens; + pigment = new PMPigment( m_pPart ); + if( !parsePigment( pigment ) ) + { + delete pigment; + return false; + } + if( !insertChild( pigment, pigmentList ) ) + delete pigment; + + // In the last entry don't expect a comma + if( expectedItems-- ) + if( m_token == ',' ) + nextToken( ); + } + while( oldConsumed != m_consumedTokens && expectedItems ); + + return true; +} + +bool PMPovrayParser::parseColorList( PMColorList* colorList, int expectedItems ) +{ + int oldConsumed; + PMColor color; + PMSolidColor* sc; + + do + { + oldConsumed = m_consumedTokens; + if( !parseColor( color ) ) + { + return false; + } + sc = new PMSolidColor( m_pPart ); + sc->setColor( color ); + if( !insertChild( sc, colorList ) ) + delete sc; + + // In the last entry don't expect a comma + if( expectedItems-- ) + if( m_token == ',' ) + nextToken( ); + } + while( oldConsumed != m_consumedTokens && expectedItems ); + + return true; +} + +bool PMPovrayParser::parseNormalList( PMNormalList* normalList, int expectedItems ) +{ + int oldConsumed; + PMNormal* normal; + + do + { + oldConsumed = m_consumedTokens; + normal = new PMNormal( m_pPart ); + if( !parseNormal( normal ) ) + { + delete normal; + return false; + } + if( !insertChild( normal, normalList ) ) + delete normal; + + // In the last entry don't expect a comma + if( expectedItems-- ) + if( m_token == ',' ) + nextToken( ); + } + while( oldConsumed != m_consumedTokens && expectedItems ); + + return true; +} + +bool PMPovrayParser::parseTextureList( PMTextureList* textureList, int expectedItems ) +{ + int oldConsumed; + PMTexture* texture; + + do + { + oldConsumed = m_consumedTokens; + texture = new PMTexture( m_pPart ); + if( !parseTexture( texture ) ) + { + delete texture; + return false; + } + if( !insertChild( texture, textureList ) ) + delete texture; + + // In the last entry don't expect a comma + if( expectedItems-- ) + if( m_token == ',' ) + nextToken( ); + } + while( oldConsumed != m_consumedTokens && expectedItems ); + + return true; +} + +bool PMPovrayParser::parseDensityList( PMDensityList* densityList, int expectedItems ) +{ + int oldConsumed; + PMDensity* density; + + do + { + oldConsumed = m_consumedTokens; + density = new PMDensity( m_pPart ); + if( !parseDensity( density ) ) + { + delete density; + return false; + } + if( !insertChild( density, densityList ) ) + delete density; + + // In the last entry don't expect a comma + if( expectedItems-- ) + if( m_token == ',' ) + nextToken( ); + } + while( oldConsumed != m_consumedTokens && expectedItems ); + + return true; +} + +bool PMPovrayParser::parseColorMap( PMColorMap* colorMap ) +{ + int oldConsumed; + double f_number1, f_number2; + PMColor color1, color2; + PMSolidColor* solidColor; + PMSolidColor* lastColor = 0; + QValueList mapValues; + bool newEntry; + bool twoColors; + + if( m_token != COLOR_MAP_TOK && m_token != COLOUR_MAP_TOK ) + return false; + nextToken( ); + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !colorMap->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + + if( m_token == '[' ) + { + nextToken( ); + if( !parseFloat( f_number1 ) ) + return false; + + twoColors = false; + if( m_token == ',' ) + { + twoColors = true; + nextToken( ); + } + else if( ( m_token == INTEGER_TOK ) || ( m_token == FLOAT_TOK ) ) + twoColors = true; + + if( twoColors ) + { + // Two colors in the same entry + + if( parseFloat( f_number2 ) ) + { + if( !parseColor( color1 ) ) + return false; + if( !parseColor( color2 ) ) + return false; + // If the first value doesn't pick up from the previous, + // or the color is different... + newEntry = true; + if( lastColor && !mapValues.isEmpty( ) ) + if( ( mapValues.last( ) == f_number1 ) && + ( lastColor->color( ) == color1 ) ) + newEntry = false; + + if( newEntry ) + { + // ... add the two colors in two different entries ... + mapValues.append( f_number1 ); + solidColor = new PMSolidColor( m_pPart ); + solidColor->setColor( color1 ); + if( !insertChild( solidColor, colorMap ) ) + delete solidColor; + else + lastColor = solidColor; + + mapValues.append( f_number2 ); + solidColor = new PMSolidColor( m_pPart ); + solidColor->setColor( color2 ); + if( !insertChild( solidColor, colorMap ) ) + delete solidColor; + else + lastColor = solidColor; + } + else + { + // ... else just add the last value and color + mapValues.append( f_number2 ); + solidColor = new PMSolidColor( m_pPart ); + solidColor->setColor( color2 ); + if( !insertChild( solidColor, colorMap ) ) + delete solidColor; + else + lastColor = solidColor; + } + } + } + else + { + // Only one color in the entry + if( !parseColor( color1 ) ) + return false; + mapValues.append( f_number1 ); + solidColor = new PMSolidColor( m_pPart ); + solidColor->setColor( color1 ); + if( !insertChild( solidColor, colorMap ) ) + delete solidColor; + else + lastColor = solidColor; + } + if( !parseToken( ']' ) ) + return false; + } + } + while( oldConsumed != m_consumedTokens ); + + colorMap->setMapValues( mapValues ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseSkySphere( PMSkySphere* sky ) +{ + int oldConsumed; + + if( !parseToken( SKY_SPHERE_TOK, "sky_sphere" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !sky->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( sky ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseRainbow( PMRainbow* rainbow ) +{ + PMVector vector; + double f_number; + int oldConsumed; + + if( !parseToken( RAINBOW_TOK, "rainbow" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !rainbow->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( rainbow ); + switch( m_token ) + { + case DIRECTION_TOK: + nextToken( ); + if( parseVector( vector ) ) + { + rainbow->enableDirection( true ); + rainbow->setDirection( vector ); + } + break; + case ANGLE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + rainbow->enableAngle( true ); + rainbow->setAngle( f_number ); + } + break; + case WIDTH_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + rainbow->enableWidth( true ); + rainbow->setWidth( f_number ); + } + break; + case DISTANCE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + rainbow->enableDistance( true ); + rainbow->setDistance( f_number ); + } + break; + case JITTER_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + rainbow->enableJitter( true ); + rainbow->setJitter( f_number ); + } + break; + case UP_TOK: + nextToken( ); + if( parseVector( vector ) ) + { + rainbow->enableUp( true ); + rainbow->setUp( vector ); + } + break; + case ARC_ANGLE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + rainbow->enableArcAngle( true ); + rainbow->setArcAngle( f_number ); + } + break; + case FALLOFF_ANGLE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + rainbow->enableFalloffAngle( true ); + rainbow->setFalloffAngle( f_number ); + } + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseFog( PMFog* fog ) +{ + PMColor color; + PMVector vector; + double f_number; + int i_number; + int fog_type; + int oldConsumed; + + if( !parseToken( FOG_TOK, "fog" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !fog->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + fog_type = 1; + if( parseToken( FOG_TYPE_TOK, "fog_type" ) ) + { + if( !parseInt( i_number ) ) + return false; + fog_type = i_number; + } + + do + { + oldConsumed = m_consumedTokens; + switch( m_token ) + { + case DISTANCE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + fog->setDistance( f_number ); + break; + case '<': + case COLOR_TOK: + case COLOUR_TOK: + case RGB_TOK: + case RGBT_TOK: + case RGBF_TOK: + case RGBFT_TOK: + case RED_TOK: + case GREEN_TOK: + case BLUE_TOK: + case TRANSMIT_TOK: + case FILTER_TOK: + case ID_TOK: + if( parseColor( color ) ) + fog->setColor( color ); + break; + case TURBULENCE_TOK: + nextToken( ); + fog->enableTurbulence( true ); + if( !parseVector( vector ) ) + return false; + fog->setValueVector( vector ); + break; + case OCTAVES_TOK: + nextToken( ); + if( !parseInt( i_number ) ) + return false; + fog->setOctaves( i_number ); + break; + case OMEGA_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + fog->setOmega( f_number ); + break; + case LAMBDA_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + fog->setLambda( f_number ); + break; + case TURB_DEPTH_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + fog->setDepth( f_number ); + break; + case FOG_OFFSET_TOK: + nextToken( ); + fog_type = 2; + if( parseFloat( f_number ) ) + fog->setFogOffset( f_number ); + break; + case FOG_ALT_TOK: + nextToken( ); + fog_type = 2; + if( parseFloat( f_number ) ) + fog->setFogAlt( f_number ); + break; + case UP_TOK: + nextToken( ); + fog_type = 2; + if( !parseVector( vector ) ) + return false; + fog->setUp( vector ); + break; + default: + break; + } + // Only parseChildObjects() if the token is not turbulence, because this + // function parses that token. + if( m_token != TURBULENCE_TOK ) + parseChildObjects( fog ); + } + while( oldConsumed != m_consumedTokens ); + + fog->setFogType( fog_type ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseMedia( PMMedia* media ) +{ + PMColor color; + double f_number; + int i_number; + int oldConsumed, oldConsumed1; + + if( !parseToken( MEDIA_TOK, "media" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !media->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( media ); + switch( m_token ) + { + case METHOD_TOK: + nextToken( ); + if( parseInt( i_number ) ) + media->setMethod( i_number ); + break; + case INTERVALS_TOK: + nextToken( ); + if( parseInt( i_number ) ) + media->setIntervals( i_number ); + break; + case SAMPLES_TOK: + nextToken( ); + if( parseInt( i_number ) ) + media->setSamplesMin( i_number ); + parseToken( ',' ); + if( parseInt( i_number ) ) + media->setSamplesMax( i_number ); + break; + case CONFIDENCE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + media->setConfidence( f_number ); + break; + case VARIANCE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + media->setVariance( f_number ); + break; + case RATIO_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + media->setRatio( f_number ); + break; + case AA_LEVEL_TOK: + nextToken( ); + if ( parseInt( i_number ) ) + media->setAALevel( i_number ); + break; + case AA_THRESHOLD_TOK: + nextToken( ); + if ( parseFloat( f_number ) ) + media->setAAThreshold( f_number ); + break; + case ABSORPTION_TOK: + nextToken( ); + if( parseColor( color ) ) + { + media->enableAbsorption( true ); + media->setAbsorption( color ); + } + break; + case EMISSION_TOK: + nextToken( ); + media->enableEmission( true ); + if( parseColor( color ) ) + media->setEmission( color ); + break; + case SCATTERING_TOK: + nextToken( ); + parseToken( '{' ); + media->enableScattering( true ); + if( parseInt( i_number ) ) + media->setScatteringType( i_number ); + parseToken( ',' ); + if( parseColor( color ) ) + media->setScatteringColor( color ); + do + { + oldConsumed1 = m_consumedTokens; + switch( m_token ) + { + case ECCENTRICITY_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + media->setScatteringEccentricity( f_number ); + break; + case EXTINCTION_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + media->setScatteringExtinction( f_number ); + break; + default: + break; + } + } + while( oldConsumed1 != m_consumedTokens ); + parseToken( '}' ); + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseDensity( PMDensity* density ) +{ + int oldConsumed; + + if( !parseToken( DENSITY_TOK, "density" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !density->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( density ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseInterior( PMInterior* interior ) +{ + double f_number; + int i_number; + int oldConsumed; + + if( !parseToken( INTERIOR_TOK, "interior" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !interior->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( interior ); + switch( m_token ) + { + case IOR_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + interior->enableIor( true ); + interior->setIor( f_number ); + } + break; + case CAUSTICS_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + interior->enableCaustics( true ); + interior->setCaustics( f_number ); + } + break; + case DISPERSION_TOK: + nextToken( ); + if ( parseFloat( f_number ) ) + { + interior->enableDispersion( true ); + interior->setDispersion( f_number ); + } + break; + case DISPERSION_SAMPLES_TOK: + nextToken( ); + if ( parseInt( i_number ) ) + { + interior->enableDispSamples( true ); + interior->setDispSamples( i_number ); + } + break; + case FADE_DISTANCE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + interior->enableFadeDistance( true ); + interior->setFadeDistance( f_number ); + } + break; + case FADE_POWER_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + interior->enableFadePower( true ); + interior->setFadePower( f_number ); + } + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseMaterial( PMMaterial* material ) +{ + int oldConsumed; + + if( !parseToken( MATERIAL_TOK, "material" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !material->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( material ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseSlope( PMSlope* slope ) +{ + double f_number; + + if( !parseToken( '<' ) ) + return false; + if( !parseFloat( f_number ) ) + return false; + slope->setHeight( f_number ); + if( !parseToken( ',' ) ) + return false; + if( !parseFloat( f_number ) ) + return false; + slope->setSlope( f_number ); + if( !parseToken( '>' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseGlobalSettings( PMGlobalSettings* globalsettings ) +{ + PMColor color; + double f_number; + int i_number; + int oldConsumed; + + // Initial global settings tokens + if( !parseToken( GLOBAL_SETTINGS_TOK, "global_settings" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + // Parse global settings tokens + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( globalsettings ); + + switch( m_token ) + { + case ADC_BAILOUT_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + globalsettings->setAdcBailout( f_number ); + break; + case AMBIENT_LIGHT_TOK: + nextToken( ); + if( parseColor( color ) ) + globalsettings->setAmbientLight( color ); + break; + case ASSUMED_GAMMA_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + globalsettings->setAssumedGamma( f_number ); + break; + case HF_GRAY_16_TOK: + nextToken( ); + switch( m_token ) + { + case ON_TOK: + globalsettings->setHfGray16( true ); + nextToken( ); + break; + case OFF_TOK: + globalsettings->setHfGray16( false ); + nextToken( ); + break; + default: + break; + } + break; + case IRID_WAVELENGTH_TOK: + nextToken( ); + if( parseColor( color ) ) + globalsettings->setIridWaveLength( color ); + break; + case MAX_INTERSECTIONS_TOK: + nextToken( ); + if( parseInt( i_number ) ) + globalsettings->setMaxIntersections( i_number ); + break; + case MAX_TRACE_LEVEL_TOK: + nextToken( ); + if( parseInt( i_number ) ) + globalsettings->setMaxTraceLevel( i_number ); + break; + case NUMBER_OF_WAVES_TOK: + nextToken( ); + if( parseInt( i_number ) ) + globalsettings->setNumberWaves( i_number ); + break; + case NOISE_GENERATOR_TOK: + nextToken( ); + if ( parseInt( i_number ) ) + globalsettings->setNoiseGenerator( + ( PMGlobalSettings::PMNoiseType ) ( i_number - 1 ) ); + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseFinish( PMFinish* finish ) +{ + PMColor color; + double f_number; + int oldConsumed, oldConsumed1; + + // Initial finish tokens "finish {" + if( !parseToken( FINISH_TOK, "finish" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + // Parse a possible declare link identifier + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !finish->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + // Parse finish tokens + do + { + oldConsumed = m_consumedTokens; + switch( m_token ) + { + case AMBIENT_TOK: + nextToken( ); + finish->enableAmbient( true ); + if( parseColor( color ) ) + finish->setAmbientColor( color ); + break; + case DIFFUSE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + finish->enableDiffuse( true ); + finish->setDiffuse( f_number ); + } + break; + case BRILLIANCE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + finish->enableBrilliance( true ); + finish->setBrilliance( f_number ); + } + break; + case PHONG_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + finish->enablePhong( true ); + finish->setPhong( f_number ); + } + break; + case PHONG_SIZE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + finish->enablePhongSize( true ); + finish->setPhongSize( f_number ); + } + break; + case METALLIC_TOK: + nextToken( ); + finish->enableMetallic( true ); + finish->setMetallic( 1.0 ); + if( parseFloat( f_number, true ) ) + finish->setMetallic( f_number ); + break; + case SPECULAR_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + finish->enableSpecular( true ); + finish->setSpecular( f_number ); + } + break; + case ROUGHNESS_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + finish->enableRoughness( true ); + finish->setRoughness( f_number ); + } + break; + case CRAND_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + finish->enableCrand( true ); + finish->setCrand( f_number ); + } + break; + case CONSERVE_ENERGY_TOK: + nextToken( ); + finish->setConserveEnergy( parseBool( ) ); + break; + case REFLECTION_TOK: + nextToken( ); + finish->enableReflection( true ); + if( !parseToken( '{' ) ) + { + printError( i18n( "Using Old Reflection Syntax" ) ); + if( parseColor( color ) ) + finish->setReflectionColor( color ); + } + else if( parseColor( color ) ) + { + if( parseToken( ',' ) ) + { + finish->enableReflectionMin( true ); + finish->setReflectionMinColor( color ); + if( parseColor( color ) ) + finish->setReflectionColor( color ); + else + return false; + } + else + finish->setReflectionColor( color ); + + do + { + oldConsumed1 = m_consumedTokens; + switch( m_token ) + { + case FRESNEL_TOK: + nextToken( ); + finish->setReflectionFresnel( parseBool( ) ); + break; + case FALLOFF_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + finish->enableRefFalloff( true ); + finish->setReflectionFalloff( f_number ); + } + break; + case EXPONENT_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + finish->enableRefExponent( true ); + finish->setReflectionExponent( f_number ); + } + break; + case METALLIC_TOK: + nextToken( ); + if ( parseFloat( f_number ) ) + { + finish->enableRefMetallic( true ); + finish->setReflectionMetallic( f_number ); + } + break; + default: + break; + } + } + while( oldConsumed1 != m_consumedTokens ); + parseToken( '}' ); + } + else + return false; + break; + case REFLECTION_EXPONENT_TOK: + nextToken( ); + if ( parseFloat( f_number ) ) + { + finish->enableRefExponent( true ); + finish->setReflectionExponent( f_number ); + } + break; + case IRID_TOK: + nextToken( ); + parseToken( '{' ); + finish->setIrid( true ); + if( parseFloat( f_number ) ) + finish->setIridAmount( f_number ); + do + { + oldConsumed1 = m_consumedTokens; + switch( m_token ) + { + case THICKNESS_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + finish->setIridThickness( f_number ); + break; + case TURBULENCE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + finish->setIridTurbulence( f_number ); + break; + default: + break; + } + } + while( oldConsumed1 != m_consumedTokens ); + parseToken( '}' ); + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseDeclare( PMDeclare* decl ) +{ + PMObject* child = 0; + PMTexture* texture = 0; + bool error = false; + + switch( m_token ) + { + case OBJECT_TOK: + error = !parseObject( decl ); + break; + // finite solid + case BLOB_TOK: + child = new PMBlob( m_pPart ); + error = !parseBlob( ( PMBlob* ) child ); + break; + case BOX_TOK: + child = new PMBox( m_pPart ); + error = !parseBox( ( PMBox* ) child ); + break; + case CONE_TOK: + child = new PMCone( m_pPart ); + error = !parseCone( ( PMCone* ) child ); + break; + case CYLINDER_TOK: + child = new PMCylinder( m_pPart ); + error = !parseCylinder( ( PMCylinder* ) child ); + break; + case HEIGHT_FIELD_TOK: + child = new PMHeightField( m_pPart ); + error = !parseHeightField( ( PMHeightField* ) child ); + break; + case JULIA_FRACTAL_TOK: + child = new PMJuliaFractal( m_pPart ); + error = !parseJuliaFractal( ( PMJuliaFractal* ) child ); + break; + case LATHE_TOK: + child = new PMLathe( m_pPart ); + error = !parseLathe( ( PMLathe* ) child ); + break; + case PRISM_TOK: + child = new PMPrism( m_pPart ); + error = !parsePrism( ( PMPrism* ) child ); + break; + case SPHERE_TOK: + child = new PMSphere( m_pPart ); + error = !parseSphere( ( PMSphere* ) child ); + break; + case SUPERELLIPSOID_TOK: + child = new PMSuperquadricEllipsoid( m_pPart ); + error = !parseSqe( ( PMSuperquadricEllipsoid* ) child ); + break; + case SOR_TOK: + child = new PMSurfaceOfRevolution( m_pPart ); + error = !parseSor( ( PMSurfaceOfRevolution* ) child ); + break; + case TEXT_TOK: + child = new PMText( m_pPart ); + error = !parseText( ( PMText* ) child ); + break; + case TORUS_TOK: + child = new PMTorus( m_pPart ); + error = !parseTorus( ( PMTorus* ) child ); + break; + // finite patch + case BICUBIC_PATCH_TOK: + child = new PMBicubicPatch( m_pPart ); + error = !parseBicubicPatch( ( PMBicubicPatch* ) child ); + break; + case DISC_TOK: + child = new PMDisc( m_pPart ); + error = !parseDisc( ( PMDisc* ) child ); + break; + case TRIANGLE_TOK: + case SMOOTH_TRIANGLE_TOK: + child = new PMTriangle( m_pPart ); + error = !parseTriangle( ( PMTriangle* ) child ); + break; + // infinite solid + case PLANE_TOK: + child = new PMPlane( m_pPart ); + error = !parsePlane( ( PMPlane* ) child ); + break; + case QUADRIC_TOK: + case CUBIC_TOK: + case QUARTIC_TOK: + case POLY_TOK: + child = new PMPolynom( m_pPart ); + error = !parsePolynom( ( PMPolynom* ) child ); + break; + // csg + case UNION_TOK: + case DIFFERENCE_TOK: + case INTERSECTION_TOK: + case MERGE_TOK: + child = new PMCSG( m_pPart ); + error = !parseCSG( ( PMCSG* ) child ); + break; + // textures + case TEXTURE_TOK: + while( m_token == TEXTURE_TOK ) + { + texture = new PMTexture( m_pPart ); + if( !parseTexture( texture ) ) + error = true; + if( !insertChild( texture, decl ) ) + { + delete texture; + texture = 0; + } + } + break; + case PIGMENT_TOK: + child = new PMPigment( m_pPart ); + error = !parsePigment( ( PMPigment* ) child ); + break; + case NORMAL_TOK: + child = new PMNormal( m_pPart ); + error = !parseNormal( ( PMNormal* ) child ); + break; + case FINISH_TOK: + child = new PMFinish( m_pPart ); + error = !parseFinish( ( PMFinish* ) child ); + break; + case TEXTURE_MAP_TOK: + child = new PMTextureMap( m_pPart ); + error = !parseTextureMap( ( PMTextureMap* ) child ); + break; + case PIGMENT_MAP_TOK: + child = new PMPigmentMap( m_pPart ); + error = !parsePigmentMap( ( PMPigmentMap* ) child ); + break; + case COLOR_MAP_TOK: + case COLOUR_MAP_TOK: + child = new PMColorMap( m_pPart ); + error = !parseColorMap( ( PMColorMap* ) child ); + break; + case NORMAL_MAP_TOK: + child = new PMNormalMap( m_pPart ); + error = !parseNormalMap( ( PMNormalMap* ) child ); + break; + case SLOPE_MAP_TOK: + child = new PMSlopeMap( m_pPart ); + error = !parseSlopeMap( ( PMSlopeMap* ) child ); + break; + case DENSITY_MAP_TOK: + child = new PMDensityMap( m_pPart ); + error = !parseDensityMap( ( PMDensityMap* ) child ); + break; + case INTERIOR_TOK: + child = new PMInterior( m_pPart ); + error = !parseInterior( ( PMInterior* ) child ); + break; + case MEDIA_TOK: + child = new PMMedia( m_pPart ); + error = !parseMedia( ( PMMedia* ) child ); + break; + case DENSITY_TOK: + child = new PMDensity( m_pPart ); + error = !parseDensity( ( PMDensity* ) child ); + break; + case MATERIAL_TOK: + child = new PMMaterial( m_pPart ); + error = !parseMaterial( ( PMMaterial* ) child ); + break; + case SKY_SPHERE_TOK: + child = new PMSkySphere( m_pPart ); + error = !parseSkySphere( ( PMSkySphere* ) child ); + break; + case RAINBOW_TOK: + child = new PMRainbow( m_pPart ); + error = !parseRainbow( ( PMRainbow* ) child ); + break; + case FOG_TOK: + child = new PMFog( m_pPart ); + error = !parseFog( ( PMFog* ) child ); + break; + // misc + case LIGHT_SOURCE_TOK: + child = new PMLight( m_pPart ); + error = !parseLight( ( PMLight* ) child ); + break; + case ISOSURFACE_TOK: + child = new PMIsoSurface( m_pPart ); + error = !parseIsoSurface( ( PMIsoSurface* ) child ); + break; + case PHOTONS_TOK: + child = new PMPhotons( m_pPart ); + error = !parsePhotons( ( PMPhotons* ) child ); + break; + case LIGHT_GROUP_TOK: + child = new PMLightGroup( m_pPart ); + error = !parseLightGroup( ( PMLightGroup* ) child ); + break; + case INTERIOR_TEXTURE_TOK: + child = new PMInteriorTexture( m_pPart ); + error = !parseInteriorTexture( ( PMInteriorTexture* ) child ); + break; + case SPHERE_SWEEP_TOK: + child = new PMSphereSweep( m_pPart ); + error = !parseSphereSweep( ( PMSphereSweep* ) child ); + break; + case MESH_TOK: + child = new PMMesh( m_pPart ); + error = !parseMesh( ( PMMesh* ) child ); + break; + } + + if( child ) + { + if( !insertChild( child, decl ) ) + { + delete child; + child = 0; + } + } + return !error; +} + +bool PMPovrayParser::parseObject( PMCompositeObject* parent ) +{ + PMObject* child; + bool error = false; + if( !parseToken( OBJECT_TOK, "object" ) ) + return false; + + if( parseToken( '{' ) ) + { + switch( m_token ) + { + case ID_TOK: + child = new PMObjectLink( m_pPart ); + error = !parseObjectLink( ( PMObjectLink* ) child ); + if( !insertChild( child, parent ) ) + delete child; + break; + default: + { + PMObject* lastChild = 0; + if( parent ) + lastChild = parent->lastChild( ); + else + lastChild = m_pResultList->last( ); + + error = !parseChildObjects( parent, 1 ); + if( !error ) + { + PMObject* newLast = 0; + if( parent ) + newLast = parent->lastChild( ); + else + newLast = m_pResultList->last( ); + + if( newLast && ( newLast != lastChild ) && + newLast->isA( "CompositeObject" ) ) + { + // one child was parsed + // append all following objects + error = !parseChildObjects( ( PMCompositeObject* ) newLast ); + } + else + { + printError( i18n( "One graphical object expected" ) ); + error = true; + } + } + break; + } + } + if( !parseToken( '}' )) + error = true; + } + else + error = true; + return !error; +} + +bool PMPovrayParser::parseObjectLink( PMObjectLink* link ) +{ + int oldConsumed; + + if( m_token != ID_TOK ) + { + printExpected( "identifier", m_pScanner->sValue( ) ); + return false; + } + + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !link->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( link ); + parseObjectModifiers( link ); + } + while( oldConsumed != m_consumedTokens ); + + return true; +} + +bool PMPovrayParser::parseIsoSurface( PMIsoSurface* iso ) +{ + PMVector vector; + double f; + int i; + int oldConsumed; + + if( !parseToken( ISOSURFACE_TOK, "isosurface" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( iso ); + parseObjectModifiers( iso ); + + switch( m_token ) + { + case FUNCTION_TOK: + nextToken( ); + if( m_token != '{' ) + { + printExpected( '{', m_pScanner->sValue( ) ); + return false; + } + + m_pScanner->scanFunction( ); + nextToken( ); + if( m_token != FUNCTION_TOK ) + return false; + iso->setFunction( QString( m_pScanner->sValue( ) ).simplifyWhiteSpace( ) ); + + nextToken( ); + parseToken( '}' ); + + break; + case CONTAINED_BY_TOK: + nextToken( ); + + if( !parseToken( '{' ) ) + return false; + + if( m_token == BOX_TOK ) + { + iso->setContainedBy( PMIsoSurface::Box ); + nextToken( ); + parseToken( '{' ); + if( parseVector( vector ) ) + iso->setCorner1( vector ); + parseToken( ',' ); + if( parseVector( vector ) ) + iso->setCorner2( vector ); + if( !parseToken( '}' ) ) + return false; + } + else if( m_token == SPHERE_TOK ) + { + iso->setContainedBy( PMIsoSurface::Sphere ); + nextToken( ); + parseToken( '{' ); + if( parseVector( vector ) ) + iso->setCenter( vector ); + parseToken( ',' ); + if( parseFloat( f ) ) + iso->setRadius( f ); + if( !parseToken( '}' ) ) + return false; + } + else + { + printUnexpected( m_pScanner->sValue( ) ); + return false; + } + + if( !parseToken( '}' ) ) + return false; + break; + case THRESHOLD_TOK: + nextToken( ); + if( parseFloat( f ) ) + iso->setThreshold( f ); + break; + case ACCURACY_TOK: + nextToken( ); + if( parseFloat( f ) ) + iso->setAccuracy( f ); + break; + case MAX_GRADIENT_TOK: + nextToken( ); + if( parseFloat( f ) ) + iso->setMaxGradient( f ); + break; + case EVALUATE_TOK: + nextToken( ); + iso->setEvaluate( true ); + if( parseFloat( f ) ) + { + iso->setEvaluateValue( 0, f ); + if( parseToken( ',' ) && parseFloat( f ) ) + { + iso->setEvaluateValue( 1, f ); + if( parseToken( ',' ) && parseFloat( f ) ) + iso->setEvaluateValue( 2, f ); + } + } + break; + case OPEN_TOK: + nextToken( ); + iso->setOpen( true ); + break; + case MAX_TRACE_TOK: + nextToken( ); + if( parseInt( i ) ) + iso->setMaxTrace( i ); + break; + case ALL_INTERSECTIONS_TOK: + nextToken( ); + iso->setAllIntersections( true ); + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseRadiosity( PMRadiosity* rad ) +{ + double f; + int i; + int oldConsumed; + + + if( !parseToken( RADIOSITY_TOK, "radiosity" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + do + { + oldConsumed = m_consumedTokens; + switch( m_token ) + { + case ADC_BAILOUT_TOK: + nextToken( ); + if( parseFloat( f ) ) + rad->setAdcBailout( f ); + break; + case ALWAYS_SAMPLE_TOK: + nextToken( ); + rad->setAlwaysSample( parseBool( ) ); + break; + case BRIGHTNESS_TOK: + nextToken( ); + if( parseFloat( f ) ) + rad->setBrightness( f ); + break; + case COUNT_TOK: + nextToken( ); + if( parseInt( i ) ) + rad->setCount( i ); + break; + case ERROR_BOUND_TOK: + nextToken( ); + if( parseFloat( f ) ) + rad->setErrorBound( f ); + break; + case GRAY_THRESHOLD_TOK: + nextToken( ); + if( parseFloat( f ) ) + rad->setGrayThreshold( f ); + break; + case LOW_ERROR_FACTOR_TOK: + nextToken( ); + if( parseFloat( f ) ) + rad->setLowErrorFactor( f ); + break; + case MAX_SAMPLE_TOK: + nextToken( ); + if ( parseFloat( f ) ) + rad->setMaxSample( f ); + break; + case MEDIA_TOK: + nextToken( ); + rad->setMedia( parseBool( ) ); + break; + case MINIMUM_REUSE_TOK: + nextToken( ); + if( parseFloat( f ) ) + rad->setMinimumReuse( f ); + break; + case NEAREST_COUNT_TOK: + nextToken( ); + if( parseInt( i ) ) + rad->setNearestCount( i ); + break; + case NORMAL_TOK: + nextToken( ); + rad->setNormal( parseBool( ) ); + break; + case PRETRACE_START_TOK: + nextToken( ); + if( parseFloat( f ) ) + rad->setPretraceStart( f ); + break; + case PRETRACE_END_TOK: + nextToken( ); + if( parseFloat( f ) ) + rad->setPretraceEnd( f ); + break; + case RECURSION_LIMIT_TOK: + nextToken( ); + if( parseInt( i) ) + rad->setRecursionLimit( i ); + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseGlobalPhotons( PMGlobalPhotons* gp ) +{ + double f; + int i; + int oldConsumed; + + + if( !parseToken( PHOTONS_TOK, "photons" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + do + { + oldConsumed = m_consumedTokens; + switch( m_token ) + { + case SPACING_TOK: + gp->setNumberType( PMGlobalPhotons::Spacing ); + nextToken( ); + if ( parseFloat( f ) ) + gp->setSpacing( f ); + break; + case COUNT_TOK: + gp->setNumberType( PMGlobalPhotons::Count ); + nextToken( ); + if ( parseInt( i ) ) + gp->setCount( i ); + break; + case GATHER_TOK: + nextToken( ); + if ( parseInt( i ) ) + { + gp->setGatherMin( i ); + if ( parseToken( ',' ) && parseInt( i ) ) + gp->setGatherMax( i ); + } + break; + case MEDIA_TOK: + nextToken( ); + if ( parseInt( i ) ) + { + gp->setMediaMaxSteps( i ); + if ( parseToken( ',' ) && parseFloat( f ) ) + gp->setMediaFactor( f ); + } + case JITTER_TOK: + nextToken( ); + if ( parseFloat( f ) ) + gp->setJitter( f ); + break; + case MAX_TRACE_LEVEL_TOK: + nextToken( ); + gp->setMaxTraceLevelGlobal( false ); + if ( parseInt( i ) ) + gp->setMaxTraceLevel( i ); + break; + case ADC_BAILOUT_TOK: + nextToken( ); + gp->setAdcBailoutGlobal( false ); + if ( parseFloat( f ) ) + gp->setAdcBailout( f ); + break; + case AUTOSTOP_TOK: + nextToken( ); + if ( parseFloat( f ) ) + gp->setAutostop( f ); + break; + case EXPAND_THRESHOLDS_TOK: + nextToken( ); + if ( parseFloat( f ) ) + { + gp->setExpandIncrease( f ); + if ( parseToken( ',' ) && parseInt( i ) ) + gp->setExpandMin( i ); + } + break; + case RADIUS_TOK: + nextToken( ); + if ( parseFloat( f ) ) + { + gp->setRadiusGather( f ); + if ( parseToken( ',' ) && parseFloat( f ) ) + { + gp->setRadiusGatherMulti( f ); + if ( parseToken( ',' ) && parseFloat( f ) ) + { + gp->setRadiusMedia( f ); + if ( parseToken( ',' ) && parseFloat( f ) ) + gp->setRadiusMediaMulti( f ); + } + } + } + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parsePhotons( PMPhotons* p ) +{ + double f; + int oldConsumed; + + if( !parseToken( PHOTONS_TOK, "photons" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + p->setTarget( false ); + + do + { + oldConsumed = m_consumedTokens; + switch( m_token ) + { + case TARGET_TOK: + nextToken( ); + p->setTarget( true ); + if ( parseFloat( f ) ) + p->setSpacingMulti( f ); + break; + case REFRACTION_TOK: + nextToken( ); + p->setRefraction( parseBool( ) ); + break; + case REFLECTION_TOK: + nextToken( ); + p->setReflection( parseBool( ) ); + break; + case COLLECT_TOK: + nextToken( ); + p->setCollect( parseBool( ) ); + break; + case PASS_THROUGH_TOK: + nextToken( ); + p->setPassThrough( parseBool( ) ); + break; + case AREA_LIGHT_TOK: + nextToken( ); + p->setAreaLight( parseBool( ) ); + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseLightGroup( PMLightGroup* lg ) +{ + int oldConsumed; + + if ( !parseToken( LIGHT_GROUP_TOK, "light_group" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + do + { + oldConsumed = m_consumedTokens; + if ( m_token == GLOBAL_LIGHTS_TOK ) + { + nextToken( ); + lg->setGlobalLights( parseBool( ) ); + } + else + { + parseChildObjects( lg ); + parseObjectModifiers( lg ); + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseInteriorTexture( PMInteriorTexture* it ) +{ + int oldConsumed; + + if( !parseToken( INTERIOR_TEXTURE_TOK, "interior_texture" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( it ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseSphereSweep( PMSphereSweep* ss ) +{ + int oldConsumed, numspheres; + QValueList points; + QValueList radii; + PMVector point; + double f; + + if( !parseToken( SPHERE_SWEEP_TOK, "sphere_sweep" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + nextToken( ); + switch ( m_token ) + { + case LINEAR_SPLINE_TOK: + ss->setSplineType( PMSphereSweep::LinearSpline ); + break; + case B_SPLINE_TOK: + ss->setSplineType( PMSphereSweep::BSpline ); + break; + case CUBIC_SPLINE_TOK: + ss->setSplineType( PMSphereSweep::CubicSpline ); + break; + default: + return false; + } + + if ( !parseInt( numspheres ) ) + return false; + + for ( int i = 0; i < numspheres; ++i ) + { + if ( !parseVector( point ) ) + return false; + points.append( point ); + if ( !parseToken( ',' ) ) + return false; + if ( !parseFloat( f ) ) + return false; + radii.append( f ); + } + + ss->setPoints( points ); + ss->setRadii( radii ); + + do + { + oldConsumed = m_consumedTokens; + if ( m_token == TOLERANCE_TOK ) + { + nextToken( ); + if ( !parseFloat( f ) ) + return false; + ss->setTolerance( f ); + } + else + { + parseObjectModifiers( ss ); + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseMesh( PMMesh* m ) +{ + int oldConsumed; + PMVector vector; + + if( !parseToken( MESH_TOK, "mesh" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + do + { + oldConsumed = m_consumedTokens; + if ( m_token == HIERARCHY_TOK ) + { + nextToken( ); + m->setHierarchy( parseBool( ) ); + } + else if ( m_token == INSIDE_VECTOR_TOK ) + { + nextToken( ); + if ( !parseVector( vector ) ) + return false; + m->enableInsideVector( true ); + m->setInsideVector( vector ); + } + else + { + parseChildObjects( m ); + parseObjectModifiers( m ); + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} diff --git a/kpovmodeler/pmpovrayparser.h b/kpovmodeler/pmpovrayparser.h new file mode 100644 index 00000000..b41beaf9 --- /dev/null +++ b/kpovmodeler/pmpovrayparser.h @@ -0,0 +1,534 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMPOVRAYPARSER_H +#define PMPOVRAYPARSER_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmparser.h" +#include "pmcomment.h" +#include "pmvector.h" + +class PMCompositeObject; +class PMGraphicalObject; +class PMBox; +class PMSphere; +class PMCylinder; +class PMCone; +class PMTorus; +class PMPlane; +class PMPolynom; +class PMDisc; +class PMBlob; +class PMBlobCylinder; +class PMBlobSphere; +class PMBicubicPatch; +class PMTriangle; +class PMCSG; +class PMHeightField; +class PMText; +class PMJuliaFractal; +class PMLathe; +class PMPrism; +class PMSurfaceOfRevolution; +class PMSuperquadricEllipsoid; +class PMScale; +class PMRotate; +class PMTranslate; +class PMBoundedBy; +class PMClippedBy; +class PMPovrayMatrix; +class PMCamera; +class PMLight; +class PMLooksLike; +class PMProjectedThrough; +class PMColor; +class PMTexture; +class PMPattern; +class PMBlendMapModifiers; +class PMWarp; +class PMPigment; +class PMNormal; +class PMTextureMap; +class PMPigmentMap; +class PMColorMap; +class PMNormalMap; +class PMBumpMap; +class PMMaterialMap; +class PMSlopeMap; +class PMDensityMap; +class PMListPattern; +class PMTextureList; +class PMPigmentList; +class PMColorList; +class PMNormalList; +class PMDensityList; +class PMImageMap; +class PMSlope; +class PMFinish; +class PMInterior; +class PMMedia; +class PMDensity; +class PMMaterial; +class PMSkySphere; +class PMRainbow; +class PMFog; +class PMDeclare; +class PMObjectLink; +class PMGlobalSettings; + +class PMIsoSurface; +class PMRadiosity; +class PMGlobalPhotons; +class PMPhotons; +class PMLightGroup; +class PMInteriorTexture; +class PMSphereSweep; +class PMMesh; + +/** + * Parser that parses povray code. + * + * All parse functions return false or 0 if an error occurred and the parse + * function couldn't recover. + */ +class PMPovrayParser : public PMParser +{ +public: + /** + * Parser that parses the device + */ + PMPovrayParser( PMPart* part, QIODevice* device ); + /** + * Parser that parses the byte array + */ + PMPovrayParser( PMPart* part, const QByteArray& array ); + /** + * Deletes the parser + */ + virtual ~PMPovrayParser( ); + +protected: + /** + * Top level parse function + */ + virtual void topParse( ); + +private: + /** + * Initializes the parser + */ + void init( ); + + /** + * Sets m_token to the next token + */ + void nextToken( ); + + /** + * Returns true if the current token is ON_TOK, TRUE_TOK or YES_TOK + */ + bool isTrue( ) const; + /** + * Returns true if the current token is OFF_TOK, FALSE_TOK or NO_TOK + */ + bool isFalse( ) const; + /** + * Returns true if the next token is no bool value or one of the + * ON, TRUE or YES tokens + */ + bool parseBool( ); + + + /** + * Looks for child objects, parses them and appends them to the parent + * object. If parent is 0, all objects are appended to the result list. + * + * If max is > 0, then the maximum number of parsed objects is max. + * + * Returns true if there where no objects or parsing was successful. + */ + bool parseChildObjects( PMCompositeObject* parent, int max = -1 ); + + + /** + * Parses the token t. + * + * If the next token is not t, it appends an error to the messages + * and returns false. + * + * If t is not a single character token, set tokenName to the token + * name (like "box", "sphere" ...) + */ + bool parseToken( int t, const QString& tokenName = QString::null ); + + /** + * Parses an item of a vector, float or color expression + */ + bool parseNumericItem( PMValue& v, bool checkForBool = false ); + /** + * Parse function for a vector literal + */ + bool parseVectorLiteral( PMVector& v ); + /** + * Parses a vector, float or color expression + */ + bool parseNumericExpression( PMValue& v, bool checkForBool = false ); + + /** + * parses a vector and float expression and returns a vector + * of size s + */ + bool parseVector( PMVector& v, unsigned int s=3 ); + /** + * parses a vector and float expression and returns the + * float value or the first coordinate of the vector + */ + bool parseFloat( double& d, bool suppressError = false ); + /** + * parses a float or int value and rounds if necessary + */ + bool parseInt( int& d ); + /** + * parses a color expression + */ + bool parseColor( PMColor& c ); + + /** + * Parse function for object modifiers + */ + bool parseObjectModifiers( PMGraphicalObject* obj ); + + /** + * Parse function for cvs objects + */ + bool parseCSG( PMCSG* csg ); + + /** + * Parse function for box objects + */ + bool parseBox( PMBox* box ); + /** + * Parse function for box objects + */ + bool parseSphere( PMSphere* sphere ); + /** + * Parse function for cylinder objects + */ + bool parseCylinder( PMCylinder* pNewCyl ); + /** + * Parse function for cone objects + */ + bool parseCone( PMCone* pNewCone ); + /** + * Parse function for torus objects + */ + bool parseTorus( PMTorus* pNewTorus ); + + /** + * Parse function for blob objects + */ + bool parseBlob( PMBlob* pNewBlob ); + /** + * Parse function for blob sphere components + */ + bool parseBlobSphere( PMBlobSphere* pNewBlobSphere ); + /** + * Parse function for blob cylinder components + */ + bool parseBlobCylinder( PMBlobCylinder* pNewBlobCylinder ); + /** + * Parse function for old blob components + */ + bool parseBlobComponent( PMBlobSphere* pNewBlobSphere ); + + /** + * Parse function for height fields + */ + bool parseHeightField( PMHeightField* pNewHeightField ); + /** + * Parse function for text objects + */ + bool parseText( PMText* pNewText ); + /** + * Parse function for julia fractals + */ + bool parseJuliaFractal( PMJuliaFractal* pNewFractal ); + + /** + * Parse function for plane objects + */ + bool parsePlane( PMPlane* pNewPlane ); + /** + * Parse function for quadric, cubic, quartic and poly + */ + bool parsePolynom( PMPolynom* pNewPoly ); + /** + * Parse function for bicubic patch objects + */ + bool parseBicubicPatch( PMBicubicPatch* pNewPatch ); + /** + * Parse function for disks + */ + bool parseDisc( PMDisc* pNewDisc ); + /** + * Parse function for triangles + */ + bool parseTriangle( PMTriangle* pNewTriangle ); + + /** + * Parse function for lathes + */ + bool parseLathe( PMLathe* pNewLathe ); + /** + * Parse function for prisms + */ + bool parsePrism( PMPrism* pNewPrism ); + /** + * Parse function for surface of revolutions + */ + bool parseSor( PMSurfaceOfRevolution* pNewSor ); + /** + * Parse function for superquadric ellipsoid + */ + bool parseSqe( PMSuperquadricEllipsoid* pNewSqe ); + + /** + * Parse function for scale commands + */ + bool parseScale( PMScale* scale ); + /** + * Parse function for rotate commands + */ + bool parseRotate( PMRotate* rotate ); + /** + * Parse function for translate commands + */ + bool parseTranslate( PMTranslate* translate ); + /** + * Parse function for matrix commands + */ + bool parseMatrix( PMPovrayMatrix* matrix ); + + /** + * Parse function for bounded_by statements + */ + bool parseBoundedBy( PMBoundedBy* bound ); + /** + * Parse function for clipped_by statements + */ + bool parseClippedBy( PMClippedBy* clipped ); + + /** + * Parse function for camera objects + */ + bool parseCamera( PMCamera* camera ); + + /** + * Parse function for light objects + */ + bool parseLight( PMLight* light ); + /** + * Parse function for looks_like statement + */ + bool parseLooksLike( PMLooksLike* ll ); + /** + * Parse function for projected_through statement + */ + bool parseProjectedThrough( PMProjectedThrough* ll ); + + /** + * Parse function for texture objects. If parseOuter is false, the parser + * won't search for the texture{} wrapper. This is useful inside a texture + * map. + */ + bool parseTexture( PMTexture* pigment, bool parseOuter = true ); + /** + * Parse function for pattern objects + */ + bool parsePattern( PMPattern* pattern, bool normal = false ); + /** + * Parse function for blend map modifier objects + */ + bool parseBlendMapModifiers( PMBlendMapModifiers* blend ); + /** + * Parse function for warp objects + */ + bool parseWarp( PMWarp* pattern ); + /** + * Parse function for pigment objects + */ + bool parsePigment( PMPigment* pigment, bool parseOuter = true ); + /** + * Parse function for normal objects + */ + bool parseNormal( PMNormal* normal ); + /** + * Parse function for texture map objects + */ + bool parseTextureMap( PMTextureMap* textureMap ); + /** + * Parse function for pigment map objects + */ + bool parsePigmentMap( PMPigmentMap* pigmentMap ); + /** + * Parse function for color map objects + */ + bool parseColorMap( PMColorMap* colorMap ); + /** + * Parse function for normal map objects + */ + bool parseNormalMap( PMNormalMap* normalMap ); + /** + * Parse function for bump map objects + */ + bool parseBumpMap( PMBumpMap* bumpMap ); + /** + * Parse function for material map objects + */ + bool parseMaterialMap( PMMaterialMap* materialMap ); + /** + * Parse function for slope map objects + */ + bool parseSlopeMap( PMSlopeMap* slopeMap ); + /** + * Parse function for density map objects + */ + bool parseDensityMap( PMDensityMap* densityMap ); + /** + * Parse function for image map objects + */ + bool parseImageMap( PMImageMap* imageMap ); + /** + * Parse function for slope objects + */ + bool parseSlope( PMSlope* slope ); + /** + * Parse function for texture list objects + */ + bool parseTextureList( PMTextureList* textureList, int expectedItems ); + /** + * Parse function for pigment list objects + */ + bool parsePigmentList( PMPigmentList* pigmentList, int expectedItems ); + /** + * Parse function for color list objects + */ + bool parseColorList( PMColorList* colorList, int expectedItems ); + /** + * Parse function for normal list objects + */ + bool parseNormalList( PMNormalList* normalList, int expectedItems ); + /** + * Parse function for density list objects + */ + bool parseDensityList( PMDensityList* densityList, int expectedItems ); + /** + * Parse function for finish objects + */ + bool parseFinish( PMFinish* finish ); + /** + * Parse function for interior objects + */ + bool parseInterior( PMInterior* interior ); + /** + * Parse function for media objects + */ + bool parseMedia( PMMedia* media ); + /** + * Parse function for density objects + */ + bool parseDensity( PMDensity* density ); + /** + * Parse function for material objects + */ + bool parseMaterial( PMMaterial* material ); + + /** + * Parse function for sky sphere objects + */ + bool parseSkySphere( PMSkySphere* sky ); + /** + * Parse function for rainbow objects + */ + bool parseRainbow( PMRainbow* rainbow ); + /** + * Parse function for fog objects + */ + bool parseFog( PMFog* fog ); + + /** + * Parse function for global settings + */ + bool parseGlobalSettings( PMGlobalSettings* decl ); + /** + * Parse function for declares + */ + bool parseDeclare( PMDeclare* decl ); + /** + * Parse function for object links + */ + bool parseObjectLink( PMObjectLink* link ); + /** + * Parse function for object keywords + */ + bool parseObject( PMCompositeObject* parent ); + + // POV-Ray 3.5 objects + bool parseIsoSurface( PMIsoSurface* iso ); + bool parseRadiosity( PMRadiosity* rad ); + bool parseGlobalPhotons( PMGlobalPhotons* gp ); + bool parsePhotons( PMPhotons* p ); + bool parseLightGroup( PMLightGroup* lg ); + bool parseInteriorTexture( PMInteriorTexture* it ); + bool parseSphereSweep( PMSphereSweep * ss ); + bool parseMesh( PMMesh* m ); + + /** + * The used scanner + */ + PMScanner* m_pScanner; + /** + * The last scanned token + */ + int m_token; + + /** + * Number of consumed tokens. + */ + int m_consumedTokens; + + /** + * All comments are skipped during parsing and stored here + */ + QPtrList m_skippedComments; + /** + * The last skipped comment text with special kpovmodeler tags*/ + QString m_lastPMComment; + /** + * true if m_lastPMComment is empty + */ + bool m_bLastPMCommentEmpty; +}; + + +#endif diff --git a/kpovmodeler/pmpovrayrenderwidget.cpp b/kpovmodeler/pmpovrayrenderwidget.cpp new file mode 100644 index 00000000..3cd44f20 --- /dev/null +++ b/kpovmodeler/pmpovrayrenderwidget.cpp @@ -0,0 +1,437 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmpovrayrenderwidget.h" +#include "pmdefaults.h" +#include "pmdebug.h" +#include "pmdragwidget.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef KDE_NO_COMPAT +#undef KDE_NO_COMPAT +#endif + +#include + +QString PMPovrayRenderWidget::s_povrayCommand = c_defaultPovrayCommand; +QStringList PMPovrayRenderWidget::s_libraryPaths; + +PMPovrayRenderWidget::PMPovrayRenderWidget( QWidget* parent, const char* name ) + : PMDragWidget( parent, name ) +{ + m_pProcess = 0; + m_bSuspended = false; + m_rcvHeader = false; + m_skipBytes = 0; + m_bPixmapUpToDate = false; + m_pTempFile = 0; + + setBackgroundColor( QColor( 0, 0, 0 ) ); +} + +PMPovrayRenderWidget::~PMPovrayRenderWidget( ) +{ + cleanup( ); +} + +bool PMPovrayRenderWidget::render( const QByteArray& scene, + const PMRenderMode& m, + const KURL& documentURL ) +{ + cleanup( ); + + m_povrayOutput = ""; + m_renderMode = m; + + if( !scene.data( ) ) + { + KMessageBox::sorry( this, i18n( "Can't render an empty scene.\n" ) ); + return false; + } + + // output to tmp file + m_pTempFile = new KTempFile( QString::null, ".pov" ); + QDataStream* dstr = m_pTempFile->dataStream( ); + + if( ( m_pTempFile->status( ) != 0 ) || !dstr ) + { + KMessageBox::sorry( this, i18n( "Couldn't write the scene to a temp file.\n" ) ); + return false; + } + + dstr->writeRawBytes( scene.data( ), scene.size( ) ); + m_pTempFile->close( ); + + m_pProcess = new KProcess( ); + connect( m_pProcess, SIGNAL( receivedStdout( KProcess*, char*, int ) ), + SLOT( slotPovrayImage( KProcess*, char*, int ) ) ); + connect( m_pProcess, SIGNAL( receivedStderr( KProcess*, char*, int ) ), + SLOT( slotPovrayMessage( KProcess*, char*, int ) ) ); + connect( m_pProcess, SIGNAL( processExited( KProcess* ) ), + SLOT( slotRenderingFinished( KProcess* ) ) ); + + *m_pProcess << s_povrayCommand; + + QStringList::ConstIterator it; + QStringList args = m_renderMode.commandLineSwitches( ); + for( it = args.begin( ); it != args.end( ); ++it ) + *m_pProcess << *it; + + for( it = s_libraryPaths.begin( ); it != s_libraryPaths.end( ); ++it ) + { + QString path = *it; + if( path != QString( "/" ) ) + if( path.right( 1 ) == QString( "/" ) ) + path.truncate( path.length( ) - 1 ); + *m_pProcess << ( QString( "+L" ) + path ); + } + *m_pProcess << QString( "+I" ) + m_pTempFile->name( ) << "+O-" << "+FT" + << "+K0.0" << "+KFI1" << "+KFF1" << "+KI0.0" << "+KF0.0" + << "+SF1" << "+EF1" << "-KC" << "-D"; + +#if ( ( KDE_VERSION_MAJOR == 2 ) && ( KDE_VERSION_MINOR >= 9 ) ) || ( KDE_VERSION_MAJOR == 3 ) + if( !documentURL.isEmpty( ) && documentURL.isLocalFile( ) ) + m_pProcess->setWorkingDirectory( documentURL.directory( ) ); +#endif + + m_rcvHeader = true; + m_rcvHeaderBytes = 0; + m_rcvPixels = 0; + m_progress = 0; + m_numRestBytes = 0; + m_line = 0; + m_column = 0; + m_skipBytes = 0; + + int width = m_renderMode.width( ); + int height = m_renderMode.height( ); + + m_image.create( width, height, 32 ); + m_image.setAlphaBuffer( m_renderMode.alpha( ) ); + m_image.fill( qRgb( 0, 0, 0 ) ); + m_bPixmapUpToDate = false; + repaint( ); + + if( !m_pProcess->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( this, i18n( "Couldn't call povray.\n" + "Please check your installation " + "or set another povray command." ) ); + delete m_pProcess; + m_pProcess = 0; + return false; + } + + m_bSuspended = false; + return true; +} + +void PMPovrayRenderWidget::killRendering( ) +{ + if( m_pProcess ) + { + if( m_bSuspended ) + m_pProcess->kill( SIGCONT ); + m_bSuspended = false; + m_pProcess->kill( ); + } +} + +void PMPovrayRenderWidget::suspendRendering( ) +{ + if( m_pProcess ) + { + m_bSuspended = true; + m_pProcess->kill( SIGSTOP ); + } +} + +void PMPovrayRenderWidget::resumeRendering( ) +{ + if( m_pProcess ) + { + m_pProcess->kill( SIGCONT ); + m_bSuspended = false; + } +} + +void PMPovrayRenderWidget::slotPovrayMessage( KProcess*, + char* buffer, int buflen ) +{ + QString str; + str.setLatin1( buffer, buflen ); + m_povrayOutput += str; + emit povrayMessage( str ); +} + +void PMPovrayRenderWidget::slotPovrayImage( KProcess*, char* buffer, int buflen ) +{ + int index = 0; + int i; + int oldLine = m_line; + + if( m_rcvHeader ) + { + // receive targa header + while( ( m_rcvHeaderBytes < 18 ) && ( index < buflen ) ) + { + m_header[m_rcvHeaderBytes] = ( unsigned char ) buffer[index]; + m_rcvHeaderBytes++; + index++; + } + + if( m_rcvHeaderBytes == 18 ) + { + // complete targa header received + m_rcvHeader = false; + m_skipBytes = m_header[0]; // id length + m_bytespp = m_header[16] / 8; + } + } + + if( m_skipBytes > 0 ) + { + int skip = buflen - index; + if( skip > m_skipBytes ) + skip = m_skipBytes; + m_skipBytes -= skip; + index += skip; + } + + if( ( m_numRestBytes > 0 ) && ( index < buflen ) ) + { + while( ( m_numRestBytes < m_bytespp ) && ( index < buflen ) ) + { + m_restBytes[m_numRestBytes] = ( unsigned char ) buffer[index]; + index++; + m_numRestBytes++; + } + if( m_numRestBytes == m_bytespp ) + { + m_numRestBytes = 0; + + if( m_bytespp == 4 ) + setPixel( m_column, m_line, + qRgba( m_restBytes[2], m_restBytes[1], + m_restBytes[0], m_restBytes[3] ) ); + else + setPixel( m_column, m_line, + qRgb( m_restBytes[2], m_restBytes[1], m_restBytes[0] ) ); + + m_column++; + m_rcvPixels++; + if( m_column == m_renderMode.width( ) ) + { + m_column = 0; + m_line++; + } + } + } + + if( index < buflen ) + { + int num = ( buflen - index ) / m_bytespp; + for( i = 0; i < num; i++ ) + { + if( m_bytespp == 4 ) + setPixel( m_column, m_line, + qRgba( buffer[index+2], buffer[index+1], + buffer[index], buffer[index+3] ) ); + else + setPixel( m_column, m_line, + qRgb( buffer[index+2], buffer[index+1], + buffer[index] ) ); + index += m_bytespp; + + m_column++; + m_rcvPixels++; + if( m_column == m_renderMode.width( ) ) + { + m_column = 0; + m_line++; + } + } + } + + if( index < buflen ) + { + m_numRestBytes = buflen - index; + for( i = 0; i < m_numRestBytes; i++ ) + { + m_restBytes[i] = buffer[index]; + index++; + } + } + + if( m_line != oldLine ) + { + QPainter paint( this ); + int offset = 0; + if( m_renderMode.subSection( ) ) + { + double sr = m_renderMode.startRow( ); + if( sr < 1 ) + offset = ( int ) ( m_renderMode.height( ) * sr + 0.5 ); + else + offset += ( int ) sr; + } + paint.drawImage( 0, offset + oldLine, + m_image.copy( 0, offset + oldLine, m_image.width( ), offset + m_line - oldLine ) ); + + emit lineFinished( m_line - 1 ); + } + + int oldProgress = m_progress; + int numPixels = 0; + if( m_renderMode.subSection( ) ) + { + int sr = 0; + if( m_renderMode.startRow( ) < 1 ) + sr = ( int ) ( m_renderMode.height( ) * m_renderMode.startRow( ) + 0.5 ); + else + sr = ( int ) m_renderMode.startRow( ); + int er = 0; + if( m_renderMode.endRow( ) < 1 ) + er = ( int ) ( m_renderMode.height( ) * m_renderMode.endRow( ) + 0.5 ); + else + er = ( int ) m_renderMode.endRow( ); + + numPixels = m_renderMode.width( ) * ( er - sr ); + } + else + numPixels = m_renderMode.width( ) * m_renderMode.height( ); + + m_progress = m_rcvPixels * 100 / numPixels; + + if( m_progress != oldProgress ) + emit progress( m_progress ); + m_bPixmapUpToDate = false; +} + +void PMPovrayRenderWidget::setPixel( int x, int y, uint c ) +{ + if( m_renderMode.subSection( ) ) + { + double sr = m_renderMode.startRow( ); + if( sr < 1 ) + y += ( int ) ( m_renderMode.height( ) * sr + 0.5 ); + else + y += ( int ) sr; + } + + if( x >= 0 && x < m_image.width( ) && + y >= 0 && y < m_image.height( ) ) + m_image.setPixel( x, y, c ); +} + +/** +void PMPovrayRenderWidget::slotWroteStdin( KProcess* ) +{ + if( m_pProcess ) + m_pProcess->closeStdin( ); + m_data.resize( 0 ); +} +*/ + +void PMPovrayRenderWidget::slotRenderingFinished( KProcess* ) +{ + if( m_pProcess->normalExit( ) ) + emit( finished( m_pProcess->exitStatus( ) ) ); + else + emit( finished( -1000 ) ); + + cleanup( ); +} + +void PMPovrayRenderWidget::paintEvent( QPaintEvent* ev ) +{ + if( !m_bPixmapUpToDate ) + { + if( !m_image.isNull( ) ) + m_pixmap.convertFromImage( m_image ); + m_bPixmapUpToDate = true; + } + bitBlt( this, ev->rect( ).left( ), ev->rect( ).top( ), + &m_pixmap, ev->rect( ).left( ), ev->rect( ).top( ), + ev->rect( ).width( ), ev->rect( ).height( ), CopyROP ); +} + +void PMPovrayRenderWidget::cleanup( ) +{ + if( m_pProcess ) + delete m_pProcess; + m_pProcess = 0; + if( m_pTempFile ) + { + m_pTempFile->unlink( ); + delete m_pTempFile; + } + m_pTempFile = 0; +} + +QSize PMPovrayRenderWidget::sizeHint( ) const +{ + QSize s; + if( m_image.isNull( ) ) + s = QSize( 200, 200 ); + else + s = m_image.size( ); + + return s.expandedTo( minimumSize( ) ); +} + +void PMPovrayRenderWidget::saveConfig( KConfig* cfg ) +{ + cfg->setGroup( "Povray" ); +#if ( ( KDE_VERSION_MAJOR == 3 ) && ( KDE_VERSION_MINOR <= 1 ) ) + cfg->writeEntry( "PovrayCommand", s_povrayCommand ); + cfg->writeEntry( "LibraryPaths", s_libraryPaths ); +#else + cfg->writePathEntry( "PovrayCommand", s_povrayCommand ); + cfg->writePathEntry( "LibraryPaths", s_libraryPaths ); +#endif +} + +void PMPovrayRenderWidget::restoreConfig( KConfig* cfg ) +{ + cfg->setGroup( "Povray" ); +#if ( ( KDE_VERSION_MAJOR == 3 ) && ( KDE_VERSION_MINOR <= 1 ) ) + s_povrayCommand = cfg->readEntry( "PovrayCommand", s_povrayCommand ); + s_libraryPaths = cfg->readListEntry( "LibraryPaths" ); +#else + s_povrayCommand = cfg->readPathEntry( "PovrayCommand", s_povrayCommand ); + s_libraryPaths = cfg->readPathListEntry( "LibraryPaths" ); +#endif +} + +void PMPovrayRenderWidget::startDrag( ) +{ + QImageDrag* d = new QImageDrag( m_image, this ); + d->dragCopy( ); +} + +#include "pmpovrayrenderwidget.moc" diff --git a/kpovmodeler/pmpovrayrenderwidget.h b/kpovmodeler/pmpovrayrenderwidget.h new file mode 100644 index 00000000..23e30721 --- /dev/null +++ b/kpovmodeler/pmpovrayrenderwidget.h @@ -0,0 +1,177 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMPOVRAYRENDERWIDGET_H +#define PMPOVRAYRENDERWIDGET_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "pmrendermode.h" +#include "pmdragwidget.h" + +class KProcess; +class KConfig; +class KURL; +class KTempFile; + +/** + * Widget that calls povray to render a scene and + * displays the output. + */ +class PMPovrayRenderWidget : public PMDragWidget +{ + Q_OBJECT +public: + /** + * Standard constructor + */ + PMPovrayRenderWidget( QWidget* parent = 0, const char* name = 0 ); + /** + * destructor + */ + virtual ~PMPovrayRenderWidget( ); + + /** + * Starts rendering for the povray code in the byte array with + * render mode m. + * @see PMRenderMode + */ + bool render( const QByteArray& scene, const PMRenderMode& m, + const KURL& documentURL ); + + /** + * Returns the povray text output + */ + QString povrayOutput( ) const { return m_povrayOutput; } + /** + * Returns the rendered image + */ + QImage image( ) const { return m_image; } + + static void saveConfig( KConfig* cfg ); + static void restoreConfig( KConfig* cfg ); + + /** + * Returns the povray command + */ + static QString povrayCommand( ) { return s_povrayCommand; } + /** + * Sets the povray command + */ + static void setPovrayCommand( const QString& c ) { s_povrayCommand = c; } + /** + * Returns the library paths + */ + static QStringList povrayLibraryPaths( ) { return s_libraryPaths; } + /** + * Sets the library paths + */ + static void setPovrayLibraryPaths( const QStringList& slist ) + { s_libraryPaths = slist; } + virtual QSize sizeHint( ) const; + + virtual void startDrag( ); +signals: + /** + * Emitted when rendering has finished + */ + void finished( int exitStatus ); + /** + * Provides progress information + */ + void progress( int percent ); + /** + * Provides progress imformation + */ + void lineFinished( int line ); + /** + * The povray output text + */ + void povrayMessage( const QString& msg ); + +public slots: + /** + * Kills rendering + */ + void killRendering( ); + /** + * Suspends rendering + */ + void suspendRendering( ); + /** + * Resumes rendering + */ + void resumeRendering( ); + +protected slots: + /** + * Receive povray messages + */ + void slotPovrayMessage( KProcess* proc, char* buffer, int buflen ); + /** + * Receive rendered image + */ + void slotPovrayImage( KProcess* proc, char* buffer, int buflen ); + /** + * Called when output has been written to the povray process + */ + //void slotWroteStdin( KProcess* proc ); + /** + * Called when the process has finished + */ + void slotRenderingFinished( KProcess* proc ); + +protected: + virtual void paintEvent( QPaintEvent* ); + +private: + void setPixel( int x, int y, uint c ); + void cleanup( ); + + KProcess* m_pProcess; + bool m_bSuspended; + PMRenderMode m_renderMode; + QImage m_image; + bool m_rcvHeader; + unsigned char m_header[18]; + int m_rcvHeaderBytes; + int m_skipBytes; + int m_bytespp; + int m_rcvPixels; + int m_progress; + unsigned char m_restBytes[4]; + int m_numRestBytes; + int m_line; + int m_column; + QPixmap m_pixmap; + bool m_bPixmapUpToDate; + QString m_povrayOutput; + KTempFile* m_pTempFile; + + static QString s_povrayCommand; + static QStringList s_libraryPaths; +}; + +#endif diff --git a/kpovmodeler/pmpovraysettings.cpp b/kpovmodeler/pmpovraysettings.cpp new file mode 100644 index 00000000..0b2824ae --- /dev/null +++ b/kpovmodeler/pmpovraysettings.cpp @@ -0,0 +1,308 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmpovraysettings.h" + +#include "pmdocumentationmap.h" +#include "pmpovrayrenderwidget.h" +#include "pmdefaults.h" +#include "pmresourcelocator.h" +#include "pmtext.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +PMPovraySettings::PMPovraySettings( QWidget* parent, const char* name ) + : PMSettingsDialogPage( parent, name ) +{ + m_selectionIndex = 0; + + QHBoxLayout* hlayout; + QVBoxLayout* vlayout; + QVBoxLayout* gvl; + QGroupBox* gb; + + vlayout = new QVBoxLayout( this, 0, KDialog::spacingHint( ) ); + + gb = new QGroupBox( i18n( "Povray Command" ), this ); + gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) ); + gvl->addSpacing( 10 ); + hlayout = new QHBoxLayout( gvl ); + hlayout->addWidget( new QLabel( i18n( "Command:" ), gb ) ); + m_pPovrayCommand = new QLineEdit( gb ); + hlayout->addWidget( m_pPovrayCommand ); + m_pBrowsePovrayCommand = new QPushButton( gb ); + m_pBrowsePovrayCommand->setPixmap( SmallIcon( "fileopen" ) ); + connect( m_pBrowsePovrayCommand, SIGNAL( clicked( ) ), + SLOT( slotBrowsePovrayCommand( ) ) ); + hlayout->addWidget( m_pBrowsePovrayCommand ); + vlayout->addWidget( gb ); + + gb = new QGroupBox( i18n( "Povray User Documentation" ), this ); + gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) ); + gvl->addSpacing( 10 ); + hlayout = new QHBoxLayout( gvl ); + hlayout->addWidget( new QLabel( i18n( "Path:" ), gb ) ); + m_pDocumentationPath = new QLineEdit( gb ); + hlayout->addWidget( m_pDocumentationPath ); + m_pBrowseDocumentationPath = new QPushButton( gb ); + m_pBrowseDocumentationPath->setPixmap( SmallIcon( "fileopen" ) ); + connect( m_pBrowseDocumentationPath, SIGNAL( clicked( ) ), + SLOT( slotBrowsePovrayDocumentation( ) ) ); + hlayout->addWidget( m_pBrowseDocumentationPath ); + vlayout->addWidget( gb ); + hlayout = new QHBoxLayout( gvl ); + hlayout->addWidget( new QLabel( i18n( "Version:" ), gb ) ); + m_pDocumentationVersion = new QComboBox( false, gb ); + QValueList versions = PMDocumentationMap::theMap( )->availableVersions( ); + QValueListIterator it; + for( it = versions.begin( ); it != versions.end( ); ++it ) + m_pDocumentationVersion->insertItem( *it ); + hlayout->addWidget( m_pDocumentationVersion ); + hlayout->addStretch( ); + + gb = new QGroupBox( i18n( "Library Paths" ), this ); + gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) ); + gvl->addSpacing( 10 ); + hlayout = new QHBoxLayout( gvl ); + m_pLibraryPaths = new QListBox( gb ); + connect( m_pLibraryPaths, SIGNAL( highlighted( int ) ), + SLOT( slotPathSelected( int ) ) ); + hlayout->addWidget( m_pLibraryPaths ); + + QVBoxLayout* bl = new QVBoxLayout( hlayout ); + m_pAddLibraryPath = new QPushButton( i18n( "Add..." ), gb ); + connect( m_pAddLibraryPath, SIGNAL( clicked( ) ), SLOT( slotAddPath( ) ) ); + bl->addWidget( m_pAddLibraryPath ); + m_pRemoveLibraryPath = new QPushButton( i18n( "Remove" ), gb ); + connect( m_pRemoveLibraryPath, SIGNAL( clicked( ) ), + SLOT( slotRemovePath( ) ) ); + bl->addWidget( m_pRemoveLibraryPath ); + m_pChangeLibraryPath = new QPushButton( i18n( "Edit..." ), gb ); + connect( m_pChangeLibraryPath, SIGNAL( clicked( ) ), + SLOT( slotEditPath( ) ) ); + bl->addWidget( m_pChangeLibraryPath ); + m_pLibraryPathUp = new QPushButton( i18n( "Up" ), gb ); + connect( m_pLibraryPathUp, SIGNAL( clicked( ) ), SLOT( slotPathUp( ) ) ); + bl->addWidget( m_pLibraryPathUp ); + m_pLibraryPathDown = new QPushButton( i18n( "Down" ), gb ); + connect( m_pLibraryPathDown, SIGNAL( clicked( ) ), + SLOT( slotPathDown( ) ) ); + bl->addWidget( m_pLibraryPathDown ); + bl->addStretch( 1 ); + vlayout->addWidget( gb ); + + vlayout->addStretch( 1 ); +} + +void PMPovraySettings::displaySettings( ) +{ + m_pPovrayCommand->setText( PMPovrayRenderWidget::povrayCommand( ) ); + m_pDocumentationPath->setText( PMDocumentationMap::theMap( )->povrayDocumentationPath( ) ); + int c = m_pDocumentationVersion->count( ); + QString s = PMDocumentationMap::theMap( )->documentationVersion( ); + int i; + for( i = 0; i < c; i++ ) + if( m_pDocumentationVersion->text( i ) == s ) + m_pDocumentationVersion->setCurrentItem( i ); + + bool sb = m_pLibraryPaths->signalsBlocked( ); + m_pLibraryPaths->blockSignals( true ); + m_pLibraryPaths->clear( ); + QStringList plist = PMPovrayRenderWidget::povrayLibraryPaths( ); + QStringList::ConstIterator it = plist.begin( ); + m_selectionIndex = -1; + for( ; it != plist.end( ); ++it ) + { + m_pLibraryPaths->insertItem( *it ); + m_selectionIndex++; + } + + m_pRemoveLibraryPath->setEnabled( false ); + m_pChangeLibraryPath->setEnabled( false ); + m_pLibraryPathUp->setEnabled( false ); + m_pLibraryPathDown->setEnabled( false ); + m_pLibraryPaths->blockSignals( sb ); +} + +void PMPovraySettings::displayDefaults( ) +{ + m_pPovrayCommand->setText( c_defaultPovrayCommand ); + m_pDocumentationVersion->setCurrentItem( 0 ); + m_pDocumentationPath->setText( QString::null ); + m_pLibraryPaths->clear(); + +} + +bool PMPovraySettings::validateData( ) +{ + return true; +} + +void PMPovraySettings::applySettings( ) +{ + PMPovrayRenderWidget::setPovrayCommand( m_pPovrayCommand->text( ) ); + PMDocumentationMap::theMap( )->setPovrayDocumentationPath( + m_pDocumentationPath->text( ) ); + PMDocumentationMap::theMap( )->setDocumentationVersion( + m_pDocumentationVersion->currentText( ) ); + QStringList plist; + int num = ( signed ) m_pLibraryPaths->count( ); + int i; + for( i = 0; i < num; i++ ) + plist.append( m_pLibraryPaths->text( i ) ); + + if( PMPovrayRenderWidget::povrayLibraryPaths( ) != plist ) + { + PMPovrayRenderWidget::setPovrayLibraryPaths( plist ); + PMResourceLocator::clearCache( ); + PMText::povrayLibraryPathsChanged( ); + emit repaintViews( ); + } +} + +void PMPovraySettings::slotAddPath( ) +{ + if( m_pLibraryPaths->count( ) >= 20 ) + KMessageBox::error( this, i18n( "Povray only supports up to 20 library paths." ) ); + else + { + QString path = KFileDialog::getExistingDirectory( QString::null, this ); + if( !path.isEmpty( ) ) + { +#if ( QT_VERSION >= 300 ) + QListBoxItem* item = m_pLibraryPaths->findItem( path, ExactMatch ); +#else + QListBoxItem* item = 0; +#endif + if( !item ) + { + m_pLibraryPaths->insertItem( path, m_selectionIndex + 1 ); + m_pLibraryPaths->setCurrentItem( m_selectionIndex + 1 ); + } + else + KMessageBox::error( this, i18n( "The list of library paths already contains this path." ) ); + } + } +} + +void PMPovraySettings::slotRemovePath( ) +{ + m_pLibraryPaths->removeItem( m_selectionIndex ); + if( ( unsigned ) m_selectionIndex >= m_pLibraryPaths->count( ) ) + m_selectionIndex--; + m_pLibraryPaths->setCurrentItem( m_selectionIndex ); +} + +void PMPovraySettings::slotPathUp( ) +{ + QListBoxItem* lbi = m_pLibraryPaths->item( m_selectionIndex ); + if( lbi ) + { + QString text = lbi->text( ); + m_pLibraryPaths->removeItem( m_selectionIndex ); + if( m_selectionIndex > 0 ) + m_selectionIndex--; + m_pLibraryPaths->insertItem( text, m_selectionIndex ); + m_pLibraryPaths->setCurrentItem( m_selectionIndex ); + } +} + +void PMPovraySettings::slotPathDown( ) +{ + QListBoxItem* lbi = m_pLibraryPaths->item( m_selectionIndex ); + if( lbi ) + { + QString text = lbi->text( ); + m_pLibraryPaths->removeItem( m_selectionIndex ); + if( ( unsigned ) m_selectionIndex < m_pLibraryPaths->count( ) ) + m_selectionIndex++; + m_pLibraryPaths->insertItem( text, m_selectionIndex ); + m_pLibraryPaths->setCurrentItem( m_selectionIndex ); + } +} + +void PMPovraySettings::slotEditPath( ) +{ + QListBoxItem* lbi = m_pLibraryPaths->item( m_selectionIndex ); + if( lbi ) + { + QString text = lbi->text( ); + QString path = KFileDialog::getExistingDirectory( text, this ); + if( !path.isEmpty( ) ) + { +#if ( QT_VERSION >= 300 ) + QListBoxItem* item = m_pLibraryPaths->findItem( path, ExactMatch ); +#else + QListBoxItem* item = 0; +#endif + if( !item ) + m_pLibraryPaths->changeItem( path, m_selectionIndex ); + else if( item != lbi ) + KMessageBox::error( this, i18n( "The list of library paths already contains this path." ) ); + } + } +} + +void PMPovraySettings::slotPathSelected( int index ) +{ + m_selectionIndex = index; + QListBoxItem* lbi = m_pLibraryPaths->item( m_selectionIndex ); + if( lbi ) + { + m_pRemoveLibraryPath->setEnabled( true ); + m_pChangeLibraryPath->setEnabled( true ); + m_pLibraryPathUp->setEnabled( index > 0 ); + m_pLibraryPathDown->setEnabled( index < ( ( signed ) m_pLibraryPaths->count( ) - 1 ) ); + } + else + { + m_pRemoveLibraryPath->setEnabled( false ); + m_pChangeLibraryPath->setEnabled( false ); + m_pLibraryPathUp->setEnabled( false ); + m_pLibraryPathDown->setEnabled( false ); + } +} + +void PMPovraySettings::slotBrowsePovrayCommand( ) +{ + QString str = KFileDialog::getOpenFileName( QString::null, QString::null ); + + if( !str.isEmpty() ) + { + m_pPovrayCommand->setText( str ); + } +} + +void PMPovraySettings::slotBrowsePovrayDocumentation( ) +{ + QString str = KFileDialog::getExistingDirectory( ); + + if( !str.isEmpty( ) ) + m_pDocumentationPath->setText( str ); +} + +#include "pmpovraysettings.moc" diff --git a/kpovmodeler/pmpovraysettings.h b/kpovmodeler/pmpovraysettings.h new file mode 100644 index 00000000..cbe07827 --- /dev/null +++ b/kpovmodeler/pmpovraysettings.h @@ -0,0 +1,98 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMPOVRAYSETTINGS_H +#define PMPOVRAYSETTINGS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsettingsdialog.h" + +class QLineEdit; +class QPushButton; +class QComboBox; +class QListBox; + +/** + * Povray configuration dialog page + */ +class PMPovraySettings : public PMSettingsDialogPage +{ + Q_OBJECT +public: + /** + * Default constructor + */ + PMPovraySettings( QWidget* parent, const char* name = 0 ); + /** */ + virtual void displaySettings( ); + /** */ + virtual bool validateData( ); + /** */ + virtual void applySettings( ); + /** */ + virtual void displayDefaults( ); + +protected slots: + void slotAddPath( ); + /** + * Called when the remove button is clicked + */ + void slotRemovePath( ); + /** + * Called when the up button is clicked + */ + void slotPathUp( ); + /** + * Called when the down button is clicked + */ + void slotPathDown( ); + /** + * Called when the edit button is clicked + */ + void slotEditPath( ); + /** + * Called when a path is selected in the list view + */ + void slotPathSelected( int index ); + /** + * Called when the browse button for the povray command is clicked + */ + void slotBrowsePovrayCommand( ); + /** + * Called when the browse button for the povray documentation is clicked + */ + void slotBrowsePovrayDocumentation( ); + +private: + QLineEdit* m_pPovrayCommand; + QPushButton* m_pBrowsePovrayCommand; + QLineEdit* m_pDocumentationPath; + QPushButton* m_pBrowseDocumentationPath; + QComboBox* m_pDocumentationVersion; + QListBox* m_pLibraryPaths; + QPushButton* m_pAddLibraryPath; + QPushButton* m_pRemoveLibraryPath; + QPushButton* m_pChangeLibraryPath; + QPushButton* m_pLibraryPathUp; + QPushButton* m_pLibraryPathDown; + int m_selectionIndex; +}; + +#endif diff --git a/kpovmodeler/pmpovraywidget.cpp b/kpovmodeler/pmpovraywidget.cpp new file mode 100644 index 00000000..d50edc7e --- /dev/null +++ b/kpovmodeler/pmpovraywidget.cpp @@ -0,0 +1,411 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmpovraywidget.h" +#include "pmpovrayrenderwidget.h" +#include "pmpovrayoutputwidget.h" +#include "pmshell.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +const int timerIntervall = 1000; +bool PMPovrayWidget::s_imageFormatsRegistered = false; + +PMPovrayWidget::PMPovrayWidget( QWidget* parent, const char* name ) + : KDialog( parent, name ) +{ + QVBoxLayout* topLayout = new QVBoxLayout( this, KDialog::marginHint( ), KDialog::spacingHint( ) ); + topLayout->addStretch( ); + + QHBoxLayout* renderLayout = new QHBoxLayout( ); + topLayout->addLayout( renderLayout, 2 ); + m_pScrollView = new QScrollView( this ); + m_pScrollView->setBackgroundMode( PaletteBase ); + renderLayout->addWidget( m_pScrollView, 2 ); + m_pRenderWidget = new PMPovrayRenderWidget( m_pScrollView->viewport( ) ); + m_pRenderWidget->setFixedSize( 200, 200 ); + m_pScrollView->addChild( m_pRenderWidget ); + topLayout->addStretch( ); + + QHBoxLayout* progressLayout = new QHBoxLayout( topLayout ); + m_pProgressBar = new QProgressBar( this ); + m_pProgressBar->hide( ); + progressLayout->addWidget( m_pProgressBar, 1 ); + m_pProgressLabel = new QLabel( this ); + progressLayout->addWidget( m_pProgressLabel, 2 ); + + QHBoxLayout* buttonLayout = new QHBoxLayout( topLayout ); + m_pStopButton = new QPushButton( i18n( "Stop" ), this ); + m_pStopButton->setEnabled( false ); + buttonLayout->addWidget( m_pStopButton ); + m_pSuspendButton = new QPushButton( i18n( "Suspend" ), this ); + m_pSuspendButton->setEnabled( false ); + buttonLayout->addWidget( m_pSuspendButton ); + m_pResumeButton = new QPushButton( i18n( "Resume" ), this ); + m_pResumeButton->setEnabled( false ); + buttonLayout->addWidget( m_pResumeButton ); + buttonLayout->addStretch( 1 ); + m_pPovrayOutputButton = new QPushButton( i18n( "Povray Output" ), this ); + buttonLayout->addWidget( m_pPovrayOutputButton ); + + buttonLayout = new QHBoxLayout( topLayout ); + m_pSaveButton = new KPushButton( KStdGuiItem::saveAs(), this ); + m_pSaveButton->setEnabled( false ); + buttonLayout->addWidget( m_pSaveButton ); + buttonLayout->addStretch( 1 ); + QPushButton* closeButton = new KPushButton( KStdGuiItem::close(), this ); + buttonLayout->addWidget( closeButton ); + + connect( m_pRenderWidget, SIGNAL( finished( int ) ), + SLOT( slotRenderingFinished( int ) ) ); + connect( m_pRenderWidget, SIGNAL( progress( int ) ), + SLOT( slotProgress( int ) ) ); + connect( m_pRenderWidget, SIGNAL( lineFinished( int ) ), + SLOT( slotLineFinished( int ) ) ); + + connect( m_pStopButton, SIGNAL( clicked( ) ), SLOT( slotStop( ) ) ); + connect( m_pSuspendButton, SIGNAL( clicked( ) ), SLOT( slotSuspend( ) ) ); + connect( m_pResumeButton, SIGNAL( clicked( ) ), SLOT( slotResume( ) ) ); + connect( m_pSaveButton, SIGNAL( clicked( ) ), SLOT( slotSave( ) ) ); + connect( closeButton, SIGNAL( clicked( ) ), SLOT( slotClose( ) ) ); + connect( m_pPovrayOutputButton, SIGNAL( clicked( ) ), + SLOT( slotPovrayOutput( ) ) ); + + m_bRunning = false; + m_pProgressTimer = new QTimer( this ); + connect( m_pProgressTimer, SIGNAL( timeout( ) ), + SLOT( slotUpdateSpeed( ) ) ); + + setCaption( i18n( "Render Window" ) ); + + m_height = m_width = 0; + m_stopped = false; + + m_pPovrayOutputWidget = new PMPovrayOutputWidget( ); + connect( m_pRenderWidget, SIGNAL( povrayMessage( const QString& ) ), + m_pPovrayOutputWidget, SLOT( slotText( const QString& ) ) ); +} + +PMPovrayWidget::~PMPovrayWidget( ) +{ + delete m_pPovrayOutputWidget; +} + +bool PMPovrayWidget::render( const QByteArray& scene, const PMRenderMode& m, + const KURL& documentURL ) +{ + bool updateSize = ( m_height != m.height( ) ) || ( m_width != m.width( ) ); + m_height = m.height( ); + m_width = m.width( ); + m_bRunning = false; + m_pPovrayOutputWidget->slotClear( ); + m_stopped = false; + + m_pRenderWidget->setFixedSize( m_width, m_height ); + QSize maxSize( m_width + m_pScrollView->frameWidth( ) * 2, + m_height + m_pScrollView->frameWidth( ) * 2 ); + m_pScrollView->setMaximumSize( maxSize ); + + if( updateSize ) + { + int w, h; + + w = maxSize.width( ) + KDialog::spacingHint( ) * 2; + h = maxSize.height( ) + m_pSaveButton->sizeHint( ).height( ) * 2 + + KDialog::spacingHint( ) * 6; + if( m_pProgressLabel->sizeHint( ).height( ) + > m_pProgressBar->sizeHint( ).height( ) ) + h += m_pProgressLabel->sizeHint( ).height( ); + else + h += m_pProgressBar->sizeHint( ).height( ); + + w += 16; + h += 16; + +#if ( ( KDE_VERSION_MAJOR == 3 ) && ( KDE_VERSION_MINOR <= 1 ) ) + QWidget* dw = QApplication::desktop( ); + if( w > dw->width( ) ) + w = dw->width( ); + if( h > dw->height( ) ) + h = dw->height( ); +#else + QRect dw = KGlobalSettings::desktopGeometry(this); + if( w > dw.width() ) + w = dw.width(); + if( h > dw.height() ) + h = dw.height(); +#endif + resize( w, h ); + } + + if( m_pRenderWidget->render( scene, m, documentURL ) ) + { + m_bRunning = true; + m_pProgressBar->setProgress( 0 ); + m_pProgressBar->show( ); + m_pProgressLabel->setText( i18n( "running" ) ); + m_pStopButton->setEnabled( true ); + m_pSuspendButton->setEnabled( true ); + m_pResumeButton->setEnabled( false ); + m_pSaveButton->setEnabled( false ); + + m_lastSpeedTime = QTime( ); + m_pProgressTimer->start( timerIntervall, true ); + m_speedInfo = false; + m_speed = 0; + m_line = 0; + m_immediateUpdate = false; + showSpeed( 0 ); + } + + return m_bRunning; +} + +void PMPovrayWidget::slotStop( ) +{ + m_stopped = true; + m_pRenderWidget->killRendering( ); + m_pSaveButton->setEnabled( true ); +} + +void PMPovrayWidget::slotSuspend( ) +{ + m_pRenderWidget->suspendRendering( ); + m_pSuspendButton->setEnabled( false ); + m_pResumeButton->setEnabled( true ); + m_pSaveButton->setEnabled( true ); + + m_pProgressTimer->stop( ); + m_lastSpeedTime = QTime( ); + m_speedInfo = false; + m_immediateUpdate = false; + m_pProgressLabel->setText( i18n( "suspended" ) ); +} + +void PMPovrayWidget::slotResume( ) +{ + m_pRenderWidget->resumeRendering( ); + m_pSuspendButton->setEnabled( true ); + m_pResumeButton->setEnabled( false ); + m_pSaveButton->setEnabled( false ); + + m_pProgressTimer->start( timerIntervall, true ); + showSpeed( m_speed ); +} + +void PMPovrayWidget::slotClose( ) +{ + hide( ); +} + +void PMPovrayWidget::slotSave( ) +{ + KTempFile* tempFile = 0; + QFile* file = 0; + bool ok = true; + + if( !s_imageFormatsRegistered ) + { + KImageIO::registerFormats( ); + s_imageFormatsRegistered = true; + } + + KURL url = KFileDialog::getSaveURL( QString::null, KImageIO::pattern( KImageIO::Writing ) ); + if( url.isEmpty( ) ) + return; + if( !PMShell::overwriteURL( url ) ) + return; + + if( !url.isValid( ) ) + { + KMessageBox::error( this, i18n( "Malformed URL" ) ); + return; + } + + QString format = KImageIO::type( url.fileName( ) ); + if( format.isEmpty( ) ) + { + KMessageBox::error( this, i18n( "Unknown image format.\n" + "Please enter a valid suffix." ) ); + return; + } + + if( !KImageIO::canWrite( format ) ) + { + KMessageBox::error( this, i18n( "Format is not supported for writing." ) ); + return; + } + + if( url.isLocalFile( ) ) + { + // Local file + file = new QFile( url.path( ) ); + if( !file->open( IO_WriteOnly ) ) + ok = false; + } + else + { + // Remote file + // provide a temp file + tempFile = new KTempFile( ); + if( tempFile->status( ) != 0 ) + ok = false; + else + file = tempFile->file( ); + } + + if( ok ) + { + QImageIO iio( file, format.latin1( ) ); + iio.setImage( m_pRenderWidget->image( ) ); + ok = iio.write( ); + + if( ok ) + { + if( tempFile ) + { + tempFile->close( ); + ok = KIO::NetAccess::upload( tempFile->name( ), url ); + tempFile->unlink( ); + file = 0; + } + else + file->close( ); + } + else + KMessageBox::error( this, i18n( "Couldn't correctly write the image.\n" + "Wrong image format?" ) ); + } + else + KMessageBox::error( this, i18n( "Couldn't write the image.\n" + "Permission denied." ) ); + + + delete file; + delete tempFile; +} + +void PMPovrayWidget::slotPovrayOutput( ) +{ + m_pPovrayOutputWidget->show( ); +} + +void PMPovrayWidget::slotRenderingFinished( int returnStatus ) +{ + kdDebug( PMArea ) << "Povray exited with status " << returnStatus << endl; + m_bRunning = false; + if( returnStatus == 0 ) + m_pSaveButton->setEnabled( true ); + m_pStopButton->setEnabled( false ); + m_pSuspendButton->setEnabled( false ); + m_pResumeButton->setEnabled( false ); + m_pProgressLabel->setText( i18n( "finished" ) ); + m_pProgressTimer->stop( ); + + if( ( returnStatus != 0 ) && !m_stopped ) + { + KMessageBox::error( this, i18n( "Povray exited abnormally.\n" + "See the povray output for details." ) + .arg( returnStatus ) ); + } + else if( m_pRenderWidget->povrayOutput( ).contains( "ERROR" ) ) + { + KMessageBox::error( this, i18n( "There were errors while rendering.\n" + "See the povray output for details." ) ); + } +} + +void PMPovrayWidget::slotProgress( int i ) +{ + m_pProgressBar->setProgress( i ); +} + +void PMPovrayWidget::slotLineFinished( int line ) +{ + m_speedInfo = true; + QTime ct = QTime::currentTime( ); + + if( !m_lastSpeedTime.isNull( ) ) + { + int msecs = m_lastSpeedTime.msecsTo( ct ); + if( msecs < 1 ) + msecs = 1; + + double g = 1.0 / ( ( double ) msecs / 500.0 + 1.0 ); + m_speed = g * m_speed + + 1000 * ( 1.0 - g ) * m_width * ( line - m_line ) / msecs; + } + + if( m_immediateUpdate ) + { + m_immediateUpdate = false; + showSpeed( m_speed ); + m_pProgressTimer->start( timerIntervall, true ); + m_speedInfo = false; + } + + m_lastSpeedTime = ct; + m_line = line; +} + +void PMPovrayWidget::slotUpdateSpeed( ) +{ + if( m_speedInfo ) + { + showSpeed( m_speed ); + m_pProgressTimer->start( timerIntervall, true ); + m_speedInfo = false; + } + else + m_immediateUpdate = true; +} + +void PMPovrayWidget::showSpeed( double pps ) +{ + QString num; + if( pps >= 1000000 ) + { + num.setNum( pps / 100000, 'g', 3 ); + num += 'M'; + } + else if( pps >= 1000 ) + { + num.setNum( pps / 1000, 'g', 3 ); + num += 'K'; + } + else + num.setNum( pps, 'g', 3 ); + + m_pProgressLabel->setText( i18n( "running, %1 pixels/second" ).arg( num ) ); +} + +#include "pmpovraywidget.moc" diff --git a/kpovmodeler/pmpovraywidget.h b/kpovmodeler/pmpovraywidget.h new file mode 100644 index 00000000..26d5bb1e --- /dev/null +++ b/kpovmodeler/pmpovraywidget.h @@ -0,0 +1,103 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMPOVRAYWIDGET_H +#define PMPOVRAYWIDGET_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +class PMPovrayRenderWidget; +class PMPovrayOutputWidget; +class PMRenderMode; + +class QProgressBar; +class QPushButton; +class QLabel; +class QScrollView; +class KURL; + +/** + * Widget with toolbar, statusbar and a @ref PMPovrayRenderWidget + */ +class PMPovrayWidget : public KDialog +{ + Q_OBJECT +public: + /** + * Standard constructor + */ + PMPovrayWidget( QWidget* parent = 0, const char* name = 0 ); + /** + * Destructor + */ + virtual ~PMPovrayWidget( ); + + /** + * Starts rendering for the povray code in the byte array with + * render mode m. + * @see PMRenderMode + */ + bool render( const QByteArray& scene, const PMRenderMode& m, + const KURL& documentURL ); + +public slots: + void slotStop( ); + void slotSuspend( ); + void slotResume( ); + void slotClose( ); + void slotSave( ); + void slotPovrayOutput( ); + +protected slots: + void slotRenderingFinished( int returnStatus ); + void slotProgress( int i ); + void slotLineFinished( int line ); + void slotUpdateSpeed( ); + +protected: + void showSpeed( double pps ); + +private: + PMPovrayRenderWidget* m_pRenderWidget; + PMPovrayOutputWidget* m_pPovrayOutputWidget; + QPushButton* m_pStopButton; + QPushButton* m_pSuspendButton; + QPushButton* m_pResumeButton; + QPushButton* m_pSaveButton; + QPushButton* m_pPovrayOutputButton; + QProgressBar* m_pProgressBar; + QLabel* m_pProgressLabel; + QScrollView* m_pScrollView; + int m_height, m_width; + bool m_bRunning; + QTime m_lastSpeedTime; + QTimer* m_pProgressTimer; + bool m_speedInfo; + bool m_immediateUpdate; + float m_speed; + int m_line; + bool m_stopped; + static bool s_imageFormatsRegistered; +}; + +#endif diff --git a/kpovmodeler/pmpreviewsettings.cpp b/kpovmodeler/pmpreviewsettings.cpp new file mode 100644 index 00000000..1254431e --- /dev/null +++ b/kpovmodeler/pmpreviewsettings.cpp @@ -0,0 +1,207 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmpreviewsettings.h" + +#include "pmlineedits.h" +#include "pmdialogeditbase.h" +#include "pmdefaults.h" + +#include +#include +#include +#include +#include +#include +#include + +PMPreviewSettings::PMPreviewSettings( QWidget* parent, const char* name ) + : PMSettingsDialogPage( parent, name ) +{ + QHBoxLayout* hlayout; + QVBoxLayout* vlayout; + QVBoxLayout* gvl; + QGridLayout* grid; + QGroupBox* gb; + + vlayout = new QVBoxLayout( this, 0, KDialog::spacingHint( ) ); + + hlayout = new QHBoxLayout( vlayout ); + grid = new QGridLayout( hlayout, 2, 2 ); + grid->addWidget( new QLabel( i18n( "Size:" ), this ), 0, 0 ); + m_pPreviewSize = new PMIntEdit( this ); + m_pPreviewSize->setValidation( true, 10, true, 400 ); + grid->addWidget( m_pPreviewSize, 0, 1 ); + + grid->addWidget( new QLabel( i18n( "Gamma:" ), this ), 1, 0 ); + m_pPreviewGamma = new PMFloatEdit( this ); + grid->addWidget( m_pPreviewGamma, 1, 1 ); + hlayout->addStretch( 1 ); + + gb = new QGroupBox( i18n( "Rendered Objects" ), this ); + vlayout->addWidget( gb ); + gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) ); + gvl->addSpacing( 10 ); + m_pPreviewSphere = new QCheckBox( i18n( "Sphere" ), gb ); + gvl->addWidget( m_pPreviewSphere ); + m_pPreviewCylinder = new QCheckBox( i18n( "Cylinder" ), gb ); + gvl->addWidget( m_pPreviewCylinder ); + m_pPreviewBox = new QCheckBox( i18n( "Box" ), gb ); + gvl->addWidget( m_pPreviewBox ); + + gb = new QGroupBox( i18n( "Wall" ), this ); + vlayout->addWidget( gb ); + gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) ); + gvl->addSpacing( 10 ); + m_pPreviewWall = new QCheckBox( i18n( "Enable wall" ), gb ); + gvl->addWidget( m_pPreviewWall ); + hlayout = new QHBoxLayout( gvl ); + hlayout->addWidget( new QLabel( i18n( "Color 1:" ), gb ) ); + m_pWallColor1 = new KColorButton( gb ); + hlayout->addWidget( m_pWallColor1 ); + hlayout->addWidget( new QLabel( i18n( "Color 2:" ), gb ) ); + m_pWallColor2 = new KColorButton( gb ); + hlayout->addWidget( m_pWallColor2 ); + hlayout->addStretch( 1 ); + + gb = new QGroupBox( i18n( "Floor" ), this ); + vlayout->addWidget( gb ); + gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) ); + gvl->addSpacing( 10 ); + m_pPreviewFloor = new QCheckBox( i18n( "Enable floor" ), gb ); + gvl->addWidget( m_pPreviewFloor ); + hlayout = new QHBoxLayout( gvl ); + hlayout->addWidget( new QLabel( i18n( "Color 1:" ), gb ) ); + m_pFloorColor1 = new KColorButton( gb ); + hlayout->addWidget( m_pFloorColor1 ); + hlayout->addWidget( new QLabel( i18n( "Color 2:" ), gb ) ); + m_pFloorColor2 = new KColorButton( gb ); + hlayout->addWidget( m_pFloorColor2 ); + hlayout->addStretch( 1 ); + + gb = new QGroupBox( i18n( "Antialiasing" ), this ); + vlayout->addWidget( gb ); + gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) ); + gvl->addSpacing( 10 ); + m_pPreviewAA = new QCheckBox( i18n( "Enable antialiasing" ), gb ); + gvl->addWidget( m_pPreviewAA ); + hlayout = new QHBoxLayout( gvl ); + hlayout->addWidget( new QLabel( i18n( "Depth:" ), gb ) ); + m_pPreviewAALevel = new PMIntEdit( gb ); + m_pPreviewAALevel->setValidation( true, 1, true, 9 ); + hlayout->addWidget( m_pPreviewAALevel ); + hlayout->addWidget( new QLabel( i18n( "Threshold:" ), gb ) ); + m_pPreviewAAThreshold = new PMFloatEdit( gb ); + hlayout->addWidget( m_pPreviewAAThreshold ); + hlayout->addStretch( 1 ); + + vlayout->addStretch( 1 ); +} + +void PMPreviewSettings::displaySettings( ) +{ + m_pPreviewSize->setValue( PMDialogEditBase::previewSize( ) ); + m_pPreviewGamma->setValue( PMDialogEditBase::previewGamma( ) ); + m_pPreviewSphere->setChecked( PMDialogEditBase::previewShowSphere( ) ); + m_pPreviewCylinder->setChecked( PMDialogEditBase::previewShowCylinder( ) ); + m_pPreviewBox->setChecked( PMDialogEditBase::previewShowBox( ) ); + m_pPreviewAA->setChecked( PMDialogEditBase::isPreviewAAEnabled( ) ); + m_pPreviewAALevel->setValue( PMDialogEditBase::previewAADepth( ) ); + m_pPreviewAAThreshold->setValue( PMDialogEditBase::previewAAThreshold( ) ); + m_pPreviewWall->setChecked( PMDialogEditBase::previewShowWall( ) ); + m_pPreviewFloor->setChecked( PMDialogEditBase::previewShowFloor( ) ); + m_pFloorColor1->setColor( PMDialogEditBase::previewFloorColor1( ) ); + m_pFloorColor2->setColor( PMDialogEditBase::previewFloorColor2( ) ); + m_pWallColor1->setColor( PMDialogEditBase::previewWallColor1( ) ); + m_pWallColor2->setColor( PMDialogEditBase::previewWallColor2( ) ); +} + +void PMPreviewSettings::displayDefaults( ) +{ + m_pPreviewSize->setValue( c_defaultTPSize ); + m_pPreviewGamma->setValue( c_defaultTPGamma ); + m_pPreviewSphere->setChecked( c_defaultTPShowSphere ); + m_pPreviewCylinder->setChecked( c_defaultTPShowCylinder ); + m_pPreviewBox->setChecked( c_defaultTPShowBox ); + m_pPreviewAA->setChecked( c_defaultTPAA ); + m_pPreviewAALevel->setValue( c_defaultTPAADepth ); + m_pPreviewAAThreshold->setValue( c_defaultTPAAThreshold ); + m_pPreviewWall->setChecked( c_defaultTPShowWall ); + m_pPreviewFloor->setChecked( c_defaultTPShowFloor ); + m_pFloorColor1->setColor( c_defaultTPFloorColor1 ); + m_pFloorColor2->setColor( c_defaultTPFloorColor2 ); + m_pWallColor1->setColor( c_defaultTPWallColor1 ); + m_pWallColor2->setColor( c_defaultTPWallColor2 ); +} + +bool PMPreviewSettings::validateData( ) +{ + if( !m_pPreviewSize->isDataValid( ) ) + { + emit showMe( ); + m_pPreviewSize->setFocus( ); + return false; + } + if( !m_pPreviewGamma->isDataValid( ) ) + { + emit showMe( ); + m_pPreviewGamma->setFocus( ); + return false; + } + if( !m_pPreviewAALevel->isDataValid( ) ) + { + emit showMe( ); + m_pPreviewAALevel->setFocus( ); + return false; + } + if( !m_pPreviewAAThreshold->isDataValid( ) ) + { + emit showMe( ); + m_pPreviewAAThreshold->setFocus( ); + return false; + } + if( !( m_pPreviewSphere->isChecked( ) || m_pPreviewCylinder->isChecked( ) + || m_pPreviewBox->isChecked( ) ) ) + { + emit showMe( ); + KMessageBox::error( this, i18n( "At least one object has to be selected." ), + i18n( "Error" ) ); + + return false; + } + return true; +} + +void PMPreviewSettings::applySettings( ) +{ + PMDialogEditBase::setPreviewSize( m_pPreviewSize->value( ) ); + PMDialogEditBase::setPreviewGamma( m_pPreviewGamma->value( ) ); + PMDialogEditBase::previewShowSphere( m_pPreviewSphere->isChecked( ) ); + PMDialogEditBase::previewShowCylinder( m_pPreviewCylinder->isChecked( ) ); + PMDialogEditBase::previewShowBox( m_pPreviewBox->isChecked( ) ); + PMDialogEditBase::setPreviewAAEnabled( m_pPreviewAA->isChecked( ) ); + PMDialogEditBase::setPreviewAADepth( m_pPreviewAALevel->value( ) ); + PMDialogEditBase::setPreviewAAThreshold( m_pPreviewAAThreshold->value( ) ); + PMDialogEditBase::previewShowFloor( m_pPreviewFloor->isChecked( ) ); + PMDialogEditBase::previewShowWall( m_pPreviewWall->isChecked( ) ); + PMDialogEditBase::setPreviewWallColor1( m_pWallColor1->color( ) ); + PMDialogEditBase::setPreviewWallColor2( m_pWallColor2->color( ) ); + PMDialogEditBase::setPreviewFloorColor1( m_pFloorColor1->color( ) ); + PMDialogEditBase::setPreviewFloorColor2( m_pFloorColor2->color( ) ); +} + +#include "pmpreviewsettings.moc" diff --git a/kpovmodeler/pmpreviewsettings.h b/kpovmodeler/pmpreviewsettings.h new file mode 100644 index 00000000..a0983002 --- /dev/null +++ b/kpovmodeler/pmpreviewsettings.h @@ -0,0 +1,69 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMPREVIEWSETTINGS_H +#define PMPREVIEWSETTINGS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsettingsdialog.h" + +class PMIntEdit; +class PMFloatEdit; +class QCheckBox; +class KColorButton; + +/** + * Texture preview configuration dialog page + */ +class PMPreviewSettings : public PMSettingsDialogPage +{ + Q_OBJECT +public: + /** + * Default constructor + */ + PMPreviewSettings( QWidget* parent, const char* name = 0 ); + /** */ + virtual void displaySettings( ); + /** */ + virtual bool validateData( ); + /** */ + virtual void applySettings( ); + /** */ + virtual void displayDefaults( ); + +private: + PMIntEdit* m_pPreviewSize; + QCheckBox* m_pPreviewSphere; + QCheckBox* m_pPreviewCylinder; + QCheckBox* m_pPreviewBox; + QCheckBox* m_pPreviewAA; + PMIntEdit* m_pPreviewAALevel; + PMFloatEdit* m_pPreviewAAThreshold; + QCheckBox* m_pPreviewWall; + QCheckBox* m_pPreviewFloor; + KColorButton* m_pFloorColor1; + KColorButton* m_pFloorColor2; + KColorButton* m_pWallColor1; + KColorButton* m_pWallColor2; + PMFloatEdit* m_pPreviewGamma; +}; + +#endif diff --git a/kpovmodeler/pmprism.cpp b/kpovmodeler/pmprism.cpp new file mode 100644 index 00000000..26fa9035 --- /dev/null +++ b/kpovmodeler/pmprism.cpp @@ -0,0 +1,1187 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmprism.h" + +#include "pmxmlhelper.h" +#include "pmprismedit.h" +#include "pmmemento.h" +#include "pmviewstructure.h" +#include "pm2dcontrolpoint.h" +#include "pmdistancecontrolpoint.h" +#include "pmprismmemento.h" +#include "pmsplinesegment.h" +#include "pmdefaults.h" +#include "pmenumproperty.h" +#include "pmobjectaction.h" + +#include + +const int defaultNumberOfPoints = 6; +const PMVector defaultPoint[defaultNumberOfPoints] = +{ + PMVector( 0.5, 1.0 ), + PMVector( 1.0, 0.0 ), + PMVector( 0.5, -1.0 ), + PMVector( -0.5, -1.0 ), + PMVector( -1.0, 0.0 ), + PMVector( -0.5, 1.0 ), +}; + +const bool defaultSturm = false; +const bool defaultOpen = false; +const PMPrism::SplineType defaultSplineType = PMPrism::LinearSpline; +const PMPrism::SweepType defaultSweepType = PMPrism::LinearSweep; +const double defaultHeight1 = 0.0; +const double defaultHeight2 = 1.0; + +int PMPrism::s_sSteps = c_defaultPrismSSteps; +int PMPrism::s_parameterKey = 0; +PMMetaObject* PMPrism::s_pMetaObject = 0; +PMObject* createNewPrism( PMPart* part ) +{ + return new PMPrism( part ); +} + +PMDefinePropertyClass( PMPrism, PMPrismProperty ); +PMDefineEnumPropertyClass( PMPrism, PMPrism::SplineType, PMSplineTypeProperty ); +PMDefineEnumPropertyClass( PMPrism, PMPrism::SweepType, PMSweepTypeProperty ); + +class PMPointProperty : public PMPropertyBase +{ +public: + PMPointProperty( ) + : PMPropertyBase( "splinePoints", PMVariant::Vector ) + { + m_index[0] = 0; + m_index[1] = 0; + } + virtual int dimensions( ) const { return 2; } + virtual void setIndex( int dimension, int index ) + { + if( dimension == 0 || dimension == 1 ) + m_index[dimension] = index; + } + virtual int size( PMObject* object, int dimension ) const + { + PMPrism* prism = ( PMPrism* ) object; + QValueList< QValueList > points = prism->points( ); + if( dimension == 0 ) + return points.size( ); + else + { + QValueList< QValueList >::ConstIterator it + = points.at( m_index[0] ); + if( it != points.end( ) ) + return ( *it ).size( ); + } + return 0; + } +protected: + virtual bool setProtected( PMObject* obj, const PMVariant& var ) + { + PMPrism* p = ( PMPrism* ) obj; + QValueList< QValueList > list = p->points( ); + QValueList< QValueList >::Iterator sit = list.begin( ); + int i; + PMVector v = var.vectorData( ); + v.resize( 2 ); + + for( i = 0; i < m_index[0] && sit != list.end( ); ++i ) + ++sit; + // expand the list if necessary + for( ; i < m_index[0]; ++i ) + list.insert( sit, QValueList< PMVector >( ) ); + if( sit == list.end( ) ) + sit = list.insert( sit, QValueList< PMVector >( ) ); + + QValueList::Iterator it = ( *sit ).begin( ); + + for( i = 0; i < m_index[1] && it != ( *sit ).end( ); ++i ) + ++it; + // expand the list if necessary + for( ; i < m_index[1]; ++i ) + ( *sit ).insert( it, v ); + if( it == ( *sit ).end( ) ) + it = ( *sit ).insert( it, v ); + else + *it = v; + + p->setPoints( list ); + return true; + } + virtual PMVariant getProtected( const PMObject* obj ) + { + PMPrism* p = ( PMPrism* ) obj; + QValueList< QValueList > list = p->points( ); + QValueList< QValueList >::ConstIterator sit = list.at( m_index[0] ); + if( sit == list.end( ) ) + { + kdError( PMArea ) << "Range error in PMPrism::PointProperty::get" << endl; + return PMVariant( ); + } + + QValueList::ConstIterator it = ( *sit ).at( m_index[1] ); + + if( it == ( *sit ).end( ) ) + { + kdError( PMArea ) << "Range error in PMPrism::PointProperty::get" << endl; + return PMVariant( ); + } + + return PMVariant( *it ); + } + +private: + int m_index[2]; +}; + +PMPrism::PMPrism( PMPart* part ) + : Base( part ) +{ + int i; + QValueList p; + + for( i = 0; i < defaultNumberOfPoints; ++i ) + p.append( defaultPoint[i] ); + m_points.append( p ); + m_splineType = defaultSplineType; + m_sweepType = defaultSweepType; + m_sturm = defaultSturm; + m_open = defaultOpen; + m_height1 = defaultHeight1; + m_height2 = defaultHeight2; +} + +PMPrism::PMPrism( const PMPrism& p ) + : Base( p ) +{ + m_splineType = p.m_splineType; + m_sweepType = p.m_sweepType; + m_points = p.m_points; + m_height1 = p.m_height1; + m_height2 = p.m_height2; + m_open = p.m_open; + m_sturm = p.m_sturm; +} + +PMPrism::~PMPrism( ) +{ +} + +QString PMPrism::description( ) const +{ + return i18n( "prism" ); +} + +void PMPrism::serialize( QDomElement& e, QDomDocument& doc ) const +{ + QDomElement data = doc.createElement( "extra_data" ); + QDomElement p, p2; + + e.setAttribute( "spline_type", m_splineType ); + e.setAttribute( "sweep_type", m_sweepType ); + e.setAttribute( "sturm", m_sturm ); + e.setAttribute( "open", m_open ); + e.setAttribute( "height1", m_height1 ); + e.setAttribute( "height2", m_height2 ); + + QValueList< QValueList >::ConstIterator it; + QValueList::ConstIterator it2; + for( it = m_points.begin( ); it != m_points.end( ); ++it ) + { + p = doc.createElement( "sub_prism" ); + for( it2 = ( *it ).begin( ); it2 != ( *it ).end( ); ++it2 ) + { + p2 = doc.createElement( "point" ); + p2.setAttribute( "vector", ( *it2 ).serializeXML( ) ); + p.appendChild( p2 ); + } + data.appendChild( p ); + } + + e.appendChild( data ); + Base::serialize( e, doc ); +} + +void PMPrism::readAttributes( const PMXMLHelper& h ) +{ + m_splineType = ( SplineType ) h.intAttribute( "spline_type", defaultSplineType ); + m_sweepType = ( SweepType ) h.intAttribute( "sweep_type", defaultSweepType ); + m_open = h.boolAttribute( "open", defaultOpen ); + m_sturm = h.boolAttribute( "sturm", defaultSturm ); + m_height1 = h.doubleAttribute( "height1", defaultHeight1 ); + m_height2 = h.doubleAttribute( "height2", defaultHeight2 ); + + m_points.clear( ); + QValueList list; + PMVector v( 2 ); + + QDomElement e = h.extraData( ); + if( !e.isNull( ) ) + { + QDomNode sp = e.firstChild( ); + while( !sp.isNull( ) ) + { + if( sp.isElement( ) ) + { + QDomElement spe = sp.toElement( ); + if( spe.tagName( ) == "sub_prism" ) + { + list.clear( ); + QDomNode c = spe.firstChild( ); + while( !c.isNull( ) ) + { + if( c.isElement( ) ) + { + QDomElement ce = c.toElement( ); + if( ce.tagName( ) == "point" ) + { + QString str = ce.attribute( "vector" ); + if( !str.isNull( ) ) + { + v.loadXML( str ); + list.append( v ); + } + } + } + c = c.nextSibling( ); + } + m_points.append( list ); + } + } + sp = sp.nextSibling( ); + } + } + + Base::readAttributes( h ); +} + +PMMetaObject* PMPrism::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Prism", Base::metaObject( ), + createNewPrism ); + s_pMetaObject->addProperty( + new PMPrismProperty( "sturm", &PMPrism::setSturm, &PMPrism::sturm ) ); + s_pMetaObject->addProperty( + new PMPrismProperty( "open", &PMPrism::setOpen, &PMPrism::open ) ); + s_pMetaObject->addProperty( + new PMPrismProperty( "height1", &PMPrism::setHeight1, &PMPrism::height1 ) ); + s_pMetaObject->addProperty( + new PMPrismProperty( "height2", &PMPrism::setHeight2, &PMPrism::height2 ) ); + + PMSplineTypeProperty* p = new PMSplineTypeProperty( + "splineType", &PMPrism::setSplineType, &PMPrism::splineType ); + p->addEnumValue( "LinearSpline", LinearSpline ); + p->addEnumValue( "QuadraticSpline", QuadraticSpline ); + p->addEnumValue( "CubicSpline", CubicSpline ); + p->addEnumValue( "BezierSpline", BezierSpline ); + s_pMetaObject->addProperty( p ); + + PMSweepTypeProperty* sp = new PMSweepTypeProperty( + "sweepType", &PMPrism::setSweepType, &PMPrism::sweepType ); + sp->addEnumValue( "LinearSweep", LinearSweep ); + sp->addEnumValue( "ConicSweep", ConicSweep ); + s_pMetaObject->addProperty( sp ); + + s_pMetaObject->addProperty( new PMPointProperty( ) ); + } + return s_pMetaObject; +} + +void PMPrism::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMPrism::setSplineType( PMPrism::SplineType t ) +{ + if( m_splineType != t ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSplineTypeID, ( int ) m_splineType ); + setViewStructureChanged( ); + m_splineType = t; + } +} + +void PMPrism::setSweepType( PMPrism::SweepType t ) +{ + if( m_sweepType != t ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSweepTypeID, ( int ) m_sweepType ); + setViewStructureChanged( ); + m_sweepType = t; + } +} + +void PMPrism::setSturm( bool s ) +{ + if( m_sturm != s ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSturmID, m_sturm ); + m_sturm = s; + } +} + +void PMPrism::setOpen( bool o ) +{ + if( m_open != o ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMOpenID, m_open ); + m_open = o; + } +} + +void PMPrism::setHeight1( double h ) +{ + if( m_height1 != h ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMHeight1ID, m_height1 ); + m_height1 = h; + setViewStructureChanged( ); + } +} + +void PMPrism::setHeight2( double h ) +{ + if( m_height2 != h ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMHeight2ID, m_height2 ); + m_height2 = h; + setViewStructureChanged( ); + } +} + +void PMPrism::setPoints( const QValueList< QValueList >& points ) +{ + if( m_points != points ) + { + if( m_pMemento ) + ( ( PMPrismMemento* ) m_pMemento )->setPrismPoints( m_points ); + + setViewStructureChanged( ); + m_points = points; + } +} + +PMDialogEditBase* PMPrism::editWidget( QWidget* parent ) const +{ + return new PMPrismEdit( parent ); +} + +void PMPrism::createMemento( ) +{ + if( m_pMemento ) + delete m_pMemento; + m_pMemento = new PMPrismMemento( this ); +} + +void PMPrism::restoreMemento( PMMemento* s ) +{ + PMPrismMemento* m = ( PMPrismMemento* ) s; + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMSplineTypeID: + setSplineType( ( SplineType ) data->intData( ) ); + break; + case PMSweepTypeID: + setSweepType( ( SweepType ) data->intData( ) ); + break; + case PMOpenID: + setOpen( data->boolData( ) ); + break; + case PMSturmID: + setSturm( data->boolData( ) ); + break; + case PMHeight1ID: + setHeight1( data->doubleData( ) ); + break; + case PMHeight2ID: + setHeight2( data->doubleData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMPrism::restoreMemento\n"; + break; + } + } + } + if( m->prismPointsSaved( ) ) + setPoints( m->prismPoints( ) ); + + Base::restoreMemento( s ); +} + + +void PMPrism::createViewStructure( ) +{ + if( s_sSteps == 0 ) + s_sSteps = c_defaultPrismSSteps; + + int sSteps = (int)( ( (float)s_sSteps / 2 ) * ( displayDetail( ) + 1 ) ); + + // calculate number of points and lines of the view structure + QValueList< QValueList >::ConstIterator spit = m_points.begin( ); + int np = 0; + for( ; spit != m_points.end( ); ++spit ) + { + int snp = ( *spit ).count( ); + switch( m_splineType ) + { + case LinearSpline: + break; + case QuadraticSpline: + snp -= 1; + break; + case CubicSpline: + snp -= 2; + break; + case BezierSpline: + snp /= 3; + break; + } + np += snp; + } + + int nl = 0; + nl = np * sSteps * 3; + np *= sSteps * 2; + + if( m_pViewStructure ) + { + if( m_pViewStructure->points( ).size( ) != ( unsigned ) np ) + m_pViewStructure->points( ).resize( np ); + if( m_pViewStructure->lines( ).size( ) != ( unsigned ) nl ) + m_pViewStructure->lines( ).resize( nl ); + } + else + m_pViewStructure = new PMViewStructure( np, nl ); + + PMLineArray& lines = m_pViewStructure->lines( ); + PMPointArray& points = m_pViewStructure->points( ); + int lb = 0; + int pb = 0; + + for( spit = m_points.begin( ); spit != m_points.end( ); ++spit ) + { + QValueList segments; + QValueList fullPoints = expandedPoints( *spit ); + + int ns = fullPoints.count( ); + int i, j; + + switch( m_splineType ) + { + case LinearSpline: + ns -= 1; + break; + case QuadraticSpline: + ns -= 2; + break; + case CubicSpline: + ns -= 3; + break; + case BezierSpline: + ns = ns / 4; + break; + } + QValueList::Iterator it1, it2, it3, it4; + + // create the spline segments + it1 = fullPoints.begin( ); + it2 = it1; ++it2; + it3 = it2; ++it3; + it4 = it3; ++it4; + PMSplineSegment s; + + for( i = 0; i < ns; ++i ) + { + switch( m_splineType ) + { + case LinearSpline: + s.calculateLinear( *it1, *it2 ); + ++it1; + ++it2; + break; + case QuadraticSpline: + s.calculateQuadratic( *it1, *it2, *it3 ); + ++it1; + ++it2; + ++it3; + break; + case CubicSpline: + s.calculateCubic( *it1, *it2, *it3, *it4 ); + ++it1; + ++it2; + ++it3; + ++it4; + break; + case BezierSpline: + s.calculateBezier( *it1, *it2, *it3, *it4 ); + for( j = 0; j < 4; ++j ) + { + ++it1; + ++it2; + ++it3; + ++it4; + } + break; + } + segments.append( s ); + } + + // create the line array + int vp = ns * sSteps; + for( i = 0; i < vp - 1; ++i ) + lines[lb+i] = PMLine( pb + i, pb + i + 1 ); + lines[lb+vp-1] = PMLine( pb, pb + vp - 1 ); + lb += vp; + for( i = 0; i < vp - 1; ++i ) + lines[lb+i] = PMLine( pb + vp + i, pb + vp + i + 1 ); + lines[lb+vp-1] = PMLine( pb + vp, pb + vp + vp - 1 ); + lb += vp; + for( i = 0; i < vp; ++i ) + lines[lb+i] = PMLine( pb + i, pb + vp + i ); + lb += vp; + + // calculate the points + PMVector point2( 2 ), point3; + QValueList::Iterator sit = segments.begin( ); + int pi = 0; + double poffset = 1.0 / sSteps; + + for( i = 0; i < ns; ++i, ++sit ) + { + for( j = 0; j < sSteps; ++j ) + { + point2 = ( *sit ).point( poffset * j ); + if( m_sweepType == LinearSweep ) + { + point3[0] = point2[0]; + point3[1] = m_height1; + point3[2] = point2[1]; + points[pb+pi] = PMPoint( point3 ); + point3[1] = m_height2; + points[pb+pi+vp] = PMPoint( point3 ); + } + else + { + point3[0] = point2[0]; + point3[1] = 1.0; + point3[2] = point2[1]; + points[pb+pi] = PMPoint( point3 * m_height1 ); + points[pb+pi+vp] = PMPoint( point3 * m_height2 ); + } + ++pi; + } + } + pb += vp * 2; + } +} + +void PMPrism::controlPoints( PMControlPointList& list ) +{ + QValueList< QValueList >::Iterator it1; + QValueList::Iterator it2; + int i1, i2; + + list.append( new PMDistanceControlPoint( PMVector( 0.0, 0.0, 0.0 ), + PMVector( 0.0, 1.0, 0.0 ), + m_height1, PMHeight1ID, + i18n( "Height 1" ) ) ); + list.append( new PMDistanceControlPoint( PMVector( 0.0, 0.0, 0.0 ), + PMVector( 0.0, 1.0, 0.0 ), + m_height2, PMHeight2ID, + i18n( "Height 2" ) ) ); + + PM2DControlPoint* cp; + + for( it1 = m_points.begin( ), i1 = 0; it1 != m_points.end( ); ++it1, ++i1 ) + { + if( m_splineType != BezierSpline ) + { + int refb = ( *it1 ).count( ) - 1; + if( m_splineType == CubicSpline ) + --refb; + it2 = ( *it1 ).begin( ); + PM2DControlPoint* firstPoint = 0; + PM2DControlPoint* secondPoint = 0; + + for( i2 = 0; it2 != ( *it1 ).end( ); ++it2, ++i2 ) + { + cp = new PM2DControlPoint( *it2, PM2DControlPoint::PM2DXZ, i2, + i18n( "Point %1.%2" ).arg( i1 + 1 ).arg( i2 + 1 ) ); + if( i2 == 0 ) + firstPoint = cp; + else if( i2 == 1 ) + secondPoint = cp; + + cp->setThirdCoordinate( m_height2 ); + if( m_sweepType == ConicSweep ) + cp->setScale( m_height2 ); + if( ( ( m_splineType == QuadraticSpline ) + || ( m_splineType == CubicSpline ) ) + && ( i2 == 1 ) ) + firstPoint->setBasePoint( cp ); + if( ( m_splineType == CubicSpline ) && ( i2 == ( refb + 2 ) ) ) + cp->setBasePoint( secondPoint ); + + list.append( cp ); + + if( ( m_splineType != BezierSpline ) && ( i2 == refb ) ) + ++i2; + } + } + else + { + it2 = ( *it1 ).begin( ); + PM2DControlPoint* firstPoint = 0; + PM2DControlPoint* lastPoint = 0; + PM2DControlPoint* startPoint = 0; + + for( i2 = 0; it2 != ( *it1 ).end( ); ++it2, ++i2 ) + { + int i2mod4 = i2 % 4; + cp = new PM2DControlPoint( *it2, PM2DControlPoint::PM2DXZ, i2, + i18n( "Point %1.%2" ).arg( i1 + 1 ).arg( i2 + 1 ) ); + if( i2mod4 == 0 ) + firstPoint = cp; + if( i2mod4 == 2 ) + lastPoint = cp; + if( !startPoint ) + startPoint = cp; + + cp->setThirdCoordinate( m_height2 ); + if( m_sweepType == ConicSweep ) + cp->setScale( m_height2 ); + if( i2mod4 == 1 ) + cp->setBasePoint( firstPoint ); + if( ( i2mod4 == 0 ) && lastPoint ) + lastPoint->setBasePoint( cp ); + + list.append( cp ); + + if( i2mod4 == 2 ) + ++i2; + } + if( lastPoint ) + lastPoint->setBasePoint( startPoint ); + } + } +} + +void PMPrism::controlPointsChanged( PMControlPointList& list ) +{ + PMControlPointListIterator it( list ); + QValueList< QValueList >::Iterator spit = m_points.begin( ); + QValueList::Iterator pit = ( *spit ).begin( ); + PM2DControlPoint* p1; + PMDistanceControlPoint* dcp; + bool firstChange = true; + bool h2changed = false; + + // IDs are ignored, quick hack, but should work + if( it.current( )->changed( ) ) + { + dcp = ( PMDistanceControlPoint* ) it.current( ); + setHeight1( dcp->distance( ) ); + } + ++it; + if( it.current( )->changed( ) ) + { + dcp = ( PMDistanceControlPoint* ) it.current( ); + setHeight2( dcp->distance( ) ); + h2changed = true; + } + ++it; + + for( ; it.current( ); ++it ) + { + p1 = ( PM2DControlPoint* ) it.current( ); + if( p1->changed( ) ) + { + if( firstChange ) + { + if( m_pMemento ) + { + PMPrismMemento* m = ( PMPrismMemento* ) m_pMemento; + if( !m->prismPointsSaved( ) ) + m->setPrismPoints( m_points ); + } + firstChange = false; + setViewStructureChanged( ); + } + ( *pit ) = p1->point( ); + } + if( h2changed ) + { + p1->setThirdCoordinate( m_height2 ); + if( m_sweepType == ConicSweep ) + p1->setScale( m_height2 ); + } + + ++pit; + if( pit == ( *spit ).end( ) ) + { + ++spit; + pit = ( *spit ).begin( ); + } + } +} + +void PMPrism::addObjectActions( const PMControlPointList& /*cp*/, + QPtrList& actions ) +{ + PMObjectAction* a; + + a = new PMObjectAction( s_pMetaObject, PMSplitSegmentID, + i18n( "Add Point" ) ); + actions.append( a ); + + a = new PMObjectAction( s_pMetaObject, PMJoinSegmentsID, + i18n( "Remove Point" ) ); + + bool enableJoin = false; + QValueList< QValueList >::ConstIterator spit = m_points.begin( ); + + int minp = 4; + switch( m_splineType ) + { + case LinearSpline: + minp = 4; + break; + case QuadraticSpline: + minp = 5; + break; + case CubicSpline: + minp = 6; + break; + case BezierSpline: + minp = 6; + break; + } + + for( ; ( spit != m_points.end( ) ) && !enableJoin; ++spit ) + if( ( *spit ).count( ) >= ( unsigned ) minp ) + enableJoin = true; + + a->setEnabled( enableJoin ); + actions.append( a ); +} + +void PMPrism::objectActionCalled( const PMObjectAction* action, + const PMControlPointList& cp, + const QPtrList& cpViewPosition, + const PMVector& clickPosition ) +{ + if( action->objectType( ) == s_pMetaObject ) + { + switch( action->actionID( ) ) + { + case PMSplitSegmentID: + splitSegment( cp, cpViewPosition, clickPosition ); + break; + case PMJoinSegmentsID: + joinSegments( cp, cpViewPosition, clickPosition ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMPrism::objectActionCalled\n"; + break; + } + } + else + Base::objectActionCalled( action, cp, cpViewPosition, clickPosition ); +} + +void PMPrism::splitSegment( const PMControlPointList& /*cp*/, + const QPtrList& cpViewPosition, + const PMVector& clickPosition ) +{ + // find nearest segment + double abs = 0.0, minabs = 1e10; + int ns = -1; + int nsp = 0; + int spnr = 0, pnr = 0; + int i; + PMVector mid( 3 ), dist( 2 ); + PMVector firstPoint( 3 ); + + QPtrListIterator it1( cpViewPosition ); + QPtrListIterator it2( cpViewPosition ); + for( i = 0; i < 2; ++i ) ++it1; + for( i = 0; i < 3; ++i ) ++it2; + + QValueList< QValueList >::Iterator spit = m_points.begin( ); + for( spnr = 0; spit != m_points.end( ); ++spit, ++spnr ) + { + int nump = ( *spit ).count( ); + bool first = true; + for( pnr = 0; pnr < nump; ++pnr ) + { + bool skip = false; + switch( m_splineType ) + { + case LinearSpline: + case BezierSpline: + break; + case QuadraticSpline: + if( pnr == 0 ) + skip = true; + break; + case CubicSpline: + if( ( pnr == 0 ) || ( pnr == ( nump - 1 ) ) ) + skip = true; + break; + } + + if( !skip ) + { + if( first ) + { + firstPoint = **it1; + first = false; + } + + if( ( ( m_splineType == CubicSpline ) && ( pnr == ( nump - 2 ) ) ) + || ( ( m_splineType != CubicSpline ) && ( pnr == ( nump - 1 ) ) ) ) + mid = ( **it1 + firstPoint ) / 2.0; + else + mid = ( **it1 + **it2 ) / 2.0; + + dist[0] = mid[0]; + dist[1] = mid[1]; + dist -= clickPosition; + abs = dist.abs( ); + + if( ( minabs > abs ) || ( ns < 0 ) ) + { + minabs = abs; + ns = pnr; + nsp = spnr; + } + } + ++it1; + ++it2; + } + } + + // add a new segment + QValueList< QValueList > newPoints = m_points; + spit = newPoints.at( nsp ); + QValueList newSubPoints = *spit; + + if( m_splineType == BezierSpline ) + { + ns /= 3; + ns *= 3; + } + QValueList::Iterator it = newSubPoints.at( ( unsigned ) ns ); + PMVector p[4]; + QValueList::Iterator hit = it, eit = newSubPoints.end( ); + --eit; + + // calculate the spline segment + PMSplineSegment segment; + switch( m_splineType ) + { + case LinearSpline: + for( i = 0; i < 2; ++i ) + { + p[i] = *hit; + ++hit; + if( hit == newSubPoints.end( ) ) + hit = newSubPoints.begin( ); + } + segment.calculateLinear( p[0], p[1] ); + break; + case QuadraticSpline: + --hit; + for( i = 0; i < 3; ++i ) + { + p[i] = *hit; + ++hit; + if( hit == newSubPoints.end( ) ) + { + hit = newSubPoints.begin( ); + ++hit; + } + } + segment.calculateQuadratic( p[0], p[1], p[2] ); + break; + case CubicSpline: + --hit; + for( i = 0; i < 4; ++i ) + { + if( hit == eit ) + { + hit = newSubPoints.begin( ); + ++hit; + p[i] = *hit; + hit = eit; + ++i; + if( i < 4 ) + p[i] = *hit; + } + else + p[i] = *hit; + ++hit; + } + segment.calculateCubic( p[0], p[1], p[2], p[3] ); + break; + case BezierSpline: + for( i = 0; i < 4; ++i ) + { + p[i] = *hit; + ++hit; + if( hit == newSubPoints.end( ) ) + hit = newSubPoints.begin( ); + } + segment.calculateBezier( p[0], p[1], p[2], p[3] ); + break; + } + + mid = segment.point( 0.5 ); + if( m_splineType != BezierSpline ) + { + ++it; + newSubPoints.insert( it, mid ); + } + else + { + PMVector end = *it; + ++it; + *it = end + ( *it - end ) / 2.0; + ++it; + + PMVector grad = segment.gradient( 0.5 ) / 4.0; + + newSubPoints.insert( it, mid - grad ); + newSubPoints.insert( it, mid ); + newSubPoints.insert( it, mid + grad ); + + ++it; + if( it == newSubPoints.end( ) ) + end = *newSubPoints.begin( ); + else + end = *it; + --it; + *it = end + ( *it - end ) / 2.0; + } + ( *spit ) = newSubPoints; + setPoints( newPoints ); +} + +void PMPrism::joinSegments( const PMControlPointList& /*cp*/, + const QPtrList& cpViewPosition, + const PMVector& clickPosition ) +{ + // find nearest point + double abs = 0.0, minabs = 1e10; + int ns = -1; + int nsp = 0; + int spnr = 0, pnr = 0; + int i; + PMVector dist( 2 ); + + QPtrListIterator it1( cpViewPosition ); + for( i = 0; i < 2; ++i ) ++it1; + + int minp = 0; + switch( m_splineType ) + { + case LinearSpline: + minp = 4; + break; + case QuadraticSpline: + minp = 5; + break; + case CubicSpline: + minp = 6; + break; + case BezierSpline: + minp = 6; + break; + } + + QValueList< QValueList >::Iterator spit = m_points.begin( ); + for( spnr = 0; spit != m_points.end( ); ++spit, ++spnr ) + { + int nump = ( *spit ).count( ); + + for( pnr = 0; pnr < nump; ++pnr ) + { + bool skip = false; + switch( m_splineType ) + { + case LinearSpline: + case BezierSpline: + break; + case QuadraticSpline: + if( pnr == 0 ) + skip = true; + break; + case CubicSpline: + if( ( pnr == 0 ) || ( pnr == ( nump - 1 ) ) ) + skip = true; + break; + } + if( nump < minp ) + skip = true; + + if( !skip ) + { + dist[0] = (**it1)[0]; + dist[1] = (**it1)[1]; + dist -= clickPosition; + abs = dist.abs( ); + + if( ( minabs > abs ) || ( ns < 0 ) ) + { + minabs = abs; + ns = pnr; + nsp = spnr; + } + } + ++it1; + } + } + + if( ns < 0 ) + { + kdError( PMArea ) << "Not enough points in PMPrism::joinSegments\n"; + return; + } + + // remove the segment + QValueList< QValueList > newPoints = m_points; + spit = newPoints.at( nsp ); + QValueList newSubPoints = *spit; + QValueList::Iterator it; + + if( m_splineType != BezierSpline ) + { + it = newSubPoints.at( ( unsigned ) ns ); + newSubPoints.remove( it ); + } + else + { + int last = ( newSubPoints.count( ) - 3 ) / 3; + ns -= 2; + if( ns < 0 ) + ns = last; + else + ns /= 3; + + it = newSubPoints.at( ns * 3 + 2 ); + if( ns != last ) + { + it = newSubPoints.remove( it ); + it = newSubPoints.remove( it ); + it = newSubPoints.remove( it ); + } + else + { + newSubPoints.remove( it ); + it = newSubPoints.begin( ); + it = newSubPoints.remove( it ); + it = newSubPoints.remove( it ); + PMVector h = *it; + it = newSubPoints.remove( it ); + newSubPoints.insert( newSubPoints.end( ), h ); + } + } + ( *spit ) = newSubPoints; + setPoints( newPoints ); +} + +void PMPrism::setSSteps( int s ) +{ + if( s >= 1 ) + s_sSteps = s; + else + kdDebug( PMArea ) << "PMPrism::setSSteps: S must be greater than 0\n"; + ++s_parameterKey; +} + +QValueList PMPrism::expandedPoints( const QValueList& p ) const +{ + // add the missing points + int refa = 0, refb = p.count( ); + QValueList result = p; + + switch( m_splineType ) + { + case LinearSpline: + break; + case QuadraticSpline: + ++refa; + break; + case CubicSpline: + ++refa; + --refb; + break; + case BezierSpline: + refb = refb / 3 * 4; + break; + } + QValueList::Iterator it1, it2, it3; + if( m_splineType != BezierSpline ) + { + it1 = result.at( refa ); + it2 = result.at( refb ); + result.insert( it2, *it1 ); + } + else + { + int i; + it1 = result.begin( ); + for( i = 1; it1 != result.end( ); ++it1, ++i ) + { + if( ( i % 3 ) == 0 ) + { + it2 = it1; + ++it2; + it3 = it2; + if( it3 == result.end( ) ) + it3 = result.begin( ); + it1 = result.insert( it2, *it3 ); + } + } + } + return result; +} diff --git a/kpovmodeler/pmprism.h b/kpovmodeler/pmprism.h new file mode 100644 index 00000000..64511ee5 --- /dev/null +++ b/kpovmodeler/pmprism.h @@ -0,0 +1,224 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMPRISM_H +#define PMPRISM_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" +#include "pmvector.h" +#include +#include +#include + +class PMViewStructure; + +/** + * Class for povray prism objects. + */ + +class PMPrism : public PMSolidObject +{ + typedef PMSolidObject Base; +public: + /** + * The spline type + */ + enum SplineType { LinearSpline, QuadraticSpline, CubicSpline, BezierSpline }; + /** + * The sweep type + */ + enum SweepType { LinearSweep, ConicSweep }; + /** + * Creates an empty PMPrism + */ + PMPrism( PMPart* part ); + /** + * Copy constructor + */ + PMPrism( const PMPrism& p ); + /** + * deletes the PMPrism + */ + virtual ~PMPrism( ); + + /** */ + virtual PMObject* copy( ) const { return new PMPrism( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMPrismEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmprism" ); } + + /** */ + virtual void createMemento( ); + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual void controlPoints( PMControlPointList& list ); + /** */ + virtual void controlPointsChanged( PMControlPointList& list ); + /** */ + virtual bool multipleSelectControlPoints( ) const { return true; } + /** */ + virtual bool hasDisplayDetail( ) const { return true; } + /** */ + virtual void addObjectActions( const PMControlPointList&, + QPtrList& ); + /** */ + virtual void objectActionCalled( const PMObjectAction*, + const PMControlPointList&, + const QPtrList&, + const PMVector& ); + + /** + * Returns the spline points + */ + QValueList< QValueList > points( ) const { return m_points; } + /** + * Sets the spline points + */ + void setPoints( const QValueList< QValueList >& points ); + /** + * Returns the spline type + */ + SplineType splineType( ) const { return m_splineType; } + /** + * Sets the spline type + */ + void setSplineType( SplineType t ); + /** + * Returns the sweep type + */ + SweepType sweepType( ) const { return m_sweepType; } + /** + * Sets the sweep type + */ + void setSweepType( SweepType t ); + /** + * Returns the sturm flag + */ + bool sturm( ) const { return m_sturm; } + /** + * Sets the sturm flag + */ + void setSturm( bool s ); + /** + * Returns the open flag + */ + bool open( ) const { return m_open; } + /** + * Sets the open flag + */ + void setOpen( bool o ); + /** + * Returns the height 1 + */ + double height1( ) const { return m_height1; } + /** + * Returns the height 2 + */ + double height2( ) const { return m_height2; } + /** + * Sets the height 1 + */ + void setHeight1( double h ); + /** + * Sets the height 2 + */ + void setHeight2( double h ); + + /** + * Sets the number of steps around the y axis + */ + static void setSSteps( int s ); + /** + * Returns the number of steps around the y axis + */ + static int sSteps( ) { return s_sSteps; } + /** + * Returns the points for POV-Ray serialization (contains additional points) + */ + QValueList expandedPoints( const QValueList& p ) const; + +protected: + /** */ + virtual void createViewStructure( ); + /** */ + virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey( ); } + +private: + /** + * Object action. Adds a spline point + */ + void splitSegment( const PMControlPointList& cp, + const QPtrList& cpViewPosition, + const PMVector& clickPosition ); + /** + * Object action. Removes a spline point + */ + void joinSegments( const PMControlPointList& cp, + const QPtrList& cpViewPosition, + const PMVector& clickPosition ); + + void stringToValues( const QString& str ); + QString valuesToString( ) const; + + /** + * IDs for @ref PMMementoData + */ + enum PMPrismMementoID { PMSplineTypeID, PMSweepTypeID, PMSturmID, PMOpenID, + PMHeight1ID, PMHeight2ID }; + /** + * IDs for the object actions + */ + enum PMPrismActionID { PMSplitSegmentID, PMJoinSegmentsID }; + SplineType m_splineType; + SweepType m_sweepType; + QValueList< QValueList > m_points; + double m_height1, m_height2; + bool m_sturm; + bool m_open; + + static int s_sSteps; + static int s_parameterKey; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmprismedit.cpp b/kpovmodeler/pmprismedit.cpp new file mode 100644 index 00000000..13ac49b5 --- /dev/null +++ b/kpovmodeler/pmprismedit.cpp @@ -0,0 +1,696 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmprismedit.h" +#include "pmprism.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" +#include "pmvectorlistedit.h" +#include "pmpart.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +PMPrismEdit::PMPrismEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; + m_lastSplineType = 0; +} + +PMPrismEdit::~PMPrismEdit( ) +{ +} + +void PMPrismEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Spline type:" ), this ) ); + m_pSplineType = new QComboBox( false, this ); + m_pSplineType->insertItem( i18n( "Linear Spline" ) ); + m_pSplineType->insertItem( i18n( "Quadratic Spline" ) ); + m_pSplineType->insertItem( i18n( "Cubic Spline" ) ); + m_pSplineType->insertItem( i18n( "Bezier Spline" ) ); + hl->addWidget( m_pSplineType ); + + hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Sweep type:" ), this ) ); + m_pSweepType = new QComboBox( false, this ); + m_pSweepType->insertItem( i18n( "Linear Sweep" ) ); + m_pSweepType->insertItem( i18n( "Conic Sweep" ) ); + hl->addWidget( m_pSweepType ); + + connect( m_pSplineType, SIGNAL( activated( int ) ), + SLOT( slotTypeChanged( int ) ) ); + connect( m_pSweepType, SIGNAL( activated( int ) ), + SLOT( slotSweepChanged( int ) ) ); + + hl = new QHBoxLayout( topLayout( ) ); + QGridLayout* gl = new QGridLayout( hl, 2, 2 ); + gl->addWidget( new QLabel( i18n( "Height 1:" ), this ), 0, 0 ); + m_pHeight1 = new PMFloatEdit( this ); + gl->addWidget( m_pHeight1, 0, 1 ); + connect( m_pHeight1, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + + gl->addWidget( new QLabel( i18n( "Height 2:" ), this ), 1, 0 ); + m_pHeight2 = new PMFloatEdit( this ); + gl->addWidget( m_pHeight2, 1, 1 ); + connect( m_pHeight2, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + hl->addStretch( 1 ); +} + +void PMPrismEdit::createBottomWidgets( ) +{ + m_pEditWidget = new QWidget( this ); + topLayout( )->addWidget( m_pEditWidget ); + m_pOpen = new QCheckBox( i18n( "type of the object", "Open" ), this ); + topLayout( )->addWidget( m_pOpen ); + m_pSturm = new QCheckBox( i18n( "Sturm" ), this ); + topLayout( )->addWidget( m_pSturm ); + connect( m_pSturm, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pOpen, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + + Base::createBottomWidgets( ); +} + +void PMPrismEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Prism" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMPrism* ) o; + + switch( m_pDisplayedObject->splineType( ) ) + { + case PMPrism::LinearSpline: + m_pSplineType->setCurrentItem( 0 ); + break; + case PMPrism::QuadraticSpline: + m_pSplineType->setCurrentItem( 1 ); + break; + case PMPrism::CubicSpline: + m_pSplineType->setCurrentItem( 2 ); + break; + case PMPrism::BezierSpline: + m_pSplineType->setCurrentItem( 3 ); + break; + } + m_pSplineType->setEnabled( !readOnly ); + switch( m_pDisplayedObject->sweepType( ) ) + { + case PMPrism::LinearSweep: + m_pSweepType->setCurrentItem( 0 ); + break; + case PMPrism::ConicSweep: + m_pSweepType->setCurrentItem( 1 ); + break; + } + m_pHeight1->setValue( m_pDisplayedObject->height1( ) ); + m_pHeight1->setReadOnly( readOnly ); + m_pHeight2->setValue( m_pDisplayedObject->height2( ) ); + m_pHeight2->setReadOnly( readOnly ); + m_pSweepType->setEnabled( !readOnly ); + m_pSturm->setChecked( m_pDisplayedObject->sturm( ) ); + m_pSturm->setEnabled( !readOnly ); + m_pOpen->setChecked( m_pDisplayedObject->open( ) ); + m_pOpen->setEnabled( !readOnly ); + displayPoints( m_pDisplayedObject->points( ) ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMPrismEdit: Can't display object\n"; +} + +void PMPrismEdit::displayPoints( const QValueList< QValueList >& sp ) +{ + bool readOnly = m_pDisplayedObject->isReadOnly( ); + + // (re)create the edit widget if necessary + createEdits( sp ); + + QValueList< QValueList >::ConstIterator spit = sp.begin( ); + QPtrListIterator< PMVectorListEdit > seit( m_points ); + QPtrListIterator< QPushButton > sbit1( m_removeButtons ); + + // display the points + for( ; ( spit != sp.end( ) ) && *seit; ++spit, ++seit, ++sbit1 ) + { + ( *seit )->setVectors( *spit ); + ( *seit )->setReadOnly( readOnly ); + ( *sbit1 )->setEnabled( !readOnly && ( *spit ).size( ) > 3 ); + } + + QPtrListIterator< QPushButton > sbit2( m_addAboveButtons ); + QPtrListIterator< QPushButton > sbit3( m_addBelowButtons ); + for( ; *sbit2; ++sbit2 ) + ( *sbit2 )->setEnabled( !readOnly ); + for( ; *sbit3; ++sbit3 ) + ( *sbit3 )->setEnabled( !readOnly ); + + QPtrListIterator bit1( m_subPrismAddButtons ); + for( ; *bit1; ++bit1 ) + ( *bit1 )->setEnabled( !readOnly ); + QPtrListIterator bit2( m_subPrismRemoveButtons ); + for( ; *bit2; ++bit2 ) + ( *bit2 )->setEnabled( !readOnly && sp.size( ) > 1 ); + updateControlPointSelection( ); +} + +void PMPrismEdit::createEdits( const QValueList< QValueList >& sp ) +{ + int st = m_pSplineType->currentItem( ); + + if( sp.size( ) != m_points.count( ) ) + { + deleteEdits( ); + + QPixmap addPixmap = SmallIcon( "pmaddpoint" ); + QPixmap removePixmap = SmallIcon( "pmremovepoint" ); + QPixmap addPrismPixmap = SmallIcon( "pmaddsubprism" ); + QVBoxLayout* tvl = new QVBoxLayout( m_pEditWidget, + 0, KDialog::spacingHint( ) ); + QHBoxLayout* hl = 0; + QVBoxLayout* vl; + QLabel* label = 0; + QPushButton* button = 0; + PMVectorListEdit* vle; + int spnr = 0; + + for( spnr = 0; spnr < ( signed ) sp.size( ); spnr++ ) + { + // create all edits for one sub prism + hl = new QHBoxLayout( tvl ); + label = new QLabel( i18n( "Sub prism %1:" ).arg( spnr + 1 ), + m_pEditWidget ); + hl->addWidget( label ); + hl->addStretch( 1 ); + m_labels.append( label ); + label->show( ); + + button = new QPushButton( m_pEditWidget ); + button->setPixmap( addPrismPixmap ); + m_subPrismAddButtons.append( button ); + connect( button, SIGNAL( clicked( ) ), SLOT( slotAddSubPrism( ) ) ); + hl->addWidget( button ); + button->show( ); + QToolTip::add( button, i18n( "Add sub prism" ) ); + + button = new QPushButton( m_pEditWidget ); + button->setPixmap( removePixmap ); + m_subPrismRemoveButtons.append( button ); + connect( button, SIGNAL( clicked( ) ), SLOT( slotRemoveSubPrism( ) ) ); + hl->addWidget( button ); + button->show( ); + if( sp.size( ) < 2 ) + button->setEnabled( false ); + QToolTip::add( button, i18n( "Remove sub prism" ) ); + + hl = new QHBoxLayout( tvl ); + + vle = new PMVectorListEdit( "x", "z", m_pEditWidget ); + m_points.append( vle ); + connect( vle, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( vle, SIGNAL( selectionChanged( ) ), + SLOT( slotSelectionChanged( ) ) ); + hl->addWidget( vle, 2 ); + vle->show( ); + + vl = new QVBoxLayout( hl ); + + button = new QPushButton( m_pEditWidget ); + button->setPixmap( SmallIcon( "pmaddpointabove" ) ); + connect( button, SIGNAL( clicked( ) ), SLOT( slotAddPointAbove( ) ) ); + m_addAboveButtons.append( button ); + button->show( ); + vl->addWidget( button ); + button = new QPushButton( m_pEditWidget ); + button->setPixmap( SmallIcon( "pmaddpoint" ) ); + connect( button, SIGNAL( clicked( ) ), SLOT( slotAddPointBelow( ) ) ); + m_addBelowButtons.append( button ); + button->show( ); + vl->addWidget( button ); + button = new QPushButton( m_pEditWidget ); + button->setPixmap( SmallIcon( "pmremovepoint" ) ); + connect( button, SIGNAL( clicked( ) ), SLOT( slotRemovePoint( ) ) ); + m_removeButtons.append( button ); + button->show( ); + vl->addWidget( button ); + + vl->addStretch( 1 ); + + tvl->addSpacing( KDialog::spacingHint( ) ); + } + + hl = new QHBoxLayout( tvl ); + label = new QLabel( i18n( "New sub prism" ), m_pEditWidget ); + hl->addWidget( label ); + hl->addStretch( 1 ); + m_labels.append( label ); + label->show( ); + + button = new QPushButton( m_pEditWidget ); + button->setPixmap( addPrismPixmap ); + m_subPrismAddButtons.append( button ); + connect( button, SIGNAL( clicked( ) ), SLOT( slotAddSubPrism( ) ) ); + hl->addWidget( button ); + button->show( ); + QToolTip::add( button, i18n( "Append sub prism" ) ); + } + + QPtrListIterator< PMVectorListEdit > vlit( m_points ); + QValueList< QValueList< PMVector > >::ConstIterator spit; + PMVectorListEdit* vle = 0; + bool newSize = false; + + for( spit = sp.begin( ); spit != sp.end( ); ++spit, ++vlit ) + { + int lines = ( *spit ).count( ); + + vle = *vlit; + if( ( vle->size( ) != lines ) /*|| ( st != m_lastSplineType )*/ ) + { + newSize = true; + vle->setSize( lines ); + } + } + if( newSize ) + { + m_pEditWidget->updateGeometry( ); + emit sizeChanged( ); + } + + m_lastSplineType = st; +} + +void PMPrismEdit::deleteEdits( ) +{ + m_labels.setAutoDelete( true ); + m_labels.clear( ); + m_labels.setAutoDelete( false ); + m_subPrismAddButtons.setAutoDelete( true ); + m_subPrismAddButtons.clear( ); + m_subPrismAddButtons.setAutoDelete( false ); + m_subPrismRemoveButtons.setAutoDelete( true ); + m_subPrismRemoveButtons.clear( ); + m_subPrismRemoveButtons.setAutoDelete( false ); + m_addAboveButtons.setAutoDelete( true ); + m_addAboveButtons.clear( ); + m_addAboveButtons.setAutoDelete( false ); + m_addBelowButtons.setAutoDelete( true ); + m_addBelowButtons.clear( ); + m_addBelowButtons.setAutoDelete( false ); + m_removeButtons.setAutoDelete( true ); + m_removeButtons.clear( ); + m_removeButtons.setAutoDelete( false ); + m_points.setAutoDelete( true ); + m_points.clear( ); + m_points.setAutoDelete( false ); + + if( m_pEditWidget->layout( ) ) + delete m_pEditWidget->layout( ); +} + +QValueList< QValueList > PMPrismEdit::splinePoints( ) +{ + QPtrListIterator< PMVectorListEdit > it( m_points ); + QValueList< QValueList > values; + + for( ; it.current( ); ++it ) + values.append( ( *it )->vectors( ) ); + + return values; +} + +void PMPrismEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + m_pDisplayedObject->setPoints( splinePoints( ) ); + + switch( m_pSplineType->currentItem( ) ) + { + case 0: + m_pDisplayedObject->setSplineType( PMPrism::LinearSpline ); + break; + case 1: + m_pDisplayedObject->setSplineType( PMPrism::QuadraticSpline ); + break; + case 2: + m_pDisplayedObject->setSplineType( PMPrism::CubicSpline ); + break; + case 3: + m_pDisplayedObject->setSplineType( PMPrism::BezierSpline ); + break; + } + switch( m_pSweepType->currentItem( ) ) + { + case 0: + m_pDisplayedObject->setSweepType( PMPrism::LinearSweep ); + break; + case 1: + m_pDisplayedObject->setSweepType( PMPrism::ConicSweep ); + break; + } + m_pDisplayedObject->setSturm( m_pSturm->isChecked( ) ); + m_pDisplayedObject->setOpen( m_pOpen->isChecked( ) ); + m_pDisplayedObject->setHeight1( m_pHeight1->value( ) ); + m_pDisplayedObject->setHeight2( m_pHeight2->value( ) ); + Base::saveContents( ); + } +} + +bool PMPrismEdit::isDataValid( ) +{ + QPtrListIterator< PMVectorListEdit > it( m_points ); + for( ; it.current( ); ++it ) + if( !it.current( )->isDataValid( ) ) + return false; + + for( it.toFirst( ); it.current( ); ++it ) + { + int np = it.current( )->size( ); + switch( m_pSplineType->currentItem( ) ) + { + case 0: + if( np < 3 ) + { + KMessageBox::error( this, i18n( "Linear splines need at least 3 points." ), + i18n( "Error" ) ); + return false; + } + break; + case 1: + if( np < 4 ) + { + KMessageBox::error( this, i18n( "Quadratic splines need at least 4 points." ), + i18n( "Error" ) ); + return false; + } + break; + case 2: + if( np < 5 ) + { + KMessageBox::error( this, i18n( "Cubic splines need at least 5 points." ), + i18n( "Error" ) ); + return false; + } + break; + case 3: + if( ( np < 3 ) || ( ( np % 3 ) != 0 ) ) + { + KMessageBox::error( this, i18n( "Bezier splines need 3 points for each segment." ), + i18n( "Error" ) ); + return false; + } + break; + } + } + + return Base::isDataValid( ); +} + +void PMPrismEdit::slotTypeChanged( int ) +{ + displayPoints( splinePoints( ) ); + emit dataChanged( ); + emit sizeChanged( ); +} + +void PMPrismEdit::slotSweepChanged( int ) +{ + emit dataChanged( ); +} + +void PMPrismEdit::slotAddPointAbove( ) +{ + QPushButton* bt = ( QPushButton* ) sender( ); + if( bt ) + { + int subIndex = m_addAboveButtons.findRef( bt ); + if( subIndex >= 0 ) + { + PMVectorListEdit* ed = m_points.at( subIndex ); + int index = ed->currentRow( ); + if( index >= 0 && index < ed->size( ) ) + { + QValueList points = ed->vectors( ); + QValueListIterator it = points.at( index ); + + PMVector newPoint = *it; + if( index != 0 ) + { + --it; + newPoint = ( newPoint + *it ) / 2; + ++it; + } + points.insert( it, newPoint ); + + ed->setSize( points.size( ) ); + ed->setVectors( points ); + if( points.size( ) > 3 ) + m_removeButtons.at( subIndex )->setEnabled( true ); + + emit dataChanged( ); + emit sizeChanged( ); + } + } + } +} + +void PMPrismEdit::slotAddPointBelow( ) +{ + QPushButton* bt = ( QPushButton* ) sender( ); + if( bt ) + { + int subIndex = m_addBelowButtons.findRef( bt ); + if( subIndex >= 0 ) + { + PMVectorListEdit* ed = m_points.at( subIndex ); + int index = ed->currentRow( ); + if( index >= 0 && index < ed->size( ) ) + { + QValueList points = ed->vectors( ); + QValueListIterator it = points.at( index ); + + PMVector newPoint = *it; + ++it; + + if( it != points.end( ) ) + newPoint = ( newPoint + *it ) / 2; + + points.insert( it, newPoint ); + + ed->setSize( points.size( ) ); + ed->setVectors( points ); + ed->setCurrentCell( index + 1, ed->currentColumn( ) ); + if( points.size( ) > 3 ) + m_removeButtons.at( subIndex )->setEnabled( true ); + + emit dataChanged( ); + emit sizeChanged( ); + } + } + } +} + +void PMPrismEdit::slotRemovePoint( ) +{ + QPushButton* bt = ( QPushButton* ) sender( ); + if( bt ) + { + int subIndex = m_removeButtons.findRef( bt ); + if( subIndex >= 0 ) + { + PMVectorListEdit* ed = m_points.at( subIndex ); + int index = ed->currentRow( ); + if( index >= 0 && index < ed->size( ) ) + { + QValueList points = ed->vectors( ); + QValueListIterator it = points.at( index ); + + points.remove( it ); + + ed->setSize( points.size( ) ); + ed->setVectors( points ); + if( points.size( ) <= 3 ) + m_removeButtons.at( subIndex )->setEnabled( false ); + + emit dataChanged( ); + emit sizeChanged( ); + } + } + } +} + +void PMPrismEdit::slotAddSubPrism( ) +{ + if( m_pSplineType->currentItem( ) == 3 ) + { + KMessageBox::information( this, i18n( "Sub prisms do not work with " + "bezier splines in POV-Ray 3.1." ), + i18n( "Warning" ), "subPrismWithBezierSplines" ); + } + + QPushButton* button = ( QPushButton* ) sender( ); + if( button ) + { + int index = m_subPrismAddButtons.findRef( button ); + if( index >= 0 ) + { + QValueList< QValueList > points = splinePoints( ); + QValueList< QValueList >::Iterator it = points.at( index ); + QValueList newSubPrism; + + if( it != points.begin( ) ) + { + --it; + newSubPrism = *it; + ++it; + + // find middle point + PMVector mid( 2 ); + int num = 0; + QValueList::Iterator pit = newSubPrism.begin( ); + for( ; pit != newSubPrism.end( ); ++pit, ++num ) + mid += *pit; + if( num > 0 ) + mid /= num; + for( pit = newSubPrism.begin( ); pit != newSubPrism.end( ); ++pit ) + *pit = ( *pit - mid ) * 0.8 + mid; + } + else + newSubPrism = *it; + + points.insert( it, newSubPrism ); + displayPoints( points ); + emit dataChanged( ); + emit sizeChanged( ); + } + } +} + +void PMPrismEdit::slotRemoveSubPrism( ) +{ + QPushButton* button = ( QPushButton* ) sender( ); + if( button ) + { + int index = m_subPrismRemoveButtons.findRef( button ); + if( index >= 0 ) + { + QValueList< QValueList > points = splinePoints( ); + QValueList< QValueList >::Iterator it = points.at( index ); + + if( points.count( ) > 1 ) + { + points.remove( it ); + displayPoints( points ); + emit dataChanged( ); + emit sizeChanged( ); + } + } + } +} + +void PMPrismEdit::slotSelectionChanged( ) +{ + PMVectorListEdit* edit = ( PMVectorListEdit* ) sender( ); + if( edit ) + { + QValueList< QValueList< PMVector > > points = m_pDisplayedObject->points( ); + + if( m_points.count( ) == points.size( ) ) + { + int i; + bool changed = false; + QValueList< QValueList< PMVector > >::Iterator spit; + PMControlPointList cp = part( )->activeControlPoints( ); + PMControlPointListIterator it( cp ); ++it; ++it; + QPtrListIterator edit( m_points ); + + for( spit = points.begin( ); spit != points.end( ) && it.current( ); + ++spit, ++edit ) + { + int np = ( *spit ).size( ); + + if( ( *edit )->size( ) == np ) + { + for( i = 0; i < np && it.current( ); i++, ++it ) + ( *it )->setSelected( ( *edit )->isSelected( i ) ); + changed = true; + } + else + for( i = 0; i < np; i++ ) + ++it; + } + if( changed ) + emit controlPointSelectionChanged( ); + } + } +} + +void PMPrismEdit::updateControlPointSelection( ) +{ + QValueList< QValueList< PMVector > > points = m_pDisplayedObject->points( ); + + if( m_points.count( ) == points.size( ) ) + { + QValueList< QValueList< PMVector > >::Iterator spit; + PMControlPointList cp = part( )->activeControlPoints( ); + PMControlPointListIterator it( cp ); ++it; ++it; + QPtrListIterator edit( m_points ); + + for( spit = points.begin( ); spit != points.end( ) && it.current( ); + ++spit, ++edit ) + { + PMVectorListEdit* vl = *edit; + int np = ( *spit ).size( ); + int i; + + if( vl->size( ) == np ) + { + vl->blockSelectionUpdates( true ); + bool sb = vl->signalsBlocked( ); + vl->blockSignals( true ); + + vl->clearSelection( ); + for( i = 0; i < np && it.current( ); i++, ++it ) + if( ( *it )->selected( ) ) + vl->select( i ); + + vl->blockSignals( sb ); + vl->blockSelectionUpdates( false ); + } + else + for( i = 0; i < np; i++ ) + ++it; + } + } +} + +#include "pmprismedit.moc" diff --git a/kpovmodeler/pmprismedit.h b/kpovmodeler/pmprismedit.h new file mode 100644 index 00000000..75a65dbd --- /dev/null +++ b/kpovmodeler/pmprismedit.h @@ -0,0 +1,122 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMPRISMEDIT_H +#define PMPRISMEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" +#include "pmvectoredit.h" +#include +#include + + +class PMPrism; +class PMFloatEdit; +class PMVectorListEdit; +class QVBoxLayout; +class QComboBox; +class QCheckBox; +class QPushButton; +class QLabel; + +/** + * Dialog edit class for @ref PMPrism + */ +class PMPrismEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMPrismEdit with parent and name + */ + PMPrismEdit( QWidget* parent, const char* name = 0 ); + /** + * Destructor + */ + virtual ~PMPrismEdit( ); + /** */ + virtual void displayObject( PMObject* o ); + /** */ + void updateControlPointSelection( ); + + /** */ + virtual bool isDataValid( ); + +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void createBottomWidgets( ); + /** */ + virtual void saveContents( ); + +private: + /** + * Displays the spline points + */ + void displayPoints( const QValueList< QValueList >& list ); + /** + * Returns the spline points from the vector edits + */ + QValueList< QValueList > splinePoints( ); + /** + * Deletes the spline point edits + */ + void deleteEdits( ); + /** + * Creates the edits for the points + */ + void createEdits( const QValueList< QValueList >& points ); + +protected slots: + void slotTypeChanged( int ); + void slotSweepChanged( int ); + void slotAddSubPrism( ); + void slotRemoveSubPrism( ); + void slotAddPointAbove( ); + void slotAddPointBelow( ); + void slotRemovePoint( ); + void slotSelectionChanged( ); + +private: + PMPrism* m_pDisplayedObject; + QPtrList< QLabel > m_labels; + QPtrList< QPushButton > m_subPrismAddButtons; + QPtrList< QPushButton > m_subPrismRemoveButtons; + QPtrList< QPushButton > m_addAboveButtons; + QPtrList< QPushButton > m_addBelowButtons; + QPtrList< QPushButton > m_removeButtons; + QPtrList< PMVectorListEdit> m_points; + QWidget* m_pEditWidget; + QComboBox* m_pSplineType; + QComboBox* m_pSweepType; + QCheckBox* m_pSturm; + QCheckBox* m_pOpen; + PMFloatEdit* m_pHeight1; + PMFloatEdit* m_pHeight2; + int m_lastSplineType; +}; + + +#endif diff --git a/kpovmodeler/pmprismmemento.cpp b/kpovmodeler/pmprismmemento.cpp new file mode 100644 index 00000000..0f50449d --- /dev/null +++ b/kpovmodeler/pmprismmemento.cpp @@ -0,0 +1,55 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmprismmemento.h" + +PMPrismMemento::PMPrismMemento( PMObject* originator ) + : PMMemento( originator ) +{ + m_bPrismPointsSaved = false; +} + +PMPrismMemento::~PMPrismMemento( ) +{ +} + +void PMPrismMemento::setPrismPoints( const QValueList< QValueList >& v ) +{ + if( !m_bPrismPointsSaved ) + { + // Direct assignment does not work with Qt 2.3.x + // The list will be changed later in a graphical + // change because QValueList::detach( ) is called + // too late! + // Copy the list by hand. + + QValueList< QValueList< PMVector > >::ConstIterator sit = v.begin( ); + for( ; sit != v.end( ); ++sit ) + { + QValueList list; + QValueList::ConstIterator it = ( *sit ).begin( ); + for( ; it != ( *sit ).end( ); ++it ) + list.append( *it ); + m_prismPoints.append( list ); + } + + m_bPrismPointsSaved = true; + addChange( PMCData ); + } +} + + diff --git a/kpovmodeler/pmprismmemento.h b/kpovmodeler/pmprismmemento.h new file mode 100644 index 00000000..a45f7fef --- /dev/null +++ b/kpovmodeler/pmprismmemento.h @@ -0,0 +1,71 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMPRISMMEMENTO_H +#define PMPRISMMEMENTO_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmmemento.h" +#include "pmvector.h" +#include + + +/** + * Memento for @ref PMPrism + */ +class PMPrismMemento : public PMMemento +{ +public: + /** + * Creates a memento for the object originator + */ + PMPrismMemento( PMObject* originator ); + /** + * Deletes the memento + */ + virtual ~PMPrismMemento( ); + + /** + * Saves the prism points + */ + void setPrismPoints( const QValueList< QValueList >& v ); + /** + * Returns the prism points + */ + QValueList< QValueList > prismPoints( ) const + { + return m_prismPoints; + } + /** + * Returns true if the prism points were saved + */ + bool prismPointsSaved( ) const { return m_bPrismPointsSaved; } + +private: + /** + * The stored points + */ + QValueList< QValueList > m_prismPoints; + bool m_bPrismPointsSaved; +}; + +#endif diff --git a/kpovmodeler/pmprojectedthrough.cpp b/kpovmodeler/pmprojectedthrough.cpp new file mode 100644 index 00000000..46ecc51c --- /dev/null +++ b/kpovmodeler/pmprojectedthrough.cpp @@ -0,0 +1,92 @@ +/* +************************************************************************** + description + ------------------- + and : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#include "pmprojectedthrough.h" + +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmnamedobjectedit.h" + +#include + +PMMetaObject* PMProjectedThrough::s_pMetaObject = 0; +PMObject* createNewProjectedThrough( PMPart* part ) +{ + return new PMProjectedThrough( part ); +} + +PMProjectedThrough::PMProjectedThrough( PMPart* part ) + : Base( part ) +{ +} + +PMProjectedThrough::PMProjectedThrough( const PMProjectedThrough& l ) + : Base( l ) +{ +} + +PMProjectedThrough::~PMProjectedThrough( ) +{ +} + + +QString PMProjectedThrough::description( ) const +{ + return i18n( "projected through" ); +} + +PMMetaObject* PMProjectedThrough::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "ProjectedThrough", Base::metaObject( ), + createNewProjectedThrough ); + // no properties + } + return s_pMetaObject; +} + +void PMProjectedThrough::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMProjectedThrough::serialize( QDomElement& e, QDomDocument& doc ) const +{ + Base::serialize( e, doc ); +} + +void PMProjectedThrough::readAttributes( const PMXMLHelper& h ) +{ + Base::readAttributes( h ); +} + +PMDialogEditBase* PMProjectedThrough::editWidget( QWidget* parent ) const +{ + return new PMNamedObjectEdit( parent ); +} + +void PMProjectedThrough::restoreMemento( PMMemento* s ) +{ + Base::restoreMemento( s ); +} + diff --git a/kpovmodeler/pmprojectedthrough.h b/kpovmodeler/pmprojectedthrough.h new file mode 100644 index 00000000..66b2a7bd --- /dev/null +++ b/kpovmodeler/pmprojectedthrough.h @@ -0,0 +1,82 @@ +//-*-C++-*- +/* +************************************************************************** + description + ------------------- + and : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMPROJECTEDTHROUGH_H +#define PMPROJECTEDTHROUGH_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmnamedobject.h" + +/** + * Class for povray projected_through statements. + */ +class PMProjectedThrough : public PMNamedObject +{ + typedef PMNamedObject Base; + +public: + /** + * Constructor + */ + PMProjectedThrough( PMPart* part ); + /** + * Copy constructor + */ + PMProjectedThrough( const PMProjectedThrough& l ); + /** + * Deletes the PMProjectedThrough + */ + virtual ~PMProjectedThrough( ); + + /** */ + virtual PMObject* copy( ) const { return new PMProjectedThrough( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMProjectedThroughEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmprojectedthrough" ); } + + /** */ + virtual void restoreMemento( PMMemento* s ); + +private: + static PMMetaObject* s_pMetaObject; +}; + + +#endif diff --git a/kpovmodeler/pmprototypemanager.cpp b/kpovmodeler/pmprototypemanager.cpp new file mode 100644 index 00000000..f458e248 --- /dev/null +++ b/kpovmodeler/pmprototypemanager.cpp @@ -0,0 +1,243 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmprototypemanager.h" +#include "pmallobjects.h" +#include + +PMPrototypeManager::PMPrototypeManager( PMPart* part ) + : m_metaDict( 43 ) +{ + m_pPart = part; + addPrototype( new PMScene( part ) ); + addPrototype( new PMGlobalSettings( part ) ); + addPrototype( new PMBox( part ) ); + addPrototype( new PMSphere( part ) ); + addPrototype( new PMCylinder( part ) ); + addPrototype( new PMCone( part ) ); + addPrototype( new PMTorus( part ) ); + addPrototype( new PMLathe( part ) ); + addPrototype( new PMPrism( part ) ); + + addPrototype( new PMSurfaceOfRevolution( part ) ); + addPrototype( new PMSuperquadricEllipsoid( part ) ); + addPrototype( new PMHeightField( part ) ); + addPrototype( new PMText( part ) ); + addPrototype( new PMJuliaFractal( part ) ); + + addPrototype( new PMBlob( part ) ); + addPrototype( new PMBlobSphere( part ) ); + addPrototype( new PMBlobCylinder( part ) ); + + addPrototype( new PMPlane( part ) ); + addPrototype( new PMPolynom( part ) ); + + addPrototype( new PMCSG( part ) ); + addPrototype( new PMDeclare( part ) ); + addPrototype( new PMObjectLink( part ) ); + + addPrototype( new PMDisc( part ) ); + addPrototype( new PMBicubicPatch( part ) ); + addPrototype( new PMTriangle( part ) ); + + addPrototype( new PMBoundedBy( part ) ); + addPrototype( new PMClippedBy( part ) ); + + addPrototype( new PMTranslate( part ) ); + addPrototype( new PMScale( part ) ); + addPrototype( new PMRotate( part ) ); + addPrototype( new PMPovrayMatrix( part ) ); + addPrototype( new PMComment( part ) ); + addPrototype( new PMRaw( part ) ); + addPrototype( new PMCamera( part ) ); + addPrototype( new PMLight( part ) ); + addPrototype( new PMLooksLike( part ) ); + addPrototype( new PMProjectedThrough( part ) ); + + addPrototype( new PMTexture( part ) ); + addPrototype( new PMPigment( part ) ); + addPrototype( new PMSolidColor( part ) ); + addPrototype( new PMNormal( part ) ); + addPrototype( new PMFinish( part ) ); + addPrototype( new PMPattern( part ) ); + addPrototype( new PMBlendMapModifiers( part ) ); + addPrototype( new PMImageMap( part ) ); + addPrototype( new PMTextureMap( part ) ); + addPrototype( new PMColorMap( part ) ); + addPrototype( new PMPigmentMap( part ) ); + addPrototype( new PMNormalMap( part ) ); + addPrototype( new PMSlopeMap( part ) ); + addPrototype( new PMDensityMap( part ) ); + addPrototype( new PMMaterialMap( part ) ); + addPrototype( new PMBumpMap( part ) ); + addPrototype( new PMTextureList( part ) ); + addPrototype( new PMColorList( part ) ); + addPrototype( new PMPigmentList( part ) ); + addPrototype( new PMNormalList( part ) ); + addPrototype( new PMDensityList( part ) ); + addPrototype( new PMWarp( part ) ); + addPrototype( new PMQuickColor( part ) ); + addPrototype( new PMSlope( part ) ); + addPrototype( new PMSkySphere( part ) ); + addPrototype( new PMRainbow( part ) ); + addPrototype( new PMFog( part ) ); + addPrototype( new PMInterior( part ) ); + addPrototype( new PMMedia( part ) ); + addPrototype( new PMMaterial( part ) ); + addPrototype( new PMDensity( part ) ); + + // POV-Ray 3.5 objects + addPrototype( new PMIsoSurface( part ) ); + addPrototype( new PMRadiosity( part ) ); + addPrototype( new PMGlobalPhotons( part ) ); + addPrototype( new PMPhotons( part ) ); + addPrototype( new PMLightGroup( part ) ); + addPrototype( new PMInteriorTexture( part ) ); + addPrototype( new PMSphereSweep( part ) ); + addPrototype( new PMMesh( part ) ); + + addDeclarationType( "GraphicalObject", i18n( "object declaration" ), "pmobjectdeclare" ); + addDeclarationType( "Light", i18n( "object declaration" ), "pmobjectdeclare" ); + addDeclarationType( "Texture", i18n( "texture declaration" ), "pmtexturedeclare" ); + addDeclarationType( "Pigment", i18n( "pigment declaration" ), "pmpigmentdeclare" ); + addDeclarationType( "Normal", i18n( "normal declaration" ), "pmnormaldeclare" ); + addDeclarationType( "Finish", i18n( "finish declaration" ), "pmfinishdeclare" ); + addDeclarationType( "TextureMap", i18n( "texture map declaration" ), "pmtexturemapdeclare" ); + addDeclarationType( "PigmentMap", i18n( "pigment map declaration" ), "pmpigmentmapdeclare" ); + addDeclarationType( "ColorMap", i18n( "color map declaration" ), "pmcolormapdeclare" ); + addDeclarationType( "NormalMap", i18n( "normal map declaration" ), "pmnormaldeclare" ); + addDeclarationType( "SlopeMap", i18n( "slope map declaration" ), "pmslopemapdeclare" ); + addDeclarationType( "DensityMap", i18n( "density map declaration" ), "pmdensitydeclare" ); + addDeclarationType( "Interior", i18n( "interior declaration" ), "pminteriordeclare" ); + addDeclarationType( "Media", i18n( "media declaration" ), "pmmediadeclare" ); + addDeclarationType( "SkySphere", i18n( "sky sphere declaration" ), "pmskyspheredeclare" ); + addDeclarationType( "Rainbow", i18n( "rainbow declaration" ), "pmrainbowdeclare" ); + addDeclarationType( "Fog", i18n( "fog declaration" ), "pmfogdeclare" ); + addDeclarationType( "Material", i18n( "material declaration" ), "pmmaterialdeclare" ); + addDeclarationType( "Density", i18n( "density declaration" ), "pmdensitydeclare" ); + addDeclarationType( "InteriorTexture", i18n( "texture declaration" ), "pminteriortexturedeclare" ); +} + +PMPrototypeManager::~PMPrototypeManager( ) +{ + /* + PMObjectListIterator it( m_prototypes ); + for( ; it.current( ); ++it ) + it.current( )->cleanUp( ); + */ +} + +void PMPrototypeManager::addPrototype( PMObject* obj ) +{ + if( !obj ) + return; + + PMMetaObject* metaObject = obj->metaObject( ); + PMMetaObject* m2 = m_metaDict.find( metaObject->className( ) ); + if( m2 ) + { + kdError( PMArea ) << "PMPrototypeManager: Class '" + << metaObject->className( ) + << "' already registered." << endl; + } + else + { + if( metaObject->isAbstract( ) ) + kdError( PMArea ) << "PMPrototypeManager: The meta object for the prototype " + << metaObject->className( ) + << " doesn't have a factory method" << endl; + + m_prototypes.append( metaObject ); + m_lowerCaseDict[metaObject->className( ).lower( )] = metaObject->className( ); + + // insert the meta object and all super classes into the hash table + while( metaObject ) + { + if( m_metaDict.find( metaObject->className( ) ) ) + metaObject = 0; + else + { + m_metaDict.insert( metaObject->className( ), metaObject ); + metaObject = metaObject->superClass( ); + } + } + } + delete obj; +} + +void PMPrototypeManager::addDeclarationType( const QString& className, + const QString& description, + const QString& pixmap ) +{ + PMMetaObject* m = metaObject( className ); + if( !m ) + kdError( PMArea ) << "PMPrototypeManager::addDeclarationType: Unknown class " << className << endl; + else + m_declareDescriptions.push_back( PMDeclareDescription( m, description, pixmap ) ); +} + +QPtrListIterator PMPrototypeManager::prototypeIterator( ) const +{ + return QPtrListIterator( m_prototypes ); +} + +const QValueList& PMPrototypeManager::declarationTypes( ) const +{ + return m_declareDescriptions; +} + +PMObject* PMPrototypeManager::newObject( const QString& name ) const +{ + if( name.isEmpty( ) ) + return 0; + + PMMetaObject* meta = m_metaDict.find( name ); + if( !meta ) + return 0; + return meta->newObject( m_pPart ); +} + +PMMetaObject* PMPrototypeManager::metaObject( const QString& name ) const +{ + if( name.isNull( ) ) + return 0; + return m_metaDict.find( name ); +} + +bool PMPrototypeManager::isA( const QString& className, + const QString& baseClass ) const +{ + return isA( metaObject( className ), baseClass ); +} + +bool PMPrototypeManager::isA( PMMetaObject* c, + const QString& baseClass ) const +{ + PMMetaObject* bc = metaObject( baseClass ); + while( c && c != bc ) + c = c->superClass( ); + return( c && ( c == bc ) ); +} + +QString PMPrototypeManager::className( const QString& lowercase ) const +{ + QMap::const_iterator it = m_lowerCaseDict.find( lowercase ); + if( it != m_lowerCaseDict.end( ) ) + return *it; + return QString::null; +} diff --git a/kpovmodeler/pmprototypemanager.h b/kpovmodeler/pmprototypemanager.h new file mode 100644 index 00000000..025b8213 --- /dev/null +++ b/kpovmodeler/pmprototypemanager.h @@ -0,0 +1,149 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMPTMANAGER_H +#define PMPTMANAGER_H + +#include "pmobject.h" +#include +#include +#include + +class PMPart; + +/** + * Description class for declarations types, used by @ref PMPrototypeManager + * and @ref PMDeclare + */ +class PMDeclareDescription +{ +public: + PMDeclareDescription( ) { } + PMDeclareDescription( const PMDeclareDescription& d ) + { + type = d.type; + description = d.description; + pixmap = d.pixmap; + } + PMDeclareDescription( PMMetaObject* t, const QString& d, const QString& p ) + { + type = t; + description = d; + pixmap = p; + } + PMDeclareDescription& operator=( const PMDeclareDescription& d ) + { + type = d.type; + description = d.description; + pixmap = d.pixmap; + return *this; + } + PMMetaObject* type; + QString description; + QString pixmap; +}; + +/** + * Prototype manager for @ref PMObject. + * + * This class stores class and inheritance information for each + * available object type. + * + * Each @ref PMPart class holds one instance of this class. The + * available objects depend on the loaded plugins. + * + * Patterns: Prototype + */ +class PMPrototypeManager +{ +public: + /** + * Creates a prototype manager for the part. + */ + PMPrototypeManager( PMPart* part ); + /** + * Deletes the prototype manager + */ + ~PMPrototypeManager( ); + /** + * Adds the object to the list of prototypes. The prototype becomes + * the owner of the object and will be delete immediately by the + * prototype manager. + */ + void addPrototype( PMObject* obj ); + /** + * Adds a declaration type. Needed information is the class type, + * the @ref description( ) and the @ref pixmap( ) + */ + void addDeclarationType( const QString& className, + const QString& description, + const QString& pixmap ); + /** + * Returns an iterator to the list of available objects + */ + QPtrListIterator prototypeIterator( ) const; + /** + * Returns an iterator to the list of available declaration types + */ + const QValueList& declarationTypes( ) const; + /** + * Returns a new PMObject by class name + */ + PMObject* newObject( const QString& name ) const; + /** + * Returns the meta object by class name or 0 if this class does + * not exist. + * @see PMMetaObject + */ + PMMetaObject* metaObject( const QString& name ) const; + /** + * Returns true if the class exists + */ + bool existsClass( const QString& name ) const + { + return metaObject( name ); + } + /** + * Returns true if the second class is a base class for + * the first class + */ + bool isA( const QString& className, const QString& baseClassName ) const; + /** + * Returns true if the second class is a base class for + * the first class + */ + bool isA( PMMetaObject* c, const QString& baseClassName ) const; + /** + * Returns the real class if only the lower case version is know. + * Used by the xml parser + */ + QString className( const QString& lowercase ) const; + /** + * Returns a pointer to the part + */ + PMPart* part( ) const { return m_pPart; } + +private: + QPtrList m_prototypes; + QDict m_metaDict; + QMap m_lowerCaseDict; + QValueList m_declareDescriptions; + PMPart* m_pPart; +}; +#endif diff --git a/kpovmodeler/pmquickcolor.cpp b/kpovmodeler/pmquickcolor.cpp new file mode 100644 index 00000000..fcf34e85 --- /dev/null +++ b/kpovmodeler/pmquickcolor.cpp @@ -0,0 +1,132 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Leonardo Skorianez + email : lsk@if.ufrj.br + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmquickcolor.h" + +#include "pmxmlhelper.h" +#include "pmquickcoloredit.h" +#include "pmmemento.h" + +#include + +const PMColor colorDefault = PMColor( 1.0, 1.0, 1.0, 0.0, 0.0 ); + +PMDefinePropertyClass( PMQuickColor, PMQuickColorProperty ); + +PMMetaObject* PMQuickColor::s_pMetaObject = 0; +PMObject* createNewQuickColor( PMPart* part ) +{ + return new PMQuickColor( part ); +} + +PMQuickColor::PMQuickColor( PMPart* part ) + : Base( part ) +{ + m_color = colorDefault; +} + +PMQuickColor::PMQuickColor( const PMQuickColor& c ) + : Base( c ) +{ + m_color = c.m_color; +} + +PMQuickColor::~PMQuickColor( ) +{ +} + +QString PMQuickColor::description( ) const +{ + return i18n( "quick color" ); +} + +void PMQuickColor::serialize( QDomElement& e, QDomDocument& /*doc*/ ) const +{ + e.setAttribute( "quickcolor", m_color.serializeXML( ) ); +} + +void PMQuickColor::readAttributes( const PMXMLHelper& h ) +{ + m_color = h.colorAttribute( "quickcolor", colorDefault ); +} + +PMMetaObject* PMQuickColor::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "QuickColor", Base::metaObject( ), + createNewQuickColor ); + s_pMetaObject->addProperty( + new PMQuickColorProperty( "color", &PMQuickColor::setColor, &PMQuickColor::color ) ); + } + return s_pMetaObject; +} + +void PMQuickColor::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMQuickColor::setColor( const PMColor& c ) +{ + if( c != m_color ) + { + if( m_pMemento ) + { + m_pMemento->addData( s_pMetaObject, PMColorID, m_color ); + m_pMemento->setViewStructureChanged( ); + } + m_color = c; + } +} + +PMDialogEditBase* PMQuickColor::editWidget( QWidget* parent ) const +{ + return new PMQuickColorEdit( parent ); +} + +void PMQuickColor::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMColorID: + setColor( data->colorData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMQuickColor::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmquickcolor.h b/kpovmodeler/pmquickcolor.h new file mode 100644 index 00000000..a1dce42d --- /dev/null +++ b/kpovmodeler/pmquickcolor.h @@ -0,0 +1,100 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Leonardo Skorianez + email : lsk2if.ufrj.br + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMQUICKCOLOR_H +#define PMQUICKCOLOR_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmobject.h" +#include "pmcolor.h" + +/** + * Class for quick colors. + * Tell POV-Ray what solid color to use for quick renders instead of a paterned pigment. + */ + +class PMQuickColor : public PMObject +{ + typedef PMObject Base; +public: + /** + * Creates a PMQuickColor + */ + PMQuickColor( PMPart* part ); + /** + * Copy constructor + */ + PMQuickColor( const PMQuickColor& c ); + /** + * deletes the PMQuickColor + */ + virtual ~PMQuickColor( ); + + /** */ + virtual PMObject* copy( ) const { return new PMQuickColor( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMQuickColorEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmquickcolor" ); } + + /** + * Returns the color + */ + PMColor color( ) const { return m_color; } + /** + * Sets the color + */ + void setColor( const PMColor& c ); + + /** */ + virtual void restoreMemento( PMMemento* s ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMQuickColorMementoID { PMColorID }; + PMColor m_color; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmquickcoloredit.cpp b/kpovmodeler/pmquickcoloredit.cpp new file mode 100644 index 00000000..35c21234 --- /dev/null +++ b/kpovmodeler/pmquickcoloredit.cpp @@ -0,0 +1,77 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Leonardo Skorianez + email : lsk@if.ufrj.br +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmquickcoloredit.h" +#include "pmquickcolor.h" +#include "pmcoloredit.h" +#include "pmdebug.h" + +#include +#include +#include + + +PMQuickColorEdit::PMQuickColorEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMQuickColorEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* layout = new QHBoxLayout( topLayout( ) ); + m_pColorEdit = new PMColorEdit( false, this ); + layout->addWidget( new QLabel( i18n( "Color:" ), this ), 0, AlignTop ); + layout->addWidget( m_pColorEdit ); + + connect( m_pColorEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMQuickColorEdit::displayObject( PMObject* o ) +{ + if( o->isA( "QuickColor" ) ) + { + m_pDisplayedObject = ( PMQuickColor* ) o; + m_pColorEdit->setColor( m_pDisplayedObject->color( ) ); + m_pColorEdit->setReadOnly( m_pDisplayedObject->isReadOnly( ) ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMQuickColorEdit: Can't display object\n"; +} + +void PMQuickColorEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setColor( m_pColorEdit->color( ) ); + } +} + +bool PMQuickColorEdit::isDataValid( ) +{ + if( !m_pColorEdit->isDataValid( ) ) + return false; + return Base::isDataValid( ); +} + +#include "pmquickcoloredit.moc" diff --git a/kpovmodeler/pmquickcoloredit.h b/kpovmodeler/pmquickcoloredit.h new file mode 100644 index 00000000..78759a88 --- /dev/null +++ b/kpovmodeler/pmquickcoloredit.h @@ -0,0 +1,65 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Leonardo Skorianez + email : lsk@if.ufrj.br +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMQUICKCOLOREDIT_H +#define PMQUICKCOLOREDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "pmdialogeditbase.h" + +class PMQuickColor; +class PMColorEdit; + +/** + * Dialog edit class for @ref PMQuickColor. + */ +class PMQuickColorEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMQuickColorEdit with parent and name + */ + PMQuickColorEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); + +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMQuickColor* m_pDisplayedObject; + PMColorEdit* m_pColorEdit; +}; + + +#endif diff --git a/kpovmodeler/pmradiosity.cpp b/kpovmodeler/pmradiosity.cpp new file mode 100644 index 00000000..d5446b25 --- /dev/null +++ b/kpovmodeler/pmradiosity.cpp @@ -0,0 +1,428 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmradiosity.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmradiosityedit.h" + +#include + +const double adcBailoutDefault = 0.01; +const double brightnessDefault = 1.0; +const int countDefault = 35; +const double errorBoundDefault = 1.8; +const double grayThresholdDefault = 0.0; +const double lowErrorFactorDefault = 0.5; +const double maxSampleDefault = -1.0; +const double minimumReuseDefault = 0.015; +const int nearestCountDefault = 5; +const double pretraceStartDefault = 0.08; +const double pretraceEndDefault = 0.04; +const int recursionLimitDefault = 2; + +PMDefinePropertyClass( PMRadiosity, PMRadiosityProperty ); +PMMetaObject* PMRadiosity::s_pMetaObject = 0; +PMObject* createNewRadiosity( PMPart* part ) +{ + return new PMRadiosity( part ); +} + +PMRadiosity::PMRadiosity( PMPart* part ) : Base( part ) +{ + m_adcBailout = adcBailoutDefault; + m_alwaysSample = true; + m_brightness = brightnessDefault; + m_count = countDefault; + m_errorBound = errorBoundDefault; + m_grayThreshold = grayThresholdDefault; + m_lowErrorFactor = lowErrorFactorDefault; + m_maxSample = maxSampleDefault; + m_media = false; + m_minimumReuse = minimumReuseDefault; + m_nearestCount = nearestCountDefault; + m_normal = false; + m_pretraceStart = pretraceStartDefault; + m_pretraceEnd = pretraceEndDefault; + m_recursionLimit = recursionLimitDefault; +} + +PMRadiosity::PMRadiosity( const PMRadiosity& r ) + : Base( r ) +{ + m_adcBailout = r.m_adcBailout; + m_alwaysSample = r.m_alwaysSample; + m_brightness = r.m_brightness; + m_count = r.m_count; + m_errorBound = r.m_errorBound; + m_grayThreshold = r.m_grayThreshold; + m_lowErrorFactor = r.m_lowErrorFactor; + m_maxSample = r.m_maxSample; + m_media = r.m_media; + m_minimumReuse = r.m_minimumReuse; + m_nearestCount = r.m_nearestCount; + m_normal = r.m_normal; + m_pretraceStart = r.m_pretraceStart; + m_pretraceEnd = r.m_pretraceEnd; + m_recursionLimit = r.m_recursionLimit; +} + +PMRadiosity::~PMRadiosity( ) +{ +} + +PMMetaObject* PMRadiosity::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Radiosity", Base::metaObject( ), + createNewRadiosity ); + s_pMetaObject->addProperty( + new PMRadiosityProperty( "adcBailout", &PMRadiosity::setAdcBailout, &PMRadiosity::adcBailout ) ); + s_pMetaObject->addProperty( + new PMRadiosityProperty( "alwaysSample", &PMRadiosity::setAlwaysSample, &PMRadiosity::alwaysSample ) ); + s_pMetaObject->addProperty( + new PMRadiosityProperty( "brightness", &PMRadiosity::setBrightness, &PMRadiosity::brightness ) ); + s_pMetaObject->addProperty( + new PMRadiosityProperty( "count", &PMRadiosity::setCount, &PMRadiosity::count ) ); + s_pMetaObject->addProperty( + new PMRadiosityProperty( "errorBound", &PMRadiosity::setErrorBound, &PMRadiosity::errorBound ) ); + s_pMetaObject->addProperty( + new PMRadiosityProperty( "grayThreshold", &PMRadiosity::setGrayThreshold, &PMRadiosity::grayThreshold ) ); + s_pMetaObject->addProperty( + new PMRadiosityProperty( "lowErrorFactor", &PMRadiosity::setLowErrorFactor, &PMRadiosity::lowErrorFactor ) ); + s_pMetaObject->addProperty( + new PMRadiosityProperty( "maxSample", &PMRadiosity::setMaxSample, &PMRadiosity::maxSample ) ); + s_pMetaObject->addProperty( + new PMRadiosityProperty( "media", &PMRadiosity::setMedia, &PMRadiosity::media ) ); + s_pMetaObject->addProperty( + new PMRadiosityProperty( "minimumReuse", &PMRadiosity::setMinimumReuse, &PMRadiosity::minimumReuse ) ); + s_pMetaObject->addProperty( + new PMRadiosityProperty( "nearestCount", &PMRadiosity::setNearestCount, &PMRadiosity::nearestCount ) ); + s_pMetaObject->addProperty( + new PMRadiosityProperty( "normal", &PMRadiosity::setNormal, &PMRadiosity::normal ) ); + s_pMetaObject->addProperty( + new PMRadiosityProperty( "pretraceStart", &PMRadiosity::setPretraceStart, &PMRadiosity::pretraceStart ) ); + s_pMetaObject->addProperty( + new PMRadiosityProperty( "pretraceEnd", &PMRadiosity::setPretraceEnd, &PMRadiosity::pretraceEnd ) ); + s_pMetaObject->addProperty( + new PMRadiosityProperty( "recursionLimit", &PMRadiosity::setRecursionLimit, &PMRadiosity::recursionLimit ) ); + } + return s_pMetaObject; +} + +void PMRadiosity::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMRadiosity::description( ) const +{ + return i18n( "radiosity" ); +} + +void PMRadiosity::serialize( QDomElement& e, QDomDocument& ) const +{ + e.setAttribute( "adc_bailout", m_adcBailout ); + + if ( m_alwaysSample ) + e.setAttribute( "always_sample", "1" ); + else + e.setAttribute( "always_sample", "0" ); + + e.setAttribute( "brightness", m_brightness ); + e.setAttribute( "count", m_count ); + e.setAttribute( "error_bound", m_errorBound ); + e.setAttribute( "gray_threshold", m_grayThreshold ); + e.setAttribute( "low_error_factor", m_lowErrorFactor ); + e.setAttribute( "max_sample", m_maxSample ); + + if ( m_media ) + e.setAttribute( "media", "1" ); + else + e.setAttribute( "media", "0" ); + + e.setAttribute( "minimum_reuse", m_minimumReuse ); + e.setAttribute( "nearest_count", m_nearestCount ); + + if ( m_normal ) + e.setAttribute( "normal", "1" ); + else + e.setAttribute( "normal", "0" ); + + e.setAttribute( "pretrace_start", m_pretraceStart ); + e.setAttribute( "pretrace_end", m_pretraceEnd ); + e.setAttribute( "recursion_limit", m_recursionLimit ); +} + +void PMRadiosity::readAttributes( const PMXMLHelper& h ) +{ + m_adcBailout = h.doubleAttribute( "adc_bailout", adcBailoutDefault ); + m_alwaysSample = h.boolAttribute( "always_sample", true ); + m_brightness = h.doubleAttribute( "brightness", brightnessDefault ); + m_count = h.intAttribute( "count", countDefault ); + m_errorBound = h.doubleAttribute( "error_bound", errorBoundDefault ); + m_grayThreshold = h.doubleAttribute( "gray_threshold", grayThresholdDefault ); + m_lowErrorFactor = h.doubleAttribute( "low_error_factor", lowErrorFactorDefault ); + m_maxSample = h.doubleAttribute( "max_sample", maxSampleDefault ); + m_media = h.boolAttribute( "media", false ); + m_minimumReuse = h.doubleAttribute( "minimum_reuse", minimumReuseDefault ); + m_nearestCount = h.intAttribute( "nearest_count", nearestCountDefault ); + m_normal = h.boolAttribute( "normal", false ); + m_pretraceStart = h.doubleAttribute( "pretrace_start", pretraceStartDefault ); + m_pretraceEnd = h.doubleAttribute( "pretrace_end", pretraceEndDefault ); + m_recursionLimit = h.intAttribute( "recursion_limit", recursionLimitDefault ); +} + +void PMRadiosity::setAdcBailout( double ab ) +{ + if( ab != m_adcBailout ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAdcBailoutID, m_adcBailout ); + m_adcBailout = ab; + } +} + +void PMRadiosity::setAlwaysSample( bool as ) +{ + if( as != m_alwaysSample ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAlwaysSampleID, m_alwaysSample ); + m_alwaysSample = as; + } +} + +void PMRadiosity::setBrightness( double b ) +{ + if( b != m_brightness ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMBrightnessID, m_brightness ); + m_brightness = b; + } +} + +void PMRadiosity::setCount( int c ) +{ + if( c != m_count ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCountID, m_count ); + m_count = c; + } +} + +void PMRadiosity::setErrorBound( double eb ) +{ + if( eb != m_errorBound ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMErrorBoundID, m_errorBound ); + m_errorBound = eb; + } +} + +void PMRadiosity::setGrayThreshold( double gt ) +{ + if( gt != m_grayThreshold ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMGrayThresholdID, m_grayThreshold ); + m_grayThreshold = gt; + } +} + +void PMRadiosity::setLowErrorFactor( double lew ) +{ + if( lew != m_lowErrorFactor ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMLowErrorFactorID, m_lowErrorFactor ); + m_lowErrorFactor = lew; + } +} + +void PMRadiosity::setMaxSample( double ms ) +{ + if( ms != m_maxSample ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMMaxSampleID, m_maxSample ); + m_maxSample = ms; + } +} + +void PMRadiosity::setMedia( bool m ) +{ + if( m != m_media ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMMediaID, m_media ); + m_media = m; + } +} + +void PMRadiosity::setMinimumReuse( double c ) +{ + if( c != m_minimumReuse ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMMinimumReuseID, m_minimumReuse ); + m_minimumReuse = c; + } +} + +void PMRadiosity::setNearestCount( int c ) +{ + if( c != m_nearestCount ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMNearestCountID, m_nearestCount ); + m_nearestCount = c; + } +} + +void PMRadiosity::setNormal( bool n ) +{ + if( n != m_normal ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMNormalID, m_normal ); + m_normal = n; + } +} + +void PMRadiosity::setPretraceStart( double ps ) +{ + if ( ps < m_pretraceEnd ) + { + kdError( PMArea ) << "Pretrace Start < Pretrace End in PMRadiosity::setPretraceStart\n"; + ps = m_pretraceEnd; + } + + if( ps != m_pretraceStart ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMPretraceStartID, m_pretraceStart ); + m_pretraceStart = ps; + } +} + +void PMRadiosity::setPretraceEnd( double pe ) +{ + if ( pe > m_pretraceStart ) + { + kdError( PMArea ) << "Pretrace End > Pretrace Start in PMRadiosity::setPretraceEnd\n"; + pe = m_pretraceStart; + } + + if( pe != m_pretraceEnd ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMPretraceEndID, m_pretraceEnd ); + m_pretraceEnd = pe; + } +} + +void PMRadiosity::setRecursionLimit( int c ) +{ + if( c != m_recursionLimit ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRecursionLimitID, m_recursionLimit ); + m_recursionLimit = c; + } +} + +PMDialogEditBase* PMRadiosity::editWidget( QWidget* parent ) const +{ + return new PMRadiosityEdit( parent ); +} + +void PMRadiosity::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMAdcBailoutID: + setAdcBailout( data->doubleData( ) ); + break; + case PMAlwaysSampleID: + setAlwaysSample( data->boolData( ) ); + break; + case PMBrightnessID: + setBrightness( data->doubleData( ) ); + break; + case PMCountID: + setCount( data->intData( ) ); + break; + case PMErrorBoundID: + setErrorBound( data->doubleData( ) ); + break; + case PMGrayThresholdID: + setGrayThreshold( data->doubleData( ) ); + break; + case PMLowErrorFactorID: + setLowErrorFactor( data->doubleData( ) ); + break; + case PMMaxSampleID: + setMaxSample( data->doubleData( ) ); + break; + case PMMediaID: + setMedia( data->boolData( ) ); + break; + case PMMinimumReuseID: + setMinimumReuse( data->doubleData( ) ); + break; + case PMNearestCountID: + setNearestCount( data->intData( ) ); + break; + case PMNormalID: + setNormal( data->boolData( ) ); + break; + case PMPretraceStartID: + setPretraceStart( data->doubleData( ) ); + break; + case PMPretraceEndID: + setPretraceEnd( data->doubleData( ) ); + break; + case PMRecursionLimitID: + setRecursionLimit( data->intData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMRadiosity::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmradiosity.h b/kpovmodeler/pmradiosity.h new file mode 100644 index 00000000..56a1cbd4 --- /dev/null +++ b/kpovmodeler/pmradiosity.h @@ -0,0 +1,241 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMRADIOSITY_H +#define PMRADIOSITY_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmobject.h" + +/** + * Class for radiosity settings. + */ + +class PMRadiosity : public PMObject +{ + typedef PMObject Base; +public: + /** + * Creates a PMRadiosity + */ + PMRadiosity( PMPart* part ); + /** + * Copy constructor + */ + PMRadiosity( const PMRadiosity& r ); + /** + * deletes the PMRadiosity + */ + virtual ~PMRadiosity( ); + + /** */ + virtual PMObject* copy( ) const { return new PMRadiosity( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMRadiosityEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmradiosity" ); } + + /** + * Returns the adc bailout + */ + double adcBailout( ) const { return m_adcBailout; } + /** + * Sets the adc bailout + */ + void setAdcBailout( double ab ); + + /** + * Returns the always sample flag + */ + bool alwaysSample( ) const { return m_alwaysSample; } + /** + * Sets the always sample flag + */ + void setAlwaysSample( bool as ); + + /** + * Returns brightness + */ + double brightness( ) const { return m_brightness; } + /** + * Sets the brightness + */ + void setBrightness( double b ); + + /** + * Returns count + */ + int count( ) const { return m_count; } + /** + * Sets the count + */ + void setCount( int c ); + + /** + * Returns error boundary + */ + double errorBound( ) const { return m_errorBound; } + /** + * Sets the error boundary + */ + void setErrorBound( double eb ); + + /** + * Returns gray threshold + */ + double grayThreshold( ) const { return m_grayThreshold; } + /** + * Sets the gray threshold + */ + void setGrayThreshold( double gt ); + + /** + * Returns low error factor + */ + double lowErrorFactor( ) const { return m_lowErrorFactor; } + /** + * Sets the low error factor + */ + void setLowErrorFactor( double lew ); + + /** + * Returns the maximum sample + */ + double maxSample( ) const { return m_maxSample; } + /** + * Sets the maximum sample + */ + void setMaxSample( double ms ); + + /** + * Returns the media flag + */ + bool media( ) const { return m_media; } + /** + * Sets the media flag + */ + void setMedia( bool m ); + + /** + * Returns minimum reuse + */ + double minimumReuse( ) const { return m_minimumReuse; } + /** + * Sets the minimum reuse + */ + void setMinimumReuse( double mr ); + + /** + * Returns nearest count + */ + int nearestCount( ) const { return m_nearestCount; } + /** + * Sets the nearest count + */ + void setNearestCount( int nc ); + + /** + * Returns the normal flag + */ + bool normal( ) const { return m_normal; } + /** + * Sets the normal flag + */ + void setNormal( bool n ); + + /** + * Returns the pretrace start + */ + double pretraceStart( ) const { return m_pretraceStart; } + /** + * Sets the pretrace start + */ + void setPretraceStart( double ps ); + + /** + * Returns the pretrace end + */ + double pretraceEnd( ) const { return m_pretraceEnd; } + /** + * Sets the pretrace end + */ + void setPretraceEnd( double pe ); + + /** + * Returns recursion limit + */ + int recursionLimit( ) const { return m_recursionLimit; } + /** + * Sets the recursion limit + */ + void setRecursionLimit( int rl ); + + /** */ + virtual void restoreMemento( PMMemento* s ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMRadiosityMementoID { PMAdcBailoutID, PMAlwaysSampleID, PMBrightnessID, + PMCountID, PMErrorBoundID, PMGrayThresholdID, + PMLowErrorFactorID, PMMaxSampleID, PMMediaID, + PMMinimumReuseID, PMNearestCountID, PMNormalID, + PMPretraceStartID, PMPretraceEndID, PMRecursionLimitID }; + + double m_adcBailout; + bool m_alwaysSample; + double m_brightness; + int m_count; + double m_errorBound; + double m_grayThreshold; + double m_lowErrorFactor; + double m_maxSample; + bool m_media; + double m_minimumReuse; + int m_nearestCount; + bool m_normal; + double m_pretraceStart; + double m_pretraceEnd; + int m_recursionLimit; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmradiosityedit.cpp b/kpovmodeler/pmradiosityedit.cpp new file mode 100644 index 00000000..1154214d --- /dev/null +++ b/kpovmodeler/pmradiosityedit.cpp @@ -0,0 +1,233 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmradiosityedit.h" +#include "pmradiosity.h" +#include "pmlineedits.h" + +#include +#include +#include +#include +#include +#include + + +PMRadiosityEdit::PMRadiosityEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMRadiosityEdit::createTopWidgets( ) +{ + QHBoxLayout* hl; + QGridLayout *gl; + QLabel* lbl; + + Base::createTopWidgets( ); + + hl = new QHBoxLayout( topLayout( ) ); + gl = new QGridLayout( hl, 15, 2 ); + + lbl = new QLabel( i18n( "Adc bailout:" ), this ); + m_pAdcBailout = new PMFloatEdit( this ); + m_pAdcBailout->setValidation( true, 0, true, 1 ); + gl->addWidget( lbl, 0, 0 ); + gl->addWidget( m_pAdcBailout, 0, 1 ); + + m_pAlwaysSample = new QCheckBox( i18n( "Always sample" ), this ); + gl->addMultiCellWidget( m_pAlwaysSample, 1, 1, 0, 1 ); + + lbl = new QLabel( i18n( "Brightness:" ), this ); + m_pBrightness = new PMFloatEdit( this ); + m_pBrightness->setValidation( true, 0, false, 0 ); + gl->addWidget( lbl, 2, 0 ); + gl->addWidget( m_pBrightness, 2, 1 ); + + lbl = new QLabel( i18n( "Count:" ), this ); + m_pCount = new PMIntEdit( this ); + m_pCount->setValidation( true, 0, true, 1600 ); + gl->addWidget( lbl, 3, 0 ); + gl->addWidget( m_pCount, 3, 1 ); + + lbl = new QLabel( i18n( "Error boundary:" ), this ); + m_pErrorBound = new PMFloatEdit( this ); + m_pErrorBound->setValidation( true, 0, false, 0 ); + gl->addWidget( lbl, 4, 0 ); + gl->addWidget( m_pErrorBound, 4, 1 ); + + lbl = new QLabel( i18n( "Gray threshold:" ), this ); + m_pGrayThreshold = new PMFloatEdit( this ); + m_pGrayThreshold->setValidation( true, 0, true, 1 ); + gl->addWidget( lbl, 5, 0 ); + gl->addWidget( m_pGrayThreshold, 5, 1 ); + + lbl = new QLabel( i18n( "Low error factor:" ), this ); + m_pLowErrorFactor = new PMFloatEdit( this ); + m_pLowErrorFactor->setValidation( true, 0, true, 1 ); + gl->addWidget( lbl, 6, 0 ); + gl->addWidget( m_pLowErrorFactor, 6, 1 ); + + lbl = new QLabel( i18n( "Maximum sample:" ), this ); + m_pMaxSample = new PMFloatEdit( this ); + m_pMaxSample->setValidation( true, -1, false, 0 ); + gl->addWidget( lbl, 7, 0 ); + gl->addWidget( m_pMaxSample, 7, 1 ); + + m_pMedia = new QCheckBox( i18n( "Media" ), this ); + gl->addMultiCellWidget( m_pMedia, 8, 8, 0, 1 ); + + lbl = new QLabel( i18n( "Minimum reuse:" ), this ); + m_pMinimumReuse = new PMFloatEdit( this ); + m_pMinimumReuse->setValidation( true, 0, true, 1 ); + gl->addWidget( lbl, 9, 0 ); + gl->addWidget( m_pMinimumReuse, 9, 1 ); + + lbl = new QLabel( i18n( "Nearest count:" ), this ); + m_pNearestCount = new PMIntEdit( this ); + m_pNearestCount->setValidation( true, 0, true, 20 ); + gl->addWidget( lbl, 10, 0 ); + gl->addWidget( m_pNearestCount, 10, 1 ); + + m_pNormal = new QCheckBox( i18n( "Normal" ), this ); + gl->addMultiCellWidget( m_pNormal, 11, 11, 0, 1 ); + + lbl = new QLabel( i18n( "Pretrace start:" ), this ); + m_pPretraceStart = new PMFloatEdit( this ); + m_pPretraceStart->setValidation( true, 0, true, 1 ); + gl->addWidget( lbl, 12, 0 ); + gl->addWidget( m_pPretraceStart, 12, 1 ); + + lbl = new QLabel( i18n( "Pretrace end:" ), this ); + m_pPretraceEnd = new PMFloatEdit( this ); + m_pPretraceEnd->setValidation( true, 0, true, 1 ); + gl->addWidget( lbl, 13, 0 ); + gl->addWidget( m_pPretraceEnd, 13, 1 ); + + lbl = new QLabel( i18n( "Recursion limit:" ), this ); + m_pRecursionLimit = new PMIntEdit( this ); + m_pRecursionLimit->setValidation( true, 1, true, 20 ); + gl->addWidget( lbl, 14, 0 ); + gl->addWidget( m_pRecursionLimit, 14, 1 ); + + hl->addStretch( 1 ); + + connect( m_pAdcBailout, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pAlwaysSample, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pBrightness, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pCount, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pErrorBound, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pGrayThreshold, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pLowErrorFactor, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pMaxSample, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pMedia, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pMinimumReuse, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pNearestCount, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pNormal, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pPretraceStart, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pPretraceEnd, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pRecursionLimit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMRadiosityEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Radiosity" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMRadiosity* ) o; + + m_pAdcBailout->setValue( m_pDisplayedObject->adcBailout( ) ); + m_pAdcBailout->setReadOnly( readOnly ); + m_pAlwaysSample->setChecked( m_pDisplayedObject->alwaysSample( ) ); + m_pAlwaysSample->setEnabled( !readOnly ); + m_pBrightness->setValue( m_pDisplayedObject->brightness( ) ); + m_pBrightness->setReadOnly( readOnly ); + m_pCount->setValue( m_pDisplayedObject->count( ) ); + m_pCount->setReadOnly( readOnly ); + m_pErrorBound->setValue( m_pDisplayedObject->errorBound( ) ); + m_pErrorBound->setReadOnly( readOnly ); + m_pGrayThreshold->setValue( m_pDisplayedObject->grayThreshold( ) ); + m_pGrayThreshold->setReadOnly( readOnly ); + m_pLowErrorFactor->setValue( m_pDisplayedObject->lowErrorFactor( ) ); + m_pLowErrorFactor->setReadOnly( readOnly ); + m_pMaxSample->setValue( m_pDisplayedObject->maxSample( ) ); + m_pMaxSample->setReadOnly( readOnly ); + m_pMedia->setChecked( m_pDisplayedObject->media( ) ); + m_pMedia->setEnabled( !readOnly ); + m_pMinimumReuse->setValue( m_pDisplayedObject->minimumReuse( ) ); + m_pMinimumReuse->setReadOnly( readOnly ); + m_pNearestCount->setValue( m_pDisplayedObject->nearestCount( ) ); + m_pNearestCount->setReadOnly( readOnly ); + m_pNormal->setChecked( m_pDisplayedObject->normal( ) ); + m_pNormal->setEnabled( !readOnly ); + m_pPretraceStart->setValue( m_pDisplayedObject->pretraceStart( ) ); + m_pPretraceStart->setReadOnly( readOnly ); + m_pPretraceEnd->setValue( m_pDisplayedObject->pretraceEnd( ) ); + m_pPretraceEnd->setReadOnly( readOnly ); + m_pRecursionLimit->setValue( m_pDisplayedObject->recursionLimit( ) ); + m_pRecursionLimit->setReadOnly( readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMRadiosityEdit: Can't display object\n"; +} + +void PMRadiosityEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setAdcBailout( m_pAdcBailout->value( ) ); + m_pDisplayedObject->setAlwaysSample( m_pAlwaysSample->isChecked( ) ); + m_pDisplayedObject->setBrightness( m_pBrightness->value( ) ); + m_pDisplayedObject->setCount( m_pCount->value( ) ); + m_pDisplayedObject->setErrorBound( m_pErrorBound->value( ) ); + m_pDisplayedObject->setGrayThreshold( m_pGrayThreshold->value( ) ); + m_pDisplayedObject->setLowErrorFactor( m_pLowErrorFactor->value( ) ); + m_pDisplayedObject->setMaxSample( m_pMaxSample->value( ) ); + m_pDisplayedObject->setMedia( m_pMedia->isChecked( ) ); + m_pDisplayedObject->setMinimumReuse( m_pMinimumReuse->value( ) ); + m_pDisplayedObject->setNearestCount( m_pNearestCount->value( ) ); + m_pDisplayedObject->setNormal( m_pNormal->isChecked( ) ); + m_pDisplayedObject->setPretraceStart( m_pPretraceStart->value( ) ); + m_pDisplayedObject->setPretraceEnd( m_pPretraceEnd->value( ) ); + m_pDisplayedObject->setRecursionLimit( m_pRecursionLimit->value( ) ); + } +} + +bool PMRadiosityEdit::isDataValid( ) +{ + if( !m_pAdcBailout->isDataValid( ) ) return false; + if( !m_pBrightness->isDataValid( ) ) return false; + if( !m_pCount->isDataValid( ) ) return false; + if( !m_pErrorBound->isDataValid( ) ) return false; + if( !m_pGrayThreshold->isDataValid( ) ) return false; + if( !m_pLowErrorFactor->isDataValid( ) ) return false; + if( !m_pMaxSample->isDataValid( ) ) return false; + if( !m_pMinimumReuse->isDataValid( ) ) return false; + if( !m_pNearestCount->isDataValid( ) ) return false; + if( !m_pPretraceStart->isDataValid( ) ) return false; + if( !m_pPretraceEnd->isDataValid( ) ) return false; + if( !m_pRecursionLimit->isDataValid( ) ) return false; + + return Base::isDataValid( ); +} + +#include "pmradiosityedit.moc" diff --git a/kpovmodeler/pmradiosityedit.h b/kpovmodeler/pmradiosityedit.h new file mode 100644 index 00000000..37ee18c7 --- /dev/null +++ b/kpovmodeler/pmradiosityedit.h @@ -0,0 +1,81 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Leon Pennington + email : leon@leonscape.co.uk +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMRADIOSITYEDIT_H +#define PMRADIOSITYEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMRadiosity; +class PMFloatEdit; +class PMIntEdit; +class QCheckBox; + +/** + * Dialog edit class for @ref PMRadiosity. + */ +class PMRadiosityEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMRadiosityEdit with parent and name + */ + PMRadiosityEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + +private: + PMRadiosity* m_pDisplayedObject; + + PMFloatEdit* m_pAdcBailout; + QCheckBox* m_pAlwaysSample; + PMFloatEdit* m_pBrightness; + PMIntEdit* m_pCount; + PMFloatEdit* m_pErrorBound; + PMFloatEdit* m_pGrayThreshold; + PMFloatEdit* m_pLowErrorFactor; + PMFloatEdit* m_pMaxSample; + QCheckBox* m_pMedia; + PMFloatEdit* m_pMinimumReuse; + PMIntEdit* m_pNearestCount; + QCheckBox* m_pNormal; + PMFloatEdit* m_pPretraceStart; + PMFloatEdit* m_pPretraceEnd; + PMIntEdit* m_pRecursionLimit; +}; + + +#endif diff --git a/kpovmodeler/pmrainbow.cpp b/kpovmodeler/pmrainbow.cpp new file mode 100644 index 00000000..5a80e013 --- /dev/null +++ b/kpovmodeler/pmrainbow.cpp @@ -0,0 +1,422 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmrainbow.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmrainbowedit.h" +#include "pmvector.h" + +#include + +PMMetaObject* PMRainbow::s_pMetaObject = 0; +PMObject* createNewRainbow( PMPart* part ) +{ + return new PMRainbow( part ); +} + +const PMVector directionDefault = PMVector( 0.0, 0.0, 0.0 ); +const double angleDefault = 0.0; +const double widthDefault = 0.0; +const double distanceDefault = 0.0; +const double jitterDefault = 0.0; +const PMVector upDefault = PMVector( 0.0, 0.0, 0.0 ); +const double arcAngleDefault = 0.0; +const double falloffAngleDefault = 0.0; + +PMDefinePropertyClass( PMRainbow, PMRainbowProperty ); + +PMRainbow::PMRainbow( PMPart* part ) + : Base( part ) +{ + m_direction = directionDefault; + m_angle = angleDefault; + m_width = widthDefault; + m_distance = distanceDefault; + m_jitter = jitterDefault; + m_up = upDefault; + m_arcAngle = arcAngleDefault; + m_falloffAngle = falloffAngleDefault; + m_enableDirection = false; + m_enableAngle = false; + m_enableWidth = false; + m_enableDistance = false; + m_enableJitter = false; + m_enableUp = false; + m_enableArcAngle = false; + m_enableFalloffAngle = false; +} + +PMRainbow::PMRainbow( const PMRainbow& r ) + : Base( r ) +{ + m_direction = r.m_direction; + m_angle = r.m_angle; + m_width = r.m_width; + m_distance = r.m_distance; + m_jitter = r.m_jitter; + m_up = r.m_up; + m_arcAngle = r.m_arcAngle; + m_falloffAngle = r.m_falloffAngle; + m_enableDirection = r.m_enableDirection; + m_enableAngle = r.m_enableAngle; + m_enableWidth = r.m_enableWidth; + m_enableDistance = r.m_enableDistance; + m_enableJitter = r.m_enableJitter; + m_enableUp = r.m_enableUp; + m_enableArcAngle = r.m_enableArcAngle; + m_enableFalloffAngle = r.m_enableFalloffAngle; +} + +PMRainbow::~PMRainbow( ) +{ +} + +PMMetaObject* PMRainbow::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Rainbow", Base::metaObject( ), + createNewRainbow ); + s_pMetaObject->addProperty( + new PMRainbowProperty( "direction", &PMRainbow::setDirection, &PMRainbow::direction ) ); + s_pMetaObject->addProperty( + new PMRainbowProperty( "angle", &PMRainbow::setAngle, &PMRainbow::angle ) ); + s_pMetaObject->addProperty( + new PMRainbowProperty( "width", &PMRainbow::setWidth, &PMRainbow::width ) ); + s_pMetaObject->addProperty( + new PMRainbowProperty( "distance", &PMRainbow::setDistance, &PMRainbow::distance ) ); + s_pMetaObject->addProperty( + new PMRainbowProperty( "jitter", &PMRainbow::setJitter, &PMRainbow::jitter ) ); + s_pMetaObject->addProperty( + new PMRainbowProperty( "up", &PMRainbow::setUp, &PMRainbow::up ) ); + s_pMetaObject->addProperty( + new PMRainbowProperty( "arcAngle", &PMRainbow::setArcAngle, &PMRainbow::arcAngle ) ); + s_pMetaObject->addProperty( + new PMRainbowProperty( "falloffAngle", &PMRainbow::setFalloffAngle, &PMRainbow::falloffAngle ) ); + s_pMetaObject->addProperty( + new PMRainbowProperty( "directionEnabled", &PMRainbow::enableDirection, &PMRainbow::isDirectionEnabled ) ); + s_pMetaObject->addProperty( + new PMRainbowProperty( "angleEnabled", &PMRainbow::enableAngle, &PMRainbow::isAngleEnabled ) ); + s_pMetaObject->addProperty( + new PMRainbowProperty( "widthEnabled", &PMRainbow::enableWidth, &PMRainbow::isWidthEnabled ) ); + s_pMetaObject->addProperty( + new PMRainbowProperty( "distanceEnabled", &PMRainbow::enableDistance, &PMRainbow::isDistanceEnabled ) ); + s_pMetaObject->addProperty( + new PMRainbowProperty( "jitterEnabled", &PMRainbow::enableJitter, &PMRainbow::isJitterEnabled ) ); + s_pMetaObject->addProperty( + new PMRainbowProperty( "upEnabled", &PMRainbow::enableUp, &PMRainbow::isUpEnabled ) ); + s_pMetaObject->addProperty( + new PMRainbowProperty( "arcAngleEnabled", &PMRainbow::enableArcAngle, &PMRainbow::isArcAngleEnabled ) ); + s_pMetaObject->addProperty( + new PMRainbowProperty( "falloffAngleEnabled", &PMRainbow::enableFalloffAngle, &PMRainbow::isFalloffAngleEnabled ) ); + } + return s_pMetaObject; +} + +void PMRainbow::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMRainbow::description( ) const +{ + return i18n( "rainbow" ); +} + +void PMRainbow::serialize( QDomElement& e, QDomDocument& doc ) const +{ + Base::serialize( e, doc ); + e.setAttribute( "enable_direction", m_enableDirection ); + e.setAttribute( "enable_angle", m_enableAngle ); + e.setAttribute( "enable_width", m_enableWidth ); + e.setAttribute( "enable_distance", m_enableDistance ); + e.setAttribute( "enable_jitter", m_enableJitter ); + e.setAttribute( "enable_up", m_enableUp ); + e.setAttribute( "enable_arc_angle", m_enableArcAngle ); + e.setAttribute( "enable_falloff_angle", m_enableFalloffAngle ); + e.setAttribute( "direction", m_direction.serializeXML( ) ); + e.setAttribute( "angle", m_angle ); + e.setAttribute( "width", m_width ); + e.setAttribute( "distance", m_distance ); + e.setAttribute( "jitter", m_jitter ); + e.setAttribute( "up", m_up.serializeXML( ) ); + e.setAttribute( "arc_angle", m_arcAngle ); + e.setAttribute( "falloff_angle", m_falloffAngle ); +} + +void PMRainbow::readAttributes( const PMXMLHelper& h ) +{ + Base::readAttributes( h ); + m_enableDirection = h.boolAttribute( "enable_direction", false ); + m_enableAngle = h.boolAttribute( "enable_angle", false ); + m_enableWidth = h.boolAttribute( "enable_width", false ); + m_enableDistance = h.boolAttribute( "enable_distance", false ); + m_enableJitter = h.boolAttribute( "enable_jitter", false ); + m_enableUp = h.boolAttribute( "enable_up", false ); + m_enableArcAngle = h.boolAttribute( "enable_arc_angle", false ); + m_enableFalloffAngle = h.boolAttribute( "enable_falloff_angle", false ); + m_direction = h.vectorAttribute( "direction", directionDefault ); + m_angle = h.doubleAttribute( "angle", angleDefault ); + m_width = h.doubleAttribute( "width", widthDefault ); + m_distance = h.doubleAttribute( "distance", distanceDefault ); + m_jitter = h.doubleAttribute( "jitter", jitterDefault ); + m_up = h.vectorAttribute( "up", upDefault ); + m_arcAngle = h.doubleAttribute( "arc_angle", arcAngleDefault ); + m_falloffAngle = h.doubleAttribute( "falloff_angle", falloffAngleDefault ); +} + +void PMRainbow::setDirection( const PMVector& c ) +{ + if( c != m_direction ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMDirectionID, m_direction ); + m_direction = c; + } +} + +void PMRainbow::setAngle( double c ) +{ + if( c != m_angle ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAngleID, m_angle ); + m_angle = c; + } +} + +void PMRainbow::setWidth( double c ) +{ + if( c != m_width ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMWidthID, m_width ); + m_width = c; + } +} + +void PMRainbow::setDistance( double c ) +{ + if( c != m_distance ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMDistanceID, m_distance ); + m_distance = c; + } +} + +void PMRainbow::setJitter( double c ) +{ + if( c != m_jitter ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMJitterID, m_jitter ); + m_jitter = c; + } +} + +void PMRainbow::setUp( const PMVector& c ) +{ + if( c != m_up ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMUpID, m_up ); + m_up = c; + } +} + +void PMRainbow::setArcAngle( double c ) +{ + if( c != m_arcAngle ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMArcAngleID, m_arcAngle ); + m_arcAngle = c; + } +} + +void PMRainbow::setFalloffAngle( double c ) +{ + if( c != m_falloffAngle ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFalloffAngleID, m_falloffAngle ); + m_falloffAngle = c; + } +} + +void PMRainbow::enableDirection( bool c ) +{ + if( c != m_enableDirection ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableDirectionID, m_enableDirection ); + m_enableDirection = c; + } +} + +void PMRainbow::enableAngle( bool c ) +{ + if( c != m_enableAngle ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableAngleID, m_enableAngle ); + m_enableAngle = c; + } +} + +void PMRainbow::enableWidth( bool c ) +{ + if( c != m_enableWidth ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableWidthID, m_enableWidth ); + m_enableWidth = c; + } +} + +void PMRainbow::enableDistance( bool c ) +{ + if( c != m_enableDistance ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableDistanceID, m_enableDistance ); + m_enableDistance = c; + } +} + +void PMRainbow::enableJitter( bool c ) +{ + if( c != m_enableJitter ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableJitterID, m_enableJitter ); + m_enableJitter = c; + } +} + +void PMRainbow::enableUp( bool c ) +{ + if( c != m_enableUp ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableUpID, m_enableUp ); + m_enableUp = c; + } +} + +void PMRainbow::enableArcAngle( bool c ) +{ + if( c != m_enableArcAngle ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableArcAngleID, m_enableArcAngle ); + m_enableArcAngle = c; + } +} + +void PMRainbow::enableFalloffAngle( bool c ) +{ + if( c != m_enableFalloffAngle ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEnableFalloffAngleID, + m_enableFalloffAngle ); + m_enableFalloffAngle = c; + } +} + +PMDialogEditBase* PMRainbow::editWidget( QWidget* parent ) const +{ + return new PMRainbowEdit( parent ); +} + +void PMRainbow::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMDirectionID: + setDirection( data->vectorData( ) ); + break; + case PMAngleID: + setAngle( data->doubleData( ) ); + break; + case PMWidthID: + setWidth( data->doubleData( ) ); + break; + case PMDistanceID: + setDistance( data->doubleData( ) ); + break; + case PMJitterID: + setJitter( data->doubleData( ) ); + break; + case PMUpID: + setUp( data->vectorData( ) ); + break; + case PMArcAngleID: + setArcAngle( data->doubleData( ) ); + break; + case PMFalloffAngleID: + setFalloffAngle( data->doubleData( ) ); + break; + case PMEnableDirectionID: + enableDirection( data->boolData( ) ); + break; + case PMEnableAngleID: + enableAngle( data->boolData( ) ); + break; + case PMEnableWidthID: + enableWidth( data->boolData( ) ); + break; + case PMEnableDistanceID: + enableDistance( data->boolData( ) ); + break; + case PMEnableJitterID: + enableJitter( data->boolData( ) ); + break; + case PMEnableUpID: + enableUp( data->boolData( ) ); + break; + case PMEnableArcAngleID: + enableArcAngle( data->boolData( ) ); + break; + case PMEnableFalloffAngleID: + enableFalloffAngle( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMRainbow::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmrainbow.h b/kpovmodeler/pmrainbow.h new file mode 100644 index 00000000..0c95c459 --- /dev/null +++ b/kpovmodeler/pmrainbow.h @@ -0,0 +1,139 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMRAINBOW_H +#define PMRAINBOW_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebase.h" + +/** + * Class for povray rainbows + */ +class PMRainbow : public PMTextureBase +{ + typedef PMTextureBase Base; +public: + /** + * Creates an PMRainbow + */ + PMRainbow( PMPart* part ); + /** + * Copy constructor + */ + PMRainbow( const PMRainbow& r ); + /** + * Deletes the object + */ + virtual ~PMRainbow( ); + + /** */ + virtual PMObject* copy( ) const { return new PMRainbow( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMRainbowEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pmrainbow" ); } + + /** */ + virtual void restoreMemento( PMMemento* s ); + + PMVector direction( ) const { return m_direction; } + double angle( ) const { return m_angle; } + double width( ) const { return m_width; } + double distance( ) const { return m_distance; } + double jitter( ) const { return m_jitter; } + PMVector up( ) const { return m_up; } + double arcAngle( ) const { return m_arcAngle; } + double falloffAngle( ) const { return m_falloffAngle; } + bool isDirectionEnabled( ) const { return m_enableDirection; } + bool isAngleEnabled( ) const { return m_enableAngle; } + bool isWidthEnabled( ) const { return m_enableWidth; } + bool isDistanceEnabled( ) const { return m_enableDistance; } + bool isJitterEnabled( ) const { return m_enableJitter; } + bool isUpEnabled( ) const { return m_enableUp; } + bool isArcAngleEnabled( ) const { return m_enableArcAngle; } + bool isFalloffAngleEnabled( ) const { return m_enableFalloffAngle; } + + void setDirection( const PMVector& c ); + void setAngle( double c ); + void setWidth( double c ); + void setDistance( double c ); + void setJitter( double c ); + void setUp( const PMVector& c ); + void setArcAngle( double c ); + void setFalloffAngle( double c ); + void enableDirection( bool c ); + void enableAngle( bool c ); + void enableWidth( bool c ); + void enableDistance( bool c ); + void enableJitter( bool c ); + void enableUp( bool c ); + void enableArcAngle( bool c ); + void enableFalloffAngle( bool c ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMRainbowMementoID { PMDirectionID, PMAngleID, PMWidthID, + PMDistanceID, PMJitterID, PMUpID, PMArcAngleID, + PMFalloffAngleID, PMEnableDirectionID, + PMEnableAngleID, PMEnableWidthID, + PMEnableDistanceID, PMEnableJitterID, PMEnableUpID, + PMEnableArcAngleID, PMEnableFalloffAngleID }; + PMVector m_direction; + double m_angle; + double m_width; + double m_distance; + double m_jitter; + PMVector m_up; + double m_arcAngle; + double m_falloffAngle; + + bool m_enableDirection; + bool m_enableAngle; + bool m_enableWidth; + bool m_enableDistance; + bool m_enableJitter; + bool m_enableUp; + bool m_enableArcAngle; + bool m_enableFalloffAngle; + + static PMMetaObject* s_pMetaObject; +}; + + +#endif diff --git a/kpovmodeler/pmrainbowedit.cpp b/kpovmodeler/pmrainbowedit.cpp new file mode 100644 index 00000000..ff359a7e --- /dev/null +++ b/kpovmodeler/pmrainbowedit.cpp @@ -0,0 +1,278 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmrainbowedit.h" +#include "pmrainbow.h" +#include "pmlineedits.h" +#include "pmvectoredit.h" +#include "pmvector.h" +#include "pmmath.h" + +#include +#include +#include +#include +#include + + +PMRainbowEdit::PMRainbowEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMRainbowEdit::createTopWidgets( ) +{ + QHBoxLayout* hl; + QGridLayout* gl; + + Base::createTopWidgets( ); + + hl = new QHBoxLayout( topLayout( ) ); + m_pEnableDirectionEdit = new QCheckBox( i18n( "Direction:" ), this ); + m_pDirectionEdit = new PMVectorEdit( "x", "y", "z", this ); + hl->addWidget( m_pEnableDirectionEdit ); + hl->addWidget( m_pDirectionEdit ); + + hl = new QHBoxLayout( topLayout( ) ); + gl = new QGridLayout( hl, 4, 2 ); + m_pEnableAngleEdit = new QCheckBox( i18n( "Angle:" ), this ); + m_pAngleEdit = new PMFloatEdit( this ); + gl->addWidget( m_pEnableAngleEdit, 0, 0 ); + gl->addWidget( m_pAngleEdit, 0, 1 ); + + m_pEnableWidthEdit = new QCheckBox( i18n( "Width:" ), this ); + m_pWidthEdit = new PMFloatEdit( this ); + gl->addWidget( m_pEnableWidthEdit, 1, 0 ); + gl->addWidget( m_pWidthEdit, 1, 1 ); + + m_pEnableDistanceEdit = new QCheckBox( i18n( "Distance:" ), this ); + m_pDistanceEdit = new PMFloatEdit( this ); + gl->addWidget( m_pEnableDistanceEdit, 2, 0 ); + gl->addWidget( m_pDistanceEdit, 2, 1 ); + + m_pEnableJitterEdit = new QCheckBox( i18n( "Jitter:" ), this ); + m_pJitterEdit = new PMFloatEdit( this ); + gl->addWidget( m_pEnableJitterEdit, 3, 0 ); + gl->addWidget( m_pJitterEdit, 3, 1 ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + m_pEnableUpEdit = new QCheckBox( i18n( "Up:" ), this ); + m_pUpEdit = new PMVectorEdit( "x", "y", "z", this ); + hl->addWidget( m_pEnableUpEdit ); + hl->addWidget( m_pUpEdit ); + + hl = new QHBoxLayout( topLayout( ) ); + gl = new QGridLayout( hl, 2, 2 ); + m_pEnableArcAngleEdit = new QCheckBox( i18n( "Arc angle:" ), this ); + m_pArcAngleEdit = new PMFloatEdit( this ); + m_pArcAngleEdit->setValidation( true, 0, true, 360 ); + gl->addWidget( m_pEnableArcAngleEdit, 0, 0 ); + gl->addWidget( m_pArcAngleEdit, 0, 1 ); + m_pEnableFalloffAngleEdit = new QCheckBox( i18n( "Falloff angle:" ), this ); + m_pFalloffAngleEdit = new PMFloatEdit( this ); + m_pFalloffAngleEdit->setValidation( true, 0, true, 360 ); + gl->addWidget( m_pEnableFalloffAngleEdit, 1, 0 ); + gl->addWidget( m_pFalloffAngleEdit, 1, 1 ); + hl->addStretch( 1 ); + + connect( m_pDirectionEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pAngleEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pWidthEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pDistanceEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pJitterEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pUpEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pArcAngleEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pFalloffAngleEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pEnableDirectionEdit, SIGNAL( clicked( ) ), SLOT( slotDirectionClicked( ) ) ); + connect( m_pEnableAngleEdit, SIGNAL( clicked( ) ), SLOT( slotAngleClicked( ) ) ); + connect( m_pEnableWidthEdit, SIGNAL( clicked( ) ), SLOT( slotWidthClicked( ) ) ); + connect( m_pEnableDistanceEdit, SIGNAL( clicked( ) ), SLOT( slotDistanceClicked( ) ) ); + connect( m_pEnableJitterEdit, SIGNAL( clicked( ) ), SLOT( slotJitterClicked( ) ) ); + connect( m_pEnableUpEdit, SIGNAL( clicked( ) ), SLOT( slotUpClicked( ) ) ); + connect( m_pEnableArcAngleEdit, SIGNAL( clicked( ) ), SLOT( slotArcAngleClicked( ) ) ); + connect( m_pEnableFalloffAngleEdit, SIGNAL( clicked( ) ), SLOT( slotFalloffAngleClicked( ) ) ); +} + +void PMRainbowEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Rainbow" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMRainbow* ) o; + + m_pDirectionEdit->setVector( m_pDisplayedObject->direction( ) ); + m_pDirectionEdit->setReadOnly( readOnly ); + m_pAngleEdit->setValue( m_pDisplayedObject->angle( ) ); + m_pAngleEdit->setReadOnly( readOnly ); + m_pWidthEdit->setValue( m_pDisplayedObject->width( ) ); + m_pWidthEdit->setReadOnly( readOnly ); + m_pDistanceEdit->setValue( m_pDisplayedObject->distance( ) ); + m_pDistanceEdit->setReadOnly( readOnly ); + m_pJitterEdit->setValue( m_pDisplayedObject->jitter( ) ); + m_pJitterEdit->setReadOnly( readOnly ); + m_pUpEdit->setVector( m_pDisplayedObject->up( ) ); + m_pUpEdit->setReadOnly( readOnly ); + m_pArcAngleEdit->setValue( m_pDisplayedObject->arcAngle( ) ); + m_pArcAngleEdit->setReadOnly( readOnly ); + m_pFalloffAngleEdit->setValue( m_pDisplayedObject->falloffAngle( ) ); + m_pFalloffAngleEdit->setReadOnly( readOnly ); + m_pEnableDirectionEdit->setChecked( m_pDisplayedObject->isDirectionEnabled( ) ); + m_pEnableDirectionEdit->setEnabled( !readOnly ); + m_pEnableAngleEdit->setChecked( m_pDisplayedObject->isAngleEnabled( ) ); + m_pEnableAngleEdit->setEnabled( !readOnly ); + m_pEnableWidthEdit->setChecked( m_pDisplayedObject->isWidthEnabled( ) ); + m_pEnableWidthEdit->setEnabled( !readOnly ); + m_pEnableDistanceEdit->setChecked( m_pDisplayedObject->isDistanceEnabled( ) ); + m_pEnableDistanceEdit->setEnabled( !readOnly ); + m_pEnableJitterEdit->setChecked( m_pDisplayedObject->isJitterEnabled( ) ); + m_pEnableJitterEdit->setEnabled( !readOnly ); + m_pEnableUpEdit->setChecked( m_pDisplayedObject->isUpEnabled( ) ); + m_pEnableUpEdit->setEnabled( !readOnly ); + m_pEnableArcAngleEdit->setChecked( m_pDisplayedObject->isArcAngleEnabled( ) ); + m_pEnableArcAngleEdit->setEnabled( !readOnly ); + m_pEnableFalloffAngleEdit->setChecked( m_pDisplayedObject->isFalloffAngleEnabled( ) ); + m_pEnableFalloffAngleEdit->setEnabled( !readOnly ); + slotDirectionClicked( ); + slotAngleClicked( ); + slotWidthClicked( ); + slotDistanceClicked( ); + slotJitterClicked( ); + slotUpClicked( ); + slotArcAngleClicked( ); + slotFalloffAngleClicked( ); + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMRainbowEdit: Can't display object\n"; +} + +void PMRainbowEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setDirection( m_pDirectionEdit->vector( ) ); + m_pDisplayedObject->setAngle( m_pAngleEdit->value( ) ); + m_pDisplayedObject->setWidth( m_pWidthEdit->value( ) ); + m_pDisplayedObject->setDistance( m_pDistanceEdit->value( ) ); + m_pDisplayedObject->setJitter( m_pJitterEdit->value( ) ); + m_pDisplayedObject->setUp( m_pUpEdit->vector( ) ); + m_pDisplayedObject->setArcAngle( m_pArcAngleEdit->value( ) ); + m_pDisplayedObject->setFalloffAngle( m_pFalloffAngleEdit->value( ) ); + m_pDisplayedObject->enableDirection( m_pEnableDirectionEdit->isChecked( ) ); + m_pDisplayedObject->enableAngle( m_pEnableAngleEdit->isChecked( ) ); + m_pDisplayedObject->enableWidth( m_pEnableWidthEdit->isChecked( ) ); + m_pDisplayedObject->enableDistance( m_pEnableDistanceEdit->isChecked( ) ); + m_pDisplayedObject->enableJitter( m_pEnableJitterEdit->isChecked( ) ); + m_pDisplayedObject->enableUp( m_pEnableUpEdit->isChecked( ) ); + m_pDisplayedObject->enableArcAngle( m_pEnableArcAngleEdit->isChecked( ) ); + m_pDisplayedObject->enableFalloffAngle( m_pEnableFalloffAngleEdit->isChecked( ) ); + } +} + +bool PMRainbowEdit::isDataValid( ) +{ + double f_angle; + + if( !m_pDirectionEdit->isDataValid( ) ) return false; + if( !m_pAngleEdit->isDataValid( ) ) return false; + if( !m_pWidthEdit->isDataValid( ) ) return false; + if( !m_pDistanceEdit->isDataValid( ) ) return false; + if( !m_pJitterEdit->isDataValid( ) ) return false; + if( !m_pUpEdit->isDataValid( ) ) return false; + if( !m_pArcAngleEdit->isDataValid( ) ) return false; + if( !m_pFalloffAngleEdit->isDataValid( ) ) return false; + if( m_pFalloffAngleEdit->value( ) > m_pArcAngleEdit->value( ) ) + { + KMessageBox::error( this, i18n( "Arc angle is smaller than falloff angle in rainbow." ), + i18n( "Error" ) ); + return false; + } + if( approxZero( fabs( PMVector::dot( m_pDirectionEdit->vector( ), m_pDirectionEdit->vector( ) ) ) ) ) + { + KMessageBox::error( this, i18n( "Direction vector is zero." ), + i18n( "Error" ) ); + return false; + } + if( approxZero( fabs( PMVector::dot( m_pUpEdit->vector( ), m_pUpEdit->vector( ) ) ) ) ) + { + KMessageBox::error( this, i18n( "Up vector is zero." ), + i18n( "Error" ) ); + return false; + } + f_angle = fabs( rad2Deg( PMVector::angle( m_pDirectionEdit->vector( ), m_pUpEdit->vector( ) ) ) ); + if( f_angle == 0.0 || f_angle == 180.0 ) + { + KMessageBox::error( this, i18n( "Direction and up vectors are co-linear." ), + i18n( "Error" ) ); + return false; + } + return Base::isDataValid( ); +} + +void PMRainbowEdit::slotDirectionClicked( ) +{ + m_pDirectionEdit->setEnabled( m_pEnableDirectionEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMRainbowEdit::slotAngleClicked( ) +{ + m_pAngleEdit->setEnabled( m_pEnableAngleEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMRainbowEdit::slotWidthClicked( ) +{ + m_pWidthEdit->setEnabled( m_pEnableWidthEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMRainbowEdit::slotDistanceClicked( ) +{ + m_pDistanceEdit->setEnabled( m_pEnableDistanceEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMRainbowEdit::slotJitterClicked( ) +{ + m_pJitterEdit->setEnabled( m_pEnableJitterEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMRainbowEdit::slotUpClicked( ) +{ + m_pUpEdit->setEnabled( m_pEnableUpEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMRainbowEdit::slotArcAngleClicked( ) +{ + m_pArcAngleEdit->setEnabled( m_pEnableArcAngleEdit->isChecked( ) ); + emit dataChanged( ); +} + +void PMRainbowEdit::slotFalloffAngleClicked( ) +{ + m_pFalloffAngleEdit->setEnabled( m_pEnableFalloffAngleEdit->isChecked( ) ); + emit dataChanged( ); +} + +#include "pmrainbowedit.moc" diff --git a/kpovmodeler/pmrainbowedit.h b/kpovmodeler/pmrainbowedit.h new file mode 100644 index 00000000..c5d4b714 --- /dev/null +++ b/kpovmodeler/pmrainbowedit.h @@ -0,0 +1,90 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMRAINBOWEDIT_H +#define PMRAINBOWEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebaseedit.h" + +class PMRainbow; +class PMFloatEdit; +class PMVectorEdit; +class QCheckBox; +class QLabel; + +/** + * Dialog edit class for @ref PMRainbow + */ +class PMRainbowEdit : public PMTextureBaseEdit +{ + Q_OBJECT + typedef PMTextureBaseEdit Base; +public: + /** + * Creates a PMRainbowEdit with parent and name + */ + PMRainbowEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + void slotDirectionClicked( ); + void slotAngleClicked( ); + void slotWidthClicked( ); + void slotDistanceClicked( ); + void slotJitterClicked( ); + void slotUpClicked( ); + void slotArcAngleClicked( ); + void slotFalloffAngleClicked( ); + +private: + PMRainbow* m_pDisplayedObject; + PMVectorEdit* m_pDirectionEdit; + PMFloatEdit* m_pAngleEdit; + PMFloatEdit* m_pWidthEdit; + PMFloatEdit* m_pDistanceEdit; + PMFloatEdit* m_pJitterEdit; + PMVectorEdit* m_pUpEdit; + PMFloatEdit* m_pArcAngleEdit; + PMFloatEdit* m_pFalloffAngleEdit; + QCheckBox* m_pEnableDirectionEdit; + QCheckBox* m_pEnableAngleEdit; + QCheckBox* m_pEnableWidthEdit; + QCheckBox* m_pEnableDistanceEdit; + QCheckBox* m_pEnableJitterEdit; + QCheckBox* m_pEnableUpEdit; + QCheckBox* m_pEnableArcAngleEdit; + QCheckBox* m_pEnableFalloffAngleEdit; +}; + + +#endif diff --git a/kpovmodeler/pmraw.cpp b/kpovmodeler/pmraw.cpp new file mode 100644 index 00000000..a2d44784 --- /dev/null +++ b/kpovmodeler/pmraw.cpp @@ -0,0 +1,135 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmraw.h" +#include "pmxmlhelper.h" + +#include "pmrawedit.h" +#include "pmmemento.h" + +#include +#include + +PMDefinePropertyClass( PMRaw, PMRawProperty ); + +PMMetaObject* PMRaw::s_pMetaObject = 0; +PMObject* createNewRaw( PMPart* part ) +{ + return new PMRaw( part ); +} + +PMRaw::PMRaw( PMPart* part ) + : Base( part ) +{ +} + +PMRaw::PMRaw( const PMRaw& r ) + : Base( r ) +{ + m_code = r.m_code; +} + +PMRaw::PMRaw( PMPart* part, const QString& t ) + : Base( part ) +{ + m_code = t; +} + +PMRaw::~PMRaw( ) +{ +} + +QString PMRaw::description( ) const +{ + return i18n( "raw povray" ); +} + +void PMRaw::setCode( const QString& code ) +{ + if( code != m_code ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCodeID, m_code ); + m_code = code; + } +} + +PMMetaObject* PMRaw::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Raw", Base::metaObject( ), + createNewRaw ); + s_pMetaObject->addProperty( + new PMRawProperty( "code", &PMRaw::setCode, &PMRaw::code ) ); + } + return s_pMetaObject; +} + +void PMRaw::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMRaw::serialize( QDomElement& e, QDomDocument& doc ) const +{ + QDomText t = doc.createTextNode( m_code ); + e.appendChild( t ); +} + +void PMRaw::readAttributes( const PMXMLHelper& h ) +{ + QDomNode e = h.element( ).firstChild( ); + if( e.isText( ) ) + m_code = e.toText( ).data( ); +} + +PMDialogEditBase* PMRaw::editWidget( QWidget* parent ) const +{ + return new PMRawEdit( parent ); +} + +void PMRaw::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMCodeID: + setCode( data->stringData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMRaw::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + diff --git a/kpovmodeler/pmraw.h b/kpovmodeler/pmraw.h new file mode 100644 index 00000000..2ba888bc --- /dev/null +++ b/kpovmodeler/pmraw.h @@ -0,0 +1,90 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMRAW_H +#define PMRAW_H + +#include "pmnamedobject.h" +#include + + +/** + * Class for raw povray code + */ +class PMRaw : public PMNamedObject +{ + typedef PMNamedObject Base; +public: + /** + * Creates an empty raw povray object + */ + PMRaw( PMPart* part ); + /** + * Copy constructor + */ + PMRaw( const PMRaw& r ); + /** + * Creates a raw povray object with text t + */ + PMRaw( PMPart* part, const QString& t ); + /** + * Deletes the raw povray object + */ + ~PMRaw( ); + + /** + * Sets the povray code + */ + void setCode( const QString& text ); + /** + * Returns the raw povray code + */ + QString code( ) const { return m_code; } + + /** */ + virtual PMObject* copy( ) const { return new PMRaw( *this ); } + /** */ + virtual QString description( ) const; + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pmraw" ); } + /** */ + virtual void restoreMemento( PMMemento* s ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMRawMementoID { PMCodeID }; + QString m_code; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmrawedit.cpp b/kpovmodeler/pmrawedit.cpp new file mode 100644 index 00000000..81d752d2 --- /dev/null +++ b/kpovmodeler/pmrawedit.cpp @@ -0,0 +1,79 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmrawedit.h" +#include "pmraw.h" + +#include +#include +#include +#include +#include + +PMRawEdit::PMRawEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMRawEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + topLayout( )->addWidget( new QLabel( i18n( "Povray code:" ), this ) ); + m_pEdit = new QMultiLineEdit( this ); +#if ( QT_VERSION >= 300 ) + m_pEdit->setTextFormat( Qt::PlainText ); + m_pEdit->setWordWrap( QTextEdit::NoWrap ); +#endif + m_pEdit->setFont( KGlobalSettings::fixedFont( ) ); + topLayout( )->addWidget( m_pEdit, 2 ); + + connect( m_pEdit, SIGNAL( textChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMRawEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Raw" ) ) + { + m_pDisplayedObject = ( PMRaw* ) o; + m_pEdit->setText( m_pDisplayedObject->code( ) ); + + m_pEdit->setReadOnly( o->isReadOnly( ) ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMRawEdit: Can't display object\n"; +} + +void PMRawEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setCode( m_pEdit->text( ) ); + } +} + +bool PMRawEdit::isDataValid( ) +{ + return Base::isDataValid( ); +} + +#include "pmrawedit.moc" diff --git a/kpovmodeler/pmrawedit.h b/kpovmodeler/pmrawedit.h new file mode 100644 index 00000000..911ceb4e --- /dev/null +++ b/kpovmodeler/pmrawedit.h @@ -0,0 +1,62 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMRAWEDIT_H +#define PMRAWEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmnamedobjectedit.h" + +class PMRaw; +class QMultiLineEdit; + +/** + * Dialog edit class for @ref PMRaw. + */ +class PMRawEdit : public PMNamedObjectEdit +{ + Q_OBJECT + typedef PMNamedObjectEdit Base; +public: + /** + * Creates a PMRawEdit with parent and name + */ + PMRawEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMRaw* m_pDisplayedObject; + QMultiLineEdit* m_pEdit; +}; + + +#endif diff --git a/kpovmodeler/pmrecursiveobjectiterator.cpp b/kpovmodeler/pmrecursiveobjectiterator.cpp new file mode 100644 index 00000000..eeacfaa6 --- /dev/null +++ b/kpovmodeler/pmrecursiveobjectiterator.cpp @@ -0,0 +1,62 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmobject.h" +#include "pmrecursiveobjectiterator.h" + +PMRecursiveObjectIterator::PMRecursiveObjectIterator( PMObject* obj ) +{ + m_pObject = obj; + m_pCurrent = obj; +} + +PMObject* PMRecursiveObjectIterator::operator++( ) +{ + if( m_pCurrent ) + { + if( m_pCurrent->firstChild( ) ) + m_pCurrent = m_pCurrent->firstChild( ); + else if( m_pCurrent == m_pObject ) + m_pCurrent = 0; + else if( m_pCurrent->nextSibling( ) ) + m_pCurrent = m_pCurrent->nextSibling( ); + else + { + bool stop = false; + do + { + m_pCurrent = m_pCurrent->parent( ); + if( !m_pCurrent ) + stop = true; + else if( m_pCurrent == m_pObject ) + { + // finished + stop = true; + m_pCurrent = 0; + } + else if( m_pCurrent->nextSibling( ) ) + { + m_pCurrent = m_pCurrent->nextSibling( ); + stop = true; + } + } + while( !stop ); + } + } + + return m_pCurrent; +} diff --git a/kpovmodeler/pmrecursiveobjectiterator.h b/kpovmodeler/pmrecursiveobjectiterator.h new file mode 100644 index 00000000..aafeaad3 --- /dev/null +++ b/kpovmodeler/pmrecursiveobjectiterator.h @@ -0,0 +1,49 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMRECURSIVEOBJECTITERATOR_H +#define PMRECURSIVEOBJECTITERATOR_H + +class PMObject; + +/** + * Iterator that + */ +class PMRecursiveObjectIterator +{ +public: + /** + * Creates an iterator that iterates recursively over the childs + * of obj. + */ + PMRecursiveObjectIterator( PMObject* obj ); + /** + * Makes the next object the current one and returns it. + */ + PMObject* operator++( ); + /** + * Returns the current object. + */ + PMObject* current( ) const { return m_pCurrent; } + +private: + PMObject* m_pObject; + PMObject* m_pCurrent; +}; + +#endif diff --git a/kpovmodeler/pmrendermanager.cpp b/kpovmodeler/pmrendermanager.cpp new file mode 100644 index 00000000..664f0fd9 --- /dev/null +++ b/kpovmodeler/pmrendermanager.cpp @@ -0,0 +1,1647 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +// conflicting types for INT32 in qt and glx +#ifndef QT_CLEAN_NAMESPACE +#define QT_CLEAN_NAMESPACE +#endif + +#include "pmrendermanager.h" +#include "pmviewstructure.h" +#include "pmobject.h" +#include "pmdeclare.h" +#include "pmcamera.h" +#include "pmquickcolor.h" +#include "pmdefaults.h" +#include "pmgraphicalobject.h" +#include "pmmath.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include // Only needed for gluPerspective + +#include "pmglview.h" + +const GLdouble dA = 0.75; +const GLdouble dB = 0.15; + +const GLdouble viewVolumeZ = 1e5; + +// Size has to be controlPointSize (see pmglview.h) +const GLubyte PointBitmap[7] = { 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE }; +const GLubyte CrossBitmap[7] = { 0x10, 0x10, 0x10, 0xFE, 0x10, 0x10, 0x10 }; + + +const int activeTimeAfterRendering = 2; +const int maxEventTime = 0; +const int maxSubdivisions = 32; +const double subdivisionDistance = 0.05; + + +PMRenderManager* PMRenderManager::s_pManager = 0; +KStaticDeleter PMRenderManager::s_staticDeleter; + +bool PMRenderManager::s_hasOpenGL = true; +bool PMRenderManager::s_hasOpenGLChecked = false; + +PMRenderManager* PMRenderManager::theManager( ) +{ + if( !s_pManager ) + s_staticDeleter.setObject( s_pManager, new PMRenderManager( ) ); + return s_pManager; +} + +PMRenderManager::PMRenderManager( ) + : QObject( qApp ) +{ + int i; + + m_bStartTask = false; + m_bStopTask = false; + m_bTaskIsRunning = false; + + m_graphicalObjectColor[0] = c_defaultGraphicalObjectColor0; + m_graphicalObjectColor[1] = c_defaultGraphicalObjectColor1; + m_textureColor[0] = c_defaultTextureColor0; + m_textureColor[1] = c_defaultTextureColor1; + m_axesColor[0] = c_defaultAxesColorX; + m_axesColor[1] = c_defaultAxesColorY; + m_axesColor[2] = c_defaultAxesColorZ; + m_controlPointColor[0] = c_defaultControlPointColor0; + m_controlPointColor[1] = c_defaultControlPointColor1; + m_backgroundColor = c_defaultBackgroundColor; + m_fieldOfViewColor = c_defaultFieldOfViewColor; + m_highDetailCameraView = c_defaultHighDetailCameraView; + m_nMaxRenderedLines = 1000; + m_gridDistance = c_defaultGridDistance; + m_gridColor = c_defaultGridColor; + m_axesViewStructureCreated = false; + m_currentVisibility = 0; + + m_renderTasks.setAutoDelete( true ); + m_matrixStack.setAutoDelete( true ); + m_quickColors.setAutoDelete( true ); + + m_nViews = 0; + + m_subdivisionViewStructure = PMViewStructure( maxSubdivisions + 1, + maxSubdivisions ); + PMLineArray& lines = m_subdivisionViewStructure.lines( ); + for( i = 0; i < maxSubdivisions; i++ ) + lines[i] = PMLine( i, i+1 ); +} + +PMRenderManager::~PMRenderManager( ) +{ + s_pManager = 0; +} + +void PMRenderManager::addView( PMGLView* view, PMObject* active, PMObject* top, + PMControlPointList* controlPoints, + double aspectRatio, int visibilityLevel, + bool graphicalChange ) +{ + PMRenderTaskListIterator it( m_renderTasks ); + PMRenderTask* task = 0; + bool restart = false; + bool first = true; + + for( ; it.current( ) && !task; ++it ) + { + if( it.current( )->view( ) == view ) + task = it.current( ); + else + first = false; + } + + if( task ) + { + if( first ) + restart = true; + else if( graphicalChange ) + { + m_renderTasks.findRef( task ); + m_renderTasks.take( ); + m_renderTasks.prepend( task ); + restart = true; + } + task->setActiveObject( active ); + task->setTopLevelObject( top ); + task->setControlPoints( controlPoints ); + task->setAspectRatio( aspectRatio ); + task->setVisibilityLevel( visibilityLevel ); + } + else + { + task = new PMRenderTask( view, active, top, controlPoints, aspectRatio, + visibilityLevel ); + if( graphicalChange ) + { + m_renderTasks.prepend( task ); + restart = true; + } + else + { + m_renderTasks.append( task ); + if( m_renderTasks.count( ) == 1 ) + restart = true; + } + } + if( restart ) + restartRendering( ); +} + +void PMRenderManager::removeView( PMGLView* view ) +{ + PMRenderTaskListIterator it( m_renderTasks ); + PMRenderTask* task = 0; + bool restart = false; + + for( ; it.current( ) && !task; ++it ) + if( it.current( )->view( ) == view ) + task = it.current( ); + + if( task ) + { + if( task == m_renderTasks.first( ) ) + { + restart = true; + if( m_bTaskIsRunning ) + emit renderingFinished( task->view( ) ); + } + m_renderTasks.removeRef( task ); + } + + if( restart ) + restartRendering( ); +} + +bool PMRenderManager::containsTask( PMGLView* view ) const +{ + PMRenderTaskListIterator it( m_renderTasks ); + bool contains = false; + + for( ; it.current( ) && !contains; ++it ) + if( it.current( )->view( ) == view ) + contains = true; + return contains; +} + +QColor PMRenderManager::controlPointColor( int i ) const +{ + if( ( i >= 0 ) && ( i <= 1 ) ) + return m_controlPointColor[i]; + return QColor( 0, 0, 0 ); +} + +void PMRenderManager::setControlPointColor( int i, const QColor& c ) +{ + if( ( i >= 0 ) && ( i <= 1 ) ) + m_controlPointColor[i] = c; +} + +QColor PMRenderManager::graphicalObjectColor( int i ) const +{ + if( ( i >= 0 ) && ( i <= 1 ) ) + return m_graphicalObjectColor[i]; + return QColor( 0, 0, 0 ); +} + +void PMRenderManager::setGraphicalObjectColor( int i, const QColor& c ) +{ + if( ( i >= 0 ) && ( i <= 1 ) ) + m_graphicalObjectColor[i] = c; +} + +QColor PMRenderManager::axesColor( int i ) const +{ + if( ( i >= 0 ) && ( i <= 2 ) ) + return m_axesColor[i]; + return QColor( 0, 0, 0 ); +} + +void PMRenderManager::setAxesColor( int i, const QColor& c ) +{ + if( ( i >= 0 ) && ( i <= 2 ) ) + m_axesColor[i] = c; +} + +void PMRenderManager::setGridDistance( int d ) +{ + if( d >= 20 ) + m_gridDistance = d; +} + +void PMRenderManager::restartRendering( ) +{ + if( !m_bTaskIsRunning && !m_bStartTask ) + startTimer( 0 ); + + m_bStartTask = true; + m_bStopTask = false; +} + +void PMRenderManager::slotStopRendering( ) +{ + m_bStopTask = true; + m_bStartTask = false; + + if( m_bTaskIsRunning ) + if( m_pCurrentTask ) + emit renderingFinished( m_pCurrentTask->view( ) ); + m_renderTasks.clear( ); +} + +void PMRenderManager::timerEvent( QTimerEvent* ) +{ + killTimers( ); + renderTask( ); +} + +void PMRenderManager::renderTask( ) +{ + m_bTaskIsRunning = true; + emit renderingStarted( ); + + int r, g, b; + bool disableView = false; + + while( m_bStartTask && !m_bStopTask ) + { + m_bStartTask = false; + + // render the views sequential + while( m_renderTasks.first( ) && !m_bStopTask && !m_bStartTask ) + { + // reset the member variables for rendering + m_pCurrentTask = m_renderTasks.first( ); + m_pCurrentGlView = m_pCurrentTask->view( ); + emit renderingStarted( m_pCurrentGlView ); + + m_renderedLines = 0; + m_selected = false; + m_pDeselectObject = 0; + m_matrixStack.clear( ); + m_quickColorObjects.clear( ); + m_quickColors.clear( ); + m_currentColor = m_graphicalObjectColor[0]; + m_specialCameraMode = false; + m_currentVisibility = 0; + m_visibilityStack.clear( ); + + if( m_bStopTask || m_bStartTask ) + break; + m_pCurrentGlView->makeCurrent( ); + + m_backgroundColor.rgb( &r, &g, &b ); + glClearColor( r/255.0, g/255.0, b/255.0, 1.0 ); + glPointSize( controlPointSize ); + glEnable( GL_DEPTH_TEST ); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + + glViewport( 0, 0, ( GLint ) m_pCurrentGlView->width( ), + ( GLint ) m_pCurrentGlView->height( ) ); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + disableView = false; + if( m_pCurrentGlView->type( ) == PMGLView::PMViewCamera ) + { + if( m_pCurrentGlView->camera( ) ) + { + if( m_pCurrentGlView->camera( )->cameraType( ) + == PMCamera::Omnimax ) + disableView = true; + } + else + disableView = true; + } + + if( !disableView ) + setProjection( ); + + glLoadIdentity( ); + + glDisable( GL_DEPTH_TEST ); + if( m_pCurrentGlView->type( ) == PMGLView::PMViewCamera ) + renderFieldOfView( ); + else + renderGrid( ); + renderDescription( ); + glEnable( GL_DEPTH_TEST ); + + if( !disableView ) + { + renderAxes( ); + + renderObject( m_pCurrentTask->topLevelObject( ) ); + if( !m_bStopTask && ! m_bStartTask ) + renderControlPoints( ); + } + + if( !m_bStopTask && ! m_bStartTask ) + { + glXWaitX( ); + emit aboutToUpdate( m_pCurrentGlView ); + if( m_bStopTask || m_bStartTask ) + break; + glXWaitX( ); + m_pCurrentGlView->swapBuffers( ); + glFinish( ); + glXWaitGL( ); + emit renderingFinished( m_pCurrentGlView ); + if( m_bStopTask || m_bStartTask ) + break; + qApp->processEvents( maxEventTime ); + if( m_bStopTask || m_bStartTask ) + break; + m_renderTasks.removeFirst( ); + } + } + } + + emit renderingFinished( ); + + m_bStopTask = false; + m_bStartTask = false; + m_bTaskIsRunning = false; +} + +void PMRenderManager::renderObject( PMObject* objectToRender ) +{ + bool children = false; + PMGraphicalObject* go = 0; + + m_objectToRenderStack.append( objectToRender ); + + if( objectToRender->isA( "GraphicalObject" ) ) + { + go = ( PMGraphicalObject* ) objectToRender; + m_visibilityStack.push( m_currentVisibility ); + if( go->isVisibilityLevelRelative( ) ) + m_currentVisibility += go->visibilityLevel( ); + else + m_currentVisibility = go->visibilityLevel( ); + } + + if( !m_selected ) + { + if( objectToRender->isSelected( ) ) + { + m_selected = true; + m_pDeselectObject = objectToRender; + if( objectToRender->hasTransformationMatrix( ) ) + if( objectToRender->parent( ) ) + m_pDeselectObject = objectToRender->parent( ); + } + } + + if( ( m_pCurrentGlView->type( ) != PMGLView::PMViewCamera ) + || ( objectToRender != ( PMObject* ) ( m_pCurrentGlView->camera( ) ) ) ) + { + PMObject* obj = 0; + + children = objectToRender->lastChild( ) || objectToRender->linkedObject( ); + if( children ) + { + bool stop; + + PMMatrix* matrix; + if( m_specialCameraMode ) + matrix = new PMMatrix( m_viewTransformation ); + else + matrix = new PMMatrix( PMMatrix::modelviewMatrix( ) ); + m_matrixStack.push( matrix ); + + // render the children and the linked object + obj = objectToRender->lastChild( ); + while( obj && !m_bStopTask && !m_bStartTask ) + { + if( !obj->isA( "Declare" ) ) + renderObject( obj ); + if( !m_bStopTask && !m_bStartTask ) + { + do + { + // Do not render declares + obj = obj->prevSibling( ); + if( !obj ) + stop = true; + else + stop = !obj->isA( "Declare" ); + } + while( !stop ); + } + } + if( !m_bStopTask && !m_bStartTask ) + { + obj = objectToRender->linkedObject( ); + if( obj ) + renderObject( obj ); + } + } + + + if( !m_bStopTask && !m_bStartTask ) + { + // children of the object are rendered + // render the object + + if( objectToRender == m_pCurrentTask->activeObject( ) ) + { + if( m_specialCameraMode ) + m_controlPointTransformation = m_viewTransformation; + else + m_controlPointTransformation = PMMatrix::modelviewMatrix( ); + } + + if( objectToRender->type( ) == "QuickColor" ) + { + PMQuickColor* qc = ( PMQuickColor* ) objectToRender; + PMObjectListIterator it( m_objectToRenderStack ); + bool pofound = false; + it.toLast( ); + + while( it.current( ) && !pofound ) + { + if( it.current( )->isA( "GraphicalObject" ) ) + pofound = true; + else + --it; + } + if( pofound ) + { + if( m_quickColorObjects.top( ) != it.current( ) ) + { + m_quickColorObjects.push( it.current( ) ); + m_quickColors.push( new QColor( m_currentColor ) ); + m_currentColor = qc->color( ).toQColor( ); + } + } + } + + PMViewStructure* vs = objectToRender->viewStructure( ); + if( objectToRender->hasTransformationMatrix( ) || vs ) + { + // object has transformation or view structure + if( vs ) + { + if( ( m_currentVisibility <= m_pCurrentTask->visibilityLevel( ) ) + || ( objectToRender == m_pCurrentTask->activeObject( ) ) ) + { + // render the view structure. + // call qApp->processEvents( ) each m_nMaxRenderedLines rendered + // lines + if( m_selected ) + setGLColor( m_graphicalObjectColor[ 1 ] ); + else + setGLColor( m_currentColor ); + + renderViewStructure( *vs ); + } + } + else if( objectToRender->hasTransformationMatrix( ) ) + { + if( m_specialCameraMode ) + m_viewTransformation = m_viewTransformation * objectToRender->transformationMatrix( ); + else + glMultMatrixd( objectToRender->transformationMatrix( ).data( ) ); + } + } + // end rendering + } + } + if( !m_bStopTask && !m_bStartTask ) + { + if( children ) + { + PMMatrix* matrix = m_matrixStack.pop( ); + + if( matrix ) + { + if( m_specialCameraMode ) + m_viewTransformation = (*matrix); + else + glLoadMatrixd( matrix->data( ) ); + delete matrix; + matrix = 0; + } + } + if( m_selected ) + { + if( m_pDeselectObject == objectToRender ) + { + m_selected = false; + m_pDeselectObject = 0; + } + } + if( m_quickColorObjects.top( ) == objectToRender ) + { + m_quickColorObjects.pop( ); + QColor* col = m_quickColors.pop( ); + if( col ) + { + m_currentColor = *col; + delete col; + col = 0; + } + } + } + + if( go ) + m_currentVisibility = m_visibilityStack.pop( ); + + m_objectToRenderStack.removeLast( ); +} + +void PMRenderManager::renderViewStructure( PMViewStructure& vs ) +{ + if( m_specialCameraMode ) + { + PMPointArray points = vs.points( ); + points.detach( ); + transformProjection( points.data( ), points.size( ), + m_pCurrentGlView->camera( ) ); + + if( m_highDetailCameraView ) + { + // subdivide line + PMLineArray& lines = vs.lines( ); + PMPointArray& utPoints = vs.points( ); + int numLines = lines.size( ); + PMPointArray& sdPoints = m_subdivisionViewStructure.points( ); + PMLineArray& sdLines = m_subdivisionViewStructure.lines( ); + int i, li, sd; + double distance; + PMPoint start, end, dir; + + for( i = 0; ( i < numLines ) && !m_bStopTask && !m_bStartTask; i++ ) + { + // calculate screen distance + start = points[lines[i].startPoint( )]; + end = points[lines[i].endPoint( )]; + dir[0] = ( end[0] - start[0] ) / m_anglex; + dir[1] = ( end[1] - start[1] ) / m_angley; + distance = sqrt( dir[0] * dir[0] + dir[1] * dir[1] ); + + // calculate number of subdivisions + sd = ( int ) ( distance / subdivisionDistance ); + if( sd > 1 ) + { + // calculate subdivision + if( sd > maxSubdivisions ) + sd = maxSubdivisions; + + sdPoints[0] = start; + sdPoints[sd] = end; + + start = utPoints[lines[i].startPoint( )]; + end = utPoints[lines[i].endPoint( )]; + dir[0] = ( end[0] - start[0] ) / sd; + dir[1] = ( end[1] - start[1] ) / sd; + dir[2] = ( end[2] - start[2] ) / sd; + + for( li = 1; li < sd; li++ ) + { + sdPoints[li][0] = start[0] + li * dir[0]; + sdPoints[li][1] = start[1] + li * dir[1]; + sdPoints[li][2] = start[2] + li * dir[2]; + } + // transform points (first and last are already transformed) + transformProjection( sdPoints.data( ) + 1, sd - 1, + m_pCurrentGlView->camera( ) ); + renderViewStructureSimple( sdPoints, sdLines, sd ); + } + else + { + sdPoints[0] = start; + sdPoints[1] = end; + renderViewStructureSimple( sdPoints, sdLines, 1 ); + } + } + } + else + renderViewStructureSimple( points, vs.lines( ) ); + } + else + renderViewStructureSimple( vs.points( ), vs.lines( ) ); +} + +void PMRenderManager::renderViewStructureSimple( PMPointArray& points, + PMLineArray& lines, + int numberOfLines ) +{ + GLuint* linesData = ( GLuint* ) ( lines.data( ) ); + unsigned int vsLines = 0; + unsigned int rl; + + if( numberOfLines < 0 ) + vsLines = lines.size( ); + else + vsLines = ( unsigned ) numberOfLines; + + glEnableClientState( GL_VERTEX_ARRAY ); + glVertexPointer( 3, GL_DOUBLE, 0, points.data( ) ); + + while( ( vsLines > 0 ) && !m_bStopTask && !m_bStartTask ) + { + rl = m_nMaxRenderedLines - m_renderedLines; + if( rl > vsLines ) + rl = vsLines; + + glDrawElements( GL_LINES, rl * 2, + GL_UNSIGNED_INT, linesData ); + + m_renderedLines += rl; + if( m_renderedLines >= m_nMaxRenderedLines ) + { + m_renderedLines = 0; + qApp->processEvents( maxEventTime ); + if( !m_bStopTask && !m_bStartTask ) + m_pCurrentGlView->makeCurrent( ); + } + + vsLines -= rl; + linesData = linesData + ( rl * 2 ); + } + + glDisableClientState( GL_VERTEX_ARRAY ); +} + +void PMRenderManager::transformProjection( PMPoint* points, int size, + PMCamera* camera ) +{ + int i; + PMPoint* data = points; + PMPoint p; + double cameraAngle = camera->angle( ) * M_PI / 180.0; + double rad, phi, h; + + if( approxZero( cameraAngle ) ) + cameraAngle = M_PI; + + switch( camera->cameraType( ) ) + { + case PMCamera::Perspective: + case PMCamera::Orthographic: + break; + + case PMCamera::UltraWideAngle: + for( i = 0; i < size; i++ ) + { + p = m_viewTransformation * (*data); + + // reverse povray's calculations + p[0] /= m_rightLength; + p[1] /= m_upLength; + p[2] /= m_directionLength; + h = sqrt( p[0] * p[0] + p[1] * p[1] + p[2] * p[2] ); + if( !approxZero( h ) ) + { + p[0] /= h; + p[1] /= h; + } + + (*data)[0] = asin( p[0] ); + (*data)[1] = asin( p[1] ); + if( p[2] > 0 ) + { + (*data)[0] = M_PI - (*data)[0]; + (*data)[1] = M_PI - (*data)[1]; + } + (*data)[2] = -h; + + data++; + } + break; + + case PMCamera::FishEye: + for( i = 0; i < size; i++ ) + { + p = m_viewTransformation * (*data); + + // reverse povray's calculations + phi = atan2( p[1], p[0] ); + rad = atan2( sqrt( p[0] * p[0] + p[1] * p[1] ), -p[2] ); + + (*data)[0] = rad * cos( phi ); + (*data)[1] = rad * sin( phi ); + (*data)[2] = -sqrt( p[0] * p[0] + p[1] * p[1] + p[2] * p[2] ); + + data++; + } + break; + + case PMCamera::Panoramic: + for( i = 0; i < size; i++ ) + { + p = m_viewTransformation * (*data); + + // reverse povray's calculations + p[0] /= m_rightLength; + p[1] /= m_upLength; + p[2] /= m_directionLength; + + (*data)[0] = atan2( p[0], -p[2] ); + (*data)[1] = atan2( p[1], sqrt( p[0] * p[0] + p[2] * p[2] ) ); + (*data)[2] = -sqrt( p[0] * p[0] + p[1] * p[1] + p[2] * p[2] ); + + data++; + } + break; + + case PMCamera::Cylinder: + switch( camera->cylinderType( ) ) + { + case 1: + for( i = 0; i < size; i++ ) + { + p = m_viewTransformation * (*data); + + // reverse povray's calculations + p[0] /= m_rightLength; + p[1] /= m_upLength; + p[2] /= m_directionLength; + + h = sqrt( p[0] * p[0] + p[2] * p[2] ); + if( approxZero( h ) ) + h = 1e-5; + + (*data)[0] = atan2( p[0], -p[2] ) / cameraAngle; + (*data)[1] = p[1] / h; + (*data)[2] = -h; + + data++; + } + break; + + case 2: + for( i = 0; i < size; i++ ) + { + p = m_viewTransformation * (*data); + + // reverse povray's calculations + p[0] /= m_rightLength; + p[1] /= m_upLength; + p[2] /= m_directionLength; + + h = sqrt( p[1] * p[1] + p[2] * p[2] ); + if( approxZero( h ) ) + h = 1e-5; + + (*data)[0] = p[0] / h; + (*data)[1] = atan2( p[1], -p[2] ) / cameraAngle; + (*data)[2] = -h; + + data++; + } + break; + + case 3: + for( i = 0; i < size; i++ ) + { + p = m_viewTransformation * (*data); + + // reverse povray's calculations + p[0] /= m_rightLength; + p[1] /= m_upLength; + p[2] /= m_directionLength; + + h = sqrt( p[0] * p[0] + p[2] * p[2] ); + if( approxZero( h ) ) + h = 1e-5; + + (*data)[0] = atan2( p[0], -p[2] ) / cameraAngle; + (*data)[1] = p[1]; + (*data)[2] = -h; + + data++; + } + break; + + case 4: + for( i = 0; i < size; i++ ) + { + p = m_viewTransformation * (*data); + + // reverse povray's calculations + p[0] /= m_rightLength; + p[1] /= m_upLength; + p[2] /= m_directionLength; + + h = sqrt( p[1] * p[1] + p[2] * p[2] ); + if( approxZero( h ) ) + h = 1e-5; + + (*data)[0] = p[0]; + (*data)[1] = atan2( p[1], -p[2] ) / cameraAngle; + (*data)[2] = -h; + + data++; + } + break; + } + break; + + case PMCamera::Omnimax: + break; + + } +} + +void PMRenderManager::renderControlPoints( ) +{ + if( ( m_pCurrentGlView->type( ) == PMGLView::PMViewCamera ) + && ( m_pCurrentGlView->camera( ) == m_pCurrentTask->activeObject( ) ) ) + return; + + if( m_specialCameraMode ) + m_viewTransformation = m_controlPointTransformation; + else + glLoadMatrixd( m_controlPointTransformation.data( ) ); + + PMControlPointList* cplist = m_pCurrentTask->controlPoints( ); + if( cplist->count( ) > 0 ) + { + PMControlPointListIterator it( *cplist ); + PMControlPoint* cp; + PMPoint v; + const GLubyte* bitmap = 0; + + // draw extra control point lines + setGLColor( m_graphicalObjectColor[1] ); + for( it.toFirst( ); it.current( ); ++it ) + { + cp = it.current( ); + if( cp->hasExtraLine( ) ) + { + PMPoint s = PMPoint( cp->extraLineStart( ) ); + PMPoint e = PMPoint( cp->extraLineEnd( ) ); + + if( m_specialCameraMode ) + { + transformProjection( &s, 1, m_pCurrentGlView->camera( ) ); + transformProjection( &e, 1, m_pCurrentGlView->camera( ) ); + } + + glBegin( GL_LINES ); + glVertex3d( s[0], s[1], s[2] ); + glVertex3d( e[0], e[1], e[2] ); + glEnd( ); + } + } + + glDisable( GL_DEPTH_TEST ); + // draw not selected control points + setGLColor( m_controlPointColor[0] ); + for( it.toFirst( ); it.current( ); ++it ) + { + cp = it.current( ); + + if( cp->display( ) ) + { + v = PMPoint( cp->position( ) ); + if( m_specialCameraMode ) + transformProjection( &v, 1, m_pCurrentGlView->camera( ) ); + switch( cp->displayType( ) ) + { + case PMControlPoint::CPPoint: + if( !cp->selected( ) ) + bitmap = PointBitmap; + break; + case PMControlPoint::CPCross: + bitmap = CrossBitmap; + break; + } + + glRasterPos3d( v[0], v[1], v[2] ); + if( bitmap ) + glBitmap( controlPointSize, controlPointSize, + controlPointSize/2, controlPointSize/2, + 0, 0, bitmap ); + } + } + // draw selected control points + setGLColor( m_controlPointColor[1] ); + for( it.toFirst( ); it.current( ); ++it ) + { + cp = it.current( ); + + if( cp->selected( ) && cp->display( ) ) + { + v = PMPoint( cp->position( ) ); + if( m_specialCameraMode ) + transformProjection( &v, 1, m_pCurrentGlView->camera( ) ); + if( cp->displayType( ) == PMControlPoint::CPPoint ) + bitmap = PointBitmap; + + glRasterPos3d( v[0], v[1], v[2] ); + if( bitmap ) + glBitmap( controlPointSize, controlPointSize, + controlPointSize/2, controlPointSize/2, + 0, 0, bitmap ); + } + } + } +} + +void PMRenderManager::renderAxes( ) +{ + int i; + + if( !m_axesViewStructureCreated ) + { + m_axesViewStructure[0] = PMViewStructure( 6, 9 ); + PMPointArray& points = m_axesViewStructure[0].points( ); + PMLineArray& lines = m_axesViewStructure[0].lines( ); + + lines[0] = PMLine( 0, 1 ); + lines[1] = PMLine( 1, 2 ); + lines[2] = PMLine( 1, 3 ); + lines[3] = PMLine( 1, 4 ); + lines[4] = PMLine( 1, 5 ); + lines[5] = PMLine( 2, 3 ); + lines[6] = PMLine( 3, 4 ); + lines[7] = PMLine( 4, 5 ); + lines[8] = PMLine( 5, 2 ); + + points[0] = PMPoint( 0.0, 0.0, 0.0 ); + points[1] = PMPoint( 1.0, 0.0, 0.0 ); + points[2] = PMPoint( dA, dB, dB ); + points[3] = PMPoint( dA, -dB, dB ); + points[4] = PMPoint( dA, -dB, -dB ); + points[5] = PMPoint( dA, dB, -dB ); + + m_axesViewStructure[1] = m_axesViewStructure[0]; + PMPointArray& points1 = m_axesViewStructure[1].points( ); + points1.detach( ); + + points1[0] = PMPoint( 0.0, 0.0, 0.0 ); + points1[1] = PMPoint( 0.0, 1.0, 0.0 ); + points1[2] = PMPoint( dB, dA, dB ); + points1[3] = PMPoint( -dB, dA, dB ); + points1[4] = PMPoint( -dB, dA, -dB ); + points1[5] = PMPoint( dB, dA, -dB ); + + m_axesViewStructure[2] = m_axesViewStructure[0]; + PMPointArray& points2 = m_axesViewStructure[2].points( ); + points2.detach( ); + + points2[0] = PMPoint( 0.0, 0.0, 0.0 ); + points2[1] = PMPoint( 0.0, 0.0, 1.0 ); + points2[2] = PMPoint( dB, dB, dA ); + points2[3] = PMPoint( -dB, dB, dA ); + points2[4] = PMPoint( -dB, -dB, dA ); + points2[5] = PMPoint( dB, -dB, dA ); + + m_axesViewStructureCreated = true; + } + + glEnable( GL_DEPTH_TEST ); + for( i = 0; i < 3; i++ ) + { + setGLColor( m_axesColor[i] ); + renderViewStructure( m_axesViewStructure[i] ); + } +} + +PMMatrix PMRenderManager::viewTransformation( PMCamera* c ) const +{ + PMVector location, lookAt, sky; + PMMatrix m; + + sky = c->sky( ); + location = c->location( ); + lookAt = c->lookAt( ); + + if( approxZero( sky.abs( ) ) ) + sky = PMVector( 0.0, 1.0, 0.0 ); + if( approxZero( ( location - lookAt ).abs( ) ) ) + lookAt = location + PMVector( 0.0, 0.0, 1.0 ); + + m = c->transformedWith( ); + if( m.canBuildInverse( ) ) + return PMMatrix::viewTransformation( location, lookAt, sky ) * m.inverse( ); + return PMMatrix::viewTransformation( location, lookAt, sky ); +} + +void PMRenderManager::setProjection( ) +{ + PMGLView::PMViewType type = m_pCurrentGlView->type( ); + PMCamera* camera = m_pCurrentGlView->camera( ); + int width = m_pCurrentGlView->width( ); + int height = m_pCurrentGlView->height( ); + + if( type == PMGLView::PMViewCamera ) + { + if( camera ) + setCameraProjection( ); + } + else + { + glMatrixMode( GL_PROJECTION ); + glLoadIdentity( ); + + double d = m_pCurrentGlView->scale( ); + + // TODO calculating the z clipping plane + glOrtho( -width/2, width/2, -height/2, height/2, + -viewVolumeZ, viewVolumeZ ); + glScaled( d, d, d ); + glTranslated( m_pCurrentGlView->translationX( ), + m_pCurrentGlView->translationY( ), 0 ); + + switch( type ) + { + case PMGLView::PMViewPosZ: + break; + case PMGLView::PMViewNegZ: + glRotated( 180.0, 0.0, 1.0, 0.0 ); + break; + case PMGLView::PMViewNegY: + glRotated( 90.0, 1.0, 0.0, 0.0 ); + break; + case PMGLView::PMViewPosY: + glRotated( -90.0, 1.0, 0.0, 0.0 ); + break; + case PMGLView::PMViewPosX: + glRotated( 90.0, 0.0, 1.0, 0.0 ); + break; + case PMGLView::PMViewNegX: + glRotated( -90.0, 0.0, 1.0, 0.0 ); + break; + default: + break; + } + + glScaled( 1.0, 1.0, -1.0 ); + + glMatrixMode( GL_MODELVIEW ); + m_pCurrentGlView->setProjectionUpToDate( true ); + } +} + +void PMRenderManager::setCameraProjection( ) +{ + PMCamera* camera = m_pCurrentGlView->camera( ); + int width = m_pCurrentGlView->width( ); + int height = m_pCurrentGlView->height( ); + double angle = M_PI / 2.0; + double modeAspect, viewAspect, cameraAspect; + + m_viewTransformation = viewTransformation( camera ); + m_upLength = camera->up( ).abs( ); + if( approxZero( m_upLength ) ) + m_upLength = 1.0; + m_rightLength = camera->right( ).abs( ); + if( approxZero( m_rightLength ) ) + m_rightLength = 1.0; + m_directionLength = camera->direction( ).abs( ); + if( approxZero( m_directionLength ) ) + m_directionLength = 1.0; + + if( camera->isAngleEnabled( ) ) + angle = camera->angle( ) * M_PI / 180.0; + + m_anglex = 0.5; + m_angley = 0.5; + if( ( angle <= 0.0 ) || ( angle > 2 * M_PI ) ) + angle = M_PI; + + switch( camera->cameraType( ) ) + { + case PMCamera::Perspective: + // If angle wasn't specified determine one from right and direction + if( !camera->isAngleEnabled( ) ) + angle = 2 * atan2( 0.5 * m_rightLength, m_directionLength ); + break; + case PMCamera::UltraWideAngle: + m_anglex = angle / ( 2.0 * M_PI ); + m_angley = angle / ( 2.0 * M_PI ); + m_specialCameraMode = true; + break; + case PMCamera::FishEye: + m_anglex = angle / 2.0; + m_angley = angle / 2.0; + m_specialCameraMode = true; + break; + case PMCamera::Panoramic: + m_anglex = M_PI / 2.0; + m_angley = M_PI / 2.0; + m_specialCameraMode = true; + break; + case PMCamera::Cylinder: + m_anglex = 0.5; + m_angley = 0.5; + m_specialCameraMode = true; + break; + case PMCamera::Omnimax: + m_specialCameraMode = true; + break; + default: + break; + } + + modeAspect = m_pCurrentTask->aspectRatio( ); + if( approxZero( modeAspect ) ) + modeAspect = 1.0; + cameraAspect = camera->aspect( ); + if( approxZero( cameraAspect ) ) + cameraAspect = 1.0; + viewAspect = ( double ) width / ( double ) height; + if( approxZero( viewAspect ) ) + viewAspect = 1.0; + + if( viewAspect > modeAspect ) + m_anglex *= viewAspect / modeAspect; + else + m_angley *= modeAspect / viewAspect; + + + glMatrixMode( GL_PROJECTION ); + glLoadIdentity( ); + + + PMVector up, right, direction; + double handedness; + PMMatrix m; + + up = camera->up( ); + right = camera->right( ); + direction = camera->direction( ); + + if( approxZero( m_upLength ) ) + up = PMVector( 0.0, 1.0, 0.0 ); + if( approxZero( m_rightLength ) ) + right = PMVector( 1.0, 0.0, 0.0 ); + if( approxZero( m_directionLength ) ) + direction = PMVector( 0.0, 0.0, 1.0 ); + + handedness = PMVector::dot( PMVector::cross( up, direction ), right ); + + switch( camera->cameraType( ) ) + { + case PMCamera::Perspective: + if( ( angle <= 0.0 ) || ( angle >= M_PI ) ) + angle = M_PI / 2.0; + + // opengl needs the vertical angle + if( viewAspect < modeAspect ) + angle = atan( tan( angle / 2.0 ) / cameraAspect * modeAspect + / viewAspect ) * 360.0 / M_PI; + else + angle = atan( tan( angle / 2.0 ) / cameraAspect ) + * 360.0 / M_PI; + + gluPerspective( angle, cameraAspect * viewAspect / modeAspect, + 0.001, viewVolumeZ ); + + if( handedness > 0 ) + glScaled( -1.0, 1.0, 1.0 ); + + glMultMatrixd( m_viewTransformation.data( ) ); + break; + + case PMCamera::Orthographic: + m_anglex = m_rightLength / 2.0; + m_angley = m_upLength / 2.0; + + if( viewAspect > modeAspect ) + m_anglex *= viewAspect / modeAspect; + else + m_angley *= modeAspect / viewAspect; + + glOrtho( -m_anglex, m_anglex, -m_angley, m_angley, + 0, viewVolumeZ ); + + if( handedness > 0 ) + glScaled( -1.0, 1.0, 1.0 ); + + glMultMatrixd( m_viewTransformation.data( ) ); + break; + + case PMCamera::UltraWideAngle: + case PMCamera::FishEye: + case PMCamera::Panoramic: + case PMCamera::Cylinder: + case PMCamera::Omnimax: + glOrtho( -m_anglex, m_anglex, -m_angley, m_angley, + -viewVolumeZ, viewVolumeZ ); + + if( handedness > 0 ) + glScaled( -1.0, 1.0, 1.0 ); + break; + } + + glMatrixMode( GL_MODELVIEW ); + m_pCurrentGlView->setProjectionUpToDate( true ); +} + +void PMRenderManager::renderFieldOfView( ) +{ + if( m_pCurrentGlView->type( ) == PMGLView::PMViewCamera ) + { + PMCamera* camera = m_pCurrentGlView->camera( ); + + if( camera ) + { + int width = m_pCurrentGlView->width( ); + int height = m_pCurrentGlView->height( ); + double modeAspect, viewAspect; + int d, vx1, vx2, vy1, vy2; + + modeAspect = m_pCurrentTask->aspectRatio( ); //camera->aspect( ); + if( approxZero( modeAspect ) ) + modeAspect = 1.0; + viewAspect = ( double ) width / ( double ) height; + + if( viewAspect < modeAspect ) + { + vx1 = 0; + vx2 = width - 1; + + d = ( int ) ( height - width / modeAspect + 0.5 ) / 2; + + vy1 = d; + vy2 = height - d - 1; + } + else + { + vy1 = 0; + vy2 = height - 1; + + d = ( int ) ( height * modeAspect ); + + d = ( width - d ) / 2; + vx1 = d; + vx2 = width - d - 1; + } + + glMatrixMode( GL_PROJECTION ); + glPushMatrix( ); + glLoadIdentity( ); + glOrtho( 0, width, 0, height, -2, 2 ); + glMatrixMode( GL_MODELVIEW ); + glPushMatrix( ); + glLoadIdentity( ); + + setGLColor( m_fieldOfViewColor ); + glDisable( GL_DEPTH_TEST ); + + if( camera->cameraType( ) == PMCamera::Omnimax ) + renderString( i18n( "not supported" ), 5.0, + height - qApp->fontMetrics( ).height( ) * 2 - 2 ); + else if( m_specialCameraMode && !m_highDetailCameraView ) + renderString( i18n( "approximated" ), 5.0, + height - qApp->fontMetrics( ).height( ) * 2 - 2 ); + + glBegin( GL_LINE_LOOP ); + + glVertex2d( vx1, vy1 ); + glVertex2d( vx2, vy1 ); + glVertex2d( vx2, vy2 ); + glVertex2d( vx1, vy2 ); + + glEnd( ); + glEnable( GL_DEPTH_TEST ); + + glMatrixMode( GL_PROJECTION ); + glPopMatrix( ); + glMatrixMode( GL_MODELVIEW ); + glPopMatrix( ); + } + } +} + +void PMRenderManager::renderGrid( ) +{ + double scale = m_pCurrentGlView->scale( ); + + if( scale >= 0 ) + { + // calculate the views grid distance + double viewGridDistance = pow( 10.0, ceil( log10( ( double ) m_gridDistance / scale ) ) ); + int sd = ( int ) ( viewGridDistance * scale + 0.5 ); + if( ( sd * 0.2 ) > m_gridDistance ) + viewGridDistance *= 0.2; + else if( ( sd * 0.5 ) > m_gridDistance ) + viewGridDistance *= 0.5; + + // draw the grid + double x1, x2, y1, y2, sx, sy; + double x, y; + int gi; + double screenx, screeny; + double signx = 1.0, signy = 1.0; + + int height = m_pCurrentGlView->height( ); + int width = m_pCurrentGlView->width( ); + double transX = m_pCurrentGlView->translationX( ); + double transY = m_pCurrentGlView->translationY( ); + int fontHeight = qApp->fontMetrics( ).height( ); + + glMatrixMode( GL_PROJECTION ); + glPushMatrix( ); + glLoadIdentity( ); + glOrtho( -width/2, width/2, -height/2, height/2, -2, 2 ); + + glMatrixMode( GL_MODELVIEW ); + glPushMatrix( ); + glLoadIdentity( ); + + setGLColor( m_gridColor ); + glDisable( GL_DEPTH_TEST ); + + switch( m_pCurrentGlView->type( ) ) + { + case PMGLView::PMViewPosX: + signx = -1.0; + break; + case PMGLView::PMViewPosY: + signy = -1.0; + break; + case PMGLView::PMViewNegZ: + signx = -1.0; + break; + default: + break; + } + + sx = width / scale; + sy = height / scale; + x1 = -transX - sx / 2; + x2 = -transX + sx / 2; + y1 = -transY - sy / 2; + y2 = -transY + sy / 2; + + sx = ceil( x1 / viewGridDistance ) * viewGridDistance; + gi = 0; + x = sx; + while( x < x2 ) + { + screenx = ( x + transX ) * scale; + glBegin( GL_LINES ); + glVertex2d( screenx, -height/2 ); + glVertex2d( screenx, height/2 ); + glEnd( ); + + QString label = QString( "%1" ).arg( x * signx, 0, 'g', 4 ); + if( approxZero( x ) && label.find( "e-" ) ) + label = "0"; + + renderString( label, screenx + 3, height / 2 - fontHeight - 2 ); + + gi++; + x = sx + viewGridDistance * gi; + } + + sy = ceil( y1 / viewGridDistance ) * viewGridDistance; + gi = 0; + y = sy; + while( y < y2 ) + { + screeny = ( y + transY ) * scale; + glBegin( GL_LINES ); + glVertex2d( -width/2, screeny ); + glVertex2d( width/2, screeny ); + glEnd( ); + + QString label = QString( "%1" ).arg( y * signy, 0, 'g', 4 ); + if( approxZero( y ) && label.find( "e-" ) ) + label = "0"; + + renderString( label, -width / 2 + 3, screeny + 2 ); + + gi++; + y = sy + viewGridDistance * gi; + } + + + setGLColor( axesColor( 0 ) ); + switch( m_pCurrentGlView->type( ) ) + { + case PMGLView::PMViewPosY: + case PMGLView::PMViewPosZ: + case PMGLView::PMViewNegY: + renderString( "x", width / 2 - qApp->fontMetrics( ).boundingRect( "x" ).width( ) - 4, -3 ); + break; + case PMGLView::PMViewNegZ: + renderString( "x", -width / 2 + 3, -3 ); + break; + default: + break; + } + setGLColor( axesColor( 1 ) ); + switch( m_pCurrentGlView->type( ) ) + { + case PMGLView::PMViewPosX: + case PMGLView::PMViewNegX: + case PMGLView::PMViewPosZ: + case PMGLView::PMViewNegZ: + renderString( "y", -3, height / 2 - fontHeight ); + break; + default: + break; + } + setGLColor( axesColor( 2 ) ); + switch( m_pCurrentGlView->type( ) ) + { + case PMGLView::PMViewPosX: + renderString( "z", -width / 2 + 3, -3 ); + break; + case PMGLView::PMViewNegX: + renderString( "z", width / 2 - qApp->fontMetrics( ).boundingRect( "z" ).width( ) - 4, -3 ); + break; + case PMGLView::PMViewNegY: + renderString( "z", -3, height / 2 - fontHeight ); + break; + case PMGLView::PMViewPosY: + renderString( "z", -3, -height / 2 ); + break; + default: + break; + } + + glEnable( GL_DEPTH_TEST ); + glMatrixMode( GL_PROJECTION ); + glPopMatrix( ); + glMatrixMode( GL_MODELVIEW ); + glPopMatrix( ); + } +} + +void PMRenderManager::renderDescription( ) +{ + int height = m_pCurrentGlView->height( ); + int width = m_pCurrentGlView->width( ); + int fontHeight = qApp->fontMetrics( ).height( ); + + glMatrixMode( GL_PROJECTION ); + glPushMatrix( ); + glLoadIdentity( ); + glOrtho( 0, width, 0, height, -2, 2 ); + glMatrixMode( GL_MODELVIEW ); + glPushMatrix( ); + glLoadIdentity( ); + + setGLColor( m_fieldOfViewColor ); + + switch( m_pCurrentGlView->type( ) ) + { + case PMGLView::PMViewPosX: + renderString( i18n( "left" ), 5.0, height - fontHeight - 2 ); + break; + case PMGLView::PMViewNegX: + renderString( i18n( "right" ), 5.0, height - fontHeight - 2 ); + break; + case PMGLView::PMViewPosY: + renderString( i18n( "bottom" ), 5.0, height - fontHeight - 2 ); + break; + case PMGLView::PMViewNegY: + renderString( i18n( "top" ), 5.0, height - fontHeight - 2 ); + break; + case PMGLView::PMViewPosZ: + renderString( i18n( "front" ), 5.0, height - fontHeight - 2 ); + break; + case PMGLView::PMViewNegZ: + renderString( i18n( "back" ), 5.0, height - fontHeight - 2 ); + break; + case PMGLView::PMViewCamera: + { + PMCamera* c = m_pCurrentGlView->camera( ); + if( c ) + { + QString name( "-" ); + if( !c->name( ).isEmpty( ) ) + name = c->name( ); + else + name = i18n( "(unnamed)" ); + + renderString( i18n( "camera" ) + ": " + name, + 5.0, height - fontHeight - 2 ); + } + else + renderString( i18n( "camera" ), 5.0, height - fontHeight - 2 ); + break; + } + } + + glEnable( GL_DEPTH_TEST ); + + glMatrixMode( GL_PROJECTION ); + glPopMatrix( ); + glMatrixMode( GL_MODELVIEW ); + glPopMatrix( ); +} + +void PMRenderManager::renderString( const QString& str, double x, double y ) +{ + int width = qApp->fontMetrics( ).boundingRect( str ).width( ); + int height = qApp->fontMetrics( ).height( ); + + // GL wants word aligned bitmap + QBitmap bm( ( ( width + 32 ) % 32 ) * 32, height, true ); + + QPainter p( &bm ); + p.setFont( qApp->font( ) ); + p.drawText( bm.rect( ), Qt::AlignLeft | Qt::AlignBottom, str ); + p.end(); + + // Transform to GL bitmap + QImage img = bm.convertToImage( ).mirror( ).convertBitOrder( QImage::BigEndian ); + + glRasterPos2d( x, y ); + glBitmap( img.width( ), img.height( ), 0, 0, 0, 0, img.bits( ) ); +} + +void PMRenderManager::setGLColor( const QColor& c ) +{ + int r, g, b; + + c.rgb( &r, &g, &b ); + glColor3ub( ( GLubyte ) r, ( GLubyte ) g, ( GLubyte ) b ); +} + +void PMRenderManager::slotRenderingSettingsChanged( ) +{ + emit renderingSettingsChanged( ); +} + +void PMRenderManager::saveConfig( KConfig* cfg ) +{ + cfg->setGroup( "Rendering" ); + cfg->writeEntry( "BackgroundColor", m_backgroundColor ); + cfg->writeEntry( "GraphicalObjectColor0", m_graphicalObjectColor[0] ); + cfg->writeEntry( "GraphicalObjectColor1", m_graphicalObjectColor[1] ); + cfg->writeEntry( "ControlPointColor0", m_controlPointColor[0] ); + cfg->writeEntry( "ControlPointColor1", m_controlPointColor[1] ); + cfg->writeEntry( "AxesColorX", m_axesColor[0] ); + cfg->writeEntry( "AxesColorY", m_axesColor[1] ); + cfg->writeEntry( "AxesColorZ", m_axesColor[2] ); + cfg->writeEntry( "GridColor", m_gridColor ); + cfg->writeEntry( "GridDistance", m_gridDistance ); + cfg->writeEntry( "FieldOfViewColor", m_fieldOfViewColor ); + cfg->writeEntry( "HighDetailCameraViews", m_highDetailCameraView ); +} + +void PMRenderManager::restoreConfig( KConfig* cfg ) +{ + cfg->setGroup( "Rendering" ); + + m_backgroundColor = cfg->readColorEntry( "BackgroundColor", &m_backgroundColor ); + m_graphicalObjectColor[0] = cfg->readColorEntry( "GraphicalObjectColor0", &( m_graphicalObjectColor[0] ) ); + m_graphicalObjectColor[1] = cfg->readColorEntry( "GraphicalObjectColor1", &( m_graphicalObjectColor[1] ) ); + m_controlPointColor[0] = cfg->readColorEntry( "ControlPointColor0", &( m_controlPointColor[0] ) ); + m_controlPointColor[1] = cfg->readColorEntry( "ControlPointColor1", &( m_controlPointColor[1] ) ); + m_axesColor[0] = cfg->readColorEntry( "AxesColorX", &( m_axesColor[0] ) ); + m_axesColor[1] = cfg->readColorEntry( "AxesColorY", &( m_axesColor[1] ) ); + m_axesColor[2] = cfg->readColorEntry( "AxesColorZ", &( m_axesColor[2] ) ); + m_gridColor = cfg->readColorEntry( "GridColor", &m_gridColor ); + m_gridDistance = cfg->readNumEntry( "GridDistance", m_gridDistance ); + m_fieldOfViewColor = cfg->readColorEntry( "FieldOfViewColor", &m_fieldOfViewColor ); + m_highDetailCameraView = cfg->readBoolEntry( "HighDetailCameraViews", m_highDetailCameraView ); +} + +bool PMRenderManager::hasOpenGL( ) +{ + if( !s_hasOpenGLChecked ) + { + s_hasOpenGL = ( glXQueryExtension( qt_xdisplay( ), 0, 0 ) != 0 ); + s_hasOpenGLChecked = true; + } + + return s_hasOpenGL; +} + +void PMRenderManager::disableOpenGL( ) +{ + s_hasOpenGLChecked = true; + s_hasOpenGL = false; +} + +#include "pmrendermanager.moc" diff --git a/kpovmodeler/pmrendermanager.h b/kpovmodeler/pmrendermanager.h new file mode 100644 index 00000000..a29a6589 --- /dev/null +++ b/kpovmodeler/pmrendermanager.h @@ -0,0 +1,435 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMRENDERMANAGER_H +#define PMRENDERMANAGER_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmcontrolpoint.h" +#include "pmmatrix.h" +#include "pmobject.h" +#include "pmviewstructure.h" + +#include +#include +#include +#include +#include +#include +#include + +class PMGLView; +class PMCamera; +class PMPoint; +class KConfig; +class QString; + +/** + * Used internally by PMRenderManager. + * + * This class stores informations for one render task. + */ +class PMRenderTask +{ +public: + PMRenderTask( PMGLView* view, PMObject* active, PMObject* top, + PMControlPointList* controlPoints, double aspectRatio, + int visibilityLevel ) + { + m_pView = view; + m_pActiveObject = active; + m_pTopLevelObject = top; + m_pControlPoints = controlPoints; + m_aspectRatio = aspectRatio; + m_visibilityLevel = visibilityLevel; + } + + ~PMRenderTask( ) { }; + + PMGLView* view( ) const { return m_pView; } + PMObject* activeObject( ) const { return m_pActiveObject; } + PMObject* topLevelObject( ) const { return m_pTopLevelObject; } + PMControlPointList* controlPoints( ) const { return m_pControlPoints; } + double aspectRatio( ) const { return m_aspectRatio; } + int visibilityLevel( ) const { return m_visibilityLevel; } + + void setView( PMGLView* view ) { m_pView = view; } + void setActiveObject( PMObject* obj ) { m_pActiveObject = obj; } + void setTopLevelObject( PMObject* obj ) { m_pTopLevelObject = obj; } + void setControlPoints( PMControlPointList* list ) { m_pControlPoints = list; } + void setAspectRatio( double ar ) { m_aspectRatio = ar; } + void setVisibilityLevel( int l ) { m_visibilityLevel = l; } + +private: + PMGLView* m_pView; + PMObject* m_pActiveObject; + PMObject* m_pTopLevelObject; + PMControlPointList* m_pControlPoints; + double m_aspectRatio; + int m_visibilityLevel; +}; + +typedef QPtrList PMRenderTaskList; +typedef QPtrListIterator PMRenderTaskListIterator; + +/** + * Class that controls the background rendering + */ +class PMRenderManager : public QObject +{ + Q_OBJECT +public: + /** + * Returns a pointer to the render manager + */ + static PMRenderManager* theManager( ); + /** + * destructor + */ + ~PMRenderManager( ); + /** + * Adds the @ref PMGLView to the list of views that have to be rendered. + * + * @param view The view + * @param active The active object + * @param top The top level object (normally the scene) + * @param controlPoints A pointer to the list of control points for the + * active object + * @param graphicalChange If true the view will be rendered with higher + * priority + */ + void addView( PMGLView* view, PMObject* active, PMObject* top, + PMControlPointList* controlPoints, double aspectRatio, + int visibilityLevel, bool graphicalChange ); + /** + * Removes the view from the list of views that have to be rendered + */ + void removeView( PMGLView* view ); + + /** + * Call this method if a PMGLView was created + */ + void viewCreated( ) { m_nViews++; } + /** + * Call this method if a PMGLView was deleted + */ + void viewDeleted( ) { m_nViews--; } + + /** + * Returns true if the render manager holds a task for the view + */ + bool containsTask( PMGLView* view ) const; + + /** + * Returns the color for the control points + */ + QColor controlPointColor( int i ) const; + /** + * Sets the control point color + */ + void setControlPointColor( int i, const QColor& c ); + /** + * Returns the color for graphical objects + */ + QColor graphicalObjectColor( int i ) const; + /** + * Sets the graphical object color + */ + void setGraphicalObjectColor( int i, const QColor& c ); + /** + * Returns the color for the coordinate axes + */ + QColor axesColor( int i ) const; + /** + * Sets the axes color + */ + void setAxesColor( int i, const QColor& c ); + /** + * Returns the background color + */ + QColor backgroundColor( ) const { return m_backgroundColor; } + /** + * Sets the background color + */ + void setBackgroundColor( const QColor& c ) { m_backgroundColor = c; } + /** + * Returns the field of view color. + */ + QColor fieldOfViewColor( ) const { return m_fieldOfViewColor; } + /** + * Sets the field of view color + */ + void setFieldOfViewColor( const QColor& c ) { m_fieldOfViewColor = c; } + + /** + * Sets the grid color + */ + void setGridColor( const QColor& c ) { m_gridColor = c; } + /** + * Returns the grid color + */ + QColor gridColor( ) { return m_gridColor; } + /** + * Sets the grid distance + */ + void setGridDistance( int d ); + /** + * Returns the grid distance + */ + int gridDistance( ) { return m_gridDistance; } + + /** + * Returns true if the camera views with complex projections + * are rendered with high detail + */ + bool highDetailCameraViews( ) const { return m_highDetailCameraView; } + /** + * Sets the highDetailCameraView flag + */ + void setHighDetailCameraViews( bool yes ) { m_highDetailCameraView = yes; } + + /** + * Sets the gl drawing color + */ + static void setGLColor( const QColor& c ); + + /** + * Saves the configuration + */ + void saveConfig( KConfig* cfg ); + /** + * Restores the configuration + */ + void restoreConfig( KConfig* cfg ); + + /** + * Returns true if the glx extension is available + */ + static bool hasOpenGL( ); + /** + * Disables OpenGL rendering + */ + static void disableOpenGL( ); + +public slots: + /** + * Stops rendering + */ + void slotStopRendering( ); + /** + * Call this when rendering settings have been changed + */ + void slotRenderingSettingsChanged( ); + +signals: + /** + * Emitted when rendering starts for the view v + */ + void renderingStarted( PMGLView* v ); + /** + * Emitted just before the view is updated + */ + void aboutToUpdate( PMGLView* v ); + /** + * Emitted when rendering has been finished for the view v + */ + void renderingFinished( PMGLView* v ); + /** + * Emitted when rendering settings (colors ...) have been changed + */ + void renderingSettingsChanged( ); + /** + * Emitted when rendering has started + */ + void renderingStarted( ); + /** + * Emitted when rendering has finished + */ + void renderingFinished( ); + +protected: + virtual void timerEvent( QTimerEvent* ); + +private: + /** + * constructor + */ + PMRenderManager( ); + + /** + * Restarts rendering + */ + void restartRendering( ); + + /** + * The background task for rendering + */ + void renderTask( ); + /** + * Renders one object + */ + void renderObject( PMObject* obj ); + /** + * Renders the view structure, subdivides the lines in high + detail camera views */ + void renderViewStructure( PMViewStructure& vs ); + /** + * Renders the view structure without subdivisions + */ + void renderViewStructureSimple( PMPointArray& points, PMLineArray& lines, + int numberOfLines = -1 ); + /** + * Renders the control points + */ + void renderControlPoints( ); + /** + * Draws the grid + */ + void renderGrid( ); + /** + * Draws the coordinate axis + */ + void renderAxes( ); + /** + * Draws the field of view for camera views + */ + void renderFieldOfView( ); + /** + * Draws the view descriptions + */ + void renderDescription( ); + /** + * Renders the string + */ + void renderString( const QString& str, double x, double y ); + + /** + * Transforms and renders the view structure for special + * camera projection types. + */ + void transformProjection( PMPoint* points, int size, PMCamera* camera ); + /** + * Sets the projection for the current view + */ + void setProjection( ); + /** + * Sets the projection for a camera view + */ + void setCameraProjection( ); + + /** + * Calculates the view transformation for the camera c + */ + PMMatrix viewTransformation( PMCamera* c ) const; + + /** + * List of render tasks. The first has the highest priority + */ + QPtrList m_renderTasks; + /** + * Flag for background rendering + */ + bool m_bStopTask, m_bStartTask, m_bTaskIsRunning; + /** + * The color for view structures of graphical objects. + * + * index 0: normal color, 1: selected + */ + QColor m_graphicalObjectColor[2]; + /** + * The color for view structures of textures + */ + QColor m_textureColor[2]; + /** + * The color for the coordinate axes + */ + QColor m_axesColor[3]; + /** + * The background color + */ + QColor m_backgroundColor; + /** + * color for control points + * + * index 0: normal color, 1: selected + */ + QColor m_controlPointColor[2]; + /** + * Color for the field of view box + */ + QColor m_fieldOfViewColor; + + /** + * Grid distance and color + */ + int m_gridDistance; + QColor m_gridColor; + /** + * If true, lines are subdivided in camera views with complex + * projections + */ + bool m_highDetailCameraView; + + /** + * Number of rendered lines between calls of processEvents( ) + */ + unsigned int m_nMaxRenderedLines; + + /** + * Number of gl views + */ + unsigned int m_nViews; + /** + * The render manager (singleton pattern) + */ + static PMRenderManager* s_pManager; + static KStaticDeleter s_staticDeleter; + + // Member variables to save stack space during rendering + PMRenderTask* m_pCurrentTask; + PMGLView* m_pCurrentGlView; + QPtrStack m_matrixStack; // I don't know if the build in gl matrix stack is deep enough + bool m_selected; + PMObject* m_pDeselectObject; + PMObjectList m_objectToRenderStack; + QPtrStack m_quickColorObjects; + QPtrStack m_quickColors; + QColor m_currentColor; + QValueStack m_visibilityStack; + int m_currentVisibility; + unsigned int m_renderedLines; + PMMatrix m_controlPointTransformation; + + // for transformProjection + bool m_specialCameraMode; + PMMatrix m_viewTransformation; + double m_upLength, m_rightLength, m_directionLength; + double m_anglex, m_angley; + PMViewStructure m_subdivisionViewStructure; + + PMViewStructure m_axesViewStructure[3]; + bool m_axesViewStructureCreated; + + static bool s_hasOpenGL; + static bool s_hasOpenGLChecked; +}; + +#endif diff --git a/kpovmodeler/pmrendermode.cpp b/kpovmodeler/pmrendermode.cpp new file mode 100644 index 00000000..1dc32290 --- /dev/null +++ b/kpovmodeler/pmrendermode.cpp @@ -0,0 +1,220 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmrendermode.h" +#include + +#include "pmxmlhelper.h" + + +PMRenderMode::PMRenderMode( ) +{ + init( ); +} + +void PMRenderMode::init( ) +{ + m_width = 640; + m_height = 480; + + m_subSection = false; + m_startRow = 1; + m_endRow = m_height; + m_startColumn = 1; + m_endColumn = m_width; + + m_quality = 9; + + m_radiosity = false; + + m_antialiasing = false; + m_samplingMethod = AntialiasingNonRecursive; + m_antialiasThreshold = 0.3; + m_antialiasJitter = false; + m_antialiasJitterAmount = 1.0; + m_antialiasDepth = 2; + + m_description = i18n( "New mode" ); + + m_alpha = false; +} + +PMRenderMode::PMRenderMode( const QDomElement& e ) +{ + init( ); + + PMXMLHelper hlp( e, 0, 0, 0, 0 ); + m_description = hlp.stringAttribute( "description", m_description ); + m_height = hlp.intAttribute( "height", m_height ); + m_width = hlp.intAttribute( "width", m_width ); + m_subSection = hlp.boolAttribute( "subsection", m_subSection ); + m_startColumn = hlp.doubleAttribute( "start_column", m_startColumn ); + m_endColumn = hlp.doubleAttribute( "end_column", m_endColumn ); + m_startRow = hlp.doubleAttribute( "start_row", m_startRow ); + m_endRow = hlp.doubleAttribute( "end_row", m_endRow ); + m_quality = hlp.intAttribute( "quality", m_quality ); + m_radiosity = hlp.boolAttribute( "radiosity", m_radiosity ); + m_antialiasing = hlp.boolAttribute( "antialiasing", m_antialiasing ); + m_samplingMethod = hlp.intAttribute( "sampling_method", m_samplingMethod ); + m_antialiasThreshold = hlp.doubleAttribute( "aa_threshold", m_antialiasThreshold ); + m_antialiasJitter = hlp.boolAttribute( "aa_jitter", m_antialiasJitter ); + m_antialiasJitterAmount = hlp.doubleAttribute( "aa_jitter_amount", m_antialiasJitterAmount ); + m_antialiasDepth = hlp.intAttribute( "aa_depth", m_antialiasDepth ); + m_alpha = hlp.boolAttribute( "alpha", m_alpha ); +} + +void PMRenderMode::serialize( QDomElement& e ) const +{ + e.setAttribute( "description", m_description ); + e.setAttribute( "height", m_height ); + e.setAttribute( "width", m_width ); + e.setAttribute( "subsection", m_subSection ); + e.setAttribute( "start_row", m_startRow ); + e.setAttribute( "end_row", m_endRow ); + e.setAttribute( "start_column", m_startColumn ); + e.setAttribute( "end_column", m_endColumn ); + e.setAttribute( "quality", m_quality ); + e.setAttribute( "radiosity", m_radiosity ); + e.setAttribute( "antialiasing", m_antialiasing ); + e.setAttribute( "sampling_method", m_samplingMethod ); + e.setAttribute( "aa_threshold", m_antialiasThreshold ); + e.setAttribute( "aa_jitter", m_antialiasJitter ); + e.setAttribute( "aa_jitter_amount", m_antialiasJitterAmount ); + e.setAttribute( "aa_depth", m_antialiasDepth ); + e.setAttribute( "alpha", m_alpha ); +} + +void PMRenderMode::setHeight( int height ) +{ + if( height >= 1 ) + m_height = height; +} + +void PMRenderMode::setWidth( int width ) +{ + if( width >= 1 ) + m_width = width; +} + +void PMRenderMode::setStartRow( double startRow ) +{ + if( startRow >= 0 ) + m_startRow = startRow; +} + +void PMRenderMode::setEndRow( double endRow ) +{ + if( endRow >= 0 ) + m_endRow = endRow; +} + +void PMRenderMode::setStartColumn( double startColumn ) +{ + if( startColumn >= 0 ) + m_startColumn = startColumn; +} + +void PMRenderMode::setEndColumn( double endColumn ) +{ + if( endColumn >= 0 ) + m_endColumn = endColumn; +} + +void PMRenderMode::setQuality( int quality ) +{ + if( ( quality >= 0 ) && ( quality <= 11 ) ) + m_quality = quality; +} + +void PMRenderMode::setAntialiasingDepth( int depth ) +{ + if( ( depth >= 1 ) && ( depth <= 9 ) ) + m_antialiasDepth = depth; +} + +void PMRenderMode::setSamplingMethod( int method ) +{ + if( ( method == AntialiasingNonRecursive ) + || ( method == AntialiasingRecursive ) ) + m_samplingMethod = method; + else + m_samplingMethod = AntialiasingNonRecursive; +} + +QStringList PMRenderMode::commandLineSwitches( ) const +{ + QStringList cl; + QString tmp; + + cl.append( QString( "+W%1" ).arg( m_width ) ); + cl.append( QString( "+H%1" ).arg( m_height ) ); + if( m_subSection ) + { + if( m_startRow < 1.0 ) + tmp.sprintf( "+SR%4.2f", m_startRow ); + else + tmp = QString( "+SR%1" ).arg( ( int ) ( m_startRow + 0.5 ) ); + cl.append( tmp ); + if( m_endRow < 1.0 ) + tmp.sprintf( "+ER%4.2f", m_endRow ); + else + tmp = QString( "+ER%1" ).arg( ( int ) ( m_endRow + 0.5 ) ); + cl.append( tmp ); + + if( m_startColumn < 1.0 ) + tmp.sprintf( "+SC%4.2f", m_startColumn ); + else + tmp = QString( "+SC%1" ).arg( ( int ) ( m_startColumn + 0.5 ) ); + cl.append( tmp ); + if( m_endColumn < 1.0 ) + tmp.sprintf( "+EC%4.2f", m_endColumn ); + else + tmp = QString( "+EC%1" ).arg( ( int ) ( m_endColumn + 0.5 ) ); + cl.append( tmp ); + } + cl.append( QString( "+Q%1" ).arg( m_quality ) ); + if( m_radiosity ) + cl.append( QString( "+QR" ) ); + else + cl.append( QString( "-QR" ) ); + + if( m_antialiasing ) + { + cl.append( QString( "+A" ) ); + cl.append( QString( "+AM%1" ).arg( m_samplingMethod ) ); + tmp.sprintf( "+A%5.3f", m_antialiasThreshold ); + cl.append( tmp ); + if( m_antialiasJitter ) + { + tmp.sprintf( "+J%5.3f", m_antialiasJitterAmount ); + cl.append( tmp ); + } + else + cl.append( QString( "-J" ) ); + cl.append( QString( "+R%1" ).arg( m_antialiasDepth ) ); + } + else + cl.append( QString( "-A" ) ); + + if( m_alpha ) + cl.append( QString( "+UA" ) ); + else + cl.append( QString( "-UA" ) ); + + return cl; +} + diff --git a/kpovmodeler/pmrendermode.h b/kpovmodeler/pmrendermode.h new file mode 100644 index 00000000..a8c891ce --- /dev/null +++ b/kpovmodeler/pmrendermode.h @@ -0,0 +1,128 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMRENDERMODE_H +#define PMRENDERMODE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +/** + * Class that represents the render options for povray + * + * See povray documentation, output options. + */ +class PMRenderMode +{ +public: + /** + * Sampling method for antialiasing. See povray documentation. + */ + enum AASamplingMethod { AntialiasingNonRecursive = 0, AntialiasingRecursive = 1 }; + + /** + * Default constructor + */ + PMRenderMode( ); + /** + * Reads the attributes from the QDomElement + */ + PMRenderMode( const QDomElement& e ); + + void setDescription( const QString& descr ) { m_description = descr; } + QString description( ) const { return m_description; } + + void setHeight( int height ); + int height( ) const { return m_height; } + void setWidth( int width ); + int width( ) const { return m_width; } + + void setSubSection( bool on ) { m_subSection = on; } + bool subSection( ) const { return m_subSection; } + void setStartRow( double startRow ); + double startRow( ) const { return m_startRow; } + void setEndRow( double endRow ); + double endRow( ) const { return m_endRow; } + void setStartColumn( double startColumn ); + double startColumn( ) const { return m_startColumn; } + void setEndColumn( double endColumn ); + double endColumn( ) const { return m_endColumn; } + + void setQuality( int quality ); + int quality( ) const { return m_quality; } + + void setRadiosity( bool on ) { m_radiosity = on; } + bool radiosity( ) const { return m_radiosity; } + + void setAntialiasing( bool on ) { m_antialiasing = on; } + bool antialiasing( ) const { return m_antialiasing; } + void setSamplingMethod( int method ); + int samplingMethod( ) const { return m_samplingMethod; } + void setAntialiasingThreshold( double t ) { m_antialiasThreshold = t; } + double antialiasingThreshold( ) const { return m_antialiasThreshold; } + void setAntialiasingJitter( bool on ) { m_antialiasJitter = on; } + bool antialiasingJitter( ) const { return m_antialiasJitter; } + void setAntialiasingJitterAmount( double amount ) { m_antialiasJitterAmount = amount; } + double antialiasingJitterAmount( ) const { return m_antialiasJitterAmount; } + void setAntialiasingDepth( int depth ); + int antialiasingDepth( ) const { return m_antialiasDepth; } + + void setAlpha( bool on ) { m_alpha = on; } + bool alpha( ) const { return m_alpha; } + + + /** + * Returns the settings as povray command line switches + */ + QStringList commandLineSwitches( ) const; + /** + * Saves the data + */ + void serialize( QDomElement& e ) const; + +private: + void init( ); + + QString m_description; + int m_height, m_width; + bool m_subSection; + double m_startRow, m_endRow, m_startColumn, m_endColumn; + + int m_quality; + bool m_radiosity; + bool m_antialiasing; + int m_samplingMethod; + double m_antialiasThreshold; + bool m_antialiasJitter; + double m_antialiasJitterAmount; + int m_antialiasDepth; + + bool m_alpha; +}; + +typedef QPtrList PMRenderModeList; +typedef QPtrListIterator PMRenderModeListIterator; + +#endif diff --git a/kpovmodeler/pmrendermodesdialog.cpp b/kpovmodeler/pmrendermodesdialog.cpp new file mode 100644 index 00000000..5c4b4b7b --- /dev/null +++ b/kpovmodeler/pmrendermodesdialog.cpp @@ -0,0 +1,611 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmrendermodesdialog.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "pmlineedits.h" + +QSize PMRenderModesDialog::s_size = QSize( 300, 200 ); + +PMRenderModesDialog::PMRenderModesDialog( PMRenderModeList* modes, QWidget* parent, const char* name ) + : KDialogBase( parent, name, true, i18n( "Render Modes" ), + Ok | Cancel, Ok ) +{ + m_selectionIndex = modes->at( ); + m_pOriginalModes = modes; + PMRenderModeListIterator it( *modes ); + for( ; it.current( ); ++it ) + m_workingModes.append( new PMRenderMode( *( it.current( ) ) ) ); + m_workingModes.setAutoDelete( true ); + + QVBox* mainPage = makeVBoxMainWidget( ); + m_pListBox = new QListBox( mainPage ); + connect( m_pListBox, SIGNAL( highlighted( int ) ), SLOT( slotModeSelected( int ) ) ); + + QHBox* buttons = new QHBox( mainPage ); + buttons->setSpacing( KDialog::spacingHint( ) ); + m_pAddButton = new QPushButton( i18n( "Add" ), buttons ); + connect( m_pAddButton, SIGNAL( clicked( ) ), SLOT( slotAdd( ) ) ); + m_pRemoveButton = new QPushButton( i18n( "Remove" ), buttons ); + connect( m_pRemoveButton, SIGNAL( clicked( ) ), SLOT( slotRemove( ) ) ); + m_pEditButton = new QPushButton( i18n( "Edit..." ), buttons ); + connect( m_pEditButton, SIGNAL( clicked( ) ), SLOT( slotEdit( ) ) ); + m_pUpButton = new QPushButton( i18n( "Up" ), buttons ); + connect( m_pUpButton, SIGNAL( clicked( ) ), SLOT( slotUp( ) ) ); + m_pDownButton = new QPushButton( i18n( "Down" ), buttons ); + connect( m_pDownButton, SIGNAL( clicked( ) ), SLOT( slotDown( ) ) ); + + m_pRemoveButton->setEnabled( false ); + m_pUpButton->setEnabled( false ); + m_pDownButton->setEnabled( false ); + + enableButtonOK( false ); + + resize( s_size ); + displayList( ); + connect( m_pListBox, SIGNAL( doubleClicked ( QListBoxItem *) ), this, SLOT(slotEdit( ) ) ); +} + +void PMRenderModesDialog::slotChanged( ) +{ + enableButtonOK( true ); +} + +void PMRenderModesDialog::slotModeSelected( int index ) +{ + m_selectionIndex = index; + checkButtons( ); + slotChanged( ); +} + +void PMRenderModesDialog::displayList( ) +{ + PMRenderModeListIterator it( m_workingModes ); + bool b = m_pListBox->signalsBlocked( ); + m_pListBox->blockSignals( true ); + + m_pListBox->clear( ); + for( ; it.current( ); ++it ) + m_pListBox->insertItem( it.current( )->description( ) ); + m_pListBox->setSelected( m_selectionIndex, true ); + + m_pListBox->blockSignals( b ); + + checkButtons( ); +} + +void PMRenderModesDialog::checkButtons( ) +{ + if( m_selectionIndex < 0 ) + { + m_pRemoveButton->setEnabled( false ); + m_pEditButton->setEnabled( false ); + m_pUpButton->setEnabled( false ); + m_pDownButton->setEnabled( false ); + } + else + { + int num = m_workingModes.count( ); + + m_pRemoveButton->setEnabled( true ); + m_pEditButton->setEnabled( true ); + m_pUpButton->setEnabled( m_selectionIndex != 0 ); + m_pDownButton->setEnabled( m_selectionIndex != ( num - 1 ) ); + } +} + +void PMRenderModesDialog::saveConfig( KConfig* cfg ) +{ + cfg->setGroup( "Appearance" ); + cfg->writeEntry( "RenderModesDialogSize", s_size ); +} + +void PMRenderModesDialog::restoreConfig( KConfig* cfg ) +{ + cfg->setGroup( "Appearance" ); + + QSize defaultSize( 300, 200 ); + s_size = cfg->readSizeEntry( "RenderModesDialogSize", &defaultSize ); +} + +void PMRenderModesDialog::resizeEvent( QResizeEvent* ev ) +{ + s_size = ev->size( ); +} + +void PMRenderModesDialog::slotAdd( ) +{ + m_selectionIndex++; + if( m_selectionIndex < 0 ) + m_selectionIndex = 0; + m_workingModes.insert( ( uint ) m_selectionIndex, new PMRenderMode( ) ); + + displayList( ); + slotChanged( ); +} + +void PMRenderModesDialog::slotRemove( ) +{ + m_workingModes.remove( ( uint ) m_selectionIndex ); + + int num = m_workingModes.count( ); + if( m_selectionIndex >= num ) + m_selectionIndex = num - 1; + + displayList( ); + slotChanged( ); +} + +void PMRenderModesDialog::slotUp( ) +{ + PMRenderMode* mode = m_workingModes.take( ( uint ) m_selectionIndex ); + m_selectionIndex--; + if( m_selectionIndex < 0 ) + m_selectionIndex = 0; + m_workingModes.insert( m_selectionIndex, mode ); + + displayList( ); + slotChanged( ); +} + +void PMRenderModesDialog::slotDown( ) +{ + PMRenderMode* mode = m_workingModes.take( ( uint ) m_selectionIndex ); + m_selectionIndex++; + + int num = m_workingModes.count( ); + if( m_selectionIndex > num ) + m_selectionIndex = num; + m_workingModes.insert( m_selectionIndex, mode ); + + displayList( ); + slotChanged( ); +} + +void PMRenderModesDialog::slotEdit( ) +{ + if ( m_selectionIndex==-1 ) + return; + PMRenderModeDialog dlg( m_workingModes.at( m_selectionIndex ) ); + bool changed = ( dlg.exec( ) == QDialog::Accepted ); + if( changed ) + { + slotChanged( ); + displayList( ); + } +} + +void PMRenderModesDialog::slotOk( ) +{ + m_pOriginalModes->setAutoDelete( true ); + m_pOriginalModes->clear( ); + m_pOriginalModes->setAutoDelete( false ); + *m_pOriginalModes = m_workingModes; + m_pOriginalModes->at( m_selectionIndex ); + + m_workingModes.setAutoDelete( false ); + m_workingModes.clear( ); + + accept( ); +} + + +QSize PMRenderModeDialog::s_size = QSize( 300, 200 ); + +const int numQuality = 9; +const char* qualityString[numQuality] = +{ + I18N_NOOP( "0, 1: Quick colors, full ambient lighting only" ), + I18N_NOOP( "2, 3: Show specified diffuse and ambient light" ), + I18N_NOOP( "4: Render shadows, but no extended lights" ), + I18N_NOOP( "5: Render shadows, including extended lights" ), + I18N_NOOP( "6, 7: Compute texture patterns" ), + I18N_NOOP( "8: Compute reflected, refracted, and transmitted rays" ), + I18N_NOOP( "9: Compute media" ), + I18N_NOOP( "10: Compute radiosity but no media" ), + I18N_NOOP( "11: Compute radiosity and media" ) +}; + +const int c_qualityToIndex[12] = { 0, 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 8 }; +const int c_indexToQuality[numQuality] = { 0, 2, 4, 5, 6, 8, 9, 10, 11 }; + +PMRenderModeDialog::PMRenderModeDialog( PMRenderMode* mode, QWidget* parent, const char* name ) + : KDialogBase( parent, name, true, i18n( "Render Modes" ), + Ok | Cancel, Ok ) +{ + m_pMode = mode; + int i; + + // main page + QWidget* page = new QWidget( this ); + setMainWidget( page ); + QVBoxLayout* topLayout = new QVBoxLayout( page, 0, spacingHint( ) ); + + QHBoxLayout* descrLayout = new QHBoxLayout( topLayout ); + QLabel* descrLabel = new QLabel( i18n( "Description:" ), page ); + descrLayout->addWidget( descrLabel ); + + m_pDescriptionEdit = new QLineEdit( page ); + descrLayout->addWidget( m_pDescriptionEdit ); + + m_pTabWidget = new QTabWidget( page ); + topLayout->addWidget( m_pTabWidget ); + + QWidget* tab; + QVBoxLayout* tabLayout; + + // size tab + tab = new QWidget( ); + m_pTabWidget->addTab( tab, i18n( "Size" ) ); + tabLayout = new QVBoxLayout( tab, marginHint( ), spacingHint( ) ); + + QHBoxLayout* sizeHelpLayout = new QHBoxLayout( tabLayout ); + QGridLayout* sizeLayout = new QGridLayout( sizeHelpLayout, 2, 2 ); + sizeLayout->addWidget( new QLabel( i18n( "Width:" ), tab ), 0, 0 ); + m_pWidthEdit = new PMIntEdit( tab ); + m_pWidthEdit->setValidation( true, 1, false, 0 ); + sizeLayout->addWidget( m_pWidthEdit, 0, 1 ); + sizeLayout->addWidget( new QLabel( i18n( "Height:" ), tab ), 1, 0 ); + m_pHeightEdit = new PMIntEdit( tab ); + m_pHeightEdit->setValidation( true, 1, false, 0 ); + sizeLayout->addWidget( m_pHeightEdit, 1, 1 ); + sizeHelpLayout->addStretch( 1 ); + + m_pSubsectionBox = new QCheckBox( i18n( "Subsection" ), tab ); + tabLayout->addWidget( m_pSubsectionBox ); + + QHBoxLayout* ssHelpLayout = new QHBoxLayout( tabLayout ); + QGridLayout* ssLayout = new QGridLayout( ssHelpLayout, 4, 2 ); + ssLayout->addWidget( new QLabel( i18n( "Start column:" ), tab ), 0, 0 ); + m_pStartColumnEdit = new PMFloatEdit( tab ); + m_pStartColumnEdit->setValidation( true, 0.0, false, 0.0 ); + ssLayout->addWidget( m_pStartColumnEdit, 0, 1 ); + ssLayout->addWidget( new QLabel( i18n( "End column:" ), tab ), 1, 0 ); + m_pEndColumnEdit = new PMFloatEdit( tab ); + m_pEndColumnEdit->setValidation( true, 0.0, false, 0.0 ); + ssLayout->addWidget( m_pEndColumnEdit, 1, 1 ); + ssLayout->addWidget( new QLabel( i18n( "Start row:" ), tab ), 2, 0 ); + m_pStartRowEdit = new PMFloatEdit( tab ); + m_pStartRowEdit->setValidation( true, 0.0, false, 0.0 ); + ssLayout->addWidget( m_pStartRowEdit, 2, 1 ); + ssLayout->addWidget( new QLabel( i18n( "End row:" ), tab ), 3, 0 ); + m_pEndRowEdit = new PMFloatEdit( tab ); + m_pEndRowEdit->setValidation( true, 0.0, false, 0.0 ); + ssLayout->addWidget( m_pEndRowEdit, 3, 1 ); + ssHelpLayout->addStretch( 1 ); + + tabLayout->addStretch( 1 ); + + // quality tab + tab = new QWidget( ); + m_pTabWidget->addTab( tab, i18n( "Quality" ) ); + tabLayout = new QVBoxLayout( tab, marginHint( ), spacingHint( ) ); + + QHBoxLayout* quHelpLayout = new QHBoxLayout( tabLayout ); + quHelpLayout->addWidget( new QLabel( i18n( "Quality:" ), tab ) ); + m_pQualityCombo = new QComboBox( tab ); + quHelpLayout->addWidget( m_pQualityCombo ); + for( i = 0; i < numQuality; i++ ) + m_pQualityCombo->insertItem( i18n( qualityString[i] ) ); + + m_pAntialiasingBox = new QCheckBox( i18n( "Antialiasing" ), tab ); + tabLayout->addWidget( m_pAntialiasingBox ); + + QHBoxLayout* aaHelpLayout = new QHBoxLayout( tabLayout ); + QGridLayout* aaGridLayout = new QGridLayout( aaHelpLayout, 5, 2 ); + aaGridLayout->addWidget( new QLabel( i18n( "Method:" ), tab ), 0, 0 ); + m_pSamplingCombo = new QComboBox( tab ); + aaGridLayout->addWidget( m_pSamplingCombo, 0, 1 ); + m_pSamplingCombo->insertItem( i18n( "Non Recursive" ) ); + m_pSamplingCombo->insertItem( i18n( "Recursive" ) ); + + aaGridLayout->addWidget( new QLabel( i18n( "Threshold:" ), tab ), 1, 0 ); + m_pThresholdEdit = new PMFloatEdit( tab ); + aaGridLayout->addWidget( m_pThresholdEdit, 1, 1 ); + + aaGridLayout->addWidget( new QLabel( i18n( "Depth:" ), tab ), 2, 0 ); + m_pAntialiasDepthEdit = new PMIntEdit( tab ); + m_pAntialiasDepthEdit->setValidation( true, 1, true, 9 ); + aaGridLayout->addWidget( m_pAntialiasDepthEdit, 2, 1 ); + + m_pJitterBox = new QCheckBox( i18n( "Jitter" ), tab ); + aaGridLayout->addMultiCellWidget( m_pJitterBox, 3, 3, 0, 1 ); + + aaGridLayout->addWidget( new QLabel( i18n( "Amount:" ), tab ), 4, 0 ); + m_pJitterAmountEdit = new PMFloatEdit( tab ); + aaGridLayout->addWidget( m_pJitterAmountEdit, 4, 1 ); + + aaHelpLayout->addStretch( 1 ); + + m_pRadiosityBox = new QCheckBox( i18n( "Radiosity" ), tab ); + tabLayout->addWidget( m_pRadiosityBox ); + + tabLayout->addStretch( 1 ); + + // output options tab + tab = new QWidget( ); + m_pTabWidget->addTab( tab, i18n( "Output" ) ); + tabLayout = new QVBoxLayout( tab, marginHint( ), spacingHint( ) ); + + m_pAlphaBox = new QCheckBox( i18n( "Alpha" ), tab ); + tabLayout->addWidget( m_pAlphaBox ); + + tabLayout->addStretch( 1 ); + + + resize( s_size ); + + // display the mode BEFORE the signals are connected!!! + displayMode( ); + + enableButtonOK( false ); + + // connect signals + connect( m_pDescriptionEdit, SIGNAL( textChanged( const QString& ) ), SLOT( slotTextChanged( const QString& ) ) ); + connect( m_pHeightEdit, SIGNAL( dataChanged( ) ), SLOT( slotChanged( ) ) ); + connect( m_pWidthEdit, SIGNAL( dataChanged( ) ), SLOT( slotChanged( ) ) ); + connect( m_pSubsectionBox, SIGNAL( toggled( bool ) ), SLOT( slotSubsectionToggled( bool ) ) ); + connect( m_pStartRowEdit, SIGNAL( dataChanged( ) ), SLOT( slotChanged( ) ) ); + connect( m_pEndRowEdit, SIGNAL( dataChanged( ) ), SLOT( slotChanged( ) ) ); + connect( m_pStartColumnEdit, SIGNAL( dataChanged( ) ), SLOT( slotChanged( ) ) ); + connect( m_pEndColumnEdit, SIGNAL( dataChanged( ) ), SLOT( slotChanged( ) ) ); + connect( m_pQualityCombo, SIGNAL( activated( int ) ), SLOT( slotActivated( int ) ) ); + connect( m_pRadiosityBox, SIGNAL( clicked( ) ), SLOT( slotChanged( ) ) ); + connect( m_pAntialiasingBox, SIGNAL( toggled( bool ) ), SLOT( slotAntialiasingToggled( bool ) ) ); + connect( m_pSamplingCombo, SIGNAL( activated( int ) ), SLOT( slotActivated( int ) ) ); + connect( m_pThresholdEdit, SIGNAL( dataChanged( ) ), SLOT( slotChanged( ) ) ); + connect( m_pJitterBox, SIGNAL( toggled( bool ) ), SLOT( slotJitterToggled( bool ) ) ); + connect( m_pJitterAmountEdit, SIGNAL( dataChanged( ) ), SLOT( slotChanged( ) ) ); + connect( m_pAntialiasDepthEdit, SIGNAL( dataChanged( ) ), SLOT( slotChanged( ) ) ); + connect( m_pAlphaBox, SIGNAL( toggled( bool ) ), SLOT( slotToggled( bool ) ) ); +} + +void PMRenderModeDialog::saveConfig( KConfig* cfg ) +{ + cfg->setGroup( "Appearance" ); + cfg->writeEntry( "RenderModeDialogSize", s_size ); +} + +void PMRenderModeDialog::restoreConfig( KConfig* cfg ) +{ + cfg->setGroup( "Appearance" ); + + QSize defaultSize( 400, 400 ); + s_size = cfg->readSizeEntry( "RenderModeDialogSize", &defaultSize ); +} + +void PMRenderModeDialog::resizeEvent( QResizeEvent* ev ) +{ + s_size = ev->size( ); +} + +bool PMRenderModeDialog::saveChanges( ) +{ + if( validate( ) ) + { + m_pMode->setDescription( m_pDescriptionEdit->text( ) ); + m_pMode->setWidth( m_pWidthEdit->value( ) ); + m_pMode->setHeight( m_pHeightEdit->value( ) ); + m_pMode->setSubSection( m_pSubsectionBox->isChecked( ) ); + if( m_pSubsectionBox->isChecked( ) ) + { + m_pMode->setStartRow( m_pStartRowEdit->value( ) ); + m_pMode->setEndRow( m_pEndRowEdit->value( ) ); + m_pMode->setStartColumn( m_pStartColumnEdit->value( ) ); + m_pMode->setEndColumn( m_pEndColumnEdit->value( ) ); + } + m_pMode->setQuality( indexToQuality( m_pQualityCombo->currentItem( ) ) ); + m_pMode->setRadiosity( m_pRadiosityBox->isChecked( ) ); + m_pMode->setAntialiasing( m_pAntialiasingBox->isChecked( ) ); + if( m_pAntialiasingBox->isChecked( ) ) + { + m_pMode->setSamplingMethod( m_pSamplingCombo->currentItem( ) ); + m_pMode->setAntialiasingThreshold( m_pThresholdEdit->value( ) ); + m_pMode->setAntialiasingJitter( m_pJitterBox->isChecked( ) ); + if( m_pJitterBox->isChecked( ) ) + m_pMode->setAntialiasingJitterAmount( m_pJitterAmountEdit->value( ) ); + m_pMode->setAntialiasingDepth( m_pAntialiasDepthEdit->value( ) ); + } + m_pMode->setAlpha( m_pAlphaBox->isChecked( ) ); + return true; + } + return false; +} + +bool PMRenderModeDialog::validate( ) +{ + if( m_pDescriptionEdit->text( ).isEmpty( ) ) + { + KMessageBox::error( this, i18n( "Please enter a description for the " + "render mode." ), i18n( "Error" ) ); + m_pDescriptionEdit->selectAll( ); + return false; + } + + // tab 0 + bool error = true; + + if( m_pHeightEdit->isDataValid( ) ) + if( m_pWidthEdit->isDataValid( ) ) + error = false; + if( !error && m_pSubsectionBox->isChecked( ) ) + { + error = true; + if( m_pStartColumnEdit->isDataValid( ) ) + if( m_pEndColumnEdit->isDataValid( ) ) + if( m_pStartRowEdit->isDataValid( ) ) + if( m_pEndRowEdit->isDataValid( ) ) + error = false; + } + + if( error ) + { + m_pTabWidget->setCurrentPage( 0 ); + return false; + } + + // tab 1 + if( m_pAntialiasingBox->isChecked( ) ) + { + error = false; + if( m_pThresholdEdit->isDataValid( ) ) + if( m_pAntialiasDepthEdit->isDataValid( ) ) + error = false; + + if( m_pJitterBox->isChecked( ) && !error ) + error = !m_pJitterAmountEdit->isDataValid( ); + + if( error ) + { + m_pTabWidget->setCurrentPage( 1 ); + return false; + } + } + + // tab 2 + + return true; +} + +void PMRenderModeDialog::displayMode( ) +{ + m_pDescriptionEdit->setText( m_pMode->description( ) ); + m_pHeightEdit->setValue( m_pMode->height( ) ); + m_pWidthEdit->setValue( m_pMode->width( ) ); + m_pSubsectionBox->setChecked( m_pMode->subSection( ) ); + enableSubsection( m_pMode->subSection( ) ); + m_pStartRowEdit->setValue( m_pMode->startRow( ) ); + m_pEndRowEdit->setValue( m_pMode->endRow( ) ); + m_pStartColumnEdit->setValue( m_pMode->startColumn( ) ); + m_pEndColumnEdit->setValue( m_pMode->endColumn( ) ); + m_pQualityCombo->setCurrentItem( qualityToIndex( m_pMode->quality( ) ) ); + m_pRadiosityBox->setChecked( m_pMode->radiosity( ) ); + m_pAntialiasingBox->setChecked( m_pMode->antialiasing( ) ); + enableAntialiasing( m_pMode->antialiasing( ) ); + m_pSamplingCombo->setCurrentItem( m_pMode->samplingMethod( ) ); + m_pThresholdEdit->setValue( m_pMode->antialiasingThreshold( ) ); + m_pJitterBox->setChecked( m_pMode->antialiasingJitter( ) ); + enableJitter( m_pMode->antialiasingJitter( ) && m_pMode->antialiasing( ) ); + m_pJitterAmountEdit->setValue( m_pMode->antialiasingJitterAmount( ) ); + m_pAntialiasDepthEdit->setValue( m_pMode->antialiasingDepth( ) ); + m_pAlphaBox->setChecked( m_pMode->alpha( ) ); +} + +void PMRenderModeDialog::enableSubsection( bool yes ) +{ + m_pStartRowEdit->setEnabled( yes ); + m_pEndRowEdit->setEnabled( yes ); + m_pStartColumnEdit->setEnabled( yes ); + m_pEndColumnEdit->setEnabled( yes ); +} + +void PMRenderModeDialog::enableAntialiasing( bool yes ) +{ + m_pSamplingCombo->setEnabled( yes ); + m_pThresholdEdit->setEnabled( yes ); + m_pAntialiasDepthEdit->setEnabled( yes ); + m_pJitterBox->setEnabled( yes ); + enableJitter( m_pJitterBox->isChecked( ) ); +} + +void PMRenderModeDialog::enableJitter( bool yes ) +{ + m_pJitterAmountEdit->setEnabled( yes ); +} + +int PMRenderModeDialog::qualityToIndex( int quality ) +{ + if( quality < 0 ) + quality = 0; + if( quality > 11 ) + quality = 11; + + return c_qualityToIndex[quality]; +} + +int PMRenderModeDialog::indexToQuality( int index ) +{ + if( index < 0 ) + index = 0; + if( index >= numQuality ) + index = numQuality - 1; + + return c_indexToQuality[index]; +} + +void PMRenderModeDialog::slotOk( ) +{ + if( saveChanges( ) ) + accept( ); +} + +void PMRenderModeDialog::slotChanged( ) +{ + enableButtonOK( true ); +} + +void PMRenderModeDialog::slotTextChanged( const QString& ) +{ + slotChanged( ); +} + +void PMRenderModeDialog::slotActivated( int ) +{ + slotChanged( ); +} + +void PMRenderModeDialog::slotSubsectionToggled( bool on ) +{ + slotChanged( ); + enableSubsection( on ); +} + +void PMRenderModeDialog::slotAntialiasingToggled( bool on ) +{ + slotChanged( ); + enableAntialiasing( on ); +} + +void PMRenderModeDialog::slotJitterToggled( bool on ) +{ + slotChanged( ); + enableJitter( on ); +} + +void PMRenderModeDialog::slotToggled( bool ) +{ + slotChanged( ); +} + +#include "pmrendermodesdialog.moc" + diff --git a/kpovmodeler/pmrendermodesdialog.h b/kpovmodeler/pmrendermodesdialog.h new file mode 100644 index 00000000..a6b6482f --- /dev/null +++ b/kpovmodeler/pmrendermodesdialog.h @@ -0,0 +1,179 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMRENDERMODESDIALOG_H +#define PMRENDERMODESDIALOG_H + +#include "pmrendermode.h" +#include + +class QCheckBox; +class QComboBox; +class QLineEdit; +class QListBox; +class QPushButton; +class QTabWidget; +class KConfig; +class PMIntEdit; +class PMFloatEdit; + +/** + * Dialog for editing a list of render modes. + * @see PMRenderMode + */ +class PMRenderModesDialog : public KDialogBase +{ + Q_OBJECT +public: + /** + * Creates a dialog for the modes list + */ + PMRenderModesDialog( PMRenderModeList* modes, QWidget* parent = 0, const char* name = 0 ); + + static void saveConfig( KConfig* cfg ); + static void restoreConfig( KConfig* cfg ); + +protected slots: + /** + * Called when a mode is selected in the list view + */ + void slotModeSelected( int index ); + + /** + * Called when the add button is klicked + */ + void slotAdd( ); + /** + * Called when the remove button is klicked + */ + void slotRemove( ); + /** + * Called when the up button is klicked + */ + void slotUp( ); + /** + * Called when the down button is klicked + */ + void slotDown( ); + /** + * Called when the edit button is klicked + */ + void slotEdit( ); + /** + * Called when the modes are changed + */ + void slotChanged( ); + virtual void slotOk( ); + +protected: + virtual void resizeEvent( QResizeEvent* ev ); + +private: + void displayList( ); + void checkButtons( ); + + PMRenderModeList* m_pOriginalModes; + PMRenderModeList m_workingModes; + int m_selectionIndex; + + QListBox* m_pListBox; + QPushButton* m_pAddButton; + QPushButton* m_pRemoveButton; + QPushButton* m_pUpButton; + QPushButton* m_pDownButton; + QPushButton* m_pEditButton; + static QSize s_size; +}; + +/** + * Dialog for editing one render mode + * @see PMRenderMode + */ +class PMRenderModeDialog : public KDialogBase +{ + Q_OBJECT +public: + /** + * Creates a dialog for the mode + */ + PMRenderModeDialog( PMRenderMode* mode, QWidget* parent = 0, const char* name = 0 ); + + static void saveConfig( KConfig* cfg ); + static void restoreConfig( KConfig* cfg ); + +protected: + virtual void resizeEvent( QResizeEvent* ev ); + + +protected slots: + virtual void slotOk( ); + void slotChanged( ); + void slotTextChanged( const QString& ); + void slotActivated( int ); + void slotSubsectionToggled( bool ); + void slotAntialiasingToggled( bool ); + void slotJitterToggled( bool ); + void slotToggled( bool ); + +private: + /** + * Saves the current changes. Returns true if successful. + */ + bool saveChanges( ); + /** + * Returns true if the data is valid + */ + bool validate( ); + /** + * Displays the selected mode + */ + void displayMode( ); + + void enableSubsection( bool yes ); + void enableAntialiasing( bool yes ); + void enableJitter( bool yes ); + int qualityToIndex( int quality ); + int indexToQuality( int index ); + + PMRenderMode* m_pMode; + + QTabWidget* m_pTabWidget; + QLineEdit* m_pDescriptionEdit; + PMIntEdit* m_pHeightEdit; + PMIntEdit* m_pWidthEdit; + QCheckBox* m_pSubsectionBox; + PMFloatEdit* m_pStartRowEdit; + PMFloatEdit* m_pEndRowEdit; + PMFloatEdit* m_pStartColumnEdit; + PMFloatEdit* m_pEndColumnEdit; + // quality + QComboBox* m_pQualityCombo; + QCheckBox* m_pRadiosityBox; + QCheckBox* m_pAntialiasingBox; + QComboBox* m_pSamplingCombo; + PMFloatEdit* m_pThresholdEdit; + QCheckBox* m_pJitterBox; + PMFloatEdit* m_pJitterAmountEdit; + PMIntEdit* m_pAntialiasDepthEdit; + // output + QCheckBox* m_pAlphaBox; + + static QSize s_size; +}; + +#endif diff --git a/kpovmodeler/pmresourcelocator.cpp b/kpovmodeler/pmresourcelocator.cpp new file mode 100644 index 00000000..7c778b31 --- /dev/null +++ b/kpovmodeler/pmresourcelocator.cpp @@ -0,0 +1,103 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmresourcelocator.h" +#include "pmpovrayrenderwidget.h" +#include "pmdebug.h" + +#include +#include + +PMResourceLocator* PMResourceLocator::s_pInstance = 0; +KStaticDeleter PMResourceLocator::s_staticDeleter; + +PMResourceLocator::PMResourceLocator( ) + : m_cache( 100, 109, true ) +{ + m_cache.setAutoDelete( true ); +} + +PMResourceLocator::~PMResourceLocator( ) +{ + m_cache.clear( ); +} + +QString PMResourceLocator::findFile( const QString& file ) +{ + if( !s_pInstance ) + s_staticDeleter.setObject( s_pInstance, new PMResourceLocator( ) ); + return s_pInstance->lookUp( file ); +} + +void PMResourceLocator::clearCache( ) +{ + if( s_pInstance ) + s_pInstance->m_cache.clear( ); +} + +QString PMResourceLocator::lookUp( const QString& file ) +{ + if( file.isEmpty( ) ) + return QString::null; + + kdDebug( PMArea ) << "LookUp: " << file << endl; + + QString* ps = m_cache.find( file ); + if( ps ) + return *ps; + + bool found = false; + QString fullPath = QString::null; + + if( file[0] == '/' ) + { + // absolute path, library paths are not used + QFileInfo info( file ); + if( info.exists( ) && info.isReadable( ) && info.isFile( ) ) + { + found = true; + fullPath = file; + } + } + else + { + QStringList plist = PMPovrayRenderWidget::povrayLibraryPaths( ); + QStringList::ConstIterator it = plist.begin( ); + for( ; ( it != plist.end( ) ) && !found; ++it ) + { + QDir dir( *it ); + QFileInfo info( dir, file ); + if( info.exists( ) && info.isReadable( ) && info.isFile( ) ) + { + found = true; + fullPath = info.absFilePath( ); + } + } + } + + if( found ) + { + QString* ni = new QString( fullPath ); + if( !m_cache.insert( file, ni ) ) + delete ni; + kdDebug( PMArea ) << "File \"" << file << "\" found in " + << fullPath << endl; + } + + return fullPath; +} + diff --git a/kpovmodeler/pmresourcelocator.h b/kpovmodeler/pmresourcelocator.h new file mode 100644 index 00000000..02e725cb --- /dev/null +++ b/kpovmodeler/pmresourcelocator.h @@ -0,0 +1,65 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMRESOURCELOCATOR_H +#define PMRESOURCELOCATOR_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +/** + * Class to find files in the povray library paths + */ +class PMResourceLocator +{ +public: + /** + * Destructor + */ + ~PMResourceLocator( ); + /** + * Returns the full path for the file or a null string if the file + * was not found. The file can be a relative or absolute path. + */ + static QString findFile( const QString& file ); + /** + * Clears the resource cache. Call this if the library paths are changed + */ + static void clearCache( ); + +private: + /** + * Constructor + */ + PMResourceLocator( ); + /** + * File lookup function + */ + QString lookUp( const QString& file ); + static PMResourceLocator* s_pInstance; + static KStaticDeleter s_staticDeleter; + + QCache m_cache; +}; + +#endif diff --git a/kpovmodeler/pmrotate.cpp b/kpovmodeler/pmrotate.cpp new file mode 100644 index 00000000..f3e34040 --- /dev/null +++ b/kpovmodeler/pmrotate.cpp @@ -0,0 +1,164 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmrotate.h" +#include "pmrotateedit.h" + +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmrotatecontrolpoint.h" + +#include +#include + +const PMVector rotateDefault = PMVector( 0, 0, 0 ); + +PMDefinePropertyClass( PMRotate, PMRotateProperty ); + +PMMetaObject* PMRotate::s_pMetaObject = 0; +PMObject* createNewRotate( PMPart* part ) +{ + return new PMRotate( part ); +} + +PMRotate::PMRotate( PMPart* part ) + : Base( part ) +{ +} + +PMRotate::PMRotate( const PMRotate& r ) + : Base( r ) +{ + m_rotate = r.m_rotate; +} + +PMRotate::~PMRotate( ) +{ +} + +QString PMRotate::description( ) const +{ + return i18n( "rotate" ); +} + +void PMRotate::serialize( QDomElement& e, QDomDocument& /*doc*/ ) const +{ + e.setAttribute( "value", m_rotate.serializeXML( ) ); +} + +void PMRotate::readAttributes( const PMXMLHelper& h ) +{ + m_rotate = h.vectorAttribute( "value", rotateDefault ); +} + +PMMetaObject* PMRotate::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Rotate", Base::metaObject( ), + createNewRotate ); + s_pMetaObject->addProperty( + new PMRotateProperty( "rotation", &PMRotate::setRotation, &PMRotate::rotation ) ); + } + return s_pMetaObject; +} + +void PMRotate::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMRotate::setRotation( const PMVector& p ) +{ + if( p != m_rotate ) + { + if( m_pMemento ) + { + m_pMemento->addData( s_pMetaObject, PMRotationID, m_rotate ); + m_pMemento->setViewStructureChanged( ); + } + m_rotate = p; + m_rotate.resize( 3 ); + } +} + +PMDialogEditBase* PMRotate::editWidget( QWidget* parent ) const +{ + return new PMRotateEdit( parent ); +} + +void PMRotate::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMRotationID: + setRotation( data->vectorData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMRotate::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + +PMMatrix PMRotate::transformationMatrix( ) const +{ + return PMMatrix::rotation( deg2Rad( m_rotate[0] ), deg2Rad( m_rotate[1] ), + deg2Rad( m_rotate[2] ) ); +} + +void PMRotate::controlPoints( PMControlPointList& list ) +{ + list.append( new PMRotateControlPoint( m_rotate, PMRotationID ) ); +} + +void PMRotate::controlPointsChanged( PMControlPointList& list ) +{ + PMControlPoint* p; + + for( p = list.first( ); p; p = list.next( ) ) + { + if( p->changed( ) ) + { + switch( p->id( ) ) + { + case PMRotationID: + setRotation( ( ( PMRotateControlPoint* ) p )->rotation( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMRotate::controlPointsChanged\n"; + break; + } + } + } +} diff --git a/kpovmodeler/pmrotate.h b/kpovmodeler/pmrotate.h new file mode 100644 index 00000000..0a8a1dbb --- /dev/null +++ b/kpovmodeler/pmrotate.h @@ -0,0 +1,102 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMROTATE_H +#define PMROTATE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmobject.h" +#include "pmvector.h" + +/** + * Class for povray rotate commands. + */ + +class PMRotate : public PMObject +{ + typedef PMObject Base; +public: + /** + * Creates a rotate < 0, 0, 0 > + */ + PMRotate( PMPart* part ); + /** + * Copy constructor + */ + PMRotate( const PMRotate& r ); + /** + * deletes the object + */ + virtual ~PMRotate( ); + + /** */ + virtual PMObject* copy( ) const { return new PMRotate( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMRotateEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pmrotate" ); } + + /** + * Returns the rotation + */ + PMVector rotation( ) const { return m_rotate; } + /** + * Sets the rotation + */ + void setRotation( const PMVector& p ); + + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual bool hasTransformationMatrix( ) const { return true; } + /** */ + virtual PMMatrix transformationMatrix( ) const; + /** */ + virtual void controlPoints( PMControlPointList& list ); + /** */ + virtual void controlPointsChanged( PMControlPointList& list ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMRotateMementoID { PMRotationID }; + PMVector m_rotate; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmrotatecontrolpoint.cpp b/kpovmodeler/pmrotatecontrolpoint.cpp new file mode 100644 index 00000000..b612b4c9 --- /dev/null +++ b/kpovmodeler/pmrotatecontrolpoint.cpp @@ -0,0 +1,78 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmrotatecontrolpoint.h" +#include "pmmath.h" +#include "pmdebug.h" + +#include +#include + +const double precision = 0.1; + +PMRotateControlPoint::PMRotateControlPoint( const PMVector& rot, int id ) + : PMControlPoint( id, i18n( "Rotation" ) ) +{ + m_rotation = rot; +} + +void PMRotateControlPoint::graphicalChangeStarted( ) +{ + m_originalRotation = m_rotation; + m_originalTransformation = + PMMatrix::rotation( deg2Rad( m_rotation.x( ) ), + deg2Rad( m_rotation.y( ) ), + deg2Rad( m_rotation.z( ) ) ); +} + +void PMRotateControlPoint::graphicalChange( const PMVector& startPoint, + const PMVector& viewNormal, + const PMVector& endPoint ) +{ + double a, x, y, z; + + a = PMVector::angle( startPoint, endPoint ); + if( !approxZero( a ) ) + { + PMMatrix m; + + if( !approx( a, M_PI ) ) + { + PMVector n = PMVector::cross( startPoint, endPoint ); + m = PMMatrix::rotation( n, a ) + * m_originalTransformation; + } + else + m = PMMatrix::rotation( viewNormal, M_PI ) + * m_originalTransformation; + + m.toRotation( &x, &y, &z ); + m_rotation[0] = rint( rad2Deg( x ) / precision ) * precision; + m_rotation[1] = rint( rad2Deg( y ) / precision ) * precision; + m_rotation[2] = rint( rad2Deg( z ) / precision ) * precision; + } +} + +void PMRotateControlPoint::snapToGrid( ) +{ + int i; + double d = rotateGrid( ); + if( !approxZero( d ) ) + for( i = 0; i < 3; i++ ) + m_rotation[i] = rint( m_rotation[i] / d ) * d; + setChanged( ); +} diff --git a/kpovmodeler/pmrotatecontrolpoint.h b/kpovmodeler/pmrotatecontrolpoint.h new file mode 100644 index 00000000..1918eec4 --- /dev/null +++ b/kpovmodeler/pmrotatecontrolpoint.h @@ -0,0 +1,73 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMROTATECONTROLPOINT_H +#define PMROTATECONTROLPOINT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + + +#include "pmcontrolpoint.h" +#include "pmmatrix.h" + +/** + * Control points for rotation + */ +class PMRotateControlPoint : public PMControlPoint +{ +public: + /** + * Creates a PMRotateControlPoint with id. + */ + PMRotateControlPoint( const PMVector& rotation, int id ); + /** + * Deletes the PMRotateControlPoint + */ + virtual ~PMRotateControlPoint( ) { }; + + /** */ + virtual PMVector position( ) const { return PMVector( 0.0, 0.0, 0.0 ); } + + /** + * Sets the rotation + */ + void setRotation( const PMVector& rot ) { m_rotation = rot; } + /** + * Returns the rotation + */ + PMVector rotation( ) const { return m_rotation; } + + /** */ + virtual PMCPDisplayType displayType( ) const { return CPCross; }; + /** */ + virtual void snapToGrid( ); +protected: + /** */ + virtual void graphicalChangeStarted( ); + /** */ + virtual void graphicalChange( const PMVector& startPoint, + const PMVector& viewNormal, + const PMVector& endPoint ); +private: + PMVector m_rotation, m_originalRotation; + PMMatrix m_originalTransformation; +}; + +#endif diff --git a/kpovmodeler/pmrotateedit.cpp b/kpovmodeler/pmrotateedit.cpp new file mode 100644 index 00000000..df2c2340 --- /dev/null +++ b/kpovmodeler/pmrotateedit.cpp @@ -0,0 +1,74 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmrotateedit.h" +#include "pmrotate.h" +#include "pmvectoredit.h" + +#include +#include + + +PMRotateEdit::PMRotateEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMRotateEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + m_pVector = new PMVectorEdit( "x", "y", "z", this ); + topLayout( )->addWidget( m_pVector ); + + connect( m_pVector, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMRotateEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Rotate" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMRotate* ) o; + + m_pVector->setVector( m_pDisplayedObject->rotation( ) ); + m_pVector->setReadOnly( readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMRotateEdit: Can't display object\n"; +} + +void PMRotateEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setRotation( m_pVector->vector( ) ); + } +} + +bool PMRotateEdit::isDataValid( ) +{ + if( m_pVector->isDataValid( ) ) + return Base::isDataValid( ); + return false; +} +#include "pmrotateedit.moc" diff --git a/kpovmodeler/pmrotateedit.h b/kpovmodeler/pmrotateedit.h new file mode 100644 index 00000000..89ca56fd --- /dev/null +++ b/kpovmodeler/pmrotateedit.h @@ -0,0 +1,62 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMROTATEEDIT_H +#define PMROTATEEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMRotate; +class PMVectorEdit; + +/** + * Dialog edit class for @ref PMRotate + */ +class PMRotateEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMRotateEdit with parent and name + */ + PMRotateEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMRotate* m_pDisplayedObject; + PMVectorEdit* m_pVector; +}; + + +#endif diff --git a/kpovmodeler/pmscale.cpp b/kpovmodeler/pmscale.cpp new file mode 100644 index 00000000..2be064c2 --- /dev/null +++ b/kpovmodeler/pmscale.cpp @@ -0,0 +1,163 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmscale.h" +#include "pmscaleedit.h" +#include "pmscalecontrolpoint.h" + +#include "pmxmlhelper.h" +#include "pmmemento.h" + +#include + +const PMVector scaleDefault = PMVector( 0, 0, 0 ); + +PMDefinePropertyClass( PMScale, PMScaleProperty ); + +PMMetaObject* PMScale::s_pMetaObject = 0; +PMObject* createNewScale( PMPart* part ) +{ + return new PMScale( part ); +} + +PMScale::PMScale( PMPart* part ) + : Base( part ) +{ + m_scale = PMVector( 1.0, 1.0, 1.0 ); +} + +PMScale::PMScale( const PMScale& s ) + : Base( s ) +{ + m_scale = s.m_scale; +} + +PMScale::~PMScale( ) +{ +} + +QString PMScale::description( ) const +{ + return i18n( "scale" ); +} + +void PMScale::serialize( QDomElement& e, QDomDocument& /*d*/ ) const +{ + e.setAttribute( "value", m_scale.serializeXML( ) ); +} + +void PMScale::readAttributes( const PMXMLHelper& h ) +{ + m_scale = h.vectorAttribute( "value", scaleDefault ); +} + +PMMetaObject* PMScale::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Scale", Base::metaObject( ), + createNewScale ); + s_pMetaObject->addProperty( + new PMScaleProperty( "scale", &PMScale::setScale, &PMScale::scale ) ); + } + return s_pMetaObject; +} + +void PMScale::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMScale::setScale( const PMVector& p ) +{ + if( p != m_scale ) + { + if( m_pMemento ) + { + m_pMemento->addData( s_pMetaObject, PMScaleID, m_scale ); + m_pMemento->setViewStructureChanged( ); + } + m_scale = p; + m_scale.resize( 3 ); + } +} + +PMDialogEditBase* PMScale::editWidget( QWidget* parent ) const +{ + return new PMScaleEdit( parent ); +} + +void PMScale::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMScaleID: + setScale( data->vectorData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMScale::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + +PMMatrix PMScale::transformationMatrix( ) const +{ + return PMMatrix::scale( m_scale[0], m_scale[1], m_scale[2] ); +} + +void PMScale::controlPoints( PMControlPointList& list ) +{ + list.append( new PMScaleControlPoint( m_scale, PMScaleID ) ); +} + +void PMScale::controlPointsChanged( PMControlPointList& list ) +{ + PMControlPoint* p; + + for( p = list.first( ); p; p = list.next( ) ) + { + if( p->changed( ) ) + { + switch( p->id( ) ) + { + case PMScaleID: + setScale( ( ( PMScaleControlPoint* ) p )->scale( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMScale::controlPointsChanged\n"; + break; + } + } + } +} diff --git a/kpovmodeler/pmscale.h b/kpovmodeler/pmscale.h new file mode 100644 index 00000000..bc1a391d --- /dev/null +++ b/kpovmodeler/pmscale.h @@ -0,0 +1,103 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMSCALE_H +#define PMSCALE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmobject.h" +#include "pmvector.h" + + +/** + * Class for povray scale commands. + */ + +class PMScale : public PMObject +{ + typedef PMObject Base; +public: + /** + * Creates a scale < 0, 0, 0 > + */ + PMScale( PMPart* part ); + /** + * Copy constructor + */ + PMScale( const PMScale& s ); + /** + * deletes the object + */ + virtual ~PMScale( ); + + /** */ + virtual PMObject* copy( ) const { return new PMScale( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMScaleEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pmscale" ); } + + /** + * Returns the scale + */ + PMVector scale( ) const { return m_scale; } + /** + * Sets the scale + */ + void setScale( const PMVector& p ); + + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual bool hasTransformationMatrix( ) const { return true; } + /** */ + virtual PMMatrix transformationMatrix( ) const; + /** */ + virtual void controlPoints( PMControlPointList& list ); + /** */ + virtual void controlPointsChanged( PMControlPointList& list ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMScaleMementoID { PMScaleID }; + PMVector m_scale; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmscalecontrolpoint.cpp b/kpovmodeler/pmscalecontrolpoint.cpp new file mode 100644 index 00000000..c6def808 --- /dev/null +++ b/kpovmodeler/pmscalecontrolpoint.cpp @@ -0,0 +1,58 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmscalecontrolpoint.h" +#include "pmmath.h" +#include "pmdebug.h" + +#include +#include + +const double precision = 0.001; + +PMScaleControlPoint::PMScaleControlPoint( const PMVector& scale, int id ) + : PMControlPoint( id, i18n( "Scale" ) ) +{ + m_scale = scale; +} + +void PMScaleControlPoint::graphicalChangeStarted( ) +{ + m_originalScale = m_scale; +} + +void PMScaleControlPoint::graphicalChange( const PMVector& startPoint, + const PMVector& /*viewNormal*/, + const PMVector& endPoint ) +{ + int i; + + for( i = 0; i < 3; i++ ) + if( !approxZero( startPoint[i] ) ) + m_scale[i] = rint( m_originalScale[i] * endPoint[i] / startPoint[i] + / precision ) * precision; +} + +void PMScaleControlPoint::snapToGrid( ) +{ + int i; + double d = scaleGrid( ); + if( !approxZero( d ) ) + for( i = 0; i < 3; i++ ) + m_scale[i] = rint( m_scale[i] / d ) * d; + setChanged( ); +} diff --git a/kpovmodeler/pmscalecontrolpoint.h b/kpovmodeler/pmscalecontrolpoint.h new file mode 100644 index 00000000..5cb4a091 --- /dev/null +++ b/kpovmodeler/pmscalecontrolpoint.h @@ -0,0 +1,71 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMSCALECONTROLPOINT_H +#define PMSCALECONTROLPOINT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + + +#include "pmcontrolpoint.h" + +/** + * Control points for scale + */ +class PMScaleControlPoint : public PMControlPoint +{ +public: + /** + * Creates a PMScaleControlPoint with id. + */ + PMScaleControlPoint( const PMVector& scale, int id ); + /** + * Deletes the PMScaleControlPoint + */ + virtual ~PMScaleControlPoint( ) { }; + + /** */ + virtual PMVector position( ) const { return PMVector( 0.0, 0.0, 0.0 ); } + + /** + * Sets the scale + */ + void setScale( const PMVector& sc ) { m_scale = sc; } + /** + * Returns the scale + */ + PMVector scale( ) const { return m_scale; } + + /** */ + virtual PMCPDisplayType displayType( ) const { return CPCross; }; + /** */ + virtual void snapToGrid( ); +protected: + /** */ + virtual void graphicalChangeStarted( ); + /** */ + virtual void graphicalChange( const PMVector& startPoint, + const PMVector& viewNormal, + const PMVector& endPoint ); +private: + PMVector m_scale, m_originalScale; +}; + +#endif diff --git a/kpovmodeler/pmscaleedit.cpp b/kpovmodeler/pmscaleedit.cpp new file mode 100644 index 00000000..1df7b40f --- /dev/null +++ b/kpovmodeler/pmscaleedit.cpp @@ -0,0 +1,74 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmscaleedit.h" +#include "pmscale.h" +#include "pmvectoredit.h" + +#include +#include + + +PMScaleEdit::PMScaleEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMScaleEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + m_pVector = new PMVectorEdit( "x", "y", "z", this ); + topLayout( )->addWidget( m_pVector ); + + connect( m_pVector, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMScaleEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Scale" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMScale* ) o; + + m_pVector->setVector( m_pDisplayedObject->scale( ) ); + m_pVector->setReadOnly( readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMScaleEdit: Can't display object\n"; +} + +void PMScaleEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setScale( m_pVector->vector( ) ); + } +} + +bool PMScaleEdit::isDataValid( ) +{ + if( m_pVector->isDataValid( ) ) + return Base::isDataValid( ); + return false; +} +#include "pmscaleedit.moc" diff --git a/kpovmodeler/pmscaleedit.h b/kpovmodeler/pmscaleedit.h new file mode 100644 index 00000000..f18989f5 --- /dev/null +++ b/kpovmodeler/pmscaleedit.h @@ -0,0 +1,62 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMSCALEEDIT_H +#define PMSCALEEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMScale; +class PMVectorEdit; + +/** + * Dialog edit class for @ref PMScale + */ +class PMScaleEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMScaleEdit with parent and name + */ + PMScaleEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMScale* m_pDisplayedObject; + PMVectorEdit* m_pVector; +}; + + +#endif diff --git a/kpovmodeler/pmscanner.cpp b/kpovmodeler/pmscanner.cpp new file mode 100644 index 00000000..f67b7035 --- /dev/null +++ b/kpovmodeler/pmscanner.cpp @@ -0,0 +1,1353 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include +#include +#include + +#include "pmdebug.h" +#include "pmscanner.h" +#include "pmtokens.h" + + +//#define PMSCAN_DEBUG + +PMReservedWordDict::PMReservedWordDict( PMDictMode mode ) + : QAsciiDict( 353 ) +{ + switch( mode ) + { + case PMDReservedWords: + insert( "aa_level", new int( AA_LEVEL_TOK ) ); + insert( "aa_threshold", new int( AA_THRESHOLD_TOK ) ); + insert( "abs", new int( ABS_TOK ) ); + insert( "absorption", new int( ABSORPTION_TOK ) ); + insert( "accuracy", new int( ACCURACY_TOK ) ); + insert( "acos", new int( ACOS_TOK ) ); + insert( "acosh", new int( ACOSH_TOK ) ); + insert( "adaptive", new int( ADAPTIVE_TOK ) ); + insert( "adc_bailout", new int( ADC_BAILOUT_TOK ) ); + insert( "agate", new int( AGATE_TOK ) ); + insert( "agate_turb", new int( AGATE_TURB_TOK ) ); + insert( "all", new int( ALL_TOK ) ); + insert( "all_intersections", new int( ALL_INTERSECTIONS_TOK ) ); + insert( "alpha", new int( ALPHA_TOK ) ); + insert( "altitude", new int( ALTITUDE_TOK ) ); + insert( "always_sample", new int ( ALWAYS_SAMPLE_TOK ) ); + insert( "ambient", new int( AMBIENT_TOK ) ); + insert( "ambient_light", new int( AMBIENT_LIGHT_TOK ) ); + insert( "angle", new int( ANGLE_TOK ) ); + insert( "aperture", new int( APERTURE_TOK ) ); + insert( "arc_angle", new int( ARC_ANGLE_TOK ) ); + insert( "area_light", new int( AREA_LIGHT_TOK ) ); + insert( "autostop", new int ( AUTOSTOP_TOK ) ); + insert( "circular", new int( AREA_CIRCULAR_TOK ) ); + insert( "asc", new int( ASC_TOK ) ); + insert( "asin", new int( ASIN_TOK ) ); + insert( "asinh", new int( ASINH_TOK ) ); + insert( "assumed_gamma", new int( ASSUMED_GAMMA_TOK ) ); + insert( "atan", new int( ATAN_TOK ) ); + insert( "atan2", new int( ATAN2_TOK ) ); + insert( "atanh", new int( ATANH_TOK ) ); + insert( "atmosphere", new int( ATMOSPHERE_TOK ) ); + insert( "atmospheric_attenuation", new int( ATMOSPHERIC_ATTENUATION_TOK ) ); + insert( "attenuating", new int( ATTENUATING_TOK ) ); + insert( "average", new int( AVERAGE_TOK ) ); + insert( "b_spline", new int( B_SPLINE_TOK ) ); + insert( "background", new int( BACKGROUND_TOK ) ); + insert( "bezier_spline", new int( BEZIER_SPLINE_TOK ) ); + insert( "bicubic_patch", new int( BICUBIC_PATCH_TOK ) ); + insert( "black_hole", new int( BLACK_HOLE_TOK ) ); + insert( "blob", new int( BLOB_TOK ) ); + insert( "blue", new int( BLUE_TOK ) ); + insert( "blur_samples", new int( BLUR_SAMPLES_TOK ) ); + insert( "bounded_by", new int( BOUNDED_BY_TOK ) ); + insert( "box", new int( BOX_TOK ) ); + insert( "boxed", new int( BOXED_TOK ) ); + insert( "bozo", new int( BOZO_TOK ) ); + insert( "brick", new int( BRICK_TOK ) ); + insert( "brick_size", new int( BRICK_SIZE_TOK ) ); + insert( "brightness", new int( BRIGHTNESS_TOK ) ); + insert( "brilliance", new int( BRILLIANCE_TOK ) ); + insert( "bumps", new int( BUMPS_TOK ) ); + insert( "bumpy1", new int( BUMPY1_TOK ) ); + insert( "bumpy2", new int( BUMPY2_TOK ) ); + insert( "bumpy3", new int( BUMPY3_TOK ) ); + insert( "bump_map", new int( BUMP_MAP_TOK ) ); + insert( "bump_size", new int( BUMP_SIZE_TOK ) ); + insert( "camera", new int( CAMERA_TOK ) ); + insert( "caustics", new int( CAUSTICS_TOK ) ); + insert( "ceil", new int( CEIL_TOK ) ); + insert( "checker", new int( CHECKER_TOK ) ); + insert( "chr", new int( CHR_TOK ) ); + insert( "cells", new int( CELLS_TOK ) ); + insert( "clipped_by", new int( CLIPPED_BY_TOK ) ); + insert( "clock", new int( CLOCK_TOK ) ); + insert( "clock_delta", new int( CLOCK_DELTA_TOK ) ); + insert( "collect", new int( COLLECT_TOK ) ); + insert( "color", new int( COLOR_TOK ) ); + insert( "color_map", new int( COLOR_MAP_TOK ) ); + insert( "colour", new int( COLOUR_TOK ) ); + insert( "colour_map", new int( COLOUR_MAP_TOK ) ); + insert( "component", new int( COMPONENT_TOK ) ); + insert( "composite", new int( COMPOSITE_TOK ) ); + insert( "concat", new int( CONCAT_TOK ) ); + insert( "cone", new int( CONE_TOK ) ); + insert( "confidence", new int( CONFIDENCE_TOK ) ); + insert( "conic_sweep", new int( CONIC_SWEEP_TOK ) ); + insert( "conserve_energy", new int( CONSERVE_ENERGY_TOK ) ); + insert( "constant", new int( CONSTANT_TOK ) ); + insert( "contained_by", new int( CONTAINED_BY_TOK ) ); + insert( "control0", new int( CONTROL0_TOK ) ); + insert( "control1", new int( CONTROL1_TOK ) ); + insert( "cos", new int( COS_TOK ) ); + insert( "cosh", new int( COSH_TOK ) ); + insert( "count", new int( COUNT_TOK ) ); + insert( "crackle", new int( CRACKLE_TOK ) ); + insert( "crand", new int( CRAND_TOK ) ); + insert( "cube", new int( CUBE_TOK ) ); + insert( "cubic", new int( CUBIC_TOK ) ); + insert( "cubic_spline", new int( CUBIC_SPLINE_TOK ) ); + insert( "cubic_wave", new int( CUBIC_WAVE_TOK ) ); + insert( "cylinder", new int( CYLINDER_TOK ) ); + insert( "cylindrical", new int( CYLINDRICAL_TOK ) ); + insert( "degrees", new int( DEGREES_TOK ) ); + insert( "dents", new int( DENTS_TOK ) ); + insert( "density", new int( DENSITY_TOK ) ); + insert( "density_file", new int( DENSITY_FILE_TOK ) ); + insert( "density_map", new int( DENSITY_MAP_TOK ) ); + insert( "df3", new int( DF3_TOK ) ); + insert( "difference", new int( DIFFERENCE_TOK ) ); + insert( "diffuse", new int( DIFFUSE_TOK ) ); + insert( "direction", new int( DIRECTION_TOK ) ); + insert( "disc", new int( DISC_TOK ) ); + insert( "dispersion", new int ( DISPERSION_TOK ) ); + insert( "dispersion_samples", new int ( DISPERSION_SAMPLES_TOK ) ); + insert( "dist_exp", new int ( DIST_EXP_TOK ) ); + insert( "distance", new int( DISTANCE_TOK ) ); + insert( "distance_maximum", new int( DISTANCE_MAXIMUM_TOK ) ); + insert( "div", new int( DIV_TOK ) ); + insert( "double_illuminate", new int( DOUBLE_ILLUMINATE_TOK ) ); + insert( "dust", new int( DUST_TOK ) ); + insert( "dust_type", new int( DUST_TYPE_TOK ) ); + insert( "eccentricity", new int( ECCENTRICITY_TOK ) ); + insert( "emission", new int( EMISSION_TOK ) ); + insert( "emitting", new int( EMITTING_TOK ) ); + insert( "error", new int( ERROR_TOK ) ); + insert( "error_bound", new int( ERROR_BOUND_TOK ) ); + insert( "evaluate", new int( EVALUATE_TOK ) ); + insert( "exp", new int( EXP_TOK ) ); + insert( "expand_thresholds", new int (EXPAND_THRESHOLDS_TOK) ); + insert( "exponent", new int( EXPONENT_TOK ) ); + insert( "exterior", new int( EXTERIOR_TOK ) ); + insert( "extinction", new int( EXTINCTION_TOK ) ); + insert( "fade_distance", new int( FADE_DISTANCE_TOK ) ); + insert( "fade_power", new int( FADE_POWER_TOK ) ); + insert( "falloff", new int( FALLOFF_TOK ) ); + insert( "falloff_angle", new int( FALLOFF_ANGLE_TOK ) ); + insert( "false", new int( FALSE_TOK ) ); + insert( "file_exists", new int( FILE_EXISTS_TOK ) ); + insert( "filter", new int( FILTER_TOK ) ); + insert( "finish", new int( FINISH_TOK ) ); + insert( "fisheye", new int( FISHEYE_TOK ) ); + insert( "flatness", new int( FLATNESS_TOK ) ); + insert( "flip", new int( FLIP_TOK ) ); + insert( "floor", new int( FLOOR_TOK ) ); + insert( "focal_point", new int( FOCAL_POINT_TOK ) ); + insert( "fog", new int( FOG_TOK ) ); + insert( "fog_alt", new int( FOG_ALT_TOK ) ); + insert( "fog_offset", new int( FOG_OFFSET_TOK ) ); + insert( "fog_type", new int( FOG_TYPE_TOK ) ); + insert( "form", new int( FORM_TOK ) ); + insert( "fresnel", new int( FRESNEL_TOK ) ); + insert( "frequency", new int( FREQUENCY_TOK ) ); + insert( "function", new int( FUNCTION_TOK ) ); + insert( "gather", new int( GATHER_TOK ) ); + insert( "gif", new int( GIF_TOK ) ); + insert( "global_lights", new int ( GLOBAL_LIGHTS_TOK ) ); + insert( "global_settings", new int( GLOBAL_SETTINGS_TOK ) ); + insert( "glowing", new int( GLOWING_TOK ) ); + insert( "gradient", new int( GRADIENT_TOK ) ); + insert( "granite", new int( GRANITE_TOK ) ); + insert( "gray_threshold", new int( GRAY_THRESHOLD_TOK ) ); + insert( "green", new int( GREEN_TOK ) ); + insert( "halo", new int( HALO_TOK ) ); + insert( "height_field", new int( HEIGHT_FIELD_TOK ) ); + insert( "hexagon", new int( HEXAGON_TOK ) ); + insert( "hf_gray_16", new int( HF_GRAY_16_TOK ) ); + insert( "hierarchy", new int( HIERARCHY_TOK ) ); + insert( "hollow", new int( HOLLOW_TOK ) ); + insert( "hypercomplex", new int( HYPERCOMPLEX_TOK ) ); + insert( "iff", new int( IFF_TOK ) ); + insert( "image_map", new int( IMAGE_MAP_TOK ) ); + insert( "incidence", new int( INCIDENCE_TOK ) ); + insert( "inside_vector", new int( INSIDE_VECTOR_TOK ) ); + insert( "int", new int( INT_TOK ) ); + insert( "interior", new int( INTERIOR_TOK ) ); + insert( "interior_texture", new int( INTERIOR_TEXTURE_TOK ) ); + insert( "interpolate", new int( INTERPOLATE_TOK ) ); + insert( "intersection", new int( INTERSECTION_TOK ) ); + insert( "intervals", new int( INTERVALS_TOK ) ); + insert( "inverse", new int( INVERSE_TOK ) ); + insert( "ior", new int( IOR_TOK ) ); + insert( "irid", new int( IRID_TOK ) ); + insert( "irid_wavelength", new int( IRID_WAVELENGTH_TOK ) ); + insert( "isosurface", new int( ISOSURFACE_TOK ) ); + insert( "jitter", new int( JITTER_TOK ) ); + insert( "julia", new int( JULIA_TOK ) ); + insert( "julia_fractal", new int( JULIA_FRACTAL_TOK ) ); + insert( "lambda", new int( LAMBDA_TOK ) ); + insert( "lathe", new int( LATHE_TOK ) ); + insert( "leopard", new int( LEOPARD_TOK ) ); + insert( "light_group", new int ( LIGHT_GROUP_TOK ) ); + insert( "light_source", new int( LIGHT_SOURCE_TOK ) ); + insert( "linear", new int( LINEAR_TOK ) ); + insert( "linear_spline", new int( LINEAR_SPLINE_TOK ) ); + insert( "linear_sweep", new int( LINEAR_SWEEP_TOK ) ); + insert( "location", new int( LOCATION_TOK ) ); + insert( "log", new int( LOG_TOK ) ); + insert( "looks_like", new int( LOOKS_LIKE_TOK ) ); + insert( "look_at", new int( LOOK_AT_TOK ) ); + insert( "low_error_factor", new int( LOW_ERROR_FACTOR_TOK ) ); + insert( "magnet", new int ( MAGNET_TOK ) ); + insert( "major_radius", new int( MAJOR_RADIUS_TOK ) ); + insert( "mandel", new int( MANDEL_TOK ) ); + insert( "map_type", new int( MAP_TYPE_TOK ) ); + insert( "marble", new int( MARBLE_TOK ) ); + insert( "material", new int( MATERIAL_TOK ) ); + insert( "material_map", new int( MATERIAL_MAP_TOK ) ); + insert( "matrix", new int( MATRIX_TOK ) ); + insert( "max", new int( MAX_TOK ) ); + insert( "max_gradient", new int( MAX_GRADIENT_TOK ) ); + insert( "max_intersections", new int( MAX_INTERSECTIONS_TOK ) ); + insert( "max_iteration", new int( MAX_ITERATION_TOK ) ); + insert( "max_sample", new int( MAX_SAMPLE_TOK ) ); + insert( "max_trace", new int( MAX_TRACE_TOK ) ); + insert( "max_trace_level", new int( MAX_TRACE_LEVEL_TOK ) ); + insert( "max_value", new int( MAX_VALUE_TOK ) ); + insert( "media", new int( MEDIA_TOK ) ); + insert( "media_attenuation", new int( MEDIA_ATTENUATION_TOK ) ); + insert( "media_interaction", new int( MEDIA_INTERACTION_TOK ) ); + insert( "merge", new int( MERGE_TOK ) ); + insert( "mesh", new int( MESH_TOK ) ); + insert( "metallic", new int( METALLIC_TOK ) ); + insert( "method", new int( METHOD_TOK ) ); + insert( "metric", new int( METRIC_TOK ) ); + insert( "min", new int( MIN_TOK ) ); + insert( "minimum_reuse", new int( MINIMUM_REUSE_TOK ) ); + insert( "mod", new int( MOD_TOK ) ); + insert( "mortar", new int( MORTAR_TOK ) ); + insert( "nearest_count", new int( NEAREST_COUNT_TOK ) ); + insert( "no", new int( NO_TOK ) ); + insert( "noise_generator", new int( NOISE_GENERATOR_TOK ) ); + insert( "normal", new int( NORMAL_TOK ) ); + insert( "normal_map", new int( NORMAL_MAP_TOK ) ); + insert( "no_image", new int( NO_IMAGE_TOK ) ); + insert( "no_reflection", new int( NO_REFLECTION_TOK ) ); + insert( "no_shadow", new int( NO_SHADOW_TOK ) ); + insert( "number_of_waves", new int( NUMBER_OF_WAVES_TOK ) ); + insert( "object", new int( OBJECT_TOK ) ); + insert( "octaves", new int( OCTAVES_TOK ) ); + insert( "off", new int( OFF_TOK ) ); + insert( "offset", new int( OFFSET_TOK ) ); + insert( "omega", new int( OMEGA_TOK ) ); + insert( "omnimax", new int( OMNIMAX_TOK ) ); + insert( "on", new int( ON_TOK ) ); + insert( "once", new int( ONCE_TOK ) ); + insert( "onion", new int( ONION_TOK ) ); + insert( "open", new int( OPEN_TOK ) ); + insert( "orient", new int( ORIENT_TOK ) ); + insert( "orthographic", new int( ORTHOGRAPHIC_TOK ) ); + insert( "panoramic", new int( PANORAMIC_TOK ) ); + insert( "parallel", new int( PARALLEL_TOK ) ); + insert( "pass_through", new int ( PASS_THROUGH_TOK ) ); + insert( "pattern1", new int( PATTERN1_TOK ) ); + insert( "pattern2", new int( PATTERN2_TOK ) ); + insert( "pattern3", new int( PATTERN3_TOK ) ); + insert( "perspective", new int( PERSPECTIVE_TOK ) ); + insert( "pgm", new int( PGM_TOK ) ); + insert( "phase", new int( PHASE_TOK ) ); + insert( "phong", new int( PHONG_TOK ) ); + insert( "phong_size", new int( PHONG_SIZE_TOK ) ); + insert( "photons", new int ( PHOTONS_TOK ) ); + insert( "pi", new int( PI_TOK ) ); + insert( "pigment", new int( PIGMENT_TOK ) ); + insert( "pigment_map", new int( PIGMENT_MAP_TOK ) ); + insert( "planar", new int( PLANAR_TOK ) ); + insert( "plane", new int( PLANE_TOK ) ); + insert( "png", new int( PNG_TOK ) ); + insert( "point_at", new int( POINT_AT_TOK ) ); + insert( "poly", new int( POLY_TOK ) ); + insert( "poly_wave", new int( POLY_WAVE_TOK ) ); + insert( "polygon", new int( POLYGON_TOK ) ); + insert( "pot", new int( POT_TOK ) ); + insert( "pow", new int( POW_TOK ) ); + insert( "ppm", new int( PPM_TOK ) ); + insert( "precision", new int( PRECISION_TOK ) ); + insert( "pretrace_end", new int( PRETRACE_END_TOK ) ); + insert( "pretrace_start", new int( PRETRACE_START_TOK ) ); + insert( "prism", new int( PRISM_TOK ) ); + insert( "projected_through", new int( PROJECTED_THROUGH_TOK ) ); + insert( "pwr", new int( PWR_TOK ) ); + insert( "quadratic_spline", new int( QUADRATIC_SPLINE_TOK ) ); + insert( "quadric", new int( QUADRIC_TOK ) ); + insert( "quartic", new int( QUARTIC_TOK ) ); + insert( "quaternion", new int( QUATERNION_TOK ) ); + insert( "quick_color", new int( QUICK_COLOR_TOK ) ); + insert( "quick_colour", new int( QUICK_COLOUR_TOK ) ); + insert( "quilted", new int( QUILTED_TOK ) ); + insert( "radial", new int( RADIAL_TOK ) ); + insert( "radians", new int( RADIANS_TOK ) ); + insert( "radiosity", new int( RADIOSITY_TOK ) ); + insert( "radius", new int( RADIUS_TOK ) ); + insert( "rainbow", new int( RAINBOW_TOK ) ); + insert( "ramp_wave", new int( RAMP_WAVE_TOK ) ); + insert( "rand", new int( RAND_TOK ) ); + insert( "ratio", new int( RATIO_TOK ) ); + insert( "reciprocal", new int( RECIPROCAL_TOK ) ); + insert( "recursion_limit", new int( RECURSION_LIMIT_TOK ) ); + insert( "red", new int( RED_TOK ) ); + insert( "reflection", new int( REFLECTION_TOK ) ); + insert( "reflection_exponent", new int( REFLECTION_EXPONENT_TOK ) ); + insert( "refraction", new int( REFRACTION_TOK ) ); + insert( "repeat", new int( REPEAT_TOK ) ); + insert( "rgb", new int( RGB_TOK ) ); + insert( "rgbf", new int( RGBF_TOK ) ); + insert( "rgbft", new int( RGBFT_TOK ) ); + insert( "rgbt", new int( RGBT_TOK ) ); + insert( "right", new int( RIGHT_TOK ) ); + insert( "ripples", new int( RIPPLES_TOK ) ); + insert( "rotate", new int( ROTATE_TOK ) ); + insert( "roughness", new int( ROUGHNESS_TOK ) ); + insert( "samples", new int( SAMPLES_TOK ) ); + insert( "scale", new int( SCALE_TOK ) ); + insert( "scallop_wave", new int( SCALLOP_WAVE_TOK ) ); + insert( "scattering", new int( SCATTERING_TOK ) ); + insert( "seed", new int( SEED_TOK ) ); + insert( "shadowless", new int( SHADOWLESS_TOK ) ); + insert( "sin", new int( SIN_TOK ) ); + insert( "sine_wave", new int( SINE_WAVE_TOK ) ); + insert( "sinh", new int( SINH_TOK ) ); + insert( "sky", new int( SKY_TOK ) ); + insert( "sky_sphere", new int( SKY_SPHERE_TOK ) ); + insert( "slice", new int( SLICE_TOK ) ); + insert( "slope", new int( SLOPE_TOK ) ); + insert( "slope_map", new int( SLOPE_MAP_TOK ) ); + insert( "smooth", new int( SMOOTH_TOK ) ); + insert( "smooth_triangle", new int( SMOOTH_TRIANGLE_TOK ) ); + insert( "solid", new int( SOLID_TOK ) ); + insert( "sor", new int( SOR_TOK ) ); + insert( "spacing", new int ( SPACING_TOK ) ); + insert( "specular", new int( SPECULAR_TOK ) ); + insert( "sphere", new int( SPHERE_TOK ) ); + insert( "sphere_sweep", new int ( SPHERE_SWEEP_TOK ) ); + insert( "spherical", new int( SPHERICAL_TOK ) ); + insert( "spiral", new int( SPIRAL_TOK ) ); + insert( "spiral1", new int( SPIRAL1_TOK ) ); + insert( "spiral2", new int( SPIRAL2_TOK ) ); + insert( "spotlight", new int( SPOTLIGHT_TOK ) ); + insert( "spotted", new int( SPOTTED_TOK ) ); + insert( "sqr", new int( SQR_TOK ) ); + insert( "sqrt", new int( SQRT_TOK ) ); + insert( "str", new int( STR_TOK ) ); + insert( "strcmp", new int( STRCMP_TOK ) ); + insert( "strength", new int( STRENGTH_TOK ) ); + insert( "strlen", new int( STRLEN_TOK ) ); + insert( "strlwr", new int( STRLWR_TOK ) ); + insert( "strupr", new int( STRUPR_TOK ) ); + insert( "sturm", new int( STURM_TOK ) ); + insert( "substr", new int( SUBSTR_TOK ) ); + insert( "superellipsoid", new int( SUPERELLIPSOID_TOK ) ); + insert( "sys", new int( SYS_TOK ) ); + insert( "t", new int( T_TOK ) ); + insert( "tan", new int( TAN_TOK ) ); + insert( "tanh", new int( TANH_TOK ) ); + insert( "target", new int( TARGET_TOK ) ); + insert( "test_camera_1", new int( TEST_CAMERA_1_TOK ) ); + insert( "test_camera_2", new int( TEST_CAMERA_2_TOK ) ); + insert( "test_camera_3", new int( TEST_CAMERA_3_TOK ) ); + insert( "test_camera_4", new int( TEST_CAMERA_4_TOK ) ); + insert( "text", new int( TEXT_TOK ) ); + insert( "texture", new int( TEXTURE_TOK ) ); + insert( "texture_map", new int( TEXTURE_MAP_TOK ) ); + insert( "tga", new int( TGA_TOK ) ); + insert( "thickness", new int( THICKNESS_TOK ) ); + insert( "threshold", new int( THRESHOLD_TOK ) ); + insert( "tightness", new int( TIGHTNESS_TOK ) ); + insert( "tile2", new int( TILE2_TOK ) ); + insert( "tiles", new int( TILES_TOK ) ); + insert( "tolerance", new int( TOLERANCE_TOK ) ); + insert( "toroidal", new int( TOROIDAL_TOK ) ); + insert( "torus", new int( TORUS_TOK ) ); + insert( "track", new int( TRACK_TOK ) ); + insert( "transform", new int( TRANSFORM_TOK ) ); + insert( "translate", new int( TRANSLATE_TOK ) ); + insert( "transmit", new int( TRANSMIT_TOK ) ); + insert( "triangle", new int( TRIANGLE_TOK ) ); + insert( "triangle_wave", new int( TRIANGLE_WAVE_TOK ) ); + insert( "true", new int( TRUE_TOK ) ); + insert( "ttf", new int( TTF_TOK ) ); + insert( "turbulence", new int( TURBULENCE_TOK ) ); + insert( "turb_depth", new int( TURB_DEPTH_TOK ) ); + insert( "type", new int( TYPE_TOK ) ); + insert( "u", new int( U_TOK ) ); + insert( "ultra_wide_angle", new int( ULTRA_WIDE_ANGLE_TOK ) ); + insert( "union", new int( UNION_TOK ) ); + insert( "up", new int( UP_TOK ) ); + insert( "use_color", new int( USE_COLOR_TOK ) ); + insert( "use_colour", new int( USE_COLOUR_TOK ) ); + insert( "use_index", new int( USE_INDEX_TOK ) ); + insert( "u_steps", new int( U_STEPS_TOK ) ); + insert( "uv_mapping", new int( UV_MAPPING_TOK ) ); + insert( "uv_vectors", new int( UV_VECTORS_TOK ) ); + insert( "v", new int( V_TOK ) ); + insert( "val", new int( VAL_TOK ) ); + insert( "variance", new int( VARIANCE_TOK ) ); + insert( "vaxis_rotate", new int( VAXIS_ROTATE_TOK ) ); + insert( "vcross", new int( VCROSS_TOK ) ); + insert( "vdot", new int( VDOT_TOK ) ); + insert( "vlength", new int( VLENGTH_TOK ) ); + insert( "vnormalize", new int( VNORMALIZE_TOK ) ); + insert( "volume_object", new int( VOLUME_OBJECT_TOK ) ); + insert( "volume_rendered", new int( VOLUME_RENDERED_TOK ) ); + insert( "vol_with_light", new int( VOL_WITH_LIGHT_TOK ) ); + insert( "vrotate", new int( VROTATE_TOK ) ); + insert( "v_steps", new int( V_STEPS_TOK ) ); + insert( "warp", new int( WARP_TOK ) ); + insert( "water_level", new int( WATER_LEVEL_TOK ) ); + insert( "waves", new int( WAVES_TOK ) ); + insert( "width", new int( WIDTH_TOK ) ); + insert( "wood", new int( WOOD_TOK ) ); + insert( "wrinkles", new int( WRINKLES_TOK ) ); + insert( "x", new int( X_TOK ) ); + insert( "y", new int( Y_TOK ) ); + insert( "yes", new int( YES_TOK ) ); + insert( "z", new int( Z_TOK ) ); + break; + case PMDDirectives: + insert( "break", new int( BREAK_TOK ) ); + insert( "case", new int( CASE_TOK ) ); + insert( "debug", new int( DEBUG_TOK ) ); + insert( "declare", new int( DECLARE_TOK ) ); + insert( "default", new int( DEFAULT_TOK ) ); + insert( "else", new int( ELSE_TOK ) ); + insert( "end", new int( END_TOK ) ); + insert( "if", new int( IF_TOK ) ); + insert( "ifdef", new int( IFDEF_TOK ) ); + insert( "ifndef", new int( IFNDEF_TOK ) ); + insert( "include", new int( INCLUDE_TOK ) ); + insert( "range", new int( RANGE_TOK ) ); + insert( "render", new int( RENDER_TOK ) ); + insert( "statistics", new int( STATISTICS_TOK ) ); + insert( "switch", new int( SWITCH_TOK ) ); + insert( "version", new int( VERSION_TOK ) ); + insert( "warning", new int( WARNING_TOK ) ); + insert( "while", new int( WHILE_TOK ) ); + break; + } +} + +PMReservedWordDict::~PMReservedWordDict( ) +{ +} + +PMReservedWordDict PMScanner::m_reservedWords( PMReservedWordDict::PMDReservedWords ); +PMReservedWordDict PMScanner::m_directives( PMReservedWordDict::PMDDirectives ); + +const char* c_commentName = "*PMName "; +const int c_commentNameLength = 8; + +const char* c_commentRawBegin = "*PMRawBegin"; +const int c_commentRawBeginLength = 11; + +const char* c_commentRawEnd = "//*PMRawEnd"; +const int c_commentRawEndLength = 11; + + +PMScanner::PMScanner( QIODevice* device ) +{ + m_svalueAlloc = 256; + m_svalue = ( char* ) malloc( m_svalueAlloc ); + m_svalue[0] = '\0'; + m_lastAlloc = m_svalue + m_svalueAlloc; + m_lastChar = m_svalue; + + m_ivalue = 0; + m_fvalue = 0; + m_pDevice = device; + m_line = 1; + m_char = 0; + m_indentation = 0; + m_rawIndentation = 0; + m_bFunctionMode = false; + +// m_lineData = ""; +// m_lineDataPos = 100; +// m_lineDataLength = 0; + nextChar( ); +} + +PMScanner::~PMScanner( ) +{ + if( m_svalue ) + free( m_svalue ); +} + +void PMScanner::nextChar( ) +{ + do + { + m_char = m_pDevice->getch( ); + } + while( m_char == '\r' ); +} + +void PMScanner::clearSValue( ) +{ + m_svalue[0] = '\0'; + m_lastChar = m_svalue; +} + +void PMScanner::addChar( char c ) +{ + *m_lastChar = c; + m_lastChar++; + + if( m_lastChar == m_lastAlloc ) + { + m_svalueAlloc += 64; + m_svalue = ( char* ) realloc( m_svalue, m_svalueAlloc ); + m_lastAlloc = m_svalue + m_svalueAlloc; + m_lastChar = m_lastAlloc - 64; + } + + *m_lastChar = '\0'; +} + +bool PMScanner::isseparation( int c ) +{ + if( c < 0 ) + return true; + if( isspace( c ) ) + return true; + switch( c ) + { + case '{': + case '}': + case '<': + case '>': + case '(': + case ')': + case '[': + case ']': + case '+': + case '-': + case '*': + case '/': + case ',': + case ';': + case '=': + case '.': + return true; + break; + default: + return false; + } + return false; +} + + +void PMScanner::scanError( int c ) +{ + m_token = SCANNER_ERROR_TOK; + if( isprint( c ) ) + m_error = i18n( "Unexpected character '%1' after \"%2\"" ) + .arg( ( char )c ).arg( m_svalue ); + else + m_error = i18n( "Unexpected character %1 after \"%2\"" ) + .arg( c, 4, 16 ).arg( m_svalue ); + +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n"; +#endif +} + + +int PMScanner::nextToken( ) +{ + int status = START_ST; + int cdepth = 0; + bool consumed; + bool end = false; + + clearSValue( ); + m_ivalue = 0; + m_fvalue = 0; +// m_error = ""; + + if( m_bFunctionMode ) + { + m_bFunctionMode = false; + // FIXME: TODO brackets in comments will not be scanned correctly + int count = 1; + + while( count > 0 ) + { + if( m_char < 0 ) + count = 0; + else if( m_char == '{' ) + count++; + else if( m_char == '}' ) + count--; + if( count > 0 ) + { + addChar( m_char ); + nextChar( ); + } + } + + if( m_char != '}' ) + { + m_error = i18n( "Function statement not terminated" ); +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n"; +#endif + m_token = SCANNER_ERROR_TOK; + } + else + m_token = FUNCTION_TOK; + } + else while( status != TOKEN_END_ST ) + { + consumed = true; + if( m_char < 0 ) + end = true; + switch( status ) + { + case START_ST: //begin + if( m_char < 0 ) + { + m_token = EOF_TOK; + addChar( 'E' ); + addChar( 'O' ); + addChar( 'F' ); + status = TOKEN_END_ST; + consumed = false; + break; + } + if( m_char == '\n' ) + { + m_line ++; + m_indentation = 0; + break; + } + if( m_char == ' ' ) + { + m_indentation++; + break; + } + if( m_char == '\t' ) + { + m_indentation += 8 - m_indentation % 8; + break; + } + if( iscntrl( m_char ) ) + break; + if( isspace( m_char ) ) + break; + if( isalpha( m_char ) || ( m_char == '_' ) ) + { + status = ID_ENDST; + addChar( m_char ); + break; + } + if( isdigit( m_char ) ) + { + status = INTEGER_ENDST; + addChar( m_char ); + break; + } + switch( m_char ) + { + case '.': + status = POINT_ST; + addChar( m_char ); + break; + case '#': + status = DIRECTIVE1_ST; + break; + case '"': + status = STRING1_ST; + break; + case '/': + status = SLASH_ST; + break; + default: + addChar( m_char ); + m_token = m_char; + status = TOKEN_END_ST; + +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": Single char '" + << QString( QChar( ( char ) m_char ) ) << "'\n"; +#endif + break; + } + break; + case ID_ENDST: // indentifier or reserved word + if( isalnum( m_char ) || ( m_char == '_' ) ) + { + addChar( m_char ); + break; + } + else if( isseparation( m_char ) ) + { + consumed = false; + m_token = m_reservedWords[ m_svalue ]; + if( m_token < 0 ) + m_token = ID_TOK; + +#ifdef PMSCAN_DEBUG + if( m_token == ID_TOK ) + kdDebug( PMArea ) << "Line " << m_line << ": Indentifier: \"" + << m_svalue << "\"\n"; + else + kdDebug( PMArea ) << "Line " << m_line << ": Reserved word: \"" + << m_svalue << "\"\n"; +#endif + + + status = TOKEN_END_ST; + } + else + { + status = TOKEN_END_ST; + scanError( m_char ); + consumed = false; + } + break; + case INTEGER_ENDST: + if( isdigit ( m_char ) ) + { + addChar( m_char ); + break; + } + else if( m_char == '.' ) + { + status = FLOAT1_ST; + addChar( m_char ); + break; + } + else if( ( m_char == 'e' ) || ( m_char == 'E' ) ) + { + status = FLOAT_EXP1_ST; + addChar( m_char ); + break; + } + else if( isseparation( m_char ) ) + { + consumed = false; + m_ivalue = atoi( m_svalue ); +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": Integer: " + << m_ivalue << "\n"; +#endif + m_token = INTEGER_TOK; + status = TOKEN_END_ST; + } + else + { + status = TOKEN_END_ST; + scanError( m_char ); + consumed = false; + } + break; + case POINT_ST: + if( isdigit( m_char ) ) + { + status = FLOAT_ENDST; + addChar( m_char ); + } + else + { + status = TOKEN_END_ST; + consumed = false; + m_token = '.'; + } + break; + case FLOAT1_ST: + if( isdigit( m_char ) ) + { + status = FLOAT_ENDST; + addChar( m_char ); + break; + } + else + { + scanError( m_char ); + status = TOKEN_END_ST; + consumed = false; + } + break; + case FLOAT_ENDST: + if( isdigit ( m_char ) ) + { + addChar( m_char ); + break; + } + if( ( m_char == 'e' ) || ( m_char == 'E' ) ) + { + status = FLOAT_EXP1_ST; + addChar( m_char ); + break; + } + else if( isseparation( m_char ) ) + { + consumed = false; + m_fvalue = atof( m_svalue ); +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": Float: " + << m_fvalue << "\n"; +#endif + m_token = FLOAT_TOK; + status = TOKEN_END_ST; + } + else + { + scanError( m_char ); + status = TOKEN_END_ST; + consumed = false; + } + break; + case FLOAT_EXP1_ST: + if( ( m_char == '-' ) || ( m_char == '+' ) ) + { + status = FLOAT_EXP2_ST; + addChar( m_char ); + break; + } + if( isdigit( m_char ) ) + { + status = FLOAT_EXP_ENDST; + addChar( m_char ); + break; + } + else + { + scanError( m_char ); + consumed = false; + status = TOKEN_END_ST; + } + break; + case FLOAT_EXP2_ST: + if( isdigit( m_char ) ) + { + status = FLOAT_EXP_ENDST; + addChar( m_char ); + break; + } + else + { + scanError( m_char ); + consumed = false; + status = TOKEN_END_ST; + } + break; + case FLOAT_EXP_ENDST: + if( isdigit ( m_char ) ) + { + addChar( m_char ); + break; + } + else if( isseparation( m_char ) ) + { + consumed = false; + m_fvalue = atof( m_svalue ); +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": Float: " + << m_fvalue << "\n"; +#endif + m_token = FLOAT_TOK; + status = TOKEN_END_ST; + } + else + { + scanError( m_char ); + consumed = false; + status = TOKEN_END_ST; + } + break; + case DIRECTIVE1_ST: + if( m_char == ' ' ) + { + // special treatment for povray inc files + // "# debug" directives + break; + } + else if( isalpha ( m_char ) ) + { + status = DIRECTIVE_ENDST; + addChar( m_char ); + break; + } + else + { + scanError( m_char ); + consumed = false; + status = TOKEN_END_ST; + } + break; + case DIRECTIVE_ENDST: + if( isalpha( m_char ) ) + { + addChar( m_char ); + break; + } + else if( isseparation( m_char ) ) + { + consumed = false; +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": Directive: \"" + << m_svalue << "\"\n"; +#endif + m_token = m_directives[ m_svalue ]; + if( m_token < 0 ) + { + m_error = i18n( "Unknown directive" ); +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n"; +#endif + + m_token = SCANNER_ERROR_TOK; + } + status = TOKEN_END_ST; + } + else + { + scanError( m_char ); + consumed = false; + status = TOKEN_END_ST; + } + break; + case STRING1_ST: + switch( m_char ) + { + case '\n': + case '\r': + consumed = false; + m_error = i18n( "String not terminated" ); + m_token = SCANNER_ERROR_TOK; + status = TOKEN_END_ST; +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n"; +#endif + break; + case '"': +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": String: \"" + << m_svalue << "\"\n"; +#endif + + m_token = STRING_TOK; + status = TOKEN_END_ST; + break; + case '\\': + status = STRINGBS_ST; + addChar( m_char ); + break; + default: + addChar( m_char ); + break; + } + break; + case STRINGBS_ST: + if( ( m_char == '\n' ) || ( m_char == '\r' ) || ( m_char < 0 ) ) + { + consumed = false; + m_error = i18n( "String not terminated" ); +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n"; +#endif + m_token = SCANNER_ERROR_TOK; + status = TOKEN_END_ST; + break; + } + else + { + status = STRING1_ST; + addChar( m_char ); + break; + } + break; + case SLASH_ST: + switch( m_char ) + { + case '/': + status = LINE_COMMENT_FIRST_ST; + break; + case '*': + status = COMMENT_NEW_LINE_ST; + cdepth ++; + break; + default: + consumed = false; + m_token = '/'; + status = TOKEN_END_ST; + } + break; + case LINE_COMMENT_FIRST_ST: + // skip the first space char + if( ( m_char == '\n' ) || ( m_char == '\r' ) || ( m_char < 0 ) ) + { +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": Empty line comment\n"; +#endif + consumed = false; + m_token = LINE_COMMENT_TOK; + status = TOKEN_END_ST; + break; + } + else if( !isspace( m_char ) ) + addChar( m_char ); + status = LINE_COMMENT_ST; + break; + case LINE_COMMENT_ST: + if( ( m_char == '\n' ) || ( m_char == '\r' ) || ( m_char < 0 ) ) + { +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": Line comment: \"" + << m_svalue << "\"\n"; +#endif + consumed = false; + m_token = LINE_COMMENT_TOK; + status = TOKEN_END_ST; + break; + } + else + { + addChar( m_char ); + int l = m_lastChar - m_svalue; + if( l == c_commentNameLength ) + { + if( strcmp( m_svalue, c_commentName ) == 0 ) + { + status = PMNAME_ST; + clearSValue( ); + } + } + if( l == c_commentRawBeginLength ) + { + if( strcmp( m_svalue, c_commentRawBegin ) == 0 ) + { + status = RAW_POVRAY_FIRST_ST; + clearSValue( ); + } + } + break; + } + break; + case COMMENT_NEW_LINE_ST: + // skip any white spaces at begin of line. + if( m_char < 0 ) + { + consumed = false; + m_error = i18n( "Comment not terminated" ); +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n"; +#endif + m_token = SCANNER_ERROR_TOK; + status = TOKEN_END_ST; + } + else if( m_char == '\n' ) + { + addChar( '\n' ); + m_line ++; + } + else if( !isspace( m_char ) ) + { + consumed = false; + status = C_COMMENT_ST; + } + break; + case C_COMMENT_ST: + if( m_char < 0 ) + { + consumed = false; + m_error = i18n( "Comment not terminated" ); +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n"; +#endif + m_token = SCANNER_ERROR_TOK; + status = TOKEN_END_ST; + } + else + { + switch( m_char ) + { + case '*': + status = COMMENT_ST_ST; + break; + case '/': + status = COMMENT_SL_ST; + addChar( m_char ); + break; + case '\n': + addChar( m_char ); + m_line ++; + status = COMMENT_NEW_LINE_ST; + break; + default: + addChar( m_char ); + } + } + break; + case COMMENT_ST_ST: + if( m_char < 0 ) + { + consumed = false; + m_error = i18n( "Comment not terminated" ); +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n"; +#endif + m_token = SCANNER_ERROR_TOK; + status = TOKEN_END_ST; + } + else + { + switch( m_char ) + { + case '/': + cdepth --; + if( cdepth == 0 ) + { +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": Comment: \"" + << m_svalue << "\"\n"; +#endif + m_token = COMMENT_TOK; + status = TOKEN_END_ST; + break; + } + else + { + status = C_COMMENT_ST; + addChar( '*' ); + addChar( '/' ); + break; + } + case '*': + addChar( m_char ); + break; + case '\n': + status = C_COMMENT_ST; + addChar( '*' ); + addChar( m_char ); + m_line ++; + break; + default: + status = C_COMMENT_ST; + addChar( '*' ); + addChar( m_char ); + break; + } + } + break; + case COMMENT_SL_ST: + if( m_char < 0 ) + { + consumed = false; + m_error = i18n( "Comment not terminated" ); +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n"; +#endif + m_token = SCANNER_ERROR_TOK; + status = TOKEN_END_ST; + } + else + { + switch( m_char ) + { + case '/': + addChar( m_char ); + break; + case '*': + status = C_COMMENT_ST; + addChar( m_char ); + cdepth ++; + break; + case '\n': + status = C_COMMENT_ST; + addChar( m_char ); + m_line ++; + break; + default: + status = C_COMMENT_ST; + addChar( m_char ); + } + } + break; + case PMNAME_ST: + if( ( m_char == '\n' ) || ( m_char == '\r' ) || ( m_char < 0 ) ) + { +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": PMName: \"" + << m_svalue << "\"\n"; +#endif + consumed = false; + m_token = PMNAME_TOK; + status = TOKEN_END_ST; + break; + } + else + { + addChar( m_char ); + break; + } + break; + case RAW_POVRAY_FIRST_ST: // skip the first line + if( m_char < 0 ) + { + consumed = false; + m_error = i18n( "Raw povray not terminated" ); +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n"; +#endif + m_token = SCANNER_ERROR_TOK; + status = TOKEN_END_ST; + } + if( m_char == '\n' ) + { + m_line++; + m_rawIndentation = 0; + status = RAW_POVRAY_LB_ST; + } + break; + case RAW_POVRAY_LB_ST: + switch( m_char ) + { + case '\n': + addChar( m_char ); + m_line++; + m_rawIndentation = 0; + // status = RAW_POVRAY_LB_ST; + break; + case ' ': + m_rawIndentation++; + if( m_rawIndentation >= m_indentation ) + status = RAW_POVRAY_ST; + break; + case '\t': + m_rawIndentation += 8 - m_rawIndentation % 8; + if( m_rawIndentation >= m_indentation ) + status = RAW_POVRAY_ST; + break; + default: + consumed = false; + status = RAW_POVRAY_ST; + break; + } + break; + case RAW_POVRAY_ST: + if( m_char < 0 ) + { + consumed = false; + m_error = i18n( "Raw povray not terminated" ); +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n"; +#endif + m_token = SCANNER_ERROR_TOK; + status = TOKEN_END_ST; + } + else if( m_char == '\n' ) + { + addChar( m_char ); + m_line++; + m_rawIndentation = 0; + status = RAW_POVRAY_LB_ST; + } + else if( m_char == '/' ) + { + m_rawPovrayEnd = 1; + status = RAW_POVRAY_END_ST; + } + else + addChar( m_char ); + break; + case RAW_POVRAY_END_ST: + if( m_char < 0 ) + { + consumed = false; + m_error = i18n( "Raw povray not terminated" ); +#ifdef PMSCAN_DEBUG + kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n"; +#endif + m_token = SCANNER_ERROR_TOK; + status = TOKEN_END_ST; + } + else if( m_char != c_commentRawEnd[m_rawPovrayEnd] ) + { + status = RAW_POVRAY_ST; + int i; + for( i = 0; i < m_rawPovrayEnd; i++ ) + addChar( c_commentRawEnd[i] ); + consumed = false; + } + else + { + m_rawPovrayEnd++; + if( m_rawPovrayEnd >= c_commentRawEndLength ) + { + status = RAW_POVRAY_END_END_ST; + if( m_lastChar > m_svalue ) + { + if( *( m_lastChar - 1 ) == '\n' ) + { + m_lastChar--; + *m_lastChar = 0; + } + } + } + } + break; + case RAW_POVRAY_END_END_ST: + if( ( m_char < 0 ) || ( m_char == '\n' ) ) + { + consumed = false; + status = TOKEN_END_ST; + m_token = RAW_POVRAY_TOK; + } + break; + case TOKEN_END_ST: + break; + } + if( consumed ) + nextChar( ); + if( end && ( status != TOKEN_END_ST ) ) + { + status = TOKEN_END_ST; + kdError( PMArea ) << "Error in scanner: No TOKEN_END_ST after EOF\n"; + } + } + + return m_token; +} + +void PMScanner::scanFunction( ) +{ + m_bFunctionMode = true; +} diff --git a/kpovmodeler/pmscanner.h b/kpovmodeler/pmscanner.h new file mode 100644 index 00000000..6a3e8529 --- /dev/null +++ b/kpovmodeler/pmscanner.h @@ -0,0 +1,191 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMSCANNER_H +#define PMSCANNER_H + +#include +#include +#include + +/** + * Dictionary of reserved words for fast lookup + * + * The class @ref PMScanner has two static dictionaries: one for reserved + * words and one for directives. The constructor will insert the items. + */ +class PMReservedWordDict : protected QAsciiDict +{ +public: + /** + * Mode for constructor. + */ + enum PMDictMode { PMDReservedWords, PMDDirectives }; + /** + * Creates a dictionary for povray reserved words or directives. + */ + PMReservedWordDict( PMDictMode mode ); + /** + * Deletes the dictionary + */ + ~PMReservedWordDict( ); + + /** + * Returns the token constant for the key if found, otherwise -1 + */ + int operator[] ( const char* key ) const { return find( key ); } + /** + * Returns the token constant for the key if found, otherwise -1 + */ + int find( const char* key ) const + { + int* result = QAsciiDict::find( key ); + if( result ) + return *result; + return -1; + } +}; + + +/** + * Scanner that scans povray tokens out of a QIODevice + */ +class PMScanner +{ +public: + /** + * Creates a scanner that scans the QIODevice device + */ + PMScanner( QIODevice* device ); + /** + * Deletes the scanner + */ + ~PMScanner( ); + + /** + * Scans the device for the next token. Returns a value of @ref PMToken + * ( > 0xFF ) or a single character + */ + int nextToken( ); + /** + * Returns the current token + */ + int currentToken( ) const { return m_token; } + + /** + * Returns the integer value of the current token if currentToken + * is INTEGER_TOK + */ + int iValue( ) const { return m_ivalue; } + /** + * Returns the double value of the current token if currentToken + * is FLOAT_TOK + */ + double fValue( ) const { return m_fvalue; } + /** + * Returns the string value of the current token if currentToken + * is ID_TOK, COMMENT_TOK, STRING_TOK + */ + const char* sValue( ) const { return m_svalue; } + /** + * Returns the current line number + */ + int currentLine( ) const { return m_line; } + /** + * Returns the error string if current token is SCANNER_ERROR_TOK + */ + QString error( ) const { return m_error; } + /** + * Special parse method for a function statement + */ + void scanFunction( ); + /** + * Returns a pointer to a dictionary with reserved words + */ + static PMReservedWordDict* reservedWords( ) { return &m_reservedWords; } + /** + * Returns a pointer to a dictionary with directives + */ + static PMReservedWordDict* directives( ) { return &m_directives; } +private: + /** + * returns true if c is one of the following characters: + * space, tab, newline, '{', '}', '<', '>', '+', '-', '*', '/', ',', + * '(', ')', '=', '[', ']', ';' + */ + inline bool isseparation( int c ); + /** + * Called on unexpected character + */ + void scanError( int c ); + /** + * Reads the next character out of the device + */ + inline void nextChar( ); + /** + * Adds the char to m_svalue + */ + inline void addChar( char c ); + /** + * Clears m_svalue + */ + inline void clearSValue( ); + + static PMReservedWordDict m_reservedWords; + static PMReservedWordDict m_directives; + + /** + * States for the state machine of the scanner + */ + enum PMScanStates + { + START_ST = 0, ID_ENDST, INTEGER_ENDST, + FLOAT1_ST, FLOAT_ENDST, FLOAT_EXP1_ST, FLOAT_EXP2_ST, FLOAT_EXP_ENDST, + POINT_ST, + DIRECTIVE1_ST, DIRECTIVE_ENDST, + STRING1_ST, STRINGBS_ST, + SLASH_ST, LINE_COMMENT_FIRST_ST, LINE_COMMENT_ST, + C_COMMENT_ST, COMMENT_ST_ST, COMMENT_SL_ST, COMMENT_NEW_LINE_ST, + PMNAME_ST, + RAW_POVRAY_FIRST_ST, RAW_POVRAY_LB_ST, RAW_POVRAY_ST, RAW_POVRAY_END_ST, + RAW_POVRAY_END_END_ST, + TOKEN_END_ST + }; + + QIODevice* m_pDevice; + + int m_char; + int m_token; + int m_ivalue; + double m_fvalue; + char* m_svalue; + char* m_lastChar; + char* m_lastAlloc; + unsigned int m_svalueAlloc; + int m_indentation; + int m_rawIndentation; + int m_rawPovrayEnd; + bool m_bFunctionMode; + + int m_line; + QString m_error; +}; + + +#endif diff --git a/kpovmodeler/pmscene.cpp b/kpovmodeler/pmscene.cpp new file mode 100644 index 00000000..b8de8eef --- /dev/null +++ b/kpovmodeler/pmscene.cpp @@ -0,0 +1,119 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmscene.h" +#include +#include +#include "pmxmlhelper.h" +#include "pmdocumentformat.h" + +const int c_defaultVisibilityLevel = 10; +PMMetaObject* PMScene::s_pMetaObject = 0; +PMObject* createNewScene( PMPart* part ) +{ + return new PMScene( part ); +} + +PMScene::PMScene( PMPart* part ) + : Base( part ) +{ + m_visibilityLevel = c_defaultVisibilityLevel; +} + +PMScene::PMScene( const PMScene& s ) + : Base( s ) +{ + m_visibilityLevel = s.m_visibilityLevel; +} + +PMScene::~PMScene( ) +{ + m_renderModes.setAutoDelete( true ); + m_renderModes.clear( ); +} + +QString PMScene::description( ) const +{ + return i18n( "scene" ); +} + +PMMetaObject* PMScene::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Scene", Base::metaObject( ), + createNewScene ); + } + return s_pMetaObject; +} + +void PMScene::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMScene::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "majorFormat", c_majorDocumentFormat ); + e.setAttribute( "minorFormat", c_minorDocumentFormat ); + e.setAttribute( "visibility_level", m_visibilityLevel ); + QDomElement data = doc.createElement( "extra_data" ); + QDomElement rm; + + PMRenderModeListIterator it( m_renderModes ); + for( ; it.current( ); ++it ) + { + rm = doc.createElement( "rendermode" ); + it.current( )->serialize( rm ); + data.appendChild( rm ); + } + + e.appendChild( data ); + Base::serialize( e, doc ); +} + +void PMScene::readAttributes( const PMXMLHelper& h ) +{ + m_visibilityLevel = h.intAttribute( "visibility_level", c_defaultVisibilityLevel ); + QDomElement e = h.extraData( ); + if( !e.isNull( ) ) + { + QDomNode c = e.firstChild( ); + while( !c.isNull( ) ) + { + if( c.isElement( ) ) + { + QDomElement ce = c.toElement( ); + if( ce.tagName( ) == "rendermode" ) + m_renderModes.append( new PMRenderMode( ce ) ); + } + c = c.nextSibling( ); + } + } + + if( m_renderModes.count( ) > 0 ) + m_renderModes.at( 0 ); + + Base::readAttributes( h ); +} + diff --git a/kpovmodeler/pmscene.h b/kpovmodeler/pmscene.h new file mode 100644 index 00000000..2932c43c --- /dev/null +++ b/kpovmodeler/pmscene.h @@ -0,0 +1,92 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMSCENE_H +#define PMSCENE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmcompositeobject.h" +#include "pmrendermode.h" + +/** + * Class for povray scenes. + * + * A document has a PMScene object as top level object. A PMScene can't have + * a parent + */ +class PMScene : public PMCompositeObject +{ + typedef PMCompositeObject Base; +public: + /** + * Creates an empty PMScene + */ + PMScene( PMPart* part ); + /** + * Copy constructor + */ + PMScene( const PMScene& s ); + /** + * deletes the scene and all objects + */ + virtual ~PMScene( ); + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual PMObject* copy( ) const { return new PMScene( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual QString pixmap( ) const { return QString( "pmscene" ); } + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a pointer to the list of render modes + * @see PMRenderMode + */ + PMRenderModeList* renderModes( ) { return &m_renderModes; } + /** + * Returns the scenes visibility level + */ + int visibilityLevel( ) const { return m_visibilityLevel; } + /** + * Sets the visibility level + */ + void setVisibilityLevel( int l ) { m_visibilityLevel = l; } + +private: + PMRenderModeList m_renderModes; + int m_visibilityLevel; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmserializer.cpp b/kpovmodeler/pmserializer.cpp new file mode 100644 index 00000000..087631cc --- /dev/null +++ b/kpovmodeler/pmserializer.cpp @@ -0,0 +1,93 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmserializer.h" +#include "pmerrorflags.h" +#include "pmdebug.h" + +#include + +unsigned int PMSerializer::s_maxErrors = 30; +unsigned int PMSerializer::s_maxWarnings = 50; + + +PMSerializer::PMSerializer( QIODevice* dev ) +{ + m_pDev = dev; + m_errors = 0; + m_warnings = 0; + m_bFatalError = false; +} + +PMSerializer::~PMSerializer( ) +{ + +} + +void PMSerializer::serializeList( const PMObjectList& objects ) +{ + PMObjectListIterator it( objects ); + for( ; it.current( ); ++it ) + serialize( it.current( ) ); +} + +int PMSerializer::errorFlags( ) const +{ + int result = 0; + if( errors( ) ) + result |= PMEError; + if( warnings( ) ) + result |= PMEWarning; + if( fatal( ) ) + result |= PMEFatal; + return result; +} + +void PMSerializer::printMessage( const QString& type, const QString& msg ) +{ + m_messages += PMMessage( type + ": " + msg ); +} + +void PMSerializer::printError( const QString& msg ) +{ + if( m_errors < s_maxErrors ) + { + printMessage( i18n( "Error" ), msg ); + m_errors++; + } + else if( m_errors == s_maxErrors ) + { + m_messages += PMMessage( i18n( "Maximum of %1 errors reached." ) + .arg( s_maxErrors ) ); + m_errors++; + } +} + +void PMSerializer::printWarning( const QString& msg ) +{ + if( m_warnings < s_maxWarnings ) + { + printMessage( i18n( "Warning" ), msg ); + m_warnings++; + } + else if( m_warnings == s_maxWarnings ) + { + m_messages += PMMessage( i18n( "Maximum of %1 warnings reached." ) + .arg( s_maxWarnings ) ); + m_warnings++; + } +} diff --git a/kpovmodeler/pmserializer.h b/kpovmodeler/pmserializer.h new file mode 100644 index 00000000..73e509d8 --- /dev/null +++ b/kpovmodeler/pmserializer.h @@ -0,0 +1,179 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMSERIALIZER_H +#define PMSERIALIZER_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +class QIODevice; + +#include "pmobject.h" +#include "pmerrordialog.h" + +#include + + +/** + * Class to serialize an object or a list of objects. + * + * Normally you don't have to create instances of this type or subclasses, + * the class @ref PMIOFormat has factory methods to create them. + * + * There is one sub class for each format. + * + * During serialization, errors can occur. These are returned + * by the method @ref errors. + */ +class PMSerializer +{ +public: + /** + * Default constructor + * + * The serialized data will be written to the io device + */ + PMSerializer( QIODevice* dev ); + /** + * Destructor + */ + virtual ~PMSerializer( ); + /** + * Returns the translated description of the format. Should return + * the same string as description( ) of the corresponding + * IO format. + */ + virtual QString description( ) const = 0; + + /** + * Serializes one object to the device + */ + virtual void serialize( PMObject* o ) = 0; + /** + * Serializes a list of objects. The default + * implementation will call serialize( PMObject* ) for each object. + */ + virtual void serializeList( const PMObjectList& objects ); + /** + * Closes the serializer + */ + virtual void close( ) = 0; + + /** + * Returns the messages of the serializer + */ + PMMessageList messages( ) const { return m_messages; } + /** + * Returns true if there were errors during serializing + */ + bool errors( ) const { return m_errors > 0; } + /** + * Returns true if there were warnings during serializing + */ + bool warnings( ) const { return m_warnings > 0; } + /** + * Returns true, if a fatal error occurred + * and it doesn't make sense to continue + */ + bool fatal( ) const { return m_bFatalError; } + /** + * Returns a bitwise combination of @ref PMErrorFlags constants + */ + int errorFlags( ) const; + + /** + * Adds an error to the message string + */ + void printError( const QString& msg ); + /** + * Adds a warning to the message string + */ + void printWarning( const QString& msg ); + /** + * Adds an info to the message string + */ + void printInfo( const QString& msg ); + /** + * Adds the message to the message string. Type is "error", "warning", + * "info" + */ + void printMessage( const QString& type, const QString& msg ); + + /** + * Sets the fatal error flag + */ + void setFatalError( ) { m_bFatalError = true; } + + /** + * returns the maximum number of errors + */ + static unsigned maxErrors( ) { return s_maxErrors; } + /** + * sets the maximum number of errors to m + */ + static void setMaxErrors( unsigned m ) { s_maxErrors = m; } + /** + * returns the maximum number of warnings + */ + static unsigned maxWarnings( ) { return s_maxWarnings; } + /** + * sets the maximum number of warnings to m + */ + static void setMaxWarnings( unsigned m ) { s_maxWarnings = m; } + +protected: + /** + * The assigned IO device for serialization + */ + QIODevice* m_pDev; + +private: + /** + * The serializer output (errors, warnings...) + */ + PMMessageList m_messages; + /** + * A dictionary object -> message + */ + QPtrDict< QPtrList > m_messageDict; + /** + * Number of warnings during parsing + */ + unsigned int m_warnings; + /** + * Number of errors during parsing + */ + unsigned int m_errors; + /** + * Flag for fatal errors + */ + bool m_bFatalError; + + /** + * maximum number of errors + */ + static unsigned int s_maxErrors; + /** + * maximum number of warnings + */ + static unsigned int s_maxWarnings; +}; + +#endif diff --git a/kpovmodeler/pmsettingsdialog.cpp b/kpovmodeler/pmsettingsdialog.cpp new file mode 100644 index 00000000..898719bc --- /dev/null +++ b/kpovmodeler/pmsettingsdialog.cpp @@ -0,0 +1,263 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.org + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#include "pmsettingsdialog.h" + +#include "pmpovraysettings.h" +#include "pmcolorsettings.h" +#include "pmgridsettings.h" +#include "pmobjectsettings.h" +#include "pmpreviewsettings.h" +#include "pmlayoutsettings.h" +#include "pmobjectlibrarysettings.h" +#include "pmpluginsettings.h" +#include "pmopenglsettings.h" + +#include "pmrendermanager.h" +#include "pmdebug.h" + +#include +#include +#include +#include +#include + +//#define KPM_WITH_OBJECT_LIBRARY + +PMSettingsDialogPage::PMSettingsDialogPage( QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ +} + +QSize PMSettingsDialog::s_size = QSize( 640, 400 ); + +PMSettingsDialog::PMSettingsDialog( PMPart* part, QWidget* parent, const char* name ) + : KDialogBase( TreeList, i18n( "Configure" ), Ok | Apply | Cancel | Default, Ok, + parent, name ) +{ + QStringList sl; + QWidget* w = 0; + PMSettingsDialogPage* p = 0; + + m_pPart = part; + + setShowIconsInTreeList( true ); + + sl.clear( ); + sl.append( i18n( "Povray" ) ); + w = addVBoxPage( sl, i18n( "Povray Options" ), + SmallIcon( "pmconfigurepovray", 22 ) ); + p = new PMPovraySettings( w ); + registerPage( w, p ); + + sl.clear( ); + sl.append( i18n( "Graphical View" ) ); + sl.append( i18n( "OpenGL" ) ); + w = addVBoxPage( sl, i18n( "OpenGL Display Settings" ), + SmallIcon( "pmconfigureopengl", 22 ) ); + p = new PMOpenGLSettings( w ); + registerPage( w, p ); + + sl.clear( ); + sl.append( i18n( "Graphical View" ) ); + setFolderIcon( sl, SmallIcon( "pmconfiguregraphicalview", 22 ) ); + sl.append( i18n( "Colors" ) ); + w = addVBoxPage( sl, i18n( "Color Settings" ), + SmallIcon( "pmconfigurecolors", 22 ) ); + p = new PMColorSettings( w ); + registerPage( w, p ); + + sl.clear( ); + sl.append( i18n( "Graphical View" ) ); + sl.append( i18n( "Grid" ) ); + w = addVBoxPage( sl, i18n( "Grid Settings" ), + SmallIcon( "pmconfiguregrid", 22 ) ); + p = new PMGridSettings( w ); + registerPage( w, p ); + + sl.clear( ); + sl.append( i18n( "Graphical View" ) ); + sl.append( i18n( "Objects" ) ); + w = addVBoxPage( sl, i18n( "Display Settings for Objects" ), + SmallIcon( "pmconfigureobjects", 22 ) ); + p = new PMObjectSettings( w ); + registerPage( w, p ); + + sl.clear( ); + sl.append( i18n( "Properties View" ) ); + setFolderIcon( sl, SmallIcon( "pmconfiguredialogview", 22 ) ); + sl.append( i18n( "Texture Preview" ) ); + w = addVBoxPage( sl, i18n( "Display Settings for Texture Previews" ), + SmallIcon( "pmconfiguretexturepreview", 22 ) ); + p = new PMPreviewSettings( w ); + registerPage( w, p ); + + sl.clear( ); + sl.append( i18n( "View Layout" ) ); + w = addVBoxPage( sl, i18n( "Display Settings for View Layouts" ), + SmallIcon( "pmconfigureviewlayout", 22 ) ); + p = new PMLayoutSettings( w ); + registerPage( w, p ); + +#ifdef KPM_WITH_OBJECT_LIBRARY + sl.clear( ); + sl.append( i18n( "Object Libraries" ) ); + w = addVBoxPage( sl, i18n( "Display Settings for Object Libraries" ), + SmallIcon( "pmconfigureobjectlibrary", 22 ) ); + p = new PMObjectLibrarySettings( w ); + registerPage( w, p ); +#endif + +#ifdef KPM_WITH_PLUGINS + sl.clear( ); + sl.append( i18n( "Plugins" ) ); + w = addVBoxPage( sl, i18n( "Plugin Settings" ) ); + p = new PMPluginSettings( w ); + registerPage( w, p ); +#endif + + displaySettings( ); + + resize( s_size ); +} + +void PMSettingsDialog::displaySettings( ) +{ + QValueList::const_iterator it; + for( it = m_pages.begin( ); it != m_pages.end( ); ++it ) + ( *it ).page->displaySettings( ); +} + +void PMSettingsDialog::slotCancel( ) +{ + QDialog::reject( ); +} + +void PMSettingsDialog::slotApply( ) +{ + if( validateData( ) ) + saveSettings( ); +} + +void PMSettingsDialog::slotOk( ) +{ + if( validateData( ) ) + { + saveSettings( ); + QDialog::accept( ); + } +} + +void PMSettingsDialog::slotDefault( ) +{ + int currentPage = activePageIndex( ); + PMSettingsDialogPage* page = 0; + QValueList::const_iterator it; + for( it = m_pages.begin( ); it != m_pages.end( ) && !page; ++it ) + if( ( *it ).index == currentPage ) + page = ( *it ).page; + if( page ) + page->displayDefaults( ); +} + +bool PMSettingsDialog::validateData( ) +{ + bool valid = true; + QValueList::const_iterator it; + for( it = m_pages.begin( ); it != m_pages.end( ) && valid; ++it ) + valid = ( *it ).page->validateData( ); + return valid; +} + +void PMSettingsDialog::saveSettings( ) +{ + m_repaint = false; + + QValueList::const_iterator it; + for( it = m_pages.begin( ); it != m_pages.end( ); ++it ) + ( *it ).page->applySettings( ); + + if( m_repaint ) + { + PMRenderManager* rm = PMRenderManager::theManager( ); + rm->slotRenderingSettingsChanged( ); + } +} + +void PMSettingsDialog::saveConfig( KConfig* cfg ) +{ + cfg->setGroup( "Appearance" ); + cfg->writeEntry( "SettingsDialogSize", s_size ); +} + +void PMSettingsDialog::restoreConfig( KConfig* cfg ) +{ + cfg->setGroup( "Appearance" ); + + QSize defaultSize( 640, 400 ); + s_size = cfg->readSizeEntry( "SettingsDialogSize", &defaultSize ); +} + +void PMSettingsDialog::resizeEvent( QResizeEvent* ev ) +{ + s_size = ev->size( ); +} + +void PMSettingsDialog::registerPage( QWidget* topPage, + PMSettingsDialogPage* page ) +{ + int i = pageIndex( topPage ); + if( i < 0 ) + kdError( PMArea ) << "PMSettingsDialog: Registered settings page" + << " not found" << endl; + else + { + m_pages.push_back( PMRegisteredSettingsPage( topPage, page, i ) ); + connect( page, SIGNAL( repaintViews( ) ), SLOT( slotRepaint( ) ) ); + connect( page, SIGNAL( showMe( ) ), SLOT( slotShowPage( ) ) ); + } +} + +void PMSettingsDialog::slotRepaint( ) +{ + m_repaint = true; +} + +void PMSettingsDialog::slotShowPage( ) +{ + const QObject* w = sender( ); + if( w ) + { + int index = findPage( ( const PMSettingsDialogPage* ) w ); + if( index >= 0 ) + showPage( index ); + } +} + +int PMSettingsDialog::findPage( const PMSettingsDialogPage* p ) +{ + int index = -1; + QValueList::const_iterator it; + for( it = m_pages.begin( ); it != m_pages.end( ) && index < 0; ++it ) + if( ( *it ).page == p ) + index = ( *it ).index; + return index; +} + +#include "pmsettingsdialog.moc" diff --git a/kpovmodeler/pmsettingsdialog.h b/kpovmodeler/pmsettingsdialog.h new file mode 100644 index 00000000..09f00973 --- /dev/null +++ b/kpovmodeler/pmsettingsdialog.h @@ -0,0 +1,187 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMSETTINGSDIALOG_H +#define PMSETTINGSDIALOG_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +class QFrame; +class QCheckBox; +class QLineEdit; +class QListBox; +class QListView; +class QButtonGroup; +class QComboBox; +class KColorButton; +class KConfig; +class PMIntEdit; +class PMFloatEdit; +class PMPart; +class PMViewLayout; +class PMViewLayoutEntry; + +/** + * Base class for configuration dialog pages. + * + * All base classes have to implement the pure virtual + * methods @ref displaySettings, @ref displayDefaults, @ref validateData + * and @ref applySettings + */ +class PMSettingsDialogPage : public QWidget +{ + Q_OBJECT +public: + /** + * Constructor + */ + PMSettingsDialogPage( QWidget* parent, const char* name = 0 ); + /** + * Display the settings here. + * + * Base classes have to implement this method. + */ + virtual void displaySettings( ) = 0; + /** + * Validate the changed data here and return true + * if the data is valid. Display an error message + * and return false otherwise. + * + * Base classes have to implement this method. + */ + virtual bool validateData( ) = 0; + /** + * Make the changes permanent here. + * + * Base classes have to implement this method. + */ + virtual void applySettings( ) = 0; + /** + * Display the default values. + * + * Base classes have to implement this method. + */ + virtual void displayDefaults( ) = 0; +signals: + /** + * Emit this signal if a parameter was changed + * that influences the wire frame rendering. + */ + void repaintViews( ); + /** + * Tells the settings dialog to show this page. + */ + void showMe( ); +}; + + +/** + * Helper class, used internally by @ref PMSettingsDialog + */ +class PMRegisteredSettingsPage +{ +public: + PMRegisteredSettingsPage( ) + { + topPage = 0; + page = 0; + index = 0; + } + PMRegisteredSettingsPage( QWidget* top, PMSettingsDialogPage* p, + int i ) + { + topPage = top; + page = p; + index = i; + } + QWidget* topPage; + PMSettingsDialogPage* page; + int index; +}; + +/** + * Configuration dialog + */ +class PMSettingsDialog : public KDialogBase +{ + Q_OBJECT +public: + /** + * Standard constructor + */ + PMSettingsDialog( PMPart* part, QWidget* parent = 0, const char* name = 0 ); + /** + * Registers a new settings page. + * + * @param topPage The page created with addVBoxPage + * @param page The internal settings page + */ + void registerPage( QWidget* topPage, PMSettingsDialogPage* page ); + + static void saveConfig( KConfig* cfg ); + static void restoreConfig( KConfig* cfg ); + +protected: + virtual void resizeEvent( QResizeEvent* ev ); + +protected slots: + /** + * Validates the data and makes the changes permanent. + */ + virtual void slotApply( ); + /** + * Validates the data, makes the changes permanent and closes the dialog. + */ + virtual void slotOk( ); + /** + * Displays the default values. + */ + virtual void slotDefault( ); + /** + * Closes the dialog without saving the data. + */ + virtual void slotCancel( ); + + /** + * Repaints the opengl views + */ + void slotRepaint( ); + /** + * Shows the sender page + */ + void slotShowPage( ); + +private: + void displaySettings( ); + bool validateData( ); + void saveSettings( ); + int findPage( const PMSettingsDialogPage* page ); + bool m_repaint; + QValueList m_pages; + PMPart* m_pPart; + + static QSize s_size; +}; + +#endif diff --git a/kpovmodeler/pmshell.cpp b/kpovmodeler/pmshell.cpp new file mode 100644 index 00000000..52702492 --- /dev/null +++ b/kpovmodeler/pmshell.cpp @@ -0,0 +1,676 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pmshell.h" +#include "pmpart.h" +#include "pmfactory.h" +#include "pmsettingsdialog.h" +#include "pmdefaults.h" +#include "pmdockwidget.h" + +#include "pmviewfactory.h" +#include "pmviewbase.h" +#include "pmunknownview.h" +#include "pmviewlayoutmanager.h" + +//#define KPM_WITH_OBJECT_LIBRARY + +const int c_statusBarInfo = 0; +const int c_statusBarControlPoints = 1; + +PMShell::PMShell( const KURL& url ) + : PMDockMainWindow( 0, "mainwindow" ) +{ + setPluginLoadingMode( DoNotLoadPlugins ); + setInstance( PMFactory::instance( ), false ); + + m_pPart = new PMPart( this, "part", this, "part", true, this ); + m_pPart->setReadWrite( ); // read-write mode + m_viewNumber = 0; + m_objectsToDelete.setAutoDelete( true ); + + if (!initialGeometrySet()) + resize(800,600); + + setupActions( ); + + restoreOptions( ); + + setupView( ); + setXMLFile( "kpovmodelershell.rc" ); + createGUI( m_pPart ); + + //guiFactory( )->addClient( m_pPart ); + m_pStatusBar = statusBar( ); + m_pStatusBar->insertItem( " ", c_statusBarInfo, 1 ); + m_pStatusBar->insertItem( "" , c_statusBarControlPoints ); + + KConfig* config = instance( )->config( ); + config->setGroup( "Appearance" ); + applyMainWindowSettings( config ); + + if( !url.isEmpty( ) ) + openURL( url ); + + setCaption( url.prettyURL( ) ); + connect( m_pPart, SIGNAL( modified( ) ), SLOT( slotModified( ) ) ); + connect( m_pPart, SIGNAL( controlPointMessage( const QString& ) ), + SLOT( slotControlPointMsg( const QString& ) ) ); +} + +PMShell::~PMShell( ) +{ +} + +void PMShell::setupActions( ) +{ +// m_helpMenu = new KHelpMenu( this, PMFactory::aboutData( ), true, +// actionCollection( ) ); + + KStdAction::openNew( this, SLOT( slotFileNew( ) ), actionCollection( ) ); + KStdAction::open( this, SLOT( slotFileOpen( ) ), actionCollection( ) ); + m_pRecent = KStdAction::openRecent( this, SLOT( slotOpenRecent( const KURL& ) ), + actionCollection( ) ); + KStdAction::save( this, SLOT( slotFileSave( ) ), actionCollection( ) ); + KStdAction::saveAs( this, SLOT( slotFileSaveAs( ) ), actionCollection( ) ); + + KStdAction::revert( this, SLOT( slotFileRevert( ) ), actionCollection( ) ); + KStdAction::print( this, SLOT( slotFilePrint( ) ), actionCollection( ) ); + + KStdAction::close( this, SLOT( slotFileClose( ) ), actionCollection( ) ); + KStdAction::quit( this, SLOT( close( ) ), actionCollection( ) ); + + m_pPathAction = new KToggleAction( i18n( "Show &Path" ), 0, this, + SLOT( slotShowPath( ) ), actionCollection( ), + "options_show_path" ); + m_pPathAction->setCheckedState(i18n("Hide &Path")); + + m_pStatusbarAction = KStdAction::showStatusbar( this, SLOT( slotShowStatusbar( ) ), + actionCollection( ) ); + + KStdAction::saveOptions( this, SLOT( saveOptions( ) ), actionCollection( ) ); + + KStdAction::keyBindings( this, SLOT( slotConfigureKeys( ) ), + actionCollection( ) ); + KStdAction::configureToolbars( this, SLOT( slotConfigureToolbars( ) ), + actionCollection( ) ); + KStdAction::preferences( this, SLOT( slotSettings( ) ), actionCollection( ) ); + + m_pNewTopViewAction = new KAction( i18n( "New Top View" ), 0, this, + SLOT( slotNewTopView( ) ), + actionCollection( ), "view_new_topview" ); + m_pNewBottomViewAction = new KAction( i18n( "New Bottom View" ), 0, this, + SLOT( slotNewBottomView( ) ), + actionCollection( ), "view_new_bottomview" ); + m_pNewLeftViewAction = new KAction( i18n( "New Left View" ), 0, this, + SLOT( slotNewLeftView( ) ), + actionCollection( ), "view_new_leftview" ); + m_pNewRightViewAction = new KAction( i18n( "New Right View" ), 0, this, + SLOT( slotNewRightView( ) ), + actionCollection( ), "view_new_rightview" ); + m_pNewFrontViewAction = new KAction( i18n( "New Front View" ), 0, this, + SLOT( slotNewFrontView( ) ), + actionCollection( ), "view_new_frontview" ); + m_pNewBackViewAction = new KAction( i18n( "New Back View" ), 0, this, + SLOT( slotNewBackView( ) ), + actionCollection( ), "view_new_back_view" ); + m_pNewCameraViewAction = new KAction( i18n( "New Camera View" ), 0, this, + SLOT( slotNewCameraView( ) ), + actionCollection( ), "view_new_cameraview" ); + + m_pNewTreeViewAction = new KAction( i18n( "New Object Tree" ), 0, this, + SLOT( slotNewTreeView( ) ), actionCollection( ), + "view_new_treeview" ); + m_pNewDialogViewAction = new KAction( i18n( "New Properties View" ), 0, this, + SLOT( slotNewDialogView( ) ), actionCollection( ), + "view_new_dialogview" ); + +#ifdef KPM_WITH_OBJECT_LIBRARY + m_pNewLibraryBrowserAction = new KAction( i18n( "New Library Browser" ), 0, this, + SLOT( slotNewLibraryBrowserView( ) ), actionCollection( ), + "view_new_librarybrowser" ); +#endif + + // Creating the view layouts menu + m_pViewLayoutsAction = new KActionMenu( i18n( "View Layouts" ), + actionCollection( ), "view_layouts_menu" ); + KPopupMenu* menu = m_pViewLayoutsAction->popupMenu( ); + connect( menu, SIGNAL( aboutToShow( ) ), SLOT( slotViewsMenuAboutToShow( ) ) ); + PMViewLayoutManager::theManager( )->fillPopupMenu( menu ); + connect( menu, SIGNAL( activated( int ) ), SLOT( slotSelectedLayout( int ) ) ); + + m_pSaveViewLayoutAction = new KAction( i18n( "Save View Layout..." ), 0, this, + SLOT( slotSaveViewLayout( ) ), + actionCollection( ), "save_view_layout" ); +} + +void PMShell::setupView( ) +{ + PMViewLayoutManager::theManager( )->displayDefaultLayout( this ); +} + + +PMDockWidget* PMShell::createView( const QString& t, PMViewOptions* o, + bool initPosition ) +{ + PMDockWidget* dock = 0; + PMViewBase* contents = 0; + + PMViewTypeFactory* factory = + PMViewFactory::theFactory( )->viewFactory( t ); + + m_viewNumber++; + QString name = QString( "View (%1)" ).arg( m_viewNumber ); + + if( factory ) + { + QString desc; + // Create the appropriate dock widget + if( o ) + desc = factory->description( o ); + else + desc = factory->description( ); + + dock = createDockWidget( name, SmallIcon( factory->iconName( ) ), 0L, + desc, desc ); + contents = factory->newInstance( dock, m_pPart ); + if( o ) + contents->restoreViewConfig( o ); + } + else + { + // unknown view type + dock = createDockWidget( name, SmallIcon( "unknown" ), 0L, + i18n( "Unknown" ), i18n( "Unknown" ) ); + contents = new PMUnknownView( t, dock ); + } + + dock->setWidget( contents ); + connect( dock, SIGNAL( headerCloseButtonClicked( ) ), + SLOT( slotDockWidgetClosed( ) ) ); + + if( initPosition ) + { + dock->resize( 300, 400 ); + dock->manualDock( 0, PMDockWidget::DockDesktop, 50, + mapToGlobal( QPoint( 50, 50 ) ) ); + } + return dock; +} + +/* +PMDockWidget* PMShell::createTreeView( ) +{ + PMDockWidget* dock = 0; + m_numTreeViews++; + QString name = QString( "Object Tree (%1)" ).arg( m_numTreeViews ); + dock = createDockWidget( name, SmallIcon( "pmtreeview" ), + 0L, i18n( "Object Tree" ), i18n( "Object Tree" ) ); + dock->setDockSite( PMDockWidget::DockFullSite ); + PMTreeView* tv = new PMTreeView( m_pPart, dock ); + dock->setWidget( tv ); + + connect( dock, SIGNAL( headerCloseButtonClicked( ) ), + SLOT( slotDockWidgetClosed( ) ) ); + + return dock; +} + +PMDockWidget* PMShell::createDialogView( ) +{ + PMDockWidget* dock = 0; + m_numDialogViews++; + QString name = QString( "Object Properties (%1)" ).arg( m_numDialogViews ); + dock = createDockWidget( name, SmallIcon( "pmdialogview" ), + 0L, i18n( "Object Properties" ), i18n( "Object Properties" ) ); + dock->setDockSite( PMDockWidget::DockFullSite ); + PMDialogView* dv = new PMDialogView( m_pPart, dock ); + dock->setWidget( dv ); + + connect( dock, SIGNAL( headerCloseButtonClicked( ) ), + SLOT( slotDockWidgetClosed( ) ) ); + + return dock; +} + +PMDockWidget* PMShell::create3DView( PMGLView::PMViewType t ) +{ + PMDockWidget* dock = 0; + m_numGLViews++; + QString name = QString( "3D View (%1)" ).arg( m_numGLViews ); + dock = createDockWidget( name, SmallIcon( "pmglview" ), + 0L, i18n( "3D View" ), i18n( "3D View" ) ); + dock->setDockSite( PMDockWidget::DockFullSite ); + PMGLView* vgl = new PMGLView( m_pPart, t, dock ); + dock->setWidget( vgl ); + connect( vgl, SIGNAL( viewTypeChanged( const QString& ) ), + dock, SLOT( slotSetCaption( const QString& ) ) ); + dock->slotSetCaption( PMGLView::viewTypeAsString( t ) ); + + connect( dock, SIGNAL( headerCloseButtonClicked( ) ), + SLOT( slotDockWidgetClosed( ) ) ); + + return dock; +} +*/ + +void PMShell::slotNewGraphicalView( PMGLView::PMViewType t ) +{ + PMGLViewOptions* o = new PMGLViewOptions( t ); + createView( "glview", o ); + delete o; +} + +void PMShell::slotNewTopView( ) +{ + slotNewGraphicalView( PMGLView::PMViewNegY ); +} + +void PMShell::slotNewBottomView( ) +{ + slotNewGraphicalView( PMGLView::PMViewPosY ); +} + +void PMShell::slotNewLeftView( ) +{ + slotNewGraphicalView( PMGLView::PMViewPosX ); +} + +void PMShell::slotNewRightView( ) +{ + slotNewGraphicalView( PMGLView::PMViewNegX ); +} + +void PMShell::slotNewFrontView( ) +{ + slotNewGraphicalView( PMGLView::PMViewPosZ ); +} + +void PMShell::slotNewBackView( ) +{ + slotNewGraphicalView( PMGLView::PMViewNegZ ); +} + +void PMShell::slotNewCameraView( ) +{ + slotNewGraphicalView( PMGLView::PMViewCamera ); +} + +void PMShell::slotNewDialogView( ) +{ + createView( "dialogview" ); +} + +void PMShell::slotNewTreeView( ) +{ + createView( "treeview" ); +} + +void PMShell::slotNewLibraryBrowserView( ) +{ + createView( "librarybrowserview" ); +} + +void PMShell::slotDockWidgetClosed( ) +{ + const QObject* o = sender( ); + if( o && o->inherits( "PMDockWidget" ) ) + { + if( m_objectsToDelete.containsRef( o ) == 0 ) + { + m_objectsToDelete.append( o ); + QTimer::singleShot( 0, this, SLOT( slotDeleteClosedObjects( ) ) ); + } + } +} + +void PMShell::slotDeleteClosedObjects( ) +{ + m_objectsToDelete.clear( ); +} + +void PMShell::openURL( const KURL& url ) +{ + m_pRecent->addURL( url ); + + if( !m_pPart->isModified( ) && m_pPart->url( ).isEmpty( ) ) + { + m_pPart->openURL( url ); + setCaption( m_pPart->url( ).prettyURL( ) ); + } + else + { + PMShell *shell = new PMShell( ); + shell->show( ); + shell->openURL( url ); + } +} + +void PMShell::slotOpenRecent( const KURL& url ) +{ + m_openRecentURL = url; + QTimer::singleShot( 0, this, SLOT( slotOpenRecentTimer( ) ) ); +} + +void PMShell::slotOpenRecentTimer( ) +{ + openURL( m_openRecentURL ); +} + +void PMShell::slotFileNew( ) +{ + if( !m_pPart->isModified( ) && m_pPart->url( ).isEmpty( ) ) + { + m_pPart->newDocument( ); + setCaption( ); + } + else + { + PMShell *shell = new PMShell( ); + shell->show( ); + } +} + +void PMShell::slotFileOpen( ) +{ + KURL url = KFileDialog::getOpenURL( + QString::null, QString( "*.kpm|" ) + i18n( "Povray Modeler Files (*.kpm)" ) + + "\n*|" + i18n( "All Files" ) ); + + if( !url.isEmpty( ) ) + openURL( url ); +} + +void PMShell::slotFileSave( ) +{ + m_pPart->slotAboutToSave( ); + + if( m_pPart->isModified( ) ) + { + if( !m_pPart->url( ).isEmpty( ) && + m_pPart->isReadWrite( ) ) + m_pPart->saveAs( m_pPart->url( ) ); + else + saveAs( ); + setCaption( m_pPart->url( ).prettyURL( ) ); + } + else + emit statusMsg( i18n( "No changes need to be saved" ) ); +} + +void PMShell::slotFileSaveAs( ) +{ + m_pPart->slotAboutToSave( ); + saveAs( ); +} + +void PMShell::saveAs( ) +{ + KFileDialog dlg( QString::null, + QString( "*.kpm|" ) + i18n( "Povray Modeler Files (*.kpm)" ) + + QString( "\n*|" ) + i18n( "All Files" ), + 0, "filedialog", true ); + dlg.setCaption( i18n( "Save As" ) ); + dlg.setOperationMode( KFileDialog::Saving ); + dlg.exec( ); + + KURL url = dlg.selectedURL( ); + + if( !url.isEmpty( ) ) + { + if( dlg.currentFilter( ) == QString( "*.kpm" ) ) + if( QFileInfo( url.path( ) ).extension( ).isEmpty( ) ) + url.setPath( url.path( ) + ".kpm" ); + + if( overwriteURL( url ) ) + { + m_pRecent->addURL( url ); + if( m_pPart->saveAs( url ) ) + setCaption( url.prettyURL( ) ); + else + KMessageBox::sorry( this, i18n( "Couldn't save the file." ) ); + } + } +} + +void PMShell::slotFileRevert( ) +{ + KURL url = m_pPart->url( ); + + if( !url.isEmpty( ) ) + m_pPart->openURL( url ); +// else +// slotFileNew( ); +} + +void PMShell::slotFilePrint( ) +{ + //TODO + // m_pPart->slotPrint( ); +} + +void PMShell::slotFileNewWindow( ) +{ + PMShell* shell = new PMShell; + shell->show( ); +} + +void PMShell::slotFileClose( ) +{ + if( m_pPart->closeURL( ) ) + { + m_pPart->closeDocument( ); + m_pPart->newDocument( ); + setCaption( ); + } +} + +void PMShell::slotShowToolbar( ) +{ + if( toolBar( )->isVisible ( ) ) + toolBar( )->hide( ); + else + toolBar( )->show( ); +} + +void PMShell::slotShowStatusbar( ) +{ + if( statusBar( )->isVisible ( ) ) + statusBar( )->hide( ); + else + statusBar( )->show( ); +} + +void PMShell::slotShowPath( ) +{ + setCaption( m_pPart->url( ).prettyURL( ) ); +} + +void PMShell::slotConfigureKeys( ) +{ + KKeyDialog kd; + kd.insert( m_pPart->actionCollection( ) ); + kd.insert( actionCollection( ) ); + kd.configure( true ); + //KKeyDialog::configure( actionCollection( ) ); +} + +void PMShell::slotSettings( ) +{ + PMSettingsDialog dlg( m_pPart ); + dlg.exec( ); +} + +void PMShell::slotConfigureToolbars( ) +{ + saveMainWindowSettings( KGlobal::config( ), "Appearance" ); + KEditToolbar dlg( factory( ) ); + connect( &dlg, SIGNAL( newToolbarConfig( ) ), + this, SLOT( slotNewToolbarConfig( ) ) ); + dlg.exec( ); +} + +void PMShell::slotNewToolbarConfig( ) +{ + createGUI( 0 ); + createShellGUI( false ); + createGUI( m_pPart ); + applyMainWindowSettings( KGlobal::config( ), "Appearance" ); +} + +void PMShell::updateGUI( ) +{ + saveMainWindowSettings( KGlobal::config( ), "Appearance" ); + createGUI( 0 ); + createShellGUI( false ); + createGUI( m_pPart ); + applyMainWindowSettings( KGlobal::config( ), "Appearance" ); +} + +void PMShell::saveOptions( ) +{ + kdDebug( PMArea ) << "Saving configuration" << endl; + KConfig* config = KGlobal::config( ); + + // set group + config->setGroup( "Appearance" ); + config->writeEntry( "ShowStatusbar", m_pStatusbarAction->isChecked( ) ); + saveMainWindowSettings( config ); + m_pRecent->saveEntries( config ); + + if( m_pPart ) + m_pPart->saveConfig( config ); + + config->sync( ); +} + +void PMShell::restoreOptions( ) +{ + KConfig* config = instance( )->config( ); + + // set group + config->setGroup( "Appearance" ); + + bool showStatusbar = config->readBoolEntry( "ShowStatusbar", true ); + + m_pStatusbarAction->blockSignals( true ); + m_pStatusbarAction->setChecked( showStatusbar ); + m_pStatusbarAction->blockSignals( false ); + + if( showStatusbar ) + statusBar( )->show( ); + else + statusBar( )->hide( ); + + m_pRecent->loadEntries( config ); +} + +void PMShell::setCaption( const QString& caption ) +{ + QString tmp; + + if( caption.isEmpty( ) ) + tmp = i18n( "unknown" ); + else + { + if( !m_pPathAction->isChecked( ) ) + tmp = caption.right( caption.length( ) - caption.findRev( '/' ) - 1 ); + else + tmp = caption; + } + + KMainWindow::setCaption( tmp, m_pPart->isModified( ) ); +} + +void PMShell::statusMsg( const QString& text ) +{ + m_pStatusBar->message( text, 5000 ); +} + +bool PMShell::queryClose( ) +{ + saveOptions( ); + return m_pPart->closeURL( ); +} + +void PMShell::showEvent( QShowEvent* ){ + activateDock( ); +} + +void PMShell::slotModified( ) +{ + setCaption( m_pPart->url( ).prettyURL( ) ); +} + +void PMShell::slotControlPointMsg( const QString& msg ) +{ + if( msg.isEmpty( ) ) + m_pStatusBar->changeItem( msg, c_statusBarControlPoints ); + else + m_pStatusBar->changeItem( QString( " " ) + msg + QString( " " ), + c_statusBarControlPoints ); +} + +bool PMShell::overwriteURL( const KURL& u ) +{ + int query = KMessageBox::Continue; + + if( u.isLocalFile( ) ) + { + QFileInfo info; + QString name( u.path( ) ); + info.setFile( name ); + if( info.exists( ) ) + query = KMessageBox::warningContinueCancel( 0, i18n( "A file with this name already exists.\nDo you want to overwrite it?" ), QString::null, i18n("Overwrite") ); + } + return ( query == KMessageBox::Continue ); +} + +void PMShell::slotSelectedLayout( int id ) +{ + QMenuItem* menu = m_pViewLayoutsAction->popupMenu( )->findItem( id ); + PMViewLayoutManager::theManager( )->displayLayout( menu->text( ), this ); +} + +void PMShell::slotSaveViewLayout( ) +{ + PMSaveViewLayoutDialog dlg( this ); + dlg.exec( ); +} + +void PMShell::slotViewsMenuAboutToShow( ) +{ + KPopupMenu* menu = m_pViewLayoutsAction->popupMenu( ); + + PMViewLayoutManager::theManager( )->fillPopupMenu( menu ); +} + +#include "pmshell.moc" diff --git a/kpovmodeler/pmshell.h b/kpovmodeler/pmshell.h new file mode 100644 index 00000000..9a0dbb91 --- /dev/null +++ b/kpovmodeler/pmshell.h @@ -0,0 +1,172 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMSHELL_H +#define PMSHELL_H + +#include "pmdockwidget.h" + +#include "pmpart.h" +#include "pmglview.h" +#include "version.h" + +#include + +//class KHelpMenu; +class KStatusBar; +class KListAction; +class KToggleAction; +class KSelectAction; +class KRecentFilesAction; +class KActionMenu; +class PMViewOptions; + +/** + * Main view for KPovModeler + */ +class PMShell : public PMDockMainWindow +{ + Q_OBJECT + +public: + /** + * Standard constructor + */ + PMShell( const KURL& = KURL( ) ); + /** + * Destructor + */ + virtual ~PMShell( ); + + /** + * Creates the actions + */ + void setupActions( ); + /** + * Creates the docking views + */ + void setupView( ); + /** + * Updates the gui (menus and toolbars) + */ + void updateGUI( ); + + /** + * Checks if a file with that name exists and asks if + * it should be overwritten. + * + * Returns true if the files is not a local file, the file does'n exist + * or the file should be overwritten. + */ + static bool overwriteURL( const KURL& u ); + +public slots: + void openURL( const KURL& ); + void slotOpenRecent( const KURL& ); + void slotOpenRecentTimer( ); + + void slotFileNew( ); + void slotFileOpen( ); + void slotFileSave( ); + void slotFileSaveAs( ); + void slotFileRevert( ); + void slotFilePrint( ); + void slotFileNewWindow( ); + void slotFileClose( ); + + void slotShowToolbar( ); + void slotShowStatusbar( ); + void slotShowPath( ); + void slotConfigureKeys( ); + void slotConfigureToolbars( ); + void slotSettings( ); + void slotNewToolbarConfig( ); + + void slotNewGraphicalView( PMGLView::PMViewType ); + void slotNewTopView( ); + void slotNewBottomView( ); + void slotNewLeftView( ); + void slotNewRightView( ); + void slotNewFrontView( ); + void slotNewBackView( ); + void slotNewCameraView( ); + void slotNewTreeView( ); + void slotNewDialogView( ); + void slotNewLibraryBrowserView( ); + + void saveOptions( ); + void restoreOptions( ); + + void setCaption( const QString& caption = QString::null ); + void statusMsg( const QString& text = QString::null ); + void slotControlPointMsg( const QString& msg = QString::null ); + + void slotModified( ); + void slotDockWidgetClosed( ); + void slotDeleteClosedObjects( ); + void slotSelectedLayout( int id ); + void slotSaveViewLayout( ); + void slotViewsMenuAboutToShow( ); + +protected: + virtual bool queryClose( ); + virtual void showEvent( QShowEvent* ); + void saveAs( ); + +public: + /** + * Creates a dock widget of view type t with custom config c. + * + * If initPosition is true, the widget is docked to the desktop. + */ + PMDockWidget* createView( const QString& t, PMViewOptions* c = 0, + bool initPosition = true ); + //PMDockWidget* createTreeView( ); + //PMDockWidget* createDialogView( ); + //PMDockWidget* create3DView( PMGLView::PMViewType ); + +private: + KRecentFilesAction* m_pRecent; + KToggleAction* m_pToolbarAction; + KToggleAction* m_pStatusbarAction; + KToggleAction* m_pPathAction; + + KAction* m_pNewTreeViewAction; + KAction* m_pNewDialogViewAction; + KAction* m_pNewTopViewAction; + KAction* m_pNewBottomViewAction; + KAction* m_pNewLeftViewAction; + KAction* m_pNewRightViewAction; + KAction* m_pNewFrontViewAction; + KAction* m_pNewBackViewAction; + KAction* m_pNewCameraViewAction; + KAction* m_pNewLibraryBrowserAction; + + KActionMenu* m_pViewLayoutsAction; + KAction* m_pSaveViewLayoutAction; + + KStatusBar* m_pStatusBar; + PMPart* m_pPart; + KURL m_openRecentURL; + + QPtrList m_objectsToDelete; + int m_viewNumber; +}; + +#endif diff --git a/kpovmodeler/pmskysphere.cpp b/kpovmodeler/pmskysphere.cpp new file mode 100644 index 00000000..735c851b --- /dev/null +++ b/kpovmodeler/pmskysphere.cpp @@ -0,0 +1,76 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmskysphere.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmskysphereedit.h" +#include "pmdebug.h" + +#include + +PMMetaObject* PMSkySphere::s_pMetaObject = 0; +PMObject* createNewSkySphere( PMPart* part ) +{ + return new PMSkySphere( part ); +} + +PMSkySphere::PMSkySphere( PMPart* part ) + : Base( part ) +{ +} + +PMSkySphere::PMSkySphere( const PMSkySphere& s ) + : Base( s ) +{ +} + +PMSkySphere::~PMSkySphere( ) +{ +} + +PMMetaObject* PMSkySphere::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "SkySphere", Base::metaObject( ), + createNewSkySphere ); + } + return s_pMetaObject; +} + +void PMSkySphere::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMSkySphere::description( ) const +{ + return i18n( "skysphere" ); +} + +PMDialogEditBase* PMSkySphere::editWidget( QWidget* parent ) const +{ + return new PMSkySphereEdit( parent ); +} + diff --git a/kpovmodeler/pmskysphere.h b/kpovmodeler/pmskysphere.h new file mode 100644 index 00000000..f3799b75 --- /dev/null +++ b/kpovmodeler/pmskysphere.h @@ -0,0 +1,75 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMSKYSPHERE_H +#define PMSKYSPHERE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebase.h" + +/** + * Class for povray skyspheres + */ +class PMSkySphere : public PMTextureBase +{ + typedef PMTextureBase Base; +public: + /** + * Creates an PMSkySphere + */ + PMSkySphere( PMPart* part ); + /** + * Copy constructor + */ + PMSkySphere( const PMSkySphere& s ); + /** + * Deletes the object + */ + virtual ~PMSkySphere( ); + + /** */ + virtual PMObject* copy( ) const { return new PMSkySphere( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** + * Returns a new @ref PMSkySphereEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pmskysphere" ); } + +private: + /** + * IDs for @ref PMMementoData + */ +// enum PMSkySphereMementoID { }; + static PMMetaObject* s_pMetaObject; +}; + + +#endif diff --git a/kpovmodeler/pmskysphereedit.cpp b/kpovmodeler/pmskysphereedit.cpp new file mode 100644 index 00000000..0dc05580 --- /dev/null +++ b/kpovmodeler/pmskysphereedit.cpp @@ -0,0 +1,44 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmskysphereedit.h" +#include "pmskysphere.h" +#include "pmlinkedit.h" + +#include +#include +#include + + +PMSkySphereEdit::PMSkySphereEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMSkySphereEdit::displayObject( PMObject* o ) +{ + if( o->isA( "SkySphere" ) ) + { + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMSkySphereEdit: Can't display object\n"; +} + +#include "pmskysphereedit.moc" diff --git a/kpovmodeler/pmskysphereedit.h b/kpovmodeler/pmskysphereedit.h new file mode 100644 index 00000000..10ef2567 --- /dev/null +++ b/kpovmodeler/pmskysphereedit.h @@ -0,0 +1,58 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMSKYSPHEREEDIT_H +#define PMSKYSPHEREEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebaseedit.h" + +class PMSkySphere; + +/** + * Dialog edit class for @ref PMSkySphere + */ +class PMSkySphereEdit : public PMTextureBaseEdit +{ + Q_OBJECT + typedef PMTextureBaseEdit Base; +public: + /** + * Creates a PMSkySphereEdit with parent and name + */ + PMSkySphereEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + +protected: + /** */ +// virtual void createTopWidgets( ); + /** */ +// virtual void saveContents( ); + +private: + PMSkySphere* m_pDisplayedObject; +}; + + +#endif diff --git a/kpovmodeler/pmslope.cpp b/kpovmodeler/pmslope.cpp new file mode 100644 index 00000000..aa652be9 --- /dev/null +++ b/kpovmodeler/pmslope.cpp @@ -0,0 +1,146 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#include "pmxmlhelper.h" +#include "pmvector.h" +#include "pmslope.h" +#include "pmslopeedit.h" +#include "pmmemento.h" + +#include + +const double heightDefault = 0; +const double slopeDefault = 0; + +PMDefinePropertyClass( PMSlope, PMSlopeProperty ); + +PMMetaObject* PMSlope::s_pMetaObject = 0; +PMObject* createNewSlope( PMPart* part ) +{ + return new PMSlope( part ); +} + +PMSlope::PMSlope( PMPart* part ) + : Base( part ) +{ + m_height = heightDefault; + m_slope = slopeDefault; +} + +PMSlope::PMSlope( const PMSlope& s ) + : Base( s ) +{ + m_height = s.m_height; + m_slope = s.m_slope; +} + +PMSlope::~PMSlope( ) +{ +} + +QString PMSlope::description( ) const +{ + return i18n( "slope" ); +} + +void PMSlope::serialize( QDomElement& e, QDomDocument& /*doc*/ ) const +{ + e.setAttribute( "height", m_height ); + e.setAttribute( "slope", m_slope ); +} + +void PMSlope::readAttributes( const PMXMLHelper& h ) +{ + m_height = h.doubleAttribute( "height", heightDefault ); + m_slope = h.doubleAttribute( "slope", slopeDefault ); +} + +PMMetaObject* PMSlope::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Slope", Base::metaObject( ), + createNewSlope ); + s_pMetaObject->addProperty( + new PMSlopeProperty( "height", &PMSlope::setHeight, &PMSlope::height ) ); + s_pMetaObject->addProperty( + new PMSlopeProperty( "slope", &PMSlope::setSlope, &PMSlope::slope ) ); + } + return s_pMetaObject; +} + +void PMSlope::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMSlope::setHeight( const double c ) +{ + if( c != m_height ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMHeightID, m_height ); + m_height = c; + } +} + +void PMSlope::setSlope( const double c ) +{ + if( c != m_slope ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSlopeID, m_slope ); + m_slope = c; + } +} + +PMDialogEditBase* PMSlope::editWidget( QWidget* parent ) const +{ + return new PMSlopeEdit( parent ); +} + +void PMSlope::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMSlopeID: + setSlope( data->doubleData( ) ); + break; + case PMHeightID: + setHeight( data->doubleData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMSlope::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmslope.h b/kpovmodeler/pmslope.h new file mode 100644 index 00000000..5f89b5b2 --- /dev/null +++ b/kpovmodeler/pmslope.h @@ -0,0 +1,94 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMSLOPE_H +#define PMSLOPE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmobject.h" + +/** + * Class for Repeat Slopes + */ + +class PMSlope : public PMObject +{ + typedef PMObject Base; +public: + /** + * Creates a PMSlope + */ + PMSlope( PMPart* part ); + /** + * Copy constructor + */ + PMSlope( const PMSlope& s ); + /** + * deletes the PMSlope + */ + virtual ~PMSlope( ); + + /** */ + virtual PMObject* copy( ) const { return new PMSlope( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMSlopeEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmslope" ); } + + double height( ) const { return m_height; } + void setHeight( double c ); + double slope( ) const { return m_slope; } + void setSlope( double c ); + + /** */ + virtual void restoreMemento( PMMemento* s ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMSlopeMementoID { PMHeightID, PMSlopeID }; + + double m_height; + double m_slope; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmslopeedit.cpp b/kpovmodeler/pmslopeedit.cpp new file mode 100644 index 00000000..5bfcb88b --- /dev/null +++ b/kpovmodeler/pmslopeedit.cpp @@ -0,0 +1,95 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmslopeedit.h" +#include "pmslope.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" + +#include +#include +#include +#include +#include +#include + + +PMSlopeEdit::PMSlopeEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMSlopeEdit::createTopWidgets( ) +{ + QHBoxLayout* hl; + QGridLayout* gl; + + Base::createTopWidgets( ); + + QLabel* label = new QLabel( i18n( "Height:" ), this ); + m_pHeightEdit = new PMFloatEdit( this ); + hl = new QHBoxLayout( topLayout( ) ); + gl = new QGridLayout( hl, 2, 2 ); + gl->addWidget( label, 0, 0 ); + gl->addWidget( m_pHeightEdit, 0, 1 ); + label = new QLabel( i18n( "Slope:" ), this ); + m_pSlopeEdit = new PMFloatEdit( this ); + gl->addWidget( label, 1, 0 ); + gl->addWidget( m_pSlopeEdit, 1, 1 ); + hl->addStretch( 1 ); + + connect( m_pHeightEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pSlopeEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMSlopeEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Slope" ) ) + { + m_pDisplayedObject = ( PMSlope* ) o; + m_pHeightEdit->setValue( m_pDisplayedObject->height( ) ); + m_pHeightEdit->setReadOnly( m_pDisplayedObject->isReadOnly( ) ); + m_pSlopeEdit->setValue( m_pDisplayedObject->slope( ) ); + m_pSlopeEdit->setReadOnly( m_pDisplayedObject->isReadOnly( ) ); + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMSlopeEdit: Can't display object\n"; +} + +void PMSlopeEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setHeight( m_pHeightEdit->value( ) ); + m_pDisplayedObject->setSlope( m_pSlopeEdit->value( ) ); + } +} + +bool PMSlopeEdit::isDataValid( ) +{ + if( !m_pHeightEdit->isDataValid( ) || + !m_pSlopeEdit->isDataValid( ) ) + return false; + + return Base::isDataValid( ); +} + +#include "pmslopeedit.moc" diff --git a/kpovmodeler/pmslopeedit.h b/kpovmodeler/pmslopeedit.h new file mode 100644 index 00000000..2c4d2af4 --- /dev/null +++ b/kpovmodeler/pmslopeedit.h @@ -0,0 +1,68 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMSLOPEEDIT_H +#define PMSLOPEEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMSlope; +class PMVectorEdit; +class PMIntEdit; +class PMFloatEdit; +class QComboBox; +class QCheckBox; +class QLabel; + +/** + * Dialog edit class for @ref PMSlope. + */ +class PMSlopeEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMSlopeEdit with parent and name + */ + PMSlopeEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMSlope* m_pDisplayedObject; + PMFloatEdit* m_pHeightEdit; + PMFloatEdit* m_pSlopeEdit; +}; + + +#endif diff --git a/kpovmodeler/pmsolidcolor.cpp b/kpovmodeler/pmsolidcolor.cpp new file mode 100644 index 00000000..c067b12d --- /dev/null +++ b/kpovmodeler/pmsolidcolor.cpp @@ -0,0 +1,127 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmsolidcolor.h" + +#include "pmxmlhelper.h" +#include "pmsolidcoloredit.h" +#include "pmmemento.h" + +#include + +const PMColor colorDefault = PMColor( 0.0, 0.0, 0.0, 0.0, 0.0 ); + +PMDefinePropertyClass( PMSolidColor, PMSolidColorProperty ); + +PMMetaObject* PMSolidColor::s_pMetaObject = 0; +PMObject* createNewSolidColor( PMPart* part ) +{ + return new PMSolidColor( part ); +} + +PMSolidColor::PMSolidColor( PMPart* part ) + : Base( part ) +{ + m_color = colorDefault; +} + +PMSolidColor::PMSolidColor( const PMSolidColor& c ) + : Base( c ) +{ + m_color = c.m_color; +} + +PMSolidColor::~PMSolidColor( ) +{ +} + +QString PMSolidColor::description( ) const +{ + return i18n( "solid color" ); +} + +void PMSolidColor::serialize( QDomElement& e, QDomDocument& /*doc*/ ) const +{ + e.setAttribute( "color", m_color.serializeXML( ) ); +} + +void PMSolidColor::readAttributes( const PMXMLHelper& h ) +{ + m_color = h.colorAttribute( "color", colorDefault ); +} + +PMMetaObject* PMSolidColor::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "SolidColor", Base::metaObject( ), + createNewSolidColor ); + s_pMetaObject->addProperty( + new PMSolidColorProperty( "color", &PMSolidColor::setColor, &PMSolidColor::color ) ); + } + return s_pMetaObject; +} + +void PMSolidColor::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMSolidColor::setColor( const PMColor& c ) +{ + if( c != m_color ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMColorID, m_color ); + m_color = c; + } +} + +PMDialogEditBase* PMSolidColor::editWidget( QWidget* parent ) const +{ + return new PMSolidColorEdit( parent ); +} + +void PMSolidColor::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMColorID: + setColor( data->colorData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMSolidColor::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmsolidcolor.h b/kpovmodeler/pmsolidcolor.h new file mode 100644 index 00000000..7a575758 --- /dev/null +++ b/kpovmodeler/pmsolidcolor.h @@ -0,0 +1,97 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMSOLIDCOLOR_H +#define PMSOLIDCOLOR_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmobject.h" +#include "pmcolor.h" + +/** + * Class for solid colors. + */ + +class PMSolidColor : public PMObject +{ + typedef PMObject Base; +public: + /** + * Creates a PMSolidColor + */ + PMSolidColor( PMPart* part ); + /** + * Copy constructor + */ + PMSolidColor( const PMSolidColor& s ); + /** + * deletes the PMSolidColor + */ + virtual ~PMSolidColor( ); + + /** */ + virtual PMObject* copy( ) const { return new PMSolidColor( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMSolidColorEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmsolidcolor" ); } + + /** + * Returns the color + */ + PMColor color( ) const { return m_color; } + /** + * Sets the color + */ + void setColor( const PMColor& c ); + + /** */ + virtual void restoreMemento( PMMemento* s ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMSolidColorMementoID { PMColorID }; + PMColor m_color; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmsolidcoloredit.cpp b/kpovmodeler/pmsolidcoloredit.cpp new file mode 100644 index 00000000..49183582 --- /dev/null +++ b/kpovmodeler/pmsolidcoloredit.cpp @@ -0,0 +1,79 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmsolidcoloredit.h" +#include "pmsolidcolor.h" +#include "pmcoloredit.h" + +#include +#include +#include + + +PMSolidColorEdit::PMSolidColorEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMSolidColorEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* layout = new QHBoxLayout( topLayout( ) ); + m_pColorEdit = new PMColorEdit( true, this ); + QLabel* label = new QLabel( i18n( "Color:" ), this ); + + layout->addWidget( label, 0, AlignTop ); + layout->addWidget( m_pColorEdit ); + + connect( m_pColorEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMSolidColorEdit::displayObject( PMObject* o ) +{ + if( o->isA( "SolidColor" ) ) + { + m_pDisplayedObject = ( PMSolidColor* ) o; + m_pColorEdit->setColor( m_pDisplayedObject->color( ) ); + + m_pColorEdit->setReadOnly( m_pDisplayedObject->isReadOnly( ) ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMSolidColorEdit: Can't display object\n"; +} + +void PMSolidColorEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setColor( m_pColorEdit->color( ) ); + } +} + +bool PMSolidColorEdit::isDataValid( ) +{ + if( !m_pColorEdit->isDataValid( ) ) + return false; + return Base::isDataValid( ); +} + +#include "pmsolidcoloredit.moc" diff --git a/kpovmodeler/pmsolidcoloredit.h b/kpovmodeler/pmsolidcoloredit.h new file mode 100644 index 00000000..57439f92 --- /dev/null +++ b/kpovmodeler/pmsolidcoloredit.h @@ -0,0 +1,62 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMSOLIDCOLOREDIT_H +#define PMSOLIDCOLOREDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMSolidColor; +class PMColorEdit; + +/** + * Dialog edit class for @ref PMSolidColor. + */ +class PMSolidColorEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMSolidColorEdit with parent and name + */ + PMSolidColorEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMSolidColor* m_pDisplayedObject; + PMColorEdit* m_pColorEdit; +}; + + +#endif diff --git a/kpovmodeler/pmsolidobject.cpp b/kpovmodeler/pmsolidobject.cpp new file mode 100644 index 00000000..6907e731 --- /dev/null +++ b/kpovmodeler/pmsolidobject.cpp @@ -0,0 +1,140 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmsolidobject.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" + + +PMDefinePropertyClass( PMSolidObject, PMSolidObjectProperty ); + +PMMetaObject* PMSolidObject::s_pMetaObject = 0; + +PMSolidObject::PMSolidObject( PMPart* part ) + : Base( part ) +{ + m_inverse = false; + m_hollow = PMUnspecified; +} + +PMSolidObject::PMSolidObject( const PMSolidObject& s ) + : Base( s ) +{ + m_inverse = s.m_inverse; + m_hollow = s.m_hollow; +} + +PMSolidObject::~PMSolidObject( ) +{ +} + +PMMetaObject* PMSolidObject::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "SolidObject", Base::metaObject( ) ); + s_pMetaObject->addProperty( + new PMSolidObjectProperty( "inverse", &PMSolidObject::setInverse, &PMSolidObject::inverse ) ); + s_pMetaObject->addProperty( + new PMSolidObjectProperty( "hollow", &PMSolidObject::setHollow, &PMSolidObject::hollow ) ); + } + return s_pMetaObject; +} + +void PMSolidObject::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMSolidObject::serialize( QDomElement& e, QDomDocument& doc ) const +{ + switch( m_hollow ) + { + case PMTrue: + e.setAttribute( "hollow", "1" ); + break; + case PMFalse: + e.setAttribute( "hollow", "0" ); + break; + case PMUnspecified: + break; + } + e.setAttribute( "inverse", m_inverse ); + + Base::serialize( e, doc ); +} + +void PMSolidObject::readAttributes( const PMXMLHelper& h ) +{ + m_hollow = h.threeStateAttribute( "hollow" ); + m_inverse = h.boolAttribute( "inverse", false ); + + Base::readAttributes( h ); +} + +void PMSolidObject::setHollow( PMThreeState h ) +{ + if( m_hollow != h ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMHollowID, m_hollow ); + m_hollow = h; + } +} + +void PMSolidObject::setInverse( bool yes ) +{ + if( m_inverse != yes ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMInverseID, m_inverse ); + m_inverse = yes; + } +} + +void PMSolidObject::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMInverseID: + setInverse( data->boolData( ) ); + break; + case PMHollowID: + setHollow( data->threeStateData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMSolidObject::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmsolidobject.h b/kpovmodeler/pmsolidobject.h new file mode 100644 index 00000000..e497c397 --- /dev/null +++ b/kpovmodeler/pmsolidobject.h @@ -0,0 +1,94 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMSOLIDOBJECT_H +#define PMSOLIDOBJECT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmgraphicalobject.h" + + +/** + * Class for povray solid objects + */ +class PMSolidObject : public PMGraphicalObject +{ + typedef PMGraphicalObject Base; +public: + /** + * Creates an empty PMSolidObject + */ + PMSolidObject( PMPart* part ); + /** + * Copy constructor + */ + PMSolidObject( const PMSolidObject& s ); + + /** + * Deletes the object and all children + */ + virtual ~PMSolidObject( ); + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns the state of the hollow flag. + * Values can be PMTrue, PMFalse, PMUnspecified. + */ + PMThreeState hollow( ) const { return m_hollow; } + /** + * Sets the hollow flag. Values can be PMTrue, PMFalse, PMUnspecified. + */ + void setHollow( PMThreeState h ); + + /** + * Returns the state of the inverse flag. + */ + bool inverse( ) const { return m_inverse; } + /** + * Sets the inverse flag + */ + void setInverse( bool yes ); + + /** */ + virtual void restoreMemento( PMMemento* s ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMSolidObjectMementoID { PMInverseID, PMHollowID }; + + bool m_inverse; + PMThreeState m_hollow; + + static PMMetaObject* s_pMetaObject; +}; + + +#endif diff --git a/kpovmodeler/pmsolidobjectedit.cpp b/kpovmodeler/pmsolidobjectedit.cpp new file mode 100644 index 00000000..e6aa3765 --- /dev/null +++ b/kpovmodeler/pmsolidobjectedit.cpp @@ -0,0 +1,82 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmsolidobjectedit.h" +#include "pmsolidobject.h" + +#include +#include +#include + +PMSolidObjectEdit::PMSolidObjectEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMSolidObjectEdit::createBottomWidgets( ) +{ + m_pInverseButton = new QCheckBox( i18n( "Inverse" ), this ); + m_pHollowButton = new QCheckBox( i18n( "Hollow" ), this ); + + m_pHollowButton->setTristate( true ); + + topLayout( )->addWidget( m_pInverseButton ); + topLayout( )->addWidget( m_pHollowButton ); + + connect( m_pHollowButton, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pInverseButton, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + + Base::createBottomWidgets( ); +} + +void PMSolidObjectEdit::displayObject( PMObject* o ) +{ + if( o->isA( "SolidObject" ) ) + { + bool readOnly = o->isReadOnly( ); + + m_pDisplayedObject = ( PMSolidObject* ) o; + setCheckBox( m_pHollowButton, m_pDisplayedObject->hollow( ) ); + m_pInverseButton->setChecked( m_pDisplayedObject->inverse( ) ); + + m_pHollowButton->setEnabled( !readOnly ); + m_pInverseButton->setEnabled( !readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMSolidObjectEdit: Can't display object\n"; +} + +void PMSolidObjectEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + m_pDisplayedObject->setHollow( checkBoxState( m_pHollowButton ) ); + m_pDisplayedObject->setInverse( m_pInverseButton->isChecked( ) ); + Base::saveContents( ); + } +} + +bool PMSolidObjectEdit::isDataValid( ) +{ + return Base::isDataValid( ); +} + +#include "pmsolidobjectedit.moc" diff --git a/kpovmodeler/pmsolidobjectedit.h b/kpovmodeler/pmsolidobjectedit.h new file mode 100644 index 00000000..3da2da6a --- /dev/null +++ b/kpovmodeler/pmsolidobjectedit.h @@ -0,0 +1,63 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMSOLIDOBJECTEDIT_H +#define PMSOLIDOBJECTEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmgraphicalobjectedit.h" + +class PMSolidObject; +class QCheckBox; + +/** + * Dialog edit class for @ref PMSolidObject. + */ +class PMSolidObjectEdit : public PMGraphicalObjectEdit +{ + Q_OBJECT + typedef PMGraphicalObjectEdit Base; +public: + /** + * Creates a PMSolidObjectEdit with parent and name + */ + PMSolidObjectEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createBottomWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMSolidObject* m_pDisplayedObject; + QCheckBox* m_pHollowButton; + QCheckBox* m_pInverseButton; +}; + + +#endif diff --git a/kpovmodeler/pmsor.cpp b/kpovmodeler/pmsor.cpp new file mode 100644 index 00000000..b7a9f0ef --- /dev/null +++ b/kpovmodeler/pmsor.cpp @@ -0,0 +1,708 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmsor.h" + +#include "pmxmlhelper.h" +#include "pmsoredit.h" +#include "pmmemento.h" +#include "pmviewstructure.h" +#include "pmsorcontrolpoint.h" +#include "pmsplinememento.h" +#include "pmsorsegment.h" +#include "pmdefaults.h" +#include "pmobjectaction.h" + +#include + +const int defaultNumberOfPoints = 4; +const PMVector defaultPoint[defaultNumberOfPoints] = +{ + PMVector( 0.0, 0.0 ), + PMVector( 0.5, 0.3 ), + PMVector( 0.5, 0.7 ), + PMVector( 0.0, 1.0 ) +}; + +const bool defaultSturm = false; +const bool defaultOpen = false; + +int PMSurfaceOfRevolution::s_rSteps = c_defaultSurfaceOfRevolutionRSteps; +int PMSurfaceOfRevolution::s_sSteps = c_defaultSurfaceOfRevolutionSSteps; +int PMSurfaceOfRevolution::s_parameterKey = 0; +PMMetaObject* PMSurfaceOfRevolution::s_pMetaObject = 0; +PMObject* createNewSurfaceOfRevolution( PMPart* part ) +{ + return new PMSurfaceOfRevolution( part ); +} + +PMDefinePropertyClass( PMSurfaceOfRevolution, PMSurfaceOfRevolutionProperty ); + +class PMPointProperty : public PMPropertyBase +{ +public: + PMPointProperty( ) + : PMPropertyBase( "controlPoints", PMVariant::Vector ) + { + m_index = 0; + } + virtual int dimensions( ) const { return 1; } + virtual void setIndex( int /*dimension*/, int index ) + { + m_index = index; + } + virtual int size( PMObject* object, int /*dimension*/ ) const + { + return ( ( PMSurfaceOfRevolution* ) object )->numberOfPoints( ); + } +protected: + virtual bool setProtected( PMObject* obj, const PMVariant& var ) + { + PMSurfaceOfRevolution* p = ( PMSurfaceOfRevolution* ) obj; + QValueList list = p->points( ); + QValueList::Iterator it = list.begin( ); + int i; + PMVector v = var.vectorData( ); + v.resize( 2 ); + + for( i = 0; i < m_index && it != list.end( ); ++i ) + ++it; + // expand the list if necessary + for( ; i < m_index; ++i ) + list.insert( it, v ); + if( it == list.end( ) ) + it = list.insert( it, v ); + else + *it = v; + + p->setPoints( list ); + return true; + } + virtual PMVariant getProtected( const PMObject* obj ) + { + PMSurfaceOfRevolution* p = ( PMSurfaceOfRevolution* ) obj; + QValueList list = p->points( ); + QValueList::ConstIterator it = list.at( m_index ); + + if( it == list.end( ) ) + { + kdError( PMArea ) << "Range error in PMSurfaceOfRevolution::PointProperty::get" << endl; + return PMVariant( ); + } + + return PMVariant( *it ); + } + +private: + int m_index; +}; + +PMSurfaceOfRevolution::PMSurfaceOfRevolution( PMPart* part ) + : Base( part ) +{ + int i; + + for( i = 0; i < defaultNumberOfPoints; ++i ) + m_points.append( defaultPoint[i] ); + m_sturm = defaultSturm; + m_open = defaultOpen; +} + +PMSurfaceOfRevolution::PMSurfaceOfRevolution( const PMSurfaceOfRevolution& s ) + : Base( s ) +{ + m_points = s.m_points; + m_sturm = s.m_sturm; + m_open = s.m_open; +} + +PMSurfaceOfRevolution::~PMSurfaceOfRevolution( ) +{ +} + +QString PMSurfaceOfRevolution::description( ) const +{ + return i18n( "surface of revolution" ); +} + +void PMSurfaceOfRevolution::serialize( QDomElement& e, QDomDocument& doc ) const +{ + QDomElement data = doc.createElement( "extra_data" ); + QDomElement p; + + e.setAttribute( "sturm", m_sturm ); + e.setAttribute( "open", m_open ); + + QValueList::ConstIterator it; + for( it = m_points.begin( ); it != m_points.end( ); ++it ) + { + p = doc.createElement( "point" ); + p.setAttribute( "vector", ( *it ).serializeXML( ) ); + data.appendChild( p ); + } + + e.appendChild( data ); + Base::serialize( e, doc ); +} + +void PMSurfaceOfRevolution::readAttributes( const PMXMLHelper& h ) +{ + m_sturm = h.boolAttribute( "sturm", defaultSturm ); + m_open = h.boolAttribute( "open", defaultOpen ); + + m_points.clear( ); + PMVector v( 2 ); + + QDomElement e = h.extraData( ); + if( !e.isNull( ) ) + { + QDomNode c = e.firstChild( ); + while( !c.isNull( ) ) + { + if( c.isElement( ) ) + { + QDomElement ce = c.toElement( ); + if( ce.tagName( ) == "point" ) + { + QString str = ce.attribute( "vector" ); + if( !str.isNull( ) ) + { + v.loadXML( str ); + m_points.append( v ); + } + } + } + c = c.nextSibling( ); + } + } + + Base::readAttributes( h ); +} + +PMMetaObject* PMSurfaceOfRevolution::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "SurfaceOfRevolution", Base::metaObject( ), + createNewSurfaceOfRevolution ); + s_pMetaObject->addProperty( + new PMSurfaceOfRevolutionProperty( "sturm", &PMSurfaceOfRevolution::setSturm, + &PMSurfaceOfRevolution::sturm ) ); + s_pMetaObject->addProperty( + new PMSurfaceOfRevolutionProperty( "open", &PMSurfaceOfRevolution::setOpen, + &PMSurfaceOfRevolution::open ) ); + s_pMetaObject->addProperty( new PMPointProperty( ) ); + } + return s_pMetaObject; +} + +void PMSurfaceOfRevolution::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMSurfaceOfRevolution::setSturm( bool s ) +{ + if( m_sturm != s ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSturmID, m_sturm ); + m_sturm = s; + } +} + +void PMSurfaceOfRevolution::setOpen( bool o ) +{ + if( m_open != o ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMOpenID, m_open ); + m_open = o; + } +} + +void PMSurfaceOfRevolution::setPoints( const QValueList& points ) +{ + if( m_points != points ) + { + if( m_pMemento ) + ( ( PMSplineMemento* ) m_pMemento )->setSplinePoints( m_points ); + + setViewStructureChanged( ); + m_points = points; + } +} + +PMDialogEditBase* PMSurfaceOfRevolution::editWidget( QWidget* parent ) const +{ + return new PMSurfaceOfRevolutionEdit( parent ); +} + +void PMSurfaceOfRevolution::createMemento( ) +{ + if( m_pMemento ) + delete m_pMemento; + m_pMemento = new PMSplineMemento( this ); +} + +void PMSurfaceOfRevolution::restoreMemento( PMMemento* s ) +{ + PMSplineMemento* m = ( PMSplineMemento* ) s; + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMSturmID: + setSturm( data->boolData( ) ); + break; + case PMOpenID: + setOpen( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMSurfaceOfRevolution::restoreMemento\n"; + break; + } + } + } + if( m->splinePointsSaved( ) ) + setPoints( m->splinePoints( ) ); + + Base::restoreMemento( s ); +} + + +void PMSurfaceOfRevolution::createViewStructure( ) +{ + if( s_sSteps == 0 ) + s_sSteps = c_defaultSurfaceOfRevolutionSSteps; + if( s_rSteps == 0 ) + s_rSteps = c_defaultSurfaceOfRevolutionRSteps; + + int rSteps = (int)( ( (float)s_rSteps / 2 ) * ( displayDetail( ) + 1 ) ); + int sSteps = (int)( ( (float)s_sSteps / 2 ) * ( displayDetail( ) + 1 ) ); + + int np = m_points.count( ); + int i, j, r; + + // calculate number of segments + int ns = np - 3; + + // calculate number of points and lines of the view structure + int vsp = ns * sSteps + 1; + int vsl = ( 2 * vsp - 1 ) * rSteps; + vsp *= rSteps; + + if( m_pViewStructure ) + { + if( m_pViewStructure->points( ).size( ) != ( unsigned ) vsp ) + m_pViewStructure->points( ).resize( vsp ); + if( m_pViewStructure->lines( ).size( ) != ( unsigned ) vsl ) + m_pViewStructure->lines( ).resize( vsl ); + } + else + m_pViewStructure = new PMViewStructure( vsp, vsl ); + + + // calculate the spline segments + QValueList segments; + QValueList::Iterator it1, it2, it3, it4; + it1 = m_points.begin( ); + it2 = it1; ++it2; + it3 = it2; ++it3; + it4 = it3; ++it4; + + for( i = 0; i < ns; ++i, ++it1, ++it2, ++it3, ++it4 ) + segments.append( PMSorSegment( *it1, *it2, *it3, *it4 ) ); + + // create the line array + PMLineArray& lines = m_pViewStructure->lines( ); + int vl = ns * sSteps; + int lb = 0; + for( i = 0; i < vl + 1; ++i ) + { + for( j = 0; j < rSteps - 1; ++j ) + lines[lb+j] = PMLine( lb + j, lb + j + 1 ); + lines[lb+rSteps-1] = PMLine( lb, lb + rSteps - 1 ); + lb += rSteps; + } + int pi = 0; + for( i = 0; i < vl; ++i ) + { + for( j = 0; j < rSteps; ++j ) + { + lines[lb] = PMLine( pi, pi + rSteps ); + ++pi; + ++lb; + } + } + + // calculate the points + PMVector point2, point3; + QValueList::Iterator sit = segments.begin( ); + + double poffset = 1.0 / sSteps; + PMMatrix rot = PMMatrix::rotation( 0.0, M_PI * 2.0 / rSteps, 0.0 ); + PMPointArray& points = m_pViewStructure->points( ); + pi = 0; + + for( i = 0; i < ns; ++i, ++sit ) + { + for( j = 0; j < sSteps; ++j ) + { + point2 = ( *sit ).point( poffset * j ); + point3[0] = point2[0]; + point3[1] = point2[1]; + point3[2] = 0.0; + + for( r = 0; r < rSteps; ++r ) + { + points[pi] = PMPoint( point3 ); + if( r != rSteps - 1 ) + point3.transform( rot ); + ++pi; + } + } + if( i == ns - 1 ) + { + point2 = ( *sit ).point( 1.0 ); + point3[0] = point2[0]; + point3[1] = point2[1]; + point3[2] = 0.0; + + for( r = 0; r < rSteps; ++r ) + { + points[pi] = PMPoint( point3 ); + if( r != rSteps - 1 ) + point3.transform( rot ); + ++pi; + } + } + } +} + +void PMSurfaceOfRevolution::controlPoints( PMControlPointList& list ) +{ + QValueList::Iterator it; + QPtrList tmp1, tmp2; + int i; + + PMSorControlPoint* cp = 0; + + PMSorControlPoint* lastPoint = 0; + cp = 0; + + for( it = m_points.begin( ), i = 0; it != m_points.end( ); ++it, ++i ) + { + lastPoint = cp; + cp = new PMSorControlPoint( lastPoint, *it, PMSorControlPoint::PM2DXY, i, + i18n( "Point %1 (xy)" ).arg( i + 1 ) ); + tmp1.append( cp ); + } + + lastPoint = 0; + cp = 0; + + for( it = m_points.begin( ), i = 0; it != m_points.end( ); ++it, ++i ) + { + lastPoint = cp; + cp = new PMSorControlPoint( lastPoint, *it, PMSorControlPoint::PM2DZY, i, + i18n( "Point %1 (yz)" ).arg( i + 1 ) ); + tmp2.append( cp ); + } + + QPtrListIterator cit1( tmp1 ), cit2( tmp2 ); + + for( ; cit1.current( ) && cit2.current( ); ++cit1, ++cit2 ) + { + ( *cit1 )->setSorLink( *cit2 ); + ( *cit2 )->setSorLink( *cit1 ); + } + for( cit1.toFirst( ); cit1.current( ); ++cit1 ) + list.append( *cit1 ); + for( cit2.toFirst( ); cit2.current( ); ++cit2 ) + list.append( *cit2 ); +} + +void PMSurfaceOfRevolution::controlPointsChanged( PMControlPointList& list ) +{ + PMControlPointListIterator it1( list ), it2( list ); + QValueList::Iterator pit = m_points.begin( ); + PMSorControlPoint* p1; + PMSorControlPoint* p2; + bool firstChange = true; + PMVector lastPoint( 2 ); + int num = list.count( ) / 2; + int pnr = 0; + + for( it2 += num; it2.current( ); ++it1, ++it2, ++pit, ++pnr ) + { + p1 = ( PMSorControlPoint* ) it1.current( ); + p2 = ( PMSorControlPoint* ) it2.current( ); + + if( p1->changed( ) ) + { + if( firstChange ) + { + if( m_pMemento ) + { + PMSplineMemento* m = ( PMSplineMemento* ) m_pMemento; + if( !m->splinePointsSaved( ) ) + m->setSplinePoints( m_points ); + } + firstChange = false; + setViewStructureChanged( ); + } + p2->setPoint( p1->point( ) ); + ( *pit ) = p1->point( ); + } + else if( p2->changed( ) ) + { + if( firstChange ) + { + if( m_pMemento ) + { + PMSplineMemento* m = ( PMSplineMemento* ) m_pMemento; + if( !m->splinePointsSaved( ) ) + m->setSplinePoints( m_points ); + } + firstChange = false; + setViewStructureChanged( ); + } + p1->setPoint( p2->point( ) ); + ( *pit ) = p2->point( ); + } + + if( ( pnr > 1 ) && ( pnr < ( num - 1 ) ) ) + { + if( ( ( *pit )[1] - lastPoint[1] ) < c_sorTolerance ) + { + ( *pit )[1] = lastPoint[1] + c_sorTolerance; + p1->setPoint( *pit ); + p2->setPoint( *pit ); + } + } + if( ( pnr == ( num - 1 ) ) || ( pnr == 2 ) ) + { + QValueList::Iterator hit = pit; + --hit; --hit; + + if( approxZero( ( *hit )[1] - ( *pit )[1], c_sorTolerance ) ) + { + ( *pit )[1] = ( *hit )[1] + c_sorTolerance; + p1->setPoint( *pit ); + p2->setPoint( *pit ); + } + } + + lastPoint = *pit; + } +} + +void PMSurfaceOfRevolution::addObjectActions( const PMControlPointList& /*cp*/, + QPtrList& actions ) +{ + PMObjectAction* a; + + a = new PMObjectAction( s_pMetaObject, PMSplitSegmentID, + i18n( "Add Point" ) ); + actions.append( a ); + + a = new PMObjectAction( s_pMetaObject, PMJoinSegmentsID, + i18n( "Remove Point" ) ); + int np = m_points.count( ); + + if( np < 5 ) + a->setEnabled( false ); + actions.append( a ); +} + +void PMSurfaceOfRevolution::objectActionCalled( const PMObjectAction* action, + const PMControlPointList& cp, + const QPtrList& cpViewPosition, + const PMVector& clickPosition ) +{ + if( action->objectType( ) == s_pMetaObject ) + { + switch( action->actionID( ) ) + { + case PMSplitSegmentID: + splitSegment( cp, cpViewPosition, clickPosition ); + break; + case PMJoinSegmentsID: + joinSegments( cp, cpViewPosition, clickPosition ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMSurfaceOfRevolution::objectActionCalled\n"; + break; + } + } + else + Base::objectActionCalled( action, cp, cpViewPosition, clickPosition ); +} + +void PMSurfaceOfRevolution::splitSegment( const PMControlPointList& /*cp*/, + const QPtrList& cpViewPosition, + const PMVector& clickPosition ) +{ + // find nearest segment + int nump = cpViewPosition.count( ) / 2 - 1; + double abs = 0.0, minabs = 1e10; + int ns = -1; + int i, j; + PMVector mid( 3 ), dist( 2 ); + + QPtrListIterator it1( cpViewPosition ); + QPtrListIterator it2( cpViewPosition ); + ++it2; + + for( j = 0; j < 2; ++j ) + { + ++it1; + ++it2; + for( i = 1; i < ( nump - 1 ); ++i ) + { + mid = ( **it1 + **it2 ) / 2.0; + dist[0] = mid[0]; + dist[1] = mid[1]; + dist -= clickPosition; + abs = dist.abs( ); + + if( ( minabs > abs ) || ( ns < 0 ) ) + { + minabs = abs; + ns = i; + } + ++it1; + ++it2; + } + ++it1; + ++it2; + ++it1; + ++it2; + } + + // add a new segment + QValueList newPoints = m_points; + QValueList::Iterator it = newPoints.at( ( unsigned ) ns ); + PMVector p[4]; + QValueList::Iterator hit = it; + + // calculate the spline segment + --hit; + for( i = 0; i < 4; ++i, ++hit ) + p[i] = *hit; + PMSorSegment segment( p[0], p[1], p[2], p[3] ); + + mid = segment.point( 0.5 ); + if( mid[0] < 0 ) + mid[0] = 0; + ++it; + it = newPoints.insert( it, mid ); + hit = it; + --it; + + for( ; hit != newPoints.end( ); ++it, ++hit ) + if( ( ( *hit )[1] - ( *it )[1] ) < c_sorTolerance ) + ( *hit )[1] = ( *it )[1] + c_sorTolerance; + + setPoints( newPoints ); +} + +void PMSurfaceOfRevolution::joinSegments( const PMControlPointList& /*cp*/, + const QPtrList& cpViewPosition, + const PMVector& clickPosition ) +{ + // find nearest point + int nump = cpViewPosition.count( ) / 2; + + if( nump < 5 ) + { + kdError( PMArea ) << "Not enough points in PMSurfaceOfRevolution::joinSegments\n"; + return; + } + + double abs = 0.0, minabs = 1e10; + int ns = -1; + int i, j; + PMVector* p; + PMVector dist( 2 ); + + QPtrListIterator it1( cpViewPosition ); + + for( j = 0; j < 2; ++j ) + { + for( i = 0; i < nump; ++i ) + { + p = *it1; + dist[0] = (*p)[0]; + dist[1] = (*p)[1]; + dist -= clickPosition; + abs = dist.abs( ); + + if( ( minabs > abs ) || ( ns < 0 ) ) + { + minabs = abs; + ns = i; + } + ++it1; + } + } + + // join two segments + QValueList newPoints = m_points; + QValueList::Iterator it; + + // never remove the first or last point + if( ns == 0 ) + ++ns; + if( ns == ( nump - 1 ) ) + --ns; + it = newPoints.at( ns ); + newPoints.remove( it ); + + setPoints( newPoints ); +} + +void PMSurfaceOfRevolution::setRSteps( int r ) +{ + if( r >= 4 ) + s_rSteps = r; + else + kdDebug( PMArea ) << "PMSurfaceOfRevolution::setRSteps: R must be greater than 3\n"; + ++s_parameterKey; +} + +void PMSurfaceOfRevolution::setSSteps( int s ) +{ + if( s >= 1 ) + s_sSteps = s; + else + kdDebug( PMArea ) << "PMSurfaceOfRevolution::setSSteps: S must be greater than 0\n"; + ++s_parameterKey; +} diff --git a/kpovmodeler/pmsor.h b/kpovmodeler/pmsor.h new file mode 100644 index 00000000..c15b305d --- /dev/null +++ b/kpovmodeler/pmsor.h @@ -0,0 +1,191 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMSOR_H +#define PMSOR_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" +#include "pmvector.h" +#include "pmsorcontrolpoint.h" +#include +#include +#include + +class PMViewStructure; + +/** + * Class for povray sor objects. + */ + +class PMSurfaceOfRevolution : public PMSolidObject +{ + typedef PMSolidObject Base; +public: + /** + * Creates an empty PMSurfaceOfRevolution + */ + PMSurfaceOfRevolution( PMPart* part ); + /** + * Copy constructor + */ + PMSurfaceOfRevolution( const PMSurfaceOfRevolution& s ); + /** + * deletes the PMSurfaceOfRevolution + */ + virtual ~PMSurfaceOfRevolution( ); + + /** */ + virtual PMObject* copy( ) const { return new PMSurfaceOfRevolution( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMSurfaceOfRevolutionEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmsor" ); } + + /** */ + virtual void createMemento( ); + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual void controlPoints( PMControlPointList& list ); + /** */ + virtual void controlPointsChanged( PMControlPointList& list ); + /** */ + virtual bool multipleSelectControlPoints( ) const { return true; } + /** */ + virtual bool hasDisplayDetail( ) const { return true; } + /** */ + virtual void addObjectActions( const PMControlPointList&, + QPtrList& ); + /** */ + virtual void objectActionCalled( const PMObjectAction*, + const PMControlPointList&, + const QPtrList&, + const PMVector& ); + + /** + * Returns the sor points + */ + QValueList points( ) const { return m_points; } + /** + * Sets the spline points + */ + void setPoints( const QValueList& points ); + /** + * Returns the number of spline points + */ + int numberOfPoints( ) const { return m_points.size( ); } + /** + * Returns the sturm flag + */ + bool sturm( ) const { return m_sturm; } + /** + * Sets the sturm flag + */ + void setSturm( bool s ); + /** + * Returns the open flag + */ + bool open( ) const { return m_open; } + /** + * Sets the open flag + */ + void setOpen( bool o ); + + /** + * Sets the number of steps around the y axis + */ + static void setRSteps( int r ); + /** + * Sets the number of subdivisions of one spline segment + */ + static void setSSteps( int v ); + /** + * Returns the number of steps around the y axis + */ + static int rSteps( ) { return s_rSteps; } + /** + * Returns the number of subdivisions of one spline segment + */ + static int sSteps( ) { return s_sSteps; } + +protected: + /** */ + virtual void createViewStructure( ); + /** */ + virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey( ); } + +private: + /** + * Object action. Adds a spline point + */ + void splitSegment( const PMControlPointList& cp, + const QPtrList& cpViewPosition, + const PMVector& clickPosition ); + /** + * Object action. Removes a spline point + */ + void joinSegments( const PMControlPointList& cp, + const QPtrList& cpViewPosition, + const PMVector& clickPosition ); + + void stringToValues( const QString& str ); + QString valuesToString( ) const; + + /** + * IDs for @ref PMMementoData + */ + enum PMSurfaceOfRevolutionMementoID { PMOpenID, PMSturmID }; + /** + * IDs for the object actions + */ + enum PMSurfaceOfRevolutionActionID { PMSplitSegmentID, PMJoinSegmentsID }; + + QValueList m_points; + bool m_sturm; + bool m_open; + + static int s_rSteps; + static int s_sSteps; + static int s_parameterKey; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmsorcontrolpoint.cpp b/kpovmodeler/pmsorcontrolpoint.cpp new file mode 100644 index 00000000..88924d05 --- /dev/null +++ b/kpovmodeler/pmsorcontrolpoint.cpp @@ -0,0 +1,228 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmsorcontrolpoint.h" +#include "pmmath.h" +#include + +PMSorControlPoint::PMSorControlPoint( PMSorControlPoint* prev, + const PMVector& point, + PMSorControlPoint::CPType type, int id, + const QString& description ) + : PMControlPoint( id, description ) +{ + m_point = point; + m_type = type; + m_pPrev = prev; + if( m_pPrev ) + m_pPrev->m_pNext = this; + m_pNext = 0; + m_pSorLink = 0; +} + +void PMSorControlPoint::graphicalChangeStarted( ) +{ + if( m_pPrev && !m_pPrev->m_pPrev && !m_pPrev->selected( ) ) + m_pPrev->graphicalChangeStarted( ); + if( m_pNext && !m_pNext->m_pNext && !m_pNext->selected( ) ) + m_pNext->graphicalChangeStarted( ); + + m_original2DPoint = m_point; + m_originalPoint = to3D( m_point ); +} + +void PMSorControlPoint::graphicalChange( const PMVector& startPoint, + const PMVector& /*viewNormal*/, + const PMVector& endPoint ) +{ + if( !m_pPrev && m_pNext->selected( ) || + !m_pNext && m_pPrev->selected( ) ) + return; + + m_point = to2D( m_originalPoint + endPoint - startPoint ); + + if( m_pSorLink && m_pSorLink->selected( ) ) + { + PMSorControlPoint* ll = m_pSorLink; + PMVector op = ll->to2D( ll->m_originalPoint + endPoint - startPoint ); + + if( ( m_point - m_original2DPoint ).abs( ) < + ( op - ll->m_original2DPoint ).abs( ) ) + m_point = op; + } + + if( m_pPrev && m_pNext ) + { + if( m_pPrev->m_pPrev ) + if( ( m_point[1] - m_pPrev->m_point[1] ) < c_sorTolerance ) + m_point[1] = m_pPrev->m_point[1] + c_sorTolerance; + if( m_pNext->m_pNext ) + if( ( m_pNext->m_point[1] - m_point[1] ) < c_sorTolerance ) + m_point[1] = m_pNext->m_point[1] - c_sorTolerance; + } + if( m_point[0] < 0.0 ) + m_point[0] = 0.0; + + if( m_pPrev && !m_pPrev->m_pPrev ) + { + m_pPrev->m_point = m_point + m_pPrev->m_original2DPoint + - m_original2DPoint; + m_pPrev->setChanged( ); + } + if( m_pNext && !m_pNext->m_pNext ) + { + m_pNext->m_point = m_point + m_pNext->m_original2DPoint + - m_original2DPoint; + m_pNext->setChanged( ); + } +} + +void PMSorControlPoint::snapToGrid( ) +{ + int i; + double d = moveGrid( ); + bool diff = false; + PMVector change( 2 ); + PMSorControlPoint* basePoint = 0; + PMSorControlPoint* linkedPoint = 0; + if( !m_pPrev ) + basePoint = m_pNext; + if( !m_pNext ) + basePoint = m_pPrev; + if( m_pPrev && !m_pPrev->m_pPrev ) + linkedPoint = m_pPrev; + if( m_pNext && !m_pNext->m_pNext ) + linkedPoint = m_pNext; + + if( basePoint && basePoint->selected( ) ) + { + m_point -= basePoint->m_point; + diff = true; + } + + if( !approxZero( d ) ) + { + for( i = 0; i < 2; i++ ) + { + change[i] = -m_point[i]; + m_point[i] = rint( m_point[i] / d ) * d; + change[i] += m_point[i]; + } + } + + if( diff ) + m_point += basePoint->m_point; + + if( linkedPoint ) + { + linkedPoint->m_point += change; + linkedPoint->setChanged( ); + } + + setChanged( ); +} + +PMVector PMSorControlPoint::to2D( const PMVector& v ) const +{ + PMVector result( 2 ); + switch( m_type ) + { + case PM2DXY: + result[0] = v[0]; + result[1] = v[1]; + break; + case PM2DXZ: + result[0] = v[0]; + result[1] = v[2]; + break; + case PM2DYZ: + result[0] = v[1]; + result[1] = v[2]; + break; + case PM2DYX: + result[0] = v[1]; + result[1] = v[0]; + break; + case PM2DZX: + result[0] = v[2]; + result[1] = v[0]; + break; + case PM2DZY: + result[0] = v[2]; + result[1] = v[1]; + break; + } + return result; +} + +PMVector PMSorControlPoint::to3D( const PMVector& vec ) const +{ + PMVector result( 3 ); + switch( m_type ) + { + case PM2DXY: + result[0] = vec[0]; + result[1] = vec[1]; + result[2] = 0.0; + break; + case PM2DXZ: + result[0] = vec[0]; + result[1] = 0.0; + result[2] = vec[1]; + break; + case PM2DYZ: + result[0] = 0.0; + result[1] = vec[0]; + result[2] = vec[1]; + break; + case PM2DYX: + result[1] = vec[0]; + result[0] = vec[1]; + result[2] = 0.0; + break; + case PM2DZX: + result[2] = vec[0]; + result[0] = vec[1]; + result[1] = 0.0; + break; + case PM2DZY: + result[2] = vec[0]; + result[1] = vec[1]; + result[0] = 0.0; + break; + } + return result; +} + +bool PMSorControlPoint::hasExtraLine( ) const +{ + return( !m_pPrev || !m_pNext ); +} + +PMVector PMSorControlPoint::extraLineStart( ) const +{ + return position( ); +} + +PMVector PMSorControlPoint::extraLineEnd( ) const +{ + if( !m_pPrev && m_pNext ) + return m_pNext->position( ); + if( m_pPrev && !m_pNext ) + return m_pPrev->position( ); + return PMVector( 0, 0, 0 ); +} diff --git a/kpovmodeler/pmsorcontrolpoint.h b/kpovmodeler/pmsorcontrolpoint.h new file mode 100644 index 00000000..0d9ec283 --- /dev/null +++ b/kpovmodeler/pmsorcontrolpoint.h @@ -0,0 +1,99 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMSORCONTROLPOINT_H +#define PMSORCONTROLPOINT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmcontrolpoint.h" + +const double c_sorTolerance = 0.0001; + +/** + * Class for free moveable control points + */ +class PMSorControlPoint : public PMControlPoint +{ +public: + /** + * Type enum + */ + enum CPType { PM2DXY, PM2DYX, PM2DXZ, PM2DZX, PM2DYZ, PM2DZY }; + /** + * Creates a PMSorControlPoint with id. Point has to be a 2D vector. + */ + PMSorControlPoint( PMSorControlPoint* prev, + const PMVector& point, CPType type, + int id, const QString& description ); + /** + * Deletes the PMSorControlPoint + */ + virtual ~PMSorControlPoint( ) { }; + + /** */ + virtual PMVector position( ) const { return to3D( m_point ); } + /** + * Sets the 2d coordinates of the control point + */ + void setPoint( const PMVector& newPoint ) { m_point = newPoint; } + /** + * 2d coordinates of the control point + */ + PMVector point( ) const { return m_point; } + /** + * This method is used by the sor object to link + * the control points in the xy and xz plane. These points are + * synchronized if both are selected. + */ + void setSorLink( PMSorControlPoint* p ) { m_pSorLink = p; } + /** + * Returns the linked control point for lathe points + */ + PMSorControlPoint* sorLink( ) const { return m_pSorLink; } + /** */ + virtual void snapToGrid( ); + + /** */ + virtual bool hasExtraLine( ) const; + /** */ + virtual PMVector extraLineStart( ) const; + /** */ + virtual PMVector extraLineEnd( ) const; + +protected: + /** */ + virtual void graphicalChangeStarted( ); + /** */ + virtual void graphicalChange( const PMVector& startPoint, + const PMVector& viewNormal, + const PMVector& endPoint ); +private: + PMVector to2D( const PMVector& v ) const; + PMVector to3D( const PMVector& v ) const; + + PMVector m_point, m_originalPoint, m_original2DPoint; + CPType m_type; + PMSorControlPoint* m_pPrev; + PMSorControlPoint* m_pNext; + PMSorControlPoint* m_pSorLink; +}; + +#endif diff --git a/kpovmodeler/pmsoredit.cpp b/kpovmodeler/pmsoredit.cpp new file mode 100644 index 00000000..b56949e6 --- /dev/null +++ b/kpovmodeler/pmsoredit.cpp @@ -0,0 +1,282 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmsoredit.h" +#include "pmsor.h" +#include "pmvectorlistedit.h" +#include "pmpart.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +PMSurfaceOfRevolutionEdit::PMSurfaceOfRevolutionEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMSurfaceOfRevolutionEdit::createBottomWidgets( ) +{ + topLayout( )->addWidget( new QLabel( i18n( "Spline points:" ), this ) ); + + m_pPoints = new PMVectorListEdit( "u", "v", this ); + connect( m_pPoints, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pPoints, SIGNAL( selectionChanged( ) ), + SLOT( slotSelectionChanged( ) ) ); + QHBoxLayout* hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( m_pPoints, 2 ); + + m_pAddAbove = new QPushButton( this ); + m_pAddAbove->setPixmap( SmallIcon( "pmaddpointabove" ) ); + m_pAddBelow = new QPushButton( this ); + m_pAddBelow->setPixmap( SmallIcon( "pmaddpoint" ) ); + m_pRemove = new QPushButton( this ); + m_pRemove->setPixmap( SmallIcon( "pmremovepoint" ) ); + connect( m_pAddAbove, SIGNAL( clicked( ) ), SLOT( slotAddPointAbove( ) ) ); + connect( m_pAddBelow, SIGNAL( clicked( ) ), SLOT( slotAddPointBelow( ) ) ); + connect( m_pRemove, SIGNAL( clicked( ) ), SLOT( slotRemovePoint( ) ) ); + + QVBoxLayout* bl = new QVBoxLayout( hl ); + bl->addWidget( m_pAddAbove ); + bl->addWidget( m_pAddBelow ); + bl->addWidget( m_pRemove ); + bl->addStretch( 1 ); + + m_pOpen = new QCheckBox( i18n( "type of the object", "Open" ), this ); + topLayout( )->addWidget( m_pOpen ); + connect( m_pOpen, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + m_pSturm = new QCheckBox( i18n( "Sturm" ), this ); + topLayout( )->addWidget( m_pSturm ); + connect( m_pSturm, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + + Base::createBottomWidgets( ); +} + +void PMSurfaceOfRevolutionEdit::displayObject( PMObject* o ) +{ + if( o->isA( "SurfaceOfRevolution" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMSurfaceOfRevolution* ) o; + + m_pOpen->setChecked( m_pDisplayedObject->open( ) ); + m_pOpen->setEnabled( !readOnly ); + m_pSturm->setChecked( m_pDisplayedObject->sturm( ) ); + m_pSturm->setEnabled( !readOnly ); + m_pPoints->setVectors( m_pDisplayedObject->points( ), true ); + updateControlPointSelection( ); + updatePointButtons( ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMSurfaceOfRevolutionEdit: Can't display object\n"; +} + +void PMSurfaceOfRevolutionEdit::updateControlPointSelection( ) +{ + PMControlPointList cp = part( )->activeControlPoints( ); + PMControlPointListIterator it( cp ); + int i; + int np = cp.count( ) / 2; + + if( np == m_pPoints->size( ) ) + { + m_pPoints->blockSelectionUpdates( true ); + bool sb = m_pPoints->signalsBlocked( ); + m_pPoints->blockSignals( true ); + + m_pPoints->clearSelection( ); + for( i = 0; i < np; i++, ++it ) + if( ( *it )->selected( ) ) + m_pPoints->select( i ); + for( i = 0; i < np; i++, ++it ) + if( ( *it )->selected( ) ) + m_pPoints->select( i ); + + m_pPoints->blockSignals( sb ); + m_pPoints->blockSelectionUpdates( false ); + } +} + +void PMSurfaceOfRevolutionEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + m_pDisplayedObject->setPoints( m_pPoints->vectors( ) ); + m_pDisplayedObject->setOpen( m_pOpen->isChecked( ) ); + m_pDisplayedObject->setSturm( m_pSturm->isChecked( ) ); + Base::saveContents( ); + } +} + +bool PMSurfaceOfRevolutionEdit::isDataValid( ) +{ + if( !m_pPoints->isDataValid( ) ) + return false; + + int np = m_pPoints->size( ); + if( np < 4 ) + { + KMessageBox::error( this, i18n( "The surface of revolution object needs at least 4 points." ), + i18n( "Error" ) ); + return false; + } + + QValueList points = m_pPoints->vectors( ); + QValueListIterator it1 = points.begin( ); + QValueListIterator it2 = it1; ++it2; + QValueListIterator it3 = it2; ++it3; + int pnr; + + for( pnr = 0; it3 != points.end( ); ++it1, ++it2, ++it3, pnr++ ) + { + if( ( pnr == 0 ) || ( pnr == ( np - 3 ) ) ) + { + if( approxZero( ( *it1 )[1] - ( *it3 )[1], c_sorTolerance ) ) + { + m_pPoints->setCurrentCell( pnr, 1 ); + KMessageBox::error( this, i18n( "The v coordinate of point %1 and %2 must be different." ) + .arg( pnr + 1 ).arg( pnr + 3 ), + i18n( "Error" ) ); + return false; + } + } + + if( pnr != 0 ) + { + if( ( ( *it2 )[1] - ( *it1 )[1] ) < c_sorTolerance ) + { + m_pPoints->setCurrentCell( pnr + 1, 1 ); + KMessageBox::error( this, i18n( "The v coordinates must be strictly increasing." ), + i18n( "Error" ) ); + return false; + } + } + } + + return Base::isDataValid( ); +} + +void PMSurfaceOfRevolutionEdit::slotAddPointAbove( ) +{ + int index = m_pPoints->currentRow( ); + if( index >= 0 ) + { + QValueList points = m_pPoints->vectors( ); + QValueListIterator it = points.at( index ); + + if( it != points.end( ) ) + { + QValueListIterator it2 = it; + it2--; + PMVector v; + if( it2 == points.end( ) ) + v = *it; + else + v = ( *it + *it2 ) / 2; + + points.insert( it, v ); + m_pPoints->setVectors( points, true ); + updatePointButtons( ); + emit dataChanged( ); + } + } +} + +void PMSurfaceOfRevolutionEdit::slotAddPointBelow( ) +{ + int index = m_pPoints->currentRow( ); + if( index >= 0 ) + { + QValueList points = m_pPoints->vectors( ); + QValueListIterator it = points.at( index ); + + if( it != points.end( ) ) + { + QValueListIterator it2 = it; + it2++; + PMVector v; + if( it2 == points.end( ) ) + v = *it; + else + v = ( *it + *it2 ) / 2; + + points.insert( it2, v ); + m_pPoints->setVectors( points, true ); + m_pPoints->setCurrentCell( index + 1, m_pPoints->currentColumn( ) ); + updatePointButtons( ); + emit dataChanged( ); + } + } +} + +void PMSurfaceOfRevolutionEdit::slotRemovePoint( ) +{ + int row = m_pPoints->currentRow( ); + + if( row >= 0 ) + { + QValueList points = m_pPoints->vectors( ); + QValueListIterator it = points.at( row ); + + if( it != points.end( ) && points.size( ) > 1 ) + { + points.remove( it ); + m_pPoints->setVectors( points, true ); + updatePointButtons( ); + emit dataChanged( ); + } + } +} + +void PMSurfaceOfRevolutionEdit::slotSelectionChanged( ) +{ + PMControlPointList cp = part( )->activeControlPoints( ); + PMControlPointListIterator it( cp ); + int np = cp.count( ) / 2; + int i; + + if( np == m_pPoints->size( ) ) + { + for( i = 0; i < np; i++, ++it ) + ( *it )->setSelected( m_pPoints->isSelected( i ) ); + for( i = 0; i < np; i++, ++it ) + ( *it )->setSelected( m_pPoints->isSelected( i ) ); + emit controlPointSelectionChanged( ); + } + updatePointButtons( ); +} + +void PMSurfaceOfRevolutionEdit::updatePointButtons( ) +{ + int row = m_pPoints->currentRow( ); + m_pAddAbove->setEnabled( row >= 0 ); + m_pAddBelow->setEnabled( row >= 0 ); + m_pRemove->setEnabled( row >= 0 && m_pPoints->size( ) > 4 ); +} + +#include "pmsoredit.moc" diff --git a/kpovmodeler/pmsoredit.h b/kpovmodeler/pmsoredit.h new file mode 100644 index 00000000..eb64be67 --- /dev/null +++ b/kpovmodeler/pmsoredit.h @@ -0,0 +1,86 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMSOREDIT_H +#define PMSOREDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" +#include "pmvectoredit.h" +#include +#include + +class PMSurfaceOfRevolution; +class QVBoxLayout; +class QComboBox; +class QCheckBox; +class QPushButton; +class QLabel; +class PMVectorListEdit; + +/** + * Dialog edit class for @ref PMSurfaceOfRevolution + */ +class PMSurfaceOfRevolutionEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMSurfaceOfRevolutionEdit with parent and name + */ + PMSurfaceOfRevolutionEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + /** */ + virtual void updateControlPointSelection( ); + + /** */ + virtual bool isDataValid( ); + +protected: + /** */ + virtual void createBottomWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + void slotAddPointAbove( ); + void slotAddPointBelow( ); + void slotRemovePoint( ); + void slotSelectionChanged( ); + +private: + void updatePointButtons( ); + + PMSurfaceOfRevolution* m_pDisplayedObject; + PMVectorListEdit* m_pPoints; + QCheckBox* m_pOpen; + QCheckBox* m_pSturm; + QPushButton* m_pAddAbove; + QPushButton* m_pAddBelow; + QPushButton* m_pRemove; +}; + + +#endif diff --git a/kpovmodeler/pmsorsegment.cpp b/kpovmodeler/pmsorsegment.cpp new file mode 100644 index 00000000..966beb2b --- /dev/null +++ b/kpovmodeler/pmsorsegment.cpp @@ -0,0 +1,97 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmsorsegment.h" +#include "pmmath.h" +#include "pmmatrix.h" +#include "pmdebug.h" +#include + +PMVector PMSorSegment::point( double t ) const +{ + t = m_t + t * m_s; + double r2 = t * ( t * ( t * m_a + m_b ) + m_c ) + m_d; + if( r2 < 0.0 ) + r2 = 0.0; + + return PMVector( sqrt( r2 ), t ); +} + +void PMSorSegment::calculateSor( const PMVector& p0, const PMVector& p1, + const PMVector& p2, const PMVector& p3 ) +{ + double b[4], h; + PMMatrix m; + + m_t = p1[1]; + m_s = p2[1] - p1[1]; + + if( approxZero( p2[1] - p0[1] ) || approxZero( p3[1] - p1[1] ) ) + { + kdError( PMArea ) << "Incorrect points in PMSorSegment::calculateSor\n"; + m_a = m_b = m_c = m_d = 0.0; + return; + } + + // interpolate the points + // see povray documentation + + b[0] = p1[0] * p1[0]; + b[1] = p2[0] * p2[0]; + b[2] = 2.0 * p1[0] * ( p2[0] - p0[0] ) / ( p2[1] - p0[1] ); + b[3] = 2.0 * p2[0] * ( p3[0] - p1[0] ) / ( p3[1] - p1[1] ); + + h = p1[1]; + + m[0][0] = h * h * h; + m[0][1] = h * h; + m[0][2] = h; + m[0][3] = 1.0; + + m[2][0] = 3.0 * h * h; + m[2][1] = 2.0 * h; + m[2][2] = 1.0; + m[2][3] = 0.0; + + h = p2[1]; + + m[1][0] = h * h * h; + m[1][1] = h * h; + m[1][2] = h; + m[1][3] = 1.0; + + m[3][0] = 3.0 * h * h; + m[3][1] = 2.0 * h; + m[3][2] = 1.0; + m[3][3] = 0.0; + + // Calculate the coefficients + // x = M^-1 * b; + + m = m.inverse( ); + + m_a = b[0] * m[0][0] + b[1] * m[0][1] + b[2] * m[0][2] + b[3] * m[0][3]; + m_b = b[0] * m[1][0] + b[1] * m[1][1] + b[2] * m[1][2] + b[3] * m[1][3]; + m_c = b[0] * m[2][0] + b[1] * m[2][1] + b[2] * m[2][2] + b[3] * m[2][3]; + m_d = b[0] * m[3][0] + b[1] * m[3][1] + b[2] * m[3][2] + b[3] * m[3][3]; + + if( approxZero( m_a ) ) m_a = 0.0; + if( approxZero( m_b ) ) m_b = 0.0; + if( approxZero( m_c ) ) m_c = 0.0; + if( approxZero( m_d ) ) m_d = 0.0; +} diff --git a/kpovmodeler/pmsorsegment.h b/kpovmodeler/pmsorsegment.h new file mode 100644 index 00000000..f0c5a2ea --- /dev/null +++ b/kpovmodeler/pmsorsegment.h @@ -0,0 +1,77 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMSORSEGMENT_H +#define PMSORSEGMENT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmvector.h" + +/** + * Helper class for sors + * + * Each instance of this class represents one sor segment. A point + * on the segment is given by the equation + * + * fi(t) = A[i] * t^3 + B[i] * t^2 + C[i] * t + D[i] + * + * with t ranging from 0 to 1. + */ +class PMSorSegment +{ +public: + /** + * Standard constructor + */ + PMSorSegment( ) + { + m_a = m_b = m_c = m_d = 0.0; + } + /** + * Constructor that calculates the segment + */ + PMSorSegment( const PMVector& p0, const PMVector& p1, + const PMVector& p2, const PMVector& p3 ) + { + calculateSor( p0, p1, p2, p3 ); + } + + /** + * Returns a 2D vector with the point on the sor segment + */ + PMVector point( double t ) const; + /** + * Returns the gradient on the sor + */ + //PMVector gradient( double t ) const; + + /** + * Calculates the sor parameters + */ + void calculateSor( const PMVector& p0, const PMVector& p1, + const PMVector& p2, const PMVector& p3 ); +private: + double m_a, m_b, m_c, m_d; + double m_t, m_s; +}; + +#endif diff --git a/kpovmodeler/pmsphere.cpp b/kpovmodeler/pmsphere.cpp new file mode 100644 index 00000000..698b5352 --- /dev/null +++ b/kpovmodeler/pmsphere.cpp @@ -0,0 +1,411 @@ +/* +************************************************************************** + pmsphere.cpp - description + ------------------- + copyright : (C) 2001 by Philippe Van Hecke + email : lephiloux@tiscalinet.be + copyright : (C) 2001-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmsphere.h" + +#include "pmxmlhelper.h" +#include "pmsphereedit.h" +#include "pmmemento.h" +#include "pm3dcontrolpoint.h" +#include "pmdistancecontrolpoint.h" +#include "pmdefaults.h" + +#include + +/** default param for the sphere */ +const double c_defaultRadius = 0.5; +const PMVector c_defaultCentre = PMVector( 0, 0, 0 ); + +/** default sphere structure */ +PMViewStructure* PMSphere::s_pDefaultViewStructure = 0; + +int PMSphere::s_vStep = c_defaultSphereVSteps; +int PMSphere::s_uStep = c_defaultSphereUSteps; +int PMSphere::s_parameterKey = 0; + +PMDefinePropertyClass( PMSphere, PMSphereProperty ); + +PMMetaObject* PMSphere::s_pMetaObject = 0; +PMObject* createNewSphere( PMPart* part ) +{ + return new PMSphere( part ); +} + +PMSphere::PMSphere( PMPart* part ) + : Base( part ) +{ + m_radius = c_defaultRadius; + m_centre = c_defaultCentre; +} + +PMSphere::PMSphere( const PMSphere& s ) + : Base( s ) +{ + m_radius = s.m_radius; + m_centre = s.m_centre; +} + +PMSphere::~PMSphere( ) +{ +} + + +QString PMSphere::description( ) const +{ + return i18n( "sphere" ); +} + +PMMetaObject* PMSphere::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Sphere", Base::metaObject( ), + createNewSphere ); + s_pMetaObject->addProperty( + new PMSphereProperty( "radius", &PMSphere::setRadius, &PMSphere::radius ) ); + s_pMetaObject->addProperty( + new PMSphereProperty( "center", &PMSphere::setCentre, &PMSphere::centre ) ); + } + return s_pMetaObject; +} + +void PMSphere::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "centre", m_centre.serializeXML( ) ); + e.setAttribute( "radius", m_radius ); + Base::serialize( e, doc ); +} + +void PMSphere::readAttributes( const PMXMLHelper& h ) +{ + m_centre = h.vectorAttribute( "centre", c_defaultCentre ); + m_radius = h.doubleAttribute( "radius", c_defaultRadius ); + Base::readAttributes( h ); +} + +PMDialogEditBase* PMSphere::editWidget( QWidget* parent ) const +{ + + return new PMSphereEdit( parent ); +} + +void PMSphere::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMRadiusID: + setRadius( data->doubleData( ) ); + break; + case PMCentreID: + setCentre( data->vectorData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PSphere::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); + +} + +void PMSphere::controlPoints( PMControlPointList& list ) +{ + PM3DControlPoint* p = new PM3DControlPoint( m_centre, PMCentreID, + i18n( "Center" ) ); + list.append( p ); + list.append( new PMDistanceControlPoint( p, PMVector( 1.0, 0.0, 0.0 ), + m_radius, PMRadiusID, + i18n( "Radius (x)" ) ) ); + list.append( new PMDistanceControlPoint( p, PMVector( 0.0, 1.0, 0.0 ), + m_radius, PMRadiusID, + i18n( "Radius (y)" ) ) ); + list.append( new PMDistanceControlPoint( p, PMVector( 0.0, 0.0, 1.0 ), + m_radius, PMRadiusID, + i18n( "Radius (z)" ) ) ); +} + +void PMSphere::controlPointsChanged( PMControlPointList& list ) +{ + PMControlPoint* p; + bool radiusChanged = false; + + for( p = list.first( ); p; p = list.next( ) ) + { + if( p->changed( ) ) + { + switch( p->id( ) ) + { + case PMCentreID: + setCentre( ( ( PM3DControlPoint* ) p )->point( ) ); + break; + case PMRadiusID: + setRadius( ( ( PMDistanceControlPoint* ) p )->distance( ) ); + radiusChanged = true; + break; + default: + kdError( PMArea ) << "Wrong ID in PMSphere::controlPointsChanged\n"; + break; + } + } + } + + if( radiusChanged ) + for( p = list.first( ); p; p = list.next( ) ) + if( p->id( ) == PMRadiusID ) + ( ( PMDistanceControlPoint* ) p )->setDistance( m_radius ); +} + +bool PMSphere::isDefault( ) +{ + if( ( m_radius == c_defaultRadius ) && ( m_centre == c_defaultCentre ) && globalDetail( ) ) + return true; + return false; +} + +void PMSphere::createViewStructure( ) +{ + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultViewStructure( ) ); + m_pViewStructure->points( ).detach( ); + } + + int uStep = (int)( ( (float)s_uStep / 2 ) * ( displayDetail( ) + 1 ) ); + int vStep = (int)( ( (float)s_vStep / 2 ) * ( displayDetail( ) + 1 ) ); + unsigned ptsSize = vStep * ( uStep - 1 ) + 2; + unsigned lineSize = vStep * ( uStep - 1 ) * 2 + vStep; + unsigned faceSize = vStep * uStep; + + if( ptsSize != m_pViewStructure->points( ).size( ) ) + m_pViewStructure->points( ).resize( ptsSize ); + + createPoints( m_pViewStructure->points( ), m_centre, m_radius, uStep, vStep ); + + if( lineSize != m_pViewStructure->lines( ).size( ) ) + { + m_pViewStructure->lines( ).detach( ); + m_pViewStructure->lines( ).resize( lineSize ); + createLines( m_pViewStructure->lines( ), uStep, vStep ); + } + + if( faceSize != m_pViewStructure->faces( ).size( ) ) + { + m_pViewStructure->faces( ).resize( faceSize ); + createFaces( m_pViewStructure->faces( ), uStep, vStep ); + } +} + +PMViewStructure* PMSphere::defaultViewStructure( ) const +{ + if( !s_pDefaultViewStructure || s_pDefaultViewStructure->parameterKey( ) != viewStructureParameterKey( ) ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + int uStep = (int)( ( (float)s_uStep / 2 ) * ( globalDetailLevel( ) + 1 ) ); + int vStep = (int)( ( (float)s_vStep / 2 ) * ( globalDetailLevel( ) + 1 ) ); + + s_pDefaultViewStructure = + new PMViewStructure( vStep * ( uStep - 1 ) + 2, + vStep * ( uStep - 1 ) * 2 + vStep, + vStep * uStep ); + + // points + createPoints( s_pDefaultViewStructure->points( ), c_defaultCentre, + c_defaultRadius, uStep, vStep ); + //lines + createLines( s_pDefaultViewStructure->lines( ), uStep, vStep ); + + //faces + createFaces( s_pDefaultViewStructure->faces( ), uStep, vStep ); + } + + return s_pDefaultViewStructure; +} + +void PMSphere::createFaces( PMFaceArray& faces, int uStep, int vStep ) +{ + int u, v, offsetPt1, offsetPt2, offsetFace; + + offsetPt1 = vStep * ( uStep - 1 ) + 1; + offsetPt2 = vStep * ( uStep - 2 ) + 1; + offsetFace = vStep * ( uStep - 1 ); + for( v = 0; v < vStep - 1; ++v ) + { + faces[v] = PMFace( 0, v + 2, v + 1 ); + faces[ offsetFace + v ] = PMFace( offsetPt1, v + offsetPt2, v + offsetPt2 + 1 ); + } + + faces[ vStep - 1 ] = PMFace( 0, 1, vStep ); + faces[ offsetFace + vStep - 1 ] = PMFace( offsetPt1, vStep + offsetPt2 - 1, offsetPt2 ); + + offsetFace = vStep; + for( u = 0; u < ( uStep - 2 ); ++u ) + { + offsetPt1 = ( u * vStep ) + 1; + offsetPt2 = ( ( u + 1 ) * vStep ) + 1; + for( v = 0; v < ( vStep - 1 ); ++v ) + faces[ offsetFace + v ] = PMFace( v + offsetPt1, v + offsetPt1 + 1, v + offsetPt2 + 1, v + offsetPt2 ); + faces[ offsetFace + vStep - 1 ] = PMFace( offsetPt1 + vStep - 1, offsetPt1, offsetPt2, offsetPt2 + vStep - 1 ); + offsetFace += vStep; + } +} + +void PMSphere::createLines( PMLineArray& lines, int uStep, int vStep ) +{ + int u, v; + int offset = 0; + + // horizontal lines + for( u = 0; u < ( uStep - 1 ); u++ ) + { + for( v = 0; v < ( vStep - 1 ); v++ ) + lines[offset + v] = + PMLine( u * vStep + v + 1, u * vStep + v + 2 ); + lines[offset + vStep - 1] = + PMLine( u * vStep + 1, u * vStep + vStep ); + + offset += vStep; + } + + // vertical lines + // lines at the "north pole" + for( v = 0; v < vStep; v++ ) + lines[offset + v] = PMLine( 0, v + 1 ); + offset += vStep; + + for( v = 0; v < vStep; v++ ) + { + for( u = 0; u < ( uStep - 2 ); u++ ) + { + lines[offset + u] = + PMLine( u * vStep + v + 1, ( u + 1 ) * vStep + v + 1 ); + } + offset += ( uStep - 2 ); + } + // lines at the "south pole" + for( v = 0; v < vStep; v++ ) + lines[offset + v] = PMLine( ( uStep - 2 ) * vStep + v + 1, + ( uStep - 1 ) * vStep + 1 ); + // offset += s_vStep; +} + +void PMSphere::createPoints( PMPointArray& points, const PMVector& centre, double radius, + int uStep, int vStep ) +{ + double l_UradStep = M_PI / uStep; + double l_VradStep = ( 2.0 * M_PI ) / vStep; + double l_u = l_UradStep; + int u, v; + + points[0] = PMPoint( centre + PMVector( 0, radius, 0 ) ); + points[ vStep * ( uStep - 1 ) + 1] = PMPoint( centre - PMVector( 0, radius, 0 ) ); + + for( u = 0; u < ( uStep - 1 ); u++ ) + { + double l_v = 0.0; + double l_rcosu = radius * sin( l_u ); + double y = ( radius * cos( l_u ) ) + centre[1]; + for( v = 0; v < vStep ; v++ ) + { + + double x = ( l_rcosu * cos( l_v ) ) + centre[0]; + double z = ( l_rcosu * sin( l_v ) ) + centre[2]; + + points[u * vStep + v + 1] = PMPoint( x, y, z ); + l_v = l_v + l_VradStep; + } + l_u = l_u + l_UradStep; + } +} + +void PMSphere::setRadius( double radius ) +{ + if( m_radius != radius ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRadiusID, m_radius ); + m_radius = radius; + setViewStructureChanged( ); + } +} + +void PMSphere::setCentre( const PMVector& centre ) +{ + if( m_centre != centre ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMCentreID, m_centre ); + m_centre = centre; + setViewStructureChanged( ); + } +} + +void PMSphere::setUSteps( int u ) +{ + if( u >= 2 ) + { + s_uStep = u; + if( s_pDefaultViewStructure ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + } + } + else + kdDebug( PMArea ) << "PMSPhere::setUSteps: U must be greater than 1\n"; + s_parameterKey++; +} + +void PMSphere::setVSteps( int v ) +{ + if( v >= 4 ) + { + s_vStep = v; + if( s_pDefaultViewStructure ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + } + } + else + kdDebug( PMArea ) << "PMSphere::setVSteps: V must be greater than 3\n"; + s_parameterKey++; +} + +void PMSphere::cleanUp( ) const +{ + if( s_pDefaultViewStructure ) + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} diff --git a/kpovmodeler/pmsphere.h b/kpovmodeler/pmsphere.h new file mode 100644 index 00000000..876fd103 --- /dev/null +++ b/kpovmodeler/pmsphere.h @@ -0,0 +1,165 @@ +//-*-C++-*- +/* +************************************************************************** + pmsphere.h - description + ------------------- + copyright : (C) 2001 by Philippe Van Hecke + email : lephiloux@tiscalinet.be + and : (C) 2001-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMSPHERE_H +#define PMSPHERE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" +#include "pmvector.h" +#include "pmviewstructure.h" + +/** + * Class for povray sphere. + */ +class PMSphere : public PMSolidObject +{ + typedef PMSolidObject Base; + +public: + /** + * Create an empty Sphere + */ + PMSphere( PMPart* part ); + /** + * Copy constructor + */ + PMSphere( const PMSphere& s ); + /** + * Delete the PMSphere + */ + virtual ~PMSphere( ); + + /** */ + virtual PMObject* copy( ) const { return new PMSphere( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMSphereEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmsphere" ); } + + /** + * Returns the centre of the sphere + */ + PMVector centre( ) const { return m_centre; } + /** + * Set the centre of the sphere + */ + void setCentre( const PMVector& centre ); + /** + * returns the radius of the sphere + */ + double radius( ) const { return m_radius; } + /** + * Sets the radius of the sphere + */ + void setRadius( double radius ); + + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual void controlPoints( PMControlPointList& list ); + /** */ + virtual void controlPointsChanged( PMControlPointList& list ); + /** */ + virtual bool hasDisplayDetail( ) const { return true; } + + /** + * Sets the number of latitutes + */ + static void setUSteps( int u ); + /** + * Sets the number of longitudes + */ + static void setVSteps( int v ); + /** + * Returns the number or latitutes + */ + static int uSteps( ) { return s_uStep; } + /** + * Returns the number or longitudes + */ + static int vSteps( ) { return s_vStep; } + /** */ + virtual void cleanUp( ) const; + +protected: + /** */ + virtual bool isDefault( ); + /** */ + virtual void createViewStructure( ); + /** */ + virtual PMViewStructure* defaultViewStructure( ) const; + /** */ + virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey(); } + +private: + /** + * Creates the faces for the view structure + */ + static void createFaces( PMFaceArray& faces, int uStep, int vStep ); + /** + * Creates the lines for the view structure + */ + static void createLines( PMLineArray& lines, int uStep, int vStep ); + /** + * Creates the points for the view structure + */ + static void createPoints( PMPointArray& points, const PMVector& centre, + double radius, int uStep, int vStep ); + + enum PMSphereMementoID { PMRadiusID, PMCentreID }; + /** + * Radius of the sphere + */ + double m_radius; + /** + * centre of the sphere + */ + PMVector m_centre; + + static PMViewStructure* s_pDefaultViewStructure; + static int s_vStep; + static int s_uStep; + static int s_parameterKey; + + static PMMetaObject* s_pMetaObject; +}; + + +#endif diff --git a/kpovmodeler/pmsphereedit.cpp b/kpovmodeler/pmsphereedit.cpp new file mode 100644 index 00000000..cb46d513 --- /dev/null +++ b/kpovmodeler/pmsphereedit.cpp @@ -0,0 +1,95 @@ +/* +************************************************************************** + + pmsphereedit.cpp - description + ------------------- + begin : Wed Jun 6 2001 + copyright : (C) 2001 by Philippe Van Hecke + email : lephiloux@tiscalinet.be +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#include "pmsphereedit.h" +#include "pmsphere.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" + +#include +#include +#include + +PMSphereEdit::PMSphereEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMSphereEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* layout; + + m_pCentre = new PMVectorEdit( "x", "y", "z", this ); + m_pRadius = new PMFloatEdit( this ); + + layout = new QHBoxLayout( topLayout( ) ); + layout->addWidget( new QLabel( i18n( "Center:" ), this ) ); + layout->addWidget( m_pCentre ); + + layout = new QHBoxLayout( topLayout( ) ); + layout->addWidget( new QLabel( i18n( "Radius:" ), this ) ); + layout->addWidget( m_pRadius ); + layout->addStretch( 1 ); + + connect( m_pCentre, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pRadius, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMSphereEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Sphere" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMSphere* ) o; + + m_pCentre->setVector( m_pDisplayedObject->centre( ) ); + m_pRadius->setValue( m_pDisplayedObject->radius( ) ); + + m_pCentre->setReadOnly( readOnly ); + m_pRadius->setReadOnly( readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMSphereEdit: Can't display object\n"; +} + +void PMSphereEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setCentre( m_pCentre->vector( ) ); + m_pDisplayedObject->setRadius( m_pRadius->value( ) ); + } +} + +bool PMSphereEdit::isDataValid( ) +{ + if( m_pCentre->isDataValid( ) ) + if( m_pRadius->isDataValid( ) ) + return Base::isDataValid( ); + return false; +} + + +#include "pmsphereedit.moc" diff --git a/kpovmodeler/pmsphereedit.h b/kpovmodeler/pmsphereedit.h new file mode 100644 index 00000000..9cd64d86 --- /dev/null +++ b/kpovmodeler/pmsphereedit.h @@ -0,0 +1,64 @@ +/* +************************************************************************** + + pmsphereedit.h - description + ------------------- + begin : Wed Jun 6 2001 + copyright : (C) 2001 by Philippe Van Hecke + email : lephiloux@tiscalinet.be +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#ifndef PMSPHEREEDIT_H +#define PMSPHEREEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" + +class PMSphere; +class PMVectorEdit; +class PMFloatEdit ; + +/** + * Dialog edit class for @ref PMSphere + */ +class PMSphereEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMSphereEdit with parent and name + */ + PMSphereEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMSphere* m_pDisplayedObject; + PMVectorEdit* m_pCentre; + PMFloatEdit* m_pRadius; +}; + + +#endif diff --git a/kpovmodeler/pmspheresweep.cpp b/kpovmodeler/pmspheresweep.cpp new file mode 100644 index 00000000..f65a029e --- /dev/null +++ b/kpovmodeler/pmspheresweep.cpp @@ -0,0 +1,894 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmspheresweep.h" + +#include "pmxmlhelper.h" +#include "pmspheresweepedit.h" +#include "pmmemento.h" +#include "pmviewstructure.h" +#include "pm3dcontrolpoint.h" +#include "pmdistancecontrolpoint.h" +#include "pmsplinememento.h" +#include "pmdefaults.h" +#include "pmenumproperty.h" +#include "pmobjectaction.h" +#include "pmpoint.h" +#include "pmmatrix.h" + +#include + +const int defaultNumberOfPoints = 2; +const PMVector defaultPoint[defaultNumberOfPoints] = +{ + PMVector( 0.0, 1.0, 0.0 ), + PMVector( 0.0, 0.0, 0.0 ) +}; +const double defaultRadii[defaultNumberOfPoints] = +{ + 0.3, 0.5 +}; + +const double defaultTolerance = 1e-6; +const PMSphereSweep::SplineType defaultSplineType = PMSphereSweep::LinearSpline; + +PMDefinePropertyClass( PMSphereSweep, PMSphereSweepProperty ); +PMDefineEnumPropertyClass( PMSphereSweep, PMSphereSweep::SplineType, PMSplineTypeProperty ); + +PMMetaObject* PMSphereSweep::s_pMetaObject = 0; +PMObject* createNewSphereSweep( PMPart* part ) +{ + return new PMSphereSweep( part ); +} + +int PMSphereSweep::s_rSteps = c_defaultSphereSweepRSteps; +int PMSphereSweep::s_sSteps = c_defaultSphereSweepSSteps; +int PMSphereSweep::s_parameterKey = 0; + + +/** + * Memento for @ref PMLathe + */ +class PMSphereSweepMemento : public PMSplineMemento +{ +public: + /** + * Creates a memento for the object originator + */ + PMSphereSweepMemento( PMObject* originator ) + : PMSplineMemento( originator ) + { + m_bRadiiSaved = false; + } + /** + * Deletes the memento + */ + virtual ~PMSphereSweepMemento( ) { }; + + /** + * Saves the radii + */ + void setRadii( const QValueList& r ) + { + if( !m_bRadiiSaved ) + { + // Direct assignment does not work with Qt 2.3.x + // The list will be changed later in a graphical + // change because QValueList::detach( ) is called + // too late! + // Copy the list by hand. + + QValueList::ConstIterator it = r.begin( ); + for( ; it != r.end( ); ++it ) + m_radii.append( *it ); + + m_bRadiiSaved = true; + addChange( PMCData ); + } + } + /** + * Returns the radii + */ + QValueList radii( ) const + { + if( !m_bRadiiSaved ) + kdError( PMArea ) << "Radii points not saved in PMSphereSweepMemento::radii\n"; + return m_radii; + } + /** + * Returns true if the spline points were saved + */ + bool radiiSaved( ) const { return m_bRadiiSaved; } + +private: + /** + * The stored radii + */ + QValueList m_radii; + bool m_bRadiiSaved; +}; + + +PMSphereSweep::PMSphereSweep( PMPart* part ) + : Base( part ) +{ + int i; + + for( i = 0; i < defaultNumberOfPoints; i++ ) + { + m_points.append( defaultPoint[i] ); + m_radii.append( defaultRadii[i] ); + } + m_splineType = defaultSplineType; + m_tolerance = defaultTolerance; +} + +PMSphereSweep::PMSphereSweep( const PMSphereSweep& l ) + : Base( l ) +{ + m_points = l.m_points; + m_radii = l.m_radii; + m_splineType = l.m_splineType; + m_tolerance = l.m_tolerance; +} + +PMSphereSweep::~PMSphereSweep( ) +{ +} + +QString PMSphereSweep::description( ) const +{ + return i18n( "sphere sweep" ); +} + +void PMSphereSweep::serialize( QDomElement& e, QDomDocument& doc ) const +{ + QDomElement data = doc.createElement( "extra_data" ); + QDomElement p; + + e.setAttribute( "spline_type", m_splineType ); + e.setAttribute( "tolerance", m_tolerance ); + + QValueList::ConstIterator it; + QValueList::ConstIterator it2; + for( it = m_points.begin( ), it2 = m_radii.begin( ); + it != m_points.end( ) && it2 != m_radii.end( ); ++it, ++it2 ) + { + p = doc.createElement( "point" ); + p.setAttribute( "vector", ( *it ).serializeXML( ) ); + p.setAttribute( "radius", *it2 ); + data.appendChild( p ); + } + + e.appendChild( data ); + Base::serialize( e, doc ); +} + +void PMSphereSweep::readAttributes( const PMXMLHelper& h ) +{ + m_splineType = ( SplineType ) h.intAttribute( "spline_type", defaultSplineType ); + m_tolerance = h.doubleAttribute( "tolerance", defaultTolerance ); + + m_points.clear( ); + m_radii.clear( ); + PMVector v( 3 ); + + QDomElement e = h.extraData( ); + if( !e.isNull( ) ) + { + QDomNode c = e.firstChild( ); + while( !c.isNull( ) ) + { + if( c.isElement( ) ) + { + QDomElement ce = c.toElement( ); + if( ce.tagName( ) == "point" ) + { + QString str = ce.attribute( "vector" ); + if( !str.isNull( ) ) + { + v.loadXML( str ); + m_points.append( v ); + QString str = ce.attribute( "radius" ); + m_radii.append( str.toDouble( ) ); + } + } + } + c = c.nextSibling( ); + } + } + + Base::readAttributes( h ); +} + +PMMetaObject* PMSphereSweep::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "SphereSweep", Base::metaObject( ), + createNewSphereSweep ); + s_pMetaObject->addProperty( + new PMSphereSweepProperty( "tolerance", &PMSphereSweep::setTolerance, &PMSphereSweep::tolerance ) ); + PMSplineTypeProperty* p = new PMSplineTypeProperty( + "splineType", &PMSphereSweep::setSplineType, &PMSphereSweep::splineType ); + p->addEnumValue( "LinearSpline", LinearSpline ); + p->addEnumValue( "BSpline", BSpline ); + p->addEnumValue( "CubicSpline", CubicSpline ); + s_pMetaObject->addProperty( p ); + //s_pMetaObject->addProperty( new PMPointProperty( ) ); + } + return s_pMetaObject; +} + +void PMSphereSweep::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMSphereSweep::setSplineType( PMSphereSweep::SplineType t ) +{ + if( m_splineType != t ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSplineTypeID, ( int ) m_splineType ); + setViewStructureChanged( ); + m_splineType = t; + } +} + +void PMSphereSweep::setTolerance( double t ) +{ + if( m_tolerance != t ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMToleranceID, m_tolerance ); + m_tolerance = t; + } +} + +void PMSphereSweep::setPoints( const QValueList& points ) +{ + if( m_points != points ) + { + if( m_pMemento ) + ( ( PMSplineMemento* ) m_pMemento )->setSplinePoints( m_points ); + + setViewStructureChanged( ); + m_points = points; + } +} + +void PMSphereSweep::setRadii( const QValueList& radii ) +{ + if( m_radii != radii ) + { + if( m_pMemento ) + ( ( PMSphereSweepMemento* ) m_pMemento )->setRadii( m_radii ); + + setViewStructureChanged( ); + m_radii = radii; + } +} + +PMDialogEditBase* PMSphereSweep::editWidget( QWidget* parent ) const +{ + return new PMSphereSweepEdit( parent ); +} + +void PMSphereSweep::createMemento( ) +{ + if( m_pMemento ) + delete m_pMemento; + m_pMemento = new PMSphereSweepMemento( this ); +} + +void PMSphereSweep::restoreMemento( PMMemento* s ) +{ + PMSphereSweepMemento* m = ( PMSphereSweepMemento* ) s; + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMSplineTypeID: + setSplineType( ( SplineType ) data->intData( ) ); + break; + case PMToleranceID: + setTolerance( data->doubleData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMSphereSweep::restoreMemento\n"; + break; + } + } + } + if( m->splinePointsSaved( ) ) + setPoints( m->splinePoints( ) ); + if( m->radiiSaved( ) ) + setRadii( m->radii( ) ); + + Base::restoreMemento( s ); +} + + +void PMSphereSweep::createViewStructure( ) +{ + int numSegments = 0; + int numSpheres = m_points.size( ); + m_segments.clear( ); + + int rSteps = (int)( ( (float)s_rSteps / 2 ) * ( displayDetail( ) + 1 ) ); + int sSteps = (int)( ( (float)s_sSteps / 2 ) * ( displayDetail( ) + 1 ) ); + + switch ( m_splineType ) + { + case LinearSpline: + numSegments = numSpheres - 1; + setLinear( sSteps ); + break; + case BSpline: + numSegments = numSpheres - 3; + setCurved( false, sSteps ); + break; + case CubicSpline: + numSegments = numSpheres - 3; + setCurved( true, sSteps ); + break; + } + + //Calculates sphere points + int numPoints = ( ( rSteps * ( rSteps - 2 ) ) + 2 ) * + ( numSegments + 1 ); + //Calculates segments points + numPoints += ( rSteps * sSteps ) * numSegments; + + //Calculates sphere lines + int numLines = ( rSteps * ( rSteps + rSteps - 3 ) ) * + ( numSegments + 1 ); + //Calculates segments lines + numLines += ( ( sSteps * rSteps ) + + ( ( sSteps - 1 ) * rSteps ) ) * numSegments; + + if ( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( numPoints, numLines ); + } + else + { + m_pViewStructure->points( ).resize( numPoints ); + m_pViewStructure->lines( ).resize( numLines ); + } + + PMPointArray& points = m_pViewStructure->points( ); + PMLineArray& lines = m_pViewStructure->lines( ); + m_nextPoint = m_nextLine = 0; + + PMVector v1, v2; + double rotval = M_PI / ( rSteps / 2 ); + + createSphere( m_segments[0].points[0], m_segments[0].radii[0], rSteps ); + for ( int i = 0; i < numSegments; ++i ) + { + for ( int j = 0; j < sSteps; ++ j ) + { + v1 = m_segments[i].points[sSteps] - m_segments[i].points[0]; + v1 = PMVector::cross( m_segments[i].direction[j], v1.orthogonal( ) ); + v1 = ( v1 * ( 1 / v1.abs( ) ) ) * m_segments[i].radii[j]; + + for ( int k = 0; k < rSteps; ++k ) + { + v2 = PMMatrix::rotation( m_segments[i].direction[j], + ( rotval * k ) ) * v1; + points[m_nextPoint++] = PMPoint( v2 + m_segments[i].points[j] ); + if ( k < ( rSteps - 1 ) ) + lines[m_nextLine++] = PMLine( + m_nextPoint - 1, m_nextPoint ); + else + lines[m_nextLine++] = PMLine( + m_nextPoint - 1, m_nextPoint - rSteps ); + + if ( j < ( sSteps - 1 ) ) + { + lines[m_nextLine++] = PMLine( + m_nextPoint - 1, m_nextPoint + ( rSteps - 1 ) ); + } + } + } + createSphere( m_segments[i].points[sSteps - 1], + m_segments[i].radii[sSteps - 1], rSteps ); + } +} + +void PMSphereSweep::controlPoints( PMControlPointList& list ) +{ + QValueList::Iterator it; + QValueList::Iterator it2; + int i, nr; + + for( it = m_points.begin( ), it2 = m_radii.begin( ), nr = 1, i = 0; + it != m_points.end( ) && it2 != m_radii.end( ); ++it, ++it2, ++nr ) + { + PM3DControlPoint* p = new PM3DControlPoint( *it, i++, + i18n( "Center %1" ).arg( nr ) ); + list.append( p ); + list.append( new PMDistanceControlPoint( p, PMVector( 1.0, 0.0, 0.0 ), + *it2, i++, + i18n( "Radius %1 (x)" ).arg( nr ), + true ) ); + list.append( new PMDistanceControlPoint( p, PMVector( 0.0, 1.0, 0.0 ), + *it2, i++, + i18n( "Radius %1 (y)" ).arg( nr ), + true ) ); + list.append( new PMDistanceControlPoint( p, PMVector( 0.0, 0.0, 1.0 ), + *it2, i++, + i18n( "Radius %1 (z)" ).arg( nr ), + true ) ); + } +} + +void PMSphereSweep::controlPointsChanged( PMControlPointList& list ) +{ + PMControlPointListIterator it1( list ); + QValueList::Iterator pit = m_points.begin( ); + QValueList::Iterator rit = m_radii.begin( ); + int i; + PM3DControlPoint* p; + PMDistanceControlPoint* r; + bool firstChange = true; + + for( ; it1.current( ) && pit != m_points.end( ) && rit != m_radii.end( ); + ++pit, ++rit ) + { + p = ( PM3DControlPoint* ) it1.current( ); + if( p->changed( ) ) + { + if( firstChange ) + { + firstChange = false; + setViewStructureChanged( ); + } + if( m_pMemento ) + { + PMSphereSweepMemento* m = ( PMSphereSweepMemento* ) m_pMemento; + if( !m->splinePointsSaved( ) ) + m->setSplinePoints( m_points ); + } + ( *pit ) = p->point( ); + } + ++it1; + + for( i = 0; i < 3 && it1.current( ); i++ ) + { + r = ( PMDistanceControlPoint* ) it1.current( ); + if( r->changed( ) ) + { + if( firstChange ) + { + firstChange = false; + setViewStructureChanged( ); + } + if( m_pMemento ) + { + PMSphereSweepMemento* m = ( PMSphereSweepMemento* ) m_pMemento; + if( !m->radiiSaved( ) ) + m->setRadii( m_radii ); + } + ( *rit ) = r->distance( ); + } + ++it1; + } + } + + for( it1.toFirst( ), rit = m_radii.begin( ); rit != m_radii.end( ); ++rit ) + { + ++it1; + for( i = 0; i < 3; ++i, ++it1 ) + ( ( PMDistanceControlPoint* ) *it1 )->setDistance( *rit ); + } +} + +void PMSphereSweep::addObjectActions( const PMControlPointList& /*cp*/, + QPtrList& actions ) +{ + PMObjectAction* a; + + a = new PMObjectAction( s_pMetaObject, PMSplitSegmentID, + i18n( "Add Sphere" ) ); + actions.append( a ); + + a = new PMObjectAction( s_pMetaObject, PMJoinSegmentsID, + i18n( "Remove Sphere" ) ); + int np = m_points.count( ); + int minp = 2; + switch( m_splineType ) + { + case LinearSpline: + minp = 2; + break; + case BSpline: + minp = 4; + break; + case CubicSpline: + minp = 4; + break; + } + + if( np < minp ) + a->setEnabled( false ); + actions.append( a ); +} + +void PMSphereSweep::objectActionCalled( const PMObjectAction* action, + const PMControlPointList& cp, + const QPtrList& cpViewPosition, + const PMVector& clickPosition ) +{ + if( action->objectType( ) == s_pMetaObject ) + { + switch( action->actionID( ) ) + { + case PMSplitSegmentID: + splitSegment( cp, cpViewPosition, clickPosition ); + break; + case PMJoinSegmentsID: + joinSegments( cp, cpViewPosition, clickPosition ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMSphereSweep::objectActionCalled\n"; + break; + } + } + else + Base::objectActionCalled( action, cp, cpViewPosition, clickPosition ); +} + +void PMSphereSweep::splitSegment( const PMControlPointList& /*cp*/, + const QPtrList& cpViewPosition, + const PMVector& clickPosition ) +{ + // find nearest segment + int nump = cpViewPosition.count( ) / 4 - 1; + double abs = 0.0, minabs = 1e10; + int ns = -1; + int i, j; + PMVector mid( 3 ), dist( 2 ); + + QPtrListIterator it1( cpViewPosition ); + QPtrListIterator it2( cpViewPosition ); + ++it2; + + for( i = 0; i < nump; i++ ) + { + bool skip = false; + switch( m_splineType ) + { + case LinearSpline: + break; + case BSpline: + case CubicSpline: + if( ( i == 0 ) || ( i == ( nump - 1 ) ) ) + skip = true; + break; + } + + if( !skip ) + { + mid = ( **it1 + **it2 ) / 2.0; + dist[0] = mid[0]; + dist[1] = mid[1]; + dist -= clickPosition; + abs = dist.abs( ); + + if( ( minabs > abs ) || ( ns < 0 ) ) + { + minabs = abs; + ns = i; + } + } + for( j = 0; j < 4; j++ ) + { + ++it1; + ++it2; + } + } + + // add a new segment + QValueList newPoints = m_points; + QValueList newRadii = m_radii; + + QValueList::Iterator it = newPoints.at( ( unsigned ) ns ); + QValueList::Iterator hit = it; + ++it; + mid = ( *it + *hit ) / 2; + newPoints.insert( it, mid ); + + QValueList::Iterator rit = newRadii.at( ( unsigned ) ns ); + QValueList::Iterator rhit = rit; + ++rit; + newRadii.insert( rit, ( *rit + *rhit ) / 2 ); + + setPoints( newPoints ); + setRadii( newRadii ); +} + +void PMSphereSweep::joinSegments( const PMControlPointList& /*cp*/, + const QPtrList& cpViewPosition, + const PMVector& clickPosition ) +{ + // find nearest point + int nump = cpViewPosition.count( ) / 4; + int minp = 0; + + switch( m_splineType ) + { + case LinearSpline: + minp = 3; + break; + case BSpline: + case CubicSpline: + minp = 5; + break; + } + + if( nump < minp ) + { + kdError( PMArea ) << "Not enough points in PMSphereSweep::joinSegments\n"; + return; + } + + double abs = 0.0, minabs = 1e10; + int ns = -1; + int i, j; + PMVector* p; + PMVector dist( 2 ); + + QPtrListIterator it1( cpViewPosition ); + + for( i = 0; i < nump; i++ ) + { + p = *it1; + dist[0] = (*p)[0]; + dist[1] = (*p)[1]; + dist -= clickPosition; + abs = dist.abs( ); + + if( ( minabs > abs ) || ( ns < 0 ) ) + { + minabs = abs; + ns = i; + } + for( j = 0; j < 4; j++ ) + ++it1; + } + + // join two segments + QValueList newPoints = m_points; + QValueList::Iterator it; + QValueList newRadii = m_radii; + QValueList::Iterator rit; + + // never remove the first or last point + if( ns == 0 ) + ns++; + if( ns == ( nump - 1 ) ) + ns--; + it = newPoints.at( ns ); + newPoints.remove( it ); + rit = newRadii.at( ns ); + newRadii.remove( rit ); + + setPoints( newPoints ); + setRadii( newRadii ); +} + +void PMSphereSweep::setRSteps( int r ) +{ + if( r >= 4 ) + s_rSteps = r; + else + kdDebug( PMArea ) << "PMSphereSweep::setRSteps: R must be greater than 3\n"; + s_parameterKey++; +} + +void PMSphereSweep::setSSteps( int s ) +{ + if( s >= 1 ) + s_sSteps = s; + else + kdDebug( PMArea ) << "PMSphereSweep::setSSteps: S must be greater than 0\n"; + s_parameterKey++; +} + +void PMSphereSweep::setLinear( int sSteps ) +{ + int numsegments = ( m_points.size( ) - 1 ); + + double raddif; + PMVector diff, angle; + Segment seg; + + for ( int i = 0; i < numsegments; ++i ) + { + seg.points.clear( ); + seg.radii.clear( ); + seg.direction.clear( ); + diff = ( m_points[i + 1] - m_points[i] ) / ( sSteps - 1.0 ); + raddif = ( m_radii[i + 1] - m_radii[i] ) / ( sSteps - 1.0 ); + angle = diff * ( 1 / diff.abs( ) ); + + for ( int j = 0; j < sSteps; ++j ) + { + seg.points.append( m_points[i] + ( diff * j ) ); + seg.radii.append( m_radii[i] + ( raddif * j ) ); + seg.direction.append( angle ); + } + m_segments.append( seg ); + } +} + +void PMSphereSweep::setCurved( bool cubic, int sSteps ) +{ + int numsegments = ( m_points.size( ) - 3 ); + PMVector centres[4]; + PMVector vtr; + double divs = 1.0 / ( sSteps - 1.0 ); + double raddif; + Segment seg; + + for ( int i = 0; i < numsegments; ++i ) + { + seg.points.clear( ); + seg.radii.clear( ); + seg.direction.clear( ); + raddif = ( m_radii[i + 2] - m_radii[i + 1] ) / ( sSteps - 1.0 ); + for ( int j = 0; j < 4; ++j ) + centres[j] = m_points[ i + j ]; + + for ( int j = 0; j < sSteps; ++j ) + { + if ( cubic ) + seg.points.append( catmullRom( centres, ( divs * j ) ) ); + else + seg.points.append( bSpline( centres, ( divs * j ) ) ); + + seg.radii.append( m_radii[i + 1] + ( raddif * j ) ); + } + + seg.direction.append( seg.points[0] - seg.points[1] ); + for ( int j = 1; j < ( sSteps - 1 ) ; ++ j ) + { + vtr = seg.points[ j - 1 ] - seg.points[j]; + vtr += seg.points[j] - seg.points[ j + 1 ]; + seg.direction.append( vtr ); + } + seg.direction.append( seg.points[ sSteps - 2 ] - + seg.points[ sSteps - 1 ] ); + + m_segments.append( seg ); + } +} + +PMVector PMSphereSweep::catmullRom( PMVector *v, double t ) +{ + PMVector rst; + double t2 = t * t; + double t3 = t * t * t; + + rst.setX( ( + ( -t3 + 2 * t2 - t ) * v[0].x( ) + + ( 3 * t3 -5 * t2 + 2 ) * v[1].x( ) + + ( -3 * t3 + 4 * t2 + t ) * v[2].x( ) + + ( t3 - t2 ) * v[3].x( ) + ) / 2 + ); + rst.setY( ( + ( -t3 + 2 * t2 -t ) * v[0].y( ) + + ( 3 * t3 -5 * t2 + 2 ) * v[1].y( ) + + ( -3 * t3 + 4 * t2 + t ) * v[2].y( ) + + ( t3 - t2) * v[3].y( ) + ) / 2 + ); + rst.setZ( ( + ( -t3 + 2 * t2 - t ) * v[0].z( ) + + ( 3 * t3 -5 * t2 + 2 ) * v[1].z( ) + + ( -3 * t3 + 4 * t2 + t ) * v[2].z( ) + + ( t3 - t2 ) * v[3].z( ) + ) / 2 + ); + + return rst; +} + +PMVector PMSphereSweep::bSpline( PMVector *v, double t ) +{ + PMVector rst; + double t2 = t * t; + double t3 = t * t * t; + + rst.setX( ( + ( -t3 + 3 * t2 -3 * t + 1 ) * v[0].x( ) + + ( 3 * t3 -6 * t2 + 4 ) * v[1].x( ) + + ( -3 * t3 + 3 * t2 + 3 * t + 1 ) * v[2].x( ) + + ( t3 ) * v[3].x( ) + ) / 6 + ); + rst.setY( ( + ( -t3 + 3 * t2 -3 * t + 1 ) * v[0].y( ) + + ( 3 * t3 -6 * t2 + 4 ) * v[1].y( ) + + ( -3 * t3 + 3 * t2 + 3 * t + 1 ) * v[2].y( ) + + ( t3 ) * v[3].y( ) + ) / 6 + ); + rst.setZ( ( + ( -t3 + 3 * t2 -3 * t + 1 ) * v[0].z( ) + + ( 3 * t3 -6 * t2 + 4 ) * v[1].z( ) + + ( -3 * t3 + 3 * t2 + 3 * t + 1 ) * v[2].z( ) + + ( t3 ) * v[3].z( ) + ) / 6 + ); + + return rst; +} + +void PMSphereSweep::createSphere( PMVector v, double r, int rSteps ) +{ + PMPointArray& points = m_pViewStructure->points( ); + PMLineArray& lines = m_pViewStructure->lines( ); + + PMVector point = PMVector( 0, 1, 0 ) * r; + int pointUp = m_nextPoint++; + int pointDown = m_nextPoint++; + double rotVal1 = M_PI / ( rSteps - 1 ); + double rotVal2 = ( M_PI / rSteps ) * 2; + + points[pointUp] = PMPoint ( point + v ); + points[pointDown] = PMPoint ( ( PMMatrix::rotation( 0, 0, M_PI ) * point ) + v ); + + + for ( int i = 0; i < rSteps; ++i ) + { + lines[ m_nextLine++] = PMLine( pointUp, m_nextPoint ); + for ( int j = 1; j < ( rSteps - 1 ); ++j ) + { + points[m_nextPoint++] = PMPoint( + ( PMMatrix::rotation( ( rotVal1 * j ), ( rotVal2 * i ), 0 ) * point ) + v ); + + if ( i < ( rSteps - 1 ) ) + lines[m_nextLine++] = PMLine( m_nextPoint - 1, m_nextPoint + + rSteps - 3 ); + else + lines[m_nextLine++] = PMLine( m_nextPoint - 1, m_nextPoint - + ( ( rSteps - 1 ) * ( rSteps - 2 ) ) - 1 ); + + if ( j < ( rSteps - 2 ) ) + lines[m_nextLine++] = PMLine( m_nextPoint - 1, m_nextPoint ); + else + lines[m_nextLine++] = PMLine( m_nextPoint - 1, pointDown ); + } + } +} diff --git a/kpovmodeler/pmspheresweep.h b/kpovmodeler/pmspheresweep.h new file mode 100644 index 00000000..281db0c3 --- /dev/null +++ b/kpovmodeler/pmspheresweep.h @@ -0,0 +1,245 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMSPHERESWEEP_H +#define PMSPHERESWEEP_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" +#include "pmvector.h" +#include +#include +#include + +class PMViewStructure; + +/** + * Class for povray sphere sweep objects. + */ + +class PMSphereSweep : public PMSolidObject +{ + typedef PMSolidObject Base; +public: + /** + * The spline type + */ + enum SplineType { LinearSpline, BSpline, CubicSpline }; + /** + * Creates an empty PMSphereSweep + */ + PMSphereSweep( PMPart* part ); + /** + * Copy constructor + */ + PMSphereSweep( const PMSphereSweep& l ); + /** + * deletes the PMSphereSweep + */ + virtual ~PMSphereSweep( ); + + /** */ + virtual PMObject* copy( ) const { return new PMSphereSweep( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMSphereSweepEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmspheresweep" ); } + + /** */ + virtual void createMemento( ); + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual void controlPoints( PMControlPointList& list ); + /** */ + virtual void controlPointsChanged( PMControlPointList& list ); + /** */ + virtual bool hasDisplayDetail( ) const { return true; } + /** */ + virtual void addObjectActions( const PMControlPointList&, + QPtrList& ); + /** */ + virtual void objectActionCalled( const PMObjectAction*, + const PMControlPointList&, + const QPtrList&, + const PMVector& ); + + /** + * Returns the spline points + */ + QValueList points( ) const { return m_points; } + /** + * Sets the spline points + */ + void setPoints( const QValueList& points ); + /** + * Returns the radii + */ + QValueList radii( ) const { return m_radii; } + /** + * Sets the radii + */ + void setRadii( const QValueList& radii ); + /** + * Returns the number of spline points + */ + int numberOfPoints( ) const { return m_points.size( ); } + /** + * Returns the spline type + */ + SplineType splineType( ) const { return m_splineType; } + /** + * Sets the spline type + */ + void setSplineType( SplineType t ); + /** + * Returns the depth tolerance + */ + double tolerance( ) const { return m_tolerance; } + /** + * Sets the depth tolerance + */ + void setTolerance( double t ); + + /** + * Sets the number of steps around the y axis + */ + static void setRSteps( int r ); + /** + * Sets the number of subdivisions of one spline segment + */ + static void setSSteps( int v ); + /** + * Returns the number of steps around the y axis + */ + static int rSteps( ) { return s_rSteps; } + /** + * Returns the number of subdivisions of one spline segment + */ + static int sSteps( ) { return s_sSteps; } + +protected: + /** */ + virtual void createViewStructure( ); + /** */ + virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey( ); } + +private: + /** + * Object action. Adds a spline point + */ + void splitSegment( const PMControlPointList& cp, + const QPtrList& cpViewPosition, + const PMVector& clickPosition ); + /** + * Object action. Removes a spline point + */ + void joinSegments( const PMControlPointList& cp, + const QPtrList& cpViewPosition, + const PMVector& clickPosition ); + + void stringToValues( const QString& str ); + QString valuesToString( ) const; + + /** + * IDs for @ref PMMementoData + */ + enum PMSphereSweepMementoID { PMSplineTypeID, PMToleranceID }; + /** + * IDs for the object actions + */ + enum PMSphereSweepActionID { PMSplitSegmentID, PMJoinSegmentsID }; + SplineType m_splineType; + QValueList m_points; + QValueList m_radii; + double m_tolerance; + + static int s_rSteps; + static int s_sSteps; + static int s_parameterKey; + + static PMMetaObject* s_pMetaObject; + + /** + * Segment Structure for holding info for + * creating view structure + */ + struct Segment{ + QValueList points; + QValueList radii; + QValueList direction; + }; + + QValueList m_segments; + int m_nextPoint; + int m_nextLine; + /** + * Sets up the segments for linear spline + * @param sSteps the number of subdivisions per segment + */ + void setLinear( int sSteps ); + /** + * Sets up segments for curved splines + * @param cubic true for cubic_spline false for b_spline + * @param sSteps the number of subdivisions per segment + */ + void setCurved( bool cubic, int sSteps ); + /** + * Returns a point on a Catmull rom spline + * @param v Pointer to four control points + * @param t position along spline ( 0.0 - 1.0 ) + */ + PMVector catmullRom( PMVector *v, double t ); + /** + * Returns a point on a cubic b spline + * @param v pointer to four control points + * @param t position along spline ( 0.0 - 1.0 ) + */ + PMVector bSpline( PMVector *v, double t ); + /** + * Creates a sphere + * @param v poisition of sphere + * @param r radius of sphere + * @param rSteps the number of steps around the y axis + */ + void createSphere( PMVector v, double r, int rSteps ); + +}; + +#endif diff --git a/kpovmodeler/pmspheresweepedit.cpp b/kpovmodeler/pmspheresweepedit.cpp new file mode 100644 index 00000000..582a0e80 --- /dev/null +++ b/kpovmodeler/pmspheresweepedit.cpp @@ -0,0 +1,354 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmspheresweepedit.h" +#include "pmspheresweep.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" +#include "pmvectorlistedit.h" +#include "pmpart.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +PMSphereSweepEdit::PMSphereSweepEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMSphereSweepEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Spline type:" ), this ) ); + m_pSplineType = new QComboBox( false, this ); + m_pSplineType->insertItem( i18n( "Linear Spline" ) ); + m_pSplineType->insertItem( i18n( "B-Spline" ) ); + m_pSplineType->insertItem( i18n( "Cubic Spline" ) ); + hl->addWidget( m_pSplineType ); + hl->addStretch( 1 ); + + connect( m_pSplineType, SIGNAL( activated( int ) ), + SLOT( slotTypeChanged( int ) ) ); +} + +void PMSphereSweepEdit::createBottomWidgets( ) +{ + topLayout( )->addWidget( new QLabel( i18n( "Spheres:" ), this ) ); + + m_pPoints = new PMVectorListEdit( "x", "y", "z", "r", this ); + connect( m_pPoints, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pPoints, SIGNAL( selectionChanged( ) ), + SLOT( slotSelectionChanged( ) ) ); + QHBoxLayout* hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( m_pPoints, 2 ); + + m_pAddAbove = new QPushButton( this ); + m_pAddAbove->setPixmap( SmallIcon( "pmaddpointabove" ) ); + m_pAddBelow = new QPushButton( this ); + m_pAddBelow->setPixmap( SmallIcon( "pmaddpoint" ) ); + m_pRemove = new QPushButton( this ); + m_pRemove->setPixmap( SmallIcon( "pmremovepoint" ) ); + connect( m_pAddAbove, SIGNAL( clicked( ) ), SLOT( slotAddPointAbove( ) ) ); + connect( m_pAddBelow, SIGNAL( clicked( ) ), SLOT( slotAddPointBelow( ) ) ); + connect( m_pRemove, SIGNAL( clicked( ) ), SLOT( slotRemovePoint( ) ) ); + + QVBoxLayout* bl = new QVBoxLayout( hl ); + bl->addWidget( m_pAddAbove ); + bl->addWidget( m_pAddBelow ); + bl->addWidget( m_pRemove ); + bl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Tolerance" ), this ) ); + m_pTolerance = new PMFloatEdit( this ); + m_pTolerance->setValidation( true, 0, false, 0 ); + hl->addWidget( m_pTolerance ); + connect( m_pTolerance, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + + Base::createBottomWidgets( ); +} + +void PMSphereSweepEdit::displayObject( PMObject* o ) +{ + if( o->isA( "SphereSweep" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMSphereSweep* ) o; + + switch( m_pDisplayedObject->splineType( ) ) + { + case PMSphereSweep::LinearSpline: + m_pSplineType->setCurrentItem( 0 ); + break; + case PMSphereSweep::BSpline: + m_pSplineType->setCurrentItem( 1 ); + break; + case PMSphereSweep::CubicSpline: + m_pSplineType->setCurrentItem( 2 ); + break; + } + m_pSplineType->setEnabled( !readOnly ); + m_pTolerance->setValue( m_pDisplayedObject->tolerance( ) ); + m_pTolerance->setReadOnly( readOnly ); + m_pPoints->setReadOnly( readOnly ); + + QValueList points = m_pDisplayedObject->points( ); + QValueList radii = m_pDisplayedObject->radii( ); + QValueListIterator pit = points.begin( ); + QValueListIterator rit = radii.begin( ); + for( ; pit != points.end( ) && rit != radii.end( ); ++pit, ++rit ) + { + ( *pit ).resize( 4 ); + ( *pit )[3] = *rit; + } + + m_pPoints->setVectors( points, true ); + updateControlPointSelection( ); + updatePointButtons( ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMSphereSweepEdit: Can't display object\n"; +} + +void PMSphereSweepEdit::updateControlPointSelection( ) +{ + /* + PMControlPointList cp = part( )->activeControlPoints( ); + PMControlPointListIterator it( cp ); + int i; + int np = cp.count( ) / 4; + + if( np == m_pPoints->size( ) ) + { + m_pPoints->blockSelectionUpdates( true ); + bool sb = m_pPoints->signalsBlocked( ); + m_pPoints->blockSignals( true ); + + m_pPoints->clearSelection( ); + for( i = 0; i < np; i++, ++it ) + if( ( *it )->selected( ) ) + m_pPoints->select( i ); + for( i = 0; i < np; i++, ++it ) + if( ( *it )->selected( ) ) + m_pPoints->select( i ); + + m_pPoints->blockSignals( sb ); + m_pPoints->blockSelectionUpdates( false ); + } + */ +} + +void PMSphereSweepEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + QValueList points = m_pPoints->vectors( ); + QValueList radii; + QValueListIterator pit = points.begin( ); + for( ; pit != points.end( ); ++pit ) + { + radii.append( ( *pit )[3] ); + ( *pit ).resize( 3 ); + } + + m_pDisplayedObject->setPoints( points ); + m_pDisplayedObject->setRadii( radii ); + + switch( m_pSplineType->currentItem( ) ) + { + case 0: + m_pDisplayedObject->setSplineType( PMSphereSweep::LinearSpline ); + break; + case 1: + m_pDisplayedObject->setSplineType( PMSphereSweep::BSpline ); + break; + case 2: + m_pDisplayedObject->setSplineType( PMSphereSweep::CubicSpline ); + break; + } + m_pDisplayedObject->setTolerance( m_pTolerance->value( ) ); + Base::saveContents( ); + } +} + +bool PMSphereSweepEdit::isDataValid( ) +{ + if( !m_pPoints->isDataValid( ) ) + return false; + + int np = m_pPoints->size( ); + switch( m_pSplineType->currentItem( ) ) + { + case 0: + if( np < 2 ) + { + KMessageBox::error( this, i18n( "Linear splines need at least 2 points." ), + i18n( "Error" ) ); + return false; + } + break; + case 1: + if( np < 4 ) + { + KMessageBox::error( this, i18n( "B-splines need at least 4 points." ), + i18n( "Error" ) ); + return false; + } + break; + case 2: + if( np < 4 ) + { + KMessageBox::error( this, i18n( "Cubic splines need at least 4 points." ), + i18n( "Error" ) ); + return false; + } + break; + case 3: + if( ( np < 4 ) || ( ( np % 4 ) != 0 ) ) + { + KMessageBox::error( this, i18n( "Bezier splines need 4 points for each segment." ), + i18n( "Error" ) ); + return false; + } + break; + } + return Base::isDataValid( ); +} + +void PMSphereSweepEdit::slotTypeChanged( int ) +{ + emit dataChanged( ); +} + +void PMSphereSweepEdit::slotAddPointAbove( ) +{ + int index = m_pPoints->currentRow( ); + if( index >= 0 ) + { + QValueList points = m_pPoints->vectors( ); + QValueListIterator it = points.at( index ); + + if( it != points.end( ) ) + { + QValueListIterator it2 = it; + it2--; + PMVector v; + if( it2 == points.end( ) ) + v = *it; + else + v = ( *it + *it2 ) / 2; + + points.insert( it, v ); + m_pPoints->setVectors( points, true ); + updatePointButtons( ); + emit dataChanged( ); + emit sizeChanged( ); + } + } +} + +void PMSphereSweepEdit::slotAddPointBelow( ) +{ + int index = m_pPoints->currentRow( ); + if( index >= 0 ) + { + QValueList points = m_pPoints->vectors( ); + QValueListIterator it = points.at( index ); + + if( it != points.end( ) ) + { + QValueListIterator it2 = it; + it2++; + PMVector v; + if( it2 == points.end( ) ) + v = *it; + else + v = ( *it + *it2 ) / 2; + + points.insert( it2, v ); + m_pPoints->setVectors( points, true ); + m_pPoints->setCurrentCell( index + 1, m_pPoints->currentColumn( ) ); + updatePointButtons( ); + emit dataChanged( ); + emit sizeChanged( ); + } + } +} + +void PMSphereSweepEdit::slotRemovePoint( ) +{ + int row = m_pPoints->currentRow( ); + + if( row >= 0 ) + { + QValueList points = m_pPoints->vectors( ); + QValueListIterator it = points.at( row ); + + if( it != points.end( ) && points.size( ) > 1 ) + { + points.remove( it ); + m_pPoints->setVectors( points, true ); + updatePointButtons( ); + emit dataChanged( ); + emit sizeChanged( ); + } + } +} + +void PMSphereSweepEdit::slotSelectionChanged( ) +{ + /* + PMControlPointList cp = part( )->activeControlPoints( ); + PMControlPointListIterator it( cp ); + int np = cp.count( ) / 2; + int i; + + if( np == m_pPoints->size( ) ) + { + for( i = 0; i < np; i++, ++it ) + ( *it )->setSelected( m_pPoints->isSelected( i ) ); + for( i = 0; i < np; i++, ++it ) + ( *it )->setSelected( m_pPoints->isSelected( i ) ); + emit controlPointSelectionChanged( ); + } + */ + updatePointButtons( ); +} + +void PMSphereSweepEdit::updatePointButtons( ) +{ + int row = m_pPoints->currentRow( ); + m_pAddAbove->setEnabled( row >= 0 ); + m_pAddBelow->setEnabled( row >= 0 ); + m_pRemove->setEnabled( row >= 0 && m_pPoints->size( ) > 2 ); +} + +#include "pmspheresweepedit.moc" diff --git a/kpovmodeler/pmspheresweepedit.h b/kpovmodeler/pmspheresweepedit.h new file mode 100644 index 00000000..58f89372 --- /dev/null +++ b/kpovmodeler/pmspheresweepedit.h @@ -0,0 +1,90 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMSPHERESWEEPEDIT_H +#define PMSPHERESWEEPEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" +#include "pmvectoredit.h" +#include +#include + +class PMSphereSweep; +class PMVectorListEdit; +class PMFloatEdit; +class QVBoxLayout; +class QComboBox; +class QCheckBox; +class QPushButton; +class QLabel; + +/** + * Dialog edit class for @ref PMSphereSweep + */ +class PMSphereSweepEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMSphereSweepEdit with parent and name + */ + PMSphereSweepEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + /** */ + virtual void updateControlPointSelection( ); + + /** */ + virtual bool isDataValid( ); + +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void createBottomWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + void slotTypeChanged( int ); + void slotAddPointAbove( ); + void slotAddPointBelow( ); + void slotRemovePoint( ); + void slotSelectionChanged( ); + +private: + void updatePointButtons( ); + + PMSphereSweep* m_pDisplayedObject; + QComboBox* m_pSplineType; + PMVectorListEdit* m_pPoints; + PMFloatEdit* m_pTolerance; + QPushButton* m_pAddAbove; + QPushButton* m_pAddBelow; + QPushButton* m_pRemove; +}; + + +#endif diff --git a/kpovmodeler/pmsplinememento.cpp b/kpovmodeler/pmsplinememento.cpp new file mode 100644 index 00000000..a197f8ea --- /dev/null +++ b/kpovmodeler/pmsplinememento.cpp @@ -0,0 +1,58 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmsplinememento.h" +#include "pmdebug.h" + +PMSplineMemento::PMSplineMemento( PMObject* originator ) + : PMMemento( originator ) +{ + m_bSplinePointsSaved = false; +} + +PMSplineMemento::~PMSplineMemento( ) +{ +} + +void PMSplineMemento::setSplinePoints( const QValueList& v ) +{ + if( !m_bSplinePointsSaved ) + { + // Direct assignment does not work with Qt 2.3.x + // The list will be changed later in a graphical + // change because QValueList::detach( ) is called + // too late! + // Copy the list by hand. + + QValueList::ConstIterator it = v.begin( ); + for( ; it != v.end( ); ++it ) + m_splinePoints.append( *it ); + + m_bSplinePointsSaved = true; + addChange( PMCData ); + } +} + +QValueList PMSplineMemento::splinePoints( ) const +{ + if( !m_bSplinePointsSaved ) + kdError( PMArea ) << "Spline points not saved in PMSplineMemento::splinePoints\n"; + + return m_splinePoints; +} + + diff --git a/kpovmodeler/pmsplinememento.h b/kpovmodeler/pmsplinememento.h new file mode 100644 index 00000000..daa4a70b --- /dev/null +++ b/kpovmodeler/pmsplinememento.h @@ -0,0 +1,68 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMSPLINEMEMENTO_H +#define PMSPLINEMEMENTO_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmmemento.h" +#include "pmvector.h" +#include + + +/** + * Memento for @ref PMLathe + */ +class PMSplineMemento : public PMMemento +{ +public: + /** + * Creates a memento for the object originator + */ + PMSplineMemento( PMObject* originator ); + /** + * Deletes the memento + */ + virtual ~PMSplineMemento( ); + + /** + * Saves the spline points + */ + void setSplinePoints( const QValueList& v ); + /** + * Returns the spline points + */ + QValueList splinePoints( ) const; + /** + * Returns true if the spline points were saved + */ + bool splinePointsSaved( ) const { return m_bSplinePointsSaved; } + +private: + /** + * The stored points + */ + QValueList m_splinePoints; + bool m_bSplinePointsSaved; +}; + +#endif diff --git a/kpovmodeler/pmsplinesegment.cpp b/kpovmodeler/pmsplinesegment.cpp new file mode 100644 index 00000000..dbbc6b18 --- /dev/null +++ b/kpovmodeler/pmsplinesegment.cpp @@ -0,0 +1,107 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmsplinesegment.h" + +PMVector PMSplineSegment::point( double t ) const +{ + double t2 = t * t; + double t3 = t2 * t; + + return PMVector( m_a[0]*t3 + m_b[0]*t2 + m_c[0]*t + m_d[0], + m_a[1]*t3 + m_b[1]*t2 + m_c[1]*t + m_d[1] ); +} + +PMVector PMSplineSegment::gradient( double t ) const +{ + double t2 = t * t; + + return PMVector( 3*m_a[0]*t2 + 2*m_b[0]*t + m_c[0], + 3*m_a[1]*t2 + 2*m_b[1]*t + m_c[1] ); +} + +void PMSplineSegment::calculateLinear( const PMVector& p1, const PMVector& p2 ) +{ + m_a[0] = 0.0; + m_b[0] = 0.0; + m_c[0] = -1.0 * p1[0] + 1.0 * p2[0]; + m_d[0] = 1.0 * p1[0]; + + m_a[1] = 0.0; + m_b[1] = 0.0; + m_c[1] = -1.0 * p1[1] + 1.0 * p2[1]; + m_d[1] = 1.0 * p1[1]; +} + +void PMSplineSegment::calculateQuadratic( const PMVector& p1, + const PMVector& p2, + const PMVector& p3 ) +{ + m_a[0] = 0.0; + m_b[0] = 0.5 * p1[0] - 1.0 * p2[0] + 0.5 * p3[0]; + m_c[0] = -0.5 * p1[0] + 0.5 * p3[0]; + m_d[0] = 1.0 * p2[0]; + + m_a[1] = 0.0; + m_b[1] = 0.5 * p1[1] - 1.0 * p2[1] + 0.5 * p3[1]; + m_c[1] = -0.5 * p1[1] + 0.5 * p3[1]; + m_d[1] = 1.0 * p2[1]; +} + +void PMSplineSegment::calculateCubic( const PMVector& p1, const PMVector& p2, + const PMVector& p3, const PMVector& p4 ) +{ + m_a[0] = -0.5 * p1[0] + 1.5 * p2[0] - 1.5 * p3[0] + 0.5 * p4[0]; + m_b[0] = p1[0] - 2.5 * p2[0] + 2.0 * p3[0] - 0.5 * p4[0]; + m_c[0] = -0.5 * p1[0] + 0.5 * p3[0]; + m_d[0] = p2[0]; + + m_a[1] = -0.5 * p1[1] + 1.5 * p2[1] - 1.5 * p3[1] + 0.5 * p4[1]; + m_b[1] = p1[1] - 2.5 * p2[1] + 2.0 * p3[1] - 0.5 * p4[1]; + m_c[1] = -0.5 * p1[1] + 0.5 * p3[1]; + m_d[1] = p2[1]; +} + +void PMSplineSegment::calculateBezier( const PMVector& p1, const PMVector& p2, + const PMVector& p3, const PMVector& p4 ) +{ + m_a[0] = - p1[0] + 3.0 * p2[0] - 3.0 * p3[0] + p4[0]; + m_b[0] = 3.0 * p1[0] - 6.0 * p2[0] + 3.0 * p3[0]; + m_c[0] = -3.0 * p1[0] + 3.0 * p2[0]; + m_d[0] = p1[0]; + + m_a[1] = - p1[1] + 3.0 * p2[1] - 3.0 * p3[1] + p4[1]; + m_b[1] = 3.0 * p1[1] - 6.0 * p2[1] + 3.0 * p3[1]; + m_c[1] = -3.0 * p1[1] + 3.0 * p2[1]; + m_d[1] = p1[1]; +} + +void PMSplineSegment::calculateQuadricBezier( const PMVector& p1, + const PMVector& p2, + const PMVector& p3 ) +{ + m_a[0] = 0; + m_b[0] = p1[0] - 2.0 * p2[0] + p3[0]; + m_c[0] = -2.0 * p1[0] + 2.0 * p2[0]; + m_d[0] = p1[0]; + + m_a[1] = 0; + m_b[1] = p1[1] - 2.0 * p2[1] + p3[1]; + m_c[1] = -2.0 * p1[1] + 2.0 * p2[1]; + m_d[1] = p1[1]; +} diff --git a/kpovmodeler/pmsplinesegment.h b/kpovmodeler/pmsplinesegment.h new file mode 100644 index 00000000..5e97ff49 --- /dev/null +++ b/kpovmodeler/pmsplinesegment.h @@ -0,0 +1,122 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMSPLINESEGMENT_H +#define PMSPLINESEGMENT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmvector.h" +#include + +/** + * Helper class for splines + * + * Each instance of this class represents one spline segment. A point + * on the segment is given by the equation + * + * fi(t) = A[i] * t^3 + B[i] * t^2 + C[i] * t + D[i] + * + * with t ranging from 0 to 1. + */ +class PMSplineSegment +{ +public: + /** + * Standard constructor + */ + PMSplineSegment( ) + { + m_a[0] = m_b[0] = m_c[0] = m_d[0] = 0.0; + m_a[1] = m_b[1] = m_c[1] = m_d[1] = 0.0; + } + /** + * Copy constructor + */ + PMSplineSegment( const PMSplineSegment& s ) + { + int i; + for( i = 0; i < 2; i++ ) + { + m_a[i] = s.m_a[i]; + m_b[i] = s.m_b[i]; + m_c[i] = s.m_c[i]; + m_d[i] = s.m_d[i]; + } + } + /** + * Assigns s to the segment + */ + PMSplineSegment& operator= ( const PMSplineSegment& s ) + { + int i; + for( i = 0; i < 2; i++ ) + { + m_a[i] = s.m_a[i]; + m_b[i] = s.m_b[i]; + m_c[i] = s.m_c[i]; + m_d[i] = s.m_d[i]; + } + return *this; + } + + /** + * Returns a 2D vector with the point on the spline segment + */ + PMVector point( double t ) const; + /** + * Returns the gradient on the spline + */ + PMVector gradient( double t ) const; + + /** + * Calculates the spline parameters for the linear spline type + */ + void calculateLinear( const PMVector& p1, const PMVector& p2 ); + /** + * Calculates the spline parameters for the quadratic spline type + */ + void calculateQuadratic( const PMVector& p1, const PMVector& p2, + const PMVector& p3 ); + /** + * Calculates the spline parameters for the cubic spline type + */ + void calculateCubic( const PMVector& p1, const PMVector& p2, + const PMVector& p3, const PMVector& p4 ); + /** + * Calculates the spline parameters for the bezier spline type + */ + void calculateBezier( const PMVector& p1, const PMVector& p2, + const PMVector& p3, const PMVector& p4 ); + /** + * Calculates the spline parameters for the quadric bezier + */ + void calculateQuadricBezier( const PMVector& p1, const PMVector& p2, + const PMVector& p3 ); + +private: + double m_a[2], m_b[2], m_c[2], m_d[2]; +}; + +typedef QValueList PMSegmentList; +typedef QValueList PMSegmentListList; + +#endif diff --git a/kpovmodeler/pmsqe.cpp b/kpovmodeler/pmsqe.cpp new file mode 100644 index 00000000..051aac72 --- /dev/null +++ b/kpovmodeler/pmsqe.cpp @@ -0,0 +1,413 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmsqe.h" + +#include "pmxmlhelper.h" +#include "pmsqeedit.h" +#include "pmmemento.h" +#include "pmviewstructure.h" +#include "pmdefaults.h" +#include "pmmath.h" + +#include + +const double c_defaultEastWestExponent = 1.0; +const double c_defaultNorthSouthExponent = 1.0; + +PMViewStructure* PMSuperquadricEllipsoid::s_pDefaultViewStructure = 0; +int PMSuperquadricEllipsoid::s_vStep = c_defaultSuperquadricEllipsoidVSteps; +int PMSuperquadricEllipsoid::s_uStep = c_defaultSuperquadricEllipsoidUSteps; +int PMSuperquadricEllipsoid::s_parameterKey = 0; + +PMDefinePropertyClass( PMSuperquadricEllipsoid, PMSuperquadricEllipsoidProperty ); + +PMMetaObject* PMSuperquadricEllipsoid::s_pMetaObject = 0; +PMObject* createNewSuperquadricEllipsoid( PMPart* part ) +{ + return new PMSuperquadricEllipsoid( part ); +} + +PMSuperquadricEllipsoid::PMSuperquadricEllipsoid( PMPart* part ) + : Base( part ) +{ + m_eastWestExponent = c_defaultEastWestExponent; + m_northSouthExponent = c_defaultNorthSouthExponent; +} + +PMSuperquadricEllipsoid::PMSuperquadricEllipsoid( const PMSuperquadricEllipsoid& s ) + : Base( s ) +{ + m_eastWestExponent = s.m_eastWestExponent; + m_northSouthExponent = s.m_northSouthExponent; +} + +PMSuperquadricEllipsoid::~PMSuperquadricEllipsoid( ) +{ +} + +QString PMSuperquadricEllipsoid::description( ) const +{ + return i18n( "superquadric ellipsoid" ); +} + +void PMSuperquadricEllipsoid::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "value_e", m_eastWestExponent ); + e.setAttribute( "value_n", m_northSouthExponent ); + Base::serialize( e, doc ); +} + +void PMSuperquadricEllipsoid::readAttributes( const PMXMLHelper& h ) +{ + m_eastWestExponent = h.doubleAttribute( "value_e", c_defaultEastWestExponent ); + m_northSouthExponent = h.doubleAttribute( "value_n", c_defaultNorthSouthExponent ); + Base::readAttributes( h ); +} + +PMMetaObject* PMSuperquadricEllipsoid::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "SuperquadricEllipsoid", Base::metaObject( ), + createNewSuperquadricEllipsoid ); + s_pMetaObject->addProperty( + new PMSuperquadricEllipsoidProperty( "eastWestExponent", + &PMSuperquadricEllipsoid::setEastWestExponent, + &PMSuperquadricEllipsoid::eastWestExponent ) ); + s_pMetaObject->addProperty( + new PMSuperquadricEllipsoidProperty( "northSouthExponent", + &PMSuperquadricEllipsoid::setNorthSouthExponent, + &PMSuperquadricEllipsoid::northSouthExponent ) ); + } + return s_pMetaObject; +} + +void PMSuperquadricEllipsoid::setEastWestExponent( double e ) +{ + if( e != m_eastWestExponent ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMEastWestExponentID, + m_eastWestExponent ); + if( e < 0.001 ) + { + kdError( PMArea ) << "EastWestExponent < 0.001 in PMSuperquadricEllipsoid::setEastWestExponent\n"; + e = 0.001; + } + m_eastWestExponent = e; + setViewStructureChanged( ); + } +} + +void PMSuperquadricEllipsoid::setNorthSouthExponent( double n ) +{ + if( n != m_northSouthExponent ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMNorthSouthExponentID, + m_northSouthExponent ); + if( n < 0.001 ) + { + kdError( PMArea ) << "NorthSouthExponent < 0.001 in PMSuperquadricEllipsoid::setNorthSouthExponent\n"; + n = 0.001; + } + + m_northSouthExponent = n; + setViewStructureChanged( ); + } +} + +PMDialogEditBase* PMSuperquadricEllipsoid::editWidget( QWidget* parent ) const +{ + return new PMSuperquadricEllipsoidEdit( parent ); +} + +void PMSuperquadricEllipsoid::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMEastWestExponentID: + setEastWestExponent( data->doubleData( ) ); + break; + case PMNorthSouthExponentID: + setNorthSouthExponent( data->doubleData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMSuperquadricEllipsoid::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + + +bool PMSuperquadricEllipsoid::isDefault( ) +{ + if( ( m_eastWestExponent == c_defaultEastWestExponent ) && + ( m_northSouthExponent == c_defaultNorthSouthExponent ) + && globalDetail( ) ) + return true; + return false; +} + +void PMSuperquadricEllipsoid::createViewStructure( ) +{ + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultViewStructure( ) ); + m_pViewStructure->points( ).detach( ); + } + + int uStep = (int)( ( (float)s_uStep / 2 ) * ( displayDetail( ) + 1 ) ); + int vStep = (int)( ( (float)s_vStep / 2 ) * ( displayDetail( ) + 1 ) ); + int uStep2 = uStep * 4; + int vStep2 = vStep * 8; + unsigned ptsSize = vStep2 * ( uStep2 - 1 ) + 2; + unsigned lineSize = vStep2 * ( uStep2 - 1 ) * 2 + vStep2; + + if( ptsSize != m_pViewStructure->points( ).size( ) ) + m_pViewStructure->points( ).resize( ptsSize ); + + createPoints( m_pViewStructure->points( ), m_eastWestExponent, + m_northSouthExponent, uStep, vStep ); + + if( lineSize != m_pViewStructure->lines( ).size( ) ) + { + m_pViewStructure->lines( ).detach( ); + m_pViewStructure->lines( ).resize( lineSize ); + createLines( m_pViewStructure->lines( ), uStep2, vStep2 ); + } +} + +PMViewStructure* PMSuperquadricEllipsoid::defaultViewStructure( ) const +{ + if( !s_pDefaultViewStructure || s_pDefaultViewStructure->parameterKey( ) != viewStructureParameterKey( ) ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + int uStep = (int)( ( (float)s_uStep / 2 ) * ( globalDetailLevel( ) + 1 ) ); + int vStep = (int)( ( (float)s_vStep / 2 ) * ( globalDetailLevel( ) + 1 ) ); + + // transform u and v steps to sphere u/v steps + int uStep2 = uStep * 4; + int vStep2 = vStep * 8; + + s_pDefaultViewStructure = + new PMViewStructure( vStep2 * ( uStep2 - 1 ) + 2, + vStep2 * ( uStep2 - 1 ) * 2 + vStep2 ); + + // points + createPoints( s_pDefaultViewStructure->points( ), + c_defaultEastWestExponent, c_defaultNorthSouthExponent, uStep, vStep ); + + createLines( s_pDefaultViewStructure->lines( ), uStep2, vStep2 ); + } + return s_pDefaultViewStructure; +} + +void PMSuperquadricEllipsoid::createLines( PMLineArray& lines, int uStep, int vStep ) +{ + int u, v; + int offset = 0; + + // horizontal lines + for( u = 0; u < ( uStep - 1 ); u++ ) + { + for( v = 0; v < ( vStep - 1 ); v++ ) + lines[offset + v] = + PMLine( u * vStep + v + 1, u * vStep + v + 2 ); + lines[offset + vStep - 1] = + PMLine( u * vStep + 1, u * vStep + vStep ); + + offset += vStep; + } + + // vertical lines + // lines at the "north pole" + for( v = 0; v < vStep; v++ ) + lines[offset + v] = PMLine( 0, v + 1 ); + offset += vStep; + + for( v = 0; v < vStep; v++ ) + { + for( u = 0; u < ( uStep - 2 ); u++ ) + { + lines[offset + u] = + PMLine( u * vStep + v + 1, ( u + 1 ) * vStep + v + 1 ); + } + offset += ( uStep - 2 ); + } + // lines at the "south pole" + for( v = 0; v < vStep; v++ ) + lines[offset + v] = PMLine( ( uStep - 2 ) * vStep + v + 1, + ( uStep - 1 ) * vStep + 1 ); + // offset += vStep; +} + +void PMSuperquadricEllipsoid::createPoints( PMPointArray& points, + double e, double n, int uStep, int vStep ) +{ + int u, v; + int zi; + int pbase = 0, pref = 0; + + if( e <= 0.001 ) + e = 0.001; + if( n <= 0.001 ) + n = 0.001; + + double c2_e = 2.0 / e; + double c2_n = 2.0 / n; + double cn_2 = n / 2.0; + double ce_2 = e / 2.0; + double cn_e = n / e; +// double ce_n = e / n; + double z = 0.0, c = 0.0, a = 0.0, a2 = 0.0, x = 0.0, y = 0.0; + double k = 0.0, k2 = 0.0, du = 0.0, dv = 0.0; + PMPoint p; + + points[0] = PMPoint( 0, 0, 1 ); + pbase++; + + for( zi = 0; zi < 2; zi++ ) + { + for( u = 0; u < uStep; u++ ) + { + du = ( double ) ( u + 1 ) / ( double ) uStep; + if( zi == 1 ) + du = 1.0 - du; + k = tan( M_PI / 4.0 * pow( du, n < 1.0 ? n : sqrt( n ) ) ); + k2 = 1 / ( pow( k, c2_n ) + 1 ); + z = pow( k2, cn_2 ); + if( zi == 1 ) + z *= k; + c = pow( 1 - pow( z, c2_n ), cn_e ); + + for( v = 0; v < ( vStep + 1 ); v++ ) + { + dv = ( double ) v / ( double ) vStep; + a = tan( M_PI / 4.0 * pow( dv, e < 1.0 ? e : sqrt( e ) ) ); + a2 = 1 + pow( a, c2_e ); + x = pow( c / a2, ce_2 ); + y = x * a; + + points[pbase+v] = PMPoint( x, y, z ); + } + // 1/8 + + pref = pbase + 2 * vStep; + for( v = 0; v < vStep; v++, pref-- ) + { + p = points[pbase+v]; + x = p[0]; + p[0] = p[1]; + p[1] = x; + points[pref] = p; + } + // 1/4 + + pref = pbase + 4 * vStep; + for( v = 0; v < ( 2 * vStep ); v++, pref-- ) + { + p = points[pbase+v]; + p[0] = -p[0]; + points[pref] = p; + } + // 1/2 + + pref = pbase + 8 * vStep - 1; + for( v = 1; v < ( 4 * vStep ); v++, pref-- ) + { + p = points[pbase+v]; + p[1] = -p[1]; + points[pref] = p; + } + + pbase += 8 * vStep; + } + } + + for( u = 0; u < ( uStep * 2 - 1 ); u++ ) + { + pbase = 1 + u * vStep * 8; + pref = 1 + ( uStep * 4 - 2 - u ) * vStep * 8; + + for( v = 0; v < ( vStep * 8 ); v++, pref++ ) + { + p = points[pbase + v]; + p[2] = -p[2]; + points[pref] = p; + } + } + points[ vStep * 8 * ( uStep * 4 - 1 ) + 1 ] = PMPoint( 0, 0, -1 ); +} + +void PMSuperquadricEllipsoid::setUSteps( int u ) +{ + if( u >= 2 ) + { + s_uStep = u; + if( s_pDefaultViewStructure ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + } + } + else + kdDebug( PMArea ) << "PMSuperquadricEllipsoid::setUSteps: U must be greater than 1\n"; + s_parameterKey++; +} + +void PMSuperquadricEllipsoid::setVSteps( int v ) +{ + if( v >= 2 ) + { + s_vStep = v; + if( s_pDefaultViewStructure ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + } + } + else + kdDebug( PMArea ) << "PMSuperquadricEllipsoid::setVSteps: V must be greater than 1\n"; + s_parameterKey++; +} + +void PMSuperquadricEllipsoid::cleanUp( ) const +{ + if( s_pDefaultViewStructure ) + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} diff --git a/kpovmodeler/pmsqe.h b/kpovmodeler/pmsqe.h new file mode 100644 index 00000000..e2d04c60 --- /dev/null +++ b/kpovmodeler/pmsqe.h @@ -0,0 +1,155 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMSQE_H +#define PMSQE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" +#include "pmvector.h" +#include "pmpoint.h" +#include "pmline.h" + +class PMViewStructure; + +/** + * Class for povray superquadric ellipsoids. + */ + +class PMSuperquadricEllipsoid : public PMSolidObject +{ + typedef PMSolidObject Base; +public: + /** + * Creates an empty PMSuperquadricEllipsoid + */ + PMSuperquadricEllipsoid( PMPart* part ); + /** + * Copy constructor + */ + PMSuperquadricEllipsoid( const PMSuperquadricEllipsoid& s ); + /** + * deletes the PMSuperquadricEllipsoid + */ + virtual ~PMSuperquadricEllipsoid( ); + + /** */ + virtual PMObject* copy( ) const { return new PMSuperquadricEllipsoid( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMSuperquadricEllipsoidEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmsqe" ); } + + /** + * Returns the east west exponent + */ + double eastWestExponent( ) const { return m_eastWestExponent; } + /** + * Sets the east west exponent + */ + void setEastWestExponent( double e ); + /** + * Returns the north south exponent + */ + double northSouthExponent( ) const { return m_northSouthExponent; } + /** + * Sets the north south exponent + */ + void setNorthSouthExponent( double n ); + + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual bool hasDisplayDetail( ) const { return true; } + + /** + * Sets the number of latitutes + */ + static void setUSteps( int u ); + /** + * Sets the number of longitudes + */ + static void setVSteps( int v ); + /** + * Returns the number or latitutes + */ + static int uSteps( ) { return s_uStep; } + /** + * Returns the number or longitudes + */ + static int vSteps( ) { return s_vStep; } + /** */ + virtual void cleanUp( ) const; + +protected: + /** */ + virtual bool isDefault( ); + /** */ + virtual void createViewStructure( ); + /** */ + virtual PMViewStructure* defaultViewStructure( ) const; + /** */ + virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey( ); } + +private: + /** + * Creates the lines for the view structure + */ + static void createLines( PMLineArray& lines, int uStep, int vStep ); + /** + * Creates the points for the view structure + */ + static void createPoints( PMPointArray& points, double e, double n, int uStep, int vStep ); + + /** + * IDs for @ref PMMementoData + */ + enum PMSQEMementoID { PMEastWestExponentID, PMNorthSouthExponentID }; + double m_eastWestExponent, m_northSouthExponent; + + /** + * The default view structure. It can be shared between sqe's + */ + static PMViewStructure* s_pDefaultViewStructure; + static int s_vStep; + static int s_uStep; + static int s_parameterKey; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmsqeedit.cpp b/kpovmodeler/pmsqeedit.cpp new file mode 100644 index 00000000..488ce2f2 --- /dev/null +++ b/kpovmodeler/pmsqeedit.cpp @@ -0,0 +1,93 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmsqeedit.h" +#include "pmsqe.h" +#include "pmlineedits.h" + +#include +#include +#include + +PMSuperquadricEllipsoidEdit::PMSuperquadricEllipsoidEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMSuperquadricEllipsoidEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + m_pValueE = new PMFloatEdit( this ); + m_pValueE->setValidation( true, 0.01, false, 1.0 ); + m_pValueN = new PMFloatEdit( this ); + m_pValueN->setValidation( true, 0.01, false, 1.0 ); + + topLayout( )->addWidget( new QLabel( i18n( "Exponents:" ), this ) ); + + QHBoxLayout* hl = new QHBoxLayout( topLayout( ) ); + QGridLayout* gl = new QGridLayout( hl, 2, 2 ); + gl->addWidget( new QLabel( i18n( "East-west:" ), this ), 0, 0 ); + gl->addWidget( m_pValueE, 0, 1 ); + gl->addWidget( new QLabel( i18n( "North-south:" ), this ), 1, 0 ); + gl->addWidget( m_pValueN, 1, 1 ); + hl->addStretch( 1 ); + + connect( m_pValueE, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pValueN, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMSuperquadricEllipsoidEdit::displayObject( PMObject* o ) +{ + if( o->isA( "SuperquadricEllipsoid" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMSuperquadricEllipsoid* ) o; + + m_pValueE->setValue( m_pDisplayedObject->eastWestExponent( ) ); + m_pValueN->setValue( m_pDisplayedObject->northSouthExponent( ) ); + + m_pValueE->setReadOnly( readOnly ); + m_pValueN->setReadOnly( readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMSuperquadricEllipsoidEdit: Can't display object\n"; +} + +void PMSuperquadricEllipsoidEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setEastWestExponent( m_pValueE->value( ) ); + m_pDisplayedObject->setNorthSouthExponent( m_pValueN->value( ) ); + } +} + +bool PMSuperquadricEllipsoidEdit::isDataValid( ) +{ + if( m_pValueE->isDataValid( ) ) + if( m_pValueN->isDataValid( ) ) + return Base::isDataValid( ); + return false; +} + +#include "pmsqeedit.moc" diff --git a/kpovmodeler/pmsqeedit.h b/kpovmodeler/pmsqeedit.h new file mode 100644 index 00000000..45ae1a2f --- /dev/null +++ b/kpovmodeler/pmsqeedit.h @@ -0,0 +1,63 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMSQEEDIT_H +#define PMSQEEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" + +class PMSuperquadricEllipsoid; +class PMFloatEdit; + +/** + * Dialog edit class for @ref PMSuperquadricEllipsoid + */ +class PMSuperquadricEllipsoidEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMSuperquadricEllipsoidEdit with parent and name + */ + PMSuperquadricEllipsoidEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMSuperquadricEllipsoid* m_pDisplayedObject; + PMFloatEdit* m_pValueE; + PMFloatEdit* m_pValueN; +}; + + +#endif diff --git a/kpovmodeler/pmsymboltable.cpp b/kpovmodeler/pmsymboltable.cpp new file mode 100644 index 00000000..bd1aab3b --- /dev/null +++ b/kpovmodeler/pmsymboltable.cpp @@ -0,0 +1,121 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmsymboltable.h" +#include "pmdeclare.h" +#include "pmdebug.h" + +#include + +PMSymbol::PMSymbol( const QString& id, PMDeclare* o ) +{ + setId( id ); + m_type = Object; + m_pObj = o; + m_pVal = 0; + m_pRenamedSymbol = 0; +} + +PMSymbol::PMSymbol( const QString& id, const PMValue& v ) +{ + setId( id ); + m_type = Value; + m_pObj = 0; + m_pVal = new PMValue( v ); + m_pRenamedSymbol = 0; +} + +PMSymbol::~PMSymbol( ) +{ + if( m_pVal ) + delete m_pVal; +} + +void PMSymbol::setId( const QString& id ) +{ + m_id = id.left( MaxIDLength ); +} + +PMDeclare* PMSymbol::object( ) const +{ + if( m_type == Object ) + return m_pObj; + kdError( PMArea ) << "Symbol is not an object\n"; + return 0; +} + +PMValue PMSymbol::value( ) const +{ + if( m_type == Value ) + return *m_pVal; + kdError( PMArea ) << "Symbol is not a value\n"; + return PMValue( ); +} + + +PMSymbolTable::PMSymbolTable( ) + : QDict( 1009 ), m_lastID( 47 ) +{ + setAutoDelete( true ); + m_lastID.setAutoDelete( true ); +} + +PMSymbolTable::~PMSymbolTable( ) +{ + clear( ); +} + +QString PMSymbolTable::findNewID( const QString& prefix ) +{ + PMSymbol* symbol; + QString testID; + unsigned int number; + + int* lastNumber = m_lastID.find( prefix ); + if( lastNumber ) + number = *lastNumber + 1; + else + number = 0; + + // find next free id + do + { + testID = prefix + QString( "%1" ).arg( number ); + symbol = find( testID ); + if( symbol ) + number++; + } + while( symbol ); + + if( lastNumber ) + *lastNumber = number; + else + m_lastID.insert( prefix, new int( number ) ); + + return testID; +} + +PMSymbol* PMSymbolTable::findNewID( const QString& prefix, PMDeclare* obj ) +{ + QString newID = findNewID( prefix ); + obj->setID( newID ); + + PMSymbol* s = new PMSymbol( newID, obj ); +// insert( newID, s ); + + return s; +} diff --git a/kpovmodeler/pmsymboltable.h b/kpovmodeler/pmsymboltable.h new file mode 100644 index 00000000..27e88785 --- /dev/null +++ b/kpovmodeler/pmsymboltable.h @@ -0,0 +1,128 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMSYMBOLTABLE_H +#define PMSYMBOLTABLE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmvalue.h" +class PMObject; +class PMDeclare; + +#include +#include + +/** + * Entry in a @ref PMSymbolTable. Can be a @ref PMValue or a @ref PMObject + */ + +class PMSymbol +{ +public: + enum PMSymbolType { Value, Object }; + /** + * Creates a entry for an object + */ + PMSymbol( const QString& id, PMDeclare* o ); + /** + * Creates a entry for a value + */ + PMSymbol( const QString& id, const PMValue& v ); + /** + * Destructor + */ + ~PMSymbol( ); + + /** + * Returns the type of the symbol + */ + PMSymbolType type( ) const { return m_type; } + /** + * Returns the id of the symbol + */ + QString id( ) const { return m_id; } + /** + * Sets the id + */ + void setId( const QString& id ); + /** + * Returns the stored object + */ + PMDeclare* object( ) const; + /** + * Returns the stored value + */ + PMValue value( ) const; + /** + * The maximum length for povray ids + */ + static const unsigned int MaxIDLength = 40; + /** + * If the parser parses a declare object with this id, the + * new id is renamed. This function returns a pointer to the + * renamed symbol. + */ + PMSymbol* renamedSymbol( ) const { return m_pRenamedSymbol; } + /** + * Sets the renamed declare object to symbol + */ + void setRenamedSymbol( PMSymbol* symbol ) { m_pRenamedSymbol = symbol; } + +private: + PMSymbolType m_type; + PMDeclare* m_pObj; + PMSymbol* m_pRenamedSymbol; + PMValue* m_pVal; + QString m_id; +}; + +/** + * Symbol table for povray #declare statements + */ +class PMSymbolTable : public QDict +{ +public: + /** + * Constructor + */ + PMSymbolTable( ); + /** + * Destructor + */ + ~PMSymbolTable( ); + /** + * Returns a free id with prefix prefix and a number as suffix + */ + QString findNewID( const QString& prefix ); + /** + * Returns a free id with prefix prefix and a number as suffix and assigns + * it to the object. + * + * Does NOT add the object to the symbol table. + * + * Returns the new symbol.*/ + PMSymbol* findNewID( const QString& prefix, PMDeclare* obj ); +private: + QDict m_lastID; +}; + +#endif diff --git a/kpovmodeler/pmtext.cpp b/kpovmodeler/pmtext.cpp new file mode 100644 index 00000000..21191cbc --- /dev/null +++ b/kpovmodeler/pmtext.cpp @@ -0,0 +1,339 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmtext.h" + +#include "pmxmlhelper.h" +#include "pmtextedit.h" +#include "pmmemento.h" +#include "pmviewstructure.h" +#include "pmresourcelocator.h" +#include "pmtruetypecache.h" +#include "pmdefaults.h" + +#include + +const QString c_defaultFont = QString( "" ); +const QString c_defaultText = QString( "" ); +const double c_defaultThickness = 1.0; +const PMVector c_defaultOffset = PMVector( 0.0, 0.0 ); + +int PMText::s_parameterKey = 0; +int PMText::s_steps = c_defaultTextSteps; + +PMDefinePropertyClass( PMText, PMTextProperty ); + +PMMetaObject* PMText::s_pMetaObject = 0; +PMObject* createNewText( PMPart* part ) +{ + return new PMText( part ); +} + +PMText::PMText( PMPart* part ) + : Base( part ) +{ + m_text = c_defaultText; + m_font = c_defaultFont; + m_thickness = c_defaultThickness; + m_offset = c_defaultOffset; +} + +PMText::PMText( const PMText& t ) + : Base( t ) +{ + m_text = t.m_text; + m_font = t.m_font; + m_thickness = t.m_thickness; + m_offset = t.m_offset; +} + +PMText::~PMText( ) +{ +} + +QString PMText::description( ) const +{ + return i18n( "text" ); +} + +void PMText::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "font", m_font ); + e.setAttribute( "text", m_text ); + e.setAttribute( "thickness", m_thickness ); + e.setAttribute( "offset", m_offset.serializeXML( ) ); + Base::serialize( e, doc ); +} + +void PMText::readAttributes( const PMXMLHelper& h ) +{ + m_font = h.stringAttribute( "font", c_defaultFont ); + m_text = h.stringAttribute( "text", c_defaultText ); + m_thickness = h.doubleAttribute( "thickness", c_defaultThickness ); + m_offset = h.vectorAttribute( "offset", c_defaultOffset ); + Base::readAttributes( h ); +} + +PMMetaObject* PMText::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Text", Base::metaObject( ), + createNewText ); + s_pMetaObject->addProperty( + new PMTextProperty( "font", &PMText::setFont, &PMText::font ) ); + s_pMetaObject->addProperty( + new PMTextProperty( "text", &PMText::setText, &PMText::text ) ); + s_pMetaObject->addProperty( + new PMTextProperty( "thickness", &PMText::setThickness, &PMText::thickness ) ); + s_pMetaObject->addProperty( + new PMTextProperty( "offset", &PMText::setOffset, &PMText::offset ) ); + } + return s_pMetaObject; +} + +void PMText::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMText::setFont( const QString& f ) +{ + if( f != m_font ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFontID, m_font ); + m_font = f; + setViewStructureChanged( ); + } +} + +void PMText::setText( const QString& t ) +{ + if( t != m_text ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMTextID, m_text ); + m_text = t; + setViewStructureChanged( ); + } +} + +void PMText::setThickness( double t ) +{ + if( t != m_thickness ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMThicknessID, m_thickness ); + m_thickness = t; + setViewStructureChanged( ); + } +} + +void PMText::setOffset( const PMVector& o ) +{ + if( o != m_offset ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMOffsetID, m_offset ); + m_offset = o; + m_offset.resize( 2 ); + setViewStructureChanged( ); + } +} + +PMDialogEditBase* PMText::editWidget( QWidget* parent ) const +{ + return new PMTextEdit( parent ); +} + +void PMText::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMFontID: + setFont( data->stringData( ) ); + break; + case PMTextID: + setText( data->stringData( ) ); + break; + case PMThicknessID: + setThickness( data->doubleData( ) ); + break; + case PMOffsetID: + setOffset( data->vectorData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMText::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + +void PMText::createViewStructure( ) +{ + // calculate needed points and lines + int nlines = 0, npoints = 0; + + QString file = PMResourceLocator::findFile( m_font ); + PMTrueTypeFont* font = PMTrueTypeCache::font( file ); + + if( font && font->isValid( ) ) + { + QTextStream str( &m_text, IO_ReadOnly ); + QChar c; + PMTrueTypeOutline* ol; + + while( !str.atEnd( ) ) + { + str >> c; + ol = font->outline( c ); + if( ol ) + { + npoints += ol->segments( ) * 2 * s_steps; + nlines += ol->segments( ) * ( 2 * s_steps + 1 ); + } + } + } + + if( !m_pViewStructure ) + m_pViewStructure = new PMViewStructure( npoints, nlines ); + else + { + if( m_pViewStructure->points( ).size( ) != ( unsigned ) npoints ) + m_pViewStructure->points( ).resize( npoints ); + if( m_pViewStructure->lines( ).size( ) != ( unsigned ) nlines ) + m_pViewStructure->lines( ).resize( nlines ); + } + + if( ( nlines > 0 ) && ( npoints > 0 ) && font ) + { + // create the view structure + QTextStream str( &m_text, IO_ReadOnly ); + QChar c, oldc; + PMTrueTypeOutline* ol; + double dp = 1.0 / s_steps; + int i; + int hnpoints = npoints / 2; + int pbase = 0; + int lbase = 0; + PMVector v2( 2 ); + PMVector v3( 3 ); + int firstPoint = 0; + PMVector coffset( 0.0, 0.0, 0.0 ); + double kerning = 0; + + PMPointArray& points = m_pViewStructure->points( ); + PMLineArray& lines = m_pViewStructure->lines( ); + + while( !str.atEnd( ) ) + { + // iterate over all characters with valid outline + + str >> c; + ol = font->outline( c ); + if( ol ) + { + // kerning offset + kerning = font->kerning( oldc, c ); + coffset[0] += kerning; + + const PMSegmentListList& out = ol->outline( ); + PMSegmentListList::ConstIterator oit; + for( oit = out.begin( ); oit != out.end( ); ++oit ) + { + // iterate over all contours + + PMSegmentList::ConstIterator sit; + PMSegmentList::ConstIterator eit = ( *oit ).end( ); + eit--; + + firstPoint = pbase; + for( sit = ( *oit ).begin( ); sit != ( *oit ).end( ); ++sit ) + { + // iterate over all segments for the current contour + + lines[lbase] = PMLine( pbase, pbase + hnpoints ); + lbase++; + + for( i = 0; i < s_steps; i++ ) + { + v2 = ( *sit ).point( i * dp ); + v3[0] = v2[0]; + v3[1] = v2[1]; + v3[2] = 0.0; + v3 += coffset; + points[pbase] = PMPoint( v3 ); + v3[2] = m_thickness; + points[pbase + hnpoints] = PMPoint( v3 ); + + if( ( i != ( s_steps - 1 ) ) || ( sit != eit ) ) + { + lines[lbase] = PMLine( pbase, pbase + 1 ); + lbase++; + lines[lbase] = PMLine( pbase + hnpoints, + pbase + hnpoints + 1 ); + lbase++; + } + else + { + lines[lbase] = PMLine( firstPoint, pbase ); + lbase++; + lines[lbase] = PMLine( firstPoint + hnpoints, + pbase + hnpoints ); + lbase++; + } + + pbase++; + } + } + } + coffset[0] -= kerning; + coffset[0] += ol->advance( ); + coffset += m_offset; + } + oldc = c; + } + if( ( lbase != nlines ) || ( pbase != hnpoints ) ) + kdError( PMArea ) << "PMText::createViewStructure is buggy!\n"; + } +} + +void PMText::setSteps( int s ) +{ + if( s >= 1 ) + s_steps = s; + else + kdDebug( PMArea ) << "PMText::setSteps: S must be greater than 0\n"; + s_parameterKey++; +} diff --git a/kpovmodeler/pmtext.h b/kpovmodeler/pmtext.h new file mode 100644 index 00000000..3a7350bb --- /dev/null +++ b/kpovmodeler/pmtext.h @@ -0,0 +1,147 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMTEXT_H +#define PMTEXT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" +#include "pmvector.h" + +class PMViewStructure; + +/** + * Class for povray truetype texts. + */ + +class PMText : public PMSolidObject +{ + typedef PMSolidObject Base; +public: + /** + * Creates an empty PMText + */ + PMText( PMPart* part ); + /** + * Copy constructor + */ + PMText( const PMText& t ); + /** + * deletes the PMText + */ + virtual ~PMText( ); + + /** */ + virtual PMObject* copy( ) const { return new PMText( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMTextEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmtext" ); } + + /** + * Returns the font file + */ + QString font( ) const { return m_font; } + /** + * Sets the font file + */ + void setFont( const QString& f ); + /** + * Returns the text + */ + QString text( ) const { return m_text; } + /** + * Sets the text + */ + void setText( const QString& t ); + /** + * Returns the thickness + */ + double thickness( ) const { return m_thickness; } + /** + * Sets the thickness + */ + void setThickness( double t ); + /** + * Returns the additional offset (2D vector) + */ + PMVector offset( ) const { return m_offset; } + /** + * Sets the offset (2D vector) + */ + void setOffset( const PMVector& o ); + + /** */ + virtual void restoreMemento( PMMemento* s ); + + /** + * Call this if the povray library paths have changed + */ + static void povrayLibraryPathsChanged( ) { s_parameterKey++; } + /** + * Returns the number of lines for rendering + */ + static int steps( ) { return s_steps; } + /** + * Sets the number of lines for rendering + */ + static void setSteps( int s ); + +protected: + /** */ + virtual void createViewStructure( ); + /** */ + virtual int viewStructureParameterKey( ) const { return s_parameterKey; } + +private: + /** + * IDs for @ref PMMementoData + */ + enum PMTextMementoID { PMFontID, PMTextID, PMThicknessID, PMOffsetID }; + QString m_font, m_text; + double m_thickness; + PMVector m_offset; + + static int s_steps; + static int s_parameterKey; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmtextedit.cpp b/kpovmodeler/pmtextedit.cpp new file mode 100644 index 00000000..16f8501d --- /dev/null +++ b/kpovmodeler/pmtextedit.cpp @@ -0,0 +1,138 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmtextedit.h" +#include "pmtext.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" + +#include +#include +#include +#include +#include +#include +#include + +PMTextEdit::PMTextEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMTextEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QHBoxLayout* hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Font:" ), this ) ); + m_pFont = new QLineEdit( this ); + hl->addWidget( m_pFont ); + m_pChooseFont = new QPushButton( this ); + m_pChooseFont->setPixmap( SmallIcon( "fileopen" ) ); + hl->addWidget( m_pChooseFont ); + + hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Text:" ), this ) ); + m_pText = new QLineEdit( this ); + hl->addWidget( m_pText ); + + hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Thickness:" ), this ) ); + m_pThickness = new PMFloatEdit( this ); + hl->addWidget( m_pThickness ); + hl->addStretch( 1 ); + + hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( new QLabel( i18n( "Offset:" ), this ) ); + m_pOffset = new PMVectorEdit( "x", "y", this ); + hl->addWidget( m_pOffset ); + + connect( m_pFont, SIGNAL( textChanged( const QString& ) ), + SLOT( slotTextChanged( const QString& ) ) ); + connect( m_pChooseFont, SIGNAL( clicked( ) ), + SLOT( slotChooseFont( ) ) ); + connect( m_pText, SIGNAL( textChanged( const QString& ) ), + SLOT( slotTextChanged( const QString& ) ) ); + connect( m_pThickness, SIGNAL( dataChanged( ) ), + SIGNAL( dataChanged( ) ) ); + connect( m_pOffset, SIGNAL( dataChanged( ) ), + SIGNAL( dataChanged( ) ) ); +} + +void PMTextEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Text" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMText* ) o; + + m_pFont->setText( m_pDisplayedObject->font( ) ); + m_pText->setText( m_pDisplayedObject->text( ) ); + m_pThickness->setValue( m_pDisplayedObject->thickness( ) ); + m_pOffset->setVector( m_pDisplayedObject->offset( ) ); + + m_pFont->setReadOnly( readOnly ); + m_pChooseFont->setEnabled( !readOnly ); + m_pText->setReadOnly( readOnly ); + m_pThickness->setReadOnly( readOnly ); + m_pOffset->setReadOnly( readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMTextEdit: Can't display object\n"; +} + +void PMTextEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setFont( m_pFont->text( ) ); + m_pDisplayedObject->setText( m_pText->text( ) ); + m_pDisplayedObject->setThickness( m_pThickness->value( ) ); + m_pDisplayedObject->setOffset( m_pOffset->vector( ) ); + } +} + +bool PMTextEdit::isDataValid( ) +{ + if( m_pThickness->isDataValid( ) ) + if( m_pOffset->isDataValid( ) ) + return Base::isDataValid( ); + return false; +} + +void PMTextEdit::slotTextChanged( const QString& ) +{ + emit dataChanged( ); +} + +void PMTextEdit::slotChooseFont( ) +{ + QString str = KFileDialog::getOpenFileName( QString::null, QString::null ); + + if( !str.isEmpty() ) + { + m_pFont->setText( str ); + emit dataChanged( ); + } +} + +#include "pmtextedit.moc" diff --git a/kpovmodeler/pmtextedit.h b/kpovmodeler/pmtextedit.h new file mode 100644 index 00000000..3dd11280 --- /dev/null +++ b/kpovmodeler/pmtextedit.h @@ -0,0 +1,74 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMTEXTEDIT_H +#define PMTEXTEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" + +class PMText; +class PMVectorEdit; +class PMFloatEdit; +class QLineEdit; +class QPushButton; + +/** + * Dialog edit class for @ref PMText + */ +class PMTextEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMTextEdit with parent and name + */ + PMTextEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); + +protected slots: + void slotTextChanged( const QString& t ); + void slotChooseFont( ); + +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMText* m_pDisplayedObject; + QLineEdit* m_pFont; + QPushButton* m_pChooseFont; + QLineEdit* m_pText; + PMFloatEdit* m_pThickness; + PMVectorEdit* m_pOffset; +}; + + +#endif diff --git a/kpovmodeler/pmtexture.cpp b/kpovmodeler/pmtexture.cpp new file mode 100644 index 00000000..4b8a21ff --- /dev/null +++ b/kpovmodeler/pmtexture.cpp @@ -0,0 +1,124 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmtexture.h" +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmtextureedit.h" + +#include + +PMDefinePropertyClass( PMTexture, PMTextureProperty ); + +PMMetaObject* PMTexture::s_pMetaObject = 0; +PMObject* createNewTexture( PMPart* part ) +{ + return new PMTexture( part ); +} + +PMTexture::PMTexture( PMPart* part ) : Base( part ) +{ + m_uvMapping = false; +} + +PMTexture::PMTexture( const PMTexture& t ) : Base( t ) +{ + m_uvMapping = t.m_uvMapping; +} + +PMTexture::~PMTexture( ) +{ +} + +PMMetaObject* PMTexture::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Texture", Base::metaObject( ), + createNewTexture ); + s_pMetaObject->addProperty( + new PMTextureProperty( "uvMapping", &PMTexture::setUVMapping, &PMTexture::uvMapping ) ); + } + return s_pMetaObject; +} + +void PMTexture::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMTexture::description( ) const +{ + return i18n( "texture" ); +} + +PMDialogEditBase* PMTexture::editWidget( QWidget* parent ) const +{ + return new PMTextureEdit( parent ); +} + +void PMTexture::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "uv_mapping", m_uvMapping ); + Base::serialize( e, doc ); +} + +void PMTexture::readAttributes( const PMXMLHelper& h ) +{ + m_uvMapping = h.boolAttribute( "uv_mapping", false ); + Base::readAttributes( h ); +} + +void PMTexture::setUVMapping( bool m ) +{ + if( m != m_uvMapping ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMUVMappingID, m_uvMapping ); + m_uvMapping = m; + } +} + +void PMTexture::restoreMemento( PMMemento *s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMUVMappingID: + setUVMapping( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMTexture::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmtexture.h b/kpovmodeler/pmtexture.h new file mode 100644 index 00000000..b8b176db --- /dev/null +++ b/kpovmodeler/pmtexture.h @@ -0,0 +1,95 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMTEXTURE_H +#define PMTEXTURE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebase.h" + +/** + * Class for povray textures + */ +class PMTexture : public PMTextureBase +{ + typedef PMTextureBase Base; +public: + /** + * Creates an PMTexture + */ + PMTexture( PMPart* part ); + /** + * Copy constructor + */ + PMTexture( const PMTexture& t ); + /** + * Deletes the object + */ + virtual ~PMTexture( ); + + /** */ + virtual PMObject* copy( ) const { return new PMTexture( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMTextureEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pmtexture" ); } + + /** + * Returns the uv mapping flag + */ + bool uvMapping() const { return m_uvMapping; } + /** + * Sets the uv maaping flag + */ + void setUVMapping( bool m ); + + /** */ + virtual void restoreMemento( PMMemento *s ); + +private: + /** + * IDs for @ref PMMementoData + */ + enum PMPigmentMementoID { PMUVMappingID }; + + bool m_uvMapping; + + static PMMetaObject* s_pMetaObject; +}; + + +#endif diff --git a/kpovmodeler/pmtexturebase.cpp b/kpovmodeler/pmtexturebase.cpp new file mode 100644 index 00000000..82a92418 --- /dev/null +++ b/kpovmodeler/pmtexturebase.cpp @@ -0,0 +1,180 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmtexturebase.h" +#include "pmdeclare.h" +#include "pmpart.h" +#include "pmsymboltable.h" +#include "pmtexturebaseedit.h" +#include "pmparser.h" + +#include "pmmemento.h" +#include "pmxmlhelper.h" + +#include + +PMDefinePropertyClass( PMTextureBase, PMTextureBaseProperty ); + +PMMetaObject* PMTextureBase::s_pMetaObject = 0; + +PMTextureBase::PMTextureBase( PMPart* part ) + : Base( part ) +{ + m_pLinkedObject = 0; +} + +PMTextureBase::PMTextureBase( const PMTextureBase& b ) + : Base( b ) +{ + m_pLinkedObject = 0; + setLinkedObject( b.m_pLinkedObject ); +} + +PMTextureBase::~PMTextureBase( ) +{ +} + +PMMetaObject* PMTextureBase::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "TextureBase", Base::metaObject( ) ); + s_pMetaObject->addProperty( + new PMTextureBaseProperty( "linkedObject", &PMTextureBase::setLinkedObjectProperty, + &PMTextureBase::linkedObjectProperty ) ); + s_pMetaObject->addProperty( + new PMTextureBaseProperty( "hasLinkedObject", 0, &PMTextureBase::hasLinkedObject ) ); + } + return s_pMetaObject; +} + +void PMTextureBase::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +bool PMTextureBase::setLinkedObject( PMDeclare* obj ) +{ + if( obj ) + { + if( obj->declareType( ) == type( ) ) + { + if( m_pLinkedObject != obj ) + { + if( m_pMemento ) + { + m_pMemento->addData( s_pMetaObject, PMLinkedObjectID, + m_pLinkedObject ); + m_pMemento->setViewStructureChanged( ); + } + + if( m_pLinkedObject ) + { + m_pLinkedObject->removeLinkedObject( this ); + if( m_pMemento ) + m_pMemento->addChangedObject( m_pLinkedObject, PMCData ); + } + m_pLinkedObject = obj; + m_pLinkedObject->addLinkedObject( this ); + if( m_pMemento ) + m_pMemento->addChangedObject( m_pLinkedObject, PMCData ); + } + return true; + } + } + else + { + if( m_pLinkedObject != 0 ) + { + if( m_pMemento ) + { + m_pMemento->addData( s_pMetaObject, PMLinkedObjectID, + m_pLinkedObject ); + m_pMemento->addChangedObject( m_pLinkedObject, PMCData ); + } + m_pLinkedObject->removeLinkedObject( this ); + m_pLinkedObject = 0; + } + return true; + } + return false; +} + +void PMTextureBase::setLinkedObjectProperty( PMObject* o ) +{ + if( o == 0 ) + setLinkedObject( 0 ); + else if( o->isA( "Declare" ) ) + setLinkedObject( ( PMDeclare* ) o ); +} + +void PMTextureBase::serialize( QDomElement& e, QDomDocument& doc ) const +{ + if( m_pLinkedObject ) + e.setAttribute( "prototype", m_pLinkedObject->id( ) ); + Base::serialize( e, doc ); +} + +void PMTextureBase::readAttributes( const PMXMLHelper& h ) +{ + QString id = h.stringAttribute( "prototype", "" ); + if( !id.isEmpty( ) ) + { + PMDeclare* link = h.parser( )->checkLink( id ); + if( link ) + { + if( link->declareType( ) == type( ) ) + { + m_pLinkedObject = link; + m_pLinkedObject->addLinkedObject( this ); + } + else + h.parser( )->printError( i18n( "Declare \"%1\" has wrong type." ) + .arg( id ) ); + } + } +} + +void PMTextureBase::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMLinkedObjectID: + setLinkedObject( ( PMDeclare* ) data->objectData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMTextureBase::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmtexturebase.h b/kpovmodeler/pmtexturebase.h new file mode 100644 index 00000000..2bd687f6 --- /dev/null +++ b/kpovmodeler/pmtexturebase.h @@ -0,0 +1,96 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMTEXTUREBASE_H +#define PMTEXTUREBASE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "pmnamedobject.h" +#include "pmdeclare.h" + +/** + * Base class for all textures that can link to declares + */ +class PMTextureBase : public PMNamedObject +{ + typedef PMNamedObject Base; +public: + /** + * Creates an PMTextureBase + */ + PMTextureBase( PMPart* part ); + /** + * Copy constructor + */ + PMTextureBase( const PMTextureBase& b ); + /** + * Deletes the object + */ + virtual ~PMTextureBase( ); + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void restoreMemento( PMMemento* s ); + + /** */ + virtual PMDeclare* linkedObject( ) const { return m_pLinkedObject; } + /** + * Sets the linked object. Returns true if successful + */ + bool setLinkedObject( PMDeclare* o ); + /** + * Returns true if a linked object is set. Used by the + * insert possibilities framework. + */ + bool hasLinkedObject( ) const { return m_pLinkedObject; } + + /** + * Method used by the properties framework + */ + PMObject* linkedObjectProperty( ) const { return m_pLinkedObject; } + /** + * Method used by the properties framework + */ + void setLinkedObjectProperty( PMObject* o ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMTextureBaseMementoID { PMLinkedObjectID }; + PMDeclare* m_pLinkedObject; + + static PMMetaObject* s_pMetaObject; +}; + + +#endif diff --git a/kpovmodeler/pmtexturebaseedit.cpp b/kpovmodeler/pmtexturebaseedit.cpp new file mode 100644 index 00000000..e9b91486 --- /dev/null +++ b/kpovmodeler/pmtexturebaseedit.cpp @@ -0,0 +1,72 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmtexturebaseedit.h" +#include "pmpigment.h" +#include "pmlinkedit.h" + +#include +#include +#include + + +PMTextureBaseEdit::PMTextureBaseEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + + +void PMTextureBaseEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + m_pLinkEdit = new PMLinkEdit( this ); + topLayout( )->addWidget( m_pLinkEdit ); + connect( m_pLinkEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + + +void PMTextureBaseEdit::displayObject( PMObject* o ) +{ + if( o->isA( "TextureBase" ) ) + { + m_pDisplayedObject = ( PMTextureBase* ) o; + m_pLinkEdit->setReadOnly( o->isReadOnly( ) ); + m_pLinkEdit->setDisplayedObject( o ); + m_pLinkEdit->setLinkPossibility( m_pDisplayedObject->type( ) ); + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMTextureBaseEdit: Can't display object\n"; +} + +void PMTextureBaseEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setLinkedObject( m_pLinkEdit->link( ) ); + } +} + +void PMTextureBaseEdit::enableLinkEdit( bool enable ) +{ + m_pLinkEdit->setEnabled( enable ); +} + +#include "pmtexturebaseedit.moc" diff --git a/kpovmodeler/pmtexturebaseedit.h b/kpovmodeler/pmtexturebaseedit.h new file mode 100644 index 00000000..b8d67f56 --- /dev/null +++ b/kpovmodeler/pmtexturebaseedit.h @@ -0,0 +1,64 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMTEXTUREBASEEDIT_H +#define PMTEXTUREBASEEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmnamedobjectedit.h" + +class PMTextureBase; +class PMLinkEdit; + +/** + * Dialog edit class for @ref PMTextureBase + */ +class PMTextureBaseEdit : public PMNamedObjectEdit +{ + Q_OBJECT + typedef PMNamedObjectEdit Base; +public: + /** + * Creates a PMTextureBaseEdit with parent and name + */ + PMTextureBaseEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + /** + * Enables/disables the link edit widget + */ + void enableLinkEdit( bool enable ); + +private: + PMTextureBase* m_pDisplayedObject; + PMLinkEdit* m_pLinkEdit; +}; + + +#endif diff --git a/kpovmodeler/pmtextureedit.cpp b/kpovmodeler/pmtextureedit.cpp new file mode 100644 index 00000000..8a3d4f9f --- /dev/null +++ b/kpovmodeler/pmtextureedit.cpp @@ -0,0 +1,67 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmtextureedit.h" +#include "pmtexture.h" +#include "pmlinkedit.h" + +#include +#include +#include + + +PMTextureEdit::PMTextureEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMTextureEdit::createTopWidgets() +{ + Base::createTopWidgets(); + m_pUVMapping = new QCheckBox( i18n( "UV mapping" ), this ); + topLayout( )->addWidget( m_pUVMapping ); + + connect( m_pUVMapping, SIGNAL( clicked() ), SIGNAL( dataChanged() ) ); +} + +void PMTextureEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Texture" ) ) + { + m_pDisplayedObject = ( PMTexture* ) o; + bool readOnly = m_pDisplayedObject->isReadOnly( ); + m_pUVMapping->setChecked( m_pDisplayedObject->uvMapping() ); + m_pUVMapping->setEnabled( !readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMTextureEdit: Can't display object\n"; +} + +void PMTextureEdit::saveContents() +{ + if( m_pDisplayedObject ) + { + Base::saveContents(); + m_pDisplayedObject->setUVMapping( m_pUVMapping->isChecked() ); + } +} + +#include "pmtextureedit.moc" diff --git a/kpovmodeler/pmtextureedit.h b/kpovmodeler/pmtextureedit.h new file mode 100644 index 00000000..7b799a5e --- /dev/null +++ b/kpovmodeler/pmtextureedit.h @@ -0,0 +1,60 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMTEXTUREEDIT_H +#define PMTEXTUREEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebaseedit.h" + +class PMTexture; +class QCheckBox; + +/** + * Dialog edit class for @ref PMTexture + */ +class PMTextureEdit : public PMTextureBaseEdit +{ + Q_OBJECT + typedef PMTextureBaseEdit Base; +public: + /** + * Creates a PMTextureEdit with parent and name + */ + PMTextureEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMTexture* m_pDisplayedObject; + QCheckBox* m_pUVMapping; +}; + + +#endif diff --git a/kpovmodeler/pmtexturemap.cpp b/kpovmodeler/pmtexturemap.cpp new file mode 100644 index 00000000..fad93c61 --- /dev/null +++ b/kpovmodeler/pmtexturemap.cpp @@ -0,0 +1,601 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmtexturemapedit.h" +#include "pmtexturemap.h" + +#include "pmxmlhelper.h" +#include "pmmapmemento.h" + +#include +#include + +class PMValueProperty : public PMPropertyBase +{ +public: + PMValueProperty( ) + : PMPropertyBase( "mapValues", PMVariant::Double ) + { + m_index = 0; + } + virtual int dimensions( ) const { return 1; } + virtual void setIndex( int /*dimension*/, int index ) + { + m_index = index; + } + virtual int size( PMObject* object, int /*dimension*/ ) const + { + return ( ( PMTextureMapBase* ) object )->mapEntries( ); + } +protected: + virtual bool setProtected( PMObject* obj, const PMVariant& var ) + { + PMTextureMapBase* m = ( PMTextureMapBase* ) obj; + QValueList list = m->mapValues( ); + QValueList::Iterator it = list.at( m_index ); + + if( it == list.end( ) ) + { + kdError( PMArea ) << "Range error in PMTextureMapBase::ValueProperty::set" << endl; + return false; + } + + *it = var.doubleData( ); + + m->setMapValues( list ); + return true; + } + virtual PMVariant getProtected( const PMObject* obj ) + { + PMTextureMapBase* m = ( PMTextureMapBase* ) obj; + QValueList list = m->mapValues( ); + QValueList::ConstIterator it = list.at( m_index ); + + if( it == list.end( ) ) + { + kdError( PMArea ) << "Range error in PMTextureMapBase::ValueProperty::get" << endl; + return PMVariant( ); + } + + return PMVariant( *it ); + } + +private: + int m_index; +}; + + +PMMetaObject* PMTextureMapBase::s_pMetaObject = 0; + +PMTextureMapBase::PMTextureMapBase( PMPart* part ) + : Base( part ) +{ +} + +PMTextureMapBase::PMTextureMapBase( const PMTextureMapBase& m ) + : Base( m ) +{ +} + +PMTextureMapBase::~PMTextureMapBase( ) +{ +} + +void PMTextureMapBase::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "map_values", valuesToString( ) ); + Base::serialize( e, doc ); +} + +void PMTextureMapBase::readAttributes( const PMXMLHelper& h ) +{ + stringToValues( h.stringAttribute( "map_values", "" ) ); + Base::readAttributes( h ); +} + +QString PMTextureMapBase::valuesToString( ) const +{ + QString str; + QValueList::ConstIterator it; + + it = m_mapValues.begin( ); + if( it != m_mapValues.end( ) ) + { + str.setNum( *it ); + ++it; + for( ; it != m_mapValues.end( ); ++it ) + str += QString( " %1" ).arg( *it ); + } + return str; +} + +void PMTextureMapBase::stringToValues( const QString& str ) +{ + m_mapValues.clear( ); + QString tstr = str; + QTextIStream s( &tstr ); + double d; + + while( !s.atEnd( ) ) + { + s >> d; + m_mapValues.append( d ); + } +} + +PMMetaObject* PMTextureMapBase::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "TextureMapBase", Base::metaObject( ) ); + s_pMetaObject->addProperty( new PMValueProperty( ) ); + } + return s_pMetaObject; +} + +void PMTextureMapBase::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +PMDialogEditBase* PMTextureMapBase::editWidget( QWidget* parent ) const +{ + return new PMTextureMapEdit( parent ); +} + +void PMTextureMapBase::restoreMemento( PMMemento* s ) +{ + PMMapMemento* m = ( PMMapMemento* ) s; + if( m->mapValuesSaved( ) ) + { + if( m_pMemento ) + ( ( PMMapMemento* ) m_pMemento )->setMapValues( m_mapValues ); + m_mapValues = m->mapValues( ); + } + if( m->removedValuesSaved( ) ) + { + if( m_pMemento ) + ( ( PMMapMemento* ) m_pMemento )->setRemovedValues( m_removedValues ); + m_removedValues = m->removedValues( ); + } + + Base::restoreMemento( s ); +} + +void PMTextureMapBase::createMemento( ) +{ + if( m_pMemento ) + delete m_pMemento; + m_pMemento = new PMMapMemento( this ); +} + +QValueList::Iterator PMTextureMapBase::valueForChild( PMObject* obj ) +{ + PMObject* o = firstChild( ); + QValueList::Iterator it = m_mapValues.begin( ); + + while( o && ( o != obj ) ) + { + if( o->type( ) == mapType( ) ) + ++it; + o = o->nextSibling( ); + } + return it; +} + +double PMTextureMapBase::mapValue( const PMObject* obj ) const +{ + PMObject* o = firstChild( ); + QValueList::ConstIterator it = m_mapValues.begin( ); + + while( o && ( o != obj ) ) + { + if( o->type( ) == mapType( ) ) + ++it; + o = o->nextSibling( ); + } + return *it; +} + +void PMTextureMapBase::childAdded( PMObject* ao ) +{ + if( ( unsigned ) countChildren( ) <= m_mapValues.count( ) ) + return; + + if( m_pMemento ) + ( ( PMMapMemento* ) m_pMemento )->setMapValues( m_mapValues ); + if( m_removedValues.isEmpty( ) ) + { + QValueList::Iterator it = valueForChild( ao ); + if( it == m_mapValues.end( ) ) + { + --it; + if( it == m_mapValues.end( ) ) + m_mapValues.append( 0.0 ); + else + { + double v = *it + 0.1; + if( v > 1.0 ) + v = 1.0; + m_mapValues.append( v ); + } + } + else if( it == m_mapValues.begin( ) ) + m_mapValues.prepend( 0.0 ); + else + { + double va = *it; + double vb = *( --it ); + m_mapValues.insert( ++it, ( va + vb ) / 2.0 ); + } + } + else + { + if( m_pMemento ) + ( ( PMMapMemento* ) m_pMemento )->setRemovedValues( m_removedValues ); + + QValueList::Iterator it = m_mapValues.begin( ); + bool stop = false; + double v = m_removedValues.last( ); + m_removedValues.remove( m_removedValues.fromLast( ) ); + + while( ( it != m_mapValues.end( ) ) && !stop ) + { + if( ( *it ) > v ) + stop = true; + else + ++it; + } + m_mapValues.insert( it, v ); + } +} + +bool PMTextureMapBase::takeChild( PMObject* o ) +{ + if( m_pMemento ) + { + ( ( PMMapMemento* ) m_pMemento )->setMapValues( m_mapValues ); + ( ( PMMapMemento* ) m_pMemento )->setRemovedValues( m_removedValues ); + } + + QValueList::Iterator it = valueForChild( o ); + if( it != m_mapValues.end( ) ) + { + m_removedValues.append( *it ); + m_mapValues.remove( it ); + } + + return Base::takeChild( o ); +} + +void PMTextureMapBase::setMapValues( const QValueList& v ) +{ + if( m_pMemento ) + { + ( ( PMMapMemento* ) m_pMemento )->setMapValues( m_mapValues ); + ( ( PMMapMemento* ) m_pMemento )->setRemovedValues( m_removedValues ); + } + m_removedValues.clear( ); + m_mapValues = v; +} + +PMObject* PMTextureMapBase::nextMapEntry( PMObject* o ) +{ + bool stop = false; + PMObject* result = o; + + do + { + if( result == 0 ) + result = firstChild( ); + else + result = result->nextSibling( ); + + if( !result ) + stop = true; + else if( result->type( ) == mapType( ) ) + stop = true; + } + while( !stop ); + + return result; +} + + +PMMetaObject* PMTextureMap::s_pMetaObject = 0; +PMObject* createNewTextureMap( PMPart* part ) +{ + return new PMTextureMap( part ); +} + +PMTextureMap::PMTextureMap( PMPart* part ) + : Base( part ) +{ +} + +PMTextureMap::PMTextureMap( const PMTextureMap& m ) + : Base( m ) +{ +} + +PMTextureMap::~PMTextureMap( ) +{ +} + +PMMetaObject* PMTextureMap::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "TextureMap", Base::metaObject( ), + createNewTextureMap ); + } + return s_pMetaObject; +} + +void PMTextureMap::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMTextureMap::description( ) const +{ + return i18n( "texture map" ); +} + + +PMMetaObject* PMPigmentMap::s_pMetaObject = 0; +PMObject* createNewPigmentMap( PMPart* part ) +{ + return new PMPigmentMap( part ); +} + +PMPigmentMap::PMPigmentMap( PMPart* part ) + : Base( part ) +{ +} + +PMPigmentMap::PMPigmentMap( const PMPigmentMap& m ) + : Base( m ) +{ +} + +PMPigmentMap::~PMPigmentMap( ) +{ +} + +PMMetaObject* PMPigmentMap::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "PigmentMap", Base::metaObject( ), + createNewPigmentMap ); + } + return s_pMetaObject; +} + +void PMPigmentMap::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMPigmentMap::description( ) const +{ + return i18n( "pigment map" ); +} + + +PMMetaObject* PMColorMap::s_pMetaObject = 0; +PMObject* createNewColorMap( PMPart* part ) +{ + return new PMColorMap( part ); +} + +PMColorMap::PMColorMap( PMPart* part ) + : Base( part ) +{ +} + +PMColorMap::PMColorMap( const PMColorMap& m ) + : Base( m ) +{ +} + +PMColorMap::~PMColorMap( ) +{ +} + +PMMetaObject* PMColorMap::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "ColorMap", Base::metaObject( ), + createNewColorMap ); + } + return s_pMetaObject; +} + +void PMColorMap::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMColorMap::description( ) const +{ + return i18n( "color map" ); +} + + +PMMetaObject* PMNormalMap::s_pMetaObject = 0; +PMObject* createNewNormalMap( PMPart* part ) +{ + return new PMNormalMap( part ); +} + +PMNormalMap::PMNormalMap( PMPart* part ) + : Base( part ) +{ +} + +PMNormalMap::PMNormalMap( const PMNormalMap& m ) + : Base( m ) +{ +} + +PMNormalMap::~PMNormalMap( ) +{ +} + +PMMetaObject* PMNormalMap::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "NormalMap", Base::metaObject( ), + createNewNormalMap ); + } + return s_pMetaObject; +} + +void PMNormalMap::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMNormalMap::description( ) const +{ + return i18n( "normal map" ); +} + + +PMMetaObject* PMSlopeMap::s_pMetaObject = 0; +PMObject* createNewSlopeMap( PMPart* part ) +{ + return new PMSlopeMap( part ); +} + +PMSlopeMap::PMSlopeMap( PMPart* part ) + : Base( part ) +{ +} + +PMSlopeMap::PMSlopeMap( const PMSlopeMap& m ) + : Base( m ) +{ +} + +PMSlopeMap::~PMSlopeMap( ) +{ +} + +PMMetaObject* PMSlopeMap::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "SlopeMap", Base::metaObject( ), + createNewSlopeMap ); + } + return s_pMetaObject; +} + +void PMSlopeMap::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMSlopeMap::description( ) const +{ + return i18n( "slope map" ); +} + + +PMMetaObject* PMDensityMap::s_pMetaObject = 0; +PMObject* createNewDensityMap( PMPart* part ) +{ + return new PMDensityMap( part ); +} + +PMDensityMap::PMDensityMap( PMPart* part ) + : Base( part ) +{ +} + +PMDensityMap::PMDensityMap( const PMDensityMap& m ) + : Base( m ) +{ +} + +PMDensityMap::~PMDensityMap( ) +{ +} + +PMMetaObject* PMDensityMap::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "DensityMap", Base::metaObject( ), + createNewDensityMap ); + } + return s_pMetaObject; +} + +void PMDensityMap::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +QString PMDensityMap::description( ) const +{ + return i18n( "density map" ); +} + + + diff --git a/kpovmodeler/pmtexturemap.h b/kpovmodeler/pmtexturemap.h new file mode 100644 index 00000000..227c7e1f --- /dev/null +++ b/kpovmodeler/pmtexturemap.h @@ -0,0 +1,368 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMTEXTUREMAP_H +#define PMTEXTUREMAP_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebase.h" +#include "pmvector.h" + +#include + +/** + * Base class for color, pigment, texture and normal maps + */ + +class PMTextureMapBase : public PMTextureBase +{ + typedef PMTextureBase Base; +public: + /** + * Creates a PMTextureMapBase + */ + PMTextureMapBase( PMPart* part ); + /** + * Copy constructor + */ + PMTextureMapBase( const PMTextureMapBase& b ); + /** + * deletes the PMTextureMapBase + */ + virtual ~PMTextureMapBase( ); + + /** */ + virtual bool dataChangeOnInsertRemove( ) const { return true; } + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void childAdded( PMObject* o ); + /** */ + virtual bool takeChild( PMObject* o ); + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns the map object type + */ + virtual QString mapType( ) const = 0; + + /** + * Returns a new @ref PMTextureMapEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + + /** */ + virtual void createMemento( ); + /** */ + virtual void restoreMemento( PMMemento* s ); + + /** + * Returns the map values + */ + QValueList mapValues( ) const { return m_mapValues; } + /** + * Sets the map values + */ + void setMapValues( const QValueList& v ); + /** + * Returns the map value for the object o + */ + double mapValue( const PMObject* o ) const; + /** + * Returns the number of map entries + */ + int mapEntries( ) const { return m_mapValues.size( ); } + +private: + PMObject* nextMapEntry( PMObject* o ); + void stringToValues( const QString& str ); + QString valuesToString( ) const; + QValueList::Iterator valueForChild( PMObject* o ); + + /** + * IDs for @ref PMMementoData + */ + // enum PMTextureMapBaseMementoID { }; + + /** + * list of map values + */ + QValueList m_mapValues; + /** + * removed map values + */ + QValueList m_removedValues; + + static PMMetaObject* s_pMetaObject; +}; + + +/** + * Class for texture maps + */ + +class PMTextureMap : public PMTextureMapBase +{ +public: + typedef PMTextureMapBase Base; + /** + * Creates a texture map + */ + PMTextureMap( PMPart* part ); + /** + * Copy constructor + */ + PMTextureMap( const PMTextureMap& m ); + /** + * Deletes the texture map + */ + virtual ~PMTextureMap( ); + + /** */ + virtual PMObject* copy( ) const { return new PMTextureMap( *this ); } + /** */ + virtual QString description( ) const; + /** */ + virtual QString mapType( ) const { return QString( "Texture" ); } + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual QString pixmap( ) const { return QString( "pmtexturemap" ); } + +private: + static PMMetaObject* s_pMetaObject; +}; + +/** + * Class for pigment maps + */ + +class PMPigmentMap : public PMTextureMapBase +{ +public: + typedef PMTextureMapBase Base; + /** + * Creates a pigment map + */ + PMPigmentMap( PMPart* part ); + /** + * Copy constructor + */ + PMPigmentMap( const PMPigmentMap& m ); + /** + * Deletes the pigment map + */ + virtual ~PMPigmentMap( ); + + /** */ + virtual PMObject* copy( ) const { return new PMPigmentMap( *this ); } + /** */ + virtual QString description( ) const; + /** */ + virtual QString mapType( ) const { return QString( "Pigment" ); } + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual QString pixmap( ) const { return QString( "pmpigmentmap" ); } + +private: + static PMMetaObject* s_pMetaObject; +}; + +/** + * Class for color maps + */ + +class PMColorMap : public PMTextureMapBase +{ +public: + typedef PMTextureMapBase Base; + /** + * Creates a color map + */ + PMColorMap( PMPart* part ); + /** + * Copy constructor + */ + PMColorMap( const PMColorMap& m ); + /** + * Deletes the color map + */ + virtual ~PMColorMap( ); + + /** */ + virtual PMObject* copy( ) const { return new PMColorMap( *this ); } + /** */ + virtual QString description( ) const; + /** */ + virtual QString mapType( ) const { return QString( "SolidColor" ); } + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual QString pixmap( ) const { return QString( "pmcolormap" ); } + +private: + static PMMetaObject* s_pMetaObject; +}; + + +/** + * Class for normal maps + */ + +class PMNormalMap : public PMTextureMapBase +{ +public: + typedef PMTextureMapBase Base; + /** + * Creates a normal map + */ + PMNormalMap( PMPart* part ); + /** + * Copy constructor + */ + PMNormalMap( const PMNormalMap& m ); + /** + * Deletes the normal map + */ + virtual ~PMNormalMap( ); + + /** */ + virtual PMObject* copy( ) const { return new PMNormalMap( *this ); } + /** */ + virtual QString description( ) const; + /** */ + virtual QString mapType( ) const { return QString( "Normal" ); } + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual QString pixmap( ) const { return QString( "pmnormalmap" ); } + +private: + static PMMetaObject* s_pMetaObject; +}; + +/** + * Class for slope maps + */ + +class PMSlopeMap : public PMTextureMapBase +{ +public: + typedef PMTextureMapBase Base; + /** + * Creates a slope map + */ + PMSlopeMap( PMPart* part ); + /** + * Copy constructor + */ + PMSlopeMap( const PMSlopeMap& m ); + /** + * Deletes the slope map + */ + virtual ~PMSlopeMap( ); + + /** */ + virtual PMObject* copy( ) const { return new PMSlopeMap( *this ); } + /** */ + virtual QString description( ) const; + /** */ + virtual QString mapType( ) const { return QString( "Slope" ); } + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual QString pixmap( ) const { return QString( "pmslopemap" ); } + +private: + static PMMetaObject* s_pMetaObject; +}; + +/** + * Class for density maps + */ + +class PMDensityMap : public PMTextureMapBase +{ +public: + typedef PMTextureMapBase Base; + /** + * Creates a density map + */ + PMDensityMap( PMPart* part ); + /** + * Copy constructor + */ + PMDensityMap( const PMDensityMap& m ); + /** + * Deletes the density map + */ + virtual ~PMDensityMap( ); + + /** */ + virtual PMObject* copy( ) const { return new PMDensityMap( *this ); } + /** */ + virtual QString description( ) const; + /** */ + virtual QString mapType( ) const { return QString( "Density" ); } + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual QString pixmap( ) const { return QString( "pmdensitymap" ); } + +private: + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmtexturemapedit.cpp b/kpovmodeler/pmtexturemapedit.cpp new file mode 100644 index 00000000..6faf4376 --- /dev/null +++ b/kpovmodeler/pmtexturemapedit.cpp @@ -0,0 +1,152 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmtexturemapedit.h" +#include "pmtexturemap.h" +#include "pmlineedits.h" + +#include +#include +#include +#include + + +PMTextureMapEdit::PMTextureMapEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; + m_numValues = 0; +} + +void PMTextureMapEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + topLayout( )->addWidget( new QLabel( i18n( "Map values:" ), this ) ); + m_pNoChildLabel = new QLabel( i18n( "(No Child Objects)" ), this ); + m_pPureLinkLabel = new QLabel( i18n( "(Pure Link)" ), this ); + topLayout( )->addWidget( m_pNoChildLabel ); + topLayout( )->addWidget( m_pPureLinkLabel ); + QHBoxLayout* hl = new QHBoxLayout( topLayout( ) ); + m_pEditLayout = new QVBoxLayout( hl ); + hl->addStretch( 1 ); +} + +void PMTextureMapEdit::displayObject( PMObject* o ) +{ + QString str; + + if( o->isA( "TextureMapBase" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMTextureMapBase* ) o; + QValueList mv = m_pDisplayedObject->mapValues( ); + QValueList::Iterator vit = mv.begin( ); + QPtrListIterator eit( m_edits ); + PMFloatEdit* edit; + + m_numValues = 0; + + for( ; vit != mv.end( ); ++vit ) + { + if( eit.current( ) ) + { + eit.current( )->setValue( *vit ); + eit.current( )->show( ); + eit.current( )->setReadOnly( readOnly ); + ++eit; + } + else + { + edit = new PMFloatEdit( this ); + m_pEditLayout->addWidget( edit ); + m_edits.append( edit ); + edit->setValue( *vit ); + edit->setValidation( true, 0.0, true, 1.0 ); + edit->setReadOnly( readOnly ); + connect( edit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + } + m_numValues++; + } + for( ; eit.current( ); ++eit ) + eit.current( )->hide( ); + if( m_numValues == 0 ) + { + if( o->linkedObject( ) ) + { + m_pPureLinkLabel->show( ); + m_pNoChildLabel->hide( ); + } + else + { + m_pPureLinkLabel->hide( ); + m_pNoChildLabel->show( ); + } + } + else + { + m_pNoChildLabel->hide( ); + m_pPureLinkLabel->hide( ); + } + } + else + kdError( PMArea ) << "PMTextureMapEdit: Can't display object\n"; + Base::displayObject( o ); + enableLinkEdit( m_numValues == 0 ); +} + +void PMTextureMapEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + if( m_numValues > 0 ) + { + QPtrListIterator it( m_edits ); + int i = 0; + QValueList values; + + for( ; ( i < m_numValues ) && it.current( ); ++i, ++it ) + values.append( it.current( )->value( ) ); + m_pDisplayedObject->setMapValues( values ); + } + Base::saveContents( ); + } +} + +bool PMTextureMapEdit::isDataValid( ) +{ + QPtrListIterator it( m_edits ); + int i = 0; + double last = 0.0; + + for( ; ( i < m_numValues ) && it.current( ); ++i, ++it ) + { + if( !it.current( )->isDataValid( ) ) + return false; + if( it.current( )->value( ) < last ) + { + KMessageBox::error( this, i18n( "The map values have to be increasing." ), + i18n( "Error" ) ); + it.current( )->setFocus( ); + return false; + } + last = it.current( )->value( ); + } + return Base::isDataValid( ); +} + +#include "pmtexturemapedit.moc" diff --git a/kpovmodeler/pmtexturemapedit.h b/kpovmodeler/pmtexturemapedit.h new file mode 100644 index 00000000..818d7435 --- /dev/null +++ b/kpovmodeler/pmtexturemapedit.h @@ -0,0 +1,70 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMTEXTUREMAPEDIT_H +#define PMTEXTUREMAPEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmtexturebaseedit.h" +#include + +class PMTextureMapBase; +class PMFloatEdit; +class QWidget; +class QVBoxLayout; +class QLabel; + +/** + * Dialog edit class for @ref PMTextureMapBase. + */ +class PMTextureMapEdit : public PMTextureBaseEdit +{ + Q_OBJECT + typedef PMTextureBaseEdit Base; +public: + /** + * Creates a PMTextureMapEdit with parent and name + */ + PMTextureMapEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMTextureMapBase* m_pDisplayedObject; + QPtrList m_edits; + QVBoxLayout* m_pEditLayout; + QLabel* m_pNoChildLabel; + QLabel* m_pPureLinkLabel; + int m_numValues; +}; + + +#endif diff --git a/kpovmodeler/pmthreestate.h b/kpovmodeler/pmthreestate.h new file mode 100644 index 00000000..7dd04cf6 --- /dev/null +++ b/kpovmodeler/pmthreestate.h @@ -0,0 +1,26 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMTHREESTATE_H +#define PMTHREESTATE_H + +/** + * Type for three state attributes: true, false, unspecified + */ +enum PMThreeState { PMTrue, PMFalse, PMUnspecified }; + +#endif diff --git a/kpovmodeler/pmtokens.h b/kpovmodeler/pmtokens.h new file mode 100644 index 00000000..f1606e53 --- /dev/null +++ b/kpovmodeler/pmtokens.h @@ -0,0 +1,463 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMTOKENS_H +#define PMTOKENS_H + + +enum PMToken { + SCANNER_ERROR_TOK=-2, + EOF_TOK=-1, + //single character tokens + //reserved words in povray + AA_LEVEL_TOK=0x100, + AA_THRESHOLD_TOK, + ABS_TOK, + ABSORPTION_TOK, + ACCURACY_TOK, + ACOS_TOK, + ACOSH_TOK, + ADAPTIVE_TOK, + ADC_BAILOUT_TOK, + AGATE_TOK, + AGATE_TURB_TOK, + ALL_TOK, + ALL_INTERSECTIONS_TOK, + ALPHA_TOK, + ALTITUDE_TOK, + ALWAYS_SAMPLE_TOK, + AMBIENT_TOK, + AMBIENT_LIGHT_TOK, + ANGLE_TOK, + APERTURE_TOK, + ARC_ANGLE_TOK, + AREA_LIGHT_TOK, + AREA_CIRCULAR_TOK, + ASC_TOK, + ASIN_TOK, + ASINH_TOK, + ASSUMED_GAMMA_TOK, + ATAN_TOK, + ATAN2_TOK, + ATANH_TOK, + ATMOSPHERE_TOK, + ATMOSPHERIC_ATTENUATION_TOK, + ATTENUATING_TOK, + AUTOSTOP_TOK, + AVERAGE_TOK, + B_SPLINE_TOK, + BACKGROUND_TOK, + BEZIER_SPLINE_TOK, + BICUBIC_PATCH_TOK, + BLACK_HOLE_TOK, + BLOB_TOK, + BLUE_TOK, + BLUR_SAMPLES_TOK, + BOUNDED_BY_TOK, + BOX_TOK, + BOXED_TOK, + BOZO_TOK, + BREAK_TOK, + BRICK_TOK, + BRICK_SIZE_TOK, + BRIGHTNESS_TOK, + BRILLIANCE_TOK, + BUMPS_TOK, + BUMPY1_TOK, + BUMPY2_TOK, + BUMPY3_TOK, + BUMP_MAP_TOK, + BUMP_SIZE_TOK, + CAMERA_TOK, + CASE_TOK, + CAUSTICS_TOK, + CEIL_TOK, + CELLS_TOK, + CHECKER_TOK, + CHR_TOK, + CLIPPED_BY_TOK, + CLOCK_TOK, + CLOCK_DELTA_TOK, + COLLECT_TOK, + COLOR_TOK, + COLOR_MAP_TOK, + COLOUR_TOK, + COLOUR_MAP_TOK, + COMPONENT_TOK, + COMPOSITE_TOK, + CONCAT_TOK, + CONE_TOK, + CONFIDENCE_TOK, + CONIC_SWEEP_TOK, + CONSERVE_ENERGY_TOK, + CONSTANT_TOK, + CONTAINED_BY_TOK, + CONTROL0_TOK, + CONTROL1_TOK, + COS_TOK, + COSH_TOK, + COUNT_TOK, + CRACKLE_TOK, + CRAND_TOK, + CUBE_TOK, + CUBIC_TOK, + CUBIC_SPLINE_TOK, + CUBIC_WAVE_TOK, + CYLINDER_TOK, + CYLINDRICAL_TOK, + DEBUG_TOK, + DECLARE_TOK, + DEFAULT_TOK, + DEGREES_TOK, + DENTS_TOK, + DENSITY_TOK, + DENSITY_FILE_TOK, + DENSITY_MAP_TOK, + DF3_TOK, + DIFFERENCE_TOK, + DIFFUSE_TOK, + DIRECTION_TOK, + DISC_TOK, + DISPERSION_TOK, + DISPERSION_SAMPLES_TOK, + DIST_EXP_TOK, + DISTANCE_TOK, + DISTANCE_MAXIMUM_TOK, + DIV_TOK, + DOUBLE_ILLUMINATE_TOK, + DUST_TOK, + DUST_TYPE_TOK, + ECCENTRICITY_TOK, + ELSE_TOK, + EMISSION_TOK, + EMITTING_TOK, + END_TOK, + ERROR_TOK, + ERROR_BOUND_TOK, + EVALUATE_TOK, + EXP_TOK, + EXPAND_THRESHOLDS_TOK, + EXPONENT_TOK, + EXTERIOR_TOK, + EXTINCTION_TOK, + FADE_DISTANCE_TOK, + FADE_POWER_TOK, + FALLOFF_TOK, + FALLOFF_ANGLE_TOK, + FALSE_TOK, + FILE_EXISTS_TOK, + FILTER_TOK, + FINISH_TOK, + FISHEYE_TOK, + FLATNESS_TOK, + FLIP_TOK, + FLOOR_TOK, + FOCAL_POINT_TOK, + FOG_TOK, + FOG_ALT_TOK, + FOG_OFFSET_TOK, + FOG_TYPE_TOK, + FORM_TOK, + FRESNEL_TOK, + FREQUENCY_TOK, + FUNCTION_TOK, + GATHER_TOK, + GIF_TOK, + GLOBAL_LIGHTS_TOK, + GLOBAL_SETTINGS_TOK, + GLOWING_TOK, + GRADIENT_TOK, + GRANITE_TOK, + GRAY_THRESHOLD_TOK, + GREEN_TOK, + HALO_TOK, + HEIGHT_FIELD_TOK, + HEXAGON_TOK, + HF_GRAY_16_TOK, + HIERARCHY_TOK, + HOLLOW_TOK, + HYPERCOMPLEX_TOK, + IF_TOK, + IFDEF_TOK, + IFF_TOK, + IFNDEF_TOK, + IMAGE_MAP_TOK, + INCIDENCE_TOK, + INCLUDE_TOK, + INSIDE_VECTOR_TOK, + INT_TOK, + INTERIOR_TOK, + INTERIOR_TEXTURE_TOK, + INTERPOLATE_TOK, + INTERSECTION_TOK, + INTERVALS_TOK, + INVERSE_TOK, + ISOSURFACE_TOK, + IOR_TOK, + IRID_TOK, + IRID_WAVELENGTH_TOK, + JITTER_TOK, + JULIA_TOK, + JULIA_FRACTAL_TOK, + LAMBDA_TOK, + LATHE_TOK, + LEOPARD_TOK, + LIGHT_GROUP_TOK, + LIGHT_SOURCE_TOK, + LINEAR_TOK, + LINEAR_SPLINE_TOK, + LINEAR_SWEEP_TOK, + LOCATION_TOK, + LOG_TOK, + LOOKS_LIKE_TOK, + LOOK_AT_TOK, + LOW_ERROR_FACTOR_TOK, + MAGNET_TOK, + MAJOR_RADIUS_TOK, + MANDEL_TOK, + MAP_TYPE_TOK, + MARBLE_TOK, + MATERIAL_TOK, + MATERIAL_MAP_TOK, + MATRIX_TOK, + MAX_TOK, + MAX_GRADIENT_TOK, + MAX_INTERSECTIONS_TOK, + MAX_ITERATION_TOK, + MAX_SAMPLE_TOK, + MAX_TRACE_TOK, + MAX_TRACE_LEVEL_TOK, + MAX_VALUE_TOK, + MEDIA_TOK, + MEDIA_ATTENUATION_TOK, + MEDIA_INTERACTION_TOK, + MERGE_TOK, + MESH_TOK, + METALLIC_TOK, + METHOD_TOK, + METRIC_TOK, + MIN_TOK, + MINIMUM_REUSE_TOK, + MOD_TOK, + MORTAR_TOK, + NEAREST_COUNT_TOK, + NO_TOK, + NOISE_GENERATOR_TOK, + NORMAL_TOK, + NORMAL_MAP_TOK, + NO_IMAGE_TOK, + NO_REFLECTION_TOK, + NO_SHADOW_TOK, + NUMBER_OF_WAVES_TOK, + OBJECT_TOK, + OCTAVES_TOK, + OFF_TOK, + OFFSET_TOK, + OMEGA_TOK, + OMNIMAX_TOK, + ON_TOK, + ONCE_TOK, + ONION_TOK, + OPEN_TOK, + ORIENT_TOK, + ORTHOGRAPHIC_TOK, + PANORAMIC_TOK, + PARALLEL_TOK, + PASS_THROUGH_TOK, + PATTERN1_TOK, + PATTERN2_TOK, + PATTERN3_TOK, + PERSPECTIVE_TOK, + PGM_TOK, + PHASE_TOK, + PHONG_TOK, + PHONG_SIZE_TOK, + PHOTONS_TOK, + PI_TOK, + PIGMENT_TOK, + PIGMENT_MAP_TOK, + PLANAR_TOK, + PLANE_TOK, + PNG_TOK, + POINT_AT_TOK, + POLY_TOK, + POLY_WAVE_TOK, + POLYGON_TOK, + POT_TOK, + POW_TOK, + PPM_TOK, + PRECISION_TOK, + PRETRACE_END_TOK, + PRETRACE_START_TOK, + PRISM_TOK, + PROJECTED_THROUGH_TOK, + PWR_TOK, + QUADRATIC_SPLINE_TOK, + QUADRIC_TOK, + QUARTIC_TOK, + QUATERNION_TOK, + QUICK_COLOR_TOK, + QUICK_COLOUR_TOK, + QUILTED_TOK, + RADIAL_TOK, + RADIANS_TOK, + RADIOSITY_TOK, + RADIUS_TOK, + RAINBOW_TOK, + RAMP_WAVE_TOK, + RAND_TOK, + RANGE_TOK, + RATIO_TOK, + RECIPROCAL_TOK, + RECURSION_LIMIT_TOK, + RED_TOK, + REFLECTION_TOK, + REFLECTION_EXPONENT_TOK, + REFRACTION_TOK, + RENDER_TOK, + REPEAT_TOK, + RGB_TOK, + RGBF_TOK, + RGBFT_TOK, + RGBT_TOK, + RIGHT_TOK, + RIPPLES_TOK, + ROTATE_TOK, + ROUGHNESS_TOK, + SAMPLES_TOK, + SCALE_TOK, + SCALLOP_WAVE_TOK, + SCATTERING_TOK, + SEED_TOK, + SHADOWLESS_TOK, + SIN_TOK, + SINE_WAVE_TOK, + SINH_TOK, + SKY_TOK, + SKY_SPHERE_TOK, + SLICE_TOK, + SLOPE_TOK, + SLOPE_MAP_TOK, + SMOOTH_TOK, + SMOOTH_TRIANGLE_TOK, + SOR_TOK, + SOLID_TOK, + SPACING_TOK, + SPECULAR_TOK, + SPHERE_TOK, + SPHERE_SWEEP_TOK, + SPHERICAL_TOK, + SPIRAL_TOK, + SPIRAL1_TOK, + SPIRAL2_TOK, + SPOTLIGHT_TOK, + SPOTTED_TOK, + SQR_TOK, + SQRT_TOK, + STATISTICS_TOK, + STR_TOK, + STRCMP_TOK, + STRENGTH_TOK, + STRLEN_TOK, + STRLWR_TOK, + STRUPR_TOK, + STURM_TOK, + SUBSTR_TOK, + SUPERELLIPSOID_TOK, + SWITCH_TOK, + SYS_TOK, + T_TOK, + TAN_TOK, + TANH_TOK, + TARGET_TOK, + TEST_CAMERA_1_TOK, + TEST_CAMERA_2_TOK, + TEST_CAMERA_3_TOK, + TEST_CAMERA_4_TOK, + TEXT_TOK, + TEXTURE_TOK, + TEXTURE_MAP_TOK, + TGA_TOK, + THICKNESS_TOK, + THRESHOLD_TOK, + TIGHTNESS_TOK, + TILE2_TOK, + TILES_TOK, + TOLERANCE_TOK, + TOROIDAL_TOK, + TORUS_TOK, + TRACK_TOK, + TRANSFORM_TOK, + TRANSLATE_TOK, + TRANSMIT_TOK, + TRIANGLE_TOK, + TRIANGLE_WAVE_TOK, + TRUE_TOK, + TTF_TOK, + TURBULENCE_TOK, + TURB_DEPTH_TOK, + TYPE_TOK, + U_TOK, + ULTRA_WIDE_ANGLE_TOK, + UNION_TOK, + UP_TOK, + USE_COLOR_TOK, + USE_COLOUR_TOK, + USE_INDEX_TOK, + U_STEPS_TOK, + UV_MAPPING_TOK, + UV_VECTORS_TOK, + V_TOK, + VAL_TOK, + VARIANCE_TOK, + VAXIS_ROTATE_TOK, + VCROSS_TOK, + VDOT_TOK, + VERSION_TOK, + VLENGTH_TOK, + VNORMALIZE_TOK, + VOLUME_OBJECT_TOK, + VOLUME_RENDERED_TOK, + VOL_WITH_LIGHT_TOK, + VROTATE_TOK, + V_STEPS_TOK, + WARNING_TOK, + WARP_TOK, + WATER_LEVEL_TOK, + WAVES_TOK, + WHILE_TOK, + WIDTH_TOK, + WOOD_TOK, + WRINKLES_TOK, + X_TOK, + Y_TOK, + YES_TOK, + Z_TOK, + // extra tokens + ID_TOK, + INTEGER_TOK, + FLOAT_TOK, + COMMENT_TOK, + LINE_COMMENT_TOK, + STRING_TOK, + PMNAME_TOK, + RAW_POVRAY_TOK +}; + +#endif diff --git a/kpovmodeler/pmtorus.cpp b/kpovmodeler/pmtorus.cpp new file mode 100644 index 00000000..c6f4238a --- /dev/null +++ b/kpovmodeler/pmtorus.cpp @@ -0,0 +1,379 @@ +/*************************************************************************** + pmtorus.cpp - description + ------------------- + copyright : (C) 2001 Philippe Van Hecke + email : lephiloux@tiscalinet.be + copyright : (C) 2002 Andreas Zehender + email : zehender@kde.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. * + * * + ***************************************************************************/ + +#include "pmtorus.h" + +#include "pmxmlhelper.h" +#include "pmtorusedit.h" +#include "pmmemento.h" +#include "pmviewstructure.h" +#include "pm3dcontrolpoint.h" +#include "pmdistancecontrolpoint.h" +#include "pmdefaults.h" + +#include + +/** default param for the Torus */ +const double c_defaultminorRadius = 0.25; +const double c_defaultmajorRadius = 0.5; +const bool c_defaultsturm = false; + +/** default Torus structure */ +PMViewStructure* PMTorus::s_pDefaultViewStructure = 0; + +int PMTorus::s_vStep = c_defaultTorusVSteps; +int PMTorus::s_uStep = c_defaultTorusUSteps; +int PMTorus::s_parameterKey = 0; + +PMDefinePropertyClass( PMTorus, PMTorusProperty ); + +PMMetaObject* PMTorus::s_pMetaObject = 0; +PMObject* createNewTorus( PMPart* part ) +{ + return new PMTorus( part ); +} + +PMTorus::PMTorus( PMPart* part ) + : Base( part ) +{ + m_minorRadius = c_defaultminorRadius; + m_majorRadius = c_defaultmajorRadius; + m_sturm = c_defaultsturm ; +} + +PMTorus::PMTorus( const PMTorus& t ) + : Base( t ) +{ + m_minorRadius = t.m_minorRadius; + m_majorRadius = t.m_majorRadius; + m_sturm = t.m_sturm; +} + +PMTorus::~PMTorus( ) +{ +} + + +QString PMTorus::description( ) const +{ + return i18n( "torus" ); +} + +PMMetaObject* PMTorus::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Torus", Base::metaObject( ), + createNewTorus ); + s_pMetaObject->addProperty( + new PMTorusProperty( "minorRadius", &PMTorus::setMinorRadius, + &PMTorus::minorRadius ) ); + s_pMetaObject->addProperty( + new PMTorusProperty( "majorRadius", &PMTorus::setMajorRadius, + &PMTorus::majorRadius ) ); + s_pMetaObject->addProperty( + new PMTorusProperty( "sturm", &PMTorus::setSturm, &PMTorus::sturm ) ); + } + return s_pMetaObject; +} + +void PMTorus::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "minor_radius", m_minorRadius ); + e.setAttribute( "major_radius", m_majorRadius ); + e.setAttribute( "sturm", m_sturm ); + + Base::serialize( e, doc ); +} + +void PMTorus::readAttributes( const PMXMLHelper& h ) +{ + m_minorRadius = h.doubleAttribute( "minor_radius", c_defaultminorRadius ); + m_majorRadius = h.doubleAttribute( "major_radius", c_defaultmajorRadius ); + m_sturm = h.boolAttribute( "sturm", c_defaultsturm ); + + Base::readAttributes( h ); +} + +PMDialogEditBase* PMTorus::editWidget( QWidget* parent ) const +{ + + return new PMTorusEdit( parent ); +} + +void PMTorus::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMMinorRadiusID: + setMinorRadius( data->doubleData( ) ); + break; + case PMMajorRadiusID: + setMajorRadius( data->doubleData( ) ); + break; + case PMSturmID: + setSturm( data->boolData( ) ); + default: + kdError( PMArea ) << "Wrong ID in PMTorus::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); + +} + +void PMTorus::controlPoints( PMControlPointList& list ) +{ + PMVector majorCenter( 0, 0, 0 ); + /** control points of the major radius */ + list.append( new PMDistanceControlPoint( majorCenter, PMVector( 1.0, 0.0, 0.0 ), + m_majorRadius, PMMajorRadiusID, + i18n( "Major radius (x)" ) ) ); + PMDistanceControlPoint* rcp = + new PMDistanceControlPoint( majorCenter, PMVector( 0.0, 0.0, 1.0 ), + m_majorRadius, PMMajorRadiusID, + i18n( "Major radius (z)" ) ); + list.append( rcp ); + + PMVector minorCenter( 0.0, 0.0, m_majorRadius ); + list.append( new PMDistanceControlPoint( rcp, PMVector( 0.0, 1.0, 0.0 ), + m_minorRadius, PMMinorRadiusID, + i18n( "Minor radius (y)" ) ) ); + list.append( new PMDistanceControlPoint( rcp, PMVector( 0.0, 0.0, 1.0 ), + m_minorRadius, PMMinorRadiusID, + i18n( "Minor radius (z)" ) ) ); +} + +void PMTorus::controlPointsChanged( PMControlPointList& list ) +{ + bool majorChanged = false, minorChanged = false; + PMControlPoint* p; + for( p = list.first( ); p; p = list.next( ) ) + { + if( p->changed( ) ) + { + switch( p->id( ) ) + { + case PMMinorRadiusID: + setMinorRadius( ( ( PMDistanceControlPoint* ) p )->distance( ) ); + ( ( PMDistanceControlPoint* ) p )->setDistance( m_minorRadius ); + minorChanged = true; + break; + case PMMajorRadiusID: + setMajorRadius( ( ( PMDistanceControlPoint* ) p )->distance( ) ); + ( ( PMDistanceControlPoint* ) p )->setDistance( m_majorRadius ); + majorChanged = true; + break; + default: + kdError( PMArea ) << "Wrong ID in PMTorus::controlPointsChanged\n"; + break; + } + } + } + + if( majorChanged ) + for( p = list.first( ); p; p = list.next( ) ) + if( p->id( ) == PMMajorRadiusID ) + ( ( PMDistanceControlPoint* ) p )->setDistance( m_majorRadius ); + if( minorChanged ) + for( p = list.first( ); p; p = list.next( ) ) + if( p->id( ) == PMMinorRadiusID ) + ( ( PMDistanceControlPoint* ) p )->setDistance( m_minorRadius ); +} + +bool PMTorus::isDefault( ) +{ + if( ( m_minorRadius == c_defaultminorRadius ) + && ( m_majorRadius == c_defaultmajorRadius ) + && globalDetail( ) ) + return true; + return false; +} + +void PMTorus::createViewStructure( ) +{ + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultViewStructure( ) ); + m_pViewStructure->points( ).detach( ); + } + + int uStep = (int)( ( (float)s_uStep / 2 ) * ( displayDetail( ) + 1 ) ); + int vStep = (int)( ( (float)s_vStep / 2 ) * ( displayDetail( ) + 1 ) ); + unsigned ptsSize = vStep * uStep; + unsigned lineSize = vStep * uStep * 2; + + if( ptsSize != m_pViewStructure->points( ).size( ) ) + m_pViewStructure->points( ).resize( ptsSize ); + + createPoints( m_pViewStructure->points( ), m_minorRadius, m_majorRadius, uStep, vStep ); + + if( lineSize != m_pViewStructure->lines( ).size( ) ) + { + m_pViewStructure->lines( ).detach( ); + m_pViewStructure->lines( ).resize( lineSize ); + createLines( m_pViewStructure->lines( ), uStep, vStep ); + } +} + +PMViewStructure* PMTorus::defaultViewStructure( ) const +{ + if( !s_pDefaultViewStructure || s_pDefaultViewStructure->parameterKey( ) != viewStructureParameterKey( ) ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + int uStep = (int)( ( (float)s_uStep / 2 ) * ( globalDetailLevel( ) + 1 ) ); + int vStep = (int)( ( (float)s_vStep / 2 ) * ( globalDetailLevel( ) + 1 ) ); + + s_pDefaultViewStructure = + new PMViewStructure( vStep * uStep , + vStep * uStep * 2 ); + + createPoints( s_pDefaultViewStructure->points( ), c_defaultminorRadius, + c_defaultmajorRadius, uStep, vStep ); + + createLines( s_pDefaultViewStructure->lines( ), uStep, vStep ); + } + return s_pDefaultViewStructure; +} + +void PMTorus::createLines( PMLineArray& lines, int uStep, int vStep ) +{ + int u, v; + for( u = 0; u < uStep; ++u ) + { + for( v = 0; v < vStep; ++v ) + { + lines[ u * vStep + v ] = PMLine( u * vStep + v, u * vStep + ( (v+1) % vStep ) ); + lines[ uStep * vStep + u * vStep + v ] = PMLine( u * vStep + v, ( (u+1) % uStep ) * vStep + v ); + } + } +} + +void PMTorus::createPoints( PMPointArray& points, double minor_radius, + double major_radius, int uStep, int vStep ) +{ + double l_UradStep = ( 2.0 * M_PI ) / uStep; + double l_VradStep = ( 2.0 * M_PI ) / vStep; + double l_u = l_UradStep; + int u, v; + + for( u = 0; u < uStep; ++u ) + { + double l_v = 0.0; + double y = minor_radius * sin ( l_u ); + double l_rcosu = major_radius + minor_radius * cos( l_u ); + + for( v = 0; v < vStep; ++v ) + { + double x = l_rcosu * cos( l_v ); + double z = l_rcosu * sin( l_v ); + points[u * vStep + v ] = PMPoint( x, y, z ); + l_v = l_v + l_VradStep; + } + l_u = l_u + l_UradStep; + } +} + +void PMTorus::setMinorRadius( double minor_radius ) +{ + if( m_minorRadius != minor_radius ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMMinorRadiusID, m_minorRadius ); + m_minorRadius = minor_radius; + setViewStructureChanged( ); + } +} + +void PMTorus::setMajorRadius( double major_radius ) +{ + if( m_majorRadius != major_radius ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMMajorRadiusID, m_majorRadius ); + m_majorRadius = major_radius; + setViewStructureChanged( ); + } +} + +void PMTorus::setSturm( bool sturm ) +{ + if( m_sturm != sturm ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMSturmID, m_sturm ); + m_sturm = sturm; + setViewStructureChanged( ); + } + +} + +void PMTorus::setUSteps( int u ) +{ + if( u >= 2 ) + { + s_uStep = u; + if( s_pDefaultViewStructure ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + } + } + else + kdDebug( PMArea ) << "PMTorus::setUSteps: U must be greater than 1\n"; + s_parameterKey++; +} + +void PMTorus::setVSteps( int v ) +{ + if( v >= 4 ) + { + s_vStep = v; + if( s_pDefaultViewStructure ) + { + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + } + } + else + kdDebug( PMArea ) << "PMTorus::setVSteps: V must be greater than 3\n"; + s_parameterKey++; +} + +void PMTorus::cleanUp( ) const +{ + if( s_pDefaultViewStructure ) + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} diff --git a/kpovmodeler/pmtorus.h b/kpovmodeler/pmtorus.h new file mode 100644 index 00000000..9f3f8225 --- /dev/null +++ b/kpovmodeler/pmtorus.h @@ -0,0 +1,172 @@ +/* + *************************************************************************** + pmtorus.h - description + ------------------- + begin : Fri Jun 22 2001 + copyright : (C) 2001 Philippe Van Hecke + email : lephiloux@tiscalinet.be + copyright : (C) 2002 Andreas Zehender + email : zehender@kde.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. * + * * + ***************************************************************************/ + +#ifndef PMTORUS_H +#define PMTORUS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobject.h" +#include "pmvector.h" +#include "pmviewstructure.h" + +class PMViewStructure; + +/** + * Class for povray torus. + */ +class PMTorus : public PMSolidObject +{ + typedef PMSolidObject Base; + +public: + /** + * Create an empty Sphere + */ + PMTorus( PMPart* part ); + /** + * Copy constructor + */ + PMTorus( const PMTorus& t ); + /** + * Delete the PMTorus + */ + virtual ~PMTorus( ); + + /** */ + virtual PMObject* copy( ) const { return new PMTorus( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMTrousEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmtorus" ); } + /** + * set minor radius see povray documentation about torus + */ + void setMinorRadius( double minor_radius ); + /** + * set major radius see povray documentation about torus + */ + void setMajorRadius( double major_radius ); + /** + * use sturm algorithme + */ + void setSturm( bool sturm ); + /** + * return minor radius see povray documentation about torus + */ + double minorRadius( ) const { return m_minorRadius; } + /** + * return major radius see povray documentation about torus + */ + double majorRadius( ) const { return m_majorRadius; } + /** + * return if we must use sturm algorithm for the torus + */ + bool sturm( ) const { return m_sturm; } + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual void controlPoints( PMControlPointList& list ); + /** */ + virtual void controlPointsChanged( PMControlPointList& list ); + /** */ + virtual bool hasDisplayDetail( ) const { return true; } + /** */ + virtual void cleanUp( ) const; + + /** + * Sets the number of circles + */ + static void setUSteps( int u ); + /** + * Sets the number of point for each circle + */ + static void setVSteps( int v ); + /** + * Returns the number circles + */ + static int uSteps( ) { return s_uStep; } + /** + * Returns the number of point for each circle + */ + static int vSteps( ) { return s_vStep; } + +protected: + /** */ + virtual bool isDefault( ); + /** */ + virtual void createViewStructure( ); + /** */ + virtual PMViewStructure* defaultViewStructure( ) const; + /** */ + virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey(); } + +private: + static void createLines( PMLineArray& lines, int uStep, int vStep ); + static void createPoints( PMPointArray& points, double minor_radius, + double major_radius, int uStep, int vStep ); + enum PMTorusMementoID { PMMinorRadiusID, PMMajorRadiusID, PMSturmID }; + /** + * Minor radius + */ + double m_minorRadius; + /** + * Major radius + */ + double m_majorRadius; + /** + * use sturm algorithm + */ + bool m_sturm; + /** + * default view structure + */ + static PMViewStructure* s_pDefaultViewStructure; + static int s_vStep; + static int s_uStep; + static int s_parameterKey; + + static PMMetaObject* s_pMetaObject; +}; + +#endif +/* +x = (major + minor cos(u)) cos(v) +y = (major + minor cos(u)) sin(v) +z = minor sin (u) */ + + diff --git a/kpovmodeler/pmtorusedit.cpp b/kpovmodeler/pmtorusedit.cpp new file mode 100644 index 00000000..01784e1d --- /dev/null +++ b/kpovmodeler/pmtorusedit.cpp @@ -0,0 +1,105 @@ +/*************************************************************************** + pmtorusedit.cpp - description + ------------------- + begin : Sun Jul 1 2001 + copyright : (C) 2001 by Van Hecke Philippe + email : lephiloux@tiscalinet.be + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "pmtorusedit.h" +#include "pmtorus.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" + +#include +#include +#include +#include + + +PMTorusEdit::PMTorusEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMTorusEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + QGridLayout* gl; + QHBoxLayout* hl; + + m_pMinorRadius = new PMFloatEdit( this ); + m_pMajorRadius = new PMFloatEdit( this ); + m_pSturm = new QCheckBox( i18n( "Sturm" ), this ); + + hl = new QHBoxLayout( topLayout( ) ); + gl = new QGridLayout( hl, 2, 2 ); + gl->addWidget( new QLabel( i18n( "Minor radius:" ), this ), 0, 0 ); + gl->addWidget( m_pMinorRadius, 0, 1 ); + gl->addWidget( new QLabel( i18n( "Major radius:" ), this ), 1, 0 ); + gl->addWidget( m_pMajorRadius, 1, 1 ); + hl->addStretch( 1 ); + + topLayout( )->addWidget( m_pSturm ); + + + connect( m_pMinorRadius, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pMajorRadius, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pSturm, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMTorusEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Torus" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMTorus* ) o; + + m_pMajorRadius->setValue( m_pDisplayedObject->majorRadius( ) ); + m_pMinorRadius->setValue( m_pDisplayedObject->minorRadius( ) ); + m_pSturm->setChecked( m_pDisplayedObject->sturm( ) ); + + m_pMajorRadius->setReadOnly( readOnly ); + m_pMinorRadius->setReadOnly( readOnly ); + m_pSturm->setEnabled( !readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMTorusEdit: Can't display object\n"; +} + +void PMTorusEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + + m_pDisplayedObject->setMajorRadius( m_pMajorRadius->value( ) ); + m_pDisplayedObject->setMinorRadius( m_pMinorRadius->value( ) ); + m_pDisplayedObject->setSturm( m_pSturm->isChecked( ) ); + } +} + +bool PMTorusEdit::isDataValid( ) +{ + if( m_pMinorRadius->isDataValid( ) ) + if( m_pMajorRadius->isDataValid( ) ) + return Base::isDataValid( ); + return false; +} + + +#include "pmtorusedit.moc" + diff --git a/kpovmodeler/pmtorusedit.h b/kpovmodeler/pmtorusedit.h new file mode 100644 index 00000000..2aea334b --- /dev/null +++ b/kpovmodeler/pmtorusedit.h @@ -0,0 +1,65 @@ +/* + ************************************************************************** + pmtorusedit.h - description + ------------------- + begin : Sat Jun 30 2001 + copyright : (C) 2001 Philippe Van Hecke + email : lephiloux@tiscalinet.be + *************************************************************************** + + *************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef PMTORUSEDIT_H +#define PMTORUSEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsolidobjectedit.h" + +class PMTorus; +class PMFloatEdit ; +class QCheckBox; + +/** + * Dialog edit class for @ref PMTorus + */ +class PMTorusEdit : public PMSolidObjectEdit +{ + Q_OBJECT + typedef PMSolidObjectEdit Base; +public: + /** + * Creates a PMSphereEdit with parent and name + */ + PMTorusEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMTorus* m_pDisplayedObject; + PMFloatEdit* m_pMinorRadius; + PMFloatEdit* m_pMajorRadius; + QCheckBox * m_pSturm; + +}; + + +#endif diff --git a/kpovmodeler/pmtranslate.cpp b/kpovmodeler/pmtranslate.cpp new file mode 100644 index 00000000..0cfab44f --- /dev/null +++ b/kpovmodeler/pmtranslate.cpp @@ -0,0 +1,162 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmtranslate.h" +#include "pmtranslateedit.h" + +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmtranslatecontrolpoint.h" + +#include + +const PMVector moveDefault = PMVector( 0.0, 0.0, 0.0 ); + +PMDefinePropertyClass( PMTranslate, PMTranslateProperty ); + +PMMetaObject* PMTranslate::s_pMetaObject = 0; +PMObject* createNewTranslate( PMPart* part ) +{ + return new PMTranslate( part ); +} + +PMTranslate::PMTranslate( PMPart* part ) + : Base( part ) +{ +} + +PMTranslate::PMTranslate( const PMTranslate& t ) + : Base( t ) +{ + m_move = t.m_move; +} + +PMTranslate::~PMTranslate( ) +{ +} + +QString PMTranslate::description( ) const +{ + return i18n( "translate" ); +} + +void PMTranslate::serialize( QDomElement& e, QDomDocument& /*doc*/ ) const +{ + e.setAttribute( "value", m_move.serializeXML( ) ); +} + +void PMTranslate::readAttributes( const PMXMLHelper& h ) +{ + m_move = h.vectorAttribute( "value", moveDefault ); +} + +PMMetaObject* PMTranslate::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Translate", Base::metaObject( ), + createNewTranslate ); + s_pMetaObject->addProperty( + new PMTranslateProperty( "translation", &PMTranslate::setTranslation, &PMTranslate::translation ) ); + } + return s_pMetaObject; +} + +void PMTranslate::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMTranslate::setTranslation( const PMVector& p ) +{ + if( p != m_move ) + { + if( m_pMemento ) + { + m_pMemento->addData( s_pMetaObject, PMTranslationID, m_move ); + m_pMemento->setViewStructureChanged( ); + } + m_move = p; + m_move.resize( 3 ); + } +} + +PMDialogEditBase* PMTranslate::editWidget( QWidget* parent ) const +{ + return new PMTranslateEdit( parent ); +} + +void PMTranslate::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMTranslationID: + setTranslation( data->vectorData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMTranslate::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + +PMMatrix PMTranslate::transformationMatrix( ) const +{ + return PMMatrix::translation( m_move[0], m_move[1], m_move[2] ); +} + +void PMTranslate::controlPoints( PMControlPointList& list ) +{ + list.append( new PMTranslateControlPoint( m_move, PMTranslationID ) ); +} + +void PMTranslate::controlPointsChanged( PMControlPointList& list ) +{ + PMControlPoint* p; + + for( p = list.first( ); p; p = list.next( ) ) + { + if( p->changed( ) ) + { + switch( p->id( ) ) + { + case PMTranslationID: + setTranslation( ( ( PMTranslateControlPoint* ) p )->translation( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMTranslate::controlPointsChanged\n"; + break; + } + } + } +} diff --git a/kpovmodeler/pmtranslate.h b/kpovmodeler/pmtranslate.h new file mode 100644 index 00000000..91f1c7c3 --- /dev/null +++ b/kpovmodeler/pmtranslate.h @@ -0,0 +1,102 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMTRANSLATE_H +#define PMTRANSLATE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmobject.h" +#include "pmvector.h" + +/** + * Class for povray move commands. + */ + +class PMTranslate : public PMObject +{ + typedef PMObject Base; +public: + /** + * Creates a move < 0, 0, 0 > + */ + PMTranslate( PMPart* part ); + /** + * Copy constructor + */ + PMTranslate( const PMTranslate& t ); + /** + * deletes the object + */ + virtual ~PMTranslate( ); + + /** */ + virtual PMObject* copy( ) const { return new PMTranslate( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMTranslateEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** */ + virtual QString pixmap( ) const { return QString( "pmtranslate" ); } + + /** + * Returns the movement + */ + PMVector translation( ) const { return m_move; } + /** + * Sets the movement + */ + void setTranslation( const PMVector& p ); + + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual bool hasTransformationMatrix( ) const { return true; } + /** */ + virtual PMMatrix transformationMatrix( ) const; + + /** */ + virtual void controlPoints( PMControlPointList& list ); + /** */ + virtual void controlPointsChanged( PMControlPointList& list ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMTranslateMementoID { PMTranslationID }; + PMVector m_move; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmtranslatecontrolpoint.cpp b/kpovmodeler/pmtranslatecontrolpoint.cpp new file mode 100644 index 00000000..857e3af9 --- /dev/null +++ b/kpovmodeler/pmtranslatecontrolpoint.cpp @@ -0,0 +1,50 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmtranslatecontrolpoint.h" +#include "pmmath.h" + +#include +#include + +PMTranslateControlPoint::PMTranslateControlPoint( const PMVector& trans, int id ) + : PMControlPoint( id, i18n( "Translation" ) ) +{ + m_translation = trans; +} + +void PMTranslateControlPoint::graphicalChangeStarted( ) +{ + m_originalTranslation = m_translation; +} + +void PMTranslateControlPoint::graphicalChange( const PMVector& startPoint, + const PMVector& /*viewNormal*/, + const PMVector& endPoint ) +{ + m_translation = m_originalTranslation + endPoint - startPoint; +} + +void PMTranslateControlPoint::snapToGrid( ) +{ + int i; + double d = moveGrid( ); + if( !approxZero( d ) ) + for( i = 0; i < 3; i++ ) + m_translation[i] = rint( m_translation[i] / d ) * d; + setChanged( ); +} diff --git a/kpovmodeler/pmtranslatecontrolpoint.h b/kpovmodeler/pmtranslatecontrolpoint.h new file mode 100644 index 00000000..292e8a67 --- /dev/null +++ b/kpovmodeler/pmtranslatecontrolpoint.h @@ -0,0 +1,71 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMTRANSLATECONTROLPOINT_H +#define PMTRANSLATECONTROLPOINT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + + +#include "pmcontrolpoint.h" + +/** + * Control points for translation + */ +class PMTranslateControlPoint : public PMControlPoint +{ +public: + /** + * Creates a PMTranslateControlPoint with id. + */ + PMTranslateControlPoint( const PMVector& translation, int id ); + /** + * Deletes the PMTranslateControlPoint + */ + virtual ~PMTranslateControlPoint( ) { }; + + /** */ + virtual PMVector position( ) const { return m_translation; } + + /** + * Sets the translation + */ + void setTranslation( PMVector trans ) { m_translation = trans; } + /** + * Returns the translation + */ + PMVector translation( ) const { return m_translation; } + + /** */ + virtual PMCPDisplayType displayType( ) const { return CPCross; }; + /** */ + virtual void snapToGrid( ); +protected: + /** */ + virtual void graphicalChangeStarted( ); + /** */ + virtual void graphicalChange( const PMVector& startPoint, + const PMVector& viewNormal, + const PMVector& endPoint ); +private: + PMVector m_translation, m_originalTranslation; +}; + +#endif diff --git a/kpovmodeler/pmtranslateedit.cpp b/kpovmodeler/pmtranslateedit.cpp new file mode 100644 index 00000000..d2690f51 --- /dev/null +++ b/kpovmodeler/pmtranslateedit.cpp @@ -0,0 +1,74 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmtranslateedit.h" +#include "pmtranslate.h" +#include "pmvectoredit.h" + +#include +#include + + +PMTranslateEdit::PMTranslateEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMTranslateEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + m_pVector = new PMVectorEdit( "x", "y", "z", this ); + topLayout( )->addWidget( m_pVector ); + + connect( m_pVector, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMTranslateEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Translate" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMTranslate* ) o; + + m_pVector->setVector( m_pDisplayedObject->translation( ) ); + m_pVector->setReadOnly( readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMTranslateEdit: Can't display object\n"; +} + +void PMTranslateEdit::saveContents( ) +{ + if( m_pDisplayedObject ) + { + Base::saveContents( ); + m_pDisplayedObject->setTranslation( m_pVector->vector( ) ); + } +} + +bool PMTranslateEdit::isDataValid( ) +{ + if( m_pVector->isDataValid( ) ) + return Base::isDataValid( ); + return false; +} +#include "pmtranslateedit.moc" diff --git a/kpovmodeler/pmtranslateedit.h b/kpovmodeler/pmtranslateedit.h new file mode 100644 index 00000000..ce27b037 --- /dev/null +++ b/kpovmodeler/pmtranslateedit.h @@ -0,0 +1,62 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMMOVEEDIT_H +#define PMMOVEEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMTranslate; +class PMVectorEdit; + +/** + * Dialog edit class for @ref PMTranslate + */ +class PMTranslateEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMTranslateEdit with parent and name + */ + PMTranslateEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private: + PMTranslate* m_pDisplayedObject; + PMVectorEdit* m_pVector; +}; + + +#endif diff --git a/kpovmodeler/pmtreeview.cpp b/kpovmodeler/pmtreeview.cpp new file mode 100644 index 00000000..66ec18a0 --- /dev/null +++ b/kpovmodeler/pmtreeview.cpp @@ -0,0 +1,820 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "pmtreeview.h" +#include "pmtreeviewitem.h" +#include "pmcommand.h" +#include "pmpart.h" +#include "pmscene.h" +#include "pmobjectdrag.h" + + +PMTreeViewWidget::PMTreeViewWidget( PMPart* part, QWidget* parent /*= 0*/, + const char* name /*=0*/ ) + : PMViewBase( parent, name ) +{ + QHBoxLayout* hl = new QHBoxLayout( this ); + PMTreeView* tv = new PMTreeView( part, this ); + hl->addWidget( tv ); +} + +QString PMTreeViewWidget::description( ) const +{ + return i18n( "Object Tree" ); +} + +PMTreeView::PMTreeView( PMPart* part, QWidget* parent /*= 0*/, + const char* name /*= 0*/ ) + : QListView( parent, name ) +{ + addColumn( i18n( "Objects" ) ); + header( )->hide( ); + setRootIsDecorated( true ); + setSorting( -1 ); + setSelectionMode( Multi ); + m_pPart = part; + + m_itemSelected = false; + m_itemDeselected = false; + m_selectionCleared = false; + m_pLastSelected = 0; + m_event = false; + m_pressed = false; + m_pDragOverItem = 0; + m_acceptSelect = false; + m_pressedItem = 0; + + viewport( )->setAcceptDrops( true ); + viewport( )->setMouseTracking( true ); + viewport( )->setFocusPolicy( QWidget::WheelFocus ); + setFocusPolicy( QWidget::WheelFocus ); + setAcceptDrops( true ); + + connect( part, SIGNAL( refresh( ) ), SLOT( slotRefresh( ) ) ); + connect( part, SIGNAL( objectChanged( PMObject*, const int, QObject* ) ), + SLOT( slotObjectChanged( PMObject*, const int, QObject* ) ) ); + connect( part, SIGNAL( clear( ) ), SLOT( slotClear( ) ) ); + connect( this, SIGNAL( objectChanged( PMObject*, const int, QObject* ) ), + part, SLOT( slotObjectChanged( PMObject*, const int, QObject* ) ) ); + + slotRefresh( ); +} + +PMTreeView::~PMTreeView( ) +{ + emit destroyed( this ); +} + +void PMTreeView::slotObjectChanged( PMObject* obj, const int mode, + QObject* sender ) +{ + PMTreeViewItem* pTreeItem = 0; + bool as = m_acceptSelect; + m_acceptSelect = true; + + if( sender != this ) + { + if( ( mode & PMCAdd ) && !( mode & PMCInsertError ) ) + { + // object was added + if( !obj->parent( ) ) + { + // object has no parent, append it as top level item + pTreeItem = new PMTreeViewItem( obj, this ); + } + else + { + // find the parent in the listview + QListViewItem* pParentTreeItem = findObject( obj->parent( ) ); + if( pParentTreeItem ) + { + PMObject* hObj = obj->prevSibling( ); + QListViewItem* pSibling = 0; + bool found = false; + + if( hObj ) + { + // find the previous sibling + pSibling = pParentTreeItem->firstChild( ); + while( pSibling && !found ) + { + if( ( ( PMTreeViewItem* ) pSibling )->object( ) == hObj ) + found = true; + else + pSibling = pSibling->nextSibling( ); + } + } + if( found ) + { + // object has sibling + pTreeItem = new PMTreeViewItem( obj, pParentTreeItem, pSibling ); + } + else + { + // object has no sibling + pTreeItem = new PMTreeViewItem( obj, pParentTreeItem ); + } + } + } + + if( pTreeItem ) + { + // add child items if necessary + if( obj->countChildren( ) > 0 ) + addChildItems( pTreeItem ); + } + } + if( mode & PMCDescription ) + { + if( !pTreeItem ) + pTreeItem = findObject( obj ); + + if( pTreeItem ) + pTreeItem->setDescriptions( ); + } + if( mode & PMCChildren ) + { + if( !pTreeItem ) + pTreeItem = findObject( obj ); + + if( pTreeItem ) + { + // delete old items + while( pTreeItem->firstChild( ) ) + delete pTreeItem->firstChild( ); + // create new + addChildItems( pTreeItem ); + pTreeItem->setOpen( true ); + } + } + if( mode & PMCNewSelection ) + { + clearSelection( ); + + if( !pTreeItem ) + pTreeItem = findObject( obj ); + + if( pTreeItem ) + { + PMTreeViewItem* p; + for( p = pTreeItem->parent( ); p; p = p->parent( ) ) + p->setOpen( true ); + pTreeItem->setSelected( true ); + setCurrentItem( pTreeItem ); + } + } + if( mode & PMCDeselected ) + { + if( !pTreeItem ) + pTreeItem = findObject( obj ); + pTreeItem->setSelected( false ); + } + if( mode & PMCSelected ) + { + if( !pTreeItem ) + pTreeItem = findObject( obj ); + pTreeItem->setSelected( true ); + } + if( mode & PMCRemove ) + { + // object was removed, remove the listview item + if( !pTreeItem ) + pTreeItem = findObject( obj ); + delete( pTreeItem ); + } + if( mode & PMCData ) + { + // special case for texture maps + if( obj ) + { + if( obj->isA( "TextureMapBase" ) ) + { + if( !pTreeItem ) + pTreeItem = findObject( obj ); + if( pTreeItem ) + { + PMTreeViewItem* it = ( PMTreeViewItem* ) pTreeItem->firstChild( ); + for( ; it; it = ( PMTreeViewItem* ) it->nextSibling( ) ) + it->setDescriptions( ); + } + } + } + } + } + m_acceptSelect = as; +} + + +PMTreeViewItem* PMTreeView::findObject( const PMObject* obj ) +{ + PMTreeViewItem* pTreeItem = 0; + + if( !obj->parent( ) ) + { + // top level object + pTreeItem = ( PMTreeViewItem* ) firstChild( ); + for( ; pTreeItem; pTreeItem = ( PMTreeViewItem* ) pTreeItem->nextSibling( ) ) + if( pTreeItem->object( ) == obj ) + return pTreeItem; + } + else + { + pTreeItem = findObject( obj->parent( ) ); + if( pTreeItem ) + { + pTreeItem = ( PMTreeViewItem* ) pTreeItem->firstChild( ); + for( ; pTreeItem; pTreeItem = ( PMTreeViewItem* ) pTreeItem->nextSibling( ) ) + if( pTreeItem->object( ) == obj ) + return pTreeItem; + } + } + return 0; +} + + +void PMTreeView::selectItem( QListViewItem* /*sitem*/ ) +{ +/* QListViewItem* pItem = 0; + bool emitSig; + emitSig = ( m_pSelectedObject != ( ( PMTreeViewItem* ) sitem )->object( ) ); + + m_pSelectedObject = ( ( PMTreeViewItem* ) sitem )->object( ); + + for( pItem = sitem->parent( ); pItem; pItem = pItem->parent( ) ) + pItem->setOpen( true ); + ensureItemVisible( sitem ); + setCurrentItem( sitem ); + setSelected( sitem, true ); + if( emitSig ) + emit objectSelected( m_pSelectedObject ); +*/ +} + +void PMTreeView::addChildItems( PMTreeViewItem* item ) +{ + PMObject* obj = 0; + PMTreeViewItem* listItem = 0; + + for( obj = item->object( )->firstChild( ); obj; obj = obj->nextSibling( ) ) + { + // insert all child objects + if( listItem ) + listItem = new PMTreeViewItem( obj, item, listItem ); + else + // first child + listItem = new PMTreeViewItem( obj, item ); + // recursive call, if child has children + if( obj->countChildren( ) > 0 ) + addChildItems( listItem ); + } +} + +void PMTreeView::slotRefresh( ) +{ + PMTreeViewItem* item; + slotClear( ); + // insert the top level items + if( m_pPart->scene( ) ) + { + item = new PMTreeViewItem( m_pPart->scene( ), this ); + addChildItems( item ); + item->setOpen( true ); +// item = new PMTreeViewItem( m_pPart->insertErrors( ), this ); +// addChildItems( item ); +// item->setOpen( true ); + } +} + +void PMTreeView::slotClear( ) +{ + clear( ); + m_pLastSelected = 0; + m_pDragOverItem = 0; + m_pressedItem = 0; +} + +void PMTreeView::itemSelected( PMTreeViewItem* item, bool selected ) +{ + repaintItem( item ); + + if( m_event ) + { + m_pLastSelected = item; + + if( selected ) + m_itemSelected = true; + else + { + if( m_itemDeselected ) + m_selectionCleared = true; + else + m_itemDeselected = true; + } + } +} + +void PMTreeView::contentsMousePressEvent( QMouseEvent * e ) +{ + m_itemSelected = false; + m_itemDeselected = false; + m_pLastSelected = 0; + m_selectionCleared = false; + m_selectOnReleaseEvent = false; + bool specialAction = false; + + QListViewItem* oldCurrent = currentItem( ); + + m_event = true; + m_acceptSelect = true; + QListView::contentsMousePressEvent( e ); + m_event = false; + m_acceptSelect = true; + + if( m_selectionCleared ) + { + emit objectChanged( 0, PMCNewSelection, this ); + specialAction = true; + } + else if( m_itemSelected || m_itemDeselected ) + { + if( !( e->state( ) & ( ShiftButton | ControlButton ) ) ) + { + specialAction = true; + // simple click, deselect all selected item + // m_pLastSelected is the new selection + + if( m_itemSelected ) + { + clearSelection( ); + m_pLastSelected->setSelected( true ); + + emit objectChanged( m_pLastSelected->object( ), PMCNewSelection, + this ); + } + else + { + m_selectOnReleaseEvent = true; + m_pLastSelected->setSelected( true ); + } + } + else if( ( e->state( ) & ShiftButton ) && oldCurrent && m_pLastSelected ) + { + if( ( oldCurrent != m_pLastSelected ) && + ( oldCurrent->parent( ) == m_pLastSelected->parent( ) ) ) + { + specialAction = true; + + // shift click, old current item has the same parent + // as the new selection. Select all items between the two + // items + if( m_pLastSelected->object( )->isSelectable( ) ) + { + bool down = oldCurrent->itemPos( ) < m_pLastSelected->itemPos( ); + QListViewItem* tmp; + + if( down ) + { + for( tmp = oldCurrent; tmp; tmp = tmp->nextSibling( ) ) + { + tmp->setSelected( true ); + emit objectChanged( (( PMTreeViewItem* ) tmp)->object( ), + PMCSelected, this ); + if( tmp == m_pLastSelected ) + break; + } + } + else + { + for( tmp = m_pLastSelected; tmp; tmp = tmp->nextSibling( ) ) + { + tmp->setSelected( true ); + emit objectChanged( (( PMTreeViewItem* ) tmp)->object( ), + PMCSelected, this ); + if( tmp == oldCurrent ) + break; + } + } + } + else + m_pLastSelected->setSelected( false ); + } + } + } + if( !specialAction ) + { + // no special action + // object is selected or deselected, no other objects are changed + if( m_itemSelected ) + { + if( m_pLastSelected->object( )->isSelectable( ) ) + emit objectChanged( m_pLastSelected->object( ), PMCSelected, this ); + else + m_pLastSelected->setSelected( false ); + } + else if( m_itemDeselected ) + emit objectChanged( m_pLastSelected->object( ), PMCDeselected, this ); + } + m_acceptSelect = false; +} + +void PMTreeView::contentsMouseMoveEvent( QMouseEvent * e ) +{ + m_itemSelected = false; + m_itemDeselected = false; + m_pLastSelected = 0; + m_selectionCleared = false; + + m_event = true; + QListView::contentsMouseMoveEvent( e ); + m_event = false; + + // ignore all selections/deselections + if( m_itemSelected || m_itemDeselected ) + m_pLastSelected->setSelected( m_pLastSelected->object( )->isSelected( ) ); +} + +void PMTreeView::viewportMousePressEvent( QMouseEvent* e ) +{ + m_acceptSelect = true; + QListView::viewportMousePressEvent( e ); + m_acceptSelect = false; + + m_pressed = false; + + QPoint p = e->pos( ); + + if( e->button( ) & RightButton ) + { + if( m_pPart->factory( ) ) + { + QPopupMenu* m = + ( QPopupMenu* ) m_pPart->factory( )->container( "treeViewPopup", m_pPart ); + if( m ) + m->exec( QCursor::pos( ) ); + } + return; + } + + PMTreeViewItem *item = ( PMTreeViewItem* )itemAt( p ); + if( item ) + { + // check if the root decoration was clicked + if( !( p.x( ) > header( )->cellPos( header( )->mapToActual( 0 ) ) + + treeStepSize( ) * ( item->depth( ) + ( rootIsDecorated( ) ? 1 : 0 ) ) + + itemMargin( ) || + p.x( ) < header( )->cellPos( header( )->mapToActual( 0 ) ) ) ) + item = 0; // p is on the root decoration + } + + if( item ) + { + if( e->button( ) == LeftButton || e->button( ) == MidButton ) + { + m_pressed = true; + m_pressedPos = e->pos( ); + m_pressedItem = item; + return; + } + } +} + +void PMTreeView::viewportMouseReleaseEvent( QMouseEvent* e ) +{ + QListView::viewportMouseReleaseEvent( e ); + + if( !m_pressed ) + return; + + m_pressed = false; + m_pressedItem = 0L; + + if( m_selectOnReleaseEvent ) + { + if( m_pLastSelected ) + { + m_acceptSelect = true; + clearSelection( ); + m_pLastSelected->setSelected( true ); + m_acceptSelect = false; + + emit objectChanged( m_pLastSelected->object( ), PMCNewSelection, this ); + } + } +} + +void PMTreeView::viewportMouseMoveEvent( QMouseEvent *e ) +{ + QListView::viewportMouseMoveEvent( e ); + + if( m_pressed && m_pressedItem ) + { + int x = e->pos( ).x( ); + int y = e->pos( ).y( ); + + //Is it time to start a drag? + if( abs( x - m_pressedPos.x( ) ) > KGlobalSettings::dndEventDelay( ) || + abs( y - m_pressedPos.y( ) ) > KGlobalSettings::dndEventDelay( ) ) + { + m_selectOnReleaseEvent = false; + + // Calculate hotspot + QPoint hotspot; + PMObjectList sortedList = m_pPart->selectedObjects( ); + + // Do not handle more mouse move or mouse release events + m_pressed = false; + + if( sortedList.count( ) > 0 ) + { + PMObjectDrag* d = new PMObjectDrag( m_pPart, sortedList, viewport( ) ); + + hotspot.setX( m_pressedItem->pixmap( 0 )->width( ) / 2 ); + hotspot.setY( m_pressedItem->pixmap( 0 )->height( ) / 2 ); + if( sortedList.count( ) == 1 ) + d->setPixmap( SmallIcon( + sortedList.first( )->pixmap( ) ), hotspot ); + else + d->setPixmap( SmallIcon( "pmdrag" ) ); + + if( d->drag( ) ) + { + kdDebug( PMArea ) << "Drag returned true\n"; + if( !targetDisplaysPart( d->target( ) ) ) + m_pPart->dragMoveSelectionTo( 0 ); + } + } + } + } +} + +void PMTreeView::viewportDragMoveEvent( QDragMoveEvent *e ) +{ + bool accept = false; + + if( m_pPart->isReadWrite( ) ) + { + if( PMObjectDrag::canDecode( e, m_pPart ) ) + { + PMTreeViewItem *item = ( PMTreeViewItem* ) itemAt( e->pos( ) ); + PMObject* obj = 0; + + if( !item ) + { + accept = false; + /* + if( e->source( ) == viewport( ) ) + { + if( m_pPart->scene( )->isSelected( ) ) + accept = false; + else + accept = true; + } + else + accept = true; + obj = m_pPart->scene( ); + */ + + m_pDragOverItem = 0L; + obj = 0; + } + else + { + obj = item->object( ); + if( ( obj->isSelectable( ) && + !obj->isSelected( ) ) || ( e->source( ) != viewport( ) ) ) + { + accept = true; + setCurrentItem( item ); + m_pDragOverItem = item; + } + else + { + accept = false; + m_pDragOverItem = 0L; + } + } + + if( accept ) + { + accept = false; + if( !obj->isReadOnly( ) ) + accept = true; + if( obj->parent( ) ) + if( !obj->parent( )->isReadOnly( ) ) + accept = true; + } + } + else + accept = false; + } + else + accept = false; + + if( accept ) + e->acceptAction( ); + else + e->ignore( ); +} + +void PMTreeView::viewportDragEnterEvent( QDragEnterEvent *e ) +{ + m_pDragOverItem = 0L; + + if( m_pPart->isReadWrite( ) ) + e->accept( PMObjectDrag::canDecode( e, m_pPart ) ); + else + e->ignore( ); +} + +void PMTreeView::viewportDragLeaveEvent( QDragLeaveEvent* ) +{ + m_pDragOverItem = 0L; +} + +void PMTreeView::viewportDropEvent( QDropEvent* e ) +{ + PMObject* obj; + + if( m_pPart->isReadWrite( ) ) + { + if( m_pDragOverItem ) + obj = m_pDragOverItem->object( ); + else + obj = m_pPart->scene( ); + + if( PMObjectDrag::canDecode( e, m_pPart ) ) + { + if( targetDisplaysPart( e->source( ) ) && + ( e->action( ) == QDropEvent::Move ) ) + { + if( m_pPart->dragMoveSelectionTo( obj ) ) + e->acceptAction( ); + else + e->ignore( ); + } + else + { + if( m_pPart->drop( obj, e ) ) + e->acceptAction( ); + else + e->ignore( ); + } + } + else + e->ignore( ); + } + else + e->ignore( ); + + m_pDragOverItem = 0L; +} + +void PMTreeView::focusOutEvent( QFocusEvent* e ) +{ + QWidget::focusOutEvent( e ); + m_pressed = false; + m_pressedItem = 0; +} + +void PMTreeView::focusInEvent( QFocusEvent* e ) +{ + QWidget::focusInEvent( e ); + m_pressed = false; + m_pressedItem = 0; +} + +void PMTreeView::keyPressEvent( QKeyEvent* e ) +{ + QListViewItem* current = currentItem( ); + QListViewItem* newSelection = 0; + bool accept = false; + bool deleteItem = false; + bool pasteItem = false; + + if( current ) + { + switch( e->key( ) ) + { + case Qt::Key_Up: + newSelection = current->itemAbove( ); + accept = true; + break; + case Qt::Key_Down: + newSelection = current->itemBelow( ); + accept = true; + break; + case Qt::Key_Left: + newSelection = current->parent( ); + accept = true; + break; + case Qt::Key_Right: + newSelection = current->firstChild( ); + accept = true; + break; + case Qt::Key_Plus: + current->setOpen( true ); + accept = true; + break; + case Qt::Key_Minus: + current->setOpen( false ); + accept = true; + case Qt::Key_Delete: + deleteItem = true; + accept = true; + break; + case Qt::CTRL+Qt::Key_V: + case Qt::SHIFT+Qt::Key_Insert: + pasteItem = true; + accept = true; + break; + } + } + + if( newSelection ) + { + m_acceptSelect = true; + clearSelection( ); + newSelection->setSelected( true ); + setCurrentItem( newSelection ); + ensureItemVisible( newSelection ); + m_acceptSelect = false; + + emit objectChanged( ( ( PMTreeViewItem* ) newSelection )->object( ), + PMCNewSelection, this ); + } + + if( deleteItem && m_pPart->isReadWrite( ) ) + { + m_pPart->slotEditDelete( ); + m_pPart->setModified( true ); + } + + if( pasteItem && m_pPart->isReadWrite( ) ) + { + m_pPart->slotEditPaste( ); + m_pPart->setModified( true ); + } + + if( accept ) + e->accept( ); + else + e->ignore( ); + QWidget::keyPressEvent( e ); +} + +bool PMTreeView::targetDisplaysPart( QWidget* target ) +{ + bool result = false; + if( !target ) // another application + result = false; + else if( target == viewport( ) ) // self + result = true; + else + { + // Widget may be a view port + // find the tree view + QWidget* t = target; + while( t && !t->isA( "PMTreeView" ) ) + t = t->parentWidget( ); + if( t ) + if( ( ( PMTreeView* ) t )->part( ) == m_pPart ) + result = true; + } + return result; +} + +QString PMTreeViewFactory::description( ) const +{ + return i18n( "Object Tree" ); +} + +#include "pmtreeview.moc" diff --git a/kpovmodeler/pmtreeview.h b/kpovmodeler/pmtreeview.h new file mode 100644 index 00000000..24f6f33f --- /dev/null +++ b/kpovmodeler/pmtreeview.h @@ -0,0 +1,182 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMTREEVIEW_H +#define PMTREEVIEW_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include "pmobject.h" +#include "pmviewbase.h" +#include "pmviewfactory.h" + +class PMTreeViewItem; +class PMPart; + +/** + * Wrapper class for the treeview/dock widget + */ +class PMTreeViewWidget : public PMViewBase +{ +public: + /** + * Default constructor + */ + PMTreeViewWidget( PMPart* pare, QWidget* parent, const char* name = 0 ); + + /** */ + virtual QString viewType( ) const { return QString( "treeview" ); } + /** */ + virtual QString description( ) const; +}; + +/** + * Widget that displays the scene as tree view + */ +class PMTreeView : public QListView +{ + Q_OBJECT + friend class PMTreeViewItem; +public: + /** + * Creates a PMTreeView with parent and name that displays the + * document doc + */ + PMTreeView( PMPart* part, QWidget* parent = 0, const char* name = 0 ); + /** + * Deletes the PMTreeView + */ + ~PMTreeView( ); + + /** + * Returns true PMTreeViewItem::setSelected should be accepted + */ + bool acceptSelect( ) const { return m_acceptSelect; } + /** + * Returns the connected part + */ + PMPart* part( ) const { return m_pPart; } + +public slots: + /** + * Called when an object is changed. + * @see PMPart::objectChanged( ) */ + void slotObjectChanged( PMObject* obj, const int mode, QObject* sender ); + /** + * Refreshes the whole csg tree + */ + void slotRefresh( ); + /** + * Clears all data + */ + void slotClear( ); + +signals: + /** + * Emitted, when an object is selected or deselected + */ + void objectChanged( PMObject* obj, const int mode, QObject* sender ); + /** + * Emitted in the destructor + */ + void destroyed( PMTreeView* v ); + +protected: + void contentsMousePressEvent( QMouseEvent * e ); + void contentsMouseMoveEvent( QMouseEvent * e ); + void itemSelected( PMTreeViewItem* item, bool selected ); + + void viewportMousePressEvent( QMouseEvent * e ); + void viewportMouseReleaseEvent( QMouseEvent* e ); + void viewportMouseMoveEvent( QMouseEvent* e ); + + void viewportDragMoveEvent( QDragMoveEvent *e ); + void viewportDragEnterEvent( QDragEnterEvent *e ); + void viewportDragLeaveEvent( QDragLeaveEvent* e ); + void viewportDropEvent( QDropEvent* e ); + + void focusOutEvent( QFocusEvent* e ); + void focusInEvent( QFocusEvent* e ); + + void keyPressEvent( QKeyEvent* e ); + +private: + /** + * Adds child items of item to the tree view + */ + void addChildItems( PMTreeViewItem* item ); + /** + * Returns the ListViewItem connected with the PMObject obj + */ + PMTreeViewItem* findObject( const PMObject* obj ); + /** + * Selects the item. Expands the tree if necessary + */ + void selectItem( QListViewItem* item ); + /** + * Returns true if the drop target is a tree view for the same part + */ + bool targetDisplaysPart( QWidget* target ); + + /** + * the displayed document + */ + PMPart* m_pPart; + + /** + * the selected items + */ +// QPtrList m_selectedItems; + PMTreeViewItem* m_pLastSelected; + bool m_itemSelected; + bool m_itemDeselected; + bool m_selectionCleared; + bool m_event; + bool m_acceptSelect; + bool m_selectOnReleaseEvent; + + PMTreeViewItem* m_pDragOverItem; +// QStringList m_lstDropFormats; + + // for drag and drop, copied from KonqBaseListViewWidget + bool m_pressed; + QPoint m_pressedPos; + PMTreeViewItem* m_pressedItem; +}; + +/** + * Factory class for the tree view + */ +class PMTreeViewFactory : public PMViewTypeFactory +{ +public: + PMTreeViewFactory( ) { } + virtual QString viewType( ) const { return QString( "treeview" ); } + virtual QString description( ) const; + virtual QString iconName( ) const { return QString( "pmtreeview" ); } + virtual PMViewBase* newInstance( QWidget* parent, PMPart* part ) const + { + return new PMTreeViewWidget( part, parent ); + } +}; + +#endif diff --git a/kpovmodeler/pmtreeviewitem.cpp b/kpovmodeler/pmtreeviewitem.cpp new file mode 100644 index 00000000..72562f78 --- /dev/null +++ b/kpovmodeler/pmtreeviewitem.cpp @@ -0,0 +1,117 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmtreeviewitem.h" +#include "pmobject.h" +#include + +#include "pmtreeview.h" +#include "pmfactory.h" +#include "pmtexturemap.h" + +PMTreeViewItem::PMTreeViewItem( PMObject* object, QListView* parent ) + : QListViewItem( parent ) +{ + m_pObject = object; + setDescriptions( ); + initSelection( ); +} + +PMTreeViewItem::PMTreeViewItem( PMObject* object, QListViewItem* parent ) + : QListViewItem( parent ) +{ + m_pObject = object; + setDescriptions( ); + initSelection( ); +} + +PMTreeViewItem::PMTreeViewItem( PMObject* object, QListView* parent, + QListViewItem* after ) + : QListViewItem( parent, after ) +{ + m_pObject = object; + setDescriptions( ); + initSelection( ); +} + +PMTreeViewItem::PMTreeViewItem( PMObject* object, QListViewItem* parent, + QListViewItem* after ) + : QListViewItem( parent, after ) +{ + m_pObject = object; + setDescriptions( ); + initSelection( ); +} + +void PMTreeViewItem::setDescriptions( ) +{ + QString text; + setPixmap( 0, SmallIcon( m_pObject->pixmap( ), PMFactory::instance( ) ) ); + + if( m_pObject->canHaveName( ) ) + { + text = m_pObject->name( ); + if( text.isEmpty( ) ) + text = m_pObject->description( ); + } + else + text = m_pObject->description( ); + + if( m_pObject->parent( ) ) + { + if( m_pObject->parent( )->isA( "TextureMapBase" ) ) + { + PMTextureMapBase* tm = ( PMTextureMapBase* ) m_pObject->parent( ); + if( m_pObject->type( ) == tm->mapType( ) ) + text = QString( "[%1] " ).arg( tm->mapValue( m_pObject ), 4, 'f', 2 ) + text; + } + } + setText( 0, text ); +} + +QString PMTreeViewItem::key( int, bool ) const +{ + QString result; + if( m_pObject->parent( ) ) + result.sprintf( "%06i", m_pObject->parent( )->findChild( m_pObject ) ); + else + result = "000000"; + return result; +} + +void PMTreeViewItem::setSelected( bool select ) +{ + bool ws = isSelected( ); + PMTreeView* treeview = ( PMTreeView* ) listView( ); + + // ignore selections during a move event + if( treeview->acceptSelect( ) ) + { + QListViewItem::setSelected( select ); + + if( ws != isSelected( ) ) + treeview->itemSelected( this, isSelected( ) ); + } +} + +void PMTreeViewItem::initSelection( ) +{ + QListViewItem::setSelected( m_pObject->isSelected( ) ); +// if( m_pObject->isSelected( ) ) +// repaint( ); +} diff --git a/kpovmodeler/pmtreeviewitem.h b/kpovmodeler/pmtreeviewitem.h new file mode 100644 index 00000000..499e2d16 --- /dev/null +++ b/kpovmodeler/pmtreeviewitem.h @@ -0,0 +1,88 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMTREEVIEWITEM_H +#define PMTREEVIEWITEM_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +class PMObject; + +/** + * QListViewItem for a @ref PMObject + * + * Each PMListViewItem is connected to a PMObject. + */ +class PMTreeViewItem : public QListViewItem +{ +public: + /** + * Constructs a new top-level list view item in the QListView parent. + */ + PMTreeViewItem( PMObject* object, QListView* parent ); + /** + * Constructs a new list view item which is a child of parent and + * first in the parent's list of children. + */ + PMTreeViewItem( PMObject* object, QListViewItem* parent ); + /** + * Constructs a list view item which is a child of parent + * and is after after in the parent's list of children. + */ + PMTreeViewItem( PMObject* object, QListView* parent, QListViewItem* after ); + /** + * Constructs a list view item which is a child of parent + * and is after after in the parent's list of children. + */ + PMTreeViewItem( PMObject* object, QListViewItem* parent, + QListViewItem* after ); + /** + * Returns the connected @ref PMObject + */ + PMObject* object( ) const { return m_pObject; } + /** + * Returns a key that can be used for sorting, here the index in the + * parents list of children + */ + virtual QString key( int column, bool ascending ) const; + /** + * Returns a pointer to the parent item + */ + PMTreeViewItem* parent( ) + { + return ( PMTreeViewItem* ) QListViewItem::parent( ); + } + void setSelected( bool select ); + + /** + * Sets the text and pixmap + */ + void setDescriptions( ); +private: + /** + * Initializes the selection at creation + */ + void initSelection( ); + PMObject* m_pObject; +}; + +#endif diff --git a/kpovmodeler/pmtriangle.cpp b/kpovmodeler/pmtriangle.cpp new file mode 100644 index 00000000..3cae7e37 --- /dev/null +++ b/kpovmodeler/pmtriangle.cpp @@ -0,0 +1,621 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmtriangle.h" +#include "pmtriangleedit.h" + +#include "pmxmlhelper.h" +#include "pmmemento.h" +#include "pmviewstructure.h" +#include "pm3dcontrolpoint.h" +#include "pmvectorcontrolpoint.h" + +#include + +const PMVector point0Default = PMVector( -1.0, 0.0, 0.0 ); +const PMVector point1Default = PMVector( 1.0, 0.0, 0.0 ); +const PMVector point2Default = PMVector( 0.0, 0.0, 1.0 ); +const PMVector normal0Default = PMVector( 0.0, 1.0, 0.0 ); +const PMVector normal1Default = PMVector( 0.0, 1.0, 0.0 ); +const PMVector normal2Default = PMVector( 0.0, 1.0, 0.0 ); +const PMVector uvVector0Default = PMVector( 0.0, 0.0 ); +const PMVector uvVector1Default = PMVector( 1.0, 0.0 ); +const PMVector uvVector2Default = PMVector( 0.5, 1.0 ); + +PMDefinePropertyClass( PMTriangle, PMTriangleProperty ); + +class PMPointProperty : public PMPropertyBase +{ +public: + PMPointProperty( ) : PMPropertyBase( "points", PMVariant::Vector ) + { + m_index = 0; + } + virtual int dimensions( ) const { return 1; } + virtual void setIndex( int /*dimension*/, int index ) + { + if( index < 0 || index > 2 ) + kdError( PMArea ) << "Illegal index in PMTriangle::PointProperty::setIndex" << endl; + else + m_index = index; + } + virtual int size( PMObject* /*object*/, int /*dimension*/ ) const + { + return 3; + } +protected: + virtual bool setProtected( PMObject* obj, const PMVariant& v ) + { + PMTriangle* p = ( PMTriangle* ) obj; + p->setPoint( m_index, v.vectorData( ) ); + return true; + } + virtual PMVariant getProtected( const PMObject* obj ) + { + const PMTriangle* p = ( const PMTriangle* ) obj; + return PMVariant( p->point( m_index ) ); + } + +private: + int m_index; +}; + +class PMNormalProperty : public PMPropertyBase +{ +public: + PMNormalProperty( ) : PMPropertyBase( "normals", PMVariant::Vector ) + { + m_index = 0; + } + virtual int dimensions( ) const { return 1; } + virtual void setIndex( int /*dimension*/, int index ) + { + if( index < 0 || index > 2 ) + kdError( PMArea ) << "Illegal index in PMTriangle::NormalProperty::setIndex" << endl; + else + m_index = index; + } + virtual int size( PMObject* /*object*/, int /*dimension*/ ) const + { + return 3; + } +protected: + virtual bool setProtected( PMObject* obj, const PMVariant& v ) + { + PMTriangle* p = ( PMTriangle* ) obj; + p->setNormal( m_index, v.vectorData( ) ); + return true; + } + virtual PMVariant getProtected( const PMObject* obj ) + { + const PMTriangle* p = ( const PMTriangle* ) obj; + return PMVariant( p->normal( m_index ) ); + } + +private: + int m_index; +}; + +class PMUVVectorProperty : public PMPropertyBase +{ +public: + PMUVVectorProperty( ) + : PMPropertyBase( "uvVectors", PMVariant::Vector ) + { + m_index = 0; + } + virtual int dimensions( ) const { return 1; } + virtual void setIndex( int /*dimension*/, int index ) + { + if( index < 0 || index > 2 ) + kdError( PMArea ) << "Illegal index in PMTriangle::UVVectorProperty::setIndex" << endl; + else + m_index = index; + } + virtual int size( PMObject* /*object*/, int /*dimension*/ ) const + { + return 2; + } +protected: + virtual bool setProtected( PMObject* obj, const PMVariant& v ) + { + PMTriangle* p = ( PMTriangle* ) obj; + p->setUVVector( m_index, v.vectorData( ) ); + return true; + } + virtual PMVariant getProtected( const PMObject* obj ) + { + const PMTriangle* p = ( const PMTriangle* ) obj; + return PMVariant( p->uvVector( m_index ) ); + } + +private: + int m_index; +}; + +PMMetaObject* PMTriangle::s_pMetaObject = 0; +PMObject* createNewTriangle( PMPart* part ) +{ + return new PMTriangle( part ); +} +PMViewStructure* PMTriangle::s_pDefaultViewStructure = 0; + +PMTriangle::PMTriangle( PMPart* part ) + : Base( part ) +{ + m_point[0] = point0Default; + m_point[1] = point1Default; + m_point[2] = point2Default; + m_normal[0] = normal0Default; + m_normal[1] = normal1Default; + m_normal[2] = normal2Default; + m_smooth = false; + m_uvVector[0] = uvVector0Default; + m_uvVector[1] = uvVector1Default; + m_uvVector[2] = uvVector2Default; + m_uvEnabled = false; +} + +PMTriangle::PMTriangle( const PMTriangle& t ) + : Base( t ) +{ + int i; + for( i = 0; i < 3; i++ ) + { + m_point[i] = t.m_point[i]; + m_normal[i] = t.m_normal[i]; + m_uvVector[i] = t.m_uvVector[i]; + } + m_smooth = t.m_smooth; + m_uvEnabled = t.m_uvEnabled; +} + +PMTriangle::~PMTriangle( ) +{ +} + +QString PMTriangle::description( ) const +{ + if( m_smooth ) + return i18n( "smooth triangle" ); + return i18n( "triangle" ); +} + +void PMTriangle::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "point0", m_point[0].serializeXML( ) ); + e.setAttribute( "point1", m_point[1].serializeXML( ) ); + e.setAttribute( "point2", m_point[2].serializeXML( ) ); + e.setAttribute( "normal0", m_normal[0].serializeXML( ) ); + e.setAttribute( "normal1", m_normal[1].serializeXML( ) ); + e.setAttribute( "normal2", m_normal[2].serializeXML( ) ); + e.setAttribute( "smooth", m_smooth ); + e.setAttribute( "uvVector0", m_uvVector[0].serializeXML( ) ); + e.setAttribute( "uvVector1", m_uvVector[1].serializeXML( ) ); + e.setAttribute( "uvVector2", m_uvVector[2].serializeXML( ) ); + e.setAttribute( "uvEnabled", m_uvEnabled ); + Base::serialize( e, doc ); +} + +void PMTriangle::readAttributes( const PMXMLHelper& h ) +{ + m_point[0] = h.vectorAttribute( "point0", point0Default ); + m_point[1] = h.vectorAttribute( "point1", point1Default ); + m_point[2] = h.vectorAttribute( "point2", point2Default ); + m_normal[0] = h.vectorAttribute( "normal0", normal0Default ); + m_normal[1] = h.vectorAttribute( "normal1", normal1Default ); + m_normal[2] = h.vectorAttribute( "normal2", normal2Default ); + m_smooth = h.boolAttribute( "smooth", false ); + m_uvVector[0] = h.vectorAttribute( "uvVector0", uvVector0Default ); + m_uvVector[1] = h.vectorAttribute( "uvVector1", uvVector1Default ); + m_uvVector[2] = h.vectorAttribute( "uvVector2", uvVector2Default ); + m_uvEnabled = h.boolAttribute( "uvEnabled", m_uvEnabled ); + Base::readAttributes( h ); +} + +PMMetaObject* PMTriangle::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Triangle", Base::metaObject( ), + createNewTriangle ); + s_pMetaObject->addProperty( + new PMTriangleProperty( "smooth", &PMTriangle::setSmoothTriangle, + &PMTriangle::isSmoothTriangle ) ); + s_pMetaObject->addProperty( new PMPointProperty( ) ); + s_pMetaObject->addProperty( new PMNormalProperty( ) ); + s_pMetaObject->addProperty( new PMUVVectorProperty( ) ); + } + return s_pMetaObject; +} + +void PMTriangle::setPoint( int i, const PMVector& p ) +{ + if( ( i >= 0 ) && ( i <= 2 ) ) + { + if( p != m_point[i] ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMPoint0ID + i, m_point[i] ); + m_point[i] = p; + m_point[i].resize( 3 ); + setViewStructureChanged( ); + } + } + else + kdError( PMArea ) << "Wrong index in PMTriangle::setPoint\n"; +} + +PMVector PMTriangle::point( int i ) const +{ + if( ( i >= 0 ) && ( i <= 2 ) ) + return m_point[i]; + else + kdError( PMArea ) << "Wrong index in PMTriangle::point\n"; + return PMVector( 0.0, 0.0, 0.0 ); +} + +void PMTriangle::setNormal( int i, const PMVector& p ) +{ + if( ( i >= 0 ) && ( i <= 2 ) ) + { + if( p != m_normal[i] ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMNormal0ID + i, m_normal[i] ); + m_normal[i] = p; + m_normal[i].resize( 3 ); + setViewStructureChanged( ); + } + } + else + kdError( PMArea ) << "Wrong index in PMTriangle::setNormal\n"; +} + +PMVector PMTriangle::normal( int i ) const +{ + if( ( i >= 0 ) && ( i <= 2 ) ) + return m_normal[i]; + else + kdError( PMArea ) << "Wrong index in PMTriangle::normal\n"; + return PMVector( 0.0, 0.0, 0.0 ); +} + +void PMTriangle::setSmoothTriangle( bool on ) +{ + if( on != m_smooth ) + { + if( m_pMemento ) + { + m_pMemento->addData( s_pMetaObject, PMSmoothID, m_smooth ); + m_pMemento->setDescriptionChanged( ); + } + m_smooth = on; + setViewStructureChanged( ); + } +} + +PMVector PMTriangle::uvVector( int i ) const +{ + if( i >= 0 && i < 3 ) + return m_uvVector[i]; + else + kdError( PMArea ) << "Wrong index in PMTriangle::uvVector\n"; + return PMVector( 0.0, 0.0 ); +} + +void PMTriangle::setUVVector( int i, const PMVector& v ) +{ + if( i >= 0 && i < 3 ) + { + if( v != m_uvVector[i] ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMUVVector0ID + i, m_uvVector[i] ); + m_uvVector[i] = v; + m_uvVector[i].resize( 2 ); + } + } + else + kdError( PMArea ) << "Wrong index in PMTriangle::setNormal\n"; +} + +void PMTriangle::enableUV( bool yes ) +{ + if( yes != m_uvEnabled ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMUVEnabledID, m_uvEnabled ); + m_uvEnabled = yes; + } +} + +PMDialogEditBase* PMTriangle::editWidget( QWidget* parent ) const +{ + return new PMTriangleEdit( parent ); +} + +void PMTriangle::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMPoint0ID: + setPoint( 0, data->vectorData( ) ); + break; + case PMPoint1ID: + setPoint( 1, data->vectorData( ) ); + break; + case PMPoint2ID: + setPoint( 2, data->vectorData( ) ); + break; + case PMNormal0ID: + setNormal( 0, data->vectorData( ) ); + break; + case PMNormal1ID: + setNormal( 1, data->vectorData( ) ); + break; + case PMNormal2ID: + setNormal( 2, data->vectorData( ) ); + break; + case PMSmoothID: + setSmoothTriangle( data->boolData( ) ); + break; + case PMUVVector0ID: + setUVVector( 0, data->vectorData( ) ); + break; + case PMUVVector1ID: + setUVVector( 1, data->vectorData( ) ); + break; + case PMUVVector2ID: + setUVVector( 2, data->vectorData( ) ); + break; + case PMUVEnabledID: + enableUV( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMTriangle::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + + +bool PMTriangle::isDefault( ) +{ + if( ( m_point[0] == point0Default ) + && ( m_point[1] == point1Default ) + && ( m_point[2] == point2Default ) ) + return true; + return false; +} + +void PMTriangle::createViewStructure( ) +{ + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultViewStructure( ) ); + m_pViewStructure->points( ).detach( ); + } + + PMPointArray& points = m_pViewStructure->points( ); + + points[0] = m_point[0]; + points[1] = m_point[1]; + points[2] = m_point[2]; +} + +PMViewStructure* PMTriangle::defaultViewStructure( ) const +{ + if( !s_pDefaultViewStructure ) + { + s_pDefaultViewStructure = new PMViewStructure( 3, 3 ); + PMPointArray& points = s_pDefaultViewStructure->points( ); + PMLineArray& lines = s_pDefaultViewStructure->lines( ); + + points[0] = point0Default; + points[1] = point1Default; + points[2] = point2Default; + + lines[0] = PMLine( 0, 1 ); + lines[1] = PMLine( 1, 2 ); + lines[2] = PMLine( 0, 2 ); + } + return s_pDefaultViewStructure; +} + +void PMTriangle::controlPoints( PMControlPointList& list ) +{ + PM3DControlPoint* cp; + + cp = new PM3DControlPoint( m_point[0], PMPoint0ID, + i18n( "Point 1" ) ); + list.append( cp ); + if( m_smooth ) + list.append( new PMVectorControlPoint( cp, m_normal[0], PMNormal0ID, + i18n( "Normal 1" ) ) ); + + cp = new PM3DControlPoint( m_point[1], PMPoint1ID, + i18n( "Point 2" ) ); + list.append( cp ); + if( m_smooth ) + list.append( new PMVectorControlPoint( cp, m_normal[1], PMNormal1ID, + i18n( "Normal 2" ) ) ); + + cp = new PM3DControlPoint( m_point[2], PMPoint2ID, + i18n( "Point 3" ) ); + list.append( cp ); + if( m_smooth ) + list.append( new PMVectorControlPoint( cp, m_normal[2], PMNormal2ID, + i18n( "Normal 3" ) ) ); +} + +void PMTriangle::controlPointsChanged( PMControlPointList& list ) +{ + PMControlPoint* p; + PMVector p0, p1, p2; + PMVector n0, n1, n2; + double normalDirection = 1.0; + PMVector triangleNormal; + bool validNormal = false; + double d; + + for( p = list.first( ); p; p = list.next( ) ) + { + switch( p->id( ) ) + { + case PMPoint0ID: + p0 = ( ( PM3DControlPoint* ) p )->point( ); + break; + case PMPoint1ID: + p1 = ( ( PM3DControlPoint* ) p )->point( ); + break; + case PMPoint2ID: + p2 = ( ( PM3DControlPoint* ) p )->point( ); + break; + case PMNormal0ID: + n0 = ( ( PMVectorControlPoint* ) p )->vector( ); + break; + case PMNormal1ID: + n1 = ( ( PMVectorControlPoint* ) p )->vector( ); + break; + case PMNormal2ID: + n2 = ( ( PMVectorControlPoint* ) p )->vector( ); + break; + default: + break; + } + } + + if( m_smooth ) + { + triangleNormal = PMVector::cross( m_point[1] - m_point[0], + m_point[2] - m_point[0] ); + normalDirection = PMVector::dot( triangleNormal, m_normal[0] ); + if( approxZero( normalDirection ) ) + normalDirection = PMVector::dot( triangleNormal, m_normal[1] ); + if( approxZero( normalDirection ) ) + normalDirection = PMVector::dot( triangleNormal, m_normal[2] ); + if( normalDirection < 0 ) + triangleNormal = -triangleNormal; + if( !approxZero( triangleNormal.abs( ) ) ) + { + validNormal = true; + triangleNormal /= triangleNormal.abs( ); + } + } + + for( p = list.first( ); p; p = list.next( ) ) + { + if( p->changed( ) ) + { + switch( p->id( ) ) + { + case PMPoint0ID: + if( !( p0.approxEqual( p1 ) || p0.approxEqual( p2 ) ) ) + setPoint( 0, p0 ); + else + ( ( PM3DControlPoint* ) p )->setPoint( m_point[0] ); + break; + case PMPoint1ID: + if( !( p1.approxEqual( p0 ) || p1.approxEqual( p2 ) ) ) + setPoint( 1, p1 ); + else + ( ( PM3DControlPoint* ) p )->setPoint( m_point[1] ); + break; + case PMPoint2ID: + if( !( p2.approxEqual( p0 ) || p2.approxEqual( p1 ) ) ) + setPoint( 2, p2 ); + else + ( ( PM3DControlPoint* ) p )->setPoint( m_point[2] ); + break; + + case PMNormal0ID: + if( validNormal ) + { + d = PMVector::dot( triangleNormal, n0 ); + if( d > 0 ) + setNormal( 0, n0 ); + else + { + setNormal( 0, n0 - ( d - 1e-5 ) * triangleNormal ); + ( ( PMVectorControlPoint* ) p )->setVector( m_normal[0] ); + } + } + else + ( ( PMVectorControlPoint* ) p )->setVector( m_normal[0] ); + break; + case PMNormal1ID: + if( validNormal ) + { + d = PMVector::dot( triangleNormal, n1 ); + if( d > 0 ) + setNormal( 1, n1 ); + else + { + setNormal( 1, n1 - ( d - 1e-5 ) * triangleNormal ); + ( ( PMVectorControlPoint* ) p )->setVector( m_normal[1] ); + } + } + else + ( ( PMVectorControlPoint* ) p )->setVector( m_normal[1] ); + break; + case PMNormal2ID: + if( validNormal ) + { + d = PMVector::dot( triangleNormal, n2 ); + if( d > 0 ) + setNormal( 2, n2 ); + else + { + setNormal( 2, n2 - ( d - 1e-5 ) * triangleNormal ); + ( ( PMVectorControlPoint* ) p )->setVector( m_normal[2] ); + } + } + else + ( ( PMVectorControlPoint* ) p )->setVector( m_normal[2] ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMTriangle::controlPointsChanged\n"; + break; + } + } + } +} + +void PMTriangle::cleanUp( ) const +{ + if( s_pDefaultViewStructure ) + delete s_pDefaultViewStructure; + s_pDefaultViewStructure = 0; + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} diff --git a/kpovmodeler/pmtriangle.h b/kpovmodeler/pmtriangle.h new file mode 100644 index 00000000..e2309c79 --- /dev/null +++ b/kpovmodeler/pmtriangle.h @@ -0,0 +1,158 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMTRIANGLE_H +#define PMTRIANGLE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmgraphicalobject.h" +#include "pmvector.h" + +class PMViewStructure; + +/** + * Class for povray triangles. + */ + +class PMTriangle : public PMGraphicalObject +{ + typedef PMGraphicalObject Base; +public: + /** + * Creates an empty PMTriangle + */ + PMTriangle( PMPart* part ); + /** + * Copy constructor + */ + PMTriangle( const PMTriangle& t ); + /** + * deletes the PMTriangle + */ + virtual ~PMTriangle( ); + + /** */ + virtual PMObject* copy( ) const { return new PMTriangle( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + /** + * Returns a new @ref PMTriangleEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmtriangle" ); } + + /** + * Returns true if the triangle is a smooth triangle + */ + bool isSmoothTriangle( ) const { return m_smooth; } + /** + * Enables/disables the normal vectors + */ + void setSmoothTriangle( bool on ); + + /** + * Returns the point with index i + */ + PMVector point( int i ) const; + /** + * Sets the point with index i + */ + void setPoint( int i, const PMVector& p ); + /** + * Returns the normal vector with index i + */ + PMVector normal( int i ) const; + /** + * Sets the mormal vector with index i + */ + void setNormal( int i, const PMVector& n ); + + /** + * Returns the uv vector with index i + */ + PMVector uvVector( int i ) const; + /** + * Sets the uv vector with index i + */ + void setUVVector( int i, const PMVector& v ); + /** + * Return true if triangle has uv vectors + */ + bool isUVEnabled( ) const { return m_uvEnabled; } + /** + * Enables/disable the uv vectors + */ + void enableUV( bool yes ); + + /** */ + virtual void restoreMemento( PMMemento* s ); + /** */ + virtual void controlPoints( PMControlPointList& list ); + /** */ + virtual void controlPointsChanged( PMControlPointList& list ); + /** */ + virtual void cleanUp( ) const; + +protected: + /** */ + virtual bool isDefault( ); + /** */ + virtual void createViewStructure( ); + /** */ + virtual PMViewStructure* defaultViewStructure( ) const; + +protected: + /** + * IDs for @ref PMMementoData + */ + enum PMTriangleMementoID { PMPoint0ID, PMPoint1ID, PMPoint2ID, + PMNormal0ID, PMNormal1ID, PMNormal2ID, + PMSmoothID, + PMUVVector0ID, PMUVVector1ID, PMUVVector2ID, + PMUVEnabledID }; + PMVector m_point[3]; + PMVector m_normal[3]; + PMVector m_uvVector[3]; + bool m_smooth; + bool m_uvEnabled; + + /** + * The default view structure. It can be shared between triangles + */ + static PMViewStructure* s_pDefaultViewStructure; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmtriangleedit.cpp b/kpovmodeler/pmtriangleedit.cpp new file mode 100644 index 00000000..7b225aa8 --- /dev/null +++ b/kpovmodeler/pmtriangleedit.cpp @@ -0,0 +1,273 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmtriangleedit.h" +#include "pmtriangle.h" +#include "pmvectoredit.h" + +#include +#include +#include +#include +#include +#include + +PMTriangleEdit::PMTriangleEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMTriangleEdit::createTopWidgets( ) +{ + Base::createTopWidgets( ); + + int i; + + QHBoxLayout *hl = new QHBoxLayout( topLayout( ) ); + m_pSmooth = new QCheckBox( i18n( "Smooth" ), this ); + hl->addWidget( m_pSmooth ); + connect( m_pSmooth, SIGNAL( toggled( bool ) ), + SLOT( slotSmoothChecked( bool ) ) ); + + m_pUVEnabled = new QCheckBox( i18n( "UV vectors" ), this ); + hl->addWidget( m_pUVEnabled ); + connect( m_pUVEnabled, SIGNAL( toggled( bool ) ), + SLOT( slotUVVectorsChecked( bool ) ) ); + + QGridLayout* gl = new QGridLayout( topLayout( ), 9, 2 ); + + for( i = 0; i < 3; i++ ) + { + m_pPoint[i] = new PMVectorEdit( "x", "y", "z", this ); + gl->addWidget( new QLabel( i18n( "Point %1:" ).arg( i+1 ), this ), + i * 3, 0 ); + gl->addWidget( m_pPoint[i], i * 3, 1 ); + connect( m_pPoint[i], SIGNAL( dataChanged( ) ), + SIGNAL( dataChanged( ) ) ); + + m_pNormal[i] = new PMVectorEdit( "x", "y", "z", this ); + m_pNormalLabel[i] = new QLabel( i18n( "Normal %1:" ).arg( i+1 ), this ); + gl->addWidget( m_pNormalLabel[i], i * 3 + 1, 0 ); + gl->addWidget( m_pNormal[i], i * 3 + 1, 1 ); + connect( m_pNormal[i], SIGNAL( dataChanged( ) ), + SIGNAL( dataChanged( ) ) ); + + m_pUVVector[i] = new PMVectorEdit( "u", "v", this ); + m_pUVVectorLabel[i] = new QLabel( i18n( "UV vector %1:" ).arg( i+1 ), this ); + gl->addWidget( m_pUVVectorLabel[i], i * 3 + 2, 0 ); + gl->addWidget( m_pUVVector[i], i * 3 + 2, 1 ); + connect( m_pUVVector[i], SIGNAL( dataChanged( ) ), + SIGNAL( dataChanged( ) ) ); + } + hl = new QHBoxLayout( topLayout( ) ); + m_pMirror = new QPushButton( i18n( "Invert Normal Vectors" ), this ); + hl->addWidget( m_pMirror ); + hl->addStretch( 1 ); + connect( m_pMirror, SIGNAL( clicked( ) ), SLOT( slotInvertNormals( ) ) ); +} + +void PMTriangleEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Triangle" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMTriangle* ) o; + bool smooth = m_pDisplayedObject->isSmoothTriangle( ); + bool uvVector = m_pDisplayedObject->isUVEnabled( ); + int i; + + for( i = 0; i < 3; i++ ) + { + m_pPoint[i]->setVector( m_pDisplayedObject->point( i ) ); + m_pPoint[i]->setReadOnly( readOnly ); + + m_pNormal[i]->setVector( m_pDisplayedObject->normal( i ) ); + m_pNormal[i]->setReadOnly( readOnly ); + + m_pUVVector[i]->setVector( m_pDisplayedObject->uvVector( i ) ); + m_pUVVector[i]->setReadOnly( readOnly ); + + m_pSmooth->setChecked( smooth ); + if( smooth ) + { + m_pNormal[i]->show( ); + m_pNormalLabel[i]->show( ); + m_pMirror->show( ); + } + else + { + m_pNormal[i]->hide( ); + m_pNormalLabel[i]->hide( ); + m_pMirror->hide( ); + } + + m_pUVEnabled->setChecked( uvVector ); + if( uvVector ) + { + m_pUVVector[i]->show( ); + m_pUVVectorLabel[i]->show( ); + } + else + { + m_pUVVector[i]->hide( ); + m_pUVVectorLabel[i]->hide( ); + } + + emit sizeChanged( ); + } + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMTriangleEdit: Can't display object\n"; +} + +void PMTriangleEdit::slotSmoothChecked( bool on ) +{ + int i; + for( i = 0; i < 3; i++ ) + { + if( on ) + { + m_pNormal[i]->show( ); + m_pNormalLabel[i]->show( ); + m_pMirror->show( ); + } + else + { + m_pNormal[i]->hide( ); + m_pNormalLabel[i]->hide( ); + m_pMirror->hide( ); + } + } + emit sizeChanged( ); + emit dataChanged( ); +} + +void PMTriangleEdit::slotUVVectorsChecked( bool on ) +{ + int i; + for( i = 0; i < 3; ++i ) + { + if( on ) + { + m_pUVVector[i]->show( ); + m_pUVVectorLabel[i]->show( ); + } + else + { + m_pUVVector[i]->hide( ); + m_pUVVectorLabel[i]->hide( ); + } + } + emit sizeChanged( ); + emit dataChanged( ); +} + +void PMTriangleEdit::slotInvertNormals( ) +{ + int i; + for( i = 0; i < 3; i++ ) + if( !m_pNormal[i]->isDataValid( ) ) + return; + + for( i = 0; i < 3; i++ ) + m_pNormal[i]->setVector( -( m_pNormal[i]->vector( ) ) ); +} + +void PMTriangleEdit::saveContents( ) +{ + int i; + if( m_pDisplayedObject ) + { + Base::saveContents( ); + for( i = 0; i < 3; i++ ) + m_pDisplayedObject->setPoint( i, m_pPoint[i]->vector( ) ); + + if( m_pSmooth->isChecked( ) ) + { + m_pDisplayedObject->setSmoothTriangle( true ); + for( i = 0; i < 3; i++ ) + m_pDisplayedObject->setNormal( i, m_pNormal[i]->vector( ) ); + } + else + m_pDisplayedObject->setSmoothTriangle( false ); + + if( m_pUVEnabled->isChecked( ) ) + { + m_pDisplayedObject->enableUV( true ); + for( i = 0; i < 3; ++i ) + m_pDisplayedObject->setUVVector( i, m_pUVVector[i]->vector( ) ); + } + else + m_pDisplayedObject->enableUV( false ); + } +} + +bool PMTriangleEdit::isDataValid( ) +{ + int i; + for( i = 0; i < 3; i++ ) + if( !m_pPoint[i]->isDataValid( ) ) + return false; + + PMVector p0 = m_pPoint[0]->vector( ), + p1 = m_pPoint[1]->vector( ), + p2 = m_pPoint[2]->vector( ); + + if( p0.approxEqual( p1 ) || p1.approxEqual( p2 ) || p0.approxEqual( p2 ) ) + { + KMessageBox::error( this, i18n( "Please enter a valid triangle." ), + i18n( "Error" ) ); + return false; + } + + if( m_pSmooth->isChecked( ) ) + { + for( i = 0; i < 3; i++ ) + if( !m_pNormal[i]->isDataValid( ) ) + return false; + + PMVector n0 = m_pNormal[0]->vector( ), + n1 = m_pNormal[1]->vector( ), + n2 = m_pNormal[2]->vector( ); + PMVector tn = PMVector::cross( p1 - p0, p2 - p0 ); + double c0 = PMVector::dot( tn, n0 ), + c1 = PMVector::dot( tn, n1 ), + c2 = PMVector::dot( tn, n2 ); + if( ( ( c0 * c1 ) < 0 ) || ( ( c0 * c2 ) < 0 ) ) + { + KMessageBox::error( this, i18n( "All normal vectors have to point" + " to the same side of the triangle." ), + i18n( "Error" ) ); + return false; + } + } + + if( m_pUVEnabled->isChecked( ) ) + { + for( i = 0; i < 3; ++i ) + if( !m_pUVVector[i]->isDataValid( ) ) + return false; + } + + return Base::isDataValid( ); +} + +#include "pmtriangleedit.moc" diff --git a/kpovmodeler/pmtriangleedit.h b/kpovmodeler/pmtriangleedit.h new file mode 100644 index 00000000..821ad68d --- /dev/null +++ b/kpovmodeler/pmtriangleedit.h @@ -0,0 +1,77 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMTRIANGLEEDIT_H +#define PMTRIANGLEEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmgraphicalobjectedit.h" + +class PMTriangle; +class PMVectorEdit; +class QCheckBox; +class QLabel; +class QPushButton; + +/** + * Dialog edit class for @ref PMTriangle + */ +class PMTriangleEdit : public PMGraphicalObjectEdit +{ + Q_OBJECT + typedef PMGraphicalObjectEdit Base; +public: + /** + * Creates a PMTriangleEdit with parent and name + */ + PMTriangleEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +private slots: + void slotSmoothChecked( bool on ); + void slotUVVectorsChecked( bool on ); + void slotInvertNormals( ); + +private: + PMTriangle* m_pDisplayedObject; + PMVectorEdit* m_pPoint[3]; + PMVectorEdit* m_pNormal[3]; + QLabel* m_pNormalLabel[3]; + QCheckBox* m_pSmooth; + QLabel* m_pUVVectorLabel[3]; + PMVectorEdit* m_pUVVector[3]; + QCheckBox* m_pUVEnabled; + QPushButton* m_pMirror; +}; + + +#endif diff --git a/kpovmodeler/pmtruetypecache.cpp b/kpovmodeler/pmtruetypecache.cpp new file mode 100644 index 00000000..9aa28d89 --- /dev/null +++ b/kpovmodeler/pmtruetypecache.cpp @@ -0,0 +1,395 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmtruetypecache.h" +#include "pmdebug.h" + +//*********************************************************************** +// Part with freetype support +//*********************************************************************** + +#ifdef HAVE_FREETYPE +#define PMFREETYPEDEBUG + +PMTrueTypeCache* PMTrueTypeCache::s_pInstance = 0; +KStaticDeleter PMTrueTypeCache::s_staticDeleter; + +PMTrueTypeCache::PMTrueTypeCache( ) + : m_cache( 10, 17, true ) +{ + bool error = FT_Init_FreeType( &m_library ); + if( error ) + kdError( PMArea ) << "Failed to initialize the freetype library\n"; + +#ifdef PMFREETYPEDEBUG + else + kdDebug( PMArea ) << "Freetype 2 initialized\n"; +#endif + + m_cache.setAutoDelete( true ); +} + +PMTrueTypeCache::~PMTrueTypeCache( ) +{ + m_cache.clear( ); + if( m_library ) + FT_Done_FreeType( m_library ); +} + +PMTrueTypeFont* PMTrueTypeCache::lookUp( const QString& file ) +{ + if( !m_library ) + return 0; + if( file.isEmpty( ) ) + return 0; + + PMTrueTypeFont* f = m_cache.find( file ); + if( !f ) + { + FT_Face face; + FT_New_Face( m_library, file.latin1( ), 0, &face ); + f = new PMTrueTypeFont( m_library, face ); + +#ifdef PMFREETYPEDEBUG + if( face ) + kdDebug( PMArea ) << "Successfully opened font " << file << endl; + + if( f->isValid( ) ) + m_cache.insert( file, f, 1 ); + else + m_cache.insert( file, f, 0 ); +#endif + } + + if( f->isValid( ) ) + return f; + + return 0; +} + +PMTrueTypeFont* PMTrueTypeCache::font( const QString& file ) +{ + if( !s_pInstance ) + s_staticDeleter.setObject( s_pInstance, new PMTrueTypeCache( ) ); + + return s_pInstance->lookUp( file ); +} + +PMTrueTypeFont::PMTrueTypeFont( FT_Library lib, FT_Face face ) + : m_cache( 100, 127 ) +{ + m_library = lib; + m_face = face; + m_valid = false; + m_validChecked = false; + m_useKerning = false; + if( m_face ) + { + m_useKerning = FT_HAS_KERNING( m_face ); + // find the correct encoding + int i; + bool found = false; + for( i = 0; ( i < m_face->num_charmaps ) && !found; i++ ) + if( m_face->charmaps[i]->platform_id == 3 ) // microsoft encodings + FT_Set_Charmap( m_face, m_face->charmaps[i] ); + for( i = 0; ( i < m_face->num_charmaps ) && !found; i++ ) + if( m_face->charmaps[i]->platform_id == 1 ) // mac encodings + FT_Set_Charmap( m_face, m_face->charmaps[i] ); + } + + m_cache.setAutoDelete( true ); +} + +PMTrueTypeFont::~PMTrueTypeFont( ) +{ + if( m_face ) + FT_Done_Face( m_face ); + m_cache.clear( ); +} + +bool PMTrueTypeFont::isValid( ) +{ + if( !m_validChecked ) + { + if( !m_face ) + m_valid = false; + else + m_valid = m_face->face_flags & FT_FACE_FLAG_SCALABLE; + +#ifdef PMFREETYPEDEBUG + if( m_valid ) + kdDebug( PMArea ) << "Font: " << m_face->family_name + << " style " << m_face->style_name + << " units_per_EM " << m_face->units_per_EM + << " height " << m_face->height << endl; +#endif + + m_validChecked = true; + } + + return m_valid; +} + +PMTrueTypeOutline* PMTrueTypeFont::outline( QChar c ) +{ + PMTrueTypeOutline* ol = 0; + + if( isValid( ) ) + { + QString str( c ); + ol = m_cache.find( str ); + if( !ol ) + { + FT_UInt glyphIndex = findGlyphIndex( c ); + + bool error = !glyphIndex; + FT_Glyph glyph = 0; + + if( !error ) + error = FT_Load_Glyph( m_face, glyphIndex, + FT_LOAD_NO_BITMAP | FT_LOAD_NO_SCALE ); + if( !error ) + error = FT_Get_Glyph( m_face->glyph, &glyph ); + +#ifdef PMFREETYPEDEBUG + if( error ) + kdDebug( PMArea ) << "Failed to load glyph for " << c.latin1( ) << "\n"; + else + { + FT_Glyph_Metrics* m = &( m_face->glyph->metrics ); + kdDebug( PMArea ) << "Glyph w: " << m->width << " h: " << m->height + << " hbx: " << m->horiBearingX << " hby: " << m->horiBearingY + << " ha: " << m->horiAdvance << endl; + } +#endif + + if( !error && glyph && ( glyph->format == ft_glyph_format_outline ) ) + { + FT_OutlineGlyph outlineGlyph = ( FT_OutlineGlyph ) glyph; + ol = new PMTrueTypeOutline( outlineGlyph, m_face ); + } + + if( glyph ) + FT_Done_Glyph( glyph ); + if( ol ) + m_cache.insert( str, ol ); + } + } + + return ol; +} + +double PMTrueTypeFont::kerning( QChar c1, QChar c2 ) +{ + double k = 0.0; + if( m_useKerning && !c1.isNull( ) && !c2.isNull( ) ) + { + FT_UInt gi1 = findGlyphIndex( c1 ); + FT_UInt gi2 = findGlyphIndex( c2 ); + if( gi1 && gi2 ) + { + FT_Vector delta; + FT_Get_Kerning( m_face, gi1, gi2, ft_kerning_unscaled, &delta ); + k = ( double ) delta.x / ( double ) m_face->units_per_EM; + } + } + + return k; +} + +FT_UInt PMTrueTypeFont::findGlyphIndex( QChar c ) +{ + FT_UInt glyphIndex = 0; + + if( m_face ) + { + // glyphIndex = FT_Get_Char_Index( m_face, c.unicode( ) ); + // if( !glyphIndex ) + char ch = c.latin1( ); + if( !ch ) + ch = '?'; + glyphIndex = FT_Get_Char_Index( m_face, ch ); + } + return glyphIndex; +} + +PMTrueTypeOutline::PMTrueTypeOutline( FT_OutlineGlyph glyph, FT_Face face ) +{ + int n = 0, p = 0, si; + FT_Outline* ol = &( glyph->outline ); + + PMVector v[4]; + bool onPoint[4] = { false, false, false, false }; + bool cubic[4] = { false, false, false, false }; + + double dfh = ( double ) face->units_per_EM; + double horiBearing = ( double ) face->glyph->metrics.horiBearingX / dfh; + + m_segments = 0; + m_contours = ol->n_contours; + m_advance = ( double ) face->glyph->metrics.horiAdvance / dfh; + +#ifdef PMFREETYPEDEBUG + + /** + kdDebug( PMArea ) << "New outline:\n"; + int dn, dp = 0; + for( dn = 0; dn < m_contours; dn++ ) + { + kdDebug( PMArea ) << " Contour " << dn << ":\n"; + for( ; dp <= ol->contours[dn]; dp++ ) + { + kdDebug( PMArea ) << " <" << ol->points[dp].x << ", " + << ol->points[dp].y << ">, " + << ( ( ol->tags[dp] & 1 ) == 1 ) << " " + << ( ( ol->tags[dp] & 2 ) == 2 ) << endl; + } + } + */ + +#endif + + for( n = 0; n < m_contours; n++ ) + { + PMSegmentList os; + PMSplineSegment s; + bool segmentCreated = false; + bool quadricSpecialCase = false; + bool contourEnd = false; + int firstPoint = p; + + si = 0; + + for( ; !contourEnd; p++, si++ ) + { + segmentCreated = false; + quadricSpecialCase = false; + + // last point = first point + if( p > ol->contours[n] ) + { + p = firstPoint; + contourEnd = true; + } + + // scale the point + v[si] = PMVector( ( double ) ol->points[p].x / dfh - horiBearing, + ( double ) ol->points[p].y / dfh ); + // point type + onPoint[si] = ( ( ol->tags[p] & 1 ) == 1 ); + cubic[si] = ( ( ol->tags[p] & 2 ) == 2 ); + + if( onPoint[si] ) + { + switch( si ) + { + case 0: + break; + case 1: + // line + s.calculateLinear( v[0], v[1] ); + segmentCreated = true; + break; + case 2: + // quadric bezier + s.calculateQuadricBezier( v[0], v[1], v[2] ); + segmentCreated = true; + break; + case 3: + // cubic bezier + s.calculateBezier( v[0], v[1], v[2], v[3] ); + segmentCreated = true; + break; + default: + kdError( PMArea ) << "Glyph outline seems incorrect. No on point.\n"; + si = 0; + break; + } + } + else if( ( si == 2 ) && ( !cubic[si] ) ) + { + // two quadric off points + // add an on point between them + v[3] = v[2]; + onPoint[3] = onPoint[2]; + cubic[3] = cubic[2]; + v[2] = ( v[1] + v[3] ) / 2.0; + onPoint[2] = true; + + s.calculateQuadricBezier( v[0], v[1], v[2] ); + segmentCreated = true; + quadricSpecialCase = true; + } + + if( segmentCreated ) + { + os.append( s ); + v[0] = v[si]; + onPoint[0] = true; + si = 0; + + if( quadricSpecialCase ) + { + v[1] = v[3]; + onPoint[1] = onPoint[3]; + cubic[1] = onPoint[3]; + si++; + } + } + } + + m_outline.append( os ); + m_segments += os.count( ); + p = ol->contours[n] + 1; + } +} + +#else //!HAVE_FREETYPE + +//*********************************************************************** +// Part without freetype support +//*********************************************************************** + +PMTrueTypeCache::PMTrueTypeCache( ) +{ +} + +PMTrueTypeFont* PMTrueTypeCache::font( const QString& ) +{ + return 0; +} + +PMTrueTypeFont::PMTrueTypeFont( ) +{ +} + +bool PMTrueTypeFont::isValid( ) +{ + return false; +} + +PMTrueTypeOutline* PMTrueTypeFont::outline( QChar ) +{ + return 0; +} + +double PMTrueTypeFont::kerning( QChar, QChar ) +{ + return 0; +} + +#endif //HAVE_FREETYPE diff --git a/kpovmodeler/pmtruetypecache.h b/kpovmodeler/pmtruetypecache.h new file mode 100644 index 00000000..b305cb1c --- /dev/null +++ b/kpovmodeler/pmtruetypecache.h @@ -0,0 +1,194 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMTRUETYPECACHE_H +#define PMTRUETYPECACHE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmsplinesegment.h" + +#include +#include + +#ifdef HAVE_FREETYPE +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H +#include FT_OUTLINE_H +#endif + +class PMTrueTypeFont; + +/** + * Cache for truetype fonts + */ +class PMTrueTypeCache +{ +public: + /** + * Returns a pointer to the font with file name "file" or 0, if the + * font does not exist or is no truetype font + * + * Returns 0 if freetype is not available. + */ + static PMTrueTypeFont* font( const QString& file ); + +#ifdef HAVE_FREETYPE + + /** + * Destructor + */ + ~PMTrueTypeCache( ); + +private: + static PMTrueTypeCache* s_pInstance; + static KStaticDeleter s_staticDeleter; + + /** + * Lookup function + */ + PMTrueTypeFont* lookUp( const QString& file ); + + QCache m_cache; + FT_Library m_library; + +#endif //HAVE_FREETYPE + +private: + /** + * Standard constructor + */ + PMTrueTypeCache( ); +}; + +/** + * Class that represents a truetype character outline + */ +class PMTrueTypeOutline +{ +public: +#ifdef HAVE_FREETYPE + /** + * Constructor that generates the outline for the glyph. + * The outline is scaled to match the font height. + */ + PMTrueTypeOutline( FT_OutlineGlyph glyph, FT_Face face ); +#else + /** + * Standard constructor. + * + * Don't use this constructor. It is only added as dummy if freetype + * is not installed. + */ + PMTrueTypeOutline( ) + { + m_contours = 0; + m_segments = 0; + m_advance = 0; + } +#endif + /** + * Returns the outline + */ + const PMSegmentListList& outline( ) const { return m_outline; } + /** + * Returns the number of contours + */ + int contours( ) const { return m_contours; } + /** + * Returns the sum of the number of segments for all contours + */ + int segments( ) const { return m_segments; } + /** + * Returns the offset for the next character + */ + double advance( ) const { return m_advance; } + + PMSegmentListList m_outline; + int m_contours; + int m_segments; + double m_advance; +}; + +/** + * Class that represents a truetype font. + * + * This class caches the glyph outlines. + */ +class PMTrueTypeFont +{ +public: + /** + * Returns the outline for the character + * + * Returns 0 if there is no glyph for the character or the font is + * not a valid, scalable true type font. + */ + PMTrueTypeOutline* outline( QChar c ); + /** + * Returns true if the font is a valid, scalable true type font + */ + bool isValid( ); + /** + * Returns the kerning offset for the two characters + */ + double kerning( QChar c1, QChar c2 ); + +#ifdef HAVE_FREETYPE + +public: + /** + * Creates a true type font + */ + PMTrueTypeFont( FT_Library lib, FT_Face face ); + /** + * Deletes the true type font + */ + ~PMTrueTypeFont( ); + +private: + FT_UInt findGlyphIndex( QChar c ); + + FT_Library m_library; + FT_Face m_face; + + bool m_valid; + bool m_validChecked; + bool m_useKerning; + + QCache m_cache; + +#else //!HAVE_FREETYPE + +public: + /** + * Standard constructor. + * + * Don't use this constructor. It is only added as dummy if freetype + * is not installed. + */ + PMTrueTypeFont( ); + +#endif //HAVE_FREETYPE + +}; + +#endif diff --git a/kpovmodeler/pmunknownview.cpp b/kpovmodeler/pmunknownview.cpp new file mode 100644 index 00000000..b6067c02 --- /dev/null +++ b/kpovmodeler/pmunknownview.cpp @@ -0,0 +1,37 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmunknownview.h" +#include +#include + +PMUnknownView::PMUnknownView( const QString& viewType, + QWidget* parent, const char* name ) + : PMViewBase( parent, name ) +{ + QHBoxLayout* hl = new QHBoxLayout( this ); + QLabel* l; + l = new QLabel( i18n( "Unknown view type \"%1\"" ).arg( viewType ), this ); + l->setAlignment( Qt::AlignCenter ); + hl->addWidget( l ); + m_viewType = viewType; +} + +QString PMUnknownView::description( ) const +{ + return i18n( "Unknown" ); +} diff --git a/kpovmodeler/pmunknownview.h b/kpovmodeler/pmunknownview.h new file mode 100644 index 00000000..b8921dd6 --- /dev/null +++ b/kpovmodeler/pmunknownview.h @@ -0,0 +1,47 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMUNKNOWNVIEW_H +#define PMUNKNOWNVIEW_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include "pmviewbase.h" + +/** + * Helper view for unknown view types + */ +class PMUnknownView : public PMViewBase +{ +public: + /** + * Default constructor + */ + PMUnknownView( const QString& viewType, QWidget* parent, + const char* name = 0 ); + /** */ + virtual QString viewType( ) const { return m_viewType; } + /** */ + virtual QString description( ) const; +private: + QString m_viewType; +}; + +#endif diff --git a/kpovmodeler/pmvalue.h b/kpovmodeler/pmvalue.h new file mode 100644 index 00000000..3d2ecb02 --- /dev/null +++ b/kpovmodeler/pmvalue.h @@ -0,0 +1,102 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMVALUE_H +#define PMVALUE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmvector.h" + +enum PMValueType { PMVFloat, PMVVector, PMVColor }; + +/** + * Helper class for parsing numeric expressions because wo don't know + * at begin of an expression, which type it is. + * + * Colors are stored as 5D vectors. + */ + +class PMValue +{ +public: + /** + * Creates a PMValue with type PMVFloat and value 0.0 + */ + PMValue( ) : m_v( 0 ) { m_d = 0.0; m_type = PMVFloat; } + /** + * Copy constructor + */ + PMValue( const PMValue& v ) + { + m_type = v.m_type; + m_d = v.m_d; + m_v = v.m_v; + } + /** + * Returns the type of the value. + * Values can be PMVFloat, PMVVector, PMVColor + */ + PMValueType type( ) const { return m_type; } + + /** + * Sets the float value and sets the type to PMVFloat + */ + void setFloat( const double d ) { m_d = d; m_type = PMVFloat; } + /** + * Sets the vector value and sets the type to PMVVector + */ + void setVector( const PMVector& v ) { m_v = v; m_type = PMVVector; } + /** + * Sets the color value and sets the type to PMVColor + */ + void setColor( const PMVector& v ) { m_v = v; m_type = PMVColor; } + + /** + * Returns the float value + */ + double floatValue( ) const { return m_d; } + /** + * Returns the vector value + */ + PMVector vector( ) const { return m_v; } + /** + * Returns the color value + */ + PMVector color( ) const { return m_v; } + /** + * Assigns v to the value + */ + PMValue& operator= ( const PMValue& v ) + { + m_type = v.m_type; + m_d = v.m_d; + m_v = v.m_v; + return *this; + } + +private: + PMValueType m_type; + double m_d; + PMVector m_v; +}; + +#endif diff --git a/kpovmodeler/pmvariant.cpp b/kpovmodeler/pmvariant.cpp new file mode 100644 index 00000000..d6b5384c --- /dev/null +++ b/kpovmodeler/pmvariant.cpp @@ -0,0 +1,920 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmvariant.h" + +#include +#include "pmcolor.h" +#include "pmvector.h" +#include "pmdebug.h" + +inline const char* dcopTypeName( const PMVariant& ) { return "PMVariant"; } + +PMVariant::PMVariant( ) +{ + m_dataType = PMVariant::None; + m_pData = 0; +} + +PMVariant::PMVariant( int data ) +{ + m_dataType = PMVariant::Integer; + m_pData = new int( data ); +} + +PMVariant::PMVariant( unsigned int data ) +{ + m_dataType = PMVariant::Unsigned; + m_pData = new unsigned( data ); +} + +PMVariant::PMVariant( double data ) +{ + m_dataType = PMVariant::Double; + m_pData = new double( data ); +} + + +PMVariant::PMVariant( bool data ) +{ + m_dataType = PMVariant::Bool; + m_pData = new bool( data ); +} + +PMVariant::PMVariant( PMThreeState data ) +{ + m_dataType = PMVariant::ThreeState; + m_pData = new PMThreeState( data ); +} + + +PMVariant::PMVariant( const QString& data ) +{ + m_dataType = PMVariant::String; + m_pData = new QString( data ); +} + +PMVariant::PMVariant( const PMVector& data ) +{ + m_dataType = PMVariant::Vector; + m_pData = new PMVector( data ); +} + +PMVariant::PMVariant( const PMColor& data ) +{ + m_dataType = PMVariant::Color; + m_pData = new PMColor( data ); +} + +PMVariant::PMVariant( PMObject* obj ) +{ + m_dataType = PMVariant::ObjectPointer; + m_pData = ( void* ) obj; +} + +PMVariant::PMVariant( const PMVariant& v ) +{ + m_pData = 0; + m_dataType = PMVariant::None; + + switch( v.m_dataType ) + { + case PMVariant::Integer: + setInt( *( ( int* ) v.m_pData ) ); + break; + case PMVariant::Unsigned: + setUnsigned( *( ( unsigned* ) v.m_pData ) ); + break; + case PMVariant::Double: + setDouble( *( ( double* ) v.m_pData ) ); + break; + case PMVariant::Bool: + setBool( *( ( bool* ) v.m_pData ) ); + break; + case PMVariant::ThreeState: + setThreeState( *( ( PMThreeState* ) v.m_pData ) ); + break; + case PMVariant::String: + setString( *( ( QString* ) v.m_pData ) ); + break; + case PMVariant::Vector: + setVector( *( ( PMVector* ) v.m_pData ) ); + break; + case PMVariant::Color: + setColor( *( ( PMColor* ) v.m_pData ) ); + break; + case PMVariant::ObjectPointer: + setObject( ( PMObject* ) v.m_pData ); + break; + case PMVariant::None: + break; + } +} + +PMVariant& PMVariant::operator= ( const PMVariant& v ) +{ + switch( v.m_dataType ) + { + case PMVariant::Integer: + setInt( *( ( int* ) v.m_pData ) ); + break; + case PMVariant::Unsigned: + setUnsigned( *( ( unsigned* ) v.m_pData ) ); + break; + case PMVariant::Double: + setDouble( *( ( double* ) v.m_pData ) ); + break; + case PMVariant::Bool: + setBool( *( ( bool* ) v.m_pData ) ); + break; + case PMVariant::ThreeState: + setThreeState( *( ( PMThreeState* ) v.m_pData ) ); + break; + case PMVariant::String: + setString( *( ( QString* ) v.m_pData ) ); + break; + case PMVariant::Vector: + setVector( *( ( PMVector* ) v.m_pData ) ); + break; + case PMVariant::Color: + setColor( *( ( PMColor* ) v.m_pData ) ); + break; + case PMVariant::ObjectPointer: + setObject( ( PMObject* ) v.m_pData ); + break; + case PMVariant::None: + break; + } + + return *this; +} + +PMVariant::~PMVariant( ) +{ + clear( ); +} + +void PMVariant::clear( ) +{ + switch( m_dataType ) + { + case PMVariant::Integer: + delete( ( int* ) m_pData ); + break; + case PMVariant::Unsigned: + delete( ( unsigned* ) m_pData ); + break; + case PMVariant::Double: + delete( ( double* ) m_pData ); + break; + case PMVariant::Bool: + delete( ( bool* ) m_pData ); + break; + case PMVariant::ThreeState: + delete( ( PMThreeState* ) m_pData ); + break; + case PMVariant::String: + delete( ( QString* ) m_pData ); + break; + case PMVariant::Vector: + delete( ( PMVector* ) m_pData ); + break; + case PMVariant::Color: + delete( ( PMColor* ) m_pData ); + break; + case PMVariant::ObjectPointer: + // delete nothing + break; + case PMVariant::None: + break; + } + + m_dataType = PMVariant::None; + m_pData = 0; +} + +void PMVariant::setInt( const int data ) +{ + if( m_dataType != PMVariant::Integer ) + { + clear( ); + m_pData = new int( data ); + m_dataType = PMVariant::Integer; + } + else + *( ( int* ) m_pData ) = data; +} + +void PMVariant::setUnsigned( const unsigned int data ) +{ + if( m_dataType != PMVariant::Unsigned ) + { + clear( ); + m_pData = new unsigned( data ); + m_dataType = PMVariant::Unsigned; + } + else + *( ( unsigned* ) m_pData ) = data; +} + +void PMVariant::setDouble( const double data ) +{ + if( m_dataType != PMVariant::Double ) + { + clear( ); + m_pData = new double( data ); + m_dataType = PMVariant::Double; + } + else + *( ( double* ) m_pData ) = data; +} + +void PMVariant::setBool( const bool data ) +{ + if( m_dataType != PMVariant::Bool ) + { + clear( ); + m_pData = new bool( data ); + m_dataType = PMVariant::Bool; + } + else + *( ( bool* ) m_pData ) = data; +} + +void PMVariant::setThreeState( const PMThreeState data ) +{ + if( m_dataType != PMVariant::ThreeState ) + { + clear( ); + m_pData = new PMThreeState( data ); + m_dataType = PMVariant::ThreeState; + } + else + *( ( PMThreeState* ) m_pData ) = data; +} + +void PMVariant::setString( const QString& data ) +{ + if( m_dataType != PMVariant::String ) + { + clear( ); + m_pData = new QString( data ); + m_dataType = PMVariant::String; + } + else + *( ( QString* ) m_pData ) = data; +} + +void PMVariant::setVector( const PMVector& data ) +{ + if( m_dataType != PMVariant::Vector ) + { + clear( ); + m_pData = new PMVector( data ); + m_dataType = PMVariant::Vector; + } + else + *( ( PMVector* ) m_pData ) = data; +} + +void PMVariant::setColor( const PMColor& data ) +{ + if( m_dataType != PMVariant::Color ) + { + clear( ); + m_pData = new PMColor( data ); + m_dataType = PMVariant::Color; + } + else + *( ( PMColor* ) m_pData ) = data; +} + +void PMVariant::setObject( PMObject* obj ) +{ + if( m_dataType != PMVariant::ObjectPointer ) + { + clear( ); + m_pData = obj; + m_dataType = PMVariant::ObjectPointer; + } + else + m_pData = obj; +} + +int PMVariant::intData( ) const +{ + if( m_dataType == PMVariant::Integer ) + return *( ( int* ) m_pData ); + kdError( PMArea ) << "Wrong type in PMVariant get function\n"; + return 0; +} + +int PMVariant::unsignedData( ) const +{ + if( m_dataType == PMVariant::Unsigned ) + return *( ( unsigned* ) m_pData ); + kdError( PMArea ) << "Wrong type in PMVariant get function\n"; + return 0; +} + +double PMVariant::doubleData( ) const +{ + if( m_dataType == PMVariant::Double ) + return *( ( double* ) m_pData ); + kdError( PMArea ) << "Wrong type in PMVariant get function\n"; + return 0; +} + +bool PMVariant::boolData( ) const +{ + if( m_dataType == PMVariant::Bool ) + return *( ( bool* ) m_pData ); + kdError( PMArea ) << "Wrong type in PMVariant get function\n"; + return false; +} + +PMThreeState PMVariant::threeStateData( ) const +{ + if( m_dataType == PMVariant::ThreeState ) + return *( ( PMThreeState* ) m_pData ); + kdError( PMArea ) << "Wrong type in PMVariant get function\n"; + return PMUnspecified; +} + +QString PMVariant::stringData( ) const +{ + if( m_dataType == PMVariant::String ) + return *( ( QString* ) m_pData ); + kdError( PMArea ) << "Wrong type in PMVariant get function\n"; + return QString::null; +} + +PMVector PMVariant::vectorData( ) const +{ + if( m_dataType == PMVariant::Vector ) + return *( ( PMVector* ) m_pData ); + kdError( PMArea ) << "Wrong type in PMVariant get function\n"; + return PMVector( ); +} + +PMColor PMVariant::colorData( ) const +{ + if( m_dataType == PMVariant::Color ) + return *( ( PMColor* ) m_pData ); + kdError( PMArea ) << "Wrong type in PMVariant get function\n"; + return PMColor( ); +} + +PMObject* PMVariant::objectData( ) const +{ + if( m_dataType == PMVariant::ObjectPointer ) + return ( PMObject* ) m_pData; + kdError( PMArea ) << "Wrong type in PMVariant get function\n"; + return 0; +} + +bool PMVariant::convertTo( PMVariant::PMVariantDataType t ) +{ + bool success = true; + + switch( m_dataType ) + { + case PMVariant::Integer: + { + int data = *( ( int* ) m_pData ); + + switch( t ) + { + case PMVariant::Integer: + break; + case PMVariant::Unsigned: + setUnsigned( ( unsigned ) data ); + break; + case PMVariant::Double: + setDouble( ( double ) data ); + break; + case PMVariant::Bool: + setBool( ( bool ) data ); + break; + case PMVariant::ThreeState: + success = false; + break; + case PMVariant::String: + { + QString tmp; + tmp.setNum( data ); + setString( tmp ); + break; + } + case PMVariant::Vector: + success = false; + break; + case PMVariant::Color: + success = false; + break; + case PMVariant::ObjectPointer: + success = false; + break; + case PMVariant::None: + success = false; + break; + } + break; + } + + case PMVariant::Unsigned: + { + unsigned data = *( ( unsigned* ) m_pData ); + + switch( t ) + { + case PMVariant::Integer: + setUnsigned( ( int ) data ); + break; + case PMVariant::Unsigned: + break; + case PMVariant::Double: + setDouble( ( double ) data ); + break; + case PMVariant::Bool: + setBool( ( bool ) data ); + break; + case PMVariant::ThreeState: + success = false; + break; + case PMVariant::String: + { + QString tmp; + tmp.setNum( data ); + setString( tmp ); + break; + } + case PMVariant::Vector: + success = false; + break; + case PMVariant::Color: + success = false; + break; + case PMVariant::ObjectPointer: + success = false; + break; + case PMVariant::None: + success = false; + break; + } + break; + } + + case PMVariant::Double: + { + double data = *( ( double* ) m_pData ); + + switch( t ) + { + case PMVariant::Integer: + setInt( ( int ) data ); + break; + case PMVariant::Unsigned: + setUnsigned( ( unsigned ) data ); + break; + case PMVariant::Double: + break; + case PMVariant::Bool: + setBool( ( bool ) data ); + break; + case PMVariant::ThreeState: + success = false; + break; + case PMVariant::String: + { + QString tmp; + tmp.setNum( data ); + setString( tmp ); + break; + } + case PMVariant::Vector: + success = false; + break; + case PMVariant::Color: + success = false; + break; + case PMVariant::ObjectPointer: + success = false; + break; + case PMVariant::None: + success = false; + break; + } + break; + } + + case PMVariant::Bool: + { + bool data = *( ( bool* ) m_pData ); + + switch( t ) + { + case PMVariant::Integer: + setInt( ( int ) data ); + break; + case PMVariant::Unsigned: + setUnsigned( ( unsigned ) data ); + break; + case PMVariant::Double: + setDouble( ( double ) data ); + break; + case PMVariant::Bool: + break; + case PMVariant::ThreeState: + if( data ) + setThreeState( PMTrue ); + else + setThreeState( PMFalse ); + break; + case PMVariant::String: + if( data ) + setString( QString( "true" ) ); + else + setString( QString( "false" ) ); + break; + case PMVariant::Vector: + success = false; + break; + case PMVariant::Color: + success = false; + break; + case PMVariant::ObjectPointer: + success = false; + break; + case PMVariant::None: + success = false; + break; + } + break; + } + + case PMVariant::ThreeState: + { + PMThreeState data = *( ( PMThreeState* ) m_pData ); + + switch( t ) + { + case PMVariant::Integer: + success = false; + break; + case PMVariant::Unsigned: + success = false; + break; + case PMVariant::Double: + success = false; + break; + case PMVariant::Bool: + if( data == PMTrue ) + setBool( true ); + else if( data == PMFalse ) + setBool( false ); + else + success = false; + break; + case PMVariant::ThreeState: + break; + case PMVariant::String: + if( data == PMTrue ) + setString( QString( "true" ) ); + else if( data == PMFalse ) + setString( QString( "false" ) ); + else + setString( QString( "unspecified" ) ); + break; + case PMVariant::Vector: + success = false; + break; + case PMVariant::Color: + success = false; + break; + case PMVariant::ObjectPointer: + success = false; + break; + case PMVariant::None: + success = false; + break; + } + break; + } + + case PMVariant::String: + { + QString data = *( ( QString* ) m_pData ); + + switch( t ) + { + case PMVariant::Integer: + { + int i = data.toInt( &success ); + if( success ) + setInt( i ); + break; + } + case PMVariant::Unsigned: + { + unsigned u = data.toUInt( &success ); + if( success ) + setUnsigned( u ); + break; + } + case PMVariant::Double: + { + double d = data.toDouble( &success ); + if( success ) + setDouble( d ); + break; + } + case PMVariant::Bool: + if( data == "true" || data == "on" || data == "yes" ) + setBool( true ); + else if( data == "false" || data == "off" || data == "no" ) + setBool( false ); + else + success = false; + break; + case PMVariant::ThreeState: + if( data == "true" || data == "on" || data == "yes" ) + setThreeState( PMTrue ); + else if( data == "false" || data == "off" || data == "no" ) + setThreeState( PMFalse ); + else if( data == "unspecified" ) + setThreeState( PMUnspecified ); + else + success = false; + break; + case PMVariant::String: + break; + case PMVariant::Vector: + success = false; + break; + case PMVariant::Color: + success = false; + break; + case PMVariant::ObjectPointer: + success = false; + break; + case PMVariant::None: + success = false; + break; + } + break; + } + + case PMVariant::Vector: + { + switch( t ) + { + case PMVariant::Vector: + break; + case PMVariant::Color: + { + PMVector v = *( ( PMVector* ) m_pData ); + if( v.size( ) == 5 ) + setColor( v ); + else + success = false; + break; + } + default: + success = false; + break; + } + break; + } + + case PMVariant::Color: + { + switch( t ) + { + case PMVariant::Vector: + { + PMColor c = *( ( PMColor* ) m_pData ); + PMVector v( 5 ); + v[0] = c.red( ); + v[1] = c.green( ); + v[2] = c.blue( ); + v[3] = c.filter( ); + v[4] = c.transmit( ); + setVector( v ); + break; + } + case PMVariant::Color: + break; + default: + success = false; + break; + } + break; + } + + case PMVariant::ObjectPointer: + success = ( t == PMVariant::ObjectPointer ); + break; + + case PMVariant::None: + success = ( t == PMVariant::None ); + break; + } + + return success; +} + +QString PMVariant::asString( ) const +{ + QString tmp; + + switch( m_dataType ) + { + case PMVariant::Integer: + { + int data = *( ( int* ) m_pData ); + + tmp.setNum( data ); + break; + } + case PMVariant::Unsigned: + { + unsigned data = *( ( unsigned* ) m_pData ); + + tmp.setNum( data ); + break; + } + case PMVariant::Double: + { + double data = *( ( double* ) m_pData ); + + tmp.setNum( data ); + break; + } + case PMVariant::Bool: + { + bool data = *( ( bool* ) m_pData ); + + if( data ) + tmp = "true"; + else + tmp = "false"; + break; + } + case PMVariant::ThreeState: + { + PMThreeState data = *( ( PMThreeState* ) m_pData ); + + if( data == PMTrue ) + tmp = "true"; + else if( data == PMFalse ) + tmp = "false"; + else + tmp = "unspecified"; + break; + } + case PMVariant::String: + { + tmp = *( ( QString* ) m_pData ); + break; + } + case PMVariant::Vector: + { + PMVector v = *( ( PMVector* ) m_pData ); + tmp = v.serializeXML( ); + break; + } + + case PMVariant::Color: + { + PMColor c = *( ( PMColor* ) m_pData ); + tmp = c.serializeXML( ); + break; + } + + case PMVariant::ObjectPointer: + tmp = ""; + break; + + case PMVariant::None: + tmp = ""; + break; + + default: + tmp = ""; + break; + } + + return tmp; +} + +bool PMVariant::fromString( const PMVariant::PMVariantDataType t, const QString& value ) +{ + bool success; + + switch( t ) + { + case PMVariant::Integer: + { + int i = value.toInt( &success ); + if( success ) + setInt( i ); + break; + } + case PMVariant::Unsigned: + { + unsigned u = value.toUInt( &success ); + if( success ) + setUnsigned( u ); + break; + } + case PMVariant::Double: + { + double d = value.toDouble( &success ); + if( success ) + setDouble( d ); + break; + } + case PMVariant::Bool: + success = true; + if( value == "true" || value == "on" || value == "yes" ) + setBool( true ); + else if( value == "false" || value == "off" || value == "no" ) + setBool( false ); + else + success = false; + break; + case PMVariant::ThreeState: + success = true; // Assume success, set to false if we fail. + if( value == "true" || value == "on" || value == "yes" ) + setThreeState( PMTrue ); + else if( value == "false" || value == "off" || value == "no" ) + setThreeState( PMFalse ); + else if( value == "unspecified" ) + setThreeState( PMUnspecified ); + else + success = false; + break; + case PMVariant::String: + setString( value ); + success = true; + break; + case PMVariant::Vector: + { + PMVector v; + v.loadXML( value ); + setVector( v ); + success = true; + break; + } + case PMVariant::Color: + { + PMColor c; + c.loadXML( value ); + setColor( c ); + success = true; + break; + } + default: + success = false; + } + return success; +} + +QDataStream& operator<<( QDataStream& stream, const PMVariant& value ) +{ + stream << (Q_INT8)value.dataType( ); + stream << value.asString( ); + + return stream; +} + +QDataStream& operator>>( QDataStream& stream, PMVariant& value ) +{ + Q_INT8 type; + PMVariant::PMVariantDataType dataType; + QString str; + + stream >> type; + dataType = (PMVariant::PMVariantDataType)type; + + stream >> str; + + value.fromString(dataType, str); + + return stream; +} diff --git a/kpovmodeler/pmvariant.h b/kpovmodeler/pmvariant.h new file mode 100644 index 00000000..01519a01 --- /dev/null +++ b/kpovmodeler/pmvariant.h @@ -0,0 +1,221 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMVARIANT_H +#define PMVARIANT_H + +#include +#include "pmcolor.h" +#include "pmvector.h" +#include "pmthreestate.h" + +class PMObject; + +/** + * Variant class for KPovModeler. + * + * Can store and convert: int, unsigned int, double, bool, + * PMThreeState, QString, PMVector, PMColor, PMObject*. + * + * Enums are stored as QString. + * + * The variant can store one type at a time. You can try to convert + * the type with the convertTo* methods. These will return bool on success. + * If the variant could not be converted, the old type and value + * did not change. + */ + +class PMVariant +{ +public: + /** + * Type of stored data + */ + enum PMVariantDataType { Integer, Unsigned, Double, Bool, + ThreeState, String, Vector, Color, + ObjectPointer, None }; + /** + * Creates an empty variant object + */ + PMVariant( ); + /** + * Stores an integer + */ + PMVariant( int data ); + /** + * Stores an unsigned integer + */ + PMVariant( unsigned int data ); + /** + * Stores a double + */ + PMVariant( double data ); + /** + * Stores a boolean + */ + PMVariant( bool data ); + /** + * Stores a @ref PMThreeState + */ + PMVariant( PMThreeState data ); + /** + * Stores a string + */ + PMVariant( const QString& data ); + /** + * Stores a @ref PMVector + */ + PMVariant( const PMVector& data ); + /** + * Stores a @ref PMColor + */ + PMVariant( const PMColor& data ); + /** + * Stores a pointer to a PMObject + */ + PMVariant( PMObject* obj ); + /** + * Copy constructor + */ + PMVariant( const PMVariant& v ); + /** + * Deletes the variant + */ + ~PMVariant( ); + + /** + * Assignment operator + */ + PMVariant& operator= ( const PMVariant& v ); + + /** + * Returns true if no data is stored + */ + bool isNull( ) const { return !m_pData; } + + /** + * Sets the integer value + */ + void setInt( int data ); + /** + * Sets the unsigned value + */ + void setUnsigned( unsigned int data ); + /** + * Sets the double value + */ + void setDouble( double data ); + /** + * Sets the boolean value + */ + void setBool( bool data ); + /** + * Sets the PMThreeState value + */ + void setThreeState( PMThreeState data ); + /** + * Sets the string data + */ + void setString( const QString& data ); + /** + * Sets the vector data + */ + void setVector( const PMVector& data ); + /** + * Sets the color data + */ + void setColor( const PMColor& data ); + /** + * Sets the object pointer + */ + void setObject( PMObject* o ); + + /** + * Returns the integer value. Data type has to be Integer! + */ + int intData( ) const; + /** + * Returns the unsigned value. Data type has to be Unsigned! + */ + int unsignedData( ) const; + /** + * Returns the double value. Data type has to be Double! + */ + double doubleData( ) const; + /** + * Returns the boolean value. Data type has to be Bool! + */ + bool boolData( ) const; + /** + * Returns the PMThreeState value. Data type has to be ThreeState! + */ + PMThreeState threeStateData( ) const; + /** + * Returns the string data. Data type has to be String! + */ + QString stringData( ) const; + /** + * Returns the vector data. Data type has to be Vector! + */ + PMVector vectorData( ) const; + /** + * Returns the color data. Data type has to be Color! + */ + PMColor colorData( ) const; + /** + * Returns the object pointer. Data type has to be ObjectPointer! + */ + PMObject* objectData( ) const; + + /** + * Converts the variant to an integer. Returns true if possible + */ + bool convertTo( PMVariantDataType t ); + + /** + * Returns the type of the stored data + */ + PMVariantDataType dataType( ) const { return m_dataType; } + + /** + * Returns the value of the stored data in string format + */ + QString asString( ) const; + /** + * Sets the value of the variant based on the string + */ + bool fromString( const PMVariant::PMVariantDataType t, const QString& value ); +private: + void clear( ); + + /** + * a pointer to the stored data + */ + void* m_pData; + /** + * Type of the data + */ + PMVariantDataType m_dataType; +}; + +// Streaming operators for PMVariant +QDataStream& operator<<( QDataStream& stream, const PMVariant& value ); +QDataStream& operator>>( QDataStream& stream, PMVariant& value ); + + +#endif diff --git a/kpovmodeler/pmvector.cpp b/kpovmodeler/pmvector.cpp new file mode 100644 index 00000000..035f0d2b --- /dev/null +++ b/kpovmodeler/pmvector.cpp @@ -0,0 +1,593 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmvector.h" +#include "pmmath.h" +#include "pmmatrix.h" +#include "pmdebug.h" + +#include +#include +#include + +double PMVector::s_dummy = 0; + +double& PMVector::operator[] ( int index ) +{ + if( ( index >= 0 ) && ( index < ( signed ) m_size ) ) + return m_coord[index]; + kdError( PMArea ) << "Bad index in PMVector operator []\n"; + return s_dummy; +} + +const double& PMVector::operator[] ( int index ) const +{ + if( ( index >= 0 ) && ( index < ( signed ) m_size ) ) + return m_coord[index]; + kdError( PMArea ) << "Bad index in PMVector operator []\n"; + return s_dummy; +} + +void PMVector::allocateMemory( unsigned int size ) +{ + m_size = size; + + if( m_size == 0 ) + m_coord = 0; + else + m_coord = ( double* ) malloc( sizeof( double ) * m_size ); +} + +PMVector::PMVector( const PMVector& v ) +{ + unsigned int i; + allocateMemory( v.m_size ); + + for( i = 0; i < m_size; i++ ) + m_coord[i] = v.m_coord[i]; +} + +PMVector::PMVector( ) +{ + unsigned int i; + + allocateMemory( 3 ); + + for( i = 0; i < 3; i++ ) + m_coord[i] = 0.0; +} + +PMVector::PMVector( unsigned int s ) +{ + unsigned int i; + + allocateMemory( s ); + + for( i = 0; i < s; i++ ) + m_coord[i] = 0.0; +} + +PMVector::PMVector( const double x, const double y ) +{ + allocateMemory( 2 ); + + m_coord[0] = x; + m_coord[1] = y; +} + +PMVector::PMVector( const double x, const double y, const double z ) +{ + allocateMemory( 3 ); + + m_coord[0] = x; + m_coord[1] = y; + m_coord[2] = z; +} + +PMVector::PMVector( const double x, const double y, const double z, + const double t ) +{ + allocateMemory( 4 ); + + m_coord[0] = x; + m_coord[1] = y; + m_coord[2] = z; + m_coord[3] = t; +} + +PMVector::~PMVector( ) +{ + if( m_coord ) + free( m_coord ); +} + + +void PMVector::resize( unsigned int s ) +{ + unsigned int i; + + if( s != m_size ) + { + m_coord = ( double* ) realloc( m_coord, sizeof( double ) * s ); + + for( i = m_size; i < s; i++ ) + m_coord[i] = 0.0; + + if( m_coord ) + m_size = s; + else + m_size = 0; // possibly out of memory + } +} + +void PMVector::transform( const PMMatrix& m ) +{ + (*this) = m * (*this); +} + +PMVector& PMVector::operator= ( const PMVector& p ) +{ + unsigned int i; + + resize( p.m_size ); + for( i = 0; i < m_size; i++ ) + m_coord[i] = p[i]; + return *this; +} + +PMVector& PMVector::operator= ( const double d ) +{ + unsigned int i; + + for( i = 0; i < m_size; i++ ) + m_coord[i] = d; + return *this; +} + +PMVector& PMVector::operator*= ( const PMVector& p ) +{ + unsigned int i; + + if( m_size != p.m_size ) + resize( p.m_size ); + + for( i = 0; i < m_size; i++ ) + m_coord[i] *= p[i]; + + return *this; +} + +PMVector& PMVector::operator/= ( const PMVector& p ) +{ + unsigned int i; + + if( m_size > p.m_size ) + { + kdError( PMArea ) << "Vector p is too small in PMVector& PMVector::operator/= ( const PMVector& p )\n"; + } + else + { + for( i = 0; i < m_size; i++ ) + { + if( approxZero( p[i] ) ) + kdError( PMArea ) << "Division by zero in PMVector::operator/= " << "\n"; + else + m_coord[i] *= p[i]; + } + } + + return *this; +} + +PMVector& PMVector::operator*= ( double d ) +{ + unsigned int i; + + for( i = 0; i < m_size; i++ ) + m_coord[i] *= d; + + return *this; +} + +PMVector& PMVector::operator/= ( double d ) +{ + if( approxZero( d ) ) + { + kdError( PMArea ) << "Division by zero in PMVector::operator/= " << "\n"; + } + else + { + unsigned int i; + + for( i = 0; i < m_size; i++ ) + m_coord[i] /= d; + } + + return *this; +} + +PMVector& PMVector::operator+= ( double d ) +{ + unsigned int i; + + for( i = 0; i < m_size; i++ ) + m_coord[i] += d; + + return *this; +} + +PMVector& PMVector::operator-= ( double d ) +{ + unsigned int i; + + for( i = 0; i < m_size; i++ ) + m_coord[i] -= d; + + return *this; +} + +PMVector& PMVector::operator+= ( const PMVector& p ) +{ + unsigned int i; + + if( m_size < p.m_size ) + resize( p.m_size ); + + for( i = 0; i < p.m_size; i++ ) + m_coord[i] += p[i]; + + return *this; +} + +PMVector& PMVector::operator-= ( const PMVector& p ) +{ + unsigned int i; + + if( m_size < p.m_size ) + resize( p.m_size ); + + for( i = 0; i < m_size; i++ ) + m_coord[i] -= p[i]; + + return *this; +} + +PMVector operator- ( const PMVector& p ) +{ + PMVector result( p.m_size ); + unsigned int i; + + for( i = 0; i < p.m_size; i++ ) + result[i] = -p[i]; + + return result; +} + +PMVector operator+ ( const PMVector& p1, const PMVector& p2 ) +{ + PMVector result( p1 ); + result += p2; + + return result; +} + +PMVector operator- ( const PMVector& p1, const PMVector& p2 ) +{ + PMVector result( p1 ); + result -= p2; + + return result; +} + +PMVector operator* ( const PMVector& p, const double d ) +{ + PMVector result( p.m_size ); + unsigned int i; + + for( i = 0; i < p.m_size; i++ ) + result[i] = p[i] * d; + + return result; +} + +PMVector operator/ ( const PMVector& p, const double d ) +{ + PMVector result( p.m_size ); + unsigned int i; + + if( approxZero( d ) ) + kdError( PMArea ) << "Division by zero in PMVector::operator/ ( PMVector& p, double d ) " << "\n"; + else + for( i = 0; i < p.m_size; i++ ) + result[i] = p[i] / d; + + return result; +} + +PMVector operator+ ( const PMVector& p, const double d ) +{ + PMVector result( p.m_size ); + unsigned int i; + + for( i = 0; i < p.m_size; i++ ) + result[i] = p[i] + d; + + return result; +} + +PMVector operator- ( const PMVector& p, const double d ) +{ + PMVector result( p.m_size ); + unsigned int i; + + for( i = 0; i < p.m_size; i++ ) + result[i] = p[i] - d; + + return result; +} + +PMVector operator* ( const double d, const PMVector& p ) +{ + PMVector result( p.m_size ); + unsigned int i; + + for( i = 0; i < p.m_size; i++ ) + result[i] = p[i] * d; + + return result; +} + +PMVector operator* ( const PMMatrix& m, const PMVector& p ) +{ + PMVector result( 3 ); + int c, i; + // for homogenous coordinates + double u; + + if( p.m_size != 3 ) + kdError( PMArea ) << "Vector has not size 3 in PMVector operator* ( const PMVector& p, const PMMatrix& m ) \n"; + else + { + for( c=0; c<3; c++ ) + { + result[c] = 0.0; + for( i=0; i<4; i++ ) + result[c] += m[i][c] * ( i<3 ? p[i] : 1.0 ); + } + + u = 0.0; + for( i=0; i<4; i++ ) + u += m[i][3] * ( i<3 ? p[i] : 1.0 ); + if( !approxZero( u ) ) + for( i=0; i<3; i++ ) + result[i] /= u; + } + + return result; +} + +PMVector operator* ( const PMVector& p1, const PMVector& p2 ) +{ + PMVector result( p1 ); + result *= p2; + + return result; +} + +PMVector operator/ ( const PMVector& p1, const PMVector& p2 ) +{ + PMVector result( p1 ); + result /= p2; + + return result; +} + +bool PMVector::operator== ( const PMVector& p ) const +{ + unsigned int i; + if( m_size != p.m_size ) + return false; + if( m_size == 0 ) + return true; + + for( i = 0; i < m_size; i++ ) + if( p.m_coord[i] != m_coord[i] ) + return false; + return true; +} + +bool PMVector::approxEqual( const PMVector& p, double epsilon ) const +{ + unsigned int i; + if( m_size != p.m_size ) + return false; + if( m_size == 0 ) + return true; + + for( i = 0; i < m_size; i++ ) + if( ! approx( p.m_coord[i], m_coord[i], epsilon ) ) + return false; + return true; +} + +bool PMVector::operator!= ( const PMVector& p ) const +{ + return !( *this == p ); +} + + +PMVector PMVector::cross( const PMVector& v1, const PMVector& v2 ) +{ + PMVector result; + if( ( v1.size( ) == 3 ) && ( v2.size( ) == 3 ) ) + { + result[0] = v1[1]*v2[2] - v1[2]*v2[1]; + result[1] = v1[2]*v2[0] - v1[0]*v2[2]; + result[2] = v1[0]*v2[1] - v1[1]*v2[0]; + } + else + kdError( PMArea ) << "Wrong sizes in PMVector::cross( )\n"; + + return result; +} + +double PMVector::dot( const PMVector& v1, const PMVector& v2 ) +{ + double result = 0.0; + unsigned int i; + + if( v1.size( ) == v2.size( ) ) + { + for( i = 0; i < v1.size( ); i++ ) + result += v1[i] * v2[i]; + } + else + kdError( PMArea ) << "Wrong sizes in PMVector::dot( )\n"; + + return result; +} + +double PMVector::angle( const PMVector& v1, const PMVector& v2 ) +{ + PMVector cr; + double s, c, n; + double a = 0; + int i; + + if( ( v1.size( ) == 3 ) && ( v2.size( ) == 3 ) ) + { + n = v1.abs( ) * v2.abs( ); + + if( approxZero( n ) ) + a = 0; + else + { + cr = cross( v1, v2 ); + s = cr.abs( ) / n; + + c = 0; + for( i = 0; i < 3; i++ ) + c += v1[i] * v2[i]; + + c = c / n; + + a = pmatan( s, c ); + } + } + else + kdError( PMArea ) << "Wrong sizes in PMVector::angle( )\n"; + + return a; +} + +double PMVector::abs( ) const +{ + unsigned int i; + double a = 0.0; + + for( i = 0; i < m_size; i++ ) + a += m_coord[i] * m_coord[i]; + + return sqrt( a ); +} + +PMVector PMVector::orthogonal( ) const +{ + PMVector result; + double l, rl; + + l = abs( ); + if( approxZero( l ) ) + { + kdError( PMArea ) << "Can't calculate an orthogonal vector from a null vector\n"; + return PMVector( 1, 0, 0 ); + } + + result = cross( (*this) / l, PMVector( 0, 0, 1 ) ); + rl = result.abs( ); + if( rl < 0.001 ) + { + result = cross( (*this) / l, PMVector( 1, 0, 0 ) ); + rl = result.abs( ); + } + return result / rl; +} + +QString PMVector::serialize( ) const +{ + QString result; + QTextStream str( &result, IO_WriteOnly ); + unsigned int i; + + if( m_size > 0 ) + { + str << '<'; + for( i = 0; i < m_size; i++ ) + { + if( i > 0 ) + str << ", "; + str << m_coord[i]; + } + str << '>'; + } + else + kdError( PMArea ) << "Can't serialize a vector with size 0\n"; + + return result; +} + +QString PMVector::serializeXML( ) const +{ + QString result; + QTextStream str( &result, IO_WriteOnly ); + unsigned int i; + + if( m_size > 0 ) + { + for( i = 0; i < m_size; i++ ) + { + if( i > 0 ) + str << ' '; + str << m_coord[i]; + } + } + else + kdError( PMArea ) << "Can't serialize a vector with size 0\n"; + + return result; +} + +bool PMVector::loadXML( const QString& str ) +{ + int i; + int size = str.contains( ' ' ) + 1; + QString tmp( str ); + QTextStream s( &tmp, IO_ReadOnly ); + QString val; + bool ok; + + resize( size ); + for( i = 0; i < size; i++ ) + { + s >> val; + m_coord[i] = val.toDouble( &ok ); + if( !ok ) + return false; + } + return true; +} diff --git a/kpovmodeler/pmvector.h b/kpovmodeler/pmvector.h new file mode 100644 index 00000000..6794d02a --- /dev/null +++ b/kpovmodeler/pmvector.h @@ -0,0 +1,275 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMVECTOR_H +#define PMVECTOR_H + +#include +#include + +class PMMatrix; + +/** + * Class for vectors with variable size + */ +class PMVector +{ +public: + /** + * Creates a vector with size s. All values are set to 0 + */ + PMVector( unsigned int s ); + /** + * Creates a vector with size 3. All values are set to 0 + */ + PMVector( ); + /** + * Creates a vector with coordinates [x,y] + */ + PMVector( const double x, const double y ); + /** + * Creates a vector with coordinates [x,y,z] + */ + PMVector( const double x, const double y, const double z ); + /** + * Creates a vector with coordinates [x,y,z,t] + */ + PMVector( const double x, const double y, const double z, const double t ); + /** + * Copy constructor. Creates a deep copy. + */ + PMVector( const PMVector& v ); + /** + * Deletes the vector + */ + ~PMVector( ); + + /** + * Returns the size of the vector + */ + unsigned int size( ) const { return m_size; } + /** + * Resizes the vector. New elements are initialized with 0 + */ + void resize( unsigned int size ); + /** + * Returns a reference to a coordinate, 0:x, 1:y, 2:z + */ + double& operator[] ( int index ); + /** + * Returns a reference to a coordinate, 0:x, 1:y, 2:z + */ + const double& operator[] ( int index ) const; + + /** + * Returns the x coordinate + */ + double x( ) const { return (*this)[0]; } + /** + * Returns the y coordinate + */ + double y( ) const { return (*this)[1]; } + /** + * Returns the z coordinate + */ + double z( ) const { return (*this)[2]; } + /** + * Returns the t coordinate + */ + double t( ) const { return (*this)[3]; } + + /** + * Sets the x coordinate + */ + void setX( const double d ) { (*this)[0] = d; } + /** + * Sets the y coordinate + */ + void setY( const double d ) { (*this)[1] = d; } + /** + * Sets the z coordinate + */ + void setZ( const double d ) { (*this)[2] = d; } + /** + * Sets the x coordinate + */ + void setT( const double d ) { (*this)[3] = d; } + + /** + * Transforms the point with the matrix m. Same as p = m * p + * + * size must be 3! + */ + void transform( const PMMatrix& m ); + + /** + * Assigns p to the vector. Resizes the vector if necessary. + */ + PMVector& operator= ( const PMVector& p ); + /** + * Sets all values to d + */ + PMVector& operator= ( const double d ); + + /** + * Multiplies all coordinates with d + */ + PMVector& operator*= ( double d ); + /** + * Divides all coordinates through d + */ + PMVector& operator/= ( double d ); + /** + * Adds d to all coordinates + */ + PMVector& operator+= ( double d ); + /** + * Subtracts d from all coordinates + */ + PMVector& operator-= ( double d ); + + /** + * Multiplies the vectors ( ...) + */ + PMVector& operator*= ( const PMVector& p ); + /** + * Divides the vectors ( ...) + */ + PMVector& operator/= ( const PMVector& p ); + + /** + * Adds p to the point. + */ + PMVector& operator+= ( const PMVector& p ); + /** + * Subtracts p from the point. + */ + PMVector& operator-= ( const PMVector& p ); + + /** + * Returns a point with negated coordinates + */ + friend PMVector operator- ( const PMVector& p ); + /** + * Adds the two points + */ + friend PMVector operator+ ( const PMVector& p1, const PMVector& p2 ); + /** + * Subtracts p2 from p1 + */ + friend PMVector operator- ( const PMVector& p1, const PMVector& p2 ); + + /** + * Multiplies all coordinates with d + */ + friend PMVector operator* ( const PMVector& p, const double d ); + /** + * Divides all coordinates by d + */ + friend PMVector operator/ ( const PMVector& p, const double d ); + /** + * Adds d to all coordinates + */ + friend PMVector operator+ ( const PMVector& p, const double d ); + /** + * Subtracts d from all coordinates + */ + friend PMVector operator- ( const PMVector& p, const double d ); + + /** + * Multiplies all coordinates with d + */ + friend PMVector operator* ( const double d, const PMVector& p ); + /** + * Multiplies the vectors ( ...) + */ + friend PMVector operator* ( const PMVector& p1, const PMVector& p2 ); + /** + * Divides the vectors ( ...) + */ + friend PMVector operator/ ( const PMVector& p1, const PMVector& p2 ); + /** + * Transforms the point p with the matrix m + * @see transform + */ + friend PMVector operator* ( const PMMatrix& m, const PMVector& p ); + + /** + * Returns true if the vectors have the same size and values + */ + bool operator== ( const PMVector& p ) const; + /** + * Returns false if the vectors have the same size and values + */ + bool operator!= ( const PMVector& p ) const; + + /** + * Returns true if the vectors have the same size and values + */ + bool approxEqual( const PMVector& p, double epsilon = 1e-6 ) const; + + /** + * Returns the cross product of v1 and v2 + * + * Size of v1 and v2 has to be 3! + */ + static PMVector cross( const PMVector& v1, const PMVector& v2 ); + /** + * Returns the dot product of v1 and v2 + */ + static double dot( const PMVector& v1, const PMVector& v2 ); + + /** + * Returns the angle between v1 and v2 + * + * Size of v1 and v2 has to be 3! + */ + static double angle( const PMVector& v1, const PMVector& v2 ); + + /** + * Returns the length of the vector + */ + double abs( ) const; + + /** + * Returns a normalized vector that is orthogonal to this vector + */ + PMVector orthogonal( ) const; + + /** + * Returns a string for serialization + */ + QString serialize( ) const; + /** + * Returns a string for xml output + */ + QString serializeXML( ) const; + /** + * loads the vector data from the xml string + */ + bool loadXML( const QString& str ); +private: + void allocateMemory( unsigned int size ); + + double* m_coord; + static double s_dummy; + unsigned int m_size; +}; + +#endif diff --git a/kpovmodeler/pmvectorcontrolpoint.cpp b/kpovmodeler/pmvectorcontrolpoint.cpp new file mode 100644 index 00000000..0a14d0b8 --- /dev/null +++ b/kpovmodeler/pmvectorcontrolpoint.cpp @@ -0,0 +1,89 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmvectorcontrolpoint.h" +#include "pmmath.h" +#include + +PMVectorControlPoint::PMVectorControlPoint( PMControlPoint* base, + const PMVector& v, int id, + const QString& description, + bool extraLine, bool normalize ) + : PMControlPoint( id, description ) +{ + m_vector = v; + m_pBasePoint = base; + m_extraLine = extraLine; + m_normalize = normalize; +} + +PMVectorControlPoint::PMVectorControlPoint( const PMVector& base, + const PMVector& v, int id, + const QString& description, + bool extraLine, bool normalize ) + : PMControlPoint( id, description ) +{ + m_vector = v; + m_constBasePoint = base; + m_pBasePoint = 0; + m_extraLine = extraLine; + m_normalize = normalize; +} + +PMVector PMVectorControlPoint::position( ) const +{ + return basePoint( ) + m_vector; +} + +PMVector PMVectorControlPoint::basePoint( ) const +{ + if( m_pBasePoint ) + return m_pBasePoint->position( ); + return m_constBasePoint; +} + +void PMVectorControlPoint::graphicalChangeStarted( ) +{ + m_originalVector = m_vector; +} + +void PMVectorControlPoint::graphicalChange( const PMVector& startPoint, + const PMVector& /*viewNormal*/, + const PMVector& endPoint ) +{ + double d; + + m_vector = m_originalVector + endPoint - startPoint; + if( m_normalize ) + { + d = m_vector.abs( ); + if( approxZero( d ) ) + m_vector = m_originalVector; + else + m_vector /= d; + } +} + +void PMVectorControlPoint::snapToGrid( ) +{ + int i; + double d = moveGrid( ); + if( !approxZero( d ) ) + for( i = 0; i < 3; i++ ) + m_vector[i] = rint( m_vector[i] / d ) * d; + setChanged( ); +} diff --git a/kpovmodeler/pmvectorcontrolpoint.h b/kpovmodeler/pmvectorcontrolpoint.h new file mode 100644 index 00000000..92713bc6 --- /dev/null +++ b/kpovmodeler/pmvectorcontrolpoint.h @@ -0,0 +1,101 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMVECTORCONTROLPOINT_H +#define PMVECTORCONTROLPOINT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + + +#include "pmcontrolpoint.h" + +/** + * Class for vector like control points + */ +class PMVectorControlPoint : public PMControlPoint +{ +public: + /** + * Creates a PMVectorControlPoint with id. + * + * The base point of the vector is given by the control point location. + */ + PMVectorControlPoint( PMControlPoint* location, const PMVector& v, + int id, const QString& description, + bool extraLine = true, bool normalize = false ); + /** + * Creates a PMVectorControlPoint with id. + * + * The base point of the vector is given by the vector p. + */ + PMVectorControlPoint( const PMVector& location, const PMVector& v, + int id, const QString& description, + bool extraLine = true, bool normalize = false ); + /** + * Deletes the PMVectorControlPoint + */ + virtual ~PMVectorControlPoint( ) { }; + + /** */ + virtual PMVector position( ) const; + /** + * Returns the base point + */ + PMVector basePoint( ) const; + + /** + * Sets the vector + */ + void setVector( PMVector newVector ) { m_vector = newVector; } + /** + * returns the vector + */ + PMVector vector( ) const { return m_vector; } + + /** */ + virtual bool hasExtraLine( ) const { return m_extraLine; } + /** + * Returns the start point of the extra line + */ + virtual PMVector extraLineStart( ) const { return basePoint( ); } + /** + * Returns the end point of the extra line + */ + virtual PMVector extraLineEnd( ) const { return position( ); } + + /** */ + virtual void snapToGrid( ); + +protected: + /** */ + virtual void graphicalChangeStarted( ); + /** */ + virtual void graphicalChange( const PMVector& startPoint, + const PMVector& viewNormal, + const PMVector& endPoint ); +private: + PMVector m_vector, m_originalVector; + PMControlPoint* m_pBasePoint; + PMVector m_constBasePoint; + bool m_extraLine; + bool m_normalize; +}; + +#endif diff --git a/kpovmodeler/pmvectoredit.cpp b/kpovmodeler/pmvectoredit.cpp new file mode 100644 index 00000000..7264f8f3 --- /dev/null +++ b/kpovmodeler/pmvectoredit.cpp @@ -0,0 +1,235 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmvectoredit.h" +#include "pmdebug.h" +#include +#include +#include +#include +#include +#include + + +PMVectorEdit::PMVectorEdit( const QString& descriptionX, + const QString& descriptionY, + QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + unsigned int i; + QHBoxLayout* layout; + QLabel* label; + + m_edits.resize( 2 ); + for( i = 0; i < 2; i++ ) + { + m_edits.insert( i, new QLineEdit( this ) ); + connect( m_edits[i], SIGNAL( textChanged( const QString& ) ), + SLOT( slotTextChanged( const QString& ) ) ); + } + + layout = new QHBoxLayout( this ); + + if( !descriptionX.isEmpty( ) ) + { + label = new QLabel( descriptionX, this ); + layout->addWidget( label ); + layout->addSpacing( KDialog::spacingHint( ) ); + } + layout->addWidget( m_edits[0] ); + layout->addSpacing( KDialog::spacingHint( ) ); + + if( !descriptionY.isEmpty( ) ) + { + label = new QLabel( descriptionY, this ); + layout->addWidget( label ); + layout->addSpacing( KDialog::spacingHint( ) ); + } + layout->addWidget( m_edits[1] ); +} + +PMVectorEdit::PMVectorEdit( const QString& descriptionX, + const QString& descriptionY, + const QString& descriptionZ, + QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + unsigned int i; + QHBoxLayout* layout; + QLabel* label; + + m_edits.resize( 3 ); + for( i = 0; i < 3; i++ ) + { + m_edits.insert( i, new QLineEdit( this ) ); + connect( m_edits[i], SIGNAL( textChanged( const QString& ) ), + SLOT( slotTextChanged( const QString& ) ) ); + } + + layout = new QHBoxLayout( this ); + + if( !descriptionX.isEmpty( ) ) + { + label = new QLabel( descriptionX, this ); + layout->addWidget( label ); + layout->addSpacing( KDialog::spacingHint( ) ); + } + layout->addWidget( m_edits[0] ); + layout->addSpacing( KDialog::spacingHint( ) ); + + if( !descriptionY.isEmpty( ) ) + { + label = new QLabel( descriptionY, this ); + layout->addWidget( label ); + layout->addSpacing( KDialog::spacingHint( ) ); + } + layout->addWidget( m_edits[1] ); + layout->addSpacing( KDialog::spacingHint( ) ); + + if( !descriptionZ.isEmpty( ) ) + { + label = new QLabel( descriptionZ, this ); + layout->addWidget( label ); + layout->addSpacing( KDialog::spacingHint( ) ); + } + layout->addWidget( m_edits[2] ); +} + +PMVectorEdit::PMVectorEdit( const QString& descriptionA, + const QString& descriptionB, + const QString& descriptionC, + const QString& descriptionD, + QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + unsigned int i; + QHBoxLayout* layout; + QLabel* label; + + m_edits.resize( 4 ); + for( i = 0; i < 4; i++ ) + { + m_edits.insert( i, new QLineEdit( this ) ); + connect( m_edits[i], SIGNAL( textChanged( const QString& ) ), + SLOT( slotTextChanged( const QString& ) ) ); + } + + layout = new QHBoxLayout( this ); + + if( !descriptionA.isEmpty( ) ) + { + label = new QLabel( descriptionA, this ); + layout->addWidget( label ); + layout->addSpacing( KDialog::spacingHint( ) ); + } + layout->addWidget( m_edits[0] ); + layout->addSpacing( KDialog::spacingHint( ) ); + + if( !descriptionB.isEmpty( ) ) + { + label = new QLabel( descriptionB, this ); + layout->addWidget( label ); + layout->addSpacing( KDialog::spacingHint( ) ); + } + layout->addWidget( m_edits[1] ); + layout->addSpacing( KDialog::spacingHint( ) ); + + if( !descriptionC.isEmpty( ) ) + { + label = new QLabel( descriptionC, this ); + layout->addWidget( label ); + layout->addSpacing( KDialog::spacingHint( ) ); + } + layout->addWidget( m_edits[2] ); + layout->addSpacing( KDialog::spacingHint( ) ); + + if( !descriptionD.isEmpty( ) ) + { + label = new QLabel( descriptionD, this ); + layout->addWidget( label ); + layout->addSpacing( KDialog::spacingHint( ) ); + } + layout->addWidget( m_edits[3] ); +} + +void PMVectorEdit::setVector( const PMVector& v, int precision ) +{ + unsigned int i; + QString str; + + if( v.size( ) != m_edits.size( ) ) + kdError( PMArea ) << "Vector has wrong size in PMVectorEdit::setVector\n"; + + for( i = 0; ( i < m_edits.size( ) ) && ( i < v.size( ) ); i++ ) + { + str.setNum( v[i], 'g', precision ); + m_edits[i]->setText( str ); + } +} + +PMVector PMVectorEdit::vector( ) const +{ + PMVector result( m_edits.size( ) ); + unsigned int i; + + for( i = 0; i < m_edits.size( ); i++ ) + result[i] = m_edits[i]->text( ).toDouble( ); + + return result; +} + +bool PMVectorEdit::isDataValid( ) +{ + bool ok = true; + unsigned int i; + + for( i = 0; ( i < m_edits.size( ) ) && ok; i++ ) + { + m_edits[i]->text( ).toDouble( &ok ); + if( !ok ) + { + KMessageBox::error( this, i18n( "Please enter a valid float value!" ), + i18n( "Error" ) ); + m_edits[i]->setFocus( ); + m_edits[i]->selectAll( ); + } + } + + return ok; +} + +void PMVectorEdit::slotTextChanged( const QString& ) +{ + emit dataChanged( ); +} + +void PMVectorEdit::setReadOnly( bool yes ) +{ + unsigned int i; + for( i = 0; ( i < m_edits.size( ) ); i++ ) + m_edits[i]->setReadOnly( yes ); +} + +void PMVectorEdit::setEnabled( bool yes ) +{ + unsigned int i; + for( i = 0; ( i < m_edits.size( ) ); i++ ) + m_edits[i]->setEnabled( yes ); +} + +#include "pmvectoredit.moc" diff --git a/kpovmodeler/pmvectoredit.h b/kpovmodeler/pmvectoredit.h new file mode 100644 index 00000000..8be64ebe --- /dev/null +++ b/kpovmodeler/pmvectoredit.h @@ -0,0 +1,100 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMVECTOREDIT_H +#define PMVECTOREDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include "pmvector.h" + +/** + * Edit widget for @ref PMVector + */ +class PMVectorEdit : public QWidget +{ + Q_OBJECT +public: + /** + * Creates an edit widget for 2D vectors. + * + * The labels shown are descriptionX and descriptionY + */ + PMVectorEdit( const QString& descriptionX, + const QString& descriptionY, + QWidget* parent, const char* name = 0 ); + /** + * Creates an edit widget for 3D vectors. + * + * The labels shown are descriptionX, descriptionY and descriptionZ + */ + PMVectorEdit( const QString& descriptionX, + const QString& descriptionY, const QString& descriptionZ, + QWidget* parent, const char* name = 0 ); + /** + * Creates an edit widget for 4D vectors. + * + * The labels shown are descriptionA, descriptionB, descriptionC + * and description D + */ + PMVectorEdit( const QString& descriptionA, const QString& descriptionB, + const QString& descriptionC, const QString& descriptionD, + QWidget* parent, const char* name = 0 ); + + /** + * Sets the displayed vector + */ + void setVector( const PMVector& v, int precision = 5 ); + /** + * Returns the displayed vector + */ + PMVector vector( ) const; + + /** + * Returns true if the text for each coordinate is a valid + * float value. Otherwise an error message is shown. + */ + bool isDataValid( ); + + /** + * Enables or disables read only mode + */ + void setReadOnly( bool yes = true ); + /** + * Reimplemented from QWidget + */ + virtual void setEnabled( bool yes ); +signals: + /** + * Emitted when one of the coordinates is changed + */ + void dataChanged( ); + +protected slots: + void slotTextChanged( const QString& ); +private: + QPtrVector m_edits; +}; + +#endif diff --git a/kpovmodeler/pmvectorlistedit.cpp b/kpovmodeler/pmvectorlistedit.cpp new file mode 100644 index 00000000..224c6b69 --- /dev/null +++ b/kpovmodeler/pmvectorlistedit.cpp @@ -0,0 +1,357 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmvectorlistedit.h" +#include "pmdebug.h" + +#include +#include +#include +#include +#include +#include + +const int c_columnWidth = 65; + + +/* +PMTableItem::PMTableItem( QTable* table ) + : QTableItem( table, QTableItem::OnTyping, QString( "" ) ) +{ + m_readOnly = false; +} + +void PMTableItem::paint( QPainter* p, const QColorGroup& cg, + const QRect& cr, bool selected ) +{ + p->fillRect( 0, 0, cr.width( ), cr.height( ), + selected ? cg.brush( QColorGroup::Highlight ) + : ( m_readOnly ? cg.brush( QColorGroup::Background ) : + cg.brush( QColorGroup::Base ) ) ); + + int w = cr.width( ); + int h = cr.height( ); + + int x = 0; + + if( selected ) + p->setPen( cg.highlightedText( ) ); + else + p->setPen( cg.text( ) ); + p->drawText( x + 2, 0, w - x - 4, h, + wordWrap( ) ? ( alignment( ) | WordBreak ) : alignment( ), text( ) ); +} +*/ + +PMVectorListEdit::PMVectorListEdit( QWidget* parent, const char* name ) + : QTable( 1, 3, parent, name ) +{ + init( 3 ); + + QHeader* header = horizontalHeader( ); + header->setLabel( 0, "x" ); + header->setLabel( 1, "y" ); + header->setLabel( 2, "z" ); +} + +PMVectorListEdit::PMVectorListEdit( const QString& c1, const QString& c2, + const QString& c3, const QString& c4, + QWidget* parent, const char* name ) + : QTable( 1, 4, parent, name ) +{ + init( 4 ); + + QHeader* header = horizontalHeader( ); + header->setLabel( 0, c1 ); + header->setLabel( 1, c2 ); + header->setLabel( 2, c3 ); + header->setLabel( 3, c4 ); +} + +PMVectorListEdit::PMVectorListEdit( const QString& c1, const QString& c2, + const QString& c3, QWidget* parent, + const char* name ) + : QTable( 1, 3, parent, name ) +{ + init( 3 ); + + QHeader* header = horizontalHeader( ); + header->setLabel( 0, c1 ); + header->setLabel( 1, c2 ); + header->setLabel( 2, c3 ); +} + +PMVectorListEdit::PMVectorListEdit( const QString& c1, const QString& c2, + QWidget* parent, const char* name ) + : QTable( 1, 2, parent, name ) +{ + init( 2 ); + + QHeader* header = horizontalHeader( ); + header->setLabel( 0, c1 ); + header->setLabel( 1, c2 ); +} + +void PMVectorListEdit::init( int dimensions ) +{ + int i; + + m_dimension = dimensions; + m_size = 0; + + horizontalHeader( )->setResizeEnabled( false ); + verticalHeader( )->setResizeEnabled( false ); + + setSelectionMode( QTable::MultiRow ); + for( i = 0; i < m_dimension; ++i ) + setColumnStretchable( i, true ); + connect( this, SIGNAL( valueChanged( int, int ) ), + SLOT( slotTextChanged( int, int ) ) ); + setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) ); +} + +void PMVectorListEdit::setVectors( const QValueList& l, + bool resize, int prec ) +{ + QValueList::ConstIterator it; + int r, nl = 0; + + for( r = 0; r < ( signed ) m_links.size( ); ++r ) + if( m_links[r] >= 0 ) + ++nl; + + if( nl == 0 && resize ) + setSize( l.size( ) ); + + for( r = 0, it = l.begin( ); it != l.end( ) && r < m_size; ++r ) + { + if( m_disabled[r] ) + { + if( !isReadOnly( ) ) + setRowReadOnly( r, true ); + } + else + { + setVector( r, *it, prec ); + if( !isReadOnly( ) ) + setRowReadOnly( r, false ); + if( m_links[r] >= 0 ) + setVector( m_links[r], *it, prec ); + ++it; + } + } + if( it != l.end( ) ) + kdError( PMArea ) << "Wrong size of vector list in PMVectorListEdit::setVectors" << endl; +} + +QValueList PMVectorListEdit::vectors( ) const +{ + QValueList l; + int i; + + for( i = 0; i < m_size; ++i ) + if( !m_disabled[i] ) + l.append( vector( i ) ); + + return l; +} + +void PMVectorListEdit::setVector( int r, const PMVector& v, int precision ) +{ + if( r < 0 || r >= m_size ) + { + kdError( PMArea ) << "Wrong vector index in PMVectorListEdit::setVector" + << endl; + return; + } + + bool sb = signalsBlocked( ); + blockSignals( true ); + + int i; + QString str; + + for( i = 0; i < m_dimension && i <= ( signed ) v.size( ); ++i ) + { + str.setNum( v[i], 'g', precision ); + setText( r, i, str ); + } + + blockSignals( sb ); +} + +PMVector PMVectorListEdit::vector( int r ) const +{ + PMVector v( m_dimension ); + + if( r < 0 || r >= m_size ) + { + kdError( PMArea ) << "Wrong vector index in PMVectorListEdit::vector" + << endl; + return v; + } + + int i; + for( i = 0; i < m_dimension; ++i ) + v[i] = text( r, i ).toDouble( ); + return v; +} + +void PMVectorListEdit::setSize( int s ) +{ + if( s < 0 || s == m_size ) + return; + + setNumRows( s ); + int i; + QHeader* h = verticalHeader( ); + QString str; + + for( i = 0; i < s; ++i ) + { + setRowStretchable( i, true ); + setRowReadOnly( i, false ); + + str.setNum( i + 1 ); + h->setLabel( i, str ); + } + m_links.fill( -1, s ); + m_disabled.fill( false, s ); + m_size = s; + updateGeometry( ); +} + +void PMVectorListEdit::setLink( int p1, int p2 ) +{ + if( p1 < 0 || p1 >= m_size || p2 >= m_size ) + return; + + QHeader* h = verticalHeader( ); + QString str; + + // remove old link + if( m_links[p1] >= 0 ) + { + str.setNum( m_links[p1] + 1 ); + h->setLabel( m_links[p1], str ); + if( !isReadOnly( ) ) + setRowReadOnly( m_links[p1], false ); + m_disabled[m_links[p1]] = false; + } + + if( p2 >= 0 ) + { + m_disabled[p2] = true; + str = QString( "%1 (=%2)" ).arg( p2 + 1 ).arg( p1 + 1 ); + h->setLabel( p2, str ); + if( !isReadOnly( ) ) + setRowReadOnly( p2, true ); + } + + m_links[p1] = p2; +} + +void PMVectorListEdit::clearLinks( ) +{ + int i; + for( i = 0; i < ( signed ) m_links.size( ); ++i ) + if( m_links[i] >= 0 ) + setLink( i, -1 ); +} + +bool PMVectorListEdit::isSelected( int i ) const +{ + return isRowSelected( i ); +} + +void PMVectorListEdit::select( int i ) +{ + selectRow( i ); +} + +void PMVectorListEdit::select( int i, int j ) +{ + QTableSelection sel( i, 0, j, m_dimension - 1 ); + addSelection( sel ); + +} + +bool PMVectorListEdit::isDataValid( ) +{ + int r, i; + bool valid = true; + double d; + + for( r = 0; r < m_size && valid; ++r ) + { + if( !m_disabled[r] ) + { + for( i = 0; i < m_dimension && valid; ++i ) + { + d = text( r, i ).toDouble( &valid ); + if( !valid ) + { + setCurrentCell( r, i ); + KMessageBox::error( this, i18n( "Please enter a valid float value!" ), + i18n( "Error" ) ); + } + } + } + } + return valid; +} + +QSize PMVectorListEdit::sizeHint( ) const +{ + return QSize( c_columnWidth * m_dimension + frameWidth( ) * 2, + frameWidth( ) * 2 + horizontalHeader( )->height( ) + + verticalHeader( )->sizeHint( ).height( ) ); +} + +void PMVectorListEdit::slotTextChanged( int, int ) +{ + emit dataChanged( ); +} + +void PMVectorListEdit::blockSelectionUpdates( bool block ) +{ + setUpdatesEnabled( !block ); + verticalHeader( )->setUpdatesEnabled( !block ); + horizontalHeader( )->setUpdatesEnabled( !block ); + if( !block ) + { + updateContents( ); + verticalHeader( )->update( ); + horizontalHeader( )->update( ); + } +} + +bool PMVectorListEdit::eventFilter( QObject* o, QEvent* e ) +{ + if( e->type( ) == QEvent::Wheel && parent( ) ) + return QApplication::sendEvent( parent( ), e ); + if( e->type( ) == QEvent::MouseButtonPress + && ( ( QMouseEvent* ) e )->button( ) == RightButton ) + { + bool b = QTable::eventFilter( o, e ); + emit showContextMenu( ); + return b; + } + return QTable::eventFilter( o, e ); +} + +#include "pmvectorlistedit.moc" diff --git a/kpovmodeler/pmvectorlistedit.h b/kpovmodeler/pmvectorlistedit.h new file mode 100644 index 00000000..f8ecb938 --- /dev/null +++ b/kpovmodeler/pmvectorlistedit.h @@ -0,0 +1,174 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMVECTORLISTEDIT_H +#define PMVECTORLISTEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "pmvector.h" + +/* +const int c_pmTableRTTI = 14352; + +class PMTableItem : public QTableItem +{ +public: + PMTableItem( QTable* table ); + + virtual void paint( QPainter* p, const QColorGroup& cg, + const QRect& cr, bool selected ); + + int rtti( ) const { return c_pmTableRTTI; } + + void setReadOnly( bool r ) { m_readOnly = r; } + bool isReadOnly( ) const { return m_readOnly; } + +private: + bool m_readOnly; +}; +*/ + + +/** + * Widget that displays a list of vectors, based on @ref QTable. + */ +class PMVectorListEdit : public QTable +{ + Q_OBJECT +public: + /** + * Constructor for 3d vectors (x, y, z) + */ + PMVectorListEdit( QWidget* parent, const char* name = 0 ); + /** + * Constructor for 3d vectors + */ + PMVectorListEdit( const QString& c1, const QString& c2, const QString& c3, + QWidget* parent, const char* name = 0 ); + /** + * Constructor for 2d vectors + */ + PMVectorListEdit( const QString& c1, const QString& c2, + QWidget* parent, const char* name = 0 ); + + /** + * Constructor for 4d vectors + */ + PMVectorListEdit( const QString& c1, const QString& c2, const QString& c3, + const QString& c4, QWidget* parent, const char* name = 0 ); + /** + * Sets and displays the vectors. The widget will automatically + * resize if no link is set and resize is true. + */ + void setVectors( const QValueList& v, bool resize = false, + int precision = 5 ); + /** + * Returns the vectors + */ + QValueList vectors( ) const; + /** + * Sets the i-th vector + */ + void setVector( int i, const PMVector& v, int precision = 5 ); + /** + * Returns the i-th vector + */ + PMVector vector( int i ) const; + /** + * Sets the number of vectors + */ + void setSize( int s ); + /** + * Returns the number of vectors + */ + int size( ) const { return m_size; } + + /** + * Adds a linked point. The point p2 will be disabled and synchronized + * with p1. + * + * Call this method before displaying vectors and remove the point + * p2 from the vector list before you call @ref setVectors( ). + * The list returned by @ref vectors( ) will not return this point. + * + * Set p2 to -1 to remove a link. + */ + void setLink( int p1, int p2 ); + /** + * Removes all links. The widget is not updated. You have to resize + * the widget and redisplay the points. + */ + void clearLinks( ); + + /** + * Returns the selection status of vector i + */ + bool isSelected( int i ) const; + /** + * Selects vector i + */ + void select( int i ); + /** + * Selects vector i to j + */ + void select( int i, int j ); + /** + * Blocks/unblocks selection updates. If block is false, the + * selection is repainted. + */ + void blockSelectionUpdates( bool block ); + + /** + * Returns true if the edited data is valid. + */ + bool isDataValid( ); + + /** */ + virtual QSize sizeHint( ) const; + /** */ + bool eventFilter( QObject* o, QEvent* e ); + +protected slots: + void slotTextChanged( int, int ); + +signals: + /** + * Emitted when the used edits a field + */ + void dataChanged( ); + /** + * Emitted after a right mouse button click + */ + void showContextMenu( ); +private: + void init( int dimensions ); + + int m_dimension, m_size; + QMemArray m_links; + QMemArray m_disabled; +}; + + +#endif diff --git a/kpovmodeler/pmview.cpp b/kpovmodeler/pmview.cpp new file mode 100644 index 00000000..fe9f32d4 --- /dev/null +++ b/kpovmodeler/pmview.cpp @@ -0,0 +1,108 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// application specific includes +#include "pmview.h" +#include "pmpart.h" +#include "pmtreeview.h" +#include "pmdialogview.h" +#include "pmglview.h" + +PMView::PMView( PMPart* part, QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + setBackgroundMode( PaletteBase ); + + QVBoxLayout* layout = new QVBoxLayout( this ); + m_pMainSplitter = new QSplitter( Qt::Horizontal, this, "MainSplitter" ); + m_pTreeEditSplitter = new QSplitter( Qt::Vertical, m_pMainSplitter, + "TreeEditSplitter" ); + + + m_pTreeView = new PMTreeView( part, m_pTreeEditSplitter, "TreeView" ); + m_pTreeView->show( ); + + m_pDialogView = new PMDialogView( part, m_pTreeEditSplitter, "EditView" ); + m_pDialogView->show( ); + + + QWidget* glArea = new QWidget( m_pMainSplitter, "GLArea" ); + glArea->show( ); + PMGLView* gl; + + QGridLayout* topLayout = new QGridLayout( glArea, 2, 2, 1, 1 ); + gl = new PMGLView( part, PMGLView::PMViewPosZ, glArea ); + topLayout->addWidget( gl, 0, 0 ); + gl = new PMGLView( part, PMGLView::PMViewPosX, glArea ); + topLayout->addWidget( gl, 0, 1 ); + gl = new PMGLView( part, PMGLView::PMViewNegY, glArea ); + topLayout->addWidget( gl, 1, 0 ); + gl = new PMGLView( part, PMGLView::PMViewCamera, glArea ); + topLayout->addWidget( gl, 1, 1 ); + + m_pMainSplitter->show( ); + + layout->addWidget( m_pMainSplitter ); + layout->activate( ); + + m_pPart = part; +} + +PMView::~PMView( ) +{ +} + +void PMView::print( QPrinter* pPrinter ) +{ + QPainter printpainter; + printpainter.begin( pPrinter ); + + // TODO: add your printing code here + + printpainter.end( ); +} + +void PMView::saveConfig( KConfig* cfg ) +{ + cfg->setGroup( "Appearance" ); + + cfg->writeEntry( "MainSplitter", m_pMainSplitter->sizes( ) ); + cfg->writeEntry( "TreeEditSplitter", m_pTreeEditSplitter->sizes( ) ); +} + +void PMView::restoreConfig( KConfig* cfg ) +{ + cfg->setGroup( "Appearance" ); + + m_pMainSplitter->setSizes( cfg->readIntListEntry( "MainSplitter" ) ); + m_pTreeEditSplitter->setSizes( cfg->readIntListEntry( "TreeEditSplitter" ) ); +} + + +#include "pmview.moc" diff --git a/kpovmodeler/pmview.h b/kpovmodeler/pmview.h new file mode 100644 index 00000000..8a216663 --- /dev/null +++ b/kpovmodeler/pmview.h @@ -0,0 +1,76 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMVIEW_H +#define PMVIEW_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +// include files for Qt +#include + +class PMTreeView; +class PMDialogView; +class PMPart; +class QSplitter; +class KConfig; + +/** + * The PMView class provides the view widget for the PMPart document class. + */ +class PMView : public QWidget +{ + Q_OBJECT +public: + /** + * Constructor for the main view + */ + PMView( PMPart* part, QWidget* parent = 0, const char* name = 0 ); + /** + * Destructor for the main view + */ + ~PMView( ); + + /** + * returns a pointer to the part + */ + PMPart* part( ) const { return m_pPart; } + + /** + * contains the implementation for printing functionality TODO*/ + void print( QPrinter* pPrinter ); + /** + * saves settings + */ + void saveConfig( KConfig* cfg ); + /** + * loads settings + */ + void restoreConfig( KConfig* cfg ); +private: + PMTreeView* m_pTreeView; + PMPart* m_pPart; + PMDialogView* m_pDialogView; + QSplitter* m_pMainSplitter; + QSplitter* m_pTreeEditSplitter; +}; + +#endif diff --git a/kpovmodeler/pmviewbase.cpp b/kpovmodeler/pmviewbase.cpp new file mode 100644 index 00000000..44c239ef --- /dev/null +++ b/kpovmodeler/pmviewbase.cpp @@ -0,0 +1,20 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmviewbase.h" + +#include "pmviewbase.moc" diff --git a/kpovmodeler/pmviewbase.h b/kpovmodeler/pmviewbase.h new file mode 100644 index 00000000..cce59922 --- /dev/null +++ b/kpovmodeler/pmviewbase.h @@ -0,0 +1,128 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMVIEWBASE_H +#define PMVIEWBASE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +class QDomElement; + +/** + * This class stores the view configuration for one view. + * + * Reimplement this class for each view type that has to store + * additional values. + * + * Created, loaded from and saved to the xml config by the corresponding + * @ref PMViewTypeFactory factory class. + */ +class PMViewOptions +{ +public: + /** + * Returns a deep copy + */ + virtual PMViewOptions* copy( ) const = 0; + /** + * Returns the identifier for the view type. Has to be equal + * to @ref PMViewBase::viewType for the corresponding view type. + */ + virtual QString viewType( ) const = 0; + /** + * Loads the data from the xml element + */ + virtual void loadData( QDomElement& e ) = 0; + /** + * Saves the data from to xml element + */ + virtual void saveData( QDomElement& e ) = 0; +}; + +/** + * Base class for configuration widgets for view types + * for the layout settings dialog page + */ +class PMViewOptionsWidget : public QWidget +{ + Q_OBJECT +public: + /** + * Default constructor + */ + PMViewOptionsWidget( QWidget* parent, const char* name = 0 ) + : QWidget( parent, name ) + { + } + +signals: + /** + * Emitted when the view type description has changed + */ + void viewTypeDescriptionChanged( ); +}; + +/** + * Interface for views. + * + * Each view type has to implement this interface. Handles the + * config loading and saving + */ +class PMViewBase : public QWidget +{ + Q_OBJECT +public: + /** + * Default constructor + */ + PMViewBase( QWidget* parent, const char* name = 0, WFlags f = 0 ) + : QWidget( parent, name, f ) + { + } + /** + * Returns the identifier for the view type. Has to be unique + * for all view types. + */ + virtual QString viewType( ) const = 0; + /** + * Returns a i18n'ed description + */ + virtual QString description( ) const = 0; + /** + * Restores the view configuration + * + * Reimplement this function if the view type has to + * restore additional values. + * @see PMViewOptions + */ + virtual void restoreViewConfig( PMViewOptions* ) { } + /** + * Saves the view configuration + * + * Reimplement this function if the view type has to + * restore additional values. + * @see PMViewOptions + */ + virtual void saveViewConfig( PMViewOptions* ) const { } +}; + +#endif diff --git a/kpovmodeler/pmviewfactory.cpp b/kpovmodeler/pmviewfactory.cpp new file mode 100644 index 00000000..58e566cc --- /dev/null +++ b/kpovmodeler/pmviewfactory.cpp @@ -0,0 +1,94 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmviewfactory.h" +#include "pmglview.h" +#include "pmtreeview.h" +#include "pmdialogview.h" +#include "pmdebug.h" +#include "pmviewbase.h" +#include "pmglview.h" +#include "pmtreeview.h" +#include "pmdialogview.h" +#include "pmlibrarybrowser.h" + +#include + +PMViewFactory* PMViewFactory::s_pInstance = 0; +KStaticDeleter PMViewFactory::s_staticDeleter; + +PMViewFactory::PMViewFactory( ) +{ + m_viewTypes.setAutoDelete( true ); + addViewType( new PMTreeViewFactory( ) ); + addViewType( new PMDialogViewFactory( ) ); + addViewType( new PMGLViewFactory( ) ); + addViewType( new PMLibraryBrowserViewFactory( ) ); +} + +PMViewFactory::~PMViewFactory( ) +{ + m_viewTypes.clear( ); +} + +PMViewFactory* PMViewFactory::theFactory( ) +{ + if( !s_pInstance ) + s_staticDeleter.setObject( s_pInstance, new PMViewFactory( ) ); + return s_pInstance; +} + +void PMViewFactory::addViewType( PMViewTypeFactory* vt ) +{ + if( vt ) + { + m_viewTypes.append( vt ); + m_dict.insert( vt->viewType( ), vt ); + } +} + +PMViewBase* PMViewFactory::newViewInstance( const QString& viewType, + QWidget* parent, PMPart* part ) const +{ + PMViewTypeFactory* f = m_dict.find( viewType ); + if( f ) + return f->newInstance( parent, part ); + + kdError( PMArea ) << "Unknown view type \"" << viewType << "\"" << endl; + return 0; +} + +PMViewOptions* PMViewFactory::newOptionsInstance( const QString& viewType ) const +{ + PMViewTypeFactory* f = m_dict.find( viewType ); + if( f ) + return f->newOptionsInstance( ); + + kdError( PMArea ) << "Unknown view type \"" << viewType << "\"" << endl; + return 0; +} + +PMViewTypeFactory* PMViewFactory::viewFactory( const QString& viewType ) const +{ + return m_dict.find( viewType ); +} + +const QPtrList& PMViewFactory::viewTypes( ) const +{ + return m_viewTypes; +} + diff --git a/kpovmodeler/pmviewfactory.h b/kpovmodeler/pmviewfactory.h new file mode 100644 index 00000000..b24814cf --- /dev/null +++ b/kpovmodeler/pmviewfactory.h @@ -0,0 +1,145 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMVIEWFACTORY_H +#define PMVIEWFACTORY_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +class PMViewBase; +class QWidget; +class PMPart; +class QDomElement; +class PMViewOptions; +class PMViewOptionsWidget; + +/** + * Factory and description class for one view type + * @see PMViewFactory + */ +class PMViewTypeFactory +{ +public: + /** + * Default constructor + */ + PMViewTypeFactory( ) { } + /** + * Destructor + */ + virtual ~PMViewTypeFactory( ) { } + /** + * Returns the id for the view type. Choose an unique name. + */ + virtual QString viewType( ) const = 0; + /** + * Returns a i18n'ed description for the view type + */ + virtual QString description( ) const = 0; + /** + * Returns a i18n'ed description for the view type, dependent + * on the options. Calls the method above by default. + */ + virtual QString description( PMViewOptions* ) const + { + return description( ); + } + /** + * Returns the icon name for the view + */ + virtual QString iconName( ) const = 0; + /** + * Returns a new view instance + */ + virtual PMViewBase* newInstance( QWidget* parent, PMPart* part ) const = 0; + /** + * Creates a config object for the view type. + * If the view doesn't have special attributes, the function returns 0; + */ + virtual PMViewOptions* newOptionsInstance( ) const { return 0; } + /** + * Creates a widget to configure the custom options + */ + virtual PMViewOptionsWidget* newOptionsWidget( QWidget*, PMViewOptions* ) + { + return 0; + } +}; + + +/** + * Factory class for KPovModeler views. + * + * Plugins can add new view types by adding new + * @ref PMViewTypeFactory objects. + */ +class PMViewFactory +{ +public: + /** + * Destructor + */ + ~PMViewFactory( ); + /** + * Returns the factory instance + */ + static PMViewFactory* theFactory( ); + + /** + * Adds a new view type + * + * The factory becomes the owner of the object + */ + void addViewType( PMViewTypeFactory* vt ); + /** + * Returns a new view of type viewType if available + */ + PMViewBase* newViewInstance( const QString& viewType, + QWidget* parent, PMPart* part ) const; + /** + * Returns a new view option instance for the given view type + */ + PMViewOptions* newOptionsInstance( const QString& viewType ) const; + /** + * Returns the factory for the given view type + */ + PMViewTypeFactory* viewFactory( const QString& viewType ) const; + /** + * Returns the list of available view types + */ + const QPtrList& viewTypes( ) const; +private: + /** + * Constructor + */ + PMViewFactory( ); + + QPtrList m_viewTypes; + QDict m_dict; + + static PMViewFactory* s_pInstance; + static KStaticDeleter s_staticDeleter; +}; + +#endif diff --git a/kpovmodeler/pmviewlayoutmanager.cpp b/kpovmodeler/pmviewlayoutmanager.cpp new file mode 100644 index 00000000..593eed27 --- /dev/null +++ b/kpovmodeler/pmviewlayoutmanager.cpp @@ -0,0 +1,935 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmviewlayoutmanager.h" +#include "pmdockwidget_private.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "pmshell.h" +#include "pmdebug.h" +#include "pmviewfactory.h" + +PMViewLayoutManager* PMViewLayoutManager::s_pInstance = 0; +KStaticDeleter PMViewLayoutManager::s_staticDeleter; + + +//================ PMViewLayoutEntry ==================== + +PMViewLayoutEntry::PMViewLayoutEntry( ) +{ + m_viewType = "treeview"; + m_dockPosition = PMDockWidget::DockRight; + m_columnWidth = 33; + m_height = 50; + m_floatingWidth = 400; + m_floatingHeight = 400; + m_floatingPositionX = 200; + m_floatingPositionY = 200; + m_pCustomOptions = 0; +} + +PMViewLayoutEntry::PMViewLayoutEntry( const PMViewLayoutEntry& e ) +{ + m_viewType = e.m_viewType; + m_dockPosition = e.m_dockPosition; + m_columnWidth = e.m_columnWidth; + m_height = e.m_height; + m_floatingWidth = e.m_floatingWidth; + m_floatingHeight = e.m_floatingHeight; + m_floatingPositionX = e.m_floatingPositionX; + m_floatingPositionY = e.m_floatingPositionY; + if( e.m_pCustomOptions ) + m_pCustomOptions = e.m_pCustomOptions->copy( ); + else + m_pCustomOptions = 0; +} + +PMViewLayoutEntry::~PMViewLayoutEntry( ) +{ + if( m_pCustomOptions ) + delete m_pCustomOptions; +} + +void PMViewLayoutEntry::loadData( QDomElement& e ) +{ + QString s; + bool ok; + + // Read the view type + s = e.tagName( ); + m_viewType = s; + + // Read dock position + s = e.attribute( "position", "Right" ); + if( s == "Right" ) m_dockPosition = PMDockWidget::DockRight; + else if( s == "Bottom" ) m_dockPosition = PMDockWidget::DockBottom; + else if( s == "Center" ) m_dockPosition = PMDockWidget::DockCenter; + else if( s == "None" ) m_dockPosition = PMDockWidget::DockNone; + + // Read the column width + s = e.attribute( "columnWidth", "33" ); + m_columnWidth = s.toInt( &ok ); + if( !ok ) m_columnWidth = 33; + + // and view height + s = e.attribute( "height", "50" ); + m_height = s.toInt( &ok ); + if( !ok ) m_height = 50; + + s = e.attribute( "floatingHeight", "400" ); + m_floatingHeight = s.toInt( &ok ); + if( !ok ) m_floatingHeight = 400; + s = e.attribute( "floatingWidth", "400" ); + m_floatingWidth = s.toInt( &ok ); + if( !ok ) m_floatingWidth = 400; + + s = e.attribute( "floatingPosX", "200" ); + m_floatingPositionX = s.toInt( &ok ); + if( !ok ) m_floatingPositionX = 200; + s = e.attribute( "floatingPosY", "200" ); + m_floatingPositionY = s.toInt( &ok ); + if( !ok ) m_floatingPositionY = 200; + + // Load custom options + if( m_pCustomOptions ) + delete m_pCustomOptions; + m_pCustomOptions = + PMViewFactory::theFactory( )->newOptionsInstance( m_viewType ); + if( m_pCustomOptions ) + m_pCustomOptions->loadData( e ); +} + +void PMViewLayoutEntry::saveData( QDomElement& e ) const +{ + QString s; + e.setTagName( m_viewType ); + switch( m_dockPosition ) + { + case PMDockWidget::DockRight: + e.setAttribute( "position", "Right" ); + break; + case PMDockWidget::DockBottom: + e.setAttribute( "position", "Bottom" ); + break; + case PMDockWidget::DockCenter: + e.setAttribute( "position", "Center" ); + break; + case PMDockWidget::DockNone: + e.setAttribute( "position", "None" ); + break; + default: + kdError( PMArea ) << i18n( "Unknown dock position." ) + << endl; + break; + } + s.setNum( m_columnWidth ); + e.setAttribute( "columnWidth", s ); + s.setNum( m_height ); + e.setAttribute( "height", s ); + s.setNum( m_floatingHeight ); + e.setAttribute( "floatingHeight", s ); + s.setNum( m_floatingWidth ); + e.setAttribute( "floatingWidth", s ); + s.setNum( m_floatingPositionX ); + e.setAttribute( "floatingPosX", s ); + s.setNum( m_floatingPositionY ); + e.setAttribute( "floatingPosY", s ); + + // save custom options + if( m_pCustomOptions ) + m_pCustomOptions->saveData( e ); +} + +void PMViewLayoutEntry::setViewType( const QString& v ) +{ + m_viewType = v; +} + +void PMViewLayoutEntry::setDockPosition( PMDockWidget::DockPosition i ) +{ + m_dockPosition = i; +} + +void PMViewLayoutEntry::setColumnWidth( int i ) +{ + m_columnWidth = i; + if( i < 1 ) + m_columnWidth = 1; +} + +void PMViewLayoutEntry::setHeight( int i ) +{ + m_height = i; + if( i < 1 ) + m_height = 1; +} + +const QString PMViewLayoutEntry::viewTypeAsString( ) +{ + PMViewTypeFactory* f = PMViewFactory::theFactory( )->viewFactory( m_viewType ); + if( f ) + { + if( m_pCustomOptions ) + return f->description( m_pCustomOptions ); + else + return f->description( ); + } + + kdError( PMArea ) << i18n( "Unknown view type." )<< endl; + return i18n( "Unknown" ); +} + +const QString PMViewLayoutEntry::dockPositionAsString( ) +{ + switch( m_dockPosition ) + { + case PMDockWidget::DockRight: + return i18n( "New Column" ); + case PMDockWidget::DockBottom: + return i18n( "Below" ); + case PMDockWidget::DockCenter: + return i18n( "Tabbed" ); + case PMDockWidget::DockNone: + return i18n( "Floating" ); + default: + kdError( PMArea ) << i18n( "Unknown dock position." ) + << endl; + return i18n( "unknown" ); + } +} + +void PMViewLayoutEntry::setCustomOptions( PMViewOptions* o ) +{ + if( m_pCustomOptions && m_pCustomOptions != o ) + delete m_pCustomOptions; + m_pCustomOptions = o; +} + +//================== PMViewLayout ====================== + +PMViewLayout::PMViewLayout( ) +{ + m_entries.clear( ); +} + +PMViewLayout::PMViewLayout( const PMViewLayout& vl ) +{ + m_entries = vl.m_entries; + m_name = vl.m_name; +} + +PMViewLayout& PMViewLayout::operator = ( const PMViewLayout& vl ) +{ + m_entries = vl.m_entries; + m_name = vl.m_name; + return *this; +} + +void PMViewLayout::loadData( QDomElement& e ) +{ + m_entries.clear( ); + m_name = e.attribute( "name", "unnamed" ); + + QDomNode m = e.firstChild( ); + while( !m.isNull( ) ) + { + if( m.isElement( ) ) + { + QDomElement me = m.toElement( ); + PMViewLayoutEntry vle; + + vle.loadData( me ); + m_entries.append( vle ); + } + m = m.nextSibling( ); + } + normalize( ); +} + +void PMViewLayout::saveData( QDomElement& e, QDomDocument& doc ) const +{ + QValueList< PMViewLayoutEntry>::const_iterator it; + + e.setAttribute( "name", m_name ); + for( it = m_entries.begin( ); it != m_entries.end( ) ; ++it ) + { + QDomElement a; + a = doc.createElement( "unknown" ); + ( *it ).saveData( a ); + e.appendChild( a ); + } +} + +void PMViewLayout::setName( const QString& n ) +{ + m_name = n; +} + +void PMViewLayout::addEntry( const PMViewLayoutEntry& e, int index ) +{ + if( index == -1 ) + m_entries.append( e ); + else + m_entries.insert( m_entries.at( index ), 1, e ); +} + +void PMViewLayout::removeEntry( int index ) +{ + m_entries.remove( m_entries.at( index ) ); +} + +void PMViewLayout::displayLayout( PMShell* shell ) +{ + PMDockWidget* lastWidget = 0; + QValueList< PMViewLayoutEntry>::const_iterator it; + bool isViewSet = false; + int lastWidth = 0, width = 100; + int lastHeight = 0, height = 100; + + for( it = m_entries.begin( ); it != m_entries.end( ) ; ++it ) + { + PMDockWidget* dock = shell->createView( ( *it ).viewType( ), + ( *it ).customOptions( ), + false ); + // Dock the widget + if( ( *it ).dockPosition( ) == PMDockWidget::DockNone ) + { + // the specified target is the desktop + dock->manualDock( 0, PMDockWidget::DockDesktop, 50, + QPoint( ( *it ).floatingPositionX( ), + ( *it ).floatingPositionY( ) ) ); + dock->resize( ( *it ).floatingWidth( ), ( *it ).floatingHeight( ) ); + dock->show( ); + } + else + { + // the first dockwidget is not docked but placed on all the window + // through setView( ) + if( !isViewSet ) + { + shell->setView( dock ); + isViewSet = true; + lastWidget = dock; + } + else + { + switch( ( *it ).dockPosition( ) ) + { + case PMDockWidget::DockRight: + dock->manualDock( lastWidget, ( *it ).dockPosition( ), + lastWidth * 100 / width ); + + width -= lastWidth; + if( width < 1 ) width = 1; + height = 100; + lastWidget = dock; + break; + case PMDockWidget::DockBottom: + dock->manualDock( lastWidget, ( *it ).dockPosition( ), + lastHeight * 100 / height ); + height -= lastHeight; + if( height < 1 ) height = 1; + lastWidget = dock; + break; + case PMDockWidget::DockCenter: + dock->manualDock( lastWidget, ( *it ).dockPosition( ), 100 ); + break; + default: + dock->manualDock( 0, PMDockWidget::DockDesktop, 100 ); + break; + } + } + + switch( ( *it ).dockPosition( ) ) + { + case PMDockWidget::DockRight: + lastWidth = ( *it ).columnWidth( ); + lastHeight = ( *it ).height( ); + break; + case PMDockWidget::DockBottom: + lastHeight = ( *it ).height( ); + break; + default: + break; + } + } + } +} + +void PMViewLayout::normalize( ) +{ + iterator it; + int sumColWidth = 0; + + it = m_entries.begin( ); + // the first entry has to be a new column + if( it != m_entries.end( ) ) + if( ( *it ).dockPosition( ) != PMDockWidget::DockRight ) + ( *it ).setDockPosition( PMDockWidget::DockRight ); + + // find negative or zero widths and heights + for( it = m_entries.begin( ); it != m_entries.end( ); ++it ) + { + if( ( *it ).columnWidth( ) < 1 ) + ( *it ).setColumnWidth( 1 ); + if( ( *it ).height( ) < 1 ) + ( *it ).setHeight( 1 ); + } + + // normalize the column widths + for( it = m_entries.begin( ); it != m_entries.end( ); ++it ) + if( ( *it ).dockPosition( ) == PMDockWidget::DockRight ) + sumColWidth += ( *it ).columnWidth( ); + if( sumColWidth == 0 ) + sumColWidth = 1; + + for( it = m_entries.begin( ); it != m_entries.end( ); ++it ) + { + if( ( *it ).dockPosition( ) == PMDockWidget::DockRight ) + { + ( *it ).setColumnWidth( ( int ) ( ( *it ).columnWidth( ) * 100.0 + / sumColWidth + 0.5 ) ); + // normalize each column + iterator it2 = it; + int height = ( *it ).height( ); + + for( it2++; it2 != m_entries.end( ) && + ( *it2 ).dockPosition( ) != PMDockWidget::DockRight; ++it2 ) + if( ( *it2 ).dockPosition( ) == PMDockWidget::DockBottom ) + height += ( *it2 ).height( ); + if( height == 0 ) + height = 1; + ( *it ).setHeight( ( int ) ( ( *it ).height( ) * 100.0 + / height + 0.5 ) ); + it2 = it; + for( it2++; it2 != m_entries.end( ) && + ( *it2 ).dockPosition( ) != PMDockWidget::DockRight; ++it2 ) + if( ( *it2 ).dockPosition( ) == PMDockWidget::DockBottom ) + ( *it2 ).setHeight( ( int ) ( ( *it2 ).height( ) * 100.0 + / height + 0.5 ) ); + } + } +} + +PMViewLayout PMViewLayout::extractViewLayout( PMShell* shell ) +{ + PMViewLayout layout; + + QValueList< QValueList< PMViewLayoutEntry > > cols; + cols.append( QValueList< PMViewLayoutEntry >( ) ); + + // find docked widgets + recursiveExtractColumns( cols, cols.begin( ), 100, + shell->centralWidget( ) ); + + QValueListIterator< QValueList< PMViewLayoutEntry > > cit; + QValueListIterator< PMViewLayoutEntry > eit; + + for( cit = cols.begin( ); cit != cols.end( ); ++cit ) + for( eit = ( *cit ).begin( ); eit != ( *cit ).end( ); ++eit ) + layout.addEntry( *eit ); + + // find floating widgets + QPtrList list; + shell->manager( )->findFloatingWidgets( list ); + QPtrListIterator it( list ); + + for( ; it.current( ); ++it ) + { + kdDebug( PMArea ) << it.current( ) << " " << it.current( )->isVisible( ) << endl; + QWidget* w = it.current( )->getWidget( ); + if( w ) + { + bool invalid = false; + PMViewLayoutEntry e; + e.setDockPosition( PMDockWidget::DockNone ); + QPoint p = it.current( )->pos( ); + e.setFloatingPositionX( p.x( ) ); + e.setFloatingPositionY( p.y( ) ); + e.setFloatingWidth( it.current( )->width( ) ); + e.setFloatingHeight( it.current( )->height( ) ); + + if( w->inherits( "PMViewBase" ) ) + { + PMViewBase* v = ( PMViewBase* ) w; + e.setViewType( v->viewType( ) ); + PMViewOptions* vo = + PMViewFactory::theFactory( )->newOptionsInstance( v->viewType( ) ); + if( vo ) + { + v->saveViewConfig( vo ); + e.setCustomOptions( vo ); + } + } + else + invalid = true; + + if( !invalid ) + layout.addEntry( e ); + } + } + + return layout; +} + +void PMViewLayout::recursiveExtractColumns( + QValueList< QValueList< PMViewLayoutEntry > >& cols, + QValueList< QValueList< PMViewLayoutEntry > >::iterator cit, + int width, QWidget* widget ) +{ + if( !widget ) + return; + + if( widget->inherits( "PMDockWidget" ) ) + { + PMDockWidget* dw = ( PMDockWidget* ) widget; + QWidget* w = dw->getWidget( ); + if( w ) + { + bool colStart = true; + if( w->inherits( "PMDockSplitter" ) ) + { + PMDockSplitter* sp = ( PMDockSplitter* ) w; + if( sp->splitterOrientation( ) == Qt::Vertical ) + { + colStart = false; + // vertical splitter, split up the current column + int w1 = ( int ) ( width * 0.01 * sp->separatorPos( ) + 0.5 ); + int w2 = width - w1; + if( w1 == 0 ) w1++; + if( w2 == 0 ) w2++; + + QValueList< QValueList< PMViewLayoutEntry > >::iterator cit1 + = cols.insert( cit, QValueList< PMViewLayoutEntry >( ) ); + + recursiveExtractColumns( cols, cit1, w1, sp->getFirst( ) ); + recursiveExtractColumns( cols, cit, w2, sp->getLast( ) ); + } + } + if( colStart ) + { + // widget is a view, a horizontal splitter or a tab widget + // a new column starts + PMViewLayoutEntry e; + e.setColumnWidth( width ); + ( *cit ).append( e ); + recursiveExtractOneColumn( *cit, ( *cit ).begin( ), 100, dw ); + } + } + } +} + +void PMViewLayout::recursiveExtractOneColumn( + QValueList< PMViewLayoutEntry >& entries, + QValueList< PMViewLayoutEntry >::iterator eit, + int height, QWidget* widget ) +{ + if( !widget ) + return; + + if( widget->inherits( "PMDockWidget" ) ) + { + PMDockWidget* dw = ( PMDockWidget* ) widget; + QWidget* w = dw->getWidget( ); + if( w ) + { + if( w->inherits( "PMDockSplitter" ) ) + { + PMDockSplitter* sp = ( PMDockSplitter* ) w; + // splitter, split up the current column + int h1 = ( int ) ( height * 0.01 * sp->separatorPos( ) + 0.5 ); + int h2 = height - h1; + if( h1 == 0 ) h1++; + if( h2 == 0 ) h2++; + + ( *eit ).setHeight( h1 ); + ( *eit ).setDockPosition( PMDockWidget::DockRight ); + + PMViewLayoutEntry e; + e.setHeight( h2 ); + e.setDockPosition( PMDockWidget::DockBottom ); + QValueList< PMViewLayoutEntry >::iterator eit1 = eit; + eit1 = entries.insert( ++eit1, e ); + + recursiveExtractOneColumn( entries, eit, h1, sp->getFirst( ) ); + recursiveExtractOneColumn( entries, eit1, h2, sp->getLast( ) ); + } + else if( w->inherits( "PMDockTabGroup" ) ) + { + PMDockTabGroup* g = ( PMDockTabGroup* ) w; + int num = g->count( ); + QWidget* tw; + int i; + for( i = 0; i < num; i++ ) + { + tw = g->page( i ); + if( i == 0 ) + recursiveExtractOneColumn( entries, eit, height, tw ); + else + { + PMViewLayoutEntry e; + e.setHeight( height ); + e.setDockPosition( PMDockWidget::DockCenter ); + + eit++; + eit = entries.insert( eit, e ); + recursiveExtractOneColumn( entries, eit, height, tw ); + } + } + } + else + { + // a kpovmodeler view??? + if( w->inherits( "PMViewBase" ) ) + { + PMViewBase* v = ( PMViewBase* ) w; + ( *eit ).setViewType( v->viewType( ) ); + PMViewOptions* vo = + PMViewFactory::theFactory( )->newOptionsInstance( v->viewType( ) ); + if( vo ) + { + v->saveViewConfig( vo ); + ( *eit ).setCustomOptions( vo ); + } + } + } + } + } +} + +//=============== PMViewLayoutManager =================== + +PMViewLayoutManager::PMViewLayoutManager( ) +{ + m_layoutsLoaded = false; + m_layoutDisplayed = false; + loadData( ); +} + +PMViewLayoutManager::~PMViewLayoutManager( ) +{ +} + +void PMViewLayoutManager::setDefaultLayout( const QString& name ) +{ + m_defaultLayout = name; +} + +QStringList PMViewLayoutManager::availableLayouts( ) +{ + QStringList result; + QValueListIterator it; + + for( it = m_layouts.begin( ); it != m_layouts.end( ); ++it ) + result.push_back( ( *it ).name( ) ); + + return result; +} + +void PMViewLayoutManager::loadData( ) +{ + if( m_layoutsLoaded ) + m_layouts.clear( ); + + m_layoutsLoaded = true; + + QString fileName = locate( "data", "kpovmodeler/viewlayouts.xml" ); + if( fileName.isEmpty( ) ) + { + // Generate a default layout + // I have a feeling this shouldn't be here but hey, it works for now + // TODO Must find a way to move this cleanly to PMShell + PMViewLayout a; + a.setName( i18n( "Default" ) ); + PMViewLayoutEntry p; + p.setViewType( "treeview" ); + p.setDockPosition( PMDockWidget::DockRight ); + p.setHeight( 50 ); + p.setColumnWidth( 33 ); + a.addEntry( p ); + p.setViewType( "dialogview" ); + p.setDockPosition( PMDockWidget::DockBottom ); + p.setHeight( 50 ); + a.addEntry( p ); + p.setViewType( "glview" ); + p.setCustomOptions( new PMGLViewOptions( PMGLView::PMViewPosX ) ); + p.setDockPosition( PMDockWidget::DockRight ); + p.setHeight( 50 ); + p.setColumnWidth( 33 ); + a.addEntry( p ); + p.setCustomOptions( new PMGLViewOptions( PMGLView::PMViewNegY ) ); + p.setDockPosition( PMDockWidget::DockBottom ); + p.setHeight( 50 ); + a.addEntry( p ); + p.setCustomOptions( new PMGLViewOptions( PMGLView::PMViewPosZ ) ); + p.setDockPosition( PMDockWidget::DockRight ); + p.setHeight( 50 ); + p.setColumnWidth( 33 ); + a.addEntry( p ); + p.setCustomOptions( new PMGLViewOptions( PMGLView::PMViewCamera ) ); + p.setDockPosition( PMDockWidget::DockBottom ); + p.setHeight( 50 ); + a.addEntry( p ); + + m_layouts.append( a ); + m_defaultLayout = a.name( ); + + return; + } + + QFile file( fileName ); + if( !file.open( IO_ReadOnly ) ) + { + kdError( PMArea ) << i18n( "Could not open the view layouts file." ) + << endl; + return; + } + + QDomDocument doc( "VIEWLAYOUTS" ); + doc.setContent( &file ); + + QDomElement e = doc.documentElement( ); + m_defaultLayout = e.attribute( "default", "empty" ); + + QDomNode c = e.firstChild( ); + + QString str; + + while( !c.isNull( ) ) + { + if( c.isElement( ) ) + { + QDomElement ce = c.toElement( ); + PMViewLayout v; + v.loadData( ce ); + m_layouts.append( v ); + } + c = c.nextSibling( ); + } +} + +void PMViewLayoutManager::saveData( ) +{ + QString fileName = locateLocal( "data", "kpovmodeler/viewlayouts.xml" ); + if( fileName.isEmpty( ) ) + { + kdError( PMArea ) << i18n( "View layouts not found." ) << endl; + return; + } + QFile file( fileName ); + if( !file.open( IO_WriteOnly ) ) + { + kdError( PMArea ) << i18n( "Could not open the view layouts file." ) + << endl; + return; + } + QDomDocument doc( "VIEWLAYOUTS" ); + QDomElement e = doc.createElement( "viewlist" ); + e.setAttribute( "default", m_defaultLayout ); + + QValueListIterator it; + + for( it = m_layouts.begin( ); it != m_layouts.end( ); ++it ) + { + QDomElement l; + + l = doc.createElement( "viewlayout" ); + ( *it ).saveData( l, doc ); + e.appendChild( l ); + } + doc.appendChild( e ); + QTextStream str( &file ); + str.setEncoding( QTextStream::UnicodeUTF8 ); + str << doc.toString( ); + file.close( ); +} + +PMViewLayoutManager* PMViewLayoutManager::theManager( ) +{ + if( !s_pInstance ) + s_staticDeleter.setObject( s_pInstance, new PMViewLayoutManager( ) ); + return s_pInstance; +} + +void PMViewLayoutManager::displayLayout( const QString& name, PMShell* shell ) +{ + PMViewLayout* v_layout = findLayout( name ); + + if( v_layout ) + { + // Destroy the existing dock widgets + if( m_layoutDisplayed ) + { + QWidgetList lst; + + if( shell->centralWidget( ) ) + shell->manager( )->findChildDockWidget( shell->centralWidget( ), lst ); + while( lst.first( ) ) + { + ( ( PMDockWidget* )lst.first( ) )->undock( ); + ( ( PMDockWidget* )lst.first( ) )->close( ); + lst.remove( ); + } + + QPtrList flist; + shell->manager( )->findFloatingWidgets( flist ); + while( flist.first( ) ) + { + flist.first( )->undock( ); + flist.first( )->close( ); + flist.remove( ); + } + } + // Create the new layout + v_layout->displayLayout( shell ); + m_layoutDisplayed = true; + } +} + +void PMViewLayoutManager::displayDefaultLayout( PMShell* shell ) +{ + displayLayout( m_defaultLayout, shell ); +} + +PMViewLayout* PMViewLayoutManager::findLayout( const QString& name ) +{ + QValueListIterator it; + for( it = m_layouts.begin( ); it != m_layouts.end( ) && + ( *it ).name( ) != name; ++it ); + + if( it == m_layouts.end( ) ) + return 0; + return &( *it ); +} + +void PMViewLayoutManager::fillPopupMenu( KPopupMenu* pMenu ) +{ + QStringList lst = availableLayouts( ); + QStringList::ConstIterator it = lst.begin( ); + + pMenu->clear( ); + if( it != lst.end( ) ) + { + for( ; it != lst.end( ); ++it ) + pMenu->insertItem( ( *it ) ); + } +} + +void PMViewLayoutManager::addLayout( const QString& name ) +{ + PMViewLayout a; + + if( m_layouts.isEmpty( ) ) + m_defaultLayout = name; + a.setName( name ); + m_layouts.append( a ); +} + +void PMViewLayoutManager::removeLayout( const QString& name ) +{ + QValueListIterator it; + for( it = m_layouts.begin( ); it != m_layouts.end( ) && + ( *it ).name( ) != name; ++it ); + + if( it != m_layouts.end( ) ) + m_layouts.remove( it ); +} + + +PMSaveViewLayoutDialog::PMSaveViewLayoutDialog( PMShell* parent, + const char* name ) + : KDialogBase( parent, name, true, i18n( "Save View Layout" ), + KDialogBase::Ok | KDialogBase::Cancel ) +{ + m_pShell = parent; + + setButtonOK( KStdGuiItem::save() ); + enableButtonOK( false ); + + QWidget* w = new QWidget( this ); + QVBoxLayout* vl = new QVBoxLayout( w, 0, KDialog::spacingHint( ) ); + + QLabel* l = new QLabel( i18n( "Enter view layout name:" ), w ); + vl->addWidget( l ); + + m_pLayoutName = new QLineEdit( w ); + vl->addWidget( m_pLayoutName ); + connect( m_pLayoutName, SIGNAL( textChanged( const QString& ) ), + SLOT( slotNameChanged( const QString& ) ) ); + + QListBox* lb = new QListBox( w ); + vl->addWidget( lb ); + connect( lb, SIGNAL( highlighted( const QString& ) ), + SLOT( slotNameSelected( const QString& ) ) ); + lb->insertStringList( PMViewLayoutManager::theManager( ) + ->availableLayouts( ) ); + + setMainWidget( w ); + setInitialSize( QSize( 300, 200 ) ); +} + +PMSaveViewLayoutDialog::~PMSaveViewLayoutDialog( ) +{ +} + +void PMSaveViewLayoutDialog::slotOk( ) +{ + QString name = m_pLayoutName->text( ); + + PMViewLayoutManager* m = PMViewLayoutManager::theManager( ); + PMViewLayout* layout = m->findLayout( name ); + + PMViewLayout newLayout = PMViewLayout::extractViewLayout( m_pShell ); + newLayout.setName( name ); + + if( layout ) + *layout = newLayout; + else + m->addLayout( newLayout ); + + m->saveData( ); + + KDialogBase::slotOk( ); +} + +void PMSaveViewLayoutDialog::slotNameChanged( const QString& s ) +{ + enableButtonOK( !s.isEmpty( ) ); +} + +void PMSaveViewLayoutDialog::slotNameSelected( const QString& s ) +{ + m_pLayoutName->setText( s ); +} + +#include "pmviewlayoutmanager.moc" diff --git a/kpovmodeler/pmviewlayoutmanager.h b/kpovmodeler/pmviewlayoutmanager.h new file mode 100644 index 00000000..c0246c5d --- /dev/null +++ b/kpovmodeler/pmviewlayoutmanager.h @@ -0,0 +1,306 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2002 by Luis Carvalho + email : lpassos@mail.telepac.pt + copyright : (C) 2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMVIEWLAYOUTMANAGER_H +#define PMVIEWLAYOUTMANAGER_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include "pmdockwidget.h" +#include "pmviewbase.h" + +class KConfig; +class QDomElement; +class QLineEdit; +class PMShell; + +/** + * Class used internally by @ref PMViewLayout + * + * This class maintains all the information needed to create a docked view. + */ +class PMViewLayoutEntry +{ +public: + /** + * Constructor + */ + PMViewLayoutEntry( ); + /** + * Copy constructor + */ + PMViewLayoutEntry( const PMViewLayoutEntry& e ); + /** + * Destructor + */ + ~PMViewLayoutEntry( ); + + QString viewType( ) const { return m_viewType; } + void setViewType( const QString& vt ); + + PMDockWidget::DockPosition dockPosition( ) const { return m_dockPosition; } + void setDockPosition( PMDockWidget::DockPosition i ); + + int columnWidth( ) const { return m_columnWidth; } + void setColumnWidth( int i ); + + int height( ) const { return m_height; } + void setHeight( int i ); + + int floatingHeight( ) const { return m_floatingHeight; } + void setFloatingHeight( int h ) { m_floatingHeight = h; } + + int floatingWidth( ) const { return m_floatingWidth; } + void setFloatingWidth( int w ) { m_floatingWidth = w; } + + int floatingPositionX( ) const { return m_floatingPositionX; } + void setFloatingPositionX( int p ) { m_floatingPositionX = p; } + int floatingPositionY( ) const { return m_floatingPositionY; } + void setFloatingPositionY( int p ) { m_floatingPositionY = p; } + + void loadData( QDomElement& e ); + void saveData( QDomElement& e ) const; + + PMViewOptions* customOptions( ) const { return m_pCustomOptions; } + void setCustomOptions( PMViewOptions* o ); + + const QString dockPositionAsString( ); + const QString viewTypeAsString( ); + +private: + QString m_viewType; + PMDockWidget::DockPosition m_dockPosition; + int m_columnWidth; + int m_height; + int m_floatingWidth; + int m_floatingHeight; + int m_floatingPositionX; + int m_floatingPositionY; + PMViewOptions* m_pCustomOptions; +}; + +/** + * Class used internally by @ref PMViewLayoutManager + * + * This class maintains a named layout. It basically stores all views + * associated with that layout. + */ +class PMViewLayout +{ +public: + typedef QValueList< PMViewLayoutEntry >::iterator iterator; + /** + * Constructor + */ + PMViewLayout( ); + /** + * Copy constructor + */ + PMViewLayout( const PMViewLayout& vl ); + /** + * Destructor + */ + ~PMViewLayout( ) { } + + /** + * Assignment operator + */ + PMViewLayout& operator = ( const PMViewLayout& vl ); + + QString name( ) const { return m_name; } + + void loadData( QDomElement& e ); + + void saveData( QDomElement& e, QDomDocument& doc ) const; + /** + * Destroy all dock widgets in PMShell and create the new ones + */ + void displayLayout( PMShell* shell ); + /** + * Sets the name of the layout + */ + void setName( const QString& n ); + /** + * + * Add a new entry to the layout. By default it adds the entry at the end + * of the list. If a position is given it adds the entry at the indicated + * position + */ + void addEntry( const PMViewLayoutEntry& e, int index = -1 ); + /** + * Removes the entry at the given position + */ + void removeEntry( int index ); + /** + * Returns an iterator to the first entry + */ + iterator begin( ) { return m_entries.begin( ); } + /** + * Returns an iterator to the last entry + */ + iterator end( ) { return m_entries.end( ); } + /** + * Returns an iterator to the n-th entry + */ + iterator at( int i ) { return m_entries.at( i ); } + /** + * Returns the entry at the given position + */ + PMViewLayoutEntry& operator[]( int index ) { return m_entries[ index ]; } + /** + * Normalizes the column width and view heights + */ + void normalize( ); + + /** + * Extracts the view layout from the current window + */ + static PMViewLayout extractViewLayout( PMShell* shell ); +private: + static void recursiveExtractColumns( + QValueList< QValueList< PMViewLayoutEntry > >& cols, + QValueList< QValueList< PMViewLayoutEntry > >::iterator cit, + int width, QWidget* widget ); + + static void recursiveExtractOneColumn( + QValueList< PMViewLayoutEntry >& entries, + QValueList< PMViewLayoutEntry >::iterator eit, + int height, QWidget* widget ); + + QString m_name; + QValueList< PMViewLayoutEntry > m_entries; +}; + +/** + * Singleton that contains the view layouts available. + * + * It interacts with @ref PMShell to create the view layouts. + * The class maintains a list of layouts as well as the name of the default + * layout. The layouts are stored in a XML file caled viewlayouts.xml. + */ +class PMViewLayoutManager +{ +public: + /** + * Destructor + */ + ~PMViewLayoutManager( ); + /** + * Returns the manager instance (singleton) + */ + static PMViewLayoutManager* theManager( ); + + /** + * Returns the list of available view layouts + */ + QStringList availableLayouts( ); + /** + * Sets the default layout + */ + void setDefaultLayout( const QString& name ); + /** + * Returns the default layout + */ + QString defaultLayout( ) const { return m_defaultLayout; } + /** + * Destroy all dock widgets in PMShell and create the new ones + */ + void displayLayout( const QString& name, PMShell* shell ); + /** + * Displays the layout indicated as default + */ + void displayDefaultLayout( PMShell* shell ); + /** + * Loads all layouts from the configuration file + */ + void loadData( ); + /** + * Saves the current layout collection to the configuration file + */ + void saveData( ); + /** + * Add a new empty layout + */ + void addLayout( const QString& name ); + /** + * Add a new layout + */ + void addLayout( const PMViewLayout& l ) { m_layouts.append( l ); } + /** + * Remove a layout + */ + void removeLayout( const QString& name ); + /** + * Get a known layout + */ + PMViewLayout* findLayout( const QString& name ); + /** + * Returns the list of available layouts + */ + QValueList layouts( ) { return m_layouts; } + /** + * Sets the list of available layouts + */ + void setLayouts( const QValueList& l ) { m_layouts = l; } + /** + * Fill the available layouts menu + */ + void fillPopupMenu( KPopupMenu* pMenu ); +private: + /** + * Constructor + */ + PMViewLayoutManager( ); + + bool m_layoutsLoaded; + bool m_layoutDisplayed; + QString m_defaultLayout; + QValueList< PMViewLayout > m_layouts; + + static PMViewLayoutManager* s_pInstance; + static KStaticDeleter s_staticDeleter; +}; + + +class PMSaveViewLayoutDialog : public KDialogBase +{ + Q_OBJECT +public: + PMSaveViewLayoutDialog( PMShell* parent, const char* name = 0 ); + ~PMSaveViewLayoutDialog( ); +protected slots: + virtual void slotOk( ); + void slotNameChanged( const QString& ); + void slotNameSelected( const QString& ); +private: + QLineEdit* m_pLayoutName; + PMShell* m_pShell; +}; + +#endif diff --git a/kpovmodeler/pmviewstructure.cpp b/kpovmodeler/pmviewstructure.cpp new file mode 100644 index 00000000..966df90b --- /dev/null +++ b/kpovmodeler/pmviewstructure.cpp @@ -0,0 +1,127 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#include "pmviewstructure.h" + +/* +void PMViewStructure::render( ) +{ + glVertexPointer( 3, GL_DOUBLE, sizeof( PMVector ), points.data( ) ); + glDrawElements( GL_LINES, lines.size( ) * 2, + GL_UNSIGNED_INT, lines.data( ) ); +} +*/ + +PMViewStructure::PMViewStructure( ) +{ + m_parameterKey = -1; +} + +PMViewStructure::PMViewStructure( unsigned int n, unsigned int l, unsigned int f ) +{ + m_points.resize( n ); + m_lines.resize( l ); + m_faces.resize( f ); + m_parameterKey = -1; +} + +PMViewStructure::PMViewStructure( const PMViewStructure& vs ) +{ + m_points = vs.m_points; + m_lines = vs.m_lines; + m_faces = vs.m_faces; + m_parameterKey = vs.m_parameterKey; +} + +PMViewStructure::PMViewStructure( const PMViewStructure* vs ) +{ + m_points = vs->m_points; + m_lines = vs->m_lines; + m_faces = vs->m_faces; + m_parameterKey = vs->m_parameterKey; +} + +PMViewStructure& PMViewStructure::operator = ( const PMViewStructure& vs ) +{ + m_lines = vs.m_lines; + m_points = vs.m_points; + m_faces = vs.m_faces; + + return *this; +} + +bool PMViewStructure::operator == ( const PMViewStructure& vs ) const +{ + return ( ( m_lines.data( ) == vs.m_lines.data( ) ) + && ( m_points.data( ) == vs.m_points.data( ) ) + && ( m_faces == vs.m_faces ) ); +} + +bool PMViewStructure::operator != ( const PMViewStructure& vs ) const +{ + return ( ( m_lines.data( ) != vs.m_lines.data( ) ) + || ( m_points.data( ) != vs.m_points.data( ) ) + || !( m_faces == vs.m_faces ) ); +} + + +PMBoundingBox::PMBoundingBox( const PMVector& min, const PMVector& max ) +{ + m_bValid = true; + m_min = min; + m_max = max; +} + +PMBoundingBox::PMBoundingBox( ) +{ + m_bValid = false; + m_min = PMVector( 0.0, 0.0, 0.0 ); + m_max = PMVector( 0.0, 0.0, 0.0 ); +} + +void PMBoundingBox::mergeWith( const PMBoundingBox& box ) +{ + if( m_bValid ) + { + if( box.m_bValid ) + { + if( box.m_min.x( ) < m_min.x( ) ) + m_min.setX( box.m_min.x( ) ); + if( box.m_min.y( ) < m_min.y( ) ) + m_min.setY( box.m_min.y( ) ); + if( box.m_min.z( ) < m_min.z( ) ) + m_min.setZ( box.m_min.z( ) ); + + if( box.m_max.x( ) > m_max.x( ) ) + m_max.setX( box.m_max.x( ) ); + if( box.m_max.y( ) > m_max.y( ) ) + m_max.setY( box.m_max.y( ) ); + if( box.m_max.z( ) > m_max.z( ) ) + m_max.setZ( box.m_max.z( ) ); + } + } + else + { + if( box.m_bValid ) + { + m_bValid = true; + m_max = box.m_max; + m_min = box.m_min; + } + } +} diff --git a/kpovmodeler/pmviewstructure.h b/kpovmodeler/pmviewstructure.h new file mode 100644 index 00000000..5356466b --- /dev/null +++ b/kpovmodeler/pmviewstructure.h @@ -0,0 +1,222 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + + +#ifndef PMVIEWSTRUCTURE_H +#define PMVIEWSTRUCTURE_H + +#include "pmface.h" +#include "pmpoint.h" +#include "pmline.h" +#include "pmmatrix.h" +#include "pmobject.h" +#include "pmvector.h" + +/** + * Represents the view structure (points, lines, faces) of an object + * + * Faces are not implemented yet but are needed later to calculate the view + * structure of csg objects + */ + +class PMViewStructure +{ + friend class PMObject; +public: + /** + * Creates an empty view structure + */ + PMViewStructure( ); + /** + * Creates a view structure with n points, l lines and f faces. + */ + PMViewStructure( unsigned int n, unsigned int l, unsigned int f = 0 ); + /** + * Creates a copy of the view structure. m_points, m_lines and m_faces are shared + */ + PMViewStructure( const PMViewStructure& vs ); + /** + * Creates a copy of the view structure. m_points, m_lines anf m_faces are shared + */ + PMViewStructure( const PMViewStructure* vs ); + + /** + * Returns a reference to the array of points + */ + PMPointArray& points( ) { return m_points; } + /** + * Returns a reference to the array of lines + */ + PMLineArray& lines( ) { return m_lines; } + /** + * Returns a refrence to the array of faces + */ + PMFaceArray& faces( ) { return m_faces; } + /** + * Returns the parameter key + */ + int parameterKey( ) const { return m_parameterKey; } + /** + * Sets the parameter key + */ + void setParameterKey( int k ) { m_parameterKey = k; } + + /** + * Assigns the view structure to this view structure. + * The points and lines are shared + */ + PMViewStructure& operator = ( const PMViewStructure& vs ); + /** + * Returns true if the view structures share the same points and lines + */ + bool operator == ( const PMViewStructure& vs ) const; + /** + * Returns false if the view structures share the same points and lines + */ + bool operator != ( const PMViewStructure& vs ) const; +protected: + /** + * Not transformed points, can be shared between PMObjects + * of the same type. m_points.data( ) can be used as vertex array. + * + * Optimized for fast rendering. + */ + PMPointArray m_points; + /** + * Lines to display. m_lines.data( ) can be used by glDrawElements. + * + * Optimized for fast rendering. + */ + PMLineArray m_lines; + /** + * Faces to display. + */ + PMFaceArray m_faces; + /** + * View structure parameter key. + * + * Each class can have parameters that modifies the number of lines and + * points of a view structure (detail level). + * + * The framework determines if the view structure is up to date by + * comparing the key with the parameter key of the corresponding class. + */ + int m_parameterKey; +}; + +/** + * Class for bounding boxes of PMObjects + */ +class PMBoundingBox +{ +public: + /** + * Creates a bounding box with min and max vectors + */ + PMBoundingBox( const PMVector& min, const PMVector& max ); + /** + * Creates an invalid bounding box. @ref PMObject::boundingBox() returns + * an invalid bounding box, if the object has none. + */ + PMBoundingBox( ); + + /** + * Returns the minimum coordinates + */ + PMVector min( ) const { return m_min; } + /** + * Returns the maximum coordinates + */ + PMVector max( ) const { return m_max; } + /** + * Returns the minumum x coordinate + */ + double minX( ) const { return m_min.x( ); } + /** + * Returns the minumum y coordinate + */ + double minY( ) const { return m_min.y( ); } + /** + * Returns the minumum z coordinate + */ + double minZ( ) const { return m_min.z( ); } + /** + * Returns the maximum x coordinate + */ + double maxX( ) const { return m_max.x( ); } + /** + * Returns the maximum y coordinate + */ + double maxY( ) const { return m_max.y( ); } + /** + * Returns the maximum z coordinate + */ + double maxZ( ) const { return m_max.z( ); } + /** + * Sets the minimum coordinates + */ + void setMin( const PMVector& min ) { m_min = min; } + /** + * Sets the maximum coordinates + */ + void setMax( const PMVector& max ) { m_max = max; } + /** + * Sets the minimum x coordinate + */ + void setMinX( const double c ) { m_min.setX( c ); } + /** + * Sets the minimum y coordinate + */ + void setMinY( const double c ) { m_min.setY( c ); } + /** + * Sets the minimum z coordinate + */ + void setMinZ( const double c ) { m_min.setZ( c ); } + /** + * Sets the maximum x coordinate + */ + void setMaxX( const double c ) { m_max.setX( c ); } + /** + * Sets the maximum y coordinate + */ + void setMaxY( const double c ) { m_max.setY( c ); } + /** + * Sets the maximum z coordinate + */ + void setMaxZ( const double c ) { m_max.setZ( c ); } + + /** + * Returns true, if the bounding box is valid + */ + bool isValid( ) const { return m_bValid; } + /** + * Sets the valid flag to v + */ + void setValid( bool v ) { m_bValid = v; } + + /** + * Merges the two bounding boxes + */ + void mergeWith( const PMBoundingBox& box ); + +private: + bool m_bValid; + PMVector m_min, m_max; +}; + +#endif diff --git a/kpovmodeler/pmwarp.cpp b/kpovmodeler/pmwarp.cpp new file mode 100644 index 00000000..76d58cf3 --- /dev/null +++ b/kpovmodeler/pmwarp.cpp @@ -0,0 +1,548 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + +#include "pmxmlhelper.h" +#include "pmvector.h" +#include "pmwarp.h" +#include "pmwarpedit.h" +#include "pmmemento.h" +#include "pmenumproperty.h" + +#include + +const PMVector directionDefault = PMVector( 1.0, 0.0, 0.0 ); +const PMVector offsetDefault = PMVector( 0.0, 0.0, 0.0 ); +const PMVector flipDefault = PMVector( 0.0, 0.0, 0.0 ); +const PMVector locationDefault = PMVector( 0.0, 0.0, 0.0 ); +const double radiusDefault = 0; +const double strengthDefault = 0; +const double falloffDefault = 0; +const bool inverseDefault = false; +const PMVector repeatDefault = PMVector( 0.0, 0.0, 0.0 ); +const PMVector turbulenceDefault = PMVector( 0.0, 0.0, 0.0 ); +const PMVector valueVectorDefault = PMVector( 0.0, 0.0, 0.0 ); +const int octavesDefault = 6; +const double omegaDefault = 0.5; +const double lambdaDefault = 2.0; +const PMVector orientationDefault = PMVector( 0.0, 0.0, 1.0 ); +const double distExpDefault = 0.0; +const double majorRadiusDefault = 1.0; + +PMDefinePropertyClass( PMWarp, PMWarpProperty ); +PMDefineEnumPropertyClass( PMWarp, PMWarp::PMWarpType, PMWarpTypeProperty ); + +PMMetaObject* PMWarp::s_pMetaObject = 0; +PMObject* createNewWarp( PMPart* part ) +{ + return new PMWarp( part ); +} + +PMWarp::PMWarp( PMPart* part ) + : Base( part ) +{ + m_warpType = PMWarp::Repeat; + m_direction = directionDefault; + m_offset = offsetDefault; + m_flip = flipDefault; + m_location = locationDefault; + m_radius = radiusDefault; + m_strength = strengthDefault; + m_falloff = falloffDefault; + m_inverse = inverseDefault; + m_repeat = repeatDefault; + m_turbulence = turbulenceDefault; + m_valueVector = valueVectorDefault; + m_octaves = octavesDefault; + m_omega = omegaDefault; + m_lambda = lambdaDefault; + m_orientation = orientationDefault; + m_distExp = distExpDefault; + m_majorRadius = majorRadiusDefault; +} + +PMWarp::PMWarp( const PMWarp& w ) + : Base( w ) +{ + m_warpType = w.m_warpType; + m_direction = w.m_direction; + m_offset = w.m_offset; + m_flip = w.m_flip; + m_location = w.m_location; + m_radius = w.m_radius; + m_strength = w.m_strength; + m_falloff = w.m_falloff; + m_inverse = w.m_inverse; + m_repeat = w.m_repeat; + m_turbulence = w.m_turbulence; + m_valueVector = w.m_valueVector; + m_octaves = w.m_octaves; + m_omega = w.m_omega; + m_lambda = w.m_lambda; + m_orientation = w.m_orientation; + m_distExp = w.m_distExp; + m_majorRadius = w.m_majorRadius; +} + +PMWarp::~PMWarp( ) +{ +} + +QString PMWarp::description( ) const +{ + return i18n( "warp" ); +} + +void PMWarp::serialize( QDomElement& e, QDomDocument& /*doc*/ ) const +{ + bool mapping = false; + + switch( m_warpType ) + { + case PMWarp::Repeat: + e.setAttribute( "warp_type", "repeat"); + e.setAttribute( "direction", m_direction.serializeXML( ) ); + e.setAttribute( "offset", m_offset.serializeXML( ) ); + e.setAttribute( "flip", m_flip.serializeXML( ) ); + break; + case PMWarp::BlackHole: + e.setAttribute( "warp_type", "black hole"); + e.setAttribute( "location", m_location.serializeXML( ) ); + e.setAttribute( "radius", m_radius ); + e.setAttribute( "strength", m_strength ); + e.setAttribute( "falloff", m_falloff ); + e.setAttribute( "inverse", m_inverse ); + e.setAttribute( "repeat", m_repeat.serializeXML( ) ); + e.setAttribute( "turbulence", m_turbulence.serializeXML( ) ); + break; + case PMWarp::Turbulence: + e.setAttribute( "warp_type", "turbulence"); + e.setAttribute( "turbulence", m_valueVector.serializeXML( ) ); + e.setAttribute( "octaves", m_octaves ); + e.setAttribute( "omega", m_omega ); + e.setAttribute( "lambda", m_lambda ); + break; + case PMWarp::Cylindrical: + mapping = true; + e.setAttribute( "warp_type", "cylindrical" ); + break; + case PMWarp::Spherical: + mapping = true; + e.setAttribute( "warp_type", "spherical" ); + break; + case PMWarp::Toroidal: + mapping = true; + e.setAttribute( "warp_type", "toroidal" ); + e.setAttribute( "major_radius", m_majorRadius ); + break; + case PMWarp::Planar: + mapping = true; + e.setAttribute( "warp_type", "planar" ); + break; + } + + if ( mapping ) + { + e.setAttribute( "orientation", m_orientation.serializeXML( ) ); + e.setAttribute( "dist_exp", m_distExp ); + } +} + +void PMWarp::readAttributes( const PMXMLHelper& h ) +{ + bool mapping = false; + QString str = h.stringAttribute( "warp_type", "repeat" ); + + if( str == "repeat" ) + { + m_warpType = PMWarp::Repeat; + m_direction = h.vectorAttribute( "direction", directionDefault ); + m_offset = h.vectorAttribute( "offset", offsetDefault ); + m_flip = h.vectorAttribute( "flip", flipDefault ); + } + else if( str == "black hole" ) + { + m_warpType = PMWarp::BlackHole; + m_location = h.vectorAttribute( "location", locationDefault ); + m_radius = h.doubleAttribute( "radius", radiusDefault ); + m_strength = h.doubleAttribute( "strength", strengthDefault ); + m_falloff = h.doubleAttribute( "falloff", falloffDefault ); + m_inverse = h.boolAttribute( "inverse", inverseDefault ); + m_repeat = h.vectorAttribute( "repeat", repeatDefault ); + m_turbulence = h.vectorAttribute( "turbulence", turbulenceDefault ); + } + else if( str == "turbulence" ) + { + m_warpType = PMWarp::Turbulence; + m_valueVector = h.vectorAttribute( "turbulence", valueVectorDefault ); + m_octaves = h.intAttribute( "octaves", octavesDefault ); + m_omega = h.doubleAttribute( "omega", omegaDefault ); + m_lambda = h.doubleAttribute( "lambda", lambdaDefault ); + } + else if( str == "cylindrical" ) + { + mapping = true; + m_warpType = PMWarp::Cylindrical; + } + else if( str == "spherical" ) + { + mapping = true; + m_warpType = PMWarp::Spherical; + } + else if( str == "toroidal" ) + { + mapping = true; + m_warpType = PMWarp::Toroidal; + m_majorRadius = h.doubleAttribute( "major_radius", majorRadiusDefault ); + } + else if( str == "planar" ) + { + mapping = true; + m_warpType = PMWarp::Planar; + } + + if( mapping ) + { + m_orientation = h.vectorAttribute( "orientation", orientationDefault ); + m_distExp = h.doubleAttribute( "dist_exp", distExpDefault ); + } +} + +PMMetaObject* PMWarp::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Warp", Base::metaObject( ), + createNewWarp ); + + PMWarpTypeProperty* p = new PMWarpTypeProperty( + "warpType", &PMWarp::setWarpType, &PMWarp::warpType ); + p->addEnumValue( "Repeat", Repeat ); + p->addEnumValue( "BlackHole", BlackHole ); + p->addEnumValue( "Turbulence", Turbulence ); + p->addEnumValue( "Cylindrical", Cylindrical ); + p->addEnumValue( "Spherical", Spherical ); + p->addEnumValue( "Toroidal", Toroidal ); + p->addEnumValue( "Planar", Planar ); + s_pMetaObject->addProperty( p ); + + s_pMetaObject->addProperty( + new PMWarpProperty( "direction", &PMWarp::setDirection, &PMWarp::direction ) ); + s_pMetaObject->addProperty( + new PMWarpProperty( "offset", &PMWarp::setOffset, &PMWarp::offset ) ); + s_pMetaObject->addProperty( + new PMWarpProperty( "flip", &PMWarp::setFlip, &PMWarp::flip ) ); + s_pMetaObject->addProperty( + new PMWarpProperty( "location", &PMWarp::setLocation, &PMWarp::location ) ); + s_pMetaObject->addProperty( + new PMWarpProperty( "radius", &PMWarp::setRadius, &PMWarp::radius ) ); + s_pMetaObject->addProperty( + new PMWarpProperty( "strength", &PMWarp::setStrength, &PMWarp::strength ) ); + s_pMetaObject->addProperty( + new PMWarpProperty( "falloff", &PMWarp::setFalloff, &PMWarp::falloff ) ); + s_pMetaObject->addProperty( + new PMWarpProperty( "inverse", &PMWarp::setInverse, &PMWarp::inverse ) ); + s_pMetaObject->addProperty( + new PMWarpProperty( "repeat", &PMWarp::setRepeat, &PMWarp::repeat ) ); + s_pMetaObject->addProperty( + new PMWarpProperty( "turbulence", &PMWarp::setTurbulence, &PMWarp::turbulence ) ); + s_pMetaObject->addProperty( + new PMWarpProperty( "valueVector", &PMWarp::setValueVector, &PMWarp::valueVector ) ); + s_pMetaObject->addProperty( + new PMWarpProperty( "octaves", &PMWarp::setOctaves, &PMWarp::octaves ) ); + s_pMetaObject->addProperty( + new PMWarpProperty( "omega", &PMWarp::setOmega, &PMWarp::omega ) ); + s_pMetaObject->addProperty( + new PMWarpProperty( "lambda", &PMWarp::setLambda, &PMWarp::lambda ) ); + s_pMetaObject->addProperty( + new PMWarpProperty( "orientation", &PMWarp::setOrientation, &PMWarp::orientation ) ); + s_pMetaObject->addProperty( + new PMWarpProperty( "dist_exp", &PMWarp::setDistExp, &PMWarp::distExp ) ); + s_pMetaObject->addProperty( + new PMWarpProperty( "major_radius", &PMWarp::setMajorRadius, &PMWarp::majorRadius ) ); + } + return s_pMetaObject; +} + +void PMWarp::cleanUp( ) const +{ + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} + +void PMWarp::setWarpType( PMWarpType c ) +{ + if( c != m_warpType ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMWarpTypeID, m_warpType ); + m_warpType = c; + } +} + +void PMWarp::setDirection( const PMVector& c ) +{ + if( c != m_direction ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMDirectionID, m_direction ); + m_direction = c; + } +} + +void PMWarp::setOffset( const PMVector& c ) +{ + if( c != m_offset ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMOffsetID, m_offset ); + m_offset = c; + } +} + +void PMWarp::setFlip( const PMVector& c ) +{ + if( c != m_flip ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFlipID, m_flip ); + m_flip = c; + } +} + +void PMWarp::setLocation( const PMVector& c ) +{ + if( c != m_location ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMLocationID, m_location ); + m_location = c; + } +} + +void PMWarp::setRadius( const double c ) +{ + if( c != m_radius ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRadiusID, m_radius ); + m_radius = c; + } +} + +void PMWarp::setStrength( const double c ) +{ + if( c != m_strength ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMStrengthID, m_strength ); + m_strength = c; + } +} + +void PMWarp::setFalloff( const double c ) +{ + if( c != m_falloff ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFalloffID, m_falloff ); + m_falloff = c; + } +} + +void PMWarp::setInverse( const bool c ) +{ + if( c != m_inverse ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMInverseID, m_inverse ); + m_inverse = c; + } +} + +void PMWarp::setRepeat( const PMVector& c ) +{ + if( c != m_repeat ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRepeatID, m_repeat ); + m_repeat = c; + } +} + +void PMWarp::setTurbulence( const PMVector& c ) +{ + if( c != m_turbulence ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMTurbulenceID, m_turbulence ); + m_turbulence = c; + } +} + +void PMWarp::setValueVector( const PMVector& c ) +{ + if( c != m_valueVector ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMValueVectorID, m_valueVector ); + m_valueVector = c; + } +} + +void PMWarp::setOctaves( const int c ) +{ + if( c != m_octaves ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMOctavesID, m_octaves ); + m_octaves = c; + } +} + +void PMWarp::setOmega( const double c ) +{ + if( c != m_omega ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMOmegaID, m_omega ); + m_omega = c; + } +} + +void PMWarp::setLambda( const double c ) +{ + if( c != m_lambda ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMLambdaID, m_lambda ); + m_lambda = c; + } +} + +void PMWarp::setOrientation( const PMVector& v ) +{ + if ( v != m_orientation ) + { + if ( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMOrientationID, m_orientation ); + m_orientation = v; + } +} + +void PMWarp::setDistExp( const double c ) +{ + if ( c != m_distExp ) + { + if ( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMDistExpID, m_distExp ); + m_distExp = c; + } +} + +void PMWarp::setMajorRadius( const double c ) +{ + if ( c != m_majorRadius ) + { + if ( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMMajorRadiusID, m_majorRadius ); + m_majorRadius = c; + } +} + +PMDialogEditBase* PMWarp::editWidget( QWidget* parent ) const +{ + return new PMWarpEdit( parent ); +} + +void PMWarp::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMWarpTypeID: + setWarpType( ( PMWarpType )data->intData( ) ); + break; + case PMDirectionID: + setDirection( data->vectorData( ) ); + break; + case PMOffsetID: + setOffset( data->vectorData( ) ); + break; + case PMFlipID: + setFlip( data->vectorData( ) ); + break; + case PMLocationID: + setLocation( data->vectorData( ) ); + break; + case PMRadiusID: + setRadius( data->doubleData( ) ); + break; + case PMStrengthID: + setStrength( data->doubleData( ) ); + break; + case PMFalloffID: + setFalloff( data->doubleData( ) ); + break; + case PMInverseID: + setInverse( data->boolData( ) ); + break; + case PMRepeatID: + setRepeat( data->vectorData( ) ); + break; + case PMTurbulenceID: + setTurbulence( data->vectorData( ) ); + break; + case PMValueVectorID: + setValueVector( data->vectorData( ) ); + break; + case PMOctavesID: + setOctaves( data->intData( ) ); + break; + case PMOmegaID: + setOmega( data->doubleData( ) ); + break; + case PMLambdaID: + setLambda( data->doubleData( ) ); + break; + case PMOrientationID: + setOrientation( data->vectorData( ) ); + break; + case PMDistExpID: + setDistExp( data->doubleData( ) ); + break; + case PMMajorRadiusID: + setMajorRadius( data->doubleData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMWarp::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} diff --git a/kpovmodeler/pmwarp.h b/kpovmodeler/pmwarp.h new file mode 100644 index 00000000..a6ed213b --- /dev/null +++ b/kpovmodeler/pmwarp.h @@ -0,0 +1,162 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMWARP_H +#define PMWARP_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmobject.h" + +/** + * Class for Repeat Warps + */ + +class PMWarp : public PMObject +{ + typedef PMObject Base; +public: + enum PMWarpType { Repeat, BlackHole, Turbulence, + Cylindrical, Spherical, Toroidal, Planar }; + + /** + * Creates a PMWarp + */ + PMWarp( PMPart* part ); + /** + * Copy constructor + */ + PMWarp( const PMWarp& w ); + /** + * deletes the PMWarp + */ + virtual ~PMWarp( ); + + /** */ + virtual PMObject* copy( ) const { return new PMWarp( *this ); } + /** */ + virtual QString description( ) const; + + /** */ + virtual PMMetaObject* metaObject( ) const; + /** */ + virtual void cleanUp( ) const; + + /** */ + virtual void serialize( QDomElement& e, QDomDocument& doc ) const; + /** */ + virtual void readAttributes( const PMXMLHelper& h ); + + /** + * Returns a new @ref PMWarpEdit + */ + virtual PMDialogEditBase* editWidget( QWidget* parent ) const; + /** + * Returns the name of the pixmap that is displayed in the tree view + * and dialog view + */ + virtual QString pixmap( ) const { return QString( "pmwarp" ); } + + PMWarpType warpType( ) const { return m_warpType; } + void setWarpType( PMWarpType c ); + + PMVector direction( ) const { return m_direction; } + void setDirection( const PMVector& c ); + PMVector offset( ) const { return m_offset; } + void setOffset( const PMVector& c ); + PMVector flip( ) const { return m_flip; } + void setFlip( const PMVector& c ); + + PMVector location( ) const { return m_location; } + void setLocation( const PMVector& v ); + double radius( ) const { return m_radius; } + void setRadius( double c ); + double strength( ) const { return m_strength; } + void setStrength( double c ); + double falloff( ) const { return m_falloff; } + void setFalloff( double c ); + bool inverse( ) const { return m_inverse; } + void setInverse( bool c ); + PMVector repeat( ) const { return m_repeat; } + void setRepeat( const PMVector& v ); + PMVector turbulence( ) const { return m_turbulence; } + void setTurbulence( const PMVector& v ); + + PMVector valueVector( ) const { return m_valueVector; } + void setValueVector( const PMVector& v ); + int octaves( ) const { return m_octaves; } + void setOctaves( int c ); + double omega( ) const { return m_omega; } + void setOmega( double c ); + double lambda( ) const { return m_lambda; } + void setLambda( double c ); + + PMVector orientation( ) const { return m_orientation;} + void setOrientation( const PMVector& v ); + double distExp( ) const { return m_distExp; } + void setDistExp( double c ); + double majorRadius( ) const { return m_majorRadius; } + void setMajorRadius( double c ); + + + /** */ + virtual void restoreMemento( PMMemento* s ); +private: + /** + * IDs for @ref PMMementoData + */ + enum PMWarpMementoID { PMWarpTypeID, PMDirectionID, PMOffsetID, PMFlipID, + PMLocationID, PMRadiusID, PMStrengthID, PMFalloffID, + PMInverseID, PMRepeatID, PMTurbulenceID, + PMValueVectorID, PMOctavesID, PMOmegaID, PMLambdaID, + PMOrientationID, PMDistExpID, PMMajorRadiusID }; + + PMWarpType m_warpType; + + // Repeat variables + PMVector m_direction; + PMVector m_offset; + PMVector m_flip; + + // Black Hole variables + PMVector m_location; + double m_radius; + double m_strength; + double m_falloff; + bool m_inverse; + PMVector m_repeat; + PMVector m_turbulence; + + // Turbulence variables + PMVector m_valueVector; + int m_octaves; + double m_omega; + double m_lambda; + + // Mapping variables + PMVector m_orientation; + double m_distExp; + double m_majorRadius; + + static PMMetaObject* s_pMetaObject; +}; + +#endif diff --git a/kpovmodeler/pmwarpedit.cpp b/kpovmodeler/pmwarpedit.cpp new file mode 100644 index 00000000..99c620dd --- /dev/null +++ b/kpovmodeler/pmwarpedit.cpp @@ -0,0 +1,407 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#include "pmwarpedit.h" +#include "pmwarp.h" +#include "pmvectoredit.h" +#include "pmlineedits.h" + +#include +#include +#include +#include +#include +#include + + +PMWarpEdit::PMWarpEdit( QWidget* parent, const char* name ) + : Base( parent, name ) +{ + m_pDisplayedObject = 0; +} + +void PMWarpEdit::createTopWidgets( ) +{ + QHBoxLayout* hl; + QVBoxLayout* vl; + QGridLayout* gl; + + Base::createTopWidgets( ); + + QLabel* label = new QLabel( i18n( "Warp type:" ), this ); + m_pWarpTypeEdit = new QComboBox( false, this ); + m_pWarpTypeEdit->insertItem( i18n( "Repeat" ) ); + m_pWarpTypeEdit->insertItem( i18n( "Black Hole" ) ); + m_pWarpTypeEdit->insertItem( i18n( "Turbulence" ) ); + m_pWarpTypeEdit->insertItem( i18n( "Cylindrical" ) ); + m_pWarpTypeEdit->insertItem( i18n( "Spherical" ) ); + m_pWarpTypeEdit->insertItem( i18n( "Toroidal" ) ); + m_pWarpTypeEdit->insertItem( i18n( "Planar" ) ); + hl = new QHBoxLayout( topLayout( ) ); + hl->addWidget( label ); + hl->addWidget( m_pWarpTypeEdit ); + hl->addStretch( 1 ); + + /* Repeat Warp Objects */ + m_pRepeatWidget = new QWidget( this ); + vl = new QVBoxLayout( m_pRepeatWidget, 0, KDialog::spacingHint( ) ); + gl = new QGridLayout( vl, 3, 2 ); + m_pDirectionLabel = new QLabel( i18n( "Direction:" ), m_pRepeatWidget ); + m_pDirectionEdit = new PMVectorEdit( "x", "y", "z", m_pRepeatWidget ); + gl->addWidget( m_pDirectionLabel, 0, 0 ); + gl->addWidget( m_pDirectionEdit, 0, 1 ); + m_pOffsetLabel = new QLabel( i18n( "Offset:" ), m_pRepeatWidget ); + m_pOffsetEdit = new PMVectorEdit( "x", "y", "z", m_pRepeatWidget ); + gl->addWidget( m_pOffsetLabel, 1, 0 ); + gl->addWidget( m_pOffsetEdit, 1, 1 ); + m_pFlipLabel = new QLabel( i18n( "Flip:" ), m_pRepeatWidget ); + m_pFlipEdit = new PMVectorEdit( "x", "y", "z", m_pRepeatWidget ); + gl->addWidget( m_pFlipLabel, 2, 0 ); + gl->addWidget( m_pFlipEdit, 2, 1 ); + + /* Black Hole Warp Objects */ + m_pBlackHoleWidget = new QWidget( this ); + vl = new QVBoxLayout( m_pBlackHoleWidget, 0, KDialog::spacingHint( ) ); + m_pLocationLabel = new QLabel( i18n( "Location:" ), m_pBlackHoleWidget ); + m_pLocationEdit = new PMVectorEdit( "x", "y", "z", m_pBlackHoleWidget ); + hl = new QHBoxLayout( vl ); + hl->addWidget( m_pLocationLabel ); + hl->addWidget( m_pLocationEdit ); + m_pRadiusLabel = new QLabel( i18n( "Radius:" ), m_pBlackHoleWidget ); + m_pRadiusEdit = new PMFloatEdit( m_pBlackHoleWidget ); + m_pStrengthLabel = new QLabel( i18n( "Strength:" ), m_pBlackHoleWidget ); + m_pStrengthEdit = new PMFloatEdit( m_pBlackHoleWidget ); + m_pFalloffLabel = new QLabel( i18n( "Falloff:" ), m_pBlackHoleWidget ); + m_pFalloffEdit = new PMFloatEdit( m_pBlackHoleWidget ); + hl = new QHBoxLayout( vl ); + gl = new QGridLayout( hl, 3, 2 ); + gl->addWidget( m_pRadiusLabel, 0, 0 ); + gl->addWidget( m_pRadiusEdit, 0, 1 ); + gl->addWidget( m_pStrengthLabel, 1, 0 ); + gl->addWidget( m_pStrengthEdit, 1, 1 ); + gl->addWidget( m_pFalloffLabel, 2, 0 ); + gl->addWidget( m_pFalloffEdit, 2, 1 ); + hl->addStretch( 1 ); + + m_pRepeatLabel = new QLabel( i18n( "Repeat:" ), m_pBlackHoleWidget ); + m_pRepeatEdit = new PMVectorEdit( "x", "y", "z", m_pBlackHoleWidget ); + hl = new QHBoxLayout( vl ); + hl->addWidget( m_pRepeatLabel ); + hl->addWidget( m_pRepeatEdit ); + m_pTurbulenceLabel = new QLabel( i18n( "Turbulence:" ), m_pBlackHoleWidget ); + m_pTurbulenceEdit = new PMVectorEdit( "x", "y", "z", m_pBlackHoleWidget ); + hl = new QHBoxLayout( vl ); + hl->addWidget( m_pTurbulenceLabel ); + hl->addWidget( m_pTurbulenceEdit ); + m_pInverseEdit = new QCheckBox( i18n( "Inverse" ), m_pBlackHoleWidget ); + vl->addWidget( m_pInverseEdit ); + + /* Turbulence Warp Objects */ + m_pTurbulenceWidget = new QWidget( this ); + vl = new QVBoxLayout( m_pTurbulenceWidget, 0, KDialog::spacingHint( ) ); + m_pValueVectorLabel = new QLabel( i18n( "Value:" ), m_pTurbulenceWidget ); + m_pValueVectorEdit = new PMVectorEdit( "x", "y", "z", m_pTurbulenceWidget ); + hl = new QHBoxLayout( vl ); + hl->addWidget( m_pValueVectorLabel ); + hl->addWidget( m_pValueVectorEdit ); + + hl = new QHBoxLayout( vl ); + gl = new QGridLayout( hl, 3, 2 ); + m_pOctavesLabel = new QLabel( i18n( "Octaves:" ), m_pTurbulenceWidget ); + m_pOctavesEdit = new PMIntEdit( m_pTurbulenceWidget ); + gl->addWidget( m_pOctavesLabel, 0, 0 ); + gl->addWidget( m_pOctavesEdit, 0, 1 ); + m_pOmegaLabel = new QLabel( i18n( "Omega:" ), m_pTurbulenceWidget ); + m_pOmegaEdit = new PMFloatEdit( m_pTurbulenceWidget ); + gl->addWidget( m_pOmegaLabel, 1, 0 ); + gl->addWidget( m_pOmegaEdit, 1, 1 ); + m_pLambdaLabel = new QLabel( i18n( "Lambda:" ), m_pTurbulenceWidget ); + m_pLambdaEdit = new PMFloatEdit( m_pTurbulenceWidget ); + gl->addWidget( m_pLambdaLabel, 2, 0 ); + gl->addWidget( m_pLambdaEdit, 2, 1 ); + hl->addStretch( 1 ); + + /* Mapping Warp Objects */ + m_pMappingWidget = new QWidget( this ); + vl = new QVBoxLayout( m_pMappingWidget, 0, KDialog::spacingHint( ) ); + label = new QLabel( i18n( "Orientation:" ), m_pMappingWidget ); + m_pOrientationEdit = new PMVectorEdit( "x", "y", "z", m_pMappingWidget ); + hl = new QHBoxLayout( vl ); + hl->addWidget( label ); + hl->addWidget( m_pOrientationEdit ); + + gl = new QGridLayout( vl, 2, 2 ); + label = new QLabel( i18n( "Distance exponent:" ), m_pMappingWidget ); + m_pDistExpEdit = new PMFloatEdit( m_pMappingWidget ); + gl->addWidget( label, 0, 0 ); + gl->addWidget( m_pDistExpEdit, 0, 1 ); + m_pMajorRadiusLabel = new QLabel( i18n( "Major radius:" ), m_pMappingWidget ); + m_pMajorRadiusEdit = new PMFloatEdit( m_pMappingWidget ); + gl->addWidget( m_pMajorRadiusLabel, 1, 0 ); + gl->addWidget( m_pMajorRadiusEdit, 1, 1 ); + + vl = new QVBoxLayout( topLayout( ) ); + vl->addSpacing( 0 ); + vl->addWidget( m_pRepeatWidget ); + vl->addWidget( m_pBlackHoleWidget ); + vl->addWidget( m_pTurbulenceWidget ); + vl->addWidget( m_pMappingWidget ); + + connect( m_pWarpTypeEdit, SIGNAL( activated( int ) ), SLOT( slotComboChanged( int ) ) ); + connect( m_pDirectionEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pOffsetEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pFlipEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pLocationEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pRadiusEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pStrengthEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pFalloffEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pInverseEdit, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pRepeatEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pTurbulenceEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pValueVectorEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pOctavesEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pOmegaEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pLambdaEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pOrientationEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pDistExpEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); + connect( m_pMajorRadiusEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) ); +} + +void PMWarpEdit::displayObject( PMObject* o ) +{ + if( o->isA( "Warp" ) ) + { + bool readOnly = o->isReadOnly( ); + m_pDisplayedObject = ( PMWarp* ) o; + + switch( m_pDisplayedObject->warpType( ) ) + { + case PMWarp::Repeat: + m_pWarpTypeEdit->setCurrentItem( 0 ); + slotComboChanged( 0 ); + break; + case PMWarp::BlackHole: + m_pWarpTypeEdit->setCurrentItem( 1 ); + slotComboChanged( 1 ); + break; + case PMWarp::Turbulence: + m_pWarpTypeEdit->setCurrentItem( 2 ); + slotComboChanged( 2 ); + break; + case PMWarp::Cylindrical: + m_pWarpTypeEdit->setCurrentItem( 3 ); + slotComboChanged( 3 ); + break; + case PMWarp::Spherical: + m_pWarpTypeEdit->setCurrentItem( 4 ); + slotComboChanged( 4 ); + break; + case PMWarp::Toroidal: + m_pWarpTypeEdit->setCurrentItem( 5 ); + slotComboChanged( 5 ); + break; + case PMWarp::Planar: + m_pWarpTypeEdit->setCurrentItem( 6 ); + slotComboChanged( 6 ); + break; + } + m_pDirectionEdit->setVector( m_pDisplayedObject->direction( ) ); + m_pDirectionEdit->setReadOnly( readOnly ); + m_pOffsetEdit->setVector( m_pDisplayedObject->offset( ) ); + m_pOffsetEdit->setReadOnly( readOnly ); + m_pFlipEdit->setVector( m_pDisplayedObject->flip( ) ); + m_pFlipEdit->setReadOnly( readOnly ); + m_pLocationEdit->setVector( m_pDisplayedObject->location( ) ); + m_pLocationEdit->setReadOnly( readOnly ); + m_pRadiusEdit->setValue( m_pDisplayedObject->radius( ) ); + m_pRadiusEdit->setReadOnly( readOnly ); + m_pStrengthEdit->setValue( m_pDisplayedObject->strength( ) ); + m_pStrengthEdit->setReadOnly( readOnly ); + m_pFalloffEdit->setValue( m_pDisplayedObject->falloff( ) ); + m_pFalloffEdit->setReadOnly( readOnly ); + m_pInverseEdit->setChecked( m_pDisplayedObject->inverse( ) ); + m_pInverseEdit->setEnabled( !readOnly ); + m_pRepeatEdit->setVector( m_pDisplayedObject->repeat( ) ); + m_pRepeatEdit->setReadOnly( readOnly ); + m_pTurbulenceEdit->setVector( m_pDisplayedObject->turbulence( ) ); + m_pTurbulenceEdit->setReadOnly( readOnly ); + m_pValueVectorEdit->setVector( m_pDisplayedObject->valueVector( ) ); + m_pValueVectorEdit->setReadOnly( readOnly ); + m_pOctavesEdit->setValue( m_pDisplayedObject->octaves( ) ); + m_pOctavesEdit->setReadOnly( readOnly ); + m_pOmegaEdit->setValue( m_pDisplayedObject->omega( ) ); + m_pOmegaEdit->setReadOnly( readOnly ); + m_pLambdaEdit->setValue( m_pDisplayedObject->lambda( ) ); + m_pLambdaEdit->setReadOnly( readOnly ); + m_pOrientationEdit->setVector( m_pDisplayedObject->orientation( ) ); + m_pOrientationEdit->setReadOnly( readOnly ); + m_pDistExpEdit->setValue( m_pDisplayedObject->distExp( ) ); + m_pDistExpEdit->setReadOnly( readOnly ); + m_pMajorRadiusEdit->setValue( m_pDisplayedObject->majorRadius( ) ); + m_pMajorRadiusEdit->setReadOnly( readOnly ); + + Base::displayObject( o ); + } + else + kdError( PMArea ) << "PMWarpEdit: Can't display object\n"; +} + +void PMWarpEdit::saveContents( ) +{ + bool mapping = false; + + if( m_pDisplayedObject ) + { + Base::saveContents( ); + switch( m_pWarpTypeEdit->currentItem( ) ) + { + case 0: + m_pDisplayedObject->setWarpType( PMWarp::Repeat ); + m_pDisplayedObject->setDirection( m_pDirectionEdit->vector( ) ); + m_pDisplayedObject->setOffset( m_pOffsetEdit->vector( ) ); + m_pDisplayedObject->setFlip( m_pOffsetEdit->vector( ) ); + break; + case 1: + m_pDisplayedObject->setWarpType( PMWarp::BlackHole ); + m_pDisplayedObject->setLocation( m_pLocationEdit->vector( ) ); + m_pDisplayedObject->setRadius( m_pRadiusEdit->value( ) ); + m_pDisplayedObject->setStrength( m_pStrengthEdit->value( ) ); + m_pDisplayedObject->setFalloff( m_pFalloffEdit->value( ) ); + m_pDisplayedObject->setInverse( m_pInverseEdit->isChecked( ) ); + m_pDisplayedObject->setRepeat( m_pRepeatEdit->vector( ) ); + m_pDisplayedObject->setTurbulence( m_pTurbulenceEdit->vector( ) ); + break; + case 2: + m_pDisplayedObject->setWarpType( PMWarp::Turbulence ); + m_pDisplayedObject->setValueVector( m_pValueVectorEdit->vector( ) ); + m_pDisplayedObject->setOctaves( m_pOctavesEdit->value( ) ); + m_pDisplayedObject->setOmega( m_pOmegaEdit->value( ) ); + m_pDisplayedObject->setLambda( m_pLambdaEdit->value( ) ); + break; + case 3: + m_pDisplayedObject->setWarpType( PMWarp::Cylindrical ); + mapping = true; + break; + case 4: + m_pDisplayedObject->setWarpType( PMWarp::Spherical ); + mapping = true; + break; + case 5: + m_pDisplayedObject->setWarpType( PMWarp::Toroidal ); + m_pDisplayedObject->setMajorRadius( m_pMajorRadiusEdit->value( ) ); + mapping = true; + break; + case 6: + m_pDisplayedObject->setWarpType( PMWarp::Planar ); + mapping = true; + break; + } + + if( mapping ) + { + m_pDisplayedObject->setOrientation( m_pOrientationEdit->vector( ) ); + m_pDisplayedObject->setDistExp( m_pDistExpEdit->value( ) ); + } + } +} + +bool PMWarpEdit::isDataValid( ) +{ + double x,y,z; + + switch( m_pWarpTypeEdit->currentItem( ) ) + { + case 0: + if( !m_pDirectionEdit->isDataValid( ) || + !m_pOffsetEdit->isDataValid( ) || + !m_pFlipEdit->isDataValid( ) ) + return false; + // The direction vector can only have one non-zero component + x = m_pDirectionEdit->vector( ).x( ); + y = m_pDirectionEdit->vector( ).y( ); + z = m_pDirectionEdit->vector( ).z( ); + if( ( x && ( y || z ) ) || ( y && ( x || z )) || ( z && ( x || y ) ) ) + return false; + break; + case 1: + break; + case 2: + if( !m_pOctavesEdit->isDataValid( ) || + m_pOctavesEdit->value( ) < 1 || + m_pOctavesEdit->value( ) > 10 ) + return false; + break; + case 3: + case 4: + case 5: + case 6: + if( !m_pOrientationEdit->isDataValid( ) || + !m_pDistExpEdit->isDataValid( ) || + !m_pMajorRadiusEdit->isDataValid( ) ) + return false; + break; + } + return Base::isDataValid( ); +} + +void PMWarpEdit::slotComboChanged( int c ) +{ + switch ( c ) + { + case 0: + m_pRepeatWidget->show( ); + m_pBlackHoleWidget->hide( ); + m_pTurbulenceWidget->hide( ); + m_pMappingWidget->hide( ); + break; + case 1: + m_pRepeatWidget->hide( ); + m_pBlackHoleWidget->show( ); + m_pTurbulenceWidget->hide( ); + m_pMappingWidget->hide( ); + break; + case 2: + m_pRepeatWidget->hide( ); + m_pBlackHoleWidget->hide( ); + m_pTurbulenceWidget->show( ); + m_pMappingWidget->hide( ); + break; + case 3: + case 4: + case 6: + m_pRepeatWidget->hide( ); + m_pBlackHoleWidget->hide( ); + m_pTurbulenceWidget->hide( ); + m_pMappingWidget->show( ); + m_pMajorRadiusLabel->hide( ); + m_pMajorRadiusEdit->hide( ); + break; + case 5: + m_pRepeatWidget->hide( ); + m_pBlackHoleWidget->hide( ); + m_pTurbulenceWidget->hide( ); + m_pMappingWidget->show( ); + m_pMajorRadiusLabel->show( ); + m_pMajorRadiusEdit->show( ); + break; + } + emit dataChanged( ); + emit sizeChanged( ); +} + +#include "pmwarpedit.moc" diff --git a/kpovmodeler/pmwarpedit.h b/kpovmodeler/pmwarpedit.h new file mode 100644 index 00000000..1140e3e6 --- /dev/null +++ b/kpovmodeler/pmwarpedit.h @@ -0,0 +1,110 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2001 by Luis Carvalho + email : lpassos@mail.telepac.pt +************************************************************************** + +************************************************************************** +* * +* 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. * +* * +**************************************************************************/ + + +#ifndef PMWARPEDIT_H +#define PMWARPEDIT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmdialogeditbase.h" + +class PMWarp; +class PMVectorEdit; +class PMIntEdit; +class PMFloatEdit; +class QComboBox; +class QCheckBox; +class QLabel; + +/** + * Dialog edit class for @ref PMWarp. + */ +class PMWarpEdit : public PMDialogEditBase +{ + Q_OBJECT + typedef PMDialogEditBase Base; +public: + /** + * Creates a PMWarpEdit with parent and name + */ + PMWarpEdit( QWidget* parent, const char* name = 0 ); + + /** */ + virtual void displayObject( PMObject* o ); + + /** */ + virtual bool isDataValid( ); +protected: + /** */ + virtual void createTopWidgets( ); + /** */ + virtual void saveContents( ); + +protected slots: + /** */ + void slotComboChanged( int c ); + +private: + PMWarp* m_pDisplayedObject; + QComboBox* m_pWarpTypeEdit; + PMVectorEdit* m_pDirectionEdit; + QLabel* m_pDirectionLabel; + PMVectorEdit* m_pOffsetEdit; + QLabel* m_pOffsetLabel; + PMVectorEdit* m_pFlipEdit; + QLabel* m_pFlipLabel; + + PMVectorEdit* m_pLocationEdit; + QLabel* m_pLocationLabel; + PMFloatEdit* m_pRadiusEdit; + QLabel* m_pRadiusLabel; + PMFloatEdit* m_pStrengthEdit; + QLabel* m_pStrengthLabel; + PMFloatEdit* m_pFalloffEdit; + QLabel* m_pFalloffLabel; + QCheckBox* m_pInverseEdit; + PMVectorEdit* m_pRepeatEdit; + QLabel* m_pRepeatLabel; + PMVectorEdit* m_pTurbulenceEdit; + QLabel* m_pTurbulenceLabel; + + PMVectorEdit* m_pValueVectorEdit; + QLabel* m_pValueVectorLabel; + PMIntEdit* m_pOctavesEdit; + QLabel* m_pOctavesLabel; + PMFloatEdit* m_pOmegaEdit; + QLabel* m_pOmegaLabel; + PMFloatEdit* m_pLambdaEdit; + QLabel* m_pLambdaLabel; + + PMVectorEdit* m_pOrientationEdit; + PMFloatEdit* m_pDistExpEdit; + PMFloatEdit* m_pMajorRadiusEdit; + QLabel* m_pMajorRadiusLabel; + + QWidget* m_pRepeatWidget; + QWidget* m_pBlackHoleWidget; + QWidget* m_pTurbulenceWidget; + QWidget* m_pMappingWidget; +}; + + +#endif diff --git a/kpovmodeler/pmxmlhelper.cpp b/kpovmodeler/pmxmlhelper.cpp new file mode 100644 index 00000000..bbb3c32c --- /dev/null +++ b/kpovmodeler/pmxmlhelper.cpp @@ -0,0 +1,160 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmxmlhelper.h" + +PMXMLHelper::PMXMLHelper( const QDomElement& e, PMPart* p, PMParser* par, + int majorDocumentFormat, int minorDocumentFormat ) +{ + m_e = e; + m_pPart = p; + m_pParser = par; + m_major = majorDocumentFormat; + m_minor = minorDocumentFormat; +} + +bool PMXMLHelper::hasAttribute( const QString& name ) const +{ + return m_e.hasAttribute( name ); +} + +int PMXMLHelper::intAttribute( const QString& name, int def ) const +{ + QString str = m_e.attribute( name ); + bool ok; + int res; + + if( str.isNull( ) ) + return def; + res = str.toInt( &ok ); + if( ok ) + return res; + return def; +} + +double PMXMLHelper::doubleAttribute( const QString& name, double def ) const +{ + QString str = m_e.attribute( name ); + bool ok; + double res; + + if( str.isNull( ) ) + return def; + res = str.toDouble( &ok ); + if( ok ) + return res; + return def; +} + +bool PMXMLHelper::boolAttribute( const QString& name, bool def ) const +{ + QString str = m_e.attribute( name ); + bool ok; + int res; + + if( str.isNull( ) ) + return def; + res = str.toInt( &ok ); + if( ok ) + return ( res != 0 ); + return def; +} + +PMThreeState PMXMLHelper::threeStateAttribute( const QString& name ) const +{ + QString str = m_e.attribute( name ); + bool ok; + int res; + + if( str.isNull( ) ) + return PMUnspecified; + res = str.toInt( &ok ); + if( ok ) + { + if( res == 0 ) + return PMFalse; + else + return PMTrue; + } + return PMUnspecified; +} + +QString PMXMLHelper::stringAttribute( const QString& name, const QString& def ) const +{ + return m_e.attribute( name, def ); +} + +PMVector PMXMLHelper::vectorAttribute( const QString& name, const PMVector& def ) const +{ + QString str = m_e.attribute( name ); + + if( str.isNull( ) ) + return def; + else + { + PMVector v; + if( v.loadXML( str ) ) + return v; + } + return def; +} + +PMMatrix PMXMLHelper::matrixAttribute( const QString& name, const PMMatrix& def ) const +{ + QString str = m_e.attribute( name ); + + if( str.isNull( ) ) + return def; + else + { + PMMatrix m; + if( m.loadXML( str ) ) + return m; + } + return def; +} + +PMColor PMXMLHelper::colorAttribute( const QString& name, const PMColor& def ) const +{ + QString str = m_e.attribute( name ); + + if( str.isNull( ) ) + return def; + else + { + PMColor c; + if( c.loadXML( str ) ) + return c; + } + return def; +} + +QDomElement PMXMLHelper::extraData( ) const +{ + QDomNode c = m_e.firstChild( ); + while( !c.isNull( ) ) + { + if( c.isElement( ) ) + { + QDomElement ce = c.toElement( ); + if( ce.tagName( ) == "extra_data" ) + return ce; + } + c = c.nextSibling( ); + } + return QDomElement( ); +} diff --git a/kpovmodeler/pmxmlhelper.h b/kpovmodeler/pmxmlhelper.h new file mode 100644 index 00000000..25ae6947 --- /dev/null +++ b/kpovmodeler/pmxmlhelper.h @@ -0,0 +1,121 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMXMLHELPER_H +#define PMXMLHELPER_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "pmobject.h" +#include "pmcolor.h" +#include "pmvector.h" +#include "pmmatrix.h" + +class PMPart; +class PMParser; + +/** + * Class for reading attributes out of a @ref QDomElement + */ +class PMXMLHelper +{ +public: + /** + * Creates a PMXMLHelper for the QDomElement& e + */ + PMXMLHelper( const QDomElement& e, PMPart* p, PMParser* par, + int majorDocumentFormat, int minorDocumentFormat ); + /** + * Returns the QDomElement + */ + QDomElement element( ) const { return m_e; } + + /** + * Returns true if the element contains the attribute + */ + bool hasAttribute( const QString& name ) const; + /** + * Reads an integer attribute + */ + int intAttribute( const QString& name, int def ) const; + /** + * Reads a double attribute + */ + double doubleAttribute( const QString& name, double def ) const; + /** + * Reads a bool attribute + */ + bool boolAttribute( const QString& name, bool def ) const; + /** + * Reads a PMThreeState attribute + */ + PMThreeState threeStateAttribute( const QString& name ) const; + /** + * Reads a string attribute + */ + QString stringAttribute( const QString& name, const QString& def ) const; + /** + * Reads a vector attribute + */ + PMVector vectorAttribute( const QString& name, const PMVector& def ) const; + /** + * Reads a matrix attribute + */ + PMMatrix matrixAttribute( const QString& name, const PMMatrix& def ) const; + /** + * Reads a color attribute + */ + PMColor colorAttribute( const QString& name, const PMColor& def ) const; + + /** + * Returns the "extra_data" child element or a null element, if there + * is no child element with tag name "extra_data" + */ + QDomElement extraData( ) const; + + /** + * Returns a pointer to the part + */ + PMPart* part( ) const { return m_pPart; } + /** + * Returns a pointer to the parser + */ + PMParser* parser( ) const { return m_pParser; } + /** + * Returns the documents major format number + */ + int majorDocumentFormat( ) const { return m_major; } + /** + * Returns the documents minor format number + */ + int minorDocumentFormat( ) const { return m_minor; } + +private: + QDomElement m_e; + PMPart* m_pPart; + PMParser* m_pParser; + int m_major; + int m_minor; +}; + +#endif diff --git a/kpovmodeler/pmxmlparser.cpp b/kpovmodeler/pmxmlparser.cpp new file mode 100644 index 00000000..520b19c0 --- /dev/null +++ b/kpovmodeler/pmxmlparser.cpp @@ -0,0 +1,177 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#include "pmxmlparser.h" + +#include +#include + +#include "pmpart.h" +#include "pmscene.h" +#include "pmxmlhelper.h" +#include "pmprototypemanager.h" +#include "pmdocumentformat.h" +#include "pmdebug.h" + +PMXMLParser::PMXMLParser( PMPart* part, QIODevice* dev ) + : PMParser( part, dev ) +{ + init( ); +} + +PMXMLParser::PMXMLParser( PMPart* part, const QByteArray& array ) + : PMParser( part, array ) +{ + init( ); +} + +void PMXMLParser::init( ) +{ + m_pDoc = 0; + m_majorDocumentFormat = 1; + m_minorDocumentFormat = 0; +} + +PMXMLParser::~PMXMLParser( ) +{ + if( m_pDoc ) + delete m_pDoc; +} + +bool PMXMLParser::initDocument( ) +{ + if( !m_pDoc ) + { + m_pDoc = new QDomDocument( "KPOVMODELER" ); + if( m_pDoc->setContent( m_pDevice ) ) + return true; + else + { + printError( i18n( "Could not load the documents data!" ) ); + setFatalError( ); + return false; + } + } + return true; +} + +void PMXMLParser::topParse( ) +{ + if( initDocument( ) ) + { + QDomElement e = m_pDoc->documentElement( ); + // read the format number + // assume 1.0 on error + QString fstring = e.attribute( "majorFormat", "1" ); + bool ok = true; + int format = fstring.toInt( &ok ); + if( !ok || ( format < 1 ) ) + format = 1; + m_majorDocumentFormat = format; + + fstring = e.attribute( "minorFormat", "0" ); + ok = true; + format = fstring.toInt( &ok ); + if( !ok || ( format < 0 ) ) + format = 0; + m_minorDocumentFormat = format; + + if( ( m_majorDocumentFormat > c_majorDocumentFormat ) + || ( m_majorDocumentFormat == c_majorDocumentFormat ) + && ( m_minorDocumentFormat > c_minorDocumentFormat ) ) + printWarning( i18n( "This document was created with a newer version of KPovModeler. " + "The whole document may not be loaded correctly." ) ); + + if( e.tagName( ) == "objects" ) + { + parseChildObjects( e, 0 ); + } + else if( e.tagName( ) == "scene" ) + { + PMScene* scene = new PMScene( m_pPart ); + insertChild( scene, 0 ); + PMXMLHelper hlp( e, m_pPart, this, + m_majorDocumentFormat, m_minorDocumentFormat ); + scene->readAttributes( hlp ); + parseChildObjects( e, scene ); + } + else + { + printError( i18n( "Wrong top level tag" ) ); + setFatalError( ); + } + } +} + +void PMXMLParser::parseChildObjects( QDomElement& e, PMObject* parent ) +{ + QDomNode c = e.firstChild( ); + while( !c.isNull( ) ) + { + if( c.isElement( ) ) + { + QDomElement ce = c.toElement( ); + PMPrototypeManager* m = m_pPart->prototypeManager( ); + PMObject* obj = m->newObject( m->className( ce.tagName( ) ) ); + if( obj ) + { + PMXMLHelper hlp( ce, m_pPart, this, + m_majorDocumentFormat, m_minorDocumentFormat ); + obj->readAttributes( hlp ); + if( insertChild( obj, parent ) ) + { + parseChildObjects( ce, obj ); + + if( obj->isA( "Declare" ) ) + checkID( ( PMDeclare* ) obj ); + } + else + delete obj; + } + else if( ce.tagName( ) != "extra_data" ) + printError( i18n( "Unknown object %1" ).arg( ce.tagName( ) ) ); + } + c = c.nextSibling( ); + } +} + + +void PMXMLParser::quickParse( QStringList& list ) +{ + if( initDocument( ) ) + { + QDomElement e = m_pDoc->documentElement( ); + if( ( e.tagName( ) == "objects" ) || ( e.tagName( ) == "scene" ) ) + { + QDomNode c = e.firstChild( ); + + while( !c.isNull( ) ) + { + if( c.isElement( ) ) + { + QDomElement ce = c.toElement( ); + QString type = m_pPart->prototypeManager( )->className( ce.tagName( ) ); + if( !type.isNull( ) ) + list.append( type ); + } + c = c.nextSibling( ); + } + } + else + printError( i18n( "Wrong top level tag" ) ); + } +} diff --git a/kpovmodeler/pmxmlparser.h b/kpovmodeler/pmxmlparser.h new file mode 100644 index 00000000..ca311048 --- /dev/null +++ b/kpovmodeler/pmxmlparser.h @@ -0,0 +1,84 @@ +//-*-C++-*- +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#ifndef PMXMLPARSER_H +#define PMXMLPARSER_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pmparser.h" + +/** + * Parser that parses kpovmodeler xml code + */ +class PMXMLParser : public PMParser +{ +public: + /** + * Parser that parses the device + */ + PMXMLParser( PMPart* part, QIODevice* device ); + /** + * Parser that parses the byte array + */ + PMXMLParser( PMPart* part, const QByteArray& array ); + /** + * Deletes the parser + */ + virtual ~PMXMLParser( ); + + /** + * Quickly scans the top level objects. Appends all top level object + * types to the list. + */ + virtual void quickParse( QStringList& list ); + /** + * Returns true, if the parser can quickly scan the top level objects. + */ + virtual bool canQuickParse( ) const { return true; } +protected: + /** + * Top level parse function + */ + virtual void topParse( ); + +private: + /** + * Inializes the parser + */ + void init( ); + /** + * Initializes the QDomDocument. Returns true if successful. + */ + bool initDocument( ); + + /** + * Looks for child objects, parses them and appends them to the parent + * object. If parent is 0, all objects are appended to the result list. + */ + void parseChildObjects( QDomElement& e, PMObject* parent ); + + QDomDocument* m_pDoc; + int m_majorDocumentFormat; + int m_minorDocumentFormat; +}; + + +#endif diff --git a/kpovmodeler/povraydocmap.xml b/kpovmodeler/povraydocmap.xml new file mode 100644 index 00000000..1981abe1 --- /dev/null +++ b/kpovmodeler/povraydocmap.xml @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kpovmodeler/questionmark.png b/kpovmodeler/questionmark.png new file mode 100644 index 00000000..19eb62d8 Binary files /dev/null and b/kpovmodeler/questionmark.png differ diff --git a/kpovmodeler/version.h b/kpovmodeler/version.h new file mode 100644 index 00000000..1fbc1f0c --- /dev/null +++ b/kpovmodeler/version.h @@ -0,0 +1,18 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.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. * +* * +**************************************************************************/ + +#define KPOVMODELER_VERSION "1.1.3" diff --git a/kruler/Makefile.am b/kruler/Makefile.am new file mode 100644 index 00000000..d2b8f278 --- /dev/null +++ b/kruler/Makefile.am @@ -0,0 +1,25 @@ +SUBDIRS = pics + +INCLUDES= $(all_includes) + +bin_PROGRAMS = kruler +kruler_METASOURCES = AUTO +kruler_LDFLAGS = $(all_libraries) $(KDE_RPATH) +kruler_LDADD = $(LIB_KDEUI) +kruler_SOURCES = klineal.cpp main.cpp + +xdg_apps_DATA = kruler.desktop + +install-data-local: uninstall.desktop + $(mkinstalldirs) $(DESTDIR)$(kde_appsdir)/Graphics + $(INSTALL_DATA) $(srcdir)/uninstall.desktop $(DESTDIR)$(kde_appsdir)/Graphics/kruler.desktop + +appdir = $(kde_datadir)/kruler +app_DATA = eventsrc + +sounddir = $(kde_datadir)/kruler/sounds +sound_DATA = move.wav + +messages: + $(XGETTEXT) $(kruler_SOURCES) -o $(podir)/kruler.pot + diff --git a/kruler/eventsrc b/kruler/eventsrc new file mode 100644 index 00000000..5f178815 --- /dev/null +++ b/kruler/eventsrc @@ -0,0 +1,192 @@ +[!Global!] +IconName=kruler +Comment=KDE Screen Ruler +Comment[af]=Kde Skerm Liniaal +Comment[ar]=مسطرة شاشة KDE +Comment[az]=KDE Ekran Xətkeşi +Comment[bg]=Линийка за екрана +Comment[bs]=KDE ekranski linijar +Comment[ca]=Regla de pantalla KDE +Comment[cs]=Obrazovkové pravítko +Comment[cy]=Mesurydd Sgrîn KDE +Comment[da]=KDE Skærmlineal +Comment[de]=Bildschirmlineal +Comment[el]=Χάρακας οθόνης του KDE +Comment[eo]=Ekranliniilo +Comment[es]=Regla para la pantalla de KDE +Comment[et]=KDE ekraani joonlaud +Comment[eu]=KDE pantaila erregela +Comment[fa]=خط‌کش پردۀ KDE +Comment[fi]=Näytön mittaaja +Comment[fr]=Règle d'écran pour KDE +Comment[ga]=Rialóir Scáileáin KDE +Comment[gl]=Regra de pantalla de KDE +Comment[he]=סרגל המסך של KDE +Comment[hi]=केडीई स्क्रीन रूलर +Comment[hr]=KDE ravnalo za ekran +Comment[hu]=Képernyővonalzó +Comment[is]=KDE Reglustikan +Comment[it]=Righello dello schermo +Comment[ja]=KDE スクリーン定規 +Comment[kk]=KDE экран өлшегіші +Comment[km]=បន្ទាត់​អេក្រង់ KDE +Comment[ko]=KDE용 화면 자 +Comment[lt]=KDE ekrano liniuotė +Comment[lv]=KDE Ekrāna Mērjosla +Comment[ms]=Pembaris Skrin KDE +Comment[mt]=Riga tal-Iskrin KDE +Comment[nb]=KDE skjermlinjal +Comment[nds]=KDE-Schirmlineaal +Comment[ne]=केडीई पर्दा रूलर +Comment[nl]=KDE Schermliniaal +Comment[nn]=KDE Skjermlinjal +Comment[nso]=Molaodi wa Pontsho ya KDE +Comment[pl]=Linijka ekranowa +Comment[pt]=Régua do ecrã do KDE +Comment[pt_BR]=Régua da Tela do KDE +Comment[ro]=Riglă de ecran pentru KDE +Comment[ru]=Экранная линейка KDE +Comment[se]=KDE-šearbmalinjála +Comment[sk]=KDE pravítko obrazovky +Comment[sl]=Zaslonsko ravnilo KDE +Comment[sr]=KDE-ов екрански лењир +Comment[sr@Latn]=KDE-ov ekranski lenjir +Comment[sv]=KDE:s skärmlinjal +Comment[ta]=கேடிஇ திரைக்கான அளவுக்கோல் +Comment[tg]=Ҷадвали экрании KDE +Comment[th]=ไม้บรรทัดบนหน้าจอของ KDE +Comment[tr]=KDE Ekran Cetveli +Comment[uk]=Лінійка екрана KDE +Comment[uz]=KDE ekran lineykasi +Comment[uz@cyrillic]=KDE экран линейкаси +Comment[ven]=Muvhusi wa tshikirini tsha KDE +Comment[xh]=Umlawuli wekhusi le KDE +Comment[zh_CN]=KDE 屏幕标尺 +Comment[zh_HK]=KDE 螢幕尺規 +Comment[zh_TW]=KDE 螢幕尺規 +Comment[zu]=Umlawuli Wesikrini se KDE + +[cursormove] +Name=Moved by Cursor Keys +Name[af]=Verskuif deur Plekaanduier Sleutels +Name[ar]=تم تحريكها بمفاتيح الفأرة +Name[az]=İstiqamət düymələri ilə hərəkət etdirildi +Name[bg]=Преместване чрез клавиатурата +Name[bs]=Pomjera se kursorskim tipkama +Name[ca]=Mogut mitjançant les tecles de cursor +Name[cs]=Přesunutý kurzorovými klávesami +Name[cy]=Symudir gan y Bysellau Cyrchydd +Name[da]=Flyttet med piletaster +Name[de]=Durch Pfeiltasten verschoben +Name[el]=Μετακινήθηκε από τα πλήκτρα κίνησης +Name[eo]=Movata de la direktoklavoj +Name[es]=Movido por las teclas del cursor +Name[et]=Liigutati nooleklahve kasutades +Name[eu]=Cursor Keys-ek mugitua +Name[fa]=توسط کلیدهای مکان‌نما حرکت کرد +Name[fi]=Siirrettiin kursorinäppäimillä +Name[fr]=Déplacée par les touches fléchées +Name[gl]=Mover coas teclas de cursor +Name[he]=הזזה באמצעות מקשי החצים +Name[hi]=संकेतक कुंजियों द्वारा खिसकता है +Name[hr]=Pomaknuto tipkama za kretanje +Name[hu]=A vonalzó elmozgatva a kurzorbillentyűkkel +Name[is]=Fært með örvalyklum +Name[it]=Spostato dai tasti cursore +Name[ja]=カーソルキーで移動 +Name[kk]=Жебелі пернелерімен жылжыту +Name[km]=បាន​ផ្លាស់ទី​ដោយ​គ្រាប់ចុច​ទស្សន៍​ទ្រនិច +Name[ko]=방향 글쇠로 옮겼습니다 +Name[lt]=Judinama klaviatūros rodyklėmis +Name[lv]=Pārvietots ar Kursora Taustiņiem +Name[ms]=Dialih oleh Kekunci Kursor +Name[mt]=Immexxi bil-buttuni tal-vleġeġ +Name[nb]=Flyttet med piltaster +Name[nds]=Mit Pieltasten verschaven +Name[ne]=कर्सर कुञ्जीद्वारा सारिएको +Name[nl]=Verplaatst met de cursortoetsen +Name[nn]=Flytt med piltastane +Name[nso]=Sutisa ke Ditobetswa tsa Cursor +Name[pl]=Przesunięto klawiszami kursora +Name[pt]=Movimentado com as Teclas de Cursor +Name[pt_BR]=Movido pelas Teclas de Direção +Name[ro]=Mutat cu tastele cursor +Name[ru]=Передвижение стрелками +Name[sk]=Presunutý kurzorovými klávesmi +Name[sl]=Premaknjeno s smernimi tipkami +Name[sr]=Померен курсорским тастерима +Name[sr@Latn]=Pomeren kursorskim tasterima +Name[sv]=Flyttade med piltangenteran +Name[ta]=சுட்டி விசையால் நகர்த்தப்பட்டது +Name[tg]=Ба ҳаракат даровардан бо аломати тира +Name[th]=ย้ายด้วยปุ่มลูกศร +Name[tr]=Yön tuşlarıyla hareket ettirildi +Name[uk]=Пересунуто клавішами курсора +Name[ven]=Tshimbidzhwa nga khii ya musevhe +Name[xh]=Ishukunyiswa zizitshixo zesalathisi +Name[zh_CN]=用光标键移动 +Name[zh_HK]=用游標鍵移動 +Name[zh_TW]=用游標鍵移動 +Name[zu]=Inyakaziswe Izikhiye Ze Cursor +Comment=The ruler has moved pixelwise using the cursor keys +Comment[af]=Die liniaal het verskuif beeldelement-gewys te gebruik Die plekaanduier sleutels +Comment[ar]=تم تحريك المسطرة بكسليا باستخدام مفاتيح الفأرة +Comment[az]=Cədvəl piksel piksel istiqamət düymələri ilə hərəkət etdirildi +Comment[bg]=Преместване чрез клавиатурата +Comment[bs]=Linijar se pomjera u pixelima koristeći kursorske tipke +Comment[ca]=La regla s'ha mogut píxel a píxel usant les tecles de cursor +Comment[cs]=Pravítko bylo kurzorovými klávesami posunuto o několik bodů +Comment[cy]=Mae'r mesurydd wedi symud o safbwynt picseli wrth ddefnyddio'r bysellau cyrchydd +Comment[da]=Linealen er flyttet en pixel af gangen med piletasterne +Comment[de]=Das Lineal wurde durch die Pfeiltasten um einige Pixel verschoben +Comment[el]=Ο χάρακας μετακινήθηκε pixelwise με τη χρήση των πλήκτρων κίνησης +Comment[eo]=La liniilo estas movita popunkte uzante la direktoklavojn +Comment[es]=La regla se ha movido entre los pixels usando las teclas del cursor +Comment[et]=Joonlauda liigutati pikselhaaval nooleklahve kasutades +Comment[eu]=Erregela mugitu da kurtsore teklek eragina +Comment[fa]=خط‌کش با استفاده از کلیدهای مکان‌نما در جهت تصویردانه حرکت کرده است. +Comment[fi]=Mittanauha on liikkunut pikseleitä käyttämällä kursorinäppäimiä +Comment[fr]=La règle s'est déplacée sous l'action des touches fléchées +Comment[gl]=A regra moverá o «pixelwise» empregando as teclas de cursor +Comment[he]=הסרגל הוזז באמצעות מקשי החצים +Comment[hi]=संकेतक कुंजियों की मदद से रूसर पिक्सलवाइज़ खिसका +Comment[hr]=Ravnalo je pomaknuto pomoću tipki za kretanje +Comment[hu]=A vonalzó elmozgatva képpontonként a kurzorbillentyűkkel +Comment[is]=Reglustikan hefur verið færð um e-a punkta með örvalyklunum +Comment[it]=Il righello è stato spostato usando i tasti cursore +Comment[ja]=定規がカーソルキーによってピクセル単位で移動しました +Comment[kk]=Өлшегіш жебелі пернелер көмегімен пикселдеп жылжиды +Comment[km]=បន្ទាត់​ត្រូវ​បាន​ផ្លាស់ទី​តាម​ភីកសែល ដោយ​ប្រើ​គ្រាប់ចុច​ទស្សន៍​ទ្រនិច +Comment[ko]=방향 글쇠로 자대를 옮겼습니다 +Comment[lt]=Liniuote buvo paslinkta kelis taškus naudojant klaviatūros rodykles. +Comment[lv]=Mērjosla pārvietota pikseļavirzienā izmantojot kursora taustiņus. +Comment[ms]= Pembaris telah mengalih ikut piksel menggunakan kekunci kursor +Comment[mt]=Ir-riga mxiet b'tikka waħda permezz tal-buttuni vleġeġ +Comment[nb]=Linjalen ble flyttet punktvis ved bruk av piltastene +Comment[nds]=Dat Lineaal warrt mit de Pieltasten pixelwies verschaven +Comment[ne]=कर्सर कुञ्जी प्रयोग गरेर रूलर पिक्सेलअनुसार सारियो +Comment[nl]=De liniaal is enkele pixels verplaatst via de cursortoetsen +Comment[nn]=Linjalen vert flytta piksel for piksel med piltastane +Comment[nso]=Molaodi o tsamaile ka mokgwa wa pixelwise a somisa ditobetswa tsa cursor +Comment[pl]=Linijka przesunięta o zadaną ilość pikseli używając klawiszy kursora +Comment[pt]=A régua foi movida com as teclas de cursor +Comment[pt_BR]=A régua foi movida usando as teclas de direção +Comment[ro]=Rigla a fost mutată cîţiva pixeli cu tastele cursor +Comment[ru]=Линейка сдвигается попиксельно с помощью стрелок. +Comment[sk]=Pravítko bolo kurzorovými klávesmi posunuté o niekoľko bodov +Comment[sl]=Ravnilo se je premaknilo po točkah z uporabo smernih tipk +Comment[sr]=Лењир се померио за пиксел помоћу курсорских тастера +Comment[sr@Latn]=Lenjir se pomerio za piksel pomoću kursorskih tastera +Comment[sv]=Linjalen har flyttats bildpunktsvis med piltangenterna +Comment[ta]=சுட்டி விசைகளை பயன்படுத்தி படத்துணுக்கு மூலமாக வரை உருளை நகர்த்தப்பட்டது +Comment[tg]=Ҷадвал бо ёрии аломати тира, пикселнокӣ ҳаракат мекунад. +Comment[tr]=Cetvel piksel piksel yön tuşlarıyla hareket ettirildi +Comment[uk]=Лінійка пересувається по пікселях за допомогою клавіш курсора +Comment[ven]=Muvhusi o sudzulusa pixelwise a tshi khou shumisa khii ya Cursor +Comment[xh]=Umlawuli ushukume jikelele kwipixel esebenzisa izitshixi zesalathisi +Comment[zh_CN]=标尺已经用光标键按像素移动 +Comment[zh_HK]=使用游標鍵移動尺規單一個像素 +Comment[zh_TW]=使用游標鍵移動尺規單一個像素 +Comment[zu]=Umlawuli unyakazise jikelele kwipixel esebenzisa izikhiye ze cursor +default_sound=move.wav +default_presentation=1 diff --git a/kruler/klineal.cpp b/kruler/klineal.cpp new file mode 100644 index 00000000..8f03c68b --- /dev/null +++ b/kruler/klineal.cpp @@ -0,0 +1,746 @@ +/*************************************************************************** + klineal.cpp - description + ------------------- + begin : Fri Oct 13 2000 + copyright : (C) 2000 by Till Krech + email : till@snafu.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "klineal.h" + +#define CFG_KEY_BGCOLOR "BgColor" +#define CFG_KEY_SCALE_FONT "ScaleFont" +#define CFG_KEY_LENGTH "Length" +#define CFG_GROUP_SETTINGS "StoredSettings" +#define DEFAULT_RULER_COLOR QColor(255, 200, 80) +#define FULLSCREENID 23 +/** +* this is our cursor bitmap: +* a line 48 pixels long with an arrow pointing down +* and a sqare with a one pixel hole at the top (end) +*/ +static const uchar cursorBits[] = { + 0x38, 0x28, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x10, +}; + +/** +* create the thingy with no borders and set up +* its members +*/ +KLineal::KLineal(QWidget*parent,const char* name):KMainWindow(parent,name){ + if (!name) { + name = "klineal"; + } + mLenMenu=0; + KWin::setType(winId(), NET::Override); // or NET::Normal + KWin::setState(winId(), NET::StaysOnTop); + setPaletteBackgroundColor(black); + QWhatsThis::add(this, + i18n( + "This is a tool to measure pixel distances and colors on the screen. " + "It is useful for working on layouts of dialogs, web pages etc." + )); + QBitmap bim = QBitmap(QSize(8, 48), cursorBits); + QWMatrix m; + m.rotate(90.0); + mNorthCursor = QCursor(bim, bim, 3, 47); + bim = bim.xForm(m); + mEastCursor = QCursor(bim, bim, 0, 3); + bim = bim.xForm(m); + mSouthCursor = QCursor(bim, bim, 4, 0); + bim = bim.xForm(m); + mWestCursor = QCursor(bim, bim, 47, 4); + + mCurrentCursor = mNorthCursor; + setMinimumSize(60,60); + setMaximumSize(8000,8000); + KConfig *cfg = kapp->config(); + QColor defaultColor = DEFAULT_RULER_COLOR; + QFont defaultFont(KGlobalSettings::generalFont().family(), 8); + defaultFont.setPixelSize(8); + if (cfg) { + cfg->setGroup(CFG_GROUP_SETTINGS); + mColor = cfg->readColorEntry(CFG_KEY_BGCOLOR, &defaultColor); + mScaleFont = cfg->readFontEntry(CFG_KEY_SCALE_FONT, &defaultFont); + mLongEdgeLen = cfg->readNumEntry(CFG_KEY_LENGTH, 600); + } else { + mColor = defaultColor; + mScaleFont = defaultFont; + mLongEdgeLen = 400; + } + kdDebug() << "mLongEdgeLen=" << mLongEdgeLen << endl; + mShortEdgeLen = 70; + + mLabel = new QLabel(this); + mLabel->setGeometry(0,height()-12,32,12); + mLabel->setBackgroundOrigin(ParentOrigin); + QFont labelFont(KGlobalSettings::generalFont().family(), 10); + labelFont.setPixelSize(10); + mLabel->setFont(labelFont); + QWhatsThis::add(mLabel, + i18n( + "This is the current distance measured in pixels." + )); + mColorLabel = new QLabel(this); + mColorLabel->resize(45,12); + mColorLabel->setPaletteBackgroundColor(mColor); + mColorLabel->hide(); + QFont colorFont(KGlobalSettings::fixedFont().family(), 10); + colorFont.setPixelSize(10); + mColorLabel->setFont(colorFont); + mColorLabel->move(mLabel->pos() + QPoint(0, 20)); + QWhatsThis::add(mColorLabel, + i18n( + "This is the current color in hexadecimal rgb representation as you may use it in HTML or as a QColor name. " + "The rectangles background shows the color of the pixel inside the " + "little square at the end of the line cursor." + )); + + resize(QSize(mLongEdgeLen, mShortEdgeLen)); + setMouseTracking(TRUE); + mDragging = FALSE; + mOrientation = South; + _clicked = false; + setOrientation(South); + // setMediumLength(); + mMenu = new KPopupMenu(this); + mMenu->insertTitle(i18n("KRuler")); + KPopupMenu *oriMenu = new KPopupMenu(this); + oriMenu->insertItem(UserIconSet("kruler-north"), i18n("&North"), this, SLOT(setNorth()), Key_N); + oriMenu->insertItem(UserIconSet("kruler-east"), i18n("&East"), this, SLOT(setEast()), Key_E); + oriMenu->insertItem(UserIconSet("kruler-south"), i18n("&South"), this, SLOT(setSouth()), Key_S); + oriMenu->insertItem(UserIconSet("kruler-west"), i18n("&West"), this, SLOT(setWest()), Key_W); + oriMenu->insertItem(i18n("&Turn Right"), this, SLOT(turnRight()), Key_R); + oriMenu->insertItem(i18n("Turn &Left"), this, SLOT(turnLeft()), Key_L); + mMenu->insertItem(i18n("&Orientation"), oriMenu); + mLenMenu = new KPopupMenu(this); + mLenMenu->insertItem(i18n("&Short"), this, SLOT(setShortLength()), CTRL+Key_S); + mLenMenu->insertItem(i18n("&Medium"), this, SLOT(setMediumLength()), CTRL+Key_M); + mLenMenu->insertItem(i18n("&Tall"), this, SLOT(setTallLength()), CTRL+Key_T); + mLenMenu->insertItem(i18n("&Full Screen Width"), this, SLOT(setFullLength()), CTRL+Key_F, FULLSCREENID); + mMenu->insertItem(i18n("&Length"), mLenMenu); + mMenu->insertItem(SmallIcon("colorscm"), i18n("&Choose Color..."), this, SLOT(choseColor()), CTRL+Key_C); + mMenu->insertItem(SmallIcon("font"), i18n("Choose &Font..."), this, SLOT(choseFont()), Key_F); + mMenu->insertSeparator(); + mMenu->insertItem(SmallIcon( "help" ), KStdGuiItem::help().text(), helpMenu()); + mMenu->insertSeparator(); + mMenu->insertItem(SmallIcon( "exit" ), KStdGuiItem::quit().text(), kapp, SLOT(quit()), CTRL+Key_Q); + mLastClickPos = geometry().topLeft()+QPoint(width()/2, height()/2); +} + +KLineal::~KLineal(){ +} + +void KLineal::move(int x, int y) { + move(QPoint(x, y)); +} + +void KLineal::move(const QPoint &p) { + setGeometry(QRect(p, size())); +} + +QPoint KLineal::pos() { + QRect r = frameGeometry(); + return r.topLeft(); +} +int KLineal::x() { + return pos().x(); +} +int KLineal::y() { + return pos().y(); +} + +static void rotateRect(QRect &r, QPoint center, int nineties) { + static int sintab[4] = {0,1,0,-1}; + static int costab[4] = {1,0,-1,0}; + int i=0; + int x1, y1, x2, y2; + if (nineties < 0) { + nineties = -nineties+4; + } + i = nineties % 4; + r.moveBy(-center.x(), -center.y()); + r.coords(&x1, &y1, &x2, &y2); + r.setCoords( + x1 * costab[i] + y1 * sintab[i], + -x1 * sintab[i] + y1 * costab[i], + x2 * costab[i] + y2 * sintab[i], + -x2 * sintab[i] + y2 * costab[i] + ); + r = r.normalize(); + r.moveBy(center.x(), center.y()); +} + +void KLineal::setupBackground() { + QColor a, b, bg = mColor; + KImageEffect::GradientType gradType = KImageEffect::HorizontalGradient; + switch (mOrientation) { + case North: + a = bg.light(120); + b = bg.dark(130); + gradType = KImageEffect::VerticalGradient; + break; + case South: + b = bg.light(120); + a = bg.dark(130); + gradType = KImageEffect::VerticalGradient; + break; + case West: + a = bg.light(120); + b = bg.dark(130); + gradType = KImageEffect::HorizontalGradient; + break; + case East: + b = bg.light(120); + a = bg.dark(130); + gradType = KImageEffect::HorizontalGradient; + break; + } + QPixmap bgPixmap = QPixmap(KImageEffect::gradient(size(), a, b, gradType)); + setErasePixmap(bgPixmap); + mLabel->setErasePixmap(bgPixmap); +} + +void KLineal::setOrientation(int inOrientation) { + QRect r = frameGeometry(); + int nineties = (int)inOrientation - (int)mOrientation; + QPoint center = mLastClickPos; + + if (_clicked) { + center = mLastClickPos; + _clicked = false; + } else { + center = r.topLeft()+QPoint(width()/2, height()/2); + } + + rotateRect(r, center, nineties); + + QRect desktop = KGlobalSettings::desktopGeometry(this); + if (r.top() < desktop.top()) + r.moveTop( desktop.top() ); + if (r.bottom() > desktop.bottom()) + r.moveBottom( desktop.bottom() ); + if (r.left() < desktop.left()) + r.moveLeft( desktop.left() ); + if (r.right() > desktop.right()) + r.moveRight( desktop.right() ); + + setGeometry(r); + mOrientation = (inOrientation + 4) % 4; + switch(mOrientation) { + case North: + mLabel->move(4, height()-mLabel->height()-4); + mColorLabel->move(mLabel->pos() + QPoint(0, -20)); + mCurrentCursor = mNorthCursor; + break; + case South: + mLabel->move(4, 4); + mColorLabel->move(mLabel->pos() + QPoint(0, 20)); + mCurrentCursor = mSouthCursor; + break; + case East: + mLabel->move(4, 4); + mColorLabel->move(mLabel->pos() + QPoint(0, 20)); + mCurrentCursor = mEastCursor; + break; + case West: + mLabel->move(width()-mLabel->width()-4, 4); + mColorLabel->move(mLabel->pos() + QPoint(-5, 20)); + mCurrentCursor = mWestCursor; + break; + } + if (mLenMenu) + mLenMenu->changeItem(FULLSCREENID, mOrientation % 2 ? i18n("&Full Screen Height") : i18n("&Full Screen Width")); + setCursor(mCurrentCursor); + setupBackground(); + repaint(); +} +void KLineal::setNorth() { + setOrientation(North); +} +void KLineal::setEast() { + setOrientation(East); +} +void KLineal::setSouth() { + setOrientation(South); +} +void KLineal::setWest() { + setOrientation(West); +} +void KLineal::turnRight() { + setOrientation(mOrientation - 1); +} +void KLineal::turnLeft() { + setOrientation(mOrientation + 1); +} +void KLineal::reLength(int percentOfScreen) { + if (percentOfScreen < 10) { + return; + } + QRect r = KGlobalSettings::desktopGeometry(this); + + if (mOrientation == North || mOrientation == South) { + mLongEdgeLen = r.width() * percentOfScreen / 100; + resize(mLongEdgeLen, height()); + } else { + mLongEdgeLen = r.height() * percentOfScreen / 100; + resize(width(), mLongEdgeLen); + } + if (x()+width() < 10) { + move (10, y()); + } + if (y()+height() < 10) { + move (x(), 10); + } + saveSettings(); +} +void KLineal::setShortLength() { + reLength(30); +} +void KLineal::setMediumLength() { + reLength(50); +} +void KLineal::setTallLength() { + reLength(75); +} +void KLineal::setFullLength() { + reLength(100); +} +void KLineal::choseColor() { + QRect r = KGlobalSettings::desktopGeometry(this); + + QPoint pos = QCursor::pos(); + if (pos.x() + mColorSelector.width() > r.width()) { + pos.setX(r.width() - mColorSelector.width()); + } + if (pos.y() + mColorSelector.height() > r.height()) { + pos.setY(r.height() - mColorSelector.height()); + } + mStoredColor = mColor; + mColorSelector.move(pos); + mColorSelector.setColor(mColor); + mColorSelector.setDefaultColor( DEFAULT_RULER_COLOR ); + mColorSelector.show(); + + connect(&mColorSelector, SIGNAL(okClicked()), this, SLOT(setColor())); + connect(&mColorSelector, SIGNAL(yesClicked()), this, SLOT(setColor())); + connect(&mColorSelector, SIGNAL(closeClicked()), this, SLOT(setColor())); + connect(&mColorSelector, SIGNAL(defaultClicked()), this, SLOT(setColor())); + connect(&mColorSelector, SIGNAL(colorSelected(const QColor&)), this, SLOT(setColor(const QColor&))); + /* + connect(&mColorSelector, SIGNAL(cancelPressed()), this, SLOT(restoreColor())); + connect(&mColorSelector, SIGNAL(okPressed()), this, SLOT(saveColor())); + */ +} + +/** +* slot to choose a font +*/ +void KLineal::choseFont() { + QFont font = mScaleFont; + int result = KFontDialog::getFont(font, false, this); + if (result == KFontDialog::Accepted) { + setFont(font); + } +} + +/** +* set the ruler color to the previously selected color +*/ +void KLineal::setFont(QFont &font) { + mScaleFont = font; + saveSettings(); + repaint(); +} + + +/** +* set the ruler color to the previously selected color +*/ +void KLineal::setColor() { + setColor(mColorSelector.color()); + saveSettings(); +} + +/** +* set the ruler color to some color +*/ +void KLineal::setColor(const QColor &color) { + mColor = color; + if ( !mColor.isValid() ) + mColor = DEFAULT_RULER_COLOR; + setupBackground(); +} + +/** +* save the ruler color to the config file +*/ +void KLineal::saveSettings() { + KConfig *cfg = kapp->config(); // new KConfig(locateLocal("config", kapp->name()+"rc")); + if (cfg) { + QColor color = mColor; + cfg->setGroup(CFG_GROUP_SETTINGS); + cfg->writeEntry(QString(CFG_KEY_BGCOLOR), color); + cfg->writeEntry(QString(CFG_KEY_SCALE_FONT), mScaleFont); + cfg->writeEntry(QString(CFG_KEY_LENGTH), mLongEdgeLen); + cfg->sync(); + } +} + +/** +* restores the color +*/ +void KLineal::restoreColor() { + setColor(mStoredColor); +} +/** +* lets the context menu appear at current cursor position +*/ +void KLineal::showMenu() { + QPoint pos = QCursor::pos(); + mMenu->popup(pos); +} + +/** +* overwritten to switch the value label and line cursor on +*/ +void KLineal::enterEvent(QEvent * /*inEvent*/) { + if (!mDragging) showLabel(); +} +/** +* overwritten to switch the value label and line cursor off +*/ +void KLineal::leaveEvent(QEvent * /*inEvent*/) { + if (!geometry().contains(QCursor::pos())) { + hideLabel(); + } +} +/** +* shows the value lable +*/ +void KLineal::showLabel() { + adjustLabel(); + mLabel->show(); + mColorLabel->show(); +} +/** +* hides the value label +*/ +void KLineal::hideLabel() { + mLabel->hide(); + mColorLabel->hide(); +} +/** +* updates the current value label +*/ +void KLineal::adjustLabel() { + QString s; + QPoint cpos = QCursor::pos(); + switch (mOrientation) { + case North: + s.sprintf("%d px", cpos.x()-x()); + break; + case East: + s.sprintf("%d px", cpos.y()-y()); + break; + case West: + s.sprintf("%d px", cpos.y()-y()); + break; + case South: + s.sprintf("%d px", cpos.x()-x()); + break; + } + mLabel->setText(s); +} +void KLineal::keyPressEvent(QKeyEvent *e) { + QPoint dist(0,0); + switch (e->key()) { + case Key_F1: + kapp->invokeHelp(); + break; + case Key_Left: + dist.setX(-1); + break; + case Key_Right: + dist.setX(1); + break; + case Key_Up: + dist.setY(-1); + break; + case Key_Down: + dist.setY(1); + break; + default: + KMainWindow::keyPressEvent(e); + return; + } + if (e->state() & ShiftButton) { + dist *= 10; + } + move(pos()+dist); + KNotifyClient::event(0, "cursormove", QString::null); +} +/** +* overwritten to handle the line cursor which is a seperate widget outside the main +* window. Also used for dragging. +*/ +void KLineal::mouseMoveEvent(QMouseEvent * /*inEvent*/) { + if (mDragging && this == mouseGrabber()) { + move(QCursor::pos() - mDragOffset); + } else { + QPoint p = QCursor::pos(); + switch (mOrientation) { + case North: + p.setY(p.y()-46); + break; + case East: + p.setX(p.x()+46); + break; + case West: + p.setX(p.x()-46); + break; + case South: + p.setY(p.y()+46); + break; + } + // cerr << p.x()-x() << "," << p.y()-y() << ": " << KColorDialog::grabColor(p).name() << endl; + QColor color = KColorDialog::grabColor(p); + int h, s, v; + color.hsv(&h, &s, &v); + mColorLabel->setText(color.name().upper()); + mColorLabel->setPaletteBackgroundColor(color); + if (v < 255/2) { + v = 255; + } else { + v = 0; + } + color.setHsv(h, s, v); + QPalette palette = mColorLabel->palette(); + palette.setColor(QColorGroup::Foreground, color); + mColorLabel->setPalette(palette); + adjustLabel(); + } +} + +/** +* overwritten for dragging and contect menu +*/ +void KLineal::mousePressEvent(QMouseEvent *inEvent) { + mLastClickPos = QCursor::pos(); + hideLabel(); + + QRect gr = geometry(); + mDragOffset = mLastClickPos - QPoint(gr.left(), gr.top()); + if (inEvent->button() == LeftButton) { + if (!mDragging) { + grabMouse(KCursor::sizeAllCursor()); + mDragging = TRUE; + } + } else if (inEvent->button() == MidButton) { + _clicked = true; + turnLeft(); + } else if (inEvent->button() == RightButton) { + showMenu(); + } +} +/** +* overwritten for dragging +*/ +void KLineal::mouseReleaseEvent(QMouseEvent * /*inEvent*/) { + if (mDragging) { + mDragging = FALSE; + releaseMouse(); + } + showLabel(); +} +/** +* draws the scale according to the orientation +*/ +void KLineal::drawScale(QPainter &painter) { + painter.setPen(black); + QFont font = mScaleFont; + // font.setPixelSize(9); + painter.setFont(font); + QFontMetrics metrics = painter.fontMetrics(); + int longCoo; + int longLen; + int shortStart; + int w = width(); + int h = height(); + + // draw a frame around the whole thing + // (for some unknown reason, this doesn't show up anymore) + switch (mOrientation) { + case North: + default: + shortStart = 0; + longLen = w; + painter.drawLine(0, 0, 0, h-1); + painter.drawLine(0, h-1, w-1, h-1); + painter.drawLine(w-1, h-1, w-1, 0); + // painter.drawLine(width()-1, 0, 0, 0); + break; + case East: + shortStart = w; + longLen = h; + painter.drawLine(0, 0, 0, h-1); + painter.drawLine(0, h-1, w-1, h-1); + // painter.drawLine(width()-1, height()-1, width()-1, 0); + painter.drawLine(w-1, 0, 0, 0); + break; + case South: + shortStart = h; + longLen = w; + painter.drawLine(0, 0, 0, h-1); + // painter.drawLine(0, height()-1, width()-1, height()-1); + painter.drawLine(w-1, h-1, w-1, 0); + painter.drawLine(w-1, 0, 0, 0); + break; + case West: + shortStart = 0; + longLen = h; + // painter.drawLine(0, 0, 0, height()-1); + painter.drawLine(0, h-1, w-1, h-1); + painter.drawLine(w-1, h-1, w-1, 0); + painter.drawLine(w-1, 0, 0, 0); + break; + } + int ten = 10, twenty = 20, fourty = 40, hundred = 100; + for (longCoo = 0; longCoo < longLen; longCoo+=2) { + int len = 6; + if (ten == 10) { + if (twenty == 20) { + /**/ + if (hundred == 100) { + font.setBold(true); + painter.setFont(font); + len = 18; + } else { + len = 15; + } + QString units; + int digits; + if (hundred == 100 || mOrientation == West || mOrientation == East) { + digits = longCoo; + } else { + digits = longCoo % 100; + } + units.sprintf("%d", digits); + QSize textSize = metrics.size(SingleLine, units); + int tw = textSize.width(); + int th = textSize.height(); + switch (mOrientation) { + case North: + if (digits < 1000 || fourty == 40 || hundred == 100) { + if (longCoo != 0) { + painter.drawText(longCoo - tw/2, shortStart + len + th, units); + } else { + painter.drawText(1, shortStart + len + th, units); + } + } + break; + case South: + if (digits < 1000 || fourty == 40 || hundred == 100) { + if (longCoo != 0) { + painter.drawText(longCoo - tw/2, shortStart - len - 2, units); + } else { + painter.drawText(1, shortStart - len - 2, units); + } + } + break; + case East: + if (longCoo != 0) { + painter.drawText(shortStart - len - tw - 2, longCoo + th/2 - 2, units); + } else { + painter.drawText(shortStart - len - tw - 2, th-2, units); + } + break; + case West: + if (longCoo != 0) { + painter.drawText(shortStart + len + 2, longCoo + th/2 - 2, units); + } else { + painter.drawText(shortStart + len + 2, th-2, units); + } + break; + } + } else { + len = 10; + } + } + switch(mOrientation) { + case North: + painter.drawLine(longCoo, shortStart, longCoo, shortStart+len); + break; + case South: + painter.drawLine(longCoo, shortStart, longCoo, shortStart-len); + break; + case East: + painter.drawLine(shortStart, longCoo, shortStart-len, longCoo); + break; + case West: + painter.drawLine(shortStart, longCoo, shortStart+len, longCoo); + break; + } + ten = (ten == 10) ? 2: ten + 2; + twenty = (twenty == 20) ? 2: twenty + 2; + fourty = (fourty == 40) ? 2: fourty + 2; + if (hundred == 100) { + hundred = 2; + font.setBold(false); + painter.setFont(font); + } else { + hundred += 2; + } + } +} +/** +* actually draws the ruler +*/ +void KLineal::paintEvent(QPaintEvent * /*inEvent*/) { + QPainter painter; + painter.begin(this); + drawScale(painter); + painter.end(); +} + +#include "klineal.moc" diff --git a/kruler/klineal.h b/kruler/klineal.h new file mode 100644 index 00000000..6fcf7015 --- /dev/null +++ b/kruler/klineal.h @@ -0,0 +1,106 @@ +/*************************************************************************** + klineal.h - description + ------------------- + begin : Fri Oct 13 2000 + copyright : (C) 2000 by Till Krech + email : till@snafu.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KLINEAL_H +#define KLINEAL_H + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +class KLineal : public KMainWindow { + Q_OBJECT +public: + enum { North=0, West=1, South=2, East=3 }; + /** constructor */ + KLineal(QWidget*parent=0,const char* name=0); + /** destructor */ + ~KLineal(); + void move(int x, int y); + void move(const QPoint &p); + QPoint pos(); + int x(); + int y(); +protected: + void keyPressEvent(QKeyEvent *e); + void mousePressEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void paintEvent(QPaintEvent *e); + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + void setupBackground(); + + +private: + void drawScale(QPainter &painter); + void reLength(int percentOfScreen); + bool mDragging; + QPoint mLastClickPos; + QPoint mDragOffset; + QLabel *mLabel; + QLabel *mColorLabel; + QFrame *mColorRect; + int mOrientation; + int mLongEdgeLen; + int mShortEdgeLen; + KPopupMenu *mMenu; + KPopupMenu *mLenMenu; + QColor mColor; + QColor mStoredColor; + QCursor mCurrentCursor; + QCursor mNorthCursor; + QCursor mEastCursor; + QCursor mWestCursor; + QCursor mSouthCursor; + QCursor mDragCursor; + KColorDialog mColorSelector; + QFont mScaleFont; + bool _clicked; +public slots: + void setOrientation(int); + void setNorth(); + void setEast(); + void setSouth(); + void setWest(); + void turnLeft(); + void turnRight(); + void showMenu(); + void hideLabel(); + void showLabel(); + void adjustLabel(); + void setShortLength(); + void setMediumLength(); + void setTallLength(); + void setFullLength(); + void setColor(); + void setFont(QFont &); + void setColor(const QColor &color); + void choseColor(); + void choseFont(); + void restoreColor(); + void saveSettings(); +}; +#endif diff --git a/kruler/kruler.desktop b/kruler/kruler.desktop new file mode 100644 index 00000000..0d9e4cc6 --- /dev/null +++ b/kruler/kruler.desktop @@ -0,0 +1,90 @@ +[Desktop Entry] +GenericName=Screen Ruler +GenericName[af]=Skerm Liniaal +GenericName[ar]=مسطرة الشاشة +GenericName[bg]=Линийка за екрана +GenericName[bs]=Ekranski linijar +GenericName[ca]=Regla de pantalla +GenericName[cs]=Obrazovkové pravítko +GenericName[cy]=Mesurydd Sgrîn +GenericName[da]=Skærmlineal +GenericName[de]=Bildschirmlineal +GenericName[el]=Χάρακας οθόνης +GenericName[eo]=Ekranliniilo +GenericName[es]=Regla para la pantalla +GenericName[et]=Ekraani joonlaud +GenericName[eu]=Pantaila erregela +GenericName[fa]=خط‌کش پرده +GenericName[fi]=Näytön mittaaja +GenericName[fr]=Règle d'écran +GenericName[gl]=Regra de pantalla +GenericName[he]=סרגל מסך +GenericName[hi]=स्क्रीन रूलर +GenericName[hr]=Ravnalo +GenericName[hu]=Képernyővonalzó +GenericName[is]=Reglustika +GenericName[it]=Righello per lo schermo +GenericName[ja]=スクリーン定規 +GenericName[kk]=Экран өлшегіші +GenericName[km]=បន្ទាត់​អេក្រង់ +GenericName[lt]=Ekrano liniuotė +GenericName[lv]=Ekrāna Mērjosla +GenericName[ms]=Pembaris Skrin +GenericName[nb]=Skjermlinjal +GenericName[nds]=Schirmlineaal +GenericName[ne]=पर्दा रूलर +GenericName[nl]=Schermliniaal +GenericName[nn]=Skjermlinjal +GenericName[pl]=Linijka ekranowa +GenericName[pt]=Régua do Ecrã +GenericName[pt_BR]=Régua da Tela +GenericName[ro]=Riglă de ecran +GenericName[ru]=Экранная линейка KDE +GenericName[se]=Šearpmalinjála +GenericName[sk]=Pravítko obrazovky +GenericName[sl]=Zaslonsko ravnilo +GenericName[sr]=Екрански лењир +GenericName[sr@Latn]=Ekranski lenjir +GenericName[sv]=Skärmlinjal +GenericName[ta]=திரை உருளை +GenericName[tg]=Ҷадвали экрании KDE +GenericName[th]=ไม้บรรทัดสำหรับจอภาพ +GenericName[tr]=Ekran Cetveli +GenericName[uk]=Лінійка екрана +GenericName[uz]=Ekran lineykasi +GenericName[uz@cyrillic]=Экран линейкаси +GenericName[ven]=Muvhusi wa Tshikirini +GenericName[zh_CN]=屏幕标尺 +GenericName[zh_HK]=螢幕尺規 +GenericName[zh_TW]=螢幕尺規 +GenericName[zu]=Umlawuli Wesikrini +Name=KRuler +Name[af]=K-lineaal +Name[ar]=المسطرة (KRuler) +Name[cy]=KMesurydd +Name[eo]=Liniilo +Name[hi]=के-रूलर +Name[hr]=Ravnalo +Name[is]=KReglustika +Name[lv]=KRulers +Name[ms]=KPembaris +Name[ne]=केडीई रूलर +Name[pl]=Linijka +Name[pt_BR]=KRégua +Name[ro]=Riglă +Name[sv]=Kruler +Name[ta]=கேவரை உருளை +Name[th]=ไม้บรรทัด - K +Name[ven]=Muvhusi wa K +Name[zh_TW]=KRuler 尺規 +Name[zu]=KUmlawuli +DocPath=kruler/index.html +MimeType= +Exec=kruler %i %m +Type=Application +Path= +Icon=kruler +Terminal=false +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Multi +Categories=Qt;KDE;Graphics;X-KDE-More; diff --git a/kruler/main.cpp b/kruler/main.cpp new file mode 100644 index 00000000..484ca318 --- /dev/null +++ b/kruler/main.cpp @@ -0,0 +1,48 @@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "klineal.h" + +static const char homePageURL[] = + "http://www.snafu.de/~till/"; +static const char freeFormText[] = + "\"May the source be with you.\""; + + + +static KCmdLineOptions options[] = +{ + KCmdLineLastOption + // INSERT YOUR COMMANDLINE OPTIONS HERE +}; + +int main(int argc, char *argv[]) +{ + + + KAboutData aboutData( "kruler", I18N_NOOP("KDE Screen Ruler"), + VERSION, + I18N_NOOP("A screen ruler for the K Desktop Environment"), + KAboutData::License_GPL, + "(c) 2000, Till Krech", + freeFormText, + homePageURL); + aboutData.addAuthor("Till Krech",I18N_NOOP("Programming"), "till@snafu.de"); + aboutData.addCredit("Gunnstein Lye",I18N_NOOP("Initial port to KDE 2"), "gl@ez.no"); + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); // Add our own options. + + KApplication a; + + KLineal *ruler = new KLineal(); + a.setMainWidget(ruler); + ruler->show(); + + return a.exec(); +} diff --git a/kruler/move.wav b/kruler/move.wav new file mode 100644 index 00000000..4922ac4b Binary files /dev/null and b/kruler/move.wav differ diff --git a/kruler/pics/Makefile.am b/kruler/pics/Makefile.am new file mode 100644 index 00000000..e29a8776 --- /dev/null +++ b/kruler/pics/Makefile.am @@ -0,0 +1,5 @@ + +pixdir = $(kde_datadir)/kruler/pics +pix_DATA = kruler-east.png kruler-north.png kruler-south.png kruler-west.png + +KDE_ICON = kruler diff --git a/kruler/pics/hi16-app-kruler.png b/kruler/pics/hi16-app-kruler.png new file mode 100644 index 00000000..dd1b953c Binary files /dev/null and b/kruler/pics/hi16-app-kruler.png differ diff --git a/kruler/pics/hi22-app-kruler.png b/kruler/pics/hi22-app-kruler.png new file mode 100644 index 00000000..32d29686 Binary files /dev/null and b/kruler/pics/hi22-app-kruler.png differ diff --git a/kruler/pics/hi32-app-kruler.png b/kruler/pics/hi32-app-kruler.png new file mode 100644 index 00000000..bd4cc0f5 Binary files /dev/null and b/kruler/pics/hi32-app-kruler.png differ diff --git a/kruler/pics/hi48-app-kruler.png b/kruler/pics/hi48-app-kruler.png new file mode 100644 index 00000000..6e35b591 Binary files /dev/null and b/kruler/pics/hi48-app-kruler.png differ diff --git a/kruler/pics/kruler-east.png b/kruler/pics/kruler-east.png new file mode 100644 index 00000000..1a87ae7d Binary files /dev/null and b/kruler/pics/kruler-east.png differ diff --git a/kruler/pics/kruler-north.png b/kruler/pics/kruler-north.png new file mode 100644 index 00000000..32d29686 Binary files /dev/null and b/kruler/pics/kruler-north.png differ diff --git a/kruler/pics/kruler-south.png b/kruler/pics/kruler-south.png new file mode 100644 index 00000000..d6c3eb5c Binary files /dev/null and b/kruler/pics/kruler-south.png differ diff --git a/kruler/pics/kruler-west.png b/kruler/pics/kruler-west.png new file mode 100644 index 00000000..473ac39b Binary files /dev/null and b/kruler/pics/kruler-west.png differ diff --git a/kruler/uninstall.desktop b/kruler/uninstall.desktop new file mode 100644 index 00000000..e1e3e173 --- /dev/null +++ b/kruler/uninstall.desktop @@ -0,0 +1,2 @@ +[Desktop Entry] +Hidden=true diff --git a/ksnapshot/Makefile.am b/ksnapshot/Makefile.am new file mode 100644 index 00000000..a9dae435 --- /dev/null +++ b/ksnapshot/Makefile.am @@ -0,0 +1,21 @@ +bin_PROGRAMS= ksnapshot + +INCLUDES = -DKSNAPVERSION="\"0.7\"" $(all_includes) + +ksnapshot_LDFLAGS = $(all_libraries) $(KDE_RPATH) +ksnapshot_LDADD = $(LIB_KDEPRINT) + +ksnapshot_SOURCES = ksnapshotiface.skel main.cpp ksnapshot.cpp \ + regiongrabber.cpp windowgrabber.cpp ksnapshotwidget.ui + +ksnapshot_METASOURCES = AUTO + +xdg_apps_DATA = ksnapshot.desktop + +KDE_ICON = ksnapshot + +EXTRA_DIST = $(xdg_apps_DATA) + +messages: rc.cpp + $(XGETTEXT) rc.cpp *.cpp -o $(podir)/ksnapshot.pot + diff --git a/ksnapshot/README b/ksnapshot/README new file mode 100644 index 00000000..0aa0b121 --- /dev/null +++ b/ksnapshot/README @@ -0,0 +1,29 @@ + KSnapshot Release Notes + ======================= + +KSnapshot is intended to be an easy to use program for making +screenshots. I can be bound to the Print Screen" key, as the program +takes a snapshot of the desktop on startup (before it displays it +window), so it's a simple way of of making snapshots. + +Currently Implemented features: + +- Mini Preview image +- Adjustable time delay. +- Auto hides it own window when grabbing. +- Grabs desktop or specific windows +- Save to various formats +- Auto increment filename + + +The original KSnapshot was implemented by Richard Moore (rich@kde.org) +for KDE1. Shortly before KDE2 I rewrote most of it to bring it a bit +closer to KDE2' higher standards. + +This version is still not good, but I wanted something that doesn't +break translations and is still comfortable to old ksnapshot users. + +Use Pixie if you want more functionality. + +Matthias ( ettrich@kde.org) + diff --git a/ksnapshot/configure.in.in b/ksnapshot/configure.in.in new file mode 100644 index 00000000..56c82023 --- /dev/null +++ b/ksnapshot/configure.in.in @@ -0,0 +1,6 @@ +dnl Check for the X shaped windows extension - test taken from kdebase/kwin/clients/keramik +KDE_CHECK_HEADERS(X11/extensions/shape.h,,, +[ +#include +#include +]) diff --git a/ksnapshot/hi16-app-ksnapshot.png b/ksnapshot/hi16-app-ksnapshot.png new file mode 100644 index 00000000..79743e82 Binary files /dev/null and b/ksnapshot/hi16-app-ksnapshot.png differ diff --git a/ksnapshot/hi22-app-ksnapshot.png b/ksnapshot/hi22-app-ksnapshot.png new file mode 100644 index 00000000..446af476 Binary files /dev/null and b/ksnapshot/hi22-app-ksnapshot.png differ diff --git a/ksnapshot/hi32-app-ksnapshot.png b/ksnapshot/hi32-app-ksnapshot.png new file mode 100644 index 00000000..4619ae8d Binary files /dev/null and b/ksnapshot/hi32-app-ksnapshot.png differ diff --git a/ksnapshot/hi48-app-ksnapshot.png b/ksnapshot/hi48-app-ksnapshot.png new file mode 100644 index 00000000..f962f5a0 Binary files /dev/null and b/ksnapshot/hi48-app-ksnapshot.png differ diff --git a/ksnapshot/hisc-app-ksnapshot.svgz b/ksnapshot/hisc-app-ksnapshot.svgz new file mode 100644 index 00000000..22f4e3fb Binary files /dev/null and b/ksnapshot/hisc-app-ksnapshot.svgz differ diff --git a/ksnapshot/ksnapshot.cpp b/ksnapshot/ksnapshot.cpp new file mode 100644 index 00000000..a0e1d06f --- /dev/null +++ b/ksnapshot/ksnapshot.cpp @@ -0,0 +1,510 @@ +/* + * KSnapshot + * + * (c) Richard J. Moore 1997-2002 + * (c) Matthias Ettrich 2000 + * (c) Aaron J. Seigo 2002 + * (c) Nadeem Hasan 2003 + * (c) Bernd Brandstetter 2004 + * + * Released under the LGPL see file LICENSE for details. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "ksnapshot.h" +#include "regiongrabber.h" +#include "windowgrabber.h" +#include "ksnapshotwidget.h" + +#include +#include + +#include + +#include + +#define kApp KApplication::kApplication() + +KSnapshot::KSnapshot(QWidget *parent, const char *name, bool grabCurrent) + : DCOPObject("interface"), + KDialogBase(parent, name, true, QString::null, Help|User1, User1, + true, KStdGuiItem::quit() ) +{ + grabber = new QWidget( 0, 0, WStyle_Customize | WX11BypassWM ); + grabber->move( -1000, -1000 ); + grabber->installEventFilter( this ); + + KStartupInfo::appStarted(); + + QVBox *vbox = makeVBoxMainWidget(); + mainWidget = new KSnapshotWidget( vbox, "mainWidget" ); + + connect(mainWidget, SIGNAL(startImageDrag()), SLOT(slotDragSnapshot())); + + connect( mainWidget, SIGNAL( newClicked() ), SLOT( slotGrab() ) ); + connect( mainWidget, SIGNAL( saveClicked() ), SLOT( slotSaveAs() ) ); + connect( mainWidget, SIGNAL( printClicked() ), SLOT( slotPrint() ) ); + connect( mainWidget, SIGNAL( copyClicked() ), SLOT( slotCopy() ) ); + + grabber->show(); + grabber->grabMouse( waitCursor ); + + if ( !grabCurrent ) + snapshot = QPixmap::grabWindow( qt_xrootwin() ); + else { + mainWidget->setMode( WindowUnderCursor ); + mainWidget->setIncludeDecorations( true ); + performGrab(); + } + + updatePreview(); + grabber->releaseMouse(); + grabber->hide(); + + KConfig *conf=KGlobal::config(); + conf->setGroup("GENERAL"); + mainWidget->setDelay(conf->readNumEntry("delay",0)); + mainWidget->setMode( conf->readNumEntry( "mode", 0 ) ); + mainWidget->setIncludeDecorations(conf->readBoolEntry("includeDecorations",true)); + filename = KURL::fromPathOrURL( conf->readPathEntry( "filename", QDir::currentDirPath()+"/"+i18n("snapshot")+"1.png" )); + + // Make sure the name is not already being used + while(KIO::NetAccess::exists( filename, false, this )) { + autoincFilename(); + } + + connect( &grabTimer, SIGNAL( timeout() ), this, SLOT( grabTimerDone() ) ); + connect( &updateTimer, SIGNAL( timeout() ), this, SLOT( updatePreview() ) ); + QTimer::singleShot( 0, this, SLOT( updateCaption() ) ); + + KHelpMenu *helpMenu = new KHelpMenu(this, KGlobal::instance()->aboutData(), false); + + QPushButton *helpButton = actionButton( Help ); + helpButton->setPopup(helpMenu->menu()); + + KAccel* accel = new KAccel(this); + accel->insert(KStdAccel::Quit, kapp, SLOT(quit())); + accel->insert( "QuickSave", i18n("Quick Save Snapshot &As..."), + i18n("Save the snapshot to the file specified by the user without showing the file dialog."), + CTRL+SHIFT+Key_S, this, SLOT(slotSave())); + accel->insert(KStdAccel::Save, this, SLOT(slotSaveAs())); +// accel->insert(KShortcut(CTRL+Key_A), this, SLOT(slotSaveAs())); + accel->insert( "SaveAs", i18n("Save Snapshot &As..."), + i18n("Save the snapshot to the file specified by the user."), + CTRL+Key_A, this, SLOT(slotSaveAs())); + accel->insert(KStdAccel::Print, this, SLOT(slotPrint())); + accel->insert(KStdAccel::New, this, SLOT(slotGrab())); + accel->insert(KStdAccel::Copy, this, SLOT(slotCopy())); + + accel->insert( "Quit2", Key_Q, this, SLOT(slotSave())); + accel->insert( "Save2", Key_S, this, SLOT(slotSaveAs())); + accel->insert( "Print2", Key_P, this, SLOT(slotPrint())); + accel->insert( "New2", Key_N, this, SLOT(slotGrab())); + accel->insert( "New3", Key_Space, this, SLOT(slotGrab())); + + setEscapeButton( User1 ); + connect( this, SIGNAL( user1Clicked() ), SLOT( reject() ) ); + + mainWidget->btnNew->setFocus(); +} + +KSnapshot::~KSnapshot() +{ +} + +void KSnapshot::resizeEvent( QResizeEvent *event) +{ + if( !updateTimer.isActive() ) + updateTimer.start(200, true); + else + updateTimer.changeInterval(200); +} + +bool KSnapshot::save( const QString &filename ) +{ + return save( KURL::fromPathOrURL( filename )); +} + +bool KSnapshot::save( const KURL& url ) +{ + if ( KIO::NetAccess::exists( url, false, this ) ) { + const QString title = i18n( "File Exists" ); + const QString text = i18n( "Do you really want to overwrite %1?" ).arg(url.prettyURL()); + if (KMessageBox::Continue != KMessageBox::warningContinueCancel( this, text, title, i18n("Overwrite") ) ) + { + return false; + } + } + + QString type( KImageIO::type(url.path()) ); + if ( type.isNull() ) + type = "PNG"; + + bool ok = false; + + if ( url.isLocalFile() ) { + KSaveFile saveFile( url.path() ); + if ( saveFile.status() == 0 ) { + if ( snapshot.save( saveFile.file(), type.latin1() ) ) + ok = saveFile.close(); + } + } + else { + KTempFile tmpFile; + tmpFile.setAutoDelete( true ); + if ( tmpFile.status() == 0 ) { + if ( snapshot.save( tmpFile.file(), type.latin1() ) ) { + if ( tmpFile.close() ) + ok = KIO::NetAccess::upload( tmpFile.name(), url, this ); + } + } + } + + QApplication::restoreOverrideCursor(); + if ( !ok ) { + kdWarning() << "KSnapshot was unable to save the snapshot" << endl; + + QString caption = i18n("Unable to save image"); + QString text = i18n("KSnapshot was unable to save the image to\n%1.") + .arg(url.prettyURL()); + KMessageBox::error(this, text, caption); + } + + return ok; +} + +void KSnapshot::slotSave() +{ + if ( save(filename) ) { + modified = false; + autoincFilename(); + } +} + +void KSnapshot::slotSaveAs() +{ + QStringList mimetypes = KImageIO::mimeTypes( KImageIO::Writing ); + KFileDialog dlg( filename.url(), mimetypes.join(" "), this, "filedialog", true); + + dlg.setOperationMode( KFileDialog::Saving ); + dlg.setCaption( i18n("Save As") ); + + KImageFilePreview *ip = new KImageFilePreview( &dlg ); + dlg.setPreviewWidget( ip ); + + if ( !dlg.exec() ) + return; + + KURL url = dlg.selectedURL(); + if ( !url.isValid() ) + return; + + if ( save(url) ) { + filename = url; + modified = false; + autoincFilename(); + } +} + +void KSnapshot::slotCopy() +{ + QClipboard *cb = QApplication::clipboard(); + cb->setPixmap( snapshot ); +} + +void KSnapshot::slotDragSnapshot() +{ + QDragObject *drobj = new QImageDrag(snapshot.convertToImage(), this); + drobj->setPixmap(mainWidget->preview()); + drobj->dragCopy(); +} + +void KSnapshot::slotGrab() +{ + hide(); + + if ( mainWidget->delay() && mainWidget->mode() != Region ) + grabTimer.start( mainWidget->delay() * 1000, true ); + else { + if ( mainWidget->mode() == Region ) { + rgnGrab = new RegionGrabber(); + connect( rgnGrab, SIGNAL( regionGrabbed( const QPixmap & ) ), + SLOT( slotRegionGrabbed( const QPixmap & ) ) ); + } + else { + grabber->show(); + grabber->grabMouse( crossCursor ); + } + } +} + +void KSnapshot::slotPrint() +{ + KPrinter printer; + if (snapshot.width() > snapshot.height()) + printer.setOrientation(KPrinter::Landscape); + else + printer.setOrientation(KPrinter::Portrait); + + qApp->processEvents(); + + if (printer.setup(this, i18n("Print Screenshot"))) + { + qApp->processEvents(); + + QPainter painter(&printer); + QPaintDeviceMetrics metrics(painter.device()); + + float w = snapshot.width(); + float dw = w - metrics.width(); + float h = snapshot.height(); + float dh = h - metrics.height(); + bool scale = false; + + if ( (dw > 0.0) || (dh > 0.0) ) + scale = true; + + if ( scale ) { + + QImage img = snapshot.convertToImage(); + qApp->processEvents(); + + float newh, neww; + if ( dw > dh ) { + neww = w-dw; + newh = neww/w*h; + } + else { + newh = h-dh; + neww = newh/h*w; + } + + img = img.smoothScale( int(neww), int(newh), QImage::ScaleMin ); + qApp->processEvents(); + + int x = (metrics.width()-img.width())/2; + int y = (metrics.height()-img.height())/2; + + painter.drawImage( x, y, img); + } + else { + int x = (metrics.width()-snapshot.width())/2; + int y = (metrics.height()-snapshot.height())/2; + painter.drawPixmap( x, y, snapshot ); + } + } + + qApp->processEvents(); +} + +void KSnapshot::slotRegionGrabbed( const QPixmap &pix ) +{ + if ( !pix.isNull() ) + { + snapshot = pix; + updatePreview(); + modified = true; + updateCaption(); + } + + delete rgnGrab; + QApplication::restoreOverrideCursor(); + show(); +} + +void KSnapshot::slotWindowGrabbed( const QPixmap &pix ) +{ + if ( !pix.isNull() ) + { + snapshot = pix; + updatePreview(); + modified = true; + updateCaption(); + } + + QApplication::restoreOverrideCursor(); + show(); +} + +void KSnapshot::closeEvent( QCloseEvent * e ) +{ + KConfig *conf=KGlobal::config(); + conf->setGroup("GENERAL"); + conf->writeEntry("delay",mainWidget->delay()); + conf->writeEntry("mode",mainWidget->mode()); + conf->writeEntry("includeDecorations",mainWidget->includeDecorations()); + KURL url = filename; + url.setPass( QString::null ); + conf->writePathEntry("filename",url.url()); + e->accept(); +} + +bool KSnapshot::eventFilter( QObject* o, QEvent* e) +{ + if ( o == grabber && e->type() == QEvent::MouseButtonPress ) { + QMouseEvent* me = (QMouseEvent*) e; + if ( QWidget::mouseGrabber() != grabber ) + return false; + if ( me->button() == LeftButton ) + performGrab(); + } + return false; +} + +void KSnapshot::autoincFilename() +{ + // Extract the filename from the path + QString name= filename.fileName(); + + // If the name contains a number then increment it + QRegExp numSearch("[0-9]+"); + + // Does it have a number? + int start = numSearch.search(name); + if (start != -1) { + // It has a number, increment it + int len = numSearch.matchedLength(); + QString numAsStr= name.mid(start, len); + QString number = QString::number(numAsStr.toInt() + 1); + number = number.rightJustify( len, '0'); + name.replace(start, len, number ); + } + else { + // no number + start = name.findRev('.'); + if (start != -1) { + // has a . somewhere, e.g. it has an extension + name.insert(start, '1'); + } + else { + // no extension, just tack it on to the end + name += '1'; + } + } + + //Rebuild the path + KURL newURL = filename; + newURL.setFileName( name ); + setURL( newURL.url() ); +} + +void KSnapshot::updatePreview() +{ + mainWidget->setPreview( snapshot ); +} + +void KSnapshot::grabTimerDone() +{ + if ( mainWidget->mode() == Region ) { + rgnGrab = new RegionGrabber(); + connect( rgnGrab, SIGNAL( regionGrabbed( const QPixmap & ) ), + SLOT( slotRegionGrabbed( const QPixmap & ) ) ); + } + else { + performGrab(); + } + KNotifyClient::beep(i18n("The screen has been successfully grabbed.")); +} + +void KSnapshot::performGrab() +{ + grabber->releaseMouse(); + grabber->hide(); + grabTimer.stop(); + if ( mainWidget->mode() == ChildWindow ) { + WindowGrabber wndGrab; + connect( &wndGrab, SIGNAL( windowGrabbed( const QPixmap & ) ), + SLOT( slotWindowGrabbed( const QPixmap & ) ) ); + wndGrab.exec(); + } + else if ( mainWidget->mode() == WindowUnderCursor ) { + snapshot = WindowGrabber::grabCurrent( mainWidget->includeDecorations() ); + } + else { + snapshot = QPixmap::grabWindow( qt_xrootwin() ); + } + updatePreview(); + QApplication::restoreOverrideCursor(); + modified = true; + updateCaption(); + show(); +} + +void KSnapshot::setTime(int newTime) +{ + mainWidget->setDelay(newTime); +} + +int KSnapshot::timeout() +{ + return mainWidget->delay(); +} + +void KSnapshot::setURL( const QString &url ) +{ + KURL newURL = KURL::fromPathOrURL( url ); + if ( newURL == filename ) + return; + + filename = newURL; + updateCaption(); +} + +void KSnapshot::setGrabMode( int m ) +{ + mainWidget->setMode( m ); +} + +int KSnapshot::grabMode() +{ + return mainWidget->mode(); +} + +void KSnapshot::updateCaption() +{ + setCaption( kApp->makeStdCaption( filename.fileName(), true, modified ) ); +} + +void KSnapshot::slotMovePointer(int x, int y) +{ + QCursor::setPos( x, y ); +} + +void KSnapshot::exit() +{ + reject(); +} +#include "ksnapshot.moc" diff --git a/ksnapshot/ksnapshot.desktop b/ksnapshot/ksnapshot.desktop new file mode 100644 index 00000000..311a2199 --- /dev/null +++ b/ksnapshot/ksnapshot.desktop @@ -0,0 +1,92 @@ +[Desktop Entry] +GenericName=Screen Capture Program +GenericName[af]=Skerm Vang Program +GenericName[ar]=برنامج تصوير الشاشة +GenericName[bg]=Снимки на екрана +GenericName[bs]=Program za "hvatanje" slike +GenericName[ca]=Programa de captura de pantalla +GenericName[cs]=Snímač obrazovky +GenericName[cy]=Rhaglen Cipio'r Sgrîn +GenericName[da]=Program til øjebliksbilleder +GenericName[de]=Bildschirmphotos +GenericName[el]=Πρόγραμμα σύλληψης οθόνης +GenericName[eo]=Ekranfota programo +GenericName[es]=Capturador de pantalla +GenericName[et]=Töölaua pildistamine +GenericName[eu]=Pantailari argazkiak ateratzeko programa +GenericName[fa]=برنامۀ گیراندازی پرده +GenericName[fi]=Ruudunkaappausohjelma +GenericName[fr]=Logiciel de capture d'écran +GenericName[ga]=Clár gabhála scáileáin +GenericName[gl]=Progama para facer capturas de pantalla +GenericName[he]=תוכנית לצילום המסך +GenericName[hi]=स्क्रीन केप्चर प्रोग्राम +GenericName[hr]=Program za snimanje zaslona +GenericName[hu]=Képlopó +GenericName[is]=Forrit sem grípur skjámyndir +GenericName[it]=Scatta foto allo schermo +GenericName[ja]=スクリーンキャプチャプログラム +GenericName[kk]=Экраннан түсіріп алу бағдарламасы +GenericName[km]=កម្មវិធី​ចាប់យក​អេក្រង់ +GenericName[lt]=Ekrano kopijos programa +GenericName[lv]=Ekrāna Sagrābšanas Programma +GenericName[ms]=Program Cekupan Skrin +GenericName[mt]=Programm biex tieħu "ritratt" tal-iskrin +GenericName[nb]=Skjermdumpprogram +GenericName[nds]=Schirmfotos opnehmen +GenericName[ne]=पर्दा समात्ने कार्यक्रम +GenericName[nl]=Schermafdrukprogramma +GenericName[nn]=Program for skjermbilete +GenericName[nso]=Lenaneo lago Apesa Pontsho +GenericName[pl]=Program do zrzutów ekranu +GenericName[pt]=Programa de Captura do Ecrã +GenericName[pt_BR]=Programa de Captura de Tela +GenericName[ro]=Program de captură de ecran +GenericName[ru]=Создание снимков экрана +GenericName[rw]=Porogaramu Gufata Mugaragaza +GenericName[se]=Šearbmagovvenprográmma +GenericName[sk]=Zachytenie obrazovky +GenericName[sl]=Program za zajem zaslona +GenericName[sr]=Програм за снимање екрана +GenericName[sr@Latn]=Program za snimanje ekrana +GenericName[sv]=Ta en skärmdump +GenericName[ta]=திரை கைப்பற்றும் நிரலி +GenericName[tg]=Эҷоди суратҳои экран +GenericName[th]=โปรแกรมจับภาพหน้าจอ +GenericName[tr]=Ekran Yakalama Programı +GenericName[uk]=Захоплювач екрана +GenericName[uz]=Skrinshot olish dasturi +GenericName[uz@cyrillic]=Скриншот олиш дастури +GenericName[ven]=Mbekanya mushumo ino gavha tshikirini +GenericName[wa]=Programe po fé des waitroûlêyes +GenericName[xh]=Iinkcazelo Ezigcina Ikhusi +GenericName[zh_CN]=屏幕截图程序 +GenericName[zh_HK]=螢幕擷取程式 +GenericName[zh_TW]=畫面擷取程式 +GenericName[zu]=Iprogremu Yokubamba Isikrini +Name=KSnapshot +Name[af]=K-kiekie +Name[cy]=KCipluniau +Name[eo]=Ekranfotilo +Name[fr]=KSnapShot +Name[hi]=के-स्नेपशॉट +Name[lv]=KSnapšots +Name[ne]=केडीई स्न्यापसट +Name[pl]=Zrzuty ekranu +Name[sv]=Ksnapshot +Name[ta]=கேதிரையை நகலெடுத்தல் +Name[th]=จับภาพ - K +Name[ven]=Tshinepe tsha K +Name[wa]=KWaitroûlêye +Name[zh_TW]=KSnapshot 快照 +Name[zu]=KEsincane isithombe +MimeType= +Exec=ksnapshot -caption "%c" %i %m +Icon=ksnapshot +Path= +Type=Application +Terminal=false +DocPath=ksnapshot/index.html +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Multi +Categories=Qt;KDE;Graphics; diff --git a/ksnapshot/ksnapshot.h b/ksnapshot/ksnapshot.h new file mode 100644 index 00000000..486c0a1b --- /dev/null +++ b/ksnapshot/ksnapshot.h @@ -0,0 +1,150 @@ +// -*- c++ -*- + +#ifndef KSNAPSHOT_H +#define KSNAPSHOT_H +#include "ksnapshotiface.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +class RegionGrabber; +class KSnapshotWidget; + +class KSnapshotPreview : public QLabel +{ + Q_OBJECT + + public: + KSnapshotPreview(QWidget *parent, const char *name = 0) + : QLabel(parent, name) + { + setAlignment(AlignHCenter | AlignVCenter); + setCursor(QCursor(Qt::PointingHandCursor)); + } + virtual ~KSnapshotPreview() {} + + void setPixmap(const QPixmap& pm) + { + // if this looks convoluted, that's because it is. drawing a PE_SizeGrip + // does unexpected things when painting directly onto the pixmap + QPixmap pixmap(pm); + QPixmap handle(15, 15); + QBitmap mask(15, 15, true); + + { + QPainter p(&mask); + style().drawPrimitive(QStyle::PE_SizeGrip, &p, QRect(0, 0, 15, 15), palette().active()); + p.end(); + handle.setMask(mask); + } + + { + QPainter p(&handle); + style().drawPrimitive(QStyle::PE_SizeGrip, &p, QRect(0, 0, 15, 15), palette().active()); + p.end(); + } + + QRect rect(pixmap.width() - 16, pixmap.height() - 16, 15, 15); + QPainter p(&pixmap); + p.drawPixmap(rect, handle); + p.end(); + QLabel::setPixmap(pixmap); + } + + signals: + void startDrag(); + + protected: + void mousePressEvent(QMouseEvent * e) + { + mClickPt = e->pos(); + } + + void mouseMoveEvent(QMouseEvent * e) + { + if (mClickPt != QPoint(0, 0) && + (e->pos() - mClickPt).manhattanLength() > KGlobalSettings::dndEventDelay()) + { + mClickPt = QPoint(0, 0); + emit startDrag(); + } + } + + void mouseReleaseEvent(QMouseEvent * /*e*/) + { + mClickPt = QPoint(0, 0); + } + + QPoint mClickPt; +}; + +class KSnapshot : public KDialogBase, virtual public KSnapshotIface +{ + Q_OBJECT + +public: + KSnapshot(QWidget *parent= 0, const char *name= 0, bool grabCurrent=false); + ~KSnapshot(); + + enum CaptureMode { FullScreen=0, WindowUnderCursor=1, Region=2, ChildWindow=3 }; + + bool save( const QString &filename ); + QString url() const { return filename.url(); } + +protected slots: + void slotGrab(); + void slotSave(); + void slotSaveAs(); + void slotCopy(); + void slotPrint(); + void slotMovePointer( int x, int y ); + + void setTime(int newTime); + void setURL(const QString &newURL); + void setGrabMode( int m ); + void exit(); + +protected: + void reject() { close(); } + + virtual void closeEvent( QCloseEvent * e ); + void resizeEvent(QResizeEvent*); + bool eventFilter( QObject*, QEvent* ); + +private slots: + void grabTimerDone(); + void slotDragSnapshot(); + void updateCaption(); + void updatePreview(); + void slotRegionGrabbed( const QPixmap & ); + void slotWindowGrabbed( const QPixmap & ); + +private: + bool save( const KURL& url ); + void performGrab(); + void autoincFilename(); + int grabMode(); + int timeout(); + + QPixmap snapshot; + QTimer grabTimer; + QTimer updateTimer; + QWidget* grabber; + KURL filename; + KSnapshotWidget *mainWidget; + RegionGrabber *rgnGrab; + bool modified; +}; + +#endif // KSNAPSHOT_H + diff --git a/ksnapshot/ksnapshotiface.h b/ksnapshot/ksnapshotiface.h new file mode 100644 index 00000000..6b1f3477 --- /dev/null +++ b/ksnapshot/ksnapshotiface.h @@ -0,0 +1,65 @@ +/** KSnapshot DCOP interface + File: ksnapshotiface.h + Date: January 12, 2001 + Author: Ian Geiser + Comments: + This is an addition to the existing KSnapshot code + that will allow other applications to access internal + public member functions via dcop. +**/ + +#ifndef __KS_IFACE_H +#define __KS_IFACE_H + +#include + +class KSnapshotIface : virtual public DCOPObject +{ + K_DCOP + k_dcop: + /** the current filename (as a URL) that will + be used to save to */ + virtual QString url() const = 0; + + /** Grab an image **/ + virtual void slotGrab() = 0; + + /** Prints the image. */ + virtual void slotPrint() = 0; + + /** Saves the image **/ + virtual void slotSave() = 0; + + /** Save the image to the specified filename */ + virtual bool save(const QString &filename) = 0; + + /** Saves image as **/ + virtual void slotSaveAs() = 0; + + /** Copy the snapshot to the clipboard. **/ + virtual void slotCopy() = 0; + + /** Set the timeout value */ + virtual void setTime(int newTime) = 0; + + /** Get the current timeout value */ + virtual int timeout() = 0; + + /** Set the URL to the file to save **/ + virtual void setURL(const QString &newURL) = 0; + + /** Set the ability to grab the entire screen, just the window + containing the mouse, or a region */ + virtual void setGrabMode(int grab) = 0; + + /** Return the current grab mode */ + virtual int grabMode() = 0; + + /** Move the mouse pointer. */ + virtual void slotMovePointer( int x, int y ) = 0; + + /** Exit KSnapshot **/ + virtual void exit() = 0; +}; + +#endif diff --git a/ksnapshot/ksnapshotwidget.ui b/ksnapshot/ksnapshotwidget.ui new file mode 100644 index 00000000..88efce1a --- /dev/null +++ b/ksnapshot/ksnapshotwidget.ui @@ -0,0 +1,361 @@ + +KSnapshotWidget + + + KSnapshotWidget + + + + 0 + 0 + 356 + 226 + + + + + unnamed + + + 0 + + + + lblImage + + + + 200 + 130 + + + + This is a preview of the current snapshot. + +The image can be dragged to another application or document to copy the full screenshot there. Try it with the Konqueror file manager. + +You can also copy the image to the clipboard by pressing Ctrl+C. + + + + + line1 + + + HLine + + + Sunken + + + Horizontal + + + + + spinDelay + + + sec + + + No delay + + + Snapshot delay in seconds + + + <qt> +This is the number of seconds to wait after clicking the <i>New Snapshot</i> button before taking the snapshot. +<p> +This is very useful for getting windows, menus and other items on the screen set up just the way you want. +<p> +If <i>no delay</i> is set, the program will wait for a mouse click before taking a snapshot. +</p> +</qt> + + + + + lblDelay + + + Snapshot &delay: + + + spinDelay + + + + + textLabel1 + + + Cap&ture mode: + + + comboMode + + + + + Spacer1 + + + Horizontal + + + Expanding + + + + 156 + 16 + + + + + + cbIncludeDecorations + + + Include &window decorations + + + true + + + When enabled, snapshot of a window will also include the window decorations + + + + + + Full Screen + + + + + Window Under Cursor + + + + + Region + + + + + Section of Window + + + + comboMode + + + <qt>Using this menu, you can select from the four following snapshot modes: +<p> +<b>Full Screen</b> - captures the entire desktop.<br> +<b>Window Under Cursor</b> - captures only the window (or menu) that is under the mouse cursor when the snapshot is taken.<br> +<b>Region</b> - captures only the region of the desktop that you specify. When taking a new snapshot in this mode you will be able to select any area of the screen by clicking and dragging the mouse.</p> +<b>Section of Window</b> - captures only a section of the window. When taking a new snapshot in this mode you will be able to select any child window by moving the mouse over it.</p></qt> + + + + + layout1 + + + + unnamed + + + + btnNew + + + &New Snapshot + + + "ksnapshot", 32 + + + Click this button to take a new snapshot. + + + + + Spacer6 + + + Vertical + + + Expanding + + + + 16 + 16 + + + + + + btnSave + + + &Save As... + + + "filesave" + + + Click this button to save the current snapshot. To quickly save the snapshot without showing the file dialog, press Ctrl+Shift+S. The filename is automatically incremented after each save. + + + + + btnCopy + + + &Copy to Clipboard + + + "editcopy" + + + Click this button to copy the current snapshot to the clipboard. + + + + + btnPrint + + + &Print... + + + "fileprint" + + + Click this button to print the current screenshot. + + + + + + + + + KSnapshotPreview +
ksnapshot.h
+ + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image0 + startDrag() +
+
+ + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000025b49444154789cb595bf4b1b6118c73f962bbc070e115af006210107f52fa8b18b071dbb445ca48bb8199c544a8b53b153092e3ad9d8ad53c962390a2da6507227441207e10296be190a774330070af74202760889899e3f22f50bc7ddfb72efe7799eef7bcf7b0305bbc06d9a4a4e9d5f9e2bd885819bd63cba0ff4a6f9eec800e7fffbd2da01fed81ff1a48d52014213b715d22b3d060d853cdce1d587d65407ec491b79b8d31fb02d0d2ea7d2012b15007422f6ab2f6f04a0ae82bbcb3f3939416882e02ca07454c2dab5086a01c9e749e2237174a1230605524ab29fb2e47fe431c652c8a3cf57c1ddca6e67f16b3ef62f1be7c0616e768ecdad4d8686860008c31067df415625beef475610095e7dbddaf3865db4d9dade223d9fc6adb8acbd5ba37c502608028488dee84830407c344e7a298daee90c3f1d263196400c0adc631773da64617e81dcd71caaaeb0be5977032f2e2d32f37206f385090de0319dbb528ae4641273da647c7c1c599591e06b3b2f24243c0d5b830678358ff03444fe9658df2dc2d390443c81eff5e1b1b56b613c3198189d20168b213481e77b88b868d95171c9ede6281f96b18bf6ddc1fe5f1fafe6513fabb7364783bdfc1efaa08e5b7129154b4c3e9b24359ba21ed4717e3a77b3423515eeb18bac4a6455a29a0a73da445624a56209236eb43eb326a497d29119477bac4179bf8c936f65a2ce14c6b0c1f2ea32ebefd7498c24b08b362b6f57709cabd9f65aa1c72e464d088280cc4686cc462672615b6d1b841ebb06dc50085a3d6f8ca56e845d96d06304f56a34f8e264533d3ddf979a5dcf0f75d0dffa6bbaaf1e0cfc0ff3922877348d5d5a0000000049454e44ae426082 + + + + + comboMode + activated(int) + KSnapshotWidget + slotModeChanged(int) + + + btnNew + clicked() + KSnapshotWidget + slotNewClicked() + + + btnPrint + clicked() + KSnapshotWidget + slotPrintClicked() + + + btnSave + clicked() + KSnapshotWidget + slotSaveClicked() + + + btnCopy + clicked() + KSnapshotWidget + slotCopyClicked() + + + lblImage + startDrag() + KSnapshotWidget + slotStartDrag() + + + + btnNew + btnSave + btnCopy + btnPrint + comboMode + spinDelay + cbIncludeDecorations + + + kdialog.h + kiconloader.h + kglobalsettings.h + ksnapshotwidget.ui.h + + + newClicked() + saveClicked() + copyClicked() + printClicked() + startImageDrag() + + + slotModeChanged( int mode ) + slotNewClicked() + slotSaveClicked() + slotCopyClicked() + slotPrintClicked() + slotStartDrag() + previewWidth() + previewHeight() + + + setPreview( const QPixmap & pm ) + setDelay( int i ) + setIncludeDecorations( bool b ) + setMode( int mode ) + delay() + includeDecorations() + mode() + preview() + +SmallIconSet + + + + kpushbutton.h + kpushbutton.h + kpushbutton.h + +
diff --git a/ksnapshot/ksnapshotwidget.ui.h b/ksnapshot/ksnapshotwidget.ui.h new file mode 100644 index 00000000..d7e757f5 --- /dev/null +++ b/ksnapshot/ksnapshotwidget.ui.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + + +void KSnapshotWidget::slotModeChanged( int mode ) +{ + switch ( mode ) + { + case 0: + cbIncludeDecorations->setEnabled(false); + break; + case 1: + cbIncludeDecorations->setEnabled(true); + break; + case 2: + cbIncludeDecorations->setEnabled(false); + break; + case 3: + cbIncludeDecorations->setEnabled(false); + break; + default: + break; + } + + spinDelay->setEnabled(mode != 2); +} + + +void KSnapshotWidget::setPreview( const QPixmap &pm ) +{ + QImage img = pm.convertToImage(); + double r1 = ( ( double ) pm.height() ) / pm.width(); + if ( r1 * previewWidth() < previewHeight() ) + img = img.smoothScale( previewWidth(), + int( previewWidth() * r1 ), + QImage::ScaleMin ); + else + img = img.smoothScale( ( int ) ( ( ( double )previewHeight() ) / r1 ), + previewHeight(), QImage::ScaleMin ); + + QToolTip::remove( lblImage ); + QToolTip::add( lblImage, + QString( "Preview of the snapshot image (%1 x %2)" ) + .arg( pm.width() ).arg( pm.height() ) ); + + lblImage->setPixmap( img ); + lblImage->adjustSize(); +} + + +void KSnapshotWidget::setDelay( int i ) +{ + spinDelay->setValue(i); +} + + +void KSnapshotWidget::setIncludeDecorations( bool b ) +{ + cbIncludeDecorations->setChecked(b); +} + + +void KSnapshotWidget::setMode( int mode ) +{ + comboMode->setCurrentItem(mode); + slotModeChanged(mode); +} + + +int KSnapshotWidget::delay() +{ + return spinDelay->value(); +} + + +bool KSnapshotWidget::includeDecorations() +{ + return cbIncludeDecorations->isChecked(); +} + + +int KSnapshotWidget::mode() +{ + return comboMode->currentItem(); +} + + +void KSnapshotWidget::slotNewClicked() +{ + emit newClicked(); +} + + +void KSnapshotWidget::slotSaveClicked() +{ + emit saveClicked(); +} + + +void KSnapshotWidget::slotPrintClicked() +{ + emit printClicked(); +} + + +void KSnapshotWidget::slotStartDrag() +{ + emit startImageDrag(); +} + + +QPixmap KSnapshotWidget::preview() +{ + return *lblImage->pixmap(); +} + + +int KSnapshotWidget::previewWidth() +{ + return lblImage->width(); +} + + +int KSnapshotWidget::previewHeight() +{ + return lblImage->height(); +} + +void KSnapshotWidget::slotCopyClicked() +{ + emit copyClicked(); +} diff --git a/ksnapshot/main.cpp b/ksnapshot/main.cpp new file mode 100644 index 00000000..f3e397e2 --- /dev/null +++ b/ksnapshot/main.cpp @@ -0,0 +1,77 @@ +/* + (c) Richard J. Moore 1997-2002 + (c) Matthias Ettrich 2000 + (c) Aaron J. Seigo 2002-2004 + (c) Nadeem Hasan 2003 + (c) Waldo Bastian 1999-2002 + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include +#include + +#include "ksnapshot.h" + +static const char description[] = + I18N_NOOP("KDE Screenshot Utility"); + +static KCmdLineOptions options[] = +{ + { "c", 0, 0 }, + { "current", I18N_NOOP("Captures the window under the mouse on startup (instead of the desktop)"), 0 }, + { 0, 0, 0 } +}; + +int main(int argc, char **argv) +{ + KAboutData aboutData( "ksnapshot", I18N_NOOP("KSnapshot"), + KSNAPVERSION, description, KAboutData::License_GPL, + "(c) 1997-2004, Richard J. Moore,\n(c) 2000, Matthias Ettrich,\n(c) 2002-2003 Aaron J. Seigo"); + aboutData.addAuthor("Richard J. Moore",0, "rich@kde.org"); + aboutData.addAuthor("Matthias Ettrich",0, "ettrich@kde.org"); + aboutData.addAuthor("Aaron J. Seigo", 0, "aseigo@kde.org"); + aboutData.addCredit( "Nadeem Hasan", I18N_NOOP("Region Grabbing\nReworked GUI"), + "nhasan@kde.org" ); + + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); // Add our own options. + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + KApplication app; + + KImageIO::registerFormats(); + + // Create top level window + KSnapshot *toplevel; + + if ( args->isSet( "current" ) ) + toplevel = new KSnapshot( 0, 0, true ); + else + toplevel = new KSnapshot(); + + args->clear(); + app.dcopClient()->setDefaultObject( toplevel->objId() ); + toplevel->setCaption( app.makeStdCaption("") ); + app.setMainWidget(toplevel); + toplevel->show(); + return app.exec(); +} + diff --git a/ksnapshot/regiongrabber.cpp b/ksnapshot/regiongrabber.cpp new file mode 100644 index 00000000..c1d8ed98 --- /dev/null +++ b/ksnapshot/regiongrabber.cpp @@ -0,0 +1,177 @@ +/* + Copyright (C) 2003 Nadeem Hasan + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "regiongrabber.h" + +#include +#include +#include +#include +#include +#include + +#include + +SizeTip::SizeTip( QWidget *parent, const char *name ) + : QLabel( parent, name, WStyle_Customize | WX11BypassWM | + WStyle_StaysOnTop | WStyle_NoBorder | WStyle_Tool ) +{ + setMargin( 2 ); + setIndent( 0 ); + setFrameStyle( QFrame::Plain | QFrame::Box ); + + setPalette( QToolTip::palette() ); +} + +void SizeTip::setTip( const QRect &rect ) +{ + QString tip = QString( "%1x%2" ).arg( rect.width() ) + .arg( rect.height() ); + + setText( tip ); + adjustSize(); + + positionTip( rect ); +} + +void SizeTip::positionTip( const QRect &rect ) +{ + QRect tipRect = geometry(); + tipRect.moveTopLeft( QPoint( 0, 0 ) ); + + if ( rect.intersects( tipRect ) ) + { + QRect deskR = KGlobalSettings::desktopGeometry( QPoint( 0, 0 ) ); + + tipRect.moveCenter( QPoint( deskR.width()/2, deskR.height()/2 ) ); + if ( !rect.contains( tipRect, true ) && rect.intersects( tipRect ) ) + tipRect.moveBottomRight( geometry().bottomRight() ); + } + + move( tipRect.topLeft() ); +} + +RegionGrabber::RegionGrabber() + : QWidget( 0, 0, WStyle_Customize | WX11BypassWM ), + mouseDown( false ), sizeTip( 0L ) +{ + sizeTip = new SizeTip( ( QWidget * )0L ); + + tipTimer = new QTimer( this ); + connect( tipTimer, SIGNAL( timeout() ), SLOT( updateSizeTip() ) ); + + QTimer::singleShot( 200, this, SLOT( initGrabber() ) ); +} + +RegionGrabber::~RegionGrabber() +{ + delete sizeTip; +} + +void RegionGrabber::initGrabber() +{ + pixmap = QPixmap::grabWindow( qt_xrootwin() ); + setPaletteBackgroundPixmap( pixmap ); + + QDesktopWidget desktopWidget; + QRect desktopSize; + if ( desktopWidget.isVirtualDesktop() ) + desktopSize = desktopWidget.geometry(); + else + desktopSize = desktopWidget.screenGeometry( qt_xrootwin() ); + + setGeometry( desktopSize ); + showFullScreen(); + + QApplication::setOverrideCursor( crossCursor ); +} + +void RegionGrabber::mousePressEvent( QMouseEvent *e ) +{ + if ( e->button() == LeftButton ) + { + mouseDown = true; + grabRect = QRect( e->pos(), e->pos() ); + } +} + +void RegionGrabber::mouseMoveEvent( QMouseEvent *e ) +{ + if ( mouseDown ) + { + sizeTip->hide(); + tipTimer->start( 250, true ); + + drawRubber(); + grabRect.setBottomRight( e->pos() ); + drawRubber(); + } +} + +void RegionGrabber::mouseReleaseEvent( QMouseEvent *e ) +{ + mouseDown = false; + drawRubber(); + sizeTip->hide(); + + grabRect.setBottomRight( e->pos() ); + grabRect = grabRect.normalize(); + + QPixmap region = QPixmap::grabWindow( winId(), grabRect.x(), grabRect.y(), + grabRect.width(), grabRect.height() ); + + QApplication::restoreOverrideCursor(); + + emit regionGrabbed( region ); +} + +void RegionGrabber::keyPressEvent( QKeyEvent *e ) +{ + if ( e->key() == Key_Escape ) + { + QApplication::restoreOverrideCursor(); + emit regionGrabbed( QPixmap() ); + } + else + e->ignore(); +} + +void RegionGrabber::updateSizeTip() +{ + QRect rect = grabRect.normalize(); + + sizeTip->setTip( rect ); + sizeTip->show(); +} + +void RegionGrabber::drawRubber() +{ + QPainter p; + p.begin( this ); + p.setRasterOp( NotROP ); + p.setPen( QPen( color0, 1 ) ); + p.setBrush( NoBrush ); + + style().drawPrimitive( QStyle::PE_FocusRect, &p, grabRect, colorGroup(), + QStyle::Style_Default, QStyleOption( colorGroup().base() ) ); + + p.end(); +} + +#include "regiongrabber.moc" diff --git a/ksnapshot/regiongrabber.h b/ksnapshot/regiongrabber.h new file mode 100644 index 00000000..ee9a8238 --- /dev/null +++ b/ksnapshot/regiongrabber.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2003 Nadeem Hasan + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef REGIONGRABBER_H +#define REGIONGRABBER_H + +#include +#include + +class QTimer; + +class SizeTip : public QLabel +{ + public: + SizeTip( QWidget *parent, const char *name=0 ); + ~SizeTip() {} + + void setTip( const QRect &rect ); + void positionTip( const QRect &rect ); +}; + +class RegionGrabber : public QWidget +{ + Q_OBJECT + + public: + RegionGrabber(); + ~RegionGrabber(); + + protected slots: + void initGrabber(); + void updateSizeTip(); + + signals: + void regionGrabbed( const QPixmap & ); + + protected: + void mousePressEvent( QMouseEvent *e ); + void mouseReleaseEvent( QMouseEvent *e ); + void mouseMoveEvent( QMouseEvent *e ); + void keyPressEvent( QKeyEvent *e ); + + void drawRubber(); + + bool mouseDown; + QRect grabRect; + QPixmap pixmap; + + SizeTip *sizeTip; + QTimer *tipTimer; +}; + +#endif // REGIONGRABBER_H + diff --git a/ksnapshot/uninstall.desktop b/ksnapshot/uninstall.desktop new file mode 100644 index 00000000..e1e3e173 --- /dev/null +++ b/ksnapshot/uninstall.desktop @@ -0,0 +1,2 @@ +[Desktop Entry] +Hidden=true diff --git a/ksnapshot/windowgrabber.cpp b/ksnapshot/windowgrabber.cpp new file mode 100644 index 00000000..036764b1 --- /dev/null +++ b/ksnapshot/windowgrabber.cpp @@ -0,0 +1,353 @@ +/* + Copyright (C) 2004 Bernd Brandstetter + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "windowgrabber.h" +#include +#include +#include +#include + +#include + +#ifdef HAVE_X11_EXTENSIONS_SHAPE_H +#include +#endif + + +static +const int minSize = 8; + +static +bool operator< ( const QRect& r1, const QRect& r2 ) +{ + return r1.width() * r1.height() < r2.width() * r2.height(); +} + +// Recursively iterates over the window w and its children, thereby building +// a tree of window descriptors. Windows in non-viewable state or with height +// or width smaller than minSize will be ignored. +static +void getWindowsRecursive( std::vector& windows, Window w, + int rx = 0, int ry = 0, int depth = 0 ) +{ + XWindowAttributes atts; + XGetWindowAttributes( qt_xdisplay(), w, &atts ); + if ( atts.map_state == IsViewable && + atts.width >= minSize && atts.height >= minSize ) { + int x = 0, y = 0; + if ( depth ) { + x = atts.x + rx; + y = atts.y + ry; + } + + QRect r( x, y, atts.width, atts.height ); + if ( std::find( windows.begin(), windows.end(), r ) == windows.end() ) { + windows.push_back( r ); + } + + Window root, parent; + Window* children; + unsigned int nchildren; + + if( XQueryTree( qt_xdisplay(), w, &root, &parent, &children, &nchildren ) != 0 ) { + for( unsigned int i = 0; i < nchildren; ++i ) { + getWindowsRecursive( windows, children[ i ], x, y, depth + 1 ); + } + if( children != NULL ) + XFree( children ); + } + } + if ( depth == 0 ) + std::sort( windows.begin(), windows.end() ); +} + +static +Window findRealWindow( Window w, int depth = 0 ) +{ + if( depth > 5 ) + return None; + static Atom wm_state = XInternAtom( qt_xdisplay(), "WM_STATE", False ); + Atom type; + int format; + unsigned long nitems, after; + unsigned char* prop; + if( XGetWindowProperty( qt_xdisplay(), w, wm_state, 0, 0, False, AnyPropertyType, + &type, &format, &nitems, &after, &prop ) == Success ) { + if( prop != NULL ) + XFree( prop ); + if( type != None ) + return w; + } + Window root, parent; + Window* children; + unsigned int nchildren; + Window ret = None; + if( XQueryTree( qt_xdisplay(), w, &root, &parent, &children, &nchildren ) != 0 ) { + for( unsigned int i = 0; + i < nchildren && ret == None; + ++i ) + ret = findRealWindow( children[ i ], depth + 1 ); + if( children != NULL ) + XFree( children ); + } + return ret; +} + +static +Window windowUnderCursor( bool includeDecorations = true ) +{ + Window root; + Window child; + uint mask; + int rootX, rootY, winX, winY; + XGrabServer( qt_xdisplay() ); + XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child, + &rootX, &rootY, &winX, &winY, &mask ); + if( child == None ) + child = qt_xrootwin(); + if( !includeDecorations ) { + Window real_child = findRealWindow( child ); + if( real_child != None ) // test just in case + child = real_child; + } + return child; +} + +static +QPixmap grabWindow( Window child, int x, int y, uint w, uint h, uint border ) +{ + QPixmap pm( QPixmap::grabWindow( qt_xrootwin(), x, y, w, h ) ); + +#ifdef HAVE_X11_EXTENSIONS_SHAPE_H + int tmp1, tmp2; + //Check whether the extension is available + if ( XShapeQueryExtension( qt_xdisplay(), &tmp1, &tmp2 ) ) { + QBitmap mask( w, h ); + //As the first step, get the mask from XShape. + int count, order; + XRectangle* rects = XShapeGetRectangles( qt_xdisplay(), child, + ShapeBounding, &count, &order ); + //The ShapeBounding region is the outermost shape of the window; + //ShapeBounding - ShapeClipping is defined to be the border. + //Since the border area is part of the window, we use bounding + // to limit our work region + if (rects) { + //Create a QRegion from the rectangles describing the bounding mask. + QRegion contents; + for ( int pos = 0; pos < count; pos++ ) + contents += QRegion( rects[pos].x, rects[pos].y, + rects[pos].width, rects[pos].height ); + XFree( rects ); + + //Create the bounding box. + QRegion bbox( 0, 0, w, h ); + + if( border > 0 ) { + contents.translate( border, border ); + contents += QRegion( 0, 0, border, h ); + contents += QRegion( 0, 0, w, border ); + contents += QRegion( 0, h - border, w, border ); + contents += QRegion( w - border, 0, border, h ); + } + + //Get the masked away area. + QRegion maskedAway = bbox - contents; + QMemArray maskedAwayRects = maskedAway.rects(); + + //Construct a bitmap mask from the rectangles + QPainter p(&mask); + p.fillRect(0, 0, w, h, Qt::color1); + for (uint pos = 0; pos < maskedAwayRects.count(); pos++) + p.fillRect(maskedAwayRects[pos], Qt::color0); + p.end(); + + pm.setMask(mask); + } + } +#endif + + return pm; +} + +WindowGrabber::WindowGrabber() +: QDialog( 0, 0, true, Qt::WStyle_Customize | Qt::WStyle_NoBorder | + Qt::WStyle_StaysOnTop | Qt::WX11BypassWM ), + current( -1 ), yPos( -1 ) +{ + Window root; + int y, x; + uint w, h, border, depth; + XGrabServer( qt_xdisplay() ); + Window child = windowUnderCursor(); + XGetGeometry( qt_xdisplay(), child, &root, &x, &y, &w, &h, &border, &depth ); + QPixmap pm( grabWindow( child, x, y, w, h, border ) ); + getWindowsRecursive( windows, child ); + XUngrabServer( qt_xdisplay() ); + + setPaletteBackgroundPixmap( pm ); + setFixedSize( pm.size() ); + setMouseTracking( true ); + setGeometry( x, y, w, h ); +} + +WindowGrabber::~WindowGrabber() +{ +} + +QPixmap WindowGrabber::grabCurrent( bool includeDecorations ) +{ + Window root; + int y, x; + uint w, h, border, depth; + XGrabServer( qt_xdisplay() ); + Window child = windowUnderCursor( includeDecorations ); + XGetGeometry( qt_xdisplay(), child, &root, &x, &y, &w, &h, &border, &depth ); + Window parent; + Window* children; + unsigned int nchildren; + if( XQueryTree( qt_xdisplay(), child, &root, &parent, + &children, &nchildren ) != 0 ) { + if( children != NULL ) + XFree( children ); + int newx, newy; + Window dummy; + if( XTranslateCoordinates( qt_xdisplay(), parent, qt_xrootwin(), + x, y, &newx, &newy, &dummy )) { + x = newx; + y = newy; + } + } + QPixmap pm( grabWindow( child, x, y, w, h, border ) ); + XUngrabServer( qt_xdisplay() ); + return pm; +} + +void WindowGrabber::mousePressEvent( QMouseEvent *e ) +{ + if ( e->button() == QMouseEvent::RightButton ) + yPos = e->globalY(); + else { + QPixmap pm; + if ( current ) { + QRect r( windows[ current ] ); + int w = r.width(); + int h = r.height(); + pm.resize( w, h ); + copyBlt( &pm, 0, 0, paletteBackgroundPixmap(), r.x(), r.y(), w, h ); + } + emit windowGrabbed( pm ); + accept(); + } +} + +void WindowGrabber::mouseReleaseEvent( QMouseEvent *e ) +{ + if ( e->button() == QMouseEvent::RightButton ) + yPos = -1; +} + +static +const int minDistance = 10; + +void WindowGrabber::mouseMoveEvent( QMouseEvent *e ) +{ + if ( yPos == -1 ) { + int w = windowIndex( e->pos() ); + if ( w != -1 && w != current ) { + current = w; + drawBorder(); + } + } + else { + int y = e->globalY(); + if ( y > yPos + minDistance ) { + decreaseScope( e->pos() ); + yPos = y; + } + else if ( y < yPos - minDistance ) { + increaseScope( e->pos() ); + yPos = y; + } + } +} + +void WindowGrabber::wheelEvent( QWheelEvent *e ) +{ + if ( e->delta() > 0 ) + increaseScope( e->pos() ); + else if ( e->delta() < 0 ) + decreaseScope( e->pos() ); + else + e->ignore(); +} + +// Increases the scope to the next-bigger window containing the mouse pointer. +// This method is activated by either rotating the mouse wheel forwards or by +// dragging the mouse forwards while keeping the right mouse button pressed. +void WindowGrabber::increaseScope( const QPoint &pos ) +{ + for ( uint i = current + 1; i < windows.size(); i++ ) { + if ( windows[ i ].contains( pos ) ) { + current = i; + break; + } + } + drawBorder(); +} + +// Decreases the scope to the next-smaller window containing the mosue pointer. +// This method is activated by either rotating the mouse wheel backwards or by +// dragging the mouse backwards while keeping the right mouse button pressed. +void WindowGrabber::decreaseScope( const QPoint &pos ) +{ + for ( int i = current - 1; i >= 0; i-- ) { + if ( windows[ i ].contains( pos ) ) { + current = i; + break; + } + } + drawBorder(); +} + +// Searches and returns the index of the first (=smallest) window +// containing the mouse pointer. +int WindowGrabber::windowIndex( const QPoint &pos ) const +{ + for ( uint i = 0; i < windows.size(); i++ ) { + if ( windows[ i ].contains( pos ) ) + return i; + } + return -1; +} + +// Draws a border around the (child) window currently containing the pointer +void WindowGrabber::drawBorder() +{ + repaint(); + + if ( current >= 0 ) { + QPainter p; + p.begin( this ); + p.setPen( QPen( Qt::red, 3 ) ); + p.drawRect( windows[ current ] ); + p.end(); + } +} + +#include "windowgrabber.moc" diff --git a/ksnapshot/windowgrabber.h b/ksnapshot/windowgrabber.h new file mode 100644 index 00000000..43598576 --- /dev/null +++ b/ksnapshot/windowgrabber.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2004 Bernd Brandstetter + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef WINDOWGRABBER_H +#define WINDOWGRABBER_H + +#include +#include +#include +#include +#include + +class WindowGrabber : public QDialog +{ + Q_OBJECT + +public: + WindowGrabber(); + ~WindowGrabber(); + + static QPixmap grabCurrent( bool includeDecorations = true ); + +signals: + void windowGrabbed( const QPixmap & ); + +protected: + void mousePressEvent( QMouseEvent * ); + void mouseReleaseEvent( QMouseEvent * ); + void mouseMoveEvent( QMouseEvent * ); + void wheelEvent( QWheelEvent * ); + +private: + void drawBorder(); + void increaseScope( const QPoint & ); + void decreaseScope( const QPoint & ); + int windowIndex( const QPoint & ) const; + std::vector windows; + int current; + int yPos; +}; + + +#endif // WINDOWGRABBER_H diff --git a/ksvg/AUTHORS b/ksvg/AUTHORS new file mode 100644 index 00000000..ead56e6b --- /dev/null +++ b/ksvg/AUTHORS @@ -0,0 +1,2 @@ +Nikolas Zimmermann +Rob Buis diff --git a/ksvg/FAQ b/ksvg/FAQ new file mode 100644 index 00000000..68897507 --- /dev/null +++ b/ksvg/FAQ @@ -0,0 +1,17 @@ +KSVG FAQ +------------------------- + +Q: Why do my fonts look wrong when trying the offical + W3C Testcases? (they don't fit in the boxes) + +A: Those testcases all use a font called 'Helvetica', + your system may use Verdana instead, which is also + wrong. I suggest you replace the following line + in your XftConfig file: + + match any family == "Helvetica" edit family += "Verdana"; + + with + + match any family == "Helvetica" edit family += "Arial"; + diff --git a/ksvg/Makefile.am b/ksvg/Makefile.am new file mode 100644 index 00000000..722e90d7 --- /dev/null +++ b/ksvg/Makefile.am @@ -0,0 +1,115 @@ +SUBDIRS = dom impl core ecma . plugin test + +lib_LTLIBRARIES = libksvg.la +libksvg_la_SOURCES = dummy.cc +libksvg_la_METASOURCES = AUTO +libksvg_la_LDFLAGS = -version-info 0:1:0 -no-undefined $(all_libraries) +libksvg_la_LIBADD = dom/libksvgdom.la impl/libksvgdomimpl.la core/libksvgcore.la ecma/libksvgecma.la \ + $(LCMS_LIBS) impl/libs/xrgbrender/libksvgxrgbrender.la impl/libs/libtext2path/src/libtext2path.la \ + impl/libs/art_support/libksvgart.la -lkjs $(LIB_KHTML) $(LIBART_LIBS) $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) + +INCLUDES = -I$(top_srcdir)/ksvg/dom -I$(top_srcdir)/ksvg/impl $(all_includes) + +dummy.cc: + echo "" > dummy.cc + +# Make it easy for developers :) +hashtables: + cd $(srcdir); \ + rm -f data/*lut* ; \ + ../../kdelibs/kjs/create_hash_table impl/SVGElementImpl.cc > data/SVGElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGSVGElementImpl.cc > data/SVGSVGElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGRectElementImpl.cc > data/SVGRectElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGLineElementImpl.cc > data/SVGLineElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGCircleElementImpl.cc > data/SVGCircleElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGImageElementImpl.cc > data/SVGImageElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGEllipseElementImpl.cc > data/SVGEllipseElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedPointsImpl.cc > data/SVGAnimatedPointsImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGPointImpl.cc > data/SVGPointImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGRectImpl.cc > data/SVGRectImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGNumberImpl.cc > data/SVGNumberImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedAngleImpl.cc > data/SVGAnimatedAngleImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedRectImpl.cc > data/SVGAnimatedRectImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedNumberImpl.cc > data/SVGAnimatedNumberImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedNumberListImpl.cc > data/SVGAnimatedNumberListImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedIntegerImpl.cc > data/SVGAnimatedIntegerImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedBooleanImpl.cc > data/SVGAnimatedBooleanImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedEnumerationImpl.cc > data/SVGAnimatedEnumerationImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedStringImpl.cc > data/SVGAnimatedStringImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedLengthImpl.cc > data/SVGAnimatedLengthImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedLengthListImpl.cc > data/SVGAnimatedLengthListImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedPreserveAspectRatioImpl.cc > data/SVGAnimatedPreserveAspectRatioImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGPreserveAspectRatioImpl.cc > data/SVGPreserveAspectRatioImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGLengthImpl.cc > data/SVGLengthImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGMatrixImpl.cc > data/SVGMatrixImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGAngleImpl.cc > data/SVGAngleImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGLocatableImpl.cc > data/SVGLocatableImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGTestsImpl.cc > data/SVGTestsImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGLangSpaceImpl.cc > data/SVGLangSpaceImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGExternalResourcesRequiredImpl.cc > data/SVGExternalResourcesRequiredImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGURIReferenceImpl.cc > data/SVGURIReferenceImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGPaintImpl.cc > data/SVGPaintImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGColorImpl.cc > data/SVGColorImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGICCColorImpl.cc > data/SVGICCColorImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGTextPositioningElementImpl.cc > data/SVGTextPositioningElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGTextContentElementImpl.cc > data/SVGTextContentElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGTransformImpl.cc > data/SVGTransformImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGTransformableImpl.cc > data/SVGTransformableImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGPointListImpl.cc > data/SVGPointListImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGNumberListImpl.cc > data/SVGNumberListImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGLengthListImpl.cc > data/SVGLengthListImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGStringListImpl.cc > data/SVGStringListImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedPathDataImpl.cc > data/SVGAnimatedPathDataImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGPathSegImpl.cc > data/SVGPathSegImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGPathSegArcImpl.cc > data/SVGPathSegArcImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGPathSegMovetoImpl.cc > data/SVGPathSegMovetoImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGPathSegLinetoImpl.cc > data/SVGPathSegLinetoImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGPathSegLinetoHorizontalImpl.cc > data/SVGPathSegLinetoHorizontalImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGPathSegLinetoVerticalImpl.cc > data/SVGPathSegLinetoVerticalImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGPathSegCurvetoCubicImpl.cc > data/SVGPathSegCurvetoCubicImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGPathSegCurvetoCubicSmoothImpl.cc > data/SVGPathSegCurvetoCubicSmoothImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGPathSegCurvetoQuadraticImpl.cc > data/SVGPathSegCurvetoQuadraticImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGPathSegCurvetoQuadraticSmoothImpl.cc > data/SVGPathSegCurvetoQuadraticSmoothImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGPathElementImpl.cc > data/SVGPathElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGPathSegListImpl.cc > data/SVGPathSegListImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGTransformListImpl.cc > data/SVGTransformListImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedTransformListImpl.cc > data/SVGAnimatedTransformListImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGAElementImpl.cc > data/SVGAElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGUseElementImpl.cc > data/SVGUseElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGDocumentImpl.cc > data/SVGDocumentImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGForeignObjectElementImpl.cc > data/SVGForeignObjectElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGScriptElementImpl.cc > data/SVGScriptElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGStyleElementImpl.cc > data/SVGStyleElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGZoomAndPanImpl.cc > data/SVGZoomAndPanImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGFitToViewBoxImpl.cc > data/SVGFitToViewBoxImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGStylableImpl.cc > data/SVGStylableImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGEventImpl.cc > data/SVGEventImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGEcma.cc > data/SVGEcma.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGMarkerElementImpl.cc > data/SVGMarkerElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGViewElementImpl.cc > data/SVGViewElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGTextContentElementImpl.cc > data/SVGTextContentElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGClipPathElementImpl.cc > data/SVGClipPathElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGColorProfileElementImpl.cc > data/SVGColorProfileElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGPatternElementImpl.cc > data/SVGPatternElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGGradientElementImpl.cc > data/SVGGradientElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGLinearGradientElementImpl.cc > data/SVGLinearGradientElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGRadialGradientElementImpl.cc > data/SVGRadialGradientElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGStopElementImpl.cc > data/SVGStopElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGAnimationElementImpl.cc > data/SVGAnimationElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGCursorElementImpl.cc > data/SVGCursorElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGSymbolElementImpl.cc > data/SVGSymbolElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGMaskElementImpl.cc > data/SVGMaskElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGGlyphElementImpl.cc > data/SVGGlyphElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGMissingGlyphElementImpl.cc > data/SVGMissingGlyphElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGGlyphRefElementImpl.cc > data/SVGGlyphRefElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGTextPathElementImpl.cc > data/SVGTextPathElementImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table impl/SVGZoomEventImpl.cc > data/SVGZoomEventImpl.lut.h; \ + ../../kdelibs/kjs/create_hash_table ecma/ksvg_window.cpp > data/ksvg_window.lut.h; + +generatedata: + cd $(srcdir); \ + rm impl/generateddata.cpp -f; \ + cd impl && ../scripts/generate.pl + +redo: + make hashtables && make generatedata diff --git a/ksvg/NEWS b/ksvg/NEWS new file mode 100644 index 00000000..19fead3e --- /dev/null +++ b/ksvg/NEWS @@ -0,0 +1,8 @@ +Mon Sep 8 ??:??:?? CEST 2003 + o Moved to kdegraphics + +Sun Jul 15 13:26:39 CEST 2001 + o First code + +Thu Jun 14 17:44:21 CEST 2001 + o KSVG Idea diff --git a/ksvg/README b/ksvg/README new file mode 100644 index 00000000..a2ad11bc --- /dev/null +++ b/ksvg/README @@ -0,0 +1,9 @@ +KSVG 0.1 +----------------------------------- + +KSVG is a KDE implementation of the +Scalable Vector Graphics Specifications. + +Have a lot of fun! + +The KSVG Team diff --git a/ksvg/RELEASE-TODO b/ksvg/RELEASE-TODO new file mode 100644 index 00000000..d520aaef --- /dev/null +++ b/ksvg/RELEASE-TODO @@ -0,0 +1,10 @@ +KSVG 0.1 - Release TODO List +-------------------------------------- + +Task +We should be done for 0.1 with the feature +set as promised, years ago :) + +Make it nice: +- idea: offer a tool to select a rectangle to zoom into (like asv has) +- idea: offer a preview widget like in karbon/kghostview to easily navigate/pan around a drawing diff --git a/ksvg/TODO b/ksvg/TODO new file mode 100644 index 00000000..7d407484 --- /dev/null +++ b/ksvg/TODO @@ -0,0 +1,10 @@ +Not ordered! + +" - unfinished tasks" +" x finished tasks" + +x textPath [Progressing: Niko, Rob] +- viewBox +- perhaps seperate parsing and rendering better +- check events handling (prepareMouseEvent) +- kill render() diff --git a/ksvg/VERSION b/ksvg/VERSION new file mode 100644 index 00000000..fe57fc6a --- /dev/null +++ b/ksvg/VERSION @@ -0,0 +1 @@ +KSVG 0.1 diff --git a/ksvg/configure.in.bot b/ksvg/configure.in.bot new file mode 100644 index 00000000..cd823b77 --- /dev/null +++ b/ksvg/configure.in.bot @@ -0,0 +1,25 @@ +if test -z "$LCMS_LIBS" -o -z "$LIBART_LIBS" -o \ + -z "$FREETYPE_LIBS" -o -z "$FRIBIDI_LIBS" -o -z "$FONTCONFIG_LIBS"; then + echo "" + echo "Some of the libraries required for KSVG are missing or too old," + echo "therefore KSVG will not be compiled." + echo "" + echo "If you want to compile KSVG you should install:" + if test -z "$LCMS_LIBS"; then + echo " * lcms 1.09 or newer (http://www.littlecms.com/)" + fi + if test -z "$LIBART_LIBS"; then + echo " * libart 2.3.8 or newer (http://www.levien.com/libart/)" + fi + if test -z "$FREETYPE_LIBS"; then + echo " * freetype 2.0.6 or newer (http://www.freetype.org)" + fi + if test -z "$FONTCONFIG_LIBS"; then + echo " * fontconfig 2.2.0 or newer (http://fontconfig.org)" + fi + if test -z "$FRIBIDI_LIBS"; then + echo " * fribidi 0.10.4 or newer (http://freedesktop.org/Software/FriBidi)" + fi + echo "" + all_tests=bad +fi diff --git a/ksvg/configure.in.in b/ksvg/configure.in.in new file mode 100644 index 00000000..34d27f52 --- /dev/null +++ b/ksvg/configure.in.in @@ -0,0 +1,203 @@ +# Check for libart +KDE_FIND_PATH(libart2-config, LIBART_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin],) + +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]) + fi +fi + +AC_SUBST(LIBART_LIBS) +AC_SUBST(LIBART_CFLAGS) +AC_SUBST(LIBART_RPATH) + +if test -z "$LIBART_LIBS"; then + DO_NOT_COMPILE="$DO_NOT_COMPILE ksvg" +fi + +# Check for fontconfig +KDE_FIND_PATH(fontconfig-config, FONTCONFIG_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin], [ + KDE_FIND_PATH( pkg-config, PKG_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin /usr/bin],) + if test -n "$PKG_CONFIG"; then + if ! $PKG_CONFIG --exists fontconfig; then + unset PKG_CONFIG + fi + fi +]) +if test -n "$FONTCONFIG_CONFIG" -o -n "$PKG_CONFIG"; then + if test -n "$FONTCONFIG_CONFIG"; then + fontconfigvers="`$FONTCONFIG_CONFIG --version 2>/dev/null | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'`" + fontconfiglibs="`$FONTCONFIG_CONFIG --libs`" + fontconfigcflags="`$FONTCONFIG_CONFIG --cflags`" + else + fontconfigvers=`$PKG_CONFIG --modversion fontconfig 2>/dev/null | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3; }'` + fontconfiglibs=`$PKG_CONFIG --libs fontconfig` + fontconfigcflags="`$PKG_CONFIG --cflags fontconfig`" + fi + if test -n "$vers" && test "$vers" -ge 2002000 + then + FONTCONFIG_LIBS=$fontconfiglibs + FONTCONFIG_RPATH= + for args in $FONTCONFIG_LIBS; do + case $args in + -L*) + FONTCONFIG_RPATH="$FONTCONFIG_RPATH $args" + ;; + esac + done + FONTCONFIG_RPATH=`echo $FONTCONFIG_RPATH | sed -e "s/-L/-R/g"` + FONTCONFIG_CFLAGS=$fontconfigcflags + + AC_DEFINE_UNQUOTED(HAVE_FONTCONFIG, 1, [Defines if your system has the fontconfig library]) + fi +fi + +AC_SUBST(FONTCONFIG_LIBS) +AC_SUBST(FONTCONFIG_CFLAGS) +AC_SUBST(FONTCONFIG_RPATH) + +if test -z "$FONTCONFIG_LIBS"; then + DO_NOT_COMPILE="$DO_NOT_COMPILE ksvg" +fi + +# Check for freetype2 +KDE_FIND_PATH(freetype-config, FREETYPE_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin],) + +if test -n "$FREETYPE_CONFIG"; then + vers=`$FREETYPE_CONFIG --version 2>/dev/null | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'` + if test -n "$vers" && test "$vers" -ge 8000002 + then + FREETYPE_LIBS="`$FREETYPE_CONFIG --libs`" + FREETYPE_RPATH= + for args in $FREETYPE_LIBS; do + case $args in + -L*) + FREETYPE_RPATH="$FREETYPE_RPATH $args" + ;; + esac + done + FREETYPE_RPATH=`echo $FREETYPE_RPATH | sed -e "s/-L/-R/g"` + FREETYPE_CFLAGS="`$FREETYPE_CONFIG --cflags`" + + AC_DEFINE_UNQUOTED(HAVE_FREETYPE, 1, [Defines if your system has the freetype library]) + + ftvers=`$FREETYPE_CONFIG --ftversion 2>/dev/null | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'` + if test -n "$ftvers" && test "$ftvers" -ge 2002000 + then + AC_DEFINE_UNQUOTED(HAVE_FREETYPE_2_2_x, 1, [Defines if your system has the 2.2.x freetype library]) + fi + fi +fi + +AC_SUBST(FREETYPE_LIBS) +AC_SUBST(FREETYPE_CFLAGS) +AC_SUBST(FREETYPE_RPATH) + +if test -z "$FREETYPE_LIBS"; then + DO_NOT_COMPILE="$DO_NOT_COMPILE ksvg" +fi + +# Check for lcms +have_lcms_header='no' +KDE_CHECK_HEADER(lcms/lcms.h,have_lcms_header='yes',,) +if test "$have_lcms_header" = 'yes' +then + LCMS_LIBS='-llcms' + AC_DEFINE(LCMS_HEADER, , [The correct header]) +else + # Alternative! Debian does it this way... + KDE_CHECK_HEADER(lcms.h,have_lcms_header='yes',,) + if test "$have_lcms_header" = 'yes' + then + LCMS_LIBS='-llcms' + AC_DEFINE(LCMS_HEADER, , [The correct header]) + + # Try to find the full path of lcms.h + for a in $includedir $prefix/include /usr/include /usr/local/include $kde_extra_includes; do + for b in lcms.h lcms/lcms.h ; do + if test -d "$a" && test -f "$a/$b" ; then + LCMSHDR="$a/$b" + fi + done + done + # Check if lcms.h was found. If not then it means that we didn't search + # the right dirs since the kde check already found a usable lcms.h + if test -n "$LCMSHDR" ; then + # Get lcms version + lcms_ver_line=`cat $LCMSHDR | grep '^// Version' ` + if test -z "$lcms_ver_line" ; then + # Some versions of lcms have the version in /* */ + lcms_ver_line=`cat $LCMSHDR | grep '^/\* Version' ` + fi + lcms_ver=`echo "$lcms_ver_line" | head -n 1 | cut -d ' ' -f 3 ` + + # Get major and minor version numbers + lcms_var_maj=`echo $lcms_ver | cut -d . -f 1` + + # Some versions have a character attached to the end of minor version + lcms_var_min=`echo $lcms_ver | cut -d . -f 2 | sed 's,[^0-9],,g'` + + if test "$lcms_var_maj" -gt 1 || test "$lcms_var_min" -lt 9 ; then + LCMS_LIBS='' + fi + fi + else + LCMS_LIBS='' + fi +fi + +if test -z "$LCMS_LIBS"; then + DO_NOT_COMPILE="$DO_NOT_COMPILE ksvg" +fi + +AC_SUBST(LCMS_LIBS) + +# Check for fribidi +KDE_FIND_PATH(fribidi-config, FRIBIDI_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin],) + +if test -n "$FRIBIDI_CONFIG"; then + vers=`$FRIBIDI_CONFIG --version 2>/dev/null | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'` + if test -n "$vers" && test "$vers" -ge 10004 + then + FRIBIDI_LIBS="`$FRIBIDI_CONFIG --libs`" + FRIBIDI_RPATH= + for args in $FIBIDI_LIBS; do + case $args in + -L*) + FRIBIDI_RPATH="$FRIBIDI_CONFIG $args" + ;; + esac + done + FRIBIDI_RPATH=`echo $FRIBIDI_RPATH | sed -e "s/-L/-R/g"` + FRIBIDI_CFLAGS="`$FRIBIDI_CONFIG --cflags`" + + AC_DEFINE_UNQUOTED(HAVE_FRIBIDI, 1, [Defines if your system has the fribidi library]) + fi +fi + +AC_SUBST(FRIBIDI_LIBS) +AC_SUBST(FRIBIDI_CFLAGS) +AC_SUBST(FRIBIDI_RPATH) + +if test -z "$FRIBIDI_LIBS"; then + DO_NOT_COMPILE="$DO_NOT_COMPILE ksvg" +fi + +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +AC_CHECK_HEADERS(sstream) +AC_LANG_RESTORE diff --git a/ksvg/core/CanvasFactory.cpp b/ksvg/core/CanvasFactory.cpp new file mode 100644 index 00000000..ca2822b2 --- /dev/null +++ b/ksvg/core/CanvasFactory.cpp @@ -0,0 +1,176 @@ +/* + Copyright (C) 2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 + +#include +#include +#include + +#include "KSVGCanvas.h" +#include "CanvasFactory.h" + +using namespace KSVG; + +CanvasFactory *CanvasFactory::s_factory = 0; + +CanvasFactory::CanvasFactory() +{ + m_canvasList.setAutoDelete(true); +} + +CanvasFactory::~CanvasFactory() +{ +} + +CanvasFactory *CanvasFactory::self() +{ + if(!s_factory) + s_factory = new CanvasFactory(); + + return s_factory; +} + +void CanvasFactory::cleanup() +{ + m_canvasList.clear(); +} + +void CanvasFactory::queryCanvas() +{ + m_canvasList.clear(); + + QValueList traderList = KTrader::self()->query("KSVG/Renderer", "(Type == 'Service')"); + KTrader::OfferList::Iterator it(traderList.begin()); + for( ; it != traderList.end(); ++it) + { + KService::Ptr ptr = (*it); + + QString name = ptr->property("Name").toString(); + QString internal = ptr->property("X-KSVG-InternalName").toString(); + if(name.isEmpty() || internal.isEmpty()) + continue; + + CanvasInfo *cinfo = new CanvasInfo(); + cinfo->service = ptr; + cinfo->canvas = 0; + cinfo->name = name; + cinfo->internal = internal; + + m_canvasList.append(cinfo); + } + + if(m_canvasList.isEmpty()) + { + kdError(26001) << "Couldn't load any canvas!!! FATAL ERROR." << endl; + return; + } +} + +KSVGCanvas *CanvasFactory::loadCanvas(int width, int height) +{ + queryCanvas(); + + KSimpleConfig *config = new KSimpleConfig("ksvgpluginrc", false); + config->setGroup("Canvas"); + QString load = config->readEntry("ActiveCanvas", "libart"); + delete config; + + QPtrListIterator it(m_canvasList); + CanvasInfo *info = it.current(); + while((info = it.current()) != 0) + { + if(info->internal == load) + { + QStringList args; + args.prepend(QString::number(width)); + args.prepend(QString::number(height)); + + info->canvas = KParts::ComponentFactory::createInstanceFromLibrary(QFile::encodeName(info->service->library()), 0, 0, args); + + if(info->canvas) + return info->canvas; + else + { + kdError(26001) << "Failed to load canvas: " << load << " FATAL ERROR." << endl; + break; + } + } + + ++it; + } + + return 0; +} + +int CanvasFactory::itemInList(KSVGCanvas *canvas) +{ + QPtrListIterator it(m_canvasList); + CanvasInfo *info = it.current(); + unsigned int i = 0; + while((info = it.current()) != 0) + { + if(info->canvas == canvas) + return i; + + i++; + ++it; + } + + return 0; +} + +QString CanvasFactory::internalNameFor(const QString &name) +{ + QPtrListIterator it(m_canvasList); + CanvasInfo *info = it.current(); + while((info = it.current()) != 0) + { + if(info->name == name) + return info->internal; + + ++it; + } + + return QString::null; +} + +void CanvasFactory::deleteCanvas(KSVGCanvas *canvas) +{ + QPtrListIterator it(m_canvasList); + CanvasInfo *info = it.current(); + while((info = it.current()) != 0) + { + if(info->canvas == canvas) + { + delete info->canvas; + info->canvas = 0; + } + + ++it; + } +} + +QPtrList CanvasFactory::canvasList() +{ + return m_canvasList; +} + +// vim:ts=4:noet diff --git a/ksvg/core/CanvasFactory.h b/ksvg/core/CanvasFactory.h new file mode 100644 index 00000000..dc272700 --- /dev/null +++ b/ksvg/core/CanvasFactory.h @@ -0,0 +1,69 @@ +/* + Copyright (C) 2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 CANVASFACTORY_H +#define CANVASFACTORY_H + +#include + +#include +#include + +namespace KSVG +{ + +class KSVGCanvas; +class CanvasInfo +{ +public: + KService::Ptr service; + KSVGCanvas *canvas; + QString name, internal; +}; + +class CanvasFactory +{ +public: + CanvasFactory(); + ~CanvasFactory(); + + static CanvasFactory *self(); + + void cleanup(); + KSVGCanvas *loadCanvas(int width, int height); + + int itemInList(KSVGCanvas *canvas); + QString internalNameFor(const QString &name); + void deleteCanvas(KSVGCanvas *canvas); + + QPtrList canvasList(); + +private: + void queryCanvas(); + + static CanvasFactory *s_factory; + QPtrList m_canvasList; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/core/CanvasItem.h b/ksvg/core/CanvasItem.h new file mode 100644 index 00000000..7ffc7ad9 --- /dev/null +++ b/ksvg/core/CanvasItem.h @@ -0,0 +1,154 @@ +/* + Copyright (C) 2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 CANVASITEM_H +#define CANVASITEM_H + +#include +#include +#include + +#define CHUNK_SIZE_HORIZONTAL 32 +#define CHUNK_SIZE_VERTICAL 32 + +namespace KSVG +{ + +class SVGElementImpl; + +enum RenderContext +{ + /* NONE = for initializing */ + NONE = 0, + /* NORMAL = use baseVal()'s for calculation, and fillRule */ + NORMAL = 1, + /* CLIPPING = use baseVal()'s for calculation, and clipRule */ + CLIPPING = 2, + /* ANIMATION = use animVal()'s for calculation, and fillRule */ + ANIMATION = 4 +}; + +enum CanvasItemUpdate +{ + UPDATE_STYLE, + UPDATE_LINEWIDTH, + UPDATE_TRANSFORM, + UPDATE_ZOOM, + UPDATE_PAN +}; + +class CanvasItem +{ +public: + CanvasItem() { m_zIndex = 0; m_referenced = false; } + virtual ~CanvasItem() { } + + virtual QRect bbox() const = 0; + virtual bool fillContains(const QPoint &) = 0; + virtual bool strokeContains(const QPoint &) = 0; + virtual void update(CanvasItemUpdate reason, int param1 = 0, int param2 = 0) = 0; + virtual void draw() = 0; + virtual bool isVisible() = 0; + + void setZIndex(unsigned int zIndex) { m_zIndex = zIndex; } + unsigned int zIndex() const { return m_zIndex; } + + void setReferenced(bool referenced) { m_referenced = referenced; } + bool referenced() const { return m_referenced; } + + virtual SVGElementImpl *element() const { return 0; } + +protected: + unsigned int m_zIndex; + bool m_referenced; +}; + +class CanvasItemPtr +{ +public: + CanvasItemPtr() : ptr(0) { } + CanvasItemPtr(CanvasItem *p) : ptr(p) { } + + bool operator<=(const CanvasItemPtr& that) const + { + // Order same-z objects by identity. + if(that.ptr->zIndex() == ptr->zIndex()) + return that.ptr >= ptr; + return that.ptr->zIndex() >= ptr->zIndex(); + } + bool operator<(const CanvasItemPtr& that) const + { + // Order same-z objects by identity. + if(that.ptr->zIndex() == ptr->zIndex()) + return that.ptr > ptr; + return that.ptr->zIndex() > ptr->zIndex(); + } + bool operator>(const CanvasItemPtr& that) const + { + // Order same-z objects by identity. + if(that.ptr->zIndex() == ptr->zIndex()) + return that.ptr < ptr; + return that.ptr->zIndex() < ptr->zIndex(); + } + bool operator==(const CanvasItemPtr& that) const { return that.ptr == ptr; } + operator CanvasItem *() const { return ptr; } + +private: + CanvasItem *ptr; +}; + +class CanvasItemList : public QValueList +{ +public: + void sort() { qHeapSort(*((QValueList *) this)); } +}; + +class CanvasChunk +{ +public: + CanvasChunk(short x, short y) : m_x(x), m_y(y), m_dirty(false) { } + + void sort() { m_list.sort(); } + const CanvasItemList &list() const { return m_list; } + + void add(CanvasItem *item) { m_list.prepend(item); m_dirty = true; } + void remove(CanvasItem *item) { m_list.remove(item); m_dirty = true; } + + void setDirty() { m_dirty = true; } + bool unsetDirty() { bool y = m_dirty; m_dirty = false; return y; } + bool isDirty() const { return m_dirty; } + + short x() const { return m_x; } + short y() const { return m_y; } + + QRect bbox() const { return QRect(m_x * CHUNK_SIZE_HORIZONTAL, m_y * CHUNK_SIZE_VERTICAL, CHUNK_SIZE_HORIZONTAL, CHUNK_SIZE_VERTICAL); } + +private: + CanvasItemList m_list; + short m_x; + short m_y; + bool m_dirty : 1; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/core/CanvasItems.cpp b/ksvg/core/CanvasItems.cpp new file mode 100644 index 00000000..0ffd017c --- /dev/null +++ b/ksvg/core/CanvasItems.cpp @@ -0,0 +1,509 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 "KSVGCanvas.h" +#include "KSVGHelper.h" +#include "KSVGTextChunk.h" + +#include "CanvasItems.h" + +#include "SVGMatrixImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGPathElementImpl.h" +#include "SVGMarkerElementImpl.h" +#include "SVGTSpanElementImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGAnimatedStringImpl.h" +#include "SVGAnimatedLengthListImpl.h" +#include "SVGAnimatedEnumerationImpl.h" + +#include +#include +#include + +#include + +using namespace KSVG; + +CanvasText::CanvasText(SVGTextElementImpl *text) : CanvasItem(), m_text(text) +{ +} + +CanvasText::~CanvasText() +{ +} + +void CanvasText::handleTSpan(KSVGCanvas *canvas, const SVGMatrixImpl *screenCTM, int &curx, int &cury, int &endx, int &endy, SVGElementImpl *element, KSVGTextChunk *textChunk, T2P::BezierPath *bpath) +{ + SVGTSpanElementImpl *tspan = dynamic_cast(element); + if(!tspan) + return; + + if(!tspan->text().isEmpty() || element->nodeName() == "tref") + { + if((KSVG_TOKEN_NOT_PARSED_ELEMENT(SVGTextPositioningElementImpl::X, tspan) && KSVG_TOKEN_NOT_PARSED_ELEMENT(SVGTextPositioningElementImpl::Y, tspan)))// && !bpath) + textChunk->addText(tspan->text(), tspan); + else + { + // new absolute value for next textChunk, render old one + if(textChunk->count() > 0) + { + createGlyphs(textChunk, canvas, screenCTM, curx, cury, curx, cury, bpath); + textChunk->clear(); + } + + int usex, usey; + bool bMultipleX = false; + bool bMultipleY = false; + + if(tspan->x()->baseVal()->numberOfItems() == 0) + { + usex = curx; + + if(tspan->dx()->baseVal()->numberOfItems() > 0) + usex += int(tspan->dx()->baseVal()->getItem(0)->value()); + } + else + { + if(tspan->x()->baseVal()->numberOfItems() > 1) + bMultipleX = true; + + usex = int(tspan->x()->baseVal()->getItem(0)->value()); + } + + if(tspan->y()->baseVal()->numberOfItems() == 0) + { + usey = cury; + + if(tspan->dy()->baseVal()->numberOfItems() > 0) + usey += int(tspan->dy()->baseVal()->getItem(0)->value()); + } + else + { + if(tspan->y()->baseVal()->numberOfItems() > 1) + bMultipleY = true; + + usey = int(tspan->y()->baseVal()->getItem(0)->value()); + } + + QString text = tspan->text(); + if(!text.isEmpty()) + { + T2P::GlyphLayoutParams *params = tspan->layoutParams(); + + if(bMultipleX || bMultipleY) + { + for(unsigned int i = 0; i < text.length(); i++) + { + if(bMultipleX && i < tspan->x()->baseVal()->numberOfItems()) + usex = int(tspan->x()->baseVal()->getItem(i)->value()); + if(bMultipleY && i < tspan->y()->baseVal()->numberOfItems()) + usey = int(tspan->y()->baseVal()->getItem(i)->value()); + + textChunk->addText(QString(text.at(i)), tspan); + createGlyphs(textChunk, canvas, screenCTM, usex, usey, endx, endy, bpath); + textChunk->clear(); + + if(!params->tb()) + usex += endx; + else + usey += endy; + } + } + else + { + textChunk->addText(text, tspan); + //createGlyphs(textChunk, canvas, screenCTM, usex, usey, endx, endy, bpath); + //textChunk->clear(); + } + + curx = usex; + cury = usey; + + if(!params->tb()) + curx += endx; + else + cury += endy; + + delete params; + } + } + } + + DOM::Node node = (tspan->getTextDirection() == LTR) ? tspan->firstChild() : tspan->lastChild(); + + bool tspanFound = false; + for(; !node.isNull(); node = ((tspan->getTextDirection() == LTR) ? node.nextSibling() : node.previousSibling())) + { + SVGElementImpl *element = m_text->ownerDoc()->getElementFromHandle(node.handle()); + if(node.nodeType() == DOM::Node::TEXT_NODE) + { + if(tspanFound) + { + DOM::Text text = node; + QString temp = text.data().string(); + textChunk->addText(temp, tspan); + } + } + else if(element->nodeName() == "tspan" || element->nodeName() == "tref") + { + tspanFound = true; + handleTSpan(canvas, screenCTM, curx, cury, endx, endy, element, textChunk, 0); + } + } + +} + +KSVGTextChunk *CanvasText::createTextChunk(KSVGCanvas *canvas, const SVGMatrixImpl *screenCTM, int &curx, int &cury, int &endx, int &endy) +{ + KSVGTextChunk *textChunk = new KSVGTextChunk(); + + SVGLengthImpl *length = m_text->x()->baseVal()->getItem(0); + if(length) + curx = int(length->value()); + + length = m_text->y()->baseVal()->getItem(0); + if(length) + cury = int(length->value()); + + // Otherwhise some js scripts which require a child, don't work (Niko) + if(!m_text->hasChildNodes()) + { + DOM::Text impl = static_cast(m_text->ownerDoc())->createTextNode(DOM::DOMString("")); + m_text->appendChild(impl); + } + else + { + DOM::Node node = (m_text->getTextDirection() == LTR) ? m_text->firstChild() : m_text->lastChild(); + + for(; !node.isNull(); node = ((m_text->getTextDirection() == LTR) ? node.nextSibling() : node.previousSibling())) + { + if(node.nodeType() == DOM::Node::TEXT_NODE) + { + DOM::Text text = node; + QString temp = text.data().string(); + + if(!temp.isEmpty()) + { + if(m_text->getTextDirection() != LTR) + { + QString convert = temp; + + for(int i = temp.length(); i > 0; i--) + convert[temp.length() - i] = temp[i - 1]; + + temp = convert; + } + + textChunk->addText(temp, m_text); + } + } + else + { + SVGElementImpl *element = m_text->ownerDoc()->getElementFromHandle(node.handle()); + if(element->nodeName() == "textPath") + { + // new absolute value for next textChunk, render old one + if(textChunk->count() > 0) + { + createGlyphs(textChunk, canvas, screenCTM, curx, cury, curx, cury); + textChunk->clear(); + } + + SVGTextPathElementImpl *tpath = dynamic_cast(element); + QString target = SVGURIReferenceImpl::getTarget(tpath->href()->baseVal().string()); + SVGPathElementImpl *path = dynamic_cast(tpath->ownerSVGElement()->getElementById(target)); + + T2P::BezierPath *bpath = 0; + if(path && path->item()) + bpath = tpath->ownerDoc()->canvas()->toBezierPath(path->item()); + + DOM::Node iterate = tpath->firstChild(); + for(; !iterate.isNull(); iterate = iterate.nextSibling()) + { + if(iterate.nodeType() == DOM::Node::TEXT_NODE) + { + DOM::Text text = iterate; + QString temp = text.data().string(); + + if(!temp.isEmpty()) + textChunk->addText(temp, tpath); + } + else + { + kdDebug() << "FOUND TSPAN IN TEXTPATH! BPATH:" << bpath <ownerDoc()->getElementFromHandle(iterate.handle()); + handleTSpan(canvas, screenCTM, curx, cury, endx, endy, itelement, textChunk, bpath); + } + } + + if(textChunk->count() > 0) + { + int usex = 0, usey = 0; + createGlyphs(textChunk, canvas, screenCTM, usex, usey, endx, endy, bpath); + textChunk->clear(); + + curx = usex; + cury = usey; + + T2P::GlyphLayoutParams *params = tpath->layoutParams(); + + if(!params->tb()) + curx += endx; + else + cury += endy; + + delete params; + } + } + else if(element->nodeName() == "tspan" || element->nodeName() == "tref") + handleTSpan(canvas, screenCTM, curx, cury, endx, endy, element, textChunk, 0); + } + } + } + + return textChunk; +} + +void CanvasText::createGlyphs(KSVGTextChunk *textChunk, KSVGCanvas *canvas, const SVGMatrixImpl *screenCTM, int curx, int cury, int &endx, int &endy, T2P::BezierPath *bpath) const +{ + double _curx = double(curx); + QMemArray _cury(1); + _cury[0] = double(cury); + + T2P::GlyphLayoutParams *params = m_text->layoutParams(); + SVGTextPositioningElementImpl *tp = textChunk->getTextElement(0); + SVGTextContentElementImpl *tc = textChunk->getTextContentElement(0); + SVGTextContentElementImpl *tc0 = tc; + + T2P::SharedFont font; + QString text; + QPtrList glyphs; + glyphs.setAutoDelete(true); + + double pathAdvance = 0; + SVGTextPathElementImpl *tpath = dynamic_cast(tc0); + if(tpath) + pathAdvance = tpath->startOffset()->baseVal()->value(); + double pathLength = bpath ? bpath->length() : 0; + double pathDy = 0; + for(unsigned int i = 0; i < textChunk->count(); i++) + { + tp = textChunk->getTextElement(i); + tc = textChunk->getTextContentElement(i); + + if(tp && tp->dx()->baseVal()->numberOfItems() > 0) + if(bpath) + pathAdvance += tp->dx()->baseVal()->getItem(0)->value() / pathLength; + else + _curx += tp->dx()->baseVal()->getItem(0)->value(); + _cury[i] += (tp && tp->dy()->baseVal()->numberOfItems() > 0) ? tp->dy()->baseVal()->getItem(0)->value() : 0; + + SVGMatrixImpl *tempMatrix = SVGSVGElementImpl::createSVGMatrix(); + tempMatrix->translate(_curx, _cury[i]); + + text = textChunk->getText(i); + if(i != textChunk->count() - 1) + text += QChar(' '); + + if(!canvas->fontContext()->ready()) + canvas->fontContext()->init(); + + font = canvas->fontContext()->requestFont(canvas->fontVisualParams(tc)); + + if(!font) + break; + + double addLetterSpacing = 0; + + // Apply affine corrections, through lengthAdjust + textLength + if(tp && tp->textLength()->baseVal()->value() != -1) + { + // #1 Measure text + SVGTextElementImpl *textElement = dynamic_cast(tp); + const SVGMatrixImpl *ctm = textElement->screenCTM(); + + T2P::Affine affine; + { + SVGMatrixImpl *temp = SVGSVGElementImpl::createSVGMatrix(); + + temp->multiply(ctm); + temp->translate(_curx, _cury[0]); + + KSVGHelper::matrixToAffine(temp, affine); + + temp->deref(); + } + + T2P::GlyphSet *measure = canvas->fontContext()->calcString(font.get(), text.ucs2(), text.length(), affine, params, bpath); + + // Free bpath's + measure->set().clear(); + + // #2 Calculate textLength + double textLength = tp->textLength()->baseVal()->value(); + + // #3 Apply the spacing + if(tp->lengthAdjust()->baseVal() == LENGTHADJUST_SPACINGANDGLYPHS) + tempMatrix->scaleNonUniform((textLength * ctm->a()) / measure->width(), 1); + else if(tp->lengthAdjust()->baseVal() == LENGTHADJUST_SPACING) + addLetterSpacing = ((textLength - (measure->width() / ctm->a())) / text.length()); + + // #4 cleanup + delete measure; + } + + { + T2P::GlyphLayoutParams *params = tc->layoutParams(); + params->setLetterSpacing(params->letterSpacing() + addLetterSpacing); + if(bpath) + { + params->setTextPathStartOffset(pathAdvance); + if(tp && tp->dy()->baseVal()->numberOfItems() > 0) + pathDy += tp->dy()->baseVal()->getItem(0)->value(); + QString shift = QString("%1%%").arg((pathDy / font->fontParams()->size()) * -100.0); + params->setBaselineShift(shift.latin1()); + } + + T2P::Affine affine; + KSVGHelper::matrixToAffine(tempMatrix, affine); + tempMatrix->deref(); + + T2P::GlyphSet *glyph = canvas->fontContext()->calcString(font.get(), text.ucs2(), text.length(), affine, params, bpath); + if(bpath) + pathAdvance += double(glyph->width()) / pathLength; + _curx += (params->tb() ? 0 : glyph->xpen()); + _cury.resize(i + 2); + _cury[i + 1] = _cury[i] + (params->tb() ? glyph->ypen() : 0); + if(!glyph) + break; + else + glyphs.append(glyph); + + delete params; + } + } + + // Calculate text-anchor + double anchor = 0; + + // anchor == "start" is the default here (Rob) + if(tc->getTextAnchor() == TAMIDDLE) + { + if(!params->tb()) + anchor = ((_curx - curx) + 1) / 2; + else + anchor = ((_cury[textChunk->count()] - cury) + 1) / 2; + } + else if(tc->getTextAnchor() == TAEND) + { + if(!params->tb()) + anchor = (_curx - curx); + else + anchor = (_cury[textChunk->count()] - cury); + } + + // Render all glyphs of the text chunk + // Take first glyphset + T2P::GlyphSet *glyph = glyphs.at(0); + if(!glyph) + return; + + // Draw 'text-decoration' + // TODO: Currently just ignore text-decoration on vertical layouts, is that correct? + // Underline and overline have to be drawn before the glyphs are rendered + if(tc0->getTextDecoration() & UNDERLINE && !params->tb()) + addTextDecoration(tc0, (curx - anchor), (cury + (glyph->underlinePosition() - glyph->pixelBaseline())), + _curx - curx, glyph->underlineThickness()); + if(tc0->getTextDecoration() & OVERLINE && !params->tb()) + addTextDecoration(tc0, (curx - anchor), (cury + (glyph->overlinePosition() - glyph->pixelBaseline())), + _curx - curx, glyph->underlineThickness()); + + for(unsigned int j = 0; j < glyphs.count(); j++) + { + glyph = glyphs.at(j); + SVGTextContentElementImpl *style = textChunk->getTextContentElement(j); + + // Draw 'text-decoration' + // TODO: Currently just ignore text-decoration on vertical layouts, is that correct? + // Underline and overline have to be drawn before the glyphs are rendered + if(style->getAttribute("text-decoration") == "underline" && !params->tb()) + addTextDecoration(style, glyph->bboxX() - anchor, (cury + (glyph->underlinePosition() - glyph->pixelBaseline())), + glyph->width(), glyph->underlineThickness()); + else if(style->getAttribute("text-decoration") == "overline" && !params->tb()) + addTextDecoration(style, glyph->bboxX() - anchor, (cury + (glyph->overlinePosition() - glyph->pixelBaseline())), + glyph->width(), glyph->underlineThickness()); + + renderCallback(style, screenCTM, glyph, params, anchor); + + // Clear GlyphAffinePair's + for(std::vector::iterator it = glyph->set().begin(); it != glyph->set().end(); ++it) + { + T2P::GlyphAffinePair *glyphAffine = *it; + delete glyphAffine; + } + + glyph->set().clear(); + + // Draw 'line-through' text decoration + // Line-through has to be drawn after the glyphs are rendered + if(style->getAttribute("text-decoration") == "line-through" && !params->tb()) + addTextDecoration(style, glyph->bboxX() - anchor, (cury + (glyph->strikeThroughPosition() - glyph->pixelBaseline())), glyph->width(), glyph->underlineThickness()); + + } + + endx = glyph->bboxX() + glyph->width(); + endy = int(_cury[glyphs.count() - 1]); + + // Draw 'line-through' text decoration + // Line-through has to be drawn after the glyphs are rendered + if(tc0->getTextDecoration() & LINE_THROUGH && !params->tb()) + addTextDecoration(tc0, (curx - anchor), (cury + (glyph->strikeThroughPosition() - glyph->pixelBaseline())), _curx - curx, glyph->underlineThickness()); + + delete params; +} + +// ##### + +void MarkerHelper::doMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle, const QString &markerId) +{ + SVGMarkerElementImpl *marker = dynamic_cast(shape->ownerSVGElement()->getElementById(markerId)); + if(marker) + marker->draw(shape, x, y, style->getStrokeWidth()->baseVal()->value(), angle); +} + +void MarkerHelper::doStartMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle) +{ + doMarker(shape, style, x, y, angle, style->getStartMarker()); +} + +void MarkerHelper::doMidMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle) +{ + doMarker(shape, style, x, y, angle, style->getMidMarker()); +} + +void MarkerHelper::doEndMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle) +{ + doMarker(shape, style, x, y, angle, style->getEndMarker()); +} + +// vim:ts=4:noet diff --git a/ksvg/core/CanvasItems.h b/ksvg/core/CanvasItems.h new file mode 100644 index 00000000..8959d6ba --- /dev/null +++ b/ksvg/core/CanvasItems.h @@ -0,0 +1,133 @@ +/* + Copyright (C) 2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 CANVASITEMS_H +#define CANVASITEMS_H + +#include +#include "CanvasItem.h" +#include "SVGTextElementImpl.h" +#include "SVGTextPathElementImpl.h" + +#include "svgpathparser.h" +#include "SVGBBoxTarget.h" + +namespace T2P +{ + class GlyphSet; + class BezierPath; + class GlyphLayoutParams; +} + +namespace KSVG +{ + +class KSVGCanvas; +class KSVGTextChunk; +class SVGPathParser; +class SVGMatrixImpl; +class SVGMarkerElementImpl; +class SVGClipPathElementImpl; +class SVGTextContentElementImpl; +class SVGTextPathElementImpl; + +#define CANVAS_CLASS(Prefix, Class, Postfix, Member) \ +class Canvas##Class : public CanvasItem \ +{ \ +public: \ + Canvas##Class(Prefix##Class##Postfix *Member) : CanvasItem(), m_##Member(Member) { } \ + virtual ~Canvas##Class() { } \ + virtual SVGElementImpl *element() { return reinterpret_cast(m_##Member); } \ +protected: \ + Prefix##Class##Postfix *m_##Member; \ +}; + +CANVAS_CLASS(SVG, ClipPath, ElementImpl, clipPath) + +class CanvasMarker : public CanvasItem +{ +public: + CanvasMarker(SVGMarkerElementImpl *marker) : CanvasItem(), m_marker(marker) {} + virtual ~CanvasMarker() {} + virtual SVGElementImpl *element() { return reinterpret_cast(m_marker); } + + virtual void draw(SVGShapeImpl *obj, double x, double y, double lwidth = 1.0, double angle = 0.0) + { + Q_UNUSED(obj); Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(lwidth); Q_UNUSED(angle); + } + +protected: + SVGMarkerElementImpl *m_marker; +}; + +class MarkerHelper +{ +protected: + void doStartMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle = 0.0); + void doMidMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle = 0.0); + void doEndMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle = 0.0); + +private: + void doMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle, const QString &marker); +}; + +class CanvasText : public CanvasItem +{ +public: + CanvasText(SVGTextElementImpl *text); + virtual ~CanvasText(); + + KSVGTextChunk *createTextChunk(KSVGCanvas *canvas, const SVGMatrixImpl *screenCTM, int &curx, int &cury, int &endx, int &endy); + virtual SVGElementImpl *element() const { return m_text; } + + virtual void renderCallback(SVGTextContentElementImpl *element, const SVGMatrixImpl *screenCTM, T2P::GlyphSet *glyph, T2P::GlyphLayoutParams *params, double anchor) const = 0; + void createGlyphs(KSVGTextChunk *textChunk, KSVGCanvas *canvas, const SVGMatrixImpl *screenCTM, int curx, int cury, int &endx, int &endy, T2P::BezierPath *bpath = 0) const; + + virtual void addTextDecoration(SVGTextContentElementImpl *element, double x, double y, double w, double h) const = 0; + +private: + void handleTSpan(KSVGCanvas *canvas, const SVGMatrixImpl *screenCTM, int &curx, int &cury, int &endx, int &endy, SVGElementImpl *element, KSVGTextChunk *textChunk, T2P::BezierPath *bpath); + +protected: + SVGTextElementImpl *m_text; +}; + +class CanvasPaintServer : public SVGBBoxTarget +{ +public: + CanvasPaintServer() : SVGBBoxTarget() { m_finalized = false; } + virtual ~CanvasPaintServer() {} + + void setFinalized() { m_finalized = true; } + void resetFinalized() { m_finalized = false; } + bool finalized() { return m_finalized; } + + virtual void finalizePaintServer() = 0; + virtual void reference(const QString &href) = 0; + +private: + bool m_finalized; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/core/DocumentFactory.cpp b/ksvg/core/DocumentFactory.cpp new file mode 100644 index 00000000..bcc0ddcb --- /dev/null +++ b/ksvg/core/DocumentFactory.cpp @@ -0,0 +1,110 @@ +/* + Copyright (C) 2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include +#include + +#include "SVGDocument.h" +#include "SVGElementImpl.h" +#include "SVGDocumentImpl.h" +#include "DocumentFactory.h" + +using namespace KSVG; + +namespace KSVG +{ + class DocumentFactory::Private + { + public: + Private() { m_docs.setAutoDelete(true); } + ~Private() { m_docs.clear(); } + + void setup(bool bFit) { m_docs.append(new SVGDocumentImpl(!bFit /* animations */, bFit)); } + SVGDocumentImpl *doc() const { return m_docs.current(); } + + private: + QPtrList m_docs; + }; +} + +static KStaticDeleter s_deleter; +static DocumentFactory *s_factory = 0; + +DocumentFactory::DocumentFactory() : m_d(new Private()) +{ +} + +DocumentFactory::~DocumentFactory() +{ + delete m_d; +} + +DocumentFactory *DocumentFactory::self() +{ + if(!s_factory) + s_deleter.setObject(s_factory, new DocumentFactory()); + return s_factory; +} + +SVGDocument *DocumentFactory::requestDocument(QObject *notifyObject, const char *notifySlot) const +{ + SVGDocumentImpl *impl = requestDocumentImpl(false); + QObject::connect(impl, SIGNAL(finishedParsing(bool, const QString &)), notifyObject, notifySlot); + + return new SVGDocument(impl); +} + +bool DocumentFactory::startParsing(SVGDocument *document, const KURL &url) +{ + if(!document || !document->handle()) + return false; + + return reinterpret_cast(document->handle())->open(url); +} + +bool DocumentFactory::attachCanvas(KSVGCanvas *canvas, SVGDocument *document) +{ + if(!canvas || !document || !document->handle()) + return false; + + SVGDocumentImpl *docImpl = reinterpret_cast(document->handle()); + + if(docImpl) + { + docImpl->attach(canvas); + return true; + } + + return false; +} + +SVGDocumentImpl *DocumentFactory::requestDocumentImpl(bool bFit) const +{ + m_d->setup(bFit); + + SVGDocumentImpl *impl = m_d->doc(); + impl->ref(); + + return impl; +} + +// vim:ts=4:noet diff --git a/ksvg/core/DocumentFactory.h b/ksvg/core/DocumentFactory.h new file mode 100644 index 00000000..290d54ac --- /dev/null +++ b/ksvg/core/DocumentFactory.h @@ -0,0 +1,63 @@ +/* + Copyright (C) 2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 DocumentFactory_H +#define DocumentFactory_H + +#include +#include + +namespace KSVG +{ + +class KSVGCanvas; +class SVGDocument; +class SVGDocumentImpl; +class DocumentFactory +{ +public: + DocumentFactory(); + ~DocumentFactory(); + + static DocumentFactory *self(); + + // Creates a document and connects the parsingFinished() signal to the notifySlot... + SVGDocument *requestDocument(QObject *notifyObject, const char *notifySlot) const; + + // Loads 'url' and emits parsingFinisihed() signal, when done + bool startParsing(SVGDocument *document, const KURL &url); + + // Attaches the a canvas to the document, that is ksvg specific code + bool attachCanvas(KSVGCanvas *canvas, SVGDocument *document); + + // Internal use only - external coders don't have the + // possibility to use SVGDocumentImpl anyway + SVGDocumentImpl *requestDocumentImpl(bool bFit) const; + +private: + class Private; + Private *m_d; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/core/KSVGCanvas.cpp b/ksvg/core/KSVGCanvas.cpp new file mode 100644 index 00000000..d4e75d79 --- /dev/null +++ b/ksvg/core/KSVGCanvas.cpp @@ -0,0 +1,786 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 "CanvasItem.h" +#include "CanvasItems.h" +#include "KSVGCanvas.moc" + +#include "SVGRectImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGStringListImpl.h" +#include "SVGClipPathElementImpl.h" +#include "SVGImageElementImpl.h" +#include "SVGDocumentImpl.h" + +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include + +#include +#include + +#define USE_TIMER + +using namespace KSVG; + +KSVGCanvas::KSVGCanvas(unsigned int width, unsigned int height) : m_viewportWidth(width), m_viewportHeight(height), m_width(width), m_height(height) +{ + m_fontContext = 0; + + m_items.setAutoDelete(true); + + m_chunkSizeVer = CHUNK_SIZE_VERTICAL; + m_chunkSizeHor = CHUNK_SIZE_HORIZONTAL; + + m_zoom = 1; + + m_buffer = 0; + + m_backgroundColor = QColor(250, 250, 250); + + m_immediateUpdate = false; +} + +void KSVGCanvas::setup(QPaintDevice *drawWindow, QPaintDevice *directWindow) +{ + m_drawWindow = drawWindow; + m_directWindow = directWindow; + + m_buffer = 0; + m_nrChannels = 3; + + setRenderBufferSize(m_width, m_height); + + xlib_rgb_init_with_depth(m_drawWindow->x11Display(), XScreenOfDisplay(m_drawWindow->x11Display(), m_drawWindow->x11Screen()), m_drawWindow->x11Depth()); + m_gc = XCreateGC(m_drawWindow->x11Display(), m_drawWindow->handle(), 0, 0); +} + +void KSVGCanvas::setViewportDimension(unsigned int w, unsigned int h) +{ + m_viewportWidth = w; + m_viewportHeight = h; + setRenderBufferSize(w, h); +} + +void KSVGCanvas::setup(unsigned char *buffer, unsigned int width, unsigned int height) +{ + setBuffer(buffer); + m_drawWindow = 0; + m_directWindow = 0; + + m_nrChannels = 4; + + if(height > 0) + { + m_width = width; + m_height = height; + } + + setRenderBufferSize(m_width, m_height); + + m_gc = 0; +} + +void KSVGCanvas::setBuffer(unsigned char *buffer) +{ + m_buffer = buffer; +} + +KSVGCanvas::~KSVGCanvas() +{ + if(m_fontContext) + delete m_fontContext; + + if(m_buffer && m_gc) + delete []m_buffer; + + if(m_gc) + XFreeGC(m_drawWindow->x11Display(), m_gc); + + reset(); +} + +void KSVGCanvas::retune(unsigned int csh, unsigned int csv) +{ + m_chunkSizeHor = csh; + m_chunkSizeVer = csv; +} + +void KSVGCanvas::resize(unsigned int w, unsigned int h) +{ + if(m_buffer && (m_width != int(w) || m_height != int(h))) + { + unsigned char *oldbuffer = m_buffer; + + m_buffer = new unsigned char[w * h * m_nrChannels]; + + int minw = kMin(int(w), m_width); + int minh = kMin(int(h), m_height); + + int origstride = m_width * m_nrChannels; + int newstride = w * m_nrChannels; + + // Redraw new areas, if any + int diffw = w - m_width; + int diffh = h - m_height; + + QRect r(m_width, 0, diffw, m_height + diffh); + QRect r3(0, m_height, m_width + diffw, diffh); + + QWMatrix mtx; + mtx.translate(m_pan.x(), m_pan.y()); + mtx.scale(m_zoom, m_zoom); + + m_width = w; + m_height = h; + + setBuffer(m_buffer); + fill(); + + if(diffw > 0 || diffh > 0) + { + CanvasItemList drawables; + if(diffw > 0) + { + QRect r2 = mtx.invert().map(r); + + // Recalc items + for(int j = r2.top() / int(m_chunkSizeVer); j <= r2.bottom() / int(m_chunkSizeVer); j++) + { + for(int i = r2.left() / int(m_chunkSizeHor); i <= r2.right() / int(m_chunkSizeHor); i++) + { + CanvasChunk *chunk = m_chunkManager.getChunk(i, j); + if(chunk) + { + for(CanvasItemList::ConstIterator it = chunk->list().begin(); it != chunk->list().end(); ++it) + { + if(!drawables.contains(*it)) + drawables.append(*it); + } + } + } + } + } + + if(diffh > 0) + { + QRect r4 = mtx.invert().map(r3); + + // Recalc items + for(int j = r4.top() / int(m_chunkSizeVer); j <= r4.bottom() / int(m_chunkSizeVer); j++) + { + for(int i = r4.left() / int(m_chunkSizeHor); i <= r4.right() / int(m_chunkSizeHor); i++) + { + CanvasChunk *chunk = m_chunkManager.getChunk(i, j); + if(chunk) + { + for(CanvasItemList::ConstIterator it = chunk->list().begin(); it != chunk->list().end(); ++it) + { + if(!drawables.contains(*it)) + drawables.append(*it); + } + } + } + } + } + + drawables.sort(); + + for(CanvasItemList::Iterator it = drawables.begin(); it != drawables.end(); ++it) + (*it)->draw(); + } + + for(int y = 0; y < minh; y++) + memcpy(m_buffer + y * newstride, oldbuffer + y * origstride, minw * m_nrChannels); + + delete []oldbuffer; + } +} + +void KSVGCanvas::setRenderBufferSize(int w, int h) +{ + kdDebug(26005) << k_funcinfo << endl; + + if(m_drawWindow) + { + bool needsRedraw = (!m_buffer) || (m_width != w || m_height != h); + + if(needsRedraw) + { + QPaintDeviceMetrics metrics(m_drawWindow); + m_width = kMin(int(w), metrics.width()); + m_height = kMin(int(h), metrics.height()); + + if(m_buffer) + delete []m_buffer; + + m_buffer = new unsigned char[m_width * m_height * m_nrChannels]; + } + } + + fill(); +} + +void KSVGCanvas::clear(const QRect &r) +{ + QRect r2 = r & QRect(0, 0, m_width, m_height); + if(!r2.isEmpty() && m_buffer) + { + for(int i = 0; i < r2.height(); i++) + memset(m_buffer + int(r2.x() * m_nrChannels) + int((r2.y() + i) * (m_width * m_nrChannels)), qRgba(250, 250, 250, 250), r2.width() * m_nrChannels); + } +} + +void KSVGCanvas::fill() +{ + if(m_buffer) + { + unsigned char r = m_backgroundColor.red(); + unsigned char g = m_backgroundColor.green(); + unsigned char b = m_backgroundColor.blue(); + + if(m_nrChannels == 3) + { + if(r == g && r == b) + memset(m_buffer, r, m_width * m_height * m_nrChannels); + else + { + unsigned char *p = m_buffer; + + for(int i = 0; i < m_width * m_height; i++) + { + *p++ = r; + *p++ = g; + *p++ = b; + } + } + } + else + { + Q_UINT32 *p = reinterpret_cast(m_buffer); + unsigned char a = qAlpha(m_backgroundColor.rgb()); + +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + Q_UINT32 rgba = (a << 24) | (b << 16) | (g << 8) | r; +#else + Q_UINT32 rgba = (r << 24) | (g << 16) | (b << 8) | a; +#endif + for(int i = 0; i < m_width * m_height; i++) + *p++ = rgba; + } + } +} + +// Clipping +void KSVGCanvas::clipToBuffer(int &x0, int &y0, int &x1, int &y1) const +{ + // clamp to viewport + x0 = QMAX(x0, 0); + x0 = QMIN(x0, int(m_width - 1)); + + y0 = QMAX(y0, 0); + y0 = QMIN(y0, int(m_height - 1)); + + x1 = QMAX(x1, 0); + x1 = QMIN(x1, int(m_width - 1)); + + y1 = QMAX(y1, 0); + y1 = QMIN(y1, int(m_height - 1)); +} + +T2P::FontVisualParams *KSVGCanvas::fontVisualParams(SVGStylableImpl *style) const +{ + T2P::FontVisualParams *fontVisualParams = new T2P::FontVisualParams(); + + // Calc weight & slant + int weight = 0, slant = 0; + EFontStyle fontStyle = style->getFontStyle(); + QString fontWeight = style->getFontWeight(); + + if(fontWeight.contains("bold")) + weight |= FC_WEIGHT_DEMIBOLD; + if(fontWeight.contains("bolder")) + weight |= FC_WEIGHT_BOLD; + if(fontWeight.contains("lighter")) + weight |= FC_WEIGHT_LIGHT; + + bool ok = true; + int weightNumber = fontWeight.toInt(&ok); + + if(ok) + weight = weightNumber; + + if(fontStyle == FSNORMAL) + slant |= FC_SLANT_ROMAN; + else if(fontStyle == ITALIC) + slant |= FC_SLANT_ITALIC; + else if(fontStyle == OBLIQUE) + slant |= FC_SLANT_OBLIQUE; + + // Calc font names + SVGStringListImpl *fontList = style->getFontFamily(); + + for(unsigned int i = 0; i <= fontList->numberOfItems(); i++) + { + DOM::DOMString *string = fontList->getItem(i); + + if(string) + fontVisualParams->fontList().push_back(string->string().latin1()); + } + + fontVisualParams->setWeight(weight); + fontVisualParams->setSlant(slant); + fontVisualParams->setSize(style->getFontSize()); + + return fontVisualParams; +} + +void KSVGCanvas::invalidate(CanvasItem *item, bool recalc) +{ + if(m_chunksByItem.find(item) != m_chunksByItem.end()) + { + if(recalc) + { + removeFromChunks(item); + addToChunks(item); + } + + QPtrListIterator it = m_chunksByItem[item]; + for(it.toFirst(); it.current(); ++it) + { + (*it)->setDirty(); + if(!m_dirtyChunks.contains(*it)) + m_dirtyChunks.append(*it); + } + } + else + addToChunks(item); +} + +void KSVGCanvas::insert(CanvasItem *item, int z) +{ + if(z == -1) + { + item->setZIndex(m_chunksByItem.size()); + m_chunksByItem[item] = QPtrList(); + addToChunks(item); + m_items.append(item); + + bool visible = item->isVisible(); + if(visible) + invalidate(item, false); + + if(m_immediateUpdate) + { + if(visible) + { + item->draw(); + QRect bbox = item->bbox(); + blit(bbox, true); + } + } + } + else + { + // make some space + for(unsigned int i = z; i < m_items.count(); i++) + m_items.at(i)->setZIndex(m_items.at(i)->zIndex() + 1); + + item->setZIndex(z); + } +} + +void KSVGCanvas::removeItem(CanvasItem *item) +{ + removeFromChunks(item); + m_items.remove(item); +} + +void KSVGCanvas::removeFromChunks(CanvasItem *item) +{ + QPtrListIterator it = m_chunksByItem[item]; + for(it.toFirst(); it.current(); ++it) + { + (*it)->remove(item); + if(!m_dirtyChunks.contains(*it)) + m_dirtyChunks.append(*it); + } + m_chunksByItem.remove(item); +} + +void KSVGCanvas::addToChunks(CanvasItem *item) +{ + QRect bbox = item->bbox(); + QWMatrix mtx; + mtx.translate(m_pan.x(), m_pan.y()); + mtx.scale(m_zoom, m_zoom); + + bbox = mtx.invert().map(bbox); + for(int j = bbox.top() / m_chunkSizeVer; j <= (bbox.bottom() / m_chunkSizeVer); j++) + { + for(int i = bbox.left() / int(m_chunkSizeHor); i <= (bbox.right() / m_chunkSizeHor); i++) + { + CanvasChunk *chunk = m_chunkManager.getChunk(i, j); + if(!chunk) + { + chunk = new CanvasChunk(i, j); + m_chunkManager.addChunk(chunk); + } + + chunk->add(item); + m_chunksByItem[item].append(chunk); + } + } +} + +unsigned int KSVGCanvas::setElementItemZIndexRecursive(SVGElementImpl *element, unsigned int z) +{ + SVGShapeImpl *shape = dynamic_cast(element); + + if(shape) + { + CanvasItem *item = shape->item(); + + if(item) + { + SVGImageElementImpl *image = dynamic_cast(shape); + + if(image && image->svgImageRootElement()) + { + // Set the z for all items in the svg image, since they live in the + // same canvas. + z = setElementItemZIndexRecursive(image->svgImageRootElement(), z); + } + else + { + item->setZIndex(z); + invalidate(item, false); + z++; + } + } + } + + for(DOM::Node node = element->firstChild(); !node.isNull(); node = node.nextSibling()) + { + SVGElementImpl *e = element->ownerDoc()->getElementFromHandle(node.handle()); + + if(e) + z = setElementItemZIndexRecursive(e, z); + } + + return z; +} + +void KSVGCanvas::update(const QPoint &panPoint, bool erase) +{ +#ifdef USE_TIMER + QTime t; + t.start(); +#endif + + int dx = panPoint.x() - m_pan.x(); + int dy = panPoint.y() - m_pan.y(); + m_pan = panPoint; + + if(erase) + fill(); + + // reset clip paths + QDictIterator itr(m_clipPaths); + for(; itr.current(); ++itr) + (*itr)->update(UPDATE_TRANSFORM); + + QWMatrix mtx; + mtx.translate(m_pan.x(), m_pan.y()); + mtx.scale(m_zoom, m_zoom); + + QRect r(0, 0, m_width, m_height); + QRect r2 = mtx.invert().map(r); + + // pan all items + for(unsigned int i = 0; i < m_items.count(); i++) + m_items.at(i)->update(UPDATE_PAN, dx, dy); + + // recalc items + CanvasItemList drawables; + QPtrListIterator it = m_items; + for(int j = r2.top() / m_chunkSizeVer; j <= (r2.bottom() / m_chunkSizeVer); j++) + { + for(int i = r2.left() / m_chunkSizeHor; i <= (r2.right() / m_chunkSizeHor); i++) + { + CanvasChunk *chunk = m_chunkManager.getChunk(i, j); + if(chunk) + { + for(CanvasItemList::ConstIterator it = chunk->list().begin(); it != chunk->list().end(); ++it) + { + if(!drawables.contains(*it)) + drawables.append(*it); + } + } + } + } + + drawables.sort(); + for(CanvasItemList::Iterator it = drawables.begin(); it != drawables.end(); ++it) + (*it)->draw(); + + if(m_drawWindow) + blit(QRect(0, 0, m_width, m_height), false); + + m_dirtyChunks.clear(); + +#ifdef USE_TIMER + kdDebug(26000) << k_funcinfo << " Total time: " << t.elapsed() << endl; +#endif +} + +void KSVGCanvas::update(float zoomFactor) +{ +#ifdef USE_TIMER + QTime t; + t.start(); +#endif + + if(zoomFactor >= 1) + { + int newWidth = static_cast(m_viewportWidth * zoomFactor); + int newHeight = static_cast(m_viewportHeight * zoomFactor); + setRenderBufferSize(newWidth, newHeight); + } + else + fill(); + + // reset clip paths + QDictIterator itr(m_clipPaths); + for(; itr.current(); ++itr) + (*itr)->update(UPDATE_TRANSFORM); + + m_zoom = zoomFactor; + + QWMatrix mtx; + mtx.translate(m_pan.x(), m_pan.y()); + mtx.scale(m_zoom, m_zoom); + + QRect r(0, 0, m_width, m_height); + QRect r2 = mtx.invert().map(r); + + // zoom all items + for(unsigned int i = 0; i < m_items.count(); i++) + m_items.at(i)->update(UPDATE_ZOOM); + + // recalc items + CanvasItemList drawables; + QPtrListIterator it = m_items; + for(int j = r2.top() / m_chunkSizeVer; j <= (r2.bottom() / m_chunkSizeVer); j++) + { + for(int i = r2.left() / m_chunkSizeHor; i <= (r2.right() / m_chunkSizeHor); i++) + { + CanvasChunk *chunk = m_chunkManager.getChunk(i, j); + if(chunk) + { + for(CanvasItemList::ConstIterator it = chunk->list().begin(); it != chunk->list().end(); ++it) + { + if(!drawables.contains(*it)) + drawables.append(*it); + } + } + } + } + + drawables.sort(); + for(CanvasItemList::Iterator it = drawables.begin(); it != drawables.end(); ++it) + (*it)->draw(); + + if(m_drawWindow) + blit(QRect(0, 0, m_width, m_height), false); + + m_dirtyChunks.clear(); + +#ifdef USE_TIMER + kdDebug(26000) << k_funcinfo << " Total time: " << t.elapsed() << endl; +#endif +} + +void KSVGCanvas::reset() +{ + m_items.clear(); + m_chunkManager.clear(); + m_chunksByItem.clear(); + m_dirtyChunks.clear(); + m_pan.setX(0); + m_pan.setY(0); + m_zoom = 1; +} + +void KSVGCanvas::update() +{ +#ifdef USE_TIMER + QTime t; + t.start(); +#endif + + QWMatrix mtx; + mtx.translate(m_pan.x(), m_pan.y()); + mtx.scale(m_zoom, m_zoom); + + // Process dirty chunks + QPtrList chunkList; + CanvasItemList drawables; + for(unsigned int i = 0; i < m_dirtyChunks.count(); i++) + { + CanvasChunk *chunk = m_dirtyChunks[i]; + Q_ASSERT(chunk->isDirty()); + + QRect r = chunk->bbox(); + QRect chunkbox(mtx.map(r.topLeft()), mtx.map(r.bottomRight())); + clear(chunkbox); + chunkList.append(chunk); + + for(CanvasItemList::ConstIterator it = chunk->list().begin(); it != chunk->list().end(); ++it) + { +// kdDebug(26005) << k_funcinfo << " Checking: " << *it << endl; + if(!drawables.contains(*it)) + { +// kdDebug(26005) << k_funcinfo << " Yes, appending to update list!" << endl; + drawables.append(*it); + } + } + + chunk->unsetDirty(); + } + + drawables.sort(); + + // Draw dirty chunks + for(CanvasItemList::Iterator it = drawables.begin(); it != drawables.end(); ++it) + { +// kdDebug(26005) << " Need to redraw dirty : " << (*it) << " with z : " << (*it)->zIndex() << endl; + (*it)->draw(); + } + + // Blit dirty chunks + QPtrListIterator it = chunkList; + for(it.toFirst(); it.current(); ++it) + { + QRect r = (*it)->bbox(); + QRect chunkbox(mtx.map(r.topLeft()), mtx.map(r.bottomRight())); + blit(chunkbox, false); + } + + m_dirtyChunks.clear(); + +#ifdef USE_TIMER + kdDebug(26005) << k_funcinfo << " Total time: " << t.elapsed() << endl; +#endif +} + +CanvasItemList KSVGCanvas::collisions(const QPoint &p, bool exact) const +{ + QWMatrix mtx; + mtx.translate(m_pan.x(), m_pan.y()); + mtx.scale(m_zoom, m_zoom); + + QPoint p2 = mtx.invert().map(p); + if(p2.x() < 0 || p2.y() < 0) + return CanvasItemList(); + + unsigned int x = p2.x() / int(m_chunkSizeHor); + unsigned int y = p2.y() / int(m_chunkSizeVer); + + CanvasItemList result; + CanvasChunk *chunk = m_chunkManager.getChunk(x, y); + if(!chunk) + return result; + + CanvasItemList list = chunk->list(); + if(exact) + { + for(CanvasItemList::Iterator it = list.begin(); it != list.end(); ++it) + { + if((*it)->fillContains(p) || (*it)->strokeContains(p) || (*it)->bbox().contains(p)) + result.append(*it); + } + + return result; + } + else + return list; +} + +void KSVGCanvas::blit(const QRect &rect, bool direct) +{ + if(m_drawWindow && m_width && m_height) + { + // clamp to viewport + int x0 = rect.x(); + x0 = QMAX(x0, 0); + x0 = QMIN(x0, int(m_width - 1)); + + int y0 = rect.y(); + y0 = QMAX(y0, 0); + y0 = QMIN(y0, int(m_height - 1)); + + int x1 = rect.x() + rect.width() + 1; + x1 = QMAX(x1, 0); + x1 = QMIN(x1, int(m_width)); + + int y1 = rect.y() + rect.height() + 1; + y1 = QMAX(y1, 0); + y1 = QMIN(y1, int(m_height)); + + xlib_draw_rgb_image(direct ? m_directWindow->handle() : m_drawWindow->handle(), m_gc, x0, y0, x1 - x0, y1 - y0, XLIB_RGB_DITHER_NONE, m_buffer + (m_width * y0 + x0) * m_nrChannels, m_width * m_nrChannels); + } +} + +void KSVGCanvas::blit() +{ + return blit(QRect(0, 0, m_width, m_height), false); +} + +void KSVGCanvas::ChunkManager::addChunk(CanvasChunk *chunk) +{ + QString key = QString("%1 %2").arg(chunk->x()).arg(chunk->y()); +// kdDebug(26005) << k_funcinfo << "Adding chunk : " << chunk << endl; + m_chunks.insert(key, chunk); +} + +CanvasChunk *KSVGCanvas::ChunkManager::getChunk(short x, short y) const +{ +// kdDebug(26005) << k_funcinfo << "getting chunk from : " << x << ", " << y << endl; + QString key = QString("%1 %2").arg(x).arg(y); + return m_chunks[key]; +} + +void KSVGCanvas::ChunkManager::clear() +{ + m_chunks.clear(); +} + +// vim:ts=4:noet diff --git a/ksvg/core/KSVGCanvas.h b/ksvg/core/KSVGCanvas.h new file mode 100644 index 00000000..7b26997c --- /dev/null +++ b/ksvg/core/KSVGCanvas.h @@ -0,0 +1,190 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 KSVGCANVAS_H +#define KSVGCANVAS_H + +#include +#include +#include +#include +#include +#include + +#include + +namespace KSVG +{ + +class SVGShapeImpl; +class SVGMatrixImpl; +class SVGStylableImpl; +class SVGElementImpl; +class SVGTextElementImpl; +class SVGRectElementImpl; +class SVGLineElementImpl; +class SVGPathElementImpl; +class SVGImageElementImpl; +class SVGCircleElementImpl; +class SVGMarkerElementImpl; +class SVGEllipseElementImpl; +class SVGPolygonElementImpl; +class SVGPolylineElementImpl; +class SVGClipPathElementImpl; + +class CanvasItem; +class CanvasChunk; +class CanvasItemList; +class CanvasClipPath; +class CanvasPaintServer; + +// Must be a QObject to be able to be loaded by KLibLoader... +class KSVGCanvas : public QObject +{ +Q_OBJECT +public: + KSVGCanvas(unsigned int width, unsigned int height); + virtual ~KSVGCanvas(); + + void setViewportDimension(unsigned int w, unsigned int h); + + void setup(QPaintDevice *drawWidget, QPaintDevice *directWindow); + void setup(unsigned char *buffer, unsigned int width = 0, unsigned int height = 0); + + void reset(); + void update(); + void update(float zoomFactor); + void update(const QPoint &panPoint, bool erase = true); + void resize(unsigned int w, unsigned int h); + void retune(unsigned int csh, unsigned int csv); + void invalidate(CanvasItem *item, bool recalc = true); + CanvasItemList collisions(const QPoint &p, bool exact = false) const; + + void setBackgroundColor(const QColor &c) { m_backgroundColor = c; } + void blit(); + void blit(const QRect &rect, bool direct); + + float zoom() const { return m_zoom; } + QPoint pan() const { return m_pan; } + void setPan(const QPoint &pan) { m_pan = pan; } + + int width() const { return m_width; } + int height() const { return m_height; } + + virtual void setRenderBufferSize(int w, int h); + void clipToBuffer(int &x0, int &y0, int &x1, int &y1) const; + + // creating canvas items + virtual CanvasItem *createRectangle(SVGRectElementImpl *rect) = 0; + virtual CanvasItem *createEllipse(SVGEllipseElementImpl *ellipse) = 0; + virtual CanvasItem *createCircle(SVGCircleElementImpl *circle) = 0; + virtual CanvasItem *createLine(SVGLineElementImpl *line) = 0; + virtual CanvasItem *createPolyline(SVGPolylineElementImpl *poly) = 0; + virtual CanvasItem *createPolygon(SVGPolygonElementImpl *poly) = 0; + virtual CanvasItem *createPath(SVGPathElementImpl *path) = 0; + virtual CanvasItem *createClipPath(SVGClipPathElementImpl *clippath) = 0; + virtual CanvasItem *createImage(SVGImageElementImpl *image) = 0; + virtual CanvasItem *createCanvasMarker(SVGMarkerElementImpl *marker) = 0; + virtual CanvasItem *createText(SVGTextElementImpl *text) = 0; + virtual CanvasPaintServer *createPaintServer(SVGElementImpl *pserver) = 0; + + void insert(CanvasItem *item, int z = -1); + void removeItem(CanvasItem *); + + // Enable to have the canvas updated and blitted on item insertion. + void setImmediateUpdate(bool immediateUpdate) { m_immediateUpdate = immediateUpdate; } + bool immediateUpdate() const { return m_immediateUpdate; } + + QPtrList allItems() const { return m_items; } + + unsigned char *renderingBuffer() const { return m_buffer; } + unsigned int nrChannels() const { return m_nrChannels; } + unsigned int rowStride() const { return m_nrChannels * m_width; } + + T2P::Converter *fontContext() { return m_fontContext; } + QPaintDevice *drawWindow() { return m_drawWindow; } + QPaintDevice *directWindow() { return m_directWindow; } + + T2P::FontVisualParams *fontVisualParams(SVGStylableImpl *style) const; + virtual T2P::BezierPath *toBezierPath(CanvasItem *item) const { Q_UNUSED(item); return 0; } + + // Assign z indices to the element and its children, starting with z, and + // return the next z value to be used. + unsigned int setElementItemZIndexRecursive(SVGElementImpl *element, unsigned int z); + +protected: + void addToChunks(CanvasItem *item); + void removeFromChunks(CanvasItem *item); + + void initVars(); + + void fill(); + void clear(const QRect &r); + + virtual void setBuffer(unsigned char *buffer); + +protected: + class ChunkManager + { + public: + ChunkManager() { m_chunks.setAutoDelete(true); } + void addChunk(CanvasChunk *chunk); + CanvasChunk *getChunk(short x, short y) const; + + void clear(); + + private: + QDict m_chunks; + } m_chunkManager; + + QValueList m_dirtyChunks; + + QMap > m_chunksByItem; + QPtrList m_items; + + QDict m_clipPaths; + + unsigned int m_viewportWidth, m_viewportHeight; + int m_width, m_height; + int m_chunkSizeHor, m_chunkSizeVer; + + QPaintDevice *m_drawWindow; + QPaintDevice *m_directWindow; + + float m_zoom; + QPoint m_pan; + + GC m_gc; + + T2P::Converter *m_fontContext; + + unsigned char *m_buffer; + unsigned int m_nrChannels; + + QColor m_backgroundColor; + + bool m_immediateUpdate; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/core/KSVGHelper.cpp b/ksvg/core/KSVGHelper.cpp new file mode 100644 index 00000000..86d111a6 --- /dev/null +++ b/ksvg/core/KSVGHelper.cpp @@ -0,0 +1,92 @@ +/* + Copyright (C) 2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "KSVGHelper.h" + +using namespace KSVG; + +bool KSVGHelper::m_initialised = false; + +int KSVGHelper::m_linearRGBFromsRGB[256]; +int KSVGHelper::m_sRGBFromLinearRGB[256]; + +// Force initialisation of the lookup tables +static KSVGHelper ksvgHelper; + +KSVGHelper::KSVGHelper() +{ + if(!m_initialised) + { + initialise(); + m_initialised = true; + } +} + +void KSVGHelper::initialise() +{ + // Set up linearRGB - sRGB conversion tables + for(int i = 0; i < 256; i++) + { + m_linearRGBFromsRGB[i] = calcLinearRGBFromsRGB(i); + m_sRGBFromLinearRGB[i] = calcSRGBFromLinearRGB(i); + } +} + +int KSVGHelper::calcLinearRGBFromsRGB(int sRGB8bit) +{ + double sRGB = sRGB8bit / 255.0; + double linearRGB; + + if(sRGB <= 0.04045) + linearRGB = sRGB / 12.92; + else + linearRGB = pow((sRGB + 0.055) / 1.055, 2.4); + + return static_cast(linearRGB * 255 + 0.5); +} + +int KSVGHelper::calcSRGBFromLinearRGB(int linearRGB8bit) +{ + double linearRGB = linearRGB8bit / 255.0; + double sRGB; + + if(linearRGB <= 0.0031308) + sRGB = linearRGB * 12.92; + else + sRGB = 1.055 * pow(linearRGB, 1 / 2.4) - 0.055; + + return static_cast(sRGB * 255 + 0.5); +} + +extern "C" +int linearRGBFromsRGB(int sRGB8bit) +{ + return KSVGHelper::linearRGBFromsRGB(sRGB8bit); +} + +extern "C" +int sRGBFromLinearRGB(int linearRGB8bit) +{ + return KSVGHelper::sRGBFromLinearRGB(linearRGB8bit); +} + +// vim:ts=4:noet diff --git a/ksvg/core/KSVGHelper.h b/ksvg/core/KSVGHelper.h new file mode 100644 index 00000000..e310889f --- /dev/null +++ b/ksvg/core/KSVGHelper.h @@ -0,0 +1,144 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 KSVGHelper_H +#define KSVGHelper_H + +#ifdef __cplusplus + +#include +#include +#include "Affine.h" +#include "Point.h" +#include "SVGMatrixImpl.h" + +namespace KSVG +{ + +class KSVGHelper +{ +public: + KSVGHelper(); + + static void matrixToAffine(SVGMatrixImpl *matrix, double affine[6]) + { + affine[0] = matrix->a(); + affine[1] = matrix->b(); + affine[2] = matrix->c(); + affine[3] = matrix->d(); + affine[4] = matrix->e(); + affine[5] = matrix->f(); + } + + static void matrixToAffine(const SVGMatrixImpl *matrix, double affine[6]) + { + KSVGHelper::matrixToAffine(const_cast(matrix), affine); + } + + static void matrixToAffine(const SVGMatrixImpl *matrix, T2P::Affine &affine) + { + KSVGHelper::matrixToAffine(const_cast(matrix), affine.data()); + } + + static void matrixToAffine(SVGMatrixImpl *matrix, T2P::Affine &affine) + { + KSVGHelper::matrixToAffine(matrix, affine.data()); + } + + static QString toColorString(QColor color) + { + int r = color.red(); + int g = color.green(); + int b = color.blue(); + + return "rgb(" + QString::number(r) + "," + QString::number(g) + "," + QString::number(b) + ")"; + } + + static unsigned int toArtColor(const QColor &color) + { + return (qRed(color.rgb()) << 24) | (qGreen(color.rgb()) << 16) | ( qBlue(color.rgb()) << 8) | (qAlpha(color.rgb())); + } + + static unsigned int toArtColor(const QColor &color, short opacity) + { + return (qRed(color.rgb()) << 24) | (qGreen(color.rgb()) << 16) | ( qBlue(color.rgb()) << 8) | (opacity); + } + + static int linearRGBFromsRGB(int sRGB8bit) { return m_linearRGBFromsRGB[sRGB8bit]; } + static int sRGBFromLinearRGB(int linearRGB8bit) { return m_sRGBFromLinearRGB[linearRGB8bit]; } + +private: + static void initialise(); + static int calcLinearRGBFromsRGB(int sRGB8bit); + static int calcSRGBFromLinearRGB(int linearRGB8bit); + + static bool m_initialised; + + static int m_linearRGBFromsRGB[256]; + static int m_sRGBFromLinearRGB[256]; +}; + +typedef T2P::Point KSVGPoint; + +class KSVGPolygon +{ +public: + KSVGPolygon() {} + + void addPoint(const KSVGPoint& point) { m_points.append(point); } + void addPoint(double x, double y) { m_points.append(KSVGPoint(x, y)); } + + KSVGPoint point(unsigned int index) const { return index < m_points.count() ? m_points[index] : KSVGPoint(); } + + unsigned int numPoints() const { return m_points.count(); } + bool isEmpty() const { return m_points.isEmpty(); } + + void clear() { m_points.clear(); } + +private: + QValueVector m_points; +}; + +class KSVGRectangle : public KSVGPolygon +{ +public: + KSVGRectangle() { addPoint(0, 0); addPoint(0, 0); addPoint(0, 0); addPoint(0, 0); } + + // Convenience constructor for an axis-aligned rectangle + KSVGRectangle(double x, double y, double width, double height) + { addPoint(KSVGPoint(x, y)); addPoint(KSVGPoint(x, y + height)); addPoint(KSVGPoint(x + width, y + height)); addPoint(KSVGPoint(x + width, y)); } + +}; +} + +extern "C" +{ +#endif // __cplusplus + +int linearRGBFromsRGB(int sRGB8bit); +int sRGBFromLinearRGB(int linearRGB8bit); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif + +// vim:ts=4:noet diff --git a/ksvg/core/KSVGLoader.cpp b/ksvg/core/KSVGLoader.cpp new file mode 100644 index 00000000..7f7591d7 --- /dev/null +++ b/ksvg/core/KSVGLoader.cpp @@ -0,0 +1,449 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGImageElementImpl.h" + +#include "KSVGLoader.moc" + +using namespace KSVG; + +KSVGLoader::KSVGLoader() : m_data(0) +{ + m_job = 0; +} + +KSVGLoader::~KSVGLoader() +{ +} + +QString KSVGLoader::loadXML(::KURL url) +{ + QString tmpFile; + if(KIO::NetAccess::download(url, tmpFile, 0)) + { + QIODevice *dev = KFilterDev::deviceForFile(tmpFile, "application/x-gzip", true); + QByteArray contents; + if(dev->open(IO_ReadOnly)) + contents = dev->readAll(); + delete dev; + KIO::NetAccess::removeTempFile(tmpFile); + return QString(contents); + } + + return QString::null; +} + +void KSVGLoader::getSVGContent(::KURL url) +{ + if(!url.prettyURL().isEmpty()) + { + if(m_job == 0) + m_job = KIO::get(url, false, false); + + m_job->setAutoErrorHandlingEnabled(true); + + connect(m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this, SLOT(slotData(KIO::Job *, const QByteArray &))); + connect(m_job, SIGNAL(result(KIO::Job *)), this, SLOT(slotResult(KIO::Job *))); + } +} + +void KSVGLoader::newImageJob(SVGImageElementImpl *image, ::KURL baseURL) +{ + if(image && image->fileName().isEmpty()) + { + kdDebug(26001) << "Image Element has no URL!" << endl; + return; + } + + ImageStreamMap *map = new ImageStreamMap(); + map->data = new QByteArray(); + map->imageElement = image; + + KIO::TransferJob *imageJob = KIO::get(::KURL(baseURL, map->imageElement->fileName()), false, false); + connect(imageJob, SIGNAL(data(KIO::Job *, const QByteArray &)), this, SLOT(slotData(KIO::Job *, const QByteArray &))); + connect(imageJob, SIGNAL(result(KIO::Job *)), this, SLOT(slotResult(KIO::Job *))); + + m_imageJobs.insert(imageJob, map); +} + +void KSVGLoader::slotData(KIO::Job *job, const QByteArray &data) +{ + if(job == m_job) + { + QDataStream dataStream(m_data, IO_WriteOnly | IO_Append); + dataStream.writeRawBytes(data.data(), data.size()); + } + else + { + QMap::Iterator it; + for(it = m_imageJobs.begin(); it != m_imageJobs.end(); ++it) + { + if(it.key() == job) + { + QDataStream dataStream(*(it.data())->data, IO_WriteOnly | IO_Append); + dataStream.writeRawBytes(data.data(), data.size()); + break; + } + } + } +} + +void KSVGLoader::slotResult(KIO::Job *job) +{ + if(job == m_job) + { + if(m_job->error() == 0) + { + QString check = static_cast(job)->url().prettyURL(); + if(check.contains(".svgz") || check.contains(".svg.gz")) + { + // decode the gzipped svg and emit it + QIODevice *dev = KFilterDev::device(new QBuffer(m_data), "application/x-gzip"); + dev->open(IO_ReadOnly); + emit gotResult(dev); + } + else + { + m_job = 0; + emit gotResult(new QBuffer(m_data)); + m_data.resize(0); + } + } + } + else if(m_postUrlData.job == job) + { + // Notify that we're done + KJS::List callBackArgs; + callBackArgs.append(*m_postUrlData.status); + + m_postUrlData.status->put(m_postUrlData.exec, KJS::Identifier("success"), KJS::Boolean(true)); + m_postUrlData.callBackFunction->call(m_postUrlData.exec, *m_postUrlData.callBackFunction, callBackArgs); + } + else + { + QMap::Iterator it; + for(it = m_imageJobs.begin(); it != m_imageJobs.end(); ++it) + { + if(it.key() == job) + { + ImageStreamMap *streamMap = it.data(); + + QBuffer buffer(*(streamMap->data)); + + if(buffer.open(IO_ReadOnly)) + { + const char *imageFormat = QImageIO::imageFormat(&buffer); + + if(imageFormat != 0) + { + QImageIO imageIO(&buffer, imageFormat); + + // Gamma correction + imageIO.setGamma(1/0.45454); + + if(imageIO.read()) + { + QImage *image = new QImage(imageIO.image()); + image->detach(); + (streamMap->imageElement)->setImage(image); + } + } + + buffer.close(); + } + + (streamMap->data)->resize(0); + + m_imageJobs.remove(static_cast(job)); + + emit imageReady(streamMap->imageElement); + break; + } + } + } +} + +QString KSVGLoader::getUrl(::KURL url, bool local) +{ + // Security issue: Only retrieve http and https + if(local || (!url.prettyURL().isEmpty()) && ((url.protocol() == "http") || (url.protocol() == "https"))) + return loadXML(url); + + return QString::null; +} + +void KSVGLoader::postUrl(::KURL url, const QByteArray &data, const QString &mimeType, KJS::ExecState *exec, KJS::Object &callBackFunction, KJS::Object &status) +{ + KIO::TransferJob *job = KIO::http_post(url, data, false); + job->addMetaData("content-type", mimeType); + + m_postUrlData.job = job; + m_postUrlData.exec = exec; + m_postUrlData.status = &status; + m_postUrlData.callBackFunction = &callBackFunction; + + connect(job, SIGNAL(result(KIO::Job *)), SLOT(slotResult(KIO::Job *))); +} + +class CharacterDataSearcher : public QXmlDefaultHandler +{ +public: + CharacterDataSearcher(const QString &id) : m_id(id) { } + + virtual bool startDocument() + { + m_foundCount = 0; + return true; + } + + virtual bool startElement(const QString &, const QString &, const QString &qName, const QXmlAttributes &atts) + { + kdDebug(26001) << "CharacterDataSearcher::startElement, qName " << qName << endl; + + int pos = atts.index("id"); + if(pos > -1 && atts.value(pos) == m_id) + { + m_foundCount++; + m_tagFound = qName; + } + + return true; + } + + virtual bool endElement(const QString &, const QString &, const QString &qName) + { + if(m_tagFound == qName && m_foundCount > 0) + { + m_foundCount--; + if(m_foundCount == 0) + return false; // done! + } + + return true; + } + + virtual bool characters(const QString &ch) + { + kdDebug(26001) << "CharacterDataSearcher::characters, read " << ch.latin1() << endl; + + if(m_tagFound != 0) + m_result += ch; + + return true; + } + + QString result() { return m_result; } + +private: + QString m_id, m_result, m_tagFound; + int m_foundCount; +}; + +QString KSVGLoader::getCharacterData(::KURL url, const QString &id) +{ + QXmlSimpleReader reader; + + CharacterDataSearcher searcher(id); + reader.setContentHandler(&searcher); + reader.setErrorHandler(&searcher); + + QString s = loadXML(url); + + QXmlInputSource source; + source.setData(s); + + reader.parse(&source); + + return searcher.result(); +} + + + +class SVGFragmentSearcher : public QXmlDefaultHandler +{ +public: + SVGFragmentSearcher(SVGDocumentImpl *doc, const QString &id, ::KURL url) : m_id(id), m_url(url), m_doc(doc) { } + + virtual bool startDocument() + { + m_result = 0; + m_currentNode = 0; + + return true; + } + + virtual bool startElement(const QString &namespaceURI, const QString &, const QString &qName, const QXmlAttributes &attrs) + { + kdDebug(26001) << "SVGFragmentSearcher::startElement, namespaceURI " << namespaceURI << ", qName " << qName << endl; + bool parse = m_result; + if(!parse) + { + int pos = attrs.index("id"); + if(pos > -1 && attrs.value(pos) == m_id) + parse = true; + } + + if(parse) + { + DOM::Element impl = static_cast(m_doc)->createElementNS(namespaceURI, qName); + SVGElementImpl *newElement = SVGDocumentImpl::createElement(qName, impl, m_doc); + newElement->setViewportElement(m_doc->rootElement()); + + if(m_currentNode) + m_currentNode->appendChild(*newElement); + else + m_result = newElement; + + QXmlAttributes newAttrs; + + for(int i = 0; i < attrs.count(); i++) + { + QString name = attrs.localName(i); + QString value = attrs.value(i); + + if(name == "id") + { + value = "@fragment@" + m_url.prettyURL() + "@" + value; + m_idMap[value] = newElement; + } + else + if(name == "href") + { + value.stripWhiteSpace(); + + if(value.startsWith("#")) + { + value.remove(0, 1); + + // Convert the id to its mangled version. + QString id = "@fragment@" + m_url.prettyURL() + "@" + value; + + if(m_idMap.contains(id)) + { + // This is a local reference to an element within the fragment. + // Just convert the href. + value = id; + } + else + { + // This is a local reference to an id outside of the fragment. + // Change it into an absolute href. + value = m_url.prettyURL() + "#" + value; + } + } + } + + newAttrs.append(attrs.qName(i), attrs.uri(i), attrs.localName(i), value); + } + + newElement->setAttributes(newAttrs); + m_currentNode = newElement; + } + + return true; + } + + virtual bool endElement(const QString &, const QString &, const QString &) + { + if(m_result) + { + m_parentNode = m_currentNode->parentNode(); + + if(m_parentNode.isNull()) + return false; // done! + + m_currentNode = &m_parentNode; + } + + return true; + } + + virtual bool characters(const QString &ch) + { + kdDebug(26001) << "SVGFragmentSearcher::characters, read " << ch.latin1() << endl; + + if(m_result) + { + SVGElementImpl *element = m_result->ownerDoc()->getElementFromHandle(m_currentNode->handle()); + if(element) + { + QString t = ch; + + SVGLangSpaceImpl *langSpace = dynamic_cast(element); + if(langSpace) + t = langSpace->handleText(ch); + + if(!t.isEmpty()) + { + DOM::Text impl = static_cast(m_result->ownerDoc())->createTextNode(t); + element->appendChild(impl); + } + } + } + + return true; + } + + SVGElementImpl *result() { return m_result; } + +private: + QString m_id; + ::KURL m_url; + + SVGDocumentImpl *m_doc; + SVGElementImpl *m_result; + + DOM::Node *m_currentNode, m_parentNode; + QMap m_idMap; +}; + +SVGElementImpl *KSVGLoader::getSVGFragment(::KURL url, SVGDocumentImpl *doc, const QString &id) +{ + QXmlSimpleReader reader; + + kdDebug(26001) << "getSVGFragment: " << url.prettyURL() << "#" << id << endl; + SVGFragmentSearcher searcher(doc, id, url); + reader.setContentHandler(&searcher); + reader.setErrorHandler(&searcher); + + QString s = loadXML(url); + + QXmlInputSource source; + source.setData(s); + + reader.parse(&source); + + return searcher.result(); +} + +// vim:ts=4:noet diff --git a/ksvg/core/KSVGLoader.h b/ksvg/core/KSVGLoader.h new file mode 100644 index 00000000..d0418411 --- /dev/null +++ b/ksvg/core/KSVGLoader.h @@ -0,0 +1,92 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 KSVGLoader_H +#define KSVGLoader_H + +#include + +class KURL; + +namespace KIO +{ + class Job; + class TransferJob; +} + +namespace KJS +{ + class Object; + class ExecState; +} + +namespace KSVG +{ + +struct ImageStreamMap; + +typedef struct +{ + KIO::Job *job; + KJS::ExecState *exec; + KJS::Object *callBackFunction, *status; +} PostUrlData; + +class SVGImageElementImpl; +class SVGElementImpl; +class SVGDocumentImpl; +class KSVGLoader : public QObject +{ +Q_OBJECT +public: + KSVGLoader(); + ~KSVGLoader(); + + void getSVGContent(::KURL url); + void newImageJob(SVGImageElementImpl *impl, ::KURL url); + + static QString getUrl(::KURL url, bool local = false); + void postUrl(::KURL url, const QByteArray &data, const QString &mimeType, KJS::ExecState *exec, KJS::Object &callBackFunction, KJS::Object &status); + static QString getCharacterData(::KURL url, const QString &id); + static SVGElementImpl *getSVGFragment(::KURL, SVGDocumentImpl *doc, const QString &id); + +signals: + void gotResult(QIODevice *); + void imageReady(SVGImageElementImpl *); + +private slots: + void slotData(KIO::Job *, const QByteArray &); + void slotResult(KIO::Job *); + +private: + static QString loadXML(::KURL); + + PostUrlData m_postUrlData; + + QByteArray m_data; + KIO::TransferJob *m_job; + QMap m_imageJobs; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/core/KSVGReader.cc b/ksvg/core/KSVGReader.cc new file mode 100644 index 00000000..dd73e420 --- /dev/null +++ b/ksvg/core/KSVGReader.cc @@ -0,0 +1,500 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include +#include +#include +#include +#include +#include "KSVGReader.moc" +#include "SVGSVGElementImpl.h" +#include "SVGViewSpecImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGMatrixImpl.h" +#include "SVGShapeImpl.h" +#include "SVGLengthImpl.h" +#include "SVGImageElementImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGUseElementImpl.h" + +namespace KSVG +{ + +class Helper +{ +public: + static Helper *self(KSVGReader *reader = 0); + + void destroy(); + + void setFit(bool bFit = true) { m_bFit = bFit; } + bool fit() { return m_bFit; } + + SVGDocumentImpl *doc() const { return m_reader->doc(); } + KSVGCanvas *canvas() const { return m_reader->canvas(); } + + void addSVGElement(SVGSVGElementImpl *one, DOM::NodeImpl *two) { m_svgMap.insert(two, one); } + SVGSVGElementImpl *nextSVGElement(SVGElementImpl *elem); + SVGSVGElementImpl *nextSVGElement(DOM::Node elem); + void setFinished(bool error, const QString &errorDesc = "") { m_reader->setFinished(error, errorDesc); } + + // Error handling + void setErrorDescription(const QString &err) { m_errorDesc = err; } + QString errorDescription() { return m_errorDesc; } + bool hasError() const { return !m_errorDesc.isEmpty(); } + + bool getURLMode() const { return m_getURLMode; } + void setGetURLMode(bool mode) { m_getURLMode = mode; } + + QString SVGFragmentId() const { return m_SVGFragmentId; } + void setSVGFragmentId(const QString &SVGFragmentId) { m_SVGFragmentId = SVGFragmentId; } + +protected: + Helper(KSVGReader *reader); + +private: + Helper(); + Helper(const Helper &rhs); + Helper &operator=(const Helper &rhs); + + static Helper *m_instance; + QMap m_svgMap; + KSVGReader *m_reader; + bool m_bFit; + bool m_getURLMode; + QString m_errorDesc; + QString m_SVGFragmentId; +}; + +class InputHandler : public QXmlDefaultHandler +{ +public: + virtual bool startDocument(); + virtual bool endDocument(); + virtual bool startElement(const QString &namespaceURI, + const QString &localName, + const QString &qName, + const QXmlAttributes &atts); + virtual bool endElement(const QString &namespaceURI, + const QString &localName, + const QString &qName); + virtual bool characters(const QString &ch); + virtual bool warning(const QXmlParseException &e); + virtual bool error(const QXmlParseException &e); + virtual bool fatalError(const QXmlParseException &e); + +private: + DOM::Node *m_rootNode; + DOM::Node *m_currentNode; + DOM::Node m_parentNode; + + bool m_noRendering, m_progressive; +}; + +} + +using namespace KSVG; + +Helper *Helper::m_instance = 0; + +Helper::Helper(KSVGReader *reader) +{ + m_reader = reader; +} + +Helper *Helper::self(KSVGReader *reader) +{ + if(m_instance && reader != 0) + m_instance->m_reader = reader; + if(!m_instance) + { + Q_ASSERT(reader != 0); + m_instance = new Helper(reader); + } + + return m_instance; +} + +void Helper::destroy() +{ + m_svgMap.clear(); +} + +SVGSVGElementImpl *Helper::nextSVGElement(SVGElementImpl *elem) +{ + return nextSVGElement(*elem); +} + +SVGSVGElementImpl *Helper::nextSVGElement(DOM::Node elem) +{ + DOM::Node foundSVG; + DOM::Node shape = elem.parentNode(); + + for(; !shape.isNull(); shape = shape.parentNode()) + { + if(reinterpret_cast(shape).nodeName() == "svg") + { + foundSVG = shape; + break; + } + } + + SVGSVGElementImpl *svg = m_svgMap[foundSVG.handle()]; + return svg; +} + +bool InputHandler::startDocument() +{ + m_rootNode = 0; + m_currentNode = 0; + m_noRendering = false; + + KSimpleConfig config("ksvgpluginrc"); + config.setGroup("Rendering"); + m_progressive = config.readBoolEntry("ProgressiveRendering", true); + + if(Helper::self()->canvas()) + Helper::self()->canvas()->setImmediateUpdate(m_progressive); + + return true; +} + +bool InputHandler::endDocument() +{ + Helper::self()->setFinished(false); + if (Helper::self()->canvas()) + Helper::self()->canvas()->setImmediateUpdate(false); + + return true; +} + +bool InputHandler::characters(const QString &ch) +{ + kdDebug(26001) << "InputHandler::characters, read " << ch << endl; + + if(ch.simplifyWhiteSpace().isEmpty()) + return true; + + QString t = ch; + + SVGSVGElementImpl *root = Helper::self()->nextSVGElement(*m_currentNode); + if(root) + { + SVGElementImpl *element = root->ownerDoc()->getElementFromHandle(m_currentNode->handle()); + SVGLangSpaceImpl *langSpace = dynamic_cast(element); + + if(langSpace) + t = langSpace->handleText(ch); + } + + if(!t.isEmpty()) + { + DOM::Text impl = static_cast(Helper::self()->doc())->createTextNode(t); + m_currentNode->appendChild(impl); + } + + return true; +} + +bool InputHandler::startElement(const QString &namespaceURI, const QString &, const QString &qName, const QXmlAttributes &attrs) +{ + kdDebug(26001) << "InputHandler::startElement, namespaceURI " << namespaceURI << " qName " << qName << endl; + + SVGElementImpl *newElement = 0; + SVGSVGElementImpl *svg = 0; + + if(qName == "svg") + { + DOM::Element impl = static_cast(Helper::self()->doc())->createElementNS(namespaceURI, qName); + newElement = SVGDocumentImpl::createElement(qName, impl, Helper::self()->doc()); + svg = dynamic_cast(newElement); + + Helper::self()->addSVGElement(svg, impl.handle()); + + // Need this before we can find our ownerSVGElement (AP) + if(m_currentNode != 0) + m_currentNode->appendChild(*svg); + else + // TODO: Those set/get attribute callls have NO effect anymore + // Convert to the new system, Rob? (Niko) + { + if(Helper::self()->fit()) + { // handle fitting of svg into small drawing area(thumb) + // TODO : aspectratio? and what about svgs that dont provide width and height? + if(svg->getAttribute("viewBox").string().isEmpty()) + { + SVGLengthImpl *width = SVGSVGElementImpl::createSVGLength(); + SVGLengthImpl *height = SVGSVGElementImpl::createSVGLength(); + width->setValueAsString(svg->getAttribute("width").string()); + height->setValueAsString(svg->getAttribute("height").string()); + QString viewbox = QString("0 0 %1 %2").arg(width->value()).arg(height->value()); + //kdDebug(26001) << "VIEWBOX : " << viewbox.latin1() << endl; + svg->setAttribute("viewBox", viewbox); + width->deref(); + height->deref(); + } + svg->setAttribute("width", QString::number(Helper::self()->canvas()->width())); + svg->setAttribute("height", QString::number(Helper::self()->canvas()->height())); + } + + if(!Helper::self()->SVGFragmentId().isEmpty()) + { + if(svg->currentView()->parseViewSpec(Helper::self()->SVGFragmentId())) + svg->setUseCurrentView(true); + } + } + + if(m_rootNode == 0) + { + Helper::self()->doc()->appendChild(*svg); + Helper::self()->doc()->setRootElement(svg); + + m_rootNode = svg; + } + } + else + { + if(!m_rootNode && !Helper::self()->getURLMode()) + { + Helper::self()->setErrorDescription(i18n("A legal svg document requires a root element")); + return false; + } + + DOM::Element impl = static_cast(Helper::self()->doc())->createElementNS(namespaceURI, qName); + newElement = SVGDocumentImpl::createElement(qName, impl, Helper::self()->doc()); + + // m_currentNode == 0 if we are dynamically extending the dom (parsexml...) + // and the file doesn't have a root element + if(m_currentNode != 0) + m_currentNode->appendChild(*newElement); + else + Helper::self()->doc()->appendChild(*newElement); + + // Special logics: + if(qName == "switch" || qName == "pattern" || qName == "mask") + m_noRendering = true; + } + + newElement->setOwnerSVGElement(Helper::self()->nextSVGElement(newElement)); + newElement->setViewportElement(newElement->ownerSVGElement()); + + newElement->setAttributes(attrs); + + if(svg && svg->ownerSVGElement() == 0) + { + SVGImageElementImpl *parentImage = Helper::self()->doc()->parentImage(); + + if(parentImage) + { + // We're being displayed in a document via an 'image' element. Set + // us up to fit into it's rectangle. + parentImage->setupSVGElement(svg); + } + } + + SVGLocatableImpl *locatable = dynamic_cast(newElement); + + if(locatable) + { + // Set up the cached screenCTM + SVGLocatableImpl *locatableParent = 0; + DOM::Node parentNode = newElement->parentNode(); + + if(!parentNode.isNull()) + { + SVGElementImpl *parent = Helper::self()->doc()->getElementFromHandle(parentNode.handle()); + + if(parent) + locatableParent = dynamic_cast(parent); + } + + SVGMatrixImpl *parentMatrix = 0; + + if(locatableParent) + parentMatrix = locatableParent->getScreenCTM(); + else + parentMatrix = SVGSVGElementImpl::createSVGMatrix(); + + locatable->updateCachedScreenCTM(parentMatrix); + parentMatrix->deref(); + } + + m_currentNode = newElement; + return !Helper::self()->hasError(); +} + +bool InputHandler::endElement(const QString &, const QString &, const QString &qName) +{ + kdDebug(26001) << "InputHandler::endElement, qName " << qName << endl; + + bool haveCanvas = Helper::self()->canvas(); + + SVGSVGElementImpl *root = Helper::self()->nextSVGElement(*m_currentNode); + SVGElementImpl *element = root ? root->ownerDoc()->getElementFromHandle(m_currentNode->handle()) : Helper::self()->doc()->getElementFromHandle(m_currentNode->handle()); + SVGShapeImpl *shape = dynamic_cast(element); + SVGTestsImpl *tests = dynamic_cast(element); + SVGStylableImpl *style = dynamic_cast(element); + + if(qName != "script" && !m_noRendering && !Helper::self()->getURLMode()) + { + if(!root) + { + if(haveCanvas) + { + if(!m_progressive) + Helper::self()->canvas()->update(); + + Helper::self()->canvas()->blit(); + + QValueList forwardReferencingUseElements = Helper::self()->doc()->forwardReferencingUseElements(); + + if(!forwardReferencingUseElements.isEmpty()) + { + // Create the elements again now that we have parsed the whole document. + QValueList::iterator it; + + Helper::self()->canvas()->setImmediateUpdate(false); + + for(it = forwardReferencingUseElements.begin(); it != forwardReferencingUseElements.end(); it++) + (*it)->createItem(Helper::self()->canvas()); + + // The newly created items will need to be moved into their correct z-order positions. + Helper::self()->doc()->resortZIndicesOnFinishedLoading(); + } + } + + return true; // we have reached the bottom + } + + if(haveCanvas && (tests ? tests->ok() : true)) + { + if((shape && !shape->isContainer()) || (!shape && element)) + element->createItem(); + } + } + + // Special logics: + if(qName == "switch" || qName == "pattern" || qName == "mask") + { + m_noRendering = false; + bool ok = tests ? tests->ok() : true; + + if(haveCanvas && element && style && ok && style->getDisplay() && style->getVisible() && qName == "pattern" || (shape && shape->directRender())) + element->createItem(); + } + + m_parentNode = m_currentNode->parentNode(); // this is needed since otherwise we get temporary vars + m_currentNode = &m_parentNode; + + return true; +} + +bool InputHandler::warning(const QXmlParseException &e) +{ + kdDebug(26001) << "[" << e.lineNumber() << ":" << e.columnNumber() << "]: WARNING: " << e.message() << endl; + return true; +} + +bool InputHandler::error(const QXmlParseException &e) +{ + kdDebug(26001) << "[" << e.lineNumber() << ":" << e.columnNumber() << "]: ERROR: " << e.message() << endl; + return true; +} + +bool InputHandler::fatalError(const QXmlParseException &e) +{ + QString error; + + if(Helper::self()->hasError()) + { + error = Helper::self()->errorDescription(); + Helper::self()->setErrorDescription(QString::null); + } + else + error = QString("[%1:%2]: FATAL ERROR: %3").arg(e.lineNumber()).arg(e.columnNumber()).arg(e.message()); + + kdDebug(26001) << "InputHandler::fatalError, " << error << endl; + + Helper::self()->setFinished(true, error); + return true; +} + +struct KSVGReader::Private +{ + QXmlSimpleReader *reader; + InputHandler *inputHandler; + SVGDocumentImpl *doc; + KSVGCanvas *canvas; +}; + +KSVGReader::KSVGReader(SVGDocumentImpl *doc, KSVGCanvas *canvas, ParsingArgs args) : QObject(), d(new Private) +{ + d->doc = doc; + d->canvas = canvas; + + d->reader = new QXmlSimpleReader(); + d->inputHandler = new InputHandler(); + + Helper::self(this); + Helper::self()->setFit(args.fit); + Helper::self()->setGetURLMode(args.getURLMode); + Helper::self()->setSVGFragmentId(args.SVGFragmentId); + + d->reader->setContentHandler(d->inputHandler); + d->reader->setErrorHandler(d->inputHandler); +} + +KSVGReader::~KSVGReader() +{ + Helper::self()->destroy(); + + delete d->reader; + delete d->inputHandler; + delete d; +} + +void KSVGReader::parse(QXmlInputSource *source) +{ + d->reader->parse(source); +} + +void KSVGReader::finishParsing(bool, const QString &errorDesc) +{ + Helper::self()->setErrorDescription(errorDesc); +} + +void KSVGReader::setFinished(bool error, const QString &errorDesc) +{ + kdDebug(26001) << "KSVGReader::setFinished" << endl; + emit finished(error, errorDesc); +} + +SVGDocumentImpl *KSVGReader::doc() +{ + return d->doc; +} + +KSVG::KSVGCanvas *KSVGReader::canvas() +{ + return d->canvas; +} + +// vim:ts=4:noet diff --git a/ksvg/core/KSVGReader.h b/ksvg/core/KSVGReader.h new file mode 100644 index 00000000..722720e1 --- /dev/null +++ b/ksvg/core/KSVGReader.h @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 KSVGReader_H +#define KSVGReader_H + +#include +#include + +namespace KSVG +{ + +class SVGDocumentImpl; +class KSVGReader : public QObject +{ +Q_OBJECT +public: + struct ParsingArgs + { + bool fit; + bool getURLMode; + + QString SVGFragmentId; + }; + + KSVGReader(SVGDocumentImpl *doc, KSVGCanvas *canvas, ParsingArgs args); + virtual ~KSVGReader(); + + void parse(QXmlInputSource *source); + void finishParsing(bool, const QString &); + +signals: + void finished(bool, const QString &); + +protected: + friend class Helper; + + SVGDocumentImpl *doc(); + KSVGCanvas *canvas(); + + void setFinished(bool error, const QString &errorDesc = 0); + +private: + struct Private; + Private *d; +}; + +} + +#endif diff --git a/ksvg/core/KSVGTextChunk.cpp b/ksvg/core/KSVGTextChunk.cpp new file mode 100644 index 00000000..b8eddcad --- /dev/null +++ b/ksvg/core/KSVGTextChunk.cpp @@ -0,0 +1,69 @@ +/* + Copyright (C) 2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 "SVGTextContentElementImpl.h" +#include "SVGTextPositioningElementImpl.h" +#include "KSVGTextChunk.h" + +using namespace KSVG; + +// Text chunks (class to store text data) +KSVGTextChunk::KSVGTextChunk() +{ +} + +KSVGTextChunk::~KSVGTextChunk() +{ +} + +unsigned int KSVGTextChunk::count() const +{ + return m_text.count(); +} + +QString KSVGTextChunk::getText(unsigned int index) const +{ + return m_text[index]; +} + +SVGTextPositioningElementImpl *KSVGTextChunk::getTextElement(unsigned int index) +{ + SVGTextContentElementImpl *content = getTextContentElement(index); + return dynamic_cast(content); +} + +SVGTextContentElementImpl *KSVGTextChunk::getTextContentElement(unsigned int index) +{ + return m_textElements.at(index); +} + +void KSVGTextChunk::clear() +{ + m_text.clear(); + m_textElements.clear(); +} + +void KSVGTextChunk::addText(const QString &text, SVGTextContentElementImpl *textElement) +{ + m_text.append(text); + m_textElements.append(textElement); +} + +// vim:ts=4:noet diff --git a/ksvg/core/KSVGTextChunk.h b/ksvg/core/KSVGTextChunk.h new file mode 100644 index 00000000..d684087a --- /dev/null +++ b/ksvg/core/KSVGTextChunk.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 KSVGTEXTCHUNK_H +#define KSVGTEXTCHUNK_H + +#include + +namespace KSVG +{ + +class SVGTextContentElementImpl; +class SVGTextPositioningElementImpl; +class KSVGTextChunk +{ +public: + KSVGTextChunk(); + ~KSVGTextChunk(); + + unsigned int count() const; + QString getText(unsigned int index) const; + SVGTextPositioningElementImpl *getTextElement(unsigned int index); + SVGTextContentElementImpl *getTextContentElement(unsigned int index); + + void clear(); + void addText(const QString &text, SVGTextContentElementImpl *textElement); + +private: + QStringList m_text; + QPtrList m_textElements; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/core/Makefile.am b/ksvg/core/Makefile.am new file mode 100644 index 00000000..e1867428 --- /dev/null +++ b/ksvg/core/Makefile.am @@ -0,0 +1,16 @@ +noinst_LTLIBRARIES = libksvgcore.la + +libksvgcore_la_SOURCES = KSVGLoader.cpp KSVGCanvas.cpp KSVGReader.cc KSVGTextChunk.cpp CanvasFactory.cpp CanvasItems.cpp KSVGHelper.cpp DocumentFactory.cpp +libksvgcore_la_METASOURCES = AUTO + +servicetypedir = $(kde_servicetypesdir) +servicetype_DATA = ksvgrenderer.desktop + +ksvginclude_HEADERS = KSVGCanvas.h CanvasItems.h CanvasItem.h CanvasFactory.h DocumentFactory.h +ksvgincludedir = $(includedir)/ksvg + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) +INCLUDES = $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) -I$(top_srcdir)/ksvg/dom -I$(top_srcdir)/ksvg/impl -I$(top_srcdir)/ksvg/ecma -I$(top_srcdir)/ksvg/impl/libs/art_support -I$(top_srcdir)/ksvg/impl/libs/libtext2path/src $(all_includes) + +KDE_OPTIONS = nofinal + diff --git a/ksvg/core/ksvgrenderer.desktop b/ksvg/core/ksvgrenderer.desktop new file mode 100644 index 00000000..f9307621 --- /dev/null +++ b/ksvg/core/ksvgrenderer.desktop @@ -0,0 +1,56 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=KSVG/Renderer +X-KDE-Derived= +Comment=KSVG Rendering Backend +Comment[ar]=خلفية رسم KSVG +Comment[bs]=KSVG renderiranje +Comment[ca]=Representació en segon pla de KSVG +Comment[cs]=Vykreslovací nástroj KSVG +Comment[cy]=Ôl-wyneb Llunio KSVG +Comment[da]=Underliggende program for KSVG-visning +Comment[de]=KSVG-Darstellungsmodul +Comment[el]=Σύστημα υποστήριξης αποτύπωσης του KSVG +Comment[es]=Motor de procesado de KSVG +Comment[et]=KSVG renderdamise taustarakendus +Comment[eu]=KSVG errendatze programa +Comment[fa]=پایانۀ پشتیبانی پرداخت KSVG +Comment[fi]=KSVG-piirtäjän taustaohjelma +Comment[fr]=Moteur de rendu KSVG +Comment[ga]=Inneall Rindreála KSVG +Comment[gl]=Backend de Renderizado KSVG +Comment[he]=מנוע רינדור KSVG +Comment[hi]=के-एसवीजी रेंडरिंग बैकएण्ड +Comment[hu]=KSVG megjelenítőmotor +Comment[is]=KSVG teiknari +Comment[it]=Backend di KSVG per il rendering +Comment[ja]=KSVG レンダリングバックエンド +Comment[kk]=KSVG кескіндеу бағдарламасы +Comment[km]=កម្មវិធី​សម្រាប់​បង្ហាញ KSVG +Comment[lt]=KSVG atkūrimo programinė sąsaja +Comment[ms]=Tepi Belakang Menrealisasi KSVG +Comment[nb]=Modul for KSVG-tegning +Comment[nds]=KSVG-Dorstellhölper +Comment[ne]=KSVG रेन्डरिङ ब्याकइन्ड +Comment[nl]=KSVG weergavecomponent +Comment[nn]=Modul for KSVG-teikning +Comment[pl]=Narzędzie do renderowania KSVG +Comment[pt]=Infra-Estrutura de Desenho KSVG +Comment[pt_BR]=Estrutura de Renderização do KSVG +Comment[ro]=Motorul de randare KSVG +Comment[ru]=Движок прорисовки KSVG +Comment[sk]=Nástroj pre zobrazovanie KSVG +Comment[sl]=Izrisovalnik KSVG +Comment[sr]=KSVG-ов позадински систем за рендеровање +Comment[sr@Latn]=KSVG-ov pozadinski sistem za renderovanje +Comment[sv]=KSVG-uppritningsmodul +Comment[ta]=KSVG வழங்கும் பின் அமைப்பு +Comment[tg]=Лағжандаи тасовироти KSVG +Comment[tr]=KSVG Tarama Arkayüzü +Comment[uk]=Інтерфейс відтворення KSVG +Comment[zh_CN]=KSVG 渲染后端 +Comment[zh_HK]=KSVG 合成後端 +Comment[zh_TW]=KSVG 上色後端介面 + +[PropertyDef::X-KSVG-InternalName] +Type=QString diff --git a/ksvg/data/SVGAElementImpl.lut.h b/ksvg/data/SVGAElementImpl.lut.h new file mode 100644 index 00000000..9ef7a610 --- /dev/null +++ b/ksvg/data/SVGAElementImpl.lut.h @@ -0,0 +1,20 @@ +/* Automatically generated from impl/SVGAElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGAElementImpl__s_hashTableStrings[] = { + "\0" + "target\0" +}; + + +static const struct HashEntry SVGAElementImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 1, SVGAElementImpl::Target, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGAElementImpl::s_hashTable = { 2, 2, SVGAElementImpl__s_hashTableEntries, 2, SVGAElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGAngleImpl.lut.h b/ksvg/data/SVGAngleImpl.lut.h new file mode 100644 index 00000000..b57f44e1 --- /dev/null +++ b/ksvg/data/SVGAngleImpl.lut.h @@ -0,0 +1,77 @@ +/* Automatically generated from impl/SVGAngleImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGAngleImpl__s_hashTableStrings[] = { + "\0" + "valueInSpecifiedUnits\0" + "valueAsString\0" + "unitType\0" + "value\0" +}; + + +static const struct HashEntry SVGAngleImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 46, SVGAngleImpl::Value, DontDelete, 0, 5 }, + { 23, SVGAngleImpl::ValueAsString, DontDelete, 0, -1 }, + { 1, SVGAngleImpl::ValueInSpecifiedUnits, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 37, SVGAngleImpl::UnitType, DontDelete, 0, -1 } +}; + +const struct HashTable SVGAngleImpl::s_hashTable = { 2, 6, SVGAngleImpl__s_hashTableEntries, 5, SVGAngleImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGAngleImplProto__s_hashTableStrings[] = { + "\0" + "convertToSpecifiedUnits\0" + "newValueSpecifiedUnits\0" +}; + + +static const struct HashEntry SVGAngleImplProto__s_hashTableEntries[] = { + { 1, SVGAngleImpl::ConvertToSpecifiedUnits, DontDelete|Function, 1, -1 }, + { 25, SVGAngleImpl::NewValueSpecifiedUnits, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGAngleImplProto::s_hashTable = { 2, 3, SVGAngleImplProto__s_hashTableEntries, 3, SVGAngleImplProto__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGAngleImplConstructor__s_hashTableStrings[] = { + "\0" + "SVG_ANGLETYPE_UNSPECIFIED\0" + "SVG_ANGLETYPE_UNKNOWN\0" + "SVG_ANGLETYPE_GRAD\0" + "SVG_ANGLETYPE_DEG\0" + "SVG_ANGLETYPE_RAD\0" +}; + + +static const struct HashEntry SVGAngleImplConstructor__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 1, KSVG::SVG_ANGLETYPE_UNSPECIFIED, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 86, KSVG::SVG_ANGLETYPE_RAD, DontDelete|ReadOnly, 0, 7 }, + { 49, KSVG::SVG_ANGLETYPE_GRAD, DontDelete|ReadOnly, 0, -1 }, + { 27, KSVG::SVG_ANGLETYPE_UNKNOWN, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 68, KSVG::SVG_ANGLETYPE_DEG, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGAngleImplConstructor::s_hashTable = { 2, 8, SVGAngleImplConstructor__s_hashTableEntries, 7, SVGAngleImplConstructor__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGAnimatedAngleImpl.lut.h b/ksvg/data/SVGAnimatedAngleImpl.lut.h new file mode 100644 index 00000000..8635120a --- /dev/null +++ b/ksvg/data/SVGAnimatedAngleImpl.lut.h @@ -0,0 +1,22 @@ +/* Automatically generated from impl/SVGAnimatedAngleImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGAnimatedAngleImpl__s_hashTableStrings[] = { + "\0" + "animVal\0" + "baseVal\0" +}; + + +static const struct HashEntry SVGAnimatedAngleImpl__s_hashTableEntries[] = { + { 9, SVGAnimatedAngleImpl::BaseVal, DontDelete|ReadOnly, 0, -1 }, + { 1, SVGAnimatedAngleImpl::AnimVal, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGAnimatedAngleImpl::s_hashTable = { 2, 3, SVGAnimatedAngleImpl__s_hashTableEntries, 3, SVGAnimatedAngleImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGAnimatedBooleanImpl.lut.h b/ksvg/data/SVGAnimatedBooleanImpl.lut.h new file mode 100644 index 00000000..928b3f0f --- /dev/null +++ b/ksvg/data/SVGAnimatedBooleanImpl.lut.h @@ -0,0 +1,22 @@ +/* Automatically generated from impl/SVGAnimatedBooleanImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGAnimatedBooleanImpl__s_hashTableStrings[] = { + "\0" + "animVal\0" + "baseVal\0" +}; + + +static const struct HashEntry SVGAnimatedBooleanImpl__s_hashTableEntries[] = { + { 9, SVGAnimatedBooleanImpl::BaseVal, DontDelete, 0, -1 }, + { 1, SVGAnimatedBooleanImpl::AnimVal, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGAnimatedBooleanImpl::s_hashTable = { 2, 3, SVGAnimatedBooleanImpl__s_hashTableEntries, 3, SVGAnimatedBooleanImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGAnimatedEnumerationImpl.lut.h b/ksvg/data/SVGAnimatedEnumerationImpl.lut.h new file mode 100644 index 00000000..b9a48bde --- /dev/null +++ b/ksvg/data/SVGAnimatedEnumerationImpl.lut.h @@ -0,0 +1,22 @@ +/* Automatically generated from impl/SVGAnimatedEnumerationImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGAnimatedEnumerationImpl__s_hashTableStrings[] = { + "\0" + "animVal\0" + "baseVal\0" +}; + + +static const struct HashEntry SVGAnimatedEnumerationImpl__s_hashTableEntries[] = { + { 9, SVGAnimatedEnumerationImpl::BaseVal, DontDelete, 0, -1 }, + { 1, SVGAnimatedEnumerationImpl::AnimVal, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGAnimatedEnumerationImpl::s_hashTable = { 2, 3, SVGAnimatedEnumerationImpl__s_hashTableEntries, 3, SVGAnimatedEnumerationImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGAnimatedIntegerImpl.lut.h b/ksvg/data/SVGAnimatedIntegerImpl.lut.h new file mode 100644 index 00000000..91934787 --- /dev/null +++ b/ksvg/data/SVGAnimatedIntegerImpl.lut.h @@ -0,0 +1,22 @@ +/* Automatically generated from impl/SVGAnimatedIntegerImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGAnimatedIntegerImpl__s_hashTableStrings[] = { + "\0" + "animVal\0" + "baseVal\0" +}; + + +static const struct HashEntry SVGAnimatedIntegerImpl__s_hashTableEntries[] = { + { 9, SVGAnimatedIntegerImpl::BaseVal, DontDelete, 0, -1 }, + { 1, SVGAnimatedIntegerImpl::AnimVal, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGAnimatedIntegerImpl::s_hashTable = { 2, 3, SVGAnimatedIntegerImpl__s_hashTableEntries, 3, SVGAnimatedIntegerImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGAnimatedLengthImpl.lut.h b/ksvg/data/SVGAnimatedLengthImpl.lut.h new file mode 100644 index 00000000..b969bf35 --- /dev/null +++ b/ksvg/data/SVGAnimatedLengthImpl.lut.h @@ -0,0 +1,22 @@ +/* Automatically generated from impl/SVGAnimatedLengthImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGAnimatedLengthImpl__s_hashTableStrings[] = { + "\0" + "animVal\0" + "baseVal\0" +}; + + +static const struct HashEntry SVGAnimatedLengthImpl__s_hashTableEntries[] = { + { 9, SVGAnimatedLengthImpl::BaseVal, DontDelete|ReadOnly, 0, -1 }, + { 1, SVGAnimatedLengthImpl::AnimVal, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGAnimatedLengthImpl::s_hashTable = { 2, 3, SVGAnimatedLengthImpl__s_hashTableEntries, 3, SVGAnimatedLengthImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGAnimatedLengthListImpl.lut.h b/ksvg/data/SVGAnimatedLengthListImpl.lut.h new file mode 100644 index 00000000..463d834d --- /dev/null +++ b/ksvg/data/SVGAnimatedLengthListImpl.lut.h @@ -0,0 +1,22 @@ +/* Automatically generated from impl/SVGAnimatedLengthListImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGAnimatedLengthListImpl__s_hashTableStrings[] = { + "\0" + "animVal\0" + "baseVal\0" +}; + + +static const struct HashEntry SVGAnimatedLengthListImpl__s_hashTableEntries[] = { + { 9, SVGAnimatedLengthListImpl::BaseVal, DontDelete|ReadOnly, 0, -1 }, + { 1, SVGAnimatedLengthListImpl::AnimVal, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGAnimatedLengthListImpl::s_hashTable = { 2, 3, SVGAnimatedLengthListImpl__s_hashTableEntries, 3, SVGAnimatedLengthListImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGAnimatedNumberImpl.lut.h b/ksvg/data/SVGAnimatedNumberImpl.lut.h new file mode 100644 index 00000000..7563430b --- /dev/null +++ b/ksvg/data/SVGAnimatedNumberImpl.lut.h @@ -0,0 +1,22 @@ +/* Automatically generated from impl/SVGAnimatedNumberImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGAnimatedNumberImpl__s_hashTableStrings[] = { + "\0" + "animVal\0" + "baseVal\0" +}; + + +static const struct HashEntry SVGAnimatedNumberImpl__s_hashTableEntries[] = { + { 9, SVGAnimatedNumberImpl::BaseVal, DontDelete, 0, -1 }, + { 1, SVGAnimatedNumberImpl::AnimVal, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGAnimatedNumberImpl::s_hashTable = { 2, 3, SVGAnimatedNumberImpl__s_hashTableEntries, 3, SVGAnimatedNumberImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGAnimatedNumberListImpl.lut.h b/ksvg/data/SVGAnimatedNumberListImpl.lut.h new file mode 100644 index 00000000..e73471fe --- /dev/null +++ b/ksvg/data/SVGAnimatedNumberListImpl.lut.h @@ -0,0 +1,22 @@ +/* Automatically generated from impl/SVGAnimatedNumberListImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGAnimatedNumberListImpl__s_hashTableStrings[] = { + "\0" + "animVal\0" + "baseVal\0" +}; + + +static const struct HashEntry SVGAnimatedNumberListImpl__s_hashTableEntries[] = { + { 9, SVGAnimatedNumberListImpl::BaseVal, DontDelete|ReadOnly, 0, -1 }, + { 1, SVGAnimatedNumberListImpl::AnimVal, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGAnimatedNumberListImpl::s_hashTable = { 2, 3, SVGAnimatedNumberListImpl__s_hashTableEntries, 3, SVGAnimatedNumberListImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGAnimatedPathDataImpl.lut.h b/ksvg/data/SVGAnimatedPathDataImpl.lut.h new file mode 100644 index 00000000..8e0e8395 --- /dev/null +++ b/ksvg/data/SVGAnimatedPathDataImpl.lut.h @@ -0,0 +1,28 @@ +/* Automatically generated from impl/SVGAnimatedPathDataImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGAnimatedPathDataImpl__s_hashTableStrings[] = { + "\0" + "animatedNormalizedPathSegList\0" + "normalizedPathSegList\0" + "animatedPathSegList\0" + "pathSegList\0" +}; + + +static const struct HashEntry SVGAnimatedPathDataImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 53, SVGAnimatedPathDataImpl::AnimatedPathSegList, DontDelete|ReadOnly, 0, 6 }, + { 0, 0, 0, 0, -1 }, + { 73, SVGAnimatedPathDataImpl::PathSegList, DontDelete|ReadOnly, 0, 5 }, + { 0, 0, 0, 0, -1 }, + { 31, SVGAnimatedPathDataImpl::NormalizedPathSegList, DontDelete|ReadOnly, 0, -1 }, + { 1, SVGAnimatedPathDataImpl::AnimatedNormalizedPathSegList, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGAnimatedPathDataImpl::s_hashTable = { 2, 7, SVGAnimatedPathDataImpl__s_hashTableEntries, 5, SVGAnimatedPathDataImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGAnimatedPointsImpl.lut.h b/ksvg/data/SVGAnimatedPointsImpl.lut.h new file mode 100644 index 00000000..6b48313a --- /dev/null +++ b/ksvg/data/SVGAnimatedPointsImpl.lut.h @@ -0,0 +1,22 @@ +/* Automatically generated from impl/SVGAnimatedPointsImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGAnimatedPointsImpl__s_hashTableStrings[] = { + "\0" + "animatedPoints\0" + "points\0" +}; + + +static const struct HashEntry SVGAnimatedPointsImpl__s_hashTableEntries[] = { + { 16, SVGAnimatedPointsImpl::Points, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGAnimatedPointsImpl::AnimatedPoints, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGAnimatedPointsImpl::s_hashTable = { 2, 3, SVGAnimatedPointsImpl__s_hashTableEntries, 3, SVGAnimatedPointsImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGAnimatedPreserveAspectRatioImpl.lut.h b/ksvg/data/SVGAnimatedPreserveAspectRatioImpl.lut.h new file mode 100644 index 00000000..a681a408 --- /dev/null +++ b/ksvg/data/SVGAnimatedPreserveAspectRatioImpl.lut.h @@ -0,0 +1,22 @@ +/* Automatically generated from impl/SVGAnimatedPreserveAspectRatioImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGAnimatedPreserveAspectRatioImpl__s_hashTableStrings[] = { + "\0" + "animVal\0" + "baseVal\0" +}; + + +static const struct HashEntry SVGAnimatedPreserveAspectRatioImpl__s_hashTableEntries[] = { + { 9, SVGAnimatedPreserveAspectRatioImpl::BaseVal, DontDelete|ReadOnly, 0, -1 }, + { 1, SVGAnimatedPreserveAspectRatioImpl::AnimVal, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGAnimatedPreserveAspectRatioImpl::s_hashTable = { 2, 3, SVGAnimatedPreserveAspectRatioImpl__s_hashTableEntries, 3, SVGAnimatedPreserveAspectRatioImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGAnimatedRectImpl.lut.h b/ksvg/data/SVGAnimatedRectImpl.lut.h new file mode 100644 index 00000000..9a16c899 --- /dev/null +++ b/ksvg/data/SVGAnimatedRectImpl.lut.h @@ -0,0 +1,22 @@ +/* Automatically generated from impl/SVGAnimatedRectImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGAnimatedRectImpl__s_hashTableStrings[] = { + "\0" + "animVal\0" + "baseVal\0" +}; + + +static const struct HashEntry SVGAnimatedRectImpl__s_hashTableEntries[] = { + { 9, SVGAnimatedRectImpl::BaseVal, DontDelete, 0, -1 }, + { 1, SVGAnimatedRectImpl::AnimVal, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGAnimatedRectImpl::s_hashTable = { 2, 3, SVGAnimatedRectImpl__s_hashTableEntries, 3, SVGAnimatedRectImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGAnimatedStringImpl.lut.h b/ksvg/data/SVGAnimatedStringImpl.lut.h new file mode 100644 index 00000000..add905dd --- /dev/null +++ b/ksvg/data/SVGAnimatedStringImpl.lut.h @@ -0,0 +1,22 @@ +/* Automatically generated from impl/SVGAnimatedStringImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGAnimatedStringImpl__s_hashTableStrings[] = { + "\0" + "animVal\0" + "baseVal\0" +}; + + +static const struct HashEntry SVGAnimatedStringImpl__s_hashTableEntries[] = { + { 9, SVGAnimatedStringImpl::BaseVal, DontDelete, 0, -1 }, + { 1, SVGAnimatedStringImpl::AnimVal, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGAnimatedStringImpl::s_hashTable = { 2, 3, SVGAnimatedStringImpl__s_hashTableEntries, 3, SVGAnimatedStringImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGAnimatedTransformListImpl.lut.h b/ksvg/data/SVGAnimatedTransformListImpl.lut.h new file mode 100644 index 00000000..7974a00e --- /dev/null +++ b/ksvg/data/SVGAnimatedTransformListImpl.lut.h @@ -0,0 +1,22 @@ +/* Automatically generated from impl/SVGAnimatedTransformListImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGAnimatedTransformListImpl__s_hashTableStrings[] = { + "\0" + "animVal\0" + "baseVal\0" +}; + + +static const struct HashEntry SVGAnimatedTransformListImpl__s_hashTableEntries[] = { + { 9, SVGAnimatedTransformListImpl::BaseVal, DontDelete|ReadOnly, 0, -1 }, + { 1, SVGAnimatedTransformListImpl::AnimVal, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGAnimatedTransformListImpl::s_hashTable = { 2, 3, SVGAnimatedTransformListImpl__s_hashTableEntries, 3, SVGAnimatedTransformListImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGAnimationElementImpl.lut.h b/ksvg/data/SVGAnimationElementImpl.lut.h new file mode 100644 index 00000000..af8ea0d5 --- /dev/null +++ b/ksvg/data/SVGAnimationElementImpl.lut.h @@ -0,0 +1,94 @@ +/* Automatically generated from impl/SVGAnimationElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGAnimationElementImpl__s_hashTableStrings[] = { + "\0" + "attributeName\0" + "attributeType\0" + "targetElement\0" + "repeatCount\0" + "accumulate\0" + "keySplines\0" + "repeatDur\0" + "additive\0" + "calcMode\0" + "keyTimes\0" + "restart\0" + "values\0" + "begin\0" + "fill\0" + "from\0" + "href\0" + "dur\0" + "end\0" + "max\0" + "min\0" + "by\0" + "to\0" +}; + + +static const struct HashEntry SVGAnimationElementImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 55, SVGAnimationElementImpl::Accumulate, DontDelete|ReadOnly, 0, 25 }, + { 0, 0, 0, 0, -1 }, + { 29, SVGAnimationElementImpl::TargetElement, DontDelete|ReadOnly, 0, 26 }, + { 66, SVGAnimationElementImpl::KeySplines, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 145, SVGAnimationElementImpl::Href, DontDelete|ReadOnly, 0, -1 }, + { 1, SVGAnimationElementImpl::AttributeName, DontDelete|ReadOnly, 0, -1 }, + { 150, SVGAnimationElementImpl::Dur, DontDelete|ReadOnly, 0, 30 }, + { 96, SVGAnimationElementImpl::CalcMode, DontDelete|ReadOnly, 0, -1 }, + { 129, SVGAnimationElementImpl::Begin, DontDelete|ReadOnly, 0, -1 }, + { 122, SVGAnimationElementImpl::Values, DontDelete|ReadOnly, 0, 23 }, + { 0, 0, 0, 0, -1 }, + { 87, SVGAnimationElementImpl::Additive, DontDelete|ReadOnly, 0, 27 }, + { 105, SVGAnimationElementImpl::KeyTimes, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 15, SVGAnimationElementImpl::AttributeType, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 169, SVGAnimationElementImpl::To, DontDelete|ReadOnly, 0, 29 }, + { 0, 0, 0, 0, -1 }, + { 140, SVGAnimationElementImpl::From, DontDelete|ReadOnly, 0, -1 }, + { 166, SVGAnimationElementImpl::By, DontDelete|ReadOnly, 0, 24 }, + { 154, SVGAnimationElementImpl::End, DontDelete|ReadOnly, 0, 28 }, + { 162, SVGAnimationElementImpl::Min, DontDelete|ReadOnly, 0, -1 }, + { 158, SVGAnimationElementImpl::Max, DontDelete|ReadOnly, 0, -1 }, + { 114, SVGAnimationElementImpl::Restart, DontDelete|ReadOnly, 0, -1 }, + { 43, SVGAnimationElementImpl::RepeatCount, DontDelete|ReadOnly, 0, -1 }, + { 77, SVGAnimationElementImpl::RepeatDur, DontDelete|ReadOnly, 0, -1 }, + { 135, SVGAnimationElementImpl::Fill, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGAnimationElementImpl::s_hashTable = { 2, 31, SVGAnimationElementImpl__s_hashTableEntries, 23, SVGAnimationElementImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGAnimationElementImplProto__s_hashTableStrings[] = { + "\0" + "getSimpleDuration\0" + "getCurrentTime\0" + "getStartTime\0" +}; + + +static const struct HashEntry SVGAnimationElementImplProto__s_hashTableEntries[] = { + { 34, SVGAnimationElementImpl::GetStartTime, DontDelete|Function, 0, -1 }, + { 1, SVGAnimationElementImpl::GetSimpleDuration, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 19, SVGAnimationElementImpl::GetCurrentTime, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGAnimationElementImplProto::s_hashTable = { 2, 5, SVGAnimationElementImplProto__s_hashTableEntries, 5, SVGAnimationElementImplProto__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGCircleElementImpl.lut.h b/ksvg/data/SVGCircleElementImpl.lut.h new file mode 100644 index 00000000..dc7fb0cc --- /dev/null +++ b/ksvg/data/SVGCircleElementImpl.lut.h @@ -0,0 +1,26 @@ +/* Automatically generated from impl/SVGCircleElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGCircleElementImpl__s_hashTableStrings[] = { + "\0" + "cx\0" + "cy\0" + "r\0" +}; + + +static const struct HashEntry SVGCircleElementImpl__s_hashTableEntries[] = { + { 4, SVGCircleElementImpl::Cy, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGCircleElementImpl::Cx, DontDelete|ReadOnly, 0, 5 }, + { 7, SVGCircleElementImpl::R, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGCircleElementImpl::s_hashTable = { 2, 6, SVGCircleElementImpl__s_hashTableEntries, 5, SVGCircleElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGClipPathElementImpl.lut.h b/ksvg/data/SVGClipPathElementImpl.lut.h new file mode 100644 index 00000000..5f5c7df2 --- /dev/null +++ b/ksvg/data/SVGClipPathElementImpl.lut.h @@ -0,0 +1,20 @@ +/* Automatically generated from impl/SVGClipPathElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGClipPathElementImpl__s_hashTableStrings[] = { + "\0" + "clipPathUnits\0" +}; + + +static const struct HashEntry SVGClipPathElementImpl__s_hashTableEntries[] = { + { 1, SVGClipPathElementImpl::ClipPathUnits, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGClipPathElementImpl::s_hashTable = { 2, 2, SVGClipPathElementImpl__s_hashTableEntries, 2, SVGClipPathElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGColorImpl.lut.h b/ksvg/data/SVGColorImpl.lut.h new file mode 100644 index 00000000..e6e0fe48 --- /dev/null +++ b/ksvg/data/SVGColorImpl.lut.h @@ -0,0 +1,76 @@ +/* Automatically generated from impl/SVGColorImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGColorImpl__s_hashTableStrings[] = { + "\0" + "colorType\0" + "ICCColor\0" + "RGBColor\0" +}; + + +static const struct HashEntry SVGColorImpl__s_hashTableEntries[] = { + { 20, SVGColorImpl::RGBColor, DontDelete|ReadOnly, 0, -1 }, + { 1, SVGColorImpl::ColorType, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 11, SVGColorImpl::ICCColor, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGColorImpl::s_hashTable = { 2, 5, SVGColorImpl__s_hashTableEntries, 5, SVGColorImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGColorImplProto__s_hashTableStrings[] = { + "\0" + "setRGBColorICCColor\0" + "setRGBColor\0" + "setColor\0" +}; + + +static const struct HashEntry SVGColorImplProto__s_hashTableEntries[] = { + { 1, SVGColorImpl::SetRGBColorICCColor, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 21, SVGColorImpl::SetRGBColor, DontDelete|Function, 1, -1 }, + { 33, SVGColorImpl::SetColor, DontDelete|Function, 3, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGColorImplProto::s_hashTable = { 2, 5, SVGColorImplProto__s_hashTableEntries, 5, SVGColorImplProto__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGColorImplConstructor__s_hashTableStrings[] = { + "\0" + "SVG_COLORTYPE_RGBCOLOR_ICCCOLOR\0" + "SVG_COLORTYPE_CURRENTCOLOR\0" + "SVG_COLORTYPE_RGBCOLOR\0" + "SVG_COLORTYPE_UNKNOWN\0" +}; + + +static const struct HashEntry SVGColorImplConstructor__s_hashTableEntries[] = { + { 83, KSVG::SVG_COLORTYPE_UNKNOWN, DontDelete|ReadOnly, 0, 6 }, + { 0, 0, 0, 0, -1 }, + { 60, KSVG::SVG_COLORTYPE_RGBCOLOR, DontDelete|ReadOnly, 0, 5 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, KSVG::SVG_COLORTYPE_RGBCOLOR_ICCCOLOR, DontDelete|ReadOnly, 0, -1 }, + { 33, KSVG::SVG_COLORTYPE_CURRENTCOLOR, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGColorImplConstructor::s_hashTable = { 2, 7, SVGColorImplConstructor__s_hashTableEntries, 5, SVGColorImplConstructor__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGColorProfileElementImpl.lut.h b/ksvg/data/SVGColorProfileElementImpl.lut.h new file mode 100644 index 00000000..40c11854 --- /dev/null +++ b/ksvg/data/SVGColorProfileElementImpl.lut.h @@ -0,0 +1,26 @@ +/* Automatically generated from impl/SVGColorProfileElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGColorProfileElementImpl__s_hashTableStrings[] = { + "\0" + "rendering-intent\0" + "href\0" + "name\0" +}; + + +static const struct HashEntry SVGColorProfileElementImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 18, SVGColorProfileElementImpl::Href, DontDelete|ReadOnly, 0, 5 }, + { 23, SVGColorProfileElementImpl::Name, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGColorProfileElementImpl::RenderingIntent, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGColorProfileElementImpl::s_hashTable = { 2, 6, SVGColorProfileElementImpl__s_hashTableEntries, 5, SVGColorProfileElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGCursorElementImpl.lut.h b/ksvg/data/SVGCursorElementImpl.lut.h new file mode 100644 index 00000000..94527e0c --- /dev/null +++ b/ksvg/data/SVGCursorElementImpl.lut.h @@ -0,0 +1,22 @@ +/* Automatically generated from impl/SVGCursorElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGCursorElementImpl__s_hashTableStrings[] = { + "\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGCursorElementImpl__s_hashTableEntries[] = { + { 1, SVGCursorElementImpl::X, DontDelete|ReadOnly, 0, -1 }, + { 3, SVGCursorElementImpl::Y, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGCursorElementImpl::s_hashTable = { 2, 3, SVGCursorElementImpl__s_hashTableEntries, 3, SVGCursorElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGDocumentImpl.lut.h b/ksvg/data/SVGDocumentImpl.lut.h new file mode 100644 index 00000000..92b7ed14 --- /dev/null +++ b/ksvg/data/SVGDocumentImpl.lut.h @@ -0,0 +1,67 @@ +/* Automatically generated from impl/SVGDocumentImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGDocumentImpl__s_hashTableStrings[] = { + "\0" + "documentElement\0" + "implementation\0" + "rootElement\0" + "referrer\0" + "doctype\0" + "domain\0" + "title\0" + "URL\0" +}; + + +static const struct HashEntry SVGDocumentImpl__s_hashTableEntries[] = { + { 74, SVGDocumentImpl::Url, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 61, SVGDocumentImpl::Domain, DontDelete|ReadOnly, 0, 10 }, + { 0, 0, 0, 0, -1 }, + { 53, SVGDocumentImpl::DocType, DontDelete|ReadOnly, 0, -1 }, + { 32, SVGDocumentImpl::RootElement, DontDelete|ReadOnly, 0, -1 }, + { 68, SVGDocumentImpl::Title, DontDelete|ReadOnly, 0, 9 }, + { 17, SVGDocumentImpl::Implementation, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 44, SVGDocumentImpl::Referrer, DontDelete|ReadOnly, 0, -1 }, + { 1, SVGDocumentImpl::DocumentElement, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGDocumentImpl::s_hashTable = { 2, 11, SVGDocumentImpl__s_hashTableEntries, 9, SVGDocumentImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGDocumentImplProto__s_hashTableStrings[] = { + "\0" + "getElementsByTagNameNS\0" + "getElementsByTagName\0" + "createElementNS\0" + "createTextNode\0" + "getElementById\0" + "createElement\0" +}; + + +static const struct HashEntry SVGDocumentImplProto__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 76, SVGDocumentImpl::GetElementById, DontDelete|Function, 1, -1 }, + { 0, 0, 0, 0, -1 }, + { 24, SVGDocumentImpl::GetElementsByTagName, DontDelete|Function, 1, 8 }, + { 61, SVGDocumentImpl::CreateTextNode, DontDelete|Function, 1, -1 }, + { 91, SVGDocumentImpl::CreateElement, DontDelete|Function, 1, 7 }, + { 0, 0, 0, 0, -1 }, + { 45, SVGDocumentImpl::CreateElementNS, DontDelete|Function, 2, -1 }, + { 1, SVGDocumentImpl::GetElementsByTagNameNS, DontDelete|Function, 2, -1 } +}; + +const struct HashTable SVGDocumentImplProto::s_hashTable = { 2, 9, SVGDocumentImplProto__s_hashTableEntries, 7, SVGDocumentImplProto__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGEcma.lut.h b/ksvg/data/SVGEcma.lut.h new file mode 100644 index 00000000..54909bab --- /dev/null +++ b/ksvg/data/SVGEcma.lut.h @@ -0,0 +1,396 @@ +/* Automatically generated from impl/SVGEcma.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGDOMNodeBridge__s_hashTableStrings[] = { + "\0" + "previousSibling\0" + "ownerDocument\0" + "namespaceURI\0" + "nextSibling\0" + "attributes\0" + "childNodes\0" + "firstChild\0" + "parentNode\0" + "lastChild\0" + "localName\0" + "nodeValue\0" + "nodeName\0" + "nodeType\0" + "prefix\0" +}; + + +static const struct HashEntry SVGDOMNodeBridge__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 67, SVGDOMNodeBridge::ChildNodes, DontDelete|ReadOnly, 0, -1 }, + { 100, SVGDOMNodeBridge::LastChild, DontDelete|ReadOnly, 0, -1 }, + { 89, SVGDOMNodeBridge::ParentNode, DontDelete|ReadOnly, 0, 18 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 139, SVGDOMNodeBridge::NodeType, DontDelete|ReadOnly, 0, 17 }, + { 130, SVGDOMNodeBridge::NodeName, DontDelete|ReadOnly, 0, 20 }, + { 17, SVGDOMNodeBridge::OwnerDocument, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 120, SVGDOMNodeBridge::NodeValue, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 78, SVGDOMNodeBridge::FirstChild, DontDelete|ReadOnly, 0, -1 }, + { 1, SVGDOMNodeBridge::PreviousSibling, DontDelete|ReadOnly, 0, 19 }, + { 44, SVGDOMNodeBridge::NextSibling, DontDelete|ReadOnly, 0, -1 }, + { 56, SVGDOMNodeBridge::Attributes, DontDelete|ReadOnly, 0, 22 }, + { 31, SVGDOMNodeBridge::NamespaceURI, DontDelete|ReadOnly, 0, 21 }, + { 148, SVGDOMNodeBridge::Prefix, DontDelete, 0, -1 }, + { 110, SVGDOMNodeBridge::LocalName, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGDOMNodeBridge::s_hashTable = { 2, 23, SVGDOMNodeBridge__s_hashTableEntries, 17, SVGDOMNodeBridge__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGDOMNodeBridgeProto__s_hashTableStrings[] = { + "\0" + "removeEventListener\0" + "getPreviousSibling\0" + "addEventListener\0" + "getOwnerDocument\0" + "getNamespaceURI\0" + "getNextSibling\0" + "getAttributes\0" + "getChildNodes\0" + "getFirstChild\0" + "getParentNode\0" + "hasAttributes\0" + "hasChildNodes\0" + "getLastChild\0" + "getLocalName\0" + "getNodeValue\0" + "insertBefore\0" + "replaceChild\0" + "appendChild\0" + "getNodeName\0" + "getNodeType\0" + "isSupported\0" + "removeChild\0" + "cloneNode\0" + "getPrefix\0" + "normalize\0" + "contains\0" +}; + + +static const struct HashEntry SVGDOMNodeBridgeProto__s_hashTableEntries[] = { + { 175, SVGDOMNodeBridge::HasChildNodes, DontDelete|Function, 0, -1 }, + { 215, SVGDOMNodeBridge::GetNodeValue, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 119, SVGDOMNodeBridge::GetChildNodes, DontDelete|Function, 0, -1 }, + { 1, SVGDOMNodeBridge::RemoveEventListener, DontDelete|Function, 3, -1 }, + { 0, 0, 0, 0, -1 }, + { 302, SVGDOMNodeBridge::RemoveChild, DontDelete|Function, 1, 37 }, + { 21, SVGDOMNodeBridge::GetPreviousSibling, DontDelete|Function, 0, -1 }, + { 228, SVGDOMNodeBridge::InsertBefore, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 254, SVGDOMNodeBridge::AppendChild, DontDelete|Function, 1, 36 }, + { 0, 0, 0, 0, -1 }, + { 161, SVGDOMNodeBridge::HasAttributes, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 133, SVGDOMNodeBridge::GetFirstChild, DontDelete|Function, 0, 32 }, + { 314, SVGDOMNodeBridge::CloneNode, DontDelete|Function, 1, 29 }, + { 57, SVGDOMNodeBridge::GetOwnerDocument, DontDelete|Function, 0, -1 }, + { 344, SVGDOMNodeBridge::Contains, DontDelete|Function, 1, 30 }, + { 147, SVGDOMNodeBridge::GetParentNode, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 40, SVGDOMNodeBridge::AddEventListener, DontDelete|Function, 3, -1 }, + { 290, SVGDOMNodeBridge::IsSupported, DontDelete|Function, 2, 31 }, + { 241, SVGDOMNodeBridge::ReplaceChild, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 334, SVGDOMNodeBridge::Normalize, DontDelete|Function, 0, 34 }, + { 266, SVGDOMNodeBridge::GetNodeName, DontDelete|Function, 0, -1 }, + { 278, SVGDOMNodeBridge::GetNodeType, DontDelete|Function, 0, 33 }, + { 189, SVGDOMNodeBridge::GetLastChild, DontDelete|Function, 0, 35 }, + { 90, SVGDOMNodeBridge::GetNextSibling, DontDelete|Function, 0, -1 }, + { 105, SVGDOMNodeBridge::GetAttributes, DontDelete|Function, 0, -1 }, + { 74, SVGDOMNodeBridge::GetNamespaceURI, DontDelete|Function, 0, -1 }, + { 324, SVGDOMNodeBridge::GetPrefix, DontDelete|Function, 0, -1 }, + { 202, SVGDOMNodeBridge::GetLocalName, DontDelete|Function, 0, -1 } +}; + +const struct HashTable SVGDOMNodeBridgeProto::s_hashTable = { 2, 38, SVGDOMNodeBridgeProto__s_hashTableEntries, 29, SVGDOMNodeBridgeProto__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGDOMElementBridge__s_hashTableStrings[] = { + "\0" + "tagName\0" +}; + + +static const struct HashEntry SVGDOMElementBridge__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 1, SVGDOMElementBridge::TagName, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGDOMElementBridge::s_hashTable = { 2, 2, SVGDOMElementBridge__s_hashTableEntries, 2, SVGDOMElementBridge__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGDOMElementBridgeProto__s_hashTableStrings[] = { + "\0" + "getElementByTagNameNS\0" + "getElementsByTagName\0" + "removeAttributeNode\0" + "getAttributeNodeNS\0" + "setAttributeNodeNS\0" + "removeAttributeNS\0" + "getAttributeNode\0" + "setAttributeNode\0" + "removeAttribute\0" + "getAttributeNS\0" + "hasAttributeNS\0" + "setAttributeNS\0" + "getAttribute\0" + "hasAttribute\0" + "setAttribute\0" +}; + + +static const struct HashEntry SVGDOMElementBridgeProto__s_hashTableEntries[] = { + { 64, SVGDOMElementBridge::GetAttributeNodeNS, DontDelete|Function, 2, -1 }, + { 170, SVGDOMElementBridge::GetAttributeNS, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 44, SVGDOMElementBridge::RemoveAttributeNode, DontDelete|Function, 1, -1 }, + { 154, SVGDOMElementBridge::RemoveAttribute, DontDelete|Function, 1, 17 }, + { 241, SVGDOMElementBridge::SetAttribute, DontDelete|Function, 2, -1 }, + { 228, SVGDOMElementBridge::HasAttribute, DontDelete|Function, 1, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 120, SVGDOMElementBridge::GetAttributeNode, DontDelete|Function, 1, -1 }, + { 215, SVGDOMElementBridge::GetAttribute, DontDelete|Function, 1, -1 }, + { 1, SVGDOMElementBridge::GetElementsByTagNameNS, DontDelete|Function, 2, -1 }, + { 102, SVGDOMElementBridge::RemoveAttributeNS, DontDelete|Function, 2, 18 }, + { 200, SVGDOMElementBridge::SetAttributeNS, DontDelete|Function, 3, -1 }, + { 185, SVGDOMElementBridge::HasAttributeNS, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 23, SVGDOMElementBridge::GetElementsByTagName, DontDelete|Function, 1, -1 }, + { 137, SVGDOMElementBridge::SetAttributeNode, DontDelete|Function, 2, -1 }, + { 83, SVGDOMElementBridge::SetAttributeNodeNS, DontDelete|Function, 1, -1 } +}; + +const struct HashTable SVGDOMElementBridgeProto::s_hashTable = { 2, 19, SVGDOMElementBridgeProto__s_hashTableEntries, 17, SVGDOMElementBridgeProto__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGDOMNodeListBridge__s_hashTableStrings[] = { + "\0" + "length\0" +}; + + +static const struct HashEntry SVGDOMNodeListBridge__s_hashTableEntries[] = { + { 1, SVGDOMNodeListBridge::Length, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGDOMNodeListBridge::s_hashTable = { 2, 2, SVGDOMNodeListBridge__s_hashTableEntries, 2, SVGDOMNodeListBridge__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGDOMNodeListBridgeProto__s_hashTableStrings[] = { + "\0" + "getLength\0" + "item\0" +}; + + +static const struct HashEntry SVGDOMNodeListBridgeProto__s_hashTableEntries[] = { + { 1, SVGDOMNodeListBridge::GetLength, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 11, SVGDOMNodeListBridge::Item, DontDelete|Function, 1, -1 } +}; + +const struct HashTable SVGDOMNodeListBridgeProto::s_hashTable = { 2, 3, SVGDOMNodeListBridgeProto__s_hashTableEntries, 3, SVGDOMNodeListBridgeProto__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGDOMCharacterDataBridge__s_hashTableStrings[] = { + "\0" + "length\0" + "data\0" +}; + + +static const struct HashEntry SVGDOMCharacterDataBridge__s_hashTableEntries[] = { + { 1, SVGDOMCharacterDataBridge::Length, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 8, SVGDOMCharacterDataBridge::Data, DontDelete, 0, -1 } +}; + +const struct HashTable SVGDOMCharacterDataBridge::s_hashTable = { 2, 3, SVGDOMCharacterDataBridge__s_hashTableEntries, 3, SVGDOMCharacterDataBridge__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGDOMCharacterDataBridgeProto__s_hashTableStrings[] = { + "\0" + "substringData\0" + "replaceData\0" + "appendData\0" + "deleteData\0" + "insertData\0" + "getLength\0" + "getData\0" + "setData\0" +}; + + +static const struct HashEntry SVGDOMCharacterDataBridgeProto__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 38, SVGDOMCharacterDataBridge::DeleteData, DontDelete|Function, 2, -1 }, + { 70, SVGDOMCharacterDataBridge::GetData, DontDelete|Function, 0, 12 }, + { 78, SVGDOMCharacterDataBridge::SetData, DontDelete|Function, 1, 11 }, + { 1, SVGDOMCharacterDataBridge::SubstringData, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 27, SVGDOMCharacterDataBridge::AppendData, DontDelete|Function, 1, -1 }, + { 15, SVGDOMCharacterDataBridge::ReplaceData, DontDelete|Function, 2, -1 }, + { 60, SVGDOMCharacterDataBridge::GetLength, DontDelete|Function, 0, -1 }, + { 49, SVGDOMCharacterDataBridge::InsertData, DontDelete|Function, 2, -1 } +}; + +const struct HashTable SVGDOMCharacterDataBridgeProto::s_hashTable = { 2, 13, SVGDOMCharacterDataBridgeProto__s_hashTableEntries, 11, SVGDOMCharacterDataBridgeProto__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGDOMTextBridge__s_hashTableStrings[] = { + "\0" + "dummy\0" +}; + + +static const struct HashEntry SVGDOMTextBridge__s_hashTableEntries[] = { + { 1, SVGDOMTextBridge::Dummy, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGDOMTextBridge::s_hashTable = { 2, 2, SVGDOMTextBridge__s_hashTableEntries, 2, SVGDOMTextBridge__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGDOMTextBridgeProto__s_hashTableStrings[] = { + "\0" + "splitText\0" +}; + + +static const struct HashEntry SVGDOMTextBridgeProto__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 1, SVGDOMTextBridge::SplitText, DontDelete|Function, 1, -1 } +}; + +const struct HashTable SVGDOMTextBridgeProto::s_hashTable = { 2, 2, SVGDOMTextBridgeProto__s_hashTableEntries, 2, SVGDOMTextBridgeProto__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGDOMDOMImplementationBridge__s_hashTableStrings[] = { + "\0" + "dummy\0" +}; + + +static const struct HashEntry SVGDOMDOMImplementationBridge__s_hashTableEntries[] = { + { 1, SVGDOMDOMImplementationBridge::Dummy, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGDOMDOMImplementationBridge::s_hashTable = { 2, 2, SVGDOMDOMImplementationBridge__s_hashTableEntries, 2, SVGDOMDOMImplementationBridge__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGDOMDOMImplementationBridgeProto__s_hashTableStrings[] = { + "\0" + "hasFeature\0" +}; + + +static const struct HashEntry SVGDOMDOMImplementationBridgeProto__s_hashTableEntries[] = { + { 1, SVGDOMDOMImplementationBridge::HasFeature, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGDOMDOMImplementationBridgeProto::s_hashTable = { 2, 2, SVGDOMDOMImplementationBridgeProto__s_hashTableEntries, 2, SVGDOMDOMImplementationBridgeProto__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGDOMDocumentFragmentBridge__s_hashTableStrings[] = { + "\0" + "dummy\0" +}; + + +static const struct HashEntry SVGDOMDocumentFragmentBridge__s_hashTableEntries[] = { + { 1, SVGDOMDocumentFragmentBridge::Dummy, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGDOMDocumentFragmentBridge::s_hashTable = { 2, 2, SVGDOMDocumentFragmentBridge__s_hashTableEntries, 2, SVGDOMDocumentFragmentBridge__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGElementImpl.lut.h b/ksvg/data/SVGElementImpl.lut.h new file mode 100644 index 00000000..fe205a71 --- /dev/null +++ b/ksvg/data/SVGElementImpl.lut.h @@ -0,0 +1,92 @@ +/* Automatically generated from impl/SVGElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGElementImpl__s_hashTableStrings[] = { + "\0" + "ownerSVGElement\0" + "viewportElement\0" + "onmouseclick\0" + "onmousedown\0" + "onmousemove\0" + "onmouseover\0" + "onactivate\0" + "onfocusout\0" + "onkeypress\0" + "onmouseout\0" + "onfocusin\0" + "onkeydown\0" + "onmouseup\0" + "onabort\0" + "onclick\0" + "onerror\0" + "onkeyup\0" + "xmlbase\0" + "onload\0" + "id\0" +}; + + +static const struct HashEntry SVGElementImpl__s_hashTableEntries[] = { + { 17, SVGElementImpl::ViewportElement, DontDelete|ReadOnly, 0, -1 }, + { 136, SVGElementImpl::OnKeyDown, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 164, SVGElementImpl::OnClick, DontDelete, 0, 27 }, + { 33, SVGElementImpl::OnClick, DontDelete, 0, -1 }, + { 93, SVGElementImpl::OnFocusOut, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 188, SVGElementImpl::XmlBase, DontDelete, 0, 25 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGElementImpl::OwnerSvgElement, DontDelete|ReadOnly, 0, 23 }, + { 0, 0, 0, 0, -1 }, + { 196, SVGElementImpl::OnLoad, DontDelete, 0, 29 }, + { 58, SVGElementImpl::OnMouseMove, DontDelete, 0, -1 }, + { 46, SVGElementImpl::OnMouseDown, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 191, SVGElementImpl::XmlBase, DontDelete, 0, 26 }, + { 203, SVGElementImpl::ElementId, DontDelete, 0, 30 }, + { 70, SVGElementImpl::OnMouseOver, DontDelete, 0, -1 }, + { 146, SVGElementImpl::OnMouseUp, DontDelete, 0, 24 }, + { 115, SVGElementImpl::OnMouseOut, DontDelete, 0, 28 }, + { 82, SVGElementImpl::OnActivate, DontDelete, 0, -1 }, + { 180, SVGElementImpl::OnKeyUp, DontDelete, 0, -1 }, + { 104, SVGElementImpl::OnKeyPress, DontDelete, 0, -1 }, + { 126, SVGElementImpl::OnFocusIn, DontDelete, 0, -1 }, + { 172, SVGElementImpl::OnError, DontDelete, 0, -1 }, + { 156, SVGElementImpl::OnAbort, DontDelete, 0, -1 } +}; + +const struct HashTable SVGElementImpl::s_hashTable = { 2, 31, SVGElementImpl__s_hashTableEntries, 23, SVGElementImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGElementImplProto__s_hashTableStrings[] = { + "\0" + "getPropertyValue\0" + "setProperty\0" + "getStyle\0" +}; + + +static const struct HashEntry SVGElementImplProto__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 18, SVGElementImpl::SetProperty, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGElementImpl::GetPropertyValue, DontDelete|Function, 1, -1 }, + { 30, SVGElementImpl::GetStyle, DontDelete|Function, 0, -1 } +}; + +const struct HashTable SVGElementImplProto::s_hashTable = { 2, 5, SVGElementImplProto__s_hashTableEntries, 5, SVGElementImplProto__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGEllipseElementImpl.lut.h b/ksvg/data/SVGEllipseElementImpl.lut.h new file mode 100644 index 00000000..a2fe34a7 --- /dev/null +++ b/ksvg/data/SVGEllipseElementImpl.lut.h @@ -0,0 +1,28 @@ +/* Automatically generated from impl/SVGEllipseElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGEllipseElementImpl__s_hashTableStrings[] = { + "\0" + "cx\0" + "cy\0" + "rx\0" + "ry\0" +}; + + +static const struct HashEntry SVGEllipseElementImpl__s_hashTableEntries[] = { + { 4, SVGEllipseElementImpl::Cy, DontDelete|ReadOnly, 0, 6 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGEllipseElementImpl::Cx, DontDelete|ReadOnly, 0, 5 }, + { 7, SVGEllipseElementImpl::Rx, DontDelete|ReadOnly, 0, -1 }, + { 10, SVGEllipseElementImpl::Ry, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGEllipseElementImpl::s_hashTable = { 2, 7, SVGEllipseElementImpl__s_hashTableEntries, 5, SVGEllipseElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGEventImpl.lut.h b/ksvg/data/SVGEventImpl.lut.h new file mode 100644 index 00000000..3283775e --- /dev/null +++ b/ksvg/data/SVGEventImpl.lut.h @@ -0,0 +1,271 @@ +/* Automatically generated from impl/SVGEventImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGEventImpl__s_hashTableStrings[] = { + "\0" + "currentTarget\0" + "cancelable\0" + "eventPhase\0" + "timeStamp\0" + "bubbles\0" + "target\0" + "type\0" +}; + + +static const struct HashEntry SVGEventImpl__s_hashTableEntries[] = { + { 1, SVGEventImpl::CurrentTarget, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 37, SVGEventImpl::TimeStamp, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 15, SVGEventImpl::Cancelable, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 55, SVGEventImpl::Target, DontDelete|ReadOnly, 0, 11 }, + { 62, SVGEventImpl::Type, DontDelete|ReadOnly, 0, -1 }, + { 26, SVGEventImpl::EventPhase, DontDelete|ReadOnly, 0, 12 }, + { 47, SVGEventImpl::Bubbles, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGEventImpl::s_hashTable = { 2, 13, SVGEventImpl__s_hashTableEntries, 11, SVGEventImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGEventImplProto__s_hashTableStrings[] = { + "\0" + "getCurrentTarget\0" + "stopPropagation\0" + "getCurrentNode\0" + "preventDefault\0" + "getCancelable\0" + "getEventphase\0" + "getTimeStamp\0" + "getBubbles\0" + "getTarget\0" + "initEvent\0" + "getType\0" +}; + + +static const struct HashEntry SVGEventImplProto__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 92, SVGEventImpl::GetTimeStamp, DontDelete|Function, 0, 17 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 34, SVGEventImpl::GetCurrentNode, DontDelete|Function, 0, 14 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 105, SVGEventImpl::GetBubbles, DontDelete|Function, 0, -1 }, + { 136, SVGEventImpl::GetType, DontDelete|Function, 0, 13 }, + { 78, SVGEventImpl::GetEventPhase, DontDelete|Function, 0, 15 }, + { 116, SVGEventImpl::GetTarget, DontDelete|Function, 0, 16 }, + { 1, SVGEventImpl::GetCurrentTarget, DontDelete|Function, 0, -1 }, + { 64, SVGEventImpl::GetCancelable, DontDelete|Function, 0, -1 }, + { 18, SVGEventImpl::StopPropagation, DontDelete|Function, 0, -1 }, + { 49, SVGEventImpl::PreventDefault, DontDelete|Function, 0, -1 }, + { 126, SVGEventImpl::InitEvent, DontDelete|Function, 3, -1 } +}; + +const struct HashTable SVGEventImplProto::s_hashTable = { 2, 18, SVGEventImplProto__s_hashTableEntries, 13, SVGEventImplProto__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGUIEventImpl__s_hashTableStrings[] = { + "\0" + "detail\0" + "view\0" +}; + + +static const struct HashEntry SVGUIEventImpl__s_hashTableEntries[] = { + { 1, SVGUIEventImpl::Detail, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 8, SVGUIEventImpl::View, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGUIEventImpl::s_hashTable = { 2, 3, SVGUIEventImpl__s_hashTableEntries, 3, SVGUIEventImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGUIEventImplProto__s_hashTableStrings[] = { + "\0" + "initUIEvent\0" + "getDetail\0" + "getView\0" +}; + + +static const struct HashEntry SVGUIEventImplProto__s_hashTableEntries[] = { + { 13, SVGUIEventImpl::GetDetail, DontDelete|Function, 0, -1 }, + { 23, SVGUIEventImpl::GetView, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGUIEventImpl::InitUIEvent, DontDelete|Function, 5, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGUIEventImplProto::s_hashTable = { 2, 5, SVGUIEventImplProto__s_hashTableEntries, 5, SVGUIEventImplProto__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGKeyEventImpl__s_hashTableStrings[] = { + "\0" + "outputString\0" + "virtKeyVal\0" + "charCode\0" + "keyCode\0" + "keyVal\0" +}; + + +static const struct HashEntry SVGKeyEventImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 34, SVGKeyEventImpl::KeyVal, DontDelete|ReadOnly, 0, -1 }, + { 25, SVGKeyEventImpl::KeyVal, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 42, SVGKeyEventImpl::KeyVal, DontDelete|ReadOnly, 0, 7 }, + { 14, SVGKeyEventImpl::VirtKeyVal, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGKeyEventImpl::OutputString, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGKeyEventImpl::s_hashTable = { 2, 8, SVGKeyEventImpl__s_hashTableEntries, 7, SVGKeyEventImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGKeyEventImplProto__s_hashTableStrings[] = { + "\0" + "checkModifier\0" + "getCharCode\0" + "getKeyCode\0" + "getKeyVal\0" +}; + + +static const struct HashEntry SVGKeyEventImplProto__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGKeyEventImpl::CheckModifier, DontDelete|Function, 1, 7 }, + { 15, SVGKeyEventImpl::GetKeyVal, DontDelete|Function, 0, 8 }, + { 0, 0, 0, 0, -1 }, + { 38, SVGKeyEventImpl::GetKeyVal, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 27, SVGKeyEventImpl::GetKeyVal, DontDelete|Function, 0, -1 }, + { 15, SVGKeyEventImpl::GetCharCode, DontDelete|Function, 0, -1 } +}; + +const struct HashTable SVGKeyEventImplProto::s_hashTable = { 2, 9, SVGKeyEventImplProto__s_hashTableEntries, 7, SVGKeyEventImplProto__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGMouseEventImpl__s_hashTableStrings[] = { + "\0" + "relatedTarget\0" + "shiftKey\0" + "clientX\0" + "clientY\0" + "ctrlKey\0" + "metaKey\0" + "screenX\0" + "screenY\0" + "altKey\0" + "button\0" +}; + + +static const struct HashEntry SVGMouseEventImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 24, SVGMouseEventImpl::ClientX, DontDelete|ReadOnly, 0, -1 }, + { 56, SVGMouseEventImpl::ScreenX, DontDelete|ReadOnly, 0, 11 }, + { 64, SVGMouseEventImpl::ScreenY, DontDelete|ReadOnly, 0, 12 }, + { 0, 0, 0, 0, -1 }, + { 48, SVGMouseEventImpl::MetaKey, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 40, SVGMouseEventImpl::CtrlKey, DontDelete|ReadOnly, 0, 14 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGMouseEventImpl::RelatedTarget, DontDelete|ReadOnly, 0, -1 }, + { 32, SVGMouseEventImpl::ClientY, DontDelete|ReadOnly, 0, 13 }, + { 15, SVGMouseEventImpl::ShiftKey, DontDelete|ReadOnly, 0, -1 }, + { 72, SVGMouseEventImpl::AltKey, DontDelete|ReadOnly, 0, -1 }, + { 79, SVGMouseEventImpl::Button, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGMouseEventImpl::s_hashTable = { 2, 15, SVGMouseEventImpl__s_hashTableEntries, 11, SVGMouseEventImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGMouseEventImplProto__s_hashTableStrings[] = { + "\0" + "getRelatedTarget\0" + "initMouseEvent\0" + "getShiftKey\0" + "getClientX\0" + "getClientY\0" + "getCtrlKey\0" + "getMetaKey\0" + "getScreenX\0" + "getScreenY\0" + "getAltKey\0" + "getButton\0" +}; + + +static const struct HashEntry SVGMouseEventImplProto__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 45, SVGMouseEventImpl::GetClientX, DontDelete|Function, 0, -1 }, + { 89, SVGMouseEventImpl::GetScreenX, DontDelete|Function, 0, 13 }, + { 100, SVGMouseEventImpl::GetScreenY, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 78, SVGMouseEventImpl::GetMetaKey, DontDelete|Function, 0, 15 }, + { 67, SVGMouseEventImpl::GetCtrlKey, DontDelete|Function, 0, -1 }, + { 33, SVGMouseEventImpl::GetShiftKey, DontDelete|Function, 0, 14 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 56, SVGMouseEventImpl::GetClientY, DontDelete|Function, 0, 16 }, + { 111, SVGMouseEventImpl::GetAltKey, DontDelete|Function, 0, -1 }, + { 121, SVGMouseEventImpl::GetButton, DontDelete|Function, 0, -1 }, + { 1, SVGMouseEventImpl::GetRelatedTarget, DontDelete|Function, 0, 17 }, + { 18, SVGMouseEventImpl::InitMouseEvent, DontDelete|Function, 15, -1 } +}; + +const struct HashTable SVGMouseEventImplProto::s_hashTable = { 2, 18, SVGMouseEventImplProto__s_hashTableEntries, 13, SVGMouseEventImplProto__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGExternalResourcesRequiredImpl.lut.h b/ksvg/data/SVGExternalResourcesRequiredImpl.lut.h new file mode 100644 index 00000000..2361f729 --- /dev/null +++ b/ksvg/data/SVGExternalResourcesRequiredImpl.lut.h @@ -0,0 +1,20 @@ +/* Automatically generated from impl/SVGExternalResourcesRequiredImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGExternalResourcesRequiredImpl__s_hashTableStrings[] = { + "\0" + "externalResourcesRequired\0" +}; + + +static const struct HashEntry SVGExternalResourcesRequiredImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 1, SVGExternalResourcesRequiredImpl::ExternalResourcesRequired, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGExternalResourcesRequiredImpl::s_hashTable = { 2, 2, SVGExternalResourcesRequiredImpl__s_hashTableEntries, 2, SVGExternalResourcesRequiredImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGFitToViewBoxImpl.lut.h b/ksvg/data/SVGFitToViewBoxImpl.lut.h new file mode 100644 index 00000000..7ef28728 --- /dev/null +++ b/ksvg/data/SVGFitToViewBoxImpl.lut.h @@ -0,0 +1,22 @@ +/* Automatically generated from impl/SVGFitToViewBoxImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGFitToViewBoxImpl__s_hashTableStrings[] = { + "\0" + "preserveAspectRatio\0" + "viewBox\0" +}; + + +static const struct HashEntry SVGFitToViewBoxImpl__s_hashTableEntries[] = { + { 1, SVGFitToViewBoxImpl::PreserveAspectRatio, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 21, SVGFitToViewBoxImpl::ViewBox, DontDelete, 0, -1 } +}; + +const struct HashTable SVGFitToViewBoxImpl::s_hashTable = { 2, 3, SVGFitToViewBoxImpl__s_hashTableEntries, 3, SVGFitToViewBoxImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGForeignObjectElementImpl.lut.h b/ksvg/data/SVGForeignObjectElementImpl.lut.h new file mode 100644 index 00000000..a53be40e --- /dev/null +++ b/ksvg/data/SVGForeignObjectElementImpl.lut.h @@ -0,0 +1,26 @@ +/* Automatically generated from impl/SVGForeignObjectElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGForeignObjectElementImpl__s_hashTableStrings[] = { + "\0" + "height\0" + "width\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGForeignObjectElementImpl__s_hashTableEntries[] = { + { 14, SVGForeignObjectElementImpl::X, DontDelete|ReadOnly, 0, -1 }, + { 16, SVGForeignObjectElementImpl::Y, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGForeignObjectElementImpl::Height, DontDelete|ReadOnly, 0, -1 }, + { 8, SVGForeignObjectElementImpl::Width, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGForeignObjectElementImpl::s_hashTable = { 2, 5, SVGForeignObjectElementImpl__s_hashTableEntries, 5, SVGForeignObjectElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGGlyphElementImpl.lut.h b/ksvg/data/SVGGlyphElementImpl.lut.h new file mode 100644 index 00000000..b4f54c4e --- /dev/null +++ b/ksvg/data/SVGGlyphElementImpl.lut.h @@ -0,0 +1,39 @@ +/* Automatically generated from impl/SVGGlyphElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGGlyphElementImpl__s_hashTableStrings[] = { + "\0" + "vert-origin-x\0" + "vert-origin-y\0" + "arabic-form\0" + "horiz-adv-x\0" + "orientation\0" + "glyph-name\0" + "vert-adv-y\0" + "unicode\0" + "lang\0" + "d\0" +}; + + +static const struct HashEntry SVGGlyphElementImpl__s_hashTableEntries[] = { + { 95, SVGGlyphElementImpl::Lang, DontDelete|ReadOnly, 0, -1 }, + { 100, SVGGlyphElementImpl::D, DontDelete|ReadOnly, 0, -1 }, + { 29, SVGGlyphElementImpl::ArabicForm, DontDelete|ReadOnly, 0, -1 }, + { 41, SVGGlyphElementImpl::HorizAdvX, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 87, SVGGlyphElementImpl::Unicode, DontDelete|ReadOnly, 0, -1 }, + { 76, SVGGlyphElementImpl::VertAdvY, DontDelete|ReadOnly, 0, -1 }, + { 53, SVGGlyphElementImpl::Orientation, DontDelete|ReadOnly, 0, -1 }, + { 65, SVGGlyphElementImpl::GlyphName, DontDelete|ReadOnly, 0, 11 }, + { 15, SVGGlyphElementImpl::VertOriginY, DontDelete|ReadOnly, 0, -1 }, + { 1, SVGGlyphElementImpl::VertOriginX, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGGlyphElementImpl::s_hashTable = { 2, 12, SVGGlyphElementImpl__s_hashTableEntries, 11, SVGGlyphElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGGlyphRefElementImpl.lut.h b/ksvg/data/SVGGlyphRefElementImpl.lut.h new file mode 100644 index 00000000..b64aab0f --- /dev/null +++ b/ksvg/data/SVGGlyphRefElementImpl.lut.h @@ -0,0 +1,28 @@ +/* Automatically generated from impl/SVGGlyphRefElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGGlyphRefElementImpl__s_hashTableStrings[] = { + "\0" + "glyphRef\0" + "format\0" + "dx\0" + "dy\0" +}; + + +static const struct HashEntry SVGGlyphRefElementImpl__s_hashTableEntries[] = { + { 1, SVGGlyphRefElementImpl::GlyphRef, DontDelete|ReadOnly, 0, -1 }, + { 18, SVGGlyphRefElementImpl::X, DontDelete|ReadOnly, 0, -1 }, + { 21, SVGGlyphRefElementImpl::Y, DontDelete|ReadOnly, 0, -1 }, + { 17, SVGGlyphRefElementImpl::Dx, DontDelete|ReadOnly, 0, -1 }, + { 20, SVGGlyphRefElementImpl::Dy, DontDelete|ReadOnly, 0, -1 }, + { 10, SVGGlyphRefElementImpl::Format, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGGlyphRefElementImpl::s_hashTable = { 2, 7, SVGGlyphRefElementImpl__s_hashTableEntries, 7, SVGGlyphRefElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGGradientElementImpl.lut.h b/ksvg/data/SVGGradientElementImpl.lut.h new file mode 100644 index 00000000..84f5c8d9 --- /dev/null +++ b/ksvg/data/SVGGradientElementImpl.lut.h @@ -0,0 +1,51 @@ +/* Automatically generated from impl/SVGGradientElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGGradientElementImpl__s_hashTableStrings[] = { + "\0" + "gradientTransform\0" + "gradientUnits\0" + "spreadMethod\0" +}; + + +static const struct HashEntry SVGGradientElementImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 19, SVGGradientElementImpl::GradientUnits, DontDelete|ReadOnly, 0, 5 }, + { 33, SVGGradientElementImpl::SpreadMethod, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGGradientElementImpl::GradientTransform, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGGradientElementImpl::s_hashTable = { 2, 6, SVGGradientElementImpl__s_hashTableEntries, 5, SVGGradientElementImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGGradientElementImplConstructor__s_hashTableStrings[] = { + "\0" + "SVG_SPREADMETHOD_REFLECT\0" + "SVG_SPREADMETHOD_UNKNOWN\0" + "SVG_SPREADMETHOD_REPEAT\0" + "SVG_SPREADMETHOD_PAD\0" +}; + + +static const struct HashEntry SVGGradientElementImplConstructor__s_hashTableEntries[] = { + { 51, KSVG::SVG_SPREADMETHOD_REPEAT, DontDelete|ReadOnly, 0, -1 }, + { 26, KSVG::SVG_SPREADMETHOD_UNKNOWN, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, KSVG::SVG_SPREADMETHOD_REFLECT, DontDelete|ReadOnly, 0, -1 }, + { 75, KSVG::SVG_SPREADMETHOD_PAD, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGGradientElementImplConstructor::s_hashTable = { 2, 5, SVGGradientElementImplConstructor__s_hashTableEntries, 5, SVGGradientElementImplConstructor__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGICCColorImpl.lut.h b/ksvg/data/SVGICCColorImpl.lut.h new file mode 100644 index 00000000..3ad22c89 --- /dev/null +++ b/ksvg/data/SVGICCColorImpl.lut.h @@ -0,0 +1,23 @@ +/* Automatically generated from impl/SVGICCColorImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGICCColorImpl__s_hashTableStrings[] = { + "\0" + "colorProfile\0" + "colors\0" +}; + + +static const struct HashEntry SVGICCColorImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 1, SVGICCColorImpl::ColorProfile, DontDelete, 0, 3 }, + { 0, 0, 0, 0, -1 }, + { 14, SVGICCColorImpl::Colors, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGICCColorImpl::s_hashTable = { 2, 4, SVGICCColorImpl__s_hashTableEntries, 3, SVGICCColorImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGImageElementImpl.lut.h b/ksvg/data/SVGImageElementImpl.lut.h new file mode 100644 index 00000000..9584ecb8 --- /dev/null +++ b/ksvg/data/SVGImageElementImpl.lut.h @@ -0,0 +1,31 @@ +/* Automatically generated from impl/SVGImageElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGImageElementImpl__s_hashTableStrings[] = { + "\0" + "preserveAspectRatio\0" + "height\0" + "width\0" + "href\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGImageElementImpl__s_hashTableEntries[] = { + { 1, SVGImageElementImpl::PreserveAspectRatio, DontDelete|ReadOnly, 0, -1 }, + { 39, SVGImageElementImpl::X, DontDelete|ReadOnly, 0, 7 }, + { 41, SVGImageElementImpl::Y, DontDelete|ReadOnly, 0, -1 }, + { 21, SVGImageElementImpl::Height, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 28, SVGImageElementImpl::Width, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 34, SVGImageElementImpl::Href, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGImageElementImpl::s_hashTable = { 2, 8, SVGImageElementImpl__s_hashTableEntries, 7, SVGImageElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGLangSpaceImpl.lut.h b/ksvg/data/SVGLangSpaceImpl.lut.h new file mode 100644 index 00000000..d8c727c4 --- /dev/null +++ b/ksvg/data/SVGLangSpaceImpl.lut.h @@ -0,0 +1,24 @@ +/* Automatically generated from impl/SVGLangSpaceImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGLangSpaceImpl__s_hashTableStrings[] = { + "\0" + "xmlspace\0" + "xmllang\0" +}; + + +static const struct HashEntry SVGLangSpaceImpl__s_hashTableEntries[] = { + { 10, SVGLangSpaceImpl::XmlLang, DontDelete, 0, -1 }, + { 1, SVGLangSpaceImpl::XmlSpace, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 13, SVGLangSpaceImpl::XmlLang, DontDelete, 0, -1 }, + { 4, SVGLangSpaceImpl::XmlSpace, DontDelete, 0, -1 } +}; + +const struct HashTable SVGLangSpaceImpl::s_hashTable = { 2, 5, SVGLangSpaceImpl__s_hashTableEntries, 5, SVGLangSpaceImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGLengthImpl.lut.h b/ksvg/data/SVGLengthImpl.lut.h new file mode 100644 index 00000000..dfd88b2f --- /dev/null +++ b/ksvg/data/SVGLengthImpl.lut.h @@ -0,0 +1,87 @@ +/* Automatically generated from impl/SVGLengthImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGLengthImpl__s_hashTableStrings[] = { + "\0" + "valueInSpecifiedUnits\0" + "valueAsString\0" + "unitType\0" + "value\0" +}; + + +static const struct HashEntry SVGLengthImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 37, SVGLengthImpl::UnitType, DontDelete|ReadOnly, 0, 5 }, + { 23, SVGLengthImpl::ValueAsString, DontDelete, 0, -1 }, + { 1, SVGLengthImpl::ValueInSpecifiedUnits, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 46, SVGLengthImpl::Value, DontDelete, 0, -1 } +}; + +const struct HashTable SVGLengthImpl::s_hashTable = { 2, 6, SVGLengthImpl__s_hashTableEntries, 5, SVGLengthImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGLengthImplProto__s_hashTableStrings[] = { + "\0" + "convertToSpecifiedUnits\0" + "newValueSpecifiedUnits\0" +}; + + +static const struct HashEntry SVGLengthImplProto__s_hashTableEntries[] = { + { 1, SVGLengthImpl::ConvertToSpecifiedUnits, DontDelete|Function, 1, -1 }, + { 25, SVGLengthImpl::NewValueSpecifiedUnits, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGLengthImplProto::s_hashTable = { 2, 3, SVGLengthImplProto__s_hashTableEntries, 3, SVGLengthImplProto__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGLengthImplConstructor__s_hashTableStrings[] = { + "\0" + "SVG_LENGTHTYPE_PERCENTAGE\0" + "SVG_LENGTHTYPE_UNKNOWN\0" + "SVG_LENGTHTYPE_NUMBER\0" + "SVG_LENGTHTYPE_EMS\0" + "SVG_LENGTHTYPE_EXS\0" + "SVG_LENGTHTYPE_CM\0" + "SVG_LENGTHTYPE_MM\0" + "SVG_LENGTHTYPE_PC\0" + "SVG_LENGTHTYPE_PT\0" + "SVG_LENGTHTYPE_PX\0" +}; + + +static const struct HashEntry SVGLengthImplConstructor__s_hashTableEntries[] = { + { 1, KSVG::SVG_LENGTHTYPE_PERCENTAGE, DontDelete|ReadOnly, 0, -1 }, + { 72, KSVG::SVG_LENGTHTYPE_EMS, DontDelete|ReadOnly, 0, 11 }, + { 27, KSVG::SVG_LENGTHTYPE_UNKNOWN, DontDelete|ReadOnly, 0, 12 }, + { 128, KSVG::SVG_LENGTHTYPE_MM, DontDelete|ReadOnly, 0, -1 }, + { 110, KSVG::SVG_LENGTHTYPE_CM, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 182, KSVG::SVG_LENGTHTYPE_PX, DontDelete|ReadOnly, 0, -1 }, + { 146, KSVG::SVG_LENGTHTYPE_PC, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 50, KSVG::SVG_LENGTHTYPE_NUMBER, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 91, KSVG::SVG_LENGTHTYPE_EXS, DontDelete|ReadOnly, 0, -1 }, + { 164, KSVG::SVG_LENGTHTYPE_PT, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGLengthImplConstructor::s_hashTable = { 2, 13, SVGLengthImplConstructor__s_hashTableEntries, 11, SVGLengthImplConstructor__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGLengthListImpl.lut.h b/ksvg/data/SVGLengthListImpl.lut.h new file mode 100644 index 00000000..9f263f81 --- /dev/null +++ b/ksvg/data/SVGLengthListImpl.lut.h @@ -0,0 +1,55 @@ +/* Automatically generated from impl/SVGLengthListImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGLengthListImpl__s_hashTableStrings[] = { + "\0" + "numberOfItems\0" +}; + + +static const struct HashEntry SVGLengthListImpl__s_hashTableEntries[] = { + { 1, SVGListDefs::NumberOfItems, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGLengthListImpl::s_hashTable = { 2, 2, SVGLengthListImpl__s_hashTableEntries, 2, SVGLengthListImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGLengthListImplProto__s_hashTableStrings[] = { + "\0" + "insertItemBefore\0" + "replaceItem\0" + "appendItem\0" + "initialize\0" + "removeItem\0" + "getItem\0" + "clear\0" +}; + + +static const struct HashEntry SVGLengthListImplProto__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 71, SVGListDefs::Clear, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 63, SVGListDefs::GetItem, DontDelete|Function, 1, -1 }, + { 1, SVGListDefs::InsertItemBefore, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 41, SVGListDefs::Initialize, DontDelete|Function, 1, -1 }, + { 52, SVGListDefs::RemoveItem, DontDelete|Function, 1, 11 }, + { 18, SVGListDefs::ReplaceItem, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 30, SVGListDefs::AppendItem, DontDelete|Function, 1, -1 } +}; + +const struct HashTable SVGLengthListImplProto::s_hashTable = { 2, 12, SVGLengthListImplProto__s_hashTableEntries, 11, SVGLengthListImplProto__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGLineElementImpl.lut.h b/ksvg/data/SVGLineElementImpl.lut.h new file mode 100644 index 00000000..857b3ee2 --- /dev/null +++ b/ksvg/data/SVGLineElementImpl.lut.h @@ -0,0 +1,27 @@ +/* Automatically generated from impl/SVGLineElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGLineElementImpl__s_hashTableStrings[] = { + "\0" + "x1\0" + "x2\0" + "y1\0" + "y2\0" +}; + + +static const struct HashEntry SVGLineElementImpl__s_hashTableEntries[] = { + { 7, SVGLineElementImpl::Y1, DontDelete|ReadOnly, 0, 5 }, + { 10, SVGLineElementImpl::Y2, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGLineElementImpl::X1, DontDelete|ReadOnly, 0, -1 }, + { 4, SVGLineElementImpl::X2, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGLineElementImpl::s_hashTable = { 2, 6, SVGLineElementImpl__s_hashTableEntries, 5, SVGLineElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGLinearGradientElementImpl.lut.h b/ksvg/data/SVGLinearGradientElementImpl.lut.h new file mode 100644 index 00000000..30755f58 --- /dev/null +++ b/ksvg/data/SVGLinearGradientElementImpl.lut.h @@ -0,0 +1,27 @@ +/* Automatically generated from impl/SVGLinearGradientElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGLinearGradientElementImpl__s_hashTableStrings[] = { + "\0" + "x1\0" + "x2\0" + "y1\0" + "y2\0" +}; + + +static const struct HashEntry SVGLinearGradientElementImpl__s_hashTableEntries[] = { + { 7, SVGLinearGradientElementImpl::Y1, DontDelete|ReadOnly, 0, 5 }, + { 10, SVGLinearGradientElementImpl::Y2, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGLinearGradientElementImpl::X1, DontDelete|ReadOnly, 0, -1 }, + { 4, SVGLinearGradientElementImpl::X2, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGLinearGradientElementImpl::s_hashTable = { 2, 6, SVGLinearGradientElementImpl__s_hashTableEntries, 5, SVGLinearGradientElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGLocatableImpl.lut.h b/ksvg/data/SVGLocatableImpl.lut.h new file mode 100644 index 00000000..5fcafcda --- /dev/null +++ b/ksvg/data/SVGLocatableImpl.lut.h @@ -0,0 +1,49 @@ +/* Automatically generated from impl/SVGLocatableImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGLocatableImpl__s_hashTableStrings[] = { + "\0" + "farthestViewportElement\0" + "nearestViewportElement\0" +}; + + +static const struct HashEntry SVGLocatableImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 25, SVGLocatableImpl::NearestViewportElement, DontDelete, 0, 3 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGLocatableImpl::FarthestViewportElement, DontDelete, 0, -1 } +}; + +const struct HashTable SVGLocatableImpl::s_hashTable = { 2, 4, SVGLocatableImpl__s_hashTableEntries, 3, SVGLocatableImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGLocatableImplProto__s_hashTableStrings[] = { + "\0" + "getTransformToElement\0" + "getScreenCTM\0" + "getBBox\0" + "getCTM\0" +}; + + +static const struct HashEntry SVGLocatableImplProto__s_hashTableEntries[] = { + { 1, SVGLocatableImpl::GetTransformToElement, DontDelete|Function, 1, -1 }, + { 23, SVGLocatableImpl::GetScreenCTM, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 36, SVGLocatableImpl::GetBBox, DontDelete|Function, 0, 5 }, + { 0, 0, 0, 0, -1 }, + { 44, SVGLocatableImpl::GetCTM, DontDelete|Function, 0, -1 } +}; + +const struct HashTable SVGLocatableImplProto::s_hashTable = { 2, 6, SVGLocatableImplProto__s_hashTableEntries, 5, SVGLocatableImplProto__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGMarkerElementImpl.lut.h b/ksvg/data/SVGMarkerElementImpl.lut.h new file mode 100644 index 00000000..d89e711c --- /dev/null +++ b/ksvg/data/SVGMarkerElementImpl.lut.h @@ -0,0 +1,90 @@ +/* Automatically generated from impl/SVGMarkerElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGMarkerElementImpl__s_hashTableStrings[] = { + "\0" + "markerHeight\0" + "markerUnits\0" + "markerWidth\0" + "orientAngle\0" + "orientType\0" + "orient\0" + "refX\0" + "refY\0" +}; + + +static const struct HashEntry SVGMarkerElementImpl__s_hashTableEntries[] = { + { 1, SVGMarkerElementImpl::MarkerHeight, DontDelete|ReadOnly, 0, 12 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 14, SVGMarkerElementImpl::MarkerUnits, DontDelete|ReadOnly, 0, -1 }, + { 50, SVGMarkerElementImpl::OrientType, DontDelete|ReadOnly, 0, 13 }, + { 68, SVGMarkerElementImpl::RefX, DontDelete|ReadOnly, 0, -1 }, + { 73, SVGMarkerElementImpl::RefY, DontDelete|ReadOnly, 0, 11 }, + { 26, SVGMarkerElementImpl::MarkerWidth, DontDelete|ReadOnly, 0, -1 }, + { 38, SVGMarkerElementImpl::OrientAngle, DontDelete|ReadOnly, 0, -1 }, + { 61, SVGMarkerElementImpl::Orient, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGMarkerElementImpl::s_hashTable = { 2, 14, SVGMarkerElementImpl__s_hashTableEntries, 11, SVGMarkerElementImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGMarkerElementImplProto__s_hashTableStrings[] = { + "\0" + "setOrientToAngle\0" + "setOrientToAuto\0" +}; + + +static const struct HashEntry SVGMarkerElementImplProto__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 18, SVGMarkerElementImpl::SetOrientToAuto, DontDelete|Function, 0, 3 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGMarkerElementImpl::SetOrientToAngle, DontDelete|Function, 0, -1 } +}; + +const struct HashTable SVGMarkerElementImplProto::s_hashTable = { 2, 4, SVGMarkerElementImplProto__s_hashTableEntries, 3, SVGMarkerElementImplProto__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGMarkerElementImplConstructor__s_hashTableStrings[] = { + "\0" + "SVG_MARKERUNITS_USERSPACEONUSE\0" + "SVG_MARKERUNITS_STROKEWIDTH\0" + "SVG_MARKER_ORIENT_UNKNOWN\0" + "SVG_MARKERUNITS_UNKNOWN\0" + "SVG_MARKER_ORIENT_ANGLE\0" + "SVG_MARKER_ORIENT_AUTO\0" +}; + + +static const struct HashEntry SVGMarkerElementImplConstructor__s_hashTableEntries[] = { + { 110, KSVG::SVG_MARKER_ORIENT_ANGLE, DontDelete|ReadOnly, 0, -1 }, + { 1, KSVG::SVG_MARKERUNITS_USERSPACEONUSE, DontDelete|ReadOnly, 0, -1 }, + { 86, KSVG::SVG_MARKERUNITS_UNKNOWN, DontDelete|ReadOnly, 0, -1 }, + { 134, KSVG::SVG_MARKER_ORIENT_AUTO, DontDelete|ReadOnly, 0, -1 }, + { 32, KSVG::SVG_MARKERUNITS_STROKEWIDTH, DontDelete|ReadOnly, 0, -1 }, + { 60, KSVG::SVG_MARKER_ORIENT_UNKNOWN, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGMarkerElementImplConstructor::s_hashTable = { 2, 7, SVGMarkerElementImplConstructor__s_hashTableEntries, 7, SVGMarkerElementImplConstructor__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGMaskElementImpl.lut.h b/ksvg/data/SVGMaskElementImpl.lut.h new file mode 100644 index 00000000..bcc32c39 --- /dev/null +++ b/ksvg/data/SVGMaskElementImpl.lut.h @@ -0,0 +1,31 @@ +/* Automatically generated from impl/SVGMaskElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGMaskElementImpl__s_hashTableStrings[] = { + "\0" + "maskContentUnits\0" + "maskUnits\0" + "height\0" + "width\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGMaskElementImpl__s_hashTableEntries[] = { + { 18, SVGMaskElementImpl::MaskUnits, DontDelete|ReadOnly, 0, -1 }, + { 41, SVGMaskElementImpl::X, DontDelete|ReadOnly, 0, -1 }, + { 43, SVGMaskElementImpl::Y, DontDelete|ReadOnly, 0, -1 }, + { 1, SVGMaskElementImpl::MaskContentUnits, DontDelete|ReadOnly, 0, 7 }, + { 0, 0, 0, 0, -1 }, + { 35, SVGMaskElementImpl::Width, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 28, SVGMaskElementImpl::Height, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGMaskElementImpl::s_hashTable = { 2, 8, SVGMaskElementImpl__s_hashTableEntries, 7, SVGMaskElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGMatrixImpl.lut.h b/ksvg/data/SVGMatrixImpl.lut.h new file mode 100644 index 00000000..05b84cb3 --- /dev/null +++ b/ksvg/data/SVGMatrixImpl.lut.h @@ -0,0 +1,74 @@ +/* Automatically generated from impl/SVGMatrixImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGMatrixImpl__s_hashTableStrings[] = { + "\0" + "a\0" + "b\0" + "c\0" + "d\0" + "e\0" + "f\0" +}; + + +static const struct HashEntry SVGMatrixImpl__s_hashTableEntries[] = { + { 3, SVGMatrixImpl::B, DontDelete, 0, -1 }, + { 5, SVGMatrixImpl::C, DontDelete, 0, -1 }, + { 7, SVGMatrixImpl::D, DontDelete, 0, -1 }, + { 9, SVGMatrixImpl::E, DontDelete, 0, -1 }, + { 11, SVGMatrixImpl::F, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGMatrixImpl::A, DontDelete, 0, -1 } +}; + +const struct HashTable SVGMatrixImpl::s_hashTable = { 2, 7, SVGMatrixImpl__s_hashTableEntries, 7, SVGMatrixImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGMatrixImplProto__s_hashTableStrings[] = { + "\0" + "rotateFromVector\0" + "scaleNonUniform\0" + "translate\0" + "multiply\0" + "inverse\0" + "rotate\0" + "flipX\0" + "flipY\0" + "scale\0" + "skewX\0" + "skewY\0" +}; + + +static const struct HashEntry SVGMatrixImplProto__s_hashTableEntries[] = { + { 80, SVGMatrixImpl::Scale, DontDelete|Function, 1, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 61, SVGMatrixImpl::Rotate, DontDelete|Function, 1, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 18, SVGMatrixImpl::ScaleNonUniform, DontDelete|Function, 2, 14 }, + { 1, SVGMatrixImpl::RotateFromVector, DontDelete|Function, 2, 15 }, + { 53, SVGMatrixImpl::Inverse, DontDelete|Function, 0, 16 }, + { 92, SVGMatrixImpl::SkewY, DontDelete|Function, 1, -1 }, + { 44, SVGMatrixImpl::Multiply, DontDelete|Function, 1, 13 }, + { 34, SVGMatrixImpl::Translate, DontDelete|Function, 2, -1 }, + { 68, SVGMatrixImpl::FlipX, DontDelete|Function, 0, -1 }, + { 74, SVGMatrixImpl::FlipY, DontDelete|Function, 0, -1 }, + { 86, SVGMatrixImpl::SkewX, DontDelete|Function, 1, -1 } +}; + +const struct HashTable SVGMatrixImplProto::s_hashTable = { 2, 17, SVGMatrixImplProto__s_hashTableEntries, 13, SVGMatrixImplProto__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGNumberImpl.lut.h b/ksvg/data/SVGNumberImpl.lut.h new file mode 100644 index 00000000..eefcb452 --- /dev/null +++ b/ksvg/data/SVGNumberImpl.lut.h @@ -0,0 +1,20 @@ +/* Automatically generated from impl/SVGNumberImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGNumberImpl__s_hashTableStrings[] = { + "\0" + "value\0" +}; + + +static const struct HashEntry SVGNumberImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 1, SVGNumberImpl::Value, DontDelete, 0, -1 } +}; + +const struct HashTable SVGNumberImpl::s_hashTable = { 2, 2, SVGNumberImpl__s_hashTableEntries, 2, SVGNumberImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGNumberListImpl.lut.h b/ksvg/data/SVGNumberListImpl.lut.h new file mode 100644 index 00000000..59edbafd --- /dev/null +++ b/ksvg/data/SVGNumberListImpl.lut.h @@ -0,0 +1,55 @@ +/* Automatically generated from impl/SVGNumberListImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGNumberListImpl__s_hashTableStrings[] = { + "\0" + "numberOfItems\0" +}; + + +static const struct HashEntry SVGNumberListImpl__s_hashTableEntries[] = { + { 1, SVGListDefs::NumberOfItems, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGNumberListImpl::s_hashTable = { 2, 2, SVGNumberListImpl__s_hashTableEntries, 2, SVGNumberListImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGNumberListImplProto__s_hashTableStrings[] = { + "\0" + "insertItemBefore\0" + "replaceItem\0" + "appendItem\0" + "initialize\0" + "removeItem\0" + "getItem\0" + "clear\0" +}; + + +static const struct HashEntry SVGNumberListImplProto__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 71, SVGListDefs::Clear, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 63, SVGListDefs::GetItem, DontDelete|Function, 1, -1 }, + { 1, SVGListDefs::InsertItemBefore, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 41, SVGListDefs::Initialize, DontDelete|Function, 1, -1 }, + { 52, SVGListDefs::RemoveItem, DontDelete|Function, 1, 11 }, + { 18, SVGListDefs::ReplaceItem, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 30, SVGListDefs::AppendItem, DontDelete|Function, 1, -1 } +}; + +const struct HashTable SVGNumberListImplProto::s_hashTable = { 2, 12, SVGNumberListImplProto__s_hashTableEntries, 11, SVGNumberListImplProto__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGPaintImpl.lut.h b/ksvg/data/SVGPaintImpl.lut.h new file mode 100644 index 00000000..48c90b33 --- /dev/null +++ b/ksvg/data/SVGPaintImpl.lut.h @@ -0,0 +1,59 @@ +/* Automatically generated from impl/SVGPaintImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGPaintImpl__s_hashTableStrings[] = { + "\0" + "paintType\0" + "uri\0" +}; + + +static const struct HashEntry SVGPaintImpl__s_hashTableEntries[] = { + { 11, SVGPaintImpl::URI, DontDelete, 0, -1 }, + { 1, SVGPaintImpl::PaintType, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGPaintImpl::s_hashTable = { 2, 3, SVGPaintImpl__s_hashTableEntries, 3, SVGPaintImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGPaintImplConstructor__s_hashTableStrings[] = { + "\0" + "SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR\0" + "SVG_PAINTTYPE_URI_CURRENTCOLOR\0" + "SVG_PAINTTYPE_CURRENTCOLOR\0" + "SVG_PAINTTYPE_URI_RGBCOLOR\0" + "SVG_PAINTTYPE_RGBCOLOR\0" + "SVG_PAINTTYPE_URI_NONE\0" + "SVG_PAINTTYPE_UNKNOWN\0" + "SVG_PAINTTYPE_NONE\0" + "SVG_PAINTTYPE_URI\0" +}; + + +static const struct HashEntry SVGPaintImplConstructor__s_hashTableEntries[] = { + { 145, KSVG::SVG_PAINTTYPE_URI_NONE, DontDelete|ReadOnly, 0, -1 }, + { 95, KSVG::SVG_PAINTTYPE_URI_RGBCOLOR, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, KSVG::SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR, DontDelete|ReadOnly, 0, -1 }, + { 68, KSVG::SVG_PAINTTYPE_CURRENTCOLOR, DontDelete|ReadOnly, 0, -1 }, + { 190, KSVG::SVG_PAINTTYPE_NONE, DontDelete|ReadOnly, 0, -1 }, + { 122, KSVG::SVG_PAINTTYPE_RGBCOLOR, DontDelete|ReadOnly, 0, 11 }, + { 209, KSVG::SVG_PAINTTYPE_URI, DontDelete|ReadOnly, 0, -1 }, + { 168, KSVG::SVG_PAINTTYPE_UNKNOWN, DontDelete|ReadOnly, 0, -1 }, + { 37, KSVG::SVG_PAINTTYPE_URI_CURRENTCOLOR, DontDelete|ReadOnly, 0, -1 }, + { 122, KSVG::SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGPaintImplConstructor::s_hashTable = { 2, 12, SVGPaintImplConstructor__s_hashTableEntries, 11, SVGPaintImplConstructor__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGPathElementImpl.lut.h b/ksvg/data/SVGPathElementImpl.lut.h new file mode 100644 index 00000000..ccded107 --- /dev/null +++ b/ksvg/data/SVGPathElementImpl.lut.h @@ -0,0 +1,87 @@ +/* Automatically generated from impl/SVGPathElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathElementImpl__s_hashTableStrings[] = { + "\0" + "pathLength\0" + "d\0" +}; + + +static const struct HashEntry SVGPathElementImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 12, SVGPathElementImpl::D, DontDelete|ReadOnly, 0, 3 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGPathElementImpl::PathLength, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGPathElementImpl::s_hashTable = { 2, 4, SVGPathElementImpl__s_hashTableEntries, 3, SVGPathElementImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathElementImplProto__s_hashTableStrings[] = { + "\0" + "createSVGPathSegCurvetoQuadraticAbs\0" + "createSVGPathSegCurvetoQuadraticRel\0" + "createSVGPathSegLinetoHorizontalAbs\0" + "createSVGPathSegLinetoHorizontalRel\0" + "createSVGPathSegLinetoVerticalAbs\0" + "createSVGPathSegLinetoVerticalRel\0" + "createSVGPathSegCurvetoCubicAbs\0" + "createSVGPathSegCurvetoCubicRel\0" + "createSVGPathSegClosePath\0" + "createSVGPathSegLinetoAbs\0" + "createSVGPathSegLinetoRel\0" + "createSVGPathSegMovetoAbs\0" + "createSVGPathSegMovetoRel\0" + "createSVGPathSegArcAbs\0" + "createSVGPathSegArcRel\0" + "getPathSegAtLength\0" + "getPointAtLength\0" + "getTotalLength\0" +}; + + +static const struct HashEntry SVGPathElementImplProto__s_hashTableEntries[] = { + { 472, SVGPathElementImpl::GetPointAtLength, DontDelete|Function, 1, -1 }, + { 453, SVGPathElementImpl::GetPathSegAtLength, DontDelete|Function, 1, 23 }, + { 0, 0, 0, 0, -1 }, + { 355, SVGPathElementImpl::CreateSVGPathSegMovetoAbs, DontDelete|Function, 2, -1 }, + { 1, SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticAbs, DontDelete|Function, 4, 28 }, + { 430, SVGPathElementImpl::CreateSVGPathSegArcRel, DontDelete|Function, 7, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 109, SVGPathElementImpl::CreateSVGPathSegLinetoHorizontalRel, DontDelete|Function, 1, 25 }, + { 0, 0, 0, 0, -1 }, + { 303, SVGPathElementImpl::CreateSVGPathSegLinetoAbs, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 277, SVGPathElementImpl::CreateSVGPathSegClosePath, DontDelete|Function, 0, -1 }, + { 245, SVGPathElementImpl::CreateSVGPathSegCurvetoCubicRel, DontDelete|Function, 6, 27 }, + { 407, SVGPathElementImpl::CreateSVGPathSegArcAbs, DontDelete|Function, 7, -1 }, + { 381, SVGPathElementImpl::CreateSVGPathSegMovetoRel, DontDelete|Function, 2, -1 }, + { 37, SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticRel, DontDelete|Function, 4, 29 }, + { 0, 0, 0, 0, -1 }, + { 73, SVGPathElementImpl::CreateSVGPathSegLinetoHorizontalAbs, DontDelete|Function, 1, -1 }, + { 489, SVGPathElementImpl::GetTotalLength, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 179, SVGPathElementImpl::CreateSVGPathSegLinetoVerticalRel, DontDelete|Function, 1, -1 }, + { 329, SVGPathElementImpl::CreateSVGPathSegLinetoRel, DontDelete|Function, 2, 24 }, + { 213, SVGPathElementImpl::CreateSVGPathSegCurvetoCubicAbs, DontDelete|Function, 6, 26 }, + { 145, SVGPathElementImpl::CreateSVGPathSegLinetoVerticalAbs, DontDelete|Function, 1, -1 }, + { 213, SVGPathElementImpl::CreateSVGPathSegCurvetoCubicAbs, DontDelete|Function, 4, -1 }, + { 245, SVGPathElementImpl::CreateSVGPathSegCurvetoCubicRel, DontDelete|Function, 4, -1 }, + { 1, SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticAbs, DontDelete|Function, 2, -1 }, + { 37, SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticRel, DontDelete|Function, 2, -1 } +}; + +const struct HashTable SVGPathElementImplProto::s_hashTable = { 2, 30, SVGPathElementImplProto__s_hashTableEntries, 23, SVGPathElementImplProto__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGPathSegArcImpl.lut.h b/ksvg/data/SVGPathSegArcImpl.lut.h new file mode 100644 index 00000000..cfd8ffc8 --- /dev/null +++ b/ksvg/data/SVGPathSegArcImpl.lut.h @@ -0,0 +1,75 @@ +/* Automatically generated from impl/SVGPathSegArcImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegArcAbsImpl__s_hashTableStrings[] = { + "\0" + "largeArcFlag\0" + "sweepFlag\0" + "angle\0" + "r1\0" + "r2\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGPathSegArcAbsImpl__s_hashTableEntries[] = { + { 38, SVGPathSegArcAbsImpl::Y, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 24, SVGPathSegArcAbsImpl::Angle, DontDelete, 0, 12 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 30, SVGPathSegArcAbsImpl::R1, DontDelete, 0, -1 }, + { 36, SVGPathSegArcAbsImpl::X, DontDelete, 0, 11 }, + { 33, SVGPathSegArcAbsImpl::R2, DontDelete, 0, -1 }, + { 1, SVGPathSegArcAbsImpl::LargeArcFlag, DontDelete, 0, 13 }, + { 14, SVGPathSegArcAbsImpl::SweepFlag, DontDelete, 0, -1 } +}; + +const struct HashTable SVGPathSegArcAbsImpl::s_hashTable = { 2, 14, SVGPathSegArcAbsImpl__s_hashTableEntries, 11, SVGPathSegArcAbsImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegArcRelImpl__s_hashTableStrings[] = { + "\0" + "largeArcFlag\0" + "sweepFlag\0" + "angle\0" + "r1\0" + "r2\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGPathSegArcRelImpl__s_hashTableEntries[] = { + { 38, SVGPathSegArcRelImpl::Y, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 24, SVGPathSegArcRelImpl::Angle, DontDelete, 0, 12 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 30, SVGPathSegArcRelImpl::R1, DontDelete, 0, -1 }, + { 36, SVGPathSegArcRelImpl::X, DontDelete, 0, 11 }, + { 33, SVGPathSegArcRelImpl::R2, DontDelete, 0, -1 }, + { 1, SVGPathSegArcRelImpl::LargeArcFlag, DontDelete, 0, 13 }, + { 14, SVGPathSegArcRelImpl::SweepFlag, DontDelete, 0, -1 } +}; + +const struct HashTable SVGPathSegArcRelImpl::s_hashTable = { 2, 14, SVGPathSegArcRelImpl__s_hashTableEntries, 11, SVGPathSegArcRelImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGPathSegCurvetoCubicImpl.lut.h b/ksvg/data/SVGPathSegCurvetoCubicImpl.lut.h new file mode 100644 index 00000000..dff7104b --- /dev/null +++ b/ksvg/data/SVGPathSegCurvetoCubicImpl.lut.h @@ -0,0 +1,65 @@ +/* Automatically generated from impl/SVGPathSegCurvetoCubicImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegCurvetoCubicAbsImpl__s_hashTableStrings[] = { + "\0" + "x1\0" + "x2\0" + "y1\0" + "y2\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGPathSegCurvetoCubicAbsImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 13, SVGPathSegCurvetoCubicAbsImpl::X, DontDelete, 0, 7 }, + { 15, SVGPathSegCurvetoCubicAbsImpl::Y, DontDelete, 0, 8 }, + { 10, SVGPathSegCurvetoCubicAbsImpl::Y2, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGPathSegCurvetoCubicAbsImpl::X1, DontDelete, 0, -1 }, + { 7, SVGPathSegCurvetoCubicAbsImpl::Y1, DontDelete, 0, 9 }, + { 4, SVGPathSegCurvetoCubicAbsImpl::X2, DontDelete, 0, -1 } +}; + +const struct HashTable SVGPathSegCurvetoCubicAbsImpl::s_hashTable = { 2, 10, SVGPathSegCurvetoCubicAbsImpl__s_hashTableEntries, 7, SVGPathSegCurvetoCubicAbsImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegCurvetoCubicRelImpl__s_hashTableStrings[] = { + "\0" + "x1\0" + "x2\0" + "y1\0" + "y2\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGPathSegCurvetoCubicRelImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 13, SVGPathSegCurvetoCubicRelImpl::X, DontDelete, 0, 7 }, + { 15, SVGPathSegCurvetoCubicRelImpl::Y, DontDelete, 0, 8 }, + { 10, SVGPathSegCurvetoCubicRelImpl::Y2, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGPathSegCurvetoCubicRelImpl::X1, DontDelete, 0, -1 }, + { 7, SVGPathSegCurvetoCubicRelImpl::Y1, DontDelete, 0, 9 }, + { 4, SVGPathSegCurvetoCubicRelImpl::X2, DontDelete, 0, -1 } +}; + +const struct HashTable SVGPathSegCurvetoCubicRelImpl::s_hashTable = { 2, 10, SVGPathSegCurvetoCubicRelImpl__s_hashTableEntries, 7, SVGPathSegCurvetoCubicRelImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGPathSegCurvetoCubicSmoothImpl.lut.h b/ksvg/data/SVGPathSegCurvetoCubicSmoothImpl.lut.h new file mode 100644 index 00000000..e84cd124 --- /dev/null +++ b/ksvg/data/SVGPathSegCurvetoCubicSmoothImpl.lut.h @@ -0,0 +1,55 @@ +/* Automatically generated from impl/SVGPathSegCurvetoCubicSmoothImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegCurvetoCubicSmoothAbsImpl__s_hashTableStrings[] = { + "\0" + "x2\0" + "y2\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGPathSegCurvetoCubicSmoothAbsImpl__s_hashTableEntries[] = { + { 7, SVGPathSegCurvetoCubicSmoothAbsImpl::X, DontDelete, 0, 5 }, + { 9, SVGPathSegCurvetoCubicSmoothAbsImpl::Y, DontDelete, 0, 6 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGPathSegCurvetoCubicSmoothAbsImpl::X2, DontDelete, 0, -1 }, + { 4, SVGPathSegCurvetoCubicSmoothAbsImpl::Y2, DontDelete, 0, -1 } +}; + +const struct HashTable SVGPathSegCurvetoCubicSmoothAbsImpl::s_hashTable = { 2, 7, SVGPathSegCurvetoCubicSmoothAbsImpl__s_hashTableEntries, 5, SVGPathSegCurvetoCubicSmoothAbsImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegCurvetoCubicSmoothRelImpl__s_hashTableStrings[] = { + "\0" + "x2\0" + "y2\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGPathSegCurvetoCubicSmoothRelImpl__s_hashTableEntries[] = { + { 7, SVGPathSegCurvetoCubicSmoothRelImpl::X, DontDelete, 0, 5 }, + { 9, SVGPathSegCurvetoCubicSmoothRelImpl::Y, DontDelete, 0, 6 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGPathSegCurvetoCubicSmoothRelImpl::X2, DontDelete, 0, -1 }, + { 4, SVGPathSegCurvetoCubicSmoothRelImpl::Y2, DontDelete, 0, -1 } +}; + +const struct HashTable SVGPathSegCurvetoCubicSmoothRelImpl::s_hashTable = { 2, 7, SVGPathSegCurvetoCubicSmoothRelImpl__s_hashTableEntries, 5, SVGPathSegCurvetoCubicSmoothRelImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGPathSegCurvetoQuadraticImpl.lut.h b/ksvg/data/SVGPathSegCurvetoQuadraticImpl.lut.h new file mode 100644 index 00000000..8513fdd5 --- /dev/null +++ b/ksvg/data/SVGPathSegCurvetoQuadraticImpl.lut.h @@ -0,0 +1,53 @@ +/* Automatically generated from impl/SVGPathSegCurvetoQuadraticImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegCurvetoQuadraticAbsImpl__s_hashTableStrings[] = { + "\0" + "x1\0" + "y1\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGPathSegCurvetoQuadraticAbsImpl__s_hashTableEntries[] = { + { 7, SVGPathSegCurvetoQuadraticAbsImpl::X, DontDelete, 0, 5 }, + { 9, SVGPathSegCurvetoQuadraticAbsImpl::Y, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGPathSegCurvetoQuadraticAbsImpl::X1, DontDelete, 0, -1 }, + { 4, SVGPathSegCurvetoQuadraticAbsImpl::Y1, DontDelete, 0, -1 } +}; + +const struct HashTable SVGPathSegCurvetoQuadraticAbsImpl::s_hashTable = { 2, 6, SVGPathSegCurvetoQuadraticAbsImpl__s_hashTableEntries, 5, SVGPathSegCurvetoQuadraticAbsImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegCurvetoQuadraticRelImpl__s_hashTableStrings[] = { + "\0" + "x1\0" + "y1\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGPathSegCurvetoQuadraticRelImpl__s_hashTableEntries[] = { + { 7, SVGPathSegCurvetoQuadraticRelImpl::X, DontDelete, 0, 5 }, + { 9, SVGPathSegCurvetoQuadraticRelImpl::Y, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGPathSegCurvetoQuadraticRelImpl::X1, DontDelete, 0, -1 }, + { 4, SVGPathSegCurvetoQuadraticRelImpl::Y1, DontDelete, 0, -1 } +}; + +const struct HashTable SVGPathSegCurvetoQuadraticRelImpl::s_hashTable = { 2, 6, SVGPathSegCurvetoQuadraticRelImpl__s_hashTableEntries, 5, SVGPathSegCurvetoQuadraticRelImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGPathSegCurvetoQuadraticSmoothImpl.lut.h b/ksvg/data/SVGPathSegCurvetoQuadraticSmoothImpl.lut.h new file mode 100644 index 00000000..6622c341 --- /dev/null +++ b/ksvg/data/SVGPathSegCurvetoQuadraticSmoothImpl.lut.h @@ -0,0 +1,43 @@ +/* Automatically generated from impl/SVGPathSegCurvetoQuadraticSmoothImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegCurvetoQuadraticSmoothAbsImpl__s_hashTableStrings[] = { + "\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGPathSegCurvetoQuadraticSmoothAbsImpl__s_hashTableEntries[] = { + { 1, SVGPathSegCurvetoQuadraticSmoothAbsImpl::X, DontDelete, 0, -1 }, + { 3, SVGPathSegCurvetoQuadraticSmoothAbsImpl::Y, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGPathSegCurvetoQuadraticSmoothAbsImpl::s_hashTable = { 2, 3, SVGPathSegCurvetoQuadraticSmoothAbsImpl__s_hashTableEntries, 3, SVGPathSegCurvetoQuadraticSmoothAbsImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegCurvetoQuadraticSmoothRelImpl__s_hashTableStrings[] = { + "\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGPathSegCurvetoQuadraticSmoothRelImpl__s_hashTableEntries[] = { + { 1, SVGPathSegCurvetoQuadraticSmoothRelImpl::X, DontDelete, 0, -1 }, + { 3, SVGPathSegCurvetoQuadraticSmoothRelImpl::Y, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGPathSegCurvetoQuadraticSmoothRelImpl::s_hashTable = { 2, 3, SVGPathSegCurvetoQuadraticSmoothRelImpl__s_hashTableEntries, 3, SVGPathSegCurvetoQuadraticSmoothRelImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGPathSegImpl.lut.h b/ksvg/data/SVGPathSegImpl.lut.h new file mode 100644 index 00000000..94436a77 --- /dev/null +++ b/ksvg/data/SVGPathSegImpl.lut.h @@ -0,0 +1,88 @@ +/* Automatically generated from impl/SVGPathSegImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegImpl__s_hashTableStrings[] = { + "\0" + "pathSegTypeAsLetter\0" + "pathSegType\0" +}; + + +static const struct HashEntry SVGPathSegImpl__s_hashTableEntries[] = { + { 21, SVGPathSegImpl::PathSegType, DontDelete|ReadOnly, 0, 3 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGPathSegImpl::PathSegTypeAsLetter, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGPathSegImpl::s_hashTable = { 2, 4, SVGPathSegImpl__s_hashTableEntries, 3, SVGPathSegImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegImplConstructor__s_hashTableStrings[] = { + "\0" + "PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS\0" + "PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL\0" + "PATHSEG_CURVETO_CUBIC_SMOOTH_ABS\0" + "PATHSEG_CURVETO_CUBIC_SMOOTH_REL\0" + "PATHSEG_CURVETO_QUADRATIC_ABS\0" + "PATHSEG_CURVETO_QUADRATIC_REL\0" + "PATHSEG_LINETO_HORIZONTAL_ABS\0" + "PATHSEG_LINETO_HORIZONTAL_REL\0" + "PATHSEG_LINETO_VERTICAL_ABS\0" + "PATHSEG_LINETO_VERTICAL_REL\0" + "PATHSEG_CURVETO_CUBIC_ABS\0" + "PATHSEG_CURVETO_CUBIC_REL\0" + "PATHSEG_LINETO_ABS\0" + "PATHSEG_LINETO_REL\0" + "PATHSEG_MOVETO_ABS\0" + "PATHSEG_MOVETO_REL\0" + "PATHSEG_CLOSEPATH\0" + "PATHSEG_ARC_ABS\0" + "PATHSEG_ARC_REL\0" + "PATHSEG_UNKNOWN\0" +}; + + +static const struct HashEntry SVGPathSegImplConstructor__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 317, KSVG::PATHSEG_CURVETO_CUBIC_ABS, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 171, KSVG::PATHSEG_CURVETO_QUADRATIC_REL, DontDelete|ReadOnly, 0, 27 }, + { 479, KSVG::PATHSEG_ARC_REL, DontDelete|ReadOnly, 0, -1 }, + { 495, KSVG::PATHSEG_UNKNOWN, DontDelete|ReadOnly, 0, 23 }, + { 369, KSVG::PATHSEG_LINETO_ABS, DontDelete|ReadOnly, 0, -1 }, + { 108, KSVG::PATHSEG_CURVETO_CUBIC_SMOOTH_REL, DontDelete|ReadOnly, 0, 28 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 426, KSVG::PATHSEG_MOVETO_REL, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 343, KSVG::PATHSEG_CURVETO_CUBIC_REL, DontDelete|ReadOnly, 0, 24 }, + { 463, KSVG::PATHSEG_ARC_ABS, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 75, KSVG::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS, DontDelete|ReadOnly, 0, -1 }, + { 231, KSVG::PATHSEG_LINETO_HORIZONTAL_REL, DontDelete|ReadOnly, 0, -1 }, + { 388, KSVG::PATHSEG_LINETO_REL, DontDelete|ReadOnly, 0, -1 }, + { 38, KSVG::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL, DontDelete|ReadOnly, 0, -1 }, + { 407, KSVG::PATHSEG_MOVETO_ABS, DontDelete|ReadOnly, 0, -1 }, + { 445, KSVG::PATHSEG_CLOSEPATH, DontDelete|ReadOnly, 0, 25 }, + { 141, KSVG::PATHSEG_CURVETO_QUADRATIC_ABS, DontDelete|ReadOnly, 0, 26 }, + { 201, KSVG::PATHSEG_LINETO_HORIZONTAL_ABS, DontDelete|ReadOnly, 0, -1 }, + { 261, KSVG::PATHSEG_LINETO_VERTICAL_ABS, DontDelete|ReadOnly, 0, -1 }, + { 289, KSVG::PATHSEG_LINETO_VERTICAL_REL, DontDelete|ReadOnly, 0, -1 }, + { 1, KSVG::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGPathSegImplConstructor::s_hashTable = { 2, 29, SVGPathSegImplConstructor__s_hashTableEntries, 23, SVGPathSegImplConstructor__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGPathSegLinetoHorizontalImpl.lut.h b/ksvg/data/SVGPathSegLinetoHorizontalImpl.lut.h new file mode 100644 index 00000000..768ac3a3 --- /dev/null +++ b/ksvg/data/SVGPathSegLinetoHorizontalImpl.lut.h @@ -0,0 +1,39 @@ +/* Automatically generated from impl/SVGPathSegLinetoHorizontalImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegLinetoHorizontalAbsImpl__s_hashTableStrings[] = { + "\0" + "x\0" +}; + + +static const struct HashEntry SVGPathSegLinetoHorizontalAbsImpl__s_hashTableEntries[] = { + { 1, SVGPathSegLinetoHorizontalAbsImpl::X, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGPathSegLinetoHorizontalAbsImpl::s_hashTable = { 2, 2, SVGPathSegLinetoHorizontalAbsImpl__s_hashTableEntries, 2, SVGPathSegLinetoHorizontalAbsImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegLinetoHorizontalRelImpl__s_hashTableStrings[] = { + "\0" + "x\0" +}; + + +static const struct HashEntry SVGPathSegLinetoHorizontalRelImpl__s_hashTableEntries[] = { + { 1, SVGPathSegLinetoHorizontalRelImpl::X, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGPathSegLinetoHorizontalRelImpl::s_hashTable = { 2, 2, SVGPathSegLinetoHorizontalRelImpl__s_hashTableEntries, 2, SVGPathSegLinetoHorizontalRelImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGPathSegLinetoImpl.lut.h b/ksvg/data/SVGPathSegLinetoImpl.lut.h new file mode 100644 index 00000000..5d754cdf --- /dev/null +++ b/ksvg/data/SVGPathSegLinetoImpl.lut.h @@ -0,0 +1,43 @@ +/* Automatically generated from impl/SVGPathSegLinetoImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegLinetoAbsImpl__s_hashTableStrings[] = { + "\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGPathSegLinetoAbsImpl__s_hashTableEntries[] = { + { 1, SVGPathSegLinetoAbsImpl::X, DontDelete, 0, -1 }, + { 3, SVGPathSegLinetoAbsImpl::Y, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGPathSegLinetoAbsImpl::s_hashTable = { 2, 3, SVGPathSegLinetoAbsImpl__s_hashTableEntries, 3, SVGPathSegLinetoAbsImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegLinetoRelImpl__s_hashTableStrings[] = { + "\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGPathSegLinetoRelImpl__s_hashTableEntries[] = { + { 1, SVGPathSegLinetoRelImpl::X, DontDelete, 0, -1 }, + { 3, SVGPathSegLinetoRelImpl::Y, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGPathSegLinetoRelImpl::s_hashTable = { 2, 3, SVGPathSegLinetoRelImpl__s_hashTableEntries, 3, SVGPathSegLinetoRelImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGPathSegLinetoVerticalImpl.lut.h b/ksvg/data/SVGPathSegLinetoVerticalImpl.lut.h new file mode 100644 index 00000000..1a48baaa --- /dev/null +++ b/ksvg/data/SVGPathSegLinetoVerticalImpl.lut.h @@ -0,0 +1,39 @@ +/* Automatically generated from impl/SVGPathSegLinetoVerticalImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegLinetoVerticalAbsImpl__s_hashTableStrings[] = { + "\0" + "y\0" +}; + + +static const struct HashEntry SVGPathSegLinetoVerticalAbsImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 1, SVGPathSegLinetoVerticalAbsImpl::Y, DontDelete, 0, -1 } +}; + +const struct HashTable SVGPathSegLinetoVerticalAbsImpl::s_hashTable = { 2, 2, SVGPathSegLinetoVerticalAbsImpl__s_hashTableEntries, 2, SVGPathSegLinetoVerticalAbsImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegLinetoVerticalRelImpl__s_hashTableStrings[] = { + "\0" + "y\0" +}; + + +static const struct HashEntry SVGPathSegLinetoVerticalRelImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 1, SVGPathSegLinetoVerticalRelImpl::Y, DontDelete, 0, -1 } +}; + +const struct HashTable SVGPathSegLinetoVerticalRelImpl::s_hashTable = { 2, 2, SVGPathSegLinetoVerticalRelImpl__s_hashTableEntries, 2, SVGPathSegLinetoVerticalRelImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGPathSegListImpl.lut.h b/ksvg/data/SVGPathSegListImpl.lut.h new file mode 100644 index 00000000..8c4df29a --- /dev/null +++ b/ksvg/data/SVGPathSegListImpl.lut.h @@ -0,0 +1,55 @@ +/* Automatically generated from impl/SVGPathSegListImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegListImpl__s_hashTableStrings[] = { + "\0" + "numberOfItems\0" +}; + + +static const struct HashEntry SVGPathSegListImpl__s_hashTableEntries[] = { + { 1, SVGListDefs::NumberOfItems, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGPathSegListImpl::s_hashTable = { 2, 2, SVGPathSegListImpl__s_hashTableEntries, 2, SVGPathSegListImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegListImplProto__s_hashTableStrings[] = { + "\0" + "insertItemBefore\0" + "replaceItem\0" + "appendItem\0" + "initialize\0" + "removeItem\0" + "getItem\0" + "clear\0" +}; + + +static const struct HashEntry SVGPathSegListImplProto__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 71, SVGListDefs::Clear, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 63, SVGListDefs::GetItem, DontDelete|Function, 1, -1 }, + { 1, SVGListDefs::InsertItemBefore, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 41, SVGListDefs::Initialize, DontDelete|Function, 1, -1 }, + { 52, SVGListDefs::RemoveItem, DontDelete|Function, 1, 11 }, + { 18, SVGListDefs::ReplaceItem, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 30, SVGListDefs::AppendItem, DontDelete|Function, 1, -1 } +}; + +const struct HashTable SVGPathSegListImplProto::s_hashTable = { 2, 12, SVGPathSegListImplProto__s_hashTableEntries, 11, SVGPathSegListImplProto__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGPathSegMovetoImpl.lut.h b/ksvg/data/SVGPathSegMovetoImpl.lut.h new file mode 100644 index 00000000..60f1c70f --- /dev/null +++ b/ksvg/data/SVGPathSegMovetoImpl.lut.h @@ -0,0 +1,43 @@ +/* Automatically generated from impl/SVGPathSegMovetoImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegMovetoAbsImpl__s_hashTableStrings[] = { + "\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGPathSegMovetoAbsImpl__s_hashTableEntries[] = { + { 1, SVGPathSegMovetoAbsImpl::X, DontDelete, 0, -1 }, + { 3, SVGPathSegMovetoAbsImpl::Y, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGPathSegMovetoAbsImpl::s_hashTable = { 2, 3, SVGPathSegMovetoAbsImpl__s_hashTableEntries, 3, SVGPathSegMovetoAbsImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGPathSegMovetoRelImpl__s_hashTableStrings[] = { + "\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGPathSegMovetoRelImpl__s_hashTableEntries[] = { + { 1, SVGPathSegMovetoRelImpl::X, DontDelete, 0, -1 }, + { 3, SVGPathSegMovetoRelImpl::Y, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGPathSegMovetoRelImpl::s_hashTable = { 2, 3, SVGPathSegMovetoRelImpl__s_hashTableEntries, 3, SVGPathSegMovetoRelImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGPatternElementImpl.lut.h b/ksvg/data/SVGPatternElementImpl.lut.h new file mode 100644 index 00000000..dc5b4527 --- /dev/null +++ b/ksvg/data/SVGPatternElementImpl.lut.h @@ -0,0 +1,37 @@ +/* Automatically generated from impl/SVGPatternElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGPatternElementImpl__s_hashTableStrings[] = { + "\0" + "patternContentUnits\0" + "patternTransform\0" + "patternUnits\0" + "height\0" + "width\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGPatternElementImpl__s_hashTableEntries[] = { + { 66, SVGPatternElementImpl::Y, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGPatternElementImpl::PatternContentUnits, DontDelete|ReadOnly, 0, -1 }, + { 58, SVGPatternElementImpl::Width, DontDelete|ReadOnly, 0, -1 }, + { 51, SVGPatternElementImpl::Height, DontDelete|ReadOnly, 0, 12 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 64, SVGPatternElementImpl::X, DontDelete|ReadOnly, 0, 11 }, + { 38, SVGPatternElementImpl::PatternUnits, DontDelete|ReadOnly, 0, -1 }, + { 21, SVGPatternElementImpl::PatternTransform, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGPatternElementImpl::s_hashTable = { 2, 13, SVGPatternElementImpl__s_hashTableEntries, 11, SVGPatternElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGPointImpl.lut.h b/ksvg/data/SVGPointImpl.lut.h new file mode 100644 index 00000000..d024c947 --- /dev/null +++ b/ksvg/data/SVGPointImpl.lut.h @@ -0,0 +1,22 @@ +/* Automatically generated from impl/SVGPointImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGPointImpl__s_hashTableStrings[] = { + "\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGPointImpl__s_hashTableEntries[] = { + { 1, SVGPointImpl::X, DontDelete, 0, -1 }, + { 3, SVGPointImpl::Y, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGPointImpl::s_hashTable = { 2, 3, SVGPointImpl__s_hashTableEntries, 3, SVGPointImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGPointListImpl.lut.h b/ksvg/data/SVGPointListImpl.lut.h new file mode 100644 index 00000000..f483be1e --- /dev/null +++ b/ksvg/data/SVGPointListImpl.lut.h @@ -0,0 +1,55 @@ +/* Automatically generated from impl/SVGPointListImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGPointListImpl__s_hashTableStrings[] = { + "\0" + "numberOfItems\0" +}; + + +static const struct HashEntry SVGPointListImpl__s_hashTableEntries[] = { + { 1, SVGListDefs::NumberOfItems, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGPointListImpl::s_hashTable = { 2, 2, SVGPointListImpl__s_hashTableEntries, 2, SVGPointListImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGPointListImplProto__s_hashTableStrings[] = { + "\0" + "insertItemBefore\0" + "replaceItem\0" + "appendItem\0" + "initialize\0" + "removeItem\0" + "getItem\0" + "clear\0" +}; + + +static const struct HashEntry SVGPointListImplProto__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 71, SVGListDefs::Clear, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 63, SVGListDefs::GetItem, DontDelete|Function, 1, -1 }, + { 1, SVGListDefs::InsertItemBefore, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 41, SVGListDefs::Initialize, DontDelete|Function, 1, -1 }, + { 52, SVGListDefs::RemoveItem, DontDelete|Function, 1, 11 }, + { 18, SVGListDefs::ReplaceItem, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 30, SVGListDefs::AppendItem, DontDelete|Function, 1, -1 } +}; + +const struct HashTable SVGPointListImplProto::s_hashTable = { 2, 12, SVGPointListImplProto__s_hashTableEntries, 11, SVGPointListImplProto__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGPreserveAspectRatioImpl.lut.h b/ksvg/data/SVGPreserveAspectRatioImpl.lut.h new file mode 100644 index 00000000..3b73e594 --- /dev/null +++ b/ksvg/data/SVGPreserveAspectRatioImpl.lut.h @@ -0,0 +1,73 @@ +/* Automatically generated from impl/SVGPreserveAspectRatioImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGPreserveAspectRatioImpl__s_hashTableStrings[] = { + "\0" + "meetOrSlice\0" + "align\0" +}; + + +static const struct HashEntry SVGPreserveAspectRatioImpl__s_hashTableEntries[] = { + { 1, SVGPreserveAspectRatioImpl::MeetOrSlice, DontDelete, 0, -1 }, + { 13, SVGPreserveAspectRatioImpl::Align, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGPreserveAspectRatioImpl::s_hashTable = { 2, 3, SVGPreserveAspectRatioImpl__s_hashTableEntries, 3, SVGPreserveAspectRatioImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGPreserveAspectRatioImplConstructor__s_hashTableStrings[] = { + "\0" + "SVG_PRESERVEASPECTRATIO_XMAXYMAX\0" + "SVG_PRESERVEASPECTRATIO_XMAXYMID\0" + "SVG_PRESERVEASPECTRATIO_XMAXYMIN\0" + "SVG_PRESERVEASPECTRATIO_XMIDYMAX\0" + "SVG_PRESERVEASPECTRATIO_XMIDYMID\0" + "SVG_PRESERVEASPECTRATIO_XMIDYMIN\0" + "SVG_PRESERVEASPECTRATIO_XMINYMAX\0" + "SVG_PRESERVEASPECTRATIO_XMINYMID\0" + "SVG_PRESERVEASPECTRATIO_XMINYMIN\0" + "SVG_PRESERVEASPECTRATIO_UNKNOWN\0" + "SVG_PRESERVEASPECTRATIO_NONE\0" + "SVG_MEETORSLICE_UNKNOWN\0" + "SVG_MEETORSLICE_SLICE\0" + "SVG_MEETORSLICE_MEET\0" +}; + + +static const struct HashEntry SVGPreserveAspectRatioImplConstructor__s_hashTableEntries[] = { + { 67, KSVG::SVG_PRESERVEASPECTRATIO_XMAXYMIN, DontDelete|ReadOnly, 0, 18 }, + { 0, 0, 0, 0, -1 }, + { 1, KSVG::SVG_PRESERVEASPECTRATIO_XMAXYMAX, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 166, KSVG::SVG_PRESERVEASPECTRATIO_XMIDYMIN, DontDelete|ReadOnly, 0, 17 }, + { 0, 0, 0, 0, -1 }, + { 34, KSVG::SVG_PRESERVEASPECTRATIO_XMAXYMID, DontDelete|ReadOnly, 0, 19 }, + { 0, 0, 0, 0, -1 }, + { 330, KSVG::SVG_PRESERVEASPECTRATIO_NONE, DontDelete|ReadOnly, 0, -1 }, + { 298, KSVG::SVG_PRESERVEASPECTRATIO_UNKNOWN, DontDelete|ReadOnly, 0, 20 }, + { 383, KSVG::SVG_MEETORSLICE_SLICE, DontDelete|ReadOnly, 0, -1 }, + { 133, KSVG::SVG_PRESERVEASPECTRATIO_XMIDYMID, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 265, KSVG::SVG_PRESERVEASPECTRATIO_XMINYMIN, DontDelete|ReadOnly, 0, -1 }, + { 359, KSVG::SVG_MEETORSLICE_UNKNOWN, DontDelete|ReadOnly, 0, -1 }, + { 232, KSVG::SVG_PRESERVEASPECTRATIO_XMINYMID, DontDelete|ReadOnly, 0, -1 }, + { 199, KSVG::SVG_PRESERVEASPECTRATIO_XMINYMAX, DontDelete|ReadOnly, 0, -1 }, + { 100, KSVG::SVG_PRESERVEASPECTRATIO_XMIDYMAX, DontDelete|ReadOnly, 0, -1 }, + { 405, KSVG::SVG_MEETORSLICE_MEET, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGPreserveAspectRatioImplConstructor::s_hashTable = { 2, 21, SVGPreserveAspectRatioImplConstructor__s_hashTableEntries, 17, SVGPreserveAspectRatioImplConstructor__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGRadialGradientElementImpl.lut.h b/ksvg/data/SVGRadialGradientElementImpl.lut.h new file mode 100644 index 00000000..ab0f702e --- /dev/null +++ b/ksvg/data/SVGRadialGradientElementImpl.lut.h @@ -0,0 +1,30 @@ +/* Automatically generated from impl/SVGRadialGradientElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGRadialGradientElementImpl__s_hashTableStrings[] = { + "\0" + "cx\0" + "cy\0" + "fx\0" + "fy\0" + "r\0" +}; + + +static const struct HashEntry SVGRadialGradientElementImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGRadialGradientElementImpl::Cx, DontDelete|ReadOnly, 0, 7 }, + { 4, SVGRadialGradientElementImpl::Cy, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 7, SVGRadialGradientElementImpl::Fx, DontDelete|ReadOnly, 0, -1 }, + { 10, SVGRadialGradientElementImpl::Fy, DontDelete|ReadOnly, 0, -1 }, + { 13, SVGRadialGradientElementImpl::R, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGRadialGradientElementImpl::s_hashTable = { 2, 8, SVGRadialGradientElementImpl__s_hashTableEntries, 7, SVGRadialGradientElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGRectElementImpl.lut.h b/ksvg/data/SVGRectElementImpl.lut.h new file mode 100644 index 00000000..d51c06c9 --- /dev/null +++ b/ksvg/data/SVGRectElementImpl.lut.h @@ -0,0 +1,29 @@ +/* Automatically generated from impl/SVGRectElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGRectElementImpl__s_hashTableStrings[] = { + "\0" + "height\0" + "width\0" + "rx\0" + "ry\0" +}; + + +static const struct HashEntry SVGRectElementImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 15, SVGRectElementImpl::X, DontDelete|ReadOnly, 0, -1 }, + { 18, SVGRectElementImpl::Y, DontDelete|ReadOnly, 0, -1 }, + { 1, SVGRectElementImpl::Height, DontDelete|ReadOnly, 0, 7 }, + { 17, SVGRectElementImpl::Ry, DontDelete|ReadOnly, 0, -1 }, + { 8, SVGRectElementImpl::Width, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 14, SVGRectElementImpl::Rx, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGRectElementImpl::s_hashTable = { 2, 8, SVGRectElementImpl__s_hashTableEntries, 7, SVGRectElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGRectImpl.lut.h b/ksvg/data/SVGRectImpl.lut.h new file mode 100644 index 00000000..439835bc --- /dev/null +++ b/ksvg/data/SVGRectImpl.lut.h @@ -0,0 +1,26 @@ +/* Automatically generated from impl/SVGRectImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGRectImpl__s_hashTableStrings[] = { + "\0" + "height\0" + "width\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGRectImpl__s_hashTableEntries[] = { + { 14, SVGRectImpl::X, DontDelete, 0, -1 }, + { 16, SVGRectImpl::Y, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGRectImpl::Height, DontDelete, 0, -1 }, + { 8, SVGRectImpl::Width, DontDelete, 0, -1 } +}; + +const struct HashTable SVGRectImpl::s_hashTable = { 2, 5, SVGRectImpl__s_hashTableEntries, 5, SVGRectImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGSVGElementImpl.lut.h b/ksvg/data/SVGSVGElementImpl.lut.h new file mode 100644 index 00000000..530095f6 --- /dev/null +++ b/ksvg/data/SVGSVGElementImpl.lut.h @@ -0,0 +1,136 @@ +/* Automatically generated from impl/SVGSVGElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGSVGElementImpl__s_hashTableStrings[] = { + "\0" + "screenPixelToMillimeterX\0" + "screenPixelToMillimeterY\0" + "pixelUnitToMillimeterX\0" + "pixelUnitToMillimeterY\0" + "contentScriptType\0" + "contentStyleType\0" + "currentTranslate\0" + "useCurrentView\0" + "currentScale\0" + "onresize\0" + "onscroll\0" + "onunload\0" + "viewport\0" + "onerror\0" + "height\0" + "onzoom\0" + "width\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGSVGElementImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 186, SVGSVGElementImpl::OnScroll, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 241, SVGSVGElementImpl::X, DontDelete|ReadOnly, 0, 27 }, + { 243, SVGSVGElementImpl::Y, DontDelete|ReadOnly, 0, -1 }, + { 228, SVGSVGElementImpl::OnZoom, DontDelete, 0, -1 }, + { 115, SVGSVGElementImpl::ContentStyleType, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 149, SVGSVGElementImpl::UseCurrentView, DontDelete, 0, 24 }, + { 221, SVGSVGElementImpl::Height, DontDelete|ReadOnly, 0, 23 }, + { 74, SVGSVGElementImpl::PixelUnitToMillimeterY, DontDelete|ReadOnly, 0, 25 }, + { 0, 0, 0, 0, -1 }, + { 235, SVGSVGElementImpl::Width, DontDelete|ReadOnly, 0, -1 }, + { 97, SVGSVGElementImpl::ContentScriptType, DontDelete, 0, 26 }, + { 164, SVGSVGElementImpl::CurrentScale, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGSVGElementImpl::ScreenPixelToMillimeterX, DontDelete|ReadOnly, 0, -1 }, + { 26, SVGSVGElementImpl::ScreenPixelToMillimeterY, DontDelete|ReadOnly, 0, -1 }, + { 204, SVGSVGElementImpl::Viewport, DontDelete|ReadOnly, 0, -1 }, + { 51, SVGSVGElementImpl::PixelUnitToMillimeterX, DontDelete|ReadOnly, 0, -1 }, + { 132, SVGSVGElementImpl::CurrentTranslate, DontDelete|ReadOnly, 0, -1 }, + { 195, SVGSVGElementImpl::OnUnload, DontDelete, 0, -1 }, + { 213, SVGSVGElementImpl::OnError, DontDelete, 0, -1 }, + { 177, SVGSVGElementImpl::OnResize, DontDelete, 0, -1 } +}; + +const struct HashTable SVGSVGElementImpl::s_hashTable = { 2, 28, SVGSVGElementImpl__s_hashTableEntries, 23, SVGSVGElementImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGSVGElementImplProto__s_hashTableStrings[] = { + "\0" + "createSVGTransformFromMatrix\0" + "getIntersectionList\0" + "createSVGTransform\0" + "unsuspendRedrawAll\0" + "checkIntersection\0" + "unpauseAnimations\0" + "animationsPaused\0" + "getEnclosureList\0" + "createSVGLength\0" + "createSVGMatrix\0" + "createSVGNumber\0" + "unsuspendRedraw\0" + "checkEnclosure\0" + "createSVGAngle\0" + "createSVGPoint\0" + "getCurrentTime\0" + "getElementById\0" + "setCurrentTime\0" + "createSVGRect\0" + "deselectAll\0" + "forceRedraw\0" +}; + + +static const struct HashEntry SVGSVGElementImplProto__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 30, SVGSVGElementImpl::GetIntersectionList, DontDelete|Function, 2, 34 }, + { 124, SVGSVGElementImpl::AnimationsPaused, DontDelete|Function, 0, -1 }, + { 222, SVGSVGElementImpl::CheckEnclosure, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 190, SVGSVGElementImpl::CreateSVGNumber, DontDelete|Function, 0, 30 }, + { 0, 0, 0, 0, -1 }, + { 267, SVGSVGElementImpl::GetCurrentTime, DontDelete|Function, 0, -1 }, + { 338, SVGSVGElementImpl::ForceRedraw, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 88, SVGSVGElementImpl::CheckIntersection, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 106, SVGSVGElementImpl::UnpauseAnimations, DontDelete|Function, 0, -1 }, + { 1, SVGSVGElementImpl::CreateSVGTransformFromMatrix, DontDelete|Function, 1, 29 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 174, SVGSVGElementImpl::CreateSVGMatrix, DontDelete|Function, 0, -1 }, + { 312, SVGSVGElementImpl::CreateSVGRect, DontDelete|Function, 0, 31 }, + { 208, SVGSVGElementImpl::SuspendRedraw, DontDelete|Function, 1, 32 }, + { 237, SVGSVGElementImpl::CreateSVGAngle, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 141, SVGSVGElementImpl::GetEnclosureList, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 50, SVGSVGElementImpl::CreateSVGTransform, DontDelete|Function, 0, -1 }, + { 252, SVGSVGElementImpl::CreateSVGPoint, DontDelete|Function, 0, -1 }, + { 158, SVGSVGElementImpl::CreateSVGLength, DontDelete|Function, 0, -1 }, + { 206, SVGSVGElementImpl::UnsuspendRedraw, DontDelete|Function, 1, -1 }, + { 69, SVGSVGElementImpl::UnsuspendRedrawAll, DontDelete|Function, 0, -1 }, + { 108, SVGSVGElementImpl::PauseAnimations, DontDelete|Function, 0, -1 }, + { 297, SVGSVGElementImpl::SetCurrentTime, DontDelete|Function, 1, 33 }, + { 326, SVGSVGElementImpl::DeselectAll, DontDelete|Function, 0, -1 }, + { 282, SVGSVGElementImpl::GetElementById, DontDelete|Function, 1, -1 } +}; + +const struct HashTable SVGSVGElementImplProto::s_hashTable = { 2, 35, SVGSVGElementImplProto__s_hashTableEntries, 29, SVGSVGElementImplProto__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGScriptElementImpl.lut.h b/ksvg/data/SVGScriptElementImpl.lut.h new file mode 100644 index 00000000..661e35a2 --- /dev/null +++ b/ksvg/data/SVGScriptElementImpl.lut.h @@ -0,0 +1,20 @@ +/* Automatically generated from impl/SVGScriptElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGScriptElementImpl__s_hashTableStrings[] = { + "\0" + "type\0" +}; + + +static const struct HashEntry SVGScriptElementImpl__s_hashTableEntries[] = { + { 1, SVGScriptElementImpl::Type, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGScriptElementImpl::s_hashTable = { 2, 2, SVGScriptElementImpl__s_hashTableEntries, 2, SVGScriptElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGStopElementImpl.lut.h b/ksvg/data/SVGStopElementImpl.lut.h new file mode 100644 index 00000000..5bdc3a98 --- /dev/null +++ b/ksvg/data/SVGStopElementImpl.lut.h @@ -0,0 +1,22 @@ +/* Automatically generated from impl/SVGStopElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGStopElementImpl__s_hashTableStrings[] = { + "\0" + "stop-opacity\0" + "offset\0" +}; + + +static const struct HashEntry SVGStopElementImpl__s_hashTableEntries[] = { + { 1, SVGStopElementImpl::StopOpacity, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 14, SVGStopElementImpl::Offset, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGStopElementImpl::s_hashTable = { 2, 3, SVGStopElementImpl__s_hashTableEntries, 3, SVGStopElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGStringListImpl.lut.h b/ksvg/data/SVGStringListImpl.lut.h new file mode 100644 index 00000000..db89d010 --- /dev/null +++ b/ksvg/data/SVGStringListImpl.lut.h @@ -0,0 +1,74 @@ +/* Automatically generated from impl/SVGStringListImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SharedString__s_hashTableStrings[] = { + "\0" + "dummy\0" +}; + + +static const struct HashEntry SharedString__s_hashTableEntries[] = { + { 1, SharedString::Dummy, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SharedString::s_hashTable = { 2, 2, SharedString__s_hashTableEntries, 2, SharedString__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGStringListImpl__s_hashTableStrings[] = { + "\0" + "numberOfItems\0" +}; + + +static const struct HashEntry SVGStringListImpl__s_hashTableEntries[] = { + { 1, SVGListDefs::NumberOfItems, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGStringListImpl::s_hashTable = { 2, 2, SVGStringListImpl__s_hashTableEntries, 2, SVGStringListImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGStringListImplProto__s_hashTableStrings[] = { + "\0" + "insertItemBefore\0" + "replaceItem\0" + "appendItem\0" + "initialize\0" + "removeItem\0" + "getItem\0" + "clear\0" +}; + + +static const struct HashEntry SVGStringListImplProto__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 71, SVGListDefs::Clear, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 63, SVGListDefs::GetItem, DontDelete|Function, 1, -1 }, + { 1, SVGListDefs::InsertItemBefore, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 41, SVGListDefs::Initialize, DontDelete|Function, 1, -1 }, + { 52, SVGListDefs::RemoveItem, DontDelete|Function, 1, 11 }, + { 18, SVGListDefs::ReplaceItem, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 30, SVGListDefs::AppendItem, DontDelete|Function, 1, -1 } +}; + +const struct HashTable SVGStringListImplProto::s_hashTable = { 2, 12, SVGStringListImplProto__s_hashTableEntries, 11, SVGStringListImplProto__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGStylableImpl.lut.h b/ksvg/data/SVGStylableImpl.lut.h new file mode 100644 index 00000000..f6e0570f --- /dev/null +++ b/ksvg/data/SVGStylableImpl.lut.h @@ -0,0 +1,143 @@ +/* Automatically generated from impl/SVGStylableImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGStylableImpl__s_hashTableStrings[] = { + "\0" + "glyph-orientation-horizontal\0" + "glyph-orientation-vertical\0" + "color-interpolation\0" + "stroke-dashoffset\0" + "stroke-miterlimit\0" + "stroke-dasharray\0" + "stroke-linejoin\0" + "text-decoration\0" + "baseline-shift\0" + "letter-spacing\0" + "pointer-events\0" + "stroke-linecap\0" + "stroke-opacity\0" + "color-profile\0" + "fill-opacity\0" + "marker-start\0" + "stroke-width\0" + "unicode-bidi\0" + "word-spacing\0" + "writing-mode\0" + "font-family\0" + "font-weight\0" + "text-anchor\0" + "font-style\0" + "marker-end\0" + "marker-mid\0" + "stop-color\0" + "visibility\0" + "className\0" + "clip-path\0" + "clip-rule\0" + "direction\0" + "fill-rule\0" + "font-size\0" + "overflow\0" + "display\0" + "cursor\0" + "marker\0" + "stroke\0" + "clip\0" + "fill\0" + "mask\0" +}; + + +static const struct HashEntry SVGStylableImpl__s_hashTableEntries[] = { + { 523, SVGStylableImpl::Fill, DontDelete|ReadOnly, 0, -1 }, + { 518, SVGStylableImpl::Clip, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 341, SVGStylableImpl::FontWeight, DontDelete|ReadOnly, 0, -1 }, + { 353, SVGStylableImpl::TextAnchor, DontDelete|ReadOnly, 0, 52 }, + { 511, SVGStylableImpl::Stroke, DontDelete|ReadOnly, 0, 56 }, + { 251, SVGStylableImpl::FillOpacity, DontDelete|ReadOnly, 0, -1 }, + { 398, SVGStylableImpl::StopColor, DontDelete|ReadOnly, 0, 61 }, + { 256, SVGStylableImpl::Opacity, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 95, SVGStylableImpl::StrokeMiterlimit, DontDelete|ReadOnly, 0, 49 }, + { 497, SVGStylableImpl::Cursor, DontDelete|ReadOnly, 0, 60 }, + { 222, SVGStylableImpl::StrokeOpacity, DontDelete|ReadOnly, 0, 62 }, + { 130, SVGStylableImpl::StrokeLineJoin, DontDelete|ReadOnly, 0, 53 }, + { 409, SVGStylableImpl::Visibility, DontDelete|ReadOnly, 0, 57 }, + { 316, SVGStylableImpl::WritingMode, DontDelete|ReadOnly, 0, 58 }, + { 0, 0, 0, 0, -1 }, + { 192, SVGStylableImpl::PointerEvents, DontDelete|ReadOnly, 0, 63 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 450, SVGStylableImpl::Direction, DontDelete|ReadOnly, 0, 51 }, + { 0, 0, 0, 0, -1 }, + { 264, SVGStylableImpl::MarkerStart, DontDelete|ReadOnly, 0, 59 }, + { 0, 0, 0, 0, -1 }, + { 237, SVGStylableImpl::ColorProfile, DontDelete|ReadOnly, 0, -1 }, + { 420, SVGStylableImpl::ClassName, DontDelete|ReadOnly, 0, 48 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 57, SVGStylableImpl::ColorInterpolation, DontDelete|ReadOnly, 0, -1 }, + { 277, SVGStylableImpl::StrokeWidth, DontDelete|ReadOnly, 0, 47 }, + { 177, SVGStylableImpl::LetterSpacing, DontDelete|ReadOnly, 0, -1 }, + { 77, SVGStylableImpl::StrokeDashOffset, DontDelete|ReadOnly, 0, -1 }, + { 470, SVGStylableImpl::FontSize, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 480, SVGStylableImpl::Overflow, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 370, SVGStylableImpl::Style, DontDelete|ReadOnly, 0, -1 }, + { 329, SVGStylableImpl::FontFamily, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 207, SVGStylableImpl::StrokeLineCap, DontDelete|ReadOnly, 0, 55 }, + { 403, SVGStylableImpl::Color, DontDelete|ReadOnly, 0, -1 }, + { 365, SVGStylableImpl::FontStyle, DontDelete|ReadOnly, 0, 50 }, + { 146, SVGStylableImpl::TextDecoration, DontDelete|ReadOnly, 0, 54 }, + { 290, SVGStylableImpl::UnicodeBidi, DontDelete|ReadOnly, 0, -1 }, + { 430, SVGStylableImpl::ClipPath, DontDelete|ReadOnly, 0, 64 }, + { 387, SVGStylableImpl::MarkerMid, DontDelete|ReadOnly, 0, -1 }, + { 376, SVGStylableImpl::MarkerEnd, DontDelete|ReadOnly, 0, -1 }, + { 504, SVGStylableImpl::Marker, DontDelete|ReadOnly, 0, -1 }, + { 489, SVGStylableImpl::Display, DontDelete|ReadOnly, 0, -1 }, + { 460, SVGStylableImpl::FillRule, DontDelete|ReadOnly, 0, -1 }, + { 440, SVGStylableImpl::ClipRule, DontDelete|ReadOnly, 0, -1 }, + { 113, SVGStylableImpl::StrokeDashArray, DontDelete|ReadOnly, 0, -1 }, + { 162, SVGStylableImpl::BaselineShift, DontDelete|ReadOnly, 0, -1 }, + { 303, SVGStylableImpl::WordSpacing, DontDelete|ReadOnly, 0, -1 }, + { 30, SVGStylableImpl::GlyphOrientationVertical, DontDelete|ReadOnly, 0, -1 }, + { 1, SVGStylableImpl::GlyphOrientationHorizontal, DontDelete|ReadOnly, 0, -1 }, + { 528, SVGStylableImpl::Mask, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGStylableImpl::s_hashTable = { 2, 65, SVGStylableImpl__s_hashTableEntries, 47, SVGStylableImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGStylableImplProto__s_hashTableStrings[] = { + "\0" + "getStyle\0" +}; + + +static const struct HashEntry SVGStylableImplProto__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 1, SVGStylableImpl::GetStyle, DontDelete|Function, 0, -1 } +}; + +const struct HashTable SVGStylableImplProto::s_hashTable = { 2, 2, SVGStylableImplProto__s_hashTableEntries, 2, SVGStylableImplProto__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGStyleElementImpl.lut.h b/ksvg/data/SVGStyleElementImpl.lut.h new file mode 100644 index 00000000..9eb6c903 --- /dev/null +++ b/ksvg/data/SVGStyleElementImpl.lut.h @@ -0,0 +1,27 @@ +/* Automatically generated from impl/SVGStyleElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGStyleElementImpl__s_hashTableStrings[] = { + "\0" + "xmlspace\0" + "media\0" + "title\0" + "type\0" +}; + + +static const struct HashEntry SVGStyleElementImpl__s_hashTableEntries[] = { + { 22, SVGStyleElementImpl::Type, DontDelete, 0, -1 }, + { 1, SVGStyleElementImpl::Xmlspace, DontDelete, 0, 5 }, + { 10, SVGStyleElementImpl::Media, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 16, SVGStyleElementImpl::Title, DontDelete, 0, -1 } +}; + +const struct HashTable SVGStyleElementImpl::s_hashTable = { 2, 6, SVGStyleElementImpl__s_hashTableEntries, 5, SVGStyleElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGSymbolElementImpl.lut.h b/ksvg/data/SVGSymbolElementImpl.lut.h new file mode 100644 index 00000000..5dba1cce --- /dev/null +++ b/ksvg/data/SVGSymbolElementImpl.lut.h @@ -0,0 +1,22 @@ +/* Automatically generated from impl/SVGSymbolElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGSymbolElementImpl__s_hashTableStrings[] = { + "\0" + "height\0" + "width\0" +}; + + +static const struct HashEntry SVGSymbolElementImpl__s_hashTableEntries[] = { + { 1, SVGSymbolElementImpl::Height, DontDelete|ReadOnly, 0, -1 }, + { 8, SVGSymbolElementImpl::Width, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGSymbolElementImpl::s_hashTable = { 2, 3, SVGSymbolElementImpl__s_hashTableEntries, 3, SVGSymbolElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGTestsImpl.lut.h b/ksvg/data/SVGTestsImpl.lut.h new file mode 100644 index 00000000..07bf4f48 --- /dev/null +++ b/ksvg/data/SVGTestsImpl.lut.h @@ -0,0 +1,45 @@ +/* Automatically generated from impl/SVGTestsImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGTestsImpl__s_hashTableStrings[] = { + "\0" + "requiredExtensions\0" + "requiredFeatures\0" + "systemLanguage\0" +}; + + +static const struct HashEntry SVGTestsImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 20, SVGTestsImpl::RequiredFeatures, DontDelete|ReadOnly, 0, 5 }, + { 1, SVGTestsImpl::RequiredExtensions, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 37, SVGTestsImpl::SystemLanguage, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGTestsImpl::s_hashTable = { 2, 6, SVGTestsImpl__s_hashTableEntries, 5, SVGTestsImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGTestsImplProto__s_hashTableStrings[] = { + "\0" + "hasExtension\0" +}; + + +static const struct HashEntry SVGTestsImplProto__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 1, SVGTestsImpl::HasExtension, DontDelete|Function, 1, -1 } +}; + +const struct HashTable SVGTestsImplProto::s_hashTable = { 2, 2, SVGTestsImplProto__s_hashTableEntries, 2, SVGTestsImplProto__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGTextContentElementImpl.lut.h b/ksvg/data/SVGTextContentElementImpl.lut.h new file mode 100644 index 00000000..8e0bf2db --- /dev/null +++ b/ksvg/data/SVGTextContentElementImpl.lut.h @@ -0,0 +1,84 @@ +/* Automatically generated from impl/SVGTextContentElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGTextContentElementImpl__s_hashTableStrings[] = { + "\0" + "lengthAdjust\0" + "textLength\0" +}; + + +static const struct HashEntry SVGTextContentElementImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 14, SVGTextContentElementImpl::TextLength, DontDelete|ReadOnly, 0, 3 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGTextContentElementImpl::LengthAdjust, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGTextContentElementImpl::s_hashTable = { 2, 4, SVGTextContentElementImpl__s_hashTableEntries, 3, SVGTextContentElementImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGTextContentElementImplProto__s_hashTableStrings[] = { + "\0" + "getStartPositionOfChar\0" + "getComputedTextLength\0" + "getCharNumAtPosition\0" + "getEndPositionOfChar\0" + "getSubStringLength\0" + "getRotationOfChar\0" + "getNumberOfChars\0" + "getExtentOfChar\0" + "selectSubString\0" +}; + + +static const struct HashEntry SVGTextContentElementImplProto__s_hashTableEntries[] = { + { 88, SVGTextContentElementImpl::GetSubStringLength, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 67, SVGTextContentElementImpl::GetEndPositionOfChar, DontDelete|Function, 1, -1 }, + { 0, 0, 0, 0, -1 }, + { 107, SVGTextContentElementImpl::GetRotationOfChar, DontDelete|Function, 1, -1 }, + { 46, SVGTextContentElementImpl::GetCharNumAtPosition, DontDelete|Function, 1, -1 }, + { 24, SVGTextContentElementImpl::GetComputedTextLength, DontDelete|Function, 0, -1 }, + { 1, SVGTextContentElementImpl::GetStartPositionOfChar, DontDelete|Function, 1, 11 }, + { 142, SVGTextContentElementImpl::GetExtentOfChar, DontDelete|Function, 1, -1 }, + { 125, SVGTextContentElementImpl::GetNumberOfChars, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 158, SVGTextContentElementImpl::SelectSubString, DontDelete|Function, 2, -1 } +}; + +const struct HashTable SVGTextContentElementImplProto::s_hashTable = { 2, 12, SVGTextContentElementImplProto__s_hashTableEntries, 11, SVGTextContentElementImplProto__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGTextContentElementImplConstructor__s_hashTableStrings[] = { + "\0" + "LENGTHADJUST_SPACINGANDGLYPHS\0" + "LENGTHADJUST_SPACING\0" + "LENGTHADJUST_UNKNOWN\0" +}; + + +static const struct HashEntry SVGTextContentElementImplConstructor__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 31, KSVG::LENGTHADJUST_SPACING, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, KSVG::LENGTHADJUST_SPACINGANDGLYPHS, DontDelete|ReadOnly, 0, -1 }, + { 52, KSVG::LENGTHADJUST_UNKNOWN, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGTextContentElementImplConstructor::s_hashTable = { 2, 5, SVGTextContentElementImplConstructor__s_hashTableEntries, 5, SVGTextContentElementImplConstructor__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGTextPathElementImpl.lut.h b/ksvg/data/SVGTextPathElementImpl.lut.h new file mode 100644 index 00000000..b13c0b70 --- /dev/null +++ b/ksvg/data/SVGTextPathElementImpl.lut.h @@ -0,0 +1,56 @@ +/* Automatically generated from impl/SVGTextPathElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGTextPathElementImpl__s_hashTableStrings[] = { + "\0" + "startOffset\0" + "spacing\0" + "method\0" +}; + + +static const struct HashEntry SVGTextPathElementImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 21, SVGTextPathElementImpl::Method, DontDelete|ReadOnly, 0, 5 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGTextPathElementImpl::StartOffset, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 13, SVGTextPathElementImpl::Spacing, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGTextPathElementImpl::s_hashTable = { 2, 6, SVGTextPathElementImpl__s_hashTableEntries, 5, SVGTextPathElementImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGTextPathElementImplConstructor__s_hashTableStrings[] = { + "\0" + "TEXTPATH_SPACINGTYPE_UNKNOWN\0" + "TEXTPATH_METHODTYPE_STRETCH\0" + "TEXTPATH_METHODTYPE_UNKNOWN\0" + "TEXTPATH_SPACINGTYPE_EXACT\0" + "TEXTPATH_METHODTYPE_ALIGN\0" + "TEXTPATH_SPACINGTYPE_AUTO\0" +}; + + +static const struct HashEntry SVGTextPathElementImplConstructor__s_hashTableEntries[] = { + { 30, KSVG::TEXTPATH_METHODTYPE_STRETCH, DontDelete|ReadOnly, 0, -1 }, + { 139, KSVG::TEXTPATH_SPACINGTYPE_AUTO, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, KSVG::TEXTPATH_SPACINGTYPE_UNKNOWN, DontDelete|ReadOnly, 0, -1 }, + { 113, KSVG::TEXTPATH_METHODTYPE_ALIGN, DontDelete|ReadOnly, 0, -1 }, + { 58, KSVG::TEXTPATH_METHODTYPE_UNKNOWN, DontDelete|ReadOnly, 0, 7 }, + { 0, 0, 0, 0, -1 }, + { 86, KSVG::TEXTPATH_SPACINGTYPE_EXACT, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGTextPathElementImplConstructor::s_hashTable = { 2, 8, SVGTextPathElementImplConstructor__s_hashTableEntries, 7, SVGTextPathElementImplConstructor__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGTextPositioningElementImpl.lut.h b/ksvg/data/SVGTextPositioningElementImpl.lut.h new file mode 100644 index 00000000..de029165 --- /dev/null +++ b/ksvg/data/SVGTextPositioningElementImpl.lut.h @@ -0,0 +1,28 @@ +/* Automatically generated from impl/SVGTextPositioningElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGTextPositioningElementImpl__s_hashTableStrings[] = { + "\0" + "rotate\0" + "dx\0" + "dy\0" +}; + + +static const struct HashEntry SVGTextPositioningElementImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 9, SVGTextPositioningElementImpl::X, DontDelete|ReadOnly, 0, -1 }, + { 12, SVGTextPositioningElementImpl::Y, DontDelete|ReadOnly, 0, -1 }, + { 8, SVGTextPositioningElementImpl::Dx, DontDelete|ReadOnly, 0, -1 }, + { 11, SVGTextPositioningElementImpl::Dy, DontDelete|ReadOnly, 0, 7 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 1, SVGTextPositioningElementImpl::Rotate, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGTextPositioningElementImpl::s_hashTable = { 2, 8, SVGTextPositioningElementImpl__s_hashTableEntries, 7, SVGTextPositioningElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGTransformImpl.lut.h b/ksvg/data/SVGTransformImpl.lut.h new file mode 100644 index 00000000..aff39a3b --- /dev/null +++ b/ksvg/data/SVGTransformImpl.lut.h @@ -0,0 +1,89 @@ +/* Automatically generated from impl/SVGTransformImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGTransformImpl__s_hashTableStrings[] = { + "\0" + "matrix\0" + "angle\0" + "type\0" +}; + + +static const struct HashEntry SVGTransformImpl__s_hashTableEntries[] = { + { 14, SVGTransformImpl::Type, DontDelete|ReadOnly, 0, -1 }, + { 1, SVGTransformImpl::Matrix, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 8, SVGTransformImpl::Angle, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGTransformImpl::s_hashTable = { 2, 5, SVGTransformImpl__s_hashTableEntries, 5, SVGTransformImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGTransformImplProto__s_hashTableStrings[] = { + "\0" + "setTranslate\0" + "setMatrix\0" + "setRotate\0" + "setScale\0" + "setSkewX\0" + "setSkewY\0" +}; + + +static const struct HashEntry SVGTransformImplProto__s_hashTableEntries[] = { + { 1, SVGTransformImpl::SetTranslate, DontDelete|Function, 2, -1 }, + { 34, SVGTransformImpl::SetScale, DontDelete|Function, 2, -1 }, + { 14, SVGTransformImpl::SetMatrix, DontDelete|Function, 1, -1 }, + { 24, SVGTransformImpl::SetRotate, DontDelete|Function, 3, -1 }, + { 43, SVGTransformImpl::SetSkewX, DontDelete|Function, 1, -1 }, + { 52, SVGTransformImpl::SetSkewY, DontDelete|Function, 1, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGTransformImplProto::s_hashTable = { 2, 7, SVGTransformImplProto__s_hashTableEntries, 7, SVGTransformImplProto__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGTransformImplConstructor__s_hashTableStrings[] = { + "\0" + "SVG_TRANSFORM_TRANSLATE\0" + "SVG_TRANSFORM_UNKNOWN\0" + "SVG_TRANSFORM_MATRIX\0" + "SVG_TRANSFORM_ROTATE\0" + "SVG_TRANSFORM_SCALE\0" + "SVG_TRANSFORM_SKEWX\0" + "SVG_TRANSFORM_SKEWY\0" +}; + + +static const struct HashEntry SVGTransformImplConstructor__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 1, KSVG::SVG_TRANSFORM_TRANSLATE, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 109, KSVG::SVG_TRANSFORM_SKEWX, DontDelete|ReadOnly, 0, -1 }, + { 47, KSVG::SVG_TRANSFORM_MATRIX, DontDelete|ReadOnly, 0, 11 }, + { 89, KSVG::SVG_TRANSFORM_SCALE, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 25, KSVG::SVG_TRANSFORM_UNKNOWN, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 68, KSVG::SVG_TRANSFORM_ROTATE, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 129, KSVG::SVG_TRANSFORM_SKEWY, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGTransformImplConstructor::s_hashTable = { 2, 12, SVGTransformImplConstructor__s_hashTableEntries, 11, SVGTransformImplConstructor__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGTransformListImpl.lut.h b/ksvg/data/SVGTransformListImpl.lut.h new file mode 100644 index 00000000..8b186a8e --- /dev/null +++ b/ksvg/data/SVGTransformListImpl.lut.h @@ -0,0 +1,55 @@ +/* Automatically generated from impl/SVGTransformListImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGTransformListImpl__s_hashTableStrings[] = { + "\0" + "numberOfItems\0" +}; + + +static const struct HashEntry SVGTransformListImpl__s_hashTableEntries[] = { + { 1, SVGListDefs::NumberOfItems, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGTransformListImpl::s_hashTable = { 2, 2, SVGTransformListImpl__s_hashTableEntries, 2, SVGTransformListImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGTransformListImplProto__s_hashTableStrings[] = { + "\0" + "insertItemBefore\0" + "replaceItem\0" + "appendItem\0" + "initialize\0" + "removeItem\0" + "getItem\0" + "clear\0" +}; + + +static const struct HashEntry SVGTransformListImplProto__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 71, SVGListDefs::Clear, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 63, SVGListDefs::GetItem, DontDelete|Function, 1, -1 }, + { 1, SVGListDefs::InsertItemBefore, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 41, SVGListDefs::Initialize, DontDelete|Function, 1, -1 }, + { 52, SVGListDefs::RemoveItem, DontDelete|Function, 1, 11 }, + { 18, SVGListDefs::ReplaceItem, DontDelete|Function, 2, -1 }, + { 0, 0, 0, 0, -1 }, + { 30, SVGListDefs::AppendItem, DontDelete|Function, 1, -1 } +}; + +const struct HashTable SVGTransformListImplProto::s_hashTable = { 2, 12, SVGTransformListImplProto__s_hashTableEntries, 11, SVGTransformListImplProto__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGTransformableImpl.lut.h b/ksvg/data/SVGTransformableImpl.lut.h new file mode 100644 index 00000000..7ca5e81f --- /dev/null +++ b/ksvg/data/SVGTransformableImpl.lut.h @@ -0,0 +1,20 @@ +/* Automatically generated from impl/SVGTransformableImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGTransformableImpl__s_hashTableStrings[] = { + "\0" + "transform\0" +}; + + +static const struct HashEntry SVGTransformableImpl__s_hashTableEntries[] = { + { 1, SVGTransformableImpl::Transform, DontDelete, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGTransformableImpl::s_hashTable = { 2, 2, SVGTransformableImpl__s_hashTableEntries, 2, SVGTransformableImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGURIReferenceImpl.lut.h b/ksvg/data/SVGURIReferenceImpl.lut.h new file mode 100644 index 00000000..08eafcb6 --- /dev/null +++ b/ksvg/data/SVGURIReferenceImpl.lut.h @@ -0,0 +1,20 @@ +/* Automatically generated from impl/SVGURIReferenceImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGURIReferenceImpl__s_hashTableStrings[] = { + "\0" + "href\0" +}; + + +static const struct HashEntry SVGURIReferenceImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 1, SVGURIReferenceImpl::Href, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGURIReferenceImpl::s_hashTable = { 2, 2, SVGURIReferenceImpl__s_hashTableEntries, 2, SVGURIReferenceImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGUseElementImpl.lut.h b/ksvg/data/SVGUseElementImpl.lut.h new file mode 100644 index 00000000..8f249826 --- /dev/null +++ b/ksvg/data/SVGUseElementImpl.lut.h @@ -0,0 +1,36 @@ +/* Automatically generated from impl/SVGUseElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGUseElementImpl__s_hashTableStrings[] = { + "\0" + "animatedInstanceRoot\0" + "instanceRoot\0" + "height\0" + "width\0" + "href\0" + "x\0" + "y\0" +}; + + +static const struct HashEntry SVGUseElementImpl__s_hashTableEntries[] = { + { 55, SVGUseElementImpl::Y, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 48, SVGUseElementImpl::Href, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 42, SVGUseElementImpl::Width, DontDelete|ReadOnly, 0, -1 }, + { 35, SVGUseElementImpl::Height, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 22, SVGUseElementImpl::InstanceRoot, DontDelete|ReadOnly, 0, 11 }, + { 0, 0, 0, 0, -1 }, + { 53, SVGUseElementImpl::X, DontDelete|ReadOnly, 0, -1 }, + { 1, SVGUseElementImpl::AnimatedInstanceRoot, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGUseElementImpl::s_hashTable = { 2, 12, SVGUseElementImpl__s_hashTableEntries, 11, SVGUseElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGViewElementImpl.lut.h b/ksvg/data/SVGViewElementImpl.lut.h new file mode 100644 index 00000000..cbc29ca3 --- /dev/null +++ b/ksvg/data/SVGViewElementImpl.lut.h @@ -0,0 +1,20 @@ +/* Automatically generated from impl/SVGViewElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGViewElementImpl__s_hashTableStrings[] = { + "\0" + "viewTarget\0" +}; + + +static const struct HashEntry SVGViewElementImpl__s_hashTableEntries[] = { + { 1, SVGViewElementImpl::ViewTarget, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 } +}; + +const struct HashTable SVGViewElementImpl::s_hashTable = { 2, 2, SVGViewElementImpl__s_hashTableEntries, 2, SVGViewElementImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGZoomAndPanImpl.lut.h b/ksvg/data/SVGZoomAndPanImpl.lut.h new file mode 100644 index 00000000..7886c67f --- /dev/null +++ b/ksvg/data/SVGZoomAndPanImpl.lut.h @@ -0,0 +1,45 @@ +/* Automatically generated from impl/SVGZoomAndPanImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGZoomAndPanImpl__s_hashTableStrings[] = { + "\0" + "zoomAndPan\0" +}; + + +static const struct HashEntry SVGZoomAndPanImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 1, SVGZoomAndPanImpl::ZoomAndPan, DontDelete, 0, -1 } +}; + +const struct HashTable SVGZoomAndPanImpl::s_hashTable = { 2, 2, SVGZoomAndPanImpl__s_hashTableEntries, 2, SVGZoomAndPanImpl__s_hashTableStrings}; + +} // namespace + +using namespace KJS; + +namespace KSVG { + +static const char SVGZoomAndPanImplConstructor__s_hashTableStrings[] = { + "\0" + "SVG_ZOOMANDPAN_DISABLE\0" + "SVG_ZOOMANDPAN_MAGNIFY\0" + "SVG_ZOOMANDPAN_UNKNOWN\0" +}; + + +static const struct HashEntry SVGZoomAndPanImplConstructor__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 24, KSVG::SVG_ZOOMANDPAN_MAGNIFY, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 47, KSVG::SVG_ZOOMANDPAN_UNKNOWN, DontDelete|ReadOnly, 0, 5 }, + { 1, KSVG::SVG_ZOOMANDPAN_DISABLE, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGZoomAndPanImplConstructor::s_hashTable = { 2, 6, SVGZoomAndPanImplConstructor__s_hashTableEntries, 5, SVGZoomAndPanImplConstructor__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/SVGZoomEventImpl.lut.h b/ksvg/data/SVGZoomEventImpl.lut.h new file mode 100644 index 00000000..5f5a277b --- /dev/null +++ b/ksvg/data/SVGZoomEventImpl.lut.h @@ -0,0 +1,29 @@ +/* Automatically generated from impl/SVGZoomEventImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char SVGZoomEventImpl__s_hashTableStrings[] = { + "\0" + "previousTranslate\0" + "zoomRectScreen\0" + "previousScale\0" + "newTranslate\0" + "newScale\0" +}; + + +static const struct HashEntry SVGZoomEventImpl__s_hashTableEntries[] = { + { 0, 0, 0, 0, -1 }, + { 1, SVGZoomEventImpl::PreviousTranslate, DontDelete|ReadOnly, 0, -1 }, + { 34, SVGZoomEventImpl::PreviousScale, DontDelete|ReadOnly, 0, -1 }, + { 19, SVGZoomEventImpl::ZoomRectScreen, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 48, SVGZoomEventImpl::NewTranslate, DontDelete|ReadOnly, 0, -1 }, + { 61, SVGZoomEventImpl::NewScale, DontDelete|ReadOnly, 0, -1 } +}; + +const struct HashTable SVGZoomEventImpl::s_hashTable = { 2, 7, SVGZoomEventImpl__s_hashTableEntries, 7, SVGZoomEventImpl__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/data/ksvg_window.lut.h b/ksvg/data/ksvg_window.lut.h new file mode 100644 index 00000000..4b6d270b --- /dev/null +++ b/ksvg/data/ksvg_window.lut.h @@ -0,0 +1,98 @@ +/* Automatically generated from ecma/ksvg_window.cpp using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */ + +using namespace KJS; + +namespace KSVG { + +static const char KSVG__Window__s_hashTableStrings[] = { + "\0" + "SVGPreserveAspectRatio\0" + "SVGTextContentElement\0" + "getSVGViewerVersion\0" + "SVGGradientElement\0" + "SVGTextPathElement\0" + "SVGMarkerElement\0" + "SVGZoomAndPan\0" + "clearInterval\0" + "SVGTransform\0" + "clearTimeout\0" + "innerHeight\0" + "setInterval\0" + "svgDocument\0" + "SVGPathSeg\0" + "innerWidth\0" + "setTimeout\0" + "SVGLength\0" + "navigator\0" + "printNode\0" + "SVGAngle\0" + "SVGColor\0" + "SVGPaint\0" + "document\0" + "parseXML\0" + "confirm\0" + "postURL\0" + "success\0" + "closed\0" + "getURL\0" + "prompt\0" + "window\0" + "alert\0" + "debug\0" + "evt\0" +}; + + +static const struct HashEntry KSVG__Window__s_hashTableEntries[] = { + { 244, KSVG::Window::_SVGLength, DontDelete|ReadOnly, 0, 39 }, + { 0, 0, 0, 0, -1 }, + { 319, KSVG::Window::_Confirm, DontDelete|Function, 1, -1 }, + { 283, KSVG::Window::_SVGColor, DontDelete|ReadOnly, 0, -1 }, + { 162, KSVG::Window::_ClearTimeout, DontDelete|Function, 1, 41 }, + { 0, 0, 0, 0, -1 }, + { 149, KSVG::Window::_SVGTransform, DontDelete|ReadOnly, 0, 38 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 377, KSVG::Window::_Debug, DontDelete|Function, 1, -1 }, + { 0, 0, 0, 0, -1 }, + { 199, KSVG::Window::_Document, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 301, KSVG::Window::_Document, DontDelete|ReadOnly, 0, 34 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 327, KSVG::Window::_PostURL, DontDelete|Function, 5, -1 }, + { 364, KSVG::Window::_Window, DontDelete|ReadOnly, 0, -1 }, + { 175, KSVG::Window::_InnerHeight, DontDelete|ReadOnly, 0, 35 }, + { 0, 0, 0, 0, -1 }, + { 233, KSVG::Window::_SetTimeout, DontDelete|Function, 2, -1 }, + { 343, KSVG::Window::_Closed, DontDelete|ReadOnly, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 46, KSVG::Window::_GetSVGViewerVersion, DontDelete|Function, 0, -1 }, + { 0, 0, 0, 0, -1 }, + { 371, KSVG::Window::_Alert, DontDelete|Function, 1, -1 }, + { 1, KSVG::Window::_SVGPreserveAspectRatio, DontDelete|ReadOnly, 0, -1 }, + { 357, KSVG::Window::_Prompt, DontDelete|Function, 2, -1 }, + { 383, KSVG::Window::_Evt, DontDelete|ReadOnly, 0, 36 }, + { 135, KSVG::Window::_ClearInterval, DontDelete|Function, 1, -1 }, + { 0, 0, 0, 0, -1 }, + { 222, KSVG::Window::_InnerWidth, DontDelete|ReadOnly, 0, 43 }, + { 121, KSVG::Window::_SVGZoomAndPan, DontDelete|ReadOnly, 0, -1 }, + { 187, KSVG::Window::_SetInterval, DontDelete|Function, 2, 37 }, + { 254, KSVG::Window::_Navigator, DontDelete|ReadOnly, 0, 45 }, + { 264, KSVG::Window::_PrintNode, DontDelete|Function, 1, -1 }, + { 274, KSVG::Window::_SVGAngle, DontDelete|ReadOnly, 0, 44 }, + { 211, KSVG::Window::_SVGPathSeg, DontDelete|ReadOnly, 0, -1 }, + { 66, KSVG::Window::_SVGGradientElement, DontDelete|ReadOnly, 0, 40 }, + { 104, KSVG::Window::_SVGMarkerElement, DontDelete|ReadOnly, 0, 42 }, + { 85, KSVG::Window::_SVGTextPathElement, DontDelete|ReadOnly, 0, -1 }, + { 292, KSVG::Window::_SVGPaint, DontDelete|ReadOnly, 0, -1 }, + { 24, KSVG::Window::_SVGTextContentElement, DontDelete|ReadOnly, 0, 46 }, + { 335, KSVG::Window::_Success, DontDelete|Function, 1, -1 }, + { 350, KSVG::Window::_GetURL, DontDelete|Function, 2, -1 }, + { 310, KSVG::Window::_ParseXML, DontDelete|Function, 1, -1 } +}; + +const struct HashTable KSVG::Window::s_hashTable = { 2, 47, KSVG__Window__s_hashTableEntries, 34, KSVG__Window__s_hashTableStrings}; + +} // namespace diff --git a/ksvg/dom/Makefile.am b/ksvg/dom/Makefile.am new file mode 100644 index 00000000..9b6b1cf7 --- /dev/null +++ b/ksvg/dom/Makefile.am @@ -0,0 +1,58 @@ +noinst_LTLIBRARIES = libksvgdom.la + +myincludedir = $(includedir)/dom +myinclude_HEADERS = SVGAElement.h SVGAltGlyphElement.h SVGAltGlyphDefElement.h SVGGlyphRefElement.h SVGAngle.h SVGAnimateColorElement.h SVGAnimateElement.h \ + SVGAnimateMotionElement.h SVGAnimateTransformElement.h SVGAnimatedAngle.h SVGAnimatedBoolean.h \ + SVGAnimatedEnumeration.h SVGAnimatedInteger.h SVGAnimatedLength.h SVGAnimatedLengthList.h \ + SVGAnimatedNumber.h SVGAnimatedNumberList.h SVGAnimatedPathData.h SVGAnimatedPoints.h \ + SVGAnimatedPreserveAspectRatio.h SVGAnimatedRect.h SVGAnimatedString.h SVGAnimatedTransformList.h \ + SVGAnimationElement.h SVGCSSRule.h SVGCircleElement.h SVGClipPathElement.h SVGColor.h \ + SVGColorProfileElement.h SVGColorProfileRule.h SVGComponentTransferFunctionElement.h SVGCursorElement.h \ + SVGDefinitionSrcElement.h SVGDefsElement.h SVGDescElement.h SVGDocument.h SVGElement.h SVGElementInstance.h \ + SVGElementInstanceList.h SVGEllipseElement.h SVGEvent.h SVGException.h SVGExternalResourcesRequired.h \ + SVGFEBlendElement.h SVGFEColorMatrixElement.h SVGFEComponentTransferElement.h SVGFECompositeElement.h \ + SVGFEConvolveMatrixElement.h SVGFEDiffuseLightingElement.h SVGFEDisplacementMapElement.h SVGFEDistantLightElement.h \ + SVGFEFloodElement.h SVGFEFuncAElement.h SVGFEFuncBElement.h SVGFEFuncGElement.h SVGFEFuncRElement.h \ + SVGFEGaussianBlurElement.h SVGFEImageElement.h SVGFEMergeElement.h SVGFEMergeNodeElement.h SVGFEMorphologyElement.h \ + SVGFEOffsetElement.h SVGFEPointLightElement.h SVGFESpecularLightingElement.h SVGFESpotLightElement.h \ + SVGFETileElement.h SVGFETurbulenceElement.h SVGFilterElement.h SVGFilterPrimitiveStandardAttributes.h \ + SVGFitToViewBox.h SVGFontElement.h SVGFontFaceElement.h SVGFontFaceFormatElement.h SVGFontFaceNameElement.h \ + SVGFontFaceSrcElement.h SVGFontFaceUriElement.h SVGForeignObjectElement.h SVGGElement.h SVGGlyphElement.h \ + SVGGradientElement.h SVGHKernElement.h SVGICCColor.h SVGImageElement.h SVGLangSpace.h SVGLength.h SVGLengthList.h \ + SVGLineElement.h SVGLinearGradientElement.h SVGLocatable.h SVGMPathElement.h SVGMarkerElement.h SVGMaskElement.h \ + SVGMatrix.h SVGMetadataElement.h SVGMissingGlyphElement.h SVGNumber.h SVGNumberList.h SVGPaint.h SVGPathElement.h \ + SVGPathSeg.h SVGPathSegArc.h SVGPathSegClosePath.h SVGPathSegCurvetoCubic.h SVGPathSegCurvetoCubicSmooth.h \ + SVGPathSegCurvetoQuadratic.h SVGPathSegCurvetoQuadraticSmooth.h SVGPathSegLineto.h SVGPathSegLinetoHorizontal.h \ + SVGPathSegLinetoVertical.h SVGPathSegList.h SVGPathSegMoveto.h SVGPatternElement.h SVGPoint.h SVGPointList.h \ + SVGPolygonElement.h SVGPolylineElement.h SVGPreserveAspectRatio.h SVGRadialGradientElement.h SVGRect.h \ + SVGRectElement.h SVGRenderingIntent.h SVGSVGElement.h SVGScriptElement.h SVGSetElement.h SVGStopElement.h \ + SVGStringList.h SVGStylable.h SVGStyleElement.h SVGSwitchElement.h SVGSymbolElement.h SVGTRefElement.h \ + SVGTSpanElement.h SVGTests.h SVGTextContentElement.h SVGTextElement.h SVGTextPathElement.h SVGTextPositioningElement.h \ + SVGTitleElement.h SVGTransform.h SVGTransformList.h SVGTransformable.h SVGURIReference.h SVGUnitTypes.h \ + SVGUseElement.h SVGVKernElement.h SVGViewElement.h SVGViewSpec.h SVGWindow.h SVGZoomAndPan.h SVGZoomEvent.h + +libksvgdom_la_SOURCES = SVGLength.cc SVGAnimatedLength.cc SVGNumber.cc SVGAnimatedNumber.cc SVGPoint.cc SVGTSpanElement.cc SVGTRefElement.cc \ + SVGAnimatedLengthList.cc SVGAnimatedNumberList.cc SVGTransformList.cc SVGAElement.cc SVGAnimatedTransformList.cc \ + SVGRectElement.cc SVGCircleElement.cc SVGEllipseElement.cc SVGLineElement.cc SVGPolylineElement.cc SVGPolygonElement.cc \ + SVGTextPositioningElement.cc SVGTextContentElement.cc SVGTextElement.cc SVGImageElement.cc SVGUseElement.cc \ + SVGMatrix.cc SVGTransform.cc SVGPointList.cc SVGDocument.cc SVGAnimatedEnumeration.cc SVGDefsElement.cc \ + SVGLocatable.cc SVGTransformable.cc SVGStylable.cc SVGGElement.cc SVGAngle.cc SVGAnimatedAngle.cc \ + SVGColor.cc SVGPathElement.cc SVGPathSegList.cc SVGTests.cc SVGLangSpace.cc SVGStringList.cc \ + SVGPathSeg.cc SVGPathSegClosePath.cc SVGPathSegMoveto.cc SVGPathSegLinetoHorizontal.cc SVGPathSegLinetoVertical.cc SVGPathSegLineto.cc \ + SVGPathSegCurvetoCubic.cc SVGDescElement.cc SVGTitleElement.cc SVGExternalResourcesRequired.cc SVGAnimatedBoolean.cc SVGNumberList.cc \ + SVGPathSegCurvetoCubicSmooth.cc SVGPathSegCurvetoQuadratic.cc SVGAnimatedRect.cc SVGAnimatedString.cc \ + SVGPathSegCurvetoQuadraticSmooth.cc SVGPathSegArc.cc SVGURIReference.cc SVGAnimatedInteger.cc SVGLengthList.cc \ + SVGSVGElement.cc SVGRect.cc SVGFitToViewBox.cc SVGAnimatedPreserveAspectRatio.cc SVGPreserveAspectRatio.cc SVGElement.cc \ + SVGStyleElement.cc SVGClipPathElement.cc SVGMaskElement.cc SVGColorProfileElement.cc SVGColorProfileRule.cc SVGZoomAndPan.cc SVGScriptElement.cc \ + SVGSwitchElement.cc SVGSymbolElement.cc \ + SVGDefinitionSrcElement.cc SVGFontFaceElement.cc SVGFontFaceFormatElement.cc SVGFontFaceNameElement.cc SVGFontFaceSrcElement.cc SVGHKernElement.cc SVGMetadataElement.cc SVGVKernElement.cc SVGCursorElement.cc SVGForeignObjectElement.cc SVGFontFaceUriElement.cc \ + SVGElementInstance.cc SVGElementInstanceList.cc SVGAnimatedPoints.cc SVGAnimatedPathData.cc SVGMarkerElement.cc SVGViewSpec.cc SVGViewElement.cc \ + SVGFilterElement.cc SVGFilterPrimitiveStandardAttributes.cc SVGFEBlendElement.cc SVGFEColorMatrixElement.cc SVGFEComponentTransferElement.cc SVGComponentTransferFunctionElement.cc SVGFEFuncAElement.cc SVGFEFuncBElement.cc SVGFEFuncGElement.cc SVGFEFuncRElement.cc SVGFECompositeElement.cc SVGFEConvolveMatrixElement.cc SVGFEFloodElement.cc SVGFEGaussianBlurElement.cc SVGFEDiffuseLightingElement.cc SVGFEDistantLightElement.cc SVGFEPointLightElement.cc SVGFESpotLightElement.cc SVGFEDisplacementMapElement.cc SVGFEMergeElement.cc SVGFEMergeNodeElement.cc SVGFEImageElement.cc SVGFEMorphologyElement.cc SVGFEOffsetElement.cc SVGFESpecularLightingElement.cc SVGFETileElement.cc SVGFETurbulenceElement.cc \ + SVGAnimationElement.cc SVGAnimateElement.cc SVGSetElement.cc SVGAnimateMotionElement.cc SVGAnimateColorElement.cc SVGAnimateTransformElement.cc \ + SVGEvent.cc SVGZoomEvent.cc SVGICCColor.cc SVGCSSRule.cc \ + SVGGradientElement.cc SVGRadialGradientElement.cc SVGLinearGradientElement.cc SVGStopElement.cc SVGPatternElement.cc SVGMPathElement.cc \ + SVGFontElement.cc SVGAltGlyphElement.cc SVGGlyphRefElement.cc SVGAltGlyphDefElement.cc SVGGlyphElement.cc SVGMissingGlyphElement.cc SVGPaint.cc SVGTextPathElement.cc SVGWindow.cc + +libksvgdom_la_METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/ksvg/core -I$(top_srcdir)/ksvg/ecma -I$(top_srcdir)/ksvg/impl -I$(top_srcdir)/ksvg/impl/libs/libtext2path/src -I$(top_srcdir)/impl/ $(all_includes) diff --git a/ksvg/dom/SVGAElement.cc b/ksvg/dom/SVGAElement.cc new file mode 100644 index 00000000..a4d7d5b1 --- /dev/null +++ b/ksvg/dom/SVGAElement.cc @@ -0,0 +1,80 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAElement.h" +#include "SVGAElementImpl.h" +#include "SVGAnimatedString.h" + +using namespace KSVG; + +SVGAElement::SVGAElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable(), SVGURIReference() +{ + impl = 0; +} + +SVGAElement::SVGAElement(const SVGAElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGURIReference(other), impl(0) +{ + (*this) = other; +} + +SVGAElement &SVGAElement::operator=(const SVGAElement &other) +{ + SVGElement::operator=(other); + SVGTests::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + SVGTransformable::operator=(other); + SVGURIReference::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAElement::SVGAElement(SVGAElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGURIReference(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAElement::~SVGAElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedString SVGAElement::target() const +{ + if(!impl) return SVGAnimatedString(0); + return SVGAnimatedString(impl->target()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAElement.h b/ksvg/dom/SVGAElement.h new file mode 100644 index 00000000..98b0f54e --- /dev/null +++ b/ksvg/dom/SVGAElement.h @@ -0,0 +1,64 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAElement_H +#define SVGAElement_H + +#include "SVGElement.h" +#include "SVGTests.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGTransformable.h" +#include "SVGURIReference.h" + +namespace KSVG +{ + +class SVGAnimatedString; +class SVGAElementImpl; +class SVGAElement : public SVGElement, + public SVGTests, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGTransformable, + public SVGURIReference +{ +public: + SVGAElement(); + SVGAElement(const SVGAElement &other); + SVGAElement &operator=(const SVGAElement &other); + SVGAElement(SVGAElementImpl *other); + virtual ~SVGAElement(); + + SVGAnimatedString target() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAElementImpl *handle() const { return impl; } + +private: + SVGAElementImpl *impl; +}; + +} + +#endif +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAltGlyphDefElement.cc b/ksvg/dom/SVGAltGlyphDefElement.cc new file mode 100644 index 00000000..f150b982 --- /dev/null +++ b/ksvg/dom/SVGAltGlyphDefElement.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAltGlyphDefElement.h" +#include "SVGAltGlyphDefElementImpl.h" + +using namespace KSVG; + +SVGAltGlyphDefElement::SVGAltGlyphDefElement() : SVGElement() +{ + impl = 0; +} + +SVGAltGlyphDefElement::SVGAltGlyphDefElement(const SVGAltGlyphDefElement &other) : SVGElement(other), impl(0) +{ + (*this) = other; +} + +SVGAltGlyphDefElement &SVGAltGlyphDefElement::operator=(const SVGAltGlyphDefElement &other) +{ + SVGElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAltGlyphDefElement::SVGAltGlyphDefElement(SVGAltGlyphDefElementImpl *other) : SVGElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAltGlyphDefElement::~SVGAltGlyphDefElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAltGlyphDefElement.h b/ksvg/dom/SVGAltGlyphDefElement.h new file mode 100644 index 00000000..c0672cf6 --- /dev/null +++ b/ksvg/dom/SVGAltGlyphDefElement.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAltGlyphDefElement_H +#define SVGAltGlyphDefElement_H + +#include "SVGElement.h" + +namespace KSVG +{ + +class SVGAltGlyphDefElementImpl; +class SVGAltGlyphDefElement : public SVGElement +{ +public: + SVGAltGlyphDefElement(); + SVGAltGlyphDefElement(const SVGAltGlyphDefElement &other); + SVGAltGlyphDefElement &operator=(const SVGAltGlyphDefElement &other); + SVGAltGlyphDefElement(SVGAltGlyphDefElementImpl *other); + virtual ~SVGAltGlyphDefElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAltGlyphDefElementImpl *handle() const { return impl; } + +private: + SVGAltGlyphDefElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAltGlyphElement.cc b/ksvg/dom/SVGAltGlyphElement.cc new file mode 100644 index 00000000..33877a74 --- /dev/null +++ b/ksvg/dom/SVGAltGlyphElement.cc @@ -0,0 +1,80 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAltGlyphElement.h" +#include "SVGAltGlyphElementImpl.h" + +using namespace KSVG; + +SVGAltGlyphElement::SVGAltGlyphElement() : SVGTextPositioningElement(), SVGURIReference() +{ + impl = 0; +} + +SVGAltGlyphElement::SVGAltGlyphElement(const SVGAltGlyphElement &other) : SVGTextPositioningElement(other), SVGURIReference(other), impl(0) +{ + (*this) = other; +} + +SVGAltGlyphElement &SVGAltGlyphElement::operator=(const SVGAltGlyphElement &other) +{ + SVGTextPositioningElement::operator=(other); + SVGURIReference::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAltGlyphElement::SVGAltGlyphElement(SVGAltGlyphElementImpl *other) : SVGTextPositioningElement(other), SVGURIReference(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAltGlyphElement::~SVGAltGlyphElement() +{ + if(impl) + impl->deref(); +} + +DOM::DOMString SVGAltGlyphElement::format() +{ + if(!impl) return DOM::DOMString(); + return impl->format(); +} + +DOM::DOMString SVGAltGlyphElement::glyphRef() +{ + if(!impl) return DOM::DOMString(); + return impl->glyphRef(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAltGlyphElement.h b/ksvg/dom/SVGAltGlyphElement.h new file mode 100644 index 00000000..191c67fe --- /dev/null +++ b/ksvg/dom/SVGAltGlyphElement.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAltGlyphElement_H +#define SVGAltGlyphElement_H + +#include "SVGTextPositioningElement.h" +#include "SVGURIReference.h" + +namespace KSVG +{ + +class SVGAltGlyphElementImpl; +class SVGAltGlyphElement : public SVGTextPositioningElement, + public SVGURIReference +{ +public: + SVGAltGlyphElement(); + SVGAltGlyphElement(const SVGAltGlyphElement &other); + SVGAltGlyphElement &operator=(const SVGAltGlyphElement &other); + SVGAltGlyphElement(SVGAltGlyphElementImpl *other); + virtual ~SVGAltGlyphElement(); + + DOM::DOMString glyphRef(); + DOM::DOMString format(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAltGlyphElementImpl *handle() const { return impl; } + +private: + SVGAltGlyphElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAngle.cc b/ksvg/dom/SVGAngle.cc new file mode 100644 index 00000000..c3cb1fae --- /dev/null +++ b/ksvg/dom/SVGAngle.cc @@ -0,0 +1,120 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAngle.h" +#include "SVGAngleImpl.h" + +using namespace KSVG; + +SVGAngle::SVGAngle() +{ + impl = new SVGAngleImpl(); + impl->ref(); +} + +SVGAngle::SVGAngle(const SVGAngle &other) : impl(0) +{ + (*this) = other; +} + +SVGAngle &SVGAngle::operator =(const SVGAngle &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAngle::SVGAngle(SVGAngleImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAngle::~SVGAngle() +{ + if(impl) + impl->deref(); +} + +unsigned short SVGAngle::unitType() const +{ + if(!impl) return SVG_ANGLETYPE_UNKNOWN; + return impl->unitType(); +} + +void SVGAngle::setValue(float value) +{ + if(impl) + impl->setValue(value); +} + +float SVGAngle::value() const +{ + if(!impl) return -1; + return impl->value(); +} + +void SVGAngle::setValueInSpecifiedUnits(float valueInSpecifiedUnits) +{ + if(impl) + impl->setValueInSpecifiedUnits(valueInSpecifiedUnits); +} + +float SVGAngle::valueInSpecifiedUnits() const +{ + if(!impl) return -1; + return impl->valueInSpecifiedUnits(); +} + +void SVGAngle::setValueAsString(const DOM::DOMString &valueAsString) +{ + if(impl) + impl->setValueAsString(valueAsString); +} + +DOM::DOMString SVGAngle::valueAsString() const +{ + if(!impl) return DOM::DOMString(); + return impl->valueAsString(); +} + +void SVGAngle::newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits) +{ + if(impl) + impl->newValueSpecifiedUnits(unitType, valueInSpecifiedUnits); +} + +void SVGAngle::convertToSpecifiedUnits(unsigned short unitType) +{ + if(impl) + impl->convertToSpecifiedUnits(unitType); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAngle.h b/ksvg/dom/SVGAngle.h new file mode 100644 index 00000000..9e301660 --- /dev/null +++ b/ksvg/dom/SVGAngle.h @@ -0,0 +1,74 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAngle_H +#define SVGAngle_H + +#include + +namespace KSVG +{ + +enum +{ + SVG_ANGLETYPE_UNKNOWN = 0, + SVG_ANGLETYPE_UNSPECIFIED = 1, + SVG_ANGLETYPE_DEG = 2, + SVG_ANGLETYPE_RAD = 3, + SVG_ANGLETYPE_GRAD = 4 +}; + +class SVGAngleImpl; +class SVGAngle +{ +public: + + SVGAngle(); + SVGAngle(const SVGAngle &other); + SVGAngle &operator=(const SVGAngle &other); + SVGAngle(SVGAngleImpl *other); + ~SVGAngle(); + + unsigned short unitType() const; + + void setValue(float value); + float value() const; + + void setValueInSpecifiedUnits(float valueInSpecifiedUnits); + float valueInSpecifiedUnits() const; + + void setValueAsString(const DOM::DOMString &valueAsString); + DOM::DOMString valueAsString() const; + + void newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits); + void convertToSpecifiedUnits(unsigned short unitType); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAngleImpl *handle() const { return impl; } + +private: + SVGAngleImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimateColorElement.cc b/ksvg/dom/SVGAnimateColorElement.cc new file mode 100644 index 00000000..0090513f --- /dev/null +++ b/ksvg/dom/SVGAnimateColorElement.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimateColorElement.h" +#include "SVGAnimateColorElementImpl.h" + +using namespace KSVG; + +SVGAnimateColorElement::SVGAnimateColorElement() : SVGAnimationElement() +{ + impl = 0; +} + +SVGAnimateColorElement::SVGAnimateColorElement(const SVGAnimateColorElement &other) : SVGAnimationElement(other), impl(0) +{ + (*this) = other; +} + +SVGAnimateColorElement &SVGAnimateColorElement::operator=(const SVGAnimateColorElement &other) +{ + SVGAnimationElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAnimateColorElement::SVGAnimateColorElement(SVGAnimateColorElementImpl *other) : SVGAnimationElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAnimateColorElement::~SVGAnimateColorElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimateColorElement.h b/ksvg/dom/SVGAnimateColorElement.h new file mode 100644 index 00000000..3e5d1616 --- /dev/null +++ b/ksvg/dom/SVGAnimateColorElement.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimateColorElement_H +#define SVGAnimateColorElement_H + +#include "SVGAnimationElement.h" + +namespace KSVG +{ + +class SVGAnimateColorElementImpl; +class SVGAnimateColorElement : public SVGAnimationElement +{ +public: + SVGAnimateColorElement(); + SVGAnimateColorElement(const SVGAnimateColorElement &other); + SVGAnimateColorElement &operator=(const SVGAnimateColorElement &other); + SVGAnimateColorElement(SVGAnimateColorElementImpl *other); + virtual ~SVGAnimateColorElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAnimateColorElementImpl *handle() const { return impl; } + +private: + SVGAnimateColorElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimateElement.cc b/ksvg/dom/SVGAnimateElement.cc new file mode 100644 index 00000000..b0b4503e --- /dev/null +++ b/ksvg/dom/SVGAnimateElement.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimateElement.h" +#include "SVGAnimateElementImpl.h" + +using namespace KSVG; + +SVGAnimateElement::SVGAnimateElement() : SVGAnimationElement() +{ + impl = 0; +} + +SVGAnimateElement::SVGAnimateElement(const SVGAnimateElement &other) : SVGAnimationElement(other), impl(0) +{ + (*this) = other; +} + +SVGAnimateElement &SVGAnimateElement::operator=(const SVGAnimateElement &other) +{ + SVGAnimationElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAnimateElement::SVGAnimateElement(SVGAnimateElementImpl *other) : SVGAnimationElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAnimateElement::~SVGAnimateElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimateElement.h b/ksvg/dom/SVGAnimateElement.h new file mode 100644 index 00000000..5856f9b2 --- /dev/null +++ b/ksvg/dom/SVGAnimateElement.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimateElement_H +#define SVGAnimateElement_H + +#include "SVGAnimationElement.h" + +namespace KSVG +{ + +class SVGAnimateElementImpl; +class SVGAnimateElement : public SVGAnimationElement +{ +public: + SVGAnimateElement(); + SVGAnimateElement(const SVGAnimateElement &other); + SVGAnimateElement &operator=(const SVGAnimateElement &other); + SVGAnimateElement(SVGAnimateElementImpl *other); + virtual ~SVGAnimateElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAnimateElementImpl *handle() const { return impl; } + +private: + SVGAnimateElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimateMotionElement.cc b/ksvg/dom/SVGAnimateMotionElement.cc new file mode 100644 index 00000000..f2758fe3 --- /dev/null +++ b/ksvg/dom/SVGAnimateMotionElement.cc @@ -0,0 +1,65 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimateMotionElement.h" +#include "SVGAnimateMotionElementImpl.h" + +using namespace KSVG; + +SVGAnimateMotionElement::SVGAnimateMotionElement() : SVGAnimationElement() +{ + impl = 0; +} + +SVGAnimateMotionElement::SVGAnimateMotionElement(const SVGAnimateMotionElement &other) : SVGAnimationElement(), impl(0) +{ + (*this) = other; +} + +SVGAnimateMotionElement &SVGAnimateMotionElement::operator =(const SVGAnimateMotionElement &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAnimateMotionElement::SVGAnimateMotionElement(SVGAnimateMotionElementImpl *other) : SVGAnimationElement() +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAnimateMotionElement::~SVGAnimateMotionElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimateMotionElement.h b/ksvg/dom/SVGAnimateMotionElement.h new file mode 100644 index 00000000..62b477b0 --- /dev/null +++ b/ksvg/dom/SVGAnimateMotionElement.h @@ -0,0 +1,47 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimateMotionElement_H +#define SVGAnimateMotionElement_H + +#include "SVGAnimationElement.h" + +namespace KSVG +{ + +class SVGAnimateMotionElementImpl; +class SVGAnimateMotionElement : public SVGAnimationElement +{ +public: + SVGAnimateMotionElement(); + SVGAnimateMotionElement(const SVGAnimateMotionElement &other); + SVGAnimateMotionElement &operator=(const SVGAnimateMotionElement &other); + SVGAnimateMotionElement(SVGAnimateMotionElementImpl *other); + virtual ~SVGAnimateMotionElement(); + +private: + SVGAnimateMotionElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimateTransformElement.cc b/ksvg/dom/SVGAnimateTransformElement.cc new file mode 100644 index 00000000..91bbb9a3 --- /dev/null +++ b/ksvg/dom/SVGAnimateTransformElement.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimateTransformElement.h" +#include "SVGAnimateTransformElementImpl.h" + +using namespace KSVG; + +SVGAnimateTransformElement::SVGAnimateTransformElement() : SVGAnimationElement() +{ + impl = 0; +} + +SVGAnimateTransformElement::SVGAnimateTransformElement(const SVGAnimateTransformElement &other) : SVGAnimationElement(other), impl(0) +{ + (*this) = other; +} + +SVGAnimateTransformElement &SVGAnimateTransformElement::operator=(const SVGAnimateTransformElement &other) +{ + SVGAnimationElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAnimateTransformElement::SVGAnimateTransformElement(SVGAnimateTransformElementImpl *other) : SVGAnimationElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAnimateTransformElement::~SVGAnimateTransformElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimateTransformElement.h b/ksvg/dom/SVGAnimateTransformElement.h new file mode 100644 index 00000000..b6c1a5ad --- /dev/null +++ b/ksvg/dom/SVGAnimateTransformElement.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimateTransformElement_H +#define SVGAnimateTransformElement_H + +#include "SVGAnimationElement.h" + +namespace KSVG +{ + +class SVGAnimateTransformElementImpl; +class SVGAnimateTransformElement : public SVGAnimationElement +{ +public: + SVGAnimateTransformElement(); + SVGAnimateTransformElement(const SVGAnimateTransformElement &other); + SVGAnimateTransformElement &operator=(const SVGAnimateTransformElement &other); + SVGAnimateTransformElement(SVGAnimateTransformElementImpl *other); + virtual ~SVGAnimateTransformElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAnimateTransformElementImpl *handle() const { return impl; } + +private: + SVGAnimateTransformElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedAngle.cc b/ksvg/dom/SVGAnimatedAngle.cc new file mode 100644 index 00000000..b8c4ff4d --- /dev/null +++ b/ksvg/dom/SVGAnimatedAngle.cc @@ -0,0 +1,79 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedAngle.h" +#include "SVGAnimatedAngleImpl.h" +#include "SVGAngle.h" + +using namespace KSVG; + +SVGAnimatedAngle::SVGAnimatedAngle() +{ + impl = new SVGAnimatedAngleImpl(); + impl->ref(); +} + +SVGAnimatedAngle::SVGAnimatedAngle(const SVGAnimatedAngle &other) : impl(0) +{ + (*this) = other; +} + +SVGAnimatedAngle &SVGAnimatedAngle::operator=(const SVGAnimatedAngle &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAnimatedAngle::SVGAnimatedAngle(SVGAnimatedAngleImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAnimatedAngle::~SVGAnimatedAngle() +{ + if(impl) + impl->deref(); +} + +SVGAngle SVGAnimatedAngle::baseVal() const +{ + if(!impl) return SVGAngle(0); + return SVGAngle(impl->baseVal()); +} + +SVGAngle SVGAnimatedAngle::animVal() const +{ + if(!impl) return SVGAngle(0); + return SVGAngle(impl->animVal()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedAngle.h b/ksvg/dom/SVGAnimatedAngle.h new file mode 100644 index 00000000..156b9c39 --- /dev/null +++ b/ksvg/dom/SVGAnimatedAngle.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedAngle_H +#define SVGAnimatedAngle_H + +namespace KSVG +{ + +class SVGAngle; +class SVGAnimatedAngleImpl; +class SVGAnimatedAngle +{ +public: + SVGAnimatedAngle(); + SVGAnimatedAngle(const SVGAnimatedAngle &other); + SVGAnimatedAngle &operator=(const SVGAnimatedAngle &other); + SVGAnimatedAngle(SVGAnimatedAngleImpl *other); + ~SVGAnimatedAngle(); + + SVGAngle baseVal() const; + SVGAngle animVal() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAnimatedAngleImpl *handle() const { return impl; } + +private: + SVGAnimatedAngleImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedBoolean.cc b/ksvg/dom/SVGAnimatedBoolean.cc new file mode 100644 index 00000000..40bb765b --- /dev/null +++ b/ksvg/dom/SVGAnimatedBoolean.cc @@ -0,0 +1,84 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedBoolean.h" +#include "SVGAnimatedBooleanImpl.h" + +using namespace KSVG; + +SVGAnimatedBoolean::SVGAnimatedBoolean() +{ + impl = new SVGAnimatedBooleanImpl(); + impl->ref(); +} + +SVGAnimatedBoolean::SVGAnimatedBoolean(const SVGAnimatedBoolean &other) : impl(0) +{ + (*this) = other; +} + +SVGAnimatedBoolean &SVGAnimatedBoolean::operator=(const SVGAnimatedBoolean &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAnimatedBoolean::SVGAnimatedBoolean(SVGAnimatedBooleanImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAnimatedBoolean::~SVGAnimatedBoolean() +{ + if(impl) + impl->deref(); +} + +void SVGAnimatedBoolean::setBaseVal(bool baseVal) +{ + if(impl) + impl->setBaseVal(baseVal); +} + +bool SVGAnimatedBoolean::baseVal() const +{ + if(!impl) return false; + return impl->baseVal(); +} + +bool SVGAnimatedBoolean::animVal() const +{ + if(!impl) return false; + return impl->animVal(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedBoolean.h b/ksvg/dom/SVGAnimatedBoolean.h new file mode 100644 index 00000000..c223fa9a --- /dev/null +++ b/ksvg/dom/SVGAnimatedBoolean.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedBoolean_H +#define SVGAnimatedBoolean_H + +namespace KSVG +{ + +class SVGAnimatedBooleanImpl; +class SVGAnimatedBoolean +{ +public: + SVGAnimatedBoolean(); + SVGAnimatedBoolean(const SVGAnimatedBoolean &other); + SVGAnimatedBoolean &operator=(const SVGAnimatedBoolean &other); + SVGAnimatedBoolean(SVGAnimatedBooleanImpl *other); + ~SVGAnimatedBoolean(); + + void setBaseVal(bool baseVal); + bool baseVal() const; + + bool animVal() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAnimatedBooleanImpl *handle() const { return impl; } + +private: + SVGAnimatedBooleanImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedEnumeration.cc b/ksvg/dom/SVGAnimatedEnumeration.cc new file mode 100644 index 00000000..2e9610d4 --- /dev/null +++ b/ksvg/dom/SVGAnimatedEnumeration.cc @@ -0,0 +1,84 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedEnumeration.h" +#include "SVGAnimatedEnumerationImpl.h" + +using namespace KSVG; + +SVGAnimatedEnumeration::SVGAnimatedEnumeration() +{ + impl = new SVGAnimatedEnumerationImpl(); + impl->ref(); +} + +SVGAnimatedEnumeration::SVGAnimatedEnumeration(const SVGAnimatedEnumeration &other) : impl(0) +{ + (*this) = other; +} + +SVGAnimatedEnumeration &SVGAnimatedEnumeration::operator=(const SVGAnimatedEnumeration &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAnimatedEnumeration::SVGAnimatedEnumeration(SVGAnimatedEnumerationImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAnimatedEnumeration::~SVGAnimatedEnumeration() +{ + if(impl) + impl->deref(); +} + +void SVGAnimatedEnumeration::setBaseVal(unsigned short baseVal) +{ + if(impl) + impl->setBaseVal(baseVal); +} + +unsigned short SVGAnimatedEnumeration::baseVal() const +{ + if(!impl) return 0; + return impl->baseVal(); +} + +unsigned short SVGAnimatedEnumeration::animVal() const +{ + if(!impl) return 0; + return impl->animVal(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedEnumeration.h b/ksvg/dom/SVGAnimatedEnumeration.h new file mode 100644 index 00000000..79f75a67 --- /dev/null +++ b/ksvg/dom/SVGAnimatedEnumeration.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedEnumeration_H +#define SVGAnimatedEnumeration_H + +namespace KSVG +{ + +class SVGAnimatedEnumerationImpl; +class SVGAnimatedEnumeration +{ +public: + SVGAnimatedEnumeration(); + SVGAnimatedEnumeration(const SVGAnimatedEnumeration &other); + SVGAnimatedEnumeration &operator=(const SVGAnimatedEnumeration &other); + SVGAnimatedEnumeration(SVGAnimatedEnumerationImpl *other); + ~SVGAnimatedEnumeration(); + + void setBaseVal(unsigned short baseVal); + unsigned short baseVal() const; + + unsigned short animVal() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAnimatedEnumerationImpl *handle() const { return impl; } + +private: + SVGAnimatedEnumerationImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedInteger.cc b/ksvg/dom/SVGAnimatedInteger.cc new file mode 100644 index 00000000..df5f9011 --- /dev/null +++ b/ksvg/dom/SVGAnimatedInteger.cc @@ -0,0 +1,84 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedInteger.h" +#include "SVGAnimatedIntegerImpl.h" + +using namespace KSVG; + +SVGAnimatedInteger::SVGAnimatedInteger() +{ + impl = new SVGAnimatedIntegerImpl(); + impl->ref(); +} + +SVGAnimatedInteger::SVGAnimatedInteger(const SVGAnimatedInteger &other) : impl(0) +{ + (*this) = other; +} + +SVGAnimatedInteger &SVGAnimatedInteger::operator=(const SVGAnimatedInteger &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAnimatedInteger::SVGAnimatedInteger(SVGAnimatedIntegerImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAnimatedInteger::~SVGAnimatedInteger() +{ + if(impl) + impl->deref(); +} + +void SVGAnimatedInteger::setBaseVal(long baseVal) +{ + if(impl) + impl->setBaseVal(baseVal); +} + +long SVGAnimatedInteger::baseVal() const +{ + if(!impl) return -1; + return impl->baseVal(); +} + +long SVGAnimatedInteger::animVal() const +{ + if(!impl) return -1; + return impl->animVal(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedInteger.h b/ksvg/dom/SVGAnimatedInteger.h new file mode 100644 index 00000000..495cda75 --- /dev/null +++ b/ksvg/dom/SVGAnimatedInteger.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedInteger_H +#define SVGAnimatedInteger_H + +namespace KSVG +{ + +class SVGAnimatedIntegerImpl; +class SVGAnimatedInteger +{ +public: + SVGAnimatedInteger(); + SVGAnimatedInteger(const SVGAnimatedInteger &other); + SVGAnimatedInteger &operator=(const SVGAnimatedInteger &other); + SVGAnimatedInteger(SVGAnimatedIntegerImpl *other); + ~SVGAnimatedInteger(); + + void setBaseVal(long baseVal); + long baseVal() const; + + long animVal() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAnimatedIntegerImpl *handle() const { return impl; } + +private: + SVGAnimatedIntegerImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedLength.cc b/ksvg/dom/SVGAnimatedLength.cc new file mode 100644 index 00000000..50172f13 --- /dev/null +++ b/ksvg/dom/SVGAnimatedLength.cc @@ -0,0 +1,79 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedLength.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGLength.h" + +using namespace KSVG; + +SVGAnimatedLength::SVGAnimatedLength() +{ + impl = new SVGAnimatedLengthImpl(); + impl->ref(); +} + +SVGAnimatedLength::SVGAnimatedLength(const SVGAnimatedLength &other) : impl(0) +{ + (*this) = other; +} + +SVGAnimatedLength &SVGAnimatedLength::operator=(const SVGAnimatedLength &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAnimatedLength::SVGAnimatedLength(SVGAnimatedLengthImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAnimatedLength::~SVGAnimatedLength() +{ + if(impl) + impl->deref(); +} + +SVGLength SVGAnimatedLength::baseVal() const +{ + if(!impl) return SVGLength(0); + return SVGLength(impl->baseVal()); +} + +SVGLength SVGAnimatedLength::animVal() const +{ + if(!impl) return SVGLength(0); + return SVGLength(impl->animVal()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedLength.h b/ksvg/dom/SVGAnimatedLength.h new file mode 100644 index 00000000..a59792e3 --- /dev/null +++ b/ksvg/dom/SVGAnimatedLength.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedLength_H +#define SVGAnimatedLength_H + +namespace KSVG +{ + +class SVGLength; +class SVGAnimatedLengthImpl; +class SVGAnimatedLength +{ +public: + SVGAnimatedLength(); + SVGAnimatedLength(const SVGAnimatedLength &other); + SVGAnimatedLength &operator=(const SVGAnimatedLength &other); + SVGAnimatedLength(SVGAnimatedLengthImpl *other); + ~SVGAnimatedLength(); + + SVGLength baseVal() const; + SVGLength animVal() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAnimatedLengthImpl *handle() const { return impl; } + +private: + SVGAnimatedLengthImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedLengthList.cc b/ksvg/dom/SVGAnimatedLengthList.cc new file mode 100644 index 00000000..f1e9c001 --- /dev/null +++ b/ksvg/dom/SVGAnimatedLengthList.cc @@ -0,0 +1,78 @@ +/* + Copyright (C) 2002 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedLengthList.h" +#include "SVGAnimatedLengthListImpl.h" + +using namespace KSVG; + +SVGAnimatedLengthList::SVGAnimatedLengthList() +{ + impl = new SVGAnimatedLengthListImpl(); + impl->ref(); +} + +SVGAnimatedLengthList::SVGAnimatedLengthList(const SVGAnimatedLengthList &other) : impl(0) +{ + (*this) = other; +} + +SVGAnimatedLengthList &SVGAnimatedLengthList::operator=(const SVGAnimatedLengthList &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAnimatedLengthList::SVGAnimatedLengthList(SVGAnimatedLengthListImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAnimatedLengthList::~SVGAnimatedLengthList() +{ + if(impl) + impl->deref(); +} + +SVGLengthList SVGAnimatedLengthList::baseVal() const +{ + if(!impl) return 0; + return impl->animVal(); +} + +SVGLengthList SVGAnimatedLengthList::animVal() const +{ + if(!impl) return 0; + return impl->baseVal(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedLengthList.h b/ksvg/dom/SVGAnimatedLengthList.h new file mode 100644 index 00000000..80eafb03 --- /dev/null +++ b/ksvg/dom/SVGAnimatedLengthList.h @@ -0,0 +1,51 @@ +/* + Copyright (C) 2002 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedLengthList_H +#define SVGAnimatedLengthList_H + +#include "SVGLengthList.h" + +namespace KSVG +{ + +class SVGAnimatedLengthListImpl; +class SVGAnimatedLengthList +{ +public: + SVGAnimatedLengthList(); + SVGAnimatedLengthList(const SVGAnimatedLengthList &); + SVGAnimatedLengthList &operator=(const SVGAnimatedLengthList &); + SVGAnimatedLengthList(SVGAnimatedLengthListImpl *); + ~SVGAnimatedLengthList(); + + SVGLengthList baseVal() const; + SVGLengthList animVal() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAnimatedLengthListImpl *handle() const { return impl; } + +private: + SVGAnimatedLengthListImpl *impl; +}; + +} + +#endif diff --git a/ksvg/dom/SVGAnimatedNumber.cc b/ksvg/dom/SVGAnimatedNumber.cc new file mode 100644 index 00000000..9e801842 --- /dev/null +++ b/ksvg/dom/SVGAnimatedNumber.cc @@ -0,0 +1,84 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedNumber.h" +#include "SVGAnimatedNumberImpl.h" + +using namespace KSVG; + +SVGAnimatedNumber::SVGAnimatedNumber() +{ + impl = new SVGAnimatedNumberImpl(); + impl->ref(); +} + +SVGAnimatedNumber::SVGAnimatedNumber(const SVGAnimatedNumber &other) : impl(0) +{ + (*this) = other; +} + +SVGAnimatedNumber &SVGAnimatedNumber::operator=(const SVGAnimatedNumber &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAnimatedNumber::SVGAnimatedNumber(SVGAnimatedNumberImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAnimatedNumber::~SVGAnimatedNumber() +{ + if(impl) + impl->deref(); +} + +void SVGAnimatedNumber::setBaseVal(float baseVal) +{ + if(impl) + impl->setBaseVal(baseVal); +} + +float SVGAnimatedNumber::baseVal() const +{ + if(!impl) return -1; + return impl->baseVal(); +} + +float SVGAnimatedNumber::animVal() const +{ + if(!impl) return -1; + return impl->animVal(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedNumber.h b/ksvg/dom/SVGAnimatedNumber.h new file mode 100644 index 00000000..8c3f1670 --- /dev/null +++ b/ksvg/dom/SVGAnimatedNumber.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedNumber_H +#define SVGAnimatedNumber_H + +namespace KSVG +{ + +class SVGAnimatedNumberImpl; +class SVGAnimatedNumber +{ +public: + SVGAnimatedNumber(); + SVGAnimatedNumber(const SVGAnimatedNumber &other); + SVGAnimatedNumber &operator=(const SVGAnimatedNumber &other); + SVGAnimatedNumber(SVGAnimatedNumberImpl *other); + ~SVGAnimatedNumber(); + + void setBaseVal(float baseVal); + float baseVal() const; + + float animVal() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAnimatedNumberImpl *handle() const { return impl; } + +private: + SVGAnimatedNumberImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedNumberList.cc b/ksvg/dom/SVGAnimatedNumberList.cc new file mode 100644 index 00000000..66881cac --- /dev/null +++ b/ksvg/dom/SVGAnimatedNumberList.cc @@ -0,0 +1,78 @@ +/* + Copyright (C) 2002 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedNumberList.h" +#include "SVGAnimatedNumberListImpl.h" + +using namespace KSVG; + +SVGAnimatedNumberList::SVGAnimatedNumberList() +{ + impl = new SVGAnimatedNumberListImpl(); + impl->ref(); +} + +SVGAnimatedNumberList::SVGAnimatedNumberList(const SVGAnimatedNumberList &other) : impl(0) +{ + (*this) = other; +} + +SVGAnimatedNumberList &SVGAnimatedNumberList::operator=(const SVGAnimatedNumberList &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAnimatedNumberList::SVGAnimatedNumberList(SVGAnimatedNumberListImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAnimatedNumberList::~SVGAnimatedNumberList() +{ + if(impl) + impl->deref(); +} + +SVGNumberList SVGAnimatedNumberList::baseVal() const +{ + if(!impl) return 0; + return impl->animVal(); +} + +SVGNumberList SVGAnimatedNumberList::animVal() const +{ + if(!impl) return 0; + return impl->baseVal(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedNumberList.h b/ksvg/dom/SVGAnimatedNumberList.h new file mode 100644 index 00000000..525ce0fd --- /dev/null +++ b/ksvg/dom/SVGAnimatedNumberList.h @@ -0,0 +1,51 @@ +/* + Copyright (C) 2002 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedNumberList_H +#define SVGAnimatedNumberList_H + +#include "SVGNumberList.h" + +namespace KSVG +{ + +class SVGAnimatedNumberListImpl; +class SVGAnimatedNumberList +{ +public: + SVGAnimatedNumberList(); + SVGAnimatedNumberList(const SVGAnimatedNumberList &); + SVGAnimatedNumberList &operator=(const SVGAnimatedNumberList &); + SVGAnimatedNumberList(SVGAnimatedNumberListImpl *); + ~SVGAnimatedNumberList(); + + SVGNumberList baseVal() const; + SVGNumberList animVal() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAnimatedNumberListImpl *handle() const { return impl; } + +private: + SVGAnimatedNumberListImpl *impl; +}; + +} + +#endif diff --git a/ksvg/dom/SVGAnimatedPathData.cc b/ksvg/dom/SVGAnimatedPathData.cc new file mode 100644 index 00000000..d332f567 --- /dev/null +++ b/ksvg/dom/SVGAnimatedPathData.cc @@ -0,0 +1,91 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedPathData.h" +#include "SVGAnimatedPathDataImpl.h" +#include "SVGPathSegList.h" + +using namespace KSVG; + +SVGAnimatedPathData::SVGAnimatedPathData() +{ + impl = new SVGAnimatedPathDataImpl(); + impl->ref(); +} + +SVGAnimatedPathData::SVGAnimatedPathData(const SVGAnimatedPathData &other) : impl(0) +{ + (*this) = other; +} + +SVGAnimatedPathData &SVGAnimatedPathData::operator=(const SVGAnimatedPathData &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAnimatedPathData::SVGAnimatedPathData(SVGAnimatedPathDataImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAnimatedPathData::~SVGAnimatedPathData() +{ + if(impl) + impl->deref(); +} + +SVGPathSegList SVGAnimatedPathData::pathSegList() const +{ + if(!impl) return SVGPathSegList(0); + return SVGPathSegList(impl->pathSegList()); +} + +SVGPathSegList SVGAnimatedPathData::normalizedPathSegList() const +{ + if(!impl) return SVGPathSegList(0); + return SVGPathSegList(impl->normalizedPathSegList()); +} + +SVGPathSegList SVGAnimatedPathData::animatedPathSegList() const +{ + if(!impl) return SVGPathSegList(0); + return SVGPathSegList(impl->animatedPathSegList()); +} + +SVGPathSegList SVGAnimatedPathData::animatedNormalizedPathSegList() const +{ + if(!impl) return SVGPathSegList(0); + return SVGPathSegList(impl->animatedNormalizedPathSegList()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedPathData.h b/ksvg/dom/SVGAnimatedPathData.h new file mode 100644 index 00000000..06ae2905 --- /dev/null +++ b/ksvg/dom/SVGAnimatedPathData.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedPathData_H +#define SVGAnimatedPathData_H + +namespace KSVG +{ + +class SVGPathSegList; +class SVGAnimatedPathDataImpl; +class SVGAnimatedPathData +{ +public: + SVGAnimatedPathData(); + SVGAnimatedPathData(const SVGAnimatedPathData &other); + SVGAnimatedPathData &operator=(const SVGAnimatedPathData &other); + SVGAnimatedPathData(SVGAnimatedPathDataImpl *other); + virtual ~SVGAnimatedPathData(); + + SVGPathSegList pathSegList() const; + SVGPathSegList normalizedPathSegList() const; + SVGPathSegList animatedPathSegList() const; + SVGPathSegList animatedNormalizedPathSegList() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAnimatedPathDataImpl *handle() const { return impl; } + +private: + SVGAnimatedPathDataImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedPoints.cc b/ksvg/dom/SVGAnimatedPoints.cc new file mode 100644 index 00000000..cc4e999d --- /dev/null +++ b/ksvg/dom/SVGAnimatedPoints.cc @@ -0,0 +1,79 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedPoints.h" +#include "SVGAnimatedPointsImpl.h" +#include "SVGPointList.h" + +using namespace KSVG; + +SVGAnimatedPoints::SVGAnimatedPoints() +{ + impl = new SVGAnimatedPointsImpl(); + impl->ref(); +} + +SVGAnimatedPoints::SVGAnimatedPoints(const SVGAnimatedPoints &other) : impl(0) +{ + (*this) = other;; +} + +SVGAnimatedPoints &SVGAnimatedPoints::operator=(const SVGAnimatedPoints &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAnimatedPoints::SVGAnimatedPoints(SVGAnimatedPointsImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAnimatedPoints::~SVGAnimatedPoints() +{ + if(impl) + impl->deref(); +} + +SVGPointList SVGAnimatedPoints::points() const +{ + if(!impl) return SVGPointList(0); + return SVGPointList(impl->points()); +} + +SVGPointList SVGAnimatedPoints::animatedPoints() const +{ + if(!impl) return SVGPointList(0); + return SVGPointList(impl->animatedPoints()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedPoints.h b/ksvg/dom/SVGAnimatedPoints.h new file mode 100644 index 00000000..3f035722 --- /dev/null +++ b/ksvg/dom/SVGAnimatedPoints.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedPoints_H +#define SVGAnimatedPoints_H + +namespace KSVG +{ + +class SVGPointList; +class SVGAnimatedPointsImpl; +class SVGAnimatedPoints +{ +public: + SVGAnimatedPoints(); + SVGAnimatedPoints(const SVGAnimatedPoints &other); + SVGAnimatedPoints &operator=(const SVGAnimatedPoints &other); + SVGAnimatedPoints(SVGAnimatedPointsImpl *other); + virtual ~SVGAnimatedPoints(); + + SVGPointList points() const; + SVGPointList animatedPoints() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAnimatedPointsImpl *handle() const { return impl; } + +private: + SVGAnimatedPointsImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedPreserveAspectRatio.cc b/ksvg/dom/SVGAnimatedPreserveAspectRatio.cc new file mode 100644 index 00000000..ed157028 --- /dev/null +++ b/ksvg/dom/SVGAnimatedPreserveAspectRatio.cc @@ -0,0 +1,79 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedPreserveAspectRatio.h" +#include "SVGAnimatedPreserveAspectRatioImpl.h" +#include "SVGPreserveAspectRatio.h" + +using namespace KSVG; + +SVGAnimatedPreserveAspectRatio::SVGAnimatedPreserveAspectRatio() +{ + impl = new SVGAnimatedPreserveAspectRatioImpl(); + impl->ref(); +} + +SVGAnimatedPreserveAspectRatio::SVGAnimatedPreserveAspectRatio(const SVGAnimatedPreserveAspectRatio &other) : impl(0) +{ + (*this) = other; +} + +SVGAnimatedPreserveAspectRatio &SVGAnimatedPreserveAspectRatio::operator=(const SVGAnimatedPreserveAspectRatio &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAnimatedPreserveAspectRatio::SVGAnimatedPreserveAspectRatio(SVGAnimatedPreserveAspectRatioImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAnimatedPreserveAspectRatio::~SVGAnimatedPreserveAspectRatio() +{ + if(impl) + impl->deref(); +} + +SVGPreserveAspectRatio SVGAnimatedPreserveAspectRatio::baseVal() const +{ + if(!impl) return SVGPreserveAspectRatio(0); + return SVGPreserveAspectRatio(impl->baseVal()); +} + +SVGPreserveAspectRatio SVGAnimatedPreserveAspectRatio::animVal() const +{ + if(!impl) return SVGPreserveAspectRatio(0); + return SVGPreserveAspectRatio(impl->animVal()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedPreserveAspectRatio.h b/ksvg/dom/SVGAnimatedPreserveAspectRatio.h new file mode 100644 index 00000000..4eea042f --- /dev/null +++ b/ksvg/dom/SVGAnimatedPreserveAspectRatio.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedPreserveAspectRatio_H +#define SVGAnimatedPreserveAspectRatio_H + + +namespace KSVG +{ + +class SVGPreserveAspectRatio; +class SVGAnimatedPreserveAspectRatioImpl; +class SVGAnimatedPreserveAspectRatio +{ +public: + SVGAnimatedPreserveAspectRatio(); + SVGAnimatedPreserveAspectRatio(const SVGAnimatedPreserveAspectRatio &other); + SVGAnimatedPreserveAspectRatio &operator=(const SVGAnimatedPreserveAspectRatio &other); + SVGAnimatedPreserveAspectRatio(SVGAnimatedPreserveAspectRatioImpl *other); + ~SVGAnimatedPreserveAspectRatio(); + + SVGPreserveAspectRatio baseVal() const; + SVGPreserveAspectRatio animVal() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAnimatedPreserveAspectRatioImpl *handle() const { return impl; } + +private: + SVGAnimatedPreserveAspectRatioImpl *impl; +}; + +} + +#endif +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedRect.cc b/ksvg/dom/SVGAnimatedRect.cc new file mode 100644 index 00000000..2c315003 --- /dev/null +++ b/ksvg/dom/SVGAnimatedRect.cc @@ -0,0 +1,79 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedRect.h" +#include "SVGAnimatedRectImpl.h" +#include "SVGRect.h" + +using namespace KSVG; + +SVGAnimatedRect::SVGAnimatedRect() +{ + impl = new SVGAnimatedRectImpl(); + impl->ref(); +} + +SVGAnimatedRect::SVGAnimatedRect(const SVGAnimatedRect &other) : impl(0) +{ + (*this) = other; +} + +SVGAnimatedRect &SVGAnimatedRect::operator=(const SVGAnimatedRect &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAnimatedRect::SVGAnimatedRect(SVGAnimatedRectImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAnimatedRect::~SVGAnimatedRect() +{ + if(impl) + impl->deref(); +} + +SVGRect SVGAnimatedRect::baseVal() const +{ + if(!impl) return SVGRect(0); + return SVGRect(impl->baseVal()); +} + +SVGRect SVGAnimatedRect::animVal() const +{ + if(!impl) return SVGRect(0); + return SVGRect(impl->animVal()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedRect.h b/ksvg/dom/SVGAnimatedRect.h new file mode 100644 index 00000000..c45a8f2d --- /dev/null +++ b/ksvg/dom/SVGAnimatedRect.h @@ -0,0 +1,51 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedRect_H +#define SVGAnimatedRect_H + +namespace KSVG +{ + +class SVGRect; +class SVGAnimatedRectImpl; +class SVGAnimatedRect +{ +public: + SVGAnimatedRect(); + SVGAnimatedRect(const SVGAnimatedRect &other); + SVGAnimatedRect &operator=(const SVGAnimatedRect &other); + SVGAnimatedRect(SVGAnimatedRectImpl *other); + ~SVGAnimatedRect(); + + SVGRect baseVal() const; + SVGRect animVal() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAnimatedRectImpl *handle() const { return impl; } + +private: + SVGAnimatedRectImpl *impl; +}; + +} + +#endif +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedString.cc b/ksvg/dom/SVGAnimatedString.cc new file mode 100644 index 00000000..5d22f4ae --- /dev/null +++ b/ksvg/dom/SVGAnimatedString.cc @@ -0,0 +1,84 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedString.h" +#include "SVGAnimatedStringImpl.h" + +using namespace KSVG; + +SVGAnimatedString::SVGAnimatedString() +{ + impl = new SVGAnimatedStringImpl(); + impl->ref(); +} + +SVGAnimatedString::SVGAnimatedString(const SVGAnimatedString &other) : impl(0) +{ + (*this) = other; +} + +SVGAnimatedString &SVGAnimatedString::operator=(const SVGAnimatedString &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAnimatedString::SVGAnimatedString(SVGAnimatedStringImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAnimatedString::~SVGAnimatedString() +{ + if(impl) + impl->deref(); +} + +void SVGAnimatedString::setBaseVal(const DOM::DOMString &baseVal) +{ + if(impl) + impl->setBaseVal(baseVal); +} + +DOM::DOMString SVGAnimatedString::baseVal() const +{ + if(!impl) return DOM::DOMString(); + return impl->baseVal(); +} + +DOM::DOMString SVGAnimatedString::animVal() const +{ + if(!impl) return DOM::DOMString(); + return impl->animVal(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedString.h b/ksvg/dom/SVGAnimatedString.h new file mode 100644 index 00000000..f97bb5c8 --- /dev/null +++ b/ksvg/dom/SVGAnimatedString.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedString_H +#define SVGAnimatedString_H + +#include + +namespace KSVG +{ + +class SVGAnimatedStringImpl; +class SVGAnimatedString +{ +public: + SVGAnimatedString(); + SVGAnimatedString(const SVGAnimatedString &other); + SVGAnimatedString &operator=(const SVGAnimatedString &other); + SVGAnimatedString(SVGAnimatedStringImpl *other); + ~SVGAnimatedString(); + + void setBaseVal(const DOM::DOMString &baseVal); + DOM::DOMString baseVal() const; + + DOM::DOMString animVal() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAnimatedStringImpl *handle() const { return impl; } + +private: + SVGAnimatedStringImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedTransformList.cc b/ksvg/dom/SVGAnimatedTransformList.cc new file mode 100644 index 00000000..a1eb43ca --- /dev/null +++ b/ksvg/dom/SVGAnimatedTransformList.cc @@ -0,0 +1,79 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedTransformList.h" +#include "SVGAnimatedTransformListImpl.h" +#include "SVGTransformList.h" + +using namespace KSVG; + +SVGAnimatedTransformList::SVGAnimatedTransformList() +{ + impl = new SVGAnimatedTransformListImpl(); + impl->ref(); +} + +SVGAnimatedTransformList::SVGAnimatedTransformList(const SVGAnimatedTransformList &other) : impl(0) +{ + (*this) = other; +} + +SVGAnimatedTransformList &SVGAnimatedTransformList::operator=(const SVGAnimatedTransformList &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAnimatedTransformList::SVGAnimatedTransformList(SVGAnimatedTransformListImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAnimatedTransformList::~SVGAnimatedTransformList() +{ + if(impl) + impl->deref(); +} + +SVGTransformList SVGAnimatedTransformList::baseVal() const +{ + if(!impl) return SVGTransformList(0); + return SVGTransformList(impl->baseVal()); +} + +SVGTransformList SVGAnimatedTransformList::animVal() const +{ + if(!impl) return SVGTransformList(0); + return SVGTransformList(impl->animVal()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimatedTransformList.h b/ksvg/dom/SVGAnimatedTransformList.h new file mode 100644 index 00000000..87a12d3b --- /dev/null +++ b/ksvg/dom/SVGAnimatedTransformList.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedTransformList_H +#define SVGAnimatedTransformList_H + +namespace KSVG +{ + +class SVGTransformList; +class SVGAnimatedTransformListImpl; +class SVGAnimatedTransformList +{ +public: + SVGAnimatedTransformList(); + SVGAnimatedTransformList(const SVGAnimatedTransformList &other); + SVGAnimatedTransformList &operator=(const SVGAnimatedTransformList &other); + SVGAnimatedTransformList(SVGAnimatedTransformListImpl *other); + ~SVGAnimatedTransformList(); + + SVGTransformList baseVal() const; + SVGTransformList animVal() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAnimatedTransformListImpl *handle() const { return impl; } + +private: + SVGAnimatedTransformListImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimationElement.cc b/ksvg/dom/SVGAnimationElement.cc new file mode 100644 index 00000000..0d4014a7 --- /dev/null +++ b/ksvg/dom/SVGAnimationElement.cc @@ -0,0 +1,93 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimationElement.h" +#include "SVGAnimationElementImpl.h" + +using namespace KSVG; + +SVGAnimationElement::SVGAnimationElement() : SVGElement(), SVGTests(), SVGExternalResourcesRequired() +{ + impl = 0; +} + +SVGAnimationElement::SVGAnimationElement(const SVGAnimationElement &other) : SVGElement(other), SVGTests(other), SVGExternalResourcesRequired(other), impl(0) +{ + (*this) = other; +} + +SVGAnimationElement &SVGAnimationElement::operator=(const SVGAnimationElement &other) +{ + SVGElement::operator=(other); + SVGTests::operator=(other); + SVGExternalResourcesRequired::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGAnimationElement::SVGAnimationElement(SVGAnimationElementImpl *other) : SVGElement(other), SVGTests(other), SVGExternalResourcesRequired(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGAnimationElement::~SVGAnimationElement() +{ + if(impl) + impl->deref(); +} + +SVGElement SVGAnimationElement::targetElement() const +{ + if(!impl) return SVGElement(0); + return SVGElement(impl->targetElement()); +} + +float SVGAnimationElement::getStartTime() +{ + if(!impl) return -1; + return impl->getStartTime(); +} + +float SVGAnimationElement::getCurrentTime() +{ + if(!impl) return -1; + return impl->getCurrentTime(); +} + +float SVGAnimationElement::getSimpleDuration() +{ + if(!impl) return -1; + return impl->getSimpleDuration(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGAnimationElement.h b/ksvg/dom/SVGAnimationElement.h new file mode 100644 index 00000000..2e4df665 --- /dev/null +++ b/ksvg/dom/SVGAnimationElement.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimationElement_H +#define SVGAnimationElement_H + +#include "SVGElement.h" +#include "SVGTests.h" +#include "SVGExternalResourcesRequired.h" + +namespace KSVG +{ + +class SVGAnimationElementImpl; +class SVGAnimationElement : public SVGElement, + public SVGTests, + public SVGExternalResourcesRequired +{ +public: + SVGAnimationElement(); + SVGAnimationElement(const SVGAnimationElement &other); + SVGAnimationElement &operator=(const SVGAnimationElement &other); + SVGAnimationElement(SVGAnimationElementImpl *other); + virtual ~SVGAnimationElement(); + + SVGElement targetElement() const; + + float getStartTime(); + float getCurrentTime(); + float getSimpleDuration(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGAnimationElementImpl *handle() const { return impl; } + +private: + SVGAnimationElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGCSSRule.cc b/ksvg/dom/SVGCSSRule.cc new file mode 100644 index 00000000..cad5657e --- /dev/null +++ b/ksvg/dom/SVGCSSRule.cc @@ -0,0 +1,66 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGCSSRule.h" +#include "SVGCSSRuleImpl.h" + +using namespace KSVG; + +SVGCSSRule::SVGCSSRule() //: css::CSSRule() +{ + impl = new SVGCSSRuleImpl(); + impl->ref(); +} + +SVGCSSRule::SVGCSSRule(const SVGCSSRule &other) : /*css::CSSRule(),*/ impl(0) +{ + (*this) = other; +} + +SVGCSSRule &SVGCSSRule::operator=(const SVGCSSRule &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGCSSRule::SVGCSSRule(SVGCSSRuleImpl *other) //: css::CSSRule() +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGCSSRule::~SVGCSSRule() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGCSSRule.h b/ksvg/dom/SVGCSSRule.h new file mode 100644 index 00000000..dc9e9360 --- /dev/null +++ b/ksvg/dom/SVGCSSRule.h @@ -0,0 +1,51 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGCSSRule_H +#define SVGCSSRule_H + +namespace KSVG +{ + +class SVGCSSRuleImpl; +class SVGCSSRule //: public css::CSSRule +{ +public: + SVGCSSRule(); + SVGCSSRule(const SVGCSSRule &other); + SVGCSSRule &operator=(const SVGCSSRule &other); + SVGCSSRule(SVGCSSRuleImpl *other); + virtual ~SVGCSSRule(); + + // add to enum + // const unsigned short COLOR_PROFILE_RULE = 7; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGCSSRuleImpl *handle() const { return impl; } + +private: + SVGCSSRuleImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGCircleElement.cc b/ksvg/dom/SVGCircleElement.cc new file mode 100644 index 00000000..13875211 --- /dev/null +++ b/ksvg/dom/SVGCircleElement.cc @@ -0,0 +1,92 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include "SVGCircleElement.h" +#include "SVGCircleElementImpl.h" +#include "SVGAnimatedLength.h" + +using namespace KSVG; + +SVGCircleElement::SVGCircleElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable() +{ + impl = 0; +} + +SVGCircleElement::SVGCircleElement(const SVGCircleElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), impl(0) +{ + (*this) = other; +} + +SVGCircleElement &SVGCircleElement::operator=(const SVGCircleElement &other) +{ + SVGElement::operator=(other); + SVGTests::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + SVGTransformable::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGCircleElement::SVGCircleElement(SVGCircleElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGCircleElement::~SVGCircleElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedLength SVGCircleElement::cx() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->cx()); +} + +SVGAnimatedLength SVGCircleElement::cy() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->cy()); +} + +SVGAnimatedLength SVGCircleElement::r() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->r()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGCircleElement.h b/ksvg/dom/SVGCircleElement.h new file mode 100644 index 00000000..65406a1c --- /dev/null +++ b/ksvg/dom/SVGCircleElement.h @@ -0,0 +1,117 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 file includes excerpts from the Scalable Vector Graphics + (SVG) 1.0 Specification (Proposed Recommendation) + http://www.w3.org/TR/SVG + + Copyright 2001 World Wide Web Consortium, (Massachusetts + Institute of Technology, Institut National de Recherche en + Informatique et en Automatique, Keio University). + All Rights Reserved. + + $Id$ + */ + +#ifndef SVGCircleElement_H +#define SVGCircleElement_H + +#include "SVGElement.h" +#include "SVGTests.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGTransformable.h" + +namespace KSVG +{ + +class SVGCircleElementImpl; + +class SVGAnimatedLength; +/** + * The circle element defines a circle based on a center + * point and radius. + * + * For more info look here :
9.3 The + * 'circle' element. + */ +class SVGCircleElement : public SVGElement, + public SVGTests, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGTransformable +{ +public: + SVGCircleElement(); + SVGCircleElement(const SVGCircleElement &); + SVGCircleElement &operator=(const SVGCircleElement &other); + SVGCircleElement(SVGCircleElementImpl *); + ~SVGCircleElement(); + + /** + * The x-axis coordinate of the center of the circle. + * If the attribute is not specified, the effect is as if a value + * of "0" were specified. + * + * This attribute is animatable. + * + * @return The x-axis coordinate of the center of the circle. + */ + SVGAnimatedLength cx(); + + /** + * The y-axis coordinate of the center of the circle. + * If the attribute is not specified, the effect is as if a value + * of "0" were specified. + * + * This attribute is animatable. + * + * @return The y-axis coordinate of the center of the circle. + */ + SVGAnimatedLength cy(); + + /** + * The radius of the circle. + * A negative value is an error (see + * Error processing). A value of zero disables rendering of + * the element. + * + * This attribute is animatable. + * + * @return The radius of the circle. + */ + SVGAnimatedLength r(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGCircleElementImpl *handle() const { return impl; } + +private: + SVGCircleElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGClipPathElement.cc b/ksvg/dom/SVGClipPathElement.cc new file mode 100644 index 00000000..f0785efc --- /dev/null +++ b/ksvg/dom/SVGClipPathElement.cc @@ -0,0 +1,79 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGClipPathElement.h" +#include "SVGClipPathElementImpl.h" +#include "SVGAnimatedEnumeration.h" + +using namespace KSVG; + +SVGClipPathElement::SVGClipPathElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable() +{ + impl = 0; +} + +SVGClipPathElement::SVGClipPathElement(const SVGClipPathElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other) +{ + (*this) = other; +} + +SVGClipPathElement &SVGClipPathElement::operator=(const SVGClipPathElement &other) +{ + SVGElement::operator=(other); + SVGTests::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + SVGTransformable::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGClipPathElement::SVGClipPathElement(SVGClipPathElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGClipPathElement::~SVGClipPathElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedEnumeration SVGClipPathElement::clipPathUnits() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->clipPathUnits()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGClipPathElement.h b/ksvg/dom/SVGClipPathElement.h new file mode 100644 index 00000000..70cfe6bb --- /dev/null +++ b/ksvg/dom/SVGClipPathElement.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGClipPathElement_H +#define SVGClipPathElement_H + +#include "SVGElement.h" +#include "SVGTests.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGTransformable.h" +#include "SVGUnitTypes.h" + +namespace KSVG +{ + +class SVGAnimatedEnumeration; +class SVGClipPathElementImpl; +class SVGClipPathElement : public SVGElement, + public SVGTests, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGTransformable, + public SVGUnitTypes +{ +public: + SVGClipPathElement(); + SVGClipPathElement(const SVGClipPathElement &other); + SVGClipPathElement &operator=(const SVGClipPathElement &other); + SVGClipPathElement(SVGClipPathElementImpl *other); + virtual ~SVGClipPathElement(); + + SVGAnimatedEnumeration clipPathUnits() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGClipPathElementImpl *handle() const { return impl; } + +private: + SVGClipPathElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGColor.cc b/ksvg/dom/SVGColor.cc new file mode 100644 index 00000000..e9294c5d --- /dev/null +++ b/ksvg/dom/SVGColor.cc @@ -0,0 +1,105 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option); any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGColor.h" +#include "SVGICCColor.h" +#include "SVGColorImpl.h" + +using namespace KSVG; + +SVGColor::SVGColor() +{ + // FIXME: no icc color support... + impl = new SVGColorImpl(0); + impl->ref(); +} + +SVGColor::SVGColor(const SVGColor &other) : impl(0) +{ + (*this) = other; +} + +SVGColor &SVGColor::operator=(const SVGColor &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; + +} + +SVGColor::SVGColor(SVGColorImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGColor::~SVGColor() +{ + if(impl) + impl->deref(); +} + +unsigned short SVGColor::colorType() const +{ + if(!impl) return SVG_COLORTYPE_UNKNOWN; + return impl->colorType(); +} + +DOM::RGBColor SVGColor::rgbColor() const +{ + if(!impl) return DOM::RGBColor(); + return impl->rgbColor(); +} + +SVGICCColor SVGColor::iccColor() const +{ + if(!impl) return SVGICCColor(); + return impl->iccColor(); +} + +void SVGColor::setRGBColor(const DOM::DOMString &rgbColor) +{ + if(impl) + impl->setRGBColor(rgbColor); +} + +void SVGColor::setRGBColorICCColor(const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor) +{ + if(impl) + impl->setRGBColorICCColor(rgbColor, iccColor); +} + +void SVGColor::setColor(unsigned short colorType, const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor) +{ + if(impl) + impl->setColor(colorType, rgbColor, iccColor); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGColor.h b/ksvg/dom/SVGColor.h new file mode 100644 index 00000000..62147ed0 --- /dev/null +++ b/ksvg/dom/SVGColor.h @@ -0,0 +1,69 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGColor_H +#define SVGColor_H + +#include +#include + +namespace KSVG +{ + +enum +{ + SVG_COLORTYPE_UNKNOWN = 0, + SVG_COLORTYPE_RGBCOLOR = 1, + SVG_COLORTYPE_RGBCOLOR_ICCCOLOR = 2, + SVG_COLORTYPE_CURRENTCOLOR = 3 +}; + +class SVGColorImpl; +class SVGICCColor; +class SVGColor // : public css::CSSValue +{ +public: + SVGColor(); + SVGColor(const SVGColor &); + SVGColor &operator=(const SVGColor &other); + SVGColor(SVGColorImpl *); + ~SVGColor(); + + unsigned short colorType() const; + + DOM::RGBColor rgbColor() const; + SVGICCColor iccColor() const; + + void setRGBColor(const DOM::DOMString &rgbColor); + void setRGBColorICCColor(const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor); + void setColor(unsigned short colorType, const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGColorImpl *handle() const { return impl; } + +private: + SVGColorImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGColorProfileElement.cc b/ksvg/dom/SVGColorProfileElement.cc new file mode 100644 index 00000000..5acdb1a1 --- /dev/null +++ b/ksvg/dom/SVGColorProfileElement.cc @@ -0,0 +1,105 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGColorProfileElement.h" +#include "SVGColorProfileElementImpl.h" +#include "SVGRenderingIntent.h" + +using namespace KSVG; + +SVGColorProfileElement::SVGColorProfileElement() : SVGElement(), SVGURIReference() +{ + impl = 0; +} + +SVGColorProfileElement::SVGColorProfileElement(const SVGColorProfileElement &other) : SVGElement(other), SVGURIReference(other), impl(0) +{ + (*this) = other; +} + +SVGColorProfileElement &SVGColorProfileElement::operator=(const SVGColorProfileElement &other) +{ + SVGElement::operator=(other); + SVGURIReference::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGColorProfileElement::SVGColorProfileElement(SVGColorProfileElementImpl *other) : SVGElement(other), SVGURIReference(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGColorProfileElement::~SVGColorProfileElement() +{ + if(impl) + impl->deref(); +} + +void SVGColorProfileElement::setLocal(const DOM::DOMString &local) +{ + if(impl) + impl->setLocal(local); +} + +DOM::DOMString SVGColorProfileElement::local() const +{ + if(!impl) return DOM::DOMString(); + return impl->local(); +} + +void SVGColorProfileElement::setName(const DOM::DOMString &name) +{ + if(impl) + impl->setName(name); +} + +DOM::DOMString SVGColorProfileElement::name() const +{ + if(!impl) return DOM::DOMString(); + return impl->name(); +} + +void SVGColorProfileElement::setRenderingIntent(unsigned short renderingIntent) +{ + if(impl) + impl->setRenderingIntent(renderingIntent); +} + +unsigned short SVGColorProfileElement::renderingIntent() const +{ + if(!impl) return RENDERING_INTENT_UNKNOWN; + return impl->renderingIntent(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGColorProfileElement.h b/ksvg/dom/SVGColorProfileElement.h new file mode 100644 index 00000000..f7f3bd41 --- /dev/null +++ b/ksvg/dom/SVGColorProfileElement.h @@ -0,0 +1,62 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGColorProfileElement_H +#define SVGColorProfileElement_H + +#include "SVGElement.h" +#include "SVGURIReference.h" +#include + +namespace KSVG +{ + +class SVGColorProfileElementImpl; +class SVGColorProfileElement : public SVGElement, + public SVGURIReference +{ +public: + SVGColorProfileElement(); + SVGColorProfileElement(const SVGColorProfileElement &other); + SVGColorProfileElement &operator=(const SVGColorProfileElement &other); + SVGColorProfileElement(SVGColorProfileElementImpl *other); + virtual ~SVGColorProfileElement(); + + void setLocal(const DOM::DOMString &local); + DOM::DOMString local() const; + + void setName(const DOM::DOMString &name); + DOM::DOMString name() const; + + void setRenderingIntent(unsigned short renderingIntent); + unsigned short renderingIntent() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGColorProfileElementImpl *handle() const { return impl; } + +private: + SVGColorProfileElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGColorProfileRule.cc b/ksvg/dom/SVGColorProfileRule.cc new file mode 100644 index 00000000..8c4ecea7 --- /dev/null +++ b/ksvg/dom/SVGColorProfileRule.cc @@ -0,0 +1,103 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGColorProfileRule.h" +#include "SVGColorProfileRuleImpl.h" +#include "SVGRenderingIntent.h" + +using namespace KSVG; + +SVGColorProfileRule::SVGColorProfileRule() : SVGCSSRule() +{ + impl = new SVGColorProfileRuleImpl(); + impl->ref(); +} + +SVGColorProfileRule::SVGColorProfileRule(const SVGColorProfileRule &other) : SVGCSSRule(), impl(0) +{ + (*this) = other; +} + +SVGColorProfileRule &SVGColorProfileRule::operator=(const SVGColorProfileRule &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGColorProfileRule::SVGColorProfileRule(SVGColorProfileRuleImpl *other) : SVGCSSRule(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGColorProfileRule::~SVGColorProfileRule() +{ + if(impl) + impl->deref(); +} + +void SVGColorProfileRule::setSrc(const DOM::DOMString &src) +{ + if(impl) + impl->setSrc(src); +} + +DOM::DOMString SVGColorProfileRule::src() const +{ + if(!impl) return DOM::DOMString(); + return impl->src(); +} + +void SVGColorProfileRule::setName(const DOM::DOMString &name) +{ + if(impl) + impl->setName(name); +} + +DOM::DOMString SVGColorProfileRule::name() const +{ + if(!impl) return DOM::DOMString(); + return impl->name(); +} + +void SVGColorProfileRule::setRenderingIntent(unsigned short renderingIntent) +{ + if(impl) + impl->setRenderingIntent(renderingIntent); +} + +unsigned short SVGColorProfileRule::renderingIntent() const +{ + if(!impl) return RENDERING_INTENT_UNKNOWN; + return impl->renderingIntent(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGColorProfileRule.h b/ksvg/dom/SVGColorProfileRule.h new file mode 100644 index 00000000..b99321ad --- /dev/null +++ b/ksvg/dom/SVGColorProfileRule.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGColorProfileRule_H +#define SVGColorProfileRule_H + +#include +#include "SVGCSSRule.h" + +namespace KSVG +{ + +class SVGColorProfileRuleImpl; +class SVGColorProfileRule : public SVGCSSRule +{ +public: + SVGColorProfileRule(); + SVGColorProfileRule(const SVGColorProfileRule &other); + SVGColorProfileRule &operator=(const SVGColorProfileRule &other); + SVGColorProfileRule(SVGColorProfileRuleImpl *other); + virtual ~SVGColorProfileRule(); + + void setSrc(const DOM::DOMString &src); + DOM::DOMString src() const; + + void setName(const DOM::DOMString &name); + DOM::DOMString name() const; + + void setRenderingIntent(unsigned short renderingIntent); + unsigned short renderingIntent() const; + +private: + SVGColorProfileRuleImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGComponentTransferFunctionElement.cc b/ksvg/dom/SVGComponentTransferFunctionElement.cc new file mode 100644 index 00000000..970da9ea --- /dev/null +++ b/ksvg/dom/SVGComponentTransferFunctionElement.cc @@ -0,0 +1,112 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGComponentTransferFunctionElement.h" +#include "SVGComponentTransferFunctionElementImpl.h" +#include "SVGAnimatedNumber.h" +#include "SVGAnimatedNumberList.h" +#include "SVGAnimatedEnumeration.h" + +using namespace KSVG; + +SVGComponentTransferFunctionElement::SVGComponentTransferFunctionElement() : SVGElement() +{ + impl = 0; +} + +SVGComponentTransferFunctionElement::SVGComponentTransferFunctionElement(const SVGComponentTransferFunctionElement &other) : SVGElement(other), impl(0) +{ + (*this) = other; +} + +SVGComponentTransferFunctionElement &SVGComponentTransferFunctionElement::operator =(const SVGComponentTransferFunctionElement &other) +{ + SVGElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGComponentTransferFunctionElement::SVGComponentTransferFunctionElement(SVGComponentTransferFunctionElementImpl *other) : SVGElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGComponentTransferFunctionElement::~SVGComponentTransferFunctionElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedEnumeration SVGComponentTransferFunctionElement::type() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->type()); +} + +SVGAnimatedNumberList SVGComponentTransferFunctionElement::tableValues() const +{ + if(!impl) return SVGAnimatedNumberList(0); + return SVGAnimatedNumberList(impl->tableValues()); +} + +SVGAnimatedNumber SVGComponentTransferFunctionElement::slope() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->slope()); +} + +SVGAnimatedNumber SVGComponentTransferFunctionElement::intercept() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->intercept()); +} + +SVGAnimatedNumber SVGComponentTransferFunctionElement::amplitude() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->amplitude()); +} + +SVGAnimatedNumber SVGComponentTransferFunctionElement::exponent() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->exponent()); +} + +SVGAnimatedNumber SVGComponentTransferFunctionElement::offset() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->offset()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGComponentTransferFunctionElement.h b/ksvg/dom/SVGComponentTransferFunctionElement.h new file mode 100644 index 00000000..d9dd0080 --- /dev/null +++ b/ksvg/dom/SVGComponentTransferFunctionElement.h @@ -0,0 +1,71 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGComponentTransferFunctionElement_H +#define SVGComponentTransferFunctionElement_H + +#include "SVGElement.h" + +namespace KSVG +{ + +enum +{ + SVG_FECOMPONENTTRANSFER_TYPE_UNKNOWN = 0, + SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY = 1, + SVG_FECOMPONENTTRANSFER_TYPE_TABLE = 2, + SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE = 3, + SVG_FECOMPONENTTRANSFER_TYPE_LINEAR = 4, + SVG_FECOMPONENTTRANSFER_TYPE_GAMMA = 5 +}; + +class SVGAnimatedEnumeration; +class SVGAnimatedNumberList; +class SVGAnimatedNumber; +class SVGComponentTransferFunctionElementImpl; +class SVGComponentTransferFunctionElement : public SVGElement +{ +public: + SVGComponentTransferFunctionElement(); + SVGComponentTransferFunctionElement(const SVGComponentTransferFunctionElement &other); + SVGComponentTransferFunctionElement &operator=(const SVGComponentTransferFunctionElement &other); + SVGComponentTransferFunctionElement(SVGComponentTransferFunctionElementImpl *other); + virtual ~SVGComponentTransferFunctionElement(); + + SVGAnimatedEnumeration type() const; + SVGAnimatedNumberList tableValues() const; + SVGAnimatedNumber slope() const; + SVGAnimatedNumber intercept() const; + SVGAnimatedNumber amplitude() const; + SVGAnimatedNumber exponent() const; + SVGAnimatedNumber offset() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGComponentTransferFunctionElementImpl *handle() const { return impl; } + +private: + SVGComponentTransferFunctionElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGCursorElement.cc b/ksvg/dom/SVGCursorElement.cc new file mode 100644 index 00000000..2eb3c0dc --- /dev/null +++ b/ksvg/dom/SVGCursorElement.cc @@ -0,0 +1,83 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGCursorElement.h" +#include "SVGCursorElementImpl.h" +#include "SVGAnimatedLength.h" + +using namespace KSVG; + +SVGCursorElement::SVGCursorElement() : SVGElement(), SVGURIReference(), SVGTests(), SVGExternalResourcesRequired() +{ + impl = 0; +} + +SVGCursorElement::SVGCursorElement(const SVGCursorElement &other) : SVGElement(other), SVGURIReference(other), SVGTests(other), SVGExternalResourcesRequired(other), impl(0) +{ + (*this) = other; +} + +SVGCursorElement &SVGCursorElement::operator =(const SVGCursorElement &other) +{ + SVGElement::operator=(other); + SVGURIReference::operator=(other); + SVGTests::operator=(other); + SVGExternalResourcesRequired::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGCursorElement::SVGCursorElement(SVGCursorElementImpl *other) : SVGElement(other), SVGURIReference(other), SVGTests(other), SVGExternalResourcesRequired(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGCursorElement::~SVGCursorElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedLength SVGCursorElement::x() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->x()); +} + +SVGAnimatedLength SVGCursorElement::y() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->y()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGCursorElement.h b/ksvg/dom/SVGCursorElement.h new file mode 100644 index 00000000..feb9b2b7 --- /dev/null +++ b/ksvg/dom/SVGCursorElement.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGCursorElement_H +#define SVGCursorElement_H + +#include "SVGElement.h" +#include "SVGURIReference.h" +#include "SVGTests.h" +#include "SVGExternalResourcesRequired.h" + +namespace KSVG +{ + +class SVGAnimatedLength; +class SVGCursorElementImpl; +class SVGCursorElement : public SVGElement, + public SVGURIReference, + public SVGTests, + public SVGExternalResourcesRequired +{ +public: + SVGCursorElement(); + SVGCursorElement(const SVGCursorElement &other); + SVGCursorElement &operator=(const SVGCursorElement &other); + SVGCursorElement(SVGCursorElementImpl *other); + virtual ~SVGCursorElement(); + + SVGAnimatedLength x() const; + SVGAnimatedLength y() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGCursorElementImpl *handle() const { return impl; } + +private: + SVGCursorElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGDefinitionSrcElement.cc b/ksvg/dom/SVGDefinitionSrcElement.cc new file mode 100644 index 00000000..755b6b4f --- /dev/null +++ b/ksvg/dom/SVGDefinitionSrcElement.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGDefinitionSrcElement.h" +#include "SVGDefinitionSrcElementImpl.h" + +using namespace KSVG; + +SVGDefinitionSrcElement::SVGDefinitionSrcElement() : SVGElement() +{ + impl = 0; +} + +SVGDefinitionSrcElement::SVGDefinitionSrcElement(const SVGDefinitionSrcElement &other) : SVGElement(other), impl(0) +{ + (*this) = other; +} + +SVGDefinitionSrcElement &SVGDefinitionSrcElement::operator =(const SVGDefinitionSrcElement &other) +{ + SVGElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGDefinitionSrcElement::SVGDefinitionSrcElement(SVGDefinitionSrcElementImpl *other) : SVGElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGDefinitionSrcElement::~SVGDefinitionSrcElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGDefinitionSrcElement.h b/ksvg/dom/SVGDefinitionSrcElement.h new file mode 100644 index 00000000..fc1b7f52 --- /dev/null +++ b/ksvg/dom/SVGDefinitionSrcElement.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGDefinitionSrcElement_H +#define SVGDefinitionSrcElement_H + +#include "SVGElement.h" + +namespace KSVG +{ + +class SVGDefinitionSrcElementImpl; +class SVGDefinitionSrcElement : public SVGElement +{ +public: + SVGDefinitionSrcElement(); + SVGDefinitionSrcElement(const SVGDefinitionSrcElement &other); + SVGDefinitionSrcElement &operator=(const SVGDefinitionSrcElement &other); + SVGDefinitionSrcElement(SVGDefinitionSrcElementImpl *other); + virtual ~SVGDefinitionSrcElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGDefinitionSrcElementImpl *handle() const { return impl; } + +private: + SVGDefinitionSrcElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGDefsElement.cc b/ksvg/dom/SVGDefsElement.cc new file mode 100644 index 00000000..67bb2baf --- /dev/null +++ b/ksvg/dom/SVGDefsElement.cc @@ -0,0 +1,72 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGDefsElement.h" +#include "SVGDefsElementImpl.h" + +using namespace KSVG; + +SVGDefsElement::SVGDefsElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable() +{ + impl = 0; +} + +SVGDefsElement::SVGDefsElement(const SVGDefsElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), impl(0) +{ + (*this) = other; +} + +SVGDefsElement &SVGDefsElement::operator =(const SVGDefsElement &other) +{ + SVGElement::operator=(other); + SVGTests::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + SVGTransformable::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGDefsElement::SVGDefsElement(SVGDefsElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGDefsElement::~SVGDefsElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGDefsElement.h b/ksvg/dom/SVGDefsElement.h new file mode 100644 index 00000000..e1e7e0a5 --- /dev/null +++ b/ksvg/dom/SVGDefsElement.h @@ -0,0 +1,78 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 file includes excerpts from the Scalable Vector Graphics + (SVG) 1.0 Specification (Proposed Recommendation) + http://www.w3.org/TR/SVG + + Copyright 2001 World Wide Web Consortium, (Massachusetts + Institute of Technology, Institut National de Recherche en + Informatique et en Automatique, Keio University). + All Rights Reserved. +*/ + +#ifndef SVGDefsElement_H +#define SVGDefsElement_H + +#include "SVGElement.h" +#include "SVGTests.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGTransformable.h" + +namespace KSVG +{ + +class SVGDefsElementImpl; + +/** + * The 'defs' element is a container element for referenced elements. For understandability and accessibility + * reasons, it is recommended that, whenever possible, referenced elements be defined inside of a 'defs'. + * + * The content model for 'defs' is the same as for the g element; thus, any element that can be a child of + * a g can also be a child of a 'defs', and vice versa. + */ +class SVGDefsElement : public SVGElement, + public SVGTests, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGTransformable +{ +public: + SVGDefsElement(); + SVGDefsElement(const SVGDefsElement &other); + SVGDefsElement &operator=(const SVGDefsElement &other); + SVGDefsElement(SVGDefsElementImpl *other); + virtual ~SVGDefsElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGDefsElementImpl *handle() const { return impl; } + +private: + SVGDefsElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGDescElement.cc b/ksvg/dom/SVGDescElement.cc new file mode 100644 index 00000000..6eed0ed9 --- /dev/null +++ b/ksvg/dom/SVGDescElement.cc @@ -0,0 +1,69 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGDescElement.h" +#include "SVGDescElementImpl.h" + +using namespace KSVG; + +SVGDescElement::SVGDescElement() : SVGElement(), SVGLangSpace(), SVGStylable() +{ + impl = 0; +} + +SVGDescElement::SVGDescElement(const SVGDescElement &other) : SVGElement(other), SVGLangSpace(other), SVGStylable(other), impl(0) +{ + (*this) = other; +} + +SVGDescElement &SVGDescElement::operator =(const SVGDescElement &other) +{ + SVGElement::operator=(other); + SVGLangSpace::operator=(other); + SVGStylable::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGDescElement::SVGDescElement(SVGDescElementImpl *other) : SVGElement(other), SVGLangSpace(other), SVGStylable(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGDescElement::~SVGDescElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGDescElement.h b/ksvg/dom/SVGDescElement.h new file mode 100644 index 00000000..9a5b270f --- /dev/null +++ b/ksvg/dom/SVGDescElement.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGDescElement_H +#define SVGDescElement_H + +#include "SVGElement.h" +#include "SVGLangSpace.h" +#include "SVGStylable.h" + +namespace KSVG +{ + +class SVGDescElementImpl; +class SVGDescElement : public SVGElement, + public SVGLangSpace, + public SVGStylable +{ +public: + SVGDescElement(); + SVGDescElement(const SVGDescElement &other); + SVGDescElement &operator=(const SVGDescElement &other); + SVGDescElement(SVGDescElementImpl *other); + virtual ~SVGDescElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGDescElementImpl *handle() const { return impl; } + +private: + SVGDescElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGDocument.cc b/ksvg/dom/SVGDocument.cc new file mode 100644 index 00000000..8734b8da --- /dev/null +++ b/ksvg/dom/SVGDocument.cc @@ -0,0 +1,138 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "ksvg_ecma.h" + +#include "SVGDocument.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElement.h" +#include "SVGWindow.h" + +using namespace KSVG; + +SVGDocument::SVGDocument() : DOM::Document(*(new SVGDocumentImpl())) +{ + impl = reinterpret_cast(handle()); + impl->ref(); +} + +SVGDocument::SVGDocument(const SVGDocument &other) : DOM::Document(other), impl(0) +{ + (*this) = other; +} + +SVGDocument &SVGDocument::operator=(const SVGDocument &other) +{ + DOM::Document::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGDocument::SVGDocument(SVGDocumentImpl *other) : DOM::Document(other->handle()) +{ + impl = other; + + if(impl) + impl->ref(); +} + +SVGDocument::~SVGDocument() +{ + if(impl) + impl->deref(); +} + +DOM::DOMString SVGDocument::title() const +{ + if(!impl) return DOM::DOMString(); + return impl->title(); +} + +DOM::DOMString SVGDocument::referrer() const +{ + if(!impl) return DOM::DOMString(); + return impl->referrer(); +} + +DOM::DOMString SVGDocument::domain() const +{ + if(!impl) return DOM::DOMString(); + return impl->domain(); +} + +DOM::DOMString SVGDocument::URL() const +{ + if(!impl) return DOM::DOMString(); + return impl->URL(); +} + +SVGWindow SVGDocument::window() const +{ + if(!impl) return SVGWindow(); + return impl->window(); +} + +SVGSVGElement SVGDocument::rootElement() const +{ + if(!impl) return SVGSVGElement(0); + return SVGSVGElement(impl->rootElement()); +} + +SVGElement SVGDocument::createElement(const DOM::DOMString &tagName) +{ + if(!impl) return SVGElement(0); + + DOM::Element impl = DOM::Document::createElement(tagName); + return SVGElement(SVGDocumentImpl::createElement(tagName, impl)); +} + +SVGElement SVGDocument::createElementNS(const DOM::DOMString &namespaceURI, const DOM::DOMString &qualifiedName) +{ + if(!impl) return SVGElement(0); + + DOM::Element impl = DOM::Document::createElementNS(namespaceURI, qualifiedName); + return SVGElement(SVGDocumentImpl::createElement(qualifiedName, impl)); +} + +// Internal +KJS::Object SVGDocument::globalJSObject() +{ + if(!impl) return KJS::Object(); + return impl->ecmaEngine()->globalObject(); +} + +KJS::ExecState *SVGDocument::globalJSExec() +{ + if(!impl) return 0; + return impl->ecmaEngine()->globalExec(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGDocument.h b/ksvg/dom/SVGDocument.h new file mode 100644 index 00000000..c3f5c7bd --- /dev/null +++ b/ksvg/dom/SVGDocument.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGDocument_H +#define SVGDocument_H + +#include + +#include +#include + +namespace KSVG +{ + +class SVGWindow; +class SVGElement; +class SVGSVGElement; +class SVGDocumentImpl; +class SVGDocument : public DOM::Document +{ +public: + SVGDocument(); + SVGDocument(const SVGDocument &other); + SVGDocument &operator=(const SVGDocument &other); + SVGDocument(SVGDocumentImpl *other); + ~SVGDocument(); + + DOM::DOMString title() const; + DOM::DOMString referrer() const; + DOM::DOMString domain() const; + DOM::DOMString URL() const; + SVGWindow window() const; + + SVGSVGElement rootElement() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGDocumentImpl *handle() const { return impl; } + + SVGElement createElement(const DOM::DOMString &tagName); + SVGElement createElementNS(const DOM::DOMString &namespaceURI, const DOM::DOMString &qualifiedName); + + KJS::Object globalJSObject(); + KJS::ExecState *globalJSExec(); + +private: + SVGDocumentImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGElement.cc b/ksvg/dom/SVGElement.cc new file mode 100644 index 00000000..0edef368 --- /dev/null +++ b/ksvg/dom/SVGElement.cc @@ -0,0 +1,124 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGSVGElement.h" +#include "SVGElement.h" +#include "SVGElementImpl.h" + +using namespace KSVG; + +// There is no way to create a SVGElement this way! Use SVGDocument. +SVGElement::SVGElement() : DOM::Element() +{ + impl = 0; // new SVGElementImpl(ownerDocument().createElement().handle()); +} + +SVGElement::SVGElement(const SVGElement &other) : DOM::Element(other), impl(0) +{ + (*this) = other; +} + +SVGElement &SVGElement::operator=(const SVGElement &other) +{ + // Baseclass assignement operators always first (Niko) + DOM::Element::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGElement::SVGElement(SVGElementImpl *other) : DOM::Element(other->handle()) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGElement::~SVGElement() +{ + if(impl) + impl->deref(); +} + +void SVGElement::setId(DOM::DOMString value) +{ + if(impl) + impl->setId(value); +} + +DOM::DOMString SVGElement::id() +{ + if(!impl) return DOM::DOMString(); + return impl->id(); +} + +void SVGElement::setXmlbase(DOM::DOMString value) +{ + if(impl) + impl->setXmlbase(value); +} + +DOM::DOMString SVGElement::xmlbase() +{ + if(!impl) return DOM::DOMString(); + return impl->xmlbase(); +} + +SVGSVGElement SVGElement::ownerSVGElement() +{ + if(!impl) return SVGSVGElement(0); + return impl->ownerSVGElement(); +} + +SVGElement SVGElement::viewportElement() +{ + if(!impl) return SVGElement(0); + return impl->viewportElement(); +} + +void SVGElement::setAttribute(const DOM::DOMString &name, const DOM::DOMString &value) +{ + if(impl) + impl->setAttributeInternal(name, value); +} + +DOM::DOMString SVGElement::getAttribute(const DOM::DOMString &name) +{ + if(!impl) return DOM::DOMString(); + return impl->getAttributeInternal(name); +} + +bool SVGElement::hasAttribute(const DOM::DOMString &name) +{ + if(!impl) return false; + return impl->hasAttribute(name); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGElement.h b/ksvg/dom/SVGElement.h new file mode 100644 index 00000000..12191b05 --- /dev/null +++ b/ksvg/dom/SVGElement.h @@ -0,0 +1,83 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGElement_H +#define SVGElement_H + +#include +#include + +namespace KSVG +{ + +// Not part of the DOM specification. Internal use only! +#define dom_cast(Class, Obj) reinterpret_cast(Obj.handle()) + +template +class SVGSafeCreator +{ +public: + SVGSafeCreator() { } + ~SVGSafeCreator() { } + + static A create(B *impl) + { + if(!impl) return A(); // Don't use A(0) it'll crash! + return A(impl); + } +}; + +class SVGSVGElement; +class SVGElementImpl; +class SVGElement : public DOM::Element +{ +public: + SVGElement(); + SVGElement(const SVGElement &other); + SVGElement &operator=(const SVGElement &other); + SVGElement(SVGElementImpl *other); + ~SVGElement(); + + void setId(DOM::DOMString); + DOM::DOMString id(); + + void setXmlbase(DOM::DOMString); + DOM::DOMString xmlbase(); + + SVGSVGElement ownerSVGElement(); + SVGElement viewportElement(); + + // We need to overwrite set/get/hasAttribute(s) + void setAttribute(const DOM::DOMString &name, const DOM::DOMString &value); + DOM::DOMString getAttribute(const DOM::DOMString &name); + bool hasAttribute(const DOM::DOMString &name); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGElementImpl *handle() const { return impl; } + +private: + SVGElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGElementInstance.cc b/ksvg/dom/SVGElementInstance.cc new file mode 100644 index 00000000..9bc027c0 --- /dev/null +++ b/ksvg/dom/SVGElementInstance.cc @@ -0,0 +1,117 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGElementInstance.h" +#include "SVGElementInstanceImpl.h" +#include "SVGElementInstanceList.h" +#include "SVGElement.h" +#include "SVGUseElement.h" + +using namespace KSVG; + +SVGElementInstance::SVGElementInstance() +{ + impl = new SVGElementInstanceImpl(); + impl->ref(); +} + +SVGElementInstance::SVGElementInstance(const SVGElementInstance &other) : impl(0) +{ + (*this) = other; +} + +SVGElementInstance &SVGElementInstance::operator =(const SVGElementInstance &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGElementInstance::SVGElementInstance(SVGElementInstanceImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGElementInstance::~SVGElementInstance() +{ + if(impl) + impl->deref(); +} + +SVGElement SVGElementInstance::correspondingElement() const +{ + if(!impl) return SVGElement(0); + return SVGElement(impl->correspondingElement()); +} + +SVGUseElement SVGElementInstance::correspondingUseElement() const +{ + if(!impl) return SVGUseElement(0); + return SVGUseElement(impl->correspondingUseElement()); +} + +SVGElementInstance SVGElementInstance::parentNode() const +{ + if(!impl) return SVGElementInstance(0); + return SVGElementInstance(impl->parentNode()); +} + +SVGElementInstanceList SVGElementInstance::childNodes() const +{ + if(!impl) return SVGElementInstanceList(0); + return SVGElementInstanceList(impl->childNodes()); +} + +SVGElementInstance SVGElementInstance::firstChild() const +{ + if(!impl) return SVGElementInstance(0); + return SVGElementInstance(impl->firstChild()); +} + +SVGElementInstance SVGElementInstance::lastChild() const +{ + if(!impl) return SVGElementInstance(0); + return SVGElementInstance(impl->lastChild()); +} + +SVGElementInstance SVGElementInstance::previousSibling() const +{ + if(!impl) return SVGElementInstance(0); + return SVGElementInstance(impl->previousSibling()); +} + +SVGElementInstance SVGElementInstance::nextSibling() const +{ + if(!impl) return SVGElementInstance(0); + return SVGElementInstance(impl->nextSibling()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGElementInstance.h b/ksvg/dom/SVGElementInstance.h new file mode 100644 index 00000000..51d81831 --- /dev/null +++ b/ksvg/dom/SVGElementInstance.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGElementInstance_H +#define SVGElementInstance_H + +namespace KSVG +{ + +class SVGElement; +class SVGUseElement; +class SVGElementInstanceList; +class SVGElementInstanceImpl; +class SVGElementInstance +{ +public: + SVGElementInstance(); + SVGElementInstance(const SVGElementInstance &other); + SVGElementInstance &operator=(const SVGElementInstance &other); + SVGElementInstance(SVGElementInstanceImpl *other); + ~SVGElementInstance(); + + SVGElement correspondingElement() const; + SVGUseElement correspondingUseElement() const; + SVGElementInstance parentNode() const; + SVGElementInstanceList childNodes() const; + SVGElementInstance firstChild() const; + SVGElementInstance lastChild() const; + SVGElementInstance previousSibling() const; + SVGElementInstance nextSibling() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGElementInstanceImpl *handle() const { return impl; } + +private: + SVGElementInstanceImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGElementInstanceList.cc b/ksvg/dom/SVGElementInstanceList.cc new file mode 100644 index 00000000..ccc99f37 --- /dev/null +++ b/ksvg/dom/SVGElementInstanceList.cc @@ -0,0 +1,79 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGElementInstanceList.h" +#include "SVGElementInstanceListImpl.h" +#include "SVGElementInstance.h" + +using namespace KSVG; + +SVGElementInstanceList::SVGElementInstanceList() +{ + impl = new SVGElementInstanceListImpl(); + impl->ref(); +} + +SVGElementInstanceList::SVGElementInstanceList(const SVGElementInstanceList &other) : impl(0) +{ + (*this) = other; +} + +SVGElementInstanceList &SVGElementInstanceList::operator=(const SVGElementInstanceList &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGElementInstanceList::SVGElementInstanceList(SVGElementInstanceListImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGElementInstanceList::~SVGElementInstanceList() +{ + if(impl) + impl->deref(); +} + +unsigned long SVGElementInstanceList::length() const +{ + if(!impl) return 0; + return impl->length(); +} + +SVGElementInstance SVGElementInstanceList::item(unsigned long index) +{ + if(!impl) return SVGElementInstance(0); + return SVGElementInstance(impl->item(index)); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGElementInstanceList.h b/ksvg/dom/SVGElementInstanceList.h new file mode 100644 index 00000000..9beb40ed --- /dev/null +++ b/ksvg/dom/SVGElementInstanceList.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGElementInstanceList_H +#define SVGElementInstanceList_H + +namespace KSVG +{ + +class SVGElementInstance; +class SVGElementInstanceListImpl; +class SVGElementInstanceList +{ +public: + SVGElementInstanceList(); + SVGElementInstanceList(const SVGElementInstanceList &other); + SVGElementInstanceList &operator=(const SVGElementInstanceList &other); + SVGElementInstanceList(SVGElementInstanceListImpl *other); + ~SVGElementInstanceList(); + + unsigned long length() const; + SVGElementInstance item(unsigned long index); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGElementInstanceListImpl *handle() const { return impl; } + +private: + SVGElementInstanceListImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGEllipseElement.cc b/ksvg/dom/SVGEllipseElement.cc new file mode 100644 index 00000000..2b744ccb --- /dev/null +++ b/ksvg/dom/SVGEllipseElement.cc @@ -0,0 +1,98 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include "SVGEllipseElement.h" +#include "SVGEllipseElementImpl.h" +#include "SVGAnimatedLength.h" + +using namespace KSVG; + +SVGEllipseElement::SVGEllipseElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable() +{ + impl = 0; +} + +SVGEllipseElement::SVGEllipseElement(const SVGEllipseElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), impl(0) +{ + (*this) = other; +} + +SVGEllipseElement &SVGEllipseElement::operator=(const SVGEllipseElement &other) +{ + SVGElement::operator=(other); + SVGTests::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + SVGTransformable::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGEllipseElement::SVGEllipseElement(SVGEllipseElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGEllipseElement::~SVGEllipseElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedLength SVGEllipseElement::cx() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->cx()); +} + +SVGAnimatedLength SVGEllipseElement::cy() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->cy()); +} + +SVGAnimatedLength SVGEllipseElement::rx() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->rx()); +} + +SVGAnimatedLength SVGEllipseElement::ry() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->ry()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGEllipseElement.h b/ksvg/dom/SVGEllipseElement.h new file mode 100644 index 00000000..78399779 --- /dev/null +++ b/ksvg/dom/SVGEllipseElement.h @@ -0,0 +1,131 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 file includes excerpts from the Scalable Vector Graphics + (SVG) 1.0 Specification (Proposed Recommendation) + http://www.w3.org/TR/SVG + + Copyright 2001 World Wide Web Consortium, (Massachusetts + Institute of Technology, Institut National de Recherche en + Informatique et en Automatique, Keio University). + All Rights Reserved. + + $Id$ + */ + +#ifndef SVGEllipseElement_H +#define SVGEllipseElement_H + +#include "SVGElement.h" +#include "SVGTests.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGTransformable.h" + +namespace KSVG +{ + +class SVGAnimatedLength; +class SVGEllipseElementImpl; + +/** + * The ellipse element defines an ellipse which is + * axis-aligned with the current user coordinate system based on a + * center point and two radii. + * + * For more info look here : 9.4 The + * 'ellipse' element. + */ +class SVGEllipseElement : public SVGElement, + public SVGTests, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGTransformable +{ +public: + SVGEllipseElement(); + SVGEllipseElement(const SVGEllipseElement &); + SVGEllipseElement &operator=(const SVGEllipseElement &other); + SVGEllipseElement(SVGEllipseElementImpl *); + ~SVGEllipseElement(); + + /** + * The x-axis coordinate of the center of the ellipse. + * If the attribute is not specified, the effect is as if a value + * of "0" were specified. + * + * This attribute is animatable. + * + * @return The x-axis coordinate of the center of the ellipse. + */ + SVGAnimatedLength cx(); + + /** + * The y-axis coordinate of the center of the ellipse. + * If the attribute is not specified, the effect is as if a value + * of "0" were specified. + * + * This attribute is animatable. + * + * @return The y-axis coordinate of the center of the ellipse. + */ + SVGAnimatedLength cy(); + + /** + * The x-axis radius of the ellipse. + * A negative value is an error (see + * Error processing). A value of zero disables rendering of + * the element. + * + * This attribute is animatable. + * + * @return The x-radius of the ellipse. + */ + SVGAnimatedLength rx(); + + /** + * The y-axis radius of the ellipse. + * A negative value is an error (see + * Error processing). A value of zero disables rendering of + * the element. + * + * This attribute is animatable. + * + * @return The y-radius of the ellipse. + */ + SVGAnimatedLength ry(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGEllipseElementImpl *handle() const { return impl; } + +private: + SVGEllipseElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGEvent.cc b/ksvg/dom/SVGEvent.cc new file mode 100644 index 00000000..19fa6d27 --- /dev/null +++ b/ksvg/dom/SVGEvent.cc @@ -0,0 +1,187 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGEvent.h" +#include "SVGEventImpl.h" + +using namespace KSVG; + +SVGEvent::SVGEvent() : DOM::Event() +{ + impl = 0; +} + +SVGEvent::SVGEvent(const SVGEvent &other) : DOM::Event(other), impl(0) +{ + (*this) = other; +} + +SVGEvent &SVGEvent::operator =(const SVGEvent &other) +{ + DOM::Event::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGEvent::SVGEvent(SVGEventImpl *other) : DOM::Event() +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGEvent::~SVGEvent() +{ + if(impl) + impl->deref(); +} + +SVGEvent::EventId SVGEvent::typeToId(DOM::DOMString type) +{ + if(type == "DOMFocusIn") + return DOMFOCUSIN_EVENT; + else if(type == "DOMFocusOut") + return DOMFOCUSOUT_EVENT; + else if(type == "DOMActivate") + return DOMACTIVATE_EVENT; + else if(type == "click") + return CLICK_EVENT; + else if(type == "mousedown") + return MOUSEDOWN_EVENT; + else if(type == "mouseup") + return MOUSEUP_EVENT; + else if(type == "mouseover") + return MOUSEOVER_EVENT; + else if(type == "mousemove") + return MOUSEMOVE_EVENT; + else if(type == "mouseout") + return MOUSEOUT_EVENT; + else if(type == "DOMSubtreeModified") + return DOMSUBTREEMODIFIED_EVENT; + else if(type == "DOMNodeInserted") + return DOMNODEINSERTED_EVENT; + else if(type == "DOMNodeRemoved") + return DOMNODEREMOVED_EVENT; + else if(type == "DOMNodeRemovedFromDocument") + return DOMNODEREMOVEDFROMDOCUMENT_EVENT; + else if(type == "DOMNodeInsertedIntoDocument") + return DOMNODEINSERTEDINTODOCUMENT_EVENT; + else if(type == "DOMAttrModified") + return DOMATTRMODIFIED_EVENT; + else if(type == "DOMCharacterDataModified") + return DOMCHARACTERDATAMODIFIED_EVENT; + else if(type == "load") + return LOAD_EVENT; + else if(type == "unload") + return UNLOAD_EVENT; + else if(type == "abort") + return ABORT_EVENT; + else if(type == "error") + return ERROR_EVENT; + else if(type == "resize") + return RESIZE_EVENT; + else if(type == "scroll") + return SCROLL_EVENT; + else if(type == "zoom") + return ZOOM_EVENT; + else if(type == "keydown") + return KEYDOWN_EVENT; + else if(type == "keyup") + return KEYUP_EVENT; + else if(type == "keypress") + return KEYPRESS_EVENT; + + return UNKNOWN_EVENT; +} + +DOM::DOMString SVGEvent::idToType(EventId id) +{ + switch(id) + { + case DOMFOCUSIN_EVENT: + return "DOMFocusIn"; + case DOMFOCUSOUT_EVENT: + return "DOMFocusOut"; + case DOMACTIVATE_EVENT: + return "DOMActivate"; + case CLICK_EVENT: + return "click"; + case MOUSEDOWN_EVENT: + return "mousedown"; + case MOUSEUP_EVENT: + return "mouseup"; + case MOUSEOVER_EVENT: + return "mouseover"; + case MOUSEMOVE_EVENT: + return "mousemove"; + case MOUSEOUT_EVENT: + return "mouseout"; + case DOMSUBTREEMODIFIED_EVENT: + return "DOMSubtreeModified"; + case DOMNODEINSERTED_EVENT: + return "DOMNodeInserted"; + case DOMNODEREMOVED_EVENT: + return "DOMNodeRemoved"; + case DOMNODEREMOVEDFROMDOCUMENT_EVENT: + return "DOMNodeRemovedFromDocument"; + case DOMNODEINSERTEDINTODOCUMENT_EVENT: + return "DOMNodeInsertedIntoDocument"; + case DOMATTRMODIFIED_EVENT: + return "DOMAttrModified"; + case DOMCHARACTERDATAMODIFIED_EVENT: + return "DOMCharacterDataModified"; + case LOAD_EVENT: + return "load"; + case UNLOAD_EVENT: + return "unload"; + case ABORT_EVENT: + return "abort"; + case ERROR_EVENT: + return "error"; + case RESIZE_EVENT: + return "resize"; + case SCROLL_EVENT: + return "scroll"; + case ZOOM_EVENT: + return "zoom"; + case KEYDOWN_EVENT: + return "keydown"; + case KEYUP_EVENT: + return "keyup"; + case KEYPRESS_EVENT: + return "keypress"; + default: + return DOM::DOMString(); + break; + } +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGEvent.h b/ksvg/dom/SVGEvent.h new file mode 100644 index 00000000..6aebf0aa --- /dev/null +++ b/ksvg/dom/SVGEvent.h @@ -0,0 +1,95 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGEvent_H +#define SVGEvent_H + +#include + +namespace KSVG +{ + +class SVGEventImpl; +class SVGEvent : public DOM::Event +{ +public: + enum EventId + { + UNKNOWN_EVENT = 0, + + // UI events + DOMFOCUSIN_EVENT, + DOMFOCUSOUT_EVENT, + DOMACTIVATE_EVENT, + + // Mouse events + CLICK_EVENT, + MOUSEDOWN_EVENT, + MOUSEUP_EVENT, + MOUSEOVER_EVENT, + MOUSEMOVE_EVENT, + MOUSEOUT_EVENT, + + // Mutation events + DOMSUBTREEMODIFIED_EVENT, + DOMNODEINSERTED_EVENT, + DOMNODEREMOVED_EVENT, + DOMNODEREMOVEDFROMDOCUMENT_EVENT, + DOMNODEINSERTEDINTODOCUMENT_EVENT, + DOMATTRMODIFIED_EVENT, + DOMCHARACTERDATAMODIFIED_EVENT, + + // SVG events + LOAD_EVENT, + UNLOAD_EVENT, + ABORT_EVENT, + ERROR_EVENT, + RESIZE_EVENT, + SCROLL_EVENT, + ZOOM_EVENT, + + // Key Events + KEYDOWN_EVENT, + KEYPRESS_EVENT, + KEYUP_EVENT + }; + + SVGEvent(); + SVGEvent(const SVGEvent &other); + SVGEvent &operator=(const SVGEvent &other); + SVGEvent(SVGEventImpl *other); + virtual ~SVGEvent(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGEventImpl *handle() const { return impl; } + + // Helper functions + static EventId typeToId(DOM::DOMString type); + static DOM::DOMString idToType(EventId id); + +private: + SVGEventImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGException.h b/ksvg/dom/SVGException.h new file mode 100644 index 00000000..dbbe7175 --- /dev/null +++ b/ksvg/dom/SVGException.h @@ -0,0 +1,51 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGException_H +#define SVGException_H + +namespace KSVG +{ +// TODO : use when DOM is full and/or ecma binding comes into play +class SVGException +{ +public: + SVGException(unsigned short code) { m_code = code; } + SVGException(const SVGException &other) { m_code = other.m_code; } + SVGException &operator=(const SVGException &other) + { + m_code = other.m_code; + return *this; + } + ~SVGException() {} + + enum ExceptionCode { + SVG_WRONG_TYPE_ERR = 0, + SVG_INVALID_VALUE_ERR = 1, + SVG_MATRIX_NOT_INVERTABLE = 2 + }; + unsigned short m_code; +}; + +}; + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGExternalResourcesRequired.cc b/ksvg/dom/SVGExternalResourcesRequired.cc new file mode 100644 index 00000000..986bf564 --- /dev/null +++ b/ksvg/dom/SVGExternalResourcesRequired.cc @@ -0,0 +1,65 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGExternalResourcesRequired.h" +#include "SVGExternalResourcesRequiredImpl.h" +#include "SVGAnimatedBoolean.h" + +using namespace KSVG; + +// This class can't be constructed seperately. +SVGExternalResourcesRequired::SVGExternalResourcesRequired() +{ + impl = 0; +} + +SVGExternalResourcesRequired::SVGExternalResourcesRequired(const SVGExternalResourcesRequired &other) : impl(0) +{ + (*this) = other; +} + +SVGExternalResourcesRequired &SVGExternalResourcesRequired::operator=(const SVGExternalResourcesRequired &other) +{ + if(impl == other.impl) + return *this; + + impl = other.impl; + + return *this; +} + +SVGExternalResourcesRequired::SVGExternalResourcesRequired(SVGExternalResourcesRequiredImpl *other) +{ + impl = other; +} + +SVGExternalResourcesRequired::~SVGExternalResourcesRequired() +{ + // We are not allowed to delete 'impl' as it's not refcounted. + // delete impl; +} + +SVGAnimatedBoolean SVGExternalResourcesRequired::externalResourcesRequired() const +{ + if(!impl) return SVGAnimatedBoolean(0); + return SVGAnimatedBoolean(impl->externalResourcesRequired()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGExternalResourcesRequired.h b/ksvg/dom/SVGExternalResourcesRequired.h new file mode 100644 index 00000000..e3668881 --- /dev/null +++ b/ksvg/dom/SVGExternalResourcesRequired.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGExternalResourcesRequired_H +#define SVGExternalResourcesRequired_H + +namespace KSVG +{ + +class SVGAnimatedBoolean; +class SVGExternalResourcesRequiredImpl; +class SVGExternalResourcesRequired +{ +public: + SVGExternalResourcesRequired(const SVGExternalResourcesRequired &other); + SVGExternalResourcesRequired &operator=(const SVGExternalResourcesRequired &other); + SVGExternalResourcesRequired(SVGExternalResourcesRequiredImpl *other); + ~SVGExternalResourcesRequired(); + + SVGAnimatedBoolean externalResourcesRequired() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGExternalResourcesRequiredImpl *handle() const { return impl; } + +protected: + SVGExternalResourcesRequired(); + +private: + SVGExternalResourcesRequiredImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEBlendElement.cc b/ksvg/dom/SVGFEBlendElement.cc new file mode 100644 index 00000000..c991d18c --- /dev/null +++ b/ksvg/dom/SVGFEBlendElement.cc @@ -0,0 +1,88 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEBlendElement.h" +#include "SVGFEBlendElementImpl.h" +#include "SVGAnimatedString.h" +#include "SVGAnimatedEnumeration.h" + +using namespace KSVG; + +SVGFEBlendElement::SVGFEBlendElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes() +{ + impl = 0; +} + +SVGFEBlendElement::SVGFEBlendElement(const SVGFEBlendElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0) +{ + (*this) = other; +} + +SVGFEBlendElement &SVGFEBlendElement::operator =(const SVGFEBlendElement &other) +{ + SVGElement::operator=(other); + SVGFilterPrimitiveStandardAttributes::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFEBlendElement::SVGFEBlendElement(SVGFEBlendElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFEBlendElement::~SVGFEBlendElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedString SVGFEBlendElement::in1() const +{ + if(!impl) return SVGAnimatedString(0); + return SVGAnimatedString(impl->in1()); +} + +SVGAnimatedString SVGFEBlendElement::in2() const +{ + if(!impl) return SVGAnimatedString(0); + return SVGAnimatedString(impl->in2()); +} + +SVGAnimatedEnumeration SVGFEBlendElement::mode() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->mode()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEBlendElement.h b/ksvg/dom/SVGFEBlendElement.h new file mode 100644 index 00000000..91c64b3f --- /dev/null +++ b/ksvg/dom/SVGFEBlendElement.h @@ -0,0 +1,68 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEBlendElement_H +#define SVGFEBlendElement_H + +#include "SVGElement.h" +#include "SVGFilterPrimitiveStandardAttributes.h" + +namespace KSVG +{ + +enum +{ + SVG_FEBLEND_MODE_UNKNOWN = 0, + SVG_FEBLEND_MODE_NORMAL = 1, + SVG_FEBLEND_MODE_MULTIPLY = 2, + SVG_FEBLEND_MODE_SCREEN = 3, + SVG_FEBLEND_MODE_DARKEN = 4, + SVG_FEBLEND_MODE_LIGHTEN = 5 +}; + +class SVGAnimatedString; +class SVGAnimatedEnumeration; +class SVGFEBlendElementImpl; +class SVGFEBlendElement : public SVGElement, + public SVGFilterPrimitiveStandardAttributes +{ +public: + SVGFEBlendElement(); + SVGFEBlendElement(const SVGFEBlendElement &other); + SVGFEBlendElement &operator=(const SVGFEBlendElement &other); + SVGFEBlendElement(SVGFEBlendElementImpl *other); + virtual ~SVGFEBlendElement(); + + SVGAnimatedString in1() const; + SVGAnimatedString in2() const; + SVGAnimatedEnumeration mode() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFEBlendElementImpl *handle() const { return impl; } + +private: + SVGFEBlendElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEColorMatrixElement.cc b/ksvg/dom/SVGFEColorMatrixElement.cc new file mode 100644 index 00000000..1f77ac0e --- /dev/null +++ b/ksvg/dom/SVGFEColorMatrixElement.cc @@ -0,0 +1,89 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEColorMatrixElement.h" +#include "SVGFEColorMatrixElementImpl.h" +#include "SVGAnimatedString.h" +#include "SVGAnimatedEnumeration.h" +#include "SVGAnimatedNumberList.h" + +using namespace KSVG; + +SVGFEColorMatrixElement::SVGFEColorMatrixElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes() +{ + impl = 0; +} + +SVGFEColorMatrixElement::SVGFEColorMatrixElement(const SVGFEColorMatrixElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0) +{ + (*this) = other; +} + +SVGFEColorMatrixElement &SVGFEColorMatrixElement::operator =(const SVGFEColorMatrixElement &other) +{ + SVGElement::operator=(other); + SVGFilterPrimitiveStandardAttributes::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFEColorMatrixElement::SVGFEColorMatrixElement(SVGFEColorMatrixElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFEColorMatrixElement::~SVGFEColorMatrixElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedString SVGFEColorMatrixElement::in1() const +{ + if(!impl) return SVGAnimatedString(0); + return SVGAnimatedString(impl->in1()); +} + +SVGAnimatedEnumeration SVGFEColorMatrixElement::type() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->type()); +} + +SVGAnimatedNumberList SVGFEColorMatrixElement::values() const +{ + if(!impl) return SVGAnimatedNumberList(0); + return SVGAnimatedNumberList(impl->values()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEColorMatrixElement.h b/ksvg/dom/SVGFEColorMatrixElement.h new file mode 100644 index 00000000..bbe51f16 --- /dev/null +++ b/ksvg/dom/SVGFEColorMatrixElement.h @@ -0,0 +1,68 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEColorMatrixElement_H +#define SVGFEColorMatrixElement_H + +#include "SVGElement.h" +#include "SVGFilterPrimitiveStandardAttributes.h" + +namespace KSVG +{ + +enum +{ + SVG_FECOLORMATRIX_TYPE_UNKNOWN = 0, + SVG_FECOLORMATRIX_TYPE_MATRIX = 1, + SVG_FECOLORMATRIX_TYPE_SATURATE = 2, + SVG_FECOLORMATRIX_TYPE_HUEROTATE = 3, + SVG_FECOLORMATRIX_TYPE_LUMINANCETOALPHA = 4 +}; + +class SVGAnimatedString; +class SVGAnimatedEnumeration; +class SVGAnimatedNumberList; +class SVGFEColorMatrixElementImpl; +class SVGFEColorMatrixElement : public SVGElement, + public SVGFilterPrimitiveStandardAttributes +{ +public: + SVGFEColorMatrixElement(); + SVGFEColorMatrixElement(const SVGFEColorMatrixElement &other); + SVGFEColorMatrixElement &operator=(const SVGFEColorMatrixElement &other); + SVGFEColorMatrixElement(SVGFEColorMatrixElementImpl *other); + virtual ~SVGFEColorMatrixElement(); + + SVGAnimatedString in1() const; + SVGAnimatedEnumeration type() const; + SVGAnimatedNumberList values() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFEColorMatrixElementImpl *handle() const { return impl; } + +private: + SVGFEColorMatrixElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEComponentTransferElement.cc b/ksvg/dom/SVGFEComponentTransferElement.cc new file mode 100644 index 00000000..ea0d7490 --- /dev/null +++ b/ksvg/dom/SVGFEComponentTransferElement.cc @@ -0,0 +1,75 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEComponentTransferElement.h" +#include "SVGFEComponentTransferElementImpl.h" +#include "SVGAnimatedString.h" + +using namespace KSVG; + +SVGFEComponentTransferElement::SVGFEComponentTransferElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes() +{ + impl = 0; +} + +SVGFEComponentTransferElement::SVGFEComponentTransferElement(const SVGFEComponentTransferElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0) +{ + (*this) = other; +} + +SVGFEComponentTransferElement &SVGFEComponentTransferElement::operator =(const SVGFEComponentTransferElement &other) +{ + SVGElement::operator=(other); + SVGFilterPrimitiveStandardAttributes::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFEComponentTransferElement::SVGFEComponentTransferElement(SVGFEComponentTransferElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFEComponentTransferElement::~SVGFEComponentTransferElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedString SVGFEComponentTransferElement::in1() const +{ + if(!impl) return SVGAnimatedString(0); + return SVGAnimatedString(impl->in1()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEComponentTransferElement.h b/ksvg/dom/SVGFEComponentTransferElement.h new file mode 100644 index 00000000..c387a4ca --- /dev/null +++ b/ksvg/dom/SVGFEComponentTransferElement.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEComponentTransferElement_H +#define SVGFEComponentTransferElement_H + +#include "SVGElement.h" +#include "SVGFilterPrimitiveStandardAttributes.h" + +namespace KSVG +{ + +class SVGAnimatedString; +class SVGFEComponentTransferElementImpl; +class SVGFEComponentTransferElement : public SVGElement, + public SVGFilterPrimitiveStandardAttributes +{ +public: + SVGFEComponentTransferElement(); + SVGFEComponentTransferElement(const SVGFEComponentTransferElement &other); + SVGFEComponentTransferElement &operator=(const SVGFEComponentTransferElement &other); + SVGFEComponentTransferElement(SVGFEComponentTransferElementImpl *other); + virtual ~SVGFEComponentTransferElement(); + + SVGAnimatedString in1() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFEComponentTransferElementImpl *handle() const { return impl; } + +private: + SVGFEComponentTransferElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFECompositeElement.cc b/ksvg/dom/SVGFECompositeElement.cc new file mode 100644 index 00000000..61cf4352 --- /dev/null +++ b/ksvg/dom/SVGFECompositeElement.cc @@ -0,0 +1,113 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFECompositeElement.h" +#include "SVGFECompositeElementImpl.h" +#include "SVGAnimatedNumber.h" +#include "SVGAnimatedString.h" +#include "SVGAnimatedEnumeration.h" + +using namespace KSVG; + +SVGFECompositeElement::SVGFECompositeElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes() +{ + impl = 0; +} + +SVGFECompositeElement::SVGFECompositeElement(const SVGFECompositeElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0) +{ + (*this) = other; +} + +SVGFECompositeElement &SVGFECompositeElement::operator =(const SVGFECompositeElement &other) +{ + SVGElement::operator=(other); + SVGFilterPrimitiveStandardAttributes::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFECompositeElement::SVGFECompositeElement(SVGFECompositeElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFECompositeElement::~SVGFECompositeElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedString SVGFECompositeElement::in1() const +{ + if(!impl) return SVGAnimatedString(0); + return SVGAnimatedString(impl->in1()); +} + +SVGAnimatedString SVGFECompositeElement::in2() const +{ + if(!impl) return SVGAnimatedString(0); + return SVGAnimatedString(impl->in2()); +} + +SVGAnimatedEnumeration SVGFECompositeElement::Operator() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->Operator()); +} + +SVGAnimatedNumber SVGFECompositeElement::k1() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->k1()); +} + +SVGAnimatedNumber SVGFECompositeElement::k2() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->k2()); +} + +SVGAnimatedNumber SVGFECompositeElement::k3() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->k3()); +} + +SVGAnimatedNumber SVGFECompositeElement::k4() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->k4()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFECompositeElement.h b/ksvg/dom/SVGFECompositeElement.h new file mode 100644 index 00000000..dcfa1817 --- /dev/null +++ b/ksvg/dom/SVGFECompositeElement.h @@ -0,0 +1,74 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFECompositeElement_H +#define SVGFECompositeElement_H + +#include "SVGElement.h" +#include "SVGFilterPrimitiveStandardAttributes.h" + +namespace KSVG +{ + +enum +{ + SVG_FECOMPOSITE_OPERATOR_UNKNOWN = 0, + SVG_FECOMPOSITE_OPERATOR_OVER = 1, + SVG_FECOMPOSITE_OPERATOR_IN = 2, + SVG_FECOMPOSITE_OPERATOR_OUT = 3, + SVG_FECOMPOSITE_OPERATOR_ATOP = 4, + SVG_FECOMPOSITE_OPERATOR_XOR = 5, + SVG_FECOMPOSITE_OPERATOR_ARITHMETIC = 6 +}; + +class SVGAnimatedString; +class SVGAnimatedEnumeration; +class SVGAnimatedNumber; +class SVGFECompositeElementImpl; +class SVGFECompositeElement : public SVGElement, + public SVGFilterPrimitiveStandardAttributes +{ +public: + SVGFECompositeElement(); + SVGFECompositeElement(const SVGFECompositeElement &other); + SVGFECompositeElement &operator=(const SVGFECompositeElement &other); + SVGFECompositeElement(SVGFECompositeElementImpl *other); + virtual ~SVGFECompositeElement(); + + SVGAnimatedString in1() const; + SVGAnimatedString in2() const; + SVGAnimatedEnumeration Operator() const; // TODO : impossible otherwise ? + SVGAnimatedNumber k1() const; + SVGAnimatedNumber k2() const; + SVGAnimatedNumber k3() const; + SVGAnimatedNumber k4() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFECompositeElementImpl *handle() const { return impl; } + +private: + SVGFECompositeElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEConvolveMatrixElement.cc b/ksvg/dom/SVGFEConvolveMatrixElement.cc new file mode 100644 index 00000000..5ecc292c --- /dev/null +++ b/ksvg/dom/SVGFEConvolveMatrixElement.cc @@ -0,0 +1,140 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEConvolveMatrixElement.h" +#include "SVGFEConvolveMatrixElementImpl.h" +#include "SVGAnimatedInteger.h" +#include "SVGAnimatedNumberList.h" +#include "SVGAnimatedNumber.h" +#include "SVGAnimatedEnumeration.h" +#include "SVGAnimatedLength.h" +#include "SVGAnimatedBoolean.h" + +using namespace KSVG; + +SVGFEConvolveMatrixElement::SVGFEConvolveMatrixElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes() +{ + impl = 0; +} + +SVGFEConvolveMatrixElement::SVGFEConvolveMatrixElement(const SVGFEConvolveMatrixElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0) +{ + (*this) = other; +} + +SVGFEConvolveMatrixElement &SVGFEConvolveMatrixElement::operator =(const SVGFEConvolveMatrixElement &other) +{ + SVGElement::operator=(other); + SVGFilterPrimitiveStandardAttributes::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFEConvolveMatrixElement::SVGFEConvolveMatrixElement(SVGFEConvolveMatrixElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFEConvolveMatrixElement::~SVGFEConvolveMatrixElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedInteger SVGFEConvolveMatrixElement::orderX() const +{ + if(!impl) return SVGAnimatedInteger(0); + return SVGAnimatedInteger(impl->orderX()); +} + +SVGAnimatedInteger SVGFEConvolveMatrixElement::orderY() const +{ + if(!impl) return SVGAnimatedInteger(0); + return SVGAnimatedInteger(impl->orderY()); +} + +SVGAnimatedNumberList SVGFEConvolveMatrixElement::kernelMatrix() const +{ + if(!impl) return SVGAnimatedNumberList(0); + return SVGAnimatedNumberList(impl->kernelMatrix()); +} + +SVGAnimatedNumber SVGFEConvolveMatrixElement::divisor() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->divisor()); +} + +SVGAnimatedNumber SVGFEConvolveMatrixElement::bias() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->bias()); +} + +SVGAnimatedInteger SVGFEConvolveMatrixElement::targetX() const +{ + if(!impl) return SVGAnimatedInteger(0); + return SVGAnimatedInteger(impl->targetX()); +} + +SVGAnimatedInteger SVGFEConvolveMatrixElement::targetY() const +{ + if(!impl) return SVGAnimatedInteger(0); + return SVGAnimatedInteger(impl->targetY()); +} + +SVGAnimatedEnumeration SVGFEConvolveMatrixElement::edgeMode() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->edgeMode()); +} + +SVGAnimatedLength SVGFEConvolveMatrixElement::kernelUnitLengthX() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->kernelUnitLengthX()); +} + +SVGAnimatedLength SVGFEConvolveMatrixElement::kernelUnitLengthY() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->kernelUnitLengthY()); +} + +SVGAnimatedBoolean SVGFEConvolveMatrixElement::preserveAlpha() const +{ + if(!impl) return SVGAnimatedBoolean(0); + return SVGAnimatedBoolean(impl->preserveAlpha()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEConvolveMatrixElement.h b/ksvg/dom/SVGFEConvolveMatrixElement.h new file mode 100644 index 00000000..88a7ed00 --- /dev/null +++ b/ksvg/dom/SVGFEConvolveMatrixElement.h @@ -0,0 +1,78 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEConvolveMatrixElement_H +#define SVGFEConvolveMatrixElement_H + +#include "SVGElement.h" +#include "SVGFilterPrimitiveStandardAttributes.h" + +namespace KSVG +{ + +enum +{ + SVG_EDGEMODE_UNKNOWN = 0, + SVG_EDGEMODE_DUPLICATE = 1, + SVG_EDGEMODE_WRAP = 2, + SVG_EDGEMODE_NONE = 3 +}; + +class SVGAnimatedInteger; +class SVGAnimatedNumberList; +class SVGAnimatedNumber; +class SVGAnimatedEnumeration; +class SVGAnimatedLength; +class SVGAnimatedBoolean; +class SVGFEConvolveMatrixElementImpl; +class SVGFEConvolveMatrixElement : public SVGElement, + public SVGFilterPrimitiveStandardAttributes +{ +public: + SVGFEConvolveMatrixElement(); + SVGFEConvolveMatrixElement(const SVGFEConvolveMatrixElement &other); + SVGFEConvolveMatrixElement &operator=(const SVGFEConvolveMatrixElement &other); + SVGFEConvolveMatrixElement(SVGFEConvolveMatrixElementImpl *other); + virtual ~SVGFEConvolveMatrixElement(); + + SVGAnimatedInteger orderX() const; + SVGAnimatedInteger orderY() const; + SVGAnimatedNumberList kernelMatrix() const; + SVGAnimatedNumber divisor() const; + SVGAnimatedNumber bias() const; + SVGAnimatedInteger targetX() const; + SVGAnimatedInteger targetY() const; + SVGAnimatedEnumeration edgeMode() const; + SVGAnimatedLength kernelUnitLengthX() const; + SVGAnimatedLength kernelUnitLengthY() const; + SVGAnimatedBoolean preserveAlpha() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFEConvolveMatrixElementImpl *handle() const { return impl; } + +private: + SVGFEConvolveMatrixElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEDiffuseLightingElement.cc b/ksvg/dom/SVGFEDiffuseLightingElement.cc new file mode 100644 index 00000000..eba5935f --- /dev/null +++ b/ksvg/dom/SVGFEDiffuseLightingElement.cc @@ -0,0 +1,88 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEDiffuseLightingElement.h" +#include "SVGFEDiffuseLightingElementImpl.h" +#include "SVGAnimatedString.h" +#include "SVGAnimatedNumber.h" + +using namespace KSVG; + +SVGFEDiffuseLightingElement::SVGFEDiffuseLightingElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes() +{ + impl = 0; +} + +SVGFEDiffuseLightingElement::SVGFEDiffuseLightingElement(const SVGFEDiffuseLightingElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0) +{ + (*this) = other; +} + +SVGFEDiffuseLightingElement &SVGFEDiffuseLightingElement::operator =(const SVGFEDiffuseLightingElement &other) +{ + SVGElement::operator=(other); + SVGFilterPrimitiveStandardAttributes::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFEDiffuseLightingElement::SVGFEDiffuseLightingElement(SVGFEDiffuseLightingElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFEDiffuseLightingElement::~SVGFEDiffuseLightingElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedString SVGFEDiffuseLightingElement::in1() const +{ + if(!impl) return SVGAnimatedString(0); + return SVGAnimatedString(impl->in1()); +} + +SVGAnimatedNumber SVGFEDiffuseLightingElement::surfaceScale() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->surfaceScale()); +} + +SVGAnimatedNumber SVGFEDiffuseLightingElement::diffuseConstant() const +{ + if(!impl) return SVGAnimatedNumber(); + return SVGAnimatedNumber(impl->diffuseConstant()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEDiffuseLightingElement.h b/ksvg/dom/SVGFEDiffuseLightingElement.h new file mode 100644 index 00000000..6356d996 --- /dev/null +++ b/ksvg/dom/SVGFEDiffuseLightingElement.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEDiffuseLightingElement_H +#define SVGFEDiffuseLightingElement_H + +#include "SVGElement.h" +#include "SVGFilterPrimitiveStandardAttributes.h" + +namespace KSVG +{ + +class SVGAnimatedString; +class SVGAnimatedNumber; +class SVGFEDiffuseLightingElementImpl; +class SVGFEDiffuseLightingElement : public SVGElement, + public SVGFilterPrimitiveStandardAttributes +{ +public: + SVGFEDiffuseLightingElement(); + SVGFEDiffuseLightingElement(const SVGFEDiffuseLightingElement &other); + SVGFEDiffuseLightingElement &operator=(const SVGFEDiffuseLightingElement &other); + SVGFEDiffuseLightingElement(SVGFEDiffuseLightingElementImpl *other); + virtual ~SVGFEDiffuseLightingElement(); + + SVGAnimatedString in1() const; + SVGAnimatedNumber surfaceScale() const; + SVGAnimatedNumber diffuseConstant() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFEDiffuseLightingElementImpl *handle() const { return impl; } + +private: + SVGFEDiffuseLightingElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEDisplacementMapElement.cc b/ksvg/dom/SVGFEDisplacementMapElement.cc new file mode 100644 index 00000000..7c41fd3e --- /dev/null +++ b/ksvg/dom/SVGFEDisplacementMapElement.cc @@ -0,0 +1,101 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEDisplacementMapElement.h" +#include "SVGFEDisplacementMapElementImpl.h" +#include "SVGAnimatedString.h" +#include "SVGAnimatedNumber.h" +#include "SVGAnimatedEnumeration.h" + +using namespace KSVG; + +SVGFEDisplacementMapElement::SVGFEDisplacementMapElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes() +{ + impl = 0; +} + +SVGFEDisplacementMapElement::SVGFEDisplacementMapElement(const SVGFEDisplacementMapElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0) +{ + (*this) = other; +} + +SVGFEDisplacementMapElement &SVGFEDisplacementMapElement::operator =(const SVGFEDisplacementMapElement &other) +{ + SVGElement::operator=(other); + SVGFilterPrimitiveStandardAttributes::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFEDisplacementMapElement::SVGFEDisplacementMapElement(SVGFEDisplacementMapElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFEDisplacementMapElement::~SVGFEDisplacementMapElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedString SVGFEDisplacementMapElement::in1() const +{ + if(!impl) return SVGAnimatedString(0); + return SVGAnimatedString(impl->in1()); +} + +SVGAnimatedString SVGFEDisplacementMapElement::in2() const +{ + if(!impl) return SVGAnimatedString(0); + return SVGAnimatedString(impl->in2()); +} + +SVGAnimatedNumber SVGFEDisplacementMapElement::scale() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->scale()); +} + +SVGAnimatedEnumeration SVGFEDisplacementMapElement::xChannelSelector() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->xChannelSelector()); +} + +SVGAnimatedEnumeration SVGFEDisplacementMapElement::yChannelSelector() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->yChannelSelector()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEDisplacementMapElement.h b/ksvg/dom/SVGFEDisplacementMapElement.h new file mode 100644 index 00000000..ee591ca4 --- /dev/null +++ b/ksvg/dom/SVGFEDisplacementMapElement.h @@ -0,0 +1,69 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEDisplacementMapElement_H +#define SVGFEDisplacementMapElement_H + +#include "SVGElement.h" +#include "SVGFilterPrimitiveStandardAttributes.h" + +namespace KSVG +{ +enum +{ + SVG_CHANNEL_UNKNOWN = 0, + SVG_CHANNEL_R = 1, + SVG_CHANNEL_G = 2, + SVG_CHANNEL_B = 3, + SVG_CHANNEL_A = 4 +}; + +class SVGAnimatedNumber; +class SVGAnimatedString; +class SVGAnimatedEnumeration; +class SVGFEDisplacementMapElementImpl; +class SVGFEDisplacementMapElement : public SVGElement, + public SVGFilterPrimitiveStandardAttributes +{ +public: + SVGFEDisplacementMapElement(); + SVGFEDisplacementMapElement(const SVGFEDisplacementMapElement &other); + SVGFEDisplacementMapElement &operator=(const SVGFEDisplacementMapElement &other); + SVGFEDisplacementMapElement(SVGFEDisplacementMapElementImpl *other); + virtual ~SVGFEDisplacementMapElement(); + + SVGAnimatedString in1() const; + SVGAnimatedString in2() const; + SVGAnimatedNumber scale() const; + SVGAnimatedEnumeration xChannelSelector() const; + SVGAnimatedEnumeration yChannelSelector() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFEDisplacementMapElementImpl *handle() const { return impl; } + +private: + SVGFEDisplacementMapElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEDistantLightElement.cc b/ksvg/dom/SVGFEDistantLightElement.cc new file mode 100644 index 00000000..92371abc --- /dev/null +++ b/ksvg/dom/SVGFEDistantLightElement.cc @@ -0,0 +1,80 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEDistantLightElement.h" +#include "SVGFEDistantLightElementImpl.h" +#include "SVGAnimatedNumber.h" + +using namespace KSVG; + +SVGFEDistantLightElement::SVGFEDistantLightElement() : SVGElement() +{ + impl = 0; +} + +SVGFEDistantLightElement::SVGFEDistantLightElement(const SVGFEDistantLightElement &other) : SVGElement(other), impl(0) +{ + (*this) = other; +} + +SVGFEDistantLightElement &SVGFEDistantLightElement::operator =(const SVGFEDistantLightElement &other) +{ + SVGElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFEDistantLightElement::SVGFEDistantLightElement(SVGFEDistantLightElementImpl *other) : SVGElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFEDistantLightElement::~SVGFEDistantLightElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedNumber SVGFEDistantLightElement::azimuth() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->azimuth()); +} + +SVGAnimatedNumber SVGFEDistantLightElement::elevation() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->elevation()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEDistantLightElement.h b/ksvg/dom/SVGFEDistantLightElement.h new file mode 100644 index 00000000..4b2c926a --- /dev/null +++ b/ksvg/dom/SVGFEDistantLightElement.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEDistantLightElement_H +#define SVGFEDistantLightElement_H + +#include "SVGElement.h" + +namespace KSVG +{ + +class SVGAnimatedNumber; +class SVGFEDistantLightElementImpl; +class SVGFEDistantLightElement : public SVGElement +{ +public: + SVGFEDistantLightElement(); + SVGFEDistantLightElement(const SVGFEDistantLightElement &other); + SVGFEDistantLightElement &operator=(const SVGFEDistantLightElement &other); + SVGFEDistantLightElement(SVGFEDistantLightElementImpl *other); + virtual ~SVGFEDistantLightElement(); + + SVGAnimatedNumber azimuth() const; + SVGAnimatedNumber elevation() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFEDistantLightElementImpl *handle() const { return impl; } + +private: + SVGFEDistantLightElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEFloodElement.cc b/ksvg/dom/SVGFEFloodElement.cc new file mode 100644 index 00000000..7b0b320c --- /dev/null +++ b/ksvg/dom/SVGFEFloodElement.cc @@ -0,0 +1,76 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEFloodElement.h" +#include "SVGFEFloodElementImpl.h" +#include "SVGAnimatedString.h" + +using namespace KSVG; + +SVGFEFloodElement::SVGFEFloodElement() : SVGElement(), SVGStylable(), SVGFilterPrimitiveStandardAttributes() +{ + impl = 0; +} + +SVGFEFloodElement::SVGFEFloodElement(const SVGFEFloodElement &other) : SVGElement(other), SVGStylable(other), SVGFilterPrimitiveStandardAttributes(other), impl(0) +{ + (*this) = other; +} + +SVGFEFloodElement &SVGFEFloodElement::operator =(const SVGFEFloodElement &other) +{ + SVGElement::operator=(other); + SVGStylable::operator=(other); + SVGFilterPrimitiveStandardAttributes::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFEFloodElement::SVGFEFloodElement(SVGFEFloodElementImpl *other) : SVGElement(other), SVGStylable(other), SVGFilterPrimitiveStandardAttributes(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFEFloodElement::~SVGFEFloodElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedString SVGFEFloodElement::in1() const +{ + if(!impl) return SVGAnimatedString(0); + return SVGAnimatedString(impl->in1()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEFloodElement.h b/ksvg/dom/SVGFEFloodElement.h new file mode 100644 index 00000000..401e056b --- /dev/null +++ b/ksvg/dom/SVGFEFloodElement.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEFloodElement_H +#define SVGFEFloodElement_H + +#include "SVGElement.h" +#include "SVGStylable.h" +#include "SVGFilterPrimitiveStandardAttributes.h" + +namespace KSVG +{ + +class SVGAnimatedString; +class SVGFEFloodElementImpl; +class SVGFEFloodElement : public SVGElement, + public SVGStylable, + public SVGFilterPrimitiveStandardAttributes +{ +public: + SVGFEFloodElement(); + SVGFEFloodElement(const SVGFEFloodElement &other); + SVGFEFloodElement &operator=(const SVGFEFloodElement &other); + SVGFEFloodElement(SVGFEFloodElementImpl *other); + virtual ~SVGFEFloodElement(); + + SVGAnimatedString in1() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFEFloodElementImpl *handle() const { return impl; } + +private: + SVGFEFloodElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEFuncAElement.cc b/ksvg/dom/SVGFEFuncAElement.cc new file mode 100644 index 00000000..cd0e9f10 --- /dev/null +++ b/ksvg/dom/SVGFEFuncAElement.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEFuncAElement.h" +#include "SVGFEFuncAElementImpl.h" + +using namespace KSVG; + +SVGFEFuncAElement::SVGFEFuncAElement() : SVGComponentTransferFunctionElement() +{ + impl = 0; +} + +SVGFEFuncAElement::SVGFEFuncAElement(const SVGFEFuncAElement &other) : SVGComponentTransferFunctionElement(other), impl(0) +{ + (*this) = other; +} + +SVGFEFuncAElement &SVGFEFuncAElement::operator =(const SVGFEFuncAElement &other) +{ + SVGComponentTransferFunctionElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFEFuncAElement::SVGFEFuncAElement(SVGFEFuncAElementImpl *other) : SVGComponentTransferFunctionElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFEFuncAElement::~SVGFEFuncAElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEFuncAElement.h b/ksvg/dom/SVGFEFuncAElement.h new file mode 100644 index 00000000..64287f27 --- /dev/null +++ b/ksvg/dom/SVGFEFuncAElement.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEFuncAElement_H +#define SVGFEFuncAElement_H + +#include "SVGComponentTransferFunctionElement.h" + +namespace KSVG +{ + +class SVGFEFuncAElementImpl; +class SVGFEFuncAElement : public SVGComponentTransferFunctionElement +{ +public: + SVGFEFuncAElement(); + SVGFEFuncAElement(const SVGFEFuncAElement &other); + SVGFEFuncAElement &operator=(const SVGFEFuncAElement &other); + SVGFEFuncAElement(SVGFEFuncAElementImpl *other); + virtual ~SVGFEFuncAElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFEFuncAElementImpl *handle() const { return impl; } + +private: + SVGFEFuncAElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEFuncBElement.cc b/ksvg/dom/SVGFEFuncBElement.cc new file mode 100644 index 00000000..2cf0fdb0 --- /dev/null +++ b/ksvg/dom/SVGFEFuncBElement.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEFuncBElement.h" +#include "SVGFEFuncBElementImpl.h" + +using namespace KSVG; + +SVGFEFuncBElement::SVGFEFuncBElement() : SVGComponentTransferFunctionElement() +{ + impl = 0; +} + +SVGFEFuncBElement::SVGFEFuncBElement(const SVGFEFuncBElement &other) : SVGComponentTransferFunctionElement(other), impl(0) +{ + (*this) = other; +} + +SVGFEFuncBElement &SVGFEFuncBElement::operator =(const SVGFEFuncBElement &other) +{ + SVGComponentTransferFunctionElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFEFuncBElement::SVGFEFuncBElement(SVGFEFuncBElementImpl *other) : SVGComponentTransferFunctionElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFEFuncBElement::~SVGFEFuncBElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEFuncBElement.h b/ksvg/dom/SVGFEFuncBElement.h new file mode 100644 index 00000000..2eacbbc3 --- /dev/null +++ b/ksvg/dom/SVGFEFuncBElement.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEFuncBElement_H +#define SVGFEFuncBElement_H + +#include "SVGComponentTransferFunctionElement.h" + +namespace KSVG +{ + +class SVGFEFuncBElementImpl; +class SVGFEFuncBElement : public SVGComponentTransferFunctionElement +{ +public: + SVGFEFuncBElement(); + SVGFEFuncBElement(const SVGFEFuncBElement &other); + SVGFEFuncBElement &operator=(const SVGFEFuncBElement &other); + SVGFEFuncBElement(SVGFEFuncBElementImpl *other); + virtual ~SVGFEFuncBElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFEFuncBElementImpl *handle() const { return impl; } + +private: + SVGFEFuncBElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEFuncGElement.cc b/ksvg/dom/SVGFEFuncGElement.cc new file mode 100644 index 00000000..ef8fdfea --- /dev/null +++ b/ksvg/dom/SVGFEFuncGElement.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEFuncGElement.h" +#include "SVGFEFuncGElementImpl.h" + +using namespace KSVG; + +SVGFEFuncGElement::SVGFEFuncGElement() : SVGComponentTransferFunctionElement() +{ + impl = 0; +} + +SVGFEFuncGElement::SVGFEFuncGElement(const SVGFEFuncGElement &other) : SVGComponentTransferFunctionElement(other), impl(0) +{ + (*this) = other; +} + +SVGFEFuncGElement &SVGFEFuncGElement::operator =(const SVGFEFuncGElement &other) +{ + SVGComponentTransferFunctionElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFEFuncGElement::SVGFEFuncGElement(SVGFEFuncGElementImpl *other) : SVGComponentTransferFunctionElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFEFuncGElement::~SVGFEFuncGElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEFuncGElement.h b/ksvg/dom/SVGFEFuncGElement.h new file mode 100644 index 00000000..09c98195 --- /dev/null +++ b/ksvg/dom/SVGFEFuncGElement.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEFuncGElement_H +#define SVGFEFuncGElement_H + +#include "SVGComponentTransferFunctionElement.h" + +namespace KSVG +{ + +class SVGFEFuncGElementImpl; +class SVGFEFuncGElement : public SVGComponentTransferFunctionElement +{ +public: + SVGFEFuncGElement(); + SVGFEFuncGElement(const SVGFEFuncGElement &other); + SVGFEFuncGElement &operator=(const SVGFEFuncGElement &other); + SVGFEFuncGElement(SVGFEFuncGElementImpl *other); + virtual ~SVGFEFuncGElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFEFuncGElementImpl *handle() const { return impl; } + +private: + SVGFEFuncGElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEFuncRElement.cc b/ksvg/dom/SVGFEFuncRElement.cc new file mode 100644 index 00000000..2020e33c --- /dev/null +++ b/ksvg/dom/SVGFEFuncRElement.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEFuncRElement.h" +#include "SVGFEFuncRElementImpl.h" + +using namespace KSVG; + +SVGFEFuncRElement::SVGFEFuncRElement() : SVGComponentTransferFunctionElement() +{ + impl = 0; +} + +SVGFEFuncRElement::SVGFEFuncRElement(const SVGFEFuncRElement &other) : SVGComponentTransferFunctionElement(other), impl(0) +{ + (*this) = other; +} + +SVGFEFuncRElement &SVGFEFuncRElement::operator =(const SVGFEFuncRElement &other) +{ + SVGComponentTransferFunctionElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFEFuncRElement::SVGFEFuncRElement(SVGFEFuncRElementImpl *other) : SVGComponentTransferFunctionElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFEFuncRElement::~SVGFEFuncRElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEFuncRElement.h b/ksvg/dom/SVGFEFuncRElement.h new file mode 100644 index 00000000..1a58ef15 --- /dev/null +++ b/ksvg/dom/SVGFEFuncRElement.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEFuncRElement_H +#define SVGFEFuncRElement_H + +#include "SVGComponentTransferFunctionElement.h" + +namespace KSVG +{ + +class SVGFEFuncRElementImpl; +class SVGFEFuncRElement : public SVGComponentTransferFunctionElement +{ +public: + SVGFEFuncRElement(); + SVGFEFuncRElement(const SVGFEFuncRElement &other); + SVGFEFuncRElement &operator=(const SVGFEFuncRElement &other); + SVGFEFuncRElement(SVGFEFuncRElementImpl *other); + virtual ~SVGFEFuncRElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFEFuncRElementImpl *handle() const { return impl; } + +private: + SVGFEFuncRElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEGaussianBlurElement.cc b/ksvg/dom/SVGFEGaussianBlurElement.cc new file mode 100644 index 00000000..2daaa8b8 --- /dev/null +++ b/ksvg/dom/SVGFEGaussianBlurElement.cc @@ -0,0 +1,94 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEGaussianBlurElement.h" +#include "SVGFEGaussianBlurElementImpl.h" +#include "SVGAnimatedString.h" +#include "SVGAnimatedNumber.h" + +using namespace KSVG; + +SVGFEGaussianBlurElement::SVGFEGaussianBlurElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes() +{ + impl = 0; +} + +SVGFEGaussianBlurElement::SVGFEGaussianBlurElement(const SVGFEGaussianBlurElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0) +{ + (*this) = other; +} + +SVGFEGaussianBlurElement &SVGFEGaussianBlurElement::operator =(const SVGFEGaussianBlurElement &other) +{ + SVGElement::operator=(other); + SVGFilterPrimitiveStandardAttributes::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFEGaussianBlurElement::SVGFEGaussianBlurElement(SVGFEGaussianBlurElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFEGaussianBlurElement::~SVGFEGaussianBlurElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedString SVGFEGaussianBlurElement::in1() const +{ + if(!impl) return SVGAnimatedString(0); + return SVGAnimatedString(impl->in1()); +} + +SVGAnimatedNumber SVGFEGaussianBlurElement::stdDeviationX() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->stdDeviationX()); +} + +SVGAnimatedNumber SVGFEGaussianBlurElement::stdDeviationY() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->stdDeviationY()); +} + +void SVGFEGaussianBlurElement::setStdDeviation(float stdDeviationX, float stdDeviationY) +{ + if(impl) + impl->setStdDeviation(stdDeviationX, stdDeviationY); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEGaussianBlurElement.h b/ksvg/dom/SVGFEGaussianBlurElement.h new file mode 100644 index 00000000..a920ea68 --- /dev/null +++ b/ksvg/dom/SVGFEGaussianBlurElement.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEGaussianBlurElement_H +#define SVGFEGaussianBlurElement_H + +#include "SVGElement.h" +#include "SVGFilterPrimitiveStandardAttributes.h" + +namespace KSVG +{ + +class SVGAnimatedString; +class SVGAnimatedNumber; +class SVGFEGaussianBlurElementImpl; +class SVGFEGaussianBlurElement : public SVGElement, + public SVGFilterPrimitiveStandardAttributes +{ +public: + SVGFEGaussianBlurElement(); + SVGFEGaussianBlurElement(const SVGFEGaussianBlurElement &other); + SVGFEGaussianBlurElement &operator=(const SVGFEGaussianBlurElement &other); + SVGFEGaussianBlurElement(SVGFEGaussianBlurElementImpl *other); + virtual ~SVGFEGaussianBlurElement(); + + SVGAnimatedString in1() const; + SVGAnimatedNumber stdDeviationX() const; + SVGAnimatedNumber stdDeviationY() const; + + void setStdDeviation(float stdDeviationX, float stdDeviationY); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFEGaussianBlurElementImpl *handle() const { return impl; } + +private: + SVGFEGaussianBlurElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEImageElement.cc b/ksvg/dom/SVGFEImageElement.cc new file mode 100644 index 00000000..6781edb6 --- /dev/null +++ b/ksvg/dom/SVGFEImageElement.cc @@ -0,0 +1,72 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEImageElement.h" +#include "SVGFEImageElementImpl.h" + +using namespace KSVG; + +SVGFEImageElement::SVGFEImageElement() : SVGElement(), SVGURIReference(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGFilterPrimitiveStandardAttributes() +{ + impl = 0; +} + +SVGFEImageElement::SVGFEImageElement(const SVGFEImageElement &other) : SVGElement(other), SVGURIReference(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGFilterPrimitiveStandardAttributes(other), impl(0) +{ + (*this) = other; +} + +SVGFEImageElement &SVGFEImageElement::operator =(const SVGFEImageElement &other) +{ + SVGElement::operator=(other); + SVGURIReference::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + SVGFilterPrimitiveStandardAttributes::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFEImageElement::SVGFEImageElement(SVGFEImageElementImpl *other) : SVGElement(other), SVGURIReference(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGFilterPrimitiveStandardAttributes(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFEImageElement::~SVGFEImageElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEImageElement.h b/ksvg/dom/SVGFEImageElement.h new file mode 100644 index 00000000..2c8d5b38 --- /dev/null +++ b/ksvg/dom/SVGFEImageElement.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEImageElement_H +#define SVGFEImageElement_H + +#include "SVGElement.h" +#include "SVGURIReference.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGFilterPrimitiveStandardAttributes.h" + +namespace KSVG +{ + +class SVGFEImageElementImpl; +class SVGFEImageElement : public SVGElement, + public SVGURIReference, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGFilterPrimitiveStandardAttributes +{ +public: + SVGFEImageElement(); + SVGFEImageElement(const SVGFEImageElement &other); + SVGFEImageElement &operator=(const SVGFEImageElement &other); + SVGFEImageElement(SVGFEImageElementImpl *other); + virtual ~SVGFEImageElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFEImageElementImpl *handle() const { return impl; } + +private: + SVGFEImageElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEMergeElement.cc b/ksvg/dom/SVGFEMergeElement.cc new file mode 100644 index 00000000..8440cd53 --- /dev/null +++ b/ksvg/dom/SVGFEMergeElement.cc @@ -0,0 +1,68 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEMergeElement.h" +#include "SVGFEMergeElementImpl.h" + +using namespace KSVG; + +SVGFEMergeElement::SVGFEMergeElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes() +{ + impl = 0; +} + +SVGFEMergeElement::SVGFEMergeElement(const SVGFEMergeElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0) +{ + (*this) = other; +} + +SVGFEMergeElement &SVGFEMergeElement::operator =(const SVGFEMergeElement &other) +{ + SVGElement::operator=(other); + SVGFilterPrimitiveStandardAttributes::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFEMergeElement::SVGFEMergeElement(SVGFEMergeElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFEMergeElement::~SVGFEMergeElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEMergeElement.h b/ksvg/dom/SVGFEMergeElement.h new file mode 100644 index 00000000..72e915ec --- /dev/null +++ b/ksvg/dom/SVGFEMergeElement.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEMergeElement_H +#define SVGFEMergeElement_H + +#include "SVGElement.h" +#include "SVGFilterPrimitiveStandardAttributes.h" + +namespace KSVG +{ + +class SVGFEMergeElementImpl; +class SVGFEMergeElement : public SVGElement, + public SVGFilterPrimitiveStandardAttributes +{ +public: + SVGFEMergeElement(); + SVGFEMergeElement(const SVGFEMergeElement &other); + SVGFEMergeElement &operator=(const SVGFEMergeElement &other); + SVGFEMergeElement(SVGFEMergeElementImpl *other); + virtual ~SVGFEMergeElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFEMergeElementImpl *handle() const { return impl; } + +private: + SVGFEMergeElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEMergeNodeElement.cc b/ksvg/dom/SVGFEMergeNodeElement.cc new file mode 100644 index 00000000..7abe70e7 --- /dev/null +++ b/ksvg/dom/SVGFEMergeNodeElement.cc @@ -0,0 +1,74 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEMergeNodeElement.h" +#include "SVGFEMergeNodeElementImpl.h" +#include "SVGAnimatedString.h" + +using namespace KSVG; + +SVGFEMergeNodeElement::SVGFEMergeNodeElement() : SVGElement() +{ + impl = 0; +} + +SVGFEMergeNodeElement::SVGFEMergeNodeElement(const SVGFEMergeNodeElement &other) : SVGElement(other), impl(0) +{ + (*this) = other; +} + +SVGFEMergeNodeElement &SVGFEMergeNodeElement::operator =(const SVGFEMergeNodeElement &other) +{ + SVGElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFEMergeNodeElement::SVGFEMergeNodeElement(SVGFEMergeNodeElementImpl *other) : SVGElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFEMergeNodeElement::~SVGFEMergeNodeElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedString SVGFEMergeNodeElement::in1() const +{ + if(!impl) return SVGAnimatedString(0); + return SVGAnimatedString(impl->in1()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEMergeNodeElement.h b/ksvg/dom/SVGFEMergeNodeElement.h new file mode 100644 index 00000000..e9002f0c --- /dev/null +++ b/ksvg/dom/SVGFEMergeNodeElement.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEMergeNodeElement_H +#define SVGFEMergeNodeElement_H + +#include "SVGElement.h" + +namespace KSVG +{ + +class SVGAnimatedString; +class SVGFEMergeNodeElementImpl; +class SVGFEMergeNodeElement : public SVGElement +{ +public: + SVGFEMergeNodeElement(); + SVGFEMergeNodeElement(const SVGFEMergeNodeElement &other); + SVGFEMergeNodeElement &operator=(const SVGFEMergeNodeElement &other); + SVGFEMergeNodeElement(SVGFEMergeNodeElementImpl *other); + virtual ~SVGFEMergeNodeElement(); + + SVGAnimatedString in1() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFEMergeNodeElementImpl *handle() const { return impl; } + +private: + SVGFEMergeNodeElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEMorphologyElement.cc b/ksvg/dom/SVGFEMorphologyElement.cc new file mode 100644 index 00000000..293d86a8 --- /dev/null +++ b/ksvg/dom/SVGFEMorphologyElement.cc @@ -0,0 +1,95 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEMorphologyElement.h" +#include "SVGFEMorphologyElementImpl.h" +#include "SVGAnimatedString.h" +#include "SVGAnimatedEnumeration.h" +#include "SVGAnimatedLength.h" + +using namespace KSVG; + +SVGFEMorphologyElement::SVGFEMorphologyElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes() +{ + impl = 0; +} + +SVGFEMorphologyElement::SVGFEMorphologyElement(const SVGFEMorphologyElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0) +{ + (*this) = other; +} + +SVGFEMorphologyElement &SVGFEMorphologyElement::operator =(const SVGFEMorphologyElement &other) +{ + SVGElement::operator=(other); + SVGFilterPrimitiveStandardAttributes::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFEMorphologyElement::SVGFEMorphologyElement(SVGFEMorphologyElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFEMorphologyElement::~SVGFEMorphologyElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedString SVGFEMorphologyElement::in1() const +{ + if(!impl) return SVGAnimatedString(0); + return SVGAnimatedString(impl->in1()); +} + +SVGAnimatedEnumeration SVGFEMorphologyElement::Operator() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->Operator()); +} + +SVGAnimatedLength SVGFEMorphologyElement::radiusX() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->radiusX()); +} + +SVGAnimatedLength SVGFEMorphologyElement::radiusY() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->radiusY()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEMorphologyElement.h b/ksvg/dom/SVGFEMorphologyElement.h new file mode 100644 index 00000000..7ca1b6a0 --- /dev/null +++ b/ksvg/dom/SVGFEMorphologyElement.h @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEMorphologyElement_H +#define SVGFEMorphologyElement_H + +#include "SVGElement.h" +#include "SVGFilterPrimitiveStandardAttributes.h" + +namespace KSVG +{ + +enum +{ + SVG_MORPHOLOGY_OPERATOR_UNKNOWN = 0, + SVG_MORPHOLOGY_OPERATOR_ERODE = 1, + SVG_MORPHOLOGY_OPERATOR_DILATE = 2 +}; + +class SVGAnimatedString; +class SVGAnimatedEnumeration; +class SVGAnimatedLength; +class SVGFEMorphologyElementImpl; +class SVGFEMorphologyElement : public SVGElement, + public SVGFilterPrimitiveStandardAttributes +{ +public: + SVGFEMorphologyElement(); + SVGFEMorphologyElement(const SVGFEMorphologyElement &other); + SVGFEMorphologyElement &operator=(const SVGFEMorphologyElement &other); + SVGFEMorphologyElement(SVGFEMorphologyElementImpl *other); + virtual ~SVGFEMorphologyElement(); + + SVGAnimatedString in1() const; + SVGAnimatedEnumeration Operator() const; + SVGAnimatedLength radiusX() const; + SVGAnimatedLength radiusY() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFEMorphologyElementImpl *handle() const { return impl; } + +private: + SVGFEMorphologyElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEOffsetElement.cc b/ksvg/dom/SVGFEOffsetElement.cc new file mode 100644 index 00000000..f16ff5ed --- /dev/null +++ b/ksvg/dom/SVGFEOffsetElement.cc @@ -0,0 +1,88 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEOffsetElement.h" +#include "SVGFEOffsetElementImpl.h" +#include "SVGAnimatedNumber.h" +#include "SVGAnimatedString.h" + +using namespace KSVG; + +SVGFEOffsetElement::SVGFEOffsetElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes() +{ + impl = 0; +} + +SVGFEOffsetElement::SVGFEOffsetElement(const SVGFEOffsetElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0) +{ + (*this) = other; +} + +SVGFEOffsetElement &SVGFEOffsetElement::operator =(const SVGFEOffsetElement &other) +{ + SVGElement::operator=(other); + SVGFilterPrimitiveStandardAttributes::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFEOffsetElement::SVGFEOffsetElement(SVGFEOffsetElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFEOffsetElement::~SVGFEOffsetElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedString SVGFEOffsetElement::in1() const +{ + if(!impl) return SVGAnimatedString(0); + return SVGAnimatedString(impl->in1()); +} + +SVGAnimatedNumber SVGFEOffsetElement::dx() const +{ + if(!impl) return SVGAnimatedNumber(0); // FIXME + return SVGAnimatedNumber(impl->dx()); +} + +SVGAnimatedNumber SVGFEOffsetElement::dy() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->dy()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEOffsetElement.h b/ksvg/dom/SVGFEOffsetElement.h new file mode 100644 index 00000000..62b63407 --- /dev/null +++ b/ksvg/dom/SVGFEOffsetElement.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEOffsetElement_H +#define SVGFEOffsetElement_H + +#include "SVGElement.h" +#include "SVGFilterPrimitiveStandardAttributes.h" + +namespace KSVG +{ + +class SVGAnimatedString; +class SVGAnimatedNumber; +class SVGFEOffsetElementImpl; +class SVGFEOffsetElement : public SVGElement, + public SVGFilterPrimitiveStandardAttributes +{ +public: + SVGFEOffsetElement(); + SVGFEOffsetElement(const SVGFEOffsetElement &other); + SVGFEOffsetElement &operator=(const SVGFEOffsetElement &other); + SVGFEOffsetElement(SVGFEOffsetElementImpl *other); + virtual ~SVGFEOffsetElement(); + + SVGAnimatedString in1() const; + SVGAnimatedNumber dx() const; + SVGAnimatedNumber dy() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFEOffsetElementImpl *handle() const { return impl; } + +private: + SVGFEOffsetElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEPointLightElement.cc b/ksvg/dom/SVGFEPointLightElement.cc new file mode 100644 index 00000000..ce5e4635 --- /dev/null +++ b/ksvg/dom/SVGFEPointLightElement.cc @@ -0,0 +1,86 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEPointLightElement.h" +#include "SVGFEPointLightElementImpl.h" +#include "SVGAnimatedNumber.h" + +using namespace KSVG; + +SVGFEPointLightElement::SVGFEPointLightElement() : SVGElement() +{ + impl = 0; +} + +SVGFEPointLightElement::SVGFEPointLightElement(const SVGFEPointLightElement &other) : SVGElement(other), impl(0) +{ + (*this) = other; +} + +SVGFEPointLightElement &SVGFEPointLightElement::operator =(const SVGFEPointLightElement &other) +{ + SVGElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFEPointLightElement::SVGFEPointLightElement(SVGFEPointLightElementImpl *other) : SVGElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFEPointLightElement::~SVGFEPointLightElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedNumber SVGFEPointLightElement::x() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->x()); +} + +SVGAnimatedNumber SVGFEPointLightElement::y() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->y()); +} + +SVGAnimatedNumber SVGFEPointLightElement::z() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->z()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFEPointLightElement.h b/ksvg/dom/SVGFEPointLightElement.h new file mode 100644 index 00000000..1d029e00 --- /dev/null +++ b/ksvg/dom/SVGFEPointLightElement.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEPointLightElement_H +#define SVGFEPointLightElement_H + +#include "SVGElement.h" + +namespace KSVG +{ + +class SVGAnimatedNumber; +class SVGFEPointLightElementImpl; +class SVGFEPointLightElement : public SVGElement +{ +public: + SVGFEPointLightElement(); + SVGFEPointLightElement(const SVGFEPointLightElement &other); + SVGFEPointLightElement &operator=(const SVGFEPointLightElement &other); + SVGFEPointLightElement(SVGFEPointLightElementImpl *other); + virtual ~SVGFEPointLightElement(); + + SVGAnimatedNumber x() const; + SVGAnimatedNumber y() const; + SVGAnimatedNumber z() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFEPointLightElementImpl *handle() const { return impl; } + +private: + SVGFEPointLightElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFESpecularLightingElement.cc b/ksvg/dom/SVGFESpecularLightingElement.cc new file mode 100644 index 00000000..924e1ce7 --- /dev/null +++ b/ksvg/dom/SVGFESpecularLightingElement.cc @@ -0,0 +1,94 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFESpecularLightingElement.h" +#include "SVGFESpecularLightingElementImpl.h" +#include "SVGAnimatedNumber.h" +#include "SVGAnimatedString.h" + +using namespace KSVG; + +SVGFESpecularLightingElement::SVGFESpecularLightingElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes() +{ + impl = 0; +} + +SVGFESpecularLightingElement::SVGFESpecularLightingElement(const SVGFESpecularLightingElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0) +{ + (*this) = other; +} + +SVGFESpecularLightingElement &SVGFESpecularLightingElement::operator =(const SVGFESpecularLightingElement &other) +{ + SVGElement::operator=(other); + SVGFilterPrimitiveStandardAttributes::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFESpecularLightingElement::SVGFESpecularLightingElement(SVGFESpecularLightingElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFESpecularLightingElement::~SVGFESpecularLightingElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedString SVGFESpecularLightingElement::in1() const +{ + if(!impl) return SVGAnimatedString(0); + return SVGAnimatedString(impl->in1()); +} + +SVGAnimatedNumber SVGFESpecularLightingElement::surfaceScale() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->surfaceScale()); +} + +SVGAnimatedNumber SVGFESpecularLightingElement::specularConstant() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->specularConstant()); +} + +SVGAnimatedNumber SVGFESpecularLightingElement::specularExponent() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->specularExponent()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFESpecularLightingElement.h b/ksvg/dom/SVGFESpecularLightingElement.h new file mode 100644 index 00000000..3566006c --- /dev/null +++ b/ksvg/dom/SVGFESpecularLightingElement.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFESpecularLightingElement_H +#define SVGFESpecularLightingElement_H + +#include "SVGElement.h" +#include "SVGFilterPrimitiveStandardAttributes.h" + +namespace KSVG +{ + +class SVGAnimatedString; +class SVGAnimatedNumber; +class SVGFESpecularLightingElementImpl; +class SVGFESpecularLightingElement : public SVGElement, + public SVGFilterPrimitiveStandardAttributes +{ +public: + SVGFESpecularLightingElement(); + SVGFESpecularLightingElement(const SVGFESpecularLightingElement &other); + SVGFESpecularLightingElement &operator=(const SVGFESpecularLightingElement &other); + SVGFESpecularLightingElement(SVGFESpecularLightingElementImpl *other); + virtual ~SVGFESpecularLightingElement(); + + SVGAnimatedString in1() const; + SVGAnimatedNumber surfaceScale() const; + SVGAnimatedNumber specularConstant() const; + SVGAnimatedNumber specularExponent() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFESpecularLightingElementImpl *handle() const { return impl; } + +private: + SVGFESpecularLightingElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFESpotLightElement.cc b/ksvg/dom/SVGFESpotLightElement.cc new file mode 100644 index 00000000..57dd498f --- /dev/null +++ b/ksvg/dom/SVGFESpotLightElement.cc @@ -0,0 +1,116 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFESpotLightElement.h" +#include "SVGFESpotLightElementImpl.h" +#include "SVGAnimatedNumber.h" + +using namespace KSVG; + +SVGFESpotLightElement::SVGFESpotLightElement() : SVGElement() +{ + impl = 0; +} + +SVGFESpotLightElement::SVGFESpotLightElement(const SVGFESpotLightElement &other) : SVGElement(other), impl(0) +{ + (*this) = other; +} + +SVGFESpotLightElement &SVGFESpotLightElement::operator =(const SVGFESpotLightElement &other) +{ + SVGElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFESpotLightElement::SVGFESpotLightElement(SVGFESpotLightElementImpl *other) : SVGElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFESpotLightElement::~SVGFESpotLightElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedNumber SVGFESpotLightElement::x() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->x()); +} + +SVGAnimatedNumber SVGFESpotLightElement::y() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->y()); +} + +SVGAnimatedNumber SVGFESpotLightElement::z() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->z()); +} + +SVGAnimatedNumber SVGFESpotLightElement::pointsAtX() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->pointsAtX()); +} + +SVGAnimatedNumber SVGFESpotLightElement::pointsAtY() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->pointsAtY()); +} + +SVGAnimatedNumber SVGFESpotLightElement::pointsAtZ() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->pointsAtZ()); +} + +SVGAnimatedNumber SVGFESpotLightElement::specularExponent() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->specularExponent()); +} + +SVGAnimatedNumber SVGFESpotLightElement::limitingConeAngle() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->limitingConeAngle()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFESpotLightElement.h b/ksvg/dom/SVGFESpotLightElement.h new file mode 100644 index 00000000..735a6428 --- /dev/null +++ b/ksvg/dom/SVGFESpotLightElement.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFESpotLightElement_H +#define SVGFESpotLightElement_H + +#include "SVGElement.h" + +namespace KSVG +{ + +class SVGAnimatedNumber; +class SVGFESpotLightElementImpl; +class SVGFESpotLightElement : public SVGElement +{ +public: + SVGFESpotLightElement(); + SVGFESpotLightElement(const SVGFESpotLightElement &other); + SVGFESpotLightElement &operator=(const SVGFESpotLightElement &other); + SVGFESpotLightElement(SVGFESpotLightElementImpl *other); + virtual ~SVGFESpotLightElement(); + + SVGAnimatedNumber x() const; + SVGAnimatedNumber y() const; + SVGAnimatedNumber z() const; + SVGAnimatedNumber pointsAtX() const; + SVGAnimatedNumber pointsAtY() const; + SVGAnimatedNumber pointsAtZ() const; + SVGAnimatedNumber specularExponent() const; + SVGAnimatedNumber limitingConeAngle() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFESpotLightElementImpl *handle() const { return impl; } + +private: + SVGFESpotLightElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFETileElement.cc b/ksvg/dom/SVGFETileElement.cc new file mode 100644 index 00000000..01c7ffed --- /dev/null +++ b/ksvg/dom/SVGFETileElement.cc @@ -0,0 +1,75 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFETileElement.h" +#include "SVGFETileElementImpl.h" +#include "SVGAnimatedString.h" + +using namespace KSVG; + +SVGFETileElement::SVGFETileElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes() +{ + impl = 0; +} + +SVGFETileElement::SVGFETileElement(const SVGFETileElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0) +{ + (*this) = other; +} + +SVGFETileElement &SVGFETileElement::operator =(const SVGFETileElement &other) +{ + SVGElement::operator=(other); + SVGFilterPrimitiveStandardAttributes::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFETileElement::SVGFETileElement(SVGFETileElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFETileElement::~SVGFETileElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedString SVGFETileElement::in1() const +{ + if(!impl) return SVGAnimatedString(0); + return SVGAnimatedString(impl->in1()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFETileElement.h b/ksvg/dom/SVGFETileElement.h new file mode 100644 index 00000000..cbf548b1 --- /dev/null +++ b/ksvg/dom/SVGFETileElement.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFETileElement_H +#define SVGFETileElement_H + +#include "SVGElement.h" +#include "SVGFilterPrimitiveStandardAttributes.h" + +namespace KSVG +{ + +class SVGAnimatedString; +class SVGFETileElementImpl; +class SVGFETileElement : public SVGElement, + public SVGFilterPrimitiveStandardAttributes +{ +public: + SVGFETileElement(); + SVGFETileElement(const SVGFETileElement &other); + SVGFETileElement &operator=(const SVGFETileElement &other); + SVGFETileElement(SVGFETileElementImpl *other); + virtual ~SVGFETileElement(); + + SVGAnimatedString in1() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFETileElementImpl *handle() const { return impl; } + +private: + SVGFETileElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFETurbulenceElement.cc b/ksvg/dom/SVGFETurbulenceElement.cc new file mode 100644 index 00000000..7d846e6b --- /dev/null +++ b/ksvg/dom/SVGFETurbulenceElement.cc @@ -0,0 +1,107 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFETurbulenceElement.h" +#include "SVGFETurbulenceElementImpl.h" +#include "SVGAnimatedEnumeration.h" +#include "SVGAnimatedNumber.h" +#include "SVGAnimatedInteger.h" + +using namespace KSVG; + +SVGFETurbulenceElement::SVGFETurbulenceElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes() +{ + impl = 0; +} + +SVGFETurbulenceElement::SVGFETurbulenceElement(const SVGFETurbulenceElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0) +{ + (*this) = other; +} + +SVGFETurbulenceElement &SVGFETurbulenceElement::operator =(const SVGFETurbulenceElement &other) +{ + SVGElement::operator=(other); + SVGFilterPrimitiveStandardAttributes::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFETurbulenceElement::SVGFETurbulenceElement(SVGFETurbulenceElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFETurbulenceElement::~SVGFETurbulenceElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedNumber SVGFETurbulenceElement::baseFrequencyX() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->baseFrequencyX()); +} + +SVGAnimatedNumber SVGFETurbulenceElement::baseFrequencyY() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->baseFrequencyY()); +} + +SVGAnimatedInteger SVGFETurbulenceElement::numOctaves() const +{ + if(!impl) return SVGAnimatedInteger(0); + return SVGAnimatedInteger(impl->numOctaves()); +} + +SVGAnimatedNumber SVGFETurbulenceElement::seed() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->seed()); +} + +SVGAnimatedEnumeration SVGFETurbulenceElement::stitchTiles() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->stitchTiles()); +} + +SVGAnimatedEnumeration SVGFETurbulenceElement::type() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->type()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFETurbulenceElement.h b/ksvg/dom/SVGFETurbulenceElement.h new file mode 100644 index 00000000..39b6050d --- /dev/null +++ b/ksvg/dom/SVGFETurbulenceElement.h @@ -0,0 +1,71 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFETurbulenceElement_H +#define SVGFETurbulenceElement_H + +#include "SVGElement.h" +#include "SVGFilterPrimitiveStandardAttributes.h" + +namespace KSVG +{ +enum +{ + SVG_TURBULENCE_TYPE_UNKNOWN = 0, + SVG_TURBULENCE_TYPE_FRACTALNOISE = 1, + SVG_TURBULENCE_TYPE_TURBULENCE = 2, + SVG_STITCHTYPE_UNKNOWN = 0, + SVG_STITCHTYPE_STITCH = 1, + SVG_STITCHTYPE_NOSTITCH = 2 +}; + +class SVGAnimatedEnumeration; +class SVGAnimatedNumber; +class SVGAnimatedInteger; +class SVGFETurbulenceElementImpl; +class SVGFETurbulenceElement : public SVGElement, + public SVGFilterPrimitiveStandardAttributes +{ +public: + SVGFETurbulenceElement(); + SVGFETurbulenceElement(const SVGFETurbulenceElement &other); + SVGFETurbulenceElement &operator=(const SVGFETurbulenceElement &other); + SVGFETurbulenceElement(SVGFETurbulenceElementImpl *other); + virtual ~SVGFETurbulenceElement(); + + SVGAnimatedNumber baseFrequencyX() const; + SVGAnimatedNumber baseFrequencyY() const; + SVGAnimatedInteger numOctaves() const; + SVGAnimatedNumber seed() const; + SVGAnimatedEnumeration stitchTiles() const; + SVGAnimatedEnumeration type() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFETurbulenceElementImpl *handle() const { return impl; } + +private: + SVGFETurbulenceElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFilterElement.cc b/ksvg/dom/SVGFilterElement.cc new file mode 100644 index 00000000..3644a807 --- /dev/null +++ b/ksvg/dom/SVGFilterElement.cc @@ -0,0 +1,128 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFilterElement.h" +#include "SVGFilterElementImpl.h" +#include "SVGAnimatedEnumeration.h" +#include "SVGAnimatedInteger.h" +#include "SVGAnimatedLength.h" + +using namespace KSVG; + +SVGFilterElement::SVGFilterElement() : SVGElement(), SVGURIReference(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGUnitTypes() +{ + impl = 0; +} + +SVGFilterElement::SVGFilterElement(const SVGFilterElement &other) : SVGElement(other), SVGURIReference(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGUnitTypes(), impl(0) +{ + (*this) = other; +} + +SVGFilterElement &SVGFilterElement::operator =(const SVGFilterElement &other) +{ + SVGElement::operator=(other); + SVGURIReference::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFilterElement::SVGFilterElement(SVGFilterElementImpl *other) : SVGElement(other), SVGURIReference(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGUnitTypes() +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFilterElement::~SVGFilterElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedEnumeration SVGFilterElement::filterUnits() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->filterUnits()); +} + +SVGAnimatedEnumeration SVGFilterElement::primitiveUnits() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->primitiveUnits()); +} + +SVGAnimatedLength SVGFilterElement::x() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->x()); +} + +SVGAnimatedLength SVGFilterElement::y() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->y()); +} + +SVGAnimatedLength SVGFilterElement::width() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->width()); +} + +SVGAnimatedLength SVGFilterElement::height() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->height()); +} + +SVGAnimatedInteger SVGFilterElement::filterResX() const +{ + if(!impl) return SVGAnimatedInteger(0); + return SVGAnimatedInteger(impl->filterResX()); +} + +SVGAnimatedInteger SVGFilterElement::filterResY() const +{ + if(!impl) return SVGAnimatedInteger(0); + return SVGAnimatedInteger(impl->filterResY()); +} + +void SVGFilterElement::setFilterRes(unsigned long filterResX, unsigned long filterResY) +{ + if(impl) + impl->setFilterRes(filterResX, filterResY); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFilterElement.h b/ksvg/dom/SVGFilterElement.h new file mode 100644 index 00000000..82f67e5c --- /dev/null +++ b/ksvg/dom/SVGFilterElement.h @@ -0,0 +1,74 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFilterElement_H +#define SVGFilterElement_H + +#include "SVGElement.h" +#include "SVGURIReference.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGUnitTypes.h" + +namespace KSVG +{ + +class SVGAnimatedEnumeration; +class SVGAnimatedLength; +class SVGAnimatedInteger; +class SVGFilterElementImpl; +class SVGFilterElement : public SVGElement, + public SVGURIReference, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGUnitTypes +{ +public: + SVGFilterElement(); + SVGFilterElement(const SVGFilterElement &other); + SVGFilterElement &operator=(const SVGFilterElement &other); + SVGFilterElement(SVGFilterElementImpl *other); + virtual ~SVGFilterElement(); + + SVGAnimatedEnumeration filterUnits() const; + SVGAnimatedEnumeration primitiveUnits() const; + SVGAnimatedLength x() const; + SVGAnimatedLength y() const; + SVGAnimatedLength width() const; + SVGAnimatedLength height() const; + SVGAnimatedInteger filterResX() const; + SVGAnimatedInteger filterResY() const; + + void setFilterRes(unsigned long filterResX, unsigned long filterResY); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFilterElementImpl *handle() const { return impl; } + +private: + SVGFilterElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFilterPrimitiveStandardAttributes.cc b/ksvg/dom/SVGFilterPrimitiveStandardAttributes.cc new file mode 100644 index 00000000..05b2ef2a --- /dev/null +++ b/ksvg/dom/SVGFilterPrimitiveStandardAttributes.cc @@ -0,0 +1,88 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFilterPrimitiveStandardAttributes.h" +#include "SVGFilterPrimitiveStandardAttributesImpl.h" +#include "SVGAnimatedString.h" +#include "SVGAnimatedLength.h" + +using namespace KSVG; + +SVGFilterPrimitiveStandardAttributes::SVGFilterPrimitiveStandardAttributes() +{ + impl = new SVGFilterPrimitiveStandardAttributesImpl(); +} + +SVGFilterPrimitiveStandardAttributes::SVGFilterPrimitiveStandardAttributes(const SVGFilterPrimitiveStandardAttributes &other) +{ + impl = other.impl; +} + +SVGFilterPrimitiveStandardAttributes &SVGFilterPrimitiveStandardAttributes::operator=(const SVGFilterPrimitiveStandardAttributes &other) +{ + if(impl == other.impl) + return *this; + + delete impl; + impl = other.impl; + + return *this; +} + +SVGFilterPrimitiveStandardAttributes::SVGFilterPrimitiveStandardAttributes(SVGFilterPrimitiveStandardAttributesImpl *other) +{ + impl = other; +} + +SVGFilterPrimitiveStandardAttributes::~SVGFilterPrimitiveStandardAttributes() +{ +} + +SVGAnimatedLength SVGFilterPrimitiveStandardAttributes::x() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->x()); +} + +SVGAnimatedLength SVGFilterPrimitiveStandardAttributes::y() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->y()); +} + +SVGAnimatedLength SVGFilterPrimitiveStandardAttributes::width() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->width()); +} + +SVGAnimatedLength SVGFilterPrimitiveStandardAttributes::height() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->height()); +} + +SVGAnimatedString SVGFilterPrimitiveStandardAttributes::result() const +{ + if(!impl) return SVGAnimatedString(0); + return SVGAnimatedString(impl->result()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFilterPrimitiveStandardAttributes.h b/ksvg/dom/SVGFilterPrimitiveStandardAttributes.h new file mode 100644 index 00000000..9d2c9894 --- /dev/null +++ b/ksvg/dom/SVGFilterPrimitiveStandardAttributes.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFilterPrimitiveStandardAttributes_H +#define SVGFilterPrimitiveStandardAttributes_H + +namespace KSVG +{ + +class SVGAnimatedLength; +class SVGAnimatedString; +class SVGFilterPrimitiveStandardAttributesImpl; +class SVGFilterPrimitiveStandardAttributes +{ +public: + SVGFilterPrimitiveStandardAttributes(const SVGFilterPrimitiveStandardAttributes &other); + SVGFilterPrimitiveStandardAttributes &operator=(const SVGFilterPrimitiveStandardAttributes &other); + SVGFilterPrimitiveStandardAttributes(SVGFilterPrimitiveStandardAttributesImpl *other); + virtual ~SVGFilterPrimitiveStandardAttributes(); + + SVGAnimatedLength x() const; + SVGAnimatedLength y() const; + SVGAnimatedLength width() const; + SVGAnimatedLength height() const; + SVGAnimatedString result() const; + +protected: + SVGFilterPrimitiveStandardAttributes(); + +private: + SVGFilterPrimitiveStandardAttributesImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFitToViewBox.cc b/ksvg/dom/SVGFitToViewBox.cc new file mode 100644 index 00000000..e0d576f0 --- /dev/null +++ b/ksvg/dom/SVGFitToViewBox.cc @@ -0,0 +1,72 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFitToViewBox.h" +#include "SVGFitToViewBoxImpl.h" +#include "SVGAnimatedRect.h" +#include "SVGAnimatedPreserveAspectRatio.h" + +using namespace KSVG; + +// This class can't be constructed seperately. +SVGFitToViewBox::SVGFitToViewBox() +{ + impl = 0; +} + +SVGFitToViewBox::SVGFitToViewBox(const SVGFitToViewBox &other) : impl(0) +{ + (*this) = other; +} + +SVGFitToViewBox &SVGFitToViewBox::operator=(const SVGFitToViewBox &other) +{ + if(impl == other.impl) + return *this; + + impl = other.impl; + + return *this; +} + +SVGFitToViewBox::SVGFitToViewBox(SVGFitToViewBoxImpl *other) +{ + impl = other; +} + +SVGFitToViewBox::~SVGFitToViewBox() +{ + // We are not allowed to delete 'impl' as it's not refcounted. + // delete impl; +} + +SVGAnimatedRect SVGFitToViewBox::viewBox() const +{ + if(!impl) return SVGAnimatedRect(0); + return SVGAnimatedRect(impl->viewBox()); +} + +SVGAnimatedPreserveAspectRatio SVGFitToViewBox::preserveAspectRatio() const +{ + if(!impl) return SVGAnimatedPreserveAspectRatio(0); + return SVGAnimatedPreserveAspectRatio(impl->preserveAspectRatio()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFitToViewBox.h b/ksvg/dom/SVGFitToViewBox.h new file mode 100644 index 00000000..50778657 --- /dev/null +++ b/ksvg/dom/SVGFitToViewBox.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFitToViewBox_H +#define SVGFitToViewBox_H + +namespace KSVG +{ + +class SVGAnimatedRect; +class SVGAnimatedPreserveAspectRatio; +class SVGFitToViewBoxImpl; +class SVGFitToViewBox +{ +public: + SVGFitToViewBox(const SVGFitToViewBox &other); + SVGFitToViewBox &operator=(const SVGFitToViewBox &other); + SVGFitToViewBox(SVGFitToViewBoxImpl *other); + ~SVGFitToViewBox(); + + SVGAnimatedRect viewBox() const; + SVGAnimatedPreserveAspectRatio preserveAspectRatio() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFitToViewBoxImpl *handle() const { return impl; } + +protected: + SVGFitToViewBox(); + +private: + SVGFitToViewBoxImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFontElement.cc b/ksvg/dom/SVGFontElement.cc new file mode 100644 index 00000000..5fae52ee --- /dev/null +++ b/ksvg/dom/SVGFontElement.cc @@ -0,0 +1,69 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFontElement.h" +#include "SVGFontElementImpl.h" + +using namespace KSVG; + +SVGFontElement::SVGFontElement() : SVGElement(), SVGExternalResourcesRequired(), SVGStylable() +{ + impl = 0; +} + +SVGFontElement::SVGFontElement(const SVGFontElement &other) : SVGElement(other), SVGExternalResourcesRequired(other), SVGStylable(other), impl(0) +{ + (*this) = other; +} + +SVGFontElement &SVGFontElement::operator =(const SVGFontElement &other) +{ + SVGElement::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFontElement::SVGFontElement(SVGFontElementImpl *other) : SVGElement(other), SVGExternalResourcesRequired(other), SVGStylable(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFontElement::~SVGFontElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFontElement.h b/ksvg/dom/SVGFontElement.h new file mode 100644 index 00000000..9ecc36bf --- /dev/null +++ b/ksvg/dom/SVGFontElement.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFontElement_H +#define SVGFontElement_H + +#include "SVGElement.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" + +namespace KSVG +{ + +class SVGFontElementImpl; +class SVGFontElement : public SVGElement, + public SVGExternalResourcesRequired, + public SVGStylable +{ +public: + SVGFontElement(); + SVGFontElement(const SVGFontElement &other); + SVGFontElement &operator=(const SVGFontElement &other); + SVGFontElement(SVGFontElementImpl *other); + virtual ~SVGFontElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFontElementImpl *handle() const { return impl; } + +private: + SVGFontElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFontFaceElement.cc b/ksvg/dom/SVGFontFaceElement.cc new file mode 100644 index 00000000..6d542a04 --- /dev/null +++ b/ksvg/dom/SVGFontFaceElement.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFontFaceElement.h" +#include "SVGFontFaceElementImpl.h" + +using namespace KSVG; + +SVGFontFaceElement::SVGFontFaceElement() : SVGElement() +{ + impl = 0; +} + +SVGFontFaceElement::SVGFontFaceElement(const SVGFontFaceElement &other) : SVGElement(other), impl(0) +{ + (*this) = other; +} + +SVGFontFaceElement &SVGFontFaceElement::operator =(const SVGFontFaceElement &other) +{ + SVGElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFontFaceElement::SVGFontFaceElement(SVGFontFaceElementImpl *other) : SVGElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFontFaceElement::~SVGFontFaceElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFontFaceElement.h b/ksvg/dom/SVGFontFaceElement.h new file mode 100644 index 00000000..f16d0eb2 --- /dev/null +++ b/ksvg/dom/SVGFontFaceElement.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFontFaceElement_H +#define SVGFontFaceElement_H + +#include "SVGElement.h" + +namespace KSVG +{ + +class SVGFontFaceElementImpl; +class SVGFontFaceElement : public SVGElement +{ +public: + SVGFontFaceElement(); + SVGFontFaceElement(const SVGFontFaceElement &other); + SVGFontFaceElement &operator=(const SVGFontFaceElement &other); + SVGFontFaceElement(SVGFontFaceElementImpl *other); + virtual ~SVGFontFaceElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFontFaceElementImpl *handle() const { return impl; } + +private: + SVGFontFaceElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFontFaceFormatElement.cc b/ksvg/dom/SVGFontFaceFormatElement.cc new file mode 100644 index 00000000..a64c5fa8 --- /dev/null +++ b/ksvg/dom/SVGFontFaceFormatElement.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFontFaceFormatElement.h" +#include "SVGFontFaceFormatElementImpl.h" + +using namespace KSVG; + +SVGFontFaceFormatElement::SVGFontFaceFormatElement() : SVGElement() +{ + impl = 0; +} + +SVGFontFaceFormatElement::SVGFontFaceFormatElement(const SVGFontFaceFormatElement &other) : SVGElement(other), impl(0) +{ + (*this) = other; +} + +SVGFontFaceFormatElement &SVGFontFaceFormatElement::operator =(const SVGFontFaceFormatElement &other) +{ + SVGElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFontFaceFormatElement::SVGFontFaceFormatElement(SVGFontFaceFormatElementImpl *other) : SVGElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFontFaceFormatElement::~SVGFontFaceFormatElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFontFaceFormatElement.h b/ksvg/dom/SVGFontFaceFormatElement.h new file mode 100644 index 00000000..577cae35 --- /dev/null +++ b/ksvg/dom/SVGFontFaceFormatElement.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFontFaceFormatElement_H +#define SVGFontFaceFormatElement_H + +#include "SVGElement.h" + +namespace KSVG +{ + +class SVGFontFaceFormatElementImpl; +class SVGFontFaceFormatElement : public SVGElement +{ +public: + SVGFontFaceFormatElement(); + SVGFontFaceFormatElement(const SVGFontFaceFormatElement &other); + SVGFontFaceFormatElement &operator=(const SVGFontFaceFormatElement &other); + SVGFontFaceFormatElement(SVGFontFaceFormatElementImpl *other); + virtual ~SVGFontFaceFormatElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFontFaceFormatElementImpl *handle() const { return impl; } + +private: + SVGFontFaceFormatElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFontFaceNameElement.cc b/ksvg/dom/SVGFontFaceNameElement.cc new file mode 100644 index 00000000..e5160869 --- /dev/null +++ b/ksvg/dom/SVGFontFaceNameElement.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFontFaceNameElement.h" +#include "SVGFontFaceNameElementImpl.h" + +using namespace KSVG; + +SVGFontFaceNameElement::SVGFontFaceNameElement() : SVGElement() +{ + impl = 0; +} + +SVGFontFaceNameElement::SVGFontFaceNameElement(const SVGFontFaceNameElement &other) : SVGElement(other), impl(0) +{ + (*this) = other; +} + +SVGFontFaceNameElement &SVGFontFaceNameElement::operator =(const SVGFontFaceNameElement &other) +{ + SVGElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFontFaceNameElement::SVGFontFaceNameElement(SVGFontFaceNameElementImpl *other) : SVGElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFontFaceNameElement::~SVGFontFaceNameElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFontFaceNameElement.h b/ksvg/dom/SVGFontFaceNameElement.h new file mode 100644 index 00000000..b246e61d --- /dev/null +++ b/ksvg/dom/SVGFontFaceNameElement.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFontFaceNameElement_H +#define SVGFontFaceNameElement_H + +#include "SVGElement.h" + +namespace KSVG +{ + +class SVGFontFaceNameElementImpl; +class SVGFontFaceNameElement : public SVGElement +{ +public: + SVGFontFaceNameElement(); + SVGFontFaceNameElement(const SVGFontFaceNameElement &other); + SVGFontFaceNameElement &operator=(const SVGFontFaceNameElement &other); + SVGFontFaceNameElement(SVGFontFaceNameElementImpl *other); + virtual ~SVGFontFaceNameElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFontFaceNameElementImpl *handle() const { return impl; } + +private: + SVGFontFaceNameElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFontFaceSrcElement.cc b/ksvg/dom/SVGFontFaceSrcElement.cc new file mode 100644 index 00000000..8ecbbffa --- /dev/null +++ b/ksvg/dom/SVGFontFaceSrcElement.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFontFaceSrcElement.h" +#include "SVGFontFaceSrcElementImpl.h" + +using namespace KSVG; + +SVGFontFaceSrcElement::SVGFontFaceSrcElement() : SVGElement() +{ + impl = 0; +} + +SVGFontFaceSrcElement::SVGFontFaceSrcElement(const SVGFontFaceSrcElement &other) : SVGElement(other), impl(0) +{ + (*this) = other; +} + +SVGFontFaceSrcElement &SVGFontFaceSrcElement::operator =(const SVGFontFaceSrcElement &other) +{ + SVGElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFontFaceSrcElement::SVGFontFaceSrcElement(SVGFontFaceSrcElementImpl *other) : SVGElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFontFaceSrcElement::~SVGFontFaceSrcElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFontFaceSrcElement.h b/ksvg/dom/SVGFontFaceSrcElement.h new file mode 100644 index 00000000..585971e0 --- /dev/null +++ b/ksvg/dom/SVGFontFaceSrcElement.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFontFaceSrcElement_H +#define SVGFontFaceSrcElement_H + +#include "SVGElement.h" + +namespace KSVG +{ + +class SVGFontFaceSrcElementImpl; +class SVGFontFaceSrcElement : public SVGElement +{ +public: + SVGFontFaceSrcElement(); + SVGFontFaceSrcElement(const SVGFontFaceSrcElement &other); + SVGFontFaceSrcElement &operator=(const SVGFontFaceSrcElement &other); + SVGFontFaceSrcElement(SVGFontFaceSrcElementImpl *other); + virtual ~SVGFontFaceSrcElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFontFaceSrcElementImpl *handle() const { return impl; } + +private: + SVGFontFaceSrcElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFontFaceUriElement.cc b/ksvg/dom/SVGFontFaceUriElement.cc new file mode 100644 index 00000000..aafb392b --- /dev/null +++ b/ksvg/dom/SVGFontFaceUriElement.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFontFaceUriElement.h" +#include "SVGFontFaceUriElementImpl.h" + +using namespace KSVG; + +SVGFontFaceUriElement::SVGFontFaceUriElement() : SVGElement() +{ + impl = 0; +} + +SVGFontFaceUriElement::SVGFontFaceUriElement(const SVGFontFaceUriElement &other) : SVGElement(other), impl(0) +{ + (*this) = other; +} + +SVGFontFaceUriElement &SVGFontFaceUriElement::operator =(const SVGFontFaceUriElement &other) +{ + SVGElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGFontFaceUriElement::SVGFontFaceUriElement(SVGFontFaceUriElementImpl *other) : SVGElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGFontFaceUriElement::~SVGFontFaceUriElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGFontFaceUriElement.h b/ksvg/dom/SVGFontFaceUriElement.h new file mode 100644 index 00000000..c2dd6514 --- /dev/null +++ b/ksvg/dom/SVGFontFaceUriElement.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFontFaceUriElement_H +#define SVGFontFaceUriElement_H + +#include "SVGElement.h" + +namespace KSVG +{ + +class SVGFontFaceUriElementImpl; +class SVGFontFaceUriElement : public SVGElement +{ +public: + SVGFontFaceUriElement(); + SVGFontFaceUriElement(const SVGFontFaceUriElement &other); + SVGFontFaceUriElement &operator=(const SVGFontFaceUriElement &other); + SVGFontFaceUriElement(SVGFontFaceUriElementImpl *other); + virtual ~SVGFontFaceUriElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGFontFaceUriElementImpl *handle() const { return impl; } + +private: + SVGFontFaceUriElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGForeignObjectElement.cc b/ksvg/dom/SVGForeignObjectElement.cc new file mode 100644 index 00000000..e12a194a --- /dev/null +++ b/ksvg/dom/SVGForeignObjectElement.cc @@ -0,0 +1,97 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGForeignObjectElement.h" +#include "SVGForeignObjectElementImpl.h" +#include "SVGAnimatedLength.h" + +using namespace KSVG; + +SVGForeignObjectElement::SVGForeignObjectElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable() +{ + impl = 0; +} + +SVGForeignObjectElement::SVGForeignObjectElement(const SVGForeignObjectElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other) +{ + (*this) = other; +} + +SVGForeignObjectElement &SVGForeignObjectElement::operator =(const SVGForeignObjectElement &other) +{ + SVGElement::operator=(other); + SVGTests::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + SVGTransformable::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGForeignObjectElement::SVGForeignObjectElement(SVGForeignObjectElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGForeignObjectElement::~SVGForeignObjectElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedLength SVGForeignObjectElement::x() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->x()); +} + +SVGAnimatedLength SVGForeignObjectElement::y() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->y()); +} + +SVGAnimatedLength SVGForeignObjectElement::width() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->width()); +} + +SVGAnimatedLength SVGForeignObjectElement::height() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->height()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGForeignObjectElement.h b/ksvg/dom/SVGForeignObjectElement.h new file mode 100644 index 00000000..0d35019f --- /dev/null +++ b/ksvg/dom/SVGForeignObjectElement.h @@ -0,0 +1,66 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGForeignObjectElement_H +#define SVGForeignObjectElement_H + +#include "SVGElement.h" +#include "SVGTests.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGTransformable.h" + +namespace KSVG +{ + +class SVGAnimatedLength; +class SVGForeignObjectElementImpl; +class SVGForeignObjectElement : public SVGElement, + public SVGTests, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGTransformable +{ +public: + SVGForeignObjectElement(); + SVGForeignObjectElement(const SVGForeignObjectElement &other); + SVGForeignObjectElement &operator=(const SVGForeignObjectElement &other); + SVGForeignObjectElement(SVGForeignObjectElementImpl *other); + virtual ~SVGForeignObjectElement(); + + SVGAnimatedLength x() const; + SVGAnimatedLength y() const; + SVGAnimatedLength width() const; + SVGAnimatedLength height() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGForeignObjectElementImpl *handle() const { return impl; } + +private: + SVGForeignObjectElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGGElement.cc b/ksvg/dom/SVGGElement.cc new file mode 100644 index 00000000..272c7608 --- /dev/null +++ b/ksvg/dom/SVGGElement.cc @@ -0,0 +1,72 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGGElement.h" +#include "SVGGElementImpl.h" + +using namespace KSVG; + +SVGGElement::SVGGElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable() +{ + impl = 0; +} + +SVGGElement::SVGGElement(const SVGGElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), impl(0) +{ + (*this) = other; +} + +SVGGElement &SVGGElement::operator =(const SVGGElement &other) +{ + SVGElement::operator=(other); + SVGTests::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + SVGTransformable::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGGElement::SVGGElement(SVGGElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGGElement::~SVGGElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGGElement.h b/ksvg/dom/SVGGElement.h new file mode 100644 index 00000000..724bbadb --- /dev/null +++ b/ksvg/dom/SVGGElement.h @@ -0,0 +1,83 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 file includes excerpts from the Scalable Vector Graphics + (SVG) 1.0 Specification (Proposed Recommendation) + http://www.w3.org/TR/SVG + + Copyright 2001 World Wide Web Consortium, (Massachusetts + Institute of Technology, Institut National de Recherche en + Informatique et en Automatique, Keio University). + All Rights Reserved. +*/ + +#ifndef SVGGElement_H +#define SVGGElement_H + +#include "SVGElement.h" +#include "SVGTests.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGTransformable.h" + +namespace KSVG +{ + +class SVGGElementImpl; + +/** + * The 'g' element is a container element for grouping together related graphics elements. + * + * Grouping constructs, when used in conjunction with the @ref desc and @ref title elements, provide + * information about document structure and semantics. Documents that are rich in structure may be + * rendered graphically, as speech, or as braille, and thus promote accessibility. + * + * A group of elements, as well as individual objects, can be given a name using the id attribute. + * Named groups are needed for several purposes such as animation and re-usable objects. + * + * A 'g' element can contain other 'g' elements nested within it, to an arbitrary depth. + */ +class SVGGElement : public SVGElement, + public SVGTests, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGTransformable +{ +public: + SVGGElement(); + SVGGElement(const SVGGElement &other); + SVGGElement &operator=(const SVGGElement &other); + SVGGElement(SVGGElementImpl *other); + ~SVGGElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGGElementImpl *handle() const { return impl; } + +private: + SVGGElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGGlyphElement.cc b/ksvg/dom/SVGGlyphElement.cc new file mode 100644 index 00000000..c852d44d --- /dev/null +++ b/ksvg/dom/SVGGlyphElement.cc @@ -0,0 +1,68 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGGlyphElement.h" +#include "SVGGlyphElementImpl.h" + +using namespace KSVG; + +SVGGlyphElement::SVGGlyphElement() : SVGElement(), SVGStylable() +{ + impl = 0; +} + +SVGGlyphElement::SVGGlyphElement(const SVGGlyphElement &other) : SVGElement(other), SVGStylable(other), impl(0) +{ + (*this) = other; +} + +SVGGlyphElement &SVGGlyphElement::operator =(const SVGGlyphElement &other) +{ + SVGElement::operator=(other); + SVGStylable::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGGlyphElement::SVGGlyphElement(SVGGlyphElementImpl *other) : SVGElement(other), SVGStylable(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGGlyphElement::~SVGGlyphElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGGlyphElement.h b/ksvg/dom/SVGGlyphElement.h new file mode 100644 index 00000000..c3d2237b --- /dev/null +++ b/ksvg/dom/SVGGlyphElement.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGGlyphElement_H +#define SVGGlyphElement_H + +#include "SVGElement.h" +#include "SVGStylable.h" + +namespace KSVG +{ + +class SVGGlyphElementImpl; +class SVGGlyphElement : public SVGElement, + public SVGStylable +{ +public: + SVGGlyphElement(); + SVGGlyphElement(const SVGGlyphElement &other); + SVGGlyphElement &operator=(const SVGGlyphElement &other); + SVGGlyphElement(SVGGlyphElementImpl *other); + virtual ~SVGGlyphElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGGlyphElementImpl *handle() const { return impl; } + +private: + SVGGlyphElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGGlyphRefElement.cc b/ksvg/dom/SVGGlyphRefElement.cc new file mode 100644 index 00000000..85c4c39f --- /dev/null +++ b/ksvg/dom/SVGGlyphRefElement.cc @@ -0,0 +1,81 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGGlyphRefElement.h" +#include "SVGGlyphRefElementImpl.h" + +using namespace KSVG; + +SVGGlyphRefElement::SVGGlyphRefElement() : SVGElement(), SVGURIReference(), SVGStylable() +{ + impl = 0; +} + +SVGGlyphRefElement::SVGGlyphRefElement(const SVGGlyphRefElement &other) : SVGElement(other), SVGURIReference(other), SVGStylable(other), impl(0) +{ + (*this) = other; +} + +SVGGlyphRefElement &SVGGlyphRefElement::operator =(const SVGGlyphRefElement &other) +{ + SVGElement::operator=(other); + SVGURIReference::operator=(other); + SVGStylable::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGGlyphRefElement::SVGGlyphRefElement(SVGGlyphRefElementImpl *other) : SVGElement(other), SVGURIReference(other), SVGStylable(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGGlyphRefElement::~SVGGlyphRefElement() +{ + if(impl) + impl->deref(); +} + +DOM::DOMString SVGGlyphRefElement::format() +{ + if(!impl) return DOM::DOMString(); + return impl->format(); +} + +DOM::DOMString SVGGlyphRefElement::glyphRef() +{ + if(!impl) return DOM::DOMString(); + return impl->glyphRef(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGGlyphRefElement.h b/ksvg/dom/SVGGlyphRefElement.h new file mode 100644 index 00000000..29e91e57 --- /dev/null +++ b/ksvg/dom/SVGGlyphRefElement.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGGlyphRefElement_H +#define SVGGlyphRefElement_H + +#include "SVGElement.h" +#include "SVGURIReference.h" +#include "SVGStylable.h" + +namespace KSVG +{ + +class SVGGlyphRefElementImpl; +class SVGGlyphRefElement : public SVGElement, + public SVGURIReference, + public SVGStylable +{ +public: + SVGGlyphRefElement(); + SVGGlyphRefElement(const SVGGlyphRefElement &other); + SVGGlyphRefElement &operator=(const SVGGlyphRefElement &other); + SVGGlyphRefElement(SVGGlyphRefElementImpl *other); + virtual ~SVGGlyphRefElement(); + + DOM::DOMString glyphRef(); + DOM::DOMString format(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGGlyphRefElementImpl *handle() const { return impl; } + +private: + SVGGlyphRefElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGGradientElement.cc b/ksvg/dom/SVGGradientElement.cc new file mode 100644 index 00000000..2afb305e --- /dev/null +++ b/ksvg/dom/SVGGradientElement.cc @@ -0,0 +1,80 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGGradientElement.h" +#include "SVGGradientElementImpl.h" +#include "SVGAnimatedTransformList.h" +#include "SVGAnimatedEnumeration.h" + +using namespace KSVG; + +SVGGradientElement::SVGGradientElement() : SVGElement(), SVGURIReference(), SVGExternalResourcesRequired(), SVGStylable(), SVGUnitTypes() +{ + impl = 0; +} + +SVGGradientElement::SVGGradientElement(const SVGGradientElement &other) : SVGElement(other), SVGURIReference(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGUnitTypes(other), impl(0) +{ + (*this) = other; +} + +SVGGradientElement &SVGGradientElement::operator =(const SVGGradientElement &other) +{ + SVGElement::operator=(other); + SVGURIReference::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + + if(impl == other.impl) + return *this; + + impl = other.impl; + + return *this; +} + +SVGGradientElement::SVGGradientElement(SVGGradientElementImpl *other) : SVGElement(other), SVGURIReference(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGUnitTypes() +{ + impl = other; +} + +SVGGradientElement::~SVGGradientElement() +{ +} + +SVGAnimatedEnumeration SVGGradientElement::gradientUnits() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->gradientUnits()); +} + +SVGAnimatedTransformList SVGGradientElement::gradientTransform() const +{ + if(!impl) return SVGAnimatedTransformList(0); + return SVGAnimatedTransformList(impl->gradientTransform()); +} + +SVGAnimatedEnumeration SVGGradientElement::spreadMethod() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->spreadMethod()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGGradientElement.h b/ksvg/dom/SVGGradientElement.h new file mode 100644 index 00000000..cff47ad8 --- /dev/null +++ b/ksvg/dom/SVGGradientElement.h @@ -0,0 +1,71 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGGradientElement_H +#define SVGGradientElement_H + +#include "SVGElement.h" +#include "SVGURIReference.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGUnitTypes.h" + +namespace KSVG +{ + +enum +{ + SVG_SPREADMETHOD_UNKNOWN = 0, + SVG_SPREADMETHOD_PAD = 1, + SVG_SPREADMETHOD_REFLECT = 2, + SVG_SPREADMETHOD_REPEAT = 3 +}; + +class SVGAnimatedEnumeration; +class SVGAnimatedTransformList; +class SVGGradientElementImpl; +class SVGGradientElement : public SVGElement, + public SVGURIReference, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGUnitTypes +{ +public: + SVGGradientElement(const SVGGradientElement &other); + SVGGradientElement &operator=(const SVGGradientElement &other); + SVGGradientElement(SVGGradientElementImpl *other); + virtual ~SVGGradientElement(); + + SVGAnimatedEnumeration gradientUnits() const; + SVGAnimatedTransformList gradientTransform() const; + SVGAnimatedEnumeration spreadMethod() const; + +protected: + SVGGradientElement(); + +private: + SVGGradientElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGHKernElement.cc b/ksvg/dom/SVGHKernElement.cc new file mode 100644 index 00000000..db46aa63 --- /dev/null +++ b/ksvg/dom/SVGHKernElement.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGHKernElement.h" +#include "SVGHKernElementImpl.h" + +using namespace KSVG; + +SVGHKernElement::SVGHKernElement() : SVGElement() +{ + impl = 0; +} + +SVGHKernElement::SVGHKernElement(const SVGHKernElement &other) : SVGElement(other), impl(0) +{ + (*this) = other; +} + +SVGHKernElement &SVGHKernElement::operator =(const SVGHKernElement &other) +{ + SVGElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGHKernElement::SVGHKernElement(SVGHKernElementImpl *other) : SVGElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGHKernElement::~SVGHKernElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGHKernElement.h b/ksvg/dom/SVGHKernElement.h new file mode 100644 index 00000000..42890727 --- /dev/null +++ b/ksvg/dom/SVGHKernElement.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGHKernElement_H +#define SVGHKernElement_H + +#include "SVGElement.h" + +namespace KSVG +{ + +class SVGHKernElementImpl; +class SVGHKernElement : public SVGElement +{ +public: + SVGHKernElement(); + SVGHKernElement(const SVGHKernElement &other); + SVGHKernElement &operator=(const SVGHKernElement &other); + SVGHKernElement(SVGHKernElementImpl *other); + virtual ~SVGHKernElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGHKernElementImpl *handle() const { return impl; } + +private: + SVGHKernElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGICCColor.cc b/ksvg/dom/SVGICCColor.cc new file mode 100644 index 00000000..6b21f3fb --- /dev/null +++ b/ksvg/dom/SVGICCColor.cc @@ -0,0 +1,85 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGICCColor.h" +#include "SVGICCColorImpl.h" +#include "SVGNumberList.h" + +using namespace KSVG; + +SVGICCColor::SVGICCColor() +{ + impl = new SVGICCColorImpl(); + impl->ref(); +} + +SVGICCColor::SVGICCColor(const SVGICCColor &other) : impl(0) +{ + (*this) = other; +} + +SVGICCColor &SVGICCColor::operator =(const SVGICCColor &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGICCColor::SVGICCColor(SVGICCColorImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGICCColor::~SVGICCColor() +{ + if(impl) + impl->deref(); +} + +void SVGICCColor::setColorProfile(const DOM::DOMString &colorProfile) +{ + if(impl) + impl->setColorProfile(colorProfile); +} + +DOM::DOMString SVGICCColor::colorProfile() const +{ + if(!impl) return DOM::DOMString(); + return DOM::DOMString(impl->colorProfile()); +} + +SVGNumberList SVGICCColor::colors() const +{ + if(!impl) return SVGNumberList(0); + return SVGNumberList(impl->colors()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGICCColor.h b/ksvg/dom/SVGICCColor.h new file mode 100644 index 00000000..628feda9 --- /dev/null +++ b/ksvg/dom/SVGICCColor.h @@ -0,0 +1,56 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGICCColor_H +#define SVGICCColor_H + +#include + +namespace KSVG +{ + +class SVGNumberList; +class SVGICCColorImpl; +class SVGICCColor +{ +public: + SVGICCColor(); + SVGICCColor(const SVGICCColor &other); + SVGICCColor &operator=(const SVGICCColor &other); + SVGICCColor(SVGICCColorImpl *other); + ~SVGICCColor(); + + void setColorProfile(const DOM::DOMString &colorProfile); + DOM::DOMString colorProfile() const; + + SVGNumberList colors() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGICCColorImpl *handle() const { return impl; } + +private: + SVGICCColorImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGImageElement.cc b/ksvg/dom/SVGImageElement.cc new file mode 100644 index 00000000..9d9374fa --- /dev/null +++ b/ksvg/dom/SVGImageElement.cc @@ -0,0 +1,106 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include "SVGImageElement.h" +#include "SVGImageElementImpl.h" +#include "SVGAnimatedLength.h" +#include "SVGAnimatedPreserveAspectRatio.h" + +using namespace KSVG; + +SVGImageElement::SVGImageElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable(), SVGURIReference() +{ + impl = 0; +} + +SVGImageElement::SVGImageElement(const SVGImageElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGURIReference(other), impl(0) +{ + (*this) = other; +} + +SVGImageElement &SVGImageElement::operator=(const SVGImageElement &other) +{ + SVGElement::operator=(other); + SVGTests::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + SVGTransformable::operator=(other); + SVGURIReference::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGImageElement::SVGImageElement(SVGImageElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGURIReference(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGImageElement::~SVGImageElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedLength SVGImageElement::x() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->x()); +} + +SVGAnimatedLength SVGImageElement::y() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->y()); +} + +SVGAnimatedLength SVGImageElement::width() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->width()); +} + +SVGAnimatedLength SVGImageElement::height() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->height()); +} + +SVGAnimatedPreserveAspectRatio SVGImageElement::preserveAspectRatio() const +{ + if(!impl) return SVGAnimatedPreserveAspectRatio(0); + return SVGAnimatedPreserveAspectRatio(impl->preserveAspectRatio()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGImageElement.h b/ksvg/dom/SVGImageElement.h new file mode 100644 index 00000000..c6487fed --- /dev/null +++ b/ksvg/dom/SVGImageElement.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGImageElement_H +#define SVGImageElement_H + +#include "SVGElement.h" +#include "SVGTests.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGTransformable.h" +#include "SVGURIReference.h" + +namespace KSVG +{ + +class SVGAnimatedPreserveAspectRatio; +class SVGAnimatedLength; +class SVGImageElementImpl; +class SVGImageElement : public SVGElement, + public SVGTests, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGTransformable, + public SVGURIReference +{ +public: + SVGImageElement(); + SVGImageElement(const SVGImageElement &); + SVGImageElement &operator=(const SVGImageElement &other); + SVGImageElement(SVGImageElementImpl *); + ~SVGImageElement(); + + SVGAnimatedLength x(); + SVGAnimatedLength y(); + SVGAnimatedLength width(); + SVGAnimatedLength height(); + SVGAnimatedPreserveAspectRatio preserveAspectRatio() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGImageElementImpl *handle() const { return impl; } + +private: + SVGImageElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGLangSpace.cc b/ksvg/dom/SVGLangSpace.cc new file mode 100644 index 00000000..2373e648 --- /dev/null +++ b/ksvg/dom/SVGLangSpace.cc @@ -0,0 +1,82 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGLangSpace.h" +#include "SVGLangSpaceImpl.h" + +using namespace KSVG; + +// This class can't be constructed seperately. +SVGLangSpace::SVGLangSpace() +{ + impl = 0; +} + +SVGLangSpace::SVGLangSpace(const SVGLangSpace &other) : impl(0) +{ + (*this) = other; +} + +SVGLangSpace &SVGLangSpace::operator=(const SVGLangSpace &other) +{ + if(impl == other.impl) + return *this; + + impl = other.impl; + + return *this; +} + +SVGLangSpace::SVGLangSpace(SVGLangSpaceImpl *other) +{ + impl = other; +} + +SVGLangSpace::~SVGLangSpace() +{ + // We are not allowed to delete 'impl' as it's not refcounted. + // delete impl; +} + +void SVGLangSpace::setXmllang(const DOM::DOMString &xmllang) +{ + if(impl) + impl->setXmllang(xmllang); +} + +DOM::DOMString SVGLangSpace::xmllang() const +{ + if(!impl) return DOM::DOMString(); + return impl->xmllang(); +} + +void SVGLangSpace::setXmlspace(const DOM::DOMString &xmlspace) +{ + if(impl) + impl->setXmlspace(xmlspace); +} + +DOM::DOMString SVGLangSpace::xmlspace() const +{ + if(!impl) return DOM::DOMString(); + return impl->xmlspace(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGLangSpace.h b/ksvg/dom/SVGLangSpace.h new file mode 100644 index 00000000..391e625d --- /dev/null +++ b/ksvg/dom/SVGLangSpace.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGLangSpace_H +#define SVGLangSpace_H + +#include + +namespace KSVG +{ + +class SVGLangSpaceImpl; +class SVGLangSpace +{ +public: + SVGLangSpace(const SVGLangSpace &other); + SVGLangSpace &operator=(const SVGLangSpace &other); + SVGLangSpace(SVGLangSpaceImpl *other); + ~SVGLangSpace(); + + void setXmllang(const DOM::DOMString &xmllang); + DOM::DOMString xmllang() const; + + void setXmlspace(const DOM::DOMString &xmlspace); + DOM::DOMString xmlspace() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGLangSpaceImpl *handle() const { return impl; } + +protected: + SVGLangSpace(); + +private: + SVGLangSpaceImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGLength.cc b/ksvg/dom/SVGLength.cc new file mode 100644 index 00000000..bb2db73f --- /dev/null +++ b/ksvg/dom/SVGLength.cc @@ -0,0 +1,135 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include "SVGLength.h" +#include "SVGShapeImpl.h" +#include "SVGLengthImpl.h" + +using namespace KSVG; + +SVGLength::SVGLength() +{ + impl = new SVGLengthImpl(); + impl->ref(); +} + +SVGLength::SVGLength(const SVGLength &other) : impl(0) +{ + (*this) = other; +} + +SVGLength &SVGLength::operator =(const SVGLength &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGLength::SVGLength(SVGLengthImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGLength::~SVGLength() +{ + if(impl) + impl->deref(); +} + +unsigned short SVGLength::unitType() const +{ + if(!impl) return SVG_LENGTHTYPE_UNKNOWN; + return impl->unitType(); +} + +void SVGLength::setValue(float value) +{ + if(impl) + { + impl->setValue(value); + + // Automatic updating of the shape if any value is changed, imagine: + // SVGCircleElement c; [...] c.r().baseVal().setValue(150); + if(impl->context() && dynamic_cast(impl->context())) + dynamic_cast(impl->context())->update(UPDATE_TRANSFORM, 0, 0); + } +} + +float SVGLength::value() const +{ + if(!impl) return -1; + return impl->value(); +} + +void SVGLength::setValueInSpecifiedUnits(float valueInSpecifiedUnits) +{ + if(impl) + impl->setValueInSpecifiedUnits(valueInSpecifiedUnits); +} + +float SVGLength::valueInSpecifiedUnits() const +{ + if(!impl) return -1; + return impl->valueInSpecifiedUnits(); +} + +void SVGLength::setValueAsString(const DOM::DOMString &valueAsString) +{ + if(impl) + impl->setValueAsString(valueAsString); +} + +DOM::DOMString SVGLength::valueAsString() const +{ + if(!impl) return DOM::DOMString(); + return impl->valueAsString(); +} + +void SVGLength::newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits) +{ + if(impl) + impl->newValueSpecifiedUnits(unitType, valueInSpecifiedUnits); +} + +void SVGLength::convertToSpecifiedUnits(unsigned short unitType) +{ + if(impl) + impl->convertToSpecifiedUnits(unitType); +} + +SVGLength::operator float() +{ + if(!impl) return -1; + return impl->valueInSpecifiedUnits(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGLength.h b/ksvg/dom/SVGLength.h new file mode 100644 index 00000000..1f0bbdae --- /dev/null +++ b/ksvg/dom/SVGLength.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGLength_H +#define SVGLength_H + +#include + +namespace KSVG +{ + +enum +{ + SVG_LENGTHTYPE_UNKNOWN, + SVG_LENGTHTYPE_NUMBER, + SVG_LENGTHTYPE_PERCENTAGE, + SVG_LENGTHTYPE_EMS, + SVG_LENGTHTYPE_EXS, + SVG_LENGTHTYPE_PX, + SVG_LENGTHTYPE_CM, + SVG_LENGTHTYPE_MM, + SVG_LENGTHTYPE_IN, + SVG_LENGTHTYPE_PT, + SVG_LENGTHTYPE_PC +}; + +class SVGLengthImpl; +class SVGLength +{ +public: + SVGLength(); + SVGLength(const SVGLength &); + SVGLength(SVGLengthImpl *); + SVGLength &operator=(const SVGLength &); + ~SVGLength(); + + unsigned short unitType() const; + + void setValue(float value); + float value() const; + + void setValueInSpecifiedUnits(float valueInSpecifiedUnits); + float valueInSpecifiedUnits() const; + + void setValueAsString(const DOM::DOMString &); + DOM::DOMString valueAsString() const; + + void newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits); + void convertToSpecifiedUnits(unsigned short unitType); + + operator float(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGLengthImpl *handle() const { return impl; } + +private: + SVGLengthImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGLengthList.cc b/ksvg/dom/SVGLengthList.cc new file mode 100644 index 00000000..c308019b --- /dev/null +++ b/ksvg/dom/SVGLengthList.cc @@ -0,0 +1,115 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGLengthList.h" +#include "SVGLengthListImpl.h" +#include "SVGLength.h" + +using namespace KSVG; + +SVGLengthList::SVGLengthList() +{ + impl = new SVGLengthListImpl(); + impl->ref(); +} + +SVGLengthList::SVGLengthList(const SVGLengthList &other) : impl(0) +{ + (*this) = other; +} + +SVGLengthList &SVGLengthList::operator=(const SVGLengthList &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGLengthList::SVGLengthList(SVGLengthListImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGLengthList::~SVGLengthList() +{ + if(impl) + impl->deref(); +} + +unsigned long SVGLengthList::numberOfItems() const +{ + if(!impl) return 0; + return impl->numberOfItems(); +} + +void SVGLengthList::clear() +{ + if(impl) + impl->clear(); +} + +SVGLength *SVGLengthList::initialize(SVGLength *newItem) +{ + if(!impl) return new SVGLength(0); + return new SVGLength(impl->initialize(newItem->handle())); +} + +SVGLength *SVGLengthList::getItem(unsigned long index) +{ + if(!impl) return new SVGLength(0); + return new SVGLength(impl->getItem(index)); +} + +SVGLength *SVGLengthList::insertItemBefore(SVGLength *newItem, unsigned long index) +{ + if(!impl) return new SVGLength(0); + return new SVGLength(impl->insertItemBefore(newItem->handle(), index)); +} + +SVGLength *SVGLengthList::replaceItem(SVGLength *newItem, unsigned long index) +{ + if(!impl) return new SVGLength(0); + return new SVGLength(impl->replaceItem(newItem->handle(), index)); +} + +SVGLength *SVGLengthList::removeItem(unsigned long index) +{ + if(!impl) return new SVGLength(0); + return new SVGLength(impl->removeItem(index)); +} + +SVGLength *SVGLengthList::appendItem(SVGLength *newItem) +{ + if(!impl) return new SVGLength(0); + return new SVGLength(impl->appendItem(newItem->handle())); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGLengthList.h b/ksvg/dom/SVGLengthList.h new file mode 100644 index 00000000..bf4ab633 --- /dev/null +++ b/ksvg/dom/SVGLengthList.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGLengthList_H +#define SVGLengthList_H + +namespace KSVG +{ + +class SVGLength; +class SVGLengthListImpl; +class SVGLengthList +{ +public: + SVGLengthList(); + SVGLengthList(const SVGLengthList &); + SVGLengthList &operator=(const SVGLengthList &); + SVGLengthList(SVGLengthListImpl *); + ~SVGLengthList(); + + unsigned long numberOfItems() const; + void clear(); + + SVGLength *initialize(SVGLength *newItem); + SVGLength *getItem(unsigned long index); + SVGLength *insertItemBefore(SVGLength *newItem, unsigned long index); + SVGLength *replaceItem(SVGLength *newItem, unsigned long index); + SVGLength *removeItem(unsigned long index); + SVGLength *appendItem(SVGLength *newItem); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGLengthListImpl *handle() const { return impl; } + +private: + SVGLengthListImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGLineElement.cc b/ksvg/dom/SVGLineElement.cc new file mode 100644 index 00000000..583c3fe3 --- /dev/null +++ b/ksvg/dom/SVGLineElement.cc @@ -0,0 +1,98 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include "SVGLineElement.h" +#include "SVGLineElementImpl.h" +#include "SVGAnimatedLength.h" + +using namespace KSVG; + +SVGLineElement::SVGLineElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable() +{ + impl = 0; +} + +SVGLineElement::SVGLineElement(const SVGLineElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), impl(0) +{ + (*this) = other; +} + +SVGLineElement &SVGLineElement::operator=(const SVGLineElement &other) +{ + SVGElement::operator=(other); + SVGTests::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + SVGTransformable::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGLineElement::SVGLineElement(SVGLineElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGLineElement::~SVGLineElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedLength SVGLineElement::x1() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->x1()); +} + +SVGAnimatedLength SVGLineElement::y1() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->y1()); +} + +SVGAnimatedLength SVGLineElement::x2() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->x2()); +} + +SVGAnimatedLength SVGLineElement::y2() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->y2()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGLineElement.h b/ksvg/dom/SVGLineElement.h new file mode 100644 index 00000000..b08a78ba --- /dev/null +++ b/ksvg/dom/SVGLineElement.h @@ -0,0 +1,126 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 file includes excerpts from the Scalable Vector Graphics + (SVG) 1.0 Specification (Proposed Recommendation) + http://www.w3.org/TR/SVG + + Copyright 2001 World Wide Web Consortium, (Massachusetts + Institute of Technology, Institut National de Recherche en + Informatique et en Automatique, Keio University). + All Rights Reserved. + + $Id$ + */ + +#ifndef SVGLineElement_H +#define SVGLineElement_H + +#include "SVGElement.h" +#include "SVGTests.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGTransformable.h" + +namespace KSVG +{ + +class SVGAnimatedLength; +class SVGLineElementImpl; + +/** + * The line element defines a line segment that starts at + * one point and ends at another. + * + * For more info look here : 9.5 The + * 'line' element. + */ +class SVGLineElement : public SVGElement, + public SVGTests, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGTransformable +{ +public: + SVGLineElement(); + SVGLineElement(const SVGLineElement &); + SVGLineElement &operator=(const SVGLineElement &other); + SVGLineElement(SVGLineElementImpl *); + ~SVGLineElement(); + + /** + * The x-axis coordinate of the start of the line. + * If the attribute is not specified, the effect is as if a value + * of "0" were specified. + * + * This attribute is animatable. + * + * @return The x-axis coordinate of the start of the line. + */ + SVGAnimatedLength x1(); + + /** + * The y-axis coordinate of the start of the line. + * If the attribute is not specified, the effect is as if a value + * of "0" were specified. + * + * This attribute is animatable. + * + * @return The y-axis coordinate of the start of the line. + */ + SVGAnimatedLength y1(); + + /** + * The x-axis coordinate of the end of the line. + * If the attribute is not specified, the effect is as if a value + * of "0" were specified. + * + * This attribute is animatable. + * + * @return The x-axis coordinate of the end of the line. + */ + SVGAnimatedLength x2(); + + /** + * The y-axis coordinate of the end of the line. + * If the attribute is not specified, the effect is as if a value + * of "0" were specified. + * + * This attribute is animatable. + * + * @return The y-axis coordinate of the end of the line. + */ + SVGAnimatedLength y2(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGLineElementImpl *handle() const { return impl; } + +private: + SVGLineElementImpl *impl; +}; + +} + +#endif + +//vim:ts=4:noet diff --git a/ksvg/dom/SVGLinearGradientElement.cc b/ksvg/dom/SVGLinearGradientElement.cc new file mode 100644 index 00000000..b3936dc4 --- /dev/null +++ b/ksvg/dom/SVGLinearGradientElement.cc @@ -0,0 +1,92 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGLinearGradientElement.h" +#include "SVGLinearGradientElementImpl.h" +#include "SVGAnimatedLength.h" + +using namespace KSVG; + +SVGLinearGradientElement::SVGLinearGradientElement() : SVGGradientElement() +{ + impl = 0; +} + +SVGLinearGradientElement::SVGLinearGradientElement(const SVGLinearGradientElement &other) : SVGGradientElement(other), impl(0) +{ + (*this) = other; +} + +SVGLinearGradientElement &SVGLinearGradientElement::operator =(const SVGLinearGradientElement &other) +{ + SVGGradientElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGLinearGradientElement::SVGLinearGradientElement(SVGLinearGradientElementImpl *other) : SVGGradientElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGLinearGradientElement::~SVGLinearGradientElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedLength SVGLinearGradientElement::x1() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->x1()); +} + +SVGAnimatedLength SVGLinearGradientElement::y1() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->y1()); +} + +SVGAnimatedLength SVGLinearGradientElement::x2() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->x2()); +} + +SVGAnimatedLength SVGLinearGradientElement::y2() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->y2()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGLinearGradientElement.h b/ksvg/dom/SVGLinearGradientElement.h new file mode 100644 index 00000000..fe60df89 --- /dev/null +++ b/ksvg/dom/SVGLinearGradientElement.h @@ -0,0 +1,141 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 file includes excerpts from the Scalable Vector Graphics + (SVG) 1.0 Specification (Proposed Recommendation) + http://www.w3.org/TR/SVG + + Copyright 2001 World Wide Web Consortium, (Massachusetts + Institute of Technology, Institut National de Recherche en + Informatique et en Automatique, Keio University). + All Rights Reserved. +*/ + +#ifndef SVGLinearGradientElement_H +#define SVGLinearGradientElement_H + +#include "SVGGradientElement.h" + +namespace KSVG +{ + +class SVGAnimatedLength; +class SVGLinearGradientElementImpl; + +/** + * linearGradient elements are never rendered directly; their + * only usage is as something that can be referenced using the + * fill and stroke properties. + * The display property does not apply to the + * linearGradient element; thus, + * linearGradient elements are not directly rendered even if the + * display property is set to a value other than none, and + * linearGradient elements are available for referencing even when + * the display property on the linearGradient element + * or any of its ancestors is set to none. + * + * For more information : + * + * 13.2.2 Linear gradients + * + */ + +class SVGLinearGradientElement : public SVGGradientElement +{ +public: + SVGLinearGradientElement(); + SVGLinearGradientElement(const SVGLinearGradientElement &other); + SVGLinearGradientElement &operator=(const SVGLinearGradientElement &other); + SVGLinearGradientElement(SVGLinearGradientElementImpl *other); + virtual ~SVGLinearGradientElement(); + + /** + * x1, y1, x2, y2 define a gradient vector for the linear gradient. + * This gradient vector provides starting and ending points onto which the + * @ref SVGGradientElement (gradient stops) are mapped. The values of x1, + * y1, x2, y2 can be either numbers or percentages. + * + * If the attribute is not specified, the effect is as if a value of "0%" + * were specified. + * + * This attribute is animatable. + * + * @return The x1 value + */ + SVGAnimatedLength x1() const; + + /** + * x1, y1, x2, y2 define a gradient vector for the linear gradient. + * This gradient vector provides starting and ending points onto which the + * @ref SVGGradientElement (gradient stops) are mapped. The values of x1, + * y1, x2, y2 can be either numbers or percentages. + * + * If the attribute is not specified, the effect is as if a value of "0%" + * were specified. + * + * This attribute is animatable. + * + * @return The y1 value + */ + SVGAnimatedLength y1() const; + + /** + * x1, y1, x2, y2 define a gradient vector for the linear gradient. + * This gradient vector provides starting and ending points onto which the + * @ref SVGGradientElement (gradient stops) are mapped. The values of x1, + * y1, x2, y2 can be either numbers or percentages. + * + * If the attribute is not specified, the effect is as if a value of "100%" + * were specified. + * + * This attribute is animatable. + * + * @return The x2 value + */ + SVGAnimatedLength x2() const; + + /** + * x1, y1, x2, y2 define a gradient vector for the linear gradient. + * This gradient vector provides starting and ending points onto which the + * @ref SVGGradientElement (gradient stops) are mapped. The values of x1, + * y1, x2, y2 can be either numbers or percentages. + * + * If the attribute is not specified, the effect is as if a value of "0%" + * were specified. + * + * This attribute is animatable. + * + * @return The y2 value + */ + SVGAnimatedLength y2() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGLinearGradientElementImpl *handle() const { return impl; } + +private: + SVGLinearGradientElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet + diff --git a/ksvg/dom/SVGLocatable.cc b/ksvg/dom/SVGLocatable.cc new file mode 100644 index 00000000..62a89e2e --- /dev/null +++ b/ksvg/dom/SVGLocatable.cc @@ -0,0 +1,97 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGLocatable.h" +#include "SVGLocatableImpl.h" +#include "SVGElement.h" +#include "SVGRect.h" +#include "SVGMatrix.h" + +using namespace KSVG; + +// This class can't be constructed seperately. +SVGLocatable::SVGLocatable() +{ + impl = 0; +} + +SVGLocatable::SVGLocatable(const SVGLocatable &other) +{ + (*this) = other; +} + +SVGLocatable &SVGLocatable::operator=(const SVGLocatable &other) +{ + if(impl == other.impl) + return *this; + + impl = other.impl; + + return *this; +} + +SVGLocatable::SVGLocatable(SVGLocatableImpl *other) +{ + impl = other; +} + +SVGLocatable::~SVGLocatable() +{ + // We are not allowed to delete 'impl' as it's not refcounted. + // delete impl; +} + +SVGElement SVGLocatable::nearestViewportElement() const +{ + if(!impl) return SVGElement(0); + return impl->nearestViewportElement(); +} + +SVGElement SVGLocatable::farthestViewportElement() const +{ + if(!impl) return SVGElement(0); + return impl->farthestViewportElement(); +} + +SVGRect SVGLocatable::getBBox() +{ + if(!impl) return SVGRect(0); + return SVGRect(impl->getBBox()); // TODO: Check correctness +} + +SVGMatrix SVGLocatable::getCTM() +{ + if(!impl) return SVGMatrix(0); + return SVGMatrix(impl->getCTM()); +} + +SVGMatrix SVGLocatable::getScreenCTM() +{ + if(!impl) return SVGMatrix(0); + return SVGMatrix(impl->getScreenCTM()); +} + +SVGMatrix SVGLocatable::getTransformToElement(const SVGElement &element) +{ + if(!impl) return SVGMatrix(0); + return SVGMatrix(impl->getTransformToElement(element.handle())); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGLocatable.h b/ksvg/dom/SVGLocatable.h new file mode 100644 index 00000000..ecb93adc --- /dev/null +++ b/ksvg/dom/SVGLocatable.h @@ -0,0 +1,122 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 file includes excerpts from the Scalable Vector Graphics + (SVG) 1.0 Specification (Proposed Recommendation) + http://www.w3.org/TR/SVG + + Copyright 2001 World Wide Web Consortium, (Massachusetts + Institute of Technology, Institut National de Recherche en + Informatique et en Automatique, Keio University). + All Rights Reserved. +*/ + +#ifndef SVGLocatable_H +#define SVGLocatable_H + +namespace KSVG +{ + +class SVGElement; +class SVGMatrix; +class SVGRect; +class SVGLocatableImpl; + +/** + * Interface SVGLocatable is for all elements which either have a transform + * attribute or don't have a transform attribute but whose content can have + * a bounding box in current user space. + */ +class SVGLocatable +{ +public: + SVGLocatable(const SVGLocatable &other); + SVGLocatable &operator=(const SVGLocatable &other); + SVGLocatable(SVGLocatableImpl *other); + virtual ~SVGLocatable(); + + /** + * The element which established the current viewport. Often, the nearest + * ancestor 'svg' element. Null if the current element is the outermost 'svg' element. + */ + SVGElement nearestViewportElement() const; + + /** + * The farthest ancestor 'svg' element. Null if the current element is + * the outermost 'svg' element. + */ + SVGElement farthestViewportElement() const; + + /** + * Returns the tight bounding box in current user space (i.e., after application of + * the transform attribute, if any) on the geometry of all contained graphics + * elements, exclusive of stroke-width and filter effects). + * + * @return An SVGRect object that defines the bounding box. + */ + SVGRect getBBox(); + + /** + * Returns the transformation matrix from current user units (i.e., after application of + * the transform attribute, if any) to the viewport coordinate system for + * the nearestViewportElement. + * + * @return An SVGMatrix object that defines the CTM. + */ + SVGMatrix getCTM(); + + /** + * Returns the transformation matrix from current user units (i.e., after application of + * the transform attribute, if any) to the parent user agent's notice of a "pixel". + * For display devices, ideally this represents a physical screen pixel. For other devices or + * environments where physical pixel sizes are not known, then an algorithm similar to the + * CSS2 definition of a "pixel" can be used instead. + * + * @return An SVGMatrix object that defines the given transformation matrix. + */ + SVGMatrix getScreenCTM(); + + /** + * Returns the transformation matrix from the user coordinate system on the current + * element (after application of the transform attribute, if any) to the + * user coordinate system on parameter element (after application of its + * transform attribute, if any). + * + * @param element The target element. + * + * @return An SVGMatrix object that defines the transformation. + */ + SVGMatrix getTransformToElement(const SVGElement &element); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGLocatableImpl *handle() const { return impl; } + +protected: + SVGLocatable(); + +private: + SVGLocatableImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGMPathElement.cc b/ksvg/dom/SVGMPathElement.cc new file mode 100644 index 00000000..6d7a36e4 --- /dev/null +++ b/ksvg/dom/SVGMPathElement.cc @@ -0,0 +1,69 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGMPathElement.h" +#include "SVGMPathElementImpl.h" + +using namespace KSVG; + +SVGMPathElement::SVGMPathElement() : SVGElement(), SVGURIReference(), SVGExternalResourcesRequired() +{ + impl = 0; +} + +SVGMPathElement::SVGMPathElement(const SVGMPathElement &other) : SVGElement(other), SVGURIReference(other), SVGExternalResourcesRequired(other), impl(0) +{ + (*this) = other; +} + +SVGMPathElement &SVGMPathElement::operator =(const SVGMPathElement &other) +{ + SVGElement::operator=(other); + SVGURIReference::operator=(other); + SVGExternalResourcesRequired::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGMPathElement::SVGMPathElement(SVGMPathElementImpl *other) : SVGElement(other), SVGURIReference(other), SVGExternalResourcesRequired(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGMPathElement::~SVGMPathElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGMPathElement.h b/ksvg/dom/SVGMPathElement.h new file mode 100644 index 00000000..e972e7ca --- /dev/null +++ b/ksvg/dom/SVGMPathElement.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGMPathElement_H +#define SVGMPathElement_H + +#include "SVGElement.h" +#include "SVGURIReference.h" +#include "SVGExternalResourcesRequired.h" + +namespace KSVG +{ + +class SVGMPathElementImpl; +class SVGMPathElement : public SVGElement, + public SVGURIReference, + public SVGExternalResourcesRequired +{ +public: + SVGMPathElement(); + SVGMPathElement(const SVGMPathElement &other); + SVGMPathElement &operator=(const SVGMPathElement &other); + SVGMPathElement(SVGMPathElementImpl *other); + virtual ~SVGMPathElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGMPathElementImpl *handle() const { return impl; } + +private: + SVGMPathElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGMarkerElement.cc b/ksvg/dom/SVGMarkerElement.cc new file mode 100644 index 00000000..7d7551da --- /dev/null +++ b/ksvg/dom/SVGMarkerElement.cc @@ -0,0 +1,129 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGMarkerElement.h" +#include "SVGMarkerElementImpl.h" +#include "SVGAnimatedLength.h" +#include "SVGAnimatedAngle.h" +#include "SVGAngle.h" +#include "SVGAnimatedEnumeration.h" + +using namespace KSVG; + +SVGMarkerElement::SVGMarkerElement() : SVGElement(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGFitToViewBox() +{ + impl = 0; +} + +SVGMarkerElement::SVGMarkerElement(const SVGMarkerElement &other) : SVGElement(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGFitToViewBox(other), impl(0) +{ + (*this) = other; +} + +SVGMarkerElement &SVGMarkerElement::operator =(const SVGMarkerElement &other) +{ + SVGElement::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + SVGFitToViewBox::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGMarkerElement::SVGMarkerElement(SVGMarkerElementImpl *other) : SVGElement(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGFitToViewBox(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGMarkerElement::~SVGMarkerElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedLength SVGMarkerElement::refX() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->refX()); +} + +SVGAnimatedLength SVGMarkerElement::refY() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->refY()); +} + +SVGAnimatedEnumeration SVGMarkerElement::markerUnits() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->markerUnits()); +} + +SVGAnimatedLength SVGMarkerElement::markerWidth() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->markerWidth()); +} + +SVGAnimatedLength SVGMarkerElement::markerHeight() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->markerHeight()); +} + +SVGAnimatedEnumeration SVGMarkerElement::orientType() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->orientType()); +} + +SVGAnimatedAngle SVGMarkerElement::orientAngle() const +{ + if(!impl) return SVGAnimatedAngle(0); + return SVGAnimatedAngle(impl->orientAngle()); +} + +void SVGMarkerElement::setOrientToAuto() +{ + if(impl) + impl->setOrientToAuto(); +} + +void SVGMarkerElement::setOrientToAngle(const SVGAngle &angle) +{ + if(impl) + impl->setOrientToAngle(angle.handle()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGMarkerElement.h b/ksvg/dom/SVGMarkerElement.h new file mode 100644 index 00000000..d2f54904 --- /dev/null +++ b/ksvg/dom/SVGMarkerElement.h @@ -0,0 +1,87 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGMarkerElement_H +#define SVGMarkerElement_H + +#include "SVGElement.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGFitToViewBox.h" + +namespace KSVG +{ + +enum +{ + SVG_MARKERUNITS_UNKNOWN = 0, + SVG_MARKERUNITS_USERSPACEONUSE = 1, + SVG_MARKERUNITS_STROKEWIDTH = 2 +}; + +enum +{ + SVG_MARKER_ORIENT_UNKNOWN = 0, + SVG_MARKER_ORIENT_AUTO = 1, + SVG_MARKER_ORIENT_ANGLE = 2 +}; + +class SVGAnimatedLength; +class SVGAnimatedAngle; +class SVGAngle; +class SVGAnimatedEnumeration; +class SVGMarkerElementImpl; +class SVGMarkerElement : public SVGElement, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGFitToViewBox +{ +public: + SVGMarkerElement(); + SVGMarkerElement(const SVGMarkerElement &other); + SVGMarkerElement &operator=(const SVGMarkerElement &other); + SVGMarkerElement(SVGMarkerElementImpl *other); + virtual ~SVGMarkerElement(); + + SVGAnimatedLength refX() const; + SVGAnimatedLength refY() const; + SVGAnimatedEnumeration markerUnits() const; + SVGAnimatedLength markerWidth() const; + SVGAnimatedLength markerHeight() const; + SVGAnimatedEnumeration orientType() const; + SVGAnimatedAngle orientAngle() const; + + void setOrientToAuto(); + void setOrientToAngle(const SVGAngle &angle); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGMarkerElementImpl *handle() const { return impl; } + +private: + SVGMarkerElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGMaskElement.cc b/ksvg/dom/SVGMaskElement.cc new file mode 100644 index 00000000..c4513adc --- /dev/null +++ b/ksvg/dom/SVGMaskElement.cc @@ -0,0 +1,109 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGMaskElement.h" +#include "SVGMaskElementImpl.h" +#include "SVGAnimatedLength.h" +#include "SVGAnimatedEnumeration.h" + +using namespace KSVG; + +SVGMaskElement::SVGMaskElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGUnitTypes() +{ + impl = 0; +} + +SVGMaskElement::SVGMaskElement(const SVGMaskElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGUnitTypes(), impl(0) +{ + (*this) = other; +} + +SVGMaskElement &SVGMaskElement::operator =(const SVGMaskElement &other) +{ + SVGElement::operator=(other); + SVGTests::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGMaskElement::SVGMaskElement(SVGMaskElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGUnitTypes() +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGMaskElement::~SVGMaskElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedEnumeration SVGMaskElement::maskUnits() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->maskUnits()); +} + +SVGAnimatedEnumeration SVGMaskElement::maskContentUnits() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->maskContentUnits()); +} + +SVGAnimatedLength SVGMaskElement::x() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->x()); +} + +SVGAnimatedLength SVGMaskElement::y() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->y()); +} + +SVGAnimatedLength SVGMaskElement::width() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->width()); +} + +SVGAnimatedLength SVGMaskElement::height() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->height()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGMaskElement.h b/ksvg/dom/SVGMaskElement.h new file mode 100644 index 00000000..6a8e26a4 --- /dev/null +++ b/ksvg/dom/SVGMaskElement.h @@ -0,0 +1,69 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGMaskElement_H +#define SVGMaskElement_H + +#include "SVGElement.h" +#include "SVGTests.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGUnitTypes.h" + +namespace KSVG +{ + +class SVGAnimatedEnumeration; +class SVGAnimatedLength; +class SVGMaskElementImpl; +class SVGMaskElement : public SVGElement, + public SVGTests, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGUnitTypes +{ +public: + SVGMaskElement(); + SVGMaskElement(const SVGMaskElement &other); + SVGMaskElement &operator=(const SVGMaskElement &other); + SVGMaskElement(SVGMaskElementImpl *other); + virtual ~SVGMaskElement(); + + SVGAnimatedEnumeration maskUnits() const; + SVGAnimatedEnumeration maskContentUnits() const; + SVGAnimatedLength x() const; + SVGAnimatedLength y() const; + SVGAnimatedLength width() const; + SVGAnimatedLength height() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGMaskElementImpl *handle() const { return impl; } + +private: + SVGMaskElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGMatrix.cc b/ksvg/dom/SVGMatrix.cc new file mode 100644 index 00000000..30eeda56 --- /dev/null +++ b/ksvg/dom/SVGMatrix.cc @@ -0,0 +1,210 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGMatrixImpl.h" +#include "SVGMatrix.h" + +using namespace KSVG; + +SVGMatrix::SVGMatrix() +{ + impl = new SVGMatrixImpl(); + impl->ref(); +} + +SVGMatrix::SVGMatrix(double a, double b, double c, double d, double e, double f) +{ + impl = new SVGMatrixImpl(a, b, c, d, e, f); + impl->ref(); +} + +SVGMatrix::SVGMatrix(const SVGMatrix &other) : impl(0) +{ + (*this) = other; +} + +SVGMatrix &SVGMatrix::operator=(const SVGMatrix &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGMatrix::SVGMatrix(SVGMatrixImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGMatrix::~SVGMatrix() +{ + if(impl) + impl->deref(); +} + +void SVGMatrix::setA(const double &a) +{ + if(impl) + impl->setA(a); +} + +double SVGMatrix::a() const +{ + if(!impl) return -1; + return impl->a(); +} + +void SVGMatrix::setB(const double &b) +{ + if(impl) + impl->setB(b); +} + +double SVGMatrix::b() const +{ + if(!impl) return -1; + return impl->b(); +} + +void SVGMatrix::setC(const double &c) +{ + if(impl) + impl->setC(c); +} + +double SVGMatrix::c() const +{ + if(!impl) return -1; + return impl->c(); +} + +void SVGMatrix::setD(const double &d) +{ + if(impl) + impl->setD(d); +} + +double SVGMatrix::d() const +{ + if(!impl) return -1; + return impl->d(); +} + +void SVGMatrix::setE(const double &e) +{ + if(impl) + impl->setE(e); +} + +double SVGMatrix::e() const +{ + if(!impl) return -1; + return impl->e(); +} + +void SVGMatrix::setF(const double &f) +{ + if(impl) + impl->setF(f); +} + +double SVGMatrix::f() const +{ + if(!impl) return -1; + return impl->f(); +} + +SVGMatrix SVGMatrix::multiply(SVGMatrix &secondMatrix) +{ + if(!impl) return SVGMatrix(0); + return SVGMatrix(impl->multiply(secondMatrix.handle())); +} + +SVGMatrix SVGMatrix::inverse() +{ + if(!impl) return SVGMatrix(0); + return SVGMatrix(impl->inverse()); +} + +SVGMatrix SVGMatrix::translate(const double &x, const double &y) +{ + if(!impl) return SVGMatrix(0); + return SVGMatrix(impl->translate(x, y)); +} + +SVGMatrix SVGMatrix::scale(const double &scaleFactor) +{ + if(!impl) return SVGMatrix(0); + return SVGMatrix(impl->scale(scaleFactor)); +} + +SVGMatrix SVGMatrix::scaleNonUniform(const double &scaleFactorX, const double &scaleFactorY) +{ + if(!impl) return SVGMatrix(0); + return SVGMatrix(impl->scaleNonUniform(scaleFactorX, scaleFactorY)); +} + +SVGMatrix SVGMatrix::rotate(const double &angle) +{ + if(!impl) return SVGMatrix(0); + return SVGMatrix(impl->rotate(angle)); +} + +SVGMatrix SVGMatrix::rotateFromVector(const double &x, const double &y) +{ + if(!impl) return SVGMatrix(0); + return SVGMatrix(impl->rotateFromVector(x, y)); +} + +SVGMatrix SVGMatrix::flipX() +{ + if(!impl) return SVGMatrix(0); + return SVGMatrix(impl->flipX()); +} + +SVGMatrix SVGMatrix::flipY() +{ + if(!impl) return SVGMatrix(0); + return SVGMatrix(impl->flipY()); +} + +SVGMatrix SVGMatrix::skewX(const double &angle) +{ + if(!impl) return SVGMatrix(0); + return SVGMatrix(impl->skewX(angle)); +} + +SVGMatrix SVGMatrix::skewY(const double &angle) +{ + if(!impl) return SVGMatrix(0); + return SVGMatrix(impl->skewY(angle)); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGMatrix.h b/ksvg/dom/SVGMatrix.h new file mode 100644 index 00000000..caf2b9a8 --- /dev/null +++ b/ksvg/dom/SVGMatrix.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGMatrix_H +#define SVGMatrix_H + +namespace KSVG +{ + +class SVGMatrixImpl; +class SVGMatrix +{ +public: + SVGMatrix(); + SVGMatrix(double, double, double, double, double, double); + SVGMatrix(const SVGMatrix &); + SVGMatrix &operator=(const SVGMatrix &); + SVGMatrix(SVGMatrixImpl *); + ~SVGMatrix(); + + void setA(const double &); + double a() const; + + void setB(const double &); + double b() const; + + void setC(const double &); + double c() const; + + void setD(const double &); + double d() const; + + void setE(const double &); + double e() const; + + void setF(const double &); + double f() const; + + SVGMatrix multiply(SVGMatrix &secondMatrix); + SVGMatrix inverse(); + SVGMatrix translate(const double &x, const double &y); + SVGMatrix scale(const double &scaleFactor); + SVGMatrix scaleNonUniform(const double &scaleFactorX, const double &scaleFactorY); + SVGMatrix rotate(const double &angle); + SVGMatrix rotateFromVector(const double &x, const double &y); + SVGMatrix flipX(); + SVGMatrix flipY(); + SVGMatrix skewX(const double &angle); + SVGMatrix skewY(const double &angle); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGMatrixImpl *handle() const { return impl; } + +private: + SVGMatrixImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGMetadataElement.cc b/ksvg/dom/SVGMetadataElement.cc new file mode 100644 index 00000000..e874e95c --- /dev/null +++ b/ksvg/dom/SVGMetadataElement.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGMetadataElement.h" +#include "SVGMetadataElementImpl.h" + +using namespace KSVG; + +SVGMetadataElement::SVGMetadataElement() : SVGElement() +{ + impl = 0; +} + +SVGMetadataElement::SVGMetadataElement(const SVGMetadataElement &other) : SVGElement(other), impl(0) +{ + (*this) = other; +} + +SVGMetadataElement &SVGMetadataElement::operator =(const SVGMetadataElement &other) +{ + SVGElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGMetadataElement::SVGMetadataElement(SVGMetadataElementImpl *other) : SVGElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGMetadataElement::~SVGMetadataElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGMetadataElement.h b/ksvg/dom/SVGMetadataElement.h new file mode 100644 index 00000000..703e48a6 --- /dev/null +++ b/ksvg/dom/SVGMetadataElement.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGMetadataElement_H +#define SVGMetadataElement_H + +#include "SVGElement.h" + +namespace KSVG +{ + +class SVGMetadataElementImpl; +class SVGMetadataElement : public SVGElement +{ +public: + SVGMetadataElement(); + SVGMetadataElement(const SVGMetadataElement &other); + SVGMetadataElement &operator=(const SVGMetadataElement &other); + SVGMetadataElement(SVGMetadataElementImpl *other); + virtual ~SVGMetadataElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGMetadataElementImpl *handle() const { return impl; } + +private: + SVGMetadataElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGMissingGlyphElement.cc b/ksvg/dom/SVGMissingGlyphElement.cc new file mode 100644 index 00000000..d9bff554 --- /dev/null +++ b/ksvg/dom/SVGMissingGlyphElement.cc @@ -0,0 +1,68 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGMissingGlyphElement.h" +#include "SVGMissingGlyphElementImpl.h" + +using namespace KSVG; + +SVGMissingGlyphElement::SVGMissingGlyphElement() : SVGElement(), SVGStylable() +{ + impl = 0; +} + +SVGMissingGlyphElement::SVGMissingGlyphElement(const SVGMissingGlyphElement &other) : SVGElement(other), SVGStylable(other), impl(0) +{ + (*this) = other; +} + +SVGMissingGlyphElement &SVGMissingGlyphElement::operator =(const SVGMissingGlyphElement &other) +{ + SVGElement::operator=(other); + SVGStylable::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGMissingGlyphElement::SVGMissingGlyphElement(SVGMissingGlyphElementImpl *other) : SVGElement(other), SVGStylable(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGMissingGlyphElement::~SVGMissingGlyphElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGMissingGlyphElement.h b/ksvg/dom/SVGMissingGlyphElement.h new file mode 100644 index 00000000..5b7e6f62 --- /dev/null +++ b/ksvg/dom/SVGMissingGlyphElement.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGMissingGlyphElement_H +#define SVGMissingGlyphElement_H + +#include "SVGElement.h" +#include "SVGStylable.h" + +namespace KSVG +{ + +class SVGMissingGlyphElementImpl; +class SVGMissingGlyphElement : public SVGElement, + public SVGStylable +{ +public: + SVGMissingGlyphElement(); + SVGMissingGlyphElement(const SVGMissingGlyphElement &other); + SVGMissingGlyphElement &operator=(const SVGMissingGlyphElement &other); + SVGMissingGlyphElement(SVGMissingGlyphElementImpl *other); + virtual ~SVGMissingGlyphElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGMissingGlyphElementImpl *handle() const { return impl; } + +private: + SVGMissingGlyphElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGNumber.cc b/ksvg/dom/SVGNumber.cc new file mode 100644 index 00000000..81208987 --- /dev/null +++ b/ksvg/dom/SVGNumber.cc @@ -0,0 +1,78 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGNumber.h" +#include "SVGNumberImpl.h" + +using namespace KSVG; + +SVGNumber::SVGNumber() +{ + impl = new SVGNumberImpl(); + impl->ref(); +} + +SVGNumber::SVGNumber(const SVGNumber &other) : impl(0) +{ + (*this) = other; +} + +SVGNumber &SVGNumber::operator=(const SVGNumber &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGNumber::SVGNumber(SVGNumberImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGNumber::~SVGNumber() +{ + if(impl) + impl->deref(); +} + +void SVGNumber::setValue(float value) +{ + if(impl) + impl->setValue(value); +} + +float SVGNumber::value() const +{ + if(!impl) return -1; + return impl->value(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGNumber.h b/ksvg/dom/SVGNumber.h new file mode 100644 index 00000000..d3efbe42 --- /dev/null +++ b/ksvg/dom/SVGNumber.h @@ -0,0 +1,51 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGNumber_H +#define SVGNumber_H + +namespace KSVG +{ + +class SVGNumberImpl; +class SVGNumber +{ +public: + SVGNumber(); + SVGNumber(const SVGNumber &); + SVGNumber &operator=(const SVGNumber &); + SVGNumber(SVGNumberImpl *); + ~SVGNumber(); + + void setValue(float value); + float value() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGNumberImpl *handle() const { return impl; } + +private: + SVGNumberImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGNumberList.cc b/ksvg/dom/SVGNumberList.cc new file mode 100644 index 00000000..92adec50 --- /dev/null +++ b/ksvg/dom/SVGNumberList.cc @@ -0,0 +1,115 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGNumberList.h" +#include "SVGNumberListImpl.h" +#include "SVGNumber.h" + +using namespace KSVG; + +SVGNumberList::SVGNumberList() +{ + impl = new SVGNumberListImpl(); + impl->ref(); +} + +SVGNumberList::SVGNumberList(const SVGNumberList &other) : impl(0) +{ + (*this) = other; +} + +SVGNumberList &SVGNumberList::operator=(const SVGNumberList &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGNumberList::SVGNumberList(SVGNumberListImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGNumberList::~SVGNumberList() +{ + if(impl) + impl->deref(); +} + +unsigned long SVGNumberList::numberOfItems() const +{ + if(!impl) return 0; + return impl->numberOfItems(); +} + +void SVGNumberList::clear() +{ + if(impl) + impl->clear(); +} + +SVGNumber *SVGNumberList::initialize(SVGNumber *newItem) +{ + if(!impl) return new SVGNumber(0); + return new SVGNumber(impl->initialize(newItem->handle())); +} + +SVGNumber *SVGNumberList::getItem(unsigned long index) +{ + if(!impl) return new SVGNumber(0); + return new SVGNumber(impl->getItem(index)); +} + +SVGNumber *SVGNumberList::insertItemBefore(SVGNumber *newItem, unsigned long index) +{ + if(!impl) return new SVGNumber(0); + return new SVGNumber(impl->insertItemBefore(newItem->handle(), index)); +} + +SVGNumber *SVGNumberList::replaceItem(SVGNumber *newItem, unsigned long index) +{ + if(!impl) return new SVGNumber(0); + return new SVGNumber(impl->replaceItem(newItem->handle(), index)); +} + +SVGNumber *SVGNumberList::removeItem(unsigned long index) +{ + if(!impl) return new SVGNumber(0); + return new SVGNumber(impl->removeItem(index)); +} + +SVGNumber *SVGNumberList::appendItem(SVGNumber *newItem) +{ + if(!impl) return new SVGNumber(0); + return new SVGNumber(impl->appendItem(newItem->handle())); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGNumberList.h b/ksvg/dom/SVGNumberList.h new file mode 100644 index 00000000..920574d7 --- /dev/null +++ b/ksvg/dom/SVGNumberList.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGNumberList_H +#define SVGNumberList_H + +namespace KSVG +{ + +class SVGNumber; +class SVGNumberListImpl; +class SVGNumberList +{ +public: + SVGNumberList(); + SVGNumberList(const SVGNumberList &); + SVGNumberList &operator=(const SVGNumberList &); + SVGNumberList(SVGNumberListImpl *); + ~SVGNumberList(); + + unsigned long numberOfItems() const; + void clear(); + SVGNumber *initialize(SVGNumber *newItem); + SVGNumber *getItem(unsigned long index); + SVGNumber *insertItemBefore(SVGNumber *newItem, unsigned long index); + SVGNumber *replaceItem(SVGNumber *newItem, unsigned long index); + SVGNumber *removeItem(unsigned long index); + SVGNumber *appendItem(SVGNumber *newItem); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGNumberListImpl *handle() const { return impl; } + +private: + SVGNumberListImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPaint.cc b/ksvg/dom/SVGPaint.cc new file mode 100644 index 00000000..7e7051d5 --- /dev/null +++ b/ksvg/dom/SVGPaint.cc @@ -0,0 +1,93 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPaint.h" +#include "SVGPaintImpl.h" + +using namespace KSVG; + +SVGPaint::SVGPaint() : SVGColor() +{ + // FIXME: no icc color support... + impl = new SVGPaintImpl(0); + impl->ref(); +} + +SVGPaint::SVGPaint(const SVGPaint &other) : SVGColor(other), impl(0) +{ + (*this) = other; +} + +SVGPaint &SVGPaint::operator =(const SVGPaint &other) +{ + SVGColor::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGPaint::SVGPaint(SVGPaintImpl *other) : SVGColor(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGPaint::~SVGPaint() +{ + if(impl) + impl->deref(); +} + +unsigned short SVGPaint::paintType() const +{ + if(!impl) return SVG_PAINTTYPE_UNKNOWN; + return impl->paintType(); +} + +DOM::DOMString SVGPaint::uri() const +{ + if(!impl) return DOM::DOMString(); + return impl->uri(); +} + +void SVGPaint::setUri(const DOM::DOMString &uri) +{ + if(impl) + impl->setUri(uri); +} + +void SVGPaint::setPaint(unsigned short paintType, const DOM::DOMString &uri, const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor) +{ + if(impl) + impl->setPaint(paintType, uri, rgbColor, iccColor); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPaint.h b/ksvg/dom/SVGPaint.h new file mode 100644 index 00000000..84f331fb --- /dev/null +++ b/ksvg/dom/SVGPaint.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPaint_H +#define SVGPaint_H + +#include "SVGColor.h" +#include + +namespace KSVG +{ + +enum +{ + SVG_PAINTTYPE_UNKNOWN = 0, + SVG_PAINTTYPE_RGBCOLOR = 1, + SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR = 2, + SVG_PAINTTYPE_NONE = 101, + SVG_PAINTTYPE_CURRENTCOLOR = 102, + SVG_PAINTTYPE_URI_NONE = 103, + SVG_PAINTTYPE_URI_CURRENTCOLOR = 104, + SVG_PAINTTYPE_URI_RGBCOLOR = 105, + SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR = 106, + SVG_PAINTTYPE_URI = 107 +}; + +class SVGPaintImpl; +class SVGPaint : public SVGColor +{ +public: + SVGPaint(); + SVGPaint(const SVGPaint &other); + SVGPaint &operator=(const SVGPaint &other); + SVGPaint(SVGPaintImpl *other); + virtual ~SVGPaint(); + + unsigned short paintType() const; + DOM::DOMString uri() const; + void setUri(const DOM::DOMString &uri); + void setPaint(unsigned short paintType, const DOM::DOMString &uri, const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPaintImpl *handle() const { return impl; } + +private: + SVGPaintImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathElement.cc b/ksvg/dom/SVGPathElement.cc new file mode 100644 index 00000000..1153cf65 --- /dev/null +++ b/ksvg/dom/SVGPathElement.cc @@ -0,0 +1,200 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPathElement.h" +#include "SVGPathElementImpl.h" +#include "SVGPoint.h" +#include "SVGPathSegClosePath.h" +#include "SVGPathSegLineto.h" +#include "SVGPathSegLinetoHorizontal.h" +#include "SVGPathSegLinetoVertical.h" +#include "SVGPathSegMoveto.h" +#include "SVGPathSegArc.h" +#include "SVGPathSegCurvetoCubic.h" +#include "SVGPathSegCurvetoCubicSmooth.h" +#include "SVGPathSegCurvetoQuadratic.h" +#include "SVGPathSegCurvetoQuadraticSmooth.h" + +using namespace KSVG; + +SVGPathElement::SVGPathElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable(), SVGAnimatedPathData() +{ + impl = 0; +} + +SVGPathElement::SVGPathElement(const SVGPathElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGAnimatedPathData(other), impl(0) +{ + (*this) = other; +} + +SVGPathElement &SVGPathElement::operator=(const SVGPathElement &other) +{ + SVGElement::operator=(other); + SVGTests::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + SVGTransformable::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGPathElement::SVGPathElement(SVGPathElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGAnimatedPathData(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGPathElement::~SVGPathElement() +{ + if(impl) + impl->deref(); +} + +/* +SVGAnimatedNumber SVGPathElement::pathLength() const +{ + return m_pathLength; +} +*/ + +float SVGPathElement::getTotalLength() +{ + return impl->getTotalLength(); +} + +SVGPoint SVGPathElement::getPointAtLength(float distance) +{ + return SVGPoint(impl->getPointAtLength(distance)); +} + +unsigned long SVGPathElement::getPathSegAtLength(float distance) +{ + return impl->getPathSegAtLength(distance); +} + +SVGPathSegClosePath SVGPathElement::createSVGPathSegClosePath() +{ + return impl->createSVGPathSegClosePath(); +} + +SVGPathSegMovetoAbs SVGPathElement::createSVGPathSegMovetoAbs(float x,float y) +{ + return impl->createSVGPathSegMovetoAbs(x, y);; +} + +SVGPathSegMovetoRel SVGPathElement::createSVGPathSegMovetoRel(float x,float y) +{ + return impl->createSVGPathSegMovetoRel(x, y); +} + +SVGPathSegLinetoAbs SVGPathElement::createSVGPathSegLinetoAbs(float x,float y) +{ + return impl->createSVGPathSegLinetoAbs(x, y); +} + +SVGPathSegLinetoRel SVGPathElement::createSVGPathSegLinetoRel(float x,float y) +{ + return impl->createSVGPathSegLinetoRel(x, y); +} + +SVGPathSegCurvetoCubicAbs SVGPathElement::createSVGPathSegCurvetoCubicAbs(float x,float y,float x1,float y1,float x2,float y2) +{ + return impl->createSVGPathSegCurvetoCubicAbs(x, y, x1, y1, x2, y2); +} + +SVGPathSegCurvetoCubicRel SVGPathElement::createSVGPathSegCurvetoCubicRel(float x,float y,float x1,float y1,float x2,float y2) +{ + return impl->createSVGPathSegCurvetoCubicRel(x, y, x1, y1, x2, y2); +} + +SVGPathSegCurvetoQuadraticAbs SVGPathElement::createSVGPathSegCurvetoQuadraticAbs(float x,float y,float x1,float y1) +{ + return impl->createSVGPathSegCurvetoQuadraticAbs(x, y, x1, y1); +} + +SVGPathSegCurvetoQuadraticRel SVGPathElement::createSVGPathSegCurvetoQuadraticRel(float x,float y,float x1,float y1) +{ + return impl->createSVGPathSegCurvetoQuadraticRel(x, y, x1, y1); +} + +SVGPathSegArcAbs SVGPathElement::createSVGPathSegArcAbs(float x,float y,float r1,float r2,float angle,bool largeArcFlag,bool sweepFlag) +{ + return impl->createSVGPathSegArcAbs(x, y, r1, r2, angle, largeArcFlag, sweepFlag); +} + +SVGPathSegArcRel SVGPathElement::createSVGPathSegArcRel(float x,float y,float r1,float r2,float angle,bool largeArcFlag,bool sweepFlag) +{ + return impl->createSVGPathSegArcRel(x, y, r1, r2, angle, largeArcFlag, sweepFlag); +} + +SVGPathSegLinetoHorizontalAbs SVGPathElement::createSVGPathSegLinetoHorizontalAbs(float x) +{ + return impl->createSVGPathSegLinetoHorizontalAbs(x); +} + +SVGPathSegLinetoHorizontalRel SVGPathElement::createSVGPathSegLinetoHorizontalRel(float x) +{ + return impl->createSVGPathSegLinetoHorizontalRel(x); +} + +SVGPathSegLinetoVerticalAbs SVGPathElement::createSVGPathSegLinetoVerticalAbs(float y) +{ + return impl->createSVGPathSegLinetoVerticalAbs(y); +} + +SVGPathSegLinetoVerticalRel SVGPathElement::createSVGPathSegLinetoVerticalRel(float y) +{ + return impl->createSVGPathSegLinetoVerticalRel(y); +} + +SVGPathSegCurvetoCubicSmoothAbs SVGPathElement::createSVGPathSegCurvetoCubicSmoothAbs(float x,float y,float x2,float y2) +{ + return impl->createSVGPathSegCurvetoCubicSmoothAbs(x, y, x2, y2);; +} + +SVGPathSegCurvetoCubicSmoothRel SVGPathElement::createSVGPathSegCurvetoCubicSmoothRel(float x,float y,float x2,float y2) +{ + return impl->createSVGPathSegCurvetoCubicSmoothRel(x, y, x2, y2); +} + +SVGPathSegCurvetoQuadraticSmoothAbs SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothAbs(float x,float y) +{ + return impl->createSVGPathSegCurvetoQuadraticSmoothAbs(x, y); +} + +SVGPathSegCurvetoQuadraticSmoothRel SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothRel(float x,float y) +{ + return impl->createSVGPathSegCurvetoQuadraticSmoothRel(x, y); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathElement.h b/ksvg/dom/SVGPathElement.h new file mode 100644 index 00000000..fa4cb379 --- /dev/null +++ b/ksvg/dom/SVGPathElement.h @@ -0,0 +1,107 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathElement_H +#define SVGPathElement_H + +#include "SVGElement.h" +#include "SVGTests.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGTransformable.h" +#include "SVGAnimatedPathData.h" + +namespace KSVG +{ + +class SVGPoint; +class SVGPathSegClosePath; +class SVGPathSegLinetoAbs; +class SVGPathSegLinetoRel; +class SVGPathSegLinetoHorizontalAbs; +class SVGPathSegLinetoHorizontalRel; +class SVGPathSegLinetoVerticalAbs; +class SVGPathSegLinetoVerticalRel; +class SVGPathSegMovetoAbs; +class SVGPathSegMovetoRel; +class SVGPathSegArcAbs; +class SVGPathSegArcRel; +class SVGPathSegCurvetoCubicAbs; +class SVGPathSegCurvetoCubicRel; +class SVGPathSegCurvetoCubicSmoothAbs; +class SVGPathSegCurvetoCubicSmoothRel; +class SVGPathSegCurvetoQuadraticAbs; +class SVGPathSegCurvetoQuadraticRel; +class SVGPathSegCurvetoQuadraticSmoothAbs; +class SVGPathSegCurvetoQuadraticSmoothRel; +class SVGPathElementImpl; +class SVGPathElement : public SVGElement, + public SVGTests, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGTransformable, + public SVGAnimatedPathData +{ +public: + SVGPathElement(); + SVGPathElement(const SVGPathElement &); + SVGPathElement &operator=(const SVGPathElement &other); + SVGPathElement(SVGPathElementImpl *); + ~SVGPathElement(); + + //SVGAnimatedNumber pathLength() const; + float getTotalLength(); + SVGPoint getPointAtLength(float distance); + unsigned long getPathSegAtLength(float distance); + + SVGPathSegClosePath createSVGPathSegClosePath(); + SVGPathSegMovetoAbs createSVGPathSegMovetoAbs(float x,float y); + SVGPathSegMovetoRel createSVGPathSegMovetoRel(float x,float y); + SVGPathSegLinetoAbs createSVGPathSegLinetoAbs(float x,float y); + SVGPathSegLinetoRel createSVGPathSegLinetoRel(float x,float y); + SVGPathSegCurvetoCubicAbs createSVGPathSegCurvetoCubicAbs(float x,float y,float x1,float y1,float x2,float y2); + SVGPathSegCurvetoCubicRel createSVGPathSegCurvetoCubicRel(float x,float y,float x1,float y1,float x2,float y2); + SVGPathSegCurvetoQuadraticAbs createSVGPathSegCurvetoQuadraticAbs(float x,float y,float x1,float y1); + SVGPathSegCurvetoQuadraticRel createSVGPathSegCurvetoQuadraticRel(float x,float y,float x1,float y1); + SVGPathSegArcAbs createSVGPathSegArcAbs(float x,float y,float r1,float r2,float angle,bool largeArcFlag,bool sweepFlag); + SVGPathSegArcRel createSVGPathSegArcRel(float x,float y,float r1,float r2,float angle,bool largeArcFlag,bool sweepFlag); + SVGPathSegLinetoHorizontalAbs createSVGPathSegLinetoHorizontalAbs(float x); + SVGPathSegLinetoHorizontalRel createSVGPathSegLinetoHorizontalRel(float x); + SVGPathSegLinetoVerticalAbs createSVGPathSegLinetoVerticalAbs(float y); + SVGPathSegLinetoVerticalRel createSVGPathSegLinetoVerticalRel(float y); + SVGPathSegCurvetoCubicSmoothAbs createSVGPathSegCurvetoCubicSmoothAbs(float x,float y,float x2,float y2); + SVGPathSegCurvetoCubicSmoothRel createSVGPathSegCurvetoCubicSmoothRel(float x,float y,float x2,float y2); + SVGPathSegCurvetoQuadraticSmoothAbs createSVGPathSegCurvetoQuadraticSmoothAbs(float x,float y); + SVGPathSegCurvetoQuadraticSmoothRel createSVGPathSegCurvetoQuadraticSmoothRel(float x,float y); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathElementImpl *handle() const { return impl; } + +private: + SVGPathElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSeg.cc b/ksvg/dom/SVGPathSeg.cc new file mode 100644 index 00000000..3fc31148 --- /dev/null +++ b/ksvg/dom/SVGPathSeg.cc @@ -0,0 +1,69 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPathSeg.h" +#include "SVGPathSegImpl.h" + +using namespace KSVG; + +SVGPathSeg::SVGPathSeg() +{ + impl = new SVGPathSegImpl(); +} + +SVGPathSeg::SVGPathSeg(const SVGPathSeg &other) +{ + impl = other.impl; +} + +SVGPathSeg &SVGPathSeg::operator=(const SVGPathSeg &other) +{ + if(impl == other.impl) + return *this; + + delete impl; + impl = other.impl; + + return *this; +} + +SVGPathSeg::SVGPathSeg(SVGPathSegImpl *other) +{ + impl = other; +} + +SVGPathSeg::~SVGPathSeg() +{ + delete impl; +} + +unsigned short SVGPathSeg::pathSegType() const +{ + if(!impl) return PATHSEG_UNKNOWN; + return impl->pathSegType(); +} + +DOM::DOMString SVGPathSeg::pathSegTypeAsLetter() const +{ + if(!impl) return DOM::DOMString(""); + return impl->pathSegTypeAsLetter(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSeg.h b/ksvg/dom/SVGPathSeg.h new file mode 100644 index 00000000..f82e3c80 --- /dev/null +++ b/ksvg/dom/SVGPathSeg.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSeg_H +#define SVGPathSeg_H + +#include + +namespace KSVG +{ + +enum +{ + PATHSEG_UNKNOWN = 0, + PATHSEG_CLOSEPATH = 1, + PATHSEG_MOVETO_ABS = 2, + PATHSEG_MOVETO_REL = 3, + PATHSEG_LINETO_ABS = 4, + PATHSEG_LINETO_REL = 5, + PATHSEG_CURVETO_CUBIC_ABS = 6, + PATHSEG_CURVETO_CUBIC_REL = 7, + PATHSEG_CURVETO_QUADRATIC_ABS = 8, + PATHSEG_CURVETO_QUADRATIC_REL = 9, + PATHSEG_ARC_ABS = 10, + PATHSEG_ARC_REL = 11, + PATHSEG_LINETO_HORIZONTAL_ABS = 12, + PATHSEG_LINETO_HORIZONTAL_REL = 13, + PATHSEG_LINETO_VERTICAL_ABS = 14, + PATHSEG_LINETO_VERTICAL_REL = 15, + PATHSEG_CURVETO_CUBIC_SMOOTH_ABS = 16, + PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17, + PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18, + PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19 +}; + +class SVGPathSegImpl; +class SVGPathSeg +{ +public: + SVGPathSeg(); + SVGPathSeg(const SVGPathSeg &); + SVGPathSeg &operator=(const SVGPathSeg &other); + SVGPathSeg(SVGPathSegImpl *); + ~SVGPathSeg(); + + unsigned short pathSegType() const; + DOM::DOMString pathSegTypeAsLetter() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegImpl *handle() const { return impl; } + +private: + SVGPathSegImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegArc.cc b/ksvg/dom/SVGPathSegArc.cc new file mode 100644 index 00000000..078137ab --- /dev/null +++ b/ksvg/dom/SVGPathSegArc.cc @@ -0,0 +1,238 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPathSegArc.h" +#include "SVGPathSegArcImpl.h" + +using namespace KSVG; + +SVGPathSegArcAbs::SVGPathSegArcAbs() : SVGPathSeg() +{ + impl = new SVGPathSegArcAbsImpl(); +} + +SVGPathSegArcAbs::SVGPathSegArcAbs(const SVGPathSegArcAbs &other) : SVGPathSeg(other) +{ + impl = other.impl; +} + +SVGPathSegArcAbs::SVGPathSegArcAbs(SVGPathSegArcAbsImpl *other) : SVGPathSeg(other) +{ + impl = other; +} + +SVGPathSegArcAbs::~SVGPathSegArcAbs() +{ + delete impl; +} + +void SVGPathSegArcAbs::setX(const float &x) +{ + if(impl) + impl->setX(x); +} + +float SVGPathSegArcAbs::x() const +{ + if(!impl) return -1; + return impl->x(); +} + +void SVGPathSegArcAbs::setY(const float &y) +{ + if(impl) + impl->setY(y); +} + +float SVGPathSegArcAbs::y() const +{ + if(!impl) return -1; + return impl->y(); +} + +void SVGPathSegArcAbs::setR1(const float &r1) +{ + if(impl) + impl->setR1(r1); +} + +float SVGPathSegArcAbs::r1() const +{ + if(!impl) return -1; + return impl->r1(); +} + +void SVGPathSegArcAbs::setR2(const float &r2) +{ + if(impl) + impl->setR2(r2); +} + +float SVGPathSegArcAbs::r2() const +{ + if(!impl) return -1; + return impl->r2(); +} + +void SVGPathSegArcAbs::setAngle(const float &angle) +{ + if(impl) + impl->setAngle(angle); +} + +float SVGPathSegArcAbs::angle() const +{ + if(!impl) return -1; + return impl->angle(); +} + +void SVGPathSegArcAbs::setLargeArcFlag(bool largeArcFlag) +{ + if(impl) + impl->setLargeArcFlag(largeArcFlag); +} + +bool SVGPathSegArcAbs::largeArcFlag() const +{ + if(!impl) return false; + return impl->largeArcFlag(); +} + +void SVGPathSegArcAbs::setSweepFlag(bool sweepFlag) +{ + if(impl) + impl->setSweepFlag(sweepFlag); +} + +bool SVGPathSegArcAbs::sweepFlag() const +{ + if(!impl) return false; + return impl->sweepFlag(); +} + + + + + +SVGPathSegArcRel::SVGPathSegArcRel() : SVGPathSeg() +{ + impl = new SVGPathSegArcRelImpl(); +} + +SVGPathSegArcRel::SVGPathSegArcRel(const SVGPathSegArcRel &other) : SVGPathSeg(other) +{ + impl = other.impl; +} + +SVGPathSegArcRel::SVGPathSegArcRel(SVGPathSegArcRelImpl *other) : SVGPathSeg(other) +{ + impl = other; +} + +SVGPathSegArcRel::~SVGPathSegArcRel() +{ + delete impl; +} + +void SVGPathSegArcRel::setX(const float &x) +{ + if(impl) + impl->setX(x); +} + +float SVGPathSegArcRel::x() const +{ + if(!impl) return -1; + return impl->x(); +} + +void SVGPathSegArcRel::setY(const float &y) +{ + if(impl) + impl->setY(y); +} + +float SVGPathSegArcRel::y() const +{ + if(!impl) return -1; + return impl->y(); +} + +void SVGPathSegArcRel::setR1(const float &r1) +{ + if(impl) + impl->setR1(r1); +} + +float SVGPathSegArcRel::r1() const +{ + if(!impl) return -1; + return impl->r1(); +} + +void SVGPathSegArcRel::setR2(const float &r2) +{ + if(impl) + impl->setR2(r2); +} + +float SVGPathSegArcRel::r2() const +{ + if(!impl) return -1; + return impl->r2(); +} + +void SVGPathSegArcRel::setAngle(const float &angle) +{ + if(impl) + impl->setAngle(angle); +} + +float SVGPathSegArcRel::angle() const +{ + if(!impl) return -1; + return impl->angle(); +} + +void SVGPathSegArcRel::setLargeArcFlag(bool largeArcFlag) +{ + if(impl) + impl->setLargeArcFlag(largeArcFlag); +} + +bool SVGPathSegArcRel::largeArcFlag() const +{ + if(!impl) return false; + return impl->largeArcFlag(); +} + +void SVGPathSegArcRel::setSweepFlag(bool sweepFlag) +{ + if(impl) + impl->setSweepFlag(sweepFlag); +} + +bool SVGPathSegArcRel::sweepFlag() const +{ + if(!impl) return false; + return impl->sweepFlag(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegArc.h b/ksvg/dom/SVGPathSegArc.h new file mode 100644 index 00000000..e9b83786 --- /dev/null +++ b/ksvg/dom/SVGPathSegArc.h @@ -0,0 +1,109 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegArc_H +#define SVGPathSegArc_H + +#include "SVGPathSeg.h" + +namespace KSVG +{ + +class SVGPathSegArcAbsImpl; +class SVGPathSegArcAbs : public SVGPathSeg +{ +public: + SVGPathSegArcAbs(); + SVGPathSegArcAbs(const SVGPathSegArcAbs &); + SVGPathSegArcAbs &operator=(const SVGPathSegArcAbs &other); + SVGPathSegArcAbs(SVGPathSegArcAbsImpl *); + ~SVGPathSegArcAbs(); + + void setX(const float &); + float x() const; + + void setY(const float &); + float y() const; + + void setR1(const float &); + float r1() const; + + void setR2(const float &); + float r2() const; + + void setAngle(const float &); + float angle() const; + + void setLargeArcFlag(bool); + bool largeArcFlag() const; + + void setSweepFlag(bool); + bool sweepFlag() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegArcAbsImpl *handle() const { return impl; } + +private: + SVGPathSegArcAbsImpl *impl; +}; + +class SVGPathSegArcRelImpl; +class SVGPathSegArcRel : public SVGPathSeg +{ +public: + SVGPathSegArcRel(); + SVGPathSegArcRel(const SVGPathSegArcRel &); + SVGPathSegArcRel &operator=(const SVGPathSegArcRel &other); + SVGPathSegArcRel(SVGPathSegArcRelImpl *); + ~SVGPathSegArcRel(); + + void setX(const float &); + float x() const; + + void setY(const float &); + float y() const; + + void setR1(const float &); + float r1() const; + + void setR2(const float &); + float r2() const; + + void setAngle(const float &); + float angle() const; + + void setLargeArcFlag(bool); + bool largeArcFlag() const; + + void setSweepFlag(bool); + bool sweepFlag() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegArcRelImpl *handle() const { return impl; } + +private: + SVGPathSegArcRelImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegClosePath.cc b/ksvg/dom/SVGPathSegClosePath.cc new file mode 100644 index 00000000..d9f33877 --- /dev/null +++ b/ksvg/dom/SVGPathSegClosePath.cc @@ -0,0 +1,46 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPathSegClosePath.h" +#include "SVGPathSegClosePathImpl.h" + +using namespace KSVG; + +SVGPathSegClosePath::SVGPathSegClosePath() : SVGPathSeg() +{ + impl = new SVGPathSegClosePathImpl(); +} + +SVGPathSegClosePath::SVGPathSegClosePath(const SVGPathSegClosePath &other) : SVGPathSeg(other) +{ + impl = other.impl; +} + +SVGPathSegClosePath::SVGPathSegClosePath(SVGPathSegClosePathImpl *other) : SVGPathSeg(other) +{ + impl = other; +} + +SVGPathSegClosePath::~SVGPathSegClosePath() +{ + delete impl; +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegClosePath.h b/ksvg/dom/SVGPathSegClosePath.h new file mode 100644 index 00000000..a7f32021 --- /dev/null +++ b/ksvg/dom/SVGPathSegClosePath.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegClosePath_H +#define SVGPathSegClosePath_H + +#include "SVGPathSeg.h" + +namespace KSVG +{ + +class SVGPathSegClosePathImpl; +class SVGPathSegClosePath : public SVGPathSeg +{ +public: + SVGPathSegClosePath(); + SVGPathSegClosePath(const SVGPathSegClosePath &); + SVGPathSegClosePath &operator=(const SVGPathSegClosePath &other); + SVGPathSegClosePath(SVGPathSegClosePathImpl *); + ~SVGPathSegClosePath(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegClosePathImpl *handle() const { return impl; } + +private: + SVGPathSegClosePathImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegCurvetoCubic.cc b/ksvg/dom/SVGPathSegCurvetoCubic.cc new file mode 100644 index 00000000..bee9ce00 --- /dev/null +++ b/ksvg/dom/SVGPathSegCurvetoCubic.cc @@ -0,0 +1,214 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPathSegCurvetoCubic.h" +#include "SVGPathSegCurvetoCubicImpl.h" + +using namespace KSVG; + +SVGPathSegCurvetoCubicAbs::SVGPathSegCurvetoCubicAbs() : SVGPathSeg() +{ + impl = new SVGPathSegCurvetoCubicAbsImpl(); +} + +SVGPathSegCurvetoCubicAbs::SVGPathSegCurvetoCubicAbs(const SVGPathSegCurvetoCubicAbs &other) : SVGPathSeg(other) +{ + impl = other.impl; +} + +SVGPathSegCurvetoCubicAbs::SVGPathSegCurvetoCubicAbs(SVGPathSegCurvetoCubicAbsImpl *other) : SVGPathSeg(other) +{ + impl = other; +} + +SVGPathSegCurvetoCubicAbs::~SVGPathSegCurvetoCubicAbs() +{ + delete impl; +} + +void SVGPathSegCurvetoCubicAbs::setX(const float &x) +{ + if(impl) + impl->setX(x); +} + +float SVGPathSegCurvetoCubicAbs::x() const +{ + if(!impl) return -1; + return impl->x(); +} + +void SVGPathSegCurvetoCubicAbs::setY(const float &y) +{ + if(impl) + impl->setY(y); +} + +float SVGPathSegCurvetoCubicAbs::y() const +{ + if(!impl) return -1; + return impl->y(); +} + +void SVGPathSegCurvetoCubicAbs::setX1(const float &x1) +{ + if(impl) + impl->setX1(x1); +} + +float SVGPathSegCurvetoCubicAbs::x1() const +{ + if(!impl) return -1; + return impl->x1(); +} + +void SVGPathSegCurvetoCubicAbs::setY1(const float &y1) +{ + if(impl) + impl->setY1(y1); +} + +float SVGPathSegCurvetoCubicAbs::y1() const +{ + if(!impl) return -1; + return impl->y1(); +} + +void SVGPathSegCurvetoCubicAbs::setX2(const float &x2) +{ + if(impl) + impl->setX2(x2); +} + +float SVGPathSegCurvetoCubicAbs::x2() const +{ + if(!impl) return -1; + return impl->x2(); +} + +void SVGPathSegCurvetoCubicAbs::setY2(const float &y2) +{ + if(impl) + impl->setY2(y2); +} + +float SVGPathSegCurvetoCubicAbs::y2() const +{ + if(!impl) return -1; + return impl->y2(); +} + + + + + +SVGPathSegCurvetoCubicRel::SVGPathSegCurvetoCubicRel() : SVGPathSeg() +{ + impl = new SVGPathSegCurvetoCubicRelImpl(); +} + +SVGPathSegCurvetoCubicRel::SVGPathSegCurvetoCubicRel(const SVGPathSegCurvetoCubicRel &other) : SVGPathSeg(other) +{ + impl = other.impl; +} + +SVGPathSegCurvetoCubicRel::SVGPathSegCurvetoCubicRel(SVGPathSegCurvetoCubicRelImpl *other) : SVGPathSeg(other) +{ + impl = other; +} + +SVGPathSegCurvetoCubicRel::~SVGPathSegCurvetoCubicRel() +{ + delete impl; +} + +void SVGPathSegCurvetoCubicRel::setX(const float &x) +{ + if(impl) + impl->setX(x); +} + +float SVGPathSegCurvetoCubicRel::x() const +{ + if(!impl) return -1; + return impl->x(); +} + +void SVGPathSegCurvetoCubicRel::setY(const float &y) +{ + if(impl) + impl->setY(y); +} + +float SVGPathSegCurvetoCubicRel::y() const +{ + if(!impl) return -1; + return impl->y(); +} + +void SVGPathSegCurvetoCubicRel::setX1(const float &x1) +{ + if(impl) + impl->setX1(x1); +} + +float SVGPathSegCurvetoCubicRel::x1() const +{ + if(!impl) return -1; + return impl->x1(); +} + +void SVGPathSegCurvetoCubicRel::setY1(const float &y1) +{ + if(impl) + impl->setY1(y1); +} + +float SVGPathSegCurvetoCubicRel::y1() const +{ + if(!impl) return -1; + return impl->y1(); +} + +void SVGPathSegCurvetoCubicRel::setX2(const float &x2) +{ + if(impl) + impl->setX2(x2); +} + +float SVGPathSegCurvetoCubicRel::x2() const +{ + if(!impl) return -1; + return impl->x2(); +} + +void SVGPathSegCurvetoCubicRel::setY2(const float &y2) +{ + if(impl) + impl->setY2(y2); +} + +float SVGPathSegCurvetoCubicRel::y2() const +{ + if(!impl) return -1; + return impl->y2(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegCurvetoCubic.h b/ksvg/dom/SVGPathSegCurvetoCubic.h new file mode 100644 index 00000000..99fde23e --- /dev/null +++ b/ksvg/dom/SVGPathSegCurvetoCubic.h @@ -0,0 +1,103 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegCurvetoCubic_H +#define SVGPathSegCurvetoCubic_H + +#include "SVGPathSeg.h" + +namespace KSVG +{ + +class SVGPathSegCurvetoCubicAbsImpl; +class SVGPathSegCurvetoCubicAbs : public SVGPathSeg +{ +public: + SVGPathSegCurvetoCubicAbs(); + SVGPathSegCurvetoCubicAbs(const SVGPathSegCurvetoCubicAbs &); + SVGPathSegCurvetoCubicAbs &operator=(const SVGPathSegCurvetoCubicAbs &other); + SVGPathSegCurvetoCubicAbs(SVGPathSegCurvetoCubicAbsImpl *); + ~SVGPathSegCurvetoCubicAbs(); + + void setX(const float &); + float x() const; + + void setY(const float &); + float y() const; + + void setX1(const float &); + float x1() const; + + void setY1(const float &); + float y1() const; + + void setX2(const float &); + float x2() const; + + void setY2(const float &); + float y2() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegCurvetoCubicAbsImpl *handle() const { return impl; } + +private: + SVGPathSegCurvetoCubicAbsImpl *impl; +}; + +class SVGPathSegCurvetoCubicRelImpl; +class SVGPathSegCurvetoCubicRel : public SVGPathSeg +{ +public: + SVGPathSegCurvetoCubicRel(); + SVGPathSegCurvetoCubicRel(const SVGPathSegCurvetoCubicRel &); + SVGPathSegCurvetoCubicRel &operator=(const SVGPathSegCurvetoCubicRel &other); + SVGPathSegCurvetoCubicRel(SVGPathSegCurvetoCubicRelImpl *); + ~SVGPathSegCurvetoCubicRel(); + + void setX(const float &); + float x() const; + + void setY(const float &); + float y() const; + + void setX1(const float &); + float x1() const; + + void setY1(const float &); + float y1() const; + + void setX2(const float &); + float x2() const; + + void setY2(const float &); + float y2() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegCurvetoCubicRelImpl *handle() const { return impl; } + +private: + SVGPathSegCurvetoCubicRelImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegCurvetoCubicSmooth.cc b/ksvg/dom/SVGPathSegCurvetoCubicSmooth.cc new file mode 100644 index 00000000..5bb9df25 --- /dev/null +++ b/ksvg/dom/SVGPathSegCurvetoCubicSmooth.cc @@ -0,0 +1,166 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPathSegCurvetoCubicSmooth.h" +#include "SVGPathSegCurvetoCubicSmoothImpl.h" + +using namespace KSVG; + +SVGPathSegCurvetoCubicSmoothAbs::SVGPathSegCurvetoCubicSmoothAbs() : SVGPathSeg() +{ + impl = new SVGPathSegCurvetoCubicSmoothAbsImpl(); +} + +SVGPathSegCurvetoCubicSmoothAbs::SVGPathSegCurvetoCubicSmoothAbs(const SVGPathSegCurvetoCubicSmoothAbs &other) : SVGPathSeg(other) +{ + impl = other.impl; +} + +SVGPathSegCurvetoCubicSmoothAbs::SVGPathSegCurvetoCubicSmoothAbs(SVGPathSegCurvetoCubicSmoothAbsImpl *other) : SVGPathSeg(other) +{ + impl = other; +} + +SVGPathSegCurvetoCubicSmoothAbs::~SVGPathSegCurvetoCubicSmoothAbs() +{ + delete impl; +} + +void SVGPathSegCurvetoCubicSmoothAbs::setX(const float &x) +{ + if(impl) + impl->setX(x); +} + +float SVGPathSegCurvetoCubicSmoothAbs::x() const +{ + if(!impl) return -1; + return impl->x(); +} + +void SVGPathSegCurvetoCubicSmoothAbs::setY(const float &y) +{ + if(impl) + impl->setY(y); +} + +float SVGPathSegCurvetoCubicSmoothAbs::y() const +{ + if(!impl) return -1; + return impl->y(); +} + +void SVGPathSegCurvetoCubicSmoothAbs::setX2(const float &x2) +{ + if(impl) + impl->setX2(x2); +} + +float SVGPathSegCurvetoCubicSmoothAbs::x2() const +{ + if(!impl) return -1; + return impl->x2(); +} + +void SVGPathSegCurvetoCubicSmoothAbs::setY2(const float &y2) +{ + if(impl) + impl->setY2(y2); +} + +float SVGPathSegCurvetoCubicSmoothAbs::y2() const +{ + if(!impl) return -1; + return impl->y2(); +} + + + + + +SVGPathSegCurvetoCubicSmoothRel::SVGPathSegCurvetoCubicSmoothRel() : SVGPathSeg() +{ + impl = new SVGPathSegCurvetoCubicSmoothRelImpl(); +} + +SVGPathSegCurvetoCubicSmoothRel::SVGPathSegCurvetoCubicSmoothRel(const SVGPathSegCurvetoCubicSmoothRel &other) : SVGPathSeg(other) +{ + impl = other.impl; +} + +SVGPathSegCurvetoCubicSmoothRel::SVGPathSegCurvetoCubicSmoothRel(SVGPathSegCurvetoCubicSmoothRelImpl *other) : SVGPathSeg(other) +{ + impl = other; +} + +SVGPathSegCurvetoCubicSmoothRel::~SVGPathSegCurvetoCubicSmoothRel() +{ + delete impl; +} + +void SVGPathSegCurvetoCubicSmoothRel::setX(const float &x) +{ + if(impl) + impl->setX(x); +} + +float SVGPathSegCurvetoCubicSmoothRel::x() const +{ + if(!impl) return -1; + return impl->x(); +} + +void SVGPathSegCurvetoCubicSmoothRel::setY(const float &y) +{ + if(impl) + impl->setY(y); +} + +float SVGPathSegCurvetoCubicSmoothRel::y() const +{ + if(!impl) return -1; + return impl->y(); +} + +void SVGPathSegCurvetoCubicSmoothRel::setX2(const float &x2) +{ + if(impl) + impl->setX2(x2); +} + +float SVGPathSegCurvetoCubicSmoothRel::x2() const +{ + if(!impl) return -1; + return impl->x2(); +} + +void SVGPathSegCurvetoCubicSmoothRel::setY2(const float &y2) +{ + if(impl) + impl->setY2(y2); +} + +float SVGPathSegCurvetoCubicSmoothRel::y2() const +{ + if(!impl) return -1; + return impl->y2(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegCurvetoCubicSmooth.h b/ksvg/dom/SVGPathSegCurvetoCubicSmooth.h new file mode 100644 index 00000000..444e54f0 --- /dev/null +++ b/ksvg/dom/SVGPathSegCurvetoCubicSmooth.h @@ -0,0 +1,91 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegCurvetoCubicSmooth_H +#define SVGPathSegCurvetoCubicSmooth_H + +#include "SVGPathSeg.h" + +namespace KSVG +{ + +class SVGPathSegCurvetoCubicSmoothAbsImpl; +class SVGPathSegCurvetoCubicSmoothAbs : public SVGPathSeg +{ +public: + SVGPathSegCurvetoCubicSmoothAbs(); + SVGPathSegCurvetoCubicSmoothAbs(const SVGPathSegCurvetoCubicSmoothAbs &); + SVGPathSegCurvetoCubicSmoothAbs &operator=(const SVGPathSegCurvetoCubicSmoothAbs &other); + SVGPathSegCurvetoCubicSmoothAbs(SVGPathSegCurvetoCubicSmoothAbsImpl *); + ~SVGPathSegCurvetoCubicSmoothAbs(); + + void setX(const float &); + float x() const; + + void setY(const float &); + float y() const; + + void setX2(const float &); + float x2() const; + + void setY2(const float &); + float y2() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegCurvetoCubicSmoothAbsImpl *handle() const { return impl; } + +private: + SVGPathSegCurvetoCubicSmoothAbsImpl *impl; +}; + +class SVGPathSegCurvetoCubicSmoothRelImpl; +class SVGPathSegCurvetoCubicSmoothRel : public SVGPathSeg +{ +public: + SVGPathSegCurvetoCubicSmoothRel(); + SVGPathSegCurvetoCubicSmoothRel(const SVGPathSegCurvetoCubicSmoothRel &); + SVGPathSegCurvetoCubicSmoothRel &operator=(const SVGPathSegCurvetoCubicSmoothRel &other); + SVGPathSegCurvetoCubicSmoothRel(SVGPathSegCurvetoCubicSmoothRelImpl *); + ~SVGPathSegCurvetoCubicSmoothRel(); + + void setX(const float &); + float x() const; + + void setY(const float &); + float y() const; + + void setX2(const float &); + float x2() const; + + void setY2(const float &); + float y2() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegCurvetoCubicSmoothRelImpl *handle() const { return impl; } + +private: + SVGPathSegCurvetoCubicSmoothRelImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegCurvetoQuadratic.cc b/ksvg/dom/SVGPathSegCurvetoQuadratic.cc new file mode 100644 index 00000000..7792db31 --- /dev/null +++ b/ksvg/dom/SVGPathSegCurvetoQuadratic.cc @@ -0,0 +1,166 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPathSegCurvetoQuadratic.h" +#include "SVGPathSegCurvetoQuadraticImpl.h" + +using namespace KSVG; + +SVGPathSegCurvetoQuadraticAbs::SVGPathSegCurvetoQuadraticAbs() : SVGPathSeg() +{ + impl = new SVGPathSegCurvetoQuadraticAbsImpl(); +} + +SVGPathSegCurvetoQuadraticAbs::SVGPathSegCurvetoQuadraticAbs(const SVGPathSegCurvetoQuadraticAbs &other) : SVGPathSeg(other) +{ + impl = other.impl; +} + +SVGPathSegCurvetoQuadraticAbs::SVGPathSegCurvetoQuadraticAbs(SVGPathSegCurvetoQuadraticAbsImpl *other) : SVGPathSeg(other) +{ + impl = other; +} + +SVGPathSegCurvetoQuadraticAbs::~SVGPathSegCurvetoQuadraticAbs() +{ + delete impl; +} + +void SVGPathSegCurvetoQuadraticAbs::setX(const float &x) +{ + if(impl) + impl->setX(x); +} + +float SVGPathSegCurvetoQuadraticAbs::x() const +{ + if(!impl) return -1; + return impl->x(); +} + +void SVGPathSegCurvetoQuadraticAbs::setY(const float &y) +{ + if(impl) + impl->setY(y); +} + +float SVGPathSegCurvetoQuadraticAbs::y() const +{ + if(!impl) return -1; + return impl->y(); +} + +void SVGPathSegCurvetoQuadraticAbs::setX1(const float &x1) +{ + if(impl) + impl->setX1(x1); +} + +float SVGPathSegCurvetoQuadraticAbs::x1() const +{ + if(!impl) return -1; + return impl->x1(); +} + +void SVGPathSegCurvetoQuadraticAbs::setY1(const float &y1) +{ + if(impl) + impl->setY1(y1); +} + +float SVGPathSegCurvetoQuadraticAbs::y1() const +{ + if(!impl) return -1; + return impl->y1(); +} + + + + + +SVGPathSegCurvetoQuadraticRel::SVGPathSegCurvetoQuadraticRel() : SVGPathSeg() +{ + impl = new SVGPathSegCurvetoQuadraticRelImpl(); +} + +SVGPathSegCurvetoQuadraticRel::SVGPathSegCurvetoQuadraticRel(const SVGPathSegCurvetoQuadraticRel &other) : SVGPathSeg(other) +{ + impl = other.impl; +} + +SVGPathSegCurvetoQuadraticRel::SVGPathSegCurvetoQuadraticRel(SVGPathSegCurvetoQuadraticRelImpl *other) : SVGPathSeg(other) +{ + impl = other; +} + +SVGPathSegCurvetoQuadraticRel::~SVGPathSegCurvetoQuadraticRel() +{ + delete impl; +} + +void SVGPathSegCurvetoQuadraticRel::setX(const float &x) +{ + if(impl) + impl->setX(x); +} + +float SVGPathSegCurvetoQuadraticRel::x() const +{ + if(!impl) return -1; + return impl->x(); +} + +void SVGPathSegCurvetoQuadraticRel::setY(const float &y) +{ + if(impl) + impl->setY(y); +} + +float SVGPathSegCurvetoQuadraticRel::y() const +{ + if(!impl) return -1; + return impl->y(); +} + +void SVGPathSegCurvetoQuadraticRel::setX1(const float &x1) +{ + if(impl) + impl->setX1(x1); +} + +float SVGPathSegCurvetoQuadraticRel::x1() const +{ + if(!impl) return -1; + return impl->x1(); +} + +void SVGPathSegCurvetoQuadraticRel::setY1(const float &y1) +{ + if(impl) + impl->setY1(y1); +} + +float SVGPathSegCurvetoQuadraticRel::y1() const +{ + if(!impl) return -1; + return impl->y1(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegCurvetoQuadratic.h b/ksvg/dom/SVGPathSegCurvetoQuadratic.h new file mode 100644 index 00000000..68bb3364 --- /dev/null +++ b/ksvg/dom/SVGPathSegCurvetoQuadratic.h @@ -0,0 +1,91 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegCurvetoQuadratic_H +#define SVGPathSegCurvetoQuadratic_H + +#include "SVGPathSeg.h" + +namespace KSVG +{ + +class SVGPathSegCurvetoQuadraticAbsImpl; +class SVGPathSegCurvetoQuadraticAbs : public SVGPathSeg +{ +public: + SVGPathSegCurvetoQuadraticAbs(); + SVGPathSegCurvetoQuadraticAbs(const SVGPathSegCurvetoQuadraticAbs &); + SVGPathSegCurvetoQuadraticAbs &operator=(const SVGPathSegCurvetoQuadraticAbs &other); + SVGPathSegCurvetoQuadraticAbs(SVGPathSegCurvetoQuadraticAbsImpl *); + ~SVGPathSegCurvetoQuadraticAbs(); + + void setX(const float &); + float x() const; + + void setY(const float &); + float y() const; + + void setX1(const float &); + float x1() const; + + void setY1(const float &); + float y1() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegCurvetoQuadraticAbsImpl *handle() const { return impl; } + +private: + SVGPathSegCurvetoQuadraticAbsImpl *impl; +}; + +class SVGPathSegCurvetoQuadraticRelImpl; +class SVGPathSegCurvetoQuadraticRel : public SVGPathSeg +{ +public: + SVGPathSegCurvetoQuadraticRel(); + SVGPathSegCurvetoQuadraticRel(const SVGPathSegCurvetoQuadraticRel &); + SVGPathSegCurvetoQuadraticRel &operator=(const SVGPathSegCurvetoQuadraticRel &other); + SVGPathSegCurvetoQuadraticRel(SVGPathSegCurvetoQuadraticRelImpl *); + ~SVGPathSegCurvetoQuadraticRel(); + + void setX(const float &); + float x() const; + + void setY(const float &); + float y() const; + + void setX1(const float &); + float x1() const; + + void setY1(const float &); + float y1() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegCurvetoQuadraticRelImpl *handle() const { return impl; } + +private: + SVGPathSegCurvetoQuadraticRelImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegCurvetoQuadraticSmooth.cc b/ksvg/dom/SVGPathSegCurvetoQuadraticSmooth.cc new file mode 100644 index 00000000..35a841c8 --- /dev/null +++ b/ksvg/dom/SVGPathSegCurvetoQuadraticSmooth.cc @@ -0,0 +1,118 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPathSegCurvetoQuadraticSmooth.h" +#include "SVGPathSegCurvetoQuadraticSmoothImpl.h" + +using namespace KSVG; + +SVGPathSegCurvetoQuadraticSmoothAbs::SVGPathSegCurvetoQuadraticSmoothAbs() : SVGPathSeg() +{ + impl = new SVGPathSegCurvetoQuadraticSmoothAbsImpl(); +} + +SVGPathSegCurvetoQuadraticSmoothAbs::SVGPathSegCurvetoQuadraticSmoothAbs(const SVGPathSegCurvetoQuadraticSmoothAbs &other) : SVGPathSeg(other) +{ + impl = other.impl; +} + +SVGPathSegCurvetoQuadraticSmoothAbs::SVGPathSegCurvetoQuadraticSmoothAbs(SVGPathSegCurvetoQuadraticSmoothAbsImpl *other) : SVGPathSeg(other) +{ + impl = other; +} + +SVGPathSegCurvetoQuadraticSmoothAbs::~SVGPathSegCurvetoQuadraticSmoothAbs() +{ + delete impl; +} + +void SVGPathSegCurvetoQuadraticSmoothAbs::setX(const float &x) +{ + if(impl) + impl->setX(x); +} + +float SVGPathSegCurvetoQuadraticSmoothAbs::x() const +{ + if(!impl) return -1; + return impl->x(); +} + +void SVGPathSegCurvetoQuadraticSmoothAbs::setY(const float &y) +{ + if(impl) + impl->setY(y); +} + +float SVGPathSegCurvetoQuadraticSmoothAbs::y() const +{ + if(!impl) return -1; + return impl->y(); +} + + + + + +SVGPathSegCurvetoQuadraticSmoothRel::SVGPathSegCurvetoQuadraticSmoothRel() : SVGPathSeg() +{ + impl = new SVGPathSegCurvetoQuadraticSmoothRelImpl(); +} + +SVGPathSegCurvetoQuadraticSmoothRel::SVGPathSegCurvetoQuadraticSmoothRel(const SVGPathSegCurvetoQuadraticSmoothRel &other) : SVGPathSeg(other) +{ + impl = other.impl; +} + +SVGPathSegCurvetoQuadraticSmoothRel::SVGPathSegCurvetoQuadraticSmoothRel(SVGPathSegCurvetoQuadraticSmoothRelImpl *other) : SVGPathSeg(other) +{ + impl = other; +} + +SVGPathSegCurvetoQuadraticSmoothRel::~SVGPathSegCurvetoQuadraticSmoothRel() +{ + delete impl; +} + +void SVGPathSegCurvetoQuadraticSmoothRel::setX(const float &x) +{ + if(impl) + impl->setX(x); +} + +float SVGPathSegCurvetoQuadraticSmoothRel::x() const +{ + if(!impl) return -1; + return impl->x(); +} + +void SVGPathSegCurvetoQuadraticSmoothRel::setY(const float &y) +{ + if(impl) + impl->setY(y); +} + +float SVGPathSegCurvetoQuadraticSmoothRel::y() const +{ + if(!impl) return -1; + return impl->y(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegCurvetoQuadraticSmooth.h b/ksvg/dom/SVGPathSegCurvetoQuadraticSmooth.h new file mode 100644 index 00000000..e5a2782f --- /dev/null +++ b/ksvg/dom/SVGPathSegCurvetoQuadraticSmooth.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegCurvetoQuadraticSmooth_H +#define SVGPathSegCurvetoQuadraticSmooth_H + +#include "SVGPathSeg.h" + +namespace KSVG +{ + +class SVGPathSegCurvetoQuadraticSmoothAbsImpl; +class SVGPathSegCurvetoQuadraticSmoothAbs : public SVGPathSeg +{ +public: + SVGPathSegCurvetoQuadraticSmoothAbs(); + SVGPathSegCurvetoQuadraticSmoothAbs(const SVGPathSegCurvetoQuadraticSmoothAbs &); + SVGPathSegCurvetoQuadraticSmoothAbs &operator=(const SVGPathSegCurvetoQuadraticSmoothAbs &other); + SVGPathSegCurvetoQuadraticSmoothAbs(SVGPathSegCurvetoQuadraticSmoothAbsImpl *); + ~SVGPathSegCurvetoQuadraticSmoothAbs(); + + void setX(const float &); + float x() const; + + void setY(const float &); + float y() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegCurvetoQuadraticSmoothAbsImpl *handle() const { return impl; } + +private: + SVGPathSegCurvetoQuadraticSmoothAbsImpl *impl; +}; + +class SVGPathSegCurvetoQuadraticSmoothRelImpl; +class SVGPathSegCurvetoQuadraticSmoothRel : public SVGPathSeg +{ +public: + SVGPathSegCurvetoQuadraticSmoothRel(); + SVGPathSegCurvetoQuadraticSmoothRel(const SVGPathSegCurvetoQuadraticSmoothRel &); + SVGPathSegCurvetoQuadraticSmoothRel &operator=(const SVGPathSegCurvetoQuadraticSmoothRel &other); + SVGPathSegCurvetoQuadraticSmoothRel(SVGPathSegCurvetoQuadraticSmoothRelImpl *); + ~SVGPathSegCurvetoQuadraticSmoothRel(); + + void setX(const float &); + float x() const; + + void setY(const float &); + float y() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegCurvetoQuadraticSmoothRelImpl *handle() const { return impl; } + +private: + SVGPathSegCurvetoQuadraticSmoothRelImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegLineto.cc b/ksvg/dom/SVGPathSegLineto.cc new file mode 100644 index 00000000..faabb04e --- /dev/null +++ b/ksvg/dom/SVGPathSegLineto.cc @@ -0,0 +1,118 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPathSegLineto.h" +#include "SVGPathSegLinetoImpl.h" + +using namespace KSVG; + +SVGPathSegLinetoAbs::SVGPathSegLinetoAbs() : SVGPathSeg() +{ + impl = new SVGPathSegLinetoAbsImpl(); +} + +SVGPathSegLinetoAbs::SVGPathSegLinetoAbs(const SVGPathSegLinetoAbs &other) : SVGPathSeg(other) +{ + impl = other.impl; +} + +SVGPathSegLinetoAbs::SVGPathSegLinetoAbs(SVGPathSegLinetoAbsImpl *other) : SVGPathSeg(other) +{ + impl = other; +} + +SVGPathSegLinetoAbs::~SVGPathSegLinetoAbs() +{ + delete impl; +} + +void SVGPathSegLinetoAbs::setX(const float &x) +{ + if(impl) + impl->setX(x); +} + +float SVGPathSegLinetoAbs::x() const +{ + if(!impl) return -1; + return impl->x(); +} + +void SVGPathSegLinetoAbs::setY(const float &y) +{ + if(impl) + impl->setY(y); +} + +float SVGPathSegLinetoAbs::y() const +{ + if(!impl) return -1; + return impl->y(); +} + + + + + +SVGPathSegLinetoRel::SVGPathSegLinetoRel() : SVGPathSeg() +{ + impl = new SVGPathSegLinetoRelImpl(); +} + +SVGPathSegLinetoRel::SVGPathSegLinetoRel(const SVGPathSegLinetoRel &other) : SVGPathSeg(other) +{ + impl = other.impl; +} + +SVGPathSegLinetoRel::SVGPathSegLinetoRel(SVGPathSegLinetoRelImpl *other) : SVGPathSeg(other) +{ + impl = other; +} + +SVGPathSegLinetoRel::~SVGPathSegLinetoRel() +{ + delete impl; +} + +void SVGPathSegLinetoRel::setX(const float &x) +{ + if(impl) + impl->setX(x); +} + +float SVGPathSegLinetoRel::x() const +{ + if(!impl) return -1; + return impl->x(); +} + +void SVGPathSegLinetoRel::setY(const float &y) +{ + if(impl) + impl->setY(y); +} + +float SVGPathSegLinetoRel::y() const +{ + if(!impl) return -1; + return impl->y(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegLineto.h b/ksvg/dom/SVGPathSegLineto.h new file mode 100644 index 00000000..df1b9862 --- /dev/null +++ b/ksvg/dom/SVGPathSegLineto.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegLineto_H +#define SVGPathSegLineto_H + +#include "SVGPathSeg.h" + +namespace KSVG +{ + +class SVGPathSegLinetoAbsImpl; +class SVGPathSegLinetoAbs : public SVGPathSeg +{ +public: + SVGPathSegLinetoAbs(); + SVGPathSegLinetoAbs(const SVGPathSegLinetoAbs &); + SVGPathSegLinetoAbs &operator=(const SVGPathSegLinetoAbs &other); + SVGPathSegLinetoAbs(SVGPathSegLinetoAbsImpl *); + ~SVGPathSegLinetoAbs(); + + void setX(const float &); + float x() const; + + void setY(const float &); + float y() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegLinetoAbsImpl *handle() const { return impl; } + +private: + SVGPathSegLinetoAbsImpl *impl; +}; + +class SVGPathSegLinetoRelImpl; +class SVGPathSegLinetoRel : public SVGPathSeg +{ +public: + SVGPathSegLinetoRel(); + SVGPathSegLinetoRel(const SVGPathSegLinetoRel &); + SVGPathSegLinetoRel &operator=(const SVGPathSegLinetoRel &other); + SVGPathSegLinetoRel(SVGPathSegLinetoRelImpl *); + ~SVGPathSegLinetoRel(); + + void setX(const float &); + float x() const; + + void setY(const float &); + float y() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegLinetoRelImpl *handle() const { return impl; } + +private: + SVGPathSegLinetoRelImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegLinetoHorizontal.cc b/ksvg/dom/SVGPathSegLinetoHorizontal.cc new file mode 100644 index 00000000..22af4e40 --- /dev/null +++ b/ksvg/dom/SVGPathSegLinetoHorizontal.cc @@ -0,0 +1,94 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPathSegLinetoHorizontal.h" +#include "SVGPathSegLinetoHorizontalImpl.h" + +using namespace KSVG; + +SVGPathSegLinetoHorizontalAbs::SVGPathSegLinetoHorizontalAbs() : SVGPathSeg() +{ + impl = new SVGPathSegLinetoHorizontalAbsImpl(); +} + +SVGPathSegLinetoHorizontalAbs::SVGPathSegLinetoHorizontalAbs(const SVGPathSegLinetoHorizontalAbs &other) : SVGPathSeg(other) +{ + impl = other.impl; +} + +SVGPathSegLinetoHorizontalAbs::SVGPathSegLinetoHorizontalAbs(SVGPathSegLinetoHorizontalAbsImpl *other) : SVGPathSeg(other) +{ + impl = other; +} + +SVGPathSegLinetoHorizontalAbs::~SVGPathSegLinetoHorizontalAbs() +{ + delete impl; +} + +void SVGPathSegLinetoHorizontalAbs::setX(const float &x) +{ + if(impl) + impl->setX(x); +} + +float SVGPathSegLinetoHorizontalAbs::x() const +{ + if(!impl) return -1; + return impl->x(); +} + + + + + +SVGPathSegLinetoHorizontalRel::SVGPathSegLinetoHorizontalRel() : SVGPathSeg() +{ + impl = new SVGPathSegLinetoHorizontalRelImpl(); +} + +SVGPathSegLinetoHorizontalRel::SVGPathSegLinetoHorizontalRel(const SVGPathSegLinetoHorizontalRel &other) : SVGPathSeg(other) +{ + impl = other.impl; +} + +SVGPathSegLinetoHorizontalRel::SVGPathSegLinetoHorizontalRel(SVGPathSegLinetoHorizontalRelImpl *other) : SVGPathSeg(other) +{ + impl = other; +} + +SVGPathSegLinetoHorizontalRel::~SVGPathSegLinetoHorizontalRel() +{ + delete impl; +} + +void SVGPathSegLinetoHorizontalRel::setX(const float &x) +{ + if(impl) + impl->setX(x); +} + +float SVGPathSegLinetoHorizontalRel::x() const +{ + if(!impl) return -1; + return impl->x(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegLinetoHorizontal.h b/ksvg/dom/SVGPathSegLinetoHorizontal.h new file mode 100644 index 00000000..51edd6ff --- /dev/null +++ b/ksvg/dom/SVGPathSegLinetoHorizontal.h @@ -0,0 +1,73 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegLinetoHorizontal_H +#define SVGPathSegLinetoHorizontal_H + +#include "SVGPathSeg.h" + +namespace KSVG +{ + +class SVGPathSegLinetoHorizontalAbsImpl; +class SVGPathSegLinetoHorizontalAbs : public SVGPathSeg +{ +public: + SVGPathSegLinetoHorizontalAbs(); + SVGPathSegLinetoHorizontalAbs(const SVGPathSegLinetoHorizontalAbs &); + SVGPathSegLinetoHorizontalAbs &operator=(const SVGPathSegLinetoHorizontalAbs &other); + SVGPathSegLinetoHorizontalAbs(SVGPathSegLinetoHorizontalAbsImpl *); + ~SVGPathSegLinetoHorizontalAbs(); + + void setX(const float &); + float x() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegLinetoHorizontalAbsImpl *handle() const { return impl; } + +private: + SVGPathSegLinetoHorizontalAbsImpl *impl; +}; + +class SVGPathSegLinetoHorizontalRelImpl; +class SVGPathSegLinetoHorizontalRel : public SVGPathSeg +{ +public: + SVGPathSegLinetoHorizontalRel(); + SVGPathSegLinetoHorizontalRel(const SVGPathSegLinetoHorizontalRel &); + SVGPathSegLinetoHorizontalRel &operator=(const SVGPathSegLinetoHorizontalRel &other); + SVGPathSegLinetoHorizontalRel(SVGPathSegLinetoHorizontalRelImpl *); + ~SVGPathSegLinetoHorizontalRel(); + + void setX(const float &); + float x() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegLinetoHorizontalRelImpl *handle() const { return impl; } + +private: + SVGPathSegLinetoHorizontalRelImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegLinetoVertical.cc b/ksvg/dom/SVGPathSegLinetoVertical.cc new file mode 100644 index 00000000..86e0c33e --- /dev/null +++ b/ksvg/dom/SVGPathSegLinetoVertical.cc @@ -0,0 +1,94 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPathSegLinetoVertical.h" +#include "SVGPathSegLinetoVerticalImpl.h" + +using namespace KSVG; + +SVGPathSegLinetoVerticalAbs::SVGPathSegLinetoVerticalAbs() : SVGPathSeg() +{ + impl = new SVGPathSegLinetoVerticalAbsImpl(); +} + +SVGPathSegLinetoVerticalAbs::SVGPathSegLinetoVerticalAbs(const SVGPathSegLinetoVerticalAbs &other) : SVGPathSeg(other) +{ + impl = other.impl; +} + +SVGPathSegLinetoVerticalAbs::SVGPathSegLinetoVerticalAbs(SVGPathSegLinetoVerticalAbsImpl *other) : SVGPathSeg(other) +{ + impl = other; +} + +SVGPathSegLinetoVerticalAbs::~SVGPathSegLinetoVerticalAbs() +{ + delete impl; +} + +void SVGPathSegLinetoVerticalAbs::setY(const float &y) +{ + if(impl) + impl->setY(y); +} + +float SVGPathSegLinetoVerticalAbs::y() const +{ + if(!impl) return -1; + return impl->y(); +} + + + + + +SVGPathSegLinetoVerticalRel::SVGPathSegLinetoVerticalRel() : SVGPathSeg() +{ + impl = new SVGPathSegLinetoVerticalRelImpl(); +} + +SVGPathSegLinetoVerticalRel::SVGPathSegLinetoVerticalRel(const SVGPathSegLinetoVerticalRel &other) : SVGPathSeg(other) +{ + impl = other.impl; +} + +SVGPathSegLinetoVerticalRel::SVGPathSegLinetoVerticalRel(SVGPathSegLinetoVerticalRelImpl *other) : SVGPathSeg(other) +{ + impl = other; +} + +SVGPathSegLinetoVerticalRel::~SVGPathSegLinetoVerticalRel() +{ + delete impl; +} + +void SVGPathSegLinetoVerticalRel::setY(const float &y) +{ + if(impl) + impl->setY(y); +} + +float SVGPathSegLinetoVerticalRel::y() const +{ + if(!impl) return -1; + return impl->y(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegLinetoVertical.h b/ksvg/dom/SVGPathSegLinetoVertical.h new file mode 100644 index 00000000..05e516a7 --- /dev/null +++ b/ksvg/dom/SVGPathSegLinetoVertical.h @@ -0,0 +1,73 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegLinetoVertical_H +#define SVGPathSegLinetoVertical_H + +#include "SVGPathSeg.h" + +namespace KSVG +{ + +class SVGPathSegLinetoVerticalAbsImpl; +class SVGPathSegLinetoVerticalAbs : public SVGPathSeg +{ +public: + SVGPathSegLinetoVerticalAbs(); + SVGPathSegLinetoVerticalAbs(const SVGPathSegLinetoVerticalAbs &); + SVGPathSegLinetoVerticalAbs &operator=(const SVGPathSegLinetoVerticalAbs &other); + SVGPathSegLinetoVerticalAbs(SVGPathSegLinetoVerticalAbsImpl *); + ~SVGPathSegLinetoVerticalAbs(); + + void setY(const float &); + float y() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegLinetoVerticalAbsImpl *handle() const { return impl; } + +private: + SVGPathSegLinetoVerticalAbsImpl *impl; +}; + +class SVGPathSegLinetoVerticalRelImpl; +class SVGPathSegLinetoVerticalRel : public SVGPathSeg +{ +public: + SVGPathSegLinetoVerticalRel(); + SVGPathSegLinetoVerticalRel(const SVGPathSegLinetoVerticalRel &); + SVGPathSegLinetoVerticalRel &operator=(const SVGPathSegLinetoVerticalRel &other); + SVGPathSegLinetoVerticalRel(SVGPathSegLinetoVerticalRelImpl *); + ~SVGPathSegLinetoVerticalRel(); + + void setY(const float &); + float y() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegLinetoVerticalRelImpl *handle() const { return impl; } + +private: + SVGPathSegLinetoVerticalRelImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegList.cc b/ksvg/dom/SVGPathSegList.cc new file mode 100644 index 00000000..e653adc6 --- /dev/null +++ b/ksvg/dom/SVGPathSegList.cc @@ -0,0 +1,114 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPathSegList.h" +#include "SVGPathSegListImpl.h" + +using namespace KSVG; + +SVGPathSegList::SVGPathSegList() +{ + impl = new SVGPathSegListImpl(); + impl->ref(); +} + +SVGPathSegList::SVGPathSegList(const SVGPathSegList &other) +{ + (*this) = other; +} + +SVGPathSegList &SVGPathSegList::operator=(const SVGPathSegList &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGPathSegList::SVGPathSegList(SVGPathSegListImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGPathSegList::~SVGPathSegList() +{ + if(impl) + impl->deref(); +} + +unsigned long SVGPathSegList::numberOfItems() const +{ + if(!impl) return 0; + return impl->numberOfItems(); +} + +void SVGPathSegList::clear() +{ + if(impl) + impl->clear(); +} + +SVGPathSeg *SVGPathSegList::initialize(SVGPathSeg *newItem) +{ + if(!impl) return new SVGPathSeg(0); + return new SVGPathSeg(impl->initialize(newItem->handle())); +} + +SVGPathSeg *SVGPathSegList::getItem(unsigned long index) +{ + if(!impl) return new SVGPathSeg(0); + return new SVGPathSeg(impl->getItem(index)); +} + +SVGPathSeg *SVGPathSegList::insertItemBefore(SVGPathSeg *newItem, unsigned long index) +{ + if(!impl) return new SVGPathSeg(0); + return new SVGPathSeg(impl->insertItemBefore(newItem->handle(), index)); +} + +SVGPathSeg *SVGPathSegList::replaceItem(SVGPathSeg *newItem, unsigned long index) +{ + if(!impl) return new SVGPathSeg(0); + return new SVGPathSeg(impl->replaceItem(newItem->handle(), index)); +} + +SVGPathSeg *SVGPathSegList::removeItem(unsigned long index) +{ + if(!impl) return new SVGPathSeg(0); + return new SVGPathSeg(impl->removeItem(index)); +} + +SVGPathSeg *SVGPathSegList::appendItem(SVGPathSeg *newItem) +{ + if(!impl) return new SVGPathSeg(0); + return new SVGPathSeg(impl->appendItem(newItem->handle())); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegList.h b/ksvg/dom/SVGPathSegList.h new file mode 100644 index 00000000..b9feca72 --- /dev/null +++ b/ksvg/dom/SVGPathSegList.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegList_H +#define SVGPathSegList_H + +namespace KSVG +{ + +class SVGPathSeg; +class SVGPathSegListImpl; +class SVGPathSegList +{ +public: + SVGPathSegList(); + SVGPathSegList(const SVGPathSegList &); + SVGPathSegList &operator=(const SVGPathSegList &other); + SVGPathSegList(SVGPathSegListImpl *); + ~SVGPathSegList(); + + unsigned long numberOfItems() const; + void clear(); + + SVGPathSeg *initialize(SVGPathSeg *newItem); + SVGPathSeg *getItem(unsigned long index); + SVGPathSeg *insertItemBefore(SVGPathSeg *newItem, unsigned long index); + SVGPathSeg *replaceItem(SVGPathSeg *newItem, unsigned long index); + SVGPathSeg *removeItem(unsigned long index); + SVGPathSeg *appendItem(SVGPathSeg *newItem); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegListImpl *handle() const { return impl; } + +private: + SVGPathSegListImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegMoveto.cc b/ksvg/dom/SVGPathSegMoveto.cc new file mode 100644 index 00000000..c5a1dac0 --- /dev/null +++ b/ksvg/dom/SVGPathSegMoveto.cc @@ -0,0 +1,118 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPathSegMoveto.h" +#include "SVGPathSegMovetoImpl.h" + +using namespace KSVG; + +SVGPathSegMovetoAbs::SVGPathSegMovetoAbs() : SVGPathSeg() +{ + impl = new SVGPathSegMovetoAbsImpl(); +} + +SVGPathSegMovetoAbs::SVGPathSegMovetoAbs(const SVGPathSegMovetoAbs &other) : SVGPathSeg(other) +{ + impl = other.impl; +} + +SVGPathSegMovetoAbs::SVGPathSegMovetoAbs(SVGPathSegMovetoAbsImpl *other) : SVGPathSeg(other) +{ + impl = other; +} + +SVGPathSegMovetoAbs::~SVGPathSegMovetoAbs() +{ + delete impl; +} + +void SVGPathSegMovetoAbs::setX(const float &x) +{ + if(impl) + impl->setX(x); +} + +float SVGPathSegMovetoAbs::x() const +{ + if(!impl) return -1; + return impl->x(); +} + +void SVGPathSegMovetoAbs::setY(const float &y) +{ + if(impl) + impl->setY(y); +} + +float SVGPathSegMovetoAbs::y() const +{ + if(!impl) return -1; + return impl->y(); +} + + + + + +SVGPathSegMovetoRel::SVGPathSegMovetoRel() : SVGPathSeg() +{ + impl = new SVGPathSegMovetoRelImpl(); +} + +SVGPathSegMovetoRel::SVGPathSegMovetoRel(const SVGPathSegMovetoRel &other) : SVGPathSeg(other) +{ + impl = other.impl; +} + +SVGPathSegMovetoRel::SVGPathSegMovetoRel(SVGPathSegMovetoRelImpl *other) : SVGPathSeg(other) +{ + impl = other; +} + +SVGPathSegMovetoRel::~SVGPathSegMovetoRel() +{ + delete impl; +} + +void SVGPathSegMovetoRel::setX(const float &x) +{ + if(impl) + impl->setX(x); +} + +float SVGPathSegMovetoRel::x() const +{ + if(!impl) return -1; + return impl->x(); +} + +void SVGPathSegMovetoRel::setY(const float &y) +{ + if(impl) + impl->setY(y); +} + +float SVGPathSegMovetoRel::y() const +{ + if(!impl) return -1; + return impl->y(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPathSegMoveto.h b/ksvg/dom/SVGPathSegMoveto.h new file mode 100644 index 00000000..874443c3 --- /dev/null +++ b/ksvg/dom/SVGPathSegMoveto.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegMoveto_H +#define SVGPathSegMoveto_H + +#include "SVGPathSeg.h" + +namespace KSVG +{ + +class SVGPathSegMovetoAbsImpl; +class SVGPathSegMovetoAbs : public SVGPathSeg +{ +public: + SVGPathSegMovetoAbs(); + SVGPathSegMovetoAbs(const SVGPathSegMovetoAbs &); + SVGPathSegMovetoAbs &operator=(const SVGPathSegMovetoAbs &other); + SVGPathSegMovetoAbs(SVGPathSegMovetoAbsImpl *); + ~SVGPathSegMovetoAbs(); + + void setX(const float &); + float x() const; + + void setY(const float &); + float y() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegMovetoAbsImpl *handle() const { return impl; } + +private: + SVGPathSegMovetoAbsImpl *impl; +}; + +class SVGPathSegMovetoRelImpl; +class SVGPathSegMovetoRel : public SVGPathSeg +{ +public: + SVGPathSegMovetoRel(); + SVGPathSegMovetoRel(const SVGPathSegMovetoRel &); + SVGPathSegMovetoRel &operator=(const SVGPathSegMovetoRel &other); + SVGPathSegMovetoRel(SVGPathSegMovetoRelImpl *); + ~SVGPathSegMovetoRel(); + + void setX(const float &); + float x() const; + + void setY(const float &); + float y() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPathSegMovetoRelImpl *handle() const { return impl; } + +private: + SVGPathSegMovetoRelImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPatternElement.cc b/ksvg/dom/SVGPatternElement.cc new file mode 100644 index 00000000..fc387a97 --- /dev/null +++ b/ksvg/dom/SVGPatternElement.cc @@ -0,0 +1,117 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPatternElement.h" +#include "SVGPatternElementImpl.h" +#include "SVGAnimatedTransformList.h" +#include "SVGAnimatedLength.h" +#include "SVGAnimatedEnumeration.h" + +using namespace KSVG; + +SVGPatternElement::SVGPatternElement() : SVGElement(), SVGURIReference(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGFitToViewBox(), SVGUnitTypes() +{ + impl = 0; +} + +SVGPatternElement::SVGPatternElement(const SVGPatternElement &other) : SVGElement(other), SVGURIReference(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGFitToViewBox(other), SVGUnitTypes(), impl(0) +{ + (*this) = other; +} + +SVGPatternElement &SVGPatternElement::operator =(const SVGPatternElement &other) +{ + SVGElement::operator=(other); + SVGTests::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + SVGFitToViewBox::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGPatternElement::SVGPatternElement(SVGPatternElementImpl *other) : SVGElement(other), SVGURIReference(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGFitToViewBox(other), SVGUnitTypes() +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGPatternElement::~SVGPatternElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedEnumeration SVGPatternElement::patternUnits() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->patternUnits()); +} + +SVGAnimatedEnumeration SVGPatternElement::patternContentUnits() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->patternContentUnits()); +} + +SVGAnimatedTransformList SVGPatternElement::patternTransform() const +{ + if(!impl) return SVGAnimatedTransformList(0); + return SVGAnimatedTransformList(impl->patternTransform()); +} + +SVGAnimatedLength SVGPatternElement::x() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->x()); +} + +SVGAnimatedLength SVGPatternElement::y() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->y()); +} + +SVGAnimatedLength SVGPatternElement::width() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->width()); +} + +SVGAnimatedLength SVGPatternElement::height() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->height()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPatternElement.h b/ksvg/dom/SVGPatternElement.h new file mode 100644 index 00000000..9caf5c14 --- /dev/null +++ b/ksvg/dom/SVGPatternElement.h @@ -0,0 +1,188 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 file includes excerpts from the Scalable Vector Graphics + (SVG) 1.0 Specification (Proposed Recommendation) + http://www.w3.org/TR/SVG + + Copyright 2001 World Wide Web Consortium, (Massachusetts + Institute of Technology, Institut National de Recherche en + Informatique et en Automatique, Keio University). + All Rights Reserved. +*/ + +#ifndef SVGPatternElement_H +#define SVGPatternElement_H + +#include "SVGElement.h" +#include "SVGURIReference.h" +#include "SVGTests.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGFitToViewBox.h" +#include "SVGUnitTypes.h" + +namespace KSVG +{ + +class SVGAnimatedEnumeration; +class SVGAnimatedTransformList; +class SVGAnimatedLength; +class SVGPatternElementImpl; + +/** + * A pattern is used to fill or stroke an object using a pre-defined graphic object which can be + * replicated ("tiled") at fixed intervals in x and y to cover the areas to be painted. + * + * Patterns are defined using a 'pattern' element and then referenced by properties 'fill' and 'stroke' + * on a given graphics element to indicate that the given element shall be filled or stroked with the + * referenced pattern. + */ +class SVGPatternElement : public SVGElement, + public SVGURIReference, + public SVGTests, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGFitToViewBox, + public SVGUnitTypes +{ +public: + SVGPatternElement(); + SVGPatternElement(const SVGPatternElement &other); + SVGPatternElement &operator=(const SVGPatternElement &other); + SVGPatternElement(SVGPatternElementImpl *other); + virtual ~SVGPatternElement(); + + /** + * Defines the coordinate system for attributes x, y, width, height. + * If patternUnits="userSpaceOnUse", x, y, width, height represent + * values in the coordinate system that results from taking the current user coordinate system in place at the time when + * the 'pattern' element is referenced (i.e., the user coordinate system for the element referencing the 'pattern' element + * via a 'fill' or 'stroke' property) and then applying the transform specified by attribute patternTransform. + * If patternUnits="objectBoundingBox", the user coordinate system for attributes x, y, width, + * height is established using the bounding box of the element to which the pattern is applied and then applying + * the transform specified by attribute patternTransform. + * If attribute patternUnits is not specified, then the effect is as if a value of objectBoundingBox were specified. + * + * This attribute is animatable. + * + * @return The current target coordinate system mode. + */ + SVGAnimatedEnumeration patternUnits() const; + + /** + * Defines the coordinate system for the contents of the 'pattern'. Note that this attribute has no effect + * if attribute viewBox is specified. + * If patternContentUnits="userSpaceOnUse", the user coordinate system for the contents of the 'pattern' element + * is the coordinate system that results from taking the current user coordinate system in place at the time + * when the 'pattern' element is referenced (i.e., the user coordinate system for the element referencing the + * 'pattern' element via a 'fill' or 'stroke' property) and then applying the transform specified by attribute + * patternTransform. + * If patternContentUnits="objectBoundingBox", the user coordinate system for the contents of the 'pattern' element + * is established using the bounding box of the element to which the pattern is applied and then applying the + * transform specified by attribute patternTransform. + * If attribute patternContentUnits is not specified, then the effect is as if a value of + * userSpaceOnUse were specified. + * + * This attribute is animatable. + * + * @return The current content coordinate system mode. + */ + SVGAnimatedEnumeration patternContentUnits() const; + + /** + * Contains the definition of an optional additional transformation from the pattern coordinate + * system onto the target coordinate system (i.e., userSpaceOnUse or objectBoundingBox). + * This allows for things such as skewing the pattern tiles. This additional transformation + * matrix is post-multiplied to (i.e., inserted to the right of) any previously defined + * transformations, including the implicit transformation necessary to convert from object + * bounding box units to user space. + * If attribute patternTransform is not specified, then the effect is as if an identity transform + * were specified. + * + * This attribute is animatable. + * + * @return The transformation list that is applied to the pattern tile. + */ + SVGAnimatedTransformList patternTransform() const; + + /** + * The attributes x, y, width, height + * indicate how the pattern tiles are placed and spaced. + * These attributes represent coordinates and values in the coordinate space specified by + * the combination of attributes patternUnits and patternTransform. + * If the attribute is not specified, the effect is as if a value of zero were specified. + * + * This attribute is animatable. + * + * @return The x-axis coordinate of the pattern tile. + */ + SVGAnimatedLength x() const; + + /** + * @see x + * If the attribute is not specified, the effect is as if a value of zero were specified. + * + * This attribute is animatable. + * + * @return The y-axis coordinate of the pattern tile. + */ + SVGAnimatedLength y() const; + + /** + * @see x + * A negative value is an error. A value of zero disables rendering of + * the element (i.e., no paint is applied). + * + * If the attribute is not specified, the effect is as if a value of zero were specified. + * + * This attribute is animatable. + * + * @return The width of the pattern tile. + */ + SVGAnimatedLength width() const; + + /** + * @see x + * A negative value is an error. A value of zero disables rendering of + * the element (i.e., no paint is applied). + * + * If the attribute is not specified, the effect is as if a value of zero were specified. + * + * This attribute is animatable. + * + * @return The height coordinate of the pattern tile. + */ + SVGAnimatedLength height() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPatternElementImpl *handle() const { return impl; } + +private: + SVGPatternElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPoint.cc b/ksvg/dom/SVGPoint.cc new file mode 100644 index 00000000..ac194e7e --- /dev/null +++ b/ksvg/dom/SVGPoint.cc @@ -0,0 +1,97 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPoint.h" +#include "SVGMatrix.h" +#include "SVGPointImpl.h" + +using namespace KSVG; + +SVGPoint::SVGPoint() +{ + impl = new SVGPointImpl(); + impl->ref(); +} + +SVGPoint::SVGPoint(const SVGPoint &other) : impl(0) +{ + (*this) = other; +} + +SVGPoint &SVGPoint::operator=(const SVGPoint &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGPoint::SVGPoint(SVGPointImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGPoint::~SVGPoint() +{ + if(impl) + impl->deref(); +} + +void SVGPoint::setX(float x) +{ + if(impl) + impl->setX(x); +} + +float SVGPoint::x() +{ + if(!impl) return -1; + return impl->x(); +} + +void SVGPoint::setY(float y) +{ + if(impl) + impl->setY(y); +} + +float SVGPoint::y() +{ + if(!impl) return -1; + return impl->y(); +} + +SVGPoint SVGPoint::matrixTransform(SVGMatrix &matrix) +{ + if(!impl) return SVGPoint(0); + return SVGPoint(impl->matrixTransform(*matrix.handle())); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPoint.h b/ksvg/dom/SVGPoint.h new file mode 100644 index 00000000..84b38e86 --- /dev/null +++ b/ksvg/dom/SVGPoint.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPoint_H +#define SVGPoint_H + +namespace KSVG +{ + +class SVGMatrix; +class SVGPointImpl; +class SVGPoint +{ +public: + SVGPoint(); + SVGPoint(const SVGPoint &); + SVGPoint &operator=(const SVGPoint &); + SVGPoint(SVGPointImpl *); + ~SVGPoint(); + + void setX(float x); + float x(); + + void setY(float y); + float y(); + + SVGPoint matrixTransform(SVGMatrix &matrix); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPointImpl *handle() const { return impl; } + +private: + SVGPointImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPointList.cc b/ksvg/dom/SVGPointList.cc new file mode 100644 index 00000000..963b1c60 --- /dev/null +++ b/ksvg/dom/SVGPointList.cc @@ -0,0 +1,114 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPoint.h" +#include "SVGPointImpl.h" +#include "SVGPointList.h" +#include "SVGPointListImpl.h" + +using namespace KSVG; + +SVGPointList::SVGPointList() +{ + impl = new SVGPointListImpl(); + impl->ref(); +} + +SVGPointList::SVGPointList(const SVGPointList &other) : impl(0) +{ + (*this) = other; +} + +SVGPointList &SVGPointList::operator=(const SVGPointList &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGPointList::SVGPointList(SVGPointListImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGPointList::~SVGPointList() +{ + if(impl) + impl->deref(); +} + +unsigned long SVGPointList::numberOfItems() const +{ + if(!impl) return 0; + return impl->numberOfItems(); +} + +void SVGPointList::clear() +{ + if(impl) + impl->clear(); +} + +SVGPoint *SVGPointList::initialize(SVGPoint *newItem) +{ + if(!impl) return new SVGPoint(0); + return new SVGPoint(impl->initialize(newItem->handle())); +} + +SVGPoint *SVGPointList::getItem(unsigned long index) +{ + if(!impl) return new SVGPoint(0); + return new SVGPoint(impl->getItem(index)); +} + +SVGPoint *SVGPointList::insertItemBefore(SVGPoint *newItem, unsigned long index) +{ + if(!impl) return new SVGPoint(0); + return new SVGPoint(impl->insertItemBefore(newItem->handle(), index)); +} + +SVGPoint *SVGPointList::replaceItem(SVGPoint *newItem, unsigned long index) +{ + if(!impl) return new SVGPoint(0); + return new SVGPoint(impl->replaceItem(newItem->handle(), index)); +} + +SVGPoint *SVGPointList::removeItem(unsigned long index) +{ + if(!impl) return new SVGPoint(0); + return new SVGPoint(impl->removeItem(index)); +} + +SVGPoint *SVGPointList::appendItem(SVGPoint *newItem) +{ + if(!impl) return new SVGPoint(0); + return new SVGPoint(impl->appendItem(newItem->handle())); +} diff --git a/ksvg/dom/SVGPointList.h b/ksvg/dom/SVGPointList.h new file mode 100644 index 00000000..cfdec4c5 --- /dev/null +++ b/ksvg/dom/SVGPointList.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPointList_H +#define SVGPointList_H + +namespace KSVG +{ + +class SVGPoint; +class SVGPointListImpl; +class SVGPointList +{ +public: + SVGPointList(); + SVGPointList(const SVGPointList &); + SVGPointList &operator=(const SVGPointList &); + SVGPointList(SVGPointListImpl *); + ~SVGPointList(); + + unsigned long numberOfItems() const; + void clear(); + + SVGPoint *initialize(SVGPoint *newItem); + SVGPoint *getItem(unsigned long index); + SVGPoint *insertItemBefore(SVGPoint *newItem, unsigned long index); + SVGPoint *replaceItem(SVGPoint *newItem, unsigned long index); + SVGPoint *removeItem(unsigned long index); + SVGPoint *appendItem(SVGPoint *newItem); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPointListImpl *handle() const { return impl; } + +private: + SVGPointListImpl *impl; +}; + +} + +#endif diff --git a/ksvg/dom/SVGPolygonElement.cc b/ksvg/dom/SVGPolygonElement.cc new file mode 100644 index 00000000..043c19df --- /dev/null +++ b/ksvg/dom/SVGPolygonElement.cc @@ -0,0 +1,84 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include "SVGPolygonElement.h" +#include "SVGPolygonElementImpl.h" +#include "SVGPointList.h" + +using namespace KSVG; + +SVGPolygonElement::SVGPolygonElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable(), SVGAnimatedPoints() +{ + impl = 0; +} + +SVGPolygonElement::SVGPolygonElement(const SVGPolygonElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGAnimatedPoints(other), impl(0) +{ + (*this) = other; +} + +SVGPolygonElement &SVGPolygonElement::operator=(const SVGPolygonElement &other) +{ + SVGElement::operator=(other); + SVGTests::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + SVGTransformable::operator=(other); + SVGAnimatedPoints::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + return *this; +} + +SVGPolygonElement::SVGPolygonElement(SVGPolygonElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGAnimatedPoints(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGPolygonElement::~SVGPolygonElement() +{ + if(impl) + impl->deref(); +} + +SVGPointList SVGPolygonElement::points() +{ + if(!impl) return SVGPointList(0); + return SVGPointList(impl->points()); +} + +SVGPointList SVGPolygonElement::animatedPoints() +{ + if(!impl) return SVGPointList(0); + return SVGPointList(impl->animatedPoints()); +} diff --git a/ksvg/dom/SVGPolygonElement.h b/ksvg/dom/SVGPolygonElement.h new file mode 100644 index 00000000..526e9815 --- /dev/null +++ b/ksvg/dom/SVGPolygonElement.h @@ -0,0 +1,106 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 file includes excerpts from the Scalable Vector Graphics + (SVG) 1.0 Specification (Proposed Recommendation) + http://www.w3.org/TR/SVG + + Copyright 2001 World Wide Web Consortium, (Massachusetts + Institute of Technology, Institut National de Recherche en + Informatique et en Automatique, Keio University). + All Rights Reserved. + + $Id$ + */ + +#ifndef SVGPolygonElement_H +#define SVGPolygonElement_H + +#include "SVGElement.h" +#include "SVGTests.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGTransformable.h" +#include "SVGAnimatedPoints.h" + +namespace KSVG +{ + +class SVGPointList; +class SVGPolygonElementImpl; + +/** + * The polygon element defines a closed shape consisting + * of connected straight line segments. + * + * For more info look here : 9.7 The + * 'polygon' element. + */ +class SVGPolygonElement : public SVGElement, + public SVGTests, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGTransformable, + public SVGAnimatedPoints +{ +public: + SVGPolygonElement(); + SVGPolygonElement(const SVGPolygonElement &); + SVGPolygonElement &operator=(const SVGPolygonElement &); + SVGPolygonElement(SVGPolygonElementImpl *); + ~SVGPolygonElement(); + + /** + * Provides access to the base (i.e., static) contents of the + * points attribute. + * + * @return A static list of the polygons points + */ + SVGPointList points(); + + /** + * Provides access to the current animated contents of the points + * attribute. + * If the given attribute or property is being animated, contains + * the current animated value of the attribute or property. + * If the given attribute or property is not currently being + * animated, contains the same value as points'. + * + * This attribute is animatable. + * + * @return A list of the polygons points + */ + SVGPointList animatedPoints(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPolygonElementImpl *handle() const { return impl; } + +private: + SVGPolygonElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPolylineElement.cc b/ksvg/dom/SVGPolylineElement.cc new file mode 100644 index 00000000..789c5847 --- /dev/null +++ b/ksvg/dom/SVGPolylineElement.cc @@ -0,0 +1,85 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include "SVGPolylineElement.h" +#include "SVGPolylineElementImpl.h" +#include "SVGPointList.h" + +using namespace KSVG; + +SVGPolylineElement::SVGPolylineElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable(), SVGAnimatedPoints() +{ + impl = 0; +} + +SVGPolylineElement::SVGPolylineElement(const SVGPolylineElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGAnimatedPoints(other), impl(0) +{ + (*this) = other; +} + +SVGPolylineElement &SVGPolylineElement::operator=(const SVGPolylineElement &other) +{ + SVGElement::operator=(other); + SVGTests::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + SVGTransformable::operator=(other); + SVGAnimatedPoints::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGPolylineElement::SVGPolylineElement(SVGPolylineElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGAnimatedPoints(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGPolylineElement::~SVGPolylineElement() +{ + if(impl) + impl->deref(); +} + +SVGPointList SVGPolylineElement::points() +{ + if(!impl) return SVGPointList(0); + return SVGPointList(impl->points()); +} + +SVGPointList SVGPolylineElement::animatedPoints() +{ + if(!impl) return SVGPointList(0); + return SVGPointList(impl->animatedPoints()); +} diff --git a/ksvg/dom/SVGPolylineElement.h b/ksvg/dom/SVGPolylineElement.h new file mode 100644 index 00000000..35e948f7 --- /dev/null +++ b/ksvg/dom/SVGPolylineElement.h @@ -0,0 +1,106 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 file includes excerpts from the Scalable Vector Graphics + (SVG) 1.0 Specification (Proposed Recommendation) + http://www.w3.org/TR/SVG + + Copyright 2001 World Wide Web Consortium, (Massachusetts + Institute of Technology, Institut National de Recherche en + Informatique et en Automatique, Keio University). + All Rights Reserved. + + $Id$ + */ + +#ifndef SVGPolylineElement_H +#define SVGPolylineElement_H + +#include "SVGElement.h" +#include "SVGTests.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGTransformable.h" +#include "SVGAnimatedPoints.h" + +namespace KSVG +{ + +/** + * The polyline element defines a set of connected + * straight line segments. Typically, polyline elements + * define open shapes. + * + * For more info look here : 9.6 The + * 'polyline' element. + */ +class SVGPointList; +class SVGPolylineElementImpl; +class SVGPolylineElement : public SVGElement, + public SVGTests, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGTransformable, + public SVGAnimatedPoints +{ +public: + SVGPolylineElement(); + SVGPolylineElement(const SVGPolylineElement &); + SVGPolylineElement &operator=(const SVGPolylineElement &); + SVGPolylineElement(SVGPolylineElementImpl *); + ~SVGPolylineElement(); + + /** + * Provides access to the base (i.e., static) contents of the + * points attribute. + * + * @return A static list of the polygons points + */ + SVGPointList points(); + + /** + * Provides access to the current animated contents of the points + * attribute. + * If the given attribute or property is being animated, contains + * the current animated value of the attribute or property. + * If the given attribute or property is not currently being + * animated, contains the same value as points'. + * + * This attribute is animatable. + * + * @return A list of the polygons points + */ + SVGPointList animatedPoints(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPolylineElementImpl *handle() const { return impl; } + +private: + SVGPolylineElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPreserveAspectRatio.cc b/ksvg/dom/SVGPreserveAspectRatio.cc new file mode 100644 index 00000000..f86ca1b4 --- /dev/null +++ b/ksvg/dom/SVGPreserveAspectRatio.cc @@ -0,0 +1,81 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPreserveAspectRatio.h" +#include "SVGPreserveAspectRatioImpl.h" + +using namespace KSVG; + +SVGPreserveAspectRatio::SVGPreserveAspectRatio() +{ + impl = new SVGPreserveAspectRatioImpl(); +} + +SVGPreserveAspectRatio::SVGPreserveAspectRatio(const SVGPreserveAspectRatio &other) +{ + impl = other.impl; +} + +SVGPreserveAspectRatio &SVGPreserveAspectRatio::operator=(const SVGPreserveAspectRatio &other) +{ + if(impl == other.impl) + return *this; + + delete impl; + impl = other.impl; + + return *this; +} + +SVGPreserveAspectRatio::SVGPreserveAspectRatio(SVGPreserveAspectRatioImpl *other) +{ + impl = other; +} + +SVGPreserveAspectRatio::~SVGPreserveAspectRatio() +{ + delete impl; +} + +void SVGPreserveAspectRatio::setAlign(unsigned short align) +{ + if(impl) + impl->setAlign(align); +} + +unsigned short SVGPreserveAspectRatio::align() const +{ + if(!impl) return SVG_PRESERVEASPECTRATIO_UNKNOWN; + return impl->align(); +} + +void SVGPreserveAspectRatio::setMeetOrSlice(unsigned short meetOrSlice) +{ + if(impl) + impl->setMeetOrSlice(meetOrSlice); +} + +unsigned short SVGPreserveAspectRatio::meetOrSlice() const +{ + if(!impl) return SVG_MEETORSLICE_UNKNOWN; + return impl->meetOrSlice(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGPreserveAspectRatio.h b/ksvg/dom/SVGPreserveAspectRatio.h new file mode 100644 index 00000000..3c1a4823 --- /dev/null +++ b/ksvg/dom/SVGPreserveAspectRatio.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPreserveAspectRatio_H +#define SVGPreserveAspectRatio_H + +namespace KSVG +{ + +enum +{ + SVG_PRESERVEASPECTRATIO_UNKNOWN = 0, + SVG_PRESERVEASPECTRATIO_NONE = 1, + SVG_PRESERVEASPECTRATIO_XMINYMIN = 2, + SVG_PRESERVEASPECTRATIO_XMIDYMIN = 3, + SVG_PRESERVEASPECTRATIO_XMAXYMIN = 4, + SVG_PRESERVEASPECTRATIO_XMINYMID = 5, + SVG_PRESERVEASPECTRATIO_XMIDYMID = 6, + SVG_PRESERVEASPECTRATIO_XMAXYMID = 7, + SVG_PRESERVEASPECTRATIO_XMINYMAX = 8, + SVG_PRESERVEASPECTRATIO_XMIDYMAX = 9, + SVG_PRESERVEASPECTRATIO_XMAXYMAX = 10 +}; + +enum +{ + SVG_MEETORSLICE_UNKNOWN = 0, + SVG_MEETORSLICE_MEET = 1, + SVG_MEETORSLICE_SLICE = 2 +}; + +class SVGPreserveAspectRatioImpl; +class SVGPreserveAspectRatio +{ +public: + SVGPreserveAspectRatio(); + SVGPreserveAspectRatio(const SVGPreserveAspectRatio &); + SVGPreserveAspectRatio &operator=(const SVGPreserveAspectRatio &other); + SVGPreserveAspectRatio(SVGPreserveAspectRatioImpl *); + ~SVGPreserveAspectRatio(); + + void setAlign(unsigned short); + unsigned short align() const; + + void setMeetOrSlice(unsigned short); + unsigned short meetOrSlice() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGPreserveAspectRatioImpl *handle() const { return impl; } + +protected: + SVGPreserveAspectRatioImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGRadialGradientElement.cc b/ksvg/dom/SVGRadialGradientElement.cc new file mode 100644 index 00000000..02f3d5f2 --- /dev/null +++ b/ksvg/dom/SVGRadialGradientElement.cc @@ -0,0 +1,98 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGRadialGradientElement.h" +#include "SVGRadialGradientElementImpl.h" +#include "SVGAnimatedLength.h" + +using namespace KSVG; + +SVGRadialGradientElement::SVGRadialGradientElement() : SVGGradientElement() +{ + impl = 0; +} + +SVGRadialGradientElement::SVGRadialGradientElement(const SVGRadialGradientElement &other) : SVGGradientElement(other), impl(0) +{ + (*this) = other; +} + +SVGRadialGradientElement &SVGRadialGradientElement::operator =(const SVGRadialGradientElement &other) +{ + SVGGradientElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGRadialGradientElement::SVGRadialGradientElement(SVGRadialGradientElementImpl *other) : SVGGradientElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGRadialGradientElement::~SVGRadialGradientElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedLength SVGRadialGradientElement::cx() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->cx()); +} + +SVGAnimatedLength SVGRadialGradientElement::cy() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->cy()); +} + +SVGAnimatedLength SVGRadialGradientElement::r() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->r()); +} + +SVGAnimatedLength SVGRadialGradientElement::fx() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->fx()); +} + +SVGAnimatedLength SVGRadialGradientElement::fy() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->fy()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGRadialGradientElement.h b/ksvg/dom/SVGRadialGradientElement.h new file mode 100644 index 00000000..c60a00ed --- /dev/null +++ b/ksvg/dom/SVGRadialGradientElement.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGRadialGradientElement_H +#define SVGRadialGradientElement_H + +#include "SVGGradientElement.h" + +namespace KSVG +{ + +class SVGAnimatedLength; +class SVGRadialGradientElementImpl; +class SVGRadialGradientElement : public SVGGradientElement +{ +public: + SVGRadialGradientElement(); + SVGRadialGradientElement(const SVGRadialGradientElement &other); + SVGRadialGradientElement &operator=(const SVGRadialGradientElement &other); + SVGRadialGradientElement(SVGRadialGradientElementImpl *other); + virtual ~SVGRadialGradientElement(); + + SVGAnimatedLength cx() const; + SVGAnimatedLength cy() const; + SVGAnimatedLength r() const; + SVGAnimatedLength fx() const; + SVGAnimatedLength fy() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGRadialGradientElementImpl *handle() const { return impl; } + +private: + SVGRadialGradientElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGRect.cc b/ksvg/dom/SVGRect.cc new file mode 100644 index 00000000..39ba48a4 --- /dev/null +++ b/ksvg/dom/SVGRect.cc @@ -0,0 +1,114 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGRect.h" +#include "SVGRectImpl.h" + +using namespace KSVG; + +SVGRect::SVGRect() +{ + impl = new SVGRectImpl(); + impl->ref(); +} + +SVGRect::SVGRect(const SVGRect &other) : impl(0) +{ + (*this) = other; +} + +SVGRect &SVGRect::operator=(const SVGRect &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGRect::SVGRect(SVGRectImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGRect::~SVGRect() +{ + if(impl) + impl->deref(); +} + +void SVGRect::setX(float x) +{ + if(impl) + impl->setX(x); +} + +float SVGRect::x() const +{ + if(!impl) return -1; + return impl->x(); +} + +void SVGRect::setY(float y) +{ + if(impl) + impl->setY(y); +} + +float SVGRect::y() const +{ + if(!impl) return -1; + return impl->y(); +} + +void SVGRect::setWidth(float width) +{ + if(impl) + impl->setWidth(width); +} + +float SVGRect::width() const +{ + if(!impl) return -1; + return impl->width(); +} + +void SVGRect::setHeight(float height) +{ + if(impl) + impl->setHeight(height); +} + +float SVGRect::height() const +{ + if(!impl) return -1; + return impl->height(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGRect.h b/ksvg/dom/SVGRect.h new file mode 100644 index 00000000..e9be6849 --- /dev/null +++ b/ksvg/dom/SVGRect.h @@ -0,0 +1,87 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 file includes excerpts from the Scalable Vector Graphics + (SVG) 1.0 Specification (Proposed Recommendation) + http://www.w3.org/TR/SVG + + Copyright 2001 World Wide Web Consortium, (Massachusetts + Institute of Technology, Institut National de Recherche en + Informatique et en Automatique, Keio University). + All Rights Reserved. +*/ + +#ifndef SVGRect_H +#define SVGRect_H + +namespace KSVG +{ + +/** + * Rectangles are defined as consisting of a (x,y) coordinate pair + * identifying a minimum X value, a minimum Y value, and a width and + * height, which are usually constrained to be non-negative. + */ +class SVGRectImpl; +class SVGRect +{ +public: + SVGRect(); + SVGRect(const SVGRect &); + SVGRect &operator=(const SVGRect &); + SVGRect(SVGRectImpl *); + ~SVGRect(); + + /** + * Corresponds to attribute x on the given element. + */ + void setX(float x); + float x() const; + + /** + * Corresponds to attribute y on the given element. + */ + void setY(float y); + float y() const; + + /** + * Corresponds to attribute width on the given element. + */ + void setWidth(float width); + float width() const; + + /** + * Corresponds to attribute height on the given element. + */ + void setHeight(float height); + float height() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGRectImpl *handle() const { return impl; } + +private: + SVGRectImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGRectElement.cc b/ksvg/dom/SVGRectElement.cc new file mode 100644 index 00000000..ef4038d4 --- /dev/null +++ b/ksvg/dom/SVGRectElement.cc @@ -0,0 +1,109 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGRectElement.h" +#include "SVGRectElementImpl.h" +#include "SVGAnimatedLength.h" + +using namespace KSVG; + +SVGRectElement::SVGRectElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable() +{ + impl = 0; +} + +SVGRectElement::SVGRectElement(const SVGRectElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), impl(0) +{ + (*this) = other; +} + +SVGRectElement &SVGRectElement::operator=(const SVGRectElement &other) +{ + SVGElement::operator=(other); + SVGTests::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + SVGTransformable::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGRectElement::SVGRectElement(SVGRectElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGRectElement::~SVGRectElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedLength SVGRectElement::x() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->x()); +} + +SVGAnimatedLength SVGRectElement::y() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->y()); +} + +SVGAnimatedLength SVGRectElement::width() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->width()); +} + +SVGAnimatedLength SVGRectElement::height() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->height()); +} + +SVGAnimatedLength SVGRectElement::rx() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->rx()); +} + +SVGAnimatedLength SVGRectElement::ry() +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->ry()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGRectElement.h b/ksvg/dom/SVGRectElement.h new file mode 100644 index 00000000..2a77420d --- /dev/null +++ b/ksvg/dom/SVGRectElement.h @@ -0,0 +1,173 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 file includes excerpts from the Scalable Vector Graphics + (SVG) 1.0 Specification (Proposed Recommendation) + http://www.w3.org/TR/SVG + + Copyright 2001 World Wide Web Consortium, (Massachusetts + Institute of Technology, Institut National de Recherche en + Informatique et en Automatique, Keio University). + All Rights Reserved. + + $Id$ + */ + +#ifndef SVGRectElement_H +#define SVGRectElement_H + +#include "SVGElement.h" +#include "SVGTests.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGTransformable.h" + +namespace KSVG +{ + +class SVGAnimatedLength; +class SVGRectElementImpl; + +/** + * The rect element defines a rectangle which is + * axis-aligned with the current + * user coordinate system. + * Rounded rectangles can be achieved by setting appropriate values + * for attributes x and y. + * + * For more info look here : 9.2 The + * 'rect' element. + */ +class SVGRectElement : public SVGElement, + public SVGTests, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGTransformable +{ +public: + SVGRectElement(); + SVGRectElement(const SVGRectElement &); + SVGRectElement &operator=(const SVGRectElement &other); + SVGRectElement(SVGRectElementImpl *); + ~SVGRectElement(); + + /** + * The x-axis coordinate of the side of the rectangle which has + * the smaller x-axis coordinate value in the current user + * coordinate system. + * If the attribute is not specified, the effect is as if a value + * of "0" were specified. + * + * This attribute is animatable. + * + * @return The x-axis coordinate of the rectangle. + */ + SVGAnimatedLength x(); + + /** + * The y-axis coordinate of the side of the rectangle which has + * the smaller y-axis coordinate value in the current user + * coordinate system. If the attribute is not specified, the + * effect is as if a value of "0" were specified. + * + * This attribute is animatable. + * + * @return The y-axis coordinate of the rectangle. + */ + SVGAnimatedLength y(); + + /** + * The width of the rectangle. A negative value is an error (see + * + * Error processing). + * A value of zero disables rendering of the element. + * + * This attribute is animatable. + * + * @return The width of the rectangle. + */ + SVGAnimatedLength width(); + + /** + * The heigth of the rectangle. A negative value is an error (see + * + * Error processing). A value of zero disables rendering of + * the element. + * + * This attribute is animatable. + * + * @return The height of the rectangle + */ + SVGAnimatedLength height(); + + /** + * For rounded rectangles, the x-axis radius of the ellipse used + * to round off the corners of the rectangle. A negative value is + * an error (see Error + * processing). + * + * See + * 9.2 The 'rect' element for info about what happens if the + * attribute is not specified. + * + * This attribute is animatable + * + * @return The x-axis radius of the ellipse used to round off the + * corners of the rectangle. + */ + SVGAnimatedLength rx(); + + /** + * For rounded rectangles, the y-axis radius of the ellipse used + * to round off the corners of the rectangle. A negative value is + * an error (see Error + * processing). + * + * See + * 9.2 The 'rect' element for info about what happens if the + * attribute is not specified. + * + * This attribute is animatable + * + * @return The y-axis radius of the ellipse used to round off the + * corners of the rectangle. + */ + SVGAnimatedLength ry(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGRectElementImpl *handle() const { return impl; } + +private: + SVGRectElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGRenderingIntent.h b/ksvg/dom/SVGRenderingIntent.h new file mode 100644 index 00000000..5293f92b --- /dev/null +++ b/ksvg/dom/SVGRenderingIntent.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGRenderingIntent_H +#define SVGRenderingIntent_H + +namespace KSVG +{ + +enum +{ + RENDERING_INTENT_UNKNOWN = 0, + RENDERING_INTENT_AUTO = 1, + RENDERING_INTENT_PERCEPTUAL = 2, + RENDERING_INTENT_RELATIVE_COLORIMETRIC = 3, + RENDERING_INTENT_SATURATION = 4, + RENDERING_INTENT_ABSOLUTE_COLORIMETRIC = 5 +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGSVGElement.cc b/ksvg/dom/SVGSVGElement.cc new file mode 100644 index 00000000..204de90c --- /dev/null +++ b/ksvg/dom/SVGSVGElement.cc @@ -0,0 +1,337 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGRect.h" +#include "SVGSVGElement.h" +#include "SVGSVGElementImpl.h" +#include "SVGAnimatedLength.h" +#include "SVGPoint.h" +#include "SVGNumber.h" +#include "SVGAngle.h" +#include "SVGMatrix.h" +#include "SVGLength.h" +#include "SVGRect.h" +#include "SVGTransform.h" +#include "SVGViewSpec.h" +#include + +using namespace KSVG; + +SVGSVGElement::SVGSVGElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGLocatable(), SVGFitToViewBox(), SVGZoomAndPan() +{ + impl = 0; +} + +SVGSVGElement::SVGSVGElement(const SVGSVGElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGLocatable(other), SVGFitToViewBox(other), SVGZoomAndPan(other), impl(0) +{ + (*this) = other; +} + +SVGSVGElement &SVGSVGElement::operator=(const SVGSVGElement &other) +{ + SVGElement::operator=(other); + SVGTests::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + SVGLocatable::operator=(other); + SVGFitToViewBox::operator=(other); + SVGZoomAndPan::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGSVGElement::SVGSVGElement(SVGSVGElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGLocatable(other), SVGFitToViewBox(other), SVGZoomAndPan(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGSVGElement::~SVGSVGElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedLength SVGSVGElement::x() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGSafeCreator::create(impl->x()); +} + +SVGAnimatedLength SVGSVGElement::y() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGSafeCreator::create(impl->y()); +} + +SVGAnimatedLength SVGSVGElement::width() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGSafeCreator::create(impl->width()); +} + +SVGAnimatedLength SVGSVGElement::height() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGSafeCreator::create(impl->height()); +} + +void SVGSVGElement::setContentScriptType(const DOM::DOMString &contentScriptType) +{ + if(impl) + setContentScriptType(contentScriptType); +} + +DOM::DOMString SVGSVGElement::contentScriptType() const +{ + if(!impl) return DOM::DOMString(); + return impl->contentScriptType(); +} + +void SVGSVGElement::setContentStyleType(const DOM::DOMString &contentStyleType) +{ + if(impl) + setContentStyleType(contentStyleType); +} + +DOM::DOMString SVGSVGElement::contentStyleType() const +{ + if(!impl) return DOM::DOMString(); + return impl->contentStyleType(); +} + +SVGRect SVGSVGElement::viewport() const +{ + if(!impl) return SVGRect(0); + return SVGRect(impl->viewport()); +} + +float SVGSVGElement::pixelUnitToMillimeterX() const +{ + if(!impl) return -1; + return impl->pixelUnitToMillimeterX(); +} + +float SVGSVGElement::pixelUnitToMillimeterY() const +{ + if(!impl) return -1; + return impl->pixelUnitToMillimeterY(); +} + +float SVGSVGElement::screenPixelToMillimeterX() const +{ + if(!impl) return -1; + return impl->screenPixelToMillimeterX(); +} + +float SVGSVGElement::screenPixelToMillimeterY() const +{ + if(!impl) return -1; + return impl->screenPixelToMillimeterY(); +} + +void SVGSVGElement::setUseCurrentView(bool useCurrentView) +{ + if(impl) + impl->setUseCurrentView(useCurrentView); +} + +bool SVGSVGElement::useCurrentView() const +{ + if(!impl) return false; + return impl->useCurrentView(); +} + +SVGViewSpec SVGSVGElement::currentView() const +{ + if(!impl) return SVGViewSpec(0); + return impl->currentView(); +} + +void SVGSVGElement::setCurrentScale(float currentScale) +{ + if(impl) + impl->setCurrentScale(currentScale); +} + +float SVGSVGElement::currentScale() const +{ + if(!impl) return -1; + return impl->currentScale(); +} + +SVGPoint SVGSVGElement::currentTranslate() const +{ + if(!impl) return SVGPoint(0); + return SVGSafeCreator::create(impl->currentTranslate()); +} + +unsigned long SVGSVGElement::suspendRedraw(unsigned long time) +{ + if(!impl) return 0; + return impl->suspendRedraw(time); +} + +void SVGSVGElement::unsuspendRedraw(unsigned long id) +{ + if(impl) + impl->unsuspendRedraw(id); +} + +void SVGSVGElement::unsuspendRedrawAll() +{ + if(impl) + impl->unsuspendRedrawAll(); +} + +void SVGSVGElement::forceRedraw() +{ + if(impl) + impl->forceRedraw(); +} + +void SVGSVGElement::pauseAnimations() +{ + if(impl) + impl->pauseAnimations(); +} + +void SVGSVGElement::unpauseAnimations() +{ + if(impl) + impl->unpauseAnimations(); +} + +bool SVGSVGElement::animationsPaused() +{ + if(!impl) return false; + return impl->animationsPaused(); +} + +float SVGSVGElement::getCurrentTime() +{ + if(!impl) return -1; + return impl->getCurrentTime(); +} + +void SVGSVGElement::setCurrentTime(float time) +{ + if(impl) + impl->setCurrentTime(time); +} + +DOM::NodeList SVGSVGElement::getIntersectionList(const SVGRect &rect,const SVGElement &referenceElement) +{ + if(!impl) return DOM::NodeList(); + return impl->getIntersectionList(rect.handle(), referenceElement.handle()); +} + +DOM::NodeList SVGSVGElement::getEnclosureList(const SVGRect &rect,const SVGElement &referenceElement) +{ + if(!impl) return DOM::NodeList(); + return impl->getEnclosureList(rect.handle(), referenceElement.handle()); +} + +bool SVGSVGElement::checkIntersection(const SVGElement &element,const SVGRect &rect) +{ + if(!impl) return false; + return impl->checkIntersection(element.handle(), rect.handle()); +} + +bool SVGSVGElement::checkEnclosure(const SVGElement &element,const SVGRect &rect) +{ + if(!impl) return false; + return impl->checkEnclosure(element.handle(), rect.handle()); +} + +void SVGSVGElement::deSelectAll() +{ + if(impl) + impl->deSelectAll(); +} + +SVGNumber SVGSVGElement::createSVGNumber() +{ + if(!impl) return SVGNumber(0); + return SVGSafeCreator::create(impl->createSVGNumber()); +} + +SVGLength SVGSVGElement::createSVGLength() +{ + if(!impl) return SVGLength(0); + return SVGSafeCreator::create(impl->createSVGLength()); +} + +SVGAngle SVGSVGElement::createSVGAngle() +{ + if(!impl) return SVGAngle(0); + return SVGSafeCreator::create(impl->createSVGAngle()); +} + +SVGPoint SVGSVGElement::createSVGPoint() +{ + if(!impl) return SVGPoint(0); + return SVGSafeCreator::create(impl->createSVGPoint()); +} + +SVGMatrix SVGSVGElement::createSVGMatrix() +{ + if(!impl) return SVGMatrix(0); + return SVGSafeCreator::create(impl->createSVGMatrix()); +} + +SVGRect SVGSVGElement::createSVGRect() +{ + if(!impl) return SVGRect(0); + return SVGSafeCreator::create(impl->createSVGRect()); +} + +SVGTransform SVGSVGElement::createSVGTransform() +{ + if(!impl) return SVGTransform(0); + return SVGSafeCreator::create(impl->createSVGTransform()); +} + +SVGTransform SVGSVGElement::createSVGTransformFromMatrix(const SVGMatrix &matrix) +{ + if(!impl) return SVGTransform(0); + return SVGSafeCreator::create(impl->createSVGTransformFromMatrix(matrix.handle())); +} + +SVGElement SVGSVGElement::getElementById(const DOM::DOMString &elementId) +{ + if(!impl) return SVGElement(0); + return SVGSafeCreator::create(impl->getElementById(elementId)); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGSVGElement.h b/ksvg/dom/SVGSVGElement.h new file mode 100644 index 00000000..59621e2e --- /dev/null +++ b/ksvg/dom/SVGSVGElement.h @@ -0,0 +1,581 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 file includes excerpts from the Scalable Vector Graphics + (SVG) 1.0 Specification (Proposed Recommendation) + http://www.w3.org/TR/SVG + + Copyright 2001 World Wide Web Consortium, (Massachusetts + Institute of Technology, Institut National de Recherche en + Informatique et en Automatique, Keio University). + All Rights Reserved. +*/ + +#ifndef SVGSVGElement_H +#define SVGSVGElement_H + +#include +#include "SVGElement.h" +#include "SVGTests.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGLocatable.h" +#include "SVGFitToViewBox.h" +#include "SVGZoomAndPan.h" + +namespace KSVG +{ +class SVGAnimatedLength; +class SVGPoint; +class SVGNumber; +class SVGAngle; +class SVGMatrix; +class SVGLength; +class SVGRect; +class SVGTransform; +class SVGViewSpec; +class SVGSVGElementImpl; + +/** + * A key interface definition is the SVGSVGElement interface, which is the + * interface that corresponds to the 'svg' element. This interface contains + * various miscellaneous commonly-used utility methods, such as matrix + * operations and the ability to control the time of redraw on visual + * rendering devices. SVGSVGElement extends ViewCSS and DocumentCSS to provide + * access to the computed values of properties and the override style sheet + * as described in DOM2. + * + * For more information : + * + * the 'svg' element + */ +class SVGSVGElement : public SVGElement, + public SVGTests, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGLocatable, + public SVGFitToViewBox, + public SVGZoomAndPan + //public events::EventTarget, + //public events::DocumentEvent, + //public css::ViewCSS, + //public css::DocumentCSS +{ +public: + SVGSVGElement(); + SVGSVGElement(const SVGSVGElement &); + SVGSVGElement &operator=(const SVGSVGElement &other); + SVGSVGElement(SVGSVGElementImpl *); + virtual ~SVGSVGElement(); + + /** + * (Has no meaning or effect on outermost 'svg' elements.) + * The x-axis coordinate of one corner of the rectangular region into which an + * embedded 'svg' element is placed. If the attribute is not specified, the + * effect is as if a value of "0" were specified. + * + * This attribute is animatable. + * + * @return The x-axis coordinate of the viewport of the 'svg' element. + */ + SVGAnimatedLength x() const; + + /** + * (Has no meaning or effect on outermost 'svg' elements.) + * The x-axis coordinate of one corner of the rectangular region into which an + * embedded 'svg' element is placed. If the attribute is not specified, the + * effect is as if a value of "0" were specified. + * + * This attribute is animatable. + * + * @return The y-axis coordinate of the viewport of the 'svg' element. + */ + SVGAnimatedLength y() const; + + /** + * For outermost 'svg' elements, the intrinsic width of the SVG document + * fragment. For embedded 'svg' elements, the width of the rectangular + * region into which the 'svg' element is placed. + * A negative value is an error (see Error + * processing ). + * A value of zero disables rendering of the element. If the attribute is not + * specified, the effect is as if a value of "100%" were specified. + * + * This attribute is animatable. + * + * @return The width of the viewport of the 'svg' element. + */ + SVGAnimatedLength width() const; + + /** + * For outermost 'svg' elements, the intrinsic height of the SVG document + * fragment. For embedded 'svg' elements, the height of the rectangular region + * into which the 'svg' element is placed. + * A negative value is an error (see Error + * processing ). + * A value of zero disables rendering of the element. If the attribute is not + * specified, the effect is as if a value of "100%" were specified. + * + * This attribute is animatable. + * + * @return The height of the viewport of the 'svg' element. + */ + SVGAnimatedLength height() const; + + /** + * The contentScriptType attribute identifies the default + * scripting language for the given document. This attribute sets the scripting + * language used to process the value strings in event attributes. The value + * content-type specifies a media type, per [RFC2045]. The default value + * is "text/ecmascript". + * + * This attribute is not animatable. + * + * @exception + * NO_MODIFICATION_ALLOWED_ERR: Raised on an attempt to change the value of a + * readonly attribute. + */ + void setContentScriptType(const DOM::DOMString &); + + /** + * @return The value of the contentScript attribute on the given + * 'svg' element. + */ + DOM::DOMString contentScriptType() const; + + /** + * Identifies the default style sheet language for the given document. This + * attribute sets the style sheet language for the style attributes that are + * available on many elements. The value of the attribute consists of a media + * type, per [RFC2045]. + * The default value is "text/css". + */ + void setContentStyleType(const DOM::DOMString &); + + /** + * @return The value of the contentStyle attribute on the given + * 'svg' element. + */ + DOM::DOMString contentStyleType() const; + + /** + * The position and size of the viewport (implicit or explicit) that + * corresponds to this 'svg' element. When the user agent is actually + * rendering the content, then the position and size values represent the + * actual values when rendering. The position and size values are unitless + * values in the coordinate system of the parent element. If no parent element + * exists (i.e., 'svg' element represents the root of the document tree), if + * this SVG document is embedded as part of another document (e.g., via the + * HTML 'object' element), then the position and size are unitless values in + * the coordinate system of the parent document. (If the parent uses CSS or + * XSL layout, then unitless values represent pixel units for the current CSS + * or XSL viewport, as described in the CSS2 specification.) If the parent + * element does not have a coordinate system, then the user agent should + * provide reasonable default values for this attribute. + * + * @return The viewport represented by a SVGRect. + */ + SVGRect viewport() const; + + /** + * Size of a pixel units (as defined by CSS2) along the x-axis of the viewport, + * which represents a unit somewhere in the range of 70dpi to 120dpi, and, on + * systems that support this, might actually match the characteristics of the + * target medium. On systems where it is impossible to know the size of a + * pixel, a suitable default pixel size is provided. + * + * @return Corresponding size of a pixel unit along the x-axis of the viewport. + */ + float pixelUnitToMillimeterX() const; + + /** + * @return Corresponding size of a pixel unit along the y-axis of the viewport. + */ + float pixelUnitToMillimeterY() const; + + /** + * User interface (UI) events in DOM Level 2 indicate the screen positions at + * which the given UI event occurred. When the user agent actually knows the + * physical size of a "screen unit", this attribute will express that + * information; otherwise, user agents will provide a suitable default value + * such as .28mm. + * + * @return Corresponding size of a screen pixel along the x-axis of the + * viewport. + */ + float screenPixelToMillimeterX() const; + + /** + * @return Corresponding size of a screen pixel along the y-axis of the + * viewport. + */ + float screenPixelToMillimeterY() const; + + /** + * The initial view (i.e., before magnification and panning) of the current + * innermost SVG document fragment can be either the "standard" view (i.e., + * based on attributes on the 'svg' element such as fitBoxToViewport) or to a + * "custom" view (i.e., a hyperlink into a particular 'view' or other element - + * see Linking + * into SVG content: URI fragments and SVG views). If the initial view + * is the "standard" view, then this attribute is false. If the initial + * view is a "custom" view, then this attribute is true. + * + * @exception DOMException + * NO_MODIFICATION_ALLOWED_ERR: Raised on an attempt to change the value of a + * readonly attribute. + */ + void setUseCurrentView(bool); + + /** + * @return Indicated whether the view is "custom" or not. + */ + bool useCurrentView() const; + + /** + * The definition of the initial view (i.e., before magnification and panning) + * of the current innermost SVG document fragment. The meaning depends on the + * situation: + * + * If the initial view was a "standard" view, then: + * + * the values for viewBox, preserveAspectRatio and + * zoomAndPan within currentView will match the + * values for the corresponding DOM attributes that are on SVGSVGElement + * directly. + * the values for transform and viewTarget within + * currentView will be null. + * + * If the initial view was a link into a 'view' element, then: + * + * the values for viewBox, preserveAspectRatio and + * zoomAndPan within currentView will correspond to + * the corresponding attributes for the given 'view' element. + * the values for transform and viewTarget within + * currentView will be null + * + * If the initial view was a link into another element (i.e., other than a + *'view'), then: + * + * the values for viewBox, preserveAspectRatio and + * zoomAndPan within currentView will match the + * values for the corresponding DOM attributes that are on SVGSVGElement + * directly for the closest ancestor 'svg' element. + * the values for transform within currentView will be null. + * the viewTarget within currentView will represent + * the target of the link. + * + * If the initial view was a link into the SVG document fragment using an SVG + * view specification fragment identifier (i.e., #svgView(...)), then: + * + * the values for viewBox, preserveAspectRatio, + * zoomAndPan, transform and viewTarget + * within currentView will correspond to the values from the SVG + * view specification fragment identifier + * + * The object itself and its contents are both readonly. + */ + SVGViewSpec currentView() const; + + /** + * The currentScale attribute indicates the current scale factor relative to + * the initial view to take into account user magnification and panning + * operations, as described under + * + * Magnification and panning. DOM attributes currentScale and + * currentTranslate are equivalent to the 2x3 matrix [a b c d e f] = + * [currentScale 0 0 currentScale currentTranslate.x currentTranslate.y]. + * If "magnification" is enabled (i.e., zoomAndPan="magnify"), then the effect + * is as if an extra transformation were placed at the outermost level on the + * SVG document fragment (i.e., outside the outermost 'svg' element). + * + * @exception DOMException + * NO_MODIFICATION_ALLOWED_ERR: Raised on an attempt to change the value of a + * readonly attribute. + * + * @param The new value of the currentScale attribute. + */ + void setCurrentScale(float); + + /** + * @return The currentScale attribute value as described above. + */ + float currentScale() const; + + /** + * The corresponding translation factor that takes into account user + * "magnification". + * + * @return The translation factor represented by an SVGPoint . + */ + SVGPoint currentTranslate() const; + + /** + * Takes a time-out value which indicates that redraw shall not occur until: + * + * (a) the corresponding unsuspendRedraw(suspend_handle_id) call has been made + * (b) an unsuspendRedrawAll() call has been made + * (c) its timer has timed out. + * + * In environments that do not support interactivity (e.g., print media), then + * redraw shall not be suspended suspend_handle_id = + * suspendRedraw(max_wait_milliseconds) and unsuspendRedraw(suspend_handle_id) + * must be packaged as balanced pairs. When you want to suspend redraw actions + * as a collection of SVG DOM changes occur, then precede the changes to the + * SVG DOM with a method call similar to suspend_handle_id = + * suspendRedraw(max_wait_milliseconds) and follow the changes with a method + * call similar to unsuspendRedraw(suspend_handle_id). Note that multiple + * suspendRedraw calls can be used at once and that each such method call is + * treated independently of the other suspendRedraw method calls. + * + * @param max_wait_milliseconds The amount of time in milliseconds to hold off + * before redrawing the device.Values greater than 60 seconds will be + * truncated down to 60 seconds. + * + * @return A number which acts as a unique identifier for the given + * suspendRedraw() call. This value must be passed as the parameter to the + * corresponding unsuspendRedraw() method call. + */ + unsigned long suspendRedraw(unsigned long max_wait_milliseconds); + + /** + * Cancels a specified suspendRedraw() by providing a unique suspend_handle_id. + * + * @param suspend_handle_id A number which acts as a unique identifier for the + * desired suspendRedraw() call. The number supplied must be a value returned + * from a previous call to suspendRedraw(). + */ + void unsuspendRedraw(unsigned long suspend_handle_id); + + /** + * Cancels all currently active suspendRedraw() method calls. This method is + * most useful at the very end of a set of SVG DOM calls to ensure that all + * pending suspendRedraw() method calls have been cancelled. + */ + void unsuspendRedrawAll(); + + /** + * In rendering environments supporting interactivity, forces the user agent to + * immediately redraw all regions of the viewport that require updating. + */ + void forceRedraw(); + + /** + * Suspends (i.e., pauses) all currently running animations that are defined + * within the SVG document fragment corresponding to this 'svg' element, + * causing the animation clock corresponding to this document fragment to stand + * still until it is paused. + */ + void pauseAnimations(); + + /** + * Unsuspends (i.e., pauses) currently running animations that are defined + * within the SVG document fragment, causing the animation clock to continue + * from the time it was suspended. + */ + void unpauseAnimations(); + + /** + * Returns true if this SVG Document fragment is in a paused state. + * + * @return Boolean indicating whether this SVG document fragment is in a paused + * state. + */ + bool animationsPaused(); + + /** + * Returns the current time in seconds relative to the start time for the + * current SVG document fragment. + * + * @return The current time in seconds. + */ + float getCurrentTime(); + + /** + * Adjusts the clock for this SVG document fragment, establishing a new current + * time. + * + * @param seconds The new current time in seconds relative to the start time + * for the current SVG document fragment. + */ + void setCurrentTime(float seconds); + + /** + * Returns the list of graphics elements whose rendered content intersects the + * supplied rectangle, honoring the 'pointer-events' property value on each + * candidate graphics element. + * + * @param rect The test rectangle. The values are in the initial coordinate + * system for the current 'svg' element. + * @param referenceElement If not null, then only return elements whose drawing + * order has them below the given reference element. + * + * @return A list of Elements whose content is intersects the supplied + * rectangle. + */ + DOM::NodeList getIntersectionList(const SVGRect &rect, const SVGElement + &referenceElement); + + /** + * Returns the list of graphics elements whose rendered content is entirely + * contained within the supplied rectangle, honoring the 'pointer-events' + * property value on each candidate graphics element. + * + * @param rect The test rectangle. The values are in the initial coordinate + * system for the current 'svg' element. + * @param referenceElement If not null, then only return elements whose drawing + * order has them below the given reference element. + * + * @return A list of Elements whose content is enclosed by the supplied + * rectangle. + */ + DOM::NodeList getEnclosureList(const SVGRect &rect, const SVGElement + &referenceElement); + + /** + * Returns true if the rendered content of the given element intersects the + * supplied rectangle, honoring the 'pointer-events' property value on each + * candidate graphics element. + * + * @param element The element on which to perform the given test. + * @param rect The test rectangle. The values are in the initial coordinate + * system for the current 'svg' element. + * + * @return True or false, depending on whether the given element intersects the + * supplied rectangle. + */ + bool checkIntersection(const SVGElement &element, const SVGRect &rect); + + /** + * Returns true if the rendered content of the given element is entirely + * contained within the supplied rectangle, honoring the 'pointer-events' + * property value on each candidate graphics element. + * + * @param element The element on which to perform the given test. + * @param rect The test rectangle. The values are in the initial coordinate + * system for the current 'svg' element. + * + * @return True or false, depending on whether the given element is enclosed by + * the supplied rectangle. + */ + bool checkEnclosure(const SVGElement &element, const SVGRect &rect); + + /** + * Unselects any selected objects, including any selections of text + * strings and type-in bars. + */ + void deSelectAll(); + + /** + * Creates an SVGNumber object outside of any document trees. + * The object is initialized to a value of zero. + * + * @return An SVGNumber object. + */ + SVGNumber createSVGNumber(); + + /** + * Creates an SVGLength object outside of any document trees. + * The object is initialized to a value of zero user units. + * + * @return An SVGLength object. + */ + SVGLength createSVGLength(); + + /** + * Creates an SVGAngle object outside of any document trees. + * The object is initialized to a value of zero degreesunitless). + * + * @return An SVGAngle object. + */ + SVGAngle createSVGAngle(); + + /** + * Creates an SVGPoint object outside of any document trees. + * The object is initialized to the point (0,0) in the user coordinate system. + * + * @return An SVGPoint object. + */ + SVGPoint createSVGPoint(); + + /** + * Creates an SVGMatrix object outside of any document trees. + * The object is initialized to a value of the identity matrix. + * + * @return An SVGMatrix object. + */ + SVGMatrix createSVGMatrix(); + + /** + * Creates an SVGRect object outside of any document trees. + * The object is initialized such that all values are set to 0 user units. + * + * @return An SVGRect object. + */ + SVGRect createSVGRect(); + + /** + * Creates an SVGTransform object outside of any document trees. + * The object is initialized to an identity matrix transform + * (SVG_TRANSFORM_MATRIX). + * + * @return An SVGTransform object. + */ + SVGTransform createSVGTransform(); + + /** + * Creates an SVGTransform object outside of any document trees. + * The object is initialized to the given matrix transform (i.e., + * SVG_TRANSFORM_MATRIX). + * + * @return An SVGTransform object. + */ + SVGTransform createSVGTransformFromMatrix(const SVGMatrix &matrix); + + /** + * Searches this SVG document fragment (i.e., the search is restricted to a + * subset of the document tree) for an Element whose id is given + * by elementId. If an Element is found, that Element + * is returned. If no such element exists, returns null. Behavior + * is not defined if more than one element has this id. + * + * @param elementId The unique id value for an element. + * + * @return The matching element. + */ + SVGElement getElementById(const DOM::DOMString &elementId); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGSVGElementImpl *handle() const { return impl; } + +private: + SVGSVGElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGScriptElement.cc b/ksvg/dom/SVGScriptElement.cc new file mode 100644 index 00000000..f599a273 --- /dev/null +++ b/ksvg/dom/SVGScriptElement.cc @@ -0,0 +1,81 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGScriptElement.h" +#include "SVGScriptElementImpl.h" + +using namespace KSVG; + +SVGScriptElement::SVGScriptElement() : SVGElement(), SVGURIReference(), SVGExternalResourcesRequired() +{ + impl = 0; +} + +SVGScriptElement::SVGScriptElement(const SVGScriptElement &other) : SVGElement(other), SVGURIReference(other), SVGExternalResourcesRequired(other), impl(0) +{ + (*this) = other; +} + +SVGScriptElement &SVGScriptElement::operator =(const SVGScriptElement &other) +{ + SVGElement::operator=(other); + SVGURIReference::operator=(other); + SVGExternalResourcesRequired::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGScriptElement::SVGScriptElement(SVGScriptElementImpl *other) : SVGElement(other), SVGURIReference(other), SVGExternalResourcesRequired(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGScriptElement::~SVGScriptElement() +{ + if(impl) + impl->deref(); +} + +void SVGScriptElement::setType(const DOM::DOMString &type) +{ + if(impl) + impl->setType(type); +} + +DOM::DOMString SVGScriptElement::type() const +{ + if(!impl) return DOM::DOMString(); + return impl->type(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGScriptElement.h b/ksvg/dom/SVGScriptElement.h new file mode 100644 index 00000000..aae1d79b --- /dev/null +++ b/ksvg/dom/SVGScriptElement.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGScriptElement_H +#define SVGScriptElement_H + +#include +#include "SVGElement.h" +#include "SVGURIReference.h" +#include "SVGExternalResourcesRequired.h" + +namespace KSVG +{ + +class SVGScriptElementImpl; +class SVGScriptElement : public SVGElement, + public SVGURIReference, + public SVGExternalResourcesRequired +{ +public: + SVGScriptElement(); + SVGScriptElement(const SVGScriptElement &other); + SVGScriptElement &operator=(const SVGScriptElement &other); + SVGScriptElement(SVGScriptElementImpl *other); + virtual ~SVGScriptElement(); + + void setType(const DOM::DOMString &type); + DOM::DOMString type() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGScriptElementImpl *handle() const { return impl; } + +private: + SVGScriptElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGSetElement.cc b/ksvg/dom/SVGSetElement.cc new file mode 100644 index 00000000..7a47c993 --- /dev/null +++ b/ksvg/dom/SVGSetElement.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGSetElement.h" +#include "SVGSetElementImpl.h" + +using namespace KSVG; + +SVGSetElement::SVGSetElement() : SVGAnimationElement() +{ + impl = 0; +} + +SVGSetElement::SVGSetElement(const SVGSetElement &other) : SVGAnimationElement(other), impl(0) +{ + (*this) = other; +} + +SVGSetElement &SVGSetElement::operator =(const SVGSetElement &other) +{ + SVGAnimationElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGSetElement::SVGSetElement(SVGSetElementImpl *other) : SVGAnimationElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGSetElement::~SVGSetElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGSetElement.h b/ksvg/dom/SVGSetElement.h new file mode 100644 index 00000000..f65a8704 --- /dev/null +++ b/ksvg/dom/SVGSetElement.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGSetElement_H +#define SVGSetElement_H + +#include "SVGAnimationElement.h" + +namespace KSVG +{ + +class SVGSetElementImpl; +class SVGSetElement : public SVGAnimationElement +{ +public: + SVGSetElement(); + SVGSetElement(const SVGSetElement &other); + SVGSetElement &operator=(const SVGSetElement &other); + SVGSetElement(SVGSetElementImpl *other); + virtual ~SVGSetElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGSetElementImpl *handle() const { return impl; } + +private: + SVGSetElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGStopElement.cc b/ksvg/dom/SVGStopElement.cc new file mode 100644 index 00000000..a9db9a56 --- /dev/null +++ b/ksvg/dom/SVGStopElement.cc @@ -0,0 +1,75 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGStopElement.h" +#include "SVGStopElementImpl.h" +#include "SVGAnimatedNumber.h" + +using namespace KSVG; + +SVGStopElement::SVGStopElement() : SVGElement(), SVGStylable() +{ + impl = 0; +} + +SVGStopElement::SVGStopElement(const SVGStopElement &other) : SVGElement(other), SVGStylable(other), impl(0) +{ + (*this) = other; +} + +SVGStopElement &SVGStopElement::operator =(const SVGStopElement &other) +{ + SVGElement::operator=(other); + SVGStylable::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGStopElement::SVGStopElement(SVGStopElementImpl *other) : SVGElement(other), SVGStylable(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGStopElement::~SVGStopElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedNumber SVGStopElement::offset() const +{ + if(!impl) return SVGAnimatedNumber(0); + return SVGAnimatedNumber(impl->offset()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGStopElement.h b/ksvg/dom/SVGStopElement.h new file mode 100644 index 00000000..3002e0cf --- /dev/null +++ b/ksvg/dom/SVGStopElement.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 file includes excerpts from the Scalable Vector Graphics + (SVG) 1.0 Specification (Proposed Recommendation) + http://www.w3.org/TR/SVG + + Copyright 2001 World Wide Web Consortium, (Massachusetts + Institute of Technology, Institut National de Recherche en + Informatique et en Automatique, Keio University). + All Rights Reserved. +*/ + +#ifndef SVGStopElement_H +#define SVGStopElement_H + +#include "SVGElement.h" +#include "SVGStylable.h" + +namespace KSVG +{ + +class SVGAnimatedNumber; +class SVGStopElementImpl; + +/** + * The ramp of colors to use on a gradient is defined by the 'stop' elements that + * are child elements to either the 'linearGradient' element or the 'radialGradient' element. + */ +class SVGStopElement : public SVGElement, + public SVGStylable +{ +public: + SVGStopElement(); + SVGStopElement(const SVGStopElement &other); + SVGStopElement &operator=(const SVGStopElement &other); + SVGStopElement(SVGStopElementImpl *other); + virtual ~SVGStopElement(); + + /** + * The offset attribute is either a (usually ranging from 0 to 1) + * or a (usually ranging from 0% to 100%) which indicates where the gradient + * stop is placed. For linear gradients, the offset attribute represents a location along + * the gradient vector. For radial gradients, it represents a percentage distance from + * (fx,fy) to the edge of the outermost/largest circle. + * + * This attribute is animatable. + * + * @return The offset where this gradient stop is placed. + */ + SVGAnimatedNumber offset() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGStopElementImpl *handle() const { return impl; } + +private: + SVGStopElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGStringList.cc b/ksvg/dom/SVGStringList.cc new file mode 100644 index 00000000..c7700e06 --- /dev/null +++ b/ksvg/dom/SVGStringList.cc @@ -0,0 +1,115 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include "SVGStringList.h" +#include "SVGStringListImpl.h" + +using namespace KSVG; + +SVGStringList::SVGStringList() +{ + impl = new SVGStringListImpl(); + impl->ref(); +} + +SVGStringList::SVGStringList(const SVGStringList &other) : impl(0) +{ + (*this) = other; +} + +SVGStringList &SVGStringList::operator=(const SVGStringList &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGStringList::SVGStringList(SVGStringListImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGStringList::~SVGStringList() +{ + if(impl) + impl->deref(); +} + +unsigned long SVGStringList::numberOfItems() const +{ + if(!impl) return 0; + return impl->numberOfItems(); +} + +void SVGStringList::clear() +{ + if(impl) + impl->clear(); +} + +DOM::DOMString *SVGStringList::initialize(DOM::DOMString *newItem) +{ + if(!impl) return new DOM::DOMString(); + return impl->initialize(new SharedString(newItem)); +} + +DOM::DOMString *SVGStringList::getItem(unsigned long index) +{ + if(!impl) return new DOM::DOMString(); + return impl->getItem(index); +} + +DOM::DOMString *SVGStringList::insertItemBefore(DOM::DOMString *newItem, unsigned long index) +{ + if(!impl) return new DOM::DOMString(); + return impl->insertItemBefore(new SharedString(newItem), index); +} + +DOM::DOMString *SVGStringList::replaceItem(DOM::DOMString *newItem, unsigned long index) +{ + if(!impl) return new DOM::DOMString(); + return impl->replaceItem(new SharedString(newItem), index); +} + +DOM::DOMString *SVGStringList::removeItem(unsigned long index) +{ + if(!impl) return new DOM::DOMString(); + return impl->removeItem(index); +} + +DOM::DOMString *SVGStringList::appendItem(DOM::DOMString *newItem) +{ + if(!impl) return new DOM::DOMString(); + return impl->appendItem(new SharedString(newItem)); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGStringList.h b/ksvg/dom/SVGStringList.h new file mode 100644 index 00000000..477273a6 --- /dev/null +++ b/ksvg/dom/SVGStringList.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGStringList_H +#define SVGStringList_H + +#include + +namespace KSVG +{ + +class SVGStringListImpl; +class SVGStringList +{ +public: + SVGStringList(); + SVGStringList(const SVGStringList &); + SVGStringList &operator=(const SVGStringList &); + SVGStringList(SVGStringListImpl *); + ~SVGStringList(); + + unsigned long numberOfItems() const; + void clear(); + + DOM::DOMString *initialize(DOM::DOMString *newItem); + DOM::DOMString *getItem(unsigned long index); + DOM::DOMString *insertItemBefore(DOM::DOMString *newItem, unsigned long index); + DOM::DOMString *replaceItem(DOM::DOMString *newItem, unsigned long index); + DOM::DOMString *removeItem(unsigned long index); + DOM::DOMString *appendItem(DOM::DOMString *newItem); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGStringListImpl *handle() const { return impl; } + +private: + SVGStringListImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGStylable.cc b/ksvg/dom/SVGStylable.cc new file mode 100644 index 00000000..14136d7d --- /dev/null +++ b/ksvg/dom/SVGStylable.cc @@ -0,0 +1,76 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGStylable.h" +#include "SVGStylableImpl.h" +#include + +using namespace KSVG; + +// This class can't be constructed seperately. +SVGStylable::SVGStylable() +{ + impl = 0; +} + +SVGStylable::SVGStylable(const SVGStylable &other) : impl(0) +{ + (*this) = other; +} + +SVGStylable &SVGStylable::operator=(const SVGStylable &other) +{ + if(impl == other.impl) + return *this; + + impl = other.impl; + + return *this; +} + +SVGStylable::SVGStylable(SVGStylableImpl *other) +{ + impl = other; +} + +SVGStylable::~SVGStylable() +{ + // We are not allowed to delete 'impl' as it's not refcounted. + // delete impl; +} + +/* +SVGAnimatedString SVGStylable::className() const +{ + return impl->className(); +} + +css::CSSStyleDeclaration SVGStylable::style() const +{ + return impl->style(); +} + +css::CSSValue SVGStylable::getPresentationAttribute(const DOMString &name) +{ + return impl->getPresentationAttribute(name); +} +*/ + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGStylable.h b/ksvg/dom/SVGStylable.h new file mode 100644 index 00000000..2fb3cf11 --- /dev/null +++ b/ksvg/dom/SVGStylable.h @@ -0,0 +1,56 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGStylable_H +#define SVGStylable_H + +namespace KSVG +{ + +class SVGStylableImpl; +class SVGStylable +{ +public: + SVGStylable(const SVGStylable &other); + SVGStylable &operator=(const SVGStylable &other); + SVGStylable(SVGStylableImpl *other); + ~SVGStylable(); + + // TODO : stylesheet support + //SVGAnimatedString className() const; + //css::CSSStyleDeclaration style() const; + //css::CSSValue getPresentationAttribute(const DOMString &name); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGStylableImpl *handle() const { return impl; } + +protected: + SVGStylable(); + +private: + SVGStylableImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet + diff --git a/ksvg/dom/SVGStyleElement.cc b/ksvg/dom/SVGStyleElement.cc new file mode 100644 index 00000000..8cf02024 --- /dev/null +++ b/ksvg/dom/SVGStyleElement.cc @@ -0,0 +1,115 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGStyleElement.h" +#include "SVGStyleElementImpl.h" + +using namespace KSVG; + +SVGStyleElement::SVGStyleElement() : SVGElement() +{ + impl = 0; +} + +SVGStyleElement::SVGStyleElement(const SVGStyleElement &other) : SVGElement(other), impl(0) +{ + (*this) = other; +} + +SVGStyleElement &SVGStyleElement::operator =(const SVGStyleElement &other) +{ + SVGElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGStyleElement::SVGStyleElement(SVGStyleElementImpl *other) : SVGElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGStyleElement::~SVGStyleElement() +{ + if(impl) + impl->deref(); +} + +void SVGStyleElement::setXmlspace(const DOM::DOMString &xmlspace) +{ + if(impl) + impl->setXmlspace(xmlspace); +} + +DOM::DOMString SVGStyleElement::xmlspace() const +{ + if(!impl) return DOM::DOMString(); + return impl->xmlspace(); +} + +void SVGStyleElement::setType(const DOM::DOMString &type) +{ + if(impl) + impl->setType(type); +} + +DOM::DOMString SVGStyleElement::type() const +{ + if(!impl) return DOM::DOMString(); + return impl->type(); +} + +void SVGStyleElement::setMedia(const DOM::DOMString &media) +{ + if(impl) + impl->setMedia(media); +} + +DOM::DOMString SVGStyleElement::media() const +{ + if(!impl) return DOM::DOMString(); + return impl->media(); +} + +void SVGStyleElement::setTitle(const DOM::DOMString &title) +{ + if(impl) + impl->setTitle(title); +} + +DOM::DOMString SVGStyleElement::title() const +{ + if(!impl) return DOM::DOMString(); + return impl->title(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGStyleElement.h b/ksvg/dom/SVGStyleElement.h new file mode 100644 index 00000000..2a1c63b8 --- /dev/null +++ b/ksvg/dom/SVGStyleElement.h @@ -0,0 +1,63 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGStyleElement_H +#define SVGStyleElement_H + +#include +#include "SVGElement.h" + +namespace KSVG +{ + +class SVGStyleElementImpl; +class SVGStyleElement : public SVGElement +{ +public: + SVGStyleElement(); + SVGStyleElement(const SVGStyleElement &other); + SVGStyleElement &operator=(const SVGStyleElement &other); + SVGStyleElement(SVGStyleElementImpl *other); + virtual ~SVGStyleElement(); + + void setXmlspace(const DOM::DOMString &xmlspace); + DOM::DOMString xmlspace() const; + + void setType(const DOM::DOMString &type); + DOM::DOMString type() const; + + void setMedia(const DOM::DOMString &media); + DOM::DOMString media() const; + + void setTitle(const DOM::DOMString &title); + DOM::DOMString title() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGStyleElementImpl *handle() const { return impl; } + +private: + SVGStyleElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGSwitchElement.cc b/ksvg/dom/SVGSwitchElement.cc new file mode 100644 index 00000000..2c4a8701 --- /dev/null +++ b/ksvg/dom/SVGSwitchElement.cc @@ -0,0 +1,72 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGSwitchElement.h" +#include "SVGSwitchElementImpl.h" + +using namespace KSVG; + +SVGSwitchElement::SVGSwitchElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable() +{ + impl = 0; +} + +SVGSwitchElement::SVGSwitchElement(const SVGSwitchElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), impl(0) +{ + (*this) = other; +} + +SVGSwitchElement &SVGSwitchElement::operator =(const SVGSwitchElement &other) +{ + SVGElement::operator=(other); + SVGTests::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + SVGTransformable::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGSwitchElement::SVGSwitchElement(SVGSwitchElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGSwitchElement::~SVGSwitchElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGSwitchElement.h b/ksvg/dom/SVGSwitchElement.h new file mode 100644 index 00000000..a4f8819d --- /dev/null +++ b/ksvg/dom/SVGSwitchElement.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGSwitchElement_H +#define SVGSwitchElement_H + +#include "SVGElement.h" +#include "SVGTests.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGTransformable.h" + +namespace KSVG +{ + +class SVGSwitchElementImpl; +class SVGSwitchElement : public SVGElement, + public SVGTests, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGTransformable +{ +public: + SVGSwitchElement(); + SVGSwitchElement(const SVGSwitchElement &other); + SVGSwitchElement &operator=(const SVGSwitchElement &other); + SVGSwitchElement(SVGSwitchElementImpl *other); + virtual ~SVGSwitchElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGSwitchElementImpl *handle() const { return impl; } + +private: + SVGSwitchElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGSymbolElement.cc b/ksvg/dom/SVGSymbolElement.cc new file mode 100644 index 00000000..d83947a5 --- /dev/null +++ b/ksvg/dom/SVGSymbolElement.cc @@ -0,0 +1,71 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGSymbolElement.h" +#include "SVGSymbolElementImpl.h" + +using namespace KSVG; + +SVGSymbolElement::SVGSymbolElement() : SVGElement(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGFitToViewBox() +{ + impl = 0; +} + +SVGSymbolElement::SVGSymbolElement(const SVGSymbolElement &other) : SVGElement(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGFitToViewBox(other), impl(0) +{ + (*this) = other; +} + +SVGSymbolElement &SVGSymbolElement::operator =(const SVGSymbolElement &other) +{ + SVGElement::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + SVGFitToViewBox::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGSymbolElement::SVGSymbolElement(SVGSymbolElementImpl *other) : SVGElement(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGFitToViewBox(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGSymbolElement::~SVGSymbolElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGSymbolElement.h b/ksvg/dom/SVGSymbolElement.h new file mode 100644 index 00000000..8d02987e --- /dev/null +++ b/ksvg/dom/SVGSymbolElement.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGSymbolElement_H +#define SVGSymbolElement_H + +#include "SVGElement.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGFitToViewBox.h" + +namespace KSVG +{ + +class SVGSymbolElementImpl; +class SVGSymbolElement : public SVGElement, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGFitToViewBox +{ +public: + SVGSymbolElement(); + SVGSymbolElement(const SVGSymbolElement &other); + SVGSymbolElement &operator=(const SVGSymbolElement &other); + SVGSymbolElement(SVGSymbolElementImpl *other); + virtual ~SVGSymbolElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGSymbolElementImpl *handle() const { return impl; } + +private: + SVGSymbolElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGTRefElement.cc b/ksvg/dom/SVGTRefElement.cc new file mode 100644 index 00000000..4faa18ec --- /dev/null +++ b/ksvg/dom/SVGTRefElement.cc @@ -0,0 +1,68 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGTRefElement.h" +#include "SVGTRefElementImpl.h" + +using namespace KSVG; + +SVGTRefElement::SVGTRefElement() : SVGTextPositioningElement(), SVGURIReference() +{ + impl = 0; +} + +SVGTRefElement::SVGTRefElement(const SVGTRefElement &other) : SVGTextPositioningElement(other), SVGURIReference(other), impl(0) +{ + (*this) = other; +} + +SVGTRefElement &SVGTRefElement::operator =(const SVGTRefElement &other) +{ + SVGTextPositioningElement::operator=(other); + SVGURIReference::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGTRefElement::SVGTRefElement(SVGTRefElementImpl *other) : SVGTextPositioningElement(other), SVGURIReference(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGTRefElement::~SVGTRefElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGTRefElement.h b/ksvg/dom/SVGTRefElement.h new file mode 100644 index 00000000..5585f1d7 --- /dev/null +++ b/ksvg/dom/SVGTRefElement.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTRefElement_H +#define SVGTRefElement_H + +#include "SVGTextPositioningElement.h" +#include "SVGURIReference.h" + +namespace KSVG +{ + +class SVGTRefElementImpl; +class SVGTRefElement : public SVGTextPositioningElement, + public SVGURIReference +{ +public: + SVGTRefElement(); + SVGTRefElement(const SVGTRefElement &other); + SVGTRefElement &operator=(const SVGTRefElement &other); + SVGTRefElement(SVGTRefElementImpl *other); + virtual ~SVGTRefElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGTRefElementImpl *handle() const { return impl; } + +private: + SVGTRefElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGTSpanElement.cc b/ksvg/dom/SVGTSpanElement.cc new file mode 100644 index 00000000..fc43309c --- /dev/null +++ b/ksvg/dom/SVGTSpanElement.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGTSpanElement.h" +#include "SVGTSpanElementImpl.h" + +using namespace KSVG; + +SVGTSpanElement::SVGTSpanElement() : SVGTextPositioningElement() +{ + impl = 0; +} + +SVGTSpanElement::SVGTSpanElement(const SVGTSpanElement &other) : SVGTextPositioningElement(other), impl(0) +{ + (*this) = other; +} + +SVGTSpanElement &SVGTSpanElement::operator =(const SVGTSpanElement &other) +{ + SVGTextPositioningElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGTSpanElement::SVGTSpanElement(SVGTSpanElementImpl *other) : SVGTextPositioningElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGTSpanElement::~SVGTSpanElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGTSpanElement.h b/ksvg/dom/SVGTSpanElement.h new file mode 100644 index 00000000..8fac655b --- /dev/null +++ b/ksvg/dom/SVGTSpanElement.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 file includes excerpts from the Scalable Vector Graphics + (SVG) 1.0 Specification (Proposed Recommendation) + http://www.w3.org/TR/SVG + + Copyright 2001 World Wide Web Consortium, (Massachusetts + Institute of Technology, Institut National de Recherche en + Informatique et en Automatique, Keio University). + All Rights Reserved. +*/ + +#ifndef SVGTSpanElement_H +#define SVGTSpanElement_H + +#include "SVGTextPositioningElement.h" + +namespace KSVG +{ + +class SVGTSpanElementImpl; + +/** + * Within a text element, text and font properties and the current + * text position can be adjusted with absolute or relative coordinate values by + * including a tspan element. + * + * For more information : + * + * 10.5 the 'tspan' element + */ +class SVGTSpanElement : public SVGTextPositioningElement +{ +public: + SVGTSpanElement(); + SVGTSpanElement(const SVGTSpanElement &other); + SVGTSpanElement &operator=(const SVGTSpanElement &other); + SVGTSpanElement(SVGTSpanElementImpl *other); + virtual ~SVGTSpanElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGTSpanElementImpl *handle() const { return impl; } + +private: + SVGTSpanElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGTests.cc b/ksvg/dom/SVGTests.cc new file mode 100644 index 00000000..9c3063b1 --- /dev/null +++ b/ksvg/dom/SVGTests.cc @@ -0,0 +1,83 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGTests.h" +#include "SVGTestsImpl.h" +#include "SVGStringList.h" + +using namespace KSVG; + +// This class can't be constructed seperately. +SVGTests::SVGTests() +{ + impl = 0; +} + +SVGTests::SVGTests(const SVGTests &other) : impl(0) +{ + (*this) = other; +} + +SVGTests &SVGTests::operator=(const SVGTests &other) +{ + if(impl == other.impl) + return *this; + + impl = other.impl; + + return *this; +} + +SVGTests::SVGTests(SVGTestsImpl *other) +{ + impl = other; +} + +SVGTests::~SVGTests() +{ + // We are not allowed to delete 'impl' as it's not refcounted. + // delete impl; +} + +SVGStringList SVGTests::requiredFeatures() const +{ + if(!impl) return SVGStringList(0); + return SVGStringList(impl->requiredFeatures()); +} + +SVGStringList SVGTests::requiredExtensions() const +{ + if(!impl) return SVGStringList(0); + return SVGStringList(impl->requiredExtensions()); +} + +SVGStringList SVGTests::systemLanguage() const +{ + if(!impl) return SVGStringList(0); + return SVGStringList(impl->systemLanguage()); +} + +bool SVGTests::hasExtension(const DOM::DOMString &extension) +{ + if(!impl) return false; + return impl->hasExtension(extension); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGTests.h b/ksvg/dom/SVGTests.h new file mode 100644 index 00000000..729b0efc --- /dev/null +++ b/ksvg/dom/SVGTests.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTests_H +#define SVGTests_H + +#include + +namespace KSVG +{ + +class SVGStringList; +class SVGTestsImpl; +class SVGTests +{ +public: + SVGTests(const SVGTests &other); + SVGTests &operator=(const SVGTests &other); + SVGTests(SVGTestsImpl *other); + ~SVGTests(); + + SVGStringList requiredFeatures() const; + SVGStringList requiredExtensions() const; + SVGStringList systemLanguage() const; + + bool hasExtension(const DOM::DOMString &extension); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGTestsImpl *handle() const { return impl; } + +protected: + SVGTests(); + +private: + SVGTestsImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGTextContentElement.cc b/ksvg/dom/SVGTextContentElement.cc new file mode 100644 index 00000000..f40d23b6 --- /dev/null +++ b/ksvg/dom/SVGTextContentElement.cc @@ -0,0 +1,120 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGTextContentElement.h" +#include "SVGTextContentElementImpl.h" +#include "SVGAnimatedEnumeration.h" +#include "SVGAnimatedLength.h" + +using namespace KSVG; + +SVGTextContentElement::SVGTextContentElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable() +{ + impl = new SVGTextContentElementImpl(0); +} + +SVGTextContentElement::SVGTextContentElement(const SVGTextContentElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other) +{ + impl = other.impl; +} + +SVGTextContentElement &SVGTextContentElement::operator=(const SVGTextContentElement &other) +{ + SVGElement::operator=(other); + SVGTests::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + + if(impl == other.impl) + return *this; + + delete impl; + impl = other.impl; + + return *this; +} + +SVGTextContentElement::SVGTextContentElement(SVGTextContentElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other) +{ + impl = other; +} + +SVGTextContentElement::~SVGTextContentElement() +{ +} + + +SVGAnimatedLength SVGTextContentElement::textLength() const +{ + return impl->textLength(); +} + +SVGAnimatedEnumeration SVGTextContentElement::lengthAdjust() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->lengthAdjust()); +} + +long SVGTextContentElement::getNumberOfChars() +{ + return impl->getNumberOfChars(); +} + +float SVGTextContentElement::getComputedTextLength() +{ + return impl->getComputedTextLength(); +} +/* +float SVGTextContentElement::getSubStringLength(const unsigned long &charnum, const unsigned long &nchars) +{ + return impl->getSubStringLength(charnum, nchars); +} + +SVGPoint SVGTextContentElement::getStartPositionOfChar(const unsigned long &charnum) +{ + return impl->getStartPositionOfChar(charnum); +} + +SVGPoint SVGTextContentElement::getEndPositionOfChar(const unsigned long &charnum) +{ + return impl->getEndPositionOfChar(charnum); +} + +SVGRect SVGTextContentElement::getExtentOfChar(const unsigned long &charnum) +{ + return impl->getExtentOfChar(charnum); +} + +float SVGTextContentElement::getRotationOfChar(const unsigned long &charnum) +{ + return impl->getRotationOfChar(charnum); +} + +long SVGTextContentElement::getCharNumAtPosition(const SVGPoint &point) +{ + return impl->getCharNumAtPosition(point); +} + +void SVGTextContentElement::selectSubString(const unsigned long &charnum, const unsigned long &nchars) +{ + return impl->selectSubString(charnum, nchars); +} +*/ diff --git a/ksvg/dom/SVGTextContentElement.h b/ksvg/dom/SVGTextContentElement.h new file mode 100644 index 00000000..2f943c06 --- /dev/null +++ b/ksvg/dom/SVGTextContentElement.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTextContentElement_H +#define SVGTextContentElement_H + +#include "SVGElement.h" +#include "SVGTests.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" + +namespace KSVG +{ + +enum +{ + LENGTHADJUST_UNKNOWN = 0, + LENGTHADJUST_SPACING = 1, + LENGTHADJUST_SPACINGANDGLYPHS = 2 +}; + +class SVGAnimatedLength; +class SVGAnimatedEnumeration; +class SVGTextContentElementImpl; +class SVGTextContentElement : public SVGElement, + public SVGTests, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable +{ +public: + SVGTextContentElement(const SVGTextContentElement &); + SVGTextContentElement &operator=(const SVGTextContentElement &other); + SVGTextContentElement(SVGTextContentElementImpl *); + ~SVGTextContentElement(); + + SVGAnimatedLength textLength() const; + SVGAnimatedEnumeration lengthAdjust() const; + long getNumberOfChars(); + float getComputedTextLength(); +// float getSubStringLength(const unsigned long &charnum, const unsigned long &nchars); +// SVGPoint getStartPositionOfChar(const unsigned long &charnum); +// SVGPoint getEndPositionOfChar(const unsigned long &charnum); +// SVGRect getExtentOfChar(const unsigned long &charnum); +// float getRotationOfChar(const unsigned long &charnum); +// long getCharNumAtPosition(const SVGPoint &point); +// void selectSubString(const unsigned long &charnum, const unsigned long &nchars); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGTextContentElementImpl *handle() const { return impl; } + +protected: + SVGTextContentElement(); + +private: + SVGTextContentElementImpl *impl; +}; + +} + +#endif diff --git a/ksvg/dom/SVGTextElement.cc b/ksvg/dom/SVGTextElement.cc new file mode 100644 index 00000000..b80a148a --- /dev/null +++ b/ksvg/dom/SVGTextElement.cc @@ -0,0 +1,68 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include "SVGTextElement.h" +#include "SVGTextElementImpl.h" +#include "SVGAnimatedLength.h" + +using namespace KSVG; + +SVGTextElement::SVGTextElement() : SVGTextPositioningElement(), SVGTransformable() +{ + impl = 0; +} + +SVGTextElement::SVGTextElement(const SVGTextElement &other) : SVGTextPositioningElement(other), SVGTransformable(other) +{ + (*this) = other; +} + +SVGTextElement &SVGTextElement::operator =(const SVGTextElement &other) +{ + SVGTextPositioningElement::operator=(other); + SVGTransformable::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGTextElement::SVGTextElement(SVGTextElementImpl *other) : SVGTextPositioningElement(other), SVGTransformable(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGTextElement::~SVGTextElement() +{ + if(impl) + impl->deref(); +} diff --git a/ksvg/dom/SVGTextElement.h b/ksvg/dom/SVGTextElement.h new file mode 100644 index 00000000..0bf459fe --- /dev/null +++ b/ksvg/dom/SVGTextElement.h @@ -0,0 +1,115 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 file includes excerpts from the Scalable Vector Graphics + (SVG) 1.0 Specification (Proposed Recommendation) + http://www.w3.org/TR/SVG + + Copyright 2001 World Wide Web Consortium, (Massachusetts + Institute of Technology, Institut National de Recherche en + Informatique et en Automatique, Keio University). + All Rights Reserved. + + $Id$ + */ + + +#ifndef SVGTextElement_H +#define SVGTextElement_H + +#include "SVGTextPositioningElement.h" +#include "SVGTransformable.h" + +namespace KSVG +{ + +class SVGAnimatedLength; +class SVGTextElementImpl; + +/** + * @short The text element defines a graphics element + * consisting of text. + * + * The XML character data within the text element, along + * with relevant attributes and properties and character-to-glyph + * mapping tables within the font itself, define the glyphs to be + * rendered. (See Characters + * and their corresponding glyphs .) The attributes and properties on the + * 'text' element indicate such things as the writing direction, font + * specification and painting attributes which describe how exactly to render + * the characters. Since text elements are rendered using the + * same rendering methods as other graphics elements, all of the same + * coordinate system transformations, painting, clipping and masking + * features that apply to shapes such as paths and rectangles also + * apply to text elements. + * + * It is possible to apply a gradient, pattern, clipping path, mask or + * filter to text.When one of these facilities is applied to text and + * keyword objectBoundingBox is used to specify a graphical effect + * relative to the "object bounding box", then the object bounding box + * units are computed relative to the entire 'text' element in all + * cases, even when different effects are applied to different 'tspan' + * elements within the same 'text' element. + * + + * The text element renders its first glyph (after bidirectionality reordering) at the initial current text + * position, which is established by the x and + * y attributes on the text element (with + * possible adjustments due to the value of the @ref text-anchor + * property, the presence of a @ref textPath element containing the + * first character, and/or an x, y, + * dx or dy attributes on a @ref tspan, @ref + * tref or @ref altGlyph element which contains the first character). + * After the glyph(s) corresponding to the given character is(are) + * rendered, the current text position is updated for the next + * character. In the simplest case, the new current text position is + * the previous current text position plus the glyphs' advance value + * (horizontal or vertical). + * + * @see SVGShape + * @see SVGTextPositioningElement + * + * For more info look here : 10.4 The + * 'text' element. + */ +class SVGTextElement : public SVGTextPositioningElement, + public SVGTransformable +{ +public: + SVGTextElement(); + SVGTextElement(const SVGTextElement &); + SVGTextElement &operator=(const SVGTextElement &other); + SVGTextElement(SVGTextElementImpl *); + ~SVGTextElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGTextElementImpl *handle() const { return impl; } + +private: + SVGTextElementImpl *impl; +}; + +} + +#endif diff --git a/ksvg/dom/SVGTextPathElement.cc b/ksvg/dom/SVGTextPathElement.cc new file mode 100644 index 00000000..1cb6b833 --- /dev/null +++ b/ksvg/dom/SVGTextPathElement.cc @@ -0,0 +1,89 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGTextPathElement.h" +#include "SVGTextPathElementImpl.h" +#include "SVGAnimatedEnumeration.h" +#include "SVGAnimatedLength.h" + +using namespace KSVG; + +SVGTextPathElement::SVGTextPathElement() : SVGTextContentElement(), SVGURIReference() +{ + impl = new SVGTextPathElementImpl(0); + impl->ref(); +} + +SVGTextPathElement::SVGTextPathElement(const SVGTextPathElement &other) : SVGTextContentElement(other), SVGURIReference(other), impl(0) +{ + (*this) = other; +} + +SVGTextPathElement &SVGTextPathElement::operator =(const SVGTextPathElement &other) +{ + SVGTextContentElement::operator=(other); + SVGURIReference::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGTextPathElement::SVGTextPathElement(SVGTextPathElementImpl *other) : SVGTextContentElement(other), SVGURIReference(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGTextPathElement::~SVGTextPathElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedLength SVGTextPathElement::startOffset() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->startOffset()); +} + +SVGAnimatedEnumeration SVGTextPathElement::method() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->method()); +} + +SVGAnimatedEnumeration SVGTextPathElement::spacing() const +{ + if(!impl) return SVGAnimatedEnumeration(0); + return SVGAnimatedEnumeration(impl->spacing()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGTextPathElement.h b/ksvg/dom/SVGTextPathElement.h new file mode 100644 index 00000000..69c7fe79 --- /dev/null +++ b/ksvg/dom/SVGTextPathElement.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTextPathElement_H +#define SVGTextPathElement_H + +#include "SVGTextContentElement.h" +#include "SVGURIReference.h" + +namespace KSVG +{ + +enum +{ + TEXTPATH_METHODTYPE_UNKNOWN = 0, + TEXTPATH_METHODTYPE_ALIGN = 1, + TEXTPATH_METHODTYPE_STRETCH = 2 +}; + +enum +{ + TEXTPATH_SPACINGTYPE_UNKNOWN = 0, + TEXTPATH_SPACINGTYPE_AUTO = 1, + TEXTPATH_SPACINGTYPE_EXACT = 2 +}; + +class SVGTextPathElementImpl; +class SVGTextPathElement : public SVGTextContentElement, + public SVGURIReference +{ +public: + SVGTextPathElement(); + SVGTextPathElement(const SVGTextPathElement &other); + SVGTextPathElement &operator=(const SVGTextPathElement &other); + SVGTextPathElement(SVGTextPathElementImpl *other); + virtual ~SVGTextPathElement(); + + SVGAnimatedLength startOffset() const; + SVGAnimatedEnumeration method() const; + SVGAnimatedEnumeration spacing() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGTextPathElementImpl *handle() const { return impl; } + +private: + SVGTextPathElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGTextPositioningElement.cc b/ksvg/dom/SVGTextPositioningElement.cc new file mode 100644 index 00000000..6ce7d346 --- /dev/null +++ b/ksvg/dom/SVGTextPositioningElement.cc @@ -0,0 +1,85 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include "SVGTextPositioningElement.h" +#include "SVGTextPositioningElementImpl.h" +#include "SVGAnimatedNumber.h" +#include "SVGAnimatedNumberList.h" +#include "SVGAnimatedLength.h" +#include "SVGAnimatedLengthList.h" + +using namespace KSVG; + +SVGTextPositioningElement::SVGTextPositioningElement() : SVGTextContentElement() +{ + impl = new SVGTextPositioningElementImpl(0); +} + +SVGTextPositioningElement::SVGTextPositioningElement(const SVGTextPositioningElement &other) : SVGTextContentElement(other) +{ + impl = other.impl; +} + +SVGTextPositioningElement &SVGTextPositioningElement::operator=(const SVGTextPositioningElement &other) +{ + SVGTextContentElement::operator=(other); + + if(impl == other.impl) + return *this; + + delete impl; + impl = other.impl; + + return *this; +} +SVGTextPositioningElement::SVGTextPositioningElement(SVGTextPositioningElementImpl *other) : SVGTextContentElement(other) +{ + impl = other; +} + +SVGTextPositioningElement::~SVGTextPositioningElement() +{ +} + +SVGAnimatedLengthList SVGTextPositioningElement::x() +{ + return SVGAnimatedLengthList(impl->x()); +} + +SVGAnimatedLengthList SVGTextPositioningElement::y() +{ + return SVGAnimatedLengthList(impl->y()); +} + +SVGAnimatedLengthList SVGTextPositioningElement::dx() +{ + return SVGAnimatedLengthList(impl->dx()); +} + +SVGAnimatedLengthList SVGTextPositioningElement::dy() +{ + return SVGAnimatedLengthList(impl->dy()); +} + +SVGAnimatedNumberList SVGTextPositioningElement::rotate() +{ + return SVGAnimatedNumberList(impl->rotate()); +} diff --git a/ksvg/dom/SVGTextPositioningElement.h b/ksvg/dom/SVGTextPositioningElement.h new file mode 100644 index 00000000..f02950ca --- /dev/null +++ b/ksvg/dom/SVGTextPositioningElement.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTextPositioningElement_H +#define SVGTextPositioningElement_H + +#include "SVGTextContentElement.h" + +namespace KSVG +{ + +class SVGAnimatedLength; +class SVGAnimatedLengthList; +class SVGAnimatedNumber; +class SVGAnimatedNumberList; +class SVGTextPositioningElementImpl; +class SVGTextPositioningElement : public SVGTextContentElement +{ +public: + SVGTextPositioningElement(const SVGTextPositioningElement &); + SVGTextPositioningElement &operator=(const SVGTextPositioningElement &other); + SVGTextPositioningElement(SVGTextPositioningElementImpl *); + ~SVGTextPositioningElement(); + + SVGAnimatedLengthList x(); + SVGAnimatedLengthList y(); + SVGAnimatedLengthList dx(); + SVGAnimatedLengthList dy(); + SVGAnimatedNumberList rotate(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGTextPositioningElementImpl *handle() const { return impl; } + +protected: + SVGTextPositioningElement(); + +private: + SVGTextPositioningElementImpl *impl; +}; + +} + +#endif diff --git a/ksvg/dom/SVGTitleElement.cc b/ksvg/dom/SVGTitleElement.cc new file mode 100644 index 00000000..f319c126 --- /dev/null +++ b/ksvg/dom/SVGTitleElement.cc @@ -0,0 +1,69 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGTitleElement.h" +#include "SVGTitleElementImpl.h" + +using namespace KSVG; + +SVGTitleElement::SVGTitleElement() : SVGElement(), SVGLangSpace(), SVGStylable() +{ + impl = 0; +} + +SVGTitleElement::SVGTitleElement(const SVGTitleElement &other) : SVGElement(other), SVGLangSpace(other), SVGStylable(other), impl(0) +{ + (*this) = other; +} + +SVGTitleElement &SVGTitleElement::operator =(const SVGTitleElement &other) +{ + SVGElement::operator=(other); + SVGLangSpace::operator=(other); + SVGStylable::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGTitleElement::SVGTitleElement(SVGTitleElementImpl *other) : SVGElement(other), SVGLangSpace(other), SVGStylable(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGTitleElement::~SVGTitleElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGTitleElement.h b/ksvg/dom/SVGTitleElement.h new file mode 100644 index 00000000..95f26272 --- /dev/null +++ b/ksvg/dom/SVGTitleElement.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTitleElement_H +#define SVGTitleElement_H + +#include "SVGElement.h" +#include "SVGLangSpace.h" +#include "SVGStylable.h" + +namespace KSVG +{ + +class SVGTitleElementImpl; +class SVGTitleElement : public SVGElement, + public SVGLangSpace, + public SVGStylable +{ +public: + SVGTitleElement(); + SVGTitleElement(const SVGTitleElement &other); + SVGTitleElement &operator=(const SVGTitleElement &other); + SVGTitleElement(SVGTitleElementImpl *other); + virtual ~SVGTitleElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGTitleElementImpl *handle() const { return impl; } + +private: + SVGTitleElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGTransform.cc b/ksvg/dom/SVGTransform.cc new file mode 100644 index 00000000..df660678 --- /dev/null +++ b/ksvg/dom/SVGTransform.cc @@ -0,0 +1,119 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGTransformImpl.h" +#include "SVGTransform.h" +#include "SVGMatrix.h" + +using namespace KSVG; + +SVGTransform::SVGTransform() +{ + impl = new SVGTransformImpl(); + impl->ref(); +} + +SVGTransform::SVGTransform(const SVGTransform &other) : impl(0) +{ + (*this) = other; +} + +SVGTransform &SVGTransform::operator=(const SVGTransform &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGTransform::SVGTransform(SVGTransformImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGTransform::~SVGTransform() +{ +} + +unsigned short SVGTransform::type() const +{ + if(!impl) return SVG_TRANSFORM_UNKNOWN; + return impl->type(); +} + +SVGMatrix SVGTransform::matrix() const +{ + if(!impl) return SVGMatrix(0); + return SVGMatrix(impl->matrix()); +} + +double SVGTransform::angle() const +{ + if(!impl) return -1; + return impl->angle(); +} + +void SVGTransform::setMatrix(SVGMatrix matrix) +{ + if(impl) + impl->setMatrix(matrix.handle()); +} + +void SVGTransform::setTranslate(double tx, double ty) +{ + if(impl) + impl->setTranslate(tx, ty); +} + +void SVGTransform::setScale(double sx, double sy) +{ + if(impl) + impl->setScale(sx, sy); +} + +void SVGTransform::setRotate(double angle, double cx, double cy) +{ + if(impl) + impl->setRotate(angle, cx, cy); +} + +void SVGTransform::setSkewX(double angle) +{ + if(impl) + impl->setSkewX(angle); +} + +void SVGTransform::setSkewY(double angle) +{ + if(impl) + impl->setSkewY(angle); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGTransform.h b/ksvg/dom/SVGTransform.h new file mode 100644 index 00000000..b7ca927f --- /dev/null +++ b/ksvg/dom/SVGTransform.h @@ -0,0 +1,71 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTransform_H +#define SVGTransform_H + +namespace KSVG +{ + +enum +{ + SVG_TRANSFORM_UNKNOWN = 0, + SVG_TRANSFORM_MATRIX = 1, + SVG_TRANSFORM_TRANSLATE = 2, + SVG_TRANSFORM_SCALE = 3, + SVG_TRANSFORM_ROTATE = 4, + SVG_TRANSFORM_SKEWX = 5, + SVG_TRANSFORM_SKEWY = 6 +}; + +class SVGMatrix; +class SVGTransformImpl; +class SVGTransform +{ +public: + SVGTransform(); + SVGTransform(const SVGTransform &); + SVGTransform &operator=(const SVGTransform &); + SVGTransform(SVGTransformImpl *); + ~SVGTransform(); + + unsigned short type() const; + SVGMatrix matrix() const; + double angle() const; + + void setMatrix(SVGMatrix); + void setTranslate(double, double); + void setScale(double, double); + void setRotate(double, double, double); + void setSkewX(double); + void setSkewY(double); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGTransformImpl *handle() const { return impl; } + +private: + SVGTransformImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGTransformList.cc b/ksvg/dom/SVGTransformList.cc new file mode 100644 index 00000000..541db510 --- /dev/null +++ b/ksvg/dom/SVGTransformList.cc @@ -0,0 +1,129 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGTransformList.h" +#include "SVGTransformListImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGMatrix.h" +#include "SVGTransform.h" + +using namespace KSVG; + +SVGTransformList::SVGTransformList() +{ + impl = new SVGTransformListImpl(); + impl->ref(); +} + +SVGTransformList::SVGTransformList(const SVGTransformList &other) +{ + (*this) = other; +} + +SVGTransformList &SVGTransformList::operator=(const SVGTransformList &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGTransformList::SVGTransformList(SVGTransformListImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGTransformList::~SVGTransformList() +{ + if(impl) + impl->deref(); +} + +unsigned long SVGTransformList::numberOfItems() const +{ + if(!impl) return 0; + return impl->numberOfItems(); +} + +void SVGTransformList::clear() +{ + if(impl) + impl->clear(); +} + +SVGTransform *SVGTransformList::initialize(SVGTransform *newItem) +{ + if(!impl) return new SVGTransform(0); + return new SVGTransform(impl->initialize(newItem->handle())); +} + +SVGTransform *SVGTransformList::getItem(unsigned long index) +{ + if(!impl) return new SVGTransform(0); + return new SVGTransform(impl->getItem(index)); +} + +SVGTransform *SVGTransformList::insertItemBefore(SVGTransform *newItem, unsigned long index) +{ + if(!impl) return new SVGTransform(0); + return new SVGTransform(impl->insertItemBefore(newItem->handle(), index)); +} + +SVGTransform *SVGTransformList::replaceItem(SVGTransform *newItem, unsigned long index) +{ + if(!impl) return new SVGTransform(0); + return new SVGTransform(impl->replaceItem(newItem->handle(), index)); +} + +SVGTransform *SVGTransformList::removeItem(unsigned long index) +{ + if(!impl) return new SVGTransform(0); + return new SVGTransform(impl->removeItem(index)); +} + +SVGTransform *SVGTransformList::appendItem(SVGTransform *newItem) +{ + if(!impl) return new SVGTransform(0); + return new SVGTransform(impl->appendItem(newItem->handle())); +} + +SVGTransform *SVGTransformList::createSVGTransformFromMatrix(SVGMatrix &matrix) +{ + if(!impl) return new SVGTransform(0); + return new SVGTransform(SVGSVGElementImpl::createSVGTransformFromMatrix(matrix.handle())); +} + +SVGTransform *SVGTransformList::consolidate() +{ + if(!impl || impl->numberOfItems()==0) return 0; + return new SVGTransform(impl->consolidate()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGTransformList.h b/ksvg/dom/SVGTransformList.h new file mode 100644 index 00000000..8d448718 --- /dev/null +++ b/ksvg/dom/SVGTransformList.h @@ -0,0 +1,63 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTransformList_H +#define SVGTransformList_H + +namespace KSVG +{ + +class SVGMatrix; +class SVGTransform; +class SVGTransformListImpl; +class SVGTransformList +{ +public: + SVGTransformList(); + SVGTransformList(const SVGTransformList &); + SVGTransformList &operator=(const SVGTransformList &); + SVGTransformList(SVGTransformListImpl *); + ~SVGTransformList(); + + unsigned long numberOfItems() const; + void clear(); + + SVGTransform *initialize(SVGTransform *newItem); + SVGTransform *getItem(unsigned long index); + SVGTransform *insertItemBefore(SVGTransform *newItem, unsigned long index); + SVGTransform *replaceItem(SVGTransform *newItem, unsigned long index); + SVGTransform *removeItem(unsigned long index); + SVGTransform *appendItem(SVGTransform *newItem); + + SVGTransform *createSVGTransformFromMatrix(SVGMatrix &matrix); + SVGTransform *consolidate(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGTransformListImpl *handle() const { return impl; } + +private: + SVGTransformListImpl *impl; +}; + +} + +#endif +// vim:ts=4:noet + diff --git a/ksvg/dom/SVGTransformable.cc b/ksvg/dom/SVGTransformable.cc new file mode 100644 index 00000000..64530d39 --- /dev/null +++ b/ksvg/dom/SVGTransformable.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGTransformable.h" +#include "SVGTransformableImpl.h" +#include "SVGAnimatedTransformList.h" + +using namespace KSVG; + +// This class can't be constructed seperately. +SVGTransformable::SVGTransformable() : SVGLocatable() +{ + impl = 0; +} + +SVGTransformable::SVGTransformable(const SVGTransformable &other) : SVGLocatable(other) +{ + (*this) = other; +} + +SVGTransformable &SVGTransformable::operator=(const SVGTransformable &other) +{ + SVGLocatable::operator=(other); + + if(impl == other.impl) + return *this; + + impl = other.impl; + + return *this; +} + +SVGTransformable::SVGTransformable(SVGTransformableImpl *other) : SVGLocatable(other) +{ + impl = other; +} + +SVGTransformable::~SVGTransformable() +{ + // We are not allowed to delete 'impl' as it's not refcounted. + // delete impl; +} + +SVGAnimatedTransformList SVGTransformable::transform() +{ + if(!impl) return SVGAnimatedTransformList(0); + return SVGAnimatedTransformList(impl->transform()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGTransformable.h b/ksvg/dom/SVGTransformable.h new file mode 100644 index 00000000..54bf0a40 --- /dev/null +++ b/ksvg/dom/SVGTransformable.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTransformable_H +#define SVGTransformable_H + +#include "SVGLocatable.h" + +namespace KSVG +{ + +class SVGAnimatedTransformList; +class SVGTransformableImpl; +class SVGTransformable : public SVGLocatable +{ +public: + SVGTransformable(const SVGTransformable &other); + SVGTransformable &operator=(const SVGTransformable &other); + SVGTransformable(SVGTransformableImpl *other); + virtual ~SVGTransformable(); + + SVGAnimatedTransformList transform(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGTransformableImpl *handle() const { return impl; } + +protected: + SVGTransformable(); + +private: + SVGTransformableImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGURIReference.cc b/ksvg/dom/SVGURIReference.cc new file mode 100644 index 00000000..e872e9d6 --- /dev/null +++ b/ksvg/dom/SVGURIReference.cc @@ -0,0 +1,63 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGURIReference.h" +#include "SVGURIReferenceImpl.h" +#include "SVGAnimatedString.h" + +using namespace KSVG; + +SVGURIReference::SVGURIReference() +{ + impl = new SVGURIReferenceImpl(); +} + +SVGURIReference::SVGURIReference(const SVGURIReference &other) +{ + impl = other.impl; +} + +SVGURIReference &SVGURIReference::operator=(const SVGURIReference &other) +{ + if(impl == other.impl) + return *this; + + delete impl; + impl = other.impl; + + return *this; +} + +SVGURIReference::SVGURIReference(SVGURIReferenceImpl *other) +{ + impl = other; +} + +SVGURIReference::~SVGURIReference() +{ +} + +SVGAnimatedString SVGURIReference::href() const +{ + if(!impl) return SVGAnimatedString(0); + return SVGAnimatedString(impl->href()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGURIReference.h b/ksvg/dom/SVGURIReference.h new file mode 100644 index 00000000..571cd2b2 --- /dev/null +++ b/ksvg/dom/SVGURIReference.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGURIReference_H +#define SVGURIReference_H + +namespace KSVG +{ + +class SVGAnimatedString; +class SVGURIReferenceImpl; +class SVGURIReference +{ +public: + SVGURIReference(const SVGURIReference &other); + SVGURIReference &operator=(const SVGURIReference &other); + SVGURIReference(SVGURIReferenceImpl *other); + virtual ~SVGURIReference(); + + SVGAnimatedString href() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGURIReferenceImpl *handle() const { return impl; } + +protected: + SVGURIReference(); + +private: + SVGURIReferenceImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGUnitTypes.h b/ksvg/dom/SVGUnitTypes.h new file mode 100644 index 00000000..76079af2 --- /dev/null +++ b/ksvg/dom/SVGUnitTypes.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGUnitTypes_H +#define SVGUnitTypes_H + +namespace KSVG +{ + +struct SVGUnitTypes +{ + enum + { + SVG_UNIT_TYPE_UNKNOWN = 0, + SVG_UNIT_TYPE_USERSPACEONUSE = 1, + SVG_UNIT_TYPE_OBJECTBOUNDINGBOX = 2 + }; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGUseElement.cc b/ksvg/dom/SVGUseElement.cc new file mode 100644 index 00000000..8cd8ef26 --- /dev/null +++ b/ksvg/dom/SVGUseElement.cc @@ -0,0 +1,111 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGUseElement.h" +#include "SVGUseElementImpl.h" +#include "SVGElementInstance.h" +#include "SVGAnimatedLength.h" + +using namespace KSVG; + +SVGUseElement::SVGUseElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable(), SVGURIReference() +{ + impl = 0; +} + +SVGUseElement::SVGUseElement(const SVGUseElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGURIReference(other), impl(0) +{ + (*this) = other; +} + +SVGUseElement &SVGUseElement::operator =(const SVGUseElement &other) +{ + SVGElement::operator=(other); + SVGTests::operator=(other); + SVGLangSpace::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGStylable::operator=(other); + SVGTransformable::operator=(other); + SVGURIReference::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGUseElement::SVGUseElement(SVGUseElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGURIReference(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGUseElement::~SVGUseElement() +{ + if(impl) + impl->deref(); +} + +SVGAnimatedLength SVGUseElement::x() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->x()); +} + +SVGAnimatedLength SVGUseElement::y() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->y()); +} + +SVGAnimatedLength SVGUseElement::width() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->width()); +} + +SVGAnimatedLength SVGUseElement::height() const +{ + if(!impl) return SVGAnimatedLength(0); + return SVGAnimatedLength(impl->height()); +} + +SVGElementInstance SVGUseElement::instanceRoot() const +{ + if(!impl) return SVGElementInstance(0); + return impl->instanceRoot(); +} + +SVGElementInstance SVGUseElement::animatedInstanceRoot() const +{ + if(!impl) return SVGElementInstance(0); + return impl->animatedInstanceRoot(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGUseElement.h b/ksvg/dom/SVGUseElement.h new file mode 100644 index 00000000..fb494abb --- /dev/null +++ b/ksvg/dom/SVGUseElement.h @@ -0,0 +1,71 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGUseElement_H +#define SVGUseElement_H + +#include "SVGElement.h" +#include "SVGTests.h" +#include "SVGLangSpace.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGStylable.h" +#include "SVGTransformable.h" +#include "SVGURIReference.h" + +namespace KSVG +{ + +class SVGAnimatedLength; +class SVGElementInstance; +class SVGUseElementImpl; +class SVGUseElement : public SVGElement, + public SVGTests, + public SVGLangSpace, + public SVGExternalResourcesRequired, + public SVGStylable, + public SVGTransformable, + public SVGURIReference +{ +public: + SVGUseElement(); + SVGUseElement(const SVGUseElement &other); + SVGUseElement &operator=(const SVGUseElement &other); + SVGUseElement(SVGUseElementImpl *other); + virtual ~SVGUseElement(); + + SVGAnimatedLength x() const; + SVGAnimatedLength y() const; + SVGAnimatedLength width() const; + SVGAnimatedLength height() const; + SVGElementInstance instanceRoot() const; + SVGElementInstance animatedInstanceRoot() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGUseElementImpl *handle() const { return impl; } + +private: + SVGUseElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGVKernElement.cc b/ksvg/dom/SVGVKernElement.cc new file mode 100644 index 00000000..ad6dbee5 --- /dev/null +++ b/ksvg/dom/SVGVKernElement.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGVKernElement.h" +#include "SVGVKernElementImpl.h" + +using namespace KSVG; + +SVGVKernElement::SVGVKernElement() : SVGElement() +{ + impl = 0; +} + +SVGVKernElement::SVGVKernElement(const SVGVKernElement &other) : SVGElement(other), impl(0) +{ + (*this) = other; +} + +SVGVKernElement &SVGVKernElement::operator =(const SVGVKernElement &other) +{ + SVGElement::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGVKernElement::SVGVKernElement(SVGVKernElementImpl *other) : SVGElement(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGVKernElement::~SVGVKernElement() +{ + if(impl) + impl->deref(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGVKernElement.h b/ksvg/dom/SVGVKernElement.h new file mode 100644 index 00000000..6649ab1a --- /dev/null +++ b/ksvg/dom/SVGVKernElement.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGVKernElement_H +#define SVGVKernElement_H + +#include "SVGElement.h" + +namespace KSVG +{ + +class SVGVKernElementImpl; +class SVGVKernElement : public SVGElement +{ +public: + SVGVKernElement(); + SVGVKernElement(const SVGVKernElement &other); + SVGVKernElement &operator=(const SVGVKernElement &other); + SVGVKernElement(SVGVKernElementImpl *other); + virtual ~SVGVKernElement(); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGVKernElementImpl *handle() const { return impl; } + +private: + SVGVKernElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGViewElement.cc b/ksvg/dom/SVGViewElement.cc new file mode 100644 index 00000000..040d6966 --- /dev/null +++ b/ksvg/dom/SVGViewElement.cc @@ -0,0 +1,77 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGViewElement.h" +#include "SVGViewElementImpl.h" +#include "SVGStringList.h" + +using namespace KSVG; + +SVGViewElement::SVGViewElement() : SVGElement(), SVGExternalResourcesRequired(), SVGFitToViewBox(), SVGZoomAndPan() +{ + impl = 0; +} + +SVGViewElement::SVGViewElement(const SVGViewElement &other) : SVGElement(other), SVGExternalResourcesRequired(other), SVGFitToViewBox(other), SVGZoomAndPan(other), impl(0) +{ + (*this) = other; +} + +SVGViewElement &SVGViewElement::operator =(const SVGViewElement &other) +{ + SVGElement::operator=(other); + SVGExternalResourcesRequired::operator=(other); + SVGFitToViewBox::operator=(other); + SVGZoomAndPan::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGViewElement::SVGViewElement(SVGViewElementImpl *other) : SVGElement(other), SVGExternalResourcesRequired(other), SVGFitToViewBox(other), SVGZoomAndPan(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGViewElement::~SVGViewElement() +{ + if(impl) + impl->deref(); +} + +SVGStringList SVGViewElement::viewTarget() const +{ + if(!impl) return SVGStringList(0); + return SVGStringList(impl->viewTarget()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGViewElement.h b/ksvg/dom/SVGViewElement.h new file mode 100644 index 00000000..fccedbc8 --- /dev/null +++ b/ksvg/dom/SVGViewElement.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGViewElement_H +#define SVGViewElement_H + +#include "SVGElement.h" +#include "SVGExternalResourcesRequired.h" +#include "SVGFitToViewBox.h" +#include "SVGZoomAndPan.h" + +namespace KSVG +{ + +class SVGStringList; +class SVGViewElementImpl; +class SVGViewElement : public SVGElement, + public SVGExternalResourcesRequired, + public SVGFitToViewBox, + public SVGZoomAndPan +{ +public: + SVGViewElement(); + SVGViewElement(const SVGViewElement &other); + SVGViewElement &operator=(const SVGViewElement &other); + SVGViewElement(SVGViewElementImpl *other); + virtual ~SVGViewElement(); + + SVGStringList viewTarget() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGViewElementImpl *handle() const { return impl; } + +private: + SVGViewElementImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGViewSpec.cc b/ksvg/dom/SVGViewSpec.cc new file mode 100644 index 00000000..a01f7b86 --- /dev/null +++ b/ksvg/dom/SVGViewSpec.cc @@ -0,0 +1,107 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGViewSpec.h" +#include "SVGViewSpecImpl.h" +#include "SVGElement.h" +#include "SVGTransformList.h" + +using namespace KSVG; + +SVGViewSpec::SVGViewSpec() : SVGZoomAndPan(), SVGFitToViewBox() +{ + impl = new SVGViewSpecImpl(); + impl->ref(); +} + +SVGViewSpec::SVGViewSpec(const SVGViewSpec &other) : SVGZoomAndPan(other), SVGFitToViewBox(other), impl(0) +{ + (*this) = other; +} + +SVGViewSpec &SVGViewSpec::operator =(const SVGViewSpec &other) +{ + SVGZoomAndPan::operator=(other); + SVGFitToViewBox::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGViewSpec::SVGViewSpec(SVGViewSpecImpl *other) : SVGZoomAndPan(other), SVGFitToViewBox(other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGViewSpec::~SVGViewSpec() +{ + if(impl) + impl->deref(); +} + +SVGTransformList SVGViewSpec::transform() const +{ + if(!impl) return SVGTransformList(0); + return SVGTransformList(impl->transform()); +} + +SVGElement SVGViewSpec::viewTarget() const +{ + if(!impl) return SVGElement(0); + return SVGElement(impl->viewTarget()); +} + +DOM::DOMString SVGViewSpec::viewBoxString() const +{ + if(!impl) return DOM::DOMString(); + return impl->viewBoxString(); +} + +DOM::DOMString SVGViewSpec::preserveAspectRatioString() const +{ + if(!impl) return DOM::DOMString(); + return impl->preserveAspectRatioString(); +} + +DOM::DOMString SVGViewSpec::transformString() const +{ + if(!impl) return DOM::DOMString(); + return impl->transformString(); +} + +DOM::DOMString SVGViewSpec::viewTargetString() const +{ + if(!impl) return DOM::DOMString(); + return impl->viewTargetString(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGViewSpec.h b/ksvg/dom/SVGViewSpec.h new file mode 100644 index 00000000..c1c7ef8e --- /dev/null +++ b/ksvg/dom/SVGViewSpec.h @@ -0,0 +1,63 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGViewSpec_H +#define SVGViewSpec_H + +#include "SVGZoomAndPan.h" +#include "SVGFitToViewBox.h" +#include + +namespace KSVG +{ + +class SVGTransformList; +class SVGElement; +class SVGViewSpecImpl; +class SVGViewSpec : public SVGZoomAndPan, + public SVGFitToViewBox +{ +public: + SVGViewSpec(); + SVGViewSpec(const SVGViewSpec &other); + SVGViewSpec &operator=(const SVGViewSpec &other); + SVGViewSpec(SVGViewSpecImpl *other); + virtual ~SVGViewSpec(); + + SVGTransformList transform() const; + SVGElement viewTarget() const; + + DOM::DOMString viewBoxString() const; + DOM::DOMString preserveAspectRatioString() const; + DOM::DOMString transformString() const; + DOM::DOMString viewTargetString() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGViewSpecImpl *handle() const { return impl; } + +private: + SVGViewSpecImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGWindow.cc b/ksvg/dom/SVGWindow.cc new file mode 100644 index 00000000..9f0fedaf --- /dev/null +++ b/ksvg/dom/SVGWindow.cc @@ -0,0 +1,175 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGWindow.h" +#include "SVGWindowImpl.h" +#include "SVGDocument.h" + +using namespace KSVG; + +SVGWindow::SVGWindow() +{ + impl = new SVGWindowImpl(); + impl->ref(); +} + +SVGWindow::SVGWindow(const SVGWindow &other) : impl(0) +{ + (*this) = other; +} + +SVGWindow &SVGWindow::operator =(const SVGWindow &other) +{ + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGWindow::SVGWindow(SVGWindowImpl *other) +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGWindow::~SVGWindow() +{ + if(impl) + impl->deref(); +} + +/*StyleSheet SVGWindow::defaultStyleSheet() const +{ + if(!impl) return ; // FIXME + return impl->defaultStyleSheet(); +}*/ + +SVGDocument SVGWindow::document() const +{ + if(!impl) return SVGDocument(0); // FIXME + return impl->document(); +} + +DOM::Event SVGWindow::evt() const +{ + if(!impl) return DOM::Event(); // FIXME + return impl->evt(); +} + +long SVGWindow::innerHeight() const +{ + if(!impl) return 0; // FIXME + return impl->innerHeight(); +} + +long SVGWindow::innerWidth() const +{ + if(!impl) return 0; // FIXME + return impl->innerWidth(); +} + +void SVGWindow::setSrc(const DOM::DOMString &src) +{ + if(impl) + impl->setSrc(src); +} + +DOM::DOMString SVGWindow::src() const +{ + if(!impl) return DOM::DOMString(); // FIXME + return impl->src(); +} + +void SVGWindow::clearInterval(long interval) +{ + if(impl) + impl->clearInterval(interval); +} + +void SVGWindow::clearTimeout(long timeout) +{ + if(impl) + impl->clearTimeout(timeout); +} + +void SVGWindow::getURL(const DOM::DOMString &uri, const DOM::EventListener &callback) +{ + if(impl) + impl->getURL(uri, callback); +} + +/*DocumentFragment SVGWindow::parseXML(const DOM::DOMString &source, const Document &document) +{ + if(!impl) return ; // FIXME + return impl->parseXML(source, document); +}*/ + +void SVGWindow::postURL(const DOM::DOMString &uri, const DOM::DOMString &data, const DOM::EventListener &callback, const DOM::DOMString &mimeType, const DOM::DOMString &contentEncoding) +{ + if(impl) + impl->postURL(uri, data, callback, mimeType, contentEncoding); +} + +DOM::DOMString SVGWindow::printNode(const DOM::Node &node) +{ + if(!impl) return DOM::DOMString(); // FIXME + return impl->printNode(node); +} + +long SVGWindow::setInterval(const DOM::DOMString &code, const long &delay) +{ + if(!impl) return 0; // FIXME + return impl->setInterval(code, delay); +} + +long SVGWindow::setTimeout(const DOM::DOMString &code, const long &delay) +{ + if(!impl) return 0; // FIXME + return impl->setTimeout(code, delay); +} + +void SVGWindow::alert(const DOM::DOMString &message) +{ + if(impl) + impl->alert(message); +} + +bool SVGWindow::confirm(const DOM::DOMString &message) +{ + if(!impl) return false; // FIXME + return impl->confirm(message); +} + +DOM::DOMString SVGWindow::prompt(const DOM::DOMString &message, const DOM::DOMString &_default) +{ + if(!impl) return DOM::DOMString(); // FIXME + return impl->prompt(message, _default); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGWindow.h b/ksvg/dom/SVGWindow.h new file mode 100644 index 00000000..2389286f --- /dev/null +++ b/ksvg/dom/SVGWindow.h @@ -0,0 +1,127 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGWindow_H +#define SVGWindow_H + +#include +#include +#include + +namespace KSVG +{ + +class SVGDocument; +class SVGWindowImpl; + +class SVGWindow +{ +public: + SVGWindow(); + SVGWindow(const SVGWindow &other); + SVGWindow &operator=(const SVGWindow &other); + SVGWindow(SVGWindowImpl *other); + virtual ~SVGWindow(); + + //StyleSheet defaultStyleSheet() const; + SVGDocument document() const; + DOM::Event evt() const; + + /** + * @return Viewport height in pixels. + */ + long innerHeight() const; + + /** + * @return Viewport width in pixels. + */ + long innerWidth() const; + + void setSrc(const DOM::DOMString &src); + + /** + * @return The URI of the current document. + */ + DOM::DOMString src() const; + + void clearInterval(long interval); + void clearTimeout(long timeout); + + /** + * Get data from the given URL using the HTTP GET method. Notify the callback when done. + * + * @param uri The URI reference for the data to be loaded. + * @param callback The method to be invoked when the data is available. + */ + void getURL(const DOM::DOMString &uri, const DOM::EventListener &callback); + //DOM::DocumentFragment parseXML(const DOM::DOMString &source, const DOM::Document &document); + void postURL(const DOM::DOMString &uri, const DOM::DOMString &data, const DOM::EventListener &callback, const DOM::DOMString &mimeType, const DOM::DOMString &contentEncoding); + + /** + * Converts a Node into a DOMString. The string is an XML representation of the Node. + * + * @param node The Node to be converted. + * @return Converts a Node into a DOMString. The string is an XML representation of the Node. + */ + DOM::DOMString printNode(const DOM::Node &node); + long setInterval(const DOM::DOMString &code, const long &delay); + long setTimeout(const DOM::DOMString &code, const long &delay); + + /** + * Displays a modal synchronous message to the user if possible in the current user environment. + * Commonly, this message takes the form of a pop-up window with a single dispose button. + * + * @param message The message to be displayed. + */ + void alert(const DOM::DOMString &message); + + /** + * Displays a modal synchronous message to the user if possible in the current user environment. + * The user is able to accept or reject the message. Commonly, this message takes the form of + * a pop-up window with either a Yes/No or OK/Cancel button pair. + * + * @param message The message to be displayed. + * @return A boolean indicating the user's response. True for accept, False for reject. + */ + bool confirm(const DOM::DOMString &message); + + /** + * Displays a modal synchronous message to the user if possible in the current user environment. + * The user is able to enter a response to the message. Commonly, this message takes the form of + * a pop-up window with a single text entry field. + * + * @param message The message to be displayed. + * @param _default The default response to suggest to the user. This can be displayed in the text field and be modified by the user. + * @return A boolean indicating the user's response. True for accept, False for reject. + */ + DOM::DOMString prompt(const DOM::DOMString &message, const DOM::DOMString &_default); + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGWindowImpl *handle() const { return impl; } + +private: + SVGWindowImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGZoomAndPan.cc b/ksvg/dom/SVGZoomAndPan.cc new file mode 100644 index 00000000..a65284f1 --- /dev/null +++ b/ksvg/dom/SVGZoomAndPan.cc @@ -0,0 +1,70 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGZoomAndPan.h" +#include "SVGZoomAndPanImpl.h" + +using namespace KSVG; + +// This class can't be constructed seperately. +SVGZoomAndPan::SVGZoomAndPan() +{ + impl = 0; +} + +SVGZoomAndPan::SVGZoomAndPan(const SVGZoomAndPan &other) : impl(0) +{ + (*this) = other; +} + +SVGZoomAndPan &SVGZoomAndPan::operator=(const SVGZoomAndPan &other) +{ + if(impl == other.impl) + return *this; + + impl = other.impl; + + return *this; +} + +SVGZoomAndPan::SVGZoomAndPan(SVGZoomAndPanImpl *other) +{ + impl = other; +} + +SVGZoomAndPan::~SVGZoomAndPan() +{ + // We are not allowed to delete 'impl' as it's not refcounted. + // delete impl; +} + +void SVGZoomAndPan::setZoomAndPan(unsigned short zoomAndPan) +{ + if(impl) + impl->setZoomAndPan(zoomAndPan); +} + +unsigned short SVGZoomAndPan::zoomAndPan() const +{ + if(!impl) return SVG_ZOOMANDPAN_UNKNOWN; + return impl->zoomAndPan(); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGZoomAndPan.h b/ksvg/dom/SVGZoomAndPan.h new file mode 100644 index 00000000..0a1cdf19 --- /dev/null +++ b/ksvg/dom/SVGZoomAndPan.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGZoomAndPan_H +#define SVGZoomAndPan_H + +namespace KSVG +{ + +enum ZoomAndPan +{ + SVG_ZOOMANDPAN_UNKNOWN = 0, + SVG_ZOOMANDPAN_DISABLE = 1, + SVG_ZOOMANDPAN_MAGNIFY = 2 +}; + +class SVGZoomAndPanImpl; +class SVGZoomAndPan +{ +public: + SVGZoomAndPan(const SVGZoomAndPan &other); + SVGZoomAndPan &operator=(const SVGZoomAndPan &other); + SVGZoomAndPan(SVGZoomAndPanImpl *other); + virtual ~SVGZoomAndPan(); + + void setZoomAndPan(unsigned short zoomAndPan); + unsigned short zoomAndPan() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGZoomAndPanImpl *handle() const { return impl; } + +protected: + SVGZoomAndPan(); + +private: + SVGZoomAndPanImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGZoomEvent.cc b/ksvg/dom/SVGZoomEvent.cc new file mode 100644 index 00000000..bc73a438 --- /dev/null +++ b/ksvg/dom/SVGZoomEvent.cc @@ -0,0 +1,99 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGZoomEvent.h" +#include "SVGZoomEventImpl.h" +#include "SVGRect.h" +#include "SVGPoint.h" + +using namespace KSVG; + +SVGZoomEvent::SVGZoomEvent() : DOM::UIEvent() +{ + impl = 0; +} + +SVGZoomEvent::SVGZoomEvent(const SVGZoomEvent &other) : DOM::UIEvent(other), impl(0) +{ + (*this) = other; +} + +SVGZoomEvent &SVGZoomEvent::operator =(const SVGZoomEvent &other) +{ + DOM::UIEvent::operator=(other); + + if(impl == other.impl) + return *this; + + if(impl) + impl->deref(); + + impl = other.impl; + + if(impl) + impl->ref(); + + return *this; +} + +SVGZoomEvent::SVGZoomEvent(SVGZoomEventImpl *other) : DOM::UIEvent() +{ + impl = other; + if(impl) + impl->ref(); +} + +SVGZoomEvent::~SVGZoomEvent() +{ + if(impl) + impl->deref(); +} + +SVGRect SVGZoomEvent::zoomRectScreen() const +{ + if(!impl) return SVGRect(0); + return SVGRect(impl->zoomRectScreen()); +} + +float SVGZoomEvent::previousScale() const +{ + if(!impl) return -1; + return impl->previousScale(); +} + +SVGPoint SVGZoomEvent::previousTranslate() const +{ + if(!impl) return SVGPoint(0); + return SVGPoint(impl->previousTranslate()); +} + +float SVGZoomEvent::newScale() const +{ + if(!impl) return -1; + return impl->newScale(); +} + +SVGPoint SVGZoomEvent::newTranslate() const +{ + if(!impl) return SVGPoint(0); + return SVGPoint(impl->newTranslate()); +} + +// vim:ts=4:noet diff --git a/ksvg/dom/SVGZoomEvent.h b/ksvg/dom/SVGZoomEvent.h new file mode 100644 index 00000000..f759e9bd --- /dev/null +++ b/ksvg/dom/SVGZoomEvent.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGZoomEvent_H +#define SVGZoomEvent_H + +#include + +namespace KSVG +{ + +class SVGRect; +class SVGPoint; +class SVGZoomEventImpl; +class SVGZoomEvent : public DOM::UIEvent +{ +public: + SVGZoomEvent(); + SVGZoomEvent(const SVGZoomEvent &other); + SVGZoomEvent &operator=(const SVGZoomEvent &other); + SVGZoomEvent(SVGZoomEventImpl *other); + virtual ~SVGZoomEvent(); + + SVGRect zoomRectScreen() const; + float previousScale() const; + SVGPoint previousTranslate() const; + float newScale() const; + SVGPoint newTranslate() const; + + // Internal! - NOT PART OF THE SVG SPECIFICATION + SVGZoomEventImpl *handle() const { return impl; } + +private: + SVGZoomEventImpl *impl; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/ecma/Makefile.am b/ksvg/ecma/Makefile.am new file mode 100644 index 00000000..b3eea2b5 --- /dev/null +++ b/ksvg/ecma/Makefile.am @@ -0,0 +1,7 @@ +INCLUDES = $(FREETYPE_CFLAGS) -I$(top_srcdir)/ksvg/dom -I$(top_srcdir)/ksvg/impl -I$(top_srcdir)/ksvg/core -I$(top_srcdir)/ksvg/data -I$(top_srcdir)/ksvg/impl/libs/libtext2path/src $(all_includes) +METASOURCES = AUTO +KDE_CXXFLAGS = $(USE_EXCEPTIONS) + +noinst_LTLIBRARIES = libksvgecma.la + +libksvgecma_la_SOURCES = ksvg_scriptinterpreter.cpp ksvg_ecma.cpp ksvg_helper.cpp ksvg_ecmaeventlistener.cpp ksvg_window.cpp diff --git a/ksvg/ecma/ksvg_bridge.h b/ksvg/ecma/ksvg_bridge.h new file mode 100644 index 00000000..784dea15 --- /dev/null +++ b/ksvg/ecma/ksvg_bridge.h @@ -0,0 +1,103 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 KSVGBridge_H +#define KSVGBridge_H + +#include + +#include +#include +#include // for ExecState + +namespace KJS +{ + class Value; + class UString; + class ExecState; +} + +// Base class for all bridges +// The T class must provide prototype(exec), get and hasProperty +// and have a static s_classInfo object +template +class KSVGBridge : public KJS::ObjectImp +{ +public: + KSVGBridge(KJS::ExecState *exec, T *impl) : KJS::ObjectImp(impl->prototype(exec)), m_impl(impl) { } + + T *impl() const { return m_impl; } + + virtual KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const + { + kdDebug(26004) << "KSVGBridge::get(), " << propertyName.qstring() << " Name: " << classInfo()->className << " Object: " << m_impl << endl; + + // Look for standard properties (e.g. those in the hashtables) + KJS::Value val = m_impl->get(exec, propertyName, this); + + if(val.type() != KJS::UndefinedType) + return val; + + // Not found -> forward to ObjectImp. + val = KJS::ObjectImp::get(exec, propertyName); + if(val.type() == KJS::UndefinedType) + kdDebug(26004) << "WARNING: " << propertyName.qstring() << " not found in... Name: " << classInfo()->className << " Object: " << m_impl << " on line : " << exec->context().curStmtFirstLine() << endl; + return val; + } + + virtual bool hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const + { + kdDebug(26004) << "KSVGBridge::hasProperty(), " << propertyName.qstring() << " Name: " << classInfo()->className << " Object: " << m_impl << endl; + + if(m_impl->hasProperty(exec, propertyName)) + return true; + + return KJS::ObjectImp::hasProperty(exec, propertyName); + } + + virtual const KJS::ClassInfo *classInfo() const { return &T::s_classInfo; } + +protected: + T *m_impl; +}; + +// Base class for readwrite bridges +// T must also implement put (use KSVG_PUT in the header file) +template +class KSVGRWBridge : public KSVGBridge +{ +public: + KSVGRWBridge(KJS::ExecState *exec, T *impl) : KSVGBridge(exec, impl) { } + + virtual void put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value &value, int attr) + { +// if(!(attr & KJS::Internal)) +// kdDebug(26004) << "KSVGBridge::put(), " << propertyName.qstring() << " Name: " << classInfo()->className << " Object: " << m_impl << endl; + + // Try to see if we know this property (and need to take special action) + if(this->m_impl->put(exec, propertyName, value, attr)) + return; + + // We don't -> set property in ObjectImp. + KJS::ObjectImp::put(exec, propertyName, value, attr); + } +}; + +#endif diff --git a/ksvg/ecma/ksvg_cacheimpl.h b/ksvg/ecma/ksvg_cacheimpl.h new file mode 100644 index 00000000..1140f1b4 --- /dev/null +++ b/ksvg/ecma/ksvg_cacheimpl.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 KSVGCacheImpl_H +#define KSVGCacheImpl_H + +#include "ksvg_scriptinterpreter.h" + +// Lookup or create JS object around an existing "DOM Object" +template +inline KJS::Value cacheDOMObject(KJS::ExecState *exec, DOMObj *domObj) +{ + KJS::ObjectImp *ret; + if(!domObj) + return KJS::Null(); + + KSVGScriptInterpreter *interp = static_cast(exec->interpreter()); + if((ret = interp->getDOMObject(domObj))) + return KJS::Value(ret); + else + { + ret = new KJSDOMObj(exec, domObj); + interp->putDOMObject(domObj, ret); + return KJS::Value(ret); + } +} + +// Lookup or create singleton Impl object, and return a unique bridge object for it. +// (Very much like KJS::cacheGlobalObject, which is for a singleton ObjectImp) +// This one is mostly used for Constructor objects. +template +inline KJS::Object cacheGlobalBridge(KJS::ExecState *exec, const KJS::Identifier &propertyName) +{ + KJS::ValueImp *obj = static_cast(exec->interpreter()->globalObject().imp())->getDirect(propertyName); + if(obj) + return KJS::Object::dynamicCast(KJS::Value(obj)); + else + { + ClassCtor* ctor = new ClassCtor(exec); // create the ClassCtor instance + KJS::Object newObject(new KSVGBridge(exec, ctor)); // create the bridge around it + exec->interpreter()->globalObject().put(exec, propertyName, newObject, KJS::Internal); + return newObject; + } +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/ecma/ksvg_ecma.cpp b/ksvg/ecma/ksvg_ecma.cpp new file mode 100644 index 00000000..a2aed6ce --- /dev/null +++ b/ksvg/ecma/ksvg_ecma.cpp @@ -0,0 +1,336 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include + +#include + +#include "SVGEcma.h" + +#include "SVGDocumentImpl.h" + +#include "ksvg_ecma.h" +#include "ksvg_window.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_ecmaeventlistener.h" + +#include "KSVGLoader.h" + +using namespace KSVG; +using namespace KJS; + +class AsyncStatus : public ObjectImp +{ +public: + AsyncStatus() : ObjectImp() { } + + virtual bool implementsCall() const { return true; } + virtual Value call(ExecState *exec, Object &thisObj, const List &args); +}; + +Value AsyncStatus::call(ExecState *exec, Object &, const List &args) +{ + kdDebug(26004) << "[AsyncStatus] " << args[0].toString(exec).ascii() << endl; + + if(args[0].toString(exec) == "success") + return Number(1); + else + return Undefined(); +} + +KSVGEcma::KSVGEcma(SVGDocumentImpl *doc) : m_doc(doc) +{ + m_init = false; + m_hasListeners = false; + + m_window = 0; + m_interpreter = 0; + + m_ecmaEventListeners.setAutoDelete(true); +} + +KSVGEcma::~KSVGEcma() +{ + // We are 0 soon so event listeners may NOT call us + QPtrListIterator it(m_ecmaEventListeners); + for(; it.current(); ++it) + it.current()->forbidRemove(); + + if(m_interpreter) + delete m_interpreter; +} + +bool KSVGEcma::initialized() +{ + return m_init; +} + +void KSVGEcma::setup() +{ + if(m_init) + return; + + m_init = true; + + // Create handler for js calls + m_window = new KSVG::Window(m_doc); + Object globalObject(m_window); + + // Create code interpreter + m_interpreter = new KSVGScriptInterpreter(globalObject, m_doc); + + // Set object prototype for global object + m_window->setPrototype(m_interpreter->builtinObjectPrototype()); + + // Create bridge for document. Could be done on demand now, though + KSVGBridge *documentRequest = new KSVGBridge(m_interpreter->globalExec(), m_doc); + documentRequest->ref(); + + m_interpreter->putDOMObject(m_doc->handle(), documentRequest); +} + +Completion KSVGEcma::evaluate(const UString &code, const Value &thisV) +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "KSVGEcma::evaluate " << code.qstring() << endl; +#endif + + return m_interpreter->evaluate(code, thisV); +} + +Object KSVGEcma::globalObject() +{ + return m_interpreter->globalObject(); +} + +ExecState *KSVGEcma::globalExec() +{ + return m_interpreter->globalExec(); +} + +SVGEventListener *KSVGEcma::createEventListener(DOM::DOMString type) +{ + QPtrListIterator it(m_ecmaEventListeners); + + for(; it.current(); ++it) + { + if(it.current()->type() == type.string()) + return static_cast(it.current()); + } + + setup(); + + Object constr = m_interpreter->builtinFunction(); + + List args; + args.append(String("event")); + args.append(String(type.string())); + + Object obj = constr.construct(m_interpreter->globalExec(), args); + + // Note that the KSVGEcmaEventListener constructor adds itself to the m_ecmaEventListeners list + KSVGEcmaEventListener *event = new KSVGEcmaEventListener(obj, type.string(), this); + event->ref(); + + // addEventListener() is called by KSVGEcmaListeners ctor, so it's + // safe to check to count of the eventListeners list (Niko) + if(m_ecmaEventListeners.count() > 0) + m_hasListeners = true; + + return event; +} + +QString KSVGEcma::valueOfEventListener(SVGEventListener *listener) const +{ + KSVGEcmaEventListener *event = static_cast(listener); + if(!event) + return QString::null; + + return event->type(); +} + +void KSVGEcma::addEventListener(KSVGEcmaEventListener *listener) +{ + m_ecmaEventListeners.append(listener); +} + +void KSVGEcma::removeEventListener(KSVGEcmaEventListener *listener) +{ + m_ecmaEventListeners.take(m_ecmaEventListeners.find(listener)); + + if(m_ecmaEventListeners.count() == 0) + m_hasListeners = false; +} + +bool KSVGEcma::hasEventListeners() +{ + return m_hasListeners; +} + +void KSVGEcma::finishedWithEvent(SVGEventImpl *event) +{ + KSVGScriptInterpreter *interpreter = static_cast(globalExec()->interpreter()); + interpreter->removeDOMObject(event); +} + +Value KSVGEcma::getUrl(ExecState *exec, ::KURL url) +{ + Object *status = new Object(new AsyncStatus()); + + // FIXME: Security issue, allows local testing of getURL(), REMOVE BEFORE RELEASE! (Niko) + QString svgDocument = KSVGLoader::getUrl(url, true); + if(svgDocument.length() > 0) + { + status->put(exec, Identifier("success"), Boolean(true)); + status->put(exec, Identifier("content"), String(svgDocument)); + } + else + { + status->put(exec, Identifier("success"), Boolean(false)); + status->put(exec, Identifier("content"), String("")); + } + + return Value(*status); +} + +void KSVGEcma::postUrl(ExecState *exec, ::KURL url, const QString &data, const QString &mimeType, const QString &contentEncoding, Object &callBackFunction) +{ + Object *status = new Object(new AsyncStatus()); + status->put(exec, Identifier("content"), String("")); + status->put(exec, Identifier("success"), Boolean(false)); + + QByteArray byteArray; + QDataStream ds(byteArray, IO_WriteOnly); + ds << data; + + // Support gzip compression + if(contentEncoding == "gzip" || contentEncoding == "deflate") + byteArray = qCompress(byteArray); + + KSVGLoader *loader = new KSVGLoader(); + loader->postUrl(url, byteArray, mimeType, exec, callBackFunction, *status); + delete loader; +} + +// Helpers +Value KSVG::getDOMNode(ExecState *exec, DOM::Node n) +{ + ObjectImp *ret = 0; + if(n.isNull()) + return Null(); + + KSVGScriptInterpreter *interpreter = static_cast(exec->interpreter()); + + ObjectImp *request = interpreter->getDOMObject(n.handle()); + if(request) + return Value(request); + + SVGElementImpl *elem = 0; + + switch(n.nodeType()) + { + case DOM::Node::ELEMENT_NODE: + elem = interpreter->document()->getElementFromHandle(n.handle()); + if(!elem) + { + // Lookup different document, if possible + SVGDocumentImpl *different = interpreter->document()->getDocumentFromHandle(n.ownerDocument().handle()); + + if(!different) + return Null(); + + elem = different->getElementFromHandle(n.handle()); + + if(!elem) + return Null(); + } + + // The generated bridge() function does not ref the ret itself + ret = elem->bridge(exec); + ret->ref(); + break; + case DOM::Node::TEXT_NODE: + ret = new KSVGRWBridge(exec, new SVGDOMTextBridge(n)); + ret->ref(); + break; + default: + ret = new KSVGBridge(exec, new SVGDOMNodeBridge(n)); + ret->ref(); + break; + } + + interpreter->putDOMObject(n.handle(), ret); + + return Value(ret); +} + +Value KSVG::getDOMEvent(ExecState *exec, SVGEventImpl *e) +{ + return e->cache(exec); +} + +Value KSVG::getString(DOM::DOMString s) +{ + if(s.isNull()) + return Null(); + else + return String(s); +} + +DOM::Node KSVG::toNode(const Value &val) +{ + Object obj = Object::dynamicCast(val); + if(obj.isNull()) + return DOM::Node(); + + SVGDOMNodeBridge *bridge = toNodeBridge(static_cast(obj.imp())); + + if(bridge) + return bridge->impl(); + + return DOM::Node(); +} + +QVariant KSVG::valueToVariant(ExecState *exec, const Value &val) +{ + QVariant res; + + switch(val.type()) + { + case BooleanType: + res = QVariant(val.toBoolean(exec), 0); + break; + case NumberType: + res = QVariant(val.toNumber(exec)); + break; + case StringType: + res = QVariant(val.toString(exec).qstring()); + break; + default: + // everything else will be 'invalid' + break; + } + + return res; +} + +// vim:ts=4:noet diff --git a/ksvg/ecma/ksvg_ecma.h b/ksvg/ecma/ksvg_ecma.h new file mode 100644 index 00000000..7c236454 --- /dev/null +++ b/ksvg/ecma/ksvg_ecma.h @@ -0,0 +1,114 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 KSVGEcma_H +#define KSVGEcma_H + +#include + +#include "ksvg_bridge.h" + +namespace DOM +{ + class Node; + class DOMString; +} + +namespace KJS +{ + class Value; + class Object; + class UString; + class ExecState; + class Completion; +} + +namespace KSVG +{ + class Window; + class SVGEventImpl; + class SVGDocumentImpl; + class SVGEventListener; + class SVGDOMNodeBridge; +} + +class QVariant; + +class KSVGEcmaEventListener; +class KSVGScriptInterpreter; + +typedef KSVGBridge KSVGEcmaEvent; + +// Helpers +namespace KSVG +{ + KJS::Value getDOMNode(KJS::ExecState *, DOM::Node); + KJS::Value getDOMEvent(KJS::ExecState *, KSVG::SVGEventImpl *); + KJS::Value getString(DOM::DOMString); + + QVariant valueToVariant(KJS::ExecState *, const KJS::Value &); + + DOM::Node toNode(const KJS::Value &); + + // This one is part of generateddata.cpp + SVGDOMNodeBridge *toNodeBridge(const KJS::ObjectImp *); +} + +class KSVGEcma +{ +public: + KSVGEcma(KSVG::SVGDocumentImpl *doc); + ~KSVGEcma(); + + void setup(); + bool initialized(); + + KJS::Completion evaluate(const KJS::UString &code, const KJS::Value &thisV); + + KJS::Object globalObject(); + KJS::ExecState *globalExec(); + + KSVGScriptInterpreter *interpreter() { return m_interpreter; } + + KSVG::SVGEventListener *createEventListener(DOM::DOMString type); + QString valueOfEventListener(KSVG::SVGEventListener *listener) const; + void addEventListener(KSVGEcmaEventListener *listener); + void removeEventListener(KSVGEcmaEventListener *listener); + bool hasEventListeners(); + + void finishedWithEvent(KSVG::SVGEventImpl *event); + + KJS::Value getUrl(KJS::ExecState *exec, ::KURL url); + void postUrl(KJS::ExecState *exec, ::KURL url, const QString &data, const QString &mimeType, const QString &contentEncoding, KJS::Object &callBackFunction); + +private: + bool m_init, m_hasListeners; + + KSVG::SVGDocumentImpl *m_doc; + + KSVG::Window *m_window; + KSVGScriptInterpreter *m_interpreter; + QPtrList m_ecmaEventListeners; + +}; + +#endif + +// vim:ts=4:noet diff --git a/ksvg/ecma/ksvg_ecmaeventlistener.cpp b/ksvg/ecma/ksvg_ecmaeventlistener.cpp new file mode 100644 index 00000000..4b59f924 --- /dev/null +++ b/ksvg/ecma/ksvg_ecmaeventlistener.cpp @@ -0,0 +1,99 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include + +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" + +#include "ksvg_ecma.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_ecmaeventlistener.h" + +using namespace KSVG; +using namespace KJS; + +KSVGEcmaEventListener::KSVGEcmaEventListener(KJS::Object _listener, QString _type, KSVGEcma *_ecma) : SVGEventListener() +{ + m_listener = _listener; + m_remove = true; + m_type = _type; + m_ecma = _ecma; + + m_ecma->addEventListener(this); +} + +KSVGEcmaEventListener::~KSVGEcmaEventListener() +{ + if(m_remove) + m_ecma->removeEventListener(this); +} + +void KSVGEcmaEventListener::forbidRemove() +{ + m_remove = false; +} + +void KSVGEcmaEventListener::handleEvent(SVGEventImpl *evt) +{ + if(m_ecma && m_listener.implementsCall()) + { + KSVGScriptInterpreter *interpreter = m_ecma->interpreter(); + ExecState *exec = m_ecma->globalExec(); + + // Append 'evt' + List args; + args.append(getDOMEvent(exec, evt)); + + // Set current event + interpreter->setCurrentEvent(evt); + + // Call it! + Object thisObj = Object::dynamicCast(getDOMNode(exec, *evt->currentTarget())); + Value retval = m_listener.call(exec, thisObj, args); + + interpreter->setCurrentEvent(0); + + if(exec->hadException()) + { + exec->clearException(); + + // onerror support + SVGSVGElementImpl *rootElement = static_cast(exec->interpreter())->document()->rootElement(); + if(rootElement) + rootElement->dispatchEvent(SVGEvent::ERROR_EVENT, true, false); + } + else + { + QVariant ret = valueToVariant(exec, retval); + if(ret.type() == QVariant::Bool && ret.toBool() == false) + evt->preventDefault(); + } + } +} + +DOM::DOMString KSVGEcmaEventListener::eventListenerType() +{ + return "KSVGEcmaEventListener - " + m_type; +} + +// vim:ts=4:noet diff --git a/ksvg/ecma/ksvg_ecmaeventlistener.h b/ksvg/ecma/ksvg_ecmaeventlistener.h new file mode 100644 index 00000000..16ebe3bc --- /dev/null +++ b/ksvg/ecma/ksvg_ecmaeventlistener.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 KSVGEcmaEventListener_H +#define KSVGEcmaEventListener_H + +#include "SVGEventImpl.h" + +namespace KJS +{ + class Object; +} + +class KSVGEcmaEventListener : public KSVG::SVGEventListener +{ +public: + KSVGEcmaEventListener(KJS::Object _listener, QString _type, KSVGEcma *_ecma); + virtual ~KSVGEcmaEventListener(); + + virtual void handleEvent(KSVG::SVGEventImpl *evt); + virtual DOM::DOMString eventListenerType(); + + QString type() { return m_type; } + + void forbidRemove(); + +private: + KSVGEcma *m_ecma; + QString m_type; + bool m_remove; + + KJS::Object m_listener; +}; + +#endif + +// vim:ts=4:noet diff --git a/ksvg/ecma/ksvg_helper.cpp b/ksvg/ecma/ksvg_helper.cpp new file mode 100644 index 00000000..597f9a06 --- /dev/null +++ b/ksvg/ecma/ksvg_helper.cpp @@ -0,0 +1,68 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include + +#include + +KJS::UString::UString(const DOM::DOMString &d) +{ + if(d.isNull()) + { + attach(&Rep::null); + return; + } + + unsigned int len = d.length(); + KJS::UChar *dat = new UChar[len]; + memcpy(dat, d.unicode(), len * sizeof(UChar)); + rep = KJS::UString::Rep::create(dat, len); +} + +KJS::UString::UString(const QString &d) +{ + unsigned int len = d.length(); + KJS::UChar *dat = new UChar[len]; + memcpy(dat, d.unicode(), len * sizeof(UChar)); + rep = KJS::UString::Rep::create(dat, len); +} + +QString KJS::UString::qstring() const +{ + return QString(reinterpret_cast(const_cast(data())), size()); +} + +DOM::DOMString KJS::UString::string() const +{ + return DOM::DOMString(reinterpret_cast(const_cast(data())), size()); +} + +DOM::DOMString KJS::Identifier::string() const +{ + return DOM::DOMString((QChar*) data(), size()); +} + +QString KJS::Identifier::qstring() const +{ + return QString((QChar*) data(), size()); +} + +// vim:ts=4:noet diff --git a/ksvg/ecma/ksvg_lookup.h b/ksvg/ecma/ksvg_lookup.h new file mode 100644 index 00000000..11c41462 --- /dev/null +++ b/ksvg/ecma/ksvg_lookup.h @@ -0,0 +1,318 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 KSVG_LOOKUP_H +#define KSVG_LOOKUP_H + +#include +#include +#include // for ExecState + +#include "ksvg_bridge.h" +#include "ksvg_scriptinterpreter.h" + +#define KSVG_GET_COMMON \ +public: \ + \ + /* The standard hasProperty call, auto-generated. Looks in hashtable, forwards to parents. */ \ + bool hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \ + \ + /* get() method, called by KSVGBridge::get */ \ + KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::ObjectImp* bridge) const; \ + \ + /* Called by lookupGet(). Auto-generated. Forwards to the parent which has the given property. */ \ + KJS::Value getInParents(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::ObjectImp* bridge) const; \ + \ + KJS::Object prototype(KJS::ExecState *exec) const;\ + \ + static const KJS::ClassInfo s_classInfo; \ + \ + static const struct KJS::HashTable s_hashTable; \ + \ + int m_attrFlags; + +// For classes with properties to read, and a hashtable. +#define KSVG_GET \ + KSVG_GET_COMMON \ + KJS::Value cache(KJS::ExecState *exec) const; + +// Same thing, for base classes (kalyptus helps finding them) +// The difference is that cache() is virtual +#define KSVG_BASECLASS_GET \ + KSVG_GET_COMMON \ + virtual KJS::Value cache(KJS::ExecState *exec) const; + +// For classes without properties, but with a parent class to forward to +#define KSVG_FORWARDGET \ +public: \ + \ + bool hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \ + \ + /* will have the code for getInParents */ \ + KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::ObjectImp* bridge) const; \ + \ + KJS::Object prototype(KJS::ExecState *exec) const;\ + \ + static const KJS::ClassInfo s_classInfo; \ + \ + KJS::Value cache(KJS::ExecState *exec) const; + +// For read-write classes only, i.e. those which support put() +#define KSVG_PUT \ + \ + /* put() method, called by KSVGBridge::put */ \ + bool put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value &value, int attr); \ + \ + /* Called by lookupPut. Auto-generated. Looks in hashtable, forwards to parents. */ \ + bool putInParents(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value &value, int attr); + +// For classes which inherit a read-write class, but have no readwrite property themselves +#define KSVG_FORWARDPUT \ + \ + /* put() method, called by KSVGBridge::put */ \ + bool put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value &value, int attr); + +// For classes which need to be accessable with getElementById -> elements +#define KSVG_NO_TAG_BRIDGE \ +public: \ + KJS::ObjectImp *bridge(KJS::ExecState *) const { return 0; } + +#define KSVG_BRIDGE \ +public: \ + KJS::ObjectImp *bridge(KJS::ExecState *) const; \ + virtual DOM::DOMString tagName() const { return s_tagName; } \ + static const DOM::DOMString s_tagName; + +// Fast setting of default values, if the token is known +// Note: this is actually misnamed it should be KSVG_SET_DEFAULT_ATTRIBUTE +#define KSVG_SET_ALT_ATTRIBUTE(Token, Name) putValueProperty(ownerDoc()->ecmaEngine()->globalExec(), Token, String(Name), Internal); + +// Check if attribute has not been parsed, if the token is known +#define KSVG_TOKEN_NOT_PARSED_ELEMENT(Token, Element) (~Element->m_attrFlags & (1 << Token)) +#define KSVG_TOKEN_NOT_PARSED(Token) KSVG_TOKEN_NOT_PARSED_ELEMENT(Token, this) + +// Checks if the interpreter is in attribute "getting" mode +#define KSVG_CHECK_ATTRIBUTE bool attributeMode = static_cast(exec->interpreter())->attributeGetMode(); + +// Sets the class specific flags to a ZERO value +#define KSVG_EMPTY_FLAGS m_attrFlags = 0; + +// to be used in generatedata.cpp +// GET p1=exec, p2=propertyName, p3=bridge +// PUT p1=exec, p2=propertyName, p3=value, p4=attr +#define GET_METHOD_ARGS KJS::ExecState *p1, const KJS::Identifier &p2, const KJS::ObjectImp *p3 +#define PUT_METHOD_ARGS KJS::ExecState *p1, const KJS::Identifier &p2, const KJS::Value &p3, int p4 + +namespace KSVG +{ + /** + * Helper method for property lookups + * + * This method does it all (looking in the hashtable, checking for function + * overrides, creating the function or retrieving from cache, calling + * getValueProperty in case of a non-function property, forwarding to parent[s] if + * unknown property). + * + * Template arguments: + * @param FuncImp the class which implements this object's functions + * @param ThisImp the class of "this". It must implement the getValueProperty(exec,token) method, + * for non-function properties, and the getInParents() method (auto-generated). + * + * Method arguments: + * @param exec execution state, as usual + * @param propertyName the property we're looking for + * @param table the static hashtable for this class + * @param thisObj "this" + */ + template + inline KJS::Value lookupGet(KJS::ExecState *exec, + const KJS::Identifier &propertyName, + const KJS::HashTable *table, + const ThisImp *thisObj, // the 'impl' object + const KJS::ObjectImp *bridge) + { + const KJS::HashEntry *entry = KJS::Lookup::findEntry(table, propertyName); + + if(!entry) // not found, forward to parents + return thisObj->getInParents(exec, propertyName, bridge); + + if(entry->attr & KJS::Function) + return KJS::lookupOrCreateFunction(exec, propertyName, + const_cast(bridge), + entry->value, entry->params, entry->attr); + + return thisObj->getValueProperty(exec, entry->value); + } + + /** + * Simplified version of lookupGet in case there are no functions, only "values". + * Using this instead of lookupGet removes the need for a FuncImp class. + */ + template + inline KJS::Value lookupGetValue(KJS::ExecState *exec, + const KJS::Identifier &propertyName, + const KJS::HashTable *table, + const ThisImp *thisObj, // the 'impl' object + const KJS::ObjectImp *bridge) + { + const KJS::HashEntry *entry = KJS::Lookup::findEntry(table, propertyName); + + if(!entry) // not found, forward to parents + return thisObj->getInParents(exec, propertyName, bridge); + + if(entry->attr & KJS::Function) + kdError(26004) << "Function bit set! Shouldn't happen in lookupGetValue! propertyName was " << propertyName.qstring() << endl; + + return thisObj->getValueProperty(exec, entry->value); + } + + /** + * This one is for "put". + * Lookup hash entry for property to be set, and set the value. + * The "this" class must implement putValueProperty. + * If it returns false, put() will return false, and KSVGRequest will set a dynamic property in ObjectImp + */ + template + inline bool lookupPut(KJS::ExecState *exec, + const KJS::Identifier &propertyName, + const KJS::Value &value, + int attr, + const KJS::HashTable *table, + ThisImp *thisObj) + { + const KJS::HashEntry *entry = KJS::Lookup::findEntry(table, propertyName); + + if(!entry) // not found, forward to parents + return thisObj->putInParents(exec, propertyName, value, attr); + else if(entry->attr & KJS::Function) // Function: put as override property + return false; + else if(entry->attr & KJS::ReadOnly && !(attr & KJS::Internal)) // readonly! Can't put! + { +#ifdef KJS_VERBOSE + kdWarning(26004) <<" Attempt to change value of readonly property '" << propertyName.qstring() << "'" << endl; +#endif + return true; // "we did it" -> don't put override property + } + else + { + if(static_cast(exec->interpreter())->attributeSetMode()) + thisObj->m_attrFlags |= (1 << entry->value); + + thisObj->putValueProperty(exec, entry->value, value, attr); + return true; + } + } +} + +// Same as kjs' DEFINE_PROTOTYPE, but with a pointer to the hashtable too, and no ClassName here +// The ClassProto ctor(exec) must be public, so we can use KJS::cacheGlobalObject... (Niko) +#define KSVG_DEFINE_PROTOTYPE(ClassProto) \ + namespace KSVG { \ + class ClassProto : public KJS::ObjectImp { \ + public: \ + static KJS::Object self(KJS::ExecState *exec); \ + ClassProto( KJS::ExecState *exec ) \ + : KJS::ObjectImp( exec->interpreter()->builtinObjectPrototype() ) {} \ + virtual const KJS::ClassInfo *classInfo() const { return &info; } \ + static const KJS::ClassInfo info; \ + KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \ + bool hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \ + \ + static const struct KJS::HashTable s_hashTable; \ + }; \ + } + +// same as IMPLEMENT_PROTOTYPE but in the KSVG namespace, and with ClassName here +// so that KSVG_DEFINE_PROTOTYPE can be put in a header file ('info' defined here) +#define KSVG_IMPLEMENT_PROTOTYPE(ClassName,ClassProto,ClassFunc) \ + KJS::Value KSVG::ClassProto::get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \ + { \ + return lookupGetFunction(exec, propertyName, &s_hashTable, this ); \ + } \ + bool KSVG::ClassProto::hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \ + { /*stupid but we need this to have a common macro for the declaration*/ \ + return KJS::ObjectImp::hasProperty(exec, propertyName); \ + } \ + KJS::Object KSVG::ClassProto::self(KJS::ExecState *exec) \ + { \ + return KJS::cacheGlobalObject( exec, "[[" ClassName ".prototype]]" ); \ + } \ + const KJS::ClassInfo ClassProto::info = { ClassName, 0, &s_hashTable, 0 }; \ + +// same as KSVG_IMPLEMENT_PROTOTYPE but with a parent class to forward calls to +// Not used within KSVG up to now - each class does a self proto lookup in generateddata.cpp +#define KSVG_IMPLEMENT_PROTOTYPE_WITH_PARENT(ClassName,ClassProto,ClassFunc,ParentProto) \ + KJS::Value KSVG::ClassProto::get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \ + { \ + KJS::Value val = lookupGetFunction(exec, propertyName, &s_hashTable, this ); \ + if ( val.type() != UndefinedType ) return val; \ + /* Not found -> forward request to "parent" prototype */ \ + return ParentProto::self(exec).get( exec, propertyName ); \ + } \ + bool KSVG::ClassProto::hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \ + { \ + if (KJS::ObjectImp::hasProperty(exec, propertyName)) \ + return true; \ + return ParentProto::self(exec).hasProperty(exec, propertyName); \ + } \ + KJS::Object KSVG::ClassProto::self(KJS::ExecState *exec) \ + { \ + return KJS::cacheGlobalObject( exec, "[[" ClassName ".prototype]]" ); \ + } \ + const KJS::ClassInfo ClassProto::info = { ClassName, 0, &s_hashTable, 0 }; \ + +#define KSVG_IMPLEMENT_PROTOFUNC(ClassFunc,Class) \ + namespace KSVG { \ + class ClassFunc : public KJS::ObjectImp { \ + public: \ + ClassFunc(KJS::ExecState *exec, int i, int len) \ + : KJS::ObjectImp( /*proto? */ ), id(i) { \ + KJS::Value protect(this); \ + put(exec,"length",KJS::Number(len),KJS::DontDelete|KJS::ReadOnly|KJS::DontEnum); \ + } \ + /** Used by call() to check the type of thisObj. Generated code */ \ + Class * cast(const KJS::ObjectImp* bridge) const; \ + \ + virtual bool implementsCall() const { return true; } \ + /** You need to implement that one */ \ + virtual KJS::Value call(KJS::ExecState *exec, KJS::Object &thisObj, const KJS::List &args); \ + private: \ + int id; \ + }; \ + } + +// To be used when casting the type of an argument +#define KSVG_CHECK(ClassName, theObj) \ + ClassName* obj = cast(static_cast(theObj.imp())); \ + if (!obj) { \ + kdDebug(26004) << k_funcinfo << " Wrong object type: expected " << ClassName::s_classInfo.className << " got " << thisObj.classInfo()->className << endl; \ + Object err = Error::create(exec,TypeError); \ + exec->setException(err); \ + return err; \ + } + +// To be used in all call() implementations! +// Can't use if (!thisObj.inherits(&ClassName::s_classInfo) since we don't +// use the (single-parent) inheritance of ClassInfo... +#define KSVG_CHECK_THIS(ClassName) KSVG_CHECK(ClassName, thisObj) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/ecma/ksvg_scriptinterpreter.cpp b/ksvg/ecma/ksvg_scriptinterpreter.cpp new file mode 100644 index 00000000..b5b9e6dd --- /dev/null +++ b/ksvg/ecma/ksvg_scriptinterpreter.cpp @@ -0,0 +1,92 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGEventImpl.h" +#include "SVGDocumentImpl.h" +#include "ksvg_scriptinterpreter.h" + +using namespace KSVG; +using namespace KJS; + +KSVGScriptInterpreter::KSVGScriptInterpreter(const Object &global, SVGDocumentImpl *doc) : Interpreter(global), m_document(doc) +{ + m_evt = 0; + + m_attributeGetMode = false; + m_attributeSetMode = false; +} + +KSVGScriptInterpreter::~KSVGScriptInterpreter() +{ + if(m_evt) + m_evt->deref(); +} + +SVGDocumentImpl *KSVGScriptInterpreter::document() +{ + return m_document; +} + +KSVG::SVGEventImpl *KSVGScriptInterpreter::currentEvent() +{ + return m_evt; +} + +void KSVGScriptInterpreter::setCurrentEvent(KSVG::SVGEventImpl *evt) +{ + m_evt = evt; +} + +KJS::ObjectImp *KSVGScriptInterpreter::getDOMObject(void *objectHandle) const +{ + return m_domObjects[objectHandle]; +} + +void KSVGScriptInterpreter::putDOMObject(void *objectHandle, KJS::ObjectImp *obj) +{ + m_domObjects.insert(objectHandle, obj); +} + +void KSVGScriptInterpreter::removeDOMObject(void *objectHandle) +{ + m_domObjects.take(objectHandle); +} + +bool KSVGScriptInterpreter::attributeGetMode() +{ + return m_attributeGetMode; +} + +bool KSVGScriptInterpreter::attributeSetMode() +{ + return m_attributeSetMode; +} + +void KSVGScriptInterpreter::setAttributeGetMode(bool temp) +{ + m_attributeGetMode = temp; +} + +void KSVGScriptInterpreter::setAttributeSetMode(bool temp) +{ + m_attributeSetMode = temp; +} + +// vim:ts=4:noet diff --git a/ksvg/ecma/ksvg_scriptinterpreter.h b/ksvg/ecma/ksvg_scriptinterpreter.h new file mode 100644 index 00000000..ed7c6af8 --- /dev/null +++ b/ksvg/ecma/ksvg_scriptinterpreter.h @@ -0,0 +1,71 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 KSVGScriptInterpreter_H +#define KSVGScriptInterpreter_H + +#include + +namespace KJS +{ + class Value; + class Object; + class Interpreter; +} + +namespace KSVG +{ + class SVGEventImpl; + class SVGDocumentImpl; +} + +class KSVGScriptInterpreter : public KJS::Interpreter +{ +public: + KSVGScriptInterpreter(const KJS::Object &global, KSVG::SVGDocumentImpl *doc); + virtual ~KSVGScriptInterpreter(); + + KSVG::SVGDocumentImpl *document(); + + KJS::ObjectImp *getDOMObject(void *objectHandle) const; + void putDOMObject(void *objectHandle, KJS::ObjectImp *obj); + void removeDOMObject(void *objectHandle); + + KSVG::SVGEventImpl *currentEvent(); + void setCurrentEvent(KSVG::SVGEventImpl *evt); + + bool attributeGetMode(); + void setAttributeGetMode(bool temp); + + bool attributeSetMode(); + void setAttributeSetMode(bool temp); + +private: + KSVG::SVGDocumentImpl *m_document; + KSVG::SVGEventImpl *m_evt; + + bool m_attributeGetMode, m_attributeSetMode; + + QPtrDict m_domObjects; +}; + +#endif + +// vim:ts=4:noet diff --git a/ksvg/ecma/ksvg_window.cpp b/ksvg/ecma/ksvg_window.cpp new file mode 100644 index 00000000..d4c04de3 --- /dev/null +++ b/ksvg/ecma/ksvg_window.cpp @@ -0,0 +1,578 @@ +/* This file is part of the KDE project + Copyright (C) 2002 David Faure + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2, as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "ksvg_window.moc" +#include "ksvg_lookup.h" +#include "ksvg_ecma.h" +#include "ksvg_bridge.h" +#include "ksvg_scriptinterpreter.h" +#include +#include +#include +#include +// for js constants +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace KSVG; + +#include "ksvg_window.lut.h" + +// Spec on http://www.protocol7.com/svg-wiki/ow.asp?AdobeSVGViewerWindow + +/* +@namespace KSVG +@begin KSVG::Window::s_hashTable 34 + closed KSVG::Window::_Closed DontDelete|ReadOnly + window KSVG::Window::_Window DontDelete|ReadOnly + evt KSVG::Window::_Evt DontDelete|ReadOnly + document KSVG::Window::_Document DontDelete|ReadOnly + svgDocument KSVG::Window::_Document DontDelete|ReadOnly + innerWidth KSVG::Window::_InnerWidth DontDelete|ReadOnly + innerHeight KSVG::Window::_InnerHeight DontDelete|ReadOnly + setTimeout KSVG::Window::_SetTimeout DontDelete|Function 2 + clearTimeout KSVG::Window::_ClearTimeout DontDelete|Function 1 + setInterval KSVG::Window::_SetInterval DontDelete|Function 2 + clearInterval KSVG::Window::_ClearInterval DontDelete|Function 1 + navigator KSVG::Window::_Navigator DontDelete|ReadOnly + printNode KSVG::Window::_PrintNode DontDelete|Function 1 + +# todo navigator, status/defaultstatus, like in KJS::Window (khtml) +# todo close +# todo instancename +# todo setsrc, getsrc, reload, focus, blur, browsereval, findinstancebyname + +# "Constructors" (usually repositories for constants) + SVGTransform KSVG::Window::_SVGTransform DontDelete|ReadOnly + SVGLength KSVG::Window::_SVGLength DontDelete|ReadOnly + SVGAngle KSVG::Window::_SVGAngle DontDelete|ReadOnly + SVGPreserveAspectRatio KSVG::Window::_SVGPreserveAspectRatio DontDelete|ReadOnly + SVGPathSeg KSVG::Window::_SVGPathSeg DontDelete|ReadOnly + SVGGradientElement KSVG::Window::_SVGGradientElement DontDelete|ReadOnly + SVGMarkerElement KSVG::Window::_SVGMarkerElement DontDelete|ReadOnly + SVGTextPathElement KSVG::Window::_SVGTextPathElement DontDelete|ReadOnly + SVGPaint KSVG::Window::_SVGPaint DontDelete|ReadOnly + SVGTextContentElement KSVG::Window::_SVGTextContentElement DontDelete|ReadOnly + SVGZoomAndPan KSVG::Window::_SVGZoomAndPan DontDelete|ReadOnly + SVGColor KSVG::Window::_SVGColor DontDelete|ReadOnly + +# Functions + alert KSVG::Window::_Alert DontDelete|Function 1 + prompt KSVG::Window::_Prompt DontDelete|Function 2 + confirm KSVG::Window::_Confirm DontDelete|Function 1 + debug KSVG::Window::_Debug DontDelete|Function 1 + success KSVG::Window::_Success DontDelete|Function 1 + getSVGViewerVersion KSVG::Window::_GetSVGViewerVersion DontDelete|Function 0 + getURL KSVG::Window::_GetURL DontDelete|Function 2 + postURL KSVG::Window::_PostURL DontDelete|Function 5 + parseXML KSVG::Window::_ParseXML DontDelete|Function 1 +@end +*/ + +KSVG_IMPLEMENT_PROTOFUNC(WindowFunc, Window) + +const ClassInfo KSVG::Window::s_classInfo = { "Window", 0, &s_hashTable, 0 }; + +KSVG::Window::Window(KSVG::SVGDocumentImpl *p) : ObjectImp(), m_doc(p) +{ + winq = new WindowQObject(this); +} + +KSVG::Window::~Window() +{ + delete winq; +} + +KSVG::Window *KSVG::Window::retrieveActive(ExecState *exec) +{ + ValueImp *imp = exec->interpreter()->globalObject().imp(); + assert(imp); + return static_cast(imp); +} + +bool KSVG::Window::hasProperty(ExecState *, const Identifier &) const +{ + return true; // See KJS::KSVG::Window::hasProperty +} + +Value KSVG::Window::get(ExecState *exec, const Identifier &p) const +{ + kdDebug(26004) << "KSVG::Window (" << this << ")::get " << p.qstring() << endl; + + if(p == "closed") + return Boolean(m_doc.isNull()); + + // we don't want any operations on a closed window + if(m_doc.isNull()) + return Undefined(); + + // Look for overrides first + Value val = ObjectImp::get(exec, p); + if(!val.isA(UndefinedType)) + return isSafeScript(exec) ? val : Undefined(); + + // Not the right way in the long run. Should use retrieve(m_doc)... + KSVGScriptInterpreter* interpreter = static_cast(exec->interpreter()); + + const HashEntry *entry = Lookup::findEntry(&KSVG::Window::s_hashTable, p); + if(entry) + { + switch(entry->value) + { + case _Document: + // special case, KSVGEcma::setup created it, so we don't need to do it + return Value(interpreter->getDOMObject(m_doc->handle())); + case _Window: + return Value(const_cast(this)); + case _Evt: + { + KSVG::SVGEventImpl *evt = interpreter->currentEvent(); + if(evt) + return getDOMEvent(exec, evt); + else + return Undefined(); + } + case _InnerWidth: + return Number(m_doc->canvas()->width()); + case _InnerHeight: + return Number(m_doc->canvas()->height()); + case _SetTimeout: + case _ClearTimeout: + case _SetInterval: + case _ClearInterval: + case _PrintNode: + { + if(isSafeScript(exec)) + return lookupOrCreateFunction(exec, p, this, entry->value, entry->params, entry->attr); + else + return Undefined(); + } + case _Alert: + case _Confirm: + case _Debug: + case _Success: + case _GetSVGViewerVersion: + case _GetURL: + case _PostURL: + case _ParseXML: + case _Prompt: + return lookupOrCreateFunction(exec, p, this, entry->value, entry->params, entry->attr); + case _SVGTransform: + return getSVGTransformImplConstructor(exec); + case _SVGLength: + return getSVGLengthImplConstructor(exec); + case _SVGAngle: + return getSVGAngleImplConstructor(exec); + case _SVGColor: + return getSVGColorImplConstructor(exec); + case _SVGPreserveAspectRatio: + return getSVGPreserveAspectRatioImplConstructor(exec); + case _SVGPathSeg: + return getSVGPathSegImplConstructor(exec); + case _SVGGradientElement: + return getSVGGradientElementImplConstructor(exec); + case _SVGMarkerElement: + return getSVGMarkerElementImplConstructor(exec); + case _SVGTextPathElement: + return getSVGTextPathElementImplConstructor(exec); + case _SVGPaint: + return getSVGPaintImplConstructor(exec); + case _SVGTextContentElement: + return getSVGTextContentElementImplConstructor(exec); + case _SVGZoomAndPan: + return getSVGZoomAndPanImplConstructor(exec); + } + } + + // This isn't necessarily a bug. Some code uses if(!window.blah) window.blah=1 + // But it can also mean something isn't loaded or implemented... + kdDebug(26004) << "KSVG::Window::get property not found: " << p.qstring() << endl; + + return Undefined(); +} + +void KSVG::Window::put(ExecState* exec, const Identifier &propertyName, const Value &value, int attr) +{ + // Called by an internal KJS call (e.g. InterpreterImp's constructor) ? + // If yes, save time and jump directly to ObjectImp. + if((attr != None && attr != DontDelete) + // Same thing if we have a local override (e.g. "var location") + || (ObjectImp::getDirect(propertyName) && isSafeScript(exec))) + { + ObjectImp::put( exec, propertyName, value, attr ); + return; + } + + const HashEntry *entry = Lookup::findEntry(&KSVG::Window::s_hashTable, propertyName); + if(entry) + { +#ifdef KJS_VERBOSE + kdDebug(26004) << "Window(" << this << ")::put " << propertyName.qstring() << endl; +#endif + //switch(entry->value) + //{ + // ... + //} + } + + if(isSafeScript(exec)) + ObjectImp::put(exec, propertyName, value, attr); +} + +bool KSVG::Window::isSafeScript(ExecState *exec) const +{ + if(m_doc.isNull()) // part deleted ? can't grant access + { + kdDebug(26004) << "KSVG::Window::isSafeScript: accessing deleted part !" << endl; + return false; + } + + KSVG::SVGDocumentImpl *activePart = static_cast(exec->interpreter())->document(); + + if(!activePart) + { + kdDebug(26004) << "KSVG::Window::isSafeScript: current interpreter's part is 0L!" << endl; + return false; + } + + if(activePart == m_doc) // Not calling from another frame, no problem. + return true; + + return false; +} + +void KSVG::Window::clear(ExecState *exec) +{ + kdDebug(26004) << "KSVG::Window::clear " << this << endl; + delete winq; + winq = new WindowQObject(this);; + + // Get rid of everything, those user vars could hold references to DOM nodes + deleteAllProperties(exec); + + // Really delete those properties, so that the DOM nodes get deref'ed + // KJS::Collector::collect(); + + // Now recreate a working global object for the next URL that will use us + Interpreter *interpreter = exec->interpreter(); + interpreter->initGlobalObject(); +} + +Value WindowFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + if(!thisObj.inherits(&KSVG::Window::s_classInfo)) + { + Object err = Error::create(exec, TypeError); + exec->setException(err); + return err; + } + + Window *window = static_cast(thisObj.imp()); + Value v = args[0]; + UString s = v.toString(exec); + QString str = s.qstring(); + + switch(id) + { + case KSVG::Window::_Alert: + SVGWindowImpl::alert(DOM::DOMString(str), "Javascript"); + return Undefined(); + case KSVG::Window::_Confirm: + return Boolean(SVGWindowImpl::confirm(DOM::DOMString(str), "Javascript")); + case KSVG::Window::_Debug: + kdDebug(26004) << "[Debug] " << str << endl; + return Undefined(); + case KSVG::Window::_Success: + //if(args[0].toString(exec) == "success") // ? Did you really mean that ? + return Number(1); + //return Undefined(); + case KSVG::Window::_GetSVGViewerVersion: + return String("0.1"); // I cant really find a central place for the version nr, so... (Rob) + case KSVG::Window::_ClearTimeout: + case KSVG::Window::_ClearInterval: + (const_cast(window))->clearTimeout(v.toInt32(exec)); + return Undefined(); + case KSVG::Window::_PrintNode: + return String(const_cast(window)->doc()->window()->printNode(toNode(args[0]))); + case KSVG::Window::_GetURL: + { + KURL url((const_cast(window))->doc()->baseUrl(), args[0].toString(exec).qstring()); + Value asyncStatus = (const_cast(window))->doc()->ecmaEngine()->getUrl(exec, url); + Object callBackFunction = Object::dynamicCast(args[1]); + List callBackArgs; + + callBackArgs.append(asyncStatus); + callBackFunction.call(exec, callBackFunction, callBackArgs); + + return Undefined(); + } + case KSVG::Window::_PostURL: + { + KURL url((const_cast(window))->doc()->baseUrl(), args[0].toString(exec).qstring()); + QString data = args[1].toString(exec).qstring(); + QString mimeType = args[3].toString(exec).qstring(); + QString contentEncoding = args[4].toString(exec).qstring(); + Object callBackFunction = Object::dynamicCast(args[2]); + + (const_cast(window))->doc()->ecmaEngine()->postUrl(exec, url, data, mimeType, contentEncoding, callBackFunction); + + return Undefined(); + }; + case KSVG::Window::_ParseXML: + { + SVGDocumentImpl *doc = new SVGDocumentImpl(); + doc->ref(); + doc->attach(0); + + // So we can find it later... + (const_cast(window))->doc()->addToDocumentDict(doc->handle(), doc); + + // Also add the current doc to the new doc! + SVGDocumentImpl *curDoc = (const_cast(window))->doc(); + doc->addToDocumentDict(curDoc->handle(), curDoc); + + QXmlInputSource *svgFragment = new QXmlInputSource(); + svgFragment->setData(args[0].toString(exec).qstring()); + + doc->parseSVG(svgFragment, true); + + DOM::DocumentFragment fragment = doc->createDocumentFragment(); + DOM::Node node = doc->firstChild(); + for(; !node.isNull(); node = node.nextSibling()) + fragment.appendChild(node); + + +// fragment = *doc; // Should copy the nodes into here... + + return (new SVGDOMDocumentFragmentBridge(fragment))->cache(exec); + } + case KSVG::Window::_Prompt: + { + // mop: from khtml. do we need that? + // part->xmlDocImpl()->updateRendering(); + bool ok; + QString str2; + if (args.size() >= 2) + str2 = KInputDialog::getText(i18n("Prompt"), + QStyleSheet::convertFromPlainText(str), + args[1].toString(exec).qstring(), &ok); + else + str2 = KInputDialog::getText(i18n("Prompt"), + QStyleSheet::convertFromPlainText(str), + QString::null, &ok); + if ( ok ) + return String(str2); + else + return Null(); + } + case KSVG::Window::_SetInterval: + if(args.size() >= 2 && v.isA(StringType)) + { + int i = args[1].toInt32(exec); + int r = (const_cast(window))->installTimeout(s, i, false); + return Number(r); + } + else if(args.size() >= 2 && !Object::dynamicCast(v).isNull() && Object::dynamicCast(v).implementsCall()) + { + Value func = args[0]; + int i = args[1].toInt32(exec); + int r = (const_cast(window))->installTimeout(s, i, false); + return Number(r); + } + else + return Undefined(); + case KSVG::Window::_SetTimeout: + if (args.size() == 2 && v.isA(StringType)) + { + int i = args[1].toInt32(exec); + int r = (const_cast(window))->installTimeout(s, i, true /*single shot*/); + return Number(r); + } + else if(args.size() >= 2 && v.isA(ObjectType) && Object::dynamicCast(v).implementsCall()) + { + Value func = args[0]; + int i = args[1].toInt32(exec); + int r = (const_cast(window))->installTimeout(s, i, false); + return Number(r); + } + else + return Undefined(); + } + + return Undefined(); +} + +int KSVG::Window::installTimeout(const UString &handler, int t, bool singleShot) +{ + return winq->installTimeout(handler, t, singleShot); +} + +void KSVG::Window::clearTimeout(int timerId) +{ + winq->clearTimeout(timerId); +} + +////////////////////// ScheduledAction //////////////////////// + +ScheduledAction::ScheduledAction(Object _func, List _args, bool _singleShot) +{ + func = _func; + args = _args; + isFunction = true; + singleShot = _singleShot; +} + +ScheduledAction::ScheduledAction(QString _code, bool _singleShot) +{ + code = _code; + isFunction = false; + singleShot = _singleShot; +} + +ScheduledAction::~ScheduledAction() +{ +} + +void ScheduledAction::execute(Window *window) +{ + Q_ASSERT(window->doc()); + + KSVGScriptInterpreter *interpreter = window->doc()->ecmaEngine()->interpreter(); + if(isFunction) + { + if(func.implementsCall()) + { + ExecState *exec = interpreter->globalExec(); + Q_ASSERT(window == interpreter->globalObject().imp()); + Object obj(window); + func.call(exec, obj, args); // note that call() creates its own execution state for the func call + } + } + else + { + interpreter->evaluate(code); + window->doc()->rerender(); + } +} + +////////////////////// WindowQObject //////////////////////// + +WindowQObject::WindowQObject(Window *w) : parent(w) +{ +} + +WindowQObject::~WindowQObject() +{ + parentDestroyed(); // reuse same code +} + +void WindowQObject::parentDestroyed() +{ + killTimers(); + + QMapIterator it; + for(it = scheduledActions.begin(); it != scheduledActions.end(); ++it) + { + ScheduledAction *action = *it; + delete action; + } + + scheduledActions.clear(); +} + +int WindowQObject::installTimeout(const UString &handler, int t, bool singleShot) +{ + int id = startTimer(t); + ScheduledAction *action = new ScheduledAction(handler.qstring(), singleShot); + scheduledActions.insert(id, action); + return id; +} + +int WindowQObject::installTimeout(const Value &func, List args, int t, bool singleShot) +{ + Object objFunc = Object::dynamicCast(func); + int id = startTimer(t); + scheduledActions.insert(id, new ScheduledAction(objFunc, args, singleShot)); + return id; +} + +void WindowQObject::clearTimeout(int timerId, bool delAction) +{ + killTimer(timerId); + + if(delAction) + { + QMapIterator it = scheduledActions.find(timerId); + if(it != scheduledActions.end()) + { + ScheduledAction *action = *it; + scheduledActions.remove(it); + delete action; + } + } +} + +void WindowQObject::timerEvent(QTimerEvent *e) +{ + QMapIterator it = scheduledActions.find(e->timerId()); + if(it != scheduledActions.end()) + { + ScheduledAction *action = *it; + bool singleShot = action->singleShot; + + // remove single shots installed by setTimeout() + if(singleShot) + { + clearTimeout(e->timerId(), false); + scheduledActions.remove(it); + } + + if(parent->doc()) + action->execute(parent); + + // It is important to test singleShot and not action->singleShot here - the + // action could have been deleted already if not single shot and if the + // JS code called by execute() calls clearTimeout(). + if(singleShot) + delete action; + } + else + kdWarning(6070) << "WindowQObject::timerEvent this=" << this << " timer " << e->timerId() << " not found (" << scheduledActions.count() << " actions in map)" << endl; +} + +void WindowQObject::timeoutClose() +{ +} diff --git a/ksvg/ecma/ksvg_window.h b/ksvg/ecma/ksvg_window.h new file mode 100644 index 00000000..28c9699e --- /dev/null +++ b/ksvg/ecma/ksvg_window.h @@ -0,0 +1,122 @@ +/* This file is part of the KDE project + Copyright (C) 2002 David Faure + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2, as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KSVG_WINDOW_H +#define KSVG_WINDOW_H + +#include +#include + +namespace KSVG { + +class SVGDocumentImpl; +class WindowQObject; + +// This is currently a fork of khtml's Window object, simplified. +// However in the long run it could become a base class for it. +// Author: David Faure +class Window : public KJS::ObjectImp { + friend class WindowFunc; + friend class WindowQObject; + friend class ScheduledAction; +public: + Window(KSVG::SVGDocumentImpl *p); + ~Window(); + + virtual KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; + virtual void put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value &value, int attr = KJS::None); + virtual bool hasProperty(KJS::ExecState * /*exec*/, const KJS::Identifier &/*p*/) const; + + /** + * Returns and registers a window object. In case there's already a Window + * for the specified part p this will be returned in order to have unique + * bindings. + */ + //static KJS::Value retrieve(KSVG::SVGDocumentImpl *p); + /** + * Returns the Window object for a given part + */ + //static Window *retrieveWindow(KSVG::SVGDocumentImpl *p); + /** + * returns a pointer to the Window object this javascript interpreting instance + * was called from. + */ + static Window *retrieveActive(KJS::ExecState *exec); + + QGuardedPtr doc() const { return m_doc; } + + int installTimeout(const KJS::UString &handler, int t, bool singleShot); + void clearTimeout(int timerId); + + bool isSafeScript(KJS::ExecState *exec) const; + void clear( KJS::ExecState *exec ); + + enum { + // Properties + _Closed, _Window, _Document, _Evt, _InnerWidth, _InnerHeight, + _SVGTransform, _SVGLength, _SVGAngle, _SVGColor, _SVGPreserveAspectRatio, _SVGGradientElement, + _SVGPathSeg, _SVGTextContentElement, _SVGPaint, _SVGZoomAndPan, _SVGMarkerElement, _SVGTextPathElement, + _SetInterval, _ClearInterval, _SetTimeout, _ClearTimeout, _Navigator, _PrintNode, + // Functions + _Alert, _Confirm, _Debug, _Success, _GetSVGViewerVersion, _GetURL, _PostURL, _ParseXML, _Prompt + }; + + virtual const KJS::ClassInfo* classInfo() const { return &s_classInfo; } + static const KJS::ClassInfo s_classInfo; + static const struct KJS::HashTable s_hashTable; + +private: + WindowQObject *winq; + QGuardedPtr m_doc; +}; + +class ScheduledAction { +public: + ScheduledAction(KJS::Object _func, KJS::List _args, bool _singleShot); + ScheduledAction(QString _code, bool _singleShot); + ~ScheduledAction(); + void execute(Window *window); + KJS::Object func; + KJS::List args; + QString code; + bool isFunction; + bool singleShot; +}; + +class WindowQObject : public QObject { + Q_OBJECT +public: + WindowQObject(Window *w); + ~WindowQObject(); + int installTimeout(const KJS::UString &handler, int t, bool singleShot); + int installTimeout(const KJS::Value &func, KJS::List args, int t, bool singleShot); + void clearTimeout(int timerId, bool delAction = true); +public slots: + void timeoutClose(); +protected slots: + void parentDestroyed(); +protected: + void timerEvent(QTimerEvent *e); +private: + Window *parent; + //KHTMLPart *part; // not guarded, may be dangling + QMap scheduledActions; +}; + +} +#endif // KSVG_WINDOW_H diff --git a/ksvg/impl/LRUCache.h b/ksvg/impl/LRUCache.h new file mode 100644 index 00000000..879f1856 --- /dev/null +++ b/ksvg/impl/LRUCache.h @@ -0,0 +1,169 @@ +/* + Copyright (C) 2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 LRUCACHE_H +#define LRUCACHE_H + +#include + +namespace KSVG +{ + +// A value-based LRU cache with a maximum total cost constraint, but with the exception that the +// most recently added item is kept in the cache even if its cost exceeds the maximum total cost. +template +class MinOneLRUCache +{ +public: + MinOneLRUCache(int maxTotalCost = 0) : m_maxTotalCost(maxTotalCost), m_totalCost(0) {} + virtual ~MinOneLRUCache() {} + + void insert(const keyType& key, const valueType& value, int cost); + bool find(const keyType& key, valueType& result); + + void setMaxTotalCost(int maxTotalCost); + int maxTotalCost() const { return m_maxTotalCost; } + int totalCost() const { return m_totalCost; } + + void clear(); + +protected: + class CacheItem + { + public: + CacheItem() : m_cost(0) {} + CacheItem(const keyType& key, const valueType& value, int cost) : m_key(key), m_value(value), m_cost(cost) {} + + const keyType& key() const { return m_key; } + const valueType& value() const { return m_value; } + int cost() const { return m_cost; } + + private: + keyType m_key; + valueType m_value; + int m_cost; + }; + + typedef QValueList CacheItemList; + + typename CacheItemList::iterator find(const keyType& key); + void enforceCostConstraint(); + + CacheItemList m_items; + int m_maxTotalCost; + int m_totalCost; +}; + +template +void MinOneLRUCache::insert(const keyType& key, const valueType& value, int cost) +{ + typename CacheItemList::iterator it = find(key); + + if(it != m_items.end()) + { + // Replace the existing item. + m_totalCost -= (*it).cost(); + m_items.erase(it); + } + + // We always hold the most recently added item in the cache, even if it exceeds + // the maximum total cost. + m_items.push_front(CacheItem(key, value, cost)); + m_totalCost += cost; + enforceCostConstraint(); +} + +template +bool MinOneLRUCache::find(const keyType& key, valueType& result) +{ + bool foundKey = false; + typename CacheItemList::iterator it = find(key); + + if(it != m_items.end()) + { + CacheItem item = *it; + result = item.value(); + + if(it != m_items.begin()) + { + // This is now the most recently used item. + m_items.erase(it); + m_items.push_front(item); + } + + foundKey = true; + } + + return foundKey; +} + +template +typename MinOneLRUCache::CacheItemList::iterator MinOneLRUCache::find(const keyType& key) +{ + typename CacheItemList::iterator it; + + for(it = m_items.begin(); it != m_items.end(); it++) + { + if((*it).key() == key) + break; + } + + return it; +} + +template +void MinOneLRUCache::enforceCostConstraint() +{ + if(m_totalCost > m_maxTotalCost && m_items.size() > 1) + { + typename CacheItemList::iterator it = m_items.begin(); + m_totalCost = (*it).cost(); + ++it; + + while(it != m_items.end() && m_totalCost + (*it).cost() <= m_maxTotalCost) + { + m_totalCost += (*it).cost(); + ++it; + } + + // Remove the remainder + while(it != m_items.end()) + it = m_items.erase(it); + } +} + +template +void MinOneLRUCache::setMaxTotalCost(int maxTotalCost) +{ + m_maxTotalCost = maxTotalCost; + enforceCostConstraint(); +} + +template +void MinOneLRUCache::clear() +{ + m_items.clear(); + m_totalCost = 0; +} + +} + +#endif + diff --git a/ksvg/impl/Makefile.am b/ksvg/impl/Makefile.am new file mode 100644 index 00000000..24e40d67 --- /dev/null +++ b/ksvg/impl/Makefile.am @@ -0,0 +1,116 @@ +SUBDIRS = libs +noinst_LTLIBRARIES = libksvgdomimpl.la + +KDE_OPTIONS = nofinal + +# The makefile has the following structure: +# datatypes +# animated datatypes +# lists +# animated lists +# base classes +# document structure +# styling +# paths +# basic shapes +# text +# painting +# color +# gradients & patterns +# clipping & masking +# filters +# interactivity +# linking +# scripting +# animations +# font & glyph stuff +# metadata +# extensibility + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) +libksvgdomimpl_la_SOURCES = \ +SVGLengthImpl.cc SVGNumberImpl.cc SVGPointImpl.cc SVGTransformImpl.cc \ +SVGMatrixImpl.cc SVGRectImpl.cc SVGAngleImpl.cc \ +\ +SVGAnimatedLengthImpl.cc SVGAnimatedNumberImpl.cc SVGAnimatedIntegerImpl.cc \ +SVGAnimatedBooleanImpl.cc SVGAnimatedEnumerationImpl.cc SVGAnimatedPreserveAspectRatioImpl.cc \ +SVGAnimatedRectImpl.cc SVGAnimatedAngleImpl.cc SVGAnimatedPathDataImpl.cc SVGAnimatedStringImpl.cc \ +\ +SVGLengthListImpl.cc SVGNumberListImpl.cc SVGPointListImpl.cc SVGTransformListImpl.cc \ +SVGStringListImpl.cc SVGPathSegListImpl.cc SVGElementInstanceListImpl.cc \ +\ +SVGAnimatedLengthListImpl.cc SVGAnimatedNumberListImpl.cc \ +SVGAnimatedPointsImpl.cc SVGAnimatedTransformListImpl.cc \ +\ +SVGShapeImpl.cc SVGContainerImpl.cc SVGBBoxTarget.cc SVGHelperImpl.cc \ +SVGStylableImpl.cc SVGTransformableImpl.cc SVGTestsImpl.cc SVGLangSpaceImpl.cc \ +SVGExternalResourcesRequiredImpl.cc SVGLocatableImpl.cc SVGFitToViewBoxImpl.cc \ +SVGPreserveAspectRatioImpl.cc SVGZoomAndPanImpl.cc SVGViewSpecImpl.cc \ +\ +SVGElementImpl.cc SVGElementInstanceImpl.cc \ +SVGDocumentImpl.cc SVGSVGElementImpl.cc SVGWindowImpl.cc \ +SVGDefsElementImpl.cc SVGUseElementImpl.cc \ +SVGDescElementImpl.cc SVGTitleElementImpl.cc \ +SVGGElementImpl.cc SVGSwitchElementImpl.cc \ +SVGSymbolElementImpl.cc SVGImageElementImpl.cc \ +SVGURIReferenceImpl.cc \ +\ +SVGStyleElementImpl.cc SVGCSSRuleImpl.cc \ +\ +SVGPathElementImpl.cc SVGPathSegImpl.cc SVGPathSegClosePathImpl.cc SVGPathSegArcImpl.cc \ +SVGPathSegMovetoImpl.cc SVGPathSegCurvetoQuadraticImpl.cc SVGPathSegCurvetoQuadraticSmoothImpl.cc \ +SVGPathSegCurvetoCubicImpl.cc SVGPathSegCurvetoCubicSmoothImpl.cc SVGPathSegLinetoImpl.cc \ +SVGPathSegLinetoHorizontalImpl.cc SVGPathSegLinetoVerticalImpl.cc \ +\ +SVGRectElementImpl.cc SVGCircleElementImpl.cc SVGEllipseElementImpl.cc SVGLineElementImpl.cc \ +SVGPolyElementImpl.cc SVGPolylineElementImpl.cc SVGPolygonElementImpl.cc \ +\ +SVGTextElementImpl.cc SVGTSpanElementImpl.cc SVGTRefElementImpl.cc \ +SVGTextPositioningElementImpl.cc SVGTextContentElementImpl.cc SVGTextPathElementImpl.cc \ +\ +SVGPaintImpl.cc SVGMarkerElementImpl.cc \ +\ +SVGColorImpl.cc SVGICCColorImpl.cc SVGColorProfileElementImpl.cc SVGColorProfileRuleImpl.cc \ +\ +SVGPaintServerImpl.cc SVGGradientElementImpl.cc SVGStopElementImpl.cc \ +SVGLinearGradientElementImpl.cc SVGRadialGradientElementImpl.cc SVGPatternElementImpl.cc \ +\ +SVGClipPathElementImpl.cc SVGMaskElementImpl.cc \ +\ +SVGFilterElementImpl.cc SVGFilterPrimitiveStandardAttributesImpl.cc \ +SVGFEBlendElementImpl.cc SVGFEColorMatrixElementImpl.cc \ +SVGFEComponentTransferElementImpl.cc SVGComponentTransferFunctionElementImpl.cc \ +SVGFEFuncAElementImpl.cc SVGFEFuncBElementImpl.cc SVGFEFuncGElementImpl.cc \ +SVGFEFuncRElementImpl.cc SVGFECompositeElementImpl.cc SVGFEConvolveMatrixElementImpl.cc \ +SVGFEFloodElementImpl.cc SVGFEGaussianBlurElementImpl.cc SVGFEDiffuseLightingElementImpl.cc \ +SVGFEDistantLightElementImpl.cc SVGFEPointLightElementImpl.cc SVGFESpotLightElementImpl.cc \ +SVGFEDisplacementMapElementImpl.cc SVGFEMergeElementImpl.cc SVGFEMergeNodeElementImpl.cc \ +SVGFEImageElementImpl.cc SVGFEMorphologyElementImpl.cc SVGFEOffsetElementImpl.cc \ +SVGFESpecularLightingElementImpl.cc SVGFETileElementImpl.cc SVGFETurbulenceElementImpl.cc \ +\ +SVGCursorElementImpl.cc \ +\ +SVGAElementImpl.cc SVGViewElementImpl.cc \ +\ +SVGScriptElementImpl.cc SVGEventImpl.cc SVGZoomEventImpl.cc \ +SVGEcma.cc generateddata.cpp \ +\ +SVGAnimationElementImpl.cc SVGAnimateElementImpl.cc SVGSetElementImpl.cc \ +SVGAnimateMotionElementImpl.cc SVGAnimateColorElementImpl.cc \ +SVGAnimateTransformElementImpl.cc SVGMPathElementImpl.cc SVGTimeScheduler.cc \ +\ +SVGFontElementImpl.cc SVGAltGlyphElementImpl.cc SVGAltGlyphDefElementImpl.cc \ +SVGGlyphRefElementImpl.cc SVGGlyphElementImpl.cc SVGMissingGlyphElementImpl.cc \ +SVGFontFaceElementImpl.cc SVGFontFaceFormatElementImpl.cc SVGFontFaceNameElementImpl.cc \ +SVGFontFaceSrcElementImpl.cc SVGFontFaceUriElementImpl.cc SVGDefinitionSrcElementImpl.cc \ +SVGHKernElementImpl.cc SVGVKernElementImpl.cc \ +\ +SVGMetadataElementImpl.cc \ +\ +SVGForeignObjectElementImpl.cc \ +\ +svgpathparser.cc + +libksvgdomimpl_la_METASOURCES = AUTO + +INCLUDES = $(FREETYPE_CFLAGS) -I$(top_srcdir)/ksvg/core -I$(top_srcdir)/ksvg/dom -I$(top_srcdir)/ksvg/ecma -I$(top_srcdir)/ksvg/data -I$(top_srcdir)/ksvg/impl/libs/art_support -I$(top_srcdir)/ksvg/impl/libs/libtext2path/src $(all_includes) diff --git a/ksvg/impl/SVGAElementImpl.cc b/ksvg/impl/SVGAElementImpl.cc new file mode 100644 index 00000000..153ff5ff --- /dev/null +++ b/ksvg/impl/SVGAElementImpl.cc @@ -0,0 +1,117 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGAElementImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGAnimatedStringImpl.h" + +using namespace KSVG; + +#include "SVGAElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGAElementImpl::SVGAElementImpl(DOM::ElementImpl *impl) : SVGContainerImpl(impl), SVGURIReferenceImpl(), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl() +{ + KSVG_EMPTY_FLAGS + + m_target = new SVGAnimatedStringImpl(); + m_target->ref(); +} + +SVGAElementImpl::~SVGAElementImpl() +{ + if(m_target) + m_target->deref(); +} + +/* +@namespace KSVG +@begin SVGAElementImpl::s_hashTable 2 + target SVGAElementImpl::Target DontDelete|ReadOnly +@end +*/ + +Value SVGAElementImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case Target: + return m_target->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGAElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case Target: + { + if(m_target) + m_target->deref(); + + SVGAnimatedStringImpl *temp = new SVGAnimatedStringImpl(); + temp->ref(); + temp->setBaseVal(value.toString(exec).string()); + setTarget(temp); + break; + } + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +void SVGAElementImpl::setTarget(SVGAnimatedStringImpl *target) +{ + m_target = target; +} + +SVGAnimatedStringImpl *SVGAElementImpl::target() const +{ + return m_target; +} + +SVGAElementImpl *SVGAElementImpl::getLink(SVGElementImpl *sourceElem) +{ + for(DOM::Node node = *sourceElem; !node.isNull(); node = node.parentNode()) + { + SVGElementImpl *elem = sourceElem->ownerDoc()->getElementFromHandle(node.handle()); + if(elem) + { + SVGAElementImpl *link = dynamic_cast(elem); + if(link) + return link; + } + } + + return false; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAElementImpl.h b/ksvg/impl/SVGAElementImpl.h new file mode 100644 index 00000000..2da4c3d4 --- /dev/null +++ b/ksvg/impl/SVGAElementImpl.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAElementImpl_H +#define SVGAElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGTestsImpl.h" +#include "SVGStylableImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGContainerImpl.h" +#include "SVGURIReferenceImpl.h" +#include "SVGTransformableImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + + +namespace KSVG +{ + +class SVGAnimatedStringImpl; +class SVGAElementImpl : public SVGContainerImpl, + public SVGURIReferenceImpl, + public SVGTestsImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGTransformableImpl +{ +public: + SVGAElementImpl(DOM::ElementImpl *); + virtual ~SVGAElementImpl(); + + void setTarget(SVGAnimatedStringImpl *target); + SVGAnimatedStringImpl *target() const; + + static SVGAElementImpl *getLink(SVGElementImpl *sourceElem); + +private: + SVGAnimatedStringImpl *m_target; + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + Target + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGAElementImpl, "a") + +} + +#endif +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAltGlyphDefElementImpl.cc b/ksvg/impl/SVGAltGlyphDefElementImpl.cc new file mode 100644 index 00000000..2a0b5fe9 --- /dev/null +++ b/ksvg/impl/SVGAltGlyphDefElementImpl.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAltGlyphDefElementImpl.h" + +using namespace KSVG; + +SVGAltGlyphDefElementImpl::SVGAltGlyphDefElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl) +{ +} + +SVGAltGlyphDefElementImpl::~SVGAltGlyphDefElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAltGlyphDefElementImpl.h b/ksvg/impl/SVGAltGlyphDefElementImpl.h new file mode 100644 index 00000000..cc1c92f4 --- /dev/null +++ b/ksvg/impl/SVGAltGlyphDefElementImpl.h @@ -0,0 +1,49 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAltGlyphDefElementImpl_H +#define SVGAltGlyphDefElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGElementImpl.h" + +namespace KSVG +{ + +class SVGAltGlyphDefElementImpl : public SVGElementImpl +{ +public: + SVGAltGlyphDefElementImpl(DOM::ElementImpl *); + virtual ~SVGAltGlyphDefElementImpl(); + +public: + KSVG_BRIDGE + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +KSVG_REGISTER_ELEMENT(SVGAltGlyphDefElementImpl, "altGlyphDef") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAltGlyphElementImpl.cc b/ksvg/impl/SVGAltGlyphElementImpl.cc new file mode 100644 index 00000000..d426bd74 --- /dev/null +++ b/ksvg/impl/SVGAltGlyphElementImpl.cc @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGSVGElementImpl.h" +#include "SVGAltGlyphElementImpl.h" + +using namespace KSVG; + +SVGAltGlyphElementImpl::SVGAltGlyphElementImpl(DOM::ElementImpl *impl) : SVGTSpanElementImpl(impl), SVGURIReferenceImpl() +{ +} + +SVGAltGlyphElementImpl::~SVGAltGlyphElementImpl() +{ +} + +void SVGAltGlyphElementImpl::setAttributes() +{ + SVGTSpanElementImpl::setAttributes(); +} + +DOM::DOMString SVGAltGlyphElementImpl::format() +{ + return ""; +} + +DOM::DOMString SVGAltGlyphElementImpl::glyphRef() +{ + return ""; +} + + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAltGlyphElementImpl.h b/ksvg/impl/SVGAltGlyphElementImpl.h new file mode 100644 index 00000000..8dcfe479 --- /dev/null +++ b/ksvg/impl/SVGAltGlyphElementImpl.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAltGlyphElementImpl_H +#define SVGAltGlyphElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGTSpanElementImpl.h" +#include "SVGURIReferenceImpl.h" + +namespace KSVG +{ + +class SVGAltGlyphElementImpl : public SVGTSpanElementImpl, + public SVGURIReferenceImpl +{ +public: + SVGAltGlyphElementImpl(DOM::ElementImpl *); + virtual ~SVGAltGlyphElementImpl(); + virtual void setAttributes(); + + DOM::DOMString glyphRef(); + DOM::DOMString format(); + +public: + KSVG_BRIDGE + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +KSVG_REGISTER_ELEMENT(SVGAltGlyphElementImpl, "altGlyph") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAngleImpl.cc b/ksvg/impl/SVGAngleImpl.cc new file mode 100644 index 00000000..6102329d --- /dev/null +++ b/ksvg/impl/SVGAngleImpl.cc @@ -0,0 +1,277 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGAngle.h" + +#include "SVGAngleImpl.h" + +using namespace KSVG; + +#include "SVGAngleImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_cacheimpl.h" + +const double deg2rad = 0.017453292519943295769; // pi/180 +const double deg2grad = 400.0 / 360.0; +const double rad2grad = deg2grad / deg2rad; + +SVGAngleImpl::SVGAngleImpl() +{ + KSVG_EMPTY_FLAGS + + m_unitType = SVG_ANGLETYPE_UNKNOWN; + m_valueInSpecifiedUnits = 0; + m_value = 0; +} + +SVGAngleImpl::~SVGAngleImpl() +{ +} + +unsigned short SVGAngleImpl::unitType() const +{ + return m_unitType; +} + +void SVGAngleImpl::setValue(float value) +{ + m_value = value; +} + +float SVGAngleImpl::value() const +{ + return m_value; +} + +// calc m_value +void SVGAngleImpl::calculate() +{ + if(m_unitType == SVG_ANGLETYPE_GRAD) + m_value = m_valueInSpecifiedUnits / deg2grad; + else if(m_unitType == SVG_ANGLETYPE_RAD) + m_value = m_valueInSpecifiedUnits / deg2rad; + else if(m_unitType == SVG_ANGLETYPE_UNSPECIFIED || m_unitType == SVG_ANGLETYPE_DEG) + m_value = m_valueInSpecifiedUnits; +} + +void SVGAngleImpl::setValueInSpecifiedUnits(float valueInSpecifiedUnits) +{ + m_valueInSpecifiedUnits = valueInSpecifiedUnits; + calculate(); +} + +float SVGAngleImpl::valueInSpecifiedUnits() const +{ + return m_valueInSpecifiedUnits; +} + +void SVGAngleImpl::setValueAsString(const DOM::DOMString &valueAsString) +{ + m_valueAsString = valueAsString; + + QString s = valueAsString.string(); + + bool bOK; + m_valueInSpecifiedUnits = s.toFloat(&bOK); + m_unitType = SVG_ANGLETYPE_UNSPECIFIED; + + if(!bOK) + { + if(s.endsWith("deg")) + m_unitType = SVG_ANGLETYPE_DEG; + else if(s.endsWith("grad")) + m_unitType = SVG_ANGLETYPE_GRAD; + else if(s.endsWith("rad")) + m_unitType = SVG_ANGLETYPE_RAD; + } + + calculate(); +} + +DOM::DOMString SVGAngleImpl::valueAsString() const +{ + m_valueAsString.string().setNum(m_valueInSpecifiedUnits); + + switch(m_unitType) + { + case SVG_ANGLETYPE_UNSPECIFIED: + case SVG_ANGLETYPE_DEG: + m_valueAsString.string() += "deg"; + break; + case SVG_ANGLETYPE_RAD: + m_valueAsString.string() += "rad"; + break; + case SVG_ANGLETYPE_GRAD: + m_valueAsString.string() += "grad"; + break; + } + + return m_valueAsString; +} + +void SVGAngleImpl::newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits) +{ + m_unitType = unitType; + m_valueInSpecifiedUnits = valueInSpecifiedUnits; + calculate(); +} + +void SVGAngleImpl::convertToSpecifiedUnits(unsigned short unitType) +{ + if(m_unitType == unitType) + return; + + if(m_unitType == SVG_ANGLETYPE_DEG && unitType == SVG_ANGLETYPE_RAD) + m_valueInSpecifiedUnits *= deg2rad; + else if(m_unitType == SVG_ANGLETYPE_GRAD && unitType == SVG_ANGLETYPE_RAD) + m_valueInSpecifiedUnits /= rad2grad; + else if(m_unitType == SVG_ANGLETYPE_DEG && unitType == SVG_ANGLETYPE_GRAD) + m_valueInSpecifiedUnits *= deg2grad; + else if(m_unitType == SVG_ANGLETYPE_RAD && unitType == SVG_ANGLETYPE_GRAD) + m_valueInSpecifiedUnits *= rad2grad; + else if(m_unitType == SVG_ANGLETYPE_RAD && unitType == SVG_ANGLETYPE_DEG) + m_valueInSpecifiedUnits /= deg2rad; + else if(m_unitType == SVG_ANGLETYPE_GRAD && unitType == SVG_ANGLETYPE_DEG) + m_valueInSpecifiedUnits /= deg2grad; + + m_unitType = unitType; +} + +// Helpers +double SVGAngleImpl::todeg(double rad) +{ + return rad / deg2rad; +} + +double SVGAngleImpl::torad(double deg) +{ + return deg * deg2rad; +} + +double SVGAngleImpl::shortestArcBisector(double angle1, double angle2) +{ + double bisector = (angle1 + angle2) / 2; + + if(fabs(angle1 - angle2) > 180) + bisector += 180; + + return bisector; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGAngleImpl::s_hashTable 5 + value SVGAngleImpl::Value DontDelete + valueInSpecifiedUnits SVGAngleImpl::ValueInSpecifiedUnits DontDelete + valueAsString SVGAngleImpl::ValueAsString DontDelete + unitType SVGAngleImpl::UnitType DontDelete +@end +@namespace KSVG +@begin SVGAngleImplProto::s_hashTable 3 + convertToSpecifiedUnits SVGAngleImpl::ConvertToSpecifiedUnits DontDelete|Function 1 + newValueSpecifiedUnits SVGAngleImpl::NewValueSpecifiedUnits DontDelete|Function 2 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGAngle", SVGAngleImplProto, SVGAngleImplProtoFunc) + +Value SVGAngleImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case Value: + return Number(value()); + case ValueInSpecifiedUnits: + return Number(valueInSpecifiedUnits()); + case ValueAsString: + return String(valueAsString().string()); + case UnitType: + return Number(unitType()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGAngleImpl::putValueProperty(ExecState *exec, int token, const KJS::Value &value, int) +{ + switch(token) + { + case Value: + setValue(value.toNumber(exec)); + break; + case ValueInSpecifiedUnits: + setValueInSpecifiedUnits(value.toNumber(exec)); + break; + case ValueAsString: + setValueAsString(value.toString(exec).string()); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +Value SVGAngleImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGAngleImpl) + + switch(id) + { + case SVGAngleImpl::ConvertToSpecifiedUnits: + obj->convertToSpecifiedUnits(static_cast(args[0].toNumber(exec))); + break; + case SVGAngleImpl::NewValueSpecifiedUnits: + obj->newValueSpecifiedUnits(static_cast(args[0].toNumber(exec)), args[1].toNumber(exec)); + break; + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + +/* +@namespace KSVG +@begin SVGAngleImplConstructor::s_hashTable 7 + SVG_ANGLETYPE_UNKNOWN KSVG::SVG_ANGLETYPE_UNKNOWN DontDelete|ReadOnly + SVG_ANGLETYPE_UNSPECIFIED KSVG::SVG_ANGLETYPE_UNSPECIFIED DontDelete|ReadOnly + SVG_ANGLETYPE_RAD KSVG::SVG_ANGLETYPE_RAD DontDelete|ReadOnly + SVG_ANGLETYPE_DEG KSVG::SVG_ANGLETYPE_DEG DontDelete|ReadOnly + SVG_ANGLETYPE_GRAD KSVG::SVG_ANGLETYPE_GRAD DontDelete|ReadOnly +@end +*/ + +Value SVGAngleImplConstructor::getValueProperty(ExecState *, int token) const +{ + return Number(token); +} + +Value KSVG::getSVGAngleImplConstructor(ExecState *exec) +{ + return cacheGlobalBridge(exec, "[[svgangle.constructor]]"); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAngleImpl.h b/ksvg/impl/SVGAngleImpl.h new file mode 100644 index 00000000..d3c656de --- /dev/null +++ b/ksvg/impl/SVGAngleImpl.h @@ -0,0 +1,102 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAngleImpl_H +#define SVGAngleImpl_H + +#include +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAngleImpl : public DOM::DomShared +{ +public: + SVGAngleImpl(); + virtual ~SVGAngleImpl(); + + unsigned short unitType() const; + + void setValue(float value); + float value() const; + + void setValueInSpecifiedUnits(float valueInSpecifiedUnits); + float valueInSpecifiedUnits() const; + + void setValueAsString(const DOM::DOMString &valueAsString); + DOM::DOMString valueAsString() const; + + void newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits); + void convertToSpecifiedUnits(unsigned short unitType); + + // Helpers + static double todeg(double rad); + static double torad(double deg); + + // Returns the angle that divides the shortest arc between the two angles. + static double shortestArcBisector(double angle1, double angle2); + +private: + unsigned short m_unitType; + float m_value; + float m_valueInSpecifiedUnits; + DOM::DOMString m_valueAsString; + + void calculate(); + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + Value, ValueInSpecifiedUnits, ValueAsString, UnitType, + // Functions + ConvertToSpecifiedUnits, NewValueSpecifiedUnits + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +class SVGAngleImplConstructor : public KJS::ObjectImp +{ +public: + SVGAngleImplConstructor(KJS::ExecState *) { } + KJS::Value getValueProperty(KJS::ExecState *, int token) const; + + // no put - all read-only + KSVG_GET +}; + +KJS::Value getSVGAngleImplConstructor(KJS::ExecState *exec); + +} + +KSVG_DEFINE_PROTOTYPE(SVGAngleImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGAngleImplProtoFunc, SVGAngleImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimateColorElementImpl.cc b/ksvg/impl/SVGAnimateColorElementImpl.cc new file mode 100644 index 00000000..c4cc0ad4 --- /dev/null +++ b/ksvg/impl/SVGAnimateColorElementImpl.cc @@ -0,0 +1,98 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include + +#include "SVGColorImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGStylableImpl.h" +#include "SVGAnimateColorElementImpl.h" + +using namespace KSVG; + +SVGAnimateColorElementImpl::SVGAnimateColorElementImpl(DOM::ElementImpl *impl) : SVGAnimationElementImpl(impl) +{ + m_fromColor = new SVGColorImpl(this); + m_fromColor->ref(); + + m_toColor = new SVGColorImpl(this); + m_toColor->ref(); +} + +SVGAnimateColorElementImpl::~SVGAnimateColorElementImpl() +{ + m_fromColor->deref(); + m_toColor->deref(); +} + +/* + * Outstanding issues + * - 'values' support + * - 'by' support + */ + +void SVGAnimateColorElementImpl::setAttributes() +{ + SVGAnimationElementImpl::setAttributes(); + + SVGStylableImpl::setColor(getFrom(), m_fromColor); + SVGStylableImpl::setColor(getTo(), m_toColor); + + ownerDoc()->timeScheduler()->addTimer(this, int(getStartTime() * 1000.0)); +} + +void SVGAnimateColorElementImpl::handleTimerEvent() +{ + if(!m_connected) + { + double duration = getSimpleDuration() * 1000.0; + double dinterval = SVGTimeScheduler::staticTimerInterval; + + m_step = 0; + m_steps = (int) rint(duration / dinterval); + + m_connected = true; + ownerDoc()->timeScheduler()->connectIntervalTimer(this); + } + else + { + QColor fromColor(m_fromColor->rgbColor().color()); + QColor toColor(m_toColor->rgbColor().color()); + + int red = (int) rint(((toColor.red() - fromColor.red()) / static_cast(m_steps)) * m_step + fromColor.red()); + int green = (int) rint(((toColor.green() - fromColor.green()) / static_cast(m_steps)) * m_step + fromColor.green()); + int blue = (int) rint(((toColor.blue() - fromColor.blue()) / static_cast(m_steps)) * m_step + fromColor.blue()); + + QString color = "rgb(" + QString::number(red) + "," + QString::number(green) + "," + QString::number(blue) + ")"; + applyAttribute(getAttributeName(), color); + } + + if(m_step < m_steps) + m_step++; + else + { + ownerDoc()->timeScheduler()->disconnectIntervalTimer(this); + m_connected = false; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimateColorElementImpl.h b/ksvg/impl/SVGAnimateColorElementImpl.h new file mode 100644 index 00000000..2832802e --- /dev/null +++ b/ksvg/impl/SVGAnimateColorElementImpl.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimateColorElementImpl_H +#define SVGAnimateColorElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGAnimationElementImpl.h" + +class QTimer; + +namespace KSVG +{ + +class SVGColorImpl; +class SVGAnimateColorElementImpl : public SVGAnimationElementImpl +{ +public: + SVGAnimateColorElementImpl(DOM::ElementImpl *); + virtual ~SVGAnimateColorElementImpl(); + + virtual void handleTimerEvent(); + virtual void setAttributes(); + +private: + SVGColorImpl *m_toColor, *m_fromColor; + + int m_steps, m_step; + +public: + KSVG_BRIDGE + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +KSVG_REGISTER_ELEMENT(SVGAnimateColorElementImpl, "animateColor") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimateElementImpl.cc b/ksvg/impl/SVGAnimateElementImpl.cc new file mode 100644 index 00000000..ab9bc52c --- /dev/null +++ b/ksvg/impl/SVGAnimateElementImpl.cc @@ -0,0 +1,191 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGDocumentImpl.h" +#include "SVGAnimateElementImpl.h" + +using namespace KSVG; + +SVGAnimateElementImpl::SVGAnimateElementImpl(DOM::ElementImpl *impl) : SVGAnimationElementImpl(impl) +{ + m_animVal = 0.0; + m_addStep = 0.0; +} + +SVGAnimateElementImpl::~SVGAnimateElementImpl() +{ +} + +void SVGAnimateElementImpl::setAttributes() +{ + SVGAnimationElementImpl::setAttributes(); + + ownerDoc()->timeScheduler()->addTimer(this, int(getStartTime() * 1000.0)); +} + +void SVGAnimateElementImpl::handleTimerEvent() +{ + if(!m_connected) + { + double duration = getSimpleDuration() * 1000.0; + double dinterval = SVGTimeScheduler::staticTimerInterval; + + m_step = 0; + m_steps = (int) rint(duration / dinterval); + + double to = 0, from = 0; + if(getTo().isEmpty()) + to = targetElement()->getAttribute(getAttributeName()).string().toDouble(); + else + to = getTo().toDouble(); + + if(getFrom().isEmpty()) + from = targetElement()->getAttribute(getAttributeName()).string().toDouble(); + else + from = getFrom().toDouble(); + + // 'by' support + if(!getBy().isEmpty()) + { + m_animVal = from; + m_addStep = getBy().toDouble() / m_steps; + } + else + { + m_animVal = from; + m_addStep = (to - m_animVal) / m_steps; + } + + m_connected = true; + ownerDoc()->timeScheduler()->connectIntervalTimer(this); + } + else + { + m_animVal += m_addStep; + applyAttribute(getAttributeName(), QString::number(m_animVal)); + } + + if(m_step < m_steps) + m_step++; + else + { + ownerDoc()->timeScheduler()->disconnectIntervalTimer(this); + m_connected = false; + if(m_fill == REMOVE) + applyAttribute(getAttributeName(), targetElement()->getAttribute(getAttributeName()).string()); + } + +#if 0 + m_attributeTimer = addTimer(interval() * 1000, false); + + + /* + m_steps = (getSimpleDuration() * 1000) / SVGAnimationElementImpl::timerTime; + m_step = 0; + + if(m_additive == "sum" && m_times == 1 && !needCombine) + { + float add; + + SVGLengthImpl *temp = new SVGLengthImpl(); + temp->ref(); + temp->setValueAsString(targetElement()->getAttribute(m_attributeName).string()); + add = temp->value(); + temp->deref(); + + m_from += add; + m_newFrom += add; + m_to += add; + m_newTo += add; + + m_additiveAdded = add; + } + + m_addStep = (m_to - m_from) / m_steps; + m_attributeTimer = addTimer(SVGAnimationElementImpl::timerTime, false);*/ + } + else + { +/* m_from += m_addStep; + + if(m_additive == "replace" && needCombine) + needCombine = false; + + applyAttribute(m_attributeName, QString::number(m_from), needCombine); + + m_step++; + + if(m_step == m_steps) + { + removeTimer(m_attributeTimer); + + if(getRepeatDuration() == "indefinite" || getRepeatCount() == "indefinite") + { + m_times++; + m_firstEvent = true; + + if(m_accumulate != "sum") + { + m_from = m_newFrom; + m_to = m_newTo; + } + else + { + m_from += (m_newFrom - m_additiveAdded) / 2; + m_to += (m_newTo - m_additiveAdded) / 2; + } + + m_addStep = 0; + m_attributeTimer = 0; + + addTimer(1); + } + else if(!getRepeatCount().isEmpty()) + { + if(m_times <= getRepeatCount().toInt()) + { + m_times++; + m_firstEvent = true; + + if(m_accumulate != "sum") + { + m_from = m_newFrom; + m_to = m_newTo; + } + else + { + m_from += (m_newFrom - m_additiveAdded) / 2; + m_to += (m_newTo - m_additiveAdded) / 2; + } + + m_addStep = 0; + m_attributeTimer = 0; + + addTimer(1); + } + } + }*/ + } +#endif // 0 +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimateElementImpl.h b/ksvg/impl/SVGAnimateElementImpl.h new file mode 100644 index 00000000..855ced6e --- /dev/null +++ b/ksvg/impl/SVGAnimateElementImpl.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimateElementImpl_H +#define SVGAnimateElementImpl_H + +#include "ksvg_lookup.h" +#include "SVGAnimationElementImpl.h" + +class QTimer; + +namespace KSVG +{ + +class SVGAnimateElementImpl : public SVGAnimationElementImpl +{ +public: + SVGAnimateElementImpl(DOM::ElementImpl *); + virtual ~SVGAnimateElementImpl(); + + virtual void handleTimerEvent(); + virtual void setAttributes(); + +private: + double m_addStep, m_animVal; + QTimer *m_timer; + + int m_steps, m_step; + +public: + KSVG_BRIDGE + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +KSVG_REGISTER_ELEMENT(SVGAnimateElementImpl, "animate") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimateMotionElementImpl.cc b/ksvg/impl/SVGAnimateMotionElementImpl.cc new file mode 100644 index 00000000..ce756d55 --- /dev/null +++ b/ksvg/impl/SVGAnimateMotionElementImpl.cc @@ -0,0 +1,102 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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. +*/ + +// TODO: CLEANUP + +#include +#include "SVGDocumentImpl.h" +#include "SVGPathElementImpl.h" +#include "SVGAnimateMotionElementImpl.h" + +using namespace KSVG; + +SVGAnimateMotionElementImpl::SVGAnimateMotionElementImpl(DOM::ElementImpl *impl) : SVGAnimationElementImpl(impl) +{ +} + +SVGAnimateMotionElementImpl::~SVGAnimateMotionElementImpl() +{ +} + +void SVGAnimateMotionElementImpl::setAttributes() +{ + SVGAnimationElementImpl::setAttributes(); + +/* + // TODO: rotate.. + + DOM::DOMString _path = getAttribute("path"); + if(!_path.isNull()) + { + if(m_path) + m_path->deref(); + + m_path = new SVGPathElementImpl(reinterpret_cast(static_cast(ownerDoc())->createElement("path").handle())); + m_path->setOwnerDoc(ownerDoc()); + m_path->setAttribute("d", _path); + m_path->setAttributes(); + } + + addTimer(int(getStartTime() * 1000));*/ +} + +//void SVGAnimateMotionElementImpl::prerender(KSVGPainter *p) +//{ +// SVGAnimationElementImpl::prerender(p); + +/* if(!m_pathArray) + { + bool temp; + m_pathArray = m_path->preparePath(&temp, p->worldMatrix()); + }*/ +//} + +void SVGAnimateMotionElementImpl::handleTimerEvent(bool /*needCombine*/) +{ +/* if(m_firstEvent) + { + m_firstEvent = false; + + m_steps = (int) (getSimpleDuration() * 1000) / interval(); + m_step = 0; + + m_motionTimer = addTimer(interval() * 1000, false); + } + else + { + m_step++; + + if(m_step <= m_pathArray->count() - 1) + { + QPoint p = m_pathArray->point(m_step - 50); + applyAttribute("x", QString::number(p.x())); + applyAttribute("y", QString::number(p.y())); + kdDebug() << " X " << p.x() << " Y " << p.y() << " (" << m_pathArray->count() << "; " << m_step << ")" < + +#include "SVGLengthImpl.h" +#include "SVGHelperImpl.h" +#include "SVGTransformImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGTransformListImpl.h" +#include "SVGAnimatedTransformListImpl.h" +#include "SVGAnimateTransformElementImpl.h" + +using namespace KSVG; + +SVGAnimateTransformElementImpl::SVGAnimateTransformElementImpl(DOM::ElementImpl *impl) : SVGAnimationElementImpl(impl) +{ + m_firstEvent = true; + m_setAttributes = false; + + m_rotateX = -1; + m_rotateY = -1; + m_times = 1; + m_from = 0; + m_to = 0; + + m_addStep = 0; +} + +SVGAnimateTransformElementImpl::~SVGAnimateTransformElementImpl() +{ +} + +void SVGAnimateTransformElementImpl::setAttributes() +{ + if(m_setAttributes) + return; + + m_setAttributes = true; + + SVGAnimationElementImpl::setAttributes(); + + /* + // TODO: much :) + + DOM::DOMString _type = getAttribute("type"); + if(!_type.isNull()) + m_type = _type.string().lower(); + + DOM::DOMString _from = getAttribute("from"); + if(!_from.isNull()) + { + if(m_type != "rotate") + { + SVGLengthImpl *temp = SVGSVGElementImpl::createSVGLength(); + temp->setValueAsString(_from.string()); + + m_from = temp->value(); + + temp->deref(); + } + else + { + SVGTransformListImpl *list = new SVGTransformListImpl(); + list->ref(); + + SVGHelperImpl::parseTransformAttribute(list, m_type + "(" + _from.string() + ")"); + + m_from = list->getFirst()->angle(); + + QStringList stringList = QStringList::split(' ', list->getFirst()->toString()); + m_rotateX = stringList[1].toInt(); + m_rotateY = stringList[2].mid(0, stringList[2].length() - 1).toInt(); + + list->deref(); + } + + m_newFrom = m_from; + m_addStep = m_from; + } + + DOM::DOMString _to = getAttribute("to"); + if(!_to.isNull()) + { + if(m_type != "rotate") + { + SVGLengthImpl *temp = SVGSVGElementImpl::createSVGLength(); + temp->setValueAsString(_to.string()); + + m_to = temp->value(); + + temp->deref(); + } + else + { + SVGTransformListImpl *list = new SVGTransformListImpl(); + list->ref(); + + SVGHelperImpl::parseTransformAttribute(list, m_type + "(" + _to.string() + ")"); + + m_to = list->getFirst()->angle(); + + list->deref(); + } + + m_newTo = m_to; + } + + // TODO: values + rotate including cx + cy + DOM::DOMString _values = getAttribute("values"); + if(!_values.isNull()) + { + QString test = _values.string(); + + if(test.contains(";")) + { + SVGLengthImpl *temp = SVGSVGElementImpl::createSVGLength(); + + QStringList list = QStringList::split(';', test); + temp->setValueAsString(list[0]); + m_from = temp->value(); + temp->setValueAsString(list[1]); + m_to = temp->value(); + + m_newFrom = m_from; + m_newTo = m_to; + m_addStep = m_from; + + temp->deref(); + } + } + + if(getStartTime() != -1) + addTimer(int(getStartTime() * 1000)); + else + addTimer(1); + */ +} + +void SVGAnimateTransformElementImpl::handleTimerEvent(bool) +{ /* + if(m_firstEvent) + { + m_firstEvent = false; + + m_steps = (int) (getSimpleDuration() * 1000) / interval(); + m_step = 0; + + m_addStep = (m_to - m_from) / m_steps; + + m_transformTimer = addTimer(interval() * 1000, false); + } + else + { + m_from += m_addStep; + + SVGTransformImpl *transform = SVGSVGElementImpl::createSVGTransform(); + + if(m_type == "rotate") + { + int x = 0, y = 0; + + if(m_rotateX != -1) + x = m_rotateX; + + if(m_rotateY != -1) + y = m_rotateY; + + transform->setRotate(m_from, x, y); + } + else if(m_type == "scale") + transform->setScale(m_from, m_from); + else if(m_type == "skewx") + transform->setSkewX(m_from); + else if(m_type == "skewy") + transform->setSkewY(m_from); + + QString trans = transform->toString(); + QString last = trans; + + if(targetElement()->hasAttribute("transform")) + { + trans += " " + targetElement()->getAttribute("transform").string(); + + if(!m_lastTransform.isEmpty()) + { + int pos = trans.find(m_lastTransform); + + QString extract; + extract += trans.mid(0, pos); + extract += trans.mid(pos + m_lastTransform.length() + 1, trans.length()); + + trans = extract; + } + } + + m_lastTransform = last; + + transform->deref(); + + applyAttribute("transform", trans); + + m_step++; + + if(m_step == m_steps) + { + removeTimer(m_transformTimer); + + if(getRepeatDuration() == "indefinite" || getRepeatCount() == "indefinite") + { + m_firstEvent = true; + m_from = m_newFrom; + m_to = m_newTo; + + m_addStep = 0; + m_transformTimer = 0; + + addTimer(1); + } + else if(!getRepeatCount().isEmpty()) + { + if(m_times <= getRepeatCount().toInt()) + { + m_times++; + m_firstEvent = true; + m_from = m_newFrom; + m_to = m_newTo; + + m_addStep = 0; + m_transformTimer = 0; + + addTimer(1); + } + } + } + } + */ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimateTransformElementImpl.h b/ksvg/impl/SVGAnimateTransformElementImpl.h new file mode 100644 index 00000000..7e6e2653 --- /dev/null +++ b/ksvg/impl/SVGAnimateTransformElementImpl.h @@ -0,0 +1,74 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimateTransformElementImpl_H +#define SVGAnimateTransformElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGAnimationElementImpl.h" + +class QTimer; + +namespace KSVG +{ + +class SVGTransformImpl; +class SVGTransformListImpl; +class SVGAnimateTransformElementImpl : public SVGAnimationElementImpl +{ +public: + SVGAnimateTransformElementImpl(DOM::ElementImpl *); + virtual ~SVGAnimateTransformElementImpl(); + + virtual void handleTimerEvent(bool needCombine = false); + virtual void setAttributes(); + +private: + QString m_type, m_lastTransform; + + int m_times; + + int m_rotateX, m_rotateY; + + int m_steps, m_step; + + double m_from, m_to, m_newFrom, m_newTo; + double m_addStep; + + QTimer *m_transformTimer; + SVGTransformListImpl *m_transformList; + + bool m_firstEvent; + bool m_setAttributes; + +public: + KSVG_BRIDGE + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +KSVG_REGISTER_ELEMENT(SVGAnimateTransformElementImpl, "animateTransform") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedAngleImpl.cc b/ksvg/impl/SVGAnimatedAngleImpl.cc new file mode 100644 index 00000000..63f0c000 --- /dev/null +++ b/ksvg/impl/SVGAnimatedAngleImpl.cc @@ -0,0 +1,83 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGAngleImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGAnimatedAngleImpl.h" + +using namespace KSVG; + +#include "SVGAnimatedAngleImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGAnimatedAngleImpl::SVGAnimatedAngleImpl() : DOM::DomShared() +{ + KSVG_EMPTY_FLAGS + + m_baseVal = SVGSVGElementImpl::createSVGAngle(); + m_animVal = SVGSVGElementImpl::createSVGAngle(); +} + +SVGAnimatedAngleImpl::~SVGAnimatedAngleImpl() +{ + if(m_baseVal) + m_baseVal->deref(); + if(m_animVal) + m_animVal->deref(); +} + +SVGAngleImpl *SVGAnimatedAngleImpl::baseVal() const +{ + return m_baseVal; +} + +SVGAngleImpl *SVGAnimatedAngleImpl::animVal() const +{ + return m_animVal; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGAnimatedAngleImpl::s_hashTable 3 + baseVal SVGAnimatedAngleImpl::BaseVal DontDelete|ReadOnly + animVal SVGAnimatedAngleImpl::AnimVal DontDelete|ReadOnly +@end +*/ + +Value SVGAnimatedAngleImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case BaseVal: + return m_baseVal->cache(exec); + case AnimVal: + return m_animVal->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedAngleImpl.h b/ksvg/impl/SVGAnimatedAngleImpl.h new file mode 100644 index 00000000..f6617ce6 --- /dev/null +++ b/ksvg/impl/SVGAnimatedAngleImpl.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedAngleImpl_H +#define SVGAnimatedAngleImpl_H + +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAngleImpl; +class SVGAnimatedAngleImpl : public DOM::DomShared +{ +public: + SVGAnimatedAngleImpl(); + virtual ~SVGAnimatedAngleImpl(); + + SVGAngleImpl *baseVal() const; + SVGAngleImpl *animVal() const; + +private: + SVGAngleImpl *m_baseVal; + SVGAngleImpl *m_animVal; + +public: + KSVG_GET + + enum + { + // Properties + BaseVal, AnimVal + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedBooleanImpl.cc b/ksvg/impl/SVGAnimatedBooleanImpl.cc new file mode 100644 index 00000000..d30fa5ef --- /dev/null +++ b/ksvg/impl/SVGAnimatedBooleanImpl.cc @@ -0,0 +1,93 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGAnimatedBooleanImpl.h" + +using namespace KSVG; + +#include "SVGAnimatedBooleanImpl.lut.h" +#include "ksvg_bridge.h" + +SVGAnimatedBooleanImpl::SVGAnimatedBooleanImpl() : DOM::DomShared() +{ + KSVG_EMPTY_FLAGS + + m_baseVal = false; + m_animVal = false; +} + +SVGAnimatedBooleanImpl::~SVGAnimatedBooleanImpl() +{ +} + +void SVGAnimatedBooleanImpl::setBaseVal(bool baseVal) +{ + m_baseVal = baseVal; +} + +bool SVGAnimatedBooleanImpl::baseVal() const +{ + return m_baseVal; +} + +bool SVGAnimatedBooleanImpl::animVal() const +{ + return m_animVal; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGAnimatedBooleanImpl::s_hashTable 3 + baseVal SVGAnimatedBooleanImpl::BaseVal DontDelete + animVal SVGAnimatedBooleanImpl::AnimVal DontDelete|ReadOnly +@end +*/ + +Value SVGAnimatedBooleanImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case BaseVal: + return Number(baseVal()); + case AnimVal: + return Number(animVal()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGAnimatedBooleanImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int) +{ + switch(token) + { + case BaseVal: + setBaseVal(value.toBoolean(exec)); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedBooleanImpl.h b/ksvg/impl/SVGAnimatedBooleanImpl.h new file mode 100644 index 00000000..9e31792e --- /dev/null +++ b/ksvg/impl/SVGAnimatedBooleanImpl.h @@ -0,0 +1,64 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedBooleanImpl_H +#define SVGAnimatedBooleanImpl_H + +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedBooleanImpl : public DOM::DomShared +{ +public: + SVGAnimatedBooleanImpl(); + virtual ~SVGAnimatedBooleanImpl(); + + void setBaseVal(bool baseVal); + bool baseVal() const; + + bool animVal() const; + +private: + bool m_baseVal; + bool m_animVal; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + BaseVal, AnimVal + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedEnumerationImpl.cc b/ksvg/impl/SVGAnimatedEnumerationImpl.cc new file mode 100644 index 00000000..f619f231 --- /dev/null +++ b/ksvg/impl/SVGAnimatedEnumerationImpl.cc @@ -0,0 +1,93 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGAnimatedEnumerationImpl.h" + +using namespace KSVG; + +#include "SVGAnimatedEnumerationImpl.lut.h" +#include "ksvg_bridge.h" + +SVGAnimatedEnumerationImpl::SVGAnimatedEnumerationImpl() : DOM::DomShared() +{ + KSVG_EMPTY_FLAGS + + m_baseVal = 0; + m_animVal = 0; +} + +SVGAnimatedEnumerationImpl::~SVGAnimatedEnumerationImpl() +{ +} + +void SVGAnimatedEnumerationImpl::setBaseVal(unsigned short baseVal) +{ + m_baseVal = baseVal; +} + +unsigned short SVGAnimatedEnumerationImpl::baseVal() const +{ + return m_baseVal; +} + +unsigned short SVGAnimatedEnumerationImpl::animVal() const +{ + return m_animVal; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGAnimatedEnumerationImpl::s_hashTable 3 + baseVal SVGAnimatedEnumerationImpl::BaseVal DontDelete + animVal SVGAnimatedEnumerationImpl::AnimVal DontDelete|ReadOnly +@end +*/ + +Value SVGAnimatedEnumerationImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case BaseVal: + return Number(baseVal()); + case AnimVal: + return Number(animVal()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGAnimatedEnumerationImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int) +{ + switch(token) + { + case BaseVal: + setBaseVal(static_cast(value.toNumber(exec))); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedEnumerationImpl.h b/ksvg/impl/SVGAnimatedEnumerationImpl.h new file mode 100644 index 00000000..ae4638f4 --- /dev/null +++ b/ksvg/impl/SVGAnimatedEnumerationImpl.h @@ -0,0 +1,64 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedEnumerationImpl_H +#define SVGAnimatedEnumerationImpl_H + +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedEnumerationImpl : public DOM::DomShared +{ +public: + SVGAnimatedEnumerationImpl(); + virtual ~SVGAnimatedEnumerationImpl(); + + void setBaseVal(unsigned short baseVal); + unsigned short baseVal() const; + + unsigned short animVal() const; + +private: + unsigned short m_baseVal; + unsigned short m_animVal; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + BaseVal, AnimVal + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedIntegerImpl.cc b/ksvg/impl/SVGAnimatedIntegerImpl.cc new file mode 100644 index 00000000..8bf08a87 --- /dev/null +++ b/ksvg/impl/SVGAnimatedIntegerImpl.cc @@ -0,0 +1,91 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGAnimatedIntegerImpl.h" + +using namespace KSVG; + +#include "SVGAnimatedIntegerImpl.lut.h" +#include "ksvg_bridge.h" + +SVGAnimatedIntegerImpl::SVGAnimatedIntegerImpl() : DOM::DomShared() +{ + KSVG_EMPTY_FLAGS + + m_baseVal = 0; + m_animVal = 0; +} + +SVGAnimatedIntegerImpl::~SVGAnimatedIntegerImpl() +{ +} + +void SVGAnimatedIntegerImpl::setBaseVal(long baseVal) +{ + m_baseVal = baseVal; +} + +long SVGAnimatedIntegerImpl::baseVal() const +{ + return m_baseVal; +} + +long SVGAnimatedIntegerImpl::animVal() const +{ + return m_animVal; +} + +/* +@namespace KSVG +@begin SVGAnimatedIntegerImpl::s_hashTable 3 + baseVal SVGAnimatedIntegerImpl::BaseVal DontDelete + animVal SVGAnimatedIntegerImpl::AnimVal DontDelete +@end +*/ + +Value SVGAnimatedIntegerImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case BaseVal: + return Number(baseVal()); + case AnimVal: + return Number(animVal()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } + return KJS::Undefined(); +} + +void SVGAnimatedIntegerImpl::putValueProperty(ExecState *exec, int token, const KJS::Value &value, int) +{ + switch(token) + { + case BaseVal: + setBaseVal(value.toInteger(exec)); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedIntegerImpl.h b/ksvg/impl/SVGAnimatedIntegerImpl.h new file mode 100644 index 00000000..8ad7ad88 --- /dev/null +++ b/ksvg/impl/SVGAnimatedIntegerImpl.h @@ -0,0 +1,64 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedIntegerImpl_H +#define SVGAnimatedIntegerImpl_H + +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedIntegerImpl : public DOM::DomShared +{ +public: + SVGAnimatedIntegerImpl(); + virtual ~SVGAnimatedIntegerImpl(); + + void setBaseVal(long baseVal); + long baseVal() const; + + long animVal() const; + +private: + long m_baseVal; + long m_animVal; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + BaseVal, AnimVal + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedLengthImpl.cc b/ksvg/impl/SVGAnimatedLengthImpl.cc new file mode 100644 index 00000000..25176965 --- /dev/null +++ b/ksvg/impl/SVGAnimatedLengthImpl.cc @@ -0,0 +1,96 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGAnimatedLengthImpl.h" +#include "SVGElementImpl.h" + +using namespace KSVG; + +#include "SVGAnimatedLengthImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGAnimatedLengthImpl::SVGAnimatedLengthImpl(LengthMode mode, SVGElementImpl *object) : DOM::DomShared() +{ + m_baseVal = new SVGLengthImpl(mode, object); + m_baseVal->ref(); + + m_animVal = new SVGLengthImpl(mode, object); + m_animVal->ref(); +} + +SVGAnimatedLengthImpl::SVGAnimatedLengthImpl(const SVGAnimatedLengthImpl &other) : DOM::DomShared() +{ + (*this) = other; +} + +SVGAnimatedLengthImpl::~SVGAnimatedLengthImpl() +{ + if(m_baseVal) + m_baseVal->deref(); + if(m_animVal) + m_animVal->deref(); +} + +SVGAnimatedLengthImpl &SVGAnimatedLengthImpl::operator=(const SVGAnimatedLengthImpl &other) +{ + *m_baseVal = *(other.m_baseVal); + *m_animVal = *(other.m_animVal); + + return *this; +} + +SVGLengthImpl *SVGAnimatedLengthImpl::baseVal() const +{ + return m_baseVal; +} + +SVGLengthImpl *SVGAnimatedLengthImpl::animVal() const +{ + return m_animVal; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGAnimatedLengthImpl::s_hashTable 3 + baseVal SVGAnimatedLengthImpl::BaseVal DontDelete|ReadOnly + animVal SVGAnimatedLengthImpl::AnimVal DontDelete|ReadOnly +@end +*/ + +Value SVGAnimatedLengthImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case BaseVal: + return m_baseVal->cache(exec); + case AnimVal: + return m_animVal->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedLengthImpl.h b/ksvg/impl/SVGAnimatedLengthImpl.h new file mode 100644 index 00000000..80f473db --- /dev/null +++ b/ksvg/impl/SVGAnimatedLengthImpl.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedLengthImpl_H +#define SVGAnimatedLengthImpl_H + +#include + +#include "SVGLengthImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ +class SVGElementImpl; +class SVGAnimatedLengthImpl : public DOM::DomShared +{ +public: + SVGAnimatedLengthImpl(LengthMode mode = LENGTHMODE_UNKNOWN, SVGElementImpl *object = 0); + SVGAnimatedLengthImpl(const SVGAnimatedLengthImpl &); + virtual ~SVGAnimatedLengthImpl(); + + SVGAnimatedLengthImpl &operator=(const SVGAnimatedLengthImpl &); + + SVGLengthImpl *baseVal() const; + SVGLengthImpl *animVal() const; + +private: + SVGLengthImpl *m_baseVal; + SVGLengthImpl *m_animVal; + +public: + KSVG_GET + + enum + { + // Properties + BaseVal, AnimVal + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedLengthListImpl.cc b/ksvg/impl/SVGAnimatedLengthListImpl.cc new file mode 100644 index 00000000..296fa1ea --- /dev/null +++ b/ksvg/impl/SVGAnimatedLengthListImpl.cc @@ -0,0 +1,95 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGAnimatedLengthListImpl.h" + +using namespace KSVG; + +#include "SVGAnimatedLengthListImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGAnimatedLengthListImpl::SVGAnimatedLengthListImpl() : DOM::DomShared() +{ + m_baseVal = new SVGLengthListImpl(); + m_baseVal->ref(); + + m_animVal = new SVGLengthListImpl(); + m_animVal->ref(); +} + +SVGAnimatedLengthListImpl::SVGAnimatedLengthListImpl(const SVGAnimatedLengthListImpl &other) : DOM::DomShared() +{ + (*this) = other; +} + +SVGAnimatedLengthListImpl::~SVGAnimatedLengthListImpl() +{ + if(m_baseVal) + m_baseVal->deref(); + if(m_animVal) + m_animVal->deref(); +} + +SVGAnimatedLengthListImpl &SVGAnimatedLengthListImpl::operator=(const SVGAnimatedLengthListImpl &other) +{ + *m_baseVal = *(other.m_baseVal); + *m_animVal = *(other.m_animVal); + + return *this; +} + +SVGLengthListImpl *SVGAnimatedLengthListImpl::baseVal() const +{ + return m_baseVal; +} + +SVGLengthListImpl *SVGAnimatedLengthListImpl::animVal() const +{ + return m_animVal; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGAnimatedLengthListImpl::s_hashTable 3 + baseVal SVGAnimatedLengthListImpl::BaseVal DontDelete|ReadOnly + animVal SVGAnimatedLengthListImpl::AnimVal DontDelete|ReadOnly +@end +*/ + +Value SVGAnimatedLengthListImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case BaseVal: + return m_baseVal->cache(exec); + case AnimVal: + return m_animVal->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedLengthListImpl.h b/ksvg/impl/SVGAnimatedLengthListImpl.h new file mode 100644 index 00000000..74f3cb1e --- /dev/null +++ b/ksvg/impl/SVGAnimatedLengthListImpl.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedLengthListImpl_H +#define SVGAnimatedLengthListImpl_H + +#include "SVGLengthListImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedLengthListImpl : public DOM::DomShared +{ +public: + SVGAnimatedLengthListImpl(); + SVGAnimatedLengthListImpl(const SVGAnimatedLengthListImpl &); + virtual ~SVGAnimatedLengthListImpl(); + + SVGAnimatedLengthListImpl &operator=(const SVGAnimatedLengthListImpl &); + + SVGLengthListImpl *baseVal() const; + SVGLengthListImpl *animVal() const; + +private: + SVGLengthListImpl *m_baseVal; + SVGLengthListImpl *m_animVal; + +public: + KSVG_GET + + enum + { + // Properties + BaseVal, AnimVal + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +} + +#endif diff --git a/ksvg/impl/SVGAnimatedNumberImpl.cc b/ksvg/impl/SVGAnimatedNumberImpl.cc new file mode 100644 index 00000000..2937c233 --- /dev/null +++ b/ksvg/impl/SVGAnimatedNumberImpl.cc @@ -0,0 +1,94 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGAnimatedNumberImpl.h" + +using namespace KSVG; + +#include "SVGAnimatedNumberImpl.lut.h" +#include "ksvg_bridge.h" + +SVGAnimatedNumberImpl::SVGAnimatedNumberImpl() : DOM::DomShared() +{ + KSVG_EMPTY_FLAGS + + m_baseVal = 0; + m_animVal = 0; +} + +SVGAnimatedNumberImpl::~SVGAnimatedNumberImpl() +{ +} + +void SVGAnimatedNumberImpl::setBaseVal(float baseVal) +{ + m_baseVal = baseVal; +} + +float SVGAnimatedNumberImpl::baseVal() const +{ + return m_baseVal; +} + +float SVGAnimatedNumberImpl::animVal() const +{ + return m_animVal; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGAnimatedNumberImpl::s_hashTable 3 + baseVal SVGAnimatedNumberImpl::BaseVal DontDelete + animVal SVGAnimatedNumberImpl::AnimVal DontDelete|ReadOnly +@end +*/ + +Value SVGAnimatedNumberImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case BaseVal: + return Number(baseVal()); + case AnimVal: + return Number(animVal()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } + + return Undefined(); +} + +void SVGAnimatedNumberImpl::putValueProperty(ExecState *exec, int token, const KJS::Value &value, int) +{ + switch(token) + { + case BaseVal: + setBaseVal(value.toNumber(exec)); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedNumberImpl.h b/ksvg/impl/SVGAnimatedNumberImpl.h new file mode 100644 index 00000000..81c9217b --- /dev/null +++ b/ksvg/impl/SVGAnimatedNumberImpl.h @@ -0,0 +1,63 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedNumberImpl_H +#define SVGAnimatedNumberImpl_H + +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedNumberImpl : public DOM::DomShared +{ +public: + SVGAnimatedNumberImpl(); + virtual ~SVGAnimatedNumberImpl(); + + void setBaseVal(float baseVal); + float baseVal() const; + + float animVal() const; + +private: + float m_baseVal; + float m_animVal; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + BaseVal, AnimVal + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedNumberListImpl.cc b/ksvg/impl/SVGAnimatedNumberListImpl.cc new file mode 100644 index 00000000..d6ff44e0 --- /dev/null +++ b/ksvg/impl/SVGAnimatedNumberListImpl.cc @@ -0,0 +1,82 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGAnimatedNumberListImpl.h" + +using namespace KSVG; + +#include "SVGAnimatedNumberListImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGAnimatedNumberListImpl::SVGAnimatedNumberListImpl() : DOM::DomShared() +{ + m_baseVal = new SVGNumberListImpl(); + m_baseVal->ref(); + + m_animVal = new SVGNumberListImpl(); + m_animVal->ref(); +} + +SVGAnimatedNumberListImpl::~SVGAnimatedNumberListImpl() +{ + if(m_baseVal) + m_baseVal->deref(); + if(m_animVal) + m_animVal->deref(); +} + +SVGNumberListImpl *SVGAnimatedNumberListImpl::baseVal() const +{ + return m_baseVal; +} + +SVGNumberListImpl *SVGAnimatedNumberListImpl::animVal() const +{ + return m_animVal; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGAnimatedNumberListImpl::s_hashTable 3 + baseVal SVGAnimatedNumberListImpl::BaseVal DontDelete|ReadOnly + animVal SVGAnimatedNumberListImpl::AnimVal DontDelete|ReadOnly +@end +*/ + +Value SVGAnimatedNumberListImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case BaseVal: + return m_baseVal->cache(exec); + case AnimVal: + return m_animVal->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedNumberListImpl.h b/ksvg/impl/SVGAnimatedNumberListImpl.h new file mode 100644 index 00000000..b44b3ffd --- /dev/null +++ b/ksvg/impl/SVGAnimatedNumberListImpl.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedNumberListImpl_H +#define SVGAnimatedNumberListImpl_H + +#include "SVGNumberListImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedNumberListImpl : public DOM::DomShared +{ +public: + SVGAnimatedNumberListImpl(); + virtual ~SVGAnimatedNumberListImpl(); + + SVGNumberListImpl *baseVal() const; + SVGNumberListImpl *animVal() const; + +private: + SVGNumberListImpl *m_baseVal; + SVGNumberListImpl *m_animVal; + +public: + KSVG_GET + + enum + { + // Properties + BaseVal, AnimVal + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +} + +#endif diff --git a/ksvg/impl/SVGAnimatedPathDataImpl.cc b/ksvg/impl/SVGAnimatedPathDataImpl.cc new file mode 100644 index 00000000..2b9ebf4c --- /dev/null +++ b/ksvg/impl/SVGAnimatedPathDataImpl.cc @@ -0,0 +1,108 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGPathSegListImpl.h" +#include "SVGAnimatedPathDataImpl.h" + +using namespace KSVG; + +#include "SVGAnimatedPathDataImpl.lut.h" +#include "ksvg_bridge.h" + +SVGAnimatedPathDataImpl::SVGAnimatedPathDataImpl() : DOM::DomShared() +{ + m_pathSegList = new SVGPathSegListImpl(); + m_pathSegList->ref(); + + m_normalizedPathSegList = new SVGPathSegListImpl(); + m_normalizedPathSegList->ref(); + + m_animatedPathSegList = new SVGPathSegListImpl(); + m_animatedPathSegList->ref(); + + m_animatedNormalizedPathSegList = new SVGPathSegListImpl(); + m_animatedNormalizedPathSegList->ref(); +} + +SVGAnimatedPathDataImpl::~SVGAnimatedPathDataImpl() +{ + if(m_pathSegList) + m_pathSegList->deref(); + if(m_normalizedPathSegList) + m_normalizedPathSegList->deref(); + if(m_animatedPathSegList) + m_animatedPathSegList->deref(); + if(m_animatedNormalizedPathSegList) + m_animatedNormalizedPathSegList->deref(); +} + +SVGPathSegListImpl *SVGAnimatedPathDataImpl::pathSegList() const +{ + return m_pathSegList; +} + +SVGPathSegListImpl *SVGAnimatedPathDataImpl::normalizedPathSegList() const +{ + return m_normalizedPathSegList; +} + +SVGPathSegListImpl *SVGAnimatedPathDataImpl::animatedPathSegList() const +{ + return m_animatedPathSegList; +} + +SVGPathSegListImpl *SVGAnimatedPathDataImpl::animatedNormalizedPathSegList() const +{ + return m_animatedNormalizedPathSegList; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGAnimatedPathDataImpl::s_hashTable 5 + pathSegList SVGAnimatedPathDataImpl::PathSegList DontDelete|ReadOnly + normalizedPathSegList SVGAnimatedPathDataImpl::NormalizedPathSegList DontDelete|ReadOnly + animatedPathSegList SVGAnimatedPathDataImpl::AnimatedPathSegList DontDelete|ReadOnly + animatedNormalizedPathSegList SVGAnimatedPathDataImpl::AnimatedNormalizedPathSegList DontDelete|ReadOnly +@end +*/ + +Value SVGAnimatedPathDataImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case PathSegList: + return pathSegList()->cache(exec); + case NormalizedPathSegList: + return normalizedPathSegList()->cache(exec); + case AnimatedPathSegList: + return animatedPathSegList()->cache(exec); + case AnimatedNormalizedPathSegList: + return animatedNormalizedPathSegList()->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); +} +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedPathDataImpl.h b/ksvg/impl/SVGAnimatedPathDataImpl.h new file mode 100644 index 00000000..2af1f893 --- /dev/null +++ b/ksvg/impl/SVGAnimatedPathDataImpl.h @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedPathDataImpl_H +#define SVGAnimatedPathDataImpl_H + +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGPathSegListImpl; + +// special case, virtual public HAS to stay +class SVGAnimatedPathDataImpl : virtual public DOM::DomShared +{ +public: + SVGAnimatedPathDataImpl(); + virtual ~SVGAnimatedPathDataImpl(); + + SVGPathSegListImpl *pathSegList() const; + SVGPathSegListImpl *normalizedPathSegList() const; + SVGPathSegListImpl *animatedPathSegList() const; + SVGPathSegListImpl *animatedNormalizedPathSegList() const; + +private: + SVGPathSegListImpl *m_pathSegList; + SVGPathSegListImpl *m_normalizedPathSegList; + SVGPathSegListImpl *m_animatedPathSegList; + SVGPathSegListImpl *m_animatedNormalizedPathSegList; + +public: + KSVG_GET + + enum + { + // Properties + PathSegList, NormalizedPathSegList, AnimatedPathSegList, AnimatedNormalizedPathSegList + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedPointsImpl.cc b/ksvg/impl/SVGAnimatedPointsImpl.cc new file mode 100644 index 00000000..093ded77 --- /dev/null +++ b/ksvg/impl/SVGAnimatedPointsImpl.cc @@ -0,0 +1,139 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include + +#include "CanvasItem.h" +#include "SVGPointListImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGAnimatedPointsImpl.h" + +using namespace KSVG; + +#include "SVGAnimatedPointsImpl.lut.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGAnimatedPointsImpl::SVGAnimatedPointsImpl() : DOM::DomShared() +{ + KSVG_EMPTY_FLAGS + + m_points = new SVGPointListImpl(); + m_points->ref(); + + m_animatedPoints = new SVGPointListImpl(); + m_animatedPoints->ref(); +} + +SVGAnimatedPointsImpl::~SVGAnimatedPointsImpl() +{ + if(m_points) + m_points->deref(); + if(m_animatedPoints) + m_animatedPoints->deref(); +} + +SVGPointListImpl *SVGAnimatedPointsImpl::points() const +{ + return m_points; +} + +SVGPointListImpl *SVGAnimatedPointsImpl::animatedPoints() const +{ + return m_animatedPoints; +} + +void SVGAnimatedPointsImpl::parsePoints(QString _points, SVGPointListImpl *points) +{ + if(_points.isEmpty()) + return; + + _points = _points.simplifyWhiteSpace(); + + if(_points.contains(",,") || _points.contains(", ,")) + return; + + _points.replace(',', ' '); + _points.replace('\r', QString::null); + _points.replace('\n', QString::null); + + _points = _points.simplifyWhiteSpace(); + + QStringList pointList = QStringList::split(' ', _points); + for(QStringList::Iterator it = pointList.begin(); it != pointList.end(); it++) + { + SVGPointImpl *point = SVGSVGElementImpl::createSVGPoint(); + point->setX((*(it++)).toFloat()); + point->setY((*it).toFloat()); + + points->appendItem(point); + } +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGAnimatedPointsImpl::s_hashTable 3 + points SVGAnimatedPointsImpl::Points DontDelete|ReadOnly + animatedPoints SVGAnimatedPointsImpl::AnimatedPoints DontDelete|ReadOnly +@end +*/ + +Value SVGAnimatedPointsImpl::getValueProperty(ExecState *exec, int token) const +{ + //KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case Points: // TODO: We need a pointList->toText function, quite trivial +// if(!attributeMode) + return points()->cache(exec); + case AnimatedPoints: + return animatedPoints()->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGAnimatedPointsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case Points: + parsePoints(value.toString(exec).qstring(), m_points); + break; + case AnimatedPoints: + parsePoints(value.toString(exec).qstring(), m_animatedPoints); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedPointsImpl.h b/ksvg/impl/SVGAnimatedPointsImpl.h new file mode 100644 index 00000000..ef4dafca --- /dev/null +++ b/ksvg/impl/SVGAnimatedPointsImpl.h @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedPointsImpl_H +#define SVGAnimatedPointsImpl_H + +#include + +#include "ksvg_lookup.h" + +class QString; + +namespace KSVG +{ + +class SVGPointListImpl; +class SVGAnimatedPointsImpl : virtual public DOM::DomShared +{ +public: + SVGAnimatedPointsImpl(); + virtual ~SVGAnimatedPointsImpl(); + + SVGPointListImpl *points() const; + SVGPointListImpl *animatedPoints() const; + + static void parsePoints(QString _points, SVGPointListImpl *points); + +protected: + SVGPointListImpl *m_points; + SVGPointListImpl *m_animatedPoints; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + Points, AnimatedPoints + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedPreserveAspectRatioImpl.cc b/ksvg/impl/SVGAnimatedPreserveAspectRatioImpl.cc new file mode 100644 index 00000000..166b987f --- /dev/null +++ b/ksvg/impl/SVGAnimatedPreserveAspectRatioImpl.cc @@ -0,0 +1,83 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGPreserveAspectRatioImpl.h" +#include "SVGAnimatedPreserveAspectRatioImpl.h" + +using namespace KSVG; + +#include "SVGAnimatedPreserveAspectRatioImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGAnimatedPreserveAspectRatioImpl::SVGAnimatedPreserveAspectRatioImpl() : DOM::DomShared() +{ + m_baseVal = new SVGPreserveAspectRatioImpl(); + m_baseVal->ref(); + + m_animVal = new SVGPreserveAspectRatioImpl(); + m_animVal->ref(); +} + +SVGAnimatedPreserveAspectRatioImpl::~SVGAnimatedPreserveAspectRatioImpl() +{ + if(m_baseVal) + m_baseVal->deref(); + if(m_animVal) + m_animVal->deref(); +} + +SVGPreserveAspectRatioImpl *SVGAnimatedPreserveAspectRatioImpl::baseVal() const +{ + return m_baseVal; +} + +SVGPreserveAspectRatioImpl *SVGAnimatedPreserveAspectRatioImpl::animVal() const +{ + return m_animVal; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGAnimatedPreserveAspectRatioImpl::s_hashTable 3 + baseVal SVGAnimatedPreserveAspectRatioImpl::BaseVal DontDelete|ReadOnly + animVal SVGAnimatedPreserveAspectRatioImpl::AnimVal DontDelete|ReadOnly +@end +*/ + +Value SVGAnimatedPreserveAspectRatioImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case BaseVal: + return m_baseVal->cache(exec); + case AnimVal: + return m_animVal->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedPreserveAspectRatioImpl.h b/ksvg/impl/SVGAnimatedPreserveAspectRatioImpl.h new file mode 100644 index 00000000..30fb7c87 --- /dev/null +++ b/ksvg/impl/SVGAnimatedPreserveAspectRatioImpl.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedPreserveAspectRatioImpl_H +#define SVGAnimatedPreserveAspectRatioImpl_H + +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGPreserveAspectRatioImpl; +class SVGAnimatedPreserveAspectRatioImpl : public DOM::DomShared +{ +public: + SVGAnimatedPreserveAspectRatioImpl(); + virtual ~SVGAnimatedPreserveAspectRatioImpl(); + + SVGPreserveAspectRatioImpl *baseVal() const; + SVGPreserveAspectRatioImpl *animVal() const; + +private: + SVGPreserveAspectRatioImpl *m_baseVal; + SVGPreserveAspectRatioImpl *m_animVal; + +public: + KSVG_GET + + enum + { + // Properties + BaseVal, AnimVal + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedRectImpl.cc b/ksvg/impl/SVGAnimatedRectImpl.cc new file mode 100644 index 00000000..4ba7a50d --- /dev/null +++ b/ksvg/impl/SVGAnimatedRectImpl.cc @@ -0,0 +1,81 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGRectImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGAnimatedRectImpl.h" + +using namespace KSVG; + +#include "SVGAnimatedRectImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGAnimatedRectImpl::SVGAnimatedRectImpl() : DOM::DomShared() +{ + m_baseVal = SVGSVGElementImpl::createSVGRect(); + m_animVal = SVGSVGElementImpl::createSVGRect(); +} + +SVGAnimatedRectImpl::~SVGAnimatedRectImpl() +{ + if(m_baseVal) + m_baseVal->deref(); + if(m_animVal) + m_animVal->deref(); +} + +SVGRectImpl *SVGAnimatedRectImpl::baseVal() const +{ + return m_baseVal; +} + +SVGRectImpl *SVGAnimatedRectImpl::animVal() const +{ + return m_animVal; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGAnimatedRectImpl::s_hashTable 3 + baseVal SVGAnimatedRectImpl::BaseVal DontDelete + animVal SVGAnimatedRectImpl::AnimVal DontDelete +@end +*/ + +Value SVGAnimatedRectImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case BaseVal: + return m_baseVal->cache(exec); + case AnimVal: + return m_animVal->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedRectImpl.h b/ksvg/impl/SVGAnimatedRectImpl.h new file mode 100644 index 00000000..0619505d --- /dev/null +++ b/ksvg/impl/SVGAnimatedRectImpl.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedRectImpl_H +#define SVGAnimatedRectImpl_H + +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGRectImpl; +class SVGAnimatedRectImpl : public DOM::DomShared +{ +public: + SVGAnimatedRectImpl(); + virtual ~SVGAnimatedRectImpl(); + + SVGRectImpl *baseVal() const; + SVGRectImpl *animVal() const; + +private: + SVGRectImpl *m_baseVal; + SVGRectImpl *m_animVal; + +public: + KSVG_GET + + enum + { + // Properties + BaseVal, AnimVal + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedStringImpl.cc b/ksvg/impl/SVGAnimatedStringImpl.cc new file mode 100644 index 00000000..1ce4f00b --- /dev/null +++ b/ksvg/impl/SVGAnimatedStringImpl.cc @@ -0,0 +1,90 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGAnimatedStringImpl.h" + +using namespace KSVG; + +#include "SVGAnimatedStringImpl.lut.h" +#include "ksvg_bridge.h" + +SVGAnimatedStringImpl::SVGAnimatedStringImpl() : DOM::DomShared() +{ + KSVG_EMPTY_FLAGS +} + +SVGAnimatedStringImpl::~SVGAnimatedStringImpl() +{ +} + +void SVGAnimatedStringImpl::setBaseVal(const DOM::DOMString &baseVal) +{ + m_baseVal = baseVal; +} + +DOM::DOMString SVGAnimatedStringImpl::baseVal() const +{ + return m_baseVal; +} + +DOM::DOMString SVGAnimatedStringImpl::animVal() const +{ + return m_animVal; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGAnimatedStringImpl::s_hashTable 3 + baseVal SVGAnimatedStringImpl::BaseVal DontDelete + animVal SVGAnimatedStringImpl::AnimVal DontDelete|ReadOnly +@end +*/ + +Value SVGAnimatedStringImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case BaseVal: + return String(baseVal().string()); + case AnimVal: + return String(animVal().string()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGAnimatedStringImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case BaseVal: + setBaseVal(value.toString(exec).string()); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedStringImpl.h b/ksvg/impl/SVGAnimatedStringImpl.h new file mode 100644 index 00000000..cc15f7e2 --- /dev/null +++ b/ksvg/impl/SVGAnimatedStringImpl.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedStringImpl_H +#define SVGAnimatedStringImpl_H + +#include +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedStringImpl : public DOM::DomShared +{ +public: + SVGAnimatedStringImpl(); + virtual ~SVGAnimatedStringImpl(); + + void setBaseVal(const DOM::DOMString &baseVal); + DOM::DOMString baseVal() const; + + DOM::DOMString animVal() const; + +private: + DOM::DOMString m_baseVal; + DOM::DOMString m_animVal; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + BaseVal, AnimVal + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedTransformListImpl.cc b/ksvg/impl/SVGAnimatedTransformListImpl.cc new file mode 100644 index 00000000..2e3b5536 --- /dev/null +++ b/ksvg/impl/SVGAnimatedTransformListImpl.cc @@ -0,0 +1,83 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGTransformListImpl.h" +#include "SVGAnimatedTransformListImpl.h" + +using namespace KSVG; + +#include "SVGAnimatedTransformListImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGAnimatedTransformListImpl::SVGAnimatedTransformListImpl() : DOM::DomShared() +{ + m_baseVal = new SVGTransformListImpl(); + m_baseVal->ref(); + + m_animVal = new SVGTransformListImpl(); + m_animVal->ref(); +} + +SVGAnimatedTransformListImpl::~SVGAnimatedTransformListImpl() +{ + if(m_baseVal) + m_baseVal->deref(); + if(m_animVal) + m_animVal->deref(); +} + +SVGTransformListImpl *SVGAnimatedTransformListImpl::baseVal() const +{ + return m_baseVal; +} + +SVGTransformListImpl *SVGAnimatedTransformListImpl::animVal() const +{ + return m_animVal; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGAnimatedTransformListImpl::s_hashTable 3 + baseVal SVGAnimatedTransformListImpl::BaseVal DontDelete|ReadOnly + animVal SVGAnimatedTransformListImpl::AnimVal DontDelete|ReadOnly +@end +*/ + +Value SVGAnimatedTransformListImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case BaseVal: + return m_baseVal->cache(exec); + case AnimVal: + return m_animVal->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimatedTransformListImpl.h b/ksvg/impl/SVGAnimatedTransformListImpl.h new file mode 100644 index 00000000..dc4be7e1 --- /dev/null +++ b/ksvg/impl/SVGAnimatedTransformListImpl.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimatedTransformListImpl_H +#define SVGAnimatedTransformListImpl_H + +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGTransformListImpl; +class SVGAnimatedTransformListImpl : public DOM::DomShared +{ +public: + SVGAnimatedTransformListImpl(); + virtual ~SVGAnimatedTransformListImpl(); + + SVGTransformListImpl *baseVal() const; + SVGTransformListImpl *animVal() const; + +private: + SVGTransformListImpl *m_baseVal; + SVGTransformListImpl *m_animVal; + +public: + KSVG_GET + + enum + { + // Properties + BaseVal, AnimVal + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimationElementImpl.cc b/ksvg/impl/SVGAnimationElementImpl.cc new file mode 100644 index 00000000..454a323e --- /dev/null +++ b/ksvg/impl/SVGAnimationElementImpl.cc @@ -0,0 +1,465 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include + +#include + +#include "CanvasItem.h" +#include "SVGHelperImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGStringListImpl.h" +#include "SVGURIReferenceImpl.h" +#include "SVGAnimationElementImpl.h" + +using namespace KSVG; + +#include "SVGAnimationElementImpl.lut.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGAnimationElementImpl::SVGAnimationElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGTestsImpl(), SVGExternalResourcesRequiredImpl() +{ + KSVG_EMPTY_FLAGS + + m_connected = false; + m_targetElement = 0; + + m_values = new SVGStringListImpl(); + m_keyTimes= new SVGStringListImpl(); + m_keySplines = new SVGStringListImpl(); + + m_fill = REMOVE; + m_additive = REPLACE; + m_accumulate = ACCUMULATE_NONE; +} + +SVGAnimationElementImpl::~SVGAnimationElementImpl() +{ + if(m_targetElement) + m_targetElement->deref(); +} + +SVGElementImpl *SVGAnimationElementImpl::targetElement() const +{ + if(!m_targetElement) + { + SVGAnimationElementImpl *modify = const_cast(this); + if(!m_href.isEmpty()) + modify->setTargetElement(ownerDoc()->getElementByIdRecursive(ownerSVGElement(), SVGURIReferenceImpl::getTarget(m_href))); + else if(!parentNode().isNull()) + modify->setTargetElement(ownerDoc()->getElementFromHandle(parentNode().handle())); + } + + return m_targetElement; +} + +double SVGAnimationElementImpl::parseClockValue(const QString &data) const +{ + QString parse = data.stripWhiteSpace(); + QString debugOutput = "parseClockValue(" + parse + ") -> "; + + if(parse == "indefinite") // Saves some time... + return -1; + + double result; + + int doublePointOne = parse.find(':'); + int doublePointTwo = parse.find(':', doublePointOne + 1); + + if(doublePointOne != -1 && doublePointTwo != -1) // Spec: "Full clock values" + { + unsigned int hours = parse.mid(0, 2).toUInt(); + unsigned int minutes = parse.mid(3, 2).toUInt(); + unsigned int seconds = parse.mid(6, 2).toUInt(); + unsigned int milliseconds = 0; + + result = (3600 * hours) + (60 * minutes) + seconds; + + if(parse.find('.') != -1) + { + QString temp = parse.mid(9, 2); + milliseconds = temp.toUInt(); + result += (milliseconds * (1 / pow(10.0, temp.length()))); + } + } + else if(doublePointOne != -1 && doublePointTwo == -1) // Spec: "Partial clock values" + { + unsigned int minutes = parse.mid(0, 2).toUInt(); + unsigned int seconds = parse.mid(3, 2).toUInt(); + unsigned int milliseconds = 0; + + result = (60 * minutes) + seconds; + + if(parse.find('.') != -1) + { + QString temp = parse.mid(6, 2); + milliseconds = temp.toUInt(); + result += (milliseconds * (1 / pow(10.0, temp.length()))); + } + } + else // Spec: "Timecount values" + { + int dotPosition = parse.find('.'); + + if(parse.endsWith("h")) + { + if(dotPosition == -1) + result = parse.mid(0, parse.length() - 1).toUInt() * 3600; + else + { + result = parse.mid(0, dotPosition).toUInt() * 3600; + QString temp = parse.mid(dotPosition + 1, parse.length() - dotPosition - 2); + result += (3600.0 * temp.toUInt()) * (1 / pow(10.0, temp.length())); + } + } + else if(parse.endsWith("min")) + { + if(dotPosition == -1) + result = parse.mid(0, parse.length() - 3).toUInt() * 60; + else + { + result = parse.mid(0, dotPosition).toUInt() * 60; + QString temp = parse.mid(dotPosition + 1, parse.length() - dotPosition - 4); + result += (60.0 * temp.toUInt()) * (1 / pow(10.0, temp.length())); + } + } + else if(parse.endsWith("ms")) + { + if(dotPosition == -1) + result = parse.mid(0, parse.length() - 2).toUInt() / 1000.0; + else + { + result = parse.mid(0, dotPosition).toUInt() / 1000.0; + QString temp = parse.mid(dotPosition + 1, parse.length() - dotPosition - 3); + result += (temp.toUInt() / 1000.0) * (1 / pow(10.0, temp.length())); + } + } + else if(parse.endsWith("s")) + { + if(dotPosition == -1) + result = parse.mid(0, parse.length() - 1).toUInt(); + else + { + result = parse.mid(0, dotPosition).toUInt(); + QString temp = parse.mid(dotPosition + 1, parse.length() - dotPosition - 2); + result += temp.toUInt() * (1 / pow(10.0, temp.length())); + } + } + else + result = parse.toDouble(); + } + + kdDebug() << debugOutput << result << endl; + return result; +} + +/* +@namespace KSVG +@begin SVGAnimationElementImpl::s_hashTable 23 + targetElement SVGAnimationElementImpl::TargetElement DontDelete|ReadOnly + href SVGAnimationElementImpl::Href DontDelete|ReadOnly + additive SVGAnimationElementImpl::Additive DontDelete|ReadOnly + accumulate SVGAnimationElementImpl::Accumulate DontDelete|ReadOnly + attributeName SVGAnimationElementImpl::AttributeName DontDelete|ReadOnly + attributeType SVGAnimationElementImpl::AttributeType DontDelete|ReadOnly + calcMode SVGAnimationElementImpl::CalcMode DontDelete|ReadOnly + values SVGAnimationElementImpl::Values DontDelete|ReadOnly + keyTimes SVGAnimationElementImpl::KeyTimes DontDelete|ReadOnly + keySplines SVGAnimationElementImpl::KeySplines DontDelete|ReadOnly + from SVGAnimationElementImpl::From DontDelete|ReadOnly + to SVGAnimationElementImpl::To DontDelete|ReadOnly + by SVGAnimationElementImpl::By DontDelete|ReadOnly + begin SVGAnimationElementImpl::Begin DontDelete|ReadOnly + dur SVGAnimationElementImpl::Dur DontDelete|ReadOnly + end SVGAnimationElementImpl::End DontDelete|ReadOnly + min SVGAnimationElementImpl::Min DontDelete|ReadOnly + max SVGAnimationElementImpl::Max DontDelete|ReadOnly + restart SVGAnimationElementImpl::Restart DontDelete|ReadOnly + repeatCount SVGAnimationElementImpl::RepeatCount DontDelete|ReadOnly + repeatDur SVGAnimationElementImpl::RepeatDur DontDelete|ReadOnly + fill SVGAnimationElementImpl::Fill DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGAnimationElementImplProto::s_hashTable 5 + getStartTime SVGAnimationElementImpl::GetStartTime DontDelete|Function 0 + getCurrentTime SVGAnimationElementImpl::GetCurrentTime DontDelete|Function 0 + getSimpleDuration SVGAnimationElementImpl::GetSimpleDuration DontDelete|Function 0 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGAnimationElement",SVGAnimationElementImplProto,SVGAnimationElementImplProtoFunc) + +Value SVGAnimationElementImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case TargetElement: + return m_targetElement->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGAnimationElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + QString val = value.toString(exec).qstring(); + switch(token) + { + case Href: + m_href = val; + break; + case Additive: + m_additive = (val == "sum") ? SUM : REPLACE; + break; + case Accumulate: + m_accumulate = (val == "sum") ? ACCUMULATE_SUM : ACCUMULATE_NONE; + break; + case AttributeName: + m_attributeName = val; + break; + case AttributeType: + if(val == "css") + m_attributeType = CSS; + else if(val == "xml") + m_attributeType = XML; + else + m_attributeType = AUTO; + break; + case CalcMode: // FIXME: See spec for default values!!! + if(val == "discrete") + m_calcMode = DISCRETE; + else if(val == "linear") + m_calcMode = LINEAR; + else if(val == "spline") + m_calcMode = SPLINE; + else if(val == "paced") + m_calcMode = PACED; + break; + case Values: + SVGHelperImpl::parseSemicolonSeperatedList(m_values, val); + break; + case KeyTimes: + SVGHelperImpl::parseSemicolonSeperatedList(m_keyTimes, val); + break; + case KeySplines: + SVGHelperImpl::parseSemicolonSeperatedList(m_keySplines, val); + break; + case From: + m_from = val; + break; + case To: + m_to = val; + break; + case By: + m_by = val; + break; + case Begin: + case End: + { + // Create list + SVGStringListImpl *temp = new SVGStringListImpl(); + temp->ref(); + + // Feed data into list + SVGHelperImpl::parseSemicolonSeperatedList(temp, val); + + // Parse data + for(unsigned int i = 0; i < temp->numberOfItems(); i++) + { + QString current = temp->getItem(i)->string(); + + if(current.startsWith("accessKey")) + { + // Register keyDownEventListener for the character + QString character = current.mid(current.length() - 2, 1); + + kdDebug() << "ACCESSKEY CHARACTER " << character << endl; + } + else if(current.startsWith("wallclock")) + { + int firstBrace = current.find("("); + int secondBrace = current.find(")"); + + QString wallclockValue = current.mid(firstBrace + 1, secondBrace - firstBrace - 2); + + kdDebug() << "WALLCLOCK VALUE " << wallclockValue << endl; + } + else if(current.contains(".")) + { + int dotPosition = current.find("."); + + QString element = current.mid(0, dotPosition); + QString clockValue; + + if(current.contains("begin")) + clockValue = current.mid(dotPosition + 6); + else if(current.contains("end")) + clockValue = current.mid(dotPosition + 4); + else if(current.contains("repeat")) + clockValue = current.mid(dotPosition + 7); + else // DOM2 Event Reference + { + int plusMinusPosition = -1; + + if(current.contains("+")) + plusMinusPosition = current.find("+"); + else if(current.contains("-")) + plusMinusPosition = current.find("-"); + + QString event = current.mid(dotPosition + 1, plusMinusPosition - dotPosition - 1); + + clockValue = current.mid(dotPosition + event.length() + 1); + kdDebug() << "EVENT " << event << endl; + } + + kdDebug() << "ELEMENT " << element << " CLOCKVALUE " << clockValue << endl; + } + else + { + if(token == Begin) + m_begin = parseClockValue(current); + else + m_end = parseClockValue(current); + } + } + + temp->deref(); + + break; + } + case Dur: + m_duration = parseClockValue(val); + break; +// case Min: +// case Max: + case Restart: + if(val == "whenNotActive") + m_restart = WHENNOTACTIVE; + else if(val == "never") + m_restart = NEVER; + else + m_restart = ALWAYS; + break; + case RepeatCount: + m_repeatCount = val; + break; + case RepeatDur: + m_repeatDur = val; + break; + case Fill: + m_fill = (val == "freeze") ? FREEZE : REMOVE; + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +Value SVGAnimationElementImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &) +{ + KSVG_CHECK_THIS(SVGAnimationElementImpl) + + switch(id) + { + case SVGAnimationElementImpl::GetStartTime: + return Number(obj->getStartTime()); + case SVGAnimationElementImpl::GetCurrentTime: + return Number(obj->getCurrentTime()); + case SVGAnimationElementImpl::GetSimpleDuration: + return Number(obj->getSimpleDuration()); + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + +void SVGAnimationElementImpl::setAttributes() +{ + SVGElementImpl::setAttributes(); + + // Spec: Default value is "replace" + if(KSVG_TOKEN_NOT_PARSED(Additive)) + KSVG_SET_ALT_ATTRIBUTE(Additive, "replace") + + // Spec: Default value is "none" + if(KSVG_TOKEN_NOT_PARSED(Accumulate)) + KSVG_SET_ALT_ATTRIBUTE(Accumulate, "none") + + // Spec: Default value is "always" + if(KSVG_TOKEN_NOT_PARSED(Restart)) + KSVG_SET_ALT_ATTRIBUTE(Restart, "always") +} + +void SVGAnimationElementImpl::setTargetElement(SVGElementImpl *target) +{ + if(m_targetElement) + m_targetElement->deref(); + + m_targetElement = target; + m_targetElement->ref(); +} + +void SVGAnimationElementImpl::applyAttribute(const QString &name, const QString &value) +{ + SVGElementImpl *target = targetElement(); + if(!target) + { + kdDebug() << k_funcinfo << " name: " << name << " value: " << value << " NO TARGET ELEMENT!" << endl; + return; + } + + // The only two cases I can imagine, where combining is needed (Niko) + bool combine = (name == "style" || name == "transform"); + + if(!combine) + target->setAttributeInternal(name, value); + else + { + kdDebug() << "TODO COMBINE: " << value << " NAME " << name << endl; + } +} + +double SVGAnimationElementImpl::getStartTime() const +{ + return m_begin; +} + +double SVGAnimationElementImpl::getCurrentTime() const +{ + return 0.0; +} + +double SVGAnimationElementImpl::getSimpleDuration() const +{ + return m_duration; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGAnimationElementImpl.h b/ksvg/impl/SVGAnimationElementImpl.h new file mode 100644 index 00000000..9fd9446e --- /dev/null +++ b/ksvg/impl/SVGAnimationElementImpl.h @@ -0,0 +1,149 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGAnimationElementImpl_H +#define SVGAnimationElementImpl_H + +#include "SVGElementImpl.h" +#include "SVGTestsImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +enum EFillMode +{ + REMOVE, + FREEZE +}; + +enum EAdditiveMode +{ + REPLACE, + SUM +}; + +enum EAccumulateMode +{ + ACCUMULATE_NONE, + ACCUMULATE_SUM +}; + +enum ECalcMode +{ + DISCRETE, + LINEAR, + PACED, + SPLINE +}; + +enum ERestart +{ + ALWAYS, + WHENNOTACTIVE, + NEVER +}; + +enum EAttributeType +{ + CSS, + XML, + AUTO +}; + +class SVGAnimationElementImpl : public SVGElementImpl, + public SVGTestsImpl, + public SVGExternalResourcesRequiredImpl +{ +public: + SVGAnimationElementImpl(DOM::ElementImpl *); + virtual ~SVGAnimationElementImpl(); + + SVGElementImpl *targetElement() const; + void setTargetElement(SVGElementImpl *target); + + void applyAttribute(const QString &name, const QString &value); + + virtual void handleTimerEvent() { } //= 0; + virtual void setAttributes(); + + double getStartTime() const; + double getCurrentTime() const; + double getSimpleDuration() const; + + QString getRepeatCount() const { return m_repeatCount; } + QString getRepeatDuration() const { return m_repeatDur; } + + QString getAttributeName() const { return m_attributeName; } + QString getFrom() const { return m_from; } + QString getTo() const { return m_to; } + QString getBy() const { return m_by; } + +protected: + double parseClockValue(const QString &data) const; + + bool m_connected; + EFillMode m_fill : 1; + EAdditiveMode m_additive : 1; + EAccumulateMode m_accumulate : 1; + ECalcMode m_calcMode : 2; + ERestart m_restart : 2; + EAttributeType m_attributeType : 2; + SVGElementImpl *m_targetElement; + + QString m_href; + QString m_attributeName; + QString m_from, m_to, m_by; + + double m_begin, m_end, m_duration; + + QString m_repeatCount, m_repeatDur; + + SVGStringListImpl *m_values, *m_keyTimes, *m_keySplines; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + TargetElement, + Href, Additive, Accumulate, AttributeName, AttributeType, + CalcMode, Values, KeyTimes, KeySplines, From, To, By, + Begin, Dur, End, Min, Max, Restart, RepeatCount, RepeatDur, Fill, + // Functions + GetStartTime, GetCurrentTime, GetSimpleDuration + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +KSVG_DEFINE_PROTOTYPE(SVGAnimationElementImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGAnimationElementImplProtoFunc, SVGAnimationElementImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGBBoxTarget.cc b/ksvg/impl/SVGBBoxTarget.cc new file mode 100644 index 00000000..fcef164e --- /dev/null +++ b/ksvg/impl/SVGBBoxTarget.cc @@ -0,0 +1,55 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGShapeImpl.h" +#include "SVGBBoxTarget.h" + +using namespace KSVG; + +SVGBBoxTarget::SVGBBoxTarget() +{ + m_target = 0; +} + +SVGBBoxTarget::~SVGBBoxTarget() +{ + if(m_target) + dynamic_cast(m_target)->deref(); +} + +SVGShapeImpl *SVGBBoxTarget::getBBoxTarget() const +{ + return m_target; +} + +void SVGBBoxTarget::setBBoxTarget(SVGShapeImpl *target) +{ + if(m_target) + dynamic_cast(m_target)->deref(); + + m_target = target; + + if(m_target) + dynamic_cast(m_target)->ref(); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGBBoxTarget.h b/ksvg/impl/SVGBBoxTarget.h new file mode 100644 index 00000000..03de657d --- /dev/null +++ b/ksvg/impl/SVGBBoxTarget.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGBBoxTarget_H +#define SVGBBoxTarget_H + +namespace KSVG +{ + +class SVGShapeImpl; +class SVGBBoxTarget +{ +public: + SVGBBoxTarget(); + virtual ~SVGBBoxTarget(); + + SVGShapeImpl *getBBoxTarget() const; + void setBBoxTarget(SVGShapeImpl *target); + +protected: + SVGShapeImpl *m_target; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGCSSRuleImpl.cc b/ksvg/impl/SVGCSSRuleImpl.cc new file mode 100644 index 00000000..991487e3 --- /dev/null +++ b/ksvg/impl/SVGCSSRuleImpl.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGCSSRuleImpl.h" + +using namespace KSVG; + +SVGCSSRuleImpl::SVGCSSRuleImpl() : DOM::DomShared()//, css::CSSRule() +{ +} + +SVGCSSRuleImpl::~SVGCSSRuleImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGCSSRuleImpl.h b/ksvg/impl/SVGCSSRuleImpl.h new file mode 100644 index 00000000..03ab4e8b --- /dev/null +++ b/ksvg/impl/SVGCSSRuleImpl.h @@ -0,0 +1,42 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGCSSRuleImpl_H +#define SVGCSSRuleImpl_H + +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGCSSRuleImpl : public DOM::DomShared //, public css::CSSRule +{ +public: + SVGCSSRuleImpl(); + virtual ~SVGCSSRuleImpl(); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGCircleElementImpl.cc b/ksvg/impl/SVGCircleElementImpl.cc new file mode 100644 index 00000000..b6246d1a --- /dev/null +++ b/ksvg/impl/SVGCircleElementImpl.cc @@ -0,0 +1,178 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include + +#include "CanvasItem.h" +#include "KSVGCanvas.h" + +#include "SVGRectImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGCircleElementImpl.h" +#include "SVGAnimatedLengthImpl.h" + +using namespace KSVG; + +#include "SVGCircleElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGCircleElementImpl::SVGCircleElementImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl() +{ + KSVG_EMPTY_FLAGS + + m_cx = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_cx->ref(); + m_cx->baseVal()->setValueAsString("-1"); + + m_cy = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_cy->ref(); + m_cy->baseVal()->setValueAsString("-1"); + + m_r = new SVGAnimatedLengthImpl(LENGTHMODE_OTHER, this); + m_r->ref(); + m_r->baseVal()->setValueAsString("-1"); +} + +SVGCircleElementImpl::~SVGCircleElementImpl() +{ + if(m_cx) + m_cx->deref(); + if(m_cy) + m_cy->deref(); + if(m_r) + m_r->deref(); +} + +SVGAnimatedLengthImpl *SVGCircleElementImpl::cx() +{ + return m_cx; +} + +SVGAnimatedLengthImpl *SVGCircleElementImpl::cy() +{ + return m_cy; +} + +SVGAnimatedLengthImpl *SVGCircleElementImpl::r() +{ + return m_r; +} + +/* +@namespace KSVG +@begin SVGCircleElementImpl::s_hashTable 5 + cx SVGCircleElementImpl::Cx DontDelete|ReadOnly + cy SVGCircleElementImpl::Cy DontDelete|ReadOnly + r SVGCircleElementImpl::R DontDelete|ReadOnly +@end +*/ + +Value SVGCircleElementImpl::getValueProperty(ExecState *exec, int token) const +{ + KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case Cx: + if(!attributeMode) + return m_cx->cache(exec); + else + return Number(m_cx->baseVal()->value()); + case Cy: + if(!attributeMode) + return m_cy->cache(exec); + else + return Number(m_cy->baseVal()->value()); + case R: + if(!attributeMode) + return m_r->cache(exec); + else + return Number(m_r->baseVal()->value()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGCircleElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case Cx: + cx()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case Cy: + cy()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case R: + r()->baseVal()->setValueAsString(value.toString(exec).qstring()); + if(r()->baseVal()->value() < 0) // A negative value is an error + gotError(i18n("Negative value for attribute r of element is illegal")); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +SVGRectImpl *SVGCircleElementImpl::getBBox() +{ + SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect(); + ret->setX(m_cx->baseVal()->value() - m_r->baseVal()->value()); + ret->setY(m_cy->baseVal()->value() - m_r->baseVal()->value()); + ret->setWidth(m_r->baseVal()->value() * 2.0); + ret->setHeight(m_r->baseVal()->value() * 2.0); + return ret; +} + +void SVGCircleElementImpl::setAttributes() +{ + SVGElementImpl::setAttributes(); + + // Spec: if not specified, effect is as if a value of "0" were specified + if(KSVG_TOKEN_NOT_PARSED(Cx)) + KSVG_SET_ALT_ATTRIBUTE(Cx, "0") + + // Spec: if not specified, effect is as if a value of "0" were specified + if(KSVG_TOKEN_NOT_PARSED(Cy)) + KSVG_SET_ALT_ATTRIBUTE(Cy, "0") +} + +void SVGCircleElementImpl::createItem(KSVGCanvas *c) +{ + if(!c) + c = ownerDoc()->canvas(); + + if(!m_item) + { + m_item = c->createCircle(this); + c->insert(m_item); + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGCircleElementImpl.h b/ksvg/impl/SVGCircleElementImpl.h new file mode 100644 index 00000000..29e0df3f --- /dev/null +++ b/ksvg/impl/SVGCircleElementImpl.h @@ -0,0 +1,84 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGCircleElementImpl_H +#define SVGCircleElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGShapeImpl.h" +#include "SVGTestsImpl.h" +#include "SVGStylableImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGTransformableImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +namespace KSVG +{ + +class SVGRectImpl; +class SVGAnimatedLengthImpl; +class SVGCircleElementImpl : public SVGShapeImpl, + public SVGTestsImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGTransformableImpl +{ +public: + SVGCircleElementImpl(DOM::ElementImpl *); + virtual ~SVGCircleElementImpl(); + + SVGAnimatedLengthImpl *cx(); + SVGAnimatedLengthImpl *cy(); + SVGAnimatedLengthImpl *r(); + + virtual void createItem(KSVGCanvas *c = 0); + virtual void setAttributes(); + + virtual SVGRectImpl *getBBox(); + +private: + SVGAnimatedLengthImpl *m_cx; + SVGAnimatedLengthImpl *m_cy; + SVGAnimatedLengthImpl *m_r; + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + Cx, Cy, R + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGCircleElementImpl, "circle") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGClipPathElementImpl.cc b/ksvg/impl/SVGClipPathElementImpl.cc new file mode 100644 index 00000000..87b4d4ac --- /dev/null +++ b/ksvg/impl/SVGClipPathElementImpl.cc @@ -0,0 +1,104 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGClipPathElement.h" +#include "SVGClipPathElementImpl.h" +#include "KSVGCanvas.h" +#include "SVGDocumentImpl.h" +#include "SVGAnimatedEnumerationImpl.h" + +using namespace KSVG; + +#include "SVGClipPathElementImpl.lut.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGClipPathElementImpl::SVGClipPathElementImpl(DOM::ElementImpl *impl) : SVGContainerImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl(), SVGBBoxTarget() +{ + KSVG_EMPTY_FLAGS + + m_clipPathUnits = new SVGAnimatedEnumerationImpl(); + m_clipPathUnits->ref(); + m_clipPathUnits->setBaseVal(SVGClipPathElement::SVG_UNIT_TYPE_UNKNOWN); +} + +SVGClipPathElementImpl::~SVGClipPathElementImpl() +{ + if(m_clipPathUnits) + m_clipPathUnits->deref(); +} + +SVGAnimatedEnumerationImpl *SVGClipPathElementImpl::clipPathUnits() const +{ + return m_clipPathUnits; +} + +/* +@namespace KSVG +@begin SVGClipPathElementImpl::s_hashTable 2 + clipPathUnits SVGClipPathElementImpl::ClipPathUnits DontDelete|ReadOnly +@end +*/ + +Value SVGClipPathElementImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case ClipPathUnits: + return m_clipPathUnits->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGClipPathElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case ClipPathUnits: + if(value.toString(exec).qstring() == "objectBoundingBox") + m_clipPathUnits->setBaseVal(SVGClipPathElement::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX); + else + m_clipPathUnits->setBaseVal(SVGClipPathElement::SVG_UNIT_TYPE_USERSPACEONUSE); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +void SVGClipPathElementImpl::setAttributes() +{ + SVGElementImpl::setAttributes(); + + // Spec: if attribute not specified, use userSpaceOnUse + if(KSVG_TOKEN_NOT_PARSED(ClipPathUnits)) + KSVG_SET_ALT_ATTRIBUTE(ClipPathUnits, "userSpaceOnUse") + + if(!m_item) + m_item = ownerDoc()->canvas()->createClipPath(this); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGClipPathElementImpl.h b/ksvg/impl/SVGClipPathElementImpl.h new file mode 100644 index 00000000..1e1879a9 --- /dev/null +++ b/ksvg/impl/SVGClipPathElementImpl.h @@ -0,0 +1,80 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGClipPathElementImpl_H +#define SVGClipPathElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGTestsImpl.h" +#include "SVGBBoxTarget.h" +#include "SVGStylableImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGContainerImpl.h" +#include "SVGTransformableImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +namespace KSVG +{ + +class SVGAnimatedEnumerationImpl; +class SVGClipPathElementImpl : public SVGContainerImpl, + public SVGTestsImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGTransformableImpl, + public SVGBBoxTarget +{ +public: + SVGClipPathElementImpl(DOM::ElementImpl *); + virtual ~SVGClipPathElementImpl(); + + SVGAnimatedEnumerationImpl *clipPathUnits() const; + + virtual void setAttributes(); + + virtual bool directRender() { return false; } + +private: + SVGAnimatedEnumerationImpl *m_clipPathUnits; + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + ClipPathUnits + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGClipPathElementImpl, "clipPath") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGColorImpl.cc b/ksvg/impl/SVGColorImpl.cc new file mode 100644 index 00000000..a01e1113 --- /dev/null +++ b/ksvg/impl/SVGColorImpl.cc @@ -0,0 +1,540 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option); any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include + +#include "SVGColor.h" + +#include "SVGColorImpl.h" +#include "SVGNumberImpl.h" +#include "SVGICCColorImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGNumberListImpl.h" +#include "SVGURIReferenceImpl.h" +#include "SVGColorProfileElementImpl.h" + +using namespace KSVG; + +#include "SVGColorImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_cacheimpl.h" + +SVGColorImpl::SVGColorImpl(SVGElementImpl *object) : m_object(object) +{ + m_colorType = SVG_COLORTYPE_UNKNOWN; + m_iccColor = 0; +} + +SVGColorImpl::SVGColorImpl(const SVGColorImpl &other) : DOM::DomShared() +{ + (*this) = other; +} + +SVGColorImpl::~SVGColorImpl() +{ + if(m_iccColor) + m_iccColor->deref(); +} + +SVGColorImpl &SVGColorImpl::operator=(const SVGColorImpl &other) +{ + m_colorType = other.m_colorType; + m_rgbColor = other.m_rgbColor; + + if(m_iccColor && other.m_iccColor) + *m_iccColor = *(other.m_iccColor); + + return *this; +} + +unsigned short SVGColorImpl::colorType() const +{ + return m_colorType; +} + +DOM::RGBColor SVGColorImpl::rgbColor() const +{ + return m_rgbColor; +} + +SVGICCColorImpl *SVGColorImpl::iccColor() const +{ + return m_iccColor; +} + +void SVGColorImpl::setRGBColor(QColor color) +{ + m_colorType = SVG_COLORTYPE_RGBCOLOR; + m_rgbColor = DOM::RGBColor(color.rgb()); +} + +void SVGColorImpl::setRGBColor(int r, int g, int b) +{ + m_colorType = SVG_COLORTYPE_RGBCOLOR; + m_rgbColor = DOM::RGBColor(QColor(r, g, b).rgb()); +} + +void SVGColorImpl::setRGBColor(const DOM::DOMString &rgbColor) +{ + if(rgbColor == "aliceblue") + setRGBColor(240, 248, 255); + else if(rgbColor == "antiquewhite") + setRGBColor(250, 235, 215); + else if(rgbColor == "aqua") + setRGBColor(0, 255, 255); + else if(rgbColor == "aquamarine") + setRGBColor(127, 255, 212); + else if(rgbColor == "azure") + setRGBColor(240, 255, 255); + else if(rgbColor == "beige") + setRGBColor(245, 245, 220); + else if(rgbColor == "bisque") + setRGBColor(255, 228, 196); + else if(rgbColor == "black") + setRGBColor(0, 0, 0); + else if(rgbColor == "blanchedalmond") + setRGBColor(255, 235, 205); + else if(rgbColor == "blue") + setRGBColor(0, 0, 255); + else if(rgbColor == "blueviolet") + setRGBColor(138, 43, 226); + else if(rgbColor == "brown") + setRGBColor(165, 42, 42); + else if(rgbColor == "burlywood") + setRGBColor(222, 184, 135); + else if(rgbColor == "cadetblue") + setRGBColor(95, 158, 160); + else if(rgbColor == "chartreuse") + setRGBColor(127, 255, 0); + else if(rgbColor == "chocolate") + setRGBColor(210, 105, 30); + else if(rgbColor == "coral") + setRGBColor(255, 127, 80); + else if(rgbColor == "cornflowerblue") + setRGBColor(100, 149, 237); + else if(rgbColor == "cornsilk") + setRGBColor(255, 248, 220); + else if(rgbColor == "crimson") + setRGBColor(220, 20, 60); + else if(rgbColor == "cyan") + setRGBColor(0, 255, 255); + else if(rgbColor == "darkblue") + setRGBColor(0, 0, 139); + else if(rgbColor == "darkcyan") + setRGBColor(0, 139, 139); + else if(rgbColor == "darkgoldenrod") + setRGBColor(184, 134, 11); + else if(rgbColor == "darkgray") + setRGBColor(169, 169, 169); + else if(rgbColor == "darkgrey") + setRGBColor(169, 169, 169); + else if(rgbColor == "darkgreen") + setRGBColor(0, 100, 0); + else if(rgbColor == "darkkhaki") + setRGBColor(189, 183, 107); + else if(rgbColor == "darkmagenta") + setRGBColor(139, 0, 139); + else if(rgbColor == "darkolivegreen") + setRGBColor(85, 107, 47); + else if(rgbColor == "darkorange") + setRGBColor(255, 140, 0); + else if(rgbColor == "darkorchid") + setRGBColor(153, 50, 204); + else if(rgbColor == "darkred") + setRGBColor(139, 0, 0); + else if(rgbColor == "darksalmon") + setRGBColor(233, 150, 122); + else if(rgbColor == "darkseagreen") + setRGBColor(143, 188, 143); + else if(rgbColor == "darkslateblue") + setRGBColor(72, 61, 139); + else if(rgbColor == "darkslategray") + setRGBColor(47, 79, 79); + else if(rgbColor == "darkslategrey") + setRGBColor(47, 79, 79); + else if(rgbColor == "darkturquoise") + setRGBColor(0, 206, 209); + else if(rgbColor == "darkviolet") + setRGBColor(148, 0, 211); + else if(rgbColor == "deeppink") + setRGBColor(255, 20, 147); + else if(rgbColor == "deepskyblue") + setRGBColor(0, 191, 255); + else if(rgbColor == "dimgray") + setRGBColor(105, 105, 105); + else if(rgbColor == "dimgrey") + setRGBColor(105, 105, 105); + else if(rgbColor == "dodgerblue") + setRGBColor(30, 144, 255); + else if(rgbColor == "firebrick") + setRGBColor(178, 34, 34); + else if(rgbColor == "floralwhite") + setRGBColor(255, 250, 240); + else if(rgbColor == "forestgreen") + setRGBColor(34, 139, 34); + else if(rgbColor == "fuchsia") + setRGBColor(255, 0, 255); + else if(rgbColor == "gainsboro") + setRGBColor(220, 220, 220); + else if(rgbColor == "ghostwhite") + setRGBColor(248, 248, 255); + else if(rgbColor == "gold") + setRGBColor(255, 215, 0); + else if(rgbColor == "goldenrod") + setRGBColor(218, 165, 32); + else if(rgbColor == "gray") + setRGBColor(128, 128, 128); + else if(rgbColor == "grey") + setRGBColor(128, 128, 128); + else if(rgbColor == "green") + setRGBColor(0, 128, 0); + else if(rgbColor == "greenyellow") + setRGBColor(173, 255, 47); + else if(rgbColor == "honeydew") + setRGBColor(240, 255, 240); + else if(rgbColor == "hotpink") + setRGBColor(255, 105, 180); + else if(rgbColor == "indianred") + setRGBColor(205, 92, 92); + else if(rgbColor == "indigo") + setRGBColor(75, 0, 130); + else if(rgbColor == "ivory") + setRGBColor(255, 255, 240); + else if(rgbColor == "khaki") + setRGBColor(240, 230, 140); + else if(rgbColor == "lavender") + setRGBColor(230, 230, 250); + else if(rgbColor == "lavenderblush") + setRGBColor(255, 240, 245); + else if(rgbColor == "lawngreen") + setRGBColor(124, 252, 0); + else if(rgbColor == "lemonchiffon") + setRGBColor(255, 250, 205); + else if(rgbColor == "lightblue") + setRGBColor(173, 216, 230); + else if(rgbColor == "lightcoral") + setRGBColor(240, 128, 128); + else if(rgbColor == "lightcyan") + setRGBColor(224, 255, 255); + else if(rgbColor == "lightgoldenrodyellow") + setRGBColor(250, 250, 210); + else if(rgbColor == "lightgray") + setRGBColor(211, 211, 211); + else if(rgbColor == "lightgrey") + setRGBColor(211, 211, 211); + else if(rgbColor == "lightgreen") + setRGBColor(144, 238, 144); + else if(rgbColor == "lightpink") + setRGBColor(255, 182, 193); + else if(rgbColor == "lightsalmon") + setRGBColor(255, 160, 122); + else if(rgbColor == "lightseagreen") + setRGBColor(32, 178, 170); + else if(rgbColor == "lightskyblue") + setRGBColor(135, 206, 250); + else if(rgbColor == "lightslategray") + setRGBColor(119, 136, 153); + else if(rgbColor == "lightslategrey") + setRGBColor(119, 136, 153); + else if(rgbColor == "lightsteelblue") + setRGBColor(176, 196, 222); + else if(rgbColor == "lightyellow") + setRGBColor(255, 255, 224); + else if(rgbColor == "lime") + setRGBColor(0, 255, 0); + else if(rgbColor == "limegreen") + setRGBColor(50, 205, 50); + else if(rgbColor == "linen") + setRGBColor(250, 240, 230); + else if(rgbColor == "magenta") + setRGBColor(255, 0, 255); + else if(rgbColor == "maroon") + setRGBColor(128, 0, 0); + else if(rgbColor == "mediumaquamarine") + setRGBColor(102, 205, 170); + else if(rgbColor == "mediumblue") + setRGBColor(0, 0, 205); + else if(rgbColor == "mediumorchid") + setRGBColor(186, 85, 211); + else if(rgbColor == "mediumpurple") + setRGBColor(147, 112, 219); + else if(rgbColor == "mediumseagreen") + setRGBColor(60, 179, 113); + else if(rgbColor == "mediumslateblue") + setRGBColor(123, 104, 238); + else if(rgbColor == "mediumspringgreen") + setRGBColor(0, 250, 154); + else if(rgbColor == "mediumturquoise") + setRGBColor(72, 209, 204); + else if(rgbColor == "mediumvioletred") + setRGBColor(199, 21, 133); + else if(rgbColor == "midnightblue") + setRGBColor(25, 25, 112); + else if(rgbColor == "mintcream") + setRGBColor(245, 255, 250); + else if(rgbColor == "mistyrose") + setRGBColor(255, 228, 225); + else if(rgbColor == "moccasin") + setRGBColor(255, 228, 181); + else if(rgbColor == "navajowhite") + setRGBColor(255, 222, 173); + else if(rgbColor == "navy") + setRGBColor(0, 0, 128); + else if(rgbColor == "oldlace") + setRGBColor(253, 245, 230); + else if(rgbColor == "olive") + setRGBColor(128, 128, 0); + else if(rgbColor == "olivedrab") + setRGBColor(107, 142, 35); + else if(rgbColor == "orange") + setRGBColor(255, 165, 0); + else if(rgbColor == "orangered") + setRGBColor(255, 69, 0); + else if(rgbColor == "orchid") + setRGBColor(218, 112, 214); + else if(rgbColor == "palegoldenrod") + setRGBColor(238, 232, 170); + else if(rgbColor == "palegreen") + setRGBColor(152, 251, 152); + else if(rgbColor == "paleturquoise") + setRGBColor(175, 238, 238); + else if(rgbColor == "palevioletred") + setRGBColor(219, 112, 147); + else if(rgbColor == "papayawhip") + setRGBColor(255, 239, 213); + else if(rgbColor == "peachpuff") + setRGBColor(255, 218, 185); + else if(rgbColor == "peru") + setRGBColor(205, 133, 63); + else if(rgbColor == "pink") + setRGBColor(255, 192, 203); + else if(rgbColor == "plum") + setRGBColor(221, 160, 221); + else if(rgbColor == "powderblue") + setRGBColor(176, 224, 230); + else if(rgbColor == "purple") + setRGBColor(128, 0, 128); + else if(rgbColor == "red") + setRGBColor(255, 0, 0); + else if(rgbColor == "rosybrown") + setRGBColor(188, 143, 143); + else if(rgbColor == "royalblue") + setRGBColor(65, 105, 225); + else if(rgbColor == "saddlebrown") + setRGBColor(139, 69, 19); + else if(rgbColor == "salmon") + setRGBColor(250, 128, 114); + else if(rgbColor == "sandybrown") + setRGBColor(244, 164, 96); + else if(rgbColor == "seagreen") + setRGBColor(46, 139, 87); + else if(rgbColor == "seashell") + setRGBColor(255, 245, 238); + else if(rgbColor == "sienna") + setRGBColor(160, 82, 45); + else if(rgbColor == "silver") + setRGBColor(192, 192, 192); + else if(rgbColor == "skyblue") + setRGBColor(135, 206, 235); + else if(rgbColor == "slateblue") + setRGBColor(106, 90, 205); + else if(rgbColor == "slategray") + setRGBColor(112, 128, 144); + else if(rgbColor == "slategrey") + setRGBColor(112, 128, 144); + else if(rgbColor == "snow") + setRGBColor(255, 250, 250); + else if(rgbColor == "springgreen") + setRGBColor(0, 255, 127); + else if(rgbColor == "steelblue") + setRGBColor(70, 130, 180); + else if(rgbColor == "tan") + setRGBColor(210, 180, 140); + else if(rgbColor == "teal") + setRGBColor(0, 128, 128); + else if(rgbColor == "thistle") + setRGBColor(216, 191, 216); + else if(rgbColor == "tomato") + setRGBColor(255, 99, 71); + else if(rgbColor == "turquoise") + setRGBColor(64, 224, 208); + else if(rgbColor == "violet") + setRGBColor(238, 130, 238); + else if(rgbColor == "wheat") + setRGBColor(245, 222, 179); + else if(rgbColor == "white") + setRGBColor(255, 255, 255); + else if(rgbColor == "whitesmoke") + setRGBColor(245, 245, 245); + else if(rgbColor == "yellow") + setRGBColor(255, 255, 0); + else if(rgbColor == "yellowgreen") + setRGBColor(154, 205, 50); +} + +void SVGColorImpl::setRGBColorICCColor(const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor) +{ + QColor color; + + QString content = iccColor.string().right(iccColor.string().length() - 10); + QString iccTarget = content.mid(0, content.find(',')); + + QStringList colors = QStringList::split(',', content); + QString r = colors[1]; + QString g = colors[2]; + QString b = colors[3].left(colors[3].length() - 1); + + iccTarget = SVGURIReferenceImpl::getTarget(iccTarget); + + SVGColorProfileElementImpl *handle = 0; + if(m_object) + handle = static_cast(dynamic_cast(m_object)->ownerDoc()->rootElement()->getElementById(iccTarget)); + + if(iccTarget.isEmpty() || !handle) + { + color.setNamedColor(rgbColor.string().stripWhiteSpace()); + setRGBColor(color); + } + else + { + color.setRgb(handle->correctPixel(r.toFloat() * 257, g.toFloat() * 257, b.toFloat() * 257)); + setRGBColor(color); + + m_colorType = SVG_COLORTYPE_RGBCOLOR_ICCCOLOR; + + if(!m_iccColor) + { + m_iccColor = new SVGICCColorImpl(); + m_iccColor->ref(); + } + + m_iccColor->setColorProfile(DOM::DOMString(content)); + + SVGNumberImpl *rnumber = SVGSVGElementImpl::createSVGNumber(); + rnumber->setValue(r.toFloat()); + + SVGNumberImpl *gnumber = SVGSVGElementImpl::createSVGNumber(); + gnumber->setValue(g.toFloat()); + + SVGNumberImpl *bnumber = SVGSVGElementImpl::createSVGNumber(); + bnumber->setValue(b.toFloat()); + + m_iccColor->colors()->clear(); + m_iccColor->colors()->appendItem(bnumber); + m_iccColor->colors()->appendItem(gnumber); + m_iccColor->colors()->appendItem(rnumber); + } +} + +void SVGColorImpl::setColor(unsigned short colorType, const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor) +{ + m_colorType = colorType; + + if(m_colorType == SVG_COLORTYPE_UNKNOWN || m_colorType == SVG_COLORTYPE_CURRENTCOLOR) + return; + + setRGBColorICCColor(rgbColor, iccColor); +} + +// Ecma stuff +/* +@namespace KSVG +@begin SVGColorImpl::s_hashTable 5 + colorType SVGColorImpl::ColorType DontDelete|ReadOnly + RGBColor SVGColorImpl::RGBColor DontDelete|ReadOnly + ICCColor SVGColorImpl::ICCColor DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGColorImplProto::s_hashTable 5 + setRGBColor SVGColorImpl::SetRGBColor DontDelete|Function 1 + setRGBColorICCColor SVGColorImpl::SetRGBColorICCColor DontDelete|Function 2 + setColor SVGColorImpl::SetColor DontDelete|Function 3 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGColor", SVGColorImplProto, SVGColorImplProtoFunc) + +Value SVGColorImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case ColorType: + return Number(colorType()); +#ifdef __GNUC__ +#warning FIXME bridge stuff +#endif + case RGBColor: + return Undefined(); + case ICCColor: + return m_iccColor->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +Value SVGColorImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGColorImpl) + + switch(id) + { + case SVGColorImpl::SetRGBColor: + obj->setRGBColor(args[0].toString(exec).string()); + break; + case SVGColorImpl::SetRGBColorICCColor: + obj->setRGBColorICCColor(args[0].toString(exec).string(), args[1].toString(exec).string()); + break; + case SVGColorImpl::SetColor: + obj->setColor(static_cast(args[0].toNumber(exec)), args[1].toString(exec).string(), args[2].toString(exec).string()); + break; + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + +/* +@namespace KSVG +@begin SVGColorImplConstructor::s_hashTable 5 + SVG_COLORTYPE_UNKNOWN KSVG::SVG_COLORTYPE_UNKNOWN DontDelete|ReadOnly + SVG_COLORTYPE_RGBCOLOR KSVG::SVG_COLORTYPE_RGBCOLOR DontDelete|ReadOnly + SVG_COLORTYPE_RGBCOLOR_ICCCOLOR KSVG::SVG_COLORTYPE_RGBCOLOR_ICCCOLOR DontDelete|ReadOnly + SVG_COLORTYPE_CURRENTCOLOR KSVG::SVG_COLORTYPE_CURRENTCOLOR DontDelete|ReadOnly +@end +*/ + +Value SVGColorImplConstructor::getValueProperty(ExecState *, int token) const +{ + return Number(token); +} + +Value KSVG::getSVGColorImplConstructor(ExecState *exec) +{ + return cacheGlobalBridge(exec, "[[svgcolor.constructor]]"); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGColorImpl.h b/ksvg/impl/SVGColorImpl.h new file mode 100644 index 00000000..d49c6f82 --- /dev/null +++ b/ksvg/impl/SVGColorImpl.h @@ -0,0 +1,94 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGColorImpl_H +#define SVGColorImpl_H + +#include +#include +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ +class SVGElementImpl; +class SVGICCColorImpl; +class SVGColorImpl : public DOM::DomShared +{ +public: + SVGColorImpl(SVGElementImpl *object); + SVGColorImpl(const SVGColorImpl &); + virtual ~SVGColorImpl(); + + SVGColorImpl &operator=(const SVGColorImpl &); + + unsigned short colorType() const; + + DOM::RGBColor rgbColor() const; + SVGICCColorImpl *iccColor() const; + + virtual void setRGBColor(const DOM::DOMString &rgbColor); + virtual void setRGBColor(int r, int g, int b); + virtual void setRGBColor(QColor color); + virtual void setRGBColorICCColor(const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor); + virtual void setColor(unsigned short colorType, const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor); + +private: + unsigned short m_colorType; + DOM::RGBColor m_rgbColor; + SVGICCColorImpl *m_iccColor; + SVGElementImpl *m_object; + +public: + KSVG_BASECLASS_GET + + enum + { + // Properties + ColorType, RGBColor, ICCColor, + // Functions + SetRGBColor, SetRGBColorICCColor, SetColor + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +class SVGColorImplConstructor : public KJS::ObjectImp +{ +public: + SVGColorImplConstructor(KJS::ExecState *) { } + KJS::Value getValueProperty(KJS::ExecState *, int token) const; + + // no put - all read-only + KSVG_GET +}; + +KJS::Value getSVGColorImplConstructor(KJS::ExecState *exec); + +} + +KSVG_DEFINE_PROTOTYPE(SVGColorImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGColorImplProtoFunc, SVGColorImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGColorProfileElementImpl.cc b/ksvg/impl/SVGColorProfileElementImpl.cc new file mode 100644 index 00000000..f898188b --- /dev/null +++ b/ksvg/impl/SVGColorProfileElementImpl.cc @@ -0,0 +1,271 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include +#include + +#include + +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" + +#include "SVGRenderingIntent.h" + +#include "SVGAnimatedStringImpl.h" +#include "SVGColorProfileElementImpl.h" + +using namespace KSVG; + +#include "SVGColorProfileElementImpl.lut.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGColorProfileElementImpl::SVGColorProfileElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGURIReferenceImpl() +{ + KSVG_EMPTY_FLAGS + + m_loaded = false; + + // Spec: Default value 'auto', if not overwritten later + m_renderingIntent = RENDERING_INTENT_AUTO; +} + +SVGColorProfileElementImpl::~SVGColorProfileElementImpl() +{ + if(m_loaded) + closeColorProfile(); +} + +/* +@namespace KSVG +@begin SVGColorProfileElementImpl::s_hashTable 5 + name SVGColorProfileElementImpl::Name DontDelete|ReadOnly + href SVGColorProfileElementImpl::Href DontDelete|ReadOnly + rendering-intent SVGColorProfileElementImpl::RenderingIntent DontDelete|ReadOnly +@end +*/ + +Value SVGColorProfileElementImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case Name: + return String(m_name); + case Href: + return href()->cache(exec); + case RenderingIntent: + return Number(m_renderingIntent); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGColorProfileElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case Name: + m_name = value.toString(exec).string(); + ownerDoc()->rootElement()->addToIdMap(m_name.string(), this); + break; + case Href: + href()->setBaseVal(value.toString(exec).string()); + break; + case RenderingIntent: + { + QString compare = value.toString(exec).qstring().lower(); + + if(compare == "perceptual") + m_renderingIntent = RENDERING_INTENT_PERCEPTUAL; + else if(compare == "relative-colorimetric") + m_renderingIntent = RENDERING_INTENT_RELATIVE_COLORIMETRIC; + else if(compare == "saturation") + m_renderingIntent = RENDERING_INTENT_SATURATION; + else if(compare == "absolute-colorimetric") + m_renderingIntent = RENDERING_INTENT_ABSOLUTE_COLORIMETRIC; + else + m_renderingIntent = RENDERING_INTENT_AUTO; + break; + } + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +void SVGColorProfileElementImpl::setLocal(const DOM::DOMString &local) +{ + m_local = local; +} + +DOM::DOMString SVGColorProfileElementImpl::local() const +{ + return m_local; +} + +void SVGColorProfileElementImpl::setName(const DOM::DOMString &name) +{ + m_name = name; +} + +DOM::DOMString SVGColorProfileElementImpl::name() const +{ + return m_name; +} + +void SVGColorProfileElementImpl::setRenderingIntent(unsigned short renderingIntent) +{ + m_renderingIntent = renderingIntent; +} + +unsigned short SVGColorProfileElementImpl::renderingIntent() const +{ + return m_renderingIntent; +} + +bool SVGColorProfileElementImpl::canLoad() +{ + QString open; + bool temp; + return canLoad(false, temp, open, true); +} + +bool SVGColorProfileElementImpl::canLoad(bool remote, bool &tempFile, QString &open, bool verbose) +{ + KURL file; + + if(!KURL::isRelativeURL(href()->baseVal().string())) + file = KURL(href()->baseVal().string()); + else + file = KURL(ownerDoc()->baseUrl(), href()->baseVal().string()); + + if(file.path().isEmpty()) + { + if(verbose) + kdDebug() << "Couldn't load color profile " << file.path() << "!" << endl; + + return false; + } + + if(file.isLocalFile()) + { + open = file.path(); + + if(!QFile::exists(open)) + { + if(verbose) + kdDebug() << "Couldn't load color profile " << file.path() << "! It does not exist." << endl; + + return false; + } + } + else + { + if(remote) + { + if(KIO::NetAccess::download(file, open, 0)) + tempFile = true; + } + } + + return true; +} + +bool SVGColorProfileElementImpl::loadColorProfile() +{ + QString open; + bool tempFile = false; + + if(!canLoad(true, tempFile, open, false)) + return false; + + m_hInput = cmsOpenProfileFromFile(open.latin1(), "r"); + m_hOutput = cmsCreate_sRGBProfile(); + + unsigned int dwIn = BYTES_SH(2) | CHANNELS_SH(_cmsChannelsOf(m_inputColorSpace)); + unsigned int dwOut = BYTES_SH(2) | CHANNELS_SH(_cmsChannelsOf(m_outputColorSpace)); + + if(m_renderingIntent != RENDERING_INTENT_AUTO) + m_hTrans = cmsCreateTransform(m_hInput, dwIn, m_hOutput, dwOut, m_renderingIntent - 2, cmsFLAGS_NOTPRECALC); + else + m_hTrans = cmsCreateTransform(m_hInput, dwIn, m_hOutput, dwOut, cmsTakeRenderingIntent(m_hInput), cmsFLAGS_NOTPRECALC); + + m_inputColorSpace = cmsGetColorSpace(m_hInput); + m_outputColorSpace = cmsGetColorSpace(m_hOutput); + m_loaded = true; + + if(tempFile) + KIO::NetAccess::removeTempFile(open); + + return true; +} + +void SVGColorProfileElementImpl::closeColorProfile() +{ + cmsDeleteTransform(m_hTrans); + cmsCloseProfile(m_hInput); +} + +QRgb SVGColorProfileElementImpl::correctPixel(float r, float g, float b) +{ + if(!m_loaded) + { + if(!loadColorProfile()) + return qRgb(0, 0, 0); + } + + unsigned short input[MAXCHANNELS], output[MAXCHANNELS]; + + input[0] = ((unsigned int) r) * 257; + input[1] = ((unsigned int) g) * 257; + input[2] = ((unsigned int) b) * 257; + + cmsDoTransform(m_hTrans, input, output, 1); + + if(m_outputColorSpace == icSigRgbData) + return qRgb(output[0] / 257, output[1] / 257, output[2] / 257); + + return qRgb(0, 0, 0); +} + +QImage *SVGColorProfileElementImpl::correctImage(QImage *input) +{ + if(!canLoad()) + return input; + + for(int y = 0; y < input->height(); y++) + { + for(int x = 0; x < input->width(); x++) + { + QRgb pixel = input->pixel(x, y); + input->setPixel(x, y, correctPixel(qRed(pixel), qGreen(pixel), qBlue(pixel))); + } + } + + return input; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGColorProfileElementImpl.h b/ksvg/impl/SVGColorProfileElementImpl.h new file mode 100644 index 00000000..2f735f03 --- /dev/null +++ b/ksvg/impl/SVGColorProfileElementImpl.h @@ -0,0 +1,100 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGColorProfileElementImpl_H +#define SVGColorProfileElementImpl_H + +#include + +// Provided by configure checks.... +#include +#undef QT_VERSION // Needed for 1.08 *grml* +#include LCMS_HEADER + +#include "SVGElementImpl.h" +#include "SVGURIReferenceImpl.h" + +#include "ksvg_lookup.h" + +class QImage; + +namespace KSVG +{ + +class SVGColorProfileElementImpl : public SVGElementImpl, + public SVGURIReferenceImpl +{ +public: + SVGColorProfileElementImpl(DOM::ElementImpl *); + virtual ~SVGColorProfileElementImpl(); + + void setLocal(const DOM::DOMString &local); + DOM::DOMString local() const; + + void setName(const DOM::DOMString &name); + DOM::DOMString name() const; + + void setRenderingIntent(unsigned short renderingIntent); + unsigned short renderingIntent() const; + + QImage *correctImage(QImage *input); + QRgb correctPixel(float r, float g, float b); + +private: + bool loadColorProfile(); + void closeColorProfile(); + + bool canLoad(); + bool canLoad(bool remote, bool &tempFile, QString &open, bool verbose); + + DOM::DOMString m_local; + DOM::DOMString m_name; + unsigned short m_renderingIntent; + + bool m_loaded; + + cmsHPROFILE m_hInput, m_hOutput; + cmsHTRANSFORM m_hTrans; + int m_intent; + + icColorSpaceSignature m_inputColorSpace, m_outputColorSpace; + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + Name, Href, RenderingIntent + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGColorProfileElementImpl, "color-profile") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGColorProfileRuleImpl.cc b/ksvg/impl/SVGColorProfileRuleImpl.cc new file mode 100644 index 00000000..3cfca560 --- /dev/null +++ b/ksvg/impl/SVGColorProfileRuleImpl.cc @@ -0,0 +1,63 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGColorProfileRuleImpl.h" + +using namespace KSVG; + +SVGColorProfileRuleImpl::SVGColorProfileRuleImpl() : SVGCSSRuleImpl() +{ +} + +SVGColorProfileRuleImpl::~SVGColorProfileRuleImpl() +{ +} + +void SVGColorProfileRuleImpl::setSrc(const DOM::DOMString &src) +{ + m_src = src; +} + +DOM::DOMString SVGColorProfileRuleImpl::src() const +{ + return m_src; +} + +void SVGColorProfileRuleImpl::setName(const DOM::DOMString &name) +{ + m_name = name; +} + +DOM::DOMString SVGColorProfileRuleImpl::name() const +{ + return m_name; +} + +void SVGColorProfileRuleImpl::setRenderingIntent(unsigned short renderingIntent) +{ + m_renderingIntent = renderingIntent; +} + +unsigned short SVGColorProfileRuleImpl::renderingIntent() const +{ + return m_renderingIntent; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGColorProfileRuleImpl.h b/ksvg/impl/SVGColorProfileRuleImpl.h new file mode 100644 index 00000000..976a76a8 --- /dev/null +++ b/ksvg/impl/SVGColorProfileRuleImpl.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGColorProfileRuleImpl_H +#define SVGColorProfileRuleImpl_H + +#include + +#include "SVGCSSRuleImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGColorProfileRuleImpl : public SVGCSSRuleImpl +{ +public: + SVGColorProfileRuleImpl(); + virtual ~SVGColorProfileRuleImpl(); + + void setSrc(const DOM::DOMString &src); + DOM::DOMString src() const; + + void setName(const DOM::DOMString &name); + DOM::DOMString name() const; + + void setRenderingIntent(unsigned short renderingIntent); + unsigned short renderingIntent() const; + +private: + DOM::DOMString m_src; + DOM::DOMString m_name; + unsigned short m_renderingIntent; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGComponentTransferFunctionElementImpl.cc b/ksvg/impl/SVGComponentTransferFunctionElementImpl.cc new file mode 100644 index 00000000..0db14aae --- /dev/null +++ b/ksvg/impl/SVGComponentTransferFunctionElementImpl.cc @@ -0,0 +1,105 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedNumberImpl.h" +#include "SVGAnimatedNumberListImpl.h" +#include "SVGAnimatedEnumerationImpl.h" +#include "SVGComponentTransferFunctionElementImpl.h" + +using namespace KSVG; + +SVGComponentTransferFunctionElementImpl::SVGComponentTransferFunctionElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl) +{ + m_type = new SVGAnimatedEnumerationImpl(); + m_type->ref(); + + m_tableValues = new SVGAnimatedNumberListImpl(); + m_tableValues->ref(); + + m_slope = new SVGAnimatedNumberImpl(); + m_slope->ref(); + + m_intercept = new SVGAnimatedNumberImpl(); + m_intercept->ref(); + + m_amplitude = new SVGAnimatedNumberImpl(); + m_amplitude->ref(); + + m_exponent = new SVGAnimatedNumberImpl(); + m_exponent->ref(); + + m_offset = new SVGAnimatedNumberImpl(); + m_offset->ref(); +} + +SVGComponentTransferFunctionElementImpl::~SVGComponentTransferFunctionElementImpl() +{ + if(m_type) + m_type->deref(); + if(m_tableValues) + m_tableValues->deref(); + if(m_slope) + m_slope->deref(); + if(m_intercept) + m_intercept->deref(); + if(m_amplitude) + m_amplitude->deref(); + if(m_exponent) + m_exponent->deref(); + if(m_offset) + m_offset->deref(); +} + +SVGAnimatedEnumerationImpl *SVGComponentTransferFunctionElementImpl::type() const +{ + return m_type; +} + +SVGAnimatedNumberListImpl *SVGComponentTransferFunctionElementImpl::tableValues() const +{ + return m_tableValues; +} + +SVGAnimatedNumberImpl *SVGComponentTransferFunctionElementImpl::slope() const +{ + return m_slope; +} + +SVGAnimatedNumberImpl *SVGComponentTransferFunctionElementImpl::intercept() const +{ + return m_intercept; +} + +SVGAnimatedNumberImpl *SVGComponentTransferFunctionElementImpl::amplitude() const +{ + return m_amplitude; +} + +SVGAnimatedNumberImpl *SVGComponentTransferFunctionElementImpl::exponent() const +{ + return m_exponent; +} + +SVGAnimatedNumberImpl *SVGComponentTransferFunctionElementImpl::offset() const +{ + return m_offset; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGComponentTransferFunctionElementImpl.h b/ksvg/impl/SVGComponentTransferFunctionElementImpl.h new file mode 100644 index 00000000..e277d462 --- /dev/null +++ b/ksvg/impl/SVGComponentTransferFunctionElementImpl.h @@ -0,0 +1,66 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGComponentTransferFunctionElementImpl_H +#define SVGComponentTransferFunctionElementImpl_H + +#include "SVGElementImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedNumberImpl; +class SVGAnimatedNumberListImpl; +class SVGAnimatedEnumerationImpl; +class SVGComponentTransferFunctionElementImpl : public SVGElementImpl +{ +public: + SVGComponentTransferFunctionElementImpl(DOM::ElementImpl *); + virtual ~SVGComponentTransferFunctionElementImpl(); + + SVGAnimatedEnumerationImpl *type() const; + SVGAnimatedNumberListImpl *tableValues() const; + SVGAnimatedNumberImpl *slope() const; + SVGAnimatedNumberImpl *intercept() const; + SVGAnimatedNumberImpl *amplitude() const; + SVGAnimatedNumberImpl *exponent() const; + SVGAnimatedNumberImpl *offset() const; + +private: + SVGAnimatedEnumerationImpl *m_type; + SVGAnimatedNumberListImpl *m_tableValues; + SVGAnimatedNumberImpl *m_slope; + SVGAnimatedNumberImpl *m_intercept; + SVGAnimatedNumberImpl *m_amplitude; + SVGAnimatedNumberImpl *m_exponent; + SVGAnimatedNumberImpl *m_offset; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGContainerImpl.cc b/ksvg/impl/SVGContainerImpl.cc new file mode 100644 index 00000000..88fb87a8 --- /dev/null +++ b/ksvg/impl/SVGContainerImpl.cc @@ -0,0 +1,135 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGRectImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGContainerImpl.h" +#include "SVGSVGElementImpl.h" +#include "kdebug.h" + +using namespace KSVG; + +SVGContainerImpl::SVGContainerImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl) +{ +} + +SVGContainerImpl::~SVGContainerImpl() +{ +} + +SVGRectImpl *SVGContainerImpl::getBBox() +{ + // just get the union of the children bboxes + QRect rect; + DOM::Node node = firstChild(); + for(; !node.isNull(); node = node.nextSibling()) + { + SVGElementImpl *elem = ownerDoc()->getElementFromHandle(node.handle()); + SVGShapeImpl *shape = dynamic_cast(elem); + SVGTestsImpl *tests = dynamic_cast(elem); + SVGStylableImpl *style = dynamic_cast(elem); + + bool ok = tests ? tests->ok() : true; + + if(shape && style && ok && style->getVisible() && style->getDisplay()) + { + SVGRectImpl *current = shape->getBBox(); + rect = rect.unite(current->qrect()); + current->deref(); + } + } + + SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect(); + *ret = rect; + return ret; +} + +void SVGContainerImpl::createItem(KSVGCanvas *c) +{ + DOM::Node node = firstChild(); + for(; !node.isNull(); node = node.nextSibling()) + { + SVGElementImpl *elem = ownerDoc()->getElementFromHandle(node.handle()); + if(elem) + elem->createItem(c); + } +} + +void SVGContainerImpl::removeItem(KSVGCanvas *c) +{ + SVGShapeImpl::removeItem(c); + + for(DOM::Node node = firstChild(); !node.isNull(); node = node.nextSibling()) + { + SVGElementImpl *elem = ownerDoc()->getElementFromHandle(node.handle()); + if(elem) + elem->removeItem(c); + } +} + +void SVGContainerImpl::update(CanvasItemUpdate reason, int param1, int param2) +{ + SVGShapeImpl::update(reason, param1, param2); + + for(DOM::Node node = firstChild(); !node.isNull(); node = node.nextSibling()) + { + SVGShapeImpl *shape = dynamic_cast(ownerDoc()->getElementFromHandle(node.handle())); + if(shape) + shape->update(reason, param1, param2); + } +} + +void SVGContainerImpl::invalidate(KSVGCanvas *c, bool recalc) +{ + SVGShapeImpl::invalidate(c, recalc); + + for(DOM::Node node = firstChild(); !node.isNull(); node = node.nextSibling()) + { + SVGShapeImpl *shape = dynamic_cast(ownerDoc()->getElementFromHandle(node.handle())); + if(shape) + shape->invalidate(c, recalc); + } +} + +void SVGContainerImpl::setReferenced(bool referenced) +{ + SVGShapeImpl::setReferenced(referenced); + + for(DOM::Node node = firstChild(); !node.isNull(); node = node.nextSibling()) + { + SVGShapeImpl *shape = dynamic_cast(ownerDoc()->getElementFromHandle(node.handle())); + if(shape) + shape->setReferenced(referenced); + } +} + +void SVGContainerImpl::draw() +{ + SVGShapeImpl::draw(); + + for(DOM::Node node = firstChild(); !node.isNull(); node = node.nextSibling()) + { + SVGShapeImpl *shape = dynamic_cast(ownerDoc()->getElementFromHandle(node.handle())); + if(shape) + shape->draw(); + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGContainerImpl.h b/ksvg/impl/SVGContainerImpl.h new file mode 100644 index 00000000..353a6154 --- /dev/null +++ b/ksvg/impl/SVGContainerImpl.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGContainerImpl_H +#define SVGContainerImpl_H + +#include "SVGShapeImpl.h" + +namespace KSVG +{ +enum CanvasItemUpdate; +class KSVGCanvas; + +class SVGContainerImpl : public SVGShapeImpl +{ +public: + SVGContainerImpl(DOM::ElementImpl *); + virtual ~SVGContainerImpl(); + + virtual bool isContainer() const { return true; } + + virtual void createItem(KSVGCanvas *c = 0); + virtual void removeItem(KSVGCanvas *c); + + virtual void update(CanvasItemUpdate reason, int param1, int param2); + virtual void invalidate(KSVGCanvas *c, bool recalc); + virtual void setReferenced(bool referenced); + virtual void draw(); + + virtual SVGRectImpl *getBBox(); + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGCursorElementImpl.cc b/ksvg/impl/SVGCursorElementImpl.cc new file mode 100644 index 00000000..331f8826 --- /dev/null +++ b/ksvg/impl/SVGCursorElementImpl.cc @@ -0,0 +1,104 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGCursorElementImpl.h" +#include "SVGAnimatedLengthImpl.h" + +using namespace KSVG; + +#include "SVGCursorElementImpl.lut.h" +#include "ksvg_bridge.h" + +SVGCursorElementImpl::SVGCursorElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGURIReferenceImpl(), SVGTestsImpl(), SVGExternalResourcesRequiredImpl() +{ + KSVG_EMPTY_FLAGS + + m_x = new SVGAnimatedLengthImpl(); + m_x->ref(); + + m_y = new SVGAnimatedLengthImpl(); + m_y->ref(); +} + +SVGCursorElementImpl::~SVGCursorElementImpl() +{ + if(m_x) + m_x->deref(); + if(m_y) + m_y->deref(); +} + +SVGAnimatedLengthImpl *SVGCursorElementImpl::x() const +{ + return m_x; +} + +SVGAnimatedLengthImpl *SVGCursorElementImpl::y() const +{ + return m_y; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGCursorElementImpl::s_hashTable 3 + x SVGCursorElementImpl::X DontDelete|ReadOnly + y SVGCursorElementImpl::Y DontDelete|ReadOnly +@end +*/ + +Value SVGCursorElementImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case X: + return m_x->cache(exec); + case Y: + return m_y->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGCursorElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case X: + x()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case Y: + y()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGCursorElementImpl.h b/ksvg/impl/SVGCursorElementImpl.h new file mode 100644 index 00000000..a063acd0 --- /dev/null +++ b/ksvg/impl/SVGCursorElementImpl.h @@ -0,0 +1,69 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGCursorElementImpl_H +#define SVGCursorElementImpl_H + +#include "SVGTestsImpl.h" +#include "SVGElementImpl.h" +#include "SVGURIReferenceImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedLengthImpl; +class SVGCursorElementImpl : public SVGElementImpl, + public SVGURIReferenceImpl, + public SVGTestsImpl, + public SVGExternalResourcesRequiredImpl +{ +public: + SVGCursorElementImpl(DOM::ElementImpl *); + virtual ~SVGCursorElementImpl(); + + SVGAnimatedLengthImpl *x() const; + SVGAnimatedLengthImpl *y() const; + +private: + SVGAnimatedLengthImpl *m_x; + SVGAnimatedLengthImpl *m_y; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + X, Y + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGDefinitionSrcElementImpl.cc b/ksvg/impl/SVGDefinitionSrcElementImpl.cc new file mode 100644 index 00000000..cf5d764c --- /dev/null +++ b/ksvg/impl/SVGDefinitionSrcElementImpl.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGDefinitionSrcElementImpl.h" + +using namespace KSVG; + +SVGDefinitionSrcElementImpl::SVGDefinitionSrcElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl) +{ +} + +SVGDefinitionSrcElementImpl::~SVGDefinitionSrcElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGDefinitionSrcElementImpl.h b/ksvg/impl/SVGDefinitionSrcElementImpl.h new file mode 100644 index 00000000..65fb359c --- /dev/null +++ b/ksvg/impl/SVGDefinitionSrcElementImpl.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGDefinitionSrcElementImpl_H +#define SVGDefinitionSrcElementImpl_H + +#include "SVGElementImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGDefinitionSrcElementImpl : public SVGElementImpl +{ +public: + SVGDefinitionSrcElementImpl(DOM::ElementImpl *); + virtual ~SVGDefinitionSrcElementImpl(); + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGDefsElementImpl.cc b/ksvg/impl/SVGDefsElementImpl.cc new file mode 100644 index 00000000..e5d7d398 --- /dev/null +++ b/ksvg/impl/SVGDefsElementImpl.cc @@ -0,0 +1,34 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGDefsElementImpl.h" + +using namespace KSVG; + +SVGDefsElementImpl::SVGDefsElementImpl(DOM::ElementImpl *impl) : SVGContainerImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl() +{ + m_display = false; // implicit display=none +} + +SVGDefsElementImpl::~SVGDefsElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGDefsElementImpl.h b/ksvg/impl/SVGDefsElementImpl.h new file mode 100644 index 00000000..e32f0dc9 --- /dev/null +++ b/ksvg/impl/SVGDefsElementImpl.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGDefsElementImpl_H +#define SVGDefsElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGTestsImpl.h" +#include "SVGStylableImpl.h" +#include "SVGContainerImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGTransformableImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +namespace KSVG +{ + +class SVGDefsElementImpl : public SVGContainerImpl, + public SVGTestsImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGTransformableImpl +{ +public: + SVGDefsElementImpl(DOM::ElementImpl *); + virtual ~SVGDefsElementImpl(); + + virtual bool directRender() { return false; } + +public: + KSVG_BRIDGE + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +KSVG_REGISTER_ELEMENT(SVGDefsElementImpl, "defs") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGDescElementImpl.cc b/ksvg/impl/SVGDescElementImpl.cc new file mode 100644 index 00000000..cb0958dd --- /dev/null +++ b/ksvg/impl/SVGDescElementImpl.cc @@ -0,0 +1,39 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGDocumentImpl.h" +#include "SVGDescElementImpl.h" + +using namespace KSVG; + +SVGDescElementImpl::SVGDescElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGLangSpaceImpl(), SVGStylableImpl(this) +{ +} + +SVGDescElementImpl::~SVGDescElementImpl() +{ +} + +void SVGDescElementImpl::createItem(KSVGCanvas *) +{ + emit ownerDoc()->gotDescription(collectText()); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGDescElementImpl.h b/ksvg/impl/SVGDescElementImpl.h new file mode 100644 index 00000000..c8136eb6 --- /dev/null +++ b/ksvg/impl/SVGDescElementImpl.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGDescElementImpl_H +#define SVGDescElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGElementImpl.h" +#include "SVGStylableImpl.h" +#include "SVGLangSpaceImpl.h" + +namespace KSVG +{ + +class SVGDescElementImpl : public SVGElementImpl, + public SVGLangSpaceImpl, + public SVGStylableImpl +{ +public: + SVGDescElementImpl(DOM::ElementImpl *impl); + virtual ~SVGDescElementImpl(); + + virtual void createItem(KSVGCanvas *c = 0); + +public: + KSVG_BRIDGE + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +KSVG_REGISTER_ELEMENT(SVGDescElementImpl, "desc") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGDocumentImpl.cc b/ksvg/impl/SVGDocumentImpl.cc new file mode 100644 index 00000000..4bbe2664 --- /dev/null +++ b/ksvg/impl/SVGDocumentImpl.cc @@ -0,0 +1,705 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#define USE_VALGRIND 0 + +#if USE_VALGRIND +#include +#endif + +#include "SVGEvent.h" +#include "SVGMatrixImpl.h" +#include "SVGWindowImpl.h" +#include "SVGElementImpl.h" +#include "SVGDocumentImpl.moc" +#include "SVGSVGElementImpl.h" +#include "SVGImageElementImpl.h" +#include "SVGScriptElementImpl.h" +#include "SVGTitleElementImpl.h" +#include "SVGAnimationElementImpl.h" + +#include "KSVGReader.h" +#include "KSVGLoader.h" +#include "KSVGCanvas.h" +#include "CanvasItem.h" + +#include + +using namespace KSVG; + +#include "SVGDocumentImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +// A sequence of prime numbers that sets the m_elemDict's hash table size as the +// number of elements in the dictionary passes each level. This keeps the lookup +// performance high as the number of elements grows. See the QDict documentation. +unsigned int SVGDocumentImpl::elemDictHashSizes [] = +{ + 101, + 211, + 401, + 809, + 1601, + 3203, + 6421, + 12809, + 25601, + 51203, + 102407, + 204803, + 409609, + 819229 +}; + +const int SVGDocumentImpl::numElemDictHashSizes = sizeof(elemDictHashSizes) / sizeof(elemDictHashSizes[0]); + +SVGDocumentImpl::SVGDocumentImpl(bool anim, bool fit, SVGImageElementImpl *parentImage) : QObject(), DOM::DomShared(), DOM::Document(), SVGDOMNodeBridge(static_cast(*this)) +{ + m_animations = anim; + + m_reader = 0; + m_loader = 0; + m_canvas = 0; + m_rootElement = 0; + m_lastTarget = 0; + m_window = 0; + + m_elemDictHashSizeIndex = 0; + m_elemDict.resize(elemDictHashSizes[m_elemDictHashSizeIndex]); + + m_timeScheduler = new SVGTimeScheduler(this); + m_ecmaEngine = new KSVGEcma(this); + m_ecmaEngine->setup(); + + m_finishedParsing = false; + m_finishedLoading = false; + m_resortZIndicesOnFinishedLoading = false; + m_fit = fit; + + m_parentImage = parentImage; + if(m_parentImage) + m_parentImage->ref(); +} + +SVGDocumentImpl::~SVGDocumentImpl() +{ + if(rootElement() && rootElement()->hasEventListener(SVGEvent::UNLOAD_EVENT, true)) + rootElement()->dispatchEvent(SVGEvent::UNLOAD_EVENT, false, false); + + QPtrList killList; + + DOM::Node node = firstChild(); + for(; !node.isNull(); node = node.nextSibling()) + { + SVGShapeImpl *shape = dynamic_cast(getElementFromHandle(node.handle())); + if(shape) + killList.append(shape); + } + + SVGShapeImpl *rend = 0; + for(rend = killList.first(); rend; rend = killList.next()) + delete rend; + + delete m_timeScheduler; + delete m_ecmaEngine; + delete m_reader; + delete m_loader; + + if(m_window) + m_window->deref(); + + if(m_parentImage) + m_parentImage->deref(); +} + +SVGWindowImpl *SVGDocumentImpl::window() +{ + if(!m_window) + { + m_window = new SVGWindowImpl(const_cast(this)); + m_window->ref(); + } + + return m_window; +} + +float SVGDocumentImpl::screenPixelsPerMillimeterX() const +{ + if(canvas() && canvas()->drawWindow()) + { + QPaintDeviceMetrics metrics(canvas()->drawWindow()); + return float(metrics.width()) / float(metrics.widthMM()); + } + else + return 90.0; +} + +float SVGDocumentImpl::screenPixelsPerMillimeterY() const +{ + if(canvas() && canvas()->drawWindow()) + { + QPaintDeviceMetrics metrics(canvas()->drawWindow()); + return float(metrics.height()) / float(metrics.heightMM()); + } + else + return 90.0; +} + +DOM::DOMString SVGDocumentImpl::title() const +{ + DOM::Node n; + for(n = rootElement()->firstChild(); !n.isNull(); n = n.nextSibling()) + { + SVGElementImpl *elem = getElementFromHandle(n.handle()); + if(dynamic_cast(elem)) + return elem->collectText(); + } + return ""; +} + +DOM::DOMString SVGDocumentImpl::referrer() const +{ + return m_referrer; +} + +DOM::DOMString SVGDocumentImpl::domain() const +{ + return m_baseURL.host(); +} + +DOM::DOMString SVGDocumentImpl::URL() const +{ + return m_baseURL.prettyURL(); +} + +void SVGDocumentImpl::setReferrer(const DOM::DOMString &referrer) +{ + // TODO : better may be to request for referrer instead of storing it + m_referrer = referrer; +} + +void SVGDocumentImpl::setRootElement(SVGSVGElementImpl *elem) +{ + m_rootElement = elem; +} + +SVGSVGElementImpl *SVGDocumentImpl::rootElement() const +{ + return m_rootElement; +} + +SVGElementImpl *SVGDocumentImpl::createElement(const DOM::DOMString &name, DOM::Element impl, SVGDocumentImpl *doc) +{ + DOM::ElementImpl *handle = reinterpret_cast(impl.handle()); + SVGElementImpl *element = SVGElementImpl::Factory::self()->create(std::string(name.string().latin1()), handle); + + if(!element) + element = new SVGElementImpl(handle); + + element->setOwnerDoc(doc); + element->ref(); + return element; +} + +bool SVGDocumentImpl::open(const ::KURL &url) +{ + if(!url.prettyURL().isEmpty()) + { + m_baseURL = url; + + if(!m_loader) + m_loader = new KSVGLoader(); + + connect(m_loader, SIGNAL(gotResult(QIODevice *)), this, SLOT(slotSVGContent(QIODevice *))); + m_loader->getSVGContent(url); + } + else + return false; + + return true; +} + +void SVGDocumentImpl::slotSVGContent(QIODevice *dev) +{ + QXmlInputSource *inputSource = new QXmlInputSource(dev); + + if(m_reader) + delete m_reader; + + KSVGReader::ParsingArgs args; + args.fit = m_fit; + args.getURLMode = false; + + QString url = m_baseURL.prettyURL(); + int pos = url.find('#'); // url can become like this.svg#svgView(viewBox(63,226,74,74)), get part after '#' + if(pos > -1) + args.SVGFragmentId = url.mid(pos + 1); + + m_reader = new KSVGReader(this, m_canvas, args); + connect(m_reader, SIGNAL(finished(bool, const QString &)), this, SLOT(slotFinishedParsing(bool, const QString &))); + m_t.start(); + +#if USE_VALGRIND + CALLTREE_ZERO_STATS(); +#endif + + m_reader->parse(inputSource); + delete dev; +} + +void SVGDocumentImpl::parseSVG(QXmlInputSource *inputSource, bool getURLMode) +{ + if(m_reader) + delete m_reader; + + KSVGReader::ParsingArgs args; + args.fit = m_fit; + args.getURLMode = getURLMode; + m_reader = new KSVGReader(this, 0, args); + connect(m_reader, SIGNAL(finished(bool, const QString &)), this, SLOT(slotFinishedParsing(bool, const QString &))); + +#if USE_VALGRIND + CALLTREE_ZERO_STATS(); +#endif + + m_reader->parse(inputSource); +} + +void SVGDocumentImpl::finishParsing(bool error, const QString &errorDesc) +{ + if(m_reader) + m_reader->finishParsing(error, errorDesc); +} + +void SVGDocumentImpl::slotFinishedParsing(bool error, const QString &errorDesc) +{ + kdDebug(26000) << k_funcinfo << "total time : " << m_t.elapsed() << endl; + +#if USE_VALGRIND + CALLTREE_DUMP_STATS(); +#endif + + if(m_animations) + m_timeScheduler->startAnimations(); + + if(m_canvas && !error && rootElement()) + executeScripts(); + + m_finishedParsing = true; + + emit finishedParsing(error, errorDesc); + if(!error) + emit finishedRendering(); + + checkFinishedLoading(); +} + +void SVGDocumentImpl::newImageJob(SVGImageElementImpl *image) +{ + kdDebug(26002) << "SVGDocumentImpl::newImageJob, " << image << endl; + m_loader->newImageJob(image, m_baseURL); +} + +void SVGDocumentImpl::notifyImageLoading(SVGImageElementImpl *image) +{ + m_imagesLoading.append(image); +} + +void SVGDocumentImpl::notifyImageLoaded(SVGImageElementImpl *image) +{ + m_imagesLoading.remove(image); + + if(m_imagesLoading.isEmpty()) + checkFinishedLoading(); +} + +void SVGDocumentImpl::checkFinishedLoading() +{ + if(m_finishedParsing && m_imagesLoading.isEmpty()) + { + m_finishedLoading = true; + + if(m_resortZIndicesOnFinishedLoading) + { + // Only resort if we're the 'outermost' document, i.e. we're not an svg image + // inside another document. We could resort as each image finishes loading, but it + // slows down the parsing phase. + if(m_parentImage == 0 && m_canvas && m_rootElement) + { + m_canvas->setElementItemZIndexRecursive(m_rootElement, 0); + m_canvas->update(); + } + } + + emit finishedLoading(); + } +} + +void SVGDocumentImpl::addForwardReferencingUseElement(SVGUseElementImpl *use) +{ + if(!m_forwardReferencingUseElements.contains(use)) + m_forwardReferencingUseElements.append(use); +} + +void SVGDocumentImpl::slotPaint() +{ + rerender(); +} + +void SVGDocumentImpl::rerender() +{ + m_canvas->update(); + emit finishedRendering(); +} + +void SVGDocumentImpl::attach(KSVG::KSVGCanvas *c) +{ + m_canvas = c; +} + +void SVGDocumentImpl::detach() +{ + m_canvas = 0; +} + +KSVG::KSVGCanvas *SVGDocumentImpl::canvas() const +{ + return m_canvas; +} + +void SVGDocumentImpl::syncCachedMatrices() +{ + if(rootElement()) + { + SVGMatrixImpl *parentMatrix = SVGSVGElementImpl::createSVGMatrix(); + rootElement()->checkCachedScreenCTM(parentMatrix); + parentMatrix->deref(); + } +} + +void SVGDocumentImpl::executeScriptsRecursive(DOM::Node start) +{ + DOM::Node node = start.firstChild(); + + for(; !node.isNull(); node = node.nextSibling()) + { + SVGElementImpl *element = getElementFromHandle(node.handle()); + + SVGContainerImpl *container = dynamic_cast(element); + if(container) + executeScriptsRecursive(node); + + SVGScriptElementImpl *script = dynamic_cast(element); + + if(script) + script->executeScript(DOM::Node()); + } +} + +bool SVGDocumentImpl::executeScriptsRecursiveCheck(DOM::Node start) +{ + bool test = true; + + DOM::Node node = start.firstChild(); + + for(; !node.isNull(); node = node.nextSibling()) + { + SVGElementImpl *element = getElementFromHandle(node.handle()); + + SVGContainerImpl *container = dynamic_cast(element); + if(container) + { + if(!executeScriptsRecursiveCheck(node)) + return false; + } + + SVGScriptElementImpl *script = dynamic_cast(element); + + if(script) + { + if(!script->canExecuteScript()) + { + test = false; + break; + } + } + } + + return test; +} + +void SVGDocumentImpl::executeScripts() +{ + bool test = executeScriptsRecursiveCheck(*rootElement()); + + if(!test) + QTimer::singleShot(50, this, SLOT(executeScripts())); + else + { + executeScriptsRecursive(*rootElement()); + + // mop: only rerender if an loadevent has been found + if(dispatchRecursiveEvent(SVGEvent::LOAD_EVENT, lastChild())) + m_canvas->update(); + } +} + +// Dispatches a non-cancelable, non-bubbles event to every child +bool SVGDocumentImpl::dispatchRecursiveEvent(SVGEvent::EventId id, DOM::Node start) +{ + bool eventExecuted = false; + + // Iterate the tree, backwards, and dispatch the event to every child + DOM::Node node = start; + for(; !node.isNull(); node = node.previousSibling()) + { + SVGElementImpl *element = getElementFromHandle(node.handle()); + + if(element && element->hasChildNodes()) + { + // Dispatch to all children + eventExecuted = dispatchRecursiveEvent(id, element->lastChild()) ? true : eventExecuted; + + // Dispatch, locally + if(element->hasEventListener(id, true)) + { + element->dispatchEvent(id, false, false); + eventExecuted = true; + } + } + else if(element && element->hasEventListener(id, true)) + { + element->dispatchEvent(id, false, false); + eventExecuted = true; + } + } + + return eventExecuted; +} + +SVGEventListener *SVGDocumentImpl::createEventListener(DOM::DOMString type) +{ + return m_ecmaEngine->createEventListener(type); +} + +SVGElementImpl *SVGDocumentImpl::recursiveSearch(DOM::Node start, const DOM::DOMString &id) +{ + DOM::Node node = start.firstChild(); + for(; !node.isNull(); node = node.nextSibling()) + { + SVGElementImpl *test = getElementFromHandle(node.handle()); + + // Look in containers + SVGContainerImpl *container = dynamic_cast(test); + if(container) + { + SVGElementImpl *found = recursiveSearch(node, id); + if(found) + return found; + } + + // Look in SVGSVGElementImpl's + SVGSVGElementImpl *svgtest = dynamic_cast(test); + if(svgtest) + { + SVGElementImpl *element = svgtest->getElementById(id); + if(element) + return element; + } + } + + return 0; +} + +/* +@namespace KSVG +@begin SVGDocumentImpl::s_hashTable 9 + title SVGDocumentImpl::Title DontDelete|ReadOnly + referrer SVGDocumentImpl::Referrer DontDelete|ReadOnly + domain SVGDocumentImpl::Domain DontDelete|ReadOnly + URL SVGDocumentImpl::Url DontDelete|ReadOnly + doctype SVGDocumentImpl::DocType DontDelete|ReadOnly + implementation SVGDocumentImpl::Implementation DontDelete|ReadOnly + rootElement SVGDocumentImpl::RootElement DontDelete|ReadOnly + documentElement SVGDocumentImpl::DocumentElement DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGDocumentImplProto::s_hashTable 7 + createTextNode SVGDocumentImpl::CreateTextNode DontDelete|Function 1 + createElement SVGDocumentImpl::CreateElement DontDelete|Function 1 + createElementNS SVGDocumentImpl::CreateElementNS DontDelete|Function 2 + getElementById SVGDocumentImpl::GetElementById DontDelete|Function 1 + getElementsByTagName SVGDocumentImpl::GetElementsByTagName DontDelete|Function 1 + getElementsByTagNameNS SVGDocumentImpl::GetElementsByTagNameNS DontDelete|Function 2 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGDocument", SVGDocumentImplProto, SVGDocumentImplProtoFunc) + +Value SVGDocumentImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case Title: + return String(title().string()); + case Referrer: + return String(referrer().string()); + case Domain: + return String(domain().string()); + case Url: + return String(URL().string()); + case DocType: + return getDOMNode(exec, doctype()); + case Implementation: + return (new SVGDOMDOMImplementationBridge(implementation()))->cache(exec); + case RootElement: + case DocumentElement: + return m_rootElement->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +Value SVGDocumentImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGDocumentImpl) + + switch(id) + { + case SVGDocumentImpl::CreateTextNode: + return getDOMNode(exec, obj->createTextNode(args[0].toString(exec).string())); + case SVGDocumentImpl::CreateElement: + case SVGDocumentImpl::CreateElementNS: + { + SVGElementImpl *newElement = 0; + + if(id == SVGDocumentImpl::CreateElement) + newElement = obj->createElement(args[0].toString(exec).qstring(), static_cast(obj)->createElement(args[0].toString(exec).string()), obj); + else if(id == SVGDocumentImpl::CreateElementNS) + newElement = obj->createElement(args[1].toString(exec).qstring(), static_cast(obj)->createElementNS(args[0].toString(exec).string(), args[1].toString(exec).string()), obj); + + newElement->setOwnerSVGElement(obj->rootElement()); // FIXME: Correct in all situations? + newElement->setViewportElement(obj->rootElement()); + newElement->setAttributes(); + + return getDOMNode(exec, *newElement); + } + case SVGDocumentImpl::GetElementById: + { + Value ret; + + SVGElementImpl *element = obj->rootElement()->getElementById(args[0].toString(exec).string()); + + if(element) + ret = getDOMNode(exec, *element); + else + { + element = obj->recursiveSearch(*obj, args[0].toString(exec).string()); + if(!element) + return Null(); + + ret = getDOMNode(exec, *element); + } + + return ret; + } + case SVGDocumentImpl::GetElementsByTagName: + return (new SVGDOMNodeListBridge(obj->getElementsByTagName(args[0].toString(exec).string())))->cache(exec); + case SVGDocumentImpl::GetElementsByTagNameNS: + return (new SVGDOMNodeListBridge(obj->getElementsByTagNameNS(args[0].toString(exec).string(), args[1].toString(exec).string())))->cache(exec); + default: + break; + } + + return KJS::Undefined(); +} + +SVGElementImpl *SVGDocumentImpl::getElementFromHandle(DOM::NodeImpl *handle) const +{ + return m_elemDict[handle]; +} + +void SVGDocumentImpl::addToElemDict(DOM::NodeImpl *handle, SVGElementImpl *obj) +{ + m_elemDict.insert(handle, obj); + + if(m_elemDict.count()>m_elemDict.size() && m_elemDictHashSizeIndexgetElementById(elementId); + + if(element) + return element; + } + + // #2 Search in all child SVGSVGElementImpl's + element = recursiveSearch(*this, elementId); + + if(element) + return element; + + // #3 Search in other documents + if(!dontSearch) + { + QPtrDictIterator it(m_documentDict); + for(; it.current(); ++it) + { + SVGElementImpl *temp = it.current()->getElementByIdRecursive(0, elementId, true); + if(temp) + return temp; + } + } + + return element; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGDocumentImpl.h b/ksvg/impl/SVGDocumentImpl.h new file mode 100644 index 00000000..c4156910 --- /dev/null +++ b/ksvg/impl/SVGDocumentImpl.h @@ -0,0 +1,245 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGDocumentImpl_H +#define SVGDocumentImpl_H + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "ksvg_lookup.h" + +#include "SVGEvent.h" +#include "SVGTimeScheduler.h" + +class KSVGEcma; +class KSVGRequest; + +namespace KJS +{ + class Value; + class UString; + class ExecState; + class Identifier; +} + +namespace KSVG +{ + +class SVGTimer; +class KSVGLoader; +class KSVGReader; +class KSVGCanvas; +class SVGImageElementImpl; +class SVGSVGElementImpl; +class SVGWindowImpl; +class SVGScriptElementImpl; +class SVGDescElementImpl; +class SVGTitleElementImpl; +class SVGUseElementImpl; +class SVGDocumentImpl : public QObject, + public DOM::DomShared, + public DOM::Document, + public SVGDOMNodeBridge +{ +Q_OBJECT +public: + SVGDocumentImpl(bool anim = true, bool bFit = false, SVGImageElementImpl *parentImage = 0); + virtual ~SVGDocumentImpl(); + + float screenPixelsPerMillimeterX() const; + float screenPixelsPerMillimeterY() const; + + DOM::DOMString title() const; + DOM::DOMString referrer() const; + DOM::DOMString domain() const; + DOM::DOMString URL() const; + + void setReferrer(const DOM::DOMString &referrer); + + void setRootElement(SVGSVGElementImpl *); + SVGSVGElementImpl *rootElement() const; + + SVGImageElementImpl *parentImage() const { return m_parentImage; } + + SVGWindowImpl *window(); + + static SVGElementImpl *createElement(const DOM::DOMString &name, DOM::Element impl, SVGDocumentImpl *doc = 0); + + bool open(const KURL &url); + void rerender(); + + void attach(KSVG::KSVGCanvas *p); + void detach(); + + bool ready() { return m_finishedParsing; } + + KURL baseUrl() { return m_baseURL; } + KSVGCanvas *canvas() const; + + // Ecma stuff + KSVGEcma *ecmaEngine() { return m_ecmaEngine; } + + void parseSVG(QXmlInputSource *inputSource, bool getURLMode = false); + + virtual bool implementsCall() const { return true; } + + void executeScriptsRecursive(DOM::Node start); + bool executeScriptsRecursiveCheck(DOM::Node start); + + bool dispatchRecursiveEvent(SVGEvent::EventId id, DOM::Node start); + + SVGElementImpl *getElementByIdRecursive(SVGSVGElementImpl *start, const DOM::DOMString &elementId, bool dontSearch = false); + + // Event stuff + SVGEventListener *createEventListener(DOM::DOMString type); + + void setLastTarget(SVGElementImpl *elem) { m_lastTarget = elem; } + SVGElementImpl *lastTarget() { return m_lastTarget; } + + // Animation stuff + SVGTimeScheduler *timeScheduler() const { return m_timeScheduler; } + + // Internal + SVGElementImpl *getElementFromHandle(DOM::NodeImpl *handle) const; + void addToElemDict(DOM::NodeImpl *handle, SVGElementImpl *obj); + void removeFromElemDict(DOM::NodeImpl *handle); + + SVGDocumentImpl *getDocumentFromHandle(DOM::NodeImpl *handle) const; + void addToDocumentDict(DOM::NodeImpl *handle, SVGDocumentImpl *obj); + + SVGElementImpl *recursiveSearch(DOM::Node start, const DOM::DOMString &id); + + void finishParsing(bool error, const QString &errorDesc); + + void newImageJob(SVGImageElementImpl *); + + void notifyImageLoading(SVGImageElementImpl *image); + void notifyImageLoaded(SVGImageElementImpl *image); + void resortZIndicesOnFinishedLoading() { m_resortZIndicesOnFinishedLoading = true; } + + void addForwardReferencingUseElement(SVGUseElementImpl *use); + QValueList forwardReferencingUseElements() const { return m_forwardReferencingUseElements; } + + // Traverse the element hierarchy and update any cached matrices that are + // no longer valid. + void syncCachedMatrices(); + +public slots: + void slotPaint(); + void executeScripts(); + +private slots: + void slotSVGContent(QIODevice *); + void slotFinishedParsing(bool error, const QString &errorDesc); + +// KDE invents public signals :) +#undef signals +#define signals public +signals: + void gotDescription(const QString &); + void gotTitle(const QString &); + void gotURL(const QString &); + + void finishedParsing(bool error, const QString &errorDesc); + void finishedRendering(); + void finishedLoading(); + +private: + void checkFinishedLoading(); + + bool m_finishedParsing; + bool m_finishedLoading; + bool m_animations; + + SVGSVGElementImpl *m_rootElement; + + SVGTimeScheduler *m_timeScheduler; + + // Set if this document is being displayed by an 'image' element reference + // rather than as the main document, 0 otherwise. + SVGImageElementImpl *m_parentImage; + + KSVGReader *m_reader; + KSVGLoader *m_loader; + KSVGCanvas *m_canvas; + + KSVGEcma *m_ecmaEngine; + + QPtrDict m_elemDict; + QPtrDict m_documentDict; + + static uint elemDictHashSizes[]; + static const int numElemDictHashSizes; + int m_elemDictHashSizeIndex; + + SVGWindowImpl *m_window; + SVGElementImpl *m_lastTarget; + + KURL m_baseURL; + + DOM::DOMString m_referrer; + + bool m_fit; + + QTime m_t; + + QValueList m_imagesLoading; + bool m_resortZIndicesOnFinishedLoading; + + QValueList m_forwardReferencingUseElements; + +public: + KSVG_BASECLASS_GET + KSVG_PUT + + enum + { + // Properties + Title, Referrer, Domain, Url, + DocType, Implementation, RootElement, DocumentElement, + // Functions + CreateTextNode, CreateElement, CreateElementNS, + GetElementById, GetElementsByTagName, GetElementsByTagNameNS + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +} + +KSVG_DEFINE_PROTOTYPE(SVGDocumentImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGDocumentImplProtoFunc, SVGDocumentImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGEcma.cc b/ksvg/impl/SVGEcma.cc new file mode 100644 index 00000000..08870d0c --- /dev/null +++ b/ksvg/impl/SVGEcma.cc @@ -0,0 +1,844 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include + +#include + +#include "CanvasItem.h" +#include "KSVGCanvas.h" + +#include "SVGEcma.h" +#include "SVGShapeImpl.h" +#include "SVGHelperImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" + +using namespace KSVG; + +#include "SVGEcma.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_ecmaeventlistener.h" +#include "ksvg_window.h" +#include "ksvg_ecma.h" + +// SVGDOMNodeBridge + +/* +@namespace KSVG +@begin SVGDOMNodeBridge::s_hashTable 17 + nodeName SVGDOMNodeBridge::NodeName DontDelete|ReadOnly + nodeValue SVGDOMNodeBridge::NodeValue DontDelete + nodeType SVGDOMNodeBridge::NodeType DontDelete|ReadOnly + parentNode SVGDOMNodeBridge::ParentNode DontDelete|ReadOnly + childNodes SVGDOMNodeBridge::ChildNodes DontDelete|ReadOnly + firstChild SVGDOMNodeBridge::FirstChild DontDelete|ReadOnly + lastChild SVGDOMNodeBridge::LastChild DontDelete|ReadOnly + previousSibling SVGDOMNodeBridge::PreviousSibling DontDelete|ReadOnly + nextSibling SVGDOMNodeBridge::NextSibling DontDelete|ReadOnly + attributes SVGDOMNodeBridge::Attributes DontDelete|ReadOnly + namespaceURI SVGDOMNodeBridge::NamespaceURI DontDelete|ReadOnly + prefix SVGDOMNodeBridge::Prefix DontDelete + localName SVGDOMNodeBridge::LocalName DontDelete|ReadOnly + ownerDocument SVGDOMNodeBridge::OwnerDocument DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGDOMNodeBridgeProto::s_hashTable 29 + insertBefore SVGDOMNodeBridge::InsertBefore DontDelete|Function 2 + replaceChild SVGDOMNodeBridge::ReplaceChild DontDelete|Function 2 + removeChild SVGDOMNodeBridge::RemoveChild DontDelete|Function 1 + appendChild SVGDOMNodeBridge::AppendChild DontDelete|Function 1 + hasAttributes SVGDOMNodeBridge::HasAttributes DontDelete|Function 0 + hasChildNodes SVGDOMNodeBridge::HasChildNodes DontDelete|Function 0 + cloneNode SVGDOMNodeBridge::CloneNode DontDelete|Function 1 + normalize SVGDOMNodeBridge::Normalize DontDelete|Function 0 + isSupported SVGDOMNodeBridge::IsSupported DontDelete|Function 2 + addEventListener SVGDOMNodeBridge::AddEventListener DontDelete|Function 3 + removeEventListener SVGDOMNodeBridge::RemoveEventListener DontDelete|Function 3 + contains SVGDOMNodeBridge::Contains DontDelete|Function 1 + getNodeName SVGDOMNodeBridge::GetNodeName DontDelete|Function 0 + getNodeValue SVGDOMNodeBridge::GetNodeValue DontDelete|Function 0 + getNodeType SVGDOMNodeBridge::GetNodeType DontDelete|Function 0 + getParentNode SVGDOMNodeBridge::GetParentNode DontDelete|Function 0 + getChildNodes SVGDOMNodeBridge::GetChildNodes DontDelete|Function 0 + getFirstChild SVGDOMNodeBridge::GetFirstChild DontDelete|Function 0 + getLastChild SVGDOMNodeBridge::GetLastChild DontDelete|Function 0 + getPreviousSibling SVGDOMNodeBridge::GetPreviousSibling DontDelete|Function 0 + getNextSibling SVGDOMNodeBridge::GetNextSibling DontDelete|Function 0 + getAttributes SVGDOMNodeBridge::GetAttributes DontDelete|Function 0 + getNamespaceURI SVGDOMNodeBridge::GetNamespaceURI DontDelete|Function 0 + getPrefix SVGDOMNodeBridge::GetPrefix DontDelete|Function 0 + getLocalName SVGDOMNodeBridge::GetLocalName DontDelete|Function 0 + getOwnerDocument SVGDOMNodeBridge::GetOwnerDocument DontDelete|Function 0 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("DOMNode", SVGDOMNodeBridgeProto, SVGDOMNodeBridgeProtoFunc) + +Value SVGDOMNodeBridge::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case NodeName: + return getString(m_impl.nodeName()); + case NodeValue: + return getString(m_impl.nodeValue()); + case NodeType: + return Number(m_impl.nodeType()); + case ParentNode: + return getDOMNode(exec, m_impl.parentNode()); + case ChildNodes: + return (new SVGDOMNodeListBridge(m_impl.childNodes()))->cache(exec); + case FirstChild: + return getDOMNode(exec, m_impl.firstChild()); + case LastChild: + return getDOMNode(exec, m_impl.lastChild()); + case PreviousSibling: + return getDOMNode(exec, m_impl.previousSibling()); + case NextSibling: + return getDOMNode(exec, m_impl.nextSibling()); +// case Attributes: // TODO + case NamespaceURI: + return getString(m_impl.namespaceURI()); + case Prefix: + return getString(m_impl.prefix()); + case LocalName: + return getString(m_impl.localName()); + case OwnerDocument: + return getDOMNode(exec, m_impl.ownerDocument()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGDOMNodeBridge::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case NodeValue: + m_impl.setNodeValue(value.toString(exec).string()); + break; + case Prefix: + m_impl.setPrefix(value.toString(exec).string()); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// Special variantion to update the element, +// triggered by one of the child nodes +void updateTextItem(ExecState *exec, const DOM::Node node) +{ + DOM::Node parent; + while(!(parent = node.parentNode()).isNull()) + { + DOM::DOMString name = parent.nodeName(); + if(name == "text" || name == "tspan" || name == "tref") + { + SVGHelperImpl::updateItem(exec, parent); + break; + } + } +} + +// Remove item from canvas +void removeItem(ExecState *exec, DOM::Node &node) +{ + // Get document + SVGDocumentImpl *doc = KSVG::Window::retrieveActive(exec)->doc(); + + // Update canvas + SVGShapeImpl *shape = dynamic_cast(doc->getElementFromHandle(node.handle())); + if(shape && shape->item()) + doc->canvas()->removeItem(shape->item()); +} + +// parseXML + getURL() need all these 5 functions to work properly +void correctHandles(SVGElementImpl *main, DOM::Node &node) +{ + DOM::Element old(node.handle()); + DOM::Element *replace = static_cast(main->ownerDoc()->getElementFromHandle(node.handle())); + + if(replace && node.nodeType() == DOM::Node::ELEMENT_NODE) + *replace = old; + + if(node.hasChildNodes()) + { + for(DOM::Node iterate = node.firstChild(); !iterate.isNull(); iterate = iterate.nextSibling()) + correctHandles(main, iterate); + } +} + +void integrateTree(SVGElementImpl *main, DOM::Node &node, DOM::Node &newNode, SVGElementImpl *obj, SVGDocumentImpl *doc) +{ + if(!obj) + return; + + // Add to global element dicts + doc->addToElemDict(newNode.handle(), obj); + doc->addToElemDict(node.handle(), obj); + + if(node.hasChildNodes()) + { + DOM::Node iterate2 = newNode.firstChild(); + for(DOM::Node iterate = node.firstChild(); !iterate.isNull(); iterate = iterate.nextSibling()) + { + integrateTree(main, iterate, iterate2, obj->ownerDoc()->getElementFromHandle(iterate2.handle()), doc); + iterate2 = iterate2.nextSibling(); + } + } +} + +void correctDocument(SVGElementImpl *main, DOM::Node &node, SVGElementImpl *obj, SVGDocumentImpl *doc) +{ + if(!obj) + return; + + // Correct document + obj->setOwnerDoc(main->ownerDoc()); + + // Correct rootElement + if(!obj->ownerSVGElement()) + obj->setOwnerSVGElement(main->ownerSVGElement()); + + // Correct viewportElement + if(!obj->viewportElement()) + obj->setViewportElement(main->viewportElement()); + + // Properly (re-)register events in the current active document + obj->setupEventListeners(main->ownerDoc(), doc); + + if(node.hasChildNodes()) + { + for(DOM::Node iterate = node.firstChild(); !iterate.isNull(); iterate = iterate.nextSibling()) + correctDocument(main, iterate, doc->getElementFromHandle(iterate.handle()), doc); + } +} + +void registerAdditional(ExecState *exec, SVGDocumentImpl *doc, DOM::Node node) +{ + // Register ID in rootElement! + SVGElementImpl *resultElement = doc->getElementFromHandle(node.handle()); + if(resultElement && resultElement->hasAttribute("id")) + doc->rootElement()->addToIdMap(resultElement->getAttribute("id").string(), resultElement); + + if(node.hasChildNodes()) + { + for(DOM::Node iterate = node.firstChild(); !iterate.isNull(); iterate = iterate.nextSibling()) + registerAdditional(exec, doc, iterate); + } +} + +Value appendHelper(ExecState *exec, DOM::Node node, DOM::Node newNode) +{ + // This is quite tricky code by me (Niko) + // Don't even try to modify it. + if(!(node.ownerDocument() == newNode.ownerDocument())) + { + // Get document + SVGDocumentImpl *doc = KSVG::Window::retrieveActive(exec)->doc(); + + // Detect ownerDoc() of newNode + SVGDocumentImpl *newDoc = doc->getDocumentFromHandle(newNode.ownerDocument().handle()); + + // Get some SVGElementImpl's + SVGElementImpl *nodeElement = doc->getElementFromHandle(node.handle()); + SVGElementImpl *newNodeElement = newDoc->getElementFromHandle(newNode.handle()); + + // Import node into document + DOM::Node result = doc->importNode(newNode, true); + + // Associate the imported node 'result' with the + // 'newNodeElement' which belongs to 'newDoc' + integrateTree(nodeElement, result, newNode, newNodeElement, doc); + + // Correct handles in SVG* elements + correctHandles(nodeElement, result); + + // Correct ownerDoc() etc.. + correctDocument(nodeElement, newNode, newNodeElement, newDoc); + + // Register ID in global map + registerAdditional(exec, doc, result); + + // Recalc style + newNodeElement->setAttributes(); + + // Append + create + update element + Value retVal = getDOMNode(exec, node.appendChild(result)); + + doc->syncCachedMatrices(); + newNodeElement->createItem(doc->canvas()); + SVGHelperImpl::updateItem(exec, *newNodeElement); + + return retVal; + } + else + { + Value retVal = getDOMNode(exec, node.appendChild(newNode)); + + // Get document + SVGDocumentImpl *doc = KSVG::Window::retrieveActive(exec)->doc(); + doc->syncCachedMatrices(); + + // Get some SVGElementImpl's + SVGElementImpl *nodeElement = doc->getElementFromHandle(newNode.handle()); + // TODO : extra check needed to see if the new elements parent is already appended + // in the doc. Not really nice, should be some other way? (Rob) + if(nodeElement && !nodeElement->parentNode().parentNode().isNull()) + { + nodeElement->setAttributes(true); + nodeElement->createItem(); + SVGHelperImpl::updateItem(exec, newNode); + } + + return retVal; + } +} + +Value SVGDOMNodeBridgeProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGDOMNodeBridge) + DOM::Node node = obj->impl(); + + switch(id) + { + case SVGDOMNodeBridge::InsertBefore: + { + DOM::Node newChild = toNode(args[0]); + DOM::Node beforeChild = toNode(args[1]); + Value retVal = getDOMNode(exec, node.insertBefore(newChild, beforeChild)); + + // Get document + SVGDocumentImpl *doc = Window::retrieveActive(exec)->doc(); + + // Get some SVGElementImpl's + SVGShapeImpl *newShape = dynamic_cast(doc->getElementFromHandle(newChild.handle())); + SVGElementImpl *newElement = doc->getElementFromHandle(newChild.handle()); + SVGShapeImpl *beforeElement = dynamic_cast(doc->getElementFromHandle(beforeChild.handle())); + if(newShape && beforeElement && beforeElement->item()) + { + int z = beforeElement->item()->zIndex(); + newElement->createItem(); + doc->canvas()->insert(newShape->item(), z); + } + SVGHelperImpl::updateItem(exec, newChild); + + return retVal; + } + case SVGDOMNodeBridge::ReplaceChild: + { + DOM::Node newChild = toNode(args[0]); + Value retVal = getDOMNode(exec, node.replaceChild(newChild, toNode(args[1]))); + SVGHelperImpl::updateItem(exec, newChild); + return retVal; + } + case SVGDOMNodeBridge::RemoveChild: + { + DOM::Node remove = toNode(args[0]); + if(remove.isNull()) + return Undefined(); + + // New removeChild logic: + // - remove from DOM tree + // - delete element (also deletes it's child element's) + removeItem(exec, remove); + Value retVal = getDOMNode(exec, node.removeChild(remove)); + return retVal; + } + case SVGDOMNodeBridge::AppendChild: + return appendHelper(exec, node, toNode(args[0])); + case SVGDOMNodeBridge::HasAttributes: + { + SVGDocumentImpl *doc = Window::retrieveActive(exec)->doc(); + SVGElementImpl *element = doc->getElementFromHandle(node.handle()); + + if(!element) + return Undefined(); + + return Boolean(element->hasAttributes()); + } + case SVGDOMNodeBridge::HasChildNodes: + return Boolean(node.hasChildNodes()); + case SVGDOMNodeBridge::CloneNode: + { + SVGDocumentImpl *doc = Window::retrieveActive(exec)->doc(); + SVGElementImpl *element = doc->getElementFromHandle(node.handle()); + SVGElementImpl *newElement = element->cloneNode(args[0].toBoolean(exec)); + + return getDOMNode(exec, *newElement); + } + case SVGDOMNodeBridge::Normalize: + { + node.normalize(); + return Undefined(); + } + case SVGDOMNodeBridge::IsSupported: + return Boolean(node.isSupported(args[0].toString(exec).string(), args[1].toString(exec).string())); + case SVGDOMNodeBridge::AddEventListener: + { + SVGDocumentImpl *doc = Window::retrieveActive(exec)->doc(); + SVGElementImpl *element = doc->getElementFromHandle(node.handle()); + + if(element) + { + SVGEvent::EventId eventId = SVGEvent::typeToId(args[0].toString(exec).string()); + if(eventId != SVGEvent::UNKNOWN_EVENT) + element->setEventListener(eventId, new KSVGEcmaEventListener(Object::dynamicCast(args[1]), QString::null, doc->ecmaEngine())); + } + return Undefined(); + } + case SVGDOMNodeBridge::RemoveEventListener: + { + SVGDocumentImpl *doc = Window::retrieveActive(exec)->doc(); + SVGElementImpl *element = doc->getElementFromHandle(node.handle()); + + if(element) + { + SVGEvent::EventId eventId = SVGEvent::typeToId(args[0].toString(exec).string()); + if(eventId != SVGEvent::UNKNOWN_EVENT) + element->removeEventListener((int) eventId); + } + return Undefined(); + } +// case SVGDOMNodeBridge::Contains: // TODO + case SVGDOMNodeBridge::GetNodeName: + return getString(node.nodeName()); + case SVGDOMNodeBridge::GetNodeValue: + return getString(node.nodeValue()); + case SVGDOMNodeBridge::GetNodeType: + return Number(node.nodeType()); + case SVGDOMNodeBridge::GetParentNode: + return getDOMNode(exec, node.parentNode()); + case SVGDOMNodeBridge::GetChildNodes: + return (new SVGDOMNodeListBridge(node.childNodes()))->cache(exec); + case SVGDOMNodeBridge::GetFirstChild: + return getDOMNode(exec, node.firstChild()); + case SVGDOMNodeBridge::GetLastChild: + return getDOMNode(exec, node.lastChild()); + case SVGDOMNodeBridge::GetPreviousSibling: + return getDOMNode(exec, node.previousSibling()); + case SVGDOMNodeBridge::GetNextSibling: + return getDOMNode(exec, node.nextSibling()); +// case SVGDOMNodeBridge::GetAttributes: // TODO + case SVGDOMNodeBridge::GetNamespaceURI: + return getString(node.namespaceURI()); + case SVGDOMNodeBridge::GetPrefix: + return getString(node.prefix()); + case SVGDOMNodeBridge::GetLocalName: + return getString(node.localName()); + case SVGDOMNodeBridge::GetOwnerDocument: + return getDOMNode(exec, node.ownerDocument()); + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + +// SVGDOMElementBridge + +/* +@namespace KSVG +@begin SVGDOMElementBridge::s_hashTable 2 + tagName SVGDOMElementBridge::TagName DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGDOMElementBridgeProto::s_hashTable 17 + getAttribute SVGDOMElementBridge::GetAttribute DontDelete|Function 1 + setAttribute SVGDOMElementBridge::SetAttribute DontDelete|Function 2 + removeAttribute SVGDOMElementBridge::RemoveAttribute DontDelete|Function 1 + getAttributeNode SVGDOMElementBridge::GetAttributeNode DontDelete|Function 1 + setAttributeNode SVGDOMElementBridge::SetAttributeNode DontDelete|Function 2 + removeAttributeNode SVGDOMElementBridge::RemoveAttributeNode DontDelete|Function 1 + getElementsByTagName SVGDOMElementBridge::GetElementsByTagName DontDelete|Function 1 + hasAttribute SVGDOMElementBridge::HasAttribute DontDelete|Function 1 + getAttributeNS SVGDOMElementBridge::GetAttributeNS DontDelete|Function 2 + setAttributeNS SVGDOMElementBridge::SetAttributeNS DontDelete|Function 3 + removeAttributeNS SVGDOMElementBridge::RemoveAttributeNS DontDelete|Function 2 + getAttributeNodeNS SVGDOMElementBridge::GetAttributeNodeNS DontDelete|Function 2 + setAttributeNodeNS SVGDOMElementBridge::SetAttributeNodeNS DontDelete|Function 1 + getElementByTagNameNS SVGDOMElementBridge::GetElementsByTagNameNS DontDelete|Function 2 + hasAttributeNS SVGDOMElementBridge::HasAttributeNS DontDelete|Function 2 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("DOMElement", SVGDOMElementBridgeProto, SVGDOMElementBridgeProtoFunc) + +Value SVGDOMElementBridge::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case TagName: + return getString(m_impl.tagName()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +Value SVGDOMElementBridgeProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGDOMElementBridge) + DOM::Element elem = obj->impl(); + + switch(id) + { + case SVGDOMElementBridge::GetAttribute: + { + SVGDocumentImpl *doc = Window::retrieveActive(exec)->doc(); + SVGElementImpl *element = doc->getElementFromHandle(elem.handle()); + if(element) + return String(element->getAttribute(args[0].toString(exec).string())); + else + return Undefined(); + } + case SVGDOMElementBridge::SetAttribute: + { + SVGDocumentImpl *doc = Window::retrieveActive(exec)->doc(); + SVGElementImpl *element = doc->getElementFromHandle(elem.handle()); + if(element) + { + element->setAttribute(args[0].toString(exec).string(), args[1].toString(exec).string()); + element->setAttributeInternal(args[0].toString(exec).string(), args[1].toString(exec).string()); + + SVGHelperImpl::updateItem(exec, elem); + } + + return Undefined(); + } + case SVGDOMElementBridge::RemoveAttribute: + { + elem.removeAttribute(args[0].toString(exec).string()); + return Undefined(); + } + case SVGDOMElementBridge::GetAttributeNode: + return getDOMNode(exec, elem.getAttributeNode(args[0].toString(exec).string())); + case SVGDOMElementBridge::SetAttributeNode: // TODO: Correct? + return getDOMNode(exec, elem.setAttributeNode(toNode(args[0]))); + case SVGDOMElementBridge::RemoveAttributeNode: // TODO: Correct? + return getDOMNode(exec, elem.removeAttributeNode(toNode(args[0]))); + case SVGDOMElementBridge::GetElementsByTagName: + return (new SVGDOMNodeListBridge(elem.getElementsByTagName(args[0].toString(exec).string())))->cache(exec); + case SVGDOMElementBridge::GetAttributeNS: + { + // This just skips NS! (Rob) + SVGDocumentImpl *doc = Window::retrieveActive(exec)->doc(); + SVGElementImpl *element = doc->getElementFromHandle(elem.handle()); + if(element) + return String(element->getAttribute(args[1].toString(exec).string())); + else + return Undefined(); + } + case SVGDOMElementBridge::SetAttributeNS: + { + // For now, we strip the NS part (Rob) + DOM::DOMString attr = args[1].toString(exec).string(); + int pos = attr.string().find(':'); + if(pos > -1) + attr = attr.string().mid(pos + 1); + + SVGDocumentImpl *doc = Window::retrieveActive(exec)->doc(); + SVGElementImpl *element = doc->getElementFromHandle(elem.handle()); + if(element) + { + element->setAttribute(attr.string(), args[2].toString(exec).string()); + element->setAttributeInternal(attr.string(), args[2].toString(exec).string()); + + SVGHelperImpl::updateItem(exec, *element); + } + + return Undefined(); + } + case SVGDOMElementBridge::RemoveAttributeNS: + { + elem.removeAttributeNS(args[0].toString(exec).string(), args[1].toString(exec).string()); + return Undefined(); + } + case SVGDOMElementBridge::GetAttributeNodeNS: + return getDOMNode(exec, elem.getAttributeNodeNS(args[0].toString(exec).string(), args[1].toString(exec).string())); + case SVGDOMElementBridge::SetAttributeNodeNS: // TODO: Correct? + return getDOMNode(exec, elem.setAttributeNodeNS(toNode(args[0]))); + case SVGDOMElementBridge::GetElementsByTagNameNS: + return (new SVGDOMNodeListBridge(elem.getElementsByTagNameNS(args[0].toString(exec).string(), args[1].toString(exec).string())))->cache(exec); + case SVGDOMElementBridge::HasAttribute: + return Boolean(elem.hasAttribute(args[0].toString(exec).string())); + case SVGDOMElementBridge::HasAttributeNS: + return Boolean(elem.hasAttributeNS(args[0].toString(exec).string(), args[1].toString(exec).string())); + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + + +// SVGDOMNodeListBridge + +/* +@namespace KSVG +@begin SVGDOMNodeListBridge::s_hashTable 2 + length SVGDOMNodeListBridge::Length DontDelete +@end +@namespace KSVG +@begin SVGDOMNodeListBridgeProto::s_hashTable 3 + getLength SVGDOMNodeListBridge::GetLength DontDelete|Function 0 + item SVGDOMNodeListBridge::Item DontDelete|Function 1 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("DOMNodeList", SVGDOMNodeListBridgeProto, SVGDOMNodeListBridgeProtoFunc) + +Value SVGDOMNodeListBridge::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case Length: + return Number(m_impl.length()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +Value SVGDOMNodeListBridgeProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGDOMNodeListBridge) + DOM::NodeList nodeList = obj->impl(); + + switch(id) + { + case SVGDOMNodeListBridge::GetLength: + return Number(nodeList.length()); + case SVGDOMNodeListBridge::Item: + return getDOMNode(exec, nodeList.item((unsigned long)args[0].toNumber(exec))); + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + +// SVGDOMCharacterDataBridge + +/* +@namespace KSVG +@begin SVGDOMCharacterDataBridge::s_hashTable 3 + data SVGDOMCharacterDataBridge::Data DontDelete + length SVGDOMCharacterDataBridge::Length DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGDOMCharacterDataBridgeProto::s_hashTable 11 + getData SVGDOMCharacterDataBridge::GetData DontDelete|Function 0 + setData SVGDOMCharacterDataBridge::SetData DontDelete|Function 1 + getLength SVGDOMCharacterDataBridge::GetLength DontDelete|Function 0 + substringData SVGDOMCharacterDataBridge::SubstringData DontDelete|Function 2 + appendData SVGDOMCharacterDataBridge::AppendData DontDelete|Function 1 + insertData SVGDOMCharacterDataBridge::InsertData DontDelete|Function 2 + deleteData SVGDOMCharacterDataBridge::DeleteData DontDelete|Function 2 + replaceData SVGDOMCharacterDataBridge::ReplaceData DontDelete|Function 2 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("DOMCharacterData", SVGDOMCharacterDataBridgeProto, SVGDOMCharacterDataBridgeProtoFunc) + +Value SVGDOMCharacterDataBridge::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case Data: + return String(m_impl.data()); + case Length: + return Number(m_impl.length()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGDOMCharacterDataBridge::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case Data: + m_impl.setData(value.toString(exec).string()); + updateTextItem(exec, m_impl); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +Value SVGDOMCharacterDataBridgeProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGDOMCharacterDataBridge) + DOM::CharacterData node = obj->impl(); + + switch(id) + { + case SVGDOMCharacterDataBridge::GetData: + return String(node.data()); + case SVGDOMCharacterDataBridge::SetData: + node.setData(args[0].toString(exec).string()); + updateTextItem(exec, node); + return Undefined(); + case SVGDOMCharacterDataBridge::GetLength: + return Number(node.length()); + case SVGDOMCharacterDataBridge::SubstringData: + { + DOM::DOMString ret = node.substringData(args[0].toInteger(exec), args[1].toInteger(exec)); + updateTextItem(exec, node); + return String(ret); + } + case SVGDOMCharacterDataBridge::AppendData: + node.appendData(args[0].toString(exec).string()); + updateTextItem(exec, node); + return Undefined(); + case SVGDOMCharacterDataBridge::InsertData: + node.insertData(args[0].toInteger(exec), args[1].toString(exec).string()); + updateTextItem(exec, node); + return Undefined(); + case SVGDOMCharacterDataBridge::DeleteData: + node.deleteData(args[0].toInteger(exec), args[1].toInteger(exec)); + updateTextItem(exec, node); + return Undefined(); + case SVGDOMCharacterDataBridge::ReplaceData: + node.replaceData(args[0].toInteger(exec), args[1].toInteger(exec), args[2].toString(exec).string()); + updateTextItem(exec, node); + return Undefined(); + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + +// SVGDOMTextBridge + +/* +@namespace KSVG +@begin SVGDOMTextBridge::s_hashTable 2 + dummy SVGDOMTextBridge::Dummy DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGDOMTextBridgeProto::s_hashTable 2 + splitText SVGDOMTextBridge::SplitText DontDelete|Function 1 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("DOMText", SVGDOMTextBridgeProto, SVGDOMTextBridgeProtoFunc) + +Value SVGDOMTextBridge::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +Value SVGDOMTextBridgeProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGDOMTextBridge) + DOM::Text node = obj->impl(); + + switch(id) + { + case SVGDOMTextBridge::SplitText: + return getDOMNode(exec, node.splitText(args[0].toInteger(exec))); + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + +// SVGDOMDOMImplementationBridge + +/* +@namespace KSVG +@begin SVGDOMDOMImplementationBridge::s_hashTable 2 + dummy SVGDOMDOMImplementationBridge::Dummy DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGDOMDOMImplementationBridgeProto::s_hashTable 2 + hasFeature SVGDOMDOMImplementationBridge::HasFeature DontDelete|Function 2 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("DOMDOMImplementation", SVGDOMDOMImplementationBridgeProto, SVGDOMDOMImplementationBridgeProtoFunc) + +Value SVGDOMDOMImplementationBridge::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +Value SVGDOMDOMImplementationBridgeProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGDOMDOMImplementationBridge) + DOM::DOMImplementation node = obj->impl(); + + switch(id) + { + case SVGDOMDOMImplementationBridge::HasFeature: + return Boolean(node.hasFeature(args[0].toString(exec).string(), args[1].toString(exec).string())); + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + +// SVGDOMDocumentFragmentBridge + +/* +@namespace KSVG +@begin SVGDOMDocumentFragmentBridge::s_hashTable 2 + dummy SVGDOMDocumentFragmentBridge::Dummy DontDelete|ReadOnly +@end +*/ + +Value SVGDOMDocumentFragmentBridge::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGEcma.h b/ksvg/impl/SVGEcma.h new file mode 100644 index 00000000..adf1ec85 --- /dev/null +++ b/ksvg/impl/SVGEcma.h @@ -0,0 +1,250 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGEcma_H +#define SVGEcma_H + +#include +#include +#include +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +// Access DOM::Node via js +class SVGDOMNodeBridge +{ +public: + SVGDOMNodeBridge(DOM::Node impl) : m_impl(impl) { KSVG_EMPTY_FLAGS } + virtual ~SVGDOMNodeBridge() { } + + DOM::Node impl() const { return m_impl; } + + KSVG_BASECLASS_GET + KSVG_PUT + + enum + { + // Properties + NodeName, NodeValue, NodeType, ParentNode, + ChildNodes, FirstChild, LastChild, PreviousSibling, + NextSibling, Attributes, NamespaceURI, Prefix, + LocalName, OwnerDocument, + // Functions + InsertBefore, ReplaceChild, RemoveChild, AppendChild, + HasAttributes, HasChildNodes, CloneNode, Normalize, + IsSupported, AddEventListener, RemoveEventListener, Contains, + GetNodeName, GetNodeValue, GetNodeType, GetParentNode, + GetChildNodes, GetFirstChild, GetLastChild, GetPreviousSibling, + GetNextSibling, GetAttributes, GetNamespaceURI, GetPrefix, + GetLocalName, GetOwnerDocument + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); + +private: + DOM::Node m_impl; +}; + +// Access DOM::Element via js +class SVGDOMElementBridge : public SVGDOMNodeBridge +{ +public: + SVGDOMElementBridge(DOM::Element impl) : SVGDOMNodeBridge(static_cast(impl)), m_impl(impl) { } + ~SVGDOMElementBridge() { } + + DOM::Element impl() const { return m_impl; } + + KSVG_GET + KSVG_FORWARDPUT + + enum + { + // Properties + TagName, + // Functions + GetAttribute, SetAttribute, RemoveAttribute, GetAttributeNode, + SetAttributeNode, RemoveAttributeNode, GetElementsByTagName, + GetAttributeNS, SetAttributeNS, RemoveAttributeNS, GetAttributeNodeNS, + SetAttributeNodeNS, GetElementsByTagNameNS, HasAttribute, HasAttributeNS + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + +private: + DOM::Element m_impl; +}; + +// Access DOM::NodeList via js +class SVGDOMNodeListBridge +{ +public: + SVGDOMNodeListBridge(DOM::NodeList impl) : m_impl(impl) { } + ~SVGDOMNodeListBridge() { } + + DOM::NodeList impl() const { return m_impl; } + + KSVG_GET + + enum + { + // Properties + Length, + // Functions + GetLength, Item + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + +private: + DOM::NodeList m_impl; +}; + +// Access DOM::CharacterData via js +class SVGDOMCharacterDataBridge : public SVGDOMNodeBridge +{ +public: + SVGDOMCharacterDataBridge(DOM::CharacterData impl) : SVGDOMNodeBridge(static_cast(impl)), m_impl(impl) { KSVG_EMPTY_FLAGS } + ~SVGDOMCharacterDataBridge() { } + + DOM::CharacterData impl() const { return m_impl; } + + KSVG_GET + KSVG_PUT + + enum + { + // Properties + Data, Length, + // Functions + GetData, SetData, GetLength, + SubstringData, AppendData, InsertData, DeleteData, ReplaceData + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); + +private: + DOM::CharacterData m_impl; +}; + +// Access DOM::Text via js +class SVGDOMTextBridge : public SVGDOMCharacterDataBridge +{ +public: + SVGDOMTextBridge(DOM::Text impl) : SVGDOMCharacterDataBridge(static_cast(impl)), m_impl(impl) { } + ~SVGDOMTextBridge() { } + + DOM::Text impl() const { return m_impl; } + + KSVG_GET + KSVG_FORWARDPUT + + enum + { + // Properties + Dummy, + // Functions + SplitText + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + +private: + DOM::Text m_impl; +}; + +// Access DOM::DOMImplementation via js +class SVGDOMDOMImplementationBridge +{ +public: + SVGDOMDOMImplementationBridge(DOM::DOMImplementation impl) : m_impl(impl) { } + ~SVGDOMDOMImplementationBridge() { } + + DOM::DOMImplementation impl() const { return m_impl; } + + KSVG_GET + KSVG_FORWARDPUT + + enum + { + // Properties + Dummy, + // Functions + HasFeature + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + +private: + DOM::DOMImplementation m_impl; +}; + +// Access DOM::DocumentFragment via js +class SVGDOMDocumentFragmentBridge : public SVGDOMNodeBridge +{ +public: + SVGDOMDocumentFragmentBridge(DOM::DocumentFragment impl) : SVGDOMNodeBridge(static_cast(impl)), m_impl(impl) { } + ~SVGDOMDocumentFragmentBridge() { } + + DOM::DocumentFragment impl() const { return m_impl; } + + KSVG_GET + KSVG_FORWARDPUT + + enum + { + // Properties + Dummy + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + +private: + DOM::DocumentFragment m_impl; +}; + +} + +KSVG_DEFINE_PROTOTYPE(SVGDOMNodeBridgeProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGDOMNodeBridgeProtoFunc, SVGDOMNodeBridge) + +KSVG_DEFINE_PROTOTYPE(SVGDOMElementBridgeProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGDOMElementBridgeProtoFunc, SVGDOMElementBridge) + +KSVG_DEFINE_PROTOTYPE(SVGDOMNodeListBridgeProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGDOMNodeListBridgeProtoFunc, SVGDOMNodeListBridge) + +KSVG_DEFINE_PROTOTYPE(SVGDOMCharacterDataBridgeProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGDOMCharacterDataBridgeProtoFunc, SVGDOMCharacterDataBridge) + +KSVG_DEFINE_PROTOTYPE(SVGDOMTextBridgeProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGDOMTextBridgeProtoFunc, SVGDOMTextBridge) + +KSVG_DEFINE_PROTOTYPE(SVGDOMDOMImplementationBridgeProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGDOMDOMImplementationBridgeProtoFunc, SVGDOMDOMImplementationBridge) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGElementImpl.cc b/ksvg/impl/SVGElementImpl.cc new file mode 100644 index 00000000..2f3d70c6 --- /dev/null +++ b/ksvg/impl/SVGElementImpl.cc @@ -0,0 +1,713 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include + +#include "SVGEvent.h" +#include "SVGEventImpl.h" +#include "SVGHelperImpl.h" +#include "SVGElementImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" + +using namespace KSVG; + +#include "SVGElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_ecma.h" + +SVGElementImpl::Factory *SVGElementImpl::Factory::m_instance = 0; + +SVGElementImpl::SVGElementImpl(DOM::ElementImpl *impl) : DOM::DomShared(), DOM::Element(impl), SVGDOMElementBridge(static_cast(*this)) +{ + KSVG_EMPTY_FLAGS + + m_ownerSVGElement = 0; + m_viewportElement = 0; + m_ownerDoc = 0; + + m_mouseOver = false; + m_focus = false; + + m_eventListeners.setAutoDelete(true); + m_attributes.setAutoDelete(true); +} + +SVGElementImpl::~SVGElementImpl() +{ + if(m_ownerSVGElement) + m_ownerSVGElement->deref(); +} + +void SVGElementImpl::setEventListener(int id, SVGEventListener *listener) +{ + if(listener) + listener->ref(); + + removeEventListener(id); + + if(listener) + { + SVGRegisteredEventListener *rl = new SVGRegisteredEventListener(static_cast(id), listener, false); + m_eventListeners.append(rl); + + listener->deref(); + } +} + +int SVGElementImpl::getEventListeners(bool local) +{ + int events = 0; + + QPtrListIterator it(m_eventListeners); + for(; it.current(); ++it) + events |= (1 << it.current()->id); + + if(local) + return events; + + for(DOM::Node node = parentNode(); !node.isNull(); node = node.parentNode()) + { + SVGElementImpl *element = ownerDoc()->getElementFromHandle(node.handle()); + + if(element) + { + QPtrListIterator it(element->m_eventListeners); + for(; it.current(); ++it) + events |= (1 << it.current()->id); + } + } + + return events; +} + +void SVGElementImpl::setupEventListeners(SVGDocumentImpl *doc, SVGDocumentImpl *newDoc) +{ + if(!doc || !newDoc) + return; + + // Changes the document where the eventlisteners are registered + // Needed for parseXML'ed elements with events, their listeners + // are created in the temporary document fragment and need to be + // registered in the main document (Niko) + QPtrListIterator it(m_eventListeners); + for(; it.current(); ++it) + { + SVGRegisteredEventListener *current = it.current(); + + QString valueOfCurrent = newDoc->ecmaEngine()->valueOfEventListener(current->listener); + setEventListener(current->id, doc->createEventListener(valueOfCurrent)); + } +} + +bool SVGElementImpl::hasEventListener(int id, bool local) +{ + // First check if we have the listener, locally + QPtrListIterator it(m_eventListeners); + for(; it.current(); ++it) + { + if(it.current()->id == id) + return true; + } + + // We have no local listeners, if we are just interessted + // in those listeners, then return now... + if(local) + return false; + + // Check every parent element + for(DOM::Node node = parentNode(); !node.isNull(); node = node.parentNode()) + { + SVGElementImpl *element = ownerDoc()->getElementFromHandle(node.handle()); + + if(element) + { + QPtrListIterator it(element->m_eventListeners); + for(; it.current(); ++it) + { + if(it.current()->id == id) + return true; + } + } + } + + return false; +} + +void SVGElementImpl::removeEventListener(int id) +{ + QPtrListIterator it(m_eventListeners); + for(; it.current(); ++it) + { + if(it.current()->id == id) + { + m_eventListeners.removeRef(it.current()); + break; + } + } +} + +void SVGElementImpl::handleLocalEvents(SVGEventImpl *evt, bool useCapture) +{ + QPtrListIterator it(m_eventListeners); + for(; it.current(); ++it) + { + if(it.current()->id == evt->id() && it.current()->useCapture == useCapture) + { + it.current()->listener->handleEvent(evt); + break; + } + } +} + +void SVGElementImpl::defaultEventHandler(SVGEventImpl *) +{ +} + +/* +@namespace KSVG +@begin SVGElementImpl::s_hashTable 23 + id SVGElementImpl::ElementId DontDelete + ownerSVGElement SVGElementImpl::OwnerSvgElement DontDelete|ReadOnly + viewportElement SVGElementImpl::ViewportElement DontDelete|ReadOnly + xmlbase SVGElementImpl::XmlBase DontDelete + base SVGElementImpl::XmlBase DontDelete + onmouseup SVGElementImpl::OnMouseUp DontDelete + onmousedown SVGElementImpl::OnMouseDown DontDelete + onmousemove SVGElementImpl::OnMouseMove DontDelete + onmouseover SVGElementImpl::OnMouseOver DontDelete + onmouseout SVGElementImpl::OnMouseOut DontDelete + onclick SVGElementImpl::OnClick DontDelete + onmouseclick SVGElementImpl::OnClick DontDelete + onactivate SVGElementImpl::OnActivate DontDelete + onkeydown SVGElementImpl::OnKeyDown DontDelete + onkeyup SVGElementImpl::OnKeyUp DontDelete + onkeypress SVGElementImpl::OnKeyPress DontDelete + onload SVGElementImpl::OnLoad DontDelete + onfocusin SVGElementImpl::OnFocusIn DontDelete + onfocusout SVGElementImpl::OnFocusOut DontDelete + onerror SVGElementImpl::OnError DontDelete + onabort SVGElementImpl::OnAbort DontDelete +@end +@namespace KSVG +@begin SVGElementImplProto::s_hashTable 5 + getStyle SVGElementImpl::GetStyle DontDelete|Function 0 + setProperty SVGElementImpl::SetProperty DontDelete|Function 2 + getPropertyValue SVGElementImpl::GetPropertyValue DontDelete|Function 1 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGElement", SVGElementImplProto, SVGElementImplProtoFunc) + +Value SVGElementImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case ElementId: + return String(id().string()); + case XmlBase: + return String(xmlbase().string()); + case OwnerSvgElement: + return getDOMNode(exec, *ownerSVGElement()); + case ViewportElement: + return getDOMNode(exec, *viewportElement()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case ElementId: + setId(value.toString(exec).string()); + break; + case XmlBase: + setXmlbase(value.toString(exec).string()); + break; + case OnMouseUp: + setEventListener(SVGEvent::MOUSEUP_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string())); + break; + case OnMouseDown: + setEventListener(SVGEvent::MOUSEDOWN_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string())); + break; + case OnMouseMove: + setEventListener(SVGEvent::MOUSEMOVE_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string())); + break; + case OnMouseOver: + setEventListener(SVGEvent::MOUSEOVER_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string())); + break; + case OnMouseOut: + setEventListener(SVGEvent::MOUSEOUT_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string())); + break; + case OnClick: + setEventListener(SVGEvent::CLICK_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string())); + break; + case OnActivate: + setEventListener(SVGEvent::DOMACTIVATE_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string())); + break; + case OnKeyDown: + setEventListener(SVGEvent::KEYDOWN_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string())); + break; + case OnKeyUp: + setEventListener(SVGEvent::KEYUP_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string())); + break; + case OnKeyPress: + setEventListener(SVGEvent::KEYPRESS_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string())); + break; + case OnLoad: + setEventListener(SVGEvent::LOAD_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string())); + break; + case OnFocusIn: + setEventListener(SVGEvent::DOMFOCUSIN_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string())); + break; + case OnFocusOut: + setEventListener(SVGEvent::DOMFOCUSOUT_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string())); + break; + case OnError: + setEventListener(SVGEvent::ERROR_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string())); + break; + case OnAbort: + setEventListener(SVGEvent::ABORT_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string())); + break; + default: + kdWarning() << k_funcinfo << "unhandled token " << token << endl; + } +} + +Value SVGElementImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGElementImpl) + + switch(id) + { + case SVGElementImpl::GetStyle: + return obj->cache(exec); + case SVGElementImpl::SetProperty: + { + DOM::DOMString attribute = args[0].toString(exec).qstring().lower(); + DOM::DOMString value = args[1].toString(exec).qstring(); + obj->setAttribute(attribute, value); + break; + } + case SVGElementImpl::GetPropertyValue: + return String(obj->getAttribute(args[0].toString(exec).qstring())); + default: + break; + } + + return Undefined(); +} + +QDict &SVGElementImpl::attributes() +{ + return m_attributes; +} + +// khtml overrides +void SVGElementImpl::setAttribute(const DOM::DOMString &name, const DOM::DOMString &value) +{ + m_attributes.replace(name.string(), new DOM::DOMString(value)); +} + +// Changes internal value. This will have no effect on getAttribute(). +void SVGElementImpl::setAttributeInternal(const DOM::DOMString &name, const DOM::DOMString &value) +{ + ExecState *exec = ownerDoc()->ecmaEngine()->globalExec(); + + static_cast(exec->interpreter())->setAttributeSetMode(true); + bridge(exec)->put(exec, Identifier(UString(name)), String(value), KJS::Internal); + static_cast(exec->interpreter())->setAttributeSetMode(false); +} + +// This gets the actual attribute as set in the svg source +DOM::DOMString SVGElementImpl::getAttribute(const DOM::DOMString &name) const +{ + DOM::DOMString *result = m_attributes[name.string()]; + if(result) + return *result; + else + return DOM::DOMString(); +} + +// This gets the internal, real-time value. This means it can return a default value +// for an attribute even if its not explicitly set in the svg source. +DOM::DOMString SVGElementImpl::getAttributeInternal(const DOM::DOMString &name) +{ + ExecState *exec = ownerDoc()->ecmaEngine()->globalExec(); + + DOM::DOMString retVal; + + static_cast(exec->interpreter())->setAttributeGetMode(true); + retVal = bridge(exec)->get(exec, Identifier(UString(name))).toString(exec).string(); + static_cast(exec->interpreter())->setAttributeGetMode(false); + + return retVal; +} + +bool SVGElementImpl::hasAttribute(const DOM::DOMString &name) +{ + return m_attributes.find(name.string()) != 0; +} + +bool SVGElementImpl::hasAttributes() +{ + return m_attributes.count() > 0; +} + +void SVGElementImpl::setApplyAttribute(const QString &name, const QString &value) +{ + if(hasAttribute(name)) + { + QString cur = getAttribute(name).string(); + cur = cur.simplifyWhiteSpace(); + + if(!cur.endsWith(";")) + cur += "; "; + + cur += value; + + setAttribute(name, cur); + } + else + setAttribute(name, value); +} + +void SVGElementImpl::setId(DOM::DOMString id) +{ + setAttribute("id", id); + + if(ownerDoc() && ownerDoc()->rootElement() && !id.isEmpty()) + ownerDoc()->rootElement()->addToIdMap(id.string(), this); + else if(m_ownerSVGElement && !id.isEmpty()) + m_ownerSVGElement->addToIdMap(id.string(), this); +} + +DOM::DOMString SVGElementImpl::id() const +{ + return getAttribute("id"); +} + +void SVGElementImpl::setXmlbase(DOM::DOMString xmlbase) +{ + setAttribute("xml:base", xmlbase); +} + +DOM::DOMString SVGElementImpl::xmlbase() const +{ + return getAttribute("xml:base"); +} + +void SVGElementImpl::setOwnerSVGElement(SVGSVGElementImpl *owner) +{ + if(m_ownerSVGElement) + m_ownerSVGElement->deref(); + + m_ownerSVGElement = owner; + + if(m_ownerSVGElement) + m_ownerSVGElement->ref(); +} + +void SVGElementImpl::setViewportElement(SVGElementImpl *viewport) +{ + if(m_viewportElement) + m_viewportElement->deref(); + + m_viewportElement = viewport; + + if(m_viewportElement) + m_viewportElement->ref(); +} + +SVGSVGElementImpl *SVGElementImpl::ownerSVGElement() const +{ + return m_ownerSVGElement; +} + +SVGElementImpl *SVGElementImpl::viewportElement() const +{ + return m_viewportElement; +} + +void SVGElementImpl::setAttributes(const QXmlAttributes &attrs) +{ + for(int i = 0; i < attrs.length(); i++) + { + setAttribute(attrs.localName(i), attrs.value(i)); + setAttributeInternal(attrs.localName(i), attrs.value(i)); + } + + setAttributes(); +} + +void SVGElementImpl::setAttributes() +{ + // Finalize style + SVGStylableImpl *style = dynamic_cast(this); + + if(style) + style->processStyle(); +} + +void SVGElementImpl::setAttributes(bool deep) +{ + // Finalize style + SVGStylableImpl *style = dynamic_cast(this); + + if(style) + style->processStyle(); + + if(deep) + { + if(hasChildNodes()) + { + DOM::Node n; + for(n = firstChild(); !n.isNull(); n = n.nextSibling()) + { + SVGElementImpl *elem = ownerDoc()->getElementFromHandle(n.handle()); + if(elem) + elem->setAttributes(true); + } + } + } +} + +bool SVGElementImpl::prepareMouseEvent(const QPoint &p, const QPoint &a, SVGMouseEventImpl *mev) +{ + SVGShapeImpl *shape = dynamic_cast(this); + if(shape) + return shape->prepareMouseEvent(p, a, mev); + + return false; +} + +bool SVGElementImpl::dispatchEvent(int id, bool canBubbleArg, bool cancelableArg) +{ + SVGEventImpl *evt = new SVGEventImpl(static_cast(id), canBubbleArg, cancelableArg); + + evt->ref(); + bool ret = dispatchEvent(evt, true); + evt->deref(); + + return ret; +} + +bool SVGElementImpl::dispatchEvent(SVGEventImpl *evt, bool tempEvent) +{ + evt->setTarget(this); + + // Find out, where to send to -> collect parent nodes + QPtrList nodeChain; + + for(DOM::Element e = *this; !e.isNull(); e = e.parentNode()) + nodeChain.prepend(ownerDoc()->getElementFromHandle(e.handle())); + + // Trigger any capturing event handlers on our way down + evt->setEventPhase(DOM::Event::CAPTURING_PHASE); + + QPtrListIterator it(nodeChain); + for(; it.current() && it.current() != this && !evt->propagationStopped(); ++it) + { + evt->setCurrentTarget(it.current()); + + if(it.current()) + it.current()->handleLocalEvents(evt, true); + } + + // Dispatch to the actual target node + it.toLast(); + if(!evt->propagationStopped()) + { + evt->setEventPhase(DOM::Event::AT_TARGET); + evt->setCurrentTarget(it.current()); + + if(it.current()) + it.current()->handleLocalEvents(evt, false); + } + + --it; + + // Bubble up again + if(evt->bubbles()) + { + evt->setEventPhase(DOM::Event::BUBBLING_PHASE); + for(; it.current() && !evt->propagationStopped(); --it) + { + evt->setCurrentTarget(it.current()); + + if(it.current()) + it.current()->handleLocalEvents(evt, false); + } + } + + evt->setCurrentTarget(0); + evt->setEventPhase(0); // I guess this is correct, the spec does not seem to say + // anything about the default event handler phase. + + if(evt->bubbles()) + { + // now we call all default event handlers (this is not part of DOM - it is internal to ksvg) + it.toLast(); + for(; it.current() && !evt->propagationStopped() && !evt->defaultPrevented() && !evt->defaultHandled(); --it) + it.current()->defaultEventHandler(evt); + } + + // If tempEvent is true, this means that the DOM implementation will not be storing a reference to the event, i.e. + // there is no way to retrieve it from javascript if a script does not already have a reference to it in a variable. + // So there is no need for the interpreter to keep the event in its cache + if(tempEvent) + ownerDoc()->ecmaEngine()->finishedWithEvent(evt); + + return !evt->defaultPrevented(); // ### what if defaultPrevented was called before dispatchEvent? +} + +bool SVGElementImpl::dispatchKeyEvent(QKeyEvent *ke) +{ + DOM::AbstractView temp; + + SVGEvent::EventId evtId = SVGEvent::UNKNOWN_EVENT; + + if(ke->type() == QEvent::KeyRelease && !ke->isAutoRepeat()) + evtId = SVGEvent::KEYUP_EVENT; + else if(ke->isAutoRepeat()) + evtId = SVGEvent::KEYPRESS_EVENT; + else if(ke->type() == QEvent::KeyPress) + evtId = SVGEvent::KEYDOWN_EVENT; + + if(evtId == SVGEvent::KEYUP_EVENT && hasEventListener(SVGEvent::DOMACTIVATE_EVENT, false)) + dispatchEvent(SVGEvent::DOMACTIVATE_EVENT, true, true); + + if(!hasEventListener(evtId, false)) + return false; + + SVGEventImpl *evt = new SVGKeyEventImpl(ke, temp, evtId); + + evt->ref(); + bool ret = dispatchEvent(evt, true); + evt->deref(); + + // Rerender now! Once! (Niko) + ownerDoc()->rerender(); + + return ret; +} + +bool SVGElementImpl::dispatchMouseEvent(int id, bool canBubbleArg, bool cancelableArg, long detailArg, long screenXArg, long screenYArg, long clientXArg, long clientYArg, bool ctrlKeyArg, bool altKeyArg, bool shiftKeyArg, bool metaKeyArg, unsigned short buttonArg, SVGElementImpl *relatedTargetArg) +{ + DOM::AbstractView temp; + + SVGEventImpl *evt = new SVGMouseEventImpl(static_cast(id), + canBubbleArg, cancelableArg, temp, detailArg, + screenXArg, screenYArg, + clientXArg, clientYArg, + ctrlKeyArg, altKeyArg, shiftKeyArg, metaKeyArg, + buttonArg, relatedTargetArg); + + evt->ref(); + bool ret = dispatchEvent(evt, true); + evt->deref(); + + return ret; +} + +void SVGElementImpl::setOwnerDoc(SVGDocumentImpl *doc) +{ + if(m_ownerDoc) + m_ownerDoc->removeFromElemDict(handle()); + + m_ownerDoc = doc; + + if(m_ownerDoc) + m_ownerDoc->addToElemDict(handle(), this); +} + +SVGDocumentImpl *SVGElementImpl::ownerDoc() const +{ + return m_ownerDoc; +} + +SVGElementImpl *SVGElementImpl::cloneNode(bool deep) +{ + DOM::Element impl = static_cast(ownerDoc())->createElementNS("", tagName()); + SVGElementImpl *newElement = SVGDocumentImpl::createElement(tagName(), impl.cloneNode(false), ownerDoc()); + newElement->setOwnerSVGElement(ownerSVGElement()); + newElement->setViewportElement(viewportElement()); + + SVGHelperImpl::copyAttributes(this, newElement); + + // Recalc style + //newElement->setAttributes(); + + if(deep) + cloneChildNodes(newElement); + + return newElement; +} + +void SVGElementImpl::cloneChildNodes(SVGElementImpl *clone) +{ + DOM::Node n; + for(n = firstChild(); !n.isNull(); n = n.nextSibling()) + { + SVGElementImpl *elem = ownerDoc()->getElementFromHandle(n.handle()); + if(elem) + clone->appendChild(*elem->cloneNode(true)); + else if(n.nodeType() == DOM::Node::TEXT_NODE) + clone->appendChild(n.cloneNode(true)); + } +} + +void SVGElementImpl::gotError(const QString &errorDesc) +{ + if(ownerDoc()) + { + ownerDoc()->finishParsing(true, errorDesc); + if(hasEventListener(SVGEvent::ERROR_EVENT, true)) + dispatchEvent(SVGEvent::ERROR_EVENT, false, false); + } +} + +QString SVGElementImpl::collectText() +{ + QString text; + + if(hasChildNodes()) + { + DOM::Node node = firstChild(); + + for(; !node.isNull(); node = node.nextSibling()) + { + if(node.nodeType() == DOM::Node::TEXT_NODE) + { + DOM::Text textNode = node; + text += textNode.data().string(); + } + } + } + + return text; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGElementImpl.h b/ksvg/impl/SVGElementImpl.h new file mode 100644 index 00000000..c69a83e8 --- /dev/null +++ b/ksvg/impl/SVGElementImpl.h @@ -0,0 +1,229 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGElementImpl_H +#define SVGElementImpl_H + +#include +#include + +#include +#include + +#include + +#include "SVGEcma.h" + +#include "ksvg_lookup.h" + +class QKeyEvent; +class QXmlAttributes; + +namespace KJS +{ + class Value; + class UString; + class ExecState; +} + +namespace KSVG +{ + +class KSVGCanvas; +class SVGEventImpl; +class SVGDocumentImpl; +class SVGEventListener; +class SVGSVGElementImpl; +class SVGMouseEventImpl; +class SVGRegisteredEventListener; +class SVGElementImpl : virtual public DOM::DomShared, + public DOM::Element, + public SVGDOMElementBridge +{ +public: + SVGElementImpl(DOM::ElementImpl *impl); + virtual ~SVGElementImpl(); + + // Attribute setting + // "Override" khtml's functions with ours + void setAttribute(const DOM::DOMString &name, const DOM::DOMString &value); + void setAttributeInternal(const DOM::DOMString &name, const DOM::DOMString &value); + DOM::DOMString getAttribute(const DOM::DOMString &name) const; + DOM::DOMString getAttributeInternal(const DOM::DOMString &name); + bool hasAttribute(const DOM::DOMString &name); + bool hasAttributes(); + + QDict &attributes(); + void setApplyAttribute(const QString &name, const QString &value); + + void setId(DOM::DOMString); + DOM::DOMString id() const; + + void setXmlbase(DOM::DOMString); + DOM::DOMString xmlbase() const; + + void setOwnerSVGElement(SVGSVGElementImpl *owner); + void setViewportElement(SVGElementImpl *viewport); + + SVGSVGElementImpl *ownerSVGElement() const; + SVGElementImpl *viewportElement() const; + + void setAttributes(const QXmlAttributes &); + virtual void setAttributes(); + void setAttributes(bool deep); + + QString collectText(); + + void setOwnerDoc(SVGDocumentImpl *doc); + SVGDocumentImpl *ownerDoc() const; + + virtual SVGElementImpl *cloneNode(bool deep); + void cloneChildNodes(SVGElementImpl *clone); + + // Event stuff + bool dispatchEvent(int id, bool canBubbleArg, bool cancelableArg); + bool dispatchEvent(SVGEventImpl *evt, bool tempEvent); + bool dispatchMouseEvent(int id, bool canBubbleArg, bool cancelableArg, long detailArg, long screenXArg, long screenYArg, long clientXArg, long clientYArg, bool ctrlKeyArg, bool altKeyArg, bool shiftKeyArg, bool metaKeyArg, unsigned short buttonArg, SVGElementImpl *relatedTargetArg); + bool dispatchKeyEvent(QKeyEvent *ke); + + void setEventListener(int id, SVGEventListener *listener); + bool hasEventListener(int id, bool local); + int getEventListeners(bool local); + void removeEventListener(int id); + void setupEventListeners(SVGDocumentImpl *doc, SVGDocumentImpl *newDoc); + + // Use with care! Internal only. + const QPtrList &eventListeners() { return m_eventListeners; } + + void handleLocalEvents(SVGEventImpl *evt, bool useCapture); + virtual void defaultEventHandler(SVGEventImpl *evt); + + bool mouseOver() { return m_mouseOver; } + void setMouseOver(bool v) { m_mouseOver = v; } + + bool focus() { return m_focus; } + void setFocus(bool v) { m_focus = v; } + + virtual bool prepareMouseEvent(const QPoint &, const QPoint &, SVGMouseEventImpl *); + + virtual void createItem(KSVGCanvas *c = 0) { Q_UNUSED(c); } + virtual void removeItem(KSVGCanvas *c) { Q_UNUSED(c); } + + // Element creation + typedef SVGElementImpl *(*FactoryFn)(DOM::ElementImpl *impl); + class Factory + { + public: + static Factory *self() + { + if(!m_instance) + m_instance = new Factory(); + + return m_instance; + } + + void announce(SVGElementImpl::FactoryFn factoryFn, const std::string &tag) + { + if(m_elementMap.find(tag) == m_elementMap.end()) + m_elementMap[tag] = factoryFn; + } + + SVGElementImpl *create(const std::string &tag, DOM::ElementImpl *impl) const + { + ElementMap::const_iterator it = m_elementMap.find(tag); + if(it != m_elementMap.end()) + return it->second(impl); + return 0; + } + + private: + Factory() { } + Factory(const Factory &rhs); + Factory &operator=(const Factory &rhs); + + static Factory *m_instance; + + typedef std::map ElementMap; + mutable ElementMap m_elementMap; + }; + + template + class Registrar + { + public: + Registrar(const std::string &tag) + { + SVGElementImpl::Factory::self()->announce(&factoryFn, tag); + } + + static SVGElementImpl *factoryFn(DOM::ElementImpl *impl) + { + return new T(impl); + } + }; + +#define KSVG_REGISTER_ELEMENT(Class, Tag) \ + static SVGElementImpl::Registrar Class##Registrar(Tag); + +protected: + void gotError(const QString &errorDesc); + +private: + SVGSVGElementImpl *m_ownerSVGElement; + SVGElementImpl *m_viewportElement; + SVGDocumentImpl *m_ownerDoc; + + bool m_mouseOver : 1; + bool m_focus : 1; + + QPtrList m_eventListeners; + QDict m_attributes; + +public: + KSVG_BASECLASS_GET + KSVG_PUT + + virtual KJS::ObjectImp *bridge(KJS::ExecState *exec) const; // NEEDS TO BE VIRTUAL HERE + + enum + { + // Properties + ElementId, OwnerSvgElement, ViewportElement, XmlBase, + OnMouseUp, OnMouseDown, OnMouseMove, OnMouseOver, OnMouseOut, + OnClick, OnActivate, OnKeyDown, OnKeyUp, OnKeyPress, OnLoad, + OnFocusIn, OnFocusOut, OnError, OnAbort, + // Functions + GetStyle, + // these do not really belong here, but the css doesnt work yet... + SetProperty, GetPropertyValue + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +KSVG_DEFINE_PROTOTYPE(SVGElementImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGElementImplProtoFunc, SVGElementImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGElementInstanceImpl.cc b/ksvg/impl/SVGElementInstanceImpl.cc new file mode 100644 index 00000000..97cd28a2 --- /dev/null +++ b/ksvg/impl/SVGElementInstanceImpl.cc @@ -0,0 +1,108 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGElementImpl.h" +#include "SVGUseElementImpl.h" +#include "SVGElementInstanceImpl.h" +#include "SVGElementInstanceListImpl.h" + +using namespace KSVG; + +SVGElementInstanceImpl::SVGElementInstanceImpl()//FIXME : events::EventTarget() +{ + m_correspondingElement = 0; + m_correspondingUseElement = 0; + m_parentNode = 0; + m_childNodes = 0; + m_firstChild = 0; + m_lastChild = 0; + m_previousSibling = 0; + m_nextSibling = 0; +} + +SVGElementInstanceImpl::~SVGElementInstanceImpl() +{ + if(m_correspondingElement) + m_correspondingElement->deref(); + if(m_correspondingUseElement) + m_correspondingUseElement->deref(); + if(m_parentNode) + m_parentNode->deref(); + if(m_childNodes) + m_childNodes->deref(); + if(m_firstChild) + m_firstChild->deref(); + if(m_lastChild) + m_lastChild->deref(); + if(m_previousSibling) + m_previousSibling->deref(); + if(m_nextSibling) + m_nextSibling->deref(); +} + +void SVGElementInstanceImpl::setCorrespondingElement(SVGElementImpl *corresponding) +{ + m_correspondingElement = corresponding; + + if(m_correspondingElement) + m_correspondingElement->ref(); +} + +SVGElementImpl *SVGElementInstanceImpl::correspondingElement() const +{ + return m_correspondingElement; +} + +SVGUseElementImpl *SVGElementInstanceImpl::correspondingUseElement() const +{ + return m_correspondingUseElement; +} + +SVGElementInstanceImpl *SVGElementInstanceImpl::parentNode() const +{ + return m_parentNode; +} + +SVGElementInstanceListImpl *SVGElementInstanceImpl::childNodes() const +{ + return m_childNodes; +} + +SVGElementInstanceImpl *SVGElementInstanceImpl::firstChild() const +{ + return m_firstChild; +} + +SVGElementInstanceImpl *SVGElementInstanceImpl::lastChild() const +{ + return m_lastChild; +} + +SVGElementInstanceImpl *SVGElementInstanceImpl::previousSibling() const +{ + return m_previousSibling; +} + +SVGElementInstanceImpl *SVGElementInstanceImpl::nextSibling() const +{ + return m_nextSibling; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGElementInstanceImpl.h b/ksvg/impl/SVGElementInstanceImpl.h new file mode 100644 index 00000000..d9f3afae --- /dev/null +++ b/ksvg/impl/SVGElementInstanceImpl.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGElementInstanceImpl_H +#define SVGElementInstanceImpl_H + +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGElementImpl; +class SVGUseElementImpl; +class SVGElementInstanceImpl; +class SVGElementInstanceListImpl; +class SVGElementInstanceImpl : public DOM::DomShared +{ +public: + SVGElementInstanceImpl(); + virtual ~SVGElementInstanceImpl(); + + SVGElementImpl *correspondingElement() const; + SVGUseElementImpl *correspondingUseElement() const; + SVGElementInstanceImpl *parentNode() const; + SVGElementInstanceListImpl *childNodes() const; + SVGElementInstanceImpl *firstChild() const; + SVGElementInstanceImpl *lastChild() const; + SVGElementInstanceImpl *previousSibling() const; + SVGElementInstanceImpl *nextSibling() const; + + void setCorrespondingElement(SVGElementImpl *); + +private: + SVGElementImpl *m_correspondingElement; + SVGUseElementImpl *m_correspondingUseElement; + SVGElementInstanceImpl *m_parentNode; + SVGElementInstanceListImpl *m_childNodes; + SVGElementInstanceImpl *m_firstChild; + SVGElementInstanceImpl *m_lastChild; + SVGElementInstanceImpl *m_previousSibling; + SVGElementInstanceImpl *m_nextSibling; + +public: + //KSVG_FORWARDGET +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGElementInstanceListImpl.cc b/ksvg/impl/SVGElementInstanceListImpl.cc new file mode 100644 index 00000000..187255ab --- /dev/null +++ b/ksvg/impl/SVGElementInstanceListImpl.cc @@ -0,0 +1,44 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGElementInstanceImpl.h" +#include "SVGElementInstanceListImpl.h" + +using namespace KSVG; + +SVGElementInstanceListImpl::SVGElementInstanceListImpl() +{ +} + +SVGElementInstanceListImpl::~SVGElementInstanceListImpl() +{ +} + +unsigned long SVGElementInstanceListImpl::length() const +{ + return m_length; +} + +SVGElementInstanceImpl *SVGElementInstanceListImpl::item(unsigned long /*index*/) +{ + return 0; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGElementInstanceListImpl.h b/ksvg/impl/SVGElementInstanceListImpl.h new file mode 100644 index 00000000..c9ac0dd2 --- /dev/null +++ b/ksvg/impl/SVGElementInstanceListImpl.h @@ -0,0 +1,49 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGElementInstanceListImpl_H +#define SVGElementInstanceListImpl_H + +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGElementInstanceImpl; +class SVGElementInstanceListImpl : public DOM::DomShared +{ +public: + SVGElementInstanceListImpl(); + virtual ~SVGElementInstanceListImpl(); + + unsigned long length() const; + SVGElementInstanceImpl *item(unsigned long index); + +private: + unsigned long m_length; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGEllipseElementImpl.cc b/ksvg/impl/SVGEllipseElementImpl.cc new file mode 100644 index 00000000..9908941a --- /dev/null +++ b/ksvg/impl/SVGEllipseElementImpl.cc @@ -0,0 +1,200 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include + +#include "CanvasItem.h" +#include "KSVGCanvas.h" + +#include "SVGRectImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGEllipseElementImpl.h" +#include "SVGAnimatedLengthImpl.h" + +using namespace KSVG; + +#include "SVGEllipseElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGEllipseElementImpl::SVGEllipseElementImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl() +{ + KSVG_EMPTY_FLAGS + + m_cx = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_cx->ref(); + m_cx->baseVal()->setValueAsString("-1"); + + m_cy = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_cy->ref(); + m_cy->baseVal()->setValueAsString("-1"); + + m_rx = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_rx->ref(); + m_rx->baseVal()->setValueAsString("-1"); + + m_ry = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_ry->ref(); + m_ry->baseVal()->setValueAsString("-1"); +} + +SVGEllipseElementImpl::~SVGEllipseElementImpl() +{ + if(m_cx) + m_cx->deref(); + if(m_cy) + m_cy->deref(); + if(m_rx) + m_rx->deref(); + if(m_ry) + m_ry->deref(); +} + +SVGAnimatedLengthImpl *SVGEllipseElementImpl::cx() +{ + return m_cx; +} + +SVGAnimatedLengthImpl *SVGEllipseElementImpl::cy() +{ + return m_cy; +} + +SVGAnimatedLengthImpl *SVGEllipseElementImpl::rx() +{ + return m_rx; +} + +SVGAnimatedLengthImpl *SVGEllipseElementImpl::ry() +{ + return m_ry; +} + +/* +@namespace KSVG +@begin SVGEllipseElementImpl::s_hashTable 5 + cx SVGEllipseElementImpl::Cx DontDelete|ReadOnly + cy SVGEllipseElementImpl::Cy DontDelete|ReadOnly + rx SVGEllipseElementImpl::Rx DontDelete|ReadOnly + ry SVGEllipseElementImpl::Ry DontDelete|ReadOnly +@end +*/ + +Value SVGEllipseElementImpl::getValueProperty(ExecState *exec, int token) const +{ + KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case Cx: + if(!attributeMode) + return m_cx->cache(exec); + else + return Number(m_cx->baseVal()->value()); + case Cy: + if(!attributeMode) + return m_cy->cache(exec); + else + return Number(m_cy->baseVal()->value()); + case Rx: + if(!attributeMode) + return m_rx->cache(exec); + else + return Number(m_rx->baseVal()->value()); + case Ry: + if(!attributeMode) + return m_ry->cache(exec); + else + return Number(m_ry->baseVal()->value()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGEllipseElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case Cx: + cx()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case Cy: + cy()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case Rx: + rx()->baseVal()->setValueAsString(value.toString(exec).qstring()); + if(rx()->baseVal()->value() < 0) // A negative value is an error + gotError("Negative value for attribute rx of element is illegal"); + break; + case Ry: + ry()->baseVal()->setValueAsString(value.toString(exec).qstring()); + if(ry()->baseVal()->value() < 0) // A negative value is an error + gotError(i18n("Negative value for attribute ry of element is illegal")); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +SVGRectImpl *SVGEllipseElementImpl::getBBox() +{ + SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect(); + ret->setX(m_cx->baseVal()->value() - m_rx->baseVal()->value()); + ret->setY(m_cy->baseVal()->value() - m_ry->baseVal()->value()); + ret->setWidth(m_rx->baseVal()->value() * 2.0); + ret->setHeight(m_ry->baseVal()->value() * 2.0); + return ret; +} + +void SVGEllipseElementImpl::setAttributes() +{ + SVGElementImpl::setAttributes(); + + // Spec: if not specified, effect is as if a value of "0" were specified + if(KSVG_TOKEN_NOT_PARSED(Cx)) + KSVG_SET_ALT_ATTRIBUTE(Cx, "0") + + // Spec: if not specified, effect is as if a value of "0" were specified + if(KSVG_TOKEN_NOT_PARSED(Cy)) + KSVG_SET_ALT_ATTRIBUTE(Cy, "0") +} + +void SVGEllipseElementImpl::createItem(KSVGCanvas *c) +{ + if(!c) + c = ownerDoc()->canvas(); + + if(!m_item) + { + m_item = c->createEllipse(this); + c->insert(m_item); + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGEllipseElementImpl.h b/ksvg/impl/SVGEllipseElementImpl.h new file mode 100644 index 00000000..131098ba --- /dev/null +++ b/ksvg/impl/SVGEllipseElementImpl.h @@ -0,0 +1,86 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGEllipseElementImpl_H +#define SVGEllipseElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGShapeImpl.h" +#include "SVGTestsImpl.h" +#include "SVGStylableImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGTransformableImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +namespace KSVG +{ + +class SVGRectImpl; +class SVGAnimatedLengthImpl; +class SVGEllipseElementImpl : public SVGShapeImpl, + public SVGTestsImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGTransformableImpl +{ +public: + SVGEllipseElementImpl(DOM::ElementImpl *); + virtual ~SVGEllipseElementImpl(); + + SVGAnimatedLengthImpl *cx(); + SVGAnimatedLengthImpl *cy(); + SVGAnimatedLengthImpl *rx(); + SVGAnimatedLengthImpl *ry(); + + virtual void createItem(KSVGCanvas *c = 0); + virtual void setAttributes(); + + virtual SVGRectImpl *getBBox(); + +private: + SVGAnimatedLengthImpl *m_cx; + SVGAnimatedLengthImpl *m_cy; + SVGAnimatedLengthImpl *m_rx; + SVGAnimatedLengthImpl *m_ry; + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + Cx, Cy, Rx, Ry + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGEllipseElementImpl, "ellipse") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGEventImpl.cc b/ksvg/impl/SVGEventImpl.cc new file mode 100644 index 00000000..418e0044 --- /dev/null +++ b/ksvg/impl/SVGEventImpl.cc @@ -0,0 +1,992 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + Additional copyright: + (C) 2001 Peter Kelly + (C) 2001 Tobias Anton + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGDocumentImpl.h" +#include "SVGEventImpl.h" + +#include + +using namespace KSVG; + +#include "ksvg_scriptinterpreter.h" +#include "SVGEventImpl.lut.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGEventImpl::SVGEventImpl() +{ + m_canBubble = false; + m_cancelable = false; + + m_propagationStopped = false; + m_defaultPrevented = false; + m_id = SVGEvent::UNKNOWN_EVENT; + m_eventPhase = 0; + m_createTime = QDateTime::currentDateTime(); + m_defaultHandled = false; + + m_target = 0; + m_currentTarget = 0; +} + +SVGEventImpl::SVGEventImpl(SVGEvent::EventId _id, bool canBubbleArg, bool cancelableArg) +{ + DOM::DOMString t = SVGEvent::idToType(_id); + m_type = t.implementation(); + + m_canBubble = canBubbleArg; + m_cancelable = cancelableArg; + + m_propagationStopped = false; + m_defaultPrevented = false; + m_id = _id; + m_eventPhase = 0; + m_createTime = QDateTime::currentDateTime(); + m_defaultHandled = false; + + m_target = 0; + m_currentTarget = 0; +} + +SVGEventImpl::~SVGEventImpl() +{ +} + +DOM::DOMString SVGEventImpl::type() const +{ + return m_type; +} + +SVGElementImpl *SVGEventImpl::target() const +{ + return m_target; +} + +void SVGEventImpl::setTarget(SVGElementImpl *_target) +{ + m_target = _target; +} + +SVGElementImpl *SVGEventImpl::currentTarget() const +{ + return m_currentTarget; +} + +void SVGEventImpl::setCurrentTarget(SVGElementImpl *_currentTarget) +{ + m_currentTarget = _currentTarget; +} + +unsigned short SVGEventImpl::eventPhase() const +{ + return m_eventPhase; +} + +void SVGEventImpl::setEventPhase(unsigned short _eventPhase) +{ + m_eventPhase = _eventPhase; +} + +bool SVGEventImpl::bubbles() const +{ + return m_canBubble; +} + +bool SVGEventImpl::cancelable() const +{ + return m_cancelable; +} + +DOM::DOMTimeStamp SVGEventImpl::timeStamp() +{ + QDateTime epoch(QDate(1970, 1, 1), QTime(0, 0)); + + // ### kjs does not yet support long long (?) so the value wraps around + return epoch.secsTo(m_createTime) * 1000 + m_createTime.time().msec(); +} + +void SVGEventImpl::stopPropagation() +{ + m_propagationStopped = true; +} + +void SVGEventImpl::preventDefault() +{ + if(m_cancelable) + m_defaultPrevented = true; +} + +void SVGEventImpl::initEvent(const DOM::DOMString &eventTypeArg, bool canBubbleArg, bool cancelableArg) +{ + // ### ensure this is not called after we have been dispatched (also for subclasses) + m_type = eventTypeArg.implementation(); + m_id = SVGEvent::typeToId(eventTypeArg); + + m_canBubble = canBubbleArg; + m_cancelable = cancelableArg; +} + +void SVGEventImpl::setDefaultHandled() +{ + m_defaultHandled = true; +} + +/* +@namespace KSVG +@begin SVGEventImpl::s_hashTable 11 + type SVGEventImpl::Type DontDelete|ReadOnly + target SVGEventImpl::Target DontDelete|ReadOnly + currentTarget SVGEventImpl::CurrentTarget DontDelete|ReadOnly + eventPhase SVGEventImpl::EventPhase DontDelete|ReadOnly + bubbles SVGEventImpl::Bubbles DontDelete|ReadOnly + cancelable SVGEventImpl::Cancelable DontDelete|ReadOnly + timeStamp SVGEventImpl::TimeStamp DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGEventImplProto::s_hashTable 13 + getType SVGEventImpl::GetType DontDelete|Function 0 + getTarget SVGEventImpl::GetTarget DontDelete|Function 0 + getCurrentTarget SVGEventImpl::GetCurrentTarget DontDelete|Function 0 + getCurrentNode SVGEventImpl::GetCurrentNode DontDelete|Function 0 + getEventphase SVGEventImpl::GetEventPhase DontDelete|Function 0 + getBubbles SVGEventImpl::GetBubbles DontDelete|Function 0 + getCancelable SVGEventImpl::GetCancelable DontDelete|Function 0 + getTimeStamp SVGEventImpl::GetTimeStamp DontDelete|Function 0 + stopPropagation SVGEventImpl::StopPropagation DontDelete|Function 0 + preventDefault SVGEventImpl::PreventDefault DontDelete|Function 0 + initEvent SVGEventImpl::InitEvent DontDelete|Function 3 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGEvent", SVGEventImplProto, SVGEventImplProtoFunc) + +Value SVGEventImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case Type: + return String(type()); + case Target: + return getDOMNode(exec, *target()); + case CurrentTarget: + return getDOMNode(exec, *currentTarget()); + case EventPhase: + return Number(eventPhase()); + case Bubbles: + return Boolean(bubbles()); + case Cancelable: + return Boolean(cancelable()); +// case TimeStamp: // TODO + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return KJS::Undefined(); + } +} + +Value SVGEventImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGEventImpl) + + switch(id) + { + case SVGEventImpl::GetType: + return String(obj->type()); + case SVGEventImpl::GetTarget: + return getDOMNode(exec, *obj->target()); + case SVGEventImpl::GetCurrentTarget: + case SVGEventImpl::GetCurrentNode: + return getDOMNode(exec, *obj->currentTarget()); + case SVGEventImpl::GetEventPhase: + return Number(obj->eventPhase()); + case SVGEventImpl::GetBubbles: + return Boolean(obj->bubbles()); + case SVGEventImpl::GetCancelable: + return Boolean(obj->cancelable()); +// case SVGEventImpl::GetTimeStamp: // TODO + case SVGEventImpl::StopPropagation: + { + obj->stopPropagation(); + return Undefined(); + } + case SVGEventImpl::PreventDefault: + { + obj->preventDefault(); + return Undefined(); + } + case SVGEventImpl::InitEvent: + { + obj->initEvent(args[0].toString(exec).string(), args[1].toBoolean(exec), args[2].toBoolean(exec)); + return Undefined(); + } + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + + + + + +SVGUIEventImpl::SVGUIEventImpl() : SVGEventImpl() +{ + m_detail = 0; +} + +SVGUIEventImpl::SVGUIEventImpl(SVGEvent::EventId _id, bool canBubbleArg, bool cancelableArg, DOM::AbstractView &viewArg, long detailArg) +: SVGEventImpl(_id, canBubbleArg, cancelableArg) +{ + m_view = viewArg; + m_detail = detailArg; +} + +SVGUIEventImpl::~SVGUIEventImpl() +{ +} + +DOM::AbstractView SVGUIEventImpl::view() const +{ + return m_view; +} + +long SVGUIEventImpl::detail() const +{ + return m_detail; +} + +void SVGUIEventImpl::initUIEvent(const DOM::DOMString &typeArg, + bool canBubbleArg, + bool cancelableArg, + const DOM::AbstractView &viewArg, + long detailArg) +{ + SVGEventImpl::initEvent(typeArg, canBubbleArg, cancelableArg); + + m_view = viewArg; + m_detail = detailArg; +} + +/* +@namespace KSVG +@begin SVGUIEventImpl::s_hashTable 3 + view SVGUIEventImpl::View DontDelete|ReadOnly + detail SVGUIEventImpl::Detail DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGUIEventImplProto::s_hashTable 5 + getView SVGUIEventImpl::GetView DontDelete|Function 0 + getDetail SVGUIEventImpl::GetDetail DontDelete|Function 0 + initUIEvent SVGUIEventImpl::InitUIEvent DontDelete|Function 5 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGUIEvent", SVGUIEventImplProto, SVGUIEventImplProtoFunc) + +Value SVGUIEventImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { +// case View: // TODO + case Detail: + return Number(detail()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return KJS::Undefined(); + } +} + +Value SVGUIEventImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &) +{ + KSVG_CHECK_THIS(SVGUIEventImpl) + + switch(id) + { +// case SVGUIEventImpl::GetView: // TODO + case SVGUIEventImpl::GetDetail: + return Number(obj->detail()); +// case SVGUIEventImpl::InitUIEvent: // TODO + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + +SVGKeyEventImpl::SVGKeyEventImpl() : SVGUIEventImpl() +{ + qKeyEvent = 0; +} + +SVGKeyEventImpl::SVGKeyEventImpl(QKeyEvent *key, DOM::AbstractView &view, SVGEvent::EventId _id) : SVGUIEventImpl(_id, true, true, view, 0) +{ + qKeyEvent = new QKeyEvent(key->type(), key->key(), key->ascii(), key->state(), key->text(), key->isAutoRepeat(), key->count()); + + // Events are supposed to be accepted by default in Qt! + // This line made QLineEdit's keyevents be ignored, so they were sent to the khtmlview + // (and e.g. space would make it scroll down) + //qKeyEvent->ignore(); + + m_detail = key->count(); + + m_numPad = false; + m_keyVal = 0; + m_virtKeyVal = DOM_VK_UNDEFINED; + m_inputGenerated = true; + + switch(key->key()) + { + case Qt::Key_Enter: + m_numPad = true; + /* fall through */ + case Qt::Key_Return: + m_virtKeyVal = DOM_VK_ENTER; + break; + case Qt::Key_NumLock: + m_numPad = true; + m_virtKeyVal = DOM_VK_NUM_LOCK; + break; + case Qt::Key_Alt: + m_virtKeyVal = DOM_VK_RIGHT_ALT; + // ### DOM_VK_LEFT_ALT; + break; + case Qt::Key_Control: + m_virtKeyVal = DOM_VK_LEFT_CONTROL; + // ### DOM_VK_RIGHT_CONTROL + break; + case Qt::Key_Shift: + m_virtKeyVal = DOM_VK_LEFT_SHIFT; + // ### DOM_VK_RIGHT_SHIFT + break; + case Qt::Key_Meta: + m_virtKeyVal = DOM_VK_LEFT_META; + // ### DOM_VK_RIGHT_META + break; + case Qt::Key_CapsLock: + m_virtKeyVal = DOM_VK_CAPS_LOCK; + break; + case Qt::Key_Delete: + m_virtKeyVal = DOM_VK_DELETE; + break; + case Qt::Key_End: + m_virtKeyVal = DOM_VK_END; + break; + case Qt::Key_Escape: + m_virtKeyVal = DOM_VK_ESCAPE; + break; + case Qt::Key_Home: + m_virtKeyVal = DOM_VK_HOME; + break; + case Qt::Key_Insert: + m_virtKeyVal = DOM_VK_INSERT; + break; + case Qt::Key_Pause: + m_virtKeyVal = DOM_VK_PAUSE; + break; + case Qt::Key_Print: + m_virtKeyVal = DOM_VK_PRINTSCREEN; + break; + case Qt::Key_ScrollLock: + m_virtKeyVal = DOM_VK_SCROLL_LOCK; + break; + case Qt::Key_Left: + m_virtKeyVal = DOM_VK_LEFT; + break; + case Qt::Key_Right: + m_virtKeyVal = DOM_VK_RIGHT; + break; + case Qt::Key_Up: + m_virtKeyVal = DOM_VK_UP; + break; + case Qt::Key_Down: + m_virtKeyVal = DOM_VK_DOWN; + break; + case Qt::Key_Next: + m_virtKeyVal = DOM_VK_PAGE_DOWN; + break; + case Qt::Key_Prior: + m_virtKeyVal = DOM_VK_PAGE_UP; + break; + case Qt::Key_F1: + m_virtKeyVal = DOM_VK_F1; + break; + case Qt::Key_F2: + m_virtKeyVal = DOM_VK_F2; + break; + case Qt::Key_F3: + m_virtKeyVal = DOM_VK_F3; + break; + case Qt::Key_F4: + m_virtKeyVal = DOM_VK_F4; + break; + case Qt::Key_F5: + m_virtKeyVal = DOM_VK_F5; + break; + case Qt::Key_F6: + m_virtKeyVal = DOM_VK_F6; + break; + case Qt::Key_F7: + m_virtKeyVal = DOM_VK_F7; + break; + case Qt::Key_F8: + m_virtKeyVal = DOM_VK_F8; + break; + case Qt::Key_F9: + m_virtKeyVal = DOM_VK_F9; + break; + case Qt::Key_F10: + m_virtKeyVal = DOM_VK_F10; + break; + case Qt::Key_F11: + m_virtKeyVal = DOM_VK_F11; + break; + case Qt::Key_F12: + m_virtKeyVal = DOM_VK_F12; + break; + case Qt::Key_F13: + m_virtKeyVal = DOM_VK_F13; + break; + case Qt::Key_F14: + m_virtKeyVal = DOM_VK_F14; + break; + case Qt::Key_F15: + m_virtKeyVal = DOM_VK_F15; + break; + case Qt::Key_F16: + m_virtKeyVal = DOM_VK_F16; + break; + case Qt::Key_F17: + m_virtKeyVal = DOM_VK_F17; + break; + case Qt::Key_F18: + m_virtKeyVal = DOM_VK_F18; + break; + case Qt::Key_F19: + m_virtKeyVal = DOM_VK_F19; + break; + case Qt::Key_F20: + m_virtKeyVal = DOM_VK_F20; + break; + case Qt::Key_F21: + m_virtKeyVal = DOM_VK_F21; + break; + case Qt::Key_F22: + m_virtKeyVal = DOM_VK_F22; + break; + case Qt::Key_F23: + m_virtKeyVal = DOM_VK_F23; + break; + case Qt::Key_F24: + m_virtKeyVal = DOM_VK_F24; + break; + default: + m_virtKeyVal = DOM_VK_UNDEFINED; + break; + } + + // m_keyVal should contain the unicode value + // of the pressed key if available. + if (!key->text().isNull()) + m_keyVal = key->text().unicode()[0]; + + // m_numPad = ??? + + // key->state returns enum ButtonState, which is ShiftButton, ControlButton and AltButton or'ed together. + m_modifier = key->state(); + + // key->text() returns the unicode sequence as a QString + m_outputString = DOM::DOMString(key->text()); +} + +SVGKeyEventImpl::SVGKeyEventImpl(SVGEvent::EventId _id, + bool canBubbleArg, + bool cancelableArg, + DOM::AbstractView &viewArg, + unsigned short detailArg, + DOM::DOMString &outputStringArg, + unsigned long keyValArg, + unsigned long virtKeyValArg, + bool inputGeneratedArg, + bool numPadArg) +: SVGUIEventImpl(_id, canBubbleArg, cancelableArg, viewArg, detailArg) +{ + qKeyEvent = 0; + m_keyVal = keyValArg; + m_virtKeyVal = virtKeyValArg; + m_inputGenerated = inputGeneratedArg; + m_outputString = outputStringArg; + m_numPad = numPadArg; + m_modifier = 0; +} + +SVGKeyEventImpl::~SVGKeyEventImpl() +{ + delete qKeyEvent; +} + +bool SVGKeyEventImpl::checkModifier(unsigned long modifierArg) +{ + return ((m_modifier && modifierArg) == modifierArg); +} + +void SVGKeyEventImpl::initKeyEvent(DOM::DOMString &typeArg, + bool canBubbleArg, + bool cancelableArg, + const DOM::AbstractView &viewArg, + long detailArg, + DOM::DOMString &outputStringArg, + unsigned long keyValArg, + unsigned long virtKeyValArg, + bool inputGeneratedArg, + bool numPadArg) +{ + SVGUIEventImpl::initUIEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg); + + m_outputString = outputStringArg; + m_keyVal = keyValArg; + m_virtKeyVal = virtKeyValArg; + m_inputGenerated = inputGeneratedArg; + m_numPad = numPadArg; +} + +void SVGKeyEventImpl::initModifier(unsigned long modifierArg, bool valueArg) +{ + if(valueArg) + m_modifier |= modifierArg; + else + m_modifier &= (modifierArg ^ 0xFFFFFFFF); +} + +bool SVGKeyEventImpl::inputGenerated() const +{ + return m_inputGenerated; +} + +unsigned long SVGKeyEventImpl::keyVal() const +{ + return m_keyVal; +} + +DOM::DOMString SVGKeyEventImpl::outputString() const +{ + return m_outputString; +} + +/* +@namespace KSVG +@begin SVGKeyEventImpl::s_hashTable 7 + keyVal SVGKeyEventImpl::KeyVal DontDelete|ReadOnly + keyCode SVGKeyEventImpl::KeyVal DontDelete|ReadOnly + charCode SVGKeyEventImpl::KeyVal DontDelete|ReadOnly + outputString SVGKeyEventImpl::OutputString DontDelete|ReadOnly + virtKeyVal SVGKeyEventImpl::VirtKeyVal DontDelete|ReadOnly +# todo visibleOutputGenerated numPad +@end +@namespace KSVG +@begin SVGKeyEventImplProto::s_hashTable 7 + checkModifier SVGKeyEventImpl::CheckModifier DontDelete|Function 1 + getKeyCode SVGKeyEventImpl::GetKeyVal DontDelete|Function 0 + getCharCode SVGKeyEventImpl::GetKeyVal DontDelete|Function 0 + getKeyVal SVGKeyEventImpl::GetKeyVal DontDelete|Function 0 + getCharCode SVGKeyEventImpl::GetCharCode DontDelete|Function 0 +# todo initModifier +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGKeyEvent", SVGKeyEventImplProto, SVGKeyEventImplProtoFunc) + +Value SVGKeyEventImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case KeyVal: + return Number(keyVal()); + case VirtKeyVal: + return Number(virtKeyVal()); + case OutputString: + return String(outputString()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +Value SVGKeyEventImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGKeyEventImpl) + + switch(id) + { + case SVGKeyEventImpl::CheckModifier: + return Boolean((static_cast *>(static_cast(thisObj.imp()))->impl())->checkModifier(args[0].toUInt32(exec))); + case SVGKeyEventImpl::GetKeyVal: + case SVGKeyEventImpl::GetCharCode: + return Number((static_cast *>(static_cast(thisObj.imp()))->impl())->keyVal()); + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + + + +// ----------------------------------------------------------------------------- + +SVGMouseEventImpl::SVGMouseEventImpl() : SVGUIEventImpl() +{ + m_screenX = 0; + m_screenY = 0; + m_clientX = 0; + m_clientY = 0; + m_ctrlKey = false; + m_altKey = false; + m_shiftKey = false; + m_metaKey = false; + m_button = 0; +} + +SVGMouseEventImpl::SVGMouseEventImpl(SVGEvent::EventId _id, + bool canBubbleArg, + bool cancelableArg, + DOM::AbstractView &viewArg, + long detailArg, + long screenXArg, + long screenYArg, + long clientXArg, + long clientYArg, + bool ctrlKeyArg, + bool altKeyArg, + bool shiftKeyArg, + bool metaKeyArg, + unsigned short buttonArg, + SVGElementImpl *relatedTargetArg) +: SVGUIEventImpl(_id, canBubbleArg, cancelableArg, viewArg, detailArg) +{ + m_screenX = screenXArg; + m_screenY = screenYArg; + m_clientX = clientXArg; + m_clientY = clientYArg; + m_ctrlKey = ctrlKeyArg; + m_altKey = altKeyArg; + m_shiftKey = shiftKeyArg; + m_metaKey = metaKeyArg; + m_button = buttonArg; + m_relatedTarget = relatedTargetArg; +} + +SVGMouseEventImpl::~SVGMouseEventImpl() +{ +} + +long SVGMouseEventImpl::screenX() const +{ + return m_screenX; +} + +long SVGMouseEventImpl::screenY() const +{ + return m_screenY; +} + +long SVGMouseEventImpl::clientX() const +{ + return m_clientX; +} + +long SVGMouseEventImpl::clientY() const +{ + return m_clientY; +} + +bool SVGMouseEventImpl::ctrlKey() const +{ + return m_ctrlKey; +} + +bool SVGMouseEventImpl::shiftKey() const +{ + return m_shiftKey; +} + +bool SVGMouseEventImpl::altKey() const +{ + return m_altKey; +} + +bool SVGMouseEventImpl::metaKey() const +{ + return m_metaKey; +} + +unsigned short SVGMouseEventImpl::button() const +{ + return m_button; +} + +SVGElementImpl *SVGMouseEventImpl::relatedTarget() const +{ + return m_relatedTarget; +} + +DOM::DOMString SVGMouseEventImpl::url() const +{ + return m_url; +} + +void SVGMouseEventImpl::setURL(DOM::DOMString url) +{ + m_url = url; +} + +void SVGMouseEventImpl::initMouseEvent(const DOM::DOMString &typeArg, + bool canBubbleArg, + bool cancelableArg, + const DOM::AbstractView &viewArg, + long detailArg, + long screenXArg, + long screenYArg, + long clientXArg, + long clientYArg, + bool ctrlKeyArg, + bool altKeyArg, + bool shiftKeyArg, + bool metaKeyArg, + unsigned short buttonArg, + SVGElementImpl *relatedTargetArg) +{ + SVGUIEventImpl::initUIEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg); + + m_screenX = screenXArg; + m_screenY = screenYArg; + m_clientX = clientXArg; + m_clientY = clientYArg; + m_ctrlKey = ctrlKeyArg; + m_altKey = altKeyArg; + m_shiftKey = shiftKeyArg; + m_metaKey = metaKeyArg; + m_button = buttonArg; + m_relatedTarget = relatedTargetArg; +} + +/* +@namespace KSVG +@begin SVGMouseEventImpl::s_hashTable 11 + screenX SVGMouseEventImpl::ScreenX DontDelete|ReadOnly + screenY SVGMouseEventImpl::ScreenY DontDelete|ReadOnly + clientX SVGMouseEventImpl::ClientX DontDelete|ReadOnly + clientY SVGMouseEventImpl::ClientY DontDelete|ReadOnly + ctrlKey SVGMouseEventImpl::CtrlKey DontDelete|ReadOnly + shiftKey SVGMouseEventImpl::ShiftKey DontDelete|ReadOnly + altKey SVGMouseEventImpl::AltKey DontDelete|ReadOnly + metaKey SVGMouseEventImpl::MetaKey DontDelete|ReadOnly + button SVGMouseEventImpl::Button DontDelete|ReadOnly + relatedTarget SVGMouseEventImpl::RelatedTarget DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGMouseEventImplProto::s_hashTable 13 + getScreenX SVGMouseEventImpl::GetScreenX DontDelete|Function 0 + getScreenY SVGMouseEventImpl::GetScreenY DontDelete|Function 0 + getClientX SVGMouseEventImpl::GetClientX DontDelete|Function 0 + getClientY SVGMouseEventImpl::GetClientY DontDelete|Function 0 + getCtrlKey SVGMouseEventImpl::GetCtrlKey DontDelete|Function 0 + getShiftKey SVGMouseEventImpl::GetShiftKey DontDelete|Function 0 + getAltKey SVGMouseEventImpl::GetAltKey DontDelete|Function 0 + getMetaKey SVGMouseEventImpl::GetMetaKey DontDelete|Function 0 + getButton SVGMouseEventImpl::GetButton DontDelete|Function 0 + getRelatedTarget SVGMouseEventImpl::GetRelatedTarget DontDelete|Function 0 + initMouseEvent SVGMouseEventImpl::InitMouseEvent DontDelete|Function 15 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGMouseEvent", SVGMouseEventImplProto, SVGMouseEventImplProtoFunc) + +Value SVGMouseEventImpl::getValueProperty(ExecState *exec, int token) const +{ + kdDebug(26004) << k_funcinfo << endl; + switch(token) + { + case ScreenX: + return Number(screenX()); + case ScreenY: + return Number(screenY()); + case ClientX: + return Number(clientX()); + case ClientY: + return Number(clientY()); + case CtrlKey: + return Number(ctrlKey()); + case ShiftKey: + return Number(shiftKey()); + case AltKey: + return Number(altKey()); + case MetaKey: + return Number(metaKey()); + case Button: + return Number(button()); + case RelatedTarget: + return getDOMNode(exec, *relatedTarget()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return KJS::Undefined(); + } +} + +Value SVGMouseEventImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &) +{ + kdDebug(26004) << k_funcinfo << endl; + KSVG_CHECK_THIS(SVGMouseEventImpl) + + switch(id) + { + case SVGMouseEventImpl::GetScreenX: + return Number(obj->screenX()); + case SVGMouseEventImpl::GetScreenY: + return Number(obj->screenY()); + case SVGMouseEventImpl::GetClientX: + return Number(obj->clientX()); + case SVGMouseEventImpl::GetClientY: + return Number(obj->clientY()); + case SVGMouseEventImpl::GetCtrlKey: + return Number(obj->ctrlKey()); + case SVGMouseEventImpl::GetShiftKey: + return Number(obj->shiftKey()); + case SVGMouseEventImpl::GetAltKey: + return Number(obj->altKey()); + case SVGMouseEventImpl::GetMetaKey: + return Number(obj->metaKey()); + case SVGMouseEventImpl::GetButton: + return Number(obj->button()); + case SVGMouseEventImpl::GetRelatedTarget: + return getDOMNode(exec, *obj->relatedTarget()); +// case SVGMouseEventImpl::InitMouseEvent: // TODO + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + + + + +SVGMutationEventImpl::SVGMutationEventImpl() : SVGEventImpl() +{ + m_attrChange = 0; +} + +SVGMutationEventImpl::SVGMutationEventImpl(SVGEvent::EventId _id, + bool canBubbleArg, + bool cancelableArg, + SVGElementImpl *relatedNodeArg, + const DOM::DOMString &prevValueArg, + const DOM::DOMString &newValueArg, + const DOM::DOMString &attrNameArg, + unsigned short attrChangeArg) +: SVGEventImpl(_id, canBubbleArg, cancelableArg) +{ + m_relatedNode = relatedNodeArg; + m_prevValue = prevValueArg.implementation(); + m_newValue = newValueArg.implementation(); + m_attrName = attrNameArg.implementation(); + m_attrChange = attrChangeArg; +} + +SVGMutationEventImpl::~SVGMutationEventImpl() +{ +} + +SVGElementImpl *SVGMutationEventImpl::relatedNode() const +{ + return m_relatedNode; +} + +DOM::DOMString SVGMutationEventImpl::prevValue() const +{ + return m_prevValue; +} + +DOM::DOMString SVGMutationEventImpl::newValue() const +{ + return m_newValue; +} + +DOM::DOMString SVGMutationEventImpl::attrName() const +{ + return m_attrName; +} + +unsigned short SVGMutationEventImpl::attrChange() const +{ + return m_attrChange; +} + +void SVGMutationEventImpl::initMutationEvent(const DOM::DOMString &typeArg, + bool canBubbleArg, + bool cancelableArg, + SVGElementImpl *relatedNodeArg, + const DOM::DOMString &prevValueArg, + const DOM::DOMString &newValueArg, + const DOM::DOMString &attrNameArg, + unsigned short attrChangeArg) +{ + SVGEventImpl::initEvent(typeArg, canBubbleArg, cancelableArg); + + m_relatedNode = relatedNodeArg; + m_prevValue = prevValueArg.implementation(); + m_newValue = newValueArg.implementation(); + m_attrName = attrNameArg.implementation(); + m_attrChange = attrChangeArg; +} + + + + + +SVGRegisteredEventListener::SVGRegisteredEventListener(SVGEvent::EventId _id, SVGEventListener *_listener, bool _useCapture) +{ + id = _id; + listener = _listener; + useCapture = _useCapture; + + listener->ref(); +} + +SVGRegisteredEventListener::~SVGRegisteredEventListener() +{ + listener->deref(); +} + +bool SVGRegisteredEventListener::operator==(const SVGRegisteredEventListener &other) +{ + return (id == other.id && + listener == other.listener && + useCapture == other.useCapture); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGEventImpl.h b/ksvg/impl/SVGEventImpl.h new file mode 100644 index 00000000..a123b09e --- /dev/null +++ b/ksvg/impl/SVGEventImpl.h @@ -0,0 +1,468 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + Additional copyright: + (C) 2001 Peter Kelly + (C) 2001 Tobias Anton + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGEventImpl_H +#define SVGEventImpl_H + +#include +#include + +#include +#include +#include +#include + +#include "SVGEvent.h" +#include "SVGElementImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +// @ecma-checked 07/07/02@ +class SVGEventImpl : public DOM::DomShared +{ +public: + SVGEventImpl(); + SVGEventImpl(SVGEvent::EventId _id, bool canBubbleArg, bool cancelableArg); + virtual ~SVGEventImpl(); + + SVGEvent::EventId id() { return m_id; } + + DOM::DOMString type() const; + + SVGElementImpl *target() const; + void setTarget(SVGElementImpl *_target); + + SVGElementImpl *currentTarget() const; + void setCurrentTarget(SVGElementImpl *_currentTarget); + + unsigned short eventPhase() const; + void setEventPhase(unsigned short _eventPhase); + + bool bubbles() const; + bool cancelable() const; + + DOM::DOMTimeStamp timeStamp(); + + void stopPropagation(); + void preventDefault(); + void initEvent(const DOM::DOMString &eventTypeArg, bool canBubbleArg, bool cancelableArg); + + virtual bool isUIEvent() { return false; } + virtual bool isMouseEvent() { return false; } + virtual bool isMutationEvent() { return false; } + virtual bool isKeyEvent() { return false; } + + virtual DOM::DOMString eventModuleName() { return ""; } + + virtual bool propagationStopped() { return m_propagationStopped; } + virtual bool defaultPrevented() { return m_defaultPrevented; } + + void setDefaultHandled(); + bool defaultHandled() const { return m_defaultHandled; } + +protected: + DOM::DOMString m_type; + bool m_canBubble; + bool m_cancelable; + + bool m_propagationStopped; + bool m_defaultPrevented; + bool m_defaultHandled; + + SVGEvent::EventId m_id; + SVGElementImpl *m_currentTarget; + SVGElementImpl *m_target; + + unsigned short m_eventPhase; + QDateTime m_createTime; + +public: + KSVG_BASECLASS_GET + + enum + { + // Properties + Type, Target, CurrentTarget, EventPhase, + Bubbles, Cancelable, TimeStamp, + // Functions + GetType, GetTarget, GetCurrentTarget, GetEventPhase, + GetBubbles, GetCancelable, GetTimeStamp, + StopPropagation, PreventDefault, InitEvent, + GetCurrentNode // Out-Of-Spec + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +class SVGEventListener : public DOM::DomShared +{ +public: + SVGEventListener() { } + virtual ~SVGEventListener() { } + + virtual void handleEvent(SVGEventImpl *) { } + virtual DOM::DOMString eventListenerType() { return ""; } +}; + +// @ecma-checked 07/07/02@ +class SVGUIEventImpl : public SVGEventImpl +{ +public: + SVGUIEventImpl(); + SVGUIEventImpl(SVGEvent::EventId _id, + bool canBubbleArg, + bool cancelableArg, + DOM::AbstractView &viewArg, + long detailArg); + + virtual ~SVGUIEventImpl(); + + DOM::AbstractView view() const; + long detail() const; + + void initUIEvent(const DOM::DOMString &typeArg, + bool canBubbleArg, + bool cancelableArg, + const DOM::AbstractView &viewArg, + long detailArg); + + virtual bool isUIEvent() { return true; } + virtual DOM::DOMString eventModuleName() { return "UIEvents"; } + +protected: + DOM::AbstractView m_view; + long m_detail; + +public: + KSVG_GET + + enum + { + // Properties + View, Detail, + // Functions + GetView, GetDetail, InitUIEvent + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +// @ecma-checked 07/07/02@ +// Introduced in DOM Level 2: - internal +class SVGMouseEventImpl : public SVGUIEventImpl +{ +public: + SVGMouseEventImpl(); + SVGMouseEventImpl(SVGEvent::EventId _id, + bool canBubbleArg, + bool cancelableArg, + DOM::AbstractView &viewArg, + long detailArg, + long screenXArg, + long screenYArg, + long clientXArg, + long clientYArg, + bool ctrlKeyArg, + bool altKeyArg, + bool shiftKeyArg, + bool metaKeyArg, + unsigned short buttonArg, + SVGElementImpl *relatedTargetArg); + + virtual ~SVGMouseEventImpl(); + + long screenX() const; + long screenY() const; + long clientX() const; + long clientY() const; + bool ctrlKey() const; + bool shiftKey() const; + bool altKey() const; + bool metaKey() const; + + unsigned short button() const; + + SVGElementImpl *relatedTarget() const; + + void initMouseEvent(const DOM::DOMString &typeArg, + bool canBubbleArg, + bool cancelableArg, + const DOM::AbstractView &viewArg, + long detailArg, + long screenXArg, + long screenYArg, + long clientXArg, + long clientYArg, + bool ctrlKeyArg, + bool altKeyArg, + bool shiftKeyArg, + bool metaKeyArg, + unsigned short buttonArg, + SVGElementImpl *relatedTargetArg); + + virtual bool isMouseEvent() { return true; } + virtual DOM::DOMString eventModuleName() { return "MouseEvents"; } + + // KSVG extensions + DOM::DOMString url() const; + void setURL(DOM::DOMString url); + +protected: + long m_screenX; + long m_screenY; + long m_clientX; + long m_clientY; + bool m_ctrlKey; + bool m_altKey; + bool m_shiftKey; + bool m_metaKey; + unsigned short m_button; + SVGElementImpl *m_relatedTarget; + + // KSVG extension + DOM::DOMString m_url; + +public: + KSVG_GET + + enum + { + // Properties + ScreenX, ScreenY, ClientX, ClientY, CtrlKey, + ShiftKey, AltKey, MetaKey, Button, RelatedTarget, + // Functions + GetScreenX, GetScreenY, GetClientX, GetClientY, GetCtrlKey, + GetShiftKey, GetAltKey, GetMetaKey, GetButton, GetRelatedTarget, + InitMouseEvent + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +class SVGKeyEventImpl : public SVGUIEventImpl +{ +public: + SVGKeyEventImpl(); + SVGKeyEventImpl(SVGEvent::EventId _id, + bool canBubbleArg, + bool cancelableArg, + DOM::AbstractView &viewArg, + unsigned short detailArg, + DOM::DOMString &outputStringArg, + unsigned long keyValArg, + unsigned long virtKeyValArg, + bool inputGeneratedArg, + bool numPadArg); + + SVGKeyEventImpl(QKeyEvent *key, DOM::AbstractView &view, SVGEvent::EventId _id); + + virtual bool isKeyEvent() { return true; } + + virtual ~SVGKeyEventImpl(); + + enum KeyCodes + { + DOM_VK_UNDEFINED = 0x0, + DOM_VK_RIGHT_ALT = 0x01, + DOM_VK_LEFT_ALT = 0x02, + DOM_VK_LEFT_CONTROL = 0x03, + DOM_VK_RIGHT_CONTROL = 0x04, + DOM_VK_LEFT_SHIFT = 0x05, + DOM_VK_RIGHT_SHIFT = 0x06, + DOM_VK_LEFT_META = 0x07, + DOM_VK_RIGHT_META = 0x08, + DOM_VK_CAPS_LOCK = 0x09, + DOM_VK_DELETE = 0x0A, + DOM_VK_END = 0x0B, + DOM_VK_ENTER = 0x0C, + DOM_VK_ESCAPE = 0x0D, + DOM_VK_HOME = 0x0E, + DOM_VK_INSERT = 0x0F, + DOM_VK_NUM_LOCK = 0x10, + DOM_VK_PAUSE = 0x11, + DOM_VK_PRINTSCREEN = 0x12, + DOM_VK_SCROLL_LOCK = 0x13, + DOM_VK_LEFT = 0x14, + DOM_VK_RIGHT = 0x15, + DOM_VK_UP = 0x16, + DOM_VK_DOWN = 0x17, + DOM_VK_PAGE_DOWN = 0x18, + DOM_VK_PAGE_UP = 0x19, + DOM_VK_F1 = 0x1A, + DOM_VK_F2 = 0x1B, + DOM_VK_F3 = 0x1C, + DOM_VK_F4 = 0x1D, + DOM_VK_F5 = 0x1E, + DOM_VK_F6 = 0x1F, + DOM_VK_F7 = 0x20, + DOM_VK_F8 = 0x21, + DOM_VK_F9 = 0x22, + DOM_VK_F10 = 0x23, + DOM_VK_F11 = 0x24, + DOM_VK_F12 = 0x25, + DOM_VK_F13 = 0x26, + DOM_VK_F14 = 0x27, + DOM_VK_F15 = 0x28, + DOM_VK_F16 = 0x29, + DOM_VK_F17 = 0x2A, + DOM_VK_F18 = 0x2B, + DOM_VK_F19 = 0x2C, + DOM_VK_F20 = 0x2D, + DOM_VK_F21 = 0x2E, + DOM_VK_F22 = 0x2F, + DOM_VK_F23 = 0x30, + DOM_VK_F24 = 0x31 + }; + + + bool checkModifier(unsigned long modiferArg); + + void initKeyEvent(DOM::DOMString &typeArg, + bool canBubbleArg, + bool cancelableArg, + const DOM::AbstractView &viewArg, + long detailArg, + DOM::DOMString &outputStringArg, + unsigned long keyValArg, + unsigned long virtKeyValArg, + bool inputGeneratedArg, + bool numPadArg); + + void initModifier(unsigned long modifierArg, bool valueArg); + + bool inputGenerated() const; + + unsigned long keyVal() const; + + bool numPad() const { return m_numPad; } + DOM::DOMString outputString() const; + + unsigned long virtKeyVal() const { return m_virtKeyVal; } + + QKeyEvent *qKeyEvent; + +private: + unsigned long m_keyVal; + unsigned long m_virtKeyVal; + bool m_inputGenerated; + DOM::DOMString m_outputString; + bool m_numPad; + + // bitfield containing state of modifiers. not part of the dom. + unsigned long m_modifier; + +public: + KSVG_GET + + enum + { + // Properties + KeyVal, VirtKeyVal, OutputString, + // Functions + CheckModifier, GetKeyVal, GetCharCode + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +class SVGMutationEventImpl : public SVGEventImpl +{ +public: + SVGMutationEventImpl(); + SVGMutationEventImpl(SVGEvent::EventId _id, + bool canBubbleArg, + bool cancelableArg, + SVGElementImpl *relatedNodeArg, + const DOM::DOMString &prevValueArg, + const DOM::DOMString &newValueArg, + const DOM::DOMString &attrNameArg, + unsigned short attrChangeArg); + ~SVGMutationEventImpl(); + + SVGElementImpl *relatedNode() const; + DOM::DOMString prevValue() const; + DOM::DOMString newValue() const; + DOM::DOMString attrName() const; + unsigned short attrChange() const; + + void initMutationEvent(const DOM::DOMString &typeArg, + bool canBubbleArg, + bool cancelableArg, + SVGElementImpl *relatedNodeArg, + const DOM::DOMString &prevValueArg, + const DOM::DOMString &newValueArg, + const DOM::DOMString &attrNameArg, + unsigned short attrChangeArg); + + virtual bool isMutationEvent() { return true; } + virtual DOM::DOMString eventModuleName() { return "MutationEvents"; } + +protected: + SVGElementImpl *m_relatedNode; + DOM::DOMString m_prevValue; + DOM::DOMString m_newValue; + DOM::DOMString m_attrName; + unsigned short m_attrChange; + +public: + KSVG_FORWARDGET +}; + +class SVGRegisteredEventListener +{ +public: + SVGRegisteredEventListener(SVGEvent::EventId _id, SVGEventListener *_listener, bool _useCapture); + ~SVGRegisteredEventListener(); + + bool operator==(const SVGRegisteredEventListener &other); + + SVGEvent::EventId id; + SVGEventListener *listener; + bool useCapture; + +private: + SVGRegisteredEventListener(const SVGRegisteredEventListener &); + SVGRegisteredEventListener &operator=(const SVGRegisteredEventListener &); +}; + +} + +KSVG_DEFINE_PROTOTYPE(SVGEventImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGEventImplProtoFunc, SVGEventImpl) + +KSVG_DEFINE_PROTOTYPE(SVGUIEventImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGUIEventImplProtoFunc, SVGUIEventImpl) + +KSVG_DEFINE_PROTOTYPE(SVGMouseEventImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGMouseEventImplProtoFunc, SVGMouseEventImpl) + +KSVG_DEFINE_PROTOTYPE(SVGKeyEventImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGKeyEventImplProtoFunc, SVGKeyEventImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGExternalResourcesRequiredImpl.cc b/ksvg/impl/SVGExternalResourcesRequiredImpl.cc new file mode 100644 index 00000000..90fd9141 --- /dev/null +++ b/ksvg/impl/SVGExternalResourcesRequiredImpl.cc @@ -0,0 +1,88 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGAnimatedBooleanImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +using namespace KSVG; + +#include "SVGExternalResourcesRequiredImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGExternalResourcesRequiredImpl::SVGExternalResourcesRequiredImpl() +{ + KSVG_EMPTY_FLAGS + + m_externalResourcesRequired = new SVGAnimatedBooleanImpl(); + m_externalResourcesRequired->ref(); +} + +SVGExternalResourcesRequiredImpl::~SVGExternalResourcesRequiredImpl() +{ + if(m_externalResourcesRequired) + m_externalResourcesRequired->deref(); +} + +SVGAnimatedBooleanImpl *SVGExternalResourcesRequiredImpl::externalResourcesRequired() const +{ + return m_externalResourcesRequired; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGExternalResourcesRequiredImpl::s_hashTable 2 + externalResourcesRequired SVGExternalResourcesRequiredImpl::ExternalResourcesRequired DontDelete|ReadOnly +@end +*/ + +Value SVGExternalResourcesRequiredImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case ExternalResourcesRequired: + return m_externalResourcesRequired->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGExternalResourcesRequiredImpl::putValueProperty(ExecState *exec, int token, const KJS::Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + switch(token) + { + case ExternalResourcesRequired: + m_externalResourcesRequired->setBaseVal(value.toBoolean(exec)); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGExternalResourcesRequiredImpl.h b/ksvg/impl/SVGExternalResourcesRequiredImpl.h new file mode 100644 index 00000000..9c5b93eb --- /dev/null +++ b/ksvg/impl/SVGExternalResourcesRequiredImpl.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGExternalResourcesRequiredImpl_H +#define SVGExternalResourcesRequiredImpl_H + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedBooleanImpl; +class SVGExternalResourcesRequiredImpl +{ +public: + SVGExternalResourcesRequiredImpl(); + ~SVGExternalResourcesRequiredImpl(); + + SVGAnimatedBooleanImpl *externalResourcesRequired() const; + +private: + SVGAnimatedBooleanImpl *m_externalResourcesRequired; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + ExternalResourcesRequired + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEBlendElementImpl.cc b/ksvg/impl/SVGFEBlendElementImpl.cc new file mode 100644 index 00000000..8b29cad5 --- /dev/null +++ b/ksvg/impl/SVGFEBlendElementImpl.cc @@ -0,0 +1,64 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEBlendElementImpl.h" +#include "SVGAnimatedStringImpl.h" +#include "SVGAnimatedEnumerationImpl.h" + +using namespace KSVG; + +SVGFEBlendElementImpl::SVGFEBlendElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl() +{ + m_in1 = new SVGAnimatedStringImpl(); + m_in1->ref(); + + m_in2 = new SVGAnimatedStringImpl(); + m_in2->ref(); + + m_mode = new SVGAnimatedEnumerationImpl(); + m_mode->ref(); +} + +SVGFEBlendElementImpl::~SVGFEBlendElementImpl() +{ + if(m_in1) + m_in1->deref(); + if(m_in2) + m_in2->deref(); + if(m_mode) + m_mode->deref(); +} + +SVGAnimatedStringImpl *SVGFEBlendElementImpl::in1() const +{ + return m_in1; +} + +SVGAnimatedStringImpl *SVGFEBlendElementImpl::in2() const +{ + return m_in2; +} + +SVGAnimatedEnumerationImpl *SVGFEBlendElementImpl::mode() const +{ + return m_mode; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEBlendElementImpl.h b/ksvg/impl/SVGFEBlendElementImpl.h new file mode 100644 index 00000000..36aab059 --- /dev/null +++ b/ksvg/impl/SVGFEBlendElementImpl.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEBlendElementImpl_H +#define SVGFEBlendElementImpl_H + +#include "SVGElementImpl.h" +#include "SVGFilterPrimitiveStandardAttributesImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedStringImpl; +class SVGAnimatedEnumerationImpl; +class SVGFEBlendElementImpl : public SVGElementImpl, + public SVGFilterPrimitiveStandardAttributesImpl +{ +public: + SVGFEBlendElementImpl(DOM::ElementImpl *); + virtual ~SVGFEBlendElementImpl(); + + SVGAnimatedStringImpl *in1() const; + SVGAnimatedStringImpl *in2() const; + SVGAnimatedEnumerationImpl *mode() const; + +private: + SVGAnimatedStringImpl *m_in1; + SVGAnimatedStringImpl *m_in2; + SVGAnimatedEnumerationImpl *m_mode; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEColorMatrixElementImpl.cc b/ksvg/impl/SVGFEColorMatrixElementImpl.cc new file mode 100644 index 00000000..14c68a56 --- /dev/null +++ b/ksvg/impl/SVGFEColorMatrixElementImpl.cc @@ -0,0 +1,65 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedStringImpl.h" +#include "SVGAnimatedNumberListImpl.h" +#include "SVGAnimatedEnumerationImpl.h" +#include "SVGFEColorMatrixElementImpl.h" + +using namespace KSVG; + +SVGFEColorMatrixElementImpl::SVGFEColorMatrixElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl() +{ + m_in1 = new SVGAnimatedStringImpl(); + m_in1->ref(); + + m_type = new SVGAnimatedEnumerationImpl(); + m_type->ref(); + + m_values = new SVGAnimatedNumberListImpl(); + m_values->ref(); +} + +SVGFEColorMatrixElementImpl::~SVGFEColorMatrixElementImpl() +{ + if(m_in1) + m_in1->deref(); + if(m_type) + m_type->deref(); + if(m_values) + m_values->deref(); +} + +SVGAnimatedStringImpl *SVGFEColorMatrixElementImpl::in1() const +{ + return m_in1; +} + +SVGAnimatedEnumerationImpl *SVGFEColorMatrixElementImpl::type() const +{ + return m_type; +} + +SVGAnimatedNumberListImpl *SVGFEColorMatrixElementImpl::values() const +{ + return m_values; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEColorMatrixElementImpl.h b/ksvg/impl/SVGFEColorMatrixElementImpl.h new file mode 100644 index 00000000..b637690b --- /dev/null +++ b/ksvg/impl/SVGFEColorMatrixElementImpl.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEColorMatrixElementImpl_H +#define SVGFEColorMatrixElementImpl_H + +#include "SVGElementImpl.h" +#include "SVGFilterPrimitiveStandardAttributesImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedStringImpl; +class SVGAnimatedEnumerationImpl; +class SVGAnimatedNumberListImpl; +class SVGFEColorMatrixElementImpl : public SVGElementImpl, + public SVGFilterPrimitiveStandardAttributesImpl +{ +public: + SVGFEColorMatrixElementImpl(DOM::ElementImpl *); + virtual ~SVGFEColorMatrixElementImpl(); + + SVGAnimatedStringImpl *in1() const; + SVGAnimatedEnumerationImpl *type() const; + SVGAnimatedNumberListImpl *values() const; + +private: + SVGAnimatedStringImpl *m_in1; + SVGAnimatedEnumerationImpl *m_type; + SVGAnimatedNumberListImpl *m_values; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEComponentTransferElementImpl.cc b/ksvg/impl/SVGFEComponentTransferElementImpl.cc new file mode 100644 index 00000000..71ee4629 --- /dev/null +++ b/ksvg/impl/SVGFEComponentTransferElementImpl.cc @@ -0,0 +1,43 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedStringImpl.h" +#include "SVGFEComponentTransferElementImpl.h" + +using namespace KSVG; + +SVGFEComponentTransferElementImpl::SVGFEComponentTransferElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl() +{ + m_in1 = new SVGAnimatedStringImpl(); + m_in1->ref(); +} + +SVGFEComponentTransferElementImpl::~SVGFEComponentTransferElementImpl() +{ + if(m_in1) + m_in1->deref(); +} + +SVGAnimatedStringImpl *SVGFEComponentTransferElementImpl::in1() const +{ + return m_in1; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEComponentTransferElementImpl.h b/ksvg/impl/SVGFEComponentTransferElementImpl.h new file mode 100644 index 00000000..21c0fd88 --- /dev/null +++ b/ksvg/impl/SVGFEComponentTransferElementImpl.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEComponentTransferElementImpl_H +#define SVGFEComponentTransferElementImpl_H + +#include "SVGElementImpl.h" +#include "SVGFilterPrimitiveStandardAttributesImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedStringImpl; +class SVGFEComponentTransferElementImpl : public SVGElementImpl, + public SVGFilterPrimitiveStandardAttributesImpl +{ +public: + SVGFEComponentTransferElementImpl(DOM::ElementImpl *); + virtual ~SVGFEComponentTransferElementImpl(); + + SVGAnimatedStringImpl *in1() const; + +private: + SVGAnimatedStringImpl *m_in1; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFECompositeElementImpl.cc b/ksvg/impl/SVGFECompositeElementImpl.cc new file mode 100644 index 00000000..e8b91b95 --- /dev/null +++ b/ksvg/impl/SVGFECompositeElementImpl.cc @@ -0,0 +1,105 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedNumberImpl.h" +#include "SVGAnimatedStringImpl.h" +#include "SVGFECompositeElementImpl.h" +#include "SVGAnimatedEnumerationImpl.h" + +using namespace KSVG; + +SVGFECompositeElementImpl::SVGFECompositeElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl() +{ + m_in1 = new SVGAnimatedStringImpl(); + m_in1->ref(); + + m_in2 = new SVGAnimatedStringImpl(); + m_in2->ref(); + + m_operator = new SVGAnimatedEnumerationImpl(); + m_operator->ref(); + + m_k1 = new SVGAnimatedNumberImpl(); + m_k1->ref(); + + m_k2 = new SVGAnimatedNumberImpl(); + m_k2->ref(); + + m_k3 = new SVGAnimatedNumberImpl(); + m_k3->ref(); + + m_k4 = new SVGAnimatedNumberImpl(); + m_k4->ref(); +} + +SVGFECompositeElementImpl::~SVGFECompositeElementImpl() +{ + if(m_in1) + m_in1->deref(); + if(m_in2) + m_in2->deref(); + if(m_operator) + m_operator->deref(); + if(m_k1) + m_k1->deref(); + if(m_k2) + m_k2->deref(); + if(m_k3) + m_k3->deref(); + if(m_k4) + m_k4->deref(); +} + +SVGAnimatedStringImpl *SVGFECompositeElementImpl::in1() const +{ + return m_in1; +} + +SVGAnimatedStringImpl *SVGFECompositeElementImpl::in2() const +{ + return m_in2; +} + +SVGAnimatedEnumerationImpl *SVGFECompositeElementImpl::Operator() const +{ + return m_operator; +} + +SVGAnimatedNumberImpl *SVGFECompositeElementImpl::k1() const +{ + return m_k1; +} + +SVGAnimatedNumberImpl *SVGFECompositeElementImpl::k2() const +{ + return m_k2; +} + +SVGAnimatedNumberImpl *SVGFECompositeElementImpl::k3() const +{ + return m_k3; +} + +SVGAnimatedNumberImpl *SVGFECompositeElementImpl::k4() const +{ + return m_k4; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFECompositeElementImpl.h b/ksvg/impl/SVGFECompositeElementImpl.h new file mode 100644 index 00000000..10796ec1 --- /dev/null +++ b/ksvg/impl/SVGFECompositeElementImpl.h @@ -0,0 +1,68 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFECompositeElementImpl_H +#define SVGFECompositeElementImpl_H + +#include "SVGElementImpl.h" +#include "SVGFilterPrimitiveStandardAttributesImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedStringImpl; +class SVGAnimatedNumberImpl; +class SVGAnimatedEnumerationImpl; +class SVGFECompositeElementImpl : public SVGElementImpl, + public SVGFilterPrimitiveStandardAttributesImpl +{ +public: + SVGFECompositeElementImpl(DOM::ElementImpl *); + virtual ~SVGFECompositeElementImpl(); + + SVGAnimatedStringImpl *in1() const; + SVGAnimatedStringImpl *in2() const; + SVGAnimatedEnumerationImpl *Operator() const; + SVGAnimatedNumberImpl *k1() const; + SVGAnimatedNumberImpl *k2() const; + SVGAnimatedNumberImpl *k3() const; + SVGAnimatedNumberImpl *k4() const; + +private: + SVGAnimatedStringImpl *m_in1; + SVGAnimatedStringImpl *m_in2; + SVGAnimatedEnumerationImpl *m_operator; + SVGAnimatedNumberImpl *m_k1; + SVGAnimatedNumberImpl *m_k2; + SVGAnimatedNumberImpl *m_k3; + SVGAnimatedNumberImpl *m_k4; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEConvolveMatrixElementImpl.cc b/ksvg/impl/SVGFEConvolveMatrixElementImpl.cc new file mode 100644 index 00000000..88eb00ee --- /dev/null +++ b/ksvg/impl/SVGFEConvolveMatrixElementImpl.cc @@ -0,0 +1,149 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedNumberImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGAnimatedIntegerImpl.h" +#include "SVGAnimatedBooleanImpl.h" +#include "SVGAnimatedIntegerImpl.h" +#include "SVGAnimatedNumberListImpl.h" +#include "SVGAnimatedEnumerationImpl.h" +#include "SVGFEConvolveMatrixElementImpl.h" + +using namespace KSVG; + +SVGFEConvolveMatrixElementImpl::SVGFEConvolveMatrixElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl() +{ + m_orderX = new SVGAnimatedIntegerImpl(); + m_orderX->ref(); + + m_orderY = new SVGAnimatedIntegerImpl(); + m_orderY->ref(); + + m_kernelMatrix = new SVGAnimatedNumberListImpl(); + m_kernelMatrix->ref(); + + m_divisor = new SVGAnimatedNumberImpl(); + m_divisor->ref(); + + m_bias = new SVGAnimatedNumberImpl(); + m_bias->ref(); + + m_targetX = new SVGAnimatedIntegerImpl(); + m_targetX->ref(); + + m_targetY = new SVGAnimatedIntegerImpl(); + m_targetY->ref(); + + m_edgeMode = new SVGAnimatedEnumerationImpl(); + m_edgeMode->ref(); + + m_kernelUnitLengthX = new SVGAnimatedLengthImpl(); + m_kernelUnitLengthX->ref(); + + m_kernelUnitLengthY = new SVGAnimatedLengthImpl(); + m_kernelUnitLengthY->ref(); + + m_preserveAlpha = new SVGAnimatedBooleanImpl(); + m_preserveAlpha->ref(); +} + +SVGFEConvolveMatrixElementImpl::~SVGFEConvolveMatrixElementImpl() +{ + if(m_orderX) + m_orderX->deref(); + if(m_orderY) + m_orderY->deref(); + if(m_kernelMatrix) + m_kernelMatrix->deref(); + if(m_divisor) + m_divisor->deref(); + if(m_bias) + m_bias->deref(); + if(m_targetX) + m_targetX->deref(); + if(m_targetY) + m_targetY->deref(); + if(m_edgeMode) + m_edgeMode->deref(); + if(m_kernelUnitLengthX) + m_kernelUnitLengthX->deref(); + if(m_kernelUnitLengthY) + m_kernelUnitLengthY->deref(); + if(m_preserveAlpha) + m_preserveAlpha->deref(); +} + +SVGAnimatedIntegerImpl *SVGFEConvolveMatrixElementImpl::orderX() const +{ + return m_orderX; +} + +SVGAnimatedIntegerImpl *SVGFEConvolveMatrixElementImpl::orderY() const +{ + return m_orderY; +} + +SVGAnimatedNumberListImpl *SVGFEConvolveMatrixElementImpl::kernelMatrix() const +{ + return m_kernelMatrix; +} + +SVGAnimatedNumberImpl *SVGFEConvolveMatrixElementImpl::divisor() const +{ + return m_divisor; +} + +SVGAnimatedNumberImpl *SVGFEConvolveMatrixElementImpl::bias() const +{ + return m_bias; +} + +SVGAnimatedIntegerImpl *SVGFEConvolveMatrixElementImpl::targetX() const +{ + return m_targetX; +} + +SVGAnimatedIntegerImpl *SVGFEConvolveMatrixElementImpl::targetY() const +{ + return m_targetY; +} + +SVGAnimatedEnumerationImpl *SVGFEConvolveMatrixElementImpl::edgeMode() const +{ + return m_edgeMode; +} + +SVGAnimatedLengthImpl *SVGFEConvolveMatrixElementImpl::kernelUnitLengthX() const +{ + return m_kernelUnitLengthX; +} + +SVGAnimatedLengthImpl *SVGFEConvolveMatrixElementImpl::kernelUnitLengthY() const +{ + return m_kernelUnitLengthY; +} + +SVGAnimatedBooleanImpl *SVGFEConvolveMatrixElementImpl::preserveAlpha() const +{ + return m_preserveAlpha; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEConvolveMatrixElementImpl.h b/ksvg/impl/SVGFEConvolveMatrixElementImpl.h new file mode 100644 index 00000000..e26518d5 --- /dev/null +++ b/ksvg/impl/SVGFEConvolveMatrixElementImpl.h @@ -0,0 +1,80 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEConvolveMatrixElementImpl_H +#define SVGFEConvolveMatrixElementImpl_H + +#include "SVGElementImpl.h" +#include "SVGFilterPrimitiveStandardAttributesImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedNumberImpl; +class SVGAnimatedLengthImpl; +class SVGAnimatedIntegerImpl; +class SVGAnimatedIntegerImpl; +class SVGAnimatedBooleanImpl; +class SVGAnimatedNumberListImpl; +class SVGAnimatedEnumerationImpl; +class SVGFEConvolveMatrixElementImpl : public SVGElementImpl, + public SVGFilterPrimitiveStandardAttributesImpl +{ +public: + SVGFEConvolveMatrixElementImpl(DOM::ElementImpl *); + virtual ~SVGFEConvolveMatrixElementImpl(); + + SVGAnimatedIntegerImpl *orderX() const; + SVGAnimatedIntegerImpl *orderY() const; + SVGAnimatedNumberListImpl *kernelMatrix() const; + SVGAnimatedNumberImpl *divisor() const; + SVGAnimatedNumberImpl *bias() const; + SVGAnimatedIntegerImpl *targetX() const; + SVGAnimatedIntegerImpl *targetY() const; + SVGAnimatedEnumerationImpl *edgeMode() const; + SVGAnimatedLengthImpl *kernelUnitLengthX() const; + SVGAnimatedLengthImpl *kernelUnitLengthY() const; + SVGAnimatedBooleanImpl *preserveAlpha() const; + +private: + SVGAnimatedIntegerImpl *m_orderX; + SVGAnimatedIntegerImpl *m_orderY; + SVGAnimatedNumberListImpl *m_kernelMatrix; + SVGAnimatedNumberImpl *m_divisor; + SVGAnimatedNumberImpl *m_bias; + SVGAnimatedIntegerImpl *m_targetX; + SVGAnimatedIntegerImpl *m_targetY; + SVGAnimatedEnumerationImpl *m_edgeMode; + SVGAnimatedLengthImpl *m_kernelUnitLengthX; + SVGAnimatedLengthImpl *m_kernelUnitLengthY; + SVGAnimatedBooleanImpl *m_preserveAlpha; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEDiffuseLightingElementImpl.cc b/ksvg/impl/SVGFEDiffuseLightingElementImpl.cc new file mode 100644 index 00000000..0b5c2565 --- /dev/null +++ b/ksvg/impl/SVGFEDiffuseLightingElementImpl.cc @@ -0,0 +1,64 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedStringImpl.h" +#include "SVGAnimatedNumberImpl.h" +#include "SVGFEDiffuseLightingElementImpl.h" + +using namespace KSVG; + +SVGFEDiffuseLightingElementImpl::SVGFEDiffuseLightingElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl() +{ + m_in1 = new SVGAnimatedStringImpl(); + m_in1->ref(); + + m_surfaceScale = new SVGAnimatedNumberImpl(); + m_surfaceScale->ref(); + + m_diffuseConstant = new SVGAnimatedNumberImpl(); + m_diffuseConstant->ref(); +} + +SVGFEDiffuseLightingElementImpl::~SVGFEDiffuseLightingElementImpl() +{ + if(m_in1) + m_in1->deref(); + if(m_surfaceScale) + m_surfaceScale->deref(); + if(m_diffuseConstant) + m_diffuseConstant->deref(); +} + +SVGAnimatedStringImpl *SVGFEDiffuseLightingElementImpl::in1() const +{ + return m_in1; +} + +SVGAnimatedNumberImpl *SVGFEDiffuseLightingElementImpl::surfaceScale() const +{ + return m_surfaceScale; +} + +SVGAnimatedNumberImpl *SVGFEDiffuseLightingElementImpl::diffuseConstant() const +{ + return m_diffuseConstant; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEDiffuseLightingElementImpl.h b/ksvg/impl/SVGFEDiffuseLightingElementImpl.h new file mode 100644 index 00000000..0be4f7f1 --- /dev/null +++ b/ksvg/impl/SVGFEDiffuseLightingElementImpl.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEDiffuseLightingElementImpl_H +#define SVGFEDiffuseLightingElementImpl_H + +#include "SVGElementImpl.h" +#include "SVGFilterPrimitiveStandardAttributesImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedStringImpl; +class SVGAnimatedNumberImpl; +class SVGFEDiffuseLightingElementImpl : public SVGElementImpl, + public SVGFilterPrimitiveStandardAttributesImpl +{ +public: + SVGFEDiffuseLightingElementImpl(DOM::ElementImpl *); + virtual ~SVGFEDiffuseLightingElementImpl(); + + SVGAnimatedStringImpl *in1() const; + SVGAnimatedNumberImpl *surfaceScale() const; + SVGAnimatedNumberImpl *diffuseConstant() const; + +private: + SVGAnimatedStringImpl *m_in1; + SVGAnimatedNumberImpl *m_surfaceScale; + SVGAnimatedNumberImpl *m_diffuseConstant; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEDisplacementMapElementImpl.cc b/ksvg/impl/SVGFEDisplacementMapElementImpl.cc new file mode 100644 index 00000000..92665ec7 --- /dev/null +++ b/ksvg/impl/SVGFEDisplacementMapElementImpl.cc @@ -0,0 +1,85 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedStringImpl.h" +#include "SVGAnimatedNumberImpl.h" +#include "SVGAnimatedEnumerationImpl.h" +#include "SVGFEDisplacementMapElementImpl.h" + +using namespace KSVG; + +SVGFEDisplacementMapElementImpl::SVGFEDisplacementMapElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl() +{ + m_in1 = new SVGAnimatedStringImpl(); + m_in1->ref(); + + m_in2 = new SVGAnimatedStringImpl(); + m_in2->ref(); + + m_scale = new SVGAnimatedNumberImpl(); + m_scale->ref(); + + m_xChannelSelector = new SVGAnimatedEnumerationImpl(); + m_xChannelSelector->ref(); + + m_yChannelSelector = new SVGAnimatedEnumerationImpl(); + m_yChannelSelector->ref(); +} + +SVGFEDisplacementMapElementImpl::~SVGFEDisplacementMapElementImpl() +{ + if(m_in1) + m_in1->deref(); + if(m_in2) + m_in2->deref(); + if(m_scale) + m_scale->deref(); + if(m_xChannelSelector) + m_xChannelSelector->deref(); + if(m_yChannelSelector) + m_yChannelSelector->deref(); +} + +SVGAnimatedStringImpl *SVGFEDisplacementMapElementImpl::in1() const +{ + return m_in1; +} + +SVGAnimatedStringImpl *SVGFEDisplacementMapElementImpl::in2() const +{ + return m_in2; +} + +SVGAnimatedNumberImpl *SVGFEDisplacementMapElementImpl::scale() const +{ + return m_scale; +} + +SVGAnimatedEnumerationImpl *SVGFEDisplacementMapElementImpl::xChannelSelector() const +{ + return m_xChannelSelector; +} + +SVGAnimatedEnumerationImpl *SVGFEDisplacementMapElementImpl::yChannelSelector() const +{ + return m_yChannelSelector; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEDisplacementMapElementImpl.h b/ksvg/impl/SVGFEDisplacementMapElementImpl.h new file mode 100644 index 00000000..3774b6cc --- /dev/null +++ b/ksvg/impl/SVGFEDisplacementMapElementImpl.h @@ -0,0 +1,64 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEDisplacementMapElementImpl_H +#define SVGFEDisplacementMapElementImpl_H + +#include "SVGElementImpl.h" +#include "SVGFilterPrimitiveStandardAttributesImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedStringImpl; +class SVGAnimatedNumberImpl; +class SVGAnimatedEnumerationImpl; +class SVGFEDisplacementMapElementImpl : public SVGElementImpl, + public SVGFilterPrimitiveStandardAttributesImpl +{ +public: + SVGFEDisplacementMapElementImpl(DOM::ElementImpl *); + virtual ~SVGFEDisplacementMapElementImpl(); + + SVGAnimatedStringImpl *in1() const; + SVGAnimatedStringImpl *in2() const; + SVGAnimatedNumberImpl *scale() const; + SVGAnimatedEnumerationImpl *xChannelSelector() const; + SVGAnimatedEnumerationImpl *yChannelSelector() const; + +private: + SVGAnimatedStringImpl *m_in1; + SVGAnimatedStringImpl *m_in2; + SVGAnimatedNumberImpl *m_scale; + SVGAnimatedEnumerationImpl *m_xChannelSelector; + SVGAnimatedEnumerationImpl *m_yChannelSelector; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEDistantLightElementImpl.cc b/ksvg/impl/SVGFEDistantLightElementImpl.cc new file mode 100644 index 00000000..b40885e0 --- /dev/null +++ b/ksvg/impl/SVGFEDistantLightElementImpl.cc @@ -0,0 +1,53 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedNumberImpl.h" +#include "SVGFEDistantLightElementImpl.h" + +using namespace KSVG; + +SVGFEDistantLightElementImpl::SVGFEDistantLightElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl) +{ + m_azimuth = new SVGAnimatedNumberImpl(); + m_azimuth->ref(); + + m_elevation = new SVGAnimatedNumberImpl(); + m_elevation->ref(); +} + +SVGFEDistantLightElementImpl::~SVGFEDistantLightElementImpl() +{ + if(m_azimuth) + m_azimuth->deref(); + if(m_elevation) + m_elevation->deref(); +} + +SVGAnimatedNumberImpl *SVGFEDistantLightElementImpl::azimuth() const +{ + return m_azimuth; +} + +SVGAnimatedNumberImpl *SVGFEDistantLightElementImpl::elevation() const +{ + return m_elevation; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEDistantLightElementImpl.h b/ksvg/impl/SVGFEDistantLightElementImpl.h new file mode 100644 index 00000000..4d995a44 --- /dev/null +++ b/ksvg/impl/SVGFEDistantLightElementImpl.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEDistantLightElementImpl_H +#define SVGFEDistantLightElementImpl_H + +#include "SVGElementImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedNumberImpl; +class SVGFEDistantLightElementImpl : public SVGElementImpl +{ +public: + SVGFEDistantLightElementImpl(DOM::ElementImpl *); + virtual ~SVGFEDistantLightElementImpl(); + + SVGAnimatedNumberImpl *azimuth() const; + SVGAnimatedNumberImpl *elevation() const; + +private: + SVGAnimatedNumberImpl *m_azimuth; + SVGAnimatedNumberImpl *m_elevation; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEFloodElementImpl.cc b/ksvg/impl/SVGFEFloodElementImpl.cc new file mode 100644 index 00000000..7cbecafd --- /dev/null +++ b/ksvg/impl/SVGFEFloodElementImpl.cc @@ -0,0 +1,43 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEFloodElementImpl.h" +#include "SVGAnimatedStringImpl.h" + +using namespace KSVG; + +SVGFEFloodElementImpl::SVGFEFloodElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGStylableImpl(this), SVGFilterPrimitiveStandardAttributesImpl() +{ + m_in1 = new SVGAnimatedStringImpl(); + m_in1->ref(); +} + +SVGFEFloodElementImpl::~SVGFEFloodElementImpl() +{ + if(m_in1) + m_in1->deref(); +} + +SVGAnimatedStringImpl *SVGFEFloodElementImpl::in1() const +{ + return m_in1; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEFloodElementImpl.h b/ksvg/impl/SVGFEFloodElementImpl.h new file mode 100644 index 00000000..858959a9 --- /dev/null +++ b/ksvg/impl/SVGFEFloodElementImpl.h @@ -0,0 +1,56 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEFloodElementImpl_H +#define SVGFEFloodElementImpl_H + +#include "SVGElementImpl.h" +#include "SVGStylableImpl.h" +#include "SVGFilterPrimitiveStandardAttributesImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedStringImpl; +class SVGFEFloodElementImpl : public SVGElementImpl, + public SVGStylableImpl, + public SVGFilterPrimitiveStandardAttributesImpl +{ +public: + SVGFEFloodElementImpl(DOM::ElementImpl *); + virtual ~SVGFEFloodElementImpl(); + + SVGAnimatedStringImpl *in1() const; + +private: + SVGAnimatedStringImpl *m_in1; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEFuncAElementImpl.cc b/ksvg/impl/SVGFEFuncAElementImpl.cc new file mode 100644 index 00000000..c7a535fa --- /dev/null +++ b/ksvg/impl/SVGFEFuncAElementImpl.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEFuncAElementImpl.h" + +using namespace KSVG; + +SVGFEFuncAElementImpl::SVGFEFuncAElementImpl(DOM::ElementImpl *impl) : SVGComponentTransferFunctionElementImpl(impl) +{ +} + +SVGFEFuncAElementImpl::~SVGFEFuncAElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEFuncAElementImpl.h b/ksvg/impl/SVGFEFuncAElementImpl.h new file mode 100644 index 00000000..7999c7e2 --- /dev/null +++ b/ksvg/impl/SVGFEFuncAElementImpl.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEFuncAElementImpl_H +#define SVGFEFuncAElementImpl_H + +#include "SVGComponentTransferFunctionElementImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGFEFuncAElementImpl : public SVGComponentTransferFunctionElementImpl +{ +public: + SVGFEFuncAElementImpl(DOM::ElementImpl *); + virtual ~SVGFEFuncAElementImpl(); + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEFuncBElementImpl.cc b/ksvg/impl/SVGFEFuncBElementImpl.cc new file mode 100644 index 00000000..4b0bbf71 --- /dev/null +++ b/ksvg/impl/SVGFEFuncBElementImpl.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEFuncBElementImpl.h" + +using namespace KSVG; + +SVGFEFuncBElementImpl::SVGFEFuncBElementImpl(DOM::ElementImpl *impl) : SVGComponentTransferFunctionElementImpl(impl) +{ +} + +SVGFEFuncBElementImpl::~SVGFEFuncBElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEFuncBElementImpl.h b/ksvg/impl/SVGFEFuncBElementImpl.h new file mode 100644 index 00000000..7236debb --- /dev/null +++ b/ksvg/impl/SVGFEFuncBElementImpl.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEFuncBElementImpl_H +#define SVGFEFuncBElementImpl_H + +#include "SVGComponentTransferFunctionElementImpl.h" +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGFEFuncBElementImpl : public SVGComponentTransferFunctionElementImpl +{ +public: + SVGFEFuncBElementImpl(DOM::ElementImpl *); + virtual ~SVGFEFuncBElementImpl(); + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEFuncGElementImpl.cc b/ksvg/impl/SVGFEFuncGElementImpl.cc new file mode 100644 index 00000000..8a60fbee --- /dev/null +++ b/ksvg/impl/SVGFEFuncGElementImpl.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEFuncGElementImpl.h" + +using namespace KSVG; + +SVGFEFuncGElementImpl::SVGFEFuncGElementImpl(DOM::ElementImpl *impl) : SVGComponentTransferFunctionElementImpl(impl) +{ +} + +SVGFEFuncGElementImpl::~SVGFEFuncGElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEFuncGElementImpl.h b/ksvg/impl/SVGFEFuncGElementImpl.h new file mode 100644 index 00000000..44baec8d --- /dev/null +++ b/ksvg/impl/SVGFEFuncGElementImpl.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEFuncGElementImpl_H +#define SVGFEFuncGElementImpl_H + +#include "SVGComponentTransferFunctionElementImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGFEFuncGElementImpl : public SVGComponentTransferFunctionElementImpl +{ +public: + SVGFEFuncGElementImpl(DOM::ElementImpl *); + virtual ~SVGFEFuncGElementImpl(); + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEFuncRElementImpl.cc b/ksvg/impl/SVGFEFuncRElementImpl.cc new file mode 100644 index 00000000..fe1b2d44 --- /dev/null +++ b/ksvg/impl/SVGFEFuncRElementImpl.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEFuncRElementImpl.h" + +using namespace KSVG; + +SVGFEFuncRElementImpl::SVGFEFuncRElementImpl(DOM::ElementImpl *impl) : SVGComponentTransferFunctionElementImpl(impl) +{ +} + +SVGFEFuncRElementImpl::~SVGFEFuncRElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEFuncRElementImpl.h b/ksvg/impl/SVGFEFuncRElementImpl.h new file mode 100644 index 00000000..17aa7812 --- /dev/null +++ b/ksvg/impl/SVGFEFuncRElementImpl.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEFuncRElementImpl_H +#define SVGFEFuncRElementImpl_H + +#include "SVGComponentTransferFunctionElementImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGFEFuncRElementImpl : public SVGComponentTransferFunctionElementImpl +{ +public: + SVGFEFuncRElementImpl(DOM::ElementImpl *); + virtual ~SVGFEFuncRElementImpl(); + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEGaussianBlurElementImpl.cc b/ksvg/impl/SVGFEGaussianBlurElementImpl.cc new file mode 100644 index 00000000..bcc2e0bf --- /dev/null +++ b/ksvg/impl/SVGFEGaussianBlurElementImpl.cc @@ -0,0 +1,68 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedStringImpl.h" +#include "SVGAnimatedNumberImpl.h" +#include "SVGFEGaussianBlurElementImpl.h" + +using namespace KSVG; + +SVGFEGaussianBlurElementImpl::SVGFEGaussianBlurElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl() +{ + m_in1 = new SVGAnimatedStringImpl(); + m_in1->ref(); + + m_stdDeviationX = new SVGAnimatedNumberImpl(); + m_stdDeviationX->ref(); + + m_stdDeviationY = new SVGAnimatedNumberImpl(); + m_stdDeviationY->ref(); +} + +SVGFEGaussianBlurElementImpl::~SVGFEGaussianBlurElementImpl() +{ + if(m_in1) + m_in1->deref(); + if(m_stdDeviationX) + m_stdDeviationX->deref(); + if(m_stdDeviationY) + m_stdDeviationY->deref(); +} + +SVGAnimatedStringImpl *SVGFEGaussianBlurElementImpl::in1() const +{ + return m_in1; +} + +SVGAnimatedNumberImpl *SVGFEGaussianBlurElementImpl::stdDeviationX() const +{ + return m_stdDeviationX; +} + +SVGAnimatedNumberImpl *SVGFEGaussianBlurElementImpl::stdDeviationY() const +{ + return m_stdDeviationY; +} + +void SVGFEGaussianBlurElementImpl::setStdDeviation(float /*stdDeviationX*/, float /*stdDeviationY*/) +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEGaussianBlurElementImpl.h b/ksvg/impl/SVGFEGaussianBlurElementImpl.h new file mode 100644 index 00000000..97707edb --- /dev/null +++ b/ksvg/impl/SVGFEGaussianBlurElementImpl.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEGaussianBlurElementImpl_H +#define SVGFEGaussianBlurElementImpl_H + +#include "SVGElementImpl.h" +#include "SVGFilterPrimitiveStandardAttributesImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedStringImpl; +class SVGAnimatedNumberImpl; +class SVGFEGaussianBlurElementImpl : public SVGElementImpl, + public SVGFilterPrimitiveStandardAttributesImpl +{ +public: + SVGFEGaussianBlurElementImpl(DOM::ElementImpl *); + virtual ~SVGFEGaussianBlurElementImpl(); + + SVGAnimatedStringImpl *in1() const; + SVGAnimatedNumberImpl *stdDeviationX() const; + SVGAnimatedNumberImpl *stdDeviationY() const; + void setStdDeviation(float stdDeviationX, float stdDeviationY); + +private: + SVGAnimatedStringImpl *m_in1; + SVGAnimatedNumberImpl *m_stdDeviationX; + SVGAnimatedNumberImpl *m_stdDeviationY; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEImageElementImpl.cc b/ksvg/impl/SVGFEImageElementImpl.cc new file mode 100644 index 00000000..f41e482d --- /dev/null +++ b/ksvg/impl/SVGFEImageElementImpl.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEImageElementImpl.h" + +using namespace KSVG; + +SVGFEImageElementImpl::SVGFEImageElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGURIReferenceImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGFilterPrimitiveStandardAttributesImpl() +{ +} + +SVGFEImageElementImpl::~SVGFEImageElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEImageElementImpl.h b/ksvg/impl/SVGFEImageElementImpl.h new file mode 100644 index 00000000..3d03e77d --- /dev/null +++ b/ksvg/impl/SVGFEImageElementImpl.h @@ -0,0 +1,56 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEImageElementImpl_H +#define SVGFEImageElementImpl_H + +#include "SVGElementImpl.h" +#include "SVGStylableImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGURIReferenceImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" +#include "SVGFilterPrimitiveStandardAttributesImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGFEImageElementImpl : public SVGElementImpl, + public SVGURIReferenceImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGFilterPrimitiveStandardAttributesImpl +{ +public: + SVGFEImageElementImpl(DOM::ElementImpl *); + virtual ~SVGFEImageElementImpl(); + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEMergeElementImpl.cc b/ksvg/impl/SVGFEMergeElementImpl.cc new file mode 100644 index 00000000..6eca907a --- /dev/null +++ b/ksvg/impl/SVGFEMergeElementImpl.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFEMergeElementImpl.h" + +using namespace KSVG; + +SVGFEMergeElementImpl::SVGFEMergeElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl() +{ +} + +SVGFEMergeElementImpl::~SVGFEMergeElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEMergeElementImpl.h b/ksvg/impl/SVGFEMergeElementImpl.h new file mode 100644 index 00000000..f4b6aaaf --- /dev/null +++ b/ksvg/impl/SVGFEMergeElementImpl.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEMergeElementImpl_H +#define SVGFEMergeElementImpl_H + +#include "SVGElementImpl.h" +#include "SVGFilterPrimitiveStandardAttributesImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGFEMergeElementImpl : public SVGElementImpl, + public SVGFilterPrimitiveStandardAttributesImpl +{ +public: + SVGFEMergeElementImpl(DOM::ElementImpl *); + virtual ~SVGFEMergeElementImpl(); + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEMergeNodeElementImpl.cc b/ksvg/impl/SVGFEMergeNodeElementImpl.cc new file mode 100644 index 00000000..1191df3b --- /dev/null +++ b/ksvg/impl/SVGFEMergeNodeElementImpl.cc @@ -0,0 +1,43 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedStringImpl.h" +#include "SVGFEMergeNodeElementImpl.h" + +using namespace KSVG; + +SVGFEMergeNodeElementImpl::SVGFEMergeNodeElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl) +{ + m_in1 = new SVGAnimatedStringImpl(); + m_in1->ref(); +} + +SVGFEMergeNodeElementImpl::~SVGFEMergeNodeElementImpl() +{ + if(m_in1) + m_in1->deref(); +} + +SVGAnimatedStringImpl *SVGFEMergeNodeElementImpl::in1() const +{ + return m_in1; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEMergeNodeElementImpl.h b/ksvg/impl/SVGFEMergeNodeElementImpl.h new file mode 100644 index 00000000..5b380757 --- /dev/null +++ b/ksvg/impl/SVGFEMergeNodeElementImpl.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEMergeNodeElementImpl_H +#define SVGFEMergeNodeElementImpl_H + +#include "SVGElementImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedStringImpl; +class SVGFEMergeNodeElementImpl : public SVGElementImpl +{ +public: + SVGFEMergeNodeElementImpl(DOM::ElementImpl *); + virtual ~SVGFEMergeNodeElementImpl(); + + SVGAnimatedStringImpl *in1() const; + +private: + SVGAnimatedStringImpl *m_in1; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEMorphologyElementImpl.cc b/ksvg/impl/SVGFEMorphologyElementImpl.cc new file mode 100644 index 00000000..e7f1a100 --- /dev/null +++ b/ksvg/impl/SVGFEMorphologyElementImpl.cc @@ -0,0 +1,75 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedStringImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGAnimatedEnumerationImpl.h" +#include "SVGFEMorphologyElementImpl.h" + +using namespace KSVG; + +SVGFEMorphologyElementImpl::SVGFEMorphologyElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl() +{ + m_in1 = new SVGAnimatedStringImpl(); + m_in1->ref(); + + m_operator = new SVGAnimatedEnumerationImpl(); + m_operator->ref(); + + m_radiusX = new SVGAnimatedLengthImpl(); + m_radiusX->ref(); + + m_radiusY = new SVGAnimatedLengthImpl(); + m_radiusY->ref(); +} + +SVGFEMorphologyElementImpl::~SVGFEMorphologyElementImpl() +{ + if(m_in1) + m_in1->deref(); + if(m_operator) + m_operator->deref(); + if(m_radiusX) + m_radiusX->deref(); + if(m_radiusY) + m_radiusY->deref(); +} + +SVGAnimatedStringImpl *SVGFEMorphologyElementImpl::in1() const +{ + return m_in1; +} + +SVGAnimatedEnumerationImpl *SVGFEMorphologyElementImpl::Operator() const +{ + return m_operator; +} + +SVGAnimatedLengthImpl *SVGFEMorphologyElementImpl::radiusX() const +{ + return m_radiusX; +} + +SVGAnimatedLengthImpl *SVGFEMorphologyElementImpl::radiusY() const +{ + return m_radiusY; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEMorphologyElementImpl.h b/ksvg/impl/SVGFEMorphologyElementImpl.h new file mode 100644 index 00000000..7941e772 --- /dev/null +++ b/ksvg/impl/SVGFEMorphologyElementImpl.h @@ -0,0 +1,62 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEMorphologyElementImpl_H +#define SVGFEMorphologyElementImpl_H + +#include "SVGElementImpl.h" +#include "SVGFilterPrimitiveStandardAttributesImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedStringImpl; +class SVGAnimatedLengthImpl; +class SVGAnimatedEnumerationImpl; +class SVGFEMorphologyElementImpl : public SVGElementImpl, + public SVGFilterPrimitiveStandardAttributesImpl +{ +public: + SVGFEMorphologyElementImpl(DOM::ElementImpl *impl); + virtual ~SVGFEMorphologyElementImpl(); + + SVGAnimatedStringImpl *in1() const; + SVGAnimatedEnumerationImpl *Operator() const; + SVGAnimatedLengthImpl *radiusX() const; + SVGAnimatedLengthImpl *radiusY() const; + +private: + SVGAnimatedStringImpl *m_in1; + SVGAnimatedEnumerationImpl *m_operator; + SVGAnimatedLengthImpl *m_radiusX; + SVGAnimatedLengthImpl *m_radiusY; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEOffsetElementImpl.cc b/ksvg/impl/SVGFEOffsetElementImpl.cc new file mode 100644 index 00000000..8c8bfbeb --- /dev/null +++ b/ksvg/impl/SVGFEOffsetElementImpl.cc @@ -0,0 +1,64 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedStringImpl.h" +#include "SVGAnimatedNumberImpl.h" +#include "SVGFEOffsetElementImpl.h" + +using namespace KSVG; + +SVGFEOffsetElementImpl::SVGFEOffsetElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl() +{ + m_in1 = new SVGAnimatedStringImpl(); + m_in1->ref(); + + m_dx = new SVGAnimatedNumberImpl(); + m_dx->ref(); + + m_dy = new SVGAnimatedNumberImpl(); + m_dy->ref(); +} + +SVGFEOffsetElementImpl::~SVGFEOffsetElementImpl() +{ + if(m_in1) + m_in1->deref(); + if(m_dx) + m_dx->deref(); + if(m_dy) + m_dy->deref(); +} + +SVGAnimatedStringImpl *SVGFEOffsetElementImpl::in1() const +{ + return m_in1; +} + +SVGAnimatedNumberImpl *SVGFEOffsetElementImpl::dx() const +{ + return m_dx; +} + +SVGAnimatedNumberImpl *SVGFEOffsetElementImpl::dy() const +{ + return m_dy; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEOffsetElementImpl.h b/ksvg/impl/SVGFEOffsetElementImpl.h new file mode 100644 index 00000000..e8c3448a --- /dev/null +++ b/ksvg/impl/SVGFEOffsetElementImpl.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEOffsetElementImpl_H +#define SVGFEOffsetElementImpl_H + +#include "SVGElementImpl.h" +#include "SVGFilterPrimitiveStandardAttributesImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedStringImpl; +class SVGAnimatedNumberImpl; +class SVGFEOffsetElementImpl : public SVGElementImpl, + public SVGFilterPrimitiveStandardAttributesImpl +{ +public: + SVGFEOffsetElementImpl(DOM::ElementImpl *impl); + virtual ~SVGFEOffsetElementImpl(); + + SVGAnimatedStringImpl *in1() const; + SVGAnimatedNumberImpl *dx() const; + SVGAnimatedNumberImpl *dy() const; + +private: + SVGAnimatedStringImpl *m_in1; + SVGAnimatedNumberImpl *m_dx; + SVGAnimatedNumberImpl *m_dy; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEPointLightElementImpl.cc b/ksvg/impl/SVGFEPointLightElementImpl.cc new file mode 100644 index 00000000..ad95d20a --- /dev/null +++ b/ksvg/impl/SVGFEPointLightElementImpl.cc @@ -0,0 +1,63 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedNumberImpl.h" +#include "SVGFEPointLightElementImpl.h" + +using namespace KSVG; + +SVGFEPointLightElementImpl::SVGFEPointLightElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl) +{ + m_x = new SVGAnimatedNumberImpl(); + m_x->ref(); + + m_y = new SVGAnimatedNumberImpl(); + m_y->ref(); + + m_z = new SVGAnimatedNumberImpl(); + m_z->ref(); +} + +SVGFEPointLightElementImpl::~SVGFEPointLightElementImpl() +{ + if(m_x) + m_x->deref(); + if(m_y) + m_y->deref(); + if(m_z) + m_z->deref(); +} + +SVGAnimatedNumberImpl *SVGFEPointLightElementImpl::x() const +{ + return m_x; +} + +SVGAnimatedNumberImpl *SVGFEPointLightElementImpl::y() const +{ + return m_y; +} + +SVGAnimatedNumberImpl *SVGFEPointLightElementImpl::z() const +{ + return m_z; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFEPointLightElementImpl.h b/ksvg/impl/SVGFEPointLightElementImpl.h new file mode 100644 index 00000000..6d66c98b --- /dev/null +++ b/ksvg/impl/SVGFEPointLightElementImpl.h @@ -0,0 +1,56 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFEPointLightElementImpl_H +#define SVGFEPointLightElementImpl_H + +#include "SVGElementImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedNumberImpl; +class SVGFEPointLightElementImpl : public SVGElementImpl +{ +public: + SVGFEPointLightElementImpl(DOM::ElementImpl *); + virtual ~SVGFEPointLightElementImpl(); + + SVGAnimatedNumberImpl *x() const; + SVGAnimatedNumberImpl *y() const; + SVGAnimatedNumberImpl *z() const; + +private: + SVGAnimatedNumberImpl *m_x; + SVGAnimatedNumberImpl *m_y; + SVGAnimatedNumberImpl *m_z; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFESpecularLightingElementImpl.cc b/ksvg/impl/SVGFESpecularLightingElementImpl.cc new file mode 100644 index 00000000..9974e146 --- /dev/null +++ b/ksvg/impl/SVGFESpecularLightingElementImpl.cc @@ -0,0 +1,74 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedStringImpl.h" +#include "SVGAnimatedNumberImpl.h" +#include "SVGFESpecularLightingElementImpl.h" + +using namespace KSVG; + +SVGFESpecularLightingElementImpl::SVGFESpecularLightingElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl() +{ + m_in1 = new SVGAnimatedStringImpl(); + m_in1->ref(); + + m_surfaceScale = new SVGAnimatedNumberImpl(); + m_surfaceScale->ref(); + + m_specularConstant = new SVGAnimatedNumberImpl(); + m_specularConstant->ref(); + + m_specularExponent = new SVGAnimatedNumberImpl(); + m_specularExponent->ref(); +} + +SVGFESpecularLightingElementImpl::~SVGFESpecularLightingElementImpl() +{ + if(m_in1) + m_in1->deref(); + if(m_surfaceScale) + m_surfaceScale->deref(); + if(m_specularConstant) + m_specularConstant->deref(); + if(m_specularExponent) + m_specularExponent->deref(); +} + +SVGAnimatedStringImpl *SVGFESpecularLightingElementImpl::in1() const +{ + return m_in1; +} + +SVGAnimatedNumberImpl *SVGFESpecularLightingElementImpl::surfaceScale() const +{ + return m_surfaceScale; +} + +SVGAnimatedNumberImpl *SVGFESpecularLightingElementImpl::specularConstant() const +{ + return m_specularConstant; +} + +SVGAnimatedNumberImpl *SVGFESpecularLightingElementImpl::specularExponent() const +{ + return m_specularExponent; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFESpecularLightingElementImpl.h b/ksvg/impl/SVGFESpecularLightingElementImpl.h new file mode 100644 index 00000000..527e7f5b --- /dev/null +++ b/ksvg/impl/SVGFESpecularLightingElementImpl.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFESpecularLightingElementImpl_H +#define SVGFESpecularLightingElementImpl_H + +#include "SVGElementImpl.h" +#include "SVGFilterPrimitiveStandardAttributesImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedStringImpl; +class SVGAnimatedNumberImpl; +class SVGFESpecularLightingElementImpl : public SVGElementImpl, + public SVGFilterPrimitiveStandardAttributesImpl +{ +public: + SVGFESpecularLightingElementImpl(DOM::ElementImpl *); + virtual ~SVGFESpecularLightingElementImpl(); + + SVGAnimatedStringImpl *in1() const; + SVGAnimatedNumberImpl *surfaceScale() const; + SVGAnimatedNumberImpl *specularConstant() const; + SVGAnimatedNumberImpl *specularExponent() const; + +private: + SVGAnimatedStringImpl *m_in1; + SVGAnimatedNumberImpl *m_surfaceScale; + SVGAnimatedNumberImpl *m_specularConstant; + SVGAnimatedNumberImpl *m_specularExponent; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFESpotLightElementImpl.cc b/ksvg/impl/SVGFESpotLightElementImpl.cc new file mode 100644 index 00000000..96950eda --- /dev/null +++ b/ksvg/impl/SVGFESpotLightElementImpl.cc @@ -0,0 +1,113 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedNumberImpl.h" +#include "SVGFESpotLightElementImpl.h" + +using namespace KSVG; + +SVGFESpotLightElementImpl::SVGFESpotLightElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl) +{ + m_x = new SVGAnimatedNumberImpl(); + m_x->ref(); + + m_y = new SVGAnimatedNumberImpl(); + m_y->ref(); + + m_z = new SVGAnimatedNumberImpl(); + m_z->ref(); + + m_pointsAtX = new SVGAnimatedNumberImpl(); + m_pointsAtX->ref(); + + m_pointsAtY = new SVGAnimatedNumberImpl(); + m_pointsAtY->ref(); + + m_pointsAtZ = new SVGAnimatedNumberImpl(); + m_pointsAtZ->ref(); + + m_specularExponent = new SVGAnimatedNumberImpl(); + m_specularExponent->ref(); + + m_limitingConeAngle = new SVGAnimatedNumberImpl(); + m_limitingConeAngle->ref(); +} + +SVGFESpotLightElementImpl::~SVGFESpotLightElementImpl() +{ + if(m_x) + m_x->deref(); + if(m_y) + m_y->deref(); + if(m_z) + m_z->deref(); + if(m_pointsAtX) + m_pointsAtX->deref(); + if(m_pointsAtY) + m_pointsAtY->deref(); + if(m_pointsAtZ) + m_pointsAtZ->deref(); + if(m_specularExponent) + m_specularExponent->deref(); + if(m_limitingConeAngle) + m_limitingConeAngle->deref(); +} + +SVGAnimatedNumberImpl *SVGFESpotLightElementImpl::x() const +{ + return m_x; +} + +SVGAnimatedNumberImpl *SVGFESpotLightElementImpl::y() const +{ + return m_y; +} + +SVGAnimatedNumberImpl *SVGFESpotLightElementImpl::z() const +{ + return m_z; +} + +SVGAnimatedNumberImpl *SVGFESpotLightElementImpl::pointsAtX() const +{ + return m_pointsAtX; +} + +SVGAnimatedNumberImpl *SVGFESpotLightElementImpl::pointsAtY() const +{ + return m_pointsAtY; +} + +SVGAnimatedNumberImpl *SVGFESpotLightElementImpl::pointsAtZ() const +{ + return m_pointsAtZ; +} + +SVGAnimatedNumberImpl *SVGFESpotLightElementImpl::specularExponent() const +{ + return m_specularExponent; +} + +SVGAnimatedNumberImpl *SVGFESpotLightElementImpl::limitingConeAngle() const +{ + return m_limitingConeAngle; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFESpotLightElementImpl.h b/ksvg/impl/SVGFESpotLightElementImpl.h new file mode 100644 index 00000000..3c808698 --- /dev/null +++ b/ksvg/impl/SVGFESpotLightElementImpl.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFESpotLightElementImpl_H +#define SVGFESpotLightElementImpl_H + +#include "SVGElementImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedNumberImpl; +class SVGFESpotLightElementImpl : public SVGElementImpl +{ +public: + SVGFESpotLightElementImpl(DOM::ElementImpl *); + virtual ~SVGFESpotLightElementImpl(); + + SVGAnimatedNumberImpl *x() const; + SVGAnimatedNumberImpl *y() const; + SVGAnimatedNumberImpl *z() const; + SVGAnimatedNumberImpl *pointsAtX() const; + SVGAnimatedNumberImpl *pointsAtY() const; + SVGAnimatedNumberImpl *pointsAtZ() const; + SVGAnimatedNumberImpl *specularExponent() const; + SVGAnimatedNumberImpl *limitingConeAngle() const; + +private: + SVGAnimatedNumberImpl *m_x; + SVGAnimatedNumberImpl *m_y; + SVGAnimatedNumberImpl *m_z; + SVGAnimatedNumberImpl *m_pointsAtX; + SVGAnimatedNumberImpl *m_pointsAtY; + SVGAnimatedNumberImpl *m_pointsAtZ; + SVGAnimatedNumberImpl *m_specularExponent; + SVGAnimatedNumberImpl *m_limitingConeAngle; +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFETileElementImpl.cc b/ksvg/impl/SVGFETileElementImpl.cc new file mode 100644 index 00000000..2a794302 --- /dev/null +++ b/ksvg/impl/SVGFETileElementImpl.cc @@ -0,0 +1,43 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFETileElementImpl.h" +#include "SVGAnimatedStringImpl.h" + +using namespace KSVG; + +SVGFETileElementImpl::SVGFETileElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl() +{ + m_in1 = new SVGAnimatedStringImpl(); + m_in1->ref(); +} + +SVGFETileElementImpl::~SVGFETileElementImpl() +{ + if(m_in1) + m_in1->deref(); +} + +SVGAnimatedStringImpl *SVGFETileElementImpl::in1() const +{ + return m_in1; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFETileElementImpl.h b/ksvg/impl/SVGFETileElementImpl.h new file mode 100644 index 00000000..29cd4167 --- /dev/null +++ b/ksvg/impl/SVGFETileElementImpl.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFETileElementImpl_H +#define SVGFETileElementImpl_H + +#include "SVGElementImpl.h" +#include "SVGFilterPrimitiveStandardAttributesImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedStringImpl; +class SVGFETileElementImpl : public SVGElementImpl, + public SVGFilterPrimitiveStandardAttributesImpl +{ +public: + SVGFETileElementImpl(DOM::ElementImpl *); + virtual ~SVGFETileElementImpl(); + + SVGAnimatedStringImpl *in1() const; + +private: + SVGAnimatedStringImpl *m_in1; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFETurbulenceElementImpl.cc b/ksvg/impl/SVGFETurbulenceElementImpl.cc new file mode 100644 index 00000000..79c68de3 --- /dev/null +++ b/ksvg/impl/SVGFETurbulenceElementImpl.cc @@ -0,0 +1,100 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedNumberImpl.h" +#include "SVGAnimatedIntegerImpl.h" +#include "SVGAnimatedEnumerationImpl.h" +#include "SVGFETurbulenceElementImpl.h" + +using namespace KSVG; + +SVGFETurbulenceElementImpl::SVGFETurbulenceElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl() +{ + m_baseFrequencyX = new SVGAnimatedNumberImpl(); + m_baseFrequencyX->ref(); + + m_baseFrequencyY = new SVGAnimatedNumberImpl(); + m_baseFrequencyY->ref(); + + m_numOctaves = new SVGAnimatedIntegerImpl(); + m_numOctaves->ref(); + + m_seed = new SVGAnimatedNumberImpl(); + m_seed->ref(); + + m_stitchTiles = new SVGAnimatedEnumerationImpl(); + m_stitchTiles->ref(); + + m_type = new SVGAnimatedEnumerationImpl(); + m_type->ref(); +} + +SVGFETurbulenceElementImpl::~SVGFETurbulenceElementImpl() +{ + if(m_baseFrequencyX) + m_baseFrequencyX->deref(); + + if(m_baseFrequencyY) + m_baseFrequencyY->deref(); + + if(m_numOctaves) + m_numOctaves->deref(); + + if(m_seed) + m_seed->deref(); + + if(m_stitchTiles) + m_stitchTiles->deref(); + + if(m_type) + m_type->deref(); +} + +SVGAnimatedNumberImpl *SVGFETurbulenceElementImpl::baseFrequencyX() const +{ + return m_baseFrequencyX; +} + +SVGAnimatedNumberImpl *SVGFETurbulenceElementImpl::baseFrequencyY() const +{ + return m_baseFrequencyY; +} + +SVGAnimatedIntegerImpl *SVGFETurbulenceElementImpl::numOctaves() const +{ + return m_numOctaves; +} + +SVGAnimatedNumberImpl *SVGFETurbulenceElementImpl::seed() const +{ + return m_seed; +} + +SVGAnimatedEnumerationImpl *SVGFETurbulenceElementImpl::stitchTiles() const +{ + return m_stitchTiles; +} + +SVGAnimatedEnumerationImpl *SVGFETurbulenceElementImpl::type() const +{ + return m_type; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFETurbulenceElementImpl.h b/ksvg/impl/SVGFETurbulenceElementImpl.h new file mode 100644 index 00000000..1275f8ca --- /dev/null +++ b/ksvg/impl/SVGFETurbulenceElementImpl.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFETurbulenceElementImpl_H +#define SVGFETurbulenceElementImpl_H + +#include "SVGElementImpl.h" +#include "SVGFilterPrimitiveStandardAttributesImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedNumberImpl; +class SVGAnimatedIntegerImpl; +class SVGAnimatedEnumerationImpl; +class SVGFETurbulenceElementImpl : public SVGElementImpl, public SVGFilterPrimitiveStandardAttributesImpl +{ +public: + SVGFETurbulenceElementImpl(DOM::ElementImpl *); + virtual ~SVGFETurbulenceElementImpl(); + + SVGAnimatedNumberImpl *baseFrequencyX() const; + SVGAnimatedNumberImpl *baseFrequencyY() const; + SVGAnimatedIntegerImpl *numOctaves() const; + SVGAnimatedNumberImpl *seed() const; + SVGAnimatedEnumerationImpl *stitchTiles() const; + SVGAnimatedEnumerationImpl *type() const; + +private: + SVGAnimatedNumberImpl *m_baseFrequencyX; + SVGAnimatedNumberImpl *m_baseFrequencyY; + SVGAnimatedIntegerImpl *m_numOctaves; + SVGAnimatedNumberImpl *m_seed; + SVGAnimatedEnumerationImpl *m_stitchTiles; + SVGAnimatedEnumerationImpl *m_type; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFilterElementImpl.cc b/ksvg/impl/SVGFilterElementImpl.cc new file mode 100644 index 00000000..eb83ad4b --- /dev/null +++ b/ksvg/impl/SVGFilterElementImpl.cc @@ -0,0 +1,119 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFilterElementImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGAnimatedIntegerImpl.h" +#include "SVGAnimatedEnumerationImpl.h" + +using namespace KSVG; + +SVGFilterElementImpl::SVGFilterElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGURIReferenceImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this) +{ + m_filterUnits = new SVGAnimatedEnumerationImpl(); + m_filterUnits->ref(); + + m_primitiveUnits = new SVGAnimatedEnumerationImpl(); + m_primitiveUnits->ref(); + + m_x = new SVGAnimatedLengthImpl(); + m_x->ref(); + + m_y = new SVGAnimatedLengthImpl(); + m_y->ref(); + + m_width = new SVGAnimatedLengthImpl(); + m_width->ref(); + + m_height = new SVGAnimatedLengthImpl(); + m_height->ref(); + + m_filterResX = new SVGAnimatedIntegerImpl(); + m_filterResX->ref(); + + m_filterResY = new SVGAnimatedIntegerImpl(); + m_filterResY->ref(); +} + +SVGFilterElementImpl::~SVGFilterElementImpl() +{ + if(m_filterUnits) + m_filterUnits->deref(); + if(m_primitiveUnits) + m_primitiveUnits->deref(); + if(m_x) + m_x->deref(); + if(m_y) + m_y->deref(); + if(m_width) + m_width->deref(); + if(m_height) + m_height->deref(); + if(m_filterResX) + m_filterResX->deref(); + if(m_filterResY) + m_filterResY->deref(); +} + +SVGAnimatedEnumerationImpl *SVGFilterElementImpl::filterUnits() const +{ + return m_filterUnits; +} + +SVGAnimatedEnumerationImpl *SVGFilterElementImpl::primitiveUnits() const +{ + return m_primitiveUnits; +} + +SVGAnimatedLengthImpl *SVGFilterElementImpl::x() const +{ + return m_x; +} + +SVGAnimatedLengthImpl *SVGFilterElementImpl::y() const +{ + return m_y; +} + +SVGAnimatedLengthImpl *SVGFilterElementImpl::width() const +{ + return m_width; +} + +SVGAnimatedLengthImpl *SVGFilterElementImpl::height() const +{ + return m_height; +} + +SVGAnimatedIntegerImpl *SVGFilterElementImpl::filterResX() const +{ + return m_filterResX; +} + +SVGAnimatedIntegerImpl *SVGFilterElementImpl::filterResY() const +{ + return m_filterResY; +} + +void SVGFilterElementImpl::setFilterRes(unsigned long /*filterResX*/, unsigned long /*filterResY*/) +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFilterElementImpl.h b/ksvg/impl/SVGFilterElementImpl.h new file mode 100644 index 00000000..ad12a9e9 --- /dev/null +++ b/ksvg/impl/SVGFilterElementImpl.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFilterElementImpl_H +#define SVGFilterElementImpl_H + +#include "SVGElementImpl.h" +#include "SVGStylableImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGURIReferenceImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedLengthImpl; +class SVGAnimatedIntegerImpl; +class SVGAnimatedEnumerationImpl; +class SVGFilterElementImpl : public SVGElementImpl, + public SVGURIReferenceImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl +{ +public: + SVGFilterElementImpl(DOM::ElementImpl *); + virtual ~SVGFilterElementImpl(); + + SVGAnimatedEnumerationImpl *filterUnits() const; + SVGAnimatedEnumerationImpl *primitiveUnits() const; + SVGAnimatedLengthImpl *x() const; + SVGAnimatedLengthImpl *y() const; + SVGAnimatedLengthImpl *width() const; + SVGAnimatedLengthImpl *height() const; + SVGAnimatedIntegerImpl *filterResX() const; + SVGAnimatedIntegerImpl *filterResY() const; + void setFilterRes(unsigned long filterResX, unsigned long filterResY); + +private: + SVGAnimatedEnumerationImpl *m_filterUnits; + SVGAnimatedEnumerationImpl *m_primitiveUnits; + SVGAnimatedLengthImpl *m_x; + SVGAnimatedLengthImpl *m_y; + SVGAnimatedLengthImpl *m_width; + SVGAnimatedLengthImpl *m_height; + SVGAnimatedIntegerImpl *m_filterResX; + SVGAnimatedIntegerImpl *m_filterResY; +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFilterPrimitiveStandardAttributesImpl.cc b/ksvg/impl/SVGFilterPrimitiveStandardAttributesImpl.cc new file mode 100644 index 00000000..3f403009 --- /dev/null +++ b/ksvg/impl/SVGFilterPrimitiveStandardAttributesImpl.cc @@ -0,0 +1,84 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGAnimatedLengthImpl.h" +#include "SVGAnimatedStringImpl.h" +#include "SVGFilterPrimitiveStandardAttributesImpl.h" + +using namespace KSVG; + +SVGFilterPrimitiveStandardAttributesImpl::SVGFilterPrimitiveStandardAttributesImpl() +{ + m_x = new SVGAnimatedLengthImpl(); + m_x->ref(); + + m_y = new SVGAnimatedLengthImpl(); + m_y->ref(); + + m_width = new SVGAnimatedLengthImpl(); + m_width->ref(); + + m_height = new SVGAnimatedLengthImpl(); + m_height->ref(); + + m_result = new SVGAnimatedStringImpl(); + m_result->ref(); +} + +SVGFilterPrimitiveStandardAttributesImpl::~SVGFilterPrimitiveStandardAttributesImpl() +{ + if(m_x) + m_x->deref(); + if(m_y) + m_y->deref(); + if(m_width) + m_width->deref(); + if(m_height) + m_height->deref(); + if(m_result) + m_result->deref(); +} + +SVGAnimatedLengthImpl *SVGFilterPrimitiveStandardAttributesImpl::x() const +{ + return m_x; +} + +SVGAnimatedLengthImpl *SVGFilterPrimitiveStandardAttributesImpl::y() const +{ + return m_y; +} + +SVGAnimatedLengthImpl *SVGFilterPrimitiveStandardAttributesImpl::width() const +{ + return m_width; +} + +SVGAnimatedLengthImpl *SVGFilterPrimitiveStandardAttributesImpl::height() const +{ + return m_height; +} + +SVGAnimatedStringImpl *SVGFilterPrimitiveStandardAttributesImpl::result() const +{ + return m_result; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFilterPrimitiveStandardAttributesImpl.h b/ksvg/impl/SVGFilterPrimitiveStandardAttributesImpl.h new file mode 100644 index 00000000..45bcd4d0 --- /dev/null +++ b/ksvg/impl/SVGFilterPrimitiveStandardAttributesImpl.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPrimitiveStandardAttributesImpl_H +#define SVGPrimitiveStandardAttributesImpl_H + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedLengthImpl; +class SVGAnimatedStringImpl; +class SVGFilterPrimitiveStandardAttributesImpl +{ +public: + SVGFilterPrimitiveStandardAttributesImpl(); + virtual ~SVGFilterPrimitiveStandardAttributesImpl(); + + SVGAnimatedLengthImpl *x() const; + SVGAnimatedLengthImpl *y() const; + SVGAnimatedLengthImpl *width() const; + SVGAnimatedLengthImpl *height() const; + SVGAnimatedStringImpl *result() const; + +private: + SVGAnimatedLengthImpl *m_x; + SVGAnimatedLengthImpl *m_y; + SVGAnimatedLengthImpl *m_width; + SVGAnimatedLengthImpl *m_height; + SVGAnimatedStringImpl *m_result; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFitToViewBoxImpl.cc b/ksvg/impl/SVGFitToViewBoxImpl.cc new file mode 100644 index 00000000..fee367b9 --- /dev/null +++ b/ksvg/impl/SVGFitToViewBoxImpl.cc @@ -0,0 +1,141 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include +#include + +#include "SVGPreserveAspectRatio.h" + +#include "SVGRectImpl.h" +#include "SVGFitToViewBoxImpl.h" +#include "SVGAnimatedRectImpl.h" +#include "SVGPreserveAspectRatioImpl.h" +#include "SVGAnimatedPreserveAspectRatioImpl.h" +#include "SVGSVGElementImpl.h" + +using namespace KSVG; + +#include "SVGFitToViewBoxImpl.lut.h" + +SVGFitToViewBoxImpl::SVGFitToViewBoxImpl() +{ + KSVG_EMPTY_FLAGS + + m_viewBox = new SVGAnimatedRectImpl(); + m_viewBox->ref(); + + m_preserveAspectRatio = new SVGAnimatedPreserveAspectRatioImpl(); + m_preserveAspectRatio->ref(); +} + +SVGFitToViewBoxImpl::~SVGFitToViewBoxImpl() +{ + if(m_viewBox) + m_viewBox->deref(); + if(m_preserveAspectRatio) + m_preserveAspectRatio->deref(); +} + +SVGAnimatedRectImpl *SVGFitToViewBoxImpl::viewBox() const +{ + return m_viewBox; +} + +SVGAnimatedPreserveAspectRatioImpl *SVGFitToViewBoxImpl::preserveAspectRatio() const +{ + return m_preserveAspectRatio; +} + +void SVGFitToViewBoxImpl::parseViewBox(const QString &s) +{ + // Set default if preserveAspectRatio wasnt parsed earlier (Rob) + if(m_preserveAspectRatio->baseVal()->align() == SVG_PRESERVEASPECTRATIO_UNKNOWN) + m_preserveAspectRatio->baseVal()->setAlign(SVG_PRESERVEASPECTRATIO_XMIDYMID); + if(m_preserveAspectRatio->baseVal()->meetOrSlice() == SVG_MEETORSLICE_UNKNOWN) + m_preserveAspectRatio->baseVal()->setMeetOrSlice(SVG_MEETORSLICE_MEET); + + // allow for viewbox def with ',' or whitespace + QString viewbox(s); + QStringList points = QStringList::split(' ', viewbox.replace(',', ' ').simplifyWhiteSpace()); + + viewBox()->baseVal()->setX(points[0].toFloat()); + viewBox()->baseVal()->setY(points[1].toFloat()); + viewBox()->baseVal()->setWidth(points[2].toFloat()); + viewBox()->baseVal()->setHeight(points[3].toFloat()); +} + +SVGMatrixImpl *SVGFitToViewBoxImpl::viewBoxToViewTransform(float viewWidth, float viewHeight) const +{ + if(viewBox()->baseVal()->width() == 0 || viewBox()->baseVal()->height() == 0) + return SVGSVGElementImpl::createSVGMatrix(); + else + return preserveAspectRatio()->baseVal()->getCTM(viewBox()->baseVal()->x(), + viewBox()->baseVal()->y(), viewBox()->baseVal()->width(), viewBox()->baseVal()->height(), + 0, 0, viewWidth, viewHeight); +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGFitToViewBoxImpl::s_hashTable 3 + viewBox SVGFitToViewBoxImpl::ViewBox DontDelete + preserveAspectRatio SVGFitToViewBoxImpl::PreserveAspectRatio DontDelete +@end +*/ + +Value SVGFitToViewBoxImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case ViewBox: + return m_viewBox->cache(exec); + case PreserveAspectRatio: + return m_preserveAspectRatio->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGFitToViewBoxImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case ViewBox: + parseViewBox(value.toString(exec).qstring()); + break; + case PreserveAspectRatio: + if(preserveAspectRatio()) + preserveAspectRatio()->baseVal()->parsePreserveAspectRatio(value.toString(exec).qstring()); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFitToViewBoxImpl.h b/ksvg/impl/SVGFitToViewBoxImpl.h new file mode 100644 index 00000000..b511d63e --- /dev/null +++ b/ksvg/impl/SVGFitToViewBoxImpl.h @@ -0,0 +1,69 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFitToViewBoxImpl_H +#define SVGFitToViewBoxImpl_H + +#include "ksvg_lookup.h" + +class QString; + +namespace KSVG +{ + +class SVGAnimatedRectImpl; +class SVGAnimatedPreserveAspectRatioImpl; +class SVGMatrixImpl; +class SVGFitToViewBoxImpl +{ +public: + SVGFitToViewBoxImpl(); + ~SVGFitToViewBoxImpl(); + + SVGAnimatedRectImpl *viewBox() const; + SVGAnimatedPreserveAspectRatioImpl *preserveAspectRatio() const; + + void parseViewBox(const QString &); + + SVGMatrixImpl *viewBoxToViewTransform(float viewWidth, float viewHeight) const; + +protected: + SVGAnimatedRectImpl *m_viewBox; + SVGAnimatedPreserveAspectRatioImpl *m_preserveAspectRatio; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + ViewBox, PreserveAspectRatio + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFontElementImpl.cc b/ksvg/impl/SVGFontElementImpl.cc new file mode 100644 index 00000000..30d4f63f --- /dev/null +++ b/ksvg/impl/SVGFontElementImpl.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFontElementImpl.h" + +using namespace KSVG; + +SVGFontElementImpl::SVGFontElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this) +{ +} + +SVGFontElementImpl::~SVGFontElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFontElementImpl.h b/ksvg/impl/SVGFontElementImpl.h new file mode 100644 index 00000000..3a753797 --- /dev/null +++ b/ksvg/impl/SVGFontElementImpl.h @@ -0,0 +1,49 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFontElementImpl_H +#define SVGFontElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGElementImpl.h" +#include "SVGStylableImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +namespace KSVG +{ + +class SVGFontElementImpl : public SVGElementImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl +{ +public: + SVGFontElementImpl(DOM::ElementImpl *); + virtual ~SVGFontElementImpl(); +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFontFaceElementImpl.cc b/ksvg/impl/SVGFontFaceElementImpl.cc new file mode 100644 index 00000000..d53e70ad --- /dev/null +++ b/ksvg/impl/SVGFontFaceElementImpl.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFontFaceElementImpl.h" + +using namespace KSVG; + +SVGFontFaceElementImpl::SVGFontFaceElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl) +{ +} + +SVGFontFaceElementImpl::~SVGFontFaceElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFontFaceElementImpl.h b/ksvg/impl/SVGFontFaceElementImpl.h new file mode 100644 index 00000000..0479ccea --- /dev/null +++ b/ksvg/impl/SVGFontFaceElementImpl.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFontFaceElementImpl_H +#define SVGFontFaceElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGElementImpl.h" + +namespace KSVG +{ + +class SVGFontFaceElementImpl : public SVGElementImpl +{ +public: + SVGFontFaceElementImpl(DOM::ElementImpl *); + virtual ~SVGFontFaceElementImpl(); + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFontFaceFormatElementImpl.cc b/ksvg/impl/SVGFontFaceFormatElementImpl.cc new file mode 100644 index 00000000..48651a68 --- /dev/null +++ b/ksvg/impl/SVGFontFaceFormatElementImpl.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFontFaceFormatElementImpl.h" + +using namespace KSVG; + +SVGFontFaceFormatElementImpl::SVGFontFaceFormatElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl) +{ +} + +SVGFontFaceFormatElementImpl::~SVGFontFaceFormatElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFontFaceFormatElementImpl.h b/ksvg/impl/SVGFontFaceFormatElementImpl.h new file mode 100644 index 00000000..380e29b1 --- /dev/null +++ b/ksvg/impl/SVGFontFaceFormatElementImpl.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFontFaceFormatElementImpl_H +#define SVGFontFaceFormatElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGElementImpl.h" + +namespace KSVG +{ + +class SVGFontFaceFormatElementImpl : public SVGElementImpl +{ +public: + SVGFontFaceFormatElementImpl(DOM::ElementImpl *); + virtual ~SVGFontFaceFormatElementImpl(); + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFontFaceNameElementImpl.cc b/ksvg/impl/SVGFontFaceNameElementImpl.cc new file mode 100644 index 00000000..276f3ae3 --- /dev/null +++ b/ksvg/impl/SVGFontFaceNameElementImpl.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFontFaceNameElementImpl.h" + +using namespace KSVG; + +SVGFontFaceNameElementImpl::SVGFontFaceNameElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl) +{ +} + +SVGFontFaceNameElementImpl::~SVGFontFaceNameElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFontFaceNameElementImpl.h b/ksvg/impl/SVGFontFaceNameElementImpl.h new file mode 100644 index 00000000..797ee17e --- /dev/null +++ b/ksvg/impl/SVGFontFaceNameElementImpl.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFontFaceNameElementImpl_H +#define SVGFontFaceNameElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGElementImpl.h" + +namespace KSVG +{ + +class SVGFontFaceNameElementImpl : public SVGElementImpl +{ +public: + SVGFontFaceNameElementImpl(DOM::ElementImpl *); + virtual ~SVGFontFaceNameElementImpl(); + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFontFaceSrcElementImpl.cc b/ksvg/impl/SVGFontFaceSrcElementImpl.cc new file mode 100644 index 00000000..bdc40611 --- /dev/null +++ b/ksvg/impl/SVGFontFaceSrcElementImpl.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFontFaceSrcElementImpl.h" + +using namespace KSVG; + +SVGFontFaceSrcElementImpl::SVGFontFaceSrcElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl) +{ +} + +SVGFontFaceSrcElementImpl::~SVGFontFaceSrcElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFontFaceSrcElementImpl.h b/ksvg/impl/SVGFontFaceSrcElementImpl.h new file mode 100644 index 00000000..f858e829 --- /dev/null +++ b/ksvg/impl/SVGFontFaceSrcElementImpl.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFontFaceSrcElementImpl_H +#define SVGFontFaceSrcElementImpl_H + +#include "ksvg_lookup.h" +#include "SVGElementImpl.h" + +namespace KSVG +{ + +class SVGFontFaceSrcElementImpl : public SVGElementImpl +{ +public: + SVGFontFaceSrcElementImpl(DOM::ElementImpl *); + virtual ~SVGFontFaceSrcElementImpl(); + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFontFaceUriElementImpl.cc b/ksvg/impl/SVGFontFaceUriElementImpl.cc new file mode 100644 index 00000000..cef5a30f --- /dev/null +++ b/ksvg/impl/SVGFontFaceUriElementImpl.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGFontFaceUriElementImpl.h" + +using namespace KSVG; + +SVGFontFaceUriElementImpl::SVGFontFaceUriElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl) +{ +} + +SVGFontFaceUriElementImpl::~SVGFontFaceUriElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGFontFaceUriElementImpl.h b/ksvg/impl/SVGFontFaceUriElementImpl.h new file mode 100644 index 00000000..2b670a82 --- /dev/null +++ b/ksvg/impl/SVGFontFaceUriElementImpl.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGFontFaceUriElementImpl_H +#define SVGFontFaceUriElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGElementImpl.h" + +namespace KSVG +{ + +class SVGFontFaceUriElementImpl : public SVGElementImpl +{ +public: + SVGFontFaceUriElementImpl(DOM::ElementImpl *); + virtual ~SVGFontFaceUriElementImpl(); + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGForeignObjectElementImpl.cc b/ksvg/impl/SVGForeignObjectElementImpl.cc new file mode 100644 index 00000000..ff605cf0 --- /dev/null +++ b/ksvg/impl/SVGForeignObjectElementImpl.cc @@ -0,0 +1,121 @@ +/* + Copyright (C) 2001-20032 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGRectImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGForeignObjectElementImpl.h" + +using namespace KSVG; + +#include "SVGForeignObjectElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGForeignObjectElementImpl::SVGForeignObjectElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl() +{ + m_x = new SVGAnimatedLengthImpl(); + m_x->ref(); + + m_y = new SVGAnimatedLengthImpl(); + m_y->ref(); + + m_width = new SVGAnimatedLengthImpl(); + m_width->ref(); + + m_height = new SVGAnimatedLengthImpl(); + m_height->ref(); +} + +SVGForeignObjectElementImpl::~SVGForeignObjectElementImpl() +{ + if(m_x) + m_x->deref(); + if(m_y) + m_y->deref(); + if(m_width) + m_width->deref(); + if(m_height) + m_height->deref(); +} + +SVGRectImpl *SVGForeignObjectElementImpl::getBBox() +{ + SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect(); + ret->setX(m_x->baseVal()->value()); + ret->setY(m_y->baseVal()->value()); + ret->setWidth(m_width->baseVal()->value()); + ret->setHeight(m_height->baseVal()->value()); + return ret; +} + +SVGAnimatedLengthImpl *SVGForeignObjectElementImpl::x() const +{ + return m_x; +} + +SVGAnimatedLengthImpl *SVGForeignObjectElementImpl::y() const +{ + return m_y; +} + +SVGAnimatedLengthImpl *SVGForeignObjectElementImpl::width() const +{ + return m_width; +} + +SVGAnimatedLengthImpl *SVGForeignObjectElementImpl::height() const +{ + return m_height; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGForeignObjectElementImpl::s_hashTable 5 + x SVGForeignObjectElementImpl::X DontDelete|ReadOnly + y SVGForeignObjectElementImpl::Y DontDelete|ReadOnly + width SVGForeignObjectElementImpl::Width DontDelete|ReadOnly + height SVGForeignObjectElementImpl::Height DontDelete|ReadOnly +@end +*/ + +Value SVGForeignObjectElementImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case X: + return m_x->cache(exec); + case Y: + return m_y->cache(exec); + case Width: + return m_width->cache(exec); + case Height: + return m_height->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGForeignObjectElementImpl.h b/ksvg/impl/SVGForeignObjectElementImpl.h new file mode 100644 index 00000000..3fea4877 --- /dev/null +++ b/ksvg/impl/SVGForeignObjectElementImpl.h @@ -0,0 +1,78 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGForeignObjectElementImpl_H +#define SVGForeignObjectElementImpl_H + +#include "SVGTestsImpl.h" +#include "SVGElementImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGStylableImpl.h" +#include "SVGTransformableImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedLengthImpl; +class SVGForeignObjectElementImpl : public SVGElementImpl, + public SVGTestsImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGTransformableImpl +{ +public: + SVGForeignObjectElementImpl(DOM::ElementImpl *); + virtual ~SVGForeignObjectElementImpl(); + + virtual SVGRectImpl *getBBox(); + + SVGAnimatedLengthImpl *x() const; + SVGAnimatedLengthImpl *y() const; + SVGAnimatedLengthImpl *width() const; + SVGAnimatedLengthImpl *height() const; + +private: + SVGAnimatedLengthImpl *m_x; + SVGAnimatedLengthImpl *m_y; + SVGAnimatedLengthImpl *m_width; + SVGAnimatedLengthImpl *m_height; + +public: + KSVG_GET + KSVG_FORWARDPUT + + enum + { + // Properties + X, Y, Width, Height + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGGElementImpl.cc b/ksvg/impl/SVGGElementImpl.cc new file mode 100644 index 00000000..9f355540 --- /dev/null +++ b/ksvg/impl/SVGGElementImpl.cc @@ -0,0 +1,36 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGGElementImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGAElementImpl.h" +#include "SVGAnimatedStringImpl.h" + +using namespace KSVG; + +SVGGElementImpl::SVGGElementImpl(DOM::ElementImpl *impl) : SVGContainerImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl() +{ +} + +SVGGElementImpl::~SVGGElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGGElementImpl.h b/ksvg/impl/SVGGElementImpl.h new file mode 100644 index 00000000..ca4a9b4e --- /dev/null +++ b/ksvg/impl/SVGGElementImpl.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGGElementImpl_H +#define SVGGElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGTestsImpl.h" +#include "SVGStylableImpl.h" +#include "SVGContainerImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGTransformableImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +namespace KSVG +{ + +class SVGGElementImpl : public SVGContainerImpl, + public SVGTestsImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGTransformableImpl +{ +public: + SVGGElementImpl(DOM::ElementImpl *); + virtual ~SVGGElementImpl(); + +public: + KSVG_BRIDGE + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +KSVG_REGISTER_ELEMENT(SVGGElementImpl, "g") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGGlyphElementImpl.cc b/ksvg/impl/SVGGlyphElementImpl.cc new file mode 100644 index 00000000..dd201466 --- /dev/null +++ b/ksvg/impl/SVGGlyphElementImpl.cc @@ -0,0 +1,98 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGGlyphElementImpl.h" + +using namespace KSVG; + +#include "SVGGlyphElementImpl.lut.h" + +SVGGlyphElementImpl::SVGGlyphElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGStylableImpl(this) +{ + KSVG_EMPTY_FLAGS +} + +SVGGlyphElementImpl::~SVGGlyphElementImpl() +{ +} + +QString SVGGlyphElementImpl::d() const +{ + return m_d; +} + +/* +@namespace KSVG +@begin SVGGlyphElementImpl::s_hashTable 11 + unicode SVGGlyphElementImpl::Unicode DontDelete|ReadOnly + glyph-name SVGGlyphElementImpl::GlyphName DontDelete|ReadOnly + d SVGGlyphElementImpl::D DontDelete|ReadOnly + orientation SVGGlyphElementImpl::Orientation DontDelete|ReadOnly + arabic-form SVGGlyphElementImpl::ArabicForm DontDelete|ReadOnly + lang SVGGlyphElementImpl::Lang DontDelete|ReadOnly + horiz-adv-x SVGGlyphElementImpl::HorizAdvX DontDelete|ReadOnly + vert-origin-x SVGGlyphElementImpl::VertOriginX DontDelete|ReadOnly + vert-origin-y SVGGlyphElementImpl::VertOriginY DontDelete|ReadOnly + vert-adv-y SVGGlyphElementImpl::VertAdvY DontDelete|ReadOnly +@end +*/ + +Value SVGGlyphElementImpl::getValueProperty(ExecState *, int token) const +{ + //KSVG_CHECK_ATTRIBUTE + + switch(token) + { + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGGlyphElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case D: + m_d = value.toString(exec).qstring(); + break; + case Unicode: + case GlyphName: + case Orientation: + case ArabicForm: + case Lang: + case HorizAdvX: + case VertOriginX: + case VertOriginY: + case VertAdvY: + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGGlyphElementImpl.h b/ksvg/impl/SVGGlyphElementImpl.h new file mode 100644 index 00000000..35781b2c --- /dev/null +++ b/ksvg/impl/SVGGlyphElementImpl.h @@ -0,0 +1,66 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGGlyphElementImpl_H +#define SVGGlyphElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGElementImpl.h" +#include "SVGStylableImpl.h" + +namespace KSVG +{ + +class SVGGlyphElementImpl : public SVGElementImpl, + public SVGStylableImpl +{ +public: + SVGGlyphElementImpl(DOM::ElementImpl *); + virtual ~SVGGlyphElementImpl(); + + QString d() const; + +private: + QString m_d; + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + Unicode, GlyphName, D, Orientation, ArabicForm, + Lang, HorizAdvX, VertOriginX, VertOriginY, VertAdvY + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGGlyphElementImpl, "glyph") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGGlyphRefElementImpl.cc b/ksvg/impl/SVGGlyphRefElementImpl.cc new file mode 100644 index 00000000..438fa0b0 --- /dev/null +++ b/ksvg/impl/SVGGlyphRefElementImpl.cc @@ -0,0 +1,134 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGSVGElementImpl.h" +#include "SVGGlyphRefElementImpl.h" + +using namespace KSVG; + +#include "SVGGlyphRefElementImpl.lut.h" +#include "ksvg_lookup.h" + +SVGGlyphRefElementImpl::SVGGlyphRefElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGURIReferenceImpl(), SVGStylableImpl(this) +{ +} + +SVGGlyphRefElementImpl::~SVGGlyphRefElementImpl() +{ +} + +void SVGGlyphRefElementImpl::setAttributes() +{ + SVGElementImpl::setAttributes(); +} + +DOM::DOMString SVGGlyphRefElementImpl::format() +{ + return ""; +} + +DOM::DOMString SVGGlyphRefElementImpl::glyphRef() +{ + return ""; +} + +float SVGGlyphRefElementImpl::x() const +{ + return m_x; +} + +float SVGGlyphRefElementImpl::y() const +{ + return m_y; +} + +float SVGGlyphRefElementImpl::dx() const +{ + return m_dx; +} + +float SVGGlyphRefElementImpl::dy() const +{ + return m_dy; +} + +/* +@namespace KSVG +@begin SVGGlyphRefElementImpl::s_hashTable 7 + glyphRef SVGGlyphRefElementImpl::GlyphRef DontDelete|ReadOnly + format SVGGlyphRefElementImpl::Format DontDelete|ReadOnly + x SVGGlyphRefElementImpl::X DontDelete|ReadOnly + y SVGGlyphRefElementImpl::Y DontDelete|ReadOnly + dx SVGGlyphRefElementImpl::Dx DontDelete|ReadOnly + dy SVGGlyphRefElementImpl::Dy DontDelete|ReadOnly +@end +*/ + +Value SVGGlyphRefElementImpl::getValueProperty(ExecState *, int token) const +{ + //KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case GlyphRef: return String(m_glyphRef); + case Format: return String(m_format); + case X: return Number(m_x); + case Y: return Number(m_y); + case Dx: return Number(m_dx); + case Dy: return Number(m_dy); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGGlyphRefElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case GlyphRef: + m_glyphRef = value.toString(exec).string(); + break; + case Format: + m_format = value.toString(exec).string(); + break; + case X: + m_x = value.toNumber(exec); + break; + case Y: + m_y = value.toNumber(exec); + break; + case Dx: + m_dx = value.toNumber(exec); + break; + case Dy: + m_dy = value.toNumber(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGGlyphRefElementImpl.h b/ksvg/impl/SVGGlyphRefElementImpl.h new file mode 100644 index 00000000..6a292a64 --- /dev/null +++ b/ksvg/impl/SVGGlyphRefElementImpl.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGGlyphRefElementImpl_H +#define SVGGlyphRefElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGElementImpl.h" +#include "SVGURIReferenceImpl.h" +#include "SVGStylableImpl.h" + +namespace KSVG +{ + +class SVGGlyphRefElementImpl : public SVGElementImpl, + public SVGURIReferenceImpl, + public SVGStylableImpl +{ +public: + SVGGlyphRefElementImpl(DOM::ElementImpl *); + virtual ~SVGGlyphRefElementImpl(); + virtual void setAttributes(); + + DOM::DOMString glyphRef(); + DOM::DOMString format(); + + float x() const; + float y() const; + float dx() const; + float dy() const; + +private: + DOM::DOMString m_glyphRef; + DOM::DOMString m_format; + float m_x; + float m_y; + float m_dx; + float m_dy; + +public: + KSVG_BRIDGE + KSVG_GET + KSVG_PUT + + enum + { + // Properties + GlyphRef, Format, X, Y, Dx, Dy + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGGlyphRefElementImpl, "glyphRef") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGGradientElementImpl.cc b/ksvg/impl/SVGGradientElementImpl.cc new file mode 100644 index 00000000..180b230a --- /dev/null +++ b/ksvg/impl/SVGGradientElementImpl.cc @@ -0,0 +1,264 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGGradientElement.h" +#include "SVGGradientElementImpl.h" +#include "SVGStopElementImpl.h" +#include "SVGAnimatedStringImpl.h" +#include "SVGSVGElementImpl.h" + +#include "KSVGCanvas.h" +#include "CanvasItems.h" +#include "SVGHelperImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGAnimatedEnumerationImpl.h" +#include "SVGAnimatedTransformListImpl.h" +#include "SVGTransformListImpl.h" +#include "SVGUnitConverter.h" + +using namespace KSVG; + +#include "SVGGradientElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" +#include "ksvg_cacheimpl.h" + +SVGGradientElementImpl::SVGGradientElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGURIReferenceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGPaintServerImpl() +{ + KSVG_EMPTY_FLAGS + + m_gradientUnits = new SVGAnimatedEnumerationImpl(); + m_gradientUnits->ref(); + + m_gradientTransform = new SVGAnimatedTransformListImpl(); + m_gradientTransform->ref(); + + m_spreadMethod = new SVGAnimatedEnumerationImpl(); + m_spreadMethod->ref(); + + m_converter = new SVGUnitConverter(); +} + +SVGGradientElementImpl::~SVGGradientElementImpl() +{ + if(m_gradientUnits) + m_gradientUnits->deref(); + if(m_gradientTransform) + m_gradientTransform->deref(); + if(m_spreadMethod) + m_spreadMethod->deref(); + delete m_converter; +} + +SVGAnimatedEnumerationImpl *SVGGradientElementImpl::gradientUnits() const +{ + return m_gradientUnits; +} + +SVGAnimatedTransformListImpl *SVGGradientElementImpl::gradientTransform() const +{ + return m_gradientTransform; +} + +SVGAnimatedEnumerationImpl *SVGGradientElementImpl::spreadMethod() const +{ + return m_spreadMethod; +} + +/* +@namespace KSVG +@begin SVGGradientElementImpl::s_hashTable 5 + gradientUnits SVGGradientElementImpl::GradientUnits DontDelete|ReadOnly + gradientTransform SVGGradientElementImpl::GradientTransform DontDelete|ReadOnly + spreadMethod SVGGradientElementImpl::SpreadMethod DontDelete|ReadOnly +@end +*/ + +Value SVGGradientElementImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case GradientUnits: + return m_gradientUnits->cache(exec); + case GradientTransform: + return m_gradientTransform->cache(exec); + case SpreadMethod: + return m_spreadMethod->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGGradientElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case GradientUnits: + if(value.toString(exec).qstring() == "userSpaceOnUse") + m_gradientUnits->setBaseVal(SVGGradientElement::SVG_UNIT_TYPE_USERSPACEONUSE); + else + m_gradientUnits->setBaseVal(SVGGradientElement::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX); + break; + case GradientTransform: + m_gradientTransform->baseVal()->clear(); + SVGHelperImpl::parseTransformAttribute(m_gradientTransform->baseVal(), value.toString(exec).qstring()); + break; + case SpreadMethod: + { + QString spreadMethod = value.toString(exec).qstring(); + + if(spreadMethod == "repeat") + m_spreadMethod->setBaseVal(SVG_SPREADMETHOD_REPEAT); + else if(spreadMethod == "reflect") + m_spreadMethod->setBaseVal(SVG_SPREADMETHOD_REFLECT); + else + m_spreadMethod->setBaseVal(SVG_SPREADMETHOD_PAD); + break; + } + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +void SVGGradientElementImpl::setAttributes() +{ + SVGElementImpl::setAttributes(); + setAttributesFromHref(); + + // Spec: if attribute not specified, use "pad" + if(KSVG_TOKEN_NOT_PARSED(SpreadMethod)) + KSVG_SET_ALT_ATTRIBUTE(SpreadMethod, "pad") + + // Spec: if attribute not specified, use objectBoundingBox + if(KSVG_TOKEN_NOT_PARSED(GradientUnits)) + KSVG_SET_ALT_ATTRIBUTE(GradientUnits, "objectBoundingBox") +} + +void SVGGradientElementImpl::setAttributesFromHref() +{ + QString _href = SVGURIReferenceImpl::getTarget(href()->baseVal().string()); + + if(!_href.isEmpty()) + { + SVGGradientElementImpl *refGradient = dynamic_cast(ownerSVGElement()->getElementById(_href)); + + if(refGradient) + { + QMap refAttributes = refGradient->gradientAttributes(); + QMap::iterator it; + + for(it = refAttributes.begin(); it != refAttributes.end(); ++it) + { + QString name = it.key(); + DOM::DOMString value = it.data(); + + if(!hasAttribute(name)) + { + setAttribute(name, value); + setAttributeInternal(name, value); + } + } + } + } +} + +SVGGradientElementImpl *SVGGradientElementImpl::stopsSource() +{ + // Spec: + // If this element has no defined gradient stops, and the referenced element does + // (possibly due to its own href attribute), then this element inherits the gradient stop from the referenced element. + // Inheritance can be indirect to an arbitrary level; thus, if the referenced element inherits attribute or gradient stops + // due to its own href attribute, then the current element can inherit those attributes or gradient stops. (mop) + bool haveStops = false; + + for(DOM::Node node = firstChild(); !node.isNull(); node = node.nextSibling()) + { + SVGStopElementImpl *stop = dynamic_cast(ownerDoc()->getElementFromHandle(node.handle())); + + if(stop) + { + haveStops = true; + break; + } + } + + SVGGradientElementImpl *source = this; + + if(!haveStops) + { + QString _href = SVGURIReferenceImpl::getTarget(href()->baseVal().string()); + + if(!_href.isEmpty()) + { + SVGGradientElementImpl *refGradient = dynamic_cast(ownerSVGElement()->getElementById(_href)); + + if(refGradient) + source = refGradient->stopsSource(); + } + } + + return source; +} + +void SVGGradientElementImpl::createItem(KSVGCanvas *c) +{ + if(!c) + c = ownerDoc()->canvas(); + + if(!m_paintServer) + m_paintServer = c->createPaintServer(this); +} + +void SVGGradientElementImpl::removeItem(KSVGCanvas *) +{ + delete m_paintServer; + m_paintServer = 0; +} + +/* +@namespace KSVG +@begin SVGGradientElementImplConstructor::s_hashTable 5 + SVG_SPREADMETHOD_UNKNOWN KSVG::SVG_SPREADMETHOD_UNKNOWN DontDelete|ReadOnly + SVG_SPREADMETHOD_PAD KSVG::SVG_SPREADMETHOD_PAD DontDelete|ReadOnly + SVG_SPREADMETHOD_REFLECT KSVG::SVG_SPREADMETHOD_REFLECT DontDelete|ReadOnly + SVG_SPREADMETHOD_REPEAT KSVG::SVG_SPREADMETHOD_REPEAT DontDelete|ReadOnly +@end +*/ + +using namespace KJS; + +Value SVGGradientElementImplConstructor::getValueProperty(ExecState *, int token) const +{ + return Number(token); +} + +Value KSVG::getSVGGradientElementImplConstructor(ExecState *exec) +{ + return cacheGlobalBridge(exec, "[[svggradientelement.constructor]]"); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGGradientElementImpl.h b/ksvg/impl/SVGGradientElementImpl.h new file mode 100644 index 00000000..e9be92d8 --- /dev/null +++ b/ksvg/impl/SVGGradientElementImpl.h @@ -0,0 +1,110 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGGradientElementImpl_H +#define SVGGradientElementImpl_H + +#include + +#include "SVGElementImpl.h" +#include "SVGStylableImpl.h" +#include "SVGURIReferenceImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" +#include "SVGPaintServerImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGUnitConverter; +class SVGAnimatedEnumerationImpl; +class SVGAnimatedTransformListImpl; +class SVGGradientElementImpl : public SVGElementImpl, + public SVGURIReferenceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGPaintServerImpl +{ +public: + SVGGradientElementImpl(DOM::ElementImpl *); + virtual ~SVGGradientElementImpl(); + + SVGAnimatedEnumerationImpl *gradientUnits() const; + SVGAnimatedTransformListImpl *gradientTransform() const; + SVGAnimatedEnumerationImpl *spreadMethod() const; + + virtual void setAttributes(); + + virtual void createItem(KSVGCanvas *c = 0); + virtual void removeItem(KSVGCanvas *c); + + SVGUnitConverter *converter() const { return m_converter; } + + // Returns the gradient element that holds the stops for this gradient, + // taking into account indirection through href. + SVGGradientElementImpl *stopsSource(); + + // Returns the linear/radial gradient attributes set on this element, + // taking into account indirection through href. + virtual QMap gradientAttributes() = 0; + +protected: + void setAttributesFromHref(); + +private: + SVGAnimatedEnumerationImpl *m_gradientUnits; + SVGAnimatedTransformListImpl *m_gradientTransform; + SVGAnimatedEnumerationImpl *m_spreadMethod; + + SVGUnitConverter *m_converter; + +public: + KSVG_GET + KSVG_PUT + KSVG_NO_TAG_BRIDGE + + enum + { + // Properties + GradientUnits, GradientTransform, SpreadMethod + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +class SVGGradientElementImplConstructor : public KJS::ObjectImp +{ +public: + SVGGradientElementImplConstructor(KJS::ExecState *) { } + KJS::Value getValueProperty(KJS::ExecState *, int token) const; + + // no put - all read-only + KSVG_GET +}; + +KJS::Value getSVGGradientElementImplConstructor(KJS::ExecState *exec); + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGHKernElementImpl.cc b/ksvg/impl/SVGHKernElementImpl.cc new file mode 100644 index 00000000..df310d6e --- /dev/null +++ b/ksvg/impl/SVGHKernElementImpl.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGHKernElementImpl.h" + +using namespace KSVG; + +SVGHKernElementImpl::SVGHKernElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl) +{ +} + +SVGHKernElementImpl::~SVGHKernElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGHKernElementImpl.h b/ksvg/impl/SVGHKernElementImpl.h new file mode 100644 index 00000000..6858b5be --- /dev/null +++ b/ksvg/impl/SVGHKernElementImpl.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGHKernElementImpl_H +#define SVGHKernElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGElementImpl.h" + +namespace KSVG +{ + +class SVGHKernElementImpl : public SVGElementImpl +{ +public: + SVGHKernElementImpl(DOM::ElementImpl *); + virtual ~SVGHKernElementImpl(); + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGHelperImpl.cc b/ksvg/impl/SVGHelperImpl.cc new file mode 100644 index 00000000..ed7e8be4 --- /dev/null +++ b/ksvg/impl/SVGHelperImpl.cc @@ -0,0 +1,230 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include + +#include "SVGRectImpl.h" +#include "SVGMatrixImpl.h" +#include "SVGHelperImpl.h" +#include "SVGElementImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGStylableImpl.h" +#include "SVGTransformImpl.h" +#include "SVGStringListImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGTransformListImpl.h" +#include "SVGTransformableImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGAnimatedLengthListImpl.h" + +#include "KSVGCanvas.h" +#include "CanvasItem.h" + +using namespace KSVG; + +#include "ksvg_ecma.h" +#include "ksvg_window.h" + +SVGHelperImpl::SVGHelperImpl() +{ +} + +SVGHelperImpl::~SVGHelperImpl() +{ +} + +void SVGHelperImpl::updateItem(KJS::ExecState *exec, const DOM::Node node) +{ + // Get document + SVGDocumentImpl *doc = Window::retrieveActive(exec)->doc(); + + // Update canvas, recursively if needed + SVGShapeImpl *shape = dynamic_cast(doc->getElementFromHandle(node.handle())); + + if(shape && shape->item()) + { + shape->item()->update(UPDATE_TRANSFORM); + shape->item()->draw(); + shape->blit(doc->canvas()); + } + + if(const_cast(node).hasChildNodes()) + { + DOM::Node iterate = node.firstChild(); + for(; !iterate.isNull(); iterate = iterate.nextSibling()) + updateItem(exec, iterate); + } +} + +void SVGHelperImpl::copyAttributes(SVGElementImpl *src, SVGElementImpl *dst) +{ + QDictIterator it(src->attributes()); + for(; it.current(); ++it) + { + DOM::DOMString name = it.currentKey(); + DOM::DOMString value = it.current()->string(); + + if(name != "id" && !dst->hasAttribute(name)) + { + dst->setAttribute(name, value); + dst->setAttributeInternal(name, value); + } + } +} + +void SVGHelperImpl::parseList(SVGStringListImpl *list, char seperator, const QString &data) +{ + // TODO : more error checking/reporting + list->clear(); + + QStringList substrings = QStringList::split(seperator, data); + QStringList::ConstIterator it = substrings.begin(); + QStringList::ConstIterator end = substrings.end(); + for(; it != end; ++it) + { + SharedString *string = new SharedString(*it); + string->ref(); + + list->appendItem(string); + } +} + +void SVGHelperImpl::parseLengthList(SVGAnimatedLengthListImpl *list, const QString &lengths, LengthMode mode, SVGElementImpl *object) +{ + // get either comma or space delimited lists + // TODO : more error checking/reporting + QStringList sublengths = QStringList::split(QRegExp("[, ]"), lengths); + QStringList::ConstIterator it = sublengths.begin(); + QStringList::ConstIterator end = sublengths.end(); + + SVGLengthImpl *lengthImpl = 0; + for(; it != end; ++it) + { + lengthImpl = new SVGLengthImpl(mode, object); + lengthImpl->ref(); + + lengthImpl->setValueAsString(*it); + list->baseVal()->appendItem(lengthImpl); + } +} + +void SVGHelperImpl::parseCommaSeperatedList(SVGStringListImpl *list, const QString &data) +{ + parseList(list, ',', data); +} + +void SVGHelperImpl::parseSemicolonSeperatedList(SVGStringListImpl *list, const QString &data) +{ + parseList(list, ';', data); +} + +void SVGHelperImpl::parseTransformAttribute(SVGTransformListImpl *list, const QString &transform) +{ + // 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("([-]?\\d*\\.?\\d+(?:e[-]?\\d+)?)"); + + int pos = 0; + QStringList params; + + while(pos >= 0) + { + pos = reg.search(subtransform[1], pos); + if(pos != -1) + { + params += reg.cap(1); + pos += reg.matchedLength(); + } + } + + if(subtransform[0].startsWith(";") || subtransform[0].startsWith(",")) + subtransform[0] = subtransform[0].right(subtransform[0].length() - 1); + + SVGTransformImpl *t = SVGSVGElementImpl::createSVGTransform(); + + if(subtransform[0] == "rotate") + { + if(params.count() == 3) + t->setRotate(params[0].toDouble(), + params[1].toDouble(), + params[2].toDouble()); + else + t->setRotate(params[0].toDouble(), 0, 0); + } + else if(subtransform[0] == "translate") + { + if(params.count() == 2) + t->setTranslate(params[0].toDouble(), params[1].toDouble()); + else // Spec : if only one param given, assume 2nd param to be 0 + t->setTranslate(params[0].toDouble(), 0); + } + else if(subtransform[0] == "scale") + { + if(params.count() == 2) + t->setScale(params[0].toDouble(), params[1].toDouble()); + else // Spec : if only one param given, assume uniform scaling + t->setScale(params[0].toDouble(), params[0].toDouble()); + } + else if(subtransform[0] == "skewx") + t->setSkewX(params[0].toDouble()); + else if(subtransform[0] == "skewy") + t->setSkewY(params[0].toDouble()); + else if(subtransform[0] == "matrix") + { + if(params.count() >= 6) + { + SVGMatrixImpl *ret = new SVGMatrixImpl(params[0].toDouble(), + params[1].toDouble(), + params[2].toDouble(), + params[3].toDouble(), + params[4].toDouble(), + params[5].toDouble()); + t->setMatrix(ret); + } + } + + list->appendItem(t); + } +} + +/// convert from user space to "real" pixels on rendering area +QRect SVGHelperImpl::fromUserspace(SVGElementImpl *obj, const QRect &r) +{ + QRect sr; + + SVGLocatableImpl *locate = dynamic_cast(obj); + + if(locate) + sr = locate->screenCTM()->qmatrix().mapRect(r); + + return sr; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGHelperImpl.h b/ksvg/impl/SVGHelperImpl.h new file mode 100644 index 00000000..e8bbdb39 --- /dev/null +++ b/ksvg/impl/SVGHelperImpl.h @@ -0,0 +1,88 @@ +/* + Copyright (C) 2002-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGHelperImpl_H +#define SVGHelperImpl_H + +#include + +#include "SVGElementImpl.h" +#include "SVGLengthImpl.h" +#include "SVGDocumentImpl.h" +#include "ksvg_ecma.h" + +#include "ksvg_lookup.h" + +class QRect; +class QString; + +namespace KSVG +{ +class SVGStringListImpl; +class SVGTransformListImpl; +class SVGAnimatedLengthListImpl; + +class SVGHelperImpl +{ +public: + SVGHelperImpl(); + ~SVGHelperImpl(); + + // Dynamic attribute updating + template + static void applyContainer(T *obj, int token, const QString &value) + { + SVGElementImpl *element = dynamic_cast(obj); + if(!element || !element->hasChildNodes()) + return; + + // Very fast propagation of attributes, when the token is known! (Niko) + for(DOM::Node node = element->firstChild(); !node.isNull(); node = node.nextSibling()) + { + T *cast = dynamic_cast(element->ownerDoc()->getElementFromHandle(node.handle())); + if(cast) + cast->putValueProperty(element->ownerDoc()->ecmaEngine()->globalExec(), token, KJS::String(value), KJS::Internal); + } + } + + // Update item on canvas + static void updateItem(KJS::ExecState *exec, const DOM::Node node); + static void copyAttributes(SVGElementImpl *src, SVGElementImpl *dst); + + // SVGAnimatedLengthList + static void parseLengthList(SVGAnimatedLengthListImpl *list, const QString &lengths, LengthMode mode = LENGTHMODE_UNKNOWN, SVGElementImpl *object = 0); + + // SVGStringList + static void parseList(SVGStringListImpl *list, char seperator, const QString &data); + static void parseCommaSeperatedList(SVGStringListImpl *list, const QString &data); + static void parseSemicolonSeperatedList(SVGStringListImpl *list, const QString &data); + + // SVGTransformList + static void parseTransformAttribute(SVGTransformListImpl *list, const QString &transform); + + // Tools + static QRect fromUserspace(SVGElementImpl *, const QRect &); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGICCColorImpl.cc b/ksvg/impl/SVGICCColorImpl.cc new file mode 100644 index 00000000..3e708ee9 --- /dev/null +++ b/ksvg/impl/SVGICCColorImpl.cc @@ -0,0 +1,107 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGICCColorImpl.h" +#include "SVGNumberListImpl.h" + +using namespace KSVG; + +#include "SVGICCColorImpl.lut.h" +#include "ksvg_bridge.h" + +SVGICCColorImpl::SVGICCColorImpl() : DOM::DomShared() +{ + m_colors = new SVGNumberListImpl(); + m_colors->ref(); +} + +SVGICCColorImpl::SVGICCColorImpl(const SVGICCColorImpl &other) : DOM::DomShared() +{ + (*this) = other; +} + +SVGICCColorImpl::~SVGICCColorImpl() +{ + if(m_colors) + m_colors->deref(); +} + +SVGICCColorImpl &SVGICCColorImpl::operator=(const SVGICCColorImpl &other) +{ + m_colorProfile = other.m_colorProfile; + *m_colors = *(other.m_colors); + + return *this; +} + +DOM::DOMString SVGICCColorImpl::colorProfile() const +{ + return m_colorProfile; +} + +void SVGICCColorImpl::setColorProfile(const DOM::DOMString &colorProfile) +{ + m_colorProfile = colorProfile; +} + +SVGNumberListImpl *SVGICCColorImpl::colors() const +{ + return m_colors; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGICCColorImpl::s_hashTable 3 + colorProfile SVGICCColorImpl::ColorProfile DontDelete + colors SVGICCColorImpl::Colors DontDelete|ReadOnly +@end +*/ + +Value SVGICCColorImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case ColorProfile: + return String(m_colorProfile.string()); + case Colors: + return m_colors->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGICCColorImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int) +{ + switch(token) + { + case ColorProfile: + m_colorProfile = value.toString(exec).string(); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGICCColorImpl.h b/ksvg/impl/SVGICCColorImpl.h new file mode 100644 index 00000000..1427e59c --- /dev/null +++ b/ksvg/impl/SVGICCColorImpl.h @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGICCColorImpl_H +#define SVGICCColorImpl_H + +#include +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGNumberListImpl; +class SVGICCColorImpl : public DOM::DomShared +{ +public: + SVGICCColorImpl(); + SVGICCColorImpl(const SVGICCColorImpl &); + virtual ~SVGICCColorImpl(); + + SVGICCColorImpl &operator=(const SVGICCColorImpl &); + + void setColorProfile(const DOM::DOMString &colorProfile); + DOM::DOMString colorProfile() const; + SVGNumberListImpl *colors() const; + +private: + DOM::DOMString m_colorProfile; + SVGNumberListImpl *m_colors; + +public: + KSVG_GET + + enum + { + // Properties + ColorProfile, Colors + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGImageElementImpl.cc b/ksvg/impl/SVGImageElementImpl.cc new file mode 100644 index 00000000..608dbda5 --- /dev/null +++ b/ksvg/impl/SVGImageElementImpl.cc @@ -0,0 +1,522 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include + +#include + +#include "CanvasItem.h" +#include "KSVGCanvas.h" +#include "KSVGHelper.h" + +#include "SVGRectImpl.h" +#include "SVGEventImpl.h" +#include "SVGMatrixImpl.h" +#include "SVGHelperImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGTransformImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGTransformListImpl.h" +#include "SVGAnimatedStringImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGImageElementImpl.moc" +#include "SVGColorProfileElementImpl.h" +#include "SVGPreserveAspectRatioImpl.h" +#include "SVGAnimatedTransformListImpl.h" +#include "SVGAnimatedPreserveAspectRatioImpl.h" +#include "SVGPatternElementImpl.h" + +using namespace KSVG; + +#include "SVGImageElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGImageElementImpl::SVGImageElementImpl(DOM::ElementImpl *impl) : QObject(), SVGShapeImpl(impl), SVGURIReferenceImpl(), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl() +{ + KSVG_EMPTY_FLAGS + + m_x = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_x->ref(); + m_x->baseVal()->setValueAsString("-1"); + + m_y = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_y->ref(); + m_y->baseVal()->setValueAsString("-1"); + + m_width = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_width->ref(); + m_width->baseVal()->setValueAsString("-1"); + + m_height = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_height->ref(); + m_height->baseVal()->setValueAsString("-1"); + + m_preserveAspectRatio = 0; + + m_doc = 0; + m_image = 0; + m_svgRoot = 0; + m_colorProfile = 0; + m_colorProfileApplied = false; +} + +SVGImageElementImpl::~SVGImageElementImpl() +{ + if(m_x) + m_x->deref(); + if(m_y) + m_y->deref(); + if(m_width) + m_width->deref(); + if(m_height) + m_height->deref(); + if(m_preserveAspectRatio) + m_preserveAspectRatio->deref(); + if(m_doc) + m_doc->deref(); + + delete m_image; +} + +SVGAnimatedLengthImpl *SVGImageElementImpl::x() +{ + return m_x; +} + +SVGAnimatedLengthImpl *SVGImageElementImpl::y() +{ + return m_y; +} + +SVGAnimatedLengthImpl *SVGImageElementImpl::width() +{ + return m_width; +} + +SVGAnimatedLengthImpl *SVGImageElementImpl::height() +{ + return m_height; +} + +SVGAnimatedPreserveAspectRatioImpl *SVGImageElementImpl::preserveAspectRatio() const +{ + return m_preserveAspectRatio; +} + +/* +@namespace KSVG +@namespace KSVG +@begin SVGImageElementImpl::s_hashTable 7 + x SVGImageElementImpl::X DontDelete|ReadOnly + y SVGImageElementImpl::Y DontDelete|ReadOnly + width SVGImageElementImpl::Width DontDelete|ReadOnly + height SVGImageElementImpl::Height DontDelete|ReadOnly + preserveAspectRatio SVGImageElementImpl::PreserveAspectRatio DontDelete|ReadOnly + href SVGImageElementImpl::Href DontDelete|ReadOnly +@end +*/ + +Value SVGImageElementImpl::getValueProperty(ExecState *exec, int token) const +{ + KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case X: + if(!attributeMode) + return m_x->cache(exec); + else + return Number(m_x->baseVal()->value()); + case Y: + if(!attributeMode) + return m_y->cache(exec); + else + return Number(m_y->baseVal()->value()); + case Width: + if(!attributeMode) + return m_width->cache(exec); + else + return Number(m_width->baseVal()->value()); + case Height: + if(!attributeMode) + return m_height->cache(exec); + else + return Number(m_height->baseVal()->value()); + case PreserveAspectRatio: + if(m_preserveAspectRatio) + return m_preserveAspectRatio->cache(exec); + else + return Undefined(); + case Href: + SVGURIReferenceImpl::getValueProperty(exec, token); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGImageElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case X: + x()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case Y: + y()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case Width: + width()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case Height: + height()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case PreserveAspectRatio: + if(!preserveAspectRatio()) + { + m_preserveAspectRatio = new SVGAnimatedPreserveAspectRatioImpl(); + m_preserveAspectRatio->ref(); + } + + preserveAspectRatio()->baseVal()->parsePreserveAspectRatio(value.toString(exec).qstring()); + break; + case Href: + SVGURIReferenceImpl::putValueProperty(exec, SVGURIReferenceImpl::Href, value, attr); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +SVGRectImpl *SVGImageElementImpl::getBBox() +{ + SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect(); + ret->setX(m_x->baseVal()->value()); + ret->setY(m_y->baseVal()->value()); + ret->setWidth(m_width->baseVal()->value()); + ret->setHeight(m_height->baseVal()->value()); + return ret; +} + +void SVGImageElementImpl::setAttributes() +{ + SVGElementImpl::setAttributes(); + + if(KSVG_TOKEN_NOT_PARSED(X)) + KSVG_SET_ALT_ATTRIBUTE(X, "0") + + if(KSVG_TOKEN_NOT_PARSED(Y)) + KSVG_SET_ALT_ATTRIBUTE(Y, "0") + + if(KSVG_TOKEN_NOT_PARSED(PreserveAspectRatio)) + { + setAttribute("preserveAspectRatio", "xMidYMid meet"); + KSVG_SET_ALT_ATTRIBUTE(PreserveAspectRatio, "xMidYMid meet") + } +} + +void SVGImageElementImpl::slotParsingFinished(bool error, const QString &errorDesc) +{ + if(error) + kdDebug(26003) << "Finished with error : " << errorDesc << endl; + else + kdDebug(26003) << "Finished without errors!" << endl; + + m_svgRoot = m_doc->rootElement(); +} + +void SVGImageElementImpl::slotLoadingFinished() +{ + ownerDoc()->notifyImageLoaded(this); +} + +void SVGImageElementImpl::createItem(KSVGCanvas *c) +{ + if(!m_item) + { + if(!c) + c = ownerDoc()->canvas(); + + m_item = c->createImage(this); + c->insert(m_item); + + if(href()->baseVal().string().endsWith(".svg") || href()->baseVal().string().endsWith(".svgz")) + { + if(!m_svgRoot) + { + m_doc = new SVGDocumentImpl(true, false, this); + m_doc->ref(); + m_doc->attach(c); + + connect(m_doc, SIGNAL(finishedParsing(bool, const QString &)), this, SLOT(slotParsingFinished(bool, const QString &))); + connect(m_doc, SIGNAL(finishedLoading()), this, SLOT(slotLoadingFinished())); + + KURL file; + + if(!KURL::isRelativeURL(href()->baseVal().string())) + file = KURL(href()->baseVal().string()); + else + file = KURL(ownerDoc()->baseUrl(), href()->baseVal().string()); + + m_doc->open(file); + + // The svg image will add items to the canvas in parallel with the main + // document, so the z-order will not be correct. Get it to fix this when everything's + // finished loading. + ownerDoc()->resortZIndicesOnFinishedLoading(); + ownerDoc()->notifyImageLoading(this); + } + else + m_svgRoot->createItem(c); + } + else + { + if(!m_image) + { + ownerDoc()->newImageJob(this); + ownerDoc()->notifyImageLoading(this); + } + } + } +} + +void SVGImageElementImpl::removeItem(KSVGCanvas *c) +{ + if(m_item && c) + { + if(m_svgRoot) + m_svgRoot->removeItem(c); + + c->removeItem(m_item); + m_item = 0; + } +} + +void SVGImageElementImpl::setupSVGElement(SVGSVGElementImpl *svg) +{ + // Set up the root svg for an svg image. + svg->setAttributeInternal("x", QString("%1").arg(x()->baseVal()->value())); + svg->setAttributeInternal("y", QString("%1").arg(y()->baseVal()->value())); + svg->setAttributeInternal("width", QString("%1").arg(width()->baseVal()->value())); + svg->setAttributeInternal("height", QString("%1").arg(height()->baseVal()->value())); + + QString par = getAttribute("preserveAspectRatio").string().stripWhiteSpace(); + + if(par.startsWith("defer")) + { + if(svg->getAttribute("preserveAspectRatio").isEmpty()) + { + par.remove("defer"); + svg->setAttribute("preserveAspectRatio", par); + svg->setAttributeInternal("preserveAspectRatio", par); + } + } + else + { + svg->setAttribute("preserveAspectRatio", par); + svg->setAttributeInternal("preserveAspectRatio", par); + } + + svg->setAttributes(); + svg->setRootParentScreenCTM(getScreenCTM()); +} + +void SVGImageElementImpl::onScreenCTMUpdated() +{ + if(m_svgRoot) + { + SVGMatrixImpl *ctm = getScreenCTM(); + + m_svgRoot->setRootParentScreenCTM(ctm); + m_svgRoot->invalidateCachedMatrices(); + m_svgRoot->ownerDoc()->syncCachedMatrices(); + } +} + +bool SVGImageElementImpl::prepareMouseEvent(const QPoint &p, const QPoint &, SVGMouseEventImpl *mev) +{ + // TODO : pointer-events should be stored here, not in SVGStylableImpl. + SVGStylableImpl *style = dynamic_cast(this); + if(!style || style->getPointerEvents() == PE_NONE) + return false; + bool test = true; + switch(style->getPointerEvents()) + { + case PE_VISIBLE: + case PE_VISIBLE_PAINTED: + case PE_VISIBLE_FILL: + case PE_VISIBLE_STROKE: test = style->getVisible(); break; + case PE_PAINTED: + case PE_FILL: + case PE_STROKE: + case PE_ALL: break; + default: test = false; + }; + + if(test && m_item) + { + if(m_item->bbox().contains(p)) + { + mev->setTarget(dynamic_cast(this)); + return true; + } + } + + return false; +} + +void SVGImageElementImpl::setImage(QImage *image) +{ + m_image = image; + + if(m_image) + { + *m_image = m_image->convertDepth(32); + + if(m_colorProfile != 0 && !m_colorProfileApplied) + { + m_colorProfileApplied = true; + applyColorProfile(); + } + + SVGPatternElementImpl::flushCachedTiles(); + + if(m_item) + { + ownerDoc()->canvas()->invalidate(m_item, false); + ownerDoc()->rerender(); + } + } + + ownerDoc()->notifyImageLoaded(this); +} + +QImage SVGImageElementImpl::scaledImage() +{ + SVGMatrixImpl *matrix = imageMatrix(); + double sx, sy; + + matrix->removeScale(&sx, &sy); + matrix->deref(); + + QImage img; + + if(sx != 1 || sy != 1) + { + int scaledWidth = static_cast(m_image->width() * sx + 0.5); + int scaledHeight = static_cast(m_image->height() * sy + 0.5); + + img = m_image->smoothScale(scaledWidth, scaledHeight); + } + else + img = *m_image; + + return img; +} + +SVGMatrixImpl *SVGImageElementImpl::imageMatrix() +{ + SVGMatrixImpl *ctm = getScreenCTM(); + + ctm->translate(x()->baseVal()->value(), y()->baseVal()->value()); + + SVGMatrixImpl *viewboxMatrix = preserveAspectRatio()->baseVal()->getCTM(0, 0, image()->width(), image()->height(), 0, 0, width()->baseVal()->value(), height()->baseVal()->value()); + + ctm->multiply(viewboxMatrix); + viewboxMatrix->deref(); + + return ctm; +} + +SVGMatrixImpl *SVGImageElementImpl::scaledImageMatrix() +{ + SVGMatrixImpl *matrix = imageMatrix(); + double sx, sy; + + matrix->removeScale(&sx, &sy); + + if(sx != 1 || sy != 1) + { + int imageWidth = static_cast(m_image->width() * sx + 0.5); + int imageHeight = static_cast(m_image->height() * sy + 0.5); + + double trueWidth = m_image->width() * sx; + double trueHeight = m_image->height() * sy; + + matrix->scaleNonUniform(trueWidth / imageWidth, trueHeight / imageHeight); + } + + return matrix; +} + +KSVGPolygon SVGImageElementImpl::clippingShape() +{ + KSVGRectangle viewport(0, 0, width()->baseVal()->value(), height()->baseVal()->value()); + SVGMatrixImpl *matrix = preserveAspectRatio()->baseVal()->getCTM(0, 0, image()->width(), image()->height(), 0, 0, width()->baseVal()->value(), height()->baseVal()->value()); + KSVGPolygon p = matrix->inverseMap(viewport); + matrix->deref(); + + matrix = imageMatrix(); + p = matrix->map(p); + matrix->deref(); + + return p; +} + +QString SVGImageElementImpl::fileName() const +{ + return href()->baseVal().string(); +} + +void SVGImageElementImpl::applyColorProfile() +{ + m_image = m_colorProfile->correctImage(m_image); +} + +void SVGImageElementImpl::applyColorProfile(SVGColorProfileElementImpl *profile, SVGImageElementImpl *image) +{ + // Only apply once, if it's the same (Niko) + if(image->m_colorProfile == profile) + return; + + image->m_colorProfile = profile; + + if(image->m_image) + { + // Image is already painted, we apply the color profile and repaint it + image->applyColorProfile(); + + if(image->item()) + { + image->ownerDoc()->canvas()->invalidate(image->item(), false); + image->ownerDoc()->rerender(); + } + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGImageElementImpl.h b/ksvg/impl/SVGImageElementImpl.h new file mode 100644 index 00000000..35ae161f --- /dev/null +++ b/ksvg/impl/SVGImageElementImpl.h @@ -0,0 +1,140 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGImageElementImpl_H +#define SVGImageElementImpl_H + +#include + +#include "ksvg_lookup.h" + +#include "SVGTestsImpl.h" +#include "SVGShapeImpl.h" +#include "SVGStylableImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGURIReferenceImpl.h" +#include "SVGTransformableImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +namespace KSVG +{ + +class KSVGPolygon; +class SVGDocumentImpl; +class SVGSVGElementImpl; +class SVGAnimatedLengthImpl; +class SVGColorProfileElementImpl; +class SVGAnimatedPreserveAspectRatioImpl; +class SVGImageElementImpl : public QObject, + public SVGShapeImpl, + public SVGURIReferenceImpl, + public SVGTestsImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGTransformableImpl +{ +Q_OBJECT +public: + SVGImageElementImpl(DOM::ElementImpl *); + virtual ~SVGImageElementImpl(); + + SVGAnimatedLengthImpl *x(); + SVGAnimatedLengthImpl *y(); + SVGAnimatedLengthImpl *width(); + SVGAnimatedLengthImpl *height(); + SVGAnimatedPreserveAspectRatioImpl *preserveAspectRatio() const; + + virtual void createItem(KSVGCanvas *c); + virtual void removeItem(KSVGCanvas *c); + + virtual void setAttributes(); + + virtual bool prepareMouseEvent(const QPoint &p, const QPoint &a, SVGMouseEventImpl *mev); + + void setImage(QImage *image); + QImage *image() { return m_image; } + + QImage scaledImage(); + SVGMatrixImpl *imageMatrix(); + SVGMatrixImpl *scaledImageMatrix(); + + SVGSVGElementImpl *svgImageRootElement() const { return m_svgRoot; } + + void applyColorProfile(); + static void applyColorProfile(SVGColorProfileElementImpl *profile, SVGImageElementImpl *image); + + QString fileName() const; + + virtual SVGRectImpl *getBBox(); + + // Screen-space clipping shape + KSVGPolygon clippingShape(); + + void onScreenCTMUpdated(); + + void setupSVGElement(SVGSVGElementImpl *svg); + +private slots: + void slotParsingFinished(bool error, const QString &errorDesc); + void slotLoadingFinished(); + +private: + SVGAnimatedLengthImpl *m_x; + SVGAnimatedLengthImpl *m_y; + SVGAnimatedLengthImpl *m_width; + SVGAnimatedLengthImpl *m_height; + + QImage *m_image; + + bool m_colorProfileApplied; + SVGAnimatedPreserveAspectRatioImpl *m_preserveAspectRatio; + SVGColorProfileElementImpl *m_colorProfile; + SVGSVGElementImpl *m_svgRoot; + SVGDocumentImpl *m_doc; + +public: + KSVG_GET + KSVG_BRIDGE + KSVG_PUT + + enum + { + // Properties + X, Y, Width, Height, PreserveAspectRatio, Href + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +struct ImageStreamMap +{ + QByteArray *data; + SVGImageElementImpl *imageElement; +}; + +KSVG_REGISTER_ELEMENT(SVGImageElementImpl, "image") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGLangSpaceImpl.cc b/ksvg/impl/SVGLangSpaceImpl.cc new file mode 100644 index 00000000..0eaada47 --- /dev/null +++ b/ksvg/impl/SVGLangSpaceImpl.cc @@ -0,0 +1,130 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGLangSpaceImpl.h" + +using namespace KSVG; + +#include "SVGLangSpaceImpl.lut.h" +#include "ksvg_bridge.h" + +SVGLangSpaceImpl::SVGLangSpaceImpl() +{ + KSVG_EMPTY_FLAGS + + // Spec: default for xml:space is "default" + setXmlspace("default"); +} + +SVGLangSpaceImpl::~SVGLangSpaceImpl() +{ +} + +void SVGLangSpaceImpl::setXmllang(const DOM::DOMString &xmllang) +{ + m_xmllang = xmllang; +} + +DOM::DOMString SVGLangSpaceImpl::xmllang() const +{ + return m_xmllang; +} + +void SVGLangSpaceImpl::setXmlspace(const DOM::DOMString &xmlspace) +{ + m_xmlspace = xmlspace; +} + +DOM::DOMString SVGLangSpaceImpl::xmlspace() const +{ + return m_xmlspace; +} + +QString SVGLangSpaceImpl::handleText(const QString &data) const +{ + QString result = data; + + if(xmlspace() == "preserve") + { + // Spec: What to do here? + // It will convert all newline and tab characters into space characters + result.replace("\n\r", QString(" ")); + result.replace("\r\n", QString(" ")); + result.replace('\t', ' '); + } + else if(xmlspace() == "default") + { + // Spec: What to do here? + // First, it will remove all newline characters (replace) + // Then it will convert all tab characters into space characters (simplifyWhiteSpace) + // Then, it will strip off all leading and trailing space characters (stripWhiteSpace) + // Then, all contiguous space characters will be consolidated. (simplifyWhiteSpace) + result.replace('\n', QString::null); + result.replace('\r', QString::null); + result = result.stripWhiteSpace().simplifyWhiteSpace(); + } + + return result; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGLangSpaceImpl::s_hashTable 5 + xmllang SVGLangSpaceImpl::XmlLang DontDelete + xmlspace SVGLangSpaceImpl::XmlSpace DontDelete + lang SVGLangSpaceImpl::XmlLang DontDelete + space SVGLangSpaceImpl::XmlSpace DontDelete +@end +*/ + +Value SVGLangSpaceImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case XmlLang: + return String(m_xmllang.string()); + case XmlSpace: + return String(m_xmlspace.string()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGLangSpaceImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int /*attr*/) +{ + switch(token) + { + case XmlLang: + m_xmllang = value.toString(exec).string(); + break; + case XmlSpace: + m_xmlspace = value.toString(exec).string(); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGLangSpaceImpl.h b/ksvg/impl/SVGLangSpaceImpl.h new file mode 100644 index 00000000..4a8c199a --- /dev/null +++ b/ksvg/impl/SVGLangSpaceImpl.h @@ -0,0 +1,67 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGLangSpaceImpl_H +#define SVGLangSpaceImpl_H + +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGLangSpaceImpl +{ +public: + SVGLangSpaceImpl(); + virtual ~SVGLangSpaceImpl(); + + void setXmllang(const DOM::DOMString &xmllang); + DOM::DOMString xmllang() const; + + void setXmlspace(const DOM::DOMString &xmlspace); + DOM::DOMString xmlspace() const; + + QString handleText(const QString &data) const; + +private: + DOM::DOMString m_xmllang; + DOM::DOMString m_xmlspace; + +public: + KSVG_BASECLASS_GET + KSVG_PUT + + enum + { + // Properties + XmlLang, XmlSpace + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGLengthImpl.cc b/ksvg/impl/SVGLengthImpl.cc new file mode 100644 index 00000000..46529022 --- /dev/null +++ b/ksvg/impl/SVGLengthImpl.cc @@ -0,0 +1,510 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include +#include +#include +#include + +#include "SVGLength.h" + +#include "SVGRectImpl.h" +#include "SVGLengthImpl.h" +#include "SVGMatrixImpl.h" +#include "SVGHelperImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGStringListImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGAnimatedRectImpl.h" +#include "svgpathparser.h" + +#include "KSVGCanvas.h" + +using namespace KSVG; + +#include "SVGLengthImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_cacheimpl.h" + +// keep track of textual description of the unit type +QString UnitText[] = +{ + "", "", "%", "em", "ex", "px", "cm", "mm", "in", "pt", "pc" +}; + +SVGLengthImpl::SVGLengthImpl(LengthMode mode, SVGElementImpl *context) : DOM::DomShared(), m_mode(mode), m_context(context) +{ + KSVG_EMPTY_FLAGS + + m_unitType = SVG_LENGTHTYPE_UNKNOWN; + m_value = 0; + m_valueInSpecifiedUnits = 0; + m_bboxContext = 0; +} + +SVGLengthImpl::SVGLengthImpl(const SVGLengthImpl &other) : DOM::DomShared() +{ + (*this) = other; +} + +SVGLengthImpl::~SVGLengthImpl() +{ +} + +double SVGLengthImpl::dpi() +{ + if(m_context && m_context->ownerDoc()) + { + if(m_mode == LENGTHMODE_WIDTH) + return 25.4 * m_context->ownerDoc()->screenPixelsPerMillimeterX(); + else if(m_mode == LENGTHMODE_HEIGHT) + return 25.4 * m_context->ownerDoc()->screenPixelsPerMillimeterY(); + else if(m_mode == LENGTHMODE_OTHER) + return 25.4 * m_context->ownerDoc()->screenPixelsPerMillimeterX(); + } + return 90.0; +} + +SVGLengthImpl &SVGLengthImpl::operator=(const SVGLengthImpl &other) +{ + m_unitType = other.m_unitType; + m_value = other.m_value; + m_valueInSpecifiedUnits = other.m_valueInSpecifiedUnits; + m_bboxContext = other.m_bboxContext; + m_mode = other.m_mode; + m_context = other.m_context; + + return *this; +} + +unsigned short SVGLengthImpl::unitType() const +{ + return m_unitType; +} + +void SVGLengthImpl::setValue(float value) +{ + m_value = value; + getValFromPx(); +} + +float SVGLengthImpl::value() +{ + if(m_unitType == SVG_LENGTHTYPE_PERCENTAGE) + { + float value = m_valueInSpecifiedUnits / 100.0; + SVGRectImpl *bbox = 0; + if(m_bboxContext && (bbox = m_bboxContext->getBBox())) + { + float result = 0; + if(m_mode == LENGTHMODE_WIDTH) + result = value * bbox->width(); + else if(m_mode == LENGTHMODE_HEIGHT) + result = value * bbox->height(); + else if(m_mode == LENGTHMODE_OTHER) + result = value * sqrt(pow(bbox->width(), 2) + pow(bbox->height(), 2)) / sqrt(2.0); + + bbox->deref(); + return result; + } + else + return percentageOfViewport(); + } + else + return m_value; +} + +void SVGLengthImpl::setValueInSpecifiedUnits(float valueInSpecifiedUnits) +{ + m_valueInSpecifiedUnits = valueInSpecifiedUnits; + convertNumToPx(); +} + +float SVGLengthImpl::valueInSpecifiedUnits() const +{ + return m_valueInSpecifiedUnits; +} + +void SVGLengthImpl::setValueAsString(const DOM::DOMString &valueAsString) +{ + convertStringToPx(valueAsString.string()); +} + +DOM::DOMString SVGLengthImpl::valueAsString() const +{ + DOM::DOMString valueAsString = QString::number(m_valueInSpecifiedUnits); + valueAsString += UnitText[m_unitType]; + return valueAsString; +} + +void SVGLengthImpl::newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits) +{ + m_valueInSpecifiedUnits = valueInSpecifiedUnits; + m_unitType = unitType; + convertNumToPx(); +} + +void SVGLengthImpl::convertToSpecifiedUnits(unsigned short unitType) +{ + m_unitType = unitType; + getValFromPx(); +} + +SVGLengthImpl::operator float() +{ + return valueInSpecifiedUnits(); +} + +bool SVGLengthImpl::getValFromPx() +{ + if(m_unitType == SVG_LENGTHTYPE_UNKNOWN) + return false; + + switch(m_unitType) + { + // case SVG_LENGTHTYPE_PERCENTAGE: TODO + // case SVG_LENGTHTYPE_EMS: TODO + // case SVG_LENGTHTYPE_EXS: TODO + //break; + case SVG_LENGTHTYPE_PX: + m_valueInSpecifiedUnits = m_value; + break; + case SVG_LENGTHTYPE_CM: + m_valueInSpecifiedUnits = m_value / dpi() * 2.54; + break; + case SVG_LENGTHTYPE_MM: + m_valueInSpecifiedUnits = m_value / dpi() * 25.4; + break; + case SVG_LENGTHTYPE_IN: + m_valueInSpecifiedUnits = m_value / dpi(); + break; + case SVG_LENGTHTYPE_PT: + m_valueInSpecifiedUnits = m_value / dpi() * 72.0; + break; + case SVG_LENGTHTYPE_PC: + m_valueInSpecifiedUnits = m_value / dpi() * 6.0; + break; + }; + return true; +} + +void SVGLengthImpl::convertStringToPx(QString s) +{ + if(s.isEmpty()) + return; + + double convNum = 0; + const char *start = s.latin1(); + const char *end = getNumber(start, convNum); + m_valueInSpecifiedUnits = convNum; + + if(uint(end - start) < s.length()) + { + if(s.endsWith(UnitText[SVG_LENGTHTYPE_PX])) + m_unitType = SVG_LENGTHTYPE_PX; + else if(s.endsWith(UnitText[SVG_LENGTHTYPE_CM])) + m_unitType = SVG_LENGTHTYPE_CM; + else if(s.endsWith(UnitText[SVG_LENGTHTYPE_PC])) + m_unitType = SVG_LENGTHTYPE_PC; + else if(s.endsWith(UnitText[SVG_LENGTHTYPE_MM])) + m_unitType = SVG_LENGTHTYPE_MM; + else if(s.endsWith(UnitText[SVG_LENGTHTYPE_IN])) + m_unitType = SVG_LENGTHTYPE_IN; + else if(s.endsWith(UnitText[SVG_LENGTHTYPE_PT])) + m_unitType = SVG_LENGTHTYPE_PT; + else if(s.endsWith(UnitText[SVG_LENGTHTYPE_PERCENTAGE])) + m_unitType = SVG_LENGTHTYPE_PERCENTAGE; + else if(s.endsWith(UnitText[SVG_LENGTHTYPE_EMS])) + m_unitType = SVG_LENGTHTYPE_EMS; + else if(s.endsWith(UnitText[SVG_LENGTHTYPE_EXS])) + m_unitType = SVG_LENGTHTYPE_EXS; + else if(s.isEmpty()) + m_unitType = SVG_LENGTHTYPE_NUMBER; + else + m_unitType = SVG_LENGTHTYPE_UNKNOWN; + } + else + m_unitType = SVG_LENGTHTYPE_PX; + convertNumToPx(); +} + +void SVGLengthImpl::convertNumToPx() +{ + switch(m_unitType) + { + case SVG_LENGTHTYPE_PX: + m_value = m_valueInSpecifiedUnits; + break; + case SVG_LENGTHTYPE_CM: + m_value = (m_valueInSpecifiedUnits / 2.54) * dpi(); + break; + case SVG_LENGTHTYPE_MM: + m_value = (m_valueInSpecifiedUnits / 25.4) * dpi(); + break; + case SVG_LENGTHTYPE_IN: + m_value = m_valueInSpecifiedUnits * dpi(); + break; + case SVG_LENGTHTYPE_PT: + m_value = (m_valueInSpecifiedUnits / 72.0) * dpi(); + break; + case SVG_LENGTHTYPE_PC: + m_value = (m_valueInSpecifiedUnits / 6.0) * dpi(); + break; + case SVG_LENGTHTYPE_EMS: // Be careful here, always recheck coords-units-BE-01.svg after touching (Niko) + case SVG_LENGTHTYPE_EXS: + if(m_context) + { + SVGStylableImpl *style = dynamic_cast(m_context); + if(!style) + break; + + bool sizeLocal = (style->getFontSize() != -1); + bool familyLocal = (style->getFontFamily() && style->getFontFamily()->getFirst()); + + SVGStylableImpl *parentStyle = 0; + if((!sizeLocal || !familyLocal) && m_context) + parentStyle = dynamic_cast(m_context->ownerDoc()->getElementFromHandle(m_context->parentNode().handle())); + + // Look up font-size in a SAFE way, because at this place + // processStyle() has NOT yet been called, so we need + // a different solution (Niko) + QString useFont = "Arial"; + double useSize = 12; + + if(sizeLocal) + useSize = style->getFontSize(); + else if(parentStyle && parentStyle->getFontSize() != -1) + useSize = parentStyle->getFontSize(); + + if(familyLocal) + useFont = style->getFontFamily()->getFirst()->string(); + else if(parentStyle && parentStyle->getFontFamily() && parentStyle->getFontFamily()->getFirst()) + useFont = parentStyle->getFontFamily()->getFirst()->string(); + + if(m_unitType == SVG_LENGTHTYPE_EMS) + m_value = m_valueInSpecifiedUnits * useSize; + else + { + // Easiest way, use qfont (Niko) + QFont font(useFont); + font.setPixelSize(static_cast(useSize)); + + QFontMetrics fm(font); + m_value = m_valueInSpecifiedUnits * fm.boundingRect('x').height(); + } + } + break; + }; +} + +void SVGLengthImpl::convertPercentageToFloat(const QString &perc, float &result) +{ + // TODO : more error checking ? + if(perc.endsWith("%")) + result = perc.left(perc.length() - 1).toFloat() / 100.0; + else + result = perc.toFloat(); +} + +QString SVGLengthImpl::convertValToPercentage(const QString &val, float benchmark) +{ + if(val.endsWith("%")) + return val; + + QString result; + float temp = val.toFloat(); + + temp = (temp / benchmark) * 100.0; + result.setNum(temp); + result.append("%"); + + return result; +} + +SVGElementImpl *SVGLengthImpl::context() const +{ + return m_context; +} + +void SVGLengthImpl::setContext(SVGElementImpl *context) +{ + m_context = context; +} + +void SVGLengthImpl::setBBoxContext(SVGShapeImpl *bbox) +{ + m_bboxContext = bbox; + convertNumToPx(); +} + +float SVGLengthImpl::percentageOfViewport() +{ + float width = 0, height = 0; + float value = m_valueInSpecifiedUnits / 100.0; + if(m_context->viewportElement()) + { + SVGSVGElementImpl *svg = dynamic_cast(m_context->viewportElement()); + if(svg) + { + // Calculate against viewBox, otherwise svg width/height + width = svg->viewBox()->baseVal()->width(); + if(width == 0) + width = svg->width()->baseVal()->value(); + height = svg->viewBox()->baseVal()->height(); + if(height == 0) + height = svg->height()->baseVal()->value(); + } + + if(m_mode == LENGTHMODE_WIDTH) + return value * width; + else if(m_mode == LENGTHMODE_HEIGHT) + return value * height; + else if(m_mode == LENGTHMODE_OTHER) + return value * sqrt(pow(width, 2) + pow(height, 2)) / sqrt(2.0); + } + else if(m_context == m_context->ownerDoc()->rootElement()) + { + if(!m_context->ownerDoc()->canvas()) // Happens when parsing with printnodetest + return 0.0; + + QPaintDeviceMetrics metrics(m_context->ownerDoc()->canvas()->drawWindow()); + + if(m_mode == LENGTHMODE_WIDTH) + return value * metrics.width(); + else if(m_mode == LENGTHMODE_HEIGHT) + return value * metrics.height(); + else if(m_mode == LENGTHMODE_OTHER) + return value * sqrt(pow(metrics.width(), 2) + pow(metrics.height(), 2)) / sqrt(2.0); + } + + return 0; +} + +// Ecma stuff +// +/* +@namespace KSVG +@begin SVGLengthImpl::s_hashTable 5 + unitType SVGLengthImpl::UnitType DontDelete|ReadOnly + value SVGLengthImpl::Value DontDelete + valueAsString SVGLengthImpl::ValueAsString DontDelete + valueInSpecifiedUnits SVGLengthImpl::ValueInSpecifiedUnits DontDelete +@end +@namespace KSVG +@begin SVGLengthImplProto::s_hashTable 3 + newValueSpecifiedUnits SVGLengthImpl::NewValueSpecifiedUnits DontDelete|Function 2 + convertToSpecifiedUnits SVGLengthImpl::ConvertToSpecifiedUnits DontDelete|Function 1 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGLength", SVGLengthImplProto, SVGLengthImplProtoFunc) + +Value SVGLengthImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case UnitType: + return Number(unitType()); + case Value: + return Number(m_value); + case ValueAsString: + return String(valueAsString().string()); + case ValueInSpecifiedUnits: + return Number(valueInSpecifiedUnits()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return KJS::Undefined(); + } +} + +void SVGLengthImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int) +{ + switch(token) + { + case Value: + setValue(value.toNumber(exec)); + SVGHelperImpl::updateItem(exec, *m_context); + break; + case ValueAsString: + setValueAsString(value.toString(exec).string()); + SVGHelperImpl::updateItem(exec, *m_context); + break; + case ValueInSpecifiedUnits: + setValueInSpecifiedUnits(value.toNumber(exec)); + SVGHelperImpl::updateItem(exec, *m_context); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +Value SVGLengthImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGLengthImpl) + + switch(id) + { + case SVGLengthImpl::NewValueSpecifiedUnits: + obj->newValueSpecifiedUnits(static_cast(args[0].toNumber(exec)), args[1].toNumber(exec)); + SVGHelperImpl::updateItem(exec, *obj->context()); + return Undefined(); + case SVGLengthImpl::ConvertToSpecifiedUnits: + obj->convertToSpecifiedUnits(static_cast(args[0].toNumber(exec))); + SVGHelperImpl::updateItem(exec, *obj->context()); + return Undefined(); + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + +/* +@namespace KSVG +@begin SVGLengthImplConstructor::s_hashTable 11 + SVG_LENGTHTYPE_UNKNOWN KSVG::SVG_LENGTHTYPE_UNKNOWN DontDelete|ReadOnly + SVG_LENGTHTYPE_NUMBER KSVG::SVG_LENGTHTYPE_NUMBER DontDelete|ReadOnly + SVG_LENGTHTYPE_PERCENTAGE KSVG::SVG_LENGTHTYPE_PERCENTAGE DontDelete|ReadOnly + SVG_LENGTHTYPE_EMS KSVG::SVG_LENGTHTYPE_EMS DontDelete|ReadOnly + SVG_LENGTHTYPE_EXS KSVG::SVG_LENGTHTYPE_EXS DontDelete|ReadOnly + SVG_LENGTHTYPE_PX KSVG::SVG_LENGTHTYPE_PX DontDelete|ReadOnly + SVG_LENGTHTYPE_CM KSVG::SVG_LENGTHTYPE_CM DontDelete|ReadOnly + SVG_LENGTHTYPE_MM KSVG::SVG_LENGTHTYPE_MM DontDelete|ReadOnly + SVG_LENGTHTYPE_PT KSVG::SVG_LENGTHTYPE_PT DontDelete|ReadOnly + SVG_LENGTHTYPE_PC KSVG::SVG_LENGTHTYPE_PC DontDelete|ReadOnly +@end +*/ + +Value SVGLengthImplConstructor::getValueProperty(ExecState *, int token) const +{ + return Number(token); +} + +Value KSVG::getSVGLengthImplConstructor(ExecState *exec) +{ + return cacheGlobalBridge(exec, "[[svglength.constructor]]"); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGLengthImpl.h b/ksvg/impl/SVGLengthImpl.h new file mode 100644 index 00000000..5879a091 --- /dev/null +++ b/ksvg/impl/SVGLengthImpl.h @@ -0,0 +1,136 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGLengthImpl_H +#define SVGLengthImpl_H + +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +enum LengthMode +{ + LENGTHMODE_UNKNOWN = 0, + LENGTHMODE_WIDTH = 1, + LENGTHMODE_HEIGHT = 2, + LENGTHMODE_OTHER = 3 +}; + +class SVGShapeImpl; +class SVGLocatableImpl; +class SVGElementImpl; +class SVGLengthImpl : public DOM::DomShared +{ +public: + SVGLengthImpl(LengthMode mode = LENGTHMODE_UNKNOWN, SVGElementImpl *context = 0); + SVGLengthImpl(const SVGLengthImpl &); + virtual ~SVGLengthImpl(); + + SVGLengthImpl &operator=(const SVGLengthImpl &); + + unsigned short unitType() const; + + void setValue(float value); + float value(); + + void setValueInSpecifiedUnits(float valueInSpecifiedUnits); + float valueInSpecifiedUnits() const; + + void setValueAsString(const DOM::DOMString &); + DOM::DOMString valueAsString() const; + + void newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits); + void convertToSpecifiedUnits(unsigned short unitType); + + operator float(); + + static void convertPercentageToFloat(const QString &perc, float &result); + + // This method converts the value val to percentage notation ("xxx%"). + // If the value string ends with the percentage sign it is returned, + // else the value is calculated against benchmark, ie. "0.2" -> "20%" + // for benchmark 1.0. This method should be useful in contexts that + // know the values should be in percentages up front, like bbox + // calculations. + static QString convertValToPercentage(const QString &val, float benchmark = 1.0); + + SVGElementImpl *context() const; + void setContext(SVGElementImpl *context); + void setBBoxContext(SVGShapeImpl *bbox); + +private: + float m_value; + float m_valueInSpecifiedUnits; + + float percentageOfViewport(); + + void convertStringToPx(QString s); + void convertNumToPx(); + bool getValFromPx(); + + unsigned short m_unitType : 4; + + // KSVG extension + LengthMode m_mode : 2; + SVGElementImpl *m_context; + SVGShapeImpl *m_bboxContext; + + double dpi(); + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + UnitType, Value, ValueAsString, ValueInSpecifiedUnits, + // Functions + NewValueSpecifiedUnits, ConvertToSpecifiedUnits + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); + +}; + +class SVGLengthImplConstructor : public KJS::ObjectImp +{ +public: + SVGLengthImplConstructor(KJS::ExecState *) { } + KJS::Value getValueProperty(KJS::ExecState *, int token) const; + + // no put - all read-only + KSVG_GET +}; + +KJS::Value getSVGLengthImplConstructor(KJS::ExecState *exec); + +} + +KSVG_DEFINE_PROTOTYPE(SVGLengthImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGLengthImplProtoFunc, SVGLengthImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGLengthListImpl.cc b/ksvg/impl/SVGLengthListImpl.cc new file mode 100644 index 00000000..31215ddd --- /dev/null +++ b/ksvg/impl/SVGLengthListImpl.cc @@ -0,0 +1,64 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGLengthListImpl.h" + +using namespace KSVG; + +#include "SVGLengthListImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGLengthListImpl::s_hashTable 2 + numberOfItems SVGListDefs::NumberOfItems DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGLengthListImplProto::s_hashTable 11 + getItem SVGListDefs::GetItem DontDelete|Function 1 + removeItem SVGListDefs::RemoveItem DontDelete|Function 1 + appendItem SVGListDefs::AppendItem DontDelete|Function 1 + initialize SVGListDefs::Initialize DontDelete|Function 1 + insertItemBefore SVGListDefs::InsertItemBefore DontDelete|Function 2 + replaceItem SVGListDefs::ReplaceItem DontDelete|Function 2 + clear SVGListDefs::Clear DontDelete|Function 0 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGLengthList", SVGLengthListImplProto, SVGLengthListImplProtoFunc) + +Value SVGLengthListImpl::getValueProperty(ExecState *exec, int token) const +{ + return SVGList::getValueProperty(exec, token); +} + +Value SVGLengthListImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGLengthListImpl) + + return obj->call(exec, static_cast *>(obj), args, id); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGLengthListImpl.h b/ksvg/impl/SVGLengthListImpl.h new file mode 100644 index 00000000..7ef8c80d --- /dev/null +++ b/ksvg/impl/SVGLengthListImpl.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGLengthListImpl_H +#define SVGLengthListImpl_H + +#include "ksvg_lookup.h" + +#include "SVGList.h" + +#include "SVGLengthImpl.h" + +namespace KSVG +{ + +class SVGLengthListImpl : public SVGList +{ +public: + KSVG_GET + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +} + +KSVG_DEFINE_PROTOTYPE(SVGLengthListImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGLengthListImplProtoFunc, SVGLengthListImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGLineElementImpl.cc b/ksvg/impl/SVGLineElementImpl.cc new file mode 100644 index 00000000..7e13f46c --- /dev/null +++ b/ksvg/impl/SVGLineElementImpl.cc @@ -0,0 +1,213 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include + +#include + +#include "CanvasItem.h" +#include "KSVGCanvas.h" + +#include "SVGRectImpl.h" +#include "SVGAngleImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGLineElementImpl.h" +#include "SVGAnimatedLengthImpl.h" + +using namespace KSVG; + +#include "SVGLineElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGLineElementImpl::SVGLineElementImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl() +{ + KSVG_EMPTY_FLAGS + + m_x1 = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_x1->ref(); + m_x1->baseVal()->setValueAsString("-1"); + + m_y1 = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_y1->ref(); + m_y1->baseVal()->setValueAsString("-1"); + + m_x2 = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_x2->ref(); + m_x2->baseVal()->setValueAsString("-1"); + + m_y2 = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_y2->ref(); + m_y2->baseVal()->setValueAsString("-1"); +} + +SVGLineElementImpl::~SVGLineElementImpl() +{ + if(m_x1) + m_x1->deref(); + if(m_x2) + m_x2->deref(); + if(m_y1) + m_y1->deref(); + if(m_y2) + m_y2->deref(); +} + +SVGAnimatedLengthImpl *SVGLineElementImpl::x1() +{ + return m_x1; +} + +SVGAnimatedLengthImpl *SVGLineElementImpl::y1() +{ + return m_y1; +} + +SVGAnimatedLengthImpl *SVGLineElementImpl::x2() +{ + return m_x2; +} + +SVGAnimatedLengthImpl *SVGLineElementImpl::y2() +{ + return m_y2; +} + +/* +@namespace KSVG +@begin SVGLineElementImpl::s_hashTable 5 + x1 SVGLineElementImpl::X1 DontDelete|ReadOnly + y1 SVGLineElementImpl::Y1 DontDelete|ReadOnly + x2 SVGLineElementImpl::X2 DontDelete|ReadOnly + y2 SVGLineElementImpl::Y2 DontDelete|ReadOnly +@end +*/ + +Value SVGLineElementImpl::getValueProperty(ExecState *exec, int token) const +{ + KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case X1: + if(!attributeMode) + return m_x1->cache(exec); + else + return Number(m_x1->baseVal()->value()); + case Y1: + if(!attributeMode) + return m_y1->cache(exec); + else + return Number(m_y1->baseVal()->value()); + case X2: + if(!attributeMode) + return m_x2->cache(exec); + else + return Number(m_x2->baseVal()->value()); + case Y2: + if(!attributeMode) + return m_y2->cache(exec); + else + return Number(m_y2->baseVal()->value()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGLineElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case X1: + x1()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case Y1: + y1()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case X2: + x2()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case Y2: + y2()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +SVGRectImpl *SVGLineElementImpl::getBBox() +{ + SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect(); + + float minx = kMin(m_x1->baseVal()->value(), m_x2->baseVal()->value()); + float miny = kMin(m_y1->baseVal()->value(), m_y2->baseVal()->value()); + float maxx = kMax(m_x1->baseVal()->value(), m_x2->baseVal()->value()); + float maxy = kMax(m_y1->baseVal()->value(), m_y2->baseVal()->value()); + ret->setX(minx); + ret->setY(miny); + ret->setWidth(maxx - minx); + ret->setHeight(maxy - miny); + + return ret; +} + +void SVGLineElementImpl::setAttributes() +{ + SVGElementImpl::setAttributes(); + + // Spec: if not specified, effect is as if a value of "0" were specified + if(KSVG_TOKEN_NOT_PARSED(X1)) + KSVG_SET_ALT_ATTRIBUTE(X1, "0") + + // Spec: if not specified, effect is as if a value of "0" were specified + if(KSVG_TOKEN_NOT_PARSED(Y1)) + KSVG_SET_ALT_ATTRIBUTE(Y1, "0") + + // Spec: if not specified, effect is as if a value of "0" were specified + if(KSVG_TOKEN_NOT_PARSED(X2)) + KSVG_SET_ALT_ATTRIBUTE(X2, "0") + + // Spec: if not specified, effect is as if a value of "0" were specified + if(KSVG_TOKEN_NOT_PARSED(Y2)) + KSVG_SET_ALT_ATTRIBUTE(Y2, "0") +} + +void SVGLineElementImpl::createItem(KSVGCanvas *c) +{ + if(!c) + c = ownerDoc()->canvas(); + + if(!m_item) + { + m_item = c->createLine(this); + c->insert(m_item); + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGLineElementImpl.h b/ksvg/impl/SVGLineElementImpl.h new file mode 100644 index 00000000..725881a3 --- /dev/null +++ b/ksvg/impl/SVGLineElementImpl.h @@ -0,0 +1,86 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGLineElementImpl_H +#define SVGLineElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGShapeImpl.h" +#include "SVGTestsImpl.h" +#include "SVGStylableImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGTransformableImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +namespace KSVG +{ + +class SVGRectImpl; +class SVGAnimatedLengthImpl; +class SVGLineElementImpl : public SVGShapeImpl, + public SVGTestsImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGTransformableImpl +{ +public: + SVGLineElementImpl(DOM::ElementImpl *); + virtual ~SVGLineElementImpl(); + + SVGAnimatedLengthImpl *x1(); + SVGAnimatedLengthImpl *y1(); + SVGAnimatedLengthImpl *x2(); + SVGAnimatedLengthImpl *y2(); + + virtual void createItem(KSVGCanvas *c = 0); + virtual void setAttributes(); + + virtual SVGRectImpl *getBBox(); + +private: + SVGAnimatedLengthImpl *m_x1; + SVGAnimatedLengthImpl *m_y1; + SVGAnimatedLengthImpl *m_x2; + SVGAnimatedLengthImpl *m_y2; + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + X1, Y1, X2, Y2 + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGLineElementImpl, "line") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGLinearGradientElementImpl.cc b/ksvg/impl/SVGLinearGradientElementImpl.cc new file mode 100644 index 00000000..54c97f01 --- /dev/null +++ b/ksvg/impl/SVGLinearGradientElementImpl.cc @@ -0,0 +1,201 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGGradientElement.h" +#include "SVGLinearGradientElementImpl.h" + +#include "SVGDocumentImpl.h" +#include "KSVGCanvas.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGLengthImpl.h" +#include "SVGUnitConverter.h" + +using namespace KSVG; + +#include "SVGLinearGradientElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGLinearGradientElementImpl::SVGLinearGradientElementImpl(DOM::ElementImpl *impl) : SVGGradientElementImpl(impl) +{ + KSVG_EMPTY_FLAGS + + m_x1 = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_x1->ref(); + + m_y1 = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_y1->ref(); + + m_x2 = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_x2->ref(); + + m_y2 = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_y2->ref(); + + converter()->add(m_x1); + converter()->add(m_y1); + converter()->add(m_x2); + converter()->add(m_y2); +} + +SVGLinearGradientElementImpl::~SVGLinearGradientElementImpl() +{ + if(m_x1) + m_x1->deref(); + if(m_y1) + m_y1->deref(); + if(m_x2) + m_x2->deref(); + if(m_y2) + m_y2->deref(); +} + +SVGAnimatedLengthImpl *SVGLinearGradientElementImpl::x1() const +{ + return m_x1; +} + +SVGAnimatedLengthImpl *SVGLinearGradientElementImpl::y1() const +{ + return m_y1; +} + +SVGAnimatedLengthImpl *SVGLinearGradientElementImpl::x2() const +{ + return m_x2; +} + +SVGAnimatedLengthImpl *SVGLinearGradientElementImpl::y2() const +{ + return m_y2; +} + +/* +@namespace KSVG +@begin SVGLinearGradientElementImpl::s_hashTable 5 + x1 SVGLinearGradientElementImpl::X1 DontDelete|ReadOnly + y1 SVGLinearGradientElementImpl::Y1 DontDelete|ReadOnly + x2 SVGLinearGradientElementImpl::X2 DontDelete|ReadOnly + y2 SVGLinearGradientElementImpl::Y2 DontDelete|ReadOnly +@end +*/ + +Value SVGLinearGradientElementImpl::getValueProperty(ExecState *exec, int token) const +{ + KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case X1: + if(!attributeMode) + return m_x1->cache(exec); + else + return Number(m_x1->baseVal()->value()); + case Y1: + if(!attributeMode) + return m_y1->cache(exec); + else + return Number(m_y1->baseVal()->value()); + case X2: + if(!attributeMode) + return m_x2->cache(exec); + else + return Number(m_x2->baseVal()->value()); + case Y2: + if(!attributeMode) + return m_y2->cache(exec); + else + return Number(m_y2->baseVal()->value()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGLinearGradientElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case X1: + converter()->modify(x1(), value.toString(exec).qstring()); + break; + case Y1: + converter()->modify(y1(), value.toString(exec).qstring()); + break; + case X2: + converter()->modify(x2(), value.toString(exec).qstring()); + break; + case Y2: + converter()->modify(y2(), value.toString(exec).qstring()); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +void SVGLinearGradientElementImpl::setAttributes() +{ + SVGGradientElementImpl::setAttributes(); + + // Spec: no attribute, effect is af value 0% is specified + if(KSVG_TOKEN_NOT_PARSED(X1)) + KSVG_SET_ALT_ATTRIBUTE(X1, "0") + + // Spec: no attribute, effect is af value 0% is specified + if(KSVG_TOKEN_NOT_PARSED(Y1)) + KSVG_SET_ALT_ATTRIBUTE(Y1, "0") + + // Spec: no attribute, effect is af value 100% is specified + if(KSVG_TOKEN_NOT_PARSED(X2)) + KSVG_SET_ALT_ATTRIBUTE(X2, "100%") + + // Spec: no attribute, effect is af value 0% is specified + if(KSVG_TOKEN_NOT_PARSED(Y2)) + KSVG_SET_ALT_ATTRIBUTE(Y2, "0") +} + +QMap SVGLinearGradientElementImpl::gradientAttributes() +{ + setAttributes(); + + QMap gradAttributes; + QDictIterator it(attributes()); + + for(; it.current(); ++it) + { + DOM::DOMString name = it.currentKey(); + DOM::DOMString value = it.current()->string(); + + if(name == "gradientUnits" || name == "gradientTransform" || name == "spreadMethod" || name == "x1" || name == "x2" || name == "y1" || name == "y2") + { + gradAttributes.insert(name.string(), value.copy()); + } + } + + return gradAttributes; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGLinearGradientElementImpl.h b/ksvg/impl/SVGLinearGradientElementImpl.h new file mode 100644 index 00000000..a230a0fe --- /dev/null +++ b/ksvg/impl/SVGLinearGradientElementImpl.h @@ -0,0 +1,74 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGLinearGradientElementImpl_H +#define SVGLinearGradientElementImpl_H + +#include "SVGGradientElementImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedLengthImpl; +class SVGLinearGradientElementImpl : public SVGGradientElementImpl +{ +public: + SVGLinearGradientElementImpl(DOM::ElementImpl *); + virtual ~SVGLinearGradientElementImpl(); + + SVGAnimatedLengthImpl *x1() const; + SVGAnimatedLengthImpl *y1() const; + SVGAnimatedLengthImpl *x2() const; + SVGAnimatedLengthImpl *y2() const; + + virtual void setAttributes(); + + virtual QMap gradientAttributes(); + +private: + SVGAnimatedLengthImpl *m_x1; + SVGAnimatedLengthImpl *m_y1; + SVGAnimatedLengthImpl *m_x2; + SVGAnimatedLengthImpl *m_y2; + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + X1, X2, Y1, Y2, Href + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGLinearGradientElementImpl, "linearGradient") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGList.h b/ksvg/impl/SVGList.h new file mode 100644 index 00000000..45eb81ba --- /dev/null +++ b/ksvg/impl/SVGList.h @@ -0,0 +1,174 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 SVGList_H +#define SVGList_H + +#include "ksvg_bridge.h" +#include "ksvg_lookup.h" +#include "ksvg_scriptinterpreter.h" +#include +#include + +namespace KSVG +{ + +class SVGListDefs +{ +public: + enum + { + // Properties + NumberOfItems, + // Functions + GetItem, RemoveItem, AppendItem, Initialize, + InsertItemBefore, ReplaceItem, Clear + }; +}; + +template +class SVGList : public DOM::DomShared +{ +public: + SVGList() { m_impl.setAutoDelete(false); } + SVGList(const SVGList &other) { *this = other; } + ~SVGList() { clear(); } + + SVGList &operator=(const SVGList &other) + { + // Clear own list + clear(); + + // Clone other's elements and append them + SVGList &get = const_cast &>(other); + for(unsigned int i = 0; i < other.numberOfItems(); i++) + { + T *obj = new T(*get.getItem(i)); + obj->ref(); + + appendItem(obj); + } + + return *this; + } + + unsigned int numberOfItems() const { return m_impl.count(); } + + void clear() + { + for(unsigned int i = 0; i < numberOfItems(); i++) + getItem(i)->deref(); + + m_impl.clear(); + } + + T *initialize(T *newItem) + { + clear(); + return appendItem(newItem); + } + + T *getFirst() const { return m_impl.getFirst(); } + + T *getLast() const { return m_impl.getLast(); } + + T *getItem(unsigned int index) { return m_impl.at(index); } + const T *getItem(unsigned int index) const { return const_cast *>(this)->m_impl.at(index); } + + T *insertItemBefore(T *newItem, unsigned int index) + { + if (index < m_vector.size()) { + m_vector.insert(index, newItem); + } else { + m_vector.append(newItem); + } + return newItem; + } + + T *replaceItem(T *newItem, unsigned int index) + { + m_impl.take(index); + m_impl.insert(index, newItem); + return newItem; + } + + T *removeItem(unsigned int index) + { + return m_impl.take(index); + } + + void removeItem(const T *item) + { + m_impl.remove(item); + } + + T *appendItem(T *newItem) + { + m_impl.append(newItem); + return newItem; + } + + // Ecma stuff + KJS::Value getValueProperty(KJS::ExecState *, int token) const + { + switch(token) + { + case SVGListDefs::NumberOfItems: + return KJS::Number(numberOfItems()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return KJS::Undefined(); + } + } + + KJS::Value call(KJS::ExecState *exec, SVGList *obj, const KJS::List &args, int id) + { + switch(id) + { + case SVGListDefs::GetItem: + return obj->getItem(static_cast(args[0].toNumber(exec)))->cache(exec); + case SVGListDefs::RemoveItem: + return obj->removeItem(static_cast(args[0].toNumber(exec)))->cache(exec); + case SVGListDefs::AppendItem: + return obj->appendItem(static_cast *>(args[0].imp())->impl())->cache(exec); + case SVGListDefs::InsertItemBefore: + return obj->insertItemBefore(static_cast *>(args[0].imp())->impl(), static_cast(args[1].toNumber(exec)))->cache(exec); + case SVGListDefs::Initialize: + return obj->initialize(static_cast *>(args[0].imp())->impl())->cache(exec); + case SVGListDefs::Clear: + { + obj->clear(); + return KJS::Undefined(); + } + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return KJS::Undefined(); + } + +private: + QPtrList m_impl; +}; + +} + +#endif diff --git a/ksvg/impl/SVGLocatableImpl.cc b/ksvg/impl/SVGLocatableImpl.cc new file mode 100644 index 00000000..0ae143fa --- /dev/null +++ b/ksvg/impl/SVGLocatableImpl.cc @@ -0,0 +1,208 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGRectImpl.h" +#include "SVGShapeImpl.h" +#include "SVGContainerImpl.h" +#include "SVGMatrixImpl.h" +#include "SVGElementImpl.h" +#include "SVGLocatableImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGDocumentImpl.h" + +using namespace KSVG; + +#include "SVGLocatableImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGLocatableImpl::SVGLocatableImpl() +{ + m_nearestViewportElement = 0; + m_farthestViewportElement = 0; + m_cachedScreenCTM = SVGSVGElementImpl::createSVGMatrix(); + m_cachedScreenCTMIsValid = false; +} + +SVGLocatableImpl::~SVGLocatableImpl() +{ + if(m_nearestViewportElement) + m_nearestViewportElement->deref(); + if(m_farthestViewportElement) + m_farthestViewportElement->deref(); + if(m_cachedScreenCTM) + m_cachedScreenCTM->deref(); +} + +SVGRectImpl *SVGLocatableImpl::getBBox() +{ + SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect(); + return ret; +} + +SVGMatrixImpl *SVGLocatableImpl::getCTM() +{ + SVGMatrixImpl *ret = SVGSVGElementImpl::createSVGMatrix(); + return ret; +} + +SVGMatrixImpl *SVGLocatableImpl::getScreenCTM() +{ + SVGMatrixImpl *ret = SVGSVGElementImpl::createSVGMatrix(); + ret->copy(m_cachedScreenCTM); + + return ret; +} + +SVGMatrixImpl *SVGLocatableImpl::getTransformToElement(SVGElementImpl *) +{ + SVGMatrixImpl *ret = SVGSVGElementImpl::createSVGMatrix(); + return ret; +} + +void SVGLocatableImpl::updateCachedScreenCTM(const SVGMatrixImpl *parentScreenCTM) +{ + m_cachedScreenCTM->copy(parentScreenCTM); + + const SVGMatrixImpl *local = localMatrix(); + + if(local) + m_cachedScreenCTM->multiply(local); + m_cachedScreenCTMIsValid = true; + + // Notify the element + onScreenCTMUpdated(); + + SVGShapeImpl *shape = dynamic_cast(this); + + if(shape) + { + // TODO: Update due to matrix animations + //if(shape->item()) + // shape->item()->update(updateReason); + + SVGElementImpl *element = dynamic_cast(this); + + DOM::Node node = element->firstChild(); + for(; !node.isNull(); node = node.nextSibling()) + { + SVGElementImpl *child = element->ownerDoc()->getElementFromHandle(node.handle()); + SVGLocatableImpl *locatable = dynamic_cast(child); + + if(child && locatable) + locatable->updateCachedScreenCTM(m_cachedScreenCTM); + } + } +} + +void SVGLocatableImpl::checkCachedScreenCTM(const SVGMatrixImpl *parentScreenCTM) +{ + if(m_cachedScreenCTMIsValid) + { + SVGElementImpl *element = dynamic_cast(this); + SVGShapeImpl *shape = dynamic_cast(this); + + if(shape) + { + DOM::Node node = element->firstChild(); + for(; !node.isNull(); node = node.nextSibling()) + { + SVGElementImpl *child = element->ownerDoc()->getElementFromHandle(node.handle()); + SVGLocatableImpl *locatable = dynamic_cast(child); + + if(child && locatable) + locatable->checkCachedScreenCTM(m_cachedScreenCTM); + } + } + } + else + updateCachedScreenCTM(parentScreenCTM); +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGLocatableImpl::s_hashTable 3 + nearestViewportElement SVGLocatableImpl::NearestViewportElement DontDelete + farthestViewportElement SVGLocatableImpl::FarthestViewportElement DontDelete +@end +@namespace KSVG +@begin SVGLocatableImplProto::s_hashTable 5 + getBBox SVGLocatableImpl::GetBBox DontDelete|Function 0 + getCTM SVGLocatableImpl::GetCTM DontDelete|Function 0 + getScreenCTM SVGLocatableImpl::GetScreenCTM DontDelete|Function 0 + getTransformToElement SVGLocatableImpl::GetTransformToElement DontDelete|Function 1 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGLocatable", SVGLocatableImplProto, SVGLocatableImplProtoFunc) + +Value SVGLocatableImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case NearestViewportElement: + return nearestViewportElement() ? nearestViewportElement()->cache(exec) : Undefined(); + case FarthestViewportElement: + return farthestViewportElement() ? farthestViewportElement()->cache(exec) : Undefined(); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +Value SVGLocatableImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGLocatableImpl) + + switch(id) + { + case SVGLocatableImpl::GetBBox: + { + SVGContainerImpl *container = dynamic_cast(obj); + if(container) + return container->getBBox()->cache(exec); + else + { + SVGShapeImpl *shape = dynamic_cast(obj); + if(shape) + return shape->getBBox()->cache(exec); + else + return obj->getBBox()->cache(exec); + } + } + case SVGLocatableImpl::GetCTM: + return obj->getCTM()->cache(exec); + case SVGLocatableImpl::GetScreenCTM: + return obj->getScreenCTM()->cache(exec); + case SVGLocatableImpl::GetTransformToElement: + return obj->getTransformToElement(static_cast *>(args[0].imp())->impl())->cache(exec); + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGLocatableImpl.h b/ksvg/impl/SVGLocatableImpl.h new file mode 100644 index 00000000..81ce3326 --- /dev/null +++ b/ksvg/impl/SVGLocatableImpl.h @@ -0,0 +1,94 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGLocatableImpl_H +#define SVGLocatableImpl_H + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGRectImpl; +class SVGMatrixImpl; +class SVGElementImpl; +class SVGLocatableImpl +{ +public: + SVGLocatableImpl(); + virtual ~SVGLocatableImpl(); + + SVGElementImpl *nearestViewportElement() const { return m_nearestViewportElement; } + SVGElementImpl *farthestViewportElement() const{ return m_farthestViewportElement; } + + virtual SVGRectImpl *getBBox(); + virtual SVGMatrixImpl *getCTM(); + virtual SVGMatrixImpl *getScreenCTM(); + + // Faster access for when a new copy isn't required. + const SVGMatrixImpl *screenCTM() const { return m_cachedScreenCTM; } + + SVGMatrixImpl *getTransformToElement(SVGElementImpl *element); + + // The local transformations concatenated together. 0 if + // there are no local transformations. + virtual const SVGMatrixImpl *localMatrix() { return 0; } + + bool cachedScreenCTMIsValid() const { return m_cachedScreenCTMIsValid; } + void invalidateCachedMatrices() { m_cachedScreenCTMIsValid = false; } + + // If the cached matrix is invalid, update it and update any child elements + // recursively. Otherwise, check child elements recursively. + virtual void checkCachedScreenCTM(const SVGMatrixImpl *parentScreenCTM); + // Update the cached matrix, and update child element cached matrices, + // recursively. + virtual void updateCachedScreenCTM(const SVGMatrixImpl *parentScreenCTM); + + // Called immediately after the screen ctm has been updated. + virtual void onScreenCTMUpdated() {} + +protected: + SVGElementImpl *m_nearestViewportElement; + SVGElementImpl *m_farthestViewportElement; + SVGMatrixImpl *m_cachedScreenCTM; + bool m_cachedScreenCTMIsValid; + +public: + KSVG_BASECLASS_GET + + enum + { + // Properties + NearestViewportElement, FarthestViewportElement, + // Functions + GetBBox, GetCTM, GetScreenCTM, GetTransformToElement + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +} + +KSVG_DEFINE_PROTOTYPE(SVGLocatableImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGLocatableImplProtoFunc, SVGLocatableImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGMPathElementImpl.cc b/ksvg/impl/SVGMPathElementImpl.cc new file mode 100644 index 00000000..84d48274 --- /dev/null +++ b/ksvg/impl/SVGMPathElementImpl.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGMPathElementImpl.h" + +using namespace KSVG; + +SVGMPathElementImpl::SVGMPathElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGURIReferenceImpl(), SVGExternalResourcesRequiredImpl() +{ +} + +SVGMPathElementImpl::~SVGMPathElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGMPathElementImpl.h b/ksvg/impl/SVGMPathElementImpl.h new file mode 100644 index 00000000..8d0bd96b --- /dev/null +++ b/ksvg/impl/SVGMPathElementImpl.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGMPathElementImpl_H +#define SVGMPathElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGElementImpl.h" +#include "SVGURIReferenceImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +namespace KSVG +{ + +class SVGMPathElementImpl : public SVGElementImpl, + public SVGURIReferenceImpl, + public SVGExternalResourcesRequiredImpl +{ +public: + SVGMPathElementImpl(DOM::ElementImpl *); + virtual ~SVGMPathElementImpl(); + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGMarkerElementImpl.cc b/ksvg/impl/SVGMarkerElementImpl.cc new file mode 100644 index 00000000..0fc1d263 --- /dev/null +++ b/ksvg/impl/SVGMarkerElementImpl.cc @@ -0,0 +1,424 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGMarkerElement.h" + +#include "SVGRectImpl.h" +#include "SVGAngleImpl.h" +#include "SVGMatrixImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGTransformImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGAnimatedRectImpl.h" +#include "SVGMarkerElementImpl.h" +#include "SVGAnimatedAngleImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGAnimatedEnumerationImpl.h" +#include "SVGPreserveAspectRatioImpl.h" +#include "SVGAnimatedPreserveAspectRatioImpl.h" + +#include "KSVGCanvas.h" + +using namespace KSVG; + +#include "SVGMarkerElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" +#include "ksvg_cacheimpl.h" + +SVGMarkerElementImpl::SVGMarkerElementImpl(DOM::ElementImpl *impl) : SVGContainerImpl(impl), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGFitToViewBoxImpl() +{ + KSVG_EMPTY_FLAGS + + m_refX = new SVGAnimatedLengthImpl(); + m_refX->ref(); + + m_refY = new SVGAnimatedLengthImpl(); + m_refY->ref(); + + m_markerUnits = new SVGAnimatedEnumerationImpl(); + m_markerUnits->ref(); + + m_markerWidth = new SVGAnimatedLengthImpl(); + m_markerWidth->ref(); + + m_markerHeight = new SVGAnimatedLengthImpl(); + m_markerHeight->ref(); + + m_orientType = new SVGAnimatedEnumerationImpl(); + m_orientType->ref(); + + m_orientAngle = new SVGAnimatedAngleImpl(); + m_orientAngle->ref(); +} + +SVGMarkerElementImpl::~SVGMarkerElementImpl() +{ + if(m_refX) + m_refX->deref(); + if(m_refY) + m_refY->deref(); + if(m_markerUnits) + m_markerUnits->deref(); + if(m_markerWidth) + m_markerWidth->deref(); + if(m_markerHeight) + m_markerHeight->deref(); + if(m_orientType) + m_orientType->deref(); + if(m_orientAngle) + m_orientAngle->deref(); +} + +SVGAnimatedLengthImpl *SVGMarkerElementImpl::refX() const +{ + return m_refX; +} + +SVGAnimatedLengthImpl *SVGMarkerElementImpl::refY() const +{ + return m_refY; +} + +SVGAnimatedEnumerationImpl *SVGMarkerElementImpl::markerUnits() const +{ + return m_markerUnits; +} + +SVGAnimatedLengthImpl *SVGMarkerElementImpl::markerWidth() const +{ + return m_markerWidth; +} + +SVGAnimatedLengthImpl *SVGMarkerElementImpl::markerHeight() const +{ + return m_markerHeight; +} + +SVGAnimatedEnumerationImpl *SVGMarkerElementImpl::orientType() const +{ + return m_orientType; +} + +SVGAnimatedAngleImpl *SVGMarkerElementImpl::orientAngle() const +{ + return m_orientAngle; +} + +void SVGMarkerElementImpl::setOrientToAuto() +{ + orientType()->setBaseVal(SVG_MARKER_ORIENT_AUTO); +} + +void SVGMarkerElementImpl::setOrientToAngle(SVGAngleImpl *angle) +{ + m_orientAngle->baseVal()->setValue(angle->value()); +} + +void SVGMarkerElementImpl::setAttributes() +{ + SVGElementImpl::setAttributes(); + + // Spec: if not specified, effect is as if a value of "0" were specified + if(KSVG_TOKEN_NOT_PARSED(RefX)) + KSVG_SET_ALT_ATTRIBUTE(RefX, "0") + + // Spec: if not specified, effect is as if a value of "0" were specified + if(KSVG_TOKEN_NOT_PARSED(RefY)) + KSVG_SET_ALT_ATTRIBUTE(RefY, "0") + + // Spec: if not specified, effect is as if a value of "3" were specified + if(KSVG_TOKEN_NOT_PARSED(MarkerWidth)) + KSVG_SET_ALT_ATTRIBUTE(MarkerWidth, "3") + + // Spec: if not specified, effect is as if a value of "3" were specified + if(KSVG_TOKEN_NOT_PARSED(MarkerHeight)) + KSVG_SET_ALT_ATTRIBUTE(MarkerHeight, "3") + + // Spec: if attribute not specified, use strokeWidth + if(KSVG_TOKEN_NOT_PARSED(MarkerUnits)) + KSVG_SET_ALT_ATTRIBUTE(MarkerUnits, "strokeWidth") + + // Spec: if attribute not specified, use angle + if(KSVG_TOKEN_NOT_PARSED(Orient)) + KSVG_SET_ALT_ATTRIBUTE(Orient, "angle") +} + +void SVGMarkerElementImpl::createItem(KSVGCanvas *c) +{ + if(!c) + c = ownerDoc()->canvas(); + + if(!m_item) + { + m_item = c->createCanvasMarker(this); + c->insert(m_item); + } +} + +void SVGMarkerElementImpl::draw(SVGShapeImpl *referencingElement, double x, double y, double lwidth, double angle) +{ + SVGMatrixImpl *mtx = dynamic_cast(referencingElement)->getScreenCTM(); + + // move to dest + mtx->translate(x, y); + + // scale by linewidth if marker units == strokewidth + if(markerUnits()->baseVal() == SVG_MARKERUNITS_STROKEWIDTH) + mtx->scale(lwidth); + + // select appropriate rotation + if(orientType()->baseVal() == SVG_MARKER_ORIENT_AUTO) + mtx->rotate(angle); + else + mtx->rotate(orientAngle()->baseVal()->value()); + + SVGRectImpl *viewBoxRect = viewBox()->baseVal(); + SVGMatrixImpl *pres = preserveAspectRatio()->baseVal()->getCTM(viewBoxRect->x(), viewBoxRect->y(), + viewBoxRect->width(), viewBoxRect->height(), + 0, 0, markerWidth()->baseVal()->value(), + markerHeight()->baseVal()->value()); + + // viewbox stuff + mtx->multiply(pres); + + // Get the vertex position in viewbox coordinates. The vertex is at (0, 0) in viewport coordinates. + double vertexX, vertexY; + pres->qmatrix().invert().map(0, 0, &vertexX, &vertexY); + + // Translate so that the vertex is at (refX, refY) in viewbox coordinates. + mtx->translate(vertexX - refX()->baseVal()->value(), vertexY - refY()->baseVal()->value()); + + if(getOverflow()) + m_clipShape.clear(); + else + { + KSVGRectangle viewport; + + if(hasAttribute("viewBox")) + { + // Get the viewport ((0, 0) - (markerWidth, markerHeight)) in viewbox coordinates. + double w, h; + pres->qmatrix().invert().map(markerWidth()->baseVal()->value(), markerHeight()->baseVal()->value(), &w, &h); + + viewport = KSVGRectangle(vertexX, vertexY, w - vertexX, h - vertexY); + } + else + viewport = KSVGRectangle(0, 0, markerWidth()->baseVal()->value(), markerHeight()->baseVal()->value()); + + // Transform to screen coordinates. + m_clipShape = mtx->map(viewport); + } + + pres->deref(); + + DOM::Node node = firstChild(); + for(; !node.isNull(); node = node.nextSibling()) + { + SVGElementImpl *element = ownerDoc()->getElementFromHandle(node.handle()); + SVGShapeImpl *shape = dynamic_cast(element); + SVGTestsImpl *tests = dynamic_cast(element); + SVGStylableImpl *style = dynamic_cast(element); + + bool ok = tests ? tests->ok() : true; + if(element && shape && style && ok && style->getVisible() && style->getDisplay()) + { + SVGLocatableImpl *locatable = dynamic_cast(element); + if(locatable) + locatable->updateCachedScreenCTM(mtx); + + shape->update(UPDATE_TRANSFORM); + shape->setReferenced(true); + shape->draw(); + shape->setReferenced(false); + } + } + + mtx->deref(); +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGMarkerElementImpl::s_hashTable 11 + refX SVGMarkerElementImpl::RefX DontDelete|ReadOnly + refY SVGMarkerElementImpl::RefY DontDelete|ReadOnly + markerUnits SVGMarkerElementImpl::MarkerUnits DontDelete|ReadOnly + markerWidth SVGMarkerElementImpl::MarkerWidth DontDelete|ReadOnly + markerHeight SVGMarkerElementImpl::MarkerHeight DontDelete|ReadOnly + orientType SVGMarkerElementImpl::OrientType DontDelete|ReadOnly + orientAngle SVGMarkerElementImpl::OrientAngle DontDelete|ReadOnly + orient SVGMarkerElementImpl::Orient DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGMarkerElementImplProto::s_hashTable 3 + setOrientToAuto SVGMarkerElementImpl::SetOrientToAuto DontDelete|Function 0 + setOrientToAngle SVGMarkerElementImpl::SetOrientToAngle DontDelete|Function 0 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGMarkerElement", SVGMarkerElementImplProto, SVGMarkerElementImplProtoFunc) + +Value SVGMarkerElementImpl::getValueProperty(ExecState *exec, int token) const +{ + KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case RefX: + if(!attributeMode) + return m_refX->cache(exec); + else + return Number(m_refX->baseVal()->value()); + case RefY: + if(!attributeMode) + return m_refY->cache(exec); + else + return Number(m_refY->baseVal()->value()); + case MarkerUnits: + if(!attributeMode) + return m_markerUnits->cache(exec); + else + return Number(m_markerUnits->baseVal()); + case MarkerWidth: + if(!attributeMode) + return m_markerWidth->cache(exec); + else + return Number(m_markerWidth->baseVal()->value()); + case MarkerHeight: + if(!attributeMode) + return m_markerHeight->cache(exec); + else + return Number(m_markerHeight->baseVal()->value()); + case OrientType: + if(!attributeMode) + return m_orientType->cache(exec); + else + return Number(m_orientType->baseVal()); + case OrientAngle: + if(!attributeMode) + return m_orientAngle->cache(exec); + else + return Number(m_orientAngle->baseVal()->value()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGMarkerElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case RefX: + refX()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case RefY: + refY()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case MarkerWidth: + markerWidth()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case MarkerHeight: + markerHeight()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case MarkerUnits: + if(value.toString(exec).qstring() == "userSpaceOnUse") + markerUnits()->setBaseVal(SVG_MARKERUNITS_USERSPACEONUSE); + else + markerUnits()->setBaseVal(SVG_MARKERUNITS_STROKEWIDTH); + break; + case Orient: + { + QString param = value.toString(exec).qstring(); + + if(param == "auto") + orientType()->setBaseVal(SVG_MARKER_ORIENT_AUTO); + else + { + orientType()->setBaseVal(SVG_MARKER_ORIENT_ANGLE); + m_orientAngle->baseVal()->setValueAsString(param); + } + break; + } + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +Value SVGMarkerElementImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGMarkerElementImpl) + + switch(id) + { + case SVGMarkerElementImpl::SetOrientToAuto: + obj->setOrientToAuto(); + return Undefined(); +#ifdef __GNUC__ +#warning FIXME cache stuff +#endif + case SVGMarkerElementImpl::SetOrientToAngle: + obj->setOrientToAngle(static_cast *>(args[0].imp())->impl()); + return Undefined(); + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + +// CONSTANTS + +/* +@namespace KSVG +@begin SVGMarkerElementImplConstructor::s_hashTable 7 + SVG_MARKERUNITS_UNKNOWN KSVG::SVG_MARKERUNITS_UNKNOWN DontDelete|ReadOnly + SVG_MARKERUNITS_USERSPACEONUSE KSVG::SVG_MARKERUNITS_USERSPACEONUSE DontDelete|ReadOnly + SVG_MARKERUNITS_STROKEWIDTH KSVG::SVG_MARKERUNITS_STROKEWIDTH DontDelete|ReadOnly + SVG_MARKER_ORIENT_UNKNOWN KSVG::SVG_MARKER_ORIENT_UNKNOWN DontDelete|ReadOnly + SVG_MARKER_ORIENT_AUTO KSVG::SVG_MARKER_ORIENT_AUTO DontDelete|ReadOnly + SVG_MARKER_ORIENT_ANGLE KSVG::SVG_MARKER_ORIENT_ANGLE DontDelete|ReadOnly +@end +*/ + +using namespace KJS; + +Value SVGMarkerElementImplConstructor::getValueProperty(ExecState *, int token) const +{ + return Number(token); +} + +Value KSVG::getSVGMarkerElementImplConstructor(ExecState *exec) +{ + return cacheGlobalBridge(exec, "[[svgmarkerelement.constructor]]"); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGMarkerElementImpl.h b/ksvg/impl/SVGMarkerElementImpl.h new file mode 100644 index 00000000..7e6539e3 --- /dev/null +++ b/ksvg/impl/SVGMarkerElementImpl.h @@ -0,0 +1,121 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGMarkerElementImpl_H +#define SVGMarkerElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGStylableImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGContainerImpl.h" +#include "SVGFitToViewBoxImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" +#include "KSVGHelper.h" + +namespace KSVG +{ + +class SVGAngleImpl; +class SVGAnimatedAngleImpl; +class SVGAnimatedLengthImpl; +class SVGAnimatedEnumerationImpl; +class SVGMarkerElementImpl : public SVGContainerImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGFitToViewBoxImpl +{ +public: + SVGMarkerElementImpl(DOM::ElementImpl *); + virtual ~SVGMarkerElementImpl(); + + SVGAnimatedLengthImpl *refX() const; + SVGAnimatedLengthImpl *refY() const; + SVGAnimatedEnumerationImpl *markerUnits() const; + SVGAnimatedLengthImpl *markerWidth() const; + SVGAnimatedLengthImpl *markerHeight() const; + SVGAnimatedEnumerationImpl *orientType() const; + SVGAnimatedAngleImpl *orientAngle() const; + + void setOrientToAuto(); + void setOrientToAngle(SVGAngleImpl *angle); + + virtual void setAttributes(); + virtual void createItem(KSVGCanvas *c = 0); + + void draw(SVGShapeImpl *referencingElement, double x, double y, double lwidth, double angle); + + KSVGPolygon clipShape() const { return m_clipShape; } + + virtual bool directRender() { return false; } + virtual bool isContainer() const { return false; } + +private: + SVGAnimatedLengthImpl *m_refX; + SVGAnimatedLengthImpl *m_refY; + SVGAnimatedEnumerationImpl *m_markerUnits; + SVGAnimatedLengthImpl *m_markerWidth; + SVGAnimatedLengthImpl *m_markerHeight; + SVGAnimatedEnumerationImpl *m_orientType; + SVGAnimatedAngleImpl *m_orientAngle; + + KSVGPolygon m_clipShape; + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + RefX, RefY, MarkerUnits, MarkerWidth, MarkerHeight, OrientType, OrientAngle, + Orient, ViewBox, PreserveAspectRatio, + // Functions + SetOrientToAuto, SetOrientToAngle + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +class SVGMarkerElementImplConstructor : public KJS::ObjectImp +{ +public: + SVGMarkerElementImplConstructor(KJS::ExecState *) { } + KJS::Value getValueProperty(KJS::ExecState *, int token) const; + + // no put - all read-only + KSVG_GET +}; + +KJS::Value getSVGMarkerElementImplConstructor(KJS::ExecState *exec); + +KSVG_REGISTER_ELEMENT(SVGMarkerElementImpl, "marker") + +} + +KSVG_DEFINE_PROTOTYPE(SVGMarkerElementImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGMarkerElementImplProtoFunc, SVGMarkerElementImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGMaskElementImpl.cc b/ksvg/impl/SVGMaskElementImpl.cc new file mode 100644 index 00000000..5cd2151e --- /dev/null +++ b/ksvg/impl/SVGMaskElementImpl.cc @@ -0,0 +1,542 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include +#include + +#include "SVGMaskElement.h" + +#include "SVGRectImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGMaskElementImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGAnimatedEnumerationImpl.h" +#include "SVGUnitConverter.h" +#include "SVGShapeImpl.h" +#include "SVGMatrixImpl.h" +#include "KSVGCanvas.h" +#include "CanvasItems.h" +#include "CanvasFactory.h" +#include "KSVGHelper.h" + +#include + +using namespace KSVG; + +#include "SVGMaskElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_ecma.h" + +SVGMaskElementImpl::SVGMaskElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGBBoxTarget() +{ + KSVG_EMPTY_FLAGS + + m_x = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_x->ref(); + + m_y = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_y->ref(); + + m_width = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_width->ref(); + + m_height = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_height->ref(); + + m_maskUnits = new SVGAnimatedEnumerationImpl(); + m_maskUnits->ref(); + + m_maskContentUnits = new SVGAnimatedEnumerationImpl(); + m_maskContentUnits->ref(); + + m_converter = new SVGUnitConverter(); + m_converter->add(m_x); + m_converter->add(m_y); + m_converter->add(m_width); + m_converter->add(m_height); + + m_canvas = 0; + + m_maskCache.setMaxTotalCost(1024 * 1024); +} + +SVGMaskElementImpl::~SVGMaskElementImpl() +{ + if(m_x) + m_x->deref(); + if(m_y) + m_y->deref(); + if(m_width) + m_width->deref(); + if(m_height) + m_height->deref(); + if(m_maskUnits) + m_maskContentUnits->deref(); + if(m_maskUnits) + m_maskContentUnits->deref(); + delete m_converter; + if(m_canvas) + delete m_canvas; +} + +SVGAnimatedEnumerationImpl *SVGMaskElementImpl::maskUnits() const +{ + return m_maskUnits; +} + +SVGAnimatedEnumerationImpl *SVGMaskElementImpl::maskContentUnits() const +{ + return m_maskContentUnits; +} + +SVGAnimatedLengthImpl *SVGMaskElementImpl::x() const +{ + return m_x; +} + +SVGAnimatedLengthImpl *SVGMaskElementImpl::y() const +{ + return m_y; +} + +SVGAnimatedLengthImpl *SVGMaskElementImpl::width() const +{ + return m_width; +} + +SVGAnimatedLengthImpl *SVGMaskElementImpl::height() const +{ + return m_height; +} + +/* +@namespace KSVG +@begin SVGMaskElementImpl::s_hashTable 7 + maskUnits SVGMaskElementImpl::MaskUnits DontDelete|ReadOnly + maskContentUnits SVGMaskElementImpl::MaskContentUnits DontDelete|ReadOnly + x SVGMaskElementImpl::X DontDelete|ReadOnly + y SVGMaskElementImpl::Y DontDelete|ReadOnly + width SVGMaskElementImpl::Width DontDelete|ReadOnly + height SVGMaskElementImpl::Height DontDelete|ReadOnly +@end +*/ +Value SVGMaskElementImpl::getValueProperty(ExecState *exec, int token) const +{ + KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case MaskUnits: + if(!attributeMode) + return m_maskUnits->cache(exec); + else + return Number(m_maskUnits->baseVal()); + case MaskContentUnits: + if(!attributeMode) + return m_maskContentUnits->cache(exec); + else + return Number(m_maskContentUnits->baseVal()); + case X: + if(!attributeMode) + return m_x->cache(exec); + else + return Number(m_x->baseVal()->value()); + case Y: + if(!attributeMode) + return m_y->cache(exec); + else + return Number(m_y->baseVal()->value()); + case Width: + if(!attributeMode) + return m_width->cache(exec); + else + return Number(m_width->baseVal()->value()); + + case Height: + if(!attributeMode) + return m_height->cache(exec); + else + return Number(m_height->baseVal()->value()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGMaskElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case MaskUnits: + if(value.toString(exec).qstring() == "objectBoundingBox") + m_maskUnits->setBaseVal(SVGMaskElement::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX); + else + m_maskUnits->setBaseVal(SVGMaskElement::SVG_UNIT_TYPE_USERSPACEONUSE); + break; + case MaskContentUnits: + if(value.toString(exec).qstring() == "objectBoundingBox") + m_maskContentUnits->setBaseVal(SVGMaskElement::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX); + else + m_maskContentUnits->setBaseVal(SVGMaskElement::SVG_UNIT_TYPE_USERSPACEONUSE); + break; + case X: + converter()->modify(x(), value.toString(exec).qstring()); + break; + case Y: + converter()->modify(y(), value.toString(exec).qstring()); + break; + case Width: + converter()->modify(width(), value.toString(exec).qstring()); + break; + case Height: + converter()->modify(height(), value.toString(exec).qstring()); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +SVGRectImpl *SVGMaskElementImpl::getBBox() +{ + SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect(); + ret->setX(m_x->baseVal()->value()); + ret->setY(m_y->baseVal()->value()); + ret->setWidth(m_width->baseVal()->value()); + ret->setHeight(m_height->baseVal()->value()); + return ret; +} + +void SVGMaskElementImpl::setAttributes() +{ + SVGElementImpl::setAttributes(); + + // Spec: if attribute not specified, use objectBoundingBox + if(KSVG_TOKEN_NOT_PARSED(MaskUnits)) + KSVG_SET_ALT_ATTRIBUTE(MaskUnits, "objectBoundingBox") + + // Spec: if attribute not specified, use userSpaceOnUse + if(KSVG_TOKEN_NOT_PARSED(MaskContentUnits)) + KSVG_SET_ALT_ATTRIBUTE(MaskContentUnits, "userSpaceOnUse") + + // Spec: if attribute not specified, use "-10%" + if(KSVG_TOKEN_NOT_PARSED(X)) + KSVG_SET_ALT_ATTRIBUTE(X, "-10%"); + + // Spec: if attribute not specified, use "-10%" + if(KSVG_TOKEN_NOT_PARSED(Y)) + KSVG_SET_ALT_ATTRIBUTE(Y, "-10%"); + + // Spec: if attribute not specified, use "120%" + if(KSVG_TOKEN_NOT_PARSED(Width)) + KSVG_SET_ALT_ATTRIBUTE(Width, "120%"); + + // Spec: if attribute not specified, use "120%" + if(KSVG_TOKEN_NOT_PARSED(Height)) + KSVG_SET_ALT_ATTRIBUTE(Height, "120%"); +} + +SVGMaskElementImpl::Mask SVGMaskElementImpl::createMask(SVGShapeImpl *referencingElement, int imageWidth, int imageHeight) +{ + converter()->finalize(referencingElement, ownerSVGElement(), maskUnits()->baseVal()); + + Q_UINT32 *imageBits = new Q_UINT32[imageWidth * imageHeight]; + + if(m_canvas == 0) + m_canvas = CanvasFactory::self()->loadCanvas(imageWidth, imageHeight); + + m_canvas->setup(reinterpret_cast(imageBits), imageWidth, imageHeight); + m_canvas->setBackgroundColor(qRgba(0, 0, 0, 0)); + + SVGMatrixImpl *baseMatrix = SVGSVGElementImpl::createSVGMatrix(); + + // Set the scale to map the mask onto the image + double xScale = static_cast(imageWidth) / width()->baseVal()->value(); + double yScale = static_cast(imageHeight) / height()->baseVal()->value(); + + baseMatrix->scaleNonUniform(xScale, yScale); + + SVGRectImpl *bbox = referencingElement->getBBox(); + + if(maskUnits()->baseVal() == SVGMaskElement::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) + baseMatrix->translate(-(bbox->x() + x()->baseVal()->value()), -(bbox->y() + y()->baseVal()->value())); + else + baseMatrix->translate(-x()->baseVal()->value(), -y()->baseVal()->value()); + + if(maskContentUnits()->baseVal() == SVGMaskElement::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) + { + baseMatrix->translate(bbox->x(), bbox->y()); + baseMatrix->scaleNonUniform(bbox->width(), bbox->height()); + } + + for(DOM::Node node = firstChild(); !node.isNull(); node = node.nextSibling()) + { + SVGElementImpl *element = ownerDoc()->getElementFromHandle(node.handle()); + SVGShapeImpl *shape = dynamic_cast(element); + SVGTestsImpl *tests = dynamic_cast(element); + SVGStylableImpl *style = dynamic_cast(element); + + bool ok = tests ? tests->ok() : true; + if(element && shape && style && ok && style->getVisible() && style->getDisplay()) + { + SVGLocatableImpl *locatable = dynamic_cast(element); + if(locatable) + locatable->updateCachedScreenCTM(baseMatrix); + + element->createItem(m_canvas); + if(shape->item()) + { + shape->item()->setReferenced(true); + m_canvas->invalidate(shape->item(), true); + } + } + } + + m_canvas->update(float(1)); + + for(DOM::Node node = firstChild(); !node.isNull(); node = node.nextSibling()) + { + SVGElementImpl *element = ownerDoc()->getElementFromHandle(node.handle()); + SVGShapeImpl *shape = dynamic_cast(element); + SVGTestsImpl *tests = dynamic_cast(element); + SVGStylableImpl *style = dynamic_cast(element); + + bool ok = tests ? tests->ok() : true; + if(element && shape && style && ok && style->getVisible() && style->getDisplay()) + { + if(shape) + shape->removeItem(m_canvas); + } + } + + + { + // Note: r and b reversed + //QImage maskImage(reinterpret_cast(imageBits), imageWidth, imageHeight, 32, 0, 0, QImage::IgnoreEndian); + //maskImage.setAlphaBuffer(true); + //maskImage.save("mask.png", "PNG"); + } + + QByteArray maskData(imageWidth * imageHeight); + const double epsilon = DBL_EPSILON; + + // Convert the rgba image into an 8-bit mask, according to the specs. + for(int i = 0; i < imageWidth * imageHeight; i++) + { + Q_UINT32 rgba = imageBits[i]; + +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + double r = (rgba & 0xff) / 255.0; + double g = ((rgba >> 8) & 0xff) / 255.0; + double b = ((rgba >> 16) & 0xff) / 255.0; + double a = ((rgba >> 24) & 0xff) / 255.0; +#else + double a = (rgba & 0xff) / 255.0; + double b = ((rgba >> 8) & 0xff) / 255.0; + double g = ((rgba >> 16) & 0xff) / 255.0; + double r = ((rgba >> 24) & 0xff) / 255.0; +#endif + + // Remove pre-multiplication by alpha. + if(a > epsilon) + { + r /= a; + g /= a; + b /= a; + } + + // Convert to linear RGB + r = KSVGHelper::linearRGBFromsRGB(int(r * 255 + 0.5)) / 255.0; + g = KSVGHelper::linearRGBFromsRGB(int(g * 255 + 0.5)) / 255.0; + b = KSVGHelper::linearRGBFromsRGB(int(b * 255 + 0.5)) / 255.0; + + // Convert 'luminance to alpha' + double luminanceAlpha = 0.2125 * r + 0.7154 * g + 0.0721 * b; + + // Multiply by alpha. + double maskValue = luminanceAlpha * a; + + maskData[i] = static_cast(maskValue * 255 + 0.5); + } + + delete [] imageBits; + + baseMatrix->deref(); + bbox->deref(); + + // The screenToMask matrix is calculated each time the mask is used so we don't + // need to set it here. + QWMatrix tempMatrix; + + return Mask(maskData, tempMatrix, imageWidth, imageHeight); +} + +SVGMaskElementImpl::Mask SVGMaskElementImpl::createMask(SVGShapeImpl *referencingElement) +{ + converter()->finalize(referencingElement, ownerSVGElement(), maskUnits()->baseVal()); + + SVGMatrixImpl *refCTM = 0; + SVGLocatableImpl *locatableRef = dynamic_cast(referencingElement); + if(locatableRef) + refCTM = locatableRef->getScreenCTM(); + else + refCTM = SVGSVGElementImpl::createSVGMatrix(); + + double xScale, yScale; + + refCTM->removeScale(&xScale, &yScale); + refCTM->deref(); + + int imageWidth = static_cast(width()->baseVal()->value() * xScale + 0.5); + int imageHeight = static_cast(height()->baseVal()->value() * yScale + 0.5); + + Mask mask; + + if(imageWidth > 0 && imageHeight > 0) + { + CacheKey key(referencingElement, imageWidth, imageHeight); + + if(!m_maskCache.find(key, mask)) + { + mask = createMask(referencingElement, imageWidth, imageHeight); + m_maskCache.insert(key, mask, imageWidth * imageHeight); + } + + // Generate a mask-coordinates to screen-coordinates matrix + SVGMatrixImpl *matrix = 0; + if(locatableRef) + matrix = locatableRef->getScreenCTM(); + else + matrix = SVGSVGElementImpl::createSVGMatrix(); + + if(maskUnits()->baseVal() == SVGMaskElement::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) + { + SVGRectImpl *bbox = referencingElement->getBBox(); + matrix->translate(bbox->x() + x()->baseVal()->value(), bbox->y() + y()->baseVal()->value()); + bbox->deref(); + } + else + matrix->translate(x()->baseVal()->value(), y()->baseVal()->value()); + + matrix->scaleNonUniform(1 / xScale, 1 / yScale); + + QWMatrix screenToMask = matrix->qmatrix().invert(); + matrix->deref(); + + mask.setScreenToMask(screenToMask); + } + + return mask; +} + +QByteArray SVGMaskElementImpl::maskRectangle(SVGShapeImpl *shape, const QRect& screenRectangle) +{ + QByteArray cumulativeMask; + + do + { + SVGStylableImpl *style = dynamic_cast(shape); + + if(style && style->hasMask()) + { + SVGElementImpl *element = shape->ownerDoc()->rootElement()->getElementById(style->getMask()); + + if(element) + { + SVGMaskElementImpl *maskElement = dynamic_cast(element); + + if(maskElement) + { + SVGMaskElementImpl::Mask mask = maskElement->createMask(shape); + + if(!mask.isEmpty()) + { + QByteArray maskData = mask.rectangle(screenRectangle); + + if(cumulativeMask.size() == 0) + cumulativeMask = maskData; + else + { + int size = cumulativeMask.size(); + + // Multiply into the cumulative mask (using fast divide by 255) + for(int i = 0; i < size; i++) + { + int tmp = maskData[i] * cumulativeMask[i] + 0x80; + cumulativeMask[i] = (tmp + (tmp >> 8)) >> 8; + } + } + } + } + } + } + + DOM::Node parentNode = shape->parentNode(); + + if(!parentNode.isNull()) + { + SVGElementImpl *parent = shape->ownerDoc()->getElementFromHandle(parentNode.handle()); + + if(parent) + shape = dynamic_cast(parent); + else + shape = 0; + } + else + shape = 0; + + } while(shape); + + return cumulativeMask; +} + +SVGMaskElementImpl::Mask::Mask(const QByteArray& mask, const QWMatrix& screenToMask, int width, int height) + : m_width(width), m_height(height), m_mask(mask), m_screenToMask(screenToMask) +{ +} + +QByteArray SVGMaskElementImpl::Mask::rectangle(int screenX, int screenY, int width, int height) +{ + QByteArray rect(width * height); + + for(int x = 0; x < width; x++) + { + for(int y = 0; y < height; y++) + { + rect[x + y * width] = value(screenX + x, screenY + y); + } + } + + return rect; +} + +QByteArray SVGMaskElementImpl::Mask::rectangle(const QRect& rect) +{ + return rectangle(rect.x(), rect.y(), rect.width(), rect.height()); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGMaskElementImpl.h b/ksvg/impl/SVGMaskElementImpl.h new file mode 100644 index 00000000..cdd1c125 --- /dev/null +++ b/ksvg/impl/SVGMaskElementImpl.h @@ -0,0 +1,158 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGMaskElementImpl_H +#define SVGMaskElementImpl_H + +#include + +#include "SVGTestsImpl.h" +#include "SVGBBoxTarget.h" +#include "SVGElementImpl.h" +#include "SVGStylableImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" +#include "LRUCache.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + + +class SVGUnitConverter; +class KSVGCanvas; +class SVGShapeImpl; +class SVGRectImpl; +class SVGAnimatedLengthImpl; +class SVGAnimatedEnumerationImpl; +class SVGMaskElementImpl : public SVGElementImpl, + public SVGTestsImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGBBoxTarget +{ +public: + + class Mask + { + public: + Mask() : m_width(0), m_height(0) {} + Mask(const QByteArray& mask, const QWMatrix& screenToMask, int width, int height); + ~Mask() {} + + bool isEmpty() const { return m_width == 0; } + unsigned char value(int screenX, int screenY) const; + QByteArray rectangle(int screenX, int screenY, int width, int height); + QByteArray rectangle(const QRect& rect); + void setScreenToMask(const QWMatrix& matrix) { m_screenToMask = matrix; } + + private: + int m_width; + int m_height; + QByteArray m_mask; + QWMatrix m_screenToMask; + }; + + SVGMaskElementImpl(DOM::ElementImpl *); + virtual ~SVGMaskElementImpl(); + + SVGAnimatedEnumerationImpl *maskUnits() const; + SVGAnimatedEnumerationImpl *maskContentUnits() const; + SVGAnimatedLengthImpl *x() const; + SVGAnimatedLengthImpl *y() const; + SVGAnimatedLengthImpl *width() const; + SVGAnimatedLengthImpl *height() const; + + virtual SVGRectImpl *getBBox(); + virtual void setAttributes(); + + SVGUnitConverter *converter() const { return m_converter; } + + Mask createMask(SVGShapeImpl *referencingElement); + + // Compute the mask on a given shape, taking into account all masks defined + // on the shape's ancestors. This is a workaround for us not having a buffer + // for container elements, so we can't mask containers directly. + static QByteArray maskRectangle(SVGShapeImpl *shape, const QRect& screenRectangle); + +private: + class CacheKey + { + public: + CacheKey() : m_element(0), m_width(0), m_height(0) {} + CacheKey(SVGElementImpl *element, int width, int height) : m_element(element), m_width(width), m_height(height) {} + bool operator==(const CacheKey& other) const { return m_element == other.m_element && m_width == other.m_width && m_height == other.m_height; } + + private: + SVGElementImpl *m_element; + int m_width; + int m_height; + }; + + Mask createMask(SVGShapeImpl *referencingElement, int imageWidth, int imageHeight); + + SVGAnimatedEnumerationImpl *m_maskUnits; + SVGAnimatedEnumerationImpl *m_maskContentUnits; + SVGAnimatedLengthImpl *m_x; + SVGAnimatedLengthImpl *m_y; + SVGAnimatedLengthImpl *m_width; + SVGAnimatedLengthImpl *m_height; + + SVGUnitConverter *m_converter; + KSVGCanvas *m_canvas; + + MinOneLRUCache m_maskCache; + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + MaskUnits, MaskContentUnits, X, Y, Width, Height + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGMaskElementImpl, "mask") + +inline unsigned char SVGMaskElementImpl::Mask::value(int screenX, int screenY) const +{ + int x, y; + + m_screenToMask.map(screenX, screenY, &x, &y); + + if(x >= 0 && x < m_width && y >= 0 && y < m_height) + return m_mask[x + y * m_width]; + else + return 0; +} + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGMatrixImpl.cc b/ksvg/impl/SVGMatrixImpl.cc new file mode 100644 index 00000000..81f14f66 --- /dev/null +++ b/ksvg/impl/SVGMatrixImpl.cc @@ -0,0 +1,460 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include + +#include "SVGAngleImpl.h" +#include "SVGMatrixImpl.h" +#include "KSVGHelper.h" + +using namespace KSVG; + +#include "SVGMatrixImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGMatrixImpl::SVGMatrixImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGMatrixImpl::SVGMatrixImpl(QWMatrix mat) +{ + m_mat = mat; +} + +SVGMatrixImpl::SVGMatrixImpl(double a, double b, double c, double d, double e, double f) +{ + m_mat.setMatrix(a, b, c, d, e, f); +} + +SVGMatrixImpl::~SVGMatrixImpl() +{ +} + +void SVGMatrixImpl::setA(const double &a) +{ + m_mat.setMatrix(a, m_mat.m12(), m_mat.m21(), m_mat.m22(), m_mat.dx(), m_mat.dy()); +} + +double SVGMatrixImpl::a() const +{ + return m_mat.m11(); +} + +void SVGMatrixImpl::setB(const double &b) +{ + m_mat.setMatrix(m_mat.m11(), b, m_mat.m21(), m_mat.m22(), m_mat.dx(), m_mat.dy()); +} + +double SVGMatrixImpl::b() const +{ + return m_mat.m12(); +} + +void SVGMatrixImpl::setC(const double &c) +{ + m_mat.setMatrix(m_mat.m11(), m_mat.m12(), c, m_mat.m22(), m_mat.dx(), m_mat.dy()); +} + +double SVGMatrixImpl::c() const +{ + return m_mat.m21(); +} + +void SVGMatrixImpl::setD(const double &d) +{ + m_mat.setMatrix(m_mat.m11(), m_mat.m12(), m_mat.m21(), d, m_mat.dx(), m_mat.dy()); +} + +double SVGMatrixImpl::d() const +{ + return m_mat.m22(); +} + +void SVGMatrixImpl::setE(const double &e) +{ + m_mat.setMatrix(m_mat.m11(), m_mat.m12(), m_mat.m21(), m_mat.m22(), e, m_mat.dy()); +} + +double SVGMatrixImpl::e() const +{ + return m_mat.dx(); +} + +void SVGMatrixImpl::setF(const double &f) +{ + m_mat.setMatrix(m_mat.m11(), m_mat.m12(), m_mat.m21(), m_mat.m22(), m_mat.dx(), f); +} + +double SVGMatrixImpl::f() const +{ + return m_mat.dy(); +} + +void SVGMatrixImpl::copy(const SVGMatrixImpl *other) +{ + m_mat.setMatrix(other->m_mat.m11(), other->m_mat.m12(), other->m_mat.m21(), other->m_mat.m22(), other->m_mat.dx(), other->m_mat.dy()); +} + +SVGMatrixImpl *SVGMatrixImpl::postMultiply(const SVGMatrixImpl *secondMatrix) +{ + QWMatrix temp(secondMatrix->a(), secondMatrix->b(), secondMatrix->c(), secondMatrix->d(), secondMatrix->e(), secondMatrix->f()); + m_mat *= temp; + return this; +} + +SVGMatrixImpl *SVGMatrixImpl::inverse() +{ + m_mat = m_mat.invert(); + return this; +} + +SVGMatrixImpl *SVGMatrixImpl::postTranslate(const double &x, const double &y) +{ + // Could optimise these. + QWMatrix temp; + temp.translate(x, y); + m_mat *= temp; + return this; +} + +SVGMatrixImpl *SVGMatrixImpl::postScale(const double &scaleFactor) +{ + QWMatrix temp; + temp.scale(scaleFactor, scaleFactor); + m_mat *= temp; + return this; +} + +SVGMatrixImpl *SVGMatrixImpl::postScaleNonUniform(const double &scaleFactorX, const double &scaleFactorY) +{ + QWMatrix temp; + temp.scale(scaleFactorX, scaleFactorY); + m_mat *= temp; + return this; +} + +SVGMatrixImpl *SVGMatrixImpl::postRotate(const double &angle) +{ + QWMatrix temp; + temp.rotate(angle); + m_mat *= temp; + return this; +} + +SVGMatrixImpl *SVGMatrixImpl::postRotateFromVector(const double &x, const double &y) +{ + QWMatrix temp; + temp.rotate(SVGAngleImpl::todeg(atan2(y, x))); + m_mat *= temp; + return this; +} + +SVGMatrixImpl *SVGMatrixImpl::postFlipX() +{ + QWMatrix temp(-1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F); + m_mat *= temp; + return this; +} + +SVGMatrixImpl *SVGMatrixImpl::postFlipY() +{ + QWMatrix temp(1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F); + m_mat *= temp; + return this; +} + +SVGMatrixImpl *SVGMatrixImpl::postSkewX(const double &angle) +{ + QWMatrix temp; + temp.shear(tan(SVGAngleImpl::torad(angle)), 0.0F); + m_mat *= temp; + return this; +} + +SVGMatrixImpl *SVGMatrixImpl::postSkewY(const double &angle) +{ + QWMatrix temp; + temp.shear(0.0F, tan(SVGAngleImpl::torad(angle))); + m_mat *= temp; + return this; +} + +SVGMatrixImpl *SVGMatrixImpl::multiply(const SVGMatrixImpl *secondMatrix) +{ + QWMatrix temp(secondMatrix->a(), secondMatrix->b(), secondMatrix->c(), secondMatrix->d(), secondMatrix->e(), secondMatrix->f()); + temp *= m_mat; + m_mat = temp; + return this; +} + +SVGMatrixImpl *SVGMatrixImpl::translate(const double &x, const double &y) +{ + m_mat.translate(x, y); + return this; +} + +SVGMatrixImpl *SVGMatrixImpl::scale(const double &scaleFactor) +{ + m_mat.scale(scaleFactor, scaleFactor); + return this; +} + +SVGMatrixImpl *SVGMatrixImpl::scaleNonUniform(const double &scaleFactorX, const double &scaleFactorY) +{ + m_mat.scale(scaleFactorX, scaleFactorY); + return this; +} + +SVGMatrixImpl *SVGMatrixImpl::rotate(const double &angle) +{ + m_mat.rotate(angle); + return this; +} + +SVGMatrixImpl *SVGMatrixImpl::rotateFromVector(const double &x, const double &y) +{ + m_mat.rotate(SVGAngleImpl::todeg(atan2(y, x))); + return this; +} + +SVGMatrixImpl *SVGMatrixImpl::flipX() +{ + m_mat.scale(-1.0f, 1.0f); + return this; +} + +SVGMatrixImpl *SVGMatrixImpl::flipY() +{ + m_mat.scale(1.0f, -1.0f); + return this; +} + +SVGMatrixImpl *SVGMatrixImpl::skewX(const double &angle) +{ + m_mat.shear(tan(SVGAngleImpl::torad(angle)), 0.0F); + return this; +} + +SVGMatrixImpl *SVGMatrixImpl::skewY(const double &angle) +{ + m_mat.shear(0.0F, tan(SVGAngleImpl::torad(angle))); + return this; +} + +void SVGMatrixImpl::setMatrix(QWMatrix mat) +{ + m_mat = mat; +} + +QWMatrix &SVGMatrixImpl::qmatrix() +{ + return m_mat; +} + +const QWMatrix &SVGMatrixImpl::qmatrix() const +{ + return m_mat; +} + +void SVGMatrixImpl::reset() +{ + m_mat.reset(); +} + +void SVGMatrixImpl::removeScale(double *xScale, double *yScale) +{ + double sx = sqrt(a()*a() + b()*b()); + double sy = sqrt(c()*c() + d()*d()); + + // Remove the scaling from the matrix. + + setA(a()/sx); + setB(b()/sx); + setC(c()/sy); + setD(d()/sy); + + *xScale = sx; + *yScale = sy; +} + +KSVGPolygon SVGMatrixImpl::map(const KSVGPolygon& polygon) const +{ + KSVGPolygon mapped; + + for(unsigned int i = 0; i < polygon.numPoints(); i++) + { + double x, y; + + m_mat.map(polygon.point(i).x(), polygon.point(i).y(), &x, &y); + mapped.addPoint(x, y); + } + + return mapped; +} + +KSVGPolygon SVGMatrixImpl::inverseMap(const KSVGPolygon& polygon) const +{ + QWMatrix inverse = m_mat.invert(); + KSVGPolygon mapped; + + for(unsigned int i = 0; i < polygon.numPoints(); i++) + { + double x, y; + + inverse.map(polygon.point(i).x(), polygon.point(i).y(), &x, &y); + mapped.addPoint(x, y); + } + + return mapped; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGMatrixImpl::s_hashTable 7 + a SVGMatrixImpl::A DontDelete + b SVGMatrixImpl::B DontDelete + c SVGMatrixImpl::C DontDelete + d SVGMatrixImpl::D DontDelete + e SVGMatrixImpl::E DontDelete + f SVGMatrixImpl::F DontDelete +@end +@namespace KSVG +@begin SVGMatrixImplProto::s_hashTable 13 + inverse SVGMatrixImpl::Inverse DontDelete|Function 0 + multiply SVGMatrixImpl::Multiply DontDelete|Function 1 + translate SVGMatrixImpl::Translate DontDelete|Function 2 + scale SVGMatrixImpl::Scale DontDelete|Function 1 + rotate SVGMatrixImpl::Rotate DontDelete|Function 1 + rotateFromVector SVGMatrixImpl::RotateFromVector DontDelete|Function 2 + scaleNonUniform SVGMatrixImpl::ScaleNonUniform DontDelete|Function 2 + flipX SVGMatrixImpl::FlipX DontDelete|Function 0 + flipY SVGMatrixImpl::FlipY DontDelete|Function 0 + skewX SVGMatrixImpl::SkewX DontDelete|Function 1 + skewY SVGMatrixImpl::SkewY DontDelete|Function 1 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGMatrix", SVGMatrixImplProto, SVGMatrixImplProtoFunc) + +Value SVGMatrixImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case A: + return Number(a()); + case B: + return Number(b()); + case C: + return Number(c()); + case D: + return Number(d()); + case E: + return Number(e()); + case F: + return Number(f()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return KJS::Undefined(); + } +} + + +void SVGMatrixImpl::putValueProperty(ExecState *exec, int token, const KJS::Value &value, int) +{ + switch(token) + { + case A: + setA(value.toNumber(exec)); + break; + case B: + setB(value.toNumber(exec)); + break; + case C: + setC(value.toNumber(exec)); + break; + case D: + setD(value.toNumber(exec)); + break; + case E: + setE(value.toNumber(exec)); + break; + case F: + setF(value.toNumber(exec)); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + break; + } +} + +Value SVGMatrixImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGMatrixImpl) + + switch(id) + { + case SVGMatrixImpl::Inverse: + return obj->inverse()->cache(exec); + break; + case SVGMatrixImpl::Multiply: + return obj->multiply(static_cast *>(args[0].imp())->impl())->cache(exec); + break; + case SVGMatrixImpl::Translate: + return obj->translate(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec); + break; + case SVGMatrixImpl::Scale: + return obj->scale(args[0].toNumber(exec))->cache(exec); + break; + case SVGMatrixImpl::Rotate: + return obj->rotate(args[0].toNumber(exec))->cache(exec); + break; + case SVGMatrixImpl::RotateFromVector: + return obj->rotateFromVector(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec); + break; + case SVGMatrixImpl::ScaleNonUniform: + return obj->scaleNonUniform(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec); + break; + case SVGMatrixImpl::FlipX: + return obj->flipX()->cache(exec); + break; + case SVGMatrixImpl::FlipY: + return obj->flipY()->cache(exec); + break; + case SVGMatrixImpl::SkewX: + return obj->skewX(args[0].toNumber(exec))->cache(exec); + break; + case SVGMatrixImpl::SkewY: + return obj->skewY(args[0].toNumber(exec))->cache(exec);; + break; + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGMatrixImpl.h b/ksvg/impl/SVGMatrixImpl.h new file mode 100644 index 00000000..a5d8edf3 --- /dev/null +++ b/ksvg/impl/SVGMatrixImpl.h @@ -0,0 +1,130 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGMatrixImpl_H +#define SVGMatrixImpl_H + +#include + +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ +class KSVGPolygon; + +class SVGMatrixImpl : public DOM::DomShared +{ +public: + SVGMatrixImpl(); + SVGMatrixImpl(QWMatrix mat); + SVGMatrixImpl(double, double, double, double, double, double); + ~SVGMatrixImpl(); + + void setA(const double &); + double a() const; + + void setB(const double &); + double b() const; + + void setC(const double &); + double c() const; + + void setD(const double &); + double d() const; + + void setE(const double &); + double e() const; + + void setF(const double &); + double f() const; + + void copy(const SVGMatrixImpl *other); + + SVGMatrixImpl *inverse(); + + // Pre-multiplied operations, as per the specs. + SVGMatrixImpl *multiply(const SVGMatrixImpl *secondMatrix); + SVGMatrixImpl *translate(const double &x, const double &y); + SVGMatrixImpl *scale(const double &scaleFactor); + SVGMatrixImpl *scaleNonUniform(const double &scaleFactorX, const double &scaleFactorY); + SVGMatrixImpl *rotate(const double &angle); + SVGMatrixImpl *rotateFromVector(const double &x, const double &y); + SVGMatrixImpl *flipX(); + SVGMatrixImpl *flipY(); + SVGMatrixImpl *skewX(const double &angle); + SVGMatrixImpl *skewY(const double &angle); + + // Post-multiplied operations + SVGMatrixImpl *postMultiply(const SVGMatrixImpl *secondMatrix); + SVGMatrixImpl *postTranslate(const double &x, const double &y); + SVGMatrixImpl *postScale(const double &scaleFactor); + SVGMatrixImpl *postScaleNonUniform(const double &scaleFactorX, const double &scaleFactorY); + SVGMatrixImpl *postRotate(const double &angle); + SVGMatrixImpl *postRotateFromVector(const double &x, const double &y); + SVGMatrixImpl *postFlipX(); + SVGMatrixImpl *postFlipY(); + SVGMatrixImpl *postSkewX(const double &angle); + SVGMatrixImpl *postSkewY(const double &angle); + + void reset(); + + // KSVG helper method + QWMatrix &qmatrix(); + const QWMatrix &qmatrix() const; + + // Determine the scaling component of the matrix and factor it out. After + // this operation, the matrix has x and y scale of one. + void removeScale(double *xScale, double *yScale); + + KSVGPolygon map(const KSVGPolygon& polygon) const; + KSVGPolygon inverseMap(const KSVGPolygon& polygon) const; + +private: + void setMatrix(QWMatrix mat); + QWMatrix m_mat; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + A, B, C, D, E, F, + // Functions + Inverse, Multiply, Translate, Scale, Rotate, + RotateFromVector, ScaleNonUniform, + FlipX, FlipY, SkewX, SkewY + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +KSVG_DEFINE_PROTOTYPE(SVGMatrixImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGMatrixImplProtoFunc, SVGMatrixImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGMetadataElementImpl.cc b/ksvg/impl/SVGMetadataElementImpl.cc new file mode 100644 index 00000000..d55d4302 --- /dev/null +++ b/ksvg/impl/SVGMetadataElementImpl.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGMetadataElementImpl.h" + +using namespace KSVG; + +SVGMetadataElementImpl::SVGMetadataElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl) +{ +} + +SVGMetadataElementImpl::~SVGMetadataElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGMetadataElementImpl.h b/ksvg/impl/SVGMetadataElementImpl.h new file mode 100644 index 00000000..363a9c11 --- /dev/null +++ b/ksvg/impl/SVGMetadataElementImpl.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGMetadataElementImpl_H +#define SVGMetadataElementImpl_H + +#include "SVGElementImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGMetadataElementImpl : public SVGElementImpl +{ +public: + SVGMetadataElementImpl(DOM::ElementImpl *); + virtual ~SVGMetadataElementImpl(); + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGMissingGlyphElementImpl.cc b/ksvg/impl/SVGMissingGlyphElementImpl.cc new file mode 100644 index 00000000..986750c3 --- /dev/null +++ b/ksvg/impl/SVGMissingGlyphElementImpl.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGMissingGlyphElementImpl.h" + +using namespace KSVG; + +SVGMissingGlyphElementImpl::SVGMissingGlyphElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGStylableImpl(this) +{ +} + +SVGMissingGlyphElementImpl::~SVGMissingGlyphElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGMissingGlyphElementImpl.h b/ksvg/impl/SVGMissingGlyphElementImpl.h new file mode 100644 index 00000000..275aba86 --- /dev/null +++ b/ksvg/impl/SVGMissingGlyphElementImpl.h @@ -0,0 +1,47 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGMissingGlyphElementImpl_H +#define SVGMissingGlyphElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGElementImpl.h" +#include "SVGStylableImpl.h" + +namespace KSVG +{ + +class SVGMissingGlyphElementImpl : public SVGElementImpl, + public SVGStylableImpl +{ +public: + SVGMissingGlyphElementImpl(DOM::ElementImpl *); + virtual ~SVGMissingGlyphElementImpl(); +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGNumberImpl.cc b/ksvg/impl/SVGNumberImpl.cc new file mode 100644 index 00000000..b926e9c2 --- /dev/null +++ b/ksvg/impl/SVGNumberImpl.cc @@ -0,0 +1,83 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGNumberImpl.h" + +using namespace KSVG; + +#include "SVGNumberImpl.lut.h" +#include "ksvg_bridge.h" + +SVGNumberImpl::SVGNumberImpl() +{ + KSVG_EMPTY_FLAGS + + m_value = 0; +} + +SVGNumberImpl::~SVGNumberImpl() +{ +} + +void SVGNumberImpl::setValue(float value) +{ + m_value = value; +} + +float SVGNumberImpl::value() +{ + return m_value; +} + +/* +@namespace KSVG +@begin SVGNumberImpl::s_hashTable 2 + value SVGNumberImpl::Value DontDelete +@end +*/ + +Value SVGNumberImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case Value: + return Number(m_value); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } + + return Undefined(); +} + +void SVGNumberImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int) +{ + switch(token) + { + case Value: + m_value = value.toNumber(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGNumberImpl.h b/ksvg/impl/SVGNumberImpl.h new file mode 100644 index 00000000..d94b3d63 --- /dev/null +++ b/ksvg/impl/SVGNumberImpl.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGNumberImpl_H +#define SVGNumberImpl_H + +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGNumberImpl : public DOM::DomShared +{ +public: + SVGNumberImpl(); + virtual ~SVGNumberImpl(); + + void setValue(float value); + float value(); + +private: + float m_value; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + Value + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGNumberListImpl.cc b/ksvg/impl/SVGNumberListImpl.cc new file mode 100644 index 00000000..8048640c --- /dev/null +++ b/ksvg/impl/SVGNumberListImpl.cc @@ -0,0 +1,64 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGNumberListImpl.h" + +using namespace KSVG; + +#include "SVGNumberListImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGNumberListImpl::s_hashTable 2 + numberOfItems SVGListDefs::NumberOfItems DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGNumberListImplProto::s_hashTable 11 + getItem SVGListDefs::GetItem DontDelete|Function 1 + removeItem SVGListDefs::RemoveItem DontDelete|Function 1 + appendItem SVGListDefs::AppendItem DontDelete|Function 1 + initialize SVGListDefs::Initialize DontDelete|Function 1 + insertItemBefore SVGListDefs::InsertItemBefore DontDelete|Function 2 + replaceItem SVGListDefs::ReplaceItem DontDelete|Function 2 + clear SVGListDefs::Clear DontDelete|Function 0 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGNumberList", SVGNumberListImplProto, SVGNumberListImplProtoFunc) + +Value SVGNumberListImpl::getValueProperty(ExecState *exec, int token) const +{ + return SVGList::getValueProperty(exec, token); +} + +Value SVGNumberListImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGNumberListImpl) + + return obj->call(exec, static_cast *>(obj), args, id); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGNumberListImpl.h b/ksvg/impl/SVGNumberListImpl.h new file mode 100644 index 00000000..87dadb6f --- /dev/null +++ b/ksvg/impl/SVGNumberListImpl.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGNumberListImpl_H +#define SVGNumberListImpl_H + +#include "SVGList.h" + +#include "SVGNumberImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGNumberListImpl : public SVGList +{ +public: + KSVG_GET + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +} + +KSVG_DEFINE_PROTOTYPE(SVGNumberListImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGNumberListImplProtoFunc, SVGNumberListImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPaintImpl.cc b/ksvg/impl/SVGPaintImpl.cc new file mode 100644 index 00000000..c1818892 --- /dev/null +++ b/ksvg/impl/SVGPaintImpl.cc @@ -0,0 +1,175 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGPaint.h" +#include "SVGColor.h" + +#include "SVGPaintImpl.h" + +using namespace KSVG; + +#include "SVGPaintImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_cacheimpl.h" + +SVGPaintImpl::SVGPaintImpl(SVGElementImpl *object) : SVGColorImpl(object) +{ + m_paintType = SVG_PAINTTYPE_UNKNOWN; +} + +SVGPaintImpl::SVGPaintImpl(const SVGPaintImpl &other) : SVGColorImpl(other) +{ + (*this) = other; +} + +SVGPaintImpl::~SVGPaintImpl() +{ +} + +SVGPaintImpl &SVGPaintImpl::operator=(const SVGPaintImpl &other) +{ + m_uri = other.m_uri; + m_paintType = other.m_paintType; + + *(static_cast(this)) = other; + + return *this; +} + +unsigned short SVGPaintImpl::paintType() const +{ + return m_paintType; +} + +DOM::DOMString SVGPaintImpl::uri() const +{ + return m_uri; +} + +void SVGPaintImpl::setUri(const DOM::DOMString &uri) +{ + m_uri = uri; + m_paintType = SVG_PAINTTYPE_URI; +} + +void SVGPaintImpl::setPaint(unsigned short paintType, const DOM::DOMString &/*uri*/, const DOM::DOMString &/*rgbColor*/, const DOM::DOMString &/*iccColor*/) +{ + m_paintType = paintType; +} + +void SVGPaintImpl::setRGBColor(QColor color) +{ + m_paintType = SVG_PAINTTYPE_RGBCOLOR; + SVGColorImpl::setRGBColor(color); +} + +void SVGPaintImpl::setRGBColor(int r, int g, int b) +{ + m_paintType = SVG_PAINTTYPE_RGBCOLOR; + SVGColorImpl::setRGBColor(r, g, b); +} + +void SVGPaintImpl::setRGBColor(const DOM::DOMString &rgbColor) +{ + m_paintType = SVG_PAINTTYPE_RGBCOLOR; + SVGColorImpl::setRGBColor(rgbColor); +} + +void SVGPaintImpl::setRGBColorICCColor(const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor) +{ + m_paintType = SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR; + SVGColorImpl::setRGBColorICCColor(rgbColor, iccColor); +} + +void SVGPaintImpl::setColor(unsigned short colorType, const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor) +{ + SVGColorImpl::setColor(colorType, rgbColor, iccColor); + + switch(colorType) + { + case SVG_COLORTYPE_CURRENTCOLOR: + m_paintType = SVG_PAINTTYPE_CURRENTCOLOR; + break; + case SVG_COLORTYPE_RGBCOLOR: + m_paintType = SVG_PAINTTYPE_CURRENTCOLOR; + break; + case SVG_COLORTYPE_RGBCOLOR_ICCCOLOR: + m_paintType = SVG_PAINTTYPE_CURRENTCOLOR; + break; + case SVG_COLORTYPE_UNKNOWN: + m_paintType = SVG_PAINTTYPE_UNKNOWN; + break; + } +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPaintImpl::s_hashTable 3 + paintType SVGPaintImpl::PaintType DontDelete + uri SVGPaintImpl::URI DontDelete +@end +*/ + +Value SVGPaintImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case PaintType: + return Number(paintType()); + case URI: + return String(uri().string()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +/* +@namespace KSVG +@begin SVGPaintImplConstructor::s_hashTable 11 +SVG_PAINTTYPE_UNKNOWN KSVG::SVG_PAINTTYPE_UNKNOWN DontDelete|ReadOnly +SVG_PAINTTYPE_CURRENTCOLOR KSVG::SVG_PAINTTYPE_CURRENTCOLOR DontDelete|ReadOnly +SVG_PAINTTYPE_RGBCOLOR KSVG::SVG_PAINTTYPE_RGBCOLOR DontDelete|ReadOnly +SVG_PAINTTYPE_RGBCOLOR KSVG::SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR DontDelete|ReadOnly +SVG_PAINTTYPE_NONE KSVG::SVG_PAINTTYPE_NONE DontDelete|ReadOnly +SVG_PAINTTYPE_URI_NONE KSVG::SVG_PAINTTYPE_URI_NONE DontDelete|ReadOnly +SVG_PAINTTYPE_URI_RGBCOLOR KSVG::SVG_PAINTTYPE_URI_RGBCOLOR DontDelete|ReadOnly +SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR KSVG::SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR DontDelete|ReadOnly +SVG_PAINTTYPE_URI_CURRENTCOLOR KSVG::SVG_PAINTTYPE_URI_CURRENTCOLOR DontDelete|ReadOnly +SVG_PAINTTYPE_URI KSVG::SVG_PAINTTYPE_URI DontDelete|ReadOnly +@end +*/ + +Value SVGPaintImplConstructor::getValueProperty(ExecState *, int token) const +{ + return Number(token); +} + +Value KSVG::getSVGPaintImplConstructor(ExecState *exec) +{ + return cacheGlobalBridge(exec, "[[svgpaint.constructor]]"); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPaintImpl.h b/ksvg/impl/SVGPaintImpl.h new file mode 100644 index 00000000..f2aa0691 --- /dev/null +++ b/ksvg/impl/SVGPaintImpl.h @@ -0,0 +1,85 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPaintImpl_H +#define SVGPaintImpl_H + +#include + +#include "ksvg_lookup.h" + +#include "SVGColorImpl.h" + +namespace KSVG +{ + +class SVGPaintImpl : public SVGColorImpl +{ +public: + SVGPaintImpl(SVGElementImpl *object); + SVGPaintImpl(const SVGPaintImpl &); + virtual ~SVGPaintImpl(); + + SVGPaintImpl &operator=(const SVGPaintImpl &); + + unsigned short paintType() const; + DOM::DOMString uri() const; + void setUri(const DOM::DOMString &uri); + void setPaint(unsigned short paintType, const DOM::DOMString &uri = "", const DOM::DOMString &rgbColor = "", const DOM::DOMString &iccColor = ""); + + virtual void setRGBColor(const DOM::DOMString &rgbColor); + virtual void setRGBColor(int r, int g, int b); + virtual void setRGBColor(QColor color); + virtual void setRGBColorICCColor(const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor); + virtual void setColor(unsigned short colorType, const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor); + +private: + unsigned short m_paintType; + DOM::DOMString m_uri; + +public: + KSVG_GET + + enum + { + // Properties + PaintType, URI + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +class SVGPaintImplConstructor : public KJS::ObjectImp +{ +public: + SVGPaintImplConstructor(KJS::ExecState *) { } + KJS::Value getValueProperty(KJS::ExecState *, int token) const; + + // no put - all read-only + KSVG_GET +}; + +KJS::Value getSVGPaintImplConstructor(KJS::ExecState *exec); + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPaintServerImpl.cc b/ksvg/impl/SVGPaintServerImpl.cc new file mode 100644 index 00000000..b3275231 --- /dev/null +++ b/ksvg/impl/SVGPaintServerImpl.cc @@ -0,0 +1,55 @@ +/* + Copyright (C) 2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGPaintServerImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" + +using namespace KSVG; + +SVGPaintServerImpl::SVGPaintServerImpl() +{ + m_paintServer = 0; +} + +SVGPaintServerImpl::~SVGPaintServerImpl() +{ +} + +CanvasPaintServer *SVGPaintServerImpl::paintServer(SVGDocumentImpl *doc, const QString& id) +{ + CanvasPaintServer *pserver = 0; + SVGElementImpl *element = doc->rootElement()->getElementById(id); + + if(element) + { + SVGPaintServerImpl *paintServerElement = dynamic_cast(element); + + if(paintServerElement) + pserver = paintServerElement->paintServer(); + } + + return pserver; +} + +// vim:ts=4:noet + diff --git a/ksvg/impl/SVGPaintServerImpl.h b/ksvg/impl/SVGPaintServerImpl.h new file mode 100644 index 00000000..df276758 --- /dev/null +++ b/ksvg/impl/SVGPaintServerImpl.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPaintServerImpl_H +#define SVGPaintServerImpl_H + +namespace KSVG +{ + +class SVGDocumentImpl; + +class CanvasPaintServer; + +class SVGPaintServerImpl +{ +public: + SVGPaintServerImpl(); + virtual ~SVGPaintServerImpl(); + + CanvasPaintServer *paintServer() { return m_paintServer; } + + static CanvasPaintServer *paintServer(SVGDocumentImpl *doc, const QString& id); + +protected: + CanvasPaintServer *m_paintServer; + +private: +}; + +} + +#endif + +// vim:ts=4:noet + diff --git a/ksvg/impl/SVGPathElementImpl.cc b/ksvg/impl/SVGPathElementImpl.cc new file mode 100644 index 00000000..f34600b8 --- /dev/null +++ b/ksvg/impl/SVGPathElementImpl.cc @@ -0,0 +1,868 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include + +#include +#include + +#include "SVGRectImpl.h" +#include "SVGPaintImpl.h" +#include "SVGPointImpl.h" +#include "SVGAngleImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGPathSegArcImpl.h" +#include "SVGPathSegListImpl.h" +#include "SVGPathElementImpl.h" +#include "SVGPathSegLinetoImpl.h" +#include "SVGPathSegMovetoImpl.h" +#include "SVGAnimatedNumberImpl.h" +#include "SVGPathSegClosePathImpl.h" +#include "SVGPathSegCurvetoCubicImpl.h" +#include "SVGPathSegLinetoVerticalImpl.h" +#include "SVGPathSegLinetoHorizontalImpl.h" +#include "SVGPathSegCurvetoQuadraticImpl.h" +#include "SVGPathSegCurvetoCubicSmoothImpl.h" +#include "SVGPathSegCurvetoQuadraticSmoothImpl.h" + +#include "SVGPaint.h" + +#include "CanvasItem.h" +#include "KSVGCanvas.h" +#include "BezierPath.h" +#include "Point.h" + +using namespace KSVG; + +#include "SVGPathElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGPathElementImpl::SVGPathElementImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl(), SVGAnimatedPathDataImpl(), SVGPathParser() +{ + KSVG_EMPTY_FLAGS + + m_pathLength = new SVGAnimatedNumberImpl(); + m_pathLength->ref(); + + m_pathLength->setBaseVal(0); +} + +SVGPathElementImpl::~SVGPathElementImpl() +{ + pathSegList()->clear(); + + if(m_pathLength) + m_pathLength->deref(); +} + +SVGAnimatedNumberImpl *SVGPathElementImpl::pathLength() const +{ + return m_pathLength; +} + +double SVGPathElementImpl::getTotalLength() +{ + T2P::BezierPath *path = ownerDoc()->canvas()->toBezierPath(m_item); + if(path) + return path->length(); + + return 0; +} + +SVGPointImpl *SVGPathElementImpl::getPointAtLength(double distance) +{ + SVGPointImpl *ret = SVGSVGElementImpl::createSVGPoint(); + double totalDistance = getTotalLength(); + T2P::BezierPath *path = ownerDoc()->canvas()->toBezierPath(m_item); + if(path) + { + T2P::Point p; + path->pointTangentNormalAt(distance / totalDistance, &p); + ret->setX(p.x()); + ret->setY(p.y()); + } + + return ret; +} + +unsigned long SVGPathElementImpl::getPathSegAtLength(double) +{ + return 0; +} + +SVGPathSegClosePathImpl *SVGPathElementImpl::createSVGPathSegClosePath() +{ + SVGPathSegClosePathImpl *temp = new SVGPathSegClosePathImpl(); + temp->ref(); + + return temp; +} + +SVGPathSegMovetoAbsImpl *SVGPathElementImpl::createSVGPathSegMovetoAbs(double x, double y) +{ + SVGPathSegMovetoAbsImpl *temp = new SVGPathSegMovetoAbsImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + return temp; +} + +SVGPathSegMovetoRelImpl *SVGPathElementImpl::createSVGPathSegMovetoRel(double x, double y) +{ + SVGPathSegMovetoRelImpl *temp = new SVGPathSegMovetoRelImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + return temp; +} + +SVGPathSegLinetoAbsImpl *SVGPathElementImpl::createSVGPathSegLinetoAbs(double x, double y) +{ + SVGPathSegLinetoAbsImpl *temp = new SVGPathSegLinetoAbsImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + return temp; +} + +SVGPathSegLinetoRelImpl *SVGPathElementImpl::createSVGPathSegLinetoRel(double x, double y) +{ + SVGPathSegLinetoRelImpl *temp = new SVGPathSegLinetoRelImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + return temp; +} + +SVGPathSegCurvetoCubicAbsImpl *SVGPathElementImpl::createSVGPathSegCurvetoCubicAbs(double x, double y, double x1, double y1, double x2, double y2) +{ + SVGPathSegCurvetoCubicAbsImpl *temp = new SVGPathSegCurvetoCubicAbsImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + temp->setX1(x1); + temp->setY1(y1); + temp->setX2(x2); + temp->setY2(y2); + return temp; +} + +SVGPathSegCurvetoCubicRelImpl *SVGPathElementImpl::createSVGPathSegCurvetoCubicRel(double x, double y, double x1, double y1, double x2, double y2) +{ + SVGPathSegCurvetoCubicRelImpl *temp = new SVGPathSegCurvetoCubicRelImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + temp->setX1(x1); + temp->setY1(y1); + temp->setX2(x2); + temp->setY2(y2); + return temp; +} + +SVGPathSegCurvetoQuadraticAbsImpl *SVGPathElementImpl::createSVGPathSegCurvetoQuadraticAbs(double x, double y, double x1, double y1) +{ + SVGPathSegCurvetoQuadraticAbsImpl *temp = new SVGPathSegCurvetoQuadraticAbsImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + temp->setX1(x1); + temp->setY1(y1); + return temp; +} + +SVGPathSegCurvetoQuadraticRelImpl *SVGPathElementImpl::createSVGPathSegCurvetoQuadraticRel(double x, double y, double x1, double y1) +{ + SVGPathSegCurvetoQuadraticRelImpl *temp = new SVGPathSegCurvetoQuadraticRelImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + temp->setX1(x1); + temp->setY1(y1); + return temp; +} + +SVGPathSegArcAbsImpl *SVGPathElementImpl::createSVGPathSegArcAbs(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag) +{ + SVGPathSegArcAbsImpl *temp = new SVGPathSegArcAbsImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + temp->setR1(r1); + temp->setR2(r2); + temp->setAngle(angle); + temp->setLargeArcFlag(largeArcFlag); + temp->setSweepFlag(sweepFlag); + return temp; +} + +SVGPathSegArcRelImpl *SVGPathElementImpl::createSVGPathSegArcRel(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag) +{ + SVGPathSegArcRelImpl *temp = new SVGPathSegArcRelImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + temp->setR1(r1); + temp->setR2(r2); + temp->setAngle(angle); + temp->setLargeArcFlag(largeArcFlag); + temp->setSweepFlag(sweepFlag); + return temp; +} + +SVGPathSegLinetoHorizontalAbsImpl *SVGPathElementImpl::createSVGPathSegLinetoHorizontalAbs(double x) +{ + SVGPathSegLinetoHorizontalAbsImpl *temp = new SVGPathSegLinetoHorizontalAbsImpl(); + temp->ref(); + + temp->setX(x); + return temp; +} + +SVGPathSegLinetoHorizontalRelImpl *SVGPathElementImpl::createSVGPathSegLinetoHorizontalRel(double x) +{ + SVGPathSegLinetoHorizontalRelImpl *temp = new SVGPathSegLinetoHorizontalRelImpl(); + temp->ref(); + + temp->setX(x); + return temp; +} + +SVGPathSegLinetoVerticalAbsImpl *SVGPathElementImpl::createSVGPathSegLinetoVerticalAbs(double y) +{ + SVGPathSegLinetoVerticalAbsImpl *temp = new SVGPathSegLinetoVerticalAbsImpl(); + temp->ref(); + + temp->setY(y); + return temp; +} + +SVGPathSegLinetoVerticalRelImpl *SVGPathElementImpl::createSVGPathSegLinetoVerticalRel(double y) +{ + SVGPathSegLinetoVerticalRelImpl *temp = new SVGPathSegLinetoVerticalRelImpl(); + temp->ref(); + + temp->setY(y); + return temp; +} + +SVGPathSegCurvetoCubicSmoothAbsImpl *SVGPathElementImpl::createSVGPathSegCurvetoCubicSmoothAbs(double x, double y, double x2, double y2) +{ + SVGPathSegCurvetoCubicSmoothAbsImpl *temp = new SVGPathSegCurvetoCubicSmoothAbsImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + temp->setX2(x2); + temp->setY2(y2); + return temp; +} + +SVGPathSegCurvetoCubicSmoothRelImpl *SVGPathElementImpl::createSVGPathSegCurvetoCubicSmoothRel(double x, double y, double x2, double y2) +{ + SVGPathSegCurvetoCubicSmoothRelImpl *temp = new SVGPathSegCurvetoCubicSmoothRelImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + temp->setX2(x2); + temp->setY2(y2); + return temp; +} + +SVGPathSegCurvetoQuadraticSmoothAbsImpl *SVGPathElementImpl::createSVGPathSegCurvetoQuadraticSmoothAbs(double x, double y) +{ + SVGPathSegCurvetoQuadraticSmoothAbsImpl *temp = new SVGPathSegCurvetoQuadraticSmoothAbsImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + return temp; +} + +SVGPathSegCurvetoQuadraticSmoothRelImpl *SVGPathElementImpl::createSVGPathSegCurvetoQuadraticSmoothRel(double x, double y) +{ + SVGPathSegCurvetoQuadraticSmoothRelImpl *temp = new SVGPathSegCurvetoQuadraticSmoothRelImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + return temp; +} + +void SVGPathElementImpl::svgMoveTo(double x1, double y1, bool, bool abs) +{ + if(abs) + pathSegList()->appendItem(createSVGPathSegMovetoAbs(x1, y1)); + else + pathSegList()->appendItem(createSVGPathSegMovetoRel(x1, y1)); +} + +void SVGPathElementImpl::svgLineTo(double x1, double y1, bool abs) +{ + if(abs) + pathSegList()->appendItem(createSVGPathSegLinetoAbs(x1, y1)); + else + pathSegList()->appendItem(createSVGPathSegLinetoRel(x1, y1)); +} + +void SVGPathElementImpl::svgLineToHorizontal(double x, bool abs) +{ + if(abs) + pathSegList()->appendItem(createSVGPathSegLinetoHorizontalAbs(x)); + else + pathSegList()->appendItem(createSVGPathSegLinetoHorizontalRel(x)); +} + +void SVGPathElementImpl::svgLineToVertical(double y, bool abs) +{ + if(abs) + pathSegList()->appendItem(createSVGPathSegLinetoVerticalAbs(y)); + else + pathSegList()->appendItem(createSVGPathSegLinetoVerticalRel(y)); +} + +void SVGPathElementImpl::svgCurveToCubic(double x1, double y1, double x2, double y2, double x, double y, bool abs) +{ + if(abs) + pathSegList()->appendItem(createSVGPathSegCurvetoCubicAbs(x, y, x1, y1, x2, y2)); + else + pathSegList()->appendItem(createSVGPathSegCurvetoCubicRel(x, y, x1, y1, x2, y2)); +} + +void SVGPathElementImpl::svgCurveToCubicSmooth(double x, double y, double x2, double y2, bool abs) +{ + if(abs) + pathSegList()->appendItem(createSVGPathSegCurvetoCubicSmoothAbs(x2, y2, x, y)); + else + pathSegList()->appendItem(createSVGPathSegCurvetoCubicSmoothRel(x2, y2, x, y)); +} + +void SVGPathElementImpl::svgCurveToQuadratic(double x, double y, double x1, double y1, bool abs) +{ + if(abs) + pathSegList()->appendItem(createSVGPathSegCurvetoQuadraticAbs(x1, y1, x, y)); + else + pathSegList()->appendItem(createSVGPathSegCurvetoQuadraticRel(x1, y1, x, y)); +} + +void SVGPathElementImpl::svgCurveToQuadraticSmooth(double x, double y, bool abs) +{ + if(abs) + pathSegList()->appendItem(createSVGPathSegCurvetoQuadraticSmoothAbs(x, y)); + else + pathSegList()->appendItem(createSVGPathSegCurvetoQuadraticSmoothRel(x, y)); +} + +void SVGPathElementImpl::svgArcTo(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag, bool abs) +{ + if(abs) + pathSegList()->appendItem(createSVGPathSegArcAbs(x, y, r1, r2, angle, largeArcFlag, sweepFlag)); + else + pathSegList()->appendItem(createSVGPathSegArcRel(x, y, r1, r2, angle, largeArcFlag, sweepFlag)); +} + +void SVGPathElementImpl::svgClosePath() +{ + pathSegList()->appendItem(createSVGPathSegClosePath()); +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathElementImpl::s_hashTable 3 + d SVGPathElementImpl::D DontDelete|ReadOnly + pathLength SVGPathElementImpl::PathLength DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGPathElementImplProto::s_hashTable 23 + getTotalLength SVGPathElementImpl::GetTotalLength DontDelete|Function 0 + getPointAtLength SVGPathElementImpl::GetPointAtLength DontDelete|Function 1 + getPathSegAtLength SVGPathElementImpl::GetPathSegAtLength DontDelete|Function 1 + createSVGPathSegClosePath SVGPathElementImpl::CreateSVGPathSegClosePath DontDelete|Function 0 + createSVGPathSegMovetoAbs SVGPathElementImpl::CreateSVGPathSegMovetoAbs DontDelete|Function 2 + createSVGPathSegMovetoRel SVGPathElementImpl::CreateSVGPathSegMovetoRel DontDelete|Function 2 + createSVGPathSegLinetoAbs SVGPathElementImpl::CreateSVGPathSegLinetoAbs DontDelete|Function 2 + createSVGPathSegLinetoRel SVGPathElementImpl::CreateSVGPathSegLinetoRel DontDelete|Function 2 + createSVGPathSegArcAbs SVGPathElementImpl::CreateSVGPathSegArcAbs DontDelete|Function 7 + createSVGPathSegArcRel SVGPathElementImpl::CreateSVGPathSegArcRel DontDelete|Function 7 + createSVGPathSegCurvetoCubicAbs SVGPathElementImpl::CreateSVGPathSegCurvetoCubicAbs DontDelete|Function 6 + createSVGPathSegCurvetoCubicRel SVGPathElementImpl::CreateSVGPathSegCurvetoCubicRel DontDelete|Function 6 + createSVGPathSegCurvetoQuadraticAbs SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticAbs DontDelete|Function 4 + createSVGPathSegCurvetoQuadraticRel SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticRel DontDelete|Function 4 + createSVGPathSegLinetoHorizontalAbs SVGPathElementImpl::CreateSVGPathSegLinetoHorizontalAbs DontDelete|Function 1 + createSVGPathSegLinetoHorizontalRel SVGPathElementImpl::CreateSVGPathSegLinetoHorizontalRel DontDelete|Function 1 + createSVGPathSegLinetoVerticalAbs SVGPathElementImpl::CreateSVGPathSegLinetoVerticalAbs DontDelete|Function 1 + createSVGPathSegLinetoVerticalRel SVGPathElementImpl::CreateSVGPathSegLinetoVerticalRel DontDelete|Function 1 + createSVGPathSegCurvetoCubicAbs SVGPathElementImpl::CreateSVGPathSegCurvetoCubicAbs DontDelete|Function 4 + createSVGPathSegCurvetoCubicRel SVGPathElementImpl::CreateSVGPathSegCurvetoCubicRel DontDelete|Function 4 + createSVGPathSegCurvetoQuadraticAbs SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticAbs DontDelete|Function 2 + createSVGPathSegCurvetoQuadraticRel SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticRel DontDelete|Function 2 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGPathElementImpl", SVGPathElementImplProto, SVGPathElementImplProtoFunc) + +Value SVGPathElementImpl::getValueProperty(ExecState *exec, int token) const +{ + //KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case PathLength: + return m_pathLength->cache(exec); + case D: +// if(!attributeMode) + { + QString d; + unsigned int nrSegs = pathSegList()->numberOfItems(); + SVGPathSegImpl *curseg = 0; + for(unsigned int i = 0; i < nrSegs; i++) + { + curseg = pathSegList()->getItem(i); + if(curseg) + d += curseg->toString() + " "; + } + return String(d); + } + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case D: + { + pathSegList()->clear(); + QString d = value.toString(exec).qstring(); + parseSVG(d, false); + if(hasMarkers()) + m_markerData = MarkerData(pathSegList()); + break; + } + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +Value SVGPathElementImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGPathElementImpl) + + switch(id) + { + case SVGPathElementImpl::GetTotalLength: + return Number(obj->getTotalLength()); + case SVGPathElementImpl::GetPointAtLength: + return obj->getPointAtLength(args[0].toNumber(exec))->cache(exec); + case SVGPathElementImpl::GetPathSegAtLength: + return Number(obj->getPathSegAtLength(args[0].toNumber(exec))); + case SVGPathElementImpl::CreateSVGPathSegClosePath: + return obj->createSVGPathSegClosePath()->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegMovetoAbs: + return obj->createSVGPathSegMovetoAbs(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegMovetoRel: + return obj->createSVGPathSegMovetoRel(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegLinetoAbs: + return obj->createSVGPathSegLinetoAbs(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegLinetoRel: + return obj->createSVGPathSegLinetoRel(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegCurvetoCubicAbs: + return obj->createSVGPathSegCurvetoCubicAbs(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec), args[4].toNumber(exec), args[5].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegCurvetoCubicRel: + return obj->createSVGPathSegCurvetoCubicRel(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec), args[4].toNumber(exec), args[5].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticAbs: + return obj->createSVGPathSegCurvetoQuadraticAbs(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticRel: + return obj->createSVGPathSegCurvetoQuadraticRel(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegArcAbs: + return obj->createSVGPathSegArcAbs(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec), args[4].toNumber(exec), args[5].toBoolean(exec), args[6].toBoolean(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegArcRel: + return obj->createSVGPathSegArcRel(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec), args[4].toNumber(exec), args[5].toBoolean(exec), args[6].toBoolean(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegLinetoHorizontalAbs: + return obj->createSVGPathSegLinetoHorizontalAbs(args[0].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegLinetoHorizontalRel: + return obj->createSVGPathSegLinetoHorizontalRel(args[0].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegLinetoVerticalAbs: + return obj->createSVGPathSegLinetoVerticalAbs(args[0].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegLinetoVerticalRel: + return obj->createSVGPathSegLinetoVerticalRel(args[0].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegCurvetoCubicSmoothAbs: + return obj->createSVGPathSegCurvetoCubicSmoothAbs(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegCurvetoCubicSmoothRel: + return obj->createSVGPathSegCurvetoCubicSmoothRel(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticSmoothAbs: + return obj->createSVGPathSegCurvetoQuadraticSmoothAbs(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticSmoothRel: + return obj->createSVGPathSegCurvetoQuadraticSmoothRel(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec); + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + +SVGRectImpl *SVGPathElementImpl::getBBox() +{ + SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect(); + + if(m_item) + { + T2P::BezierPath *path = ownerDoc()->canvas()->toBezierPath(m_item); + if(path) + { + T2P::Point topLeft; + T2P::Point bottomRight; + + path->boundingBox(&topLeft, &bottomRight); + + ret->setX(topLeft.x()); + ret->setY(topLeft.y()); + ret->setWidth(bottomRight.x() - topLeft.x()); + ret->setHeight(bottomRight.y() - topLeft.y()); + } + } + return ret; +} + +void SVGPathElementImpl::createItem(KSVGCanvas *c) +{ + if(!c) + c = ownerDoc()->canvas(); + + if(!m_item) + { + // TODO : this is a quick fix for this problem: + // d attribute encountered before marker attributes. + // Try to process the attributes in the right order, ie. + // d attr processing should be last. + if(hasMarkers() && m_markerData.numMarkers() == 0) + m_markerData = MarkerData(pathSegList()); + m_item = c->createPath(this); + c->insert(m_item); + } +} + +SVGPathElementImpl::MarkerData::MarkerData(SVGPathSegListImpl *path) +{ + unsigned int numSegments = path->numberOfItems(); + double curx = 0; + double cury = 0; + int currentSubpathStartIndex = -1; + double previousQuadraticX1 = 0; + double previousQuadraticY1 = 0; + double previousCubicX2 = 0; + double previousCubicY2 = 0; + + QValueVector pathSegmentData(numSegments); + + for(unsigned int i = 0; i < numSegments; i++) + { + SVGPathSegImpl *segment = path->getItem(i); + struct SegmentData data; + + data.type = segment->pathSegType(); + + if(segment->pathSegType() == PATHSEG_MOVETO_ABS || segment->pathSegType() == PATHSEG_MOVETO_REL) + { + if(currentSubpathStartIndex >= 0) + { + // Finish the previous subpath. + for(unsigned int j = currentSubpathStartIndex; j < i; j++) + { + pathSegmentData[j].subpathStartIndex = currentSubpathStartIndex; + pathSegmentData[j].subpathEndIndex = i - 1; + pathSegmentData[j].subpathIsClosed = false; + } + } + + currentSubpathStartIndex = i; + } + else if(segment->pathSegType() == PATHSEG_CLOSEPATH) + { + if(currentSubpathStartIndex >= 0) + { + SVGPathSegClosePathImpl *s = static_cast(segment); + + s->setX(pathSegmentData[currentSubpathStartIndex].startx + pathSegmentData[currentSubpathStartIndex].dx); + s->setY(pathSegmentData[currentSubpathStartIndex].starty + pathSegmentData[currentSubpathStartIndex].dy); + + for(unsigned int j = currentSubpathStartIndex; j < i; j++) + { + pathSegmentData[j].subpathStartIndex = currentSubpathStartIndex; + pathSegmentData[j].subpathEndIndex = i; + pathSegmentData[j].subpathIsClosed = true; + } + + data.subpathStartIndex = currentSubpathStartIndex; + data.subpathEndIndex = i; + data.subpathIsClosed = true; + } + + currentSubpathStartIndex = i + 1; + } + + switch(segment->pathSegType()) + { + case PATHSEG_CURVETO_CUBIC_ABS: + { + SVGPathSegCurvetoCubicAbsImpl *s = static_cast(segment); + previousCubicX2 = s->x2(); + previousCubicY2 = s->y2(); + break; + } + case PATHSEG_CURVETO_CUBIC_REL: + { + SVGPathSegCurvetoCubicRelImpl *s = static_cast(segment); + previousCubicX2 = curx + s->x2(); + previousCubicY2 = cury + s->y2(); + break; + } + case PATHSEG_CURVETO_CUBIC_SMOOTH_ABS: + { + SVGPathSegCurvetoCubicSmoothAbsImpl *s = static_cast(segment); + s->setPreviousX2(previousCubicX2); + s->setPreviousY2(previousCubicY2); + previousCubicX2 = s->x2(); + previousCubicY2 = s->y2(); + break; + } + case PATHSEG_CURVETO_CUBIC_SMOOTH_REL: + { + SVGPathSegCurvetoCubicSmoothRelImpl *s = static_cast(segment); + s->setPreviousAbsX2(previousCubicX2); + s->setPreviousAbsY2(previousCubicY2); + previousCubicX2 = curx + s->x2(); + previousCubicY2 = cury + s->y2(); + break; + } + case PATHSEG_CURVETO_QUADRATIC_ABS: + { + SVGPathSegCurvetoQuadraticAbsImpl *s = static_cast(segment); + previousQuadraticX1 = s->x1(); + previousQuadraticY1 = s->y1(); + break; + } + case PATHSEG_CURVETO_QUADRATIC_REL: + { + SVGPathSegCurvetoQuadraticRelImpl *s = static_cast(segment); + previousQuadraticX1 = curx + s->x1(); + previousQuadraticY1 = cury + s->y1(); + break; + } + case PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS: + { + SVGPathSegCurvetoQuadraticSmoothAbsImpl *s = static_cast(segment); + s->setPreviousX1(previousQuadraticX1); + s->setPreviousY1(previousQuadraticY1); + previousQuadraticX1 = s->x1(curx); + previousQuadraticY1 = s->y1(cury); + break; + } + case PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL: + { + SVGPathSegCurvetoQuadraticSmoothRelImpl *s = static_cast(segment); + s->setPreviousAbsX1(previousQuadraticX1); + s->setPreviousAbsY1(previousQuadraticY1); + previousQuadraticX1 = s->absX1(curx); + previousQuadraticY1 = s->absY1(cury); + break; + } + default: + previousCubicX2 = curx; + previousCubicY2 = cury; + previousQuadraticX1 = curx; + previousQuadraticY1 = cury; + break; + } + + data.startx = curx; + data.starty = cury; + + segment->getDeltasAndSlopes(curx, cury, &data.dx, &data.dy, &data.startSlope, &data.endSlope); + + pathSegmentData[i] = data; + + curx += data.dx; + cury += data.dy; + } + + if(currentSubpathStartIndex >= 0) + { + // Finish the previous subpath. + for(unsigned int j = currentSubpathStartIndex; j < numSegments; j++) + { + pathSegmentData[j].subpathStartIndex = currentSubpathStartIndex; + pathSegmentData[j].subpathEndIndex = numSegments - 1; + pathSegmentData[j].subpathIsClosed = false; + } + } + + m_markers.resize(numSegments); + + for(unsigned int i = 0; i < numSegments; i++) + { + struct Marker marker; + + marker.x = pathSegmentData[i].startx + pathSegmentData[i].dx; + marker.y = pathSegmentData[i].starty + pathSegmentData[i].dy; + + double inSlope; + double outSlope; + bool haveInSlope = false; + bool haveOutSlope = false; + + if(pathSegmentData[i].subpathStartIndex == i && pathSegmentData[i].subpathIsClosed) + { + // Spec: For closed subpaths, the marker for the initial vertex uses the end direction + // of the corresponding closepath for its incoming slope and the first segment's + // start slope for its outgoing slope. + haveInSlope = getEndSlope(pathSegmentData, pathSegmentData[i].subpathEndIndex, &inSlope); + haveOutSlope = getStartSlope(pathSegmentData, i + 1, &outSlope); + } + else if(pathSegmentData[i].type == PATHSEG_CLOSEPATH) + { + haveInSlope = getEndSlope(pathSegmentData, i, &inSlope); + + // Spec: If the segment following a closepath is other than a moveto, the marker + // for the closepath uses the following segment's start direction as its + // outgoing direction. + if(i + 1 < numSegments && (pathSegmentData[i + 1].type != PATHSEG_MOVETO_ABS && pathSegmentData[i + 1].type != PATHSEG_MOVETO_REL)) + haveOutSlope = getStartSlope(pathSegmentData, i + 1, &outSlope); + else + haveOutSlope = getStartSlope(pathSegmentData, pathSegmentData[i].subpathStartIndex, &outSlope); + } + else + { + haveOutSlope = getStartSlope(pathSegmentData, i + 1, &outSlope); + haveInSlope = getEndSlope(pathSegmentData, i, &inSlope); + } + + if(!haveInSlope && !haveOutSlope) + { + outSlope = 0; + inSlope = 0; + } + else if(haveInSlope && !haveOutSlope) + outSlope = inSlope; + else if(!haveInSlope && haveOutSlope) + inSlope = outSlope; + + double bisector = SVGAngleImpl::shortestArcBisector(inSlope, outSlope); + marker.angle = bisector; + + m_markers[i] = marker; + } +} + +bool SVGPathElementImpl::MarkerData::getStartSlope(QValueVector segments, unsigned int i, double *pStartSlope) +{ + if(i > segments.count() - 1 || segments[i].type == PATHSEG_MOVETO_ABS || segments[i].type == PATHSEG_MOVETO_REL) + return false; + else + { + const double epsilon = DBL_EPSILON; + + if(fabs(segments[i].dx) > epsilon || fabs(segments[i].dy) > epsilon) + { + *pStartSlope = segments[i].startSlope; + return true; + } + else + { + int subpathStartIndex = segments[i].subpathStartIndex; + + for(int j = i - 1; j >= subpathStartIndex; j--) + { + if(segments[j].type == PATHSEG_MOVETO_ABS || segments[j].type == PATHSEG_MOVETO_REL) + return false; + + if(fabs(segments[j].dx) > epsilon || fabs(segments[j].dy) > epsilon) + { + *pStartSlope = segments[j].endSlope; + return true; + } + } + + return false; + } + } +} + +bool SVGPathElementImpl::MarkerData::getEndSlope(QValueVector segments, unsigned int i, double *pEndSlope) +{ + if(i > segments.count() - 1 || segments[i].type == PATHSEG_MOVETO_ABS || segments[i].type == PATHSEG_MOVETO_REL) + return false; + else + { + const double epsilon = DBL_EPSILON; + + if(fabs(segments[i].dx) > epsilon || fabs(segments[i].dy) > epsilon) + { + *pEndSlope = segments[i].endSlope; + return true; + } + else + { + int subpathEndIndex = segments[i].subpathEndIndex; + + for(int j = i + 1; j <= subpathEndIndex; j++) + { + if(segments[j].type == PATHSEG_MOVETO_ABS || segments[j].type == PATHSEG_MOVETO_REL) + return false; + + if(fabs(segments[j].dx) > epsilon || fabs(segments[j].dy) > epsilon) + { + *pEndSlope = segments[j].startSlope; + return true; + } + } + + return false; + } + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathElementImpl.h b/ksvg/impl/SVGPathElementImpl.h new file mode 100644 index 00000000..a9af56fc --- /dev/null +++ b/ksvg/impl/SVGPathElementImpl.h @@ -0,0 +1,194 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathElementImpl_H +#define SVGPathElementImpl_H + +#include + +#include "svgpathparser.h" + +#include "ksvg_lookup.h" + +#include "SVGShapeImpl.h" +#include "SVGTestsImpl.h" +#include "SVGStylableImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGTransformableImpl.h" +#include "SVGAnimatedPathDataImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +namespace KSVG +{ + +class SVGPointImpl; +class SVGPathSegImpl; +class SVGPathSegArcAbsImpl; +class SVGPathSegArcRelImpl; +class SVGAnimatedNumberImpl; +class SVGPathSegClosePathImpl; +class SVGPathSegLinetoAbsImpl; +class SVGPathSegLinetoRelImpl; +class SVGPathSegMovetoAbsImpl; +class SVGPathSegMovetoRelImpl; +class SVGPathSegCurvetoCubicAbsImpl; +class SVGPathSegCurvetoCubicRelImpl; +class SVGPathSegLinetoVerticalAbsImpl; +class SVGPathSegLinetoVerticalRelImpl; +class SVGPathSegLinetoHorizontalAbsImpl; +class SVGPathSegLinetoHorizontalRelImpl; +class SVGPathSegCurvetoQuadraticAbsImpl; +class SVGPathSegCurvetoQuadraticRelImpl; +class SVGPathSegCurvetoCubicSmoothAbsImpl; +class SVGPathSegCurvetoCubicSmoothRelImpl; +class SVGPathSegCurvetoQuadraticSmoothAbsImpl; +class SVGPathSegCurvetoQuadraticSmoothRelImpl; +class SVGPathElementImpl : public SVGShapeImpl, + public SVGTestsImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGTransformableImpl, + public SVGAnimatedPathDataImpl, + public ::SVGPathParser +{ +public: + SVGPathElementImpl(DOM::ElementImpl *impl); + virtual ~SVGPathElementImpl(); + + SVGAnimatedNumberImpl *pathLength() const; + double getTotalLength(); + SVGPointImpl *getPointAtLength(double distance); + unsigned long getPathSegAtLength(double distance); + + SVGPathSegClosePathImpl *createSVGPathSegClosePath(); + SVGPathSegMovetoAbsImpl *createSVGPathSegMovetoAbs(double x, double y); + SVGPathSegMovetoRelImpl *createSVGPathSegMovetoRel(double x, double y); + SVGPathSegLinetoAbsImpl *createSVGPathSegLinetoAbs(double x, double y); + SVGPathSegLinetoRelImpl *createSVGPathSegLinetoRel(double x, double y); + SVGPathSegCurvetoCubicAbsImpl *createSVGPathSegCurvetoCubicAbs(double x, double y, double x1, double y1, double x2, double y2); + SVGPathSegCurvetoCubicRelImpl *createSVGPathSegCurvetoCubicRel(double x, double y, double x1, double y1, double x2, double y2); + SVGPathSegCurvetoQuadraticAbsImpl *createSVGPathSegCurvetoQuadraticAbs(double x, double y, double x1, double y1); + SVGPathSegCurvetoQuadraticRelImpl *createSVGPathSegCurvetoQuadraticRel(double x, double y, double x1, double y1); + SVGPathSegArcAbsImpl *createSVGPathSegArcAbs(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag); + SVGPathSegArcRelImpl *createSVGPathSegArcRel(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag); + SVGPathSegLinetoHorizontalAbsImpl *createSVGPathSegLinetoHorizontalAbs(double x); + SVGPathSegLinetoHorizontalRelImpl *createSVGPathSegLinetoHorizontalRel(double x); + SVGPathSegLinetoVerticalAbsImpl *createSVGPathSegLinetoVerticalAbs(double y); + SVGPathSegLinetoVerticalRelImpl *createSVGPathSegLinetoVerticalRel(double y); + SVGPathSegCurvetoCubicSmoothAbsImpl *createSVGPathSegCurvetoCubicSmoothAbs(double x, double y, double x2, double y2); + SVGPathSegCurvetoCubicSmoothRelImpl *createSVGPathSegCurvetoCubicSmoothRel(double x, double y, double x2, double y2); + SVGPathSegCurvetoQuadraticSmoothAbsImpl *createSVGPathSegCurvetoQuadraticSmoothAbs(double x, double y); + SVGPathSegCurvetoQuadraticSmoothRelImpl *createSVGPathSegCurvetoQuadraticSmoothRel(double x, double y); + + virtual void createItem(KSVGCanvas *c = 0); + + virtual SVGRectImpl *getBBox(); + + class MarkerData + { + public: + struct Marker + { + double x; + double y; + double angle; + }; + + MarkerData() {} + MarkerData(SVGPathSegListImpl *path); + + const Marker& marker(unsigned int i) const { return m_markers[i]; } + unsigned int numMarkers() const { return m_markers.count(); } + + private: + struct SegmentData + { + double startx; + double starty; + double dx; + double dy; + double startSlope; + double endSlope; + unsigned int subpathStartIndex; + unsigned int subpathEndIndex; + bool subpathIsClosed; + int type; + }; + + static bool getStartSlope(QValueVector segments, unsigned int i, double *pStartSlope); + static bool getEndSlope(QValueVector segments, unsigned int i, double *pEndSlope); + + QValueVector m_markers; + }; + + MarkerData markerData() const { return m_markerData; } + +private: + SVGAnimatedNumberImpl *m_pathLength; + MarkerData m_markerData; + + virtual void svgMoveTo(double x1, double y1, bool closed, bool abs = true); + virtual void svgLineTo(double x1, double y1, bool abs = true); + virtual void svgLineToHorizontal(double x, bool abs = true); + virtual void svgLineToVertical(double y, bool abs = true); + virtual void svgCurveToCubic(double x1, double y1, double x2, double y2, double x, double y, bool abs = true); + virtual void svgCurveToCubicSmooth(double x, double y, double x2, double y2, bool abs = true); + virtual void svgCurveToQuadratic(double x, double y, double x1, double y1, bool abs = true); + virtual void svgCurveToQuadraticSmooth(double x, double y, bool abs = true); + virtual void svgArcTo(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag, bool abs = true); + virtual void svgClosePath(); + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + D, PathLength, + // Functions + GetTotalLength, GetPointAtLength, GetPathSegAtLength, + CreateSVGPathSegClosePath, CreateSVGPathSegMovetoAbs, CreateSVGPathSegMovetoRel, + CreateSVGPathSegLinetoAbs, CreateSVGPathSegLinetoRel, CreateSVGPathSegCurvetoCubicAbs, + CreateSVGPathSegCurvetoCubicRel, CreateSVGPathSegCurvetoQuadraticAbs, + CreateSVGPathSegCurvetoQuadraticRel, CreateSVGPathSegArcAbs, + CreateSVGPathSegArcRel, CreateSVGPathSegLinetoHorizontalAbs, + CreateSVGPathSegLinetoHorizontalRel, CreateSVGPathSegLinetoVerticalAbs, + CreateSVGPathSegLinetoVerticalRel, CreateSVGPathSegCurvetoCubicSmoothAbs, + CreateSVGPathSegCurvetoCubicSmoothRel, CreateSVGPathSegCurvetoQuadraticSmoothAbs, + CreateSVGPathSegCurvetoQuadraticSmoothRel + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGPathElementImpl, "path") + +} + +KSVG_DEFINE_PROTOTYPE(SVGPathElementImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGPathElementImplProtoFunc, SVGPathElementImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegArcImpl.cc b/ksvg/impl/SVGPathSegArcImpl.cc new file mode 100644 index 00000000..9fb4190f --- /dev/null +++ b/ksvg/impl/SVGPathSegArcImpl.cc @@ -0,0 +1,495 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include + +#include "SVGPathSegArcImpl.h" +#include "SVGAngleImpl.h" + +using namespace KSVG; + +#include "SVGPathSegArcImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +static void getArcSlopes(bool relative, double curx, double cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag, double *pStartSlope, double *pEndSlope) +{ + double sin_th, cos_th; + double a00, a01, a10, a11; + double x0, y0, x1, y1, xc, yc; + double d, sfactor, sfactor_sq; + double th0, th1, th_arc; + int i, n_segs; + + sin_th = sin(angle * (M_PI / 180.0)); + cos_th = cos(angle * (M_PI / 180.0)); + + double dx; + + if(!relative) + dx = (curx - x) / 2.0; + else + dx = -x / 2.0; + + double dy; + + if(!relative) + dy = (cury - y) / 2.0; + else + dy = -y / 2.0; + + double _x1 = cos_th * dx + sin_th * dy; + double _y1 = -sin_th * dx + cos_th * dy; + double Pr1 = r1 * r1; + double Pr2 = r2 * r2; + double Px = _x1 * _x1; + double Py = _y1 * _y1; + + // Spec : check if radii are large enough + double check = Px / Pr1 + Py / Pr2; + if(check > 1) + { + r1 = r1 * sqrt(check); + r2 = r2 * sqrt(check); + } + + a00 = cos_th / r1; + a01 = sin_th / r1; + a10 = -sin_th / r2; + a11 = cos_th / r2; + + x0 = a00 * curx + a01 * cury; + y0 = a10 * curx + a11 * cury; + + if(!relative) + x1 = a00 * x + a01 * y; + else + x1 = a00 * (curx + x) + a01 * (cury + y); + + if(!relative) + y1 = a10 * x + a11 * y; + else + y1 = a10 * (curx + x) + a11 * (cury + y); + + /* (x0, y0) is current point in transformed coordinate space. + (x1, y1) is new point in transformed coordinate space. + + The arc fits a unit-radius circle in this space. + */ + + d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0); + + sfactor_sq = 1.0 / d - 0.25; + + if(sfactor_sq < 0) + sfactor_sq = 0; + + sfactor = sqrt(sfactor_sq); + + if(sweepFlag == largeArcFlag) + sfactor = -sfactor; + + xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0); + yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0); + + /* (xc, yc) is center of the circle. */ + th0 = atan2(y0 - yc, x0 - xc); + th1 = atan2(y1 - yc, x1 - xc); + + th_arc = th1 - th0; + if(th_arc < 0 && sweepFlag) + th_arc += 2 * M_PI; + else if(th_arc > 0 && !sweepFlag) + th_arc -= 2 * M_PI; + + n_segs = (int) (int) ceil(fabs(th_arc / (M_PI * 0.5 + 0.001))); + + for(int step = 0; step < 2; step++) + { + i = step == 0 ? 0 : n_segs - 1; + + double sin_th, cos_th; + double a00, a01, a10, a11; + double x1, y1, x2, y2, x3, y3; + double t; + double th_half; + + double _th0 = th0 + i * th_arc / n_segs; + double _th1 = th0 + (i + 1) * th_arc / n_segs; + + sin_th = sin(angle * (M_PI / 180.0)); + cos_th = cos(angle * (M_PI / 180.0)); + + /* inverse transform compared with rsvg_path_arc */ + a00 = cos_th * r1; + a01 = -sin_th * r2; + a10 = sin_th * r1; + a11 = cos_th * r2; + + th_half = 0.5 * (_th1 - _th0); + t = (8.0 / 3.0) * sin(th_half * 0.5) * sin(th_half * 0.5) / sin(th_half); + x1 = xc + cos(_th0) - t * sin(_th0); + y1 = yc + sin(_th0) + t * cos(_th0); + x3 = xc + cos(_th1); + y3 = yc + sin(_th1); + x2 = x3 + t * sin(_th1); + y2 = y3 - t * cos(_th1); + + double bezX1 = a00 * x1 + a01 * y1; + double bezY1 = a10 * x1 + a11 * y1; + double bezX2 = a00 * x2 + a01 * y2; + double bezY2 = a10 * x2 + a11 * y2; + double bezX = a00 * x3 + a01 * y3; + double bezY = a10 * x3 + a11 * y3; + + if(step == 0) + *pStartSlope = SVGAngleImpl::todeg(atan2(bezY1 - cury, bezX1 - curx)); + else + *pEndSlope = SVGAngleImpl::todeg(atan2(bezY - bezY2, bezX - bezX2)); + } +} + +SVGPathSegArcAbsImpl::SVGPathSegArcAbsImpl() : SVGPathSegImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGPathSegArcAbsImpl::~SVGPathSegArcAbsImpl() +{ +} + +void SVGPathSegArcAbsImpl::setX(double x) +{ + m_x = x; +} + +double SVGPathSegArcAbsImpl::x() const +{ + return m_x; +} + +void SVGPathSegArcAbsImpl::setY(double y) +{ + m_y = y; +} + +double SVGPathSegArcAbsImpl::y() const +{ + return m_y; +} + +void SVGPathSegArcAbsImpl::setR1(double r1) +{ + m_r1 = r1; +} + +double SVGPathSegArcAbsImpl::r1() const +{ + return m_r1; +} + +void SVGPathSegArcAbsImpl::setR2(double r2) +{ + m_r2 = r2; +} + +double SVGPathSegArcAbsImpl::r2() const +{ + return m_r2; +} + +void SVGPathSegArcAbsImpl::setAngle(double angle) +{ + m_angle = angle; +} + +double SVGPathSegArcAbsImpl::angle() const +{ + return m_angle; +} + +void SVGPathSegArcAbsImpl::setLargeArcFlag(bool largeArcFlag) +{ + m_largeArcFlag = largeArcFlag; +} + +bool SVGPathSegArcAbsImpl::largeArcFlag() const +{ + return m_largeArcFlag; +} + +void SVGPathSegArcAbsImpl::setSweepFlag(bool sweepFlag) +{ + m_sweepFlag = sweepFlag; +} + +bool SVGPathSegArcAbsImpl::sweepFlag() const +{ + return m_sweepFlag; +} + +void SVGPathSegArcAbsImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const +{ + double dx = x() - curx; + double dy = y() - cury; + double startSlope; + double endSlope; + getArcSlopes(false, curx, cury, angle(), x(), y(), r1(), r2(), largeArcFlag(), sweepFlag(), &startSlope, &endSlope); + *pDx = dx; + *pDy = dy; + *pStartSlope = startSlope; + *pEndSlope = endSlope; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegArcAbsImpl::s_hashTable 11 + x SVGPathSegArcAbsImpl::X DontDelete + y SVGPathSegArcAbsImpl::Y DontDelete + r1 SVGPathSegArcAbsImpl::R1 DontDelete + r2 SVGPathSegArcAbsImpl::R2 DontDelete + angle SVGPathSegArcAbsImpl::Angle DontDelete + largeArcFlag SVGPathSegArcAbsImpl::LargeArcFlag DontDelete + sweepFlag SVGPathSegArcAbsImpl::SweepFlag DontDelete +@end +*/ + +Value SVGPathSegArcAbsImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case X: + return Number(x()); + case Y: + return Number(y()); + case R1: + return Number(r1()); + case R2: + return Number(r2()); + case Angle: + return Number(angle()); + case LargeArcFlag: + return Boolean(largeArcFlag()); + case SweepFlag: + return Boolean(sweepFlag()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathSegArcAbsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case X: + m_x = value.toNumber(exec); + break; + case Y: + m_y = value.toNumber(exec); + break; + case R1: + m_r1 = value.toNumber(exec); + break; + case R2: + m_r2 = value.toNumber(exec); + break; + case Angle: + m_angle = value.toNumber(exec); + break; + case LargeArcFlag: + m_largeArcFlag = value.toBoolean(exec); + break; + case SweepFlag: + m_sweepFlag = value.toBoolean(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + + + +SVGPathSegArcRelImpl::SVGPathSegArcRelImpl() : SVGPathSegImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGPathSegArcRelImpl::~SVGPathSegArcRelImpl() +{ +} + +void SVGPathSegArcRelImpl::setX(double x) +{ + m_x = x; +} + +double SVGPathSegArcRelImpl::x() const +{ + return m_x; +} + +void SVGPathSegArcRelImpl::setY(double y) +{ + m_y = y; +} + +double SVGPathSegArcRelImpl::y() const +{ + return m_y; +} + +void SVGPathSegArcRelImpl::setR1(double r1) +{ + m_r1 = r1; +} + +double SVGPathSegArcRelImpl::r1() const +{ + return m_r1; +} + +void SVGPathSegArcRelImpl::setR2(double r2) +{ + m_r2 = r2; +} + +double SVGPathSegArcRelImpl::r2() const +{ + return m_r2; +} + +void SVGPathSegArcRelImpl::setAngle(double angle) +{ + m_angle = angle; +} + +double SVGPathSegArcRelImpl::angle() const +{ + return m_angle; +} + +void SVGPathSegArcRelImpl::setLargeArcFlag(bool largeArcFlag) +{ + m_largeArcFlag = largeArcFlag; +} + +bool SVGPathSegArcRelImpl::largeArcFlag() const +{ + return m_largeArcFlag; +} + +void SVGPathSegArcRelImpl::setSweepFlag(bool sweepFlag) +{ + m_sweepFlag = sweepFlag; +} + +bool SVGPathSegArcRelImpl::sweepFlag() const +{ + return m_sweepFlag; +} + +void SVGPathSegArcRelImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const +{ + double dx = x(); + double dy = y(); + double startSlope; + double endSlope; + getArcSlopes(true, curx, cury, angle(), x(), y(), r1(), r2(), largeArcFlag(), sweepFlag(), &startSlope, &endSlope); + *pDx = dx; + *pDy = dy; + *pStartSlope = startSlope; + *pEndSlope = endSlope; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegArcRelImpl::s_hashTable 11 + x SVGPathSegArcRelImpl::X DontDelete + y SVGPathSegArcRelImpl::Y DontDelete + r1 SVGPathSegArcRelImpl::R1 DontDelete + r2 SVGPathSegArcRelImpl::R2 DontDelete + angle SVGPathSegArcRelImpl::Angle DontDelete + largeArcFlag SVGPathSegArcRelImpl::LargeArcFlag DontDelete + sweepFlag SVGPathSegArcRelImpl::SweepFlag DontDelete +@end +*/ + +Value SVGPathSegArcRelImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case X: + return Number(x()); + case Y: + return Number(y()); + case R1: + return Number(r1()); + case R2: + return Number(r2()); + case Angle: + return Number(angle()); + case LargeArcFlag: + return Boolean(largeArcFlag()); + case SweepFlag: + return Boolean(sweepFlag()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathSegArcRelImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case X: + m_x = value.toNumber(exec); + break; + case Y: + m_y = value.toNumber(exec); + break; + case R1: + m_r1 = value.toNumber(exec); + break; + case R2: + m_r2 = value.toNumber(exec); + break; + case Angle: + m_angle = value.toNumber(exec); + break; + case LargeArcFlag: + m_largeArcFlag = value.toBoolean(exec); + break; + case SweepFlag: + m_sweepFlag = value.toBoolean(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegArcImpl.h b/ksvg/impl/SVGPathSegArcImpl.h new file mode 100644 index 00000000..f0e375d6 --- /dev/null +++ b/ksvg/impl/SVGPathSegArcImpl.h @@ -0,0 +1,150 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegArcImpl_H +#define SVGPathSegArcImpl_H + +#include "ksvg_lookup.h" + +#include "SVGPathSegImpl.h" + +namespace KSVG +{ + +class SVGPathSegArcAbsImpl : public SVGPathSegImpl +{ +public: + SVGPathSegArcAbsImpl(); + virtual ~SVGPathSegArcAbsImpl(); + + virtual unsigned short pathSegType() const { return PATHSEG_ARC_ABS; } + virtual DOM::DOMString pathSegTypeAsLetter() const { return "A"; } + virtual QString toString() const { return QString("A %1 %2 %3 %4 %5 %6 %7").arg(m_r1).arg(m_r2).arg(m_angle).arg(m_largeArcFlag).arg(m_sweepFlag).arg(m_x).arg(m_y); } + + void setX(double x); + double x() const; + + void setY(double y); + double y() const; + + void setR1(double r1); + double r1() const; + + void setR2(double r2); + double r2() const; + + void setAngle(double angle); + double angle() const; + + void setLargeArcFlag(bool largeArcFlag); + bool largeArcFlag() const; + + void setSweepFlag(bool sweepFlag); + bool sweepFlag() const; + + virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const; + +private: + double m_x; + double m_y; + double m_r1; + double m_r2; + double m_angle; + + bool m_largeArcFlag : 1; + bool m_sweepFlag : 1; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + X, Y, R1, R2, Angle, LargeArcFlag, SweepFlag + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + + +class SVGPathSegArcRelImpl : public SVGPathSegImpl +{ +public: + SVGPathSegArcRelImpl(); + virtual ~SVGPathSegArcRelImpl(); + + virtual unsigned short pathSegType() const { return PATHSEG_ARC_REL; } + virtual DOM::DOMString pathSegTypeAsLetter() const { return "a"; } + virtual QString toString() const { return QString("a %1 %2 %3 %4 %5 %6 %7").arg(m_r1).arg(m_r2).arg(m_angle).arg(m_largeArcFlag).arg(m_sweepFlag).arg(m_x).arg(m_y); } + + void setX(double x); + double x() const; + + void setY(double y); + double y() const; + + void setR1(double r1); + double r1() const; + + void setR2(double r2); + double r2() const; + + void setAngle(double angle); + double angle() const; + + void setLargeArcFlag(bool largeArcFlag); + bool largeArcFlag() const; + + void setSweepFlag(bool sweepFlag); + bool sweepFlag() const; + + virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const; + +private: + double m_x; + double m_y; + double m_r1; + double m_r2; + double m_angle; + + bool m_largeArcFlag : 1; + bool m_sweepFlag : 1; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + X, Y, R1, R2, Angle, LargeArcFlag, SweepFlag + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegClosePathImpl.cc b/ksvg/impl/SVGPathSegClosePathImpl.cc new file mode 100644 index 00000000..c18e6027 --- /dev/null +++ b/ksvg/impl/SVGPathSegClosePathImpl.cc @@ -0,0 +1,46 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPathSegClosePathImpl.h" +#include "SVGAngleImpl.h" + +using namespace KSVG; + +SVGPathSegClosePathImpl::SVGPathSegClosePathImpl() : SVGPathSegImpl() +{ +} + +SVGPathSegClosePathImpl::~SVGPathSegClosePathImpl() +{ +} + +void SVGPathSegClosePathImpl::getDeltasAndSlopes(double curx, double cury, double *pdx, double *pdy, double *pstartSlope, double *pendSlope) const +{ + double dx = x() - curx; + double dy = y() - cury; + double startSlope = SVGAngleImpl::todeg(atan2(dy, dx)); + double endSlope = startSlope; + *pdx = dx; + *pdy = dy; + *pstartSlope = startSlope; + *pendSlope = endSlope; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegClosePathImpl.h b/ksvg/impl/SVGPathSegClosePathImpl.h new file mode 100644 index 00000000..c4cf63ce --- /dev/null +++ b/ksvg/impl/SVGPathSegClosePathImpl.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegClosePathImpl_H +#define SVGPathSegClosePathImpl_H + +#include "ksvg_lookup.h" + +#include "SVGPathSegImpl.h" + +namespace KSVG +{ + +class SVGPathSegClosePathImpl : public SVGPathSegImpl +{ +public: + SVGPathSegClosePathImpl(); + virtual ~SVGPathSegClosePathImpl(); + + virtual unsigned short pathSegType() const { return PATHSEG_CLOSEPATH; } + virtual DOM::DOMString pathSegTypeAsLetter() const { return "Z"; } + virtual QString toString() const { return "Z"; } + + void setX(double x) { m_x = x; } + void setY(double y) { m_y = y; } + + double x() const { return m_x; } + double y() const { return m_y; } + + virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const; + +private: + double m_x; + double m_y; + +public: + KSVG_FORWARDGET +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegCurvetoCubicImpl.cc b/ksvg/impl/SVGPathSegCurvetoCubicImpl.cc new file mode 100644 index 00000000..468b1fb3 --- /dev/null +++ b/ksvg/impl/SVGPathSegCurvetoCubicImpl.cc @@ -0,0 +1,325 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGPathSegCurvetoCubicImpl.h" +#include "SVGAngleImpl.h" + +using namespace KSVG; + +#include "SVGPathSegCurvetoCubicImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGPathSegCurvetoCubicAbsImpl::SVGPathSegCurvetoCubicAbsImpl() : SVGPathSegImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGPathSegCurvetoCubicAbsImpl::~SVGPathSegCurvetoCubicAbsImpl() +{ +} + +void SVGPathSegCurvetoCubicAbsImpl::setX(const double &x) +{ + m_x = x; +} + +double SVGPathSegCurvetoCubicAbsImpl::x() const +{ + return m_x; +} + +void SVGPathSegCurvetoCubicAbsImpl::setY(const double &y) +{ + m_y = y; +} + +double SVGPathSegCurvetoCubicAbsImpl::y() const +{ + return m_y; +} + +void SVGPathSegCurvetoCubicAbsImpl::setX1(const double &x1) +{ + m_x1 = x1; +} + +double SVGPathSegCurvetoCubicAbsImpl::x1() const +{ + return m_x1; +} + +void SVGPathSegCurvetoCubicAbsImpl::setY1(const double &y1) +{ + m_y1 = y1; +} + +double SVGPathSegCurvetoCubicAbsImpl::y1() const +{ + return m_y1; +} + +void SVGPathSegCurvetoCubicAbsImpl::setX2(const double &x2) +{ + m_x2 = x2; +} + +double SVGPathSegCurvetoCubicAbsImpl::x2() const +{ + return m_x2; +} + +void SVGPathSegCurvetoCubicAbsImpl::setY2(const double &y2) +{ + m_y2 = y2; +} + +double SVGPathSegCurvetoCubicAbsImpl::y2() const +{ + return m_y2; +} + +void SVGPathSegCurvetoCubicAbsImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const +{ + double dx = x() - curx; + double dy = y() - cury; + double startSlope = SVGAngleImpl::todeg(atan2(y1() - cury, x1() - curx)); + double endSlope = SVGAngleImpl::todeg(atan2(y() - y2(), x() - x2())); + *pDx = dx; + *pDy = dy; + *pStartSlope = startSlope; + *pEndSlope = endSlope; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegCurvetoCubicAbsImpl::s_hashTable 7 + x SVGPathSegCurvetoCubicAbsImpl::X DontDelete + y SVGPathSegCurvetoCubicAbsImpl::Y DontDelete + x1 SVGPathSegCurvetoCubicAbsImpl::X1 DontDelete + y1 SVGPathSegCurvetoCubicAbsImpl::Y1 DontDelete + x2 SVGPathSegCurvetoCubicAbsImpl::X2 DontDelete + y2 SVGPathSegCurvetoCubicAbsImpl::Y2 DontDelete +@end +*/ + +Value SVGPathSegCurvetoCubicAbsImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case X: + return Number(x()); + case Y: + return Number(y()); + case X1: + return Number(x1()); + case Y1: + return Number(y1()); + case X2: + return Number(x2()); + case Y2: + return Number(y2()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathSegCurvetoCubicAbsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case X: + m_x = value.toNumber(exec); + break; + case Y: + m_y = value.toNumber(exec); + break; + case X1: + m_x1 = value.toNumber(exec); + break; + case Y1: + m_y1 = value.toNumber(exec); + break; + case X2: + m_x2 = value.toNumber(exec); + break; + case Y2: + m_y2 = value.toNumber(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + + + + +SVGPathSegCurvetoCubicRelImpl::SVGPathSegCurvetoCubicRelImpl() : SVGPathSegImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGPathSegCurvetoCubicRelImpl::~SVGPathSegCurvetoCubicRelImpl() +{ +} + +void SVGPathSegCurvetoCubicRelImpl::setX(const double &x) +{ + m_x = x; +} + +double SVGPathSegCurvetoCubicRelImpl::x() const +{ + return m_x; +} + +void SVGPathSegCurvetoCubicRelImpl::setY(const double &y) +{ + m_y = y; +} + +double SVGPathSegCurvetoCubicRelImpl::y() const +{ + return m_y; +} + +void SVGPathSegCurvetoCubicRelImpl::setX1(const double &x1) +{ + m_x1 = x1; +} + +double SVGPathSegCurvetoCubicRelImpl::x1() const +{ + return m_x1; +} + +void SVGPathSegCurvetoCubicRelImpl::setY1(const double &y1) +{ + m_y1 = y1; +} + +double SVGPathSegCurvetoCubicRelImpl::y1() const +{ + return m_y1; +} + +void SVGPathSegCurvetoCubicRelImpl::setX2(const double &x2) +{ + m_x2 = x2; +} + +double SVGPathSegCurvetoCubicRelImpl::x2() const +{ + return m_x2; +} + +void SVGPathSegCurvetoCubicRelImpl::setY2(const double &y2) +{ + m_y2 = y2; +} + +double SVGPathSegCurvetoCubicRelImpl::y2() const +{ + return m_y2; +} + +void SVGPathSegCurvetoCubicRelImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const +{ + Q_UNUSED(curx); + Q_UNUSED(cury); + double dx = x(); + double dy = y(); + double startSlope = SVGAngleImpl::todeg(atan2(y1(), x1())); + double endSlope = SVGAngleImpl::todeg(atan2(y() - y2(), x() - x2())); + *pDx = dx; + *pDy = dy; + *pStartSlope = startSlope; + *pEndSlope = endSlope; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegCurvetoCubicRelImpl::s_hashTable 7 + x SVGPathSegCurvetoCubicRelImpl::X DontDelete + y SVGPathSegCurvetoCubicRelImpl::Y DontDelete + x1 SVGPathSegCurvetoCubicRelImpl::X1 DontDelete + y1 SVGPathSegCurvetoCubicRelImpl::Y1 DontDelete + x2 SVGPathSegCurvetoCubicRelImpl::X2 DontDelete + y2 SVGPathSegCurvetoCubicRelImpl::Y2 DontDelete +@end +*/ + +Value SVGPathSegCurvetoCubicRelImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case X: + return Number(x()); + case Y: + return Number(y()); + case X1: + return Number(x1()); + case Y1: + return Number(y1()); + case X2: + return Number(x2()); + case Y2: + return Number(y2()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathSegCurvetoCubicRelImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case X: + m_x = value.toNumber(exec); + break; + case Y: + m_y = value.toNumber(exec); + break; + case X1: + m_x1 = value.toNumber(exec); + break; + case Y1: + m_y1 = value.toNumber(exec); + break; + case X2: + m_x2 = value.toNumber(exec); + break; + case Y2: + m_y2 = value.toNumber(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegCurvetoCubicImpl.h b/ksvg/impl/SVGPathSegCurvetoCubicImpl.h new file mode 100644 index 00000000..8f408f91 --- /dev/null +++ b/ksvg/impl/SVGPathSegCurvetoCubicImpl.h @@ -0,0 +1,139 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegCurvetoCubicImpl_H +#define SVGPathSegCurvetoCubicImpl_H + +#include "ksvg_lookup.h" + +#include "SVGPathSegImpl.h" + +namespace KSVG +{ + +class SVGPathSegCurvetoCubicAbsImpl : public SVGPathSegImpl +{ +public: + SVGPathSegCurvetoCubicAbsImpl(); + virtual ~SVGPathSegCurvetoCubicAbsImpl(); + + virtual unsigned short pathSegType() const { return PATHSEG_CURVETO_CUBIC_ABS; } + virtual DOM::DOMString pathSegTypeAsLetter() const { return "C"; } + virtual QString toString() const { return QString("C %1 %2 %3 %4 %5 %6").arg(m_x1).arg(m_y1).arg(m_x2).arg(m_y2).arg(m_x).arg(m_y); } + + void setX(const double &); + double x() const; + + void setY(const double &); + double y() const; + + void setX1(const double &); + double x1() const; + + void setY1(const double &); + double y1() const; + + void setX2(const double &); + double x2() const; + + void setY2(const double &); + double y2() const; + + virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const; + +private: + double m_x; + double m_y; + double m_x1; + double m_y1; + double m_x2; + double m_y2; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + X, Y, X1, Y1, X2, Y2 + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +class SVGPathSegCurvetoCubicRelImpl : public SVGPathSegImpl +{ +public: + SVGPathSegCurvetoCubicRelImpl(); + virtual ~SVGPathSegCurvetoCubicRelImpl(); + + virtual unsigned short pathSegType() const { return PATHSEG_CURVETO_CUBIC_REL; } + virtual DOM::DOMString pathSegTypeAsLetter() const { return "c"; } + virtual QString toString() const { return QString("c %1 %2 %3 %4 %5 %6").arg(m_x1).arg(m_y1).arg(m_x2).arg(m_y2).arg(m_x).arg(m_y); } + + void setX(const double &); + double x() const; + + void setY(const double &); + double y() const; + + void setX1(const double &); + double x1() const; + + void setY1(const double &); + double y1() const; + + void setX2(const double &); + double x2() const; + + void setY2(const double &); + double y2() const; + + virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const; + +private: + double m_x; + double m_y; + double m_x1; + double m_y1; + double m_x2; + double m_y2; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + X, Y, X1, Y1, X2, Y2 + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegCurvetoCubicSmoothImpl.cc b/ksvg/impl/SVGPathSegCurvetoCubicSmoothImpl.cc new file mode 100644 index 00000000..1d5c124a --- /dev/null +++ b/ksvg/impl/SVGPathSegCurvetoCubicSmoothImpl.cc @@ -0,0 +1,298 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGPathSegCurvetoCubicSmoothImpl.h" +#include "SVGAngleImpl.h" + +using namespace KSVG; + +#include "SVGPathSegCurvetoCubicSmoothImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGPathSegCurvetoCubicSmoothAbsImpl::SVGPathSegCurvetoCubicSmoothAbsImpl() : SVGPathSegImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGPathSegCurvetoCubicSmoothAbsImpl::~SVGPathSegCurvetoCubicSmoothAbsImpl() +{ +} + +void SVGPathSegCurvetoCubicSmoothAbsImpl::setX(const double &x) +{ + m_x = x; +} + +double SVGPathSegCurvetoCubicSmoothAbsImpl::x() const +{ + return m_x; +} + +void SVGPathSegCurvetoCubicSmoothAbsImpl::setY(const double &y) +{ + m_y = y; +} + +double SVGPathSegCurvetoCubicSmoothAbsImpl::y() const +{ + return m_y; +} + +void SVGPathSegCurvetoCubicSmoothAbsImpl::setX2(const double &x2) +{ + m_x2 = x2; +} + +double SVGPathSegCurvetoCubicSmoothAbsImpl::x2() const +{ + return m_x2; +} + +void SVGPathSegCurvetoCubicSmoothAbsImpl::setY2(const double &y2) +{ + m_y2 = y2; +} + +double SVGPathSegCurvetoCubicSmoothAbsImpl::y2() const +{ + return m_y2; +} + +void SVGPathSegCurvetoCubicSmoothAbsImpl::setPreviousX2(double x2) +{ + m_previousX2 = x2; +} + +void SVGPathSegCurvetoCubicSmoothAbsImpl::setPreviousY2(double y2) +{ + m_previousY2 = y2; +} + +double SVGPathSegCurvetoCubicSmoothAbsImpl::x1(double curx) const +{ + return curx - (m_previousX2 - curx); +} + +double SVGPathSegCurvetoCubicSmoothAbsImpl::y1(double cury) const +{ + return cury - (m_previousY2 - cury); +} + +void SVGPathSegCurvetoCubicSmoothAbsImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const +{ + double dx = x() - curx; + double dy = y() - cury; + double startSlope = SVGAngleImpl::todeg(atan2(y1(cury) - cury, x1(curx) - curx)); + double endSlope = SVGAngleImpl::todeg(atan2(y() - y2(), x() - x2())); + *pDx = dx; + *pDy = dy; + *pStartSlope = startSlope; + *pEndSlope = endSlope; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegCurvetoCubicSmoothAbsImpl::s_hashTable 5 + x SVGPathSegCurvetoCubicSmoothAbsImpl::X DontDelete + y SVGPathSegCurvetoCubicSmoothAbsImpl::Y DontDelete + x2 SVGPathSegCurvetoCubicSmoothAbsImpl::X2 DontDelete + y2 SVGPathSegCurvetoCubicSmoothAbsImpl::Y2 DontDelete +@end +*/ + +Value SVGPathSegCurvetoCubicSmoothAbsImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case X: + return Number(x()); + case Y: + return Number(y()); + case X2: + return Number(x2()); + case Y2: + return Number(y2()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathSegCurvetoCubicSmoothAbsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case X: + m_x = value.toNumber(exec); + break; + case Y: + m_y = value.toNumber(exec); + break; + case X2: + m_x2 = value.toNumber(exec); + break; + case Y2: + m_y2 = value.toNumber(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + + + +SVGPathSegCurvetoCubicSmoothRelImpl::SVGPathSegCurvetoCubicSmoothRelImpl() : SVGPathSegImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGPathSegCurvetoCubicSmoothRelImpl::~SVGPathSegCurvetoCubicSmoothRelImpl() +{ +} + +void SVGPathSegCurvetoCubicSmoothRelImpl::setX(const double &x) +{ + m_x = x; +} + +double SVGPathSegCurvetoCubicSmoothRelImpl::x() const +{ + return m_x; +} + +void SVGPathSegCurvetoCubicSmoothRelImpl::setY(const double &y) +{ + m_y = y; +} + +double SVGPathSegCurvetoCubicSmoothRelImpl::y() const +{ + return m_y; +} + +void SVGPathSegCurvetoCubicSmoothRelImpl::setX2(const double &x2) +{ + m_x2 = x2; +} + +double SVGPathSegCurvetoCubicSmoothRelImpl::x2() const +{ + return m_x2; +} + +void SVGPathSegCurvetoCubicSmoothRelImpl::setY2(const double &y2) +{ + m_y2 = y2; +} + +double SVGPathSegCurvetoCubicSmoothRelImpl::y2() const +{ + return m_y2; +} + +void SVGPathSegCurvetoCubicSmoothRelImpl::setPreviousAbsX2(double x2) +{ + m_previousAbsX2 = x2; +} + +void SVGPathSegCurvetoCubicSmoothRelImpl::setPreviousAbsY2(double y2) +{ + m_previousAbsY2 = y2; +} + +double SVGPathSegCurvetoCubicSmoothRelImpl::absX1(double curx) const +{ + return curx - (m_previousAbsX2 - curx); +} + +double SVGPathSegCurvetoCubicSmoothRelImpl::absY1(double cury) const +{ + return cury - (m_previousAbsY2 - cury); +} + +void SVGPathSegCurvetoCubicSmoothRelImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const +{ + double dx = x(); + double dy = y(); + double startSlope = SVGAngleImpl::todeg(atan2(absY1(cury) - cury, absX1(curx) - curx)); + double endSlope = SVGAngleImpl::todeg(atan2(y() - y2(), x() - x2())); + *pDx = dx; + *pDy = dy; + *pStartSlope = startSlope; + *pEndSlope = endSlope; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegCurvetoCubicSmoothRelImpl::s_hashTable 5 + x SVGPathSegCurvetoCubicSmoothRelImpl::X DontDelete + y SVGPathSegCurvetoCubicSmoothRelImpl::Y DontDelete + x2 SVGPathSegCurvetoCubicSmoothRelImpl::X2 DontDelete + y2 SVGPathSegCurvetoCubicSmoothRelImpl::Y2 DontDelete +@end +*/ + +Value SVGPathSegCurvetoCubicSmoothRelImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case X: + return Number(x()); + case Y: + return Number(y()); + case X2: + return Number(x2()); + case Y2: + return Number(y2()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathSegCurvetoCubicSmoothRelImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case X: + m_x = value.toNumber(exec); + break; + case Y: + m_y = value.toNumber(exec); + break; + case X2: + m_x2 = value.toNumber(exec); + break; + case Y2: + m_y2 = value.toNumber(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegCurvetoCubicSmoothImpl.h b/ksvg/impl/SVGPathSegCurvetoCubicSmoothImpl.h new file mode 100644 index 00000000..0def6514 --- /dev/null +++ b/ksvg/impl/SVGPathSegCurvetoCubicSmoothImpl.h @@ -0,0 +1,139 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegCurvetoCubicSmoothImpl_H +#define SVGPathSegCurvetoCubicSmoothImpl_H + +#include "ksvg_lookup.h" + +#include "SVGPathSegImpl.h" + +namespace KSVG +{ + +class SVGPathSegCurvetoCubicSmoothAbsImpl : public SVGPathSegImpl +{ +public: + SVGPathSegCurvetoCubicSmoothAbsImpl(); + virtual ~SVGPathSegCurvetoCubicSmoothAbsImpl(); + + virtual unsigned short pathSegType() const { return PATHSEG_CURVETO_CUBIC_SMOOTH_ABS; } + virtual DOM::DOMString pathSegTypeAsLetter() const { return "S"; } + virtual QString toString() const { return QString("S %1 %2 %3 %4").arg(m_x2).arg(m_y2).arg(m_x).arg(m_y); } + + void setX(const double &); + double x() const; + + void setY(const double &); + double y() const; + + void setX2(const double &); + double x2() const; + + void setY2(const double &); + double y2() const; + + void setPreviousX2(double x2); + void setPreviousY2(double y2); + + double x1(double curx) const; + double y1(double cury) const; + + virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const; + +private: + double m_x; + double m_y; + double m_x2; + double m_y2; + double m_previousX2; + double m_previousY2; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + X, Y, X2, Y2 + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +class SVGPathSegCurvetoCubicSmoothRelImpl : public SVGPathSegImpl +{ +public: + SVGPathSegCurvetoCubicSmoothRelImpl(); + virtual ~SVGPathSegCurvetoCubicSmoothRelImpl(); + + virtual unsigned short pathSegType() const { return PATHSEG_CURVETO_CUBIC_SMOOTH_REL; } + virtual DOM::DOMString pathSegTypeAsLetter() const { return "s"; } + virtual QString toString() const { return QString("s %1 %2 %3 %4").arg(m_x2).arg(m_y2).arg(m_x).arg(m_y); } + + void setX(const double &); + double x() const; + + void setY(const double &); + double y() const; + + void setX2(const double &); + double x2() const; + + void setY2(const double &); + double y2() const; + + void setPreviousAbsX2(double x2); + void setPreviousAbsY2(double y2); + + double absX1(double curx) const; + double absY1(double cury) const; + + virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const; + +private: + double m_x; + double m_y; + double m_x2; + double m_y2; + double m_previousAbsX2; + double m_previousAbsY2; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + X, Y, X2, Y2 + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegCurvetoQuadraticImpl.cc b/ksvg/impl/SVGPathSegCurvetoQuadraticImpl.cc new file mode 100644 index 00000000..e6199a21 --- /dev/null +++ b/ksvg/impl/SVGPathSegCurvetoQuadraticImpl.cc @@ -0,0 +1,260 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGPathSegCurvetoQuadraticImpl.h" +#include "SVGAngleImpl.h" + +using namespace KSVG; + +#include "SVGPathSegCurvetoQuadraticImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGPathSegCurvetoQuadraticAbsImpl::SVGPathSegCurvetoQuadraticAbsImpl() : SVGPathSegImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGPathSegCurvetoQuadraticAbsImpl::~SVGPathSegCurvetoQuadraticAbsImpl() +{ +} + +void SVGPathSegCurvetoQuadraticAbsImpl::setX(const double &x) +{ + m_x = x; +} + +double SVGPathSegCurvetoQuadraticAbsImpl::x() const +{ + return m_x; +} + +void SVGPathSegCurvetoQuadraticAbsImpl::setY(const double &y) +{ + m_y = y; +} + +double SVGPathSegCurvetoQuadraticAbsImpl::y() const +{ + return m_y; +} + +void SVGPathSegCurvetoQuadraticAbsImpl::setX1(const double &x1) +{ + m_x1 = x1; +} + +double SVGPathSegCurvetoQuadraticAbsImpl::x1() const +{ + return m_x1; +} + +void SVGPathSegCurvetoQuadraticAbsImpl::setY1(const double &y1) +{ + m_y1 = y1; +} + +double SVGPathSegCurvetoQuadraticAbsImpl::y1() const +{ + return m_y1; +} + +void SVGPathSegCurvetoQuadraticAbsImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const +{ + double dx = x() - curx; + double dy = y() - cury; + double startSlope = SVGAngleImpl::todeg(atan2(y1() - cury, x1() - curx)); + double endSlope = SVGAngleImpl::todeg(atan2(y() - y1(), x() - x1())); + *pDx = dx; + *pDy = dy; + *pStartSlope = startSlope; + *pEndSlope = endSlope; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegCurvetoQuadraticAbsImpl::s_hashTable 5 + x SVGPathSegCurvetoQuadraticAbsImpl::X DontDelete + y SVGPathSegCurvetoQuadraticAbsImpl::Y DontDelete + x1 SVGPathSegCurvetoQuadraticAbsImpl::X1 DontDelete + y1 SVGPathSegCurvetoQuadraticAbsImpl::Y1 DontDelete +@end +*/ + +Value SVGPathSegCurvetoQuadraticAbsImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case X: + return Number(x()); + case Y: + return Number(y()); + case X1: + return Number(x1()); + case Y1: + return Number(y1()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathSegCurvetoQuadraticAbsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case X: + m_x = value.toNumber(exec); + break; + case Y: + m_y = value.toNumber(exec); + break; + case X1: + m_x1 = value.toNumber(exec); + break; + case Y1: + m_y1 = value.toNumber(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + + + +SVGPathSegCurvetoQuadraticRelImpl::SVGPathSegCurvetoQuadraticRelImpl() : SVGPathSegImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGPathSegCurvetoQuadraticRelImpl::~SVGPathSegCurvetoQuadraticRelImpl() +{ +} + +void SVGPathSegCurvetoQuadraticRelImpl::setX(const double &x) +{ + m_x = x; +} + +double SVGPathSegCurvetoQuadraticRelImpl::x() const +{ + return m_x; +} + +void SVGPathSegCurvetoQuadraticRelImpl::setY(const double &y) +{ + m_y = y; +} + +double SVGPathSegCurvetoQuadraticRelImpl::y() const +{ + return m_y; +} + +void SVGPathSegCurvetoQuadraticRelImpl::setX1(const double &x1) +{ + m_x1 = x1; +} + +double SVGPathSegCurvetoQuadraticRelImpl::x1() const +{ + return m_x1; +} + +void SVGPathSegCurvetoQuadraticRelImpl::setY1(const double &y1) +{ + m_y1 = y1; +} + +double SVGPathSegCurvetoQuadraticRelImpl::y1() const +{ + return m_y1; +} + +void SVGPathSegCurvetoQuadraticRelImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const +{ + Q_UNUSED(curx); + Q_UNUSED(cury); + double dx = x(); + double dy = y(); + double startSlope = SVGAngleImpl::todeg(atan2(y1(), x1())); + double endSlope = SVGAngleImpl::todeg(atan2(y() - y1(), x() - x1())); + *pDx = dx; + *pDy = dy; + *pStartSlope = startSlope; + *pEndSlope = endSlope; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegCurvetoQuadraticRelImpl::s_hashTable 5 + x SVGPathSegCurvetoQuadraticRelImpl::X DontDelete + y SVGPathSegCurvetoQuadraticRelImpl::Y DontDelete + x1 SVGPathSegCurvetoQuadraticRelImpl::X1 DontDelete + y1 SVGPathSegCurvetoQuadraticRelImpl::Y1 DontDelete +@end +*/ + +Value SVGPathSegCurvetoQuadraticRelImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case X: + return Number(x()); + case Y: + return Number(y()); + case X1: + return Number(x1()); + case Y1: + return Number(y1()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathSegCurvetoQuadraticRelImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case X: + m_x = value.toNumber(exec); + break; + case Y: + m_y = value.toNumber(exec); + break; + case X1: + m_x1 = value.toNumber(exec); + break; + case Y1: + m_y1 = value.toNumber(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegCurvetoQuadraticImpl.h b/ksvg/impl/SVGPathSegCurvetoQuadraticImpl.h new file mode 100644 index 00000000..6fe9ef15 --- /dev/null +++ b/ksvg/impl/SVGPathSegCurvetoQuadraticImpl.h @@ -0,0 +1,123 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegCurvetoQuadraticImpl_H +#define SVGPathSegCurvetoQuadraticImpl_H + +#include "ksvg_lookup.h" + +#include "SVGPathSegImpl.h" + +namespace KSVG +{ + +class SVGPathSegCurvetoQuadraticAbsImpl : public SVGPathSegImpl +{ +public: + SVGPathSegCurvetoQuadraticAbsImpl(); + virtual ~SVGPathSegCurvetoQuadraticAbsImpl(); + + virtual unsigned short pathSegType() const { return PATHSEG_CURVETO_QUADRATIC_ABS; } + virtual DOM::DOMString pathSegTypeAsLetter() const { return "Q"; } + virtual QString toString() const { return QString("Q %1 %2 %3 %4").arg(m_x1).arg(m_y1).arg(m_x).arg(m_y); } + + void setX(const double &); + double x() const; + + void setY(const double &); + double y() const; + + void setX1(const double &); + double x1() const; + + void setY1(const double &); + double y1() const; + + virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const; + +private: + double m_x; + double m_y; + double m_x1; + double m_y1; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + X, Y, X1, Y1 + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +class SVGPathSegCurvetoQuadraticRelImpl : public SVGPathSegImpl +{ +public: + SVGPathSegCurvetoQuadraticRelImpl(); + virtual ~SVGPathSegCurvetoQuadraticRelImpl(); + + virtual unsigned short pathSegType() const { return PATHSEG_CURVETO_QUADRATIC_REL; } + virtual DOM::DOMString pathSegTypeAsLetter() const { return "q"; } + virtual QString toString() const { return QString("q %1 %2 %3 %4").arg(m_x1).arg(m_y1).arg(m_x).arg(m_y); } + + void setX(const double &); + double x() const; + + void setY(const double &); + double y() const; + + void setX1(const double &); + double x1() const; + + void setY1(const double &); + double y1() const; + + virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const; + +private: + double m_x; + double m_y; + double m_x1; + double m_y1; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + X, Y, X1, Y1 + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegCurvetoQuadraticSmoothImpl.cc b/ksvg/impl/SVGPathSegCurvetoQuadraticSmoothImpl.cc new file mode 100644 index 00000000..f8c141da --- /dev/null +++ b/ksvg/impl/SVGPathSegCurvetoQuadraticSmoothImpl.cc @@ -0,0 +1,235 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGPathSegCurvetoQuadraticSmoothImpl.h" +#include "SVGAngleImpl.h" + +using namespace KSVG; + +#include "SVGPathSegCurvetoQuadraticSmoothImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGPathSegCurvetoQuadraticSmoothAbsImpl::SVGPathSegCurvetoQuadraticSmoothAbsImpl() : SVGPathSegImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGPathSegCurvetoQuadraticSmoothAbsImpl::~SVGPathSegCurvetoQuadraticSmoothAbsImpl() +{ +} + +void SVGPathSegCurvetoQuadraticSmoothAbsImpl::setX(const double &x) +{ + m_x = x; +} + +double SVGPathSegCurvetoQuadraticSmoothAbsImpl::x() const +{ + return m_x; +} + +void SVGPathSegCurvetoQuadraticSmoothAbsImpl::setY(const double &y) +{ + m_y = y; +} + +double SVGPathSegCurvetoQuadraticSmoothAbsImpl::y() const +{ + return m_y; +} + +void SVGPathSegCurvetoQuadraticSmoothAbsImpl::setPreviousX1(double x1) +{ + m_previousX1 = x1; +} + +void SVGPathSegCurvetoQuadraticSmoothAbsImpl::setPreviousY1(double y1) +{ + m_previousY1 = y1; +} + +double SVGPathSegCurvetoQuadraticSmoothAbsImpl::x1(double curx) const +{ + return curx - (m_previousX1 - curx); +} + +double SVGPathSegCurvetoQuadraticSmoothAbsImpl::y1(double cury) const +{ + return cury - (m_previousY1 - cury); +} + +void SVGPathSegCurvetoQuadraticSmoothAbsImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const +{ + double dx = x() - curx; + double dy = y() - cury; + double startSlope = SVGAngleImpl::todeg(atan2(y1(cury) - cury, x1(curx) - curx)); + double endSlope = SVGAngleImpl::todeg(atan2(y() - y1(cury), x() - x1(curx))); + *pDx = dx; + *pDy = dy; + *pStartSlope = startSlope; + *pEndSlope = endSlope; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegCurvetoQuadraticSmoothAbsImpl::s_hashTable 3 + x SVGPathSegCurvetoQuadraticSmoothAbsImpl::X DontDelete + y SVGPathSegCurvetoQuadraticSmoothAbsImpl::Y DontDelete +@end +*/ + +Value SVGPathSegCurvetoQuadraticSmoothAbsImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case X: + return Number(x()); + case Y: + return Number(y()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathSegCurvetoQuadraticSmoothAbsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case X: + m_x = value.toNumber(exec); + break; + case Y: + m_y = value.toNumber(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + + + + +SVGPathSegCurvetoQuadraticSmoothRelImpl::SVGPathSegCurvetoQuadraticSmoothRelImpl() : SVGPathSegImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGPathSegCurvetoQuadraticSmoothRelImpl::~SVGPathSegCurvetoQuadraticSmoothRelImpl() +{ +} + +void SVGPathSegCurvetoQuadraticSmoothRelImpl::setX(const double &x) +{ + m_x = x; +} + +double SVGPathSegCurvetoQuadraticSmoothRelImpl::x() const +{ + return m_x; +} + +void SVGPathSegCurvetoQuadraticSmoothRelImpl::setY(const double &y) +{ + m_y = y; +} + +double SVGPathSegCurvetoQuadraticSmoothRelImpl::y() const +{ + return m_y; +} + +void SVGPathSegCurvetoQuadraticSmoothRelImpl::setPreviousAbsX1(double x1) +{ + m_previousAbsX1 = x1; +} + +void SVGPathSegCurvetoQuadraticSmoothRelImpl::setPreviousAbsY1(double y1) +{ + m_previousAbsY1 = y1; +} + +double SVGPathSegCurvetoQuadraticSmoothRelImpl::absX1(double curx) const +{ + return curx - (m_previousAbsX1 - curx); +} + +double SVGPathSegCurvetoQuadraticSmoothRelImpl::absY1(double cury) const +{ + return cury - (m_previousAbsY1 - cury); +} + +void SVGPathSegCurvetoQuadraticSmoothRelImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const +{ + double dx = x(); + double dy = y(); + double startSlope = SVGAngleImpl::todeg(atan2(absY1(cury) - cury, absX1(curx) - curx)); + double endSlope = SVGAngleImpl::todeg(atan2(cury + y() - absY1(cury), curx + x() - absX1(curx))); + *pDx = dx; + *pDy = dy; + *pStartSlope = startSlope; + *pEndSlope = endSlope; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegCurvetoQuadraticSmoothRelImpl::s_hashTable 3 + x SVGPathSegCurvetoQuadraticSmoothRelImpl::X DontDelete + y SVGPathSegCurvetoQuadraticSmoothRelImpl::Y DontDelete +@end +*/ + +Value SVGPathSegCurvetoQuadraticSmoothRelImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case X: + return Number(x()); + case Y: + return Number(y()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathSegCurvetoQuadraticSmoothRelImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case X: + m_x = value.toNumber(exec); + break; + case Y: + m_y = value.toNumber(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegCurvetoQuadraticSmoothImpl.h b/ksvg/impl/SVGPathSegCurvetoQuadraticSmoothImpl.h new file mode 100644 index 00000000..dffa3355 --- /dev/null +++ b/ksvg/impl/SVGPathSegCurvetoQuadraticSmoothImpl.h @@ -0,0 +1,123 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegCurvetoQuadraticSmoothImpl_H +#define SVGPathSegCurvetoQuadraticSmoothImpl_H + +#include "ksvg_lookup.h" + +#include "SVGPathSegImpl.h" + +namespace KSVG +{ + +class SVGPathSegCurvetoQuadraticSmoothAbsImpl : public SVGPathSegImpl +{ +public: + SVGPathSegCurvetoQuadraticSmoothAbsImpl(); + virtual ~SVGPathSegCurvetoQuadraticSmoothAbsImpl(); + + virtual unsigned short pathSegType() const { return PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS; } + virtual DOM::DOMString pathSegTypeAsLetter() const { return "T"; } + virtual QString toString() const { return QString("T %1 %2").arg(m_x).arg(m_y); } + + void setX(const double &); + double x() const; + + void setY(const double &); + double y() const; + + void setPreviousX1(double x1); + void setPreviousY1(double y1); + + double x1(double curx) const; + double y1(double cury) const; + + virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const; + +private: + double m_x; + double m_y; + double m_previousX1; + double m_previousY1; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + X, Y + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +class SVGPathSegCurvetoQuadraticSmoothRelImpl : public SVGPathSegImpl +{ +public: + SVGPathSegCurvetoQuadraticSmoothRelImpl(); + virtual ~SVGPathSegCurvetoQuadraticSmoothRelImpl(); + + virtual unsigned short pathSegType() const { return PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL; } + virtual DOM::DOMString pathSegTypeAsLetter() const { return "t"; } + virtual QString toString() const { return QString("t %1 %2").arg(m_x).arg(m_y); } + + void setX(const double &); + double x() const; + + void setY(const double &); + double y() const; + + void setPreviousAbsX1(double x1); + void setPreviousAbsY1(double y1); + + double absX1(double curx) const; + double absY1(double cury) const; + + virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const; + +private: + double m_x; + double m_y; + double m_previousAbsX1; + double m_previousAbsY1; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + X, Y + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegImpl.cc b/ksvg/impl/SVGPathSegImpl.cc new file mode 100644 index 00000000..c1f2934d --- /dev/null +++ b/ksvg/impl/SVGPathSegImpl.cc @@ -0,0 +1,107 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGPathSegImpl.h" + +using namespace KSVG; + +#include "SVGPathSegImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_cacheimpl.h" + +SVGPathSegImpl::SVGPathSegImpl() +{ +} + +SVGPathSegImpl::~SVGPathSegImpl() +{ +} + +void SVGPathSegImpl::getDeltasAndSlopes(double, double, double *dx, double *dy, double *startSlope, double *endSlope) const +{ + *dx = 0; + *dy = 0; + *startSlope = 0; + *endSlope = 0; +} + +// Exma stuff + +/* +@namespace KSVG +@begin SVGPathSegImpl::s_hashTable 3 + pathSegType SVGPathSegImpl::PathSegType DontDelete|ReadOnly + pathSegTypeAsLetter SVGPathSegImpl::PathSegTypeAsLetter DontDelete|ReadOnly +@end +*/ + +Value SVGPathSegImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case PathSegType: + return Number(pathSegType()); + case PathSegTypeAsLetter: + return String(pathSegTypeAsLetter().string()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +/* +@namespace KSVG +@begin SVGPathSegImplConstructor::s_hashTable 23 + PATHSEG_UNKNOWN KSVG::PATHSEG_UNKNOWN DontDelete|ReadOnly + PATHSEG_CLOSEPATH KSVG::PATHSEG_CLOSEPATH DontDelete|ReadOnly + PATHSEG_MOVETO_ABS KSVG::PATHSEG_MOVETO_ABS DontDelete|ReadOnly + PATHSEG_MOVETO_REL KSVG::PATHSEG_MOVETO_REL DontDelete|ReadOnly + PATHSEG_LINETO_ABS KSVG::PATHSEG_LINETO_ABS DontDelete|ReadOnly + PATHSEG_LINETO_REL KSVG::PATHSEG_LINETO_REL DontDelete|ReadOnly + PATHSEG_CURVETO_CUBIC_ABS KSVG::PATHSEG_CURVETO_CUBIC_ABS DontDelete|ReadOnly + PATHSEG_CURVETO_CUBIC_REL KSVG::PATHSEG_CURVETO_CUBIC_REL DontDelete|ReadOnly + PATHSEG_CURVETO_QUADRATIC_ABS KSVG::PATHSEG_CURVETO_QUADRATIC_ABS DontDelete|ReadOnly + PATHSEG_CURVETO_QUADRATIC_REL KSVG::PATHSEG_CURVETO_QUADRATIC_REL DontDelete|ReadOnly + PATHSEG_ARC_ABS KSVG::PATHSEG_ARC_ABS DontDelete|ReadOnly + PATHSEG_ARC_REL KSVG::PATHSEG_ARC_REL DontDelete|ReadOnly + PATHSEG_LINETO_HORIZONTAL_ABS KSVG::PATHSEG_LINETO_HORIZONTAL_ABS DontDelete|ReadOnly + PATHSEG_LINETO_HORIZONTAL_REL KSVG::PATHSEG_LINETO_HORIZONTAL_REL DontDelete|ReadOnly + PATHSEG_LINETO_VERTICAL_ABS KSVG::PATHSEG_LINETO_VERTICAL_ABS DontDelete|ReadOnly + PATHSEG_LINETO_VERTICAL_REL KSVG::PATHSEG_LINETO_VERTICAL_REL DontDelete|ReadOnly + PATHSEG_CURVETO_CUBIC_SMOOTH_ABS KSVG::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS DontDelete|ReadOnly + PATHSEG_CURVETO_CUBIC_SMOOTH_REL KSVG::PATHSEG_CURVETO_CUBIC_SMOOTH_REL DontDelete|ReadOnly + PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS KSVG::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS DontDelete|ReadOnly + PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL KSVG::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL DontDelete|ReadOnly +@end +*/ + +Value SVGPathSegImplConstructor::getValueProperty(ExecState *, int token) const +{ + return Number(token); +} + +Value KSVG::getSVGPathSegImplConstructor(ExecState *exec) +{ + return cacheGlobalBridge(exec, "[[svgpathseg.constructor]]"); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegImpl.h b/ksvg/impl/SVGPathSegImpl.h new file mode 100644 index 00000000..64d8b5b0 --- /dev/null +++ b/ksvg/impl/SVGPathSegImpl.h @@ -0,0 +1,75 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegImpl_H +#define SVGPathSegImpl_H + +#include + +#include "ksvg_lookup.h" + +#include "SVGPathSeg.h" + +namespace KSVG +{ + +class SVGPathElementImpl; +class SVGPathSegImpl : public DOM::DomShared +{ +public: + SVGPathSegImpl(); + virtual ~SVGPathSegImpl(); + + virtual unsigned short pathSegType() const { return PATHSEG_UNKNOWN; } + virtual DOM::DOMString pathSegTypeAsLetter() const { return ""; } + virtual QString toString() const { return ""; } + + virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const; + +public: + KSVG_BASECLASS_GET + + enum + { + // Properties + PathSegType, PathSegTypeAsLetter + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + +}; + +class SVGPathSegImplConstructor : public KJS::ObjectImp +{ +public: + SVGPathSegImplConstructor(KJS::ExecState *) { } + KJS::Value getValueProperty(KJS::ExecState *, int token) const; + + // no put - all read-only + KSVG_GET +}; + +KJS::Value getSVGPathSegImplConstructor(KJS::ExecState *exec); + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegLinetoHorizontalImpl.cc b/ksvg/impl/SVGPathSegLinetoHorizontalImpl.cc new file mode 100644 index 00000000..e36e49de --- /dev/null +++ b/ksvg/impl/SVGPathSegLinetoHorizontalImpl.cc @@ -0,0 +1,167 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGPathSegLinetoHorizontalImpl.h" +#include "SVGAngleImpl.h" + +using namespace KSVG; + +#include "SVGPathSegLinetoHorizontalImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGPathSegLinetoHorizontalAbsImpl::SVGPathSegLinetoHorizontalAbsImpl() : SVGPathSegImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGPathSegLinetoHorizontalAbsImpl::~SVGPathSegLinetoHorizontalAbsImpl() +{ +} + +void SVGPathSegLinetoHorizontalAbsImpl::setX(const double &x) +{ + m_x = x; +} + +double SVGPathSegLinetoHorizontalAbsImpl::x() const +{ + return m_x; +} + +void SVGPathSegLinetoHorizontalAbsImpl::getDeltasAndSlopes(double curx, double cury, double *pdx, double *pdy, double *pstartSlope, double *pendSlope) const +{ + Q_UNUSED(cury); + double dx = x() - curx; + double dy = 0; + double startSlope = SVGAngleImpl::todeg(atan2(dy, dx)); + double endSlope = startSlope; + *pdx = dx; + *pdy = dy; + *pstartSlope = startSlope; + *pendSlope = endSlope; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegLinetoHorizontalAbsImpl::s_hashTable 2 + x SVGPathSegLinetoHorizontalAbsImpl::X DontDelete +@end +*/ + +Value SVGPathSegLinetoHorizontalAbsImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case X: + return Number(x()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathSegLinetoHorizontalAbsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case X: + m_x = value.toNumber(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + + + + + +SVGPathSegLinetoHorizontalRelImpl::SVGPathSegLinetoHorizontalRelImpl() : SVGPathSegImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGPathSegLinetoHorizontalRelImpl::~SVGPathSegLinetoHorizontalRelImpl() +{ +} + +void SVGPathSegLinetoHorizontalRelImpl::setX(const double &x) +{ + m_x = x; +} + +double SVGPathSegLinetoHorizontalRelImpl::x() const +{ + return m_x; +} + +void SVGPathSegLinetoHorizontalRelImpl::getDeltasAndSlopes(double curx, double cury, double *pdx, double *pdy, double *pstartSlope, double *pendSlope) const +{ + Q_UNUSED(curx); + Q_UNUSED(cury); + double dx = x(); + double dy = 0; + double startSlope = SVGAngleImpl::todeg(atan2(dy, dx)); + double endSlope = startSlope; + *pdx = dx; + *pdy = dy; + *pstartSlope = startSlope; + *pendSlope = endSlope; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegLinetoHorizontalRelImpl::s_hashTable 2 + x SVGPathSegLinetoHorizontalRelImpl::X DontDelete +@end +*/ + +Value SVGPathSegLinetoHorizontalRelImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case X: + return Number(x()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathSegLinetoHorizontalRelImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case X: + m_x = value.toNumber(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegLinetoHorizontalImpl.h b/ksvg/impl/SVGPathSegLinetoHorizontalImpl.h new file mode 100644 index 00000000..020d29d7 --- /dev/null +++ b/ksvg/impl/SVGPathSegLinetoHorizontalImpl.h @@ -0,0 +1,99 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegLinetoHorizontalImpl_H +#define SVGPathSegLinetoHorizontalImpl_H + +#include "ksvg_lookup.h" + +#include "SVGPathSegImpl.h" + +namespace KSVG +{ + +class SVGPathSegLinetoHorizontalAbsImpl : public SVGPathSegImpl +{ +public: + SVGPathSegLinetoHorizontalAbsImpl(); + virtual ~SVGPathSegLinetoHorizontalAbsImpl(); + + virtual unsigned short pathSegType() const { return PATHSEG_LINETO_HORIZONTAL_ABS; } + virtual DOM::DOMString pathSegTypeAsLetter() const { return "H"; } + virtual QString toString() const { return QString("H %1").arg(m_x); } + + void setX(const double &); + double x() const; + + virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const; + +private: + double m_x; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + X + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +class SVGPathSegLinetoHorizontalRelImpl : public SVGPathSegImpl +{ +public: + SVGPathSegLinetoHorizontalRelImpl(); + virtual ~SVGPathSegLinetoHorizontalRelImpl(); + + virtual unsigned short pathSegType() const { return PATHSEG_LINETO_HORIZONTAL_REL; } + virtual DOM::DOMString pathSegTypeAsLetter() const { return "h"; } + virtual QString toString() const { return QString("h %1").arg(m_x); } + + void setX(const double &); + double x() const; + + virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const; + +private: + double m_x; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + X + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegLinetoImpl.cc b/ksvg/impl/SVGPathSegLinetoImpl.cc new file mode 100644 index 00000000..04203352 --- /dev/null +++ b/ksvg/impl/SVGPathSegLinetoImpl.cc @@ -0,0 +1,196 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGPathSegLinetoImpl.h" +#include "SVGAngleImpl.h" + +using namespace KSVG; + +#include "SVGPathSegLinetoImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGPathSegLinetoAbsImpl::SVGPathSegLinetoAbsImpl() : SVGPathSegImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGPathSegLinetoAbsImpl::~SVGPathSegLinetoAbsImpl() +{ +} + +void SVGPathSegLinetoAbsImpl::setX(const double &x) +{ + m_x = x; +} + +double SVGPathSegLinetoAbsImpl::x() const +{ + return m_x; +} + +void SVGPathSegLinetoAbsImpl::setY(const double &y) +{ + m_y = y; +} + +double SVGPathSegLinetoAbsImpl::y() const +{ + return m_y; +} + +void SVGPathSegLinetoAbsImpl::getDeltasAndSlopes(double curx, double cury, double *pdx, double *pdy, double *pstartSlope, double *pendSlope) const +{ + double dx = x() - curx; + double dy = y() - cury; + double startSlope = SVGAngleImpl::todeg(atan2(dy, dx)); + double endSlope = startSlope; + *pdx = dx; + *pdy = dy; + *pstartSlope = startSlope; + *pendSlope = endSlope; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegLinetoAbsImpl::s_hashTable 3 + x SVGPathSegLinetoAbsImpl::X DontDelete + y SVGPathSegLinetoAbsImpl::Y DontDelete +@end +*/ + +Value SVGPathSegLinetoAbsImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case X: + return Number(x()); + case Y: + return Number(y()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathSegLinetoAbsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case X: + m_x = value.toNumber(exec); + break; + case Y: + m_y = value.toNumber(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + + + +SVGPathSegLinetoRelImpl::SVGPathSegLinetoRelImpl() : SVGPathSegImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGPathSegLinetoRelImpl::~SVGPathSegLinetoRelImpl() +{ +} + +void SVGPathSegLinetoRelImpl::setX(const double &x) +{ + m_x = x; +} + +double SVGPathSegLinetoRelImpl::x() const +{ + return m_x; +} + +void SVGPathSegLinetoRelImpl::setY(const double &y) +{ + m_y = y; +} + +double SVGPathSegLinetoRelImpl::y() const +{ + return m_y; +} + +void SVGPathSegLinetoRelImpl::getDeltasAndSlopes(double curx, double cury, double *pdx, double *pdy, double *pstartSlope, double *pendSlope) const +{ + Q_UNUSED(curx); + Q_UNUSED(cury); + double dx = x(); + double dy = y(); + double startSlope = SVGAngleImpl::todeg(atan2(dy, dx)); + double endSlope = startSlope; + *pdx = dx; + *pdy = dy; + *pstartSlope = startSlope; + *pendSlope = endSlope; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegLinetoRelImpl::s_hashTable 3 + x SVGPathSegLinetoRelImpl::X DontDelete + y SVGPathSegLinetoRelImpl::Y DontDelete +@end +*/ + +Value SVGPathSegLinetoRelImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case X: + return Number(x()); + case Y: + return Number(y()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathSegLinetoRelImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case X: + m_x = value.toNumber(exec); + break; + case Y: + m_y = value.toNumber(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegLinetoImpl.h b/ksvg/impl/SVGPathSegLinetoImpl.h new file mode 100644 index 00000000..3e315022 --- /dev/null +++ b/ksvg/impl/SVGPathSegLinetoImpl.h @@ -0,0 +1,107 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegLinetoImpl_H +#define SVGPathSegLinetoImpl_H + +#include "ksvg_lookup.h" + +#include "SVGPathSegImpl.h" + +namespace KSVG +{ + +class SVGPathSegLinetoAbsImpl : public SVGPathSegImpl +{ +public: + SVGPathSegLinetoAbsImpl(); + virtual ~SVGPathSegLinetoAbsImpl(); + + virtual unsigned short pathSegType() const { return PATHSEG_LINETO_ABS; } + virtual DOM::DOMString pathSegTypeAsLetter() const { return "L"; } + virtual QString toString() const { return QString("L %1 %2").arg(m_x).arg(m_y); } + + void setX(const double &); + double x() const; + + void setY(const double &); + double y() const; + + virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const; + +private: + double m_x; + double m_y; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + X, Y + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +class SVGPathSegLinetoRelImpl : public SVGPathSegImpl +{ +public: + SVGPathSegLinetoRelImpl(); + virtual ~SVGPathSegLinetoRelImpl(); + + virtual unsigned short pathSegType() const { return PATHSEG_LINETO_REL; } + virtual DOM::DOMString pathSegTypeAsLetter() const { return "l"; } + virtual QString toString() const { return QString("l %1 %2").arg(m_x).arg(m_y); } + + void setX(const double &); + double x() const; + + void setY(const double &); + double y() const; + + virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const; + +private: + double m_x; + double m_y; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + X, Y + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegLinetoVerticalImpl.cc b/ksvg/impl/SVGPathSegLinetoVerticalImpl.cc new file mode 100644 index 00000000..0eca1280 --- /dev/null +++ b/ksvg/impl/SVGPathSegLinetoVerticalImpl.cc @@ -0,0 +1,165 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGPathSegLinetoVerticalImpl.h" +#include "SVGAngleImpl.h" + +using namespace KSVG; + +#include "SVGPathSegLinetoVerticalImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGPathSegLinetoVerticalAbsImpl::SVGPathSegLinetoVerticalAbsImpl() : SVGPathSegImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGPathSegLinetoVerticalAbsImpl::~SVGPathSegLinetoVerticalAbsImpl() +{ +} + +void SVGPathSegLinetoVerticalAbsImpl::setY(const double &y) +{ + m_y = y; +} + +double SVGPathSegLinetoVerticalAbsImpl::y() const +{ + return m_y; +} + +void SVGPathSegLinetoVerticalAbsImpl::getDeltasAndSlopes(double curx, double cury, double *pdx, double *pdy, double *pstartSlope, double *pendSlope) const +{ + Q_UNUSED(curx); + double dx = 0; + double dy = y() - cury; + double startSlope = SVGAngleImpl::todeg(atan2(dy, dx)); + double endSlope = startSlope; + *pdx = dx; + *pdy = dy; + *pstartSlope = startSlope; + *pendSlope = endSlope; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegLinetoVerticalAbsImpl::s_hashTable 2 + y SVGPathSegLinetoVerticalAbsImpl::Y DontDelete +@end +*/ + +Value SVGPathSegLinetoVerticalAbsImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case Y: + return Number(y()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathSegLinetoVerticalAbsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case Y: + m_y = value.toNumber(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + + + +SVGPathSegLinetoVerticalRelImpl::SVGPathSegLinetoVerticalRelImpl() : SVGPathSegImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGPathSegLinetoVerticalRelImpl::~SVGPathSegLinetoVerticalRelImpl() +{ +} + +void SVGPathSegLinetoVerticalRelImpl::setY(const double &y) +{ + m_y = y; +} + +double SVGPathSegLinetoVerticalRelImpl::y() const +{ + return m_y; +} + +void SVGPathSegLinetoVerticalRelImpl::getDeltasAndSlopes(double curx, double cury, double *pdx, double *pdy, double *pstartSlope, double *pendSlope) const +{ + Q_UNUSED(curx); + Q_UNUSED(cury); + double dx = 0; + double dy = y(); + double startSlope = SVGAngleImpl::todeg(atan2(dy, dx)); + double endSlope = startSlope; + *pdx = dx; + *pdy = dy; + *pstartSlope = startSlope; + *pendSlope = endSlope; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegLinetoVerticalRelImpl::s_hashTable 2 + y SVGPathSegLinetoVerticalRelImpl::Y DontDelete +@end +*/ + +Value SVGPathSegLinetoVerticalRelImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case Y: + return Number(y()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathSegLinetoVerticalRelImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case Y: + m_y = value.toNumber(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegLinetoVerticalImpl.h b/ksvg/impl/SVGPathSegLinetoVerticalImpl.h new file mode 100644 index 00000000..c50906d9 --- /dev/null +++ b/ksvg/impl/SVGPathSegLinetoVerticalImpl.h @@ -0,0 +1,99 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegLinetoVerticalImpl_H +#define SVGPathSegLinetoVerticalImpl_H + +#include "ksvg_lookup.h" + +#include "SVGPathSegImpl.h" + +namespace KSVG +{ + +class SVGPathSegLinetoVerticalAbsImpl : public SVGPathSegImpl +{ +public: + SVGPathSegLinetoVerticalAbsImpl(); + virtual~SVGPathSegLinetoVerticalAbsImpl(); + + virtual unsigned short pathSegType() const { return PATHSEG_LINETO_VERTICAL_ABS; } + virtual DOM::DOMString pathSegTypeAsLetter() const { return "V"; } + virtual QString toString() const { return QString("V %1").arg(m_y); } + + void setY(const double &); + double y() const; + + virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const; + +private: + double m_y; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + Y + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +class SVGPathSegLinetoVerticalRelImpl : public SVGPathSegImpl +{ +public: + SVGPathSegLinetoVerticalRelImpl(); + virtual ~SVGPathSegLinetoVerticalRelImpl(); + + virtual unsigned short pathSegType() const { return PATHSEG_LINETO_VERTICAL_REL; } + virtual DOM::DOMString pathSegTypeAsLetter() const { return "v"; } + virtual QString toString() const { return QString("v %1").arg(m_y); } + + void setY(const double &); + double y() const; + + virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const; + +private: + double m_y; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + Y + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegListImpl.cc b/ksvg/impl/SVGPathSegListImpl.cc new file mode 100644 index 00000000..ee316938 --- /dev/null +++ b/ksvg/impl/SVGPathSegListImpl.cc @@ -0,0 +1,64 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGPathSegListImpl.h" + +using namespace KSVG; + +#include "SVGPathSegListImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegListImpl::s_hashTable 2 + numberOfItems SVGListDefs::NumberOfItems DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGPathSegListImplProto::s_hashTable 11 + getItem SVGListDefs::GetItem DontDelete|Function 1 + removeItem SVGListDefs::RemoveItem DontDelete|Function 1 + appendItem SVGListDefs::AppendItem DontDelete|Function 1 + initialize SVGListDefs::Initialize DontDelete|Function 1 + insertItemBefore SVGListDefs::InsertItemBefore DontDelete|Function 2 + replaceItem SVGListDefs::ReplaceItem DontDelete|Function 2 + clear SVGListDefs::Clear DontDelete|Function 0 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGPathSegList", SVGPathSegListImplProto, SVGPathSegListImplProtoFunc) + +Value SVGPathSegListImpl::getValueProperty(ExecState *exec, int token) const +{ + return SVGList::getValueProperty(exec, token); +} + +Value SVGPathSegListImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGPathSegListImpl) + + return obj->call(exec, static_cast *>(obj), args, id); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegListImpl.h b/ksvg/impl/SVGPathSegListImpl.h new file mode 100644 index 00000000..ef9c8c6e --- /dev/null +++ b/ksvg/impl/SVGPathSegListImpl.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegListImpl_H +#define SVGPathSegListImpl_H + +#include "SVGList.h" + +#include "SVGPathSegImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGPathSegListImpl : public SVGList +{ +public: + KSVG_GET + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +} + +KSVG_DEFINE_PROTOTYPE(SVGPathSegListImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGPathSegListImplProtoFunc, SVGPathSegListImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegMovetoImpl.cc b/ksvg/impl/SVGPathSegMovetoImpl.cc new file mode 100644 index 00000000..2eb64b41 --- /dev/null +++ b/ksvg/impl/SVGPathSegMovetoImpl.cc @@ -0,0 +1,196 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGPathSegMovetoImpl.h" +#include "SVGAngleImpl.h" + +using namespace KSVG; + +#include "SVGPathSegMovetoImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGPathSegMovetoAbsImpl::SVGPathSegMovetoAbsImpl() : SVGPathSegImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGPathSegMovetoAbsImpl::~SVGPathSegMovetoAbsImpl() +{ +} + +void SVGPathSegMovetoAbsImpl::setX(const double &x) +{ + m_x = x; +} + +double SVGPathSegMovetoAbsImpl::x() const +{ + return m_x; +} + +void SVGPathSegMovetoAbsImpl::setY(const double &y) +{ + m_y = y; +} + +double SVGPathSegMovetoAbsImpl::y() const +{ + return m_y; +} + +void SVGPathSegMovetoAbsImpl::getDeltasAndSlopes(double curx, double cury, double *pdx, double *pdy, double *pstartSlope, double *pendSlope) const +{ + double dx = x() - curx; + double dy = y() - cury; + double startSlope = 0; + double endSlope = 0; + *pdx = dx; + *pdy = dy; + *pstartSlope = startSlope; + *pendSlope = endSlope; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegMovetoAbsImpl::s_hashTable 3 + x SVGPathSegMovetoAbsImpl::X DontDelete + y SVGPathSegMovetoAbsImpl::Y DontDelete +@end +*/ + +Value SVGPathSegMovetoAbsImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case X: + return Number(x()); + case Y: + return Number(y()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathSegMovetoAbsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case X: + m_x = value.toNumber(exec); + break; + case Y: + m_y = value.toNumber(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + + + +SVGPathSegMovetoRelImpl::SVGPathSegMovetoRelImpl() : SVGPathSegImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGPathSegMovetoRelImpl::~SVGPathSegMovetoRelImpl() +{ +} + +void SVGPathSegMovetoRelImpl::setX(const double &x) +{ + m_x = x; +} + +double SVGPathSegMovetoRelImpl::x() const +{ + return m_x; +} + +void SVGPathSegMovetoRelImpl::setY(const double &y) +{ + m_y = y; +} + +double SVGPathSegMovetoRelImpl::y() const +{ + return m_y; +} + +void SVGPathSegMovetoRelImpl::getDeltasAndSlopes(double curx, double cury, double *pdx, double *pdy, double *pstartSlope, double *pendSlope) const +{ + Q_UNUSED(curx); + Q_UNUSED(cury); + double dx = x(); + double dy = y(); + double startSlope = 0; + double endSlope = 0; + *pdx = dx; + *pdy = dy; + *pstartSlope = startSlope; + *pendSlope = endSlope; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegMovetoRelImpl::s_hashTable 3 + x SVGPathSegMovetoRelImpl::X DontDelete + y SVGPathSegMovetoRelImpl::Y DontDelete +@end +*/ + +Value SVGPathSegMovetoRelImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case X: + return Number(x()); + case Y: + return Number(y()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathSegMovetoRelImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case X: + m_x = value.toNumber(exec); + break; + case Y: + m_y = value.toNumber(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPathSegMovetoImpl.h b/ksvg/impl/SVGPathSegMovetoImpl.h new file mode 100644 index 00000000..dfbad355 --- /dev/null +++ b/ksvg/impl/SVGPathSegMovetoImpl.h @@ -0,0 +1,107 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPathSegMovetoImpl_H +#define SVGPathSegMovetoImpl_H + +#include "ksvg_lookup.h" + +#include "SVGPathSegImpl.h" + +namespace KSVG +{ + +class SVGPathSegMovetoAbsImpl : public SVGPathSegImpl +{ +public: + SVGPathSegMovetoAbsImpl(); + virtual ~SVGPathSegMovetoAbsImpl(); + + virtual unsigned short pathSegType() const { return PATHSEG_MOVETO_ABS; } + virtual DOM::DOMString pathSegTypeAsLetter() const { return "M"; } + virtual QString toString() const { return QString("M %1 %2").arg(m_x).arg(m_y); } + + void setX(const double &); + double x() const; + + void setY(const double &); + double y() const; + + virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const; + +private: + double m_x; + double m_y; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + X, Y + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +class SVGPathSegMovetoRelImpl : public SVGPathSegImpl +{ +public: + SVGPathSegMovetoRelImpl(); + virtual ~SVGPathSegMovetoRelImpl(); + + virtual unsigned short pathSegType() const { return PATHSEG_MOVETO_REL; } + virtual DOM::DOMString pathSegTypeAsLetter() const { return "m"; } + virtual QString toString() const { return QString("m %1 %2").arg(m_x).arg(m_y); } + + void setX(const double &); + double x() const; + + void setY(const double &); + double y() const; + + virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const; + +private: + double m_x; + double m_y; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + X, Y + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPatternElementImpl.cc b/ksvg/impl/SVGPatternElementImpl.cc new file mode 100644 index 00000000..0b591487 --- /dev/null +++ b/ksvg/impl/SVGPatternElementImpl.cc @@ -0,0 +1,509 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include + +#include "SVGPatternElement.h" +#include "SVGPatternElementImpl.h" + +#include "CanvasFactory.h" +#include "KSVGCanvas.h" +#include "CanvasItems.h" +#include "SVGHelperImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGTransformListImpl.h" +#include "SVGAnimatedTransformListImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGAnimatedEnumerationImpl.h" +#include "SVGAnimatedStringImpl.h" +#include "SVGUnitConverter.h" +#include "SVGShapeImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGMatrixImpl.h" +#include "SVGRectImpl.h" + +using namespace KSVG; + +#include "SVGPatternElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +QValueList SVGPatternElementImpl::m_patternElements; + +SVGPatternElementImpl::SVGPatternElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGURIReferenceImpl(), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGFitToViewBoxImpl(), SVGPaintServerImpl() +{ + KSVG_EMPTY_FLAGS + + m_patternUnits = new SVGAnimatedEnumerationImpl(); + m_patternUnits->ref(); + + m_patternContentUnits = new SVGAnimatedEnumerationImpl(); + m_patternContentUnits->ref(); + + m_patternTransform = new SVGAnimatedTransformListImpl(); + m_patternTransform->ref(); + + m_x = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_x->ref(); + + m_y = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_y->ref(); + + m_width = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_width->ref(); + + m_height = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_height->ref(); + + m_converter = new SVGUnitConverter(); + m_converter->add(m_x); + m_converter->add(m_y); + m_converter->add(m_width); + m_converter->add(m_height); + + m_patternElements.append(this); + + m_canvas = 0; + m_location = this; + + m_tileCache.setMaxTotalCost(1024 * 1024); +} + +SVGPatternElementImpl::~SVGPatternElementImpl() +{ + if(m_patternUnits) + m_patternUnits->deref(); + if(m_patternContentUnits) + m_patternContentUnits->deref(); + if(m_patternTransform) + m_patternTransform->deref(); + if(m_x) + m_x->deref(); + if(m_y) + m_y->deref(); + if(m_width) + m_width->deref(); + if(m_height) + m_height->deref(); + delete m_converter; + m_patternElements.remove(this); +} + +SVGAnimatedEnumerationImpl *SVGPatternElementImpl::patternUnits() const +{ + return m_patternUnits; +} + +SVGAnimatedEnumerationImpl *SVGPatternElementImpl::patternContentUnits() const +{ + return m_patternContentUnits; +} + +SVGAnimatedTransformListImpl *SVGPatternElementImpl::patternTransform() const +{ + return m_patternTransform; +} + +SVGAnimatedLengthImpl *SVGPatternElementImpl::x() const +{ + return m_x; +} + +SVGAnimatedLengthImpl *SVGPatternElementImpl::y() const +{ + return m_y; +} + +SVGAnimatedLengthImpl *SVGPatternElementImpl::width() const +{ + return m_width; +} + +SVGAnimatedLengthImpl *SVGPatternElementImpl::height() const +{ + return m_height; +} + +void SVGPatternElementImpl::createItem(KSVGCanvas *c) +{ + if(!c) + c = ownerDoc()->canvas(); + + if(!m_paintServer) + m_paintServer = c->createPaintServer(this); +} + +void SVGPatternElementImpl::removeItem(KSVGCanvas *) +{ + delete m_paintServer; + m_paintServer = 0; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPatternElementImpl::s_hashTable 11 + x SVGPatternElementImpl::X DontDelete|ReadOnly + y SVGPatternElementImpl::Y DontDelete|ReadOnly + width SVGPatternElementImpl::Width DontDelete|ReadOnly + height SVGPatternElementImpl::Height DontDelete|ReadOnly + patternUnits SVGPatternElementImpl::PatternUnits DontDelete|ReadOnly + patternContentUnits SVGPatternElementImpl::PatternContentUnits DontDelete|ReadOnly + patternTransform SVGPatternElementImpl::PatternTransform DontDelete|ReadOnly +@end +*/ + +Value SVGPatternElementImpl::getValueProperty(ExecState *exec, int token) const +{ + KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case X: + if(!attributeMode) + return m_x->cache(exec); + else + return Number(m_x->baseVal()->value()); + case Y: + if(!attributeMode) + return m_y->cache(exec); + else + return Number(m_y->baseVal()->value()); + case Width: + if(!attributeMode) + return m_width->cache(exec); + else + return Number(m_width->baseVal()->value()); + case Height: + if(!attributeMode) + return m_height->cache(exec); + else + return Number(m_height->baseVal()->value()); + case PatternUnits: + if(!attributeMode) + return m_patternUnits->cache(exec); + else + return Number(m_patternUnits->baseVal()); + case PatternContentUnits: + if(!attributeMode) + return m_patternContentUnits->cache(exec); + else + return Number(m_patternContentUnits->baseVal()); + case PatternTransform: + //if(!attributeMode) + return m_patternTransform->cache(exec); + //else + // return Number(m_patternTransform->baseVal()->value()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPatternElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case X: + converter()->modify(x(), value.toString(exec).qstring()); + break; + case Y: + converter()->modify(y(), value.toString(exec).qstring()); + break; + case Width: + converter()->modify(width(), value.toString(exec).qstring()); + if(width()->baseVal()->value() < 0) // A negative value is an error + gotError(i18n("Negative value for attribute width of element is illegal")); + break; + case Height: + converter()->modify(height(), value.toString(exec).qstring()); + if(height()->baseVal()->value() < 0) // A negative value is an error + gotError(i18n("Negative value for attribute height of element is illegal")); + break; + case PatternUnits: + if(value.toString(exec).qstring() == "userSpaceOnUse") + m_patternUnits->setBaseVal(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE); + else + m_patternUnits->setBaseVal(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX); + break; + case PatternContentUnits: + if(value.toString(exec).qstring() == "userSpaceOnUse") + m_patternContentUnits->setBaseVal(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE); + else + m_patternContentUnits->setBaseVal(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX); + break; + case PatternTransform: + m_patternTransform->baseVal()->clear(); + SVGHelperImpl::parseTransformAttribute(m_patternTransform->baseVal(), value.toString(exec).qstring()); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +void SVGPatternElementImpl::setAttributes() +{ + SVGElementImpl::setAttributes(); + + // Spec: if attribute not specified, use a value of 0 + if(KSVG_TOKEN_NOT_PARSED(X)) + KSVG_SET_ALT_ATTRIBUTE(X, "0") + + // Spec: if attribute not specified, use a value of 0 + if(KSVG_TOKEN_NOT_PARSED(Y)) + KSVG_SET_ALT_ATTRIBUTE(Y, "0") + + // Spec: if attribute not specified, use objectBoundingBox + if(KSVG_TOKEN_NOT_PARSED(PatternUnits)) + KSVG_SET_ALT_ATTRIBUTE(PatternUnits, "objectBoundingBox") + + // Spec: If attribute not specified, use userSpaceOnUse + if(KSVG_TOKEN_NOT_PARSED(PatternContentUnits)) + KSVG_SET_ALT_ATTRIBUTE(PatternContentUnits, "userSpaceOnUse") + + // Spec: default value + if(KSVG_TOKEN_NOT_PARSED(PreserveAspectRatio)) + KSVG_SET_ALT_ATTRIBUTE(PreserveAspectRatio, "xMidYMid meet") +} + +void SVGPatternElementImpl::flushCachedTiles() +{ + QValueList::iterator it; + + for(it = m_patternElements.begin(); it != m_patternElements.end(); it++) + { + SVGPatternElementImpl *pattern = *it; + + if(pattern->paintServer()) + pattern->paintServer()->resetFinalized(); + } +} + +QImage SVGPatternElementImpl::createTile(SVGShapeImpl *referencingElement, int imageWidth, int imageHeight) +{ + converter()->finalize(referencingElement, ownerSVGElement(), patternUnits()->baseVal()); + + QImage image(imageWidth, imageHeight, 32); + image.setAlphaBuffer(true); + + if(m_canvas == 0) + { + m_canvas = CanvasFactory::self()->loadCanvas(image.width(), image.height()); + m_canvas->setBackgroundColor(qRgba(0, 0, 0, 0)); + } + + m_canvas->setup(image.bits(), image.width(), image.height()); + + SVGMatrixImpl *baseMatrix = SVGSVGElementImpl::createSVGMatrix(); + + // Set the scale to map the tile onto the integral sized image + double xScale = static_cast(imageWidth) / width()->baseVal()->value(); + double yScale = static_cast(imageHeight) / height()->baseVal()->value(); + + baseMatrix->scaleNonUniform(xScale, yScale); + + if(hasAttribute("viewBox")) + { + SVGMatrixImpl *viewboxMatrix = viewBoxToViewTransform(width()->baseVal()->value(), height()->baseVal()->value()); + + baseMatrix->multiply(viewboxMatrix); + viewboxMatrix->deref(); + } + else + { + if(patternContentUnits()->baseVal() == SVGPatternElement::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) + { + // Get local coordinate bounding box + SVGRectImpl *rect = referencingElement->getBBox(); + + baseMatrix->translate(rect->qrect().x(), rect->qrect().y()); + baseMatrix->scaleNonUniform(rect->qrect().width(), rect->qrect().height()); + rect->deref(); + } + } + + for(DOM::Node node = m_location->firstChild(); !node.isNull(); node = node.nextSibling()) + { + SVGElementImpl *element = ownerDoc()->getElementFromHandle(node.handle()); + SVGShapeImpl *shape = dynamic_cast(element); + SVGTestsImpl *tests = dynamic_cast(element); + SVGStylableImpl *style = dynamic_cast(element); + + bool ok = tests ? tests->ok() : true; + if(element && shape && style && ok && style->getVisible() && style->getDisplay()) + { + SVGLocatableImpl *locatable = dynamic_cast(element); + if(locatable) + locatable->updateCachedScreenCTM(baseMatrix); + + element->createItem(m_canvas); + if(shape->item()) + { + shape->item()->setReferenced(true); + m_canvas->invalidate(shape->item(), true); + } + } + } + + baseMatrix->deref(); + + m_canvas->update(float(1)); + + if(getOverflow()) + { + QPtrList items = m_canvas->allItems(); + QRect allItemsBBox; + + QPtrListIterator it(items); + CanvasItem *item; + + while((item = *it) != 0) + { + QRect bbox = item->bbox(); + allItemsBBox |= bbox; + ++it; + } + + if(allItemsBBox.left() < 0 || allItemsBBox.right() >= imageWidth || allItemsBBox.top() < 0 || allItemsBBox.bottom() >= imageHeight) + { + // Get the range in whole-tile units that covers the bounding box, where (0, 0) is the + // usual tile position. + int tileLeft = (allItemsBBox.left() - (imageWidth - 1)) / imageWidth; + int tileRight = allItemsBBox.right() / imageWidth; + int tileTop = (allItemsBBox.top() - (imageHeight - 1)) / imageHeight; + int tileBottom = allItemsBBox.bottom() / imageHeight; + + for(int tileX = tileLeft; tileX <= tileRight; tileX++) + { + for(int tileY = tileTop; tileY <= tileBottom; tileY++) + { + if(tileX != 0 || tileY !=0) + { + QPoint panPoint(-(tileX * imageWidth), -(tileY * imageHeight)); + m_canvas->update(panPoint, false); + } + } + } + } + } + + for(DOM::Node node = m_location->firstChild(); !node.isNull(); node = node.nextSibling()) + { + SVGElementImpl *element = ownerDoc()->getElementFromHandle(node.handle()); + + if(element) + element->removeItem(m_canvas); + } + + return image; +} + +void SVGPatternElementImpl::reference(const QString &href) +{ + // Copy attributes + SVGElementImpl *src = ownerSVGElement()->getElementById(href); + + if(src) + { + SVGHelperImpl::copyAttributes(src, this); + + // Spec: Change location to referenced element so we + // can take the children elements to render from there + if(m_location == this) + m_location = src; + } +} + +void SVGPatternElementImpl::finalizePaintServer() +{ + // Clear out any cached tiles since we may be being refinalised after an image + // inside a pattern has finished loading. + m_tileCache.clear(); + + QString _href = SVGURIReferenceImpl::getTarget(href()->baseVal().string()); + if(!_href.isEmpty()) + reference(_href); +} + +SVGPatternElementImpl::Tile SVGPatternElementImpl::createTile(SVGShapeImpl *referencingElement) +{ + converter()->finalize(referencingElement, ownerSVGElement(), patternUnits()->baseVal()); + + SVGTransformableImpl *transformable = dynamic_cast(referencingElement); + SVGMatrixImpl *matrix = 0; + if(transformable) + matrix = transformable->getScreenCTM(); + else + matrix = SVGSVGElementImpl::createSVGMatrix(); + + matrix->translate(x()->baseVal()->value(), y()->baseVal()->value()); + + SVGMatrixImpl *patTransform = patternTransform()->baseVal()->concatenate(); + if(patTransform) + { + matrix->multiply(patTransform); + patTransform->deref(); + } + + double xScale, yScale; + matrix->removeScale(&xScale, &yScale); + + double tileWidth = width()->baseVal()->value() * xScale; + double tileHeight = height()->baseVal()->value() * yScale; + + int imageWidth = static_cast(tileWidth + 0.5); + int imageHeight = static_cast(tileHeight + 0.5); + + Tile tile; + + if(imageWidth > 0 && imageHeight > 0) + { + QSize size(imageWidth, imageHeight); + QImage image; + + if(!m_tileCache.find(size, image)) + { + image = createTile(referencingElement, imageWidth, imageHeight); + m_tileCache.insert(size, image, image.width() * image.height() * 4); + } + + // Map integral tile dimensions onto its true size + double adjustXScale = tileWidth / imageWidth; + double adjustYScale = tileHeight / imageHeight; + + matrix->scaleNonUniform(adjustXScale, adjustYScale); + QWMatrix screenToTile = matrix->qmatrix().invert(); + + tile = Tile(image, screenToTile); + } + + matrix->deref(); + + return tile; +} + diff --git a/ksvg/impl/SVGPatternElementImpl.h b/ksvg/impl/SVGPatternElementImpl.h new file mode 100644 index 00000000..612fcfae --- /dev/null +++ b/ksvg/impl/SVGPatternElementImpl.h @@ -0,0 +1,136 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPatternElementImpl_H +#define SVGPatternElementImpl_H + +#include +#include + +#include "SVGTestsImpl.h" +#include "SVGElementImpl.h" +#include "SVGStylableImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGURIReferenceImpl.h" +#include "SVGFitToViewBoxImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" +#include "SVGPaintServerImpl.h" +#include "LRUCache.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGUnitConverter; +class SVGAnimatedLengthImpl; +class SVGAnimatedEnumerationImpl; +class SVGAnimatedTransformListImpl; +class SVGShapeImpl; +class SVGPatternElementImpl : public SVGElementImpl, + public SVGURIReferenceImpl, + public SVGTestsImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGFitToViewBoxImpl, + public SVGPaintServerImpl +{ +public: + SVGPatternElementImpl(DOM::ElementImpl *); + virtual ~SVGPatternElementImpl(); + + SVGAnimatedEnumerationImpl *patternUnits() const; + SVGAnimatedEnumerationImpl *patternContentUnits() const; + SVGAnimatedTransformListImpl *patternTransform() const; + SVGAnimatedLengthImpl *x() const; + SVGAnimatedLengthImpl *y() const; + SVGAnimatedLengthImpl *width() const; + SVGAnimatedLengthImpl *height() const; + + virtual void setAttributes(); + + virtual void createItem(KSVGCanvas *c = 0); + virtual void removeItem(KSVGCanvas *c); + + SVGUnitConverter *converter() const { return m_converter; } + + void reference(const QString &href); + void finalizePaintServer(); + + class Tile + { + public: + Tile() {} + Tile(const QImage& image, const QWMatrix& screenToTile) : m_image(image), m_screenToTile(screenToTile) {} + + QImage image() const { return m_image; } + const QWMatrix& screenToTile() const { return m_screenToTile; } + + private: + QImage m_image; + QWMatrix m_screenToTile; + }; + + Tile createTile(SVGShapeImpl *referencingElement); + + static void flushCachedTiles(); + +private: + QImage createTile(SVGShapeImpl *referencingElement, int imageWidth, int imageHeight); + + SVGAnimatedEnumerationImpl *m_patternUnits; + SVGAnimatedEnumerationImpl *m_patternContentUnits; + SVGAnimatedTransformListImpl *m_patternTransform; + SVGAnimatedLengthImpl *m_x; + SVGAnimatedLengthImpl *m_y; + SVGAnimatedLengthImpl *m_width; + SVGAnimatedLengthImpl *m_height; + + SVGUnitConverter *m_converter; + + KSVGCanvas *m_canvas; + SVGElementImpl *m_location; // the referenced element + MinOneLRUCache m_tileCache; + + static QValueList m_patternElements; + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + X, Y, Width, Height, PatternUnits, PatternContentUnits, PatternTransform + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGPatternElementImpl, "pattern") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPointImpl.cc b/ksvg/impl/SVGPointImpl.cc new file mode 100644 index 00000000..c3697f58 --- /dev/null +++ b/ksvg/impl/SVGPointImpl.cc @@ -0,0 +1,108 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGPointImpl.h" +#include "SVGSVGElementImpl.h" + +using namespace KSVG; + +#include "SVGPointImpl.lut.h" +#include "ksvg_bridge.h" + +SVGPointImpl::SVGPointImpl() : DOM::DomShared() +{ + KSVG_EMPTY_FLAGS + + m_x = 0; + m_y = 0; +} + +SVGPointImpl::~SVGPointImpl() +{ +} + +void SVGPointImpl::setX(float x) +{ + m_x = x; +} + +float SVGPointImpl::x() const +{ + return m_x; +} + +void SVGPointImpl::setY(float y) +{ + m_y = y; +} + +float SVGPointImpl::y() const +{ + return m_y; +} + +SVGPointImpl *SVGPointImpl::matrixTransform(const SVGMatrixImpl &) +{ + SVGPointImpl *ret = SVGSVGElementImpl::createSVGPoint(); + return ret; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPointImpl::s_hashTable 3 + x SVGPointImpl::X DontDelete + y SVGPointImpl::Y DontDelete +@end +*/ + +Value SVGPointImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case X: + return Number(x()); + case Y: + return Number(y()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPointImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case X: + m_x = value.toNumber(exec); + break; + case Y: + m_y = value.toNumber(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPointImpl.h b/ksvg/impl/SVGPointImpl.h new file mode 100644 index 00000000..55132cf3 --- /dev/null +++ b/ksvg/impl/SVGPointImpl.h @@ -0,0 +1,66 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPointImpl_H +#define SVGPointImpl_H + +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGMatrixImpl; +class SVGPointImpl : public DOM::DomShared +{ +public: + SVGPointImpl(); + virtual ~SVGPointImpl(); + + void setX(float x); + float x() const; + + void setY(float y); + float y() const; + + SVGPointImpl *matrixTransform(const SVGMatrixImpl &matrix); + +private: + float m_x; + float m_y; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + X, Y + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif diff --git a/ksvg/impl/SVGPointListImpl.cc b/ksvg/impl/SVGPointListImpl.cc new file mode 100644 index 00000000..34574b60 --- /dev/null +++ b/ksvg/impl/SVGPointListImpl.cc @@ -0,0 +1,64 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGPointListImpl.h" + +using namespace KSVG; + +#include "SVGPointListImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPointListImpl::s_hashTable 2 + numberOfItems SVGListDefs::NumberOfItems DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGPointListImplProto::s_hashTable 11 + getItem SVGListDefs::GetItem DontDelete|Function 1 + removeItem SVGListDefs::RemoveItem DontDelete|Function 1 + appendItem SVGListDefs::AppendItem DontDelete|Function 1 + initialize SVGListDefs::Initialize DontDelete|Function 1 + insertItemBefore SVGListDefs::InsertItemBefore DontDelete|Function 2 + replaceItem SVGListDefs::ReplaceItem DontDelete|Function 2 + clear SVGListDefs::Clear DontDelete|Function 0 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGPointList", SVGPointListImplProto, SVGPointListImplProtoFunc) + +Value SVGPointListImpl::getValueProperty(ExecState *exec, int token) const +{ + return SVGList::getValueProperty(exec, token); +} + +Value SVGPointListImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGPointListImpl) + + return obj->call(exec, static_cast *>(obj), args, id); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPointListImpl.h b/ksvg/impl/SVGPointListImpl.h new file mode 100644 index 00000000..61d93731 --- /dev/null +++ b/ksvg/impl/SVGPointListImpl.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPointListImpl_H +#define SVGPointListImpl_H + +#include "SVGList.h" + +#include "SVGPointImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGPointListImpl : public SVGList +{ +public: + KSVG_GET + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +} + +KSVG_DEFINE_PROTOTYPE(SVGPointListImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGPointListImplProtoFunc, SVGPointListImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPolyElementImpl.cc b/ksvg/impl/SVGPolyElementImpl.cc new file mode 100644 index 00000000..69ef57cd --- /dev/null +++ b/ksvg/impl/SVGPolyElementImpl.cc @@ -0,0 +1,141 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include + +#include + +#include "SVGRectImpl.h" +#include "SVGPointListImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGPolyElementImpl.h" +#include "SVGAngleImpl.h" + +using namespace KSVG; + +SVGPolyElementImpl::SVGPolyElementImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl(), SVGAnimatedPointsImpl() +{ +} + +SVGPolyElementImpl::~SVGPolyElementImpl() +{ +} + +SVGRectImpl *SVGPolyElementImpl::getBBox() +{ + SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect(); + + unsigned int nrPoints = points()->numberOfItems(); + float minx, miny, maxx, maxy, tempx, tempy; + minx = points()->getItem(0)->x(); + miny = points()->getItem(0)->y(); + maxx = points()->getItem(0)->x(); + maxy = points()->getItem(0)->y(); + + for(unsigned int i = 1; i < nrPoints; ++i) + { + tempx = points()->getItem(i)->x(); + tempy = points()->getItem(i)->y(); + + if(tempx < minx) + minx = tempx; + if(tempx > maxx) + maxx = tempx; + if(tempy < miny) + miny = tempy; + if(tempy > maxy) + maxy = tempy; + } + + ret->setX(minx); + ret->setY(miny); + ret->setWidth(maxx - minx); + ret->setHeight(maxy - miny); + return ret; +} + +bool SVGPolyElementImpl::findOutSlope(unsigned int point, double *outSlope) const +{ + unsigned int nextPoint; + + if(point == points()->numberOfItems() - 1) + { + if(m_isOpenPath) + return false; + else + nextPoint = 0; + } + else + nextPoint = point + 1; + + if(point == nextPoint) + return false; + + double x = points()->getItem(point)->x(); + double y = points()->getItem(point)->y(); + double nextX = points()->getItem(nextPoint)->x(); + double nextY = points()->getItem(nextPoint)->y(); + const double epsilon = DBL_EPSILON; + + if(fabs(x - nextX) < epsilon && fabs(y - nextY) < epsilon) + return findOutSlope(nextPoint, outSlope); + else + { + double slope = SVGAngleImpl::todeg(atan2(nextY - y, nextX - x)); + *outSlope = slope; + return true; + } +} + +bool SVGPolyElementImpl::findInSlope(unsigned int point, double *inSlope) const +{ + unsigned int prevPoint; + + if(point == 0) + { + if(m_isOpenPath) + return false; + else + prevPoint = points()->numberOfItems() - 1; + } + else + prevPoint = point - 1; + + if(point == prevPoint) + return false; + + double x = points()->getItem(point)->x(); + double y = points()->getItem(point)->y(); + double prevX = points()->getItem(prevPoint)->x(); + double prevY = points()->getItem(prevPoint)->y(); + const double epsilon = DBL_EPSILON; + + if(fabs(x - prevX) < epsilon && fabs(y - prevY) < epsilon) + return findInSlope(prevPoint, inSlope); + else + { + double slope = SVGAngleImpl::todeg(atan2(y - prevY, x - prevX)); + *inSlope = slope; + return true; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPolyElementImpl.h b/ksvg/impl/SVGPolyElementImpl.h new file mode 100644 index 00000000..ded41d0c --- /dev/null +++ b/ksvg/impl/SVGPolyElementImpl.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPolyElementImpl_H +#define SVGPolyElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGShapeImpl.h" +#include "SVGTestsImpl.h" +#include "SVGStylableImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGTransformableImpl.h" +#include "SVGAnimatedPointsImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +namespace KSVG +{ + +class SVGPointListImpl; +class SVGPolyElementImpl : public SVGShapeImpl, + public SVGTestsImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGTransformableImpl, + public SVGAnimatedPointsImpl +{ +public: + SVGPolyElementImpl(DOM::ElementImpl *); + virtual ~SVGPolyElementImpl(); + + virtual SVGRectImpl *getBBox(); + + virtual void drawMarkers() = 0; + +protected: + bool findOutSlope(unsigned int point, double *outSlope) const; + bool findInSlope(unsigned int point, double *inSlope) const; + + bool m_isOpenPath; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT + KSVG_NO_TAG_BRIDGE +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPolygonElementImpl.cc b/ksvg/impl/SVGPolygonElementImpl.cc new file mode 100644 index 00000000..bf38ff37 --- /dev/null +++ b/ksvg/impl/SVGPolygonElementImpl.cc @@ -0,0 +1,88 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPointListImpl.h" +#include "SVGPolygonElementImpl.h" +#include "SVGDocumentImpl.h" +#include "KSVGCanvas.h" +#include "SVGAngleImpl.h" + +using namespace KSVG; + +SVGPolygonElementImpl::SVGPolygonElementImpl(DOM::ElementImpl *impl) : SVGPolyElementImpl(impl) +{ + m_isOpenPath = false; +} + +void SVGPolygonElementImpl::createItem(KSVGCanvas *c) +{ + if(!c) + c = ownerDoc()->canvas(); + + if(!m_item) + { + m_item = c->createPolygon(this); + c->insert(m_item); + } +} + +void SVGPolygonElementImpl::drawMarkers() +{ + SVGPointListImpl *pts = points(); + unsigned int nrPoints = pts->numberOfItems(); + + if(nrPoints > 0 && hasMarkers()) + { + for(unsigned int i = 0; i < nrPoints; ++i) + { + double inSlope; + double outSlope; + bool haveInSlope = findInSlope(i, &inSlope); + bool haveOutSlope = findOutSlope(i, &outSlope); + + if(!haveInSlope && haveOutSlope) + inSlope = outSlope; + else if(haveInSlope && !haveOutSlope) + outSlope = inSlope; + else if(!haveInSlope && !haveOutSlope) + { + inSlope = 0; + outSlope = 0; + } + + double bisector = SVGAngleImpl::shortestArcBisector(inSlope, outSlope); + + if(i == 0) + { + if(hasStartMarker()) + doStartMarker(this, this, pts->getItem(i)->x(), pts->getItem(i)->y(), bisector); + if(hasEndMarker()) + doEndMarker(this, this, pts->getItem(i)->x(), pts->getItem(i)->y(), bisector); + } + else + { + if(hasMidMarker()) + doMidMarker(this, this, pts->getItem(i)->x(), pts->getItem(i)->y(), bisector); + } + } + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPolygonElementImpl.h b/ksvg/impl/SVGPolygonElementImpl.h new file mode 100644 index 00000000..1c7e8c3b --- /dev/null +++ b/ksvg/impl/SVGPolygonElementImpl.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPolygonElementImpl_H +#define SVGPolygonElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGPolyElementImpl.h" +#include "CanvasItems.h" + +namespace KSVG +{ + +class SVGPolygonElementImpl : public SVGPolyElementImpl, public MarkerHelper +{ +public: + SVGPolygonElementImpl(DOM::ElementImpl *); + virtual ~SVGPolygonElementImpl() { } + + virtual void createItem(KSVGCanvas *c = 0); + + virtual void drawMarkers(); + +public: + KSVG_BRIDGE + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +KSVG_REGISTER_ELEMENT(SVGPolygonElementImpl, "polygon") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPolylineElementImpl.cc b/ksvg/impl/SVGPolylineElementImpl.cc new file mode 100644 index 00000000..9c95a928 --- /dev/null +++ b/ksvg/impl/SVGPolylineElementImpl.cc @@ -0,0 +1,100 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGPointListImpl.h" +#include "SVGPolylineElementImpl.h" +#include "SVGDocumentImpl.h" +#include "KSVGCanvas.h" +#include "SVGAngleImpl.h" + +using namespace KSVG; + +SVGPolylineElementImpl::SVGPolylineElementImpl(DOM::ElementImpl *impl) : SVGPolyElementImpl(impl) +{ + m_isOpenPath = true; +} + +void SVGPolylineElementImpl::createItem(KSVGCanvas *c) +{ + if(!c) + c = ownerDoc()->canvas(); + + if(!m_item) + { + m_item = c->createPolyline(this); + c->insert(m_item); + } +} + +void SVGPolylineElementImpl::drawMarkers() +{ + SVGPointListImpl *pts = points(); + unsigned int nrPoints = pts->numberOfItems(); + + if(nrPoints > 0 && hasMarkers()) + { + if(hasStartMarker()) + { + double outSlope; + + if(!findOutSlope(0, &outSlope)) + outSlope = 0; + + doStartMarker(this, this, pts->getItem(0)->x(), pts->getItem(0)->y(), outSlope); + } + + if(hasMidMarker()) + { + for(unsigned int i = 1; i < nrPoints - 1; ++i) + { + double inSlope; + double outSlope; + bool haveInSlope = findInSlope(i, &inSlope); + bool haveOutSlope = findOutSlope(i, &outSlope); + + if(!haveInSlope && haveOutSlope) + inSlope = outSlope; + else if(haveInSlope && !haveOutSlope) + outSlope = inSlope; + else if(!haveInSlope && !haveOutSlope) + { + inSlope = 0; + outSlope = 0; + } + + double bisector = SVGAngleImpl::shortestArcBisector(inSlope, outSlope); + + doMidMarker(this, this, pts->getItem(i)->x(), pts->getItem(i)->y(), bisector); + } + } + + if(hasEndMarker()) + { + double inSlope; + + if(!findInSlope(nrPoints - 1, &inSlope)) + inSlope = 0; + + doEndMarker(this, this, pts->getItem(nrPoints - 1)->x(), pts->getItem(nrPoints - 1)->y(), inSlope); + } + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPolylineElementImpl.h b/ksvg/impl/SVGPolylineElementImpl.h new file mode 100644 index 00000000..c6ea5885 --- /dev/null +++ b/ksvg/impl/SVGPolylineElementImpl.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPolylineElementImpl_H +#define SVGPolylineElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGPolyElementImpl.h" +#include "CanvasItems.h" + +namespace KSVG +{ + +class SVGPolylineElementImpl : public SVGPolyElementImpl, public MarkerHelper +{ +public: + SVGPolylineElementImpl(DOM::ElementImpl *); + virtual ~SVGPolylineElementImpl() { } + + virtual void createItem(KSVGCanvas *c = 0); + + virtual void drawMarkers(); + +public: + KSVG_BRIDGE + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +KSVG_REGISTER_ELEMENT(SVGPolylineElementImpl, "polyline") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPreserveAspectRatioImpl.cc b/ksvg/impl/SVGPreserveAspectRatioImpl.cc new file mode 100644 index 00000000..c8660e61 --- /dev/null +++ b/ksvg/impl/SVGPreserveAspectRatioImpl.cc @@ -0,0 +1,217 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include +#include + +#include "SVGPreserveAspectRatio.h" + +#include "SVGMatrixImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGPreserveAspectRatioImpl.h" + +using namespace KSVG; + +#include "SVGPreserveAspectRatioImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_cacheimpl.h" + +SVGPreserveAspectRatioImpl::SVGPreserveAspectRatioImpl() +{ + KSVG_EMPTY_FLAGS + + m_meetOrSlice = SVG_MEETORSLICE_UNKNOWN; + m_align = SVG_PRESERVEASPECTRATIO_UNKNOWN; +} + +SVGPreserveAspectRatioImpl::~SVGPreserveAspectRatioImpl() +{ +} + +void SVGPreserveAspectRatioImpl::setAlign(unsigned short align) +{ + m_align = align; +} + +unsigned short SVGPreserveAspectRatioImpl::align() const +{ + return m_align; +} + +void SVGPreserveAspectRatioImpl::setMeetOrSlice(unsigned short meetOrSlice) +{ + m_meetOrSlice = meetOrSlice; +} + +unsigned short SVGPreserveAspectRatioImpl::meetOrSlice() const +{ + return m_meetOrSlice; +} + +void SVGPreserveAspectRatioImpl::parsePreserveAspectRatio(const QString &str) +{ + // Spec: set the defaults + setAlign(SVG_PRESERVEASPECTRATIO_NONE); + setMeetOrSlice(SVG_MEETORSLICE_MEET); + + QStringList params = QStringList::split(' ', str.simplifyWhiteSpace()); + + if(params[0].compare("none") == 0) + m_align = SVG_PRESERVEASPECTRATIO_NONE; + else if(params[0].compare("xMinYMin") == 0) + m_align = SVG_PRESERVEASPECTRATIO_XMINYMIN; + else if(params[0].compare("xMidYMin") == 0) + m_align = SVG_PRESERVEASPECTRATIO_XMIDYMIN; + else if(params[0].compare("xMaxYMin") == 0) + m_align = SVG_PRESERVEASPECTRATIO_XMAXYMIN; + else if(params[0].compare("xMinYMid") == 0) + m_align = SVG_PRESERVEASPECTRATIO_XMINYMID; + else if(params[0].compare("xMidYMid") == 0) + m_align = SVG_PRESERVEASPECTRATIO_XMIDYMID; + else if(params[0].compare("xMaxYMid") == 0) + m_align = SVG_PRESERVEASPECTRATIO_XMAXYMID; + else if(params[0].compare("xMinYMax") == 0) + m_align = SVG_PRESERVEASPECTRATIO_XMINYMAX; + else if(params[0].compare("xMidYMax") == 0) + m_align = SVG_PRESERVEASPECTRATIO_XMIDYMAX; + else if(params[0].compare("xMaxYMax") == 0) + m_align = SVG_PRESERVEASPECTRATIO_XMAXYMAX; + + if(params[1].compare("slice") == 0) + m_meetOrSlice = SVG_MEETORSLICE_SLICE; + else + m_meetOrSlice = SVG_MEETORSLICE_MEET; +} + +SVGMatrixImpl *SVGPreserveAspectRatioImpl::getCTM(float logicX, float logicY, float logicWidth, float logicHeight, + float /*physX*/, float /*physY*/, float physWidth, float physHeight) +{ + SVGMatrixImpl *temp = SVGSVGElementImpl::createSVGMatrix(); + + if(align() == SVG_PRESERVEASPECTRATIO_UNKNOWN) + return temp; + + float vpar = logicWidth / logicHeight; + float svgar = physWidth / physHeight; + + if(align() == SVG_PRESERVEASPECTRATIO_NONE) + { + temp->scaleNonUniform(physWidth / logicWidth, physHeight / logicHeight); + temp->translate(-logicX, -logicY); + } + else if(vpar < svgar && (meetOrSlice() == SVG_MEETORSLICE_MEET) || vpar >= svgar && (meetOrSlice() == SVG_MEETORSLICE_SLICE)) + { + temp->scale(physHeight / logicHeight); + + if(align() == SVG_PRESERVEASPECTRATIO_XMINYMIN || align() == SVG_PRESERVEASPECTRATIO_XMINYMID || align() == SVG_PRESERVEASPECTRATIO_XMINYMAX) + temp->translate(-logicX, -logicY); + else if(align() == SVG_PRESERVEASPECTRATIO_XMIDYMIN || align() == SVG_PRESERVEASPECTRATIO_XMIDYMID || align() == SVG_PRESERVEASPECTRATIO_XMIDYMAX) + temp->translate(-logicX - (logicWidth - physWidth * logicHeight / physHeight) / 2, -logicY); + else + temp->translate(-logicX - (logicWidth - physWidth * logicHeight / physHeight), -logicY); + } + else + { + temp->scale(physWidth / logicWidth); + + if(align() == SVG_PRESERVEASPECTRATIO_XMINYMIN || align() == SVG_PRESERVEASPECTRATIO_XMIDYMIN || align() == SVG_PRESERVEASPECTRATIO_XMAXYMIN) + temp->translate(-logicX, -logicY); + else if(align() == SVG_PRESERVEASPECTRATIO_XMINYMID || align() == SVG_PRESERVEASPECTRATIO_XMIDYMID || align() == SVG_PRESERVEASPECTRATIO_XMAXYMID) + temp->translate(-logicX, -logicY - (logicHeight - physHeight * logicWidth / physWidth) / 2); + else + temp->translate(-logicX, -logicY - (logicHeight - physHeight * logicWidth / physWidth)); + } + + return temp; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPreserveAspectRatioImpl::s_hashTable 3 + align SVGPreserveAspectRatioImpl::Align DontDelete + meetOrSlice SVGPreserveAspectRatioImpl::MeetOrSlice DontDelete +@end +*/ + +Value SVGPreserveAspectRatioImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case Align: + return Number(align()); + case MeetOrSlice: + return Number(meetOrSlice()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return KJS::Undefined(); + } +} + +void SVGPreserveAspectRatioImpl::putValueProperty(ExecState *exec, int token, const KJS::Value &value, int) +{ + switch(token) + { + case Align: + m_align = static_cast(value.toNumber(exec)); + break; + case MeetOrSlice: + m_meetOrSlice = static_cast(value.toNumber(exec)); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +/* +@namespace KSVG +@begin SVGPreserveAspectRatioImplConstructor::s_hashTable 17 + SVG_PRESERVEASPECTRATIO_UNKNOWN KSVG::SVG_PRESERVEASPECTRATIO_UNKNOWN DontDelete|ReadOnly + SVG_PRESERVEASPECTRATIO_NONE KSVG::SVG_PRESERVEASPECTRATIO_NONE DontDelete|ReadOnly + SVG_PRESERVEASPECTRATIO_XMINYMIN KSVG::SVG_PRESERVEASPECTRATIO_XMINYMIN DontDelete|ReadOnly + SVG_PRESERVEASPECTRATIO_XMIDYMIN KSVG::SVG_PRESERVEASPECTRATIO_XMIDYMIN DontDelete|ReadOnly + SVG_PRESERVEASPECTRATIO_XMAXYMIN KSVG::SVG_PRESERVEASPECTRATIO_XMAXYMIN DontDelete|ReadOnly + SVG_PRESERVEASPECTRATIO_XMINYMID KSVG::SVG_PRESERVEASPECTRATIO_XMINYMID DontDelete|ReadOnly + SVG_PRESERVEASPECTRATIO_XMIDYMID KSVG::SVG_PRESERVEASPECTRATIO_XMIDYMID DontDelete|ReadOnly + SVG_PRESERVEASPECTRATIO_XMAXYMID KSVG::SVG_PRESERVEASPECTRATIO_XMAXYMID DontDelete|ReadOnly + SVG_PRESERVEASPECTRATIO_XMINYMAX KSVG::SVG_PRESERVEASPECTRATIO_XMINYMAX DontDelete|ReadOnly + SVG_PRESERVEASPECTRATIO_XMIDYMAX KSVG::SVG_PRESERVEASPECTRATIO_XMIDYMAX DontDelete|ReadOnly + SVG_PRESERVEASPECTRATIO_XMAXYMAX KSVG::SVG_PRESERVEASPECTRATIO_XMAXYMAX DontDelete|ReadOnly + SVG_MEETORSLICE_UNKNOWN KSVG::SVG_MEETORSLICE_UNKNOWN DontDelete|ReadOnly + SVG_MEETORSLICE_MEET KSVG::SVG_MEETORSLICE_MEET DontDelete|ReadOnly + SVG_MEETORSLICE_SLICE KSVG::SVG_MEETORSLICE_SLICE DontDelete|ReadOnly +@end +*/ + +Value SVGPreserveAspectRatioImplConstructor::getValueProperty(ExecState *, int token) const +{ + return Number(token > SVG_PRESERVEASPECTRATIO_XMAXYMAX ? token - SVG_MEETORSLICE_UNKNOWN : token); +} + +Value KSVG::getSVGPreserveAspectRatioImplConstructor(ExecState *exec) +{ + return cacheGlobalBridge(exec, "[[svgpreserveaspectratio.constructor]]"); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGPreserveAspectRatioImpl.h b/ksvg/impl/SVGPreserveAspectRatioImpl.h new file mode 100644 index 00000000..4a14a6b0 --- /dev/null +++ b/ksvg/impl/SVGPreserveAspectRatioImpl.h @@ -0,0 +1,84 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGPreserveAspectRatioImpl_H +#define SVGPreserveAspectRatioImpl_H + +#include + +#include "ksvg_lookup.h" + +class QString; + +namespace KSVG +{ + +class SVGMatrixImpl; +class SVGPreserveAspectRatioImpl : public DOM::DomShared +{ +public: + SVGPreserveAspectRatioImpl(); + virtual ~SVGPreserveAspectRatioImpl(); + + void setAlign(unsigned short); + unsigned short align() const; + + void setMeetOrSlice(unsigned short); + unsigned short meetOrSlice() const; + + void parsePreserveAspectRatio(const QString &); + SVGMatrixImpl *getCTM(float logicX, float logicY, float logicWidth, float logicHeight, + float physX, float physY, float physWidth, float physHeight); + +protected: + unsigned short m_align; + unsigned short m_meetOrSlice; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + Align, MeetOrSlice + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +class SVGPreserveAspectRatioImplConstructor : public KJS::ObjectImp +{ +public: + SVGPreserveAspectRatioImplConstructor(KJS::ExecState *) { } + KJS::Value getValueProperty(KJS::ExecState *, int token) const; + + // no put - all read-only + KSVG_GET +}; + +KJS::Value getSVGPreserveAspectRatioImplConstructor(KJS::ExecState *exec); + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGRadialGradientElementImpl.cc b/ksvg/impl/SVGRadialGradientElementImpl.cc new file mode 100644 index 00000000..8d00cf15 --- /dev/null +++ b/ksvg/impl/SVGRadialGradientElementImpl.cc @@ -0,0 +1,216 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGGradientElement.h" +#include "SVGRadialGradientElementImpl.h" + +#include "SVGDocumentImpl.h" +#include "KSVGCanvas.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGUnitConverter.h" + +using namespace KSVG; + +#include "SVGRadialGradientElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGRadialGradientElementImpl::SVGRadialGradientElementImpl(DOM::ElementImpl *impl) : SVGGradientElementImpl(impl) +{ + KSVG_EMPTY_FLAGS + + m_cx = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_cx->ref(); + + m_cy = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_cy->ref(); + + m_r = new SVGAnimatedLengthImpl(LENGTHMODE_OTHER, this); + m_r->ref(); + + m_fx = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_fx->ref(); + + m_fy = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_fy->ref(); + + converter()->add(m_cx); + converter()->add(m_cy); + converter()->add(m_r); + converter()->add(m_fx); + converter()->add(m_fy); +} + +SVGRadialGradientElementImpl::~SVGRadialGradientElementImpl() +{ + if(m_cx) + m_cx->deref(); + if(m_cy) + m_cy->deref(); + if(m_r) + m_r->deref(); + if(m_fx) + m_fx->deref(); + if(m_fy) + m_fy->deref(); +} + +SVGAnimatedLengthImpl *SVGRadialGradientElementImpl::cx() const +{ + return m_cx; +} + +SVGAnimatedLengthImpl *SVGRadialGradientElementImpl::cy() const +{ + return m_cy; +} + +SVGAnimatedLengthImpl *SVGRadialGradientElementImpl::r() const +{ + return m_r; +} + +SVGAnimatedLengthImpl *SVGRadialGradientElementImpl::fx() const +{ + return m_fx; +} + +SVGAnimatedLengthImpl *SVGRadialGradientElementImpl::fy() const +{ + return m_fy; +} + +/* +@namespace KSVG +@begin SVGRadialGradientElementImpl::s_hashTable 7 + cx SVGRadialGradientElementImpl::Cx DontDelete|ReadOnly + cy SVGRadialGradientElementImpl::Cy DontDelete|ReadOnly + r SVGRadialGradientElementImpl::R DontDelete|ReadOnly + fx SVGRadialGradientElementImpl::Fx DontDelete|ReadOnly + fy SVGRadialGradientElementImpl::Fy DontDelete|ReadOnly +@end +*/ + +Value SVGRadialGradientElementImpl::getValueProperty(ExecState *exec, int token) const +{ + KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case Cx: + if(!attributeMode) + return m_cx->cache(exec); + else + return Number(m_cx->baseVal()->value()); + case Cy: + if(!attributeMode) + return m_cy->cache(exec); + else + return Number(m_cy->baseVal()->value()); + case R: + if(!attributeMode) + return m_r->cache(exec); + else + return Number(m_r->baseVal()->value()); + case Fx: + if(!attributeMode) + return m_fx->cache(exec); + else + return Number(m_fx->baseVal()->value()); + case Fy: + if(!attributeMode) + return m_fy->cache(exec); + else + return Number(m_fy->baseVal()->value()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGRadialGradientElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case Cx: + converter()->modify(cx(), value.toString(exec).qstring()); + break; + case Cy: + converter()->modify(cy(), value.toString(exec).qstring()); + break; + case R: + converter()->modify(r(), value.toString(exec).qstring()); + break; + case Fx: + converter()->modify(fx(), value.toString(exec).qstring()); + break; + case Fy: + converter()->modify(fy(), value.toString(exec).qstring()); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +void SVGRadialGradientElementImpl::setAttributes() +{ + SVGGradientElementImpl::setAttributes(); + + // Spec: no attribute, effect is af value 50% is specified + if(KSVG_TOKEN_NOT_PARSED(Cx)) + KSVG_SET_ALT_ATTRIBUTE(Cx, "50%") + + // Spec: no attribute, effect is af value 50% is specified + if(KSVG_TOKEN_NOT_PARSED(Cy)) + KSVG_SET_ALT_ATTRIBUTE(Cy, "50%") + + // Spec: no attribute, effect is af value 50% is specified + if(KSVG_TOKEN_NOT_PARSED(R)) + KSVG_SET_ALT_ATTRIBUTE(R, "50%") +} + +QMap SVGRadialGradientElementImpl::gradientAttributes() +{ + setAttributes(); + + QMap gradAttributes; + QDictIterator it(attributes()); + + for(; it.current(); ++it) + { + DOM::DOMString name = it.currentKey(); + DOM::DOMString value = it.current()->string(); + + if(name == "gradientUnits" || name == "gradientTransform" || name == "spreadMethod" || name == "cx" || name == "cy" || name == "r" || name == "fx" || name == "fy") + { + gradAttributes.insert(name.string(), value.copy()); + } + } + + return gradAttributes; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGRadialGradientElementImpl.h b/ksvg/impl/SVGRadialGradientElementImpl.h new file mode 100644 index 00000000..2f6c58c1 --- /dev/null +++ b/ksvg/impl/SVGRadialGradientElementImpl.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGRadialGradientElementImpl_H +#define SVGRadialGradientElementImpl_H + +#include "SVGGradientElementImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedLengthImpl; +class SVGRadialGradientElementImpl : public SVGGradientElementImpl +{ +public: + SVGRadialGradientElementImpl(DOM::ElementImpl *); + virtual ~SVGRadialGradientElementImpl(); + + SVGAnimatedLengthImpl *cx() const; + SVGAnimatedLengthImpl *cy() const; + SVGAnimatedLengthImpl *r() const; + SVGAnimatedLengthImpl *fx() const; + SVGAnimatedLengthImpl *fy() const; + + virtual void setAttributes(); + + virtual QMap gradientAttributes(); + +private: + SVGAnimatedLengthImpl *m_cx; + SVGAnimatedLengthImpl *m_cy; + SVGAnimatedLengthImpl *m_r; + SVGAnimatedLengthImpl *m_fx; + SVGAnimatedLengthImpl *m_fy; + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + Cx, Cy, R, Fx, Fy, Href + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGRadialGradientElementImpl, "radialGradient") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGRectElementImpl.cc b/ksvg/impl/SVGRectElementImpl.cc new file mode 100644 index 00000000..3dad7cbf --- /dev/null +++ b/ksvg/impl/SVGRectElementImpl.cc @@ -0,0 +1,244 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include + +#include "SVGRectImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGRectElementImpl.h" +#include "SVGAnimatedLengthImpl.h" + +#include "KSVGCanvas.h" +#include "CanvasItem.h" + +using namespace KSVG; + +#include "SVGRectElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGRectElementImpl::SVGRectElementImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl() +{ + KSVG_EMPTY_FLAGS + + m_x = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_x->ref(); + m_x->baseVal()->setValueAsString("-1"); + + m_y = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_y->ref(); + m_y->baseVal()->setValueAsString("-1"); + + m_width = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_width->ref(); + m_width->baseVal()->setValueAsString("-1"); + + m_height = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_height->ref(); + m_height->baseVal()->setValueAsString("-1"); + + m_rx = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_rx->ref(); + m_rx->baseVal()->setValueAsString("-1"); + + m_ry = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_ry->ref(); + m_ry->baseVal()->setValueAsString("-1"); +} + +SVGRectElementImpl::~SVGRectElementImpl() +{ + if(m_x) + m_x->deref(); + if(m_y) + m_y->deref(); + if(m_width) + m_width->deref(); + if(m_height) + m_height->deref(); + if(m_rx) + m_rx->deref(); + if(m_ry) + m_ry->deref(); +} + +SVGAnimatedLengthImpl *SVGRectElementImpl::x() +{ + return m_x; +} + +SVGAnimatedLengthImpl *SVGRectElementImpl::y() +{ + return m_y; +} + +SVGAnimatedLengthImpl *SVGRectElementImpl::width() +{ + return m_width; +} + +SVGAnimatedLengthImpl *SVGRectElementImpl::height() +{ + return m_height; +} + +SVGAnimatedLengthImpl *SVGRectElementImpl::rx() +{ + return m_rx; +} + +SVGAnimatedLengthImpl *SVGRectElementImpl::ry() +{ + return m_ry; +} + +/* +@namespace KSVG +@begin SVGRectElementImpl::s_hashTable 7 + x SVGRectElementImpl::X DontDelete|ReadOnly + y SVGRectElementImpl::Y DontDelete|ReadOnly + width SVGRectElementImpl::Width DontDelete|ReadOnly + height SVGRectElementImpl::Height DontDelete|ReadOnly + rx SVGRectElementImpl::Rx DontDelete|ReadOnly + ry SVGRectElementImpl::Ry DontDelete|ReadOnly +@end +*/ + +Value SVGRectElementImpl::getValueProperty(ExecState *exec, int token) const +{ + KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case X: + if(!attributeMode) + return m_x->cache(exec); + else + return Number(m_x->baseVal()->value()); + case Y: + if(!attributeMode) + return m_y->cache(exec); + else + return Number(m_y->baseVal()->value()); + case Width: + if(!attributeMode) + return m_width->cache(exec); + else + return Number(m_width->baseVal()->value()); + case Height: + if(!attributeMode) + return m_height->cache(exec); + else + return Number(m_height->baseVal()->value()); + case Rx: + if(!attributeMode) + return m_rx->cache(exec); + else + return Number(m_rx->baseVal()->value()); + case Ry: + if(!attributeMode) + return m_ry->cache(exec); + else + return Number(m_ry->baseVal()->value()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGRectElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case X: + x()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case Y: + y()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case Width: + width()->baseVal()->setValueAsString(value.toString(exec).qstring()); + if(width()->baseVal()->value() < 0) // A negative value is an error + gotError(i18n("Negative value for attribute width of element is illegal")); + break; + case Height: + height()->baseVal()->setValueAsString(value.toString(exec).qstring()); + if(height()->baseVal()->value() < 0) // A negative value is an error + gotError(i18n("Negative value for attribute height of element is illegal")); + break; + case Rx: + rx()->baseVal()->setValueAsString(value.toString(exec).qstring()); + if(rx()->baseVal()->value() < 0) // A negative value is an error + gotError(i18n("Negative value for attribute rx of element is illegal")); + break; + case Ry: + ry()->baseVal()->setValueAsString(value.toString(exec).qstring()); + if(ry()->baseVal()->value() < 0) // A negative value is an error + gotError(i18n("Negative value for attribute ry of element is illegal")); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +SVGRectImpl *SVGRectElementImpl::getBBox() +{ + SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect(); + ret->setX(m_x->baseVal()->value()); + ret->setY(m_y->baseVal()->value()); + ret->setWidth(m_width->baseVal()->value()); + ret->setHeight(m_height->baseVal()->value()); + return ret; +} + +void SVGRectElementImpl::setAttributes() +{ + SVGElementImpl::setAttributes(); + + // Spec: if not specified, effect is as if a value of "0" were specified + if(KSVG_TOKEN_NOT_PARSED(X)) + KSVG_SET_ALT_ATTRIBUTE(X, "0") + + // Spec: if not specified, effect is as if a value of "0" were specified + if(KSVG_TOKEN_NOT_PARSED(Y)) + KSVG_SET_ALT_ATTRIBUTE(Y, "0") +} + +void SVGRectElementImpl::createItem(KSVGCanvas *c) +{ + if(!c) + c = ownerDoc()->canvas(); + + if(!m_item) + { + m_item = c->createRectangle(this); + c->insert(m_item); + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGRectElementImpl.h b/ksvg/impl/SVGRectElementImpl.h new file mode 100644 index 00000000..690084d7 --- /dev/null +++ b/ksvg/impl/SVGRectElementImpl.h @@ -0,0 +1,90 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGRectElementImpl_H +#define SVGRectElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGShapeImpl.h" +#include "SVGTestsImpl.h" +#include "SVGStylableImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGTransformableImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +namespace KSVG +{ + +class SVGRectImpl; +class SVGAnimatedLengthImpl; +class SVGRectElementImpl : public SVGShapeImpl, + public SVGTestsImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGTransformableImpl +{ +public: + SVGRectElementImpl(DOM::ElementImpl *); + virtual ~SVGRectElementImpl(); + + SVGAnimatedLengthImpl *x(); + SVGAnimatedLengthImpl *y(); + SVGAnimatedLengthImpl *width(); + SVGAnimatedLengthImpl *height(); + SVGAnimatedLengthImpl *rx(); + SVGAnimatedLengthImpl *ry(); + + virtual void createItem(KSVGCanvas *c = 0); + virtual void setAttributes(); + + virtual SVGRectImpl *getBBox(); + +private: + SVGAnimatedLengthImpl *m_x; + SVGAnimatedLengthImpl *m_y; + SVGAnimatedLengthImpl *m_width; + SVGAnimatedLengthImpl *m_height; + SVGAnimatedLengthImpl *m_rx; + SVGAnimatedLengthImpl *m_ry; + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + X, Y, Width, Height, Rx, Ry + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGRectElementImpl, "rect") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGRectImpl.cc b/ksvg/impl/SVGRectImpl.cc new file mode 100644 index 00000000..1f6c0d51 --- /dev/null +++ b/ksvg/impl/SVGRectImpl.cc @@ -0,0 +1,157 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include + +#include "SVGRectImpl.h" + +using namespace KSVG; + +#include "SVGRectImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGRectImpl::SVGRectImpl() +{ + KSVG_EMPTY_FLAGS + + m_x = 0; + m_y = 0; + m_width = 0; + m_height = 0; +} + +SVGRectImpl::SVGRectImpl(const QRect &other) +{ + (*this) = other; +} + +SVGRectImpl::~SVGRectImpl() +{ +} + +void SVGRectImpl::setX(float x) +{ + m_x = x; +} + +float SVGRectImpl::x() const +{ + return m_x; +} + +void SVGRectImpl::setY(float y) +{ + m_y = y; +} + +float SVGRectImpl::y() const +{ + return m_y; +} + +void SVGRectImpl::setWidth(float width) +{ + m_width = width; +} + +float SVGRectImpl::width() const +{ + return m_width; +} + +void SVGRectImpl::setHeight(float height) +{ + m_height = height; +} + +float SVGRectImpl::height() const +{ + return m_height; +} + +QRect SVGRectImpl::qrect() const +{ + // ceil() so the integer rectangle contains the whole real one. + return QRect(int(m_x), int(m_y), int(ceil(m_width)), int(ceil(m_height))); +} + +SVGRectImpl &SVGRectImpl::operator=(const QRect &other) +{ + m_x = other.x(); + m_y = other.y(); + m_width = other.width(); + m_height = other.height(); + + return *this; +} + +/* +@namespace KSVG +@begin SVGRectImpl::s_hashTable 5 + x SVGRectImpl::X DontDelete + y SVGRectImpl::Y DontDelete + width SVGRectImpl::Width DontDelete + height SVGRectImpl::Height DontDelete +@end +*/ + +Value SVGRectImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case X: + return Number(m_x); + case Y: + return Number(m_y); + case Width: + return Number(m_width); + case Height: + return Number(m_height); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGRectImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int) +{ + switch(token) + { + case X: + m_x = value.toNumber(exec); + break; + case Y: + m_y = value.toNumber(exec); + break; + case Width: + m_width = value.toNumber(exec); + break; + case Height: + m_height = value.toNumber(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGRectImpl.h b/ksvg/impl/SVGRectImpl.h new file mode 100644 index 00000000..e0b0e889 --- /dev/null +++ b/ksvg/impl/SVGRectImpl.h @@ -0,0 +1,80 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGRectImpl_H +#define SVGRectImpl_H + +#include + +#include "ksvg_lookup.h" + +class QRect; + +namespace KSVG +{ + +class SVGRectImpl : public DOM::DomShared +{ +public: + SVGRectImpl(); + SVGRectImpl(const QRect &); + virtual ~SVGRectImpl(); + + void setX(float x); + float x() const; + + void setY(float y); + float y() const; + + void setWidth(float width); + float width() const; + + void setHeight(float height); + float height() const; + + QRect qrect() const; + + SVGRectImpl &operator=(const QRect &); + +private: + float m_x; + float m_y; + float m_width; + float m_height; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + X, Y, Width, Height + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGSVGElementImpl.cc b/ksvg/impl/SVGSVGElementImpl.cc new file mode 100644 index 00000000..b54cf521 --- /dev/null +++ b/ksvg/impl/SVGSVGElementImpl.cc @@ -0,0 +1,982 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include +#include +#include + +#define USE_VALGRIND 0 + +#if USE_VALGRIND +#include +#endif + +#include "SVGLength.h" + +#include "SVGRectImpl.h" +#include "SVGAngleImpl.h" +#include "SVGShapeImpl.h" +#include "SVGPointImpl.h" +#include "SVGNumberImpl.h" +#include "SVGMatrixImpl.h" + +#include "SVGEventImpl.h" +#include "SVGAElementImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGViewSpecImpl.h" +#include "SVGTransformImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGAnimatedRectImpl.h" +#include "SVGTransformListImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGAnimatedStringImpl.h" +#include "SVGPreserveAspectRatioImpl.h" +#include "SVGAnimatedTransformListImpl.h" +#include "SVGAnimatedPreserveAspectRatioImpl.h" + +#include "CanvasItem.h" +#include "KSVGCanvas.h" + +using namespace KSVG; + +#include "SVGSVGElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGSVGElementImpl::SVGSVGElementImpl(DOM::ElementImpl *impl) : SVGContainerImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGLocatableImpl(), SVGFitToViewBoxImpl(), SVGZoomAndPanImpl() +{ + KSVG_EMPTY_FLAGS + + m_x = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_x->ref(); + + m_y = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_y->ref(); + + m_width = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_width->ref(); + + m_height = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_height->ref(); + + m_viewport = SVGSVGElementImpl::createSVGRect(); + + m_currentTranslate = SVGSVGElementImpl::createSVGPoint(); + + m_currentView = new SVGViewSpecImpl(); + m_currentView->ref(); + + m_currentScale = 1.0; + + m_useCurrentView = false; + + m_clip[0] = 0; + m_clip[1] = 0; + m_clip[2] = 0; + m_clip[3] = 0; + + m_rootParentScreenCTM = 0; + + m_localMatrix = SVGSVGElementImpl::createSVGMatrix(); +} + +SVGSVGElementImpl::~SVGSVGElementImpl() +{ + if(m_x) + m_x->deref(); + if(m_y) + m_y->deref(); + if(m_width) + m_width->deref(); + if(m_height) + m_height->deref(); + if(m_viewport) + m_viewport->deref(); + if(m_currentTranslate) + m_currentTranslate->deref(); + if(m_currentView) + m_currentView->deref(); + if(m_rootParentScreenCTM) + m_rootParentScreenCTM->deref(); + if(m_localMatrix) + m_localMatrix->deref(); +} + +bool SVGSVGElementImpl::isRootElement() const +{ + return ownerDoc()->rootElement() == this; +} + +void SVGSVGElementImpl::setAttributes() +{ + SVGElementImpl::setAttributes(); + + // Spec: if not specified, effect is as if a value of "0" were specified + if(KSVG_TOKEN_NOT_PARSED(X)) + KSVG_SET_ALT_ATTRIBUTE(X, "0") + + // Spec: if not specified, effect is as if a value of "0" were specified + if(KSVG_TOKEN_NOT_PARSED(Y)) + KSVG_SET_ALT_ATTRIBUTE(Y, "0") + + // Spec: If the attribute is not specified, the effect is as if a value of "100%" were specified. + if(KSVG_TOKEN_NOT_PARSED(Width)) + KSVG_SET_ALT_ATTRIBUTE(Width, "100%") + + // Spec: If the attribute is not specified, the effect is as if a value of "100%" were specified. + if(KSVG_TOKEN_NOT_PARSED(Height)) + KSVG_SET_ALT_ATTRIBUTE(Height, "100%") + + // Spec: The contentScriptType should default to "text/ecmascript". + if(KSVG_TOKEN_NOT_PARSED(ContentScriptType)) + KSVG_SET_ALT_ATTRIBUTE(ContentScriptType, "text/ecmascript") + + // Spec: The contentStyleType should default to "text/css". + if(KSVG_TOKEN_NOT_PARSED(ContentStyleType)) + KSVG_SET_ALT_ATTRIBUTE(ContentStyleType, "text/css") + + if(m_useCurrentView) + { + parseViewBox(m_currentView->viewBoxString().string()); + preserveAspectRatio()->baseVal()->parsePreserveAspectRatio(m_currentView->preserveAspectRatioString().string()); + } + + m_viewport->setX(x()->baseVal()->value()); + m_viewport->setY(y()->baseVal()->value()); + m_viewport->setWidth(width()->baseVal()->value()); + m_viewport->setHeight(height()->baseVal()->value()); + + if(isRootElement() && ownerDoc()->parentImage() == 0) + { + if(ownerDoc()->canvas()) + ownerDoc()->canvas()->setViewportDimension(int(ceil(width()->baseVal()->value() * currentScale())), int(ceil(height()->baseVal()->value() * currentScale()))); + + // Special case for outermost svg element: + // We need to register our id manually, because + // m_ownerSVGElement is 0 in SVGElementImpl::setAttributes (Niko) + if(!id().isNull()) + addToIdMap(id().string(), this); + } +} + +SVGAnimatedLengthImpl *SVGSVGElementImpl::x() +{ + return m_x; +} + +SVGAnimatedLengthImpl *SVGSVGElementImpl::y() +{ + return m_y; +} + +SVGAnimatedLengthImpl *SVGSVGElementImpl::width() +{ + return m_width; +} + +SVGAnimatedLengthImpl *SVGSVGElementImpl::height() +{ + return m_height; +} + +void SVGSVGElementImpl::setContentScriptType(const DOM::DOMString &contentScriptType) +{ + setAttribute("contentScriptType", contentScriptType); +} + +DOM::DOMString SVGSVGElementImpl::contentScriptType() const +{ + return getAttribute("contentScriptType"); +} + +void SVGSVGElementImpl::setContentStyleType(const DOM::DOMString &contentStyleType) +{ + setAttribute("contentStyleType", contentStyleType); +} + +DOM::DOMString SVGSVGElementImpl::contentStyleType() const +{ + return getAttribute("contentStyleType"); +} + +SVGRectImpl *SVGSVGElementImpl::viewport() +{ + return m_viewport; +} + +SVGRectImpl *SVGSVGElementImpl::getBBox() +{ + SVGRectImpl *ret = new SVGRectImpl(getCTM()->qmatrix().invert().map(m_viewport->qrect())); + ret->ref(); + return ret; +} + +float SVGSVGElementImpl::pixelUnitToMillimeterX() const +{ + return ownerDoc()->screenPixelsPerMillimeterX(); +} + +float SVGSVGElementImpl::pixelUnitToMillimeterY() const +{ + return ownerDoc()->screenPixelsPerMillimeterY(); +} + +float SVGSVGElementImpl::screenPixelToMillimeterX() const +{ + return pixelUnitToMillimeterX(); +} + +float SVGSVGElementImpl::screenPixelToMillimeterY() const +{ + return pixelUnitToMillimeterY(); +} + +void SVGSVGElementImpl::setUseCurrentView(bool useCurrentView) +{ + m_useCurrentView = useCurrentView; +} + +bool SVGSVGElementImpl::useCurrentView() const +{ + return m_useCurrentView; +} + +SVGViewSpecImpl *SVGSVGElementImpl::currentView() const +{ + return m_currentView; +} + +void SVGSVGElementImpl::setCurrentScale(float currentScale) +{ + if( m_currentScale != currentScale ) + { + m_currentScale = currentScale; + invalidateCachedMatrices(); + + if(hasEventListener(SVGEvent::ZOOM_EVENT, true)) + dispatchEvent(SVGEvent::ZOOM_EVENT, false, false); + } +} + +float SVGSVGElementImpl::currentScale() const +{ + return m_currentScale; +} + +void SVGSVGElementImpl::setCurrentTranslate(const QPoint &p) +{ + if(m_currentTranslate->x() != p.x() || m_currentTranslate->y() != p.y()) + { + m_currentTranslate->setX(p.x()); + m_currentTranslate->setY(p.y()); + invalidateCachedMatrices(); + if(hasEventListener(SVGEvent::SCROLL_EVENT, true)) + dispatchEvent(SVGEvent::SCROLL_EVENT, false, false); + } +} + +SVGPointImpl *SVGSVGElementImpl::currentTranslate() +{ + return m_currentTranslate; +} + +unsigned long SVGSVGElementImpl::suspendRedraw(unsigned long) +{ + return 0; +} + +void SVGSVGElementImpl::unsuspendRedraw(unsigned long) +{ +} + +void SVGSVGElementImpl::unsuspendRedrawAll() +{ +} + +void SVGSVGElementImpl::forceRedraw() +{ +#if USE_VALGRIND + CALLTREE_ZERO_STATS(); +#endif + + QTime timer; + timer.start(); + + if(ownerDoc() && ownerDoc()->canvas()) + ownerDoc()->canvas()->update(); + + kdDebug(26000) << "forceRedraw in " << timer.elapsed()/1000.0 << " seconds" << endl; + +#if USE_VALGRIND + CALLTREE_DUMP_STATS(); +#endif +} + +void SVGSVGElementImpl::pauseAnimations() +{ + if(!ownerDoc()->timeScheduler()->animationsPaused()) + ownerDoc()->timeScheduler()->toggleAnimations(); +} + +void SVGSVGElementImpl::unpauseAnimations() +{ + if(ownerDoc()->timeScheduler()->animationsPaused()) + ownerDoc()->timeScheduler()->toggleAnimations(); +} + +bool SVGSVGElementImpl::animationsPaused() +{ + return ownerDoc()->timeScheduler()->animationsPaused(); +} + +float SVGSVGElementImpl::getCurrentTime() const +{ + return ownerDoc()->timeScheduler()->elapsed(); +} + +void SVGSVGElementImpl::setCurrentTime(float) +{ +} + +DOM::NodeList SVGSVGElementImpl::getIntersectionList(SVGRectImpl *, SVGElementImpl *) +{ + // TODO : implement me + return DOM::NodeList(); +} + +DOM::NodeList SVGSVGElementImpl::getEnclosureList(SVGRectImpl *rect, SVGElementImpl */*referenceElement*/) +{ + DOM::NodeList list; + + DOM::Node node = firstChild(); + for(; !node.isNull(); node = node.nextSibling()) + { + SVGElementImpl *element = ownerDoc()->getElementFromHandle(node.handle()); + SVGShapeImpl *shape = dynamic_cast(element); + if(shape) + { + if(shape->isContainer()) + // TODO : pass it on to container::getEnclosureList() which should return a NodeList + kdDebug() << "!shape" << endl; + else + { + // TODO : add the shape to list if the test succeeds + SVGRectImpl *current = shape->getBBox(); + if(rect->qrect().contains(current->qrect(), true)) + kdDebug() << "shape : " << element->nodeName().string() << " is fully enclosed" << endl; + + current->deref(); + } + } + } + + return list; +} + +bool SVGSVGElementImpl::checkIntersection(SVGElementImpl *element, SVGRectImpl *rect) +{ + SVGShapeImpl *shape = dynamic_cast(element); + if(!shape) + return false; + + SVGRectImpl *current = shape->getBBox(); + bool result = rect->qrect().intersects(current->qrect()); + current->deref(); + return result; +} + +bool SVGSVGElementImpl::checkEnclosure(SVGElementImpl *element, SVGRectImpl *rect) +{ + SVGShapeImpl *shape = dynamic_cast(element); + if(!shape) + return false; + + SVGRectImpl *current = shape->getBBox(); + bool result = rect->qrect().contains(current->qrect()); + current->deref(); + return result; +} + +void SVGSVGElementImpl::deSelectAll() +{ +} + +SVGNumberImpl *SVGSVGElementImpl::createSVGNumber() +{ + // Spec: Creates an SVGNumber object outside of any document + // trees. The object is initialized to a value of zero. + SVGNumberImpl *ret = new SVGNumberImpl(); + ret->ref(); + return ret; +} + +SVGLengthImpl *SVGSVGElementImpl::createSVGLength() +{ + // Spec: Creates an SVGLength object outside of any document + // trees. The object is initialized to the value of 0 user units. + SVGLengthImpl *ret = new SVGLengthImpl(); + ret->ref(); + return ret; +} + +SVGAngleImpl *SVGSVGElementImpl::createSVGAngle() +{ + // Spec: Creates an SVGAngle object outside of any document + // trees. The object is initialized to the value 0 degrees (unitless). + SVGAngleImpl *ret = new SVGAngleImpl(); + ret->ref(); + return ret; +} + +SVGPointImpl *SVGSVGElementImpl::createSVGPoint() +{ + // Spec: Creates an SVGPoint object outside of any document + // trees. The object is initialized to the point (0,0) in the user coordinate system. + SVGPointImpl *ret = new SVGPointImpl(); + ret->ref(); + return ret; +} + +SVGMatrixImpl *SVGSVGElementImpl::createSVGMatrix() +{ + // Spec: Creates an SVGMatrix object outside of any document + // trees. The object is initialized to the identity matrix. + SVGMatrixImpl *ret = new SVGMatrixImpl(QWMatrix(1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F)); + ret->ref(); + return ret; +} + +SVGRectImpl *SVGSVGElementImpl::createSVGRect() +{ + // Spec: Creates an SVGRect object outside of any document + // trees. The object is initialized such that all values are set to 0 user units. + SVGRectImpl *ret = new SVGRectImpl(); + ret->ref(); + return ret; +} + +SVGTransformImpl *SVGSVGElementImpl::createSVGTransform() +{ + // Spec: Creates an SVGTransform object outside of any document + // trees. The object is initialized to an identity matrix transform (SVG_TRANSFORM_MATRIX). + SVGTransformImpl *transform = createSVGTransformFromMatrix(createSVGMatrix()); + + // createSVGMatrix already ref's the matrix, the SVGTransformImpl->setMatrix + // call also does this, prevent non deleting of the object by deref'ing (Niko) + transform->matrix()->deref(); + + return transform; +} + +SVGTransformImpl *SVGSVGElementImpl::createSVGTransformFromMatrix(SVGMatrixImpl *mat) +{ + // Spec: Creates an SVGTransform object outside of any document + // trees. The object is initialized to the given matrix transform (i.e., SVG_TRANSFORM_MATRIX). + SVGTransformImpl *ret = new SVGTransformImpl(); + ret->setMatrix(mat); + ret->ref(); + return ret; +} + +SVGElementImpl *SVGSVGElementImpl::getElementById(const DOM::DOMString &elementId) +{ + return m_map[elementId.string()]; +} + +void SVGSVGElementImpl::addToIdMap(const QString &id, SVGElementImpl *obj) +{ + m_map.insert(id, obj); +} + +SVGMatrixImpl *SVGSVGElementImpl::getCTM() +{ + return viewBoxToViewTransform(width()->baseVal()->value(), height()->baseVal()->value()); +} + +const SVGMatrixImpl *SVGSVGElementImpl::localMatrix() +{ + // TODO: only update the matrix when needed and just return m_localMatrix + + m_localMatrix->reset(); + + if(ownerSVGElement() == 0) + { + if(m_rootParentScreenCTM != 0) + m_localMatrix->copy(m_rootParentScreenCTM); + + // We're the outermost svg element. + // Put the zoom scale and translate into the matrix. + m_localMatrix->translate(currentTranslate()->x(), currentTranslate()->y()); + m_localMatrix->scale(currentScale()); + } + + // Apply viewport translation. + m_localMatrix->translate(x()->baseVal()->value(), y()->baseVal()->value()); + + // And viewbox. + SVGMatrixImpl *viewboxMatrix = viewBoxToViewTransform(width()->baseVal()->value(), height()->baseVal()->value()); + + m_localMatrix->multiply(viewboxMatrix); + viewboxMatrix->deref(); + + return m_localMatrix; +} + +void SVGSVGElementImpl::setClip(const QString &clip) +{ + // TODO : this routine should probably be shared between all classes that establish new viewports (Rob) + if(!clip.startsWith("rect(") || !clip.endsWith(")")) + return; + + QString work = clip.mid(5, clip.length() - 6); + QStringList substrings = QStringList::split(',', clip); + QStringList::ConstIterator it = substrings.begin(); + + if(m_clip[0]) + m_clip[0]->deref(); + m_clip[0] = SVGSVGElementImpl::createSVGLength(); + + if(*it != "auto") + m_clip[0]->setValueAsString(*it); + ++it; + + if(m_clip[1]) + m_clip[1]->deref(); + m_clip[1] = SVGSVGElementImpl::createSVGLength(); + + if(*it != "auto") + m_clip[1]->setValueAsString(*it); + ++it; + + if(m_clip[2]) + m_clip[2]->deref(); + m_clip[2] = SVGSVGElementImpl::createSVGLength(); + + if(*it != "auto") + m_clip[2]->setValueAsString(*it); + ++it; + + if(m_clip[3]) + m_clip[3]->deref(); + m_clip[3] = SVGSVGElementImpl::createSVGLength(); + + if(*it != "auto") + m_clip[3]->setValueAsString(*it); +} + +QRect SVGSVGElementImpl::clip() +{ + // Get viewport in user coordinates. + QRect v(0, 0, m_viewport->qrect().width(), m_viewport->qrect().height()); + + SVGMatrixImpl *ctm = getCTM(); + QRect r = ctm->qmatrix().invert().mapRect(v); + ctm->deref(); + + if(m_clip[0]) + r.setTop(static_cast(r.top() + m_clip[0]->value())); + if(m_clip[1]) + r.setRight(static_cast(r.right() - m_clip[1]->value())); + if(m_clip[2]) + r.setBottom(static_cast(r.bottom() - m_clip[2]->value())); + if(m_clip[3]) + r.setLeft(static_cast(r.left() + m_clip[3]->value())); + + return r; +} + +void SVGSVGElementImpl::setRootParentScreenCTM(SVGMatrixImpl *screenCTM) +{ + if(m_rootParentScreenCTM != 0) + m_rootParentScreenCTM->deref(); + + m_rootParentScreenCTM = screenCTM; + screenCTM->ref(); +} + +bool SVGSVGElementImpl::prepareMouseEvent(const QPoint &p, const QPoint &a, SVGMouseEventImpl *mev) +{ + // mop: central bool var which turns to true once the current "mouseover" element has been found + bool ret = false, dorerender = false; + SVGElementImpl *elem = 0; + + SVGMatrixImpl *ctm = getCTM(); + QPoint userA = ctm->qmatrix().invert().map(a); + ctm->deref(); + + // Just check the lastTarget once (mop) + if(ownerDoc()->lastTarget()) + { + elem = ownerDoc()->lastTarget(); + ret = elem->prepareMouseEvent(p, userA, mev); + + // mop: only proceed if element is not the current element anymore. rest is done in the lower part + if(!ret) + { + if(elem->hasEventListener(SVGEvent::MOUSEOUT_EVENT, false)) + { + dorerender = true; + elem->setMouseOver(false); + elem->dispatchMouseEvent(SVGEvent::MOUSEOUT_EVENT, true, true, 0, mev->screenX(), mev->screenY(), mev->clientX(), mev->clientY(), mev->ctrlKey(), mev->altKey(), mev->shiftKey(), mev->metaKey(), mev->button(), elem); + } + + if(elem->hasEventListener(SVGEvent::DOMFOCUSOUT_EVENT, false) && elem->focus()) + { + dorerender = true; + elem->setFocus(false); + elem->dispatchEvent(SVGEvent::DOMFOCUSOUT_EVENT, true, true); + } + + // mop: unset last target once we left it + ownerDoc()->setLastTarget(0); + } + } + + // mop: DAMN...logic doesn't work :( + // we cant use the results of the above check because something like this + // _________ + // | ____ | + // ||____| | + // |_________| + // + // wouldn't work because even if the mousepointer would be in the inner rect it would still be inside the bbox + // of the outer (assuming that the outer is the lastTarget). :( + ret = false; + + // mop: just check for a node until the element where the mouse is over is found + // mop: "ret" can be set from the above stuff too... + // find the element here and do the event stuff in the lower part..much cleaner + CanvasItemList hits = ownerDoc()->canvas()->collisions(p, true); + for(CanvasItemList::Iterator it = hits.begin(); it != hits.end(); ++it) + { + elem = (*it)->element(); + if(elem) + { + // Check if mouse is over a certain shape... + // mop: once an element has been found check eventlisteners and leave immediately + ret = elem->prepareMouseEvent(p, userA, mev); + if(ret) break; + } + } + + // mop: has an element been found? + if(ret) + { + int events = mev->target()->getEventListeners(false); + + // Dispatch mousemove, mousedown, mouseup and mouseclick events + bool cancel = (mev->id() != SVGEvent::MOUSEMOVE_EVENT); + + if(events & 1 << mev->id()) + { + mev->target()->dispatchMouseEvent(mev->id(), true, cancel, 0, mev->screenX(), mev->screenY(), mev->clientX(), mev->clientY(), mev->ctrlKey(), mev->altKey(), mev->shiftKey(), mev->metaKey(), mev->button(), elem); + dorerender = true; // mop: if it has the event then rerender + } + + // If a mouse "moves" over a shape, it's also "over" the shape + if(mev->id() == SVGEvent::MOUSEMOVE_EVENT) + { + mev->target()->setMouseOver(true); + if(events & 1 << SVGEvent::MOUSEOVER_EVENT) + { + mev->target()->dispatchMouseEvent(SVGEvent::MOUSEOVER_EVENT, true, cancel, 0, mev->screenX(), mev->screenY(), mev->clientX(), mev->clientY(), mev->ctrlKey(), mev->altKey(), mev->shiftKey(), mev->metaKey(), mev->button(), elem); + dorerender = true; + } + + } + + // Also send an domactivate + focusin event on mouseup + bool dolinktest = true; + if(mev->id() == SVGEvent::MOUSEUP_EVENT) + { + mev->target()->setFocus(true); + + if(events & 1 << SVGEvent::CLICK_EVENT) + { + dolinktest = mev->target()->dispatchEvent(SVGEvent::CLICK_EVENT, true, true); + dorerender = true; + } + + if(events & 1 << SVGEvent::DOMACTIVATE_EVENT) + { + mev->target()->dispatchEvent(SVGEvent::DOMACTIVATE_EVENT, true, true); + dorerender = true; + } + + if(events & 1 << SVGEvent::DOMFOCUSIN_EVENT) + { + mev->target()->dispatchEvent(SVGEvent::DOMFOCUSIN_EVENT, true, true); + dorerender = true; + } + } + + // Hyperlink support + SVGAElementImpl* link=0; + if(dolinktest && !mev->defaultPrevented()) + { + link = SVGAElementImpl::getLink(elem); + if(link) + { + mev->setURL(link->href()->baseVal()); + emit ownerDoc()->gotURL(link->target()->baseVal().string()); + } + } + + // The mouse is over a shape, so we have a target..we need to register that for a mouseout + ownerDoc()->setLastTarget(mev->target()); + } + + // mop: all events may trigger changed style, add elements etc. this is definately needed :( + if(dorerender) + ownerDoc()->rerender(); + + return dorerender; // mop: some kind of event has been found and executed +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGSVGElementImpl::s_hashTable 23 + x SVGSVGElementImpl::X DontDelete|ReadOnly + y SVGSVGElementImpl::Y DontDelete|ReadOnly + width SVGSVGElementImpl::Width DontDelete|ReadOnly + height SVGSVGElementImpl::Height DontDelete|ReadOnly + viewport SVGSVGElementImpl::Viewport DontDelete|ReadOnly + contentScriptType SVGSVGElementImpl::ContentScriptType DontDelete + contentStyleType SVGSVGElementImpl::ContentStyleType DontDelete + pixelUnitToMillimeterX SVGSVGElementImpl::PixelUnitToMillimeterX DontDelete|ReadOnly + pixelUnitToMillimeterY SVGSVGElementImpl::PixelUnitToMillimeterY DontDelete|ReadOnly + screenPixelToMillimeterX SVGSVGElementImpl::ScreenPixelToMillimeterX DontDelete|ReadOnly + screenPixelToMillimeterY SVGSVGElementImpl::ScreenPixelToMillimeterY DontDelete|ReadOnly + useCurrentView SVGSVGElementImpl::UseCurrentView DontDelete + currentScale SVGSVGElementImpl::CurrentScale DontDelete + currentTranslate SVGSVGElementImpl::CurrentTranslate DontDelete|ReadOnly + onunload SVGSVGElementImpl::OnUnload DontDelete + onerror SVGSVGElementImpl::OnError DontDelete + onresize SVGSVGElementImpl::OnResize DontDelete + onzoom SVGSVGElementImpl::OnZoom DontDelete + onscroll SVGSVGElementImpl::OnScroll DontDelete +@end +@namespace KSVG +@begin SVGSVGElementImplProto::s_hashTable 29 + createSVGNumber SVGSVGElementImpl::CreateSVGNumber DontDelete|Function 0 + createSVGLength SVGSVGElementImpl::CreateSVGLength DontDelete|Function 0 + createSVGAngle SVGSVGElementImpl::CreateSVGAngle DontDelete|Function 0 + createSVGPoint SVGSVGElementImpl::CreateSVGPoint DontDelete|Function 0 + createSVGMatrix SVGSVGElementImpl::CreateSVGMatrix DontDelete|Function 0 + createSVGRect SVGSVGElementImpl::CreateSVGRect DontDelete|Function 0 + createSVGTransform SVGSVGElementImpl::CreateSVGTransform DontDelete|Function 0 + createSVGTransformFromMatrix SVGSVGElementImpl::CreateSVGTransformFromMatrix DontDelete|Function 1 + suspendRedraw SVGSVGElementImpl::SuspendRedraw DontDelete|Function 1 + unsuspendRedraw SVGSVGElementImpl::UnsuspendRedraw DontDelete|Function 1 + unsuspendRedrawAll SVGSVGElementImpl::UnsuspendRedrawAll DontDelete|Function 0 + forceRedraw SVGSVGElementImpl::ForceRedraw DontDelete|Function 0 + pauseAnimations SVGSVGElementImpl::PauseAnimations DontDelete|Function 0 + unpauseAnimations SVGSVGElementImpl::UnpauseAnimations DontDelete|Function 0 + animationsPaused SVGSVGElementImpl::AnimationsPaused DontDelete|Function 0 + getCurrentTime SVGSVGElementImpl::GetCurrentTime DontDelete|Function 0 + setCurrentTime SVGSVGElementImpl::SetCurrentTime DontDelete|Function 1 + getIntersectionList SVGSVGElementImpl::GetIntersectionList DontDelete|Function 2 + getEnclosureList SVGSVGElementImpl::GetEnclosureList DontDelete|Function 2 + checkIntersection SVGSVGElementImpl::CheckIntersection DontDelete|Function 2 + checkEnclosure SVGSVGElementImpl::CheckEnclosure DontDelete|Function 2 + deselectAll SVGSVGElementImpl::DeselectAll DontDelete|Function 0 + getElementById SVGSVGElementImpl::GetElementById DontDelete|Function 1 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGSVGElement", SVGSVGElementImplProto, SVGSVGElementImplProtoFunc) + +Value SVGSVGElementImpl::getValueProperty(ExecState *exec, int token) const +{ + KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case X: + if(!attributeMode) + return m_x->cache(exec); + else + return Number(m_x->baseVal()->value()); + case Y: + if(!attributeMode) + return m_y->cache(exec); + else + return Number(m_y->baseVal()->value()); + case Width: + if(!attributeMode) + return m_width->cache(exec); + else + return Number(m_width->baseVal()->value()); + case Height: + if(!attributeMode) + return m_height->cache(exec); + else + return Number(m_height->baseVal()->value()); + case Viewport: + return m_viewport->cache(exec); + case ContentScriptType: + return String(contentScriptType().string()); + case ContentStyleType: + return String(contentStyleType().string()); + case PixelUnitToMillimeterX: + return Number(pixelUnitToMillimeterX()); + case PixelUnitToMillimeterY: + return Number(pixelUnitToMillimeterY()); + case ScreenPixelToMillimeterX: + return Number(screenPixelToMillimeterX()); + case ScreenPixelToMillimeterY: + return Number(screenPixelToMillimeterY()); + case UseCurrentView: + return Boolean(useCurrentView()); + case CurrentScale: + return Number(currentScale()); + case CurrentTranslate: + return m_currentTranslate->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGSVGElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case ContentScriptType: + setContentScriptType(value.toString(exec).string()); + break; + case ContentStyleType: + setContentStyleType(value.toString(exec).string()); + break; + case CurrentScale: + m_currentScale = value.toNumber(exec); + break; + case X: + x()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case Y: + y()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case Width: + width()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case Height: + height()->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case OnUnload: + // Spec: only applicable to outermost 'svg' elements + if(isRootElement()) + setEventListener(SVGEvent::UNLOAD_EVENT, ownerDoc()->createEventListener(value.toString(exec).qstring())); + break; + case OnError: + setEventListener(SVGEvent::ERROR_EVENT, ownerDoc()->createEventListener(value.toString(exec).qstring())); + break; + case OnResize: + // Spec: only applicable to outermost 'svg' elements + if(isRootElement()) + setEventListener(SVGEvent::RESIZE_EVENT, ownerDoc()->createEventListener(value.toString(exec).qstring())); + break; + case OnZoom: + // Spec: only applicable to outermost 'svg' elements + if(isRootElement()) + setEventListener(SVGEvent::ZOOM_EVENT, ownerDoc()->createEventListener(value.toString(exec).qstring())); + break; + case OnScroll: + // Spec: only applicable to outermost 'svg' elements + if(isRootElement()) + setEventListener(SVGEvent::SCROLL_EVENT, ownerDoc()->createEventListener(value.toString(exec).qstring())); + break; + default: + kdWarning() << k_funcinfo << "unhandled token " << token << endl; + } +} + +Value SVGSVGElementImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGSVGElementImpl) + + switch(id) + { + case SVGSVGElementImpl::CreateSVGNumber: + return obj->createSVGNumber()->cache(exec); + case SVGSVGElementImpl::CreateSVGLength: + return obj->createSVGLength()->cache(exec); + case SVGSVGElementImpl::CreateSVGAngle: + return obj->createSVGAngle()->cache(exec); + case SVGSVGElementImpl::CreateSVGPoint: + return obj->createSVGPoint()->cache(exec); + case SVGSVGElementImpl::CreateSVGMatrix: + return obj->createSVGMatrix()->cache(exec); + case SVGSVGElementImpl::CreateSVGRect: + return obj->createSVGRect()->cache(exec); + case SVGSVGElementImpl::CreateSVGTransform: + return obj->createSVGTransform()->cache(exec); + case SVGSVGElementImpl::CreateSVGTransformFromMatrix: + return obj->createSVGTransformFromMatrix(static_cast *>(args[0].imp())->impl())->cache(exec); + case SVGSVGElementImpl::GetElementById: + { + // Keep in sync with SVGDocumentImpl's version. + Value ret; + + SVGElementImpl *element = obj->getElementById(args[0].toString(exec).string()); + + if(element) + ret = getDOMNode(exec, *element); + else + { + element = obj->ownerDoc()->recursiveSearch(*(obj->ownerDoc()), args[0].toString(exec).string()); + if(!element) + return Null(); + + ret = getDOMNode(exec, *element); + } + + return ret; + } + case SVGSVGElementImpl::GetCurrentTime: + return Number(obj->getCurrentTime()); + case SVGSVGElementImpl::SetCurrentTime: + obj->setCurrentTime(args[0].toNumber(exec)); + return Undefined(); + case SVGSVGElementImpl::DeselectAll: + obj->deSelectAll(); + return Undefined(); + case SVGSVGElementImpl::PauseAnimations: + obj->pauseAnimations(); + return Undefined(); + case SVGSVGElementImpl::UnpauseAnimations: + obj->unpauseAnimations(); + return Undefined(); + case SVGSVGElementImpl::AnimationsPaused: + return Boolean(obj->animationsPaused()); + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGSVGElementImpl.h b/ksvg/impl/SVGSVGElementImpl.h new file mode 100644 index 00000000..2405458e --- /dev/null +++ b/ksvg/impl/SVGSVGElementImpl.h @@ -0,0 +1,198 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGSVGElementImpl_H +#define SVGSVGElementImpl_H + +#include + +#include + +#include "SVGTestsImpl.h" +#include "SVGElementImpl.h" +#include "SVGStylableImpl.h" +#include "SVGLocatableImpl.h" +#include "SVGContainerImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGZoomAndPanImpl.h" +#include "SVGFitToViewBoxImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGPointImpl; +class SVGAngleImpl; +class SVGNumberImpl; +class SVGLengthImpl; +class SVGMatrixImpl; +class SVGViewSpecImpl; +class SVGTransformImpl; +class SVGAnimatedLengthImpl; +class SVGAnimationElementImpl; +class SVGSVGElementImpl : public SVGContainerImpl, + public SVGTestsImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGLocatableImpl, + public SVGFitToViewBoxImpl, + public SVGZoomAndPanImpl +{ +public: + SVGSVGElementImpl(DOM::ElementImpl *); + virtual ~SVGSVGElementImpl(); + + bool isRootElement() const; + + SVGAnimatedLengthImpl *x(); + SVGAnimatedLengthImpl *y(); + SVGAnimatedLengthImpl *width(); + SVGAnimatedLengthImpl *height(); + + void setContentScriptType(const DOM::DOMString &); + DOM::DOMString contentScriptType() const; + + void setContentStyleType(const DOM::DOMString &); + DOM::DOMString contentStyleType() const; + + SVGRectImpl *viewport(); + SVGRectImpl *getBBox(); + + float pixelUnitToMillimeterX() const; + float pixelUnitToMillimeterY() const; + float screenPixelToMillimeterX() const; + float screenPixelToMillimeterY() const; + + void setUseCurrentView(bool); + bool useCurrentView() const; + SVGViewSpecImpl *currentView() const; + + void setCurrentScale(float); + float currentScale() const; + + SVGPointImpl *currentTranslate(); + void setCurrentTranslate(const QPoint &p); + + unsigned long suspendRedraw(unsigned long max_wait_milliseconds); + void unsuspendRedraw(unsigned long suspend_handle_id); + void unsuspendRedrawAll(); + void forceRedraw(); + + void pauseAnimations(); + void unpauseAnimations(); + + bool animationsPaused(); + + float getCurrentTime() const; + void setCurrentTime(float seconds); + DOM::NodeList getIntersectionList(SVGRectImpl *rect, SVGElementImpl *referenceElement); + DOM::NodeList getEnclosureList(SVGRectImpl *rect, SVGElementImpl *referenceElement); + bool checkIntersection(SVGElementImpl *element, SVGRectImpl *rect); + bool checkEnclosure(SVGElementImpl *element, SVGRectImpl *rect); + void deSelectAll(); + + // Static creators for svg primitives + static SVGNumberImpl *createSVGNumber(); + static SVGLengthImpl *createSVGLength(); + static SVGAngleImpl *createSVGAngle(); + static SVGPointImpl *createSVGPoint(); + static SVGMatrixImpl *createSVGMatrix(); + static SVGRectImpl *createSVGRect(); + static SVGTransformImpl *createSVGTransform(); + static SVGTransformImpl *createSVGTransformFromMatrix(SVGMatrixImpl *matrix); + + SVGElementImpl *getElementById(const DOM::DOMString &elementId); + void addToIdMap(const QString &id, SVGElementImpl *obj); + + virtual SVGMatrixImpl *getCTM(); + virtual const SVGMatrixImpl *localMatrix(); + + void setAttributes(); + + bool prepareMouseEvent(const QPoint &p, const QPoint &a, SVGMouseEventImpl *event); + + virtual bool isContainer() const { return true; } + + virtual void setClip(const QString &clip); + virtual QRect clip(); + + void setRootParentScreenCTM(SVGMatrixImpl *screenCTM); + +private: + SVGAnimatedLengthImpl *m_x; + SVGAnimatedLengthImpl *m_y; + SVGAnimatedLengthImpl *m_width; + SVGAnimatedLengthImpl *m_height; + + SVGRectImpl *m_viewport; + + bool m_useCurrentView; + + SVGViewSpecImpl *m_currentView; + + float m_currentScale; + + SVGPointImpl *m_currentTranslate; + + SVGLengthImpl *m_clip[4]; + + QMap m_map; + + // Transformation provided by the 'parent' of the outermost svg element + SVGMatrixImpl *m_rootParentScreenCTM; + + SVGMatrixImpl *m_localMatrix; + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + X, Y, Width, Height, ContentScriptType, ContentStyleType, Viewport, + PixelUnitToMillimeterX, PixelUnitToMillimeterY, ScreenPixelToMillimeterX, ScreenPixelToMillimeterY, + UseCurrentView, CurrentScale, CurrentTranslate, OnUnload, OnError, OnResize, OnZoom, OnScroll, + // Functions + CreateSVGNumber, CreateSVGLength, CreateSVGAngle, CreateSVGPoint, CreateSVGMatrix, CreateSVGRect, CreateSVGTransform, + CreateSVGTransformFromMatrix, SuspendRedraw, UnsuspendRedraw, UnsuspendRedrawAll, ForceRedraw, + PauseAnimations, UnpauseAnimations, AnimationsPaused, GetCurrentTime, SetCurrentTime, + GetIntersectionList, GetEnclosureList, CheckIntersection, CheckEnclosure, + DeselectAll, GetElementById + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGSVGElementImpl, "svg") + +} + +KSVG_DEFINE_PROTOTYPE(SVGSVGElementImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGSVGElementImplProtoFunc, SVGSVGElementImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGScriptElementImpl.cc b/ksvg/impl/SVGScriptElementImpl.cc new file mode 100644 index 00000000..9a211425 --- /dev/null +++ b/ksvg/impl/SVGScriptElementImpl.cc @@ -0,0 +1,185 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include +#include +#include + +#include "SVGDocumentImpl.h" +#include "SVGAnimatedStringImpl.h" +#include "SVGScriptElementImpl.moc" + +using namespace KSVG; + +#include "SVGScriptElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGScriptElementImpl::SVGScriptElementImpl(DOM::ElementImpl *impl) : QObject(), SVGElementImpl(impl), SVGURIReferenceImpl(), SVGExternalResourcesRequiredImpl() +{ + KSVG_EMPTY_FLAGS + + m_job = 0; + m_added = false; +} + +SVGScriptElementImpl::~SVGScriptElementImpl() +{ +} + +void SVGScriptElementImpl::setType(const DOM::DOMString &type) +{ + setAttribute("type", type); +} + +DOM::DOMString SVGScriptElementImpl::type() const +{ + return getAttribute("type"); +} + +void SVGScriptElementImpl::setAttributes() +{ + SVGElementImpl::setAttributes(); + + // Spec: provide a default type + if(KSVG_TOKEN_NOT_PARSED(Type)) + KSVG_SET_ALT_ATTRIBUTE(Type, "text/ecmascript") + + // Remote downloading + QString href = m_href->baseVal().string(); + + if(!href.isEmpty()) + { + KURL url(ownerDoc()->baseUrl(), href); + + if(m_job == 0) + m_job = KIO::get(url, false, false); + + connect(m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this, SLOT(slotData(KIO::Job *, const QByteArray &))); + connect(m_job, SIGNAL(result(KIO::Job *)), this, SLOT(slotResult(KIO::Job *))); + } +} + +void SVGScriptElementImpl::slotData(KIO::Job *, const QByteArray &data) +{ + QDataStream dataStream(m_data, IO_WriteOnly | IO_Append); + dataStream.writeRawBytes(data.data(), data.size()); +} + +void SVGScriptElementImpl::slotResult(KIO::Job *) +{ + m_job = 0; + + // Append a NULL terminator so we don't die + m_data.resize(m_data.size() + 1); + m_data[m_data.size() - 1] = '\0'; + + QBuffer buf(m_data); + QIODevice *dev = KFilterDev::device(&buf, "application/x-gzip", false); + QByteArray contents; + if(dev->open(IO_ReadOnly)) + contents = dev->readAll(); + delete dev; + m_text = QString::fromUtf8(contents.data()); + + m_data.resize(0); +} + +bool SVGScriptElementImpl::canExecuteScript() +{ + if(!m_added) + { + m_added = true; + m_text += collectText(); + } + + if(m_text.isEmpty() && !getAttribute("href").isNull() && !getAttribute("href").string().isEmpty()) + return false; + + return true; +} + +bool SVGScriptElementImpl::executeScript(DOM::Node node) +{ + return SVGScriptElementImpl::executeScript(node, ownerDoc(), m_text); +} + +bool SVGScriptElementImpl::executeScript(DOM::Node node, SVGDocumentImpl *document, const QString &text) +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "SVGScriptElementImpl::executeScript n=" << node.nodeName().string().latin1() << "(" << (node.isNull() ? 0 : node.nodeType()) << ") " << text << endl; +#endif + KSVGEcma *ecmaEngine = document->ecmaEngine(); + + if(!ecmaEngine->initialized()) + ecmaEngine->setup(); + + KJS::Value thisNode = node.isNull() ? ecmaEngine->globalObject() : getDOMNode(ecmaEngine->globalExec(), node); + + KJS::UString code(text); + KJS::Completion comp = ecmaEngine->evaluate(code, thisNode); + + // TODO: If that's needed find a better solution which + // doesn't cause endless loops if the func, specified in + // onerror="..." isn't yet available + // onerror support +// if(comp.complType() == Throw) +// document->rootElement()->dispatchEvent(SVGEventImpl::ERROR_EVENT, false, false); + + return (comp.complType() == KJS::Normal) || (comp.complType() == KJS::ReturnValue); +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGScriptElementImpl::s_hashTable 2 + type SVGScriptElementImpl::Type DontDelete +@end +*/ + +Value SVGScriptElementImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case Type: + return String(type()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGScriptElementImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int) +{ + switch(token) + { + case Type: + setType(value.toString(exec).string()); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGScriptElementImpl.h b/ksvg/impl/SVGScriptElementImpl.h new file mode 100644 index 00000000..95affee2 --- /dev/null +++ b/ksvg/impl/SVGScriptElementImpl.h @@ -0,0 +1,90 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGScriptElementImpl_H +#define SVGScriptElementImpl_H + +#include + +#include + +#include + +#include "SVGElementImpl.h" +#include "SVGURIReferenceImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGScriptElementImpl : public QObject, + public SVGElementImpl, + public SVGURIReferenceImpl, + public SVGExternalResourcesRequiredImpl +{ +Q_OBJECT +public: + SVGScriptElementImpl(DOM::ElementImpl *); + virtual ~SVGScriptElementImpl(); + + void setType(const DOM::DOMString &type); + DOM::DOMString type() const; + + virtual void setAttributes(); + + bool canExecuteScript(); + bool executeScript(DOM::Node node); + + static bool executeScript(DOM::Node node, SVGDocumentImpl *document, const QString &text); + +private slots: + void slotData(KIO::Job *, const QByteArray &); + void slotResult(KIO::Job *); + +private: + KIO::TransferJob *m_job; + QByteArray m_data; + QString m_text; + bool m_added; + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + Type + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGScriptElementImpl, "script") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGSetElementImpl.cc b/ksvg/impl/SVGSetElementImpl.cc new file mode 100644 index 00000000..66460db9 --- /dev/null +++ b/ksvg/impl/SVGSetElementImpl.cc @@ -0,0 +1,48 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGDocumentImpl.h" +#include "SVGSetElementImpl.h" + +using namespace KSVG; + +SVGSetElementImpl::SVGSetElementImpl(DOM::ElementImpl *impl) : SVGAnimationElementImpl(impl) +{ +} + +SVGSetElementImpl::~SVGSetElementImpl() +{ +} + +void SVGSetElementImpl::setAttributes() +{ + SVGAnimationElementImpl::setAttributes(); + + // Always create singleShot timers when used by (Niko) + // Those are automatically deleted by the scheduler after timeout. + ownerDoc()->timeScheduler()->addTimer(this, int(getStartTime() * 1000.0)); +} + +void SVGSetElementImpl::handleTimerEvent() +{ + applyAttribute(getAttributeName(), getTo()); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGSetElementImpl.h b/ksvg/impl/SVGSetElementImpl.h new file mode 100644 index 00000000..ab9f5ec5 --- /dev/null +++ b/ksvg/impl/SVGSetElementImpl.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGSetElementImpl_H +#define SVGSetElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGAnimationElementImpl.h" + +class QTimer; + +namespace KSVG +{ + +class SVGSetElementImpl : public SVGAnimationElementImpl +{ +public: + SVGSetElementImpl(DOM::ElementImpl *); + virtual ~SVGSetElementImpl(); + + virtual void handleTimerEvent(); + virtual void setAttributes(); + +public: + KSVG_BRIDGE + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +KSVG_REGISTER_ELEMENT(SVGSetElementImpl, "set") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGShapeImpl.cc b/ksvg/impl/SVGShapeImpl.cc new file mode 100644 index 00000000..68e89aaa --- /dev/null +++ b/ksvg/impl/SVGShapeImpl.cc @@ -0,0 +1,162 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGPaint.h" + +#include "SVGRectImpl.h" +#include "SVGEventImpl.h" +#include "SVGShapeImpl.h" +#include "SVGPaintImpl.h" +#include "SVGMatrixImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGClipPathElementImpl.h" +#include "SVGAnimatedLengthListImpl.h" + +#include "CanvasItem.h" +#include "KSVGCanvas.h" + +using namespace KSVG; + +SVGShapeImpl::SVGShapeImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl) +{ + m_item = 0; +} + +SVGShapeImpl::~SVGShapeImpl() +{ + if(hasChildNodes()) + { + DOM::Node node = firstChild(); + for(; !node.isNull(); node = node.nextSibling()) + { + SVGShapeImpl *rend = dynamic_cast(ownerDoc()->getElementFromHandle(node.handle())); + if(rend) + rend->deref(); + } + } +} + +bool SVGShapeImpl::directRender() +{ + SVGShapeImpl *parent = dynamic_cast(ownerDoc()->getElementFromHandle(parentNode().handle())); + if(parent) + return parent->directRender(); + else + return true; +} + +SVGRectImpl *SVGShapeImpl::getBBox() +{ + SVGRectImpl *rect = SVGSVGElementImpl::createSVGRect(); + return rect; +} + +SVGRectImpl *SVGShapeImpl::getBBoxInternal() +{ + SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect(); + if(m_item) + { + QRect r = m_item->bbox(); + ret->setX(r.x()); + ret->setY(r.y()); + ret->setWidth(r.width()); + ret->setHeight(r.height()); + } + return ret; +} + +bool SVGShapeImpl::prepareMouseEvent(const QPoint &p, const QPoint &, SVGMouseEventImpl *mev) +{ + // TODO : pointer-events should be stored here, not in SVGStylableImpl. + SVGStylableImpl *style = dynamic_cast(this); + if(!style || style->getPointerEvents() == PE_NONE) + return false; + bool testFill = false; + bool testStroke = false; + switch(style->getPointerEvents()) + { + case PE_VISIBLE: testFill = testStroke = style->getVisible(); break; + case PE_VISIBLE_PAINTED: testStroke = style->getVisible() && style->isStroked(); + case PE_VISIBLE_FILL: testFill = style->getVisible() && style->isFilled(); break; + case PE_VISIBLE_STROKE: testStroke = style->getVisible() && style->isStroked(); break; + case PE_PAINTED: testStroke = style->isStroked(); + case PE_FILL: testFill = style->isFilled(); break; + case PE_STROKE: testStroke = style->isStroked(); break; + case PE_ALL: + default: testFill = testStroke = true; + }; + + if(testFill || testStroke) + { + if((testFill && m_item->fillContains(p)) || (testStroke && m_item->strokeContains(p))) + { + mev->setTarget(this); + return true; + } + } + + return false; +} + +void SVGShapeImpl::update(CanvasItemUpdate reason, int param1, int param2) +{ + if(m_item) + m_item->update(reason, param1, param2); +} + +void SVGShapeImpl::invalidate(KSVGCanvas *c, bool recalc) +{ + if(m_item && c) + c->invalidate(m_item, recalc); +} + +void SVGShapeImpl::setReferenced(bool referenced) +{ + if(m_item) + m_item->setReferenced(referenced); +} + +void SVGShapeImpl::draw() +{ + if(m_item) + m_item->draw(); +} + +void SVGShapeImpl::blit(KSVGCanvas *c) +{ + SVGRectImpl *rect = getBBoxInternal(); + c->blit(rect->qrect(), true); + rect->deref(); +} + +void SVGShapeImpl::removeItem(KSVGCanvas *c) +{ + if(m_item && c) + { + c->removeItem(m_item); + m_item = 0; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGShapeImpl.h b/ksvg/impl/SVGShapeImpl.h new file mode 100644 index 00000000..ae183251 --- /dev/null +++ b/ksvg/impl/SVGShapeImpl.h @@ -0,0 +1,73 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGShapeImpl_H +#define SVGShapeImpl_H + +#include "SVGElementImpl.h" +#include "CanvasItem.h" + +class QPoint; + +namespace KSVG +{ + +class KSVGCanvas; + +class SVGRectImpl; +class SVGMouseEventImpl; + +class SVGShapeImpl : public SVGElementImpl +{ +public: + SVGShapeImpl(DOM::ElementImpl *); + virtual ~SVGShapeImpl(); + + virtual SVGRectImpl *getBBox(); + virtual SVGRectImpl *getBBoxInternal(); + + virtual bool prepareMouseEvent(const QPoint &p, const QPoint &a, SVGMouseEventImpl *mev); + + virtual bool directRender(); + virtual bool isContainer() const { return false; } + + virtual void update(CanvasItemUpdate reason, int param1 = 0, int param2 = 0); + virtual void invalidate(KSVGCanvas *c, bool recalc); + virtual void setReferenced(bool referenced); + virtual void draw(); + virtual void blit(KSVGCanvas *); + + virtual void removeItem(KSVGCanvas *c); + + CanvasItem *item() { return m_item; } + +protected: + CanvasItem *m_item; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGStopElementImpl.cc b/ksvg/impl/SVGStopElementImpl.cc new file mode 100644 index 00000000..09761232 --- /dev/null +++ b/ksvg/impl/SVGStopElementImpl.cc @@ -0,0 +1,125 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include "SVGLengthImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGStopElementImpl.h" +#include "SVGAnimatedNumberImpl.h" +#include "SVGColorImpl.h" + +using namespace KSVG; + +#include "SVGStopElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGStopElementImpl::SVGStopElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGStylableImpl(this) +{ + KSVG_EMPTY_FLAGS + + m_offset = new SVGAnimatedNumberImpl(); + m_offset->ref(); + + m_stopOpacity = 1; +} + +SVGStopElementImpl::~SVGStopElementImpl() +{ + if(m_offset) + m_offset->deref(); +} + +SVGAnimatedNumberImpl *SVGStopElementImpl::offset() const +{ + return m_offset; +} + +float SVGStopElementImpl::stopOpacity() const +{ + return m_stopOpacity; +} + + +/* +@namespace KSVG +@begin SVGStopElementImpl::s_hashTable 3 + offset SVGStopElementImpl::Offset DontDelete|ReadOnly + stop-opacity SVGStopElementImpl::StopOpacity DontDelete|ReadOnly +@end +*/ + +Value SVGStopElementImpl::getValueProperty(ExecState *exec, int token) const +{ + KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case Offset: + if(!attributeMode) + return m_offset->cache(exec); + else + return Number(m_offset->baseVal()); + case StopOpacity: + if(!attributeMode) + return Undefined(); + else + return Number(m_stopOpacity); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGStopElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case Offset: + float temp; + SVGLengthImpl::convertPercentageToFloat(value.toString(exec).qstring(), temp); + offset()->setBaseVal(temp); + break; + case StopOpacity: + { + SVGLengthImpl::convertPercentageToFloat(value.toString(exec).qstring(), m_stopOpacity); + break; + } + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +void SVGStopElementImpl::setAttributes() +{ + SVGElementImpl::setAttributes(); + + // Spec: if not set, specifiy 0 + if(KSVG_TOKEN_NOT_PARSED(Offset)) + KSVG_SET_ALT_ATTRIBUTE(Offset, "0") +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGStopElementImpl.h b/ksvg/impl/SVGStopElementImpl.h new file mode 100644 index 00000000..369b7867 --- /dev/null +++ b/ksvg/impl/SVGStopElementImpl.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGStopElementImpl_H +#define SVGStopElementImpl_H + +#include "SVGElementImpl.h" +#include "SVGStylableImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGAnimatedNumberImpl; +class SVGStopElementImpl : public SVGElementImpl, + public SVGStylableImpl +{ +public: + SVGStopElementImpl(DOM::ElementImpl *); + virtual ~SVGStopElementImpl(); + + SVGAnimatedNumberImpl *offset() const; + float stopOpacity() const; + + virtual void setAttributes(); + +private: + SVGAnimatedNumberImpl *m_offset; + float m_stopOpacity; + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + Offset, StopOpacity + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGStopElementImpl, "stop") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGStringListImpl.cc b/ksvg/impl/SVGStringListImpl.cc new file mode 100644 index 00000000..b70adfdd --- /dev/null +++ b/ksvg/impl/SVGStringListImpl.cc @@ -0,0 +1,93 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGStringListImpl.h" + +using namespace KSVG; + +#include "SVGStringListImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +// Ecma stuff + +/* +@namespace KSVG +@begin SharedString::s_hashTable 2 + dummy SharedString::Dummy DontDelete|ReadOnly +@end +*/ + +/* +@namespace KSVG +@begin SVGStringListImpl::s_hashTable 2 + numberOfItems SVGListDefs::NumberOfItems DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGStringListImplProto::s_hashTable 11 + getItem SVGListDefs::GetItem DontDelete|Function 1 + removeItem SVGListDefs::RemoveItem DontDelete|Function 1 + appendItem SVGListDefs::AppendItem DontDelete|Function 1 + initialize SVGListDefs::Initialize DontDelete|Function 1 + insertItemBefore SVGListDefs::InsertItemBefore DontDelete|Function 2 + replaceItem SVGListDefs::ReplaceItem DontDelete|Function 2 + clear SVGListDefs::Clear DontDelete|Function 0 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGStringList", SVGStringListImplProto, SVGStringListImplProtoFunc) + +Value SVGStringListImpl::getValueProperty(ExecState *exec, int token) const +{ + return SVGList::getValueProperty(exec, token); +} + +Value SVGStringListImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGStringListImpl) + + return obj->call(exec, static_cast *>(obj), args, id); +} + +QString SVGStringListImpl::join(const QString &seperator) const +{ + SVGStringListImpl *self = const_cast(this); + + QString result; + + if(!self->getItem(0)) + return result; + else + result += self->getItem(0)->string(); + + for(unsigned int i = 1; i <= numberOfItems(); i++) + { + DOM::DOMString *string = self->getItem(i); + + if(string) + result += seperator + string->string(); + } + + return result; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGStringListImpl.h b/ksvg/impl/SVGStringListImpl.h new file mode 100644 index 00000000..7f69a3c9 --- /dev/null +++ b/ksvg/impl/SVGStringListImpl.h @@ -0,0 +1,82 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGStringListImpl_H +#define SVGStringListImpl_H + +#include + +#include "SVGList.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SharedString : public DOM::DomShared, + public DOM::DOMString +{ +public: + SharedString() : DOM::DomShared(), DOM::DOMString() { } + SharedString(const QString &string) : DOM::DomShared(), DOM::DOMString(string) { } + SharedString(const SharedString &string) : DOM::DomShared(), DOM::DOMString(string) { } + SharedString(DOM::DOMString *string) : DOM::DomShared(), DOM::DOMString(string->implementation()) { } + virtual ~SharedString() { } + +public: + KSVG_GET + + enum + { + // Properties + Dummy + }; + + KJS::Value getValueProperty(KJS::ExecState *, int token) const + { + switch(token) + { + case Dummy: + return KJS::Undefined(); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return KJS::Undefined(); + } + } +}; + +class SVGStringListImpl : public SVGList +{ +public: + KSVG_GET + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + + QString join(const QString &seperator) const; +}; + +} + +KSVG_DEFINE_PROTOTYPE(SVGStringListImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGStringListImplProtoFunc, SVGStringListImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGStylableImpl.cc b/ksvg/impl/SVGStylableImpl.cc new file mode 100644 index 00000000..096ebf93 --- /dev/null +++ b/ksvg/impl/SVGStylableImpl.cc @@ -0,0 +1,1309 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include + +#include "CanvasItem.h" +#include "KSVGCanvas.h" + +#include "SVGPaint.h" +#include "SVGColorImpl.h" +#include "SVGPaintImpl.h" +#include "SVGHelperImpl.h" +#include "SVGLengthImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGStylableImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGStringListImpl.h" +#include "SVGImageElementImpl.h" +#include "SVGURIReferenceImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGColorProfileElementImpl.h" +#include "SVGAnimatedLengthListImpl.h" + +using namespace KSVG; + +#include "SVGStylableImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGStylableImpl::SVGStylableImpl(SVGElementImpl *object) : m_object(object) +{ + KSVG_EMPTY_FLAGS + + // View propidx.html, if you want to verify those default values (Niko) + m_flags = SVG_STYLE_FLAG_NONE; + + // Initialize all pointers to 0 + // Important! + m_color = 0; + m_fillColor = 0; + m_stopColor = 0; + m_dashArray = 0; + m_dashOffset = 0; + m_strokeWidth = 0; + m_strokeColor = 0; + m_fontFamily = 0; + + m_fillOpacity = 1; + m_strokeOpacity = 1; + m_opacity = 1; + + // Special case, getFontSize() could be accessed + // _before_ processStyle() is called -> no default + // value for font-size yet -> crash + // SVGLengthImpl access it when parsing em/ex values (Niko) + m_fontSize = -1; +} + +SVGStylableImpl::~SVGStylableImpl() +{ + if(m_strokeWidth) + m_strokeWidth->deref(); + if(m_fontFamily) + m_fontFamily->deref(); + if(m_strokeColor) + m_strokeColor->deref(); + if(m_fillColor) + m_fillColor->deref(); + if(m_color) + m_color->deref(); + if(m_stopColor) + m_stopColor->deref(); + if(m_dashOffset) + m_dashOffset->deref(); + if(m_dashArray) + m_dashArray->deref(); +} + +void SVGStylableImpl::processStyle() +{ + SVGStylableImpl *parentStyle = 0; + if(m_object && m_object->ownerDoc()) + parentStyle = dynamic_cast(m_object->ownerDoc()->getElementFromHandle((*m_object).parentNode().handle())); + + // Spec: default "none" + if(~m_flags & SVG_STYLE_FLAG_STROKE) + { + m_strokeColor = new SVGPaintImpl(m_object); + m_strokeColor->ref(); + + SVGPaintImpl *strokeColor = 0L; + if(parentStyle) + strokeColor = parentStyle->getStrokeColor(); + + if(strokeColor) + *m_strokeColor = *strokeColor; + else + m_strokeColor->setPaint(SVG_PAINTTYPE_NONE); + } + + // Spec: default "black" + if(~m_flags & SVG_STYLE_FLAG_FILL) + { + m_fillColor = new SVGPaintImpl(m_object); + m_fillColor->ref(); + + SVGPaintImpl *fillColor = 0; + if(parentStyle) + fillColor = parentStyle->getFillColor(); + + if(fillColor) + *m_fillColor = *fillColor; + else + m_fillColor->setRGBColor(DOM::DOMString("black")); + } + + // Spec: no real default + if(~m_flags & SVG_STYLE_FLAG_COLOR) + { + m_color = new SVGColorImpl(m_object); + m_color->ref(); + SVGColorImpl *color = 0; + if(parentStyle) + color = parentStyle->getColor(); + + if(color) + *m_color = *color; + } + + // Spec: default sRGB + if(~m_flags & SVG_STYLE_FLAG_COLOR_INTERPOLATION) + { + if(parentStyle) + m_colorInterpolation = parentStyle->getColorInterpolation(); + else + m_colorInterpolation = CI_SRGB; + } + + // Spec: default "1" + if(~m_flags & SVG_STYLE_FLAG_STROKE_WIDTH) + { + m_strokeWidth = new SVGAnimatedLengthImpl(LENGTHMODE_OTHER, m_object); + m_strokeWidth->ref(); + + SVGAnimatedLengthImpl *strokeWidth = 0; + if(parentStyle) + strokeWidth = parentStyle->getStrokeWidth(); + + if(strokeWidth) + *m_strokeWidth = *strokeWidth; + else + m_strokeWidth->baseVal()->setValue(1.0); + } + + // Spec: default "4" + if(~m_flags & SVG_STYLE_FLAG_STROKE_MITER_LIMIT) + { + if(parentStyle) + m_strokeMiterlimit = parentStyle->getStrokeMiterlimit(); + else + m_strokeMiterlimit = 4; + } + + // Spec: default "butt" + if(~m_flags & SVG_STYLE_FLAG_STROKE_LINE_CAP) + { + if(parentStyle) + m_capStyle = parentStyle->getCapStyle(); + else + m_capStyle = PATH_STROKE_CAP_BUTT; + } + + // Spec: default "miter" + if(~m_flags & SVG_STYLE_FLAG_STROKE_LINE_JOIN) + { + if(parentStyle) + m_joinStyle = parentStyle->getJoinStyle(); + else + m_joinStyle = PATH_STROKE_JOIN_MITER; + } + + // Spec: default "auto" + if(~m_flags & SVG_STYLE_FLAG_CURSOR) + { + if(parentStyle) + m_cursor = parentStyle->getCursor(); + else + m_cursor = CURSOR_AUTO; + } + + // Spec: default "visiblePainted" + if(~m_flags & SVG_STYLE_FLAG_POINTER_EVENTS) + { + if(parentStyle) + m_pointerEvents = parentStyle->getPointerEvents(); + else + m_pointerEvents = PE_VISIBLE_PAINTED; + } + + // Spec: default "0" + if(~m_flags & SVG_STYLE_FLAG_STROKE_DASH_OFFSET) + { + m_dashOffset = new SVGAnimatedLengthImpl(LENGTHMODE_OTHER, m_object); + m_dashOffset->ref(); + + SVGAnimatedLengthImpl *dashOffset = 0; + if(parentStyle) + dashOffset = parentStyle->getDashOffset(); + + if(dashOffset) + *m_dashOffset = *dashOffset; + else + m_dashOffset->baseVal()->setValue(0); + } + + // Spec: default "none" -> 0 == empty dash array + if(~m_flags & SVG_STYLE_FLAG_STROKE_DASH_ARRAY) + { + SVGAnimatedLengthListImpl *dashArray = 0; + if(parentStyle) + dashArray = parentStyle->getDashArray(); + + if(dashArray) + { + if (!m_dashArray) + { + m_dashArray = new SVGAnimatedLengthListImpl(); + m_dashArray->ref(); + } + *m_dashArray = *dashArray; + } + else + m_dashArray = 0; + } + + // Spec: default "1" -> 1 == Not opaque + if(~m_flags & SVG_STYLE_FLAG_FILL_OPACITY) + { + if(parentStyle) + m_fillOpacity = parentStyle->getFillOpacity(); + else + m_fillOpacity = 1; + } + + if(~m_flags & SVG_STYLE_FLAG_STROKE_OPACITY) + { + if(parentStyle) + m_strokeOpacity = parentStyle->getStrokeOpacity(); + else + m_strokeOpacity = 1; + } + + // Fake group opacity by multiplying by our parent's group opacity + if(~m_flags & SVG_STYLE_FLAG_OPACITY) + { + if(parentStyle) + m_opacity = parentStyle->getOpacity(); + else + m_opacity = 1; + } + else + if(parentStyle) + m_opacity *= parentStyle->getOpacity(); + + if(~m_flags & SVG_STYLE_FLAG_CLIP_PATH) + m_clipPath = ""; + + if(~m_flags & SVG_STYLE_FLAG_MASK) + m_mask = ""; + + // Spec: default "nonzero" + if(~m_flags & SVG_STYLE_FLAG_FILL_RULE) + { + if(parentStyle) + m_fillRule = parentStyle->getFillRule(); + else + m_fillRule = RULE_NONZERO; + } + + if(~m_flags & SVG_STYLE_FLAG_CLIP_RULE) + { + if(parentStyle) + m_clipRule = parentStyle->getClipRule(); + else + m_clipRule = RULE_NONZERO; + } + + // Spec: default "hidden" + if(~m_flags & SVG_STYLE_FLAG_OVERFLOW) + { + if(parentStyle) + m_overflow = parentStyle->getOverflow(); + else + m_overflow = false; + } + + // We are not really, spec compatible here, we just + // define a bool, to indicate wheter an element should + // be rendered or not. + if(~m_flags & SVG_STYLE_FLAG_DISPLAY) + m_display = true; + + if(~m_flags & SVG_STYLE_FLAG_VISIBILITY) + { + if(parentStyle) + m_visible = parentStyle->getVisible(); + else + m_visible = true; + } + + // Spec: default "medium" + if(~m_flags & SVG_STYLE_FLAG_FONT_SIZE) + { + if(parentStyle) + m_fontSize = parentStyle->getFontSize(); + else + m_fontSize = fontSizeForText("medium"); + } + + // Spec: default "depends on user agent" -> "Arial" for SVG + if(~m_flags & SVG_STYLE_FLAG_FONT_FAMILY) + { + if(!m_fontFamily) + { + m_fontFamily = new SVGStringListImpl(); + m_fontFamily->ref(); + } + + SVGStringListImpl *fontFamily = 0; + if(parentStyle) + fontFamily = parentStyle->getFontFamily(); + + if(fontFamily) + *m_fontFamily = *fontFamily; + else + { + SharedString *string = new SharedString("Arial"); + string->ref(); + + m_fontFamily->appendItem(string); + } + } + + // Spec: default "normal" + if(~m_flags & SVG_STYLE_FLAG_FONT_STYLE) + { + if(parentStyle) + m_fontStyle = parentStyle->getFontStyle(); + else + m_fontStyle = FSNORMAL; + } + + // Spec: default "normal" + if(~m_flags & SVG_STYLE_FLAG_FONT_WEIGHT) + { + if(parentStyle) + m_fontWeight = parentStyle->getFontWeight(); + else + m_fontWeight = "normal"; + } + + // Spec: default "start" + if(~m_flags & SVG_STYLE_FLAG_TEXT_ANCHOR) + { + if(parentStyle) + m_textAnchor = parentStyle->getTextAnchor(); + else + m_textAnchor = TASTART; + } + + // Spec: default "LTR" + if(~m_flags & SVG_STYLE_FLAG_TEXT_DIRECTION) + { + if(parentStyle) + m_textDirection = parentStyle->getTextDirection(); + else + m_textDirection = LTR; + } + + // Spec: default "none" + if(~m_flags & SVG_STYLE_FLAG_TEXT_DECORATION) + { + if(parentStyle) + m_textDecoration = parentStyle->getTextDecoration(); + else + m_textDecoration = TDNONE; + } + + // Spec: default "baseline" + if(~m_flags & SVG_STYLE_FLAG_BASELINE_SHIFT) + { + if(parentStyle) + m_baselineShift = parentStyle->getBaselineShift(); + else + m_baselineShift = "baseline"; + } + + // Spec: default "lr-tb", FIXME + if(~m_flags & SVG_STYLE_FLAG_TEXT_WRITING_MODE) + { + if(parentStyle) + m_textWritingMode = parentStyle->getTextWritingMode(); + else + m_textWritingMode = LR; + } + + // Spec: default "normal" + if(~m_flags & SVG_STYLE_FLAG_TEXT_UNICODE_BIDI) + { + if(parentStyle) + m_textUnicodeBidi = parentStyle->getTextUnicodeBidi(); + else + m_textUnicodeBidi = UBNORMAL; + } + + // Spec: default "auto" + if(~m_flags & SVG_STYLE_FLAG_GLYPH_ORIENTATION_VERTICAL) + { + if(parentStyle) + m_glyphOrientationVertical = parentStyle->getGlyphOrientationVertical(); + else + m_glyphOrientationVertical = "auto"; + } + + // Spec: default "auto" + if(~m_flags & SVG_STYLE_FLAG_GLYPH_ORIENTATION_HORIZONTAL) + { + if(parentStyle) + m_glyphOrientationHorizontal = parentStyle->getGlyphOrientationHorizontal(); + else + m_glyphOrientationHorizontal = "auto"; + } + + // Spec: default "normal" + if(~m_flags & SVG_STYLE_FLAG_LETTER_SPACING) + { + if(parentStyle) + m_letterSpacing = parentStyle->getLetterSpacing(); + else + m_letterSpacing = "normal"; + } + + // Spec: default "normal" + if(~m_flags & SVG_STYLE_FLAG_WORD_SPACING) + { + if(parentStyle) + m_wordSpacing = parentStyle->getWordSpacing(); + else + m_wordSpacing = "normal"; + } + + // Spec: default "black" + if(~m_flags & SVG_STYLE_FLAG_STOP) + { + m_stopColor = new SVGColorImpl(m_object); + m_stopColor->ref(); + + m_stopColor->setRGBColor(DOM::DOMString("black")); + } + + // Spec: default "none" + if(~m_flags & SVG_STYLE_FLAG_MARKER_START) + { + if(parentStyle) + m_startMarker = parentStyle->getStartMarker(); + else + m_startMarker = QString::null; + } + + // Spec: default "none" + if(~m_flags & SVG_STYLE_FLAG_MARKER_MID) + { + if(parentStyle) + m_midMarker = parentStyle->getMidMarker(); + else + m_midMarker = QString::null; + } + + // Spec: default "none" + if(~m_flags & SVG_STYLE_FLAG_MARKER_END) + { + if(parentStyle) + m_endMarker = parentStyle->getEndMarker(); + else + m_endMarker = QString::null; + } +} + +bool SVGStylableImpl::isStroked() const +{ + if(!m_strokeColor) + return false; + + return m_strokeColor->paintType() != SVG_PAINTTYPE_UNKNOWN && + m_strokeColor->paintType() != SVG_PAINTTYPE_NONE && + m_strokeColor->paintType() != SVG_PAINTTYPE_URI_NONE; +} + +bool SVGStylableImpl::isFilled() const +{ + if(!m_fillColor) + return false; + + return m_fillColor->paintType() != SVG_PAINTTYPE_UNKNOWN && + m_fillColor->paintType() != SVG_PAINTTYPE_NONE && + m_fillColor->paintType() != SVG_PAINTTYPE_URI_NONE; +} + +QString SVGStylableImpl::extractUrlId(const QString &url) +{ + QString id; + + if(url.startsWith("url(#")) + { + int idstart = url.find("#") + 1; + id = url.mid(idstart, url.length() - idstart - 1); + } + else + id = url; + + return id; +} + +void SVGStylableImpl::setMarkers(const QString &marker) +{ + setStartMarker(marker); + setMidMarker(marker); + setEndMarker(marker); +} + +void SVGStylableImpl::setStartMarker(const QString &startMarker) +{ + if(startMarker.startsWith("url(#")) + { + int idstart = startMarker.find("#") + 1; + m_startMarker = startMarker.mid(idstart, startMarker.length() - idstart - 1); + } + else if(startMarker == "none") + m_startMarker = QString::null; +} + +void SVGStylableImpl::setMidMarker(const QString &midMarker) +{ + if(midMarker.startsWith("url(#")) + { + int idstart = midMarker.find("#") + 1; + m_midMarker = midMarker.mid(idstart, midMarker.length() - idstart - 1); + } + else if(midMarker == "none") + m_midMarker = QString::null; +} + +void SVGStylableImpl::setEndMarker(const QString &endMarker) +{ + if(endMarker.startsWith("url(#")) + { + int idstart = endMarker.find("#") + 1; + m_endMarker = endMarker.mid(idstart, endMarker.length() - idstart - 1); + } + else if(endMarker == "none") + m_endMarker = QString::null; +} + +bool SVGStylableImpl::hasMarkers() const +{ + return !m_startMarker.isEmpty() || !m_midMarker.isEmpty() || !m_endMarker.isEmpty(); +} + +void SVGStylableImpl::setPaint(const QString ¶m, SVGPaintImpl *svgPaint) +{ + if(param.stripWhiteSpace() == "none") + svgPaint->setPaint(SVG_PAINTTYPE_NONE, DOM::DOMString(""), DOM::DOMString("")); + else if(SVGURIReferenceImpl::isUrl(param)) + svgPaint->setUri(SVGURIReferenceImpl::getTarget(param)); + else + setColor(param, svgPaint); +} + +void SVGStylableImpl::setColor(const QString ¶m, SVGColorImpl *svgColor) +{ + if(param.stripWhiteSpace().startsWith("#")) + { + if(param.contains("icc-color")) + { + QString first = param.left(7); + QString last = param.right(param.length() - 8); + + svgColor->setRGBColorICCColor(first, last); + } + else + { + QColor color; + color.setNamedColor(param.stripWhiteSpace()); + svgColor->setRGBColor(color); + } + } + else if(param.stripWhiteSpace().startsWith("rgb(")) + { + QString parse = param.stripWhiteSpace(); + QStringList colors = QStringList::split(',', parse); + QString r = colors[0].right((colors[0].length() - 4)); + QString g = colors[1]; + QString b = colors[2].left((colors[2].length() - 1)); + + if(r.contains("%")) + { + r = r.left(r.length() - 1); + r = QString::number(int((double(255 * r.toDouble()) / 100.0))); + } + + if(g.contains("%")) + { + g = g.left(g.length() - 1); + g = QString::number(int((double(255 * g.toDouble()) / 100.0))); + } + + if(b.contains("%")) + { + b = b.left(b.length() - 1); + b = QString::number(int((double(255 * b.toDouble()) / 100.0))); + } + + svgColor->setRGBColor(int(r.toFloat()), int(g.toFloat()), int(b.toFloat())); + } + else + { + if(param.stripWhiteSpace().lower() == "currentcolor") + svgColor->setColor(SVG_COLORTYPE_CURRENTCOLOR, DOM::DOMString(""), DOM::DOMString("")); + else + svgColor->setRGBColor(DOM::DOMString(param.stripWhiteSpace().lower())); + } +} + +QRect SVGStylableImpl::clip() +{ + return QRect(); +} + +void SVGStylableImpl::setClip(const QString &) +{ +} + +float SVGStylableImpl::fontSizeForText(const QString &value) +{ + float ret = -1; + + // Spec: "On a computer screen a scaling factor of 1.2 is suggested between adjacent indexes" + const float factor = 1.2; + + // Spec: "If the 'medium' font is 12pt, the 'large' font could be 14.4pt." + const float mediumFont = 12.0; + + if(value == "xx-small") + ret = mediumFont - (3.0 * factor); + else if(value == "x-small") + ret = mediumFont - (2.0 * factor); + else if(value == "small") + ret = mediumFont - factor; + else if(value == "medium") + ret = mediumFont; + else if(value == "large") + ret = mediumFont + factor; + else if(value == "x-large") + ret = mediumFont + (2.0 * factor); + else if(value == "xx-large") + ret = mediumFont + (3.0 * factor); + + return ret; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGStylableImpl::s_hashTable 47 + className SVGStylableImpl::ClassName DontDelete|ReadOnly + style SVGStylableImpl::Style DontDelete|ReadOnly + stroke-width SVGStylableImpl::StrokeWidth DontDelete|ReadOnly + stroke-miterlimit SVGStylableImpl::StrokeMiterlimit DontDelete|ReadOnly + stroke-linecap SVGStylableImpl::StrokeLineCap DontDelete|ReadOnly + stroke-linejoin SVGStylableImpl::StrokeLineJoin DontDelete|ReadOnly + stroke SVGStylableImpl::Stroke DontDelete|ReadOnly + fill SVGStylableImpl::Fill DontDelete|ReadOnly + color SVGStylableImpl::Color DontDelete|ReadOnly + stop-color SVGStylableImpl::StopColor DontDelete|ReadOnly + font-size SVGStylableImpl::FontSize DontDelete|ReadOnly + font-family SVGStylableImpl::FontFamily DontDelete|ReadOnly + font-weight SVGStylableImpl::FontWeight DontDelete|ReadOnly + font-style SVGStylableImpl::FontStyle DontDelete|ReadOnly + text-decoration SVGStylableImpl::TextDecoration DontDelete|ReadOnly + text-anchor SVGStylableImpl::TextAnchor DontDelete|ReadOnly + direction SVGStylableImpl::Direction DontDelete|ReadOnly + writing-mode SVGStylableImpl::WritingMode DontDelete|ReadOnly + unicode-bidi SVGStylableImpl::UnicodeBidi DontDelete|ReadOnly + opacity SVGStylableImpl::Opacity DontDelete|ReadOnly + fill-opacity SVGStylableImpl::FillOpacity DontDelete|ReadOnly + stroke-opacity SVGStylableImpl::StrokeOpacity DontDelete|ReadOnly + clip-path SVGStylableImpl::ClipPath DontDelete|ReadOnly + marker-start SVGStylableImpl::MarkerStart DontDelete|ReadOnly + marker-mid SVGStylableImpl::MarkerMid DontDelete|ReadOnly + marker-end SVGStylableImpl::MarkerEnd DontDelete|ReadOnly + marker SVGStylableImpl::Marker DontDelete|ReadOnly + cursor SVGStylableImpl::Cursor DontDelete|ReadOnly + display SVGStylableImpl::Display DontDelete|ReadOnly + overflow SVGStylableImpl::Overflow DontDelete|ReadOnly + clip SVGStylableImpl::Clip DontDelete|ReadOnly + visibility SVGStylableImpl::Visibility DontDelete|ReadOnly + fill-rule SVGStylableImpl::FillRule DontDelete|ReadOnly + clip-rule SVGStylableImpl::ClipRule DontDelete|ReadOnly + stroke-dashoffset SVGStylableImpl::StrokeDashOffset DontDelete|ReadOnly + stroke-dasharray SVGStylableImpl::StrokeDashArray DontDelete|ReadOnly + color-profile SVGStylableImpl::ColorProfile DontDelete|ReadOnly + baseline-shift SVGStylableImpl::BaselineShift DontDelete|ReadOnly + letter-spacing SVGStylableImpl::LetterSpacing DontDelete|ReadOnly + word-spacing SVGStylableImpl::WordSpacing DontDelete|ReadOnly + pointer-events SVGStylableImpl::PointerEvents DontDelete|ReadOnly + glyph-orientation-vertical SVGStylableImpl::GlyphOrientationVertical DontDelete|ReadOnly + glyph-orientation-horizontal SVGStylableImpl::GlyphOrientationHorizontal DontDelete|ReadOnly + color-interpolation SVGStylableImpl::ColorInterpolation DontDelete|ReadOnly + mask SVGStylableImpl::Mask DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGStylableImplProto::s_hashTable 2 + getStyle SVGStylableImpl::GetStyle DontDelete|Function 0 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGStylable", SVGStylableImplProto, SVGStylableImplProtoFunc) + +Value SVGStylableImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + //case ClassName: + // return String(className().string()); + case Style: + return String(m_object ? m_object->DOM::Element::getAttribute("style") : ""); + case Visibility: + return String(m_visible ? "visible" : "hidden"); + case Display: + return String(m_display ? "inline" : "none"); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGStylableImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + QString param = value.toString(exec).qstring(); + + if (param.isEmpty()) + return; + + bool redraw = false; + bool inherit = (param == "inherit"); + int update = -1; + + switch(token) + { + case Style: + { + if(!m_object) + return; + + QStringList substyles = QStringList::split(';', param); + for(QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it) + { + QStringList substyle = QStringList::split(':', (*it)); + m_object->setAttributeInternal(substyle[0].stripWhiteSpace(), substyle[1].stripWhiteSpace()); + } + break; + } + case StrokeWidth: + if(m_flags & SVG_STYLE_FLAG_STROKE_WIDTH) + { + redraw = true; + update = UPDATE_LINEWIDTH; + } + if(inherit) + m_flags &= ~SVG_STYLE_FLAG_STROKE_WIDTH; + else + { + m_flags |= SVG_STYLE_FLAG_STROKE_WIDTH; + + if(!m_strokeWidth) + { + m_strokeWidth = new SVGAnimatedLengthImpl(LENGTHMODE_OTHER, m_object); + m_strokeWidth->ref(); + } + + m_strokeWidth->baseVal()->setValueAsString(param); + } + break; + case StrokeMiterlimit: + m_flags |= SVG_STYLE_FLAG_STROKE_MITER_LIMIT; + if(!inherit) + m_strokeMiterlimit = param.toUInt(); + break; + case StrokeLineCap: + m_flags |= SVG_STYLE_FLAG_STROKE_LINE_CAP; + if(param == "butt") + m_capStyle = PATH_STROKE_CAP_BUTT; + else if(param == "round") + m_capStyle = PATH_STROKE_CAP_ROUND; + else if(param == "square") + m_capStyle = PATH_STROKE_CAP_SQUARE; + break; + case StrokeLineJoin: + m_flags |= SVG_STYLE_FLAG_STROKE_LINE_JOIN; + if(param == "miter") + m_joinStyle = PATH_STROKE_JOIN_MITER; + else if(param == "round") + m_joinStyle = PATH_STROKE_JOIN_ROUND; + else if(param == "bevel") + m_joinStyle = PATH_STROKE_JOIN_BEVEL; + break; + case Stroke: + if(m_flags & SVG_STYLE_FLAG_STROKE) + redraw = true; + if(inherit) + m_flags &= ~SVG_STYLE_FLAG_STROKE; + else + { + m_flags |= SVG_STYLE_FLAG_STROKE; + + if(!m_strokeColor) + { + m_strokeColor = new SVGPaintImpl(m_object); + m_strokeColor->ref(); + } + + setPaint(param, m_strokeColor); + } + break; + case Fill: + if(m_flags & SVG_STYLE_FLAG_FILL) + { + redraw = true; + update = UPDATE_STYLE; + } + if(inherit) + m_flags &= ~SVG_STYLE_FLAG_FILL; + else + { + m_flags |= SVG_STYLE_FLAG_FILL; + + if(!m_fillColor) + { + m_fillColor = new SVGPaintImpl(m_object); + m_fillColor->ref(); + } + + setPaint(param, m_fillColor); + } + break; + case Color: + if(m_flags & SVG_STYLE_FLAG_COLOR) + redraw = true; + if(inherit) + m_flags &= ~SVG_STYLE_FLAG_COLOR; + else + { + m_flags |= SVG_STYLE_FLAG_COLOR; + + if(!m_color) + { + m_color = new SVGColorImpl(m_object); + m_color->ref(); + } + setColor(param, m_color); + } + break; + case StopColor: + m_flags |= SVG_STYLE_FLAG_STOP; + + if(!m_stopColor) + { + m_stopColor = new SVGColorImpl(m_object); + m_stopColor->ref(); + } + + if(!inherit) + setColor(param, m_stopColor); + break; + case ColorInterpolation: + if(inherit) + m_flags &= ~SVG_STYLE_FLAG_COLOR_INTERPOLATION; + else + { + m_flags |= SVG_STYLE_FLAG_COLOR_INTERPOLATION; + if(param == "auto" || param == "sRGB") + m_colorInterpolation = CI_SRGB; + else + if(param == "linearRGB") + m_colorInterpolation = CI_LINEARRGB; + } + break; + case FontSize: + { + m_flags |= SVG_STYLE_FLAG_FONT_SIZE; + if(!inherit) + { + double temp = fontSizeForText(param); + if(temp != -1) // Is "absolute-size" + { + m_fontSize = temp; + break; + } + + SVGLengthImpl *length = SVGSVGElementImpl::createSVGLength(); + length->setContext(m_object); + length->setValueAsString(DOM::DOMString(param)); + m_fontSize = length->value(); + length->deref(); + } + break; + } + case FontFamily: + m_flags |= SVG_STYLE_FLAG_FONT_FAMILY; + + // Hacks + // #1 Replace "'" characters by "" + param = param.replace('\'', QString::null); + // #2 Replace "MS-Gothic" by "MS Gothic" + param = param.replace("MS-Gothic", "MS Gothic"); + // #3 Replace "Helvetica" by "Arial" + param = param.replace("Helvetica", "Arial"); + param = param.replace("helvetica", "Arial"); + + if(!m_fontFamily) + { + m_fontFamily = new SVGStringListImpl(); + m_fontFamily->ref(); + } + + if(!inherit) + SVGHelperImpl::parseCommaSeperatedList(m_fontFamily, param); + break; + case FontWeight: + m_flags |= SVG_STYLE_FLAG_FONT_WEIGHT; + if(!inherit) + m_fontWeight = param; + break; + case FontStyle: + m_flags |= SVG_STYLE_FLAG_FONT_STYLE; + if(param == "normal") + m_fontStyle = FSNORMAL; + else if(param == "italic") + m_fontStyle = ITALIC; + else if(param == "oblique") + m_fontStyle = OBLIQUE; + break; + case TextDecoration: + m_flags |= SVG_STYLE_FLAG_TEXT_DECORATION; + if(param == "none") + m_textDecoration = TDNONE; + { + // CSS2 allows multiple decorations + m_textDecoration = TDNONE; + QStringList decorations = QStringList::split(' ', param); + for(QStringList::Iterator it = decorations.begin(); it != decorations.end(); ++it) + { + if(*it == "underline") + m_textDecoration |= UNDERLINE; + else if(*it == "overline") + m_textDecoration |= OVERLINE; + else if(*it == "line-through") + m_textDecoration |= LINE_THROUGH; + } + } + break; + case TextAnchor: + m_flags |= SVG_STYLE_FLAG_TEXT_ANCHOR; + if(param == "start") + m_textAnchor = TASTART; + else if(param == "middle") + m_textAnchor = TAMIDDLE; + else if(param == "end") + m_textAnchor = TAEND; + break; + case Direction: + m_flags |= SVG_STYLE_FLAG_TEXT_DIRECTION; + // Spec: direction is only processed when unicode-bidi + // is set to bidi-override or embedded + if(m_textUnicodeBidi == OVERRIDE || + m_textUnicodeBidi == EMBED || + m_textUnicodeBidi == UBNORMAL) + { + if(param == "rtl") + m_textDirection = RTL; + else if(param == "ltr") + m_textDirection = LTR; + } + break; + case WritingMode: + m_flags |= SVG_STYLE_FLAG_TEXT_WRITING_MODE; + if(param == "lr-tb" || param == "lr") + m_textWritingMode = LR; + else if(param == "rl-tb" || param == "rl") + m_textWritingMode = RL; + else if(param == "tb-lr" || param == "tb") + m_textWritingMode = TB; + break; + case UnicodeBidi: + m_flags |= SVG_STYLE_FLAG_TEXT_UNICODE_BIDI; + if(param == "normal") + m_textUnicodeBidi = UBNORMAL; + else if(param == "embed") + m_textUnicodeBidi = EMBED; + else if(param == "bidi-override") + m_textUnicodeBidi = OVERRIDE; + break; + case GlyphOrientationVertical: + m_flags |= SVG_STYLE_FLAG_GLYPH_ORIENTATION_VERTICAL; + m_glyphOrientationVertical = param; + break; + case GlyphOrientationHorizontal: + m_flags |= SVG_STYLE_FLAG_GLYPH_ORIENTATION_HORIZONTAL; + m_glyphOrientationHorizontal = param; + break; + case Opacity: + m_flags |= SVG_STYLE_FLAG_OPACITY; + + if(!inherit) + { + SVGLengthImpl::convertPercentageToFloat(value.toString(exec).qstring(), m_opacity); + } + break; + case FillOpacity: + m_flags |= SVG_STYLE_FLAG_FILL_OPACITY; + + if(!inherit) + { + SVGLengthImpl::convertPercentageToFloat(value.toString(exec).qstring(), m_fillOpacity); + } + break; + case StrokeOpacity: + m_flags |= SVG_STYLE_FLAG_STROKE_OPACITY; + + if(!inherit) + { + SVGLengthImpl::convertPercentageToFloat(value.toString(exec).qstring(), m_strokeOpacity); + } + break; + case ClipPath: + m_flags |= SVG_STYLE_FLAG_CLIP_PATH; + if(!inherit) + m_clipPath = extractUrlId(param); + break; + case Mask: + m_flags |= SVG_STYLE_FLAG_MASK; + if(!inherit) + m_mask = extractUrlId(param); + break; + case MarkerStart: + m_flags |= SVG_STYLE_FLAG_MARKER_START; + if(!inherit) + setStartMarker(param); + break; + case MarkerMid: + m_flags |= SVG_STYLE_FLAG_MARKER_MID; + if(!inherit) + setMidMarker(param); + break; + case MarkerEnd: + m_flags |= SVG_STYLE_FLAG_MARKER_END; + if(!inherit) + setEndMarker(param); + break; + case Marker: + m_flags |= (SVG_STYLE_FLAG_MARKER_START | SVG_STYLE_FLAG_MARKER_MID | SVG_STYLE_FLAG_MARKER_END); + if(!inherit) + setMarkers(param); + break; + case PointerEvents: + m_flags |= SVG_STYLE_FLAG_POINTER_EVENTS; + if(param == "none") + m_pointerEvents = PE_NONE; + else if(param == "stroke") + m_pointerEvents = PE_STROKE; + else if(param == "fill") + m_pointerEvents = PE_FILL; + else if(param == "painted") + m_pointerEvents = PE_PAINTED; + else if(param == "visibleStroke") + m_pointerEvents = PE_VISIBLE_STROKE; + else if(param == "visibleFill") + m_pointerEvents = PE_VISIBLE_FILL; + else if(param == "visiblePainted") + m_pointerEvents = PE_VISIBLE_PAINTED; + else if(param == "visible") + m_pointerEvents = PE_VISIBLE; + else if(param == "all") + m_pointerEvents = PE_ALL; + break; + case Cursor: + m_flags |= SVG_STYLE_FLAG_CURSOR; + if(param == "auto") + m_cursor = CURSOR_AUTO; + else if(param == "crosshair") + m_cursor = CURSOR_CROSSHAIR; + else if(param == "default") + m_cursor = CURSOR_DEFAULT; + else if(param == "pointer") + m_cursor = CURSOR_POINTER; + else if(param == "move") + m_cursor = CURSOR_MOVE; + else if(param == "e-resize") + m_cursor = CURSOR_E_RESIZE; + else if(param == "ne-resize") + m_cursor = CURSOR_NE_RESIZE; + else if(param == "nw-resize") + m_cursor = CURSOR_NW_RESIZE; + else if(param == "n-resize") + m_cursor = CURSOR_N_RESIZE; + else if(param == "se-resize") + m_cursor = CURSOR_SE_RESIZE; + else if(param == "sw-resize") + m_cursor = CURSOR_SW_RESIZE; + else if(param == "s-resize") + m_cursor = CURSOR_S_RESIZE; + else if(param == "w-resize") + m_cursor = CURSOR_W_RESIZE; + else if(param == "text") + m_cursor = CURSOR_TEXT; + else if(param == "wait") + m_cursor = CURSOR_WAIT; + else if(param == "help") + m_cursor = CURSOR_HELP; + break; + case Display: + m_flags |= SVG_STYLE_FLAG_DISPLAY; + + if(param == "none") + m_display = false; + else if(!inherit) + m_display = true; + break; + case Overflow: + m_flags |= SVG_STYLE_FLAG_OVERFLOW; + if(param == "hidden" || param == "scroll") + m_overflow = false; + else if(!inherit) + m_overflow = true; + break; + case Clip: + m_flags |= SVG_STYLE_FLAG_CLIP_PATH; + if(!inherit) + setClip(param); + break; + case Visibility: + if(m_flags & SVG_STYLE_FLAG_VISIBILITY) + redraw = true; + if(inherit) + m_flags &= ~SVG_STYLE_FLAG_COLOR; + else + { + m_flags |= SVG_STYLE_FLAG_VISIBILITY; + + if(param == "visible") + m_visible = true; + else if(!inherit) + m_visible = false; + + // Just a quick fix for the script-* files (Niko) + // Any better solution?? + update = UPDATE_TRANSFORM; + redraw = true; + } + SVGHelperImpl::applyContainer(this, Visibility, param); + break; + case FillRule: + m_flags |= SVG_STYLE_FLAG_FILL_RULE; + if(!inherit) + m_fillRule = (param == "evenodd" ? RULE_EVENODD : RULE_NONZERO); + break; + case ClipRule: + m_flags |= SVG_STYLE_FLAG_CLIP_RULE; + if(!inherit) + m_clipRule = (param == "evenodd" ? RULE_EVENODD : RULE_NONZERO); + break; + case StrokeDashOffset: + m_flags |= SVG_STYLE_FLAG_STROKE_DASH_OFFSET; + + if(!m_dashOffset) + { + m_dashOffset = new SVGAnimatedLengthImpl(LENGTHMODE_OTHER, m_object); + m_dashOffset->ref(); + } + + if(!inherit) + m_dashOffset->baseVal()->setValueAsString(param); + break; + case StrokeDashArray: + { + m_flags |= SVG_STYLE_FLAG_STROKE_DASH_ARRAY; + + if(!m_dashArray) + { + m_dashArray = new SVGAnimatedLengthListImpl(); + m_dashArray->ref(); + } + else + m_dashArray->baseVal()->clear(); + + if(param != "none" && !inherit) + SVGHelperImpl::parseLengthList(m_dashArray, param); + break; + } + case ColorProfile: + { + m_flags |= SVG_STYLE_FLAG_COLOR_PROFILE; + if(!inherit) + { + if(!m_object) + return; + + SVGColorProfileElementImpl *handle = static_cast(m_object->ownerSVGElement()->getElementById(SVGURIReferenceImpl::getTarget(param))); + if(handle) + SVGImageElementImpl::applyColorProfile(handle, static_cast(this)); + } + break; + } + case BaselineShift: + { + m_flags |= SVG_STYLE_FLAG_BASELINE_SHIFT; + if(!inherit) + m_baselineShift = param; + break; + } + case LetterSpacing: + m_flags |= SVG_STYLE_FLAG_LETTER_SPACING; + case WordSpacing: + { + if(!inherit) + { + if(token == WordSpacing) + { + m_flags |= SVG_STYLE_FLAG_WORD_SPACING; + m_wordSpacing = param; + } + else + m_letterSpacing = param; + } + break; + } + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } + + if(redraw) + { + SVGShapeImpl *shape = dynamic_cast(m_object); + if(inherit) + processStyle(); + + if(shape && shape->item()) + { + if(update > -1) + shape->item()->update(static_cast(update)); + else if(m_object) + m_object->ownerDoc()->canvas()->invalidate(shape->item(), false); + } + } +} + +Value SVGStylableImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &) +{ + KSVG_CHECK_THIS(SVGStylableImpl) + + switch(id) + { + case SVGStylableImpl::GetStyle: + return Undefined(); + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGStylableImpl.h b/ksvg/impl/SVGStylableImpl.h new file mode 100644 index 00000000..0a399a4c --- /dev/null +++ b/ksvg/impl/SVGStylableImpl.h @@ -0,0 +1,327 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGStylableImpl_H +#define SVGStylableImpl_H + +#include +#include + +#include + +#include "ksvg_lookup.h" + +class QRect; + +// from libart, but now no dependency +typedef enum +{ + PATH_STROKE_JOIN_MITER, + PATH_STROKE_JOIN_ROUND, + PATH_STROKE_JOIN_BEVEL +} PathStrokeJoinType; + +typedef enum +{ + PATH_STROKE_CAP_BUTT, + PATH_STROKE_CAP_ROUND, + PATH_STROKE_CAP_SQUARE +} PathStrokeCapType; + +#define SVG_STYLE_FLAG_NONE 0x0000000000000ULL +#define SVG_STYLE_FLAG_BASELINE_SHIFT 0x0000000000001ULL +#define SVG_STYLE_FLAG_CLIP_PATH 0x0000000000002ULL +#define SVG_STYLE_FLAG_CLIP_RULE 0x0000000000004ULL +#define SVG_STYLE_FLAG_COLOR 0x0000000000008ULL +#define SVG_STYLE_FLAG_COLOR_INTERPOLATION 0x0000000000010ULL +#define SVG_STYLE_FLAG_COLOR_INTERPOLATION_FILTERS 0x0000000000020ULL +#define SVG_STYLE_FLAG_COLOR_PROFILE 0x0000000000040ULL +#define SVG_STYLE_FLAG_COLOR_RENDERING 0x0000000000080ULL +#define SVG_STYLE_FLAG_CURSOR 0x0000000000100ULL +#define SVG_STYLE_FLAG_DIRECTION 0x0000000000200ULL +#define SVG_STYLE_FLAG_DISPLAY 0x0000000000400ULL +#define SVG_STYLE_FLAG_FILL 0x0000000000800ULL +#define SVG_STYLE_FLAG_FILL_OPACITY 0x0000000001000ULL +#define SVG_STYLE_FLAG_FILL_RULE 0x0000000002000ULL +#define SVG_STYLE_FLAG_FONT_FAMILY 0x0000000004000ULL +#define SVG_STYLE_FLAG_FONT_SIZE 0x0000000008000ULL +#define SVG_STYLE_FLAG_FONT_SIZE_ADJUST 0x0000000010000ULL +#define SVG_STYLE_FLAG_FONT_STRETCH 0x0000000020000ULL +#define SVG_STYLE_FLAG_FONT_STYLE 0x0000000040000ULL +#define SVG_STYLE_FLAG_FONT_VARIANT 0x0000000080000ULL +#define SVG_STYLE_FLAG_FONT_WEIGHT 0x0000000100000ULL +#define SVG_STYLE_FLAG_GLYPH_ORIENTATION_HORIZONTAL 0x0000000200000ULL +#define SVG_STYLE_FLAG_GLYPH_ORIENTATION_VERTICAL 0x0000000400000ULL +#define SVG_STYLE_FLAG_IMAGE_RENDERING 0x0000000800000ULL +#define SVG_STYLE_FLAG_KERNING 0x0000001000000ULL +#define SVG_STYLE_FLAG_LETTER_SPACING 0x0000002000000ULL +#define SVG_STYLE_FLAG_MARKER 0x0000004000000ULL +#define SVG_STYLE_FLAG_MARKER_END 0x0000008000000ULL +#define SVG_STYLE_FLAG_MARKER_MID 0x0000010000000ULL +#define SVG_STYLE_FLAG_MARKER_START 0x0000020000000ULL +#define SVG_STYLE_FLAG_OPACITY 0x0000040000000ULL +#define SVG_STYLE_FLAG_POINTER_EVENTS 0x0000080000000ULL +#define SVG_STYLE_FLAG_SHAPE_RENDERING 0x0000100000000ULL +#define SVG_STYLE_FLAG_STOP 0x0000200000000ULL +#define SVG_STYLE_FLAG_STROKE_DASH_ARRAY 0x0000400000000ULL +#define SVG_STYLE_FLAG_STROKE_DASH_OFFSET 0x0000800000000ULL +#define SVG_STYLE_FLAG_STROKE_LINE_CAP 0x0001000000000ULL +#define SVG_STYLE_FLAG_STROKE_LINE_JOIN 0x0002000000000ULL +#define SVG_STYLE_FLAG_STROKE_MITER_LIMIT 0x0004000000000ULL +#define SVG_STYLE_FLAG_STROKE_OPACITY 0x0008000000000ULL +#define SVG_STYLE_FLAG_STROKE 0x0010000000000ULL +#define SVG_STYLE_FLAG_STROKE_WIDTH 0x0020000000000ULL +#define SVG_STYLE_FLAG_TEXT_ANCHOR 0x0040000000000ULL +#define SVG_STYLE_FLAG_TEXT_DECORATION 0x0080000000000ULL +#define SVG_STYLE_FLAG_TEXT_DIRECTION 0x0100000000000ULL +#define SVG_STYLE_FLAG_TEXT_RENDERING 0x0200000000000ULL +#define SVG_STYLE_FLAG_TEXT_UNICODE_BIDI 0x0400000000000ULL +#define SVG_STYLE_FLAG_TEXT_WRITING_MODE 0x0800000000000ULL +#define SVG_STYLE_FLAG_VISIBILITY 0x1000000000000ULL +#define SVG_STYLE_FLAG_WORD_SPACING 0x2000000000000ULL +#define SVG_STYLE_FLAG_OVERFLOW 0x4000000000000ULL +#define SVG_STYLE_FLAG_MASK 0x0008000000000000ULL + +//?#define SVG_STYLE_FLAG_MASK_INHERIT 0x0010000000000000ULL + +// Helper macros +#define STYLE_GET(Return, Name, Member) \ +protected:\ + Return Member;\ +public:\ +Return get ##Name () const { return Member; } + +#define STYLE_GET_OPTIM(Return, Name, Member, Optim) \ +protected:\ + Return Member : Optim;\ +public:\ +Return get ##Name () const { return Member; } + +#define STYLE_HAS(Name, Member) \ +bool has##Name () { return ! Member .isEmpty(); } + +namespace KSVG +{ + +enum ECursor +{ + CURSOR_AUTO, + CURSOR_CROSSHAIR, + CURSOR_DEFAULT, + CURSOR_POINTER, + CURSOR_MOVE, + CURSOR_E_RESIZE, + CURSOR_NE_RESIZE, + CURSOR_N_RESIZE, + CURSOR_NW_RESIZE, + CURSOR_SE_RESIZE, + CURSOR_SW_RESIZE, + CURSOR_S_RESIZE, + CURSOR_W_RESIZE, + CURSOR_TEXT, + CURSOR_WAIT, + CURSOR_HELP +}; + +enum ETextDirection +{ + LTR, RTL +}; + +enum ETextDecoration +{ + TDNONE = 0, UNDERLINE = 1, OVERLINE = 2, LINE_THROUGH = 4 +}; + +enum ETextAnchor +{ + TASTART, TAMIDDLE, TAEND +}; + +enum EUnicodeBidi +{ + UBNORMAL, EMBED, OVERRIDE, INHERIT +}; + +enum EFontStyle +{ + FSNORMAL, ITALIC, OBLIQUE +}; + +enum ETextWritingMode +{ + LR, RL, TB +}; + +enum EWindRule +{ + RULE_NONZERO, + RULE_EVENODD +}; + +enum EPointerEvents +{ + PE_NONE, + PE_STROKE, + PE_FILL, + PE_PAINTED, + PE_VISIBLE, + PE_VISIBLE_STROKE, + PE_VISIBLE_FILL, + PE_VISIBLE_PAINTED, + PE_ALL, + PE_INHERIT +}; + +enum EColorInterpolation +{ + CI_SRGB, + CI_LINEARRGB +}; + +class SVGColorImpl; +class SVGPaintImpl; +class SVGLengthImpl; +class SVGAnimatedLengthImpl; +class SVGAnimatedLengthListImpl; +class SVGMatrixImpl; +class SVGStringListImpl; +class SVGElementImpl; +class SVGStylableImpl +{ +public: + SVGStylableImpl(SVGElementImpl *object); + virtual ~SVGStylableImpl(); + + static void setColor(const QString &, SVGColorImpl *); + + STYLE_GET(SVGAnimatedLengthImpl *, DashOffset, m_dashOffset) + STYLE_GET(SVGAnimatedLengthListImpl *, DashArray, m_dashArray) + STYLE_GET(SVGPaintImpl *, StrokeColor, m_strokeColor) + STYLE_GET(SVGPaintImpl *, FillColor, m_fillColor) + STYLE_GET(SVGColorImpl *, StopColor, m_stopColor) + STYLE_GET(SVGColorImpl *, Color, m_color) + STYLE_GET(SVGAnimatedLengthImpl *, StrokeWidth, m_strokeWidth) + STYLE_GET(SVGStringListImpl *, FontFamily, m_fontFamily); + STYLE_GET(float, FontSize, m_fontSize) + STYLE_GET(QString, LetterSpacing, m_letterSpacing) + STYLE_GET(QString, WordSpacing, m_wordSpacing) + STYLE_GET(QString, FontWeight, m_fontWeight) + STYLE_GET(QString, ClipPath, m_clipPath) + STYLE_GET(QString, Mask, m_mask) + STYLE_GET(QString, StartMarker, m_startMarker) + STYLE_GET(QString, MidMarker, m_midMarker) + STYLE_GET(QString, EndMarker, m_endMarker) + STYLE_GET(QString, BaselineShift, m_baselineShift) + STYLE_GET(QString, GlyphOrientationVertical, m_glyphOrientationVertical) + STYLE_GET(QString, GlyphOrientationHorizontal, m_glyphOrientationHorizontal) + STYLE_GET(float, Opacity, m_opacity) + STYLE_GET(float, FillOpacity, m_fillOpacity) + STYLE_GET(float, StrokeOpacity, m_strokeOpacity) + STYLE_GET(unsigned int, StrokeMiterlimit, m_strokeMiterlimit) + + STYLE_GET_OPTIM(EPointerEvents, PointerEvents, m_pointerEvents, 4) + STYLE_GET_OPTIM(ECursor, Cursor, m_cursor, 4) + STYLE_GET_OPTIM(EWindRule, FillRule, m_fillRule, 1) + STYLE_GET_OPTIM(EWindRule, ClipRule, m_clipRule, 1) + STYLE_GET_OPTIM(PathStrokeCapType, CapStyle, m_capStyle, 2) + STYLE_GET_OPTIM(PathStrokeJoinType, JoinStyle, m_joinStyle, 2) + STYLE_GET_OPTIM(ETextDirection, TextDirection, m_textDirection, 1) + STYLE_GET_OPTIM(unsigned int, TextDecoration, m_textDecoration, 3) + STYLE_GET_OPTIM(ETextAnchor, TextAnchor, m_textAnchor, 2) + STYLE_GET_OPTIM(EUnicodeBidi, TextUnicodeBidi, m_textUnicodeBidi, 2) + STYLE_GET_OPTIM(ETextWritingMode, TextWritingMode, m_textWritingMode, 2) + STYLE_GET_OPTIM(EFontStyle, FontStyle, m_fontStyle, 2) + STYLE_GET_OPTIM(bool, Overflow, m_overflow, 1) + STYLE_GET_OPTIM(bool, Visible, m_visible, 1) + STYLE_GET_OPTIM(bool, Display, m_display, 1) + STYLE_GET_OPTIM(EColorInterpolation, ColorInterpolation, m_colorInterpolation, 1) + + STYLE_HAS(ClipPath, m_clipPath) + STYLE_HAS(Mask, m_mask) + STYLE_HAS(StartMarker, m_startMarker) + STYLE_HAS(MidMarker, m_midMarker) + STYLE_HAS(EndMarker, m_endMarker) + + // Special "set" cases + void setStartMarker(const QString &); + void setMidMarker(const QString &); + void setEndMarker(const QString &); + void setMarkers(const QString &); + + // Special "has" cases + bool hasMarkers() const; + + // Special "is" cases + bool isStroked() const; + bool isFilled() const; + + // Function which sets default values + void processStyle(); + + // Special virtual functions + virtual void setClip(const QString &clip); + virtual QRect clip(); + +protected: + float fontSizeForText(const QString &); + + SVGElementImpl *m_object; + +private: + void setPaint(const QString &, SVGPaintImpl *); + QString extractUrlId(const QString& string); + + unsigned long long m_flags; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + ClassName, Style, + StrokeWidth, StrokeMiterlimit, StrokeLineCap, StrokeLineJoin, + Stroke, Fill, Color, StopColor, FontSize, FontFamily, FontWeight, + FontStyle, TextDecoration, TextAnchor, Direction, WritingMode, + UnicodeBidi, Opacity, FillOpacity, StrokeOpacity, ClipPath, + MarkerStart, MarkerMid, MarkerEnd, Marker, Cursor, Display, + Overflow, Clip, Visibility, FillRule, ClipRule, + StrokeDashOffset, StrokeDashArray, ColorProfile, BaselineShift, + LetterSpacing, WordSpacing, PointerEvents, + GlyphOrientationVertical, GlyphOrientationHorizontal, + ColorInterpolation, Mask, + // Functions + GetStyle + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +KSVG_DEFINE_PROTOTYPE(SVGStylableImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGStylableImplProtoFunc, SVGStylableImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGStyleElementImpl.cc b/ksvg/impl/SVGStyleElementImpl.cc new file mode 100644 index 00000000..d826441b --- /dev/null +++ b/ksvg/impl/SVGStyleElementImpl.cc @@ -0,0 +1,135 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGStyleElementImpl.h" + +using namespace KSVG; + +#include "SVGStyleElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGStyleElementImpl::SVGStyleElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl) +{ + KSVG_EMPTY_FLAGS +} + +SVGStyleElementImpl::~SVGStyleElementImpl() +{ +} + +void SVGStyleElementImpl::setXmlspace(const DOM::DOMString &xmlspace) +{ + setAttribute("xml:space", xmlspace); +} + +DOM::DOMString SVGStyleElementImpl::xmlspace() const +{ + return getAttribute("xml:space"); +} + +void SVGStyleElementImpl::setType(const DOM::DOMString &type) +{ + setAttribute("type", type); +} + +DOM::DOMString SVGStyleElementImpl::type() const +{ + return getAttribute("type"); +} + +void SVGStyleElementImpl::setMedia(const DOM::DOMString &media) +{ + setAttribute("media", media); +} + +DOM::DOMString SVGStyleElementImpl::media() const +{ + return getAttribute("media"); +} + +void SVGStyleElementImpl::setTitle(const DOM::DOMString &title) +{ + setAttribute("title", title); +} + +DOM::DOMString SVGStyleElementImpl::title() const +{ + return getAttribute("title"); +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGStyleElementImpl::s_hashTable 5 + xmlspace SVGStyleElementImpl::Xmlspace DontDelete + type SVGStyleElementImpl::Type DontDelete + media SVGStyleElementImpl::Media DontDelete + title SVGStyleElementImpl::Title DontDelete +@end +*/ + +Value SVGStyleElementImpl::getValueProperty(ExecState *, int token) const +{ + //KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case Xmlspace: + return String(xmlspace()); + case Type: + return String(type()); + case Media: + return String(media()); + case Title: + return String(title()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGStyleElementImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int) +{ + switch(token) + { + case Xmlspace: + setXmlspace(value.toString(exec).string()); + break; + case Type: + setType(value.toString(exec).string()); + break; + case Media: + setMedia(value.toString(exec).string()); + break; + case Title: + setTitle(value.toString(exec).string()); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + break; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGStyleElementImpl.h b/ksvg/impl/SVGStyleElementImpl.h new file mode 100644 index 00000000..fcf7b152 --- /dev/null +++ b/ksvg/impl/SVGStyleElementImpl.h @@ -0,0 +1,72 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGStyleElementImpl_H +#define SVGStyleElementImpl_H + +#include + +#include "SVGElementImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGStyleElementImpl : public SVGElementImpl +{ +public: + SVGStyleElementImpl(DOM::ElementImpl *); + virtual ~SVGStyleElementImpl(); + + void setXmlspace(const DOM::DOMString &xmlspace); + DOM::DOMString xmlspace() const; + + void setType(const DOM::DOMString &type); + DOM::DOMString type() const; + + void setMedia(const DOM::DOMString &media); + DOM::DOMString media() const; + + void setTitle(const DOM::DOMString &title); + DOM::DOMString title() const; + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + Xmlspace, Type, Media, Title + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGStyleElementImpl, "style") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGSwitchElementImpl.cc b/ksvg/impl/SVGSwitchElementImpl.cc new file mode 100644 index 00000000..613a1982 --- /dev/null +++ b/ksvg/impl/SVGSwitchElementImpl.cc @@ -0,0 +1,58 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGDocumentImpl.h" +#include "SVGSwitchElementImpl.h" +#include "KSVGCanvas.h" + +using namespace KSVG; + +SVGSwitchElementImpl::SVGSwitchElementImpl(DOM::ElementImpl *impl) : SVGContainerImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl() +{ +} + +SVGSwitchElementImpl::~SVGSwitchElementImpl() +{ +} + +void SVGSwitchElementImpl::createItem(KSVGCanvas *c) +{ + if(!c) + c = ownerDoc()->canvas(); + + DOM::Node node = firstChild(); + for(; !node.isNull(); node = node.nextSibling()) + { + SVGElementImpl *element = ownerDoc()->getElementFromHandle(node.handle()); + SVGShapeImpl *shape = dynamic_cast(element); + SVGTestsImpl *tests = dynamic_cast(element); + SVGStylableImpl *style = dynamic_cast(element); + + bool ok = tests ? tests->ok() : true; + + if(element && shape && ok && style->getVisible() && style->getDisplay() && (shape->directRender() || !directRender())) + { + element->createItem(c); + break; + } + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGSwitchElementImpl.h b/ksvg/impl/SVGSwitchElementImpl.h new file mode 100644 index 00000000..2b29d2a4 --- /dev/null +++ b/ksvg/impl/SVGSwitchElementImpl.h @@ -0,0 +1,62 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGSwitchElementImpl_H +#define SVGSwitchElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGTestsImpl.h" +#include "SVGStylableImpl.h" +#include "SVGContainerImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGTransformableImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +namespace KSVG +{ + +class SVGSwitchElementImpl : public SVGContainerImpl, + public SVGTestsImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGTransformableImpl +{ +public: + SVGSwitchElementImpl(DOM::ElementImpl *); + virtual ~SVGSwitchElementImpl(); + + virtual void createItem(KSVGCanvas *c = 0); + virtual bool isContainer() const { return true; } + +public: + KSVG_BRIDGE + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +KSVG_REGISTER_ELEMENT(SVGSwitchElementImpl, "switch") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGSymbolElementImpl.cc b/ksvg/impl/SVGSymbolElementImpl.cc new file mode 100644 index 00000000..da0b5b90 --- /dev/null +++ b/ksvg/impl/SVGSymbolElementImpl.cc @@ -0,0 +1,106 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGRectImpl.h" +#include "SVGMatrixImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGAnimatedRectImpl.h" +#include "SVGSymbolElementImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGPreserveAspectRatioImpl.h" +#include "SVGAnimatedPreserveAspectRatioImpl.h" +#include "KSVGCanvas.h" + +using namespace KSVG; + +#include "SVGSymbolElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" + +SVGSymbolElementImpl::SVGSymbolElementImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGFitToViewBoxImpl() +{ + KSVG_EMPTY_FLAGS + + m_width = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this); + m_width->ref(); + + m_height = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this); + m_height->ref(); +} + +SVGSymbolElementImpl::~SVGSymbolElementImpl() +{ + if(m_width) + m_width->deref(); + if(m_height) + m_height->deref(); +} +/* +@namespace KSVG +@begin SVGSymbolElementImpl::s_hashTable 3 + width SVGSymbolElementImpl::Width DontDelete|ReadOnly + height SVGSymbolElementImpl::Height DontDelete|ReadOnly +@end +*/ + +Value SVGSymbolElementImpl::getValueProperty(ExecState *exec, int token) const +{ + KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case Width: + if(!attributeMode) + return m_width->cache(exec); + else + return Number(m_width->baseVal()->value()); + case Height: + if(!attributeMode) + return m_height->cache(exec); + else + return Number(m_height->baseVal()->value()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGSymbolElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case Width: + m_width->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + case Height: + m_height->baseVal()->setValueAsString(value.toString(exec).qstring()); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGSymbolElementImpl.h b/ksvg/impl/SVGSymbolElementImpl.h new file mode 100644 index 00000000..19278ea0 --- /dev/null +++ b/ksvg/impl/SVGSymbolElementImpl.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGSymbolElementImpl_H +#define SVGSymbolElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGShapeImpl.h" +#include "SVGStylableImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGFitToViewBoxImpl.h" +#include "SVGTransformableImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +namespace KSVG +{ + +class SVGFitToViewBoxImpl; +class SVGAnimatedLengthImpl; +class SVGSymbolElementImpl : public SVGShapeImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGFitToViewBoxImpl +{ +public: + SVGSymbolElementImpl(DOM::ElementImpl *); + virtual ~SVGSymbolElementImpl(); + + virtual bool isContainer() const { return true; } + virtual bool directRender() { return false; } + +private: + SVGAnimatedLengthImpl *m_width; + SVGAnimatedLengthImpl *m_height; + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + Width, Height + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGSymbolElementImpl, "symbol") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTRefElementImpl.cc b/ksvg/impl/SVGTRefElementImpl.cc new file mode 100644 index 00000000..c1c7e540 --- /dev/null +++ b/ksvg/impl/SVGTRefElementImpl.cc @@ -0,0 +1,76 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGTRefElementImpl.h" +#include "SVGTextElementImpl.h" +#include "SVGAnimatedStringImpl.h" + +#include "KSVGLoader.h" + +using namespace KSVG; + +SVGTRefElementImpl::SVGTRefElementImpl(DOM::ElementImpl *impl) : SVGTSpanElementImpl(impl), SVGURIReferenceImpl() +{ +} + +SVGTRefElementImpl::~SVGTRefElementImpl() +{ +} + +void SVGTRefElementImpl::setAttributes() +{ + SVGTSpanElementImpl::setAttributes(); + + DOM::DOMString _href = href()->baseVal(); + + if(!_href.isNull()) + href()->setBaseVal(DOM::DOMString(SVGURIReferenceImpl::getTarget(_href.string()))); + + // get the text of the referenced element + QString text; + + QString url = _href.string().stripWhiteSpace(), filename, id; + if(!SVGURIReferenceImpl::parseURIReference(url, filename, id)) + return; + + if(!filename.isEmpty()) // a reference into another svg + text = KSVGLoader::getCharacterData(KURL(ownerDoc()->baseUrl().path(), filename), id); + else + { + // a reference to an element in this svg + SVGElementImpl *target = ownerSVGElement()->getElementById(id); + SVGTextElementImpl *textTarget = dynamic_cast(target); + + if(textTarget) + text = textTarget->text(); + } + + text = handleText(text); + + if(!text.isEmpty()) + { + DOM::Text impl = static_cast(ownerDoc())->createTextNode(text); + appendChild(impl); + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTRefElementImpl.h b/ksvg/impl/SVGTRefElementImpl.h new file mode 100644 index 00000000..60d82231 --- /dev/null +++ b/ksvg/impl/SVGTRefElementImpl.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTRefElementImpl_H +#define SVGTRefElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGTSpanElementImpl.h" +#include "SVGURIReferenceImpl.h" + +namespace KSVG +{ + +class SVGTRefElementImpl : public SVGTSpanElementImpl, + public SVGURIReferenceImpl +{ +public: + SVGTRefElementImpl(DOM::ElementImpl *); + virtual ~SVGTRefElementImpl(); + virtual void setAttributes(); + +public: + KSVG_BRIDGE + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +KSVG_REGISTER_ELEMENT(SVGTRefElementImpl, "tref") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTSpanElementImpl.cc b/ksvg/impl/SVGTSpanElementImpl.cc new file mode 100644 index 00000000..7265c66e --- /dev/null +++ b/ksvg/impl/SVGTSpanElementImpl.cc @@ -0,0 +1,64 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGDocumentImpl.h" +#include "SVGTextElementImpl.h" +#include "SVGTSpanElementImpl.h" +#include "SVGAnimatedLengthListImpl.h" + +#include "KSVGCanvas.h" +#include "KSVGTextChunk.h" + +using namespace KSVG; +using namespace KJS; + +SVGTSpanElementImpl::SVGTSpanElementImpl(DOM::ElementImpl *impl) : SVGTextPositioningElementImpl(impl) +{ +} + +SVGTSpanElementImpl::~SVGTSpanElementImpl() +{ +} + +long SVGTSpanElementImpl::getNumberOfChars() +{ + return text().length(); +} + +QString SVGTSpanElementImpl::text() +{ + // Otherwhise some js scripts which require a child, don't work (Niko) + if(!hasChildNodes()) + { + DOM::Text impl = static_cast(ownerDoc())->createTextNode(DOM::DOMString("")); + appendChild(impl); + } + + return textDirectionAwareText(); +} + +void SVGTSpanElementImpl::setAttributes() +{ + SVGTextPositioningElementImpl::setAttributes(); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTSpanElementImpl.h b/ksvg/impl/SVGTSpanElementImpl.h new file mode 100644 index 00000000..26e4903d --- /dev/null +++ b/ksvg/impl/SVGTSpanElementImpl.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTSpanElementImpl_H +#define SVGTSpanElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGTextPositioningElementImpl.h" + +namespace KSVG +{ + +class SVGTSpanElementImpl : public SVGTextPositioningElementImpl +{ +public: + SVGTSpanElementImpl(DOM::ElementImpl *); + virtual ~SVGTSpanElementImpl(); + + QString text(); + + virtual long getNumberOfChars(); + + virtual void setAttributes(); + +public: + KSVG_BRIDGE + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +KSVG_REGISTER_ELEMENT(SVGTSpanElementImpl, "tspan") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTestsImpl.cc b/ksvg/impl/SVGTestsImpl.cc new file mode 100644 index 00000000..8bbccf80 --- /dev/null +++ b/ksvg/impl/SVGTestsImpl.cc @@ -0,0 +1,178 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include + +#include "SVGTestsImpl.h" +#include "SVGStringListImpl.h" + +using namespace KSVG; + +#include "SVGTestsImpl.lut.h" + +SVGTestsImpl::SVGTestsImpl() +{ + KSVG_EMPTY_FLAGS + + m_requiredFeatures = new SVGStringListImpl(); + m_requiredFeatures->ref(); + + m_requiredExtensions = new SVGStringListImpl(); + m_requiredExtensions->ref(); + + m_systemLanguage = new SVGStringListImpl(); + m_systemLanguage->ref(); +} + +SVGTestsImpl::~SVGTestsImpl() +{ + if(m_requiredFeatures) + m_requiredFeatures->deref(); + if(m_requiredExtensions) + m_requiredExtensions->deref(); + if(m_systemLanguage) + m_systemLanguage->deref(); +} + +void SVGTestsImpl::parseRequiredFeatures(const QString &/*value*/) +{ + // FIXME +} + +void SVGTestsImpl::parseRequiredExtensions(const QString &value) +{ + m_requiredExtensions->appendItem(new SharedString(value)); +} + +void SVGTestsImpl::parseSystemLanguage(const QString &value) +{ + m_systemLanguage->appendItem(new SharedString(value)); +} + +SVGStringListImpl *SVGTestsImpl::requiredFeatures() const +{ + return m_requiredFeatures; +} + +SVGStringListImpl *SVGTestsImpl::requiredExtensions() const +{ + return m_requiredExtensions; +} + +SVGStringListImpl *SVGTestsImpl::systemLanguage() const +{ + return m_systemLanguage; +} + +bool SVGTestsImpl::ok() +{ + for(unsigned int i = 0;i < m_requiredExtensions->numberOfItems();i++) + { + // FIXME + return false; + } + for(unsigned int i = 0;i < m_systemLanguage->numberOfItems();i++) + { + QString value = m_systemLanguage->getItem(i)->string(); + if(value.isEmpty() || value != (KGlobal::locale()->language()).left(2)) + return false; + } + return true; +} + +bool SVGTestsImpl::hasExtension(const DOM::DOMString &/*extension*/) +{ + return false; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGTestsImpl::s_hashTable 5 + requiredFeatures SVGTestsImpl::RequiredFeatures DontDelete|ReadOnly + requiredExtensions SVGTestsImpl::RequiredExtensions DontDelete|ReadOnly + systemLanguage SVGTestsImpl::SystemLanguage DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGTestsImplProto::s_hashTable 2 + hasExtension SVGTestsImpl::HasExtension DontDelete|Function 1 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGTests", SVGTestsImplProto, SVGTestsImplProtoFunc) + +Value SVGTestsImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case RequiredFeatures: + return m_requiredFeatures->cache(exec); + case RequiredExtensions: + return m_requiredExtensions->cache(exec); + case SystemLanguage: + return m_systemLanguage->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGTestsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case RequiredFeatures: + parseRequiredFeatures(value.toString(exec).qstring()); + break; + case RequiredExtensions: + parseRequiredExtensions(value.toString(exec).qstring()); + break; + case SystemLanguage: + parseSystemLanguage(value.toString(exec).qstring()); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +Value SVGTestsImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGTestsImpl) + + switch(id) + { + case SVGTestsImpl::HasExtension: + return Boolean(obj->hasExtension(args[0].toString(exec).string())); + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTestsImpl.h b/ksvg/impl/SVGTestsImpl.h new file mode 100644 index 00000000..c5b05a5f --- /dev/null +++ b/ksvg/impl/SVGTestsImpl.h @@ -0,0 +1,77 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTestsImpl_H +#define SVGTestsImpl_H + +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGStringListImpl; +class SVGTestsImpl +{ +public: + SVGTestsImpl(); + ~SVGTestsImpl(); + + void parseRequiredFeatures(const QString &value); + void parseRequiredExtensions(const QString &value); + void parseSystemLanguage(const QString &value); + + SVGStringListImpl *requiredFeatures() const; + SVGStringListImpl *requiredExtensions() const; + SVGStringListImpl *systemLanguage() const; + + bool ok(); + bool hasExtension(const DOM::DOMString &extension); + +private: + SVGStringListImpl *m_requiredFeatures; + SVGStringListImpl *m_requiredExtensions; + SVGStringListImpl *m_systemLanguage; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + RequiredFeatures, RequiredExtensions, SystemLanguage, + // Functions + HasExtension + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +KSVG_DEFINE_PROTOTYPE(SVGTestsImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGTestsImplProtoFunc, SVGTestsImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTextContentElementImpl.cc b/ksvg/impl/SVGTextContentElementImpl.cc new file mode 100644 index 00000000..f51d8807 --- /dev/null +++ b/ksvg/impl/SVGTextContentElementImpl.cc @@ -0,0 +1,285 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include + +#include "Glyph.h" + +#include "SVGStringListImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGTextContentElementImpl.h" +#include "SVGTextElementImpl.h" +#include "SVGAnimatedEnumerationImpl.h" +#include "SVGDocumentImpl.h" + +using namespace KSVG; + +#include "SVGTextContentElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_cacheimpl.h" + +SVGTextContentElementImpl::SVGTextContentElementImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this) +{ + KSVG_EMPTY_FLAGS + + m_lengthAdjust = new SVGAnimatedEnumerationImpl(); + m_lengthAdjust->ref(); + + // Spec: default value 'spacing' + m_lengthAdjust->setBaseVal(LENGTHADJUST_SPACING); + + m_textLength = new SVGAnimatedLengthImpl(); + m_textLength->baseVal()->setValueAsString("-1"); + m_textLength->ref(); +} + +SVGTextContentElementImpl::~SVGTextContentElementImpl() +{ + if(m_lengthAdjust) + m_lengthAdjust->deref(); + if(m_textLength) + m_textLength->deref(); +} + +QString SVGTextContentElementImpl::textDirectionAwareText() +{ + QString text; + + if(hasChildNodes()) + { + bool ltr = getTextDirection() == LTR; + DOM::Node node = ltr ? firstChild() : lastChild(); + + for(; !node.isNull(); node = ltr ? node.nextSibling() : node.previousSibling()) + { + if(node.nodeType() == TEXT_NODE) + { + DOM::Text textNode = node; + QString temp = textNode.data().string(); + + if(!ltr) + { + QString convert = temp; + + for(int i = temp.length(); i > 0; i--) + convert[temp.length() - i] = temp[i - 1]; + + text += convert; + } + else + text += temp; + } + else + return text; + } + } + + return text; +} + +T2P::GlyphLayoutParams *SVGTextContentElementImpl::layoutParams() const +{ + SVGStylableImpl *style = const_cast(this); + + T2P::GlyphLayoutParams *params = new T2P::GlyphLayoutParams(); + params->setTb(style->getTextWritingMode() == TB); + params->setUseBidi(style->getTextUnicodeBidi() == UBNORMAL); + if(!dynamic_cast(m_object)) // not allowed for + params->setBaselineShift(style->getBaselineShift().latin1()); + + bool worked = true; + int deg = style->getGlyphOrientationVertical().toInt(&worked); + if(!worked) + params->setGlyphOrientationVertical(-90); + else + params->setGlyphOrientationVertical(deg); + + worked = true; + deg = style->getGlyphOrientationHorizontal().toInt(&worked); + if(!worked) + params->setGlyphOrientationHorizontal(-90); + else + params->setGlyphOrientationHorizontal(deg); + + SVGLengthImpl *length = new SVGLengthImpl(LENGTHMODE_OTHER, const_cast(this)); + length->ref(); + + if(style->getLetterSpacing() != "normal" && style->getLetterSpacing() != "inherit") + length->setValueAsString(DOM::DOMString(style->getLetterSpacing())); + params->setLetterSpacing(length->value()); + + if(style->getWordSpacing() != "normal" && style->getWordSpacing() != "inherit") + length->setValueAsString(DOM::DOMString(style->getWordSpacing())); + params->setWordSpacing(length->value()); + + length->deref(); + + return params; +} + +SVGAnimatedLengthImpl *SVGTextContentElementImpl::textLength() const +{ + return m_textLength; +} + +SVGAnimatedEnumerationImpl *SVGTextContentElementImpl::lengthAdjust() const +{ + return m_lengthAdjust; +} + +long SVGTextContentElementImpl::getNumberOfChars() +{ + return 0; +} + +float SVGTextContentElementImpl::getComputedTextLength() +{ + return 0.0; +} + +/* +float SVGTextContentElementImpl::getSubStringLength(const unsigned long &charnum,const unsigned long &nchars) +{ +} + +SVGPoint SVGTextContentElementImpl::getStartPositionOfChar(const unsigned long &charnum) +{ +} + +SVGPoint SVGTextContentElementImpl::getEndPositionOfChar(const unsigned long &charnum) +{ +} + +SVGRect SVGTextContentElementImpl::getExtentOfChar(const unsigned long &charnum) +{ +} + +float SVGTextContentElementImpl::getRotationOfChar(const unsigned long &charnum) +{ +} + +long SVGTextContentElementImpl::getCharNumAtPosition(const SVGPoint &point) +{ +} + +void SVGTextContentElementImpl::selectSubString(const unsigned long &charnum,const unsigned long &nchars) +{ +} +*/ + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGTextContentElementImpl::s_hashTable 3 + textLength SVGTextContentElementImpl::TextLength DontDelete|ReadOnly + lengthAdjust SVGTextContentElementImpl::LengthAdjust DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGTextContentElementImplProto::s_hashTable 11 + getNumberOfChars SVGTextContentElementImpl::GetNumberOfChars DontDelete|Function 0 + getComputedTextLength SVGTextContentElementImpl::GetComputedTextLength DontDelete|Function 0 + getSubStringLength SVGTextContentElementImpl::GetSubStringLength DontDelete|Function 2 + getStartPositionOfChar SVGTextContentElementImpl::GetStartPositionOfChar DontDelete|Function 1 + getEndPositionOfChar SVGTextContentElementImpl::GetEndPositionOfChar DontDelete|Function 1 + getExtentOfChar SVGTextContentElementImpl::GetExtentOfChar DontDelete|Function 1 + getRotationOfChar SVGTextContentElementImpl::GetRotationOfChar DontDelete|Function 1 + getCharNumAtPosition SVGTextContentElementImpl::GetCharNumAtPosition DontDelete|Function 1 + selectSubString SVGTextContentElementImpl::SelectSubString DontDelete|Function 2 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGTextContentElement", SVGTextContentElementImplProto, SVGTextContentElementImplProtoFunc) + +Value SVGTextContentElementImpl::getValueProperty(ExecState *, int token) const +{ + //KSVG_CHECK_ATTRIBUTE + + switch(token) + { + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGTextContentElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case TextLength: + m_textLength->baseVal()->setValueAsString(value.toString(exec).string()); + if(m_textLength->baseVal()->value() < 0) // A negative value is an error + gotError(i18n("Negative value for attribute textLength of element is illegal")); + break; + case LengthAdjust: + { + QString temp = value.toString(exec).qstring(); + if(temp == "spacingAndGlyphs") + m_lengthAdjust->setBaseVal(LENGTHADJUST_SPACINGANDGLYPHS); + else if(temp == "spacing") + m_lengthAdjust->setBaseVal(LENGTHADJUST_SPACING); + break; + } + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +Value SVGTextContentElementImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &) +{ + KSVG_CHECK_THIS(SVGTextContentElementImpl) + + switch(id) + { + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + +/* +@namespace KSVG +@begin SVGTextContentElementImplConstructor::s_hashTable 5 + LENGTHADJUST_UNKNOWN KSVG::LENGTHADJUST_UNKNOWN DontDelete|ReadOnly + LENGTHADJUST_SPACING KSVG::LENGTHADJUST_SPACING DontDelete|ReadOnly + LENGTHADJUST_SPACINGANDGLYPHS KSVG::LENGTHADJUST_SPACINGANDGLYPHS DontDelete|ReadOnly +@end +*/ + +Value SVGTextContentElementImplConstructor::getValueProperty(ExecState *, int token) const +{ + return Number(token); +} + +Value KSVG::getSVGTextContentElementImplConstructor(ExecState *exec) +{ + return cacheGlobalBridge(exec, "[[svgtextcontentelement.constructor]]"); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTextContentElementImpl.h b/ksvg/impl/SVGTextContentElementImpl.h new file mode 100644 index 00000000..26bbc041 --- /dev/null +++ b/ksvg/impl/SVGTextContentElementImpl.h @@ -0,0 +1,115 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTextContentElementImpl_H +#define SVGTextContentElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGShapeImpl.h" +#include "SVGTestsImpl.h" +#include "SVGStylableImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGTextContentElement.h" +#include "SVGExternalResourcesRequiredImpl.h" + +namespace T2P +{ + class GlyphLayoutParams; +} + +namespace KSVG +{ + +class SVGAnimatedLengthImpl; +class SVGAnimatedEnumerationImpl; +class SVGTextContentElementImpl : public SVGShapeImpl, + public SVGTestsImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl +{ +public: + SVGTextContentElementImpl(DOM::ElementImpl *impl); + virtual ~SVGTextContentElementImpl(); + + QString textDirectionAwareText(); + + virtual T2P::GlyphLayoutParams *layoutParams() const; + + SVGAnimatedLengthImpl *textLength() const; + SVGAnimatedEnumerationImpl *lengthAdjust() const; + + virtual long getNumberOfChars(); + float getComputedTextLength(); + +// float getSubStringLength(const unsigned long &charnum, const unsigned long &nchars); +// SVGPoint getStartPositionOfChar(const unsigned long &charnum); +// SVGPoint getEndPositionOfChar(const unsigned long &charnum); +// SVGRect getExtentOfChar(const unsigned long &charnum); +// float getRotationOfChar(const unsigned long &charnum); +// long getCharNumAtPosition(const SVGPoint &point); +// void selectSubString(const unsigned long &charnum, const unsigned long &nchars); + +private: + SVGAnimatedEnumerationImpl *m_lengthAdjust; + SVGAnimatedLengthImpl *m_textLength; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + TextLength, LengthAdjust, + // Functions + GetTextLength, GetLengthAdjust, + GetNumberOfChars, GetComputedTextLength, + GetSubStringLength, GetStartPositionOfChar, + GetEndPositionOfChar, GetExtentOfChar, + GetRotationOfChar, GetCharNumAtPosition, + SelectSubString + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +class SVGTextContentElementImplConstructor : public KJS::ObjectImp +{ +public: + SVGTextContentElementImplConstructor(KJS::ExecState *) { } + KJS::Value getValueProperty(KJS::ExecState *, int token) const; + + // no put - all read-only + KSVG_GET +}; + +KJS::Value getSVGTextContentElementImplConstructor(KJS::ExecState *exec); + +} + +KSVG_DEFINE_PROTOTYPE(SVGTextContentElementImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGTextContentElementImplProtoFunc, SVGTextContentElementImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTextElementImpl.cc b/ksvg/impl/SVGTextElementImpl.cc new file mode 100644 index 00000000..634c227d --- /dev/null +++ b/ksvg/impl/SVGTextElementImpl.cc @@ -0,0 +1,124 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGRectImpl.h" +#include "SVGEventImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGTextElementImpl.h" + +#include "CanvasItem.h" +#include "KSVGCanvas.h" + +using namespace KSVG; + +SVGTextElementImpl::SVGTextElementImpl(DOM::ElementImpl *impl) : SVGTextPositioningElementImpl(impl), SVGTransformableImpl() +{ + m_bboxX = 0; + m_bboxY = 0; + + m_bboxWidth = 0; + m_bboxHeight = 0; +} + +SVGTextElementImpl::~SVGTextElementImpl() +{ +} + +long SVGTextElementImpl::getNumberOfChars() +{ + return text().length(); +} + +QString SVGTextElementImpl::text() +{ + // Otherwhise some js scripts which require a child, don't work (Niko) + if(!hasChildNodes()) + { + DOM::Text impl = static_cast(ownerDoc())->createTextNode(DOM::DOMString("")); + appendChild(impl); + } + + return textDirectionAwareText(); +} + +SVGRectImpl *SVGTextElementImpl::getBBox() +{ + SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect(); + ret->setX(m_bboxX); + ret->setY(m_bboxY); + ret->setWidth(m_bboxWidth); + ret->setHeight(m_bboxHeight); + return ret; +} + +void SVGTextElementImpl::createItem(KSVGCanvas *c ) +{ + if(!c) + c = ownerDoc()->canvas(); + + if(!m_item) + { + m_item = c->createText(this); + // Set up bbox before insert(), as that may render the item + QRect rect = m_item->bbox(); + m_bboxX = rect.x(); + m_bboxY = rect.y(); + m_bboxWidth = rect.width(); + m_bboxHeight = rect.height(); + c->insert(m_item); + } +} + +bool SVGTextElementImpl::prepareMouseEvent(const QPoint &p, const QPoint &, SVGMouseEventImpl *mev) +{ + // TODO : pointer-events should be stored here, not in SVGStylableImpl. + SVGStylableImpl *style = dynamic_cast(this); + if(!style || style->getPointerEvents() == PE_NONE) + return false; + bool test = false; + switch(style->getPointerEvents()) + { + case PE_VISIBLE: test = style->getVisible(); break; + case PE_VISIBLE_PAINTED: test = style->getVisible() && (style->isStroked() || style->isFilled()) ; break; + case PE_VISIBLE_FILL: test = style->getVisible() && style->isFilled(); break; + case PE_VISIBLE_STROKE: test = style->getVisible() && style->isStroked(); break; + case PE_PAINTED: test = style->isStroked() || style->isFilled(); break; + case PE_FILL: test = style->isFilled(); break; + case PE_STROKE: test = style->isStroked(); break; + case PE_ALL: + default: test = true; + }; + + if(test) + { + if(m_item->bbox().contains(p)) + { + mev->setTarget(dynamic_cast(this)); + return true; + } + } + + return false; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTextElementImpl.h b/ksvg/impl/SVGTextElementImpl.h new file mode 100644 index 00000000..e0c2ca8d --- /dev/null +++ b/ksvg/impl/SVGTextElementImpl.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTextElementImpl_H +#define SVGTextElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGTransformableImpl.h" +#include "SVGTextPositioningElementImpl.h" + +namespace KSVG +{ + +class SVGRectImpl; +class SVGTextElementImpl : public SVGTextPositioningElementImpl, + public SVGTransformableImpl +{ +public: + SVGTextElementImpl(DOM::ElementImpl *); + virtual ~SVGTextElementImpl(); + + QString text(); + + virtual long getNumberOfChars(); + + virtual void createItem(KSVGCanvas *c = 0); + + virtual SVGRectImpl *getBBox(); + + virtual bool prepareMouseEvent(const QPoint &p, const QPoint &a, SVGMouseEventImpl *mev); + +private: + int m_bboxX, m_bboxY, m_bboxWidth, m_bboxHeight; + +public: + KSVG_BRIDGE + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +KSVG_REGISTER_ELEMENT(SVGTextElementImpl, "text") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTextPathElementImpl.cc b/ksvg/impl/SVGTextPathElementImpl.cc new file mode 100644 index 00000000..ec218046 --- /dev/null +++ b/ksvg/impl/SVGTextPathElementImpl.cc @@ -0,0 +1,240 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include + +#include "Glyph.h" + +#include "SVGDocumentImpl.h" +#include "SVGTextPathElement.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGTextPathElementImpl.h" +#include "SVGAnimatedEnumerationImpl.h" + +using namespace KSVG; + +#include "SVGTextPathElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_ecma.h" +#include "ksvg_cacheimpl.h" + +SVGTextPathElementImpl::SVGTextPathElementImpl(DOM::ElementImpl *impl) : SVGTextContentElementImpl(impl), SVGURIReferenceImpl() +{ + KSVG_EMPTY_FLAGS + + m_startOffset = new SVGAnimatedLengthImpl(); + m_startOffset->ref(); + + m_method = new SVGAnimatedEnumerationImpl(); + m_method->ref(); + + m_spacing = new SVGAnimatedEnumerationImpl(); + m_spacing->ref(); +} + +SVGTextPathElementImpl::~SVGTextPathElementImpl() +{ + if(m_startOffset) + m_startOffset->deref(); + if(m_method) + m_method->deref(); + if(m_spacing) + m_spacing->deref(); +} + +SVGAnimatedLengthImpl *SVGTextPathElementImpl::startOffset() const +{ + return m_startOffset; +} + +SVGAnimatedEnumerationImpl *SVGTextPathElementImpl::method() const +{ + return m_method; +} + +SVGAnimatedEnumerationImpl *SVGTextPathElementImpl::spacing() const +{ + return m_spacing; +} + +QString SVGTextPathElementImpl::text() +{ + // Otherwhise some js scripts which require a child, don't work (Niko) + if(!hasChildNodes()) + { + DOM::Text impl = static_cast(ownerDoc())->createTextNode(DOM::DOMString("")); + appendChild(impl); + } + + return textDirectionAwareText(); +} + +void SVGTextPathElementImpl::setAttributes() +{ + SVGElementImpl::setAttributes(); + + // Spec: if not specified, effect is as if a value of "0" were specified + if(KSVG_TOKEN_NOT_PARSED(StartOffset)) + KSVG_SET_ALT_ATTRIBUTE(StartOffset, "0") + + // Spec: if not specified, effect is as if a value of "align" were specified + if(KSVG_TOKEN_NOT_PARSED(Method)) + KSVG_SET_ALT_ATTRIBUTE(Method, "align") + + // Spec: if not specified, effect is as if a value of "exact" were specified + if(KSVG_TOKEN_NOT_PARSED(Spacing)) + KSVG_SET_ALT_ATTRIBUTE(Spacing, "exact") +} + +T2P::GlyphLayoutParams *SVGTextPathElementImpl::layoutParams() const +{ + T2P::GlyphLayoutParams *params = SVGTextContentElementImpl::layoutParams(); + params->setTextPathStartOffset(startOffset()->baseVal()->value()); + return params; +} + + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGTextPathElementImpl::s_hashTable 5 + startOffset SVGTextPathElementImpl::StartOffset DontDelete|ReadOnly + method SVGTextPathElementImpl::Method DontDelete|ReadOnly + spacing SVGTextPathElementImpl::Spacing DontDelete|ReadOnly +@end +*/ + +Value SVGTextPathElementImpl::getValueProperty(ExecState *exec, int token) const +{ + KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case StartOffset: + if(!attributeMode) + return m_startOffset->cache(exec); + else + return Number(m_startOffset->baseVal()->value()); + case Method: + if(!attributeMode) + return m_method->cache(exec); + else + return Number(m_method->baseVal()); + case Spacing: + if(!attributeMode) + return m_spacing->cache(exec); + else + return Number(m_spacing->baseVal()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGTextPathElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case StartOffset: + { + QString param = value.toString(exec).qstring(); + + if(param.endsWith("%")) + { + QString value = param.left(param.length() - 1); + bool ok = false; + double dValue = value.toDouble(&ok); + if(ok) + startOffset()->baseVal()->setValue(dValue / 100.0); + else + kdDebug() << "Couldn't parse startOffset: " << value << endl; + } + else + startOffset()->baseVal()->setValueAsString(value.toString(exec).qstring()); + + if(startOffset()->baseVal()->value() < 0) // A negative value is an error + gotError(i18n("Negative value for attribute startOffset of element is illegal")); + break; + } + case Method: + { + QString param = value.toString(exec).qstring(); + + if(param == "align") + method()->setBaseVal(TEXTPATH_METHODTYPE_ALIGN); + else if(param == "stretch") + method()->setBaseVal(TEXTPATH_METHODTYPE_STRETCH); + else + method()->setBaseVal(TEXTPATH_METHODTYPE_UNKNOWN); + + break; + } + case Spacing: + { + QString param = value.toString(exec).qstring(); + + if(param == "auto") + spacing()->setBaseVal(TEXTPATH_SPACINGTYPE_AUTO); + else if(param == "exact") + spacing()->setBaseVal(TEXTPATH_SPACINGTYPE_EXACT); + else + spacing()->setBaseVal(TEXTPATH_SPACINGTYPE_UNKNOWN); + + break; + } + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// CONSTANTS + +/* +@namespace KSVG +@begin SVGTextPathElementImplConstructor::s_hashTable 7 + TEXTPATH_METHODTYPE_UNKNOWN KSVG::TEXTPATH_METHODTYPE_UNKNOWN DontDelete|ReadOnly + TEXTPATH_METHODTYPE_ALIGN KSVG::TEXTPATH_METHODTYPE_ALIGN DontDelete|ReadOnly + TEXTPATH_METHODTYPE_STRETCH KSVG::TEXTPATH_METHODTYPE_STRETCH DontDelete|ReadOnly + TEXTPATH_SPACINGTYPE_UNKNOWN KSVG::TEXTPATH_SPACINGTYPE_UNKNOWN DontDelete|ReadOnly + TEXTPATH_SPACINGTYPE_AUTO KSVG::TEXTPATH_SPACINGTYPE_AUTO DontDelete|ReadOnly + TEXTPATH_SPACINGTYPE_EXACT KSVG::TEXTPATH_SPACINGTYPE_EXACT DontDelete|ReadOnly +@end +*/ + +using namespace KJS; + +Value SVGTextPathElementImplConstructor::getValueProperty(ExecState *, int token) const +{ + return Number(token); +} + +Value KSVG::getSVGTextPathElementImplConstructor(ExecState *exec) +{ + return cacheGlobalBridge(exec, "[[svgtextpathelement.constructor]]"); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTextPathElementImpl.h b/ksvg/impl/SVGTextPathElementImpl.h new file mode 100644 index 00000000..8231f0cd --- /dev/null +++ b/ksvg/impl/SVGTextPathElementImpl.h @@ -0,0 +1,84 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTextPathElementImpl_H +#define SVGTextPathElementImpl_H + +#include "SVGURIReferenceImpl.h" +#include "SVGTextContentElementImpl.h" + +namespace KSVG +{ + +class SVGTextPathElementImpl : public SVGTextContentElementImpl, + public SVGURIReferenceImpl +{ +public: + SVGTextPathElementImpl(DOM::ElementImpl *); + virtual ~SVGTextPathElementImpl(); + + QString text(); + + SVGAnimatedLengthImpl *startOffset() const; + SVGAnimatedEnumerationImpl *method() const; + SVGAnimatedEnumerationImpl *spacing() const; + + virtual void setAttributes(); + virtual T2P::GlyphLayoutParams *layoutParams() const; + +private: + SVGAnimatedLengthImpl *m_startOffset; + SVGAnimatedEnumerationImpl *m_method; + SVGAnimatedEnumerationImpl *m_spacing; + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + StartOffset, Method, Spacing + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +class SVGTextPathElementImplConstructor : public KJS::ObjectImp +{ +public: + SVGTextPathElementImplConstructor(KJS::ExecState *) { } + KJS::Value getValueProperty(KJS::ExecState *, int token) const; + + // no put - all read-only + KSVG_GET +}; + +KJS::Value getSVGTextPathElementImplConstructor(KJS::ExecState *exec); + +KSVG_REGISTER_ELEMENT(SVGTextPathElementImpl, "textPath") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTextPositioningElementImpl.cc b/ksvg/impl/SVGTextPositioningElementImpl.cc new file mode 100644 index 00000000..924fd091 --- /dev/null +++ b/ksvg/impl/SVGTextPositioningElementImpl.cc @@ -0,0 +1,198 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGHelperImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGAnimatedLengthListImpl.h" +#include "SVGAnimatedNumberListImpl.h" +#include "SVGTextPositioningElementImpl.h" + +using namespace KSVG; + +#include "SVGTextPositioningElementImpl.lut.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGTextPositioningElementImpl::SVGTextPositioningElementImpl(DOM::ElementImpl *impl) : SVGTextContentElementImpl(impl) +{ + KSVG_EMPTY_FLAGS + + m_x = new SVGAnimatedLengthListImpl(); + m_x->ref(); + + m_y = new SVGAnimatedLengthListImpl(); + m_y->ref(); + + m_dx = new SVGAnimatedLengthListImpl(); + m_dx->ref(); + + m_dy = new SVGAnimatedLengthListImpl(); + m_dy->ref(); + + m_rotate = new SVGAnimatedNumberListImpl(); + m_rotate->ref(); +} + +SVGTextPositioningElementImpl::~SVGTextPositioningElementImpl() +{ + if(m_x) + m_x->deref(); + if(m_y) + m_y->deref(); + if(m_dx) + m_dx->deref(); + if(m_dy) + m_dy->deref(); + if(m_rotate) + m_rotate->deref(); +} + +SVGAnimatedLengthListImpl *SVGTextPositioningElementImpl::x() +{ + return m_x; +} + +SVGAnimatedLengthListImpl *SVGTextPositioningElementImpl::y() +{ + return m_y; +} + +SVGAnimatedLengthListImpl *SVGTextPositioningElementImpl::dx() +{ + return m_dx; +} + +SVGAnimatedLengthListImpl *SVGTextPositioningElementImpl::dy() +{ + return m_dy; +} + +SVGAnimatedNumberListImpl *SVGTextPositioningElementImpl::rotate() +{ + return m_rotate; +} + +/* +@namespace KSVG +@begin SVGTextPositioningElementImpl::s_hashTable 7 + x SVGTextPositioningElementImpl::X DontDelete|ReadOnly + y SVGTextPositioningElementImpl::Y DontDelete|ReadOnly + dx SVGTextPositioningElementImpl::Dx DontDelete|ReadOnly + dy SVGTextPositioningElementImpl::Dy DontDelete|ReadOnly + rotate SVGTextPositioningElementImpl::Rotate DontDelete|ReadOnly +@end +*/ + +Value SVGTextPositioningElementImpl::getValueProperty(ExecState *exec, int token) const +{ + KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case X: + if(!attributeMode) + return m_x->cache(exec); + else + return Number(m_x->baseVal()->getItem(0)->value()); + case Y: + if(!attributeMode) + return m_y->cache(exec); + else + return Number(m_y->baseVal()->getItem(0)->value()); + case Dx: + if(!attributeMode) + return m_dx->cache(exec); + else + return Number(m_dx->baseVal()->getItem(0)->value()); + case Dy: + if(!attributeMode) + return m_dy->cache(exec); + else + return Number(m_dy->baseVal()->getItem(0)->value()); + case Rotate: + if(!attributeMode) + return m_rotate->cache(exec); + else + return Number(m_rotate->baseVal()->getItem(0)->value()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGTextPositioningElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case X: + x()->baseVal()->clear(); + SVGHelperImpl::parseLengthList(x(), value.toString(exec).qstring(), LENGTHMODE_WIDTH, this); + break; + case Y: + y()->baseVal()->clear(); + SVGHelperImpl::parseLengthList(y(), value.toString(exec).qstring(), LENGTHMODE_HEIGHT, this); + break; + case Dx: + dx()->baseVal()->clear(); + SVGHelperImpl::parseLengthList(dx(), value.toString(exec).qstring(), LENGTHMODE_WIDTH, this); + break; + case Dy: + dy()->baseVal()->clear(); + SVGHelperImpl::parseLengthList(dy(), value.toString(exec).qstring(), LENGTHMODE_HEIGHT, this); + break; + case Rotate: + { + rotate()->baseVal()->clear(); + + SVGNumberImpl *number = SVGSVGElementImpl::createSVGNumber(); + number->setValue(value.toNumber(exec)); + rotate()->baseVal()->appendItem(number); + break; + } + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +void SVGTextPositioningElementImpl::setAttributes() +{ + SVGElementImpl::setAttributes(); + + if(tagName() != "text") + return; + + // Spec: If the attribute is not specified, the effect is as if a value of "0" were specified. + if(KSVG_TOKEN_NOT_PARSED(X)) + KSVG_SET_ALT_ATTRIBUTE(X, "0") + + // Spec: If the attribute is not specified, the effect is as if a value of "0" were specified. + if(KSVG_TOKEN_NOT_PARSED(Y)) + KSVG_SET_ALT_ATTRIBUTE(Y, "0") +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTextPositioningElementImpl.h b/ksvg/impl/SVGTextPositioningElementImpl.h new file mode 100644 index 00000000..c80b48ff --- /dev/null +++ b/ksvg/impl/SVGTextPositioningElementImpl.h @@ -0,0 +1,83 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTextPositioningElementImpl_H +#define SVGTextPositioningElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGTextContentElementImpl.h" + +namespace KJS +{ + class Value; + class Object; + class UString; + class ExecState; +} + +namespace KSVG +{ + +class SVGShapeImpl; +class GlyphLayoutParams; +class SVGAnimatedLengthListImpl; +class SVGAnimatedNumberListImpl; + +class SVGTextPositioningElementImpl : public SVGTextContentElementImpl +{ +public: + SVGTextPositioningElementImpl(DOM::ElementImpl *impl); + virtual ~SVGTextPositioningElementImpl(); + + SVGAnimatedLengthListImpl *x(); + SVGAnimatedLengthListImpl *y(); + SVGAnimatedLengthListImpl *dx(); + SVGAnimatedLengthListImpl *dy(); + SVGAnimatedNumberListImpl *rotate(); + + virtual void setAttributes(); + +private: + SVGAnimatedLengthListImpl *m_x; + SVGAnimatedLengthListImpl *m_y; + SVGAnimatedLengthListImpl *m_dx; + SVGAnimatedLengthListImpl *m_dy; + SVGAnimatedNumberListImpl *m_rotate; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + X, Y, Dx, Dy, Rotate + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTimeScheduler.cc b/ksvg/impl/SVGTimeScheduler.cc new file mode 100644 index 00000000..efff77ac --- /dev/null +++ b/ksvg/impl/SVGTimeScheduler.cc @@ -0,0 +1,234 @@ +/* + Copyright (C) 2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "KSVGCanvas.h" +#include "CanvasItem.h" +#include "SVGShapeImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGTimeScheduler.moc" + +using namespace KSVG; + +SVGTimer::SVGTimer(QObject *scheduler, unsigned int ms, bool singleShot) +{ + m_ms = ms; + m_singleShot = singleShot; + m_timer = new QTimer(scheduler); +} + +SVGTimer::~SVGTimer() +{ + delete m_timer; +} + +bool SVGTimer::operator==(const QTimer *timer) +{ + return (m_timer == timer); +} + +const QTimer *SVGTimer::qtimer() const +{ + return m_timer; +} + +void SVGTimer::start(QObject *receiver, const char *member) +{ + QObject::connect(m_timer, SIGNAL(timeout()), receiver, member); + m_timer->start(m_ms, m_singleShot); +} + +void SVGTimer::stop() +{ + m_timer->stop(); +} + +bool SVGTimer::isActive() const +{ + return m_timer->isActive(); +} + +unsigned int SVGTimer::ms() const +{ + return m_ms; +} + +bool SVGTimer::singleShot() const +{ + return m_singleShot; +} + +void SVGTimer::notifyAll() +{ + if(m_notifyList.isEmpty()) + return; + + QValueList elements; + for(unsigned int i = m_notifyList.count();i > 0; i--) + { + SVGElementImpl *element = m_notifyList[i - 1]; + if(!element) + continue; + + SVGAnimationElementImpl *animation = dynamic_cast(element); + if(animation) + { + animation->handleTimerEvent(); + + SVGElementImpl *target = animation->targetElement(); + if(!elements.contains(target)) + elements.append(target); + } + } + + // Optimized update logic (to avoid 4 updates, on the same element) + QValueList::iterator it2; + for(it2 = elements.begin(); it2 != elements.end(); ++it2) + { + SVGShapeImpl *shape = dynamic_cast(*it2); + if(shape && shape->item()) + shape->item()->update(UPDATE_TRANSFORM); + } +} + +void SVGTimer::addNotify(SVGElementImpl *element) +{ + m_notifyList.append(element); +} + +void SVGTimer::removeNotify(SVGElementImpl *element) +{ + m_notifyList.remove(element); + + if(m_notifyList.isEmpty()) + stop(); +} + +const unsigned int SVGTimeScheduler::staticTimerInterval = 15; // milliseconds + +SVGTimeScheduler::SVGTimeScheduler(SVGDocumentImpl *doc) : QObject(), m_doc(doc) +{ + // Create static interval timers but don't start it yet! + m_intervalTimer = new SVGTimer(this, staticTimerInterval, false); + m_creationTime.start(); +} + +SVGTimeScheduler::~SVGTimeScheduler() +{ + // Usually singleShot timers cleanup themselves, after usage + SVGTimerList::iterator it; + for(it = m_timerList.begin(); it != m_timerList.end(); ++it) + { + SVGTimer *svgTimer = *it; + delete svgTimer; + } + delete m_intervalTimer; +} + +void SVGTimeScheduler::addTimer(SVGElementImpl *element, unsigned int ms) +{ + SVGTimer *svgTimer = new SVGTimer(this, ms, true); + svgTimer->addNotify(element); + m_timerList.append(svgTimer); +} + +void SVGTimeScheduler::connectIntervalTimer(SVGElementImpl *element) +{ + m_intervalTimer->addNotify(element); +} + +void SVGTimeScheduler::disconnectIntervalTimer(SVGElementImpl *element) +{ + m_intervalTimer->removeNotify(element); +} + +void SVGTimeScheduler::startAnimations() +{ + SVGTimerList::iterator it; + for(it = m_timerList.begin(); it != m_timerList.end(); ++it) + { + SVGTimer *svgTimer = *it; + if(svgTimer && !svgTimer->isActive()) + svgTimer->start(this, SLOT(slotTimerNotify())); + } +} + +void SVGTimeScheduler::toggleAnimations() +{ + if(m_intervalTimer->isActive()) + m_intervalTimer->stop(); + else + m_intervalTimer->start(this, SLOT(slotTimerNotify())); +} + +bool SVGTimeScheduler::animationsPaused() const +{ + return !m_intervalTimer->isActive(); +} + +void SVGTimeScheduler::slotTimerNotify() +{ + QTimer *senderTimer = const_cast(static_cast(sender())); + + SVGTimer *svgTimer = 0; + SVGTimerList::iterator it; + for(it = m_timerList.begin(); it != m_timerList.end(); ++it) + { + SVGTimer *cur = *it; + if(*cur == senderTimer) + { + svgTimer = cur; + break; + } + } + + if(!svgTimer) + { + svgTimer = (*m_intervalTimer == senderTimer) ? m_intervalTimer : 0; + + if(!svgTimer) + return; + } + + svgTimer->notifyAll(); + + // Animations need direct updates + if(m_doc->canvas()) + m_doc->canvas()->update(); + emit m_doc->finishedRendering(); + + if(svgTimer->singleShot()) + { + m_timerList.remove(svgTimer); + delete svgTimer; + } + + // The singleShot timers of ie. with begin="3s" are notified + // by the previous call, and now all connections to the interval timer + // are created and now we just need to fire that timer (Niko) + if(svgTimer != m_intervalTimer && !m_intervalTimer->isActive()) + m_intervalTimer->start(this, SLOT(slotTimerNotify())); +} + +float SVGTimeScheduler::elapsed() const +{ + return float(m_creationTime.elapsed()) / 1000.0; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTimeScheduler.h b/ksvg/impl/SVGTimeScheduler.h new file mode 100644 index 00000000..ae4c6d37 --- /dev/null +++ b/ksvg/impl/SVGTimeScheduler.h @@ -0,0 +1,104 @@ +/* + Copyright (C) 2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTimeScheduler_H +#define SVGTimeScheduler_H + +#include +#include +#include +#include + +#include "SVGElementImpl.h" +#include "SVGAnimationElementImpl.h" + +namespace KSVG +{ + +typedef QValueList SVGNotifyList; +class SVGTimer +{ +public: + SVGTimer(QObject *scheduler, unsigned int ms, bool singleShot); + ~SVGTimer(); + + bool operator==(const QTimer *timer); + const QTimer *qtimer() const; + + void start(QObject *receiver, const char *member); + void stop(); + + bool isActive() const; + + unsigned int ms() const; + bool singleShot() const; + + void notifyAll(); + void addNotify(SVGElementImpl *element); + void removeNotify(SVGElementImpl *element); + +private: + unsigned int m_ms; + bool m_invoked, m_singleShot; + + QTimer *m_timer; + SVGNotifyList m_notifyList; +}; + +typedef QValueList SVGTimerList; +class SVGDocumentImpl; +class SVGTimeScheduler : public QObject +{ +Q_OBJECT +public: + SVGTimeScheduler(SVGDocumentImpl *doc); + ~SVGTimeScheduler(); + + // Adds singleShot Timers + void addTimer(SVGElementImpl *element, unsigned int ms); + + // (Dis-)Connects to interval timer with ms = 'staticTimerInterval' + void connectIntervalTimer(SVGElementImpl *element); + void disconnectIntervalTimer(SVGElementImpl *element); + + void startAnimations(); + void toggleAnimations(); + bool animationsPaused() const; + + // time elapsed in seconds after creation of this object + float elapsed() const; + + static const unsigned int staticTimerInterval; + +private slots: + void slotTimerNotify(); + +private: + SVGDocumentImpl *m_doc; + SVGTimerList m_timerList; + SVGTimer *m_intervalTimer; + QTime m_creationTime; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTitleElementImpl.cc b/ksvg/impl/SVGTitleElementImpl.cc new file mode 100644 index 00000000..5bfe2936 --- /dev/null +++ b/ksvg/impl/SVGTitleElementImpl.cc @@ -0,0 +1,39 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGDocumentImpl.h" +#include "SVGTitleElementImpl.h" + +using namespace KSVG; + +SVGTitleElementImpl::SVGTitleElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGLangSpaceImpl(), SVGStylableImpl(this) +{ +} + +SVGTitleElementImpl::~SVGTitleElementImpl() +{ +} + +void SVGTitleElementImpl::createItem(KSVGCanvas *) +{ + emit ownerDoc()->gotTitle(collectText()); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTitleElementImpl.h b/ksvg/impl/SVGTitleElementImpl.h new file mode 100644 index 00000000..7c948842 --- /dev/null +++ b/ksvg/impl/SVGTitleElementImpl.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTitleElementImpl_H +#define SVGTitleElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGElementImpl.h" +#include "SVGStylableImpl.h" +#include "SVGLangSpaceImpl.h" + +namespace KSVG +{ + +class SVGTitleElementImpl : public SVGElementImpl, + public SVGLangSpaceImpl, + public SVGStylableImpl +{ +public: + SVGTitleElementImpl(DOM::ElementImpl *); + virtual ~SVGTitleElementImpl(); + + virtual void createItem(KSVGCanvas *c = 0); + +public: + KSVG_BRIDGE + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +KSVG_REGISTER_ELEMENT(SVGTitleElementImpl, "title") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTransformImpl.cc b/ksvg/impl/SVGTransformImpl.cc new file mode 100644 index 00000000..53ea9bf3 --- /dev/null +++ b/ksvg/impl/SVGTransformImpl.cc @@ -0,0 +1,240 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGTransform.h" + +#include "SVGMatrixImpl.h" +#include "SVGTransformImpl.h" +#include "SVGSVGElementImpl.h" + +using namespace KSVG; + +#include "SVGTransformImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_cacheimpl.h" + +SVGTransformImpl::SVGTransformImpl() +{ + m_matrix = SVGSVGElementImpl::createSVGMatrix(); + + m_type = SVG_TRANSFORM_UNKNOWN; + m_angle = 0; +} + +SVGTransformImpl::~SVGTransformImpl() +{ + if(m_matrix) + m_matrix->deref(); +} + +unsigned short SVGTransformImpl::type() const +{ + return m_type; +} + +SVGMatrixImpl *SVGTransformImpl::matrix() const +{ + return m_matrix; +} + +double SVGTransformImpl::angle() const +{ + return m_angle; +} + +void SVGTransformImpl::setMatrix(SVGMatrixImpl *matrix) +{ + if(!matrix) + return; + + m_type = SVG_TRANSFORM_MATRIX; + m_angle = 0; + + m_matrix->deref(); + m_matrix = matrix; + m_matrix->ref(); +} + +void SVGTransformImpl::setTranslate(double tx, double ty) +{ + m_type = SVG_TRANSFORM_TRANSLATE; + m_angle = 0; + m_matrix->reset(); + m_matrix->translate(tx, ty); +} + +void SVGTransformImpl::setScale(double sx, double sy) +{ + m_type = SVG_TRANSFORM_SCALE; + m_angle = 0; + m_matrix->reset(); + m_matrix->scaleNonUniform(sx, sy); +} + +void SVGTransformImpl::setRotate(double angle, double cx, double cy) +{ + m_type = SVG_TRANSFORM_ROTATE; + // mop: evil...fix that...needed to make toString() work correctly + m_cx = cx; + m_cy = cy; + m_angle = angle; + m_matrix->reset(); + m_matrix->translate(cx, cy); + m_matrix->rotate(angle); + m_matrix->translate(-cx, -cy); +} + +void SVGTransformImpl::setSkewX(double angle) +{ + m_type = SVG_TRANSFORM_SKEWX; + m_angle = angle; + m_matrix->reset(); + m_matrix->skewX(angle); +} + +void SVGTransformImpl::setSkewY(double angle) +{ + m_type = SVG_TRANSFORM_SKEWY; + m_angle = angle; + m_matrix->reset(); + m_matrix->skewY(angle); +} + +QString SVGTransformImpl::toString() const +{ + switch (m_type) + { + case SVG_TRANSFORM_UNKNOWN: + return QString(); + case SVG_TRANSFORM_MATRIX: + return QString("matrix(" + QString::number(m_matrix->a()) + " " + QString::number(m_matrix->b()) + " " + QString::number(m_matrix->c()) + " " + QString::number(m_matrix->d()) + " " + QString::number(m_matrix->e()) + " " + QString::number(m_matrix->f()) + ")"); + case SVG_TRANSFORM_TRANSLATE: + return QString("translate(" + QString::number(m_matrix->e()) + " " + QString::number(m_matrix->f()) + ")"); + case SVG_TRANSFORM_SCALE: + return QString("scale(" + QString::number(m_matrix->a()) + " " + QString::number(m_matrix->d()) + ")"); + case SVG_TRANSFORM_ROTATE: + return QString("rotate(" + QString::number(m_angle) + " " + QString::number(m_cx) + " " + QString::number(m_cy) + ")"); + case SVG_TRANSFORM_SKEWX: + return QString("skewX(" + QString::number(m_angle) + ")"); + case SVG_TRANSFORM_SKEWY: + return QString("skewY(" + QString::number(m_angle) + ")"); + default: + kdWarning() << "Unknown transform type " << m_type << endl; + return QString(); + } +} + +// ECMA binding + +/* +@namespace KSVG +@begin SVGTransformImpl::s_hashTable 5 + type SVGTransformImpl::Type DontDelete|ReadOnly + matrix SVGTransformImpl::Matrix DontDelete|ReadOnly + angle SVGTransformImpl::Angle DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGTransformImplProto::s_hashTable 7 + setMatrix SVGTransformImpl::SetMatrix DontDelete|Function 1 + setTranslate SVGTransformImpl::SetTranslate DontDelete|Function 2 + setScale SVGTransformImpl::SetScale DontDelete|Function 2 + setRotate SVGTransformImpl::SetRotate DontDelete|Function 3 + setSkewX SVGTransformImpl::SetSkewX DontDelete|Function 1 + setSkewY SVGTransformImpl::SetSkewY DontDelete|Function 1 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGTransform", SVGTransformImplProto, SVGTransformImplProtoFunc) + +Value SVGTransformImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case Type: + return Number(m_type); + case Matrix: + return m_matrix->cache(exec); + case Angle: + return Number(m_angle); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +Value SVGTransformImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGTransformImpl) + + switch(id) + { + case SVGTransformImpl::SetMatrix: + obj->setMatrix(static_cast *>(args[0].imp())->impl()); + break; + case SVGTransformImpl::SetTranslate: + obj->setTranslate(args[0].toNumber(exec), args[1].toNumber(exec)); + break; + case SVGTransformImpl::SetScale: + obj->setScale(args[0].toNumber(exec), args[1].toNumber(exec)); + break; + case SVGTransformImpl::SetRotate: + obj->setRotate(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec)); + break; + case SVGTransformImpl::SetSkewX: + obj->setSkewX(args[0].toNumber(exec)); + break; + case SVGTransformImpl::SetSkewY: + obj->setSkewY(args[0].toNumber(exec)); + break; + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + +/* +@namespace KSVG +@begin SVGTransformImplConstructor::s_hashTable 11 + SVG_TRANSFORM_UNKNOWN KSVG::SVG_TRANSFORM_UNKNOWN DontDelete|ReadOnly + SVG_TRANSFORM_MATRIX KSVG::SVG_TRANSFORM_MATRIX DontDelete|ReadOnly + SVG_TRANSFORM_TRANSLATE KSVG::SVG_TRANSFORM_TRANSLATE DontDelete|ReadOnly + SVG_TRANSFORM_SCALE KSVG::SVG_TRANSFORM_SCALE DontDelete|ReadOnly + SVG_TRANSFORM_ROTATE KSVG::SVG_TRANSFORM_ROTATE DontDelete|ReadOnly + SVG_TRANSFORM_SKEWX KSVG::SVG_TRANSFORM_SKEWX DontDelete|ReadOnly + SVG_TRANSFORM_SKEWY KSVG::SVG_TRANSFORM_SKEWY DontDelete|ReadOnly +@end +*/ + +Value SVGTransformImplConstructor::getValueProperty(ExecState *, int token) const +{ + return Number(token); +} + +Value KSVG::getSVGTransformImplConstructor(ExecState *exec) +{ + return cacheGlobalBridge(exec, "[[svgtransform.constructor]]"); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTransformImpl.h b/ksvg/impl/SVGTransformImpl.h new file mode 100644 index 00000000..69d71b8f --- /dev/null +++ b/ksvg/impl/SVGTransformImpl.h @@ -0,0 +1,99 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTransformImpl_H +#define SVGTransformImpl_H + +#include +#include + +#include "ksvg_lookup.h" + +class QString; + +namespace KSVG +{ + +class SVGMatrixImpl; +class SVGTransformImpl : public DOM::DomShared +{ +public: + SVGTransformImpl(); + virtual ~SVGTransformImpl(); + + unsigned short type() const; + + SVGMatrixImpl *matrix() const; + + double angle() const; + + void setMatrix(SVGMatrixImpl *); + void setTranslate(double, double); + void setScale(double, double); + void setRotate(double, double, double); + void setSkewX(double); + void setSkewY(double); + + QString toString() const; + +private: + // mop: we have to store the optional rotate stuff :( anyone with a better solution please fix that ;) + double m_cx; + double m_cy; + + unsigned short m_type; + SVGMatrixImpl *m_matrix; + double m_angle; + +public: + KSVG_GET + + enum + { + // Properties + Type, Matrix, Angle, + // Functions + SetMatrix, SetTranslate, SetScale, + SetRotate, SetSkewX, SetSkewY + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +class SVGTransformImplConstructor : public KJS::ObjectImp +{ +public: + SVGTransformImplConstructor(KJS::ExecState *) { } + KJS::Value getValueProperty(KJS::ExecState *, int token) const; + + // no put - all read-only + KSVG_GET +}; + +KJS::Value getSVGTransformImplConstructor(KJS::ExecState *exec); + +} + +KSVG_DEFINE_PROTOTYPE(SVGTransformImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGTransformImplProtoFunc, SVGTransformImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTransformListImpl.cc b/ksvg/impl/SVGTransformListImpl.cc new file mode 100644 index 00000000..5ecc16b6 --- /dev/null +++ b/ksvg/impl/SVGTransformListImpl.cc @@ -0,0 +1,103 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGMatrixImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGTransformListImpl.h" + +using namespace KSVG; + +#include "SVGTransformListImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGTransformListImpl::s_hashTable 2 + numberOfItems SVGListDefs::NumberOfItems DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGTransformListImplProto::s_hashTable 11 + getItem SVGListDefs::GetItem DontDelete|Function 1 + removeItem SVGListDefs::RemoveItem DontDelete|Function 1 + appendItem SVGListDefs::AppendItem DontDelete|Function 1 + initialize SVGListDefs::Initialize DontDelete|Function 1 + insertItemBefore SVGListDefs::InsertItemBefore DontDelete|Function 2 + replaceItem SVGListDefs::ReplaceItem DontDelete|Function 2 + clear SVGListDefs::Clear DontDelete|Function 0 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGTransformList", SVGTransformListImplProto, SVGTransformListImplProtoFunc) + +Value SVGTransformListImpl::getValueProperty(ExecState *exec, int token) const +{ + return SVGList::getValueProperty(exec, token); +} + +Value SVGTransformListImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGTransformListImpl) + + return obj->call(exec, static_cast *>(obj), args, id); +} + +SVGTransformImpl *SVGTransformListImpl::consolidate() +{ + SVGTransformImpl *trans = 0; + + if(numberOfItems()>0) + { + trans = SVGSVGElementImpl::createSVGTransform(); + SVGMatrixImpl *matrix = SVGSVGElementImpl::createSVGMatrix(); + + for(unsigned int i = 0; i < numberOfItems(); i++) + matrix->multiply(getItem(i)->matrix()); + + // Pedantic - sets type to MATRIX as per spec. + trans->setMatrix(matrix); + matrix->deref(); + initialize(trans); + trans->ref(); + } + + return trans; +} + +SVGMatrixImpl *SVGTransformListImpl::concatenate() const +{ + SVGMatrixImpl *matrix = 0; + + if(numberOfItems()>0) + { + matrix = SVGSVGElementImpl::createSVGMatrix(); + + for(unsigned int i = 0; i < numberOfItems(); i++) + matrix->multiply(getItem(i)->matrix()); + } + + return matrix; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTransformListImpl.h b/ksvg/impl/SVGTransformListImpl.h new file mode 100644 index 00000000..d59c6046 --- /dev/null +++ b/ksvg/impl/SVGTransformListImpl.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTransformListImpl_H +#define SVGTransformListImpl_H + +#include "SVGList.h" + +#include "SVGTransformImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGTransformListImpl : public SVGList +{ +public: + KSVG_GET + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + + SVGTransformImpl *consolidate(); + + // Concatenate the transforms. Returns 0 if list is empty + SVGMatrixImpl *concatenate() const; +}; + +} + +KSVG_DEFINE_PROTOTYPE(SVGTransformListImplProto) +KSVG_IMPLEMENT_PROTOFUNC(SVGTransformListImplProtoFunc, SVGTransformListImpl) + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTransformableImpl.cc b/ksvg/impl/SVGTransformableImpl.cc new file mode 100644 index 00000000..59dd904b --- /dev/null +++ b/ksvg/impl/SVGTransformableImpl.cc @@ -0,0 +1,169 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGMatrixImpl.h" +#include "SVGHelperImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGTransformableImpl.h" +#include "SVGTransformListImpl.h" +#include "SVGAnimatedTransformListImpl.h" +#include "SVGElementImpl.h" +#include "SVGDocumentImpl.h" + +using namespace KSVG; + +#include "SVGTransformableImpl.lut.h" +#include "ksvg_bridge.h" + +SVGTransformableImpl::SVGTransformableImpl() : SVGLocatableImpl() +{ + KSVG_EMPTY_FLAGS + + m_transform = new SVGAnimatedTransformListImpl(); + m_transform->ref(); + + m_localMatrix = 0; +} + +SVGTransformableImpl::SVGTransformableImpl(const SVGTransformableImpl &other) : SVGLocatableImpl() +{ + (*this) = other; +} + +SVGTransformableImpl::~SVGTransformableImpl() +{ + if(m_transform) + m_transform->deref(); + if(m_localMatrix) + m_localMatrix->deref(); +} + +SVGTransformableImpl &SVGTransformableImpl::operator=(const SVGTransformableImpl &other) +{ + SVGTransformListImpl *otherTransform = other.m_transform->baseVal(); + + // Concat computed values + for(unsigned int i = 0;i < otherTransform->numberOfItems(); i++) + { + SVGTransformImpl *trafo = otherTransform->getItem(i); + m_transform->baseVal()->insertItemBefore(SVGSVGElementImpl::createSVGTransformFromMatrix(trafo->matrix()), i); + } + + return *this; +} + +SVGAnimatedTransformListImpl *SVGTransformableImpl::transform() const +{ + return m_transform; +} + +SVGMatrixImpl *SVGTransformableImpl::getCTM() +{ + SVGMatrixImpl *ctm = SVGSVGElementImpl::createSVGMatrix(); + + SVGElementImpl *element = dynamic_cast(this); + Q_ASSERT(element); + + DOM::Node parentNde = element->parentNode(); + + if(!parentNde.isNull() && parentNde.nodeType() != DOM::Node::DOCUMENT_NODE) + { + SVGElementImpl *parent = element->ownerDoc()->getElementFromHandle(parentNde.handle()); + SVGLocatableImpl *locatableParent = dynamic_cast(parent); + + if(locatableParent) + { + SVGMatrixImpl *parentCTM = locatableParent->getCTM(); + ctm->multiply(parentCTM); + parentCTM->deref(); + } + } + + if(m_localMatrix) + { + ctm->multiply(m_localMatrix); + } + + return ctm; +} + +void SVGTransformableImpl::updateLocalMatrix() +{ + if(m_transform->baseVal()->numberOfItems()>0) + { + if(m_localMatrix) + m_localMatrix->deref(); + + m_localMatrix = m_transform->baseVal()->concatenate(); + } + else + { + if(m_localMatrix) + { + m_localMatrix->deref(); + m_localMatrix = 0; + } + } + + invalidateCachedMatrices(); +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGTransformableImpl::s_hashTable 2 + transform SVGTransformableImpl::Transform DontDelete +@end +*/ + +Value SVGTransformableImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case Transform: + return m_transform->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGTransformableImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case Transform: + SVGHelperImpl::parseTransformAttribute(m_transform->baseVal(), value.toString(exec).qstring()); + updateLocalMatrix(); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGTransformableImpl.h b/ksvg/impl/SVGTransformableImpl.h new file mode 100644 index 00000000..edff5831 --- /dev/null +++ b/ksvg/impl/SVGTransformableImpl.h @@ -0,0 +1,77 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGTransformableImpl_H +#define SVGTransformableImpl_H + +#include + +#include "SVGLocatableImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGMatrixImpl; +class SVGAnimatedTransformListImpl; + +class SVGTransformableImpl : public SVGLocatableImpl +{ +public: + SVGTransformableImpl(); + SVGTransformableImpl(const SVGTransformableImpl &); + virtual ~SVGTransformableImpl(); + + SVGTransformableImpl &operator=(const SVGTransformableImpl &); + + SVGAnimatedTransformListImpl *transform() const; + + virtual SVGMatrixImpl *getCTM(); + + // The local transformations concatenated together. 0 if + // there are no local transformations. + virtual const SVGMatrixImpl *localMatrix() { return m_localMatrix; } + +private: + SVGAnimatedTransformListImpl *m_transform; + SVGMatrixImpl *m_localMatrix; + + void updateLocalMatrix(); + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + Transform + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGURIReferenceImpl.cc b/ksvg/impl/SVGURIReferenceImpl.cc new file mode 100644 index 00000000..a68b7442 --- /dev/null +++ b/ksvg/impl/SVGURIReferenceImpl.cc @@ -0,0 +1,135 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGURIReferenceImpl.h" +#include "SVGAnimatedStringImpl.h" + +using namespace KSVG; + +#include "SVGURIReferenceImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +SVGURIReferenceImpl::SVGURIReferenceImpl() +{ + KSVG_EMPTY_FLAGS + + m_href = new SVGAnimatedStringImpl(); + m_href->ref(); +} + +SVGURIReferenceImpl::~SVGURIReferenceImpl() +{ + if(m_href) + m_href->deref(); +} + +SVGAnimatedStringImpl *SVGURIReferenceImpl::href() const +{ + return m_href; +} + +bool SVGURIReferenceImpl::parseURIReference(const QString &urireference, QString &uri, QString &elementreference) +{ + int seperator = urireference.find("#"); + + if(seperator == -1) + return false; + + uri = urireference.left(seperator); + elementreference = urireference.mid(seperator + 1); + + return true; +} + +bool SVGURIReferenceImpl::isUrl(const QString &url) +{ + QString temp = url.stripWhiteSpace(); + return temp.startsWith("url(#") && temp.endsWith(")"); +} + +QString SVGURIReferenceImpl::getTarget(const QString &url) +{ + if(url.startsWith("url(")) // URI References, ie. fill:url(#target) + { + unsigned int start = url.find("#") + 1; + unsigned int end = url.findRev(")"); + + return url.mid(start, end - start); + } + else if(url.find("#") > -1) // format is #target + { + unsigned int start = url.find("#") + 1; + + return url.mid(start, url.length() - start); + } + else // Normal Reference, ie. style="color-profile:changeColor" + return url; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGURIReferenceImpl::s_hashTable 2 + href SVGURIReferenceImpl::Href DontDelete|ReadOnly +@end +*/ + +Value SVGURIReferenceImpl::getValueProperty(ExecState *exec, int token) const +{ + switch(token) + { + case Href: + return m_href->cache(exec); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGURIReferenceImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case Href: + { + if(m_href) + m_href->deref(); + + SVGAnimatedStringImpl *temp = new SVGAnimatedStringImpl(); + temp->ref(); + temp->setBaseVal(value.toString(exec).string()); + m_href = temp; + break; + } + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGURIReferenceImpl.h b/ksvg/impl/SVGURIReferenceImpl.h new file mode 100644 index 00000000..d6ee42c5 --- /dev/null +++ b/ksvg/impl/SVGURIReferenceImpl.h @@ -0,0 +1,64 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGURIReferenceImpl_H +#define SVGURIReferenceImpl_H + +#include "ksvg_lookup.h" + +class QString; + +namespace KSVG +{ + +class SVGAnimatedStringImpl; +class SVGURIReferenceImpl +{ +public: + SVGURIReferenceImpl(); + ~SVGURIReferenceImpl(); + + SVGAnimatedStringImpl *href() const; + static QString getTarget(const QString &url); + static bool isUrl(const QString &url); + static bool parseURIReference(const QString &urireference, QString &uri, QString &elementreference); + +protected: + SVGAnimatedStringImpl *m_href; + +public: + KSVG_GET + KSVG_PUT + + enum + { + // Properties + Href + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGUnitConverter.h b/ksvg/impl/SVGUnitConverter.h new file mode 100644 index 00000000..90c95796 --- /dev/null +++ b/ksvg/impl/SVGUnitConverter.h @@ -0,0 +1,100 @@ +/* + Copyright (C) 2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGUnitConverter_H +#define SVGUnitConverter_H + +#include + +#include + +#include "SVGUnitTypes.h" +#include "SVGShapeImpl.h" +#include "SVGAnimatedLengthImpl.h" + +namespace KSVG +{ + +class SVGUnitConverter +{ +public: + SVGUnitConverter() { m_dict.setAutoDelete(true); } + ~SVGUnitConverter() { } + + void add(SVGAnimatedLengthImpl *obj) + { + UnitData *data = new UnitData(); + data->valueAsString = QString::null; + + m_dict.insert(obj, data); + } + + void modify(SVGAnimatedLengthImpl *obj, const QString &value) + { + UnitData *data = m_dict.find(obj); + + if(data) + data->valueAsString = value; + } + + void finalize(SVGShapeImpl *bboxContext, SVGShapeImpl *userContext, unsigned short unitType) + { + bool user = (unitType == SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE); + bool bbox = (unitType == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX); + + if(!user && !bbox) // Invalid unit type + return; + + QPtrDictIterator it(m_dict); + for(; it.current(); ++it) + { + UnitData *data = it.current(); + + if(!data) + continue; + + SVGAnimatedLengthImpl *obj = static_cast(it.currentKey()); + + if(bbox) + obj->baseVal()->setBBoxContext(bboxContext); + else + obj->baseVal()->setBBoxContext(userContext); + + if(user) // Just assign value, no conversion needed! + obj->baseVal()->setValueAsString(data->valueAsString); + else // Convert to objectBoundingBox + obj->baseVal()->setValueAsString(SVGLengthImpl::convertValToPercentage(data->valueAsString)); + } + } + +private: + typedef struct + { + QString valueAsString; // Original value + } UnitData; + + QPtrDict m_dict; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGUseElementImpl.cc b/ksvg/impl/SVGUseElementImpl.cc new file mode 100644 index 00000000..3bd38a42 --- /dev/null +++ b/ksvg/impl/SVGUseElementImpl.cc @@ -0,0 +1,409 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include + +#include "KSVGLoader.h" +#include "KSVGCanvas.h" + +#include "SVGRectImpl.h" +#include "SVGEventImpl.h" +#include "SVGHelperImpl.h" +#include "SVGMatrixImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGTransformImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGUseElementImpl.h" +#include "SVGSymbolElementImpl.h" +#include "SVGTransformListImpl.h" +#include "SVGAnimatedStringImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGElementInstanceImpl.h" +#include "SVGAnimatedTransformListImpl.h" + +using namespace KSVG; + +#include "SVGUseElementImpl.lut.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGUseElementImpl::SVGUseElementImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl), SVGURIReferenceImpl(), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl() +{ + KSVG_EMPTY_FLAGS + + m_x = new SVGAnimatedLengthImpl(); + m_x->ref(); + + m_y = new SVGAnimatedLengthImpl(); + m_y->ref(); + + m_width = new SVGAnimatedLengthImpl(); + m_width->ref(); + + m_height = new SVGAnimatedLengthImpl(); + m_height->ref(); + + m_instanceRoot = 0; +} + +SVGUseElementImpl::~SVGUseElementImpl() +{ + if(m_x) + m_x->deref(); + if(m_y) + m_y->deref(); + if(m_width) + m_width->deref(); + if(m_height) + m_height->deref(); + if(m_instanceRoot) + m_instanceRoot->deref(); +} + +SVGAnimatedLengthImpl *SVGUseElementImpl::x() const +{ + return m_x; +} + +SVGAnimatedLengthImpl *SVGUseElementImpl::y() const +{ + return m_y; +} + +SVGAnimatedLengthImpl *SVGUseElementImpl::width() const +{ + return m_width; +} + +SVGAnimatedLengthImpl *SVGUseElementImpl::height() const +{ + return m_height; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGUseElementImpl::s_hashTable 11 + x SVGUseElementImpl::X DontDelete|ReadOnly + y SVGUseElementImpl::Y DontDelete|ReadOnly + width SVGUseElementImpl::Width DontDelete|ReadOnly + height SVGUseElementImpl::Height DontDelete|ReadOnly + href SVGUseElementImpl::Href DontDelete|ReadOnly + instanceRoot SVGUseElementImpl::InstanceRoot DontDelete|ReadOnly + animatedInstanceRoot SVGUseElementImpl::AnimatedInstanceRoot DontDelete|ReadOnly +@end +*/ + +Value SVGUseElementImpl::getValueProperty(ExecState *exec, int token) const +{ + KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case X: + if(!attributeMode) + return m_x->cache(exec); + else + return Number(m_x->baseVal()->value()); + case Y: + if(!attributeMode) + return m_y->cache(exec); + else + return Number(m_y->baseVal()->value()); + case Width: + if(!attributeMode) + return m_width->cache(exec); + else + return Number(m_width->baseVal()->value()); + case Height: + if(!attributeMode) + return m_height->cache(exec); + else + return Number(m_height->baseVal()->value()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGUseElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case X: + x()->baseVal()->setValue(value.toNumber(exec)); + break; + case Y: + y()->baseVal()->setValue(value.toNumber(exec)); + break; + case Width: + width()->baseVal()->setValue(value.toNumber(exec)); + break; + case Height: + height()->baseVal()->setValue(value.toNumber(exec)); + break; + case Href: + { + QString url = value.toString(exec).qstring(); + href()->setBaseVal(SVGURIReferenceImpl::getTarget(url)); + break; + } + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +SVGRectImpl *SVGUseElementImpl::getBBox() +{ + if(m_instanceRoot) + { + SVGShapeImpl *shape = dynamic_cast(m_instanceRoot->correspondingElement()); + if(KSVG_TOKEN_NOT_PARSED(Width) && KSVG_TOKEN_NOT_PARSED(Height) && shape) + return shape->getBBox(); + } + + SVGRectImpl *ret = new SVGRectImpl(); + ret->ref(); + ret->setX(m_x->baseVal()->value()); + ret->setY(m_y->baseVal()->value()); + ret->setWidth(m_width->baseVal()->value()); + ret->setHeight(m_height->baseVal()->value()); + return ret; +} + +SVGElementInstanceImpl *SVGUseElementImpl::instanceRoot() const +{ + return m_instanceRoot; +} + +SVGElementInstanceImpl *SVGUseElementImpl::animatedInstanceRoot() const +{ + return m_animatedInstanceRoot; +} + +void SVGUseElementImpl::createItem(KSVGCanvas *c) +{ + if(!m_instanceRoot) + { + // ownerSVGElement()->getElementById() is wrong here. + // It could reference elements from other documents when using getURL (Niko) + QString filename, id; + DOM::DOMString url = getAttribute("href"); + if(!SVGURIReferenceImpl::parseURIReference(url.string(), filename, id)) + return; + + SVGElementImpl *orig; + if(!filename.isEmpty()) + { + KURL fragmentUrl(ownerDoc()->baseUrl(), url.string()); + + id = fragmentUrl.ref(); + fragmentUrl.setRef(QString::null); + + orig = KSVGLoader::getSVGFragment(fragmentUrl, ownerDoc(), id); + } + else + { + orig = ownerDoc()->getElementByIdRecursive(ownerSVGElement(), href()->baseVal()); + + if(orig == 0) + { + // The document will try to create this item again once the parsing has finished. + ownerDoc()->addForwardReferencingUseElement(this); + } + } + + if(orig == 0) + return; + + setReferencedElement(orig); + + // Create a parent, a + SVGElementImpl *parent = 0; + DOM::Element impl = static_cast(ownerDoc())->createElement("g"); + parent = SVGDocumentImpl::createElement("g", impl, ownerDoc()); + SVGElementImpl *clone = orig->cloneNode(true); + + // Apply the use-correction + QString trans; + trans += " translate("; + trans += QString::number(x()->baseVal()->value()); + trans += " "; + trans += QString::number(y()->baseVal()->value()); + trans += ")"; + + // Apply the transform attribute and render the element + parent->setAttributeInternal("transform", trans); + parent->setAttribute("transform", trans); + + // Apply width/height if symbol + if(dynamic_cast(clone)) + { + DOM::Element impl = static_cast(ownerDoc())->createElement("svg"); + SVGElementImpl *symbolSvg = SVGDocumentImpl::createElement("svg", impl, ownerDoc()); + + SVGHelperImpl::copyAttributes(orig, symbolSvg); + + symbolSvg->setAttribute("width", getAttribute("width")); + symbolSvg->setAttributeInternal("width", getAttribute("width")); + symbolSvg->setAttribute("height", getAttribute("height")); + symbolSvg->setAttributeInternal("height", getAttribute("height")); + DOM::Node node = clone->firstChild(); + for(; !node.isNull(); node = clone->firstChild()) + symbolSvg->appendChild(node); + + clone = symbolSvg; + } + else if(dynamic_cast(clone)) + { + if(!getAttribute("width").isEmpty()) + { + clone->setAttribute("width", getAttribute("width")); + clone->setAttributeInternal("width", getAttribute("width")); + } + + if(!getAttribute("height").isEmpty()) + { + clone->setAttribute("height", getAttribute("height")); + clone->setAttributeInternal("height", getAttribute("height")); + } + } + + appendChild(*parent); + parent->appendChild(*clone); + + setupSubtree(parent, ownerSVGElement(), viewportElement()); + + m_instanceRoot->setCorrespondingElement(clone); + + dynamic_cast(parent)->updateCachedScreenCTM(screenCTM()); + + // Redirect local ecma event handlers to the correspondingElement + QPtrListIterator it(eventListeners()); + SVGRegisteredEventListener *eventListener; + while((eventListener = it.current()) != 0) + { + ++it; + clone->setEventListener(eventListener->id, eventListener->listener); + } + } + + if(m_instanceRoot) + { + SVGElementImpl *element = m_instanceRoot->correspondingElement(); + element->createItem(c); + } +} + +void SVGUseElementImpl::removeItem(KSVGCanvas *c) +{ + if(m_instanceRoot) + { + SVGElementImpl *element = m_instanceRoot->correspondingElement(); + element->removeItem(c); + } +} + +void SVGUseElementImpl::setupSubtree(SVGElementImpl *element, SVGSVGElementImpl *ownerSVG, SVGElementImpl *viewport) +{ + element->setOwnerSVGElement(ownerSVG); + element->setViewportElement(viewport); + element->setAttributes(); + + SVGSVGElementImpl *thisSVG = dynamic_cast(element); + + if(thisSVG != 0) + { + ownerSVG = thisSVG; + viewport = element; + } + + DOM::Node child = element->firstChild(); + for(; !child.isNull(); child = child.nextSibling()) + { + SVGElementImpl *childElement = ownerDoc()->getElementFromHandle(child.handle()); + if(childElement != 0) + setupSubtree(childElement, ownerSVG, viewport); + } +} + +void SVGUseElementImpl::setReferencedElement(SVGElementImpl *referenced) +{ + if(!referenced) + return; + + if(!m_instanceRoot) + { + m_instanceRoot = new SVGElementInstanceImpl(); + m_instanceRoot->ref(); + } + + m_instanceRoot->setCorrespondingElement(referenced); +} + +void SVGUseElementImpl::update(CanvasItemUpdate reason, int param1, int param2) +{ + if(m_instanceRoot) + { + SVGShapeImpl *shape = dynamic_cast(m_instanceRoot->correspondingElement()); + if(shape) + shape->update(reason, param1, param2); + } +} + +void SVGUseElementImpl::invalidate(KSVGCanvas *c, bool recalc) +{ + if(m_instanceRoot) + { + SVGShapeImpl *shape = dynamic_cast(m_instanceRoot->correspondingElement()); + if(shape) + shape->invalidate(c, recalc); + } +} + +void SVGUseElementImpl::setReferenced(bool referenced) +{ + if(m_instanceRoot) + { + SVGShapeImpl *shape = dynamic_cast(m_instanceRoot->correspondingElement()); + if(shape) + shape->setReferenced(referenced); + } +} + +void SVGUseElementImpl::draw() +{ + if(m_instanceRoot) + { + SVGShapeImpl *shape = dynamic_cast(m_instanceRoot->correspondingElement()); + if(shape) + shape->draw(); + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGUseElementImpl.h b/ksvg/impl/SVGUseElementImpl.h new file mode 100644 index 00000000..02eb8d88 --- /dev/null +++ b/ksvg/impl/SVGUseElementImpl.h @@ -0,0 +1,101 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGUseElementImpl_H +#define SVGUseElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGTestsImpl.h" +#include "SVGShapeImpl.h" +#include "SVGStylableImpl.h" +#include "SVGLangSpaceImpl.h" +#include "SVGURIReferenceImpl.h" +#include "SVGTransformableImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +namespace KSVG +{ + +class SVGAnimatedLengthImpl; +class SVGElementInstanceImpl; +class SVGUseElementImpl : public SVGShapeImpl, + public SVGURIReferenceImpl, + public SVGTestsImpl, + public SVGLangSpaceImpl, + public SVGExternalResourcesRequiredImpl, + public SVGStylableImpl, + public SVGTransformableImpl +{ +public: + SVGUseElementImpl(DOM::ElementImpl *); + virtual ~SVGUseElementImpl(); + + SVGAnimatedLengthImpl *x() const; + SVGAnimatedLengthImpl *y() const; + SVGAnimatedLengthImpl *width() const; + SVGAnimatedLengthImpl *height() const; + + SVGElementInstanceImpl *instanceRoot() const; + SVGElementInstanceImpl *animatedInstanceRoot() const; + + virtual void createItem(KSVGCanvas *c); + virtual void removeItem(KSVGCanvas *c); + virtual void update(CanvasItemUpdate reason, int param1, int param2); + virtual void invalidate(KSVGCanvas *c, bool recalc); + virtual void setReferenced(bool referenced); + virtual void draw(); + + virtual SVGRectImpl *getBBox(); + + void setReferencedElement(SVGElementImpl *); + +private: + SVGAnimatedLengthImpl *m_x; + SVGAnimatedLengthImpl *m_y; + SVGAnimatedLengthImpl *m_width; + SVGAnimatedLengthImpl *m_height; + SVGElementInstanceImpl *m_instanceRoot; + SVGElementInstanceImpl *m_animatedInstanceRoot; + + void setupSubtree(SVGElementImpl *element, SVGSVGElementImpl *ownerSVG, SVGElementImpl *viewport); + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + X, Y, Width, Height, Href, InstanceRoot, AnimatedInstanceRoot + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGUseElementImpl, "use") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGVKernElementImpl.cc b/ksvg/impl/SVGVKernElementImpl.cc new file mode 100644 index 00000000..b89d6e6f --- /dev/null +++ b/ksvg/impl/SVGVKernElementImpl.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGVKernElementImpl.h" + +using namespace KSVG; + +SVGVKernElementImpl::SVGVKernElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl) +{ +} + +SVGVKernElementImpl::~SVGVKernElementImpl() +{ +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGVKernElementImpl.h b/ksvg/impl/SVGVKernElementImpl.h new file mode 100644 index 00000000..c8302c35 --- /dev/null +++ b/ksvg/impl/SVGVKernElementImpl.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGVKernElementImpl_H +#define SVGVKernElementImpl_H + +#include "ksvg_lookup.h" + +#include "SVGElementImpl.h" + +namespace KSVG +{ + +class SVGVKernElementImpl : public SVGElementImpl +{ +public: + SVGVKernElementImpl(DOM::ElementImpl *impl); + virtual ~SVGVKernElementImpl(); + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGViewElementImpl.cc b/ksvg/impl/SVGViewElementImpl.cc new file mode 100644 index 00000000..a051fba0 --- /dev/null +++ b/ksvg/impl/SVGViewElementImpl.cc @@ -0,0 +1,94 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGStringListImpl.h" +#include "SVGViewElementImpl.h" + +using namespace KSVG; + +#include "SVGViewElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGViewElementImpl::SVGViewElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGExternalResourcesRequiredImpl(), SVGFitToViewBoxImpl(), SVGZoomAndPanImpl() +{ + KSVG_EMPTY_FLAGS + + m_viewTarget = new SVGStringListImpl(); + m_viewTarget->ref(); +} + +SVGViewElementImpl::~SVGViewElementImpl() +{ + if(m_viewTarget) + m_viewTarget->deref(); +} + +SVGStringListImpl *SVGViewElementImpl::viewTarget() const +{ + return m_viewTarget; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGViewElementImpl::s_hashTable 2 + viewTarget SVGViewElementImpl::ViewTarget DontDelete|ReadOnly +@end +*/ + +Value SVGViewElementImpl::getValueProperty(ExecState *, int token) const +{ + //KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case ViewTarget: + // TODO + return Undefined(); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGViewElementImpl::putValueProperty(ExecState *, int token, const Value &, int attr) +{ + // This class has just ReadOnly properties, only with the Internal flag set + // it's allowed to modify those. + if(!(attr & KJS::Internal)) + return; + + switch(token) + { + case ViewTarget: + // TODO + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGViewElementImpl.h b/ksvg/impl/SVGViewElementImpl.h new file mode 100644 index 00000000..8b8d7e0b --- /dev/null +++ b/ksvg/impl/SVGViewElementImpl.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGViewElementImpl_H +#define SVGViewElementImpl_H + +#include "SVGElementImpl.h" +#include "SVGZoomAndPanImpl.h" +#include "SVGFitToViewBoxImpl.h" +#include "SVGExternalResourcesRequiredImpl.h" + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGStringListImpl; +class SVGViewElementImpl : public SVGElementImpl, + public SVGExternalResourcesRequiredImpl, + public SVGFitToViewBoxImpl, + public SVGZoomAndPanImpl +{ +public: + SVGViewElementImpl(DOM::ElementImpl *); + virtual ~SVGViewElementImpl(); + + SVGStringListImpl *viewTarget() const; + +private: + SVGStringListImpl *m_viewTarget; + +public: + KSVG_GET + KSVG_PUT + KSVG_BRIDGE + + enum + { + // Properties + ViewTarget + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +KSVG_REGISTER_ELEMENT(SVGViewElementImpl, "view") + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGViewSpecImpl.cc b/ksvg/impl/SVGViewSpecImpl.cc new file mode 100644 index 00000000..07412cc5 --- /dev/null +++ b/ksvg/impl/SVGViewSpecImpl.cc @@ -0,0 +1,98 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include + +#include "SVGElementImpl.h" +#include "SVGViewSpecImpl.h" +#include "SVGTransformListImpl.h" + +using namespace KSVG; + +SVGViewSpecImpl::SVGViewSpecImpl() : SVGZoomAndPanImpl(), SVGFitToViewBoxImpl() +{ + m_transform = new SVGTransformListImpl(); + m_transform->ref(); + + m_viewTarget = new SVGElementImpl(0); + m_viewTarget->ref(); +} + +SVGViewSpecImpl::~SVGViewSpecImpl() +{ + if(m_transform) + m_transform->deref(); + if(m_viewTarget) + m_viewTarget->deref(); +} + +SVGTransformListImpl *SVGViewSpecImpl::transform() const +{ + return m_transform; +} + +SVGElementImpl *SVGViewSpecImpl::viewTarget() const +{ + return m_viewTarget; +} + +DOM::DOMString SVGViewSpecImpl::viewBoxString() const +{ + return m_viewBoxString; +} + +DOM::DOMString SVGViewSpecImpl::preserveAspectRatioString() const +{ + return m_preserveAspectRatioString; +} + +DOM::DOMString SVGViewSpecImpl::transformString() const +{ + return m_transformString; +} + +DOM::DOMString SVGViewSpecImpl::viewTargetString() const +{ + return m_viewTargetString; +} + +bool SVGViewSpecImpl::parseViewSpec(const QString &s) +{ + if(!s.startsWith("svgView(")) + return false; + + // remove 'svgView(' and ')' + QStringList subAttrs = QStringList::split(';', s.mid(8)); + + for(QStringList::ConstIterator it = subAttrs.begin() ; it != subAttrs.end(); ++it) + { + if((*it).startsWith("viewBox(")) + m_viewBoxString = (*it).mid(8); + else if((*it).startsWith("zoomAndPan(")) + parseZoomAndPan(DOM::DOMString((*it).mid(11))); + else if((*it).startsWith("preserveAspectRatio(")) + m_preserveAspectRatioString = (*it).mid(20); + } + return true; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGViewSpecImpl.h b/ksvg/impl/SVGViewSpecImpl.h new file mode 100644 index 00000000..f9e01e48 --- /dev/null +++ b/ksvg/impl/SVGViewSpecImpl.h @@ -0,0 +1,69 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGViewSpecImpl_H +#define SVGViewSpecImpl_H + +#include +#include + +#include "ksvg_lookup.h" + +#include "SVGZoomAndPanImpl.h" +#include "SVGFitToViewBoxImpl.h" + +namespace KSVG +{ + +class SVGElementImpl; +class SVGTransformListImpl; +class SVGViewSpecImpl : public DOM::DomShared, public SVGZoomAndPanImpl, public SVGFitToViewBoxImpl +{ +public: + SVGViewSpecImpl(); + virtual ~SVGViewSpecImpl(); + + SVGTransformListImpl *transform() const; + SVGElementImpl *viewTarget() const; + DOM::DOMString viewBoxString() const; + DOM::DOMString preserveAspectRatioString() const; + DOM::DOMString transformString() const; + DOM::DOMString viewTargetString() const; + + bool parseViewSpec(const QString &); + +private: + SVGTransformListImpl *m_transform; + SVGElementImpl *m_viewTarget; + DOM::DOMString m_viewBoxString; + DOM::DOMString m_preserveAspectRatioString; + DOM::DOMString m_transformString; + DOM::DOMString m_viewTargetString; + +public: + KSVG_FORWARDGET + KSVG_FORWARDPUT +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGWindowImpl.cc b/ksvg/impl/SVGWindowImpl.cc new file mode 100644 index 00000000..b19847a4 --- /dev/null +++ b/ksvg/impl/SVGWindowImpl.cc @@ -0,0 +1,187 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 "SVGWindowImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGEvent.h" +#include "KSVGCanvas.h" +#include +#include + +#include + +#include +#include +#include +#include + +using namespace KSVG; + + +SVGWindowImpl::SVGWindowImpl() +{ + m_document = 0; +} + +SVGWindowImpl::SVGWindowImpl(SVGDocumentImpl *doc) +{ + m_document = doc; + if(m_document) + m_document->ref(); +} + +SVGWindowImpl::~SVGWindowImpl() +{ + if(m_document) + m_document->deref(); +} + +/*StyleSheet SVGWindowImpl::defaultStyleSheet() const +{ + return m_defaultStyleSheet; +}*/ + +SVGDocumentImpl *SVGWindowImpl::document() const +{ + return m_document; +} + +DOM::Event SVGWindowImpl::evt() const +{ + return KSVG::SVGEvent(m_document->ecmaEngine()->interpreter()->currentEvent()); +} + +long SVGWindowImpl::innerHeight() const +{ + return m_document ? int(m_document->canvas()->height()) : -1; +} + +long SVGWindowImpl::innerWidth() const +{ + return m_document ? int(m_document->canvas()->width()) : -1; +} + +void SVGWindowImpl::setSrc(const DOM::DOMString &/*src*/) +{ + // TODO : make KURL, load and parse doc +} + +DOM::DOMString SVGWindowImpl::src() const +{ + if(!m_document) + return DOM::DOMString(); + return m_document->baseUrl().prettyURL(); +} + +void SVGWindowImpl::clearInterval(long /*interval*/) +{ +} + +void SVGWindowImpl::clearTimeout(long /*timeout*/) +{ +} + +void SVGWindowImpl::getURL(const DOM::DOMString &/*uri*/, const DOM::EventListener &/*callback*/) +{ +} + +/*DocumentFragment SVGWindowImpl::parseXML(const DOM::DOMString &source, const Document &document) +{ +}*/ + +void SVGWindowImpl::postURL(const DOM::DOMString &/*uri*/, const DOM::DOMString &/*data*/, const DOM::EventListener &/*callback*/, const DOM::DOMString &/*mimeType*/, const DOM::DOMString &/*contentEncoding*/) +{ +} + +DOM::DOMString SVGWindowImpl::printNode(const DOM::Node &node, unsigned short level) +{ + QString ret; + if(node.isNull()) return ret; + SVGElementImpl *elem = m_document->getElementFromHandle(node.handle()); + if(node.nodeType() == DOM::Node::DOCUMENT_NODE) + { + ret += "<\?xml version=\"1.0\" encoding=\"UTF-8\"\?>\n" + printNode(node.firstChild()).string() + "\n"; + } + else if(node.nodeType() == DOM::Node::TEXT_NODE) + { + printIndentation(ret, level); + ret += node.nodeValue().string(); + } + else if(elem) + { + printIndentation(ret, level); + ret += "<" + elem->tagName().string(); + // handle attrs + QDictIterator it(elem->attributes()); + for(;it.current(); ++it) + ret += " " + it.currentKey() + "=\"" + it.current()->string() + '\"'; + if(elem->firstChild().isNull()) // no children + ret += " />\n"; + else // handle children + { + ret += ">\n"; + for(DOM::Node child = node.firstChild();!child.isNull();child = child.nextSibling()) + ret += printNode(child, level + 1).string(); + printIndentation(ret, level); + ret += "tagName().string() + ">\n"; + } + } + return ret; +} + +void SVGWindowImpl::printIndentation(QString &ret, unsigned short level, unsigned short indent) +{ + for(int i = 0;i < indent * level;i++) + ret += " "; +} + +long SVGWindowImpl::setInterval(const DOM::DOMString &/*code*/, const long &/*delay*/) +{ + return 0; +} + +long SVGWindowImpl::setTimeout(const DOM::DOMString &/*code*/, const long &/*delay*/) +{ + return 0; +} + +void SVGWindowImpl::alert(const DOM::DOMString &message, const QString &title) +{ + KMessageBox::error(0L, QStyleSheet::convertFromPlainText(message.string()), title); +} + +bool SVGWindowImpl::confirm(const DOM::DOMString &message, const QString &title) +{ + return KMessageBox::warningContinueCancel(0L, QStyleSheet::convertFromPlainText(message.string()), title, KStdGuiItem::ok()) == KMessageBox::Continue; +} + +DOM::DOMString SVGWindowImpl::prompt(const DOM::DOMString &message, const DOM::DOMString &_default, const QString &) +{ + bool ok; + QString str; + str = KInputDialog::getText(i18n("Prompt"), QStyleSheet::convertFromPlainText(message.string()), _default.string(), &ok); + if(ok) + return str; + else + return ""; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGWindowImpl.h b/ksvg/impl/SVGWindowImpl.h new file mode 100644 index 00000000..0861809e --- /dev/null +++ b/ksvg/impl/SVGWindowImpl.h @@ -0,0 +1,73 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGWindowImpl_H +#define SVGWindowImpl_H + +#include +#include +#include +#include + +namespace KSVG +{ +class SVGDocumentImpl; + +class SVGWindowImpl : public DOM::DomShared +{ +public: + SVGWindowImpl(); + SVGWindowImpl(SVGDocumentImpl *doc); + virtual ~SVGWindowImpl(); + + //StyleSheet defaultStyleSheet() const; + SVGDocumentImpl *document() const; + DOM::Event evt() const; + long innerHeight() const; + long innerWidth() const; + + void setSrc(const DOM::DOMString &src); + DOM::DOMString src() const; + + void clearInterval(long interval); + void clearTimeout(long timeout); + void getURL(const DOM::DOMString &uri, const DOM::EventListener &callback); + //DocumentFragment parseXML(const DOM::DOMString &source, const Document &document); + void postURL(const DOM::DOMString &uri, const DOM::DOMString &data, const DOM::EventListener &callback, const DOM::DOMString &mimeType, const DOM::DOMString &contentEncoding); + DOM::DOMString printNode(const DOM::Node &node, unsigned short level = 0); + long setInterval(const DOM::DOMString &code, const long &delay); + long setTimeout(const DOM::DOMString &code, const long &delay); + static void alert(const DOM::DOMString &message, const QString &title = "SVG Window"); + static bool confirm(const DOM::DOMString &message, const QString &title = "SVG Window"); + static DOM::DOMString prompt(const DOM::DOMString &message, const DOM::DOMString &_default, const QString &title = "SVG Window"); + +private: + void printIndentation(QString &ret, unsigned short level, unsigned short indent = 2); + +private: + //StyleSheet m_defaultStyleSheet; + SVGDocumentImpl *m_document; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGZoomAndPanImpl.cc b/ksvg/impl/SVGZoomAndPanImpl.cc new file mode 100644 index 00000000..f3bf96ce --- /dev/null +++ b/ksvg/impl/SVGZoomAndPanImpl.cc @@ -0,0 +1,112 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 + +#include "SVGZoomAndPan.h" +#include "SVGZoomAndPanImpl.h" + +using namespace KSVG; + +#include "SVGZoomAndPanImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_cacheimpl.h" + +SVGZoomAndPanImpl::SVGZoomAndPanImpl() +{ + KSVG_EMPTY_FLAGS + + m_zoomAndPan = SVG_ZOOMANDPAN_MAGNIFY; +} + +SVGZoomAndPanImpl::~SVGZoomAndPanImpl() +{ +} + +void SVGZoomAndPanImpl::setZoomAndPan(unsigned short zoomAndPan) +{ + m_zoomAndPan = zoomAndPan; +} + +unsigned short SVGZoomAndPanImpl::zoomAndPan() const +{ + return m_zoomAndPan; +} + +void SVGZoomAndPanImpl::parseZoomAndPan(const DOM::DOMString &attr) +{ + if(attr == "disable") + m_zoomAndPan = SVG_ZOOMANDPAN_DISABLE; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGZoomAndPanImpl::s_hashTable 2 + zoomAndPan SVGZoomAndPanImpl::ZoomAndPan DontDelete +@end +*/ + +Value SVGZoomAndPanImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case ZoomAndPan: + return Number(zoomAndPan()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return KJS::Undefined(); + } +} + +void SVGZoomAndPanImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int) +{ + switch(token) + { + case ZoomAndPan: + parseZoomAndPan(value.toString(exec).string()); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +/* +@namespace KSVG +@begin SVGZoomAndPanImplConstructor::s_hashTable 5 + SVG_ZOOMANDPAN_UNKNOWN KSVG::SVG_ZOOMANDPAN_UNKNOWN DontDelete|ReadOnly + SVG_ZOOMANDPAN_DISABLE KSVG::SVG_ZOOMANDPAN_DISABLE DontDelete|ReadOnly + SVG_ZOOMANDPAN_MAGNIFY KSVG::SVG_ZOOMANDPAN_MAGNIFY DontDelete|ReadOnly +@end +*/ + +Value SVGZoomAndPanImplConstructor::getValueProperty(ExecState *, int token) const +{ + return Number(token); +} + +Value KSVG::getSVGZoomAndPanImplConstructor(ExecState *exec) +{ + return cacheGlobalBridge(exec, "[[svgzoomandpan.constructor]]"); +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGZoomAndPanImpl.h b/ksvg/impl/SVGZoomAndPanImpl.h new file mode 100644 index 00000000..ed7fef98 --- /dev/null +++ b/ksvg/impl/SVGZoomAndPanImpl.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGZoomAndPanImpl_H +#define SVGZoomAndPanImpl_H + +#include +#include + +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGZoomAndPanImpl +{ +public: + SVGZoomAndPanImpl(); + virtual ~SVGZoomAndPanImpl(); + + void setZoomAndPan(unsigned short zoomAndPan); + unsigned short zoomAndPan() const; + + void parseZoomAndPan(const DOM::DOMString &attr); + +private: + unsigned short m_zoomAndPan; + +public: + KSVG_BASECLASS_GET + KSVG_PUT + + enum + { + // Properties + ZoomAndPan + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; + void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr); +}; + +class SVGZoomAndPanImplConstructor : public KJS::ObjectImp +{ +public: + SVGZoomAndPanImplConstructor(KJS::ExecState *) { } + KJS::Value getValueProperty(KJS::ExecState *, int token) const; + + // no put - all read-only + KSVG_GET +}; + +KJS::Value getSVGZoomAndPanImplConstructor(KJS::ExecState *exec); + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGZoomEventImpl.cc b/ksvg/impl/SVGZoomEventImpl.cc new file mode 100644 index 00000000..448309f0 --- /dev/null +++ b/ksvg/impl/SVGZoomEventImpl.cc @@ -0,0 +1,111 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include "SVGRectImpl.h" +#include "SVGPointImpl.h" +#include "SVGZoomEventImpl.h" + +using namespace KSVG; + +#include "SVGZoomEventImpl.lut.h" +#include "SVGSVGElementImpl.h" + +using namespace KJS; + +SVGZoomEventImpl::SVGZoomEventImpl(SVGEvent::EventId _id, + bool canBubbleArg, + bool cancelableArg, + DOM::AbstractView &viewArg, + long detailArg, + float previousScale, SVGPointImpl *previousTranslate, + float newScale, SVGPointImpl *newTranslate) +: SVGUIEventImpl(_id, canBubbleArg, cancelableArg, viewArg, detailArg), m_previousScale( previousScale ), m_newScale( newScale ) +{ + m_zoomRectScreen = SVGSVGElementImpl::createSVGRect(); + m_previousTranslate = previousTranslate; + if(m_previousTranslate) + m_previousTranslate->ref(); + m_newTranslate = newTranslate; + if(m_newTranslate) + m_newTranslate->ref(); +} + +SVGZoomEventImpl::~SVGZoomEventImpl() +{ + if(m_zoomRectScreen) + m_zoomRectScreen->deref(); + if(m_previousTranslate) + m_previousTranslate->deref(); + if(m_newTranslate) + m_newTranslate->deref(); +} + +SVGRectImpl *SVGZoomEventImpl::zoomRectScreen() const +{ + return m_zoomRectScreen; +} + +float SVGZoomEventImpl::previousScale() const +{ + return m_previousScale; +} + +SVGPointImpl *SVGZoomEventImpl::previousTranslate() const +{ + return m_previousTranslate; +} + +float SVGZoomEventImpl::newScale() const +{ + return m_newScale; +} + +SVGPointImpl *SVGZoomEventImpl::newTranslate() const +{ + return m_newTranslate; +} + +/* +@namespace KSVG +@begin SVGZoomEventImpl::s_hashTable 7 + zoomRectScreen SVGZoomEventImpl::ZoomRectScreen DontDelete|ReadOnly + previousScale SVGZoomEventImpl::PreviousScale DontDelete|ReadOnly + previousTranslate SVGZoomEventImpl::PreviousTranslate DontDelete|ReadOnly + newScale SVGZoomEventImpl::NewScale DontDelete|ReadOnly + newTranslate SVGZoomEventImpl::NewTranslate DontDelete|ReadOnly +@end +*/ + +Value SVGZoomEventImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case PreviousScale: + return Number(previousScale()); + case NewScale: + return Number(newScale()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/SVGZoomEventImpl.h b/ksvg/impl/SVGZoomEventImpl.h new file mode 100644 index 00000000..41706a37 --- /dev/null +++ b/ksvg/impl/SVGZoomEventImpl.h @@ -0,0 +1,77 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 SVGZoomEventImpl_H +#define SVGZoomEventImpl_H + +#include "SVGEventImpl.h" +#include "ksvg_lookup.h" + +namespace KSVG +{ + +class SVGRectImpl; +class SVGPointImpl; +class SVGZoomEventImpl : public SVGUIEventImpl +{ +public: + SVGZoomEventImpl(SVGEvent::EventId _id, + bool canBubbleArg, + bool cancelableArg, + DOM::AbstractView &viewArg, + long detailArg, + float previousScale, SVGPointImpl *previousTranslate, + float newScale, SVGPointImpl *newTranslate); + virtual ~SVGZoomEventImpl(); + + SVGRectImpl *zoomRectScreen() const; + + float previousScale() const; + SVGPointImpl *previousTranslate() const; + + float newScale() const; + SVGPointImpl *newTranslate() const; + +private: + SVGRectImpl *m_zoomRectScreen; + + float m_previousScale; + SVGPointImpl *m_previousTranslate; + + float m_newScale; + SVGPointImpl *m_newTranslate; + +public: + KSVG_GET + + enum + { + // Properties + ZoomRectScreen, PreviousScale, PreviousTranslate, NewScale, NewTranslate + }; + + KJS::Value getValueProperty(KJS::ExecState *exec, int token) const; +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/TODO b/ksvg/impl/TODO new file mode 100644 index 00000000..8cfd4c4a --- /dev/null +++ b/ksvg/impl/TODO @@ -0,0 +1,5 @@ +* cleanup SVGSVGElementImpl +* cleanup SVGShapeImpl +* fix SVGStringListImpl +* attriubuteMode get() for SVGGlyphElementImpl +* default attributes, ... for SVGGlyphElementImpl diff --git a/ksvg/impl/generateddata.cpp b/ksvg/impl/generateddata.cpp new file mode 100644 index 00000000..5a4b3d7b --- /dev/null +++ b/ksvg/impl/generateddata.cpp @@ -0,0 +1,8899 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace KSVG; +using namespace KJS; + +#include "ksvg_cacheimpl.h" + +// For all classes with generated data: the ClassInfo +const DOM::DOMString SVGAElementImpl::s_tagName = "a"; +const ClassInfo SVGAElementImpl::s_classInfo = {"KSVG::SVGAElementImpl",0,&SVGAElementImpl::s_hashTable,0}; +const DOM::DOMString SVGAltGlyphDefElementImpl::s_tagName = "altGlyphDef"; +const ClassInfo SVGAltGlyphDefElementImpl::s_classInfo = {"KSVG::SVGAltGlyphDefElementImpl",0,0,0}; +const DOM::DOMString SVGAltGlyphElementImpl::s_tagName = "altGlyph"; +const ClassInfo SVGAltGlyphElementImpl::s_classInfo = {"KSVG::SVGAltGlyphElementImpl",0,0,0}; +const ClassInfo SVGAngleImpl::s_classInfo = {"KSVG::SVGAngleImpl",0,&SVGAngleImpl::s_hashTable,0}; +const ClassInfo SVGAngleImplConstructor::s_classInfo = {"KSVG::SVGAngleImplConstructor",0,&SVGAngleImplConstructor::s_hashTable,0}; +const DOM::DOMString SVGAnimateColorElementImpl::s_tagName = "animateColor"; +const ClassInfo SVGAnimateColorElementImpl::s_classInfo = {"KSVG::SVGAnimateColorElementImpl",0,0,0}; +const DOM::DOMString SVGAnimateElementImpl::s_tagName = "animate"; +const ClassInfo SVGAnimateElementImpl::s_classInfo = {"KSVG::SVGAnimateElementImpl",0,0,0}; +const DOM::DOMString SVGAnimateMotionElementImpl::s_tagName = "animateMotion"; +const ClassInfo SVGAnimateMotionElementImpl::s_classInfo = {"KSVG::SVGAnimateMotionElementImpl",0,0,0}; +const DOM::DOMString SVGAnimateTransformElementImpl::s_tagName = "animateTransform"; +const ClassInfo SVGAnimateTransformElementImpl::s_classInfo = {"KSVG::SVGAnimateTransformElementImpl",0,0,0}; +const ClassInfo SVGAnimatedAngleImpl::s_classInfo = {"KSVG::SVGAnimatedAngleImpl",0,&SVGAnimatedAngleImpl::s_hashTable,0}; +const ClassInfo SVGAnimatedBooleanImpl::s_classInfo = {"KSVG::SVGAnimatedBooleanImpl",0,&SVGAnimatedBooleanImpl::s_hashTable,0}; +const ClassInfo SVGAnimatedEnumerationImpl::s_classInfo = {"KSVG::SVGAnimatedEnumerationImpl",0,&SVGAnimatedEnumerationImpl::s_hashTable,0}; +const ClassInfo SVGAnimatedIntegerImpl::s_classInfo = {"KSVG::SVGAnimatedIntegerImpl",0,&SVGAnimatedIntegerImpl::s_hashTable,0}; +const ClassInfo SVGAnimatedLengthImpl::s_classInfo = {"KSVG::SVGAnimatedLengthImpl",0,&SVGAnimatedLengthImpl::s_hashTable,0}; +const ClassInfo SVGAnimatedLengthListImpl::s_classInfo = {"KSVG::SVGAnimatedLengthListImpl",0,&SVGAnimatedLengthListImpl::s_hashTable,0}; +const ClassInfo SVGAnimatedNumberImpl::s_classInfo = {"KSVG::SVGAnimatedNumberImpl",0,&SVGAnimatedNumberImpl::s_hashTable,0}; +const ClassInfo SVGAnimatedNumberListImpl::s_classInfo = {"KSVG::SVGAnimatedNumberListImpl",0,&SVGAnimatedNumberListImpl::s_hashTable,0}; +const ClassInfo SVGAnimatedPathDataImpl::s_classInfo = {"KSVG::SVGAnimatedPathDataImpl",0,&SVGAnimatedPathDataImpl::s_hashTable,0}; +const ClassInfo SVGAnimatedPointsImpl::s_classInfo = {"KSVG::SVGAnimatedPointsImpl",0,&SVGAnimatedPointsImpl::s_hashTable,0}; +const ClassInfo SVGAnimatedPreserveAspectRatioImpl::s_classInfo = {"KSVG::SVGAnimatedPreserveAspectRatioImpl",0,&SVGAnimatedPreserveAspectRatioImpl::s_hashTable,0}; +const ClassInfo SVGAnimatedRectImpl::s_classInfo = {"KSVG::SVGAnimatedRectImpl",0,&SVGAnimatedRectImpl::s_hashTable,0}; +const ClassInfo SVGAnimatedStringImpl::s_classInfo = {"KSVG::SVGAnimatedStringImpl",0,&SVGAnimatedStringImpl::s_hashTable,0}; +const ClassInfo SVGAnimatedTransformListImpl::s_classInfo = {"KSVG::SVGAnimatedTransformListImpl",0,&SVGAnimatedTransformListImpl::s_hashTable,0}; +const ClassInfo SVGAnimationElementImpl::s_classInfo = {"KSVG::SVGAnimationElementImpl",0,&SVGAnimationElementImpl::s_hashTable,0}; +const DOM::DOMString SVGCircleElementImpl::s_tagName = "circle"; +const ClassInfo SVGCircleElementImpl::s_classInfo = {"KSVG::SVGCircleElementImpl",0,&SVGCircleElementImpl::s_hashTable,0}; +const DOM::DOMString SVGClipPathElementImpl::s_tagName = "clipPath"; +const ClassInfo SVGClipPathElementImpl::s_classInfo = {"KSVG::SVGClipPathElementImpl",0,&SVGClipPathElementImpl::s_hashTable,0}; +const ClassInfo SVGColorImpl::s_classInfo = {"KSVG::SVGColorImpl",0,&SVGColorImpl::s_hashTable,0}; +const ClassInfo SVGColorImplConstructor::s_classInfo = {"KSVG::SVGColorImplConstructor",0,&SVGColorImplConstructor::s_hashTable,0}; +const DOM::DOMString SVGColorProfileElementImpl::s_tagName = "color-profile"; +const ClassInfo SVGColorProfileElementImpl::s_classInfo = {"KSVG::SVGColorProfileElementImpl",0,&SVGColorProfileElementImpl::s_hashTable,0}; +const ClassInfo SVGComponentTransferFunctionElementImpl::s_classInfo = {"KSVG::SVGComponentTransferFunctionElementImpl",0,0,0}; +const ClassInfo SVGContainerImpl::s_classInfo = {"KSVG::SVGContainerImpl",0,0,0}; +const ClassInfo SVGCursorElementImpl::s_classInfo = {"KSVG::SVGCursorElementImpl",0,&SVGCursorElementImpl::s_hashTable,0}; +const ClassInfo SVGDOMCharacterDataBridge::s_classInfo = {"KSVG::SVGDOMCharacterDataBridge",0,&SVGDOMCharacterDataBridge::s_hashTable,0}; +const ClassInfo SVGDOMDOMImplementationBridge::s_classInfo = {"KSVG::SVGDOMDOMImplementationBridge",0,&SVGDOMDOMImplementationBridge::s_hashTable,0}; +const ClassInfo SVGDOMDocumentFragmentBridge::s_classInfo = {"KSVG::SVGDOMDocumentFragmentBridge",0,&SVGDOMDocumentFragmentBridge::s_hashTable,0}; +const ClassInfo SVGDOMElementBridge::s_classInfo = {"KSVG::SVGDOMElementBridge",0,&SVGDOMElementBridge::s_hashTable,0}; +const ClassInfo SVGDOMNodeBridge::s_classInfo = {"KSVG::SVGDOMNodeBridge",0,&SVGDOMNodeBridge::s_hashTable,0}; +const ClassInfo SVGDOMNodeListBridge::s_classInfo = {"KSVG::SVGDOMNodeListBridge",0,&SVGDOMNodeListBridge::s_hashTable,0}; +const ClassInfo SVGDOMTextBridge::s_classInfo = {"KSVG::SVGDOMTextBridge",0,&SVGDOMTextBridge::s_hashTable,0}; +const ClassInfo SVGDefinitionSrcElementImpl::s_classInfo = {"KSVG::SVGDefinitionSrcElementImpl",0,0,0}; +const DOM::DOMString SVGDefsElementImpl::s_tagName = "defs"; +const ClassInfo SVGDefsElementImpl::s_classInfo = {"KSVG::SVGDefsElementImpl",0,0,0}; +const DOM::DOMString SVGDescElementImpl::s_tagName = "desc"; +const ClassInfo SVGDescElementImpl::s_classInfo = {"KSVG::SVGDescElementImpl",0,0,0}; +const ClassInfo SVGDocumentImpl::s_classInfo = {"KSVG::SVGDocumentImpl",0,&SVGDocumentImpl::s_hashTable,0}; +const ClassInfo SVGElementImpl::s_classInfo = {"KSVG::SVGElementImpl",0,&SVGElementImpl::s_hashTable,0}; +const DOM::DOMString SVGEllipseElementImpl::s_tagName = "ellipse"; +const ClassInfo SVGEllipseElementImpl::s_classInfo = {"KSVG::SVGEllipseElementImpl",0,&SVGEllipseElementImpl::s_hashTable,0}; +const ClassInfo SVGEventImpl::s_classInfo = {"KSVG::SVGEventImpl",0,&SVGEventImpl::s_hashTable,0}; +const ClassInfo SVGExternalResourcesRequiredImpl::s_classInfo = {"KSVG::SVGExternalResourcesRequiredImpl",0,&SVGExternalResourcesRequiredImpl::s_hashTable,0}; +const ClassInfo SVGFEBlendElementImpl::s_classInfo = {"KSVG::SVGFEBlendElementImpl",0,0,0}; +const ClassInfo SVGFEColorMatrixElementImpl::s_classInfo = {"KSVG::SVGFEColorMatrixElementImpl",0,0,0}; +const ClassInfo SVGFEComponentTransferElementImpl::s_classInfo = {"KSVG::SVGFEComponentTransferElementImpl",0,0,0}; +const ClassInfo SVGFECompositeElementImpl::s_classInfo = {"KSVG::SVGFECompositeElementImpl",0,0,0}; +const ClassInfo SVGFEConvolveMatrixElementImpl::s_classInfo = {"KSVG::SVGFEConvolveMatrixElementImpl",0,0,0}; +const ClassInfo SVGFEDiffuseLightingElementImpl::s_classInfo = {"KSVG::SVGFEDiffuseLightingElementImpl",0,0,0}; +const ClassInfo SVGFEDisplacementMapElementImpl::s_classInfo = {"KSVG::SVGFEDisplacementMapElementImpl",0,0,0}; +const ClassInfo SVGFEDistantLightElementImpl::s_classInfo = {"KSVG::SVGFEDistantLightElementImpl",0,0,0}; +const ClassInfo SVGFEFloodElementImpl::s_classInfo = {"KSVG::SVGFEFloodElementImpl",0,0,0}; +const ClassInfo SVGFEFuncAElementImpl::s_classInfo = {"KSVG::SVGFEFuncAElementImpl",0,0,0}; +const ClassInfo SVGFEFuncBElementImpl::s_classInfo = {"KSVG::SVGFEFuncBElementImpl",0,0,0}; +const ClassInfo SVGFEFuncGElementImpl::s_classInfo = {"KSVG::SVGFEFuncGElementImpl",0,0,0}; +const ClassInfo SVGFEFuncRElementImpl::s_classInfo = {"KSVG::SVGFEFuncRElementImpl",0,0,0}; +const ClassInfo SVGFEGaussianBlurElementImpl::s_classInfo = {"KSVG::SVGFEGaussianBlurElementImpl",0,0,0}; +const ClassInfo SVGFEImageElementImpl::s_classInfo = {"KSVG::SVGFEImageElementImpl",0,0,0}; +const ClassInfo SVGFEMergeElementImpl::s_classInfo = {"KSVG::SVGFEMergeElementImpl",0,0,0}; +const ClassInfo SVGFEMergeNodeElementImpl::s_classInfo = {"KSVG::SVGFEMergeNodeElementImpl",0,0,0}; +const ClassInfo SVGFEMorphologyElementImpl::s_classInfo = {"KSVG::SVGFEMorphologyElementImpl",0,0,0}; +const ClassInfo SVGFEOffsetElementImpl::s_classInfo = {"KSVG::SVGFEOffsetElementImpl",0,0,0}; +const ClassInfo SVGFEPointLightElementImpl::s_classInfo = {"KSVG::SVGFEPointLightElementImpl",0,0,0}; +const ClassInfo SVGFESpecularLightingElementImpl::s_classInfo = {"KSVG::SVGFESpecularLightingElementImpl",0,0,0}; +const ClassInfo SVGFESpotLightElementImpl::s_classInfo = {"KSVG::SVGFESpotLightElementImpl",0,0,0}; +const ClassInfo SVGFETileElementImpl::s_classInfo = {"KSVG::SVGFETileElementImpl",0,0,0}; +const ClassInfo SVGFETurbulenceElementImpl::s_classInfo = {"KSVG::SVGFETurbulenceElementImpl",0,0,0}; +const ClassInfo SVGFilterElementImpl::s_classInfo = {"KSVG::SVGFilterElementImpl",0,0,0}; +const ClassInfo SVGFitToViewBoxImpl::s_classInfo = {"KSVG::SVGFitToViewBoxImpl",0,&SVGFitToViewBoxImpl::s_hashTable,0}; +const ClassInfo SVGFontElementImpl::s_classInfo = {"KSVG::SVGFontElementImpl",0,0,0}; +const ClassInfo SVGFontFaceElementImpl::s_classInfo = {"KSVG::SVGFontFaceElementImpl",0,0,0}; +const ClassInfo SVGFontFaceFormatElementImpl::s_classInfo = {"KSVG::SVGFontFaceFormatElementImpl",0,0,0}; +const ClassInfo SVGFontFaceNameElementImpl::s_classInfo = {"KSVG::SVGFontFaceNameElementImpl",0,0,0}; +const ClassInfo SVGFontFaceSrcElementImpl::s_classInfo = {"KSVG::SVGFontFaceSrcElementImpl",0,0,0}; +const ClassInfo SVGFontFaceUriElementImpl::s_classInfo = {"KSVG::SVGFontFaceUriElementImpl",0,0,0}; +const ClassInfo SVGForeignObjectElementImpl::s_classInfo = {"KSVG::SVGForeignObjectElementImpl",0,&SVGForeignObjectElementImpl::s_hashTable,0}; +const DOM::DOMString SVGGElementImpl::s_tagName = "g"; +const ClassInfo SVGGElementImpl::s_classInfo = {"KSVG::SVGGElementImpl",0,0,0}; +const DOM::DOMString SVGGlyphElementImpl::s_tagName = "glyph"; +const ClassInfo SVGGlyphElementImpl::s_classInfo = {"KSVG::SVGGlyphElementImpl",0,&SVGGlyphElementImpl::s_hashTable,0}; +const DOM::DOMString SVGGlyphRefElementImpl::s_tagName = "glyphRef"; +const ClassInfo SVGGlyphRefElementImpl::s_classInfo = {"KSVG::SVGGlyphRefElementImpl",0,&SVGGlyphRefElementImpl::s_hashTable,0}; +const ClassInfo SVGGradientElementImpl::s_classInfo = {"KSVG::SVGGradientElementImpl",0,&SVGGradientElementImpl::s_hashTable,0}; +const ClassInfo SVGGradientElementImplConstructor::s_classInfo = {"KSVG::SVGGradientElementImplConstructor",0,&SVGGradientElementImplConstructor::s_hashTable,0}; +const ClassInfo SVGHKernElementImpl::s_classInfo = {"KSVG::SVGHKernElementImpl",0,0,0}; +const ClassInfo SVGICCColorImpl::s_classInfo = {"KSVG::SVGICCColorImpl",0,&SVGICCColorImpl::s_hashTable,0}; +const DOM::DOMString SVGImageElementImpl::s_tagName = "image"; +const ClassInfo SVGImageElementImpl::s_classInfo = {"KSVG::SVGImageElementImpl",0,&SVGImageElementImpl::s_hashTable,0}; +const ClassInfo SVGKeyEventImpl::s_classInfo = {"KSVG::SVGKeyEventImpl",0,&SVGKeyEventImpl::s_hashTable,0}; +const ClassInfo SVGLangSpaceImpl::s_classInfo = {"KSVG::SVGLangSpaceImpl",0,&SVGLangSpaceImpl::s_hashTable,0}; +const ClassInfo SVGLengthImpl::s_classInfo = {"KSVG::SVGLengthImpl",0,&SVGLengthImpl::s_hashTable,0}; +const ClassInfo SVGLengthImplConstructor::s_classInfo = {"KSVG::SVGLengthImplConstructor",0,&SVGLengthImplConstructor::s_hashTable,0}; +const ClassInfo SVGLengthListImpl::s_classInfo = {"KSVG::SVGLengthListImpl",0,&SVGLengthListImpl::s_hashTable,0}; +const DOM::DOMString SVGLineElementImpl::s_tagName = "line"; +const ClassInfo SVGLineElementImpl::s_classInfo = {"KSVG::SVGLineElementImpl",0,&SVGLineElementImpl::s_hashTable,0}; +const DOM::DOMString SVGLinearGradientElementImpl::s_tagName = "linearGradient"; +const ClassInfo SVGLinearGradientElementImpl::s_classInfo = {"KSVG::SVGLinearGradientElementImpl",0,&SVGLinearGradientElementImpl::s_hashTable,0}; +const ClassInfo SVGLocatableImpl::s_classInfo = {"KSVG::SVGLocatableImpl",0,&SVGLocatableImpl::s_hashTable,0}; +const ClassInfo SVGMPathElementImpl::s_classInfo = {"KSVG::SVGMPathElementImpl",0,0,0}; +const DOM::DOMString SVGMarkerElementImpl::s_tagName = "marker"; +const ClassInfo SVGMarkerElementImpl::s_classInfo = {"KSVG::SVGMarkerElementImpl",0,&SVGMarkerElementImpl::s_hashTable,0}; +const ClassInfo SVGMarkerElementImplConstructor::s_classInfo = {"KSVG::SVGMarkerElementImplConstructor",0,&SVGMarkerElementImplConstructor::s_hashTable,0}; +const DOM::DOMString SVGMaskElementImpl::s_tagName = "mask"; +const ClassInfo SVGMaskElementImpl::s_classInfo = {"KSVG::SVGMaskElementImpl",0,&SVGMaskElementImpl::s_hashTable,0}; +const ClassInfo SVGMatrixImpl::s_classInfo = {"KSVG::SVGMatrixImpl",0,&SVGMatrixImpl::s_hashTable,0}; +const ClassInfo SVGMetadataElementImpl::s_classInfo = {"KSVG::SVGMetadataElementImpl",0,0,0}; +const ClassInfo SVGMissingGlyphElementImpl::s_classInfo = {"KSVG::SVGMissingGlyphElementImpl",0,0,0}; +const ClassInfo SVGMouseEventImpl::s_classInfo = {"KSVG::SVGMouseEventImpl",0,&SVGMouseEventImpl::s_hashTable,0}; +const ClassInfo SVGMutationEventImpl::s_classInfo = {"KSVG::SVGMutationEventImpl",0,0,0}; +const ClassInfo SVGNumberImpl::s_classInfo = {"KSVG::SVGNumberImpl",0,&SVGNumberImpl::s_hashTable,0}; +const ClassInfo SVGNumberListImpl::s_classInfo = {"KSVG::SVGNumberListImpl",0,&SVGNumberListImpl::s_hashTable,0}; +const ClassInfo SVGPaintImpl::s_classInfo = {"KSVG::SVGPaintImpl",0,&SVGPaintImpl::s_hashTable,0}; +const ClassInfo SVGPaintImplConstructor::s_classInfo = {"KSVG::SVGPaintImplConstructor",0,&SVGPaintImplConstructor::s_hashTable,0}; +const DOM::DOMString SVGPathElementImpl::s_tagName = "path"; +const ClassInfo SVGPathElementImpl::s_classInfo = {"KSVG::SVGPathElementImpl",0,&SVGPathElementImpl::s_hashTable,0}; +const ClassInfo SVGPathSegArcAbsImpl::s_classInfo = {"KSVG::SVGPathSegArcAbsImpl",0,&SVGPathSegArcAbsImpl::s_hashTable,0}; +const ClassInfo SVGPathSegArcRelImpl::s_classInfo = {"KSVG::SVGPathSegArcRelImpl",0,&SVGPathSegArcRelImpl::s_hashTable,0}; +const ClassInfo SVGPathSegClosePathImpl::s_classInfo = {"KSVG::SVGPathSegClosePathImpl",0,0,0}; +const ClassInfo SVGPathSegCurvetoCubicAbsImpl::s_classInfo = {"KSVG::SVGPathSegCurvetoCubicAbsImpl",0,&SVGPathSegCurvetoCubicAbsImpl::s_hashTable,0}; +const ClassInfo SVGPathSegCurvetoCubicRelImpl::s_classInfo = {"KSVG::SVGPathSegCurvetoCubicRelImpl",0,&SVGPathSegCurvetoCubicRelImpl::s_hashTable,0}; +const ClassInfo SVGPathSegCurvetoCubicSmoothAbsImpl::s_classInfo = {"KSVG::SVGPathSegCurvetoCubicSmoothAbsImpl",0,&SVGPathSegCurvetoCubicSmoothAbsImpl::s_hashTable,0}; +const ClassInfo SVGPathSegCurvetoCubicSmoothRelImpl::s_classInfo = {"KSVG::SVGPathSegCurvetoCubicSmoothRelImpl",0,&SVGPathSegCurvetoCubicSmoothRelImpl::s_hashTable,0}; +const ClassInfo SVGPathSegCurvetoQuadraticAbsImpl::s_classInfo = {"KSVG::SVGPathSegCurvetoQuadraticAbsImpl",0,&SVGPathSegCurvetoQuadraticAbsImpl::s_hashTable,0}; +const ClassInfo SVGPathSegCurvetoQuadraticRelImpl::s_classInfo = {"KSVG::SVGPathSegCurvetoQuadraticRelImpl",0,&SVGPathSegCurvetoQuadraticRelImpl::s_hashTable,0}; +const ClassInfo SVGPathSegCurvetoQuadraticSmoothAbsImpl::s_classInfo = {"KSVG::SVGPathSegCurvetoQuadraticSmoothAbsImpl",0,&SVGPathSegCurvetoQuadraticSmoothAbsImpl::s_hashTable,0}; +const ClassInfo SVGPathSegCurvetoQuadraticSmoothRelImpl::s_classInfo = {"KSVG::SVGPathSegCurvetoQuadraticSmoothRelImpl",0,&SVGPathSegCurvetoQuadraticSmoothRelImpl::s_hashTable,0}; +const ClassInfo SVGPathSegImpl::s_classInfo = {"KSVG::SVGPathSegImpl",0,&SVGPathSegImpl::s_hashTable,0}; +const ClassInfo SVGPathSegImplConstructor::s_classInfo = {"KSVG::SVGPathSegImplConstructor",0,&SVGPathSegImplConstructor::s_hashTable,0}; +const ClassInfo SVGPathSegLinetoAbsImpl::s_classInfo = {"KSVG::SVGPathSegLinetoAbsImpl",0,&SVGPathSegLinetoAbsImpl::s_hashTable,0}; +const ClassInfo SVGPathSegLinetoHorizontalAbsImpl::s_classInfo = {"KSVG::SVGPathSegLinetoHorizontalAbsImpl",0,&SVGPathSegLinetoHorizontalAbsImpl::s_hashTable,0}; +const ClassInfo SVGPathSegLinetoHorizontalRelImpl::s_classInfo = {"KSVG::SVGPathSegLinetoHorizontalRelImpl",0,&SVGPathSegLinetoHorizontalRelImpl::s_hashTable,0}; +const ClassInfo SVGPathSegLinetoRelImpl::s_classInfo = {"KSVG::SVGPathSegLinetoRelImpl",0,&SVGPathSegLinetoRelImpl::s_hashTable,0}; +const ClassInfo SVGPathSegLinetoVerticalAbsImpl::s_classInfo = {"KSVG::SVGPathSegLinetoVerticalAbsImpl",0,&SVGPathSegLinetoVerticalAbsImpl::s_hashTable,0}; +const ClassInfo SVGPathSegLinetoVerticalRelImpl::s_classInfo = {"KSVG::SVGPathSegLinetoVerticalRelImpl",0,&SVGPathSegLinetoVerticalRelImpl::s_hashTable,0}; +const ClassInfo SVGPathSegListImpl::s_classInfo = {"KSVG::SVGPathSegListImpl",0,&SVGPathSegListImpl::s_hashTable,0}; +const ClassInfo SVGPathSegMovetoAbsImpl::s_classInfo = {"KSVG::SVGPathSegMovetoAbsImpl",0,&SVGPathSegMovetoAbsImpl::s_hashTable,0}; +const ClassInfo SVGPathSegMovetoRelImpl::s_classInfo = {"KSVG::SVGPathSegMovetoRelImpl",0,&SVGPathSegMovetoRelImpl::s_hashTable,0}; +const DOM::DOMString SVGPatternElementImpl::s_tagName = "pattern"; +const ClassInfo SVGPatternElementImpl::s_classInfo = {"KSVG::SVGPatternElementImpl",0,&SVGPatternElementImpl::s_hashTable,0}; +const ClassInfo SVGPointImpl::s_classInfo = {"KSVG::SVGPointImpl",0,&SVGPointImpl::s_hashTable,0}; +const ClassInfo SVGPointListImpl::s_classInfo = {"KSVG::SVGPointListImpl",0,&SVGPointListImpl::s_hashTable,0}; +const ClassInfo SVGPolyElementImpl::s_classInfo = {"KSVG::SVGPolyElementImpl",0,0,0}; +const DOM::DOMString SVGPolygonElementImpl::s_tagName = "polygon"; +const ClassInfo SVGPolygonElementImpl::s_classInfo = {"KSVG::SVGPolygonElementImpl",0,0,0}; +const DOM::DOMString SVGPolylineElementImpl::s_tagName = "polyline"; +const ClassInfo SVGPolylineElementImpl::s_classInfo = {"KSVG::SVGPolylineElementImpl",0,0,0}; +const ClassInfo SVGPreserveAspectRatioImpl::s_classInfo = {"KSVG::SVGPreserveAspectRatioImpl",0,&SVGPreserveAspectRatioImpl::s_hashTable,0}; +const ClassInfo SVGPreserveAspectRatioImplConstructor::s_classInfo = {"KSVG::SVGPreserveAspectRatioImplConstructor",0,&SVGPreserveAspectRatioImplConstructor::s_hashTable,0}; +const DOM::DOMString SVGRadialGradientElementImpl::s_tagName = "radialGradient"; +const ClassInfo SVGRadialGradientElementImpl::s_classInfo = {"KSVG::SVGRadialGradientElementImpl",0,&SVGRadialGradientElementImpl::s_hashTable,0}; +const DOM::DOMString SVGRectElementImpl::s_tagName = "rect"; +const ClassInfo SVGRectElementImpl::s_classInfo = {"KSVG::SVGRectElementImpl",0,&SVGRectElementImpl::s_hashTable,0}; +const ClassInfo SVGRectImpl::s_classInfo = {"KSVG::SVGRectImpl",0,&SVGRectImpl::s_hashTable,0}; +const DOM::DOMString SVGSVGElementImpl::s_tagName = "svg"; +const ClassInfo SVGSVGElementImpl::s_classInfo = {"KSVG::SVGSVGElementImpl",0,&SVGSVGElementImpl::s_hashTable,0}; +const DOM::DOMString SVGScriptElementImpl::s_tagName = "script"; +const ClassInfo SVGScriptElementImpl::s_classInfo = {"KSVG::SVGScriptElementImpl",0,&SVGScriptElementImpl::s_hashTable,0}; +const DOM::DOMString SVGSetElementImpl::s_tagName = "set"; +const ClassInfo SVGSetElementImpl::s_classInfo = {"KSVG::SVGSetElementImpl",0,0,0}; +const ClassInfo SVGShapeImpl::s_classInfo = {"KSVG::SVGShapeImpl",0,0,0}; +const DOM::DOMString SVGStopElementImpl::s_tagName = "stop"; +const ClassInfo SVGStopElementImpl::s_classInfo = {"KSVG::SVGStopElementImpl",0,&SVGStopElementImpl::s_hashTable,0}; +const ClassInfo SVGStringListImpl::s_classInfo = {"KSVG::SVGStringListImpl",0,&SVGStringListImpl::s_hashTable,0}; +const ClassInfo SVGStylableImpl::s_classInfo = {"KSVG::SVGStylableImpl",0,&SVGStylableImpl::s_hashTable,0}; +const DOM::DOMString SVGStyleElementImpl::s_tagName = "style"; +const ClassInfo SVGStyleElementImpl::s_classInfo = {"KSVG::SVGStyleElementImpl",0,&SVGStyleElementImpl::s_hashTable,0}; +const DOM::DOMString SVGSwitchElementImpl::s_tagName = "switch"; +const ClassInfo SVGSwitchElementImpl::s_classInfo = {"KSVG::SVGSwitchElementImpl",0,0,0}; +const DOM::DOMString SVGSymbolElementImpl::s_tagName = "symbol"; +const ClassInfo SVGSymbolElementImpl::s_classInfo = {"KSVG::SVGSymbolElementImpl",0,&SVGSymbolElementImpl::s_hashTable,0}; +const DOM::DOMString SVGTRefElementImpl::s_tagName = "tref"; +const ClassInfo SVGTRefElementImpl::s_classInfo = {"KSVG::SVGTRefElementImpl",0,0,0}; +const DOM::DOMString SVGTSpanElementImpl::s_tagName = "tspan"; +const ClassInfo SVGTSpanElementImpl::s_classInfo = {"KSVG::SVGTSpanElementImpl",0,0,0}; +const ClassInfo SVGTestsImpl::s_classInfo = {"KSVG::SVGTestsImpl",0,&SVGTestsImpl::s_hashTable,0}; +const ClassInfo SVGTextContentElementImpl::s_classInfo = {"KSVG::SVGTextContentElementImpl",0,&SVGTextContentElementImpl::s_hashTable,0}; +const ClassInfo SVGTextContentElementImplConstructor::s_classInfo = {"KSVG::SVGTextContentElementImplConstructor",0,&SVGTextContentElementImplConstructor::s_hashTable,0}; +const DOM::DOMString SVGTextElementImpl::s_tagName = "text"; +const ClassInfo SVGTextElementImpl::s_classInfo = {"KSVG::SVGTextElementImpl",0,0,0}; +const DOM::DOMString SVGTextPathElementImpl::s_tagName = "textPath"; +const ClassInfo SVGTextPathElementImpl::s_classInfo = {"KSVG::SVGTextPathElementImpl",0,&SVGTextPathElementImpl::s_hashTable,0}; +const ClassInfo SVGTextPathElementImplConstructor::s_classInfo = {"KSVG::SVGTextPathElementImplConstructor",0,&SVGTextPathElementImplConstructor::s_hashTable,0}; +const ClassInfo SVGTextPositioningElementImpl::s_classInfo = {"KSVG::SVGTextPositioningElementImpl",0,&SVGTextPositioningElementImpl::s_hashTable,0}; +const DOM::DOMString SVGTitleElementImpl::s_tagName = "title"; +const ClassInfo SVGTitleElementImpl::s_classInfo = {"KSVG::SVGTitleElementImpl",0,0,0}; +const ClassInfo SVGTransformImpl::s_classInfo = {"KSVG::SVGTransformImpl",0,&SVGTransformImpl::s_hashTable,0}; +const ClassInfo SVGTransformImplConstructor::s_classInfo = {"KSVG::SVGTransformImplConstructor",0,&SVGTransformImplConstructor::s_hashTable,0}; +const ClassInfo SVGTransformListImpl::s_classInfo = {"KSVG::SVGTransformListImpl",0,&SVGTransformListImpl::s_hashTable,0}; +const ClassInfo SVGTransformableImpl::s_classInfo = {"KSVG::SVGTransformableImpl",0,&SVGTransformableImpl::s_hashTable,0}; +const ClassInfo SVGUIEventImpl::s_classInfo = {"KSVG::SVGUIEventImpl",0,&SVGUIEventImpl::s_hashTable,0}; +const ClassInfo SVGURIReferenceImpl::s_classInfo = {"KSVG::SVGURIReferenceImpl",0,&SVGURIReferenceImpl::s_hashTable,0}; +const DOM::DOMString SVGUseElementImpl::s_tagName = "use"; +const ClassInfo SVGUseElementImpl::s_classInfo = {"KSVG::SVGUseElementImpl",0,&SVGUseElementImpl::s_hashTable,0}; +const ClassInfo SVGVKernElementImpl::s_classInfo = {"KSVG::SVGVKernElementImpl",0,0,0}; +const DOM::DOMString SVGViewElementImpl::s_tagName = "view"; +const ClassInfo SVGViewElementImpl::s_classInfo = {"KSVG::SVGViewElementImpl",0,&SVGViewElementImpl::s_hashTable,0}; +const ClassInfo SVGViewSpecImpl::s_classInfo = {"KSVG::SVGViewSpecImpl",0,0,0}; +const ClassInfo SVGZoomAndPanImpl::s_classInfo = {"KSVG::SVGZoomAndPanImpl",0,&SVGZoomAndPanImpl::s_hashTable,0}; +const ClassInfo SVGZoomAndPanImplConstructor::s_classInfo = {"KSVG::SVGZoomAndPanImplConstructor",0,&SVGZoomAndPanImplConstructor::s_hashTable,0}; +const ClassInfo SVGZoomEventImpl::s_classInfo = {"KSVG::SVGZoomEventImpl",0,&SVGZoomEventImpl::s_hashTable,0}; +const ClassInfo SharedString::s_classInfo = {"KSVG::SharedString",0,&SharedString::s_hashTable,0}; + +bool SVGAElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGAElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGContainerImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGTestsImpl::hasProperty(p1,p2)) return true; + if(SVGTransformableImpl::hasProperty(p1,p2)) return true; + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGAElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGAElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGContainerImpl::hasProperty(p1,p2)) return SVGContainerImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3); + if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3); + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGAElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGAElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGContainerImpl::hasProperty(p1,p2)) { + SVGContainerImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTestsImpl::hasProperty(p1,p2)) { + SVGTestsImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTransformableImpl::hasProperty(p1,p2)) { + SVGTransformableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGURIReferenceImpl::hasProperty(p1,p2)) { + SVGURIReferenceImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGAElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGAElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGAElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAltGlyphDefElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGAltGlyphDefElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGAltGlyphDefElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGAltGlyphDefElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGAltGlyphDefElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGAltGlyphDefElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAltGlyphElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGTSpanElementImpl::hasProperty(p1,p2)) return true; + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGAltGlyphElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGTSpanElementImpl::hasProperty(p1,p2)) return SVGTSpanElementImpl::get(p1,p2,p3); + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGAltGlyphElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGTSpanElementImpl::hasProperty(p1,p2)) { + SVGTSpanElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGURIReferenceImpl::hasProperty(p1,p2)) { + SVGURIReferenceImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGAltGlyphElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGAltGlyphElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGAltGlyphElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAngleImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGAngleImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGAngleImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + return false; +} + +Value SVGAngleImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGAngleImpl *SVGAngleImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGAngleImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGAngleImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + Q_UNUSED(p3); + return Undefined(); +} + +bool SVGAngleImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGAngleImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGAngleImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGAngleImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGAngleImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAngleImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGAngleImplConstructor::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGAngleImplConstructor::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGAngleImplConstructor::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGAngleImplConstructor::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGAngleImplConstructor::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAnimateColorElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGAnimationElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGAnimateColorElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGAnimationElementImpl::hasProperty(p1,p2)) return SVGAnimationElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGAnimateColorElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGAnimationElementImpl::hasProperty(p1,p2)) { + SVGAnimationElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGAnimateColorElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGAnimateColorElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGAnimateColorElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAnimateElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGAnimationElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGAnimateElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGAnimationElementImpl::hasProperty(p1,p2)) return SVGAnimationElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGAnimateElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGAnimationElementImpl::hasProperty(p1,p2)) { + SVGAnimationElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGAnimateElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGAnimateElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGAnimateElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAnimateMotionElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGAnimationElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGAnimateMotionElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGAnimationElementImpl::hasProperty(p1,p2)) return SVGAnimationElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGAnimateMotionElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGAnimationElementImpl::hasProperty(p1,p2)) { + SVGAnimationElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGAnimateMotionElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGAnimateMotionElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGAnimateMotionElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAnimateTransformElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGAnimationElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGAnimateTransformElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGAnimationElementImpl::hasProperty(p1,p2)) return SVGAnimationElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGAnimateTransformElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGAnimationElementImpl::hasProperty(p1,p2)) { + SVGAnimationElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGAnimateTransformElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGAnimateTransformElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGAnimateTransformElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAnimatedAngleImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGAnimatedAngleImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGAnimatedAngleImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGAnimatedAngleImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGAnimatedAngleImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGAnimatedAngleImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAnimatedBooleanImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGAnimatedBooleanImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGAnimatedBooleanImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGAnimatedBooleanImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +bool SVGAnimatedBooleanImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGAnimatedBooleanImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGAnimatedBooleanImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGAnimatedBooleanImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAnimatedEnumerationImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGAnimatedEnumerationImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGAnimatedEnumerationImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGAnimatedEnumerationImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +bool SVGAnimatedEnumerationImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGAnimatedEnumerationImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGAnimatedEnumerationImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGAnimatedEnumerationImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAnimatedIntegerImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGAnimatedIntegerImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGAnimatedIntegerImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGAnimatedIntegerImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +bool SVGAnimatedIntegerImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGAnimatedIntegerImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGAnimatedIntegerImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGAnimatedIntegerImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAnimatedLengthImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGAnimatedLengthImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGAnimatedLengthImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGAnimatedLengthImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGAnimatedLengthImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGAnimatedLengthImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAnimatedLengthListImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGAnimatedLengthListImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGAnimatedLengthListImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGAnimatedLengthListImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGAnimatedLengthListImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGAnimatedLengthListImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAnimatedNumberImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGAnimatedNumberImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGAnimatedNumberImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGAnimatedNumberImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +bool SVGAnimatedNumberImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGAnimatedNumberImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGAnimatedNumberImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGAnimatedNumberImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAnimatedNumberListImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGAnimatedNumberListImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGAnimatedNumberListImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGAnimatedNumberListImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGAnimatedNumberListImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGAnimatedNumberListImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAnimatedPathDataImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGAnimatedPathDataImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGAnimatedPathDataImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGAnimatedPathDataImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGAnimatedPathDataImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGAnimatedPathDataImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAnimatedPointsImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGAnimatedPointsImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGAnimatedPointsImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGAnimatedPointsImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +bool SVGAnimatedPointsImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGAnimatedPointsImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGAnimatedPointsImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGAnimatedPointsImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAnimatedPreserveAspectRatioImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGAnimatedPreserveAspectRatioImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGAnimatedPreserveAspectRatioImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGAnimatedPreserveAspectRatioImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGAnimatedPreserveAspectRatioImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGAnimatedPreserveAspectRatioImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAnimatedRectImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGAnimatedRectImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGAnimatedRectImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGAnimatedRectImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGAnimatedRectImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGAnimatedRectImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAnimatedStringImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGAnimatedStringImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGAnimatedStringImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGAnimatedStringImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +bool SVGAnimatedStringImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGAnimatedStringImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGAnimatedStringImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGAnimatedStringImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAnimatedTransformListImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGAnimatedTransformListImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGAnimatedTransformListImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGAnimatedTransformListImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGAnimatedTransformListImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGAnimatedTransformListImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGAnimationElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGAnimationElementImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGAnimationElementImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + if(SVGElementImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGTestsImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGAnimationElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGAnimationElementImpl *SVGAnimationElementImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGAnimationElementImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGAnimationElementImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGAnimationElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGAnimationElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTestsImpl::hasProperty(p1,p2)) { + SVGTestsImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGAnimationElementImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGAnimationElementImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGAnimationElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGCircleElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGCircleElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGShapeImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGTestsImpl::hasProperty(p1,p2)) return true; + if(SVGTransformableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGCircleElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGCircleElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3); + if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGCircleElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGCircleElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGShapeImpl::hasProperty(p1,p2)) { + SVGShapeImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTestsImpl::hasProperty(p1,p2)) { + SVGTestsImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTransformableImpl::hasProperty(p1,p2)) { + SVGTransformableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGCircleElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGCircleElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGCircleElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGClipPathElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGClipPathElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGContainerImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGTestsImpl::hasProperty(p1,p2)) return true; + if(SVGTransformableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGClipPathElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGClipPathElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGContainerImpl::hasProperty(p1,p2)) return SVGContainerImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3); + if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGClipPathElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGClipPathElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGContainerImpl::hasProperty(p1,p2)) { + SVGContainerImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTestsImpl::hasProperty(p1,p2)) { + SVGTestsImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTransformableImpl::hasProperty(p1,p2)) { + SVGTransformableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGClipPathElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGClipPathElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGClipPathElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGColorImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGColorImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGColorImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + return false; +} + +Value SVGColorImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGColorImpl *SVGColorImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGColorImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGColorImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + Q_UNUSED(p3); + return Undefined(); +} + +Object SVGColorImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGColorImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGColorImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGColorImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGColorImplConstructor::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGColorImplConstructor::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGColorImplConstructor::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGColorImplConstructor::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGColorImplConstructor::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGColorProfileElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGColorProfileElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGElementImpl::hasProperty(p1,p2)) return true; + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGColorProfileElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGColorProfileElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGColorProfileElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGColorProfileElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGURIReferenceImpl::hasProperty(p1,p2)) { + SVGURIReferenceImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGColorProfileElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGColorProfileElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGColorProfileElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGComponentTransferFunctionElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGComponentTransferFunctionElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGComponentTransferFunctionElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGComponentTransferFunctionElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGComponentTransferFunctionElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGContainerImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGShapeImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGContainerImpl::get(GET_METHOD_ARGS) const +{ + if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGContainerImpl::put(PUT_METHOD_ARGS) +{ + if(SVGShapeImpl::hasProperty(p1,p2)) { + SVGShapeImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGContainerImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGContainerImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGCursorElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGCursorElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGElementImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGTestsImpl::hasProperty(p1,p2)) return true; + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGCursorElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGCursorElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3); + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGCursorElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGCursorElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTestsImpl::hasProperty(p1,p2)) { + SVGTestsImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGURIReferenceImpl::hasProperty(p1,p2)) { + SVGURIReferenceImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGCursorElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGCursorElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGDOMCharacterDataBridge::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGDOMCharacterDataBridge::s_hashTable,p2); + if(e) return true; + Object proto = SVGDOMCharacterDataBridgeProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + if(SVGDOMNodeBridge::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGDOMCharacterDataBridge::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGDOMCharacterDataBridge *SVGDOMCharacterDataBridgeProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGDOMCharacterDataBridge::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGDOMCharacterDataBridgeProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + if(SVGDOMNodeBridge::hasProperty(p1,p2)) return SVGDOMNodeBridge::get(p1,p2,p3); + return Undefined(); +} + +bool SVGDOMCharacterDataBridge::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGDOMCharacterDataBridge::putInParents(PUT_METHOD_ARGS) +{ + if(SVGDOMNodeBridge::hasProperty(p1,p2)) { + SVGDOMNodeBridge::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGDOMCharacterDataBridge::prototype(ExecState *p1) const +{ + if(p1) return SVGDOMCharacterDataBridgeProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGDOMCharacterDataBridge::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGDOMDOMImplementationBridge::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGDOMDOMImplementationBridge::s_hashTable,p2); + if(e) return true; + Object proto = SVGDOMDOMImplementationBridgeProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + return false; +} + +Value SVGDOMDOMImplementationBridge::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGDOMDOMImplementationBridge *SVGDOMDOMImplementationBridgeProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGDOMDOMImplementationBridge::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGDOMDOMImplementationBridgeProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + Q_UNUSED(p3); + return Undefined(); +} + +bool SVGDOMDOMImplementationBridge::put(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGDOMDOMImplementationBridge::prototype(ExecState *p1) const +{ + if(p1) return SVGDOMDOMImplementationBridgeProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGDOMDOMImplementationBridge::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGDOMDocumentFragmentBridge::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGDOMDocumentFragmentBridge::s_hashTable,p2); + if(e) return true; + if(SVGDOMNodeBridge::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGDOMDocumentFragmentBridge::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGDOMDocumentFragmentBridge::getInParents(GET_METHOD_ARGS) const +{ + if(SVGDOMNodeBridge::hasProperty(p1,p2)) return SVGDOMNodeBridge::get(p1,p2,p3); + return Undefined(); +} + +bool SVGDOMDocumentFragmentBridge::put(PUT_METHOD_ARGS) +{ + if(SVGDOMNodeBridge::hasProperty(p1,p2)) { + SVGDOMNodeBridge::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGDOMDocumentFragmentBridge::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGDOMDocumentFragmentBridge::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGDOMElementBridge::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGDOMElementBridge::s_hashTable,p2); + if(e) return true; + Object proto = SVGDOMElementBridgeProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + if(SVGDOMNodeBridge::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGDOMElementBridge::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGDOMElementBridge *SVGDOMElementBridgeProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGDOMElementBridge::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGDOMElementBridgeProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + if(SVGDOMNodeBridge::hasProperty(p1,p2)) return SVGDOMNodeBridge::get(p1,p2,p3); + return Undefined(); +} + +bool SVGDOMElementBridge::put(PUT_METHOD_ARGS) +{ + if(SVGDOMNodeBridge::hasProperty(p1,p2)) { + SVGDOMNodeBridge::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGDOMElementBridge::prototype(ExecState *p1) const +{ + if(p1) return SVGDOMElementBridgeProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGDOMElementBridge::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGDOMNodeBridge::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGDOMNodeBridge::s_hashTable,p2); + if(e) return true; + Object proto = SVGDOMNodeBridgeProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + return false; +} + +Value SVGDOMNodeBridge::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGDOMNodeBridge *SVGDOMNodeBridgeProtoFunc::cast(const ObjectImp *p1) const +{ + return KSVG::toNodeBridge(p1); +} + +SVGDOMNodeBridge *KSVG::toNodeBridge(const ObjectImp *p1) +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGDOMNodeBridge::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGDOMNodeBridgeProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + Q_UNUSED(p3); + return Undefined(); +} + +bool SVGDOMNodeBridge::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGDOMNodeBridge::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGDOMNodeBridge::prototype(ExecState *p1) const +{ + if(p1) return SVGDOMNodeBridgeProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGDOMNodeBridge::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGDOMNodeListBridge::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGDOMNodeListBridge::s_hashTable,p2); + if(e) return true; + Object proto = SVGDOMNodeListBridgeProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + return false; +} + +Value SVGDOMNodeListBridge::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGDOMNodeListBridge *SVGDOMNodeListBridgeProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGDOMNodeListBridge::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGDOMNodeListBridgeProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + Q_UNUSED(p3); + return Undefined(); +} + +Object SVGDOMNodeListBridge::prototype(ExecState *p1) const +{ + if(p1) return SVGDOMNodeListBridgeProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGDOMNodeListBridge::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGDOMTextBridge::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGDOMTextBridge::s_hashTable,p2); + if(e) return true; + Object proto = SVGDOMTextBridgeProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + if(SVGDOMCharacterDataBridge::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGDOMTextBridge::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGDOMTextBridge *SVGDOMTextBridgeProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGDOMTextBridge::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGDOMTextBridgeProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + if(SVGDOMCharacterDataBridge::hasProperty(p1,p2)) return SVGDOMCharacterDataBridge::get(p1,p2,p3); + return Undefined(); +} + +bool SVGDOMTextBridge::put(PUT_METHOD_ARGS) +{ + if(SVGDOMCharacterDataBridge::hasProperty(p1,p2)) { + SVGDOMCharacterDataBridge::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGDOMTextBridge::prototype(ExecState *p1) const +{ + if(p1) return SVGDOMTextBridgeProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGDOMTextBridge::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGDefinitionSrcElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGDefinitionSrcElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGDefinitionSrcElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGDefinitionSrcElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGDefinitionSrcElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGDefsElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGContainerImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGTestsImpl::hasProperty(p1,p2)) return true; + if(SVGTransformableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGDefsElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGContainerImpl::hasProperty(p1,p2)) return SVGContainerImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3); + if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGDefsElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGContainerImpl::hasProperty(p1,p2)) { + SVGContainerImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTestsImpl::hasProperty(p1,p2)) { + SVGTestsImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTransformableImpl::hasProperty(p1,p2)) { + SVGTransformableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGDefsElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGDefsElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGDefsElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGDescElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGDescElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGDescElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGDescElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGDescElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGDescElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGDocumentImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGDocumentImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGDocumentImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + if(SVGDOMNodeBridge::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGDocumentImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGDocumentImpl *SVGDocumentImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGDocumentImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGDocumentImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + if(SVGDOMNodeBridge::hasProperty(p1,p2)) return SVGDOMNodeBridge::get(p1,p2,p3); + return Undefined(); +} + +bool SVGDocumentImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGDocumentImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGDOMNodeBridge::hasProperty(p1,p2)) { + SVGDOMNodeBridge::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGDocumentImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGDocumentImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGDocumentImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGElementImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGElementImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + if(SVGDOMElementBridge::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGElementImpl *SVGElementImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGElementImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGElementImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + if(SVGDOMElementBridge::hasProperty(p1,p2)) return SVGDOMElementBridge::get(p1,p2,p3); + return Undefined(); +} + +bool SVGElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGDOMElementBridge::hasProperty(p1,p2)) { + SVGDOMElementBridge::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGElementImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGElementImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGEllipseElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGEllipseElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGShapeImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGTestsImpl::hasProperty(p1,p2)) return true; + if(SVGTransformableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGEllipseElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGEllipseElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3); + if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGEllipseElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGEllipseElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGShapeImpl::hasProperty(p1,p2)) { + SVGShapeImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTestsImpl::hasProperty(p1,p2)) { + SVGTestsImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTransformableImpl::hasProperty(p1,p2)) { + SVGTransformableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGEllipseElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGEllipseElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGEllipseElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGEventImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGEventImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGEventImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + return false; +} + +Value SVGEventImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGEventImpl *SVGEventImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGEventImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGEventImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + Q_UNUSED(p3); + return Undefined(); +} + +Object SVGEventImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGEventImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGEventImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGExternalResourcesRequiredImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGExternalResourcesRequiredImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGExternalResourcesRequiredImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGExternalResourcesRequiredImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +bool SVGExternalResourcesRequiredImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGExternalResourcesRequiredImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGExternalResourcesRequiredImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGExternalResourcesRequiredImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFEBlendElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFEBlendElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFEBlendElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFEBlendElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFEBlendElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFEColorMatrixElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFEColorMatrixElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFEColorMatrixElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFEColorMatrixElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFEColorMatrixElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFEComponentTransferElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFEComponentTransferElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFEComponentTransferElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFEComponentTransferElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFEComponentTransferElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFECompositeElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFECompositeElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFECompositeElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFECompositeElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFECompositeElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFEConvolveMatrixElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFEConvolveMatrixElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFEConvolveMatrixElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFEConvolveMatrixElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFEConvolveMatrixElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFEDiffuseLightingElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFEDiffuseLightingElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFEDiffuseLightingElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFEDiffuseLightingElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFEDiffuseLightingElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFEDisplacementMapElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFEDisplacementMapElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFEDisplacementMapElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFEDisplacementMapElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFEDisplacementMapElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFEDistantLightElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFEDistantLightElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFEDistantLightElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFEDistantLightElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFEDistantLightElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFEFloodElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFEFloodElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFEFloodElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFEFloodElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFEFloodElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFEFuncAElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFEFuncAElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) return SVGComponentTransferFunctionElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFEFuncAElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) { + SVGComponentTransferFunctionElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFEFuncAElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFEFuncAElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFEFuncBElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFEFuncBElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) return SVGComponentTransferFunctionElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFEFuncBElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) { + SVGComponentTransferFunctionElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFEFuncBElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFEFuncBElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFEFuncGElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFEFuncGElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) return SVGComponentTransferFunctionElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFEFuncGElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) { + SVGComponentTransferFunctionElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFEFuncGElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFEFuncGElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFEFuncRElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFEFuncRElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) return SVGComponentTransferFunctionElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFEFuncRElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) { + SVGComponentTransferFunctionElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFEFuncRElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFEFuncRElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFEGaussianBlurElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFEGaussianBlurElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFEGaussianBlurElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFEGaussianBlurElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFEGaussianBlurElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFEImageElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFEImageElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFEImageElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGURIReferenceImpl::hasProperty(p1,p2)) { + SVGURIReferenceImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFEImageElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFEImageElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFEMergeElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFEMergeElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFEMergeElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFEMergeElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFEMergeElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFEMergeNodeElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFEMergeNodeElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFEMergeNodeElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFEMergeNodeElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFEMergeNodeElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFEMorphologyElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFEMorphologyElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFEMorphologyElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFEMorphologyElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFEMorphologyElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFEOffsetElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFEOffsetElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFEOffsetElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFEOffsetElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFEOffsetElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFEPointLightElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFEPointLightElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFEPointLightElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFEPointLightElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFEPointLightElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFESpecularLightingElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFESpecularLightingElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFESpecularLightingElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFESpecularLightingElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFESpecularLightingElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFESpotLightElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFESpotLightElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFESpotLightElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFESpotLightElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFESpotLightElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFETileElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFETileElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFETileElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFETileElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFETileElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFETurbulenceElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFETurbulenceElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFETurbulenceElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFETurbulenceElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFETurbulenceElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFilterElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFilterElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFilterElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGURIReferenceImpl::hasProperty(p1,p2)) { + SVGURIReferenceImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFilterElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFilterElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFitToViewBoxImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGFitToViewBoxImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGFitToViewBoxImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGFitToViewBoxImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +bool SVGFitToViewBoxImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGFitToViewBoxImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGFitToViewBoxImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFitToViewBoxImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFontElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFontElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFontElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFontElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFontElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFontFaceElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFontFaceElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFontFaceElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFontFaceElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFontFaceElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFontFaceFormatElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFontFaceFormatElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFontFaceFormatElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFontFaceFormatElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFontFaceFormatElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFontFaceNameElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFontFaceNameElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFontFaceNameElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFontFaceNameElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFontFaceNameElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFontFaceSrcElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFontFaceSrcElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFontFaceSrcElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFontFaceSrcElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFontFaceSrcElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGFontFaceUriElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGFontFaceUriElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGFontFaceUriElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGFontFaceUriElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGFontFaceUriElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGForeignObjectElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGForeignObjectElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGElementImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGTestsImpl::hasProperty(p1,p2)) return true; + if(SVGTransformableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGForeignObjectElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGForeignObjectElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3); + if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGForeignObjectElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTestsImpl::hasProperty(p1,p2)) { + SVGTestsImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTransformableImpl::hasProperty(p1,p2)) { + SVGTransformableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGForeignObjectElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGForeignObjectElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGGElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGContainerImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGTestsImpl::hasProperty(p1,p2)) return true; + if(SVGTransformableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGGElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGContainerImpl::hasProperty(p1,p2)) return SVGContainerImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3); + if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGGElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGContainerImpl::hasProperty(p1,p2)) { + SVGContainerImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTestsImpl::hasProperty(p1,p2)) { + SVGTestsImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTransformableImpl::hasProperty(p1,p2)) { + SVGTransformableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGGElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGGElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGGElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGGlyphElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGGlyphElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGElementImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGGlyphElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGGlyphElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGGlyphElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGGlyphElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGGlyphElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGGlyphElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGGlyphElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGGlyphRefElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGGlyphRefElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGElementImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGGlyphRefElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGGlyphRefElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGGlyphRefElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGGlyphRefElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGURIReferenceImpl::hasProperty(p1,p2)) { + SVGURIReferenceImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGGlyphRefElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGGlyphRefElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGGlyphRefElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGGradientElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGGradientElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGElementImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGGradientElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGGradientElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGGradientElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGGradientElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGURIReferenceImpl::hasProperty(p1,p2)) { + SVGURIReferenceImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGGradientElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGGradientElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGGradientElementImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGGradientElementImplConstructor::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGGradientElementImplConstructor::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGGradientElementImplConstructor::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGGradientElementImplConstructor::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGGradientElementImplConstructor::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGHKernElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGHKernElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGHKernElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGHKernElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGHKernElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGICCColorImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGICCColorImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGICCColorImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGICCColorImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGICCColorImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGICCColorImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGImageElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGImageElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGShapeImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGTestsImpl::hasProperty(p1,p2)) return true; + if(SVGTransformableImpl::hasProperty(p1,p2)) return true; + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGImageElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGImageElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3); + if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3); + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGImageElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGImageElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGShapeImpl::hasProperty(p1,p2)) { + SVGShapeImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTestsImpl::hasProperty(p1,p2)) { + SVGTestsImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTransformableImpl::hasProperty(p1,p2)) { + SVGTransformableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGURIReferenceImpl::hasProperty(p1,p2)) { + SVGURIReferenceImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGImageElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGImageElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGImageElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGKeyEventImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGKeyEventImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGKeyEventImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + if(SVGUIEventImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGKeyEventImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGKeyEventImpl *SVGKeyEventImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGKeyEventImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGKeyEventImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + if(SVGUIEventImpl::hasProperty(p1,p2)) return SVGUIEventImpl::get(p1,p2,p3); + return Undefined(); +} + +Object SVGKeyEventImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGKeyEventImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGKeyEventImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGLangSpaceImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGLangSpaceImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGLangSpaceImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGLangSpaceImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +bool SVGLangSpaceImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGLangSpaceImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGLangSpaceImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGLangSpaceImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGLengthImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGLengthImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGLengthImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + return false; +} + +Value SVGLengthImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGLengthImpl *SVGLengthImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGLengthImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGLengthImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + Q_UNUSED(p3); + return Undefined(); +} + +bool SVGLengthImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGLengthImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGLengthImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGLengthImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGLengthImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGLengthImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGLengthImplConstructor::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGLengthImplConstructor::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGLengthImplConstructor::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGLengthImplConstructor::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGLengthImplConstructor::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGLengthListImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGLengthListImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGLengthListImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + return false; +} + +Value SVGLengthListImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGLengthListImpl *SVGLengthListImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGLengthListImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGLengthListImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + Q_UNUSED(p3); + return Undefined(); +} + +Object SVGLengthListImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGLengthListImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGLengthListImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGLineElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGLineElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGShapeImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGTestsImpl::hasProperty(p1,p2)) return true; + if(SVGTransformableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGLineElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGLineElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3); + if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGLineElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGLineElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGShapeImpl::hasProperty(p1,p2)) { + SVGShapeImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTestsImpl::hasProperty(p1,p2)) { + SVGTestsImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTransformableImpl::hasProperty(p1,p2)) { + SVGTransformableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGLineElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGLineElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGLineElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGLinearGradientElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGLinearGradientElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGGradientElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGLinearGradientElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGLinearGradientElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGGradientElementImpl::hasProperty(p1,p2)) return SVGGradientElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGLinearGradientElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGLinearGradientElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGGradientElementImpl::hasProperty(p1,p2)) { + SVGGradientElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGLinearGradientElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGLinearGradientElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGLinearGradientElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGLocatableImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGLocatableImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGLocatableImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + return false; +} + +Value SVGLocatableImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGLocatableImpl *SVGLocatableImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGLocatableImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGLocatableImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + Q_UNUSED(p3); + return Undefined(); +} + +Object SVGLocatableImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGLocatableImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGLocatableImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGMPathElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGMPathElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGMPathElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGURIReferenceImpl::hasProperty(p1,p2)) { + SVGURIReferenceImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGMPathElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGMPathElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGMarkerElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGMarkerElementImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGMarkerElementImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + if(SVGContainerImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGMarkerElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGMarkerElementImpl *SVGMarkerElementImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGMarkerElementImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGMarkerElementImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + if(SVGContainerImpl::hasProperty(p1,p2)) return SVGContainerImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return SVGFitToViewBoxImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGMarkerElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGMarkerElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGContainerImpl::hasProperty(p1,p2)) { + SVGContainerImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) { + SVGFitToViewBoxImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGMarkerElementImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGMarkerElementImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGMarkerElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGMarkerElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGMarkerElementImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGMarkerElementImplConstructor::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGMarkerElementImplConstructor::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGMarkerElementImplConstructor::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGMarkerElementImplConstructor::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGMarkerElementImplConstructor::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGMaskElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGMaskElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGElementImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGTestsImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGMaskElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGMaskElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGMaskElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGMaskElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTestsImpl::hasProperty(p1,p2)) { + SVGTestsImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGMaskElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGMaskElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGMaskElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGMatrixImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGMatrixImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGMatrixImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + return false; +} + +Value SVGMatrixImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGMatrixImpl *SVGMatrixImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGMatrixImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGMatrixImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + Q_UNUSED(p3); + return Undefined(); +} + +bool SVGMatrixImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGMatrixImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGMatrixImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGMatrixImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGMatrixImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGMetadataElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGMetadataElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGMetadataElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGMetadataElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGMetadataElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGMissingGlyphElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGMissingGlyphElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGMissingGlyphElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGMissingGlyphElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGMissingGlyphElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGMouseEventImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGMouseEventImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGMouseEventImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + if(SVGUIEventImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGMouseEventImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGMouseEventImpl *SVGMouseEventImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGMouseEventImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGMouseEventImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + if(SVGUIEventImpl::hasProperty(p1,p2)) return SVGUIEventImpl::get(p1,p2,p3); + return Undefined(); +} + +Object SVGMouseEventImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGMouseEventImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGMouseEventImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGMutationEventImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGEventImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGMutationEventImpl::get(GET_METHOD_ARGS) const +{ + if(SVGEventImpl::hasProperty(p1,p2)) return SVGEventImpl::get(p1,p2,p3); + return Undefined(); +} + +Object SVGMutationEventImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGMutationEventImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGNumberImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGNumberImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGNumberImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGNumberImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +bool SVGNumberImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGNumberImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGNumberImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGNumberImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGNumberListImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGNumberListImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGNumberListImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + return false; +} + +Value SVGNumberListImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGNumberListImpl *SVGNumberListImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGNumberListImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGNumberListImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + Q_UNUSED(p3); + return Undefined(); +} + +Object SVGNumberListImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGNumberListImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGNumberListImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPaintImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPaintImpl::s_hashTable,p2); + if(e) return true; + if(SVGColorImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPaintImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPaintImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGColorImpl::hasProperty(p1,p2)) return SVGColorImpl::get(p1,p2,p3); + return Undefined(); +} + +Object SVGPaintImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPaintImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPaintImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPaintImplConstructor::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGPaintImplConstructor::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPaintImplConstructor::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGPaintImplConstructor::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPaintImplConstructor::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathElementImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGPathElementImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + if(SVGAnimatedPathDataImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGShapeImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGTestsImpl::hasProperty(p1,p2)) return true; + if(SVGTransformableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGPathElementImpl *SVGPathElementImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGPathElementImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGPathElementImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + if(SVGAnimatedPathDataImpl::hasProperty(p1,p2)) return SVGAnimatedPathDataImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3); + if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPathElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPathElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGShapeImpl::hasProperty(p1,p2)) { + SVGShapeImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTestsImpl::hasProperty(p1,p2)) { + SVGTestsImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTransformableImpl::hasProperty(p1,p2)) { + SVGTransformableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGPathElementImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGPathElementImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGPathElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGPathElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegArcAbsImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegArcAbsImpl::s_hashTable,p2); + if(e) return true; + if(SVGPathSegImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathSegArcAbsImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPathSegArcAbsImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPathSegArcAbsImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPathSegArcAbsImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGPathSegArcAbsImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegArcAbsImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegArcRelImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegArcRelImpl::s_hashTable,p2); + if(e) return true; + if(SVGPathSegImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathSegArcRelImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPathSegArcRelImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPathSegArcRelImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPathSegArcRelImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGPathSegArcRelImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegArcRelImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegClosePathImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGPathSegImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathSegClosePathImpl::get(GET_METHOD_ARGS) const +{ + if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3); + return Undefined(); +} + +Object SVGPathSegClosePathImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegClosePathImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegCurvetoCubicAbsImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegCurvetoCubicAbsImpl::s_hashTable,p2); + if(e) return true; + if(SVGPathSegImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathSegCurvetoCubicAbsImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPathSegCurvetoCubicAbsImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPathSegCurvetoCubicAbsImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPathSegCurvetoCubicAbsImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGPathSegCurvetoCubicAbsImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegCurvetoCubicAbsImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegCurvetoCubicRelImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegCurvetoCubicRelImpl::s_hashTable,p2); + if(e) return true; + if(SVGPathSegImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathSegCurvetoCubicRelImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPathSegCurvetoCubicRelImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPathSegCurvetoCubicRelImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPathSegCurvetoCubicRelImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGPathSegCurvetoCubicRelImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegCurvetoCubicRelImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegCurvetoCubicSmoothAbsImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegCurvetoCubicSmoothAbsImpl::s_hashTable,p2); + if(e) return true; + if(SVGPathSegImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathSegCurvetoCubicSmoothAbsImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPathSegCurvetoCubicSmoothAbsImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPathSegCurvetoCubicSmoothAbsImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPathSegCurvetoCubicSmoothAbsImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGPathSegCurvetoCubicSmoothAbsImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegCurvetoCubicSmoothAbsImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegCurvetoCubicSmoothRelImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegCurvetoCubicSmoothRelImpl::s_hashTable,p2); + if(e) return true; + if(SVGPathSegImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathSegCurvetoCubicSmoothRelImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPathSegCurvetoCubicSmoothRelImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPathSegCurvetoCubicSmoothRelImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPathSegCurvetoCubicSmoothRelImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGPathSegCurvetoCubicSmoothRelImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegCurvetoCubicSmoothRelImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegCurvetoQuadraticAbsImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegCurvetoQuadraticAbsImpl::s_hashTable,p2); + if(e) return true; + if(SVGPathSegImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathSegCurvetoQuadraticAbsImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPathSegCurvetoQuadraticAbsImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPathSegCurvetoQuadraticAbsImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPathSegCurvetoQuadraticAbsImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGPathSegCurvetoQuadraticAbsImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegCurvetoQuadraticAbsImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegCurvetoQuadraticRelImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegCurvetoQuadraticRelImpl::s_hashTable,p2); + if(e) return true; + if(SVGPathSegImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathSegCurvetoQuadraticRelImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPathSegCurvetoQuadraticRelImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPathSegCurvetoQuadraticRelImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPathSegCurvetoQuadraticRelImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGPathSegCurvetoQuadraticRelImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegCurvetoQuadraticRelImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegCurvetoQuadraticSmoothAbsImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegCurvetoQuadraticSmoothAbsImpl::s_hashTable,p2); + if(e) return true; + if(SVGPathSegImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathSegCurvetoQuadraticSmoothAbsImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPathSegCurvetoQuadraticSmoothAbsImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPathSegCurvetoQuadraticSmoothAbsImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPathSegCurvetoQuadraticSmoothAbsImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGPathSegCurvetoQuadraticSmoothAbsImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegCurvetoQuadraticSmoothAbsImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegCurvetoQuadraticSmoothRelImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegCurvetoQuadraticSmoothRelImpl::s_hashTable,p2); + if(e) return true; + if(SVGPathSegImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathSegCurvetoQuadraticSmoothRelImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPathSegCurvetoQuadraticSmoothRelImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPathSegCurvetoQuadraticSmoothRelImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPathSegCurvetoQuadraticSmoothRelImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGPathSegCurvetoQuadraticSmoothRelImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegCurvetoQuadraticSmoothRelImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGPathSegImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPathSegImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGPathSegImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegImplConstructor::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGPathSegImplConstructor::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPathSegImplConstructor::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGPathSegImplConstructor::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegImplConstructor::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegLinetoAbsImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegLinetoAbsImpl::s_hashTable,p2); + if(e) return true; + if(SVGPathSegImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathSegLinetoAbsImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPathSegLinetoAbsImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPathSegLinetoAbsImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPathSegLinetoAbsImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGPathSegLinetoAbsImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegLinetoAbsImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegLinetoHorizontalAbsImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegLinetoHorizontalAbsImpl::s_hashTable,p2); + if(e) return true; + if(SVGPathSegImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathSegLinetoHorizontalAbsImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPathSegLinetoHorizontalAbsImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPathSegLinetoHorizontalAbsImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPathSegLinetoHorizontalAbsImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGPathSegLinetoHorizontalAbsImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegLinetoHorizontalAbsImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegLinetoHorizontalRelImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegLinetoHorizontalRelImpl::s_hashTable,p2); + if(e) return true; + if(SVGPathSegImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathSegLinetoHorizontalRelImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPathSegLinetoHorizontalRelImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPathSegLinetoHorizontalRelImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPathSegLinetoHorizontalRelImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGPathSegLinetoHorizontalRelImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegLinetoHorizontalRelImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegLinetoRelImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegLinetoRelImpl::s_hashTable,p2); + if(e) return true; + if(SVGPathSegImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathSegLinetoRelImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPathSegLinetoRelImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPathSegLinetoRelImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPathSegLinetoRelImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGPathSegLinetoRelImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegLinetoRelImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegLinetoVerticalAbsImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegLinetoVerticalAbsImpl::s_hashTable,p2); + if(e) return true; + if(SVGPathSegImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathSegLinetoVerticalAbsImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPathSegLinetoVerticalAbsImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPathSegLinetoVerticalAbsImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPathSegLinetoVerticalAbsImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGPathSegLinetoVerticalAbsImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegLinetoVerticalAbsImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegLinetoVerticalRelImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegLinetoVerticalRelImpl::s_hashTable,p2); + if(e) return true; + if(SVGPathSegImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathSegLinetoVerticalRelImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPathSegLinetoVerticalRelImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPathSegLinetoVerticalRelImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPathSegLinetoVerticalRelImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGPathSegLinetoVerticalRelImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegLinetoVerticalRelImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegListImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegListImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGPathSegListImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathSegListImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGPathSegListImpl *SVGPathSegListImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGPathSegListImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGPathSegListImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + Q_UNUSED(p3); + return Undefined(); +} + +Object SVGPathSegListImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGPathSegListImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegListImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegMovetoAbsImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegMovetoAbsImpl::s_hashTable,p2); + if(e) return true; + if(SVGPathSegImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathSegMovetoAbsImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPathSegMovetoAbsImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPathSegMovetoAbsImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPathSegMovetoAbsImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGPathSegMovetoAbsImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegMovetoAbsImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPathSegMovetoRelImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPathSegMovetoRelImpl::s_hashTable,p2); + if(e) return true; + if(SVGPathSegImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPathSegMovetoRelImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPathSegMovetoRelImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPathSegMovetoRelImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPathSegMovetoRelImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGPathSegMovetoRelImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPathSegMovetoRelImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPatternElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPatternElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGElementImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGTestsImpl::hasProperty(p1,p2)) return true; + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPatternElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPatternElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return SVGFitToViewBoxImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3); + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPatternElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPatternElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) { + SVGFitToViewBoxImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTestsImpl::hasProperty(p1,p2)) { + SVGTestsImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGURIReferenceImpl::hasProperty(p1,p2)) { + SVGURIReferenceImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGPatternElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGPatternElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGPatternElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPointImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPointImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGPointImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPointImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +bool SVGPointImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPointImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGPointImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPointImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPointListImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPointListImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGPointListImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPointListImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGPointListImpl *SVGPointListImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGPointListImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGPointListImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + Q_UNUSED(p3); + return Undefined(); +} + +Object SVGPointListImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGPointListImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGPointListImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPolyElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGAnimatedPointsImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGShapeImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGTestsImpl::hasProperty(p1,p2)) return true; + if(SVGTransformableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPolyElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGAnimatedPointsImpl::hasProperty(p1,p2)) return SVGAnimatedPointsImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3); + if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPolyElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGAnimatedPointsImpl::hasProperty(p1,p2)) { + SVGAnimatedPointsImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGShapeImpl::hasProperty(p1,p2)) { + SVGShapeImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTestsImpl::hasProperty(p1,p2)) { + SVGTestsImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTransformableImpl::hasProperty(p1,p2)) { + SVGTransformableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGPolyElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPolyElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPolygonElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGPolyElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPolygonElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGPolyElementImpl::hasProperty(p1,p2)) return SVGPolyElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPolygonElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGPolyElementImpl::hasProperty(p1,p2)) { + SVGPolyElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGPolygonElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGPolygonElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGPolygonElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPolylineElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGPolyElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGPolylineElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGPolyElementImpl::hasProperty(p1,p2)) return SVGPolyElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGPolylineElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGPolyElementImpl::hasProperty(p1,p2)) { + SVGPolyElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGPolylineElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGPolylineElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGPolylineElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPreserveAspectRatioImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPreserveAspectRatioImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGPreserveAspectRatioImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPreserveAspectRatioImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +bool SVGPreserveAspectRatioImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGPreserveAspectRatioImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGPreserveAspectRatioImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPreserveAspectRatioImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGPreserveAspectRatioImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGPreserveAspectRatioImplConstructor::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGPreserveAspectRatioImplConstructor::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGPreserveAspectRatioImplConstructor::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGPreserveAspectRatioImplConstructor::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGPreserveAspectRatioImplConstructor::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGRadialGradientElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGRadialGradientElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGGradientElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGRadialGradientElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGRadialGradientElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGGradientElementImpl::hasProperty(p1,p2)) return SVGGradientElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGRadialGradientElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGRadialGradientElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGGradientElementImpl::hasProperty(p1,p2)) { + SVGGradientElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGRadialGradientElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGRadialGradientElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGRadialGradientElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGRectElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGRectElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGShapeImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGTestsImpl::hasProperty(p1,p2)) return true; + if(SVGTransformableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGRectElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGRectElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3); + if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGRectElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGRectElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGShapeImpl::hasProperty(p1,p2)) { + SVGShapeImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTestsImpl::hasProperty(p1,p2)) { + SVGTestsImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTransformableImpl::hasProperty(p1,p2)) { + SVGTransformableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGRectElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGRectElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGRectElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGRectImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGRectImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGRectImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGRectImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +bool SVGRectImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGRectImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGRectImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGRectImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGSVGElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGSVGElementImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGSVGElementImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + if(SVGContainerImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGLocatableImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGTestsImpl::hasProperty(p1,p2)) return true; + if(SVGZoomAndPanImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGSVGElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGSVGElementImpl *SVGSVGElementImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGSVGElementImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGSVGElementImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + if(SVGContainerImpl::hasProperty(p1,p2)) return SVGContainerImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return SVGFitToViewBoxImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGLocatableImpl::hasProperty(p1,p2)) return SVGLocatableImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3); + if(SVGZoomAndPanImpl::hasProperty(p1,p2)) return SVGZoomAndPanImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGSVGElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGSVGElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGContainerImpl::hasProperty(p1,p2)) { + SVGContainerImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) { + SVGFitToViewBoxImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTestsImpl::hasProperty(p1,p2)) { + SVGTestsImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGZoomAndPanImpl::hasProperty(p1,p2)) { + SVGZoomAndPanImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGSVGElementImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGSVGElementImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGSVGElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGSVGElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGScriptElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGScriptElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGElementImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGScriptElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGScriptElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGScriptElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGScriptElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGURIReferenceImpl::hasProperty(p1,p2)) { + SVGURIReferenceImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGScriptElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGScriptElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGScriptElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGSetElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGAnimationElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGSetElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGAnimationElementImpl::hasProperty(p1,p2)) return SVGAnimationElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGSetElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGAnimationElementImpl::hasProperty(p1,p2)) { + SVGAnimationElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGSetElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGSetElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGSetElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGShapeImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGShapeImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGShapeImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGShapeImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGShapeImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGStopElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGStopElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGElementImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGStopElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGStopElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGStopElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGStopElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGStopElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGStopElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGStopElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGStringListImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGStringListImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGStringListImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + return false; +} + +Value SVGStringListImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGStringListImpl *SVGStringListImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGStringListImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGStringListImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + Q_UNUSED(p3); + return Undefined(); +} + +Object SVGStringListImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGStringListImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGStringListImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGStylableImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGStylableImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGStylableImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + return false; +} + +Value SVGStylableImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGStylableImpl *SVGStylableImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGStylableImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGStylableImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + Q_UNUSED(p3); + return Undefined(); +} + +bool SVGStylableImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGStylableImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGStylableImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGStylableImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGStylableImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGStyleElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGStyleElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGStyleElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGStyleElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGStyleElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGStyleElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGStyleElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGStyleElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGStyleElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGSwitchElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGContainerImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGTestsImpl::hasProperty(p1,p2)) return true; + if(SVGTransformableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGSwitchElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGContainerImpl::hasProperty(p1,p2)) return SVGContainerImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3); + if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGSwitchElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGContainerImpl::hasProperty(p1,p2)) { + SVGContainerImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTestsImpl::hasProperty(p1,p2)) { + SVGTestsImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTransformableImpl::hasProperty(p1,p2)) { + SVGTransformableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGSwitchElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGSwitchElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGSwitchElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGSymbolElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGSymbolElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGShapeImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGSymbolElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGSymbolElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return SVGFitToViewBoxImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGSymbolElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGSymbolElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) { + SVGFitToViewBoxImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGShapeImpl::hasProperty(p1,p2)) { + SVGShapeImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGSymbolElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGSymbolElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGSymbolElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGTRefElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGTSpanElementImpl::hasProperty(p1,p2)) return true; + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGTRefElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGTSpanElementImpl::hasProperty(p1,p2)) return SVGTSpanElementImpl::get(p1,p2,p3); + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGTRefElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGTSpanElementImpl::hasProperty(p1,p2)) { + SVGTSpanElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGURIReferenceImpl::hasProperty(p1,p2)) { + SVGURIReferenceImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGTRefElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGTRefElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGTRefElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGTSpanElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGTextPositioningElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGTSpanElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGTextPositioningElementImpl::hasProperty(p1,p2)) return SVGTextPositioningElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGTSpanElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGTextPositioningElementImpl::hasProperty(p1,p2)) { + SVGTextPositioningElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGTSpanElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGTSpanElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGTSpanElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGTestsImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGTestsImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGTestsImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + return false; +} + +Value SVGTestsImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGTestsImpl *SVGTestsImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGTestsImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGTestsImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + Q_UNUSED(p3); + return Undefined(); +} + +bool SVGTestsImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGTestsImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGTestsImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGTestsImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGTestsImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGTextContentElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGTextContentElementImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGTextContentElementImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGShapeImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGTestsImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGTextContentElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGTextContentElementImpl *SVGTextContentElementImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGTextContentElementImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGTextContentElementImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGTextContentElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGTextContentElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGShapeImpl::hasProperty(p1,p2)) { + SVGShapeImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTestsImpl::hasProperty(p1,p2)) { + SVGTestsImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGTextContentElementImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGTextContentElementImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGTextContentElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGTextContentElementImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGTextContentElementImplConstructor::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGTextContentElementImplConstructor::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGTextContentElementImplConstructor::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGTextContentElementImplConstructor::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGTextContentElementImplConstructor::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGTextElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGTextPositioningElementImpl::hasProperty(p1,p2)) return true; + if(SVGTransformableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGTextElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGTextPositioningElementImpl::hasProperty(p1,p2)) return SVGTextPositioningElementImpl::get(p1,p2,p3); + if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGTextElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGTextPositioningElementImpl::hasProperty(p1,p2)) { + SVGTextPositioningElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTransformableImpl::hasProperty(p1,p2)) { + SVGTransformableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGTextElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGTextElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGTextElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGTextPathElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGTextPathElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGTextContentElementImpl::hasProperty(p1,p2)) return true; + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGTextPathElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGTextPathElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGTextContentElementImpl::hasProperty(p1,p2)) return SVGTextContentElementImpl::get(p1,p2,p3); + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGTextPathElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGTextPathElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGTextContentElementImpl::hasProperty(p1,p2)) { + SVGTextContentElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGURIReferenceImpl::hasProperty(p1,p2)) { + SVGURIReferenceImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGTextPathElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGTextPathElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGTextPathElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGTextPathElementImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGTextPathElementImplConstructor::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGTextPathElementImplConstructor::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGTextPathElementImplConstructor::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGTextPathElementImplConstructor::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGTextPathElementImplConstructor::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGTextPositioningElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGTextPositioningElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGTextContentElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGTextPositioningElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGTextPositioningElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGTextContentElementImpl::hasProperty(p1,p2)) return SVGTextContentElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGTextPositioningElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGTextPositioningElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGTextContentElementImpl::hasProperty(p1,p2)) { + SVGTextContentElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGTextPositioningElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGTextPositioningElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGTitleElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGTitleElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGTitleElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGTitleElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGTitleElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGTitleElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGTransformImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGTransformImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGTransformImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + return false; +} + +Value SVGTransformImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGTransformImpl *SVGTransformImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGTransformImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGTransformImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + Q_UNUSED(p3); + return Undefined(); +} + +Object SVGTransformImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGTransformImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGTransformImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGTransformImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGTransformImplConstructor::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGTransformImplConstructor::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGTransformImplConstructor::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGTransformImplConstructor::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGTransformImplConstructor::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGTransformListImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGTransformListImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGTransformListImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + return false; +} + +Value SVGTransformListImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGTransformListImpl *SVGTransformListImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGTransformListImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGTransformListImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + Q_UNUSED(p3); + return Undefined(); +} + +Object SVGTransformListImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGTransformListImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGTransformListImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGTransformableImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGTransformableImpl::s_hashTable,p2); + if(e) return true; + if(SVGLocatableImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGTransformableImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGTransformableImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGLocatableImpl::hasProperty(p1,p2)) return SVGLocatableImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGTransformableImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGTransformableImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGTransformableImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGTransformableImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGUIEventImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGUIEventImpl::s_hashTable,p2); + if(e) return true; + Object proto = SVGUIEventImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return true; + if(SVGEventImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGUIEventImpl::get(GET_METHOD_ARGS) const +{ + return lookupGet(p1,p2,&s_hashTable,this,p3); +} + +SVGUIEventImpl *SVGUIEventImplProtoFunc::cast(const ObjectImp *p1) const +{ + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + { const KSVGBridge *test = dynamic_cast * >(p1); + if(test) return test->impl(); } + return 0; +} + +Value SVGUIEventImpl::getInParents(GET_METHOD_ARGS) const +{ + Object proto = SVGUIEventImplProto::self(p1); + if(proto.hasProperty(p1,p2)) return proto.get(p1,p2); + if(SVGEventImpl::hasProperty(p1,p2)) return SVGEventImpl::get(p1,p2,p3); + return Undefined(); +} + +Object SVGUIEventImpl::prototype(ExecState *p1) const +{ + if(p1) return SVGUIEventImplProto::self(p1); + return Object::dynamicCast(Null()); +} + +Value SVGUIEventImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGURIReferenceImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGURIReferenceImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGURIReferenceImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGURIReferenceImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +bool SVGURIReferenceImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGURIReferenceImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGURIReferenceImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGURIReferenceImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGUseElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGUseElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true; + if(SVGShapeImpl::hasProperty(p1,p2)) return true; + if(SVGStylableImpl::hasProperty(p1,p2)) return true; + if(SVGTestsImpl::hasProperty(p1,p2)) return true; + if(SVGTransformableImpl::hasProperty(p1,p2)) return true; + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGUseElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGUseElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3); + if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3); + if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3); + if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3); + if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3); + if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGUseElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGUseElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGLangSpaceImpl::hasProperty(p1,p2)) { + SVGLangSpaceImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGShapeImpl::hasProperty(p1,p2)) { + SVGShapeImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGStylableImpl::hasProperty(p1,p2)) { + SVGStylableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTestsImpl::hasProperty(p1,p2)) { + SVGTestsImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGTransformableImpl::hasProperty(p1,p2)) { + SVGTransformableImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGURIReferenceImpl::hasProperty(p1,p2)) { + SVGURIReferenceImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGUseElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGUseElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGUseElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGVKernElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGVKernElementImpl::get(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGVKernElementImpl::put(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGVKernElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGVKernElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGViewElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGViewElementImpl::s_hashTable,p2); + if(e) return true; + if(SVGElementImpl::hasProperty(p1,p2)) return true; + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true; + if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return true; + if(SVGZoomAndPanImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGViewElementImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGViewElementImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3); + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3); + if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return SVGFitToViewBoxImpl::get(p1,p2,p3); + if(SVGZoomAndPanImpl::hasProperty(p1,p2)) return SVGZoomAndPanImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGViewElementImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGViewElementImpl::putInParents(PUT_METHOD_ARGS) +{ + if(SVGElementImpl::hasProperty(p1,p2)) { + SVGElementImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) { + SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) { + SVGFitToViewBoxImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGZoomAndPanImpl::hasProperty(p1,p2)) { + SVGZoomAndPanImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGViewElementImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +ObjectImp *SVGViewElementImpl::bridge(ExecState *p1) const +{ + return new KSVGRWBridge(p1,const_cast(this)); +} + +Value SVGViewElementImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGViewSpecImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return true; + if(SVGZoomAndPanImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGViewSpecImpl::get(GET_METHOD_ARGS) const +{ + if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return SVGFitToViewBoxImpl::get(p1,p2,p3); + if(SVGZoomAndPanImpl::hasProperty(p1,p2)) return SVGZoomAndPanImpl::get(p1,p2,p3); + return Undefined(); +} + +bool SVGViewSpecImpl::put(PUT_METHOD_ARGS) +{ + if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) { + SVGFitToViewBoxImpl::put(p1,p2,p3,p4); + return true; + } + if(SVGZoomAndPanImpl::hasProperty(p1,p2)) { + SVGZoomAndPanImpl::put(p1,p2,p3,p4); + return true; + } + return false; +} + +Object SVGViewSpecImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGViewSpecImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGZoomAndPanImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGZoomAndPanImpl::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGZoomAndPanImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGZoomAndPanImpl::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +bool SVGZoomAndPanImpl::put(PUT_METHOD_ARGS) +{ + return lookupPut(p1,p2,p3,p4,&s_hashTable,this); +} + +bool SVGZoomAndPanImpl::putInParents(PUT_METHOD_ARGS) +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4); + return false; +} + +Object SVGZoomAndPanImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGZoomAndPanImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGZoomAndPanImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGZoomAndPanImplConstructor::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SVGZoomAndPanImplConstructor::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGZoomAndPanImplConstructor::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SVGZoomAndPanImplConstructor::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGZoomAndPanImplConstructor::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SVGZoomEventImpl::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SVGZoomEventImpl::s_hashTable,p2); + if(e) return true; + if(SVGUIEventImpl::hasProperty(p1,p2)) return true; + return false; +} + +Value SVGZoomEventImpl::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SVGZoomEventImpl::getInParents(GET_METHOD_ARGS) const +{ + if(SVGUIEventImpl::hasProperty(p1,p2)) return SVGUIEventImpl::get(p1,p2,p3); + return Undefined(); +} + +Object SVGZoomEventImpl::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SVGZoomEventImpl::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + +bool SharedString::hasProperty(ExecState *p1,const Identifier &p2) const +{ + const HashEntry *e = Lookup::findEntry(&SharedString::s_hashTable,p2); + if(e) return true; + Q_UNUSED(p1); + return false; +} + +Value SharedString::get(GET_METHOD_ARGS) const +{ + return lookupGetValue(p1,p2,&s_hashTable,this,p3); +} + +Value SharedString::getInParents(GET_METHOD_ARGS) const +{ + Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); + return Undefined(); +} + +Object SharedString::prototype(ExecState *p1) const +{ + if(p1) return p1->interpreter()->builtinObjectPrototype(); + return Object::dynamicCast(Null()); +} + +Value SharedString::cache(ExecState *p1) const +{ + return KJS::Value(cacheDOMObject >(p1,const_cast(this))); +} + diff --git a/ksvg/impl/libs/Makefile.am b/ksvg/impl/libs/Makefile.am new file mode 100644 index 00000000..76f41e24 --- /dev/null +++ b/ksvg/impl/libs/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = xrgbrender art_support libtext2path diff --git a/ksvg/impl/libs/art_support/Makefile.am b/ksvg/impl/libs/art_support/Makefile.am new file mode 100644 index 00000000..4bf00dd7 --- /dev/null +++ b/ksvg/impl/libs/art_support/Makefile.am @@ -0,0 +1,4 @@ +noinst_LTLIBRARIES = libksvgart.la +libksvgart_la_SOURCES = art_render_misc.c art_rgba_svp.c art_misc.c + +INCLUDES = $(LIBART_CFLAGS) $(all_includes) diff --git a/ksvg/impl/libs/art_support/art_misc.c b/ksvg/impl/libs/art_support/art_misc.c new file mode 100644 index 00000000..69b45306 --- /dev/null +++ b/ksvg/impl/libs/art_support/art_misc.c @@ -0,0 +1,1841 @@ +#include +#include +#include +#include +#include + +#include "art_misc.h" + +extern double ceil(double x); +extern double floor(double x); + +/** + * art_vpath_render_bez: Render a bezier segment into the vpath. + * @p_vpath: Where the pointer to the #ArtVpath structure is stored. + * @pn_points: Pointer to the number of points in *@p_vpath. + * @pn_points_max: Pointer to the number of points allocated. + * @x0: X coordinate of starting bezier point. + * @y0: Y coordinate of starting bezier point. + * @x1: X coordinate of first bezier control point. + * @y1: Y coordinate of first bezier control point. + * @x2: X coordinate of second bezier control point. + * @y2: Y coordinate of second bezier control point. + * @x3: X coordinate of ending bezier point. + * @y3: Y coordinate of ending bezier point. + * @flatness: Flatness control. + * + * Renders a bezier segment into the vector path, reallocating and + * updating *@p_vpath and *@pn_vpath_max as necessary. *@pn_vpath is + * incremented by the number of vector points added. + * + * This step includes (@x0, @y0) but not (@x3, @y3). + * + * The @flatness argument guides the amount of subdivision. The Adobe + * PostScript reference manual defines flatness as the maximum + * deviation between the any point on the vpath approximation and the + * corresponding point on the "true" curve, and we follow this + * definition here. A value of 0.25 should ensure high quality for aa + * rendering. + **/ + void +ksvg_art_vpath_render_bez (ArtVpath **p_vpath, int *pn, int *pn_max, + double x0, double y0, + double x1, double y1, + double x2, double y2, + double x3, double y3, + double flatness) +{ + double x3_0, y3_0; + double z3_0_dot; + double z1_dot, z2_dot; + double z1_perp, z2_perp; + double max_perp_sq; + + double x_m, y_m; + double xa1, ya1; + double xa2, ya2; + double xb1, yb1; + double xb2, yb2; + + /* It's possible to optimize this routine a fair amount. + + First, once the _dot conditions are met, they will also be met in + all further subdivisions. So we might recurse to a different + routine that only checks the _perp conditions. + + Second, the distance _should_ decrease according to fairly + predictable rules (a factor of 4 with each subdivision). So it might + be possible to note that the distance is within a factor of 4 of + acceptable, and subdivide once. But proving this might be hard. + + Third, at the last subdivision, x_m and y_m can be computed more + expeditiously (as in the routine above). + + Finally, if we were able to subdivide by, say 2 or 3, this would + allow considerably finer-grain control, i.e. fewer points for the + same flatness tolerance. This would speed things up downstream. + + In any case, this routine is unlikely to be the bottleneck. It's + just that I have this undying quest for more speed... + +*/ + + x3_0 = x3 - x0; + y3_0 = y3 - y0; + + /* z3_0_dot is dist z0-z3 squared */ + z3_0_dot = x3_0 * x3_0 + y3_0 * y3_0; + + /* todo: this test is far from satisfactory. */ + if (z3_0_dot < 0.001) + goto nosubdivide; + + /* we can avoid subdivision if: + + z1 has distance no more than flatness from the z0-z3 line + + z1 is no more z0'ward than flatness past z0-z3 + + z1 is more z0'ward than z3'ward on the line traversing z0-z3 + + and correspondingly for z2 */ + + /* perp is distance from line, multiplied by dist z0-z3 */ + max_perp_sq = flatness * flatness * z3_0_dot; + z1_perp = (y1 - y0) * x3_0 - (x1 - x0) * y3_0; + if (z1_perp * z1_perp > max_perp_sq) + goto subdivide; + + z2_perp = (y3 - y2) * x3_0 - (x3 - x2) * y3_0; + if (z2_perp * z2_perp > max_perp_sq) + goto subdivide; + + z1_dot = (x1 - x0) * x3_0 + (y1 - y0) * y3_0; + if (z1_dot < 0 && z1_dot * z1_dot > max_perp_sq) + goto subdivide; + + z2_dot = (x3 - x2) * x3_0 + (y3 - y2) * y3_0; + if (z2_dot < 0 && z2_dot * z2_dot > max_perp_sq) + goto subdivide; + + if (z1_dot + z1_dot > z3_0_dot) + goto subdivide; + + if (z2_dot + z2_dot > z3_0_dot) + goto subdivide; + +nosubdivide: + /* don't subdivide */ + art_vpath_add_point (p_vpath, pn, pn_max, + ART_LINETO, x3, y3); + return; + +subdivide: + + xa1 = (x0 + x1) * 0.5; + ya1 = (y0 + y1) * 0.5; + xa2 = (x0 + 2 * x1 + x2) * 0.25; + ya2 = (y0 + 2 * y1 + y2) * 0.25; + xb1 = (x1 + 2 * x2 + x3) * 0.25; + yb1 = (y1 + 2 * y2 + y3) * 0.25; + xb2 = (x2 + x3) * 0.5; + yb2 = (y2 + y3) * 0.5; + x_m = (xa2 + xb1) * 0.5; + y_m = (ya2 + yb1) * 0.5; +#ifdef VERBOSE + printf ("%g,%g %g,%g %g,%g %g,%g\n", xa1, ya1, xa2, ya2, + xb1, yb1, xb2, yb2); +#endif + ksvg_art_vpath_render_bez (p_vpath, pn, pn_max, + x0, y0, xa1, ya1, xa2, ya2, x_m, y_m, flatness); + ksvg_art_vpath_render_bez (p_vpath, pn, pn_max, + x_m, y_m, xb1, yb1, xb2, yb2, x3, y3, flatness); +} + +#define RENDER_LEVEL 4 +#define RENDER_SIZE (1 << (RENDER_LEVEL)) + +/** + * ksvg_art_bez_path_to_vec: Create vpath from bezier path. + * @bez: Bezier path. + * @flatness: Flatness control. + * + * Creates a vector path closely approximating the bezier path defined by + * @bez. The @flatness argument controls the amount of subdivision. In + * general, the resulting vpath deviates by at most @flatness pixels + * from the "ideal" path described by @bez. + * + * Return value: Newly allocated vpath. + **/ + ArtVpath * +ksvg_art_bez_path_to_vec(const ArtBpath *bez, double flatness) +{ + ArtVpath *vec; + int vec_n, vec_n_max; + int bez_index; + double x, y; + + vec_n = 0; + vec_n_max = RENDER_SIZE; + vec = art_new (ArtVpath, vec_n_max); + + /* Initialization is unnecessary because of the precondition that the + bezier path does not begin with LINETO or CURVETO, but is here + to make the code warning-free. */ + x = 0; + y = 0; + + bez_index = 0; + do + { +#ifdef VERBOSE + printf ("%s %g %g\n", + bez[bez_index].code == ART_CURVETO ? "curveto" : + bez[bez_index].code == ART_LINETO ? "lineto" : + bez[bez_index].code == ART_MOVETO ? "moveto" : + bez[bez_index].code == ART_MOVETO_OPEN ? "moveto-open" : + "end", bez[bez_index].x3, bez[bez_index].y3); +#endif + /* make sure space for at least one more code */ + if (vec_n >= vec_n_max) + art_expand (vec, ArtVpath, vec_n_max); + switch (bez[bez_index].code) + { + case ART_MOVETO_OPEN: + case ART_MOVETO: + case ART_LINETO: + x = bez[bez_index].x3; + y = bez[bez_index].y3; + vec[vec_n].code = bez[bez_index].code; + vec[vec_n].x = x; + vec[vec_n].y = y; + vec_n++; + break; + case ART_END: + vec[vec_n].code = ART_END; + vec[vec_n].x = 0; + vec[vec_n].y = 0; + vec_n++; + break; + case ART_END2: + vec[vec_n].code = (ArtPathcode)ART_END2; + vec[vec_n].x = bez[bez_index].x3; + vec[vec_n].y = bez[bez_index].y3; + vec_n++; + break; + case ART_CURVETO: +#ifdef VERBOSE + printf ("%g,%g %g,%g %g,%g %g,%g\n", x, y, + bez[bez_index].x1, bez[bez_index].y1, + bez[bez_index].x2, bez[bez_index].y2, + bez[bez_index].x3, bez[bez_index].y3); +#endif + ksvg_art_vpath_render_bez (&vec, &vec_n, &vec_n_max, + x, y, + bez[bez_index].x1, bez[bez_index].y1, + bez[bez_index].x2, bez[bez_index].y2, + bez[bez_index].x3, bez[bez_index].y3, + flatness); + x = bez[bez_index].x3; + y = bez[bez_index].y3; + break; + } + } + while (bez[bez_index++].code != ART_END); + return vec; +} + +/* 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 ksvg_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; +} + +/** + * ksvg_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. + * @alpha: Alpha, range 0..256. + * + * 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. + * + * KSVG additions : we have changed this function to support an alpha level as well. +* also we made sure compositing an rgba image over an rgb buffer works. +**/ + void ksvg_art_rgb_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, + int alpha) +{ + /* 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); + + if(alpha == 255) + for (y = y0; y < y1; y++) + { + pt.y = y + 0.5; + run_x0 = x0; + run_x1 = x1; + ksvg_art_rgb_affine_run (&run_x0, &run_x1, y, src_width, src_height, + inv); + dst_p = dst_linestart + (run_x0 - x0) * 3; + 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] = dst_p[0] + (((src_p[2] - dst_p[0]) * src_p[3] + 0x80) >> 8); + dst_p[1] = dst_p[1] + (((src_p[1] - dst_p[1]) * src_p[3] + 0x80) >> 8); + dst_p[2] = dst_p[2] + (((src_p[0] - dst_p[2]) * src_p[3] + 0x80) >> 8); + dst_p += 3; + } + dst_linestart += dst_rowstride; + } + else + for (y = y0; y < y1; y++) + { + pt.y = y + 0.5; + run_x0 = x0; + run_x1 = x1; + ksvg_art_rgb_affine_run (&run_x0, &run_x1, y, src_width, src_height, + inv); + dst_p = dst_linestart + (run_x0 - x0) * 3; + 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] = dst_p[0] + (((src_p[2] - dst_p[0]) * alpha + 0x80) >> 8); + dst_p[1] = dst_p[1] + (((src_p[1] - dst_p[1]) * alpha + 0x80) >> 8); + dst_p[2] = dst_p[2] + (((src_p[0] - dst_p[2]) * alpha + 0x80) >> 8); + dst_p += 3; + } + dst_linestart += dst_rowstride; + } +} + + +typedef struct _ksvgArtRgbAffineClipAlphaData ksvgArtRgbAffineClipAlphaData; + +struct _ksvgArtRgbAffineClipAlphaData +{ + int alphatab[256]; + art_u8 alpha; + art_u8 *dst; + int dst_rowstride; + int x0, x1; + double inv[6]; + const art_u8 *src; + int src_width; + int src_height; + int src_rowstride; + const art_u8 *mask; + int y0; +}; + +static +void ksvg_art_rgb_affine_clip_run(art_u8 *dst_p, int x0, int x1, int y, const double inv[6], + int alpha, const art_u8 *src, int src_rowstride, int src_width, int src_height) +{ + const art_u8 *src_p; + ArtPoint pt, src_pt; + int src_x, src_y; + int x; + + if(alpha > 255) + alpha = 255; + + pt.y = y; + + for(x = x0; x < x1; x++) + { + pt.x = x; + + art_affine_point(&src_pt, &pt, inv); + + src_x = (int)(src_pt.x); + src_y = (int)(src_pt.y); + + if(src_x >= 0 && src_x < src_width && src_y >= 0 && src_y < src_height) + { + int s; + int d; + int tmp; + int srcAlpha; + + src_p = src + (src_y * src_rowstride) + src_x * 4; + + srcAlpha = alpha * src_p[3] + 0x80; + srcAlpha = (srcAlpha + (srcAlpha >> 8)) >> 8; + + d = *dst_p; + s = src_p[2]; + + tmp = srcAlpha * (s - d) + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + *dst_p++ = d + tmp; + + d = *dst_p; + s = src_p[1]; + + tmp = srcAlpha * (s - d) + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + *dst_p++ = d + tmp; + + d = *dst_p; + s = src_p[0]; + + tmp = srcAlpha * (s - d) + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + *dst_p++ = d + tmp; + } + else + dst_p += 3; + } +} + +static void +ksvg_art_rgb_affine_clip_callback (void *callback_data, int y, + int start, ArtSVPRenderAAStep *steps, int n_steps) +{ + ksvgArtRgbAffineClipAlphaData *data = (ksvgArtRgbAffineClipAlphaData *)callback_data; + art_u8 *linebuf; + int run_x0, run_x1; + art_u32 running_sum = start; + int x0, x1; + int k; + int *alphatab; + int alpha; + + linebuf = data->dst; + x0 = data->x0; + x1 = data->x1; + + alphatab = data->alphatab; + + if(n_steps > 0) + { + run_x1 = steps[0].x; + if(run_x1 > x0) + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgb_affine_clip_run(linebuf, x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + + 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) + ksvg_art_rgb_affine_clip_run(linebuf + (run_x0 - x0) * 3, run_x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + } + running_sum += steps[k].delta; + if(x1 > run_x1) + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgb_affine_clip_run(linebuf + (run_x1 - x0) * 3, run_x1, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + } + else + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgb_affine_clip_run(linebuf, x0, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + + data->dst += data->dst_rowstride; +} + +static +void ksvg_art_rgb_affine_clip_mask_run(art_u8 *dst_p, const art_u8 *mask, int x0, int x1, int y, const double inv[6], + int alpha, const art_u8 *src, int src_rowstride, int src_width, int src_height) +{ + const art_u8 *src_p; + ArtPoint pt, src_pt; + int src_x, src_y; + int x; + + if(alpha > 255) + alpha = 255; + + pt.y = y; + + for(x = x0; x < x1; x++) + { + pt.x = x; + + art_affine_point(&src_pt, &pt, inv); + + src_x = (int)(src_pt.x); + src_y = (int)(src_pt.y); + + if(src_x >= 0 && src_x < src_width && src_y >= 0 && src_y < src_height) + { + int s; + int d; + int tmp; + int srcAlpha; + + src_p = src + (src_y * src_rowstride) + src_x * 4; + + srcAlpha = alpha * src_p[3] + 0x80; + srcAlpha = (srcAlpha + (srcAlpha >> 8)) >> 8; + + srcAlpha = (srcAlpha * *mask++) + 0x80; + srcAlpha = (srcAlpha + (srcAlpha >> 8)) >> 8; + + d = *dst_p; + s = src_p[2]; + + tmp = srcAlpha * (s - d) + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + *dst_p++ = d + tmp; + + d = *dst_p; + s = src_p[1]; + + tmp = srcAlpha * (s - d) + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + *dst_p++ = d + tmp; + + d = *dst_p; + s = src_p[0]; + + tmp = srcAlpha * (s - d) + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + *dst_p++ = d + tmp; + } + else + { + dst_p += 3; + mask++; + } + } +} + +static void +ksvg_art_rgb_affine_clip_mask_callback (void *callback_data, int y, + int start, ArtSVPRenderAAStep *steps, int n_steps) +{ + ksvgArtRgbAffineClipAlphaData *data = (ksvgArtRgbAffineClipAlphaData *)callback_data; + art_u8 *linebuf; + int run_x0, run_x1; + art_u32 running_sum = start; + int x0, x1; + int k; + int *alphatab; + int alpha; + const art_u8 *maskbuf; + + linebuf = data->dst; + x0 = data->x0; + x1 = data->x1; + + alphatab = data->alphatab; + maskbuf = data->mask + (y - data->y0) * (x1 - x0); + + if(n_steps > 0) + { + run_x1 = steps[0].x; + if(run_x1 > x0) + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgb_affine_clip_mask_run(linebuf, maskbuf, x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + + 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) + ksvg_art_rgb_affine_clip_mask_run(linebuf + (run_x0 - x0) * 3, maskbuf + (run_x0 - x0), run_x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + } + running_sum += steps[k].delta; + if(x1 > run_x1) + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgb_affine_clip_mask_run(linebuf + (run_x1 - x0) * 3, maskbuf + (run_x1 - x0), run_x1, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + } + else + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgb_affine_clip_mask_run(linebuf, maskbuf, x0, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + + data->dst += data->dst_rowstride; +} + +static +void ksvg_art_rgba_affine_clip_run(art_u8 *dst_p, int x0, int x1, int y, const double inv[6], + int alpha, const art_u8 *src, int src_rowstride, int src_width, int src_height) +{ + const art_u8 *src_p; + ArtPoint pt, src_pt; + int src_x, src_y; + int x; + + if(alpha > 255) + alpha = 255; + + pt.y = y; + + for(x = x0; x < x1; x++) + { + pt.x = x; + + art_affine_point(&src_pt, &pt, inv); + + src_x = (int)(src_pt.x); + src_y = (int)(src_pt.y); + + if(src_x >= 0 && src_x < src_width && src_y >= 0 && src_y < src_height) + { + int s; + int d; + int tmp; + int srcAlpha; + + src_p = src + (src_y * src_rowstride) + src_x * 4; + + srcAlpha = alpha * src_p[3] + 0x80; + srcAlpha = (srcAlpha + (srcAlpha >> 8)) >> 8; + + d = *dst_p; + s = src_p[2]; + + tmp = srcAlpha * (s - d) + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + *dst_p++ = d + tmp; + + d = *dst_p; + s = src_p[1]; + + tmp = srcAlpha * (s - d) + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + *dst_p++ = d + tmp; + + d = *dst_p; + s = src_p[0]; + + tmp = srcAlpha * (s - d) + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + *dst_p++ = d + tmp; + + d = *dst_p; + + tmp = srcAlpha * (255 - d) + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + *dst_p++ = d + tmp; + } + else + dst_p += 4; + } +} + +static void +ksvg_art_rgba_affine_clip_callback (void *callback_data, int y, + int start, ArtSVPRenderAAStep *steps, int n_steps) +{ + ksvgArtRgbAffineClipAlphaData *data = (ksvgArtRgbAffineClipAlphaData *)callback_data; + art_u8 *linebuf; + int run_x0, run_x1; + art_u32 running_sum = start; + int x0, x1; + int k; + int *alphatab; + int alpha; + + linebuf = data->dst; + x0 = data->x0; + x1 = data->x1; + + alphatab = data->alphatab; + + if(n_steps > 0) + { + run_x1 = steps[0].x; + if(run_x1 > x0) + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgba_affine_clip_run(linebuf, x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + + 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) + ksvg_art_rgba_affine_clip_run(linebuf + (run_x0 - x0) * 4, run_x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + } + running_sum += steps[k].delta; + if(x1 > run_x1) + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgba_affine_clip_run(linebuf + (run_x1 - x0) * 4, run_x1, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + } + else + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgba_affine_clip_run(linebuf, x0, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + + data->dst += data->dst_rowstride; +} + +static +void ksvg_art_rgba_affine_clip_mask_run(art_u8 *dst_p, const art_u8 *mask, int x0, int x1, int y, const double inv[6], + int alpha, const art_u8 *src, int src_rowstride, int src_width, int src_height) +{ + const art_u8 *src_p; + ArtPoint pt, src_pt; + int src_x, src_y; + int x; + + if(alpha > 255) + alpha = 255; + + pt.y = y; + + for(x = x0; x < x1; x++) + { + pt.x = x; + + art_affine_point(&src_pt, &pt, inv); + + src_x = (int)(src_pt.x); + src_y = (int)(src_pt.y); + + if(src_x >= 0 && src_x < src_width && src_y >= 0 && src_y < src_height) + { + int s; + int d; + int tmp; + int srcAlpha; + + src_p = src + (src_y * src_rowstride) + src_x * 4; + + srcAlpha = alpha * src_p[3] + 0x80; + srcAlpha = (srcAlpha + (srcAlpha >> 8)) >> 8; + + srcAlpha = (srcAlpha * *mask++) + 0x80; + srcAlpha = (srcAlpha + (srcAlpha >> 8)) >> 8; + + d = *dst_p; + s = src_p[2]; + + tmp = srcAlpha * (s - d) + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + *dst_p++ = d + tmp; + + d = *dst_p; + s = src_p[1]; + + tmp = srcAlpha * (s - d) + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + *dst_p++ = d + tmp; + + d = *dst_p; + s = src_p[0]; + + tmp = srcAlpha * (s - d) + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + *dst_p++ = d + tmp; + + d = *dst_p; + + tmp = srcAlpha * (255 - d) + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + *dst_p++ = d + tmp; + } + else + { + dst_p += 4; + mask++; + } + } +} + +static void +ksvg_art_rgba_affine_clip_mask_callback (void *callback_data, int y, + int start, ArtSVPRenderAAStep *steps, int n_steps) +{ + ksvgArtRgbAffineClipAlphaData *data = (ksvgArtRgbAffineClipAlphaData *)callback_data; + art_u8 *linebuf; + int run_x0, run_x1; + art_u32 running_sum = start; + int x0, x1; + int k; + int *alphatab; + int alpha; + const art_u8 *maskbuf; + + linebuf = data->dst; + x0 = data->x0; + x1 = data->x1; + + alphatab = data->alphatab; + maskbuf = data->mask + (y - data->y0) * (x1 - x0); + + if(n_steps > 0) + { + run_x1 = steps[0].x; + if(run_x1 > x0) + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgba_affine_clip_mask_run(linebuf, maskbuf, x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + + 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) + ksvg_art_rgba_affine_clip_mask_run(linebuf + (run_x0 - x0) * 4, maskbuf + (run_x0 - x0), run_x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + } + running_sum += steps[k].delta; + if(x1 > run_x1) + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgba_affine_clip_mask_run(linebuf + (run_x1 - x0) * 4, maskbuf + (run_x1 - x0), run_x1, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + } + else + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgba_affine_clip_mask_run(linebuf, maskbuf, x0, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + + data->dst += data->dst_rowstride; +} + +/** + * ksvg_art_rgb_affine_clip: Affine transform source RGB image and composite, with clipping path. + * @svp: Clipping path. + * @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. + * @alpha: Alpha, range 0..256. + * + * 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. + * + * KSVG additions : we have changed this function to support an alpha level as well. +* also we made sure compositing an rgba image over an rgb buffer works. +**/ +void ksvg_art_rgb_affine_clip(const ArtSVP *svp, art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride, int dst_channels, + const art_u8 *src, + int src_width, int src_height, int src_rowstride, + const double affine[6], + int alpha, const art_u8 *mask) +{ + ksvgArtRgbAffineClipAlphaData data; + int i; + int a, da; + + data.alpha = alpha; + + 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.dst = dst; + data.dst_rowstride = dst_rowstride; + data.x0 = x0; + data.x1 = x1; + data.y0 = y0; + data.mask = mask; + + art_affine_invert(data.inv, affine); + + data.src = src; + data.src_width = src_width; + data.src_height = src_height; + data.src_rowstride = src_rowstride; + + if(dst_channels == 3) + { + if(mask) + art_svp_render_aa(svp, x0, y0, x1, y1, ksvg_art_rgb_affine_clip_mask_callback, &data); + else + art_svp_render_aa(svp, x0, y0, x1, y1, ksvg_art_rgb_affine_clip_callback, &data); + } + else + { + if(mask) + art_svp_render_aa(svp, x0, y0, x1, y1, ksvg_art_rgba_affine_clip_mask_callback, &data); + else + art_svp_render_aa(svp, x0, y0, x1, y1, ksvg_art_rgba_affine_clip_callback, &data); + } +} + + +static +void ksvg_art_rgb_texture_run(art_u8 *dst_p, int x0, int x1, int y, const double inv[6], + int alpha, const art_u8 *src, int src_rowstride, int src_width, int src_height) +{ + const art_u8 *src_p; + ArtPoint pt, src_pt; + int src_x, src_y; + int x; + int srcAlpha; + + if(alpha > 255) + alpha = 255; + + /* TODO: optimise and filter? */ + pt.y = y + 0.5; + + for(x = x0; x < x1; x++) + { + int s; + int d; + int tmp; + int tmp2; + + pt.x = x + 0.5; + + art_affine_point(&src_pt, &pt, inv); + + src_x = (int)floor(src_pt.x); + src_y = (int)floor(src_pt.y); + + if(src_x < 0) + { + /* Can't assume % behaviour with negative values */ + src_x += ((src_x / -src_width) + 1) * src_width; + } + + if(src_y < 0) + { + src_y += ((src_y / -src_height) + 1) * src_height; + } + + src_x %= src_width; + src_y %= src_height; + + src_p = src + (src_y * src_rowstride) + src_x * 4; + + /* Pattern source is in RGBA format, premultiplied. + * alpha represents fill/stroke/group opacity. + * + * Multiply source alpha by 'alpha' then composite over. + * For each channel, d = d + alpha * (s - srcAlpha * d). + */ + + srcAlpha = src_p[3]; + + d = *dst_p; + s = *src_p++; + + tmp = srcAlpha * d + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + tmp2 = alpha * (s - tmp) + 0x80; + tmp2 = (tmp2 + (tmp2 >> 8)) >> 8; + + *dst_p++ = d + tmp2; + + d = *dst_p; + s = *src_p++; + + tmp = srcAlpha * d + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + tmp2 = alpha * (s - tmp) + 0x80; + tmp2 = (tmp2 + (tmp2 >> 8)) >> 8; + + *dst_p++ = d + tmp2; + + d = *dst_p; + s = *src_p++; + + tmp = srcAlpha * d + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + tmp2 = alpha * (s - tmp) + 0x80; + tmp2 = (tmp2 + (tmp2 >> 8)) >> 8; + + *dst_p++ = d + tmp2; + } +} + +static void +ksvg_art_rgb_texture_callback (void *callback_data, int y, + int start, ArtSVPRenderAAStep *steps, int n_steps) +{ + ksvgArtRgbAffineClipAlphaData *data = (ksvgArtRgbAffineClipAlphaData *)callback_data; + art_u8 *linebuf; + int run_x0, run_x1; + art_u32 running_sum = start; + int x0, x1; + int k; + int *alphatab; + int alpha; + + linebuf = data->dst; + x0 = data->x0; + x1 = data->x1; + + alphatab = data->alphatab; + + if(n_steps > 0) + { + run_x1 = steps[0].x; + if(run_x1 > x0) + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgb_texture_run(linebuf, x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + + 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) + ksvg_art_rgb_texture_run(linebuf + (run_x0 - x0) * 3, run_x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + } + running_sum += steps[k].delta; + if(x1 > run_x1) + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgb_texture_run(linebuf + (run_x1 - x0) * 3, run_x1, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + } + else + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgb_texture_run(linebuf, x0, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + + data->dst += data->dst_rowstride; +} + +static +void ksvg_art_rgb_texture_mask_run(art_u8 *dst_p, const art_u8 *mask, int x0, int x1, int y, const double inv[6], + int alpha, const art_u8 *src, int src_rowstride, int src_width, int src_height) +{ + const art_u8 *src_p; + ArtPoint pt, src_pt; + int src_x, src_y; + int x; + int srcAlpha; + + if(alpha > 255) + alpha = 255; + + /* TODO: optimise and filter? */ + pt.y = y + 0.5; + + for(x = x0; x < x1; x++) + { + int s; + int d; + int am; + int tmp; + int tmp2; + + pt.x = x + 0.5; + + art_affine_point(&src_pt, &pt, inv); + + src_x = (int)floor(src_pt.x); + src_y = (int)floor(src_pt.y); + + if(src_x < 0) + { + /* Can't assume % behaviour with negative values */ + src_x += ((src_x / -src_width) + 1) * src_width; + } + + if(src_y < 0) + { + src_y += ((src_y / -src_height) + 1) * src_height; + } + + src_x %= src_width; + src_y %= src_height; + + src_p = src + (src_y * src_rowstride) + src_x * 4; + + /* Pattern source is in RGBA format, premultiplied. + * alpha represents fill/stroke/group opacity. + * + * Multiply source alpha by 'alpha' and mask value then composite over. + * For each channel, d = d + alpha * mask * (s - srcAlpha * d). + */ + + am = (alpha * *mask++) + 0x80; + am = (am + (am >> 8)) >> 8; + + srcAlpha = src_p[3]; + + d = *dst_p; + s = *src_p++; + + tmp = srcAlpha * d + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + tmp2 = am * (s - tmp) + 0x80; + tmp2 = (tmp2 + (tmp2 >> 8)) >> 8; + + *dst_p++ = d + tmp2; + + d = *dst_p; + s = *src_p++; + + tmp = srcAlpha * d + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + tmp2 = am * (s - tmp) + 0x80; + tmp2 = (tmp2 + (tmp2 >> 8)) >> 8; + + *dst_p++ = d + tmp2; + + d = *dst_p; + s = *src_p++; + + tmp = srcAlpha * d + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + tmp2 = am * (s - tmp) + 0x80; + tmp2 = (tmp2 + (tmp2 >> 8)) >> 8; + + *dst_p++ = d + tmp2; + } +} + +static void +ksvg_art_rgb_texture_mask_callback (void *callback_data, int y, + int start, ArtSVPRenderAAStep *steps, int n_steps) +{ + ksvgArtRgbAffineClipAlphaData *data = (ksvgArtRgbAffineClipAlphaData *)callback_data; + art_u8 *linebuf; + int run_x0, run_x1; + art_u32 running_sum = start; + int x0, x1; + int k; + int *alphatab; + int alpha; + const art_u8 *maskbuf; + + linebuf = data->dst; + x0 = data->x0; + x1 = data->x1; + + alphatab = data->alphatab; + + maskbuf = data->mask + (y - data->y0) * (x1 - x0); + + if(n_steps > 0) + { + run_x1 = steps[0].x; + if(run_x1 > x0) + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgb_texture_mask_run(linebuf, maskbuf, x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + + 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) + ksvg_art_rgb_texture_mask_run(linebuf + (run_x0 - x0) * 3, maskbuf + (run_x0 - x0), run_x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + } + running_sum += steps[k].delta; + if(x1 > run_x1) + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgb_texture_mask_run(linebuf + (run_x1 - x0) * 3, maskbuf + (run_x1 - x0), run_x1, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + } + else + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgb_texture_mask_run(linebuf, maskbuf, x0, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + + data->dst += data->dst_rowstride; +} + +static +void ksvg_art_rgba_texture_run(art_u8 *dst_p, int x0, int x1, int y, const double inv[6], + int alpha, const art_u8 *src, int src_rowstride, int src_width, int src_height) +{ + const art_u8 *src_p; + ArtPoint pt, src_pt; + int src_x, src_y; + int x; + int srcAlpha; + + if(alpha > 255) + alpha = 255; + + /* TODO: optimise and filter? */ + pt.y = y + 0.5; + + for(x = x0; x < x1; x++) + { + int s; + int d; + int tmp; + int tmp2; + + pt.x = x + 0.5; + + art_affine_point(&src_pt, &pt, inv); + + src_x = (int)floor(src_pt.x); + src_y = (int)floor(src_pt.y); + + if(src_x < 0) + { + /* Can't assume % behaviour with negative values */ + src_x += ((src_x / -src_width) + 1) * src_width; + } + + if(src_y < 0) + { + src_y += ((src_y / -src_height) + 1) * src_height; + } + + src_x %= src_width; + src_y %= src_height; + + src_p = src + (src_y * src_rowstride) + src_x * 4; + + /* Pattern source is in RGBA format, premultiplied. + * alpha represents fill/stroke/group opacity. + * + * Multiply source alpha by 'alpha' then composite over. + * For each colour channel, d = d + alpha * (s - srcAlpha * d). + */ + + srcAlpha = src_p[3]; + + d = *dst_p; + s = *src_p++; + + tmp = srcAlpha * d + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + tmp2 = alpha * (s - tmp) + 0x80; + tmp2 = (tmp2 + (tmp2 >> 8)) >> 8; + + *dst_p++ = d + tmp2; + + d = *dst_p; + s = *src_p++; + + tmp = srcAlpha * d + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + tmp2 = alpha * (s - tmp) + 0x80; + tmp2 = (tmp2 + (tmp2 >> 8)) >> 8; + + *dst_p++ = d + tmp2; + + d = *dst_p; + s = *src_p++; + + tmp = srcAlpha * d + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + tmp2 = alpha * (s - tmp) + 0x80; + tmp2 = (tmp2 + (tmp2 >> 8)) >> 8; + + *dst_p++ = d + tmp2; + + /* dstAlpha = dstAlpha + srcAlpha * alpha * (1 - dstAlpha) */ + d = *dst_p; + + tmp = srcAlpha * alpha + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + tmp2 = tmp * (255 - d) + 0x80; + tmp2 = (tmp2 + (tmp2 >> 8)) >> 8; + + *dst_p++ = d + tmp2; + src_p++; + } +} + +static void +ksvg_art_rgba_texture_callback (void *callback_data, int y, + int start, ArtSVPRenderAAStep *steps, int n_steps) +{ + ksvgArtRgbAffineClipAlphaData *data = (ksvgArtRgbAffineClipAlphaData *)callback_data; + art_u8 *linebuf; + int run_x0, run_x1; + art_u32 running_sum = start; + int x0, x1; + int k; + int *alphatab; + int alpha; + + linebuf = data->dst; + x0 = data->x0; + x1 = data->x1; + + alphatab = data->alphatab; + + if(n_steps > 0) + { + run_x1 = steps[0].x; + if(run_x1 > x0) + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgba_texture_run(linebuf, x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + + 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) + ksvg_art_rgba_texture_run(linebuf + (run_x0 - x0) * 4, run_x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + } + running_sum += steps[k].delta; + if(x1 > run_x1) + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgba_texture_run(linebuf + (run_x1 - x0) * 4, run_x1, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + } + else + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgba_texture_run(linebuf, x0, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + + data->dst += data->dst_rowstride; +} + +static +void ksvg_art_rgba_texture_mask_run(art_u8 *dst_p, const art_u8 *mask, int x0, int x1, int y, const double inv[6], + int alpha, const art_u8 *src, int src_rowstride, int src_width, int src_height) +{ + const art_u8 *src_p; + ArtPoint pt, src_pt; + int src_x, src_y; + int x; + int srcAlpha; + + if(alpha > 255) + alpha = 255; + + /* TODO: optimise and filter? */ + pt.y = y + 0.5; + + for(x = x0; x < x1; x++) + { + int s; + int d; + int am; + int tmp; + int tmp2; + + pt.x = x + 0.5; + + art_affine_point(&src_pt, &pt, inv); + + src_x = (int)floor(src_pt.x); + src_y = (int)floor(src_pt.y); + + if(src_x < 0) + { + /* Can't assume % behaviour with negative values */ + src_x += ((src_x / -src_width) + 1) * src_width; + } + + if(src_y < 0) + { + src_y += ((src_y / -src_height) + 1) * src_height; + } + + src_x %= src_width; + src_y %= src_height; + + src_p = src + (src_y * src_rowstride) + src_x * 4; + + /* Pattern source is in RGBA format, premultiplied. + * alpha represents fill/stroke/group opacity. + * + * Multiply source alpha by 'alpha' and mask value then composite over. + * For each channel, d = d + alpha * mask * (s - srcAlpha * d). + */ + + am = (alpha * *mask++) + 0x80; + am = (am + (am >> 8)) >> 8; + + srcAlpha = src_p[3]; + + d = *dst_p; + s = *src_p++; + + tmp = srcAlpha * d + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + tmp2 = am * (s - tmp) + 0x80; + tmp2 = (tmp2 + (tmp2 >> 8)) >> 8; + + *dst_p++ = d + tmp2; + + d = *dst_p; + s = *src_p++; + + tmp = srcAlpha * d + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + tmp2 = am * (s - tmp) + 0x80; + tmp2 = (tmp2 + (tmp2 >> 8)) >> 8; + + *dst_p++ = d + tmp2; + + d = *dst_p; + s = *src_p++; + + tmp = srcAlpha * d + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + tmp2 = am * (s - tmp) + 0x80; + tmp2 = (tmp2 + (tmp2 >> 8)) >> 8; + + *dst_p++ = d + tmp2; + + /* dstAlpha = dstAlpha + srcAlpha * alpha * mask * (1 - dstAlpha) */ + d = *dst_p; + + tmp = srcAlpha * am + 0x80; + tmp = (tmp + (tmp >> 8)) >> 8; + + tmp2 = tmp * (255 - d) + 0x80; + tmp2 = (tmp2 + (tmp2 >> 8)) >> 8; + + *dst_p++ = d + tmp2; + src_p++; + } +} + +static void +ksvg_art_rgba_texture_mask_callback (void *callback_data, int y, + int start, ArtSVPRenderAAStep *steps, int n_steps) +{ + ksvgArtRgbAffineClipAlphaData *data = (ksvgArtRgbAffineClipAlphaData *)callback_data; + art_u8 *linebuf; + int run_x0, run_x1; + art_u32 running_sum = start; + int x0, x1; + int k; + int *alphatab; + int alpha; + const art_u8 *maskbuf; + + linebuf = data->dst; + x0 = data->x0; + x1 = data->x1; + + alphatab = data->alphatab; + + maskbuf = data->mask + (y - data->y0) * (x1 - x0); + + if(n_steps > 0) + { + run_x1 = steps[0].x; + if(run_x1 > x0) + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgba_texture_mask_run(linebuf, maskbuf, x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + + 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) + ksvg_art_rgba_texture_mask_run(linebuf + (run_x0 - x0) * 4, maskbuf + (run_x0 - x0), run_x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + } + running_sum += steps[k].delta; + if(x1 > run_x1) + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgba_texture_mask_run(linebuf + (run_x1 - x0) * 4, maskbuf + (run_x1 - x0), run_x1, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + } + else + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + ksvg_art_rgba_texture_mask_run(linebuf, maskbuf, x0, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height); + } + + data->dst += data->dst_rowstride; +} + +/** + * ksvg_art_rgb_texture: Affine transform source RGB image and composite, with clipping path. + * @svp: Clipping path. + * @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. + * @alpha: Alpha, range 0..256. + * + * 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. + * + * KSVG additions : we have changed this function to support an alpha level as well. +* also we made sure compositing an rgba image over an rgb buffer works. +**/ +void ksvg_art_rgb_texture(const ArtSVP *svp, art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride, + int dst_channels, + const art_u8 *src, + int src_width, int src_height, int src_rowstride, + const double affine[6], + ArtFilterLevel level, + ArtAlphaGamma *alphaGamma, + int alpha, + const art_u8 *mask) +{ + ksvgArtRgbAffineClipAlphaData data; + int i; + int a, da; + + data.alpha = alpha; + + 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.dst = dst; + data.dst_rowstride = dst_rowstride; + data.x0 = x0; + data.x1 = x1; + + data.inv[0] = affine[0]; + data.inv[1] = affine[1]; + data.inv[2] = affine[2]; + data.inv[3] = affine[3]; + data.inv[4] = affine[4]; + data.inv[5] = affine[5]; + + data.src = src; + data.src_width = src_width; + data.src_height = src_height; + data.src_rowstride = src_rowstride; + + data.mask = mask; + data.y0 = y0; + + if(mask) + { + if(dst_channels == 3) + art_svp_render_aa(svp, x0, y0, x1, y1, ksvg_art_rgb_texture_mask_callback, &data); + else + art_svp_render_aa(svp, x0, y0, x1, y1, ksvg_art_rgba_texture_mask_callback, &data); + } + else + { + if(dst_channels == 3) + art_svp_render_aa(svp, x0, y0, x1, y1, ksvg_art_rgb_texture_callback, &data); + else + art_svp_render_aa(svp, x0, y0, x1, y1, ksvg_art_rgba_texture_callback, &data); + } +} + +/** + * ksvg_art_svp_move: moves an svp relatively to the current position. + * @svp: SVP to move. + * @dx: relative amount to move horizontally. + * @dy: relative amount to move vertically. + * + * Note : this function always moves the svp, not taking into account render buffer + * boundaries. + **/ +void ksvg_art_svp_move(ArtSVP *svp, int dx, int dy) +{ + int i, j; + ArtSVPSeg *seg; + + if(dx == 0 && dy == 0) return; + for(i = 0;i < svp->n_segs;i++) + { + seg = &svp->segs[i]; + for(j = 0;j < seg->n_points;j++) + { + seg->points[j].x += dx; + seg->points[j].y += dy; + } + seg->bbox.x0 += dx; + seg->bbox.y0 += dy; + seg->bbox.x1 += dx; + seg->bbox.y1 += dy; + } +} + diff --git a/ksvg/impl/libs/art_support/art_misc.h b/ksvg/impl/libs/art_support/art_misc.h new file mode 100644 index 00000000..52f09a63 --- /dev/null +++ b/ksvg/impl/libs/art_support/art_misc.h @@ -0,0 +1,79 @@ +/* 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 __KSVG_ART_H__ +#define __KSVG_ART_H__ + +#include +#include +#include +#include +#include +#include + +#define ART_END2 10 + +#ifdef __cplusplus +extern "C" { +#endif + + void ksvg_art_vpath_render_bez (ArtVpath **p_vpath, int *pn, int *pn_max, + double x0, double y0, + double x1, double y1, + double x2, double y2, + double x3, double y3, + double flatness); + + ArtVpath *ksvg_art_bez_path_to_vec(const ArtBpath *bez, double flatness); + + void ksvg_art_rgb_affine_run (int *p_x0, int *p_x1, int y, + int src_width, int src_height, + const double affine[6]); + + void ksvg_art_rgb_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, + int alpha); + + void ksvg_art_rgb_affine_clip(const ArtSVP *svp, art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride, int dst_channels, + const art_u8 *src, + int src_width, int src_height, int src_rowstride, + const double affine[6], + int alpha, const art_u8 *mask); + + void ksvg_art_rgb_texture(const ArtSVP *svp, art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride, + int dst_channels, + const art_u8 *src, + int src_width, int src_height, int src_rowstride, + const double affine[6], + ArtFilterLevel level, + ArtAlphaGamma *alphaGamma, + int alpha, + const art_u8 *mask); + + void ksvg_art_svp_move(ArtSVP *svp, int dx, int dy); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ksvg/impl/libs/art_support/art_render_misc.c b/ksvg/impl/libs/art_support/art_render_misc.c new file mode 100644 index 00000000..1603da1e --- /dev/null +++ b/ksvg/impl/libs/art_support/art_render_misc.c @@ -0,0 +1,774 @@ +/* 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) 2001-2003 KSVG Team + * + * 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 + * Alexander Larsson + */ + +#include "config.h" +#include "art_render_misc.h" + +#include +#include +#include +#include + +/* These are in KSVGHelper.cpp */ +int linearRGBFromsRGB(int sRGB8bit); +int sRGBFromLinearRGB(int linearRGB8bit); + +typedef struct _ArtImageSourceGradRad ArtImageSourceGradRad; + +struct _ArtImageSourceGradRad { + ArtImageSource super; + const ArtKSVGGradientRadial *gradient; + double a; +}; + +#define EPSILON 1e-6 + +/** + * art_ksvg_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_ksvg_render_gradient_setpix (ArtRender *render, + art_u8 *dst, + int n_stops, ArtGradientStop *stops, + double offset, ArtKSVGGradientInterpolation interpolation) +{ + 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); + if(interpolation == ART_KSVG_LINEARRGB_INTERPOLATION) + { + for (j = 0; j < n_ch; j++) + { + int z0, z1; + int z; + int z0_8bit, z0_linearRGB_8bit; + int z1_8bit, z1_linearRGB_8bit; + int z_8bit, z_sRGB_8bit; + + /* Note: Using explicit variables for intermediate steps since */ + /* the ART_PIX macros reference the argument more than once. */ + z0 = stops[ix - 1].color[j]; + z0_8bit = ART_PIX_8_FROM_MAX(z0); + z0_linearRGB_8bit = linearRGBFromsRGB(z0_8bit); + z0 = ART_PIX_MAX_FROM_8(z0_linearRGB_8bit); + + z1 = stops[ix].color[j]; + z1_8bit = ART_PIX_8_FROM_MAX(z1); + z1_linearRGB_8bit = linearRGBFromsRGB(z1_8bit); + z1 = ART_PIX_MAX_FROM_8(z1_linearRGB_8bit); + + z = floor (z0 + (z1 - z0) * interp + 0.5); + z_8bit = ART_PIX_8_FROM_MAX(z); + z_sRGB_8bit = sRGBFromLinearRGB(z_8bit); + + if (render->buf_depth == 8) + dst[j] = z_sRGB_8bit; + else /* (render->buf_depth == 16) */ + ((art_u16 *)dst)[j] = ART_PIX_MAX_FROM_8(z_sRGB_8bit); + } + } + else + { + /* sRGB interpolation */ + 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_ksvg_render_gradient_radial_done (ArtRenderCallback *self, ArtRender *render) +{ + art_free (self); +} + +static void +art_ksvg_render_gradient_radial_render (ArtRenderCallback *self, ArtRender *render, + art_u8 *dest, int y) +{ + ArtImageSourceGradRad *z = (ArtImageSourceGradRad *)self; + const ArtKSVGGradientRadial *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_ksvg_render_gradient_setpix (render, bufp, n_stops, stops, z, gradient->interpolation); + bufp += pixstride; + b_a += db_a; + rad += drad; + drad += ddrad; + } +} + +static void +art_ksvg_render_gradient_radial_negotiate (ArtImageSource *self, ArtRender *render, + ArtImageSourceFlags *p_flags, + int *p_buf_depth, ArtAlphaType *p_alpha) +{ + self->super.render = art_ksvg_render_gradient_radial_render; + *p_flags = 0; + *p_buf_depth = render->depth; + *p_alpha = ART_ALPHA_SEPARATE; +} + +/** + * art_ksvg_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_ksvg_render_gradient_radial (ArtRender *render, + const ArtKSVGGradientRadial *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_ksvg_render_gradient_radial_done; + image_source->super.negotiate = art_ksvg_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); +} + + +/* Hack to find out how to define alloca on different platforms. + * Modified version of glib/galloca.h. + */ + +#ifdef __GNUC__ +/* GCC does the right thing */ + #undef alloca + #define alloca(size) __builtin_alloca (size) +#elif defined (HAVE_ALLOCA_H) +/* a native and working alloca.h is there */ + #include +#else /* !__GNUC__ && !HAVE_ALLOCA_H */ + #ifdef _MSC_VER + #include + #define alloca _alloca + #else /* !_MSC_VER */ + #ifdef _AIX + #pragma alloca + #else /* !_AIX */ + #ifndef alloca /* predefined by HP cc +Olibcalls */ +char *alloca (); + #endif /* !alloca */ + #endif /* !_AIX */ + #endif /* !_MSC_VER */ +#endif /* !__GNUC__ && !HAVE_ALLOCA_H */ + +#undef DEBUG_SPEW + +typedef struct _ArtImageSourceGradLin ArtImageSourceGradLin; + +/* The stops will be copied right after this structure */ +struct _ArtImageSourceGradLin +{ + ArtImageSource super; + ArtKSVGGradientLinear gradient; + ArtGradientStop stops[1]; +}; + +#ifndef MAX + #define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif /* MAX */ + +#ifndef MIN + #define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif /* MIN */ + +static void +art_ksvg_rgba_gradient_run (art_u8 *buf, + art_u8 *color1, + art_u8 *color2, + int len) +{ + int i; + int r, g, b, a; + int dr, dg, db, da; + +#ifdef DEBUG_SPEW + printf ("gradient run from %3d %3d %3d %3d to %3d %3d %3d %3d in %d pixels\n", + color1[0], color1[1], color1[2], color1[3], + color2[0], color2[1], color2[2], color2[3], + len); +#endif + + r = (color1[0] << 16) + 0x8000; + g = (color1[1] << 16) + 0x8000; + b = (color1[2] << 16) + 0x8000; + a = (color1[3] << 16) + 0x8000; + dr = ((color2[0] - color1[0]) << 16) / len; + dg = ((color2[1] - color1[1]) << 16) / len; + db = ((color2[2] - color1[2]) << 16) / len; + da = ((color2[3] - color1[3]) << 16) / len; + + for(i = 0; i < len; i++) + { + *buf++ = (r>>16); + *buf++ = (g>>16); + *buf++ = (b>>16); + *buf++ = (a>>16); + + r += dr; + g += dg; + b += db; + a += da; + } +} + +static void +ksvg_calc_color_at (ArtGradientStop *stops, + int n_stops, + ArtGradientSpread spread, + double offset, + double offset_fraction, + int favor_start, + int ix, + art_u8 *color) +{ + double off0, off1; + int j; + + if(spread == ART_GRADIENT_PAD) + { + if(offset < EPSILON) + { + color[0] = ART_PIX_8_FROM_MAX (stops[0].color[0]); + color[1] = ART_PIX_8_FROM_MAX (stops[0].color[1]); + color[2] = ART_PIX_8_FROM_MAX (stops[0].color[2]); + color[3] = ART_PIX_8_FROM_MAX (stops[0].color[3]); + return; + } + if(offset >= 1.0 - EPSILON) + { + color[0] = ART_PIX_8_FROM_MAX (stops[n_stops-1].color[0]); + color[1] = ART_PIX_8_FROM_MAX (stops[n_stops-1].color[1]); + color[2] = ART_PIX_8_FROM_MAX (stops[n_stops-1].color[2]); + color[3] = ART_PIX_8_FROM_MAX (stops[n_stops-1].color[3]); + return; + } + } + + if(ix > 0 && ix < n_stops) + { + off0 = stops[ix - 1].offset; + off1 = stops[ix].offset; + if(fabs (off1 - off0) > EPSILON) + { + double interp; + double o; + o = offset_fraction; + + if((fabs (o) < EPSILON) && (!favor_start)) + o = 1.0; + else if((fabs (o-1.0) < EPSILON) && (favor_start)) + o = 0.0; + + /* + if (offset_fraction == 0.0 && !favor_start) + offset_fraction = 1.0; + */ + + interp = (o - off0) / (off1 - off0); + for(j = 0; j < 4; 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); + color[j] = ART_PIX_8_FROM_MAX (z); + } + return; + } + /* If offsets are too close to safely do the division, just + pick the ix color. */ + color[0] = ART_PIX_8_FROM_MAX (stops[ix].color[0]); + color[1] = ART_PIX_8_FROM_MAX (stops[ix].color[1]); + color[2] = ART_PIX_8_FROM_MAX (stops[ix].color[2]); + color[3] = ART_PIX_8_FROM_MAX (stops[ix].color[3]); + return; + } + + /*printf ("WARNING! bad ix %d in calc_color_at() [internal error]\n", ix); + assert (0);*/ +} + +static void +art_ksvg_render_gradient_linear_render_8 (ArtRenderCallback *self, + ArtRender *render, + art_u8 *dest, int y) +{ + ArtImageSourceGradLin *z = (ArtImageSourceGradLin *)self; + const ArtKSVGGradientLinear *gradient = &(z->gradient); + int i; + int width = render->x1 - render->x0; + int len; + double offset, d_offset; + double offset_fraction; + int next_stop; + int ix; + art_u8 color1[4], color2[4]; + int n_stops = gradient->n_stops; + int extra_stops; + ArtGradientStop *stops = gradient->stops; + ArtGradientStop *tmp_stops; + art_u8 *bufp = render->image_buf; + ArtGradientSpread spread = gradient->spread; + +#ifdef DEBUG_SPEW + printf ("x1: %d, x2: %d, y: %d\n", render->x0, render->x1, y); + printf ("spread: %d, stops:", gradient->spread); + for(i=0;istops[i].offset); + } + printf ("\n"); + printf ("a: %f, b: %f, c: %f\n", gradient->a, gradient->b, gradient->c); +#endif + + offset = render->x0 * gradient->affine[0] + y * gradient->affine[2] + gradient->affine[4]; + d_offset = gradient->affine[0]; + + /* We need to force the gradient to extend the whole 0..1 segment, + because the rest of the code doesn't handle partial gradients + correctly */ + if((gradient->stops[0].offset > EPSILON /* == 0.0 */) || + (gradient->stops[n_stops-1].offset < (1.0 - EPSILON))) + { + extra_stops = 0; + tmp_stops = stops = alloca (sizeof (ArtGradientStop) * (n_stops + 2)); + if(gradient->stops[0].offset > EPSILON /* 0.0 */) + { + memcpy (tmp_stops, gradient->stops, sizeof (ArtGradientStop)); + tmp_stops[0].offset = 0.0; + tmp_stops += 1; + extra_stops++; + } + memcpy (tmp_stops, gradient->stops, sizeof (ArtGradientStop) * n_stops); + if(gradient->stops[n_stops-1].offset < (1.0 - EPSILON)) + { + tmp_stops += n_stops; + memcpy (tmp_stops, &gradient->stops[n_stops-1], sizeof (ArtGradientStop)); + tmp_stops[0].offset = 1.0; + extra_stops++; + } + n_stops += extra_stops; + + +#ifdef DEBUG_SPEW + printf ("start/stop modified stops:"); + for(i=0;i offset_fraction || + (d_offset < 0.0 && fabs (stops[ix].offset - offset_fraction) < EPSILON)) + break; + if(ix == 0) + ix = n_stops - 1; + else if(ix == n_stops) + ix = n_stops - 1; + +#ifdef DEBUG_SPEW + printf ("Initial ix: %d\n", ix); +#endif +#if 0 + assert (ix > 0); + assert (ix < n_stops); + assert ((stops[ix-1].offset <= offset_fraction + EPSILON) || + ((stops[ix].offset > (1.0 - EPSILON)) && (offset_fraction < EPSILON /* == 0.0*/))); + /*assert (offset_fraction <= stops[ix].offset);*/ + /* FIXME: These asserts may be broken, it is for now + safer to not use them. Should be fixed! + See bug #121850 + assert ((offset_fraction != stops[ix-1].offset) || + (d_offset >= 0.0)); + assert ((offset_fraction != stops[ix].offset) || + (d_offset <= 0.0)); + */ +#endif + while(width > 0) + { +#ifdef DEBUG_SPEW + printf ("ix: %d\n", ix); + printf ("start offset: %f\n", offset); +#endif + ksvg_calc_color_at (stops, n_stops, + spread, + offset, + offset_fraction, + (d_offset > -EPSILON), + ix, + color1); + + if(d_offset > 0) + next_stop = ix; + else + next_stop = ix-1; + +#ifdef DEBUG_SPEW + printf ("next_stop: %d\n", next_stop); +#endif + if(fabs (d_offset) > EPSILON) + { + double o; + o = offset_fraction; + + if((fabs (o) <= EPSILON) && (ix == n_stops - 1)) + o = 1.0; + else if((fabs (o-1.0) <= EPSILON) && (ix == 1)) + o = 0.0; + +#ifdef DEBUG_SPEW + printf ("o: %f\n", o); +#endif + len = (int)floor (fabs ((stops[next_stop].offset - o) / d_offset)) + 1; + len = MAX (len, 0); + len = MIN (len, width); + } + else + { + len = width; + } +#ifdef DEBUG_SPEW + printf ("len: %d\n", len); +#endif + if(len > 0) + { + offset = offset + (len-1) * d_offset; + offset_fraction = offset - floor (offset); +#ifdef DEBUG_SPEW + printf ("end offset: %f, fraction: %f\n", offset, offset_fraction); +#endif + ksvg_calc_color_at (stops, n_stops, + spread, + offset, + offset_fraction, + (d_offset < EPSILON), + ix, + color2); + + art_ksvg_rgba_gradient_run (bufp, + color1, + color2, + len); + offset += d_offset; + offset_fraction = offset - floor (offset); + } + + if(d_offset > 0) + { + do + { + ix++; + if(ix == n_stops) + ix = 1; + /* Note: offset_fraction can actually be one here on x86 machines that + does calculations with extended precision, but later rounds to 64bit. + This happens if the 80bit offset_fraction is larger than the + largest 64bit double that is less than one. + */ + } + while(!((stops[ix-1].offset <= offset_fraction && + offset_fraction < stops[ix].offset) || + (ix == 1 && offset_fraction > (1.0 - EPSILON)))); + } + else + { + do + { + ix--; + if(ix == 0) + ix = n_stops - 1; + } + while(!((stops[ix-1].offset < offset_fraction && + offset_fraction <= stops[ix].offset) || + (ix == n_stops - 1 && offset_fraction < EPSILON /* == 0.0*/))); + } + + bufp += 4*len; + width -= len; + } +} + +static void +art_ksvg_render_gradient_linear_done (ArtRenderCallback *self, ArtRender *render) +{ + art_free (self); +} + +static void +art_ksvg_render_gradient_linear_render (ArtRenderCallback *self, ArtRender *render, + art_u8 *dest, int y) +{ + ArtImageSourceGradLin *z = (ArtImageSourceGradLin *)self; + const ArtKSVGGradientLinear *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->affine[0] + y * gradient->affine[2] + gradient->affine[4]; + d_offset = gradient->affine[0]; + + 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_ksvg_render_gradient_setpix (render, bufp, n_stops, stops, actual_offset, gradient->interpolation); + offset += d_offset; + bufp += pixstride; + } +} + +static void +art_ksvg_render_gradient_linear_negotiate (ArtImageSource *self, ArtRender *render, + ArtImageSourceFlags *p_flags, + int *p_buf_depth, ArtAlphaType *p_alpha) +{ + ArtImageSourceGradLin *z = (ArtImageSourceGradLin *)self; + + if(render->depth == 8 && + render->n_chan == 3 && + z->gradient.interpolation == ART_KSVG_SRGB_INTERPOLATION) + { + /* The optimised renderer doesn't support linearRGB interpolation at the moment */ + /* so we only use it for sRGB, which is more common anyway. */ + self->super.render = art_ksvg_render_gradient_linear_render_8; + *p_flags = 0; + *p_buf_depth = 8; + *p_alpha = ART_ALPHA_SEPARATE; + return; + } + + self->super.render = art_ksvg_render_gradient_linear_render; + *p_flags = 0; + *p_buf_depth = render->depth; + *p_alpha = ART_ALPHA_SEPARATE; +} + +/** + * art_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_ksvg_render_gradient_linear (ArtRender *render, + const ArtKSVGGradientLinear *gradient, + ArtFilterLevel level) +{ + ArtImageSourceGradLin *image_source = art_alloc (sizeof (ArtImageSourceGradLin) + + sizeof (ArtGradientStop) * (gradient->n_stops - 1)); + + image_source->super.super.render = NULL; + image_source->super.super.done = art_ksvg_render_gradient_linear_done; + image_source->super.negotiate = art_ksvg_render_gradient_linear_negotiate; + + /* copy the gradient into the structure */ + image_source->gradient = *gradient; + image_source->gradient.stops = image_source->stops; + memcpy (image_source->gradient.stops, gradient->stops, sizeof (ArtGradientStop) * gradient->n_stops); + + art_render_add_image_source (render, &image_source->super); +} + diff --git a/ksvg/impl/libs/art_support/art_render_misc.h b/ksvg/impl/libs/art_support/art_render_misc.h new file mode 100644 index 00000000..d1f3690b --- /dev/null +++ b/ksvg/impl/libs/art_support/art_render_misc.h @@ -0,0 +1,90 @@ +/* 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) 2001-2002 KSVG Team + * + * 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 + * Alexander Larsson + */ + +#ifndef __ART_RENDER_MISC_H__ +#define __ART_RENDER_MISC_H__ + +#ifdef LIBART_COMPILATION +#include "art_filterlevel.h" +#include "art_render.h" +#include "art_render_gradient.h" +#else +#include +#include +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef enum +{ + ART_KSVG_SRGB_INTERPOLATION, + ART_KSVG_LINEARRGB_INTERPOLATION +} ArtKSVGGradientInterpolation; + +typedef struct _ArtKSVGGradientRadial ArtKSVGGradientRadial; + +struct _ArtKSVGGradientRadial { + 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; + ArtKSVGGradientInterpolation interpolation; +}; + +void +art_ksvg_render_gradient_radial (ArtRender *render, + const ArtKSVGGradientRadial *gradient, + ArtFilterLevel level); + +typedef struct _ArtKSVGGradientLinear ArtKSVGGradientLinear; + +struct _ArtKSVGGradientLinear { + double affine[6]; /* transforms screen gradient vector to unit vector (1, 0) */ + ArtGradientSpread spread; + int n_stops; + ArtGradientStop *stops; + ArtKSVGGradientInterpolation interpolation; +}; + +void +art_ksvg_render_gradient_linear (ArtRender *render, + const ArtKSVGGradientLinear *gradient, + ArtFilterLevel level); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __ART_RENDER_MISC_H__ */ diff --git a/ksvg/impl/libs/art_support/art_rgba_svp.c b/ksvg/impl/libs/art_support/art_rgba_svp.c new file mode 100644 index 00000000..47c7d924 --- /dev/null +++ b/ksvg/impl/libs/art_support/art_rgba_svp.c @@ -0,0 +1,659 @@ +/* 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 + +#include "art_rgba_svp.h" + +#include +#include +#include +#include + +/* RGBA renderers */ + +typedef struct _ArtKSVGRgbaSVPAlphaData ArtKSVGRgbaSVPAlphaData; + +struct _ArtKSVGRgbaSVPAlphaData { + int alphatab[256]; + art_u8 r, g, b, alpha; + art_u32 rgba; + art_u8 *buf; + art_u8 *mask; + int rowstride; + int x0, x1; + int y0; +}; + +/** + * art_rgba_fill_run: fill an RGBA 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, solid + * alpha. Thus, locations @buf (inclusive) through @buf + 4 * @n + * (exclusive) are written. + **/ +static void +art_ksvg_rgba_fill_run (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int n) +{ + int i; +#if X_BYTE_ORDER == X_BIG_ENDIAN + art_u32 src_rgba; +#else + art_u32 src_abgr; +#endif + +#if X_BYTE_ORDER == X_BIG_ENDIAN + src_rgba = (r << 24) | (g << 16) | (b << 8) | 255; +#else + src_abgr = (255 << 24) | (b << 16) | (g << 8) | r; +#endif + for(i = 0; i < n; i++) + { +#if X_BYTE_ORDER == X_BIG_ENDIAN + ((art_u32 *)buf)[i] = src_rgba; +#else + ((art_u32 *)buf)[i] = src_abgr; +#endif + } +} + +/** + * art_rgba_run_alpha: Render semitransparent color over RGBA buffer. + * @buf: Buffer for rendering. + * @r: Red, range 0..255. + * @g: Green, range 0..255. + * @b: Blue, range 0..255. + * @alpha: Alpha, range 0..255. + * @n: Number of RGB triples to render. + * + * Renders a sequential run of solid (@r, @g, @b) color over @buf with + * opacity @alpha. Note that the range of @alpha is 0..255, in contrast + * to art_rgb_run_alpha, which has a range of 0..256. + **/ +static void +art_ksvg_rgba_run_alpha (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n) +{ + int i; + int v; + int tmp; + + if(alpha > 255) + alpha = 255; + + for(i = 0; i < n; i++) + { + v = *buf; + tmp = (r - v) * alpha + 0x80; + *buf++ = v + ((tmp + (tmp >> 8)) >> 8); + + v = *buf; + tmp = (g - v) * alpha + 0x80; + *buf++ = v + ((tmp + (tmp >> 8)) >> 8); + + v = *buf; + tmp = (b - v) * alpha + 0x80; + *buf++ = v + ((tmp + (tmp >> 8)) >> 8); + + v = *buf; + tmp = (255 - alpha) * v + 0x80; + *buf++ = alpha + ((tmp + (tmp >> 8)) >> 8); + } +} + +static void +art_ksvg_rgba_mask_run_alpha (art_u8 *buf, art_u8 *mask, art_u8 r, art_u8 g, art_u8 b, int alpha, int n) +{ + int i; + int v; + int am; + int tmp; + + if(alpha > 255) + alpha = 255; + + for(i = 0; i < n; i++) + { + am = (alpha * *mask++) + 0x80; + am = (am + (am >> 8)) >> 8; + + v = *buf; + tmp = (r - v) * am + 0x80; + *buf++ = v + ((tmp + (tmp >> 8)) >> 8); + + v = *buf; + tmp = (g - v) * am + 0x80; + *buf++ = v + ((tmp + (tmp >> 8)) >> 8); + + v = *buf; + tmp = (b - v) * am + 0x80; + *buf++ = v + ((tmp + (tmp >> 8)) >> 8); + + v = *buf; + tmp = (255 - am) * v + 0x80; + *buf++ = am + ((tmp + (tmp >> 8)) >> 8); + } +} + +static void +art_ksvg_rgba_svp_alpha_callback(void *callback_data, int y, + int start, ArtSVPRenderAAStep *steps, int n_steps) +{ + ArtKSVGRgbaSVPAlphaData *data = (ArtKSVGRgbaSVPAlphaData *)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_ksvg_rgba_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_ksvg_rgba_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_ksvg_rgba_run_alpha (linebuf + (run_x1 - x0) * 4, + r, g, b, alphatab[alpha], + x1 - run_x1); + } + } + else + { + alpha = (running_sum >> 16) & 0xff; + if (alpha) + art_ksvg_rgba_run_alpha (linebuf, + r, g, b, alphatab[alpha], + x1 - x0); + } + + data->buf += data->rowstride; +} + +static void +art_ksvg_rgba_svp_alpha_opaque_callback(void *callback_data, int y, + int start, + ArtSVPRenderAAStep *steps, int n_steps) +{ + ArtKSVGRgbaSVPAlphaData *data = (ArtKSVGRgbaSVPAlphaData *)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 rgba; + int *alphatab; + int alpha; + + linebuf = data->buf; + x0 = data->x0; + x1 = data->x1; + + r = data->r; + g = data->g; + b = data->b; + rgba = data->rgba; + 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_ksvg_rgba_fill_run (linebuf, + r, g, b, + run_x1 - x0); + else + art_ksvg_rgba_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_ksvg_rgba_fill_run (linebuf + (run_x0 - x0) * 4, + r, g, b, + run_x1 - run_x0); + else + art_ksvg_rgba_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_ksvg_rgba_fill_run (linebuf + (run_x1 - x0) * 4, + r, g, b, + x1 - run_x1); + else + art_ksvg_rgba_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_ksvg_rgba_fill_run (linebuf, + r, g, b, + x1 - x0); + else + art_ksvg_rgba_run_alpha (linebuf, + r, g, b, alphatab[alpha], + x1 - x0); + } + } + data->buf += data->rowstride; +} + +static void +art_ksvg_rgba_svp_alpha_mask_callback(void *callback_data, int y, + int start, ArtSVPRenderAAStep *steps, int n_steps) +{ + ArtKSVGRgbaSVPAlphaData *data = (ArtKSVGRgbaSVPAlphaData *)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; + art_u8 *maskbuf; + + linebuf = data->buf; + x0 = data->x0; + x1 = data->x1; + + r = data->r; + g = data->g; + b = data->b; + alphatab = data->alphatab; + + maskbuf = data->mask + (y - data->y0) * (data->x1 - data->x0); + + if(n_steps > 0) + { + run_x1 = steps[0].x; + if(run_x1 > x0) + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + art_ksvg_rgba_mask_run_alpha (linebuf, maskbuf, + 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_ksvg_rgba_mask_run_alpha (linebuf + (run_x0 - x0) * 4, maskbuf + (run_x0 - x0), + 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_ksvg_rgba_mask_run_alpha (linebuf + (run_x1 - x0) * 4, maskbuf + (run_x1 - x0) , + r, g, b, alphatab[alpha], + x1 - run_x1); + } + } + else + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + art_ksvg_rgba_mask_run_alpha (linebuf, maskbuf, + 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_ksvg_rgba_svp_alpha(const ArtSVP *svp, + int x0, int y0, int x1, int y1, + art_u32 rgba, + art_u8 *buf, int rowstride, + ArtAlphaGamma *alphagamma, + art_u8 *mask) +{ + ArtKSVGRgbaSVPAlphaData data; + int r, g, b; + int i; + int a, da; + int alpha; + + r = (rgba >> 24) & 0xff; + g = (rgba >> 16) & 0xff; + b = (rgba >> 8) & 0xff; + alpha = rgba & 0xff; + + data.r = r; + data.g = g; + data.b = b; + data.alpha = alpha; + data.rgba = rgba; + data.mask = mask; + + 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; + data.y0 = y0; + + if(mask) + art_svp_render_aa (svp, x0, y0, x1, y1, art_ksvg_rgba_svp_alpha_mask_callback, &data); + else + { + if (alpha == 255) + art_svp_render_aa (svp, x0, y0, x1, y1, art_ksvg_rgba_svp_alpha_opaque_callback, &data); + else + art_svp_render_aa (svp, x0, y0, x1, y1, art_ksvg_rgba_svp_alpha_callback, &data); + } +} + +/* RGB renderers */ + +static void +art_ksvg_rgb_mask_run_alpha(art_u8 *buf, art_u8 *mask, art_u8 r, art_u8 g, art_u8 b, int alpha, int n) +{ + int i; + int v; + int am; + int tmp; + + if(alpha > 255) + alpha = 255; + + for(i = 0; i < n; i++) + { + am = (alpha * *mask++) + 0x80; + am = (am + (am >> 8)) >> 8; + + v = *buf; + tmp = (r - v) * am + 0x80; + *buf++ = v + ((tmp + (tmp >> 8)) >> 8); + + v = *buf; + tmp = (g - v) * am + 0x80; + *buf++ = v + ((tmp + (tmp >> 8)) >> 8); + + v = *buf; + tmp = (b - v) * am + 0x80; + *buf++ = v + ((tmp + (tmp >> 8)) >> 8); + } +} + +static void +art_ksvg_rgb_svp_alpha_mask_callback(void *callback_data, int y, + int start, ArtSVPRenderAAStep *steps, int n_steps) +{ + ArtKSVGRgbaSVPAlphaData *data = (ArtKSVGRgbaSVPAlphaData *)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; + art_u8 *maskbuf; + + linebuf = data->buf; + x0 = data->x0; + x1 = data->x1; + + r = data->r; + g = data->g; + b = data->b; + alphatab = data->alphatab; + + maskbuf = data->mask + (y - data->y0) * (data->x1 - data->x0); + + if(n_steps > 0) + { + run_x1 = steps[0].x; + if(run_x1 > x0) + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + art_ksvg_rgb_mask_run_alpha (linebuf, maskbuf, + 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_ksvg_rgb_mask_run_alpha (linebuf + (run_x0 - x0) * 3, maskbuf + (run_x0 - x0), + 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_ksvg_rgb_mask_run_alpha (linebuf + (run_x1 - x0) * 3, maskbuf + (run_x1 - x0) , + r, g, b, alphatab[alpha], + x1 - run_x1); + } + } + else + { + alpha = (running_sum >> 16) & 0xff; + if(alpha) + art_ksvg_rgb_mask_run_alpha (linebuf, maskbuf, + 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_ksvg_rgb_svp_alpha_mask(const ArtSVP *svp, + int x0, int y0, int x1, int y1, + art_u32 rgba, + art_u8 *buf, int rowstride, + ArtAlphaGamma *alphagamma, + art_u8 *mask) +{ + ArtKSVGRgbaSVPAlphaData data; + int r, g, b, alpha; + int i; + int a, da; + + r = rgba >> 24; + g = (rgba >> 16) & 0xff; + b = (rgba >> 8) & 0xff; + alpha = rgba & 0xff; + + data.r = r; + data.g = g; + data.b = b; + data.alpha = alpha; + data.mask = mask; + + 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; + data.y0 = y0; + + art_svp_render_aa(svp, x0, y0, x1, y1, art_ksvg_rgb_svp_alpha_mask_callback, &data); +} + diff --git a/ksvg/impl/libs/art_support/art_rgba_svp.h b/ksvg/impl/libs/art_support/art_rgba_svp.h new file mode 100644 index 00000000..b59096d4 --- /dev/null +++ b/ksvg/impl/libs/art_support/art_rgba_svp.h @@ -0,0 +1,57 @@ +/* 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_RGBA_SVP_H__ +#define __ART_RGBA_SVP_H__ + +/* Render a sorted vector path into an RGB buffer. */ + +#ifdef LIBART_COMPILATION +#include "art_alphagamma.h" +#include "art_svp.h" +#else +#include +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void +art_ksvg_rgba_svp_alpha(const ArtSVP *svp, + int x0, int y0, int x1, int y1, + art_u32 rgba, + art_u8 *buf, int rowstride, + ArtAlphaGamma *alphagamma, + art_u8 *mask); + +void +art_ksvg_rgb_svp_alpha_mask(const ArtSVP *svp, + int x0, int y0, int x1, int y1, + art_u32 rgba, + art_u8 *buf, int rowstride, + ArtAlphaGamma *alphagamma, + art_u8 *mask); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __ART_RGB_SVP_H__ */ diff --git a/ksvg/impl/libs/libtext2path/AUTHORS b/ksvg/impl/libs/libtext2path/AUTHORS new file mode 100644 index 00000000..efa499dd --- /dev/null +++ b/ksvg/impl/libs/libtext2path/AUTHORS @@ -0,0 +1 @@ +Nikolas Zimmermann diff --git a/ksvg/impl/libs/libtext2path/COPYING b/ksvg/impl/libs/libtext2path/COPYING new file mode 100644 index 00000000..0b84a43f --- /dev/null +++ b/ksvg/impl/libs/libtext2path/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +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 give any other recipients of the Program a copy of this License +along with the Program. + +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 Program or any portion +of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +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 Program, 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 Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) 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; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, 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 executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or 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 counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program 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. + + 5. 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 Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. 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 Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program 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 Program. + +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. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program 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. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 Program +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 Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, 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 + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ksvg/impl/libs/libtext2path/ChangeLog b/ksvg/impl/libs/libtext2path/ChangeLog new file mode 100644 index 00000000..fad2a19b --- /dev/null +++ b/ksvg/impl/libs/libtext2path/ChangeLog @@ -0,0 +1,2 @@ +Fri Jul 25 08:30:43 CEST 2003 - Nikolas Zimmermann + o Initial Creation diff --git a/ksvg/impl/libs/libtext2path/INSTALL b/ksvg/impl/libs/libtext2path/INSTALL new file mode 100644 index 00000000..28fadaa7 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/INSTALL @@ -0,0 +1,181 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + diff --git a/ksvg/impl/libs/libtext2path/Makefile.am b/ksvg/impl/libs/libtext2path/Makefile.am new file mode 100644 index 00000000..c7f2f390 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/Makefile.am @@ -0,0 +1,7 @@ +SUBDIRS = src +DIST_SUBDIRS = src + +#pkgconfigdir = $(libdir)/pkgconfig +#kgconfig_DATA = libtext2path-0.1.pc + +#EXTRA_DIST = autogen.sh diff --git a/ksvg/impl/libs/libtext2path/NEWS b/ksvg/impl/libs/libtext2path/NEWS new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/NEWS @@ -0,0 +1 @@ + diff --git a/ksvg/impl/libs/libtext2path/README b/ksvg/impl/libs/libtext2path/README new file mode 100644 index 00000000..b9493b88 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/README @@ -0,0 +1,4 @@ +libtext2path v0.1 +Nikolas Zimmermann +---------------------------------------------------------------------- +TODO: Write documentation! :) diff --git a/ksvg/impl/libs/libtext2path/VERSION b/ksvg/impl/libs/libtext2path/VERSION new file mode 100644 index 00000000..6c2cb464 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/VERSION @@ -0,0 +1 @@ +libtext2path-0.1 diff --git a/ksvg/impl/libs/libtext2path/configure.in.in b/ksvg/impl/libs/libtext2path/configure.in.in new file mode 100644 index 00000000..2198ab52 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/configure.in.in @@ -0,0 +1,41 @@ +#AC_INIT(src/Converter.h) +#AM_CONFIG_HEADER(config.h) + +dnl ----------------------------------------------- +dnl Package name and version number (user defined) +dnl ----------------------------------------------- +GENERIC_LIBRARY_NAME=libtext2path-0.1 + +# release versioning +GENERIC_MAJOR_VERSION=0 +GENERIC_MINOR_VERSION=1 +GENERIC_MICRO_VERSION=0 + +# API version (often = GENERIC_MAJOR_VERSION.GENERIC_MINOR_VERSION) +GENERIC_API_VERSION=0.1 +AC_SUBST(GENERIC_API_VERSION) + +#shared library versioning +GENERIC_LIBRARY_VERSION=0:1:0 + +dnl -------------------------------- +dnl Package name and version number +dnl -------------------------------- +AC_SUBST(GENERIC_LIBRARY_VERSION) + +AC_SUBST(GENERIC_LIBRARY_NAME) + +GENERIC_VERSION=$GENERIC_MAJOR_VERSION.$GENERIC_MINOR_VERSION.$GENERIC_MICRO_VERSION +GENERIC_RELEASE=$GENERIC_MAJOR_VERSION.$GENERIC_MINOR_VERSION +AC_SUBST(GENERIC_RELEASE) +AC_SUBST(GENERIC_VERSION) + + +dnl ----------------------------------------------- +dnl Checks for programs. +dnl ----------------------------------------------- + +dnl Check for fontconfig +# PKG_CHECK_MODULES(DEPS, fontconfig >= 2.2.0) +#AC_SUBST(DEPS_CFLAGS) +#AC_SUBST(DEPS_LIBS) diff --git a/ksvg/impl/libs/libtext2path/libtext2path.lsm b/ksvg/impl/libs/libtext2path/libtext2path.lsm new file mode 100644 index 00000000..7407a0ff --- /dev/null +++ b/ksvg/impl/libs/libtext2path/libtext2path.lsm @@ -0,0 +1,16 @@ +Begin4 +Title: libtext2path -- Some description +Version: 0.1 +Entered-date: YYYY-MM-DD +Description: +Keywords: KDE3 Qt +Author: Nikolas Zimmermann +Maintained-by: Nikolas Zimmermann +Home-page: +Alternate-site: +Primary-site: ftp://ftp.kde.org/pub/kde/unstable/apps/utils + xxxxxx libtext2path-0.1.tar.gz + xxx libtext2path-0.1.lsm +Platform: Linux. Needs KDE 2.x +Copying-policy: GPL +End diff --git a/ksvg/impl/libs/libtext2path/libtext2path.pc.in b/ksvg/impl/libs/libtext2path/libtext2path.pc.in new file mode 100644 index 00000000..1d4b4210 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/libtext2path.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libtext2path +Description: Converts FreeType glyphs to bezier paths +Version: @VERSION@ +Libs: -L${libdir} -ltext2path +Cflags: -I${includedir}/@GENERIC_LIBRARY_NAME@ -I${libdir}/@GENERIC_LIBRARY_NAME@/include + diff --git a/ksvg/impl/libs/libtext2path/libtext2path.spec b/ksvg/impl/libs/libtext2path/libtext2path.spec new file mode 100644 index 00000000..e0c217bd --- /dev/null +++ b/ksvg/impl/libs/libtext2path/libtext2path.spec @@ -0,0 +1,41 @@ +%define distversion %( perl -e 'Creating /home/nikoz/Projects/libtext2path/libtext2path.spec...=\<\>;/(\d+)\.(\d)\.?(\d)?/; print "".(||0)' /etc/*-release) +Name: libtext2path +Summary: libtext2path -- Some description +Version: 0.1 +Release: %{_vendor}_%{distversion} +Copyright: GPL +Group: X11/KDE/Utilities +Source: ftp://ftp.kde.org/pub/kde/unstable/apps/utils/%{name}-%{version}.tar.gz +Packager: Nikolas Zimmermann +BuildRoot: /tmp/%{name}-%{version} +Prefix: /usr/kde/cvs + +%description +A long description + +%prep +rm -rf $RPM_BUILD_ROOT +%setup -n %{name}-%{version} +CFLAGS="" CXXFLAGS="" ./configure --disable-debug --enable-final --prefix=%{prefix} + +%build +# Setup for parallel builds +numprocs=1 +if [ "" = "0" ]; then + numprocs=1 +fi + +make -j + +%install +make install-strip DESTDIR=$RPM_BUILD_ROOT + +cd +find . -type d | sed '1,2d;s,^\.,\%attr(-\,root\,root) \%dir ,' > /%{name}-master.list +find . -type f -o -type l | sed 's|^\.||' >> $RPM_BUILD_DIR/%{name}-master.list + +%clean +rm -rf $RPM_BUILD_DIR/%{name}-%{version} +rm -rf $RPM_BUILD_DIR/-master.list + +%files -f $RPM_BUILD_DIR/%{name}-master.list diff --git a/ksvg/impl/libs/libtext2path/src/Affine.cpp b/ksvg/impl/libs/libtext2path/src/Affine.cpp new file mode 100644 index 00000000..d06b53bc --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/Affine.cpp @@ -0,0 +1,174 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 + +#include "Point.h" +#include "Affine.h" + +using namespace T2P; + +Affine::Affine() +{ + m_affine[0] = 1.0; + m_affine[1] = 0.0; + m_affine[2] = 0.0; + m_affine[3] = 1.0; + m_affine[4] = 0.0; + m_affine[5] = 0.0; +} + +Affine::Affine(double affine[6]) +{ + for(int i = 0; i < 6; i++) + m_affine[i] = affine[i]; +} + +Affine::Affine(const Affine &other) +{ + (*this) = other; +} + +Affine::Affine(double m11, double m12, double m21, double m22, double dx, double dy) +{ + m_affine[0] = m11; m_affine[1] = m12; m_affine[2] = m21; + m_affine[3] = m22; m_affine[4] = dx; m_affine[5] = dy; +} + +Affine::~Affine() +{ +} + +Affine &Affine::operator*=(Affine &other) +{ + double d0 = m11() * other.m11() + m12() * other.m21(); + double d1 = m11() * other.m12() + m12() * other.m22(); + double d2 = m21() * other.m11() + m22() * other.m21(); + double d3 = m21() * other.m12() + m22() * other.m22(); + double d4 = dx() * other.m11() + dy() * other.m21() + other.dx(); + double d5 = dx() * other.m12() + dy() * other.m22() + other.dy(); + + m_affine[0] = d0; m_affine[1] = d1; m_affine[2] = d2; + m_affine[3] = d3; m_affine[4] = d4; m_affine[5] = d5; + + return *this; +} + +Affine &Affine::operator=(const Affine &other) +{ + for(int i = 0; i < 6; i++) + m_affine[i] = other.m_affine[i]; + + return *this; +} + +double &Affine::m11() +{ + return m_affine[0]; +} + +double &Affine::m12() +{ + return m_affine[1]; +} + +double &Affine::m21() +{ + return m_affine[2]; +} + +double &Affine::m22() +{ + return m_affine[3]; +} + +double &Affine::dx() +{ + return m_affine[4]; +} + +double &Affine::dy() +{ + return m_affine[5]; +} + +void Affine::scale(double s) +{ + scale(s, s); +} + +void Affine::scale(double sx, double sy) +{ + m_affine[0] = sx; + m_affine[3] = sy; +} + +void Affine::translate(const Point &point) +{ + m_affine[4] += point.x(); + m_affine[5] += point.y(); +} + +void Affine::translate(double tx, double ty) +{ + m_affine[4] += tx * m_affine[0] + ty * m_affine[2]; + m_affine[5] += tx * m_affine[1] + ty * m_affine[3]; +} + +void Affine::rotate(double angle) +{ + double sina = sin(angle); + double cosa = cos(angle); + + double tm11 = cosa * m_affine[0] + sina * m_affine[2]; + double tm12 = cosa * m_affine[1] + sina * m_affine[3]; + double tm21 = -sina * m_affine[0] + cosa * m_affine[2]; + double tm22 = -sina * m_affine[1] + cosa * m_affine[3]; + + m_affine[0] = tm11; m_affine[1] = tm12; + m_affine[2] = tm21; m_affine[3] = tm22; +} + +void Affine::rotateAround(double angle, const Point &point) +{ + translate(point); + rotate(angle); + translate(point.invert()); +} + +void Affine::rotateAround(double angle, double cx, double cy) +{ + translate(-cx, -cy); + rotate(angle); + translate(cx, cy); +} + +Point Affine::mapPoint(const Point &p) const +{ + return Point(p.x() * m_affine[0] + p.y() * m_affine[2] + m_affine[4], + p.x() * m_affine[1] + p.y() * m_affine[3] + m_affine[5]); +} + +double *Affine::data() +{ + return m_affine; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/libs/libtext2path/src/Affine.h b/ksvg/impl/libs/libtext2path/src/Affine.h new file mode 100644 index 00000000..c0f11e9b --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/Affine.h @@ -0,0 +1,67 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 T2P_AFFINE_H +#define T2P_AFFINE_H + +namespace T2P +{ + class Point; + class Affine + { + public: + Affine(); + Affine(double affine[6]); + Affine(const Affine &other); + Affine(double m11, double m12, double m21, double m22, double dx, double dy); + ~Affine(); + + Affine &operator*=(Affine &other); + Affine &operator=(const Affine &other); + + double &m11(); + double &m12(); + double &m21(); + double &m22(); + double &dx(); + double &dy(); + + void scale(double s); + void scale(double sx, double sy); + void translate(const Point &point); // Assumes point is already transformed + void translate(double tx, double ty); + + void rotate(double angle); + void rotateAround(double angle, const Point &point); // Assumes point is already transformed + void rotateAround(double angle, double cx, double cy); + + Point mapPoint(const Point &p) const; + + // Internal + double *data(); + + private: + double m_affine[6]; + }; +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/libs/libtext2path/src/BezierPath.h b/ksvg/impl/libs/libtext2path/src/BezierPath.h new file mode 100644 index 00000000..1c357abd --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/BezierPath.h @@ -0,0 +1,56 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 T2P_BEZIERPATH_H +#define T2P_BEZIERPATH_H + +#include + +namespace T2P +{ + class Point; + class BezierPath + { + public: + BezierPath() { } + virtual ~BezierPath() { } + + /** + * Calculates the arclength from p0 to the point parametrized by 0 <= t <= 1. + */ + virtual double length(double t = 1.0) = 0; + + /** + * 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). + */ + virtual void pointTangentNormalAt(double t, Point *p = 0, Point *tn = 0, Point *n = 0) = 0; + + /** + * Calculates the axis-aligned bounding box. + */ + virtual void boundingBox(Point *topLeft, Point *bottomRight) = 0; + }; +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/libs/libtext2path/src/Cache.h b/ksvg/impl/libs/libtext2path/src/Cache.h new file mode 100644 index 00000000..a85fdf92 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/Cache.h @@ -0,0 +1,156 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 T2P_CACHE_H +#define T2P_CACHE_H + +#include +#include +#include +#include + +#include "myboost/shared_ptr.hpp" + +namespace T2P +{ + class CacheElement + { + public: + CacheElement(std::string key) : m_key(key), m_usage(0) { } + ~CacheElement() { } + + std::string key() const { return m_key; } + int usage() const { return m_usage; } + + void incUsage() { m_usage++; } + + private: + std::string m_key; + int m_usage; + }; + + template + class Cache + { + public: + typedef myboost::shared_ptr SharedT; + + Cache(int maxSize = 10) : m_size(0), m_maxSize(maxSize) { } + ~Cache() { clear(); } + + // Number of elements in cache + int size() const { return m_size; } + + // Maximum number of elements in cache + int maxSize() const { return m_maxSize; } + + // Add new entry + void insert(const std::string &key, SharedT &value) + { + // TODO: Add real LRU logic, now i will just delete the less + // used item when inserting a new item would exceed maxSize + if(m_size == m_maxSize) + { + // Find less used item + typename std::map::const_iterator it = m_cacheMap.begin(); + int usage = (*it).second->usage(); std::string keyUsage = (*it).second->key(); + for(it++; it != m_cacheMap.end(); ++it) + { + int curUsage = (*it).second->usage(); + if(curUsage < usage) + { + usage = curUsage; + keyUsage = (*it).second->key(); + } + } + +// std::cout << "[CACHE] Removing less used element with key: " << keyUsage << " (Used " << usage << " times!)" << std::endl; + remove(keyUsage); + } + + m_size++; + m_entries.push_back(value); + m_cacheMap[value] = new CacheElement(key); + } + + // Remove single entry + void remove(const std::string &key) + { + for(typename std::vector::iterator it = m_entries.begin(); it != m_entries.end(); ++it) + { + SharedT cur = *it; + if(m_cacheMap[cur]->key() == key) + { + m_size--; + + typename std::map::iterator cacheElement = m_cacheMap.find(cur); + m_cacheMap.erase(cacheElement); + delete cacheElement->second; + m_entries.erase(it); // Only valid to write because we don't go on here! + break; // Otherwhise the iterators _may_ be invalid! + } + } + } + + // Remove all entries + void clear() + { + m_size = 0; + m_entries.clear(); + m_cacheMap.clear(); + } + + // Lookup entry + SharedT find(const std::string &key) + { + for(typename std::vector::const_iterator it = m_entries.begin(); it != m_entries.end(); ++it) + { + SharedT cur = *it; + if(m_cacheMap[cur]->key() == key) + { + m_cacheMap[cur]->incUsage(); + return cur; + } + } + + return SharedT(); + } + + void dump() + { + std::cout << "[CACHE] " << size() << " of " << maxSize() << " Objects in the cache." << std::endl; + + for(typename std::vector::iterator it = m_entries.begin(); it != m_entries.end(); ++it) + { + SharedT cur = *it; + std::cout << "[CACHE] - " << m_cacheMap[cur]->key() << " -> " << cur << " (Usage: " << m_cacheMap[cur]->usage() << ")" << std::endl; + } + } + + private: + std::vector m_entries; + std::map m_cacheMap; + int m_size, m_maxSize; + }; +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/libs/libtext2path/src/Converter.cpp b/ksvg/impl/libs/libtext2path/src/Converter.cpp new file mode 100644 index 00000000..7810b417 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/Converter.cpp @@ -0,0 +1,505 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 + +#include "myboost/shared_ptr.hpp" +#include +#include +#include + +#include "Font.h" +#include "Glyph.h" +#include "Tools.h" +#include "Rectangle.h" +#include "Converter.h" +#include "QtUnicode.h" +#include "GlyphTracer.h" + +// Macros +#define FT_TRUNC(x) ((x) >> 6) +#define FT_TOFLOAT(x) ((x) * (1.0 / 64.0)) +#define FT_FROMFLOAT(x) ((int) floor ((x) * 64.0 + 0.5)) + +const double deg2rad = 0.017453292519943295769; // pi/180 + +using namespace T2P; + +// Font engine. The core component. +Converter::Converter(GlyphTracer *tracer) : m_glyphTracer(tracer) +{ + m_init = false; + m_kerning = true; + m_library = 0; +} + +Converter::~Converter() +{ + if(m_glyphTracer) + delete m_glyphTracer; + + m_fontCache.clear(); + m_glyphCache.clear(); + + // Close FreeType2 library + if(m_library) + FT_Done_FreeType(m_library); +} + +void Converter::init() +{ + // Initialize FreeType2 + m_init = (FT_Init_FreeType(&m_library) == 0); +} + +bool Converter::ready() +{ + return m_init; +} + +void Converter::setKerning(bool mode) +{ + m_kerning = mode; +} + +// Lookup font in cache or create new font +SharedFont Converter::requestFont(const FontVisualParams *params) +{ + std::string cacheKey = cacheFontKey(params); + SharedFont cached = m_fontCache.find(cacheKey); + + // If not available in cache, create new one and cache it :) + if(cached) + { + delete params; + return cached; + } + else + { + // Create a new Font + SharedFont newFont(new Font(this)); + + // Load the font + if(!newFont->load(params)) + { + delete params; + return SharedFont(); + } + + // Append to cache + m_fontCache.insert(cacheKey, newFont); + return newFont; + } +} + +GlyphAffinePair *Converter::requestGlyph(GlyphRenderParams *params, Rectangle &bbox, Affine &affine, bool onlyLatin) +{ + // 1. Select glyph to have glyphIndex information, + // needed to generate the cache lookup key + selectGlyph(params); + + SharedGlyph cached = m_glyphCache.find(cacheGlyphKey(params)); + + // If not available in cache, render new one and cache it :) + // If we're mixing ie. japanese and latin characters (TTB layout), + // then we also have to re-calculate the glyph again with the appropriate rotation matrix (Niko) + if(!cached || !onlyLatin) + cached = calcGlyph(params, affine, onlyLatin); + + // Correct bezier path by setting up the correct scaling matrix + // and multiplying with the current glyph affine + double fontSize = params->font()->fontParams()->size(); + + T2P::Affine correctAffine; + correctAffine.scale(0.001 * fontSize, -0.001 * fontSize); + correctAffine *= affine; + + // Get bbox information + Point p1(FT_TRUNC(cached->ftBbox()->xMin), FT_TRUNC(cached->ftBbox()->yMin)); + Point p2(FT_TRUNC(cached->ftBbox()->xMax), FT_TRUNC(cached->ftBbox()->yMax)); + + bbox.setA(affine.mapPoint(p1)); + bbox.setB(affine.mapPoint(p2)); + + return new GlyphAffinePair(cached.get(), correctAffine); +} + +void Converter::selectGlyph(GlyphRenderParams *params) +{ + // 1. Select glyph + test if it exists + // | + // |-> if it doesn't exist, replace by a '?' and check if exists + // |-> if it does exist, use it! + params->setGlyphIndex(FT_Get_Char_Index(params->font()->fontFace(), (FT_ULong) params->character())); + + if(params->glyphIndex() == 0) + params->setGlyphIndex(FT_Get_Char_Index(params->font()->fontFace(), '?')); + + // 2. Load glyph into font's glyphSlot, according to the GlyphLayoutParams + int flags = FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; + + // 3. Don't pass FT_LOAD_VERTICAL_LAYOUT on TTB layouts when rendering + // a latin glyph because it needs to be rotated... + if(params->layout()->tb()) + { + Script script; + SCRIPT_FOR_CHAR(script, params->character()) + if(script != Latin || params->layout()->glyphOrientationVertical() == 0) + flags |= FT_LOAD_VERTICAL_LAYOUT; + } + + FT_Error error = FT_Load_Glyph(params->font()->fontFace(), params->glyphIndex(), flags); + if(error) + params->setGlyphIndex(0); +} + +SharedGlyph Converter::calcGlyph(const GlyphRenderParams *params, Affine &affine, bool onlyLatin) +{ + // 2. Apply kerning if needed + if(m_kerning && params->lastGlyph() != 0 && params->glyphIndex() != 0) + { + FT_Vector kerningVector; + double kx, ky; + + FT_Get_Kerning(params->font()->fontFace(), params->lastGlyph(), params->glyphIndex(), ft_kerning_default, &kerningVector); + + kx = FT_TRUNC(kerningVector.x); + ky = FT_TRUNC(kerningVector.y); + + affine.dx() += kx + affine.m21() * ky; + + // Only apply y kerning in TB mode + if(params->layout()->tb()) + affine.dy() += kx + affine.m22() * ky; + } + + // 3. Prepare path tracing + FT_OutlineGlyph ftGlyph; + FT_Get_Glyph(params->font()->fontFace()->glyph, reinterpret_cast(&ftGlyph)); + + // 3a. Prepare tracing matrix + Affine traceAffine; + traceAffine.scale(1000.0 / params->font()->fontFace()->units_per_EM); + + // 3b. Enable character rotation, if needed + if(params->layout()->tb()) + { + Script script; + SCRIPT_FOR_CHAR(script, params->character()) + if(!onlyLatin && script == Latin) + { + FT_Matrix matrix; + + double angle = deg2rad * params->layout()->glyphOrientationVertical(); + matrix.xx = (FT_Fixed)( cos(angle) * 0x10000L); + matrix.xy = (FT_Fixed)(-sin(angle) * 0x10000L); + matrix.yx = (FT_Fixed)( sin(angle) * 0x10000L); + matrix.yy = (FT_Fixed)( cos(angle) * 0x10000L); + + FT_Glyph_Transform(reinterpret_cast(ftGlyph), &matrix, 0); + } + } + + // 4. Begin path tracing + // - Setup glyphOutlineing glyph + // - Start tracing + // - Close path + FT_Outline *ftOut = &ftGlyph->outline; + + SharedGlyph glyphOutline(new Glyph()); + glyphOutline->setBezierPath(m_glyphTracer->allocBezierPath(ftOut->n_points * 2 + ftOut->n_contours + 1)); + glyphOutline->setAffine(traceAffine); + + FT_Outline_Decompose(ftOut, m_glyphTracer->outlineFuncs(), glyphOutline.get()); + + m_glyphTracer->closePath(glyphOutline.get()); + + // 5. Determine bounding box (aka "cbox") + FT_Glyph_Get_CBox(reinterpret_cast(ftGlyph), ft_glyph_bbox_unscaled, glyphOutline->ftBbox()); + + // 6. Cache glyph! + m_glyphCache.insert(cacheGlyphKey(params), glyphOutline); + + FT_Done_Glyph(reinterpret_cast(ftGlyph)); + + return glyphOutline; +} + +GlyphSet *Converter::calcString(Font *font, const unsigned short *text, unsigned int length, Affine &affine, const GlyphLayoutParams *params, BezierPath *bpath) +{ + unsigned short *bidi = 0; + + // 0. Apply BiDi Rules + if(params->useBidi()) + { + FriBidiCharType baseDir = FRIBIDI_TYPE_N; + FriBidiChar *unicodeIn = new FriBidiChar[length + 1]; + FriBidiChar *unicodeOut = new FriBidiChar[length + 1]; + bidi = new unsigned short[length + 1]; + + for(unsigned int i = 0; i < length; i++) + unicodeIn[i] = text[i]; + + fribidi_log2vis(unicodeIn, length, &baseDir, unicodeOut, 0, 0, 0); + + for(unsigned int i = 0; i < length; i++) + bidi[i] = unicodeOut[i]; + + bidi[length] = 0; + delete []unicodeIn; + delete []unicodeOut; + } + else + bidi = const_cast(text); + + // Detect character rotation if needed, + // probably working in 0.1% of the cases :/ + Script script; + bool onlyLatin = true; + for(unsigned int i = 0; i < length; i++) + { + SCRIPT_FOR_CHAR(script, bidi[i]) + if(script != Latin) + { + onlyLatin = false; + break; + } + } + + // 1. Set initial font size + double fontSize = font->fontParams()->size(); + FT_Set_Char_Size(font->fontFace(), FT_FROMFLOAT(fontSize), FT_FROMFLOAT(fontSize), 0, 0); + + // 2. Compute positioning metrics + // - See http://www.freetype.org/freetype2/docs/tutorial/stepX.html (X = 1 or 2) + int pixelHeight = (int) (FT_TOFLOAT(font->fontFace()->size->metrics.ascender - font->fontFace()->size->metrics.descender) * affine.m22()); + int pixelBaseline = (int) (FT_TOFLOAT(font->fontFace()->size->metrics.ascender) * affine.m22()); + int pixelUnderlinePosition = (int) (((font->fontFace()->ascender - font->fontFace()->underline_position - font->fontFace()->underline_thickness / 2) * fontSize / font->fontFace()->units_per_EM) * affine.m22()); + int pixelUnderlineThickness = T2PMAX(1, (int) ((font->fontFace()->underline_thickness * fontSize / font->fontFace()->units_per_EM) * affine.m22())); + + // 3. Prepare needed variables for the rendering loop + // - rendering params (layout, font...) + // - bounding box (per glyph, overall) + // - glyph matrix (overall) + // - resulting glyph sets + GlyphRenderParams *renderParams = new GlyphRenderParams(); + renderParams->setFont(font); + renderParams->setLayout(params); + renderParams->setLastGlyph(0); + renderParams->setGlyphIndex(0); + + Affine glyphAffine(affine); + Rectangle bbox, currentBbox; + GlyphSet *result = new GlyphSet(); + + // Align to path start, if bpath != 0 + Point pathPoint, pathTangent, pathNormal; + double pathLength = 0, pathAdvance = 0; + double startOffset = params->textPathStartOffset(); + + if(bpath) + { + pathLength = bpath->length(); + bpath->pointTangentNormalAt(startOffset, &pathPoint, &pathTangent); + + glyphAffine.dx() = pathPoint.x(); + glyphAffine.dy() = pathPoint.y(); + glyphAffine.rotate(atan2(pathTangent.y(), pathTangent.x())); + + std::cout << "[T2P] Starting textPath at: " << pathPoint.x() << ", " << pathPoint.y() << std::endl; + } + + // elements can have different baseline-shift's + // baseline-shift support (Niko) + double baseline = 0; + if(!params->baselineShift().empty()) + { + if(params->baselineShift() == "sub") + baseline += fontSize / 5 + 1; + else if(params->baselineShift() == "super") + baseline -= fontSize / 3 + 1; + else + { + std::string temp = params->baselineShift(); + if(temp.find("%") > 0) + baseline -= (atof(temp.c_str()) / 100.0) * fontSize; + else + baseline -= atoi(temp.c_str()); + } + + if(!params->tb()) + glyphAffine.translate(0, baseline); + else + glyphAffine.translate(-baseline, 0); + } + + // 4. Enter main rendering loop + for(unsigned int i = 0; i < length; i++) + { + // 4a. Modify character to render + renderParams->setCharacter(bidi[i]); + + // 4c. Get glyph outline + GlyphAffinePair *glyphOutline = requestGlyph(renderParams, currentBbox, glyphAffine, onlyLatin); + m_glyphTracer->correctGlyph(glyphOutline); + + // 4d. Save advance values + result->m_glyphXAdvance.push_back((font->fontFace()->glyph->advance.x * fontSize / font->fontFace()->units_per_EM) * affine.m11()); + result->m_glyphYAdvance.push_back((font->fontFace()->glyph->advance.y * fontSize / font->fontFace()->units_per_EM) * affine.m22()); + + // 4e. Misc + // - union current + overall bounding box + // - add glyph to list of glyphs + // - apply letter & word spacing + if(renderParams->glyphIndex() != 0) + { + // Remember last glyph for kerning + renderParams->setLastGlyph(renderParams->glyphIndex()); + + // Union current + overall bounding box + bbox.bboxUnion(bbox, currentBbox); + + // Move glyph locations for the next glyph to be + // rendered apply letter & word spacing + bool addGlyph = true; + if(!params->tb()) + { + if(bpath) + { + double advance = startOffset + (pathAdvance / pathLength); + if(advance < 0.0 || advance > 1.0) // dont render off-path glyphs + addGlyph = false; + + pathAdvance += (result->m_glyphXAdvance.back() + params->letterSpacing() * affine.m11()) + ((bidi[(i + 1)] == ' ') ? params->wordSpacing() * affine.m11() : 0); + + std::cout << "[T2P] Adjusting textPath advance: " << pathAdvance << " Path Length: " << pathLength << " StartOffset: " << startOffset << " Position in Path (relative 0-1): " << pathAdvance/pathLength << " Adjusted by offset: " << startOffset + (pathAdvance / pathLength) << std::endl; + + bpath->pointTangentNormalAt(startOffset + (pathAdvance / pathLength), &pathPoint, &pathTangent, &pathNormal); + + glyphAffine.m11() = affine.m11(); + glyphAffine.m12() = affine.m12(); + glyphAffine.m21() = affine.m21(); + glyphAffine.m22() = affine.m22(); + glyphAffine.dx() = pathPoint.x(); + glyphAffine.dy() = pathPoint.y(); + + glyphAffine.rotateAround(atan2(pathTangent.y(), pathTangent.x()), Point(result->m_glyphXAdvance.back() / 2, result->m_glyphYAdvance.back() / 2)); + + std::cout << "[T2P] Aligning textPath to: " << pathPoint.x() << ", " << pathPoint.y() << std::endl; + if(!params->tb()) + glyphAffine.translate(0, baseline); + else + glyphAffine.translate(-baseline, 0); + } + else + glyphAffine.dx() += (result->m_glyphXAdvance.back() + params->letterSpacing() * affine.m11()) + ((bidi[(i + 1)] == ' ') ? params->wordSpacing() * affine.m11() : 0); + } + else + { + double advy = result->m_glyphYAdvance.back(); + + Script script; + SCRIPT_FOR_CHAR(script, bidi[i]) + if(!onlyLatin && script == Latin && params->glyphOrientationVertical() != 0) + advy = result->m_glyphXAdvance.back(); + + glyphAffine.dy() += (advy + params->letterSpacing() * affine.m22()) + ((bidi[(i + 1)] == ' ') ? params->wordSpacing() * affine.m22() : 0); + } + + // Copy bezier path/affine pair + if(addGlyph) + { + result->m_set.push_back(glyphOutline); + result->m_glyphCount++; + } + else + delete glyphOutline; + } + } + + // 5. Fill out resulting data structures + result->m_underlinePosition = pixelUnderlinePosition; + result->m_overlinePosition = pixelHeight - pixelUnderlinePosition; + result->m_strikeThroughPosition = (result->m_underlinePosition + result->m_overlinePosition) / 2; + result->m_pixelBaseline = pixelBaseline; + result->m_underlineThickness = pixelUnderlineThickness; + + result->m_xpen = glyphAffine.dx() - affine.dx(); + result->m_ypen = glyphAffine.dy() - affine.dy(); + + result->m_bboxX = T2PMAX(1, int(bbox.a().x())); + result->m_bboxY = T2PMAX(1, int(bbox.a().y() - int(pixelHeight / 2))); + result->m_height = T2PMAX(1, int(bbox.b().y() - bbox.a().y())); + + // Correct bounding box information also on + // vertical layouts! (Niko) + if(!params->tb()) + { + if(bpath) + result->m_width = int(pathAdvance); + else + result->m_width = T2PMAX(1, int(bbox.b().x() - bbox.a().x())); + } + else + result->m_width = T2PMAX(1, pixelHeight); + + // 6. Cleanup memory + if(text != bidi) + delete []bidi; + + delete renderParams; + + // 7. Eventually, dump cache statistics + // m_glyphCache.dump(); + // m_fontCache.dump(); + + return result; +} + +std::string Converter::cacheFontKey(const FontVisualParams *params) const +{ + // TODO: Tune the key + std::string key; + + key += Tools::joinList('|', const_cast(params)->fontList()); + key += Tools::a2str(params->weight()); + key += Tools::a2str(params->slant()); + key += Tools::a2str(params->size()); + + // std::cout << "Font cache key: " << key << std::endl; + return key; +} + +std::string Converter::cacheGlyphKey(const GlyphRenderParams *params) const +{ + // TODO: Tune the key + std::string key; + + key += params->font()->fontFile(); + key += Tools::a2str(params->character()); + key += Tools::a2str(params->glyphIndex()); + key += Tools::a2str(params->font()->fontParams()->size()); + key += Tools::a2str(params->font()->fontParams()->weight()); + key += Tools::a2str(params->font()->fontParams()->slant()); + + // std::cout << "Glyph cache key: " << key << std::endl; + return key; +} +// vim:ts=4:noet diff --git a/ksvg/impl/libs/libtext2path/src/Converter.h b/ksvg/impl/libs/libtext2path/src/Converter.h new file mode 100644 index 00000000..d6e19521 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/Converter.h @@ -0,0 +1,94 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 T2P_CONVERTER_H +#define T2P_CONVERTER_H + +#include "Cache.h" + +// FreeType 2 includes +#include +#include FT_FREETYPE_H +#include FT_OUTLINE_H +#include FT_GLYPH_H + +namespace T2P +{ + class BezierPath; + + class Font; + class Glyph; + class Affine; + class GlyphSet; + class Rectangle; + class GlyphTracer; + class GlyphAffinePair; + class FontVisualParams; + class GlyphLayoutParams; + class GlyphRenderParams; + + typedef myboost::shared_ptr SharedFont; + typedef myboost::shared_ptr SharedGlyph; + + class Converter + { + public: + Converter(GlyphTracer *tracer); + ~Converter(); + + // Is initialized? + void init(); + bool ready(); + + // Kerning control + void setKerning(bool mode); + + SharedFont requestFont(const FontVisualParams *params); + GlyphAffinePair *requestGlyph(GlyphRenderParams *params, Rectangle &bbox, Affine &affine, bool onlyLatin); + + GlyphSet *calcString(Font *font, const unsigned short *text, unsigned int length, Affine &affine, const GlyphLayoutParams *params, BezierPath *bpath = 0); + SharedGlyph calcGlyph(const GlyphRenderParams *params, Affine &affine, bool onlyLatin); + + void selectGlyph(GlyphRenderParams *params); + + protected: + friend class Font; + + // Internal + FT_Library library() { return m_library; } + + private: + std::string cacheFontKey(const FontVisualParams *params) const; + std::string cacheGlyphKey(const GlyphRenderParams *params) const; + + FT_Library m_library; + + GlyphTracer *m_glyphTracer; + + Cache m_glyphCache; + Cache m_fontCache; + + bool m_init, m_kerning; + }; +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/libs/libtext2path/src/Font.cpp b/ksvg/impl/libs/libtext2path/src/Font.cpp new file mode 100644 index 00000000..1d6f7005 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/Font.cpp @@ -0,0 +1,252 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 +#include +#include + +#include "Font.h" +#include "Tools.h" +#include "Converter.h" + +// Macros +#define FT_TRUNC(x) ((x) >> 6) +#define FT_TOFLOAT(x) ((x) * (1.0 / 64.0)) +#define FT_FROMFLOAT(x) ((int) floor ((x) * 64.0 + 0.5)) + +using namespace T2P; + +FontVisualParams::FontVisualParams() +{ + m_size = 0.0; + m_slant = 0; + m_weight = 0; +} + +FontVisualParams::FontVisualParams(const FontVisualParams &other) +{ + (*this) = other; +} + +FontVisualParams::~FontVisualParams() +{ +} + +FontVisualParams &FontVisualParams::operator=(const FontVisualParams &other) +{ + m_size = other.m_size; + m_slant = other.m_slant; + m_weight = other.m_weight; + m_fontList = other.m_fontList; + + return *this; +} + +void FontVisualParams::setWeight(int weight) +{ + m_weight = weight; +} + +int FontVisualParams::weight() const +{ + return m_weight; +} + +void FontVisualParams::setSlant(int slant) +{ + m_slant = slant; +} + +int FontVisualParams::slant() const +{ + return m_slant; +} + +void FontVisualParams::setSize(double size) +{ + m_size = size; +} + +double FontVisualParams::size() const +{ + return m_size; +} + +std::list &FontVisualParams::fontList() +{ + return m_fontList; +} + +// ##### + +Font::Font(Converter *context) : m_context(context) +{ + m_ready = false; + + m_fontFace = 0; + m_fontParams = 0; +} + +Font::~Font() +{ + // Release font face + if(m_ready && m_fontFace) + { + // FIXME: Debug that! + //std::cout << "CALLING DONE FACE " << m_fontFace << std::endl; + FT_Done_Face(m_fontFace); + } + + delete m_fontParams; +} + +std::string Font::buildRequest(const FontVisualParams *fontParams, int &id) +{ + // Use FontConfig to locate & select fonts and use + // FreeType2 to open them + FcPattern *pattern; + std::string fileName; + + pattern = FcPatternBuild(0, + FC_WEIGHT, FcTypeInteger, fontParams->weight(), + FC_SLANT, FcTypeInteger, fontParams->slant(), + FC_SIZE, FcTypeDouble, fontParams->size(), + NULL); + + // Add multiple font names + std::list &fontList = const_cast(fontParams)->fontList(); + + for(std::list::const_iterator it = fontList.begin(); it != fontList.end(); ++it) + { + std::string string = *it; + + if(!string.empty()) + FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast(string.c_str())); + } + + // Always load vertical layout + FcPatternAddBool(pattern, FC_VERTICAL_LAYOUT, true); + + // Disable hinting + FcPatternAddBool(pattern, FC_HINTING, false); + + // Perform the default font pattern modification operations. + FcDefaultSubstitute(pattern); + FcConfigSubstitute(FcConfigGetCurrent(), pattern, FcMatchPattern); + + // Match the pattern! + FcResult result; + FcPattern *match = FcFontMatch(0, pattern, &result); + + // Destroy pattern + FcPatternDestroy(pattern); + + // Get index & filename + FcChar8 *temp; + + if(match) + { + FcPattern *pattern = FcPatternDuplicate(match); + + // Get index & filename + if(FcPatternGetString(pattern, FC_FILE, 0, &temp) != FcResultMatch || + FcPatternGetInteger(pattern, FC_INDEX, 0, &id) != FcResultMatch) + { + std::cout << "Font::buildRequest(), could not load font file for requested font \"" << Tools::joinList('|', fontList) << "\"" << std::endl; + return fileName; + } + + fileName = reinterpret_cast(temp); + + // Kill pattern + FcPatternDestroy(pattern); + } + + // Kill pattern + FcPatternDestroy(match); + + return fileName; +} + +bool Font::load(const FontVisualParams *fontParams) +{ + // Build FontConfig request pattern + int id = -1; + std::string filename = Font::buildRequest(fontParams, id); + + // Load font directly using FreeType2 + std::cout << "Font::load(), loading " << filename << " for requested font \"" << Tools::joinList('|', const_cast(fontParams)->fontList()) << "\"" << std::endl; + + FT_Error error = FT_New_Face(m_context->library(), filename.c_str(), id, &m_fontFace); + if(error) + { + std::cout << "Font::load(), could not load font. Aborting!" << std::endl; + return false; + } + if(!FT_IS_SCALABLE(m_fontFace)) + { + std::cout << "Font::load(), font does not contain outlines. Aborting!" << std::endl; + FT_Done_Face(m_fontFace); + m_fontFace = 0; + return false; + } + + // Choose unicode charmap + for(int charmap = 0; charmap < m_fontFace->num_charmaps; charmap++) + { + if(m_fontFace->charmaps[charmap]->encoding == ft_encoding_unicode) + { + FT_Error error = FT_Set_Charmap(m_fontFace, m_fontFace->charmaps[charmap]); + + if(error) + { + std::cout << "Font::load(), unable to select unicode charmap. Aborting!" << std::endl; + + FT_Done_Face(m_fontFace); + m_fontFace = 0; + + return false; + } + } + } + + m_fontParams = fontParams; + m_fontFile = filename; + m_ready = true; + + return true; +} + +FT_Face &Font::fontFace() +{ + return m_fontFace; +} + +std::string Font::fontFile() const +{ + return m_fontFile; +} + +const FontVisualParams *Font::fontParams() const +{ + return m_fontParams; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/libs/libtext2path/src/Font.h b/ksvg/impl/libs/libtext2path/src/Font.h new file mode 100644 index 00000000..72844285 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/Font.h @@ -0,0 +1,91 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 T2P_FONT_H +#define T2P_FONT_H + +#include +#include + +// FreeType 2 includes +#include +#include FT_FREETYPE_H + +namespace T2P +{ + class Converter; + + class FontVisualParams + { + public: + FontVisualParams(); + FontVisualParams(const FontVisualParams &other); + ~FontVisualParams(); + + FontVisualParams &operator=(const FontVisualParams &other); + + void setWeight(int weight); + int weight() const; + + void setSlant(int slant); + int slant() const; + + void setSize(double size); + double size() const; + + std::list &fontList(); + + private: + int m_weight, m_slant; + double m_size; + + std::list m_fontList; + }; + + class Font + { + public: + Font(Converter *context); + ~Font(); + + // Build font loading request for FontConfig + static std::string buildRequest(const FontVisualParams *fontParams, int &id); + + // Load it! :) + bool load(const FontVisualParams *fontParams); + + FT_Face &fontFace(); + std::string fontFile() const; + const FontVisualParams *fontParams() const; + + private: + FT_Face m_fontFace; + std::string m_fontFile; + + Converter *m_context; + const FontVisualParams *m_fontParams; + + bool m_ready; + }; +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/libs/libtext2path/src/Glyph.cpp b/ksvg/impl/libs/libtext2path/src/Glyph.cpp new file mode 100644 index 00000000..5d172018 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/Glyph.cpp @@ -0,0 +1,353 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 +#include "Glyph.h" + +using namespace T2P; + +Glyph::Glyph() +{ + m_bezierPath = 0; +} + +Glyph::~Glyph() +{ + delete m_bezierPath; + m_bezierPath = 0; +} + +Affine &Glyph::affine() +{ + return m_affine; +} + +void Glyph::setAffine(const Affine &affine) +{ + m_affine = affine; +} + +const BezierPath *Glyph::bezierPath() const +{ + return const_cast(m_bezierPath); +} + +BezierPath *Glyph::modifiableBezierPath() +{ + return m_bezierPath; +} + +void Glyph::setBezierPath(const BezierPath *bpath) +{ + m_bezierPath = const_cast(bpath); +} + +FT_BBox *Glyph::ftBbox() +{ + return m_ftBbox; +} + +// ##### + +GlyphAffinePair::GlyphAffinePair(const Glyph *glyph, const Affine &affine) +{ + m_glyph = glyph; + m_affine = affine; + m_transformatedPath = 0; +} + +GlyphAffinePair::~GlyphAffinePair() +{ + // The glyphs are shared and thus not deleted (Niko) + delete m_transformatedPath; +} + +void GlyphAffinePair::setTransformatedPath(const BezierPath *path) +{ + m_transformatedPath = path; +} + +const BezierPath *GlyphAffinePair::transformatedPath() const +{ + return m_transformatedPath; +} + +const Glyph *GlyphAffinePair::glyph() const +{ + return m_glyph; +} + +Affine &GlyphAffinePair::affine() +{ + return m_affine; +} + +// ##### + +GlyphSet::GlyphSet() +{ + m_glyphCount = 0; + + m_bboxX = 0; + m_bboxY = 0; + m_width = 0; + m_height = 0; + + m_xpen = 0; + m_ypen = 0; + + m_underlinePosition = 0; + m_underlineThickness = 0; + m_overlinePosition = 0; + m_strikeThroughPosition = 0; + m_pixelBaseline = 0; +} + +GlyphSet::~GlyphSet() +{ + m_set.clear(); +} + +std::vector &GlyphSet::set() +{ + return m_set; +} + +std::list GlyphSet::glyphXAdvance() +{ + return m_glyphXAdvance; +} + +std::list GlyphSet::glyphYAdvance() +{ + return m_glyphYAdvance; +} + +unsigned int GlyphSet::glyphCount() const +{ + return m_glyphCount; +} + +int GlyphSet::width() const +{ + return m_width; +} + +int GlyphSet::height() const +{ + return m_height; +} + +int GlyphSet::bboxX() const +{ + return m_bboxX; +} + +int GlyphSet::bboxY() const +{ + return m_bboxY; +} + +double GlyphSet::xpen() const +{ + return m_xpen; +} + +double GlyphSet::ypen() const +{ + return m_ypen; +} + +int GlyphSet::underlinePosition() const +{ + return m_underlinePosition; +} + +int GlyphSet::underlineThickness() const +{ + return m_underlineThickness; +} + +int GlyphSet::overlinePosition() const +{ + return m_overlinePosition; +} + +int GlyphSet::strikeThroughPosition() const +{ + return m_strikeThroughPosition; +} + +int GlyphSet::pixelBaseline() const +{ + return m_pixelBaseline; +} + +// ##### + +GlyphLayoutParams::GlyphLayoutParams() +{ +} + +GlyphLayoutParams::~GlyphLayoutParams() +{ +} + +bool GlyphLayoutParams::tb() const +{ + return m_tb; +} + +void GlyphLayoutParams::setTb(bool tb) +{ + m_tb = tb; +} + +bool GlyphLayoutParams::useBidi() const +{ + return m_useBidi; +} + +void GlyphLayoutParams::setUseBidi(bool bidi) +{ + m_useBidi = bidi; +} + +double GlyphLayoutParams::wordSpacing() const +{ + return m_wordSpacing; +} + +void GlyphLayoutParams::setWordSpacing(double wordSpacing) +{ + m_wordSpacing = wordSpacing; +} + +double GlyphLayoutParams::letterSpacing() const +{ + return m_letterSpacing; +} + +void GlyphLayoutParams::setLetterSpacing(double letterSpacing) +{ + m_letterSpacing = letterSpacing; +} + +std::string GlyphLayoutParams::baselineShift() const +{ + return m_baseline; +} + +void GlyphLayoutParams::setBaselineShift(const std::string &baseline) +{ + m_baseline = baseline; +} + +int GlyphLayoutParams::glyphOrientationVertical() const +{ + return m_glyphOrientationVertical; +} + +void GlyphLayoutParams::setGlyphOrientationVertical(int orient) +{ + m_glyphOrientationVertical = orient; +} + +int GlyphLayoutParams::glyphOrientationHorizontal() const +{ + return m_glyphOrientationHorizontal; +} + +void GlyphLayoutParams::setGlyphOrientationHorizontal(int orient) +{ + m_glyphOrientationHorizontal = orient; +} + +double GlyphLayoutParams::textPathStartOffset() const +{ + return m_textPathStartOffset; +} + +void GlyphLayoutParams::setTextPathStartOffset(double offset) +{ + m_textPathStartOffset = offset; +} + +// ##### + +GlyphRenderParams::GlyphRenderParams() +{ +} + +GlyphRenderParams::~GlyphRenderParams() +{ +} + +Font *GlyphRenderParams::font() const +{ + return m_font; +} + +void GlyphRenderParams::setFont(Font *font) +{ + m_font = font; +} + +const GlyphLayoutParams *GlyphRenderParams::layout() const +{ + return m_layout; +} + +void GlyphRenderParams::setLayout(const GlyphLayoutParams *layout) +{ + m_layout = layout; +} + +unsigned int GlyphRenderParams::glyphIndex() const +{ + return m_glyphIndex; +} + +void GlyphRenderParams::setGlyphIndex(unsigned int glyphIndex) +{ + m_glyphIndex = glyphIndex; +} + +unsigned int GlyphRenderParams::lastGlyph() const +{ + return m_lastGlyph; +} + +void GlyphRenderParams::setLastGlyph(unsigned int lastGlyph) +{ + m_lastGlyph = lastGlyph; +} + +unsigned short GlyphRenderParams::character() const +{ + return m_character; +} + +void GlyphRenderParams::setCharacter(unsigned short character) +{ + m_character = character; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/libs/libtext2path/src/Glyph.h b/ksvg/impl/libs/libtext2path/src/Glyph.h new file mode 100644 index 00000000..b3bd3fb5 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/Glyph.h @@ -0,0 +1,198 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 T2P_GLYPH_H +#define T2P_GLYPH_H + +#include +#include +#include + +#include "Affine.h" +#include "BezierPath.h" + +// FreeType 2 includes +#include +#include FT_FREETYPE_H + +namespace T2P +{ + class Font; + + // Represent one single glyph in cache + class Glyph + { + public: + Glyph(); + ~Glyph(); + + Affine &affine(); // Initial tracing affine + void setAffine(const Affine &affine); + + const BezierPath *bezierPath() const; // Non-modifyable bezierPath belonging to this glyph + BezierPath *modifiableBezierPath(); // ONLY USED BY GLYPHTRACER, DO NOT USE SOMEWHERE ELSE! + void setBezierPath(const BezierPath *bpath); + + FT_BBox *ftBbox(); + + private: + Affine m_affine; + FT_BBox m_ftBbox[4]; + BezierPath *m_bezierPath; + }; + + // Is created for every character which needs to + // be rendered and has to be deleted by the "client" + class GlyphAffinePair + { + public: + GlyphAffinePair(const Glyph *glyph, const Affine &affine); + ~GlyphAffinePair(); + + void setTransformatedPath(const BezierPath *path); + const BezierPath *transformatedPath() const; + + const Glyph *glyph() const; + Affine &affine(); + + private: + const Glyph *m_glyph; + const BezierPath *m_transformatedPath; + Affine m_affine; + }; + + class GlyphSet + { + public: + GlyphSet(); + ~GlyphSet(); + + std::vector &set(); + std::list glyphXAdvance(); + std::list glyphYAdvance(); + + unsigned int glyphCount() const; + + int width() const; + int height() const; + + int bboxX() const; + int bboxY() const; + + double xpen() const; + double ypen() const; + + int underlinePosition() const; + int underlineThickness() const; + int overlinePosition() const; + int strikeThroughPosition() const; + int pixelBaseline() const; + + private: + friend class Converter; + unsigned int m_glyphCount; // Number of glyphs in the set + + int m_bboxX, m_bboxY; // Bounding box locations (x,y) + (x + width, y + width) + int m_width, m_height; + + double m_xpen, m_ypen; // relative pen locations + + int m_underlinePosition, m_underlineThickness, m_overlinePosition, m_strikeThroughPosition, m_pixelBaseline; + + std::vector m_set; // Bezier paths in the set + + std::list m_glyphXAdvance; // List of advance values needed ie. for text paths + std::list m_glyphYAdvance; + }; + + class GlyphLayoutParams + { + public: + GlyphLayoutParams(); + ~GlyphLayoutParams(); + + bool tb() const; + void setTb(bool tb); + + bool useBidi() const; + void setUseBidi(bool bidi); + + double wordSpacing() const; + void setWordSpacing(double wordSpacing); + + double letterSpacing() const; + void setLetterSpacing(double letterSpacing); + + std::string baselineShift() const; + void setBaselineShift(const std::string &baseline); + + int glyphOrientationVertical() const; + void setGlyphOrientationVertical(int orient); + + int glyphOrientationHorizontal() const; + void setGlyphOrientationHorizontal(int orient); + + // textOnPath specific stuff + double textPathStartOffset() const; + void setTextPathStartOffset(double offset); + + private: + bool m_tb; // Top-To-Bottom or Bottom-To-Top ? + bool m_useBidi; // Use Bidi ? + double m_wordSpacing, m_letterSpacing; // word/character spacing + double m_textPathStartOffset; // range: 0.0 - 1.0; start offset in the path + int m_glyphOrientationVertical, m_glyphOrientationHorizontal; // Degrees... + std::string m_baseline; // baseline description, using same system as svg + }; + + class GlyphRenderParams + { + public: + GlyphRenderParams(); + ~GlyphRenderParams(); + + Font *font() const; + void setFont(Font *font); + + const GlyphLayoutParams *layout() const; + void setLayout(const GlyphLayoutParams *layout); + + unsigned int glyphIndex() const; + void setGlyphIndex(unsigned int glyphIndex); + + unsigned int lastGlyph() const; + void setLastGlyph(unsigned int lastGlyph); + + unsigned short character() const; + void setCharacter(unsigned short character); + + private: + Font *m_font; + const GlyphLayoutParams *m_layout; // Glyph layouting params + + unsigned int m_glyphIndex; // 'character' index in font + unsigned int m_lastGlyph; // Kerning + unsigned short m_character; // Unicode glyph to process + }; +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/libs/libtext2path/src/GlyphTracer.cpp b/ksvg/impl/libs/libtext2path/src/GlyphTracer.cpp new file mode 100644 index 00000000..42457553 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/GlyphTracer.cpp @@ -0,0 +1,76 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 "GlyphTracer.h" + +using namespace T2P; + +GlyphTracer::GlyphTracer() +{ + m_moveTo = 0; + m_lineTo = 0; + m_conicBezier = 0; + m_cubicBezier = 0; + m_outlineMethods = 0; +} + +GlyphTracer::~GlyphTracer() +{ + delete m_outlineMethods; +} + +void GlyphTracer::setMoveto(FT_Outline_MoveToFunc funcPtr) +{ + m_moveTo = funcPtr; +} + +void GlyphTracer::setLineto(FT_Outline_LineToFunc funcPtr) +{ + m_lineTo = funcPtr; +} + +void GlyphTracer::setConicBezier(FT_Outline_ConicToFunc funcPtr) +{ + m_conicBezier = funcPtr; +} + +void GlyphTracer::setCubicBezier(FT_Outline_CubicToFunc funcPtr) +{ + m_cubicBezier = funcPtr; +} + +FT_Outline_Funcs *GlyphTracer::outlineFuncs() +{ + if(m_outlineMethods) + return m_outlineMethods; + + FT_Outline_Funcs *ret = new FT_Outline_Funcs(); + ret->move_to = m_moveTo; + ret->line_to = m_lineTo; + ret->conic_to = m_conicBezier; + ret->cubic_to = m_cubicBezier; + ret->shift = 0; + ret->delta = 0; + + m_outlineMethods = ret; + return m_outlineMethods; +} + +// vim:ts=4:noet diff --git a/ksvg/impl/libs/libtext2path/src/GlyphTracer.h b/ksvg/impl/libs/libtext2path/src/GlyphTracer.h new file mode 100644 index 00000000..7607ecad --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/GlyphTracer.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 T2P_GLYPHTRACER_H +#define T2P_GLYPHTRACER_H + +// FreeType 2 includes +#include +#include FT_FREETYPE_H + +namespace T2P +{ + class Glyph; + class BezierPath; + class GlyphAffinePair; + + class GlyphTracer + { + public: + GlyphTracer(); + virtual ~GlyphTracer(); + + // Needs to be implemented + virtual void correctGlyph(GlyphAffinePair *glyphAffine) = 0; + virtual BezierPath *allocBezierPath(int size) = 0; + virtual void closePath(Glyph *glyph) = 0; + + // FreeType glyph tracing functions + void setMoveto(FT_Outline_MoveToFunc funcPtr); + void setLineto(FT_Outline_LineToFunc funcPtr); + void setConicBezier(FT_Outline_ConicToFunc funcPtr); + void setCubicBezier(FT_Outline_CubicToFunc funcPtr); + + FT_Outline_Funcs *outlineFuncs(); + + private: + FT_Outline_Funcs *m_outlineMethods; + + FT_Outline_MoveToFunc m_moveTo; + FT_Outline_LineToFunc m_lineTo; + FT_Outline_ConicToFunc m_conicBezier; + FT_Outline_CubicToFunc m_cubicBezier; + }; +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/libs/libtext2path/src/Makefile.am b/ksvg/impl/libs/libtext2path/src/Makefile.am new file mode 100644 index 00000000..175e1a91 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/Makefile.am @@ -0,0 +1,10 @@ +lib_LTLIBRARIES = libtext2path.la + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) +INCLUDES = $(FRIBIDI_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) $(all_includes) + +libtext2path_includedir=$(includedir)/libtext2path-0.1 +libtext2path_include_HEADERS = BezierPath.h Glyph.h GlyphTracer.h + +libtext2path_la_SOURCES = Affine.cpp Rectangle.cpp Font.cpp Glyph.cpp GlyphTracer.cpp Converter.cpp QtUnicode.cpp +libtext2path_la_LDFLAGS = $(FRIBIDI_LIBS) $(FONTCONFIG_LIBS) diff --git a/ksvg/impl/libs/libtext2path/src/Point.h b/ksvg/impl/libs/libtext2path/src/Point.h new file mode 100644 index 00000000..d95742a2 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/Point.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 T2P_POINT_H +#define T2P_POINT_H + +namespace T2P +{ + class Point + { + public: + Point() { m_x = 0.0; m_y = 0.0; } + Point(double x, double y) { m_x = x; m_y = y; } + Point &operator=(const Point &other) { m_x = other.x(); m_y = other.y(); return *this; } + + friend inline Point operator+(const Point &, const Point &); + friend inline Point operator-(const Point &, const Point &); + friend inline Point operator*(const double &, const Point &); + friend inline Point operator*(const Point &, const double &); + + double x() const { return m_x; } + double y() const { return m_y; } + + void setX(double x) { m_x = x; } + void setY(double y) { m_y = y; } + + const Point invert() const + { + Point temp; + temp.setX(-x()); + temp.setY(-y()); + return temp; + } + + private: + double m_x; + double m_y; + }; + + inline Point operator+(const Point &p1, const Point &p2) { return Point(p1.m_x + p2.m_x, p1.m_y + p2.m_y); } + inline Point operator-(const Point &p1, const Point &p2) { return Point(p1.m_x - p2.m_x, p1.m_y - p2.m_y); } + inline Point operator*(const double &c, const Point &p) { return Point(p.m_x * c, p.m_y * c); } + inline Point operator*(const Point &p, const double &c) { return Point(p.m_x * c, p.m_y * c); } +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/libs/libtext2path/src/QtUnicode.cpp b/ksvg/impl/libs/libtext2path/src/QtUnicode.cpp new file mode 100644 index 00000000..694ed5c7 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/QtUnicode.cpp @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** +** ??? +** +** Copyright (C) 2002-2003 Trolltech AS. All rights reserved. +** +** This file is part of the kernel module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "QtUnicode.h" + +using namespace T2P; +// START OF GENERATED DATA + +// copied form qfont.h, as we can't include it in tools. Do not modify without +// changing the script enum in qfont.h aswell. +const unsigned char QtUnicode::otherScripts [120] = { +#define SCRIPTS_02 0 + 0xaf, Latin, 0xff, SpacingModifiers, // row 0x02, index 0 +#define SCRIPTS_03 4 + 0x6f, CombiningMarks, 0xff, Greek, // row 0x03, index 4 +#define SCRIPTS_05 8 + 0x2f, Cyrillic, 0x8f, Armenian, 0xff, Hebrew, // row 0x05, index 8 +#define SCRIPTS_07 14 + 0x4f, Syriac, 0x7f, Unicode, 0xbf, Thaana, + 0xff, Unicode, // row 0x07, index 14 +#define SCRIPTS_10 22 + 0x9f, Myanmar, 0xff, Georgian, // row 0x10, index 20 +#define SCRIPTS_13 26 + 0x7f, Ethiopic, 0x9f, Unicode, 0xff, Cherokee, // row 0x13, index 24 +#define SCRIPTS_16 32 + 0x7f, CanadianAboriginal, 0x9f, Ogham, + 0xff, Runic, // row 0x16 index 30 +#define SCRIPTS_17 38 + 0x1f, Tagalog, 0x3f, Hanunoo, 0x5f, Buhid, + 0x7f, Tagbanwa, 0xff, Khmer, // row 0x17, index 36 +#define SCRIPTS_18 48 + 0xaf, Mongolian, 0xff, Unicode, // row 0x18, index 46 +#define SCRIPTS_20 52 + 0x0b, Unicode, 0x0d, UnknownScript, 0x6f, Unicode, 0x9f, NumberForms, + 0xab, CurrencySymbols, 0xac, Latin, + 0xcf, CurrencySymbols, 0xff, CombiningMarks, // row 0x20, index 50 +#define SCRIPTS_21 68 + 0x4f, LetterlikeSymbols, 0x8f, NumberForms, + 0xff, MathematicalOperators, // row 0x21, index 62 +#define SCRIPTS_24 74 + 0x5f, TechnicalSymbols, 0xff, EnclosedAndSquare, // row 0x24, index 68 +#define SCRIPTS_2e 78 + 0x7f, Unicode, 0xff, Han, // row 0x2e, index 72 +#define SCRIPTS_30 82 + 0x3f, Han, 0x9f, Hiragana, 0xff, Katakana, // row 0x30, index 76 +#define SCRIPTS_31 88 + 0x2f, Bopomofo, 0x8f, Hangul, 0x9f, Han, + 0xff, Unicode, // row 0x31, index 82 +#define SCRIPTS_fb 96 + 0x06, Latin, 0x1c, Unicode, 0x4f, Hebrew, + 0xff, Arabic, // row 0xfb, index 90 +#define SCRIPTS_fe 104 + 0x1f, Unicode, 0x2f, CombiningMarks, 0x6f, Unicode, + 0xff, Arabic, // row 0xfe, index 98 +#define SCRIPTS_ff 112 + 0x5e, Katakana, 0x60, Unicode, // row 0xff, index 106 + 0x9f, KatakanaHalfWidth, 0xff, Unicode +}; + +// (uc-0x0900)>>7 +const unsigned char QtUnicode::indicScripts [] = +{ + Devanagari, Bengali, + Gurmukhi, Gujarati, + Oriya, Tamil, + Telugu, Kannada, + Malayalam, Sinhala, + Thai, Lao +}; + + +// 0x80 + x: x is the offset into the otherScripts table +const unsigned char QtUnicode::scriptTable[256] = +{ + Latin, Latin, 0x80+SCRIPTS_02, 0x80+SCRIPTS_03, + Cyrillic, 0x80+SCRIPTS_05, Arabic, 0x80+SCRIPTS_07, + Unicode, SCRIPTS_INDIC, SCRIPTS_INDIC, SCRIPTS_INDIC, + SCRIPTS_INDIC, SCRIPTS_INDIC, SCRIPTS_INDIC, Tibetan, + + 0x80+SCRIPTS_10, Hangul, Ethiopic, 0x80+SCRIPTS_13, + CanadianAboriginal, CanadianAboriginal, 0x80+SCRIPTS_16, 0x80+SCRIPTS_17, + 0x80+SCRIPTS_18, Unicode, Unicode, Unicode, + Unicode, Unicode, Latin, Greek, + + 0x80+SCRIPTS_20, 0x80+SCRIPTS_21, MathematicalOperators, TechnicalSymbols, + 0x80+SCRIPTS_24, GeometricSymbols, MiscellaneousSymbols, MiscellaneousSymbols, + Braille, Unicode, Unicode, Unicode, + Unicode, Unicode, 0x80+SCRIPTS_2e, Han, + + 0x80+SCRIPTS_30, 0x80+SCRIPTS_31, EnclosedAndSquare, EnclosedAndSquare, + Han, Han, Han, Han, + Han, Han, Han, Han, + Han, Han, Han, Han, + + Han, Han, Han, Han, Han, Han, Han, Han, + Han, Han, Han, Han, Han, Han, Han, Han, + + Han, Han, Han, Han, Han, Han, Han, Han, + Han, Han, Han, Han, Han, Han, Han, Han, + + Han, Han, Han, Han, Han, Han, Han, Han, + Han, Han, Han, Han, Han, Han, Han, Han, + + Han, Han, Han, Han, Han, Han, Han, Han, + Han, Han, Han, Han, Han, Han, Han, Han, + + + Han, Han, Han, Han, Han, Han, Han, Han, + Han, Han, Han, Han, Han, Han, Han, Han, + + Han, Han, Han, Han, Han, Han, Han, Han, + Han, Han, Han, Han, Han, Han, Han, Han, + + Yi, Yi, Yi, Yi, Yi, Unicode, Unicode, Unicode, + Unicode, Unicode, Unicode, Unicode, Hangul, Hangul, Hangul, Hangul, + + Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, + Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, + + Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, + Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, + + Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, + Unicode, Unicode, Unicode, Unicode, Unicode, Unicode, Unicode, Unicode, + + Unicode, Unicode, Unicode, Unicode, Unicode, Unicode, Unicode, Unicode, + Unicode, Unicode, Unicode, Unicode, Unicode, Unicode, Unicode, Unicode, + + Unicode, Unicode, Unicode, Unicode, Unicode, Unicode, Unicode, Unicode, + Unicode, Han, Han, 0x80+SCRIPTS_fb, Arabic, Arabic, 0x80+SCRIPTS_fe, 0x80+SCRIPTS_ff +}; + diff --git a/ksvg/impl/libs/libtext2path/src/QtUnicode.h b/ksvg/impl/libs/libtext2path/src/QtUnicode.h new file mode 100644 index 00000000..41008500 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/QtUnicode.h @@ -0,0 +1,149 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 T2P_QT_UNICODE_H +#define T2P_QT_UNICODE_H + +namespace T2P +{ + enum Script + { + // European Alphabetic Scripts + Latin, + Greek, + Cyrillic, + Armenian, + Georgian, + Runic, + Ogham, + SpacingModifiers, + CombiningMarks, + + // Middle Eastern Scripts + Hebrew, + Arabic, + Syriac, + Thaana, + + // South and Southeast Asian Scripts + Devanagari, + Bengali, + Gurmukhi, + Gujarati, + Oriya, + Tamil, + Telugu, + Kannada, + Malayalam, + Sinhala, + Thai, + Lao, + Tibetan, + Myanmar, + Khmer, + + // East Asian Scripts + Han, + Hiragana, + Katakana, + Hangul, + Bopomofo, + Yi, + + // Additional Scripts + Ethiopic, + Cherokee, + CanadianAboriginal, + Mongolian, + + // Symbols + CurrencySymbols, + LetterlikeSymbols, + NumberForms, + MathematicalOperators, + TechnicalSymbols, + GeometricSymbols, + MiscellaneousSymbols, + EnclosedAndSquare, + Braille, + + Unicode, + + // some scripts added in Unicode 3.2 + Tagalog, + Hanunoo, + Buhid, + Tagbanwa, + + KatakanaHalfWidth, + + // End + NScripts, + UnknownScript = NScripts + }; + + class QtUnicode + { + public: + QtUnicode() { } + ~QtUnicode() { } + + static int scriptForChar(unsigned short uc) + { + unsigned char script = QtUnicode::scriptTable[(uc >> 8)]; + if(script >= QtUnicode::SCRIPTS_INDIC) + { + if(script == QtUnicode::SCRIPTS_INDIC) + script = QtUnicode::indicScripts[(uc - 0x0900) >> 7]; + else + { + // 0x80 + SCRIPTS_xx + unsigned char index = script - 0x80; + unsigned char cell = uc & 0xff; + while(QtUnicode::otherScripts[index++] < cell) + index++; + script = QtUnicode::otherScripts[index]; + } + } + + return script; + } + + private: + enum + { + SCRIPTS_INDIC = 0x7e + }; + + static const unsigned char otherScripts[]; + static const unsigned char indicScripts[]; + static const unsigned char scriptTable[]; + }; +} + +#define SCRIPT_FOR_CHAR(script, c) \ +if(c < 0x100) \ + script = T2P::Latin; \ +else \ + script = (T2P::Script) QtUnicode::scriptForChar(c); + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/libs/libtext2path/src/Rectangle.cpp b/ksvg/impl/libs/libtext2path/src/Rectangle.cpp new file mode 100644 index 00000000..ef59d6be --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/Rectangle.cpp @@ -0,0 +1,102 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 "Tools.h" +#include "Rectangle.h" + +using namespace T2P; + +Rectangle::Rectangle() +{ +} + +Rectangle::Rectangle(const Rectangle &other) +{ + (*this) = other; +} + +Rectangle::Rectangle(const Point &a, const Point &b) : m_a(a), m_b(b) +{ +} + +Rectangle::Rectangle(double x, double y, double width, double height) +{ + m_a = Point(x, y); + m_b = Point(x + width, y + height); +} + +Rectangle::~Rectangle() +{ +} + +Rectangle &Rectangle::operator=(const Rectangle &other) +{ + m_a = other.m_a; + m_b = other.m_b; + + return *this; +} + +Point Rectangle::a() const +{ + return m_a; +} + +void Rectangle::setA(const Point &a) +{ + m_a = a; +} + +Point Rectangle::b() const +{ + return m_b; +} + +void Rectangle::setB(const Point &b) +{ + m_b = b; +} + +void Rectangle::bboxUnion(const Rectangle &src1, const Rectangle &src2) +{ + double src1x0 = src1.a().x(), src1x1 = src1.b().x(); + double src1y0 = src1.a().y(), src1y1 = src1.b().y(); + + double src2x0 = src2.a().x(), src2x1 = src2.b().x(); + double src2y0 = src2.a().y(), src2y1 = src2.b().y(); + + if(src1x1 <= src1x0 || src1y1 <= src1y0) // Is src1 empty? + { // Copy src2 to dst + setA(Point(src2x0, src2y0)); + setB(Point(src2x1, src2y1)); + } + else if(src2x1 <= src2x0 || src2y1 <= src2y0) // Is src2 empty? + { // Copy src1 to dest + setA(Point(src1x0, src1y0)); + setB(Point(src1x1, src1y1)); + } + else + { + setA(Point(T2PMIN(src1x0, src2x0), T2PMIN(src1y0, src2y0))); + setB(Point(T2PMAX(src1x1, src2x1), T2PMAX(src1y1, src2y1))); + } +} + +// vim:ts=4:noet diff --git a/ksvg/impl/libs/libtext2path/src/Rectangle.h b/ksvg/impl/libs/libtext2path/src/Rectangle.h new file mode 100644 index 00000000..1a5eeeb1 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/Rectangle.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 T2P_RECTANGLE_H +#define T2P_RECTANGLE_H + +#include "Point.h" + +namespace T2P +{ + class Rectangle + { + public: + Rectangle(); + Rectangle(const Rectangle &other); + Rectangle(const Point &a, const Point &b); + Rectangle(double x, double y, double width, double height); + ~Rectangle(); + + Rectangle &operator=(const Rectangle &other); + + Point a() const; + void setA(const Point &a); + + Point b() const; + void setB(const Point &b); + + // Finds the smallest rectangle that includes src1 and src2. + void bboxUnion(const Rectangle &src1, const Rectangle &src2); + + private: + Point m_a, m_b; + }; +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/libs/libtext2path/src/Tools.h b/ksvg/impl/libs/libtext2path/src/Tools.h new file mode 100644 index 00000000..c7753365 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/Tools.h @@ -0,0 +1,85 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 T2P_TOOLS_H +#define T2P_TOOLS_H + +#include +#include +#include +#ifdef HAVE_SSTREAM +# include +#else +# include +# define ostringstream ostrstream +#endif + +#define T2PMAX(a, b) ((b) < (a) ? (a) : (b)) +#define T2PMIN(a, b) ((a) < (b) ? (a) : (b)) + +namespace T2P +{ + class Tools + { + public: + static std::string joinList(char seperator, std::list &list) + { + std::string result; + + if(list.empty()) + return result; + + bool first = true; + for(std::list::const_iterator it = list.begin(); it != list.end(); ++it) + { + std::string string = *it; + + if(!string.empty()) + { + if(!first) + result += seperator + string; + else + { + result += string; + first = false; + } + } + } + + return result; + } + + template + static std::string a2str(T arg) + { + std::ostringstream buffer; + buffer << arg; + return buffer.str(); + } + }; +} + +#ifdef ostringstream +# undef ostringstream +#endif + +#endif + +// vim:ts=4:noet diff --git a/ksvg/impl/libs/libtext2path/src/myboost/assert.hpp b/ksvg/impl/libs/libtext2path/src/myboost/assert.hpp new file mode 100644 index 00000000..3f3c61c2 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/myboost/assert.hpp @@ -0,0 +1,24 @@ +// +// boost/assert.hpp - BOOST_ASSERT(expr) +// +// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// Note: There are no include guards. This is intentional. +// +// See http://www.boost.org/libs/utility/assert.html for documentation. +// + +#ifndef ASSERT_HPP +#define ASSERT_HPP + +#undef BOOST_ASSERT + +# include +# define BOOST_ASSERT(expr) assert(expr) + +#endif diff --git a/ksvg/impl/libs/libtext2path/src/myboost/checked_delete.hpp b/ksvg/impl/libs/libtext2path/src/myboost/checked_delete.hpp new file mode 100644 index 00000000..73afd5f5 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/myboost/checked_delete.hpp @@ -0,0 +1,61 @@ +#ifndef BOOST_CHECKED_DELETE_HPP_INCLUDED +#define BOOST_CHECKED_DELETE_HPP_INCLUDED + +// +// boost/checked_delete.hpp +// +// Copyright (c) 1999, 2000, 2001, 2002 boost.org +// Copyright (c) 2002, 2003 Peter Dimov +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// See http://www.boost.org/libs/utility/checked_delete.html for documentation. +// + +namespace myboost +{ + +// verify that types are complete for increased safety + +template inline void checked_delete(T * x) +{ + // Intel 7 accepts sizeof(incomplete) as 0 in system headers + typedef char type_must_be_complete[ sizeof(T)? 1: -1 ]; + delete x; +} + +template inline void checked_array_delete(T * x) +{ + typedef char type_must_be_complete[ sizeof(T)? 1: -1 ]; + delete [] x; +} + +template struct checked_deleter +{ + typedef void result_type; + typedef T * argument_type; + + void operator()(T * x) const + { + // boost:: disables ADL + myboost::checked_delete(x); + } +}; + +template struct checked_array_deleter +{ + typedef void result_type; + typedef T * argument_type; + + void operator()(T * x) const + { + myboost::checked_array_delete(x); + } +}; + +} // namespace myboost + +#endif // #ifndef BOOST_CHECKED_DELETE_HPP_INCLUDED diff --git a/ksvg/impl/libs/libtext2path/src/myboost/lightweight_mutex.hpp b/ksvg/impl/libs/libtext2path/src/myboost/lightweight_mutex.hpp new file mode 100644 index 00000000..10db127c --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/myboost/lightweight_mutex.hpp @@ -0,0 +1,74 @@ +#ifndef BOOST_DETAIL_LWM_PTHREADS_HPP_INCLUDED +#define BOOST_DETAIL_LWM_PTHREADS_HPP_INCLUDED + +// +// boost/detail/lwm_pthreads.hpp +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// + +#include + +namespace myboost +{ + +namespace detail +{ + +class lightweight_mutex +{ +private: + + pthread_mutex_t m_; + + lightweight_mutex(lightweight_mutex const &); + lightweight_mutex & operator=(lightweight_mutex const &); + +public: + + lightweight_mutex() + { + pthread_mutex_init(&m_, 0); + } + + ~lightweight_mutex() + { + pthread_mutex_destroy(&m_); + } + + class scoped_lock; + friend class scoped_lock; + + class scoped_lock + { + private: + + pthread_mutex_t & m_; + + scoped_lock(scoped_lock const &); + scoped_lock & operator=(scoped_lock const &); + + public: + + scoped_lock(lightweight_mutex & m): m_(m.m_) + { + pthread_mutex_lock(&m_); + } + + ~scoped_lock() + { + pthread_mutex_unlock(&m_); + } + }; +}; + +} // namespace detail + +} // namespace myboost + +#endif // #ifndef BOOST_DETAIL_LWM_PTHREADS_HPP_INCLUDED diff --git a/ksvg/impl/libs/libtext2path/src/myboost/shared_count.hpp b/ksvg/impl/libs/libtext2path/src/myboost/shared_count.hpp new file mode 100644 index 00000000..e8ec19a8 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/myboost/shared_count.hpp @@ -0,0 +1,367 @@ +#ifndef BOOST_DETAIL_SHARED_COUNT_HPP_INCLUDED +#define BOOST_DETAIL_SHARED_COUNT_HPP_INCLUDED + +// +// detail/shared_count.hpp +// +// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// + +#include "myboost/checked_delete.hpp" +#include "myboost/throw_exception.hpp" +#include "myboost/lightweight_mutex.hpp" + +#include // std::auto_ptr, std::allocator +#include // std::less +#include // std::exception +#include // std::bad_alloc +#include // std::type_info in get_deleter +#include // std::size_t + +namespace myboost +{ + +class bad_weak_ptr: public std::exception +{ +public: + + virtual char const * what() const throw() + { + return "myboost::bad_weak_ptr"; + } +}; + +namespace detail +{ + +class sp_counted_base +{ +private: + + typedef detail::lightweight_mutex mutex_type; + +public: + + sp_counted_base(): use_count_(1), weak_count_(1) + { + } + + virtual ~sp_counted_base() // nothrow + { + } + + // dispose() is called when use_count_ drops to zero, to release + // the resources managed by *this. + + virtual void dispose() = 0; // nothrow + + // destruct() is called when weak_count_ drops to zero. + + virtual void destruct() // nothrow + { + delete this; + } + + virtual void * get_deleter(std::type_info const & ti) = 0; + + void add_ref_copy() + { + mutex_type::scoped_lock lock(mtx_); + ++use_count_; + } + + void add_ref_lock() + { + mutex_type::scoped_lock lock(mtx_); + if(use_count_ == 0) myboost::throw_exception(myboost::bad_weak_ptr()); + ++use_count_; + } + + void release() // nothrow + { + { + mutex_type::scoped_lock lock(mtx_); + long new_use_count = --use_count_; + + if(new_use_count != 0) return; + } + + dispose(); + weak_release(); + } + + void weak_add_ref() // nothrow + { + mutex_type::scoped_lock lock(mtx_); + ++weak_count_; + } + + void weak_release() // nothrow + { + long new_weak_count; + + { + mutex_type::scoped_lock lock(mtx_); + new_weak_count = --weak_count_; + } + + if(new_weak_count == 0) + { + destruct(); + } + } + + long use_count() const // nothrow + { + mutex_type::scoped_lock lock(mtx_); + return use_count_; + } + +private: + + sp_counted_base(sp_counted_base const &); + sp_counted_base & operator= (sp_counted_base const &); + + long use_count_; // #shared + long weak_count_; // #weak + (#shared != 0) + + mutable mutex_type mtx_; +}; + +template class sp_counted_base_impl: public sp_counted_base +{ +private: + + P ptr; // copy constructor must not throw + D del; // copy constructor must not throw + + sp_counted_base_impl(sp_counted_base_impl const &); + sp_counted_base_impl & operator= (sp_counted_base_impl const &); + + typedef sp_counted_base_impl this_type; + +public: + + // pre: initial_use_count <= initial_weak_count, d(p) must not throw + + sp_counted_base_impl(P p, D d): ptr(p), del(d) + { + } + + virtual void dispose() // nothrow + { + del(ptr); + } + + virtual void * get_deleter(std::type_info const & ti) + { + return ti == typeid(D)? &del: 0; + } + + void * operator new(std::size_t) + { + return std::allocator().allocate(1, static_cast(0)); + } + + void operator delete(void * p) + { + std::allocator().deallocate(static_cast(p), 1); + } +}; + +class weak_count; + +class shared_count +{ +private: + + sp_counted_base * pi_; + + friend class weak_count; + +public: + + shared_count(): pi_(0) // nothrow + { + } + + template shared_count(P p, D d): pi_(0) + { + + try + { + pi_ = new sp_counted_base_impl(p, d); + } + catch(...) + { + d(p); // delete p + throw; + } + + + pi_ = new sp_counted_base_impl(p, d); + + if(pi_ == 0) + { + d(p); // delete p + myboost::throw_exception(std::bad_alloc()); + } + } + + // auto_ptr is special cased to provide the strong guarantee + + template + explicit shared_count(std::auto_ptr & r): pi_(new sp_counted_base_impl< Y *, checked_deleter >(r.get(), checked_deleter())) + { + r.release(); + } + + ~shared_count() // nothrow + { + if(pi_ != 0) pi_->release(); + } + + shared_count(shared_count const & r): pi_(r.pi_) // nothrow + { + if(pi_ != 0) pi_->add_ref_copy(); + } + + explicit shared_count(weak_count const & r); // throws bad_weak_ptr when r.use_count() == 0 + + shared_count & operator= (shared_count const & r) // nothrow + { + sp_counted_base * tmp = r.pi_; + if(tmp != 0) tmp->add_ref_copy(); + if(pi_ != 0) pi_->release(); + pi_ = tmp; + + return *this; + } + + void swap(shared_count & r) // nothrow + { + sp_counted_base * tmp = r.pi_; + r.pi_ = pi_; + pi_ = tmp; + } + + long use_count() const // nothrow + { + return pi_ != 0? pi_->use_count(): 0; + } + + bool unique() const // nothrow + { + return use_count() == 1; + } + + friend inline bool operator==(shared_count const & a, shared_count const & b) + { + return a.pi_ == b.pi_; + } + + friend inline bool operator<(shared_count const & a, shared_count const & b) + { + return std::less()(a.pi_, b.pi_); + } + + void * get_deleter(std::type_info const & ti) const + { + return pi_? pi_->get_deleter(ti): 0; + } +}; + +class weak_count +{ +private: + + sp_counted_base * pi_; + + friend class shared_count; + +public: + + weak_count(): pi_(0) // nothrow + { + } + + weak_count(shared_count const & r): pi_(r.pi_) // nothrow + { + if(pi_ != 0) pi_->weak_add_ref(); + } + + weak_count(weak_count const & r): pi_(r.pi_) // nothrow + { + if(pi_ != 0) pi_->weak_add_ref(); + } + + ~weak_count() // nothrow + { + if(pi_ != 0) pi_->weak_release(); + } + + weak_count & operator= (shared_count const & r) // nothrow + { + sp_counted_base * tmp = r.pi_; + if(tmp != 0) tmp->weak_add_ref(); + if(pi_ != 0) pi_->weak_release(); + pi_ = tmp; + + return *this; + } + + weak_count & operator= (weak_count const & r) // nothrow + { + sp_counted_base * tmp = r.pi_; + if(tmp != 0) tmp->weak_add_ref(); + if(pi_ != 0) pi_->weak_release(); + pi_ = tmp; + + return *this; + } + + void swap(weak_count & r) // nothrow + { + sp_counted_base * tmp = r.pi_; + r.pi_ = pi_; + pi_ = tmp; + } + + long use_count() const // nothrow + { + return pi_ != 0? pi_->use_count(): 0; + } + + friend inline bool operator==(weak_count const & a, weak_count const & b) + { + return a.pi_ == b.pi_; + } + + friend inline bool operator<(weak_count const & a, weak_count const & b) + { + return std::less()(a.pi_, b.pi_); + } +}; + +inline shared_count::shared_count(weak_count const & r): pi_(r.pi_) +{ + if(pi_ != 0) + { + pi_->add_ref_lock(); + } + else + { + myboost::throw_exception(myboost::bad_weak_ptr()); + } +} + +} // namespace detail + +} // namespace myboost + +#endif // #ifndef BOOST_DETAIL_SHARED_COUNT_HPP_INCLUDED diff --git a/ksvg/impl/libs/libtext2path/src/myboost/shared_ptr.hpp b/ksvg/impl/libs/libtext2path/src/myboost/shared_ptr.hpp new file mode 100644 index 00000000..3f2fe30d --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/myboost/shared_ptr.hpp @@ -0,0 +1,395 @@ +#ifndef BOOST_SHARED_PTR_HPP_INCLUDED +#define BOOST_SHARED_PTR_HPP_INCLUDED + +// shared_ptr.hpp +// +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002, 2003 Peter Dimov +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// See http://www.boost.org/libs/smart_ptr/shared_ptr.htm for documentation. +// + +#include "myboost/assert.hpp" +#include "myboost/checked_delete.hpp" +#include "myboost/throw_exception.hpp" +#include "myboost/shared_count.hpp" + +#include // for std::auto_ptr +#include // for std::swap +#include // for std::less +#include // for std::bad_cast +#include // for std::basic_ostream + +namespace myboost +{ + +template class weak_ptr; +template class enable_shared_from_this; + +namespace detail +{ + +struct static_cast_tag {}; +struct const_cast_tag {}; +struct dynamic_cast_tag {}; +struct polymorphic_cast_tag {}; + +template struct shared_ptr_traits +{ + typedef T & reference; +}; + +template<> struct shared_ptr_traits +{ + typedef void reference; +}; + +template<> struct shared_ptr_traits +{ + typedef void reference; +}; + +template<> struct shared_ptr_traits +{ + typedef void reference; +}; + +template<> struct shared_ptr_traits +{ + typedef void reference; +}; + +// enable_shared_from_this support + +template void sp_enable_shared_from_this(myboost::enable_shared_from_this * pe, Y * px, shared_count const & pn) +{ + if(pe != 0) pe->_internal_weak_this._internal_assign(px, pn); +} + +inline void sp_enable_shared_from_this(void const *, void const *, shared_count const &) +{ +} + +} // namespace detail + + +// +// shared_ptr +// +// An enhanced relative of scoped_ptr with reference counted copy semantics. +// The object pointed to is deleted when the last shared_ptr pointing to it +// is destroyed or reset. +// + +template class shared_ptr +{ +private: + + // Borland 5.5.1 specific workaround + typedef shared_ptr this_type; + +public: + + typedef T element_type; + typedef T value_type; + typedef T * pointer; + typedef typename detail::shared_ptr_traits::reference reference; + + shared_ptr(): px(0), pn() // never throws in 1.30+ + { + } + + template + explicit shared_ptr(Y * p): px(p), pn(p, checked_deleter()) // Y must be complete + { + detail::sp_enable_shared_from_this(p, p, pn); + } + + // + // Requirements: D's copy constructor must not throw + // + // shared_ptr will release p by calling d(p) + // + + template shared_ptr(Y * p, D d): px(p), pn(p, d) + { + detail::sp_enable_shared_from_this(p, p, pn); + } + +// generated copy constructor, assignment, destructor are fine... +// except that Borland C++ has a bug, and g++ with -Wsynth warns + shared_ptr & operator=(shared_ptr const & r) // never throws + { + px = r.px; + pn = r.pn; // shared_count::op= doesn't throw + return *this; + } + + template + explicit shared_ptr(weak_ptr const & r): pn(r.pn) // may throw + { + // it is now safe to copy r.px, as pn(r.pn) did not throw + px = r.px; + } + + template + shared_ptr(shared_ptr const & r): px(r.px), pn(r.pn) // never throws + { + } + + template + shared_ptr(shared_ptr const & r, detail::static_cast_tag): px(static_cast(r.px)), pn(r.pn) + { + } + + template + shared_ptr(shared_ptr const & r, detail::const_cast_tag): px(const_cast(r.px)), pn(r.pn) + { + } + + template + shared_ptr(shared_ptr const & r, detail::dynamic_cast_tag): px(dynamic_cast(r.px)), pn(r.pn) + { + if(px == 0) // need to allocate new counter -- the cast failed + { + pn = detail::shared_count(); + } + } + + template + shared_ptr(shared_ptr const & r, detail::polymorphic_cast_tag): px(dynamic_cast(r.px)), pn(r.pn) + { + if(px == 0) + { + myboost::throw_exception(std::bad_cast()); + } + } + + template + explicit shared_ptr(std::auto_ptr & r): px(r.get()), pn() + { + Y * tmp = r.get(); + pn = detail::shared_count(r); + detail::sp_enable_shared_from_this(tmp, tmp, pn); + } + + template + shared_ptr & operator=(shared_ptr const & r) // never throws + { + px = r.px; + pn = r.pn; // shared_count::op= doesn't throw + return *this; + } + + template + shared_ptr & operator=(std::auto_ptr & r) + { + this_type(r).swap(*this); + return *this; + } + + void reset() // never throws in 1.30+ + { + this_type().swap(*this); + } + + template void reset(Y * p) // Y must be complete + { + BOOST_ASSERT(p == 0 || p != px); // catch self-reset errors + this_type(p).swap(*this); + } + + template void reset(Y * p, D d) + { + this_type(p, d).swap(*this); + } + + reference operator* () const // never throws + { + BOOST_ASSERT(px != 0); + return *px; + } + + T * operator-> () const // never throws + { + BOOST_ASSERT(px != 0); + return px; + } + + T * get() const // never throws + { + return px; + } + + typedef T * (this_type::*unspecified_bool_type)() const; + + operator unspecified_bool_type() const // never throws + { + return px == 0? 0: &this_type::get; + } + + // operator! is redundant, but some compilers need it + + bool operator! () const // never throws + { + return px == 0; + } + + bool unique() const // never throws + { + return pn.unique(); + } + + long use_count() const // never throws + { + return pn.use_count(); + } + + void swap(shared_ptr & other) // never throws + { + std::swap(px, other.px); + pn.swap(other.pn); + } + + template bool _internal_less(shared_ptr const & rhs) const + { + return pn < rhs.pn; + } + + void * _internal_get_deleter(std::type_info const & ti) const + { + return pn.get_deleter(ti); + } + +// Tasteless as this may seem, making all members public allows member templates +// to work in the absence of member template friends. (Matthew Langston) + +# if __GNUC__ >= 2 && __GNUC_MINOR__ >= 97 +private: + + template friend class shared_ptr; + template friend class weak_ptr; +#endif + + T * px; // contained pointer + detail::shared_count pn; // reference counter + +}; // shared_ptr + +template inline bool operator==(shared_ptr const & a, shared_ptr const & b) +{ + return a.get() == b.get(); +} + +template inline bool operator!=(shared_ptr const & a, shared_ptr const & b) +{ + return a.get() != b.get(); +} + +#if __GNUC__ == 2 && __GNUC_MINOR__ <= 96 + +// Resolve the ambiguity between our op!= and the one in rel_ops + +template inline bool operator!=(shared_ptr const & a, shared_ptr const & b) +{ + return a.get() != b.get(); +} + +#endif + +template inline bool operator<(shared_ptr const & a, shared_ptr const & b) +{ + return a._internal_less(b); +} + +template inline void swap(shared_ptr & a, shared_ptr & b) +{ + a.swap(b); +} + +template shared_ptr static_pointer_cast(shared_ptr const & r) +{ + return shared_ptr(r, detail::static_cast_tag()); +} + +template shared_ptr const_pointer_cast(shared_ptr const & r) +{ + return shared_ptr(r, detail::const_cast_tag()); +} + +template shared_ptr dynamic_pointer_cast(shared_ptr const & r) +{ + return shared_ptr(r, detail::dynamic_cast_tag()); +} + +// shared_*_cast names are deprecated. Use *_pointer_cast instead. + +template shared_ptr shared_static_cast(shared_ptr const & r) +{ + return shared_ptr(r, detail::static_cast_tag()); +} + +template shared_ptr shared_dynamic_cast(shared_ptr const & r) +{ + return shared_ptr(r, detail::dynamic_cast_tag()); +} + +template shared_ptr shared_polymorphic_cast(shared_ptr const & r) +{ + return shared_ptr(r, detail::polymorphic_cast_tag()); +} + +template shared_ptr shared_polymorphic_downcast(shared_ptr const & r) +{ + BOOST_ASSERT(dynamic_cast(r.get()) == r.get()); + return shared_static_cast(r); +} + +// get_pointer() enables boost::mem_fn to recognize shared_ptr + +template inline T * get_pointer(shared_ptr const & p) +{ + return p.get(); +} + +// operator<< + + +template std::ostream & operator<< (std::ostream & os, shared_ptr const & p) +{ + os << p.get(); + return os; +} + + +// get_deleter (experimental) + +#if (defined(__GNUC__) && (__GNUC__ < 3)) || (defined(__EDG_VERSION__) && (__EDG_VERSION__ <= 238)) + +// g++ 2.9x doesn't allow static_cast(void *) +// apparently EDG 2.38 also doesn't accept it + +template D * get_deleter(shared_ptr const & p) +{ + void const * q = p._internal_get_deleter(typeid(D)); + return const_cast(static_cast(q)); +} + +#else + +template D * get_deleter(shared_ptr const & p) +{ + return static_cast(p._internal_get_deleter(typeid(D))); +} + +#endif + +} // namespace boost + + +#endif // #ifndef BOOST_SHARED_PTR_HPP_INCLUDED diff --git a/ksvg/impl/libs/libtext2path/src/myboost/throw_exception.hpp b/ksvg/impl/libs/libtext2path/src/myboost/throw_exception.hpp new file mode 100644 index 00000000..dd32ec43 --- /dev/null +++ b/ksvg/impl/libs/libtext2path/src/myboost/throw_exception.hpp @@ -0,0 +1,30 @@ +#ifndef BOOST_THROW_EXCEPTION_HPP_INCLUDED +#define BOOST_THROW_EXCEPTION_HPP_INCLUDED + + +// +// boost/throw_exception.hpp +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// http://www.boost.org/libs/utility/throw_exception.html +// + +# include + +namespace myboost +{ + +template void throw_exception(E const & e) +{ + throw e; +} + +} // namespace myboost + +#endif // #ifndef BOOST_THROW_EXCEPTION_HPP_INCLUDED diff --git a/ksvg/impl/libs/xrgbrender/Makefile.am b/ksvg/impl/libs/xrgbrender/Makefile.am new file mode 100644 index 00000000..1e9ebcc1 --- /dev/null +++ b/ksvg/impl/libs/xrgbrender/Makefile.am @@ -0,0 +1,5 @@ +INCLUDES = $(all_includes) + +noinst_LTLIBRARIES = libksvgxrgbrender.la + +libksvgxrgbrender_la_SOURCES = gdk-pixbuf-xlib.c gdk-pixbuf-xlib-drawable.c gdk-pixbuf-xlibrgb.c diff --git a/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib-drawable.c b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib-drawable.c new file mode 100644 index 00000000..01f60976 --- /dev/null +++ b/ksvg/impl/libs/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 + * Cody Russell + * Federico Mena-Quintero + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * 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 */ + + +#include +#include +#include +#include "gdk-pixbuf-xlib-private.h" +#include +#include + +#if (X_BYTE_ORDER == X_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/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib-private.h b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib-private.h new file mode 100644 index 00000000..f1113339 --- /dev/null +++ b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib-private.h @@ -0,0 +1,30 @@ +/* GdkPixbuf library - Xlib header file + * + * Authors: John Harper + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * 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 "gdk-pixbuf-xlib.h" +#include + +extern Display *gdk_pixbuf_dpy; +extern int gdk_pixbuf_screen; + +#endif diff --git a/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib.c b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib.c new file mode 100644 index 00000000..8383246b --- /dev/null +++ b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib.c @@ -0,0 +1,46 @@ +/* GdkPixbuf library - Initialization functions + * + * Author: John Harper + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * 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 +#include +/*#include */ +#include "gdk-pixbuf-xlib-private.h" + +Display *gdk_pixbuf_dpy = NULL; +int gdk_pixbuf_screen = -1; + +/** + * 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/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib.h b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib.h new file mode 100644 index 00000000..aa94c7c6 --- /dev/null +++ b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib.h @@ -0,0 +1,78 @@ +/* GdkPixbuf library - Xlib header file + * + * Authors: John Harper + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * 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 */ +/* #include */ +#include + + + +/* init */ + +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/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlibrgb.c b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlibrgb.c new file mode 100644 index 00000000..eb7e4cdf --- /dev/null +++ b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlibrgb.c @@ -0,0 +1,3425 @@ +/* -*- 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 + */ + +/* 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 + * Manish Singh + * Tim Janik + * Peter Mattis + * Spencer Kimball + * Josh MacDonald + * Christopher Blizzard + * Owen Taylor + * Shawn T. Amundson +*/ + +#include + +#if HAVE_CONFIG_H +# include +# if STDC_HEADERS +# include +# include +# include +# endif +#else +# include +# include +#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_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 X_BYTE_ORDER == X_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); + } +} + + + +#if X_BYTE_ORDER == X_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 X_BYTE_ORDER == X_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 X_BYTE_ORDER == X_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 X_BYTE_ORDER == X_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 X_BYTE_ORDER == X_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_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/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlibrgb.h b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlibrgb.h new file mode 100644 index 00000000..afde174e --- /dev/null +++ b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlibrgb.h @@ -0,0 +1,145 @@ +/* -*- 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 + */ + +/* 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 + * Manish Singh + * Tim Janik + * Peter Mattis + * Spencer Kimball + * Josh MacDonald + * Christopher Blizzard + * Owen Taylor + * Shawn T. Amundson +*/ + + +#ifndef __XLIB_RGB_H__ +#define __XLIB_RGB_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include +#include +#include + + +typedef struct _XlibRgbCmap XlibRgbCmap; + +struct _XlibRgbCmap { + unsigned int colors[256]; + unsigned char lut[256]; /* for 8-bit modes */ +}; + +void +xlib_rgb_init_with_depth (Display *display, Screen *screen, int prefDepth); + +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_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/ksvg/impl/svgpathparser.cc b/ksvg/impl/svgpathparser.cc new file mode 100644 index 00000000..0f7521e0 --- /dev/null +++ b/ksvg/impl/svgpathparser.cc @@ -0,0 +1,564 @@ +/* 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 "svgpathparser.h" +#include +#include + +// parses the number into parameter number +const char * +KSVG::getNumber( const char *ptr, double &number ) +{ + int integer, exponent; + double decimal, frac; + int sign, expsign; + + exponent = 0; + integer = 0; + frac = 1.0; + decimal = 0; + sign = 1; + expsign = 1; + + // read the sign + if(*ptr == '+') + ptr++; + else if(*ptr == '-') + { + ptr++; + sign = -1; + } + + // read the integer part + while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9') + integer = (integer * 10) + *(ptr++) - '0'; + if(*ptr == '.') // read the decimals + { + ptr++; + while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9') + decimal += (*(ptr++) - '0') * (frac *= 0.1); + } + + if(*ptr == 'e' || *ptr == 'E') // read the exponent part + { + ptr++; + + // read the sign of the exponent + if(*ptr == '+') + ptr++; + else if(*ptr == '-') + { + ptr++; + expsign = -1; + } + + exponent = 0; + while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9') + { + exponent *= 10; + exponent += *ptr - '0'; + ptr++; + } + } + number = integer + decimal; + number *= sign * pow( (double)10, double( expsign * exponent ) ); + + return ptr; +} + +// parses the coord into parameter number and forwards to the next coord in the path data +const char * +SVGPathParser::getCoord( const char *ptr, double &number ) +{ + ptr = KSVG::getNumber( ptr, number ); + // skip the following space + if(*ptr == ' ') + ptr++; + + return ptr; +} + +void +SVGPathParser::parseSVG( const QString &s, bool process ) +{ + if(!s.isEmpty()) + { + QString d = s; + d = d.replace(',', ' '); + d = d.simplifyWhiteSpace(); + const char *ptr = d.latin1(); + const char *end = d.latin1() + d.length() + 1; + + double contrlx, contrly, curx, cury, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc; + double px1, py1, px2, py2, px3, py3; + bool relative, closed = true; + char command = *(ptr++), lastCommand = ' '; + + subpathx = subpathy = curx = cury = contrlx = contrly = 0.0; + while( ptr < end ) + { + if( *ptr == ' ' ) + ptr++; + + relative = false; + + //std::cout << "Command : " << command << std::endl; + switch( command ) + { + case 'm': + relative = true; + case 'M': + { + ptr = getCoord( ptr, tox ); + ptr = getCoord( ptr, toy ); + + if( process ) + { + subpathx = curx = relative ? curx + tox : tox; + subpathy = cury = relative ? cury + toy : toy; + + svgMoveTo( curx, cury, closed ); + } + else + svgMoveTo( tox, toy, closed, !relative ); + closed = false; + break; + } + case 'l': + relative = true; + case 'L': + { + ptr = getCoord( ptr, tox ); + ptr = getCoord( ptr, toy ); + + if( process ) + { + curx = relative ? curx + tox : tox; + cury = relative ? cury + toy : toy; + + svgLineTo( curx, cury ); + } + else + svgLineTo( tox, toy, !relative ); + break; + } + case 'h': + { + ptr = getCoord( ptr, tox ); + if( process ) + { + curx = curx + tox; + svgLineTo( curx, cury ); + } + else + svgLineToHorizontal( tox, false ); + break; + } + case 'H': + { + ptr = getCoord( ptr, tox ); + if( process ) + { + curx = tox; + svgLineTo( curx, cury ); + } + else + svgLineToHorizontal( tox ); + break; + } + case 'v': + { + ptr = getCoord( ptr, toy ); + if( process ) + { + cury = cury + toy; + svgLineTo( curx, cury ); + } + else + svgLineToVertical( toy, false ); + break; + } + case 'V': + { + ptr = getCoord( ptr, toy ); + if( process ) + { + cury = toy; + svgLineTo( curx, cury ); + } + else + svgLineToVertical( toy ); + break; + } + case 'z': + case 'Z': + { + // reset curx, cury for next path + if( process ) + { + curx = subpathx; + cury = subpathy; + } + closed = true; + svgClosePath(); + break; + } + case 'c': + relative = true; + case 'C': + { + ptr = getCoord( ptr, x1 ); + ptr = getCoord( ptr, y1 ); + ptr = getCoord( ptr, x2 ); + ptr = getCoord( ptr, y2 ); + ptr = getCoord( ptr, tox ); + ptr = getCoord( ptr, toy ); + + if( process ) + { + px1 = relative ? curx + x1 : x1; + py1 = relative ? cury + y1 : y1; + px2 = relative ? curx + x2 : x2; + py2 = relative ? cury + y2 : y2; + px3 = relative ? curx + tox : tox; + py3 = relative ? cury + toy : toy; + + svgCurveToCubic( px1, py1, px2, py2, px3, py3 ); + + contrlx = relative ? curx + x2 : x2; + contrly = relative ? cury + y2 : y2; + curx = relative ? curx + tox : tox; + cury = relative ? cury + toy : toy; + } + else + svgCurveToCubic( x1, y1, x2, y2, tox, toy, !relative ); + + break; + } + case 's': + relative = true; + case 'S': + { + ptr = getCoord( ptr, x2 ); + ptr = getCoord( ptr, y2 ); + ptr = getCoord( ptr, tox ); + ptr = getCoord( ptr, toy ); + + if( process ) + { + px1 = 2 * curx - contrlx; + py1 = 2 * cury - contrly; + px2 = relative ? curx + x2 : x2; + py2 = relative ? cury + y2 : y2; + px3 = relative ? curx + tox : tox; + py3 = relative ? cury + toy : toy; + + svgCurveToCubic( px1, py1, px2, py2, px3, py3 ); + + contrlx = relative ? curx + x2 : x2; + contrly = relative ? cury + y2 : y2; + curx = relative ? curx + tox : tox; + cury = relative ? cury + toy : toy; + } + else + svgCurveToCubicSmooth( x2, y2, tox, toy, !relative ); + break; + } + case 'q': + relative = true; + case 'Q': + { + ptr = getCoord( ptr, x1 ); + ptr = getCoord( ptr, y1 ); + ptr = getCoord( ptr, tox ); + ptr = getCoord( ptr, toy ); + + if( process ) + { + px1 = relative ? (curx + 2 * (x1 + curx)) * (1.0 / 3.0) : (curx + 2 * x1) * (1.0 / 3.0); + py1 = relative ? (cury + 2 * (y1 + cury)) * (1.0 / 3.0) : (cury + 2 * y1) * (1.0 / 3.0); + px2 = relative ? ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0) : (tox + 2 * x1) * (1.0 / 3.0); + py2 = relative ? ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0) : (toy + 2 * y1) * (1.0 / 3.0); + px3 = relative ? curx + tox : tox; + py3 = relative ? cury + toy : toy; + + svgCurveToCubic( px1, py1, px2, py2, px3, py3 ); + + contrlx = relative ? curx + x1 : (tox + 2 * x1) * (1.0 / 3.0); + contrly = relative ? cury + y1 : (toy + 2 * y1) * (1.0 / 3.0); + curx = relative ? curx + tox : tox; + cury = relative ? cury + toy : toy; + } + else + svgCurveToQuadratic( x1, y1, tox, toy, !relative ); + break; + } + case 't': + relative = true; + case 'T': + { + ptr = getCoord(ptr, tox); + ptr = getCoord(ptr, toy); + + if( process ) + { + xc = 2 * curx - contrlx; + yc = 2 * cury - contrly; + + px1 = (curx + 2 * xc) * (1.0 / 3.0); + py1 = (cury + 2 * yc) * (1.0 / 3.0); + px2 = relative ? ((curx + tox) + 2 * xc) * (1.0 / 3.0) : (tox + 2 * xc) * (1.0 / 3.0); + py2 = relative ? ((cury + toy) + 2 * yc) * (1.0 / 3.0) : (toy + 2 * yc) * (1.0 / 3.0); + px3 = relative ? curx + tox : tox; + py3 = relative ? cury + toy : toy; + + svgCurveToCubic( px1, py1, px2, py2, px3, py3 ); + + contrlx = xc; + contrly = yc; + curx = relative ? curx + tox : tox; + cury = relative ? cury + toy : toy; + } + else + svgCurveToQuadraticSmooth( tox, toy, !relative ); + break; + } + case 'a': + relative = true; + case 'A': + { + bool largeArc, sweep; + double angle, rx, ry; + ptr = getCoord( ptr, rx ); + ptr = getCoord( ptr, ry ); + ptr = getCoord( ptr, angle ); + ptr = getCoord( ptr, tox ); + largeArc = tox == 1; + ptr = getCoord( ptr, tox ); + sweep = tox == 1; + ptr = getCoord( ptr, tox ); + ptr = getCoord( ptr, toy ); + + // Spec: radii are nonnegative numbers + rx = fabs(rx); + ry = fabs(ry); + + if( process ) + calculateArc( relative, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep ); + else + svgArcTo( tox, toy, rx, ry, angle, largeArc, sweep, !relative ); + } + } + + lastCommand = command; + + if(*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9')) + { + // there are still coords in this command + if(command == 'M') + command = 'L'; + else if(command == 'm') + command = 'l'; + } + else + command = *(ptr++); + + if( lastCommand != 'C' && lastCommand != 'c' && + lastCommand != 'S' && lastCommand != 's' && + lastCommand != 'Q' && lastCommand != 'q' && + lastCommand != 'T' && lastCommand != 't') + { + contrlx = curx; + contrly = cury; + } + } + } +} + +// This works by converting the SVG arc to "simple" beziers. +// For each bezier found a svgToCurve call is done. +// Adapted from Niko's code in kdelibs/kdecore/svgicons. +// Maybe this can serve in some shared lib? (Rob) +void +SVGPathParser::calculateArc(bool relative, double &curx, double &cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag) +{ + double sin_th, cos_th; + double a00, a01, a10, a11; + double x0, y0, x1, y1, xc, yc; + double d, sfactor, sfactor_sq; + double th0, th1, th_arc; + int i, n_segs; + + sin_th = sin(angle * (M_PI / 180.0)); + cos_th = cos(angle * (M_PI / 180.0)); + + double dx; + + if(!relative) + dx = (curx - x) / 2.0; + else + dx = -x / 2.0; + + double dy; + + if(!relative) + dy = (cury - y) / 2.0; + else + dy = -y / 2.0; + + double _x1 = cos_th * dx + sin_th * dy; + double _y1 = -sin_th * dx + cos_th * dy; + double Pr1 = r1 * r1; + double Pr2 = r2 * r2; + double Px = _x1 * _x1; + double Py = _y1 * _y1; + + // Spec : check if radii are large enough + double check = Px / Pr1 + Py / Pr2; + if(check > 1) + { + r1 = r1 * sqrt(check); + r2 = r2 * sqrt(check); + } + + a00 = cos_th / r1; + a01 = sin_th / r1; + a10 = -sin_th / r2; + a11 = cos_th / r2; + + x0 = a00 * curx + a01 * cury; + y0 = a10 * curx + a11 * cury; + + if(!relative) + x1 = a00 * x + a01 * y; + else + x1 = a00 * (curx + x) + a01 * (cury + y); + + if(!relative) + y1 = a10 * x + a11 * y; + else + y1 = a10 * (curx + x) + a11 * (cury + y); + + /* (x0, y0) is current point in transformed coordinate space. + (x1, y1) is new point in transformed coordinate space. + + The arc fits a unit-radius circle in this space. + */ + + d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0); + + sfactor_sq = 1.0 / d - 0.25; + + if(sfactor_sq < 0) + sfactor_sq = 0; + + sfactor = sqrt(sfactor_sq); + + if(sweepFlag == largeArcFlag) + sfactor = -sfactor; + + xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0); + yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0); + + /* (xc, yc) is center of the circle. */ + th0 = atan2(y0 - yc, x0 - xc); + th1 = atan2(y1 - yc, x1 - xc); + + th_arc = th1 - th0; + if(th_arc < 0 && sweepFlag) + th_arc += 2 * M_PI; + else if(th_arc > 0 && !sweepFlag) + th_arc -= 2 * M_PI; + + n_segs = (int) (int) ceil(fabs(th_arc / (M_PI * 0.5 + 0.001))); + + for(i = 0; i < n_segs; i++) + { + { + double sin_th, cos_th; + double a00, a01, a10, a11; + double x1, y1, x2, y2, x3, y3; + double t; + double th_half; + + double _th0 = th0 + i * th_arc / n_segs; + double _th1 = th0 + (i + 1) * th_arc / n_segs; + + sin_th = sin(angle * (M_PI / 180.0)); + cos_th = cos(angle * (M_PI / 180.0)); + + /* inverse transform compared with rsvg_path_arc */ + a00 = cos_th * r1; + a01 = -sin_th * r2; + a10 = sin_th * r1; + a11 = cos_th * r2; + + th_half = 0.5 * (_th1 - _th0); + t = (8.0 / 3.0) * sin(th_half * 0.5) * sin(th_half * 0.5) / sin(th_half); + x1 = xc + cos(_th0) - t * sin(_th0); + y1 = yc + sin(_th0) + t * cos(_th0); + x3 = xc + cos(_th1); + y3 = yc + sin(_th1); + x2 = x3 + t * sin(_th1); + y2 = y3 - t * cos(_th1); + + svgCurveToCubic( a00 * x1 + a01 * y1, a10 * x1 + a11 * y1, a00 * x2 + a01 * y2, a10 * x2 + a11 * y2, a00 * x3 + a01 * y3, a10 * x3 + a11 * y3 ); + } + } + + if(!relative) + curx = x; + else + curx += x; + + if(!relative) + cury = y; + else + cury += y; +} + +void +SVGPathParser::svgLineToHorizontal( double, bool ) +{ +} + +void +SVGPathParser::svgLineToVertical( double, bool ) +{ +} + +void +SVGPathParser::svgCurveToCubicSmooth( double, double, double, double, bool ) +{ +} + +void +SVGPathParser::svgCurveToQuadratic( double, double, double, double, bool ) +{ +} + +void +SVGPathParser::svgCurveToQuadraticSmooth( double, double, bool ) +{ +} + +void +SVGPathParser::svgArcTo( double, double, double, double, double, bool, bool, bool ) +{ +} diff --git a/ksvg/impl/svgpathparser.h b/ksvg/impl/svgpathparser.h new file mode 100644 index 00000000..3a9495d0 --- /dev/null +++ b/ksvg/impl/svgpathparser.h @@ -0,0 +1,63 @@ +/* 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 __SVGPATHPARSER_H__ +#define __SVGPATHPARSER_H__ + +class QString; + +namespace KSVG +{ + const char *getNumber( const char *, double & ); +} + +/** + * Parser for svg path data, contained in the d attribute. + * + * The parser delivers encountered commands and parameters by calling + * methods that correspond to those commands. Clients have to derive + * from this class and implement the abstract command methods. + * + * There are two operating modes. By default the parser just delivers unaltered + * svg path data commands and parameters. In the second mode, it will convert all + * relative coordinates to absolute ones, and convert all curves to cubic beziers. + */ +class SVGPathParser +{ +public: + void parseSVG( const QString &d, bool process = false ); + + static const char *getCoord( const char *, double & ); + +protected: + virtual void svgMoveTo( double x1, double y1, bool closed, bool abs = true ) = 0; + virtual void svgLineTo( double x1, double y1, bool abs = true ) = 0; + virtual void svgLineToHorizontal( double x, bool abs = true ); + virtual void svgLineToVertical( double y, bool abs = true ); + virtual void svgCurveToCubic( double x1, double y1, double x2, double y2, double x, double y, bool abs = true ) = 0; + virtual void svgCurveToCubicSmooth( double x, double y, double x2, double y2, bool abs = true ); + virtual void svgCurveToQuadratic( double x, double y, double x1, double y1, bool abs = true ); + virtual void svgCurveToQuadraticSmooth( double x, double y, bool abs = true ); + virtual void svgArcTo( double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag, bool abs = true ); + virtual void svgClosePath() = 0; +private: + void calculateArc( bool relative, double &curx, double &cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag ); +}; + +#endif diff --git a/ksvg/plugin/Makefile.am b/ksvg/plugin/Makefile.am new file mode 100644 index 00000000..73202df4 --- /dev/null +++ b/ksvg/plugin/Makefile.am @@ -0,0 +1,29 @@ +SUBDIRS = backends . + +INCLUDES = $(FREETYPE_CFLAGS) -I$(top_srcdir)/ksvg -I$(top_srcdir)/ksvg/dom -I$(top_srcdir)/ksvg/impl -I$(top_srcdir)/ksvg/ecma -I$(top_srcdir)/ksvg/core -I$(top_srcdir)/ksvg/impl/libs/libtext2path/src $(all_includes) +METASOURCES = AUTO +KDE_CXXFLAGS = $(USE_EXCEPTIONS) + +kde_module_LTLIBRARIES = libksvgplugin.la svgthumbnail.la + +libksvgplugin_la_SOURCES = ksvg_plugin.cpp ksvg_factory.cpp ksvg_widget.cpp +libksvgplugin_la_LIBADD = ../libksvg.la +libksvgplugin_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) + +ksvginclude_HEADERS = ksvg_plugin.h +ksvgincludedir = $(includedir)/ksvg + +kde_services_DATA = ksvgplugin.desktop + +svgthumbnail_la_SOURCES = svgcreator.cpp +svgthumbnail_la_LIBADD = ../libksvg.la +svgthumbnail_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +services_DATA = svgthumbnail.desktop +servicesdir = $(kde_servicesdir) + +partdir = $(kde_datadir)/ksvg +part_DATA = ksvgplugin.rc + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/ksvgplugin.pot diff --git a/ksvg/plugin/backends/Makefile.am b/ksvg/plugin/backends/Makefile.am new file mode 100644 index 00000000..eb3c3089 --- /dev/null +++ b/ksvg/plugin/backends/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = libart #agg diff --git a/ksvg/plugin/backends/agg/AggCanvas.cpp b/ksvg/plugin/backends/agg/AggCanvas.cpp new file mode 100644 index 00000000..245d36e1 --- /dev/null +++ b/ksvg/plugin/backends/agg/AggCanvas.cpp @@ -0,0 +1,130 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 "AggCanvas.h" +#include "SVGShapeImpl.h" +#include "SVGPaintImpl.h" +#include "SVGPaint.h" +#include "SVGGradientElementImpl.h" +#include "SVGLinearGradientElementImpl.h" +#include "SVGRadialGradientElementImpl.h" +#include "SVGPatternElementImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include + +#include "AggCanvasItems.h" +#include "GlyphTracerAgg.h" + +#include "agg_vertex_iterator.h" +#include "agg_bounding_rect.h" + +using namespace KSVG; + +AggCanvas::AggCanvas(unsigned int width, unsigned int height) : KSVGCanvas(width, height) +{ + m_fontContext = new T2P::Converter(new T2P::GlyphTracerAgg()); +} + +void AggCanvas::setRenderBufferSize(int w, int h) +{ + KSVGCanvas::setRenderBufferSize(w, h); + m_buf.attach(m_buffer, m_width, m_height, m_width * m_nrChannels); +} + +void AggCanvas::setBuffer(unsigned char *buffer) +{ + KSVGCanvas::setBuffer(buffer); + m_buf.attach(m_buffer, m_width, m_height, m_width * m_nrChannels); +} + +T2P::BezierPath *AggCanvas::toBezierPath(CanvasItem *item) const +{ + // Only handle AggPath items + return dynamic_cast(item); +} + +// drawing primitives +CanvasItem *AggCanvas::createRectangle(SVGRectElementImpl *rect) +{ + return new AggRectangle(this, rect); +} + +CanvasItem *AggCanvas::createEllipse(SVGEllipseElementImpl *ellipse) +{ + return new AggEllipse(this, ellipse); +} + +CanvasItem *AggCanvas::createCircle(SVGCircleElementImpl *circle) +{ + return new AggCircle(this, circle); +} + +CanvasItem *AggCanvas::createLine(SVGLineElementImpl *line) +{ + return new AggLine(this, line); +} + +CanvasItem *AggCanvas::createPolyline(SVGPolylineElementImpl *poly) +{ + return new AggPolyline(this, poly); +} + +CanvasItem *AggCanvas::createPolygon(SVGPolygonElementImpl *poly) +{ + return new AggPolygon(this, poly); +} + +CanvasItem *AggCanvas::createPath(SVGPathElementImpl *path) +{ + return new AggPath(this, path); +} + +CanvasItem *AggCanvas::createClipPath(SVGClipPathElementImpl *) +{ + return 0; +} + +CanvasItem *AggCanvas::createImage(SVGImageElementImpl *image) +{ + return new AggImage(this, image); +} + +CanvasItem *AggCanvas::createCanvasMarker(SVGMarkerElementImpl *marker) +{ + return new AggMarker(this, marker); +} + +CanvasItem *AggCanvas::createText(SVGTextElementImpl *text) +{ + return new AggText(this, text); +} + +CanvasPaintServer *AggCanvas::createPaintServer(SVGElementImpl *pserver) +{ + AggPaintServer *result = 0; + if(dynamic_cast(pserver)) + result = new AggLinearGradient(dynamic_cast(pserver)); + else if(dynamic_cast(pserver)) + result = new AggRadialGradient(dynamic_cast(pserver)); + else if(dynamic_cast(pserver)) + result = new AggPattern(dynamic_cast(pserver)); + return result; +} + diff --git a/ksvg/plugin/backends/agg/AggCanvas.h b/ksvg/plugin/backends/agg/AggCanvas.h new file mode 100644 index 00000000..9df7a826 --- /dev/null +++ b/ksvg/plugin/backends/agg/AggCanvas.h @@ -0,0 +1,77 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 AGGCANVAS_H +#define AGGCANVAS_H + +#include "KSVGCanvas.h" + +#include "agg_basics.h" +#include "agg_rendering_buffer.h" +#include "agg_path_storage.h" +#include "agg_rasterizer_scanline_aa.h" +#include "agg_scanline_u.h" +#include "agg_renderer_scanline.h" +#include "agg_pixfmt_rgb24.h" + +namespace KSVG +{ + +class AggPaintServer; +class SVGElementImpl; +class AggCanvas : public KSVGCanvas +{ +public: + AggCanvas(unsigned int width, unsigned int height); + + virtual T2P::BezierPath *toBezierPath(CanvasItem *item) const; + + // creating canvas items + virtual CanvasItem *createRectangle(SVGRectElementImpl *rect); + virtual CanvasItem *createEllipse(SVGEllipseElementImpl *ellipse); + virtual CanvasItem *createCircle(SVGCircleElementImpl *circle); + virtual CanvasItem *createLine(SVGLineElementImpl *line); + virtual CanvasItem *createPolyline(SVGPolylineElementImpl *poly); + virtual CanvasItem *createPolygon(SVGPolygonElementImpl *poly); + virtual CanvasItem *createPath(SVGPathElementImpl *path); + virtual CanvasItem *createClipPath(SVGClipPathElementImpl *clippath); + virtual CanvasItem *createImage(SVGImageElementImpl *image); + virtual CanvasItem *createCanvasMarker(SVGMarkerElementImpl *marker); + virtual CanvasItem *createText(SVGTextElementImpl *text); + virtual CanvasPaintServer *createPaintServer(SVGElementImpl *pserver); + + virtual void setRenderBufferSize(int w, int h); + + agg::rendering_buffer &buf() { return m_buf; } + + float zoom() const { return m_zoom; } + + agg::rasterizer_scanline_aa<> m_ras; + +protected: + virtual void setBuffer(unsigned char *buffer); + +protected: + agg::rendering_buffer m_buf; +}; + +}; + +#endif diff --git a/ksvg/plugin/backends/agg/AggCanvasFactory.cpp b/ksvg/plugin/backends/agg/AggCanvasFactory.cpp new file mode 100644 index 00000000..439623ad --- /dev/null +++ b/ksvg/plugin/backends/agg/AggCanvasFactory.cpp @@ -0,0 +1,45 @@ +/* + Copyright (C) 2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 + +#include "AggCanvas.h" +#include "AggCanvasFactory.h" + +using namespace KSVG; + +K_EXPORT_COMPONENT_FACTORY(libksvgrendereragg, AggCanvasFactory) + +AggCanvasFactory::AggCanvasFactory() +{ +} + +AggCanvasFactory::~AggCanvasFactory() +{ +} + +QObject *AggCanvasFactory::createObject(QObject *, const char *, const char *, const QStringList &args) +{ + unsigned int width = (*args.at(1)).toUInt(); + unsigned int height = (*args.at(0)).toUInt(); + return new AggCanvas(width, height); +} + +// vim:ts=4:noet diff --git a/ksvg/plugin/backends/agg/AggCanvasFactory.h b/ksvg/plugin/backends/agg/AggCanvasFactory.h new file mode 100644 index 00000000..9fb3ffbf --- /dev/null +++ b/ksvg/plugin/backends/agg/AggCanvasFactory.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 AGGCANVASFACTORY_H +#define AGGCANVASFACTORY_H + +#include + +#include "CanvasItem.h" +#include "KSVGCanvas.h" + +namespace KSVG +{ + +class AggCanvasFactory : public KLibFactory +{ +public: + AggCanvasFactory(); + virtual ~AggCanvasFactory(); + + virtual QObject *createObject(QObject *parent = 0, const char *pname = 0, const char *name = "QObject", const QStringList &args = QStringList()); +}; + +}; + +#endif + +/// vim:ts=4:noet diff --git a/ksvg/plugin/backends/agg/AggCanvasItems.cpp b/ksvg/plugin/backends/agg/AggCanvasItems.cpp new file mode 100644 index 00000000..4ceb6109 --- /dev/null +++ b/ksvg/plugin/backends/agg/AggCanvasItems.cpp @@ -0,0 +1,1747 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 + +#include "SVGPaint.h" +#include "SVGRectImpl.h" +#include "SVGAngleImpl.h" +#include "SVGPaintImpl.h" +#include "SVGMatrixImpl.h" +#include "SVGUnitTypes.h" +#include "SVGHelperImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGPointListImpl.h" +#include "SVGMarkerElement.h" +#include "SVGMarkerElementImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGPathSegListImpl.h" +#include "SVGAnimatedRectImpl.h" +#include "SVGAnimatedAngleImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGPolygonElementImpl.h" +#include "SVGClipPathElementImpl.h" +#include "SVGPolylineElementImpl.h" +#include "SVGStopElementImpl.h" +#include "SVGGradientElement.h" +#include "SVGGradientElementImpl.h" +#include "SVGLinearGradientElementImpl.h" +#include "SVGRadialGradientElementImpl.h" +#include "SVGPatternElementImpl.h" +#include "SVGAnimatedNumberImpl.h" +#include "SVGAnimatedLengthListImpl.h" +#include "SVGAnimatedEnumerationImpl.h" +#include "SVGAnimatedStringImpl.h" +#include "SVGPreserveAspectRatioImpl.h" +#include "SVGAnimatedPreserveAspectRatioImpl.h" +#include "SVGAnimatedTransformListImpl.h" +#include "SVGTransformListImpl.h" +#include "SVGUnitConverter.h" + +#include "Glyph.h" +#include "Converter.h" +#include "KSVGTextChunk.h" + +#include "agg_rasterizer_scanline_aa.h" +#include "agg_scanline_u.h" +#include "agg_scanline_p.h" +#include "agg_bounding_rect.h" +#include "agg_ellipse.h" +#include "agg_span_image_filter_rgba32.h" +#include "agg_color_rgba8.h" +#include "agg_gray8.h" +#include "agg_span_gradient.h" +#include "agg_span_interpolator_linear.h" +#include "agg_span_pattern_rgba32.h" +#include "agg_renderer_scanline.h" + +#include "AggCanvas.h" +#include "AggCanvasItems.h" + +extern "C" +{ +/* These are in KSVGHelper.cpp */ +int linearRGBFromsRGB(int sRGB8bit); +int sRGBFromLinearRGB(int linearRGB8bit); +} + +struct color_function_profile +{ + color_function_profile() {} + color_function_profile(const agg::rgba8 *colors) : + m_colors(colors) {} + + const agg::rgba8& operator [] (unsigned v) const + { + return m_colors[v]; + } + + const agg::rgba8 *m_colors; +}; + +using namespace KSVG; + +// agg2 helpers + +agg::vcgen_stroke::line_cap_e toAggLineCap(PathStrokeCapType cap) +{ + if(cap == PATH_STROKE_CAP_BUTT) + return agg::vcgen_stroke::butt_cap; + else if(cap == PATH_STROKE_CAP_ROUND) + return agg::vcgen_stroke::round_cap; + else + return agg::vcgen_stroke::square_cap; +} + +template +stroke::stroke(Source& src, KSVG::SVGStylableImpl *style) : m_s(src) +{ + m_s.width(style->getStrokeWidth()->baseVal()->value()); + m_s.line_join((agg::vcgen_stroke::line_join_e)style->getJoinStyle()); + m_s.miter_limit(style->getStrokeMiterlimit()); + m_s.line_cap(toAggLineCap(style->getCapStyle())); +} + +template +dash_stroke::dash_stroke(Source& src, KSVG::SVGStylableImpl *style) : m_d(src), m_ds(m_d) +{ + unsigned int dashLength = style->getDashArray() ? style->getDashArray()->baseVal()->numberOfItems() : 0; + // there are dashes to be rendered + unsigned int count = (dashLength % 2) == 0 ? dashLength : dashLength * 2; + for(unsigned int i = 0; i < count; i += 2) + m_d.add_dash(style->getDashArray()->baseVal()->getItem(i % dashLength)->value(), + style->getDashArray()->baseVal()->getItem((i + 1) % dashLength)->value()); + m_d.dash_start(style->getDashOffset()->baseVal()->value()); + m_ds.width(style->getStrokeWidth()->baseVal()->value()); + m_ds.line_join((agg::vcgen_stroke::line_join_e)style->getJoinStyle()); + m_ds.miter_limit(style->getStrokeMiterlimit()); + m_ds.line_cap(toAggLineCap(style->getCapStyle())); +} + +template +dash_stroke_simple::dash_stroke_simple(Source& src, KSVG::SVGStylableImpl *style) +{ + //if(style->isStroked() && style->getStrokeWidth()->baseVal()->value() > 0) + //{ + unsigned int dashLength = style->getDashArray() ? style->getDashArray()->baseVal()->numberOfItems() : 0; + if(dashLength > 0) + impl = new dash_stroke(src, style); + else + impl = new stroke(src, style); + //} + //else + //impl = 0; +} + +void renderPathSolid(AggCanvas *canvas, const agg::rgba8 &color) +{ + agg::scanline_p8 sl; + if(canvas->nrChannels() == 3) + { + typedef agg::pixfmt_rgb24 pixfmt; + typedef agg::renderer_base renderer_base; + typedef agg::renderer_scanline_p_solid renderer_solid; + + pixfmt pixf(canvas->buf()); + renderer_base rb(pixf); + renderer_solid ren(rb); + + ren.color(color); + canvas->m_ras.render(sl, ren); + } + else + { + typedef agg::pixfmt_rgba32 pixfmt; + typedef agg::renderer_base renderer_base; + typedef agg::renderer_scanline_p_solid renderer_solid; + + pixfmt pixf(canvas->buf()); + renderer_base rb(pixf); + renderer_solid ren(rb); + + ren.color(color); + canvas->m_ras.render(sl, ren); + } +} + +// ##### + +BezierPathAggStroked::BezierPathAggStroked(SVGStylableImpl *style) +: T2P::BezierPathAgg(), m_curved_trans_clipped(m_curved_trans), m_curved_stroked(m_curved, style), m_curved_stroked_trans(m_curved_stroked, m_transform), m_curved_stroked_trans_clipped(m_curved_stroked_trans), m_style(style) +{ +} + +BezierPathAggStroked::BezierPathAggStroked(const T2P::BezierPathAgg &other, SVGStylableImpl *style) +: T2P::BezierPathAgg(other), m_curved_trans_clipped(m_curved_trans), m_curved_stroked(m_curved, style), m_curved_stroked_trans(m_curved_stroked, m_transform), m_curved_stroked_trans_clipped(m_curved_stroked_trans), m_style(style) +{ +} + +AggShape::AggShape(AggCanvas *c, SVGStylableImpl *style) : CanvasItem(), BezierPathAggStroked(style), m_canvas(c) +{ + m_context = NORMAL; + m_fillPainter = 0; + m_strokePainter = 0; +} + +AggShape::~AggShape() +{ + freeSVPs(); + delete m_fillPainter; + delete m_strokePainter; +} + +QRect AggShape::bbox() const +{ + return m_bbox; +} + +bool AggShape::fillContains(const QPoint &p) +{ + agg::rasterizer_scanline_aa<> ras; + ras.filling_rule(m_style->getFillRule() == RULE_EVENODD ? agg::fill_even_odd : agg::fill_non_zero); + ras.add_path(m_curved_trans); + bool b = ras.hit_test(p.x(), p.y()); + return b; +} + +bool AggShape::strokeContains(const QPoint &p) +{ + agg::rasterizer_scanline_aa<> ras; + ras.add_path(m_curved_stroked_trans); + bool b = ras.hit_test(p.x(), p.y()); + return b; +} + +void AggShape::update(CanvasItemUpdate reason, int param1, int param2) +{ + if(reason == UPDATE_STYLE) + { + if(!m_fillPainter || !m_strokePainter) + AggShape::init(); + if(m_fillPainter) + m_fillPainter->update(m_style); + if(m_strokePainter) + m_strokePainter->update(m_style); + m_canvas->invalidate(this, false); + } + else if(reason == UPDATE_TRANSFORM) + { + freeSVPs(); + init(); + m_canvas->invalidate(this, true); + } + else if(reason == UPDATE_ZOOM) + init(); + else if(reason == UPDATE_PAN) + { + agg::trans_affine mtx(1, 0, 0, 1, param1, param2); + m_transform *= mtx; + } + else if(reason == UPDATE_LINEWIDTH) + { + init(); + m_canvas->invalidate(this, true); + } +} + +void AggShape::draw(SVGShapeImpl *shape) +{ + if(!m_referenced && (!m_style->getVisible() || !m_style->getDisplay() || !shape->directRender())) + return; + + //if(!m_strokeSVP && (!m_fillSVP || !m_style->isFilled())) + // init(); + agg::rect cb; + if(m_canvas->nrChannels() == 3) + { + agg::pixfmt_rgb24 pixf(m_canvas->buf()); + agg::renderer_base rb(pixf); + cb = rb.clip_box(); + } + else + { + agg::pixfmt_rgba32 pixf(m_canvas->buf()); + agg::renderer_base rb(pixf); + cb = rb.clip_box(); + } + + m_curved_trans_clipped.clip_box(cb.x1, cb.y1, cb.x2 + 1, cb.y2 + 1); + m_curved_stroked_trans_clipped.clip_box(cb.x1, cb.y1, cb.x2 + 1, cb.y2 + 1); + + double x1, y1, x2, y2; + agg::bounding_rect(m_curved_trans, *this, 0, 1, &x1, &y1, &x2, &y2); + m_bbox = QRect(int(x1), int(y1), int(x2 - x1), int(y2 - y1)); + + m_curved.approximation_scale(pow(m_transform.scale(), 0.75)); + + if(m_fillPainter) + m_fillPainter->draw(m_canvas, m_curved_trans, m_style, shape); + if(m_strokePainter) + m_strokePainter->draw(m_canvas, m_curved_stroked_trans, m_style, shape); +} + +bool AggShape::isVisible(SVGShapeImpl *shape) +{ + return m_referenced || (m_style->getVisible() && m_style->getDisplay() && shape->directRender()); +} + +void AggShape::calcSVPs(const SVGMatrixImpl *matrix) +{ + // transform + m_transform = agg::trans_affine(matrix->a(), matrix->b(), matrix->c(), matrix->d(), matrix->e(), matrix->f()); + + double x1, y1, x2, y2; + agg::bounding_rect(m_curved_trans, *this, 0, 1, &x1, &y1, &x2, &y2); + m_bbox = QRect(int(x1), int(y1), int(x2 - x1), int(y2 - y1)); +} + +void AggShape::init(const SVGMatrixImpl *) +{ +} + +void AggShape::init() +{ + if(m_style->isFilled()) + { + if(m_fillPainter == 0) + m_fillPainter = new AggFillPaintServer(m_style); + } + else + { + delete m_fillPainter; + m_fillPainter = 0; + } + + // Spec: A zero value causes no stroke to be painted. + if(m_style->isStroked() && m_style->getStrokeWidth()->baseVal()->value() > 0) + { + if(m_strokePainter == 0) + m_strokePainter = new AggStrokePaintServer(m_style); + } + else + { + delete m_strokePainter; + m_strokePainter = 0; + } +} + +void AggShape::freeSVPs() +{ + m_storage.remove_all(); +} + +// ##### + +AggStrokePaintServer::AggStrokePaintServer(SVGStylableImpl *style) +{ + update(style); +} + +void AggStrokePaintServer::update(SVGStylableImpl *style) +{ + if(style->getStrokeColor()->paintType() != SVG_PAINTTYPE_URI) + { + QColor qcolor; + if(style->getStrokeColor()->paintType() == SVG_PAINTTYPE_CURRENTCOLOR) + qcolor = style->getColor()->rgbColor().color(); + else + qcolor = style->getStrokeColor()->rgbColor().color(); + + short opacity = static_cast(style->getStrokeOpacity() * style->getOpacity() * 255); + + // Spec: clamping + opacity = opacity < 0 ? 0 : opacity; + opacity = opacity > 255 ? 255 : opacity; + + m_color = agg::rgba8(qcolor.red(), qcolor.green(), qcolor.blue()); + m_color.opacity(style->getStrokeOpacity() * style->getOpacity()); + } +} + +template +void AggStrokePaintServer::draw(AggCanvas *canvas, VertexSource &vs, SVGStylableImpl *style, SVGShapeImpl *shape) +{ + canvas->m_ras.reset(); + if(style->getStrokeColor()->paintType() == SVG_PAINTTYPE_URI) + { + AggPaintServer *pserver = static_cast(SVGPaintServerImpl::paintServer(shape->ownerDoc(), style->getStrokeColor()->uri().string())); + if(!pserver) return; + pserver->setBBoxTarget(shape); + + // TODO : Clipping + if(!pserver->finalized()) + pserver->finalizePaintServer(); + canvas->m_ras.add_path(vs); + pserver->render(canvas); + } + else + { + canvas->m_ras.add_path(vs); + renderPathSolid(canvas, m_color); + } +} + +AggFillPaintServer::AggFillPaintServer(SVGStylableImpl *style) +{ + update(style); +} + +void AggFillPaintServer::update(SVGStylableImpl *style) +{ + if(style->getFillColor()->paintType() != SVG_PAINTTYPE_URI) + { + QColor qcolor; + if(style->getFillColor()->paintType() == SVG_PAINTTYPE_CURRENTCOLOR) + qcolor = style->getColor()->rgbColor().color(); + else + qcolor = style->getFillColor()->rgbColor().color(); + + short opacity = static_cast(style->getFillOpacity() * style->getOpacity() * 255); + + // Spec: clamping + opacity = opacity < 0 ? 0 : opacity; + opacity = opacity > 255 ? 255 : opacity; + + m_color = agg::rgba8(qcolor.red(), qcolor.green(), qcolor.blue()); + m_color.opacity(style->getFillOpacity() * style->getOpacity()); + } +} + +template +void AggFillPaintServer::draw(AggCanvas *canvas, VertexSource &vs, SVGStylableImpl *style, SVGShapeImpl *shape) +{ + canvas->m_ras.reset(); + if(style->getFillColor()->paintType() == SVG_PAINTTYPE_URI) + { + AggPaintServer *pserver = static_cast(SVGPaintServerImpl::paintServer(shape->ownerDoc(), style->getFillColor()->uri().string())); + if(!pserver) return; + pserver->setBBoxTarget(shape); + + // TODO : Clipping + if(!pserver->finalized()) + pserver->finalizePaintServer(); + canvas->m_ras.add_path(vs); + pserver->render(canvas); + } + else + { + canvas->m_ras.filling_rule(style->getFillRule() == RULE_EVENODD ? agg::fill_even_odd : agg::fill_non_zero); + canvas->m_ras.add_path(vs); + renderPathSolid(canvas, m_color); + } +} + +// ##### + +AggRectangle::AggRectangle(AggCanvas *c, SVGRectElementImpl *rect) +: AggShape(c, rect), m_rect(rect) +{ + init(); +} + +void AggRectangle::draw() +{ + if(isVisible()) + AggShape::draw(m_rect); +} + +bool AggRectangle::isVisible() +{ + // Spec: a value of zero disables rendering + return AggShape::isVisible(m_rect) && m_rect->width()->baseVal()->value() > 0 && m_rect->height()->baseVal()->value() > 0; +} + +void AggRectangle::init() +{ + init(m_rect->screenCTM()); +} + +void AggRectangle::init(const SVGMatrixImpl *screenCTM) +{ + AggShape::init(); + if(m_storage.total_vertices() == 0) + { + double x = m_rect->x()->baseVal()->value(); + double y = m_rect->y()->baseVal()->value(); + double width = m_rect->width()->baseVal()->value(); + double height = m_rect->height()->baseVal()->value(); + double rx = m_rect->rx()->baseVal()->value(); + double ry = m_rect->ry()->baseVal()->value(); + + // Spec: If there is no rx or ry specified, draw a normal rect + if(rx == -1 && ry == -1) + { + m_storage.move_to(x, y); + m_storage.line_to(x + width, y); + m_storage.line_to(x + width, y + height); + m_storage.line_to(x, y + height); + } + else + { + int i = 0; + + // Spec: If rx isn't specified, but ry, set rx to ry + if(rx == -1) + rx = ry; + + // Spec: If ry isn't specified, but rx, set ry to rx + if(ry == -1) + ry = rx; + + // Spec: If rx is greater than half of the width of the rectangle + // then set rx to half of the width + if(rx > width / 2) + rx = width / 2; + + // Spec: If ry is greater than half of the height of the rectangle + // then set ry to half of the height + if(ry > height / 2) + ry = height / 2; + + m_storage.move_to(x + rx, y); + + i++; + m_storage.curve4(x + rx * (1 - 0.552), y, x, y + ry * (1 - 0.552), x, y + ry); + i++; + if(ry < height / 2) + { + m_storage.line_to(x, y + height - ry); + i++; + } + m_storage.curve4(x, y + height - ry * (1 - 0.552), x + rx * (1 - 0.552), y + height, x + rx, y + height); + i++; + if(rx < width / 2) + { + m_storage.line_to(x + width - rx, y + height); + i++; + } + m_storage.curve4(x + width - rx * (1 - 0.552), y + height, x + width, y + height - ry * (1 - 0.552), x + width, y + height - ry); + i++; + if(ry < height / 2) + { + m_storage.line_to(x + width, y + ry); + i++; + } + m_storage.curve4(x + width, y + ry * (1 - 0.552), x + width - rx * (1 - 0.552), y, x + width - rx, y); + i++; + if(rx < width / 2) + { + m_storage.line_to(x + rx, y); + i++; + } + } + m_storage.close_polygon(); + } + //if(m_context == NORMAL) + calcSVPs(screenCTM); + //else + // calcClipSVP(vec, m_rect, screenCTM, &m_fillSVP); +} + +// ##### + +AggEllipse::AggEllipse(AggCanvas *c, SVGEllipseElementImpl *ellipse) +: AggShape(c, ellipse), m_ellipse(ellipse) +{ + init(); +} + +void AggEllipse::draw() +{ + if(isVisible()) + AggShape::draw(m_ellipse); +} + +bool AggEllipse::isVisible() +{ + // Spec: dont render when rx and/or ry is zero + return AggShape::isVisible(m_ellipse) && m_ellipse->rx()->baseVal()->value() > 0 && m_ellipse->ry()->baseVal()->value() > 0; +} + +void AggEllipse::init() +{ + init(m_ellipse->screenCTM()); +} + +void AggEllipse::init(const SVGMatrixImpl *screenCTM) +{ + AggShape::init(); + if(m_storage.total_vertices() == 0) + { + double rx = m_ellipse->rx()->baseVal()->value(); + double ry = m_ellipse->ry()->baseVal()->value(); + double cx = m_ellipse->cx()->baseVal()->value(); + double cy = m_ellipse->cy()->baseVal()->value(); + + agg::ellipse ell(cx, cy, rx, ry, 100); + ell.rewind(0); + double x, y; + unsigned int cmd; + while((cmd = ell.vertex(&x, &y)) != agg::path_cmd_stop) + m_storage.add_vertex(x, y, cmd); + m_storage.close_polygon(); + } + //if(m_context == NORMAL) + calcSVPs(screenCTM); + //else + // calcClipSVP(vec2, m_ellipse, screenCTM, &m_fillSVP); +} + +// ##### + +AggCircle::AggCircle(AggCanvas *c, SVGCircleElementImpl *circle) +: AggShape(c, circle), m_circle(circle) +{ + init(); +} + +void AggCircle::draw() +{ + if(isVisible()) + AggShape::draw(m_circle); +} + +bool AggCircle::isVisible() +{ + // Spec: a value of zero disables rendering + return AggShape::isVisible(m_circle) && m_circle->r()->baseVal()->value() > 0; +} + +void AggCircle::init() +{ + init(m_circle->screenCTM()); +} + +void AggCircle::init(const SVGMatrixImpl *screenCTM) +{ + AggShape::init(); + if(m_storage.total_vertices() == 0) + { + double r = m_circle->r()->baseVal()->value(); + double cx = m_circle->cx()->baseVal()->value(); + double cy = m_circle->cy()->baseVal()->value(); + + agg::ellipse ell(cx, cy, r, r, 100); + ell.rewind(0); + double x, y; + unsigned int cmd; + while((cmd = ell.vertex(&x, &y)) != agg::path_cmd_stop) + m_storage.add_vertex(x, y, cmd); + m_storage.close_polygon(); + } + //if(m_context == NORMAL) + calcSVPs(screenCTM); + //else + // calcClipSVP(vec2, m_ellipse, screenCTM, &m_fillSVP); +} + +// ##### + +AggLine::AggLine(AggCanvas *c, SVGLineElementImpl *line) +: AggShape(c, line), MarkerHelper(), m_line(line) +{ + init(); +} + +AggLine::~AggLine() +{ +} + +void AggLine::draw() +{ + if(isVisible()) + { + // transform ( zoom?) + //agg::trans_affine transform = m_transform; + //agg::trans_affine mtx(m_canvas->zoom(), 0, 0, m_canvas->zoom(), m_canvas->pan().x(), m_canvas->pan().y()); + //m_transform *= mtx; + //m_curved.approximation_scale(pow(m_transform.scale(), 0.75)); + + if(m_style->isStroked()) + { + m_canvas->m_ras.reset(); + m_canvas->m_ras.add_path(m_curved_stroked_trans); + QColor qcolor; + if(m_style->getStrokeColor()->paintType() == SVG_PAINTTYPE_CURRENTCOLOR) + qcolor = m_style->getColor()->rgbColor().color(); + else + qcolor = m_style->getStrokeColor()->rgbColor().color(); + agg::rgba8 color(qcolor.red(), qcolor.green(), qcolor.blue()); + color.opacity(m_style->getStrokeOpacity() * m_style->getOpacity()); + renderPathSolid(m_canvas, color); + } + //m_transform = transform; + + if(m_line->hasMarkers()) + { + double x1 = m_line->x1()->baseVal()->value(); + double y1 = m_line->y1()->baseVal()->value(); + double x2 = m_line->x2()->baseVal()->value(); + double y2 = m_line->y2()->baseVal()->value(); + double slope = SVGAngleImpl::todeg(atan2(y2 - y1, x2 - x1)); + + if(m_line->hasStartMarker()) + doStartMarker(m_line, m_line, x1, y1, slope); + if(m_line->hasEndMarker()) + doEndMarker(m_line, m_line, x2, y2, slope); + } + } +} + +bool AggLine::isVisible() +{ + return AggShape::isVisible(m_line); +} + +void AggLine::init() +{ + init(m_line->screenCTM()); +} + +void AggLine::init(const SVGMatrixImpl *screenCTM) +{ + AggShape::init(); + if(m_storage.total_vertices() == 0) + { + m_storage.move_to(m_line->x1()->baseVal()->value(), m_line->y1()->baseVal()->value()); + // A subpath consisting of a moveto and lineto to the same exact location or a subpath consisting of a moveto + // and a closepath will be stroked only if the 'stroke-linecap' property is set to "round", producing a circle + // centered at the given point. + double x2 = m_line->x2()->baseVal()->value(); + double y2 = m_line->y2()->baseVal()->value(); + if(x2 == m_line->x1()->baseVal()->value() && y2 == m_line->y1()->baseVal()->value() && m_line->getCapStyle() == PATH_STROKE_CAP_ROUND) + m_storage.line_to(x2 + .5, y2); + else + m_storage.line_to(x2, y2); + } + //if(m_context == NORMAL) + calcSVPs(screenCTM); + //else + // calcClipSVP(polyline, m_poly, screenCTM, &m_fillSVP); +} + +// ##### +AggPoly::AggPoly(AggCanvas *c, SVGPolyElementImpl *poly) +: AggShape(c, poly), MarkerHelper(), m_poly(poly) +{ +} + +AggPoly::~AggPoly() +{ +} + +void AggPoly::init() +{ + init(m_poly->screenCTM()); +} + +void AggPoly::draw() +{ + if(isVisible()) + { + AggShape::draw(m_poly); + + if(m_poly->hasMarkers()) + m_poly->drawMarkers(); + } +} + +bool AggPoly::isVisible() +{ + return AggShape::isVisible(m_poly); +} + +// ##### +AggPolyline::AggPolyline(AggCanvas *c, SVGPolylineElementImpl *poly) +: AggPoly(c, poly) +{ + AggPoly::init(); +} + +AggPolyline::~AggPolyline() +{ +} + +void AggPolyline::init(const SVGMatrixImpl *screenCTM) +{ + AggShape::init(); + if(m_storage.total_vertices() == 0) + { + unsigned int numberOfPoints = m_poly->points()->numberOfItems(); + + if(numberOfPoints < 1) + return; + + m_storage.move_to(m_poly->points()->getItem(0)->x(), m_poly->points()->getItem(0)->y()); + + // A subpath consisting of a moveto and lineto to the same exact location or a subpath consisting of a moveto + // and a closepath will be stroked only if the 'stroke-linecap' property is set to "round", producing a circle + // centered at the given point. + if(numberOfPoints == 2) + { + double x1 = m_poly->points()->getItem(1)->x(); + double y1 = m_poly->points()->getItem(1)->y(); + if(x1 == m_poly->points()->getItem(0)->x() && y1 == m_poly->points()->getItem(0)->y() && m_poly->getCapStyle() == PATH_STROKE_CAP_ROUND) + m_storage.line_to(m_poly->points()->getItem(1)->x() + .5, m_poly->points()->getItem(1)->y()); + else + m_storage.line_to(m_poly->points()->getItem(1)->x(), m_poly->points()->getItem(1)->y()); + } + else + { + unsigned int index; + for(index = 1; index < numberOfPoints; index++) + m_storage.line_to(m_poly->points()->getItem(index)->x(), m_poly->points()->getItem(index)->y()); + } + } + //if(m_context == NORMAL) + calcSVPs(screenCTM); + //else + // calcClipSVP(polyline, m_poly, screenCTM, &m_fillSVP); +} + +// ##### + +AggPolygon::AggPolygon(AggCanvas *c, SVGPolygonElementImpl *poly) +: AggPoly(c, poly) +{ + AggPoly::init(); +} + +AggPolygon::~AggPolygon() +{ +} + +void AggPolygon::init(const SVGMatrixImpl *screenCTM) +{ + AggShape::init(); + if(m_storage.total_vertices() == 0) + { + int numberOfPoints = m_poly->points()->numberOfItems(); + + if(numberOfPoints < 1) + return; + + m_storage.move_to(m_poly->points()->getItem(0)->x(), m_poly->points()->getItem(0)->y()); + + int index; + for(index = 1; index < numberOfPoints; index++) + m_storage.line_to(m_poly->points()->getItem(index)->x(), m_poly->points()->getItem(index)->y()); + + m_storage.line_to(m_poly->points()->getItem(0)->x(), m_poly->points()->getItem(0)->y()); + m_storage.close_polygon(); + } + //if(m_context == NORMAL) + calcSVPs(screenCTM); + //else + // calcClipSVP(polygon, m_poly, screenCTM, &m_fillSVP); +} + +// ##### + +AggPath::AggPath(AggCanvas *c, SVGPathElementImpl *path) +: AggShape(c, path), SVGPathParser(), MarkerHelper(), m_path(path) +{ + init(); +} + +AggPath::~AggPath() +{ +} + +void AggPath::draw() +{ + AggShape::draw(m_path); + + if(m_path->hasMarkers()) + { + SVGPathElementImpl::MarkerData markers = m_path->markerData(); + int numMarkers = markers.numMarkers(); + + if(m_path->hasStartMarker()) + doStartMarker(m_path, m_path, markers.marker(0).x, markers.marker(0).y, markers.marker(0).angle); + + for(int i = 1; i < numMarkers - 1; i++) + { + if(m_path->hasMidMarker()) + doMidMarker(m_path, m_path, markers.marker(i).x, markers.marker(i).y, markers.marker(i).angle); + } + + if(m_path->hasEndMarker()) + doEndMarker(m_path, m_path, markers.marker(numMarkers - 1).x, markers.marker(numMarkers - 1).y, markers.marker(numMarkers - 1).angle); + } +} + +bool AggPath::isVisible() +{ + return AggShape::isVisible(m_path); +} + +void AggPath::init() +{ + init(m_path->screenCTM()); +} + +void AggPath::init(const SVGMatrixImpl *screenCTM) +{ + AggShape::init(); + if(m_storage.total_vertices() == 0) + { + if(!m_path->getAttribute("d").string().isEmpty()) + { + m_storage.start_new_path(); + parseSVG(m_path->getAttribute("d").string(), true); + + // A subpath consisting of a moveto and lineto to the same exact location or a subpath consisting of a moveto + // and a closepath will be stroked only if the 'stroke-linecap' property is set to "round", producing a circle + // centered at the given point. + if(m_storage.total_vertices() == 2 && agg::is_line_to(m_storage.command(1))) + { + double x1, y1; + double x2, y2; + m_storage.vertex(0, &x1, &y1); + m_storage.vertex(1, &x2, &y2); + if(x1 == x2 && y1 == y2 && m_path->getCapStyle() == PATH_STROKE_CAP_ROUND) + m_storage.modify_vertex(1, x2 + .5, y2); + } + // TODO : handle filled paths that are not closed explicitly + } + } + + // There are pure-moveto paths which reference paint servers *bah* + // Do NOT render them + bool dontrender = m_storage.total_vertices() == 1 && agg::is_move_to((*m_storage.begin()).cmd); + if(!dontrender && m_context == NORMAL) + calcSVPs(screenCTM); + //else + // calcClipSVP(ksvg_art_bez_path_to_vec(m_array.data(), 0.25), m_path, screenCTM, &m_fillSVP); +} + +void AggPath::svgMoveTo(double x1, double y1, bool, bool) +{ + m_storage.move_to(x1, y1); +} + +void AggPath::svgLineTo(double x1, double y1, bool) +{ + m_storage.line_to(x1, y1); +} + +void AggPath::svgCurveToCubic(double x1, double y1, double x2, double y2, double x3, double y3, bool) +{ + m_storage.curve4(x1, y1, x2, y2, x3, y3); +} + +void AggPath::svgClosePath() +{ + m_storage.close_polygon(); +} + +// ##### + +AggMarker::AggMarker(AggCanvas *c, SVGMarkerElementImpl *marker) +: CanvasMarker(marker), m_canvas(c)//, m_clippingRectangle(0) +{ +} + +AggMarker::~AggMarker() +{ + //if(m_clippingRectangle) + // art_svp_free(m_clippingRectangle); +} + +void AggMarker::init() +{ +} + +void AggMarker::draw() +{ +} + +void AggMarker::draw(SVGShapeImpl * /*obj*/, int /*x*/, int /*y*/, float /*lwidth*/, double /*angle*/) +{ +} + +// ##### + +AggImage::AggImage(AggCanvas *c, SVGImageElementImpl *image) +: m_canvas(c), m_image(image) +{ +} + +AggImage::~AggImage() +{ +} + +void AggImage::draw() +{ + if(isVisible()) + { + //KSVGPolygon clippingPolygon = m_image->clippingShape(); + + QImage *img = m_image->image(); + if(!img) return; + QImage image = m_image->scaledImage(); + agg::rendering_buffer source_buffer; + source_buffer.attach(image.bits(), image.width(), image.height(), image.width() * 4); + + typedef agg::pixfmt_rgb24 pixfmt; + typedef agg::renderer_base renderer_base; + + pixfmt pixf(m_canvas->buf()); + renderer_base rb(pixf); + + typedef agg::span_interpolator_linear<> interpolator_type; + typedef agg::span_image_filter_rgba32_bilinear span_gen_type; + typedef agg::renderer_scanline_u renderer_type; + SVGMatrixImpl *ctm = m_image->scaledImageMatrix(); + agg::trans_affine img_mtx(ctm->a(), ctm->b(), ctm->c(), ctm->d(), ctm->e(), ctm->f()); + kdDebug() << "ctm->e() : " << ctm->e() << endl; + kdDebug() << "ctm->f() : " << ctm->f() << endl; + double x1 = 0; + double y1 = 0; + double x2 = image.width(); + double y2 = image.height(); + img_mtx.transform(&x1, &y1); + img_mtx.transform(&x2, &y2); + img_mtx.invert(); + + interpolator_type interpolator(img_mtx); + agg::span_allocator sa; + span_gen_type sg(sa, source_buffer, agg::rgba(1, 1, 1, 0), interpolator); + renderer_type ri(rb, sg); + + agg::scanline_u8 sl; + + //rb.reset_clipping(true); + // Clip image against buffer + agg::path_storage viewp; + viewp.move_to(x1, y1); + viewp.line_to(x1, y2); + viewp.line_to(x2, y2); + viewp.line_to(x2, y1); + viewp.close_polygon(); + m_canvas->m_ras.add_path(viewp); + m_canvas->m_ras.render(sl, ri); + + ctm->deref(); + } +} + +bool AggImage::isVisible() +{ + return (m_referenced || (m_image->getVisible() && m_image->getDisplay() && m_image->directRender())) && m_image->image(); +} + +void AggImage::init() +{ +} + +QRect AggImage::bbox() const +{ + QRect bbox(static_cast(m_image->x()->baseVal()->value()), + static_cast(m_image->y()->baseVal()->value()), + static_cast(m_image->width()->baseVal()->value()), + static_cast(m_image->height()->baseVal()->value())); + + + return SVGHelperImpl::fromUserspace(m_image, bbox); +} + +// ##### + +AggText::AggText(AggCanvas *c, SVGTextElementImpl *text) +: CanvasText(text), m_canvas(c) +{ + init(); + m_drawItems.setAutoDelete(true); +} + +AggText::~AggText() +{ +} + +bool AggText::fillContains(const QPoint &p) +{ + QPtrListIterator it(m_drawItems); + + SVPElement *fill = it.current(); + while(fill) + { + if(fill->svp) + { + agg::rasterizer_scanline_aa<> ras; + ras.filling_rule(fill->element->getFillRule() == RULE_EVENODD ? agg::fill_even_odd : agg::fill_non_zero); + ras.add_path(fill->svp->m_curved_trans); + if(ras.hit_test(p.x(), p.y())) + return true; + } + + fill = ++it; + } + + return false; +} + +bool AggText::strokeContains(const QPoint &p) +{ + QPtrListIterator it(m_drawItems); + + SVPElement *stroke = it.current(); + while(stroke) + { + if(stroke->svp) + { + agg::rasterizer_scanline_aa<> ras; + ras.filling_rule(stroke->element->getFillRule() == RULE_EVENODD ? agg::fill_even_odd : agg::fill_non_zero); + ras.add_path(stroke->svp->m_curved_stroked_trans); + if(ras.hit_test(p.x(), p.y())) + return true; + } + + stroke = ++it; + } + + return false; +} + +QRect AggText::bbox() const +{ + QRect result, rect; + + QPtrListIterator it(m_drawItems); + + SVPElement *elem = it.current(); + while(elem) + { + double x1, y1, x2, y2; + if(elem && elem->svp) + { + if(agg::bounding_rect(elem->svp->m_curved_trans, *this, 0, 1, &x1, &y1, &x2, &y2)) + { + rect.setX(int(x1)); + rect.setY(int(y1)); + rect.setWidth(int(x2 - x1)); + rect.setHeight(int(y2 - y1)); + + result = result.unite(rect); + } + } + elem = ++it; + } + return result; +} + +void AggText::update(CanvasItemUpdate reason, int param1, int param2) +{ + if(reason == UPDATE_STYLE) + { + QPtrListIterator it(m_drawItems); + + SVPElement *svpelement = it.current(); + SVGTextContentElementImpl *text; + while(svpelement) + { + text = svpelement->element; + if(svpelement->fillPainter) + svpelement->fillPainter->update(text); + if(svpelement->strokePainter) + svpelement->strokePainter->update(text); + + svpelement = ++it; + } + m_canvas->invalidate(this, false); + } + else if(reason == UPDATE_TRANSFORM) + { + clearCurved(); + init(); + m_canvas->invalidate(this, true); + } + else if(reason == UPDATE_ZOOM) + { + clearCurved(); + init(); + } + else if(reason == UPDATE_PAN) + { + QPtrListIterator it(m_drawItems); + + SVPElement *svpelement = it.current(); + T2P::BezierPathAgg *bpath; + while(svpelement) + { + bpath = svpelement->svp; + agg::trans_affine mtx(1, 0, 0, 1, param1, param2); + bpath->m_transform *= mtx; + + svpelement = ++it; + } + } + /* + else if(reason == UPDATE_LINEWIDTH) + { + }*/ +} + +void AggText::draw() +{ + QPtrListIterator it(m_drawItems); + + SVPElement *svpelement = it.current(); + BezierPathAggStroked *bpath; + SVGTextContentElementImpl *text; + + while(svpelement) + { + bpath = svpelement->svp; + text = svpelement->element; + if(!text->getVisible() || !text->getDisplay() || !text->directRender()) + return; + + bpath->m_curved.approximation_scale(pow(bpath->m_transform.scale(), 1.25)); + + if(svpelement->fillPainter) + svpelement->fillPainter->draw(m_canvas, bpath->m_curved_trans, text, text); + if(svpelement->strokePainter) + svpelement->strokePainter->draw(m_canvas, bpath->m_curved_stroked_trans, text, text); + + svpelement = ++it; + } +} + +bool AggText::isVisible() +{ + bool foundVisible = false; + QPtrListIterator it(m_drawItems); + + SVPElement *svpelement = it.current(); + SVGTextContentElementImpl *text; + + while(svpelement) + { + text = svpelement->element; + if(text->getVisible() && text->getDisplay() && text->directRender()) + { + foundVisible = true; + break; + } + + svpelement = ++it; + } + + return foundVisible; +} + +void AggText::init() +{ + init(m_text->screenCTM()); +} + +void AggText::renderCallback(SVGTextContentElementImpl *element, const SVGMatrixImpl *screenCTM, T2P::GlyphSet *glyph, T2P::GlyphLayoutParams *params, double anchor) const +{ + for(unsigned int i = 0; i < glyph->glyphCount(); i++) + { + T2P::GlyphAffinePair *glyphAffine = glyph->set().at(i); + T2P::BezierPathAgg *bpath = const_cast(static_cast(glyphAffine->transformatedPath())); + + // text-anchor/baseline-shift support + if(!params->tb()) + bpath->m_transform = agg::trans_affine(screenCTM->a(), screenCTM->b(), screenCTM->c(), screenCTM->d(), screenCTM->e() - anchor * screenCTM->a(), screenCTM->f()); + else + bpath->m_transform = agg::trans_affine(screenCTM->a(), screenCTM->b(), screenCTM->c(), screenCTM->d(), screenCTM->e(), screenCTM->f() - anchor * screenCTM->d()); + + SVPElement *svpelement = new SVPElement(); + svpelement->svp = new BezierPathAggStroked(*bpath, element); + svpelement->element = element; + + if(element->isFilled()) + svpelement->fillPainter = new AggFillPaintServer(element); + + // Spec: A zero value causes no stroke to be painted. + if(element->isStroked() && element->getStrokeWidth()->baseVal()->value() > 0) + svpelement->strokePainter = new AggStrokePaintServer(element); + m_drawItems.append(svpelement); + } +} + +void AggText::init(const SVGMatrixImpl *screenCTM) +{ + int curx = 0, cury = 0, endx = 0, endy = 0; + KSVGTextChunk *textChunk = CanvasText::createTextChunk(m_canvas, screenCTM, curx, cury, endx, endy); + + if(textChunk->count() > 0) + CanvasText::createGlyphs(textChunk, m_canvas, screenCTM, curx, cury, endx, endy); + + delete textChunk; +} + +void AggText::clearCurved() +{ + m_drawItems.clear(); + // TODO: Huh - nobody does anything with the *trans* objects?: +} + +void AggText::addTextDecoration(SVGTextContentElementImpl *element, double x, double y, double width, double height) const +{ + if(element->isFilled() || element->isStroked()) + { + // compute rect + BezierPathAggStroked *bpath = new BezierPathAggStroked(element); + bpath->m_storage.move_to(x, y); + bpath->m_storage.line_to(x + width, y); + bpath->m_storage.line_to(x + width, y + height); + bpath->m_storage.line_to(x, y + height); + + const SVGMatrixImpl *mat = m_text->screenCTM(); + bpath->m_transform = agg::trans_affine(mat->a(), mat->b(), mat->c(), mat->d(), mat->e(), mat->f()); + + SVPElement *svpelement = new SVPElement(); + svpelement->svp = bpath; + svpelement->element = element; + + if(element->isFilled()) + svpelement->fillPainter = new AggFillPaintServer(element); + + // Spec: A zero value causes no stroke to be painted. + if(element->isStroked() && element->getStrokeWidth()->baseVal()->value() > 0) + svpelement->strokePainter = new AggStrokePaintServer(element); + + m_drawItems.append(svpelement); + } +} + +AggText::SVPElement::~SVPElement() +{ + delete svp; + delete fillPainter; + delete strokePainter; +} + +// ### + +AggGradient::AggGradient(SVGGradientElementImpl *gradient) : m_gradient(gradient) +{ +} + +void AggGradient::parseGradientStops(SVGGradientElementImpl *gradient) +{ + bool srgb = m_gradient->getColorInterpolation() == CI_SRGB; + int r = 0, g = 0, b = 0, a = 255, r1 = 0, g1 = 0, b1 = 0, a1 = 255; + unsigned int end = 255; + float oldOffset = -1, newOffset = -1; + for(DOM::Node node = gradient->firstChild(); !node.isNull(); node = node.nextSibling()) + { + SVGStopElementImpl *elem = dynamic_cast(gradient->ownerDoc()->getElementFromHandle(node.handle())); + if(node.nodeName() == "stop" && elem) + { + oldOffset = newOffset; + newOffset = elem->offset()->baseVal(); + + // Spec: skip double offset specifications + if(oldOffset == newOffset) + continue; + + //offsets++; + + // Get color + QColor qStopColor; + + if(elem->getStopColor()->colorType() == SVG_COLORTYPE_CURRENTCOLOR) + qStopColor = elem->getColor()->rgbColor().color(); + else + qStopColor = elem->getStopColor()->rgbColor().color(); + + // Convert in an agg suitable form + QString tempName = qStopColor.name(); + const char *str = tempName.latin1(); + + // We need to take into account fill/stroke opacity, if available (Rob) + float opacity = 1.0; + SVGStylableImpl *style = dynamic_cast(getBBoxTarget()); + if(style) + opacity = style->getFillOpacity() * style->getOpacity(); + int stopColor = 0; + + for(int i = 1; str[i]; i++) + { + int hexval; + if(str[i] >= '0' && str[i] <= '9') + hexval = str[i] - '0'; + else if (str[i] >= 'A' && str[i] <= 'F') + hexval = str[i] - 'A' + 10; + else if (str[i] >= 'a' && str[i] <= 'f') + hexval = str[i] - 'a' + 10; + else + break; + + stopColor = (stopColor << 4) + hexval; + } + + // Apply stop-opacity + opacity *= elem->stopOpacity(); + + // Get rgba color including stop-opacity + Q_UINT32 rgba = (stopColor << 8) | int(floor(int(opacity * 255.0) + 0.5)); + + // Convert from separated to premultiplied alpha + a = rgba & 0xff; + r = !srgb ? linearRGBFromsRGB((rgba >> 24)) : (rgba >> 24); + g = !srgb ? linearRGBFromsRGB(((rgba >> 16) & 0xff)) : (rgba >> 16) & 0xff; + b = !srgb ? linearRGBFromsRGB(((rgba >> 8) & 0xff)) : (rgba >> 8) & 0xff; + + end = int(newOffset * 255); + // interpolate + unsigned int start = (oldOffset == -1) ? 0 : int(oldOffset * 255); + if(oldOffset == -1) + { + r1 = r; + g1 = g; + b1 = b; + a1 = a; + } + int diffr = r - r1; + int diffg = g - g1; + int diffb = b - b1; + int diffa = a - a1; + unsigned int nsteps = end - start; + for(unsigned int i = 0;i <= nsteps;i++) + { + double diff = double(i) / double(nsteps); + m_colorprofile[start + i].r = !srgb ? sRGBFromLinearRGB(int(r1 + diff * diffr)) : int(r1 + diff * diffr); + m_colorprofile[start + i].g = !srgb ? sRGBFromLinearRGB(int(g1 + diff * diffg)) : int(g1 + diff * diffg); + m_colorprofile[start + i].b = !srgb ? sRGBFromLinearRGB(int(b1 + diff * diffb)) : int(b1 + diff * diffb); + m_colorprofile[start + i].a = !srgb ? sRGBFromLinearRGB(int(a1 + diff * diffa)) : int(a1 + diff * diffa); + } + r1 = r; + g1 = g; + b1 = b; + a1 = a; + } + } + // last section + for(unsigned int i = end;i <= 255;i++) + { + m_colorprofile[i].r = r; + m_colorprofile[i].g = g; + m_colorprofile[i].b = b; + m_colorprofile[i].a = a; + } +} + +void AggGradient::finalizePaintServer() +{ + parseGradientStops(m_gradient->stopsSource()); + + QString _href = SVGURIReferenceImpl::getTarget(m_gradient->href()->baseVal().string()); + if(!_href.isEmpty()) + reference(_href); + + setFinalized(); +} + +void AggGradient::reference(const QString &/*href*/) +{ +} + +void AggLinearGradient::render(AggCanvas *c) +{ + SVGLinearGradientElementImpl *linear = dynamic_cast(m_gradient); + + linear->converter()->finalize(getBBoxTarget(), linear->ownerSVGElement(), linear->gradientUnits()->baseVal()); + + double _x1 = linear->x1()->baseVal()->value(); + double _y1 = linear->y1()->baseVal()->value(); + double _x2 = linear->x2()->baseVal()->value(); + double _y2 = linear->y2()->baseVal()->value(); + + // Adjust to gradient transform + SVGMatrixImpl *gradTrans = linear->gradientTransform()->baseVal()->concatenate(); + if(gradTrans) + { + QWMatrix m = gradTrans->qmatrix(); + m.map(_x1, _y1, &_x1, &_y1); + m.map(_x2, _y2, &_x2, &_y2); + gradTrans->deref(); + } + + // Get the basic bbox that will be the rendering area + SVGRectImpl *userBBox = getBBoxTarget()->getBBox(); + + // Compute x1, y1, x2 and y2 + bool objectbbox = (linear->gradientUnits()->baseVal() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX); + + // Respect current transformation matrix (so gradients zoom with...) + SVGTransformableImpl *transformable = dynamic_cast(getBBoxTarget()); + const SVGMatrixImpl *matrix = 0; + if(transformable) + matrix = transformable->screenCTM(); + + if(objectbbox) + { + _x1 += userBBox->x(); + _y1 += userBBox->y(); + _x2 += userBBox->x(); + _y2 += userBBox->y(); + } + + userBBox->deref(); + + gradient_polymorphic_wrapper_base* gr_ptr = &m_linPad; + if(linear->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REPEAT) + gr_ptr = &m_linRepeat; + else if(linear->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REFLECT) + gr_ptr = &m_linReflect; + + agg::trans_affine mtx_g1; + double dx = _x2 - _x1; + double dy = _y2 - _y1; + double angle = (atan2(dy, dx)); + mtx_g1 *= agg::trans_affine_rotation(angle); + mtx_g1 *= agg::trans_affine_translation(_x1, _y1); + mtx_g1 *= agg::trans_affine(matrix->a(), matrix->b(), matrix->c(), matrix->d(), matrix->e(), matrix->f()); + mtx_g1.invert(); + + double len = sqrt(dx * dx + dy * dy); + if(len > 0) + { + typedef agg::span_interpolator_linear<> interpolator_type; + typedef agg::span_gradient gradient_span_gen; + typedef agg::span_allocator gradient_span_alloc; + color_function_profile colors(m_colorprofile); + gradient_span_alloc span_alloc; + interpolator_type inter(mtx_g1); + gradient_span_gen span_gen(span_alloc, inter, *gr_ptr, colors, 0, len); + + agg::scanline_u8 sl; + + if(c->nrChannels() == 3) + { + typedef agg::pixfmt_rgb24 pixfmt; + typedef agg::renderer_base renderer_base; + typedef agg::renderer_scanline_u renderer_gradient; + + pixfmt pixf(c->buf()); + renderer_base rb(pixf); + + renderer_gradient r1(rb, span_gen); + c->m_ras.render(sl, r1); + } + else + { + typedef agg::pixfmt_rgba32 pixfmt; + typedef agg::renderer_base renderer_base; + typedef agg::renderer_scanline_u renderer_gradient; + + pixfmt pixf(c->buf()); + renderer_base rb(pixf); + + renderer_gradient r1(rb, span_gen); + c->m_ras.render(sl, r1); + } + } +} + +void AggRadialGradient::render(AggCanvas *c) +{ + SVGRadialGradientElementImpl *radial = dynamic_cast(m_gradient); + + radial->converter()->finalize(getBBoxTarget(), radial->ownerSVGElement(), radial->gradientUnits()->baseVal()); + + double _cx = radial->cx()->baseVal()->value(); + double _cy = radial->cy()->baseVal()->value(); + double _fx = radial->fx()->baseVal()->value(); + double _fy = radial->fy()->baseVal()->value(); + double _r = radial->r()->baseVal()->value(); + + // Get the basic bbox that will be the rendering area + SVGRectImpl *screenBBox = getBBoxTarget()->getBBoxInternal(); + + if(screenBBox->width() == 0 || screenBBox->height() == 0) + { + screenBBox->deref(); + return; + } + + screenBBox->deref(); + + // Compute x1, y1, x2 and y2 + bool objectbbox = (radial->gradientUnits()->baseVal() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX); + + SVGRectImpl *userBBox = getBBoxTarget()->getBBox(); + float width = userBBox->width(); + float height = userBBox->height(); + + if(objectbbox) + { + _cx += userBBox->x(); + _cy += userBBox->y(); + _fx += userBBox->x(); + _fy += userBBox->y(); + } + + gradient_polymorphic_wrapper_base* gr_ptr = &m_radialPad; + if(radial->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REPEAT) + gr_ptr = &m_radialRepeat; + else if(radial->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REFLECT) + gr_ptr = &m_radialReflect; + + agg::trans_affine mtx_g1; + + + // Adjust to gradient transform + SVGMatrixImpl *gradTrans = radial->gradientTransform()->baseVal()->concatenate(); + if(gradTrans) + { + agg::trans_affine mtx; + QWMatrix m = gradTrans->qmatrix(); + mtx = agg::trans_affine(m.m11(), m.m12(), m.m21(), m.m22(), m.dx(), m.dy()); + gradTrans->deref(); + mtx_g1 *= mtx; + } + + userBBox->deref(); + + int diff = int(width - height); // allow slight tolerance + if(objectbbox && !(diff > -2 && diff < 2)) + { + // make elliptical or circular depending on bbox aspect ratio + float ratioX = (width / height) * sqrt(2); + float ratioY = (height / width) * sqrt(2); + mtx_g1 *= agg::trans_affine_scaling((width > height) ? sqrt(2) : ratioX, (width > height) ? ratioY :sqrt(2)); + } + + mtx_g1 *= agg::trans_affine_translation(_cx, _cy); + + // Respect current transformation matrix (so gradients zoom with...) + SVGTransformableImpl *transformable = dynamic_cast(getBBoxTarget()); + const SVGMatrixImpl *matrix = 0; + if(transformable) + matrix = transformable->screenCTM(); + + if(!matrix) + return; + + mtx_g1 *= agg::trans_affine(matrix->a(), matrix->b(), matrix->c(), matrix->d(), matrix->e(), matrix->f()); + + mtx_g1.invert(); + + typedef agg::span_interpolator_linear<> interpolator_type; + typedef agg::span_gradient gradient_span_gen; + typedef agg::span_allocator gradient_span_alloc; + color_function_profile colors(m_colorprofile); + gradient_span_alloc span_alloc; + interpolator_type inter(mtx_g1); + gradient_span_gen span_gen(span_alloc, inter, *gr_ptr, colors, 0, _r); + + agg::scanline_u8 sl; + if(c->nrChannels() == 3) + { + typedef agg::pixfmt_rgb24 pixfmt; + typedef agg::renderer_base renderer_base; + typedef agg::renderer_scanline_u renderer_gradient; + + pixfmt pixf(c->buf()); + renderer_base rb(pixf); + + renderer_gradient r1(rb, span_gen); + c->m_ras.render(sl, r1); + } + else + { + typedef agg::pixfmt_rgba32 pixfmt; + typedef agg::renderer_base renderer_base; + typedef agg::renderer_scanline_u renderer_gradient; + + pixfmt pixf(c->buf()); + renderer_base rb(pixf); + + renderer_gradient r1(rb, span_gen); + c->m_ras.render(sl, r1); + } +} + +AggPattern::AggPattern(SVGPatternElementImpl *pattern) : AggPaintServer(), m_pattern(pattern) +{ +} + +void AggPattern::finalizePaintServer() +{ + m_pattern->finalizePaintServer(); + setFinalized(); +} + +void AggPattern::reference(const QString &href) +{ + m_pattern->reference(href); +} + +void AggPattern::render(AggCanvas *c) +{ + SVGPatternElementImpl::Tile tile = m_pattern->createTile(getBBoxTarget()); + + if(!tile.image().isNull()) + { + QWMatrix m = tile.screenToTile(); + double affine[6]; + + affine[0] = m.m11(); + affine[1] = m.m12(); + affine[2] = m.m21(); + affine[3] = m.m22(); + affine[4] = m.dx(); + affine[5] = m.dy(); + + typedef agg::pixfmt_rgb24 pixfmt; + typedef agg::renderer_base renderer_base; + typedef agg::renderer_scanline_p_solid renderer_solid; + + pixfmt pixf(c->buf()); + renderer_base rb(pixf); + renderer_solid rs(rb); + //double width = c->buf().width(); + //double height = c->buf().height(); + + typedef agg::span_pattern_rgba32 span_gen_type; + typedef agg::renderer_scanline_u renderer_type; + + SVGRectImpl *screenBBox = getBBoxTarget()->getBBoxInternal(); + double offset_x = affine[4]; + double offset_y = affine[5]; + screenBBox->deref(); + agg::rendering_buffer m_pattern_rbuf; + m_pattern_rbuf.attach(tile.image().bits(), tile.image().width(), tile.image().height(), tile.image().width() * 4); + agg::span_allocator sa; + span_gen_type sg(sa, m_pattern_rbuf, unsigned(offset_x), unsigned(offset_y)); + + renderer_type rp(rb, sg); + + agg::scanline_u8 sl; + rs.color(agg::rgba(0,0,0)); + c->m_ras.render(sl, rp); + } +} + +// vim:ts=4:noet diff --git a/ksvg/plugin/backends/agg/AggCanvasItems.h b/ksvg/plugin/backends/agg/AggCanvasItems.h new file mode 100644 index 00000000..a8c242ec --- /dev/null +++ b/ksvg/plugin/backends/agg/AggCanvasItems.h @@ -0,0 +1,500 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 AGGCANVASITEMS_H +#define AGGCANVASITEMS_H + +#include "CanvasItem.h" +#include "CanvasItems.h" +#include "BezierPathAgg.h" + +#include "SVGPathElementImpl.h" +#include "SVGPolyElementImpl.h" +#include "SVGLineElementImpl.h" +#include "SVGRectElementImpl.h" +#include "SVGTextElementImpl.h" +#include "SVGImageElementImpl.h" +#include "SVGCircleElementImpl.h" +#include "SVGEllipseElementImpl.h" + +#include "agg_basics.h" +#include "agg_conv_transform.h" +#include "agg_conv_curve.h" +#include "agg_conv_dash.h" +#include "agg_conv_stroke.h" +#include "agg_conv_clip_polygon.h" +#include "agg_span_gradient.h" + +#include "SVGBBoxTarget.h" + +// gradient helpers + +//------------------------------------------------------------------------ +class gradient_polymorphic_wrapper_base +{ +public: + virtual int calculate(int x, int y, int) const = 0; +}; + +template +class gradient_polymorphic_wrapper : public gradient_polymorphic_wrapper_base +{ +public: + virtual int calculate(int x, int y, int d) const + { + return m_gradient.calculate(x, y, d); + } +private: + GradientF m_gradient; +}; + +class gradient_radial_repeat +{ +public: + int calculate(int x, int y, int d) const + { + return int(sqrt(pow(x, 2) + pow(y, 2))) % d; + } +}; + +class gradient_radial_reflect +{ +public: + int calculate(int x, int y, int d) const + { + int dist = int(sqrt(pow(x, 2) + pow(y, 2))); + if((dist / d) % 2 == 0) + return dist % d; + else + return d - (dist % d); + } +}; + +class gradient_linear_repeat +{ +public: + int calculate(int x, int y, int d) const + { + return (x < 0) ? (d - (-x % d)) : (x % d); + } +}; + +class gradient_linear_reflect +{ +public: + int calculate(int x, int y, int d) const + { + if((abs(x) / d) % 2 == 0) + return (x < 0) ? (-x % d) : (x % d); + else + return (x > 0) ? (d - (x % d)) : (d - (-x % d)); + } +}; + + +#define AGG_CLASS(Class, Type, Member) \ +class Agg##Class : public AggShape \ +{ \ +public: \ + Agg##Class(AggCanvas *c, Type *Member); \ + virtual ~Agg##Class() { } \ + virtual void draw(); \ + virtual bool isVisible(); \ + virtual void init(); \ + virtual void init(const SVGMatrixImpl *screenCTM); \ + virtual SVGElementImpl *element() const { return m_##Member; } \ +protected: \ + Type *m_##Member; \ +}; + +class stroke_dash_base +{ +public: + virtual ~stroke_dash_base() {} + + virtual void rewind(unsigned) = 0; + virtual unsigned vertex(double*, double*) = 0; +}; + +template +class stroke : public stroke_dash_base +{ +public: + typedef agg::conv_stroke stroke_type; + + stroke(Source& src, KSVG::SVGStylableImpl *style); + + void rewind(unsigned id) { m_s.rewind(id); } + unsigned vertex(double* x, double* y) { return m_s.vertex(x, y); } + +private: + stroke_type m_s; +}; + +template +class dash_stroke : public stroke_dash_base +{ +public: + typedef agg::conv_dash dash_type; + typedef agg::conv_stroke dash_stroke_type; + + dash_stroke(Source& src, KSVG::SVGStylableImpl *style); + + void rewind(unsigned id) { m_ds.rewind(id); } + unsigned vertex(double* x, double* y) { return m_ds.vertex(x, y); } + +private: + dash_type m_d; + dash_stroke_type m_ds; +}; + +template +class dash_stroke_simple +{ +public: + dash_stroke_simple(Source& src, KSVG::SVGStylableImpl *style); + ~dash_stroke_simple() { delete impl; } + + void rewind(unsigned id) { impl->rewind(id); } + unsigned vertex(double* x, double* y) { return impl->vertex(x, y); } + +private: + stroke_dash_base *impl; +}; + +typedef dash_stroke_simple curved_stroked; +typedef agg::conv_transform curved_stroked_trans; +typedef agg::conv_clip_polygon curved_stroked_trans_clipped; +typedef agg::conv_clip_polygon curved_trans_clipped; +//typedef agg::conv_contour curved_trans_contour; +//typedef agg::conv_clip_polygon curved_trans_contour_clipped; + +namespace KSVG +{ + class SVGGradientElementImpl; + class SVGRadialGradientElementImpl; + class SVGLinearGradientElementImpl; + class SVGPatternElementImpl; + + class AggPaintServer : public CanvasPaintServer + { + public: + AggPaintServer() : CanvasPaintServer() {} + virtual ~AggPaintServer() {} + + virtual void finalizePaintServer() = 0; + virtual void reference(const QString &href) = 0; + + virtual void render(AggCanvas *c) = 0; + }; + + class AggGradient : public AggPaintServer + { + public: + AggGradient(SVGGradientElementImpl *gradient); + virtual ~AggGradient() {} + + void parseGradientStops(SVGGradientElementImpl *gradient); + + virtual void finalizePaintServer(); + virtual void reference(const QString &href); + + protected: + SVGGradientElementImpl *m_gradient; + agg::rgba8 m_colorprofile[256]; + }; + + class AggLinearGradient : public AggGradient + { + public: + AggLinearGradient(SVGLinearGradientElementImpl *linear) : AggGradient(linear) {} + + virtual void render(AggCanvas *c); + + protected: + gradient_polymorphic_wrapper m_linPad; + gradient_polymorphic_wrapper m_linRepeat; + gradient_polymorphic_wrapper m_linReflect; + }; + + class AggRadialGradient : public AggGradient + { + public: + AggRadialGradient(SVGRadialGradientElementImpl *radial) : AggGradient(radial) {} + + virtual void render(AggCanvas *c); + + protected: + gradient_polymorphic_wrapper m_radialPad; + gradient_polymorphic_wrapper m_radialRepeat; + gradient_polymorphic_wrapper m_radialReflect; + }; + + class AggPattern : public AggPaintServer + { + public: + AggPattern(SVGPatternElementImpl *pattern); + virtual ~AggPattern() {} + + virtual void finalizePaintServer(); + virtual void reference(const QString &); + + virtual void render(AggCanvas *c); + + protected: + SVGPatternElementImpl *m_pattern; + }; + + class AggCanvas; + + class AggFillPaintServer + { + public: + AggFillPaintServer(SVGStylableImpl *style); + void update(SVGStylableImpl *style); + template + void draw(AggCanvas *canvas, VertexSource &vs, SVGStylableImpl *style, SVGShapeImpl *shape); + + private: + agg::rgba8 m_color; + }; + + class AggStrokePaintServer + { + public: + AggStrokePaintServer(SVGStylableImpl *style); + void update(SVGStylableImpl *style); + template + void draw(AggCanvas *canvas, VertexSource &vs, SVGStylableImpl *style, SVGShapeImpl *shape); + + private: + agg::rgba8 m_color; + }; + + class BezierPathAggStroked : public T2P::BezierPathAgg + { + public: + BezierPathAggStroked(SVGStylableImpl *style); + BezierPathAggStroked(const T2P::BezierPathAgg &other, SVGStylableImpl *style); + + curved_trans_clipped m_curved_trans_clipped; + curved_stroked m_curved_stroked; + curved_stroked_trans m_curved_stroked_trans; + curved_stroked_trans_clipped m_curved_stroked_trans_clipped; + SVGStylableImpl *m_style; + }; + + class AggShape : public CanvasItem, public BezierPathAggStroked + { + public: + AggShape(AggCanvas *c, SVGStylableImpl *style); + virtual ~AggShape(); + + virtual QRect bbox() const; + virtual bool fillContains(const QPoint &p); + virtual bool strokeContains(const QPoint &p); + virtual void update(CanvasItemUpdate reason, int param1 = 0, int param2 = 0); + void draw(SVGShapeImpl *shape); + void calcSVPs(const SVGMatrixImpl *matrix); + virtual void init(); + virtual void init(const SVGMatrixImpl *); + bool isVisible(SVGShapeImpl *shape); + + void setRenderContext(RenderContext context) { m_context = context; } + + agg::path_storage &storage() { return m_storage; } + agg::trans_affine &transform() { return m_transform; } + + protected: + void freeSVPs(); + + RenderContext m_context; + AggCanvas *m_canvas; + QRect m_bbox; + AggFillPaintServer *m_fillPainter; + AggStrokePaintServer *m_strokePainter; + }; + + AGG_CLASS(Rectangle, SVGRectElementImpl, rect) + AGG_CLASS(Ellipse, SVGEllipseElementImpl, ellipse) + AGG_CLASS(Circle, SVGCircleElementImpl, circle) + + class AggLine : public AggShape, public MarkerHelper + { + public: + AggLine(AggCanvas *c, SVGLineElementImpl *line); + virtual ~AggLine(); + + virtual void draw(); + virtual bool isVisible(); + virtual void init(); + virtual void init(const SVGMatrixImpl *screenCTM); + + virtual SVGElementImpl *element() const { return m_line; } + + protected: + SVGLineElementImpl *m_line; + }; + + class AggPoly : public AggShape, public MarkerHelper + { + public: + AggPoly(AggCanvas *c, SVGPolyElementImpl *poly); + virtual ~AggPoly(); + + virtual void draw(); + virtual bool isVisible(); + virtual void init(); + virtual void init(const SVGMatrixImpl *screenCTM) = 0; + + virtual SVGElementImpl *element() const { return m_poly; } + + protected: + SVGPolyElementImpl *m_poly; + + }; + class AggPolyline : public AggPoly + { + public: + AggPolyline(AggCanvas *c, SVGPolylineElementImpl *poly); + virtual ~AggPolyline(); + + virtual void init(const SVGMatrixImpl *screenCTM); + }; + + class AggPolygon : public AggPoly + { + public: + AggPolygon(AggCanvas *c, SVGPolygonElementImpl *poly); + virtual ~AggPolygon(); + + virtual void init(const SVGMatrixImpl *screenCTM); + }; + + class AggPath : public AggShape, public ::SVGPathParser, public MarkerHelper + { + public: + AggPath(AggCanvas *c, SVGPathElementImpl *path); + virtual ~AggPath(); + + virtual void draw(); + virtual bool isVisible(); + virtual void init(); + virtual void init(const SVGMatrixImpl *screenCTM); + + virtual SVGElementImpl *element() const { return m_path; } + + protected: + SVGPathElementImpl *m_path; + + virtual void svgMoveTo(double x1, double y1, bool closed, 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(); + }; + + class AggMarker : public CanvasMarker + { + public: + AggMarker(AggCanvas *c, SVGMarkerElementImpl *marker); + virtual ~AggMarker(); + + virtual QRect bbox() const { return QRect(); } + virtual bool fillContains(const QPoint &) { return true; } + virtual bool strokeContains(const QPoint &) { return true; } + virtual void update(CanvasItemUpdate, int = 0, int = 0) { } + virtual void init(); + virtual void draw(); + virtual bool isVisible() { return false; } + + void draw(SVGShapeImpl *obj, int x, int y, float lwidth = 1.0, double angle = 0.0); + //const ArtSVP *clippingRectangle() const { return m_clippingRectangle; } + + protected: + AggCanvas *m_canvas; + //ArtSVP *m_clippingRectangle; + }; + + class AggImage : public CanvasItem + { + public: + AggImage(AggCanvas *c, SVGImageElementImpl *image); + virtual ~AggImage(); + + virtual QRect bbox() const; + virtual bool fillContains(const QPoint &) { return true; } + virtual bool strokeContains(const QPoint &) { return true; } + virtual void update(CanvasItemUpdate, int = 0, int = 0) { } + virtual void init(); + virtual void draw(); + virtual bool isVisible(); + + virtual SVGElementImpl *element() const { return m_image; } + + protected: + AggCanvas *m_canvas; + SVGImageElementImpl *m_image; + }; + + class AggText : public CanvasText + { + public: + AggText(AggCanvas *c, SVGTextElementImpl *text); + virtual ~AggText(); + + virtual QRect bbox() const; + virtual bool fillContains(const QPoint &p); + virtual bool strokeContains(const QPoint &p); + virtual void update(CanvasItemUpdate, int param1 = 0, int param2 = 0); + virtual void draw(); + virtual bool isVisible(); + virtual void init(); + virtual void init(const SVGMatrixImpl *screenCTM); + + virtual void renderCallback(SVGTextContentElementImpl *element, const SVGMatrixImpl *screenCTM, T2P::GlyphSet *glyph, T2P::GlyphLayoutParams *params, double anchor) const; + + virtual void addTextDecoration(SVGTextContentElementImpl *element, double x, double y, double w, double h) const; + + unsigned operator [](unsigned) const { return 0; } + + protected: + AggCanvas *m_canvas; + + private: + void clearCurved(); + class SVPElement + { + public: + SVPElement() { svp = 0; element = 0; fillPainter = 0; strokePainter = 0; } + ~SVPElement(); + + BezierPathAggStroked *svp; + SVGTextContentElementImpl *element; + AggFillPaintServer *fillPainter; + AggStrokePaintServer *strokePainter; + }; + + mutable QPtrList m_drawItems; + }; +}; + +#endif + +// vim:ts=4:noet diff --git a/ksvg/plugin/backends/agg/BezierPathAgg.cpp b/ksvg/plugin/backends/agg/BezierPathAgg.cpp new file mode 100644 index 00000000..10a75c1c --- /dev/null +++ b/ksvg/plugin/backends/agg/BezierPathAgg.cpp @@ -0,0 +1,126 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 +#include "Point.h" +#include "BezierPathAgg.h" + +#include + +#include +#include + +using namespace T2P; + +double BezierPathAgg::length(double t) +{ + if(m_length < 0.0) + { + double total = 0.0; + double x = 0.0, y = 0.0; + double x2, y2; + unsigned cmd; + unsigned int id = 0; + m_curved_trans.rewind(id); + while(!agg::is_stop(cmd = m_curved_trans.vertex(&x2, &y2))) + { + if(agg::is_move_to(cmd)) + { + x = x2; + y = y2; + } + else if(agg::is_line_to(cmd)) + { + double dx = x, dy = y; + dx = x2 - dx; + dy = y2 - dy; + total += sqrt(pow(dx, 2) + pow(dy, 2)); + x = x2; + y = y2; + } + } + return total * t; + } + else + return m_length * t; +} + +void BezierPathAgg::pointTangentNormalAt(double t, Point *p, Point *tn, Point *n) +{ + double totallen = length(t); + double total = 0.0; + double x = 0.0, y = 0.0; + double x2, y2; + unsigned cmd; + unsigned int id = 0; + m_curved_trans.rewind(id); + while(!agg::is_stop(cmd = m_curved_trans.vertex(&x2, &y2))) + { + if(agg::is_move_to(cmd)) + { + x = x2; + y = y2; + } + else if(agg::is_line_to(cmd)) + { + double dx = x, dy = y; + x = x2; + y = y2; + dx = x - dx; + dy = y - dy; + double seg_len = sqrt(pow(dx, 2) + pow(dy, 2)); + total += seg_len; + if(total >= totallen) + { + double fract = 1 - (totallen - (total - seg_len)) / seg_len; + if(p) + { + p->setX(x - dx * fract); + p->setY(y - dy * fract); + } + if(tn) + { + //kdDebug() << k_funcinfo << "dx : " << dx << endl; + //kdDebug() << k_funcinfo << "dy : " << dy << endl; + tn->setX(dx); + tn->setY(dy); + } + if(n) + { + // Calculate vector product of "binormal" x tangent + // (0,0,1) x (dx,dy,0), which is simply (dy,-dx,0). + n->setX(dy); + n->setY(-dx); + } + return; + } + } + } +} + +void BezierPathAgg::boundingBox(Point *topLeft, Point *bottomRight) +{ + double x1, y1, x2, y2; + agg::bounding_rect(m_curved, *this, 0, 1, &x1, &y1, &x2, &y2); + *topLeft = Point(x1, y1); + *bottomRight = Point(x2, y2); +} + +// vim:ts=4:noet diff --git a/ksvg/plugin/backends/agg/BezierPathAgg.h b/ksvg/plugin/backends/agg/BezierPathAgg.h new file mode 100644 index 00000000..21451aa9 --- /dev/null +++ b/ksvg/plugin/backends/agg/BezierPathAgg.h @@ -0,0 +1,83 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 T2P_BEZIERPATH_AGG_H +#define T2P_BEZIERPATH_AGG_H + +#include +#include +#include +#include +#include + +#include "Affine.h" +#include "BezierPath.h" + +typedef agg::conv_curve curved; +typedef agg::conv_transform curved_trans; + +namespace T2P +{ + class BezierPathAgg : public BezierPath + { + public: + BezierPathAgg() : BezierPath(), + m_curved(m_storage), m_curved_trans(m_curved, m_transform) + { + m_length = -1; + } + + ~BezierPathAgg() {} + + BezierPathAgg(const BezierPathAgg &other) : BezierPath(), m_storage(other.m_storage), + m_curved(m_storage), m_curved_trans(m_curved, m_transform) + { + m_transform = other.m_transform; + m_length = other.m_length; + } + + void copy_from(const agg::path_storage &ps, Affine &affine) + { + for(unsigned i = 0; i < ps.total_vertices(); i++) + { + double x, y; + unsigned cmd = ps.vertex(i, &x, &y); + m_storage.add_vertex(affine.dx() + x * affine.m11() + y * affine.m21(), + affine.dy() + x * affine.m12() + y * affine.m22(), cmd); + } + } + + unsigned operator [](unsigned) { return 0; } + + virtual double length(double t = 1.0); + virtual void pointTangentNormalAt(double t, Point *p = 0, Point *tn = 0, Point *n = 0); + virtual void boundingBox(Point *topLeft, Point *bottomRight); + + agg::path_storage m_storage; + curved m_curved; + curved_trans m_curved_trans; + agg::trans_affine m_transform; + double m_length; + }; +}; + +#endif + +// vim:ts=4:noet diff --git a/ksvg/plugin/backends/agg/GlyphTracerAgg.cpp b/ksvg/plugin/backends/agg/GlyphTracerAgg.cpp new file mode 100644 index 00000000..39b00146 --- /dev/null +++ b/ksvg/plugin/backends/agg/GlyphTracerAgg.cpp @@ -0,0 +1,113 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 + +#include "Glyph.h" +#include "Point.h" +#include "BezierPathAgg.h" +#include "GlyphTracerAgg.h" + +using namespace T2P; + +int traceMoveto(FT_Vector *to, void *obj) +{ + Glyph *glyph = reinterpret_cast(obj); + Affine &affine = glyph->affine(); + BezierPathAgg *bpath = static_cast(glyph->modifiableBezierPath()); + Point p = affine.mapPoint(Point(to->x, to->y)); + bpath->m_storage.move_to(p.x(), p.y()); + return 0; +} + +int traceLineto(FT_Vector *to, void *obj) +{ + Glyph *glyph = reinterpret_cast(obj); + Affine &affine = glyph->affine(); + BezierPathAgg *bpath = static_cast(glyph->modifiableBezierPath()); + Point p = affine.mapPoint(Point(to->x, to->y)); + bpath->m_storage.line_to(p.x(), p.y()); + return 0; +} + +int traceConicBezier(FT_Vector *control, FT_Vector *to, void *obj) +{ + Glyph *glyph = reinterpret_cast(obj); + Affine &affine = glyph->affine(); + BezierPathAgg *bpath = static_cast(glyph->modifiableBezierPath()); + Point c = affine.mapPoint(Point(control->x, control->y)); + Point p = affine.mapPoint(Point(to->x, to->y)); + + double sx, sy; + bpath->m_storage.vertex(bpath->m_storage.total_vertices() - 1, &sx, &sy); + bpath->m_storage.curve4(c.x() - (c.x() - sx) / 3, c.y() - (c.y() - sy) / 3, + c.x() + (p.x() - c.x()) / 3, c.y() + (p.y() - c.y()) / 3, p.x(), p.y()); + + return 0; +} + +int traceCubicBezier(FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *obj) +{ + Glyph *glyph = reinterpret_cast(obj); + Affine &affine = glyph->affine(); + BezierPathAgg *bpath = static_cast(glyph->modifiableBezierPath()); + Point p = affine.mapPoint(Point(to->x, to->y)); + Point c1 = affine.mapPoint(Point(control1->x, control1->y)); + Point c2 = affine.mapPoint(Point(control2->x, control2->y)); + bpath->m_storage.curve4(c1.x(), c1.y(), c2.x(), c2.y(), p.x(), p.y()); + return 0; +} + +GlyphTracerAgg::GlyphTracerAgg() : GlyphTracer() +{ + setMoveto(*traceMoveto); + setLineto(*traceLineto); + setConicBezier(*traceConicBezier); + setCubicBezier(*traceCubicBezier); +} + +GlyphTracerAgg::~GlyphTracerAgg() +{ +} + +void GlyphTracerAgg::correctGlyph(GlyphAffinePair *glyphAffine) +{ + + // Take bezier path belonging to glyph (Note: that one is _UNMODIFIABLE_, once calculated) + const BezierPathAgg *path = static_cast(glyphAffine->glyph()->bezierPath()); + + BezierPathAgg *transformatedPath = static_cast(allocBezierPath(0)); + Affine &affine = glyphAffine->affine(); + transformatedPath->copy_from(path->m_storage, affine); + glyphAffine->setTransformatedPath(transformatedPath); +} + +BezierPath *GlyphTracerAgg::allocBezierPath(int) +{ + return new BezierPathAgg(); +} + +void GlyphTracerAgg::closePath(Glyph *glyph) +{ + BezierPathAgg *bpath = static_cast(glyph->modifiableBezierPath()); + bpath->m_storage.close_polygon(); +} + +// vim:ts=4:noet diff --git a/ksvg/plugin/backends/agg/GlyphTracerAgg.h b/ksvg/plugin/backends/agg/GlyphTracerAgg.h new file mode 100644 index 00000000..5fb24d4b --- /dev/null +++ b/ksvg/plugin/backends/agg/GlyphTracerAgg.h @@ -0,0 +1,49 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 T2P_GLYPHTRACER_AGG_H +#define T2P_GLYPHTRACER_AGG_H + +#include "GlyphTracer.h" + +// FreeType 2 includes +#include +#include FT_FREETYPE_H + +namespace T2P +{ + class Glyph; + class BezierPath; + + class GlyphTracerAgg : public GlyphTracer + { + public: + GlyphTracerAgg(); + ~GlyphTracerAgg(); + + virtual void correctGlyph(GlyphAffinePair *glyphAffine); + virtual BezierPath *allocBezierPath(int size); + virtual void closePath(Glyph *glyph); + }; +}; + +#endif + +// vim:ts=4:noet diff --git a/ksvg/plugin/backends/agg/Makefile.am b/ksvg/plugin/backends/agg/Makefile.am new file mode 100644 index 00000000..4e883809 --- /dev/null +++ b/ksvg/plugin/backends/agg/Makefile.am @@ -0,0 +1,15 @@ +kde_module_LTLIBRARIES = libksvgrendereragg.la + +# Damn agg2 has no configuration querying possibility! +AGG_CFLAGS = -I/cvs/agg2/include/ +AGG_LIBS = /cvs/agg2/src/libagg.a + +libksvgrendereragg_la_SOURCES = BezierPathAgg.cpp GlyphTracerAgg.cpp AggCanvas.cpp AggCanvasItems.cpp AggCanvasFactory.cpp +libksvgrendereragg_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +libksvgrendereragg_la_LIBADD = ../../../libksvg.la $(AGG_LIBS) +libksvgrendereragg_la_METASOURCES = AUTO + +kde_services_DATA = ksvgaggcanvas.desktop + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) +INCLUDES = $(KDE_INCLUDES) $(AGG_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) -I$(top_srcdir)/ksvg/dom -I$(top_srcdir)/ksvg/impl -I$(top_srcdir)/ksvg/ecma -I$(top_srcdir)/ksvg/core -I$(top_srcdir)/ksvg/impl/libs/art_support -I$(top_srcdir)/ksvg/impl/libs/libtext2path/src $(all_includes) diff --git a/ksvg/plugin/backends/agg/ksvgaggcanvas.desktop b/ksvg/plugin/backends/agg/ksvgaggcanvas.desktop new file mode 100644 index 00000000..ac51836b --- /dev/null +++ b/ksvg/plugin/backends/agg/ksvgaggcanvas.desktop @@ -0,0 +1,101 @@ +[Desktop Entry] +Type=Service +ServiceTypes=KSVG/Renderer +X-KDE-Library=libksvgrendereragg +X-KSVG-InternalName=agg +Name=KSVG Rendering Backend - Anti Grain Geometry +Name[ar]=خلفية رسم ل KSVG - هندسة Anti Grain +Name[bs]=KSVG renderiranje - Anti Grain Geometry +Name[ca]=Representació en segon pla de KSVG - Geometria anti gra +Name[cs]=Vykreslovací nástroj KSVG - Anti Grain Geometry +Name[cy]=Ôl-wyneb Llunio KSVG - Geometreg Wrth-Raen +Name[da]=Underliggende program for KSVG-visning - antikorn geometri +Name[de]=KSVG-Darstellungsmodul - Antikörnungs-Geometrie +Name[el]= Σύστημα υποστήριξης αποτύπωσης του KSVG - Anti Grain Geometry +Name[es]=Motor de procesado de KSVG - Geometría suavizada +Name[et]=KSVG renderdamise taustarakendus - teralisusevastane geomeetria (AGG) +Name[eu]=KSVG errendatze programa - Anti Grain geometriarekin +Name[fa]=پایانۀ پشتیبانی پرداخت KSVG - هندسۀ ضد ذره +Name[fi]=KSVG-piirtäjän taustaohjelma - sileä geometria +Name[fr]=Moteur de rendu KSVG - Anti Grain Geometry +Name[gl]=Mecanismo de Interpretación KSVG - Xeometría Anti-gran +Name[he]=מנוע רינדור KSVG +Name[hi]=के-एसवीजी रेंडरिंग बैकएण्ड- एन्टी ग्रेन ज्यामिती +Name[hu]=KSVG megjelenítő motor - AGG (Anti Grain Geometry) +Name[is]=KSVG teiknari - Anti Grain Geometry +Name[it]=Backend KSVG per il rendering - Geometrie senza sgranature +Name[ja]=KSVG レンダリングバックエンド - Anti Grain Geometry +Name[kk]=KSVG кескіндеу бағдарламасы - қиыршықтыққа қарсы геометриясы +Name[km]=កម្មវិធី​សម្រាប់​បង្ហាញ KSVG - រាង​មិន​គ្រើម +Name[lt]=KSVG atkūrimo programinė sąsaja - Anti Grain geometrija +Name[ms]=Tepi Belakang KSVG - Geometri Anti Bijian +Name[nb]=Modul for KSVG-tegning – antikorngeometri +Name[nds]=KSVG-Dorstellhölper - Antigrissel-Geometrie +Name[ne]=KSVG रेन्डरिङ ब्याकइन्ड - एन्टि ग्रेन ज्योमेट्रि +Name[nl]=KSVG weergavecomponent - Anti Grain Geometry +Name[nn]=Modul for KSVG-teikning – antikorngeometri +Name[pl]=Narzędzie do renderowania KSVG - nieziarnista geometria +Name[pt]=Infra-Estrutura de Desenho do KSVG - Geometria Anti-Grão +Name[pt_BR]=Estrutura de Renderização do KSVG - Geometria Anti-Grain +Name[ro]=Motor de randare KSVG - Anti Grain Geometry +Name[ru]=Движок отрисовки KSVG - противозернистая геометрия +Name[sk]=Nástroj pre zobrazovanie KSVG - antigranularitná geometria +Name[sl]=Izrisovalnik KSVG - Protizrnska geometrija +Name[sr]=KSVG-ов позадински систем за рендеровање — Противзрнаста геометрија +Name[sr@Latn]=KSVG-ov pozadinski sistem za renderovanje — Protivzrnasta geometrija +Name[sv]=KSVG-uppritningsmodul - geometri mot korninghet +Name[ta]=KSVG வழங்கும் பின் அமைப்பு - ஆன்டி க்ரேன் ஜியோமெட்ரி +Name[tg]=Лағжандаи тасовироти KSVG - геометрияи мутақобили гандумӣ +Name[tr]=KSVG Derleme Aracı - Taneciksiz Geometri +Name[uk]=Інтерфейс відтворення KSVG - AGG +Name[zh_CN]=KSVG 渲染后端 - 反增长几何形状 +Name[zh_HK]=KSVG 合成後端 - Anti Grain Geometry +Name[zh_TW]=KSVG 上色後端介面 - Anti Grain Geometry +Comment=New, unstable ksvg rendering backend +Comment[bs]=Novi, nestabilni ksvg renderiranje backend +Comment[ca]=Nou, inestable representador en segon pla de ksvg +Comment[cs]=Nový, nestabilní vykreslovací nástroj KSVG +Comment[cy]=Ôl-wyneb llunio ksvg newydd, ansad +Comment[da]=Nyt, ustabilt underliggende program til ksvg-visning +Comment[de]=Neues, unausgereiftes KSVG-Darstellungsmodul +Comment[el]=Νέο υπό ανάπτυξη σύστημα υποστήριξης αποτύπωσης +Comment[es]=Nuevo motor de procesado de ksvg, inestable +Comment[et]=Uus ebastabiilne ksvg renderdamise taustarakendus +Comment[eu]=Berria, ksvg errendatze programa ezegonkorra +Comment[fa]=جدید، پایانۀ پشتیبانی ناپایدار پرداخت ksvg +Comment[fi]=Uusi epävakaa ksvg-piirtäjän taustaohjelma +Comment[fr]=Nouveau moteur de rendu KSVG instable +Comment[gl]=Novo e inestábel mecanismo de interpretación ksvg +Comment[he]=חדש, מנוע רינדור לא יציב עבור KSVG +Comment[hi]=नया, अस्थिर के-एसवीजी रेंडरिंग बैकएण्ड +Comment[hu]=Új, még nem teljesen kiforrott megjelenítőmotor a KSVG-hez +Comment[is]=Nýr og óstöðugur ksvg teiknari +Comment[it]=Nuovo, instabile backend di KSVG per il rendering +Comment[ja]=新しく、まだ開発途上の ksvg レンダリングバックエンド +Comment[kk]=Жаңа, әлі тұрақсыз KSVG кескіндеу бағдарламасы +Comment[km]=កម្មវិធី​សម្រាប់​បង្ហាញ ksvg ថ្មី​តែ​មិន​សូវ​ឋិតថេរ +Comment[lt]=Nauja, nestabili ksvg atkūrimo programinė sąsaja +Comment[ms]=Tepi Belakang Menrealisasi ksvg yang baru dan tidak stabil +Comment[nb]=Ny og ustabil modul for ksvg-tegning +Comment[nds]=Nieg, nich stevig KSVG-Dorstellhölper +Comment[ne]=नयाँ, अस्थिर ksvg रेन्डरिङ ब्याकइन्ड +Comment[nl]=Nieuwe, niet stabiele KSVG weergavecomponent +Comment[nn]=Ny og ustabil modul for ksvg-teikning +Comment[pl]=Nowe, niestabilne, narzędzie do renderowania KSVG +Comment[pt]=Uma infra-estrutura de desenho do ksvg, nova e instável +Comment[pt_BR]=Nova e instável estrutura de renderização do ksvg +Comment[ro]=Motor de randare KSVG nou, netestat suficient +Comment[ru]=Новый, нестабильный движок прорисовки ksvg +Comment[sk]=Nová, nestabilná verzia nástroja pre zobrazovanie ksvg +Comment[sl]=Nov, nestabilen izrisovalnik KSVG +Comment[sr]=Нов, нестабилан KSVG-ов позадински систем за рендеровање +Comment[sr@Latn]=Nov, nestabilan KSVG-ov pozadinski sistem za renderovanje +Comment[sv]=Ny, instabil KSVG-uppritningsmodul +Comment[ta]=புதிய, நிலையில்லாத ksvg வழங்கும் பின் அமைப்பு +Comment[tg]=Лағжандаи ғайриустувори тасовироти ksvg-и нав +Comment[tr]=Yeni, stabil olmayan ksvg derleme aracı +Comment[uk]=Новий, нестабільний інтерфейс відтворення KSVG +Comment[zh_CN]=新的不稳定的 ksvg 渲染后端 +Comment[zh_HK]=新但不穩定的 ksvg 合成後端 +Comment[zh_TW]=新的,不穩定的 ksvg 上色後端介面 +author=Rob Buis diff --git a/ksvg/plugin/backends/libart/BezierPathLibart.cpp b/ksvg/plugin/backends/libart/BezierPathLibart.cpp new file mode 100644 index 00000000..fb163952 --- /dev/null +++ b/ksvg/plugin/backends/libart/BezierPathLibart.cpp @@ -0,0 +1,160 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 +#include "Point.h" +#include "BezierPathLibart.h" + +#include + +#include +#include +#include + +using namespace T2P; + +BezierPathLibart::BezierPathLibart() : BezierPath() +{ + m_array.resize(0); + m_length = -1; +} + +BezierPathLibart::BezierPathLibart(ArtBpath *other) : BezierPath() +{ + int i = 0; + for(;other[i].code != ART_END; i++) + { + ensureSpace(m_array, i) + m_array[i] = other[i]; + } + ensureSpace(m_array, i) + m_array[i].code = ART_END; +} + +BezierPathLibart::~BezierPathLibart() +{ +} + +double BezierPathLibart::length(double t) +{ + if(m_length < 0.0) + { + double total = 0.0; + // We cheat a bit... + ArtVpath *vpath = art_bez_path_to_vec(m_array.data(), 0.25); + double x = 0.0, y = 0.0; + for(int i = 0; vpath[i].code != ART_END; i++) + { + if(vpath[i].code == ART_MOVETO) + { + x = vpath[i].x; + y = vpath[i].y; + } + else if(vpath[i].code == ART_LINETO) + { + double dx = x, dy = y; + x = vpath[i].x; + y = vpath[i].y; + dx = x - dx; + dy = y - dy; + total += sqrt(pow(dx, 2) + pow(dy, 2)); + } + } + art_free(vpath); + return total * t; + } + else + return m_length * t; +} + +void BezierPathLibart::pointTangentNormalAt(double t, Point *p, Point *tn, Point *n) +{ + double totallen = length(t); + // We cheat a bit... + ArtVpath *vpath = art_bez_path_to_vec(m_array.data(), 0.25); + double total = 0.0; + double x = 0.0, y = 0.0; + for(int i = 0; vpath[i].code != ART_END; i++) + { + if(vpath[i].code == ART_MOVETO) + { + x = vpath[i].x; + y = vpath[i].y; + } + else if(vpath[i].code == ART_LINETO) + { + double dx = x, dy = y; + x = vpath[i].x; + y = vpath[i].y; + dx = x - dx; + dy = y - dy; + double seg_len = sqrt(pow(dx, 2) + pow(dy, 2)); + total += seg_len; + if(total >= totallen) + { + double fract = 1 - (totallen - (total - seg_len)) / seg_len; + if(p) + { + p->setX(x - dx * fract); + p->setY(y - dy * fract); + } + // Calculate tangent + if(tn) + { + tn->setX(dx); + tn->setY(dy); + } + // 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(dy); + n->setY(-dx); + } + return; + } + } + } + art_free(vpath); +} + +void BezierPathLibart::boundingBox(Point *topLeft, Point *bottomRight) +{ + if(m_array.count() > 0) + { + // We cheat a bit... + ArtVpath *vpath = art_bez_path_to_vec(m_array.data(), 0.25); + + ArtDRect rect; + art_vpath_bbox_drect(vpath, &rect); + art_free(vpath); + + *topLeft = Point(rect.x0, rect.y0); + *bottomRight = Point(rect.x1, rect.y1); + } + else + { + *topLeft = Point(0, 0); + *bottomRight = Point(0, 0); + } +} + +// vim:ts=4:noet diff --git a/ksvg/plugin/backends/libart/BezierPathLibart.h b/ksvg/plugin/backends/libart/BezierPathLibart.h new file mode 100644 index 00000000..a6dfd2b9 --- /dev/null +++ b/ksvg/plugin/backends/libart/BezierPathLibart.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 T2P_BEZIERPATH_LIBART_H +#define T2P_BEZIERPATH_LIBART_H + +#include "BezierPath.h" +#include + +class _ArtBpath; + +#define ensureSpace(vec, index) if((int)vec.size() == index) vec.resize(index + 1); + +namespace T2P +{ + class BezierPathLibart : public BezierPath + { + public: + BezierPathLibart(); + BezierPathLibart(_ArtBpath *other); + ~BezierPathLibart(); + + virtual double length(double t = 1.0); + virtual void pointTangentNormalAt(double t, Point *p = 0, Point *tn = 0, Point *n = 0); + virtual void boundingBox(Point *topLeft, Point *bottomRight); + + // Don't make those private members, these are all internal anyway... + QMemArray<_ArtBpath> m_array; + double m_length; + }; +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/plugin/backends/libart/GlyphTracerLibart.cpp b/ksvg/plugin/backends/libart/GlyphTracerLibart.cpp new file mode 100644 index 00000000..b034c6e6 --- /dev/null +++ b/ksvg/plugin/backends/libart/GlyphTracerLibart.cpp @@ -0,0 +1,177 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 + +#include + +#include "Glyph.h" +#include "Point.h" +#include "BezierPathLibart.h" +#include "GlyphTracerLibart.h" + +#include + +#include + +#ifdef HAVE_FREETYPE_2_2_x + #define FT_VECTOR_PARAMETER const FT_Vector +#else + #define FT_VECTOR_PARAMETER FT_Vector +#endif + +using namespace T2P; + +int traceMoveto(FT_VECTOR_PARAMETER *to, void *obj) +{ + Glyph *glyph = reinterpret_cast(obj); + Affine &affine = glyph->affine(); + BezierPathLibart *path = static_cast(glyph->modifiableBezierPath()); + Point p = affine.mapPoint(Point(to->x, to->y)); + + int index = path->m_array.count(); + if(index == 0 || + p.x() != path->m_array[index - 1].x3 || + p.y() != path->m_array[index - 1].y3) + { + path->m_array.resize(index + 1); + path->m_array[index].code = ART_MOVETO; + path->m_array[index].x3 = p.x(); + path->m_array[index].y3 = p.y(); + } + + return 0; +} + +int traceLineto(FT_VECTOR_PARAMETER *to, void *obj) +{ + Glyph *glyph = reinterpret_cast(obj); + Affine &affine = glyph->affine(); + BezierPathLibart *path = static_cast(glyph->modifiableBezierPath()); + Point p = affine.mapPoint(Point(to->x, to->y)); + + int index = path->m_array.count(); + ArtBpath *last = &path->m_array[index - 1]; + + if((p.x() != last->x3) || (p.y() != last->y3)) + { + path->m_array.resize(index + 1); + path->m_array[index].code = ART_LINETO; + path->m_array[index].x3 = p.x(); + path->m_array[index].y3 = p.y(); + } + + return 0; +} + +int traceConicBezier(FT_VECTOR_PARAMETER *control, FT_VECTOR_PARAMETER *to, void *obj) +{ + Glyph *glyph = reinterpret_cast(obj); + Affine &affine = glyph->affine(); + BezierPathLibart *path = static_cast(glyph->modifiableBezierPath()); + + int index = path->m_array.count(); + if(!(index > 0)) + return -1; + + path->m_array.resize(index + 1); + ArtBpath *s = &path->m_array[index - 1]; + ArtBpath *e = &path->m_array[index]; + + e->code = ART_CURVETO; + + Point c = affine.mapPoint(Point(control->x, control->y)); + Point p = affine.mapPoint(Point(to->x, to->y)); + e->x3 = p.x(); + e->y3 = p.y(); + + path->m_array[index].x1 = c.x() - (c.x() - s->x3) / 3; + path->m_array[index].y1 = c.y() - (c.y() - s->y3) / 3; + path->m_array[index].x2 = c.x() + (e->x3 - c.x()) / 3; + path->m_array[index].y2 = c.y() + (e->y3 - c.y()) / 3; + + return 0; +} + +int traceCubicBezier(FT_VECTOR_PARAMETER *control1, FT_VECTOR_PARAMETER *control2, FT_VECTOR_PARAMETER *to, void *obj) +{ + Glyph *glyph = reinterpret_cast(obj); + Affine &affine = glyph->affine(); + BezierPathLibart *path = static_cast(glyph->modifiableBezierPath()); + + Point p = affine.mapPoint(Point(to->x, to->y)); + Point c1 = affine.mapPoint(Point(control1->x, control1->y)); + Point c2 = affine.mapPoint(Point(control2->x, control2->y)); + + int index = path->m_array.count(); + path->m_array.resize(index + 1); + path->m_array[index].code = ART_CURVETO; + path->m_array[index].x1 = c1.x(); + path->m_array[index].y1 = c1.y(); + path->m_array[index].x2 = c2.x(); + path->m_array[index].y2 = c2.y(); + path->m_array[index].x3 = p.x(); + path->m_array[index].y3 = p.y(); + + return 0; +} + +GlyphTracerLibart::GlyphTracerLibart() : GlyphTracer() +{ + setMoveto(*traceMoveto); + setLineto(*traceLineto); + setConicBezier(*traceConicBezier); + setCubicBezier(*traceCubicBezier); +} + +GlyphTracerLibart::~GlyphTracerLibart() +{ +} + +void GlyphTracerLibart::correctGlyph(GlyphAffinePair *glyphAffine) +{ + // Take bezier path belonging to glyph (Note: that one is _UNMODIFIABLE_, once calculated) + const BezierPathLibart *path = static_cast(glyphAffine->glyph()->bezierPath()); + + // Create a new empty path with the same size + ArtBpath *transformed = art_bpath_affine_transform(path->m_array.data(), glyphAffine->affine().data()); + BezierPathLibart *transformatedPath = new BezierPathLibart(transformed); + art_free(transformed); + glyphAffine->setTransformatedPath(transformatedPath); +} + +BezierPath *GlyphTracerLibart::allocBezierPath(int) +{ + BezierPathLibart *bpath = new BezierPathLibart(); + //if(size != 0) + // bpath->m_array.resize(size); + + return bpath; +} + +void GlyphTracerLibart::closePath(Glyph *glyph) +{ + BezierPathLibart *path = static_cast(glyph->modifiableBezierPath()); + int index = path->m_array.count(); + path->m_array.resize(index + 1); + path->m_array[index].code = ART_END; +} + +// vim:ts=4:noet diff --git a/ksvg/plugin/backends/libart/GlyphTracerLibart.h b/ksvg/plugin/backends/libart/GlyphTracerLibart.h new file mode 100644 index 00000000..39b87490 --- /dev/null +++ b/ksvg/plugin/backends/libart/GlyphTracerLibart.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2003 Nikolas Zimmermann + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 T2P_GLYPHTRACER_LIBART_H +#define T2P_GLYPHTRACER_LIBART_H + +#include "GlyphTracer.h" + +// FreeType 2 includes +#include +#include FT_FREETYPE_H + +namespace T2P +{ + class Glyph; + class BezierPath; + class GlyphAffinePair; + + class GlyphTracerLibart : public GlyphTracer + { + public: + GlyphTracerLibart(); + virtual ~GlyphTracerLibart(); + + virtual void correctGlyph(GlyphAffinePair *glyphAffine); + virtual BezierPath *allocBezierPath(int size); + virtual void closePath(Glyph *glyph); + }; +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/plugin/backends/libart/LibartCanvas.cpp b/ksvg/plugin/backends/libart/LibartCanvas.cpp new file mode 100644 index 00000000..5697b623 --- /dev/null +++ b/ksvg/plugin/backends/libart/LibartCanvas.cpp @@ -0,0 +1,425 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 "LibartCanvas.h" +#include "SVGMatrixImpl.h" +#include "SVGRectImpl.h" +#include "SVGPaintImpl.h" +#include "SVGShapeImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGStringListImpl.h" +#include "SVGPatternElementImpl.h" +#include "SVGGradientElementImpl.h" +#include "SVGLinearGradientElementImpl.h" +#include "SVGRadialGradientElementImpl.h" +#include "SVGClipPathElementImpl.h" +#include "SVGTextPositioningElementImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGAnimatedLengthListImpl.h" +#include "SVGAnimatedEnumerationImpl.h" +#include "SVGMarkerElementImpl.h" +#include "SVGMaskElementImpl.h" + +#include +#include +#include + +#include "SVGPaint.h" + +#include +#include +#include + +#include "KSVGHelper.h" +#include "KSVGTextChunk.h" +#include "LibartCanvasItems.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include "BezierPathLibart.h" +#include "GlyphTracerLibart.h" + +#include + +ArtSVP *art_svp_from_rect(int x0, int y0, int x1, int y1) +{ + ArtVpath vpath[] = + { + { ART_MOVETO, x0, y0 }, + { ART_LINETO, x0, y1 }, + { ART_LINETO, x1, y1 }, + { ART_LINETO, x1, y0 }, + { ART_LINETO, x0, y0 }, + { ART_END, 0, 0} + }; + + return art_svp_from_vpath(vpath); +} + +ArtSVP *art_svp_from_irect(ArtIRect *bbox) +{ + return art_svp_from_rect(bbox->x0, bbox->y0, bbox->x1, bbox->y1); +} + +ArtSVP *art_svp_from_qrect(const QRect& rect) +{ + return art_svp_from_rect(rect.left(), rect.top(), rect.right() + 1, rect.bottom() + 1); +} + +using namespace KSVG; + +LibartCanvas::LibartCanvas(unsigned int width, unsigned int height) : KSVGCanvas(width, height) +{ + m_fontContext = new T2P::Converter(new T2P::GlyphTracerLibart()); +} + +T2P::BezierPath *LibartCanvas::toBezierPath(CanvasItem *item) const +{ + LibartPath *path = dynamic_cast(item); + if(!path) + return 0; + + // Only handle LibartPath items + //T2P::BezierPathLibart *result = new T2P::BezierPathLibart(path->m_array.data()); + return path; +} + +// drawing primitives +CanvasItem *LibartCanvas::createRectangle(SVGRectElementImpl *rect) +{ + return new LibartRectangle(this, rect); +} + +CanvasItem *LibartCanvas::createEllipse(SVGEllipseElementImpl *ellipse) +{ + return new LibartEllipse(this, ellipse); +} + +CanvasItem *LibartCanvas::createCircle(SVGCircleElementImpl *circle) +{ + return new LibartCircle(this, circle); +} + +CanvasItem *LibartCanvas::createLine(SVGLineElementImpl *line) +{ + return new LibartLine(this, line); +} + +CanvasItem *LibartCanvas::createPolyline(SVGPolylineElementImpl *poly) +{ + return new LibartPolyline(this, poly); +} + +CanvasItem *LibartCanvas::createPolygon(SVGPolygonElementImpl *poly) +{ + return new LibartPolygon(this, poly); +} + +CanvasItem *LibartCanvas::createPath(SVGPathElementImpl *path) +{ + return new LibartPath(this, path); +} + +CanvasItem *LibartCanvas::createClipPath(SVGClipPathElementImpl *clippath) +{ + CanvasClipPath *result = new LibartClipPath(this, clippath); + QString index = clippath->id().string(); + m_clipPaths.insert(index, result); + return result; +} + +CanvasItem *LibartCanvas::createImage(SVGImageElementImpl *image) +{ + return new LibartImage(this, image); +} + +CanvasItem *LibartCanvas::createCanvasMarker(SVGMarkerElementImpl *marker) +{ + return new LibartMarker(this, marker); +} + +CanvasItem *LibartCanvas::createText(SVGTextElementImpl *text) +{ + return new LibartText(this, text); +} + +CanvasPaintServer *LibartCanvas::createPaintServer(SVGElementImpl *pserver) +{ + LibartPaintServer *result; + if(dynamic_cast(pserver)) + result = new LibartLinearGradient(dynamic_cast(pserver)); + else if(dynamic_cast(pserver)) + result = new LibartRadialGradient(dynamic_cast(pserver)); + else if(dynamic_cast(pserver)) + result = new LibartPattern(dynamic_cast(pserver)); + return result; +} + +void LibartCanvas::drawImage(QImage image, SVGStylableImpl *style, const SVGMatrixImpl *matrix, const KSVGPolygon& clippingPolygon) +{ + SVGShapeImpl *shape = dynamic_cast(style); + + if(shape) + { + if(image.depth() != 32) + image = image.convertDepth(32); + + ArtSVP *imageBorder = svpFromPolygon(clippingPolygon); + ArtSVP *clipSvp = clipSingleSVP(imageBorder, shape); + + ArtDRect bbox; + art_drect_svp(&bbox, clipSvp); + + // clamp to viewport + int x0 = int(bbox.x0); + int y0 = int(bbox.y0); + + // Use inclusive coords for x1/y1 for clipToBuffer + int x1 = int(ceil(bbox.x1)) - 1; + int y1 = int(ceil(bbox.y1)) - 1; + + if(x0 < int(m_width) && y0 < int(m_height) && x1 >= 0 && y1 >= 0) + { + clipToBuffer(x0, y0, x1, y1); + + QRect screenBBox(x0, y0, x1 - x0 + 1, y1 - y0 + 1); + + QByteArray mask = SVGMaskElementImpl::maskRectangle(shape, screenBBox); + + double affine[6]; + KSVGHelper::matrixToAffine(matrix, affine); + + ksvg_art_rgb_affine_clip(clipSvp, m_buffer + x0 * nrChannels() + y0 * rowStride(), x0, y0, x1 + 1, y1 + 1, rowStride(), nrChannels(), image.bits(), image.width(), image.height(), image.width() * 4, affine, int(style->getOpacity() * 255), (const art_u8 *)mask.data()); + } + + art_svp_free(imageBorder); + art_svp_free(clipSvp); + } +} + +ArtSVP *LibartCanvas::clippingRect(const QRect &rect, const SVGMatrixImpl *ctm) +{ + ArtVpath *vec = allocVPath(6); + // Order of points in clipping rectangle must be counter-clockwise + bool flip = ((ctm->a() * ctm->d()) < (ctm->b() * ctm->c())); + + vec[0].code = ART_MOVETO; + vec[0].x = rect.x(); + vec[0].y = rect.y(); + + vec[1].code = ART_LINETO; + vec[1].x = rect.x() + (flip ? rect.width() : 0); + vec[1].y = rect.y() + (flip ? 0 : rect.height()); + + vec[2].code = ART_LINETO; + vec[2].x = rect.x() + rect.width(); + vec[2].y = rect.y() + rect.height(); + + vec[3].code = ART_LINETO; + vec[3].x = rect.x() + (flip ? 0 : rect.width()); + vec[3].y = rect.y() + (flip ? rect.height() : 0); + + vec[4].code = ART_LINETO; + vec[4].x = rect.x(); + vec[4].y = rect.y(); + + vec[5].code = ART_END; + + double affine[6]; + KSVGHelper::matrixToAffine(ctm, affine); + + ArtVpath *temp = art_vpath_affine_transform(vec, affine); + art_free(vec); + + ArtSVP *result = art_svp_from_vpath(temp); + art_free(temp); + return result; +} + +ArtSVP *LibartCanvas::clipSingleSVP(ArtSVP *svp, SVGShapeImpl *shape) +{ + ArtSVP *clippedSvp = copy_svp(svp); + SVGStylableImpl *style = dynamic_cast(shape); + + if(style) + { + QString clipPathRef = style->getClipPath(); + + if(!clipPathRef.isEmpty()) + { + CanvasClipPath *clipPath = m_clipPaths[clipPathRef]; + + if(clipPath) + { + LibartClipPath *lclip = dynamic_cast(clipPath); + reinterpret_cast(clipPath->element())->setBBoxTarget(shape); + + lclip->init(); + + if(lclip->clipSVP()) + { + ArtSVP *s = art_svp_intersect(lclip->clipSVP(), clippedSvp); + art_svp_free(clippedSvp); + clippedSvp = s; + } + } + } + } + + SVGSVGElementImpl *svg = dynamic_cast(shape); + + // Clip outer svg, unless width and height not set + if(svg && (!svg->isRootElement() || !svg->getAttribute("width").isEmpty() || !svg->getAttribute("height").isEmpty()) && !svg->getOverflow()) + { + ArtSVP *svgClip = clippingRect(svg->clip(), svg->screenCTM()); + ArtSVP *s = art_svp_intersect(svgClip, clippedSvp); + art_svp_free(clippedSvp); + art_svp_free(svgClip); + clippedSvp = s; + } + + if(dynamic_cast(shape) != 0) + { + // TODO: inherit clipping paths into tile space + } + else if(dynamic_cast(shape) != 0) + { + SVGMarkerElementImpl *marker = static_cast(shape); + + if(!marker->clipShape().isEmpty()) + { + ArtSVP *clipShape = svpFromPolygon(marker->clipShape()); + ArtSVP *s = art_svp_intersect(clipShape, clippedSvp); + art_svp_free(clipShape); + art_svp_free(clippedSvp); + clippedSvp = s; + } + + // TODO: inherit clipping paths into marker space + } + else + { + SVGElementImpl *element = dynamic_cast(shape); + DOM::Node parentNode = element->parentNode(); + + if(!parentNode.isNull()) + { + SVGElementImpl *parent = element->ownerDoc()->getElementFromHandle(parentNode.handle()); + + if(parent) + { + SVGShapeImpl *parentShape = dynamic_cast(parent); + + if(parentShape) + { + // Clip against ancestor clipping paths + ArtSVP *parentClippedSvp = clipSingleSVP(clippedSvp, parentShape); + art_svp_free(clippedSvp); + clippedSvp = parentClippedSvp; + } + } + } + } + + return clippedSvp; +} + +void LibartCanvas::drawSVP(ArtSVP *svp, art_u32 color, QByteArray mask, QRect screenBBox) +{ + int x0 = screenBBox.left(); + int y0 = screenBBox.top(); + int x1 = screenBBox.right(); + int y1 = screenBBox.bottom(); + + if(m_nrChannels == 3) + { + if(mask.data()) + art_ksvg_rgb_svp_alpha_mask(svp, x0, y0, x1 + 1, y1 + 1, color, m_buffer + x0 * 3 + y0 * 3 * m_width, m_width * 3, 0, (art_u8 *)mask.data()); + else + art_rgb_svp_alpha(svp, x0, y0, x1 + 1, y1 + 1, color, m_buffer + x0 * 3 + y0 * 3 * m_width, m_width * 3, 0); + } + else + art_ksvg_rgba_svp_alpha(svp, x0, y0, x1 + 1, y1 + 1, color, m_buffer + x0 * 4 + y0 * 4 * m_width, m_width * 4, 0, (art_u8 *)mask.data()); +} + +ArtSVP *LibartCanvas::copy_svp(const ArtSVP *svp) +{ + // No API to copy an SVP so do so without accessing the data structure directly. + ArtVpath *vec = allocVPath(1); + + vec[0].code = ART_END; + + ArtSVP *empty = art_svp_from_vpath(vec); + art_free(vec); + + ArtSVP *result = art_svp_union(empty, svp); + art_svp_free(empty); + + return result; +} + +ArtSVP *LibartCanvas::svpFromPolygon(const KSVGPolygon& polygon) +{ + if(polygon.numPoints() > 2) + { + ArtVpath *points = new ArtVpath[polygon.numPoints() + 2]; + + points[0].code = ART_MOVETO; + points[0].x = polygon.point(0).x(); + points[0].y = polygon.point(0).y(); + + unsigned int i; + + for(i = 1; i < polygon.numPoints(); i++) + { + points[i].code = ART_LINETO; + points[i].x = polygon.point(i).x(); + points[i].y = polygon.point(i).y(); + } + + points[i].code = ART_LINETO; + points[i].x = polygon.point(0).x(); + points[i].y = polygon.point(0).y(); + + points[i + 1].code = ART_END; + + ArtSVP *svp = art_svp_from_vpath(points); + delete [] points; + + return svp; + } + else + return 0; +} + +// vim:ts=4:noet diff --git a/ksvg/plugin/backends/libart/LibartCanvas.h b/ksvg/plugin/backends/libart/LibartCanvas.h new file mode 100644 index 00000000..e0da1682 --- /dev/null +++ b/ksvg/plugin/backends/libart/LibartCanvas.h @@ -0,0 +1,84 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 LIBARTCANVAS_H +#define LIBARTCANVAS_H + +#include "CanvasItem.h" +#include "KSVGCanvas.h" + +#include +#include +#include + +#include +#include +#include "GlyphTracerLibart.h" + +class QString; +class QImage; + +struct _ArtSVP; + +namespace KSVG +{ + +class LibartPaintServer; +class SVGElementImpl; +class SVGStylableImpl; +class SVGSVGElementImpl; +class KSVGPolygon; +class LibartCanvas : public KSVGCanvas +{ +public: + LibartCanvas(unsigned int width, unsigned int height); + + void drawSVP(_ArtSVP *svp, art_u32 color, QByteArray mask, QRect screenBBox); + void drawImage(QImage image, SVGStylableImpl *style, const SVGMatrixImpl *matrix, const KSVGPolygon& clippingPolygon); + + virtual T2P::BezierPath *toBezierPath(CanvasItem *item) const; + + // creating canvas items + virtual CanvasItem *createRectangle(SVGRectElementImpl *rect); + virtual CanvasItem *createEllipse(SVGEllipseElementImpl *ellipse); + virtual CanvasItem *createCircle(SVGCircleElementImpl *circle); + virtual CanvasItem *createLine(SVGLineElementImpl *line); + virtual CanvasItem *createPolyline(SVGPolylineElementImpl *poly); + virtual CanvasItem *createPolygon(SVGPolygonElementImpl *poly); + virtual CanvasItem *createPath(SVGPathElementImpl *path); + virtual CanvasItem *createClipPath(SVGClipPathElementImpl *clippath); + virtual CanvasItem *createImage(SVGImageElementImpl *image); + virtual CanvasItem *createCanvasMarker(SVGMarkerElementImpl *marker); + virtual CanvasItem *createText(SVGTextElementImpl *text); + virtual CanvasPaintServer *createPaintServer(SVGElementImpl *pserver); + + _ArtSVP *clippingRect(const QRect &rect, const SVGMatrixImpl *ctm); + _ArtSVP *svpFromPolygon(const KSVGPolygon& polygon); + + static ArtSVP *copy_svp(const ArtSVP *svp); + + _ArtSVP *clipSingleSVP(_ArtSVP *svp, SVGShapeImpl *clipShape); +}; + +} + +#endif + +// vim:ts=4:noet diff --git a/ksvg/plugin/backends/libart/LibartCanvasFactory.cpp b/ksvg/plugin/backends/libart/LibartCanvasFactory.cpp new file mode 100644 index 00000000..48d37f05 --- /dev/null +++ b/ksvg/plugin/backends/libart/LibartCanvasFactory.cpp @@ -0,0 +1,45 @@ +/* + Copyright (C) 2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 + +#include "LibartCanvas.h" +#include "LibartCanvasFactory.h" + +using namespace KSVG; + +K_EXPORT_COMPONENT_FACTORY(libksvgrendererlibart, LibartCanvasFactory) + +LibartCanvasFactory::LibartCanvasFactory() +{ +} + +LibartCanvasFactory::~LibartCanvasFactory() +{ +} + +QObject *LibartCanvasFactory::createObject(QObject *, const char *, const char *, const QStringList &args) +{ + int width = (*args.at(1)).toInt(); + int height = (*args.at(0)).toInt(); + return new LibartCanvas(width, height); +} + +// vim:ts=4:noet diff --git a/ksvg/plugin/backends/libart/LibartCanvasFactory.h b/ksvg/plugin/backends/libart/LibartCanvasFactory.h new file mode 100644 index 00000000..5b3ed0b3 --- /dev/null +++ b/ksvg/plugin/backends/libart/LibartCanvasFactory.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 LIBARTCANVASFACTORY_H +#define LIBARTCANVASFACTORY_H + +#include + +#include "CanvasItem.h" +#include "KSVGCanvas.h" + +namespace KSVG +{ + +class LibartCanvasFactory : public KLibFactory +{ +public: + LibartCanvasFactory(); + virtual ~LibartCanvasFactory(); + + virtual QObject *createObject(QObject *parent = 0, const char *pname = 0, const char *name = "QObject", const QStringList &args = QStringList()); +}; + +} + +#endif + +/// vim:ts=4:noet diff --git a/ksvg/plugin/backends/libart/LibartCanvasItems.cpp b/ksvg/plugin/backends/libart/LibartCanvasItems.cpp new file mode 100644 index 00000000..5dd97be1 --- /dev/null +++ b/ksvg/plugin/backends/libart/LibartCanvasItems.cpp @@ -0,0 +1,2209 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 + +#include +#include + +#include "SVGPaint.h" +#include "SVGRectImpl.h" +#include "SVGAngleImpl.h" +#include "SVGPaintImpl.h" +#include "SVGUnitTypes.h" +#include "SVGHelperImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGPointListImpl.h" +#include "SVGMarkerElement.h" +#include "SVGMarkerElementImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGPathSegListImpl.h" +#include "SVGAnimatedRectImpl.h" +#include "SVGAnimatedStringImpl.h" +#include "SVGImageElementImpl.h" +#include "SVGAnimatedAngleImpl.h" +#include "SVGAnimatedLengthImpl.h" +#include "SVGPolygonElementImpl.h" +#include "SVGClipPathElementImpl.h" +#include "SVGPolylineElementImpl.h" +#include "SVGAnimatedLengthListImpl.h" +#include "SVGAnimatedNumberImpl.h" +#include "SVGAnimatedEnumerationImpl.h" +#include "SVGPreserveAspectRatioImpl.h" +#include "SVGAnimatedPreserveAspectRatioImpl.h" +#include "SVGGradientElementImpl.h" +#include "SVGGradientElement.h" +#include "SVGLinearGradientElementImpl.h" +#include "SVGRadialGradientElementImpl.h" +#include "SVGPatternElementImpl.h" +#include "SVGPatternElement.h" +#include "SVGStopElementImpl.h" +#include "SVGStylableImpl.h" +#include "SVGAnimatedTransformListImpl.h" +#include "SVGTransformListImpl.h" +#include "SVGUnitConverter.h" +#include "SVGTextPathElementImpl.h" +#include "SVGMaskElementImpl.h" + +#include "KSVGHelper.h" +#include "LibartCanvasItems.h" +#include "KSVGTextChunk.h" + +#include "art_misc.h" +#include "art_render_misc.h" +#include "BezierPathLibart.h" +#include "Point.h" + +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace KSVG; + +LibartShape::LibartShape(LibartCanvas *c, SVGStylableImpl *style) : m_canvas(c), m_style(style) +{ + m_fillSVP = 0; + m_strokeSVP = 0; + m_fillPainter = 0; + m_strokePainter = 0; +} + +LibartShape::~LibartShape() +{ + freeSVPs(); + delete m_fillPainter; + delete m_strokePainter; +} + +QRect LibartShape::bbox() const +{ + QRect rect; + if(m_strokeSVP || m_fillSVP) + { + ArtIRect *irect = new ArtIRect(); + ArtVpath *vpath = art_vpath_from_svp(m_strokeSVP ? m_strokeSVP : m_fillSVP); + art_vpath_bbox_irect(vpath, irect); + art_free(vpath); + + rect.setX(irect->x0); + rect.setY(irect->y0); + rect.setWidth(irect->x1 - irect->x0); + rect.setHeight(irect->y1 - irect->y0); + + delete irect; + } + + return rect; +} + +bool LibartShape::isVisible(SVGShapeImpl *shape) +{ + return m_referenced || (m_style->getVisible() && m_style->getDisplay() && shape->directRender()); +} + +bool LibartShape::fillContains(const QPoint &p) +{ + if(m_fillSVP) + return art_svp_point_wind(m_fillSVP, p.x(), p.y()) != 0; + else + return false; +} + +bool LibartShape::strokeContains(const QPoint &p) +{ + if(m_strokeSVP) + return art_svp_point_wind(m_strokeSVP, p.x(), p.y()) != 0; + else + return false; +} + +void LibartShape::update(CanvasItemUpdate reason, int param1, int param2) +{ + if(reason == UPDATE_STYLE) + { + if(!m_fillPainter || !m_strokePainter) + LibartShape::init(); + if(m_fillPainter) + m_fillPainter->update(m_style); + if(m_strokePainter) + m_strokePainter->update(m_style); + m_canvas->invalidate(this, false); + } + else if(reason == UPDATE_TRANSFORM) + { + reset(); + m_canvas->invalidate(this, true); + } + else if(reason == UPDATE_ZOOM) + reset(); + else if(reason == UPDATE_PAN) + { + if(m_fillSVP) + ksvg_art_svp_move(m_fillSVP, param1, param2); + if(m_strokeSVP) + ksvg_art_svp_move(m_strokeSVP, param1, param2); + } + else if(reason == UPDATE_LINEWIDTH) + { + if(m_strokeSVP) + { + art_svp_free(m_strokeSVP); + m_strokeSVP = 0; + } + init(); + m_canvas->invalidate(this, true); + } +} + +void LibartShape::draw(SVGShapeImpl *shape) +{ + if(!m_referenced && (!m_style->getVisible() || !m_style->getDisplay() || !shape->directRender())) + return; + + bool fillOk = m_fillSVP && m_style->isFilled(); + bool strokeOk = m_strokeSVP && m_style->isStroked() && m_style->getStrokeWidth()->baseVal()->value() > 0; // Spec: A zero value causes no stroke to be painted. + + if(fillOk || strokeOk) + { + if(m_fillPainter && m_fillSVP) + m_fillPainter->draw(m_canvas, m_fillSVP, m_style, shape); + + if(m_strokePainter && m_strokeSVP) + m_strokePainter->draw(m_canvas, m_strokeSVP, m_style, shape); + } +} + +void LibartShape::init(const SVGMatrixImpl *) +{ +} + +void LibartPainter::update(SVGStylableImpl *style) +{ + if(paintType(style) != SVG_PAINTTYPE_URI) + { + QColor qcolor; + if(paintType(style) == SVG_PAINTTYPE_CURRENTCOLOR) + qcolor = style->getColor()->rgbColor().color(); + else + qcolor = color(style); + + short _opacity = static_cast(opacity(style) * 255 + 0.5); + + // Spec: clamping + _opacity = _opacity < 0 ? 0 : _opacity; + _opacity = _opacity > 255 ? 255 : _opacity; + + m_color = KSVGHelper::toArtColor(qcolor, _opacity); + } +} + +void LibartPainter::draw(LibartCanvas *canvas, _ArtSVP *svp, SVGStylableImpl *style, SVGShapeImpl *shape) +{ + ArtSVP *clippedSvp = canvas->clipSingleSVP(svp, shape); + + // Clipping + ArtDRect bbox; + art_drect_svp(&bbox, clippedSvp); + + // clamp to viewport + int x0 = int(bbox.x0); + int y0 = int(bbox.y0); + + // Use inclusive coords for x1/y1 for clipToBuffer + int x1 = int(ceil(bbox.x1)) - 1; + int y1 = int(ceil(bbox.y1)) - 1; + + if(x0 < int(canvas->width()) && y0 < int(canvas->height()) && x1 > -1 && y1 > -1) + { + canvas->clipToBuffer(x0, y0, x1, y1); + + QRect screenBBox(x0, y0, x1 - x0 + 1, y1 - y0 + 1); + + QByteArray mask = SVGMaskElementImpl::maskRectangle(shape, screenBBox); + + if(paintType(style) == SVG_PAINTTYPE_URI) + { + LibartPaintServer *pserver = static_cast(SVGPaintServerImpl::paintServer(shape->ownerDoc(), paintUri(style))); + + if(pserver) + { + pserver->setBBoxTarget(shape); + if(!pserver->finalized()) + pserver->finalizePaintServer(); + pserver->render(canvas, clippedSvp, opacity(style), mask, screenBBox); + } + } + else + canvas->drawSVP(clippedSvp, m_color, mask, screenBBox); + } + + art_svp_free(clippedSvp); +} + +LibartStrokePainter::LibartStrokePainter(SVGStylableImpl *style) +{ + update(style); +} + +LibartFillPainter::LibartFillPainter(SVGStylableImpl *style) +{ + update(style); +} + +void LibartShape::init() +{ + if(m_style->isFilled()) + { + if(m_fillPainter == 0) + m_fillPainter = new LibartFillPainter(m_style); + } + else + { + delete m_fillPainter; + m_fillPainter = 0; + } + + // Spec: A zero value causes no stroke to be painted. + if(m_style->isStroked() && m_style->getStrokeWidth()->baseVal()->value() > 0) + { + if(m_strokePainter == 0) + m_strokePainter = new LibartStrokePainter(m_style); + } + else + { + delete m_strokePainter; + m_strokePainter = 0; + } +} + +void LibartShape::initClipItem() +{ + init(); +} + +ArtSVP *LibartShape::clipSVP() +{ + return m_fillSVP; +} + +void LibartShape::freeSVPs() +{ + if(m_fillSVP) + art_svp_free(m_fillSVP); + if(m_strokeSVP) + art_svp_free(m_strokeSVP); + + m_fillSVP = 0; + m_strokeSVP = 0; +} + +void LibartShape::calcClipSVP(ArtVpath *vec, SVGStylableImpl *style, const SVGMatrixImpl *matrix, _ArtSVP **clipSVP) +{ + double affine[6]; + KSVGHelper::matrixToAffine(matrix, affine); + + if(!style) + { + art_free(vec); + return; + } + + ArtVpath *vtemp = art_vpath_affine_transform(vec, affine); + art_free(vec); + vec = vtemp; + + ArtSVP *temp; + ArtSvpWriter *swr; + temp = art_svp_from_vpath(vec); + + if(style->getClipRule() == RULE_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); + *clipSVP = art_svp_writer_rewind_reap(swr); + + art_svp_free(temp); + art_free(vec); +} + +void LibartShape::calcSVPs(ArtVpath *vec, SVGStylableImpl *style, const SVGMatrixImpl *matrix, ArtSVP **strokeSVP, ArtSVP **fillSVP) +{ + if(style) + { + double affine[6]; + KSVGHelper::matrixToAffine(matrix, affine); + + ArtVpath *temp = art_vpath_affine_transform(vec, affine); + art_free(vec); + vec = temp; + calcSVPInternal(vec, style, affine, strokeSVP, fillSVP); + } + else + art_free(vec); +} + +void LibartShape::calcSVPs(ArtBpath *bpath, SVGStylableImpl *style, const SVGMatrixImpl *matrix, ArtSVP **strokeSVP, ArtSVP **fillSVP) +{ + if(style) + { + double affine[6]; + KSVGHelper::matrixToAffine(matrix, affine); + + ArtBpath *temp = art_bpath_affine_transform(bpath, affine); + ArtVpath *vec = ksvg_art_bez_path_to_vec(temp, 0.25); + art_free(temp); + calcSVPInternal(vec, style, affine, strokeSVP, fillSVP); + } +} + +void LibartShape::calcSVPInternal(ArtVpath *vec, SVGStylableImpl *style, double *affine, ArtSVP **strokeSVP, ArtSVP **fillSVP) +{ + ArtSVP *svp; + + // Filling + { + ArtSvpWriter *swr; + ArtSVP *temp; + temp = art_svp_from_vpath(vec); + + if(style->getFillRule() == RULE_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); + svp = art_svp_writer_rewind_reap(swr); + + *fillSVP = svp; + art_svp_free(temp); + } + + // Stroking + if(style->isStroked() || style->getStrokeColor()->paintType() == SVG_PAINTTYPE_URI) + { + double ratio = art_affine_expansion(affine); + + unsigned int dashLength; + if(style->getDashArray() && (dashLength = style->getDashArray()->baseVal()->numberOfItems()) > 0) + { + // HACK: libart will hang in art_vpath_dash() if passed an array with only zeroes. + bool allZeroes = true; + + // there are dashes to be rendered + ArtVpathDash dash; + dash.offset = int(style->getDashOffset()->baseVal()->value()) * ratio; + dash.n_dash = dashLength; + double *dashes = new double[dashLength]; + for(unsigned int i = 0; i < dashLength; i++) + { + dashes[i] = style->getDashArray()->baseVal()->getItem(i)->value() * ratio; + if(dashes[i] != 0.0) + allZeroes = false; + } + dash.dash = dashes; + + if(!allZeroes) + { + // get the dashed VPath and use that for the stroke render operation + ArtVpath *vec2 = art_vpath_dash(vec, &dash); + art_free(vec); + vec = vec2; + } + + // reset the dashes + delete [] dashes; + } + + double penWidth = style->getStrokeWidth()->baseVal()->value() * ratio; + svp = art_svp_vpath_stroke(vec, (ArtPathStrokeJoinType)style->getJoinStyle(), (ArtPathStrokeCapType)style->getCapStyle(), penWidth, style->getStrokeMiterlimit(), 0.25); + + *strokeSVP = svp; + } + art_free(vec); +} + +// ##### + +LibartRectangle::LibartRectangle(LibartCanvas *c, SVGRectElementImpl *rect) +: LibartShape(c, rect), m_rect(rect) +{ + init(); +} + +void LibartRectangle::draw() +{ + if(isVisible()) + LibartShape::draw(m_rect); +} + +bool LibartRectangle::isVisible() +{ + // Spec: a value of zero disables rendering + return LibartShape::isVisible(m_rect) && m_rect->width()->baseVal()->value() > 0 && m_rect->height()->baseVal()->value() > 0; +} + +void LibartRectangle::init() +{ + init(m_rect->screenCTM()); +} + +void LibartRectangle::init(const SVGMatrixImpl *screenCTM) +{ + LibartShape::init(); + double x = m_rect->x()->baseVal()->value(); + double y = m_rect->y()->baseVal()->value(); + double width = m_rect->width()->baseVal()->value(); + double height = m_rect->height()->baseVal()->value(); + double rx = m_rect->rx()->baseVal()->value(); + double ry = m_rect->ry()->baseVal()->value(); + + // Spec: If there is no rx or ry specified, draw a normal rect + if(rx == -1 && ry == -1) + { + ArtVpath *vec = allocVPath(6); + + vec[0].code = ART_MOVETO; + vec[0].x = x; + vec[0].y = y; + + vec[1].code = ART_LINETO; + vec[1].x = x; + vec[1].y = y + height; + + vec[2].code = ART_LINETO; + vec[2].x = x + width; + vec[2].y = y + height; + + vec[3].code = ART_LINETO; + vec[3].x = x + width; + vec[3].y = y; + + vec[4].code = ART_LINETO; + vec[4].x = x; + vec[4].y = y; + + vec[5].code = ART_END; + + if(m_context == NORMAL) + calcSVPs(vec, m_rect, screenCTM, &m_strokeSVP, &m_fillSVP); + else + calcClipSVP(vec, m_rect, screenCTM, &m_fillSVP); + } + else + { + ArtVpath *res; + ArtBpath *vec = allocBPath(10); + + int i = 0; + + // Spec: If rx isn't specified, but ry, set rx to ry + if(rx == -1) + rx = ry; + + // Spec: If ry isn't specified, but rx, set ry to rx + if(ry == -1) + ry = rx; + + // Spec: If rx is greater than half of the width of the rectangle + // then set rx to half of the width + if(rx > width / 2) + rx = width / 2; + + // Spec: If ry is greater than half of the height of the rectangle + // then set ry to half of the height + if(ry > height / 2) + ry = height / 2; + + vec[i].code = ART_MOVETO_OPEN; + vec[i].x3 = x + rx; + vec[i].y3 = y; + + i++; + + vec[i].code = ART_CURVETO; + vec[i].x1 = x + rx * (1 - 0.552); + vec[i].y1 = y; + vec[i].x2 = x; + vec[i].y2 = y + ry * (1 - 0.552); + vec[i].x3 = x; + vec[i].y3 = y + ry; + + i++; + + if(ry < height / 2) + { + vec[i].code = ART_LINETO; + vec[i].x3 = x; + vec[i].y3 = y + height - ry; + + i++; + } + vec[i].code = ART_CURVETO; + vec[i].x1 = x; + vec[i].y1 = y + height - ry * (1 - 0.552); + vec[i].x2 = x + rx * (1 - 0.552); + vec[i].y2 = y + height; + vec[i].x3 = x + rx; + vec[i].y3 = y + height; + + i++; + + if(rx < width / 2) + { + vec[i].code = ART_LINETO; + vec[i].x3 = x + width - rx; + vec[i].y3 = y + height; + + i++; + } + + vec[i].code = ART_CURVETO; + vec[i].x1 = x + width - rx * (1 - 0.552); + vec[i].y1 = y + height; + vec[i].x2 = x + width; + vec[i].y2 = y + height - ry * (1 - 0.552); + vec[i].x3 = x + width; + + vec[i].y3 = y + height - ry; + + i++; + + if(ry < height / 2) + { + vec[i].code = ART_LINETO; + vec[i].x3 = x + width; + vec[i].y3 = y + ry; + + i++; + } + vec[i].code = ART_CURVETO; + vec[i].x1 = x + width; + vec[i].y1 = y + ry * (1 - 0.552); + vec[i].x2 = x + width - rx * (1 - 0.552); + vec[i].y2 = y; + vec[i].x3 = x + width - rx; + vec[i].y3 = y; + + i++; + + if(rx < width / 2) + { + vec[i].code = ART_LINETO; + vec[i].x3 = x + rx; + vec[i].y3 = y; + + i++; + } + + vec[i].code = ART_END; + + res = ksvg_art_bez_path_to_vec(vec, 0.25); + if(m_context == NORMAL) + calcSVPs(res, m_rect, screenCTM, &m_strokeSVP, &m_fillSVP); + else + calcClipSVP(res, m_rect, screenCTM, &m_fillSVP); + art_free(vec); + } +} + +// ##### + +LibartEllipse::LibartEllipse(LibartCanvas *c, SVGEllipseElementImpl *ellipse) +: LibartShape(c, ellipse), m_ellipse(ellipse) +{ + init(); +} + +void LibartEllipse::draw() +{ + if(isVisible()) + LibartShape::draw(m_ellipse); +} + +bool LibartEllipse::isVisible() +{ + // Spec: dont render when rx and/or ry is zero + return LibartShape::isVisible(m_ellipse) && m_ellipse->rx()->baseVal()->value() > 0 && m_ellipse->ry()->baseVal()->value() > 0; +} + +void LibartEllipse::init() +{ + init(m_ellipse->screenCTM()); +} + +void LibartEllipse::init(const SVGMatrixImpl *screenCTM) +{ + LibartShape::init(); + ArtBpath *temp = allocBPath(6); + + double x1, y1, x2, y2, x3, y3; + double len = 0.55228474983079356; + double rx = m_ellipse->rx()->baseVal()->value(); + double ry = m_ellipse->ry()->baseVal()->value(); + double cx = m_ellipse->cx()->baseVal()->value(); + double cy = m_ellipse->cy()->baseVal()->value(); + double cos4[] = {1.0, 0.0, -1.0, 0.0, 1.0}; + double sin4[] = {0.0, 1.0, 0.0, -1.0, 0.0}; + int i = 0; + + temp[i].code = ART_MOVETO; + temp[i].x3 = cx + rx; + temp[i].y3 = cy; + + i++; + + while(i < 5) + { + x1 = cos4[i-1] + len * cos4[i]; + y1 = sin4[i-1] + len * sin4[i]; + x2 = cos4[i] + len * cos4[i-1]; + y2 = sin4[i] + len * sin4[i-1]; + x3 = cos4[i]; + y3 = sin4[i]; + + temp[i].code = ART_CURVETO; + temp[i].x1 = cx + x1 * rx; + temp[i].y1 = cy + y1 * ry; + temp[i].x2 = cx + x2 * rx; + temp[i].y2 = cy + y2 * ry; + temp[i].x3 = cx + x3 * rx; + temp[i].y3 = cy + y3 * ry; + + i++; + } + + temp[i].code = ART_END; + + if(m_context == NORMAL) + calcSVPs(temp, m_ellipse, screenCTM, &m_strokeSVP, &m_fillSVP); + else + calcClipSVP(ksvg_art_bez_path_to_vec(temp, 0.25), m_ellipse, screenCTM, &m_fillSVP); + art_free(temp); +} + +// ##### + +LibartCircle::LibartCircle(LibartCanvas *c, SVGCircleElementImpl *circle) +: LibartShape(c, circle), m_circle(circle) +{ + init(); +} + +void LibartCircle::draw() +{ + // Spec: a value of zero disables rendering + if(isVisible()) + LibartShape::draw(m_circle); +} + +bool LibartCircle::isVisible() +{ + // Spec: dont render when rx and/or ry is zero + return LibartShape::isVisible(m_circle) && m_circle->r()->baseVal()->value() > 0; +} + +void LibartCircle::init() +{ + init(m_circle->screenCTM()); +} + +void LibartCircle::init(const SVGMatrixImpl *screenCTM) +{ + LibartShape::init(); + ArtBpath *temp = allocBPath(6); + + double x1, y1, x2, y2, x3, y3; + double len = 0.55228474983079356; + double r = m_circle->r()->baseVal()->value(); + double cx = m_circle->cx()->baseVal()->value(); + double cy = m_circle->cy()->baseVal()->value(); + double cos4[] = {1.0, 0.0, -1.0, 0.0, 1.0}; + double sin4[] = {0.0, 1.0, 0.0, -1.0, 0.0}; + int i = 0; + + temp[i].code = ART_MOVETO; + temp[i].x3 = cx + r; + temp[i].y3 = cy; + + i++; + + while(i < 5) + { + x1 = cos4[i-1] + len * cos4[i]; + y1 = sin4[i-1] + len * sin4[i]; + x2 = cos4[i] + len * cos4[i-1]; + y2 = sin4[i] + len * sin4[i-1]; + x3 = cos4[i]; + y3 = sin4[i]; + + temp[i].code = ART_CURVETO; + temp[i].x1 = cx + x1 * r; + temp[i].y1 = cy + y1 * r; + temp[i].x2 = cx + x2 * r; + temp[i].y2 = cy + y2 * r; + temp[i].x3 = cx + x3 * r; + temp[i].y3 = cy + y3 * r; + + i++; + } + + temp[i].code = ART_END; + + if(m_context == NORMAL) + calcSVPs(temp, m_circle, screenCTM, &m_strokeSVP, &m_fillSVP); + else + calcClipSVP(ksvg_art_bez_path_to_vec(temp, 0.25), m_circle, screenCTM, &m_fillSVP); + art_free(temp); +} + +// ##### + +LibartLine::LibartLine(LibartCanvas *c, SVGLineElementImpl *line) +: LibartShape(c, line), MarkerHelper(), m_line(line) +{ + init(); +} + +LibartLine::~LibartLine() +{ +} + +void LibartLine::draw() +{ + LibartShape::draw(m_line); + + if(m_line->hasMarkers()) + { + double x1 = m_line->x1()->baseVal()->value(); + double y1 = m_line->y1()->baseVal()->value(); + double x2 = m_line->x2()->baseVal()->value(); + double y2 = m_line->y2()->baseVal()->value(); + double slope = SVGAngleImpl::todeg(atan2(y2 - y1, x2 - x1)); + + if(m_line->hasStartMarker()) + doStartMarker(m_line, m_line, x1, y1, slope); + if(m_line->hasEndMarker()) + doEndMarker(m_line, m_line, x2, y2, slope); + } +} + +bool LibartLine::isVisible() +{ + return LibartShape::isVisible(m_line); +} + +void LibartLine::init() +{ + init(m_line->screenCTM()); +} + +void LibartLine::init(const SVGMatrixImpl *screenCTM) +{ + LibartShape::init(); + ArtVpath *vec; + + vec = allocVPath(3); + + vec[0].code = ART_MOVETO_OPEN; + vec[0].x = m_line->x1()->baseVal()->value(); + vec[0].y = m_line->y1()->baseVal()->value(); + + vec[1].code = ART_LINETO; + vec[1].x = m_line->x2()->baseVal()->value(); + vec[1].y = m_line->y2()->baseVal()->value(); + + // A subpath consisting of a moveto and lineto to the same exact location or a subpath consisting of a moveto + // and a closepath will be stroked only if the 'stroke-linecap' property is set to "round", producing a circle + // centered at the given point. + if(vec[1].x == vec[0].x && vec[1].y == vec[0].y && m_line->getCapStyle() == PATH_STROKE_CAP_ROUND) + vec[1].x += .5; + + vec[2].code = ART_END; + + if(m_context == NORMAL) + { + calcSVPs(vec, m_line, screenCTM, &m_strokeSVP, &m_fillSVP); + art_svp_free(m_fillSVP); + m_fillSVP = 0; + } + else + calcClipSVP(vec, m_line, screenCTM, &m_fillSVP); +} + +// ##### +LibartPoly::LibartPoly(LibartCanvas *c, SVGPolyElementImpl *poly) +: LibartShape(c, poly), MarkerHelper(), m_poly(poly) +{ +} + +LibartPoly::~LibartPoly() +{ +} + +void LibartPoly::init() +{ + init(m_poly->screenCTM()); +} + +void LibartPoly::draw() +{ + LibartShape::draw(m_poly); + + if(m_poly->hasMarkers()) + m_poly->drawMarkers(); +} + +bool LibartPoly::isVisible() +{ + return LibartShape::isVisible(m_poly); +} + +// ##### +LibartPolyline::LibartPolyline(LibartCanvas *c, SVGPolylineElementImpl *poly) +: LibartPoly(c, poly) +{ + LibartPoly::init(); +} + +LibartPolyline::~LibartPolyline() +{ +} + +void LibartPolyline::init(const SVGMatrixImpl *screenCTM) +{ + LibartShape::init(); + unsigned int numberOfPoints = m_poly->points()->numberOfItems(); + + if(numberOfPoints < 1) + return; + + ArtVpath *polyline = allocVPath(2 + numberOfPoints); + + polyline[0].code = ART_MOVETO_OPEN; + polyline[0].x = m_poly->points()->getItem(0)->x(); + polyline[0].y = m_poly->points()->getItem(0)->y(); + + unsigned int index; + for(index = 1; index < numberOfPoints; index++) + { + polyline[index].code = ART_LINETO; + polyline[index].x = m_poly->points()->getItem(index)->x(); + polyline[index].y = m_poly->points()->getItem(index)->y(); + } + + // A subpath consisting of a moveto and lineto to the same exact location or a subpath consisting of a moveto + // and a closepath will be stroked only if the 'stroke-linecap' property is set to "round", producing a circle + // centered at the given point. + if(numberOfPoints == 2 && polyline[1].x == polyline[0].x && polyline[1].y == polyline[0].y && m_poly->getCapStyle() == PATH_STROKE_CAP_ROUND) + polyline[1].x += .5; + + + if(m_poly->isFilled()) // if the polyline must be filled, inform libart that it should not be closed. + { + polyline[index].code = (ArtPathcode) ART_END2; + polyline[index].x = m_poly->points()->getItem(0)->x(); + polyline[index++].y = m_poly->points()->getItem(0)->y(); + } + + polyline[index].code = ART_END; + if(m_context == NORMAL) + calcSVPs(polyline, m_poly, screenCTM, &m_strokeSVP, &m_fillSVP); + else + calcClipSVP(polyline, m_poly, screenCTM, &m_fillSVP); +} + +// ##### + +LibartPolygon::LibartPolygon(LibartCanvas *c, SVGPolygonElementImpl *poly) +: LibartPoly(c, poly) +{ + LibartPoly::init(); +} + +LibartPolygon::~LibartPolygon() +{ +} + +void LibartPolygon::init(const SVGMatrixImpl *screenCTM) +{ + LibartShape::init(); + unsigned int numberOfPoints = m_poly->points()->numberOfItems(); + + if(numberOfPoints < 1) + return; + + ArtVpath *polygon = allocVPath(2 + numberOfPoints); + + polygon[0].code = ART_MOVETO; + polygon[0].x = m_poly->points()->getItem(0)->x(); + polygon[0].y = m_poly->points()->getItem(0)->y(); + + unsigned int index; + for(index = 1; index < numberOfPoints; index++) + { + polygon[index].code = ART_LINETO; + polygon[index].x = m_poly->points()->getItem(index)->x(); + polygon[index].y = m_poly->points()->getItem(index)->y(); + } + + polygon[index].code = ART_LINETO; + polygon[index].x = m_poly->points()->getItem(0)->x(); + polygon[index].y = m_poly->points()->getItem(0)->y(); + + index++; + polygon[index].code = ART_END; + + if(m_context == NORMAL) + calcSVPs(polygon, m_poly, screenCTM, &m_strokeSVP, &m_fillSVP); + else + calcClipSVP(polygon, m_poly, screenCTM, &m_fillSVP); +} + +// ##### + +LibartPath::LibartPath(LibartCanvas *c, SVGPathElementImpl *path) +: LibartShape(c, path), MarkerHelper(), T2P::BezierPathLibart(), ::SVGPathParser(), m_path(path) +{ + reset(); +} + +LibartPath::~LibartPath() +{ +} + +void LibartPath::reset() +{ + m_array.resize(0); + LibartShape::reset(); +} + +void LibartPath::draw() +{ + LibartShape::draw(m_path); + + if(m_path->hasMarkers()) + { + SVGPathElementImpl::MarkerData markers = m_path->markerData(); + int numMarkers = markers.numMarkers(); + + if(m_path->hasStartMarker()) + doStartMarker(m_path, m_path, markers.marker(0).x, markers.marker(0).y, markers.marker(0).angle); + + for(int i = 1; i < numMarkers - 1; i++) + { + if(m_path->hasMidMarker()) + doMidMarker(m_path, m_path, markers.marker(i).x, markers.marker(i).y, markers.marker(i).angle); + } + + if(m_path->hasEndMarker()) + doEndMarker(m_path, m_path, markers.marker(numMarkers - 1).x, markers.marker(numMarkers - 1).y, markers.marker(numMarkers - 1).angle); + } +} + +bool LibartPath::isVisible() +{ + return LibartShape::isVisible(m_path); +} + +void LibartPath::init() +{ + init(m_path->screenCTM()); +} + +void LibartPath::init(const SVGMatrixImpl *screenCTM) +{ + LibartShape::init(); + if(m_array.count() > 0) + { + if(m_context == NORMAL) + calcSVPs(m_array.data(), m_path, screenCTM, &m_strokeSVP, &m_fillSVP); + else + calcClipSVP(ksvg_art_bez_path_to_vec(m_array.data(), 0.25), m_path, screenCTM, &m_fillSVP); + } + else if(!m_path->getAttribute("d").string().isEmpty()) + { + parseSVG(m_path->getAttribute("d").string(), true); + + int index = m_array.count(); + double curx = m_array[index - 1].x3; + double cury = m_array[index - 1].y3; + + // Find last subpath + int find = -1; + for(int i = index - 1; i >= 0; i--) + { + if(m_array[i].code == ART_MOVETO_OPEN || m_array[i].code == ART_MOVETO) + { + find = i; + break; + } + } + + // Fix a problem where the .svg file used floats as values... (sofico.svg) + if(curx != m_array[find].x3 && cury != m_array[find].y3) + { + if((int) curx == (int) m_array[find].x3 && (int) cury == (int) m_array[find].y3) + { + ensureSpace(m_array, index) + + m_array[index].code = ART_LINETO; + m_array[index].x3 = m_array[find].x3; + m_array[index].y3 = m_array[find].y3; + + curx = m_array[find].x3; + cury = m_array[find].y3; + + index++; + } + } + + // handle filled paths that are not closed explicitly + if(m_path->getFillColor()->paintType() != SVG_PAINTTYPE_NONE) + { + if((int) curx != (int) m_array[find].x3 || (int) cury != (int) m_array[find].y3) + { + ensureSpace(m_array, index) + + m_array[index].code = (ArtPathcode)ART_END2; + m_array[index].x3 = m_array[find].x3; + m_array[index].y3 = m_array[find].y3; + + curx = m_array[find].x3; + cury = m_array[find].y3; + + index++; + } + } + + // close + ensureSpace(m_array, index) + + m_array[index].code = ART_END; + + // A subpath consisting of a moveto and lineto to the same exact location or a subpath consisting of a moveto + // and a closepath will be stroked only if the 'stroke-linecap' property is set to "round", producing a circle + // centered at the given point. + if(index == 2 && m_array[1].code == ART_LINETO && m_array[1].x3 == m_array[0].x3 && m_array[1].y3 == m_array[0].y3 && m_path->getCapStyle() == PATH_STROKE_CAP_ROUND) + m_array[1].x3 += .5; + + // There are pure-moveto paths which reference paint servers *bah* + // Do NOT render them + bool render = false; + for(int i = index; i >= 0; i--) + { + if(m_array[i].code != ART_MOVETO_OPEN && m_array[i].code != ART_MOVETO && !(m_array[i].code >= ART_END)) + { + render = true; + break; + } + } + + if(render && m_context == NORMAL) + calcSVPs(m_array.data(), m_path, screenCTM, &m_strokeSVP, &m_fillSVP); + else + calcClipSVP(ksvg_art_bez_path_to_vec(m_array.data(), 0.25), m_path, screenCTM, &m_fillSVP); + } +} + +void LibartPath::svgMoveTo(double x1, double y1, bool closed, bool) +{ + int index = m_array.count(); + + if(index > 0 && !closed) + { + // Find last subpath + int find = -1; + for(int i = index - 1; i >= 0; i--) + { + if(m_array[i].code == ART_MOVETO_OPEN || m_array[i].code == ART_MOVETO) + { + find = i; + break; + } + } + + ensureSpace(m_array, index) + + m_array[index].code = (ArtPathcode) ART_END2; + m_array[index].x3 = m_array[find].x3; + m_array[index].y3 = m_array[find].y3; + + index++; + } + + ensureSpace(m_array, index) + + m_array[index].code = (index == 0) ? ART_MOVETO : ART_MOVETO_OPEN; + m_array[index].x3 = x1; + m_array[index].y3 = y1; +} + +void LibartPath::svgLineTo(double x1, double y1, bool) +{ + int index = m_array.count(); + + ensureSpace(m_array, index) + + m_array[index].code = ART_LINETO; + m_array[index].x3 = x1; + m_array[index].y3 = y1; +} + +void LibartPath::svgCurveToCubic(double x1, double y1, double x2, double y2, double x3, double y3, bool) +{ + int index = m_array.count(); + + ensureSpace(m_array, index) + + m_array[index].code = ART_CURVETO; + m_array[index].x1 = x1; + m_array[index].y1 = y1; + m_array[index].x2 = x2; + m_array[index].y2 = y2; + m_array[index].x3 = x3; + m_array[index].y3 = y3; +} + +void LibartPath::svgClosePath() +{ + int index = m_array.count(); + double curx = m_array[index - 1].x3; + double cury = m_array[index - 1].y3; + + int find = -1; + for(int i = index - 1; i >= 0; i--) + { + if(m_array[i].code == ART_MOVETO_OPEN || m_array[i].code == ART_MOVETO) + { + find = i; + break; + } + } + + if(find != -1) + { + if(m_array[find].x3 != curx || m_array[find].y3 != cury) + { + ensureSpace(m_array, index) + + m_array[index].code = ART_LINETO; + m_array[index].x3 = m_array[find].x3; + m_array[index].y3 = m_array[find].y3; + } + } +} + +// ##### + +LibartClipPath::LibartClipPath(LibartCanvas *c, SVGClipPathElementImpl *clipPath) +: CanvasClipPath(clipPath), m_canvas(c) +{ + m_clipSVP = 0; + m_clipItems.setAutoDelete(true); +} + +LibartClipPath::~LibartClipPath() +{ + if(m_clipSVP) + art_svp_free(m_clipSVP); +} + +void LibartClipPath::update(CanvasItemUpdate, int, int) +{ + if(m_clipSVP) + art_svp_free(m_clipSVP); + m_clipSVP = 0; +} + +void LibartClipPath::init() +{ + SVGMatrixImpl *clipMatrix = 0; + + // Start with referencing element's coordinate system + SVGLocatableImpl *locatableReferrer = dynamic_cast(m_clipPath->getBBoxTarget()); + if(locatableReferrer) + clipMatrix = locatableReferrer->getScreenCTM(); + else + clipMatrix = SVGSVGElementImpl::createSVGMatrix(); + + if(m_clipPath->clipPathUnits()->baseVal() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX && m_clipPath->getBBoxTarget()) + { + SVGRectImpl *rect = m_clipPath->getBBoxTarget()->getBBox(); + + clipMatrix->translate(rect->qrect().x(), rect->qrect().y()); + clipMatrix->scaleNonUniform(rect->qrect().width(), rect->qrect().height()); + + rect->deref(); + } + + // Add transformations on the clipPath element itself + if(m_clipPath->localMatrix()) + clipMatrix->multiply(m_clipPath->localMatrix()); + + if(m_clipSVP) + { + art_svp_free(m_clipSVP); + m_clipSVP = 0; + } + + DOM::Node node = m_clipPath->firstChild(); + for(; !node.isNull(); node = node.nextSibling()) + { + SVGElementImpl *element = m_clipPath->ownerDoc()->getElementFromHandle(node.handle()); + SVGShapeImpl *shape = dynamic_cast(element); + SVGTestsImpl *tests = dynamic_cast(element); + + bool ok = tests ? tests->ok() : true; + + if(element && shape && ok && !shape->isContainer()) + { + LibartClipItem *clipElement = dynamic_cast(shape->item()); + + if(dynamic_cast(shape->item())) + { + // The cast to a clipElement above is failing when it is valid. But only + // in the plugin - svgdisplay works fine. What's going on? (Adrian) + clipElement = dynamic_cast(shape->item()); + } + + if(clipElement) + { + clipElement->setRenderContext(CLIPPING); + + // Push coordinate system down to children. + SVGLocatableImpl *locatable = dynamic_cast(shape); + if(locatable) + locatable->updateCachedScreenCTM(clipMatrix); + + clipElement->initClipItem(); + + ArtSVP *one = clipElement->clipSVP(); + if(!one) + break; + + if(m_clipSVP == 0) + m_clipSVP = LibartCanvas::copy_svp(one); + else + { + ArtSVP *svp_union = art_svp_union(m_clipSVP, one); + art_svp_free(m_clipSVP); + m_clipSVP = svp_union; + } + } + } + } + + clipMatrix->deref(); +} + +void LibartClipPath::draw() +{ +} + +ArtSVP *LibartClipPath::clipSVP() +{ + return m_clipSVP; +} + +// ##### + +LibartImage::LibartImage(LibartCanvas *c, SVGImageElementImpl *image) +: m_canvas(c), m_image(image) +{ +} + +LibartImage::~LibartImage() +{ +} + +void LibartImage::draw() +{ + if(isVisible()) + { + SVGMatrixImpl *ctm = m_image->scaledImageMatrix(); + QImage image = m_image->scaledImage(); + KSVGPolygon clippingPolygon = m_image->clippingShape(); + + m_canvas->drawImage(image, m_image, ctm, clippingPolygon); + + ctm->deref(); + } +} + +bool LibartImage::isVisible() +{ + return (m_referenced || (m_image->getVisible() && m_image->getDisplay() && m_image->directRender())) && m_image->image(); +} + +void LibartImage::init() +{ +} + +QRect LibartImage::bbox() const +{ + QRect bbox(static_cast(m_image->x()->baseVal()->value()), + static_cast(m_image->y()->baseVal()->value()), + static_cast(m_image->width()->baseVal()->value()), + static_cast(m_image->height()->baseVal()->value())); + + + return SVGHelperImpl::fromUserspace(m_image, bbox); +} + +// ##### + +LibartMarker::LibartMarker(LibartCanvas *c, SVGMarkerElementImpl *marker) +: CanvasMarker(marker), m_canvas(c) +{ +} + +LibartMarker::~LibartMarker() +{ +} + +void LibartMarker::init() +{ +} + +void LibartMarker::draw() +{ +} + +// ##### + +LibartText::LibartText(LibartCanvas *c, SVGTextElementImpl *text) +: CanvasText(text), m_canvas(c) +{ + m_drawFillItems.setAutoDelete(true); + m_drawStrokeItems.setAutoDelete(true); + m_fillPainters.setAutoDelete(true); + m_strokePainters.setAutoDelete(true); + + init(); +} + +LibartText::~LibartText() +{ + clearSVPs(); +} + +LibartText::SVPElement::~SVPElement() +{ + if(svp) + art_svp_free(svp); +} + +QRect LibartText::bbox() const +{ + QRect result, rect; + + QPtrListIterator it1(m_drawFillItems); + QPtrListIterator it2(m_drawStrokeItems); + + SVPElement *fill = it1.current(), *stroke = it2.current(); + while(fill != 0 || stroke != 0) + { + ArtIRect *irect = new ArtIRect(); + ArtVpath *vpath = art_vpath_from_svp((stroke && stroke->svp) ? stroke->svp : fill->svp); + art_vpath_bbox_irect(vpath, irect); + art_free(vpath); + + rect.setX(irect->x0); + rect.setY(irect->y0); + rect.setWidth(irect->x1 - irect->x0); + rect.setHeight(irect->y1 - irect->y0); + + delete irect; + + result = result.unite(rect); + + fill = ++it1; + stroke = ++it2; + } + return result; +} + +bool LibartText::fillContains(const QPoint &p) +{ + QPtrListIterator it(m_drawFillItems); + + SVPElement *fill = it.current(); + while(fill && fill->svp) + { + if(fill->svp && art_svp_point_wind(fill->svp, p.x(), p.y()) != 0) + return true; + + fill = ++it; + } + + return false; +} + +bool LibartText::strokeContains(const QPoint &p) +{ + QPtrListIterator it(m_drawStrokeItems); + + SVPElement *stroke = it.current(); + while(stroke && stroke->svp) + { + if(stroke->svp && art_svp_point_wind(stroke->svp, p.x(), p.y()) != 0) + return true; + + stroke = ++it; + } + + return false; +} + +void LibartText::update(CanvasItemUpdate reason, int param1, int param2) +{ + if(reason == UPDATE_STYLE) + { + QPtrListIterator it1(m_drawFillItems); + QPtrListIterator it2(m_drawStrokeItems); + SVPElement *fill = it1.current(), *stroke = it2.current(); + while(fill != 0 || stroke != 0) + { + SVGTextContentElementImpl *text = fill ? fill->element : stroke->element; + + bool fillOk = fill && fill->svp && text->isFilled(); + bool strokeOk = stroke && stroke->svp && text->isStroked() && text->getStrokeWidth()->baseVal()->value() > 0; // Spec: A zero value causes no stroke to be painted. + if(fillOk || strokeOk) + { + if(m_fillPainters.find(text)) + m_fillPainters[text]->update(text); + + if(m_strokePainters.find(text)) + m_strokePainters[text]->update(text); + } + fill = ++it1; + stroke = ++it2; + } + m_canvas->invalidate(this, false); + } + else if(reason == UPDATE_TRANSFORM) + { + clearSVPs(); + init(); + m_canvas->invalidate(this, true); + } + else if(reason == UPDATE_ZOOM) + { + clearSVPs(); + init(); + } + else if(reason == UPDATE_PAN) + { + QPtrListIterator it1(m_drawFillItems); + QPtrListIterator it2(m_drawStrokeItems); + + double affine[6]; + KSVGHelper::matrixToAffine(m_text->screenCTM(), affine); + + SVPElement *fill = it1.current(), *stroke = it2.current(); + while(fill != 0 || stroke != 0) + { + SVGTextContentElementImpl *text = fill ? fill->element : stroke->element; + + bool fillOk = fill && fill->svp && text->isFilled(); + bool strokeOk = stroke && stroke->svp && text->isStroked() && text->getStrokeWidth()->baseVal()->value() > 0; // Spec: A zero value causes no stroke to be painted. + + if(fillOk) + ksvg_art_svp_move(fill->svp, param1, param2); + if(strokeOk) + ksvg_art_svp_move(stroke->svp, param1, param2); + fill = ++it1; + stroke = ++it2; + } + } + /* + else if(reason == UPDATE_LINEWIDTH) + { + }*/ +} + +void LibartText::draw() +{ + QPtrListIterator it1(m_drawFillItems); + QPtrListIterator it2(m_drawStrokeItems); + + SVPElement *fill = it1.current(), *stroke = it2.current(); + while(fill != 0 || stroke != 0) + { + SVGTextContentElementImpl *text = fill ? fill->element : stroke->element; + if(!text || !text->getVisible() || !text->getDisplay() || !text->directRender()) + return; + + bool fillOk = fill && fill->svp && text->isFilled(); + bool strokeOk = stroke && stroke->svp && text->isStroked() && text->getStrokeWidth()->baseVal()->value() > 0; // Spec: A zero value causes no stroke to be painted. + + if(fillOk || strokeOk) + { + if(fillOk && m_fillPainters.find(text)) + m_fillPainters[text]->draw(m_canvas, fill->svp, text, text); + + if(strokeOk && m_strokePainters.find(text)) + m_strokePainters[text]->draw(m_canvas, stroke->svp, text, text); + } + fill = ++it1; + stroke = ++it2; + } +} + +bool LibartText::isVisible() +{ + bool foundVisible = false; + QPtrListIterator it1(m_drawFillItems); + QPtrListIterator it2(m_drawStrokeItems); + + SVPElement *fill = it1.current(), *stroke = it2.current(); + while(fill != 0 || stroke != 0) + { + SVGTextContentElementImpl *text = fill ? fill->element : stroke->element; + if(text && text->getVisible() && text->getDisplay() && text->directRender()) + { + foundVisible = true; + break; + } + + fill = ++it1; + stroke = ++it2; + } + + return foundVisible; +} + +void LibartText::init() +{ + init(m_text->screenCTM()); +} + +void LibartText::renderCallback(SVGTextContentElementImpl *element, const SVGMatrixImpl *screenCTM, T2P::GlyphSet *glyph, T2P::GlyphLayoutParams *params, double anchor) const +{ + unsigned int glyphCount = glyph->glyphCount(); // Don't call it n times in the for loop + for(unsigned int i = 0; i < glyphCount; i++) + { + T2P::GlyphAffinePair *glyphAffine = glyph->set()[i]; + ArtBpath *bezier = static_cast(glyphAffine->transformatedPath())->m_array.data(); + ArtBpath *result = bezier; + + // text-anchor support + if(anchor != 0) + { + double correct[6]; + + if(!params->tb()) + art_affine_translate(correct, -anchor, 0); + else + art_affine_translate(correct, 0, -anchor); + + ArtBpath *temp = art_bpath_affine_transform(result, correct); + //art_free(result); + result = temp; + } + + ArtSVP *fillSVP = 0, *strokeSVP = 0; + + if(m_context == NORMAL) + LibartShape::calcSVPs(result, m_text, screenCTM, &strokeSVP, &fillSVP); + else + LibartShape::calcClipSVP(ksvg_art_bez_path_to_vec(result, 0.25), m_text, screenCTM, &fillSVP); + + SVPElement *fillElement = new SVPElement(); + fillElement->svp = fillSVP; + fillElement->element = element; + + SVPElement *strokeElement = new SVPElement(); + strokeElement->svp = strokeSVP; + strokeElement->element = element; + + m_drawFillItems.append(fillElement); + m_drawStrokeItems.append(strokeElement); + + if(!m_fillPainters.find(element) && element->isFilled()) + m_fillPainters.insert(element, new LibartFillPainter(element)); + + // Spec: A zero value causes no stroke to be painted. + if(!m_strokePainters.find(element) && element->isStroked() && element->getStrokeWidth()->baseVal()->value() > 0) + m_strokePainters.insert(element, new LibartStrokePainter(element)); + } +} + +void LibartText::init(const SVGMatrixImpl *screenCTM) +{ + int curx = 0, cury = 0, endx = 0, endy = 0; + KSVGTextChunk *textChunk = CanvasText::createTextChunk(m_canvas, screenCTM, curx, cury, endx, endy); + + if(textChunk->count() > 0) + CanvasText::createGlyphs(textChunk, m_canvas, screenCTM, curx, cury, endx, endy); + + delete textChunk; +} + +void LibartText::clearSVPs() +{ + m_drawFillItems.clear(); + m_drawStrokeItems.clear(); + m_fillPainters.clear(); + m_strokePainters.clear(); +} + +void LibartText::addTextDecoration(SVGTextContentElementImpl *element, double x, double y, double width, double height) const +{ + if(m_text->isFilled() || m_text->isStroked()) + { + // compute rect svp + ArtVpath *vec = allocVPath(6); + + vec[0].code = ART_MOVETO; + vec[0].x = x; + vec[0].y = y; + + vec[1].code = ART_LINETO; + vec[1].x = x; + vec[1].y = y + height; + + vec[2].code = ART_LINETO; + vec[2].x = x + width; + vec[2].y = y + height; + + vec[3].code = ART_LINETO; + vec[3].x = x + width; + vec[3].y = y; + + vec[4].code = ART_LINETO; + vec[4].x = x; + vec[4].y = y; + + vec[5].code = ART_END; + double affine[6]; + KSVGHelper::matrixToAffine(m_text->screenCTM(), affine); + + ArtVpath *temp = art_vpath_affine_transform(vec, affine); + art_free(vec); + vec = temp; + + if(m_text->isFilled()) + { + ArtSvpWriter *swr; + ArtSVP *temp = art_svp_from_vpath(vec); + + swr = art_svp_writer_rewind_new(ART_WIND_RULE_ODDEVEN); + + art_svp_intersector(temp, swr); + ArtSVP *fillSVP = art_svp_writer_rewind_reap(swr); + + SVPElement *fillElement = new SVPElement(); + fillElement->svp = fillSVP; + fillElement->element = element; + + m_drawFillItems.append(fillElement); + + if(!m_fillPainters.find(element) && element->isFilled()) + m_fillPainters.insert(element, new LibartFillPainter(element)); + + art_svp_free(temp); + } + // Stroking + if(m_text->isStroked() || m_text->getStrokeColor()->paintType() == SVG_PAINTTYPE_URI) + { + double ratio = art_affine_expansion(affine); + ArtSVP *strokeSVP = art_svp_vpath_stroke(vec, (ArtPathStrokeJoinType)m_text->getJoinStyle(), (ArtPathStrokeCapType)m_text->getCapStyle(), m_text->getStrokeWidth()->baseVal()->value() * ratio, m_text->getStrokeMiterlimit(), 0.25); + + SVPElement *strokeElement = new SVPElement(); + strokeElement->svp = strokeSVP; + strokeElement->element = element; + + m_drawStrokeItems.append(strokeElement); + + // Spec: A zero value causes no stroke to be painted. + if(!m_strokePainters.find(element) && element->isStroked() && element->getStrokeWidth()->baseVal()->value() > 0) + m_strokePainters.insert(element, new LibartStrokePainter(element)); + } + art_free(vec); + } +} + +void LibartText::initClipItem() +{ + init(); +} + +ArtSVP *LibartText::clipSVP() +{ + ArtSVP *svp = 0; + QPtrListIterator it(m_drawFillItems); + + SVPElement *fill = it.current(); + while(fill && fill->svp) + { + if(svp == 0) + svp = LibartCanvas::copy_svp(fill->svp); + else + { + ArtSVP *svp_union = art_svp_union(svp, fill->svp); + art_svp_free(svp); + svp = svp_union; + } + + fill = ++it; + } + + return svp; +} + +ArtRender *LibartPaintServer::createRenderer(QRect bbox, KSVGCanvas *c) +{ + int x0 = bbox.x(); + int y0 = bbox.y(); + int x1 = bbox.right(); + int y1 = bbox.bottom(); + + c->clipToBuffer(x0, y0, x1, y1); + + // Note: We always pass 3 for the number of channels since the ART_ALPHA parameter + // adds the alpha channel when present. + ArtRender *render = 0; + render = art_render_new(QMIN(x0, x1), + QMIN(y0, y1), + QMAX(x0, x1) + 1, + QMAX(y0, y1) + 1, + c->renderingBuffer() + x0 * c->nrChannels() + y0 * c->rowStride(), + c->rowStride(), 3, 8, + c->nrChannels() == 3 ? ART_ALPHA_NONE : ART_ALPHA_PREMUL, 0); + + return render; +} + +void LibartGradient::parseGradientStops(SVGGradientElementImpl *gradient) +{ + const double epsilon = DBL_EPSILON; + + for(DOM::Node node = gradient->firstChild(); !node.isNull(); node = node.nextSibling()) + { + SVGStopElementImpl *elem = dynamic_cast(m_gradient->ownerDoc()->getElementFromHandle(node.handle())); + if(elem) + { + m_stops.resize(m_stops.size() + 1); + + ArtGradientStop *stop = &(m_stops[m_stops.size() - 1]); + + stop->offset = elem->offset()->baseVal(); + + // Spec: clamp range to 0 to 1 + if(stop->offset < epsilon) + stop->offset = 0; + else if(stop->offset > 1 - epsilon) + stop->offset = 1; + + // Spec: if offset is less than previous offset, set it to the previous offset + if(m_stops.size() > 1 && stop->offset < (stop - 1)->offset + epsilon) + stop->offset = (stop - 1)->offset; + + // Get color + QColor qStopColor; + + if(elem->getStopColor()->colorType() == SVG_COLORTYPE_CURRENTCOLOR) + qStopColor = elem->getColor()->rgbColor().color(); + else + qStopColor = elem->getStopColor()->rgbColor().color(); + + // Convert in a libart suitable form + QString tempName = qStopColor.name(); + const char *str = tempName.latin1(); + + int stopColor = 0; + + for(int i = 1; str[i]; i++) + { + int hexval; + if(str[i] >= '0' && str[i] <= '9') + hexval = str[i] - '0'; + else if (str[i] >= 'A' && str[i] <= 'F') + hexval = str[i] - 'A' + 10; + else if (str[i] >= 'a' && str[i] <= 'f') + hexval = str[i] - 'a' + 10; + else + break; + + stopColor = (stopColor << 4) + hexval; + } + + // Apply stop-opacity + float opacity = elem->stopOpacity(); + + // Get rgba color including stop-opacity + Q_UINT32 rgba = (stopColor << 8) | int(opacity * 255.0 + 0.5); + Q_UINT32 r, g, b, a; + + a = rgba & 0xff; + r = (rgba >> 24) & 0xff; + g = (rgba >> 16) & 0xff; + b = (rgba >> 8) & 0xff; + + stop->color[0] = ART_PIX_MAX_FROM_8(r); + stop->color[1] = ART_PIX_MAX_FROM_8(g); + stop->color[2] = ART_PIX_MAX_FROM_8(b); + stop->color[3] = ART_PIX_MAX_FROM_8(a); + } + } +} + +void LibartGradient::finalizePaintServer() +{ + parseGradientStops(m_gradient->stopsSource()); + + QString _href = SVGURIReferenceImpl::getTarget(m_gradient->href()->baseVal().string()); + if(!_href.isEmpty()) + reference(_href); + + setFinalized(); +} + +void LibartGradient::reference(const QString &) +{ +} + +void LibartLinearGradient::render(KSVGCanvas *c, ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox) +{ + if(!m_stops.isEmpty()) + { + m_linear->converter()->finalize(getBBoxTarget(), m_linear->ownerSVGElement(), m_linear->gradientUnits()->baseVal()); + + ArtKSVGGradientLinear *linear = art_new(ArtKSVGGradientLinear, 1); + + if(m_linear->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REPEAT) + linear->spread = ART_GRADIENT_REPEAT; + else if(m_linear->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REFLECT) + linear->spread = ART_GRADIENT_REFLECT; + else + linear->spread = ART_GRADIENT_PAD; + + linear->interpolation = m_linear->getColorInterpolation() == CI_SRGB ? ART_KSVG_SRGB_INTERPOLATION : ART_KSVG_LINEARRGB_INTERPOLATION; + + ArtRender *render = createRenderer(screenBBox, c); + + double _x1 = m_linear->x1()->baseVal()->value(); + double _y1 = m_linear->y1()->baseVal()->value(); + double _x2 = m_linear->x2()->baseVal()->value(); + double _y2 = m_linear->y2()->baseVal()->value(); + + // Respect current transformation matrix (so gradients zoom with...) + SVGTransformableImpl *transformable = dynamic_cast(getBBoxTarget()); + SVGMatrixImpl *matrix = 0; + if(transformable) + matrix = transformable->getScreenCTM(); + else + matrix = SVGSVGElementImpl::createSVGMatrix(); + + const double epsilon = DBL_EPSILON; + + if(m_linear->gradientUnits()->baseVal() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) + { + // Here we're undoing the unit-converter's work because putting the + // bounding box transform into the matrix here lets the gradient transform + // sit at the right point in the chain to work with bounding box coordinates. It + // also removes the need for code to generate the 'not perpendicular to gradient vector' effect. + SVGRectImpl *userBbox = getBBoxTarget()->getBBox(); + + double width = userBbox->width(); + double height = userBbox->height(); + + // Catch case of width or height of zero, which can be the case for lines. + if(width < epsilon) + width = 1; + if(height < epsilon) + height = 1; + + _x1 /= width; + _y1 /= height; + _x2 /= width; + _y2 /= height; + + matrix->translate(userBbox->x(), userBbox->y()); + matrix->scaleNonUniform(width, height); + + userBbox->deref(); + } + + // Adjust to gradient transform + SVGMatrixImpl *gradTrans = m_linear->gradientTransform()->baseVal()->concatenate(); + if(gradTrans) + { + matrix->multiply(gradTrans); + gradTrans->deref(); + } + + double dx = _x2 - _x1; + double dy = _y2 - _y1; + + if(fabs(dx) < epsilon && fabs(dy) < epsilon) + { + // Lines can generate (0, 0) with bbox coords. + dx = 1; + dy = 0; + } + + double angle = atan2(dy, dx); + double length = sqrt(dx * dx + dy * dy); + + const double pi = 3.14159265358979323846; + + matrix->translate(_x1, _y1); + matrix->scale(length); + matrix->rotate(angle * 180.0 / pi); + + double affine[6]; + + KSVGHelper::matrixToAffine(matrix, affine); + art_affine_invert(linear->affine, affine); + + matrix->deref(); + + QMemArray stops = m_stops; + stops.detach(); + + for(unsigned int i = 0; i < stops.size(); i++) + stops[i].color[3] = ArtPixMaxDepth(stops[i].color[3] * opacity + 0.5); + + if(m_linear->x1()->baseVal()->valueInSpecifiedUnits() == m_linear->x2()->baseVal()->valueInSpecifiedUnits() + && m_linear->y1()->baseVal()->valueInSpecifiedUnits() == m_linear->y2()->baseVal()->valueInSpecifiedUnits()) + { + // Spec: If x1 == x2 and y1 == y2, paint the area in a single colour, using the colour + // of the last stop. + // + // Using valueInSpecifiedUnits() so that we are comparing the values before possible + // conversion to bounding box units by the converter. + if(stops.size() > 1) + { + stops[0] = stops[stops.size() - 1]; + stops.resize(1); + } + } + + linear->stops = &(stops[0]); + linear->n_stops = stops.size(); + + art_render_svp(render, svp); + art_ksvg_render_gradient_linear(render, linear, ART_FILTER_HYPER); + + if(mask.data()) + art_render_mask(render, screenBBox.left(), screenBBox.top(), screenBBox.right() + 1, screenBBox.bottom() + 1, + (const art_u8 *)mask.data(), screenBBox.width()); + + art_render_invoke(render); + + art_free(linear); + } +} + +void LibartRadialGradient::render(KSVGCanvas *c, ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox) +{ + if(!m_stops.isEmpty()) + { + m_radial->converter()->finalize(getBBoxTarget(), m_radial->ownerSVGElement(), m_radial->gradientUnits()->baseVal()); + + ArtKSVGGradientRadial *radial = art_new(ArtKSVGGradientRadial, 1); + + if(m_radial->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REPEAT) + radial->spread = ART_GRADIENT_REPEAT; + else if(m_radial->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REFLECT) + radial->spread = ART_GRADIENT_REFLECT; + else + radial->spread = ART_GRADIENT_PAD; + + radial->interpolation = m_radial->getColorInterpolation() == CI_SRGB ? ART_KSVG_SRGB_INTERPOLATION : ART_KSVG_LINEARRGB_INTERPOLATION; + + ArtRender *render = createRenderer(screenBBox, c); + + // Respect current transformation matrix (so gradients zoom with...) + SVGTransformableImpl *transformable = dynamic_cast(getBBoxTarget()); + SVGMatrixImpl *matrix = 0; + if(transformable) + matrix = transformable->getScreenCTM(); + else + matrix = SVGSVGElementImpl::createSVGMatrix(); + + double _cx = m_radial->cx()->baseVal()->value(); + double _cy = m_radial->cy()->baseVal()->value(); + double _r = m_radial->r()->baseVal()->value(); + + double _fx; + double _fy; + + // Spec: If attribute fx is not specified, fx will coincide with cx. + if(m_radial->getAttribute("fx").isEmpty()) + _fx = _cx; + else + _fx = m_radial->fx()->baseVal()->value(); + + // Spec: If attribute fy is not specified, fy will coincide with cy. + if(m_radial->getAttribute("fy").isEmpty()) + _fy = _cy; + else + _fy = m_radial->fy()->baseVal()->value(); + + const double epsilon = DBL_EPSILON; + + if(m_radial->gradientUnits()->baseVal() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) + { + // Here we're undoing the unit-converter's work because putting the + // bounding box transform into the matrix here lets the gradient transform + // sit at the right point in the chain to work with bounding box coordinates. + // It also produces the elliptical shape due to the non-uniform scaling. + SVGRectImpl *userBBox = getBBoxTarget()->getBBox(); + + double width = userBBox->width(); + double height = userBBox->height(); + + // Catch case of width or height of zero, which can be the case for lines. + if(width < epsilon) + width = 1; + if(height < epsilon) + height = 1; + + _cx /= width; + _cy /= height; + _fx /= width; + _fy /= height; + _r /= (sqrt(width * width + height * height) / 1.4142135623731); + + matrix->translate(userBBox->x(), userBBox->y()); + matrix->scaleNonUniform(width, height); + + userBBox->deref(); + } + + // Adjust to gradient transforms + SVGMatrixImpl *transform = m_radial->gradientTransform()->baseVal()->concatenate(); + + if(transform) + { + matrix->multiply(transform); + transform->deref(); + } + + double fx = (_fx - _cx) / _r; + double fy = (_fy - _cy) / _r; + + if(fx * fx + fy * fy > 0.99) + { + // Spec: If (fx, fy) lies outside the circle defined by (cx, cy) and r, set (fx, fy) + // to the point of intersection of the line through (fx, fy) and the circle. + // + // Note: We need to keep (fx, fy) inside the unit circle in order for + // libart to render the gradient correctly. + double angle = atan2(fy, fx); + fx = cos(angle) * 0.99; + fy = sin(angle) * 0.99; + } + + radial->fx = fx; + radial->fy = fy; + + matrix->translate(_cx, _cy); + matrix->scale(_r); + + double affine[6]; + + KSVGHelper::matrixToAffine(matrix, affine); + art_affine_invert(radial->affine, affine); + + matrix->deref(); + + QMemArray stops = m_stops; + stops.detach(); + + for(unsigned int i = 0; i < stops.size(); i++) + stops[i].color[3] = ArtPixMaxDepth(stops[i].color[3] * opacity + 0.5); + + radial->stops = &(stops[0]); + radial->n_stops = stops.size(); + + art_render_svp(render, svp); + art_ksvg_render_gradient_radial(render, radial, ART_FILTER_HYPER); + + if(mask.data()) + art_render_mask(render, screenBBox.left(), screenBBox.top(), screenBBox.right() + 1, screenBBox.bottom() + 1, + (const art_u8 *)mask.data(), screenBBox.width()); + + art_render_invoke(render); + + art_free(radial); + } +} + +LibartPattern::LibartPattern(SVGPatternElementImpl *pattern) + : m_pattern(pattern) +{ +} + +void LibartPattern::finalizePaintServer() +{ + m_pattern->finalizePaintServer(); + setFinalized(); +} + +void LibartPattern::reference(const QString &href) +{ + m_pattern->reference(href); +} + +void LibartPattern::render(KSVGCanvas *c, ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox) +{ + SVGPatternElementImpl::Tile tile = m_pattern->createTile(getBBoxTarget()); + + if(!tile.image().isNull()) + { + QWMatrix m = tile.screenToTile(); + double affine[6]; + + affine[0] = m.m11(); + affine[1] = m.m12(); + affine[2] = m.m21(); + affine[3] = m.m22(); + affine[4] = m.dx(); + affine[5] = m.dy(); + + int alpha = int(opacity * 255 + 0.5); + + ksvg_art_rgb_texture(svp, c->renderingBuffer() + screenBBox.x() * c->nrChannels() + screenBBox.y() * c->rowStride(), screenBBox.left(), screenBBox.top(), screenBBox.right() + 1, screenBBox.bottom() + 1, c->rowStride(), c->nrChannels(), tile.image().bits(), tile.image().width(), tile.image().height(), tile.image().width() * 4, affine, ART_FILTER_NEAREST, 0L, alpha, (art_u8 *)mask.data()); + } +} + +// vim:ts=4:noet diff --git a/ksvg/plugin/backends/libart/LibartCanvasItems.h b/ksvg/plugin/backends/libart/LibartCanvasItems.h new file mode 100644 index 00000000..c62224e5 --- /dev/null +++ b/ksvg/plugin/backends/libart/LibartCanvasItems.h @@ -0,0 +1,414 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint 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 LIBARTCANVASITEMS_H +#define LIBARTCANVASITEMS_H + +#include + +#include "CanvasItems.h" +#include "LibartCanvas.h" +#include "BezierPathLibart.h" + +#include "SVGPathElementImpl.h" +#include "SVGPolyElementImpl.h" +#include "SVGLineElementImpl.h" +#include "SVGRectElementImpl.h" +#include "SVGTextElementImpl.h" +#include "SVGCircleElementImpl.h" +#include "SVGEllipseElementImpl.h" + +// Helpers +#define allocVPath(n) art_new(ArtVpath, n) +#define allocBPath(n) art_new(ArtBpath, n) + +#define LIBART_CLASS(Class, Type, Member) \ +class Libart##Class : public LibartShape \ +{ \ +public: \ + Libart##Class(LibartCanvas *c, Type *Member); \ + virtual ~Libart##Class() { } \ + virtual void draw(); \ + virtual bool isVisible(); \ + virtual void init(); \ + virtual void init(const SVGMatrixImpl *screenCTM); \ + virtual SVGElementImpl *element() const { return m_##Member; } \ +protected: \ + Type *m_##Member; \ +}; + +struct _ArtSVP; +struct _ArtBpath; +struct _ArtRender; +struct _ArtGradientStop; + +namespace KSVG +{ + class SVGImageElementImpl; + class SVGGradientElementImpl; + class SVGRadialGradientElementImpl; + class SVGLinearGradientElementImpl; + class SVGPatternElementImpl; + + class LibartPaintServer : public CanvasPaintServer + { + public: + LibartPaintServer() : CanvasPaintServer() {} + virtual ~LibartPaintServer() {} + + virtual void render(KSVGCanvas *c, _ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox) = 0; + + _ArtRender *createRenderer(QRect rect, KSVGCanvas *c); + }; + + class LibartGradient : public LibartPaintServer + { + public: + LibartGradient(SVGGradientElementImpl *gradient) : m_gradient(gradient) {} + virtual ~LibartGradient() {} + + void parseGradientStops(SVGGradientElementImpl *gradient); + + virtual void finalizePaintServer(); + virtual void reference(const QString &href); + + protected: + SVGGradientElementImpl *m_gradient; + QMemArray<_ArtGradientStop> m_stops; + }; + + class LibartLinearGradient : public LibartGradient + { + public: + LibartLinearGradient(SVGLinearGradientElementImpl *linear) : LibartGradient(linear), m_linear(linear) {} + + virtual void render(KSVGCanvas *c, _ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox); + + protected: + SVGLinearGradientElementImpl *m_linear; + }; + + class LibartRadialGradient : public LibartGradient + { + public: + LibartRadialGradient(SVGRadialGradientElementImpl *radial) : LibartGradient(radial), m_radial(radial) {} + + virtual void render(KSVGCanvas *c, _ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox); + + protected: + SVGRadialGradientElementImpl *m_radial; + }; + + class LibartPattern : public LibartPaintServer + { + public: + LibartPattern(SVGPatternElementImpl *pattern); + virtual ~LibartPattern() {} + + virtual void finalizePaintServer(); + virtual void reference(const QString &href); + + virtual void render(KSVGCanvas *c, _ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox); + + protected: + SVGPatternElementImpl *m_pattern; + }; + + class LibartPainter + { + public: + LibartPainter() { m_color = 0; } + virtual ~LibartPainter() {} + + void update(SVGStylableImpl *style); + void draw(LibartCanvas *canvas, _ArtSVP *svp, SVGStylableImpl *style, SVGShapeImpl *shape); + + virtual float opacity(SVGStylableImpl *style) const = 0; + virtual unsigned short paintType(SVGStylableImpl *style) const = 0; + virtual QString paintUri(SVGStylableImpl *style) const = 0; + virtual QRgb color(SVGStylableImpl *style) const = 0; + + protected: + art_u32 m_color; + }; + + class LibartFillPainter : public LibartPainter + { + public: + LibartFillPainter(SVGStylableImpl *style); + + float opacity(SVGStylableImpl *style) const { return style->getFillOpacity() * style->getOpacity(); } + unsigned short paintType(SVGStylableImpl *style) const { return style->getFillColor()->paintType(); } + QString paintUri(SVGStylableImpl *style) const { return style->getFillColor()->uri().string(); } + QRgb color(SVGStylableImpl *style) const { return style->getFillColor()->rgbColor().color(); } + }; + + class LibartStrokePainter : public LibartPainter + { + public: + LibartStrokePainter(SVGStylableImpl *style); + + float opacity(SVGStylableImpl *style) const { return style->getStrokeOpacity() * style->getOpacity(); } + unsigned short paintType(SVGStylableImpl *style) const { return style->getStrokeColor()->paintType(); } + QString paintUri(SVGStylableImpl *style) const { return style->getStrokeColor()->uri().string(); } + QRgb color(SVGStylableImpl *style) const { return style->getStrokeColor()->rgbColor().color(); } + }; + + class LibartClipItem + { + public: + LibartClipItem() { m_context = NORMAL; } + virtual ~LibartClipItem() {} + + virtual void initClipItem() = 0; + void setRenderContext(RenderContext context) { m_context = context; } + virtual ArtSVP *clipSVP() = 0; + + protected: + RenderContext m_context; + }; + + class LibartShape : public CanvasItem, public LibartClipItem + { + public: + LibartShape(LibartCanvas *c, SVGStylableImpl *style); + virtual ~LibartShape(); + + virtual QRect bbox() const; + virtual bool fillContains(const QPoint &p); + virtual bool strokeContains(const QPoint &p); + virtual void update(CanvasItemUpdate reason, int param1 = 0, int param2 = 0); + void draw(SVGShapeImpl *shape); + bool isVisible(SVGShapeImpl *shape); + + virtual void init(); + virtual void init(const SVGMatrixImpl *); + virtual void reset() { freeSVPs(); init(); } + + void initClipItem(); + ArtSVP *clipSVP(); + + static void calcClipSVP(ArtVpath *vec, SVGStylableImpl *style, const SVGMatrixImpl *matrix, _ArtSVP **clipSVP); + static void calcSVPs(ArtVpath *vec, SVGStylableImpl *style, const SVGMatrixImpl *matrix, _ArtSVP **strokeSVP, _ArtSVP **fillSVP); + static void calcSVPs(_ArtBpath *bpath, SVGStylableImpl *style, const SVGMatrixImpl *matrix, _ArtSVP **strokeSVP, _ArtSVP **fillSVP); + + protected: + void freeSVPs(); + static void calcSVPInternal(ArtVpath *vec, SVGStylableImpl *style, double *affine, ArtSVP **strokeSVP, ArtSVP **fillSVP); + + _ArtSVP *m_fillSVP; + _ArtSVP *m_strokeSVP; + LibartFillPainter *m_fillPainter; + LibartStrokePainter *m_strokePainter; + LibartCanvas *m_canvas; + SVGStylableImpl *m_style; + }; + + LIBART_CLASS(Rectangle, SVGRectElementImpl, rect) + LIBART_CLASS(Ellipse, SVGEllipseElementImpl, ellipse) + LIBART_CLASS(Circle, SVGCircleElementImpl, circle) + + class LibartLine : public LibartShape, public MarkerHelper + { + public: + LibartLine(LibartCanvas *c, SVGLineElementImpl *line); + virtual ~LibartLine(); + + virtual void draw(); + virtual bool isVisible(); + virtual void init(); + virtual void init(const SVGMatrixImpl *screenCTM); + + virtual SVGElementImpl *element() const { return m_line; } + + protected: + SVGLineElementImpl *m_line; + }; + + class LibartPoly : public LibartShape, public MarkerHelper + { + public: + LibartPoly(LibartCanvas *c, SVGPolyElementImpl *poly); + virtual ~LibartPoly(); + + virtual void draw(); + virtual bool isVisible(); + virtual void init(); + virtual void init(const SVGMatrixImpl *screenCTM) = 0; + + virtual SVGElementImpl *element() const { return m_poly; } + + protected: + SVGPolyElementImpl *m_poly; + + }; + class LibartPolyline : public LibartPoly + { + public: + LibartPolyline(LibartCanvas *c, SVGPolylineElementImpl *poly); + virtual ~LibartPolyline(); + + virtual void init(const SVGMatrixImpl *screenCTM); + }; + + class LibartPolygon : public LibartPoly + { + public: + LibartPolygon(LibartCanvas *c, SVGPolygonElementImpl *poly); + virtual ~LibartPolygon(); + + virtual void init(const SVGMatrixImpl *screenCTM); + }; + + class LibartPath : public LibartShape, public MarkerHelper, public T2P::BezierPathLibart, public ::SVGPathParser + { + public: + LibartPath(LibartCanvas *c, SVGPathElementImpl *path); + virtual ~LibartPath(); + + virtual void draw(); + virtual bool isVisible(); + virtual void reset(); + virtual void init(); + virtual void init(const SVGMatrixImpl *screenCTM); + + virtual SVGElementImpl *element() const { return m_path; } + + protected: + friend class LibartCanvas; + SVGPathElementImpl *m_path; + + virtual void svgMoveTo(double x1, double y1, bool closed, 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(); + }; + + class LibartClipPath : public CanvasClipPath + { + public: + LibartClipPath(LibartCanvas *c, SVGClipPathElementImpl *clipPath); + virtual ~LibartClipPath(); + + virtual QRect bbox() const { return QRect(); } + virtual bool fillContains(const QPoint &) { return true; } + virtual bool strokeContains(const QPoint &) { return true; } + virtual void update(CanvasItemUpdate, int param1 = 0, int param2 = 0); + virtual void init(); + virtual void draw(); + virtual bool isVisible() { return false; } + + _ArtSVP *clipSVP(); + + protected: + LibartCanvas *m_canvas; + _ArtSVP *m_clipSVP; + + QPtrList m_clipItems; + }; + + class LibartImage : public CanvasItem + { + public: + LibartImage(LibartCanvas *c, SVGImageElementImpl *image); + virtual ~LibartImage(); + + virtual QRect bbox() const; + virtual bool fillContains(const QPoint &) { return true; } + virtual bool strokeContains(const QPoint &) { return true; } + virtual void update(CanvasItemUpdate, int = 0, int = 0) { } + virtual void init(); + virtual void draw(); + virtual bool isVisible(); + + // We can't include SVGImageElementImpl.h here + // because of compiliation errors (X11 headers!) + virtual SVGElementImpl *element() const { return reinterpret_cast(m_image); } + + protected: + LibartCanvas *m_canvas; + SVGImageElementImpl *m_image; + }; + + class LibartMarker : public CanvasMarker + { + public: + LibartMarker(LibartCanvas *c, SVGMarkerElementImpl *marker); + virtual ~LibartMarker(); + + virtual QRect bbox() const { return QRect(); } + virtual bool fillContains(const QPoint &) { return true; } + virtual bool strokeContains(const QPoint &) { return true; } + virtual void update(CanvasItemUpdate, int = 0, int = 0) { } + virtual void init(); + virtual void draw(); + virtual bool isVisible() { return false; } + + protected: + LibartCanvas *m_canvas; + }; + + class LibartText : public CanvasText, public LibartClipItem + { + public: + LibartText(LibartCanvas *c, SVGTextElementImpl *text); + virtual ~LibartText(); + + virtual QRect bbox() const; + virtual bool fillContains(const QPoint &p); + virtual bool strokeContains(const QPoint &p); + virtual void update(CanvasItemUpdate reason, int param1 = 0, int param2 = 0); + virtual void draw(); + virtual bool isVisible(); + virtual void init(); + virtual void init(const SVGMatrixImpl *screenCTM); + + virtual void renderCallback(SVGTextContentElementImpl *element, const SVGMatrixImpl *screenCTM, T2P::GlyphSet *glyph, T2P::GlyphLayoutParams *params, double anchor) const; + virtual void addTextDecoration(SVGTextContentElementImpl *element, double x, double y, double w, double h) const; + + void initClipItem(); + ArtSVP *clipSVP(); + + protected: + LibartCanvas *m_canvas; + + private: + void clearSVPs(); + + class SVPElement + { + public: + SVPElement() { svp = 0; element = 0; } + ~SVPElement(); + + _ArtSVP *svp; + SVGTextContentElementImpl *element; + }; + + // renderCallback() is const. + mutable QPtrList m_drawFillItems; + mutable QPtrList m_drawStrokeItems; + mutable QPtrDict m_fillPainters; + mutable QPtrDict m_strokePainters; + }; +} + +#endif + diff --git a/ksvg/plugin/backends/libart/Makefile.am b/ksvg/plugin/backends/libart/Makefile.am new file mode 100644 index 00000000..b3f4ea5b --- /dev/null +++ b/ksvg/plugin/backends/libart/Makefile.am @@ -0,0 +1,11 @@ +kde_module_LTLIBRARIES = libksvgrendererlibart.la + +libksvgrendererlibart_la_SOURCES = BezierPathLibart.cpp GlyphTracerLibart.cpp LibartCanvas.cpp LibartCanvasItems.cpp LibartCanvasFactory.cpp +libksvgrendererlibart_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +libksvgrendererlibart_la_LIBADD = ../../../libksvg.la +libksvgrendererlibart_la_METASOURCES = AUTO + +kde_services_DATA = ksvglibartcanvas.desktop + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) +INCLUDES = $(LIBART_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) -I$(top_srcdir)/ksvg/dom -I$(top_srcdir)/ksvg/impl -I$(top_srcdir)/ksvg/ecma -I$(top_srcdir)/ksvg/core -I$(top_srcdir)/ksvg/impl/libs/art_support -I$(top_srcdir)/ksvg/impl/libs/libtext2path/src $(KDE_INCLUDES) $(all_includes) diff --git a/ksvg/plugin/backends/libart/ksvglibartcanvas.desktop b/ksvg/plugin/backends/libart/ksvglibartcanvas.desktop new file mode 100644 index 00000000..af6f3a6c --- /dev/null +++ b/ksvg/plugin/backends/libart/ksvglibartcanvas.desktop @@ -0,0 +1,101 @@ +[Desktop Entry] +Type=Service +ServiceTypes=KSVG/Renderer +X-KDE-Library=libksvgrendererlibart +X-KSVG-InternalName=libart +Name=KSVG Rendering Backend - Libart +Name[ar]=خلفية الرسم ل KSVG - Libart +Name[bs]=KSVG renderiranje - Libart +Name[ca]=Representació en segon pla de KSVG - Biblioteca d'imatges +Name[cs]=Vykreslovací nástroj KSVG - Libart +Name[cy]=Ôl-wyneb Llunio KSVG - Libart +Name[da]=Underliggende program til KSVG-visning - Libart +Name[de]=KSVG-Darstellungsmodul - Libart +Name[el]=Σύστημα υποστήριξης αποτύπωσης του KSVG - Libart +Name[es]=Motor de procesado de KSVG - Libart +Name[et]=KSVG renderdamise taustarakendus - Libart +Name[eu]=KSVG errendatze programa - Libart +Name[fa]=پایانۀ پشتیبانی پرداخت KSVG - Libart +Name[fi]=KSVG-piirtäjän taustaohjelma - Libart +Name[fr]=Moteur de rendu KSVG - Libart +Name[ga]=Inneall Rindreála KSVG - Libart +Name[gl]=Mecanismo de Interpretación KSVG - Libart +Name[hi]=के-एसवीजी रेंडरिंग बैकएण्ड- लिबआर्ट +Name[hu]=KSVG megjelenítőmotor - Libart +Name[is]=KSVG teiknari - Libart +Name[it]=Backend di KSVG per il rendering - Libart +Name[ja]=KSVG レンダリングバックエンド - Libart +Name[kk]=KSVG кескіндеу бағдарламасы - Libart +Name[km]=កម្មវិធី​សម្រាប់​បង្ហាញ KSVG - Libart +Name[lt]=KSVG atkūrimo programinė sąsaja - Libart +Name[ms]=Tepi Belakang Menrealisasi KSVG - Libart +Name[nb]=Modul for KSVG-tegning – Libart +Name[nds]=KSVG-Dorstellhölper - Libart +Name[ne]=KSVG रेन्डरिङ ब्याकइन्ड - लिबर्ट +Name[nl]=KSVG weergavecomponent - Libart +Name[nn]=Modul for KSVG-teikning – Libart +Name[pl]=Narzędzie do renderowania KSVG - Libart +Name[pt]=Infra-Estrutura de Desenho do KSVG - Libart +Name[pt_BR]=Estrutura de KSVG Rendering Backend - Libart +Name[ro]=Motor de randare KSVG - Libart +Name[ru]=Движок отрисовки KSVG - Libart +Name[sk]=Nástroj pre zobrazovanie KSVG - libart +Name[sl]=Izrisovalnik KSVG - Libart +Name[sr]=KSVG-ов позадински систем за рендеровање — Libart +Name[sr@Latn]=KSVG-ov pozadinski sistem za renderovanje — Libart +Name[sv]=KSVG-uppritningsmodul - konstbibliotek +Name[ta]=KSVG வழங்கும் பின் அமைப்பு - லிபார்ட் +Name[tg]=Лағжандаи тасовироти KSVG - Libart +Name[tr]=KSVG Derleme Aracı - Libart +Name[uk]=Інтерфейс відтворення KSVG - Libart +Name[zh_CN]=KSVG 渲染后端 - Libart +Name[zh_HK]=KSVG 合成後端 - Libart +Name[zh_TW]=KSVG 上色後端介面 - Libart +Comment=Mature ksvg rendering backend +Comment[ar]=خلفية الرسم لksvg البالغة +Comment[bs]=Zreli ksvg rendering backend +Comment[ca]=Representador madur en segon pla de ksvg +Comment[cs]=Vyspělý vykreslovací nástroj KSVG +Comment[cy]=Ôl-wyneb llunio ksvg aeddfed +Comment[da]=Modent underliggende program til ksvg-visning +Comment[de]=Ausgereiftes KSVG-Darstellungsmodul +Comment[el]=Ώριμο σύστημα υποστήριξης αποτύπωσης του KSVG +Comment[es]=Motor de procesado de ksvg tradicional +Comment[et]=Kasutamisküps ksvg renderdamise taustarakendus +Comment[eu]=ksvg errendatze programa egonkorra +Comment[fa]=پایانۀ پشتیبانی کامل پرداخت ksvg +Comment[fi]=Kypsä ksvg-piirtäjän taustaohjelma +Comment[fr]=Moteur de rendu KSVG mature +Comment[gl]=Mecanismo de interpretación maduro ksvg +Comment[hi]=परिपक्व के-एसवीजी रेंडरिंग बैकएण्ड +Comment[hu]=Egy kiforrott megjelenítőmotor a KSVG-hez +Comment[is]=Reyndur ksvg teiknari +Comment[it]=Maturo backend di KSVG per il rendering +Comment[ja]=成熟した ksvg レンダリングバックエンド +Comment[kk]=Баяғы, жетілірдірген, KSVG кескіндеу бағдарламасы +Comment[km]=កម្មវិធី​សម្រាប់​បង្ហាញ ksvg ចាស់ៗ +Comment[lt]=Išvystyta ksvg atkūrimo programinė sąsaja +Comment[ms]=Tepi belakang menrealisasi ksvg matang +Comment[nb]=Velutviklet modul for ksvg-tegning +Comment[nds]=Reep KSVG-Dorstellhölper +Comment[ne]=पूर्ण विकसित ksvg रेन्डरिङ ब्याकइन्ड +Comment[nl]=Volgroeide KSVG weergavecomponent +Comment[nn]=Velutvikla modul for ksvg-teikning +Comment[pl]=Dopracowane narzędzie do renderowania KSVG +Comment[pt]=Uma infra-estrutura de desenho do ksvg mais madura +Comment[pt_BR]=Estrutura de renderização madura do ksvg +Comment[ro]=Motor de randare KSVG matur +Comment[ru]=Старый движок отрисовки ksvg +Comment[sk]=Stabilný nástroj pre zobrazovanie ksvg +Comment[sl]=Zrel izrisovalnik KSVG +Comment[sr]=Стари KSVG-ов позадински систем за рендеровање +Comment[sr@Latn]=Stari KSVG-ov pozadinski sistem za renderovanje +Comment[sv]=Mogen KSVG-uppritningsmodul +Comment[ta]=முழுமையான ksvg வழங்கும் பின் அமைப்பு +Comment[tg]=Лағжандаи тасовироти кӯҳнаи ksvg +Comment[tr]=Tamamlanmış ksvg derleme aracı +Comment[uk]=Стабільний інтерфейс відтворення KSVG +Comment[zh_CN]=稳定的 ksvg 渲染后端 +Comment[zh_HK]=成熟的 ksvg 合成後端 +Comment[zh_TW]=成熟的 ksvg 上色後端介面 +author=Nikolas Zimmermann diff --git a/ksvg/plugin/ksvg_factory.cpp b/ksvg/plugin/ksvg_factory.cpp new file mode 100644 index 00000000..b231783c --- /dev/null +++ b/ksvg/plugin/ksvg_factory.cpp @@ -0,0 +1,100 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include +#include +#include +#include + +#include "ksvg_plugin.h" +#include "ksvg_factory.moc" + +#include +#include +#include + +extern "C" +{ + void *init_libksvgplugin() + { + KGlobal::locale()->insertCatalogue("ksvgplugin"); + return new KSVGPluginFactory(); + } +} + +KInstance *KSVGPluginFactory::s_instance = 0; +KAboutData *KSVGPluginFactory::s_about = 0; + +KSVGPluginFactory::KSVGPluginFactory(QObject *parent, const char *name) : KParts::Factory(parent, name) +{ +} + +KSVGPluginFactory::~KSVGPluginFactory() +{ + delete s_instance; + s_instance = 0; + delete s_about; + + s_about = 0; +} + +KParts::Part *KSVGPluginFactory::createPartObject(QWidget *parentWidget, const char *wname, QObject *parent, const char *name, const char *, const QStringList &args) +{ + // Get the width and height of the + // TODO : + unsigned int width = 0, height = 0; + bool dummy; + QRegExp r1("(WIDTH)(\\s*=\\s*\")(\\d+)(\\w*)(\")"); + QRegExp r2("(HEIGHT)(\\s*=\\s*\")(\\d+)(\\w*)(\")"); + for(QValueListConstIterator it = args.begin(); it != args.end(); ++it) + { + if(r1.search(*it) > -1) + width = r1.cap(3).toUInt(&dummy); + if(r2.search(*it) > -1) + height = r2.cap(3).toUInt(&dummy); + } + + return new KSVGPlugin(parentWidget, wname, parent, name, width, height); +} + +KInstance *KSVGPluginFactory::instance() +{ + if(!s_instance) + { + s_about = new KAboutData("ksvg", I18N_NOOP("KSVG"), "0.1", "KSVG\nFreedom for veKtors",KAboutData::License_GPL_V2,"(c) 2001-2003, The KSVG Team",0,"http://svg.kde.org"); + s_about->addAuthor("Rob Buis", 0, "buis@kde.org"); + s_about->addAuthor("Nikolas Zimmermann", 0, "wildfox@kde.org"); + s_about->addCredit("Adrian Page", 0); + s_about->addCredit("Andreas Streichardt", 0, "mop@spaceregents.de"); + s_instance = new KInstance(s_about); + } + + return s_instance; +} + +KSVGPluginBrowserExtension::KSVGPluginBrowserExtension(KSVGPlugin *parent) +: KParts::BrowserExtension(parent, "KSVGPlugin BrowserExtension") +{ +} + +KSVGPluginBrowserExtension::~KSVGPluginBrowserExtension() +{ +} diff --git a/ksvg/plugin/ksvg_factory.h b/ksvg/plugin/ksvg_factory.h new file mode 100644 index 00000000..b462c782 --- /dev/null +++ b/ksvg/plugin/ksvg_factory.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 KSVGFactory_H +#define KSVGFactory_H + +#include +#include + +class KAboutData; +class KInstance; + +class KSVGPluginFactory : public KParts::Factory +{ +Q_OBJECT +public: + KSVGPluginFactory(QObject *parent = 0, const char *name = 0); + virtual ~KSVGPluginFactory(); + + virtual KParts::Part *createPartObject(QWidget *parentWidget = 0, const char *widgetName = 0, QObject *parent = 0, const char *name = 0, const char *classname = "KParts::Part", const QStringList &args = QStringList()); + + static KInstance *instance(); + +private: + static KInstance *s_instance; + static KAboutData *s_about; +}; + +class KSVGPluginBrowserExtension : public KParts::BrowserExtension +{ +Q_OBJECT +friend class KSVGPlugin; + +public: + KSVGPluginBrowserExtension(KSVGPlugin *parent); + virtual ~KSVGPluginBrowserExtension(); +}; + +#endif + +// vim:ts=4:noet diff --git a/ksvg/plugin/ksvg_plugin.cpp b/ksvg/plugin/ksvg_plugin.cpp new file mode 100644 index 00000000..37e0a0dd --- /dev/null +++ b/ksvg/plugin/ksvg_plugin.cpp @@ -0,0 +1,417 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include +#include +#include +#include +#include +#include +#include + +#include "ksvg_widget.h" +#include "ksvg_factory.h" +#include "ksvg_plugin.moc" + +#include "KSVGCanvas.h" +#include "KSVGLoader.h" +#include "CanvasFactory.h" +#include "DocumentFactory.h" + +#include "SVGDocument.h" +#include "SVGWindowImpl.h" +#include "SVGZoomAndPan.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" + +#include + +using namespace KSVG; + +#define DEFAULT_WIDTH 400 +#define DEFAULT_HEIGHT 400 +#define ZOOM_FACTOR 1.2 + +struct KSVGPlugin::Private +{ + KSVGWidget *window; + KSVGPluginBrowserExtension *extension; + + KAction *zoomInAction; + KAction *zoomOutAction; + KAction *zoomResetAction; + KAction *stopAnimationsAction; + KAction *viewSourceAction; + KAction *viewMemoryAction; + KAction *aboutApp; + KAction *saveToPNG; + KToggleAction *fontKerningAction; + KToggleAction *progressiveAction; + KSelectAction *renderingBackendAction; + + QString description; + + QPoint panPoint; + float zoomFactor; + + SVGDocumentImpl *doc; + KSVGCanvas *canvas; + QPixmap *backgroundPixmap; + KAboutApplication *aboutKSVG; + + unsigned int width; + unsigned int height; +}; + +KSVGPlugin::KSVGPlugin(QWidget *wparent, const char *, QObject *parent, const char *name, unsigned int width, unsigned int height) : KParts::ReadOnlyPart(parent, name) +{ + kdDebug(26003) << "KSVGPlugin::KSVGPlugin" << endl; + setInstance(KSVGPluginFactory::instance()); + + ksvgd = new KSVGPlugin::Private(); + + ksvgd->width = width; + ksvgd->height = height; + + ksvgd->zoomFactor = 1.0; + + ksvgd->doc = 0; + + ksvgd->window = new KSVGWidget(this, wparent, "Rendering Widget"); + connect(ksvgd->window, SIGNAL(browseURL(const QString &)), this, SLOT(browseURL(const QString &))); + ksvgd->window->show(); + + KParts::Part::setWidget(ksvgd->window); + + ksvgd->extension = new KSVGPluginBrowserExtension(this); + + ksvgd->backgroundPixmap = new QPixmap(width > 0 ? width : DEFAULT_WIDTH, height > 0 ? height : DEFAULT_HEIGHT); + ksvgd->backgroundPixmap->fill(); + + ksvgd->canvas = KSVG::CanvasFactory::self()->loadCanvas(width > 0 ? width : DEFAULT_WIDTH, height > 0 ? height : DEFAULT_HEIGHT); + if(!ksvgd->canvas) + return; + + ksvgd->canvas->setup(ksvgd->backgroundPixmap, ksvgd->window); + + ksvgd->zoomInAction = KStdAction::zoomIn(this, SLOT(slotZoomIn()), actionCollection()); + ksvgd->zoomOutAction = KStdAction::zoomOut(this, SLOT(slotZoomOut()), actionCollection()); + ksvgd->zoomResetAction = new KAction(i18n("Zoom &Reset"), "viewmag", this, SLOT(slotZoomReset()), actionCollection(), "zoom_reset"); + ksvgd->stopAnimationsAction = new KAction(i18n("&Stop Animations"), "stop", Key_Escape, this, SLOT(slotStop()), actionCollection(), "stop_anims"); + ksvgd->viewSourceAction = new KAction(i18n("View &Source"), "document2", Key_F6, this, SLOT(slotViewSource()), actionCollection(), "view_source"); + ksvgd->viewMemoryAction = new KAction(i18n("View &Memory"), "document2", Key_F7, this, SLOT(slotViewMemory()), actionCollection(), "view_memory"); + ksvgd->saveToPNG = new KAction(i18n("Save to PNG..."), "save", 0, this, SLOT(slotSaveToPNG()), actionCollection(), "save_to_png"); +// ksvgd->aboutApp = KStdAction::aboutApp(this, SLOT(slotAboutKSVG()), actionCollection());//, "KSVG"); + ksvgd->aboutApp = new KAction(i18n("About KSVG"), "vectorgfx", 0, this, SLOT(slotAboutKSVG()), actionCollection(), "help_about_app"); + ksvgd->fontKerningAction = new KToggleAction(i18n("Use Font &Kerning"), "viewmagfit", Key_F8, this, SLOT(slotFontKerning()), actionCollection(), "font_kerning"); + ksvgd->progressiveAction = new KToggleAction(i18n("Use &Progressive Rendering"), "", Key_F9, this, SLOT(slotProgressiveRendering()), actionCollection(), "progressive"); + + KSimpleConfig config("ksvgpluginrc", true); + config.setGroup("Rendering"); + ksvgd->fontKerningAction->setChecked(config.readBoolEntry("FontKerning", true)); + ksvgd->progressiveAction->setChecked(config.readBoolEntry("ProgressiveRendering", true)); + + ksvgd->renderingBackendAction = new KSelectAction(i18n("Rendering &Backend"), 0, this, SLOT(slotRenderingBackend()), actionCollection(), "rendering_backend"); + + QStringList items; + QPtrList canvasList = KSVG::CanvasFactory::self()->canvasList(); + QPtrListIterator it(canvasList); + KSVG::CanvasInfo *canvasInfo = 0; + while((canvasInfo = it.current()) != 0) + { + items << canvasInfo->name; + ++it; + } + + ksvgd->renderingBackendAction->setItems(items); + ksvgd->renderingBackendAction->setCurrentItem(KSVG::CanvasFactory::self()->itemInList(ksvgd->canvas)); + + ksvgd->aboutKSVG = new KAboutApplication(KSVGPluginFactory::instance()->aboutData(), wparent); + + setXMLFile("ksvgplugin.rc"); +} + +KSVGPlugin::~KSVGPlugin() +{ + kdDebug(26003) << "KSVGPlugin::~KSVGPlugin" << endl; + + if(ksvgd->doc && ksvgd->doc->rootElement()) + ksvgd->doc->rootElement()->pauseAnimations(); + + KSVG::CanvasFactory::self()->cleanup(); + delete ksvgd->extension; + + if(ksvgd->doc) + ksvgd->doc->detach(); + + delete ksvgd->canvas; + delete ksvgd->backgroundPixmap; + delete ksvgd; +} + +SVGDocumentImpl *KSVGPlugin::docImpl() +{ + return ksvgd->doc; +} + +SVGDocument KSVGPlugin::document() +{ + return SVGDocument(ksvgd->doc); +} + +void KSVGPlugin::reset() +{ + if(ksvgd->canvas) + ksvgd->canvas->reset(); + + ksvgd->zoomFactor = 1; + ksvgd->window->reset(); + ksvgd->panPoint = QPoint(0, 0); +} + +bool KSVGPlugin::openURL(const KURL &url) +{ + m_url = url; + + if(!url.prettyURL().isEmpty()) + { + reset(); + + DocumentFactory *docFactory = DocumentFactory::self(); + + // when embedded, stick to passed width and height + ksvgd->doc = docFactory->requestDocumentImpl((ksvgd->width > 0 && ksvgd->height > 0)); + + ksvgd->doc->attach(ksvgd->canvas); + ksvgd->doc->addToDocumentDict(ksvgd->doc->handle(), ksvgd->doc); + ksvgd->doc->setReferrer(ksvgd->extension->urlArgs().metaData()["referrer"]); + + connect(ksvgd->doc, SIGNAL(finishedParsing(bool, const QString &)), this, SLOT(slotParsingFinished(bool, const QString &))); + connect(ksvgd->doc, SIGNAL(finishedRendering()), this, SLOT(slotRenderingFinished())); + connect(ksvgd->doc, SIGNAL(gotDescription(const QString &)), this, SLOT(slotSetDescription(const QString &))); + connect(ksvgd->doc, SIGNAL(gotTitle(const QString &)), this, SLOT(slotSetTitle(const QString &))); + connect(ksvgd->doc, SIGNAL(gotURL(const QString &)), this, SLOT(slotGotURL(const QString &))); + connect(ksvgd->window, SIGNAL(redraw(const QRect &)), this, SLOT(slotRedraw(const QRect &))); + + ksvgd->backgroundPixmap->fill(); + bitBlt(ksvgd->window, 0, 0, ksvgd->backgroundPixmap, 0, 0, ksvgd->backgroundPixmap->width(), ksvgd->backgroundPixmap->height()); + ksvgd->zoomFactor = 1; + + emit started(0); + ksvgd->doc->open(url); + emit completed(); + } + else + return false; + + return true; +} + +void KSVGPlugin::browseURL(const QString &url) +{ + ksvgd->doc->rootElement()->pauseAnimations(); + KParts::URLArgs args; + args.frameName = "_self"; + emit ksvgd->extension->openURLRequest(KURL(m_url, url), args); +} + +void KSVGPlugin::slotRedraw(const QRect &r) +{ + if(ksvgd->window->width() != ksvgd->backgroundPixmap->width() || + ksvgd->window->height() != ksvgd->backgroundPixmap->height()) + { + ksvgd->backgroundPixmap->resize(ksvgd->window->width(), ksvgd->window->height()); + + if(ksvgd->doc && ksvgd->doc->canvas()) + { + ksvgd->doc->canvas()->resize(ksvgd->window->width(), ksvgd->window->height()); + ksvgd->doc->canvas()->blit(); + } + } + + bitBlt(ksvgd->window, r.x(), r.y(), ksvgd->backgroundPixmap, r.x(), r.y(), r.width(), r.height()); +} + +void KSVGPlugin::slotViewSource() +{ + KTempFile temp; + *temp.textStream() << KSVGLoader::getUrl(m_url, true) << endl; + KRun::runURL(KURL(temp.name()), "text/plain", true); +} + +void KSVGPlugin::slotViewMemory() +{ + KTempFile temp; + *temp.textStream() << ksvgd->doc->window()->printNode(*ksvgd->doc).string() << endl; + KRun::runURL(KURL(temp.name()), "text/plain", true); +} + +void KSVGPlugin::slotFontKerning() +{ + KSimpleConfig config("ksvgpluginrc", false); + config.setGroup("Rendering"); + config.writeEntry("FontKerning", ksvgd->fontKerningAction->isChecked()); + + if(ksvgd->doc) + { + SVGSVGElementImpl *root = ksvgd->doc->rootElement(); + if(!root) + return; + + ksvgd->doc->canvas()->fontContext()->setKerning(ksvgd->fontKerningAction->isChecked()); + update(); + } +} + +void KSVGPlugin::slotProgressiveRendering() +{ + KSimpleConfig config("ksvgpluginrc", false); + config.setGroup("Rendering"); + config.writeEntry("ProgressiveRendering", ksvgd->progressiveAction->isChecked()); +} + +void KSVGPlugin::slotRenderingBackend() +{ + KSimpleConfig config("ksvgpluginrc", false); + config.setGroup("Canvas"); + config.writeEntry("ActiveCanvas", KSVG::CanvasFactory::self()->internalNameFor(ksvgd->renderingBackendAction->currentText())); + config.sync(); + KSVG::CanvasFactory::self()->deleteCanvas(ksvgd->canvas); + ksvgd->canvas = KSVG::CanvasFactory::self()->loadCanvas(ksvgd->width > 0 ? ksvgd->width : DEFAULT_WIDTH, ksvgd->height > 0 ? ksvgd->height : DEFAULT_HEIGHT); + if(!ksvgd->canvas) + return; + + ksvgd->canvas->setup(ksvgd->backgroundPixmap, ksvgd->window); + openURL(m_url); +} + +void KSVGPlugin::slotAboutKSVG() +{ + ksvgd->aboutKSVG->show(); +} + +void KSVGPlugin::slotStop() +{ + if(ksvgd->doc->rootElement()->animationsPaused()) + ksvgd->doc->rootElement()->unpauseAnimations(); + else + ksvgd->doc->rootElement()->pauseAnimations(); +} + +void KSVGPlugin::slotParsingFinished(bool error, const QString &errorDesc) +{ + emit completed(); + + if(error) + { + kdDebug(26003) << "Finished with error : " << errorDesc << endl; + emit setStatusBarText(errorDesc); + } + else + kdDebug(26003) << "Finished without errors!" << endl; +} + +void KSVGPlugin::slotRenderingFinished() +{ + bitBlt(ksvgd->window, 0, 0, ksvgd->backgroundPixmap, 0, 0, ksvgd->canvas->width(), ksvgd->canvas->height()); +} + +void KSVGPlugin::slotZoomIn() +{ + ksvgd->zoomFactor *= ZOOM_FACTOR; + update(); +} + +void KSVGPlugin::slotZoomOut() +{ + ksvgd->zoomFactor *= (1.0 / ZOOM_FACTOR); + update(); +} + +void KSVGPlugin::slotZoomReset() +{ + ksvgd->zoomFactor = 1.0; + update(); +} + +void KSVGPlugin::slotSaveToPNG() +{ + if(ksvgd && ksvgd->backgroundPixmap) + { + QImage img = ksvgd->backgroundPixmap->convertToImage(); + QString filename = KFileDialog::getSaveFileName(); + if(!filename.isEmpty()) + img.save(filename, "PNG"); + } +} + +void KSVGPlugin::setPanPoint(const QPoint &translate) +{ + ksvgd->panPoint = translate; + update(); +} + +void KSVGPlugin::update() +{ + if(ksvgd->doc) + { + SVGSVGElementImpl *root = ksvgd->doc->rootElement(); + if(!root || root->zoomAndPan() != SVG_ZOOMANDPAN_MAGNIFY) + return; + + ksvgd->backgroundPixmap->fill(); + + bool zoomChanged = ksvgd->zoomFactor != root->currentScale(); + root->setCurrentScale(ksvgd->zoomFactor); + root->setCurrentTranslate(ksvgd->panPoint); + + ksvgd->doc->syncCachedMatrices(); + + if(zoomChanged) + ksvgd->doc->canvas()->update(ksvgd->zoomFactor); + else + ksvgd->doc->canvas()->update(ksvgd->panPoint); + + // Fixes drawing glitches + slotRedraw(QRect(0, 0, ksvgd->backgroundPixmap->width(), ksvgd->backgroundPixmap->height())); + } +} + +void KSVGPlugin::slotSetDescription(const QString &desc) +{ + ksvgd->description = desc; + emit setStatusBarText(i18n("Description: %1").arg(desc)); +} + +void KSVGPlugin::slotSetTitle(const QString &title) +{ + emit setWindowCaption(title); +} + +void KSVGPlugin::slotGotURL(const QString &text) +{ + if(text.isNull() && !ksvgd->description.isEmpty()) + emit setStatusBarText(i18n("Description: %1").arg(ksvgd->description)); + else + emit setStatusBarText(text); +} + +// vim:ts=4:noet diff --git a/ksvg/plugin/ksvg_plugin.h b/ksvg/plugin/ksvg_plugin.h new file mode 100644 index 00000000..87286be9 --- /dev/null +++ b/ksvg/plugin/ksvg_plugin.h @@ -0,0 +1,87 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 KSVGPlugin_H +#define KSVGPlugin_H + +#include +#include + +namespace KSVG +{ + class SVGDocument; + class SVGDocumentImpl; + class SVGDescElementImpl; + class SVGTitleElementImpl; +} + +class KSVGPlugin : public KParts::ReadOnlyPart +{ +Q_OBJECT +public: + KSVGPlugin(QWidget *parentWidget, const char *wname, QObject *parent, const char *name, unsigned int width = 0, unsigned int height = 0); + virtual ~KSVGPlugin(); + + virtual bool openFile() { return false; } + virtual bool openURL(const KURL &url); + + KSVG::SVGDocument document(); + KSVG::SVGDocumentImpl *docImpl(); + + void reset(); + void setPanPoint(const QPoint &translate); + void update(); + void setPopupActive(bool); + +signals: + void gotHyperlink(const QString &); + void gotHyperlinkCoordinate(const QRect &); + +public slots: + void slotRedraw(const QRect &); + +private slots: + void browseURL(const QString &url); + void slotStop(); + void slotViewSource(); + void slotViewMemory(); + void slotFontKerning(); + void slotProgressiveRendering(); + void slotRenderingBackend(); + void slotZoomIn(); + void slotZoomOut(); + void slotZoomReset(); + void slotAboutKSVG(); + void slotSaveToPNG(); + + void slotParsingFinished(bool error, const QString &errorDesc); + void slotRenderingFinished(); + void slotSetDescription(const QString &); + void slotSetTitle(const QString &); + void slotGotURL(const QString &); + +private: + class Private; + Private *ksvgd; +}; + +#endif + +// vim:ts=4:noet diff --git a/ksvg/plugin/ksvg_widget.cpp b/ksvg/plugin/ksvg_widget.cpp new file mode 100644 index 00000000..073e60a5 --- /dev/null +++ b/ksvg/plugin/ksvg_widget.cpp @@ -0,0 +1,267 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 +#include +#include +#include "ksvg_widget.moc" + +#include "ksvg_plugin.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" + +KSVGWidget::KSVGWidget(KSVGPlugin *part, QWidget *parent, const char *name) +: QWidget(parent, name), m_part(part) +{ + setMouseTracking(true); + setFocusPolicy(WheelFocus); + + setBackgroundMode(NoBackground); + + reset(); +} + +KSVGWidget::~KSVGWidget() +{ +} + +KSVGPlugin *KSVGWidget::part() const +{ + return m_part; +} + +void KSVGWidget::reset() +{ + m_oldPanningPos.setX(0); + m_oldPanningPos.setY(0); + m_panningPos.setX(0); + m_panningPos.setY(0); +} + +void KSVGWidget::paintEvent(QPaintEvent *e) +{ + emit redraw(e->rect()); +} + +KSVG::SVGMouseEventImpl *KSVGWidget::newMouseEvent(KSVG::SVGEvent::EventId id, QMouseEvent *event) +{ + DOM::AbstractView temp; + + int clientX = event->x(); + int clientY = event->y(); + + if(part()->docImpl() && part()->docImpl()->rootElement()) + { + clientX = int(clientX / part()->docImpl()->rootElement()->currentScale()); + clientY = int(clientY / part()->docImpl()->rootElement()->currentScale()); + } + + int button = 0; + if(event->stateAfter() & Qt::LeftButton) + button = 1; + else if(event->stateAfter() & Qt::MidButton) + button = 2; + else if(event->stateAfter() & Qt::RightButton) + button = 3; + + KSVG::SVGMouseEventImpl *mev = new KSVG::SVGMouseEventImpl(id, // type + true, // canBubbleArg + true, // cancelableArg + temp, // view + 0, // detail + event->globalX(), //screenXArg + event->globalY(), // screenYArg, + clientX, // clientXArg + clientY, // clientYArg + (event->state() & Qt::ControlButton), // ctrlKeyArg + (event->state() & Qt::AltButton), // altKeyArg + (event->state() & Qt::ShiftButton), // shiftKeyArg + (event->state() & Qt::MetaButton), // metaKeyArg + button, // buttonArg + 0); + + mev->ref(); + + return mev; +} + +void KSVGWidget::mouseMoveEvent(QMouseEvent *event) +{ + if(event->state() & QMouseEvent::ControlButton && event->state() & QMouseEvent::LeftButton) + { + if(m_panningPos.isNull()) + m_panningPos = event->pos(); + else + part()->setPanPoint(m_oldPanningPos - (m_panningPos - event->pos())); + + return; + } + else if(event->state() & QMouseEvent::ControlButton) + return; + + KSVG::SVGMouseEventImpl *mev = newMouseEvent(KSVG::SVGEvent::MOUSEMOVE_EVENT, event); + + if(part()->docImpl() && part()->docImpl()->rootElement()) + part()->docImpl()->rootElement()->prepareMouseEvent(event->pos(), event->pos(), mev); + + if(mev->target() && mev->url().string().isEmpty()) + { + KSVG::SVGElementImpl *target = const_cast(mev->target()); + KSVG::SVGStylableImpl *style = dynamic_cast(target); + + if(!style) + { + setCursor(KCursor::arrowCursor()); + return; + } + + switch(style->getCursor()) + { + case KSVG::CURSOR_CROSSHAIR: + setCursor(KCursor::crossCursor()); + break; + case KSVG::CURSOR_POINTER: + setCursor(KCursor::handCursor()); + break; + case KSVG::CURSOR_MOVE: + setCursor(KCursor::sizeAllCursor()); + break; + case KSVG::CURSOR_E_RESIZE: + case KSVG::CURSOR_W_RESIZE: + setCursor(KCursor::sizeHorCursor()); + break; + case KSVG::CURSOR_N_RESIZE: + case KSVG::CURSOR_S_RESIZE: + setCursor(KCursor::sizeVerCursor()); + break; + case KSVG::CURSOR_NW_RESIZE: + case KSVG::CURSOR_SE_RESIZE: + setCursor(KCursor::sizeFDiagCursor()); + break; + case KSVG::CURSOR_NE_RESIZE: + case KSVG::CURSOR_SW_RESIZE: + setCursor(KCursor::sizeBDiagCursor()); + break; + case KSVG::CURSOR_TEXT: + setCursor(KCursor::ibeamCursor()); + break; + case KSVG::CURSOR_WAIT: + setCursor(KCursor::waitCursor()); + break; + case KSVG::CURSOR_HELP: + setCursor(KCursor::whatsThisCursor()); + break; + default: + setCursor(KCursor::arrowCursor()); + } + } + else if(mev->url().string().isEmpty()) + setCursor(KCursor::arrowCursor()); + + if(!mev->url().string().isEmpty()) + setCursor(KCursor::handCursor()); + + mev->deref(); +} + +void KSVGWidget::mousePressEvent(QMouseEvent *event) +{ + if(event->state() & QMouseEvent::ControlButton) + return; + + if(event->button() == RightButton) + { + if(part() && part()->factory()) + { + QPopupMenu *popup = static_cast(part()->factory()->container("popupmenu", part())); + if(popup) + popup->popup(event->globalPos()); + } + } + + KSVG::SVGMouseEventImpl *mev = newMouseEvent(KSVG::SVGEvent::MOUSEDOWN_EVENT, event); + + if(part()->docImpl() && part()->docImpl()->rootElement()) + part()->docImpl()->rootElement()->prepareMouseEvent(event->pos(), event->pos(), mev); + + mev->deref(); +} + +void KSVGWidget::mouseReleaseEvent(QMouseEvent *event) +{ + if(!m_panningPos.isNull()) + { + m_oldPanningPos = m_oldPanningPos - (m_panningPos - event->pos()); + m_panningPos.setX(0); + m_panningPos.setY(0); + } + + if(event->state() & QMouseEvent::ControlButton) + return; + + KSVG::SVGMouseEventImpl *mev = newMouseEvent(KSVG::SVGEvent::MOUSEUP_EVENT, event); + + if(part()->docImpl() && part()->docImpl()->rootElement()) + part()->docImpl()->rootElement()->prepareMouseEvent(event->pos(), event->pos(), mev); + + if(!mev->url().string().isEmpty()) + { + QString url = mev->url().string(); + if(url.startsWith("#")) + url.prepend(part()->docImpl()->baseUrl().prettyURL()); + emit browseURL(url); + } + + mev->deref(); +} + +void KSVGWidget::keyPressEvent(QKeyEvent *ke) +{ + if(ke->stateAfter() & QMouseEvent::ControlButton) + { + setCursor(KCursor::sizeAllCursor()); + return; + } + + if(part()->docImpl()->lastTarget()) + part()->docImpl()->lastTarget()->dispatchKeyEvent(ke); +} + +void KSVGWidget::keyReleaseEvent(QKeyEvent *ke) +{ + if(ke->state() & QMouseEvent::ControlButton) + { + setCursor(KCursor::arrowCursor()); + return; + } + + if(part()->docImpl()->lastTarget()) + part()->docImpl()->lastTarget()->dispatchKeyEvent(ke); +} + +void KSVGWidget::resizeEvent(QResizeEvent *e) +{ + if(part()->docImpl() && part()->docImpl()->rootElement()) + part()->docImpl()->rootElement()->dispatchEvent(KSVG::SVGEvent::RESIZE_EVENT, true, false); + + emit redraw(QRect(0, 0, e->size().width(), e->size().height())); +} + +// vim:ts=4:noet diff --git a/ksvg/plugin/ksvg_widget.h b/ksvg/plugin/ksvg_widget.h new file mode 100644 index 00000000..3cd94849 --- /dev/null +++ b/ksvg/plugin/ksvg_widget.h @@ -0,0 +1,68 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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 KSVGWidget_H +#define KSVGWidget_H + +#include + +#include + +#include + +class KSVGPlugin; +class KSVGWidget : public QWidget +{ +Q_OBJECT +public: + KSVGWidget(KSVGPlugin *part, QWidget *parent, const char *name); + virtual ~KSVGWidget(); + + KSVGPlugin *part() const; + + void reset(); + +protected: + virtual void paintEvent(QPaintEvent *); + + virtual void mouseMoveEvent(QMouseEvent *); + virtual void mousePressEvent(QMouseEvent *); + virtual void mouseReleaseEvent(QMouseEvent *); + + virtual void keyPressEvent(QKeyEvent *); + virtual void keyReleaseEvent(QKeyEvent *); + + virtual void resizeEvent(QResizeEvent *); + +signals: + void browseURL(const QString &); + void redraw(const QRect &); + +private: + KSVG::SVGMouseEventImpl *newMouseEvent(KSVG::SVGEvent::EventId id, QMouseEvent *event); + + QPoint m_panningPos; + QPoint m_oldPanningPos; + KSVGPlugin *m_part; +}; + +#endif + +// vim:ts=4:noet diff --git a/ksvg/plugin/ksvgplugin.desktop b/ksvg/plugin/ksvgplugin.desktop new file mode 100644 index 00000000..9eaffdc7 --- /dev/null +++ b/ksvg/plugin/ksvgplugin.desktop @@ -0,0 +1,85 @@ +[Desktop Entry] +Name=KSVGPlugin +Name[ar]=برنامج KSVGPlugin +Name[ca]=Connector KSVG +Name[cy]=AtegynKSVG +Name[el]=Πρόσθετο KSVG +Name[eo]=Vektorgrafiko-kromaĵo +Name[eu]=KSVGPlugina +Name[fr]=Module SVG +Name[hi]=के-एसवीजी-प्लगइन +Name[hu]=KSVG bővítőmodul +Name[is]=KSVGÍforrit +Name[lv]=KSVGIespraudnis +Name[ne]=KSVG प्लगइन +Name[pl]=Wtyczka KSVG +Name[ro]=Modul KSVG +Name[sv]=KSVG-insticksprogram +Name[ta]=KSVGசொருகுப்பொருள் +Name[tr]=KSVG Eklentisi +Name[xh]=Iplagi efakiweyo ye KSVG +Name[zu]=Iplagi efakiweyo ye KSVG +Icon=vectorgfx +MimeType=image/svg+xml;image/svg +Comment=Scalable Vector Graphics Viewer +Comment[ar]=عارض الرسومات الثابتة القابلة للقياس +Comment[az]=Miqyaslı Vektor Qrafikaları Nümayişçisi +Comment[bs]=Scalable Vector Graphics preglednik +Comment[ca]=Visualitzador de gràfics vectorials escalables (SVG) +Comment[cs]=Prohlížeč pro formát Scalable Vector Graphics (SVG) +Comment[cy]=Gwelydd Graffeg Fector Graddedig +Comment[da]=Fremviser af skalerbar vektorgrafik +Comment[de]=Betrachter für skalierbare Vektorgraphiken +Comment[el]=Προβολέας διανυσματικών γραφικών +Comment[eo]=Rigardilo por pligrandigeblaj vektorgrafikoj +Comment[es]=Visor de gráficos vectoriales escalables (SVG) +Comment[et]=Skaleeritava vektorgraafika (SVG) näitaja +Comment[eu]=Scalable Vector Graphics ikustailua +Comment[fa]=مشاهده‌گر نگاره‌‌‌‌‌سازی مقیاس‌پذیر برداری +Comment[fi]=Scalable Vector Graphics -näytin +Comment[fr]=Afficheur d'images au format Graphisme vectoriel échelonnable (SVG) +Comment[ga]=Amharcán SVG (Scalable Vector Graphics) +Comment[gl]=Visor de gráficos vectoriais escalables +Comment[hi]=स्केलेबल वेक्टर ग्राफिक्स प्रदर्शक +Comment[hr]=Preglednik SVG datoteka +Comment[hu]=SVG-megjelenítő +Comment[is]=Scalable Vector Graphics (SVG) myndbirtir +Comment[it]=Visore di file SVG +Comment[ja]=SVG (スケーラブルベクトルグラフィックス) ビューア +Comment[kk]=SVG файлдарды қарау +Comment[km]=កម្មវិធី​មើល​ក្រាហ្វិក​វ៉ិចទ័រ​មាន​មាត្រដ្ឋាន +Comment[lt]=Kintamo dydžio vektorinė grafika +Comment[lv]=Mērogojamas Vektoru Grafikas Skatītājs +Comment[ms]=Pemapar Grafik Vektor Boleh Skala +Comment[mt]=Werrej tas-"Scalable Vector Graphics" +Comment[nb]=Framvisningsprogram for SVG-bilde («Scalable Vector Graphics») +Comment[nds]=Kieker för skaleerbor Vektorgrafiken +Comment[ne]=मापनयोग्य भेक्टर ग्राफिक्स दर्शक +Comment[nl]=Scalable Vector Graphics-weergaveprogramma +Comment[nn]=Framvisingsprogram for SVG-grafikk («Scalable Vector Graphics») +Comment[pl]=Przeglądarka dla plików SVG (skalowalnej grafiki wektorowej) +Comment[pt]=Visualizador de Gráficos Vectoriais Escaláveis (SVG) +Comment[pt_BR]=Visualizador de Vetores Escaláveis +Comment[ro]=Vizualizor SVG +Comment[ru]=Просмотр SVG +Comment[sk]=Prehliadač pre škálovateľnú vektorovú grafiku SVG +Comment[sl]=Pregledovalnik skalabilne vektorske grafike +Comment[sr]=Приказивач скалабилне векторске графике +Comment[sr@Latn]=Prikazivač skalabilne vektorske grafike +Comment[sv]=Visning av skalbar vektorgrafik +Comment[ta]=அளவிடக்கூடிய வெக்டார் சித்திரங்கள் காட்சி +Comment[tg]=Намоиши SVG +Comment[tr]=Boyutlandırılabilir Vektör Grafik Gösterici +Comment[uk]=Переглядач векторної графіки +Comment[uz]=SVG koʻruvchi +Comment[uz@cyrillic]=SVG кўрувчи +Comment[ven]=Muvhono wa girafiki wa scalable vector +Comment[xh]=Umboniseli wemizobo olinganiselwayo onesalathiso +Comment[zh_CN]=可缩放矢量图查看器 +Comment[zh_HK]=可縮放向量圖形(SVG)檢視器 +Comment[zh_TW]=可調整的向量圖形檢視器 +Comment[zu]=Umbonisi wemidwebo Onenani Elibalekayo +Type=Service +ServiceTypes=KParts/ReadOnlyPart,Browser/View +X-KDE-Library=libksvgplugin +InitialPreference=11 diff --git a/ksvg/plugin/ksvgplugin.rc b/ksvg/plugin/ksvgplugin.rc new file mode 100644 index 00000000..a689f4d8 --- /dev/null +++ b/ksvg/plugin/ksvgplugin.rc @@ -0,0 +1,35 @@ + + + + &Settings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ksvg/plugin/svgcreator.cpp b/ksvg/plugin/svgcreator.cpp new file mode 100644 index 00000000..c6689c9a --- /dev/null +++ b/ksvg/plugin/svgcreator.cpp @@ -0,0 +1,92 @@ +/* + Copyright (c) 2001 Malte Starostik + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +// $Id$ + +#include + +#include +#include + +#include "KSVGCanvas.h" +#include "CanvasFactory.h" + +#include + +#include "SVGSVGElementImpl.h" +#include "SVGDocumentImpl.h" + +#include "svgcreator.moc" + +extern "C" +{ + ThumbCreator *new_creator() + { + return new SVGCreator; + } +} + +SVGCreator::SVGCreator() +{ +} + +SVGCreator::~SVGCreator() +{ +} + +bool SVGCreator::create(const QString &path, int width, int height, QImage &img) +{ + KSVG::SVGDocumentImpl *doc = new KSVG::SVGDocumentImpl(false, true); + doc->ref(); + + QPixmap pix(width, height); + pix.fill(Qt::white); + + KSVG::KSVGCanvas *c = KSVG::CanvasFactory::self()->loadCanvas(width, height); + c->setup(&pix, &pix); + + doc->attach(c); + connect(doc, SIGNAL(finishedRendering()), SLOT(slotFinished())); + doc->open( KURL::fromPathOrURL(path)); + + m_finished = false; + + while(!m_finished) + kapp->processOneEvent(); + + doc->deref(); + + img = pix.convertToImage(); + + delete c; + + return true; +} + +void SVGCreator::slotFinished() +{ + m_finished = true; +} + +ThumbCreator::Flags SVGCreator::flags() const +{ + return DrawFrame; +} + +// vim: ts=4 sw=4 noet diff --git a/ksvg/plugin/svgcreator.h b/ksvg/plugin/svgcreator.h new file mode 100644 index 00000000..ad1b8f30 --- /dev/null +++ b/ksvg/plugin/svgcreator.h @@ -0,0 +1,45 @@ +/* + Copyright (c) 2001 Malte Starostik + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +// $Id$ + +#ifndef __svgcreator_h__ +#define __svgcreator_h__ + +#include + +class SVGCreator : public QObject, public ThumbCreator +{ + Q_OBJECT +public: + SVGCreator(); + virtual ~SVGCreator(); + virtual bool create(const QString &path, int width, int height, QImage &img); + virtual Flags flags() const; + +private slots: + void slotFinished(); + +private: + bool m_finished; +}; + +#endif + +// vim: ts=4 sw=4 noet diff --git a/ksvg/plugin/svgthumbnail.desktop b/ksvg/plugin/svgthumbnail.desktop new file mode 100644 index 00000000..47fed23b --- /dev/null +++ b/ksvg/plugin/svgthumbnail.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Type=Service +Name=Scalable Vector Graphics +Name[ar]=رسومات ثابتة قابلة للقياس +Name[az]=Miqyaslı Vektor Qrafikaları +Name[ca]=Gràfics vectorials escalables (SVG) +Name[cy]=Graffeg Fector Graddedig +Name[da]=Skalerbar vektorgrafik +Name[de]=Skalierbare Vektorgraphiken +Name[el]=Διανυσματικά γραφικά +Name[eo]=Vektorgrafikoj +Name[es]=Gráficos vectoriales escalables (SVG) +Name[et]=Skaleeritav vektorgraafika (SVG) +Name[fa]=نگاره‌سازی مقیاس‌پذیر برداری +Name[fr]=Graphisme vectoriel échelonnable (SVG) +Name[gl]=Gráficos vectoriais escalables +Name[hi]=स्केलेबल वेक्टर ग्राफिक्स +Name[hu]=SVG +Name[it]=Grafica vettoriale riscalabile +Name[ja]=SVG (スケーラブルベクトルグラフィックス) +Name[kk]=SVG сызбалы суреттер +Name[km]=ក្រាហ្វិក​វ៉ិចទ័រ​មាន​មាត្រដ្ឋាន +Name[lt]=Kintamo dydžio vektorinė grafika +Name[lv]=Mērogojama Vektoru Grafika +Name[ms]=Grafik Vektor Boleh Skala +Name[nds]=Skaleerbor Vektorgrafiken +Name[ne]=मापनयोग्य भेक्टर ग्राफिक्स +Name[pl]=Skalowalna Grafika Wektorowa +Name[pt]=SVG - Gráficos Vectoriais Escaláveis +Name[pt_BR]=Vetores Escaláveis +Name[ro]=Grafică vectorială scalabilă (SVG) +Name[ru]=Векторные рисунки (.svg) +Name[sl]=Skalabilna vektorska grafika +Name[sr]=Скалабилна векторска графика (SVG) +Name[sr@Latn]=Skalabilna vektorska grafika (SVG) +Name[sv]=Skalbar vektorgrafik +Name[ta]=அளவிடக்கூடிய வெக்டார் சித்திரங்கள் +Name[tg]=Расмҳои вектории масштабкунанда (SVG) +Name[tr]=Boyutlandırılabilir Vektör Grafiği +Name[uk]=Масштабовна векторна графіка +Name[ven]=Dzigirafiki ya vekitha ya Scalable +Name[xh]=Imizobo elinganiselwayo enesalathisi +Name[zh_CN]=可缩放矢量图 +Name[zh_HK]=可縮放向量圖形(SVG) +Name[zh_TW]=可調整的向量圖形 +Name[zu]=Imidwebo Enenani Elibalekayo +Icon=thumbnail +MimeTypes=image/svg+xml +X-KDE-Library=svgthumbnail +ServiceTypes=ThumbCreator +InitialPreference=5 +CacheThumbnail=true diff --git a/ksvg/scripts/COPYRIGHTS b/ksvg/scripts/COPYRIGHTS new file mode 100644 index 00000000..bcb24052 --- /dev/null +++ b/ksvg/scripts/COPYRIGHTS @@ -0,0 +1,19 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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. +*/ diff --git a/ksvg/scripts/ECMACHECK b/ksvg/scripts/ECMACHECK new file mode 100755 index 00000000..955ea81d --- /dev/null +++ b/ksvg/scripts/ECMACHECK @@ -0,0 +1,25 @@ +#!/bin/bash +TESTSUITE=test/official/1.0 # Nikos setting +ECMATESTS=test/ecma +konqueror $TESTSUITE/script-eventDom-BE-01.svg +konqueror $TESTSUITE/script-uiEvents-BE-02.svg +konqueror $TESTSUITE/dom-core-BE-01.svg +konqueror $TESTSUITE/dom-eventListener-BE-04.svg +konqueror $TESTSUITE/dom-featureString-BE-03.svg +konqueror $TESTSUITE/dom-svg-BE-02.svg +konqueror $TESTSUITE/extend-multiNS-BE-01.svg +konqueror $TESTSUITE/interact-onload-BE-07.svg +konqueror $TESTSUITE/interact-bubble-BE-04.svg +konqueror $TESTSUITE/interact-pEvents-BE-05.svg +konqueror $TESTSUITE/interact-pEvents-BE-06.svg +konqueror $ECMATESTS/broken.svg +konqueror $ECMATESTS/circle.svg +konqueror $ECMATESTS/clock.svg +konqueror $ECMATESTS/bbox/bbox-circle.svg +konqueror $ECMATESTS/bbox/bbox-ellipse.svg +konqueror $ECMATESTS/bbox/bbox-line.svg +konqueror $ECMATESTS/bbox/bbox-path.svg +konqueror $ECMATESTS/bbox/bbox-path2.svg +konqueror $ECMATESTS/bbox/bbox-polygon.svg +konqueror $ECMATESTS/bbox/bbox-polyline.svg +konqueror $ECMATESTS/bbox/bbox-rect.svg diff --git a/ksvg/scripts/OPENREF b/ksvg/scripts/OPENREF new file mode 100755 index 00000000..f8fbecb0 --- /dev/null +++ b/ksvg/scripts/OPENREF @@ -0,0 +1,9 @@ +#!/bin/bash +pid=`dcopstart konqueror --profile filemanagement` +loc=`pwd`/$1 +sleep 1 +dcop $pid konqueror-mainwindow#1 openURL ${loc}svg +sleep 1 +dcop $pid qt/KXMLGUILClient-KActionCollection/splitviewh activate +sleep 1 +dcop $pid konqueror-mainwindow#1 openURL ${loc}png diff --git a/ksvg/scripts/README b/ksvg/scripts/README new file mode 100644 index 00000000..17130216 --- /dev/null +++ b/ksvg/scripts/README @@ -0,0 +1,16 @@ +This document explains how to generate a SVG C++ header/sourcefile pair : + +1. go to dir idl +2. copy the svg.idl file to the classname you want to generate, for example SVGRect +3. edit the newly created file to only include the class info, delete the rest +4. run ../gen.sh classname (without extension) to generate the pair + +Caveats: +1. all inheritance specification must be on the same line +2. no support yet for exceptions, comments +3. this works for mawk 1.3.3, with slight adjustments it should run for + other awk implementations + +07-07-2001 +Rob Buis. + diff --git a/ksvg/scripts/add_static.pl b/ksvg/scripts/add_static.pl new file mode 100644 index 00000000..9a88c00f --- /dev/null +++ b/ksvg/scripts/add_static.pl @@ -0,0 +1,42 @@ +# Add #include "ksvg_lookup.h", GENERATEDDATA and ELEMENTDATA to all headers passed as argument +# Usage: perl -w -i.bak add_static.pl *.h +my $added_ksvg_lookup = 0; +#my $added_staticdata = 0; +my $inclass=0; +my $bracelevel=0; +my $class_bracelevel; +my $has_staticdata=0; +while (<>) { + $added_ksvg_lookup=0 if (/\#ifndef/); # this while loop runs over multiple files... + $added_ksvg_lookup=1 if (/\#include \"ksvg_lookup.h\"/); # already there + if (!$added_ksvg_lookup) { + if (/^\s*\#\s*include/ || /^namespace/ || /^class/) { + $added_ksvg_lookup = 1; + print '#include "ksvg_lookup.h"' . "\n"; + } + } + if ( /^class/ && !/;/ ) { + die if $inclass; + $inclass=1; + $class_bracelevel=$bracelevel; + $has_staticdata=0; + } + if ( /{/ ) { + $bracelevel++; + die if /{.*{/; # not handled currently + } + if ( /}/ ) { + $bracelevel--; + die if /}.*}/; # not handled currently + } + $has_staticdata = 1 if ( $inclass && /GENERATEDDATA/ ); + if ( $inclass && ($class_bracelevel == $bracelevel) && /};/ ) { + print "public:\n\tGENERATEDDATA\n" if ( !$has_staticdata ); + $inclass=0; + # $added_staticdata=1; + } + print; +} +die "still in class!" if ($inclass); +die "bracelevel != 0!" if ($bracelevel); +#die "found no class where to add GENERATEDDATA!" if (!$added_staticdata); diff --git a/ksvg/scripts/check_hashtablesize.pl b/ksvg/scripts/check_hashtablesize.pl new file mode 100755 index 00000000..d22e3f30 --- /dev/null +++ b/ksvg/scripts/check_hashtablesize.pl @@ -0,0 +1,224 @@ +# Script to check hashtable sizes. +# Copyright 2002 Nikolas Zimmermann + +my $input = shift; +my $calcMode = 0; + +# Check incoming arguments +if(length($input) > 0) { + $calcMode = $input; +} else { + print "Usage:\n"; + print "perl check_hashtablesize.pl [0/1/2]\n\n"; + print "Show...\n"; + print "0) all hashtables of prototype definitions\n"; + print "1) all hashtables of non-prototype definitions\n"; + print "2) all hashtables of svg*constructor definitions\n"; + exit(-1); +} + +# Test if a number is prime or not +sub calcPrime +{ + my $start = shift; + my $dividecount = 0; + + for(my $i = $start - 1; $i > 0; --$i) + { + my $result = $start / $i; + + if($result == int($result)) { + $dividecount++; + } + } + + if($dividecount == 1) { + return 1; + } else { + return 0; + } +} + +# Find the next prime number +sub findNextPrime +{ + my $start = shift; + my $i = $start + 1; + my $found = 0; + + while($found == 0) + { + if(calcPrime($i)) { + $found = 1; + } else { + $i++; + } + } + + return $i; +} + +# Common routine for calculating hashtable sizes +sub calcSize +{ + my $calc = shift; + my $save = shift; + my $minus = shift; + + my @temp = split(/\n/, $calc); + + foreach(@temp) { + my $process = $_; + $process =~ s/\s+/ /g; + + my @line = split(/ /, $process); + my $class = substr($line[1], 0, index($line[1], ":") - $minus); + + $$save{$class} = $line[2]; + } +} + +# Go to impl dir +chdir "../impl"; + +# Global counters +my %counterwork; +my %counter1; +my %counter2; +my %counter3; + +# Read hashtable size +my $readSize1 = `find -type f | xargs grep -I DontDelete | grep -v KSVG:: | grep Function`; +my $readSize2 = `find -type f | xargs grep -I DontDelete | grep -v KSVG:: | grep -v Function`; +my $readSize3 = `find -type f | xargs grep -I DontDelete | grep KSVG::`; + +my @result1 = split(/.\//, $readSize1); +my @result2 = split(/.\//, $readSize2); +my @result3 = split(/.\//, $readSize3); + +# Calculate hashtable size +# calcSize1 = print out all prototype hashtables +# calcSize2 = print out all non-prototype hashtables +# calcSize3 = print out all svg*constructors hashtables +my $calcSize1 = `find -type f | xargs grep -I s_hashTable | grep \@begin | grep -v generateddata | grep -v Constructor | grep -v Impl:: | grep -v Bridge::`; +my $calcSize2 = `find -type f | xargs grep -I s_hashTable | grep \@begin | grep -v generateddata | grep -v Constructor | grep -v Proto::`; +my $calcSize3 = `find -type f | xargs grep -I s_hashTable | grep \@begin | grep -v generateddata | grep Constructor`; + +# Bring in suitable form +calcSize($calcSize1, \%counter1, 5); +calcSize($calcSize2, \%counter2, 0); +calcSize($calcSize3, \%counter3, 11); + +# Helper +my $lastclass = ""; + +print "Classname\t\t\t\t'H.S. File'\t\t'H.S. Calculated'\tIs 'H.S. File' prime?\tDo they differ?\n"; +print "-------------------------------------------------------------------------------------------------------------------------------\n"; + +my @useresult; +if($calcMode == 0) { + @useresult = @result1; +} elsif($calcMode == 1) { + @useresult = @result2; +} else { + @useresult = @result3; +} + +foreach(@useresult) { + my $line = $_; + $line =~ s/\s+/ /g; + + if($line ne "") { + my @middle = split(/ /, $line); + my $class = substr($middle[2], 0, index($middle[2], ":")); + + # Special case for lists and svg*constructors + if($class eq "SVGListDefs" || $calcMode == 2) + { + my $temp = $middle[0]; + + if($calcMode != 2) { + $temp =~ s/.cc://; + $class = $temp; + } else { + $temp =~ s/.cc//; + $class = substr($temp, 0, index($temp, ":")); + } + } + + if($class eq $lastclass) { + $counterwork{$class}++; + } + else { + $counterwork{$class} = 1; + + if($lastclass ne "") { + my $len = length($lastclass); + + my $string = $lastclass; + + # Ugly hack with those numbers, anyone + # got a better idea? + if($len < 11) { + $string .= "\t\t\t\t\t"; + } elsif($len < 16) { + $string .= "\t\t\t\t"; + } elsif($len < 24) { + $string .= "\t\t\t"; + } elsif($len < 32) { + $string .= "\t\t"; + } else { + $string .= "\t"; + } + + my $combine; + + if($calcMode == 0) { + $combine = $counter1{$lastclass}; + } elsif($calcMode == 1) { + $combine = $counter2{$lastclass}; + } else { + $combine = $counter3{$lastclass}; + } + + if($combine eq 0 || $combine eq "") { + $combine = "-"; + } + + $string .= $combine; + $string .= "\t\t\t"; + + # Find next prime + my $next = findNextPrime($counterwork{$lastclass}); + + $string .= $next; + $string .= "\t\t\t"; + + # Is 'H.S. File' a prime? + my $calc = calcPrime($combine); + if($calc == 0) { + $string .= "NO!"; + } else { + $string .= "Yes"; + } + + $string .= "\t\t\t"; + + if($combine != $next) { + $string .= "YES!"; + } else { + $string .= "No"; + } + + $string .= "\n"; + + print $string; + } + } + + $lastclass = $class; + } +} + +# Go back! :) +chdir "../scripts"; diff --git a/ksvg/scripts/gen.sh b/ksvg/scripts/gen.sh new file mode 100755 index 00000000..d608385b --- /dev/null +++ b/ksvg/scripts/gen.sh @@ -0,0 +1,51 @@ +# try to find an appropriate awk interpreter +if which mawk > /dev/null 2>&1; then + cmd_awk=`which mawk`; +else + if which awk > /dev/null 2>&1; then + cmd_awk=`which awk`; + else + echo "No suitable AWK interpreter found. Aborting." + exit 1 + fi +fi + +# make them +touch $1.h +touch $1.cc + +#start with copyright notices +cat ../COPYRIGHTS > $1.h +cat ../COPYRIGHTS > $1.cc + +# add define for multiple include problem +echo "" >> $1.h +echo "#ifndef $1_H" >> $1.h +echo "#define $1_H" >> $1.h +echo "" >> $1.h +echo "namespace KSVG" >> $1.h +echo "{" >> $1.h +echo "" >> $1.h + +#include in .cc + namespace +echo "" >> $1.cc +echo "#include \"$1.h\"" >> $1.cc +echo "#include \"$1Impl.h\"" >> $1.cc +echo "" >> $1.cc +echo "using namespace KSVG;" >> $1.cc +echo "" >> $1.cc + +#go go go +$cmd_awk -f ../makeheader $1 +$cmd_awk -f ../makecc $1 + +#add end of define +echo "};" >> $1.h +echo "" >> $1.h +echo "#endif" >> $1.h +echo "" >> $1.h + +echo "// vim:ts=4:noet" >> $1.h +echo "// vim:ts=4:noet" >> $1.cc + +#done I hope diff --git a/ksvg/scripts/generate.pl b/ksvg/scripts/generate.pl new file mode 100755 index 00000000..a9419dcc --- /dev/null +++ b/ksvg/scripts/generate.pl @@ -0,0 +1,69 @@ +#!/usr/bin/perl -w + +my $kalyptusdir = "../../../kdebindings/kalyptus"; + +use File::Basename; + +my $here = `pwd`; +chomp $here; +my $outdir = $here . "/generate.pl.tmpdir"; +my $finaloutdir = $here; + +## Note: outdir and finaloutdir should NOT be the same dir! + +if (! -d $outdir) { mkdir $outdir; } + +mkdir $finaloutdir unless (-d $finaloutdir); + + +# Need to cd to kalyptus's directory so that perl finds Ast.pm etc. +chdir "$kalyptusdir" or die "Couldn't go to $kalyptusdir (edit script to change dir)\n"; + +# Find out which header files we need to parse +my %excludes = ( +); + +# List headers, and exclude the ones listed above +my @headers = (); +my $incdir=$here; +opendir (INCS, $incdir) or die "Couldn't find $incdir"; +foreach $filename (readdir(INCS)) { + $entry = $incdir."/".$filename; + if ( ( -e $entry or -l $entry ) # A real file or a symlink + && ( ! -d _ ) ) # Not a symlink to a dir though + { + push(@headers, $entry) + if ( !defined $excludes{$filename} # Not excluded + && $filename =~ /\.h$/ ); # Not a backup file etc. Only headers. + } +} +closedir INCS; + +# Launch kalyptus +system "perl kalyptus @ARGV -fECMA --name=ksvg --outputdir=$outdir @headers"; +my $exit = $? >> 8; +exit $exit if ($exit); + +# Generate diff for generateddata.cpp +if ( -e "$finaloutdir/generateddata.cpp" ) { + system "diff -u $finaloutdir/generateddata.cpp $outdir/generateddata.cpp > $outdir/generateddata.cpp.diff"; +} + +# Copy changed or new files to finaloutdir +#opendir (OUT, $outdir) or die "Couldn't opendir $outdir"; +#foreach $filename (readdir(OUT)) { +my $filename = "generateddata.cpp"; + #next if ( -d "$outdir/$filename" ); # only files, not dirs + my $docopy = 1; + if ( -f "$finaloutdir/$filename" ) { + # How can I do a fast file compare in perl? + system "cmp -s $outdir/$filename $finaloutdir/$filename"; + $docopy = ($?>>8); # 0 if files identical, 1 if different + } + if ($docopy) { + #print STDERR "Updating $filename...\n"; + system "cp -f $outdir/$filename $finaloutdir/$filename"; + } + +# Delete outdir +system "rm -rf $outdir"; diff --git a/ksvg/scripts/genimpl.sh b/ksvg/scripts/genimpl.sh new file mode 100755 index 00000000..5a0742d2 --- /dev/null +++ b/ksvg/scripts/genimpl.sh @@ -0,0 +1,49 @@ +# try to find an appropriate awk interpreter +if which mawk > /dev/null 2>&1; then + cmd_awk=`which mawk`; +else + if which awk > /dev/null 2>&1; then + cmd_awk=`which awk`; + else + echo "No suitable AWK interpreter found. Aborting." + exit 1 + fi +fi + +# you cant touch this +touch $1Impl.h +touch $1Impl.cc + +#start with copyright notices +cat ../COPYRIGHTS > $1Impl.h +cat ../COPYRIGHTS > $1Impl.cc + +# add define for multiple include problem +echo "" >> $1Impl.h +echo "#ifndef $1Impl_H" >> $1Impl.h +echo "#define $1Impl_H" >> $1Impl.h + +# namespace +echo "" >> $1Impl.h +echo "namespace KSVG" >> $1Impl.h +echo "{" >> $1Impl.h + +#include in .cc + namespace +echo "" >> $1Impl.cc +echo "#include \"$1Impl.h\"" >> $1Impl.cc +echo "" >> $1Impl.cc +echo "using namespace KSVG;" >> $1Impl.cc +echo "" >> $1Impl.cc + +#go go go +$cmd_awk -f ../makeimpl $1 + +#add end of define +echo "};" >> $1Impl.h +echo "" >> $1Impl.h +echo "#endif" >> $1Impl.h +echo "" >> $1Impl.h +echo "// vim:ts=4:noet" >> $1Impl.h + +echo "// vim:ts=4:noet" >> $1Impl.cc +#done I hope diff --git a/ksvg/scripts/getjs.php b/ksvg/scripts/getjs.php new file mode 100755 index 00000000..5f300fe9 --- /dev/null +++ b/ksvg/scripts/getjs.php @@ -0,0 +1,390 @@ +#!/usr/local/bin/php +class=$name; + $this->functions=array(); + $this->properties=array(); + $this->constants=array(); + $this->parmas=array(); + } + + function add_content($content) + { + if ($content->type==0) + { + if (!in_array($content->name,$this->properties)) + { + $this->properties[]=$content->name; + $this->readonly[$content->name]=$content->readonly; + } + } + elseif ($content->type==1) + { + if (!in_array($content->name,$this->functions)) + { + $this->functions[]=$content->name; + $this->params[$content->name]=$content->params; + } + } + elseif ($content->type==2) + { + if (!in_array($content->name,$this->constants)) + $this->constants[]=$content->name; + } + } + + function to_text() + { + $headline=$this->class." (".(sizeof($this->properties))." Properties and ".(sizeof($this->functions))." Functions and ".(sizeof($this->constants))." Constants)"; + echo($headline."\n"); + echo("===================="); + echo("\n\n"); + + + echo("Properties\n"); + echo("----------\n"); + for ($i=0;$iproperties);$i++) + { + echo($this->properties[$i]."\n"); + } + + echo("\n"); + echo("Functions\n"); + echo("----------\n"); + for ($i=0;$ifunctions);$i++) + { + echo($this->functions[$i]."\n"); + } + + echo("\n"); + echo("Constants\n"); + echo("----------\n"); + for ($i=0;$iconstants);$i++) + { + echo($this->constants[$i]."\n"); + } + + echo("\n%%%%%%%%%%%%%%%%%%%%%%%%\n\n"); + } + + function to_html() + { + echo("class."\">"); + echo("Back to Index"); + echo("
%1 %2
%1 %2
%1
%1 %2
%1 %2
nor (without + // concantenating sentences and words with tense). However, it is + // recommended that you give them the following values: + // + // e.g.: + // text = i18n ("

(Rotating|Skewing) the (image|selection) to" + // " %1x%2 may take a substantial amount of memory." + // " This can reduce system" + // " responsiveness and cause other application resource" + // " problems.

").arg (newWidth, newHeight) + // + // "

Are you sure want to (rotate|skew) the" + // " (image|selection)?

"); + // caption = i18n ("Rotate (Image|Selection)?"); + // continueButtonText = i18n ("Rotat&e (Image|Selection)"); + static bool warnIfBigImageSize (int oldWidth, int oldHeight, + int newWidth, int newHeight, + const QString &text, + const QString &caption, + const QString &continueButtonText, + QWidget *parent); + + +protected: + // There is no need to maintain binary compatibility at this stage. + // The d-pointer is just so that you can experiment without recompiling + // the kitchen sink. + class kpToolPrivate *d; +}; + +#endif // __kp_tool_h__ diff --git a/kolourpaint/kpview.cpp b/kolourpaint/kpview.cpp new file mode 100644 index 00000000..1f18c659 --- /dev/null +++ b/kolourpaint/kpview.cpp @@ -0,0 +1,1910 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_VIEW 0 +#define DEBUG_KP_VIEW_RENDERER ((DEBUG_KP_VIEW && 0) || 0) + + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if DEBUG_KP_VIEW || DEBUG_KP_VIEW_RENDERER + #include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +struct kpViewPrivate +{ + // sync: kpView::paintEvent() + // + // Normally, these pointers must be valid while the kpView is alive. + // Generally, the objects they point to are deleted only after kpView + // is deleted. + // + // However, sometimes we use deleteLater() for the kpView. + // Before the delayed deletion is executed, those objects are deleted + // and then our paintEvent() is called. paintEvent() must therefore + // have some way of realising that those objects have been deleted so + // we use guardded pointers. + // + // For more details, see SVN commit: + // "r385274 | dang | 2005-02-02 22:08:27 +1100 (Wed, 02 Feb 2005) | 21 lines". + QGuardedPtr m_document; + QGuardedPtr m_toolToolBar; + QGuardedPtr m_viewManager; + QGuardedPtr m_buddyView; + QGuardedPtr m_scrollableContainer; + + int m_hzoom, m_vzoom; + QPoint m_origin; + bool m_showGrid; + bool m_isBuddyViewScrollableContainerRectangleShown; + QRect m_buddyViewScrollableContainerRectangle; + + QRegion m_queuedUpdateArea; + QPixmap *m_backBuffer; +}; + + +kpView::kpView (kpDocument *document, + kpToolToolBar *toolToolBar, + kpViewManager *viewManager, + kpView *buddyView, + kpViewScrollableContainer *scrollableContainer, + QWidget *parent, const char *name) + + : QWidget (parent, name, Qt::WNoAutoErase/*no flicker*/), + d (new kpViewPrivate ()) +{ + d->m_document = document; + d->m_toolToolBar = toolToolBar; + d->m_viewManager = viewManager; + d->m_buddyView = buddyView; + d->m_scrollableContainer = scrollableContainer; + + d->m_hzoom = 100, d->m_vzoom = 100; + d->m_origin = QPoint (0, 0); + d->m_showGrid = false; + d->m_isBuddyViewScrollableContainerRectangleShown = false; + + d->m_backBuffer = 0; + + + setBackgroundMode (Qt::NoBackground); // no flicker + setFocusPolicy (QWidget::WheelFocus); + setMouseTracking (true); // mouseMoveEvent's even when no mousebtn down + setKeyCompression (true); + setInputMethodEnabled (true); // ensure using InputMethod +} + +kpView::~kpView () +{ + setHasMouse (false); + + delete d->m_backBuffer; + delete d; +} + + +// public +kpDocument *kpView::document () const +{ + return d->m_document; +} + +// protected +kpSelection *kpView::selection () const +{ + return document () ? document ()->selection () : 0; +} + +// public +kpToolToolBar *kpView::toolToolBar () const +{ + return d->m_toolToolBar; +} + +// protected +kpTool *kpView::tool () const +{ + return toolToolBar () ? toolToolBar ()->tool () : 0; +} + +// public +kpViewManager *kpView::viewManager () const +{ + return d->m_viewManager; +} + +// public +kpView *kpView::buddyView () const +{ + return d->m_buddyView; +} + +// public +kpViewScrollableContainer *kpView::buddyViewScrollableContainer () const +{ + return (buddyView () ? buddyView ()->scrollableContainer () : 0); +} + +// public +kpViewScrollableContainer *kpView::scrollableContainer () const +{ + return d->m_scrollableContainer; +} + + +// public +int kpView::zoomLevelX (void) const +{ + return d->m_hzoom; +} + +// public +int kpView::zoomLevelY (void) const +{ + return d->m_vzoom; +} + +// public virtual +void kpView::setZoomLevel (int hzoom, int vzoom) +{ + if (hzoom == d->m_hzoom && vzoom == d->m_vzoom) + return; + + if (hzoom <= 0 || vzoom <= 0) + return; + + d->m_hzoom = hzoom; + d->m_vzoom = vzoom; + + if (viewManager ()) + viewManager ()->updateView (this); + + emit zoomLevelChanged (hzoom, vzoom); +} + + +// public +QPoint kpView::origin () const +{ + return d->m_origin; +} + +// public virtual +void kpView::setOrigin (const QPoint &origin) +{ +#if DEBUG_KP_VIEW + kdDebug () << "kpView(" << name () << ")::setOrigin" << origin << endl; +#endif + + if (origin == d->m_origin) + { + #if DEBUG_KP_VIEW + kdDebug () << "\tNOP" << endl; + #endif + return; + } + + d->m_origin = origin; + + if (viewManager ()) + viewManager ()->updateView (this); + + emit originChanged (origin); +} + + +// public +bool kpView::canShowGrid () const +{ + // (minimum zoom level < 400% would probably be reported as a bug by + // users who thought that the grid was a part of the image!) + return ((zoomLevelX () >= 400 && zoomLevelX () % 100 == 0) && + (zoomLevelY () >= 400 && zoomLevelY () % 100 == 0)); +} + +// public +bool kpView::isGridShown () const +{ + return d->m_showGrid; +} + +// public +void kpView::showGrid (bool yes) +{ + if (d->m_showGrid == yes) + return; + + if (yes && !canShowGrid ()) + return; + + d->m_showGrid = yes; + + if (viewManager ()) + viewManager ()->updateView (this); +} + + +// public +bool kpView::isBuddyViewScrollableContainerRectangleShown () const +{ + return d->m_isBuddyViewScrollableContainerRectangleShown; +} + +// public +void kpView::showBuddyViewScrollableContainerRectangle (bool yes) +{ + if (yes == d->m_isBuddyViewScrollableContainerRectangleShown) + return; + + d->m_isBuddyViewScrollableContainerRectangleShown = yes; + + if (d->m_isBuddyViewScrollableContainerRectangleShown) + { + // Got these connect statements by analysing deps of + // updateBuddyViewScrollableContainerRectangle() rect update code. + + connect (this, SIGNAL (zoomLevelChanged (int, int)), + this, SLOT (updateBuddyViewScrollableContainerRectangle ())); + connect (this, SIGNAL (originChanged (const QPoint &)), + this, SLOT (updateBuddyViewScrollableContainerRectangle ())); + + if (buddyViewScrollableContainer ()) + { + connect (buddyViewScrollableContainer (), SIGNAL (contentsMovingSoon (int, int)), + this, SLOT (updateBuddyViewScrollableContainerRectangle ())); + connect (buddyViewScrollableContainer (), SIGNAL (resized ()), + this, SLOT (updateBuddyViewScrollableContainerRectangle ())); + } + + if (buddyView ()) + { + connect (buddyView (), SIGNAL (zoomLevelChanged (int, int)), + this, SLOT (updateBuddyViewScrollableContainerRectangle ())); + connect (buddyView (), SIGNAL (originChanged (const QPoint &)), + this, SLOT (updateBuddyViewScrollableContainerRectangle ())); + + connect (buddyView (), SIGNAL (sizeChanged (int, int)), + this, SLOT (updateBuddyViewScrollableContainerRectangle ())); + } + + } + else + { + disconnect (this, SIGNAL (zoomLevelChanged (int, int)), + this, SLOT (updateBuddyViewScrollableContainerRectangle ())); + disconnect (this, SIGNAL (originChanged (const QPoint &)), + this, SLOT (updateBuddyViewScrollableContainerRectangle ())); + + if (buddyViewScrollableContainer ()) + { + disconnect (buddyViewScrollableContainer (), SIGNAL (contentsMovingSoon (int, int)), + this, SLOT (updateBuddyViewScrollableContainerRectangle ())); + disconnect (buddyViewScrollableContainer (), SIGNAL (resized ()), + this, SLOT (updateBuddyViewScrollableContainerRectangle ())); + } + + if (buddyView ()) + { + disconnect (buddyView (), SIGNAL (zoomLevelChanged (int, int)), + this, SLOT (updateBuddyViewScrollableContainerRectangle ())); + disconnect (buddyView (), SIGNAL (originChanged (const QPoint &)), + this, SLOT (updateBuddyViewScrollableContainerRectangle ())); + + disconnect (buddyView (), SIGNAL (sizeChanged (int, int)), + this, SLOT (updateBuddyViewScrollableContainerRectangle ())); + } + + } + + updateBuddyViewScrollableContainerRectangle (); +} + + +// protected +QRect kpView::buddyViewScrollableContainerRectangle () const +{ + return d->m_buddyViewScrollableContainerRectangle; +} + +// protected slot +void kpView::updateBuddyViewScrollableContainerRectangle () +{ + if (viewManager ()) + viewManager ()->setQueueUpdates (); + + { + if (d->m_buddyViewScrollableContainerRectangle.isValid ()) + { + if (viewManager ()) + { + // Erase last + viewManager ()->updateViewRectangleEdges (this, + d->m_buddyViewScrollableContainerRectangle); + } + } + + + QRect newRect; + if (isBuddyViewScrollableContainerRectangleShown () && + buddyViewScrollableContainer () && buddyView ()) + { + QRect docRect = buddyView ()->transformViewToDoc ( + QRect (buddyViewScrollableContainer ()->contentsXSoon (), + buddyViewScrollableContainer ()->contentsYSoon (), + QMIN (buddyView ()->width (), + buddyViewScrollableContainer ()->visibleWidth ()), + QMIN (buddyView ()->height (), + buddyViewScrollableContainer ()->visibleHeight ()))); + + + QRect viewRect = this->transformDocToView (docRect); + + + // (Surround the area of interest by moving outwards by 1 pixel in each + // direction - don't overlap area) + newRect = QRect (viewRect.x () - 1, + viewRect.y () - 1, + viewRect.width () + 2, + viewRect.height () + 2); + } + else + { + newRect = QRect (); + } + + if (newRect != d->m_buddyViewScrollableContainerRectangle) + { + // (must set before updateView() for paintEvent() to see new + // rect) + d->m_buddyViewScrollableContainerRectangle = newRect; + + if (newRect.isValid ()) + { + if (viewManager ()) + { + viewManager ()->updateViewRectangleEdges (this, + d->m_buddyViewScrollableContainerRectangle); + } + } + } + } + + if (viewManager ()) + viewManager ()->restoreQueueUpdates (); +} + + +// public +double kpView::transformViewToDocX (double viewX) const +{ + return (viewX - origin ().x ()) * 100.0 / zoomLevelX (); +} + +// public +double kpView::transformViewToDocY (double viewY) const +{ + return (viewY - origin ().y ()) * 100.0 / zoomLevelY (); +} + +// public +QPoint kpView::transformViewToDoc (const QPoint &viewPoint) const +{ + return QPoint ((int) transformViewToDocX (viewPoint.x ()), + (int) transformViewToDocY (viewPoint.y ())); +} + +// public +QRect kpView::transformViewToDoc (const QRect &viewRect) const +{ + if (zoomLevelX () == 100 && zoomLevelY () == 100) + { + return QRect (viewRect.x () - origin ().x (), + viewRect.y () - origin ().y (), + viewRect.width (), + viewRect.height ()); + } + else + { + const QPoint docTopLeft = transformViewToDoc (viewRect.topLeft ()); + + // (don't call transformViewToDoc[XY]() - need to round up dimensions) + const int docWidth = qRound (double (viewRect.width ()) * 100.0 / double (zoomLevelX ())); + const int docHeight = qRound (double (viewRect.height ()) * 100.0 / double (zoomLevelY ())); + + // (like QWMatrix::Areas) + return QRect (docTopLeft.x (), docTopLeft.y (), docWidth, docHeight); + } +} + + +// public +double kpView::transformDocToViewX (double docX) const +{ + return (docX * zoomLevelX () / 100.0) + origin ().x (); +} + +// public +double kpView::transformDocToViewY (double docY) const +{ + return (docY * zoomLevelY () / 100.0) + origin ().y (); +} + +// public +QPoint kpView::transformDocToView (const QPoint &docPoint) const +{ + return QPoint ((int) transformDocToViewX (docPoint.x ()), + (int) transformDocToViewY (docPoint.y ())); +} + +// public +QRect kpView::transformDocToView (const QRect &docRect) const +{ + if (zoomLevelX () == 100 && zoomLevelY () == 100) + { + return QRect (docRect.x () + origin ().x (), + docRect.y () + origin ().y (), + docRect.width (), + docRect.height ()); + } + else + { + const QPoint viewTopLeft = transformDocToView (docRect.topLeft ()); + + // (don't call transformDocToView[XY]() - need to round up dimensions) + const int viewWidth = qRound (double (docRect.width ()) * double (zoomLevelX ()) / 100.0); + const int viewHeight = qRound (double (docRect.height ()) * double (zoomLevelY ()) / 100.0); + + // (like QWMatrix::Areas) + return QRect (viewTopLeft.x (), viewTopLeft.y (), viewWidth, viewHeight); + } +} + + +// public +QPoint kpView::transformViewToOtherView (const QPoint &viewPoint, + const kpView *otherView) +{ + if (this == otherView) + return viewPoint; + + const double docX = transformViewToDocX (viewPoint.x ()); + const double docY = transformViewToDocY (viewPoint.y ()); + + const double otherViewX = otherView->transformDocToViewX (docX); + const double otherViewY = otherView->transformDocToViewY (docY); + + return QPoint ((int) otherViewX, (int) otherViewY); +} + + +// public +int kpView::zoomedDocWidth () const +{ + return document () ? document ()->width () * zoomLevelX () / 100 : 0; +} + +// public +int kpView::zoomedDocHeight () const +{ + return document () ? document ()->height () * zoomLevelY () / 100 : 0; +} + + +// public +void kpView::setHasMouse (bool yes) +{ + kpViewManager *vm = viewManager (); + if (!vm) + return; + +#if DEBUG_KP_VIEW && 0 + kdDebug () << "kpView(" << name () + << ")::setHasMouse(" << yes + << ") existing viewUnderCursor=" + << (vm->viewUnderCursor () ? vm->viewUnderCursor ()->name () : "(none)") + << endl; +#endif + if (yes && vm->viewUnderCursor () != this) + vm->setViewUnderCursor (this); + else if (!yes && vm->viewUnderCursor () == this) + vm->setViewUnderCursor (0); +} + + +// public +void kpView::addToQueuedArea (const QRegion ®ion) +{ +#if DEBUG_KP_VIEW && 0 + kdDebug () << "kpView(" << name () + << ")::addToQueuedArea() already=" << d->m_queuedUpdateArea + << " - plus - " << region + << endl; +#endif + d->m_queuedUpdateArea += region; +} + +// public +void kpView::addToQueuedArea (const QRect &rect) +{ +#if DEBUG_KP_VIEW && 0 + kdDebug () << "kpView(" << name () + << ")::addToQueuedArea() already=" << d->m_queuedUpdateArea + << " - plus - " << rect + << endl; +#endif + d->m_queuedUpdateArea += rect; +} + +// public +void kpView::invalidateQueuedArea () +{ +#if DEBUG_KP_VIEW && 0 + kdDebug () << "kpView::invalidateQueuedArea()" << endl; +#endif + + d->m_queuedUpdateArea = QRegion (); +} + +// public +void kpView::updateQueuedArea () +{ + kpViewManager *vm = viewManager (); +#if DEBUG_KP_VIEW && 0 + kdDebug () << "kpView(" << name () + << ")::updateQueuedArea() vm=" << (bool) vm + << " queueUpdates=" << (vm && vm->queueUpdates ()) + << " fastUpdates=" << (vm && vm->fastUpdates ()) + << " area=" << d->m_queuedUpdateArea + << endl; +#endif + + if (!vm) + return; + + if (vm->queueUpdates ()) + return; + + if (!d->m_queuedUpdateArea.isNull ()) + vm->updateView (this, d->m_queuedUpdateArea); + + invalidateQueuedArea (); +} + +// public +void kpView::updateMicroFocusHint (const QRect µFocusHint) +{ + int x = microFocusHint.topLeft().x(); + int y = microFocusHint.topLeft().y(); + int width = microFocusHint.width(); + int height = microFocusHint.height(); + setMicroFocusHint (x, y, width, height); +} + +// public +QRect kpView::selectionViewRect () const +{ + return selection () ? + transformDocToView (selection ()->boundingRect ()) : + QRect (); + +} + +// public +QPoint kpView::mouseViewPoint (const QPoint &returnViewPoint) const +{ + if (returnViewPoint != KP_INVALID_POINT) + return returnViewPoint; + else + return mapFromGlobal (QCursor::pos ()); +} + +// public +QPoint kpView::mouseViewPointRelativeToSelection (const QPoint &viewPoint) const +{ + if (!selection ()) + return KP_INVALID_POINT; + + return mouseViewPoint (viewPoint) - transformDocToView (selection ()->topLeft ()); +} + +// public +bool kpView::mouseOnSelection (const QPoint &viewPoint) const +{ + const QRect selViewRect = selectionViewRect (); + if (!selViewRect.isValid ()) + return false; + + return selViewRect.contains (mouseViewPoint (viewPoint)); +} + + +// public +int kpView::textSelectionMoveBorderAtomicSize () const +{ + if (!selection () || !selection ()->isText ()) + return 0; + + return QMAX (4, zoomLevelX () / 100); +} + +// public +bool kpView::mouseOnSelectionToMove (const QPoint &viewPoint) const +{ + if (!mouseOnSelection (viewPoint)) + return false; + + if (!selection ()->isText ()) + return true; + + if (mouseOnSelectionResizeHandle (viewPoint)) + return false; + + + const QPoint viewPointRelSel = mouseViewPointRelativeToSelection (viewPoint); + + // Middle point should always be selectable + const QPoint selCenterDocPoint = selection ()->boundingRect ().center (); + if (tool () && + tool ()->currentPoint () == selCenterDocPoint) + { + return false; + } + + + const int atomicSize = textSelectionMoveBorderAtomicSize (); + const QRect selViewRect = selectionViewRect (); + + return (viewPointRelSel.x () < atomicSize || + viewPointRelSel.x () >= selViewRect.width () - atomicSize || + viewPointRelSel.y () < atomicSize || + viewPointRelSel.y () >= selViewRect.height () - atomicSize); +} + + +// protected +bool kpView::selectionLargeEnoughToHaveResizeHandlesIfAtomicSize (int atomicSize) const +{ + if (!selection ()) + return false; + + const QRect selViewRect = selectionViewRect (); + + return (selViewRect.width () >= atomicSize * 5 || + selViewRect.height () >= atomicSize * 5); +} + +// public +int kpView::selectionResizeHandleAtomicSize () const +{ + int atomicSize = QMIN (7, QMAX (4, zoomLevelX () / 100)); + while (atomicSize > 0 && + !selectionLargeEnoughToHaveResizeHandlesIfAtomicSize (atomicSize)) + { + atomicSize--; + } + + return atomicSize; +} + +// public +bool kpView::selectionLargeEnoughToHaveResizeHandles () const +{ + return (selectionResizeHandleAtomicSize () > 0); +} + +// public +QRegion kpView::selectionResizeHandlesViewRegion (bool forRenderer) const +{ + QRegion ret; + + const int atomicLength = selectionResizeHandleAtomicSize (); + if (atomicLength <= 0) + return QRegion (); + + + // HACK: At low zoom (e.g. 100%), resize handles will probably be too + // big and overlap text / cursor / too much of selection. + // + // So limit the _visual_ size of handles at low zoom. The + // handles' grab area remains the same for usability; so yes, + // there are a few pixels that don't look grabable but they are. + // + // The real solution is to be able to partially render the + // handles outside of the selection view rect. If not possible, + // at least for text boxes, render text on top of handles. + int normalAtomicLength = atomicLength; + int vertEdgeAtomicLength = atomicLength; + if (forRenderer && selection ()) + { + if (zoomLevelX () <= 150) + { + if (normalAtomicLength > 1) + normalAtomicLength--; + + if (vertEdgeAtomicLength > 1) + vertEdgeAtomicLength--; + } + + // 1 line of text? + if (selection ()->isText () && selection ()->textLines ().size () == 1) + { + if (zoomLevelX () <= 150) + vertEdgeAtomicLength = QMIN (vertEdgeAtomicLength, QMAX (2, zoomLevelX () / 100)); + else if (zoomLevelX () <= 250) + vertEdgeAtomicLength = QMIN (vertEdgeAtomicLength, QMAX (3, zoomLevelX () / 100)); + } + } + + + const QRect selViewRect = selectionViewRect (); + +#define ADD_BOX_RELATIVE_TO_SELECTION(type,x,y) \ + ret += QRect ((x), (y), type##AtomicLength, type##AtomicLength) + + ADD_BOX_RELATIVE_TO_SELECTION (normal, + selViewRect.width () - normalAtomicLength, + selViewRect.height () - normalAtomicLength); + ADD_BOX_RELATIVE_TO_SELECTION (normal, + selViewRect.width () - normalAtomicLength, + 0); + ADD_BOX_RELATIVE_TO_SELECTION (normal, + 0, + selViewRect.height () - normalAtomicLength); + ADD_BOX_RELATIVE_TO_SELECTION (normal, + 0, + 0); + + ADD_BOX_RELATIVE_TO_SELECTION (vertEdge, + selViewRect.width () - vertEdgeAtomicLength, + (selViewRect.height () - vertEdgeAtomicLength) / 2); + ADD_BOX_RELATIVE_TO_SELECTION (normal, + (selViewRect.width () - normalAtomicLength) / 2, + selViewRect.height () - normalAtomicLength); + ADD_BOX_RELATIVE_TO_SELECTION (normal, + (selViewRect.width () - normalAtomicLength) / 2, + 0); + ADD_BOX_RELATIVE_TO_SELECTION (vertEdge, + 0, + (selViewRect.height () - vertEdgeAtomicLength) / 2); + +#undef ADD_BOX_RELATIVE_TO_SELECTION + + ret.translate (selViewRect.x (), selViewRect.y ()); + ret = ret.intersect (selViewRect); + + return ret; +} + +// public +int kpView::mouseOnSelectionResizeHandle (const QPoint &viewPoint) const +{ +#if DEBUG_KP_VIEW + kdDebug () << "kpView::mouseOnSelectionResizeHandle(viewPoint=" + << viewPoint << ")" << endl; +#endif + + if (!mouseOnSelection (viewPoint)) + { + #if DEBUG_KP_VIEW + kdDebug () << "\tmouse not on sel" << endl; + #endif + return 0; + } + + + const QRect selViewRect = selectionViewRect (); +#if DEBUG_KP_VIEW + kdDebug () << "\tselViewRect=" << selViewRect << endl; +#endif + + + const int atomicLength = selectionResizeHandleAtomicSize (); +#if DEBUG_KP_VIEW + kdDebug () << "\tatomicLength=" << atomicLength << endl; +#endif + + if (atomicLength <= 0) + { + #if DEBUG_KP_VIEW + kdDebug () << "\tsel not large enough to have resize handles" << endl; + #endif + // Want to make it possible to move a small selection + return 0; + } + + + const QPoint viewPointRelSel = mouseViewPointRelativeToSelection (viewPoint); +#if DEBUG_KP_VIEW + kdDebug () << "\tviewPointRelSel=" << viewPointRelSel << endl; +#endif + + +#define LOCAL_POINT_IN_BOX_AT(x,y) \ + QRect ((x), (y), atomicLength, atomicLength).contains (viewPointRelSel) + + // Favour the bottom & right and the corners. + if (LOCAL_POINT_IN_BOX_AT (selViewRect.width () - atomicLength, + selViewRect.height () - atomicLength)) + { + return Bottom | Right; + } + else if (LOCAL_POINT_IN_BOX_AT (selViewRect.width () - atomicLength, 0)) + { + return Top | Right; + } + else if (LOCAL_POINT_IN_BOX_AT (0, selViewRect.height () - atomicLength)) + { + return Bottom | Left; + } + else if (LOCAL_POINT_IN_BOX_AT (0, 0)) + { + return Top | Left; + } + else if (LOCAL_POINT_IN_BOX_AT (selViewRect.width () - atomicLength, + (selViewRect.height () - atomicLength) / 2)) + { + return Right; + } + else if (LOCAL_POINT_IN_BOX_AT ((selViewRect.width () - atomicLength) / 2, + selViewRect.height () - atomicLength)) + { + return Bottom; + } + else if (LOCAL_POINT_IN_BOX_AT ((selViewRect.width () - atomicLength) / 2, 0)) + { + return Top; + } + else if (LOCAL_POINT_IN_BOX_AT (0, (selViewRect.height () - atomicLength) / 2)) + { + return Left; + } + else + { + #if DEBUG_KP_VIEW + kdDebug () << "\tnot on sel resize handle" << endl; + #endif + return 0; + } +#undef LOCAL_POINT_IN_BOX_AT +} + +// public +bool kpView::mouseOnSelectionToSelectText (const QPoint &viewPoint) const +{ +#if DEBUG_KP_VIEW + kdDebug () << "kpView::mouseOnSelectionToSelectText(viewPoint=" + << viewPoint << ")" << endl; +#endif + + if (!mouseOnSelection (viewPoint)) + { + #if DEBUG_KP_VIEW + kdDebug () << "\tmouse non on sel" << endl; + #endif + return false; + } + + if (!selection ()->isText ()) + { + #if DEBUG_KP_VIEW + kdDebug () << "\tsel not text" << endl; + #endif + return false; + } + +#if DEBUG_KP_VIEW + kdDebug () << "\tmouse on sel: to move=" << mouseOnSelectionToMove () + << " to resize=" << mouseOnSelectionResizeHandle () + << endl; +#endif + + return (!mouseOnSelectionToMove (viewPoint) && + !mouseOnSelectionResizeHandle (viewPoint)); +} + + +// protected virtual [base QWidget] +void kpView::mouseMoveEvent (QMouseEvent *e) +{ +#if DEBUG_KP_VIEW && 0 + kdDebug () << "kpView(" << name () << ")::mouseMoveEvent (" + << e->x () << "," << e->y () << ")" + << endl; +#endif + + // TODO: This is wrong if you leaveEvent the mainView by mouseMoving on the + // mainView, landing on top of the thumbnailView cleverly put on top + // of the mainView. + setHasMouse (rect ().contains (e->pos ())); + + if (tool ()) + tool ()->mouseMoveEvent (e); + + e->accept (); +} + +// protected virtual [base QWidget] +void kpView::mousePressEvent (QMouseEvent *e) +{ +#if DEBUG_KP_VIEW && 0 + kdDebug () << "kpView(" << name () << ")::mousePressEvent (" + << e->x () << "," << e->y () << ")" + << endl; +#endif + + setHasMouse (true); + + if (tool ()) + tool ()->mousePressEvent (e); + + e->accept (); +} + +// protected virtual [base QWidget] +void kpView::mouseReleaseEvent (QMouseEvent *e) +{ +#if DEBUG_KP_VIEW && 0 + kdDebug () << "kpView(" << name () << ")::mouseReleaseEvent (" + << e->x () << "," << e->y () << ")" + << endl; +#endif + + setHasMouse (rect ().contains (e->pos ())); + + if (tool ()) + tool ()->mouseReleaseEvent (e); + + e->accept (); +} + +// public virtual [base QWidget] +void kpView::wheelEvent (QWheelEvent *e) +{ + if (tool ()) + tool ()->wheelEvent (e); +} + + +// protected virtual [base QWidget] +void kpView::keyPressEvent (QKeyEvent *e) +{ +#if DEBUG_KP_VIEW && 0 + kdDebug () << "kpView(" << name () << ")::keyPressEvent()" << endl; +#endif + + if (tool ()) + tool ()->keyPressEvent (e); + + e->accept (); +} + +// protected virtual [base QWidget] +void kpView::keyReleaseEvent (QKeyEvent *e) +{ +#if DEBUG_KP_VIEW && 0 + kdDebug () << "kpView(" << name () << ")::keyReleaseEvent()" << endl; +#endif + + if (tool ()) + tool ()->keyReleaseEvent (e); + + e->accept (); +} + + +// protected virtual [base QWidget] +void kpView::focusInEvent (QFocusEvent *e) +{ +#if DEBUG_KP_VIEW && 0 + kdDebug () << "kpView(" << name () << ")::focusInEvent()" << endl; +#endif + if (tool ()) + tool ()->focusInEvent (e); +} + +// protected virtual [base QWidget] +void kpView::focusOutEvent (QFocusEvent *e) +{ +#if DEBUG_KP_VIEW && 0 + kdDebug () << "kpView(" << name () << ")::focusOutEvent()" << endl; +#endif + if (tool ()) + tool ()->focusOutEvent (e); +} + + +// protected virtual [base QWidget] +void kpView::enterEvent (QEvent *e) +{ +#if DEBUG_KP_VIEW && 0 + kdDebug () << "kpView(" << name () << ")::enterEvent()" << endl; +#endif + + // Don't call setHasMouse(true) as it displays the brush cursor (if + // active) when dragging open a menu and then dragging + // past the extents of the menu due to Qt sending us an EnterEvent. + // We're already covered by MouseMoveEvent anyway. + // + // But disabling this causes a more serious problem: RMB on a text + // box and Esc. We have no other reliable way to determine if the + // mouse is still above the view (user could have moved mouse out + // while RMB menu was up) and hence the cursor is not updated. + setHasMouse (true); + + if (tool ()) + tool ()->enterEvent (e); +} + +// protected virtual [base QWidget] +void kpView::leaveEvent (QEvent *e) +{ +#if DEBUG_KP_VIEW && 0 + kdDebug () << "kpView(" << name () << ")::leaveEvent()" << endl; +#endif + + setHasMouse (false); + if (tool ()) + tool ()->leaveEvent (e); +} + + +// protected virtual [base QWidget] +void kpView::dragEnterEvent (QDragEnterEvent *) +{ +#if DEBUG_KP_VIEW && 1 + kdDebug () << "kpView(" << name () << ")::dragEnterEvent()" << endl; +#endif + + setHasMouse (true); +} + +// protected virtual [base QWidget] +void kpView::dragLeaveEvent (QDragLeaveEvent *) +{ +#if DEBUG_KP_VIEW && 1 + kdDebug () << "kpView(" << name () << ")::dragLeaveEvent" << endl; +#endif + + setHasMouse (false); +} + + +// public virtual [base QWidget] +void kpView::resize (int w, int h) +{ +#if DEBUG_KP_VIEW && 1 + kdDebug () << "kpView(" << name () + << ")::resize(" << w << "," << h << ")" + << endl; +#endif + + QWidget::resize (w, h); +} + +// protected virtual [base QWidget] +void kpView::resizeEvent (QResizeEvent *e) +{ +#if DEBUG_KP_VIEW && 1 + kdDebug () << "kpView(" << name () << ")::resizeEvent(" + << e->size () + << " vs actual=" << size () + << ") old=" << e->oldSize () << endl; +#endif + + QWidget::resizeEvent (e); + + emit sizeChanged (width (), height ()); + emit sizeChanged (size ()); +} + + +// private virtual +void kpView::imStartEvent (QIMEvent *e) +{ +#if DEBUG_KP_VIEW && 1 + kdDebug () << "kpView(" << name () << ")::imStartEvent" << endl; +#endif + + if (tool ()) + tool ()->imStartEvent (e); + e->accept(); +} + +// private virtual +void kpView::imComposeEvent (QIMEvent *e) +{ +#if DEBUG_KP_VIEW && 1 + kdDebug () << "kpView(" << name () << ")::imComposeEvent" << endl; +#endif + + if (tool ()) + tool ()->imComposeEvent (e); + e->accept(); +} + +// private virtual +void kpView::imEndEvent (QIMEvent *e) +{ +#if DEBUG_KP_VIEW && 1 + kdDebug () << "kpView(" << name () << ")::imEndEvent" << endl; +#endif + + if (tool ()) + tool ()->imEndEvent (e); + e->accept(); +} + + +// +// Renderer +// + +// protected +QRect kpView::paintEventGetDocRect (const QRect &viewRect) const +{ +#if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "kpView::paintEventGetDocRect(" << viewRect << ")" << endl; +#endif + + QRect docRect; + + // From the "we aren't sure whether to round up or round down" department: + + if (zoomLevelX () < 100 || zoomLevelY () < 100) + docRect = transformViewToDoc (viewRect); + else + { + // think of a grid - you need to fully cover the zoomed-in pixels + // when docRect is zoomed back to the view later + docRect = QRect (transformViewToDoc (viewRect.topLeft ()), // round down + transformViewToDoc (viewRect.bottomRight ())); // round down + } + + if (zoomLevelX () % 100 || zoomLevelY () % 100) + { + // at least round up the bottom-right point and deal with matrix weirdness: + // - helpful because it ensures we at least cover the required area + // at e.g. 67% or 573% + // - harmless since paintEventDrawRect() clips for us anyway + docRect.setBottomRight (docRect.bottomRight () + QPoint (2, 2)); + } + +#if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\tdocRect=" << docRect << endl; +#endif + kpDocument *doc = document (); + if (doc) + { + docRect = docRect.intersect (doc->rect ()); + #if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\tintersect with doc=" << docRect << endl; + #endif + } + + return docRect; +} + +// public +void kpView::drawTransparentBackground (QPainter *painter, + int /*viewWidth*/, int /*viewHeight*/, + const QRect &rect, + bool isPreview) +{ + const int cellSize = !isPreview ? 16 : 10; + + int starty = rect.y (); + if (starty % cellSize) + starty -= (starty % cellSize); + + int startx = rect.x (); + if (startx % cellSize) + startx -= (startx % cellSize); + + painter->save (); + for (int y = starty; y <= rect.bottom (); y += cellSize) + { + for (int x = startx; x <= rect.right (); x += cellSize) + { + bool parity = (x / cellSize + y / cellSize) % 2; + QColor col; + + if (parity) + { + if (!isPreview) + col = QColor (213, 213, 213); + else + col = QColor (224, 224, 224); + } + else + col = Qt::white; + + painter->fillRect (x - rect.x (), y - rect.y (), cellSize, cellSize, + col); + } + } + painter->restore (); +} + +// protected +void kpView::paintEventDrawCheckerBoard (QPainter *painter, const QRect &viewRect) +{ + kpDocument *doc = document (); + if (!doc) + return; + + drawTransparentBackground (painter, + doc->width () * zoomLevelX () / 100, + doc->height () * zoomLevelY () / 100, + viewRect); +} + +// protected +void kpView::paintEventDrawSelection (QPixmap *destPixmap, const QRect &docRect) +{ +#if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "kpView::paintEventDrawSelection() docRect=" << docRect << endl; +#endif + + kpDocument *doc = document (); + if (!doc) + { + #if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\tno doc - abort" << endl; + #endif + return; + } + + kpSelection *sel = doc->selection (); + if (!sel) + { + #if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\tno sel - abort" << endl; + #endif + return; + } + + + // + // Draw selection pixmap (if there is one) + // +#if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\tdraw sel pixmap @ " << sel->topLeft () << endl; +#endif + sel->paint (destPixmap, docRect); + + + // + // Draw selection border + // + + kpViewManager *vm = viewManager (); +#if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\tsel border visible=" + << vm->selectionBorderVisible () + << endl; +#endif + if (vm->selectionBorderVisible ()) + { + QPainter destPixmapPainter (destPixmap); + destPixmapPainter.setRasterOp (Qt::XorROP); + destPixmapPainter.setPen (QPen (Qt::white, 1, Qt::DotLine)); + + destPixmapPainter.setBackgroundMode (QPainter::OpaqueMode); + destPixmapPainter.setBackgroundColor (Qt::blue); + + QBitmap maskBitmap; + QPainter maskBitmapPainter; + if (destPixmap->mask ()) + { + maskBitmap = *destPixmap->mask (); + maskBitmapPainter.begin (&maskBitmap); + maskBitmapPainter.setPen (Qt::color1/*opaque*/); + } + + + #define PAINTER_CMD(cmd) \ + { \ + destPixmapPainter . cmd; \ + if (maskBitmapPainter.isActive ()) \ + maskBitmapPainter . cmd; \ + } + + QRect boundingRect = sel->boundingRect (); + #if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\tsel boundingRect=" + << boundingRect + << endl; + #endif + + if (boundingRect.topLeft () != boundingRect.bottomRight ()) + { + switch (sel->type ()) + { + case kpSelection::Rectangle: + case kpSelection::Text: + #if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\tselection border = rectangle" << endl; + kdDebug () << "\t\tx=" << boundingRect.x () - docRect.x () + << " y=" << boundingRect.y () - docRect.y () + << " w=" << boundingRect.width () + << " h=" << boundingRect.height () + << endl; + #endif + PAINTER_CMD (drawRect (boundingRect.x () - docRect.x (), + boundingRect.y () - docRect.y (), + boundingRect.width (), + boundingRect.height ())); + break; + + case kpSelection::Ellipse: + #if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\tselection border = ellipse" << endl; + #endif + PAINTER_CMD (drawEllipse (boundingRect.x () - docRect.x (), + boundingRect.y () - docRect.y (), + boundingRect.width (), + boundingRect.height ())); + break; + + case kpSelection::Points: + { + #if DEBUG_KP_VIEW_RENDERER + kdDebug () << "\tselection border = freeForm" << endl; + #endif + QPointArray points = sel->points (); + points.detach (); + points.translate (-docRect.x (), -docRect.y ()); + if (vm->selectionBorderFinished ()) + { + PAINTER_CMD (drawPolygon (points)); + } + else + { + PAINTER_CMD (drawPolyline (points)); + } + + break; + } + + default: + kdError () << "kpView::paintEventDrawSelection() unknown sel border type" << endl; + break; + } + + + if (vm->selectionBorderFinished () && + (sel->type () == kpSelection::Ellipse || + sel->type () == kpSelection::Points)) + { + destPixmapPainter.save (); + + destPixmapPainter.setRasterOp (Qt::NotROP); + PAINTER_CMD (drawRect (boundingRect.x () - docRect.x (), + boundingRect.y () - docRect.y (), + boundingRect.width (), + boundingRect.height ())); + + destPixmapPainter.restore (); + } + } + else + { + // SYNC: Work around Qt bug: can't draw 1x1 rectangle + PAINTER_CMD (drawPoint (boundingRect.topLeft () - docRect.topLeft ())); + } + + #undef PAINTER_CMD + + destPixmapPainter.end (); + if (maskBitmapPainter.isActive ()) + maskBitmapPainter.end (); + + destPixmap->setMask (maskBitmap); + } + + + // + // Draw text cursor + // + + if (sel->isText () && + vm->textCursorEnabled () && + (vm->textCursorBlinkState () || + // For the current main window: + // As long as _any_ view has focus, blink _all_ views not just the + // one with focus // !this->isActiveWindow () + !vm->activeView ())) // sync: call will break when vm is not held by 1 mainWindow + { + // TODO: Fix code duplication: kpViewManager::{setTextCursorPosition,updateTextCursor}() & kpView::paintEventDrawSelection() + QPoint topLeft = sel->pointForTextRowCol (vm->textCursorRow (), vm->textCursorCol ()); + if (topLeft != KP_INVALID_POINT) + { + QRect rect = QRect (topLeft.x (), topLeft.y (), + 1, sel->textStyle ().fontMetrics ().height ()); + rect = rect.intersect (sel->textAreaRect ()); + if (!rect.isEmpty ()) + { + rect.moveBy (-docRect.x (), -docRect.y ()); + + QBitmap maskBitmap; + QPainter destPixmapPainter, maskBitmapPainter; + + if (destPixmap->mask ()) + { + maskBitmap = *destPixmap->mask (); + maskBitmapPainter.begin (&maskBitmap); + maskBitmapPainter.fillRect (rect, Qt::color1/*opaque*/); + maskBitmapPainter.end (); + } + + destPixmapPainter.begin (destPixmap); + destPixmapPainter.setRasterOp (Qt::XorROP); + destPixmapPainter.fillRect (rect, Qt::white); + destPixmapPainter.end (); + + if (!maskBitmap.isNull ()) + destPixmap->setMask (maskBitmap); + } + } + } +} + +// protected +bool kpView::selectionResizeHandleAtomicSizeCloseToZoomLevel () const +{ + return (abs (selectionResizeHandleAtomicSize () - zoomLevelX () / 100) < 3); +} + +// protected +void kpView::paintEventDrawSelectionResizeHandles (QPainter *painter, const QRect &viewRect) +{ +#if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "kpView::paintEventDrawSelectionResizeHandles(" + << viewRect << ")" << endl; +#endif + + if (!selectionLargeEnoughToHaveResizeHandles ()) + { + #if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\tsel not large enough to have resize handles" << endl; + #endif + return; + } + + kpViewManager *vm = viewManager (); + if (!vm || !vm->selectionBorderVisible () || !vm->selectionBorderFinished ()) + { + #if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\tsel border not visible or not finished" << endl; + #endif + + return; + } + + const QRect selViewRect = selectionViewRect (); +#if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\tselViewRect=" << selViewRect << endl; +#endif + if (!selViewRect.intersects (viewRect)) + { + #if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\tdoesn't intersect viewRect" << endl; + #endif + return; + } + + QRegion selResizeHandlesRegion = selectionResizeHandlesViewRegion (true/*for renderer*/); +#if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\tsel resize handles view region=" + << selResizeHandlesRegion << endl; +#endif + selResizeHandlesRegion.translate (-viewRect.x (), -viewRect.y ()); + + painter->save (); + + QColor fillColor; + if (selectionResizeHandleAtomicSizeCloseToZoomLevel ()) + { + fillColor = Qt::blue; + painter->setRasterOp (Qt::CopyROP); + } + else + { + fillColor = Qt::white; + painter->setRasterOp (Qt::XorROP); + } + + QMemArray rects = selResizeHandlesRegion.rects (); + for (QMemArray ::ConstIterator it = rects.begin (); + it != rects.end (); + it++) + { + painter->fillRect (*it, fillColor); + } + + painter->restore (); +} + +// protected +void kpView::paintEventDrawTempPixmap (QPixmap *destPixmap, const QRect &docRect) +{ + kpViewManager *vm = viewManager (); + if (!vm) + return; + + const kpTempPixmap *tpm = vm->tempPixmap (); +#if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "kpView::paintEventDrawTempPixmap() tempPixmap=" + << tpm + << " isVisible=" + << (tpm ? tpm->isVisible (vm) : false) + << endl; +#endif + + if (!tpm || !tpm->isVisible (vm)) + return; + + tpm->paint (destPixmap, docRect); +} + +// protected +void kpView::paintEventDrawGridLines (QPainter *painter, const QRect &viewRect) +{ + int hzoomMultiple = zoomLevelX () / 100; + int vzoomMultiple = zoomLevelY () / 100; + + QPen ordinaryPen (Qt::gray); + QPen tileBoundaryPen (Qt::lightGray); + + painter->setPen (ordinaryPen); + + // horizontal lines + int starty = viewRect.top (); + if (starty % vzoomMultiple) + starty = (starty + vzoomMultiple) / vzoomMultiple * vzoomMultiple; + int tileHeight = 16 * vzoomMultiple; // CONFIG + for (int y = starty - viewRect.y (); y <= viewRect.bottom () - viewRect.y (); y += vzoomMultiple) + { + if (0 && tileHeight > 0 && y % tileHeight == 0) + { + painter->setPen (tileBoundaryPen); + //painter.setRasterOp (Qt::XorROP); + } + + painter->drawLine (0, y, viewRect.right () - viewRect.left (), y); + + if (0 && tileHeight > 0 && y % tileHeight == 0) + { + painter->setPen (ordinaryPen); + //painter.setRasterOp (Qt::CopyROP); + } + } + + // vertical lines + int startx = viewRect.left (); + if (startx % hzoomMultiple) + startx = (startx + hzoomMultiple) / hzoomMultiple * hzoomMultiple; + int tileWidth = 16 * hzoomMultiple; // CONFIG + for (int x = startx - viewRect.x (); x <= viewRect.right () - viewRect.x (); x += hzoomMultiple) + { + if (0 && tileWidth > 0 && x % tileWidth == 0) + { + painter->setPen (tileBoundaryPen); + //painter.setRasterOp (Qt::XorROP); + } + + painter->drawLine (x, 0, x, viewRect.bottom () - viewRect.top ()); + + if (0 && tileWidth > 0 && x % tileWidth == 0) + { + painter->setPen (ordinaryPen); + //painter.setRasterOp (Qt::CopyROP); + } + } +} + + +void kpView::paintEventDrawRect (const QRect &viewRect) +{ +#if DEBUG_KP_VIEW_RENDERER + kdDebug () << "\tkpView::paintEventDrawRect(viewRect=" << viewRect + << ")" << endl; +#endif + + kpViewManager *vm = viewManager (); + const kpDocument *doc = document (); + + if (!vm || !doc) + return; + + + if (viewRect.isEmpty ()) + return; + + + QRect docRect = paintEventGetDocRect (viewRect); + +#if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\tdocRect=" << docRect << endl; +#endif + +// uncomment to cause deliberate flicker (identifies needless updates) +#if DEBUG_KP_VIEW_RENDERER && 0 + QPainter flickerPainter (this); + flickerPainter.fillRect (viewRect, Qt::red); + flickerPainter.end (); +#endif + + + // + // Prepare Back Buffer + // + + if (!d->m_backBuffer || + d->m_backBuffer->width () < viewRect.width () || + d->m_backBuffer->height () < viewRect.height () || + d->m_backBuffer->width () > width () || + d->m_backBuffer->height () > height ()) + { + // don't use QPixmap::resize() as that wastes time copying pixels + // that will be overwritten anyway + // + // OPT: Should use doubling trick or at least go up in multiples + // to reduce X server pressure. + delete d->m_backBuffer; + d->m_backBuffer = new QPixmap (viewRect.width (), viewRect.height ()); + } + +// uncomment to catch bits of the view that the renderer forgot to update +#if 0 + d->m_backBuffer->fill (Qt::green); +#endif + + QPainter backBufferPainter; + backBufferPainter.begin (d->m_backBuffer); + + + // + // Draw checkboard for transparent images and/or views with borders + // + + QPixmap docPixmap; + + bool tempPixmapWillBeRendered = false; + + if (!docRect.isEmpty ()) + { + docPixmap = doc->getPixmapAt (docRect); + + tempPixmapWillBeRendered = + (!doc->selection () && + vm->tempPixmap () && + vm->tempPixmap ()->isVisible (vm) && + docRect.intersects (vm->tempPixmap ()->rect ())); + + #if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\ttempPixmapWillBeRendered=" << tempPixmapWillBeRendered + << " (sel=" << doc->selection () + << " tempPixmap=" << vm->tempPixmap () + << " tempPixmap.isVisible=" << (vm->tempPixmap () ? vm->tempPixmap ()->isVisible (vm) : false) + << " docRect.intersects(tempPixmap.rect)=" << (vm->tempPixmap () ? docRect.intersects (vm->tempPixmap ()->rect ()) : false) + << ")" + << endl; + #endif + } + + if (docPixmap.mask () || + (tempPixmapWillBeRendered && vm->tempPixmap ()->mayChangeDocumentMask ())) + { + #if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\tmask=" << (bool) docPixmap.mask () + << endl; + #endif + paintEventDrawCheckerBoard (&backBufferPainter, viewRect); + } + else + { + #if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\tno mask" << endl; + #endif + } + + + if (!docRect.isEmpty ()) + { + // + // Draw docPixmap + tempPixmap + // + + if (doc->selection ()) + { + paintEventDrawSelection (&docPixmap, docRect); + } + else if (tempPixmapWillBeRendered) + { + paintEventDrawTempPixmap (&docPixmap, docRect); + } + + #if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\torigin=" << origin () << endl; + #endif + // blit scaled version of docPixmap + tempPixmap onto Back Buffer + #if DEBUG_KP_VIEW_RENDERER && 1 + QTime scaleTimer; scaleTimer.start (); + #endif + backBufferPainter.translate (origin ().x () - viewRect.x (), + origin ().y () - viewRect.y ()); + backBufferPainter.scale (double (zoomLevelX ()) / 100.0, + double (zoomLevelY ()) / 100.0); + backBufferPainter.drawPixmap (docRect, docPixmap); + backBufferPainter.resetXForm (); // back to 1-1 scaling + #if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\tscale time=" << scaleTimer.elapsed () << endl; + #endif + + } // if (!docRect.isEmpty ()) { + + + // + // Draw Grid Lines + // + + if (isGridShown ()) + { + #if DEBUG_KP_VIEW_RENDERER && 1 + QTime gridTimer; gridTimer.start (); + #endif + paintEventDrawGridLines (&backBufferPainter, viewRect); + #if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\tgrid time=" << gridTimer.elapsed () << endl; + #endif + } + + + const QRect bvsvRect = buddyViewScrollableContainerRectangle (); + if (!bvsvRect.isEmpty ()) + { + backBufferPainter.save (); + + backBufferPainter.setRasterOp (Qt::XorROP); + backBufferPainter.setPen (Qt::white); + backBufferPainter.translate (-viewRect.x (), -viewRect.y ()); + backBufferPainter.drawRect (bvsvRect); + + backBufferPainter.restore (); + } + + + if (!docRect.isEmpty ()) + { + if (doc->selection ()) + { + // Draw resize handles on top of possible grid lines + paintEventDrawSelectionResizeHandles (&backBufferPainter, viewRect); + } + } + + + // + // Blit Back Buffer to View + // + + backBufferPainter.end (); + + bitBlt (this, viewRect.topLeft (), + d->m_backBuffer, QRect (0, 0, viewRect.width (), viewRect.height ())); +} + + +// protected virtual [base QWidget] +void kpView::paintEvent (QPaintEvent *e) +{ + // sync: kpViewPrivate + // WARNING: document(), viewManager() and friends might be 0 in this method. + // TODO: I'm not 100% convinced that we always check if their friends are 0. + +#if DEBUG_KP_VIEW_RENDERER && 1 + QTime timer; + timer.start (); +#endif + + kpViewManager *vm = viewManager (); + +#if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "kpView(" << name () << ")::paintEvent() vm=" << (bool) vm + << " queueUpdates=" << (vm && vm->queueUpdates ()) + << " fastUpdates=" << (vm && vm->fastUpdates ()) + << " viewRect=" << e->rect () + << " erased=" << e->erased () + << " topLeft=" << QPoint (x (), y ()) + << endl; +#endif + + if (!vm) + return; + + if (vm->queueUpdates ()) + { + // OPT: if this update was due to the document, + // use document coordinates (in case of a zoom change in + // which view coordinates become out of date) + addToQueuedArea (e->region ()); + return; + } + + + QRegion viewRegion = clipRegion ().intersect (e->region ()); + QMemArray rects = viewRegion.rects (); +#if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\t#rects = " << rects.count () << endl; +#endif + + for (QMemArray ::ConstIterator it = rects.begin (); + it != rects.end (); + it++) + { + paintEventDrawRect (*it); + } + + +#if DEBUG_KP_VIEW_RENDERER && 1 + kdDebug () << "\tall done in: " << timer.restart () << "ms" << endl; +#endif +} + + +#include diff --git a/kolourpaint/kpview.h b/kolourpaint/kpview.h new file mode 100644 index 00000000..0bf8c495 --- /dev/null +++ b/kolourpaint/kpview.h @@ -0,0 +1,535 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_VIEW_H +#define KP_VIEW_H + + +#include + +#include + + +class kpDocument; +class kpSelection; +class kpTool; +class kpToolToolBar; +class kpViewManager; +class kpViewScrollableContainer; + + +/** + * @short Abstract base class for all views. + * + * This is the abstract base class for all views. A view is a widget that + * renders a possibly zoomed onscreen representation of a document. + * + * 1 view corresponds to 1 document. + * 1 document corresponds to 0 or more views. + * + * @see kpViewManager + * + * @author Clarence Dang + */ +class kpView : public QWidget +{ +Q_OBJECT + +public: + /** + * Constructs a view. + * + * @param document The document this view is representing. + * @param toolToolBar The tool tool bar. + * @param viewManager The view manager. + * @param buddyView The view this view watches over (e.g. a thumbnail + * view would watch over the main view). May be 0. + * See for example, highlightBuddyViewRectangle(). + * @param scrollableContainer This view's scrollable container. + * May be 0. + * + * You must call adjustEnvironment() at the end of your constructor. + */ + kpView (kpDocument *document, + kpToolToolBar *toolToolBar, + kpViewManager *viewManager, + kpView *buddyView, + kpViewScrollableContainer *scrollableContainer, + QWidget *parent, const char *name); + + /** + * Destructs this view. Informs the viewManager() that the mouse + * cursor is no longer above this view. + */ + virtual ~kpView (); + + + /** + * @returns the document. + */ + kpDocument *document () const; + +protected: + /** + * @returns the document's selection. + */ + kpSelection *selection () const; + +public: + /** + * @returns the tool tool bar. + */ + kpToolToolBar *toolToolBar () const; + +protected: + /** + * @returns the currently selected tool. + */ + kpTool *tool () const; + +public: + /** + * @returns the view manager. + */ + kpViewManager *viewManager () const; + + /** + * @returns the buddy view. + */ + kpView *buddyView () const; + + /** + * @returns the buddyView()'s scrollable container. + */ + kpViewScrollableContainer *buddyViewScrollableContainer () const; + + /** + * @returns this view's scrollable container. + */ + kpViewScrollableContainer *scrollableContainer () const; + + + /** + * @returns the horizontal zoom level (100 is unzoomed). + */ + int zoomLevelX (void) const; + + /** + * @returns the vertical zoom level (100 is unzoomed). + */ + int zoomLevelY (void) const; + + /** + * Sets the horizontal and vertical zoom levels. + * + * @param hzoom Horizontal zoom level. + * @param vzoom Vertical zoom level. + * + * If reimplementing, you must call this base implementation. + */ + virtual void setZoomLevel (int hzoom, int vzoom); + + + /** + * @returns in views coordinates, where the top-left document() pixel + * will be rendered (default: (0,0)). + */ + QPoint origin () const; + + /** + * Sets the origin. + * + * @param origin New origin. + * + * If reimplementing, you must call this base implementation. + */ + virtual void setOrigin (const QPoint &origin); + + + /** + * @returns whether at this zoom level, the grid can be enabled. + * This is based on whether the grid can be sensibly rendered. + */ + bool canShowGrid () const; + + /** + * @returns whether the grid is currently shown. + */ + bool isGridShown () const; + + /** + * Turns on/off the grid. + * + * @param yes Whether to enable the grid. + */ + void showGrid (bool yes = true); + + + /** + * @returns whether to draw a rectangle highlighting the area of + * buddyView() visible through buddyViewScrollableContainer(). + */ + bool isBuddyViewScrollableContainerRectangleShown () const; + + /** + * Turns on/off the rectangle highlighting the area of buddyView() + * visible through buddyViewScrollableContainer() and redraws. + * + * @param yes Whether to turn on the rectangle. + */ + void showBuddyViewScrollableContainerRectangle (bool yes = true); + +protected: + /** + * @returns the current rectangle highlighting the area of buddyView() + * visible through buddyViewScrollableContainer(), that is being + * rendered by this view. + */ + QRect buddyViewScrollableContainerRectangle () const; + +protected slots: + /** + * Updates the buddyViewScrollableContainerRectangle() and redraws + * appropriately. + * + * This is already connected to zoomLevelChanged() and originChanged(); + * buddyView() and buddyViewScrollableContainer() signals. There is probably no + * need to call this function directly. + */ + void updateBuddyViewScrollableContainerRectangle (); + + +public: + + /** + * @param viewX Horizontal position in view coordinates. + * + * @returns viewX transformed to document coordinates, based on the + * origin() and zoomLevelX(). + */ + double transformViewToDocX (double viewX) const; + + /** + * @param viewY Vertical position in view coordinates. + * + * @returns viewY transformed to document coordinates, based on the + * origin() and zoomLevelY(). + */ + double transformViewToDocY (double viewY) const; + + /** + * @param viewPoint Position in view coordinates. + * + * @returns viewPoint transformed to document coordinates, based on the + * origin(), zoomLevelX() and zoomLevelY(). + */ + QPoint transformViewToDoc (const QPoint &viewPoint) const; + + /** + * @param viewRect Rectangle in view coordinates. + * + * @returns viewRect transformed to document coordinates based on the + * origin(), zoomLevelX() and zoomLevelY(). + * + * For bounding rectangles, you should use this function instead of + * transformViewToDocX(), transformViewToDocY() or + * transformViewToDoc(const QPoint &) which act on coordinates only. + */ + QRect transformViewToDoc (const QRect &viewRect) const; + + + /** + * @param docX Horizontal position in document coordinates. + * + * @returns docX transformed to view coordinates, based on the origin() + * and zoomLevelX(). + */ + double transformDocToViewX (double docX) const; + + /** + * @param docY Vertical position in document coordinates. + * + * @returns docY transformed to view coordinates, based on the origin() + * and zoomLevelY(). + */ + double transformDocToViewY (double docY) const; + + /** + * @param docPoint Position in document coordinates. + * + * @returns docPoint transformed to view coordinates, based on the + * origin(), zoomLevelX(), zoomLevelY(). + */ + QPoint transformDocToView (const QPoint &docPoint) const; + + /** + * @param docRect Rectangle in document coordinates. + * + * @return docRect transformed to view coordinates, based on the + * origin(), zoomLevelX() and zoomLevelY(). + * + * For bounding rectangles, you should use this function instead of + * transformDocToViewX(), transformDocToViewY() or + * transformDocToView(const QPoint &) which act on coordinates only. + */ + QRect transformDocToView (const QRect &docRect) const; + + + /** + * @param viewPoint Position in view coordinates. + * @param otherView View whose coordinate system the return value will + * be in. + * + * @returns viewPoint transformed to the coordinate system of + * @param otherView based on this and otherView's origin(), + * zoomLevelX() and zoomLevelY(). This has less rounding + * error than otherView->transformDocToView (transformViewToDoc (viewPoint)). + */ + QPoint transformViewToOtherView (const QPoint &viewPoint, + const kpView *otherView); + + + /** + * @returns the approximate view width required to display the entire + * document(), based on the zoom level only. + */ + int zoomedDocWidth () const; + + /** + * @returns the approximate view height required to display the entire + * document(), based on the zoom level only. + */ + int zoomedDocHeight () const; + + +protected: + /** + * Updates the viewManager() on whether or not the mouse is directly + * above this view. Among other things, this ensures the brush cursor + * is updated. + * + * This should be called in event handlers. + * + * @param yes Whether the mouse is directly above this view. + */ + void setHasMouse (bool yes = true); + + +public: + /** + * Adds a region (in view coordinates) to the dirty area that is + * repainted when the parent @ref kpViewManager is set not to queue + * updates. + * + * @param region Region (in view coordinates) that needs repainting. + */ + void addToQueuedArea (const QRegion ®ion); + + /** + * Convenience function. Same as above. + * + * Adds a rectangle (in view coordinates) to the dirty area that is + * repainted when the parent @ref kpViewManager is set not to queue + * updates. + * + * @param rect Rectangle (in view coordinates) that needs repainting. + */ + void addToQueuedArea (const QRect &rect); + + /** + * Removes the dirty region that has been queued for updating. + * Does not update the view. + */ + void invalidateQueuedArea (); + + /** + * Updates the part of the view described by dirty region and then + * calls invalidateQueuedArea(). Does nothing if @ref kpViewManager + * is set to queue updates. + */ + void updateQueuedArea (); + + void updateMicroFocusHint (const QRect µFocusHint); + + +public slots: + /** + * Call this when the "environment" (e.g. document size) changes. The + * environment is defined by the caller and should be based on the type + * of view. For instance, an unzoomed thumbnail view would also + * include in its environment the contents position of an associated + * scrollable container. + * + * This is never called by the kpView base class. + * + * Implementors should change whatever state is neccessary for their + * type of view. For instance, an unzoomed view would resize itself; + * a zoomed thumbnail would change the zoom level. + */ + virtual void adjustToEnvironment () = 0; + + +public: + QRect selectionViewRect () const; + + // (if is KP_INVALID_POINT, it uses QCursor::pos()) + + QPoint mouseViewPoint (const QPoint &returnViewPoint = KP_INVALID_POINT) const; + QPoint mouseViewPointRelativeToSelection (const QPoint &viewPoint = KP_INVALID_POINT) const; + bool mouseOnSelection (const QPoint &viewPoint = KP_INVALID_POINT) const; + + int textSelectionMoveBorderAtomicSize () const; + bool mouseOnSelectionToMove (const QPoint &viewPoint = KP_INVALID_POINT) const; + +protected: + bool selectionLargeEnoughToHaveResizeHandlesIfAtomicSize (int atomicSize) const; +public: + int selectionResizeHandleAtomicSize () const; + bool selectionLargeEnoughToHaveResizeHandles () const; + + QRegion selectionResizeHandlesViewRegion (bool forRenderer = false) const; + + enum SelectionResizeType + { + None = 0, + Left = 1, + Right = 2, + Top = 4, + Bottom = 8 + }; + + // Returns a bitwise OR of the SelectionResizeType's + int mouseOnSelectionResizeHandle (const QPoint &viewPoint = KP_INVALID_POINT) const; + + bool mouseOnSelectionToSelectText (const QPoint &viewPoint = KP_INVALID_POINT) const; + + +signals: + /** + * Emitted after all zooming code has been executed. + * + * @param zoomLevelX New zoomLevelX() + * @param zoomLevelY New zoomLevelY() + */ + void zoomLevelChanged (int zoomLevelX, int zoomLevelY); + + /** + * Emitted after all resizing code has been executed. + * + * @param size New view size. + */ + void sizeChanged (const QSize &size); + + /** + * Convenience signal - same as above. + * + * Emitted after all resizing code has been executed. + * + * @param width New view width. + * @param height New view height. + */ + void sizeChanged (int width, int height); + + /** + * Emitted after all origin changing code has been executed. + * + * @param origin The new origin. + */ + void originChanged (const QPoint &origin); + +protected: + virtual void mouseMoveEvent (QMouseEvent *e); + virtual void mousePressEvent (QMouseEvent *e); + virtual void mouseReleaseEvent (QMouseEvent *e); +public: + // (needs to be public as it may also get event from + // QScrollView::contentsWheelEvent()) + virtual void wheelEvent (QWheelEvent *e); + +protected: + virtual void keyPressEvent (QKeyEvent *e); + virtual void keyReleaseEvent (QKeyEvent *e); + + virtual void focusInEvent (QFocusEvent *e); + virtual void focusOutEvent (QFocusEvent *e); + + virtual void enterEvent (QEvent *e); + virtual void leaveEvent (QEvent *e); + + virtual void dragEnterEvent (QDragEnterEvent *); + virtual void dragLeaveEvent (QDragLeaveEvent *); + + virtual void imStartEvent (QIMEvent *e); + virtual void imComposeEvent (QIMEvent *e); + virtual void imEndEvent (QIMEvent *e); + +public: + virtual void resize (int w, int h); +protected: + virtual void resizeEvent (QResizeEvent *e); + + +protected: + QRect paintEventGetDocRect (const QRect &viewRect) const; +public: + /** + * Draws an opaque background representing transparency. Currently, + * it draws a checkerboard. + * + * @param painter Painter. + * @param viewWidth Total width of the view visible to the user. + * @param viewHeight Total height of the view visible to the user. + * @param rect Rectangle to paint in relative to the painter. Note + * that this function does not clip and may draw slightly + * more than the requested rectangle. TODO: why not? + * @param isPreview Whether the view is for a preview as opposed to + * e.g. editing. If set, this function may render + * slightly differently. + */ + static void drawTransparentBackground (QPainter *painter, + int viewWidth, int viewHeight, + const QRect &rect, + bool isPreview = false); +protected: + void paintEventDrawCheckerBoard (QPainter *painter, const QRect &viewRect); + void paintEventDrawSelection (QPixmap *destPixmap, const QRect &docRect); + bool selectionResizeHandleAtomicSizeCloseToZoomLevel () const; + void paintEventDrawSelectionResizeHandles (QPainter *painter, const QRect &viewRect); + void paintEventDrawTempPixmap (QPixmap *destPixmap, const QRect &docRect); + void paintEventDrawGridLines (QPainter *painter, const QRect &viewRect); + + void paintEventDrawRect (const QRect &viewRect); + virtual void paintEvent (QPaintEvent *e); + + +private: + struct kpViewPrivate *d; +}; + + +#endif // KP_VIEW_H diff --git a/kolourpaint/kpviewmanager.cpp b/kolourpaint/kpviewmanager.cpp new file mode 100644 index 00000000..d649f359 --- /dev/null +++ b/kolourpaint/kpviewmanager.cpp @@ -0,0 +1,766 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_VIEW_MANAGER 0 + + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + + +kpViewManager::kpViewManager (kpMainWindow *mainWindow) + : m_textCursorBlinkTimer (0), + m_textCursorRow (-1), + m_textCursorCol (-1), + m_textCursorBlinkState (true), + m_mainWindow (mainWindow), + m_tempPixmap (0), + m_viewUnderCursor (0), + m_selectionBorderVisible (false), + m_selectionBorderFinished (false) +{ + m_queueUpdatesCounter = m_fastUpdatesCounter = 0; +} + +// private +kpDocument *kpViewManager::document () const +{ + return m_mainWindow ? m_mainWindow->document () : 0; +} + +kpViewManager::~kpViewManager () +{ + unregisterAllViews (); + + delete m_tempPixmap; m_tempPixmap = 0; +} + + +void kpViewManager::registerView (kpView *view) +{ +#if DEBUG_KP_VIEW_MANAGER && 1 + kdDebug () << "kpViewManager::registerView (" << view << ")" << endl; +#endif + if (view && m_views.findRef (view) < 0) + { + #if DEBUG_KP_VIEW_MANAGER && 1 + kdDebug () << "\tadded view" << endl; + #endif + view->setCursor (m_cursor); + m_views.append (view); + } + else + { + #if DEBUG_KP_VIEW_MANAGER && 1 + kdDebug () << "\tignored register view attempt" << endl; + #endif + } +} + +void kpViewManager::unregisterView (kpView *view) +{ + if (view) + { + if (view == m_viewUnderCursor) + m_viewUnderCursor = 0; + + view->unsetCursor (); + m_views.removeRef (view); + } +} + +void kpViewManager::unregisterAllViews () +{ + // no autoDelete + m_views.clear (); +} + + +// public +const kpTempPixmap *kpViewManager::tempPixmap () const +{ + return m_tempPixmap; +} + +// public +void kpViewManager::setTempPixmap (const kpTempPixmap &tempPixmap) +{ +#if DEBUG_KP_VIEW_MANAGER + kdDebug () << "kpViewManager::setTempPixmap(isBrush=" + << tempPixmap.isBrush () + << ",topLeft=" << tempPixmap.topLeft () + << ",pixmap.rect=" << tempPixmap.pixmap ().rect () + << ")" << endl; +#endif + + QRect oldRect; + + if (m_tempPixmap) + { + oldRect = m_tempPixmap->rect (); + delete m_tempPixmap; + m_tempPixmap = 0; + } + + m_tempPixmap = new kpTempPixmap (tempPixmap); + + + setQueueUpdates (); + + if (oldRect.isValid ()) + updateViews (oldRect); + updateViews (m_tempPixmap->rect ()); + + restoreQueueUpdates (); +} + +// public +void kpViewManager::invalidateTempPixmap () +{ + if (!m_tempPixmap) + return; + + QRect oldRect = m_tempPixmap->rect (); + + delete m_tempPixmap; + m_tempPixmap = 0; + + updateViews (oldRect); +} + + +// public +bool kpViewManager::selectionBorderVisible () const +{ + return m_selectionBorderVisible; +} + +// public +void kpViewManager::setSelectionBorderVisible (bool yes) +{ + if (m_selectionBorderVisible == yes) + return; + + m_selectionBorderVisible = yes; + + if (document () && document ()->selection ()) + updateViews (document ()->selection ()->boundingRect ()); +} + + +// public +bool kpViewManager::selectionBorderFinished () const +{ + return m_selectionBorderFinished; +} + +// public +void kpViewManager::setSelectionBorderFinished (bool yes) +{ + if (m_selectionBorderFinished == yes) + return; + + m_selectionBorderFinished = yes; + + if (document () && document ()->selection ()) + updateViews (document ()->selection ()->boundingRect ()); +} + + +bool kpViewManager::textCursorEnabled () const +{ + return (bool) m_textCursorBlinkTimer; +} + +void kpViewManager::setTextCursorEnabled (bool yes) +{ +#if DEBUG_KP_VIEW_MANAGER && 1 + kdDebug () << "kpViewManager::setTextCursorEnabled(" << yes << ")" << endl; +#endif + + if (yes == textCursorEnabled ()) + return; + + delete m_textCursorBlinkTimer; + m_textCursorBlinkTimer = 0; + + setFastUpdates (); + setQueueUpdates (); + + m_textCursorBlinkState = true; + + if (yes) + { + m_textCursorBlinkTimer = new QTimer (this); + connect (m_textCursorBlinkTimer, SIGNAL (timeout ()), + this, SLOT (slotTextCursorBlink ())); + slotTextCursorBlink (); + } + // TODO: What if !yes - shouldn't it clear the cursor? + + restoreQueueUpdates (); + restoreFastUpdates (); +} + + +int kpViewManager::textCursorRow () const +{ + bool handledErrors = false; + if (m_mainWindow) + { + kpDocument *doc = m_mainWindow->document (); + if (doc) + { + kpSelection *sel = doc->selection (); + if (sel && sel->isText ()) + { + if (m_textCursorRow >= (int) sel->textLines ().size ()) + { + #if DEBUG_KP_VIEW_MANAGER && 1 + kdDebug () << "kpViewManager::textCursorRow() row=" + << m_textCursorRow + << endl; + #endif + (const_cast (this))->m_textCursorRow = + sel->textLines ().size () - 1; + } + + handledErrors = true; + } + } + } + + if (!handledErrors) + { + #if DEBUG_KP_VIEW_MANAGER && 1 + kdDebug () << "kpViewManager::textCursorRow() no mw, doc or text sel" << endl; + #endif + (const_cast (this))->m_textCursorRow = -1; + } + + return m_textCursorRow; +} + +int kpViewManager::textCursorCol () const +{ + int row = textCursorRow (); + if (row < 0) + return -1; + + bool handledErrors = false; + if (m_mainWindow) + { + kpDocument *doc = m_mainWindow->document (); + if (doc) + { + kpSelection *sel = doc->selection (); + if (sel && sel->isText ()) + { + if (m_textCursorCol > (int) sel->textLines () [row].length ()) + { + #if DEBUG_KP_VIEW_MANAGER && 1 + kdDebug () << "kpViewManager::textCursorRow() col=" + << m_textCursorCol + << endl; + #endif + (const_cast (this))->m_textCursorCol = + sel->textLines () [row].length (); + } + + handledErrors = true; + } + } + } + + if (!handledErrors) + { + #if DEBUG_KP_VIEW_MANAGER && 1 + kdDebug () << "kpViewManager::textCursorCol() no mw, doc or text sel" << endl; + #endif + (const_cast (this))->m_textCursorCol = -1; + } + + return m_textCursorCol; +} + +void kpViewManager::setTextCursorPosition (int row, int col, bool isUpdateMicroFocusHint) +{ + if (row == m_textCursorRow && col == m_textCursorCol) + return; + + setFastUpdates (); + setQueueUpdates (); + + m_textCursorBlinkState = false; + updateTextCursor (); + + m_textCursorRow = row; + m_textCursorCol = col; + + m_textCursorBlinkState = true; + updateTextCursor (); + + restoreQueueUpdates (); + restoreFastUpdates (); + + if (isUpdateMicroFocusHint) + { + kpDocument *doc = m_mainWindow->document (); + if (!doc) + return; + + kpSelection *sel = doc->selection (); + if (!sel || !sel->isText ()) + return; + + if (m_viewUnderCursor) + { + // TODO: Fix code duplication: kpViewManager::{setTextCursorPosition,updateTextCursor}() & kpView::paintEventDrawSelection() + QPoint topLeft = sel->pointForTextRowCol (m_textCursorRow, m_textCursorCol); + if (topLeft != KP_INVALID_POINT) + { + // TODO: I think you need to consider zooming e.g. try editing + // text at 800% or with focus set to the thumbnail. + // kpSelection/kpDocument works fully in unzoomed + // coordinates unlike the view (which is zoomed and can + // change size). + // + // To fix it here, I think you should call + // m_viewUnderCursor->transformDocToView(QRect). However, + // the rest of the InputMethod support still needs to + // audited for this. + // + // [Bug #27] + m_viewUnderCursor->updateMicroFocusHint(QRect (topLeft.x (), topLeft.y (), 1, sel->textStyle ().fontMetrics ().height ())); + } + } + } +} + + +bool kpViewManager::textCursorBlinkState () const +{ + return m_textCursorBlinkState; +} + +void kpViewManager::setTextCursorBlinkState (bool on) +{ + if (on == m_textCursorBlinkState) + return; + + m_textCursorBlinkState = on; + + updateTextCursor (); +} + + +// protected +void kpViewManager::updateTextCursor () +{ +#if DEBUG_KP_VIEW_MANAGER && 0 + kdDebug () << "kpViewManager::updateTextCursor()" << endl; +#endif + + if (!m_mainWindow) + return; + + kpDocument *doc = m_mainWindow->document (); + if (!doc) + return; + + kpSelection *sel = doc->selection (); + if (!sel || !sel->isText ()) + return; + + // TODO: Fix code duplication: kpViewManager::{setTextCursorPosition,updateTextCursor}() & kpView::paintEventDrawSelection() + QPoint topLeft = sel->pointForTextRowCol (m_textCursorRow, m_textCursorCol); + if (topLeft != KP_INVALID_POINT) + { + setFastUpdates (); + updateViews (QRect (topLeft.x (), topLeft.y (), 1, sel->textStyle ().fontMetrics ().height ())); + restoreFastUpdates (); + } +} + +// protected slot +void kpViewManager::slotTextCursorBlink () +{ +#if DEBUG_KP_VIEW_MANAGER && 0 + kdDebug () << "kpViewManager::slotTextCursorBlink() cursorBlinkState=" + << m_textCursorBlinkState << endl; +#endif + + if (m_textCursorBlinkTimer) + { + m_textCursorBlinkTimer->start (QApplication::cursorFlashTime () / 2, + true/*single shot*/); + } + + updateTextCursor (); + m_textCursorBlinkState = !m_textCursorBlinkState; +} + + +void kpViewManager::setCursor (const QCursor &cursor) +{ + for (QPtrList ::const_iterator it = m_views.begin (); + it != m_views.end (); + it++) + { + (*it)->setCursor (cursor); + } + + m_cursor = cursor; +} + +void kpViewManager::unsetCursor () +{ + for (QPtrList ::const_iterator it = m_views.begin (); + it != m_views.end (); + it++) + { + (*it)->unsetCursor (); + } + + m_cursor = QCursor (); +} + + +kpView *kpViewManager::viewUnderCursor (bool usingQt) const +{ + if (!usingQt) + { + kpViewManager *nonConstThis = const_cast (this); + + if (m_viewUnderCursor && nonConstThis->m_views.findRef (m_viewUnderCursor) < 0) + { + kdError () << "kpViewManager::viewUnderCursor(): invalid view" << endl; + nonConstThis->m_viewUnderCursor = 0; + } + + + return m_viewUnderCursor; + } + else + { + for (QPtrList ::const_iterator it = m_views.begin (); + it != m_views.end (); + it++) + { + if ((*it)->hasMouse ()) + return (*it); + } + + return 0; + } +} + +void kpViewManager::setViewUnderCursor (kpView *view) +{ +#if DEBUG_KP_VIEW_MANAGER && 1 + kdDebug () << "kpViewManager::setViewUnderCursor (" + << (view ? view->name () : "(none)") << ")" + << " old=" << (m_viewUnderCursor ? m_viewUnderCursor->name () : "(none)") + << endl; +#endif + if (view == m_viewUnderCursor) + return; + + m_viewUnderCursor = view; + + if (!m_viewUnderCursor) + { + // Hide the brush if the mouse cursor just left the view + if (m_tempPixmap && m_tempPixmap->isBrush ()) + { + #if DEBUG_KP_VIEW_MANAGER && 1 + kdDebug () << "\thiding brush pixmap since cursor left view" << endl; + #endif + updateViews (m_tempPixmap->rect ()); + } + } + else + { + if (m_mainWindow && m_mainWindow->tool ()) + { + #if DEBUG_KP_VIEW_MANAGER && 1 + kdDebug () << "\tnotify tool that something changed below cursor" << endl; + #endif + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + } + } +} + + +// public +kpView *kpViewManager::activeView () const +{ + for (QPtrList ::const_iterator it = m_views.begin (); + it != m_views.end (); + it++) + { + if ((*it)->isActiveWindow ()) + return (*it); + } + + return 0; +} + + +// public +bool kpViewManager::queueUpdates () const +{ + return (m_queueUpdatesCounter > 0); +} + +// public +void kpViewManager::setQueueUpdates () +{ + m_queueUpdatesCounter++; +#if DEBUG_KP_VIEW_MANAGER && 1 + kdDebug () << "kpViewManager::setQueueUpdates() counter=" + << m_queueUpdatesCounter << endl; +#endif +} + +// public +void kpViewManager::restoreQueueUpdates () +{ + m_queueUpdatesCounter--; +#if DEBUG_KP_VIEW_MANAGER && 1 + kdDebug () << "kpViewManager::restoreQueueUpdates() counter=" + << m_queueUpdatesCounter << endl; +#endif + if (m_queueUpdatesCounter < 0) + { + kdError () << "kpViewManager::restoreQueueUpdates() counter=" + << m_queueUpdatesCounter; + } + + if (m_queueUpdatesCounter <= 0) + { + for (QPtrList ::const_iterator it = m_views.begin (); + it != m_views.end (); + it++) + { + (*it)->updateQueuedArea (); + } + } +} + + +// public +bool kpViewManager::fastUpdates () const +{ + return (m_fastUpdatesCounter > 0); +} + +// public +void kpViewManager::setFastUpdates () +{ + m_fastUpdatesCounter++; +#if DEBUG_KP_VIEW_MANAGER && 0 + kdDebug () << "kpViewManager::setFastUpdates() counter=" + << m_fastUpdatesCounter << endl; +#endif +} + +// public +void kpViewManager::restoreFastUpdates () +{ + m_fastUpdatesCounter--; +#if DEBUG_KP_VIEW_MANAGER && 0 + kdDebug () << "kpViewManager::restoreFastUpdates() counter=" + << m_fastUpdatesCounter << endl; +#endif + if (m_fastUpdatesCounter < 0) + { + kdError () << "kpViewManager::restoreFastUpdates() counter=" + << m_fastUpdatesCounter; + } +} + + +void kpViewManager::updateView (kpView *v) +{ + updateView (v, QRect (0, 0, v->width (), v->height ())); +} + +void kpViewManager::updateView (kpView *v, const QRect &viewRect) +{ + if (!queueUpdates ()) + { + if (fastUpdates ()) + v->repaint (viewRect, false/*no erase*/); + else + v->update (viewRect); + } + else + v->addToQueuedArea (viewRect); +} + +void kpViewManager::updateView (kpView *v, int x, int y, int w, int h) +{ + updateView (v, QRect (x, y, w, h)); +} + +void kpViewManager::updateView (kpView *v, const QRegion &viewRegion) +{ + if (!queueUpdates ()) + { + if (fastUpdates ()) + v->repaint (viewRegion, false/*no erase*/); + else + v->update (viewRegion.boundingRect ()); + } + else + v->addToQueuedArea (viewRegion); +} + +void kpViewManager::updateViewRectangleEdges (kpView *v, const QRect &viewRect) +{ + if (viewRect.height () <= 0 || viewRect.width () <= 0) + return; + + // Top line + updateView (v, QRect (viewRect.x (), viewRect.y (), + viewRect.width (), 1)); + + if (viewRect.height () >= 2) + { + // Bottom line + updateView (v, QRect (viewRect.x (), viewRect.bottom (), + viewRect.width (), 1)); + + if (viewRect.height () > 2) + { + // Left line + updateView (v, QRect (viewRect.x (), viewRect.y () + 1, + 1, viewRect.height () - 2)); + + if (viewRect.width () >= 2) + { + // Right line + updateView (v, QRect (viewRect.right (), viewRect.y () + 1, + 1, viewRect.height () - 2)); + } + } + } +} + + +void kpViewManager::updateViews () +{ + kpDocument *doc = document (); + if (doc) + updateViews (QRect (0, 0, doc->width (), doc->height ())); +} + +void kpViewManager::updateViews (const QRect &docRect) +{ +#if DEBUG_KP_VIEW_MANAGER && 0 + kdDebug () << "kpViewManager::updateViews (" << docRect << ")" << endl; +#endif + + for (QPtrList ::const_iterator it = m_views.begin (); + it != m_views.end (); + it++) + { + kpView *view = *it; + + #if DEBUG_KP_VIEW_MANAGER && 0 + kdDebug () << "\tupdating view " << view->name () << endl; + #endif + if (view->zoomLevelX () % 100 == 0 && view->zoomLevelY () % 100 == 0) + { + #if DEBUG_KP_VIEW_MANAGER && 0 + kdDebug () << "\t\tviewRect=" << view->transformDocToView (docRect) << endl; + #endif + updateView (view, view->transformDocToView (docRect)); + } + else + { + QRect viewRect = view->transformDocToView (docRect); + + int diff = qRound (double (QMAX (view->zoomLevelX (), view->zoomLevelY ())) / 100.0) + 1; + + QRect newRect = QRect (viewRect.x () - diff, + viewRect.y () - diff, + viewRect.width () + 2 * diff, + viewRect.height () + 2 * diff) + .intersect (QRect (0, 0, view->width (), view->height ())); + + #if DEBUG_KP_VIEW_MANAGER && 0 + kdDebug () << "\t\tviewRect (+compensate)=" << newRect << endl; + #endif + updateView (view, newRect); + } + } +} + +void kpViewManager::updateViews (int x, int y, int w, int h) +{ + updateViews (QRect (x, y, w, h)); +} + + +void kpViewManager::adjustViewsToEnvironment () +{ +#if DEBUG_KP_VIEW_MANAGER && 1 + kdDebug () << "kpViewManager::adjustViewsToEnvironment()" + << " numViews=" << m_views.count () + << endl; +#endif + for (QPtrList ::const_iterator it = m_views.begin (); + it != m_views.end (); + it++) + { + kpView *view = *it; + + #if DEBUG_KP_VIEW_MANAGER && 1 + kdDebug () << "\tview: " << view->name () + << endl; + #endif + view->adjustToEnvironment (); + } +} + +#include + diff --git a/kolourpaint/kpviewmanager.h b/kolourpaint/kpviewmanager.h new file mode 100644 index 00000000..c6ea1ef0 --- /dev/null +++ b/kolourpaint/kpviewmanager.h @@ -0,0 +1,220 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kpviewmanager_h__ +#define __kpviewmanager_h__ + +#include +#include +#include +#include + + +class QPixmap; +class QRect; +class QTimer; + +class kpDocument; +class kpView; +class kpMainWindow; +class kpTempPixmap; + +class kpViewManager : public QObject +{ +Q_OBJECT + +public: + kpViewManager (kpMainWindow *mainWindow); + ~kpViewManager (); + + + // + // Registering views + // + + void registerView (kpView *view); + void unregisterView (kpView *view); + void unregisterAllViews (); + + + // + // Temp Pixmap + // + + const kpTempPixmap *tempPixmap () const; + void setTempPixmap (const kpTempPixmap &tempPixmap); + void invalidateTempPixmap (); + + + // + // Selections + // + + bool selectionBorderVisible () const; + void setSelectionBorderVisible (bool yes = true); + + bool selectionBorderFinished () const; + void setSelectionBorderFinished (bool yes = true); + + + // + // Text Cursor + // + + bool textCursorEnabled () const; + void setTextCursorEnabled (bool yes = true); + + int textCursorRow () const; + int textCursorCol () const; + void setTextCursorPosition (int row, int col, bool isUpdateMicroFocusHint = false); + + bool textCursorBlinkState () const; + void setTextCursorBlinkState (bool on = true); + +protected: + void updateTextCursor (); + + QTimer *m_textCursorBlinkTimer; + int m_textCursorRow, m_textCursorCol; + bool m_textCursorBlinkState; + +protected slots: + void slotTextCursorBlink (); + +public: + + // + // Cursors + // + + void setCursor (const QCursor &cursor); + void unsetCursor (); + + + // + // View + // + + kpView *viewUnderCursor (bool usingQt = false) const; + + // + // QWidget::hasMouse() is unreliable: + // + // "bool QWidget::hasMouse () const + // ... See the "underMouse" property for details. + // . + // . + // . + // bool underMouse + // ... This value is not updated properly during drag and drop operations." + // + // i.e. it's possible that hasMouse() returns false in a mousePressEvent()! + // + // This hack needs to be called from kpView so that viewUnderCursor() works + // as a reasonable replacement (although there is at least one case where + // it still won't work - just after a fake drag onto the view). + // + void setViewUnderCursor (kpView *view); + + + // Returns a pointer to the view that has keyboard focus or else, 0 + // TODO: rename to "anActiveView()" or "aViewIsActive()" as more than + // 1 view can be active at the same time? + kpView *activeView () const; + + + // Specifies whether KolourPaint will queue _all_ paint events + // (generated by you or the window system), until the + // corresponding call to restoreQueueUpdates(). Use this + // before multiple, big, non-interactive changes to the + // document to eliminate virtually all flicker. + // + // This is better than QWidget::setUpdatesEnabled() because + // restoreQueueUpdates() automatically restores only the regions + // of the views that need to be repainted, per view. + bool queueUpdates () const; + void setQueueUpdates (); + void restoreQueueUpdates (); + + // Controls behaviour of updateViews(): + // + // Slow: Let Qt buffer paint events via QWidget::update(). + // Results in less flicker. Paint events are probably merged + // so long-term efficiency is increased at the expense of + // reduced responsiveness (default). + // Fast: Force Qt to redraw immediately. No paint events + // are merged so there is great potential for flicker, + // if used inappropriately. Use this when the redraw + // area is small and KolourPaint's responsiveness is + // critical. Continual use of this mode can result in + // unnecessary redraws and incredibly slugish performance. + bool fastUpdates () const; + void setFastUpdates (); + void restoreFastUpdates (); + +private: + int m_queueUpdatesCounter, m_fastUpdatesCounter; + +public slots: + // updating views + void updateView (kpView *v); + void updateView (kpView *v, const QRect &viewRect); + void updateView (kpView *v, int x, int y, int w, int h); + void updateView (kpView *v, const QRegion &viewRegion); + void updateViewRectangleEdges (kpView *v, const QRect &viewRect); + + void updateViews (); + void updateViews (const QRect &docRect); + void updateViews (int x, int y, int w, int h); + + void adjustViewsToEnvironment (); + +private: + // don't use + kpViewManager (const kpViewManager &); + bool operator= (const kpViewManager &); + + kpDocument *document () const; + + kpMainWindow *m_mainWindow; + QPtrList m_views; + QCursor m_cursor; + + kpTempPixmap *m_tempPixmap; + kpView *m_viewUnderCursor; + + bool m_selectionBorderVisible; + bool m_selectionBorderFinished; + + // There is no need to maintain binary compatibility at this stage. + // The d-pointer is just so that you can experiment without recompiling + // the kitchen sink. + class kpViewManagerPrivate *d; +}; + +#endif // __kpviewmanager_h__ diff --git a/kolourpaint/kpviewscrollablecontainer.cpp b/kolourpaint/kpviewscrollablecontainer.cpp new file mode 100644 index 00000000..637f71b7 --- /dev/null +++ b/kolourpaint/kpviewscrollablecontainer.cpp @@ -0,0 +1,1390 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_VIEW_SCROLLABLE_CONTAINER 0 + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + + +// (Pulled from out of Thurston's hat) +static const int DragScrollLeftTopMargin = 0; +static const int DragScrollRightBottomMargin = 16; // scrollbarish +static const int DragScrollInterval = 1000 / 10; +static const int DragScrollInitialInterval = DragScrollInterval * 2; +static const int DragScrollNumPixels = 5; +static const int DragDistanceFromRectMaxFor1stMultiplier = 50; +static const int DragDistanceFromRectMaxFor2ndMultiplier = 100; + +static const int GripSize = 7; +static const int GripHandleSize = 7; + + +kpGrip::kpGrip (GripType type, + QWidget *parent, const char *name) + : QWidget (parent, name), + m_type (type), + m_startPoint (KP_INVALID_POINT), + m_currentPoint (KP_INVALID_POINT), + m_shouldReleaseMouseButtons (false) +{ + setCursor (cursorForType (m_type)); + + setMouseTracking (true); // mouseMoveEvent's even when no mousebtn down + + updatePixmap (); +} + +kpGrip::~kpGrip () +{ +} + + +// public +kpGrip::GripType kpGrip::type () const +{ + return m_type; +} + + +// public static +const QCursor &kpGrip::cursorForType (GripType type) +{ + switch (type) + { + case Bottom: + return Qt::sizeVerCursor; + break; // one day you'll forget + + case Right: + return Qt::sizeHorCursor; + break; // one day you'll forget + + case BottomRight: + return Qt::sizeFDiagCursor; + break; // one day you'll forget + } + + return Qt::arrowCursor; +} + + +// public +QRect kpGrip::hotRect (bool toGlobal) const +{ + QRect ret; + + switch (m_type) + { + case Bottom: + { + const int handleX = (width () - GripHandleSize) / 2; + ret = QRect (handleX, 0, + GripHandleSize, height ()); + break; + } + case Right: + { + const int handleY = (height () - GripHandleSize) / 2; + ret = QRect (0, handleY, + width (), GripHandleSize); + break; + } + case BottomRight: + // pixmap all opaque + ret = rect (); + break; + + default: + return QRect (); + } + + return (toGlobal ? QRect (mapToGlobal (ret.topLeft ()), + mapToGlobal (ret.bottomRight ())) + : ret); +} + + +// public +bool kpGrip::isDrawing () const +{ + return (m_startPoint != KP_INVALID_POINT); +} + + +// public +QString kpGrip::haventBegunDrawUserMessage () const +{ + return i18n ("Left drag the handle to resize the image."); +} + + +// public +QString kpGrip::userMessage () const +{ + return m_userMessage; +} + +// public +void kpGrip::setUserMessage (const QString &message) +{ + // Don't do NOP checking here since another grip might have changed + // the message so an apparent NOP for this grip is not a NOP in the + // global sense (kpViewScrollableContainer::slotGripStatusMessageChanged()). + + m_userMessage = message; + emit statusMessageChanged (message); +} + + +// protected +void kpGrip::updatePixmap () +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpGrip::updatePixmap() rect=" << rect () << endl; +#endif + if (width () <= 0 || height () <= 0) + return; + + QPixmap pixmap (width (), height ()); + pixmap.fill (colorGroup ().highlight ()); + kpPixmapFX::ensureTransparentAt (&pixmap, pixmap.rect ()); + const QRect hr = hotRect (); +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "\thotRect=" << hr << endl; +#endif + if (hr.isValid ()) + kpPixmapFX::ensureOpaqueAt (&pixmap, hr); + + setBackgroundPixmap (pixmap); + if (pixmap.mask ()) + setMask (*pixmap.mask ()); +} + + +// protected +void kpGrip::cancel () +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpGrip::cancel()" << endl; +#endif + if (m_currentPoint == KP_INVALID_POINT) + return; + + m_startPoint = KP_INVALID_POINT; + m_currentPoint = KP_INVALID_POINT; + + setUserMessage (i18n ("Resize Image: Let go of all the mouse buttons.")); + setCursor (Qt::arrowCursor); + m_shouldReleaseMouseButtons = true; + + releaseKeyboard (); + emit cancelledDraw (); +} + + +// protected virtual [base QWidget] +void kpGrip::keyReleaseEvent (QKeyEvent *e) +{ + if (m_startPoint != KP_INVALID_POINT && + e->key () == Qt::Key_Escape) + { + cancel (); + } +} + +// protected virtual [base QWidget] +void kpGrip::mousePressEvent (QMouseEvent *e) +{ + if (m_startPoint == KP_INVALID_POINT && + (e->stateAfter () & Qt::MouseButtonMask) == Qt::LeftButton) + { + m_startPoint = e->pos (); + m_currentPoint = e->pos (); + emit beganDraw (); + grabKeyboard (); + + setUserMessage (i18n ("Resize Image: Right click to cancel.")); + setCursor (cursorForType (m_type)); + } + else + { + if (m_startPoint != KP_INVALID_POINT) + cancel (); + } +} + +// public +QPoint kpGrip::viewDeltaPoint () const +{ + if (m_startPoint == KP_INVALID_POINT) + return KP_INVALID_POINT; + + const QPoint point = mapFromGlobal (QCursor::pos ()); + + // TODO: this is getting out of sync with m_currentPoint + + return QPoint (((m_type & Right) ? point.x () - m_startPoint.x () : 0), + ((m_type & Bottom) ? point.y () - m_startPoint.y () : 0)); + +} + +// public +void kpGrip::mouseMovedTo (const QPoint &point, bool dueToDragScroll) +{ + if (m_startPoint == KP_INVALID_POINT) + return; + + m_currentPoint = point; + + emit continuedDraw (((m_type & Right) ? point.x () - m_startPoint.x () : 0), + ((m_type & Bottom) ? point.y () - m_startPoint.y () : 0), + dueToDragScroll); +} + +// protected virtual [base QWidget] +void kpGrip::mouseMoveEvent (QMouseEvent *e) +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpGrip::mouseMoveEvent() m_startPoint=" << m_startPoint + << " stateAfter=" << e->stateAfter () + << endl; +#endif + + if (m_startPoint == KP_INVALID_POINT) + { + if ((e->stateAfter () & Qt::MouseButtonMask) == 0) + setUserMessage (haventBegunDrawUserMessage ()); + return; + } + + mouseMovedTo (e->pos (), false/*not due to drag scroll*/); +} + +// protected virtual [base QWidget] +void kpGrip::mouseReleaseEvent (QMouseEvent *e) +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpGrip::mouseReleaseEvent() m_startPoint=" << m_startPoint + << " stateAfter=" << e->stateAfter () + << endl; +#endif + + if (m_startPoint != KP_INVALID_POINT) + { + const int dx = m_currentPoint.x () - m_startPoint.x (), + dy = m_currentPoint.y () - m_startPoint.y (); + + m_currentPoint = KP_INVALID_POINT; + m_startPoint = KP_INVALID_POINT; + + releaseKeyboard (); + emit endedDraw ((m_type & Right) ? dx : 0, + (m_type & Bottom) ? dy : 0); + } + + if ((e->stateAfter () & Qt::MouseButtonMask) == 0) + { + m_shouldReleaseMouseButtons = false; + setUserMessage (QString::null); + setCursor (cursorForType (m_type)); + + releaseKeyboard (); + emit releasedAllButtons (); + } +} + + +// protected virtual [base QWidget] +void kpGrip::resizeEvent (QResizeEvent *) +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpGrip::resizeEvent()" << endl; +#endif + updatePixmap (); +} + + +// protected virtual [base QWidget] +void kpGrip::enterEvent (QEvent * /*e*/) +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpGrip::enterEvent()" + << " m_startPoint=" << m_startPoint + << " shouldReleaseMouseButtons=" + << m_shouldReleaseMouseButtons << endl; +#endif + + if (m_startPoint == KP_INVALID_POINT && + !m_shouldReleaseMouseButtons) + { + #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "\tsending message" << endl; + #endif + setUserMessage (haventBegunDrawUserMessage ()); + } +} + +// protected virtual [base QWidget] +void kpGrip::leaveEvent (QEvent * /*e*/) +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpGrip::leaveEvent()" + << " m_startPoint=" << m_startPoint + << " shouldReleaseMouseButtons=" + << m_shouldReleaseMouseButtons << endl; +#endif + if (m_startPoint == KP_INVALID_POINT && + !m_shouldReleaseMouseButtons) + { + setUserMessage (QString::null); + } +} + + +// protected virtual [base QWidget] +void kpGrip::paintEvent (QPaintEvent *e) +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 0 + kdDebug () << "kpGrip::paintEvent(" << e->rect () << ")" << endl; +#endif + QWidget::paintEvent (e); +} + + +// TODO: Are we checking for m_view == 0 often enough? +kpViewScrollableContainer::kpViewScrollableContainer (kpMainWindow *parent, + const char *name) + : QScrollView ((QWidget *) parent, name, Qt::WStaticContents | Qt::WNoAutoErase), + m_mainWindow (parent), + m_contentsXSoon (-1), m_contentsYSoon (-1), + m_view (0), + m_bottomGrip (new kpGrip (kpGrip::Bottom, viewport (), "Bottom Grip")), + m_rightGrip (new kpGrip (kpGrip::Right, viewport (), "Right Grip")), + m_bottomRightGrip (new kpGrip (kpGrip::BottomRight, viewport (), "BottomRight Grip")), + m_docResizingGrip (0), + m_dragScrollTimer (new QTimer (this)), + m_zoomLevel (100), + m_scrollTimerRunOnce (false), + m_resizeRoundedLastViewX (-1), m_resizeRoundedLastViewY (-1), + m_resizeRoundedLastViewDX (0), m_resizeRoundedLastViewDY (0), + m_haveMovedFromOriginalDocSize (false) + +{ + m_bottomGrip->setFixedHeight (GripSize); + m_bottomGrip->hide (); + addChild (m_bottomGrip); + connectGripSignals (m_bottomGrip); + + m_rightGrip->setFixedWidth (GripSize); + m_rightGrip->hide (); + addChild (m_rightGrip); + connectGripSignals (m_rightGrip); + + m_bottomRightGrip->setFixedSize (GripSize, GripSize); + m_bottomRightGrip->hide (); + addChild (m_bottomRightGrip); + connectGripSignals (m_bottomRightGrip); + + + connect (this, SIGNAL (contentsMoving (int, int)), + this, SLOT (slotContentsMoving (int, int))); + + connect (m_dragScrollTimer, SIGNAL (timeout ()), + this, SLOT (slotDragScroll ())); +} + +kpViewScrollableContainer::~kpViewScrollableContainer () +{ +} + + +// public +int kpViewScrollableContainer::contentsXSoon () +{ + if (m_contentsXSoon < 0) + return contentsX (); + else + return m_contentsXSoon; +} + +// public +int kpViewScrollableContainer::contentsYSoon () +{ + if (m_contentsYSoon < 0) + return contentsY (); + else + return m_contentsYSoon; +} + + +// protected +void kpViewScrollableContainer::connectGripSignals (kpGrip *grip) +{ + connect (grip, SIGNAL (beganDraw ()), + this, SLOT (slotGripBeganDraw ())); + connect (grip, SIGNAL (continuedDraw (int, int, bool)), + this, SLOT (slotGripContinuedDraw (int, int, bool))); + connect (grip, SIGNAL (cancelledDraw ()), + this, SLOT (slotGripCancelledDraw ())); + connect (grip, SIGNAL (endedDraw (int, int)), + this, SLOT (slotGripEndedDraw (int, int))); + + connect (grip, SIGNAL (statusMessageChanged (const QString &)), + this, SLOT (slotGripStatusMessageChanged (const QString &))); + + connect (grip, SIGNAL (releasedAllButtons ()), + this, SLOT (recalculateStatusMessage ())); +} + + +// public +QSize kpViewScrollableContainer::newDocSize () const +{ + return newDocSize (m_resizeRoundedLastViewDX, + m_resizeRoundedLastViewDY); +} + +// public +bool kpViewScrollableContainer::haveMovedFromOriginalDocSize () const +{ + return m_haveMovedFromOriginalDocSize; +} + +// public +QString kpViewScrollableContainer::statusMessage () const +{ + return m_gripStatusMessage; +} + +// public +void kpViewScrollableContainer::clearStatusMessage () +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 1 + kdDebug () << "kpViewScrollableContainer::clearStatusMessage()" << endl; +#endif + m_bottomRightGrip->setUserMessage (QString::null); + m_bottomGrip->setUserMessage (QString::null); + m_rightGrip->setUserMessage (QString::null); +} + + +// protected +QSize kpViewScrollableContainer::newDocSize (int viewDX, int viewDY) const +{ + if (!m_view) + return QSize (); + + if (!docResizingGrip ()) + return QSize (); + + const int docX = (int) m_view->transformViewToDocX (m_view->width () + viewDX); + const int docY = (int) m_view->transformViewToDocY (m_view->height () + viewDY); + + return QSize (QMAX (1, docX), QMAX (1, docY)); +} + + +// protected +void kpViewScrollableContainer::calculateDocResizingGrip () +{ + if (m_bottomRightGrip->isDrawing ()) + m_docResizingGrip = m_bottomRightGrip; + else if (m_bottomGrip->isDrawing ()) + m_docResizingGrip = m_bottomGrip; + else if (m_rightGrip->isDrawing ()) + m_docResizingGrip = m_rightGrip; + else + m_docResizingGrip = 0; +} + +// protected +kpGrip *kpViewScrollableContainer::docResizingGrip () const +{ + return m_docResizingGrip; +} + + +// protected +int kpViewScrollableContainer::bottomResizeLineWidth () const +{ + if (!docResizingGrip ()) + return -1; + + if (!m_view) + return -1; + + if (docResizingGrip ()->type () & kpGrip::Bottom) + return QMAX (m_view->zoomLevelY () / 100, 1); + else + return 1; +} + +// protected +int kpViewScrollableContainer::rightResizeLineWidth () const +{ + if (!docResizingGrip ()) + return -1; + + if (!m_view) + return -1; + + if (docResizingGrip ()->type () & kpGrip::Right) + return QMAX (m_view->zoomLevelX () / 100, 1); + else + return 1; +} + + +// protected +QRect kpViewScrollableContainer::bottomResizeLineRect () const +{ + if (m_resizeRoundedLastViewX < 0 || m_resizeRoundedLastViewY < 0) + return QRect (); + + return QRect (QPoint (0, + m_resizeRoundedLastViewY), + QPoint (m_resizeRoundedLastViewX - 1, + m_resizeRoundedLastViewY + bottomResizeLineWidth () - 1)); +} + +// protected +QRect kpViewScrollableContainer::rightResizeLineRect () const +{ + if (m_resizeRoundedLastViewX < 0 || m_resizeRoundedLastViewY < 0) + return QRect (); + + return QRect (QPoint (m_resizeRoundedLastViewX, + 0), + QPoint (m_resizeRoundedLastViewX + rightResizeLineWidth () - 1, + m_resizeRoundedLastViewY - 1)); +} + +// protected +QRect kpViewScrollableContainer::bottomRightResizeLineRect () const +{ + if (m_resizeRoundedLastViewX < 0 || m_resizeRoundedLastViewY < 0) + return QRect (); + + return QRect (QPoint (m_resizeRoundedLastViewX, + m_resizeRoundedLastViewY), + QPoint (m_resizeRoundedLastViewX + rightResizeLineWidth () - 1, + m_resizeRoundedLastViewY + bottomResizeLineWidth () - 1)); +} + + +// TODO: are these 2 correct? Remember that viewport()->x() == 1, viewport()->y() == 1 + +// protected +QPoint kpViewScrollableContainer::mapViewToViewport (const QPoint &viewPoint) +{ + return viewPoint - QPoint (contentsX (), contentsY ()); +} + +// protected +QRect kpViewScrollableContainer::mapViewToViewport (const QRect &viewRect) +{ + if (!viewRect.isValid ()) + return QRect (); + + QRect ret = viewRect; + ret.moveBy (-contentsX (), -contentsY ()); + return ret; +} + + +// protected +QRect kpViewScrollableContainer::mapViewportToGlobal (const QRect &viewportRect) +{ + return kpWidgetMapper::toGlobal (viewport (), viewportRect); +} + +// protected +QRect kpViewScrollableContainer::mapViewToGlobal (const QRect &viewRect) +{ + return mapViewportToGlobal (mapViewToViewport (viewRect)); +} + + +// protected +void kpViewScrollableContainer::repaintWidgetAtResizeLineViewRect ( + QWidget *widget, const QRect &resizeLineViewRect) +{ + const QRect resizeLineGlobalRect = mapViewToGlobal (resizeLineViewRect); + const QRect widgetGlobalRect = kpWidgetMapper::toGlobal (widget, + widget->rect ()); + + const QRect redrawGlobalRect = + resizeLineGlobalRect.intersect (widgetGlobalRect); + + const QRect redrawWidgetRect = + kpWidgetMapper::fromGlobal (widget, redrawGlobalRect); + + + if (redrawWidgetRect.isValid ()) + { + // TODO: should be "!widget->testWFlags (Qt::WRepaintNoErase)" + // but for some reason, doesn't work for viewport(). + const bool erase = !dynamic_cast (widget); + widget->repaint (redrawWidgetRect, erase); + } +} + +// protected +void kpViewScrollableContainer::repaintWidgetAtResizeLines (QWidget *widget) +{ + repaintWidgetAtResizeLineViewRect (widget, rightResizeLineRect ()); + repaintWidgetAtResizeLineViewRect (widget, bottomResizeLineRect ()); + repaintWidgetAtResizeLineViewRect (widget, bottomRightResizeLineRect ()); +} + +// protected +void kpViewScrollableContainer::eraseResizeLines () +{ + if (m_resizeRoundedLastViewX >= 0 && m_resizeRoundedLastViewY >= 0) + { + repaintWidgetAtResizeLines (viewport ()); + repaintWidgetAtResizeLines (m_view); + + repaintWidgetAtResizeLines (m_bottomGrip); + repaintWidgetAtResizeLines (m_rightGrip); + repaintWidgetAtResizeLines (m_bottomRightGrip); + } +} + + +// protected +void kpViewScrollableContainer::drawResizeLines () +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 0 + kdDebug () << "kpViewScrollableContainer::drawResizeLines()" + << " lastViewX=" << m_resizeRoundedLastViewX + << " lastViewY=" << m_resizeRoundedLastViewY + << endl; +#endif + + + QPainter p (viewport (), true/*unclipped*/); + p.setRasterOp (Qt::NotROP); + + const QRect rightRect = rightResizeLineRect (); + if (rightRect.isValid ()) + p.fillRect (mapViewToViewport (rightRect), Qt::white); + + const QRect bottomRect = bottomResizeLineRect (); + if (bottomRect.isValid ()) + p.fillRect (mapViewToViewport (bottomRect), Qt::white); + + const QRect bottomRightRect = bottomRightResizeLineRect (); + if (bottomRightRect.isValid ()) + p.fillRect (mapViewToViewport (bottomRightRect), Qt::white); + + p.end (); +} + + +// protected +void kpViewScrollableContainer::updateResizeLines (int viewX, int viewY, + int viewDX, int viewDY) +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 0 + kdDebug () << "kpViewScrollableContainer::updateResizeLines(" + << viewX << "," << viewY << ")" + << " oldViewX=" << m_resizeRoundedLastViewX + << " oldViewY=" << m_resizeRoundedLastViewY + << " viewDX=" << viewDX + << " viewDY=" << viewDY + << endl; +#endif + + eraseResizeLines (); + + + if (viewX >= 0 && viewY >= 0) + { + m_resizeRoundedLastViewX = (int) m_view->transformDocToViewX ((int) m_view->transformViewToDocX (viewX)); + m_resizeRoundedLastViewY = (int) m_view->transformDocToViewY ((int) m_view->transformViewToDocY (viewY)); + + m_resizeRoundedLastViewDX = viewDX; + m_resizeRoundedLastViewDY = viewDY; + } + else + { + m_resizeRoundedLastViewX = -1; + m_resizeRoundedLastViewY = -1; + + m_resizeRoundedLastViewDX = 0; + m_resizeRoundedLastViewDY = 0; + } + + // TODO: This is suboptimal since if another window pops up on top of + // KolourPaint then disappears, the lines are not redrawn + // (although this doesn't happen very frequently since we grab the + // keyboard and mouse when resizing): + // + // e.g. sleep 5 && gedit & sleep 10 && killall gedit + // + // Should be done in the paintEvent's of every child of the + // scrollview. + drawResizeLines (); +} + + +// protected slot +void kpViewScrollableContainer::slotGripBeganDraw () +{ + if (!m_view) + return; + + calculateDocResizingGrip (); + + m_haveMovedFromOriginalDocSize = false; + + updateResizeLines (m_view->width (), m_view->height (), + 0/*viewDX*/, 0/*viewDY*/); + + emit beganDocResize (); +} + +// protected slot +void kpViewScrollableContainer::slotGripContinuedDraw (int inViewDX, int inViewDY, + bool dueToDragScroll) +{ + int viewDX = inViewDX, + viewDY = inViewDY; + +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpViewScrollableContainer::slotGripContinuedDraw(" + << viewDX << "," << viewDY << ") size=" + << newDocSize (viewDX, viewDY) + << " dueToDragScroll=" << dueToDragScroll + << endl; +#endif + + if (!m_view) + return; + + if (!dueToDragScroll && + beginDragScroll (QPoint (), QPoint (), m_view->zoomLevelX ())) + { + const QPoint newViewDeltaPoint = docResizingGrip ()->viewDeltaPoint (); + viewDX = newViewDeltaPoint.x (); + viewDY = newViewDeltaPoint.y (); + #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "\tdrag scrolled - new view delta point=" + << newViewDeltaPoint + << endl; + #endif + } + + m_haveMovedFromOriginalDocSize = true; + + updateResizeLines (QMAX (1, QMAX (m_view->width () + viewDX, (int) m_view->transformDocToViewX (1))), + QMAX (1, QMAX (m_view->height () + viewDY, (int) m_view->transformDocToViewY (1))), + viewDX, viewDY); + + emit continuedDocResize (newDocSize ()); +} + +// protected slot +void kpViewScrollableContainer::slotGripCancelledDraw () +{ + m_haveMovedFromOriginalDocSize = false; + + updateResizeLines (-1, -1, 0, 0); + + calculateDocResizingGrip (); + + emit cancelledDocResize (); + + endDragScroll (); +} + +// protected slot +void kpViewScrollableContainer::slotGripEndedDraw (int viewDX, int viewDY) +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpViewScrollableContainer::slotGripEndedDraw(" + << viewDX << "," << viewDY << ") size=" + << newDocSize (viewDX, viewDY) + << endl; +#endif + + if (!m_view) + return; + + const QSize newSize = newDocSize (viewDX, viewDY); + + m_haveMovedFromOriginalDocSize = false; + + // must erase lines before view size changes + updateResizeLines (-1, -1, 0, 0); + + calculateDocResizingGrip (); + + emit endedDocResize (newSize); + + endDragScroll (); +} + + +// protected slot +void kpViewScrollableContainer::slotGripStatusMessageChanged (const QString &string) +{ + if (string == m_gripStatusMessage) + return; + + m_gripStatusMessage = string; + emit statusMessageChanged (string); +} + + +// public slot +void kpViewScrollableContainer::recalculateStatusMessage () +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpViewScrollabelContainer::recalculateStatusMessage()" << endl; + kdDebug () << "\tQCursor::pos=" << QCursor::pos () + << " global visibleRect=" + << kpWidgetMapper::toGlobal (this, + QRect (0, 0, visibleWidth (), visibleHeight ())) + << " brGrip.hotRect=" << m_bottomRightGrip->hotRect (true) + << " bGrip.hotRect=" << m_bottomGrip->hotRect (true) + << " rGrip.hotRect=" << m_rightGrip->hotRect (true) + << endl; +#endif + + // HACK: After dragging to a new size, handles move so that they are now + // under the mouse pointer but no mouseMoveEvent() is generated for + // any grip. This also handles the case of cancelling over any + // grip. + // + if (kpWidgetMapper::toGlobal (this, + QRect (0, 0, visibleWidth (), visibleHeight ())) + .contains (QCursor::pos ())) + { + if (m_bottomRightGrip->isShown () && + m_bottomRightGrip->hotRect (true/*to global*/) + .contains (QCursor::pos ())) + { + m_bottomRightGrip->setUserMessage (i18n ("Left drag the handle to resize the image.")); + } + else if (m_bottomGrip->isShown () && + m_bottomGrip->hotRect (true/*to global*/) + .contains (QCursor::pos ())) + { + m_bottomGrip->setUserMessage (i18n ("Left drag the handle to resize the image.")); + } + else if (m_rightGrip->isShown () && + m_rightGrip->hotRect (true/*to global*/) + .contains (QCursor::pos ())) + { + m_rightGrip->setUserMessage (i18n ("Left drag the handle to resize the image.")); + } + else + { + clearStatusMessage (); + } + } + else + { + clearStatusMessage (); + } +} + + +// protected slot +void kpViewScrollableContainer::slotContentsMoving (int x, int y) +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpViewScrollableContainer::slotContentsMoving(" + << x << "," << y << ")" + << " contentsX=" << contentsX () + << " contentsY=" << contentsY () << endl; +#endif + + m_contentsXSoon = x, m_contentsYSoon = y; + emit contentsMovingSoon (m_contentsXSoon, m_contentsYSoon); + + // Reduce flicker - don't let QScrollView scroll to-be-erased lines + eraseResizeLines (); + + QTimer::singleShot (0, this, SLOT (slotContentsMoved ())); +} + +// protected slot +void kpViewScrollableContainer::slotContentsMoved () +{ + m_contentsXSoon = m_contentsYSoon = -1; + + kpGrip *grip = docResizingGrip (); +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpViewScrollableContainer::slotContentsMoved()" + << " grip=" << grip + << " contentsX=" << contentsX () + << " contentsY=" << contentsY () << endl; +#endif + if (!grip) + return; + + grip->mouseMovedTo (grip->mapFromGlobal (QCursor::pos ()), + true/*moved due to drag scroll*/); +} + + +// protected +void kpViewScrollableContainer::disconnectViewSignals () +{ + disconnect (m_view, SIGNAL (sizeChanged (const QSize &)), + this, SLOT (updateGrips ())); + disconnect (m_view, SIGNAL (destroyed ()), + this, SLOT (slotViewDestroyed ())); +} + +// protected +void kpViewScrollableContainer::connectViewSignals () +{ + connect (m_view, SIGNAL (sizeChanged (const QSize &)), + this, SLOT (updateGrips ())); + connect (m_view, SIGNAL (destroyed ()), + this, SLOT (slotViewDestroyed ())); +} + + +// public virtual [base QScrollView] +void kpViewScrollableContainer::addChild (QWidget *widget, int x, int y) +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpViewScrollableContainer::addChild(" << widget + << "," << x << "," << y << endl; +#endif + + QScrollView::addChild (widget, x, y); + + kpView *view = dynamic_cast (widget); +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "\tcast to kpView: " << view << endl; +#endif + if (view) + { + setView (view); + } +} + + +// public +kpView *kpViewScrollableContainer::view () const +{ + return m_view; +} + +// public +void kpViewScrollableContainer::setView (kpView *view) +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpViewScrollableContainer::setView(" << view << ")" << endl; +#endif + + if (m_view == view) + return; + + if (m_view) + { + disconnectViewSignals (); + } + + m_view = view; + + updateGrips (); + + if (m_view) + { + connectViewSignals (); + } +} + + +// public slot +void kpViewScrollableContainer::updateGrips () +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpViewScrollableContainer::updateGrips() m_view=" + << m_view << endl; +#endif + + if (m_view) + { + m_bottomGrip->setFixedWidth (m_view->width ()); + moveChild (m_bottomGrip, 0, m_view->height ()); + + m_rightGrip->setFixedHeight (m_view->height ()); + moveChild (m_rightGrip, m_view->width (), 0); + + moveChild (m_bottomRightGrip, m_view->width (), m_view->height ()); + } + + m_bottomGrip->setShown (bool (m_view)); + m_rightGrip->setShown (bool (m_view)); + m_bottomRightGrip->setShown (bool (m_view)); + +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "\tcontentsRect=" << contentsRect () + << " visibleRect=" << visibleRect () + << " viewportRect=" << viewport ()->rect () + << endl; +#endif + + if (m_view) + { + resizeContents (m_view->width () + m_rightGrip->width (), + m_view->height () + m_bottomGrip->height ()); + } + else + { + resizeContents (0, 0); + } + + recalculateStatusMessage (); +} + +// protected slot +void kpViewScrollableContainer::slotViewDestroyed () +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpViewScrollableContainer::slotViewDestroyed() m_view=" + << m_view << endl; +#endif + + m_view = 0; + updateGrips (); +} + + +// public slot +bool kpViewScrollableContainer::beginDragScroll (const QPoint &/*docPoint*/, + const QPoint &/*lastDocPoint*/, + int zoomLevel, + bool *didSomething) +{ + if (didSomething) + *didSomething = false; + + m_zoomLevel = zoomLevel; + + const QPoint p = mapFromGlobal (QCursor::pos ()); + +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpViewScrollableContainer::beginDragScroll() p=" << p + << " dragScrollTimerRunOnce=" << m_scrollTimerRunOnce + << endl; +#endif + + bool stopDragScroll = true; + bool scrolled = false; + + if (!noDragScrollRect ().contains (p)) + { + if (m_dragScrollTimer->isActive ()) + { + if (m_scrollTimerRunOnce) + { + scrolled = slotDragScroll (); + } + } + else + { + m_scrollTimerRunOnce = false; + m_dragScrollTimer->start (DragScrollInitialInterval); + } + + stopDragScroll = false; + } + + if (stopDragScroll) + m_dragScrollTimer->stop (); + + if (didSomething) + *didSomething = scrolled; + + return scrolled; +} + +// public slot +bool kpViewScrollableContainer::beginDragScroll (const QPoint &docPoint, + const QPoint &lastDocPoint, + int zoomLevel) +{ + return beginDragScroll (docPoint, lastDocPoint, zoomLevel, + 0/*don't want scrolled notification*/); +} + + +// public slot +bool kpViewScrollableContainer::endDragScroll () +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpViewScrollableContainer::endDragScroll()" << endl; +#endif + + if (m_dragScrollTimer->isActive ()) + { + m_dragScrollTimer->stop (); + return true; + } + else + { + return false; + } +} + + +static const int distanceFromRectToMultiplier (int dist) +{ + if (dist < 0) + return 0; + else if (dist < DragDistanceFromRectMaxFor1stMultiplier) + return 1; + else if (dist < DragDistanceFromRectMaxFor2ndMultiplier) + return 2; + else + return 4; +} + + +// protected slot +bool kpViewScrollableContainer::slotDragScroll (bool *didSomething) +{ + bool scrolled = false; + + if (didSomething) + *didSomething = false; + + + const QRect rect = noDragScrollRect (); + const QPoint pos = mapFromGlobal (QCursor::pos ()); + +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpViewScrollableContainer::slotDragScroll()" + << " noDragScrollRect=" << rect + << " pos=" << pos + << " contentsX=" << contentsX () + << " contentsY=" << contentsY () << endl; +#endif + + int dx = 0, dy = 0; + int dxMultiplier = 0, dyMultiplier = 0; + + if (pos.x () < rect.left ()) + { + dx = -DragScrollNumPixels; + dxMultiplier = distanceFromRectToMultiplier (rect.left () - pos.x ()); + } + else if (pos.x () > rect.right ()) + { + dx = +DragScrollNumPixels; + dxMultiplier = distanceFromRectToMultiplier (pos.x () - rect.right ()); + } + + if (pos.y () < rect.top ()) + { + dy = -DragScrollNumPixels; + dyMultiplier = distanceFromRectToMultiplier (rect.top () - pos.y ()); + } + else if (pos.y () > rect.bottom ()) + { + dy = +DragScrollNumPixels; + dyMultiplier = distanceFromRectToMultiplier (pos.y () - rect.bottom ()); + } + +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 0 + kdDebug () << "kpViewScrollableContainer::slotDragScroll()" + << " dx=" << dx << " * " << dxMultiplier + << " dy=" << dy << " * " << dyMultiplier + << " zoomLevel=" << m_zoomLevel + << endl; +#endif + + dx *= dxMultiplier;// * QMAX (1, m_zoomLevel / 100); + dy *= dyMultiplier;// * QMAX (1, m_zoomLevel / 100); + + if (dx || dy) + { + const int oldContentsX = contentsX (), + oldContentsY = contentsY (); + + scrollBy (dx, dy); + + #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 1 + kdDebug () << "\tafter scrollBy():" + << " contentsX=" << contentsX () + << " contentsY=" << contentsY () << endl; + #endif + + scrolled = (oldContentsX != contentsX () || + oldContentsY != contentsY ()); + + if (scrolled) + { + QRegion region = QRect (contentsX (), contentsY (), + visibleWidth (), visibleHeight ()); + region -= QRect (oldContentsX, oldContentsY, + visibleWidth (), visibleHeight ()); + + // Repaint newly exposed region immediately to reduce tearing + // of scrollView. + m_view->repaint (region, false/*no erase*/); + } + } + + + m_dragScrollTimer->changeInterval (DragScrollInterval); + m_scrollTimerRunOnce = true; + + + if (didSomething) + *didSomething = scrolled; + + return scrolled; +} + +// protected virtual [base QScrollView] +void kpViewScrollableContainer::contentsDragMoveEvent (QDragMoveEvent *e) +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpViewScrollableContainer::contentsDragMoveEvent" + << e->pos () + << endl; +#endif + + QScrollView::contentsDragMoveEvent (e); +} + +// protected slot +bool kpViewScrollableContainer::slotDragScroll () +{ + return slotDragScroll (0/*don't want scrolled notification*/); +} + + +// protected virtual [base QScrollView] +void kpViewScrollableContainer::contentsMouseMoveEvent (QMouseEvent *e) +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpViewScrollableContainer::contentsMouseMoveEvent" + << e->pos () + << endl; +#endif + + QScrollView::contentsMouseMoveEvent (e); +} + +// protected virtual [base QScrollView] +void kpViewScrollableContainer::mouseMoveEvent (QMouseEvent *e) +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpViewScrollableContainer::mouseMoveEvent" + << e->pos () + << endl; +#endif + + QScrollView::mouseMoveEvent (e); +} + + +// protected virtual [base QScrollView] +void kpViewScrollableContainer::contentsWheelEvent (QWheelEvent *e) +{ + e->ignore (); + + if (m_view) + m_view->wheelEvent (e); + + if (!e->isAccepted ()) + QScrollView::contentsWheelEvent (e); +} + + +QRect kpViewScrollableContainer::noDragScrollRect () const +{ + return QRect (DragScrollLeftTopMargin, DragScrollLeftTopMargin, + width () - DragScrollLeftTopMargin - DragScrollRightBottomMargin, + height () - DragScrollLeftTopMargin - DragScrollRightBottomMargin); +} + +// protected virtual [base QScrollView] +bool kpViewScrollableContainer::eventFilter (QObject *watchedObject, QEvent *event) +{ + return QScrollView::eventFilter (watchedObject, event); +} + +// protected virtual [base QScrollView] +void kpViewScrollableContainer::viewportPaintEvent (QPaintEvent *e) +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER + kdDebug () << "kpViewScrollableContainer::viewportPaintEvent(" + << e->rect () + << ")" << endl; +#endif + + QScrollView::viewportPaintEvent (e); +} + +// protected virtual [base QFrame] +void kpViewScrollableContainer::paintEvent (QPaintEvent *e) +{ +#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 0 + kdDebug () << "kpViewScrollableContainer::paintEvent(" + << e->rect () + << ")" << endl; +#endif + + QScrollView::paintEvent (e); +} + +// protected virtual [base QScrollView] +void kpViewScrollableContainer::resizeEvent (QResizeEvent *e) +{ + QScrollView::resizeEvent (e); + + emit resized (); +} + + +#include diff --git a/kolourpaint/kpviewscrollablecontainer.h b/kolourpaint/kpviewscrollablecontainer.h new file mode 100644 index 00000000..203bbd1f --- /dev/null +++ b/kolourpaint/kpviewscrollablecontainer.h @@ -0,0 +1,255 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_VIEW_SCROLLABLE_CONTAINER_H +#define KP_VIEW_SCROLLABLE_CONTAINER_H + + +#include +#include +#include + + +class QCursor; +class QRect; +class QTimer; + +class kpGrip; +class kpView; +class kpMainWindow; + + +// TODO: refactor by sharing iface's with kpTool +class kpGrip : public QWidget +{ +Q_OBJECT + +public: + enum GripType + { + Right = 1, Bottom = 2, + BottomRight = Right | Bottom + }; + + kpGrip (GripType type, + QWidget *parent, const char *name = 0); + virtual ~kpGrip (); + + GripType type () const; + + static const QCursor &cursorForType (GripType type); + + QRect hotRect (bool toGlobal = false) const; + + bool isDrawing () const; + +signals: + void beganDraw (); + void continuedDraw (int viewDX, int viewDY, bool dueToDragScroll); + void cancelledDraw (); + void endedDraw (int viewDX, int viewDY); + + void statusMessageChanged (const QString &string); + + void releasedAllButtons (); + +public: + QString haventBegunDrawUserMessage () const; + + QString userMessage () const; + void setUserMessage (const QString &message); + +protected: + void updatePixmap (); + void cancel (); + +protected: + virtual void keyReleaseEvent (QKeyEvent *e); + virtual void mousePressEvent (QMouseEvent *e); +public: + QPoint viewDeltaPoint () const; + void mouseMovedTo (const QPoint &point, bool dueToDragScroll); +protected: + virtual void mouseMoveEvent (QMouseEvent *e); + virtual void mouseReleaseEvent (QMouseEvent *e); + virtual void resizeEvent (QResizeEvent *e); + + virtual void enterEvent (QEvent *e); + virtual void leaveEvent (QEvent *e); + + virtual void paintEvent (QPaintEvent *e); + +protected: + GripType m_type; + QPoint m_startPoint, m_currentPoint; + QString m_userMessage; + bool m_shouldReleaseMouseButtons; +}; + + +class kpViewScrollableContainer : public QScrollView +{ +Q_OBJECT + +public: + kpViewScrollableContainer (kpMainWindow *parent, const char *name = 0); + virtual ~kpViewScrollableContainer (); + + // Same as contentsX() and contentsY() except that after + // contentsMovingSoon() is emitted and before the scrollview actually + // scrolls, they return the would be values of contentsX() and + // contentsY() after scrolling. + int contentsXSoon (); + int contentsYSoon (); + +signals: + // connect to this instead of contentsMoving(int,int) so that + // contentsXSoon() and contentsYSoon() work + void contentsMovingSoon (int contentsX, int contentsY); + + void beganDocResize (); + void continuedDocResize (const QSize &size); + void cancelledDocResize (); + void endedDocResize (const QSize &size); + + // (string.isEmpty() if kpViewScrollableContainer has nothing to say) + void statusMessageChanged (const QString &string); + + void resized (); + +public: + QSize newDocSize () const; + bool haveMovedFromOriginalDocSize () const; + QString statusMessage () const; + void clearStatusMessage (); + +protected: + void connectGripSignals (kpGrip *grip); + + QSize newDocSize (int viewDX, int viewDY) const; + + void calculateDocResizingGrip (); + kpGrip *docResizingGrip () const; + + int bottomResizeLineWidth () const; + int rightResizeLineWidth () const; + + QRect bottomResizeLineRect () const; + QRect rightResizeLineRect () const; + QRect bottomRightResizeLineRect () const; + + QPoint mapViewToViewport (const QPoint &viewPoint); + QRect mapViewToViewport (const QRect &viewRect); + + QRect mapViewportToGlobal (const QRect &viewportRect); + QRect mapViewToGlobal (const QRect &viewRect); + + void repaintWidgetAtResizeLineViewRect (QWidget *widget, + const QRect &resizeLineViewRect); + void repaintWidgetAtResizeLines (QWidget *widget); + void eraseResizeLines (); + + void drawResizeLines (); + + void updateResizeLines (int viewX, int viewY, + int viewDX, int viewDY); + +protected slots: + void slotGripBeganDraw (); + void slotGripContinuedDraw (int viewDX, int viewDY, bool dueToScrollView); + void slotGripCancelledDraw (); + void slotGripEndedDraw (int viewDX, int viewDY); + + void slotGripStatusMessageChanged (const QString &string); + +public slots: + void recalculateStatusMessage (); + +protected slots: + void slotContentsMoving (int x, int y); + void slotContentsMoved (); + +protected: + void disconnectViewSignals (); + void connectViewSignals (); + +public: + // Calls setView() after adding if it's a kpView. + virtual void addChild (QWidget *widget, int x = 0, int y = 0); + + kpView *view () const; + void setView (kpView *view); + +public slots: + void updateGrips (); +protected slots: + void slotViewDestroyed (); + +public slots: + // TODO: Why the QPoint's? + // Why the need for view's zoomLevel? We have the view() anyway. + bool beginDragScroll (const QPoint &, const QPoint &, + int zoomLevel, + bool *didSomething); + bool beginDragScroll (const QPoint &, const QPoint &, + int zoomLevel); + bool endDragScroll (); + +protected slots: + bool slotDragScroll (bool *didSomething); + bool slotDragScroll (); + +protected: + QRect noDragScrollRect () const; + + virtual void contentsDragMoveEvent (QDragMoveEvent *e); + virtual void contentsMouseMoveEvent (QMouseEvent *e); + virtual void contentsWheelEvent (QWheelEvent *e); + virtual void mouseMoveEvent (QMouseEvent *e); + virtual bool eventFilter (QObject *watchedObject, QEvent *e); + virtual void viewportPaintEvent (QPaintEvent *e); + virtual void paintEvent (QPaintEvent *e); + virtual void resizeEvent (QResizeEvent *e); + +protected: + kpMainWindow *m_mainWindow; + int m_contentsXSoon, m_contentsYSoon; + kpView *m_view; + kpGrip *m_bottomGrip, *m_rightGrip, *m_bottomRightGrip; + kpGrip *m_docResizingGrip; + QTimer *m_dragScrollTimer; + int m_zoomLevel; + bool m_scrollTimerRunOnce; + int m_resizeRoundedLastViewX, m_resizeRoundedLastViewY; + int m_resizeRoundedLastViewDX, m_resizeRoundedLastViewDY; + bool m_haveMovedFromOriginalDocSize; + QString m_gripStatusMessage; +}; + + +#endif // KP_VIEW_SCROLLABLE_CONTAINER_H diff --git a/kolourpaint/kpwidgetmapper.cpp b/kolourpaint/kpwidgetmapper.cpp new file mode 100644 index 00000000..beb2624c --- /dev/null +++ b/kolourpaint/kpwidgetmapper.cpp @@ -0,0 +1,76 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include +#include +#include + + +namespace kpWidgetMapper +{ + + +QPoint fromGlobal (const QWidget *widget, const QPoint &point) +{ + if (!widget) + return point; + + return widget->mapFromGlobal (point); +} + +QRect fromGlobal (const QWidget *widget, const QRect &rect) +{ + if (!widget || !rect.isValid ()) + return rect; + + QPoint topLeft = fromGlobal (widget, rect.topLeft ()); + return QRect (topLeft.x (), topLeft.y (), rect.width (), rect.height ()); +} + + +QPoint toGlobal (const QWidget *widget, const QPoint &point) +{ + if (!widget) + return point; + + return widget->mapToGlobal (point); +} + +QRect toGlobal (const QWidget *widget, const QRect &rect) +{ + if (!widget || !rect.isValid ()) + return rect; + + QPoint topLeft = toGlobal (widget, rect.topLeft ()); + return QRect (topLeft.x (), topLeft.y (), rect.width (), rect.height ()); +} + + +} // namespace kpWidgetMapper { diff --git a/kolourpaint/kpwidgetmapper.h b/kolourpaint/kpwidgetmapper.h new file mode 100644 index 00000000..b5c4c412 --- /dev/null +++ b/kolourpaint/kpwidgetmapper.h @@ -0,0 +1,47 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef KP_WIDGET_MAPPER +#define KP_WIDGET_MAPPER + + +class QWidget; +class QPoint; +class QRect; + + +namespace kpWidgetMapper +{ + QPoint fromGlobal (const QWidget *widget, const QPoint &point); + QRect fromGlobal (const QWidget *widget, const QRect &rect); + + QPoint toGlobal (const QWidget *widget, const QPoint &point); + QRect toGlobal (const QWidget *widget, const QRect &rect); +} + + +#endif // KP_WIDGET_MAPPER diff --git a/kolourpaint/patches/checkerboard-faster-render.diff b/kolourpaint/patches/checkerboard-faster-render.diff new file mode 100644 index 00000000..8c9c6402 --- /dev/null +++ b/kolourpaint/patches/checkerboard-faster-render.diff @@ -0,0 +1,141 @@ +At 100% zoom: kpMainWindow::drawTransparentBackground() accounts for +about 75% of kpView::paintEvent()'s time. Bottleneck is +QPainter::fillRect(). QPainter::drawPixmap() seems much faster. For +800x600, renderer goes from 10ms to 1ms. + +--- kpmainwindow.cpp 2004-08-05 02:10:38.000000000 +1000 ++++ kpmainwindow.cpp 2004-09-29 11:24:45.000000000 +1000 +@@ -838,12 +838,116 @@ + } + + ++#if 1 ++// (indexed by [isPreview][parity]) ++static QPixmap *checkerBoardCache [2][2] = {{0, 0}, {0, 0}}; ++ ++ ++static int checkerBoardCellSize (bool isPreview) ++{ ++ return !isPreview ? 16 : 10; ++} ++ ++ ++// public ++static QPixmap *createCheckerBoardCache (bool isPreview, bool parity) ++{ ++ int cellSize = checkerBoardCellSize (isPreview); ++ const int rep = 2; // must be multiple of 2 ++ ++ QPixmap *newPixmap = new QPixmap (cellSize * rep, cellSize * rep); ++ QPainter painter (newPixmap); ++ ++ int parityAsInt = parity ? 1 : 0; ++ for (int y = 0; y < rep; y++) ++ { ++ for (int x = 0; x < rep; x++) ++ { ++ QColor col; ++ ++ if ((parityAsInt + x + y) % 2) ++ { ++ if (!isPreview) ++ col = QColor (213, 213, 213); ++ else ++ col = QColor (224, 224, 224); ++ } ++ else ++ col = Qt::white; ++ ++ painter.fillRect (x * cellSize, y * cellSize, ++ cellSize, cellSize, ++ col); ++ } ++ } ++ ++ painter.end (); ++ return newPixmap; ++} ++ ++void kpMainWindow::drawTransparentBackground (QPainter *painter, ++ int /*viewWidth*/, int /*viewHeight*/, ++ const QRect &rect, ++ bool isPreview) ++{ ++#if DEBUG_KP_MAIN_WINDOW && 1 || 1 ++ kdDebug () << "\tkpMainWindow::drawTransparentBackground(rect=" ++ << rect << ")" << endl; ++ QTime totalTimer; totalTimer.start (); ++#endif ++ ++ int cellSize = checkerBoardCellSize (isPreview); ++ ++ ++ int starty = rect.y (); ++ if (starty % cellSize) ++ starty -= (starty % cellSize); ++ ++ int startx = rect.x (); ++ if (startx % cellSize) ++ startx -= (startx % cellSize); ++ ++ ++ int parity = ((startx / cellSize + starty / cellSize) % 2) ? 1 : 0; ++ ++ if (!checkerBoardCache [isPreview][parity]) ++ { ++ checkerBoardCache [isPreview][parity] = createCheckerBoardCache (isPreview, parity); ++ } ++ ++ QPixmap *tilePixmap = checkerBoardCache [isPreview][parity]; ++ for (int y = starty; y <= rect.bottom (); y += tilePixmap->height ()) ++ { ++ for (int x = startx; x <= rect.right (); x += tilePixmap->width ()) ++ { ++ painter->drawPixmap (x - rect.x (), y - rect.y (), *tilePixmap); ++ } ++ } ++ ++#if DEBUG_KP_MAIN_WINDOW && 1 || 1 ++{ ++ const int totalTimerElapsed = totalTimer.elapsed (); ++ kdDebug () << "\t\ttotal=" << totalTimerElapsed << endl; ++} ++#endif ++} ++ ++ ++#else ++ + // public + void kpMainWindow::drawTransparentBackground (QPainter *painter, + int /*viewWidth*/, int /*viewHeight*/, + const QRect &rect, + bool isPreview) + { ++#if DEBUG_KP_MAIN_WINDOW && 1 ++ kdDebug () << "\tkpMainWindow::drawTransparentBackground(rect=" ++ << rect << ")" << endl; ++ QTime totalTimer; totalTimer.start (); ++#endif ++ ++ + const int cellSize = !isPreview ? 16 : 10; + + int starty = rect.y (); +@@ -877,8 +982,15 @@ + } + } + painter->restore (); +-} + ++#if DEBUG_KP_MAIN_WINDOW && 1 || 1 ++{ ++ const int totalTimerElapsed = totalTimer.elapsed (); ++ kdDebug () << "\t\ttotal=" << totalTimerElapsed << endl; ++} ++#endif ++} ++#endif + + // private slot + void kpMainWindow::slotUpdateCaption () diff --git a/kolourpaint/patches/color_eraser_speedup.diff b/kolourpaint/patches/color_eraser_speedup.diff new file mode 100644 index 00000000..5e1ff7b7 --- /dev/null +++ b/kolourpaint/patches/color_eraser_speedup.diff @@ -0,0 +1,264 @@ +[probably no longer applies without modification] + +Attempts to improve the performance of the Color Eraser & Eraser +by drawing only _unique_ rectangles across interpolation lines +and by not drawing pixmaps when the user has a solid rectangular +brush. + +- appears to decrease the performance of the Eraser (QRegion + overhead?). +- reduces code clarity +- unsure of whether it increases performance of Color Eraser + (sometimes it seems faster, sometimes not) + +Index: tools/kptoolpen.cpp +=================================================================== +RCS file: /home/kde/kdenonbeta/kolourpaint/tools/kptoolpen.cpp,v +retrieving revision 1.9 +diff -u -p -r1.9 kptoolpen.cpp +--- tools/kptoolpen.cpp 6 Dec 2003 06:53:36 -0000 1.9 ++++ tools/kptoolpen.cpp 6 Dec 2003 06:55:46 -0000 +@@ -34,12 +34,13 @@ + #include + #include + #include +-#include +-#include +-#include + #if DEBUG_KP_TOOL_PEN + #include + #endif ++#include ++#include ++#include ++#include + + #include + #include +@@ -416,31 +417,28 @@ void kpToolPen::draw (const QPoint &this + rect = neededRect (rect, m_brushPixmap [m_mouseButton].width ()); + + #if DEBUG_KP_TOOL_PEN +- if (m_mode & WashesPixmaps) +- { +- kdDebug () << "Washing pixmap (w=" << rect.width () +- << ",h=" << rect.height () << ")" << endl; +- } ++ kdDebug () << "kpToolPen::draw() interpolate: area (w=" << rect.width () ++ << ",h=" << rect.height () << ")" << endl; + QTime timer; + int convAndWashTime; + #endif + +- QPixmap pixmap = document ()->getPixmapAt (rect); +- QPainter painter (&pixmap); ++ // optimsation - only render intersections of rectangles once ++ bool delayedDraw = ((m_mode & SquareBrushes) && ++ ((m_mode & WashesPixmaps) || ++ (m_mode == Eraser)/*solid rectangular brush*/)); ++ ++ ++ QPixmap pixmap; ++ QPainter painter; ++ pixmap = document ()->getPixmapAt (rect); ++ painter.begin (&pixmap); + painter.setPen (color (m_mouseButton)); + +- QImage image; +- if (m_mode & WashesPixmaps) +- { + #if DEBUG_KP_TOOL_PEN ++ if (m_mode & WashesPixmaps) + timer.start (); + #endif +- image = pixmap.convertToImage (); +- #if DEBUG_KP_TOOL_PEN +- convAndWashTime = timer.restart (); +- kdDebug () << "\tconvert to image: " << convAndWashTime << " ms" << endl; +- #endif +- } + + bool didSomething = false; + +@@ -453,10 +451,21 @@ void kpToolPen::draw (const QPoint &this + else if (m_mode & (DrawsPixmaps | WashesPixmaps)) + { + QRgb colorToReplace; ++ QImage image; ++ QRegion region; + + if (m_mode & WashesPixmaps) ++ { + colorToReplace = color (1 - m_mouseButton).rgb (); + ++ image = pixmap.convertToImage (); ++ ++ #if DEBUG_KP_TOOL_PEN ++ convAndWashTime = timer.restart (); ++ kdDebug () << "\tconvert to image: " << convAndWashTime << " ms" << endl; ++ #endif ++ } ++ + // Sweeps a pixmap along a line (modified Bresenham's line algorithm, + // see MODIFIED comment below). + // +@@ -485,19 +494,27 @@ void kpToolPen::draw (const QPoint &this + int x = 0; + int y = 0; + +- if (m_mode & WashesPixmaps) ++ if (delayedDraw) + { +- if (wash (&painter, image, +- colorToReplace, +- rect, plotx + rect.left (), ploty + rect.top ())) +- { +- didSomething = true; +- } ++ region = region.unite (hotRect (plotx + rect.left (), ploty + rect.top ())); + } + else + { +- painter.drawPixmap (hotPoint (plotx, ploty), m_brushPixmap [m_mouseButton]); +- didSomething = true; ++ if (m_mode & WashesPixmaps) ++ { ++ if (wash (&painter, image, ++ colorToReplace, ++ rect, plotx + rect.left (), ploty + rect.top ())) ++ { ++ didSomething = true; ++ } ++ } ++ else ++ { ++ painter.drawPixmap (hotPoint (plotx, ploty), ++ m_brushPixmap [m_mouseButton]); ++ didSomething = true; ++ } + } + + for (int i = 0; i <= inc; i++) +@@ -541,39 +558,115 @@ void kpToolPen::draw (const QPoint &this + // is more than 1 point, of course). This is in contrast to the + // ordinary line algorithm which can create diagonal adjacencies. + ++ if (delayedDraw) ++ { ++ region = region.unite (hotRect (plotx + rect.left (), oldploty + rect.top ())); ++ } ++ else ++ { ++ if (m_mode & WashesPixmaps) ++ { ++ if (wash (&painter, image, ++ colorToReplace, ++ rect, plotx + rect.left (), oldploty + rect.top ())) ++ { ++ didSomething = true; ++ } ++ } ++ else ++ { ++ painter.drawPixmap (hotPoint (plotx, oldploty), ++ m_brushPixmap [m_mouseButton]); ++ didSomething = true; ++ } ++ } ++ } ++ ++ if (delayedDraw) ++ { ++ region = region.unite (hotRect (plotx + rect.left (), ploty + rect.top ())); ++ } ++ else ++ { + if (m_mode & WashesPixmaps) + { + if (wash (&painter, image, + colorToReplace, +- rect, plotx + rect.left (), oldploty + rect.top ())) ++ rect, plotx + rect.left (), ploty + rect.top ())) + { + didSomething = true; + } + } + else + { +- painter.drawPixmap (hotPoint (plotx, oldploty), m_brushPixmap [m_mouseButton]); ++ painter.drawPixmap (hotPoint (plotx, ploty), ++ m_brushPixmap [m_mouseButton]); + didSomething = true; + } + } +- ++ } ++ } ++ ++ if (delayedDraw) ++ { ++ QMemArray rects = region.rects (); ++ ++ int numRects = rects.count (); ++ #if DEBUG_KP_TOOL_PEN ++ kdDebug () << "\tdelayed draw now happening: numRects=" ++ << numRects << endl; ++ int convImageMS = 0; ++ int washMS = 0; ++ int setDocMS = 0; ++ QTime timer; ++ #endif ++ for (int i = 0; i < numRects; i++) ++ { ++ QRect r = rects [i]; ++ QPixmap pm = document ()->getPixmapAt (r); ++ #if DEBUG_KP_TOOL_PEN && 0 ++ kdDebug () << "\tr=" << r << endl; ++ #endif ++ ++ bool drew = false; ++ + if (m_mode & WashesPixmaps) + { ++ timer.start (); ++ + if (wash (&painter, image, + colorToReplace, +- rect, plotx + rect.left (), ploty + rect.top ())) ++ rect, r)) + { +- didSomething = true; ++ drew = true; + } ++ washMS += timer.restart (); + } + else + { +- painter.drawPixmap (hotPoint (plotx, ploty), m_brushPixmap [m_mouseButton]); ++ painter.setBrush (color (m_mouseButton)); ++ painter.drawRect (r.x () - rect.x (), ++ r.y () - rect.y (), ++ r.width (), ++ r.height ()); ++ drew = true; ++ } ++ ++ if (drew) ++ { ++ m_currentCommand->updateBoundingRect (r); + didSomething = true; ++ setDocMS += timer.restart (); + } + } ++ ++ #if DEBUG_KP_TOOL_PEN ++ kdDebug () << "convImageMS=" << convImageMS ++ << " washMS=" << washMS ++ << " setDocMS=" << setDocMS ++ << endl; ++ #endif + } +- + } + + painter.end (); diff --git a/kolourpaint/patches/doc_resize_no_flicker.diff b/kolourpaint/patches/doc_resize_no_flicker.diff new file mode 100644 index 00000000..ae5f9aba --- /dev/null +++ b/kolourpaint/patches/doc_resize_no_flicker.diff @@ -0,0 +1,614 @@ +Eliminates flicker when moving document resize lines / dragging resize +handles by: + +1. Not erasing areas that will be subsequently painted over with resize + lines. +2. Erasing the old areas and painting the new ones atomicly by using + clever NOT'ing of pixels. + +Additionally, recover the resize lines after a window pops up momentarily +over KolourPaint (kpViewScrollableContainer::windowActivationChange()). + +Critical bugs with this code and scrollbars: + +1. Drag scrolling leaves trails of resize lines. +2. Moving the mouse cursor above the start of the document does not result + in a resize line at document y = 1. + +Because I'm still debugging, there are a few hacks in the code such as +"m_resizeLinesDontPaintClever". + +Index: kpviewscrollablecontainer.cpp +=================================================================== +RCS file: /home/kde/kdegraphics/kolourpaint/kpviewscrollablecontainer.cpp,v +retrieving revision 1.7 +diff -u -p -r1.7 kpviewscrollablecontainer.cpp +--- kpviewscrollablecontainer.cpp 29 Jul 2004 12:47:15 -0000 1.7 ++++ kpviewscrollablecontainer.cpp 30 Jul 2004 11:37:20 -0000 +@@ -1,4 +1,4 @@ +- ++static bool inScroll = false; + /* + Copyright (c) 2003-2004 Clarence Dang + All rights reserved. +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -240,7 +241,7 @@ void kpGrip::mousePressEvent (QMouseEven + m_startPoint = e->pos (); + m_currentPoint = e->pos (); + emit beganDraw (); +- grabKeyboard (); ++ //grabKeyboard (); HACK + + setUserMessage (i18n ("Resize Image: Right click to cancel.")); + setCursor (cursorForType (m_type)); +@@ -387,6 +388,7 @@ kpViewScrollableContainer::kpViewScrolla + m_scrollTimerRunOnce (false), + m_resizeRoundedLastViewX (-1), m_resizeRoundedLastViewY (-1), + m_resizeRoundedLastViewDX (0), m_resizeRoundedLastViewDY (0), ++ m_resizeLinesDontPaintClever (0), + m_haveMovedFromOriginalDocSize (false) + + { +@@ -561,6 +563,18 @@ QRect kpViewScrollableContainer::bottomR + m_resizeRoundedLastViewY + bottomResizeLineWidth () - 1)); + } + ++// protected ++QRegion kpViewScrollableContainer::resizeLinesRegion () const ++{ ++ QRegion ret; ++ ++ ret += rightResizeLineRect (); ++ ret += bottomResizeLineRect (); ++ ret += bottomRightResizeLineRect (); ++ ++ return ret; ++} ++ + + // TODO: are these 2 correct? Remember that viewport()->x() == 1, viewport()->y() == 1 + +@@ -581,6 +595,17 @@ QRect kpViewScrollableContainer::mapView + return ret; + } + ++// protected ++QRegion kpViewScrollableContainer::mapViewToViewport (const QRegion &viewRegion) ++{ ++ if (viewRegion.isEmpty ()) ++ return viewRegion; ++ ++ QRegion ret = viewRegion; ++ ret.translate (-contentsX (), -contentsY ()); ++ return ret; ++} ++ + + // protected + QRect kpViewScrollableContainer::mapViewportToGlobal (const QRect &viewportRect) +@@ -589,89 +614,108 @@ QRect kpViewScrollableContainer::mapView + } + + // protected ++QRegion kpViewScrollableContainer::mapViewportToGlobal (const QRegion &viewportRegion) ++{ ++ return kpWidgetMapper::toGlobal (viewport (), viewportRegion); ++} ++ ++ ++// protected + QRect kpViewScrollableContainer::mapViewToGlobal (const QRect &viewRect) + { + return mapViewportToGlobal (mapViewToViewport (viewRect)); + } + ++// protected ++QRegion kpViewScrollableContainer::mapViewToGlobal (const QRegion &viewRegion) ++{ ++ return mapViewportToGlobal (mapViewToViewport (viewRegion)); ++} ++ + + // protected +-void kpViewScrollableContainer::repaintWidgetAtResizeLineViewRect ( +- QWidget *widget, const QRect &resizeLineViewRect) ++void kpViewScrollableContainer::repaintWidgetRegion ( ++ QWidget *widget, ++ const QRegion &viewRegion) + { +- const QRect resizeLineGlobalRect = mapViewToGlobal (resizeLineViewRect); ++ const QRegion globalRegion = mapViewToGlobal (viewRegion); ++ + const QRect widgetGlobalRect = kpWidgetMapper::toGlobal (widget, + widget->rect ()); + +- const QRect redrawGlobalRect = +- resizeLineGlobalRect.intersect (widgetGlobalRect); + +- const QRect redrawWidgetRect = +- kpWidgetMapper::fromGlobal (widget, redrawGlobalRect); ++ const QRegion redrawGlobalRegion = ++ globalRegion.intersect (widgetGlobalRect); + ++ const QRegion redrawWidgetRegion = ++ kpWidgetMapper::fromGlobal (widget, redrawGlobalRegion); + +- if (redrawWidgetRect.isValid ()) ++ ++ if (!redrawWidgetRegion.isEmpty ()) + { + // TODO: should be "!widget->testWFlags (Qt::WRepaintNoErase)" + // but for some reason, doesn't work for viewport(). + const bool erase = !dynamic_cast (widget); +- widget->repaint (redrawWidgetRect, erase); ++ widget->repaint (redrawWidgetRegion, erase); + } + } + + // protected +-void kpViewScrollableContainer::repaintWidgetAtResizeLines (QWidget *widget) ++void kpViewScrollableContainer::eraseResizeLines (const QRegion &viewRegion) + { +- repaintWidgetAtResizeLineViewRect (widget, rightResizeLineRect ()); +- repaintWidgetAtResizeLineViewRect (widget, bottomResizeLineRect ()); +- repaintWidgetAtResizeLineViewRect (widget, bottomRightResizeLineRect ()); +-} ++ if (viewRegion.isEmpty ()) ++ return; + +-// protected +-void kpViewScrollableContainer::eraseResizeLines () +-{ +- if (m_resizeRoundedLastViewX >= 0 && m_resizeRoundedLastViewY >= 0) +- { +- repaintWidgetAtResizeLines (viewport ()); +- repaintWidgetAtResizeLines (m_view); + +- repaintWidgetAtResizeLines (m_bottomGrip); +- repaintWidgetAtResizeLines (m_rightGrip); +- repaintWidgetAtResizeLines (m_bottomRightGrip); +- } ++ repaintWidgetRegion (viewport (), viewRegion); ++ repaintWidgetRegion (m_view, viewRegion); ++ ++ repaintWidgetRegion (m_bottomGrip, viewRegion); ++ repaintWidgetRegion (m_rightGrip, viewRegion); ++ repaintWidgetRegion (m_bottomRightGrip, viewRegion); + } + + + // protected +-void kpViewScrollableContainer::drawResizeLines () ++void kpViewScrollableContainer::drawResizeLines (const QRegion &viewRegion) + { + #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER +- kdDebug () << "kpViewScrollableContainer::drawResizeLines()" ++ kdDebug () << "kpViewScrollableContainer::drawResizeLines(" ++ << viewRegion <<")" + << " lastViewX=" << m_resizeRoundedLastViewX + << " lastViewY=" << m_resizeRoundedLastViewY + << endl; + #endif + ++ if (viewRegion.isEmpty ()) ++ return; ++ + + QPainter p (viewport (), true/*unclipped*/); + p.setRasterOp (Qt::NotROP); + +- const QRect rightRect = rightResizeLineRect (); +- if (rightRect.isValid ()) +- p.fillRect (mapViewToViewport (rightRect), Qt::white); +- +- const QRect bottomRect = bottomResizeLineRect (); +- if (bottomRect.isValid ()) +- p.fillRect (mapViewToViewport (bottomRect), Qt::white); +- +- const QRect bottomRightRect = bottomRightResizeLineRect (); +- if (bottomRightRect.isValid ()) +- p.fillRect (mapViewToViewport (bottomRightRect), Qt::white); ++ const QMemArray rects = mapViewToViewport (viewRegion).rects (); ++ for (QMemArray ::ConstIterator it = rects.begin (); ++ it != rects.end (); ++ it++) ++ { ++ p.fillRect (*it, Qt::white); ++ } + + p.end (); + } + + ++template ++static inline void swap (T &a, T &b) ++{ ++ T temp = a; ++ ++ a = b; ++ b = temp; ++} ++ ++ + // protected + void kpViewScrollableContainer::updateResizeLines (int viewX, int viewY, + int viewDX, int viewDY) +@@ -686,36 +730,71 @@ void kpViewScrollableContainer::updateRe + << endl; + #endif + +- eraseResizeLines (); +- ++ int newResizeRoundedLastViewX = -1, ++ newResizeRoundedLastViewY = -1; ++ int newResizeRoundedLastViewDX = 0, ++ newResizeRoundedLastViewDY = 0; + + if (viewX >= 0 && viewY >= 0) + { +- m_resizeRoundedLastViewX = m_view->zoomDocToViewX (m_view->zoomViewToDocX (viewX)); +- m_resizeRoundedLastViewY = m_view->zoomDocToViewY (m_view->zoomViewToDocY (viewY)); ++ newResizeRoundedLastViewX = m_view->zoomDocToViewX (m_view->zoomViewToDocX (viewX)); ++ newResizeRoundedLastViewY = m_view->zoomDocToViewY (m_view->zoomViewToDocY (viewY)); + +- m_resizeRoundedLastViewDX = viewDX; +- m_resizeRoundedLastViewDY = viewDY; ++ newResizeRoundedLastViewDX = viewDX; ++ newResizeRoundedLastViewDY = viewDY; + } +- else +- { +- m_resizeRoundedLastViewX = -1; +- m_resizeRoundedLastViewY = -1; + +- m_resizeRoundedLastViewDX = 0; +- m_resizeRoundedLastViewDY = 0; +- } + +- // TODO: This is suboptimal since if another window pops up on top of +- // KolourPaint then disappears, the lines are not redrawn +- // (although this doesn't happen very frequently since we grab the +- // keyboard and mouse when resizing): +- // +- // e.g. sleep 5 && gedit & sleep 10 && killall gedit ++ QRegion oldLinesRegion = resizeLinesRegion (); ++#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER ++ kdDebug () << "\toldLinesRegion=" << oldLinesRegion << endl; ++#endif ++ ++ ++// (macro instead of writing out code to permit experimentation) ++#define SWAP_LAST_VIEW_STATS() \ ++{ \ ++ swap (m_resizeRoundedLastViewX, newResizeRoundedLastViewX); \ ++ swap (m_resizeRoundedLastViewY, newResizeRoundedLastViewY); \ ++ \ ++ swap (m_resizeRoundedLastViewDX, newResizeRoundedLastViewDX); \ ++ swap (m_resizeRoundedLastViewDY, newResizeRoundedLastViewDY); \ ++} ++ SWAP_LAST_VIEW_STATS (); ++#undef SWAP_LAST_VIEW_STATS ++ ++ ++ QRegion newLinesRegion = resizeLinesRegion (); ++#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER ++ kdDebug () << "\tnewLinesRegion=" << newLinesRegion << endl; ++#endif ++ ++ ++ // TODO: This is suboptimal - we will get redraw errors sooner or later. ++ // But I've tried hard to avoid them (e.g. windowActivationChange()). + // + // Should be done in the paintEvent's of every child of the + // scrollview. +- drawResizeLines (); ++ ++ if (m_resizeLinesDontPaintClever) ++ { ++ // (drawResizeLines() NOT's the pixels - so we can erase old and draw ++ // new at the same time) ++ drawResizeLines (newLinesRegion.eor (oldLinesRegion)); ++ #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER ++ kdDebug () << "\tNOTRregion=" ++ << newLinesRegion.eor (oldLinesRegion) << endl; ++ #endif ++ } ++ else ++ { ++ eraseResizeLines (oldLinesRegion); ++ drawResizeLines (newLinesRegion); ++ #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER ++ kdDebug () << "\tnot erasing old lines; NOTRregion=" ++ << newLinesRegion << endl; ++ #endif ++ } + } + + +@@ -729,6 +808,8 @@ void kpViewScrollableContainer::slotGrip + + m_haveMovedFromOriginalDocSize = false; + ++ m_resizeLinesDontPaintClever = true; ++ + updateResizeLines (m_view->width (), m_view->height (), + 0/*viewDX*/, 0/*viewDY*/); + +@@ -750,12 +831,28 @@ void kpViewScrollableContainer::slotGrip + + m_haveMovedFromOriginalDocSize = true; + ++#if 0 ++ if (inScroll != !m_resizeLinesNeedErase) ++ { ++ kdError () << "slotGripContDraw EXCEPTION 0: inScroll=" << inScroll << endl; ++ memset (0, 42, 1048576); ++ } ++#endif ++ + updateResizeLines (QMAX (1, QMAX (m_view->width () + viewDX, m_view->zoomDocToViewX (1))), + QMAX (1, QMAX (m_view->height () + viewDY, m_view->zoomDocToViewY (1))), + viewDX, viewDY); + + emit continuedDocResize (newDocSize ()); + ++#if 0 ++ if (!m_resizeLinesNeedErase) ++ { ++ kdError () << "slotGripContDraw EXCEPTION 1" << endl; ++ memset (0, 42, 1048576); ++ } ++#endif ++ + beginDragScroll (QPoint (), QPoint (), m_view->zoomLevelX ()); + } + +@@ -859,8 +956,19 @@ void kpViewScrollableContainer::slotCont + << x << "," << y << ")" << endl; + #endif + ++ m_resizeLinesDontPaintClever++; ++ ++ if (inScroll && 0) ++ { ++ kdError () << "slotContentsMovING EXCEPTION" << endl; ++ memset (0, 42, 1048576); ++ } ++ ++ inScroll = true; + // Reduce flicker - don't let QScrollView scroll to-be-erased lines +- eraseResizeLines (); ++ //eraseResizeLines (resizeLinesRegion ()); ++ //m_resizeLinesNeedErase = false; ++ + + QTimer::singleShot (0, this, SLOT (slotContentsMoved ())); + } +@@ -874,9 +982,27 @@ void kpViewScrollableContainer::slotCont + << " grip=" << grip << endl; + #endif + if (!grip) ++ { ++ inScroll = false; + return; ++ } + ++ if (!inScroll && 0) ++ { ++ kdError () << "slotContentsMoved EXCEPTION" << endl; ++ memset (0, 42, 1048576); ++ } + grip->mouseMovedTo (grip->mapFromGlobal (QCursor::pos ())); ++#if 0 ++ if (!m_resizeLinesNeedErase) ++ { ++ kdError () << "slotContentsMoved EXCEPTION 2" << endl; ++ memset (0, 42, 1048576); ++ } ++#endif ++ inScroll = false; ++ ++ m_resizeLinesDontPaintClever--; + } + + +@@ -1191,7 +1317,7 @@ bool kpViewScrollableContainer::eventFil + // protected virtual [base QScrollView] + void kpViewScrollableContainer::viewportPaintEvent (QPaintEvent *e) + { +-#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER ++#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 0 + kdDebug () << "kpViewScrollableContainer::viewportPaintEvent(" + << e->rect () + << ")" << endl; +@@ -1213,4 +1339,42 @@ void kpViewScrollableContainer::paintEve + } + + ++// protected slot ++void kpViewScrollableContainer::windowActivationChanged () ++{ ++ if (isActiveWindow () && ++ m_resizeRoundedLastViewX >= 0 && m_resizeRoundedLastViewY >= 0) ++ { ++ // We were obscured by a window that popped up monmentarily and ++ // this clobbered the resize lines (since the scrollView's child ++ // widgets don't draw them). This doesn't happen very frequently ++ // since we grab the keyboard and mouse when resizing but: ++ // ++ // e.g. sleep 5 && gedit & sleep 10 && killall gedit ++ // ++ ++ // Repaint child widgets at the resize lines to make sure any ++ // remains of the resize lines are gone. ++ eraseResizeLines (resizeLinesRegion ()); ++ ++ // Draw the resize lines by NOT-ing the child widget pixels. ++ drawResizeLines (resizeLinesRegion ()); ++ } ++} ++ ++// protected virtual [base QWidget] ++void kpViewScrollableContainer::windowActivationChange (bool wasActive) ++{ ++#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 1 ++ kdDebug () << "kpViewScrollableContainer::windowActivationChange(" ++ << wasActive << ")" << endl; ++#endif ++ ++ QScrollView::windowActivationChange (wasActive); ++ ++ // Wait for m_view to update ++ QTimer::singleShot (0, this, SLOT (windowActivationChanged ())); ++} ++ ++ + #include +Index: kpviewscrollablecontainer.h +=================================================================== +RCS file: /home/kde/kdegraphics/kolourpaint/kpviewscrollablecontainer.h,v +retrieving revision 1.3 +diff -u -p -r1.3 kpviewscrollablecontainer.h +--- kpviewscrollablecontainer.h 19 Jul 2004 05:00:47 -0000 1.3 ++++ kpviewscrollablecontainer.h 30 Jul 2004 11:37:21 -0000 +@@ -31,6 +31,7 @@ + + + #include ++#include + #include + #include + +@@ -147,19 +148,23 @@ protected: + QRect bottomResizeLineRect () const; + QRect rightResizeLineRect () const; + QRect bottomRightResizeLineRect () const; ++ QRegion resizeLinesRegion () const; + + QPoint mapViewToViewport (const QPoint &viewPoint); + QRect mapViewToViewport (const QRect &viewRect); ++ QRegion mapViewToViewport (const QRegion &viewRegion); + + QRect mapViewportToGlobal (const QRect &viewportRect); ++ QRegion mapViewportToGlobal (const QRegion &viewportRegion); ++ + QRect mapViewToGlobal (const QRect &viewRect); ++ QRegion mapViewToGlobal (const QRegion &viewRegion); + +- void repaintWidgetAtResizeLineViewRect (QWidget *widget, +- const QRect &resizeLineViewRect); +- void repaintWidgetAtResizeLines (QWidget *widget); +- void eraseResizeLines (); ++ void repaintWidgetRegion (QWidget *widget, ++ const QRegion &viewRegion); ++ void eraseResizeLines (const QRegion &viewRegion); + +- void drawResizeLines (); ++ void drawResizeLines (const QRegion &viewRegion); + + void updateResizeLines (int viewX, int viewY, + int viewDX, int viewDY); +@@ -213,6 +218,12 @@ protected: + virtual void viewportPaintEvent (QPaintEvent *e); + virtual void paintEvent (QPaintEvent *e); + ++protected slots: ++ void windowActivationChanged (); ++protected: ++ virtual void windowActivationChange (bool wasActive); ++ ++ + protected: + kpMainWindow *m_mainWindow; + kpView *m_view; +@@ -223,6 +234,7 @@ protected: + bool m_scrollTimerRunOnce; + int m_resizeRoundedLastViewX, m_resizeRoundedLastViewY; + int m_resizeRoundedLastViewDX, m_resizeRoundedLastViewDY; ++ int m_resizeLinesDontPaintClever; + bool m_haveMovedFromOriginalDocSize; + QString m_gripStatusMessage; + }; +Index: kpwidgetmapper.cpp +=================================================================== +RCS file: /home/kde/kdegraphics/kolourpaint/kpwidgetmapper.cpp,v +retrieving revision 1.1 +diff -u -p -r1.1 kpwidgetmapper.cpp +--- kpwidgetmapper.cpp 10 Jul 2004 11:38:09 -0000 1.1 ++++ kpwidgetmapper.cpp 30 Jul 2004 11:37:21 -0000 +@@ -30,6 +30,7 @@ + + #include + #include ++#include + #include + + +@@ -54,6 +55,17 @@ QRect fromGlobal (const QWidget *widget, + return QRect (topLeft.x (), topLeft.y (), rect.width (), rect.height ()); + } + ++QRegion fromGlobal (const QWidget *widget, const QRegion ®ion) ++{ ++ if (!widget || region.isEmpty ()) ++ return region; ++ ++ const QPoint widgetGlobalTopLeft = toGlobal (widget, QPoint (0, 0)); ++ QRegion ret = region; ++ ret.translate (-widgetGlobalTopLeft.x (), -widgetGlobalTopLeft.y ()); ++ return ret; ++} ++ + + QPoint toGlobal (const QWidget *widget, const QPoint &point) + { +@@ -72,5 +84,16 @@ QRect toGlobal (const QWidget *widget, c + return QRect (topLeft.x (), topLeft.y (), rect.width (), rect.height ()); + } + ++QRegion toGlobal (const QWidget *widget, const QRegion ®ion) ++{ ++ if (!widget || region.isEmpty ()) ++ return region; ++ ++ const QPoint widgetGlobalTopLeft = toGlobal (widget, QPoint (0, 0)); ++ QRegion ret = region; ++ ret.translate (widgetGlobalTopLeft.x (), widgetGlobalTopLeft.y ()); ++ return ret; ++} ++ + + } // namespace kpWidgetMapper { +Index: kpwidgetmapper.h +=================================================================== +RCS file: /home/kde/kdegraphics/kolourpaint/kpwidgetmapper.h,v +retrieving revision 1.1 +diff -u -p -r1.1 kpwidgetmapper.h +--- kpwidgetmapper.h 10 Jul 2004 11:38:09 -0000 1.1 ++++ kpwidgetmapper.h 30 Jul 2004 11:37:21 -0000 +@@ -32,15 +32,18 @@ + class QWidget; + class QPoint; + class QRect; ++class QRegion; + + + namespace kpWidgetMapper + { + QPoint fromGlobal (const QWidget *widget, const QPoint &point); + QRect fromGlobal (const QWidget *widget, const QRect &rect); ++ QRegion fromGlobal (const QWidget *widget, const QRegion ®ion); + + QPoint toGlobal (const QWidget *widget, const QPoint &point); + QRect toGlobal (const QWidget *widget, const QRect &rect); ++ QRegion toGlobal (const QWidget *widget, const QRegion ®ion); + } + + diff --git a/kolourpaint/pics/Makefile.am b/kolourpaint/pics/Makefile.am new file mode 100644 index 00000000..2e4aed53 --- /dev/null +++ b/kolourpaint/pics/Makefile.am @@ -0,0 +1,13 @@ +SUBDIRS = custom + +KDE_ICON = kolourpaint + +actionicondir = $(kde_datadir)/kolourpaint/icons +actionicon_ICON = AUTO + +# Change the following line every time you add an icon +# to force Makefile regeneration: +# +# 4 +# + diff --git a/kolourpaint/pics/cr16-action-tool_brush.png b/kolourpaint/pics/cr16-action-tool_brush.png new file mode 100644 index 00000000..32a23881 Binary files /dev/null and b/kolourpaint/pics/cr16-action-tool_brush.png differ diff --git a/kolourpaint/pics/cr16-action-tool_color_picker.png b/kolourpaint/pics/cr16-action-tool_color_picker.png new file mode 100644 index 00000000..569171e6 Binary files /dev/null and b/kolourpaint/pics/cr16-action-tool_color_picker.png differ diff --git a/kolourpaint/pics/cr16-action-tool_color_washer.png b/kolourpaint/pics/cr16-action-tool_color_washer.png new file mode 100644 index 00000000..97193458 Binary files /dev/null and b/kolourpaint/pics/cr16-action-tool_color_washer.png differ diff --git a/kolourpaint/pics/cr16-action-tool_curve.png b/kolourpaint/pics/cr16-action-tool_curve.png new file mode 100644 index 00000000..b86c96fb Binary files /dev/null and b/kolourpaint/pics/cr16-action-tool_curve.png differ diff --git a/kolourpaint/pics/cr16-action-tool_ellipse.png b/kolourpaint/pics/cr16-action-tool_ellipse.png new file mode 100644 index 00000000..608d40b7 Binary files /dev/null and b/kolourpaint/pics/cr16-action-tool_ellipse.png differ diff --git a/kolourpaint/pics/cr16-action-tool_elliptical_selection.png b/kolourpaint/pics/cr16-action-tool_elliptical_selection.png new file mode 100644 index 00000000..70edc438 Binary files /dev/null and b/kolourpaint/pics/cr16-action-tool_elliptical_selection.png differ diff --git a/kolourpaint/pics/cr16-action-tool_eraser.png b/kolourpaint/pics/cr16-action-tool_eraser.png new file mode 100644 index 00000000..459d28a2 Binary files /dev/null and b/kolourpaint/pics/cr16-action-tool_eraser.png differ diff --git a/kolourpaint/pics/cr16-action-tool_flood_fill.png b/kolourpaint/pics/cr16-action-tool_flood_fill.png new file mode 100644 index 00000000..746ede5b Binary files /dev/null and b/kolourpaint/pics/cr16-action-tool_flood_fill.png differ diff --git a/kolourpaint/pics/cr16-action-tool_free_form_selection.png b/kolourpaint/pics/cr16-action-tool_free_form_selection.png new file mode 100644 index 00000000..ed03ba39 Binary files /dev/null and b/kolourpaint/pics/cr16-action-tool_free_form_selection.png differ diff --git a/kolourpaint/pics/cr16-action-tool_line.png b/kolourpaint/pics/cr16-action-tool_line.png new file mode 100644 index 00000000..ce282923 Binary files /dev/null and b/kolourpaint/pics/cr16-action-tool_line.png differ diff --git a/kolourpaint/pics/cr16-action-tool_pen.png b/kolourpaint/pics/cr16-action-tool_pen.png new file mode 100644 index 00000000..ae64f5aa Binary files /dev/null and b/kolourpaint/pics/cr16-action-tool_pen.png differ diff --git a/kolourpaint/pics/cr16-action-tool_polygon.png b/kolourpaint/pics/cr16-action-tool_polygon.png new file mode 100644 index 00000000..a5500d94 Binary files /dev/null and b/kolourpaint/pics/cr16-action-tool_polygon.png differ diff --git a/kolourpaint/pics/cr16-action-tool_polyline.png b/kolourpaint/pics/cr16-action-tool_polyline.png new file mode 100644 index 00000000..1e23ccd9 Binary files /dev/null and b/kolourpaint/pics/cr16-action-tool_polyline.png differ diff --git a/kolourpaint/pics/cr16-action-tool_rect_selection.png b/kolourpaint/pics/cr16-action-tool_rect_selection.png new file mode 100644 index 00000000..a85ef3f8 Binary files /dev/null and b/kolourpaint/pics/cr16-action-tool_rect_selection.png differ diff --git a/kolourpaint/pics/cr16-action-tool_rectangle.png b/kolourpaint/pics/cr16-action-tool_rectangle.png new file mode 100644 index 00000000..a8455de0 Binary files /dev/null and b/kolourpaint/pics/cr16-action-tool_rectangle.png differ diff --git a/kolourpaint/pics/cr16-action-tool_rounded_rectangle.png b/kolourpaint/pics/cr16-action-tool_rounded_rectangle.png new file mode 100644 index 00000000..4b5a0617 Binary files /dev/null and b/kolourpaint/pics/cr16-action-tool_rounded_rectangle.png differ diff --git a/kolourpaint/pics/cr16-action-tool_spraycan.png b/kolourpaint/pics/cr16-action-tool_spraycan.png new file mode 100644 index 00000000..75b7f748 Binary files /dev/null and b/kolourpaint/pics/cr16-action-tool_spraycan.png differ diff --git a/kolourpaint/pics/cr16-action-tool_text.png b/kolourpaint/pics/cr16-action-tool_text.png new file mode 100644 index 00000000..ffaab637 Binary files /dev/null and b/kolourpaint/pics/cr16-action-tool_text.png differ diff --git a/kolourpaint/pics/cr22-action-tool_brush.png b/kolourpaint/pics/cr22-action-tool_brush.png new file mode 100644 index 00000000..f2ad76cf Binary files /dev/null and b/kolourpaint/pics/cr22-action-tool_brush.png differ diff --git a/kolourpaint/pics/cr22-action-tool_color_picker.png b/kolourpaint/pics/cr22-action-tool_color_picker.png new file mode 100644 index 00000000..3b7ed752 Binary files /dev/null and b/kolourpaint/pics/cr22-action-tool_color_picker.png differ diff --git a/kolourpaint/pics/cr22-action-tool_color_washer.png b/kolourpaint/pics/cr22-action-tool_color_washer.png new file mode 100644 index 00000000..35fcbac1 Binary files /dev/null and b/kolourpaint/pics/cr22-action-tool_color_washer.png differ diff --git a/kolourpaint/pics/cr22-action-tool_curve.png b/kolourpaint/pics/cr22-action-tool_curve.png new file mode 100644 index 00000000..9723e209 Binary files /dev/null and b/kolourpaint/pics/cr22-action-tool_curve.png differ diff --git a/kolourpaint/pics/cr22-action-tool_ellipse.png b/kolourpaint/pics/cr22-action-tool_ellipse.png new file mode 100644 index 00000000..cc57b2f8 Binary files /dev/null and b/kolourpaint/pics/cr22-action-tool_ellipse.png differ diff --git a/kolourpaint/pics/cr22-action-tool_elliptical_selection.png b/kolourpaint/pics/cr22-action-tool_elliptical_selection.png new file mode 100644 index 00000000..a6b23e11 Binary files /dev/null and b/kolourpaint/pics/cr22-action-tool_elliptical_selection.png differ diff --git a/kolourpaint/pics/cr22-action-tool_eraser.png b/kolourpaint/pics/cr22-action-tool_eraser.png new file mode 100644 index 00000000..78632a55 Binary files /dev/null and b/kolourpaint/pics/cr22-action-tool_eraser.png differ diff --git a/kolourpaint/pics/cr22-action-tool_flood_fill.png b/kolourpaint/pics/cr22-action-tool_flood_fill.png new file mode 100644 index 00000000..17cfefba Binary files /dev/null and b/kolourpaint/pics/cr22-action-tool_flood_fill.png differ diff --git a/kolourpaint/pics/cr22-action-tool_free_form_selection.png b/kolourpaint/pics/cr22-action-tool_free_form_selection.png new file mode 100644 index 00000000..cc397f09 Binary files /dev/null and b/kolourpaint/pics/cr22-action-tool_free_form_selection.png differ diff --git a/kolourpaint/pics/cr22-action-tool_line.png b/kolourpaint/pics/cr22-action-tool_line.png new file mode 100644 index 00000000..7ab3c3d9 Binary files /dev/null and b/kolourpaint/pics/cr22-action-tool_line.png differ diff --git a/kolourpaint/pics/cr22-action-tool_pen.png b/kolourpaint/pics/cr22-action-tool_pen.png new file mode 100644 index 00000000..f80fa363 Binary files /dev/null and b/kolourpaint/pics/cr22-action-tool_pen.png differ diff --git a/kolourpaint/pics/cr22-action-tool_polygon.png b/kolourpaint/pics/cr22-action-tool_polygon.png new file mode 100644 index 00000000..1d05ec57 Binary files /dev/null and b/kolourpaint/pics/cr22-action-tool_polygon.png differ diff --git a/kolourpaint/pics/cr22-action-tool_polyline.png b/kolourpaint/pics/cr22-action-tool_polyline.png new file mode 100644 index 00000000..36c089c9 Binary files /dev/null and b/kolourpaint/pics/cr22-action-tool_polyline.png differ diff --git a/kolourpaint/pics/cr22-action-tool_rect_selection.png b/kolourpaint/pics/cr22-action-tool_rect_selection.png new file mode 100644 index 00000000..3dc8c75a Binary files /dev/null and b/kolourpaint/pics/cr22-action-tool_rect_selection.png differ diff --git a/kolourpaint/pics/cr22-action-tool_rectangle.png b/kolourpaint/pics/cr22-action-tool_rectangle.png new file mode 100644 index 00000000..9954c17e Binary files /dev/null and b/kolourpaint/pics/cr22-action-tool_rectangle.png differ diff --git a/kolourpaint/pics/cr22-action-tool_rounded_rectangle.png b/kolourpaint/pics/cr22-action-tool_rounded_rectangle.png new file mode 100644 index 00000000..b736a6cc Binary files /dev/null and b/kolourpaint/pics/cr22-action-tool_rounded_rectangle.png differ diff --git a/kolourpaint/pics/cr22-action-tool_spraycan.png b/kolourpaint/pics/cr22-action-tool_spraycan.png new file mode 100644 index 00000000..bbd35078 Binary files /dev/null and b/kolourpaint/pics/cr22-action-tool_spraycan.png differ diff --git a/kolourpaint/pics/cr22-action-tool_text.png b/kolourpaint/pics/cr22-action-tool_text.png new file mode 100644 index 00000000..52b3ccf7 Binary files /dev/null and b/kolourpaint/pics/cr22-action-tool_text.png differ diff --git a/kolourpaint/pics/cr32-action-tool_brush.png b/kolourpaint/pics/cr32-action-tool_brush.png new file mode 100644 index 00000000..18bcab66 Binary files /dev/null and b/kolourpaint/pics/cr32-action-tool_brush.png differ diff --git a/kolourpaint/pics/cr32-action-tool_color_picker.png b/kolourpaint/pics/cr32-action-tool_color_picker.png new file mode 100644 index 00000000..38197e44 Binary files /dev/null and b/kolourpaint/pics/cr32-action-tool_color_picker.png differ diff --git a/kolourpaint/pics/cr32-action-tool_color_washer.png b/kolourpaint/pics/cr32-action-tool_color_washer.png new file mode 100644 index 00000000..b49c03ca Binary files /dev/null and b/kolourpaint/pics/cr32-action-tool_color_washer.png differ diff --git a/kolourpaint/pics/cr32-action-tool_curve.png b/kolourpaint/pics/cr32-action-tool_curve.png new file mode 100644 index 00000000..db900434 Binary files /dev/null and b/kolourpaint/pics/cr32-action-tool_curve.png differ diff --git a/kolourpaint/pics/cr32-action-tool_ellipse.png b/kolourpaint/pics/cr32-action-tool_ellipse.png new file mode 100644 index 00000000..f6315fdc Binary files /dev/null and b/kolourpaint/pics/cr32-action-tool_ellipse.png differ diff --git a/kolourpaint/pics/cr32-action-tool_elliptical_selection.png b/kolourpaint/pics/cr32-action-tool_elliptical_selection.png new file mode 100644 index 00000000..72c5fc7c Binary files /dev/null and b/kolourpaint/pics/cr32-action-tool_elliptical_selection.png differ diff --git a/kolourpaint/pics/cr32-action-tool_eraser.png b/kolourpaint/pics/cr32-action-tool_eraser.png new file mode 100644 index 00000000..92efe970 Binary files /dev/null and b/kolourpaint/pics/cr32-action-tool_eraser.png differ diff --git a/kolourpaint/pics/cr32-action-tool_flood_fill.png b/kolourpaint/pics/cr32-action-tool_flood_fill.png new file mode 100644 index 00000000..6c116a71 Binary files /dev/null and b/kolourpaint/pics/cr32-action-tool_flood_fill.png differ diff --git a/kolourpaint/pics/cr32-action-tool_free_form_selection.png b/kolourpaint/pics/cr32-action-tool_free_form_selection.png new file mode 100644 index 00000000..b27f17d2 Binary files /dev/null and b/kolourpaint/pics/cr32-action-tool_free_form_selection.png differ diff --git a/kolourpaint/pics/cr32-action-tool_line.png b/kolourpaint/pics/cr32-action-tool_line.png new file mode 100644 index 00000000..b42db17f Binary files /dev/null and b/kolourpaint/pics/cr32-action-tool_line.png differ diff --git a/kolourpaint/pics/cr32-action-tool_pen.png b/kolourpaint/pics/cr32-action-tool_pen.png new file mode 100644 index 00000000..a5881690 Binary files /dev/null and b/kolourpaint/pics/cr32-action-tool_pen.png differ diff --git a/kolourpaint/pics/cr32-action-tool_polygon.png b/kolourpaint/pics/cr32-action-tool_polygon.png new file mode 100644 index 00000000..5f643e3c Binary files /dev/null and b/kolourpaint/pics/cr32-action-tool_polygon.png differ diff --git a/kolourpaint/pics/cr32-action-tool_polyline.png b/kolourpaint/pics/cr32-action-tool_polyline.png new file mode 100644 index 00000000..fabc5a48 Binary files /dev/null and b/kolourpaint/pics/cr32-action-tool_polyline.png differ diff --git a/kolourpaint/pics/cr32-action-tool_rect_selection.png b/kolourpaint/pics/cr32-action-tool_rect_selection.png new file mode 100644 index 00000000..c13c43b9 Binary files /dev/null and b/kolourpaint/pics/cr32-action-tool_rect_selection.png differ diff --git a/kolourpaint/pics/cr32-action-tool_rectangle.png b/kolourpaint/pics/cr32-action-tool_rectangle.png new file mode 100644 index 00000000..a271b7e5 Binary files /dev/null and b/kolourpaint/pics/cr32-action-tool_rectangle.png differ diff --git a/kolourpaint/pics/cr32-action-tool_rounded_rectangle.png b/kolourpaint/pics/cr32-action-tool_rounded_rectangle.png new file mode 100644 index 00000000..ed572dda Binary files /dev/null and b/kolourpaint/pics/cr32-action-tool_rounded_rectangle.png differ diff --git a/kolourpaint/pics/cr32-action-tool_spraycan.png b/kolourpaint/pics/cr32-action-tool_spraycan.png new file mode 100644 index 00000000..b908810c Binary files /dev/null and b/kolourpaint/pics/cr32-action-tool_spraycan.png differ diff --git a/kolourpaint/pics/cr32-action-tool_text.png b/kolourpaint/pics/cr32-action-tool_text.png new file mode 100644 index 00000000..a80b07a6 Binary files /dev/null and b/kolourpaint/pics/cr32-action-tool_text.png differ diff --git a/kolourpaint/pics/cr48-action-tool_brush.png b/kolourpaint/pics/cr48-action-tool_brush.png new file mode 100644 index 00000000..55758f0d Binary files /dev/null and b/kolourpaint/pics/cr48-action-tool_brush.png differ diff --git a/kolourpaint/pics/cr48-action-tool_color_picker.png b/kolourpaint/pics/cr48-action-tool_color_picker.png new file mode 100644 index 00000000..e5414d6e Binary files /dev/null and b/kolourpaint/pics/cr48-action-tool_color_picker.png differ diff --git a/kolourpaint/pics/cr48-action-tool_color_washer.png b/kolourpaint/pics/cr48-action-tool_color_washer.png new file mode 100644 index 00000000..2966d680 Binary files /dev/null and b/kolourpaint/pics/cr48-action-tool_color_washer.png differ diff --git a/kolourpaint/pics/cr48-action-tool_curve.png b/kolourpaint/pics/cr48-action-tool_curve.png new file mode 100644 index 00000000..c046a3ab Binary files /dev/null and b/kolourpaint/pics/cr48-action-tool_curve.png differ diff --git a/kolourpaint/pics/cr48-action-tool_ellipse.png b/kolourpaint/pics/cr48-action-tool_ellipse.png new file mode 100644 index 00000000..a17095b1 Binary files /dev/null and b/kolourpaint/pics/cr48-action-tool_ellipse.png differ diff --git a/kolourpaint/pics/cr48-action-tool_elliptical_selection.png b/kolourpaint/pics/cr48-action-tool_elliptical_selection.png new file mode 100644 index 00000000..637b9603 Binary files /dev/null and b/kolourpaint/pics/cr48-action-tool_elliptical_selection.png differ diff --git a/kolourpaint/pics/cr48-action-tool_eraser.png b/kolourpaint/pics/cr48-action-tool_eraser.png new file mode 100644 index 00000000..69e5b77a Binary files /dev/null and b/kolourpaint/pics/cr48-action-tool_eraser.png differ diff --git a/kolourpaint/pics/cr48-action-tool_flood_fill.png b/kolourpaint/pics/cr48-action-tool_flood_fill.png new file mode 100644 index 00000000..a2937a95 Binary files /dev/null and b/kolourpaint/pics/cr48-action-tool_flood_fill.png differ diff --git a/kolourpaint/pics/cr48-action-tool_free_form_selection.png b/kolourpaint/pics/cr48-action-tool_free_form_selection.png new file mode 100644 index 00000000..b0dd0ae9 Binary files /dev/null and b/kolourpaint/pics/cr48-action-tool_free_form_selection.png differ diff --git a/kolourpaint/pics/cr48-action-tool_line.png b/kolourpaint/pics/cr48-action-tool_line.png new file mode 100644 index 00000000..6d28915b Binary files /dev/null and b/kolourpaint/pics/cr48-action-tool_line.png differ diff --git a/kolourpaint/pics/cr48-action-tool_pen.png b/kolourpaint/pics/cr48-action-tool_pen.png new file mode 100644 index 00000000..16d0f2f3 Binary files /dev/null and b/kolourpaint/pics/cr48-action-tool_pen.png differ diff --git a/kolourpaint/pics/cr48-action-tool_polygon.png b/kolourpaint/pics/cr48-action-tool_polygon.png new file mode 100644 index 00000000..d06b5b64 Binary files /dev/null and b/kolourpaint/pics/cr48-action-tool_polygon.png differ diff --git a/kolourpaint/pics/cr48-action-tool_polyline.png b/kolourpaint/pics/cr48-action-tool_polyline.png new file mode 100644 index 00000000..2d859d96 Binary files /dev/null and b/kolourpaint/pics/cr48-action-tool_polyline.png differ diff --git a/kolourpaint/pics/cr48-action-tool_rect_selection.png b/kolourpaint/pics/cr48-action-tool_rect_selection.png new file mode 100644 index 00000000..71b59563 Binary files /dev/null and b/kolourpaint/pics/cr48-action-tool_rect_selection.png differ diff --git a/kolourpaint/pics/cr48-action-tool_rectangle.png b/kolourpaint/pics/cr48-action-tool_rectangle.png new file mode 100644 index 00000000..9320c2d4 Binary files /dev/null and b/kolourpaint/pics/cr48-action-tool_rectangle.png differ diff --git a/kolourpaint/pics/cr48-action-tool_rounded_rectangle.png b/kolourpaint/pics/cr48-action-tool_rounded_rectangle.png new file mode 100644 index 00000000..91b8a185 Binary files /dev/null and b/kolourpaint/pics/cr48-action-tool_rounded_rectangle.png differ diff --git a/kolourpaint/pics/cr48-action-tool_spraycan.png b/kolourpaint/pics/cr48-action-tool_spraycan.png new file mode 100644 index 00000000..cb653e54 Binary files /dev/null and b/kolourpaint/pics/cr48-action-tool_spraycan.png differ diff --git a/kolourpaint/pics/cr48-action-tool_text.png b/kolourpaint/pics/cr48-action-tool_text.png new file mode 100644 index 00000000..1d007c02 Binary files /dev/null and b/kolourpaint/pics/cr48-action-tool_text.png differ diff --git a/kolourpaint/pics/crsc-action-tool_brush.svgz b/kolourpaint/pics/crsc-action-tool_brush.svgz new file mode 100644 index 00000000..5559a91b Binary files /dev/null and b/kolourpaint/pics/crsc-action-tool_brush.svgz differ diff --git a/kolourpaint/pics/crsc-action-tool_color_picker.svgz b/kolourpaint/pics/crsc-action-tool_color_picker.svgz new file mode 100644 index 00000000..810cfe6b Binary files /dev/null and b/kolourpaint/pics/crsc-action-tool_color_picker.svgz differ diff --git a/kolourpaint/pics/crsc-action-tool_color_washer.svgz b/kolourpaint/pics/crsc-action-tool_color_washer.svgz new file mode 100644 index 00000000..00f72a44 Binary files /dev/null and b/kolourpaint/pics/crsc-action-tool_color_washer.svgz differ diff --git a/kolourpaint/pics/crsc-action-tool_curve.svgz b/kolourpaint/pics/crsc-action-tool_curve.svgz new file mode 100644 index 00000000..fa995555 Binary files /dev/null and b/kolourpaint/pics/crsc-action-tool_curve.svgz differ diff --git a/kolourpaint/pics/crsc-action-tool_ellipse.svgz b/kolourpaint/pics/crsc-action-tool_ellipse.svgz new file mode 100644 index 00000000..42ca1349 Binary files /dev/null and b/kolourpaint/pics/crsc-action-tool_ellipse.svgz differ diff --git a/kolourpaint/pics/crsc-action-tool_elliptical_selection.svgz b/kolourpaint/pics/crsc-action-tool_elliptical_selection.svgz new file mode 100644 index 00000000..6b7c23b2 Binary files /dev/null and b/kolourpaint/pics/crsc-action-tool_elliptical_selection.svgz differ diff --git a/kolourpaint/pics/crsc-action-tool_eraser.svgz b/kolourpaint/pics/crsc-action-tool_eraser.svgz new file mode 100644 index 00000000..1a0278cc Binary files /dev/null and b/kolourpaint/pics/crsc-action-tool_eraser.svgz differ diff --git a/kolourpaint/pics/crsc-action-tool_flood_fill.svgz b/kolourpaint/pics/crsc-action-tool_flood_fill.svgz new file mode 100644 index 00000000..24725599 Binary files /dev/null and b/kolourpaint/pics/crsc-action-tool_flood_fill.svgz differ diff --git a/kolourpaint/pics/crsc-action-tool_free_form_selection.svgz b/kolourpaint/pics/crsc-action-tool_free_form_selection.svgz new file mode 100644 index 00000000..2f304923 Binary files /dev/null and b/kolourpaint/pics/crsc-action-tool_free_form_selection.svgz differ diff --git a/kolourpaint/pics/crsc-action-tool_line.svgz b/kolourpaint/pics/crsc-action-tool_line.svgz new file mode 100644 index 00000000..f2cb1822 Binary files /dev/null and b/kolourpaint/pics/crsc-action-tool_line.svgz differ diff --git a/kolourpaint/pics/crsc-action-tool_pen.svgz b/kolourpaint/pics/crsc-action-tool_pen.svgz new file mode 100644 index 00000000..da783fda Binary files /dev/null and b/kolourpaint/pics/crsc-action-tool_pen.svgz differ diff --git a/kolourpaint/pics/crsc-action-tool_polygon.svgz b/kolourpaint/pics/crsc-action-tool_polygon.svgz new file mode 100644 index 00000000..2e8e9066 Binary files /dev/null and b/kolourpaint/pics/crsc-action-tool_polygon.svgz differ diff --git a/kolourpaint/pics/crsc-action-tool_polyline.svgz b/kolourpaint/pics/crsc-action-tool_polyline.svgz new file mode 100644 index 00000000..f5f2e881 Binary files /dev/null and b/kolourpaint/pics/crsc-action-tool_polyline.svgz differ diff --git a/kolourpaint/pics/crsc-action-tool_rect_selection.svgz b/kolourpaint/pics/crsc-action-tool_rect_selection.svgz new file mode 100644 index 00000000..ac7ae6cf Binary files /dev/null and b/kolourpaint/pics/crsc-action-tool_rect_selection.svgz differ diff --git a/kolourpaint/pics/crsc-action-tool_rectangle.svgz b/kolourpaint/pics/crsc-action-tool_rectangle.svgz new file mode 100644 index 00000000..c12ebf7c Binary files /dev/null and b/kolourpaint/pics/crsc-action-tool_rectangle.svgz differ diff --git a/kolourpaint/pics/crsc-action-tool_rounded_rectangle.svgz b/kolourpaint/pics/crsc-action-tool_rounded_rectangle.svgz new file mode 100644 index 00000000..37625f3f Binary files /dev/null and b/kolourpaint/pics/crsc-action-tool_rounded_rectangle.svgz differ diff --git a/kolourpaint/pics/crsc-action-tool_spraycan.svgz b/kolourpaint/pics/crsc-action-tool_spraycan.svgz new file mode 100644 index 00000000..6095c388 Binary files /dev/null and b/kolourpaint/pics/crsc-action-tool_spraycan.svgz differ diff --git a/kolourpaint/pics/crsc-action-tool_text.svgz b/kolourpaint/pics/crsc-action-tool_text.svgz new file mode 100644 index 00000000..c6be2b8f Binary files /dev/null and b/kolourpaint/pics/crsc-action-tool_text.svgz differ diff --git a/kolourpaint/pics/custom/Makefile.am b/kolourpaint/pics/custom/Makefile.am new file mode 100644 index 00000000..e796e21a --- /dev/null +++ b/kolourpaint/pics/custom/Makefile.am @@ -0,0 +1,10 @@ +customicondir = $(kde_datadir)/kolourpaint/pics +customicon_DATA = tool_spraycan_9x9.png tool_spraycan_17x17.png tool_spraycan_29x29.png \ + color_transparent_26x26.png colorbutton_swap_16x16.png \ + option_opaque.png option_transparent.png \ + resize.png scale.png smooth_scale.png \ + image_skew_horizontal.png image_skew_vertical.png \ + image_rotate_anticlockwise.png image_rotate_clockwise.png + +EXTRA_DIST = $(customicon_DATA) + diff --git a/kolourpaint/pics/custom/color_transparent_26x26.png b/kolourpaint/pics/custom/color_transparent_26x26.png new file mode 100644 index 00000000..3ba3d39e Binary files /dev/null and b/kolourpaint/pics/custom/color_transparent_26x26.png differ diff --git a/kolourpaint/pics/custom/colorbutton_swap_16x16.png b/kolourpaint/pics/custom/colorbutton_swap_16x16.png new file mode 100644 index 00000000..cebe9ed5 Binary files /dev/null and b/kolourpaint/pics/custom/colorbutton_swap_16x16.png differ diff --git a/kolourpaint/pics/custom/image_rotate_anticlockwise.png b/kolourpaint/pics/custom/image_rotate_anticlockwise.png new file mode 100644 index 00000000..8ef21bf2 Binary files /dev/null and b/kolourpaint/pics/custom/image_rotate_anticlockwise.png differ diff --git a/kolourpaint/pics/custom/image_rotate_clockwise.png b/kolourpaint/pics/custom/image_rotate_clockwise.png new file mode 100644 index 00000000..dee00f4a Binary files /dev/null and b/kolourpaint/pics/custom/image_rotate_clockwise.png differ diff --git a/kolourpaint/pics/custom/image_skew_horizontal.png b/kolourpaint/pics/custom/image_skew_horizontal.png new file mode 100644 index 00000000..c27c8223 Binary files /dev/null and b/kolourpaint/pics/custom/image_skew_horizontal.png differ diff --git a/kolourpaint/pics/custom/image_skew_vertical.png b/kolourpaint/pics/custom/image_skew_vertical.png new file mode 100644 index 00000000..e84ac257 Binary files /dev/null and b/kolourpaint/pics/custom/image_skew_vertical.png differ diff --git a/kolourpaint/pics/custom/option_opaque.png b/kolourpaint/pics/custom/option_opaque.png new file mode 100644 index 00000000..ab442ecb Binary files /dev/null and b/kolourpaint/pics/custom/option_opaque.png differ diff --git a/kolourpaint/pics/custom/option_transparent.png b/kolourpaint/pics/custom/option_transparent.png new file mode 100644 index 00000000..e751d7e9 Binary files /dev/null and b/kolourpaint/pics/custom/option_transparent.png differ diff --git a/kolourpaint/pics/custom/resize.png b/kolourpaint/pics/custom/resize.png new file mode 100644 index 00000000..0046cbcf Binary files /dev/null and b/kolourpaint/pics/custom/resize.png differ diff --git a/kolourpaint/pics/custom/scale.png b/kolourpaint/pics/custom/scale.png new file mode 100644 index 00000000..9f0904dd Binary files /dev/null and b/kolourpaint/pics/custom/scale.png differ diff --git a/kolourpaint/pics/custom/smooth_scale.png b/kolourpaint/pics/custom/smooth_scale.png new file mode 100644 index 00000000..5c48a6e2 Binary files /dev/null and b/kolourpaint/pics/custom/smooth_scale.png differ diff --git a/kolourpaint/pics/custom/tool_spraycan_17x17.png b/kolourpaint/pics/custom/tool_spraycan_17x17.png new file mode 100644 index 00000000..c5d228b0 Binary files /dev/null and b/kolourpaint/pics/custom/tool_spraycan_17x17.png differ diff --git a/kolourpaint/pics/custom/tool_spraycan_29x29.png b/kolourpaint/pics/custom/tool_spraycan_29x29.png new file mode 100644 index 00000000..47cfce16 Binary files /dev/null and b/kolourpaint/pics/custom/tool_spraycan_29x29.png differ diff --git a/kolourpaint/pics/custom/tool_spraycan_9x9.png b/kolourpaint/pics/custom/tool_spraycan_9x9.png new file mode 100644 index 00000000..85dde5a8 Binary files /dev/null and b/kolourpaint/pics/custom/tool_spraycan_9x9.png differ diff --git a/kolourpaint/pics/hi16-app-kolourpaint.png b/kolourpaint/pics/hi16-app-kolourpaint.png new file mode 100644 index 00000000..7802218f Binary files /dev/null and b/kolourpaint/pics/hi16-app-kolourpaint.png differ diff --git a/kolourpaint/pics/hi22-app-kolourpaint.png b/kolourpaint/pics/hi22-app-kolourpaint.png new file mode 100644 index 00000000..9f411e5c Binary files /dev/null and b/kolourpaint/pics/hi22-app-kolourpaint.png differ diff --git a/kolourpaint/pics/hi32-app-kolourpaint.png b/kolourpaint/pics/hi32-app-kolourpaint.png new file mode 100644 index 00000000..33e3e6f2 Binary files /dev/null and b/kolourpaint/pics/hi32-app-kolourpaint.png differ diff --git a/kolourpaint/pics/hi48-app-kolourpaint.png b/kolourpaint/pics/hi48-app-kolourpaint.png new file mode 100644 index 00000000..6878b110 Binary files /dev/null and b/kolourpaint/pics/hi48-app-kolourpaint.png differ diff --git a/kolourpaint/pics/hisc-app-kolourpaint.svgz b/kolourpaint/pics/hisc-app-kolourpaint.svgz new file mode 100644 index 00000000..9823cf97 Binary files /dev/null and b/kolourpaint/pics/hisc-app-kolourpaint.svgz differ diff --git a/kolourpaint/pixmapfx/Makefile.am b/kolourpaint/pixmapfx/Makefile.am new file mode 100644 index 00000000..dfa1d697 --- /dev/null +++ b/kolourpaint/pixmapfx/Makefile.am @@ -0,0 +1,19 @@ +INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../cursors -I$(srcdir)/../interfaces \ + -I$(srcdir)/../pixmapfx \ + -I$(srcdir)/../tools \ + -I$(srcdir)/../views \ + -I$(srcdir)/../widgets $(all_includes) + +noinst_LTLIBRARIES = libkolourpaintpixmapfx.la +libkolourpaintpixmapfx_la_SOURCES = kpcoloreffect.cpp \ + kpeffectbalance.cpp \ + kpeffectblursharpen.cpp \ + kpeffectemboss.cpp \ + kpeffectflatten.cpp \ + kpeffectinvert.cpp \ + kpeffectreducecolors.cpp \ + kpeffectsdialog.cpp \ + kpfloodfill.cpp \ + kppixmapfx.cpp + +METASOURCES = AUTO diff --git a/kolourpaint/pixmapfx/kpcoloreffect.cpp b/kolourpaint/pixmapfx/kpcoloreffect.cpp new file mode 100644 index 00000000..1660c1fa --- /dev/null +++ b/kolourpaint/pixmapfx/kpcoloreffect.cpp @@ -0,0 +1,168 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + + +kpColorEffectCommand::kpColorEffectCommand (const QString &name, + bool actOnSelection, + kpMainWindow *mainWindow) + : kpCommand (mainWindow), + m_name (name), + m_actOnSelection (actOnSelection), + m_oldPixmapPtr (0) +{ +} + +kpColorEffectCommand::~kpColorEffectCommand () +{ + delete m_oldPixmapPtr; m_oldPixmapPtr = 0; +} + + +// public virtual [base kpCommand] +QString kpColorEffectCommand::name () const +{ + if (m_actOnSelection) + return i18n ("Selection: %1").arg (m_name); + else + return m_name; +} + + +// public virtual [base kpCommand] +int kpColorEffectCommand::size () const +{ + return kpPixmapFX::pixmapSize (m_oldPixmapPtr); +} + + +// public virtual [base kpCommand] +void kpColorEffectCommand::execute () +{ + kpDocument *doc = document (); + if (!doc) + return; + + QApplication::setOverrideCursor (Qt::waitCursor); + + + const QPixmap oldPixmap = *doc->pixmap (m_actOnSelection); + + if (!isInvertible ()) + { + m_oldPixmapPtr = new QPixmap (); + *m_oldPixmapPtr = oldPixmap; + } + + + QPixmap newPixmap = /*pure virtual*/applyColorEffect (oldPixmap); + + doc->setPixmap (m_actOnSelection, newPixmap); + + + QApplication::restoreOverrideCursor (); +} + +// public virtual [base kpCommand] +void kpColorEffectCommand::unexecute () +{ + kpDocument *doc = document (); + if (!doc) + return; + + QApplication::setOverrideCursor (Qt::waitCursor); + + + QPixmap newPixmap; + + if (!isInvertible ()) + { + newPixmap = *m_oldPixmapPtr; + } + else + { + newPixmap = /*pure virtual*/applyColorEffect (*doc->pixmap (m_actOnSelection)); + } + + doc->setPixmap (m_actOnSelection, newPixmap); + + + delete m_oldPixmapPtr; m_oldPixmapPtr = 0; + + + QApplication::restoreOverrideCursor (); +} + + +kpColorEffectWidget::kpColorEffectWidget (bool actOnSelection, + kpMainWindow *mainWindow, + QWidget *parent, const char *name) + : QWidget (parent, name), + m_actOnSelection (actOnSelection), + m_mainWindow (mainWindow) +{ +} + +kpColorEffectWidget::~kpColorEffectWidget () +{ +} + + +// public +QString kpColorEffectWidget::caption () const +{ + return QString::null; +} + + +// protected +int kpColorEffectWidget::marginHint () const +{ + return 0; +} + +// protected +int kpColorEffectWidget::spacingHint () const +{ + return KDialog::spacingHint (); +} + + +#include diff --git a/kolourpaint/pixmapfx/kpcoloreffect.h b/kolourpaint/pixmapfx/kpcoloreffect.h new file mode 100644 index 00000000..8b3dfd09 --- /dev/null +++ b/kolourpaint/pixmapfx/kpcoloreffect.h @@ -0,0 +1,111 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_COLOR_EFFECT_H +#define KP_COLOR_EFFECT_H + +#include +#include + +#include + +class QPixmap; + +class kpDocument; +class kpMainWindow; + + +class kpColorEffectCommand : public kpCommand +{ +public: + kpColorEffectCommand (const QString &name, + bool actOnSelection, + kpMainWindow *mainWindow); + virtual ~kpColorEffectCommand (); + + virtual QString name () const; + virtual int size () const; + +public: + virtual void execute (); + virtual void unexecute (); + +public: + // Return true if applyColorEffect(applyColorEffect(pixmap)) == pixmap + // to avoid storing the old pixmap, saving memory. + virtual bool isInvertible () const { return false; } + +protected: + virtual QPixmap applyColorEffect (const QPixmap &pixmap) = 0; + +private: + QString m_name; + bool m_actOnSelection; + + QPixmap *m_oldPixmapPtr; +}; + + +class kpColorEffectWidget : public QWidget +{ +Q_OBJECT + +public: + kpColorEffectWidget (bool actOnSelection, + kpMainWindow *mainWindow, + QWidget *parent, const char *name = 0); + virtual ~kpColorEffectWidget (); + +signals: + void settingsChangedNoWaitCursor (); + + void settingsChanged (); + + // (same as settingsChanged() but preview doesn't update until there + // has been no activity for a while - used for sliders in slow effects) + void settingsChangedDelayed (); + +public: + virtual QString caption () const; + + virtual bool isNoOp () const = 0; + virtual QPixmap applyColorEffect (const QPixmap &pixmap) = 0; + + virtual kpColorEffectCommand *createCommand () const = 0; + +protected: + int marginHint () const; + int spacingHint () const; + +protected: + bool m_actOnSelection; + kpMainWindow *m_mainWindow; +}; + + +#endif // KP_COLOR_EFFECT_H diff --git a/kolourpaint/pixmapfx/kpeffectbalance.cpp b/kolourpaint/pixmapfx/kpeffectbalance.cpp new file mode 100644 index 00000000..f4494d29 --- /dev/null +++ b/kolourpaint/pixmapfx/kpeffectbalance.cpp @@ -0,0 +1,517 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_EFFECT_BALANCE 0 + + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + + +#if DEBUG_KP_EFFECT_BALANCE + #include +#endif + + +kpEffectBalanceCommand::kpEffectBalanceCommand (int channels, + int brightness, int contrast, int gamma, + bool actOnSelection, + kpMainWindow *mainWindow) + : kpColorEffectCommand (i18n ("Balance"), actOnSelection, mainWindow), + m_channels (channels), + m_brightness (brightness), m_contrast (contrast), m_gamma (gamma) +{ +} + +kpEffectBalanceCommand::~kpEffectBalanceCommand () +{ +} + + +static inline int between0And255 (int val) +{ + if (val < 0) + return 0; + else if (val > 255) + return 255; + else + return val; +} + + +static inline int brightness (int base, int strength) +{ + return between0And255 (base + strength * 255 / 50); +} + +static inline int contrast (int base, int strength) +{ + return between0And255 ((base - 127) * (strength + 50) / 50 + 127); +} + +static inline int gamma (int base, int strength) +{ + return between0And255 (qRound (255.0 * pow (base / 255.0, 1.0 / pow (10, strength / 50.0)))); +} + + +static inline int brightnessContrastGamma (int base, + int newBrightness, + int newContrast, + int newGamma) +{ + return gamma (contrast (brightness (base, newBrightness), + newContrast), + newGamma); +} + +static inline QRgb brightnessContrastGammaForRGB (QRgb rgb, + int channels, + int brightness, int contrast, int gamma) +{ + int red = qRed (rgb); + int green = qGreen (rgb); + int blue = qBlue (rgb); + + + if (channels & kpEffectBalanceCommand::Red) + red = brightnessContrastGamma (red, brightness, contrast, gamma); + if (channels & kpEffectBalanceCommand::Green) + green = brightnessContrastGamma (green, brightness, contrast, gamma); + if (channels & kpEffectBalanceCommand::Blue) + blue = brightnessContrastGamma (blue, brightness, contrast, gamma); + + + return qRgba (red, green, blue, qAlpha (rgb)); +} + + +// public static +QPixmap kpEffectBalanceCommand::applyColorEffect (const QPixmap &pixmap, + int channels, + int brightness, int contrast, int gamma) +{ +#if DEBUG_KP_EFFECT_BALANCE + kdDebug () << "kpEffectBalanceCommand::applyColorEffect(" + << "channels=" << channels + << ",brightness=" << brightness + << ",contrast=" << contrast + << ",gamma=" << gamma + << ")" << endl; + QTime timer; timer.start (); +#endif + + QImage image = kpPixmapFX::convertToImage (pixmap); +#if DEBUG_KP_EFFECT_BALANCE + kdDebug () << "\tconvertToImage=" << timer.restart () << endl; +#endif + + + Q_UINT8 transformRed [256], + transformGreen [256], + transformBlue [256]; + + for (int i = 0; i < 256; i++) + { + Q_UINT8 applied = (Q_UINT8) brightnessContrastGamma (i, brightness, contrast, gamma); + + if (channels & kpEffectBalanceCommand::Red) + transformRed [i] = applied; + else + transformRed [i] = i; + + if (channels & kpEffectBalanceCommand::Green) + transformGreen [i] = applied; + else + transformGreen [i] = i; + + if (channels & kpEffectBalanceCommand::Blue) + transformBlue [i] = applied; + else + transformBlue [i] = i; + } + +#if DEBUG_KP_EFFECT_BALANCE + kdDebug () << "\tbuild lookup=" << timer.restart () << endl; +#endif + + + if (image.depth () > 8) + { + for (int y = 0; y < image.height (); y++) + { + for (int x = 0; x < image.width (); x++) + { + const QRgb rgb = image.pixel (x, y); + + const Q_UINT8 red = (Q_UINT8) qRed (rgb); + const Q_UINT8 green = (Q_UINT8) qGreen (rgb); + const Q_UINT8 blue = (Q_UINT8) qBlue (rgb); + const Q_UINT8 alpha = (Q_UINT8) qAlpha (rgb); + + image.setPixel (x, y, + qRgba (transformRed [red], + transformGreen [green], + transformBlue [blue], + alpha)); + + #if 0 + image.setPixel (x, y, + brightnessContrastGammaForRGB (image.pixel (x, y), + channels, + brightness, contrast, gamma)); + #endif + } + } + } + else + { + for (int i = 0; i < image.numColors (); i++) + { + const QRgb rgb = image.color (i); + + const Q_UINT8 red = (Q_UINT8) qRed (rgb); + const Q_UINT8 green = (Q_UINT8) qGreen (rgb); + const Q_UINT8 blue = (Q_UINT8) qBlue (rgb); + const Q_UINT8 alpha = (Q_UINT8) qAlpha (rgb); + + image.setColor (i, + qRgba (transformRed [red], + transformGreen [green], + transformBlue [blue], + alpha)); + + #if 0 + image.setColor (i, + brightnessContrastGammaForRGB (image.color (i), + channels, + brightness, contrast, gamma)); + #endif + } + + } +#if DEBUG_KP_EFFECT_BALANCE + kdDebug () << "\teffect=" << timer.restart () << endl; +#endif + + const QPixmap retPixmap = kpPixmapFX::convertToPixmap (image); +#if DEBUG_KP_EFFECT_BALANCE + kdDebug () << "\tconvertToPixmap=" << timer.restart () << endl; +#endif + + return retPixmap; +} + +// protected virtual [base kpColorEffectCommand] +QPixmap kpEffectBalanceCommand::applyColorEffect (const QPixmap &pixmap) +{ + return applyColorEffect (pixmap, m_channels, + m_brightness, m_contrast, m_gamma); +} + + + +kpEffectBalanceWidget::kpEffectBalanceWidget (bool actOnSelection, + kpMainWindow *mainWindow, + QWidget *parent, const char *name) + : kpColorEffectWidget (actOnSelection, mainWindow, parent, name) +{ + QGridLayout *lay = new QGridLayout (this, 5, 5, marginHint (), spacingHint ()); + + + QLabel *brightnessLabel = new QLabel (i18n ("&Brightness:"), this); + m_brightnessInput = new KIntNumInput (0/*value*/, this); + m_brightnessInput->setRange (-50, 50, 1/*step*/, true/*slider*/); + QPushButton *brightnessResetPushButton = new QPushButton (i18n ("Re&set"), this); + + QLabel *contrastLabel = new QLabel (i18n ("Co&ntrast:"), this); + m_contrastInput = new KIntNumInput (0/*value*/, this); + m_contrastInput->setRange (-50, 50, 1/*step*/, true/*slider*/); + QPushButton *contrastResetPushButton = new QPushButton (i18n ("&Reset"), this); + + QLabel *gammaLabel = new QLabel (i18n ("&Gamma:"), this); + m_gammaInput = new KIntNumInput (0/*value*/, this); + m_gammaInput->setRange (-50, 50, 1/*step*/, true/*slider*/); + // TODO: This is what should be shown in the m_gammaInput spinbox + m_gammaLabel = new QLabel (this); + // TODO: This doesn't seem to be wide enough with some fonts so the + // whole layout moves when we drag the gamma slider. + m_gammaLabel->setMinimumWidth (m_gammaLabel->fontMetrics ().width (" 10.00 ")); + m_gammaLabel->setAlignment (m_gammaLabel->alignment () | Qt::AlignRight); + QPushButton *gammaResetPushButton = new QPushButton (i18n ("Rese&t"), this); + + + QWidget *spaceWidget = new QLabel (this); + spaceWidget->setFixedSize (1, spacingHint ()); + + + QLabel *channelLabel = new QLabel (i18n ("C&hannels:"), this); + m_channelsComboBox = new KComboBox (this); + m_channelsComboBox->insertItem (i18n ("All")); + m_channelsComboBox->insertItem (i18n ("Red")); + m_channelsComboBox->insertItem (i18n ("Green")); + m_channelsComboBox->insertItem (i18n ("Blue")); + + + QPushButton *resetPushButton = new QPushButton (i18n ("Reset &All Values"), this); + + + brightnessLabel->setBuddy (m_brightnessInput); + contrastLabel->setBuddy (m_contrastInput); + gammaLabel->setBuddy (m_gammaInput); + + channelLabel->setBuddy (m_channelsComboBox); + + + lay->addWidget (brightnessLabel, 0, 0); + lay->addMultiCellWidget (m_brightnessInput, 0, 0, 1, 2); + lay->addWidget (brightnessResetPushButton, 0, 4); + + lay->addWidget (contrastLabel, 1, 0); + lay->addMultiCellWidget (m_contrastInput, 1, 1, 1, 2); + lay->addWidget (contrastResetPushButton, 1, 4); + + lay->addWidget (gammaLabel, 2, 0); + lay->addMultiCellWidget (m_gammaInput, 2, 2, 1, 2); + lay->addWidget (m_gammaLabel, 2, 3); + lay->addWidget (gammaResetPushButton, 2, 4); + + lay->addMultiCellWidget (spaceWidget, 3, 3, 0, 4); + lay->addMultiCellWidget (resetPushButton, 4, 4, 2, 4, Qt::AlignRight); + + lay->addWidget (channelLabel, 4, 0); + lay->addWidget (m_channelsComboBox, 4, 1, Qt::AlignLeft); + //lay->addWidget (resetPushButton, 4, 2, Qt::AlignRight); + + lay->setColStretch (1, 1); + + + // (no need for settingsChangedDelayed() since BCG effect is so fast :)) + connect (m_brightnessInput, SIGNAL (valueChanged (int)), + this, SIGNAL (settingsChangedNoWaitCursor ())); + connect (m_contrastInput, SIGNAL (valueChanged (int)), + this, SIGNAL (settingsChangedNoWaitCursor ())); + + connect (m_gammaInput, SIGNAL (valueChanged (int)), + this, SLOT (recalculateGammaLabel ())); + connect (m_gammaInput, SIGNAL (valueChanged (int)), + this, SIGNAL (settingsChangedNoWaitCursor ())); + + connect (m_channelsComboBox, SIGNAL (activated (int)), + this, SIGNAL (settingsChanged ())); + + connect (brightnessResetPushButton, SIGNAL (clicked ()), + this, SLOT (resetBrightness ())); + connect (contrastResetPushButton, SIGNAL (clicked ()), + this, SLOT (resetContrast ())); + connect (gammaResetPushButton, SIGNAL (clicked ()), + this, SLOT (resetGamma ())); + + connect (resetPushButton, SIGNAL (clicked ()), + this, SLOT (resetAll ())); + + + recalculateGammaLabel (); +} + +kpEffectBalanceWidget::~kpEffectBalanceWidget () +{ +} + + +// public virtual [base kpColorEffectWidget] +QString kpEffectBalanceWidget::caption () const +{ + return i18n ("Settings"); +} + + +// public virtual [base kpColorEffectWidget] +bool kpEffectBalanceWidget::isNoOp () const +{ + return (brightness () == 0 && contrast () == 0 && gamma () == 0); +} + +// public virtual [base kpColorEffectWidget] +QPixmap kpEffectBalanceWidget::applyColorEffect (const QPixmap &pixmap) +{ + return kpEffectBalanceCommand::applyColorEffect (pixmap, + channels (), brightness (), contrast (), gamma ()); +} + +// public virtual [base kpColorEffectWidget] +kpColorEffectCommand *kpEffectBalanceWidget::createCommand () const +{ + return new kpEffectBalanceCommand (channels (), + brightness (), contrast (), gamma (), + m_actOnSelection, + m_mainWindow); +} + + +// protected +int kpEffectBalanceWidget::channels () const +{ + switch (m_channelsComboBox->currentItem ()) + { + default: + case 0: + return kpEffectBalanceCommand::RGB; + + case 1: + return kpEffectBalanceCommand::Red; + + case 2: + return kpEffectBalanceCommand::Green; + + case 3: + return kpEffectBalanceCommand::Blue; + } +} + + +// protected +int kpEffectBalanceWidget::brightness () const +{ + return m_brightnessInput->value (); +} + +// protected +int kpEffectBalanceWidget::contrast () const +{ + return m_contrastInput->value (); +} + +// protected +int kpEffectBalanceWidget::gamma () const +{ + return m_gammaInput->value (); +} + + +// protected slot +void kpEffectBalanceWidget::recalculateGammaLabel () +{ + m_gammaLabel->setText ( + " " + + QString::number (pow (10, gamma () / 50.0), + 'f'/*[-]9.9*/, + 2/*precision*/) + + " "); + m_gammaLabel->repaint (); +} + + +// protected slot +void kpEffectBalanceWidget::resetBrightness () +{ + if (brightness () == 0) + return; + + bool sb = signalsBlocked (); + + if (!sb) blockSignals (true); + m_brightnessInput->setValue (0); + if (!sb) blockSignals (false); + + // Immediate update (if signals aren't blocked) + emit settingsChanged (); +} + +// protected slot +void kpEffectBalanceWidget::resetContrast () +{ + if (contrast () == 0) + return; + + bool sb = signalsBlocked (); + + if (!sb) blockSignals (true); + m_contrastInput->setValue (0); + if (!sb) blockSignals (false); + + // Immediate update (if signals aren't blocked) + emit settingsChanged (); +} + +// protected slot +void kpEffectBalanceWidget::resetGamma () +{ + if (gamma () == 0) + return; + + bool sb = signalsBlocked (); + + if (!sb) blockSignals (true); + m_gammaInput->setValue (0); + recalculateGammaLabel (); + if (!sb) blockSignals (false); + + // Immediate update (if signals aren't blocked) + emit settingsChanged (); +} + + +// protected slot +void kpEffectBalanceWidget::resetAll () +{ + if (isNoOp ()) + return; + + // Prevent multiple settingsChanged() which would normally result in + // redundant, expensive preview repaints + blockSignals (true); + + resetBrightness (); + resetContrast (); + resetGamma (); + + recalculateGammaLabel (); + + blockSignals (false); + + emit settingsChanged (); +} + + +#include diff --git a/kolourpaint/pixmapfx/kpeffectbalance.h b/kolourpaint/pixmapfx/kpeffectbalance.h new file mode 100644 index 00000000..b045159f --- /dev/null +++ b/kolourpaint/pixmapfx/kpeffectbalance.h @@ -0,0 +1,116 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_EFFECT_BALANCE_H +#define KP_EFFECT_BALANCE_H + +#include + + +class QLabel; + +class KComboBox; +class KIntNumInput; + +class kpMainWindowe; + + +class kpEffectBalanceCommand : public kpColorEffectCommand +{ +public: + enum Channel + { + None = 0, + Red = 1, Green = 2, Blue = 4, + RGB = Red | Green | Blue + }; + + // , & are from -50 to 50 + + kpEffectBalanceCommand (int channels, + int brightness, int contrast, int gamma, + bool actOnSelection, + kpMainWindow *mainWindow); + virtual ~kpEffectBalanceCommand (); + + static QPixmap applyColorEffect (const QPixmap &pixmap, + int channels, + int brightness, int contrast, int gamma); + +protected: + virtual QPixmap applyColorEffect (const QPixmap &pixmap); + +protected: + int m_channels; + int m_brightness, m_contrast, m_gamma; +}; + + +class kpEffectBalanceWidget : public kpColorEffectWidget +{ +Q_OBJECT + +public: + kpEffectBalanceWidget (bool actOnSelection, + kpMainWindow *mainWindow, + QWidget *parent, const char *name = 0); + virtual ~kpEffectBalanceWidget (); + + virtual QString caption () const; + + virtual bool isNoOp () const; + virtual QPixmap applyColorEffect (const QPixmap &pixmap); + + virtual kpColorEffectCommand *createCommand () const; + +protected: + int channels () const; + + int brightness () const; + int contrast () const; + int gamma () const; + +protected slots: + void recalculateGammaLabel (); + + void resetBrightness (); + void resetContrast (); + void resetGamma (); + + void resetAll (); + +protected: + KIntNumInput *m_brightnessInput, + *m_contrastInput, + *m_gammaInput; + QLabel *m_gammaLabel; + KComboBox *m_channelsComboBox; +}; + + +#endif // KP_EFFECT_BALANCE_H diff --git a/kolourpaint/pixmapfx/kpeffectblursharpen.cpp b/kolourpaint/pixmapfx/kpeffectblursharpen.cpp new file mode 100644 index 00000000..50c0b27d --- /dev/null +++ b/kolourpaint/pixmapfx/kpeffectblursharpen.cpp @@ -0,0 +1,291 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_EFFECT_BLUR_SHARPEN 0 + + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + + +static QString nameForType (kpEffectBlurSharpenCommand::Type type) +{ + if (type == kpEffectBlurSharpenCommand::Blur) + return i18n ("Soften"); + else if (type == kpEffectBlurSharpenCommand::Sharpen) + return i18n ("Sharpen"); + else + return QString::null; +} + + +kpEffectBlurSharpenCommand::kpEffectBlurSharpenCommand (Type type, + double radius, double sigma, + int repeat, + bool actOnSelection, + kpMainWindow *mainWindow) + : kpColorEffectCommand (::nameForType (type), actOnSelection, mainWindow), + m_type (type), + m_radius (radius), m_sigma (sigma), + m_repeat (repeat) +{ +} + +kpEffectBlurSharpenCommand::~kpEffectBlurSharpenCommand () +{ +} + + +// public static +QPixmap kpEffectBlurSharpenCommand::apply (const QPixmap &pixmap, + Type type, double radius, double sigma, + int repeat) +{ +#if DEBUG_KP_EFFECT_BLUR_SHARPEN + kdDebug () << "kpEffectBlurSharpenCommand::apply(type=" + << int (type) + << " radius=" << radius + << " sigma=" << sigma + << " repeat=" << repeat + << ")" + << endl; +#endif + + // (KImageEffect::(blur|sharpen)() ignores mask) + QPixmap usePixmap = kpPixmapFX::pixmapWithDefinedTransparentPixels ( + pixmap, + Qt::white/*arbitrarily chosen*/); + + + QImage image = kpPixmapFX::convertToImage (usePixmap); + + for (int i = 0; i < repeat; i++) + { + if (type == Blur) + image = KImageEffect::blur (image, radius, sigma); + else if (type == Sharpen) + image = KImageEffect::sharpen (image, radius, sigma); + } + + QPixmap retPixmap = kpPixmapFX::convertToPixmap (image); + + + // KImageEffect::(blur|sharpen)() nukes mask - restore it + if (usePixmap.mask ()) + retPixmap.setMask (*usePixmap.mask ()); + + + return retPixmap; +} + +// protected virtual [base kpColorEffectCommand] +QPixmap kpEffectBlurSharpenCommand::applyColorEffect (const QPixmap &pixmap) +{ + return apply (pixmap, m_type, m_radius, m_sigma, m_repeat); +} + + + +kpEffectBlurSharpenWidget::kpEffectBlurSharpenWidget (bool actOnSelection, + kpMainWindow *mainWindow, + QWidget *parent, const char *name) + : kpColorEffectWidget (actOnSelection, mainWindow, parent, name) +{ + QGridLayout *lay = new QGridLayout (this, 4, 2, marginHint (), spacingHint ()); + + + QLabel *amountLabel = new QLabel (i18n ("&Amount:"), this); + m_amountInput = new KIntNumInput (this); + m_amountInput->setRange (-10, 10, 1/*step*/, true/*slider*/); + + m_typeLabel = new QLabel (this); + + + amountLabel->setBuddy (m_amountInput); + + + lay->addWidget (amountLabel, 0, 0); + lay->addWidget (m_amountInput, 0, 1); + + lay->addMultiCellWidget (m_typeLabel, 1, 1, 0, 1, Qt::AlignCenter); + + lay->setColStretch (1, 1); + + + connect (m_amountInput, SIGNAL (valueChanged (int)), + this, SIGNAL (settingsChangedDelayed ())); + + connect (m_amountInput, SIGNAL (valueChanged (int)), + this, SLOT (slotUpdateTypeLabel ())); +} + +kpEffectBlurSharpenWidget::~kpEffectBlurSharpenWidget () +{ +} + + +// public virtual [base kpColorEffectWidget] +QString kpEffectBlurSharpenWidget::caption () const +{ + return QString::null; +} + + +// public virtual [base kpColorEffectWidget] +bool kpEffectBlurSharpenWidget::isNoOp () const +{ + return (type () == kpEffectBlurSharpenCommand::None); +} + +// public virtual [base kpColorEffectWidget] +QPixmap kpEffectBlurSharpenWidget::applyColorEffect (const QPixmap &pixmap) +{ + return kpEffectBlurSharpenCommand::apply (pixmap, + type (), radius (), sigma (), repeat ()); +} + +// public virtual [base kpColorEffectWidget] +kpColorEffectCommand *kpEffectBlurSharpenWidget::createCommand () const +{ + return new kpEffectBlurSharpenCommand (type (), radius (), sigma (), repeat (), + m_actOnSelection, + m_mainWindow); +} + + +// protected slot +void kpEffectBlurSharpenWidget::slotUpdateTypeLabel () +{ + QString text = ::nameForType (type ()); + +#if DEBUG_KP_EFFECT_BLUR_SHARPEN + kdDebug () << "kpEffectBlurSharpenWidget::slotUpdateTypeLabel() text=" + << text << endl; +#endif + m_typeLabel->setText (text); +} + + +// protected +kpEffectBlurSharpenCommand::Type kpEffectBlurSharpenWidget::type () const +{ + if (m_amountInput->value () == 0) + return kpEffectBlurSharpenCommand::None; + else if (m_amountInput->value () < 0) + return kpEffectBlurSharpenCommand::Blur; + else + return kpEffectBlurSharpenCommand::Sharpen; +} + +// The numbers that follow were picked by experimentation. +// I still have no idea what "radius" and "sigma" mean +// (even after reading the API). + +// protected +double kpEffectBlurSharpenWidget::radius () const +{ + if (m_amountInput->value () == 0) + return 0; + + if (m_amountInput->value () < 0) + { + return 8; + } + else + { + const double SharpenMin = .1; + const double SharpenMax = 2.5; + + return SharpenMin + + (m_amountInput->value () - 1) * + (SharpenMax - SharpenMin) / + (m_amountInput->maxValue () - 1); + } +} + +// protected +double kpEffectBlurSharpenWidget::sigma () const +{ + if (m_amountInput->value () == 0) + return 0; + + if (m_amountInput->value () < 0) + { + const double BlurMin = .5; + const double BlurMax = 4; + + return BlurMin + + (-m_amountInput->value () - 1) * + (BlurMax - BlurMin) / + (-m_amountInput->minValue () - 1); + } + else + { + const double SharpenMin = .5; + const double SharpenMax = 3.0; + + return SharpenMin + + (m_amountInput->value () - 1) * + (SharpenMax - SharpenMin) / + (m_amountInput->maxValue () - 1); + } +} + +// protected +int kpEffectBlurSharpenWidget::repeat () const +{ + if (m_amountInput->value () == 0) + return 0; + + if (m_amountInput->value () < 0) + return 1; + else + { + const double SharpenMin = 1; + const double SharpenMax = 2; + + return qRound (SharpenMin + + (m_amountInput->value () - 1) * + (SharpenMax - SharpenMin) / + (m_amountInput->maxValue () - 1)); + } +} + +#include diff --git a/kolourpaint/pixmapfx/kpeffectblursharpen.h b/kolourpaint/pixmapfx/kpeffectblursharpen.h new file mode 100644 index 00000000..3b12def1 --- /dev/null +++ b/kolourpaint/pixmapfx/kpeffectblursharpen.h @@ -0,0 +1,105 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_EFFECT_BLUR_SHARPEN_H +#define KP_EFFECT_BLUR_SHARPEN_H + + +#include + +#include + + +class QLabel; + +class KIntNumInput; + +class kpMainWindow; + + +class kpEffectBlurSharpenCommand : public kpColorEffectCommand +{ +public: + enum Type + { + None = 0, Blur, Sharpen + }; + + kpEffectBlurSharpenCommand (Type type, + double radius, double sigma, + int repeat, + bool actOnSelection, + kpMainWindow *mainWindow); + virtual ~kpEffectBlurSharpenCommand (); + + static QPixmap apply (const QPixmap &pixmap, + Type type, double radius, double sigma, + int repeat); + +protected: + virtual QPixmap applyColorEffect (const QPixmap &pixmap); + +protected: + Type m_type; + double m_radius, m_sigma; + int m_repeat; +}; + + +class kpEffectBlurSharpenWidget : public kpColorEffectWidget +{ +Q_OBJECT + +public: + kpEffectBlurSharpenWidget (bool actOnSelection, + kpMainWindow *mainWindow, + QWidget *parent, const char *name = 0); + virtual ~kpEffectBlurSharpenWidget (); + + virtual QString caption () const; + + virtual bool isNoOp () const; + virtual QPixmap applyColorEffect (const QPixmap &pixmap); + + virtual kpColorEffectCommand *createCommand () const; + +protected slots: + void slotUpdateTypeLabel (); + +protected: + kpEffectBlurSharpenCommand::Type type () const; + double radius () const; + double sigma () const; + int repeat () const; + + KIntNumInput *m_amountInput; + QLabel *m_typeLabel; +}; + + +#endif // KP_EFFECT_BLUR_SHARPEN_H diff --git a/kolourpaint/pixmapfx/kpeffectemboss.cpp b/kolourpaint/pixmapfx/kpeffectemboss.cpp new file mode 100644 index 00000000..e33f3a42 --- /dev/null +++ b/kolourpaint/pixmapfx/kpeffectemboss.cpp @@ -0,0 +1,228 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_EFFECT_EMBOSS 0 + + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + + +kpEffectEmbossCommand::kpEffectEmbossCommand (double radius, double sigma, + int repeat, + bool actOnSelection, + kpMainWindow *mainWindow) + : kpColorEffectCommand (i18n ("Emboss"), actOnSelection, mainWindow), + m_radius (radius), m_sigma (sigma), + m_repeat (repeat) +{ +} + +kpEffectEmbossCommand::~kpEffectEmbossCommand () +{ +} + + +// public static +QPixmap kpEffectEmbossCommand::apply (const QPixmap &pixmap, + double radius, double sigma, + int repeat) +{ +#if DEBUG_KP_EFFECT_EMBOSS + kdDebug () << "kpEffectEmbossCommand::apply()" + << " radius=" << radius + << " sigma=" << sigma + << " repeat=" << repeat + << ")" + << endl; +#endif + + // (KImageEffect::emboss() ignores mask) + QPixmap usePixmap = kpPixmapFX::pixmapWithDefinedTransparentPixels ( + pixmap, + Qt::white/*arbitrarily chosen*/); + + + QImage image = kpPixmapFX::convertToImage (usePixmap); + + for (int i = 0; i < repeat; i++) + { + image = KImageEffect::emboss (image, radius, sigma); + } + + QPixmap retPixmap = kpPixmapFX::convertToPixmap (image); + + + // KImageEffect::emboss() nukes mask - restore it + if (usePixmap.mask ()) + retPixmap.setMask (*usePixmap.mask ()); + + + return retPixmap; +} + +// protected virtual [base kpColorEffectCommand] +QPixmap kpEffectEmbossCommand::applyColorEffect (const QPixmap &pixmap) +{ + return apply (pixmap, m_radius, m_sigma, m_repeat); +} + + + +kpEffectEmbossWidget::kpEffectEmbossWidget (bool actOnSelection, + kpMainWindow *mainWindow, + QWidget *parent, const char *name) + : kpColorEffectWidget (actOnSelection, mainWindow, parent, name) +{ + QGridLayout *lay = new QGridLayout (this, 4, 2, marginHint (), spacingHint ()); + + +#if 0 + QLabel *amountLabel = new QLabel (i18n ("&Amount:"), this); + m_amountInput = new KIntNumInput (this); + m_amountInput->setRange (0, 10, 1/*step*/, true/*slider*/); + m_amountInput->setSpecialValueText (i18n ("None")); + + + amountLabel->setBuddy (m_amountInput); + + + lay->addWidget (amountLabel, 0, 0); + lay->addWidget (m_amountInput, 0, 1); + + lay->setColStretch (1, 1); + + + connect (m_amountInput, SIGNAL (valueChanged (int)), + this, SIGNAL (settingsChanged ())); +#endif + + m_enableCheckBox = new QCheckBox (i18n ("E&nable"), this); + + + lay->addMultiCellWidget (m_enableCheckBox, 0, 0, 0, 1, Qt::AlignCenter); + + + // (settingsChangedDelayed() instead of settingsChanged() so that the + // user can quickly press OK to apply effect to document directly and + // not have to wait for the also slow preview) + connect (m_enableCheckBox, SIGNAL (toggled (bool)), + this, SIGNAL (settingsChangedDelayed ())); +} + +kpEffectEmbossWidget::~kpEffectEmbossWidget () +{ +} + + +// public virtual [base kpColorEffectWidget] +QString kpEffectEmbossWidget::caption () const +{ + return QString::null; +} + + +// public virtual [base kpColorEffectWidget] +bool kpEffectEmbossWidget::isNoOp () const +{ + //return (m_amountInput->value () == 0); + return !m_enableCheckBox->isChecked (); +} + +// public virtual [base kpColorEffectWidget] +QPixmap kpEffectEmbossWidget::applyColorEffect (const QPixmap &pixmap) +{ + if (isNoOp ()) + return pixmap; + + return kpEffectEmbossCommand::apply (pixmap, radius (), sigma (), repeat ()); +} + +// public virtual [base kpColorEffectWidget] +kpColorEffectCommand *kpEffectEmbossWidget::createCommand () const +{ + return new kpEffectEmbossCommand (radius (), sigma (), repeat (), + m_actOnSelection, + m_mainWindow); +} + + +// The numbers that follow were picked by experimentation. +// I still have no idea what "radius" and "sigma" mean +// (even after reading the API). + +// protected +double kpEffectEmbossWidget::radius () const +{ + //if (m_amountInput->value () == 0) + // return 0; + + return 0; +} + + +// protected +double kpEffectEmbossWidget::sigma () const +{ +#if 0 + if (m_amountInput->value () == 0) + return 0; + + const double Min = 1; + const double Max = 1.2; + + return Min + + (m_amountInput->maxValue () - m_amountInput->value ()) * + (Max - Min) / + (m_amountInput->maxValue () - 1); +#endif + + return 1; +} + +// protected +int kpEffectEmbossWidget::repeat () const +{ + return 1; +} + + +#include diff --git a/kolourpaint/pixmapfx/kpeffectemboss.h b/kolourpaint/pixmapfx/kpeffectemboss.h new file mode 100644 index 00000000..0234627f --- /dev/null +++ b/kolourpaint/pixmapfx/kpeffectemboss.h @@ -0,0 +1,93 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_EFFECT_EMBOSS_H +#define KP_EFFECT_EMBOSS_H + + +#include + +#include + + +class QCheckBox; +class KIntNumInput; + +class kpMainWindow; + + +class kpEffectEmbossCommand : public kpColorEffectCommand +{ +public: + kpEffectEmbossCommand (double radius, double sigma, + int repeat, + bool actOnSelection, + kpMainWindow *mainWindow); + virtual ~kpEffectEmbossCommand (); + + static QPixmap apply (const QPixmap &pixmap, + double radius, double sigma, + int repeat); + +protected: + virtual QPixmap applyColorEffect (const QPixmap &pixmap); + +protected: + double m_radius, m_sigma; + int m_repeat; +}; + + +class kpEffectEmbossWidget : public kpColorEffectWidget +{ +Q_OBJECT + +public: + kpEffectEmbossWidget (bool actOnSelection, + kpMainWindow *mainWindow, + QWidget *parent, const char *name = 0); + virtual ~kpEffectEmbossWidget (); + + virtual QString caption () const; + + virtual bool isNoOp () const; + virtual QPixmap applyColorEffect (const QPixmap &pixmap); + + virtual kpColorEffectCommand *createCommand () const; + +protected: + double radius () const; + double sigma () const; + int repeat () const; + + //KIntNumInput *m_amountInput; + QCheckBox *m_enableCheckBox; +}; + + +#endif // KP_EFFECT_EMBOSS_H diff --git a/kolourpaint/pixmapfx/kpeffectflatten.cpp b/kolourpaint/pixmapfx/kpeffectflatten.cpp new file mode 100644 index 00000000..6a81bca0 --- /dev/null +++ b/kolourpaint/pixmapfx/kpeffectflatten.cpp @@ -0,0 +1,266 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_EFFECT_FLATTEN 0 + + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +// +// kpEffectFlattenCommand +// + +kpEffectFlattenCommand::kpEffectFlattenCommand (const QColor &color1, + const QColor &color2, + bool actOnSelection, + kpMainWindow *mainWindow) + : kpColorEffectCommand (i18n ("Flatten"), actOnSelection, mainWindow), + m_color1 (color1), m_color2 (color2) +{ +} + +kpEffectFlattenCommand::~kpEffectFlattenCommand () +{ +} + + +// public static +void kpEffectFlattenCommand::apply (QPixmap *destPixmapPtr, + const QColor &color1, const QColor &color2) +{ + if (!destPixmapPtr) + return; + + QImage image = kpPixmapFX::convertToImage (*destPixmapPtr); + apply (&image, color1, color2); + *destPixmapPtr = kpPixmapFX::convertToPixmap (image); +} + +// public static +QPixmap kpEffectFlattenCommand::apply (const QPixmap &pm, + const QColor &color1, const QColor &color2) +{ + QImage image = kpPixmapFX::convertToImage (pm); + apply (&image, color1, color2); + return kpPixmapFX::convertToPixmap (image); +} + +// public static +void kpEffectFlattenCommand::apply (QImage *destImagePtr, + const QColor &color1, const QColor &color2) +{ + if (!destImagePtr) + return; + + KImageEffect::flatten (*destImagePtr/*ref*/, color1, color2); +} + +// public static +QImage kpEffectFlattenCommand::apply (const QImage &img, + const QColor &color1, const QColor &color2) +{ + QImage retImage = img; + apply (&retImage, color1, color2); + return retImage; +} + + +// +// kpEffectFlattenCommand implements kpColorEffectCommand interface +// + +// protected virtual [base kpColorEffectCommand] +QPixmap kpEffectFlattenCommand::applyColorEffect (const QPixmap &pixmap) +{ + return apply (pixmap, m_color1, m_color2); +} + + +// +// kpEffectFlattenWidget +// + +// public static +// Don't initialise globally when we probably don't have a colour +// allocation context. This way, the colours aren't sometimes invalid +// (e.g. at 8-bit). +QColor kpEffectFlattenWidget::s_lastColor1; +QColor kpEffectFlattenWidget::s_lastColor2; + +kpEffectFlattenWidget::kpEffectFlattenWidget (bool actOnSelection, + kpMainWindow *mainWindow, + QWidget *parent, + const char *name) + : kpColorEffectWidget (actOnSelection, mainWindow, parent, name) +{ + if (!s_lastColor1.isValid () || !s_lastColor2.isValid ()) + { + KConfigGroupSaver cfgGroupSaver (KGlobal::config (), kpSettingsGroupFlattenEffect); + KConfigBase *cfg = cfgGroupSaver.config (); + + s_lastColor1 = cfg->readColorEntry (kpSettingFlattenEffectColor1); + if (!s_lastColor1.isValid ()) + s_lastColor1 = Qt::red; + + s_lastColor2 = cfg->readColorEntry (kpSettingFlattenEffectColor2); + if (!s_lastColor2.isValid ()) + s_lastColor2 = Qt::blue; + } + + + m_enableCheckBox = new QCheckBox (i18n ("E&nable"), this); + + QVBox *colorButtonContainer = new QVBox (this); + colorButtonContainer->setMargin (KDialog::marginHint () / 2); + colorButtonContainer->setSpacing (spacingHint ()); + m_color1Button = new KColorButton (s_lastColor1, colorButtonContainer); + m_color2Button = new KColorButton (s_lastColor2, colorButtonContainer); + + + m_color1Button->setEnabled (false); + m_color2Button->setEnabled (false); + + + QVBoxLayout *lay = new QVBoxLayout (this, marginHint (), spacingHint ()); + lay->addWidget (m_enableCheckBox); + lay->addWidget (colorButtonContainer); + + + connect (m_enableCheckBox, SIGNAL (toggled (bool)), + this, SLOT (slotEnableChanged (bool))); + + connect (m_color1Button, SIGNAL (changed (const QColor &)), + this, SIGNAL (settingsChanged ())); + connect (m_color2Button, SIGNAL (changed (const QColor &)), + this, SIGNAL (settingsChanged ())); +} + +kpEffectFlattenWidget::~kpEffectFlattenWidget () +{ + s_lastColor1 = color1 (); + s_lastColor2 = color2 (); + + + KConfigGroupSaver cfgGroupSaver (KGlobal::config (), kpSettingsGroupFlattenEffect); + KConfigBase *cfg = cfgGroupSaver.config (); + + cfg->writeEntry (kpSettingFlattenEffectColor1, s_lastColor1); + cfg->writeEntry (kpSettingFlattenEffectColor2, s_lastColor2); + cfg->sync (); +} + + +// public +QColor kpEffectFlattenWidget::color1 () const +{ + return m_color1Button->color (); +} + +// public +QColor kpEffectFlattenWidget::color2 () const +{ + return m_color2Button->color (); +} + + +// +// kpEffectFlattenWidget implements kpColorEffectWidget interface +// + +// public virtual [base kpColorEffectWidget] +QString kpEffectFlattenWidget::caption () const +{ + return i18n ("Colors"); +} + + +// public virtual [base kpColorEffectWidget] +bool kpEffectFlattenWidget::isNoOp () const +{ + return !m_enableCheckBox->isChecked (); +} + +// public virtual [base kpColorEffectWidget] +QPixmap kpEffectFlattenWidget::applyColorEffect (const QPixmap &pixmap) +{ +#if DEBUG_KP_EFFECT_FLATTEN + kdDebug () << "kpEffectFlattenWidget::applyColorEffect() nop=" + << isNoOp () << endl; +#endif + + if (isNoOp ()) + return pixmap; + + return kpEffectFlattenCommand::apply (pixmap, color1 (), color2 ()); +} + + +// public virtual [base kpColorEffectWidget] +kpColorEffectCommand *kpEffectFlattenWidget::createCommand () const +{ + return new kpEffectFlattenCommand (color1 (), color2 (), + m_actOnSelection, + m_mainWindow); +} + + +// protected slot: +void kpEffectFlattenWidget::slotEnableChanged (bool enable) +{ +#if DEBUG_KP_EFFECT_FLATTEN + kdDebug () << "kpEffectFlattenWidget::slotEnableChanged(" << enable + << ") enableButton=" << m_enableCheckBox->isChecked () + << endl; +#endif + + m_color1Button->setEnabled (enable); + m_color2Button->setEnabled (enable); + + emit settingsChanged (); +} + + +#include + diff --git a/kolourpaint/pixmapfx/kpeffectflatten.h b/kolourpaint/pixmapfx/kpeffectflatten.h new file mode 100644 index 00000000..79c9bbaf --- /dev/null +++ b/kolourpaint/pixmapfx/kpeffectflatten.h @@ -0,0 +1,115 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_EFFECT_FLATTEN_H +#define KP_EFFECT_FLATTEN_H + + +#include + +#include + + +class QCheckBox; +class QImage; + +class KColorButton; + +class kpMainWindow; + + +class kpEffectFlattenCommand : public kpColorEffectCommand +{ +public: + kpEffectFlattenCommand (const QColor &color1, const QColor &color2, + bool actOnSelection, + kpMainWindow *mainWindow); + virtual ~kpEffectFlattenCommand (); + + + static void apply (QPixmap *destPixmapPtr, + const QColor &color1, const QColor &color2); + static QPixmap apply (const QPixmap &pm, + const QColor &color1, const QColor &color2); + static void apply (QImage *destImagePtr, + const QColor &color1, const QColor &color2); + static QImage apply (const QImage &img, + const QColor &color1, const QColor &color2); + + + // + // kpColorEffectCommand interface + // + +protected: + virtual QPixmap applyColorEffect (const QPixmap &pixmap); + + QColor m_color1, m_color2; +}; + + +class kpEffectFlattenWidget : public kpColorEffectWidget +{ +Q_OBJECT + +public: + kpEffectFlattenWidget (bool actOnSelection, + kpMainWindow *mainWindow, + QWidget *parent, const char *name = 0); + virtual ~kpEffectFlattenWidget (); + + + static QColor s_lastColor1, s_lastColor2; + + + QColor color1 () const; + QColor color2 () const; + + + // + // kpColorEffectWidget interface + // + + virtual QString caption () const; + + virtual bool isNoOp () const; + virtual QPixmap applyColorEffect (const QPixmap &pixmap); + + virtual kpColorEffectCommand *createCommand () const; + +protected slots: + void slotEnableChanged (bool enable); + +protected: + QCheckBox *m_enableCheckBox; + KColorButton *m_color1Button, *m_color2Button; +}; + + + +#endif // KP_EFFECT_FLATTEN_H diff --git a/kolourpaint/pixmapfx/kpeffectinvert.cpp b/kolourpaint/pixmapfx/kpeffectinvert.cpp new file mode 100644 index 00000000..b9bb00a8 --- /dev/null +++ b/kolourpaint/pixmapfx/kpeffectinvert.cpp @@ -0,0 +1,315 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_EFFECT_INVERT 0 + + +#include + +#include +#include +#include +#include + +#include +#include + +#include + + +// +// kpEffectInvertCommand +// + +kpEffectInvertCommand::kpEffectInvertCommand (int channels, + bool actOnSelection, + kpMainWindow *mainWindow) + : kpColorEffectCommand (channels == RGB ? + i18n ("Invert Colors") : i18n ("Invert"), + actOnSelection, mainWindow), + m_channels (channels) +{ +} + +kpEffectInvertCommand::kpEffectInvertCommand (bool actOnSelection, + kpMainWindow *mainWindow) + : kpColorEffectCommand (i18n ("Invert Colors"), actOnSelection, mainWindow), + m_channels (RGB) +{ +} + +kpEffectInvertCommand::~kpEffectInvertCommand () +{ +} + + +// public static +void kpEffectInvertCommand::apply (QPixmap *destPixmapPtr, int channels) +{ + QImage image = kpPixmapFX::convertToImage (*destPixmapPtr); + apply (&image, channels); + *destPixmapPtr = kpPixmapFX::convertToPixmap (image); +} + +// public static +QPixmap kpEffectInvertCommand::apply (const QPixmap &pm, int channels) +{ + QImage image = kpPixmapFX::convertToImage (pm); + apply (&image, channels); + return kpPixmapFX::convertToPixmap (image); +} + +// public static +void kpEffectInvertCommand::apply (QImage *destImagePtr, int channels) +{ + QRgb mask = qRgba ((channels & Red) ? 0xFF : 0, + (channels & Green) ? 0xFF : 0, + (channels & Blue) ? 0xFF : 0, + 0/*don't invert alpha*/); +#if DEBUG_KP_EFFECT_INVERT + kdDebug () << "kpEffectInvertCommand::apply(channels=" << channels + << ") mask=" << (int *) mask + << endl; +#endif + + if (destImagePtr->depth () > 8) + { + #if 0 + // SYNC: TODO: Qt BUG - invertAlpha argument is inverted!!! + destImagePtr->invertPixels (true/*no invert alpha (Qt 3.2)*/); + #else + // Above version works for Qt 3.2 at least. + // But this version will always work (slower, though) and supports + // inverting particular channels. + for (int y = 0; y < destImagePtr->height (); y++) + { + for (int x = 0; x < destImagePtr->width (); x++) + { + destImagePtr->setPixel (x, y, destImagePtr->pixel (x, y) ^ mask); + } + } + #endif + } + else + { + for (int i = 0; i < destImagePtr->numColors (); i++) + { + destImagePtr->setColor (i, destImagePtr->color (i) ^ mask); + } + } +} + +// public static +QImage kpEffectInvertCommand::apply (const QImage &img, int channels) +{ + QImage retImage = img; + apply (&retImage, channels); + return retImage; +} + + +// +// kpEffectInvertCommand implements kpColorEffectCommand interface +// + +// protected virtual [base kpColorEffectCommand] +QPixmap kpEffectInvertCommand::applyColorEffect (const QPixmap &pixmap) +{ + return apply (pixmap, m_channels); +} + + +// +// kpEffectInvertWidget +// + +kpEffectInvertWidget::kpEffectInvertWidget (bool actOnSelection, + kpMainWindow *mainWindow, + QWidget *parent, + const char *name) + : kpColorEffectWidget (actOnSelection, mainWindow, parent, name) +{ + QVBoxLayout *topLevelLay = new QVBoxLayout (this, marginHint (), spacingHint ()); + + + QWidget *centerWidget = new QWidget (this); + topLevelLay->addWidget (centerWidget, 0/*stretch*/, Qt::AlignCenter); + + + QVBoxLayout *centerWidgetLay = new QVBoxLayout (centerWidget, + 0/*margin*/, + spacingHint ()); + + + m_redCheckBox = new QCheckBox (i18n ("&Red"), centerWidget); + m_greenCheckBox = new QCheckBox (i18n ("&Green"), centerWidget); + m_blueCheckBox = new QCheckBox (i18n ("&Blue"), centerWidget); + + QWidget *spaceWidget = new QWidget (centerWidget); + spaceWidget->setFixedSize (1, spacingHint ()); + + m_allCheckBox = new QCheckBox (i18n ("&All"), centerWidget); + + + m_redCheckBox->setChecked (false); + m_greenCheckBox->setChecked (false); + m_blueCheckBox->setChecked (false); + + m_allCheckBox->setChecked (false); + + + centerWidgetLay->addWidget (m_redCheckBox); + centerWidgetLay->addWidget (m_greenCheckBox); + centerWidgetLay->addWidget (m_blueCheckBox); + + centerWidgetLay->addWidget (spaceWidget); + + centerWidgetLay->addWidget (m_allCheckBox); + + + m_inSignalHandler = false; + connect (m_redCheckBox, SIGNAL (toggled (bool)), + this, SLOT (slotRGBCheckBoxToggled ())); + connect (m_greenCheckBox, SIGNAL (toggled (bool)), + this, SLOT (slotRGBCheckBoxToggled ())); + connect (m_blueCheckBox, SIGNAL (toggled (bool)), + this, SLOT (slotRGBCheckBoxToggled ())); + + connect (m_allCheckBox, SIGNAL (toggled (bool)), + this, SLOT (slotAllCheckBoxToggled ())); +} + +kpEffectInvertWidget::~kpEffectInvertWidget () +{ +} + + +// public +int kpEffectInvertWidget::channels () const +{ +#if DEBUG_KP_EFFECT_INVERT + kdDebug () << "kpEffectInvertWidget::channels()" + << " isChecked: r=" << m_redCheckBox->isChecked () + << " g=" << m_greenCheckBox->isChecked () + << " b=" << m_blueCheckBox->isChecked () + << endl; +#endif + + int channels = 0; + + + if (m_redCheckBox->isChecked ()) + channels |= kpEffectInvertCommand::Red; + + if (m_greenCheckBox->isChecked ()) + channels |= kpEffectInvertCommand::Green; + + if (m_blueCheckBox->isChecked ()) + channels |= kpEffectInvertCommand::Blue; + + +#if DEBUG_KP_EFFECT_INVERT + kdDebug () << "\treturning channels=" << (int *) channels << endl; +#endif + return channels; +} + + +// +// kpEffectInvertWidget implements kpColorEffectWidget interface +// + +// public virtual [base kpColorEffectWidget] +QString kpEffectInvertWidget::caption () const +{ + return i18n ("Channels"); +} + + +// public virtual [base kpColorEffectWidget] +bool kpEffectInvertWidget::isNoOp () const +{ + return (channels () == kpEffectInvertCommand::None); +} + +// public virtual [base kpColorEffectWidget] +QPixmap kpEffectInvertWidget::applyColorEffect (const QPixmap &pixmap) +{ + return kpEffectInvertCommand::apply (pixmap, channels ()); +} + + +// public virtual [base kpColorEffectWidget] +kpColorEffectCommand *kpEffectInvertWidget::createCommand () const +{ + return new kpEffectInvertCommand (channels (), + m_actOnSelection, + m_mainWindow); +} + + +// protected slots +void kpEffectInvertWidget::slotRGBCheckBoxToggled () +{ + if (m_inSignalHandler) + return; + + m_inSignalHandler = true; + + //blockSignals (true); + m_allCheckBox->setChecked (m_redCheckBox->isChecked () && + m_blueCheckBox->isChecked () && + m_greenCheckBox->isChecked ()); + //blockSignals (false); + + emit settingsChanged (); + + m_inSignalHandler = false; +} + +// protected slot +void kpEffectInvertWidget::slotAllCheckBoxToggled () +{ + if (m_inSignalHandler) + return; + + m_inSignalHandler = true; + + //blockSignals (true); + m_redCheckBox->setChecked (m_allCheckBox->isChecked ()); + m_greenCheckBox->setChecked (m_allCheckBox->isChecked ()); + m_blueCheckBox->setChecked (m_allCheckBox->isChecked ()); + //blockSignals (false); + + emit settingsChanged (); + + m_inSignalHandler = false; +} + + +#include + diff --git a/kolourpaint/pixmapfx/kpeffectinvert.h b/kolourpaint/pixmapfx/kpeffectinvert.h new file mode 100644 index 00000000..61d6cfda --- /dev/null +++ b/kolourpaint/pixmapfx/kpeffectinvert.h @@ -0,0 +1,130 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_EFFECT_INVERT_H +#define KP_EFFECT_INVERT_H + + +#include + + +class QCheckBox; +class QImage; + +class kpMainWindow; + + +class kpEffectInvertCommand : public kpColorEffectCommand +{ +public: + enum Channel + { + None = 0, + Red = 1, Green = 2, Blue = 4, + RGB = Red | Green | Blue + }; + + kpEffectInvertCommand (int channels, + bool actOnSelection, + kpMainWindow *mainWindow); + kpEffectInvertCommand (bool actOnSelection, + kpMainWindow *mainWindow); + virtual ~kpEffectInvertCommand (); + + + // + // Inverts the colours of each pixel in the given image. + // These functions differ from QImage::invertPixels() in the following ways: + // + // 1. for 8-bit images, it inverts the colours of the Colour Table + // (this means that you would get visually similar results to inversion + // at higher bit depths - rather than a "random-looking" inversion + // depending on the contents of the Colour Table) + // 2. never inverts the Alpha Buffer + // + + static void apply (QPixmap *destPixmapPtr, int channels = RGB); + static QPixmap apply (const QPixmap &pm, int channels = RGB); + static void apply (QImage *destImagePtr, int channels = RGB); + static QImage apply (const QImage &img, int channels = RGB); + + + // + // kpColorEffectCommand interface + // + +public: + virtual bool isInvertible () const { return true; } + +protected: + virtual QPixmap applyColorEffect (const QPixmap &pixmap); + + int m_channels; +}; + + +class kpEffectInvertWidget : public kpColorEffectWidget +{ +Q_OBJECT + +public: + kpEffectInvertWidget (bool actOnSelection, + kpMainWindow *mainWindow, + QWidget *parent, const char *name = 0); + virtual ~kpEffectInvertWidget (); + + + int channels () const; + + + // + // kpColorEffectWidget interface + // + + virtual QString caption () const; + + virtual bool isNoOp () const; + virtual QPixmap applyColorEffect (const QPixmap &pixmap); + + virtual kpColorEffectCommand *createCommand () const; + +protected slots: + void slotRGBCheckBoxToggled (); + void slotAllCheckBoxToggled (); + +protected: + QCheckBox *m_redCheckBox, *m_greenCheckBox, *m_blueCheckBox, + *m_allCheckBox; + + // blockSignals() didn't seem to work + bool m_inSignalHandler; +}; + + + +#endif // KP_EFFECT_INVERT_H diff --git a/kolourpaint/pixmapfx/kpeffectreducecolors.cpp b/kolourpaint/pixmapfx/kpeffectreducecolors.cpp new file mode 100644 index 00000000..b6eb7a42 --- /dev/null +++ b/kolourpaint/pixmapfx/kpeffectreducecolors.cpp @@ -0,0 +1,446 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_EFFECT_REDUCE_COLORS 0 + + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + + +QImage convertImageDepth (const QImage &image, int depth, bool dither) +{ +#if DEBUG_KP_EFFECT_REDUCE_COLORS + kdDebug () << "::convertImageDepth() changing image (w=" << image.width () + << ",h=" << image.height () + << ") depth from " << image.depth () + << " to " << depth + << " (dither=" << dither << ")" + << endl; +#endif + + if (image.isNull ()) + return image; + + if (depth == image.depth ()) + return image; + + +#if DEBUG_KP_EFFECT_REDUCE_COLORS && 0 + for (int y = 0; y < image.height (); y++) + { + for (int x = 0; x < image.width (); x++) + { + fprintf (stderr, " %08X", image.pixel (x, y)); + } + fprintf (stderr, "\n"); + } +#endif + + + // Hack around Qt's braindead QImage::convertDepth(1, ...) (with + // dithering off) which produces pathetic results with an image that + // only has 2 colours - sometimes it just gives a completely black + // result. Instead, we simply preserve the 2 colours. One use case + // is resaving a "colour monochrome" image (<= 2 colours but not + // necessarily black & white). + if (depth == 1 && !dither) + { + #if DEBUG_KP_EFFECT_REDUCE_COLORS + kdDebug () << "\tinvoking convert-to-depth 1 hack" << endl; + #endif + QRgb color0, color1; + bool color0Valid = false, color1Valid = false; + + bool moreThan2Colors = false; + + QImage monoImage (image.width (), image.height (), + 1/*depth*/, 2/*numColors*/, QImage::LittleEndian); + #if DEBUG_KP_EFFECT_REDUCE_COLORS + kdDebug () << "\t\tinitialising output image w=" << monoImage.width () + << ",h=" << monoImage.height () + << ",d=" << monoImage.depth () + << endl; + #endif + for (int y = 0; y < image.height (); y++) + { + for (int x = 0; x < image.width (); x++) + { + QRgb imagePixel = image.pixel (x, y); + + if (color0Valid && imagePixel == color0) + monoImage.setPixel (x, y, 0); + else if (color1Valid && imagePixel == color1) + monoImage.setPixel (x, y, 1); + else if (!color0Valid) + { + color0 = imagePixel; + color0Valid = true; + monoImage.setPixel (x, y, 0); + #if DEBUG_KP_EFFECT_REDUCE_COLORS + kdDebug () << "\t\t\tcolor0=" << (int *) color0 + << " at x=" << x << ",y=" << y << endl; + #endif + } + else if (!color1Valid) + { + color1 = imagePixel; + color1Valid = true; + monoImage.setPixel (x, y, 1); + #if DEBUG_KP_EFFECT_REDUCE_COLORS + kdDebug () << "\t\t\tcolor1=" << (int *) color1 + << " at x=" << x << ",y=" << y << endl; + #endif + } + else + { + #if DEBUG_KP_EFFECT_REDUCE_COLORS + kdDebug () << "\t\t\timagePixel=" << (int *) imagePixel + << " at x=" << x << ",y=" << y + << " moreThan2Colors - abort hack" << endl; + #endif + moreThan2Colors = true; + + // Dijkstra, this is clearer than double break'ing or + // a check in both loops + goto exit_loop; + } + } + } + exit_loop: + + if (!moreThan2Colors) + { + monoImage.setColor (0, color0Valid ? color0 : 0xFFFFFF); + monoImage.setColor (1, color1Valid ? color1 : 0x000000); + return monoImage; + } + } + + + QImage retImage = image.convertDepth (depth, + Qt::AutoColor | + (dither ? Qt::DiffuseDither : Qt::ThresholdDither) | + Qt::ThresholdAlphaDither | + (dither ? Qt::PreferDither : Qt::AvoidDither)); + +#if DEBUG_KP_EFFECT_REDUCE_COLORS && 0 + kdDebug () << "After colour reduction:" << endl; + for (int y = 0; y < image.height (); y++) + { + for (int x = 0; x < image.width (); x++) + { + fprintf (stderr, " %08X", image.pixel (x, y)); + } + fprintf (stderr, "\n"); + } +#endif + + return retImage; +} + + +// +// kpEffectReduceColorsCommand +// + +kpEffectReduceColorsCommand::kpEffectReduceColorsCommand (int depth, bool dither, + bool actOnSelection, + kpMainWindow *mainWindow) + : kpColorEffectCommand (commandName (depth, dither), actOnSelection, mainWindow), + m_depth (depth), m_dither (dither) +{ +} + +kpEffectReduceColorsCommand::~kpEffectReduceColorsCommand () +{ +} + + +// public +QString kpEffectReduceColorsCommand::commandName (int depth, int dither) const +{ + if (depth == 1) + { + if (dither) + return i18n ("Reduce to Monochrome (Dithered)"); + else + return i18n ("Reduce to Monochrome"); + } + else if (depth == 8) + { + if (dither) + return i18n ("Reduce to 256 Color (Dithered)"); + else + return i18n ("Reduce to 256 Color"); + } + else + { + return QString::null; + } +} + + +// public static +void kpEffectReduceColorsCommand::apply (QPixmap *destPixmapPtr, int depth, bool dither) +{ + if (!destPixmapPtr) + return; + + if (depth != 1 && depth != 8) + return; + + + QImage image = kpPixmapFX::convertToImage (*destPixmapPtr); + + + image = ::convertImageDepth (image, depth, dither); + + if (image.isNull ()) + return; + + + QPixmap pixmap = kpPixmapFX::convertToPixmap (image, false/*no dither*/); + + + // HACK: The above "image.convertDepth()" erases the Alpha Channel + // (at least for monochrome). + // qpixmap.html says "alpha masks on monochrome images are ignored." + // + // Put the mask back. + // + if (destPixmapPtr->mask ()) + pixmap.setMask (*destPixmapPtr->mask ()); + + *destPixmapPtr = pixmap; +} + +// public static +QPixmap kpEffectReduceColorsCommand::apply (const QPixmap &pm, int depth, bool dither) +{ + QPixmap ret = pm; + apply (&ret, depth, dither); + return ret; +} + + +// +// kpEffectReduceColorsCommand implements kpColorEffectCommand interface +// + +// protected virtual [base kpColorEffectCommand] +QPixmap kpEffectReduceColorsCommand::applyColorEffect (const QPixmap &pixmap) +{ + return apply (pixmap, m_depth, m_dither); +} + + +// +// kpEffectReduceColorsWidget +// + +kpEffectReduceColorsWidget::kpEffectReduceColorsWidget (bool actOnSelection, + kpMainWindow *mainWindow, + QWidget *parent, + const char *name) + : kpColorEffectWidget (actOnSelection, mainWindow, parent, name) +{ + QVBoxLayout *lay = new QVBoxLayout (this, marginHint (), spacingHint ()); + + + m_blackAndWhiteRadioButton = + new QRadioButton (i18n ("&Monochrome"), this); + + m_blackAndWhiteDitheredRadioButton = + new QRadioButton (i18n ("Mo&nochrome (dithered)"), this); + + m_8BitRadioButton = new QRadioButton (i18n ("256 co&lor"), this); + + m_8BitDitheredRadioButton = new QRadioButton (i18n ("256 colo&r (dithered)"), this); + + m_24BitRadioButton = new QRadioButton (i18n ("24-&bit color"), this); + + + QButtonGroup *buttonGroup = new QButtonGroup (this); + buttonGroup->hide (); + + buttonGroup->insert (m_blackAndWhiteRadioButton); + buttonGroup->insert (m_blackAndWhiteDitheredRadioButton); + buttonGroup->insert (m_8BitRadioButton); + buttonGroup->insert (m_8BitDitheredRadioButton); + buttonGroup->insert (m_24BitRadioButton); + + + const int screenDepth = QPixmap::defaultDepth (); +#if DEBUG_KP_EFFECT_REDUCE_COLORS + kdDebug () << "kpEffectReduceColorsWidget:: screenDepth=" + << screenDepth + << endl; +#endif + + // Note that everything is disabled for a 1-bit screen since there + // would be no effect. I won't support 2-bit or 4-bit screens either :) + m_blackAndWhiteRadioButton->setEnabled (screenDepth >= 8); + m_blackAndWhiteDitheredRadioButton->setEnabled (screenDepth >= 8); + m_8BitRadioButton->setEnabled (screenDepth >= 8); + // (not enabled if screenDepth==8 as m_8BitRadioButton already serves + // as NOP default) + m_8BitDitheredRadioButton->setEnabled (screenDepth > 8); + // (not "screenDepth >= 24" as we need a NOP default for 15/16-bit + // screens) + m_24BitRadioButton->setEnabled (screenDepth > 8); + + + m_defaultRadioButton = 0; + + if (m_24BitRadioButton->isEnabled ()) + { + #if DEBUG_KP_EFFECT_REDUCE_COLORS + kdDebug () << "\tdefault is 24-bit button" << endl; + #endif + m_defaultRadioButton = m_24BitRadioButton; + } + else if (m_8BitRadioButton->isEnabled ()) + { + #if DEBUG_KP_EFFECT_REDUCE_COLORS + kdDebug () << "\tdefault is 8-bit button" << endl; + #endif + m_defaultRadioButton = m_8BitRadioButton; + } + else + { + #if DEBUG_KP_EFFECT_REDUCE_COLORS + kdDebug () << "\tuser must have a 1-bit screen - no default" << endl; + #endif + } + + + if (m_defaultRadioButton) + m_defaultRadioButton->setChecked (true); + + + lay->addWidget (m_blackAndWhiteRadioButton); + lay->addWidget (m_blackAndWhiteDitheredRadioButton); + lay->addWidget (m_8BitRadioButton); + lay->addWidget (m_8BitDitheredRadioButton); + lay->addWidget (m_24BitRadioButton); + + + connect (m_blackAndWhiteRadioButton, SIGNAL (toggled (bool)), + this, SIGNAL (settingsChanged ())); + connect (m_blackAndWhiteDitheredRadioButton, SIGNAL (toggled (bool)), + this, SIGNAL (settingsChanged ())); + connect (m_8BitRadioButton, SIGNAL (toggled (bool)), + this, SIGNAL (settingsChanged ())); + connect (m_8BitDitheredRadioButton, SIGNAL (toggled (bool)), + this, SIGNAL (settingsChanged ())); + connect (m_24BitRadioButton, SIGNAL (toggled (bool)), + this, SIGNAL (settingsChanged ())); +} + +kpEffectReduceColorsWidget::~kpEffectReduceColorsWidget () +{ +} + + +// public +int kpEffectReduceColorsWidget::depth () const +{ + if (m_blackAndWhiteRadioButton->isChecked () || + m_blackAndWhiteDitheredRadioButton->isChecked ()) + { + return 1; + } + else if (m_8BitRadioButton->isChecked () || + m_8BitDitheredRadioButton->isChecked ()) + { + return 8; + } + else if (m_24BitRadioButton->isChecked ()) + { + return 24; + } + else + { + return 0; + } +} + +// public +bool kpEffectReduceColorsWidget::dither () const +{ + return (m_blackAndWhiteDitheredRadioButton->isChecked () || + m_8BitDitheredRadioButton->isChecked ()); +} + + +// +// kpEffectReduceColorsWidget implements kpColorEffectWidget interface +// + +// public virtual [base kpColorEffectWidget] +QString kpEffectReduceColorsWidget::caption () const +{ + return i18n ("Reduce To"); +} + + +// public virtual [base kpColorEffectWidget] +bool kpEffectReduceColorsWidget::isNoOp () const +{ + return (!m_defaultRadioButton || m_defaultRadioButton->isChecked ()); +} + +// public virtual [base kpColorEffectWidget] +QPixmap kpEffectReduceColorsWidget::applyColorEffect (const QPixmap &pixmap) +{ + return kpEffectReduceColorsCommand::apply (pixmap, depth (), dither ()); +} + + +// public virtual [base kpColorEffectWidget] +kpColorEffectCommand *kpEffectReduceColorsWidget::createCommand () const +{ + return new kpEffectReduceColorsCommand (depth (), dither (), + m_actOnSelection, + m_mainWindow); +} + + +#include + diff --git a/kolourpaint/pixmapfx/kpeffectreducecolors.h b/kolourpaint/pixmapfx/kpeffectreducecolors.h new file mode 100644 index 00000000..a14cffc7 --- /dev/null +++ b/kolourpaint/pixmapfx/kpeffectreducecolors.h @@ -0,0 +1,110 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_EFFECT_REDUCE_COLORS_H +#define KP_EFFECT_REDUCE_COLORS_H + + +#include + + +class QRadioButton; +class QImage; + +class kpMainWindow; + + +QImage convertImageDepth (const QImage &image, int depth, bool dither); + + +class kpEffectReduceColorsCommand : public kpColorEffectCommand +{ +public: + // depth must be 1 or 8 + kpEffectReduceColorsCommand (int depth, bool dither, + bool actOnSelection, + kpMainWindow *mainWindow); + virtual ~kpEffectReduceColorsCommand (); + + QString commandName (int depth, int dither) const; + + // (always preserves mask) + static void apply (QPixmap *destPixmapPtr, int depth, bool dither); + static QPixmap apply (const QPixmap &pm, int depth, bool dither); + + + // + // kpColorEffectCommand interface + // + +protected: + virtual QPixmap applyColorEffect (const QPixmap &pixmap); + + int m_depth; + bool m_dither; +}; + + +class kpEffectReduceColorsWidget : public kpColorEffectWidget +{ +Q_OBJECT + +public: + kpEffectReduceColorsWidget (bool actOnSelection, + kpMainWindow *mainWindow, + QWidget *parent, const char *name = 0); + virtual ~kpEffectReduceColorsWidget (); + + + int depth () const; + bool dither () const; + + + // + // kpColorEffectWidget interface + // + + virtual QString caption () const; + + virtual bool isNoOp () const; + virtual QPixmap applyColorEffect (const QPixmap &pixmap); + + virtual kpColorEffectCommand *createCommand () const; + +protected: + QRadioButton *m_blackAndWhiteRadioButton, + *m_blackAndWhiteDitheredRadioButton, + *m_8BitRadioButton, + *m_8BitDitheredRadioButton, + *m_24BitRadioButton; + QRadioButton *m_defaultRadioButton; +}; + + + +#endif // KP_EFFECT_REDUCE_COLORS_H diff --git a/kolourpaint/pixmapfx/kpeffectsdialog.cpp b/kolourpaint/pixmapfx/kpeffectsdialog.cpp new file mode 100644 index 00000000..666f81cf --- /dev/null +++ b/kolourpaint/pixmapfx/kpeffectsdialog.cpp @@ -0,0 +1,369 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_EFFECTS_DIALOG 0 + + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// protected static +int kpEffectsDialog::s_lastWidth = 640; +int kpEffectsDialog::s_lastHeight = 620; + + +kpEffectsDialog::kpEffectsDialog (bool actOnSelection, + kpMainWindow *parent, + const char *name) + : kpToolPreviewDialog (kpToolPreviewDialog::Preview, + true/*reserve top row*/, + QString::null/*caption*/, + QString::null/*afterActionText (no Dimensions Group Box)*/, + actOnSelection, + parent, + name), + m_delayedUpdateTimer (new QTimer (this)), + m_effectsComboBox (0), + m_settingsGroupBox (0), + m_settingsLayout (0), + m_colorEffectWidget (0) +{ +#if DEBUG_KP_EFFECTS_DIALOG + kdDebug () << "kpEffectsDialog::kpEffectsDialog()" << endl; +#endif + + if (actOnSelection) + setCaption (i18n ("More Image Effects (Selection)")); + else + setCaption (i18n ("More Image Effects")); + + + connect (m_delayedUpdateTimer, SIGNAL (timeout ()), + this, SLOT (slotUpdateWithWaitCursor ())); + + + QHBox *effectContainer = new QHBox (mainWidget ()); + effectContainer->setSpacing (spacingHint () * 4 + /*need more space for QGroupBox titles*/); + effectContainer->setMargin (0); + + QLabel *label = new QLabel (i18n ("&Effect:"), effectContainer); + + m_effectsComboBox = new KComboBox (effectContainer); + m_effectsComboBox->insertItem (i18n ("Balance")); + m_effectsComboBox->insertItem (i18n ("Emboss")); + m_effectsComboBox->insertItem (i18n ("Flatten")); + m_effectsComboBox->insertItem (i18n ("Invert")); + m_effectsComboBox->insertItem (i18n ("Reduce Colors")); + m_effectsComboBox->insertItem (i18n ("Soften & Sharpen")); + + label->setBuddy (m_effectsComboBox); + effectContainer->setStretchFactor (m_effectsComboBox, 1); + + addCustomWidgetToFront (effectContainer); + + + m_settingsGroupBox = new QGroupBox (mainWidget ()); + m_settingsLayout = new QVBoxLayout (m_settingsGroupBox, + marginHint () * 2, + spacingHint ()); + addCustomWidgetToBack (m_settingsGroupBox); + + + connect (m_effectsComboBox, SIGNAL (activated (int)), + this, SLOT (selectEffect (int))); + selectEffect (0); + + + resize (s_lastWidth, s_lastHeight); + + +#if DEBUG_KP_EFFECTS_DIALOG + kdDebug () << "\tabout to slotUpdate()" << endl; +#endif + slotUpdate (); +} + +kpEffectsDialog::~kpEffectsDialog () +{ + s_lastWidth = width (); + s_lastHeight = height (); +} + + +// public virtual [base kpToolPreviewDialog] +bool kpEffectsDialog::isNoOp () const +{ + if (!m_colorEffectWidget) + return true; + + return m_colorEffectWidget->isNoOp (); +} + +// public +kpColorEffectCommand *kpEffectsDialog::createCommand () const +{ + if (!m_colorEffectWidget) + return 0; + + return m_colorEffectWidget->createCommand (); +} + + +// protected virtual [base kpToolPreviewDialog] +QSize kpEffectsDialog::newDimensions () const +{ + kpDocument *doc = document (); + if (!doc) + return QSize (); + + return QSize (doc->width (m_actOnSelection), + doc->height (m_actOnSelection)); +} + +// protected virtual [base kpToolPreviewDialog] +QPixmap kpEffectsDialog::transformPixmap (const QPixmap &pixmap, + int targetWidth, int targetHeight) const +{ + QPixmap pixmapWithEffect; + + if (m_colorEffectWidget) + pixmapWithEffect = m_colorEffectWidget->applyColorEffect (pixmap); + else + pixmapWithEffect = pixmap; + + return kpPixmapFX::scale (pixmapWithEffect, targetWidth, targetHeight); +} + + +// public +int kpEffectsDialog::selectedEffect () const +{ + return m_effectsComboBox->currentItem (); +} + +// public slot +void kpEffectsDialog::selectEffect (int which) +{ +#if DEBUG_KP_EFFECTS_DIALOG + kdDebug () << "kpEffectsDialog::selectEffect(" << which << ")" << endl; +#endif + + if (which < 0 || + which >= m_effectsComboBox->count ()) + { + return; + } + + if (which != m_effectsComboBox->currentItem ()) + m_effectsComboBox->setCurrentItem (which); + + + delete m_colorEffectWidget; + m_colorEffectWidget = 0; + + + m_settingsGroupBox->setCaption (QString::null); + +#define CREATE_EFFECT_WIDGET(name) \ + m_colorEffectWidget = new name (m_actOnSelection, \ + m_mainWindow, \ + m_settingsGroupBox) + switch (which) + { + case 0: + CREATE_EFFECT_WIDGET (kpEffectBalanceWidget); + break; + + case 1: + CREATE_EFFECT_WIDGET (kpEffectEmbossWidget); + break; + + case 2: + CREATE_EFFECT_WIDGET (kpEffectFlattenWidget); + break; + + case 3: + CREATE_EFFECT_WIDGET (kpEffectInvertWidget); + break; + + case 4: + CREATE_EFFECT_WIDGET (kpEffectReduceColorsWidget); + break; + + case 5: + CREATE_EFFECT_WIDGET (kpEffectBlurSharpenWidget); + break; + } +#undef CREATE_EFFECT_WIDGET + + + if (m_colorEffectWidget) + { + #if DEBUG_KP_EFFECTS_DIALOG + kdDebug () << "\twidget exists for effect #" << endl; + #endif + m_settingsGroupBox->setTitle (m_colorEffectWidget->caption ()); + + + // Don't resize the preview when showing the widget: + // TODO: actually work + + QSize previewGroupBoxMinSize = m_previewGroupBox->minimumSize (); + QSize previewGroupBoxMaxSize = m_previewGroupBox->maximumSize (); + QLayout::ResizeMode previewGroupBoxResizeMode = + m_previewGroupBox->layout () ? + m_previewGroupBox->layout ()->resizeMode () : + QLayout::Auto; + #if DEBUG_KP_EFFECTS_DIALOG + kdDebug () << "\tpreviewGroupBox: minSize=" << previewGroupBoxMinSize + << " maxSize=" << previewGroupBoxMaxSize + << " size=" << m_previewGroupBox->size () + << " layout=" << m_previewGroupBox->layout () + << " resizeMode=" << previewGroupBoxResizeMode + << endl; + #endif + + if (m_previewGroupBox->layout ()) + m_previewGroupBox->layout ()->setResizeMode (QLayout::FreeResize); + #if DEBUG_KP_EFFECTS_DIALOG + kdDebug () << "\tafter set resizeMode, previewGroupBox.size=" + << m_previewGroupBox->size () << endl; + #endif + m_previewGroupBox->setFixedSize (m_previewGroupBox->size ()); + #if DEBUG_KP_EFFECTS_DIALOG + kdDebug () << "\tafter set fixedSize, previewGroupBox.size=" + << m_previewGroupBox->size () << endl; + #endif + + // Show widget + m_settingsLayout->addWidget (m_colorEffectWidget); + #if DEBUG_KP_EFFECTS_DIALOG + kdDebug () << "\tafter addWidget, previewGroupBox.size=" + << m_previewGroupBox->size () << endl; + #endif + m_colorEffectWidget->show (); + #if DEBUG_KP_EFFECTS_DIALOG + kdDebug () << "\tafter addWidget show, previewGroupBox.size=" + << m_previewGroupBox->size () << endl; + #endif + + m_previewGroupBox->setMinimumSize (previewGroupBoxMinSize); + m_previewGroupBox->setMaximumSize (previewGroupBoxMaxSize); + #if DEBUG_KP_EFFECTS_DIALOG + kdDebug () << "\tafter set fixedSize, previewGroupBox.size=" + << m_previewGroupBox->size () << endl; + #endif + if (m_previewGroupBox->layout ()) + m_previewGroupBox->layout ()->setResizeMode (previewGroupBoxResizeMode); + #if DEBUG_KP_EFFECTS_DIALOG + kdDebug () << "\tafter restore resizeMode, previewGroupBox.size=" + << m_previewGroupBox->size () << endl; + #endif + + + connect (m_colorEffectWidget, SIGNAL (settingsChangedNoWaitCursor ()), + this, SLOT (slotUpdate ())); + connect (m_colorEffectWidget, SIGNAL (settingsChanged ()), + this, SLOT (slotUpdateWithWaitCursor ())); + connect (m_colorEffectWidget, SIGNAL (settingsChangedDelayed ()), + this, SLOT (slotDelayedUpdate ())); + slotUpdateWithWaitCursor (); + #if DEBUG_KP_EFFECTS_DIALOG + kdDebug () << "\tafter slotUpdateWithWaitCursor, previewGroupBox.size=" + << m_previewGroupBox->size () << endl; + #endif + } +} + + +// protected slot virtual [base kpToolPreviewDialog] +void kpEffectsDialog::slotUpdate () +{ +#if DEBUG_KP_EFFECTS_DIALOG + kdDebug () << "kpEffectsDialog::slotUpdate()" + << " timerActive=" << m_delayedUpdateTimer->isActive () + << endl; +#endif + + m_delayedUpdateTimer->stop (); + + kpToolPreviewDialog::slotUpdate (); +} + +// protected slot virtual [base kpToolPreviewDialog] +void kpEffectsDialog::slotUpdateWithWaitCursor () +{ +#if DEBUG_KP_EFFECTS_DIALOG + kdDebug () << "kpEffectsDialog::slotUpdateWithWaitCursor()" + << " timerActive=" << m_delayedUpdateTimer->isActive () + << endl; +#endif + + m_delayedUpdateTimer->stop (); + + kpToolPreviewDialog::slotUpdateWithWaitCursor (); +} + + +// protected slot +void kpEffectsDialog::slotDelayedUpdate () +{ +#if DEBUG_KP_EFFECTS_DIALOG + kdDebug () << "kpEffectsDialog::slotDelayedUpdate()" + << " timerActive=" << m_delayedUpdateTimer->isActive () + << endl; +#endif + m_delayedUpdateTimer->stop (); + + m_delayedUpdateTimer->start (400/*ms*/, true/*single shot*/); +} + + +#include diff --git a/kolourpaint/pixmapfx/kpeffectsdialog.h b/kolourpaint/pixmapfx/kpeffectsdialog.h new file mode 100644 index 00000000..fe7265cc --- /dev/null +++ b/kolourpaint/pixmapfx/kpeffectsdialog.h @@ -0,0 +1,90 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_EFFECTS_DIALOG_H +#define KP_EFFECTS_DIALOG_H + + +#include + + +class QGroupBox; +class QStringList; +class QTimer; +class QVBoxLayout; + +class KComboBox; + +class kpColorEffectCommand; +class kpColorEffectWidget; +class kpMainWindow; + + +class kpEffectsDialog : public kpToolPreviewDialog +{ +Q_OBJECT + +public: + kpEffectsDialog (bool actOnSelection, + kpMainWindow *parent, + const char *name = 0); + virtual ~kpEffectsDialog (); + + virtual bool isNoOp () const; + kpColorEffectCommand *createCommand () const; + +protected: + virtual QSize newDimensions () const; + virtual QPixmap transformPixmap (const QPixmap &pixmap, + int targetWidth, int targetHeight) const; + +public: + int selectedEffect () const; +public slots: + void selectEffect (int which); + +protected slots: + virtual void slotUpdate (); + virtual void slotUpdateWithWaitCursor (); + + void slotDelayedUpdate (); + +protected: + static int s_lastWidth, s_lastHeight; + + QTimer *m_delayedUpdateTimer; + + KComboBox *m_effectsComboBox; + QGroupBox *m_settingsGroupBox; + QVBoxLayout *m_settingsLayout; + + kpColorEffectWidget *m_colorEffectWidget; +}; + + +#endif // KP_EFFECTS_DIALOG_H diff --git a/kolourpaint/pixmapfx/kpfloodfill.cpp b/kolourpaint/pixmapfx/kpfloodfill.cpp new file mode 100644 index 00000000..602e8acf --- /dev/null +++ b/kolourpaint/pixmapfx/kpfloodfill.cpp @@ -0,0 +1,362 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_FLOOD_FILL 0 + + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + + +kpFloodFill::kpFloodFill (QPixmap *pixmap, int x, int y, + const kpColor &color, int processedColorSimilarity) + : m_pixmapPtr (pixmap), m_x (x), m_y (y), + m_color (color), m_processedColorSimilarity (processedColorSimilarity), + m_initState (0) +{ +} + +kpFloodFill::~kpFloodFill () +{ +} + + +// private +int kpFloodFill::fillLinesListSize (const QValueList &fillLines) const +{ + return (fillLines.size () * kpFloodFill::FillLine::size ()); +} + +// public +int kpFloodFill::size () const +{ + int fillLinesCacheSize = 0; + for (QValueVector < QValueList >::const_iterator it = m_fillLinesCache.begin (); + it != m_fillLinesCache.end (); + it++) + { + fillLinesCacheSize += fillLinesListSize (*it); + } + + return fillLinesListSize (m_fillLines) + + kpPixmapFX::imageSize (m_image) + + fillLinesCacheSize; +} + + +QRect kpFloodFill::boundingRect () const +{ + return m_boundingRect; +} + +bool kpFloodFill::fill () +{ + if (m_initState < 2 && !prepare ()) + { + kdError () << "kpFloodFill:fill() could not prepare()!" << endl; + return false; + } + + // not trying to do a NOP fill + if (m_boundingRect.isValid ()) + { + QApplication::setOverrideCursor (Qt::waitCursor); + + QPainter painter, maskPainter; + QBitmap maskBitmap; + + if (m_pixmapPtr->mask () || m_color.isTransparent ()) + { + maskBitmap = kpPixmapFX::getNonNullMask (*m_pixmapPtr); + maskPainter.begin (&maskBitmap); + maskPainter.setPen (m_color.maskColor ()); + } + + if (m_color.isOpaque ()) + { + painter.begin (m_pixmapPtr); + painter.setPen (m_color.toQColor ()); + } + + const QValueList ::ConstIterator fillLinesEnd = m_fillLines.end (); + for (QValueList ::ConstIterator it = m_fillLines.begin (); + it != fillLinesEnd; + it++) + { + QPoint p1 = QPoint ((*it).m_x1, (*it).m_y); + QPoint p2 = QPoint ((*it).m_x2, (*it).m_y); + + if (painter.isActive ()) + painter.drawLine (p1, p2); + + if (maskPainter.isActive ()) + maskPainter.drawLine (p1, p2); + } + + if (painter.isActive ()) + painter.end (); + + if (maskPainter.isActive ()) + maskPainter.end (); + + if (!maskBitmap.isNull ()) + m_pixmapPtr->setMask (maskBitmap); + + QApplication::restoreOverrideCursor (); + } + else + { + #if DEBUG_KP_FLOOD_FILL && 1 + kdDebug () << "kpFloodFill::fill() performing NOP fill" << endl; + #endif + } + + return true; +} + +bool kpFloodFill::prepareColorToChange () +{ +#if DEBUG_KP_FLOOD_FILL && 1 + kdDebug () << "kpFloodFill::prepareColorToChange" << endl; +#endif + + m_colorToChange = kpPixmapFX::getColorAtPixel (*m_pixmapPtr, QPoint (m_x, m_y)); + + if (m_colorToChange.isOpaque ()) + { + #if DEBUG_KP_FLOOD_FILL && 1 + kdDebug () << "\tcolorToChange: r=" << m_colorToChange.red () + << ", b=" << m_colorToChange.blue () + << ", g=" << m_colorToChange.green () + << endl; + #endif + } + else + { + #if DEBUG_KP_FLOOD_FILL && 1 + kdDebug () << "\tcolorToChange: transparent" << endl; + #endif + } + + m_initState = 1; + return true; +} + +// Derived from the zSprite2 Graphics Engine + +bool kpFloodFill::prepare () +{ +#if DEBUG_KP_FLOOD_FILL && 1 + kdDebug () << "kpFloodFill::prepare()" << endl; +#endif + m_boundingRect = QRect (); + + if (m_initState < 1 && !prepareColorToChange ()) + { + kdError () << "kpFloodFill:prepare() could not prepareColorToChange()!" << endl; + return false; + } + +#if DEBUG_KP_FLOOD_FILL && 1 + kdDebug () << "\tperforming NOP check" << endl; +#endif + + // get the color we need to replace + if (m_processedColorSimilarity == 0 && m_color == m_colorToChange) + { + // need to do absolutely nothing (this is a significant optimisation + // for people who randomly click a lot over already-filled areas) + m_initState = 2; // sync with all "return true"'s + return true; + } + +#if DEBUG_KP_FLOOD_FILL && 1 + kdDebug () << "\tconverting to image" << endl; +#endif + + // is this the only way to read pixels? + m_image = kpPixmapFX::convertToImage (*m_pixmapPtr); + if (m_image.isNull ()) + { + kdError () << "kpFloodFill::prepare() could not convert to QImage" << endl; + return false; + } + +#if DEBUG_KP_FLOOD_FILL && 1 + kdDebug () << "\tcreating fillLinesCache" << endl; +#endif + + // ready cache + m_fillLinesCache.resize (m_pixmapPtr->height ()); + +#if DEBUG_KP_FLOOD_FILL && 1 + kdDebug () << "\tcreating fill lines" << endl; +#endif + + // draw initial line + addLine (m_y, findMinX (m_y, m_x), findMaxX (m_y, m_x)); + + for (QValueList ::ConstIterator it = m_fillLines.begin (); + it != m_fillLines.end (); + it++) + { + #if DEBUG_KP_FLOOD_FILL && 0 + kdDebug () << "Expanding from y=" << (*it).m_y + << " x1=" << (*it).m_x1 + << " x2=" << (*it).m_x2 + << endl; + #endif + + // make more lines above and below current line + findAndAddLines (*it, -1); + findAndAddLines (*it, +1); + } + +#if DEBUG_KP_FLOOD_FILL && 1 + kdDebug () << "\tfinalising memory usage" << endl; +#endif + + // finalize memory usage + m_image.reset (); + m_fillLinesCache.clear (); + + m_initState = 2; // sync with all "return true"'s + return true; +} + +void kpFloodFill::addLine (int y, int x1, int x2) +{ +#if DEBUG_KP_FLOOD_FILL && 0 + kdDebug () << "kpFillCommand::fillAddLine (" << y << "," << x1 << "," << x2 << ")" << endl; +#endif + + m_fillLines.append (FillLine (y, x1, x2)); + m_fillLinesCache [y].append (FillLine (y /* OPT */, x1, x2)); + m_boundingRect = m_boundingRect.unite (QRect (QPoint (x1, y), QPoint (x2, y))); +} + +kpColor kpFloodFill::pixelColor (int x, int y, bool *beenHere) const +{ + if (beenHere) + *beenHere = false; + + if (y >= (int) m_fillLinesCache.count ()) + { + kdError () << "kpFloodFill::pixelColor(" + << x << "," + << y << ") y out of range=" << m_pixmapPtr->height () << endl; + return kpColor::invalid; + } + + const QValueList ::ConstIterator theEnd = m_fillLinesCache [y].end (); + for (QValueList ::ConstIterator it = m_fillLinesCache [y].begin (); + it != theEnd; + it++) + { + if (x >= (*it).m_x1 && x <= (*it).m_x2) + { + if (beenHere) + *beenHere = true; + return m_color; + } + } + + return kpPixmapFX::getColorAtPixel (m_image, QPoint (x, y)); +} + +bool kpFloodFill::shouldGoTo (int x, int y) const +{ + bool beenThere; + const kpColor col = pixelColor (x, y, &beenThere); + + return (!beenThere && col.isSimilarTo (m_colorToChange, m_processedColorSimilarity)); +} + +void kpFloodFill::findAndAddLines (const FillLine &fillLine, int dy) +{ + // out of bounds? + if (fillLine.m_y + dy < 0 || fillLine.m_y + dy >= m_pixmapPtr->height ()) + return; + + for (int xnow = fillLine.m_x1; xnow <= fillLine.m_x2; xnow++) + { + // At current position, right colour? + if (shouldGoTo (xnow, fillLine.m_y + dy)) + { + // Find minimum and maximum x values + int minxnow = findMinX (fillLine.m_y + dy, xnow); + int maxxnow = findMaxX (fillLine.m_y + dy, xnow); + + // Draw line + addLine (fillLine.m_y + dy, minxnow, maxxnow); + + // Move x pointer + xnow = maxxnow; + } + } +} + +// finds the minimum x value at a certain line to be filled +int kpFloodFill::findMinX (int y, int x) const +{ + for (;;) + { + if (x < 0) + return 0; + + if (shouldGoTo (x, y)) + x--; + else + return x + 1; + } +} + +// finds the maximum x value at a certain line to be filled +int kpFloodFill::findMaxX (int y, int x) const +{ + for (;;) + { + if (x > m_pixmapPtr->width () - 1) + return m_pixmapPtr->width () - 1; + + if (shouldGoTo (x, y)) + x++; + else + return x - 1; + } +} diff --git a/kolourpaint/pixmapfx/kpfloodfill.h b/kolourpaint/pixmapfx/kpfloodfill.h new file mode 100644 index 00000000..5c0d8001 --- /dev/null +++ b/kolourpaint/pixmapfx/kpfloodfill.h @@ -0,0 +1,106 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kpfloodfill_h__ +#define __kpfloodfill_h__ + +#include +#include +#include + +#include + +class QPixmap; + +class kpFloodFill +{ +public: + kpFloodFill (QPixmap *pixmap, int x, int y, + const kpColor &color, + int processedColorSimilarity); + ~kpFloodFill (); + + int size () const; + + kpColor color () const { return m_color; } + int processedColorSimilarity () const { return m_processedColorSimilarity; } + + // you should call [prepareColorToChange(),[prepare(),[fill()]]] + bool prepareColorToChange (); + + // (only valid after prepareColorToChange()) + kpColor colorToChange () const { return m_colorToChange; }; + + bool prepare (); + QRect boundingRect () const; // only valid after prepare() + + bool fill (); + +private: + QPixmap *m_pixmapPtr; + int m_x, m_y; + kpColor m_color; + int m_processedColorSimilarity; + + int m_initState; + + QRect m_boundingRect; + + struct FillLine + { + FillLine (int y = -1, int x1 = -1, int x2 = -1) + : m_y (y), m_x1 (x1), m_x2 (x2) + { + } + + static int size () + { + return sizeof (FillLine); + } + + int m_y, m_x1, m_x2; + }; + + int fillLinesListSize (const QValueList &fillLines) const; + + void addLine (int y, int x1, int x2); + kpColor pixelColor (int x, int y, bool *beenHere = 0) const; + bool shouldGoTo (int x, int y) const; + void findAndAddLines (const FillLine &fillLine, int dy); + int findMinX (int y, int x) const; + int findMaxX (int y, int x) const; + + QValueList m_fillLines; + + // Init info + QImage m_image; + QValueVector < QValueList > m_fillLinesCache; + kpColor m_colorToChange; +}; + +#endif // __kpfloodfill_h__ diff --git a/kolourpaint/pixmapfx/kppixmapfx.cpp b/kolourpaint/pixmapfx/kppixmapfx.cpp new file mode 100644 index 00000000..1bd0b173 --- /dev/null +++ b/kolourpaint/pixmapfx/kppixmapfx.cpp @@ -0,0 +1,1677 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_PIXMAP_FX 0 + + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + + +// +// Overflow Resistant Arithmetic: +// + +// public static +int kpPixmapFX::addDimensions (int lhs, int rhs) +{ + if (lhs < 0 || rhs < 0 || + lhs > INT_MAX - rhs) + { + return INT_MAX; + } + + return lhs + rhs; +} + +// public static +int kpPixmapFX::multiplyDimensions (int lhs, int rhs) +{ + if (rhs == 0) + return 0; + + if (lhs < 0 || rhs < 0 || + lhs > INT_MAX / rhs) + { + return INT_MAX; + } + + return lhs * rhs; +} + + +// +// QPixmap Statistics +// + +// public static +int kpPixmapFX::pixmapArea (const QPixmap &pixmap) +{ + return kpPixmapFX::pixmapArea (pixmap.width (), pixmap.height ()); +} + +// public static +int kpPixmapFX::pixmapArea (const QPixmap *pixmap) +{ + return (pixmap ? kpPixmapFX::pixmapArea (*pixmap) : 0); +} + +// public static +int kpPixmapFX::pixmapArea (int width, int height) +{ + return multiplyDimensions (width, height); +} + + +// public static +int kpPixmapFX::pixmapSize (const QPixmap &pixmap) +{ + return kpPixmapFX::pixmapSize (pixmap.width (), pixmap.height (), + pixmap.depth ()); +} + +// public static +int kpPixmapFX::pixmapSize (const QPixmap *pixmap) +{ + return (pixmap ? kpPixmapFX::pixmapSize (*pixmap) : 0); +} + +// public static +int kpPixmapFX::pixmapSize (int width, int height, int depth) +{ + // handle 15bpp + int roundedDepth = (depth > 8 ? (depth + 7) / 8 * 8 : depth); + +#if DEBUG_KP_PIXMAP_FX && 0 + kdDebug () << "kpPixmapFX::pixmapSize() w=" << width + << " h=" << height + << " d=" << depth + << " roundedDepth=" << roundedDepth + << " ret=" + << multiplyDimensions (kpPixmapFX::pixmapArea (width, height), roundedDepth) / 8 + << endl; +#endif + return multiplyDimensions (kpPixmapFX::pixmapArea (width, height), roundedDepth) / 8; +} + + +// public static +int kpPixmapFX::imageSize (const QImage &image) +{ + return kpPixmapFX::imageSize (image.width (), image.height (), image.depth ()); +} + +// public static +int kpPixmapFX::imageSize (const QImage *image) +{ + return (image ? kpPixmapFX::imageSize (*image) : 0); +} + +// public static +int kpPixmapFX::imageSize (int width, int height, int depth) +{ + // handle 15bpp + int roundedDepth = (depth > 8 ? (depth + 7) / 8 * 8 : depth); + +#if DEBUG_KP_PIXMAP_FX && 0 + kdDebug () << "kpPixmapFX::imageSize() w=" << width + << " h=" << height + << " d=" << depth + << " roundedDepth=" << roundedDepth + << " ret=" + << multiplyDimensions (multiplyDimensions (width, height), roundedDepth) / 8 + << endl; +#endif + + return multiplyDimensions (multiplyDimensions (width, height), roundedDepth) / 8; +} + + +// public static +int kpPixmapFX::selectionSize (const kpSelection &sel) +{ + return sel.size (); +} + +// public static +int kpPixmapFX::selectionSize (const kpSelection *sel) +{ + return (sel ? sel->size () : 0); +} + + +// public static +int kpPixmapFX::stringSize (const QString &string) +{ +#if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "kpPixmapFX::stringSize(" << string << ")" + << " len=" << string.length () + << " sizeof(QChar)=" << sizeof (QChar) + << endl; +#endif + return string.length () * sizeof (QChar); +} + + +// public static +int kpPixmapFX::pointArraySize (const QPointArray &points) +{ +#if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "kpPixmapFX::pointArraySize() points.size=" + << points.size () + << " sizeof(QPoint)=" << sizeof (QPoint) + << endl; +#endif + + return (points.size () * sizeof (QPoint)); +} + + +// +// QPixmap/QImage Conversion Functions +// + +// public static +QImage kpPixmapFX::convertToImage (const QPixmap &pixmap) +{ + if (pixmap.isNull ()) + return QImage (); + + return pixmap.convertToImage (); +} + + +// Returns true if contains translucency (rather than just transparency) +// QPixmap::hasAlphaChannel() appears to give incorrect results +static bool imageHasAlphaChannel (const QImage &image) +{ + if (image.depth () < 32) + return false; + + for (int y = 0; y < image.height (); y++) + { + for (int x = 0; x < image.width (); x++) + { + const QRgb rgb = image.pixel (x, y); + + if (qAlpha (rgb) > 0 && qAlpha (rgb) < 255) + return true; + } + } + + return false; +} + +static int imageNumColorsUpTo (const QImage &image, int max) +{ + QMap rgbMap; + + if (image.depth () <= 8) + { + for (int i = 0; i < image.numColors () && (int) rgbMap.size () < max; i++) + { + rgbMap.insert (image.color (i), true); + } + } + else + { + for (int y = 0; y < image.height () && (int) rgbMap.size () < max; y++) + { + for (int x = 0; x < image.width () && (int) rgbMap.size () < max; x++) + { + rgbMap.insert (image.pixel (x, y), true); + } + } + } + + return rgbMap.size (); +} + +static void convertToPixmapWarnAboutLoss (const QImage &image, + const kpPixmapFX::WarnAboutLossInfo &wali) +{ + if (!wali.isValid ()) + return; + + + const QString colorDepthTranslucencyDontAskAgain = + wali.m_dontAskAgainPrefix + "_ColorDepthTranslucency"; + const QString colorDepthDontAskAgain = + wali.m_dontAskAgainPrefix + "_ColorDepth"; + const QString translucencyDontAskAgain = + wali.m_dontAskAgainPrefix + "_Translucency"; + +#if DEBUG_KP_PIXMAP_FX && 1 + QTime timer; + timer.start (); +#endif + + bool hasAlphaChannel = + (KMessageBox::shouldBeShownContinue (translucencyDontAskAgain) && + imageHasAlphaChannel (image)); + +#if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "\twarnAboutLoss - check hasAlphaChannel took " + << timer.restart () << "msec" << endl; +#endif + + bool moreColorsThanDisplay = + (KMessageBox::shouldBeShownContinue (colorDepthDontAskAgain) && + image.depth () > QColor::numBitPlanes () && + QColor::numBitPlanes () < 24); // 32 indicates alpha channel + + int screenDepthNeeded = 0; + + if (moreColorsThanDisplay) + screenDepthNeeded = QMIN (24, image.depth ()); + +#if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "\ttranslucencyShouldBeShown=" + << KMessageBox::shouldBeShownContinue (translucencyDontAskAgain) + << endl + << "\thasAlphaChannel=" << hasAlphaChannel + << endl + << "\tcolorDepthShownBeShown=" + << KMessageBox::shouldBeShownContinue (colorDepthDontAskAgain) + << endl + << "\timage.depth()=" << image.depth () + << endl + << "\tscreenDepth=" << QColor::numBitPlanes () + << endl + << "\tmoreColorsThanDisplay=" << moreColorsThanDisplay + << endl + << "\tneedDepth=" << screenDepthNeeded + << endl; +#endif + + + QApplication::setOverrideCursor (Qt::arrowCursor); + + if (moreColorsThanDisplay && hasAlphaChannel) + { + KMessageBox::information (wali.m_parent, + wali.m_moreColorsThanDisplayAndHasAlphaChannelMessage + .arg (screenDepthNeeded), + QString::null, // or would you prefer "Low Screen Depth and Image Contains Transparency"? :) + colorDepthTranslucencyDontAskAgain); + + if (!KMessageBox::shouldBeShownContinue (colorDepthTranslucencyDontAskAgain)) + { + KMessageBox::saveDontShowAgainContinue (colorDepthDontAskAgain); + KMessageBox::saveDontShowAgainContinue (translucencyDontAskAgain); + } + } + else if (moreColorsThanDisplay) + { + KMessageBox::information (wali.m_parent, + wali.m_moreColorsThanDisplayMessage + .arg (screenDepthNeeded), + i18n ("Low Screen Depth"), + colorDepthDontAskAgain); + } + else if (hasAlphaChannel) + { + KMessageBox::information (wali.m_parent, + wali.m_hasAlphaChannelMessage, + i18n ("Image Contains Translucency"), + translucencyDontAskAgain); + } + + QApplication::restoreOverrideCursor (); +} + +// public static +QPixmap kpPixmapFX::convertToPixmap (const QImage &image, bool pretty, + const WarnAboutLossInfo &wali) +{ +#if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "kpPixmapFX::convertToPixmap(image,pretty=" << pretty + << ",warnAboutLossInfo.isValid=" << wali.isValid () + << ")" << endl; + QTime timer; + timer.start (); +#endif + + if (image.isNull ()) + return QPixmap (); + + + QPixmap destPixmap; + + if (!pretty) + { + destPixmap.convertFromImage (image, + Qt::ColorOnly/*always display depth*/ | + Qt::ThresholdDither/*no dither*/ | + Qt::ThresholdAlphaDither/*no dither alpha*/| + Qt::AvoidDither); + } + else + { + destPixmap.convertFromImage (image, + Qt::ColorOnly/*always display depth*/ | + Qt::DiffuseDither/*hi quality dither*/ | + Qt::ThresholdAlphaDither/*no dither alpha*/ | + Qt::PreferDither/*(dither even if <256 colours)*/); + } + +#if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "\tconversion took " << timer.elapsed () << "msec" << endl; +#endif + + kpPixmapFX::ensureNoAlphaChannel (&destPixmap); + + + if (wali.isValid ()) + convertToPixmapWarnAboutLoss (image, wali); + + + return destPixmap; +} + +// TODO: don't dup convertToPixmap() code +// public static +QPixmap kpPixmapFX::convertToPixmapAsLosslessAsPossible (const QImage &image, + const WarnAboutLossInfo &wali) +{ +#if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "kpPixmapFX::convertToPixmapAsLosslessAsPossible(image depth=" + << image.depth () + << ",warnAboutLossInfo.isValid=" << wali.isValid () + << ") screenDepth=" << QPixmap::defaultDepth () + << " imageNumColorsUpTo257=" << imageNumColorsUpTo (image, 257) + << endl; + QTime timer; + timer.start (); +#endif + + if (image.isNull ()) + return QPixmap (); + + + const int screenDepth = (QPixmap::defaultDepth () >= 24 ? + 32 : + QPixmap::defaultDepth ()); + + QPixmap destPixmap; + int ditherFlags = 0; + + if (image.depth () <= screenDepth) + { + #if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "\timage depth <= screen depth - don't dither" + << " (AvoidDither | ThresholdDither)" << endl; + #endif + + ditherFlags = (Qt::AvoidDither | Qt::ThresholdDither); + } + // PRE: image.depth() > screenDepth + // ASSERT: screenDepth < 32 + else if (screenDepth <= 8) + { + const int screenNumColors = (1 << screenDepth); + + #if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "\tscreen depth <= 8; imageNumColorsUpTo" + << (screenNumColors + 1) + << "=" << imageNumColorsUpTo (image, screenNumColors + 1) + << endl; + #endif + + if (imageNumColorsUpTo (image, screenNumColors + 1) <= screenNumColors) + { + #if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "\t\tcolors fit on screen - don't dither" + << " (AvoidDither | ThresholdDither)" << endl; + #endif + ditherFlags = (Qt::AvoidDither | Qt::ThresholdDither); + } + else + { + #if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "\t\tcolors don't fit on screen - dither" + << " (PreferDither | DiffuseDither)" << endl; + #endif + ditherFlags = (Qt::PreferDither | Qt::DiffuseDither); + } + } + // PRE: image.depth() > screenDepth && + // screenDepth > 8 + // ASSERT: screenDepth < 32 + else + { + #if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "\tscreen depth > 8 - read config" << endl; + #endif + + int configDitherIfNumColorsGreaterThan = 323; + + KConfigGroupSaver cfgGroupSaver (KGlobal::config (), + kpSettingsGroupGeneral); + KConfigBase *cfg = cfgGroupSaver.config (); + + if (cfg->hasKey (kpSettingDitherOnOpen)) + { + configDitherIfNumColorsGreaterThan = cfg->readNumEntry (kpSettingDitherOnOpen); + } + else + { + cfg->writeEntry (kpSettingDitherOnOpen, configDitherIfNumColorsGreaterThan); + cfg->sync (); + } + + #if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "\t\tcfg=" << configDitherIfNumColorsGreaterThan + << " image=" << imageNumColorsUpTo (image, configDitherIfNumColorsGreaterThan + 1) + << endl; + #endif + + if (imageNumColorsUpTo (image, configDitherIfNumColorsGreaterThan + 1) > + configDitherIfNumColorsGreaterThan) + { + #if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "\t\t\talways dither (PreferDither | DiffuseDither)" + << endl; + #endif + ditherFlags = (Qt::PreferDither | Qt::DiffuseDither); + } + else + { + #if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "\t\t\tdon't dither (AvoidDither | ThresholdDither)" + << endl; + #endif + ditherFlags = (Qt::AvoidDither | Qt::ThresholdDither); + } + } + + + destPixmap.convertFromImage (image, + Qt::ColorOnly/*always display depth*/ | + Qt::ThresholdAlphaDither/*no dither alpha*/ | + ditherFlags); + +#if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "\tconversion took " << timer.elapsed () << "msec" << endl; +#endif + + kpPixmapFX::ensureNoAlphaChannel (&destPixmap); + + + if (wali.isValid ()) + convertToPixmapWarnAboutLoss (image, wali); + + + return destPixmap; +} + + +// public static +QPixmap kpPixmapFX::pixmapWithDefinedTransparentPixels (const QPixmap &pixmap, + const QColor &transparentColor) +{ + if (!pixmap.mask ()) + return pixmap; + + QPixmap retPixmap (pixmap.width (), pixmap.height ()); + retPixmap.fill (transparentColor); + + QPainter p (&retPixmap); + p.drawPixmap (QPoint (0, 0), pixmap); + p.end (); + + retPixmap.setMask (*pixmap.mask ()); + return retPixmap; +} + + +// +// Get/Set Parts of Pixmap +// + + +// public static +QPixmap kpPixmapFX::getPixmapAt (const QPixmap &pm, const QRect &rect) +{ + QPixmap retPixmap (rect.width (), rect.height ()); + +#if DEBUG_KP_PIXMAP_FX && 0 + kdDebug () << "kpPixmapFX::getPixmapAt(pm.hasMask=" + << (pm.mask () ? 1 : 0) + << ",rect=" + << rect + << ")" + << endl; +#endif + + const QRect validSrcRect = pm.rect ().intersect (rect); + const bool wouldHaveUndefinedPixels = (validSrcRect != rect); + + if (wouldHaveUndefinedPixels) + { + #if DEBUG_KP_PIXMAP_FX && 0 + kdDebug () << "\tret would contain undefined pixels - setting them to transparent" << endl; + #endif + QBitmap transparentMask (rect.width (), rect.height ()); + transparentMask.fill (Qt::color0/*transparent*/); + retPixmap.setMask (transparentMask); + } + + if (validSrcRect.isEmpty ()) + { + #if DEBUG_KP_PIXMAP_FX && 0 + kdDebug () << "\tsilly case - completely invalid rect - ret transparent pixmap" << endl; + #endif + return retPixmap; + } + + + const QPoint destTopLeft = validSrcRect.topLeft () - rect.topLeft (); + + // copy data _and_ mask (if avail) + copyBlt (&retPixmap, /* dest */ + destTopLeft.x (), destTopLeft.y (), /* dest pt */ + &pm, /* src */ + validSrcRect.x (), validSrcRect.y (), /* src pt */ + validSrcRect.width (), validSrcRect.height ()); + + if (wouldHaveUndefinedPixels && retPixmap.mask () && !pm.mask ()) + { + #if DEBUG_KP_PIXMAP_FX && 0 + kdDebug () << "\tensure opaque in valid region" << endl; + #endif + kpPixmapFX::ensureOpaqueAt (&retPixmap, + QRect (destTopLeft.x (), destTopLeft.y (), + validSrcRect.width (), validSrcRect.height ())); + } + +#if DEBUG_KP_PIXMAP_FX && 0 + kdDebug () << "\tretPixmap.hasMask=" + << (retPixmap.mask () ? 1 : 0) + << endl; +#endif + + return retPixmap; +} + + +// public static +void kpPixmapFX::setPixmapAt (QPixmap *destPixmapPtr, const QRect &destRect, + const QPixmap &srcPixmap) +{ + if (!destPixmapPtr) + return; + +#if DEBUG_KP_PIXMAP_FX && 0 + kdDebug () << "kpPixmapFX::setPixmapAt(destPixmap->rect=" + << destPixmapPtr->rect () + << ",destPixmap->hasMask=" + << (destPixmapPtr->mask () ? 1 : 0) + << ",destRect=" + << destRect + << ",srcPixmap.rect=" + << srcPixmap.rect () + << ",srcPixmap.hasMask=" + << (srcPixmap.mask () ? 1 : 0) + << ")" + << endl; +#endif + +#if DEBUG_KP_PIXMAP_FX && 0 + if (destPixmapPtr->mask ()) + { + QImage image = kpPixmapFX::convertToImage (*destPixmapPtr); + int numTrans = 0; + + for (int y = 0; y < image.height (); y++) + { + for (int x = 0; x < image.width (); x++) + { + if (qAlpha (image.pixel (x, y)) == 0) + numTrans++; + } + } + + kdDebug () << "\tdestPixmapPtr numTrans=" << numTrans << endl; + } +#endif + +#if 0 + // TODO: why does undo'ing a single pen dot on a transparent pixel, + // result in a opaque image, except for that single transparent pixel??? + // Qt bug on boundary case? + + // copy data _and_ mask + copyBlt (destPixmapPtr, + destAt.x (), destAt.y (), + &srcPixmap, + 0, 0, + destRect.width (), destRect.height ()); +#else + bitBlt (destPixmapPtr, + destRect.x (), destRect.y (), + &srcPixmap, + 0, 0, + destRect.width (), destRect.height (), + Qt::CopyROP, + true/*ignore mask*/); + + if (srcPixmap.mask ()) + { + QBitmap mask = getNonNullMask (*destPixmapPtr); + bitBlt (&mask, + destRect.x (), destRect.y (), + srcPixmap.mask (), + 0, 0, + destRect.width (), destRect.height (), + Qt::CopyROP, + true/*ignore mask*/); + destPixmapPtr->setMask (mask); + } +#endif + + if (destPixmapPtr->mask () && !srcPixmap.mask ()) + { + #if DEBUG_KP_PIXMAP_FX && 0 + kdDebug () << "\t\topaque'ing dest rect" << endl; + #endif + kpPixmapFX::ensureOpaqueAt (destPixmapPtr, destRect); + } + +#if DEBUG_KP_PIXMAP_FX && 0 + kdDebug () << "\tdestPixmap->hasMask=" + << (destPixmapPtr->mask () ? 1 : 0) + << endl; + if (destPixmapPtr->mask ()) + { + QImage image = kpPixmapFX::convertToImage (*destPixmapPtr); + int numTrans = 0; + + for (int y = 0; y < image.height (); y++) + { + for (int x = 0; x < image.width (); x++) + { + if (qAlpha (image.pixel (x, y)) == 0) + numTrans++; + } + } + + kdDebug () << "\tdestPixmapPtr numTrans=" << numTrans << endl; + } +#endif +} + +// public static +void kpPixmapFX::setPixmapAt (QPixmap *destPixmapPtr, const QPoint &destAt, + const QPixmap &srcPixmap) +{ + kpPixmapFX::setPixmapAt (destPixmapPtr, + QRect (destAt.x (), destAt.y (), + srcPixmap.width (), srcPixmap.height ()), + srcPixmap); +} + +// public static +void kpPixmapFX::setPixmapAt (QPixmap *destPixmapPtr, int destX, int destY, + const QPixmap &srcPixmap) +{ + kpPixmapFX::setPixmapAt (destPixmapPtr, QPoint (destX, destY), srcPixmap); +} + + +// public static +void kpPixmapFX::paintPixmapAt (QPixmap *destPixmapPtr, const QPoint &destAt, + const QPixmap &srcPixmap) +{ + if (!destPixmapPtr) + return; + + // Copy src (masked by src's mask) on top of dest. + bitBlt (destPixmapPtr, /* dest */ + destAt.x (), destAt.y (), /* dest pt */ + &srcPixmap, /* src */ + 0, 0 /* src pt */); + + kpPixmapFX::ensureOpaqueAt (destPixmapPtr, destAt, srcPixmap); +} + +// public static +void kpPixmapFX::paintPixmapAt (QPixmap *destPixmapPtr, int destX, int destY, + const QPixmap &srcPixmap) +{ + kpPixmapFX::paintPixmapAt (destPixmapPtr, QPoint (destX, destY), srcPixmap); +} + + +// public static +kpColor kpPixmapFX::getColorAtPixel (const QPixmap &pm, const QPoint &at) +{ +#if DEBUG_KP_PIXMAP_FX && 0 + kdDebug () << "kpToolColorPicker::colorAtPixel" << p << endl; +#endif + + if (at.x () < 0 || at.x () >= pm.width () || + at.y () < 0 || at.y () >= pm.height ()) + { + return kpColor::invalid; + } + + QPixmap pixmap = getPixmapAt (pm, QRect (at, at)); + QImage image = kpPixmapFX::convertToImage (pixmap); + if (image.isNull ()) + { + kdError () << "kpPixmapFX::getColorAtPixel(QPixmap) could not convert to QImage" << endl; + return kpColor::invalid; + } + + return getColorAtPixel (image, QPoint (0, 0)); +} + +// public static +kpColor kpPixmapFX::getColorAtPixel (const QPixmap &pm, int x, int y) +{ + return kpPixmapFX::getColorAtPixel (pm, QPoint (x, y)); +} + +// public static +kpColor kpPixmapFX::getColorAtPixel (const QImage &img, const QPoint &at) +{ + if (!img.valid (at.x (), at.y ())) + return kpColor::invalid; + + QRgb rgba = img.pixel (at.x (), at.y ()); + return kpColor (rgba); +} + +// public static +kpColor kpPixmapFX::getColorAtPixel (const QImage &img, int x, int y) +{ + return kpPixmapFX::getColorAtPixel (img, QPoint (x, y)); +} + + +// +// Mask Operations +// + + +// public static +void kpPixmapFX::ensureNoAlphaChannel (QPixmap *destPixmapPtr) +{ + if (destPixmapPtr->hasAlphaChannel ()) + destPixmapPtr->setMask (kpPixmapFX::getNonNullMask/*just in case*/ (*destPixmapPtr)); +} + + +// public static +QBitmap kpPixmapFX::getNonNullMask (const QPixmap &pm) +{ + if (pm.mask ()) + return *pm.mask (); + else + { + QBitmap maskBitmap (pm.width (), pm.height ()); + maskBitmap.fill (Qt::color1/*opaque*/); + + return maskBitmap; + } +} + + +// public static +void kpPixmapFX::ensureTransparentAt (QPixmap *destPixmapPtr, const QRect &destRect) +{ + if (!destPixmapPtr) + return; + + QBitmap maskBitmap = getNonNullMask (*destPixmapPtr); + + QPainter p (&maskBitmap); + + p.setPen (Qt::color0/*transparent*/); + p.setBrush (Qt::color0/*transparent*/); + + p.drawRect (destRect); + + p.end (); + + destPixmapPtr->setMask (maskBitmap); +} + + +// public static +void kpPixmapFX::paintMaskTransparentWithBrush (QPixmap *destPixmapPtr, const QPoint &destAt, + const QPixmap &brushBitmap) +{ + if (!destPixmapPtr) + return; + + if (brushBitmap.depth () > 1) + { + kdError () << "kpPixmapFX::paintMaskTransparentWidthBrush() passed brushPixmap with depth > 1" << endl; + return; + } + + QBitmap destMaskBitmap = kpPixmapFX::getNonNullMask (*destPixmapPtr); + + // Src + // Dest Mask Brush Bitmap = Result + // ------------------------------------- + // 0 0 0 + // 0 1 0 + // 1 0 1 + // 1 1 0 + // + // Brush Bitmap value of 1 means "make transparent" + // 0 means "leave it as it is" + + bitBlt (&destMaskBitmap, + destAt.x (), destAt.y (), + &brushBitmap, + 0, 0, + brushBitmap.width (), brushBitmap.height (), + Qt::NotAndROP); + + destPixmapPtr->setMask (destMaskBitmap); +} + +// public static +void kpPixmapFX::paintMaskTransparentWithBrush (QPixmap *destPixmapPtr, int destX, int destY, + const QPixmap &brushBitmap) +{ + kpPixmapFX::paintMaskTransparentWithBrush (destPixmapPtr, + QPoint (destX, destY), + brushBitmap); +} + + +// public static +void kpPixmapFX::ensureOpaqueAt (QPixmap *destPixmapPtr, const QRect &destRect) +{ + if (!destPixmapPtr || !destPixmapPtr->mask ()/*already opaque*/) + return; + + QBitmap maskBitmap = *destPixmapPtr->mask (); + + QPainter p (&maskBitmap); + + p.setPen (Qt::color1/*opaque*/); + p.setBrush (Qt::color1/*opaque*/); + + p.drawRect (destRect); + + p.end (); + + destPixmapPtr->setMask (maskBitmap); +} + +// public static +void kpPixmapFX::ensureOpaqueAt (QPixmap *destPixmapPtr, const QPoint &destAt, + const QPixmap &srcPixmap) +{ + if (!destPixmapPtr || !destPixmapPtr->mask ()/*already opaque*/) + return; + + QBitmap destMask = *destPixmapPtr->mask (); + + if (srcPixmap.mask ()) + { + bitBlt (&destMask, /* dest */ + destAt, /* dest pt */ + srcPixmap.mask (), /* src */ + QRect (0, 0, srcPixmap.width (), srcPixmap.height ()), /* src rect */ + Qt::OrROP/*if either is opaque, it's opaque*/); + } + else + { + QPainter p (&destMask); + + p.setPen (Qt::color1/*opaque*/); + p.setBrush (Qt::color1/*opaque*/); + + p.drawRect (destAt.x (), destAt.y (), + srcPixmap.width (), srcPixmap.height ()); + + p.end (); + } + + destPixmapPtr->setMask (destMask); +} + +// public static +void kpPixmapFX::ensureOpaqueAt (QPixmap *destPixmapPtr, int destX, int destY, + const QPixmap &srcPixmap) +{ + kpPixmapFX::ensureOpaqueAt (destPixmapPtr, QPoint (destX, destY), srcPixmap); +} + + +// +// Effects +// + +// public static +void kpPixmapFX::convertToGrayscale (QPixmap *destPixmapPtr) +{ + QImage image = kpPixmapFX::convertToImage (*destPixmapPtr); + kpPixmapFX::convertToGrayscale (&image); + *destPixmapPtr = kpPixmapFX::convertToPixmap (image); +} + +// public static +QPixmap kpPixmapFX::convertToGrayscale (const QPixmap &pm) +{ + QImage image = kpPixmapFX::convertToImage (pm); + kpPixmapFX::convertToGrayscale (&image); + return kpPixmapFX::convertToPixmap (image); +} + +static QRgb toGray (QRgb rgb) +{ + // naive way that doesn't preserve brightness + // int gray = (qRed (rgb) + qGreen (rgb) + qBlue (rgb)) / 3; + + // over-exaggerates red & blue + // int gray = qGray (rgb); + + int gray = (212671 * qRed (rgb) + 715160 * qGreen (rgb) + 72169 * qBlue (rgb)) / 1000000; + return qRgba (gray, gray, gray, qAlpha (rgb)); +} + +// public static +void kpPixmapFX::convertToGrayscale (QImage *destImagePtr) +{ + if (destImagePtr->depth () > 8) + { + // hmm, why not just write to the pixmap directly??? + + for (int y = 0; y < destImagePtr->height (); y++) + { + for (int x = 0; x < destImagePtr->width (); x++) + { + destImagePtr->setPixel (x, y, toGray (destImagePtr->pixel (x, y))); + } + } + } + else + { + // 1- & 8- bit images use a color table + for (int i = 0; i < destImagePtr->numColors (); i++) + destImagePtr->setColor (i, toGray (destImagePtr->color (i))); + } +} + +// public static +QImage kpPixmapFX::convertToGrayscale (const QImage &img) +{ + QImage retImage = img; + kpPixmapFX::convertToGrayscale (&retImage); + return retImage; +} + + +// public static +void kpPixmapFX::fill (QPixmap *destPixmapPtr, const kpColor &color) +{ + if (!destPixmapPtr) + return; + + if (color.isOpaque ()) + { + destPixmapPtr->setMask (QBitmap ()); // no mask = opaque + destPixmapPtr->fill (color.toQColor ()); + } + else + { + kpPixmapFX::ensureTransparentAt (destPixmapPtr, destPixmapPtr->rect ()); + } +} + +// public static +QPixmap kpPixmapFX::fill (const QPixmap &pm, const kpColor &color) +{ + QPixmap ret = pm; + kpPixmapFX::fill (&ret, color); + return ret; +} + + +// public static +void kpPixmapFX::resize (QPixmap *destPixmapPtr, int w, int h, + const kpColor &backgroundColor, bool fillNewAreas) +{ +#if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "kpPixmapFX::resize()" << endl; +#endif + + if (!destPixmapPtr) + return; + + int oldWidth = destPixmapPtr->width (); + int oldHeight = destPixmapPtr->height (); + + if (w == oldWidth && h == oldHeight) + return; + + + destPixmapPtr->resize (w, h); + + if (fillNewAreas && (w > oldWidth || h > oldHeight)) + { + #if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "\tfilling in new areas" << endl; + #endif + QBitmap maskBitmap; + QPainter painter, maskPainter; + + if (backgroundColor.isOpaque ()) + { + painter.begin (destPixmapPtr); + painter.setPen (backgroundColor.toQColor ()); + painter.setBrush (backgroundColor.toQColor ()); + } + + if (backgroundColor.isTransparent () || destPixmapPtr->mask ()) + { + maskBitmap = kpPixmapFX::getNonNullMask (*destPixmapPtr); + maskPainter.begin (&maskBitmap); + maskPainter.setPen (backgroundColor.maskColor ()); + maskPainter.setBrush (backgroundColor.maskColor ()); + } + + #define PAINTER_CALL(cmd) \ + { \ + if (painter.isActive ()) \ + painter . cmd ; \ + \ + if (maskPainter.isActive ()) \ + maskPainter . cmd ; \ + } + if (w > oldWidth) + PAINTER_CALL (drawRect (oldWidth, 0, w - oldWidth, oldHeight)); + + if (h > oldHeight) + PAINTER_CALL (drawRect (0, oldHeight, w, h - oldHeight)); + #undef PAINTER_CALL + + if (maskPainter.isActive ()) + maskPainter.end (); + + if (painter.isActive ()) + painter.end (); + + if (!maskBitmap.isNull ()) + destPixmapPtr->setMask (maskBitmap); + } +} + +// public static +QPixmap kpPixmapFX::resize (const QPixmap &pm, int w, int h, + const kpColor &backgroundColor, bool fillNewAreas) +{ + QPixmap ret = pm; + kpPixmapFX::resize (&ret, w, h, backgroundColor, fillNewAreas); + return ret; +} + + +// public static +void kpPixmapFX::scale (QPixmap *destPixmapPtr, int w, int h, bool pretty) +{ + if (!destPixmapPtr) + return; + + *destPixmapPtr = kpPixmapFX::scale (*destPixmapPtr, w, h, pretty); +} + +// public static +QPixmap kpPixmapFX::scale (const QPixmap &pm, int w, int h, bool pretty) +{ +#if DEBUG_KP_PIXMAP_FX && 0 + kdDebug () << "kpPixmapFX::scale(oldRect=" << pm.rect () + << ",w=" << w + << ",h=" << h + << ",pretty=" << pretty + << ")" + << endl; +#endif + + if (w == pm.width () && h == pm.height ()) + return pm; + + if (pretty) + { + QImage image = kpPixmapFX::convertToImage (pm); + + #if DEBUG_KP_PIXMAP_FX && 0 + kdDebug () << "\tBefore smooth scale:" << endl; + for (int y = 0; y < image.height (); y++) + { + for (int x = 0; x < image.width (); x++) + { + fprintf (stderr, " %08X", image.pixel (x, y)); + } + fprintf (stderr, "\n"); + } + #endif + + image = image.smoothScale (w, h); + + #if DEBUG_KP_PIXMAP_FX && 0 + kdDebug () << "\tAfter smooth scale:" << endl; + for (int y = 0; y < image.height (); y++) + { + for (int x = 0; x < image.width (); x++) + { + fprintf (stderr, " %08X", image.pixel (x, y)); + } + fprintf (stderr, "\n"); + } + #endif + + return kpPixmapFX::convertToPixmap (image, false/*let's not smooth it again*/); + } + else + { + QWMatrix matrix; + + matrix.scale (double (w) / double (pm.width ()), + double (h) / double (pm.height ())); + + return pm.xForm (matrix); + } +} + + +// public static +double kpPixmapFX::AngleInDegreesEpsilon = + KP_RADIANS_TO_DEGREES (atan (1.0 / 10000.0)) + / (2.0/*max error allowed*/ * 2.0/*for good measure*/); + + +static QWMatrix matrixWithZeroOrigin (const QWMatrix &matrix, int width, int height) +{ +#if DEBUG_KP_PIXMAP_FX + kdDebug () << "matrixWithZeroOrigin(w=" << width << ",h=" << height << ")" << endl; + kdDebug () << "\tmatrix: m11=" << matrix.m11 () + << " m12=" << matrix.m12 () + << " m21=" << matrix.m21 () + << " m22=" << matrix.m22 () + << " dx=" << matrix.dx () + << " dy=" << matrix.dy () + << endl; +#endif + // TODO: Should we be using QWMatrix::Areas? + QRect newRect = matrix.mapRect (QRect (0, 0, width, height)); +#if DEBUG_KP_PIXMAP_FX + kdDebug () << "\tnewRect=" << newRect << endl; +#endif + + QWMatrix translatedMatrix (matrix.m11 (), matrix.m12 (), matrix.m21 (), matrix.m22 (), + matrix.dx () - newRect.left (), matrix.dy () - newRect.top ()); + + return translatedMatrix; +} + +static QPixmap xForm (const QPixmap &pm, const QWMatrix &transformMatrix_, + const kpColor &backgroundColor, + int targetWidth, int targetHeight) +{ + QWMatrix transformMatrix = transformMatrix_; + +#if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "kppixmapfx.cpp: xForm(pm.size=" << pm.size () + << ",targetWidth=" << targetWidth + << ",targetHeight=" << targetHeight + << ")" + << endl; +#endif + // TODO: Should we be using QWMatrix::Areas? + QRect newRect = transformMatrix.map (pm.rect ()); +#if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "\tmappedRect=" << newRect << endl; + +#endif + + QWMatrix scaleMatrix; + if (targetWidth > 0 && targetWidth != newRect.width ()) + { + #if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "\tadjusting for targetWidth" << endl; + #endif + scaleMatrix.scale (double (targetWidth) / double (newRect.width ()), 1); + } + + if (targetHeight > 0 && targetHeight != newRect.height ()) + { + #if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "\tadjusting for targetHeight" << endl; + #endif + scaleMatrix.scale (1, double (targetHeight) / double (newRect.height ())); + } + + if (!scaleMatrix.isIdentity ()) + { + #if DEBUG_KP_PIXMAP_FX && 1 + // TODO: What is going on here??? Why isn't matrix * working properly? + QWMatrix wrongMatrix = transformMatrix * scaleMatrix; + QWMatrix oldHat = transformMatrix; + if (targetWidth > 0 && targetWidth != newRect.width ()) + oldHat.scale (double (targetWidth) / double (newRect.width ()), 1); + if (targetHeight > 0 && targetHeight != newRect.height ()) + oldHat.scale (1, double (targetHeight) / double (newRect.height ())); + QWMatrix altHat = transformMatrix; + altHat.scale ((targetWidth > 0 && targetWidth != newRect.width ()) ? double (targetWidth) / double (newRect.width ()) : 1, + (targetHeight > 0 && targetHeight != newRect.height ()) ? double (targetHeight) / double (newRect.height ()) : 1); + QWMatrix correctMatrix = scaleMatrix * transformMatrix; + + kdDebug () << "\tsupposedlyWrongMatrix: m11=" << wrongMatrix.m11 () // <<<---- this is the correct matrix??? + << " m12=" << wrongMatrix.m12 () + << " m21=" << wrongMatrix.m21 () + << " m22=" << wrongMatrix.m22 () + << " dx=" << wrongMatrix.dx () + << " dy=" << wrongMatrix.dy () + << " rect=" << wrongMatrix.map (pm.rect ()) + << endl + << "\ti_used_to_use_thisMatrix: m11=" << oldHat.m11 () + << " m12=" << oldHat.m12 () + << " m21=" << oldHat.m21 () + << " m22=" << oldHat.m22 () + << " dx=" << oldHat.dx () + << " dy=" << oldHat.dy () + << " rect=" << oldHat.map (pm.rect ()) + << endl + << "\tabove but scaled at the same time: m11=" << altHat.m11 () + << " m12=" << altHat.m12 () + << " m21=" << altHat.m21 () + << " m22=" << altHat.m22 () + << " dx=" << altHat.dx () + << " dy=" << altHat.dy () + << " rect=" << altHat.map (pm.rect ()) + << endl + << "\tsupposedlyCorrectMatrix: m11=" << correctMatrix.m11 () + << " m12=" << correctMatrix.m12 () + << " m21=" << correctMatrix.m21 () + << " m22=" << correctMatrix.m22 () + << " dx=" << correctMatrix.dx () + << " dy=" << correctMatrix.dy () + << " rect=" << correctMatrix.map (pm.rect ()) + << endl; + #endif + + transformMatrix = transformMatrix * scaleMatrix; + + // TODO: Should we be using QWMatrix::Areas? + newRect = transformMatrix.map (pm.rect ()); + #if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "\tnewRect after targetWidth,targetHeight adjust=" << newRect << endl; + #endif + } + + + QPixmap newPixmap (targetWidth > 0 ? targetWidth : newRect.width (), + targetHeight > 0 ? targetHeight : newRect.height ()); + if ((targetWidth > 0 && targetWidth != newRect.width ()) || + (targetHeight > 0 && targetHeight != newRect.height ())) + { + #if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "kppixmapfx.cpp: xForm(pm.size=" << pm.size () + << ",targetWidth=" << targetWidth + << ",targetHeight=" << targetHeight + << ") newRect=" << newRect + << " (you are a victim of rounding error)" + << endl; + #endif + } + + QBitmap newBitmapMask; + + if (backgroundColor.isOpaque ()) + newPixmap.fill (backgroundColor.toQColor ()); + + if (backgroundColor.isTransparent () || pm.mask ()) + { + newBitmapMask.resize (newPixmap.width (), newPixmap.height ()); + newBitmapMask.fill (backgroundColor.maskColor ()); + } + + QPainter painter (&newPixmap); +#if DEBUG_KP_PIXMAP_FX && 1 + kdDebug () << "\tmatrix: m11=" << transformMatrix.m11 () + << " m12=" << transformMatrix.m12 () + << " m21=" << transformMatrix.m21 () + << " m22=" << transformMatrix.m22 () + << " dx=" << transformMatrix.dx () + << " dy=" << transformMatrix.dy () + << endl; + const QWMatrix trueMatrix = QPixmap::trueMatrix (transformMatrix, + pm.width (), pm.height ()); + kdDebug () << "\ttrue matrix: m11=" << trueMatrix.m11 () + << " m12=" << trueMatrix.m12 () + << " m21=" << trueMatrix.m21 () + << " m22=" << trueMatrix.m22 () + << " dx=" << trueMatrix.dx () + << " dy=" << trueMatrix.dy () + << endl; +#endif + painter.setWorldMatrix (transformMatrix); +#if DEBUG_KP_PIXMAP_FX && 0 + kdDebug () << "\ttranslate top=" << painter.xForm (QPoint (0, 0)) << endl; + kdDebug () << "\tmatrix: m11=" << painter.worldMatrix ().m11 () + << " m12=" << painter.worldMatrix ().m12 () + << " m21=" << painter.worldMatrix ().m21 () + << " m22=" << painter.worldMatrix ().m22 () + << " dx=" << painter.worldMatrix ().dx () + << " dy=" << painter.worldMatrix ().dy () + << endl; +#endif + painter.drawPixmap (QPoint (0, 0), pm); + painter.end (); + + if (!newBitmapMask.isNull ()) + { + QPainter maskPainter (&newBitmapMask); + maskPainter.setWorldMatrix (transformMatrix); + maskPainter.drawPixmap (QPoint (0, 0), kpPixmapFX::getNonNullMask (pm)); + maskPainter.end (); + newPixmap.setMask (newBitmapMask); + } + + return newPixmap; +} + +// public static +QWMatrix kpPixmapFX::skewMatrix (int width, int height, double hangle, double vangle) +{ + if (fabs (hangle - 0) < kpPixmapFX::AngleInDegreesEpsilon && + fabs (vangle - 0) < kpPixmapFX::AngleInDegreesEpsilon) + { + return QWMatrix (); + } + + + /* Diagram for completeness :) + * + * |---------- w ----------| + * (0,0) + * _ _______________________ (w,0) + * | |\~_ va | + * | | \ ~_ | + * | |ha\ ~__ | + * | \ ~__ | dy + * h | \ ~___ | + * | \ ~___ | + * | | \ ~___| (w,w*tan(va)=dy) + * | | \ * \ + * _ |________\________|_____|\ vertical shear factor + * (0,h) dx ^~_ | \ | + * | ~_ \________\________ General Point (x,y) V + * | ~__ \ Skewed Point (x + y*tan(ha),y + x*tan(va)) + * (h*tan(ha)=dx,h) ~__ \ ^ + * ~___ \ | + * ~___ \ horizontal shear factor + * Key: ~___\ + * ha = hangle (w + h*tan(ha)=w+dx,h + w*tan(va)=w+dy) + * va = vangle + * + * Skewing really just twists a rectangle into a parallelogram. + * + */ + + //QWMatrix matrix (1, tan (KP_DEGREES_TO_RADIANS (vangle)), tan (KP_DEGREES_TO_RADIANS (hangle)), 1, 0, 0); + // I think this is clearer than above :) + QWMatrix matrix; + matrix.shear (tan (KP_DEGREES_TO_RADIANS (hangle)), + tan (KP_DEGREES_TO_RADIANS (vangle))); + + return matrixWithZeroOrigin (matrix, width, height); +} + +// public static +QWMatrix kpPixmapFX::skewMatrix (const QPixmap &pixmap, double hangle, double vangle) +{ + return kpPixmapFX::skewMatrix (pixmap.width (), pixmap.height (), hangle, vangle); +} + + +// public static +void kpPixmapFX::skew (QPixmap *destPixmapPtr, double hangle, double vangle, + const kpColor &backgroundColor, + int targetWidth, int targetHeight) +{ + if (!destPixmapPtr) + return; + + *destPixmapPtr = kpPixmapFX::skew (*destPixmapPtr, hangle, vangle, + backgroundColor, + targetWidth, targetHeight); +} + +// public static +QPixmap kpPixmapFX::skew (const QPixmap &pm, double hangle, double vangle, + const kpColor &backgroundColor, + int targetWidth, int targetHeight) +{ +#if DEBUG_KP_PIXMAP_FX + kdDebug () << "kpPixmapFX::skew() pm.width=" << pm.width () + << " pm.height=" << pm.height () + << " hangle=" << hangle + << " vangle=" << vangle + << " targetWidth=" << targetWidth + << " targetHeight=" << targetHeight + << endl; +#endif + + if (fabs (hangle - 0) < kpPixmapFX::AngleInDegreesEpsilon && + fabs (vangle - 0) < kpPixmapFX::AngleInDegreesEpsilon && + (targetWidth <= 0 && targetHeight <= 0)/*don't want to scale?*/) + { + return pm; + } + + if (fabs (hangle) > 90 - kpPixmapFX::AngleInDegreesEpsilon || + fabs (vangle) > 90 - kpPixmapFX::AngleInDegreesEpsilon) + { + kdError () << "kpPixmapFX::skew() passed hangle and/or vangle out of range (-90 < x < 90)" << endl; + return pm; + } + + + QWMatrix matrix = skewMatrix (pm, hangle, vangle); + + return ::xForm (pm, matrix, backgroundColor, targetWidth, targetHeight); +} + + +// public static +QWMatrix kpPixmapFX::rotateMatrix (int width, int height, double angle) +{ + if (fabs (angle - 0) < kpPixmapFX::AngleInDegreesEpsilon) + { + return QWMatrix (); + } + + QWMatrix matrix; + matrix.translate (width / 2, height / 2); + matrix.rotate (angle); + + return matrixWithZeroOrigin (matrix, width, height); +} + +// public static +QWMatrix kpPixmapFX::rotateMatrix (const QPixmap &pixmap, double angle) +{ + return kpPixmapFX::rotateMatrix (pixmap.width (), pixmap.height (), angle); +} + + +// public static +bool kpPixmapFX::isLosslessRotation (double angle) +{ + const double angleIn = angle; + + // Reflect angle into positive if negative + if (angle < 0) + angle = -angle; + + // Remove multiples of 90 to make sure 0 <= angle <= 90 + angle -= ((int) angle) / 90 * 90; + + // "Impossible" situation? + if (angle < 0 || angle > 90) + { + kdError () << "kpPixmapFX::isLosslessRotation(" << angleIn + << ") result=" << angle + << endl; + return false; // better safe than sorry + } + + const bool ret = (angle < kpPixmapFX::AngleInDegreesEpsilon || + 90 - angle < kpPixmapFX::AngleInDegreesEpsilon); +#if DEBUG_KP_PIXMAP_FX + kdDebug () << "kpPixmapFX::isLosslessRotation(" << angleIn << ")" + << " residual angle=" << angle + << " returning " << ret + << endl; +#endif + return ret; +} + + +// public static +void kpPixmapFX::rotate (QPixmap *destPixmapPtr, double angle, + const kpColor &backgroundColor, + int targetWidth, int targetHeight) +{ + if (!destPixmapPtr) + return; + + *destPixmapPtr = kpPixmapFX::rotate (*destPixmapPtr, angle, + backgroundColor, + targetWidth, targetHeight); +} + +// public static +QPixmap kpPixmapFX::rotate (const QPixmap &pm, double angle, + const kpColor &backgroundColor, + int targetWidth, int targetHeight) +{ + if (fabs (angle - 0) < kpPixmapFX::AngleInDegreesEpsilon && + (targetWidth <= 0 && targetHeight <= 0)/*don't want to scale?*/) + { + return pm; + } + + + QWMatrix matrix = rotateMatrix (pm, angle); + + return ::xForm (pm, matrix, backgroundColor, targetWidth, targetHeight); +} + + +// public static +QWMatrix kpPixmapFX::flipMatrix (int width, int height, bool horz, bool vert) +{ + if (width <= 0 || height <= 0) + { + kdError () << "kpPixmapFX::flipMatrix() passed invalid dimensions" << endl; + return QWMatrix (); + } + + return QWMatrix (horz ? -1 : +1, // m11 + 0, // m12 + 0, // m21 + vert ? -1 : +1, // m22 + horz ? (width - 1) : 0, // dx + vert ? (height - 1) : 0); // dy +} + +// public static +QWMatrix kpPixmapFX::flipMatrix (const QPixmap &pixmap, bool horz, bool vert) +{ + return kpPixmapFX::flipMatrix (pixmap.width (), pixmap.height (), + horz, vert); +} + + +// public static +void kpPixmapFX::flip (QPixmap *destPixmapPtr, bool horz, bool vert) +{ + if (!horz && !vert) + return; + + *destPixmapPtr = kpPixmapFX::flip (*destPixmapPtr, horz, vert); +} + +// public static +QPixmap kpPixmapFX::flip (const QPixmap &pm, bool horz, bool vert) +{ + if (!horz && !vert) + return pm; + + return pm.xForm (flipMatrix (pm, horz, vert)); +} + +// public static +void kpPixmapFX::flip (QImage *destImagePtr, bool horz, bool vert) +{ + if (!horz && !vert) + return; + + *destImagePtr = kpPixmapFX::flip (*destImagePtr, horz, vert); +} + +// public static +QImage kpPixmapFX::flip (const QImage &img, bool horz, bool vert) +{ + if (!horz && !vert) + return img; + + return img.mirror (horz, vert); +} diff --git a/kolourpaint/pixmapfx/kppixmapfx.h b/kolourpaint/pixmapfx/kppixmapfx.h new file mode 100644 index 00000000..c083ee43 --- /dev/null +++ b/kolourpaint/pixmapfx/kppixmapfx.h @@ -0,0 +1,450 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_PIXMAP_FX_H +#define KP_PIXMAP_FX_H + + +#include + + +class QBitmap; +class QColor; +class QImage; +class QPointArray; +class QPixmap; +class QPoint; +class QRect; +class QString; +class QWidget; +class QWMatrix; + +class kpColor; +class kpSelection; + + +class kpPixmapFX +{ +public: + + // + // Overflow Resistant Arithmetic: + // + // Returns INT_MAX if or < 0 or if would overflow. + static int addDimensions (int lhs, int rhs); + static int multiplyDimensions (int lhs, int rhs); + + + // + // QPixmap Statistics + // + + // Returns the width * height. + static int pixmapArea (const QPixmap &pixmap); + static int pixmapArea (const QPixmap *pixmap); + static int pixmapArea (int width, int height); + + // Returns the estimated size of in pixmap memory. + static int pixmapSize (const QPixmap &pixmap); + static int pixmapSize (const QPixmap *pixmap); + static int pixmapSize (int width, int height, int depth); + + static int imageSize (const QImage &image); + static int imageSize (const QImage *image); + static int imageSize (int width, int height, int depth); + + static int selectionSize (const kpSelection &sel); + static int selectionSize (const kpSelection *sel); + + static int stringSize (const QString &string); + + static int pointArraySize (const QPointArray &points); + + + // + // QPixmap/QImage Conversion Functions + // + + // + // Converts to a QImage and returns it. + // + // WARNING: On an 8-bit screen: + // + // QPixmap result = convertToPixmap (convertToImage (pixmap)); + // + // is slightly differently colored to . + // + // KolourPaint needs to convert to QImage occasionally as + // QImage allows KolourPaint to read pixels and because the QImage + // methods give reliable results and pixel-identical results on + // all platforms. The QPixmap paint engine has no such guarantee + // and even depends on the quality of the video driver. + // + // As a result, KolourPaint should not be used on an 8-bit screen. + // HITODO: Add warning on startup, like in KolourPaint/KDE4. + // + // This bug will be fixed when KolourPaint gets a proper image library, + // where QPixmap -> QImage -> QPixmap transitions will be not be needed. + static QImage convertToImage (const QPixmap &pixmap); + + // + // Dialog info for warning about data loss with convertToPixmap(). + // + struct WarnAboutLossInfo + { + // : + // + // i18n ("The (image \"example.jpg\"|image from the clipboard)" + // " may have more colors than the current screen mode." + // " In order to display it, some colors may be changed." + // " Try increasing your screen depth to at least %1bpp." + // + // "\nIt also" + // + // " contains translucency which is not fully" + // " supported. The translucency data will be" + // " approximated with a 1-bit transparency mask.") + // + // : + // i18n ("The (image \"example.jpg\"|image from the clipboard)" + // " may have more colors than the current screen mode." + // " In order to display it, some colors may be changed." + // " Try increasing your screen depth to at least %1bpp.") + // + // : + // i18n ("The (image \"example.jpg\"|image from the clipboard)" + // " contains translucency which is not fully" + // " supported. The translucency data will be" + // " approximated with a 1-bit transparency mask.") + // + // : + // + // Don'tAskAgain ID for dialog. + // + // : + // + // Dialog parent + // + WarnAboutLossInfo (const QString &moreColorsThanDisplayAndHasAlphaChannelMessage, + const QString &moreColorsThanDisplayMessage, + const QString &hasAlphaChannelMessage, + const QString &dontAskAgainPrefix, + QWidget *parent) + : + m_moreColorsThanDisplayAndHasAlphaChannelMessage ( + moreColorsThanDisplayAndHasAlphaChannelMessage), + m_moreColorsThanDisplayMessage ( + moreColorsThanDisplayMessage), + m_hasAlphaChannelMessage ( + hasAlphaChannelMessage), + m_dontAskAgainPrefix ( + dontAskAgainPrefix), + m_parent (parent), + m_isValid (true) + { + } + + WarnAboutLossInfo () + : m_parent (0), + m_isValid (false) + { + } + + ~WarnAboutLossInfo () + { + } + + + bool isValid () const { return m_isValid; } + + + QString m_moreColorsThanDisplayAndHasAlphaChannelMessage, + m_moreColorsThanDisplayMessage, + m_hasAlphaChannelMessage; + QString m_dontAskAgainPrefix; + QWidget *m_parent; + bool m_isValid; + }; + + // + // Converts to a QPixmap of the current display's depth and + // returns it. + // + // If the flag is set, it will dither the image making the + // returned pixmap look better but if the image has few colours + // (less than the screen can handle), this will be at the expense of + // exactness of conversion. + // + // This will automatically call ensureNoAlphaChannel(). + // + // Never use a foreign QPixmap that is offered to you - always get the + // foreign QImage and use this function to convert it to a sane QPixmap. + // + // , if specified, describes parameters for the dialog that comes + // up warning the user of data loss if the contains translucency + // and/or more colors than the current display. + // + static QPixmap convertToPixmap (const QImage &image, bool pretty = false, + const WarnAboutLossInfo &wali = WarnAboutLossInfo ()); + + // Same as convertToPixmap() but tries as hard as possible to make the + // pixmap look like the original - when in doubt, reads the + // config to see whether or not to dither (default: on). + // + // If you know for sure that can be displayed losslessly on + // the screen, you should call convertToPixmap() with = false + // instead. If you know for sure that cannot be displayed + // losslessly, then call convertToPixmap() with = true. + // + static QPixmap convertToPixmapAsLosslessAsPossible (const QImage &image, + const WarnAboutLossInfo &wali = WarnAboutLossInfo ()); + + + // Sets the RGB values of the pixels where is transparent to + // . This has visually no effect on the + // unless the mask is lost. + static QPixmap pixmapWithDefinedTransparentPixels (const QPixmap &pixmap, + const QColor &transparentColor); + + + // + // Get/Set Parts of Pixmap + // + + + // + // Returns the pixel and mask data found at the in . + // + static QPixmap getPixmapAt (const QPixmap &pm, const QRect &rect); + + // + // Sets the pixel and mask data at in <*destPixmapPtr> + // to . + // + static void setPixmapAt (QPixmap *destPixmapPtr, const QRect &destRect, + const QPixmap &srcPixmap); + + // + // Sets the pixel and mask data at the rectangle in <*destPixmapPtr>, + // with the top-left and dimensions , + // to . + // + static void setPixmapAt (QPixmap *destPixmapPtr, const QPoint &destAt, + const QPixmap &srcPixmap); + static void setPixmapAt (QPixmap *destPixmapPtr, int destX, int destY, + const QPixmap &srcPixmap); + + // + // Draws on top of <*destPixmapPtr> at . + // The mask of <*destPixmapPtr> is adjusted so that all opaque + // pixels in will be opaque in <*destPixmapPtr>. + // + static void paintPixmapAt (QPixmap *destPixmapPtr, const QPoint &destAt, + const QPixmap &srcPixmap); + static void paintPixmapAt (QPixmap *destPixmapPtr, int destX, int destY, + const QPixmap &srcPixmap); + + // + // Returns the colour of the pixel at in . + // If the pixel is transparent, a value is returned such that + // kpTool::isColorTransparent() will return true. + // + static kpColor getColorAtPixel (const QPixmap &pm, const QPoint &at); + static kpColor getColorAtPixel (const QPixmap &pm, int x, int y); + + // + // Returns the color of the pixel at in . + // If the pixel is transparent, a value is returned such that + // kpTool::isColorTransparent() will return true. + // + static kpColor getColorAtPixel (const QImage &img, const QPoint &at); + static kpColor getColorAtPixel (const QImage &img, int x, int y); + + + // + // Mask Operations + // + + + // + // Removes <*destPixmapPtr>'s Alpha Channel and attempts to convert it + // to a mask. KolourPaint - and QPixmap to a great extent - does not + // support Alpha Channels - only masks. Call this whenever you get + // a pixmap from a foreign source; else all KolourPaint code will + // exhibit "undefined behaviour". + // + static void ensureNoAlphaChannel (QPixmap *destPixmapPtr); + + // + // Returns 's mask or a fully opaque mask (with 's dimensions) + // if does not have a mask. + // + static QBitmap getNonNullMask (const QPixmap &pm); + + // + // Ensures that <*destPixmapPtr> is transparent at . + // + static void ensureTransparentAt (QPixmap *destPixmapPtr, const QRect &destRect); + + // + // Sets the mask of <*destPixmapPtr> at the rectangle, with the + // top-left and dimensions , + // to transparent where is opaque. + // + // must be a QPixmap of depth 1 (or a QBitmap). + // + static void paintMaskTransparentWithBrush (QPixmap *destPixmapPtr, const QPoint &destAt, + const QPixmap &brushBitmap); + static void paintMaskTransparentWithBrush (QPixmap *destPixmapPtr, int destX, int destY, + const QPixmap &brushBitmap); + + // + // Ensures that <*destPixmapPtr> is opaque at . + // + static void ensureOpaqueAt (QPixmap *destPixmapPtr, const QRect &destRect); + + // + // Ensures that 's opaque pixels will be opaque if + // painted onto <*destPixmapPtr> at . + // + static void ensureOpaqueAt (QPixmap *destPixmapPtr, const QPoint &destAt, + const QPixmap &srcPixmap); + static void ensureOpaqueAt (QPixmap *destPixmapPtr, int destX, int destY, + const QPixmap &srcPixmap); + + + // + // Effects + // + + + // + // Converts the image to grayscale. + // + static void convertToGrayscale (QPixmap *destPixmapPtr); + static QPixmap convertToGrayscale (const QPixmap &pm); + static void convertToGrayscale (QImage *destImagePtr); + static QImage convertToGrayscale (const QImage &img); + + // + // Fills an image in the given color. + // + static void fill (QPixmap *destPixmapPtr, const kpColor &color); + static QPixmap fill (const QPixmap &pm, const kpColor &color); + + // + // Resizes an image to the given width and height, + // filling any new areas with if is set. + // + static void resize (QPixmap *destPixmapPtr, int w, int h, + const kpColor &backgroundColor, bool fillNewAreas = true); + static QPixmap resize (const QPixmap &pm, int w, int h, + const kpColor &backgroundColor, bool fillNewAreas = true); + + // + // Scales an image to the given width and height. + // If is true, a smooth scale will be used. + // + static void scale (QPixmap *destPixmapPtr, int w, int h, bool pretty = false); + static QPixmap scale (const QPixmap &pm, int w, int h, bool pretty = false); + + + // The minimum difference between 2 angles (in degrees) such that they are + // considered different. This gives you at least enough precision to + // rotate an image whose width <= 10000 such that its height increases + // by just 1 (and similarly with height <= 10000 and width). + // + // Currently used for skew & rotate operations. + static double AngleInDegreesEpsilon; + + + // + // Skews an image. + // + // horizontal angle clockwise (-90 < x < 90) + // vertical angle clockwise (-90 < x < 90) + // color to fill new areas with + // if > 0, the desired width of the resultant pixmap + // if > 0, the desired height of the resultant pixmap + // + // Using & to generate preview pixmaps is + // significantly more efficient than skewing and then scaling yourself. + // + static QWMatrix skewMatrix (int width, int height, double hangle, double vangle); + static QWMatrix skewMatrix (const QPixmap &pixmap, double hangle, double vangle); + + static void skew (QPixmap *destPixmapPtr, double hangle, double vangle, + const kpColor &backgroundColor, + int targetWidth = -1, int targetHeight = -1); + static QPixmap skew (const QPixmap &pm, double hangle, double vangle, + const kpColor &backgroundColor, + int targetWidth = -1, int targetHeight = -1); + + // + // Rotates an image. + // + // clockwise angle to rotate by + // color to fill new areas with + // if > 0, the desired width of the resultant pixmap + // if > 0, the desired height of the resultant pixmap + // + // Using & to generate preview pixmaps is + // significantly more efficient than rotating and then scaling yourself. + // + static QWMatrix rotateMatrix (int width, int height, double angle); + static QWMatrix rotateMatrix (const QPixmap &pixmap, double angle); + + static bool isLosslessRotation (double angle); + + static void rotate (QPixmap *destPixmapPtr, double angle, + const kpColor &backgroundColor, + int targetWidth = -1, int targetHeight = -1); + static QPixmap rotate (const QPixmap &pm, double angle, + const kpColor &backgroundColor, + int targetWidth = -1, int targetHeight = -1); + + + // + // Flips an image in the given directions. + // + static QWMatrix flipMatrix (int width, int height, bool horz, bool vert); + static QWMatrix flipMatrix (const QPixmap &pixmap, bool horz, bool vert); + + // TODO: this kind of overloading is error prone + // e.g. QPixmap pixmap; + // kpPixmapFX::flip (pixmap, false, true); + // looks like it will flip vertically but does absolutely nothing! + // (should be &pixmap) + static void flip (QPixmap *destPixmapPtr, bool horz, bool vert); + static QPixmap flip (const QPixmap &pm, bool horz, bool vert); + static void flip (QImage *destImagePtr, bool horz, bool vert); + static QImage flip (const QImage &img, bool horz, bool vert); +}; + + +#endif // KP_PIXMAP_FX_H diff --git a/kolourpaint/tests/45deg_line.png b/kolourpaint/tests/45deg_line.png new file mode 100644 index 00000000..5af95109 Binary files /dev/null and b/kolourpaint/tests/45deg_line.png differ diff --git a/kolourpaint/tests/4x4-transparent.png b/kolourpaint/tests/4x4-transparent.png new file mode 100644 index 00000000..58b0668e Binary files /dev/null and b/kolourpaint/tests/4x4-transparent.png differ diff --git a/kolourpaint/tests/5x5.png b/kolourpaint/tests/5x5.png new file mode 100644 index 00000000..850766c7 Binary files /dev/null and b/kolourpaint/tests/5x5.png differ diff --git a/kolourpaint/tests/depth1.bmp b/kolourpaint/tests/depth1.bmp new file mode 100644 index 00000000..326c665a Binary files /dev/null and b/kolourpaint/tests/depth1.bmp differ diff --git a/kolourpaint/tests/dither.png b/kolourpaint/tests/dither.png new file mode 100644 index 00000000..443ed07c Binary files /dev/null and b/kolourpaint/tests/dither.png differ diff --git a/kolourpaint/tests/rotate.png b/kolourpaint/tests/rotate.png new file mode 100644 index 00000000..f6f028b4 Binary files /dev/null and b/kolourpaint/tests/rotate.png differ diff --git a/kolourpaint/tests/small16x16.png b/kolourpaint/tests/small16x16.png new file mode 100644 index 00000000..ed61d4d6 Binary files /dev/null and b/kolourpaint/tests/small16x16.png differ diff --git a/kolourpaint/tests/tool_fill_xlimit.png b/kolourpaint/tests/tool_fill_xlimit.png new file mode 100644 index 00000000..b499879a Binary files /dev/null and b/kolourpaint/tests/tool_fill_xlimit.png differ diff --git a/kolourpaint/tests/transparent.png b/kolourpaint/tests/transparent.png new file mode 100644 index 00000000..c05a92ef Binary files /dev/null and b/kolourpaint/tests/transparent.png differ diff --git a/kolourpaint/tests/transparent_selection.png b/kolourpaint/tests/transparent_selection.png new file mode 100644 index 00000000..8db8b7e5 Binary files /dev/null and b/kolourpaint/tests/transparent_selection.png differ diff --git a/kolourpaint/tools/Makefile.am b/kolourpaint/tools/Makefile.am new file mode 100644 index 00000000..9c665cb1 --- /dev/null +++ b/kolourpaint/tools/Makefile.am @@ -0,0 +1,53 @@ +INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../cursors -I$(srcdir)/../interfaces \ + -I$(srcdir)/../pixmapfx \ + -I$(srcdir)/../tools \ + -I$(srcdir)/../views \ + -I$(srcdir)/../widgets $(all_includes) + +noinst_LTLIBRARIES = libkolourpainttools.la +libkolourpainttools_la_SOURCES = kptoolaction.cpp \ + kptoolairspray.cpp \ + kptoolautocrop.cpp \ + kptoolbrush.cpp kptoolclear.cpp \ + kptoolcolorpicker.cpp kptoolcolorwasher.cpp \ + kptoolconverttograyscale.cpp \ + kptoolcrop.cpp \ + kptoolcurve.cpp \ + kptoolellipse.cpp \ + kptoolellipticalselection.cpp kptooleraser.cpp \ + kptoolflip.cpp kptoolfloodfill.cpp \ + kptoolfreeformselection.cpp \ + kptoolline.cpp kptoolpen.cpp \ + kptoolpolygon.cpp kptoolpolyline.cpp \ + kptoolpreviewdialog.cpp \ + kptoolrectangle.cpp kptoolrectselection.cpp \ + kptoolresizescale.cpp kptoolrotate.cpp \ + kptoolroundedrectangle.cpp kptoolselection.cpp \ + kptoolskew.cpp kptooltext.cpp + +# TODO: Why is this needed? Isn't linking at the toplevel enough? +libkolourpainttools_la_LIBADD = ../pixmapfx/libkolourpaintpixmapfx.la ../cursors/libkolourpaintcursors.la + +METASOURCES = kptoolaction.moc \ + kptoolairspray.moc \ + kptoolbrush.moc \ + kptoolcolorpicker.moc \ + kptoolcolorwasher.moc \ + kptoolcurve.moc \ + kptoolellipse.moc \ + kptooleraser.moc \ + kptoolflip.moc \ + kptoolfloodfill.moc \ + kptoolline.moc \ + kptoolpen.moc \ + kptoolpolygon.moc \ + kptoolpolyline.moc \ + kptoolpreviewdialog.moc \ + kptoolrectangle.moc \ + kptoolresizescale.moc \ + kptoolrotate.moc \ + kptoolroundedrectangle.moc \ + kptoolselection.moc \ + kptoolskew.moc \ + kptooltext.moc + diff --git a/kolourpaint/tools/kptoolaction.cpp b/kolourpaint/tools/kptoolaction.cpp new file mode 100644 index 00000000..ef5c8510 --- /dev/null +++ b/kolourpaint/tools/kptoolaction.cpp @@ -0,0 +1,107 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include + + +kpToolAction::kpToolAction (const QString &text, + const QString &pic, const KShortcut &shortcut, + const QObject *receiver, const char *slot, + QObject *parent, const char *name) + : KToggleAction (text, + pic, shortcut, + receiver, slot, + parent, name) +{ + updateToolTip (); +} + +kpToolAction::~kpToolAction () +{ +} + + +// protected +void kpToolAction::updateToolTip () +{ + const QString newToolTip = + kpTool::toolTipForTextAndShortcut (text (), shortcut ()); + if (newToolTip == toolTip ()) + return; + + setToolTip (newToolTip); + emit toolTipChanged (newToolTip); +} + + +// +// KToggleAction interface +// + +// public slot virtual [base KAction] +void kpToolAction::setText (const QString &text) +{ + KToggleAction::setText (text); + updateToolTip (); +} + +// public slot virtual [base KAction] +bool kpToolAction::setShortcut (const KShortcut &shortcut) +{ + bool ret = KToggleAction::setShortcut (shortcut); + updateToolTip (); + return ret; +} + + +// +// KToggleAction implements kpSingleKeyTriggersActionInterface +// + +// public virtual [base kpSingleKeyTriggersActionInterface] +const char *kpToolAction::actionName () const +{ + return name (); +} + +// public virtual [base kpSingleKeyTriggersActionInterface] +KShortcut kpToolAction::actionShortcut () const +{ + return shortcut (); +} + +// public virtual [base kpSingleKeyTriggersActionInterface] +void kpToolAction::actionSetShortcut (const KShortcut &shortcut) +{ + setShortcut (shortcut); +} + + +#include diff --git a/kolourpaint/tools/kptoolaction.h b/kolourpaint/tools/kptoolaction.h new file mode 100644 index 00000000..df4e407e --- /dev/null +++ b/kolourpaint/tools/kptoolaction.h @@ -0,0 +1,78 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef KP_TOOL_ACTION_H +#define KP_TOOL_ACTION_H + +#include + +#include + + +// Same as KToggleAction but shows the first single key trigger in the tooltip. +class kpToolAction : public KToggleAction, + public kpSingleKeyTriggersActionInterface +{ +Q_OBJECT + +public: + kpToolAction (const QString &text, + const QString &pic, const KShortcut &shortcut, + const QObject *receiver, const char *slot, + QObject *parent, const char *name); + virtual ~kpToolAction (); + + +signals: + // Not emitted when toolTip is manually overriden by setToolTip() + void toolTipChanged (const QString &string); + +protected: + void updateToolTip (); + + + // + // KToggleAction interface + // + +public slots: + virtual void setText (const QString &text); + virtual bool setShortcut (const KShortcut &shortcut); + + + // + // kpSingleKeyTriggersActionInterface + // + +public: + virtual const char *actionName () const; + virtual KShortcut actionShortcut () const; + virtual void actionSetShortcut (const KShortcut &shortcut); +}; + + +#endif // KP_TOOL_ACTION_H diff --git a/kolourpaint/tools/kptoolairspray.cpp b/kolourpaint/tools/kptoolairspray.cpp new file mode 100644 index 00000000..43f8bef3 --- /dev/null +++ b/kolourpaint/tools/kptoolairspray.cpp @@ -0,0 +1,376 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_TOOL_SPRAYCAN 0 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * kpToolAirSpray + */ + +kpToolAirSpray::kpToolAirSpray (kpMainWindow *mainWindow) + : kpTool (i18n ("Spraycan"), i18n ("Sprays graffiti"), + Qt::Key_Y, + mainWindow, "tool_spraycan"), + m_currentCommand (0) +{ + m_timer = new QTimer (this); + connect (m_timer, SIGNAL (timeout ()), this, SLOT (actuallyDraw ())); +} + +kpToolAirSpray::~kpToolAirSpray () +{ + delete m_currentCommand; +} + + +// private +QString kpToolAirSpray::haventBegunDrawUserMessage () const +{ + return i18n ("Click or drag to spray graffiti."); +} + +// public virtual +void kpToolAirSpray::begin () +{ + kpToolToolBar *tb = toolToolBar (); + + m_toolWidgetSpraycanSize = 0; + m_size = 10; + + if (tb) + { + m_toolWidgetSpraycanSize = tb->toolWidgetSpraycanSize (); + + if (m_toolWidgetSpraycanSize) + { + m_size = m_toolWidgetSpraycanSize->spraycanSize (); + connect (m_toolWidgetSpraycanSize, SIGNAL (spraycanSizeChanged (int)), + this, SLOT (slotSpraycanSizeChanged (int))); + + m_toolWidgetSpraycanSize->show (); + } + } + + setUserMessage (haventBegunDrawUserMessage ()); +} + +// public virtual +void kpToolAirSpray::end () +{ + if (m_toolWidgetSpraycanSize) + { + disconnect (m_toolWidgetSpraycanSize, SIGNAL (spraycanSizeChanged (int)), + this, SLOT (slotSpraycanSizeChanged (int))); + m_toolWidgetSpraycanSize = 0; + } + + setUserMessage (haventBegunDrawUserMessage ()); +} + +// private slot +void kpToolAirSpray::slotSpraycanSizeChanged (int size) +{ + m_size = size; +} + + +void kpToolAirSpray::beginDraw () +{ + m_currentCommand = new kpToolAirSprayCommand ( + color (m_mouseButton), + m_size, + mainWindow ()); + + // without delay + actuallyDraw (); + + // use a timer instead of reimplementing draw() (we don't draw all the time) + m_timer->start (25); + + setUserMessage (cancelUserMessage ()); +} + +void kpToolAirSpray::draw (const QPoint &thisPoint, const QPoint &, const QRect &) +{ + // if the user is moving the spray, make the spray line continuous + if (thisPoint != m_lastPoint) + { + // without delay + actuallyDraw (); + } + + setUserShapePoints (thisPoint); +} + +void kpToolAirSpray::actuallyDraw () +{ + QPointArray pArray (10); + int numPoints = 0; + + QPoint p = m_currentPoint; + +#if DEBUG_KP_TOOL_SPRAYCAN + kdDebug () << "kpToolAirSpray::actuallyDraw() currentPoint=" << p + << " size=" << m_size + << endl; +#endif + + int radius = m_size / 2; + + for (int i = 0; i < 10; i++) + { + int dx, dy; + + dx = (rand () % m_size) - radius; + dy = (rand () % m_size) - radius; + + // make it look circular + // OPT: can be done better + if (dx * dx + dy * dy <= radius * radius) + pArray [numPoints++] = QPoint (p.x () + dx, p.y () + dy); + } + + pArray.resize (numPoints); + + if (numPoints > 0) + { + // leave the command to draw + m_currentCommand->addPoints (pArray); + } +} + +// virtual +void kpToolAirSpray::cancelShape () +{ +#if 0 + endDraw (QPoint (), QRect ()); + mainWindow ()->commandHistory ()->undo (); +#else + m_timer->stop (); + + m_currentCommand->finalize (); + m_currentCommand->cancel (); + + delete m_currentCommand; + m_currentCommand = 0; +#endif + + setUserMessage (i18n ("Let go of all the mouse buttons.")); +} + +void kpToolAirSpray::releasedAllButtons () +{ + setUserMessage (haventBegunDrawUserMessage ()); +} + +// virtual +void kpToolAirSpray::endDraw (const QPoint &, const QRect &) +{ + m_timer->stop (); + + m_currentCommand->finalize (); + mainWindow ()->commandHistory ()->addCommand (m_currentCommand, false /* don't exec */); + + // don't delete - it's up to the commandHistory + m_currentCommand = 0; + + setUserMessage (haventBegunDrawUserMessage ()); +} + + +/* + * kpToolAirSprayCommand + */ + +kpToolAirSprayCommand::kpToolAirSprayCommand (const kpColor &color, int size, + kpMainWindow *mainWindow) + : kpCommand (mainWindow), + m_color (color), + m_size (size), + m_newPixmapPtr (0) +{ + m_oldPixmap = *document ()->pixmap (); +} + +kpToolAirSprayCommand::~kpToolAirSprayCommand () +{ + delete m_newPixmapPtr; +} + + +// public virtual [base kpCommand] +QString kpToolAirSprayCommand::name () const +{ + return i18n ("Spraycan"); +} + + +// public virtual [base kpCommand] +int kpToolAirSprayCommand::size () const +{ + return kpPixmapFX::pixmapSize (m_newPixmapPtr) + + kpPixmapFX::pixmapSize (m_oldPixmap); +} + + +// Redo: +// +// must not call before unexecute() as m_newPixmapPtr is null +// (one reason why we told addCommand() not to execute, +// the other being that the dots have already been draw onto the doc) +void kpToolAirSprayCommand::execute () +{ + if (m_newPixmapPtr) + { + document ()->setPixmapAt (*m_newPixmapPtr, m_boundingRect.topLeft ()); + + // (will be regenerated in unexecute() if required) + delete m_newPixmapPtr; + m_newPixmapPtr = 0; + } + else + kdError () << "kpToolAirSprayCommand::execute() has null m_newPixmapPtr" << endl; +} + +// Undo: +void kpToolAirSprayCommand::unexecute () +{ + if (!m_newPixmapPtr) + { + // the ultimate in laziness - figure out Redo info only if we Undo + m_newPixmapPtr = new QPixmap (m_boundingRect.width (), m_boundingRect.height ()); + *m_newPixmapPtr = document ()->getPixmapAt (m_boundingRect); + } + else + kdError () << "kpToolAirSprayCommand::unexecute() has non-null newPixmapPtr" << endl; + + document ()->setPixmapAt (m_oldPixmap, m_boundingRect.topLeft ()); +} + + +// public +void kpToolAirSprayCommand::addPoints (const QPointArray &points) +{ + QRect docRect = points.boundingRect (); + +#if DEBUG_KP_TOOL_SPRAYCAN + kdDebug () << "kpToolAirSprayCommand::addPoints() docRect=" << docRect + << " numPoints=" << points.count () << endl; + for (int i = 0; i < (int) points.count (); i++) + kdDebug () << "\t" << i << ": " << points [i] << endl; +#endif + + QPixmap pixmap = document ()->getPixmapAt (docRect); + QBitmap mask; + + QPainter painter, maskPainter; + + if (m_color.isOpaque ()) + { + painter.begin (&pixmap); + painter.setPen (m_color.toQColor ()); + } + + if (pixmap.mask () || m_color.isTransparent ()) + { + mask = kpPixmapFX::getNonNullMask (pixmap); + maskPainter.begin (&mask); + maskPainter.setPen (m_color.maskColor ()); + } + + for (int i = 0; i < (int) points.count (); i++) + { + QPoint pt (points [i].x () - docRect.x (), + points [i].y () - docRect.y ()); + + if (painter.isActive ()) + painter.drawPoint (pt); + + if (maskPainter.isActive ()) + maskPainter.drawPoint (pt); + } + + if (maskPainter.isActive ()) + maskPainter.end (); + + if (painter.isActive ()) + painter.end (); + + if (!mask.isNull ()) + pixmap.setMask (mask); + + viewManager ()->setFastUpdates (); + document ()->setPixmapAt (pixmap, docRect.topLeft ()); + viewManager ()->restoreFastUpdates (); + + m_boundingRect = m_boundingRect.unite (docRect); +} + +void kpToolAirSprayCommand::finalize () +{ + // store only needed part of doc pixmap + m_oldPixmap = kpTool::neededPixmap (m_oldPixmap, m_boundingRect); +} + +void kpToolAirSprayCommand::cancel () +{ + if (m_boundingRect.isValid ()) + { + viewManager ()->setFastUpdates (); + document ()->setPixmapAt (m_oldPixmap, m_boundingRect.topLeft ()); + viewManager ()->restoreFastUpdates (); + } +} + +#include diff --git a/kolourpaint/tools/kptoolairspray.h b/kolourpaint/tools/kptoolairspray.h new file mode 100644 index 00000000..24f02787 --- /dev/null +++ b/kolourpaint/tools/kptoolairspray.h @@ -0,0 +1,110 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolairspray_h__ +#define __kptoolairspray_h__ + +#include +#include +#include + +class QPixmap; +class QPoint; +class QRect; +class QString; +class QTimer; + +class kpMainWindow; +class kpToolAirSprayCommand; +class kpToolWidgetSpraycanSize; +class kpViewManager; + +class kpToolAirSpray : public kpTool +{ +Q_OBJECT + +public: + kpToolAirSpray (kpMainWindow *); + virtual ~kpToolAirSpray (); + +private: + QString haventBegunDrawUserMessage () const; + +public: + virtual void begin (); + virtual void end (); + +private slots: + void slotSpraycanSizeChanged (int size); + +public: + virtual void beginDraw (); + virtual void draw (const QPoint &thisPoint, const QPoint &, const QRect &); + virtual void cancelShape (); + virtual void releasedAllButtons (); + virtual void endDraw (const QPoint &, const QRect &); + +public slots: + void actuallyDraw (); + +private: + kpToolWidgetSpraycanSize *m_toolWidgetSpraycanSize; + kpToolAirSprayCommand *m_currentCommand; + QTimer *m_timer; + int m_size; +}; + +class kpToolAirSprayCommand : public kpCommand +{ +public: + kpToolAirSprayCommand (const kpColor &color, int size, + kpMainWindow *mainWindow); + virtual ~kpToolAirSprayCommand (); + + virtual QString name () const; + + virtual int size () const; + + virtual void execute (); + virtual void unexecute (); + + // interface for KToolAirSpray + void addPoints (const QPointArray &points); + void finalize (); + void cancel (); + +private: + kpColor m_color; + int m_size; + + QPixmap *m_newPixmapPtr; + QPixmap m_oldPixmap; + QRect m_boundingRect; +}; + +#endif // __kptoolairspray_h__ diff --git a/kolourpaint/tools/kptoolautocrop.cpp b/kolourpaint/tools/kptoolautocrop.cpp new file mode 100644 index 00000000..244c192d --- /dev/null +++ b/kolourpaint/tools/kptoolautocrop.cpp @@ -0,0 +1,780 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// TODO: Color Similarity is obviously useful in Autocrop but it isn't +// obvious as to how to implement it. The current heuristic, +// for each side, chooses an arbitrary reference color for which +// all other candidate pixels in that side are tested against +// for similarity. But if the reference color happens to be at +// one extreme of the range of colors in that side, then pixels +// at the other extreme would not be deemed similar enough. The +// key is to find the median color as the reference but how do +// you do this if you don't know which pixels to sample in the first +// place (that's what you're trying to find)? Chicken and egg situation. +// +// The other heuristic that is in doubt is the use of the average +// color in determining the similarity of sides (it is possible +// to get vastly differently colors in both sides yet they will be +// considered similar). + +#define DEBUG_KP_TOOL_AUTO_CROP 0 + + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +kpToolAutoCropBorder::kpToolAutoCropBorder (const QPixmap *pixmapPtr, + int processedColorSimilarity) + : m_pixmapPtr (pixmapPtr), + m_processedColorSimilarity (processedColorSimilarity) +{ + invalidate (); +} + + +// public +int kpToolAutoCropBorder::size () const +{ + return sizeof (kpToolAutoCropBorder); +} + + +// public +const QPixmap *kpToolAutoCropBorder::pixmap () const +{ + return m_pixmapPtr; +} + +// public +int kpToolAutoCropBorder::processedColorSimilarity () const +{ + return m_processedColorSimilarity; +} + +// public +QRect kpToolAutoCropBorder::rect () const +{ + return m_rect; +} + +// public +int kpToolAutoCropBorder::left () const +{ + return m_rect.left (); +} + +// public +int kpToolAutoCropBorder::right () const +{ + return m_rect.right (); +} + +// public +int kpToolAutoCropBorder::top () const +{ + return m_rect.top (); +} + +// public +int kpToolAutoCropBorder::bottom () const +{ + return m_rect.bottom (); +} + +// public +kpColor kpToolAutoCropBorder::referenceColor () const +{ + return m_referenceColor; +} + +// public +kpColor kpToolAutoCropBorder::averageColor () const +{ + if (!m_rect.isValid ()) + return kpColor::invalid; + + if (m_referenceColor.isTransparent ()) + return kpColor::transparent; + else if (m_processedColorSimilarity == 0) + return m_referenceColor; + else + { + int numPixels = (m_rect.width () * m_rect.height ()); + if (numPixels <= 0) + { + kdError () << "kpToolAutoCropBorder::averageColor() rect=" << m_rect << endl; + return kpColor::invalid; + } + + return kpColor (m_redSum / numPixels, + m_greenSum / numPixels, + m_blueSum / numPixels); + } +} + +bool kpToolAutoCropBorder::isSingleColor () const +{ + return m_isSingleColor; +} + + +// public +bool kpToolAutoCropBorder::calculate (int isX, int dir) +{ +#if DEBUG_KP_TOOL_AUTO_CROP && 1 + kdDebug () << "kpToolAutoCropBorder::calculate() CALLED!" << endl; +#endif + int maxX = m_pixmapPtr->width () - 1; + int maxY = m_pixmapPtr->height () - 1; + + QImage image = kpPixmapFX::convertToImage (*m_pixmapPtr); + if (image.isNull ()) + { + kdError () << "Border::calculate() could not convert to QImage" << endl; + return false; + } + + // (sync both branches) + if (isX) + { + int numCols = 0; + int startX = (dir > 0) ? 0 : maxX; + + kpColor col = kpPixmapFX::getColorAtPixel (image, startX, 0); + for (int x = startX; + x >= 0 && x <= maxX; + x += dir) + { + int y; + for (y = 0; y <= maxY; y++) + { + if (!kpPixmapFX::getColorAtPixel (image, x, y).isSimilarTo (col, m_processedColorSimilarity)) + break; + } + + if (y <= maxY) + break; + else + numCols++; + } + + if (numCols) + { + m_rect = QRect (QPoint (startX, 0), + QPoint (startX + (numCols - 1) * dir, maxY)).normalize (); + m_referenceColor = col; + } + } + else + { + int numRows = 0; + int startY = (dir > 0) ? 0 : maxY; + + kpColor col = kpPixmapFX::getColorAtPixel (image, 0, startY); + for (int y = startY; + y >= 0 && y <= maxY; + y += dir) + { + int x; + for (x = 0; x <= maxX; x++) + { + if (!kpPixmapFX::getColorAtPixel (image, x, y).isSimilarTo (col, m_processedColorSimilarity)) + break; + } + + if (x <= maxX) + break; + else + numRows++; + } + + if (numRows) + { + m_rect = QRect (QPoint (0, startY), + QPoint (maxX, startY + (numRows - 1) * dir)).normalize (); + m_referenceColor = col; + } + } + + + if (m_rect.isValid ()) + { + m_isSingleColor = true; + + if (m_referenceColor.isOpaque () && m_processedColorSimilarity != 0) + { + for (int y = m_rect.top (); y <= m_rect.bottom (); y++) + { + for (int x = m_rect.left (); x <= m_rect.right (); x++) + { + kpColor colAtPixel = kpPixmapFX::getColorAtPixel (image, x, y); + + if (m_isSingleColor && colAtPixel != m_referenceColor) + m_isSingleColor = false; + + m_redSum += colAtPixel.red (); + m_greenSum += colAtPixel.green (); + m_blueSum += colAtPixel.blue (); + } + } + } + } + + + return true; +} + +// public +bool kpToolAutoCropBorder::fillsEntirePixmap () const +{ + return (m_rect == m_pixmapPtr->rect ()); +} + +// public +bool kpToolAutoCropBorder::exists () const +{ + // (will use in an addition so make sure returns 1 or 0) + return (m_rect.isValid () ? 1 : 0); +} + +// public +void kpToolAutoCropBorder::invalidate () +{ + m_rect = QRect (); + m_referenceColor = kpColor::invalid; + m_redSum = m_greenSum = m_blueSum = 0; + m_isSingleColor = false; +} + + +class kpSetOverrideCursorSaver +{ +public: + kpSetOverrideCursorSaver (const QCursor &cursor) + { + QApplication::setOverrideCursor (cursor); + } + + ~kpSetOverrideCursorSaver () + { + QApplication::restoreOverrideCursor (); + } +}; + + +void showNothingToAutocropMessage (kpMainWindow *mainWindow, bool actOnSelection) +{ + kpSetOverrideCursorSaver cursorSaver (Qt::arrowCursor); + + if (actOnSelection) + { + KMessageBox::information (mainWindow, + i18n ("KolourPaint cannot remove the selection's internal border as it" + " could not be located."), + i18n ("Cannot Remove Internal Border"), + "NothingToAutoCrop"); + } + else + { + KMessageBox::information (mainWindow, + i18n ("KolourPaint cannot automatically crop the image as its" + " border could not be located."), + i18n ("Cannot Autocrop"), + "NothingToAutoCrop"); + } +} + +bool kpToolAutoCrop (kpMainWindow *mainWindow) +{ +#if DEBUG_KP_TOOL_AUTO_CROP + kdDebug () << "kpToolAutoCrop() CALLED!" << endl; +#endif + + if (!mainWindow) + { + kdError () << "kpToolAutoCrop() passed NULL mainWindow" << endl; + return false; + } + + kpDocument *doc = mainWindow->document (); + if (!doc) + { + kdError () << "kpToolAutoCrop() passed NULL document" << endl; + return false; + } + + // OPT: if already pulled selection pixmap, no need to do it again here + QPixmap pixmap = doc->selection () ? doc->getSelectedPixmap () : *doc->pixmap (); + if (pixmap.isNull ()) + { + kdError () << "kptoolAutoCrop() pased NULL pixmap" << endl; + return false; + } + + kpViewManager *vm = mainWindow->viewManager (); + if (!vm) + { + kdError () << "kpToolAutoCrop() passed NULL vm" << endl; + return false; + } + + int processedColorSimilarity = mainWindow->colorToolBar ()->processedColorSimilarity (); + kpToolAutoCropBorder leftBorder (&pixmap, processedColorSimilarity), + rightBorder (&pixmap, processedColorSimilarity), + topBorder (&pixmap, processedColorSimilarity), + botBorder (&pixmap, processedColorSimilarity); + + + kpSetOverrideCursorSaver cursorSaver (Qt::waitCursor); + + // TODO: With Colour Similarity, a lot of weird (and wonderful) things can + // happen resulting in a huge number of code paths. Needs refactoring + // and regression testing. + // + // TODO: e.g. When the top fills entire rect but bot doesn't we could + // invalidate top and continue autocrop. + int numRegions = 0; + if (!leftBorder.calculate (true/*x*/, +1/*going right*/) || + leftBorder.fillsEntirePixmap () || + !rightBorder.calculate (true/*x*/, -1/*going left*/) || + rightBorder.fillsEntirePixmap () || + !topBorder.calculate (false/*y*/, +1/*going down*/) || + topBorder.fillsEntirePixmap () || + !botBorder.calculate (false/*y*/, -1/*going up*/) || + botBorder.fillsEntirePixmap () || + ((numRegions = leftBorder.exists () + + rightBorder.exists () + + topBorder.exists () + + botBorder.exists ()) == 0)) + { + #if DEBUG_KP_TOOL_AUTO_CROP + kdDebug () << "\tcan't find border; leftBorder.rect=" << leftBorder.rect () + << " rightBorder.rect=" << rightBorder.rect () + << " topBorder.rect=" << topBorder.rect () + << " botBorder.rect=" << botBorder.rect () + << endl; + #endif + ::showNothingToAutocropMessage (mainWindow, (bool) doc->selection ()); + return false; + } + +#if DEBUG_KP_TOOL_AUTO_CROP + kdDebug () << "\tnumRegions=" << numRegions << endl; + kdDebug () << "\t\tleft=" << leftBorder.rect () + << " refCol=" << (leftBorder.exists () ? (int *) leftBorder.referenceColor ().toQRgb () : 0) + << " avgCol=" << (leftBorder.exists () ? (int *) leftBorder.averageColor ().toQRgb () : 0) + << endl; + kdDebug () << "\t\tright=" << rightBorder.rect () + << " refCol=" << (rightBorder.exists () ? (int *) rightBorder.referenceColor ().toQRgb () : 0) + << " avgCol=" << (rightBorder.exists () ? (int *) rightBorder.averageColor ().toQRgb () : 0) + << endl; + kdDebug () << "\t\ttop=" << topBorder.rect () + << " refCol=" << (topBorder.exists () ? (int *) topBorder.referenceColor ().toQRgb () : 0) + << " avgCol=" << (topBorder.exists () ? (int *) topBorder.averageColor ().toQRgb () : 0) + << endl; + kdDebug () << "\t\tbot=" << botBorder.rect () + << " refCol=" << (botBorder.exists () ? (int *) botBorder.referenceColor ().toQRgb () : 0) + << " avgCol=" << (botBorder.exists () ? (int *) botBorder.averageColor ().toQRgb () : 0) + << endl; +#endif + + + // In case e.g. the user pastes a solid, coloured-in rectangle, + // we favour killing the bottom and right regions + // (these regions probably contain the unwanted whitespace due + // to the doc being bigger than the pasted selection to start with). + // + // We also kill if they kiss or even overlap. + + if (leftBorder.exists () && rightBorder.exists ()) + { + const kpColor leftCol = leftBorder.averageColor (); + const kpColor rightCol = rightBorder.averageColor (); + + if ((numRegions == 2 && !leftCol.isSimilarTo (rightCol, processedColorSimilarity)) || + leftBorder.right () >= rightBorder.left () - 1) // kissing or overlapping + { + #if DEBUG_KP_TOOL_AUTO_CROP + kdDebug () << "\tignoring left border" << endl; + #endif + leftBorder.invalidate (); + } + } + + if (topBorder.exists () && botBorder.exists ()) + { + const kpColor topCol = topBorder.averageColor (); + const kpColor botCol = botBorder.averageColor (); + + if ((numRegions == 2 && !topCol.isSimilarTo (botCol, processedColorSimilarity)) || + topBorder.bottom () >= botBorder.top () - 1) // kissing or overlapping + { + #if DEBUG_KP_TOOL_AUTO_CROP + kdDebug () << "\tignoring top border" << endl; + #endif + topBorder.invalidate (); + } + } + + + mainWindow->addImageOrSelectionCommand ( + new kpToolAutoCropCommand ( + (bool) doc->selection (), + leftBorder, rightBorder, + topBorder, botBorder, + mainWindow)); + + + return true; +} + + +kpToolAutoCropCommand::kpToolAutoCropCommand (bool actOnSelection, + const kpToolAutoCropBorder &leftBorder, + const kpToolAutoCropBorder &rightBorder, + const kpToolAutoCropBorder &topBorder, + const kpToolAutoCropBorder &botBorder, + kpMainWindow *mainWindow) + : kpNamedCommand (name (actOnSelection, DontShowAccel), mainWindow), + m_actOnSelection (actOnSelection), + m_leftBorder (leftBorder), + m_rightBorder (rightBorder), + m_topBorder (topBorder), + m_botBorder (botBorder), + m_leftPixmap (0), + m_rightPixmap (0), + m_topPixmap (0), + m_botPixmap (0) +{ + kpDocument *doc = document (); + if (!doc) + { + kdError () << "kpToolAutoCropCommand::() without doc" << endl; + m_oldWidth = 0; + m_oldHeight = 0; + return; + } + + m_oldWidth = doc->width (m_actOnSelection); + m_oldHeight = doc->height (m_actOnSelection); +} + +kpToolAutoCropCommand::~kpToolAutoCropCommand () +{ + deleteUndoPixmaps (); +} + + +// public static +QString kpToolAutoCropCommand::name (bool actOnSelection, int options) +{ + if (actOnSelection) + { + if (options & ShowAccel) + return i18n ("Remove Internal B&order"); + else + return i18n ("Remove Internal Border"); + } + else + { + if (options & ShowAccel) + return i18n ("Autocr&op"); + else + return i18n ("Autocrop"); + } +} + + +// public virtual [base kpCommand] +int kpToolAutoCropCommand::size () const +{ + return m_leftBorder.size () + + m_rightBorder.size () + + m_topBorder.size () + + m_botBorder.size () + + kpPixmapFX::pixmapSize (m_leftPixmap) + + kpPixmapFX::pixmapSize (m_rightPixmap) + + kpPixmapFX::pixmapSize (m_topPixmap) + + kpPixmapFX::pixmapSize (m_botPixmap) + + m_oldSelection.size (); +} + + +// private +void kpToolAutoCropCommand::getUndoPixmap (const kpToolAutoCropBorder &border, QPixmap **pixmap) +{ + kpDocument *doc = document (); + +#if DEBUG_KP_TOOL_AUTO_CROP && 1 + kdDebug () << "kpToolAutoCropCommand::getUndoPixmap()" << endl; + kdDebug () << "\tpixmap=" << pixmap + << " border: rect=" << border.rect () + << " isSingleColor=" << border.isSingleColor () + << endl; +#endif + + if (!doc) + return; + + if (pixmap && border.exists () && !border.isSingleColor ()) + { + if (*pixmap) + { + #if DEBUG_KP_TOOL_AUTO_CROP && 1 + kdDebug () << "\talready have *pixmap - delete it" << endl; + #endif + delete *pixmap; + } + + *pixmap = new QPixmap ( + kpPixmapFX::getPixmapAt (*doc->pixmap (m_actOnSelection), + border.rect ())); + } +} + + +// private +void kpToolAutoCropCommand::getUndoPixmaps () +{ + getUndoPixmap (m_leftBorder, &m_leftPixmap); + getUndoPixmap (m_rightBorder, &m_rightPixmap); + getUndoPixmap (m_topBorder, &m_topPixmap); + getUndoPixmap (m_botBorder, &m_botPixmap); +} + +// private +void kpToolAutoCropCommand::deleteUndoPixmaps () +{ +#if DEBUG_KP_TOOL_AUTO_CROP && 1 + kdDebug () << "kpToolAutoCropCommand::deleteUndoPixmaps()" << endl; +#endif + + delete m_leftPixmap; m_leftPixmap = 0; + delete m_rightPixmap; m_rightPixmap = 0; + delete m_topPixmap; m_topPixmap = 0; + delete m_botPixmap; m_botPixmap = 0; +} + + +// public virtual [base kpCommand] +void kpToolAutoCropCommand::execute () +{ + if (!m_contentsRect.isValid ()) + m_contentsRect = contentsRect (); + + + getUndoPixmaps (); + + + kpDocument *doc = document (); + if (!doc) + return; + + + QPixmap pixmapWithoutBorder = + kpTool::neededPixmap (*doc->pixmap (m_actOnSelection), + m_contentsRect); + + + if (!m_actOnSelection) + doc->setPixmap (pixmapWithoutBorder); + else + { + m_oldSelection = *doc->selection (); + m_oldSelection.setPixmap (QPixmap ()); + + // m_contentsRect is relative to the top of the sel + // while sel is relative to the top of the doc + QRect rect = m_contentsRect; + rect.moveBy (m_oldSelection.x (), m_oldSelection.y ()); + + kpSelection sel (kpSelection::Rectangle, + rect, + pixmapWithoutBorder, + m_oldSelection.transparency ()); + + doc->setSelection (sel); + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + } +} + +// public virtual [base kpCommand] +void kpToolAutoCropCommand::unexecute () +{ +#if DEBUG_KP_TOOL_AUTO_CROP && 1 + kdDebug () << "kpToolAutoCropCommand::unexecute()" << endl; +#endif + + kpDocument *doc = document (); + if (!doc) + return; + + QPixmap pixmap (m_oldWidth, m_oldHeight); + QBitmap maskBitmap; + + // restore the position of the centre image + kpPixmapFX::setPixmapAt (&pixmap, m_contentsRect, + *doc->pixmap (m_actOnSelection)); + + // draw the borders + + QPainter painter (&pixmap); + QPainter maskPainter; + + const kpToolAutoCropBorder *borders [] = + { + &m_leftBorder, &m_rightBorder, + &m_topBorder, &m_botBorder, + 0 + }; + + const QPixmap *pixmaps [] = + { + m_leftPixmap, m_rightPixmap, + m_topPixmap, m_botPixmap, + 0 + }; + + const QPixmap **p = pixmaps; + for (const kpToolAutoCropBorder **b = borders; *b; b++, p++) + { + if (!(*b)->exists ()) + continue; + + if ((*b)->isSingleColor ()) + { + kpColor col = (*b)->referenceColor (); + #if DEBUG_KP_TOOL_AUTO_CROP && 1 + kdDebug () << "\tdrawing border " << (*b)->rect () + << " rgb=" << (int *) col.toQRgb () /* %X hack */ << endl; + #endif + + if (col.isOpaque ()) + { + painter.fillRect ((*b)->rect (), col.toQColor ()); + } + else + { + if (maskBitmap.isNull ()) + { + // TODO: dangerous when a painter is active on pixmap? + maskBitmap = kpPixmapFX::getNonNullMask (pixmap); + maskPainter.begin (&maskBitmap); + } + + maskPainter.fillRect ((*b)->rect (), Qt::color0/*transparent*/); + } + } + else + { + #if DEBUG_KP_TOOL_AUTO_CROP && 1 + kdDebug () << "\trestoring border pixmap " << (*b)->rect () << endl; + #endif + // **p cannot contain a single transparent pixel because + // if it did, all other pixels must be transparent (only + // transparent pixels are similar to transparent pixels) + // and the other branch would execute. + if (*p) + { + // TODO: We should really edit the mask here. Due to good + // luck (if "maskBitmap" is initialized above, this region + // will be marked as opaque in the mask; if it's not + // initialized, we will be opaque by default), we + // don't actually have to edit the mask but this is + // highly error-prone. + painter.drawPixmap ((*b)->rect (), **p); + } + } + } + + if (maskPainter.isActive ()) + maskPainter.end (); + + painter.end (); + + if (!maskBitmap.isNull ()) + pixmap.setMask (maskBitmap); + + + if (!m_actOnSelection) + doc->setPixmap (pixmap); + else + { + kpSelection sel = m_oldSelection; + sel.setPixmap (pixmap); + + doc->setSelection (sel); + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + } + + + deleteUndoPixmaps (); +} + + +// private +QRect kpToolAutoCropCommand::contentsRect () const +{ + const QPixmap *pixmap = document ()->pixmap (m_actOnSelection); + + QPoint topLeft (m_leftBorder.exists () ? + m_leftBorder.rect ().right () + 1 : + 0, + m_topBorder.exists () ? + m_topBorder.rect ().bottom () + 1 : + 0); + QPoint botRight (m_rightBorder.exists () ? + m_rightBorder.rect ().left () - 1 : + pixmap->width () - 1, + m_botBorder.exists () ? + m_botBorder.rect ().top () - 1 : + pixmap->height () - 1); + + return QRect (topLeft, botRight); +} diff --git a/kolourpaint/tools/kptoolautocrop.h b/kolourpaint/tools/kptoolautocrop.h new file mode 100644 index 00000000..4d016a1d --- /dev/null +++ b/kolourpaint/tools/kptoolautocrop.h @@ -0,0 +1,127 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolautocrop_h__ +#define __kptoolautocrop_h__ + +#include + +#include + +#include +#include + +class QPixmap; +class kpDocument; +class kpMainWindow; +class kpViewManager; + + +// (returns true on success (even if it did nothing) or false on error) +bool kpToolAutoCrop (kpMainWindow *mainWindow); + + +class kpToolAutoCropBorder +{ +public: + kpToolAutoCropBorder (const QPixmap *pixmapPtr, int processedColorSimilarity); + + int size () const; + + const QPixmap *pixmap () const; + int processedColorSimilarity () const; + QRect rect () const; + int left () const; + int right () const; + int top () const; + int bottom () const; + kpColor referenceColor () const; + kpColor averageColor () const; + bool isSingleColor () const; + + // (returns true on success (even if no rect) or false on error) + bool calculate (int isX, int dir); + + bool fillsEntirePixmap () const; + bool exists () const; + void invalidate (); + +private: + const QPixmap *m_pixmapPtr; + int m_processedColorSimilarity; + + QRect m_rect; + kpColor m_referenceColor; + int m_redSum, m_greenSum, m_blueSum; + bool m_isSingleColor; +}; + + +class kpToolAutoCropCommand : public kpNamedCommand +{ +public: + kpToolAutoCropCommand (bool actOnSelection, + const kpToolAutoCropBorder &leftBorder, + const kpToolAutoCropBorder &rightBorder, + const kpToolAutoCropBorder &topBorder, + const kpToolAutoCropBorder &botBorder, + kpMainWindow *mainWindow); + virtual ~kpToolAutoCropCommand (); + + enum NameOptions + { + DontShowAccel = 0, + ShowAccel = 1 + }; + + static QString name (bool actOnSelection, int options); + + virtual int size () const; + +private: + void getUndoPixmap (const kpToolAutoCropBorder &border, QPixmap **pixmap); + void getUndoPixmaps (); + void deleteUndoPixmaps (); + +public: + virtual void execute (); + virtual void unexecute (); + +private: + QRect contentsRect () const; + + bool m_actOnSelection; + kpToolAutoCropBorder m_leftBorder, m_rightBorder, m_topBorder, m_botBorder; + QPixmap *m_leftPixmap, *m_rightPixmap, *m_topPixmap, *m_botPixmap; + + QRect m_contentsRect; + int m_oldWidth, m_oldHeight; + kpSelection m_oldSelection; +}; + +#endif // __kptoolautocrop_h__ diff --git a/kolourpaint/tools/kptoolbrush.cpp b/kolourpaint/tools/kptoolbrush.cpp new file mode 100644 index 00000000..6e684ed9 --- /dev/null +++ b/kolourpaint/tools/kptoolbrush.cpp @@ -0,0 +1,45 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include + +kpToolBrush::kpToolBrush (kpMainWindow *mainWindow) + : kpToolPen (kpToolPen::Brush, + i18n ("Brush"), + i18n ("Draw using brushes of different shapes and sizes"), + Qt::Key_B, + mainWindow, "tool_brush") +{ +} + +kpToolBrush::~kpToolBrush () +{ +} + +#include diff --git a/kolourpaint/tools/kptoolbrush.h b/kolourpaint/tools/kptoolbrush.h new file mode 100644 index 00000000..69498495 --- /dev/null +++ b/kolourpaint/tools/kptoolbrush.h @@ -0,0 +1,43 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolbrush_h__ +#define __kptoolbrush_h__ + +#include + +class kpToolBrush : public kpToolPen +{ +Q_OBJECT + +public: + kpToolBrush (kpMainWindow *mainWindow); + virtual ~kpToolBrush (); +}; + +#endif // __kptoolbrush_h__ diff --git a/kolourpaint/tools/kptoolclear.cpp b/kolourpaint/tools/kptoolclear.cpp new file mode 100644 index 00000000..230e54a3 --- /dev/null +++ b/kolourpaint/tools/kptoolclear.cpp @@ -0,0 +1,135 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + + +kpToolClearCommand::kpToolClearCommand (bool actOnSelection, + const kpColor &newColor, + kpMainWindow *mainWindow) + : kpCommand (mainWindow), + m_actOnSelection (actOnSelection), + m_newColor (newColor), + m_oldPixmapPtr (0) +{ +} + +kpToolClearCommand::kpToolClearCommand (bool actOnSelection, + kpMainWindow *mainWindow) + : kpCommand (mainWindow), + m_actOnSelection (actOnSelection), + m_newColor (mainWindow ? mainWindow->backgroundColor () : kpColor::invalid), + m_oldPixmapPtr (0) +{ +} + +kpToolClearCommand::~kpToolClearCommand () +{ + delete m_oldPixmapPtr; +} + + +// public virtual [base kpCommand] +QString kpToolClearCommand::name () const +{ + QString opName = i18n ("Clear"); + + if (m_actOnSelection) + return i18n ("Selection: %1").arg (opName); + else + return opName; +} + + +// public virtual [base kpCommand] +int kpToolClearCommand::size () const +{ + return kpPixmapFX::pixmapSize (m_oldPixmapPtr); +} + + +// public virtual [base kpCommand] +void kpToolClearCommand::execute () +{ + kpDocument *doc = document (); + if (!doc) + { + kdError () << "kpToolClearCommand::execute() without doc" << endl; + return; + } + + + m_oldPixmapPtr = new QPixmap (); + *m_oldPixmapPtr = *doc->pixmap (m_actOnSelection); + + + if (m_actOnSelection) + { + // OPT: could just edit pixmap directly and signal change + kpSelection *sel = doc->selection (); + + QPixmap newPixmap (sel->width (), sel->height ()); + kpPixmapFX::fill (&newPixmap, m_newColor); + // TODO: maybe disable Image/Clear if transparent colour + if (m_newColor.isOpaque ()) + newPixmap.setMask (sel->maskForOwnType ()); + + sel->setPixmap (newPixmap); + } + else + doc->fill (m_newColor); +} + +// public virtual [base kpCommand] +void kpToolClearCommand::unexecute () +{ + kpDocument *doc = document (); + if (!doc) + { + kdError () << "kpToolClearCommand::execute() without doc" << endl; + return; + } + + + doc->setPixmap (m_actOnSelection, *m_oldPixmapPtr); + + + delete m_oldPixmapPtr; + m_oldPixmapPtr = 0; +} diff --git a/kolourpaint/tools/kptoolclear.h b/kolourpaint/tools/kptoolclear.h new file mode 100644 index 00000000..ccf3697f --- /dev/null +++ b/kolourpaint/tools/kptoolclear.h @@ -0,0 +1,68 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolclear_h__ +#define __kptoolclear_h__ + +#include + +#include + +class QPixmap; +class QString; + +class kpDocument; +class kpMainWindow; + + +class kpToolClearCommand : public kpCommand +{ +public: + kpToolClearCommand (bool actOnSelection, + const kpColor &newColor, + kpMainWindow *mainWindow); + kpToolClearCommand (bool actOnSelection, + kpMainWindow *mainWindow); + virtual ~kpToolClearCommand (); + + virtual QString name () const; + + virtual int size () const; + + virtual void execute (); + virtual void unexecute (); + +private: + bool m_actOnSelection; + + kpColor m_newColor; + QPixmap *m_oldPixmapPtr; +}; + + +#endif // __kptoolclear_h__ diff --git a/kolourpaint/tools/kptoolcolorpicker.cpp b/kolourpaint/tools/kptoolcolorpicker.cpp new file mode 100644 index 00000000..1050b1cf --- /dev/null +++ b/kolourpaint/tools/kptoolcolorpicker.cpp @@ -0,0 +1,197 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_TOOL_COLOR_PICKER 0 + + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + + +/* + * kpToolColorPicker + */ + +kpToolColorPicker::kpToolColorPicker (kpMainWindow *mainWindow) + : kpTool (i18n ("Color Picker"), i18n ("Lets you select a color from the image"), + Qt::Key_C, + mainWindow, "tool_color_picker") +{ +} + +kpToolColorPicker::~kpToolColorPicker () +{ +} + +kpColor kpToolColorPicker::colorAtPixel (const QPoint &p) +{ +#if DEBUG_KP_TOOL_COLOR_PICKER && 0 + kdDebug () << "kpToolColorPicker::colorAtPixel" << p << endl; +#endif + + return kpPixmapFX::getColorAtPixel (*document ()->pixmap (), p); +} + + +QString kpToolColorPicker::haventBegunDrawUserMessage () const +{ + return i18n ("Click to select a color."); +} + +void kpToolColorPicker::begin () +{ + setUserMessage (haventBegunDrawUserMessage ()); +} + +// virtual +void kpToolColorPicker::beginDraw () +{ + m_oldColor = color (m_mouseButton); + + setUserMessage (cancelUserMessage ()); +} + +// virtual +void kpToolColorPicker::draw (const QPoint &thisPoint, const QPoint &, const QRect &) +{ + const kpColor color = colorAtPixel (thisPoint); + + if (color.isValid ()) + { + mainWindow ()->colorToolBar ()->setColor (m_mouseButton, color); + setUserShapePoints (thisPoint); + } + else + { + mainWindow ()->colorToolBar ()->setColor (m_mouseButton, m_oldColor); + setUserShapePoints (); + } +} + +// virtual +void kpToolColorPicker::cancelShape () +{ + mainWindow ()->colorToolBar ()->setColor (m_mouseButton, m_oldColor); + + setUserMessage (i18n ("Let go of all the mouse buttons.")); +} + +void kpToolColorPicker::releasedAllButtons () +{ + setUserMessage (haventBegunDrawUserMessage ()); + +} + +// virtual +void kpToolColorPicker::endDraw (const QPoint &thisPoint, const QRect &) +{ + const kpColor color = colorAtPixel (thisPoint); + + if (color.isValid ()) + { + kpToolColorPickerCommand *cmd = new kpToolColorPickerCommand ( + m_mouseButton, + color, m_oldColor, + mainWindow ()); + + mainWindow ()->commandHistory ()->addCommand (cmd, false /* no exec */); + setUserMessage (haventBegunDrawUserMessage ()); + } + else + { + cancelShape (); + } +} + +/* + * kpToolColorPickerCommand + */ + +kpToolColorPickerCommand::kpToolColorPickerCommand (int mouseButton, + const kpColor &newColor, + const kpColor &oldColor, + kpMainWindow *mainWindow) + : kpCommand (mainWindow), + m_mouseButton (mouseButton), + m_newColor (newColor), + m_oldColor (oldColor) +{ +} + +kpToolColorPickerCommand::~kpToolColorPickerCommand () +{ +} + + +// public virtual [base kpCommand] +QString kpToolColorPickerCommand::name () const +{ + return i18n ("Color Picker"); +} + + +// public virtual [base kpCommand] +int kpToolColorPickerCommand::size () const +{ + return 0; +} + + +// public virtual [base kpCommand] +void kpToolColorPickerCommand::execute () +{ + colorToolBar ()->setColor (m_mouseButton, m_newColor); +} + +// public virtual [base kpCommand] +void kpToolColorPickerCommand::unexecute () +{ + colorToolBar ()->setColor (m_mouseButton, m_oldColor); +} + + +// private +kpColorToolBar *kpToolColorPickerCommand::colorToolBar () const +{ + return m_mainWindow ? m_mainWindow->colorToolBar () : 0; +} + +#include diff --git a/kolourpaint/tools/kptoolcolorpicker.h b/kolourpaint/tools/kptoolcolorpicker.h new file mode 100644 index 00000000..46fc94be --- /dev/null +++ b/kolourpaint/tools/kptoolcolorpicker.h @@ -0,0 +1,95 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolcolorpicker_h__ +#define __kptoolcolorpicker_h__ + +#include + +#include +#include + +class QPoint; +class QRect; + +class kpColorToolBar; + +class kpToolColorPicker : public kpTool +{ +Q_OBJECT + +public: + kpToolColorPicker (kpMainWindow *); + virtual ~kpToolColorPicker (); + + // generally the user goes to pick a color but wants to return to using + // his/her previous drawing tool + virtual bool returnToPreviousToolAfterEndDraw () const { return true; } + +private: + QString haventBegunDrawUserMessage () const; + +public: + virtual void begin (); + virtual void beginDraw (); + virtual void draw (const QPoint &thisPoint, const QPoint &, const QRect &); + virtual void cancelShape (); + virtual void releasedAllButtons (); + virtual void endDraw (const QPoint &thisPoint, const QRect &); + +private: + kpColor colorAtPixel (const QPoint &p); + + kpColor m_oldColor; +}; + +class kpToolColorPickerCommand : public kpCommand +{ +public: + kpToolColorPickerCommand (int mouseButton, + const kpColor &newColor, const kpColor &oldColor, + kpMainWindow *mainWindow); + virtual ~kpToolColorPickerCommand (); + + virtual QString name () const; + + virtual int size () const; + + virtual void execute (); + virtual void unexecute (); + +private: + kpColorToolBar *colorToolBar () const; + +private: + int m_mouseButton; + kpColor m_newColor; + kpColor m_oldColor; +}; + +#endif // __kptoolcolorpicker_h__ diff --git a/kolourpaint/tools/kptoolcolorwasher.cpp b/kolourpaint/tools/kptoolcolorwasher.cpp new file mode 100644 index 00000000..6c2d091f --- /dev/null +++ b/kolourpaint/tools/kptoolcolorwasher.cpp @@ -0,0 +1,45 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include + +kpToolColorWasher::kpToolColorWasher (kpMainWindow *mainWindow) + : kpToolPen (kpToolPen::ColorWasher, + i18n ("Color Eraser"), + i18n ("Replaces pixels of the foreground color with the background color"), + Qt::Key_O, + mainWindow, "tool_color_washer") +{ +} + +kpToolColorWasher::~kpToolColorWasher () +{ +} + +#include diff --git a/kolourpaint/tools/kptoolcolorwasher.h b/kolourpaint/tools/kptoolcolorwasher.h new file mode 100644 index 00000000..1a707c3e --- /dev/null +++ b/kolourpaint/tools/kptoolcolorwasher.h @@ -0,0 +1,43 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolcolorwasher_h__ +#define __kptoolcolorwasher_h__ + +#include + +class kpToolColorWasher : public kpToolPen +{ +Q_OBJECT + +public: + kpToolColorWasher (kpMainWindow *mainWindow); + virtual ~kpToolColorWasher (); +}; + +#endif // __kptoolcolorwasher_h__ diff --git a/kolourpaint/tools/kptoolconverttograyscale.cpp b/kolourpaint/tools/kptoolconverttograyscale.cpp new file mode 100644 index 00000000..a80ef8fa --- /dev/null +++ b/kolourpaint/tools/kptoolconverttograyscale.cpp @@ -0,0 +1,106 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + + +kpToolConvertToGrayscaleCommand::kpToolConvertToGrayscaleCommand (bool actOnSelection, + kpMainWindow *mainWindow) + : kpCommand (mainWindow), + m_actOnSelection (actOnSelection), + m_oldPixmapPtr (0) +{ +} + +kpToolConvertToGrayscaleCommand::~kpToolConvertToGrayscaleCommand () +{ + delete m_oldPixmapPtr; +} + + +// public virtual [base kpCommand] +QString kpToolConvertToGrayscaleCommand::name () const +{ + QString opName = i18n ("Reduce to Grayscale"); + + if (m_actOnSelection) + return i18n ("Selection: %1").arg (opName); + else + return opName; +} + + +// public virtual [base kpCommand] +int kpToolConvertToGrayscaleCommand::size () const +{ + return kpPixmapFX::pixmapSize (m_oldPixmapPtr); +} + + +// public virtual [base kpCommand] +void kpToolConvertToGrayscaleCommand::execute () +{ + kpDocument *doc = document (); + if (!doc) + return; + + QApplication::setOverrideCursor (Qt::waitCursor); + + m_oldPixmapPtr = new QPixmap (); + *m_oldPixmapPtr = *doc->pixmap (m_actOnSelection); + + QPixmap newPixmap = kpPixmapFX::convertToGrayscale (*doc->pixmap (m_actOnSelection)); + + doc->setPixmap (m_actOnSelection, newPixmap); + + QApplication::restoreOverrideCursor (); +} + +// public virtual [base kpCommand] +void kpToolConvertToGrayscaleCommand::unexecute () +{ + kpDocument *doc = document (); + if (!doc) + return; + + doc->setPixmap (m_actOnSelection, *m_oldPixmapPtr); + + delete m_oldPixmapPtr; + m_oldPixmapPtr = 0; +} + diff --git a/kolourpaint/tools/kptoolconverttograyscale.h b/kolourpaint/tools/kptoolconverttograyscale.h new file mode 100644 index 00000000..6ea5e515 --- /dev/null +++ b/kolourpaint/tools/kptoolconverttograyscale.h @@ -0,0 +1,57 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolconverttograyscale_h__ +#define __kptoolconverttograyscale_h__ + +#include + +class QPixmap; +class QString; + +class kpMainWindow; + +class kpToolConvertToGrayscaleCommand : public kpCommand +{ +public: + kpToolConvertToGrayscaleCommand (bool actOnSelection, + kpMainWindow *mainWindow); + virtual ~kpToolConvertToGrayscaleCommand (); + + virtual QString name () const; + virtual int size () const; + + virtual void execute (); + virtual void unexecute (); + +private: + bool m_actOnSelection; + QPixmap *m_oldPixmapPtr; +}; + +#endif // __kptoolconverttograyscale_h__ diff --git a/kolourpaint/tools/kptoolcrop.cpp b/kolourpaint/tools/kptoolcrop.cpp new file mode 100644 index 00000000..8cc6e880 --- /dev/null +++ b/kolourpaint/tools/kptoolcrop.cpp @@ -0,0 +1,335 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_TOOL_CROP 0 + + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +kpSelection selectionBorderAndMovedTo0_0 (const kpSelection &sel) +{ + kpSelection borderSel = sel; + + borderSel.setPixmap (QPixmap ()); // only interested in border + borderSel.moveTo (QPoint (0, 0)); + + return borderSel; +} + + +// +// kpToolCropSetImageCommand +// + +class kpToolCropSetImageCommand : public kpCommand +{ +public: + kpToolCropSetImageCommand (kpMainWindow *mainWindow); + virtual ~kpToolCropSetImageCommand (); + + /* (uninteresting child of macro cmd) */ + virtual QString name () const { return QString::null; } + + virtual int size () const + { + return kpPixmapFX::pixmapSize (m_oldPixmap) + + kpPixmapFX::selectionSize (m_fromSelection) + + kpPixmapFX::pixmapSize (m_pixmapIfFromSelectionDoesntHaveOne); + } + + virtual void execute (); + virtual void unexecute (); + +protected: + kpColor m_backgroundColor; + QPixmap m_oldPixmap; + kpSelection m_fromSelection; + QPixmap m_pixmapIfFromSelectionDoesntHaveOne; +}; + + +kpToolCropSetImageCommand::kpToolCropSetImageCommand (kpMainWindow *mainWindow) + : kpCommand (mainWindow), + m_backgroundColor (mainWindow ? mainWindow->backgroundColor () : kpColor::invalid), + m_fromSelection (*mainWindow->document ()->selection ()), + m_pixmapIfFromSelectionDoesntHaveOne ( + m_fromSelection.pixmap () ? + QPixmap () : + mainWindow->document ()->getSelectedPixmap ()) +{ +} + +kpToolCropSetImageCommand::~kpToolCropSetImageCommand () +{ +} + + +// public virtual [base kpCommand] +void kpToolCropSetImageCommand::execute () +{ +#if DEBUG_KP_TOOL_CROP + kdDebug () << "kpToolCropSetImageCommand::execute()" << endl; +#endif + + viewManager ()->setQueueUpdates (); + { + m_oldPixmap = kpPixmapFX::getPixmapAt (*document ()->pixmap (), + QRect (0, 0, m_fromSelection.width (), m_fromSelection.height ())); + + + // + // e.g. original elliptical selection: + // + // t/---\ T = original transparent selection pixel + // | TT | t = outside the selection region + // t\__/t [every other character] = original opaque selection pixel + // + // Afterwards, the _document_ image becomes: + // + // b/---\ T = [unchanged] + // | TT | b = background color + // b\__/b [every other character] = [unchanged] + // + // The selection is deleted. + // + // TODO: Do not introduce a mask if the result will not contain + // any transparent pixels. + // + + QPixmap newDocPixmap (m_fromSelection.width (), m_fromSelection.height ()); + kpPixmapFX::fill (&newDocPixmap, m_backgroundColor); + + #if DEBUG_KP_TOOL_CROP + kdDebug () << "\tsel: rect=" << m_fromSelection.boundingRect () + << " pm=" << m_fromSelection.pixmap () + << endl; + #endif + QPixmap selTransparentPixmap; + + if (m_fromSelection.pixmap ()) + { + selTransparentPixmap = m_fromSelection.transparentPixmap (); + #if DEBUG_KP_TOOL_CROP + kdDebug () << "\thave pixmap; rect=" + << selTransparentPixmap.rect () + << endl; + #endif + } + else + { + selTransparentPixmap = m_pixmapIfFromSelectionDoesntHaveOne; + #if DEBUG_KP_TOOL_CROP + kdDebug () << "\tno pixmap in sel - get it; rect=" + << selTransparentPixmap.rect () + << endl; + #endif + } + + kpPixmapFX::paintMaskTransparentWithBrush (&newDocPixmap, + QPoint (0, 0), + m_fromSelection.maskForOwnType ()); + + kpPixmapFX::paintPixmapAt (&newDocPixmap, + QPoint (0, 0), + selTransparentPixmap); + + + document ()->setPixmapAt (newDocPixmap, QPoint (0, 0)); + document ()->selectionDelete (); + + + if (mainWindow ()->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + } + viewManager ()->restoreQueueUpdates (); +} + +// public virtual [base kpCommand] +void kpToolCropSetImageCommand::unexecute () +{ +#if DEBUG_KP_TOOL_CROP + kdDebug () << "kpToolCropSetImageCommand::unexecute()" << endl; +#endif + + viewManager ()->setQueueUpdates (); + { + document ()->setPixmapAt (m_oldPixmap, QPoint (0, 0)); + m_oldPixmap.resize (0, 0); + + #if DEBUG_KP_TOOL_CROP + kdDebug () << "\tsel: rect=" << m_fromSelection.boundingRect () + << " pm=" << m_fromSelection.pixmap () + << endl; + #endif + document ()->setSelection (m_fromSelection); + + if (mainWindow ()->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + } + viewManager ()->restoreQueueUpdates (); +} + + +// +// kpToolCropCommand +// + + +class kpToolCropCommand : public kpMacroCommand +{ +public: + kpToolCropCommand (kpMainWindow *mainWindow); + virtual ~kpToolCropCommand (); +}; + + +kpToolCropCommand::kpToolCropCommand (kpMainWindow *mainWindow) + : kpMacroCommand (i18n ("Set as Image"), mainWindow) +{ +#if DEBUG_KP_TOOL_CROP + kdDebug () << "kpToolCropCommand::()" << endl; +#endif + + if (!mainWindow || + !mainWindow->document () || + !mainWindow->document ()->selection ()) + { + kdError () << "kpToolCropCommand::kpToolCropCommand() without sel" << endl; + return; + } + + kpSelection *sel = mainWindow->document ()->selection (); + + +#if DEBUG_KP_TOOL_CROP + kdDebug () << "\tsel: w=" << sel->width () + << " h=" << sel->height () + << " <- resizing doc to these dimen" << endl; +#endif + + // (must resize doc _before_ kpToolCropSetImageCommand in case doc + // needs to gets bigger - else pasted down pixmap may not fit) + addCommand ( + new kpToolResizeScaleCommand ( + false/*act on doc, not sel*/, + sel->width (), sel->height (), + kpToolResizeScaleCommand::Resize, + mainWindow)); + + + if (sel->isText ()) + { + #if DEBUG_KP_TOOL_CROP + kdDebug () << "\tisText" << endl; + kdDebug () << "\tclearing doc with trans cmd" << endl; + #endif + addCommand ( + new kpToolClearCommand ( + false/*act on doc*/, + kpColor::transparent, + mainWindow)); + + #if DEBUG_KP_TOOL_CROP + kdDebug () << "\tmoving sel to (0,0) cmd" << endl; + #endif + kpToolSelectionMoveCommand *moveCmd = + new kpToolSelectionMoveCommand ( + QString::null/*uninteresting child of macro cmd*/, + mainWindow); + moveCmd->moveTo (QPoint (0, 0), true/*move on exec, not now*/); + moveCmd->finalize (); + addCommand (moveCmd); + } + else + { + #if DEBUG_KP_TOOL_CROP + kdDebug () << "\tis pixmap sel" << endl; + kdDebug () << "\tcreating SetImage cmd" << endl; + #endif + addCommand (new kpToolCropSetImageCommand (mainWindow)); + + #if 0 + addCommand ( + new kpToolSelectionCreateCommand ( + QString::null/*uninteresting child of macro cmd*/, + selectionBorderAndMovedTo0_0 (*sel), + mainWindow)); + #endif + } +} + +kpToolCropCommand::~kpToolCropCommand () +{ +} + + +void kpToolCrop (kpMainWindow *mainWindow) +{ + kpDocument *doc = mainWindow->document (); + if (!doc) + return; + + kpSelection *sel = doc ? doc->selection () : 0; + if (!sel) + return; + + + bool selWasText = sel->isText (); + kpSelection borderSel = selectionBorderAndMovedTo0_0 (*sel); + + + mainWindow->addImageOrSelectionCommand ( + new kpToolCropCommand (mainWindow), + true/*add create cmd*/, + false/*don't add pull cmd*/); + + + if (!selWasText) + { + mainWindow->commandHistory ()->addCommand ( + new kpToolSelectionCreateCommand ( + i18n ("Selection: Create"), + borderSel, + mainWindow)); + } +} diff --git a/kolourpaint/tools/kptoolcrop.h b/kolourpaint/tools/kptoolcrop.h new file mode 100644 index 00000000..c710a041 --- /dev/null +++ b/kolourpaint/tools/kptoolcrop.h @@ -0,0 +1,39 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_TOOL_CROP_H +#define KP_TOOL_CROP_H + + +class kpMainWindow; + + +void kpToolCrop (kpMainWindow *mainWindow); + + +#endif // KP_TOOL_CROP_H diff --git a/kolourpaint/tools/kptoolcurve.cpp b/kolourpaint/tools/kptoolcurve.cpp new file mode 100644 index 00000000..f889c1ba --- /dev/null +++ b/kolourpaint/tools/kptoolcurve.cpp @@ -0,0 +1,47 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include + + +kpToolCurve::kpToolCurve (kpMainWindow *mainWindow) + : kpToolPolygon (Curve, + i18n ("Curve"), + i18n ("Draws curves"), + Qt::Key_V, + mainWindow, "tool_curve") +{ +} + +kpToolCurve::~kpToolCurve () +{ +} + +#include diff --git a/kolourpaint/tools/kptoolcurve.h b/kolourpaint/tools/kptoolcurve.h new file mode 100644 index 00000000..489ce1fb --- /dev/null +++ b/kolourpaint/tools/kptoolcurve.h @@ -0,0 +1,45 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolcurve_h__ +#define __kptoolcurve_h__ + +#include + +class kpMainWindow; + +class kpToolCurve : public kpToolPolygon +{ +Q_OBJECT + +public: + kpToolCurve (kpMainWindow *mainWindow); + virtual ~kpToolCurve (); +}; + +#endif // __kptoolcurve_h__ diff --git a/kolourpaint/tools/kptoolellipse.cpp b/kolourpaint/tools/kptoolellipse.cpp new file mode 100644 index 00000000..f3b31dbb --- /dev/null +++ b/kolourpaint/tools/kptoolellipse.cpp @@ -0,0 +1,45 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include + +kpToolEllipse::kpToolEllipse (kpMainWindow *mainWindow) + : kpToolRectangle (Ellipse, + i18n ("Ellipse"), + i18n ("Draws ellipses and circles"), + Qt::Key_E, + mainWindow, "tool_ellipse") +{ +} + +kpToolEllipse::~kpToolEllipse () +{ +} + +#include diff --git a/kolourpaint/tools/kptoolellipse.h b/kolourpaint/tools/kptoolellipse.h new file mode 100644 index 00000000..fc9bf798 --- /dev/null +++ b/kolourpaint/tools/kptoolellipse.h @@ -0,0 +1,45 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolellipse_h__ +#define __kptoolellipse_h__ + +#include + +class kpMainWindow; + +class kpToolEllipse : public kpToolRectangle +{ +Q_OBJECT + +public: + kpToolEllipse (kpMainWindow *); + virtual ~kpToolEllipse (); +}; + +#endif // __kptoolellipse_h__ diff --git a/kolourpaint/tools/kptoolellipticalselection.cpp b/kolourpaint/tools/kptoolellipticalselection.cpp new file mode 100644 index 00000000..13daf799 --- /dev/null +++ b/kolourpaint/tools/kptoolellipticalselection.cpp @@ -0,0 +1,46 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include + + +kpToolEllipticalSelection::kpToolEllipticalSelection (kpMainWindow *mainWindow) + : kpToolSelection (Ellipse, + i18n ("Selection (Elliptical)"), + i18n ("Makes an elliptical or circular selection"), + Qt::Key_I, + mainWindow, "tool_elliptical_selection") +{ +} + +kpToolEllipticalSelection::~kpToolEllipticalSelection () +{ +} + diff --git a/kolourpaint/tools/kptoolellipticalselection.h b/kolourpaint/tools/kptoolellipticalselection.h new file mode 100644 index 00000000..9dbd643e --- /dev/null +++ b/kolourpaint/tools/kptoolellipticalselection.h @@ -0,0 +1,43 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolellipticalselection_h__ +#define __kptoolellipticalselection_h__ + +#include + +class kpMainWindow; + +class kpToolEllipticalSelection : public kpToolSelection +{ +public: + kpToolEllipticalSelection (kpMainWindow *); + virtual ~kpToolEllipticalSelection (); +}; + +#endif // __kptoolellipticalselection_h__ diff --git a/kolourpaint/tools/kptooleraser.cpp b/kolourpaint/tools/kptooleraser.cpp new file mode 100644 index 00000000..1acbf66e --- /dev/null +++ b/kolourpaint/tools/kptooleraser.cpp @@ -0,0 +1,44 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include + +kpToolEraser::kpToolEraser (kpMainWindow *mainWindow) + : kpToolPen (kpToolPen::Eraser, + i18n ("Eraser"), i18n ("Lets you rub out mistakes"), + Qt::Key_A, + mainWindow, "tool_eraser") +{ +} + +kpToolEraser::~kpToolEraser () +{ +} + +#include diff --git a/kolourpaint/tools/kptooleraser.h b/kolourpaint/tools/kptooleraser.h new file mode 100644 index 00000000..4dd7704a --- /dev/null +++ b/kolourpaint/tools/kptooleraser.h @@ -0,0 +1,43 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptooleraser_h__ +#define __kptooleraser_h__ + +#include + +class kpToolEraser : public kpToolPen +{ +Q_OBJECT + +public: + kpToolEraser (kpMainWindow *mainWindow); + virtual ~kpToolEraser (); +}; + +#endif // __kptooleraser_h__ diff --git a/kolourpaint/tools/kptoolflip.cpp b/kolourpaint/tools/kptoolflip.cpp new file mode 100644 index 00000000..58eeb66d --- /dev/null +++ b/kolourpaint/tools/kptoolflip.cpp @@ -0,0 +1,213 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + + +/* + * kpToolFlipCommand + */ + +kpToolFlipCommand::kpToolFlipCommand (bool actOnSelection, + bool horiz, bool vert, + kpMainWindow *mainWindow) + : kpCommand (mainWindow), + m_actOnSelection (actOnSelection), + m_horiz (horiz), m_vert (vert) +{ +} + +kpToolFlipCommand::~kpToolFlipCommand () +{ +} + + +// public virtual [base kpCommand] +QString kpToolFlipCommand::name () const +{ + QString opName; + + +#if 1 + opName = i18n ("Flip"); +#else // re-enable when giving full descriptions for all actions + if (m_horiz && m_vert) + opName = i18n ("Flip horizontally and vertically"); + else if (m_horiz) + opName = i18n ("Flip horizontally"); + else if (m_vert) + opName = i18n ("Flip vertically"); + else + { + kdError () << "kpToolFlipCommand::name() not asked to flip" << endl; + return QString::null; + } +#endif + + + if (m_actOnSelection) + return i18n ("Selection: %1").arg (opName); + else + return opName; +} + + +// public virtual [base kpCommand] +int kpToolFlipCommand::size () const +{ + return 0; +} + + +// public virtual [base kpCommand] +void kpToolFlipCommand::execute () +{ + flip (); +} + +// public virtual [base kpCommand] +void kpToolFlipCommand::unexecute () +{ + flip (); +} + + +// private +void kpToolFlipCommand::flip () +{ + kpDocument *doc = document (); + if (!doc) + return; + + + QApplication::setOverrideCursor (Qt::waitCursor); + + + if (m_actOnSelection) + { + doc->selection ()->flip (m_horiz, m_vert); + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + } + else + { + QPixmap newPixmap = kpPixmapFX::flip (*doc->pixmap (), m_horiz, m_vert); + + doc->setPixmap (newPixmap); + } + + + QApplication::restoreOverrideCursor (); +} + + +/* + * kpToolFlipDialog + */ + +// private static +bool kpToolFlipDialog::s_lastIsVerticalFlip = true; + + +kpToolFlipDialog::kpToolFlipDialog (bool actOnSelection, QWidget *parent) + : KDialogBase (parent, 0/*name*/, true/*modal*/, + actOnSelection ? i18n ("Flip Selection") : i18n ("Flip Image"), + KDialogBase::Ok | KDialogBase::Cancel) +{ + QVBox *vbox = makeVBoxMainWidget (); + + if (!vbox) + { + kdError () << "kpToolFlipDialog::kpToolFlipDialog() received NULL vbox" << endl; + } + else + { + QVButtonGroup *buttonGroup = new QVButtonGroup (i18n ("Direction"), vbox); + + // I'm sure vert flipping is much more common than horiz flipping so make it come first + m_verticalFlipRadioButton = new QRadioButton (i18n ("&Vertical (upside-down)"), buttonGroup); + m_horizontalFlipRadioButton = new QRadioButton (i18n ("&Horizontal"), buttonGroup); + + m_verticalFlipRadioButton->setChecked (s_lastIsVerticalFlip); + m_horizontalFlipRadioButton->setChecked (!s_lastIsVerticalFlip); + + connect (m_verticalFlipRadioButton, SIGNAL (toggled (bool)), + this, SLOT (slotIsVerticalFlipChanged ())); + connect (m_horizontalFlipRadioButton, SIGNAL (toggled (bool)), + this, SLOT (slotIsVerticalFlipChanged ())); + } +} + +kpToolFlipDialog::~kpToolFlipDialog () +{ +} + + +// public slot +void kpToolFlipDialog::slotIsVerticalFlipChanged () +{ + s_lastIsVerticalFlip = m_verticalFlipRadioButton->isChecked (); +} + + +// public +bool kpToolFlipDialog::getHorizontalFlip () const +{ + return m_horizontalFlipRadioButton->isChecked (); +} + +// public +bool kpToolFlipDialog::getVerticalFlip () const +{ + return m_verticalFlipRadioButton->isChecked (); +} + +// public +bool kpToolFlipDialog::isNoOp () const +{ + return !getHorizontalFlip () && !getVerticalFlip (); +} + + +#include + diff --git a/kolourpaint/tools/kptoolflip.h b/kolourpaint/tools/kptoolflip.h new file mode 100644 index 00000000..c287c320 --- /dev/null +++ b/kolourpaint/tools/kptoolflip.h @@ -0,0 +1,88 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolflip_h__ +#define __kptoolflip_h__ + +#include +#include + +class QRadioButton; +class QString; + +class kpDocument; +class kpMainWindow; + + +class kpToolFlipCommand : public kpCommand +{ +public: + kpToolFlipCommand (bool actOnSelection, + bool horiz, bool vert, + kpMainWindow *mainWindow); + virtual ~kpToolFlipCommand (); + + virtual QString name () const; + + virtual int size () const; + + virtual void execute (); + virtual void unexecute (); + +private: + void flip (); + + bool m_actOnSelection; + bool m_horiz, m_vert; +}; + + +class kpToolFlipDialog : public KDialogBase +{ +Q_OBJECT + +public: + kpToolFlipDialog (bool actOnSelection, QWidget *parent); + ~kpToolFlipDialog (); + +private: + static bool s_lastIsVerticalFlip; + +public slots: + void slotIsVerticalFlipChanged (); + +public: + bool getHorizontalFlip () const; + bool getVerticalFlip () const; + bool isNoOp () const; + +private: + QRadioButton *m_horizontalFlipRadioButton, *m_verticalFlipRadioButton; +}; + +#endif // __kptoolflip_h__ diff --git a/kolourpaint/tools/kptoolfloodfill.cpp b/kolourpaint/tools/kptoolfloodfill.cpp new file mode 100644 index 00000000..bb17d701 --- /dev/null +++ b/kolourpaint/tools/kptoolfloodfill.cpp @@ -0,0 +1,261 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_TOOL_FLOOD_FILL 0 + + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + + +/* + * kpToolFloodFill + */ + +kpToolFloodFill::kpToolFloodFill (kpMainWindow *mainWindow) + : kpTool (i18n ("Flood Fill"), i18n ("Fills regions in the image"), + Qt::Key_F, + mainWindow, "tool_flood_fill"), + m_currentCommand (0) +{ +} + +kpToolFloodFill::~kpToolFloodFill () +{ +} + +QString kpToolFloodFill::haventBegunDrawUserMessage () const +{ + return i18n ("Click to fill a region."); +} + +void kpToolFloodFill::begin () +{ + setUserMessage (haventBegunDrawUserMessage ()); +} + +// virtual +void kpToolFloodFill::beginDraw () +{ +#if DEBUG_KP_TOOL_FLOOD_FILL && 1 + kdDebug () << "kpToolFloodFill::beginDraw()" << endl; +#endif + + QApplication::setOverrideCursor (Qt::waitCursor); + + // Flood Fill is an expensive CPU operation so we only fill at a + // mouse click (beginDraw ()), not on mouse move (virtually draw()) + m_currentCommand = new kpToolFloodFillCommand (m_currentPoint.x (), m_currentPoint.y (), + color (m_mouseButton), processedColorSimilarity (), + mainWindow ()); + + if (m_currentCommand->prepareColorToChange ()) + { + #if DEBUG_KP_TOOL_FLOOD_FILL && 1 + kdDebug () << "\tperforming new-doc-corner-case check" << endl; + #endif + if (document ()->url ().isEmpty () && !document ()->isModified ()) + { + m_currentCommand->setFillEntirePixmap (); + m_currentCommand->execute (); + } + else if (m_currentCommand->prepare ()) + { + m_currentCommand->execute (); + } + else + { + kdError () << "kpToolFloodFill::beginDraw() could not fill!" << endl; + } + } + else + { + kdError () << "kpToolFloodFill::beginDraw() could not prepareColorToChange!" << endl; + } + + QApplication::restoreOverrideCursor (); + + setUserMessage (cancelUserMessage ()); +} + +// virtual +void kpToolFloodFill::draw (const QPoint &thisPoint, const QPoint &, const QRect &) +{ + setUserShapePoints (thisPoint); +} + +// virtual +void kpToolFloodFill::cancelShape () +{ +#if 0 + endDraw (QPoint (), QRect ()); + mainWindow ()->commandHistory ()->undo (); +#else + m_currentCommand->unexecute (); + + delete m_currentCommand; + m_currentCommand = 0; +#endif + + setUserMessage (i18n ("Let go of all the mouse buttons.")); +} + +void kpToolFloodFill::releasedAllButtons () +{ + setUserMessage (haventBegunDrawUserMessage ()); +} + +// virtual +void kpToolFloodFill::endDraw (const QPoint &, const QRect &) +{ + mainWindow ()->commandHistory ()->addCommand (m_currentCommand, + false /* no exec - we already did it up there */); + + // don't delete + m_currentCommand = 0; + setUserMessage (haventBegunDrawUserMessage ()); +} + + +/* + * kpToolFloodFillCommand + */ + +kpToolFloodFillCommand::kpToolFloodFillCommand (int x, int y, + const kpColor &color, int processedColorSimilarity, + kpMainWindow *mainWindow) + : kpCommand (mainWindow), + kpFloodFill (document ()->pixmap (), x, y, color, processedColorSimilarity), + m_fillEntirePixmap (false) +{ +} + +kpToolFloodFillCommand::~kpToolFloodFillCommand () +{ +} + + +// public virtual [base kpCommand] +QString kpToolFloodFillCommand::name () const +{ + return i18n ("Flood Fill"); +} + +// public virtual [base kpCommand] +int kpToolFloodFillCommand::size () const +{ + return kpFloodFill::size () + kpPixmapFX::pixmapSize (m_oldPixmap); +} + + +void kpToolFloodFillCommand::setFillEntirePixmap (bool yes) +{ + m_fillEntirePixmap = yes; +} + + +// virtual +void kpToolFloodFillCommand::execute () +{ +#if DEBUG_KP_TOOL_FLOOD_FILL && 1 + kdDebug () << "kpToolFloodFillCommand::execute() m_fillEntirePixmap=" << m_fillEntirePixmap << endl; +#endif + + kpDocument *doc = document (); + if (!doc) + return; + + + if (m_fillEntirePixmap) + { + doc->fill (kpFloodFill::color ()); + } + else + { + QRect rect = kpFloodFill::boundingRect (); + if (rect.isValid ()) + { + QApplication::setOverrideCursor (QCursor::waitCursor); + + m_oldPixmap = doc->getPixmapAt (rect); + + kpFloodFill::fill (); + doc->slotContentsChanged (rect); + + QApplication::restoreOverrideCursor (); + } + else + { + #if DEBUG_KP_TOOL_FLOOD_FILL && 1 + kdDebug () << "\tinvalid boundingRect - must be NOP case" << endl; + #endif + } + } +} + +// virtual +void kpToolFloodFillCommand::unexecute () +{ + kpDocument *doc = document (); + if (!doc) + return; + + + if (m_fillEntirePixmap) + { + doc->fill (kpFloodFill::colorToChange ()); + } + else + { + QRect rect = kpFloodFill::boundingRect (); + if (rect.isValid ()) + { + doc->setPixmapAt (m_oldPixmap, rect.topLeft ()); + + m_oldPixmap.resize (0, 0); + + doc->slotContentsChanged (rect); + } + } +} + +#include diff --git a/kolourpaint/tools/kptoolfloodfill.h b/kolourpaint/tools/kptoolfloodfill.h new file mode 100644 index 00000000..a2eeaa5a --- /dev/null +++ b/kolourpaint/tools/kptoolfloodfill.h @@ -0,0 +1,94 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolfloodfill_h__ +#define __kptoolfloodfill_h__ + +#include + +#include + +#include +#include + + +class QString; + +class kpColor; + +class kpMainWindow; +class kpToolFloodFillCommand; + + +class kpToolFloodFill : public kpTool +{ +Q_OBJECT + +public: + kpToolFloodFill (kpMainWindow *); + virtual ~kpToolFloodFill (); + +private: + QString haventBegunDrawUserMessage () const; + +public: + virtual void begin (); + virtual void beginDraw (); + virtual void draw (const QPoint &thisPoint, const QPoint &, const QRect &); + virtual void cancelShape (); + virtual void releasedAllButtons (); + virtual void endDraw (const QPoint &, const QRect &); + +private: + kpToolFloodFillCommand *m_currentCommand; +}; + + +class kpToolFloodFillCommand : public kpCommand, public kpFloodFill +{ +public: + kpToolFloodFillCommand (int x, int y, + const kpColor &color, int processedColorSimilarity, + kpMainWindow *mainWindow); + virtual ~kpToolFloodFillCommand (); + + virtual QString name () const; + + virtual int size () const; + + void setFillEntirePixmap (bool yes = true); + + virtual void execute (); + virtual void unexecute (); + +private: + QPixmap m_oldPixmap; + bool m_fillEntirePixmap; +}; + +#endif // __kptoolfloodfill_h__ diff --git a/kolourpaint/tools/kptoolfreeformselection.cpp b/kolourpaint/tools/kptoolfreeformselection.cpp new file mode 100644 index 00000000..7c736728 --- /dev/null +++ b/kolourpaint/tools/kptoolfreeformselection.cpp @@ -0,0 +1,46 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include + + +kpToolFreeFormSelection::kpToolFreeFormSelection (kpMainWindow *mainWindow) + : kpToolSelection (kpToolSelection::FreeForm, + i18n ("Selection (Free-Form)"), + i18n ("Makes a free-form selection"), + Qt::Key_M, + mainWindow, "tool_free_form_selection") +{ +} + +kpToolFreeFormSelection::~kpToolFreeFormSelection () +{ +} + diff --git a/kolourpaint/tools/kptoolfreeformselection.h b/kolourpaint/tools/kptoolfreeformselection.h new file mode 100644 index 00000000..28f1e5ec --- /dev/null +++ b/kolourpaint/tools/kptoolfreeformselection.h @@ -0,0 +1,43 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolfreeformselection_h__ +#define __kptoolfreeformselection_h__ + +#include + +class kpMainWindow; + +class kpToolFreeFormSelection : public kpToolSelection +{ +public: + kpToolFreeFormSelection (kpMainWindow *); + virtual ~kpToolFreeFormSelection (); +}; + +#endif // __kptoolfreeformselection_h__ diff --git a/kolourpaint/tools/kptoolline.cpp b/kolourpaint/tools/kptoolline.cpp new file mode 100644 index 00000000..809824d9 --- /dev/null +++ b/kolourpaint/tools/kptoolline.cpp @@ -0,0 +1,47 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include + + +kpToolLine::kpToolLine (kpMainWindow *mainWindow) + : kpToolPolygon (Line, + i18n ("Line"), + i18n ("Draws lines"), + Qt::Key_L, + mainWindow, "tool_line") +{ +} + +kpToolLine::~kpToolLine () +{ +} + +#include diff --git a/kolourpaint/tools/kptoolline.h b/kolourpaint/tools/kptoolline.h new file mode 100644 index 00000000..7a956245 --- /dev/null +++ b/kolourpaint/tools/kptoolline.h @@ -0,0 +1,45 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolline_h__ +#define __kptoolline_h__ + +#include + +class kpMainWindow; + +class kpToolLine : public kpToolPolygon +{ +Q_OBJECT + +public: + kpToolLine (kpMainWindow *); + virtual ~kpToolLine (); +}; + +#endif // __kptoolline_h__ diff --git a/kolourpaint/tools/kptoolpen.cpp b/kolourpaint/tools/kptoolpen.cpp new file mode 100644 index 00000000..eb731ceb --- /dev/null +++ b/kolourpaint/tools/kptoolpen.cpp @@ -0,0 +1,1145 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_TOOL_PEN 0 + +#include +#include +#include +#include +#include +#if DEBUG_KP_TOOL_PEN + #include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * kpToolPen + */ + +kpToolPen::kpToolPen (Mode mode, + const QString &text, const QString &description, + int key, + kpMainWindow *mainWindow, const char *name) + : kpTool (text, description, key, mainWindow, name), + m_mode (mode), + m_toolWidgetBrush (0), + m_toolWidgetEraserSize (0), + m_currentCommand (0) +{ +} + +kpToolPen::kpToolPen (kpMainWindow *mainWindow) + : kpTool (i18n ("Pen"), i18n ("Draws dots and freehand strokes"), + Qt::Key_P, + mainWindow, "tool_pen"), + m_mode (Pen), + m_toolWidgetBrush (0), + m_toolWidgetEraserSize (0), + m_currentCommand (0) +{ +} + +void kpToolPen::setMode (Mode mode) +{ + int usesPixmaps = (mode & (DrawsPixmaps | WashesPixmaps)); + int usesBrushes = (mode & (SquareBrushes | DiverseBrushes)); + + if ((usesPixmaps && !usesBrushes) || + (usesBrushes && !usesPixmaps)) + { + kdError () << "kpToolPen::setMode() passed invalid mode" << endl; + return; + } + + m_mode = mode; +} + +kpToolPen::~kpToolPen () +{ +} + + +// private +QString kpToolPen::haventBegunDrawUserMessage () const +{ + switch (m_mode) + { + case Pen: + case Brush: + return i18n ("Click to draw dots or drag to draw strokes."); + return i18n ("Click to draw dots or drag to draw strokes."); + case Eraser: + return i18n ("Click or drag to erase."); + case ColorWasher: + return i18n ("Click or drag to erase pixels of the foreground color."); + default: + return QString::null; + } +} + +// virtual +void kpToolPen::begin () +{ + m_toolWidgetBrush = 0; + m_brushIsDiagonalLine = false; + + kpToolToolBar *tb = toolToolBar (); + if (!tb) + return; + + if (m_mode & SquareBrushes) + { + m_toolWidgetEraserSize = tb->toolWidgetEraserSize (); + connect (m_toolWidgetEraserSize, SIGNAL (eraserSizeChanged (int)), + this, SLOT (slotEraserSizeChanged (int))); + m_toolWidgetEraserSize->show (); + + slotEraserSizeChanged (m_toolWidgetEraserSize->eraserSize ()); + + viewManager ()->setCursor (kpCursorProvider::lightCross ()); + } + + if (m_mode & DiverseBrushes) + { + m_toolWidgetBrush = tb->toolWidgetBrush (); + connect (m_toolWidgetBrush, SIGNAL (brushChanged (const QPixmap &, bool)), + this, SLOT (slotBrushChanged (const QPixmap &, bool))); + m_toolWidgetBrush->show (); + + slotBrushChanged (m_toolWidgetBrush->brush (), + m_toolWidgetBrush->brushIsDiagonalLine ()); + + viewManager ()->setCursor (kpCursorProvider::lightCross ()); + } + + setUserMessage (haventBegunDrawUserMessage ()); +} + +// virtual +void kpToolPen::end () +{ + if (m_toolWidgetEraserSize) + { + disconnect (m_toolWidgetEraserSize, SIGNAL (eraserSizeChanged (int)), + this, SLOT (slotEraserSizeChanged (int))); + m_toolWidgetEraserSize = 0; + } + + if (m_toolWidgetBrush) + { + disconnect (m_toolWidgetBrush, SIGNAL (brushChanged (const QPixmap &, bool)), + this, SLOT (slotBrushChanged (const QPixmap &, bool))); + m_toolWidgetBrush = 0; + } + + kpViewManager *vm = viewManager (); + if (vm) + { + if (vm->tempPixmap () && vm->tempPixmap ()->isBrush ()) + vm->invalidateTempPixmap (); + + if (m_mode & (SquareBrushes | DiverseBrushes)) + vm->unsetCursor (); + } + + // save memory + for (int i = 0; i < 2; i++) + m_brushPixmap [i].resize (0, 0); + m_cursorPixmap.resize (0, 0); +} + +// virtual +void kpToolPen::beginDraw () +{ + switch (m_mode) + { + case Pen: + m_currentCommand = new kpToolPenCommand (i18n ("Pen"), mainWindow ()); + break; + case Brush: + m_currentCommand = new kpToolPenCommand (i18n ("Brush"), mainWindow ()); + break; + case Eraser: + m_currentCommand = new kpToolPenCommand (i18n ("Eraser"), mainWindow ()); + break; + case ColorWasher: + m_currentCommand = new kpToolPenCommand (i18n ("Color Eraser"), mainWindow ()); + break; + + default: + m_currentCommand = new kpToolPenCommand (i18n ("Custom Pen or Brush"), mainWindow ()); + break; + } + + // we normally show the Brush pix in the foreground colour but if the + // user starts drawing in the background color, we don't want to leave + // the cursor in the foreground colour -- just hide it in all cases + // to avoid confusion + viewManager ()->invalidateTempPixmap (); + + setUserMessage (cancelUserMessage ()); +} + +// virtual +void kpToolPen::hover (const QPoint &point) +{ +#if DEBUG_KP_TOOL_PEN && 0 + kdDebug () << "kpToolPen::hover(" << point << ")" + << " hasBegun=" << hasBegun () + << " hasBegunDraw=" << hasBegunDraw () + << " cursorPixmap.isNull=" << m_cursorPixmap.isNull () + << endl; +#endif + if (point != KP_INVALID_POINT && !m_cursorPixmap.isNull ()) + { + // (for hotPoint() as m_mouseButton is not normally defined in hover()) + m_mouseButton = 0; + + kpTempPixmap::RenderMode renderMode; + QPixmap cursorPixmapForTempPixmap = m_cursorPixmap; + + if (m_mode & SquareBrushes) + renderMode = kpTempPixmap::SetPixmap; + else if (m_mode & DiverseBrushes) + { + if (color (0).isOpaque ()) + renderMode = kpTempPixmap::PaintPixmap; + else + { + renderMode = kpTempPixmap::PaintMaskTransparentWithBrush; + cursorPixmapForTempPixmap = kpPixmapFX::getNonNullMask (m_cursorPixmap); + } + } + + viewManager ()->setFastUpdates (); + + viewManager ()->setTempPixmap ( + kpTempPixmap (true/*brush*/, + renderMode, + hotPoint (), + cursorPixmapForTempPixmap)); + + viewManager ()->restoreFastUpdates (); + } + +#if DEBUG_KP_TOOL_PEN && 0 + if (document ()->rect ().contains (point)) + { + QImage image = kpPixmapFX::convertToImage (*document ()->pixmap ()); + + QRgb v = image.pixel (point.x (), point.y ()); + kdDebug () << "(" << point << "): r=" << qRed (v) + << " g=" << qGreen (v) + << " b=" << qBlue (v) + << " a=" << qAlpha (v) + << endl; + } +#endif + + setUserShapePoints (point); +} + +bool kpToolPen::wash (QPainter *painter, QPainter *maskPainter, + const QImage &image, + const kpColor &colorToReplace, + const QRect &imageRect, int plotx, int ploty) +{ + return wash (painter, maskPainter, image, colorToReplace, imageRect, hotRect (plotx, ploty)); +} + +bool kpToolPen::wash (QPainter *painter, QPainter *maskPainter, + const QImage &image, + const kpColor &colorToReplace, + const QRect &imageRect, const QRect &drawRect) +{ + bool didSomething = false; + +#if DEBUG_KP_TOOL_PEN && 0 + kdDebug () << "kpToolPen::wash(imageRect=" << imageRect + << ",drawRect=" << drawRect + << ")" << endl; +#endif + +// make use of scanline coherence +#define FLUSH_LINE() \ +{ \ + if (painter && painter->isActive ()) \ + painter->drawLine (startDrawX, y, x - 1, y); \ + if (maskPainter && maskPainter->isActive ()) \ + maskPainter->drawLine (startDrawX, y, x - 1, y); \ + didSomething = true; \ + startDrawX = -1; \ +} + + const int maxY = drawRect.bottom () - imageRect.top (); + + const int minX = drawRect.left () - imageRect.left (); + const int maxX = drawRect.right () - imageRect.left (); + + for (int y = drawRect.top () - imageRect.top (); + y <= maxY; + y++) + { + int startDrawX = -1; + + int x; // for FLUSH_LINE() + for (x = minX; x <= maxX; x++) + { + #if DEBUG_KP_TOOL_PEN && 0 + fprintf (stderr, "y=%i x=%i colorAtPixel=%08X colorToReplace=%08X ... ", + y, x, + kpPixmapFX::getColorAtPixel (image, QPoint (x, y)).toQRgb (), + colorToReplace.toQRgb ()); + #endif + if (kpPixmapFX::getColorAtPixel (image, QPoint (x, y)).isSimilarTo (colorToReplace, processedColorSimilarity ())) + { + #if DEBUG_KP_TOOL_PEN && 0 + fprintf (stderr, "similar\n"); + #endif + if (startDrawX < 0) + startDrawX = x; + } + else + { + #if DEBUG_KP_TOOL_PEN && 0 + fprintf (stderr, "different\n"); + #endif + if (startDrawX >= 0) + FLUSH_LINE (); + } + } + + if (startDrawX >= 0) + FLUSH_LINE (); + } + +#undef FLUSH_LINE + + return didSomething; +} + +// virtual +void kpToolPen::globalDraw () +{ + // it's easiest to reimplement globalDraw() here rather than in + // all the relevant subclasses + + if (m_mode == Eraser) + { + #if DEBUG_KP_TOOL_PEN + kdDebug () << "kpToolPen::globalDraw() eraser" << endl; + #endif + mainWindow ()->commandHistory ()->addCommand ( + new kpToolClearCommand (false/*act on doc, not sel*/, mainWindow ())); + } + else if (m_mode == ColorWasher) + { + #if DEBUG_KP_TOOL_PEN + kdDebug () << "kpToolPen::globalDraw() colour eraser" << endl; + #endif + if (foregroundColor () == backgroundColor () && processedColorSimilarity () == 0) + return; + + QApplication::setOverrideCursor (Qt::waitCursor); + + kpToolPenCommand *cmd = new kpToolPenCommand ( + i18n ("Color Eraser"), mainWindow ()); + + QPainter painter, maskPainter; + QBitmap maskBitmap; + + if (backgroundColor ().isOpaque ()) + { + painter.begin (document ()->pixmap ()); + painter.setPen (backgroundColor ().toQColor ()); + } + + if (backgroundColor ().isTransparent () || + document ()->pixmap ()->mask ()) + { + maskBitmap = kpPixmapFX::getNonNullMask (*document ()->pixmap ()); + maskPainter.begin (&maskBitmap); + + maskPainter.setPen (backgroundColor ().maskColor ()); + } + + const QImage image = kpPixmapFX::convertToImage (*document ()->pixmap ()); + QRect rect = document ()->rect (); + + const bool didSomething = wash (&painter, &maskPainter, image, + foregroundColor ()/*replace foreground*/, + rect, rect); + + // flush + if (painter.isActive ()) + painter.end (); + + if (maskPainter.isActive ()) + maskPainter.end (); + + if (didSomething) + { + if (!maskBitmap.isNull ()) + document ()->pixmap ()->setMask (maskBitmap); + + + document ()->slotContentsChanged (rect); + + + cmd->updateBoundingRect (rect); + cmd->finalize (); + + mainWindow ()->commandHistory ()->addCommand (cmd, false /* don't exec */); + + // don't delete - it's up to the commandHistory + cmd = 0; + } + else + { + #if DEBUG_KP_TOOL_PEN + kdDebug () << "\tisNOP" << endl; + #endif + delete cmd; + cmd = 0; + } + + QApplication::restoreOverrideCursor (); + } +} + +// virtual +// TODO: refactor! +void kpToolPen::draw (const QPoint &thisPoint, const QPoint &lastPoint, const QRect &) +{ + if ((m_mode & WashesPixmaps) && (foregroundColor () == backgroundColor ()) && processedColorSimilarity () == 0) + return; + + // sync: remember to restoreFastUpdates() in all exit paths + viewManager ()->setFastUpdates (); + + if (m_brushIsDiagonalLine ? currentPointCardinallyNextToLast () : currentPointNextToLast ()) + { + if (m_mode & DrawsPixels) + { + QPixmap pixmap (1, 1); + + const kpColor c = color (m_mouseButton); + + // OPT: this seems hopelessly inefficient + if (c.isOpaque ()) + { + pixmap.fill (c.toQColor ()); + } + else + { + QBitmap mask (1, 1); + mask.fill (Qt::color0/*transparent*/); + + pixmap.setMask (mask); + } + + // draw onto doc + document ()->setPixmapAt (pixmap, thisPoint); + + m_currentCommand->updateBoundingRect (thisPoint); + } + // Brush & Eraser + else if (m_mode & DrawsPixmaps) + { + if (color (m_mouseButton).isOpaque ()) + document ()->paintPixmapAt (m_brushPixmap [m_mouseButton], hotPoint ()); + else + { + kpPixmapFX::paintMaskTransparentWithBrush (document ()->pixmap (), + hotPoint (), + kpPixmapFX::getNonNullMask (m_brushPixmap [m_mouseButton])); + document ()->slotContentsChanged (hotRect ()); + } + + m_currentCommand->updateBoundingRect (hotRect ()); + } + else if (m_mode & WashesPixmaps) + { + #if DEBUG_KP_TOOL_PEN + kdDebug () << "Washing pixmap (immediate)" << endl; + QTime timer; + #endif + QRect rect = hotRect (); + #if DEBUG_KP_TOOL_PEN + timer.start (); + #endif + QPixmap pixmap = document ()->getPixmapAt (rect); + #if DEBUG_KP_TOOL_PEN + kdDebug () << "\tget from doc: " << timer.restart () << "ms" << endl; + #endif + const QImage image = kpPixmapFX::convertToImage (pixmap); + #if DEBUG_KP_TOOL_PEN + kdDebug () << "\tconvert to image: " << timer.restart () << "ms" << endl; + #endif + QPainter painter, maskPainter; + QBitmap maskBitmap; + + if (color (m_mouseButton).isOpaque ()) + { + painter.begin (&pixmap); + painter.setPen (color (m_mouseButton).toQColor ()); + } + + if (color (m_mouseButton).isTransparent () || + pixmap.mask ()) + { + maskBitmap = kpPixmapFX::getNonNullMask (pixmap); + maskPainter.begin (&maskBitmap); + maskPainter.setPen (color (m_mouseButton).maskColor ()); + } + + bool didSomething = wash (&painter, &maskPainter, + image, + color (1 - m_mouseButton)/*color to replace*/, + rect, rect); + + if (painter.isActive ()) + painter.end (); + + if (maskPainter.isActive ()) + maskPainter.end (); + + if (didSomething) + { + if (!maskBitmap.isNull ()) + pixmap.setMask (maskBitmap); + + #if DEBUG_KP_TOOL_PEN + kdDebug () << "\twashed: " << timer.restart () << "ms" << endl; + #endif + document ()->setPixmapAt (pixmap, hotPoint ()); + #if DEBUG_KP_TOOL_PEN + kdDebug () << "\tset doc: " << timer.restart () << "ms" << endl; + #endif + m_currentCommand->updateBoundingRect (hotRect ()); + #if DEBUG_KP_TOOL_PEN + kdDebug () << "\tupdate boundingRect: " << timer.restart () << "ms" << endl; + kdDebug () << "\tdone" << endl; + #endif + } + + #if DEBUG_KP_TOOL_PEN && 1 + kdDebug () << endl; + #endif + } + } + // in reality, the system is too slow to give us all the MouseMove events + // so we "interpolate" the missing points :) + else + { + // find bounding rectangle + QRect rect = QRect (thisPoint, lastPoint).normalize (); + if (m_mode != DrawsPixels) + rect = neededRect (rect, m_brushPixmap [m_mouseButton].width ()); + + #if DEBUG_KP_TOOL_PEN + if (m_mode & WashesPixmaps) + { + kdDebug () << "Washing pixmap (w=" << rect.width () + << ",h=" << rect.height () << ")" << endl; + } + QTime timer; + int convAndWashTime; + #endif + + const kpColor c = color (m_mouseButton); + bool transparent = c.isTransparent (); + + QPixmap pixmap = document ()->getPixmapAt (rect); + QBitmap maskBitmap; + + QPainter painter, maskPainter; + + if (m_mode & (DrawsPixels | WashesPixmaps)) + { + if (!transparent) + { + painter.begin (&pixmap); + painter.setPen (c.toQColor ()); + } + + if (transparent || pixmap.mask ()) + { + maskBitmap = kpPixmapFX::getNonNullMask (pixmap); + maskPainter.begin (&maskBitmap); + maskPainter.setPen (c.maskColor ()); + } + } + + QImage image; + if (m_mode & WashesPixmaps) + { + #if DEBUG_KP_TOOL_PEN + timer.start (); + #endif + image = kpPixmapFX::convertToImage (pixmap); + #if DEBUG_KP_TOOL_PEN + convAndWashTime = timer.restart (); + kdDebug () << "\tconvert to image: " << convAndWashTime << " ms" << endl; + #endif + } + + bool didSomething = false; + + if (m_mode & DrawsPixels) + { + QPoint sp = lastPoint - rect.topLeft (), ep = thisPoint - rect.topLeft (); + if (painter.isActive ()) + painter.drawLine (sp, ep); + + if (maskPainter.isActive ()) + maskPainter.drawLine (sp, ep); + + didSomething = true; + } + // Brush & Eraser + else if (m_mode & (DrawsPixmaps | WashesPixmaps)) + { + kpColor colorToReplace; + + if (m_mode & WashesPixmaps) + colorToReplace = color (1 - m_mouseButton); + + // Sweeps a pixmap along a line (modified Bresenham's line algorithm, + // see MODIFIED comment below). + // + // Derived from the zSprite2 Graphics Engine + + const int x1 = (thisPoint - rect.topLeft ()).x (), + y1 = (thisPoint - rect.topLeft ()).y (), + x2 = (lastPoint - rect.topLeft ()).x (), + y2 = (lastPoint - rect.topLeft ()).y (); + + // Difference of x and y values + int dx = x2 - x1; + int dy = y2 - y1; + + // Absolute values of differences + int ix = kAbs (dx); + int iy = kAbs (dy); + + // Larger of the x and y differences + int inc = ix > iy ? ix : iy; + + // Plot location + int plotx = x1; + int ploty = y1; + + int x = 0; + int y = 0; + + if (m_mode & WashesPixmaps) + { + if (wash (&painter, &maskPainter, image, + colorToReplace, + rect, plotx + rect.left (), ploty + rect.top ())) + { + didSomething = true; + } + } + else + { + if (!transparent) + { + kpPixmapFX::paintPixmapAt (&pixmap, + hotPoint (plotx, ploty), + m_brushPixmap [m_mouseButton]); + } + else + { + kpPixmapFX::paintMaskTransparentWithBrush (&pixmap, + hotPoint (plotx, ploty), + kpPixmapFX::getNonNullMask (m_brushPixmap [m_mouseButton])); + } + + didSomething = true; + } + + for (int i = 0; i <= inc; i++) + { + // oldplotx is equally as valid but would look different + // (but nobody will notice which one it is) + int oldploty = ploty; + int plot = 0; + + x += ix; + y += iy; + + if (x > inc) + { + plot++; + x -= inc; + + if (dx < 0) + plotx--; + else + plotx++; + } + + if (y > inc) + { + plot++; + y -= inc; + + if (dy < 0) + ploty--; + else + ploty++; + } + + if (plot) + { + if (m_brushIsDiagonalLine && plot == 2) + { + // MODIFIED: every point is + // horizontally or vertically adjacent to another point (if there + // is more than 1 point, of course). This is in contrast to the + // ordinary line algorithm which can create diagonal adjacencies. + + if (m_mode & WashesPixmaps) + { + if (wash (&painter, &maskPainter, image, + colorToReplace, + rect, plotx + rect.left (), oldploty + rect.top ())) + { + didSomething = true; + } + } + else + { + if (!transparent) + { + kpPixmapFX::paintPixmapAt (&pixmap, + hotPoint (plotx, oldploty), + m_brushPixmap [m_mouseButton]); + } + else + { + kpPixmapFX::paintMaskTransparentWithBrush (&pixmap, + hotPoint (plotx, oldploty), + kpPixmapFX::getNonNullMask (m_brushPixmap [m_mouseButton])); + } + + didSomething = true; + } + } + + if (m_mode & WashesPixmaps) + { + if (wash (&painter, &maskPainter, image, + colorToReplace, + rect, plotx + rect.left (), ploty + rect.top ())) + { + didSomething = true; + } + } + else + { + if (!transparent) + { + kpPixmapFX::paintPixmapAt (&pixmap, + hotPoint (plotx, ploty), + m_brushPixmap [m_mouseButton]); + } + else + { + kpPixmapFX::paintMaskTransparentWithBrush (&pixmap, + hotPoint (plotx, ploty), + kpPixmapFX::getNonNullMask (m_brushPixmap [m_mouseButton])); + } + + didSomething = true; + } + } + } + + } + + if (painter.isActive ()) + painter.end (); + + if (maskPainter.isActive ()) + maskPainter.end (); + + #if DEBUG_KP_TOOL_PEN + if (m_mode & WashesPixmaps) + { + int ms = timer.restart (); + kdDebug () << "\ttried to wash: " << ms << "ms" + << " (" << (ms ? (rect.width () * rect.height () / ms) : -1234) + << " pixels/ms)" + << endl; + convAndWashTime += ms; + } + #endif + + + if (didSomething) + { + if (!maskBitmap.isNull ()) + pixmap.setMask (maskBitmap); + + // draw onto doc + document ()->setPixmapAt (pixmap, rect.topLeft ()); + + #if DEBUG_KP_TOOL_PEN + if (m_mode & WashesPixmaps) + { + int ms = timer.restart (); + kdDebug () << "\tset doc: " << ms << "ms" << endl; + convAndWashTime += ms; + } + #endif + + m_currentCommand->updateBoundingRect (rect); + + #if DEBUG_KP_TOOL_PEN + if (m_mode & WashesPixmaps) + { + int ms = timer.restart (); + kdDebug () << "\tupdate boundingRect: " << ms << "ms" << endl; + convAndWashTime += ms; + kdDebug () << "\tdone (" << (convAndWashTime ? (rect.width () * rect.height () / convAndWashTime) : -1234) + << " pixels/ms)" + << endl; + } + #endif + } + + #if DEBUG_KP_TOOL_PEN + if (m_mode & WashesPixmaps) + kdDebug () << endl; + #endif + } + + viewManager ()->restoreFastUpdates (); + setUserShapePoints (thisPoint); +} + +// virtual +void kpToolPen::cancelShape () +{ + m_currentCommand->finalize (); + m_currentCommand->cancel (); + + delete m_currentCommand; + m_currentCommand = 0; + + updateBrushCursor (false/*no recalc*/); + + setUserMessage (i18n ("Let go of all the mouse buttons.")); +} + +void kpToolPen::releasedAllButtons () +{ + setUserMessage (haventBegunDrawUserMessage ()); +} + +// virtual +void kpToolPen::endDraw (const QPoint &, const QRect &) +{ + m_currentCommand->finalize (); + mainWindow ()->commandHistory ()->addCommand (m_currentCommand, false /* don't exec */); + + // don't delete - it's up to the commandHistory + m_currentCommand = 0; + + updateBrushCursor (false/*no recalc*/); + + setUserMessage (haventBegunDrawUserMessage ()); +} + + +// TODO: maybe the base should be virtual? +kpColor kpToolPen::color (int which) +{ +#if DEBUG_KP_TOOL_PEN && 0 + kdDebug () << "kpToolPen::color (" << which << ")" << endl; +#endif + + // Pen & Brush + if ((m_mode & SwappedColors) == 0) + return kpTool::color (which); + // only the (Color) Eraser uses the opposite color + else + return kpTool::color (which ? 0 : 1); // don't trust !0 == 1 +} + +// virtual private slot +void kpToolPen::slotForegroundColorChanged (const kpColor &col) +{ +#if DEBUG_KP_TOOL_PEN + kdDebug () << "kpToolPen::slotForegroundColorChanged()" << endl; +#endif + if (col.isOpaque ()) + m_brushPixmap [(m_mode & SwappedColors) ? 1 : 0].fill (col.toQColor ()); + + updateBrushCursor (); +} + +// virtual private slot +void kpToolPen::slotBackgroundColorChanged (const kpColor &col) +{ +#if DEBUG_KP_TOOL_PEN + kdDebug () << "kpToolPen::slotBackgroundColorChanged()" << endl; +#endif + + if (col.isOpaque ()) + m_brushPixmap [(m_mode & SwappedColors) ? 0 : 1].fill (col.toQColor ()); + + updateBrushCursor (); +} + +// private slot +void kpToolPen::slotBrushChanged (const QPixmap &pixmap, bool isDiagonalLine) +{ +#if DEBUG_KP_TOOL_PEN + kdDebug () << "kpToolPen::slotBrushChanged()" << endl; +#endif + for (int i = 0; i < 2; i++) + { + m_brushPixmap [i] = pixmap; + if (color (i).isOpaque ()) + m_brushPixmap [i].fill (color (i).toQColor ()); + } + + m_brushIsDiagonalLine = isDiagonalLine; + + updateBrushCursor (); +} + +// private slot +void kpToolPen::slotEraserSizeChanged (int size) +{ +#if DEBUG_KP_TOOL_PEN + kdDebug () << "KpToolPen::slotEraserSizeChanged(size=" << size << ")" << endl; +#endif + + for (int i = 0; i < 2; i++) + { + // Note: No matter what, the eraser's brush pixmap is never given + // a mask. + // + // With a transparent color, since we don't fill anything, the + // resize by itself will leave us with garbage pixels. This + // doesn't matter because: + // + // 1. The hover cursor will ask kpToolWidgetEraserSize for a proper + // cursor pixmap. + // 2. We will draw using kpPixmapFX::paintMaskTransparentWithBrush() + // which only cares about the opaqueness. + m_brushPixmap [i].resize (size, size); + if (color (i).isOpaque ()) + m_brushPixmap [i].fill (color (i).toQColor ()); + } + + updateBrushCursor (); +} + +QPoint kpToolPen::hotPoint () const +{ + return hotPoint (m_currentPoint); +} + +QPoint kpToolPen::hotPoint (int x, int y) const +{ + return hotPoint (QPoint (x, y)); +} + +QPoint kpToolPen::hotPoint (const QPoint &point) const +{ + /* + * e.g. + * Width 5: + * 0 1 2 3 4 + * ^ + * | + * Center + */ + return point - + QPoint (m_brushPixmap [m_mouseButton].width () / 2, + m_brushPixmap [m_mouseButton].height () / 2); +} + +QRect kpToolPen::hotRect () const +{ + return hotRect (m_currentPoint); +} + +QRect kpToolPen::hotRect (int x, int y) const +{ + return hotRect (QPoint (x, y)); +} + +QRect kpToolPen::hotRect (const QPoint &point) const +{ + QPoint topLeft = hotPoint (point); + return QRect (topLeft.x (), + topLeft.y (), + m_brushPixmap [m_mouseButton].width (), + m_brushPixmap [m_mouseButton].height ()); +} + +// private +void kpToolPen::updateBrushCursor (bool recalc) +{ +#if DEBUG_KP_TOOL_PEN && 1 + kdDebug () << "kpToolPen::updateBrushCursor(recalc=" << recalc << ")" << endl; +#endif + + if (recalc) + { + if (m_mode & SquareBrushes) + m_cursorPixmap = m_toolWidgetEraserSize->cursorPixmap (color (0)); + else if (m_mode & DiverseBrushes) + m_cursorPixmap = m_brushPixmap [0]; + } + + hover (hasBegun () ? m_currentPoint : currentPoint ()); +} + + +/* + * kpToolPenCommand + */ + +kpToolPenCommand::kpToolPenCommand (const QString &name, kpMainWindow *mainWindow) + : kpNamedCommand (name, mainWindow), + m_pixmap (*document ()->pixmap ()) +{ +} + +kpToolPenCommand::~kpToolPenCommand () +{ +} + + +// public virtual [base kpCommand] +int kpToolPenCommand::size () const +{ + return kpPixmapFX::pixmapSize (m_pixmap); +} + + +// public virtual [base kpCommand] +void kpToolPenCommand::execute () +{ + swapOldAndNew (); +} + +// public virtual [base kpCommand] +void kpToolPenCommand::unexecute () +{ + swapOldAndNew (); +} + + +// private +void kpToolPenCommand::swapOldAndNew () +{ + if (m_boundingRect.isValid ()) + { + QPixmap oldPixmap = document ()->getPixmapAt (m_boundingRect); + + document ()->setPixmapAt (m_pixmap, m_boundingRect.topLeft ()); + + m_pixmap = oldPixmap; + } +} + +// public +void kpToolPenCommand::updateBoundingRect (const QPoint &point) +{ + updateBoundingRect (QRect (point, point)); +} + +// public +void kpToolPenCommand::updateBoundingRect (const QRect &rect) +{ +#if DEBUG_KP_TOOL_PEN & 0 + kdDebug () << "kpToolPenCommand::updateBoundingRect() existing=" + << m_boundingRect + << " plus=" + << rect + << endl; +#endif + m_boundingRect = m_boundingRect.unite (rect); +#if DEBUG_KP_TOOL_PEN & 0 + kdDebug () << "\tresult=" << m_boundingRect << endl; +#endif +} + +// public +void kpToolPenCommand::finalize () +{ + if (m_boundingRect.isValid ()) + { + // store only needed part of doc pixmap + m_pixmap = kpTool::neededPixmap (m_pixmap, m_boundingRect); + } + else + { + m_pixmap.resize (0, 0); + } +} + +// public +void kpToolPenCommand::cancel () +{ + if (m_boundingRect.isValid ()) + { + viewManager ()->setFastUpdates (); + document ()->setPixmapAt (m_pixmap, m_boundingRect.topLeft ()); + viewManager ()->restoreFastUpdates (); + } +} + +#include diff --git a/kolourpaint/tools/kptoolpen.h b/kolourpaint/tools/kptoolpen.h new file mode 100644 index 00000000..f57eb367 --- /dev/null +++ b/kolourpaint/tools/kptoolpen.h @@ -0,0 +1,160 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolpen_h__ +#define __kptoolpen_h__ + +#include +#include + +#include +#include + +class QPoint; +class QString; + +class kpColor; +class kpMainWindow; +class kpToolPenCommand; +class kpToolWidgetBrush; +class kpToolWidgetEraserSize; +class kpViewManager; + +class kpToolPen : public kpTool +{ +Q_OBJECT + +public: + enum Mode + { + // tool properties + DrawsPixels = (1 << 0), DrawsPixmaps = (1 << 1), WashesPixmaps = (1 << 2), + NoBrushes = 0, SquareBrushes = (1 << 3), DiverseBrushes = (1 << 4), + NormalColors = 0, SwappedColors = (1 << 5), + + // tools: + // + // Pen = draws pixels, "interpolates" by "sweeping" pixels along a line (no brushes) + // Brush = draws pixmaps, "interpolates" by "sweeping" pixmaps along a line (interesting brushes) + // Eraser = Brush but with foreground & background colors swapped (a few square brushes) + // Color Washer = Brush that replaces/washes the foreground color with the background color + // + // (note the capitalization of "brush" here :)) + Pen = DrawsPixels | NoBrushes | NormalColors, + Brush = DrawsPixmaps | DiverseBrushes | NormalColors, + Eraser = DrawsPixmaps | SquareBrushes | SwappedColors, + ColorWasher = WashesPixmaps | SquareBrushes | SwappedColors + }; + + kpToolPen (Mode mode, const QString &text, const QString &description, + int key, + kpMainWindow *mainWindow, const char *name); + kpToolPen (kpMainWindow *mainWindow); + virtual ~kpToolPen (); + + void setMode (Mode mode); + +private: + QString haventBegunDrawUserMessage () const; + +public: + virtual void begin (); + virtual void end (); + + virtual void beginDraw (); + virtual void hover (const QPoint &point); + virtual void globalDraw (); + virtual void draw (const QPoint &thisPoint, const QPoint &lastPoint, const QRect &); + virtual void cancelShape (); + virtual void releasedAllButtons (); + virtual void endDraw (const QPoint &, const QRect &); + +private slots: + virtual void slotForegroundColorChanged (const kpColor &col); + virtual void slotBackgroundColorChanged (const kpColor &col); + + void slotBrushChanged (const QPixmap &pixmap, bool isDiagonalLine); + void slotEraserSizeChanged (int size); + +private: + bool wash (QPainter *painter, QPainter *maskPainter, + const QImage &image, + const kpColor &colorToReplace, + const QRect &imageRect, int plotx, int ploty); + bool wash (QPainter *painter, QPainter *maskPainter, + const QImage &image, + const kpColor &colorToReplace, + const QRect &imageRect, const QRect &drawRect); + + kpColor color (int which); + + QPoint hotPoint () const; + QPoint hotPoint (int x, int y) const; + QPoint hotPoint (const QPoint &point) const; + QRect hotRect () const; + QRect hotRect (int x, int y) const; + QRect hotRect (const QPoint &point) const; + + Mode m_mode; + + void updateBrushCursor (bool recalc = true); + + kpToolWidgetBrush *m_toolWidgetBrush; + kpToolWidgetEraserSize *m_toolWidgetEraserSize; + QPixmap m_brushPixmap [2]; + QPixmap m_cursorPixmap; + bool m_brushIsDiagonalLine; + + kpToolPenCommand *m_currentCommand; +}; + +class kpToolPenCommand : public kpNamedCommand +{ +public: + kpToolPenCommand (const QString &name, kpMainWindow *mainWindow); + virtual ~kpToolPenCommand (); + + virtual int size () const; + + virtual void execute (); + virtual void unexecute (); + + // interface for KToolPen + void updateBoundingRect (const QPoint &point); + void updateBoundingRect (const QRect &rect); + void finalize (); + void cancel (); + +private: + void swapOldAndNew (); + + QPixmap m_pixmap; + QRect m_boundingRect; +}; + +#endif // __kptoolpen_h__ diff --git a/kolourpaint/tools/kptoolpolygon.cpp b/kolourpaint/tools/kptoolpolygon.cpp new file mode 100644 index 00000000..fb68745c --- /dev/null +++ b/kolourpaint/tools/kptoolpolygon.cpp @@ -0,0 +1,895 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_TOOL_POLYGON 0 + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#if DEBUG_KP_TOOL_POLYGON +static const char *pointArrayToString (const QPointArray &pointArray) +{ + static char string [1000]; + string [0] = '\0'; + + for (QPointArray::ConstIterator it = pointArray.begin (); + it != pointArray.end (); + it++) + { + QString ps = QString (" (%1, %2)").arg ((*it).x ()).arg ((*it).y ()); + const char *pss = ps.latin1 (); + if (strlen (string) + strlen (pss) + 1 > sizeof (string) / sizeof (string [0])) + break; + strcat (string, pss); + } + + return string; +} +#endif + + +static QPen makeMaskPen (const kpColor &color, int lineWidth, Qt::PenStyle lineStyle) +{ + return QPen (color.maskColor (), + lineWidth == 1 ? 0/*closer to looking width 1*/ : lineWidth, lineStyle, + Qt::RoundCap, Qt::RoundJoin); +} + +static QPen makePen (const kpColor &color, int lineWidth, Qt::PenStyle lineStyle) +{ + if (color.isOpaque ()) + { + return QPen (color.toQColor (), + lineWidth == 1 ? 0/*closer to looking width 1*/ : lineWidth, lineStyle, + Qt::RoundCap, Qt::RoundJoin); + } + else + return Qt::NoPen; +} + +static QBrush makeMaskBrush (const kpColor &foregroundColor, + const kpColor &backgroundColor, + kpToolWidgetFillStyle *toolWidgetFillStyle) +{ + if (toolWidgetFillStyle) + return toolWidgetFillStyle->maskBrush (foregroundColor, backgroundColor); + else + return Qt::NoBrush; +} + +static QBrush makeBrush (const kpColor &foregroundColor, + const kpColor &backgroundColor, + kpToolWidgetFillStyle *toolWidgetFillStyle) +{ + if (toolWidgetFillStyle) + return toolWidgetFillStyle->brush (foregroundColor, backgroundColor); + else + return Qt::NoBrush; +} + +static bool only1PixelInPointArray (const QPointArray &points) +{ + if (points.count () == 0) + return false; + + for (int i = 1; i < (int) points.count (); i++) + { + if (points [i] != points [0]) + return false; + } + + return true; +} + +static QPixmap pixmap (const QPixmap &oldPixmap, + const QPointArray &points, const QRect &rect, + const kpColor &foregroundColor, kpColor backgroundColor, + int lineWidth, Qt::PenStyle lineStyle, + kpToolWidgetFillStyle *toolWidgetFillStyle, + enum kpToolPolygon::Mode mode, bool final = true) +{ + // + // figure out points to draw relative to topLeft of oldPixmap + + QPointArray pointsInRect = points; + pointsInRect.detach (); + pointsInRect.translate (-rect.x (), -rect.y ()); + +#if DEBUG_KP_TOOL_POLYGON && 0 + kdDebug () << "kptoolpolygon.cpp: pixmap(): points=" << pointArrayToString (points) << endl; +#endif + + + // + // draw + + QPen pen = makePen (foregroundColor, lineWidth, lineStyle), + maskPen = makeMaskPen (foregroundColor, lineWidth, lineStyle); + QBrush brush = makeBrush (foregroundColor, backgroundColor, toolWidgetFillStyle), + maskBrush = makeMaskBrush (foregroundColor, backgroundColor, toolWidgetFillStyle); + + QPixmap pixmap = oldPixmap; + QBitmap maskBitmap; + + QPainter painter, maskPainter; + + if (pixmap.mask () || + (maskPen.style () != Qt::NoPen && + maskPen.color () == Qt::color0/*transparent*/) || + (maskBrush.style () != Qt::NoBrush && + maskBrush.color () == Qt::color0/*transparent*/)) + { + maskBitmap = kpPixmapFX::getNonNullMask (pixmap); + maskPainter.begin (&maskBitmap); + maskPainter.setPen (maskPen); + maskPainter.setBrush (maskBrush); + + #if DEBUG_KP_TOOL_POLYGON && 0 + kdDebug () << "\tmaskPainter begin because:" << endl + << "\t\tpixmap.mask=" << pixmap.mask () << endl + << "\t\t(maskPenStyle!=NoPen)=" << (maskPen.style () != Qt::NoPen) << endl + << "\t\t(maskPenColor==trans)=" << (maskPen.color () == Qt::color0) << endl + << "\t\t(maskBrushStyle!=NoBrush)=" << (maskBrush.style () != Qt::NoBrush) << endl + << "\t\t(maskBrushColor==trans)=" << (maskBrush.color () == Qt::color0) << endl; + #endif + } + + if (pen.style () != Qt::NoPen || + brush.style () != Qt::NoBrush) + { + painter.begin (&pixmap); + painter.setPen (pen); + painter.setBrush (brush); + + #if DEBUG_KP_TOOL_POLYGON && 0 + kdDebug () << "\tpainter begin pen.rgb=" + << (int *) painter.pen ().color ().rgb () + << endl; + #endif + } + +#define PAINTER_CALL(cmd) \ +{ \ + if (painter.isActive ()) \ + painter . cmd ; \ + \ + if (maskPainter.isActive ()) \ + maskPainter . cmd ; \ +} + + // SYNC: Qt bug + if (only1PixelInPointArray (pointsInRect)) + { + PAINTER_CALL (drawPoint (pointsInRect [0])); + } + else + { + switch (mode) + { + case kpToolPolygon::Line: + case kpToolPolygon::Polyline: + PAINTER_CALL (drawPolyline (pointsInRect)); + break; + case kpToolPolygon::Polygon: + // TODO: why aren't the ends rounded? + PAINTER_CALL (drawPolygon (pointsInRect)); + + if (!final && 0/*HACK for TODO*/) + { + int count = pointsInRect.count (); + + if (count > 2) + { + if (painter.isActive ()) + { + QPen XORpen = painter.pen (); + XORpen.setColor (Qt::white); + + painter.setPen (XORpen); + painter.setRasterOp (Qt::XorROP); + } + + if (maskPainter.isActive ()) + { + QPen XORpen = maskPainter.pen (); + + // TODO??? + #if 0 + if (kpTool::isColorTransparent (foregroundColor)) + XORpen.setColor (Qt::color1/*opaque*/); + else + XORpen.setColor (Qt::color0/*transparent*/); + #endif + + maskPainter.setPen (XORpen); + } + + PAINTER_CALL (drawLine (pointsInRect [0], pointsInRect [count - 1])); + } + } + break; + case kpToolPolygon::Curve: + int numPoints = pointsInRect.count (); + QPointArray pa (4); + + pa [0] = pointsInRect [0]; + pa [3] = pointsInRect [1]; + + switch (numPoints) + { + case 2: + pa [1] = pointsInRect [0]; + pa [2] = pointsInRect [1]; + break; + case 3: + pa [1] = pa [2] = pointsInRect [2]; + break; + case 4: + pa [1] = pointsInRect [2]; + pa [2] = pointsInRect [3]; + } + + PAINTER_CALL (drawCubicBezier (pa)); + } + } +#undef PAINTER_CALL + + if (painter.isActive ()) + painter.end (); + + if (maskPainter.isActive ()) + maskPainter.end (); + + if (!maskBitmap.isNull ()) + pixmap.setMask (maskBitmap); + + return pixmap; +} + + +/* + * kpToolPolygon + */ + +kpToolPolygon::kpToolPolygon (Mode mode, + const QString &text, const QString &description, + int key, + kpMainWindow *mainWindow, const char *name) + : kpTool (text, description, key, mainWindow, name), + m_mode (mode), + m_toolWidgetFillStyle (0), + m_toolWidgetLineWidth (0) +{ +} + +kpToolPolygon::kpToolPolygon (kpMainWindow *mainWindow) + : kpTool (i18n ("Polygon"), i18n ("Draws polygons"), + Qt::Key_G, + mainWindow, "tool_polygon"), + m_mode (Polygon), + m_toolWidgetFillStyle (0), + m_toolWidgetLineWidth (0) +{ +} + +kpToolPolygon::~kpToolPolygon () +{ +} + +void kpToolPolygon::setMode (Mode m) +{ + m_mode = m; +} + + +// private +QString kpToolPolygon::haventBegunShapeUserMessage () const +{ + switch (m_mode) + { + case Line: + return i18n ("Drag to draw."); + case Polygon: + case Polyline: + return i18n ("Drag to draw the first line."); + case Curve: + return i18n ("Drag out the start and end points."); + default: + return QString::null; + } +} + +// virtual +void kpToolPolygon::begin () +{ + kpToolToolBar *tb = toolToolBar (); + +#if DEBUG_KP_TOOL_POLYGON + kdDebug () << "kpToolPolygon::begin() tb=" << tb << endl; +#endif + + if (tb) + { + if (m_mode == Polygon) + m_toolWidgetFillStyle = tb->toolWidgetFillStyle (); + else + m_toolWidgetFillStyle = 0; + + m_toolWidgetLineWidth = tb->toolWidgetLineWidth (); + + if (m_toolWidgetFillStyle) + { + connect (m_toolWidgetFillStyle, SIGNAL (fillStyleChanged (kpToolWidgetFillStyle::FillStyle)), + this, SLOT (slotFillStyleChanged (kpToolWidgetFillStyle::FillStyle))); + } + connect (m_toolWidgetLineWidth, SIGNAL (lineWidthChanged (int)), + this, SLOT (slotLineWidthChanged (int))); + + if (m_toolWidgetFillStyle) + m_toolWidgetFillStyle->show (); + m_toolWidgetLineWidth->show (); + + m_lineWidth = m_toolWidgetLineWidth->lineWidth (); + } + else + { + m_toolWidgetFillStyle = 0; + m_toolWidgetLineWidth = 0; + + m_lineWidth = 1; + } + + viewManager ()->setCursor (QCursor (CrossCursor)); + + m_originatingMouseButton = -1; + + setUserMessage (haventBegunShapeUserMessage ()); +} + +// virtual +void kpToolPolygon::end () +{ + endShape (); + + if (m_toolWidgetFillStyle) + { + disconnect (m_toolWidgetFillStyle, SIGNAL (fillStyleChanged (kpToolWidgetFillStyle::FillStyle)), + this, SLOT (slotFillStyleChanged (kpToolWidgetFillStyle::FillStyle))); + m_toolWidgetFillStyle = 0; + } + + if (m_toolWidgetLineWidth) + { + disconnect (m_toolWidgetLineWidth, SIGNAL (lineWidthChanged (int)), + this, SLOT (slotLineWidthChanged (int))); + m_toolWidgetLineWidth = 0; + } + + viewManager ()->unsetCursor (); +} + + +void kpToolPolygon::beginDraw () +{ +#if DEBUG_KP_TOOL_POLYGON + kdDebug () << "kpToolPolygon::beginDraw() m_points=" << pointArrayToString (m_points) + << ", startPoint=" << m_startPoint << endl; +#endif + + bool endedShape = false; + + // starting with a line... + if (m_points.count () == 0) + { + m_originatingMouseButton = m_mouseButton; + m_points.putPoints (m_points.count (), 2, + m_startPoint.x (), m_startPoint.y (), + m_startPoint.x (), m_startPoint.y ()); + } + // continuing poly* + else + { + if (m_mouseButton != m_originatingMouseButton) + { + m_mouseButton = m_originatingMouseButton; + endShape (); + endedShape = true; + } + else + { + int count = m_points.count (); + m_points.putPoints (count, 1, + m_startPoint.x (), m_startPoint.y ()); + + // start point = last end point; + // _not_ the new/current start point + // (which is disregarded in a poly* as only the end points count + // after the initial line) + // + // Curve Tool ignores m_startPoint (doesn't call applyModifiers()) + // after the initial has been defined. + m_startPoint = m_points [count - 1]; + } + } + +#if DEBUG_KP_TOOL_POLYGON + kdDebug () << "\tafterwards, m_points=" << pointArrayToString (m_points) << endl; +#endif + + if (!endedShape) + { + switch (m_mode) + { + case Line: + case Curve: + case Polygon: + case Polyline: + setUserMessage (cancelUserMessage ()); + break; + + default: + kdError () << "kpToolPolygon::beginDraw() shape" << endl; + break; + } + } +} + +// private +void kpToolPolygon::applyModifiers () +{ + int count = m_points.count (); + + m_toolLineStartPoint = m_startPoint; /* also correct for poly* tool (see beginDraw()) */ + m_toolLineEndPoint = m_currentPoint; + +#if DEBUG_KP_TOOL_POLYGON && 1 + kdDebug () << "kpToolPolygon::applyModifiers() #pts=" << count + << " line: startPt=" << m_toolLineStartPoint + << " endPt=" << m_toolLineEndPoint + << " modifiers: shift=" << m_shiftPressed + << " alt=" << m_altPressed + << " ctrl=" << m_controlPressed + << endl; +#endif + + // angles + if (m_shiftPressed || m_controlPressed) + { + int diffx = m_toolLineEndPoint.x () - m_toolLineStartPoint.x (); + int diffy = m_toolLineEndPoint.y () - m_toolLineStartPoint.y (); + + double ratio; + if (diffx == 0) + ratio = DBL_MAX; + else + ratio = fabs (double (diffy) / double (diffx)); + #if DEBUG_KP_TOOL_POLYGON && 1 + kdDebug () << "\tdiffx=" << diffx << " diffy=" << diffy + << " ratio=" << ratio + << endl; + #endif + + // Shift = 0, 45, 90 + // Alt = 0, 30, 60, 90 + // Shift + Alt = 0, 30, 45, 60, 90 + double angles [10]; // "ought to be enough for anybody" + int numAngles = 0; + angles [numAngles++] = 0; + if (m_controlPressed) + angles [numAngles++] = KP_PI / 6; + if (m_shiftPressed) + angles [numAngles++] = KP_PI / 4; + if (m_controlPressed) + angles [numAngles++] = KP_PI / 3; + angles [numAngles++] = KP_PI / 2; + + double angle = angles [numAngles - 1]; + for (int i = 0; i < numAngles - 1; i++) + { + double acceptingRatio = tan ((angles [i] + angles [i + 1]) / 2.0); + if (ratio < acceptingRatio) + { + angle = angles [i]; + break; + } + } + + // horizontal (dist from start !maintained) + if (fabs (KP_RADIANS_TO_DEGREES (angle) - 0) + < kpPixmapFX::AngleInDegreesEpsilon) + { + m_toolLineEndPoint = QPoint (m_toolLineEndPoint.x (), m_toolLineStartPoint.y ()); + } + // vertical (dist from start !maintained) + else if (fabs (KP_RADIANS_TO_DEGREES (angle) - 90) + < kpPixmapFX::AngleInDegreesEpsilon) + { + m_toolLineEndPoint = QPoint (m_toolLineStartPoint.x (), m_toolLineEndPoint.y ()); + } + // diagonal (dist from start maintained) + else + { + const double dist = sqrt (diffx * diffx + diffy * diffy); + + #define sgn(a) ((a)<0?-1:1) + // Round distances _before_ adding to any coordinate + // (ensures consistent rounding behaviour in x & y directions) + const int newdx = qRound (dist * cos (angle) * sgn (diffx)); + const int newdy = qRound (dist * sin (angle) * sgn (diffy)); + #undef sgn + + m_toolLineEndPoint = QPoint (m_toolLineStartPoint.x () + newdx, + m_toolLineStartPoint.y () + newdy); + + #if DEBUG_KP_TOOL_POLYGON && 1 + kdDebug () << "\t\tdiagonal line: dist=" << dist + << " angle=" << (angle * 180 / KP_PI) + << " endPoint=" << m_toolLineEndPoint + << endl; + #endif + } + } // if (m_shiftPressed || m_controlPressed) { + + // centring + if (m_altPressed && 0/*ALT is unreliable*/) + { + // start = start - diff + // = start - (end - start) + // = start - end + start + // = 2 * start - end + if (count == 2) + m_toolLineStartPoint += (m_toolLineStartPoint - m_toolLineEndPoint); + else + m_toolLineEndPoint += (m_toolLineEndPoint - m_toolLineStartPoint); + } // if (m_altPressed) { + + m_points [count - 2] = m_toolLineStartPoint; + m_points [count - 1] = m_toolLineEndPoint; + + m_toolLineRect = kpTool::neededRect (QRect (m_toolLineStartPoint, m_toolLineEndPoint).normalize (), + m_lineWidth); +} + +// virtual +void kpToolPolygon::draw (const QPoint &, const QPoint &, const QRect &) +{ + if (m_points.count () == 0) + return; + +#if DEBUG_KP_TOOL_POLYGON + kdDebug () << "kpToolPolygon::draw() m_points=" << pointArrayToString (m_points) + << ", endPoint=" << m_currentPoint << endl; +#endif + + bool drawingALine = (m_mode != Curve) || + (m_mode == Curve && m_points.count () == 2); + + if (drawingALine) + applyModifiers (); + else + m_points [m_points.count () - 1] = m_currentPoint; + +#if DEBUG_KP_TOOL_POLYGON + kdDebug () << "\tafterwards, m_points=" << pointArrayToString (m_points) << endl; +#endif + + updateShape (); + + if (drawingALine) + setUserShapePoints (m_toolLineStartPoint, m_toolLineEndPoint); + else + setUserShapePoints (m_currentPoint); +} + +// private slot +void kpToolPolygon::updateShape () +{ + if (m_points.count () == 0) + return; + + QRect boundingRect = kpTool::neededRect (m_points.boundingRect (), m_lineWidth); + +#if DEBUG_KP_TOOL_POLYGON + kdDebug () << "kpToolPolygon::updateShape() boundingRect=" + << boundingRect + << " lineWidth=" + << m_lineWidth + << endl; +#endif + + QPixmap oldPixmap = document ()->getPixmapAt (boundingRect); + QPixmap newPixmap = pixmap (oldPixmap, + m_points, boundingRect, + color (m_mouseButton), color (1 - m_mouseButton), + m_lineWidth, Qt::SolidLine, + m_toolWidgetFillStyle, + m_mode, false/*not final*/); + + viewManager ()->setFastUpdates (); + viewManager ()->setTempPixmap (kpTempPixmap (false/*always display*/, + kpTempPixmap::SetPixmap/*render mode*/, + boundingRect.topLeft (), + newPixmap)); + viewManager ()->restoreFastUpdates (); +} + +// virtual +void kpToolPolygon::cancelShape () +{ +#if 0 + endDraw (QPoint (), QRect ()); + commandHistory ()->undo (); +#else + viewManager ()->invalidateTempPixmap (); +#endif + m_points.resize (0); + + setUserMessage (i18n ("Let go of all the mouse buttons.")); +} + +void kpToolPolygon::releasedAllButtons () +{ + if (!hasBegunShape ()) + setUserMessage (haventBegunShapeUserMessage ()); + + // --- else case already handled by endDraw() --- +} + +// virtual +void kpToolPolygon::endDraw (const QPoint &, const QRect &) +{ +#if DEBUG_KP_TOOL_POLYGON + kdDebug () << "kpToolPolygon::endDraw() m_points=" << pointArrayToString (m_points) << endl; +#endif + + if (m_points.count () == 0) + return; + + if (m_mode == Line || + (m_mode == Curve && m_points.count () >= 4) || + m_points.count () >= 50) + { + endShape (); + } + else + { + switch (m_mode) + { + case Line: + kdError () << "kpToolPolygon::endDraw() - line not ended" << endl; + setUserMessage (); + break; + + case Polygon: + case Polyline: + if (m_points.isEmpty ()) + { + kdError () << "kpToolPolygon::endDraw() exception - poly without points" << endl; + setUserMessage (); + } + else + { + if (m_mouseButton == 0) + { + setUserMessage (i18n ("Left drag another line or right click to finish.")); + } + else + { + setUserMessage (i18n ("Right drag another line or left click to finish.")); + } + } + + break; + + case Curve: + if (m_points.size () == 2) + { + if (m_mouseButton == 0) + { + setUserMessage (i18n ("Left drag to set the first control point or right click to finish.")); + } + else + { + setUserMessage (i18n ("Right drag to set the first control point or left click to finish.")); + } + } + else if (m_points.size () == 3) + { + if (m_mouseButton == 0) + { + setUserMessage (i18n ("Left drag to set the last control point or right click to finish.")); + } + else + { + setUserMessage (i18n ("Right drag to set the last control point or left click to finish.")); + } + } + else + { + kdError () << "kpToolPolygon::endDraw() exception - points" << endl; + setUserMessage (); + } + + break; + + default: + kdError () << "kpToolPolygon::endDraw() - clueless" << endl; + setUserMessage (); + break; + } + } +} + +// public virtual +void kpToolPolygon::endShape (const QPoint &, const QRect &) +{ +#if DEBUG_KP_TOOL_POLYGON + kdDebug () << "kpToolPolygon::endShape() m_points=" << pointArrayToString (m_points) << endl; +#endif + + if (!hasBegunShape ()) + return; + + viewManager ()->invalidateTempPixmap (); + + QRect boundingRect = kpTool::neededRect (m_points.boundingRect (), m_lineWidth); + + kpToolPolygonCommand *lineCommand = + new kpToolPolygonCommand + (text (), + m_points, boundingRect, + color (m_mouseButton), color (1 - m_mouseButton), + m_lineWidth, Qt::SolidLine, + m_toolWidgetFillStyle, + document ()->getPixmapAt (boundingRect), + m_mode, + mainWindow ()); + + commandHistory ()->addCommand (lineCommand); + + m_points.resize (0); + setUserMessage (haventBegunShapeUserMessage ()); + +} + +// public virtual +bool kpToolPolygon::hasBegunShape () const +{ + return (m_points.count () > 0); +} + + +// public slot +void kpToolPolygon::slotLineWidthChanged (int width) +{ + m_lineWidth = width; + updateShape (); +} + +// public slot +void kpToolPolygon::slotFillStyleChanged (kpToolWidgetFillStyle::FillStyle /*fillStyle*/) +{ + updateShape (); +} + +// virtual protected slot +void kpToolPolygon::slotForegroundColorChanged (const kpColor &) +{ + updateShape (); +} + +// virtual protected slot +void kpToolPolygon::slotBackgroundColorChanged (const kpColor &) +{ + updateShape (); +} + + +/* + * kpToolPolygonCommand + */ + +kpToolPolygonCommand::kpToolPolygonCommand (const QString &name, + const QPointArray &points, + const QRect &normalizedRect, + const kpColor &foregroundColor, const kpColor &backgroundColor, + int lineWidth, Qt::PenStyle lineStyle, + kpToolWidgetFillStyle *toolWidgetFillStyle, + const QPixmap &originalArea, + enum kpToolPolygon::Mode mode, + kpMainWindow *mainWindow) + : kpNamedCommand (name, mainWindow), + m_points (points), + m_normalizedRect (normalizedRect), + m_foregroundColor (foregroundColor), m_backgroundColor (backgroundColor), + m_lineWidth (lineWidth), m_lineStyle (lineStyle), + m_toolWidgetFillStyle (toolWidgetFillStyle), + m_originalArea (originalArea), + m_mode (mode) +{ + m_points.detach (); +} + +kpToolPolygonCommand::~kpToolPolygonCommand () +{ +} + + +// public virtual [base kpCommand] +int kpToolPolygonCommand::size () const +{ + return kpPixmapFX::pointArraySize (m_points) + + kpPixmapFX::pixmapSize (m_originalArea); +} + + +// public virtual [base kpCommand] +void kpToolPolygonCommand::execute () +{ + QPixmap p = pixmap (m_originalArea, + m_points, m_normalizedRect, + m_foregroundColor, m_backgroundColor, + m_lineWidth, m_lineStyle, + m_toolWidgetFillStyle, + m_mode); + document ()->setPixmapAt (p, m_normalizedRect.topLeft ()); +} + +// public virtual [base kpCommand] +void kpToolPolygonCommand::unexecute () +{ + document ()->setPixmapAt (m_originalArea, m_normalizedRect.topLeft ()); +} + +#include diff --git a/kolourpaint/tools/kptoolpolygon.h b/kolourpaint/tools/kptoolpolygon.h new file mode 100644 index 00000000..456dc4c0 --- /dev/null +++ b/kolourpaint/tools/kptoolpolygon.h @@ -0,0 +1,157 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolpolygon_h__ +#define __kptoolpolygon_h__ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +class QMouseEvent; +class QPen; +class QPoint; +class QRect; +class QString; + +class kpView; +class kpDocument; +class kpMainWindow; + +class kpToolWidgetFillStyle; +class kpToolWidgetLineWidth; +class kpViewManager; + +class kpToolPolygon : public kpTool +{ +Q_OBJECT + +public: + enum Mode + { + Polygon, Polyline, Line, Curve + }; + + kpToolPolygon (Mode mode, const QString &text, const QString &description, + int key, + kpMainWindow *mainWindow, const char *name); + kpToolPolygon (kpMainWindow *mainWindow); + virtual ~kpToolPolygon (); + + void setMode (Mode mode); + + virtual bool careAboutModifierState () const { return true; } + +private: + QString haventBegunShapeUserMessage () const; + +public: + virtual void begin (); + virtual void end (); + + virtual void beginDraw (); + virtual void draw (const QPoint &, const QPoint &, const QRect &); + virtual void cancelShape (); + virtual void releasedAllButtons (); + virtual void endDraw (const QPoint &, const QRect &); + virtual void endShape (const QPoint & = QPoint (), const QRect & = QRect ()); + + virtual bool hasBegunShape () const; + +public slots: + void slotLineWidthChanged (int width); + void slotFillStyleChanged (kpToolWidgetFillStyle::FillStyle fillStyle); + +protected slots: + virtual void slotForegroundColorChanged (const kpColor &); + virtual void slotBackgroundColorChanged (const kpColor &); + +private slots: + void updateShape (); + +private: + Mode m_mode; + + kpToolWidgetFillStyle *m_toolWidgetFillStyle; + + int m_lineWidth; + kpToolWidgetLineWidth *m_toolWidgetLineWidth; + + int m_originatingMouseButton; + + void applyModifiers (); + + QPoint m_toolLineStartPoint, m_toolLineEndPoint; + QRect m_toolLineRect; + + QPointArray m_points; +}; + +class kpToolPolygonCommand : public kpNamedCommand +{ +public: + kpToolPolygonCommand (const QString &name, + const QPointArray &points, + const QRect &normalizedRect, + const kpColor &foregroundColor, const kpColor &backgroundColor, + int lineWidth, Qt::PenStyle lineStyle, + kpToolWidgetFillStyle *toolWidgetFillStyle, + const QPixmap &originalArea, + kpToolPolygon::Mode mode, + kpMainWindow *mainWindow); + virtual ~kpToolPolygonCommand (); + + virtual int size () const; + + virtual void execute (); + virtual void unexecute (); + +private: + QPointArray m_points; + QRect m_normalizedRect; + + kpColor m_foregroundColor, m_backgroundColor; + int m_lineWidth; + Qt::PenStyle m_lineStyle; + kpToolWidgetFillStyle *m_toolWidgetFillStyle; + + QPixmap m_originalArea; + kpToolPolygon::Mode m_mode; +}; + +#endif // __kptoolpolygon_h__ diff --git a/kolourpaint/tools/kptoolpolyline.cpp b/kolourpaint/tools/kptoolpolyline.cpp new file mode 100644 index 00000000..6299b5b7 --- /dev/null +++ b/kolourpaint/tools/kptoolpolyline.cpp @@ -0,0 +1,47 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include + + +kpToolPolyline::kpToolPolyline (kpMainWindow *mainWindow) + : kpToolPolygon (Polyline, + i18n ("Connected Lines"), + i18n ("Draws connected lines"), + Qt::Key_N, + mainWindow, "tool_polyline") +{ +} + +kpToolPolyline::~kpToolPolyline () +{ +} + +#include diff --git a/kolourpaint/tools/kptoolpolyline.h b/kolourpaint/tools/kptoolpolyline.h new file mode 100644 index 00000000..f76a3959 --- /dev/null +++ b/kolourpaint/tools/kptoolpolyline.h @@ -0,0 +1,46 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolpolyline_h__ +#define __kptoolpolyline_h__ + +#include + +class kpMainWindow; + +class kpToolPolyline : public kpToolPolygon +{ +Q_OBJECT + +public: + kpToolPolyline (kpMainWindow *); + virtual ~kpToolPolyline (); +}; + +#endif // __kptoolpolyline_h__ + diff --git a/kolourpaint/tools/kptoolpreviewdialog.cpp b/kolourpaint/tools/kptoolpreviewdialog.cpp new file mode 100644 index 00000000..23149232 --- /dev/null +++ b/kolourpaint/tools/kptoolpreviewdialog.cpp @@ -0,0 +1,431 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_TOOL_PREVIEW_DIALOG 0 + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + + +kpToolPreviewDialog::kpToolPreviewDialog (Features features, + bool reserveTopRow, + const QString &caption, + const QString &afterActionText, + bool actOnSelection, + kpMainWindow *parent, + const char *name) + : KDialogBase (parent, name, true/*modal*/, + caption, + KDialogBase::Ok | KDialogBase::Cancel), + m_afterActionText (afterActionText), + m_actOnSelection (actOnSelection), + m_mainWindow (parent), + m_dimensionsGroupBox (0), + m_afterTransformDimensionsLabel (0), + m_previewGroupBox (0), + m_previewPixmapLabel (0), + m_gridLayout (0) +{ + QWidget *baseWidget = new QWidget (this); + setMainWidget (baseWidget); + + + if (document ()) + { + m_oldWidth = document ()->width (actOnSelection); + m_oldHeight = document ()->height (actOnSelection); + } + else + { + m_oldWidth = m_oldHeight = 1; + } + + + if (features & Dimensions) + createDimensionsGroupBox (); + + if (features & Preview) + createPreviewGroupBox (); + + + m_gridLayout = new QGridLayout (baseWidget, 4, 2, + 0/*margin*/, spacingHint ()); + m_gridNumRows = reserveTopRow ? 1 : 0; + if (m_dimensionsGroupBox || m_previewGroupBox) + { + if (m_dimensionsGroupBox && m_previewGroupBox) + { + m_gridLayout->addWidget (m_dimensionsGroupBox, m_gridNumRows, 0); + m_gridLayout->addWidget (m_previewGroupBox, m_gridNumRows, 1); + + m_gridLayout->setColStretch (1, 1); + } + else if (m_dimensionsGroupBox) + { + m_gridLayout->addMultiCellWidget (m_dimensionsGroupBox, + m_gridNumRows, m_gridNumRows, 0, 1); + } + else if (m_previewGroupBox) + { + m_gridLayout->addMultiCellWidget (m_previewGroupBox, + m_gridNumRows, m_gridNumRows, 0, 1); + } + + m_gridLayout->setRowStretch (m_gridNumRows, 1); + m_gridNumRows++;; + } +} + +kpToolPreviewDialog::~kpToolPreviewDialog () +{ +} + + +// private +void kpToolPreviewDialog::createDimensionsGroupBox () +{ + m_dimensionsGroupBox = new QGroupBox (i18n ("Dimensions"), mainWidget ()); + + QLabel *originalLabel = new QLabel (i18n ("Original:"), m_dimensionsGroupBox); + QString originalDimensions; + if (document ()) + { + originalDimensions = i18n ("%1 x %2") + .arg (m_oldWidth) + .arg (m_oldHeight); + + // Stop the Dimensions Group Box from resizing so often + const QString minimumLengthString ("100000 x 100000"); + const int padLength = minimumLengthString.length (); + for (int i = originalDimensions.length (); i < padLength; i++) + originalDimensions += " "; + } + QLabel *originalDimensionsLabel = new QLabel (originalDimensions, m_dimensionsGroupBox); + + QLabel *afterTransformLabel = new QLabel (m_afterActionText, m_dimensionsGroupBox); + m_afterTransformDimensionsLabel = new QLabel (m_dimensionsGroupBox); + + + QGridLayout *dimensionsLayout = new QGridLayout (m_dimensionsGroupBox, + 2, 2, + marginHint () * 2, spacingHint ()); + + dimensionsLayout->addWidget (originalLabel, 0, 0, Qt::AlignBottom); + dimensionsLayout->addWidget (originalDimensionsLabel, 0, 1, Qt::AlignBottom); + dimensionsLayout->addWidget (afterTransformLabel, 1, 0, Qt::AlignTop); + dimensionsLayout->addWidget (m_afterTransformDimensionsLabel, 1, 1, Qt::AlignTop); +} + +// private +void kpToolPreviewDialog::createPreviewGroupBox () +{ + m_previewGroupBox = new QGroupBox (i18n ("Preview"), mainWidget ()); + + m_previewPixmapLabel = new kpResizeSignallingLabel (m_previewGroupBox); + m_previewPixmapLabel->setMinimumSize (150, 110); + connect (m_previewPixmapLabel, SIGNAL (resized ()), + this, SLOT (updatePreview ())); + + QPushButton *updatePushButton = new QPushButton (i18n ("&Update"), + m_previewGroupBox); + connect (updatePushButton, SIGNAL (clicked ()), + this, SLOT (slotUpdateWithWaitCursor ())); + + + QVBoxLayout *previewLayout = new QVBoxLayout (m_previewGroupBox, + marginHint () * 2, + QMAX (1, spacingHint () / 2)); + + previewLayout->addWidget (m_previewPixmapLabel, 1/*stretch*/); + previewLayout->addWidget (updatePushButton, 0/*stretch*/, Qt::AlignHCenter); +} + + +// protected +kpDocument *kpToolPreviewDialog::document () const +{ + return m_mainWindow ? m_mainWindow->document () : 0; +} + + +// protected +void kpToolPreviewDialog::addCustomWidgetToFront (QWidget *w) +{ + m_gridLayout->addMultiCellWidget (w, 0, 0, 0, 1); +} + +// protected +void kpToolPreviewDialog::addCustomWidget (QWidget *w) +{ + m_gridLayout->addMultiCellWidget (w, m_gridNumRows, m_gridNumRows, 0, 1); + m_gridNumRows++; +} + + +// private +void kpToolPreviewDialog::updateDimensions () +{ + if (!m_dimensionsGroupBox) + return; + + kpDocument *doc = document (); + if (!doc) + return; + + QSize newDim = newDimensions (); +#if DEBUG_KP_TOOL_PREVIEW_DIALOG + kdDebug () << "kpToolPreviewDialog::updateDimensions(): newDim=" << newDim << endl; +#endif + + QString newDimString = i18n ("%1 x %2") + .arg (newDim.width ()) + .arg (newDim.height ()); + m_afterTransformDimensionsLabel->setText (newDimString); +} + + +// public static +double kpToolPreviewDialog::aspectScale (int newWidth, int newHeight, + int oldWidth, int oldHeight) +{ + double widthScale = double (newWidth) / double (oldWidth); + double heightScale = double (newHeight) / double (oldHeight); + + // Keeps aspect ratio + return QMIN (widthScale, heightScale); +} + +// public static +int kpToolPreviewDialog::scaleDimension (int dimension, double scale, int min, int max) +{ + return QMAX (min, + QMIN (max, + qRound (dimension * scale))); +} + + +// private +void kpToolPreviewDialog::updateShrukenDocumentPixmap () +{ +#if DEBUG_KP_TOOL_PREVIEW_DIALOG + kdDebug () << "kpToolPreviewDialog::updateShrukenDocumentPixmap()" + << " shrunkenDocPixmap.size=" + << m_shrunkenDocumentPixmap.size () + << " previewPixmapLabelSizeWhenUpdatedPixmap=" + << m_previewPixmapLabelSizeWhenUpdatedPixmap + << " previewPixmapLabel.size=" + << m_previewPixmapLabel->size () + << endl; +#endif + + if (!m_previewGroupBox) + return; + + + kpDocument *doc = document (); + if (!doc || !doc->pixmap ()) + { + kdError () << "kpToolPreviewDialog::updateShrunkenDocumentPixmap() doc=" + << doc << endl; + return; + } + + if (m_shrunkenDocumentPixmap.isNull () || + m_previewPixmapLabel->size () != m_previewPixmapLabelSizeWhenUpdatedPixmap) + { + #if DEBUG_KP_TOOL_PREVIEW_DIALOG + kdDebug () << "\tupdating shrunkenDocPixmap" << endl; + #endif + + // TODO: Why the need to keep aspect ratio here? + // Isn't scaling the skewed result maintaining aspect enough? + double keepsAspectScale = aspectScale (m_previewPixmapLabel->width (), + m_previewPixmapLabel->height (), + m_oldWidth, + m_oldHeight); + + QPixmap pixmap; + + if (m_actOnSelection) + { + kpSelection sel = *doc->selection (); + if (!sel.pixmap ()) + sel.setPixmap (doc->getSelectedPixmap ()); + + pixmap = sel.transparentPixmap (); + } + else + { + pixmap = *doc->pixmap (); + } + + m_shrunkenDocumentPixmap = kpPixmapFX::scale ( + pixmap, + scaleDimension (m_oldWidth, + keepsAspectScale, + 1, m_previewPixmapLabel->width ()), + scaleDimension (m_oldHeight, + keepsAspectScale, + 1, m_previewPixmapLabel->height ())); + #if 0 + m_shrunkenDocumentPixmap = kpPixmapFX::scale ( + m_actOnSelection ? doc->getSelectedPixmap () : *doc->pixmap (), + m_previewPixmapLabel->width (), + m_previewPixmapLabel->height ()); + #endif + + m_previewPixmapLabelSizeWhenUpdatedPixmap = m_previewPixmapLabel->size (); + } +} + + +// private +void kpToolPreviewDialog::updatePreview () +{ +#if DEBUG_KP_TOOL_PREVIEW_DIALOG + kdDebug () << "kpToolPreviewDialog::updatePreview()" << endl; +#endif + + if (!m_previewGroupBox) + return; + + + kpDocument *doc = document (); + if (!doc) + return; + + updateShrukenDocumentPixmap (); + + if (!m_shrunkenDocumentPixmap.isNull ()) + { + QSize newDim = newDimensions (); + double keepsAspectScale = aspectScale (m_previewPixmapLabel->width (), + m_previewPixmapLabel->height (), + newDim.width (), + newDim.height ()); + + int targetWidth = scaleDimension (newDim.width (), + keepsAspectScale, + 1, // min + m_previewPixmapLabel->width ()); // max + int targetHeight = scaleDimension (newDim.height (), + keepsAspectScale, + 1, // min + m_previewPixmapLabel->height ()); // max + + // TODO: Some effects work directly on QImage; so could cache the + // QImage so that transformPixmap() is faster + QPixmap transformedShrunkenDocumentPixmap = + transformPixmap (m_shrunkenDocumentPixmap, targetWidth, targetHeight); + + QPixmap previewPixmap (m_previewPixmapLabel->width (), + m_previewPixmapLabel->height ()); + kpPixmapFX::fill (&previewPixmap, kpColor::transparent); + kpPixmapFX::setPixmapAt (&previewPixmap, + (previewPixmap.width () - transformedShrunkenDocumentPixmap.width ()) / 2, + (previewPixmap.height () - transformedShrunkenDocumentPixmap.height ()) / 2, + transformedShrunkenDocumentPixmap); + +#if DEBUG_KP_TOOL_PREVIEW_DIALOG + kdDebug () << "kpToolPreviewDialog::updatePreview ():" + << " shrunkenDocumentPixmap: w=" + << m_shrunkenDocumentPixmap.width () + << " h=" + << m_shrunkenDocumentPixmap.height () + << " previewPixmapLabel: w=" + << m_previewPixmapLabel->width () + << " h=" + << m_previewPixmapLabel->height () + << " transformedShrunkenDocumentPixmap: w=" + << transformedShrunkenDocumentPixmap.width () + << " h=" + << transformedShrunkenDocumentPixmap.height () + << " previewPixmap: w=" + << previewPixmap.width () + << " h=" + << previewPixmap.height () + << endl; +#endif + + m_previewPixmapLabel->setPixmap (previewPixmap); + + // immediate update esp. for expensive previews + m_previewPixmapLabel->repaint (false/*no erase*/); + +#if DEBUG_KP_TOOL_PREVIEW_DIALOG + kdDebug () << "\tafter QLabel::setPixmap() previewPixmapLabel: w=" + << m_previewPixmapLabel->width () + << " h=" + << m_previewPixmapLabel->height () + << endl; +#endif + } +} + + +// protected slot virtual +void kpToolPreviewDialog::slotUpdate () +{ +#if DEBUG_KP_TOOL_PREVIEW_DIALOG + kdDebug () << "kpToolPreviewDialog::slotUpdate()" << endl; +#endif + updateDimensions (); + updatePreview (); +} + +// protected slot virtual +void kpToolPreviewDialog::slotUpdateWithWaitCursor () +{ +#if DEBUG_KP_TOOL_PREVIEW_DIALOG + kdDebug () << "kpToolPreviewDialog::slotUpdateWithWaitCursor()" + << endl; +#endif + + QApplication::setOverrideCursor (Qt::waitCursor); + + slotUpdate (); + + QApplication::restoreOverrideCursor (); +} + + +#include diff --git a/kolourpaint/tools/kptoolpreviewdialog.h b/kolourpaint/tools/kptoolpreviewdialog.h new file mode 100644 index 00000000..35efdc38 --- /dev/null +++ b/kolourpaint/tools/kptoolpreviewdialog.h @@ -0,0 +1,131 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __kp_tool_preview_dialog_h__ +#define __kp_tool_preview_dialog_h__ + + +#include + +#include + + +class QLabel; +class QGridLayout; +class QGroupBox; + +class kpDocument; +class kpMainWindow; +class kpResizeSignallingLabel; + + +class kpToolPreviewDialog : public KDialogBase +{ +Q_OBJECT + +public: + enum Features + { + Dimensions = 1, Preview = 2, + AllFeatures = Dimensions | Preview + }; + + // You must call slotUpdate() in your constructor + kpToolPreviewDialog (Features features, + bool reserveTopRow, + // e.g. "Skew (Image|Selection)" + const QString &caption, + // (in the Dimensions Group Box) e.g. "After Skew:" + const QString &afterActionText, + bool actOnSelection, + kpMainWindow *parent, + const char *name = 0); + virtual ~kpToolPreviewDialog (); + +private: + void createDimensionsGroupBox (); + void createPreviewGroupBox (); + +public: + virtual bool isNoOp () const = 0; + +protected: + kpDocument *document () const; + + // All widgets must have mainWidget() as their parent + void addCustomWidgetToFront (QWidget *w); // see in ctor + void addCustomWidget (QWidget *w); + void addCustomWidgetToBack (QWidget *w) + { + addCustomWidget (w); + } + + virtual QSize newDimensions () const = 0; + virtual QPixmap transformPixmap (const QPixmap &pixmap, + int targetWidth, int targetHeight) const = 0; + +private: + void updateDimensions (); + +public: + static double aspectScale (int newWidth, int newHeight, + int oldWidth, int oldHeight); + static int scaleDimension (int dimension, double scale, int min, int max); + +private: + void updateShrukenDocumentPixmap (); + +protected slots: + void updatePreview (); + + // Call this whenever a value (e.g. an angle) changes + // and the Dimensions & Preview need to be updated + virtual void slotUpdate (); + + virtual void slotUpdateWithWaitCursor (); + +protected: + QString m_afterActionText; + bool m_actOnSelection; + kpMainWindow *m_mainWindow; + + int m_oldWidth, m_oldHeight; + + QGroupBox *m_dimensionsGroupBox; + QLabel *m_afterTransformDimensionsLabel; + + QGroupBox *m_previewGroupBox; + kpResizeSignallingLabel *m_previewPixmapLabel; + QSize m_previewPixmapLabelSizeWhenUpdatedPixmap; + QPixmap m_shrunkenDocumentPixmap; + + QGridLayout *m_gridLayout; + int m_gridNumRows; +}; + + +#endif // __kp_tool_preview_dialog_h__ diff --git a/kolourpaint/tools/kptoolrectangle.cpp b/kolourpaint/tools/kptoolrectangle.cpp new file mode 100644 index 00000000..275db667 --- /dev/null +++ b/kolourpaint/tools/kptoolrectangle.cpp @@ -0,0 +1,638 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_TOOL_RECTANGLE 0 + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static QPixmap pixmap (const kpToolRectangle::Mode mode, + kpDocument *document, const QRect &rect, + const QPoint &startPoint, const QPoint &endPoint, + const QPen &pen, const QPen &maskPen, + const QBrush &brush, const QBrush &maskBrush) +{ + QPixmap pixmap = document->getPixmapAt (rect); + QBitmap maskBitmap; + + QPainter painter, maskPainter; + +#if DEBUG_KP_TOOL_RECTANGLE && 1 + kdDebug () << "pixmap: rect=" << rect + << " startPoint=" << startPoint + << " endPoint=" << endPoint + << endl; + kdDebug () << "\tm: p=" << (maskPen.style () != Qt::NoPen) + << " b=" << (maskBrush.style () != Qt::NoBrush) + << " o: p=" << (pen.style () != Qt::NoPen) + << " b=" << (brush.style () != Qt::NoBrush) + << endl; + kdDebug () << "\tmaskPen.color()=" << (int *) maskPen.color ().rgb () + << " transparent=" << (int *) Qt::color0.rgb ()/*transparent*/ + << endl; +#endif + + if (pixmap.mask () || + (maskPen.style () != Qt::NoPen && + maskPen.color () == Qt::color0/*transparent*/) || + (maskBrush.style () != Qt::NoBrush && + maskBrush.color () == Qt::color0/*transparent*/)) + { + maskBitmap = kpPixmapFX::getNonNullMask (pixmap); + maskPainter.begin (&maskBitmap); + maskPainter.setPen (maskPen); + maskPainter.setBrush (maskBrush); + } + + if (pen.style () != Qt::NoPen || + brush.style () != Qt::NoBrush) + { + painter.begin (&pixmap); + painter.setPen (pen); + painter.setBrush (brush); + } + +#define PAINTER_CALL(cmd) \ +{ \ + if (painter.isActive ()) \ + painter . cmd ; \ + \ + if (maskPainter.isActive ()) \ + maskPainter . cmd ; \ +} + + if (startPoint != endPoint) + { + #if DEBUG_KP_TOOL_RECTANGLE && 1 + kdDebug () << "\tdraw shape" << endl; + #endif + + // TODO: Rectangle of pen width 1, height 1 and width X is rendered + // as width X - 1. + switch (mode) + { + case kpToolRectangle::Rectangle: + PAINTER_CALL (drawRect (QRect (startPoint - rect.topLeft (), endPoint - rect.topLeft ()))); + break; + case kpToolRectangle::RoundedRectangle: + PAINTER_CALL (drawRoundRect (QRect (startPoint - rect.topLeft (), endPoint - rect.topLeft ()))); + break; + case kpToolRectangle::Ellipse: + PAINTER_CALL (drawEllipse (QRect (startPoint - rect.topLeft (), endPoint - rect.topLeft ()))); + break; + default: + kdError () << "kptoolrectangle.cpp::pixmap() passed unknown mode: " << int (mode) << endl; + break; + } + } + else + { + #if DEBUG_KP_TOOL_RECTANGLE && 1 + kdDebug () << "\tstartPoint == endPoint" << endl; + #endif + // SYNC: Work around Qt bug: can't draw 1x1 rectangle + // Not strictly correct for border width > 1 + // but better than not drawing at all + PAINTER_CALL (drawPoint (startPoint - rect.topLeft ())); + } +#undef PAINTER_CALL + + if (painter.isActive ()) + painter.end (); + + if (maskPainter.isActive ()) + maskPainter.end (); + + if (!maskBitmap.isNull ()) + pixmap.setMask (maskBitmap); + + return pixmap; +} + + +/* + * kpToolRectangle + */ + +kpToolRectangle::kpToolRectangle (Mode mode, + const QString &text, + const QString &description, + int key, + kpMainWindow *mainWindow, + const char *name) + : kpTool (text, description, key, mainWindow, name), + m_mode (mode), + m_toolWidgetLineWidth (0), + m_toolWidgetFillStyle (0) +{ +} + +kpToolRectangle::kpToolRectangle (kpMainWindow *mainWindow) + : kpTool (i18n ("Rectangle"), i18n ("Draws rectangles and squares"), + Qt::Key_R, + mainWindow, "tool_rectangle"), + m_mode (Rectangle), + m_toolWidgetLineWidth (0), + m_toolWidgetFillStyle (0) +{ +} + +kpToolRectangle::~kpToolRectangle () +{ +} + +void kpToolRectangle::setMode (Mode mode) +{ + m_mode = mode; +} + + +// private +void kpToolRectangle::updatePens () +{ + for (int i = 0; i < 2; i++) + updatePen (i); +} + +// private +void kpToolRectangle::updateBrushes () +{ + for (int i = 0; i < 2; i++) + updateBrush (i); +} + +// virtual private slot +void kpToolRectangle::slotForegroundColorChanged (const kpColor &) +{ +#if DEBUG_KP_TOOL_RECTANGLE + kdDebug () << "kpToolRectangle::slotForegroundColorChanged()" << endl; +#endif + updatePen (0); + updateBrush (0); // brush may be in foreground color + updateBrush (1); +} + +// virtual private slot +void kpToolRectangle::slotBackgroundColorChanged (const kpColor &) +{ +#if DEBUG_KP_TOOL_RECTANGLE + kdDebug () << "kpToolRectangle::slotBackgroundColorChanged()" << endl; + kdDebug () << "\tm_toolWidgetFillStyle=" << m_toolWidgetFillStyle << endl; +#endif + updatePen (1); + updateBrush (0); + updateBrush (1); // brush may be in background color +} + +// private +void kpToolRectangle::updatePen (int mouseButton) +{ + QColor maskPenColor = color (mouseButton).maskColor (); + + if (!m_toolWidgetLineWidth) + { + if (color (mouseButton).isOpaque ()) + m_pen [mouseButton] = QPen (color (mouseButton).toQColor ()); + else + m_pen [mouseButton] = Qt::NoPen; + m_maskPen [mouseButton] = QPen (maskPenColor); + } + else + { + if (color (mouseButton).isOpaque ()) + { + m_pen [mouseButton] = QPen (color (mouseButton).toQColor (), + m_toolWidgetLineWidth->lineWidth (), + Qt::SolidLine); + } + else + m_pen [mouseButton] = Qt::NoPen; + m_maskPen [mouseButton] = QPen (maskPenColor, + m_toolWidgetLineWidth->lineWidth (), + Qt::SolidLine); + } +} + +void kpToolRectangle::updateBrush (int mouseButton) +{ +#if DEBUG_KP_TOOL_RECTANGLE + kdDebug () << "kpToolRectangle::brush () mouseButton=" << mouseButton + << " m_toolWidgetFillStyle=" << m_toolWidgetFillStyle + << endl; +#endif + if (m_toolWidgetFillStyle) + { + m_brush [mouseButton] = m_toolWidgetFillStyle->brush ( + color (mouseButton)/*foreground colour*/, + color (1 - mouseButton)/*background colour*/); + + m_maskBrush [mouseButton] = m_toolWidgetFillStyle->maskBrush ( + color (mouseButton)/*foreground colour*/, + color (1 - mouseButton)/*background colour*/); + } + else + { + m_brush [mouseButton] = Qt::NoBrush; + m_maskBrush [mouseButton] = Qt::NoBrush; + } +} + + +// private slot virtual +void kpToolRectangle::slotLineWidthChanged () +{ + updatePens (); + + if (hasBegunDraw ()) + updateShape (); +} + +// private slot virtual +void kpToolRectangle::slotFillStyleChanged () +{ + updateBrushes (); + + if (hasBegunDraw ()) + updateShape (); +} + + +// private +QString kpToolRectangle::haventBegunDrawUserMessage () const +{ + return i18n ("Drag to draw."); +} + +// virtual +void kpToolRectangle::begin () +{ +#if DEBUG_KP_TOOL_RECTANGLE + kdDebug () << "kpToolRectangle::begin ()" << endl; +#endif + + kpToolToolBar *tb = toolToolBar (); + +#if DEBUG_KP_TOOL_RECTANGLE + kdDebug () << "\ttoolToolBar=" << tb << endl; +#endif + + if (tb) + { + m_toolWidgetLineWidth = tb->toolWidgetLineWidth (); + connect (m_toolWidgetLineWidth, SIGNAL (lineWidthChanged (int)), + this, SLOT (slotLineWidthChanged ())); + m_toolWidgetLineWidth->show (); + + updatePens (); + + + m_toolWidgetFillStyle = tb->toolWidgetFillStyle (); + connect (m_toolWidgetFillStyle, SIGNAL (fillStyleChanged (kpToolWidgetFillStyle::FillStyle)), + this, SLOT (slotFillStyleChanged ())); + m_toolWidgetFillStyle->show (); + + updateBrushes (); + } + +#if DEBUG_KP_TOOL_RECTANGLE + kdDebug () << "\t\tm_toolWidgetFillStyle=" << m_toolWidgetFillStyle << endl; +#endif + + viewManager ()->setCursor (QCursor (CrossCursor)); + + setUserMessage (haventBegunDrawUserMessage ()); +} + +// virtual +void kpToolRectangle::end () +{ +#if DEBUG_KP_TOOL_RECTANGLE + kdDebug () << "kpToolRectangle::end ()" << endl; +#endif + + if (m_toolWidgetLineWidth) + { + disconnect (m_toolWidgetLineWidth, SIGNAL (lineWidthChanged (int)), + this, SLOT (slotLineWidthChanged ())); + m_toolWidgetLineWidth = 0; + } + + if (m_toolWidgetFillStyle) + { + disconnect (m_toolWidgetFillStyle, SIGNAL (fillStyleChanged (kpToolWidgetFillStyle::FillStyle)), + this, SLOT (slotFillStyleChanged ())); + m_toolWidgetFillStyle = 0; + } + + viewManager ()->unsetCursor (); +} + +void kpToolRectangle::applyModifiers () +{ + QRect rect = QRect (m_startPoint, m_currentPoint).normalize (); + +#if DEBUG_KP_TOOL_RECTANGLE + kdDebug () << "kpToolRectangle::applyModifiers(" << rect + << ") shift=" << m_shiftPressed + << " ctrl=" << m_controlPressed + << endl; +#endif + + // user wants to m_startPoint == centre + if (m_controlPressed) + { + int xdiff = kAbs (m_startPoint.x () - m_currentPoint.x ()); + int ydiff = kAbs (m_startPoint.y () - m_currentPoint.y ()); + rect = QRect (m_startPoint.x () - xdiff, m_startPoint.y () - ydiff, + xdiff * 2 + 1, ydiff * 2 + 1); + } + + // user wants major axis == minor axis: + // rectangle --> square + // rounded rectangle --> rounded square + // ellipse --> circle + if (m_shiftPressed) + { + if (!m_controlPressed) + { + if (rect.width () < rect.height ()) + { + if (m_startPoint.y () == rect.y ()) + rect.setHeight (rect.width ()); + else + rect.setY (rect.bottom () - rect.width () + 1); + } + else + { + if (m_startPoint.x () == rect.x ()) + rect.setWidth (rect.height ()); + else + rect.setX (rect.right () - rect.height () + 1); + } + } + // have to maintain the centre + else + { + if (rect.width () < rect.height ()) + { + QPoint center = rect.center (); + rect.setHeight (rect.width ()); + rect.moveCenter (center); + } + else + { + QPoint center = rect.center (); + rect.setWidth (rect.height ()); + rect.moveCenter (center); + } + } + } + + m_toolRectangleStartPoint = rect.topLeft (); + m_toolRectangleEndPoint = rect.bottomRight (); + + m_toolRectangleRectWithoutLineWidth = rect; + m_toolRectangleRect = kpTool::neededRect (rect, QMAX (m_pen [m_mouseButton].width (), + m_maskPen [m_mouseButton].width ())); +} + +void kpToolRectangle::beginDraw () +{ + setUserMessage (cancelUserMessage ()); +} + +void kpToolRectangle::updateShape () +{ + viewManager ()->setFastUpdates (); + + QPixmap newPixmap = pixmap (m_mode, document (), m_toolRectangleRect, + m_toolRectangleStartPoint, m_toolRectangleEndPoint, + m_pen [m_mouseButton], m_maskPen [m_mouseButton], + m_brush [m_mouseButton], m_maskBrush [m_mouseButton]); + kpTempPixmap newTempPixmap (false/*always display*/, + kpTempPixmap::SetPixmap/*render mode*/, + m_toolRectangleRect.topLeft (), + newPixmap); + viewManager ()->setTempPixmap (newTempPixmap); + + viewManager ()->restoreFastUpdates (); +} + +void kpToolRectangle::draw (const QPoint &, const QPoint &, const QRect &) +{ + applyModifiers (); + + + updateShape (); + + + // Recover the start and end points from the transformed & normalized m_toolRectangleRect + + // S. or S or SC or S == C + // .C C + if (m_currentPoint.x () >= m_startPoint.x () && + m_currentPoint.y () >= m_startPoint.y ()) + { + setUserShapePoints (m_toolRectangleRectWithoutLineWidth.topLeft (), + m_toolRectangleRectWithoutLineWidth.bottomRight ()); + } + // .C or C + // S. S + else if (m_currentPoint.x () >= m_startPoint.x () && + m_currentPoint.y () < m_startPoint.y ()) + { + setUserShapePoints (m_toolRectangleRectWithoutLineWidth.bottomLeft (), + m_toolRectangleRectWithoutLineWidth.topRight ()); + } + // .S or CS + // C. + else if (m_currentPoint.x () < m_startPoint.x () && + m_currentPoint.y () >= m_startPoint.y ()) + { + setUserShapePoints (m_toolRectangleRectWithoutLineWidth.topRight (), + m_toolRectangleRectWithoutLineWidth.bottomLeft ()); + } + // C. + // .S + else + { + setUserShapePoints (m_toolRectangleRectWithoutLineWidth.bottomRight (), + m_toolRectangleRectWithoutLineWidth.topLeft ()); + } +} + +void kpToolRectangle::cancelShape () +{ +#if 0 + endDraw (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + mainWindow ()->commandHistory ()->undo (); +#else + viewManager ()->invalidateTempPixmap (); +#endif + + setUserMessage (i18n ("Let go of all the mouse buttons.")); +} + +void kpToolRectangle::releasedAllButtons () +{ + setUserMessage (haventBegunDrawUserMessage ()); +} + +void kpToolRectangle::endDraw (const QPoint &, const QRect &) +{ + applyModifiers (); + + // TODO: flicker + viewManager ()->invalidateTempPixmap (); + + mainWindow ()->commandHistory ()->addCommand ( + new kpToolRectangleCommand + (m_mode, + m_pen [m_mouseButton], m_maskPen [m_mouseButton], + m_brush [m_mouseButton], m_maskBrush [m_mouseButton], + m_toolRectangleRect, m_toolRectangleStartPoint, m_toolRectangleEndPoint, + mainWindow ())); + + setUserMessage (haventBegunDrawUserMessage ()); +} + + +/* + * kpToolRectangleCommand + */ + +kpToolRectangleCommand::kpToolRectangleCommand (kpToolRectangle::Mode mode, + const QPen &pen, const QPen &maskPen, + const QBrush &brush, const QBrush &maskBrush, + const QRect &rect, + const QPoint &startPoint, const QPoint &endPoint, + kpMainWindow *mainWindow) + : kpCommand (mainWindow), + m_mode (mode), + m_pen (pen), m_maskPen (maskPen), + m_brush (brush), m_maskBrush (maskBrush), + m_rect (rect), + m_startPoint (startPoint), + m_endPoint (endPoint), + m_oldPixmapPtr (0) +{ +} + +kpToolRectangleCommand::~kpToolRectangleCommand () +{ + delete m_oldPixmapPtr; +} + + +// public virtual [base kpCommand] +QString kpToolRectangleCommand::name () const +{ + switch (m_mode) + { + case kpToolRectangle::Rectangle: + return i18n ("Rectangle"); + case kpToolRectangle::RoundedRectangle: + return i18n ("Rounded Rectangle"); + case kpToolRectangle::Ellipse: + return i18n ("Ellipse"); + default: + kdError () << "kpToolRectangleCommand::name() passed unknown mode: " << int (m_mode) << endl; + return QString::null; + } +} + + +// public virtual [base kpCommand] +int kpToolRectangleCommand::size () const +{ + return kpPixmapFX::pixmapSize (m_oldPixmapPtr); +} + + +// public virtual [base kpCommand] +void kpToolRectangleCommand::execute () +{ + kpDocument *doc = document (); + if (!doc) + return; + + // store Undo info + if (!m_oldPixmapPtr) + { + // OPT: I can do better with no brush + m_oldPixmapPtr = new QPixmap (); + *m_oldPixmapPtr = doc->getPixmapAt (m_rect); + } + else + kdError () << "kpToolRectangleCommand::execute() m_oldPixmapPtr not null" << endl; + + doc->setPixmapAt (pixmap (m_mode, doc, + m_rect, m_startPoint, m_endPoint, + m_pen, m_maskPen, + m_brush, m_maskBrush), + m_rect.topLeft ()); +} + +// public virtual [base kpCommand] +void kpToolRectangleCommand::unexecute () +{ + kpDocument *doc = document (); + if (!doc) + return; + + if (m_oldPixmapPtr) + { + doc->setPixmapAt (*m_oldPixmapPtr, m_rect.topLeft ()); + + delete m_oldPixmapPtr; + m_oldPixmapPtr = 0; + } + else + kdError () << "kpToolRectangleCommand::unexecute() m_oldPixmapPtr null" << endl; +} + +#include diff --git a/kolourpaint/tools/kptoolrectangle.h b/kolourpaint/tools/kptoolrectangle.h new file mode 100644 index 00000000..0fcf5ff4 --- /dev/null +++ b/kolourpaint/tools/kptoolrectangle.h @@ -0,0 +1,142 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolrectangle_h__ +#define __kptoolrectangle_h__ + +#include +#include +#include +#include +#include + +#include + +#include + +class QString; + +class kpColor; +class kpMainWindow; +class kpToolWidgetFillStyle; +class kpToolWidgetLineWidth; +class kpViewManager; + +class kpToolRectangle : public kpTool +{ +Q_OBJECT + +public: + // it turns out that these shapes are all really the same thing + // (same options, same feel) - the only real difference is the + // drawing functions (a one line change) + enum Mode {Rectangle, RoundedRectangle, Ellipse}; + + kpToolRectangle (Mode mode, + const QString &text, const QString &description, + int key, + kpMainWindow *mainWindow, + const char *name); + kpToolRectangle (kpMainWindow *); + virtual ~kpToolRectangle (); + + void setMode (Mode mode); + + virtual bool careAboutModifierState () const { return true; } + +private: + QString haventBegunDrawUserMessage () const; + +public: + virtual void begin (); + virtual void end (); + + virtual void beginDraw (); +private: + void updateShape (); +public: + virtual void draw (const QPoint &, const QPoint &, const QRect &); + virtual void cancelShape (); + virtual void releasedAllButtons (); + virtual void endDraw (const QPoint &, const QRect &); + +private slots: + void updatePens (); + void updateBrushes (); + + virtual void slotForegroundColorChanged (const kpColor &); + virtual void slotBackgroundColorChanged (const kpColor &); + + virtual void slotLineWidthChanged (); + virtual void slotFillStyleChanged (); + +private: + Mode m_mode; + + kpToolWidgetLineWidth *m_toolWidgetLineWidth; + kpToolWidgetFillStyle *m_toolWidgetFillStyle; + + void updatePen (int mouseButton); + QPen m_pen [2], m_maskPen [2]; + + void updateBrush (int mouseButton); + QBrush m_brush [2], m_maskBrush [2]; + + void applyModifiers (); + QPoint m_toolRectangleStartPoint, m_toolRectangleEndPoint; + QRect m_toolRectangleRectWithoutLineWidth, m_toolRectangleRect; +}; + +class kpToolRectangleCommand : public kpCommand +{ +public: + kpToolRectangleCommand (kpToolRectangle::Mode mode, + const QPen &pen, const QPen &maskPen, + const QBrush &brush, const QBrush &maskBrush, + const QRect &rect, + const QPoint &startPoint, const QPoint &endPoint, + kpMainWindow *mainWindow); + virtual ~kpToolRectangleCommand (); + + virtual QString name () const; + + virtual int size () const; + + virtual void execute (); + virtual void unexecute (); + +private: + kpToolRectangle::Mode m_mode; + QPen m_pen, m_maskPen; + QBrush m_brush, m_maskBrush; + QRect m_rect; + QPoint m_startPoint, m_endPoint; + QPixmap *m_oldPixmapPtr; +}; + +#endif // __kptoolrectangle_h__ diff --git a/kolourpaint/tools/kptoolrectselection.cpp b/kolourpaint/tools/kptoolrectselection.cpp new file mode 100644 index 00000000..3726cbfe --- /dev/null +++ b/kolourpaint/tools/kptoolrectselection.cpp @@ -0,0 +1,46 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include + + +kpToolRectSelection::kpToolRectSelection (kpMainWindow *mainWindow) + : kpToolSelection (Rectangle, + i18n ("Selection (Rectangular)"), + i18n ("Makes a rectangular selection"), + Qt::Key_S, + mainWindow, "tool_rect_selection") +{ +} + +kpToolRectSelection::~kpToolRectSelection () +{ +} + diff --git a/kolourpaint/tools/kptoolrectselection.h b/kolourpaint/tools/kptoolrectselection.h new file mode 100644 index 00000000..0d66b7a5 --- /dev/null +++ b/kolourpaint/tools/kptoolrectselection.h @@ -0,0 +1,43 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolrectselection_h__ +#define __kptoolrectselection_h__ + +#include + +class kpMainWindow; + +class kpToolRectSelection : public kpToolSelection +{ +public: + kpToolRectSelection (kpMainWindow *); + virtual ~kpToolRectSelection (); +}; + +#endif // __kptoolrectselection_h__ diff --git a/kolourpaint/tools/kptoolresizescale.cpp b/kolourpaint/tools/kptoolresizescale.cpp new file mode 100644 index 00000000..ce9c9059 --- /dev/null +++ b/kolourpaint/tools/kptoolresizescale.cpp @@ -0,0 +1,1222 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_TOOL_RESIZE_SCALE_COMMAND 0 +#define DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG 0 + + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +/* + * kpToolResizeScaleCommand + */ + +kpToolResizeScaleCommand::kpToolResizeScaleCommand (bool actOnSelection, + int newWidth, int newHeight, + Type type, + kpMainWindow *mainWindow) + : kpCommand (mainWindow), + m_actOnSelection (actOnSelection), + m_type (type), + m_backgroundColor (mainWindow ? mainWindow->backgroundColor () : kpColor::invalid), + m_oldSelection (0) +{ + kpDocument *doc = document (); + + m_oldWidth = doc->width (m_actOnSelection); + m_oldHeight = doc->height (m_actOnSelection); + + m_actOnTextSelection = (m_actOnSelection && + doc && doc->selection () && + doc->selection ()->isText ()); + + resize (newWidth, newHeight); + + // If we have a selection _border_ (but not a floating selection), + // then scale the selection with the document + m_scaleSelectionWithImage = (!m_actOnSelection && + (m_type == Scale || m_type == SmoothScale) && + document ()->selection () && + !document ()->selection ()->pixmap ()); +} + +kpToolResizeScaleCommand::~kpToolResizeScaleCommand () +{ + delete m_oldSelection; +} + + +// public virtual [base kpCommand] +QString kpToolResizeScaleCommand::name () const +{ + if (m_actOnSelection) + { + if (m_actOnTextSelection) + { + if (m_type == Resize) + return i18n ("Text: Resize Box"); + } + else + { + if (m_type == Scale) + return i18n ("Selection: Scale"); + else if (m_type == SmoothScale) + return i18n ("Selection: Smooth Scale"); + } + } + else + { + switch (m_type) + { + case Resize: + return i18n ("Resize"); + case Scale: + return i18n ("Scale"); + case SmoothScale: + return i18n ("Smooth Scale"); + } + } + + return QString::null; +} + +// public virtual [base kpCommand] +int kpToolResizeScaleCommand::size () const +{ + return kpPixmapFX::pixmapSize (m_oldPixmap) + + kpPixmapFX::pixmapSize (m_oldRightPixmap) + + kpPixmapFX::pixmapSize (m_oldBottomPixmap) + + (m_oldSelection ? m_oldSelection->size () : 0); +} + + +// public +int kpToolResizeScaleCommand::newWidth () const +{ + return m_newWidth; +} + +// public +void kpToolResizeScaleCommand::setNewWidth (int width) +{ + resize (width, newHeight ()); +} + + +// public +int kpToolResizeScaleCommand::newHeight () const +{ + return m_newHeight; +} + +// public +void kpToolResizeScaleCommand::setNewHeight (int height) +{ + resize (newWidth (), height); +} + + +// public +QSize kpToolResizeScaleCommand::newSize () const +{ + return QSize (newWidth (), newHeight ()); +} + +// public virtual +void kpToolResizeScaleCommand::resize (int width, int height) +{ + m_newWidth = width; + m_newHeight = height; + + m_isLosslessScale = ((m_type == Scale) && + (m_newWidth / m_oldWidth * m_oldWidth == m_newWidth) && + (m_newHeight / m_oldHeight * m_oldHeight == m_newHeight)); +} + + +// public +bool kpToolResizeScaleCommand::scaleSelectionWithImage () const +{ + return m_scaleSelectionWithImage; +} + + +// private +void kpToolResizeScaleCommand::scaleSelectionRegionWithDocument () +{ +#if DEBUG_KP_TOOL_RESIZE_SCALE_COMMAND + kdDebug () << "kpToolResizeScaleCommand::scaleSelectionRegionWithDocument" + << endl; +#endif + + if (!m_oldSelection) + { + kdError () << "kpToolResizeScaleCommand::scaleSelectionRegionWithDocument()" + << " without old sel" << endl; + return; + } + + if (m_oldSelection->pixmap ()) + { + kdError () << "kpToolResizeScaleCommand::scaleSelectionRegionWithDocument()" + << " old sel has pixmap" << endl; + return; + } + + + const double horizScale = double (m_newWidth) / double (m_oldWidth); + const double vertScale = double (m_newHeight) / double (m_oldHeight); + + const int newX = (int) (m_oldSelection->x () * horizScale); + const int newY = (int) (m_oldSelection->y () * vertScale); + + + QPointArray currentPoints = m_oldSelection->points (); + currentPoints.detach (); + + currentPoints.translate (-currentPoints.boundingRect ().x (), + -currentPoints.boundingRect ().y ()); + + // TODO: refactor into kpPixmapFX + QWMatrix scaleMatrix; + scaleMatrix.scale (horizScale, vertScale); + currentPoints = scaleMatrix.map (currentPoints); + + currentPoints.translate ( + -currentPoints.boundingRect ().x () + newX, + -currentPoints.boundingRect ().y () + newY); + + document ()->setSelection (kpSelection (currentPoints, QPixmap (), + m_oldSelection->transparency ())); + + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); +} + + +// public virtual [base kpCommand] +void kpToolResizeScaleCommand::execute () +{ +#if DEBUG_KP_TOOL_RESIZE_SCALE_COMMAND + kdDebug () << "kpToolResizeScaleCommand::execute() type=" + << (int) m_type + << " oldWidth=" << m_oldWidth + << " oldHeight=" << m_oldHeight + << " newWidth=" << m_newWidth + << " newHeight=" << m_newHeight + << endl; +#endif + + if (m_oldWidth == m_newWidth && m_oldHeight == m_newHeight) + return; + + if (m_type == Resize) + { + if (m_actOnSelection) + { + if (!m_actOnTextSelection) + { + kdError () << "kpToolResizeScaleCommand::execute() resizing sel doesn't make sense" << endl; + return; + } + else + { + QApplication::setOverrideCursor (Qt::waitCursor); + document ()->selection ()->textResize (m_newWidth, m_newHeight); + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + + QApplication::restoreOverrideCursor (); + } + } + else + { + QApplication::setOverrideCursor (Qt::waitCursor); + + + if (m_newWidth < m_oldWidth) + { + m_oldRightPixmap = kpPixmapFX::getPixmapAt ( + *document ()->pixmap (), + QRect (m_newWidth, 0, + m_oldWidth - m_newWidth, m_oldHeight)); + } + + if (m_newHeight < m_oldHeight) + { + m_oldBottomPixmap = kpPixmapFX::getPixmapAt ( + *document ()->pixmap (), + QRect (0, m_newHeight, + m_newWidth, m_oldHeight - m_newHeight)); + } + + document ()->resize (m_newWidth, m_newHeight, m_backgroundColor); + + + QApplication::restoreOverrideCursor (); + } + } + else + { + QApplication::setOverrideCursor (Qt::waitCursor); + + + QPixmap oldPixmap = *document ()->pixmap (m_actOnSelection); + + if (!m_isLosslessScale) + m_oldPixmap = oldPixmap; + + QPixmap newPixmap = kpPixmapFX::scale (oldPixmap, m_newWidth, m_newHeight, + m_type == SmoothScale); + + + if (!m_oldSelection && document ()->selection ()) + { + // Save sel border + m_oldSelection = new kpSelection (*document ()->selection ()); + m_oldSelection->setPixmap (QPixmap ()); + } + + if (m_actOnSelection) + { + QRect newRect = QRect (m_oldSelection->x (), m_oldSelection->y (), + newPixmap.width (), newPixmap.height ()); + + // Not possible to retain non-rectangular selection borders on scale + // (think about e.g. a 45 deg line as part of the border & 2x scale) + document ()->setSelection ( + kpSelection (kpSelection::Rectangle, newRect, newPixmap, + m_oldSelection->transparency ())); + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + } + else + { + document ()->setPixmap (newPixmap); + + if (m_scaleSelectionWithImage) + { + scaleSelectionRegionWithDocument (); + } + } + + + QApplication::restoreOverrideCursor (); + } +} + +// public virtual [base kpCommand] +void kpToolResizeScaleCommand::unexecute () +{ +#if DEBUG_KP_TOOL_RESIZE_SCALE_COMMAND + kdDebug () << "kpToolResizeScaleCommand::unexecute() type=" + << m_type << endl; +#endif + + if (m_oldWidth == m_newWidth && m_oldHeight == m_newHeight) + return; + + kpDocument *doc = document (); + if (!doc) + return; + + if (m_type == Resize) + { + if (m_actOnSelection) + { + if (!m_actOnTextSelection) + { + kdError () << "kpToolResizeScaleCommand::unexecute() resizing sel doesn't make sense" << endl; + return; + } + else + { + QApplication::setOverrideCursor (Qt::waitCursor); + document ()->selection ()->textResize (m_oldWidth, m_oldHeight); + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + + QApplication::restoreOverrideCursor (); + } + } + else + { + QApplication::setOverrideCursor (Qt::waitCursor); + + + QPixmap newPixmap (m_oldWidth, m_oldHeight); + + kpPixmapFX::setPixmapAt (&newPixmap, QPoint (0, 0), + *doc->pixmap ()); + + if (m_newWidth < m_oldWidth) + { + kpPixmapFX::setPixmapAt (&newPixmap, + QPoint (m_newWidth, 0), + m_oldRightPixmap); + } + + if (m_newHeight < m_oldHeight) + { + kpPixmapFX::setPixmapAt (&newPixmap, + QPoint (0, m_newHeight), + m_oldBottomPixmap); + } + + doc->setPixmap (newPixmap); + + + QApplication::restoreOverrideCursor (); + } + } + else + { + QApplication::setOverrideCursor (Qt::waitCursor); + + + QPixmap oldPixmap; + + if (!m_isLosslessScale) + oldPixmap = m_oldPixmap; + else + oldPixmap = kpPixmapFX::scale (*doc->pixmap (m_actOnSelection), + m_oldWidth, m_oldHeight); + + + if (m_actOnSelection) + { + kpSelection oldSelection = *m_oldSelection; + oldSelection.setPixmap (oldPixmap); + doc->setSelection (oldSelection); + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + } + else + { + doc->setPixmap (oldPixmap); + + if (m_scaleSelectionWithImage) + { + doc->setSelection (*m_oldSelection); + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + } + } + + + QApplication::restoreOverrideCursor (); + } +} + + +/* + * kpToolResizeScaleDialog + */ + +#define SET_VALUE_WITHOUT_SIGNAL_EMISSION(knuminput_instance,value) \ +{ \ + knuminput_instance->blockSignals (true); \ + knuminput_instance->setValue (value); \ + knuminput_instance->blockSignals (false); \ +} + +#define IGNORE_KEEP_ASPECT_RATIO(cmd) \ +{ \ + m_ignoreKeepAspectRatio++; \ + cmd; \ + m_ignoreKeepAspectRatio--; \ +} + + +// private static +kpToolResizeScaleCommand::Type kpToolResizeScaleDialog::s_lastType = + kpToolResizeScaleCommand::Resize; + +// private static +double kpToolResizeScaleDialog::s_lastPercentWidth = 100, + kpToolResizeScaleDialog::s_lastPercentHeight = 100; + + +kpToolResizeScaleDialog::kpToolResizeScaleDialog (kpMainWindow *mainWindow) + : KDialogBase ((QWidget *) mainWindow, + 0/*name*/, + true/*modal*/, + i18n ("Resize / Scale")/*caption*/, + KDialogBase::Ok | KDialogBase::Cancel), + m_mainWindow (mainWindow), + m_ignoreKeepAspectRatio (0) +{ + // Using the percentage from last time become too confusing so disable for now + s_lastPercentWidth = 100, s_lastPercentHeight = 100; + + + QWidget *baseWidget = new QWidget (this); + setMainWidget (baseWidget); + + + createActOnBox (baseWidget); + createOperationGroupBox (baseWidget); + createDimensionsGroupBox (baseWidget); + + + QVBoxLayout *baseLayout = new QVBoxLayout (baseWidget, 0/*margin*/, spacingHint ()); + baseLayout->addWidget (m_actOnBox); + baseLayout->addWidget (m_operationGroupBox); + baseLayout->addWidget (m_dimensionsGroupBox); + + + slotActOnChanged (); + + m_newWidthInput->setEditFocus (); + + //enableButtonOK (!isNoOp ()); +} + +kpToolResizeScaleDialog::~kpToolResizeScaleDialog () +{ +} + + +// private +kpDocument *kpToolResizeScaleDialog::document () const +{ + return m_mainWindow ? m_mainWindow->document () : 0; +} + +// private +kpSelection *kpToolResizeScaleDialog::selection () const +{ + return document () ? document ()->selection () : 0; +} + + +// private +void kpToolResizeScaleDialog::createActOnBox (QWidget *baseWidget) +{ + m_actOnBox = new QHBox (baseWidget); + m_actOnBox->setSpacing (spacingHint () * 2); + + + m_actOnLabel = new QLabel (i18n ("Ac&t on:"), m_actOnBox); + m_actOnCombo = new KComboBox (m_actOnBox); + + + m_actOnLabel->setBuddy (m_actOnCombo); + + m_actOnCombo->insertItem (i18n ("Entire Image"), Image); + if (selection ()) + { + QString selName = i18n ("Selection"); + + if (selection ()->isText ()) + selName = i18n ("Text Box"); + + m_actOnCombo->insertItem (selName, Selection); + m_actOnCombo->setCurrentItem (Selection); + } + else + { + m_actOnLabel->setEnabled (false); + m_actOnCombo->setEnabled (false); + } + + + m_actOnBox->setStretchFactor (m_actOnCombo, 1); + + + connect (m_actOnCombo, SIGNAL (activated (int)), + this, SLOT (slotActOnChanged ())); +} + + +static QIconSet toolButtonIconSet (const QString &iconName) +{ + QIconSet iconSet = UserIconSet (iconName); + + + // No "disabled" pixmap is generated by UserIconSet() so generate it + // ourselves: + + QPixmap disabledIcon = KGlobal::iconLoader ()->iconEffect ()->apply ( + UserIcon (iconName), + KIcon::Toolbar, KIcon::DisabledState); + + const QPixmap iconSetNormalIcon = iconSet.pixmap (QIconSet::Small, + QIconSet::Normal); + + // I bet past or future versions of KIconEffect::apply() resize the + // disabled icon if we claim it's in group KIcon::Toolbar. So resize + // it to match the QIconSet::Normal icon, just in case. + disabledIcon = kpPixmapFX::scale (disabledIcon, + iconSetNormalIcon.width (), + iconSetNormalIcon.height (), + true/*smooth scale*/); + + + iconSet.setPixmap (disabledIcon, + QIconSet::Small, QIconSet::Disabled); + + return iconSet; +} + +static void toolButtonSetLook (QToolButton *button, + const QString &iconName, + const QString &name) +{ + button->setIconSet (toolButtonIconSet (iconName)); + button->setUsesTextLabel (true); + button->setTextLabel (name, false/*no tooltip*/); + button->setAccel (QAccel::shortcutKey (name)); + button->setFocusPolicy (QWidget::StrongFocus); + button->setToggleButton (true); +} + + +// private +void kpToolResizeScaleDialog::createOperationGroupBox (QWidget *baseWidget) +{ + m_operationGroupBox = new QGroupBox (i18n ("Operation"), baseWidget); + QWhatsThis::add (m_operationGroupBox, + i18n ("" + "
    " + "
  • Resize: The size of the picture will be" + " increased" + " by creating new areas to the right and/or bottom" + " (filled in with the background color) or" + " decreased by cutting" + " it at the right and/or bottom.
  • " + + "
  • Scale: The picture will be expanded" + " by duplicating pixels or squashed by dropping pixels.
  • " + + "
  • Smooth Scale: This is the same as" + " Scale except that it blends neighboring" + " pixels to produce a smoother looking picture.
  • " + "
" + "
")); + + // TODO: ALT+R doesn't select the button. + m_resizeButton = new QToolButton (m_operationGroupBox); + toolButtonSetLook (m_resizeButton, + QString::fromLatin1 ("resize"), + i18n ("&Resize")); + + m_scaleButton = new QToolButton (m_operationGroupBox); + toolButtonSetLook (m_scaleButton, + QString::fromLatin1 ("scale"), + i18n ("&Scale")); + + m_smoothScaleButton = new QToolButton (m_operationGroupBox); + toolButtonSetLook (m_smoothScaleButton, + QString::fromLatin1 ("smooth_scale"), + i18n ("S&mooth Scale")); + + + //m_resizeLabel = new QLabel (i18n ("&Resize"), m_operationGroupBox); + //m_scaleLabel = new QLabel (i18n ("&Scale"), m_operationGroupBox); + //m_smoothScaleLabel = new QLabel (i18n ("S&mooth scale"), m_operationGroupBox); + + + //m_resizeLabel->setAlignment (m_resizeLabel->alignment () | Qt::ShowPrefix); + //m_scaleLabel->setAlignment (m_scaleLabel->alignment () | Qt::ShowPrefix); + //m_smoothScaleLabel->setAlignment (m_smoothScaleLabel->alignment () | Qt::ShowPrefix); + + + QButtonGroup *resizeScaleButtonGroup = new QButtonGroup (baseWidget); + resizeScaleButtonGroup->setExclusive (true); + resizeScaleButtonGroup->hide (); + + resizeScaleButtonGroup->insert (m_resizeButton); + resizeScaleButtonGroup->insert (m_scaleButton); + resizeScaleButtonGroup->insert (m_smoothScaleButton); + + + QGridLayout *operationLayout = new QGridLayout (m_operationGroupBox, + 1, 2, + marginHint () * 2/*don't overlap groupbox title*/, + spacingHint ()); + + operationLayout->addWidget (m_resizeButton, 0, 0, Qt::AlignCenter); + //operationLayout->addWidget (m_resizeLabel, 1, 0, Qt::AlignCenter); + + operationLayout->addWidget (m_scaleButton, 0, 1, Qt::AlignCenter); + //operationLayout->addWidget (m_scaleLabel, 1, 1, Qt::AlignCenter); + + operationLayout->addWidget (m_smoothScaleButton, 0, 2, Qt::AlignCenter); + //operationLayout->addWidget (m_smoothScaleLabel, 1, 2, Qt::AlignCenter); + + + connect (m_resizeButton, SIGNAL (toggled (bool)), + this, SLOT (slotTypeChanged ())); + connect (m_scaleButton, SIGNAL (toggled (bool)), + this, SLOT (slotTypeChanged ())); + connect (m_smoothScaleButton, SIGNAL (toggled (bool)), + this, SLOT (slotTypeChanged ())); +} + +// private +void kpToolResizeScaleDialog::createDimensionsGroupBox (QWidget *baseWidget) +{ + m_dimensionsGroupBox = new QGroupBox (i18n ("Dimensions"), baseWidget); + + QLabel *widthLabel = new QLabel (i18n ("Width:"), m_dimensionsGroupBox); + widthLabel->setAlignment (widthLabel->alignment () | Qt::AlignHCenter); + QLabel *heightLabel = new QLabel (i18n ("Height:"), m_dimensionsGroupBox); + heightLabel->setAlignment (heightLabel->alignment () | Qt::AlignHCenter); + + QLabel *originalLabel = new QLabel (i18n ("Original:"), m_dimensionsGroupBox); + m_originalWidthInput = new KIntNumInput ( + document ()->width ((bool) selection ()), + m_dimensionsGroupBox); + QLabel *xLabel0 = new QLabel (i18n ("x"), m_dimensionsGroupBox); + m_originalHeightInput = new KIntNumInput ( + document ()->height ((bool) selection ()), + m_dimensionsGroupBox); + + QLabel *newLabel = new QLabel (i18n ("&New:"), m_dimensionsGroupBox); + m_newWidthInput = new KIntNumInput (m_dimensionsGroupBox); + QLabel *xLabel1 = new QLabel (i18n ("x"), m_dimensionsGroupBox); + m_newHeightInput = new KIntNumInput (m_dimensionsGroupBox); + + QLabel *percentLabel = new QLabel (i18n ("&Percent:"), m_dimensionsGroupBox); + m_percentWidthInput = new KDoubleNumInput (0.01/*lower*/, 1000000/*upper*/, + 100/*value*/, 1/*step*/, + 2/*precision*/, + m_dimensionsGroupBox); + m_percentWidthInput->setSuffix (i18n ("%")); + QLabel *xLabel2 = new QLabel (i18n ("x"), m_dimensionsGroupBox); + m_percentHeightInput = new KDoubleNumInput (0.01/*lower*/, 1000000/*upper*/, + 100/*value*/, 1/*step*/, + 2/*precision*/, + m_dimensionsGroupBox); + m_percentHeightInput->setSuffix (i18n ("%")); + + m_keepAspectRatioCheckBox = new QCheckBox (i18n ("Keep &aspect ratio"), + m_dimensionsGroupBox); + + + m_originalWidthInput->setEnabled (false); + m_originalHeightInput->setEnabled (false); + originalLabel->setBuddy (m_originalWidthInput); + newLabel->setBuddy (m_newWidthInput); + m_percentWidthInput->setValue (s_lastPercentWidth); + m_percentHeightInput->setValue (s_lastPercentHeight); + percentLabel->setBuddy (m_percentWidthInput); + + + QGridLayout *dimensionsLayout = new QGridLayout (m_dimensionsGroupBox, + 5, 4, marginHint () * 2, spacingHint ()); + dimensionsLayout->setColStretch (1/*column*/, 1); + dimensionsLayout->setColStretch (3/*column*/, 1); + + + dimensionsLayout->addWidget (widthLabel, 0, 1); + dimensionsLayout->addWidget (heightLabel, 0, 3); + + dimensionsLayout->addWidget (originalLabel, 1, 0); + dimensionsLayout->addWidget (m_originalWidthInput, 1, 1); + dimensionsLayout->addWidget (xLabel0, 1, 2); + dimensionsLayout->addWidget (m_originalHeightInput, 1, 3); + + dimensionsLayout->addWidget (newLabel, 2, 0); + dimensionsLayout->addWidget (m_newWidthInput, 2, 1); + dimensionsLayout->addWidget (xLabel1, 2, 2); + dimensionsLayout->addWidget (m_newHeightInput, 2, 3); + + dimensionsLayout->addWidget (percentLabel, 3, 0); + dimensionsLayout->addWidget (m_percentWidthInput, 3, 1); + dimensionsLayout->addWidget (xLabel2, 3, 2); + dimensionsLayout->addWidget (m_percentHeightInput, 3, 3); + + dimensionsLayout->addMultiCellWidget (m_keepAspectRatioCheckBox, 4, 4, 0, 3); + dimensionsLayout->setRowStretch (4/*row*/, 1); + dimensionsLayout->setRowSpacing (4/*row*/, dimensionsLayout->rowSpacing (4) * 2); + + + connect (m_newWidthInput, SIGNAL (valueChanged (int)), + this, SLOT (slotWidthChanged (int))); + connect (m_newHeightInput, SIGNAL (valueChanged (int)), + this, SLOT (slotHeightChanged (int))); + + connect (m_percentWidthInput, SIGNAL (valueChanged (double)), + this, SLOT (slotPercentWidthChanged (double))); + connect (m_percentHeightInput, SIGNAL (valueChanged (double)), + this, SLOT (slotPercentHeightChanged (double))); + + connect (m_keepAspectRatioCheckBox, SIGNAL (toggled (bool)), + this, SLOT (setKeepAspectRatio (bool))); +} + + +// private +void kpToolResizeScaleDialog::widthFitHeightToAspectRatio () +{ + if (m_keepAspectRatioCheckBox->isChecked () && !m_ignoreKeepAspectRatio) + { + // width / height = oldWidth / oldHeight + // height = width * oldHeight / oldWidth + const int newHeight = qRound (double (imageWidth ()) * double (originalHeight ()) + / double (originalWidth ())); + IGNORE_KEEP_ASPECT_RATIO (m_newHeightInput->setValue (newHeight)); + } +} + +// private +void kpToolResizeScaleDialog::heightFitWidthToAspectRatio () +{ + if (m_keepAspectRatioCheckBox->isChecked () && !m_ignoreKeepAspectRatio) + { + // width / height = oldWidth / oldHeight + // width = height * oldWidth / oldHeight + const int newWidth = qRound (double (imageHeight ()) * double (originalWidth ()) + / double (originalHeight ())); + IGNORE_KEEP_ASPECT_RATIO (m_newWidthInput->setValue (newWidth)); + } +} + + +// private +bool kpToolResizeScaleDialog::resizeEnabled () const +{ + return (!actOnSelection () || + (actOnSelection () && selection ()->isText ())); +} + +// private +bool kpToolResizeScaleDialog::scaleEnabled () const +{ + return (!(actOnSelection () && selection ()->isText ())); +} + +// private +bool kpToolResizeScaleDialog::smoothScaleEnabled () const +{ + return scaleEnabled (); +} + + +// public slot +void kpToolResizeScaleDialog::slotActOnChanged () +{ +#if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1 + kdDebug () << "kpToolResizeScaleDialog::slotActOnChanged()" << endl; +#endif + + m_resizeButton->setEnabled (resizeEnabled ()); + //m_resizeLabel->setEnabled (resizeEnabled ()); + + m_scaleButton->setEnabled (scaleEnabled ()); + //m_scaleLabel->setEnabled (scaleEnabled ()); + + m_smoothScaleButton->setEnabled (smoothScaleEnabled ()); + //m_smoothScaleLabel->setEnabled (smoothScaleEnabled ()); + + + // TODO: somehow share logic with (resize|*scale)Enabled() + if (actOnSelection ()) + { + if (selection ()->isText ()) + { + m_resizeButton->setOn (true); + } + else + { + if (s_lastType == kpToolResizeScaleCommand::Scale) + m_scaleButton->setOn (true); + else + m_smoothScaleButton->setOn (true); + } + } + else + { + if (s_lastType == kpToolResizeScaleCommand::Resize) + m_resizeButton->setOn (true); + else if (s_lastType == kpToolResizeScaleCommand::Scale) + m_scaleButton->setOn (true); + else + m_smoothScaleButton->setOn (true); + } + + + m_originalWidthInput->setValue (originalWidth ()); + m_originalHeightInput->setValue (originalHeight ()); + + + m_newWidthInput->blockSignals (true); + m_newHeightInput->blockSignals (true); + + m_newWidthInput->setMinValue (actOnSelection () ? + selection ()->minimumWidth () : + 1); + m_newHeightInput->setMinValue (actOnSelection () ? + selection ()->minimumHeight () : + 1); + + m_newWidthInput->blockSignals (false); + m_newHeightInput->blockSignals (false); + + + IGNORE_KEEP_ASPECT_RATIO (slotPercentWidthChanged (m_percentWidthInput->value ())); + IGNORE_KEEP_ASPECT_RATIO (slotPercentHeightChanged (m_percentHeightInput->value ())); + + setKeepAspectRatio (m_keepAspectRatioCheckBox->isChecked ()); +} + + +// public slot +void kpToolResizeScaleDialog::slotTypeChanged () +{ + s_lastType = type (); +} + +// public slot +void kpToolResizeScaleDialog::slotWidthChanged (int width) +{ +#if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1 + kdDebug () << "kpToolResizeScaleDialog::slotWidthChanged(" + << width << ")" << endl; +#endif + const double newPercentWidth = double (width) * 100 / double (originalWidth ()); + + SET_VALUE_WITHOUT_SIGNAL_EMISSION (m_percentWidthInput, newPercentWidth); + + widthFitHeightToAspectRatio (); + + //enableButtonOK (!isNoOp ()); + s_lastPercentWidth = newPercentWidth; +} + +// public slot +void kpToolResizeScaleDialog::slotHeightChanged (int height) +{ +#if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1 + kdDebug () << "kpToolResizeScaleDialog::slotHeightChanged(" + << height << ")" << endl; +#endif + const double newPercentHeight = double (height) * 100 / double (originalHeight ()); + + SET_VALUE_WITHOUT_SIGNAL_EMISSION (m_percentHeightInput, newPercentHeight); + + heightFitWidthToAspectRatio (); + + //enableButtonOK (!isNoOp ()); + s_lastPercentHeight = newPercentHeight; +} + +// public slot +void kpToolResizeScaleDialog::slotPercentWidthChanged (double percentWidth) +{ +#if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1 + kdDebug () << "kpToolResizeScaleDialog::slotPercentWidthChanged(" + << percentWidth << ")" << endl; +#endif + + SET_VALUE_WITHOUT_SIGNAL_EMISSION (m_newWidthInput, + qRound (percentWidth * originalWidth () / 100.0)); + + widthFitHeightToAspectRatio (); + + //enableButtonOK (!isNoOp ()); + s_lastPercentWidth = percentWidth; +} + +// public slot +void kpToolResizeScaleDialog::slotPercentHeightChanged (double percentHeight) +{ +#if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1 + kdDebug () << "kpToolResizeScaleDialog::slotPercentHeightChanged(" + << percentHeight << ")" << endl; +#endif + + SET_VALUE_WITHOUT_SIGNAL_EMISSION (m_newHeightInput, + qRound (percentHeight * originalHeight () / 100.0)); + + heightFitWidthToAspectRatio (); + + //enableButtonOK (!isNoOp ()); + s_lastPercentHeight = percentHeight; +} + +// public +bool kpToolResizeScaleDialog::keepAspectRatio () const +{ + return m_keepAspectRatioCheckBox->isChecked (); +} + +// public slot +void kpToolResizeScaleDialog::setKeepAspectRatio (bool on) +{ +#if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1 + kdDebug () << "kpToolResizeScaleDialog::setKeepAspectRatio(" + << on << ")" << endl; +#endif + if (on != m_keepAspectRatioCheckBox->isChecked ()) + m_keepAspectRatioCheckBox->setChecked (on); + + if (on) + widthFitHeightToAspectRatio (); +} + +#undef IGNORE_KEEP_ASPECT_RATIO +#undef SET_VALUE_WITHOUT_SIGNAL_EMISSION + + +// private +int kpToolResizeScaleDialog::originalWidth () const +{ + return document ()->width (actOnSelection ()); +} + +// private +int kpToolResizeScaleDialog::originalHeight () const +{ + return document ()->height (actOnSelection ()); +} + + +// public +int kpToolResizeScaleDialog::imageWidth () const +{ + return m_newWidthInput->value (); +} + +// public +int kpToolResizeScaleDialog::imageHeight () const +{ + return m_newHeightInput->value (); +} + +// public +bool kpToolResizeScaleDialog::actOnSelection () const +{ + return (m_actOnCombo->currentItem () == Selection); +} + +// public +kpToolResizeScaleCommand::Type kpToolResizeScaleDialog::type () const +{ + if (m_resizeButton->isOn ()) + return kpToolResizeScaleCommand::Resize; + else if (m_scaleButton->isOn ()) + return kpToolResizeScaleCommand::Scale; + else + return kpToolResizeScaleCommand::SmoothScale; +} + +// public +bool kpToolResizeScaleDialog::isNoOp () const +{ + return (imageWidth () == originalWidth () && + imageHeight () == originalHeight ()); +} + + +// private slot virtual [base KDialogBase] +void kpToolResizeScaleDialog::slotOk () +{ + enum { eText, eSelection, eImage } actionTarget = eText; + + if (actOnSelection ()) + { + if (selection ()->isText ()) + { + actionTarget = eText; + } + else + { + actionTarget = eSelection; + } + } + else + { + actionTarget = eImage; + } + + + QString message, caption, continueButtonText; + + // Note: If eText, can't Scale nor SmoothScale. + // If eSelection, can't Resize. + + switch (type ()) + { + default: + case kpToolResizeScaleCommand::Resize: + if (actionTarget == eText) + { + message = + i18n ("

Resizing the text box to %1x%2" + " may take a substantial amount of memory." + " This can reduce system" + " responsiveness and cause other application resource" + " problems.

" + + "

Are you sure you want to resize the text box?

"); + + caption = i18n ("Resize Text Box?"); + continueButtonText = i18n ("R&esize Text Box"); + } + else if (actionTarget == eImage) + { + message = + i18n ("

Resizing the image to %1x%2" + " may take a substantial amount of memory." + " This can reduce system" + " responsiveness and cause other application resource" + " problems.

" + + "

Are you sure you want to resize the image?

"); + + caption = i18n ("Resize Image?"); + continueButtonText = i18n ("R&esize Image"); + } + + break; + + case kpToolResizeScaleCommand::Scale: + if (actionTarget == eImage) + { + message = + i18n ("

Scaling the image to %1x%2" + " may take a substantial amount of memory." + " This can reduce system" + " responsiveness and cause other application resource" + " problems.

" + + "

Are you sure you want to scale the image?

"); + + caption = i18n ("Scale Image?"); + continueButtonText = i18n ("Scal&e Image"); + } + else if (actionTarget == eSelection) + { + message = + i18n ("

Scaling the selection to %1x%2" + " may take a substantial amount of memory." + " This can reduce system" + " responsiveness and cause other application resource" + " problems.

" + + "

Are you sure you want to scale the selection?

"); + + caption = i18n ("Scale Selection?"); + continueButtonText = i18n ("Scal&e Selection"); + } + + break; + + case kpToolResizeScaleCommand::SmoothScale: + if (actionTarget == eImage) + { + message = + i18n ("

Smooth Scaling the image to %1x%2" + " may take a substantial amount of memory." + " This can reduce system" + " responsiveness and cause other application resource" + " problems.

" + + "

Are you sure you want to smooth scale the image?

"); + + caption = i18n ("Smooth Scale Image?"); + continueButtonText = i18n ("Smooth Scal&e Image"); + } + else if (actionTarget == eSelection) + { + message = + i18n ("

Smooth Scaling the selection to %1x%2" + " may take a substantial amount of memory." + " This can reduce system" + " responsiveness and cause other application resource" + " problems.

" + + "

Are you sure you want to smooth scale the selection?

"); + + caption = i18n ("Smooth Scale Selection?"); + continueButtonText = i18n ("Smooth Scal&e Selection"); + } + + break; + } + + + if (kpTool::warnIfBigImageSize (originalWidth (), + originalHeight (), + imageWidth (), imageHeight (), + message.arg (imageWidth ()).arg (imageHeight ()), + caption, + continueButtonText, + this)) + { + KDialogBase::slotOk (); + } +} + + +#include diff --git a/kolourpaint/tools/kptoolresizescale.h b/kolourpaint/tools/kptoolresizescale.h new file mode 100644 index 00000000..e23b040e --- /dev/null +++ b/kolourpaint/tools/kptoolresizescale.h @@ -0,0 +1,196 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolresizescale_h__ +#define __kptoolresizescale_h__ + +#include + +#include +#include + +#include +#include + +class QCheckBox; +class QGroupBox; +class QHBox; +class QRadioButton; +class QSize; +class QString; +class QToolButton; + +class KComboBox; +class KDoubleNumInput; +class KIntNumInput; + +class kpDocument; +class kpMainWindow; +class kpViewManager; + +class kpToolResizeScaleCommand : public kpCommand +{ +public: + enum Type + { + Resize, Scale, SmoothScale + }; + + kpToolResizeScaleCommand (bool actOnSelection, + int newWidth, int newHeight, + Type type, + kpMainWindow *mainWindow); + virtual ~kpToolResizeScaleCommand (); + + virtual QString name () const; + virtual int size () const; + +public: + int newWidth () const; + void setNewWidth (int width); + + int newHeight () const; + void setNewHeight (int height); + + QSize newSize () const; + virtual void resize (int width, int height); + +public: + bool scaleSelectionWithImage () const; + +private: + void scaleSelectionRegionWithDocument (); + +public: + virtual void execute (); + virtual void unexecute (); + +protected: + bool m_actOnSelection; + int m_newWidth, m_newHeight; + Type m_type; + bool m_isLosslessScale; + bool m_scaleSelectionWithImage; + kpColor m_backgroundColor; + + int m_oldWidth, m_oldHeight; + bool m_actOnTextSelection; + QPixmap m_oldPixmap, m_oldRightPixmap, m_oldBottomPixmap; + kpSelection *m_oldSelection; +}; + +class kpToolResizeScaleDialog : public KDialogBase +{ +Q_OBJECT + +public: + kpToolResizeScaleDialog (kpMainWindow *mainWindow); + virtual ~kpToolResizeScaleDialog (); + + enum ActOn + { + Image, Selection + }; + +private: + static kpToolResizeScaleCommand::Type s_lastType; + static double s_lastPercentWidth, s_lastPercentHeight; + +private: + kpDocument *document () const; + kpSelection *selection () const; + + void createActOnBox (QWidget *baseWidget); + void createOperationGroupBox (QWidget *baseWidget); + void createDimensionsGroupBox (QWidget *baseWidget); + + void widthFitHeightToAspectRatio (); + void heightFitWidthToAspectRatio (); + +private: + bool resizeEnabled () const; + bool scaleEnabled () const; + bool smoothScaleEnabled () const; + +public slots: + void slotActOnChanged (); + void slotTypeChanged (); + + void slotWidthChanged (int width); + void slotHeightChanged (int height); + + void slotPercentWidthChanged (double percentWidth); + void slotPercentHeightChanged (double percentHeight); + +public: + // (refers only to the state of the checkbox - user of dialog does + // not have to do extra calculations) + bool keepAspectRatio () const; +public slots: + void setKeepAspectRatio (bool on); + +private: + int originalWidth () const; + int originalHeight () const; + +public: + int imageWidth () const; + int imageHeight () const; + bool actOnSelection () const; + kpToolResizeScaleCommand::Type type () const; + + bool isNoOp () const; + +private slots: + virtual void slotOk (); + +private: + kpMainWindow *m_mainWindow; + + QHBox *m_actOnBox; + QLabel *m_actOnLabel; + KComboBox *m_actOnCombo; + + QGroupBox *m_operationGroupBox; + QToolButton *m_resizeButton, + *m_scaleButton, + *m_smoothScaleButton; + QLabel *m_resizeLabel, + *m_scaleLabel, + *m_smoothScaleLabel; + + QGroupBox *m_dimensionsGroupBox; + KIntNumInput *m_originalWidthInput, *m_originalHeightInput, + *m_newWidthInput, *m_newHeightInput; + KDoubleNumInput *m_percentWidthInput, *m_percentHeightInput; + QCheckBox *m_keepAspectRatioCheckBox; + + int m_ignoreKeepAspectRatio; +}; + +#endif // __kptoolresizescale_h__ diff --git a/kolourpaint/tools/kptoolrotate.cpp b/kolourpaint/tools/kptoolrotate.cpp new file mode 100644 index 00000000..8a37b673 --- /dev/null +++ b/kolourpaint/tools/kptoolrotate.cpp @@ -0,0 +1,500 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_TOOL_ROTATE 0 + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +kpToolRotateCommand::kpToolRotateCommand (bool actOnSelection, + double angle, + kpMainWindow *mainWindow) + : kpCommand (mainWindow), + m_actOnSelection (actOnSelection), + m_angle (angle), + m_backgroundColor (mainWindow ? mainWindow->backgroundColor (actOnSelection) : kpColor::invalid), + m_losslessRotation (kpPixmapFX::isLosslessRotation (angle)) +{ +} + +kpToolRotateCommand::~kpToolRotateCommand () +{ +} + + +// public virtual [base kpCommand] +QString kpToolRotateCommand::name () const +{ + QString opName = i18n ("Rotate"); + + if (m_actOnSelection) + return i18n ("Selection: %1").arg (opName); + else + return opName; +} + + +// public virtual [base kpCommand] +int kpToolRotateCommand::size () const +{ + return kpPixmapFX::pixmapSize (m_oldPixmap) + + m_oldSelection.size (); +} + + +// public virtual [base kpCommand] +void kpToolRotateCommand::execute () +{ + kpDocument *doc = document (); + if (!doc) + return; + + + QApplication::setOverrideCursor (Qt::waitCursor); + + + if (!m_losslessRotation) + m_oldPixmap = *doc->pixmap (m_actOnSelection); + + + QPixmap newPixmap = kpPixmapFX::rotate (*doc->pixmap (m_actOnSelection), + m_angle, + m_backgroundColor); + + + if (m_actOnSelection) + { + kpSelection *sel = doc->selection (); + + // Save old selection + m_oldSelection = *sel; + m_oldSelection.setPixmap (QPixmap ()); + + + // Calculate new top left (so selection rotates about centre) + // (the Times2 trickery is used to reduce integer division error without + // resorting to the troublesome world of floating point) + QPoint oldCenterTimes2 (sel->x () * 2 + sel->width (), + sel->y () * 2 + sel->height ()); + QPoint newTopLeftTimes2 (oldCenterTimes2 - QPoint (newPixmap.width (), newPixmap.height ())); + QPoint newTopLeft (newTopLeftTimes2.x () / 2, newTopLeftTimes2.y () / 2); + + + // Calculate rotated points + QPointArray currentPoints = sel->points (); + currentPoints.translate (-currentPoints.boundingRect ().x (), + -currentPoints.boundingRect ().y ()); + QWMatrix rotateMatrix = kpPixmapFX::rotateMatrix (*doc->pixmap (m_actOnSelection), m_angle); + currentPoints = rotateMatrix.map (currentPoints); + currentPoints.translate (-currentPoints.boundingRect ().x () + newTopLeft.x (), + -currentPoints.boundingRect ().y () + newTopLeft.y ()); + + + if (currentPoints.boundingRect ().width () == newPixmap.width () && + currentPoints.boundingRect ().height () == newPixmap.height ()) + { + doc->setSelection (kpSelection (currentPoints, newPixmap, + m_oldSelection.transparency ())); + } + else + { + // TODO: fix the latter "victim of" problem in kpSelection by + // allowing the border width & height != pixmap width & height + // Or maybe autocrop? + #if DEBUG_KP_TOOL_ROTATE + kdDebug () << "kpToolRotateCommand::execute() currentPoints.boundingRect=" + << currentPoints.boundingRect () + << " newPixmap: w=" << newPixmap.width () + << " h=" << newPixmap.height () + << " (victim of rounding error and/or rotated-a-(rectangular)-pixmap-that-was-transparent-in-the-corners-making-sel-uselessly-bigger-than-needs-be)" + << endl; + #endif + doc->setSelection (kpSelection (kpSelection::Rectangle, + QRect (newTopLeft.x (), newTopLeft.y (), + newPixmap.width (), newPixmap.height ()), + newPixmap, + m_oldSelection.transparency ())); + } + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + } + else + doc->setPixmap (newPixmap); + + + QApplication::restoreOverrideCursor (); +} + +// public virtual [base kpCommand] +void kpToolRotateCommand::unexecute () +{ + kpDocument *doc = document (); + if (!doc) + return; + + + QApplication::setOverrideCursor (Qt::waitCursor); + + + QPixmap oldPixmap; + + if (!m_losslessRotation) + { + oldPixmap = m_oldPixmap; + m_oldPixmap.resize (0, 0); + } + else + { + oldPixmap = kpPixmapFX::rotate (*doc->pixmap (m_actOnSelection), + 360 - m_angle, + m_backgroundColor); + } + + + if (!m_actOnSelection) + doc->setPixmap (oldPixmap); + else + { + kpSelection oldSelection = m_oldSelection; + oldSelection.setPixmap (oldPixmap); + doc->setSelection (oldSelection); + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + } + + + QApplication::restoreOverrideCursor (); +} + + +/* + * kpToolRotateDialog + */ + + +// private static +int kpToolRotateDialog::s_lastWidth = -1, + kpToolRotateDialog::s_lastHeight = -1; + +// private static +bool kpToolRotateDialog::s_lastIsClockwise = true; +int kpToolRotateDialog::s_lastAngleRadioButtonID = 3; +int kpToolRotateDialog::s_lastAngleCustom = 0; + + +kpToolRotateDialog::kpToolRotateDialog (bool actOnSelection, + kpMainWindow *mainWindow, + const char *name) + : kpToolPreviewDialog (kpToolPreviewDialog::AllFeatures, + false/*don't reserve top row*/, + actOnSelection ? i18n ("Rotate Selection") : i18n ("Rotate Image"), + i18n ("After Rotate:"), + actOnSelection, mainWindow, name) +{ + // Too confusing - disable for now + s_lastAngleRadioButtonID = 3; + s_lastAngleCustom = 0; + + + createDirectionGroupBox (); + createAngleGroupBox (); + + + if (s_lastWidth > 0 && s_lastHeight > 0) + resize (s_lastWidth, s_lastHeight); + + + slotAngleCustomRadioButtonToggled (m_angleCustomRadioButton->isChecked ()); + slotUpdate (); +} + +kpToolRotateDialog::~kpToolRotateDialog () +{ + s_lastWidth = width (), s_lastHeight = height (); +} + + +// private +void kpToolRotateDialog::createDirectionGroupBox () +{ + QGroupBox *directionGroupBox = new QGroupBox (i18n ("Direction"), mainWidget ()); + addCustomWidget (directionGroupBox); + + + QLabel *antiClockwisePixmapLabel = new QLabel (directionGroupBox); + antiClockwisePixmapLabel->setPixmap (UserIcon ("image_rotate_anticlockwise")); + + QLabel *clockwisePixmapLabel = new QLabel (directionGroupBox); + clockwisePixmapLabel->setPixmap (UserIcon ("image_rotate_clockwise")); + + + m_antiClockwiseRadioButton = new QRadioButton (i18n ("Cou&nterclockwise"), directionGroupBox); + m_clockwiseRadioButton = new QRadioButton (i18n ("C&lockwise"), directionGroupBox); + + + m_antiClockwiseRadioButton->setChecked (!s_lastIsClockwise); + m_clockwiseRadioButton->setChecked (s_lastIsClockwise); + + + QButtonGroup *buttonGroup = new QButtonGroup (directionGroupBox); + buttonGroup->hide (); + + buttonGroup->insert (m_antiClockwiseRadioButton); + buttonGroup->insert (m_clockwiseRadioButton); + + + QGridLayout *directionLayout = new QGridLayout (directionGroupBox, + 2, 2, marginHint () * 2, spacingHint ()); + directionLayout->addWidget (antiClockwisePixmapLabel, 0, 0, Qt::AlignCenter); + directionLayout->addWidget (clockwisePixmapLabel, 0, 1, Qt::AlignCenter); + directionLayout->addWidget (m_antiClockwiseRadioButton, 1, 0, Qt::AlignCenter); + directionLayout->addWidget (m_clockwiseRadioButton, 1, 1, Qt::AlignCenter); + + + connect (m_antiClockwiseRadioButton, SIGNAL (toggled (bool)), + this, SLOT (slotUpdate ())); + connect (m_clockwiseRadioButton, SIGNAL (toggled (bool)), + this, SLOT (slotUpdate ())); +} + +// private +void kpToolRotateDialog::createAngleGroupBox () +{ + QGroupBox *angleGroupBox = new QGroupBox (i18n ("Angle"), mainWidget ()); + addCustomWidget (angleGroupBox); + + + m_angle90RadioButton = new QRadioButton (i18n ("90 °rees"), angleGroupBox); + m_angle180RadioButton = new QRadioButton (i18n ("180 d&egrees"), angleGroupBox); + m_angle270RadioButton = new QRadioButton (i18n ("270 de&grees"), angleGroupBox); + + m_angleCustomRadioButton = new QRadioButton (i18n ("C&ustom:"), angleGroupBox); + m_angleCustomInput = new KIntNumInput (s_lastAngleCustom, angleGroupBox); + m_angleCustomInput->setMinValue (-359); + m_angleCustomInput->setMaxValue (+359); + QLabel *degreesLabel = new QLabel (i18n ("degrees"), angleGroupBox); + + + m_angleButtonGroup = new QButtonGroup (angleGroupBox); + m_angleButtonGroup->hide (); + + m_angleButtonGroup->insert (m_angle90RadioButton); + m_angleButtonGroup->insert (m_angle180RadioButton); + m_angleButtonGroup->insert (m_angle270RadioButton); + + m_angleButtonGroup->insert (m_angleCustomRadioButton); + + m_angleButtonGroup->setButton (s_lastAngleRadioButtonID); + + + QGridLayout *angleLayout = new QGridLayout (angleGroupBox, + 6, 3, + marginHint () * 2, spacingHint ()); + + angleLayout->addMultiCellWidget (m_angle90RadioButton, 0, 0, 0, 2); + angleLayout->addMultiCellWidget (m_angle180RadioButton, 1, 1, 0, 2); + angleLayout->addMultiCellWidget (m_angle270RadioButton, 2, 2, 0, 2); + + angleLayout->addWidget (m_angleCustomRadioButton, 3, 0); + angleLayout->addWidget (m_angleCustomInput, 3, 1); + angleLayout->addWidget (degreesLabel, 3, 2); + + angleLayout->setColStretch (1, 2); // Stretch Custom Angle Input + + + connect (m_angle90RadioButton, SIGNAL (toggled (bool)), + this, SLOT (slotUpdate ())); + connect (m_angle180RadioButton, SIGNAL (toggled (bool)), + this, SLOT (slotUpdate ())); + connect (m_angle270RadioButton, SIGNAL (toggled (bool)), + this, SLOT (slotUpdate ())); + + connect (m_angleCustomRadioButton, SIGNAL (toggled (bool)), + this, SLOT (slotAngleCustomRadioButtonToggled (bool))); + connect (m_angleCustomRadioButton, SIGNAL (toggled (bool)), + this, SLOT (slotUpdate ())); + + connect (m_angleCustomInput, SIGNAL (valueChanged (int)), + this, SLOT (slotUpdate ())); +} + + +// public virtual [base kpToolPreviewDialog] +bool kpToolRotateDialog::isNoOp () const +{ + return (angle () == 0); +} + +// public +int kpToolRotateDialog::angle () const +{ + int retAngle; + + + if (m_angle90RadioButton->isChecked ()) + retAngle = 90; + else if (m_angle180RadioButton->isChecked ()) + retAngle = 180; + else if (m_angle270RadioButton->isChecked ()) + retAngle = 270; + else // if (m_angleCustomRadioButton->isChecked ()) + retAngle = m_angleCustomInput->value (); + + + if (m_antiClockwiseRadioButton->isChecked ()) + retAngle *= -1; + + + if (retAngle < 0) + retAngle += ((0 - retAngle) / 360 + 1) * 360; + + if (retAngle >= 360) + retAngle -= ((retAngle - 360) / 360 + 1) * 360; + + + return retAngle; +} + + +// private virtual [base kpToolPreviewDialog] +QSize kpToolRotateDialog::newDimensions () const +{ + QWMatrix matrix = kpPixmapFX::rotateMatrix (m_oldWidth, m_oldHeight, angle ()); + // TODO: Should we be using QWMatrix::Areas? + QRect rect = matrix.map (QRect (0, 0, m_oldWidth, m_oldHeight)); + return rect.size (); +} + +// private virtual [base kpToolPreviewDialog] +QPixmap kpToolRotateDialog::transformPixmap (const QPixmap &pixmap, + int targetWidth, int targetHeight) const +{ + return kpPixmapFX::rotate (pixmap, angle (), + m_mainWindow ? m_mainWindow->backgroundColor (m_actOnSelection) : kpColor::invalid, + targetWidth, targetHeight); +} + + +// private slot +void kpToolRotateDialog::slotAngleCustomRadioButtonToggled (bool isChecked) +{ + m_angleCustomInput->setEnabled (isChecked); + + if (isChecked) + m_angleCustomInput->setEditFocus (); +} + +// private slot virtual [base kpToolPreviewDialog] +void kpToolRotateDialog::slotUpdate () +{ + s_lastIsClockwise = m_clockwiseRadioButton->isChecked (); + s_lastAngleRadioButtonID = m_angleButtonGroup->selectedId (); + s_lastAngleCustom = m_angleCustomInput->value (); + + kpToolPreviewDialog::slotUpdate (); +} + + +// private slot virtual [base KDialogBase] +void kpToolRotateDialog::slotOk () +{ + QString message, caption, continueButtonText; + + if (document ()->selection ()) + { + if (!document ()->selection ()->isText ()) + { + message = + i18n ("

Rotating the selection to %1x%2" + " may take a substantial amount of memory." + " This can reduce system" + " responsiveness and cause other application resource" + " problems.

" + + "

Are you sure want to rotate the selection?

"); + + caption = i18n ("Rotate Selection?"); + continueButtonText = i18n ("Rotat&e Selection"); + } + } + else + { + message = + i18n ("

Rotating the image to %1x%2" + " may take a substantial amount of memory." + " This can reduce system" + " responsiveness and cause other application resource" + " problems.

" + + "

Are you sure want to rotate the image?

"); + + caption = i18n ("Rotate Image?"); + continueButtonText = i18n ("Rotat&e Image"); + } + + + const int newWidth = newDimensions ().width (); + const int newHeight = newDimensions ().height (); + + if (kpTool::warnIfBigImageSize (m_oldWidth, + m_oldHeight, + newWidth, newHeight, + message.arg (newWidth).arg (newHeight), + caption, + continueButtonText, + this)) + { + KDialogBase::slotOk (); + } +} + +#include diff --git a/kolourpaint/tools/kptoolrotate.h b/kolourpaint/tools/kptoolrotate.h new file mode 100644 index 00000000..887473dc --- /dev/null +++ b/kolourpaint/tools/kptoolrotate.h @@ -0,0 +1,129 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolrotate_h__ +#define __kptoolrotate_h__ + +#include +#include + +#include + +#include +#include +#include +#include + + +class QButtonGroup; +class QRadioButton; +class QString; + +class KIntNumInput; + +class kpDocument; +class kpViewManager; +class kpMainWindow; + + +class kpToolRotateCommand : public kpCommand +{ +public: + kpToolRotateCommand (bool actOnSelection, + double angle, // 0 <= angle < 360 (clockwise) + kpMainWindow *mainWindow); + virtual ~kpToolRotateCommand (); + + virtual QString name () const; + + virtual int size () const; + + virtual void execute (); + virtual void unexecute (); + +private: + bool m_actOnSelection; + double m_angle; + + kpColor m_backgroundColor; + + bool m_losslessRotation; + QPixmap m_oldPixmap; + kpSelection m_oldSelection; +}; + + +class kpToolRotateDialog : public kpToolPreviewDialog +{ +Q_OBJECT + +public: + kpToolRotateDialog (bool actOnSelection, + kpMainWindow *parent, + const char *name = 0); + virtual ~kpToolRotateDialog (); + +private: + static int s_lastWidth, s_lastHeight; + static bool s_lastIsClockwise; + static int s_lastAngleRadioButtonID; + static int s_lastAngleCustom; + + void createDirectionGroupBox (); + void createAngleGroupBox (); + +public: + virtual bool isNoOp () const; + int angle () const; // 0 <= angle < 360 (clockwise); + +private: + virtual QSize newDimensions () const; + virtual QPixmap transformPixmap (const QPixmap &pixmap, + int targetWidth, int targetHeight) const; + +private slots: + void slotAngleCustomRadioButtonToggled (bool isChecked); + virtual void slotUpdate (); + +private slots: + virtual void slotOk (); + +private: + QRadioButton *m_antiClockwiseRadioButton, + *m_clockwiseRadioButton; + + QButtonGroup *m_angleButtonGroup; + QRadioButton *m_angle90RadioButton, + *m_angle180RadioButton, + *m_angle270RadioButton, + *m_angleCustomRadioButton; + KIntNumInput *m_angleCustomInput; +}; + + +#endif // __kptoolrotate_h__ diff --git a/kolourpaint/tools/kptoolroundedrectangle.cpp b/kolourpaint/tools/kptoolroundedrectangle.cpp new file mode 100644 index 00000000..b0f4ba05 --- /dev/null +++ b/kolourpaint/tools/kptoolroundedrectangle.cpp @@ -0,0 +1,45 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include + +kpToolRoundedRectangle::kpToolRoundedRectangle (kpMainWindow *mainWindow) + : kpToolRectangle (RoundedRectangle, + i18n ("Rounded Rectangle"), + i18n ("Draws rectangles and squares with rounded corners"), + Qt::Key_U, + mainWindow, "tool_rounded_rectangle") +{ +} + +kpToolRoundedRectangle::~kpToolRoundedRectangle () +{ +} + +#include diff --git a/kolourpaint/tools/kptoolroundedrectangle.h b/kolourpaint/tools/kptoolroundedrectangle.h new file mode 100644 index 00000000..924c1b34 --- /dev/null +++ b/kolourpaint/tools/kptoolroundedrectangle.h @@ -0,0 +1,45 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptoolroundedrectangle_h__ +#define __kptoolroundedrectangle_h__ + +#include + +class kpMainWindow; + +class kpToolRoundedRectangle : public kpToolRectangle +{ +Q_OBJECT + +public: + kpToolRoundedRectangle (kpMainWindow *); + virtual ~kpToolRoundedRectangle (); +}; + +#endif // __kptoolroundedrectangle_h__ diff --git a/kolourpaint/tools/kptoolselection.cpp b/kolourpaint/tools/kptoolselection.cpp new file mode 100644 index 00000000..f664f01b --- /dev/null +++ b/kolourpaint/tools/kptoolselection.cpp @@ -0,0 +1,2371 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_TOOL_SELECTION 0 + + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +kpToolSelection::kpToolSelection (Mode mode, + const QString &text, + const QString &description, + int key, + kpMainWindow *mainWindow, + const char *name) + : kpTool (text, description, key, mainWindow, name), + m_mode (mode), + m_currentPullFromDocumentCommand (0), + m_currentMoveCommand (0), + m_currentResizeScaleCommand (0), + m_toolWidgetOpaqueOrTransparent (0), + m_currentCreateTextCommand (0), + m_createNOPTimer (new QTimer (this)), + m_RMBMoveUpdateGUITimer (new QTimer (this)) +{ + connect (m_createNOPTimer, SIGNAL (timeout ()), + this, SLOT (delayedDraw ())); + connect (m_RMBMoveUpdateGUITimer, SIGNAL (timeout ()), + this, SLOT (slotRMBMoveUpdateGUI ())); +} + +kpToolSelection::~kpToolSelection () +{ +} + + +// private +void kpToolSelection::pushOntoDocument () +{ +#if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "kpToolSelection::pushOntoDocument() CALLED" << endl; +#endif + mainWindow ()->slotDeselect (); +} + + +// protected +bool kpToolSelection::onSelectionToMove () const +{ + kpView *v = viewManager ()->viewUnderCursor (); + if (!v) + return 0; + + return v->mouseOnSelectionToMove (m_currentViewPoint); +} + +// protected +int kpToolSelection::onSelectionResizeHandle () const +{ + kpView *v = viewManager ()->viewUnderCursor (); + if (!v) + return 0; + + return v->mouseOnSelectionResizeHandle (m_currentViewPoint); +} + +// protected +bool kpToolSelection::onSelectionToSelectText () const +{ + kpView *v = viewManager ()->viewUnderCursor (); + if (!v) + return 0; + + return v->mouseOnSelectionToSelectText (m_currentViewPoint); +} + + +// public +QString kpToolSelection::haventBegunDrawUserMessage () const +{ +#if DEBUG_KP_TOOL_SELECTION && 0 + kdDebug () << "kpToolSelection::haventBegunDrawUserMessage()" + " cancelledShapeButStillHoldingButtons=" + << m_cancelledShapeButStillHoldingButtons + << endl; +#endif + + if (m_cancelledShapeButStillHoldingButtons) + return i18n ("Let go of all the mouse buttons."); + + kpSelection *sel = document ()->selection (); + if (sel && onSelectionResizeHandle () && !controlOrShiftPressed ()) + { + if (m_mode == Text) + return i18n ("Left drag to resize text box."); + else + return i18n ("Left drag to scale selection."); + } + else if (sel && sel->contains (m_currentPoint)) + { + if (m_mode == Text) + { + if (onSelectionToSelectText () && !controlOrShiftPressed ()) + return i18n ("Left click to change cursor position."); + else + return i18n ("Left drag to move text box."); + } + else + { + return i18n ("Left drag to move selection."); + } + } + else + { + if (m_mode == Text) + return i18n ("Left drag to create text box."); + else + return i18n ("Left drag to create selection."); + } +} + + +// virtual +void kpToolSelection::begin () +{ +#if DEBUG_KP_TOOL_SELECTION + kdDebug () << "kpToolSelection::begin()" << endl; +#endif + + kpToolToolBar *tb = toolToolBar (); + + if (tb) + { + m_toolWidgetOpaqueOrTransparent = tb->toolWidgetOpaqueOrTransparent (); + + if (m_toolWidgetOpaqueOrTransparent) + { + connect (m_toolWidgetOpaqueOrTransparent, SIGNAL (isOpaqueChanged (bool)), + this, SLOT (slotIsOpaqueChanged ())); + m_toolWidgetOpaqueOrTransparent->show (); + } + } + else + { + m_toolWidgetOpaqueOrTransparent = 0; + } + + viewManager ()->setQueueUpdates (); + { + viewManager ()->setSelectionBorderVisible (true); + viewManager ()->setSelectionBorderFinished (true); + } + viewManager ()->restoreQueueUpdates (); + + m_startDragFromSelectionTopLeft = QPoint (); + m_dragType = Unknown; + m_dragHasBegun = false; + m_hadSelectionBeforeDrag = false; // arbitrary + m_resizeScaleType = 0; + + m_currentPullFromDocumentCommand = 0; + m_currentMoveCommand = 0; + m_currentResizeScaleCommand = 0; + m_currentCreateTextCommand = 0; + + m_cancelledShapeButStillHoldingButtons = false; + + setUserMessage (haventBegunDrawUserMessage ()); +} + +// virtual +void kpToolSelection::end () +{ +#if DEBUG_KP_TOOL_SELECTION + kdDebug () << "kpToolSelection::end()" << endl; +#endif + + if (document ()->selection ()) + pushOntoDocument (); + + if (m_toolWidgetOpaqueOrTransparent) + { + disconnect (m_toolWidgetOpaqueOrTransparent, SIGNAL (isOpaqueChanged (bool)), + this, SLOT (slotIsOpaqueChanged ())); + m_toolWidgetOpaqueOrTransparent = 0; + } + + viewManager ()->unsetCursor (); +} + +// virtual +void kpToolSelection::reselect () +{ +#if DEBUG_KP_TOOL_SELECTION + kdDebug () << "kpToolSelection::reselect()" << endl; +#endif + + if (document ()->selection ()) + pushOntoDocument (); +} + + +// virtual +void kpToolSelection::beginDraw () +{ +#if DEBUG_KP_TOOL_SELECTION + kdDebug () << "kpToolSelection::beginDraw() m_startPoint=" + << m_startPoint + << " QCursor::pos() view startPoint=" + << m_viewUnderStartPoint->mapFromGlobal (QCursor::pos ()) + << endl; +#endif + + m_createNOPTimer->stop (); + m_RMBMoveUpdateGUITimer->stop (); + + + // In case the cursor was wrong to start with + // (forgot to call kpTool::somethingBelowTheCursorChanged()), + // make sure it is correct during this operation. + hover (m_currentPoint); + + // Currently used only to end the current text + if (hasBegunShape ()) + endShape (m_currentPoint, QRect (m_startPoint/* TODO: wrong */, m_currentPoint).normalize ()); + + m_dragType = Create; + m_dragHasBegun = false; + + kpSelection *sel = document ()->selection (); + m_hadSelectionBeforeDrag = bool (sel); + + if (sel) + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\thas sel region rect=" << sel->boundingRect () << endl; + #endif + QRect selectionRect = sel->boundingRect (); + + if (onSelectionResizeHandle () && !controlOrShiftPressed ()) + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\t\tis resize/scale" << endl; + #endif + + m_startDragFromSelectionTopLeft = m_currentPoint - selectionRect.topLeft (); + m_dragType = ResizeScale; + m_resizeScaleType = onSelectionResizeHandle (); + + viewManager ()->setQueueUpdates (); + { + viewManager ()->setSelectionBorderVisible (true); + viewManager ()->setSelectionBorderFinished (true); + viewManager ()->setTextCursorEnabled (false); + } + viewManager ()->restoreQueueUpdates (); + } + else if (sel->contains (m_currentPoint)) + { + if (m_mode == Text && onSelectionToSelectText () && !controlOrShiftPressed ()) + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\t\tis select cursor pos" << endl; + #endif + + m_dragType = SelectText; + + viewManager ()->setTextCursorPosition (sel->textRowForPoint (m_currentPoint), + sel->textColForPoint (m_currentPoint)); + } + else + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\t\tis move" << endl; + #endif + + m_startDragFromSelectionTopLeft = m_currentPoint - selectionRect.topLeft (); + m_dragType = Move; + + if (m_mouseButton == 0) + { + setSelectionBorderForMove (); + } + else + { + // Don't hide sel border momentarily if user is just + // right _clicking_ selection + m_RMBMoveUpdateGUITimer->start (100, true/*single shot*/); + } + } + } + else + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\t\tis new sel" << endl; + #endif + + pushOntoDocument (); + } + } + + // creating new selection? + if (m_dragType == Create) + { + viewManager ()->setQueueUpdates (); + { + viewManager ()->setSelectionBorderVisible (true); + viewManager ()->setSelectionBorderFinished (false); + viewManager ()->setTextCursorEnabled (false); + } + viewManager ()->restoreQueueUpdates (); + + m_createNOPTimer->start (200, true/*single shot*/); + } + + if (m_dragType != SelectText) + { + setUserMessage (cancelUserMessage ()); + } +} + + +// protected +const QCursor &kpToolSelection::cursor () const +{ +#if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "kpToolSelection::cursor()" + << " m_currentPoint=" << m_currentPoint + << " QCursor::pos() view under cursor=" + << (viewUnderCursor () ? + viewUnderCursor ()->mapFromGlobal (QCursor::pos ()) : + KP_INVALID_POINT) + << " controlOrShiftPressed=" << controlOrShiftPressed () + << endl; +#endif + + kpSelection *sel = document () ? document ()->selection () : 0; + + if (sel && onSelectionResizeHandle () && !controlOrShiftPressed ()) + { + #if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "\tonSelectionResizeHandle=" + << onSelectionResizeHandle () << endl; + #endif + switch (onSelectionResizeHandle ()) + { + case (kpView::Top | kpView::Left): + case (kpView::Bottom | kpView::Right): + return Qt::sizeFDiagCursor; + + case (kpView::Bottom | kpView::Left): + case (kpView::Top | kpView::Right): + return Qt::sizeBDiagCursor; + + case kpView::Top: + case kpView::Bottom: + return Qt::sizeVerCursor; + + case kpView::Left: + case kpView::Right: + return Qt::sizeHorCursor; + } + + return Qt::arrowCursor; + } + else if (sel && sel->contains (m_currentPoint)) + { + #if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "\tsel contains currentPoint; selecting text? " + << onSelectionToSelectText () << endl; + #endif + + if (m_mode == Text && onSelectionToSelectText () && !controlOrShiftPressed ()) + return Qt::ibeamCursor; + else + return Qt::sizeAllCursor; + } + else + { + #if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "\tnot on sel" << endl; + #endif + return Qt::crossCursor; + } +} + +// virtual +void kpToolSelection::hover (const QPoint &point) +{ +#if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "kpToolSelection::hover" << point << endl; +#endif + + viewManager ()->setCursor (cursor ()); + + setUserShapePoints (point, KP_INVALID_POINT, false/*don't set size*/); + if (document () && document ()->selection ()) + { + setUserShapeSize (document ()->selection ()->width (), + document ()->selection ()->height ()); + } + else + { + setUserShapeSize (KP_INVALID_SIZE); + } + + QString mess = haventBegunDrawUserMessage (); + if (mess != userMessage ()) + setUserMessage (mess); +} + +// protected +void kpToolSelection::popupRMBMenu () +{ + QPopupMenu *pop = mainWindow () ? mainWindow ()->selectionToolRMBMenu () : 0; + if (!pop) + return; + + // WARNING: enters event loop - may re-enter view/tool event handlers + pop->exec (QCursor::pos ()); + + // Cursor may have moved while menu up, triggering mouseMoveEvents + // for the menu - not the view. Update cursor position now. + somethingBelowTheCursorChanged (); +} + +// protected +void kpToolSelection::setSelectionBorderForMove () +{ + // don't show border while moving + viewManager ()->setQueueUpdates (); + { + viewManager ()->setSelectionBorderVisible (false); + viewManager ()->setSelectionBorderFinished (true); + viewManager ()->setTextCursorEnabled (false); + } + viewManager ()->restoreQueueUpdates (); +} + +// protected slot +void kpToolSelection::slotRMBMoveUpdateGUI () +{ + // (just in case not called from single shot) + m_RMBMoveUpdateGUITimer->stop (); + + setSelectionBorderForMove (); + + kpSelection * const sel = document () ? document ()->selection () : 0; + if (sel) + setUserShapePoints (sel->topLeft ()); +} + +// protected slot +void kpToolSelection::delayedDraw () +{ +#if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "kpToolSelection::delayedDraw() hasBegunDraw=" + << hasBegunDraw () + << " currentPoint=" << m_currentPoint + << " lastPoint=" << m_lastPoint + << " startPoint=" << m_startPoint + << endl; +#endif + + // (just in case not called from single shot) + m_createNOPTimer->stop (); + + if (hasBegunDraw ()) + { + draw (m_currentPoint, m_lastPoint, + QRect (m_startPoint, m_currentPoint).normalize ()); + } +} + +// virtual +void kpToolSelection::draw (const QPoint &inThisPoint, const QPoint & /*lastPoint*/, + const QRect &inNormalizedRect) +{ + QPoint thisPoint = inThisPoint; + QRect normalizedRect = inNormalizedRect; + +#if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "kpToolSelection::draw" << thisPoint + << " startPoint=" << m_startPoint + << " normalizedRect=" << normalizedRect << endl; +#endif + + + // OPT: return when thisPoint == m_lastPoint so that e.g. when creating + // Points sel, press modifiers doesn't add multiple points in same + // place + + + bool nextDragHasBegun = true; + + + if (m_dragType == Create) + { + #if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "\tnot moving - resizing rect to" << normalizedRect + << endl; + kdDebug () << "\t\tcreateNOPTimer->isActive()=" + << m_createNOPTimer->isActive () + << " viewManhattanLength from startPoint=" + << m_viewUnderStartPoint->transformDocToViewX ((thisPoint - m_startPoint).manhattanLength ()) + << endl; + #endif + + if (m_createNOPTimer->isActive ()) + { + if (m_viewUnderStartPoint->transformDocToViewX ((thisPoint - m_startPoint).manhattanLength ()) <= 6) + { + #if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "\t\tsuppress accidental movement" << endl; + #endif + thisPoint = m_startPoint; + } + else + { + #if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "\t\tit's a \"big\" intended move - stop timer" << endl; + #endif + m_createNOPTimer->stop (); + } + } + + + // Prevent unintentional 1-pixel selections + if (!m_dragHasBegun && thisPoint == m_startPoint) + { + if (m_mode != kpToolSelection::Text) + { + #if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "\tnon-text NOP - return" << endl; + #endif + setUserShapePoints (thisPoint); + return; + } + else // m_mode == kpToolSelection::Text + { + // Attempt to deselect text box by clicking? + if (m_hadSelectionBeforeDrag) + { + #if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "\ttext box deselect - NOP - return" << endl; + #endif + setUserShapePoints (thisPoint); + return; + } + + // Drag-wise, this is a NOP so we'd normally return (hence + // m_dragHasBegun would not change). However, as a special + // case, allow user to create a text box using a single + // click. But don't set m_dragHasBegun for next iteration + // since it would be untrue. + // + // This makes sure that a single click creation of text box + // works even if draw() is invoked more than once at the + // same position (esp. with accidental drag suppression + // (above)). + nextDragHasBegun = false; + } + } + + + switch (m_mode) + { + case kpToolSelection::Rectangle: + { + const QRect usefulRect = normalizedRect.intersect (document ()->rect ()); + document ()->setSelection (kpSelection (kpSelection::Rectangle, usefulRect, + mainWindow ()->selectionTransparency ())); + + setUserShapePoints (m_startPoint, + QPoint (QMAX (0, QMIN (m_currentPoint.x (), document ()->width () - 1)), + QMAX (0, QMIN (m_currentPoint.y (), document ()->height () - 1)))); + break; + } + case kpToolSelection::Text: + { + const kpTextStyle textStyle = mainWindow ()->textStyle (); + + int minimumWidth, minimumHeight; + + // Just a click? + if (!m_dragHasBegun && thisPoint == m_startPoint) + { + #if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "\tclick creating text box" << endl; + #endif + + // (Click creating text box with RMB would not be obvious + // since RMB menu most likely hides text box immediately + // afterwards) + if (m_mouseButton == 1) + break; + + + minimumWidth = kpSelection::preferredMinimumWidthForTextStyle (textStyle); + if (thisPoint.x () >= m_startPoint.x ()) + { + if (m_startPoint.x () + minimumWidth - 1 >= document ()->width ()) + { + minimumWidth = QMAX (kpSelection::minimumWidthForTextStyle (textStyle), + document ()->width () - m_startPoint.x ()); + } + } + else + { + if (m_startPoint.x () - minimumWidth + 1 < 0) + { + minimumWidth = QMAX (kpSelection::minimumWidthForTextStyle (textStyle), + m_startPoint.x () + 1); + } + } + + minimumHeight = kpSelection::preferredMinimumHeightForTextStyle (textStyle); + if (thisPoint.y () >= m_startPoint.y ()) + { + if (m_startPoint.y () + minimumHeight - 1 >= document ()->height ()) + { + minimumHeight = QMAX (kpSelection::minimumHeightForTextStyle (textStyle), + document ()->height () - m_startPoint.y ()); + } + } + else + { + if (m_startPoint.y () - minimumHeight + 1 < 0) + { + minimumHeight = QMAX (kpSelection::minimumHeightForTextStyle (textStyle), + m_startPoint.y () + 1); + } + } + } + else + { + #if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "\tdrag creating text box" << endl; + #endif + minimumWidth = kpSelection::minimumWidthForTextStyle (textStyle); + minimumHeight = kpSelection::minimumHeightForTextStyle (textStyle); + } + + + if (normalizedRect.width () < minimumWidth) + { + if (thisPoint.x () >= m_startPoint.x ()) + normalizedRect.setWidth (minimumWidth); + else + normalizedRect.setX (normalizedRect.right () - minimumWidth + 1); + } + + if (normalizedRect.height () < minimumHeight) + { + if (thisPoint.y () >= m_startPoint.y ()) + normalizedRect.setHeight (minimumHeight); + else + normalizedRect.setY (normalizedRect.bottom () - minimumHeight + 1); + } + #if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "\t\tnormalizedRect=" << normalizedRect + << " kpSelection::preferredMinimumSize=" + << QSize (minimumWidth, minimumHeight) + << endl; + #endif + + QValueVector textLines (1, QString ()); + kpSelection sel (normalizedRect, textLines, textStyle); + + if (!m_currentCreateTextCommand) + { + m_currentCreateTextCommand = new kpToolSelectionCreateCommand ( + i18n ("Text: Create Box"), + sel, + mainWindow ()); + } + else + m_currentCreateTextCommand->setFromSelection (sel); + + viewManager ()->setTextCursorPosition (0, 0); + document ()->setSelection (sel); + + QPoint actualEndPoint = KP_INVALID_POINT; + if (m_startPoint == normalizedRect.topLeft ()) + actualEndPoint = normalizedRect.bottomRight (); + else if (m_startPoint == normalizedRect.bottomRight ()) + actualEndPoint = normalizedRect.topLeft (); + else if (m_startPoint == normalizedRect.topRight ()) + actualEndPoint = normalizedRect.bottomLeft (); + else if (m_startPoint == normalizedRect.bottomLeft ()) + actualEndPoint = normalizedRect.topRight (); + + setUserShapePoints (m_startPoint, actualEndPoint); + break; + } + case kpToolSelection::Ellipse: + document ()->setSelection (kpSelection (kpSelection::Ellipse, normalizedRect, + mainWindow ()->selectionTransparency ())); + setUserShapePoints (m_startPoint, m_currentPoint); + break; + case kpToolSelection::FreeForm: + QPointArray points; + + if (document ()->selection ()) + points = document ()->selection ()->points (); + + + // (not detached so will modify "points" directly but + // still need to call kpDocument::setSelection() to + // update screen) + + if (!m_dragHasBegun) + { + // We thought the drag at startPoint was a NOP + // but it turns out that it wasn't... + points.putPoints (points.count (), 1, m_startPoint.x (), m_startPoint.y ()); + } + + // TODO: there should be an upper limit on this before drawing the + // polygon becomes too slow + points.putPoints (points.count (), 1, thisPoint.x (), thisPoint.y ()); + + + document ()->setSelection (kpSelection (points, mainWindow ()->selectionTransparency ())); + #if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "\t\tfreeform; #points=" << document ()->selection ()->points ().count () << endl; + #endif + + setUserShapePoints (m_currentPoint); + break; + } + + viewManager ()->setSelectionBorderVisible (true); + } + else if (m_dragType == Move) + { + #if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "\tmoving selection" << endl; + #endif + + kpSelection *sel = document ()->selection (); + + QRect targetSelRect = QRect (thisPoint.x () - m_startDragFromSelectionTopLeft.x (), + thisPoint.y () - m_startDragFromSelectionTopLeft.y (), + sel->width (), + sel->height ()); + + #if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "\t\tstartPoint=" << m_startPoint + << " thisPoint=" << thisPoint + << " startDragFromSel=" << m_startDragFromSelectionTopLeft + << " targetSelRect=" << targetSelRect + << endl; + #endif + + // Try to make sure selection still intersects document so that it's + // reachable. + + if (targetSelRect.right () < 0) + targetSelRect.moveBy (-targetSelRect.right (), 0); + else if (targetSelRect.left () >= document ()->width ()) + targetSelRect.moveBy (document ()->width () - targetSelRect.left () - 1, 0); + + if (targetSelRect.bottom () < 0) + targetSelRect.moveBy (0, -targetSelRect.bottom ()); + else if (targetSelRect.top () >= document ()->height ()) + targetSelRect.moveBy (0, document ()->height () - targetSelRect.top () - 1); + + #if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "\t\t\tafter ensure sel rect clickable=" << targetSelRect << endl; + #endif + + + if (!m_dragHasBegun && + targetSelRect.topLeft () + m_startDragFromSelectionTopLeft == m_startPoint) + { + #if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "\t\t\t\tnop" << endl; + #endif + + + if (!m_RMBMoveUpdateGUITimer->isActive ()) + { + // (slotRMBMoveUpdateGUI() calls similar line) + setUserShapePoints (sel->topLeft ()); + } + + // Prevent both NOP drag-moves + return; + } + + + if (m_RMBMoveUpdateGUITimer->isActive ()) + { + m_RMBMoveUpdateGUITimer->stop (); + slotRMBMoveUpdateGUI (); + } + + + if (!sel->pixmap () && !m_currentPullFromDocumentCommand) + { + m_currentPullFromDocumentCommand = new kpToolSelectionPullFromDocumentCommand ( + QString::null/*uninteresting child of macro cmd*/, + mainWindow ()); + m_currentPullFromDocumentCommand->execute (); + } + + if (!m_currentMoveCommand) + { + m_currentMoveCommand = new kpToolSelectionMoveCommand ( + QString::null/*uninteresting child of macro cmd*/, + mainWindow ()); + m_currentMoveCommandIsSmear = false; + } + + + //viewManager ()->setQueueUpdates (); + //viewManager ()->setFastUpdates (); + + if (m_shiftPressed) + m_currentMoveCommandIsSmear = true; + + if (!m_dragHasBegun && (m_controlPressed || m_shiftPressed)) + m_currentMoveCommand->copyOntoDocument (); + + m_currentMoveCommand->moveTo (targetSelRect.topLeft ()); + + if (m_shiftPressed) + m_currentMoveCommand->copyOntoDocument (); + + //viewManager ()->restoreFastUpdates (); + //viewManager ()->restoreQueueUpdates (); + + QPoint start = m_currentMoveCommand->originalSelection ().topLeft (); + QPoint end = targetSelRect.topLeft (); + setUserShapePoints (start, end, false/*don't set size*/); + setUserShapeSize (end.x () - start.x (), end.y () - start.y ()); + } + else if (m_dragType == ResizeScale) + { + #if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "\tresize/scale" << endl; + #endif + + kpSelection *sel = document ()->selection (); + + if (!m_dragHasBegun && thisPoint == m_startPoint) + { + #if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "\t\tnop" << endl; + #endif + + setUserShapePoints (QPoint (sel->width (), sel->height ())); + return; + } + + + if (!sel->pixmap () && !m_currentPullFromDocumentCommand) + { + m_currentPullFromDocumentCommand = new kpToolSelectionPullFromDocumentCommand ( + QString::null/*uninteresting child of macro cmd*/, + mainWindow ()); + m_currentPullFromDocumentCommand->execute (); + } + + if (!m_currentResizeScaleCommand) + { + m_currentResizeScaleCommand = new kpToolSelectionResizeScaleCommand (mainWindow ()); + } + + + kpSelection originalSelection = m_currentResizeScaleCommand->originalSelection (); + const int oldWidth = originalSelection.width (); + const int oldHeight = originalSelection.height (); + + + // Determine new width. + + int userXSign = 0; + if (m_resizeScaleType & kpView::Left) + userXSign = -1; + else if (m_resizeScaleType & kpView::Right) + userXSign = +1; + + int newWidth = oldWidth + userXSign * (thisPoint.x () - m_startPoint.x ()); + + newWidth = QMAX (originalSelection.minimumWidth (), newWidth); + + + // Determine new height. + + int userYSign = 0; + if (m_resizeScaleType & kpView::Top) + userYSign = -1; + else if (m_resizeScaleType & kpView::Bottom) + userYSign = +1; + + int newHeight = oldHeight + userYSign * (thisPoint.y () - m_startPoint.y ()); + + newHeight = QMAX (originalSelection.minimumHeight (), newHeight); + + + // Keep aspect ratio? + if (m_shiftPressed && !sel->isText ()) + { + // Width changed more than height? At equality, favour width. + // Fix width, change height. + if ((userXSign ? double (newWidth) / oldWidth : 0) >= + (userYSign ? double (newHeight) / oldHeight : 0)) + { + newHeight = newWidth * oldHeight / oldWidth; + newHeight = QMAX (originalSelection.minimumHeight (), + newHeight); + } + // Height changed more than width? + // Fix height, change width. + else + { + newWidth = newHeight * oldWidth / oldHeight; + newWidth = QMAX (originalSelection.minimumWidth (), newWidth); + } + } + + + // Adjust x/y to new width/height for left/top resizes. + + int newX = originalSelection.x (); + int newY = originalSelection.y (); + + if (m_resizeScaleType & kpView::Left) + { + newX -= (newWidth - originalSelection.width ()); + } + + if (m_resizeScaleType & kpView::Top) + { + newY -= (newHeight - originalSelection.height ()); + } + + #if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "\t\tnewX=" << newX + << " newY=" << newY + << " newWidth=" << newWidth + << " newHeight=" << newHeight + << endl; + #endif + + + viewManager ()->setFastUpdates (); + m_currentResizeScaleCommand->resizeAndMoveTo (newWidth, newHeight, + QPoint (newX, newY), + true/*smooth scale delayed*/); + viewManager ()->restoreFastUpdates (); + + setUserShapePoints (QPoint (originalSelection.width (), + originalSelection.height ()), + QPoint (newWidth, + newHeight), + false/*don't set size*/); + setUserShapeSize (newWidth - originalSelection.width (), + newHeight - originalSelection.height ()); + } + + + m_dragHasBegun = nextDragHasBegun; +} + +// virtual +void kpToolSelection::cancelShape () +{ +#if DEBUG_KP_TOOL_SELECTION + kdDebug () << "kpToolSelection::cancelShape() mouseButton=" << m_mouseButton << endl; +#endif + + m_createNOPTimer->stop (); + m_RMBMoveUpdateGUITimer->stop (); + + + viewManager ()->setQueueUpdates (); + { + if (m_dragType == Move) + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\twas drag moving - undo drag and undo acquire" << endl; + #endif + + if (m_currentMoveCommand) + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\t\tundo currentMoveCommand" << endl; + #endif + m_currentMoveCommand->finalize (); + m_currentMoveCommand->unexecute (); + delete m_currentMoveCommand; + m_currentMoveCommand = 0; + + if (document ()->selection ()->isText ()) + viewManager ()->setTextCursorBlinkState (true); + } + } + else if (m_dragType == Create) + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\twas creating sel - kill" << endl; + #endif + + // TODO: should we give the user back the selection s/he had before (if any)? + document ()->selectionDelete (); + + if (m_currentCreateTextCommand) + { + delete m_currentCreateTextCommand; + m_currentCreateTextCommand = 0; + } + } + else if (m_dragType == ResizeScale) + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\twas resize/scale sel - kill" << endl; + #endif + + if (m_currentResizeScaleCommand) + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\t\tundo currentResizeScaleCommand" << endl; + #endif + m_currentResizeScaleCommand->finalize (); // (unneeded but let's be safe) + m_currentResizeScaleCommand->unexecute (); + delete m_currentResizeScaleCommand; + m_currentResizeScaleCommand = 0; + + if (document ()->selection ()->isText ()) + viewManager ()->setTextCursorBlinkState (true); + } + } + + + if (m_currentPullFromDocumentCommand) + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\t\tundo pullFromDocumentCommand" << endl; + #endif + m_currentPullFromDocumentCommand->unexecute (); + delete m_currentPullFromDocumentCommand; + m_currentPullFromDocumentCommand = 0; + } + + + viewManager ()->setSelectionBorderVisible (true); + viewManager ()->setSelectionBorderFinished (true); + viewManager ()->setTextCursorEnabled (m_mode == Text && true); + } + viewManager ()->restoreQueueUpdates (); + + + m_dragType = Unknown; + m_cancelledShapeButStillHoldingButtons = true; + setUserMessage (i18n ("Let go of all the mouse buttons.")); +} + +// virtual +void kpToolSelection::releasedAllButtons () +{ + m_cancelledShapeButStillHoldingButtons = false; + setUserMessage (haventBegunDrawUserMessage ()); +} + +// virtual +void kpToolSelection::endDraw (const QPoint & /*thisPoint*/, const QRect & /*normalizedRect*/) +{ + m_createNOPTimer->stop (); + m_RMBMoveUpdateGUITimer->stop (); + + + viewManager ()->setQueueUpdates (); + { + if (m_currentCreateTextCommand) + { + commandHistory ()->addCommand (m_currentCreateTextCommand, false/*no exec*/); + m_currentCreateTextCommand = 0; + } + + kpMacroCommand *cmd = 0; + if (m_currentMoveCommand) + { + if (m_currentMoveCommandIsSmear) + { + cmd = new kpMacroCommand (i18n ("%1: Smear") + .arg (document ()->selection ()->name ()), + mainWindow ()); + } + else + { + cmd = new kpMacroCommand ((document ()->selection ()->isText () ? + i18n ("Text: Move Box") : + i18n ("Selection: Move")), + mainWindow ()); + } + + if (document ()->selection ()->isText ()) + viewManager ()->setTextCursorBlinkState (true); + } + else if (m_currentResizeScaleCommand) + { + cmd = new kpMacroCommand (m_currentResizeScaleCommand->kpNamedCommand::name (), + mainWindow ()); + + if (document ()->selection ()->isText ()) + viewManager ()->setTextCursorBlinkState (true); + } + + if (m_currentPullFromDocumentCommand) + { + if (!m_currentMoveCommand && !m_currentResizeScaleCommand) + { + kdError () << "kpToolSelection::endDraw() pull without move nor resize/scale" << endl; + delete m_currentPullFromDocumentCommand; + m_currentPullFromDocumentCommand = 0; + } + else + { + kpSelection selection; + + if (m_currentMoveCommand) + selection = m_currentMoveCommand->originalSelection (); + else if (m_currentResizeScaleCommand) + selection = m_currentResizeScaleCommand->originalSelection (); + + // just the border + selection.setPixmap (QPixmap ()); + + kpCommand *createCommand = new kpToolSelectionCreateCommand ( + i18n ("Selection: Create"), + selection, + mainWindow ()); + + if (kpToolSelectionCreateCommand::nextUndoCommandIsCreateBorder (commandHistory ())) + commandHistory ()->setNextUndoCommand (createCommand); + else + commandHistory ()->addCommand (createCommand, + false/*no exec - user already dragged out sel*/); + + + cmd->addCommand (m_currentPullFromDocumentCommand); + m_currentPullFromDocumentCommand = 0; + } + } + + if (m_currentMoveCommand) + { + m_currentMoveCommand->finalize (); + cmd->addCommand (m_currentMoveCommand); + m_currentMoveCommand = 0; + + if (document ()->selection ()->isText ()) + viewManager ()->setTextCursorBlinkState (true); + } + + if (m_currentResizeScaleCommand) + { + m_currentResizeScaleCommand->finalize (); + cmd->addCommand (m_currentResizeScaleCommand); + m_currentResizeScaleCommand = 0; + + if (document ()->selection ()->isText ()) + viewManager ()->setTextCursorBlinkState (true); + } + + if (cmd) + commandHistory ()->addCommand (cmd, false/*no exec*/); + + viewManager ()->setSelectionBorderVisible (true); + viewManager ()->setSelectionBorderFinished (true); + viewManager ()->setTextCursorEnabled (m_mode == Text && true); + } + viewManager ()->restoreQueueUpdates (); + + + m_dragType = Unknown; + setUserMessage (haventBegunDrawUserMessage ()); + + + if (m_mouseButton == 1/*right*/) + popupRMBMenu (); +} + + +// protected virtual [base kpTool] +void kpToolSelection::keyPressEvent (QKeyEvent *e) +{ +#if DEBUG_KP_TOOL_SELECTION && 0 + kdDebug () << "kpToolSelection::keyPressEvent(e->text='" << e->text () << "')" << endl; +#endif + + + e->ignore (); + + + if (document ()->selection () && + !hasBegunDraw () && + e->key () == Qt::Key_Escape) + { + #if DEBUG_KP_TOOL_SELECTION && 0 + kdDebug () << "\tescape pressed with sel when not begun draw - deselecting" << endl; + #endif + + pushOntoDocument (); + e->accept (); + } + + + if (!e->isAccepted ()) + { + #if DEBUG_KP_TOOL_SELECTION && 0 + kdDebug () << "\tkey processing did not accept (text was '" + << e->text () + << "') - passing on event to kpTool" + << endl; + #endif + + kpTool::keyPressEvent (e); + return; + } +} + + +// private slot +void kpToolSelection::selectionTransparencyChanged (const QString & /*name*/) +{ +#if 0 +#if DEBUG_KP_TOOL_SELECTION + kdDebug () << "kpToolSelection::selectionTransparencyChanged(" << name << ")" << endl; +#endif + + if (mainWindow ()->settingSelectionTransparency ()) + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\trecursion - abort setting selection transparency: " + << mainWindow ()->settingSelectionTransparency () << endl; + #endif + return; + } + + if (document ()->selection ()) + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\thave sel - set transparency" << endl; + #endif + + kpSelectionTransparency oldST = document ()->selection ()->transparency (); + kpSelectionTransparency st = mainWindow ()->selectionTransparency (); + + // TODO: This "NOP" check causes us a great deal of trouble e.g.: + // + // Select a solid red rectangle. + // Switch to transparent and set red as the background colour. + // (the selection is now invisible) + // Invert Colours. + // (the selection is now cyan) + // Change the background colour to green. + // (no command is added to undo this as the selection does not change) + // Undo. + // The rectangle is no longer invisible. + // + //if (document ()->selection ()->setTransparency (st, true/*check harder for no change in mask*/)) + + document ()->selection ()->setTransparency (st); + if (true) + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\t\twhich changed the pixmap" << endl; + #endif + + commandHistory ()->addCommand (new kpToolSelectionTransparencyCommand ( + i18n ("Selection: Transparency"), // name, + st, oldST, + mainWindow ()), + false/* no exec*/); + } + } +#endif + + // TODO: I've duplicated the code (see below 3x) to make sure + // kpSelectionTransparency(oldST)::transparentColor() is defined + // and not taken from kpDocument (where it may not be defined because + // the transparency may be opaque). + // + // That way kpToolSelectionTransparencyCommand can force set colours. +} + + +// protected slot virtual +void kpToolSelection::slotIsOpaqueChanged () +{ +#if DEBUG_KP_TOOL_SELECTION + kdDebug () << "kpToolSelection::slotIsOpaqueChanged()" << endl; +#endif + + if (mainWindow ()->settingSelectionTransparency ()) + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\trecursion - abort setting selection transparency: " + << mainWindow ()->settingSelectionTransparency () << endl; + #endif + return; + } + + if (document ()->selection ()) + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\thave sel - set transparency" << endl; + #endif + + QApplication::setOverrideCursor (Qt::waitCursor); + + if (hasBegunShape ()) + endShapeInternal (); + + kpSelectionTransparency st = mainWindow ()->selectionTransparency (); + kpSelectionTransparency oldST = st; + oldST.setOpaque (!oldST.isOpaque ()); + + document ()->selection ()->setTransparency (st); + commandHistory ()->addCommand (new kpToolSelectionTransparencyCommand ( + st.isOpaque () ? + i18n ("Selection: Opaque") : + i18n ("Selection: Transparent"), + st, oldST, + mainWindow ()), + false/* no exec*/); + + QApplication::restoreOverrideCursor (); + } +} + +// protected slot virtual [base kpTool] +void kpToolSelection::slotBackgroundColorChanged (const kpColor &) +{ +#if DEBUG_KP_TOOL_SELECTION + kdDebug () << "kpToolSelection::slotBackgroundColorChanged()" << endl; +#endif + + if (mainWindow ()->settingSelectionTransparency ()) + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\trecursion - abort setting selection transparency: " + << mainWindow ()->settingSelectionTransparency () << endl; + #endif + return; + } + + if (document ()->selection ()) + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\thave sel - set transparency" << endl; + #endif + + QApplication::setOverrideCursor (Qt::waitCursor); + + kpSelectionTransparency st = mainWindow ()->selectionTransparency (); + kpSelectionTransparency oldST = st; + oldST.setTransparentColor (oldBackgroundColor ()); + + document ()->selection ()->setTransparency (st); + commandHistory ()->addCommand (new kpToolSelectionTransparencyCommand ( + i18n ("Selection: Transparency Color"), + st, oldST, + mainWindow ()), + false/* no exec*/); + + QApplication::restoreOverrideCursor (); + } +} + +// protected slot virtual [base kpTool] +void kpToolSelection::slotColorSimilarityChanged (double, int) +{ +#if DEBUG_KP_TOOL_SELECTION + kdDebug () << "kpToolSelection::slotColorSimilarityChanged()" << endl; +#endif + + if (mainWindow ()->settingSelectionTransparency ()) + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\trecursion - abort setting selection transparency: " + << mainWindow ()->settingSelectionTransparency () << endl; + #endif + return; + } + + if (document ()->selection ()) + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\thave sel - set transparency" << endl; + #endif + + QApplication::setOverrideCursor (Qt::waitCursor); + + kpSelectionTransparency st = mainWindow ()->selectionTransparency (); + kpSelectionTransparency oldST = st; + oldST.setColorSimilarity (oldColorSimilarity ()); + + document ()->selection ()->setTransparency (st); + commandHistory ()->addCommand (new kpToolSelectionTransparencyCommand ( + i18n ("Selection: Transparency Color Similarity"), + st, oldST, + mainWindow ()), + false/* no exec*/); + + QApplication::restoreOverrideCursor (); + } +} + + +/* + * kpToolSelectionCreateCommand + */ + +kpToolSelectionCreateCommand::kpToolSelectionCreateCommand (const QString &name, + const kpSelection &fromSelection, + kpMainWindow *mainWindow) + : kpNamedCommand (name, mainWindow), + m_fromSelection (0), + m_textRow (0), m_textCol (0) +{ + setFromSelection (fromSelection); +} + +kpToolSelectionCreateCommand::~kpToolSelectionCreateCommand () +{ + delete m_fromSelection; +} + + +// public virtual [base kpCommand] +int kpToolSelectionCreateCommand::size () const +{ + return kpPixmapFX::selectionSize (m_fromSelection); +} + + +// public static +bool kpToolSelectionCreateCommand::nextUndoCommandIsCreateBorder ( + kpCommandHistory *commandHistory) +{ + if (!commandHistory) + return false; + + kpCommand *cmd = commandHistory->nextUndoCommand (); + if (!cmd) + return false; + + kpToolSelectionCreateCommand *c = dynamic_cast (cmd); + if (!c) + return false; + + const kpSelection *sel = c->fromSelection (); + if (!sel) + return false; + + return (!sel->pixmap ()); +} + + +// public +const kpSelection *kpToolSelectionCreateCommand::fromSelection () const +{ + return m_fromSelection; +} + +// public +void kpToolSelectionCreateCommand::setFromSelection (const kpSelection &fromSelection) +{ + delete m_fromSelection; + m_fromSelection = new kpSelection (fromSelection); +} + +// public virtual [base kpCommand] +void kpToolSelectionCreateCommand::execute () +{ +#if DEBUG_KP_TOOL_SELECTION + kdDebug () << "kpToolSelectionCreateCommand::execute()" << endl; +#endif + + kpDocument *doc = document (); + if (!doc) + { + kdError () << "kpToolSelectionCreateCommand::execute() without doc" << endl; + return; + } + + if (m_fromSelection) + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\tusing fromSelection" << endl; + kdDebug () << "\t\thave sel=" << doc->selection () + << " pixmap=" << (doc->selection () ? doc->selection ()->pixmap () : 0) + << endl; + #endif + if (!m_fromSelection->isText ()) + { + if (m_fromSelection->transparency () != m_mainWindow->selectionTransparency ()) + m_mainWindow->setSelectionTransparency (m_fromSelection->transparency ()); + } + else + { + if (m_fromSelection->textStyle () != m_mainWindow->textStyle ()) + m_mainWindow->setTextStyle (m_fromSelection->textStyle ()); + } + + m_mainWindow->viewManager ()->setTextCursorPosition (m_textRow, m_textCol); + doc->setSelection (*m_fromSelection); + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + } +} + +// public virtual [base kpCommand] +void kpToolSelectionCreateCommand::unexecute () +{ + kpDocument *doc = document (); + if (!doc) + { + kdError () << "kpToolSelectionCreateCommand::unexecute() without doc" << endl; + return; + } + + if (!doc->selection ()) + { + // Was just a border that got deselected? + if (m_fromSelection && !m_fromSelection->pixmap ()) + return; + + kdError () << "kpToolSelectionCreateCommand::unexecute() without sel region" << endl; + return; + } + + m_textRow = m_mainWindow->viewManager ()->textCursorRow (); + m_textCol = m_mainWindow->viewManager ()->textCursorCol (); + + doc->selectionDelete (); + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); +} + + +/* + * kpToolSelectionPullFromDocumentCommand + */ + +kpToolSelectionPullFromDocumentCommand::kpToolSelectionPullFromDocumentCommand (const QString &name, + kpMainWindow *mainWindow) + : kpNamedCommand (name, mainWindow), + m_backgroundColor (mainWindow ? mainWindow->backgroundColor () : kpColor::invalid), + m_originalSelectionRegion (0) +{ +#if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "kpToolSelectionPullFromDocumentCommand::() mainWindow=" + << m_mainWindow + << endl; +#endif +} + +kpToolSelectionPullFromDocumentCommand::~kpToolSelectionPullFromDocumentCommand () +{ + delete m_originalSelectionRegion; +} + + +// public virtual [base kpCommand] +int kpToolSelectionPullFromDocumentCommand::size () const +{ + return kpPixmapFX::selectionSize (m_originalSelectionRegion); +} + + +// public virtual [base kpCommand] +void kpToolSelectionPullFromDocumentCommand::execute () +{ +#if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "kpToolSelectionPullFromDocumentCommand::execute()" << endl; +#endif + + kpDocument *doc = document (); + + if (!doc) + { + kdError () << "kpToolSelectionPullFromDocumentCommand::execute() without doc" << endl; + return; + } + + kpViewManager *vm = m_mainWindow ? m_mainWindow->viewManager () : 0; + if (vm) + vm->setQueueUpdates (); + + // In case the user CTRL+Z'ed, selected a random region to throw us off + // and then CTRL+Shift+Z'ed putting us here. Make sure we pull from the + // originally requested region - not the random one. + if (m_originalSelectionRegion) + { + if (m_originalSelectionRegion->transparency () != m_mainWindow->selectionTransparency ()) + m_mainWindow->setSelectionTransparency (m_originalSelectionRegion->transparency ()); + + doc->setSelection (*m_originalSelectionRegion); + } + else + { + // must have selection region but not pixmap + if (!doc->selection () || doc->selection ()->pixmap ()) + { + kdError () << "kpToolSelectionPullFromDocumentCommand::execute() sel=" + << doc->selection () + << " pixmap=" + << (doc->selection () ? doc->selection ()->pixmap () : 0) + << endl; + if (vm) + vm->restoreQueueUpdates (); + return; + } + } + + doc->selectionPullFromDocument (m_backgroundColor); + + if (vm) + vm->restoreQueueUpdates (); +} + +// public virtual [base kpCommand] +void kpToolSelectionPullFromDocumentCommand::unexecute () +{ +#if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "kpToolSelectionPullFromDocumentCommand::unexecute()" << endl; +#endif + + kpDocument *doc = document (); + + if (!doc) + { + kdError () << "kpToolSelectionPullFromDocumentCommand::unexecute() without doc" << endl; + return; + } + + // must have selection pixmap + if (!doc->selection () || !doc->selection ()->pixmap ()) + { + kdError () << "kpToolSelectionPullFromDocumentCommand::unexecute() sel=" + << doc->selection () + << " pixmap=" + << (doc->selection () ? doc->selection ()->pixmap () : 0) + << endl; + return; + } + + + // We can have faith that this is the state of the selection after + // execute(), rather than after the user tried to throw us off by + // simply selecting another region as to do that, a destroy command + // must have been used. + doc->selectionCopyOntoDocument (false/*use opaque pixmap*/); + doc->selection ()->setPixmap (QPixmap ()); + + delete m_originalSelectionRegion; + m_originalSelectionRegion = new kpSelection (*doc->selection ()); +} + + +/* + * kpToolSelectionTransparencyCommand + */ + +kpToolSelectionTransparencyCommand::kpToolSelectionTransparencyCommand (const QString &name, + const kpSelectionTransparency &st, + const kpSelectionTransparency &oldST, + kpMainWindow *mainWindow) + : kpNamedCommand (name, mainWindow), + m_st (st), + m_oldST (oldST) +{ +} + +kpToolSelectionTransparencyCommand::~kpToolSelectionTransparencyCommand () +{ +} + + +// public virtual [base kpCommand] +int kpToolSelectionTransparencyCommand::size () const +{ + return 0; +} + + +// public virtual [base kpCommand] +void kpToolSelectionTransparencyCommand::execute () +{ +#if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "kpToolSelectionTransparencyCommand::execute()" << endl; +#endif + kpDocument *doc = document (); + if (!doc) + return; + + QApplication::setOverrideCursor (Qt::waitCursor); + + m_mainWindow->setSelectionTransparency (m_st, true/*force colour change*/); + + if (doc->selection ()) + doc->selection ()->setTransparency (m_st); + + QApplication::restoreOverrideCursor (); +} + +// public virtual [base kpCommand] +void kpToolSelectionTransparencyCommand::unexecute () +{ +#if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "kpToolSelectionTransparencyCommand::unexecute()" << endl; +#endif + + kpDocument *doc = document (); + if (!doc) + return; + + QApplication::setOverrideCursor (Qt::waitCursor); + + m_mainWindow->setSelectionTransparency (m_oldST, true/*force colour change*/); + + if (doc->selection ()) + doc->selection ()->setTransparency (m_oldST); + + QApplication::restoreOverrideCursor (); +} + + +/* + * kpToolSelectionMoveCommand + */ + +kpToolSelectionMoveCommand::kpToolSelectionMoveCommand (const QString &name, + kpMainWindow *mainWindow) + : kpNamedCommand (name, mainWindow) +{ + kpDocument *doc = document (); + if (doc && doc->selection ()) + { + m_startPoint = m_endPoint = doc->selection ()->topLeft (); + } +} + +kpToolSelectionMoveCommand::~kpToolSelectionMoveCommand () +{ +} + + +// public +kpSelection kpToolSelectionMoveCommand::originalSelection () const +{ + kpDocument *doc = document (); + if (!doc || !doc->selection ()) + { + kdError () << "kpToolSelectionMoveCommand::originalSelection() doc=" + << doc + << " sel=" + << (doc ? doc->selection () : 0) + << endl; + return kpSelection (kpSelection::Rectangle, QRect ()); + } + + kpSelection selection = *doc->selection(); + selection.moveTo (m_startPoint); + + return selection; +} + + +// public virtual [base kpComand] +int kpToolSelectionMoveCommand::size () const +{ + return kpPixmapFX::pixmapSize (m_oldDocumentPixmap) + + kpPixmapFX::pointArraySize (m_copyOntoDocumentPoints); +} + + +// public virtual [base kpCommand] +void kpToolSelectionMoveCommand::execute () +{ +#if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "kpToolSelectionMoveCommand::execute()" << endl; +#endif + + kpDocument *doc = document (); + if (!doc) + { + kdError () << "kpToolSelectionMoveCommand::execute() no doc" << endl; + return; + } + + kpSelection *sel = doc->selection (); + + // have to have pulled pixmap by now + if (!sel || !sel->pixmap ()) + { + kdError () << "kpToolSelectionMoveCommand::execute() but haven't pulled pixmap yet: " + << "sel=" << sel << " sel->pixmap=" << (sel ? sel->pixmap () : 0) + << endl; + return; + } + + kpViewManager *vm = m_mainWindow ? m_mainWindow->viewManager () : 0; + + if (vm) + vm->setQueueUpdates (); + + QPointArray::ConstIterator copyOntoDocumentPointsEnd = m_copyOntoDocumentPoints.end (); + for (QPointArray::ConstIterator it = m_copyOntoDocumentPoints.begin (); + it != copyOntoDocumentPointsEnd; + it++) + { + sel->moveTo (*it); + doc->selectionCopyOntoDocument (); + } + + sel->moveTo (m_endPoint); + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + + if (vm) + vm->restoreQueueUpdates (); +} + +// public virtual [base kpCommand] +void kpToolSelectionMoveCommand::unexecute () +{ +#if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "kpToolSelectionMoveCommand::unexecute()" << endl; +#endif + + kpDocument *doc = document (); + if (!doc) + { + kdError () << "kpToolSelectionMoveCommand::unexecute() no doc" << endl; + return; + } + + kpSelection *sel = doc->selection (); + + // have to have pulled pixmap by now + if (!sel || !sel->pixmap ()) + { + kdError () << "kpToolSelectionMoveCommand::unexecute() but haven't pulled pixmap yet: " + << "sel=" << sel << " sel->pixmap=" << (sel ? sel->pixmap () : 0) + << endl; + return; + } + + kpViewManager *vm = m_mainWindow ? m_mainWindow->viewManager () : 0; + + if (vm) + vm->setQueueUpdates (); + + if (!m_oldDocumentPixmap.isNull ()) + doc->setPixmapAt (m_oldDocumentPixmap, m_documentBoundingRect.topLeft ()); +#if DEBUG_KP_TOOL_SELECTION && 1 + kdDebug () << "\tmove to startPoint=" << m_startPoint << endl; +#endif + sel->moveTo (m_startPoint); + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + + if (vm) + vm->restoreQueueUpdates (); +} + +// public +void kpToolSelectionMoveCommand::moveTo (const QPoint &point, bool moveLater) +{ +#if DEBUG_KP_TOOL_SELECTION && 0 + kdDebug () << "kpToolSelectionMoveCommand::moveTo" << point + << " moveLater=" << moveLater + <selection (); + + // have to have pulled pixmap by now + if (!sel) + { + kdError () << "kpToolSelectionMoveCommand::moveTo() no sel region" << endl; + return; + } + + if (!sel->pixmap ()) + { + kdError () << "kpToolSelectionMoveCommand::moveTo() no sel pixmap" << endl; + return; + } + + if (point == sel->topLeft ()) + return; + + sel->moveTo (point); + } + + m_endPoint = point; +} + +// public +void kpToolSelectionMoveCommand::moveTo (int x, int y, bool moveLater) +{ + moveTo (QPoint (x, y), moveLater); +} + +// public +void kpToolSelectionMoveCommand::copyOntoDocument () +{ +#if DEBUG_KP_TOOL_SELECTION + kdDebug () << "kpToolSelectionMoveCommand::copyOntoDocument()" << endl; +#endif + + kpDocument *doc = document (); + if (!doc) + return; + + kpSelection *sel = doc->selection (); + + // have to have pulled pixmap by now + if (!sel) + { + kdError () << "\tkpToolSelectionMoveCommand::copyOntoDocument() without sel region" << endl; + return; + } + + if (!sel->pixmap ()) + { + kdError () << "kpToolSelectionMoveCommand::moveTo() no sel pixmap" << endl; + return; + } + + if (m_oldDocumentPixmap.isNull ()) + m_oldDocumentPixmap = *doc->pixmap (); + + QRect selBoundingRect = sel->boundingRect (); + m_documentBoundingRect.unite (selBoundingRect); + + doc->selectionCopyOntoDocument (); + + m_copyOntoDocumentPoints.putPoints (m_copyOntoDocumentPoints.count (), + 1, + selBoundingRect.x (), + selBoundingRect.y ()); +} + +// public +void kpToolSelectionMoveCommand::finalize () +{ + if (!m_oldDocumentPixmap.isNull () && !m_documentBoundingRect.isNull ()) + { + m_oldDocumentPixmap = kpTool::neededPixmap (m_oldDocumentPixmap, + m_documentBoundingRect); + } +} + + +/* + * kpToolSelectionResizeScaleCommand + */ + +kpToolSelectionResizeScaleCommand::kpToolSelectionResizeScaleCommand ( + kpMainWindow *mainWindow) + : kpNamedCommand (mainWindow->document ()->selection ()->isText () ? + i18n ("Text: Resize Box") : + i18n ("Selection: Smooth Scale"), + mainWindow), + m_smoothScaleTimer (new QTimer (this)) +{ + m_originalSelection = *selection (); + + m_newTopLeft = selection ()->topLeft (); + m_newWidth = selection ()->width (); + m_newHeight = selection ()->height (); + + connect (m_smoothScaleTimer, SIGNAL (timeout ()), + this, SLOT (resizeScaleAndMove ())); +} + +kpToolSelectionResizeScaleCommand::~kpToolSelectionResizeScaleCommand () +{ +} + + +// public virtual +int kpToolSelectionResizeScaleCommand::size () const +{ + return m_originalSelection.size (); +} + + +// public +kpSelection kpToolSelectionResizeScaleCommand::originalSelection () const +{ + return m_originalSelection; +} + + +// public +QPoint kpToolSelectionResizeScaleCommand::topLeft () const +{ + return m_newTopLeft; +} + +// public +void kpToolSelectionResizeScaleCommand::moveTo (const QPoint &point) +{ + if (point == m_newTopLeft) + return; + + m_newTopLeft = point; + selection ()->moveTo (m_newTopLeft); +} + + +// public +int kpToolSelectionResizeScaleCommand::width () const +{ + return m_newWidth; +} + +// public +int kpToolSelectionResizeScaleCommand::height () const +{ + return m_newHeight; +} + +// public +void kpToolSelectionResizeScaleCommand::resize (int width, int height, + bool delayed) +{ + if (width == m_newWidth && height == m_newHeight) + return; + + m_newWidth = width; + m_newHeight = height; + + resizeScaleAndMove (delayed); +} + + +// public +void kpToolSelectionResizeScaleCommand::resizeAndMoveTo (int width, int height, + const QPoint &point, + bool delayed) +{ + if (width == m_newWidth && height == m_newHeight && + point == m_newTopLeft) + { + return; + } + + m_newWidth = width; + m_newHeight = height; + m_newTopLeft = point; + + resizeScaleAndMove (delayed); +} + + +// protected +void kpToolSelectionResizeScaleCommand::killSmoothScaleTimer () +{ + m_smoothScaleTimer->stop (); +} + + +// protected +void kpToolSelectionResizeScaleCommand::resizeScaleAndMove (bool delayed) +{ +#if DEBUG_KP_TOOL_SELECTION + kdDebug () << "kpToolSelectionResizeScaleCommand::resizeScaleAndMove(delayed=" + << delayed << ")" << endl; +#endif + + killSmoothScaleTimer (); + + kpSelection newSel; + + if (selection ()->isText ()) + { + newSel = m_originalSelection; + newSel.textResize (m_newWidth, m_newHeight); + } + else + { + newSel = kpSelection (kpSelection::Rectangle, + QRect (m_originalSelection.x (), + m_originalSelection.y (), + m_newWidth, + m_newHeight), + kpPixmapFX::scale (*m_originalSelection.pixmap (), + m_newWidth, m_newHeight, + !delayed/*if not delayed, smooth*/), + m_originalSelection.transparency ()); + + if (delayed) + { + // Call self with delayed==false in 200ms + m_smoothScaleTimer->start (200/*ms*/, true/*single shot*/); + } + } + + newSel.moveTo (m_newTopLeft); + + m_mainWindow->document ()->setSelection (newSel); +} + +// protected slots +void kpToolSelectionResizeScaleCommand::resizeScaleAndMove () +{ +#if DEBUG_KP_TOOL_SELECTION + kdDebug () << "kpToolSelectionResizeScaleCommand::resizeScaleAndMove()" << endl; +#endif + resizeScaleAndMove (false/*no delay*/); +} + + +// public +void kpToolSelectionResizeScaleCommand::finalize () +{ +#if DEBUG_KP_TOOL_SELECTION + kdDebug () << "kpToolSelectionResizeScaleCommand::finalize()" + << " smoothScaleTimer->isActive=" + << m_smoothScaleTimer->isActive () + << endl; +#endif + + // Make sure the selection contains the final image and the timer won't + // fire afterwards. + if (m_smoothScaleTimer->isActive ()) + { + resizeScaleAndMove (); + Q_ASSERT (!m_smoothScaleTimer->isActive ()); + } +} + + +// public virtual [base kpToolResizeScaleCommand] +void kpToolSelectionResizeScaleCommand::execute () +{ + QApplication::setOverrideCursor (Qt::waitCursor); + + killSmoothScaleTimer (); + + resizeScaleAndMove (); + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + + QApplication::restoreOverrideCursor (); +} + +// public virtual [base kpToolResizeScaleCommand] +void kpToolSelectionResizeScaleCommand::unexecute () +{ + QApplication::setOverrideCursor (Qt::waitCursor); + + killSmoothScaleTimer (); + + m_mainWindow->document ()->setSelection (m_originalSelection); + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + + QApplication::restoreOverrideCursor (); +} + + +/* + * kpToolSelectionDestroyCommand + */ + +kpToolSelectionDestroyCommand::kpToolSelectionDestroyCommand (const QString &name, + bool pushOntoDocument, + kpMainWindow *mainWindow) + : kpNamedCommand (name, mainWindow), + m_pushOntoDocument (pushOntoDocument), + m_oldSelection (0) +{ +} + +kpToolSelectionDestroyCommand::~kpToolSelectionDestroyCommand () +{ + delete m_oldSelection; +} + + +// public virtual [base kpCommand] +int kpToolSelectionDestroyCommand::size () const +{ + return kpPixmapFX::pixmapSize (m_oldDocPixmap) + + kpPixmapFX::selectionSize (m_oldSelection); +} + + +// public virtual [base kpCommand] +void kpToolSelectionDestroyCommand::execute () +{ +#if DEBUG_KP_TOOL_SELECTION + kdDebug () << "kpToolSelectionDestroyCommand::execute () CALLED" << endl; +#endif + + kpDocument *doc = document (); + if (!doc) + { + kdError () << "kpToolSelectionDestroyCommand::execute() without doc" << endl; + return; + } + + if (!doc->selection ()) + { + kdError () << "kpToolSelectionDestroyCommand::execute() without sel region" << endl; + return; + } + + m_textRow = m_mainWindow->viewManager ()->textCursorRow (); + m_textCol = m_mainWindow->viewManager ()->textCursorCol (); + + m_oldSelection = new kpSelection (*doc->selection ()); + if (m_pushOntoDocument) + { + m_oldDocPixmap = doc->getPixmapAt (doc->selection ()->boundingRect ()); + doc->selectionPushOntoDocument (); + } + else + doc->selectionDelete (); + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); +} + +// public virtual [base kpCommand] +void kpToolSelectionDestroyCommand::unexecute () +{ +#if DEBUG_KP_TOOL_SELECTION + kdDebug () << "kpToolSelectionDestroyCommand::unexecute () CALLED" << endl; +#endif + + kpDocument *doc = document (); + if (!doc) + { + kdError () << "kpToolSelectionDestroyCommand::unexecute() without doc" << endl; + return; + } + + if (doc->selection ()) + { + // not error because it's possible that the user dragged out a new + // region (without pulling pixmap), and then CTRL+Z + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "kpToolSelectionDestroyCommand::unexecute() already has sel region" << endl; + #endif + + if (doc->selection ()->pixmap ()) + { + kdError () << "kpToolSelectionDestroyCommand::unexecute() already has sel pixmap" << endl; + return; + } + } + + if (!m_oldSelection) + { + kdError () << "kpToolSelectionDestroyCommand::unexecute() without old sel" << endl; + return; + } + + if (m_pushOntoDocument) + { + #if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\tunpush oldDocPixmap onto doc first" << endl; + #endif + doc->setPixmapAt (m_oldDocPixmap, m_oldSelection->topLeft ()); + } + +#if DEBUG_KP_TOOL_SELECTION + kdDebug () << "\tsetting selection to: rect=" << m_oldSelection->boundingRect () + << " pixmap=" << m_oldSelection->pixmap () + << " pixmap.isNull()=" << (m_oldSelection->pixmap () + ? + m_oldSelection->pixmap ()->isNull () + : + true) + << endl; +#endif + if (!m_oldSelection->isText ()) + { + if (m_oldSelection->transparency () != m_mainWindow->selectionTransparency ()) + m_mainWindow->setSelectionTransparency (m_oldSelection->transparency ()); + } + else + { + if (m_oldSelection->textStyle () != m_mainWindow->textStyle ()) + m_mainWindow->setTextStyle (m_oldSelection->textStyle ()); + } + + m_mainWindow->viewManager ()->setTextCursorPosition (m_textRow, m_textCol); + doc->setSelection (*m_oldSelection); + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + + delete m_oldSelection; + m_oldSelection = 0; +} + +#include diff --git a/kolourpaint/tools/kptoolselection.h b/kolourpaint/tools/kptoolselection.h new file mode 100644 index 00000000..ee978a15 --- /dev/null +++ b/kolourpaint/tools/kptoolselection.h @@ -0,0 +1,313 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kp_tool_selection_h__ +#define __kp_tool_selection_h__ + + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +class QPoint; +class QRect; +class QTimer; + +class kpMainWindow; +class kpSelection; + +class kpToolSelectionCreateCommand; +class kpToolSelectionMoveCommand; +class kpToolSelectionPullFromDocumentCommand; +class kpToolSelectionResizeScaleCommand; +class kpToolWidgetOpaqueOrTransparent; + + +class kpToolSelection : public kpTool +{ +Q_OBJECT + +public: + enum Mode {Rectangle, Ellipse, FreeForm, Text}; + + kpToolSelection (Mode mode, + const QString &text, const QString &description, + int key, + kpMainWindow *mainWindow, const char *name); + virtual ~kpToolSelection (); + + void setMode (Mode mode) { m_mode = mode; } + +private: + void pushOntoDocument (); + +protected: + bool onSelectionToMove () const; + int onSelectionResizeHandle () const; + bool onSelectionToSelectText () const; + +public: + QString haventBegunDrawUserMessage () const; + + virtual void begin (); + virtual void end (); + virtual void reselect (); + + virtual bool careAboutModifierState () const { return true; } + bool controlOrShiftPressed () const { return (m_controlPressed || m_shiftPressed); } + + virtual void beginDraw (); +protected: + const QCursor &cursor () const; +public: + virtual void hover (const QPoint &point); +protected: + void popupRMBMenu (); + void setSelectionBorderForMove (); +protected slots: + void slotRMBMoveUpdateGUI (); + void delayedDraw (); +public: + virtual void draw (const QPoint &thisPoint, const QPoint &lastPoint, + const QRect &normalizedRect); + virtual void cancelShape (); + virtual void releasedAllButtons (); + virtual void endDraw (const QPoint &thisPoint, const QRect &normalizedRect); + +protected: + virtual void keyPressEvent (QKeyEvent *e); + +protected: + void selectionTransparencyChanged (const QString &name); + +protected slots: + virtual void slotIsOpaqueChanged (); + virtual void slotBackgroundColorChanged (const kpColor &color); + virtual void slotColorSimilarityChanged (double similarity, int); + +protected: + Mode m_mode; + + QPoint m_startDragFromSelectionTopLeft; + enum DragType + { + Unknown, Create, Move, SelectText, ResizeScale + }; + DragType m_dragType; + bool m_dragHasBegun; + bool m_hadSelectionBeforeDrag; + int m_resizeScaleType; + + kpToolSelectionPullFromDocumentCommand *m_currentPullFromDocumentCommand; + kpToolSelectionMoveCommand *m_currentMoveCommand; + bool m_currentMoveCommandIsSmear; + kpToolSelectionResizeScaleCommand *m_currentResizeScaleCommand; + kpToolWidgetOpaqueOrTransparent *m_toolWidgetOpaqueOrTransparent; + + kpToolSelectionCreateCommand *m_currentCreateTextCommand; + bool m_cancelledShapeButStillHoldingButtons; + + QTimer *m_createNOPTimer, *m_RMBMoveUpdateGUITimer; +}; + +class kpToolSelectionCreateCommand : public kpNamedCommand +{ +public: + // (if fromSelection doesn't have a pixmap, it will only recreate the region) + kpToolSelectionCreateCommand (const QString &name, const kpSelection &fromSelection, + kpMainWindow *mainWindow); + virtual ~kpToolSelectionCreateCommand (); + + virtual int size () const; + + static bool nextUndoCommandIsCreateBorder (kpCommandHistory *commandHistory); + + const kpSelection *fromSelection () const; + void setFromSelection (const kpSelection &fromSelection); + + virtual void execute (); + virtual void unexecute (); + +private: + kpSelection *m_fromSelection; + + int m_textRow, m_textCol; +}; + +class kpToolSelectionPullFromDocumentCommand : public kpNamedCommand +{ +public: + kpToolSelectionPullFromDocumentCommand (const QString &name, kpMainWindow *mainWindow); + virtual ~kpToolSelectionPullFromDocumentCommand (); + + virtual int size () const; + + virtual void execute (); + virtual void unexecute (); + +private: + kpColor m_backgroundColor; + kpSelection *m_originalSelectionRegion; +}; + +class kpToolSelectionTransparencyCommand : public kpNamedCommand +{ +public: + kpToolSelectionTransparencyCommand (const QString &name, + const kpSelectionTransparency &st, + const kpSelectionTransparency &oldST, + kpMainWindow *mainWindow); + virtual ~kpToolSelectionTransparencyCommand (); + + virtual int size () const; + + virtual void execute (); + virtual void unexecute (); + +private: + kpSelectionTransparency m_st, m_oldST; +}; + +class kpToolSelectionMoveCommand : public kpNamedCommand +{ +public: + kpToolSelectionMoveCommand (const QString &name, kpMainWindow *mainWindow); + virtual ~kpToolSelectionMoveCommand (); + + kpSelection originalSelection () const; + + virtual int size () const; + + virtual void execute (); + virtual void unexecute (); + + void moveTo (const QPoint &point, bool moveLater = false); + void moveTo (int x, int y, bool moveLater = false); + void copyOntoDocument (); + void finalize (); + +private: + QPoint m_startPoint, m_endPoint; + + QPixmap m_oldDocumentPixmap; + + // area of document affected (not the bounding rect of the sel) + QRect m_documentBoundingRect; + + QPointArray m_copyOntoDocumentPoints; +}; + +// You could subclass kpToolResizeScaleCommand and/or +// kpToolSelectionMoveCommand instead if want a disaster. +// This is different to kpToolResizeScaleCommand in that: +// +// 1. This only works for selections. +// 2. This is designed for the size and position to change several times +// before execute(). +// +class kpToolSelectionResizeScaleCommand : public QObject, + public kpNamedCommand +{ +Q_OBJECT + +public: + kpToolSelectionResizeScaleCommand (kpMainWindow *mainWindow); + virtual ~kpToolSelectionResizeScaleCommand (); + + virtual int size () const; + +public: + kpSelection originalSelection () const; + + QPoint topLeft () const; + void moveTo (const QPoint &point); + + int width () const; + int height () const; + void resize (int width, int height, bool delayed = false); + + // (equivalent to resize() followed by moveTo() but faster) + void resizeAndMoveTo (int width, int height, const QPoint &point, + bool delayed = false); + +protected: + void killSmoothScaleTimer (); + + // If , does a fast, low-quality scale and then calls itself + // with unset for a smooth scale, a short time later. + // If acting on a text box, is ignored. + void resizeScaleAndMove (bool delayed); + +protected slots: + void resizeScaleAndMove (/*delayed = false*/); + +public: + void finalize (); + +public: + virtual void execute (); + virtual void unexecute (); + +protected: + kpSelection m_originalSelection; + + QPoint m_newTopLeft; + int m_newWidth, m_newHeight; + + QTimer *m_smoothScaleTimer; +}; + +class kpToolSelectionDestroyCommand : public kpNamedCommand +{ +public: + kpToolSelectionDestroyCommand (const QString &name, bool pushOntoDocument, + kpMainWindow *mainWindow); + virtual ~kpToolSelectionDestroyCommand (); + + virtual int size () const; + + virtual void execute (); + virtual void unexecute (); + +private: + bool m_pushOntoDocument; + QPixmap m_oldDocPixmap; + kpSelection *m_oldSelection; + + int m_textRow, m_textCol; +}; + +#endif // __kp_tool_selection_h__ diff --git a/kolourpaint/tools/kptoolskew.cpp b/kolourpaint/tools/kptoolskew.cpp new file mode 100644 index 00000000..f1e446be --- /dev/null +++ b/kolourpaint/tools/kptoolskew.cpp @@ -0,0 +1,449 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_TOOL_SKEW 0 +#define DEBUG_KP_TOOL_SKEW_DIALOG 0 + + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +/* + * kpToolSkewCommand + */ + +kpToolSkewCommand::kpToolSkewCommand (bool actOnSelection, + int hangle, int vangle, + kpMainWindow *mainWindow) + : kpCommand (mainWindow), + m_actOnSelection (actOnSelection), + m_hangle (hangle), m_vangle (vangle), + m_backgroundColor (mainWindow ? mainWindow->backgroundColor (actOnSelection) : kpColor::invalid), + m_oldPixmapPtr (0) +{ +} + +kpToolSkewCommand::~kpToolSkewCommand () +{ + delete m_oldPixmapPtr; +} + + +// public virtual [base kpCommand] +QString kpToolSkewCommand::name () const +{ + QString opName = i18n ("Skew"); + + if (m_actOnSelection) + return i18n ("Selection: %1").arg (opName); + else + return opName; +} + + +// public virtual [base kpCommand] +int kpToolSkewCommand::size () const +{ + return kpPixmapFX::pixmapSize (m_oldPixmapPtr) + + m_oldSelection.size (); +} + + +// public virtual [base kpCommand] +void kpToolSkewCommand::execute () +{ + kpDocument *doc = document (); + if (!doc) + return; + + + QApplication::setOverrideCursor (Qt::waitCursor); + + + m_oldPixmapPtr = new QPixmap (); + *m_oldPixmapPtr = *doc->pixmap (m_actOnSelection); + + + QPixmap newPixmap = kpPixmapFX::skew (*doc->pixmap (m_actOnSelection), + kpToolSkewDialog::horizontalAngleForPixmapFX (m_hangle), + kpToolSkewDialog::verticalAngleForPixmapFX (m_vangle), + m_backgroundColor); + + if (m_actOnSelection) + { + kpSelection *sel = doc->selection (); + + // Save old selection + m_oldSelection = *sel; + + + // Calculate skewed points + QPointArray currentPoints = sel->points (); + currentPoints.translate (-currentPoints.boundingRect ().x (), + -currentPoints.boundingRect ().y ()); + QWMatrix skewMatrix = kpPixmapFX::skewMatrix ( + *doc->pixmap (m_actOnSelection), + kpToolSkewDialog::horizontalAngleForPixmapFX (m_hangle), + kpToolSkewDialog::verticalAngleForPixmapFX (m_vangle)); + currentPoints = skewMatrix.map (currentPoints); + currentPoints.translate (-currentPoints.boundingRect ().x () + m_oldSelection.x (), + -currentPoints.boundingRect ().y () + m_oldSelection.y ()); + + + if (currentPoints.boundingRect ().width () == newPixmap.width () && + currentPoints.boundingRect ().height () == newPixmap.height ()) + { + doc->setSelection (kpSelection (currentPoints, newPixmap, + m_oldSelection.transparency ())); + } + else + { + // TODO: fix the latter "victim of" problem in kpSelection by + // allowing the border width & height != pixmap width & height + // Or maybe autocrop? + #if DEBUG_KP_TOOL_SKEW + kdDebug () << "kpToolSkewCommand::execute() currentPoints.boundingRect=" + << currentPoints.boundingRect () + << " newPixmap: w=" << newPixmap.width () + << " h=" << newPixmap.height () + << " (victim of rounding error and/or skewed-a-(rectangular)-pixmap-that-was-transparent-in-the-corners-making-sel-uselessly-bigger-than-needs-be))" + << endl; + #endif + doc->setSelection (kpSelection (kpSelection::Rectangle, + QRect (currentPoints.boundingRect ().x (), + currentPoints.boundingRect ().y (), + newPixmap.width (), + newPixmap.height ()), + newPixmap, + m_oldSelection.transparency ())); + } + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + } + else + { + doc->setPixmap (newPixmap); + } + + + QApplication::restoreOverrideCursor (); +} + +// public virtual [base kpCommand] +void kpToolSkewCommand::unexecute () +{ + kpDocument *doc = document (); + if (!doc) + return; + + + QApplication::setOverrideCursor (Qt::waitCursor); + + + QPixmap oldPixmap = *m_oldPixmapPtr; + delete m_oldPixmapPtr; m_oldPixmapPtr = 0; + + + if (!m_actOnSelection) + doc->setPixmap (oldPixmap); + else + { + kpSelection oldSelection = m_oldSelection; + doc->setSelection (oldSelection); + + if (m_mainWindow->tool ()) + m_mainWindow->tool ()->somethingBelowTheCursorChanged (); + } + + + QApplication::restoreOverrideCursor (); +} + + +/* + * kpToolSkewDialog + */ + + +// private static +int kpToolSkewDialog::s_lastWidth = -1, + kpToolSkewDialog::s_lastHeight = -1; + +// private static +int kpToolSkewDialog::s_lastHorizontalAngle = 0, + kpToolSkewDialog::s_lastVerticalAngle = 0; + + +kpToolSkewDialog::kpToolSkewDialog (bool actOnSelection, kpMainWindow *parent, + const char *name) + : kpToolPreviewDialog (kpToolPreviewDialog::AllFeatures, + false/*don't reserve top row*/, + actOnSelection ? i18n ("Skew Selection") : i18n ("Skew Image"), + i18n ("After Skew:"), + actOnSelection, parent, name) +{ + // Too confusing - disable for now + s_lastHorizontalAngle = s_lastVerticalAngle = 0; + + + createAngleGroupBox (); + + + if (s_lastWidth > 0 && s_lastHeight > 0) + resize (s_lastWidth, s_lastHeight); + + + slotUpdate (); + + + m_horizontalSkewInput->setEditFocus (); +} + +kpToolSkewDialog::~kpToolSkewDialog () +{ + s_lastWidth = width (), s_lastHeight = height (); +} + + +// private +void kpToolSkewDialog::createAngleGroupBox () +{ + QGroupBox *angleGroupBox = new QGroupBox (i18n ("Angle"), mainWidget ()); + addCustomWidget (angleGroupBox); + + + QLabel *horizontalSkewPixmapLabel = new QLabel (angleGroupBox); + horizontalSkewPixmapLabel->setPixmap (UserIcon ("image_skew_horizontal")); + + QLabel *horizontalSkewLabel = new QLabel (i18n ("&Horizontal:"), angleGroupBox); + m_horizontalSkewInput = new KIntNumInput (s_lastHorizontalAngle, angleGroupBox); + m_horizontalSkewInput->setMinValue (-89); + m_horizontalSkewInput->setMaxValue (+89); + + QLabel *horizontalSkewDegreesLabel = new QLabel (i18n ("degrees"), angleGroupBox); + + + QLabel *verticalSkewPixmapLabel = new QLabel (angleGroupBox); + verticalSkewPixmapLabel->setPixmap (UserIcon ("image_skew_vertical")); + + QLabel *verticalSkewLabel = new QLabel (i18n ("&Vertical:"), angleGroupBox); + m_verticalSkewInput = new KIntNumInput (s_lastVerticalAngle, angleGroupBox); + m_verticalSkewInput->setMinValue (-89); + m_verticalSkewInput->setMaxValue (+89); + + QLabel *verticalSkewDegreesLabel = new QLabel (i18n ("degrees"), angleGroupBox); + + + horizontalSkewLabel->setBuddy (m_horizontalSkewInput); + verticalSkewLabel->setBuddy (m_verticalSkewInput); + + + QGridLayout *angleLayout = new QGridLayout (angleGroupBox, 4, 4, + marginHint () * 2, spacingHint ()); + + angleLayout->addWidget (horizontalSkewPixmapLabel, 0, 0); + angleLayout->addWidget (horizontalSkewLabel, 0, 1); + angleLayout->addWidget (m_horizontalSkewInput, 0, 2); + angleLayout->addWidget (horizontalSkewDegreesLabel, 0, 3); + + angleLayout->addWidget (verticalSkewPixmapLabel, 1, 0); + angleLayout->addWidget (verticalSkewLabel, 1, 1); + angleLayout->addWidget (m_verticalSkewInput, 1, 2); + angleLayout->addWidget (verticalSkewDegreesLabel, 1, 3); + + + connect (m_horizontalSkewInput, SIGNAL (valueChanged (int)), + this, SLOT (slotUpdate ())); + connect (m_verticalSkewInput, SIGNAL (valueChanged (int)), + this, SLOT (slotUpdate ())); +} + + +// private virtual [base kpToolPreviewDialog] +QSize kpToolSkewDialog::newDimensions () const +{ + kpDocument *doc = document (); + if (!doc) + return QSize (); + + QWMatrix skewMatrix = kpPixmapFX::skewMatrix (*doc->pixmap (), + horizontalAngleForPixmapFX (), + verticalAngleForPixmapFX ()); + // TODO: Should we be using QWMatrix::Areas? + QRect skewRect = skewMatrix.mapRect (doc->rect (m_actOnSelection)); + + return QSize (skewRect.width (), skewRect.height ()); +} + +// private virtual [base kpToolPreviewDialog] +QPixmap kpToolSkewDialog::transformPixmap (const QPixmap &pixmap, + int targetWidth, int targetHeight) const +{ + return kpPixmapFX::skew (pixmap, + horizontalAngleForPixmapFX (), + verticalAngleForPixmapFX (), + m_mainWindow ? m_mainWindow->backgroundColor (m_actOnSelection) : kpColor::invalid, + targetWidth, + targetHeight); +} + + +// private +void kpToolSkewDialog::updateLastAngles () +{ + s_lastHorizontalAngle = horizontalAngle (); + s_lastVerticalAngle = verticalAngle (); +} + +// private slot virtual [base kpToolPreviewDialog] +void kpToolSkewDialog::slotUpdate () +{ + updateLastAngles (); + kpToolPreviewDialog::slotUpdate (); +} + + +// public +int kpToolSkewDialog::horizontalAngle () const +{ + return m_horizontalSkewInput->value (); +} + +// public +int kpToolSkewDialog::verticalAngle () const +{ + return m_verticalSkewInput->value (); +} + + +// public static +int kpToolSkewDialog::horizontalAngleForPixmapFX (int hangle) +{ + return -hangle; +} + +// public static +int kpToolSkewDialog::verticalAngleForPixmapFX (int vangle) +{ + return -vangle; +} + + +// public +int kpToolSkewDialog::horizontalAngleForPixmapFX () const +{ + return kpToolSkewDialog::horizontalAngleForPixmapFX (horizontalAngle ()); +} + +// public +int kpToolSkewDialog::verticalAngleForPixmapFX () const +{ + return kpToolSkewDialog::verticalAngleForPixmapFX (verticalAngle ()); +} + + +// public virtual [base kpToolPreviewDialog] +bool kpToolSkewDialog::isNoOp () const +{ + return (horizontalAngle () == 0) && (verticalAngle () == 0); +} + + +// private slot virtual [base KDialogBase] +void kpToolSkewDialog::slotOk () +{ + QString message, caption, continueButtonText; + + if (document ()->selection ()) + { + if (!document ()->selection ()->isText ()) + { + message = + i18n ("

Skewing the selection to %1x%2" + " may take a substantial amount of memory." + " This can reduce system" + " responsiveness and cause other application resource" + " problems.

" + + "

Are you sure want to skew the selection?

"); + + caption = i18n ("Skew Selection?"); + continueButtonText = i18n ("Sk&ew Selection"); + } + } + else + { + message = + i18n ("

Skewing the image to %1x%2" + " may take a substantial amount of memory." + " This can reduce system" + " responsiveness and cause other application resource" + " problems.

" + + "

Are you sure want to skew the image?

"); + + caption = i18n ("Skew Image?"); + continueButtonText = i18n ("Sk&ew Image"); + } + + + const int newWidth = newDimensions ().width (); + const int newHeight = newDimensions ().height (); + + if (kpTool::warnIfBigImageSize (m_oldWidth, + m_oldHeight, + newWidth, newHeight, + message.arg (newWidth).arg (newHeight), + caption, + continueButtonText, + this)) + { + KDialogBase::slotOk (); + } +} + +#include diff --git a/kolourpaint/tools/kptoolskew.h b/kolourpaint/tools/kptoolskew.h new file mode 100644 index 00000000..570909c2 --- /dev/null +++ b/kolourpaint/tools/kptoolskew.h @@ -0,0 +1,121 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kptool_skew_h__ +#define __kptool_skew_h__ + +#include + +#include +#include + +#include +#include +#include + +class QGroupBox; +class QLabel; +class QPixmap; + +class KIntNumInput; + +class kpDocument; +class kpMainWindow; + + +class kpToolSkewCommand : public kpCommand +{ +public: + kpToolSkewCommand (bool actOnSelection, + int hangle, int vangle, + kpMainWindow *mainWindow); + virtual ~kpToolSkewCommand (); + + virtual QString name () const; + + virtual int size () const; + + virtual void execute (); + virtual void unexecute (); + +private: + bool m_actOnSelection; + int m_hangle, m_vangle; + + kpColor m_backgroundColor; + QPixmap *m_oldPixmapPtr; + kpSelection m_oldSelection; +}; + + +class kpToolSkewDialog : public kpToolPreviewDialog +{ +Q_OBJECT + +public: + kpToolSkewDialog (bool actOnSelection, kpMainWindow *parent, + const char *name = 0); + virtual ~kpToolSkewDialog (); + +private: + static int s_lastWidth, s_lastHeight; + static int s_lastHorizontalAngle, s_lastVerticalAngle; + + void createAngleGroupBox (); + + virtual QSize newDimensions () const; + virtual QPixmap transformPixmap (const QPixmap &pixmap, + int targetWidth, int targetHeight) const; + + void updateLastAngles (); + +private slots: + virtual void slotUpdate (); + +public: + // These are the angles the users sees in the dialog and... + int horizontalAngle () const; + int verticalAngle () const; + + // ...these functions translate them for use in kpPixmapFX::skew(). + static int horizontalAngleForPixmapFX (int hangle); + static int verticalAngleForPixmapFX (int vangle); + + int horizontalAngleForPixmapFX () const; + int verticalAngleForPixmapFX () const; + + virtual bool isNoOp () const; + +private slots: + virtual void slotOk (); + +private: + KIntNumInput *m_horizontalSkewInput, *m_verticalSkewInput; +}; + +#endif // __kptool_skew_h__ diff --git a/kolourpaint/tools/kptooltext.cpp b/kolourpaint/tools/kptooltext.cpp new file mode 100644 index 00000000..73a60e66 --- /dev/null +++ b/kolourpaint/tools/kptooltext.cpp @@ -0,0 +1,1394 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_TOOL_TEXT 0 + + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + + +kpToolText::kpToolText (kpMainWindow *mainWindow) + : kpToolSelection (Text, + i18n ("Text"), i18n ("Writes text"), + Qt::Key_T, + mainWindow, "tool_text"), + m_isIMStarted (false), + m_IMStartCursorRow (0), + m_IMStartCursorCol (0), + m_IMPreeditStr (0) +{ +} + +kpToolText::~kpToolText () +{ +} + + +// public virtual [base kpToolSelection] +void kpToolText::begin () +{ +#if DEBUG_KP_TOOL_TEXT && 1 + kdDebug () << "kpToolText::begin()" << endl; +#endif + + mainWindow ()->enableTextToolBarActions (true); + viewManager ()->setTextCursorEnabled (true); + + m_insertCommand = 0; + m_enterCommand = 0; + m_backspaceCommand = 0; + m_deleteCommand = 0; + + kpToolSelection::begin (); +} + +// public virtual [base kpToolSelection] +void kpToolText::end () +{ +#if DEBUG_KP_TOOL_TEXT && 1 + kdDebug () << "kpToolText::end()" << endl; +#endif + + kpToolSelection::end (); + + viewManager ()->setTextCursorEnabled (false); + mainWindow ()->enableTextToolBarActions (false); +} + + +// public +bool kpToolText::hasBegunText () const +{ + return (m_insertCommand || + m_enterCommand || + m_backspaceCommand || + m_deleteCommand); +} + +// public virtual [base kpTool] +bool kpToolText::hasBegunShape () const +{ + return (hasBegunDraw () || hasBegunText ()); +} + + +// public virtual [base kpToolSelection] +void kpToolText::cancelShape () +{ +#if DEBUG_KP_TOOL_TEXT + kdDebug () << "kpToolText::cancelShape()" << endl; +#endif + + if (m_dragType != Unknown) + kpToolSelection::cancelShape (); + else if (hasBegunText ()) + { + m_insertCommand = 0; + m_enterCommand = 0; + m_backspaceCommand = 0; + m_deleteCommand = 0; + + commandHistory ()->undo (); + } + else + kpToolSelection::cancelShape (); +} + +// public virtual [base kpTool] +void kpToolText::endShape (const QPoint &thisPoint, const QRect &normalizedRect) +{ +#if DEBUG_KP_TOOL_TEXT + kdDebug () << "kpToolText::endShape()" << endl; +#endif + + if (m_dragType != Unknown) + kpToolSelection::endDraw (thisPoint, normalizedRect); + else if (hasBegunText ()) + { + m_insertCommand = 0; + m_enterCommand = 0; + m_backspaceCommand = 0; + m_deleteCommand = 0; + } + else + kpToolSelection::endDraw (thisPoint, normalizedRect); +} + + +// protected virtual [base kpTool] +void kpToolText::keyPressEvent (QKeyEvent *e) +{ +#if DEBUG_KP_TOOL_TEXT + kdDebug () << "kpToolText::keyPressEvent(e->text='" << e->text () << "')" << endl; +#endif + + + e->ignore (); + + + if (hasBegunDraw ()) + { + #if DEBUG_KP_TOOL_TEXT + kdDebug () << "\talready began draw with mouse - passing on event to kpTool" << endl; + #endif + kpToolSelection::keyPressEvent (e); + return; + } + + + kpSelection *sel = document ()->selection (); + + if (!sel || !sel->isText ()) + { + #if DEBUG_KP_TOOL_TEXT + kdDebug () << "\tno text sel - passing on event to kpTool" << endl; + #endif + //if (hasBegunShape ()) + // endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + + kpToolSelection::keyPressEvent (e); + return; + } + + + const QValueVector textLines = sel->textLines (); + int cursorRow = viewManager ()->textCursorRow (); + int cursorCol = viewManager ()->textCursorCol (); + + +#define IS_SPACE(c) ((c).isSpace () || (c).isNull ()) + if (e->key () == Qt::Key_Enter || e->key () == Qt::Key_Return) + { + #if DEBUG_KP_TOOL_TEXT + kdDebug () << "\tenter pressed" << endl; + #endif + if (!m_enterCommand) + { + // TODO: why not endShapeInternal(); ditto for everywhere else in this file? + if (hasBegunShape ()) + endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + + m_enterCommand = new kpToolTextEnterCommand (i18n ("Text: New Line"), + viewManager ()->textCursorRow (), viewManager ()->textCursorCol (), + mainWindow ()); + commandHistory ()->addCommand (m_enterCommand, false/*no exec*/); + } + else + m_enterCommand->addEnter (); + + e->accept (); + } + else if (e->key () == Qt::Key_Backspace) + { + #if DEBUG_KP_TOOL_TEXT + kdDebug () << "\tbackspace pressed" << endl; + #endif + + if (!m_backspaceCommand) + { + if (hasBegunShape ()) + endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + + m_backspaceCommand = new kpToolTextBackspaceCommand (i18n ("Text: Backspace"), + viewManager ()->textCursorRow (), viewManager ()->textCursorCol (), + mainWindow ()); + commandHistory ()->addCommand (m_backspaceCommand, false/*no exec*/); + } + else + m_backspaceCommand->addBackspace (); + + e->accept (); + } + else if (e->key () == Qt::Key_Delete) + { + #if DEBUG_KP_TOOL_TEXT + kdDebug () << "\tdelete pressed" << endl; + #endif + + if (!m_deleteCommand) + { + if (hasBegunShape ()) + endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + + m_deleteCommand = new kpToolTextDeleteCommand (i18n ("Text: Delete"), + viewManager ()->textCursorRow (), viewManager ()->textCursorCol (), + mainWindow ()); + commandHistory ()->addCommand (m_deleteCommand, false/*no exec*/); + } + else + m_deleteCommand->addDelete (); + + e->accept (); + } + else if (e->key () == Qt::Key_Up) + { + #if DEBUG_KP_TOOL_TEXT + kdDebug () << "\tup pressed" << endl; + #endif + + if (hasBegunShape ()) + endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + + if (cursorRow > 0) + { + cursorRow--; + cursorCol = QMIN (cursorCol, (int) textLines [cursorRow].length ()); + viewManager ()->setTextCursorPosition (cursorRow, cursorCol); + } + + e->accept (); + } + else if (e->key () == Qt::Key_Down) + { + #if DEBUG_KP_TOOL_TEXT + kdDebug () << "\tdown pressed" << endl; + #endif + + if (hasBegunShape ()) + endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + + if (cursorRow < (int) textLines.size () - 1) + { + cursorRow++; + cursorCol = QMIN (cursorCol, (int) textLines [cursorRow].length ()); + viewManager ()->setTextCursorPosition (cursorRow, cursorCol); + } + + e->accept (); + } + else if (e->key () == Qt::Key_Left) + { + #if DEBUG_KP_TOOL_TEXT + kdDebug () << "\tleft pressed" << endl; + #endif + + #define MOVE_CURSOR_LEFT() \ + { \ + cursorCol--; \ + \ + if (cursorCol < 0) \ + { \ + cursorRow--; \ + if (cursorRow < 0) \ + { \ + cursorRow = 0; \ + cursorCol = 0; \ + } \ + else \ + cursorCol = textLines [cursorRow].length (); \ + } \ + } + + if (hasBegunShape ()) + endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + + if ((e->state () & Qt::ControlButton) == 0) + { + #if DEBUG_KP_TOOL_TEXT + kdDebug () << "\tmove single char" << endl; + #endif + + MOVE_CURSOR_LEFT (); + viewManager ()->setTextCursorPosition (cursorRow, cursorCol); + } + else + { + #if DEBUG_KP_TOOL_TEXT + kdDebug () << "\tmove to start of word" << endl; + #endif + + // (these comments will exclude the row=0,col=0 boundary case) + + #define IS_ON_ANCHOR() (!IS_SPACE (textLines [cursorRow][cursorCol]) && \ + (cursorCol == 0 || IS_SPACE (textLines [cursorRow][cursorCol - 1]))) + if (IS_ON_ANCHOR ()) + MOVE_CURSOR_LEFT (); + + // --- now we're not on an anchor point (start of word) --- + + // End up on a letter... + while (!(cursorRow == 0 && cursorCol == 0) && + (IS_SPACE (textLines [cursorRow][cursorCol]))) + { + MOVE_CURSOR_LEFT (); + } + + // --- now we're on a letter --- + + // Find anchor point + while (!(cursorRow == 0 && cursorCol == 0) && !IS_ON_ANCHOR ()) + { + MOVE_CURSOR_LEFT (); + } + + #undef IS_ON_ANCHOR + + viewManager ()->setTextCursorPosition (cursorRow, cursorCol); + } + + #undef MOVE_CURSOR_LEFT + + e->accept (); + + } + else if (e->key () == Qt::Key_Right) + { + #if DEBUG_KP_TOOL_TEXT + kdDebug () << "\tright pressed" << endl; + #endif + + #define MOVE_CURSOR_RIGHT() \ + { \ + cursorCol++; \ + \ + if (cursorCol > (int) textLines [cursorRow].length ()) \ + { \ + cursorRow++; \ + if (cursorRow > (int) textLines.size () - 1) \ + { \ + cursorRow = textLines.size () - 1; \ + cursorCol = textLines [cursorRow].length (); \ + } \ + else \ + cursorCol = 0; \ + } \ + } + + if (hasBegunShape ()) + endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + + if ((e->state () & Qt::ControlButton) == 0) + { + #if DEBUG_KP_TOOL_TEXT + kdDebug () << "\tmove single char" << endl; + #endif + + MOVE_CURSOR_RIGHT (); + viewManager ()->setTextCursorPosition (cursorRow, cursorCol); + } + else + { + #if DEBUG_KP_TOOL_TEXT + kdDebug () << "\tmove to start of word" << endl; + #endif + + // (these comments will exclude the last row,end col boundary case) + + #define IS_AT_END() (cursorRow == (int) textLines.size () - 1 && \ + cursorCol == (int) textLines [cursorRow].length ()) + + // Find space + while (!IS_AT_END () && !IS_SPACE (textLines [cursorRow][cursorCol])) + { + MOVE_CURSOR_RIGHT (); + } + + // --- now we're on a space --- + + // Find letter + while (!IS_AT_END () && IS_SPACE (textLines [cursorRow][cursorCol])) + { + MOVE_CURSOR_RIGHT (); + } + + // --- now we're on a letter --- + + viewManager ()->setTextCursorPosition (cursorRow, cursorCol); + + #undef IS_AT_END + } + + #undef MOVE_CURSOR_RIGHT + + e->accept (); + } + else if (e->key () == Qt::Key_Home) + { + #if DEBUG_KP_TOOL_TEXT + kdDebug () << "\thome pressed" << endl; + #endif + + if (hasBegunShape ()) + endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + + if (e->state () & Qt::ControlButton) + cursorRow = 0; + + cursorCol = 0; + + viewManager ()->setTextCursorPosition (cursorRow, cursorCol); + + e->accept (); + } + else if (e->key () == Qt::Key_End) + { + #if DEBUG_KP_TOOL_TEXT + kdDebug () << "\tend pressed" << endl; + #endif + + if (hasBegunShape ()) + endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + + if (e->state () & Qt::ControlButton) + cursorRow = textLines.size () - 1; + + cursorCol = textLines [cursorRow].length (); + + viewManager ()->setTextCursorPosition (cursorRow, cursorCol); + + e->accept (); + } + else + { + #if DEBUG_KP_TOOL_TEXT + kdDebug () << "\ttext='" << e->text () << "'" << endl; + #endif + QString usableText; + for (int i = 0; i < (int) e->text ().length (); i++) + { + if (e->text ().at (i).isPrint ()) + usableText += e->text ().at (i); + } + #if DEBUG_KP_TOOL_TEXT + kdDebug () << "\tusableText='" << usableText << "'" << endl; + #endif + + if (usableText.length () > 0) + { + if (!m_insertCommand) + { + if (hasBegunShape ()) + endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + + m_insertCommand = new kpToolTextInsertCommand (i18n ("Text: Write"), + viewManager ()->textCursorRow (), viewManager ()->textCursorCol (), + usableText, + mainWindow ()); + commandHistory ()->addCommand (m_insertCommand, false/*no exec*/); + } + else + m_insertCommand->addText (usableText); + + e->accept (); + } + } +#undef IS_SPACE + + + if (!e->isAccepted ()) + { + #if DEBUG_KP_TOOL_TEXT + kdDebug () << "\tkey processing did not accept (text was '" + << e->text () + << "') - passing on event to kpToolSelection" + << endl; + #endif + //if (hasBegunShape ()) + // endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + + kpToolSelection::keyPressEvent (e); + return; + } +} + +void kpToolText::imStartEvent (QIMEvent *e) +{ +#if DEBUG_KP_TOOL_TEXT && 1 + kdDebug () << "kpToolText::imStartEvent() text='" << e->text () + << " cursorPos=" << e->cursorPos () + << " selectionLength=" << e->selectionLength () + << endl; +#endif + + kpSelection *sel = document ()->selection (); + if (hasBegunDraw() || !sel || !sel->isText ()) + { + e->ignore(); + return; + } + + m_IMStartCursorRow = viewManager ()->textCursorRow (); + m_IMStartCursorCol = viewManager ()->textCursorCol (); + m_IMPreeditStr = QString::null; +} + +void kpToolText::imComposeEvent (QIMEvent *e) +{ +#if DEBUG_KP_TOOL_TEXT && 1 + kdDebug () << "kpToolText::imComposeEvent() text='" << e->text () + << " cursorPos=" << e->cursorPos () + << " selectionLength=" << e->selectionLength () + << endl; +#endif + + kpSelection *sel = document ()->selection (); + if (hasBegunDraw() || !sel || !sel->isText ()) + { + e->ignore(); + return; + } + + // remove old preedit + if (m_IMPreeditStr.length() > 0 ) + { + // set cursor at the start input point + viewManager ()->setTextCursorPosition (m_IMStartCursorRow, m_IMStartCursorCol); + for (unsigned int i = 0; i < m_IMPreeditStr.length(); i++) + { + if (!m_deleteCommand) + { + if (hasBegunShape ()) + endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + + m_deleteCommand = new kpToolTextDeleteCommand (i18n ("Text: Delete"), + viewManager ()->textCursorRow (), viewManager ()->textCursorCol (), + mainWindow ()); + commandHistory ()->addCommand (m_deleteCommand, false/*no exec*/); + } + else + m_deleteCommand->addDelete (); + } + } + + // insert new preedit + m_IMPreeditStr = e->text(); + if (m_IMPreeditStr.length() > 0) + { + if (!m_insertCommand) + { + if (hasBegunShape ()) + endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + + m_insertCommand = new kpToolTextInsertCommand (i18n ("Text: Write"), + viewManager ()->textCursorRow (), viewManager ()->textCursorCol (), + m_IMPreeditStr, + mainWindow ()); + commandHistory ()->addCommand (m_insertCommand, false/*no exec*/); + } + else + m_insertCommand->addText (m_IMPreeditStr); + } + + // set cursor pos + if (m_IMStartCursorRow >= 0) + { + int row = m_IMStartCursorRow; + int col = m_IMStartCursorCol + e->cursorPos () /* + e->selectionLength()*/; + viewManager ()->setTextCursorPosition (row, col, true /* update MicroFocusHint */); + } +} + +void kpToolText::imEndEvent (QIMEvent *e) +{ +#if DEBUG_KP_TOOL_TEXT && 1 + kdDebug () << "kpToolText::imEndEvent() text='" << e->text () + << " cursorPos=" << e->cursorPos () + << " selectionLength=" << e->selectionLength () + << endl; +#endif + + kpSelection *sel = document ()->selection (); + if (hasBegunDraw() || !sel || !sel->isText ()) + { + e->ignore(); + return; + } + + // remove old preedit + if (m_IMPreeditStr.length() > 0 ) + { + // set cursor at the start input point + viewManager ()->setTextCursorPosition (m_IMStartCursorRow, m_IMStartCursorCol); + for (unsigned int i = 0; i < m_IMPreeditStr.length(); i++) + { + if (!m_deleteCommand) + { + if (hasBegunShape ()) + endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + + m_deleteCommand = new kpToolTextDeleteCommand (i18n ("Text: Delete"), + viewManager ()->textCursorRow (), viewManager ()->textCursorCol (), + mainWindow ()); + commandHistory ()->addCommand (m_deleteCommand, false/*no exec*/); + } + else + m_deleteCommand->addDelete (); + } + } + m_IMPreeditStr = QString::null; + + // commit string + QString inputStr = e->text(); + if (inputStr.length() > 0) + { + if (!m_insertCommand) + { + if (hasBegunShape ()) + endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + + m_insertCommand = new kpToolTextInsertCommand (i18n ("Text: Write"), + viewManager ()->textCursorRow (), viewManager ()->textCursorCol (), + inputStr, + mainWindow ()); + commandHistory ()->addCommand (m_insertCommand, false/*no exec*/); + } + else + m_insertCommand->addText (inputStr); + } +} + + +// protected +bool kpToolText::shouldChangeTextStyle () const +{ + if (mainWindow ()->settingTextStyle ()) + { + #if DEBUG_KP_TOOL_TEXT + kdDebug () << "\trecursion - abort setting text style: " + << mainWindow ()->settingTextStyle () + << endl; + #endif + return false; + } + + if (!document ()->selection () || + !document ()->selection ()->isText ()) + { + #if DEBUG_KP_TOOL_TEXT + kdDebug () << "\tno text selection - abort setting text style" << endl; + #endif + return false; + } + + return true; +} + +// protected +void kpToolText::changeTextStyle (const QString &name, + const kpTextStyle &newTextStyle, + const kpTextStyle &oldTextStyle) +{ +#if DEBUG_KP_TOOL_TEXT + kdDebug () << "kpToolText::changeTextStyle(" << name << ")" << endl; +#endif + + if (hasBegunShape ()) + endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ()); + + commandHistory ()->addCommand ( + new kpToolTextChangeStyleCommand ( + name, + newTextStyle, + oldTextStyle, + mainWindow ())); +} + + +// protected slot virtual [base kpToolSelection] +void kpToolText::slotIsOpaqueChanged () +{ +#if DEBUG_KP_TOOL_TEXT + kdDebug () << "kpToolText::slotIsOpaqueChanged()" << endl; +#endif + + if (!shouldChangeTextStyle ()) + return; + + kpTextStyle newTextStyle = mainWindow ()->textStyle (); + kpTextStyle oldTextStyle = newTextStyle; + oldTextStyle.setBackgroundOpaque (!m_toolWidgetOpaqueOrTransparent->isOpaque ()); + + changeTextStyle (newTextStyle.isBackgroundOpaque () ? + i18n ("Text: Opaque Background") : + i18n ("Text: Transparent Background"), + newTextStyle, + oldTextStyle); +} + +// protected slot virtual [base kpTool] +void kpToolText::slotColorsSwapped (const kpColor &newForegroundColor, + const kpColor &newBackgroundColor) +{ +#if DEBUG_KP_TOOL_TEXT + kdDebug () << "kpToolText::slotColorsSwapped()" << endl; +#endif + + if (!shouldChangeTextStyle ()) + return; + + kpTextStyle newTextStyle = mainWindow ()->textStyle (); + kpTextStyle oldTextStyle = newTextStyle; + oldTextStyle.setForegroundColor (newBackgroundColor); + oldTextStyle.setBackgroundColor (newForegroundColor); + + changeTextStyle (i18n ("Text: Swap Colors"), + newTextStyle, + oldTextStyle); +} + +// protected slot virtual [base kpTool] +void kpToolText::slotForegroundColorChanged (const kpColor & /*color*/) +{ +#if DEBUG_KP_TOOL_TEXT + kdDebug () << "kpToolText::slotForegroundColorChanged()" << endl; +#endif + + if (!shouldChangeTextStyle ()) + return; + + kpTextStyle newTextStyle = mainWindow ()->textStyle (); + kpTextStyle oldTextStyle = newTextStyle; + oldTextStyle.setForegroundColor (oldForegroundColor ()); + + changeTextStyle (i18n ("Text: Foreground Color"), + newTextStyle, + oldTextStyle); +} + +// protected slot virtual [base kpToolSelection] +void kpToolText::slotBackgroundColorChanged (const kpColor & /*color*/) +{ +#if DEBUG_KP_TOOL_TEXT + kdDebug () << "kpToolText::slotBackgroundColorChanged()" << endl; +#endif + + if (!shouldChangeTextStyle ()) + return; + + kpTextStyle newTextStyle = mainWindow ()->textStyle (); + kpTextStyle oldTextStyle = newTextStyle; + oldTextStyle.setBackgroundColor (oldBackgroundColor ()); + + changeTextStyle (i18n ("Text: Background Color"), + newTextStyle, + oldTextStyle); +} + +// protected slot virtual [base kpToolSelection] +void kpToolText::slotColorSimilarityChanged (double, int) +{ + // --- don't pass on event to kpToolSelection which would have set the + // SelectionTransparency - not relevant to the Text Tool --- +} + + +// public slot +void kpToolText::slotFontFamilyChanged (const QString &fontFamily, + const QString &oldFontFamily) +{ +#if DEBUG_KP_TOOL_TEXT + kdDebug () << "kpToolText::slotFontFamilyChanged() new=" + << fontFamily + << " old=" + << oldFontFamily + << endl; +#else + (void) fontFamily; +#endif + + if (!shouldChangeTextStyle ()) + return; + + kpTextStyle newTextStyle = mainWindow ()->textStyle (); + kpTextStyle oldTextStyle = newTextStyle; + oldTextStyle.setFontFamily (oldFontFamily); + + changeTextStyle (i18n ("Text: Font"), + newTextStyle, + oldTextStyle); +} + +// public slot +void kpToolText::slotFontSizeChanged (int fontSize, int oldFontSize) +{ +#if DEBUG_KP_TOOL_TEXT + kdDebug () << "kpToolText::slotFontSizeChanged() new=" + << fontSize + << " old=" + << oldFontSize + << endl; +#else + (void) fontSize; +#endif + + if (!shouldChangeTextStyle ()) + return; + + kpTextStyle newTextStyle = mainWindow ()->textStyle (); + kpTextStyle oldTextStyle = newTextStyle; + oldTextStyle.setFontSize (oldFontSize); + + changeTextStyle (i18n ("Text: Font Size"), + newTextStyle, + oldTextStyle); +} + + +// public slot +void kpToolText::slotBoldChanged (bool isBold) +{ +#if DEBUG_KP_TOOL_TEXT + kdDebug () << "kpToolText::slotBoldChanged(" << isBold << ")" << endl; +#endif + + if (!shouldChangeTextStyle ()) + return; + + kpTextStyle newTextStyle = mainWindow ()->textStyle (); + kpTextStyle oldTextStyle = newTextStyle; + oldTextStyle.setBold (!isBold); + + changeTextStyle (i18n ("Text: Bold"), + newTextStyle, + oldTextStyle); +} + +// public slot +void kpToolText::slotItalicChanged (bool isItalic) +{ +#if DEBUG_KP_TOOL_TEXT + kdDebug () << "kpToolText::slotItalicChanged(" << isItalic << ")" << endl; +#endif + + if (!shouldChangeTextStyle ()) + return; + + kpTextStyle newTextStyle = mainWindow ()->textStyle (); + kpTextStyle oldTextStyle = newTextStyle; + oldTextStyle.setItalic (!isItalic); + + changeTextStyle (i18n ("Text: Italic"), + newTextStyle, + oldTextStyle); +} + +// public slot +void kpToolText::slotUnderlineChanged (bool isUnderline) +{ +#if DEBUG_KP_TOOL_TEXT + kdDebug () << "kpToolText::slotUnderlineChanged(" << isUnderline << ")" << endl; +#endif + + if (!shouldChangeTextStyle ()) + return; + + kpTextStyle newTextStyle = mainWindow ()->textStyle (); + kpTextStyle oldTextStyle = newTextStyle; + oldTextStyle.setUnderline (!isUnderline); + + changeTextStyle (i18n ("Text: Underline"), + newTextStyle, + oldTextStyle); +} + +// public slot +void kpToolText::slotStrikeThruChanged (bool isStrikeThru) +{ +#if DEBUG_KP_TOOL_TEXT + kdDebug () << "kpToolText::slotStrikeThruChanged(" << isStrikeThru << ")" << endl; +#endif + + if (!shouldChangeTextStyle ()) + return; + + kpTextStyle newTextStyle = mainWindow ()->textStyle (); + kpTextStyle oldTextStyle = newTextStyle; + oldTextStyle.setStrikeThru (!isStrikeThru); + + changeTextStyle (i18n ("Text: Strike Through"), + newTextStyle, + oldTextStyle); +} + + +/* + * kpToolTextChangeStyleCommand + */ + +kpToolTextChangeStyleCommand::kpToolTextChangeStyleCommand (const QString &name, + const kpTextStyle &newTextStyle, const kpTextStyle &oldTextStyle, + kpMainWindow *mainWindow) + : kpNamedCommand (name, mainWindow), + m_newTextStyle (newTextStyle), + m_oldTextStyle (oldTextStyle) +{ +} + +kpToolTextChangeStyleCommand::~kpToolTextChangeStyleCommand () +{ +} + + +// public virtual [base kpCommand] +int kpToolTextChangeStyleCommand::size () const +{ + return 0; +} + + +// public virtual [base kpCommand] +void kpToolTextChangeStyleCommand::execute () +{ +#if DEBUG_KP_TOOL_TEXT && 1 + kdDebug () << "kpToolTextChangeStyleCommand::execute()" + << " font=" << m_newTextStyle.fontFamily () + << " fontSize=" << m_newTextStyle.fontSize () + << " isBold=" << m_newTextStyle.isBold () + << " isItalic=" << m_newTextStyle.isItalic () + << " isUnderline=" << m_newTextStyle.isUnderline () + << " isStrikeThru=" << m_newTextStyle.isStrikeThru () + << endl; +#endif + + m_mainWindow->setTextStyle (m_newTextStyle); + if (selection ()) + selection ()->setTextStyle (m_newTextStyle); + else + kdError () << "kpToolTextChangeStyleCommand::execute() without sel" << endl; +} + +// public virtual [base kpCommand] +void kpToolTextChangeStyleCommand::unexecute () +{ +#if DEBUG_KP_TOOL_TEXT && 1 + kdDebug () << "kpToolTextChangeStyleCommand::unexecute()" + << " font=" << m_newTextStyle.fontFamily () + << " fontSize=" << m_newTextStyle.fontSize () + << " isBold=" << m_newTextStyle.isBold () + << " isItalic=" << m_newTextStyle.isItalic () + << " isUnderline=" << m_newTextStyle.isUnderline () + << " isStrikeThru=" << m_newTextStyle.isStrikeThru () + << endl; +#endif + + m_mainWindow->setTextStyle (m_oldTextStyle); + if (selection ()) + selection ()->setTextStyle (m_oldTextStyle); + else + kdError () << "kpToolTextChangeStyleCommand::unexecute() without sel" << endl; +} + + +/* + * kpToolTextInsertCommand + */ + +kpToolTextInsertCommand::kpToolTextInsertCommand (const QString &name, + int row, int col, QString newText, + kpMainWindow *mainWindow) + : kpNamedCommand (name, mainWindow), + m_row (row), m_col (col) +{ + viewManager ()->setTextCursorPosition (m_row, m_col); + addText (newText); +} + +kpToolTextInsertCommand::~kpToolTextInsertCommand () +{ +} + + +// public +void kpToolTextInsertCommand::addText (const QString &moreText) +{ + if (moreText.isEmpty ()) + return; + + QValueVector textLines = selection ()->textLines (); + const QString leftHalf = textLines [m_row].left (m_col); + const QString rightHalf = textLines [m_row].mid (m_col); + textLines [m_row] = leftHalf + moreText + rightHalf; + selection ()->setTextLines (textLines); + + m_newText += moreText; + m_col += moreText.length (); + + viewManager ()->setTextCursorPosition (m_row, m_col); +} + + +// public virtual [base kpCommand] +int kpToolTextInsertCommand::size () const +{ + return m_newText.length () * sizeof (QChar); +} + + +// public virtual [base kpCommand] +void kpToolTextInsertCommand::execute () +{ + viewManager ()->setTextCursorPosition (m_row, m_col); + + QString text = m_newText; + m_newText = QString::null; + addText (text); +} + +// public virtual [base kpCommand] +void kpToolTextInsertCommand::unexecute () +{ + viewManager ()->setTextCursorPosition (m_row, m_col); + + QValueVector textLines = selection ()->textLines (); + const QString leftHalf = textLines [m_row].left (m_col - m_newText.length ()); + const QString rightHalf = textLines [m_row].mid (m_col); + textLines [m_row] = leftHalf + rightHalf; + selection ()->setTextLines (textLines); + + m_col -= m_newText.length (); + + viewManager ()->setTextCursorPosition (m_row, m_col); +} + + +/* + * kpToolTextEnterCommand + */ + +kpToolTextEnterCommand::kpToolTextEnterCommand (const QString &name, + int row, int col, + kpMainWindow *mainWindow) + : kpNamedCommand (name, mainWindow), + m_row (row), m_col (col), + m_numEnters (0) +{ + viewManager ()->setTextCursorPosition (m_row, m_col); + addEnter (); +} + +kpToolTextEnterCommand::~kpToolTextEnterCommand () +{ +} + + +// public +void kpToolTextEnterCommand::addEnter () +{ + QValueVector textLines = selection ()->textLines (); + + const QString rightHalf = textLines [m_row].mid (m_col); + + textLines [m_row].truncate (m_col); + textLines.insert (textLines.begin () + m_row + 1, rightHalf); + + selection ()->setTextLines (textLines); + + m_row++; + m_col = 0; + + viewManager ()->setTextCursorPosition (m_row, m_col); + + m_numEnters++; +} + + +// public virtual [base kpCommand] +int kpToolTextEnterCommand::size () const +{ + return 0; +} + + +// public virtual [base kpCommand] +void kpToolTextEnterCommand::execute () +{ + viewManager ()->setTextCursorPosition (m_row, m_col); + int oldNumEnters = m_numEnters; + m_numEnters = 0; + + for (int i = 0; i < oldNumEnters; i++) + addEnter (); +} + +// public virtual [base kpCommand] +void kpToolTextEnterCommand::unexecute () +{ + viewManager ()->setTextCursorPosition (m_row, m_col); + + QValueVector textLines = selection ()->textLines (); + + for (int i = 0; i < m_numEnters; i++) + { + if (m_col != 0) + { + kdError () << "kpToolTextEnterCommand::unexecute() col=" << m_col << endl; + break; + } + + if (m_row <= 0) + break; + + int newRow = m_row - 1; + int newCol = textLines [newRow].length (); + + textLines [newRow] += textLines [m_row]; + + textLines.erase (textLines.begin () + m_row); + + m_row = newRow; + m_col = newCol; + } + + selection ()->setTextLines (textLines); + + viewManager ()->setTextCursorPosition (m_row, m_col); +} + + +/* + * kpToolTextBackspaceCommand + */ + +kpToolTextBackspaceCommand::kpToolTextBackspaceCommand (const QString &name, + int row, int col, + kpMainWindow *mainWindow) + : kpNamedCommand (name, mainWindow), + m_row (row), m_col (col), + m_numBackspaces (0) +{ + viewManager ()->setTextCursorPosition (m_row, m_col); + addBackspace (); +} + +kpToolTextBackspaceCommand::~kpToolTextBackspaceCommand () +{ +} + + +// public +void kpToolTextBackspaceCommand::addBackspace () +{ + QValueVector textLines = selection ()->textLines (); + + if (m_col > 0) + { + m_deletedText.prepend (textLines [m_row][m_col - 1]); + + textLines [m_row] = textLines [m_row].left (m_col - 1) + + textLines [m_row].mid (m_col); + m_col--; + } + else + { + if (m_row > 0) + { + int newCursorRow = m_row - 1; + int newCursorCol = textLines [newCursorRow].length (); + + m_deletedText.prepend ('\n'); + + textLines [newCursorRow] += textLines [m_row]; + + textLines.erase (textLines.begin () + m_row); + + m_row = newCursorRow; + m_col = newCursorCol; + } + } + + selection ()->setTextLines (textLines); + + viewManager ()->setTextCursorPosition (m_row, m_col); + + m_numBackspaces++; +} + + +// public virtual [base kpCommand] +int kpToolTextBackspaceCommand::size () const +{ + return m_deletedText.length () * sizeof (QChar); +} + + +// public virtual [base kpCommand] +void kpToolTextBackspaceCommand::execute () +{ + viewManager ()->setTextCursorPosition (m_row, m_col); + + m_deletedText = QString::null; + int oldNumBackspaces = m_numBackspaces; + m_numBackspaces = 0; + + for (int i = 0; i < oldNumBackspaces; i++) + addBackspace (); +} + +// public virtual [base kpCommand] +void kpToolTextBackspaceCommand::unexecute () +{ + viewManager ()->setTextCursorPosition (m_row, m_col); + + QValueVector textLines = selection ()->textLines (); + + for (int i = 0; i < (int) m_deletedText.length (); i++) + { + if (m_deletedText [i] == '\n') + { + const QString rightHalf = textLines [m_row].mid (m_col); + + textLines [m_row].truncate (m_col); + textLines.insert (textLines.begin () + m_row + 1, rightHalf); + + m_row++; + m_col = 0; + } + else + { + const QString leftHalf = textLines [m_row].left (m_col); + const QString rightHalf = textLines [m_row].mid (m_col); + + textLines [m_row] = leftHalf + m_deletedText [i] + rightHalf; + m_col++; + } + } + + m_deletedText = QString::null; + + selection ()->setTextLines (textLines); + + viewManager ()->setTextCursorPosition (m_row, m_col); +} + + +/* + * kpToolTextDeleteCommand + */ + +kpToolTextDeleteCommand::kpToolTextDeleteCommand (const QString &name, + int row, int col, + kpMainWindow *mainWindow) + : kpNamedCommand (name, mainWindow), + m_row (row), m_col (col), + m_numDeletes (0) +{ + viewManager ()->setTextCursorPosition (m_row, m_col); + addDelete (); +} + +kpToolTextDeleteCommand::~kpToolTextDeleteCommand () +{ +} + + +// public +void kpToolTextDeleteCommand::addDelete () +{ + QValueVector textLines = selection ()->textLines (); + + if (m_col < (int) textLines [m_row].length ()) + { + m_deletedText.prepend (textLines [m_row][m_col]); + + textLines [m_row] = textLines [m_row].left (m_col) + + textLines [m_row].mid (m_col + 1); + } + else + { + if (m_row < (int) textLines.size () - 1) + { + m_deletedText.prepend ('\n'); + + textLines [m_row] += textLines [m_row + 1]; + textLines.erase (textLines.begin () + m_row + 1); + } + } + + selection ()->setTextLines (textLines); + + viewManager ()->setTextCursorPosition (m_row, m_col); + + m_numDeletes++; +} + + +// public virtual [base kpCommand] +int kpToolTextDeleteCommand::size () const +{ + return m_deletedText.length () * sizeof (QChar); +} + + +// public virtual [base kpCommand] +void kpToolTextDeleteCommand::execute () +{ + viewManager ()->setTextCursorPosition (m_row, m_col); + + m_deletedText = QString::null; + int oldNumDeletes = m_numDeletes; + m_numDeletes = 0; + + for (int i = 0; i < oldNumDeletes; i++) + addDelete (); +} + +// public virtual [base kpCommand] +void kpToolTextDeleteCommand::unexecute () +{ + viewManager ()->setTextCursorPosition (m_row, m_col); + + QValueVector textLines = selection ()->textLines (); + + for (int i = 0; i < (int) m_deletedText.length (); i++) + { + if (m_deletedText [i] == '\n') + { + const QString rightHalf = textLines [m_row].mid (m_col); + + textLines [m_row].truncate (m_col); + textLines.insert (textLines.begin () + m_row + 1, rightHalf); + } + else + { + const QString leftHalf = textLines [m_row].left (m_col); + const QString rightHalf = textLines [m_row].mid (m_col); + + textLines [m_row] = leftHalf + m_deletedText [i] + rightHalf; + } + } + + m_deletedText = QString::null; + + selection ()->setTextLines (textLines); + + viewManager ()->setTextCursorPosition (m_row, m_col); +} + + +#include diff --git a/kolourpaint/tools/kptooltext.h b/kolourpaint/tools/kptooltext.h new file mode 100644 index 00000000..a99654b7 --- /dev/null +++ b/kolourpaint/tools/kptooltext.h @@ -0,0 +1,203 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kp_tool_text_h__ +#define __kp_tool_text_h__ + +#include + +#include + +#include +#include + +class kpColor; +class kpMainWindow; +class kpSelection; +class kpViewManager; + +class kpToolText : public kpToolSelection +{ +Q_OBJECT + +public: + kpToolText (kpMainWindow *mainWindow); + virtual ~kpToolText (); + + virtual bool careAboutColorsSwapped () const { return true; } + + virtual void begin (); + virtual void end (); + + bool hasBegunText () const; + virtual bool hasBegunShape () const; + virtual void cancelShape (); + virtual void endShape (const QPoint &thisPoint, const QRect &normalizedRect); + +protected: + virtual void keyPressEvent (QKeyEvent *e); + virtual void imStartEvent (QIMEvent *e); + virtual void imComposeEvent (QIMEvent *e); + virtual void imEndEvent (QIMEvent *e); + +protected: + bool shouldChangeTextStyle () const; + void changeTextStyle (const QString &name, + const kpTextStyle &newTextStyle, + const kpTextStyle &oldTextStyle); + +protected slots: + virtual void slotIsOpaqueChanged (); + virtual void slotColorsSwapped (const kpColor &newForegroundColor, + const kpColor &newBackgroundColor); + virtual void slotForegroundColorChanged (const kpColor &color); + virtual void slotBackgroundColorChanged (const kpColor &color); + virtual void slotColorSimilarityChanged (double, int); + +public slots: + void slotFontFamilyChanged (const QString &fontFamily, const QString &oldFontFamily); + void slotFontSizeChanged (int fontSize, int oldFontSize); + void slotBoldChanged (bool isBold); + void slotItalicChanged (bool isItalic); + void slotUnderlineChanged (bool isUnderline); + void slotStrikeThruChanged (bool isStrikeThru); + +protected: + class kpToolTextInsertCommand *m_insertCommand; + class kpToolTextEnterCommand *m_enterCommand; + class kpToolTextBackspaceCommand *m_backspaceCommand; + class kpToolTextDeleteCommand *m_deleteCommand; + + bool m_isIMStarted; + int m_IMStartCursorRow; + int m_IMStartCursorCol; + QString m_IMPreeditStr; +}; + + +class kpToolTextChangeStyleCommand : public kpNamedCommand +{ +public: + kpToolTextChangeStyleCommand (const QString &name, + const kpTextStyle &newTextStyle, const kpTextStyle &oldTextStyle, + kpMainWindow *mainWindow); + virtual ~kpToolTextChangeStyleCommand (); + + virtual int size () const; + + virtual void execute (); + virtual void unexecute (); + +protected: + kpTextStyle m_newTextStyle, m_oldTextStyle; +}; + +class kpToolTextInsertCommand : public kpNamedCommand +{ +public: + kpToolTextInsertCommand (const QString &name, + int row, int col, QString newText, + kpMainWindow *mainWindow); + virtual ~kpToolTextInsertCommand (); + + void addText (const QString &moreText); + + virtual int size () const; + + virtual void execute (); + virtual void unexecute (); + +protected: + int m_row, m_col; + QString m_newText; +}; + +class kpToolTextEnterCommand : public kpNamedCommand +{ +public: + kpToolTextEnterCommand (const QString &name, + int row, int col, + kpMainWindow *mainWindow); + virtual ~kpToolTextEnterCommand (); + + void addEnter (); + + virtual int size () const; + + virtual void execute (); + virtual void unexecute (); + +protected: + int m_row, m_col; + int m_numEnters; +}; + +class kpToolTextBackspaceCommand : public kpNamedCommand +{ +public: + kpToolTextBackspaceCommand (const QString &name, + int row, int col, + kpMainWindow *mainWindow); + virtual ~kpToolTextBackspaceCommand (); + + void addBackspace (); + + virtual int size () const; + + virtual void execute (); + virtual void unexecute (); + +protected: + int m_row, m_col; + int m_numBackspaces; + QString m_deletedText; +}; + +class kpToolTextDeleteCommand : public kpNamedCommand +{ +public: + kpToolTextDeleteCommand (const QString &name, + int row, int col, + kpMainWindow *mainWindow); + virtual ~kpToolTextDeleteCommand (); + + void addDelete (); + + virtual int size () const; + + virtual void execute (); + virtual void unexecute (); + +protected: + int m_row, m_col; + int m_numDeletes; + QString m_deletedText; +}; + +#endif // __kp_tool_text_h__ + diff --git a/kolourpaint/views/Makefile.am b/kolourpaint/views/Makefile.am new file mode 100644 index 00000000..2d771cfc --- /dev/null +++ b/kolourpaint/views/Makefile.am @@ -0,0 +1,14 @@ +INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../cursors -I$(srcdir)/../interfaces \ + -I$(srcdir)/../pixmapfx \ + -I$(srcdir)/../tools \ + -I$(srcdir)/../views \ + -I$(srcdir)/../widgets $(all_includes) + +noinst_LTLIBRARIES = libkolourpaintviews.la +libkolourpaintviews_la_SOURCES = kpthumbnailview.cpp \ + kpunzoomedthumbnailview.cpp \ + kpzoomedthumbnailview.cpp \ + kpzoomedview.cpp + +METASOURCES = AUTO + diff --git a/kolourpaint/views/kpthumbnailview.cpp b/kolourpaint/views/kpthumbnailview.cpp new file mode 100644 index 00000000..32c54376 --- /dev/null +++ b/kolourpaint/views/kpthumbnailview.cpp @@ -0,0 +1,98 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_THUMBNAIL_VIEW 0 + + +#include + +#include + + +kpThumbnailView::kpThumbnailView (kpDocument *document, + kpToolToolBar *toolToolBar, + kpViewManager *viewManager, + kpView *buddyView, + kpViewScrollableContainer *scrollableContainer, + QWidget *parent, const char *name) + + : kpView (document, toolToolBar, viewManager, + buddyView, + scrollableContainer, + parent, name) +{ +} + +kpThumbnailView::~kpThumbnailView () +{ +} + + +// protected +void kpThumbnailView::setMaskToCoverDocument () +{ +#if DEBUG_KP_THUMBNAIL_VIEW + kdDebug () << "kpThumbnailView::setMaskToCoverDocument()" + << " origin=" << origin () + << " zoomedDoc: width=" << zoomedDocWidth () + << " height=" << zoomedDocHeight () + << endl; +#endif + + setMask (QRegion (QRect (origin ().x (), origin ().y (), + zoomedDocWidth (), zoomedDocHeight ()))); +} + + +// protected virtual [base kpView] +void kpThumbnailView::resizeEvent (QResizeEvent *e) +{ +#if DEBUG_KP_THUMBNAIL_VIEW + kdDebug () << "kpThumbnailView(" << name () << ")::resizeEvent()" + << endl; +#endif + + // For QResizeEvent's, Qt already throws an entire widget repaint into + // the event loop. So eat useless update() calls that can only slow + // things down. + // TODO: this doesn't seem to work. + const bool oldIsUpdatesEnabled = isUpdatesEnabled (); + setUpdatesEnabled (false); + + { + kpView::resizeEvent (e); + + adjustToEnvironment (); + } + + setUpdatesEnabled (oldIsUpdatesEnabled); +} + + +#include + diff --git a/kolourpaint/views/kpthumbnailview.h b/kolourpaint/views/kpthumbnailview.h new file mode 100644 index 00000000..c3420833 --- /dev/null +++ b/kolourpaint/views/kpthumbnailview.h @@ -0,0 +1,90 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_THUMBNAIL_VIEW +#define KP_THUMBNAIL_VIEW + + +#include + + +/** + * @short Abstract base class for all thumbnail views. + * + * @author Clarence Dang + */ +class kpThumbnailView : public kpView +{ +Q_OBJECT + +public: + /** + * Constructs a thumbnail view. + * + * You must call adjustEnvironment() at the end of your constructor. + */ + kpThumbnailView (kpDocument *document, + kpToolToolBar *toolToolBar, + kpViewManager *viewManager, + kpView *buddyView, + kpViewScrollableContainer *scrollableContainer, + QWidget *parent, const char *name); + + /** + * Destructs this thumbnail view. + */ + virtual ~kpThumbnailView (); + + + /** + * @returns the caption to display in an enclosing thumbnail window. + */ + virtual QString caption () const = 0; + + +protected: + /** + * Sets the mask to cover the rectangle with top-left, origin() and + * dimensions equal to or slightly less than (in case of rounding + * error) the size of the document in view coordinates. This ensures + * that all pixels are initialised with either document pixels or the + * standard widget background. + */ + void setMaskToCoverDocument (); + + + /** + * Calls adjustToEnvironment() in response to a resize event. + * + * Extends @ref kpView. + */ + virtual void resizeEvent (QResizeEvent *e); +}; + + +#endif // KP_THUMBNAIL_VIEW diff --git a/kolourpaint/views/kpunzoomedthumbnailview.cpp b/kolourpaint/views/kpunzoomedthumbnailview.cpp new file mode 100644 index 00000000..09d5aed1 --- /dev/null +++ b/kolourpaint/views/kpunzoomedthumbnailview.cpp @@ -0,0 +1,212 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_UNZOOMED_THUMBNAIL_VIEW 0 + + +#include + +#include +#include + +#include +#include +#include + + +struct kpUnzoomedThumbnailViewPrivate +{ +}; + + +kpUnzoomedThumbnailView::kpUnzoomedThumbnailView ( + kpDocument *document, + kpToolToolBar *toolToolBar, + kpViewManager *viewManager, + kpView *buddyView, + kpViewScrollableContainer *scrollableContainer, + QWidget *parent, const char *name) + + : kpThumbnailView (document, toolToolBar, viewManager, + buddyView, + scrollableContainer, + parent, name), + d (new kpUnzoomedThumbnailViewPrivate ()) +{ + if (buddyViewScrollableContainer ()) + { + connect (buddyViewScrollableContainer (), + SIGNAL (contentsMovingSoon (int, int)), + this, + SLOT (adjustToEnvironment ())); + } + + // Call to virtual function - this is why the class is sealed + adjustToEnvironment (); +} + + +kpUnzoomedThumbnailView::~kpUnzoomedThumbnailView () +{ + delete d; +} + + +// public virtual [base kpThumbnailView] +QString kpUnzoomedThumbnailView::caption () const +{ + return i18n ("Unzoomed Mode - Thumbnail"); +} + + +// public slot virtual [base kpView] +void kpUnzoomedThumbnailView::adjustToEnvironment () +{ + if (!buddyView () || !buddyViewScrollableContainer () || !document ()) + return; + + const int scrollViewContentsX = + buddyViewScrollableContainer ()->contentsXSoon (); + const int scrollViewContentsY = + buddyViewScrollableContainer ()->contentsYSoon (); + +#if DEBUG_KP_UNZOOMED_THUMBNAIL_VIEW + kdDebug () << "kpUnzoomedThumbnailView(" << name () + << ")::adjustToEnvironment(" + << scrollViewContentsX + << "," + << scrollViewContentsY + << ") width=" << width () + << " height=" << height () + << endl; +#endif + + +#if 1 + int x; + if (document ()->width () > width ()) + { + x = (int) buddyView ()->transformViewToDocX (scrollViewContentsX); + const int rightMostAllowedX = QMAX (0, document ()->width () - width ()); + #if DEBUG_KP_UNZOOMED_THUMBNAIL_VIEW + kdDebug () << "\tdocX=" << x + << " docWidth=" << document ()->width () + << " rightMostAllowedX=" << rightMostAllowedX + << endl; + #endif + if (x > rightMostAllowedX) + x = rightMostAllowedX; + } + // Thumbnail width <= doc width + else + { + // Centre X (rather than flush left to be consistent with + // kpZoomedThumbnailView) + x = -(width () - document ()->width ()) / 2; + } + + + int y; + if (document ()->height () > height ()) + { + y = (int) buddyView ()->transformViewToDocY (scrollViewContentsY); + const int bottomMostAllowedY = QMAX (0, document ()->height () - height ()); + #if DEBUG_KP_UNZOOMED_THUMBNAIL_VIEW + kdDebug () << "\tdocY=" << y + << " docHeight=" << document ()->height () + << " bottomMostAllowedY=" << bottomMostAllowedY + << endl; + #endif + if (y > bottomMostAllowedY) + y = bottomMostAllowedY; + } + // Thumbnail height <= doc height + else + { + // Centre Y (rather than flush top to be consistent with + // kpZoomedThumbnailView) + y = -(height () - document ()->height ()) / 2; + } +// Prefer to keep visible area centred in thumbnail instead of flushed left. +// Gives more editing context to the left and top. +// But feels awkward for left-to-right users. So disabled for now. +// Not totally tested. +#else + if (!buddyViewScrollableContainer ()) + return; + + QRect docRect = buddyView ()->transformViewToDoc ( + QRect (buddyViewScrollableContainer ()->contentsXSoon (), + buddyViewScrollableContainer ()->contentsYSoon (), + QMIN (buddyView ()->width (), buddyViewScrollableContainer ()->visibleWidth ()), + QMIN (buddyView ()->height (), buddyViewScrollableContainer ()->visibleHeight ()))); + + x = docRect.x () - (width () - docRect.width ()) / 2; + kdDebug () << "\tnew suggest x=" << x << endl; + const int rightMostAllowedX = QMAX (0, document ()->width () - width ()); + if (x < 0) + x = 0; + if (x > rightMostAllowedX) + x = rightMostAllowedX; + + y = docRect.y () - (height () - docRect.height ()) / 2; + kdDebug () << "\tnew suggest y=" << y << endl; + const int bottomMostAllowedY = QMAX (0, document ()->height () - height ()); + if (y < 0) + y = 0; + if (y > bottomMostAllowedY) + y = bottomMostAllowedY; +#endif + + + if (viewManager ()) + { + viewManager ()->setFastUpdates (); + viewManager ()->setQueueUpdates (); + } + + { + // OPT: scrollView impl would be much, much faster + setOrigin (QPoint (-x, -y)); + setMaskToCoverDocument (); + + // Above might be a NOP even if e.g. doc size changed so force + // update + if (viewManager ()) + viewManager ()->updateView (this); + } + + if (viewManager ()) + { + viewManager ()->restoreQueueUpdates (); + viewManager ()->restoreFastUpdates (); + } +} + + +#include diff --git a/kolourpaint/views/kpunzoomedthumbnailview.h b/kolourpaint/views/kpunzoomedthumbnailview.h new file mode 100644 index 00000000..0f7ccf53 --- /dev/null +++ b/kolourpaint/views/kpunzoomedthumbnailview.h @@ -0,0 +1,106 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_UNZOOMED_THUMBNAIL_VIEW_H +#define KP_UNZOOMED_THUMBNAIL_VIEW_H + + +#include + + +class kpViewScrollableContainer; + + +/** + * @short Unzoomed thumbnail view of a document. + * + * This is an unzoomed thumbnail view of a document. Unlike + * @ref kpZoomedThumbnailView, it never changes the zoom level. And unlike + * @ref kpZoomedView, it never resizes itself. Instead, it changes its + * origin according to the main view's scrollable container so that the + * top-left most document pixel displayed in the scrollable container will + * be visible. + * + * Do not call setZoomLevel() nor setOrigin(). + * + * This class is sealed. Do not derive from it. + * + * @author Clarence Dang + */ +/*sealed*/ class kpUnzoomedThumbnailView : public kpThumbnailView +{ +Q_OBJECT + +public: + /** + * Constructs an unzoomed thumbnail view. + */ + kpUnzoomedThumbnailView (kpDocument *document, + kpToolToolBar *toolToolBar, + kpViewManager *viewManager, + kpView *buddyView, + kpViewScrollableContainer *scrollableContainer, + QWidget *parent, const char *name); + + /** + * Destructs an unzoomed thumbnail view. + */ + virtual ~kpUnzoomedThumbnailView (); + + + /** + * Implements @ref kpThumbnailView. + */ + QString caption () const; + + +public slots: + /** + * Changes its origin according to the main view's scrollable container + * so that the top-left most document pixel displayed in the scrollable + * container will be visible. + * + * It tries to maximise the used area of this view. Unused areas will + * be set to the widget background thanks to the mask. + * + * Call this if the size of the document changes. + * Already connected to buddyViewScrollableContainer()'s + * contentsMovingSoon(int,int) signal. + * Already called by @ref kpThumbnailView resizeEvent(). + * + * Implements @ref kpView. + */ + virtual void adjustToEnvironment (); + + +private: + struct kpUnzoomedThumbnailViewPrivate *d; +}; + + +#endif // KP_UNZOOMED_THUMBNAIL_VIEW_H diff --git a/kolourpaint/views/kpzoomedthumbnailview.cpp b/kolourpaint/views/kpzoomedthumbnailview.cpp new file mode 100644 index 00000000..ecbfd317 --- /dev/null +++ b/kolourpaint/views/kpzoomedthumbnailview.cpp @@ -0,0 +1,140 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_ZOOMED_THUMBNAIL_VIEW 0 + + +#include + +#include +#include + +#include +#include + + +kpZoomedThumbnailView::kpZoomedThumbnailView (kpDocument *document, + kpToolToolBar *toolToolBar, + kpViewManager *viewManager, + kpView *buddyView, + kpViewScrollableContainer *scrollableContainer, + QWidget *parent, const char *name) + + : kpThumbnailView (document, toolToolBar, viewManager, + buddyView, + scrollableContainer, + parent, name) +{ + // Call to virtual function - this is why the class is sealed + adjustToEnvironment (); +} + + +kpZoomedThumbnailView::~kpZoomedThumbnailView () +{ +} + + +// public virtual [base kpThumbnailView] +QString kpZoomedThumbnailView::caption () const +{ + return i18n ("%1% - Thumbnail").arg (zoomLevelX ()); +} + + +// public slot virtual [base kpView] +void kpZoomedThumbnailView::adjustToEnvironment () +{ +#if DEBUG_KP_ZOOMED_THUMBNAIL_VIEW + kdDebug () << "kpZoomedThumbnailView(" << name () + << ")::adjustToEnvironment()" + << " width=" << width () + << " height=" << height () + << endl; +#endif + + if (!document ()) + return; + +#if DEBUG_KP_ZOOMED_THUMBNAIL_VIEW + kdDebug () << "\tdoc: width=" << document ()->width () + << " height=" << document ()->height () + << endl; +#endif + + if (document ()->width () <= 0 || document ()->height () <= 0) + { + kdError () << "kpZoomedThumbnailView::adjustToEnvironment() doc:" + << " width=" << document ()->width () + << " height=" << document ()->height () + << endl; + return; + } + + + int hzoom = QMAX (1, width () * 100 / document ()->width ()); + int vzoom = QMAX (1, height () * 100 / document ()->height ()); + + // keep aspect ratio + if (hzoom < vzoom) + vzoom = hzoom; + else + hzoom = vzoom; + +#if DEBUG_KP_ZOOMED_THUMBNAIL_VIEW && 1 + kdDebug () << "\tproposed zoom=" << hzoom << endl; +#endif + if (hzoom > 100 || vzoom > 100) + { + #if DEBUG_KP_ZOOMED_THUMBNAIL_VIEW && 1 + kdDebug () << "\twon't magnify - setting zoom to 100%" << endl; + #endif + hzoom = 100, vzoom = 100; + } + + + if (viewManager ()) + viewManager ()->setQueueUpdates (); + + { + setZoomLevel (hzoom, vzoom); + + setOrigin (QPoint ((width () - zoomedDocWidth ()) / 2, + (height () - zoomedDocHeight ()) / 2)); + setMaskToCoverDocument (); + + if (viewManager ()) + viewManager ()->updateView (this); + } + + if (viewManager ()) + viewManager ()->restoreQueueUpdates (); +} + + +#include diff --git a/kolourpaint/views/kpzoomedthumbnailview.h b/kolourpaint/views/kpzoomedthumbnailview.h new file mode 100644 index 00000000..0bcb367c --- /dev/null +++ b/kolourpaint/views/kpzoomedthumbnailview.h @@ -0,0 +1,95 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_ZOOMED_THUMBNAIL_VIEW_H +#define KP_ZOOMED_THUMBNAIL_VIEW_H + + +#include + + +/** + * @short Zoomed thumbnail view of a document. + * + * This is a zoomed thumbnail view of a document. Unlike @ref kpZoomedView, + * it never resizes itself. Instead, it changes its zoom level to + * accommodate the display of entire document in the view, while + * maintaining aspect. + * + * Do not call setZoomLevel() nor setOrigin(). + * + * This class is sealed. Do not derive from it. + * + * @author Clarence Dang + */ +/*sealed*/ class kpZoomedThumbnailView : public kpThumbnailView +{ +Q_OBJECT + +public: + /** + * Constructs a zoomed thumbnail view. + */ + kpZoomedThumbnailView (kpDocument *document, + kpToolToolBar *toolToolBar, + kpViewManager *viewManager, + kpView *buddyView, + kpViewScrollableContainer *scrollableContainer, + QWidget *parent, const char *name); + + /** + * Destructs a zoomed thumbnail view. + */ + virtual ~kpZoomedThumbnailView (); + + + /** + * Implements @ref kpThumbnailView. + */ + QString caption () const; + + +public slots: + /** + * Changes its zoom level to accommodate the display of entire document + * in the view. It maintains aspect by changing the origin and mask. + * + * Call this if the size of the document changes. + * Already called by @ref kpThumbnailView resizeEvent(). + * + * Implements @ref kpView. + */ + virtual void adjustToEnvironment (); + + +private: + struct kpZoomedThumbnailViewPrivate *d; +}; + + +#endif // KP_ZOOMED_THUMBNAIL_VIEW_H diff --git a/kolourpaint/views/kpzoomedview.cpp b/kolourpaint/views/kpzoomedview.cpp new file mode 100644 index 00000000..ef1d6981 --- /dev/null +++ b/kolourpaint/views/kpzoomedview.cpp @@ -0,0 +1,103 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_ZOOMED_VIEW 0 + + +#include + +#include + +#include +#include +#include + + +kpZoomedView::kpZoomedView (kpDocument *document, + kpToolToolBar *toolToolBar, + kpViewManager *viewManager, + kpView *buddyView, + kpViewScrollableContainer *scrollableContainer, + QWidget *parent, const char *name) + + : kpView (document, toolToolBar, viewManager, + buddyView, + scrollableContainer, + parent, name) +{ + // Call to virtual function - this is why the class is sealed + adjustToEnvironment (); +} + +kpZoomedView::~kpZoomedView () +{ +} + + +// public virtual [base kpView] +void kpZoomedView::setZoomLevel (int hzoom, int vzoom) +{ +#if DEBUG_KP_ZOOMED_VIEW + kdDebug () << "kpZoomedView(" << name () << ")::setZoomLevel(" + << hzoom << "," << vzoom << ")" << endl; +#endif + + if (viewManager ()) + viewManager ()->setQueueUpdates (); + + { + kpView::setZoomLevel (hzoom, vzoom); + + adjustToEnvironment (); + } + + if (viewManager ()) + viewManager ()->restoreQueueUpdates (); +} + + +// public slot virtual [base kpView] +void kpZoomedView::adjustToEnvironment () +{ +#if DEBUG_KP_ZOOMED_VIEW + kdDebug () << "kpZoomedView(" << name () << ")::adjustToEnvironment()" + << " doc: width=" << document ()->width () + << " height=" << document ()->height () + << endl; +#endif + + if (document ()) + { + // TODO: use zoomedDocWidth() & zoomedDocHeight()? + resize ((int) transformDocToViewX (document ()->width ()), + (int) transformDocToViewY (document ()->height ())); + } +} + + +#include diff --git a/kolourpaint/views/kpzoomedview.h b/kolourpaint/views/kpzoomedview.h new file mode 100644 index 00000000..c3729282 --- /dev/null +++ b/kolourpaint/views/kpzoomedview.h @@ -0,0 +1,96 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KP_ZOOMED_VIEW_H +#define KP_ZOOMED_VIEW_H + + +#include + + +/** + * @short Zoomed view of a document. Suitable as an ordinary editing view. + * + * This is a zoomed view of a document. It resizes according to the size + * of the document and the zoom level. Do not manually call resize() for + * this reason. + * + * It is suitable as an ordinary editing view. + * + * Do not call setOrigin(). + * + * This class is sealed. Do not derive from it. + * + * @author Clarence Dang + */ +/*sealed*/ class kpZoomedView : public kpView +{ +Q_OBJECT + +public: + /** + * Constructs a zoomed view. + */ + kpZoomedView (kpDocument *document, + kpToolToolBar *toolToolBar, + kpViewManager *viewManager, + kpView *buddyView, + kpViewScrollableContainer *scrollableContainer, + QWidget *parent, const char *name); + + /** + * Destructs an unzoomed view. + */ + virtual ~kpZoomedView (); + + + /** + * Extends @kpView. Calls adjustToEnvironment(). + */ + virtual void setZoomLevel (int hzoom, int vzoom); + + +public slots: + /** + * Resizes itself so that the entire document in the zoom level fits + * almost perfectly. + * + * Call this if the size of the document changes. + * Already called by setZoomLevel(). + * + * Implements @ref kpView. + */ + virtual void adjustToEnvironment (); + + +private: + struct kpZoomedViewPrivate *d; +}; + + +#endif // KP_ZOOMED_VIEW_H diff --git a/kolourpaint/widgets/Makefile.am b/kolourpaint/widgets/Makefile.am new file mode 100644 index 00000000..f6501fac --- /dev/null +++ b/kolourpaint/widgets/Makefile.am @@ -0,0 +1,21 @@ +INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../cursors -I$(srcdir)/../interfaces \ + -I$(srcdir)/../pixmapfx \ + -I$(srcdir)/../tools \ + -I$(srcdir)/../views \ + -I$(srcdir)/../widgets $(all_includes) + +noinst_LTLIBRARIES = libkolourpaintwidgets.la +libkolourpaintwidgets_la_SOURCES = kpcolorsimilaritycube.cpp \ + kpcolorsimilaritydialog.cpp \ + kpcolortoolbar.cpp \ + kpresizesignallinglabel.cpp \ + kpsqueezedtextlabel.cpp \ + kptooltoolbar.cpp \ + kptoolwidgetbase.cpp kptoolwidgetbrush.cpp \ + kptoolwidgeterasersize.cpp kptoolwidgetfillstyle.cpp \ + kptoolwidgetlinewidth.cpp \ + kptoolwidgetopaqueortransparent.cpp \ + kptoolwidgetspraycansize.cpp + +METASOURCES = AUTO + diff --git a/kolourpaint/widgets/kpcolorsimilaritycube.cpp b/kolourpaint/widgets/kpcolorsimilaritycube.cpp new file mode 100644 index 00000000..9fe3f29b --- /dev/null +++ b/kolourpaint/widgets/kpcolorsimilaritycube.cpp @@ -0,0 +1,348 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_COLOR_SIMILARITY_CUBE 0 + + +#include + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + + +const double kpColorSimilarityCube::colorCubeDiagonalDistance = + sqrt (255 * 255 * 3); + +kpColorSimilarityCube::kpColorSimilarityCube (int look, + kpMainWindow *mainWindow, + QWidget *parent, + const char *name) + : QFrame (parent, name, Qt::WNoAutoErase/*no flicker*/), + m_mainWindow (mainWindow), + m_colorSimilarity (-1) +{ + if (look & Depressed) + setFrameStyle (QFrame::Panel | QFrame::Sunken); + + setColorSimilarity (0); + + + // Don't cause the translators grief by appending strings + // - duplicate text with 2 cases + + if (look & DoubleClickInstructions) + { + QWhatsThis::add (this, + i18n ("

Color Similarity is how close " + "colors must be in the RGB Color Cube " + "to be considered the same.

" + + "

If you set it to something " + "other than Exact, " + "you can work more effectively with dithered " + "images and photos.

" + + "

This feature applies to transparent selections, as well as " + "the Flood Fill, Color Eraser and Autocrop " + "tools.

" + + // sync: different to else case + "

To configure it, double click on the cube.

" + + "
")); + } + else + { + QWhatsThis::add (this, + i18n ("

Color Similarity is how close " + "colors must be in the RGB Color Cube " + "to be considered the same.

" + + "

If you set it to something " + "other than Exact, " + "you can work more effectively with dithered " + "images and photos.

" + + "

This feature applies to transparent selections, as well as " + "the Flood Fill, Color Eraser and Autocrop " + "tools.

" + + "
")); + } +} + +kpColorSimilarityCube::~kpColorSimilarityCube () +{ +} + + +// public +double kpColorSimilarityCube::colorSimilarity () const +{ + return m_colorSimilarity; +} + +// public +void kpColorSimilarityCube::setColorSimilarity (double similarity) +{ +#if DEBUG_KP_COLOR_SIMILARITY_CUBE + kdDebug () << "kpColorSimilarityCube::setColorSimilarity(" << similarity << ")" << endl; +#endif + + if (m_colorSimilarity == similarity) + return; + + if (similarity < 0) + similarity = 0; + else if (similarity > kpColorSimilarityDialog::maximumColorSimilarity) + similarity = kpColorSimilarityDialog::maximumColorSimilarity; + + m_colorSimilarity = similarity; + + repaint (false/*no erase*/); +} + + +// protected virtual [base QWidget] +QSize kpColorSimilarityCube::sizeHint () const +{ + return QSize (52, 52); +} + + +// protected +QColor kpColorSimilarityCube::color (int redOrGreenOrBlue, + int baseBrightness, + int similarityDirection) const +{ + int brightness = int (baseBrightness + + similarityDirection * + .5 * m_colorSimilarity * kpColorSimilarityCube::colorCubeDiagonalDistance); + + if (brightness < 0) + brightness = 0; + else if (brightness > 255) + brightness = 255; + + switch (redOrGreenOrBlue) + { + default: + case 0: return QColor (brightness, 0, 0); + case 1: return QColor (0, brightness, 0); + case 2: return QColor (0, 0, brightness); + } +} + +static QPoint pointBetween (const QPoint &p, const QPoint &q) +{ + return QPoint ((p.x () + q.x ()) / 2, (p.y () + q.y ()) / 2); +} + +static void drawQuadrant (QPainter *p, + const QColor &col, + const QPoint &p1, const QPoint &p2, const QPoint &p3, + const QPoint pointNotOnOutline) +{ + p->save (); + + + QPointArray points (4); + points [0] = p1; + points [1] = p2; + points [2] = p3; + points [3] = pointNotOnOutline; + + p->setPen (col); + p->setBrush (col); + p->drawPolygon (points); + + + points.resize (3); + + p->setPen (Qt::black); + p->setBrush (Qt::NoBrush); + p->drawPolyline (points); + + + p->restore (); +} + +// protected +void kpColorSimilarityCube::drawFace (QPainter *p, + int redOrGreenOrBlue, + const QPoint &tl, const QPoint &tr, + const QPoint &bl, const QPoint &br) +{ +#if DEBUG_KP_COLOR_SIMILARITY_CUBE + kdDebug () << "kpColorSimilarityCube(RorGorB=" << redOrGreenOrBlue + << ",tl=" << tl + << ",tr=" << tr + << ",bl=" << bl + << ",br=" << br + << ")" + << endl; +#endif + + // tl --- tm --- tr + // | | | + // | | | + // ml --- mm --- mr + // | | | + // | | | + // bl --- bm --- br + + const QPoint tm (::pointBetween (tl, tr)); + const QPoint bm (::pointBetween (bl, br)); + + const QPoint ml (::pointBetween (tl, bl)); + const QPoint mr (::pointBetween (tr, br)); + const QPoint mm (::pointBetween (ml, mr)); + + + const int baseBrightness = QMAX (127, + 255 - int (kpColorSimilarityDialog::maximumColorSimilarity * + kpColorSimilarityCube::colorCubeDiagonalDistance / 2)); + QColor colors [2] = + { + color (redOrGreenOrBlue, baseBrightness, -1), + color (redOrGreenOrBlue, baseBrightness, +1) + }; + + if (!isEnabled ()) + { + #if DEBUG_KP_COLOR_SIMILARITY_CUBE + kdDebug () << "\tnot enabled - making us grey" << endl; + #endif + colors [0] = colorGroup ().background (); + colors [1] = colorGroup ().background (); + } + +#if DEBUG_KP_COLOR_SIMILARITY_CUBE + kdDebug () << "\tmaxColorSimilarity=" << kpColorSimilarityDialog::maximumColorSimilarity + << " colorCubeDiagDist=" << kpColorSimilarityCube::colorCubeDiagonalDistance + << endl + << "\tbaseBrightness=" << baseBrightness + << " color[0]=" << ((colors [0].rgb () & RGB_MASK) >> ((2 - redOrGreenOrBlue) * 8)) + << " color[1]=" << ((colors [1].rgb () & RGB_MASK) >> ((2 - redOrGreenOrBlue) * 8)) + << endl; +#endif + + + ::drawQuadrant (p, colors [0], tm, tl, ml, mm); + ::drawQuadrant (p, colors [1], tm, tr, mr, mm); + ::drawQuadrant (p, colors [1], ml, bl, bm, mm); + ::drawQuadrant (p, colors [0], bm, br, mr, mm); +} + +// protected virtual [base QFrame] +void kpColorSimilarityCube::drawContents (QPainter *p) +{ + QRect cr (contentsRect ()); + + QPixmap backBuffer (cr.width (), cr.height ()); + backBuffer.fill (colorGroup ().background ()); + + QPainter backBufferPainter (&backBuffer); + + int cubeRectSize = QMIN (cr.width () * 6 / 8, cr.height () * 6 / 8); + int dx = (cr.width () - cubeRectSize) / 2, + dy = (cr.height () - cubeRectSize) / 2; + backBufferPainter.translate (dx, dy); + + // + // P------- Q --- --- + // / / | | | + // /A / | side | + // R-------S T --- cubeRectSize + // | | / / | + // S | | / side | + // U-------V --- --- + // |-------| + // side + // |-----------| + // cubeRectSize + // + // + + const double angle = KP_DEGREES_TO_RADIANS (45); + // S + S sin A = cubeRectSize + // (1 + sin A) x S = cubeRectSize + const double side = double (cubeRectSize) / (1 + sin (angle)); + + + const QPoint pointP ((int) (side * cos (angle)), 0); + const QPoint pointQ ((int) (side * cos (angle) + side), 0); + const QPoint pointR (0, (int) (side * sin (angle))); + const QPoint pointS ((int) (side), (int) (side * sin (angle))); + const QPoint pointU (0, (int) (side * sin (angle) + side)); + const QPoint pointT ((int) (side + side * cos (angle)), (int) (side)); + const QPoint pointV ((int) (side), (int) (side * sin (angle) + side)); + + + // Top Face + drawFace (&backBufferPainter, + 0/*red*/, + pointP, pointQ, + pointR, pointS); + + + // Bottom Face + drawFace (&backBufferPainter, + 1/*green*/, + pointR, pointS, + pointU, pointV); + + + // Right Face + drawFace (&backBufferPainter, + 2/*blue*/, + pointS, pointQ, + pointV, pointT); + + +#if 0 + backBufferPainter.save (); + backBufferPainter.setPen (Qt::cyan); + backBufferPainter.drawRect (0, 0, cubeRectSize, cubeRectSize); + backBufferPainter.restore (); +#endif + + + backBufferPainter.end (); + + p->drawPixmap (cr, backBuffer); +} diff --git a/kolourpaint/widgets/kpcolorsimilaritycube.h b/kolourpaint/widgets/kpcolorsimilaritycube.h new file mode 100644 index 00000000..358d4b3a --- /dev/null +++ b/kolourpaint/widgets/kpcolorsimilaritycube.h @@ -0,0 +1,72 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kp_color_similarity_cube_h__ +#define __kp_color_similarity_cube_h__ + +#include + +class kpColor; +class kpMainWindow; + +class kpColorSimilarityCube : public QFrame +{ +public: + enum Look + { + Plain = 0, + Depressed = 1, + DoubleClickInstructions = 2 + }; + + kpColorSimilarityCube (int look, + kpMainWindow *mainWindow, + QWidget *parent, + const char *name = 0); + virtual ~kpColorSimilarityCube (); + + static const double colorCubeDiagonalDistance; + + double colorSimilarity () const; + void setColorSimilarity (double similarity); + + virtual QSize sizeHint () const; + +protected: + QColor color (int redOrGreenOrBlue, int baseBrightness, int similarityDirection) const; + void drawFace (QPainter *p, + int redOrGreenOrBlue, + const QPoint &tl, const QPoint &tr, + const QPoint &bl, const QPoint &br); + virtual void drawContents (QPainter *p); + + kpMainWindow *m_mainWindow; + double m_colorSimilarity; +}; + +#endif // __kp_color_similarity_cube_h__ diff --git a/kolourpaint/widgets/kpcolorsimilaritydialog.cpp b/kolourpaint/widgets/kpcolorsimilaritydialog.cpp new file mode 100644 index 00000000..d2766568 --- /dev/null +++ b/kolourpaint/widgets/kpcolorsimilaritydialog.cpp @@ -0,0 +1,123 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include +#include +#include +#include + +#include +#include + +#include + + +// public static +const double kpColorSimilarityDialog::maximumColorSimilarity = .30; + + +kpColorSimilarityDialog::kpColorSimilarityDialog (kpMainWindow *mainWindow, + QWidget *parent, + const char *name) + : KDialogBase (parent, name, true/*modal*/, + i18n ("Color Similarity"), + KDialogBase::Ok | KDialogBase::Cancel), + m_mainWindow (mainWindow) +{ + QWidget *baseWidget = new QWidget (this); + setMainWidget (baseWidget); + + + QGroupBox *cubeGroupBox = new QGroupBox (i18n ("Preview"), baseWidget); + + m_colorSimilarityCube = new kpColorSimilarityCube (kpColorSimilarityCube::Plain, + mainWindow, cubeGroupBox); + m_colorSimilarityCube->setMinimumSize (240, 180); + + QPushButton *updatePushButton = new QPushButton (i18n ("&Update"), cubeGroupBox); + + + QVBoxLayout *cubeLayout = new QVBoxLayout (cubeGroupBox, marginHint () * 2, spacingHint ()); + cubeLayout->addWidget (m_colorSimilarityCube, 1/*stretch*/); + cubeLayout->addWidget (updatePushButton, 0/*stretch*/, Qt::AlignHCenter); + + + connect (updatePushButton, SIGNAL (clicked ()), + this, SLOT (slotColorSimilarityValueChanged ())); + + + QGroupBox *inputGroupBox = new QGroupBox (i18n ("RGB Color Cube Distance"), baseWidget); + + m_colorSimilarityInput = new KIntNumInput (inputGroupBox); + m_colorSimilarityInput->setRange (0, int (kpColorSimilarityDialog::maximumColorSimilarity * 100 + .1/*don't floor below target int*/), + 5/*step*/, true/*slider*/); + m_colorSimilarityInput->setSuffix (i18n ("%")); + m_colorSimilarityInput->setSpecialValueText (i18n ("Exact Match")); + + + QVBoxLayout *inputLayout = new QVBoxLayout (inputGroupBox, marginHint () * 2, spacingHint ()); + inputLayout->addWidget (m_colorSimilarityInput); + + + connect (m_colorSimilarityInput, SIGNAL (valueChanged (int)), + this, SLOT (slotColorSimilarityValueChanged ())); + + + QVBoxLayout *baseLayout = new QVBoxLayout (baseWidget, 0/*margin*/, spacingHint () * 2); + baseLayout->addWidget (cubeGroupBox, 1/*stretch*/); + baseLayout->addWidget (inputGroupBox); +} + +kpColorSimilarityDialog::~kpColorSimilarityDialog () +{ +} + + +// public +double kpColorSimilarityDialog::colorSimilarity () const +{ + return m_colorSimilarityCube->colorSimilarity (); +} + +// public +void kpColorSimilarityDialog::setColorSimilarity (double similarity) +{ + m_colorSimilarityInput->setValue (qRound (similarity * 100)); +} + + +// private slot +void kpColorSimilarityDialog::slotColorSimilarityValueChanged () +{ + m_colorSimilarityCube->setColorSimilarity (double (m_colorSimilarityInput->value ()) / 100); +} + + +#include diff --git a/kolourpaint/widgets/kpcolorsimilaritydialog.h b/kolourpaint/widgets/kpcolorsimilaritydialog.h new file mode 100644 index 00000000..fd70ecd0 --- /dev/null +++ b/kolourpaint/widgets/kpcolorsimilaritydialog.h @@ -0,0 +1,62 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __kp_color_similarity_dialog_h__ +#define __kp_color_similarity_dialog_h__ + +#include + +class KIntNumInput; + +class kpColorSimilarityCube; +class kpMainWindow; + +class kpColorSimilarityDialog : public KDialogBase +{ +Q_OBJECT + +public: + kpColorSimilarityDialog (kpMainWindow *mainWindow, + QWidget *parent, + const char *name = 0); + virtual ~kpColorSimilarityDialog (); + + double colorSimilarity () const; + void setColorSimilarity (double similarity); + + static const double maximumColorSimilarity; + +private slots: + void slotColorSimilarityValueChanged (); + +private: + kpMainWindow *m_mainWindow; + kpColorSimilarityCube *m_colorSimilarityCube; + KIntNumInput *m_colorSimilarityInput; +}; + +#endif // __kp_color_similarity_dialog_h__ diff --git a/kolourpaint/widgets/kpcolortoolbar.cpp b/kolourpaint/widgets/kpcolortoolbar.cpp new file mode 100644 index 00000000..cba73b4f --- /dev/null +++ b/kolourpaint/widgets/kpcolortoolbar.cpp @@ -0,0 +1,1112 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_COLOR_TOOL_BAR 0 + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +/* + * kpDualColorButton + */ + +kpDualColorButton::kpDualColorButton (kpMainWindow *mainWindow, + QWidget *parent, const char *name) + : QFrame (parent, name, Qt::WNoAutoErase/*no flicker*/), + m_mainWindow (mainWindow), + m_backBuffer (0) +{ + setFrameStyle (QFrame::Panel | QFrame::Sunken); + + m_color [0] = kpColor (0, 0, 0); // black + m_color [1] = kpColor (255, 255, 255); // white + + setAcceptDrops (true); +} + +kpDualColorButton::~kpDualColorButton () +{ + delete m_backBuffer; m_backBuffer = 0; +} + + +kpColor kpDualColorButton::color (int which) const +{ + if (which < 0 || which > 1) + { + kdWarning () << "kpDualColorButton::color (" << which + << ") - out of range" << endl; + which = 0; + } + + return m_color [which]; +} + +kpColor kpDualColorButton::foregroundColor () const +{ + return color (0); +} + +kpColor kpDualColorButton::backgroundColor () const +{ + return color (1); +} + + +void kpDualColorButton::setColor (int which, const kpColor &color) +{ + if (which < 0 || which > 1) + { + kdWarning () << "kpDualColorButton::setColor (" << which + << ") - out of range" << endl; + which = 0; + } + + if (m_color [which] == color) + return; + + m_oldColor [which] = m_color [which]; + m_color [which] = color; + update (); + + if (which == 0) + emit foregroundColorChanged (color); + else + emit backgroundColorChanged (color); +} + +void kpDualColorButton::setForegroundColor (const kpColor &color) +{ + setColor (0, color); +} + +void kpDualColorButton::setBackgroundColor (const kpColor &color) +{ + setColor (1, color); +} + + +// public +kpColor kpDualColorButton::oldForegroundColor () const +{ + return m_oldColor [0]; +} + +// public +kpColor kpDualColorButton::oldBackgroundColor () const +{ + return m_oldColor [1]; +} + + +// public virtual [base QWidget] +QSize kpDualColorButton::sizeHint () const +{ + return QSize (52, 52); +} + + +// protected +QRect kpDualColorButton::swapPixmapRect () const +{ + QPixmap swapPixmap = UserIcon ("colorbutton_swap_16x16"); + + return QRect (contentsRect ().width () - swapPixmap.width (), + 0, + swapPixmap.width (), + swapPixmap.height ()); +} + +// protected +QRect kpDualColorButton::foregroundBackgroundRect () const +{ + QRect cr (contentsRect ()); + return QRect (cr.width () / 8, + cr.height () / 8, + cr.width () * 6 / 8, + cr.height () * 6 / 8); +} + +// protected +QRect kpDualColorButton::foregroundRect () const +{ + QRect fbr (foregroundBackgroundRect ()); + return QRect (fbr.x (), + fbr.y (), + fbr.width () * 3 / 4, + fbr.height () * 3 / 4); +} + +// protected +QRect kpDualColorButton::backgroundRect () const +{ + QRect fbr (foregroundBackgroundRect ()); + return QRect (fbr.x () + fbr.width () / 4, + fbr.y () + fbr.height () / 4, + fbr.width () * 3 / 4, + fbr.height () * 3 / 4); +} + + +// TODO: drag a colour from this widget + +// protected virtual [base QWidget] +void kpDualColorButton::dragMoveEvent (QDragMoveEvent *e) +{ + e->accept ((foregroundRect ().contains (e->pos ()) || + backgroundRect ().contains (e->pos ())) && + KColorDrag::canDecode (e)); +} + +// protected virtual [base QWidget] +void kpDualColorButton::dropEvent (QDropEvent *e) +{ + QColor col; + KColorDrag::decode (e, col/*ref*/); + + if (col.isValid ()) + { + if (foregroundRect ().contains (e->pos ())) + setForegroundColor (kpColor (col.rgb ())); + else if (backgroundRect ().contains (e->pos ())) + setBackgroundColor (kpColor (col.rgb ())); + } +} + + +// protected virtual [base QWidget] +void kpDualColorButton::mousePressEvent (QMouseEvent * /*e*/) +{ + // eat right-mouse click to prevent it from getting to the toolbar +} + +// protected virtual [base QWidget] +void kpDualColorButton::mouseDoubleClickEvent (QMouseEvent *e) +{ + int whichColor = -1; + + if (foregroundRect ().contains (e->pos ())) + whichColor = 0; + else if (backgroundRect ().contains (e->pos ())) + whichColor = 1; + + if (whichColor == 0 || whichColor == 1) + { + QColor col = Qt::black; + if (color (whichColor).isOpaque ()) + col = color (whichColor).toQColor (); + else + { + // TODO: If you double-click on a transparent color and press OK, you get + // black, instead of the color staying as transparent. + // + // We should modify or fork KColorDialog to allow us to fix this. + // + // It would be wrong to stop the user from double-clicking on a + // transparent color as that would make the UI inconsistent, compared + // to opaque colors. + } + + // TODO: parent + if (KColorDialog::getColor (col/*ref*/)) + setColor (whichColor, kpColor (col.rgb ())); + } +} + +// protected virtual [base QWidget] +void kpDualColorButton::mouseReleaseEvent (QMouseEvent *e) +{ + if (swapPixmapRect ().contains (e->pos ()) && + m_color [0] != m_color [1]) + { + #if DEBUG_KP_COLOR_TOOL_BAR && 1 + kdDebug () << "kpDualColorButton::mouseReleaseEvent() swap colors:" << endl; + #endif + m_oldColor [0] = m_color [0]; + m_oldColor [1] = m_color [1]; + + kpColor temp = m_color [0]; + m_color [0] = m_color [1]; + m_color [1] = temp; + + update (); + + emit colorsSwapped (m_color [0], m_color [1]); + emit foregroundColorChanged (m_color [0]); + emit backgroundColorChanged (m_color [1]); + } +} + + +// protected virtual [base QFrame] +void kpDualColorButton::drawContents (QPainter *p) +{ +#if DEBUG_KP_COLOR_TOOL_BAR && 1 + kdDebug () << "kpDualColorButton::draw() rect=" << rect () + << " contentsRect=" << contentsRect () + << endl; +#endif + + if (!m_backBuffer || + m_backBuffer->width () != contentsRect ().width () || + m_backBuffer->height () != contentsRect ().height ()) + { + delete m_backBuffer; + m_backBuffer = new QPixmap (contentsRect ().width (), contentsRect ().height ()); + } + + + QPainter backBufferPainter (m_backBuffer); + + if (isEnabled () && m_mainWindow) + { + kpView::drawTransparentBackground (&backBufferPainter, + m_backBuffer->width (), m_backBuffer->height (), + m_backBuffer->rect (), + true/*preview*/); + } + else + { + backBufferPainter.fillRect (m_backBuffer->rect (), + colorGroup ().color (QColorGroup::Background)); + } + + QPixmap swapPixmap = UserIcon ("colorbutton_swap_16x16"); + if (!isEnabled ()) + { + // swapPixmap has a mask after all + swapPixmap.fill (colorGroup ().color (QColorGroup::Dark)); + } + backBufferPainter.drawPixmap (swapPixmapRect ().topLeft (), swapPixmap); + + // foreground patch must be drawn after background patch + // as it overlaps on top of background patch + QRect bgRect = backgroundRect (); + QRect bgRectInside = QRect (bgRect.x () + 2, bgRect.y () + 2, + bgRect.width () - 4, bgRect.height () - 4); + if (isEnabled ()) + { + #if DEBUG_KP_COLOR_TOOL_BAR && 1 + kdDebug () << "\tbackgroundColor=" << (int *) m_color [1].toQRgb () + << endl; + #endif + if (m_color [1].isOpaque ()) + backBufferPainter.fillRect (bgRectInside, m_color [1].toQColor ()); + else + backBufferPainter.drawPixmap (bgRectInside, UserIcon ("color_transparent_26x26")); + } + else + backBufferPainter.fillRect (bgRectInside, colorGroup ().color (QColorGroup::Button)); + qDrawShadePanel (&backBufferPainter, bgRect, colorGroup (), + false/*not sunken*/, 2/*lineWidth*/, + 0/*never fill*/); + + QRect fgRect = foregroundRect (); + QRect fgRectInside = QRect (fgRect.x () + 2, fgRect.y () + 2, + fgRect.width () - 4, fgRect.height () - 4); + if (isEnabled ()) + { + #if DEBUG_KP_COLOR_TOOL_BAR && 1 + kdDebug () << "\tforegroundColor=" << (int *) m_color [0].toQRgb () + << endl; + #endif + if (m_color [0].isOpaque ()) + backBufferPainter.fillRect (fgRectInside, m_color [0].toQColor ()); + else + backBufferPainter.drawPixmap (fgRectInside, UserIcon ("color_transparent_26x26")); + } + else + backBufferPainter.fillRect (fgRectInside, colorGroup ().color (QColorGroup::Button)); + qDrawShadePanel (&backBufferPainter, fgRect, colorGroup (), + false/*not sunken*/, 2/*lineWidth*/, + 0/*never fill*/); + + backBufferPainter.end (); + + p->drawPixmap (contentsRect (), *m_backBuffer); +} + + +/* + * kpColorCells + */ + +static inline int roundUp2 (int val) +{ + return val % 2 ? val + 1 : val; +} + +static inline int btwn0_255 (int val) +{ + if (val < 0) + return 0; + else if (val > 255) + return 255; + else + return val; +} + +enum +{ + blendDark = 25, + blendNormal = 50, + blendLight = 75, + blendAdd = 100 +}; + +static QColor blend (const QColor &a, const QColor &b, int percent = blendNormal) +{ + return QColor (btwn0_255 (roundUp2 (a.red () + b.red ()) * percent / 100), + btwn0_255 (roundUp2 (a.green () + b.green ()) * percent / 100), + btwn0_255 (roundUp2 (a.blue () + b.blue ()) * percent / 100)); +} + +static QColor add (const QColor &a, const QColor &b) +{ + return blend (a, b, blendAdd); +} + + + + + +// +// make our own colors in case weird ones like "Qt::cyan" +// (turquoise) get changed by Qt +// + +// primary colors + B&W +static QColor kpRed; +static QColor kpGreen; +static QColor kpBlue; +static QColor kpBlack; +static QColor kpWhite; + +// intentionally _not_ an HSV darkener +static QColor dark (const QColor &color) +{ + return blend (color, kpBlack); +} + +// full-brightness colors +static QColor kpYellow; +static QColor kpPurple; +static QColor kpAqua; + +// mixed colors +static QColor kpGrey; +static QColor kpLightGrey; +static QColor kpOrange; + +// pastel colors +static QColor kpPink; +static QColor kpLightGreen; +static QColor kpLightBlue; +static QColor kpTan; + +static bool ownColorsInitialised = false; + +/* TODO: clean up this code!!! + * (probably when adding palette load/save) + */ +#define rows 2 +#define cols 11 +kpColorCells::kpColorCells (QWidget *parent, + Qt::Orientation o, + const char *name) + : KColorCells (parent, rows, cols), + m_mouseButton (-1) +{ + setName (name); + + setShading (false); // no 3D look + + // Trap KColorDrag so that kpMainWindow does not trap it. + // See our impl of dropEvent(). + setAcceptDrops (true); + setAcceptDrags (true); + + connect (this, SIGNAL (colorDoubleClicked (int)), + SLOT (slotColorDoubleClicked (int))); + + if (!ownColorsInitialised) + { + // Don't initialise globally when we probably don't have a colour + // allocation context. This way, the colours aren't sometimes + // invalid (e.g. at 8-bit). + + kpRed = QColor (255, 0, 0); + kpGreen = QColor (0, 255, 0); + kpBlue = QColor (0, 0, 255); + kpBlack = QColor (0, 0, 0); + kpWhite = QColor (255, 255, 255); + + kpYellow = add (kpRed, kpGreen); + kpPurple = add (kpRed, kpBlue); + kpAqua = add (kpGreen, kpBlue); + + kpGrey = blend (kpBlack, kpWhite); + kpLightGrey = blend (kpGrey, kpWhite); + kpOrange = blend (kpRed, kpYellow); + + kpPink = blend (kpRed, kpWhite); + kpLightGreen = blend (kpGreen, kpWhite); + kpLightBlue = blend (kpBlue, kpWhite); + kpTan = blend (kpYellow, kpWhite); + + ownColorsInitialised = true; + } + + setOrientation (o); +} + +kpColorCells::~kpColorCells () +{ +} + +Qt::Orientation kpColorCells::orientation () const +{ + return m_orientation; +} + +void kpColorCells::setOrientation (Qt::Orientation o) +{ + int c, r; + + if (o == Qt::Horizontal) + { + c = cols; + r = rows; + } + else + { + c = rows; + r = cols; + } + +#if DEBUG_KP_COLOR_TOOL_BAR + kdDebug () << "kpColorCells::setOrientation(): r=" << r << " c=" << c << endl; +#endif + + setNumRows (r); + setNumCols (c); + + setCellWidth (26); + setCellHeight (26); + + setFixedSize (numCols () * cellWidth () + frameWidth () * 2, + numRows () * cellHeight () + frameWidth () * 2); + +/* + kdDebug () << "\tlimits: array=" << sizeof (colors) / sizeof (colors [0]) + << " r*c=" << r * c << endl; + kdDebug () << "\tsizeof (colors)=" << sizeof (colors) + << " sizeof (colors [0])=" << sizeof (colors [0]) + << endl;*/ + QColor colors [] = + { + kpBlack, + kpGrey, + kpRed, + kpOrange, + kpYellow, + kpGreen, + kpAqua, + kpBlue, + kpPurple, + kpPink, + kpLightGreen, + + kpWhite, + kpLightGrey, + dark (kpRed), + dark (kpOrange)/*brown*/, + dark (kpYellow), + dark (kpGreen), + dark (kpAqua), + dark (kpBlue), + dark (kpPurple), + kpLightBlue, + kpTan + }; + + for (int i = 0; + /*i < int (sizeof (colors) / sizeof (colors [0])) &&*/ + i < r * c; + i++) + { + int y, x; + int pos; + + if (o == Qt::Horizontal) + { + y = i / cols; + x = i % cols; + pos = i; + } + else + { + y = i % cols; + x = i / cols; + // int x = rows - 1 - i / cols; + pos = y * rows + x; + } + + KColorCells::setColor (pos, colors [i]); + //QToolTip::add (this, cellGeometry (y, x), colors [i].name ()); + } + + m_orientation = o; +} + +// virtual protected [base KColorCells] +void kpColorCells::dropEvent (QDropEvent *e) +{ + // Eat event so that: + // + // 1. User doesn't clobber the palette (until we support reconfigurable + // palettes) + // 2. kpMainWindow::dropEvent() doesn't try to paste colour code as text + // (when the user slips and drags colour cell a little instead of clicking) + e->accept (); +} + +// virtual protected +void kpColorCells::paintCell (QPainter *painter, int row, int col) +{ + QColor oldColor; + int cellNo; + + if (!isEnabled ()) + { + cellNo = row * numCols () + col; + + // make all cells 3D (so that disabled palette doesn't look flat) + setShading (true); + + oldColor = KColorCells::color (cellNo); + KColorCells::colors [cellNo] = backgroundColor (); + } + + + // no focus rect as it doesn't make sense + // since 2 colors (foreground & background) can be selected + KColorCells::selected = -1; + KColorCells::paintCell (painter, row, col); + + + if (!isEnabled ()) + { + KColorCells::colors [cellNo] = oldColor; + setShading (false); + } +} + +// virtual protected +void kpColorCells::mouseReleaseEvent (QMouseEvent *e) +{ + m_mouseButton = -1; + + Qt::ButtonState button = e->button (); +#if DEBUG_KP_COLOR_TOOL_BAR + kdDebug () << "kpColorCells::mouseReleaseEvent(left=" + << (button & Qt::LeftButton) + << ",right=" + << (button & Qt::RightButton) + << ")" + << endl; +#endif + if (!((button & Qt::LeftButton) && (button & Qt::RightButton))) + { + if (button & Qt::LeftButton) + m_mouseButton = 0; + else if (button & Qt::RightButton) + m_mouseButton = 1; + } + + connect (this, SIGNAL (colorSelected (int)), this, SLOT (slotColorSelected (int))); + KColorCells::mouseReleaseEvent (e); + disconnect (this, SIGNAL (colorSelected (int)), this, SLOT (slotColorSelected (int))); + +#if DEBUG_KP_COLOR_TOOL_BAR + kdDebug () << "kpColorCells::mouseReleaseEvent() setting m_mouseButton back to -1" << endl; +#endif + m_mouseButton = -1; +} + +// protected virtual [base KColorCells] +void kpColorCells::resizeEvent (QResizeEvent *e) +{ + // KColorCells::resizeEvent() tries to adjust the cellWidth and cellHeight + // to the current dimensions but doesn't take into account + // frame{Width,Height}(). + // + // In any case, we already set the cell{Width,Height} and a fixed + // widget size and don't want any of it changed. Eat the resize event. + (void) e; +} + +// protected slot +void kpColorCells::slotColorSelected (int cell) +{ +#if DEBUG_KP_COLOR_TOOL_BAR + kdDebug () << "kpColorCells::slotColorSelected(cell=" << cell + << ") mouseButton = " << m_mouseButton << endl; +#endif + QColor c = KColorCells::color (cell); + + if (m_mouseButton == 0) + { + emit foregroundColorChanged (c); + emit foregroundColorChanged (kpColor (c.rgb ())); + } + else if (m_mouseButton == 1) + { + emit backgroundColorChanged (c); + emit backgroundColorChanged (kpColor (c.rgb ())); + } + + m_mouseButton = -1; // just in case +} + +// protected slot +void kpColorCells::slotColorDoubleClicked (int cell) +{ +#if DEBUG_KP_COLOR_TOOL_BAR + kdDebug () << "kpColorCells::slotColorDoubleClicked(cell=" + << cell << ")" << endl; +#endif + + QColor color = KColorCells::color (cell); + + // TODO: parent + if (KColorDialog::getColor (color/*ref*/)) + KColorCells::setColor (cell, color); +} + + +/* + * kpTransparentColorCell + */ + +kpTransparentColorCell::kpTransparentColorCell (QWidget *parent, const char *name) + : QFrame (parent, name) +{ +#if DEBUG_KP_COLOR_TOOL_BAR + kdDebug () << "kpTransparentColorCell::kpTransparentColorCell()" << endl; +#endif + + setFrameStyle (QFrame::Panel | QFrame::Sunken); +#if DEBUG_KP_COLOR_TOOL_BAR && 0 + kdDebug () << "\tdefault line width=" << lineWidth () + << " frame width=" << frameWidth () << endl; +#endif + //setLineWidth (2); +#if DEBUG_KP_COLOR_TOOL_BAR && 0 + kdDebug () << "\tline width=" << lineWidth () + << " frame width=" << frameWidth () << endl; +#endif + + m_pixmap = UserIcon ("color_transparent_26x26"); + + QToolTip::add (this, i18n ("Transparent")); +} + +kpTransparentColorCell::~kpTransparentColorCell () +{ +} + + +// public virtual [base QWidget] +QSize kpTransparentColorCell::sizeHint () const +{ + return QSize (m_pixmap.width () + frameWidth () * 2, + m_pixmap.height () + frameWidth () * 2); +} + +// protected virtual [base QWidget] +void kpTransparentColorCell::mousePressEvent (QMouseEvent * /*e*/) +{ + // eat right-mouse click to prevent it from getting to the toolbar +} + +// protected virtual [base QWidget] +void kpTransparentColorCell::mouseReleaseEvent (QMouseEvent *e) +{ + if (rect ().contains (e->pos ())) + { + if (e->button () == Qt::LeftButton) + { + emit transparentColorSelected (0); + emit foregroundColorChanged (kpColor::transparent); + } + else if (e->button () == Qt::RightButton) + { + emit transparentColorSelected (1); + emit backgroundColorChanged (kpColor::transparent); + } + } +} + +// protected virtual [base QFrame] +void kpTransparentColorCell::drawContents (QPainter *p) +{ + QFrame::drawContents (p); + if (isEnabled ()) + { + #if DEBUG_KP_COLOR_TOOL_BAR + kdDebug () << "kpTransparentColorCell::drawContents() contentsRect=" + << contentsRect () + << endl; + #endif + p->drawPixmap (contentsRect (), m_pixmap); + } +} + + +/* + * kpColorPalette + */ + +kpColorPalette::kpColorPalette (QWidget *parent, + Qt::Orientation o, + const char *name) + : QWidget (parent, name), + m_boxLayout (0) +{ +#if DEBUG_KP_COLOR_TOOL_BAR + kdDebug () << "kpColorPalette::kpColorPalette()" << endl; +#endif + + m_transparentColorCell = new kpTransparentColorCell (this); + m_transparentColorCell->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed); + connect (m_transparentColorCell, SIGNAL (foregroundColorChanged (const kpColor &)), + this, SIGNAL (foregroundColorChanged (const kpColor &))); + connect (m_transparentColorCell, SIGNAL (backgroundColorChanged (const kpColor &)), + this, SIGNAL (backgroundColorChanged (const kpColor &))); + + m_colorCells = new kpColorCells (this); + connect (m_colorCells, SIGNAL (foregroundColorChanged (const kpColor &)), + this, SIGNAL (foregroundColorChanged (const kpColor &))); + connect (m_colorCells, SIGNAL (backgroundColorChanged (const kpColor &)), + this, SIGNAL (backgroundColorChanged (const kpColor &))); + + setOrientation (o); +} + +kpColorPalette::~kpColorPalette () +{ +} + +// public +Qt::Orientation kpColorPalette::orientation () const +{ + return m_orientation; +} + +void kpColorPalette::setOrientation (Qt::Orientation o) +{ + m_colorCells->setOrientation (o); + + delete m_boxLayout; + + if (o == Qt::Horizontal) + { + m_boxLayout = new QBoxLayout (this, QBoxLayout::LeftToRight, 0/*margin*/, 5/*spacing*/); + m_boxLayout->addWidget (m_transparentColorCell, 0/*stretch*/, Qt::AlignVCenter); + m_boxLayout->addWidget (m_colorCells); + } + else + { + m_boxLayout = new QBoxLayout (this, QBoxLayout::TopToBottom, 0/*margin*/, 5/*spacing*/); + m_boxLayout->addWidget (m_transparentColorCell, 0/*stretch*/, Qt::AlignHCenter); + m_boxLayout->addWidget (m_colorCells); + } + + m_orientation = o; +} + + +/* + * kpColorSimilarityToolBarItem + */ + +kpColorSimilarityToolBarItem::kpColorSimilarityToolBarItem (kpMainWindow *mainWindow, + QWidget *parent, + const char *name) + : kpColorSimilarityCube (kpColorSimilarityCube::Depressed | + kpColorSimilarityCube::DoubleClickInstructions, + mainWindow, parent, name), + m_mainWindow (mainWindow), + m_processedColorSimilarity (kpColor::Exact) +{ + setColorSimilarity (mainWindow->configColorSimilarity ()); +} + +kpColorSimilarityToolBarItem::~kpColorSimilarityToolBarItem () +{ +} + + +// public +int kpColorSimilarityToolBarItem::processedColorSimilarity () const +{ + return m_processedColorSimilarity; +} + + +// public slot +void kpColorSimilarityToolBarItem::setColorSimilarity (double similarity) +{ + m_oldColorSimilarity = colorSimilarity (); + + kpColorSimilarityCube::setColorSimilarity (similarity); + if (similarity > 0) + QToolTip::add (this, i18n ("Color similarity: %1%").arg (qRound (similarity * 100))); + else + QToolTip::add (this, i18n ("Color similarity: Exact")); + + m_processedColorSimilarity = kpColor::processSimilarity (colorSimilarity ()); + + m_mainWindow->configSetColorSimilarity (colorSimilarity ()); + + emit colorSimilarityChanged (colorSimilarity (), m_processedColorSimilarity); +} + +// public +double kpColorSimilarityToolBarItem::oldColorSimilarity () const +{ + return m_oldColorSimilarity; +} + + +// private virtual [base QWidget] +void kpColorSimilarityToolBarItem::mousePressEvent (QMouseEvent * /*e*/) +{ + // eat right-mouse click to prevent it from getting to the toolbar +} + +// private virtual [base QWidget] +void kpColorSimilarityToolBarItem::mouseDoubleClickEvent (QMouseEvent * /*e*/) +{ + kpColorSimilarityDialog dialog (m_mainWindow, this); + dialog.setColorSimilarity (colorSimilarity ()); + if (dialog.exec ()) + { + setColorSimilarity (dialog.colorSimilarity ()); + } +} + + +/* + * kpColorToolBar + */ + +kpColorToolBar::kpColorToolBar (const QString &label, kpMainWindow *mainWindow, const char *name) + : KToolBar (mainWindow, name), + m_mainWindow (mainWindow) +{ + setText (label); + + + QWidget *base = new QWidget (this); + m_boxLayout = new QBoxLayout (base, QBoxLayout::LeftToRight, + 5/*margin*/, (10 * 4)/*spacing*/); + + m_dualColorButton = new kpDualColorButton (mainWindow, base); + m_dualColorButton->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed); + connect (m_dualColorButton, SIGNAL (colorsSwapped (const kpColor &, const kpColor &)), + this, SIGNAL (colorsSwapped (const kpColor &, const kpColor &))); + connect (m_dualColorButton, SIGNAL (foregroundColorChanged (const kpColor &)), + this, SIGNAL (foregroundColorChanged (const kpColor &))); + connect (m_dualColorButton, SIGNAL (backgroundColorChanged (const kpColor &)), + this, SIGNAL (backgroundColorChanged (const kpColor &))); + m_boxLayout->addWidget (m_dualColorButton, 0/*stretch*/); + + m_colorPalette = new kpColorPalette (base); + connect (m_colorPalette, SIGNAL (foregroundColorChanged (const kpColor &)), + m_dualColorButton, SLOT (setForegroundColor (const kpColor &))); + connect (m_colorPalette, SIGNAL (backgroundColorChanged (const kpColor &)), + m_dualColorButton, SLOT (setBackgroundColor (const kpColor &))); + m_boxLayout->addWidget (m_colorPalette, 0/*stretch*/); + + m_colorSimilarityToolBarItem = new kpColorSimilarityToolBarItem (mainWindow, base); + m_colorSimilarityToolBarItem->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed); + connect (m_colorSimilarityToolBarItem, SIGNAL (colorSimilarityChanged (double, int)), + this, SIGNAL (colorSimilarityChanged (double, int))); + m_boxLayout->addWidget (m_colorSimilarityToolBarItem, 0/*stretch*/); + + // HACK: couldn't get QSpacerItem to work + QWidget *fakeSpacer = new QWidget (base); + m_boxLayout->addWidget (fakeSpacer, 1/*stretch*/); + + m_lastDockedOrientationSet = false; + setOrientation (orientation ()); + + KToolBar::insertWidget (0, base->width (), base); +} + +// virtual +void kpColorToolBar::setOrientation (Qt::Orientation o) +{ + // (QDockWindow::undock() calls us) + bool isOutsideDock = (place () == QDockWindow::OutsideDock); + + if (!m_lastDockedOrientationSet || !isOutsideDock) + { + m_lastDockedOrientation = o; + m_lastDockedOrientationSet = true; + } + + if (isOutsideDock) + { + //kdDebug () << "\toutside dock, forcing orientation to last" << endl; + o = m_lastDockedOrientation; + } + + if (o == Qt::Horizontal) + { + m_boxLayout->setDirection (QBoxLayout::LeftToRight); + } + else + { + m_boxLayout->setDirection (QBoxLayout::TopToBottom); + } + + m_colorPalette->setOrientation (o); + + KToolBar::setOrientation (o); +} + +kpColorToolBar::~kpColorToolBar () +{ +} + +kpColor kpColorToolBar::color (int which) const +{ + if (which < 0 || which > 1) + { + kdWarning () << "kpColorToolBar::color (" << which + << ") - out of range" << endl; + which = 0; + } + + return m_dualColorButton->color (which); +} + +void kpColorToolBar::setColor (int which, const kpColor &color) +{ + if (which < 0 || which > 1) + { + kdWarning () << "kpColorToolBar::setColor (" << which + << ") - out of range" << endl; + which = 0; + } + + m_dualColorButton->setColor (which, color); +} + +kpColor kpColorToolBar::foregroundColor () const +{ + return m_dualColorButton->foregroundColor (); +} + +void kpColorToolBar::setForegroundColor (const kpColor &color) +{ + m_dualColorButton->setForegroundColor (color); +} + +kpColor kpColorToolBar::backgroundColor () const +{ + return m_dualColorButton->backgroundColor (); +} + +void kpColorToolBar::setBackgroundColor (const kpColor &color) +{ + m_dualColorButton->setBackgroundColor (color); +} + + +kpColor kpColorToolBar::oldForegroundColor () const +{ + return m_dualColorButton->oldForegroundColor (); +} + +kpColor kpColorToolBar::oldBackgroundColor () const +{ + return m_dualColorButton->oldBackgroundColor (); +} + +double kpColorToolBar::oldColorSimilarity () const +{ + return m_colorSimilarityToolBarItem->oldColorSimilarity (); +} + + +double kpColorToolBar::colorSimilarity () const +{ + return m_colorSimilarityToolBarItem->colorSimilarity (); +} + +void kpColorToolBar::setColorSimilarity (double similarity) +{ + m_colorSimilarityToolBarItem->setColorSimilarity (similarity); +} + +int kpColorToolBar::processedColorSimilarity () const +{ + return m_colorSimilarityToolBarItem->processedColorSimilarity (); +} + + +#include diff --git a/kolourpaint/widgets/kpcolortoolbar.h b/kolourpaint/widgets/kpcolortoolbar.h new file mode 100644 index 00000000..b4a77bfb --- /dev/null +++ b/kolourpaint/widgets/kpcolortoolbar.h @@ -0,0 +1,297 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kp_color_toolbar_h__ +#define __kp_color_toolbar_h__ + + +#include +#include + +#include +#include + +#include +#include + + +class QGridLayout; +class KColorButton; + +class kpColorSimilarityCube; +class kpMainWindow; + + +// +// Widget similar to KDualColorButton. +// Main differences: +// - more consistent feel with other KolourPaint widgets +// (esp. kpColorPalette) +// - displays the transparent colour using the special pixmap +// used by kpTransparentColorCell +// - no obscure "current" colour +// +class kpDualColorButton : public QFrame +{ +Q_OBJECT + +public: + kpDualColorButton (kpMainWindow *mainWindow, + QWidget *parent, const char *name = 0); + virtual ~kpDualColorButton (); + + kpColor color (int which) const; + kpColor foregroundColor () const; + kpColor backgroundColor () const; + +public slots: + void setColor (int which, const kpColor &color); + void setForegroundColor (const kpColor &color); + void setBackgroundColor (const kpColor &color); + +signals: + // If you connect to this signal, ignore the following + // foregroundColorChanged() and backgroundColorChanged() signals + void colorsSwapped (const kpColor &newForegroundColor, + const kpColor &newBackgroundColor); + + void foregroundColorChanged (const kpColor &color); + void backgroundColorChanged (const kpColor &color); + +public: + // (only valid in slots connected to foregroundColorChanged()) + kpColor oldForegroundColor () const; + // (only valid in slots connected to backgroundColorChanged()) + kpColor oldBackgroundColor () const; + +public: + virtual QSize sizeHint () const; + +protected: + QRect swapPixmapRect () const; + QRect foregroundBackgroundRect () const; + QRect foregroundRect () const; + QRect backgroundRect () const; + + //virtual void dragEnterEvent (QDragEnterEvent *e); + virtual void dragMoveEvent (QDragMoveEvent *e); + virtual void dropEvent (QDropEvent *e); + + virtual void mousePressEvent (QMouseEvent *e); + virtual void mouseDoubleClickEvent (QMouseEvent *e); + virtual void mouseReleaseEvent (QMouseEvent *e); + + virtual void drawContents (QPainter *p); + + kpMainWindow *m_mainWindow; + kpColor m_color [2]; + kpColor m_oldColor [2]; + QPixmap *m_backBuffer; +}; + + +class kpColorCells : public KColorCells +{ +Q_OBJECT + +public: + kpColorCells (QWidget *parent, + Qt::Orientation o = Qt::Horizontal, + const char *name = 0); + virtual ~kpColorCells (); + + Qt::Orientation orientation () const; + void setOrientation (Qt::Orientation o); + +signals: + void foregroundColorChanged (const QColor &color); + void backgroundColorChanged (const QColor &color); + + // lazy + void foregroundColorChanged (const kpColor &color); + void backgroundColorChanged (const kpColor &color); + +protected: + Qt::Orientation m_orientation; + + virtual void dropEvent (QDropEvent *e); + virtual void paintCell (QPainter *painter, int row, int col); + virtual void mouseReleaseEvent (QMouseEvent *e); + virtual void resizeEvent (QResizeEvent *e); + + int m_mouseButton; + +protected slots: + void slotColorSelected (int cell); + void slotColorDoubleClicked (int cell); +}; + + +class kpTransparentColorCell : public QFrame +{ +Q_OBJECT + +public: + kpTransparentColorCell (QWidget *parent, const char *name = 0); + virtual ~kpTransparentColorCell (); + + virtual QSize sizeHint () const; + +signals: + void transparentColorSelected (int mouseButton); + + // lazy + void foregroundColorChanged (const kpColor &color); + void backgroundColorChanged (const kpColor &color); + +protected: + virtual void mousePressEvent (QMouseEvent *e); + virtual void mouseReleaseEvent (QMouseEvent *e); + + virtual void drawContents (QPainter *p); + + QPixmap m_pixmap; +}; + + +class kpColorPalette : public QWidget +{ +Q_OBJECT + +public: + kpColorPalette (QWidget *parent, + Qt::Orientation o = Qt::Horizontal, + const char *name = 0); + virtual ~kpColorPalette (); + + Qt::Orientation orientation () const; + void setOrientation (Qt::Orientation o); + +signals: + void foregroundColorChanged (const kpColor &color); + void backgroundColorChanged (const kpColor &color); + +protected: + Qt::Orientation m_orientation; + + QBoxLayout *m_boxLayout; + kpTransparentColorCell *m_transparentColorCell; + kpColorCells *m_colorCells; +}; + + +class kpColorSimilarityToolBarItem : public kpColorSimilarityCube +{ +Q_OBJECT + +public: + kpColorSimilarityToolBarItem (kpMainWindow *mainWindow, + QWidget *parent, + const char *name = 0); + virtual ~kpColorSimilarityToolBarItem (); + +public: + int processedColorSimilarity () const; + +public slots: + void setColorSimilarity (double similarity); + +signals: + void colorSimilarityChanged (double similarity, int processedSimilarity); + +public: + // (only valid in slots connected to colorSimilarityChanged()); + double oldColorSimilarity () const; + +private: + virtual void mousePressEvent (QMouseEvent *e); + virtual void mouseDoubleClickEvent (QMouseEvent *e); + +private: + kpMainWindow *m_mainWindow; + + double m_oldColorSimilarity; + int m_processedColorSimilarity; +}; + + +class kpColorToolBar : public KToolBar +{ +Q_OBJECT + +public: + kpColorToolBar (const QString &label, kpMainWindow *mainWindow, const char *name = 0); + virtual ~kpColorToolBar (); + + kpColor color (int which) const; + void setColor (int which, const kpColor &color); + + kpColor foregroundColor () const; + kpColor backgroundColor () const; + + double colorSimilarity () const; + void setColorSimilarity (double similarity); + int processedColorSimilarity () const; + +signals: + // If you connect to this signal, ignore the following + // foregroundColorChanged() and backgroundColorChanged() signals + void colorsSwapped (const kpColor &newForegroundColor, + const kpColor &newBackgroundColor); + + void foregroundColorChanged (const kpColor &color); + void backgroundColorChanged (const kpColor &color); + void colorSimilarityChanged (double similarity, int processedSimilarity); + +public: + // (only valid in slots connected to foregroundColorChanged()) + kpColor oldForegroundColor () const; + // (only valid in slots connected to backgroundColorChanged()) + kpColor oldBackgroundColor () const; + + // (only valid in slots connected to colorSimilarityChanged()) + double oldColorSimilarity () const; + +public slots: + void setForegroundColor (const kpColor &color); + void setBackgroundColor (const kpColor &color); + +private: + kpMainWindow *m_mainWindow; + + Qt::Orientation m_lastDockedOrientation; + bool m_lastDockedOrientationSet; + virtual void setOrientation (Qt::Orientation o); + + QBoxLayout *m_boxLayout; + kpDualColorButton *m_dualColorButton; + kpColorPalette *m_colorPalette; + kpColorSimilarityToolBarItem *m_colorSimilarityToolBarItem; +}; + +#endif // __kp_color_toolbar_h__ diff --git a/kolourpaint/widgets/kpresizesignallinglabel.cpp b/kolourpaint/widgets/kpresizesignallinglabel.cpp new file mode 100644 index 00000000..77d0ad2b --- /dev/null +++ b/kolourpaint/widgets/kpresizesignallinglabel.cpp @@ -0,0 +1,67 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_RESIZE_SIGNALLING_LABEL 0 + + +#include + +#include + + +kpResizeSignallingLabel::kpResizeSignallingLabel (const QString &string, + QWidget *parent, + const char *name) + : QLabel (string, parent, name) +{ +} + +kpResizeSignallingLabel::kpResizeSignallingLabel (QWidget *parent, + const char *name) + : QLabel (parent, name) +{ +} + +kpResizeSignallingLabel::~kpResizeSignallingLabel () +{ +} + + +// protected virtual [base QLabel] +void kpResizeSignallingLabel::resizeEvent (QResizeEvent *e) +{ +#if DEBUG_KP_RESIZE_SIGNALLING_LABEL + kdDebug () << "kpResizeSignallingLabel::resizeEvent() newSize=" << e->size () + << " oldSize=" << e->oldSize () << endl; +#endif + QLabel::resizeEvent (e); + + emit resized (); +} + + +#include diff --git a/kolourpaint/widgets/kpresizesignallinglabel.h b/kolourpaint/widgets/kpresizesignallinglabel.h new file mode 100644 index 00000000..6cd3beba --- /dev/null +++ b/kolourpaint/widgets/kpresizesignallinglabel.h @@ -0,0 +1,52 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef KP_RESIZE_SIGNALLING_LABEL +#define KP_RESIZE_SIGNALLING_LABEL + + +#include + + +class kpResizeSignallingLabel : public QLabel +{ +Q_OBJECT + +public: + kpResizeSignallingLabel (const QString &string, QWidget *parent, const char *name = 0); + kpResizeSignallingLabel (QWidget *parent, const char *name = 0); + virtual ~kpResizeSignallingLabel (); + +signals: + void resized (); + +protected: + virtual void resizeEvent (QResizeEvent *e); +}; + + +#endif // KP_RESIZE_SIGNALLING_LABEL diff --git a/kolourpaint/widgets/kpsqueezedtextlabel.cpp b/kolourpaint/widgets/kpsqueezedtextlabel.cpp new file mode 100644 index 00000000..53fd85c9 --- /dev/null +++ b/kolourpaint/widgets/kpsqueezedtextlabel.cpp @@ -0,0 +1,215 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG_KP_SQUEEZED_TEXT_LABEL 0 + + +#include + +#include +#include +#include + +#include +#include + + +kpSqueezedTextLabel::kpSqueezedTextLabel (QWidget *parent, const char *name) + : QLabel (parent, name), + m_showEllipsis (true) +{ +} + +kpSqueezedTextLabel::kpSqueezedTextLabel (const QString &text, QWidget *parent, const char *name) + : QLabel (parent, name), + m_showEllipsis (true) +{ + setText (text); +} + + +// public virtual +QSize kpSqueezedTextLabel::minimumSizeHint () const +{ +#if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1 + kdDebug () << "kpSqueezedTextLabel::minimumSizeHint() qLabel prefers" + << QLabel::minimumSizeHint () << endl; +#endif + return QSize (-1/*no minimum width*/, QLabel::minimumHeight ()); +} + + +// public +QString kpSqueezedTextLabel::fullText () const +{ + return m_fullText; +} + + +// public +bool kpSqueezedTextLabel::showEllipsis () const +{ + return m_showEllipsis; +} + +// public +void kpSqueezedTextLabel::setShowEllipsis (bool yes) +{ + if (m_showEllipsis == yes) + return; + + m_showEllipsis = yes; + + squeezeText (); +} + + +// public slots virtual [base QLabel] +void kpSqueezedTextLabel::setText (const QString &text) +{ + m_fullText = text; + squeezeText (); +} + + +// protected virtual [base QWidget] +void kpSqueezedTextLabel::resizeEvent (QResizeEvent *e) +{ +#if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1 + kdDebug () << "kpSqueezedTextLabeL::resizeEvent() size=" << e->size () + << " oldSize=" << e->oldSize () + << endl; +#endif + squeezeText (); +} + + +// protected +QString kpSqueezedTextLabel::ellipsisText () const +{ + return m_showEllipsis ? i18n ("...") : QString::null; +} + +// protected +void kpSqueezedTextLabel::squeezeText () +{ +#if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1 + kdDebug () << "kpSqueezedTextLabeL::squeezeText" << endl; +#endif + + QFontMetrics fontMetrics (font ()); + int fullTextWidth = fontMetrics.width (m_fullText); +#if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1 + kdDebug () << "\tfullText=" << m_fullText + << " fullTextWidth=" << fullTextWidth + << " labelWidth=" << width () + << endl; +#endif + + if (fullTextWidth <= width ()) + { + #if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1 + kdDebug () << "\tfullText will fit - display" << endl; + #endif + QLabel::setText (m_fullText); + } + else + { + #if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1 + kdDebug () << "\tfullText won't fit :( - squeeze" << endl; + kdDebug () << "\t\twidth of \"...\"=" + << fontMetrics.width (ellipsisText ()) + << endl; + + #endif + if (fontMetrics.width (ellipsisText ()) > width ()) + { + #if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1 + kdDebug () << "\t\t\tcan't even fit \"...\" - forget it" << endl; + #endif + QLabel::setText (QString::null); + return; + } + + // Binary search our way to fit squeezed text + int numLettersToUseLo = 0; + int numLettersToUseHi = m_fullText.length (); + int numLettersToUse = 0; + + while (numLettersToUseLo <= numLettersToUseHi) + { + int numLettersToUseMid = (numLettersToUseLo + numLettersToUseHi) / 2; + int squeezedWidth = fontMetrics.width (m_fullText.left (numLettersToUseMid) + ellipsisText ()); + #if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1 + kdDebug () << "\tbsearch: lo=" << numLettersToUseLo + << " hi=" << numLettersToUseHi + << " mid=" << numLettersToUseMid + << " acceptable=" << numLettersToUse + << " squeezedWidth=" << squeezedWidth + << endl; + #endif + + if (squeezedWidth == width ()) + { + #if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1 + kdDebug () << "\t\tperfect match!" << endl; + #endif + numLettersToUse = numLettersToUseMid; + break; + } + else if (squeezedWidth < width ()) + { + #if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1 + kdDebug () << "\t\tsmall enough - numLettersToUse=" + << numLettersToUse << endl; + #endif + if (numLettersToUseMid > numLettersToUse) + { + numLettersToUse = numLettersToUseMid; + #if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1 + kdDebug () << "\t\t\tset numLettersToUse=" + << numLettersToUse + << endl; + #endif + } + + numLettersToUseLo = numLettersToUseMid + 1; + } + else + { + #if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1 + kdDebug () << "\t\ttoo big" << endl; + #endif + numLettersToUseHi = numLettersToUseMid - 1; + } + } + + QLabel::setText (m_fullText.left (numLettersToUse) + ellipsisText ()); + } +} + +#include diff --git a/kolourpaint/widgets/kpsqueezedtextlabel.h b/kolourpaint/widgets/kpsqueezedtextlabel.h new file mode 100644 index 00000000..57aa7b2f --- /dev/null +++ b/kolourpaint/widgets/kpsqueezedtextlabel.h @@ -0,0 +1,65 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __kp_squeezed_text_label_h__ +#define __kp_squeezed_text_label_h__ + +#include +#include + + +// KSqueezedTextLabel done properly - squeeze at the end of the string, +// not the middle. +class kpSqueezedTextLabel : public QLabel +{ +Q_OBJECT + +public: + kpSqueezedTextLabel (QWidget *parent, const char *name = 0); + kpSqueezedTextLabel (const QString &text, QWidget *parent, const char *name = 0); + + virtual QSize minimumSizeHint () const; + + // TODO: maybe text() should return the full text? + QString fullText () const; + + bool showEllipsis () const; + void setShowEllipsis (bool yes = true); + +public slots: + virtual void setText (const QString &text); + +protected: + virtual void resizeEvent (QResizeEvent *); + QString ellipsisText () const; + void squeezeText (); + + QString m_fullText; + bool m_showEllipsis; +}; + +#endif // __kp_squeezed_text_label_h__ diff --git a/kolourpaint/widgets/kptooltoolbar.cpp b/kolourpaint/widgets/kptooltoolbar.cpp new file mode 100644 index 00000000..b8d1985c --- /dev/null +++ b/kolourpaint/widgets/kptooltoolbar.cpp @@ -0,0 +1,640 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_TOOL_TOOL_BAR 0 + + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class kpToolButton : public QToolButton +{ +public: + kpToolButton (kpTool *tool, QWidget *parent) + : QToolButton (parent), + m_tool (tool) + { + } + + virtual ~kpToolButton () + { + } + +protected: + // virtual [base QWidget] + void mouseDoubleClickEvent (QMouseEvent *e) + { + if (e->button () == Qt::LeftButton && m_tool) + m_tool->globalDraw (); + } + + kpTool *m_tool; +}; + + +kpToolToolBar::kpToolToolBar (const QString &label, kpMainWindow *mainWindow, int colsOrRows, const char *name) + : KToolBar ((QWidget *) mainWindow, name, false/*don't use global toolBar settings*/, true/*readConfig*/), + m_vertCols (colsOrRows), + m_buttonGroup (0), + m_baseWidget (0), + m_baseLayout (0), + m_toolLayout (0), + m_previousTool (0), m_currentTool (0), + m_defaultIconSize (0) +{ + setText (label); + + + // With these lines enabled, mousePressEvent's weren't being generated + // when right clicking in empty part of the toolbar (each call affects + // the toolbar in its respective orientation). They don't seem to be + // needed anyway since !isResizeEnabled(). + + //setHorizontallyStretchable (false); + //setVerticallyStretchable (false); + + + m_baseWidget = new QWidget (this); + +#if DEBUG_KP_TOOL_TOOL_BAR + QTime timer; + timer.start (); +#endif + + m_toolWidgets.append (m_toolWidgetBrush = + new kpToolWidgetBrush (m_baseWidget, "Tool Widget Brush")); + m_toolWidgets.append (m_toolWidgetEraserSize = + new kpToolWidgetEraserSize (m_baseWidget, "Tool Widget Eraser Size")); + m_toolWidgets.append (m_toolWidgetFillStyle = + new kpToolWidgetFillStyle (m_baseWidget, "Tool Widget Fill Style")); + m_toolWidgets.append (m_toolWidgetLineWidth = + new kpToolWidgetLineWidth (m_baseWidget, "Tool Widget Line Width")); + m_toolWidgets.append (m_toolWidgetOpaqueOrTransparent = + new kpToolWidgetOpaqueOrTransparent (m_baseWidget, "Tool Widget Opaque/Transparent")); + m_toolWidgets.append (m_toolWidgetSpraycanSize = + new kpToolWidgetSpraycanSize (m_baseWidget, "Tool Widget Spraycan Size")); + +#if DEBUG_KP_TOOL_TOOL_BAR + kdDebug () << "kpToolToolBar:: create tool widgets msec=" + << timer.restart () << endl; +#endif + + for (QValueVector ::const_iterator it = m_toolWidgets.begin (); + it != m_toolWidgets.end (); + it++) + { + connect (*it, SIGNAL (optionSelected (int, int)), + this, SIGNAL (toolWidgetOptionSelected ())); + } + +#if DEBUG_KP_TOOL_TOOL_BAR + kdDebug () << "kpToolToolBar:: connect widgets msec=" + << timer.restart () << endl; +#endif + + m_lastDockedOrientationSet = false; + setOrientation (orientation ()); + +#if DEBUG_KP_TOOL_TOOL_BAR + kdDebug () << "kpToolToolBar:: layout tool widgets msec=" + << timer.elapsed () << endl; +#endif + + m_buttonGroup = new QButtonGroup (); // invisible + m_buttonGroup->setExclusive (true); + + connect (m_buttonGroup, SIGNAL (clicked (int)), SLOT (slotToolButtonClicked ())); + + hideAllToolWidgets (); +} + +kpToolToolBar::~kpToolToolBar () +{ + unregisterAllTools (); + delete m_buttonGroup; +} + + +// private +int kpToolToolBar::defaultIconSize () +{ + // Cached? + if (m_defaultIconSize > 0) + return m_defaultIconSize; + +#if DEBUG_KP_TOOL_TOOL_BAR + kdDebug () << "kpToolToolBar::defaultIconSize()" << endl; +#endif + + + KConfigGroupSaver cfgGroupSaver (KGlobal::config (), + kpSettingsGroupTools); + KConfigBase *cfg = cfgGroupSaver.config (); + + if (cfg->hasKey (kpSettingToolBoxIconSize)) + { + m_defaultIconSize = cfg->readNumEntry (kpSettingToolBoxIconSize); + #if DEBUG_KP_TOOL_TOOL_BAR + kdDebug () << "\tread: " << m_defaultIconSize << endl; + #endif + } + else + { + m_defaultIconSize = -1; +#if DEBUG_KP_TOOL_TOOL_BAR + kdDebug () << "\tfirst time - writing default: " << m_defaultIconSize << endl; +#endif + cfg->writeEntry (kpSettingToolBoxIconSize, m_defaultIconSize); + cfg->sync (); + } + + + if (m_defaultIconSize <= 0) + { + // Adapt according to screen geometry + const QRect desktopSize = KGlobalSettings::desktopGeometry (this); + #if DEBUG_KP_TOOL_TOOL_BAR + kdDebug () << "\tadapting to screen size=" << desktopSize << endl; + #endif + + if (desktopSize.width () >= 1024 && desktopSize.height () >= 768) + m_defaultIconSize = KIcon::SizeSmallMedium/*22x22*/; + else + m_defaultIconSize = KIcon::SizeSmall/*16x16*/; + } + + +#if DEBUG_KP_TOOL_TOOL_BAR + kdDebug () << "\treturning " << m_defaultIconSize << endl; +#endif + return m_defaultIconSize; +} + +// public +void kpToolToolBar::registerTool (kpTool *tool) +{ + for (QValueVector ::const_iterator it = m_buttonToolPairs.begin (); + it != m_buttonToolPairs.end (); + it++) + { + if ((*it).m_tool == tool) + return; + } + int num = m_buttonToolPairs.count (); + + QToolButton *b = new kpToolButton (tool, m_baseWidget); + b->setAutoRaise (true); + b->setUsesBigPixmap (false); + b->setUsesTextLabel (false); + b->setToggleButton (true); + + b->setText (tool->text ()); + b->setIconSet (tool->iconSet (defaultIconSize ())); + QToolTip::add (b, tool->toolTip ()); + QWhatsThis::add (b, tool->description ()); + + m_buttonGroup->insert (b); + addButton (b, orientation (), num); + + m_buttonToolPairs.append (kpButtonToolPair (b, tool)); + + + connect (tool, SIGNAL (actionActivated ()), + this, SLOT (slotToolActionActivated ())); + connect (tool, SIGNAL (actionToolTipChanged (const QString &)), + this, SLOT (slotToolActionToolTipChanged ())); +} + +// public +void kpToolToolBar::unregisterTool (kpTool *tool) +{ + for (QValueVector ::iterator it = m_buttonToolPairs.begin (); + it != m_buttonToolPairs.end (); + it++) + { + if ((*it).m_tool == tool) + { + delete ((*it).m_button); + m_buttonToolPairs.erase (it); + + disconnect (tool, SIGNAL (actionActivated ()), + this, SLOT (slotToolActionActivated ())); + disconnect (tool, SIGNAL (actionToolTipChanged (const QString &)), + this, SLOT (slotToolActionToolTipChanged ())); + break; + } + } +} + +// public +void kpToolToolBar::unregisterAllTools () +{ + for (QValueVector ::iterator it = m_buttonToolPairs.begin (); + it != m_buttonToolPairs.end (); + it++) + { + delete ((*it).m_button); + } + + m_buttonToolPairs.clear (); +} + + +// public +kpTool *kpToolToolBar::tool () const +{ + return m_currentTool; +} + +// public +void kpToolToolBar::selectTool (const kpTool *tool, bool reselectIfSameTool) +{ +#if DEBUG_KP_TOOL_TOOL_BAR + kdDebug () << "kpToolToolBar::selectTool (tool=" << tool + << ") currentTool=" << m_currentTool + << endl; +#endif + + if (!reselectIfSameTool && tool == m_currentTool) + return; + + if (tool) + { + for (QValueVector ::iterator it = m_buttonToolPairs.begin (); + it != m_buttonToolPairs.end (); + it++) + { + if ((*it).m_tool == tool) + { + m_buttonGroup->setButton (m_buttonGroup->id ((*it).m_button)); + slotToolButtonClicked (); + break; + } + } + } + else + { + QButton *b = m_buttonGroup->selected (); + #if DEBUG_KP_TOOL_TOOL_BAR + kdDebug () << "\twant to select no tool - button selected=" << b << endl; + #endif + if (b) + { + b->toggle (); + slotToolButtonClicked (); + } + } +} + + +// public +kpTool *kpToolToolBar::previousTool () const +{ + return m_previousTool; +} + +// public +void kpToolToolBar::selectPreviousTool () +{ + selectTool (m_previousTool); +} + + +// public +void kpToolToolBar::hideAllToolWidgets () +{ + for (QValueVector ::const_iterator it = m_toolWidgets.begin (); + it != m_toolWidgets.end (); + it++) + { + (*it)->hide (); + } +} + +// public +int kpToolToolBar::numShownToolWidgets () const +{ +#if DEBUG_KP_TOOL_TOOL_BAR + kdDebug () << "kpToolToolBar::numShownToolWidgets()" << endl; +#endif + + int ret = 0; + + for (QValueVector ::const_iterator it = m_toolWidgets.begin (); + it != m_toolWidgets.end (); + it++) + { + #if DEBUG_KP_TOOL_TOOL_BAR + kdDebug () << "\t" << (*it)->name () + << " isShown=" << (*it)->isShown () + << endl; + #endif + if ((*it)->isShown ()) + ret++; + } + + return ret; +} + +// public +kpToolWidgetBase *kpToolToolBar::shownToolWidget (int which) const +{ + int uptoVisibleWidget = 0; + + for (QValueVector ::const_iterator it = m_toolWidgets.begin (); + it != m_toolWidgets.end (); + it++) + { + if ((*it)->isShown ()) + { + if (which == uptoVisibleWidget) + return *it; + + uptoVisibleWidget++; + } + } + + return 0; +} + + +// public +bool kpToolToolBar::toolsSingleKeyTriggersEnabled () const +{ + for (QValueVector ::const_iterator it = m_buttonToolPairs.begin (); + it != m_buttonToolPairs.end (); + it++) + { + if (!(*it).m_tool->singleKeyTriggersEnabled ()) + return false; + } + + return true; +} + +// public +void kpToolToolBar::enableToolsSingleKeyTriggers (bool enable) +{ +#if DEBUG_KP_TOOL_TOOL_BAR + kdDebug () << "kpToolToolBar::enableToolsSingleKeyTriggers(" << enable << ")" << endl; +#endif + + for (QValueVector ::const_iterator it = m_buttonToolPairs.begin (); + it != m_buttonToolPairs.end (); + it++) + { + (*it).m_tool->enableSingleKeyTriggers (enable); + } +} + + +// private slot +void kpToolToolBar::slotToolButtonClicked () +{ + QButton *b = m_buttonGroup->selected (); + +#if DEBUG_KP_TOOL_TOOL_BAR + kdDebug () << "kpToolToolBar::slotToolButtonClicked() button=" << b << endl; +#endif + + kpTool *tool = 0; + for (QValueVector ::iterator it = m_buttonToolPairs.begin (); + it != m_buttonToolPairs.end (); + it++) + { + if ((*it).m_button == b) + { + tool = (*it).m_tool; + break; + } + } + +#if DEBUG_KP_TOOL_TOOL_BAR + kdDebug () << "\ttool=" << tool + << " currentTool=" << m_currentTool + << endl; +#endif + + if (tool == m_currentTool) + { + if (m_currentTool) + m_currentTool->reselect (); + + return; + } + + if (m_currentTool) + m_currentTool->endInternal (); + + m_previousTool = m_currentTool; + m_currentTool = tool; + + if (m_currentTool) + { + kpToolAction *action = m_currentTool->action (); + if (action) + { + action->setChecked (true); + } + + m_currentTool->beginInternal (); + } + + emit sigToolSelected (m_currentTool); +} + + +#define CONST_KP_TOOL_SENDER() (dynamic_cast (sender ())) + +// private slot +void kpToolToolBar::slotToolActionActivated () +{ + const kpTool *tool = CONST_KP_TOOL_SENDER (); + +#if DEBUG_KP_TOOL_TOOL_BAR + kdDebug () << "kpToolToolBar::slotToolActionActivated() tool=" + << (tool ? tool->name () : "null") + << endl; +#endif + + if (m_currentTool) + { + // If the user clicks on the same KToggleAction, it unchecks it + // - this is inconsistent with the Tool Box so always make sure it's + // checked. + kpToolAction *action = m_currentTool->action (); + if (action) + { + action->setChecked (true); + } + } + + selectTool (tool, true/*reselect if same tool*/); +} + +// private slot +void kpToolToolBar::slotToolActionToolTipChanged () +{ + const kpTool *tool = CONST_KP_TOOL_SENDER (); + +#if DEBUG_KP_TOOL_TOOL_BAR + kdDebug () << "kpToolToolBar::slotToolActionToolTipChanged() tool=" + << (tool ? tool->name () : "null") + << endl; +#endif + + if (!tool) + return; + + for (QValueVector ::const_iterator it = m_buttonToolPairs.begin (); + it != m_buttonToolPairs.end (); + it++) + { + if (tool == (*it).m_tool) + { + QToolTip::add ((*it).m_button, tool->toolTip ()); + return; + } + } +} + + +// public slot virtual [base QDockWindow] +void kpToolToolBar::setOrientation (Qt::Orientation o) +{ +#if DEBUG_KP_TOOL_TOOL_BAR + kdDebug () << "kpToolToolBar::setOrientation(" + << (o == Qt::Vertical ? "vertical" : "horizontal") + << ") called!" << endl; +#endif + + // (QDockWindow::undock() calls us) + bool isOutsideDock = (place () == QDockWindow::OutsideDock); + + if (!m_lastDockedOrientationSet || !isOutsideDock) + { + m_lastDockedOrientation = o; + m_lastDockedOrientationSet = true; + } + + if (isOutsideDock) + { + #if DEBUG_KP_TOOL_TOOL_BAR + kdDebug () << "\toutside dock, forcing orientation to last" << endl; + #endif + o = m_lastDockedOrientation; + } + + delete m_toolLayout; + delete m_baseLayout; + if (o == Qt::Vertical) + { + m_baseLayout = new QBoxLayout (m_baseWidget, QBoxLayout::TopToBottom, + 5/*margin*/, + 10/*spacing*/); + m_toolLayout = new QGridLayout (m_baseLayout, + 5/*arbitrary rows since toolBar auto-expands*/, + m_vertCols, + 0/*margin*/, + 0/*spacing*/); + } + else // if (o == Qt::Horizontal) + { + m_baseLayout = new QBoxLayout (m_baseWidget, QBoxLayout::LeftToRight, + 5/*margin*/, + 10/*spacing*/); + m_toolLayout = new QGridLayout (m_baseLayout, + m_vertCols/*rows in this case, since horiz*/, + 5/*arbitrary cols since toolBar auto-expands*/, + 0/*margin*/, + 0/*spacing*/); + } + + int num = 0; + + for (QValueVector ::iterator it = m_buttonToolPairs.begin (); + it != m_buttonToolPairs.end (); + it++) + { + addButton ((*it).m_button, o, num); + num++; + } + + for (QValueVector ::const_iterator it = m_toolWidgets.begin (); + it != m_toolWidgets.end (); + it++) + { + if (*it) + { + m_baseLayout->addWidget (*it, + 0/*stretch*/, + o == Qt::Vertical ? Qt::AlignHCenter : Qt::AlignVCenter); + } + } + + KToolBar::setOrientation (o); +} + +// private +void kpToolToolBar::addButton (QButton *button, Qt::Orientation o, int num) +{ + if (o == Qt::Vertical) + m_toolLayout->addWidget (button, num / m_vertCols, num % m_vertCols); + else + { + // maps Left (o = vertical) to Bottom (o = horizontal) + int row = (m_vertCols - 1) - (num % m_vertCols); + m_toolLayout->addWidget (button, row, num / m_vertCols); + } +} + + +#include diff --git a/kolourpaint/widgets/kptooltoolbar.h b/kolourpaint/widgets/kptooltoolbar.h new file mode 100644 index 00000000..c3a7d1b7 --- /dev/null +++ b/kolourpaint/widgets/kptooltoolbar.h @@ -0,0 +1,155 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kp_tool_tool_bar_h__ +#define __kp_tool_tool_bar_h__ + +#include + +#include + + +class QBoxLayout; +class QButton; +class QButtonGroup; +class QWidget; +class QGridLayout; + +class kpMainWindow; +class kpTool; + +class kpToolWidgetBase; +class kpToolWidgetBrush; +class kpToolWidgetEraserSize; +class kpToolWidgetFillStyle; +class kpToolWidgetLineWidth; +class kpToolWidgetOpaqueOrTransparent; +class kpToolWidgetSpraycanSize; + +class kpToolToolBar : public KToolBar +{ +Q_OBJECT + +public: + kpToolToolBar (const QString &label, kpMainWindow *mainWindow, int colsOrRows = 2, const char *name = 0); + virtual ~kpToolToolBar (); + +private: + int defaultIconSize (); +public: + void registerTool (kpTool *tool); + void unregisterTool (kpTool *tool); + void unregisterAllTools (); + + kpTool *tool () const; + void selectTool (const kpTool *tool, bool reselectIfSameTool = false); + + kpTool *previousTool () const; + void selectPreviousTool (); + + void hideAllToolWidgets (); + // could this be cleaner (the tools have to access them individually somehow)? + kpToolWidgetBrush *toolWidgetBrush () const { return m_toolWidgetBrush; } + kpToolWidgetEraserSize *toolWidgetEraserSize () const { return m_toolWidgetEraserSize; } + kpToolWidgetFillStyle *toolWidgetFillStyle () const { return m_toolWidgetFillStyle; } + kpToolWidgetLineWidth *toolWidgetLineWidth () const { return m_toolWidgetLineWidth; } + kpToolWidgetOpaqueOrTransparent *toolWidgetOpaqueOrTransparent () const { return m_toolWidgetOpaqueOrTransparent; } + kpToolWidgetSpraycanSize *toolWidgetSpraycanSize () const { return m_toolWidgetSpraycanSize; } + +public: + int numShownToolWidgets () const; + kpToolWidgetBase *shownToolWidget (int which) const; + + bool toolsSingleKeyTriggersEnabled () const; + void enableToolsSingleKeyTriggers (bool enable); + +signals: + void sigToolSelected (kpTool *tool); // tool may be 0 + void toolWidgetOptionSelected (); + +private slots: + void slotToolButtonClicked (); + + void slotToolActionActivated (); + void slotToolActionToolTipChanged (); + +public slots: + virtual void setOrientation (Qt::Orientation o); + +private: + void addButton (QButton *button, Qt::Orientation o, int num); + + Qt::Orientation m_lastDockedOrientation; + bool m_lastDockedOrientationSet; + int m_vertCols; + + QButtonGroup *m_buttonGroup; + QWidget *m_baseWidget; + QBoxLayout *m_baseLayout; + QGridLayout *m_toolLayout; + + kpToolWidgetBrush *m_toolWidgetBrush; + kpToolWidgetEraserSize *m_toolWidgetEraserSize; + kpToolWidgetFillStyle *m_toolWidgetFillStyle; + kpToolWidgetLineWidth *m_toolWidgetLineWidth; + kpToolWidgetOpaqueOrTransparent *m_toolWidgetOpaqueOrTransparent; + kpToolWidgetSpraycanSize *m_toolWidgetSpraycanSize; + + QValueVector m_toolWidgets; + +private: + struct kpButtonToolPair + { + kpButtonToolPair (QButton *button, kpTool *tool) + : m_button (button), m_tool (tool) + { + } + + kpButtonToolPair () + : m_button (0), m_tool (0) + { + } + + QButton *m_button; + kpTool *m_tool; + }; + + QValueVector m_buttonToolPairs; + + kpTool *m_previousTool, *m_currentTool; + + int m_defaultIconSize; + +private: + // There is no need to maintain binary compatibility at this stage. + // The d-pointer is just so that you can experiment without recompiling + // the kitchen sink. + class kpToolToolBarPrivate *d; +}; + +#endif // __kp_tool_tool_bar_h__ diff --git a/kolourpaint/widgets/kptoolwidgetbase.cpp b/kolourpaint/widgets/kptoolwidgetbase.cpp new file mode 100644 index 00000000..a0042dbc --- /dev/null +++ b/kolourpaint/widgets/kptoolwidgetbase.cpp @@ -0,0 +1,608 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define DEBUG_KP_TOOL_WIDGET_BASE 0 + + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +kpToolWidgetBase::kpToolWidgetBase (QWidget *parent, const char *name) + : QFrame (parent, name), + m_invertSelectedPixmap (true), + m_selectedRow (-1), m_selectedCol (-1) +{ + if (!name) + kdError () << "kpToolWidgetBase::kpToolWidgetBase() without name" << endl; + + setFrameStyle (QFrame::Panel | QFrame::Sunken); + setFixedSize (44, 66); +} + +kpToolWidgetBase::~kpToolWidgetBase () +{ +} + + +// public +void kpToolWidgetBase::addOption (const QPixmap &pixmap, const QString &toolTip) +{ + if (m_pixmaps.isEmpty ()) + startNewOptionRow (); + + m_pixmaps.last ().append (pixmap); + m_pixmapRects.last ().append (QRect ()); + m_toolTips.last ().append (toolTip); +} + +// public +void kpToolWidgetBase::startNewOptionRow () +{ + m_pixmaps.resize (m_pixmaps.count () + 1); + m_pixmapRects.resize (m_pixmapRects.count () + 1); + m_toolTips.resize (m_toolTips.count () + 1); +} + +// public +void kpToolWidgetBase::finishConstruction (int fallBackRow, int fallBackCol) +{ +#if DEBUG_KP_TOOL_WIDGET_BASE + kdDebug () << "kpToolWidgetBase(" << name () + << ")::kpToolWidgetBase(fallBack:row=" << fallBackRow + << ",col=" << fallBackCol + << ")" + << endl; +#endif + + relayoutOptions (); + + const QPair rowColPair = defaultSelectedRowAndCol (); + if (!setSelected (rowColPair.first, rowColPair.second, false/*don't save*/)) + { + if (!setSelected (fallBackRow, fallBackCol)) + { + if (!setSelected (0, 0)) + { + kdError () << "kpToolWidgetBase::finishConstruction() " + "can't even fall back to setSelected(row=0,col=0)" << endl; + } + } + } +} + + +// private +QValueVector kpToolWidgetBase::spreadOutElements (const QValueVector &sizes, int max) +{ + if (sizes.count () == 0) + return QValueVector (); + else if (sizes.count () == 1) + return QValueVector (1, sizes.first () > max ? 0 : 1/*margin*/); + + QValueVector retOffsets (sizes.count ()); + + int totalSize = 0; + for (int i = 0; i < (int) sizes.count (); i++) + totalSize += sizes [i]; + + int margin = 1; + + // if don't fit with margin, then just return elements + // packed right next to each other + if (totalSize + margin * 2 > max) + { + retOffsets [0] = 0; + for (int i = 1; i < (int) sizes.count (); i++) + retOffsets [i] = retOffsets [i - 1] + sizes [i - 1]; + + return retOffsets; + } + + int maxLeftOver = max - (totalSize + margin * 2); + + int startCompensating = -1; + int numCompensate = 0; + + int spacing = 0; + + spacing = maxLeftOver / (sizes.count () - 1); + if (spacing * int (sizes.count () - 1) < maxLeftOver) + { + numCompensate = maxLeftOver - spacing * (sizes.count () - 1); + startCompensating = ((sizes.count () - 1) - numCompensate) / 2; + } + + retOffsets [0] = margin; + for (int i = 1; i < (int) sizes.count (); i++) + { + retOffsets [i] += retOffsets [i - 1] + + sizes [i - 1] + + spacing + + ((numCompensate && + i >= startCompensating && + i < startCompensating + numCompensate) ? 1 : 0); + } + + return retOffsets; +} + + +// public +QPair kpToolWidgetBase::defaultSelectedRowAndCol () const +{ + int row = -1, col = -1; + + if (name ()) + { + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupTools); + KConfigBase *cfg = cfgGroupSaver.config (); + + QString nameString = QString::fromLatin1 (name ()); + + row = cfg->readNumEntry (nameString + QString::fromLatin1 (" Row"), -1); + col = cfg->readNumEntry (nameString + QString::fromLatin1 (" Col"), -1); + } + +#if DEBUG_KP_TOOL_WIDGET_BASE + kdDebug () << "kpToolWidgetBase(" << name () + << ")::defaultSelectedRowAndCol() returning row=" << row + << " col=" << col + << endl; +#endif + + return qMakePair (row, col); +} + +// public +int kpToolWidgetBase::defaultSelectedRow () const +{ + return defaultSelectedRowAndCol ().first; +} + +// public +int kpToolWidgetBase::defaultSelectedCol () const +{ + return defaultSelectedRowAndCol ().second; +} + +// public +void kpToolWidgetBase::saveSelectedAsDefault () const +{ +#if DEBUG_KP_TOOL_WIDGET_BASE + kdDebug () << "kpToolWidgetBase(" << name () + << ")::saveSelectedAsDefault() row=" << m_selectedRow + << " col=" << m_selectedCol << endl; +#endif + + if (!name ()) + return; + + KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupTools); + KConfigBase *cfg = cfgGroupSaver.config (); + + QString nameString = QString::fromLatin1 (name ()); + cfg->writeEntry (nameString + QString::fromLatin1 (" Row"), m_selectedRow); + cfg->writeEntry (nameString + QString::fromLatin1 (" Col"), m_selectedCol); + cfg->sync (); +} + + +// public +void kpToolWidgetBase::relayoutOptions () +{ +#if DEBUG_KP_TOOL_WIDGET_BASE + kdDebug () << "kpToolWidgetBase::relayoutOptions()" << endl; +#endif + + while (!m_pixmaps.isEmpty () && m_pixmaps.last ().count () == 0) + { + #if DEBUG_KP_TOOL_WIDGET_BASE + kdDebug () << "\tkilling #" << m_pixmaps.count () - 1 << endl; + #endif + m_pixmaps.resize (m_pixmaps.count () - 1); + m_pixmapRects.resize (m_pixmapRects.count () - 1); + m_toolTips.resize (m_toolTips.count () - 1); + } + + if (m_pixmaps.isEmpty ()) + return; + +#if DEBUG_KP_TOOL_WIDGET_BASE + kdDebug () << "\tsurvived killing of empty rows" << endl; + kdDebug () << "\tfinding heights of rows:" << endl; +#endif + + QValueVector maxHeightOfRow (m_pixmaps.count ()); + + for (int r = 0; r < (int) m_pixmaps.count (); r++) + { + for (int c = 0; c < (int) m_pixmaps [r].count (); c++) + { + if (c == 0 || m_pixmaps [r][c].height () > maxHeightOfRow [r]) + maxHeightOfRow [r] = m_pixmaps [r][c].height (); + } + #if DEBUG_KP_TOOL_WIDGET_BASE + kdDebug () << "\t\t" << r << ": " << maxHeightOfRow [r] << endl; + #endif + } + + QValueVector rowYOffset = spreadOutElements (maxHeightOfRow, height ()); +#if DEBUG_KP_TOOL_WIDGET_BASE + kdDebug () << "\tspread out offsets of rows:" << endl; + for (int r = 0; r < (int) rowYOffset.count (); r++) + kdDebug () << "\t\t" << r << ": " << rowYOffset [r] << endl; +#endif + + for (int r = 0; r < (int) m_pixmaps.count (); r++) + { + #if DEBUG_KP_TOOL_WIDGET_BASE + kdDebug () << "\tlaying out row " << r << ":" << endl; + #endif + + QValueVector widths (m_pixmaps [r].count ()); + for (int c = 0; c < (int) m_pixmaps [r].count (); c++) + widths [c] = m_pixmaps [r][c].width (); + #if DEBUG_KP_TOOL_WIDGET_BASE + kdDebug () << "\t\twidths of cols:" << endl; + for (int c = 0; c < (int) m_pixmaps [r].count (); c++) + kdDebug () << "\t\t\t" << c << ": " << widths [c] << endl; + #endif + + QValueVector colXOffset = spreadOutElements (widths, width ()); + #if DEBUG_KP_TOOL_WIDGET_BASE + kdDebug () << "\t\tspread out offsets of cols:" << endl; + for (int c = 0; c < (int) colXOffset.count (); c++) + kdDebug () << "\t\t\t" << c << ": " << colXOffset [c] << endl; + #endif + + for (int c = 0; c < (int) colXOffset.count (); c++) + { + int x = colXOffset [c]; + int y = rowYOffset [r]; + int w, h; + + if (c == (int) colXOffset.count () - 1) + { + if (x + m_pixmaps [r][c].width () >= width ()) + w = m_pixmaps [r][c].width (); + else + w = width () - 1 - x; + } + else + w = colXOffset [c + 1] - x; + + if (r == (int) m_pixmaps.count () - 1) + { + if (y + m_pixmaps [r][c].height () >= height ()) + h = m_pixmaps [r][c].height (); + else + h = height () - 1 - y; + } + else + h = rowYOffset [r + 1] - y; + + m_pixmapRects [r][c] = QRect (x, y, w, h); + + if (!m_toolTips [r][c].isEmpty ()) + QToolTip::add (this, m_pixmapRects [r][c], m_toolTips [r][c]); + } + } + + update (); +} + + +// public +int kpToolWidgetBase::selectedRow () const +{ + return m_selectedRow; +} + +// public +int kpToolWidgetBase::selectedCol () const +{ + return m_selectedCol; +} + +// public +int kpToolWidgetBase::selected () const +{ + if (m_selectedRow < 0 || + m_selectedRow >= (int) m_pixmaps.count () || + m_selectedCol < 0) + { + return -1; + } + + int upto = 0; + for (int y = 0; y < m_selectedRow; y++) + upto += m_pixmaps [y].count (); + + if (m_selectedCol >= (int) m_pixmaps [m_selectedRow].count ()) + return -1; + + upto += m_selectedCol; + + return upto; +} + + +// public +bool kpToolWidgetBase::hasPreviousOption (int *row, int *col) const +{ +#if DEBUG_KP_TOOL_WIDGET_BASE + kdDebug () << "kpToolWidgetBase" << name () + << "::hasPreviousOption() current row=" << m_selectedRow + << " col=" << m_selectedCol + << endl; +#endif + if (row) + *row = -1; + if (col) + *col = -1; + + + if (m_selectedRow < 0 || m_selectedCol < 0) + return false; + + int newRow = m_selectedRow, + newCol = m_selectedCol; + + newCol--; + if (newCol < 0) + { + newRow--; + if (newRow < 0) + return false; + + newCol = m_pixmaps [newRow].count () - 1; + if (newCol < 0) + return false; + } + + + if (row) + *row = newRow; + if (col) + *col = newCol; + + return true; +} + +// public +bool kpToolWidgetBase::hasNextOption (int *row, int *col) const +{ +#if DEBUG_KP_TOOL_WIDGET_BASE + kdDebug () << "kpToolWidgetBase" << name () + << "::hasNextOption() current row=" << m_selectedRow + << " col=" << m_selectedCol + << endl; +#endif + + if (row) + *row = -1; + if (col) + *col = -1; + + + if (m_selectedRow < 0 || m_selectedCol < 0) + return false; + + int newRow = m_selectedRow, + newCol = m_selectedCol; + + newCol++; + if (newCol >= (int) m_pixmaps [newRow].count ()) + { + newRow++; + if (newRow >= (int) m_pixmaps.count ()) + return false; + + newCol = 0; + if (newCol >= (int) m_pixmaps [newRow].count ()) + return false; + } + + + if (row) + *row = newRow; + if (col) + *col = newCol; + + return true; +} + + +// public slot virtual +bool kpToolWidgetBase::setSelected (int row, int col, bool saveAsDefault) +{ +#if DEBUG_KP_TOOL_WIDGET_BASE + kdDebug () << "kpToolWidgetBase::setSelected(row=" << row + << ",col=" << col + << ",saveAsDefault=" << saveAsDefault + << ")" + << endl; +#endif + + if (row < 0 || col < 0 || + row >= (int) m_pixmapRects.count () || col >= (int) m_pixmapRects [row].count ()) + { + #if DEBUG_KP_TOOL_WIDGET_BASE + kdDebug () << "\tout of range" << endl; + #endif + return false; + } + + if (row == m_selectedRow && col == m_selectedCol) + { + #if DEBUG_KP_TOOL_WIDGET_BASE + kdDebug () << "\tNOP" << endl; + #endif + + if (saveAsDefault) + saveSelectedAsDefault (); + + return true; + } + + const int wasSelectedRow = m_selectedRow; + const int wasSelectedCol = m_selectedCol; + + m_selectedRow = row, m_selectedCol = col; + + if (wasSelectedRow >= 0 && wasSelectedCol >= 0) + { + // unhighlight old option + update (m_pixmapRects [wasSelectedRow][wasSelectedCol]); + } + + // highlight new option + update (m_pixmapRects [row][col]); + +#if DEBUG_KP_TOOL_WIDGET_BASE + kdDebug () << "\tOK" << endl; +#endif + + if (saveAsDefault) + saveSelectedAsDefault (); + + emit optionSelected (row, col); + return true; +} + +// public slot +bool kpToolWidgetBase::setSelected (int row, int col) +{ + return setSelected (row, col, true/*set as default*/); +} + + +// public slot +bool kpToolWidgetBase::selectPreviousOption () +{ + int newRow, newCol; + if (!hasPreviousOption (&newRow, &newCol)) + return false; + + return setSelected (newRow, newCol); +} + +// public slot +bool kpToolWidgetBase::selectNextOption () +{ + int newRow, newCol; + if (!hasNextOption (&newRow, &newCol)) + return false; + + return setSelected (newRow, newCol); +} + + +// protected virtual [base QWidget] +void kpToolWidgetBase::mousePressEvent (QMouseEvent *e) +{ + e->ignore (); + + if (e->button () != Qt::LeftButton) + return; + + + for (int i = 0; i < (int) m_pixmapRects.count (); i++) + { + for (int j = 0; j < (int) m_pixmapRects [i].count (); j++) + { + if (m_pixmapRects [i][j].contains (e->pos ())) + { + setSelected (i, j); + e->accept (); + return; + } + } + } +} + +// protected virtual [base QFrame] +void kpToolWidgetBase::drawContents (QPainter *painter) +{ +#if DEBUG_KP_TOOL_WIDGET_BASE && 1 + kdDebug () << "kpToolWidgetBase::drawContents(): rect=" << contentsRect () << endl; +#endif + + for (int i = 0; i < (int) m_pixmaps.count (); i++) + { + #if DEBUG_KP_TOOL_WIDGET_BASE && 1 + kdDebug () << "\tRow: " << i << endl; + #endif + + for (int j = 0; j < (int) m_pixmaps [i].count (); j++) + { + QRect rect = m_pixmapRects [i][j]; + QPixmap pixmap = m_pixmaps [i][j]; + + #if DEBUG_KP_TOOL_WIDGET_BASE && 1 + kdDebug () << "\t\tCol: " << j << " rect=" << rect << endl; + #endif + + if (i == m_selectedRow && j == m_selectedCol) + { + painter->fillRect (rect, Qt::blue/*selection color*/); + + if (m_invertSelectedPixmap) + kpEffectInvertCommand::apply (&pixmap); + } + + #if DEBUG_KP_TOOL_WIDGET_BASE && 1 + kdDebug () << "\t\t\tdraw pixmap @ x=" + << rect.x () + (rect.width () - pixmap.width ()) / 2 + << " y=" + << rect.y () + (rect.height () - pixmap.height ()) / 2 + << endl; + + #endif + + painter->drawPixmap (QPoint (rect.x () + (rect.width () - pixmap.width ()) / 2, + rect.y () + (rect.height () - pixmap.height ()) / 2), + pixmap); + } + } +} + +#include diff --git a/kolourpaint/widgets/kptoolwidgetbase.h b/kolourpaint/widgets/kptoolwidgetbase.h new file mode 100644 index 00000000..a23f9a16 --- /dev/null +++ b/kolourpaint/widgets/kptoolwidgetbase.h @@ -0,0 +1,112 @@ + +/* + Copyright (c) 2003,2004,2005 Clarence Dang + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __kp_tool_widget_base_h__ +#define __kp_tool_widget_base_h__ + +#include +#include +#include +#include +#include +#include + + +class QPainter; + + +// TODO: frame becomes a combobox when its parent kpToolToolBar becomes too small +class kpToolWidgetBase : public QFrame +{ +Q_OBJECT + +public: + kpToolWidgetBase (QWidget *parent, const char *name); // must provide a name for config to work + virtual ~kpToolWidgetBase (); + +public: + void addOption (const QPixmap &pixmap, const QString &toolTip = QString::null); + void startNewOptionRow (); + + // Call this at the end of your constructor. + // If the default row & col could not be read from the config, + // & are passed to setSelected(). + void finishConstruction (int fallBackRow, int fallBackCol); + +private: + QValueVector spreadOutElements (const QValueVector &sizes, int maxSize); + +public: // (only have to use these if you don't use finishConstruction()) + // (rereads from config file) + QPair defaultSelectedRowAndCol () const; + int defaultSelectedRow () const; + int defaultSelectedCol () const; + + void saveSelectedAsDefault () const; + + void relayoutOptions (); + +public: + int selectedRow () const; + int selectedCol () const; + + int selected () const; + + bool hasPreviousOption (int *row = 0, int *col = 0) const; + bool hasNextOption (int *row = 0, int *col = 0) const; + +public slots: + // (returns whether and
\n"); + echo("\n"); + + if (sizeof($this->functions)>0) + { + echo("\n"); + + for ($i=0;$ifunctions);$i++) + { + echo("\n"); + } + } + + if (sizeof($this->properties)>0) + { + echo("\n"); + + for ($i=0;$iproperties);$i++) + { + if ($this->readonly[$this->properties[$i]]) + $readonly="Property is ReadOnly"; + else + $readonly="Property is ReadWrite"; + + echo("\n"); + } + } + + if (sizeof($this->constants)>0) + { + echo("\n"); + + for ($i=0;$iconstants);$i++) + { + echo("\n"); + } + } + echo("

".$this->class."

Functions

 ".$this->functions[$i]."".$this->params[$this->functions[$i]]." Parameter(s)

Properties

 ".$this->properties[$i]."$readonly

Constants

 ".$this->constants[$i]."


"); + } + + function to_svg(&$x,&$y) + { + $xtemp=$x+50; + $ytemp=$y+50; + + echo("".$this->class.""); + + $ytemp+=10; + + if (sizeof($this->functions)>0) + { + echo("Functions\n"); + + $ytemp+=10; + + for ($i=0;$ifunctions);$i++) + { + echo("".$this->functions[$i]." with ".$this->params[$this->functions[$i]]." Parameter(s)\n"); + $ytemp+=10; + } + } + + if (sizeof($this->properties)>0) + { + echo("Properties\n"); + + $ytemp+=10; + + for ($i=0;$iproperties);$i++) + { + if ($this->readonly[$this->properties[$i]]) + $readonly="Property is ReadOnly"; + else + $readonly="Property is ReadWrite"; + + echo("".$this->properties[$i]." $readonly\n"); + $ytemp+=10; + } + } + + if (sizeof($this->constants)>0) + { + echo("Constants\n"); + + $ytemp+=10; + + for ($i=0;$iconstants);$i++) + { + echo("".$this->constants[$i]."\n"); + $ytemp+=10; + } + } + $x=$xtemp+200; + } +} + +class kalyptus_result +{ + var $class; + var $type; // 0 = Property ; 1 = Function ; 2 = Constant + var $name; + var $params; + var $readonly; + + function kalyptus_result($class,$type,$name,$params=0) + { + $this->class=$class; + $this->type=$type; + $this->name=$name; + $this->params=$params; + } + + function setReadOnly($value) + { + $this->readonly=$value; + } +} + +function parse_kalyptus($line,&$fp,&$last_constructor) +{ + if (preg_match("/^[ \t^#]*([a-zA-Z_]*)[ \t]*KSVG::.*DontDelete/",$line,$match)) + { + if (DEBUG) fputs($fp,"MATCH => Constant ".$match[1]." in class ".$match[2]."\n"); + return new kalyptus_result($last_constructor,2,$match[1]); + } + elseif (preg_match("/^[ \t^#]*([a-zA-Z_]*)[ \t]*([a-zA-Z_]*)::.*Function ([0-9])/",$line,$match)) + { + if (DEBUG) fputs($fp,"MATCH => Function ".$match[1]." in class ".$match[2]."\n"); + return new kalyptus_result($match[2],1,$match[1],$match[3]); + } + elseif (preg_match("/^[ \t^#]*([a-zA-Z_]*)[ \t]*([a-zA-Z_]*)::.*DontDelete\|ReadOnly/",$line,$match)) + { + if (DEBUG) fputs($fp,"MATCH => Property ".$match[1]." in class ".$match[2]."\n"); + $property=new kalyptus_result($match[2],0,$match[1]); + $property->setReadOnly(true); + return $property; + } + elseif (preg_match("/^[ \t^#]*([a-zA-Z_]*)[ \t]*([a-zA-Z_]*)::.*DontDelete/",$line,$match)) + { + if (DEBUG) fputs($fp,"MATCH => Property ".$match[1]." in class ".$match[2]."\n"); + $property=new kalyptus_result($match[2],0,$match[1]); + $property->setReadOnly(false); + return $property; + } + elseif (preg_match("/^[ \t@begin^#]*([a-zA-Z_]*)Constructor::s_hashTable.*/",$line,$match)) + { + if (DEBUG) fputs($fp,"Constructor => ".$match[1]."\n"); + $last_constructor=$match[1]; + return false; + } + else + { + if (DEBUG) fputs($fp,"Ignored => ".$line."\n"); + return false; + } +} + +function do_output($output,$ecma_classes) +{ + ksort($ecma_classes); + + reset($ecma_classes); + + switch($output) + { + case "txt": + foreach ($ecma_classes as $classname => $obj) + { + $obj->to_text(); + } + break; + case "svg": + echo("\n"); + + $x=0; + $y=0; + + foreach ($ecma_classes as $classname => $obj) + { + $obj->to_svg($x,$y); + } + echo(""); + break; + default: + echo("\n\n"); + + echo("

Contents


\n"); + + foreach ($ecma_classes as $classname => $obj) + { + echo("$classname
\n"); + } + + echo("
\n"); + + foreach ($ecma_classes as $classname => $obj) + { + $obj->to_html(); + } + echo("\n"); + } +} + +function searchKalyptusCode($file,&$fp) +{ + global $ecma_classes; + + ob_start(); + readfile($file); + $content=ob_get_contents(); + ob_end_clean(); + + if (preg_match("/@begin(.*)@end/s",$content,$matches)) // FIXME broken....if several @end's are there it takes always the last + { + if (DEBUG) fputs($fp,"Found ".(sizeof($matches)-1)." Matches in ".$file."\n"); + for ($i=1;$iclass]) + $ecma_classes[$results[$i]->class]->add_content($results[$i]); + else + { + $ecma_classes[$results[$i]->class]=new ecma_class($results[$i]->class); + $ecma_classes[$results[$i]->class]->add_content($results[$i]); + } + } + } +} + +function crawlFiles($path) +{ + global $ecma_classes; + + $fp=fopen("php://stderr","w+"); + + if ($dir = @opendir($path)) + { + while (($file = readdir($dir)) !== false) + { + if (($file!=".") && ($file!="..")) + { + if (is_dir($path."/".$file)) + { + fputs($fp,"Entering directory ".$file."\n"); + crawlFiles($path."/".$file); + fputs($fp,"Leaving directory ".$file."\n"); + } + elseif (is_file($path."/".$file) && preg_match("/^[A-Za-z0-9_]+(\.cc|\.cpp|\.h|\.hpp)$/",$file)) + { + fputs($fp,"\tchecking $file\n"); + searchKalyptusCode($path."/".$file,$fp); + } + } + } + closedir($dir); + } +} + +define(DEBUG,0); + +$ecma_classes=array(); + +$ksvg_path="../"; + +$path=basename(realpath($ksvg_path)); + +if ($path!="ksvg") +{ + echo "Execute it in base ksvg dir please :S\n"; + return false; +} + +crawlFiles($ksvg_path); + +do_output($argv[1],$ecma_classes); +?> diff --git a/ksvg/scripts/idl/svg.idl b/ksvg/scripts/idl/svg.idl new file mode 100644 index 00000000..9b5ea3db --- /dev/null +++ b/ksvg/scripts/idl/svg.idl @@ -0,0 +1,1756 @@ +// File: svg.idl +#ifndef _SVG_IDL_ +#define _SVG_IDL_ + + +// For access to DOM2 core +#include "dom.idl" + +// For access to DOM2 events +#include "events.idl" + +// For access to those parts from DOM2 CSS OM used by SVG DOM. +#include "css.idl" + +// For access to those parts from DOM2 Views OM used by SVG DOM. +#include "views.idl" + +// For access to the SMIL OM used by SVG DOM. +#include "smil.idl" + +#pragma prefix "dom.w3c.org" +#pragma javaPackage "org.w3c.dom" +module svg +{ + typedef dom::DOMString DOMString; + typedef dom::DOMException DOMException; + typedef dom::Element Element; + typedef dom::Document Document; + typedef dom::NodeList NodeList; + + // Predeclarations + interface SVGElement; + interface SVGLangSpace; + interface SVGExternalResourcesRequired; + interface SVGTests; + interface SVGFitToViewBox; + interface SVGZoomAndPan; + interface SVGViewSpec; + interface SVGURIReference; + interface SVGPoint; + interface SVGMatrix; + interface SVGPreserveAspectRatio; + interface SVGAnimatedPreserveAspectRatio; + interface SVGTransformList; + interface SVGAnimatedTransformList; + interface SVGTransform; + interface SVGICCColor; + interface SVGColor; + interface SVGPaint; + interface SVGTransformable; + interface SVGDocument; + interface SVGSVGElement; + interface SVGElementInstance; + interface SVGElementInstanceList; + + + exception SVGException { + unsigned short code; + }; + + // SVGExceptionCode + const unsigned short SVG_WRONG_TYPE_ERR = 0; + const unsigned short SVG_INVALID_VALUE_ERR = 1; + const unsigned short SVG_MATRIX_NOT_INVERTABLE = 2; + + interface SVGElement : Element { + attribute DOMString id; + // raises DOMException on setting + attribute DOMString xmlbase; + // raises DOMException on setting + readonly attribute SVGSVGElement ownerSVGElement; + readonly attribute SVGElement viewportElement; + }; + + interface SVGAnimatedBoolean { + + attribute boolean baseVal; + // raises DOMException on setting + readonly attribute boolean animVal; + }; + + interface SVGAnimatedString { + + attribute DOMString baseVal; + // raises DOMException on setting + readonly attribute DOMString animVal; + }; + + interface SVGStringList { + + readonly attribute unsigned long numberOfItems; + + void clear ( ) + raises( DOMException ); + DOMString initialize ( in DOMString newItem ) + raises( DOMException, SVGException ); + DOMString getItem ( in unsigned long index ) + raises( DOMException ); + DOMString insertItemBefore ( in DOMString newItem, in unsigned long index ) + raises( DOMException, SVGException ); + DOMString replaceItem ( in DOMString newItem, in unsigned long index ) + raises( DOMException, SVGException ); + DOMString removeItem ( in unsigned long index ) + raises( DOMException ); + DOMString appendItem ( in DOMString newItem ) + raises( DOMException, SVGException ); + }; + + interface SVGAnimatedEnumeration { + + attribute unsigned short baseVal; + // raises DOMException on setting + readonly attribute unsigned short animVal; + }; + + interface SVGAnimatedInteger { + + attribute long baseVal; + // raises DOMException on setting + readonly attribute long animVal; + }; + + interface SVGNumber { + + attribute float value; + // raises DOMException on setting + }; + + interface SVGAnimatedNumber { + + attribute float baseVal; + // raises DOMException on setting + readonly attribute float animVal; + }; + + interface SVGNumberList { + + readonly attribute unsigned long numberOfItems; + + void clear ( ) + raises( DOMException ); + SVGNumber initialize ( in SVGNumber newItem ) + raises( DOMException, SVGException ); + SVGNumber getItem ( in unsigned long index ) + raises( DOMException ); + SVGNumber insertItemBefore ( in SVGNumber newItem, in unsigned long index ) + raises( DOMException, SVGException ); + SVGNumber replaceItem ( in SVGNumber newItem, in unsigned long index ) + raises( DOMException, SVGException ); + SVGNumber removeItem ( in unsigned long index ) + raises( DOMException ); + SVGNumber appendItem ( in SVGNumber newItem ) + raises( DOMException, SVGException ); + }; + + interface SVGAnimatedNumberList { + + readonly attribute SVGNumberList baseVal; + readonly attribute SVGNumberList animVal; + }; + + interface SVGLength { + + // Length Unit Types + const unsigned short SVG_LENGTHTYPE_UNKNOWN = 0; + const unsigned short SVG_LENGTHTYPE_NUMBER = 1; + const unsigned short SVG_LENGTHTYPE_PERCENTAGE = 2; + const unsigned short SVG_LENGTHTYPE_EMS = 3; + const unsigned short SVG_LENGTHTYPE_EXS = 4; + const unsigned short SVG_LENGTHTYPE_PX = 5; + const unsigned short SVG_LENGTHTYPE_CM = 6; + const unsigned short SVG_LENGTHTYPE_MM = 7; + const unsigned short SVG_LENGTHTYPE_IN = 8; + const unsigned short SVG_LENGTHTYPE_PT = 9; + const unsigned short SVG_LENGTHTYPE_PC = 10; + + readonly attribute unsigned short unitType; + attribute float value; + // raises DOMException on setting + attribute float valueInSpecifiedUnits; + // raises DOMException on setting + attribute DOMString valueAsString; + // raises DOMException on setting + + void newValueSpecifiedUnits ( in unsigned short unitType, in float valueInSpecifiedUnits ); + void convertToSpecifiedUnits ( in unsigned short unitType ); + }; + + interface SVGAnimatedLength { + + readonly attribute SVGLength baseVal; + readonly attribute SVGLength animVal; + }; + + interface SVGLengthList { + + readonly attribute unsigned long numberOfItems; + + void clear ( ) + raises( DOMException ); + SVGLength initialize ( in SVGLength newItem ) + raises( DOMException, SVGException ); + SVGLength getItem ( in unsigned long index ) + raises( DOMException ); + SVGLength insertItemBefore ( in SVGLength newItem, in unsigned long index ) + raises( DOMException, SVGException ); + SVGLength replaceItem ( in SVGLength newItem, in unsigned long index ) + raises( DOMException, SVGException ); + SVGLength removeItem ( in unsigned long index ) + raises( DOMException ); + SVGLength appendItem ( in SVGLength newItem ) + raises( DOMException, SVGException ); + }; + + interface SVGAnimatedLengthList { + + readonly attribute SVGLengthList baseVal; + readonly attribute SVGLengthList animVal; + }; + + interface SVGAngle { + + // Angle Unit Types + const unsigned short SVG_ANGLETYPE_UNKNOWN = 0; + const unsigned short SVG_ANGLETYPE_UNSPECIFIED = 1; + const unsigned short SVG_ANGLETYPE_DEG = 2; + const unsigned short SVG_ANGLETYPE_RAD = 3; + const unsigned short SVG_ANGLETYPE_GRAD = 4; + + readonly attribute unsigned short unitType; + attribute float value; + // raises DOMException on setting + attribute float valueInSpecifiedUnits; + // raises DOMException on setting + attribute DOMString valueAsString; + // raises DOMException on setting + + void newValueSpecifiedUnits ( in unsigned short unitType, in float valueInSpecifiedUnits ); + void convertToSpecifiedUnits ( in unsigned short unitType ); + }; + + interface SVGAnimatedAngle { + + readonly attribute SVGAngle baseVal; + readonly attribute SVGAngle animVal; + }; + + interface SVGColor : css::CSSValue { + // Color Types + const unsigned short SVG_COLORTYPE_UNKNOWN = 0; + const unsigned short SVG_COLORTYPE_RGBCOLOR = 1; + const unsigned short SVG_COLORTYPE_RGBCOLOR_ICCCOLOR = 2; + const unsigned short SVG_COLORTYPE_CURRENTCOLOR = 3; + + readonly attribute unsigned short colorType; + readonly attribute css::RGBColor rgbColor; + readonly attribute SVGICCColor iccColor; + + void setRGBColor ( in DOMString rgbColor ) + raises( SVGException ); + void setRGBColorICCColor ( in DOMString rgbColor, in DOMString iccColor ) + raises( SVGException ); + void setColor ( in unsigned short colorType, in DOMString rgbColor, in DOMString iccColor ) + raises( SVGException ); + }; + + interface SVGICCColor { + + attribute DOMString colorProfile; + // raises DOMException on setting + readonly attribute SVGNumberList colors; + }; + + interface SVGRect { + + attribute float x; + // raises DOMException on setting + attribute float y; + // raises DOMException on setting + attribute float width; + // raises DOMException on setting + attribute float height; + // raises DOMException on setting + }; + + interface SVGAnimatedRect { + + readonly attribute SVGRect baseVal; + readonly attribute SVGRect animVal; + }; + + interface SVGUnitTypes { + + // Unit Types + const unsigned short SVG_UNIT_TYPE_UNKNOWN = 0; + const unsigned short SVG_UNIT_TYPE_USERSPACEONUSE = 1; + const unsigned short SVG_UNIT_TYPE_OBJECTBOUNDINGBOX = 2; + }; + + interface SVGStylable { + + readonly attribute SVGAnimatedString className; + readonly attribute css::CSSStyleDeclaration style; + + css::CSSValue getPresentationAttribute ( in DOMString name ); + }; + + interface SVGLocatable { + + readonly attribute SVGElement nearestViewportElement; + readonly attribute SVGElement farthestViewportElement; + + SVGRect getBBox ( ); + SVGMatrix getCTM ( ); + SVGMatrix getScreenCTM ( ); + SVGMatrix getTransformToElement ( in SVGElement element ) + raises( SVGException ); + }; + + interface SVGTransformable : SVGLocatable { + readonly attribute SVGAnimatedTransformList transform; + }; + + interface SVGTests { + + readonly attribute SVGStringList requiredFeatures; + readonly attribute SVGStringList requiredExtensions; + readonly attribute SVGStringList systemLanguage; + + boolean hasExtension ( in DOMString extension ); + }; + + interface SVGLangSpace { + + attribute DOMString xmllang; + // raises DOMException on setting + attribute DOMString xmlspace; + // raises DOMException on setting + }; + + interface SVGExternalResourcesRequired { + + readonly attribute SVGAnimatedBoolean externalResourcesRequired; + }; + + interface SVGFitToViewBox { + + readonly attribute SVGAnimatedRect viewBox; + readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio; + }; + + interface SVGZoomAndPan { + + // Zoom and Pan Types + const unsigned short SVG_ZOOMANDPAN_UNKNOWN = 0; + const unsigned short SVG_ZOOMANDPAN_DISABLE = 1; + const unsigned short SVG_ZOOMANDPAN_MAGNIFY = 2; + + attribute unsigned short zoomAndPan; + // raises DOMException on setting + }; + + interface SVGViewSpec : + SVGZoomAndPan, + SVGFitToViewBox { + + readonly attribute SVGTransformList transform; + readonly attribute SVGElement viewTarget; + readonly attribute DOMString viewBoxString; + readonly attribute DOMString preserveAspectRatioString; + readonly attribute DOMString transformString; + readonly attribute DOMString viewTargetString; + }; + + interface SVGURIReference { + + readonly attribute SVGAnimatedString href; + }; + + interface SVGCSSRule : css::CSSRule { + // Additional CSS RuleType to support ICC color specifications + const unsigned short COLOR_PROFILE_RULE = 7; + }; + + interface SVGRenderingIntent { + + // Rendering Intent Types + const unsigned short RENDERING_INTENT_UNKNOWN = 0; + const unsigned short RENDERING_INTENT_AUTO = 1; + const unsigned short RENDERING_INTENT_PERCEPTUAL = 2; + const unsigned short RENDERING_INTENT_RELATIVE_COLORIMETRIC = 3; + const unsigned short RENDERING_INTENT_SATURATION = 4; + const unsigned short RENDERING_INTENT_ABSOLUTE_COLORIMETRIC = 5; + }; + + interface SVGDocument : + Document, + events::DocumentEvent { + + readonly attribute DOMString title; + readonly attribute DOMString referrer; + readonly attribute DOMString domain; + readonly attribute DOMString URL; + readonly attribute SVGSVGElement rootElement; + }; + + interface SVGSVGElement : + SVGElement, + SVGTests, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGLocatable, + SVGFitToViewBox, + SVGZoomAndPan, + events::EventTarget, + events::DocumentEvent, + css::ViewCSS, + css::DocumentCSS { + + readonly attribute SVGAnimatedLength x; + readonly attribute SVGAnimatedLength y; + readonly attribute SVGAnimatedLength width; + readonly attribute SVGAnimatedLength height; + attribute DOMString contentScriptType; + // raises DOMException on setting + attribute DOMString contentStyleType; + // raises DOMException on setting + readonly attribute SVGRect viewport; + readonly attribute float pixelUnitToMillimeterX; + readonly attribute float pixelUnitToMillimeterY; + readonly attribute float screenPixelToMillimeterX; + readonly attribute float screenPixelToMillimeterY; + attribute boolean useCurrentView; + // raises DOMException on setting + readonly attribute SVGViewSpec currentView; + attribute float currentScale; + // raises DOMException on setting + readonly attribute SVGPoint currentTranslate; + + unsigned long suspendRedraw ( in unsigned long max_wait_milliseconds ); + void unsuspendRedraw ( in unsigned long suspend_handle_id ) + raises( DOMException ); + void unsuspendRedrawAll ( ); + void forceRedraw ( ); + void pauseAnimations ( ); + void unpauseAnimations ( ); + boolean animationsPaused ( ); + float getCurrentTime ( ); + void setCurrentTime ( in float seconds ); + NodeList getIntersectionList ( in SVGRect rect, in SVGElement referenceElement ); + NodeList getEnclosureList ( in SVGRect rect, in SVGElement referenceElement ); + boolean checkIntersection ( in SVGElement element, in SVGRect rect ); + boolean checkEnclosure ( in SVGElement element, in SVGRect rect ); + void deselectAll ( ); + SVGNumber createSVGNumber ( ); + SVGLength createSVGLength ( ); + SVGAngle createSVGAngle ( ); + SVGPoint createSVGPoint ( ); + SVGMatrix createSVGMatrix ( ); + SVGRect createSVGRect ( ); + SVGTransform createSVGTransform ( ); + SVGTransform createSVGTransformFromMatrix ( in SVGMatrix matrix ); + Element getElementById ( in DOMString elementId ); + }; + + interface SVGGElement : + SVGElement, + SVGTests, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGTransformable, + events::EventTarget {}; + + interface SVGDefsElement : + SVGElement, + SVGTests, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGTransformable, + events::EventTarget {}; + + interface SVGDescElement : + SVGElement, + SVGLangSpace, + SVGStylable {}; + + interface SVGTitleElement : + SVGElement, + SVGLangSpace, + SVGStylable {}; + + interface SVGSymbolElement : + SVGElement, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGFitToViewBox, + events::EventTarget {}; + + interface SVGUseElement : + SVGElement, + SVGURIReference, + SVGTests, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGTransformable, + events::EventTarget { + + readonly attribute SVGAnimatedLength x; + readonly attribute SVGAnimatedLength y; + readonly attribute SVGAnimatedLength width; + readonly attribute SVGAnimatedLength height; + readonly attribute SVGElementInstance instanceRoot; + readonly attribute SVGElementInstance animatedInstanceRoot; + }; + + interface SVGElementInstance : events::EventTarget { + readonly attribute SVGElement correspondingElement; + readonly attribute SVGUseElement correspondingUseElement; + readonly attribute SVGElementInstance parentNode; + readonly attribute SVGElementInstanceList childNodes; + readonly attribute SVGElementInstance firstChild; + readonly attribute SVGElementInstance lastChild; + readonly attribute SVGElementInstance previousSibling; + readonly attribute SVGElementInstance nextSibling; + }; + + interface SVGElementInstanceList { + + readonly attribute unsigned long length; + + SVGElementInstance item ( in unsigned long index ); + }; + + interface SVGImageElement : + SVGElement, + SVGURIReference, + SVGTests, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGTransformable, + events::EventTarget { + + readonly attribute SVGAnimatedLength x; + readonly attribute SVGAnimatedLength y; + readonly attribute SVGAnimatedLength width; + readonly attribute SVGAnimatedLength height; + readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio; + }; + + interface SVGSwitchElement : + SVGElement, + SVGTests, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGTransformable, + events::EventTarget {}; + + interface GetSVGDocument { + + SVGDocument getSVGDocument ( ) + raises( DOMException ); + }; + + interface SVGStyleElement : SVGElement { + attribute DOMString xmlspace; + // raises DOMException on setting + attribute DOMString type; + // raises DOMException on setting + attribute DOMString media; + // raises DOMException on setting + attribute DOMString title; + // raises DOMException on setting + }; + + interface SVGPoint { + + attribute float x; + // raises DOMException on setting + attribute float y; + // raises DOMException on setting + + SVGPoint matrixTransform ( in SVGMatrix matrix ); + }; + + interface SVGPointList { + + readonly attribute unsigned long numberOfItems; + + void clear ( ) + raises( DOMException ); + SVGPoint initialize ( in SVGPoint newItem ) + raises( DOMException, SVGException ); + SVGPoint getItem ( in unsigned long index ) + raises( DOMException ); + SVGPoint insertItemBefore ( in SVGPoint newItem, in unsigned long index ) + raises( DOMException, SVGException ); + SVGPoint replaceItem ( in SVGPoint newItem, in unsigned long index ) + raises( DOMException, SVGException ); + SVGPoint removeItem ( in unsigned long index ) + raises( DOMException ); + SVGPoint appendItem ( in SVGPoint newItem ) + raises( DOMException, SVGException ); + }; + + interface SVGMatrix { + + attribute float a; + // raises DOMException on setting + attribute float b; + // raises DOMException on setting + attribute float c; + // raises DOMException on setting + attribute float d; + // raises DOMException on setting + attribute float e; + // raises DOMException on setting + attribute float f; + // raises DOMException on setting + + SVGMatrix multiply ( in SVGMatrix secondMatrix ); + SVGMatrix inverse ( ) + raises( SVGException ); + SVGMatrix translate ( in float x, in float y ); + SVGMatrix scale ( in float scaleFactor ); + SVGMatrix scaleNonUniform ( in float scaleFactorX, in float scaleFactorY ); + SVGMatrix rotate ( in float angle ); + SVGMatrix rotateFromVector ( in float x, in float y ) + raises( SVGException ); + SVGMatrix flipX ( ); + SVGMatrix flipY ( ); + SVGMatrix skewX ( in float angle ); + SVGMatrix skewY ( in float angle ); + }; + + interface SVGTransform { + + // Transform Types + const unsigned short SVG_TRANSFORM_UNKNOWN = 0; + const unsigned short SVG_TRANSFORM_MATRIX = 1; + const unsigned short SVG_TRANSFORM_TRANSLATE = 2; + const unsigned short SVG_TRANSFORM_SCALE = 3; + const unsigned short SVG_TRANSFORM_ROTATE = 4; + const unsigned short SVG_TRANSFORM_SKEWX = 5; + const unsigned short SVG_TRANSFORM_SKEWY = 6; + + readonly attribute unsigned short type; + readonly attribute SVGMatrix matrix; + readonly attribute float angle; + + void setMatrix ( in SVGMatrix matrix ); + void setTranslate ( in float tx, in float ty ); + void setScale ( in float sx, in float sy ); + void setRotate ( in float angle, in float cx, in float cy ); + void setSkewX ( in float angle ); + void setSkewY ( in float angle ); + }; + + interface SVGTransformList { + + readonly attribute unsigned long numberOfItems; + + void clear ( ) + raises( DOMException ); + SVGTransform initialize ( in SVGTransform newItem ) + raises( DOMException, SVGException ); + SVGTransform getItem ( in unsigned long index ) + raises( DOMException ); + SVGTransform insertItemBefore ( in SVGTransform newItem, in unsigned long index ) + raises( DOMException, SVGException ); + SVGTransform replaceItem ( in SVGTransform newItem, in unsigned long index ) + raises( DOMException, SVGException ); + SVGTransform removeItem ( in unsigned long index ) + raises( DOMException ); + SVGTransform appendItem ( in SVGTransform newItem ) + raises( DOMException, SVGException ); + SVGTransform createSVGTransformFromMatrix ( in SVGMatrix matrix ); + SVGTransform consolidate ( ); + }; + + interface SVGAnimatedTransformList { + + readonly attribute SVGTransformList baseVal; + readonly attribute SVGTransformList animVal; + }; + + interface SVGPreserveAspectRatio { + + // Alignment Types + const unsigned short SVG_PRESERVEASPECTRATIO_UNKNOWN = 0; + const unsigned short SVG_PRESERVEASPECTRATIO_NONE = 1; + const unsigned short SVG_PRESERVEASPECTRATIO_XMINYMIN = 2; + const unsigned short SVG_PRESERVEASPECTRATIO_XMIDYMIN = 3; + const unsigned short SVG_PRESERVEASPECTRATIO_XMAXYMIN = 4; + const unsigned short SVG_PRESERVEASPECTRATIO_XMINYMID = 5; + const unsigned short SVG_PRESERVEASPECTRATIO_XMIDYMID = 6; + const unsigned short SVG_PRESERVEASPECTRATIO_XMAXYMID = 7; + const unsigned short SVG_PRESERVEASPECTRATIO_XMINYMAX = 8; + const unsigned short SVG_PRESERVEASPECTRATIO_XMIDYMAX = 9; + const unsigned short SVG_PRESERVEASPECTRATIO_XMAXYMAX = 10; + // Meet-or-slice Types + const unsigned short SVG_MEETORSLICE_UNKNOWN = 0; + const unsigned short SVG_MEETORSLICE_MEET = 1; + const unsigned short SVG_MEETORSLICE_SLICE = 2; + + attribute unsigned short align; + // raises DOMException on setting + attribute unsigned short meetOrSlice; + // raises DOMException on setting + }; + + interface SVGAnimatedPreserveAspectRatio { + + readonly attribute SVGPreserveAspectRatio baseVal; + readonly attribute SVGPreserveAspectRatio animVal; + }; + + interface SVGPathSeg { + + // Path Segment Types + const unsigned short PATHSEG_UNKNOWN = 0; + const unsigned short PATHSEG_CLOSEPATH = 1; + const unsigned short PATHSEG_MOVETO_ABS = 2; + const unsigned short PATHSEG_MOVETO_REL = 3; + const unsigned short PATHSEG_LINETO_ABS = 4; + const unsigned short PATHSEG_LINETO_REL = 5; + const unsigned short PATHSEG_CURVETO_CUBIC_ABS = 6; + const unsigned short PATHSEG_CURVETO_CUBIC_REL = 7; + const unsigned short PATHSEG_CURVETO_QUADRATIC_ABS = 8; + const unsigned short PATHSEG_CURVETO_QUADRATIC_REL = 9; + const unsigned short PATHSEG_ARC_ABS = 10; + const unsigned short PATHSEG_ARC_REL = 11; + const unsigned short PATHSEG_LINETO_HORIZONTAL_ABS = 12; + const unsigned short PATHSEG_LINETO_HORIZONTAL_REL = 13; + const unsigned short PATHSEG_LINETO_VERTICAL_ABS = 14; + const unsigned short PATHSEG_LINETO_VERTICAL_REL = 15; + const unsigned short PATHSEG_CURVETO_CUBIC_SMOOTH_ABS = 16; + const unsigned short PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17; + const unsigned short PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18; + const unsigned short PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19; + + readonly attribute unsigned short pathSegType; + readonly attribute DOMString pathSegTypeAsLetter; + }; + + interface SVGPathSegClosePath : SVGPathSeg {}; + + interface SVGPathSegMovetoAbs : SVGPathSeg { + attribute float x; + // raises DOMException on setting + attribute float y; + // raises DOMException on setting + }; + + interface SVGPathSegMovetoRel : SVGPathSeg { + attribute float x; + // raises DOMException on setting + attribute float y; + // raises DOMException on setting + }; + + interface SVGPathSegLinetoAbs : SVGPathSeg { + attribute float x; + // raises DOMException on setting + attribute float y; + // raises DOMException on setting + }; + + interface SVGPathSegLinetoRel : SVGPathSeg { + attribute float x; + // raises DOMException on setting + attribute float y; + // raises DOMException on setting + }; + + interface SVGPathSegCurvetoCubicAbs : SVGPathSeg { + attribute float x; + // raises DOMException on setting + attribute float y; + // raises DOMException on setting + attribute float x1; + // raises DOMException on setting + attribute float y1; + // raises DOMException on setting + attribute float x2; + // raises DOMException on setting + attribute float y2; + // raises DOMException on setting + }; + + interface SVGPathSegCurvetoCubicRel : SVGPathSeg { + attribute float x; + // raises DOMException on setting + attribute float y; + // raises DOMException on setting + attribute float x1; + // raises DOMException on setting + attribute float y1; + // raises DOMException on setting + attribute float x2; + // raises DOMException on setting + attribute float y2; + // raises DOMException on setting + }; + + interface SVGPathSegCurvetoQuadraticAbs : SVGPathSeg { + attribute float x; + // raises DOMException on setting + attribute float y; + // raises DOMException on setting + attribute float x1; + // raises DOMException on setting + attribute float y1; + // raises DOMException on setting + }; + + interface SVGPathSegCurvetoQuadraticRel : SVGPathSeg { + attribute float x; + // raises DOMException on setting + attribute float y; + // raises DOMException on setting + attribute float x1; + // raises DOMException on setting + attribute float y1; + // raises DOMException on setting + }; + + interface SVGPathSegArcAbs : SVGPathSeg { + attribute float x; + // raises DOMException on setting + attribute float y; + // raises DOMException on setting + attribute float r1; + // raises DOMException on setting + attribute float r2; + // raises DOMException on setting + attribute float angle; + // raises DOMException on setting + attribute boolean largeArcFlag; + // raises DOMException on setting + attribute boolean sweepFlag; + // raises DOMException on setting + }; + + interface SVGPathSegArcRel : SVGPathSeg { + attribute float x; + // raises DOMException on setting + attribute float y; + // raises DOMException on setting + attribute float r1; + // raises DOMException on setting + attribute float r2; + // raises DOMException on setting + attribute float angle; + // raises DOMException on setting + attribute boolean largeArcFlag; + // raises DOMException on setting + attribute boolean sweepFlag; + // raises DOMException on setting + }; + + interface SVGPathSegLinetoHorizontalAbs : SVGPathSeg { + attribute float x; + // raises DOMException on setting + }; + + interface SVGPathSegLinetoHorizontalRel : SVGPathSeg { + attribute float x; + // raises DOMException on setting + }; + + interface SVGPathSegLinetoVerticalAbs : SVGPathSeg { + attribute float y; + // raises DOMException on setting + }; + + interface SVGPathSegLinetoVerticalRel : SVGPathSeg { + attribute float y; + // raises DOMException on setting + }; + + interface SVGPathSegCurvetoCubicSmoothAbs : SVGPathSeg { + attribute float x; + // raises DOMException on setting + attribute float y; + // raises DOMException on setting + attribute float x2; + // raises DOMException on setting + attribute float y2; + // raises DOMException on setting + }; + + interface SVGPathSegCurvetoCubicSmoothRel : SVGPathSeg { + attribute float x; + // raises DOMException on setting + attribute float y; + // raises DOMException on setting + attribute float x2; + // raises DOMException on setting + attribute float y2; + // raises DOMException on setting + }; + + interface SVGPathSegCurvetoQuadraticSmoothAbs : SVGPathSeg { + attribute float x; + // raises DOMException on setting + attribute float y; + // raises DOMException on setting + }; + + interface SVGPathSegCurvetoQuadraticSmoothRel : SVGPathSeg { + attribute float x; + // raises DOMException on setting + attribute float y; + // raises DOMException on setting + }; + + interface SVGPathSegList { + + readonly attribute unsigned long numberOfItems; + + void clear ( ) + raises( DOMException ); + SVGPathSeg initialize ( in SVGPathSeg newItem ) + raises( DOMException, SVGException ); + SVGPathSeg getItem ( in unsigned long index ) + raises( DOMException ); + SVGPathSeg insertItemBefore ( in SVGPathSeg newItem, in unsigned long index ) + raises( DOMException, SVGException ); + SVGPathSeg replaceItem ( in SVGPathSeg newItem, in unsigned long index ) + raises( DOMException, SVGException ); + SVGPathSeg removeItem ( in unsigned long index ) + raises( DOMException ); + SVGPathSeg appendItem ( in SVGPathSeg newItem ) + raises( DOMException, SVGException ); + }; + + interface SVGAnimatedPathData { + + readonly attribute SVGPathSegList pathSegList; + readonly attribute SVGPathSegList normalizedPathSegList; + readonly attribute SVGPathSegList animatedPathSegList; + readonly attribute SVGPathSegList animatedNormalizedPathSegList; + }; + + interface SVGPathElement : + SVGElement, + SVGTests, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGTransformable, + events::EventTarget, + SVGAnimatedPathData { + + readonly attribute SVGAnimatedNumber pathLength; + + float getTotalLength ( ); + SVGPoint getPointAtLength ( in float distance ); + unsigned long getPathSegAtLength ( in float distance ); + SVGPathSegClosePath createSVGPathSegClosePath ( ); + SVGPathSegMovetoAbs createSVGPathSegMovetoAbs ( in float x, in float y ); + SVGPathSegMovetoRel createSVGPathSegMovetoRel ( in float x, in float y ); + SVGPathSegLinetoAbs createSVGPathSegLinetoAbs ( in float x, in float y ); + SVGPathSegLinetoRel createSVGPathSegLinetoRel ( in float x, in float y ); + SVGPathSegCurvetoCubicAbs createSVGPathSegCurvetoCubicAbs ( in float x, in float y, in float x1, in float y1, in float x2, in float y2 ); + SVGPathSegCurvetoCubicRel createSVGPathSegCurvetoCubicRel ( in float x, in float y, in float x1, in float y1, in float x2, in float y2 ); + SVGPathSegCurvetoQuadraticAbs createSVGPathSegCurvetoQuadraticAbs ( in float x, in float y, in float x1, in float y1 ); + SVGPathSegCurvetoQuadraticRel createSVGPathSegCurvetoQuadraticRel ( in float x, in float y, in float x1, in float y1 ); + SVGPathSegArcAbs createSVGPathSegArcAbs ( in float x, in float y, in float r1, in float r2, in float angle, in boolean largeArcFlag, in boolean sweepFlag ); + SVGPathSegArcRel createSVGPathSegArcRel ( in float x, in float y, in float r1, in float r2, in float angle, in boolean largeArcFlag, in boolean sweepFlag ); + SVGPathSegLinetoHorizontalAbs createSVGPathSegLinetoHorizontalAbs ( in float x ); + SVGPathSegLinetoHorizontalRel createSVGPathSegLinetoHorizontalRel ( in float x ); + SVGPathSegLinetoVerticalAbs createSVGPathSegLinetoVerticalAbs ( in float y ); + SVGPathSegLinetoVerticalRel createSVGPathSegLinetoVerticalRel ( in float y ); + SVGPathSegCurvetoCubicSmoothAbs createSVGPathSegCurvetoCubicSmoothAbs ( in float x, in float y, in float x2, in float y2 ); + SVGPathSegCurvetoCubicSmoothRel createSVGPathSegCurvetoCubicSmoothRel ( in float x, in float y, in float x2, in float y2 ); + SVGPathSegCurvetoQuadraticSmoothAbs createSVGPathSegCurvetoQuadraticSmoothAbs ( in float x, in float y ); + SVGPathSegCurvetoQuadraticSmoothRel createSVGPathSegCurvetoQuadraticSmoothRel ( in float x, in float y ); + }; + + interface SVGRectElement : + SVGElement, + SVGTests, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGTransformable, + events::EventTarget { + + readonly attribute SVGAnimatedLength x; + readonly attribute SVGAnimatedLength y; + readonly attribute SVGAnimatedLength width; + readonly attribute SVGAnimatedLength height; + readonly attribute SVGAnimatedLength rx; + readonly attribute SVGAnimatedLength ry; + }; + + interface SVGCircleElement : + SVGElement, + SVGTests, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGTransformable, + events::EventTarget { + + readonly attribute SVGAnimatedLength cx; + readonly attribute SVGAnimatedLength cy; + readonly attribute SVGAnimatedLength r; + }; + + interface SVGEllipseElement : + SVGElement, + SVGTests, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGTransformable, + events::EventTarget { + + readonly attribute SVGAnimatedLength cx; + readonly attribute SVGAnimatedLength cy; + readonly attribute SVGAnimatedLength rx; + readonly attribute SVGAnimatedLength ry; + }; + + interface SVGLineElement : + SVGElement, + SVGTests, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGTransformable, + events::EventTarget { + + readonly attribute SVGAnimatedLength x1; + readonly attribute SVGAnimatedLength y1; + readonly attribute SVGAnimatedLength x2; + readonly attribute SVGAnimatedLength y2; + }; + + interface SVGAnimatedPoints { + + readonly attribute SVGPointList points; + readonly attribute SVGPointList animatedPoints; + }; + + interface SVGPolylineElement : + SVGElement, + SVGTests, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGTransformable, + events::EventTarget, + SVGAnimatedPoints {}; + + interface SVGPolygonElement : + SVGElement, + SVGTests, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGTransformable, + events::EventTarget, + SVGAnimatedPoints {}; + + interface SVGTextContentElement : + SVGElement, + SVGTests, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + events::EventTarget { + + // lengthAdjust Types + const unsigned short LENGTHADJUST_UNKNOWN = 0; + const unsigned short LENGTHADJUST_SPACING = 1; + const unsigned short LENGTHADJUST_SPACINGANDGLYPHS = 2; + + readonly attribute SVGAnimatedLength textLength; + readonly attribute SVGAnimatedEnumeration lengthAdjust; + + long getNumberOfChars ( ); + float getComputedTextLength ( ); + float getSubStringLength ( in unsigned long charnum, in unsigned long nchars ) + raises( DOMException ); + SVGPoint getStartPositionOfChar ( in unsigned long charnum ) + raises( DOMException ); + SVGPoint getEndPositionOfChar ( in unsigned long charnum ) + raises( DOMException ); + SVGRect getExtentOfChar ( in unsigned long charnum ) + raises( DOMException ); + float getRotationOfChar ( in unsigned long charnum ) + raises( DOMException ); + long getCharNumAtPosition ( in SVGPoint point ); + void selectSubString ( in unsigned long charnum, in unsigned long nchars ) + raises( DOMException ); + }; + + interface SVGTextPositioningElement : SVGTextContentElement { + readonly attribute SVGAnimatedLengthList x; + readonly attribute SVGAnimatedLengthList y; + readonly attribute SVGAnimatedLengthList dx; + readonly attribute SVGAnimatedLengthList dy; + readonly attribute SVGAnimatedNumberList rotate; + }; + + interface SVGTextElement : + SVGTextPositioningElement, + SVGTransformable {}; + + interface SVGTSpanElement : SVGTextPositioningElement {}; + + interface SVGTRefElement : + SVGTextPositioningElement, + SVGURIReference {}; + + interface SVGTextPathElement : + SVGTextContentElement, + SVGURIReference { + + // textPath Method Types + const unsigned short TEXTPATH_METHODTYPE_UNKNOWN = 0; + const unsigned short TEXTPATH_METHODTYPE_ALIGN = 1; + const unsigned short TEXTPATH_METHODTYPE_STRETCH = 2; + // textPath Spacing Types + const unsigned short TEXTPATH_SPACINGTYPE_UNKNOWN = 0; + const unsigned short TEXTPATH_SPACINGTYPE_AUTO = 1; + const unsigned short TEXTPATH_SPACINGTYPE_EXACT = 2; + + readonly attribute SVGAnimatedLength startOffset; + readonly attribute SVGAnimatedEnumeration method; + readonly attribute SVGAnimatedEnumeration spacing; + }; + + interface SVGAltGlyphElement : + SVGTextPositioningElement, + SVGURIReference { + + attribute DOMString glyphRef; + // raises DOMException on setting + attribute DOMString format; + // raises DOMException on setting + }; + + interface SVGAltGlyphDefElement : SVGElement {}; + + interface SVGAltGlyphItemElement : SVGElement {}; + + interface SVGGlyphRefElement : + SVGElement, + SVGURIReference, + SVGStylable { + + attribute DOMString glyphRef; + // raises DOMException on setting + attribute DOMString format; + // raises DOMException on setting + attribute float x; + // raises DOMException on setting + attribute float y; + // raises DOMException on setting + attribute float dx; + // raises DOMException on setting + attribute float dy; + // raises DOMException on setting + }; + + interface SVGPaint : SVGColor { + // Paint Types + const unsigned short SVG_PAINTTYPE_UNKNOWN = 0; + const unsigned short SVG_PAINTTYPE_RGBCOLOR = 1; + const unsigned short SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR = 2; + const unsigned short SVG_PAINTTYPE_NONE = 101; + const unsigned short SVG_PAINTTYPE_CURRENTCOLOR = 102; + const unsigned short SVG_PAINTTYPE_URI_NONE = 103; + const unsigned short SVG_PAINTTYPE_URI_CURRENTCOLOR = 104; + const unsigned short SVG_PAINTTYPE_URI_RGBCOLOR = 105; + const unsigned short SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR = 106; + const unsigned short SVG_PAINTTYPE_URI = 107; + + readonly attribute unsigned short paintType; + readonly attribute DOMString uri; + + void setUri ( in DOMString uri ); + void setPaint ( in unsigned short paintType, in DOMString uri, in DOMString rgbColor, in DOMString iccColor ) + raises( SVGException ); + }; + + interface SVGMarkerElement : + SVGElement, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGFitToViewBox { + + // Marker Unit Types + const unsigned short SVG_MARKERUNITS_UNKNOWN = 0; + const unsigned short SVG_MARKERUNITS_USERSPACEONUSE = 1; + const unsigned short SVG_MARKERUNITS_STROKEWIDTH = 2; + // Marker Orientation Types + const unsigned short SVG_MARKER_ORIENT_UNKNOWN = 0; + const unsigned short SVG_MARKER_ORIENT_AUTO = 1; + const unsigned short SVG_MARKER_ORIENT_ANGLE = 2; + + readonly attribute SVGAnimatedLength refX; + readonly attribute SVGAnimatedLength refY; + readonly attribute SVGAnimatedEnumeration markerUnits; + readonly attribute SVGAnimatedLength markerWidth; + readonly attribute SVGAnimatedLength markerHeight; + readonly attribute SVGAnimatedEnumeration orientType; + readonly attribute SVGAnimatedAngle orientAngle; + + void setOrientToAuto ( ); + void setOrientToAngle ( in SVGAngle angle ); + }; + + interface SVGColorProfileElement : + SVGElement, + SVGURIReference, + SVGRenderingIntent { + + attribute DOMString local; + // raises DOMException on setting + attribute DOMString name; + // raises DOMException on setting + attribute unsigned short renderingIntent; + // raises DOMException on setting + }; + + interface SVGColorProfileRule : + SVGCSSRule, + SVGRenderingIntent { + + attribute DOMString src; + // raises DOMException on setting + attribute DOMString name; + // raises DOMException on setting + attribute unsigned short renderingIntent; + // raises DOMException on setting + }; + + interface SVGGradientElement : + SVGElement, + SVGURIReference, + SVGExternalResourcesRequired, + SVGStylable, + SVGUnitTypes { + + // Spread Method Types + const unsigned short SVG_SPREADMETHOD_UNKNOWN = 0; + const unsigned short SVG_SPREADMETHOD_PAD = 1; + const unsigned short SVG_SPREADMETHOD_REFLECT = 2; + const unsigned short SVG_SPREADMETHOD_REPEAT = 3; + + readonly attribute SVGAnimatedEnumeration gradientUnits; + readonly attribute SVGAnimatedTransformList gradientTransform; + readonly attribute SVGAnimatedEnumeration spreadMethod; + }; + + interface SVGLinearGradientElement : SVGGradientElement { + readonly attribute SVGAnimatedLength x1; + readonly attribute SVGAnimatedLength y1; + readonly attribute SVGAnimatedLength x2; + readonly attribute SVGAnimatedLength y2; + }; + + interface SVGRadialGradientElement : SVGGradientElement { + readonly attribute SVGAnimatedLength cx; + readonly attribute SVGAnimatedLength cy; + readonly attribute SVGAnimatedLength r; + readonly attribute SVGAnimatedLength fx; + readonly attribute SVGAnimatedLength fy; + }; + + interface SVGStopElement : + SVGElement, + SVGStylable { + + readonly attribute SVGAnimatedNumber offset; + }; + + interface SVGPatternElement : + SVGElement, + SVGURIReference, + SVGTests, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGFitToViewBox, + SVGUnitTypes { + + readonly attribute SVGAnimatedEnumeration patternUnits; + readonly attribute SVGAnimatedEnumeration patternContentUnits; + readonly attribute SVGAnimatedTransformList patternTransform; + readonly attribute SVGAnimatedLength x; + readonly attribute SVGAnimatedLength y; + readonly attribute SVGAnimatedLength width; + readonly attribute SVGAnimatedLength height; + }; + + interface SVGClipPathElement : + SVGElement, + SVGTests, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGTransformable, + SVGUnitTypes { + + readonly attribute SVGAnimatedEnumeration clipPathUnits; + }; + + interface SVGMaskElement : + SVGElement, + SVGTests, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGUnitTypes { + + readonly attribute SVGAnimatedEnumeration maskUnits; + readonly attribute SVGAnimatedEnumeration maskContentUnits; + readonly attribute SVGAnimatedLength x; + readonly attribute SVGAnimatedLength y; + readonly attribute SVGAnimatedLength width; + readonly attribute SVGAnimatedLength height; + }; + + interface SVGFilterElement : + SVGElement, + SVGURIReference, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGUnitTypes { + + readonly attribute SVGAnimatedEnumeration filterUnits; + readonly attribute SVGAnimatedEnumeration primitiveUnits; + readonly attribute SVGAnimatedLength x; + readonly attribute SVGAnimatedLength y; + readonly attribute SVGAnimatedLength width; + readonly attribute SVGAnimatedLength height; + readonly attribute SVGAnimatedInteger filterResX; + readonly attribute SVGAnimatedInteger filterResY; + + void setFilterRes ( in unsigned long filterResX, in unsigned long filterResY ); + }; + + interface SVGFilterPrimitiveStandardAttributes { + + readonly attribute SVGAnimatedLength x; + readonly attribute SVGAnimatedLength y; + readonly attribute SVGAnimatedLength width; + readonly attribute SVGAnimatedLength height; + readonly attribute SVGAnimatedString result; + }; + + interface SVGFEBlendElement : + SVGElement, + SVGFilterPrimitiveStandardAttributes { + + // Blend Mode Types + const unsigned short SVG_FEBLEND_MODE_UNKNOWN = 0; + const unsigned short SVG_FEBLEND_MODE_NORMAL = 1; + const unsigned short SVG_FEBLEND_MODE_MULTIPLY = 2; + const unsigned short SVG_FEBLEND_MODE_SCREEN = 3; + const unsigned short SVG_FEBLEND_MODE_DARKEN = 4; + const unsigned short SVG_FEBLEND_MODE_LIGHTEN = 5; + + readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedString in2; + readonly attribute SVGAnimatedEnumeration mode; + }; + + interface SVGFEColorMatrixElement : + SVGElement, + SVGFilterPrimitiveStandardAttributes { + + // Color Matrix Types + const unsigned short SVG_FECOLORMATRIX_TYPE_UNKNOWN = 0; + const unsigned short SVG_FECOLORMATRIX_TYPE_MATRIX = 1; + const unsigned short SVG_FECOLORMATRIX_TYPE_SATURATE = 2; + const unsigned short SVG_FECOLORMATRIX_TYPE_HUEROTATE = 3; + const unsigned short SVG_FECOLORMATRIX_TYPE_LUMINANCETOALPHA = 4; + + readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedEnumeration type; + readonly attribute SVGAnimatedNumberList values; + }; + + interface SVGFEComponentTransferElement : + SVGElement, + SVGFilterPrimitiveStandardAttributes { + + readonly attribute SVGAnimatedString in1; + }; + + interface SVGComponentTransferFunctionElement : SVGElement { + // Component Transfer Types + const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_UNKNOWN = 0; + const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY = 1; + const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_TABLE = 2; + const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE = 3; + const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_LINEAR = 4; + const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_GAMMA = 5; + + readonly attribute SVGAnimatedEnumeration type; + readonly attribute SVGAnimatedNumberList tableValues; + readonly attribute SVGAnimatedNumber slope; + readonly attribute SVGAnimatedNumber intercept; + readonly attribute SVGAnimatedNumber amplitude; + readonly attribute SVGAnimatedNumber exponent; + readonly attribute SVGAnimatedNumber offset; + }; + + interface SVGFEFuncRElement : SVGComponentTransferFunctionElement {}; + + interface SVGFEFuncGElement : SVGComponentTransferFunctionElement {}; + + interface SVGFEFuncBElement : SVGComponentTransferFunctionElement {}; + + interface SVGFEFuncAElement : SVGComponentTransferFunctionElement {}; + + interface SVGFECompositeElement : + SVGElement, + SVGFilterPrimitiveStandardAttributes { + + // Composite Operators + const unsigned short SVG_FECOMPOSITE_OPERATOR_UNKNOWN = 0; + const unsigned short SVG_FECOMPOSITE_OPERATOR_OVER = 1; + const unsigned short SVG_FECOMPOSITE_OPERATOR_IN = 2; + const unsigned short SVG_FECOMPOSITE_OPERATOR_OUT = 3; + const unsigned short SVG_FECOMPOSITE_OPERATOR_ATOP = 4; + const unsigned short SVG_FECOMPOSITE_OPERATOR_XOR = 5; + const unsigned short SVG_FECOMPOSITE_OPERATOR_ARITHMETIC = 6; + + readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedString in2; + readonly attribute SVGAnimatedEnumeration operator; + readonly attribute SVGAnimatedNumber k1; + readonly attribute SVGAnimatedNumber k2; + readonly attribute SVGAnimatedNumber k3; + readonly attribute SVGAnimatedNumber k4; + }; + + interface SVGFEConvolveMatrixElement : + SVGElement, + SVGFilterPrimitiveStandardAttributes { + + // Edge Mode Values + const unsigned short SVG_EDGEMODE_UNKNOWN = 0; + const unsigned short SVG_EDGEMODE_DUPLICATE = 1; + const unsigned short SVG_EDGEMODE_WRAP = 2; + const unsigned short SVG_EDGEMODE_NONE = 3; + + readonly attribute SVGAnimatedInteger orderX; + readonly attribute SVGAnimatedInteger orderY; + readonly attribute SVGAnimatedNumberList kernelMatrix; + readonly attribute SVGAnimatedNumber divisor; + readonly attribute SVGAnimatedNumber bias; + readonly attribute SVGAnimatedInteger targetX; + readonly attribute SVGAnimatedInteger targetY; + readonly attribute SVGAnimatedEnumeration edgeMode; + readonly attribute SVGAnimatedLength kernelUnitLengthX; + readonly attribute SVGAnimatedLength kernelUnitLengthY; + readonly attribute SVGAnimatedBoolean preserveAlpha; + }; + + interface SVGFEDiffuseLightingElement : + SVGElement, + SVGStylable, + SVGFilterPrimitiveStandardAttributes { + + readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedNumber surfaceScale; + readonly attribute SVGAnimatedNumber diffuseConstant; + }; + + interface SVGFEDistantLightElement : SVGElement { + readonly attribute SVGAnimatedNumber azimuth; + readonly attribute SVGAnimatedNumber elevation; + }; + + interface SVGFEPointLightElement : SVGElement { + readonly attribute SVGAnimatedNumber x; + readonly attribute SVGAnimatedNumber y; + readonly attribute SVGAnimatedNumber z; + }; + + interface SVGFESpotLightElement : SVGElement { + readonly attribute SVGAnimatedNumber x; + readonly attribute SVGAnimatedNumber y; + readonly attribute SVGAnimatedNumber z; + readonly attribute SVGAnimatedNumber pointsAtX; + readonly attribute SVGAnimatedNumber pointsAtY; + readonly attribute SVGAnimatedNumber pointsAtZ; + readonly attribute SVGAnimatedNumber specularExponent; + readonly attribute SVGAnimatedNumber limitingConeAngle; + }; + + interface SVGFEDisplacementMapElement : + SVGElement, + SVGFilterPrimitiveStandardAttributes { + + // Channel Selectors + const unsigned short SVG_CHANNEL_UNKNOWN = 0; + const unsigned short SVG_CHANNEL_R = 1; + const unsigned short SVG_CHANNEL_G = 2; + const unsigned short SVG_CHANNEL_B = 3; + const unsigned short SVG_CHANNEL_A = 4; + + readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedString in2; + readonly attribute SVGAnimatedNumber scale; + readonly attribute SVGAnimatedEnumeration xChannelSelector; + readonly attribute SVGAnimatedEnumeration yChannelSelector; + }; + + interface SVGFEFloodElement : + SVGElement, + SVGStylable, + SVGFilterPrimitiveStandardAttributes { + + readonly attribute SVGAnimatedString in1; + }; + + interface SVGFEGaussianBlurElement : + SVGElement, + SVGFilterPrimitiveStandardAttributes { + + readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedNumber stdDeviationX; + readonly attribute SVGAnimatedNumber stdDeviationY; + + void setStdDeviation ( in float stdDeviationX, in float stdDeviationY ); + }; + + interface SVGFEImageElement : + SVGElement, + SVGURIReference, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGFilterPrimitiveStandardAttributes {}; + + interface SVGFEMergeElement : + SVGElement, + SVGFilterPrimitiveStandardAttributes {}; + + interface SVGFEMergeNodeElement : SVGElement { + readonly attribute SVGAnimatedString in1; + }; + + interface SVGFEMorphologyElement : + SVGElement, + SVGFilterPrimitiveStandardAttributes { + + // Morphology Operators + const unsigned short SVG_MORPHOLOGY_OPERATOR_UNKNOWN = 0; + const unsigned short SVG_MORPHOLOGY_OPERATOR_ERODE = 1; + const unsigned short SVG_MORPHOLOGY_OPERATOR_DILATE = 2; + + readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedEnumeration operator; + readonly attribute SVGAnimatedLength radiusX; + readonly attribute SVGAnimatedLength radiusY; + }; + + interface SVGFEOffsetElement : + SVGElement, + SVGFilterPrimitiveStandardAttributes { + + readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedNumber dx; + readonly attribute SVGAnimatedNumber dy; + }; + + interface SVGFESpecularLightingElement : + SVGElement, + SVGStylable, + SVGFilterPrimitiveStandardAttributes { + + readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedNumber surfaceScale; + readonly attribute SVGAnimatedNumber specularConstant; + readonly attribute SVGAnimatedNumber specularExponent; + }; + + interface SVGFETileElement : + SVGElement, + SVGFilterPrimitiveStandardAttributes { + + readonly attribute SVGAnimatedString in1; + }; + + interface SVGFETurbulenceElement : + SVGElement, + SVGFilterPrimitiveStandardAttributes { + + // Turbulence Types + const unsigned short SVG_TURBULENCE_TYPE_UNKNOWN = 0; + const unsigned short SVG_TURBULENCE_TYPE_FRACTALNOISE = 1; + const unsigned short SVG_TURBULENCE_TYPE_TURBULENCE = 2; + // Stitch Options + const unsigned short SVG_STITCHTYPE_UNKNOWN = 0; + const unsigned short SVG_STITCHTYPE_STITCH = 1; + const unsigned short SVG_STITCHTYPE_NOSTITCH = 2; + + readonly attribute SVGAnimatedNumber baseFrequencyX; + readonly attribute SVGAnimatedNumber baseFrequencyY; + readonly attribute SVGAnimatedInteger numOctaves; + readonly attribute SVGAnimatedNumber seed; + readonly attribute SVGAnimatedEnumeration stitchTiles; + readonly attribute SVGAnimatedEnumeration type; + }; + + interface SVGCursorElement : + SVGElement, + SVGURIReference, + SVGTests, + SVGExternalResourcesRequired { + + readonly attribute SVGAnimatedLength x; + readonly attribute SVGAnimatedLength y; + }; + + interface SVGAElement : + SVGElement, + SVGURIReference, + SVGTests, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGTransformable, + events::EventTarget { + + readonly attribute SVGAnimatedString target; + }; + + interface SVGViewElement : + SVGElement, + SVGExternalResourcesRequired, + SVGFitToViewBox, + SVGZoomAndPan { + + readonly attribute SVGStringList viewTarget; + }; + + interface SVGScriptElement : + SVGElement, + SVGURIReference, + SVGExternalResourcesRequired { + + attribute DOMString type; + // raises DOMException on setting + }; + + interface SVGEvent : events::Event {}; + + interface SVGZoomEvent : events::UIEvent { + readonly attribute SVGRect zoomRectScreen; + readonly attribute float previousScale; + readonly attribute SVGPoint previousTranslate; + readonly attribute float newScale; + readonly attribute SVGPoint newTranslate; + }; + + interface SVGAnimationElement : + SVGElement, + SVGTests, + SVGExternalResourcesRequired, + smil::ElementTimeControl, + events::EventTarget { + + readonly attribute SVGElement targetElement; + + float getStartTime ( ); + float getCurrentTime ( ); + float getSimpleDuration ( ) + raises( DOMException ); + }; + + interface SVGAnimateElement : SVGAnimationElement {}; + + interface SVGSetElement : SVGAnimationElement {}; + + interface SVGAnimateMotionElement : SVGAnimationElement {}; + + interface SVGMPathElement : + SVGElement, + SVGURIReference, + SVGExternalResourcesRequired {}; + + interface SVGAnimateColorElement : SVGAnimationElement {}; + + interface SVGAnimateTransformElement : SVGAnimationElement {}; + + interface SVGFontElement : + SVGElement, + SVGExternalResourcesRequired, + SVGStylable {}; + + interface SVGGlyphElement : + SVGElement, + SVGStylable {}; + + interface SVGMissingGlyphElement : + SVGElement, + SVGStylable {}; + + interface SVGHKernElement : SVGElement {}; + + interface SVGVKernElement : SVGElement {}; + + interface SVGFontFaceElement : SVGElement {}; + + interface SVGFontFaceSrcElement : SVGElement {}; + + interface SVGFontFaceUriElement : SVGElement {}; + + interface SVGFontFaceFormatElement : SVGElement {}; + + interface SVGFontFaceNameElement : SVGElement {}; + + interface SVGDefinitionSrcElement : SVGElement {}; + + interface SVGMetadataElement : SVGElement {}; + + interface SVGForeignObjectElement : + SVGElement, + SVGTests, + SVGLangSpace, + SVGExternalResourcesRequired, + SVGStylable, + SVGTransformable, + events::EventTarget { + + readonly attribute SVGAnimatedLength x; + readonly attribute SVGAnimatedLength y; + readonly attribute SVGAnimatedLength width; + readonly attribute SVGAnimatedLength height; + }; + + +}; + +#endif // _SVG_IDL_ \ No newline at end of file diff --git a/ksvg/scripts/makecc b/ksvg/scripts/makecc new file mode 100644 index 00000000..29a28b93 --- /dev/null +++ b/ksvg/scripts/makecc @@ -0,0 +1,211 @@ +function printg( a ) +{ + printf a >> FILENAME ".cc" +} +function doFunc( a ) +{ + gsub("attribute", "", $0) + nr = split($0, b, " ") + # do method + i = 1 + nrparams = 0 + rettype = b[1] + while ( i < nr && b[i + 1] != "(" ) + { + printg( b[i++] ) + printg( " " ) + } + printg( clas "::" ) + method = b[i] + while ( i < nr && b[i + 1] != ");" ) + { + if( b[i] == "in" ) + { + if( b[i + 1] != "float" && match( b[i + 1], "unsigned") == 0) + { + float = "ok" + printg( "const " ) + } + else + float = "bad" + i++ + while ( i + 1 < nr && b[i + 1] != "in" && b[i + 1] != ");" ) + { + printg( b[i++] " " ) + } + param[nrparams++] = b[i] + if( float == "ok" ) + printg( "&" b[i++] ) + else + printg( b[i++] ) + if( i < nr ) printg( " " ) + } + else + printg( b[i++] ) + } + printg( ")\n{\n" ); + if( rettype != "void" ) + { + printg( "\tif(!impl) return ; // FIXME\n" ) + printg( "\treturn impl->" method "(" ) + } + else + printg( "\tif(impl)\n\t\timpl->" method "(" ) + k = 0 + while( k < nrparams ) + { + printg( param[k++] ) + if( k < nrparams ) printg( " " ) + } + printg( ");\n" ) + printg( "}\n\n" ); +} + +function doAttr( a, class ) +{ + sub( ";", "", a) + sub( "\r", "", a) + gsub("attribute", "", a) + nr = split(a, b, " ") + + # do put method + printg( "void " clas "::set" ) + printg( toupper( substr( b[nr], 1, 1) ) ) + printg( substr( b[nr], 2) "(" ) + i = 1 + if( b[i] != "float" && match( b[i], "unsigned") == 0) + { + float = "ok" + printg( "const " ) + } + else + float = "bad" + while ( i < nr ) + { + printg( b[i++] ) + if( i < nr ) printg( " " ) + } + if( float == "ok" ) + printg( " &" b[nr] ")\n{\n" ) + else + printg( " " b[nr] ")\n{\n" ) + printg( "\tif(impl)\n\t\timpl->set") + printg( toupper( substr( b[nr], 1, 1) ) ) + printg( substr( b[nr], 2) "(" ) + printg( b[nr] ");\n}\n\n" ) + + # do get method + i = 1 + while ( i < nr ) + { + printg( b[i++] " " ) + } + $temp = b[nr] + printg( clas "::" $temp "() const\n{\n" ) + printg( "\tif(!impl) return ; // FIXME\n\treturn impl->" ) + printg( substr( b[nr], 1) "(" ) + printg( ");\n}\n\n" ) +} + +function doReadonlyAttr( a, class ) +{ + gsub("readonly attribute", "", $0) + nr = split($0, b, " ") + + # do get method + i = 1 + while ( i < nr ) + { + printg( b[i++] " " ) + } + sub( ";", "", b[nr]) + sub( "\r", "", b[nr]) + $temp = b[nr] + printg( clas "::" $temp "() const\n{\n" ) + printg( "\tif(!impl) return ; // FIXME\n\treturn impl->" ) + printg( substr( b[nr], 1) "(" ) + printg( ");\n}\n\n" ) +} +{ + sub("boolean", "bool", $0) + if(/interface /) + { + gsub(" interface ", "", $0) + gsub(": ", ": public ", $0) + gsub(",", ", public", $0) + gsub("{", "\n{", $0) + sub( ";", "", $0 ) + sub( "\r", "", $0 ) + nr = split($0, b, " ") + clas = b[1] + #printg( "// " clas " specification\n\n\n" ) + printg( clas "::" clas "()" ) + if( nr > 2 ) + { + i = 2 + sub( ":", " : ", b[i] ) + while ( i < nr ) + { + sub( "public", "", b[i] ) + sub( ",", "(), ", b[i] ) + printg( b[i++] ) + } + printg( "()" ) + } + printg( "\n{\n\timpl = new " clas "Impl();\n\timpl->ref();\n}\n\n" ) + printg( clas "::" clas "(const " clas " &other)" ) + if( nr > 2 ) + { + i = 2 + while ( i < nr ) + printg( b[i++] ) + + printg( "(), impl(0)" ) + } + else + printg( " : impl(0)" ) + printg( "\n{\n\t(*this) = other;\n}\n\n" ) + printg( clas " &" clas "::operator =(const " clas " &other)\n{\n\tif(impl == other.impl)\n\t\treturn *this;\n\n\tif(impl)\n\t\timpl->deref();\n\n\timpl = other.impl;\n\n\tif(impl)\n\t\timpl->ref();\n\n\treturn *this;\n}\n\n" ) + printg( clas "::" clas "(" clas "Impl *other)" ) + if( nr > 2 ) + { + i = 2 + while ( i < nr ) + printg( b[i++] ) + + printg( "()" ) + } + printg( "\n{\n\timpl = other;\n\tif(impl)\n\t\timpl->ref();\n}\n\n" ) + printg( clas "::~" clas "()\n{\n\tif(impl)\n\t\timpl->deref();\n}\n\n" ) + } + else if(/readonly attribute/) + { + doReadonlyAttr( $0, $class ) + } + else if(/attribute /) + { + doAttr( $0, $class ) + } + else if(/raises/) + { + } + else if(/\)/) + { + doFunc( $0 ); + } + else if(/};/) + { + } + else if(/ = /) + { + } + #else if(//) + #{ + # # end of class + # printf $0; + #} +} +# END +# { +# print "};"; +# } diff --git a/ksvg/scripts/makeheader b/ksvg/scripts/makeheader new file mode 100644 index 00000000..f8594690 --- /dev/null +++ b/ksvg/scripts/makeheader @@ -0,0 +1,164 @@ +function printg( a ) +{ + printf a >> FILENAME ".h" +} +function doFunc( a ) +{ + gsub("attribute", "", $0) + nr = split($0, b, " ") + printg( "\t" ) + # do method + i = 1 + while ( i < nr && b[i + 1] != "(" ) + { + printg( b[i++] ) + printg( " " ) + } + while ( i < nr && b[i + 1] != ");" ) + { + if( b[i] == "in" ) + { + if( b[i + 1] != "float" && b[i + 1] != "unsigned" && b[i+1] != "short" && b[i+1] != "bool" ) + { + float = "ok" + printg( "const " ) + } + else + float = "bad" + i++ + while ( i + 1 < nr && b[i + 1] != "in" && b[i + 1] != ");" ) + { + printg( b[i++] " " ) + #if( b[ i ] != ");" ) printg( " " ) + } + if( float == "ok" ) + printg( "&" b[i++] ) + else + printg( b[i++] ) + if( i < nr ) printg( " " ) + } + else + printg( b[i++] ) + } + printg( ");\n" ); +} + +function doAttr( a, class ) +{ + sub( ";", "", a) + sub( "\r", "", a) + gsub("attribute", "", a) + nr = split(a, b, " ") + + # do put method + printg( "\tvoid set" ) + printg( toupper( substr( b[nr], 1, 1) ) ) + printg( substr( b[nr], 2) "(" ) + i = 1 + if( b[i] != "float" && b[i] != "unsigned" && b[i] != "short" && b[i] != "bool" ) + #if( b[i] != "float" && match( b[i], "unsigned") == 0) + { + float = "ok" + printg( "const " ) + } + else + float = "bad" + while ( i < nr ) + { + printg( b[i++] ) + if( i < nr ) printg( " " ) + } + if( float == "ok" ) + printg( " &" ) + else + printg( " " ) + + printg( b[nr] ");\n" ) + + # do get method + printg("\t") + i = 1 + while ( i < nr ) + { + printg( b[i++] " " ) + } + $temp = b[nr] + printg( $temp "() const;" ) + printg( "\n\n" ) +} + +function doReadonlyAttr( a, class ) +{ + gsub("readonly attribute", "", $0) + nr = split($0, b, " ") + + # do get method + i = 1 + printg("\t") + while ( i < nr ) + { + printg( b[i++] " " ) + } + sub( ";", "", b[nr]) + sub( "\r", "", b[nr]) + $temp = b[nr] + printg( $temp "() const;" ) + printg( "\n" ) +} +{ + sub("boolean", "bool", $0); # to shut up frerich :P + if(/interface /) + { + gsub(" interface ", "", $0) + gsub(": ", ": public ", $0) + gsub(",", ", public", $0) + gsub("{", "\n{", $0) + sub( ";", "", $0 ) + sub( "\r", "", $0 ) + nr = split($0, b, " ") + clas = b[1] + printg( "class " clas "Impl;" ) + printg( "\nclass " ) + printg( $0 ) + printg( "\npublic:\n" ) + printg( "\t" clas "();\n" ) + printg( "\t" clas "(const " clas " &other);\n" ) + printg( "\t" clas " &operator=(const " clas " &other);\n" ) + printg( "\t" clas "(" clas "Impl *other);\n" ) + printg( "\tvirtual ~" clas "();\n\n" ) + #printg( "\tbool isNull() const { return !impl; }\n" ) + } + else if(/readonly attribute/) + { + doReadonlyAttr( $0, $class ) + } + else if(/attribute /) + { + doAttr( $0, $class ) + } + else if(/raises/) + { + } + else if(/\)/) + { + doFunc( $0 ); + } + else if(/};/) + { + printg( "private:\n\t" clas "Impl *impl;\n};\n\n" ); + } + else if(/ = /) + { + sub( "\r", "", $0 ) + printg( $0 "\n" ); + } + #else if(//) + #{ + # # end of class + # printf $0; + #} +} +# END +# { +# print "};"; +# } diff --git a/ksvg/scripts/makeimpl b/ksvg/scripts/makeimpl new file mode 100644 index 00000000..fb5ab8f5 --- /dev/null +++ b/ksvg/scripts/makeimpl @@ -0,0 +1,440 @@ +function printtoctor( aa ) +{ + ctor = ctor aa +} +function printtodtor( aa ) +{ + dtor = dtor aa +} +function printtofunc( aa ) +{ + fun = fun aa +} +function printp( a ) +{ + #printf a >> "PRIVATE" + private = private a +} +function printg( a ) +{ + printf a >> FILENAME "Impl.h" +} +function printh( a ) +{ + printf a >> FILENAME "Impl.cc" +} +function doFuncCC( a, class ) +{ + gsub("attribute", "", $0) + nr = split($0, b, " ") + # do method + i = 1 + while ( i < nr && b[i + 1] != "(" ) + { + var = b[i++] + if(match(var, "SVG") != 0 ) + printtofunc( var "Impl " ) + else + printtofunc( var " " ) + } + printtofunc( class "::" ); + while ( i < nr && b[i + 1] != ");" ) + { + if( b[i] == "in" ) + { + if(b[i + 1] != "float" && b[i + 1] != "unsigned" && b[i+1] != "short" && b[i+1] != "bool" ) + #if(b[i + 1] != "float" && match(b[i + 1], "unsigned") == 0) + { + float = "ok" + printtofunc( "const " ) + } + else + { + float = "bad" + } + i++ + while ( i + 1 < nr && b[i + 1] != "in" && b[i + 1] != ");" ) + { + var = b[i++] + if(match(var, "SVG") != 0 ) + printtofunc( var "Impl " ) + else + printtofunc( var " " ) + } + if( float == "ok") + { + printtofunc( "&" b[i++] ) + } + else + { + printtofunc( b[i++] ) + } + if( i < nr ) printtofunc( " " ) + } + else + printtofunc( b[i++] ) + } + printtofunc( ")\n{\n}\n\n" ); +} + +function doFunc( a ) +{ + gsub("attribute", "", $0) + nr = split($0, b, " ") + printg( "\t" ) + # do method + i = 1 + while ( i < nr && b[i + 1] != "(" ) + { + var = b[i++] + if(match(var, "SVG") != 0 ) + printg( var "Impl " ) + else + printg( var " " ) + } + while ( i < nr && b[i + 1] != ");" ) + { + if( b[i] == "in" ) + { + if(b[i + 1] != "float" && b[i + 1] != "unsigned" && b[i+1] != "short" && b[i+1] != "bool" ) + { + float = "ok" + printg( "const " ) + } + else + { + float = "bad" + } + i++ + while ( i + 1 < nr && b[i + 1] != "in" && b[i + 1] != ");" ) + { + var = b[i++] + if(match(var, "SVG") != 0 ) + printg( var "Impl " ) + else + printg( var " " ) + } + if( float == "ok") + { + if( b[ i ] != "in" ) printg( "&" b[i++] ) + } + else + { + if( b[ i ] != "in" ) printg( b[i++] ) + } + if( i < nr ) printg( " " ) + } + else + printg( b[i++] ) + } + printg( ");\n" ); +} + +function doAttr( a, class ) +{ + sub( ";", "", a) + sub( "\r", "", a) + gsub("attribute", "", a) + nr = split(a, b, " ") + + # do put method + printg( "\tvoid set" ) + printg( toupper( substr( b[nr], 1, 1) ) ) + printg( substr( b[nr], 2) "(" ) + i = 1 + if(b[i] != "float" && b[i] != "unsigned" && b[i] != "short" && b[i] != "bool" ) + { + float = "ok" + printg( "const " ) + } + else + { + float = "bad" + } + while ( i < nr ) + { + var = b[i++] + if(match(var, "SVG") != 0 ) + printg( var "Impl" ) + else + printg( var ) + if( i < nr ) printg( " " ) + } + if( float == "ok") + printg( " &" ) + else + printg( " " )n + printg( b[nr] ");\n" ) + + # do put method .cc + printtofunc( "void " clas "::set" ) + printtofunc( toupper( substr( b[nr], 1, 1) ) ) + printtofunc( substr( b[nr], 2) "(" ) + i = 1 + if(b[i] != "float" && b[i] != "unsigned" && b[i] != "short" && b[i] != "bool" ) + { + float = "ok" + printtofunc( "const " ) + } + else + { + float = "bad" + } + while ( i < nr ) + { + var = b[i++] + if(match(var, "SVG") != 0 ) + printtofunc( var "Impl" ) + else + printtofunc( var ) + if( i < nr ) printtofunc( " " ) + } + if( float == "ok") + printtofunc( " &" ) + else + printtofunc( " " ) + printtofunc( b[nr] ")\n{\n\tm_" b[nr] " = " b[nr] ";\n}\n\n" ) + + + # do get method .h + i = 1 + printg( "\t" ) + while ( i < nr ) + { + var = b[i++] + if(match(var, "SVG") != 0 ) + printg( var "Impl *" ) + else + printg( var " " ) + } + sub( ";", "", b[nr]) + sub( "\r", "", b[nr]) + $temp = b[nr] + printg( $temp "() const;\n" ) + + # do get method .cc + i = 1 + while ( i < nr ) + { + var = b[i++] + if(match(var, "SVG") != 0 ) + printtofunc( var "Impl *" ) + else + printtofunc( var " " ) + } + sub( ";", "", b[nr]) + sub( "\r", "", b[nr]) + $temp = b[nr] + printtofunc( clas "::" $temp "() const\n{\n\treturn m_" $temp ) + printtofunc( ";\n}\n\n" ) + + # do var + i = 1 + printp( "\t" ) + while ( i < nr ) + { + var = b[i++] + if(match(var, "SVG") != 0 ) + { + var = var "Impl" + printp( var " *" ) + } + else + printp( var " " ) + } + printp( "m_" ) + #printp( toupper( substr( b[nr], 1, 1) ) ) + printp( substr( b[nr], 1) ";\n" ) + + #add to ctor + dtor + if(match(var, "SVG") != 0) + { + printtoctor("\tm_" substr( b[nr], 1) " = new " var "();\n" ) + printtoctor("\tm_" substr( b[nr], 1) "->ref();\n\n" ) + printtodtor("\tif(m_" substr( b[nr], 1) ")\n" ) + printtodtor("\t\tm_" substr( b[nr], 1) "->deref();\n\n" ) + } +} + +function doReadonlyAttr( a, class ) +{ + gsub("readonly attribute", "", $0) + nr = split($0, b, " ") + + # do get method .h + i = 1 + printg( "\t" ) + while ( i < nr ) + { + var = b[i++] + if(match(var, "SVG") != 0 ) + printg( var "Impl *" ) + else + printg( var " " ) + } + sub( ";", "", b[nr]) + sub( "\r", "", b[nr]) + $temp = b[nr] + printg( $temp "() const;\n" ) + + # do get method .cc + i = 1 + while ( i < nr ) + { + var = b[i++] + if(match(var, "SVG") != 0 ) + printtofunc( var "Impl *" ) + else + printtofunc( var " " ) + } + sub( ";", "", b[nr]) + sub( "\r", "", b[nr]) + $temp = b[nr] + printtofunc( clas "::" $temp "() const\n{\n\treturn m_" $temp ) + printtofunc( ";\n}\n\n" ) + + # do var + i = 1 + printp( "\t" ) + while ( i < nr ) + { + var = b[i++] + if(match(var, "SVG") != 0 ) + { + var = var "Impl" + printp( var " *" ) + } + else + printp( var " " ) + } + printp( "m_" ) + printp( substr( b[nr], 1) ";\n" ) + + #add to ctor + dtor + if(match(var, "SVG") != 0) + { + printtoctor("\tm_" substr( b[nr], 1) " = new " var "();\n" ) + printtoctor("\tm_" substr( b[nr], 1) "->ref();\n\n" ) + printtodtor("\tif(m_" substr( b[nr], 1) ")\n" ) + printtodtor("\t\tm_" substr( b[nr], 1) "->deref();\n\n" ) + } +} +{ + sub("boolean", "bool", $0); # to shut up frerich :P + # Frerich: Thank you :-) + if(/interface /) + { + private = "\nprivate:\n"; + gsub(" interface ", "", $0) + gsub(": ", ": public ", $0) + gsub(",", ", public", $0) + gsub("{", "\n{", $0) + sub( ";", "", $0 ) + sub( "\r", "", $0 ) + printg( "\nclass " ) + #printg( $0 ) + #printg( "\npublic:\n" ) + nr = split($0, b, " ") + clas = b[1] "Impl" + printg( clas " " ) + i = 2 + while ( i < nr ) + { + if(match(b[i], "SVG") != 0 ) + { + if(match(b[i], ",") != 0) + sub( ",", "Impl," , b[i]) + else + b[i] = b[i] "Impl" + } + printg( b[i++] " " ) + } + printg( "\n{\npublic:\n" ) + printg( "\t" clas "();\n" ) + #printg( "\t" clas "(const " clas " &other)" ) + #if( nr > 2 ) + #{ + # i = 2 + # sub( ":", " : ", b[i] ) + # while ( i < nr ) + # { + # sub( "public", "", b[i] ) + # sub( ",", "(), ", b[i] ) + # printg( b[i++] ) + # } + # printg( "()" ) + #} + #printg( " { *this = other; }\n" ) + + printg( "\tvirtual ~" clas "();\n\n" ) + #printg( "\t" clas " &operator=(const " clas " &other);\n\n" ) + + # CC part + #printh( "// " b[1] " implementation \n\n" ) + printtoctor( clas "::" clas "()" ) + if( nr > 2 ) + { + i = 2 + sub( ":", " : ", b[i] ) + while ( i < nr ) + { + sub( "public", "",b[i] ) + sub( ",", "(), ", b[i] ) + printtoctor( b[i++] ) + } + + printtoctor( "()" ) + } + printtoctor( "\n{\n" ) + + printtodtor( clas "::~" clas "()\n{\n" ) + #printh( clas " &" clas "::operator =(const " clas " &other)\n{\n\treturn *this;\n}\n\n" ) + + } + else if(/readonly attribute/) + { + doReadonlyAttr( $0, $class ) + } + else if(/attribute /) + { + doAttr( $0, $class ) + } + else if(/raises/) + { + } + else if(/\)/) + { + doFuncCC( $0, clas ); + doFunc( $0 ); + } + else if(/};/) + { + printg(private) + printg( "};\n\n" ); + + printh( "\n" ctor ) + printh( "}\n\n" ) + ctor = "" + + printh( dtor ) + printh( "}\n\n" ) + dtor = "" + + printh( fun ) + fun = "" + } + else if(/ = /) + { +# sub( "\r", "", $0 ) +# printg( $0 "\n" ); + } + #else if(//) + #{ + # # end of class + # printf $0; + #} +} +# END +# { +# print "};"; +# } diff --git a/ksvg/test/Makefile.am b/ksvg/test/Makefile.am new file mode 100644 index 00000000..7b2d8286 --- /dev/null +++ b/ksvg/test/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = external diff --git a/ksvg/test/Units.svg b/ksvg/test/Units.svg new file mode 100644 index 00000000..f3a8569b --- /dev/null +++ b/ksvg/test/Units.svg @@ -0,0 +1,43 @@ + + + +Example Units +Illustrates various units options + + + + + + +Abs. units: + + + + + + + + + +Rel. units: + + + + + + + + +Percentages: + + + + + + + + + diff --git a/ksvg/test/W3C_TESTSUITE_1.1 b/ksvg/test/W3C_TESTSUITE_1.1 new file mode 100644 index 00000000..b0766355 --- /dev/null +++ b/ksvg/test/W3C_TESTSUITE_1.1 @@ -0,0 +1,227 @@ +Testsuite-Check v1.1 FULL +----------------- + +http://www.w3.org/Graphics/SVG/Test/20021112/htmlframe/full-index.html + +- = none working +o = half working +x = fully working +c = crashed +p = could not check +e = crash on destruction + +[ANIMATION] +animate-elem-02-t - +animate-elem-03-t - +animate-elem-04-t - +animate-elem-05-t - +animate-elem-06-t - +animate-elem-07-t - +animate-elem-08-t - +animate-elem-09-t - +animate-elem-10-t - +animate-elem-11-t - +animate-elem-12-t - +animate-elem-13-t - +animate-elem-14-t - +animate-elem-15-t - +animate-elem-16-t - +animate-elem-17-t - +animate-elem-18-t - +animate-elem-19-t - +animate-elem-20-t - +animate-elem-21-t - +animate-elem-22-b - +animate-elem-23-t - +animate-elem-24-t - +animate-elem-25-t - +animate-elem-26-t - +animate-elem-27-t - +animate-elem-28-t - +animate-elem-29-b - + +[COLOR] +color-prof-01-f x crashes when embedded +color-prop-01-b x +color-prop-02-f x +color-prop-03-t x + +[COORDS] +coords-trans-01-b x +coords-trans-02-t x +coords-trans-03-t x +coords-trans-04-t x +coords-trans-05-t x +coords-trans-06-t x +coords-units-01-b x Pattern is a bit off but size is ok +coords-units-02-b o +coords-units-03-b x +coords-viewattr-01-b x + +[EXTEND] +extend-namespace-01-f x + +[FILTERS] +filters-blend-01-b - +filters-color-01-b - +filters-composite-01-b - +filters-comptran-01-b - +filters-conv-01-f - +filters-diffuse-01-f - +filters-displace-01-f - +filters-example-01-b - +filters-gauss-01-b - +filters-image-01-b - +filters-light-01-f - +filters-morph-01-f - +filters-offset-01-b - +filters-specular-01-f - +filters-tile-01-b - + +[FONTS] +fonts-elem-01-t o SVG Font doesn't work +fonts-elem-02-t - looks really strange +fonts-elem-03-t o SVG Font doesn't work +fonts-elem-04-t o SVG Font doesn't work + +[INTERACT] +interact-cursor-01-b o +interact-dom-01-t x +interact-events-01-t x +interact-order-01-t x +interact-order-02-t o same as above +interact-order-03-t o +interact-zoom-01-t - + +[LINKING] +linking-a-01-b x doesn't work when embedded?! +linking-a-02-b x " +linking-a-03-t x " +linking-a-04-t x +linking-uri-01-b - +linking-uri-02-b - +linking-uri-03-t x + +[MASKING] +masking-mask-01-b - +masking-opacity-01-b o +masking-path-01-b x +masking-path-02-b x +masking-path-03-t x +masking-path-04-b o +masking-path-05-f x + +[METADATA] +metadata-example-01-b x + +[PAINTING] +painting-fill-01-t x +painting-fill-02-t x +painting-fill-03-t x +painting-fill-04-t x +painting-marker-01-f o Not every element drawn...hmm +painting-marker-02-f o same +painting-render-01-b o linearRGB wrong +painting-stroke-01-t x +painting-stroke-02-t x +painting-stroke-03-t x +painting-stroke-04-t x + +[PATHS] +paths-data-01-t x +paths-data-02-t x +paths-data-03-f x +paths-data-04-t x +paths-data-05-t x +paths-data-06-t x +paths-data-07-t x + +[PSERVERS] +pservers-grad-01-b x +pservers-grad-02-b x +pservers-grad-03-b x +pservers-grad-04-b x +pservers-grad-05-b o partially wrong colors +pservers-grad-06-b o no transformations to the pattern +pservers-grad-07-b x +pservers-grad-08-b x +pservers-grad-09-b x +pservers-grad-10-b x +pservers-grad-11-b x +pservers-grad-12-b x +pservers-pattern-01-b o patternpositioning + +[RENDER] +render-elems-01-t x +render-elems-02-t x +render-elems-03-t x +render-elems-06-t x +render-elems-07-t x +render-elems-08-t x +render-groups-01-b - badly broken.. +render-groups-03-t o SVG font +render-groups-04-b - + +[SCRIPT] +script-handle-01-t x +script-handle-02-t x +script-handle-03-t x +script-handle-04-t x + +[SHAPES] +shapes-circle-01-t x +shapes-ellipse-01-t x +shapes-line-01-t x +shapes-polygon-01-t x +shapes-polyline-01-t x +shapes-rect-01-t x + +[STRUCT] +struct-cond-01-t x +struct-cond-02-t x +struct-defs-01-t x +struct-dom-01-t x Reference PNG wrong?! +struct-dom-02-t x everything false. but text says thats ok +struct-dom-03-t x same +struct-dom-04-t x same +struct-dom-05-t x same +struct-dom-06-t x +struct-frag-01-t x empty image +struct-group-01-t x +struct-group-02-t x +struct-image-01-t o SVG Image dimensions wrong +struct-image-02-t x +struct-image-03-t o no gamma correction +struct-symbol-01-b - + +[STYLING] +styling-css-01-t - no